From 9904adfaca139581d6b03947a7e23c7e2cb64339 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 27 Apr 2020 12:24:13 +0200 Subject: [PATCH 0001/2595] virtio-net: fix rsc_ext compat handling virtio_net_rsc_ext_num_{packets,dupacks} needs to be available independently of the presence of VIRTIO_NET_HDR_F_RSC_INFO. Fixes: 2974e916df87 ("virtio-net: support RSC v4/v6 tcp traffic for Windows HCK") Signed-off-by: Cornelia Huck Message-Id: <20200427102415.10915-2-cohuck@redhat.com> --- hw/net/virtio-net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index a46e3b37a7..e85d902588 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -83,6 +83,8 @@ #define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc_ext data in csum_ fields */ #define VIRTIO_NET_F_RSC_EXT 61 +#endif + static inline __virtio16 *virtio_net_rsc_ext_num_packets( struct virtio_net_hdr *hdr) { @@ -95,8 +97,6 @@ static inline __virtio16 *virtio_net_rsc_ext_num_dupacks( return &hdr->csum_offset; } -#endif - static VirtIOFeature feature_sizes[] = { {.flags = 1ULL << VIRTIO_NET_F_MAC, .end = endof(struct virtio_net_config, mac)}, From dc6f8d458a4ccc360723993f31d310d06469f55f Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 27 Apr 2020 12:24:14 +0200 Subject: [PATCH 0002/2595] linux-headers: update against Linux 5.7-rc3 commit 6a8b55ed4056ea5559ebe4f6a4b247f627870d4c Reviewed-by: Michael S. Tsirkin # virtio/vhost parts Signed-off-by: Cornelia Huck Message-Id: <20200427102415.10915-3-cohuck@redhat.com> --- include/standard-headers/linux/ethtool.h | 10 +- .../linux/input-event-codes.h | 5 +- include/standard-headers/linux/pci_regs.h | 2 + include/standard-headers/linux/vhost_types.h | 8 ++ .../standard-headers/linux/virtio_balloon.h | 12 ++- include/standard-headers/linux/virtio_ids.h | 1 + include/standard-headers/linux/virtio_net.h | 102 +++++++++++++++++- linux-headers/COPYING | 2 + linux-headers/asm-x86/kvm.h | 1 + linux-headers/asm-x86/unistd_32.h | 1 + linux-headers/asm-x86/unistd_64.h | 1 + linux-headers/asm-x86/unistd_x32.h | 1 + linux-headers/linux/kvm.h | 47 +++++++- linux-headers/linux/mman.h | 5 +- linux-headers/linux/userfaultfd.h | 42 ++++++-- linux-headers/linux/vfio.h | 37 +++++++ linux-headers/linux/vhost.h | 24 +++++ 17 files changed, 281 insertions(+), 20 deletions(-) diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h index 8adf3b018b..1200890c86 100644 --- a/include/standard-headers/linux/ethtool.h +++ b/include/standard-headers/linux/ethtool.h @@ -596,6 +596,9 @@ struct ethtool_pauseparam { * @ETH_SS_LINK_MODES: link mode names * @ETH_SS_MSG_CLASSES: debug message class names * @ETH_SS_WOL_MODES: wake-on-lan modes + * @ETH_SS_SOF_TIMESTAMPING: SOF_TIMESTAMPING_* flags + * @ETH_SS_TS_TX_TYPES: timestamping Tx types + * @ETH_SS_TS_RX_FILTERS: timestamping Rx filters */ enum ethtool_stringset { ETH_SS_TEST = 0, @@ -610,6 +613,9 @@ enum ethtool_stringset { ETH_SS_LINK_MODES, ETH_SS_MSG_CLASSES, ETH_SS_WOL_MODES, + ETH_SS_SOF_TIMESTAMPING, + ETH_SS_TS_TX_TYPES, + ETH_SS_TS_RX_FILTERS, /* add new constants above here */ ETH_SS_COUNT @@ -1330,6 +1336,7 @@ enum ethtool_fec_config_bits { ETHTOOL_FEC_OFF_BIT, ETHTOOL_FEC_RS_BIT, ETHTOOL_FEC_BASER_BIT, + ETHTOOL_FEC_LLRS_BIT, }; #define ETHTOOL_FEC_NONE (1 << ETHTOOL_FEC_NONE_BIT) @@ -1337,6 +1344,7 @@ enum ethtool_fec_config_bits { #define ETHTOOL_FEC_OFF (1 << ETHTOOL_FEC_OFF_BIT) #define ETHTOOL_FEC_RS (1 << ETHTOOL_FEC_RS_BIT) #define ETHTOOL_FEC_BASER (1 << ETHTOOL_FEC_BASER_BIT) +#define ETHTOOL_FEC_LLRS (1 << ETHTOOL_FEC_LLRS_BIT) /* CMDs currently supported */ #define ETHTOOL_GSET 0x00000001 /* DEPRECATED, Get settings. @@ -1521,7 +1529,7 @@ enum ethtool_link_mode_bit_indices { ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71, ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT = 72, ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT = 73, - + ETHTOOL_LINK_MODE_FEC_LLRS_BIT = 74, /* must be last entry */ __ETHTOOL_LINK_MODE_MASK_NBITS }; diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h index b484c25289..ebf72c1031 100644 --- a/include/standard-headers/linux/input-event-codes.h +++ b/include/standard-headers/linux/input-event-codes.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* * Input event codes * @@ -652,6 +652,9 @@ /* Electronic privacy screen control */ #define KEY_PRIVACY_SCREEN_TOGGLE 0x279 +/* Select an area of screen to be copied */ +#define KEY_SELECTIVE_SCREENSHOT 0x27a + /* * Some keyboards have keys which do not have a defined meaning, these keys * are intended to be programmed / bound to macros by the user. For most diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h index 5437690483..f9701410d3 100644 --- a/include/standard-headers/linux/pci_regs.h +++ b/include/standard-headers/linux/pci_regs.h @@ -605,6 +605,7 @@ #define PCI_EXP_SLTCTL_PWR_OFF 0x0400 /* Power Off */ #define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */ #define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */ +#define PCI_EXP_SLTCTL_IBPD_DISABLE 0x4000 /* In-band PD disable */ #define PCI_EXP_SLTSTA 26 /* Slot Status */ #define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */ #define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */ @@ -680,6 +681,7 @@ #define PCI_EXP_LNKSTA2 50 /* Link Status 2 */ #define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 52 /* v2 endpoints with link end here */ #define PCI_EXP_SLTCAP2 52 /* Slot Capabilities 2 */ +#define PCI_EXP_SLTCAP2_IBPD 0x00000001 /* In-band PD Disable Supported */ #define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ #define PCI_EXP_SLTSTA2 58 /* Slot Status 2 */ diff --git a/include/standard-headers/linux/vhost_types.h b/include/standard-headers/linux/vhost_types.h index 5351fe172d..a678d8fbaa 100644 --- a/include/standard-headers/linux/vhost_types.h +++ b/include/standard-headers/linux/vhost_types.h @@ -119,6 +119,14 @@ struct vhost_scsi_target { unsigned short reserved; }; +/* VHOST_VDPA specific definitions */ + +struct vhost_vdpa_config { + uint32_t off; + uint32_t len; + uint8_t buf[0]; +}; + /* Feature bits */ /* Log all write descriptors. Can be changed while device is active. */ #define VHOST_F_LOG_ALL 26 diff --git a/include/standard-headers/linux/virtio_balloon.h b/include/standard-headers/linux/virtio_balloon.h index 9375ca2a70..f343bfefd8 100644 --- a/include/standard-headers/linux/virtio_balloon.h +++ b/include/standard-headers/linux/virtio_balloon.h @@ -36,6 +36,7 @@ #define VIRTIO_BALLOON_F_DEFLATE_ON_OOM 2 /* Deflate balloon on OOM */ #define VIRTIO_BALLOON_F_FREE_PAGE_HINT 3 /* VQ to report free pages */ #define VIRTIO_BALLOON_F_PAGE_POISON 4 /* Guest is using page poisoning */ +#define VIRTIO_BALLOON_F_REPORTING 5 /* Page reporting virtqueue */ /* Size of a PFN in the balloon interface. */ #define VIRTIO_BALLOON_PFN_SHIFT 12 @@ -47,8 +48,15 @@ struct virtio_balloon_config { uint32_t num_pages; /* Number of pages we've actually got in balloon. */ uint32_t actual; - /* Free page report command id, readonly by guest */ - uint32_t free_page_report_cmd_id; + /* + * Free page hint command id, readonly by guest. + * Was previously named free_page_report_cmd_id so we + * need to carry that name for legacy support. + */ + union { + uint32_t free_page_hint_cmd_id; + uint32_t free_page_report_cmd_id; /* deprecated */ + }; /* Stores PAGE_POISON if page poisoning is in use */ uint32_t poison_val; }; diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h index 585e07b273..ecc27a1740 100644 --- a/include/standard-headers/linux/virtio_ids.h +++ b/include/standard-headers/linux/virtio_ids.h @@ -46,5 +46,6 @@ #define VIRTIO_ID_IOMMU 23 /* virtio IOMMU */ #define VIRTIO_ID_FS 26 /* virtio filesystem */ #define VIRTIO_ID_PMEM 27 /* virtio pmem */ +#define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */ #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/include/standard-headers/linux/virtio_net.h b/include/standard-headers/linux/virtio_net.h index 260c3681d7..a90f79e1b1 100644 --- a/include/standard-headers/linux/virtio_net.h +++ b/include/standard-headers/linux/virtio_net.h @@ -57,6 +57,9 @@ * Steering */ #define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */ +#define VIRTIO_NET_F_HASH_REPORT 57 /* Supports hash report */ +#define VIRTIO_NET_F_RSS 60 /* Supports RSS RX steering */ +#define VIRTIO_NET_F_RSC_EXT 61 /* extended coalescing info */ #define VIRTIO_NET_F_STANDBY 62 /* Act as standby for another device * with the same MAC. */ @@ -69,6 +72,17 @@ #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ #define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */ +/* supported/enabled hash types */ +#define VIRTIO_NET_RSS_HASH_TYPE_IPv4 (1 << 0) +#define VIRTIO_NET_RSS_HASH_TYPE_TCPv4 (1 << 1) +#define VIRTIO_NET_RSS_HASH_TYPE_UDPv4 (1 << 2) +#define VIRTIO_NET_RSS_HASH_TYPE_IPv6 (1 << 3) +#define VIRTIO_NET_RSS_HASH_TYPE_TCPv6 (1 << 4) +#define VIRTIO_NET_RSS_HASH_TYPE_UDPv6 (1 << 5) +#define VIRTIO_NET_RSS_HASH_TYPE_IP_EX (1 << 6) +#define VIRTIO_NET_RSS_HASH_TYPE_TCP_EX (1 << 7) +#define VIRTIO_NET_RSS_HASH_TYPE_UDP_EX (1 << 8) + struct virtio_net_config { /* The config defining mac address (if VIRTIO_NET_F_MAC) */ uint8_t mac[ETH_ALEN]; @@ -92,6 +106,12 @@ struct virtio_net_config { * Any other value stands for unknown. */ uint8_t duplex; + /* maximum size of RSS key */ + uint8_t rss_max_key_size; + /* maximum number of indirection table entries */ + uint16_t rss_max_indirection_table_length; + /* bitmask of supported VIRTIO_NET_RSS_HASH_ types */ + uint32_t supported_hash_types; } QEMU_PACKED; /* @@ -104,6 +124,7 @@ struct virtio_net_config { struct virtio_net_hdr_v1 { #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start, csum_offset */ #define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */ +#define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc info in csum_ fields */ uint8_t flags; #define VIRTIO_NET_HDR_GSO_NONE 0 /* Not a GSO frame */ #define VIRTIO_NET_HDR_GSO_TCPV4 1 /* GSO frame, IPv4 TCP (TSO) */ @@ -113,11 +134,46 @@ struct virtio_net_hdr_v1 { uint8_t gso_type; __virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */ __virtio16 gso_size; /* Bytes to append to hdr_len per frame */ - __virtio16 csum_start; /* Position to start checksumming from */ - __virtio16 csum_offset; /* Offset after that to place checksum */ + union { + struct { + __virtio16 csum_start; + __virtio16 csum_offset; + }; + /* Checksum calculation */ + struct { + /* Position to start checksumming from */ + __virtio16 start; + /* Offset after that to place checksum */ + __virtio16 offset; + } csum; + /* Receive Segment Coalescing */ + struct { + /* Number of coalesced segments */ + uint16_t segments; + /* Number of duplicated acks */ + uint16_t dup_acks; + } rsc; + }; __virtio16 num_buffers; /* Number of merged rx buffers */ }; +struct virtio_net_hdr_v1_hash { + struct virtio_net_hdr_v1 hdr; + uint32_t hash_value; +#define VIRTIO_NET_HASH_REPORT_NONE 0 +#define VIRTIO_NET_HASH_REPORT_IPv4 1 +#define VIRTIO_NET_HASH_REPORT_TCPv4 2 +#define VIRTIO_NET_HASH_REPORT_UDPv4 3 +#define VIRTIO_NET_HASH_REPORT_IPv6 4 +#define VIRTIO_NET_HASH_REPORT_TCPv6 5 +#define VIRTIO_NET_HASH_REPORT_UDPv6 6 +#define VIRTIO_NET_HASH_REPORT_IPv6_EX 7 +#define VIRTIO_NET_HASH_REPORT_TCPv6_EX 8 +#define VIRTIO_NET_HASH_REPORT_UDPv6_EX 9 + uint16_t hash_report; + uint16_t padding; +}; + #ifndef VIRTIO_NET_NO_LEGACY /* This header comes first in the scatter-gather list. * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must @@ -228,7 +284,9 @@ struct virtio_net_ctrl_mac { /* * Control Receive Flow Steering - * + */ +#define VIRTIO_NET_CTRL_MQ 4 +/* * The command VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET * enables Receive Flow Steering, specifying the number of the transmit and * receive queues that will be used. After the command is consumed and acked by @@ -241,11 +299,47 @@ struct virtio_net_ctrl_mq { __virtio16 virtqueue_pairs; }; -#define VIRTIO_NET_CTRL_MQ 4 #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET 0 #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN 1 #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX 0x8000 +/* + * The command VIRTIO_NET_CTRL_MQ_RSS_CONFIG has the same effect as + * VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET does and additionally configures + * the receive steering to use a hash calculated for incoming packet + * to decide on receive virtqueue to place the packet. The command + * also provides parameters to calculate a hash and receive virtqueue. + */ +struct virtio_net_rss_config { + uint32_t hash_types; + uint16_t indirection_table_mask; + uint16_t unclassified_queue; + uint16_t indirection_table[1/* + indirection_table_mask */]; + uint16_t max_tx_vq; + uint8_t hash_key_length; + uint8_t hash_key_data[/* hash_key_length */]; +}; + + #define VIRTIO_NET_CTRL_MQ_RSS_CONFIG 1 + +/* + * The command VIRTIO_NET_CTRL_MQ_HASH_CONFIG requests the device + * to include in the virtio header of the packet the value of the + * calculated hash and the report type of hash. It also provides + * parameters for hash calculation. The command requires feature + * VIRTIO_NET_F_HASH_REPORT to be negotiated to extend the + * layout of virtio header as defined in virtio_net_hdr_v1_hash. + */ +struct virtio_net_hash_config { + uint32_t hash_types; + /* for compatibility with virtio_net_rss_config */ + uint16_t reserved[4]; + uint8_t hash_key_length; + uint8_t hash_key_data[/* hash_key_length */]; +}; + + #define VIRTIO_NET_CTRL_MQ_HASH_CONFIG 2 + /* * Control network offloads * diff --git a/linux-headers/COPYING b/linux-headers/COPYING index da4cb28feb..a635a38ef9 100644 --- a/linux-headers/COPYING +++ b/linux-headers/COPYING @@ -16,3 +16,5 @@ In addition, other licenses may also apply. Please see: Documentation/process/license-rules.rst for more details. + +All contributions to the Linux Kernel are subject to this COPYING file. diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index 503d3f42da..3f3f780c8c 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -390,6 +390,7 @@ struct kvm_sync_regs { #define KVM_STATE_NESTED_GUEST_MODE 0x00000001 #define KVM_STATE_NESTED_RUN_PENDING 0x00000002 #define KVM_STATE_NESTED_EVMCS 0x00000004 +#define KVM_STATE_NESTED_MTF_PENDING 0x00000008 #define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001 #define KVM_STATE_NESTED_SMM_VMXON 0x00000002 diff --git a/linux-headers/asm-x86/unistd_32.h b/linux-headers/asm-x86/unistd_32.h index f6e06fcfbd..1e6c1a5867 100644 --- a/linux-headers/asm-x86/unistd_32.h +++ b/linux-headers/asm-x86/unistd_32.h @@ -429,4 +429,5 @@ #define __NR_openat2 437 #define __NR_pidfd_getfd 438 + #endif /* _ASM_X86_UNISTD_32_H */ diff --git a/linux-headers/asm-x86/unistd_64.h b/linux-headers/asm-x86/unistd_64.h index 924f826d2d..6daf0aecb2 100644 --- a/linux-headers/asm-x86/unistd_64.h +++ b/linux-headers/asm-x86/unistd_64.h @@ -351,4 +351,5 @@ #define __NR_openat2 437 #define __NR_pidfd_getfd 438 + #endif /* _ASM_X86_UNISTD_64_H */ diff --git a/linux-headers/asm-x86/unistd_x32.h b/linux-headers/asm-x86/unistd_x32.h index 010307757b..e3f17ef370 100644 --- a/linux-headers/asm-x86/unistd_x32.h +++ b/linux-headers/asm-x86/unistd_x32.h @@ -340,4 +340,5 @@ #define __NR_preadv2 (__X32_SYSCALL_BIT + 546) #define __NR_pwritev2 (__X32_SYSCALL_BIT + 547) + #endif /* _ASM_X86_UNISTD_X32_H */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 265099100e..9804495a46 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -474,12 +474,17 @@ struct kvm_s390_mem_op { __u32 size; /* amount of bytes */ __u32 op; /* type of operation */ __u64 buf; /* buffer in userspace */ - __u8 ar; /* the access register number */ - __u8 reserved[31]; /* should be set to 0 */ + union { + __u8 ar; /* the access register number */ + __u32 sida_offset; /* offset into the sida */ + __u8 reserved[32]; /* should be set to 0 */ + }; }; /* types for kvm_s390_mem_op->op */ #define KVM_S390_MEMOP_LOGICAL_READ 0 #define KVM_S390_MEMOP_LOGICAL_WRITE 1 +#define KVM_S390_MEMOP_SIDA_READ 2 +#define KVM_S390_MEMOP_SIDA_WRITE 3 /* flags for kvm_s390_mem_op->flags */ #define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0) #define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1) @@ -1010,6 +1015,8 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_ARM_NISV_TO_USER 177 #define KVM_CAP_ARM_INJECT_EXT_DABT 178 #define KVM_CAP_S390_VCPU_RESETS 179 +#define KVM_CAP_S390_PROTECTED 180 +#define KVM_CAP_PPC_SECURE_GUEST 181 #ifdef KVM_CAP_IRQ_ROUTING @@ -1478,6 +1485,39 @@ struct kvm_enc_region { #define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3) #define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4) +struct kvm_s390_pv_sec_parm { + __u64 origin; + __u64 length; +}; + +struct kvm_s390_pv_unp { + __u64 addr; + __u64 size; + __u64 tweak; +}; + +enum pv_cmd_id { + KVM_PV_ENABLE, + KVM_PV_DISABLE, + KVM_PV_SET_SEC_PARMS, + KVM_PV_UNPACK, + KVM_PV_VERIFY, + KVM_PV_PREP_RESET, + KVM_PV_UNSHARE_ALL, +}; + +struct kvm_pv_cmd { + __u32 cmd; /* Command to be executed */ + __u16 rc; /* Ultravisor return code */ + __u16 rrc; /* Ultravisor return reason code */ + __u64 data; /* Data or address */ + __u32 flags; /* flags for future extensions. Must be 0 for now */ + __u32 reserved[3]; +}; + +/* Available with KVM_CAP_S390_PROTECTED */ +#define KVM_S390_PV_COMMAND _IOWR(KVMIO, 0xc5, struct kvm_pv_cmd) + /* Secure Encrypted Virtualization command */ enum sev_cmd_id { /* Guest initialization commands */ @@ -1628,4 +1668,7 @@ struct kvm_hyperv_eventfd { #define KVM_HYPERV_CONN_ID_MASK 0x00ffffff #define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0) +#define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (1 << 0) +#define KVM_DIRTY_LOG_INITIALLY_SET (1 << 1) + #endif /* __LINUX_KVM_H */ diff --git a/linux-headers/linux/mman.h b/linux-headers/linux/mman.h index 1f6e2cd89c..51ea363759 100644 --- a/linux-headers/linux/mman.h +++ b/linux-headers/linux/mman.h @@ -5,8 +5,9 @@ #include #include -#define MREMAP_MAYMOVE 1 -#define MREMAP_FIXED 2 +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 +#define MREMAP_DONTUNMAP 4 #define OVERCOMMIT_GUESS 0 #define OVERCOMMIT_ALWAYS 1 diff --git a/linux-headers/linux/userfaultfd.h b/linux-headers/linux/userfaultfd.h index ce78878d12..8d3996eb82 100644 --- a/linux-headers/linux/userfaultfd.h +++ b/linux-headers/linux/userfaultfd.h @@ -19,7 +19,8 @@ * means the userland is reading). */ #define UFFD_API ((__u64)0xAA) -#define UFFD_API_FEATURES (UFFD_FEATURE_EVENT_FORK | \ +#define UFFD_API_FEATURES (UFFD_FEATURE_PAGEFAULT_FLAG_WP | \ + UFFD_FEATURE_EVENT_FORK | \ UFFD_FEATURE_EVENT_REMAP | \ UFFD_FEATURE_EVENT_REMOVE | \ UFFD_FEATURE_EVENT_UNMAP | \ @@ -34,7 +35,8 @@ #define UFFD_API_RANGE_IOCTLS \ ((__u64)1 << _UFFDIO_WAKE | \ (__u64)1 << _UFFDIO_COPY | \ - (__u64)1 << _UFFDIO_ZEROPAGE) + (__u64)1 << _UFFDIO_ZEROPAGE | \ + (__u64)1 << _UFFDIO_WRITEPROTECT) #define UFFD_API_RANGE_IOCTLS_BASIC \ ((__u64)1 << _UFFDIO_WAKE | \ (__u64)1 << _UFFDIO_COPY) @@ -52,6 +54,7 @@ #define _UFFDIO_WAKE (0x02) #define _UFFDIO_COPY (0x03) #define _UFFDIO_ZEROPAGE (0x04) +#define _UFFDIO_WRITEPROTECT (0x06) #define _UFFDIO_API (0x3F) /* userfaultfd ioctl ids */ @@ -68,6 +71,8 @@ struct uffdio_copy) #define UFFDIO_ZEROPAGE _IOWR(UFFDIO, _UFFDIO_ZEROPAGE, \ struct uffdio_zeropage) +#define UFFDIO_WRITEPROTECT _IOWR(UFFDIO, _UFFDIO_WRITEPROTECT, \ + struct uffdio_writeprotect) /* read() structure */ struct uffd_msg { @@ -203,13 +208,14 @@ struct uffdio_copy { __u64 dst; __u64 src; __u64 len; - /* - * There will be a wrprotection flag later that allows to map - * pages wrprotected on the fly. And such a flag will be - * available if the wrprotection ioctl are implemented for the - * range according to the uffdio_register.ioctls. - */ #define UFFDIO_COPY_MODE_DONTWAKE ((__u64)1<<0) + /* + * UFFDIO_COPY_MODE_WP will map the page write protected on + * the fly. UFFDIO_COPY_MODE_WP is available only if the + * write protected ioctl is implemented for the range + * according to the uffdio_register.ioctls. + */ +#define UFFDIO_COPY_MODE_WP ((__u64)1<<1) __u64 mode; /* @@ -231,4 +237,24 @@ struct uffdio_zeropage { __s64 zeropage; }; +struct uffdio_writeprotect { + struct uffdio_range range; +/* + * UFFDIO_WRITEPROTECT_MODE_WP: set the flag to write protect a range, + * unset the flag to undo protection of a range which was previously + * write protected. + * + * UFFDIO_WRITEPROTECT_MODE_DONTWAKE: set the flag to avoid waking up + * any wait thread after the operation succeeds. + * + * NOTE: Write protecting a region (WP=1) is unrelated to page faults, + * therefore DONTWAKE flag is meaningless with WP=1. Removing write + * protection (WP=0) in response to a page fault wakes the faulting + * task unless DONTWAKE is set. + */ +#define UFFDIO_WRITEPROTECT_MODE_WP ((__u64)1<<0) +#define UFFDIO_WRITEPROTECT_MODE_DONTWAKE ((__u64)1<<1) + __u64 mode; +}; + #endif /* _LINUX_USERFAULTFD_H */ diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index fb10370d29..a41c452865 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -707,6 +707,43 @@ struct vfio_device_ioeventfd { #define VFIO_DEVICE_IOEVENTFD _IO(VFIO_TYPE, VFIO_BASE + 16) +/** + * VFIO_DEVICE_FEATURE - _IORW(VFIO_TYPE, VFIO_BASE + 17, + * struct vfio_device_feature) + * + * Get, set, or probe feature data of the device. The feature is selected + * using the FEATURE_MASK portion of the flags field. Support for a feature + * can be probed by setting both the FEATURE_MASK and PROBE bits. A probe + * may optionally include the GET and/or SET bits to determine read vs write + * access of the feature respectively. Probing a feature will return success + * if the feature is supported and all of the optionally indicated GET/SET + * methods are supported. The format of the data portion of the structure is + * specific to the given feature. The data portion is not required for + * probing. GET and SET are mutually exclusive, except for use with PROBE. + * + * Return 0 on success, -errno on failure. + */ +struct vfio_device_feature { + __u32 argsz; + __u32 flags; +#define VFIO_DEVICE_FEATURE_MASK (0xffff) /* 16-bit feature index */ +#define VFIO_DEVICE_FEATURE_GET (1 << 16) /* Get feature into data[] */ +#define VFIO_DEVICE_FEATURE_SET (1 << 17) /* Set feature from data[] */ +#define VFIO_DEVICE_FEATURE_PROBE (1 << 18) /* Probe feature support */ + __u8 data[]; +}; + +#define VFIO_DEVICE_FEATURE _IO(VFIO_TYPE, VFIO_BASE + 17) + +/* + * Provide support for setting a PCI VF Token, which is used as a shared + * secret between PF and VF drivers. This feature may only be set on a + * PCI SR-IOV PF when SR-IOV is enabled on the PF and there are no existing + * open VFs. Data provided when setting this feature is a 16-byte array + * (__u8 b[16]), representing a UUID. + */ +#define VFIO_DEVICE_FEATURE_PCI_VF_TOKEN (0) + /* -------- API for Type1 VFIO IOMMU -------- */ /** diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h index 40d028eed6..9fe72e4b13 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -116,4 +116,28 @@ #define VHOST_VSOCK_SET_GUEST_CID _IOW(VHOST_VIRTIO, 0x60, __u64) #define VHOST_VSOCK_SET_RUNNING _IOW(VHOST_VIRTIO, 0x61, int) +/* VHOST_VDPA specific defines */ + +/* Get the device id. The device ids follow the same definition of + * the device id defined in virtio-spec. + */ +#define VHOST_VDPA_GET_DEVICE_ID _IOR(VHOST_VIRTIO, 0x70, __u32) +/* Get and set the status. The status bits follow the same definition + * of the device status defined in virtio-spec. + */ +#define VHOST_VDPA_GET_STATUS _IOR(VHOST_VIRTIO, 0x71, __u8) +#define VHOST_VDPA_SET_STATUS _IOW(VHOST_VIRTIO, 0x72, __u8) +/* Get and set the device config. The device config follows the same + * definition of the device config defined in virtio-spec. + */ +#define VHOST_VDPA_GET_CONFIG _IOR(VHOST_VIRTIO, 0x73, \ + struct vhost_vdpa_config) +#define VHOST_VDPA_SET_CONFIG _IOW(VHOST_VIRTIO, 0x74, \ + struct vhost_vdpa_config) +/* Enable/disable the ring. */ +#define VHOST_VDPA_SET_VRING_ENABLE _IOW(VHOST_VIRTIO, 0x75, \ + struct vhost_vring_state) +/* Get the max ring size. */ +#define VHOST_VDPA_GET_VRING_NUM _IOR(VHOST_VIRTIO, 0x76, __u16) + #endif From 9b39d29470e9dbef24ee842a44ea56bd92b855ea Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:06 -0400 Subject: [PATCH 0003/2595] s390x: Move diagnose 308 subcodes and rcs into ipl.h They are part of the IPL process, so let's put them into the ipl header. Signed-off-by: Janosch Frank Reviewed-by: Cornelia Huck Reviewed-by: Christian Borntraeger Reviewed-by: David Hildenbrand Message-Id: <20200319131921.2367-2-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/ipl.h | 11 +++++++++++ target/s390x/diag.c | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index 3e44abe1c6..a5665e6bfd 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -159,6 +159,17 @@ struct S390IPLState { typedef struct S390IPLState S390IPLState; QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong"); +#define DIAG_308_RC_OK 0x0001 +#define DIAG_308_RC_NO_CONF 0x0102 +#define DIAG_308_RC_INVALID 0x0402 + +#define DIAG308_RESET_MOD_CLR 0 +#define DIAG308_RESET_LOAD_NORM 1 +#define DIAG308_LOAD_CLEAR 3 +#define DIAG308_LOAD_NORMAL_DUMP 4 +#define DIAG308_SET 5 +#define DIAG308_STORE 6 + #define S390_IPL_TYPE_FCP 0x00 #define S390_IPL_TYPE_CCW 0x02 #define S390_IPL_TYPE_QEMU_SCSI 0xff diff --git a/target/s390x/diag.c b/target/s390x/diag.c index 54e5670b3f..8aba6341f9 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -49,17 +49,6 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3) return diag288_class->handle_timer(diag288, func, timeout); } -#define DIAG_308_RC_OK 0x0001 -#define DIAG_308_RC_NO_CONF 0x0102 -#define DIAG_308_RC_INVALID 0x0402 - -#define DIAG308_RESET_MOD_CLR 0 -#define DIAG308_RESET_LOAD_NORM 1 -#define DIAG308_LOAD_CLEAR 3 -#define DIAG308_LOAD_NORMAL_DUMP 4 -#define DIAG308_SET 5 -#define DIAG308_STORE 6 - static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr, uintptr_t ra, bool write) { From 78ee6bd04821847036a805cb4bdd46464e1d3098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 13 Apr 2020 00:35:56 +0200 Subject: [PATCH 0004/2595] various: Remove suspicious '\' character outside of #define in C code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following coccinelle warnings: $ spatch --sp-file --verbose-parsing ... \ scripts/coccinelle/remove_local_err.cocci ... SUSPICIOUS: a \ character appears outside of a #define at ./target/ppc/translate_init.inc.c:5213 SUSPICIOUS: a \ character appears outside of a #define at ./target/ppc/translate_init.inc.c:5261 SUSPICIOUS: a \ character appears outside of a #define at ./target/microblaze/cpu.c:166 SUSPICIOUS: a \ character appears outside of a #define at ./target/microblaze/cpu.c:167 SUSPICIOUS: a \ character appears outside of a #define at ./target/microblaze/cpu.c:169 SUSPICIOUS: a \ character appears outside of a #define at ./target/microblaze/cpu.c:170 SUSPICIOUS: a \ character appears outside of a #define at ./target/microblaze/cpu.c:171 SUSPICIOUS: a \ character appears outside of a #define at ./target/microblaze/cpu.c:172 SUSPICIOUS: a \ character appears outside of a #define at ./target/microblaze/cpu.c:173 SUSPICIOUS: a \ character appears outside of a #define at ./target/i386/cpu.c:5787 SUSPICIOUS: a \ character appears outside of a #define at ./target/i386/cpu.c:5789 SUSPICIOUS: a \ character appears outside of a #define at ./target/i386/cpu.c:5800 SUSPICIOUS: a \ character appears outside of a #define at ./target/i386/cpu.c:5801 SUSPICIOUS: a \ character appears outside of a #define at ./target/i386/cpu.c:5802 SUSPICIOUS: a \ character appears outside of a #define at ./target/i386/cpu.c:5804 SUSPICIOUS: a \ character appears outside of a #define at ./target/i386/cpu.c:5805 SUSPICIOUS: a \ character appears outside of a #define at ./target/i386/cpu.c:5806 SUSPICIOUS: a \ character appears outside of a #define at ./target/i386/cpu.c:6329 SUSPICIOUS: a \ character appears outside of a #define at ./hw/sd/sdhci.c:1133 SUSPICIOUS: a \ character appears outside of a #define at ./hw/scsi/scsi-disk.c:3081 SUSPICIOUS: a \ character appears outside of a #define at ./hw/net/virtio-net.c:1529 SUSPICIOUS: a \ character appears outside of a #define at ./hw/riscv/sifive_u.c:468 SUSPICIOUS: a \ character appears outside of a #define at ./dump/dump.c:1895 SUSPICIOUS: a \ character appears outside of a #define at ./block/vhdx.c:2209 SUSPICIOUS: a \ character appears outside of a #define at ./block/vhdx.c:2215 SUSPICIOUS: a \ character appears outside of a #define at ./block/vhdx.c:2221 SUSPICIOUS: a \ character appears outside of a #define at ./block/vhdx.c:2222 SUSPICIOUS: a \ character appears outside of a #define at ./block/replication.c:172 SUSPICIOUS: a \ character appears outside of a #define at ./block/replication.c:173 Reviewed-by: Marc-André Lureau Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200412223619.11284-2-f4bug@amsat.org> Reviewed-by: Alistair Francis Acked-by: David Gibson Signed-off-by: Markus Armbruster --- block/replication.c | 4 ++-- block/vhdx.c | 8 ++++---- dump/dump.c | 2 +- hw/net/virtio-net.c | 2 +- hw/riscv/sifive_u.c | 2 +- hw/scsi/scsi-disk.c | 2 +- hw/sd/sdhci.c | 2 +- target/i386/cpu.c | 18 +++++++++--------- target/microblaze/cpu.c | 14 +++++++------- target/ppc/translate_init.inc.c | 4 ++-- 10 files changed, 29 insertions(+), 29 deletions(-) diff --git a/block/replication.c b/block/replication.c index da013c2041..971f0fe266 100644 --- a/block/replication.c +++ b/block/replication.c @@ -172,8 +172,8 @@ static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, if ((bs->open_flags & (BDRV_O_INACTIVE | BDRV_O_RDWR)) == BDRV_O_RDWR) { *nperm |= BLK_PERM_WRITE; } - *nshared = BLK_PERM_CONSISTENT_READ \ - | BLK_PERM_WRITE \ + *nshared = BLK_PERM_CONSISTENT_READ + | BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED; return; } diff --git a/block/vhdx.c b/block/vhdx.c index 33e57cd656..e16fdc2f2d 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -2206,20 +2206,20 @@ static QemuOptsList vhdx_create_opts = { .name = VHDX_BLOCK_OPT_BLOCK_SIZE, .type = QEMU_OPT_SIZE, .def_value_str = stringify(0), - .help = "Block Size; min 1MB, max 256MB. " \ + .help = "Block Size; min 1MB, max 256MB. " "0 means auto-calculate based on image size." }, { .name = BLOCK_OPT_SUBFMT, .type = QEMU_OPT_STRING, - .help = "VHDX format type, can be either 'dynamic' or 'fixed'. "\ + .help = "VHDX format type, can be either 'dynamic' or 'fixed'. " "Default is 'dynamic'." }, { .name = VHDX_BLOCK_OPT_ZERO, .type = QEMU_OPT_BOOL, - .help = "Force use of payload blocks of type 'ZERO'. "\ - "Non-standard, but default. Do not set to 'off' when "\ + .help = "Force use of payload blocks of type 'ZERO'. " + "Non-standard, but default. Do not set to 'off' when " "using 'qemu-img convert' with subformat=dynamic." }, { NULL } diff --git a/dump/dump.c b/dump/dump.c index 22ed1d3b0d..248ea06370 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -1892,7 +1892,7 @@ static void dump_process(DumpState *s, Error **errp) result = qmp_query_dump(NULL); /* should never fail */ assert(result); - qapi_event_send_dump_completed(result, !!local_err, (local_err ? \ + qapi_event_send_dump_completed(result, !!local_err, (local_err ? error_get_pretty(local_err) : NULL)); qapi_free_DumpQueryResult(result); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index a46e3b37a7..eddfa7f923 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1526,7 +1526,7 @@ static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain, + sizeof(struct eth_header)); unit->ip = ip6; unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); - unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\ + unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + sizeof(struct ip6_header)); unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 56351c4faa..998666c91f 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -465,7 +465,7 @@ static void riscv_sifive_u_machine_instance_init(Object *obj) object_property_add_bool(obj, "start-in-flash", sifive_u_get_start_in_flash, sifive_u_set_start_in_flash, NULL); object_property_set_description(obj, "start-in-flash", - "Set on to tell QEMU's ROM to jump to " \ + "Set on to tell QEMU's ROM to jump to " "flash. Otherwise QEMU will jump to DRAM", NULL); } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 1c0cb63a6f..e5bcd0baf8 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -3078,7 +3078,7 @@ static const TypeInfo scsi_cd_info = { #ifdef __linux__ static Property scsi_block_properties[] = { - DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \ + DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk), DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false), DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index de63ffb037..70531ad360 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1130,7 +1130,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) /* Limit block size to the maximum buffer size */ if (extract32(s->blksize, 0, 12) > s->buf_maxsz) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than " \ + qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than " "the maximum buffer 0x%x", __func__, s->blksize, s->buf_maxsz); diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 90ffc5f3b1..9c256ab159 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5784,9 +5784,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, host_cpuid(index, 0, eax, ebx, ecx, edx); break; } - *eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | \ + *eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | (L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES); - *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \ + *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | (L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES); *ecx = encode_cache_cpuid80000005(env->cache_info_amd.l1d_cache); *edx = encode_cache_cpuid80000005(env->cache_info_amd.l1i_cache); @@ -5797,13 +5797,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, host_cpuid(index, 0, eax, ebx, ecx, edx); break; } - *eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | \ - (L2_DTLB_2M_ENTRIES << 16) | \ - (AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | \ + *eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | + (L2_DTLB_2M_ENTRIES << 16) | + (AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | (L2_ITLB_2M_ENTRIES); - *ebx = (AMD_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) | \ - (L2_DTLB_4K_ENTRIES << 16) | \ - (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \ + *ebx = (AMD_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) | + (L2_DTLB_4K_ENTRIES << 16) | + (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | (L2_ITLB_4K_ENTRIES); encode_cache_cpuid80000006(env->cache_info_amd.l2_cache, cpu->enable_l3_cache ? @@ -6326,7 +6326,7 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) */ env->features[w] |= x86_cpu_get_supported_feature_word(w, cpu->migratable) & - ~env->user_features[w] & \ + ~env->user_features[w] & ~feature_word_info[w].no_autoenable_flags; } } diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index a2c2f271df..c9cf2364ca 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -163,14 +163,14 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) qemu_init_vcpu(cs); - env->pvr.regs[0] = PVR0_USE_EXC_MASK \ - | PVR0_USE_ICACHE_MASK \ + env->pvr.regs[0] = PVR0_USE_EXC_MASK + | PVR0_USE_ICACHE_MASK | PVR0_USE_DCACHE_MASK; - env->pvr.regs[2] = PVR2_D_OPB_MASK \ - | PVR2_D_LMB_MASK \ - | PVR2_I_OPB_MASK \ - | PVR2_I_LMB_MASK \ - | PVR2_FPU_EXC_MASK \ + env->pvr.regs[2] = PVR2_D_OPB_MASK + | PVR2_D_LMB_MASK + | PVR2_I_OPB_MASK + | PVR2_I_LMB_MASK + | PVR2_FPU_EXC_MASK | 0; version = cpu->cfg.version ? cpu->cfg.version : DEFAULT_CPU_VERSION; diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index e853164a86..fd763e588e 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -5210,7 +5210,7 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) PPC_FLOAT_STFIWX | PPC_WAIT | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | PPC_64B | PPC_POPCNTB | PPC_POPCNTWD; - pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | \ + pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | PPC2_FP_CVT_S64; pcc->msr_mask = (1ull << MSR_CM) | (1ull << MSR_GS) | @@ -5258,7 +5258,7 @@ POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data) PPC_FLOAT_STFIWX | PPC_WAIT | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | PPC_64B | PPC_POPCNTB | PPC_POPCNTWD | PPC_ALTIVEC; - pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | \ + pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | PPC2_FP_CVT_S64 | PPC2_ATOMIC_ISA206; pcc->msr_mask = (1ull << MSR_CM) | (1ull << MSR_GS) | From 32c2dcf5e87bf05153df92e49de75f72d4466e4e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 09:49:19 +0200 Subject: [PATCH 0005/2595] tests-qemu-opts: Cover has_help_option(), qemu_opt_has_help_opt() The two turn out to be inconsistent for "a,b,,help". Test case marked /* BUG */. Signed-off-by: Markus Armbruster Message-Id: <20200415074927.19897-2-armbru@redhat.com> Reviewed-by: Eric Blake --- tests/test-qemu-opts.c | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index ef96e84aed..88a3e7bdf4 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -728,6 +728,49 @@ static void test_opts_parse_size(void) qemu_opts_reset(&opts_list_02); } +static void test_has_help_option(void) +{ + static const struct { + const char *params; + /* expected value of has_help_option() */ + bool expect_has_help_option; + /* expected value of qemu_opt_has_help_opt() with implied=false */ + bool expect_opt_has_help_opt; + /* expected value of qemu_opt_has_help_opt() with implied=true */ + bool expect_opt_has_help_opt_implied; + } test[] = { + { "help", true, true, false }, + { "?", true, true, false }, + { "helpme", false, false, false }, + { "?me", false, false, false }, + { "a,help", true, true, true }, + { "a,?", true, true, true }, + { "a=0,help,b", true, true, true }, + { "a=0,?,b", true, true, true }, + { "help,b=1", true, true, false }, + { "?,b=1", true, true, false }, + { "a,b,,help", false /* BUG */, true, true }, + { "a,b,,?", false /* BUG */, true, true }, + }; + int i; + QemuOpts *opts; + + for (i = 0; i < ARRAY_SIZE(test); i++) { + g_assert_cmpint(has_help_option(test[i].params), + ==, test[i].expect_has_help_option); + opts = qemu_opts_parse(&opts_list_03, test[i].params, false, + &error_abort); + g_assert_cmpint(qemu_opt_has_help_opt(opts), + ==, test[i].expect_opt_has_help_opt); + qemu_opts_del(opts); + opts = qemu_opts_parse(&opts_list_03, test[i].params, true, + &error_abort); + g_assert_cmpint(qemu_opt_has_help_opt(opts), + ==, test[i].expect_opt_has_help_opt_implied); + qemu_opts_del(opts); + } +} + static void append_verify_list_01(QemuOptDesc *desc, bool with_overlapping) { int i = 0; @@ -990,6 +1033,7 @@ int main(int argc, char *argv[]) g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool); g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number); g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size); + g_test_add_func("/qemu-opts/has_help_option", test_has_help_option); g_test_add_func("/qemu-opts/append_to_null", test_opts_append_to_null); g_test_add_func("/qemu-opts/append", test_opts_append); g_test_add_func("/qemu-opts/to_qdict/basic", test_opts_to_qdict_basic); From 6129803b55553b90805aa5012077b21c6c6eacdc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 09:49:20 +0200 Subject: [PATCH 0006/2595] qemu-options: Factor out get_opt_name_value() helper The next commits will put it to use. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Kevin Wolf Message-Id: <20200415074927.19897-3-armbru@redhat.com> --- util/qemu-option.c | 102 +++++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 46 deletions(-) diff --git a/util/qemu-option.c b/util/qemu-option.c index 97172b5eaa..f08f4bc458 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -805,61 +805,71 @@ void qemu_opts_print(QemuOpts *opts, const char *separator) } } +static const char *get_opt_name_value(const char *params, + const char *firstname, + char **name, char **value) +{ + const char *p, *pe, *pc; + + pe = strchr(params, '='); + pc = strchr(params, ','); + + if (!pe || (pc && pc < pe)) { + /* found "foo,more" */ + if (firstname) { + /* implicitly named first option */ + *name = g_strdup(firstname); + p = get_opt_value(params, value); + } else { + /* option without value, must be a flag */ + p = get_opt_name(params, name, ','); + if (strncmp(*name, "no", 2) == 0) { + memmove(*name, *name + 2, strlen(*name + 2) + 1); + *value = g_strdup("off"); + } else { + *value = g_strdup("on"); + } + } + } else { + /* found "foo=bar,more" */ + p = get_opt_name(params, name, '='); + assert(*p == '='); + p++; + p = get_opt_value(p, value); + } + + assert(!*p || *p == ','); + if (*p == ',') { + p++; + } + return p; +} + static void opts_do_parse(QemuOpts *opts, const char *params, const char *firstname, bool prepend, bool *invalidp, Error **errp) { - char *option = NULL; - char *value = NULL; - const char *p,*pe,*pc; Error *local_err = NULL; + char *option, *value; + const char *p; - for (p = params; *p != '\0'; p++) { - pe = strchr(p, '='); - pc = strchr(p, ','); - if (!pe || (pc && pc < pe)) { - /* found "foo,more" */ - if (p == params && firstname) { - /* implicitly named first option */ - option = g_strdup(firstname); - p = get_opt_value(p, &value); - } else { - /* option without value, probably a flag */ - p = get_opt_name(p, &option, ','); - if (strncmp(option, "no", 2) == 0) { - memmove(option, option+2, strlen(option+2)+1); - value = g_strdup("off"); - } else { - value = g_strdup("on"); - } - } - } else { - /* found "foo=bar,more" */ - p = get_opt_name(p, &option, '='); - assert(*p == '='); - p++; - p = get_opt_value(p, &value); - } - if (strcmp(option, "id") != 0) { - /* store and parse */ - opt_set(opts, option, value, prepend, invalidp, &local_err); - value = NULL; - if (local_err) { - error_propagate(errp, local_err); - goto cleanup; - } - } - if (*p != ',') { - break; + for (p = params; *p;) { + p = get_opt_name_value(p, firstname, &option, &value); + firstname = NULL; + + if (!strcmp(option, "id")) { + g_free(option); + g_free(value); + continue; } + + opt_set(opts, option, value, prepend, invalidp, &local_err); g_free(option); - g_free(value); - option = value = NULL; + if (local_err) { + error_propagate(errp, local_err); + return; + } } - - cleanup: - g_free(option); - g_free(value); } /** From 933d1527785fe839300459abb486905094d192a7 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 09:49:21 +0200 Subject: [PATCH 0007/2595] qemu-option: Fix sloppy recognition of "id=..." after ",," Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Kevin Wolf Message-Id: <20200415074927.19897-4-armbru@redhat.com> --- tests/test-qemu-opts.c | 4 ++-- util/qemu-option.c | 27 +++++++++++++++++++-------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index 88a3e7bdf4..8ff97268d8 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -500,10 +500,10 @@ static void test_opts_parse(void) g_assert(!opts); /* TODO Cover .merge_lists = true */ - /* Buggy ID recognition */ + /* Buggy ID recognition (fixed) */ opts = qemu_opts_parse(&opts_list_03, "x=,,id=bar", false, &error_abort); g_assert_cmpuint(opts_count(opts), ==, 1); - g_assert_cmpstr(qemu_opts_id(opts), ==, "bar"); /* BUG */ + g_assert(!qemu_opts_id(opts)); g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, ",id=bar"); /* Anti-social ID */ diff --git a/util/qemu-option.c b/util/qemu-option.c index f08f4bc458..d2956082bd 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -872,6 +872,24 @@ static void opts_do_parse(QemuOpts *opts, const char *params, } } +static char *opts_parse_id(const char *params) +{ + const char *p; + char *name, *value; + + for (p = params; *p;) { + p = get_opt_name_value(p, NULL, &name, &value); + if (!strcmp(name, "id")) { + g_free(name); + return value; + } + g_free(name); + g_free(value); + } + + return NULL; +} + /** * Store options parsed from @params into @opts. * If @firstname is non-null, the first key=value in @params may omit @@ -889,20 +907,13 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, bool *invalidp, Error **errp) { const char *firstname; - char *id = NULL; - const char *p; + char *id = opts_parse_id(params); QemuOpts *opts; Error *local_err = NULL; assert(!permit_abbrev || list->implied_opt_name); firstname = permit_abbrev ? list->implied_opt_name : NULL; - if (strncmp(params, "id=", 3) == 0) { - get_opt_value(params + 3, &id); - } else if ((p = strstr(params, ",id=")) != NULL) { - get_opt_value(p + 4, &id); - } - /* * This code doesn't work for defaults && !list->merge_lists: when * params has no id=, and list has an element with !opts->id, it From 80a94855737622436a9b5cd25315b9c80d7e3ffa Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 09:49:22 +0200 Subject: [PATCH 0008/2595] qemu-option: Fix has_help_option()'s sloppy parsing has_help_option() uses its own parser. It's inconsistent with qemu_opts_parse(), as demonstrated by test-qemu-opts case /qemu-opts/has_help_option. Fix by reusing the common parser. Signed-off-by: Markus Armbruster Message-Id: <20200415074927.19897-5-armbru@redhat.com> Reviewed-by: Eric Blake --- tests/test-qemu-opts.c | 4 ++-- util/qemu-option.c | 39 +++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index 8ff97268d8..77c944c4aa 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -749,8 +749,8 @@ static void test_has_help_option(void) { "a=0,?,b", true, true, true }, { "help,b=1", true, true, false }, { "?,b=1", true, true, false }, - { "a,b,,help", false /* BUG */, true, true }, - { "a,b,,?", false /* BUG */, true, true }, + { "a,b,,help", true, true, true }, + { "a,b,,?", true, true, true }, }; int i; QemuOpts *opts; diff --git a/util/qemu-option.c b/util/qemu-option.c index d2956082bd..0abf26b61f 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -165,26 +165,6 @@ void parse_option_size(const char *name, const char *value, *ret = size; } -bool has_help_option(const char *param) -{ - const char *p = param; - bool result = false; - - while (*p && !result) { - char *value; - - p = get_opt_value(p, &value); - if (*p) { - p++; - } - - result = is_help_option(value); - g_free(value); - } - - return result; -} - bool is_valid_option_list(const char *p) { char *value = NULL; @@ -890,6 +870,25 @@ static char *opts_parse_id(const char *params) return NULL; } +bool has_help_option(const char *params) +{ + const char *p; + char *name, *value; + bool ret; + + for (p = params; *p;) { + p = get_opt_name_value(p, NULL, &name, &value); + ret = is_help_option(name); + g_free(name); + g_free(value); + if (ret) { + return true; + } + } + + return false; +} + /** * Store options parsed from @params into @opts. * If @firstname is non-null, the first key=value in @params may omit From 59d27ebc446baec4a972cc146df732910b5aa2de Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 09:49:23 +0200 Subject: [PATCH 0009/2595] test-qemu-opts: Simplify test_has_help_option() after bug fix Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Kevin Wolf Message-Id: <20200415074927.19897-6-armbru@redhat.com> --- tests/test-qemu-opts.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index 77c944c4aa..2a0f42a09b 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -732,41 +732,39 @@ static void test_has_help_option(void) { static const struct { const char *params; - /* expected value of has_help_option() */ - bool expect_has_help_option; /* expected value of qemu_opt_has_help_opt() with implied=false */ - bool expect_opt_has_help_opt; + bool expect; /* expected value of qemu_opt_has_help_opt() with implied=true */ - bool expect_opt_has_help_opt_implied; + bool expect_implied; } test[] = { - { "help", true, true, false }, - { "?", true, true, false }, - { "helpme", false, false, false }, - { "?me", false, false, false }, - { "a,help", true, true, true }, - { "a,?", true, true, true }, - { "a=0,help,b", true, true, true }, - { "a=0,?,b", true, true, true }, - { "help,b=1", true, true, false }, - { "?,b=1", true, true, false }, - { "a,b,,help", true, true, true }, - { "a,b,,?", true, true, true }, + { "help", true, false }, + { "?", true, false }, + { "helpme", false, false }, + { "?me", false, false }, + { "a,help", true, true }, + { "a,?", true, true }, + { "a=0,help,b", true, true }, + { "a=0,?,b", true, true }, + { "help,b=1", true, false }, + { "?,b=1", true, false }, + { "a,b,,help", true, true }, + { "a,b,,?", true, true }, }; int i; QemuOpts *opts; for (i = 0; i < ARRAY_SIZE(test); i++) { g_assert_cmpint(has_help_option(test[i].params), - ==, test[i].expect_has_help_option); + ==, test[i].expect); opts = qemu_opts_parse(&opts_list_03, test[i].params, false, &error_abort); g_assert_cmpint(qemu_opt_has_help_opt(opts), - ==, test[i].expect_opt_has_help_opt); + ==, test[i].expect); qemu_opts_del(opts); opts = qemu_opts_parse(&opts_list_03, test[i].params, true, &error_abort); g_assert_cmpint(qemu_opt_has_help_opt(opts), - ==, test[i].expect_opt_has_help_opt_implied); + ==, test[i].expect_implied); qemu_opts_del(opts); } } From 56a9efa199a603b77e7f2bd0e84e11e897bf7473 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 09:49:24 +0200 Subject: [PATCH 0010/2595] qemu-option: Avoid has_help_option() in qemu_opts_parse_noisily() When opts_parse() sets @invalidp to true, qemu_opts_parse_noisily() uses has_help_option() to decide whether to print help. This parses the input string a second time. Easy to avoid: replace @invalidp by @help_wanted. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200415074927.19897-7-armbru@redhat.com> --- util/qemu-option.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/util/qemu-option.c b/util/qemu-option.c index 0abf26b61f..2d0d24ee27 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -519,7 +519,7 @@ int qemu_opt_unset(QemuOpts *opts, const char *name) } static void opt_set(QemuOpts *opts, const char *name, char *value, - bool prepend, bool *invalidp, Error **errp) + bool prepend, bool *help_wanted, Error **errp) { QemuOpt *opt; const QemuOptDesc *desc; @@ -529,8 +529,8 @@ static void opt_set(QemuOpts *opts, const char *name, char *value, if (!desc && !opts_accepts_any(opts)) { g_free(value); error_setg(errp, QERR_INVALID_PARAMETER, name); - if (invalidp) { - *invalidp = true; + if (help_wanted && is_help_option(name)) { + *help_wanted = true; } return; } @@ -827,7 +827,7 @@ static const char *get_opt_name_value(const char *params, static void opts_do_parse(QemuOpts *opts, const char *params, const char *firstname, bool prepend, - bool *invalidp, Error **errp) + bool *help_wanted, Error **errp) { Error *local_err = NULL; char *option, *value; @@ -843,7 +843,7 @@ static void opts_do_parse(QemuOpts *opts, const char *params, continue; } - opt_set(opts, option, value, prepend, invalidp, &local_err); + opt_set(opts, option, value, prepend, help_wanted, &local_err); g_free(option); if (local_err) { error_propagate(errp, local_err); @@ -903,7 +903,7 @@ void qemu_opts_do_parse(QemuOpts *opts, const char *params, static QemuOpts *opts_parse(QemuOptsList *list, const char *params, bool permit_abbrev, bool defaults, - bool *invalidp, Error **errp) + bool *help_wanted, Error **errp) { const char *firstname; char *id = opts_parse_id(params); @@ -928,7 +928,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, return NULL; } - opts_do_parse(opts, params, firstname, defaults, invalidp, &local_err); + opts_do_parse(opts, params, firstname, defaults, help_wanted, &local_err); if (local_err) { error_propagate(errp, local_err); qemu_opts_del(opts); @@ -964,11 +964,11 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params, { Error *err = NULL; QemuOpts *opts; - bool invalidp = false; + bool help_wanted = false; - opts = opts_parse(list, params, permit_abbrev, false, &invalidp, &err); + opts = opts_parse(list, params, permit_abbrev, false, &help_wanted, &err); if (err) { - if (invalidp && has_help_option(params)) { + if (help_wanted) { qemu_opts_print_help(list, true); error_free(err); } else { From 6d2b5cbafb8fb4bb3563cbf698b3a0903a993d7a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 09:49:25 +0200 Subject: [PATCH 0011/2595] qemu-img: Factor out accumulate_options() helper Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Kevin Wolf Message-Id: <20200415074927.19897-8-armbru@redhat.com> --- qemu-img.c | 59 +++++++++++++++++++++--------------------------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 821cbf610e..d36b21b758 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -223,6 +223,25 @@ static bool qemu_img_object_print_help(const char *type, QemuOpts *opts) return true; } +static int accumulate_options(char **options, char *optarg) +{ + char *new_options; + + if (!is_valid_option_list(optarg)) { + error_report("Invalid option list: %s", optarg); + return -1; + } + + if (!*options) { + *options = g_strdup(optarg); + } else { + new_options = g_strdup_printf("%s,%s", *options, optarg); + g_free(*options); + *options = new_options; + } + return 0; +} + static QemuOptsList qemu_source_opts = { .name = "source", .implied_opt_name = "file", @@ -482,17 +501,9 @@ static int img_create(int argc, char **argv) fmt = optarg; break; case 'o': - if (!is_valid_option_list(optarg)) { - error_report("Invalid option list: %s", optarg); + if (accumulate_options(&options, optarg) < 0) { goto fail; } - if (!options) { - options = g_strdup(optarg); - } else { - char *old_options = options; - options = g_strdup_printf("%s,%s", options, optarg); - g_free(old_options); - } break; case 'q': quiet = true; @@ -2127,17 +2138,9 @@ static int img_convert(int argc, char **argv) s.compressed = true; break; case 'o': - if (!is_valid_option_list(optarg)) { - error_report("Invalid option list: %s", optarg); + if (accumulate_options(&options, optarg) < 0) { goto fail_getopt; } - if (!options) { - options = g_strdup(optarg); - } else { - char *old_options = options; - options = g_strdup_printf("%s,%s", options, optarg); - g_free(old_options); - } break; case 'l': if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) { @@ -3953,18 +3956,10 @@ static int img_amend(int argc, char **argv) help(); break; case 'o': - if (!is_valid_option_list(optarg)) { - error_report("Invalid option list: %s", optarg); + if (accumulate_options(&options, optarg) < 0) { ret = -1; goto out_no_progress; } - if (!options) { - options = g_strdup(optarg); - } else { - char *old_options = options; - options = g_strdup_printf("%s,%s", options, optarg); - g_free(old_options); - } break; case 'f': fmt = optarg; @@ -4855,17 +4850,9 @@ static int img_measure(int argc, char **argv) out_fmt = optarg; break; case 'o': - if (!is_valid_option_list(optarg)) { - error_report("Invalid option list: %s", optarg); + if (accumulate_options(&options, optarg) < 0) { goto out; } - if (!options) { - options = g_strdup(optarg); - } else { - char *old_options = options; - options = g_strdup_printf("%s,%s", options, optarg); - g_free(old_options); - } break; case 'l': if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) { From 80c710cb06ff40b45de033e4352528b3adcd2de9 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 09:49:26 +0200 Subject: [PATCH 0012/2595] qemu-img: Move is_valid_option_list() to qemu-img.c and rewrite is_valid_option_list()'s purpose is ensuring qemu-img.c's can safely join multiple parameter strings separated by ',' like this: g_strdup_printf("%s,%s", params1, params2); How it does that is anything but obvious. A close reading of the code reveals that it fails exactly when its argument starts with ',' or ends with an odd number of ','. Makes sense, actually, because when the argument starts with ',', a separating ',' preceding it would get escaped, and when it ends with an odd number of ',', a separating ',' following it would get escaped. Move it to qemu-img.c and rewrite it the obvious way. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200415074927.19897-9-armbru@redhat.com> --- include/qemu/option.h | 1 - qemu-img.c | 26 ++++++++++++++++++++++++++ util/qemu-option.c | 22 ---------------------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/include/qemu/option.h b/include/qemu/option.h index 844587cab3..eb4097889d 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -33,7 +33,6 @@ const char *get_opt_value(const char *p, char **value); void parse_option_size(const char *name, const char *value, uint64_t *ret, Error **errp); bool has_help_option(const char *param); -bool is_valid_option_list(const char *param); enum QemuOptType { QEMU_OPT_STRING = 0, /* no parsing (use string as-is) */ diff --git a/qemu-img.c b/qemu-img.c index d36b21b758..cc51db7ed4 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -223,6 +223,32 @@ static bool qemu_img_object_print_help(const char *type, QemuOpts *opts) return true; } +/* + * Is @optarg safe for accumulate_options()? + * It is when multiple of them can be joined together separated by ','. + * To make that work, @optarg must not start with ',' (or else a + * separating ',' preceding it gets escaped), and it must not end with + * an odd number of ',' (or else a separating ',' following it gets + * escaped). + */ +static bool is_valid_option_list(const char *optarg) +{ + size_t len = strlen(optarg); + size_t i; + + if (optarg[0] == ',') { + return false; + } + + for (i = len; i > 0 && optarg[i - 1] == ','; i--) { + } + if ((len - i) % 2) { + return false; + } + + return true; +} + static int accumulate_options(char **options, char *optarg) { char *new_options; diff --git a/util/qemu-option.c b/util/qemu-option.c index 2d0d24ee27..9542988183 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -165,28 +165,6 @@ void parse_option_size(const char *name, const char *value, *ret = size; } -bool is_valid_option_list(const char *p) -{ - char *value = NULL; - bool result = false; - - while (*p) { - p = get_opt_value(p, &value); - if ((*p && !*++p) || - (!*value || *value == ',')) { - goto out; - } - - g_free(value); - value = NULL; - } - - result = true; -out: - g_free(value); - return result; -} - static const char *opt_type_to_string(enum QemuOptType type) { switch (type) { From f62514b3def5fb2acbef64d0e053c0c31fa45aff Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 09:49:27 +0200 Subject: [PATCH 0013/2595] qemu-img: Reject broken -o "" qemu-img create, convert, amend, and measure use accumulate_options() to merge multiple -o options. This is broken for -o "": $ qemu-img create -f qcow2 -o backing_file=a -o "" -o backing_fmt=raw,size=1M new.qcow2 qemu-img: warning: Could not verify backing image. This may become an error in future versions. Could not open 'a,backing_fmt=raw': No such file or directory Formatting 'new.qcow2', fmt=qcow2 size=1048576 backing_file=a,,backing_fmt=raw cluster_size=65536 lazy_refcounts=off refcount_bits=16 $ qemu-img info new.qcow2 image: new.qcow2 file format: qcow2 virtual size: 1 MiB (1048576 bytes) disk size: 196 KiB cluster_size: 65536 --> backing file: a,backing_fmt=raw Format specific information: compat: 1.1 lazy refcounts: false refcount bits: 16 corrupt: false Merging these three -o the obvious way is wrong, because it results in an unwanted ',' escape: backing_file=a,,backing_fmt=raw,size=1M ~~ We could silently drop -o "", but Kevin asked me to reject it instead. Signed-off-by: Markus Armbruster Message-Id: <20200415074927.19897-10-armbru@redhat.com> Reviewed-by: Eric Blake --- qemu-img.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index cc51db7ed4..a2369766f0 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -229,14 +229,16 @@ static bool qemu_img_object_print_help(const char *type, QemuOpts *opts) * To make that work, @optarg must not start with ',' (or else a * separating ',' preceding it gets escaped), and it must not end with * an odd number of ',' (or else a separating ',' following it gets - * escaped). + * escaped), or be empty (or else a separating ',' preceding it can + * escape a separating ',' following it). + * */ static bool is_valid_option_list(const char *optarg) { size_t len = strlen(optarg); size_t i; - if (optarg[0] == ',') { + if (!optarg[0] || optarg[0] == ',') { return false; } From 2a340b67bd0a702e6d2102691cb2cb2177b7e210 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:06 +0200 Subject: [PATCH 0014/2595] cryptodev: Fix cryptodev_builtin_cleanup() error API violation The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. cryptodev_builtin_cleanup() passes @errp to cryptodev_builtin_sym_close_session() in a loop. Harmless, because cryptodev_builtin_sym_close_session() can't actually fail. Fix it anyway. Cc: Gonglei Signed-off-by: Markus Armbruster Message-Id: <20200422130719.28225-2-armbru@redhat.com> --- backends/cryptodev-builtin.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c index c8ae3b9742..14316333fe 100644 --- a/backends/cryptodev-builtin.c +++ b/backends/cryptodev-builtin.c @@ -282,12 +282,7 @@ static int cryptodev_builtin_sym_close_session( CryptoDevBackendBuiltin *builtin = CRYPTODEV_BACKEND_BUILTIN(backend); - if (session_id >= MAX_NUM_SESSIONS || - builtin->sessions[session_id] == NULL) { - error_setg(errp, "Cannot find a valid session id: %" PRIu64 "", - session_id); - return -1; - } + assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]); qcrypto_cipher_free(builtin->sessions[session_id]->cipher); g_free(builtin->sessions[session_id]); @@ -356,8 +351,7 @@ static void cryptodev_builtin_cleanup( for (i = 0; i < MAX_NUM_SESSIONS; i++) { if (builtin->sessions[i] != NULL) { - cryptodev_builtin_sym_close_session( - backend, i, 0, errp); + cryptodev_builtin_sym_close_session(backend, i, 0, &error_abort); } } From 77ed971b9d96a288e497509054e1e59493ffd1fc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:07 +0200 Subject: [PATCH 0015/2595] block/file-posix: Fix check_cache_dropped() error handling The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. check_cache_dropped() calls error_setg() in a loop. It fails to break the loop in one instance. If a subsequent iteration error_setg()s again, it trips error_setv()'s assertion. Fix it to break the loop. Fixes: 31be8a2a97ecba7d31a82932286489cac318e9e9 Cc: Stefan Hajnoczi Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200422130719.28225-3-armbru@redhat.com> --- block/file-posix.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/block/file-posix.c b/block/file-posix.c index 7e19bbff5f..094e3b0212 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -2691,10 +2691,13 @@ static void check_cache_dropped(BlockDriverState *bs, Error **errp) vec_end = DIV_ROUND_UP(length, page_size); for (i = 0; i < vec_end; i++) { if (vec[i] & 0x1) { - error_setg(errp, "page cache still in use!"); break; } } + if (i < vec_end) { + error_setg(errp, "page cache still in use!"); + break; + } } if (window) { From abc9bf69a66a11499a801ff545b8fe7adbb3a04c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:08 +0200 Subject: [PATCH 0016/2595] cpus: Fix configure_icount() error API violation The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. configure_icount() is wrong that way. Harmless, because its @errp is always &error_abort or &error_fatal. Just as wrong (and just as harmless): when it fails, it can still update global state. Fix all that. Cc: Paolo Bonzini Signed-off-by: Markus Armbruster Message-Id: <20200422130719.28225-4-armbru@redhat.com> --- cpus.c | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/cpus.c b/cpus.c index ef441bdf62..1b542b37f9 100644 --- a/cpus.c +++ b/cpus.c @@ -797,40 +797,49 @@ void cpu_ticks_init(void) void configure_icount(QemuOpts *opts, Error **errp) { - const char *option; + const char *option = qemu_opt_get(opts, "shift"); + bool sleep = qemu_opt_get_bool(opts, "sleep", true); + bool align = qemu_opt_get_bool(opts, "align", false); + long time_shift = -1; char *rem_str = NULL; - option = qemu_opt_get(opts, "shift"); - if (!option) { - if (qemu_opt_get(opts, "align") != NULL) { - error_setg(errp, "Please specify shift option when using align"); - } + if (!option && qemu_opt_get(opts, "align")) { + error_setg(errp, "Please specify shift option when using align"); return; } - icount_sleep = qemu_opt_get_bool(opts, "sleep", true); + if (align && !sleep) { + error_setg(errp, "align=on and sleep=off are incompatible"); + return; + } + + if (strcmp(option, "auto") != 0) { + errno = 0; + time_shift = strtol(option, &rem_str, 0); + if (errno != 0 || *rem_str != '\0' || !strlen(option)) { + error_setg(errp, "icount: Invalid shift value"); + return; + } + } else if (icount_align_option) { + error_setg(errp, "shift=auto and align=on are incompatible"); + return; + } else if (!icount_sleep) { + error_setg(errp, "shift=auto and sleep=off are incompatible"); + return; + } + + icount_sleep = sleep; if (icount_sleep) { timers_state.icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, icount_timer_cb, NULL); } - icount_align_option = qemu_opt_get_bool(opts, "align", false); + icount_align_option = align; - if (icount_align_option && !icount_sleep) { - error_setg(errp, "align=on and sleep=off are incompatible"); - } - if (strcmp(option, "auto") != 0) { - errno = 0; - timers_state.icount_time_shift = strtol(option, &rem_str, 0); - if (errno != 0 || *rem_str != '\0' || !strlen(option)) { - error_setg(errp, "icount: Invalid shift value"); - } + if (time_shift >= 0) { + timers_state.icount_time_shift = time_shift; use_icount = 1; return; - } else if (icount_align_option) { - error_setg(errp, "shift=auto and align=on are incompatible"); - } else if (!icount_sleep) { - error_setg(errp, "shift=auto and sleep=off are incompatible"); } use_icount = 2; From 9ec374a781c34daa6e70fcd885ef30e090cc2384 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:09 +0200 Subject: [PATCH 0017/2595] cpus: Proper range-checking for -icount shift=N timers_state.icount_time_shift must be in [0,63] to avoid undefined behavior when shifting by it, e.g. in cpu_icount_to_ns(). icount_adjust() clamps it to [0,MAX_ICOUNT_SHIFT], with MAX_ICOUNT_SHIFT = 10. configure_icount() doesn't. Fix that. Fixes: a8bfac37085c3372366d722f131a7e18d664ee4d Cc: Paolo Bonzini Signed-off-by: Markus Armbruster Message-Id: <20200422130719.28225-5-armbru@redhat.com> --- cpus.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cpus.c b/cpus.c index 1b542b37f9..5670c96bcf 100644 --- a/cpus.c +++ b/cpus.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/config-file.h" +#include "qemu/cutils.h" #include "migration/vmstate.h" #include "monitor/monitor.h" #include "qapi/error.h" @@ -801,7 +802,6 @@ void configure_icount(QemuOpts *opts, Error **errp) bool sleep = qemu_opt_get_bool(opts, "sleep", true); bool align = qemu_opt_get_bool(opts, "align", false); long time_shift = -1; - char *rem_str = NULL; if (!option && qemu_opt_get(opts, "align")) { error_setg(errp, "Please specify shift option when using align"); @@ -814,9 +814,8 @@ void configure_icount(QemuOpts *opts, Error **errp) } if (strcmp(option, "auto") != 0) { - errno = 0; - time_shift = strtol(option, &rem_str, 0); - if (errno != 0 || *rem_str != '\0' || !strlen(option)) { + if (qemu_strtol(option, NULL, 0, &time_shift) < 0 + || time_shift < 0 || time_shift > MAX_ICOUNT_SHIFT) { error_setg(errp, "icount: Invalid shift value"); return; } From 0fbddcecf23dcc311b42d9faf87dc2656dadd62a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:10 +0200 Subject: [PATCH 0018/2595] arm/virt: Fix virt_machine_device_plug_cb() error API violation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. virt_machine_device_plug_cb() passes @errp to cryptodev_builtin_sym_close_session() in a loop. Harmless, because cryptodev_builtin_sym_close_session() can't actually fail. Fix by dropping its Error ** parameter. Cc: Peter Maydell Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200422130719.28225-6-armbru@redhat.com> --- hw/arm/virt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 7dc96abf72..cca5316256 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1186,7 +1186,7 @@ static void create_smmu(const VirtMachineState *vms, g_free(node); } -static void create_virtio_iommu_dt_bindings(VirtMachineState *vms, Error **errp) +static void create_virtio_iommu_dt_bindings(VirtMachineState *vms) { const char compat[] = "virtio,pci-iommu"; uint16_t bdf = vms->virtio_iommu_bdf; @@ -2118,7 +2118,7 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, vms->iommu = VIRT_IOMMU_VIRTIO; vms->virtio_iommu_bdf = pci_get_bdf(pdev); - create_virtio_iommu_dt_bindings(vms, errp); + create_virtio_iommu_dt_bindings(vms); } } From 07a978ef376cde544cca564ec225a8eb79ff2d54 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:11 +0200 Subject: [PATCH 0019/2595] fdc: Fix fallback=auto error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fdctrl_realize_common() rejects fallback=auto. Used by devices "isa-fdc", "sysbus-fdc", "SUNW,fdtwo". The error handling is broken: $ qemu-system-x86_64 -nodefaults -device isa-fdc,fallback=auto,driveA=fd0 -drive if=none,id=fd0 ** ERROR:/work/armbru/qemu/hw/block/fdc.c:434:pick_drive_type: assertion failed: (drv->drive != FLOPPY_DRIVE_TYPE_AUTO) Aborted (core dumped) Cause: fdctrl_realize_common() neglects to bail out after setting the error. Fix that. Fixes: a73275dd6fc3bfda33165bebc28e0c33c20cb0a0 Cc: John Snow Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200422130719.28225-7-armbru@redhat.com> --- hw/block/fdc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 33bc9e2f92..9628cc171e 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2615,6 +2615,7 @@ static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl, if (fdctrl->fallback == FLOPPY_DRIVE_TYPE_AUTO) { error_setg(errp, "Cannot choose a fallback FDrive type of 'auto'"); + return; } /* Fill 'command_to_handler' lookup table */ From ee29f6e92d987bd7f37e3a0002dd839f8431adb1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:12 +0200 Subject: [PATCH 0020/2595] bochs-display: Fix vgamem=SIZE error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bochs_display_realize() rejects out-of-range vgamem. The error handling is broken: $ qemu-system-x86_64 -S -display none -monitor stdio QEMU 4.2.93 monitor - type 'help' for more information (qemu) device_add bochs-display,vgamem=1 Error: bochs-display: video memory too small (qemu) device_add bochs-display,vgamem=1 RAMBlock "0000:00:04.0/bochs-display-vram" already registered, abort! Aborted (core dumped) Cause: bochs_display_realize() neglects to bail out after setting the error. Fix that. Fixes: 765c94290863eef1fc4a67819d452cc13b7854a1 Cc: Gerd Hoffmann Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200422130719.28225-8-armbru@redhat.com> Reviewed-by: Gerd Hoffmann --- hw/display/bochs-display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c index 70eb619ef4..e763a0a72d 100644 --- a/hw/display/bochs-display.c +++ b/hw/display/bochs-display.c @@ -267,16 +267,18 @@ static void bochs_display_realize(PCIDevice *dev, Error **errp) Object *obj = OBJECT(dev); int ret; - s->con = graphic_console_init(DEVICE(dev), 0, &bochs_display_gfx_ops, s); - if (s->vgamem < 4 * MiB) { error_setg(errp, "bochs-display: video memory too small"); + return; } if (s->vgamem > 256 * MiB) { error_setg(errp, "bochs-display: video memory too big"); + return; } s->vgamem = pow2ceil(s->vgamem); + s->con = graphic_console_init(DEVICE(dev), 0, &bochs_display_gfx_ops, s); + memory_region_init_ram(&s->vram, obj, "bochs-display-vram", s->vgamem, &error_fatal); memory_region_init_io(&s->vbe, obj, &bochs_display_vbe_ops, s, From 843c4cfcf445fc3d6458ff31136c44e03dda8866 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:13 +0200 Subject: [PATCH 0021/2595] virtio-net: Fix duplex=... and speed=... error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virtio_net_device_realize() rejects invalid duplex and speed values. The error handling is broken: $ ../qemu/bld-sani/x86_64-softmmu/qemu-system-x86_64 -S -display none -monitor stdio QEMU 4.2.93 monitor - type 'help' for more information (qemu) device_add virtio-net,duplex=x Error: 'duplex' must be 'half' or 'full' (qemu) c ================================================================= ==15654==ERROR: AddressSanitizer: heap-use-after-free on address 0x62e000014590 at pc 0x560b75c8dc13 bp 0x7fffdf1a6950 sp 0x7fffdf1a6940 READ of size 8 at 0x62e000014590 thread T0 #0 0x560b75c8dc12 in object_dynamic_cast_assert /work/armbru/qemu/qom/object.c:826 #1 0x560b74c38ac0 in virtio_vmstate_change /work/armbru/qemu/hw/virtio/virtio.c:3210 #2 0x560b74d9765e in vm_state_notify /work/armbru/qemu/softmmu/vl.c:1271 #3 0x560b7494ba72 in vm_prepare_start /work/armbru/qemu/cpus.c:2156 #4 0x560b7494bacd in vm_start /work/armbru/qemu/cpus.c:2162 #5 0x560b75a7d890 in qmp_cont /work/armbru/qemu/monitor/qmp-cmds.c:160 #6 0x560b75a8d70a in hmp_cont /work/armbru/qemu/monitor/hmp-cmds.c:1043 #7 0x560b75a799f2 in handle_hmp_command /work/armbru/qemu/monitor/hmp.c:1082 [...] 0x62e000014590 is located 33168 bytes inside of 42288-byte region [0x62e00000c400,0x62e000016930) freed by thread T1 here: #0 0x7feadd39491f in __interceptor_free (/lib64/libasan.so.5+0x10d91f) #1 0x7feadcebcd7c in g_free (/lib64/libglib-2.0.so.0+0x55d7c) #2 0x560b75c8fd40 in object_unref /work/armbru/qemu/qom/object.c:1128 #3 0x560b7498a625 in memory_region_unref /work/armbru/qemu/memory.c:1762 #4 0x560b74999fa4 in do_address_space_destroy /work/armbru/qemu/memory.c:2788 #5 0x560b762362fc in call_rcu_thread /work/armbru/qemu/util/rcu.c:283 #6 0x560b761c8884 in qemu_thread_start /work/armbru/qemu/util/qemu-thread-posix.c:519 #7 0x7fead9be34bf in start_thread (/lib64/libpthread.so.0+0x84bf) previously allocated by thread T0 here: #0 0x7feadd394d18 in __interceptor_malloc (/lib64/libasan.so.5+0x10dd18) #1 0x7feadcebcc88 in g_malloc (/lib64/libglib-2.0.so.0+0x55c88) #2 0x560b75c8cf8a in object_new /work/armbru/qemu/qom/object.c:699 #3 0x560b75010ad9 in qdev_device_add /work/armbru/qemu/qdev-monitor.c:654 #4 0x560b750120c2 in qmp_device_add /work/armbru/qemu/qdev-monitor.c:805 #5 0x560b75012c1b in hmp_device_add /work/armbru/qemu/qdev-monitor.c:905 [...] ==15654==ABORTING Cause: virtio_net_device_realize() neglects to bail out after setting the error. Fix that. Fixes: 9473939ed7addcaaeb8fde5c093918fb7fa0919c Cc: "Michael S. Tsirkin" Cc: Jason Wang Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200422130719.28225-9-armbru@redhat.com> Acked-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index eddfa7f923..65bb6886c7 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -2947,6 +2947,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) n->net_conf.duplex = DUPLEX_FULL; } else { error_setg(errp, "'duplex' must be 'half' or 'full'"); + return; } n->host_features |= (1ULL << VIRTIO_NET_F_SPEED_DUPLEX); } else { @@ -2955,7 +2956,9 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) if (n->net_conf.speed < SPEED_UNKNOWN) { error_setg(errp, "'speed' must be between 0 and INT_MAX"); - } else if (n->net_conf.speed >= 0) { + return; + } + if (n->net_conf.speed >= 0) { n->host_features |= (1ULL << VIRTIO_NET_F_SPEED_DUPLEX); } From c61d1d9e4976d127a73bec14376d8e828491f62c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:14 +0200 Subject: [PATCH 0022/2595] xen/pt: Fix flawed conversion to realize() The conversion of xen_pt_initfn() to xen_pt_realize() blindly replaced XEN_PT_ERR() by error_setg(). Several error conditions that did not fail xen_pt_initfn() now fail xen_pt_realize(). Unsurprisingly, the cleanup on these errors looks highly suspicious. Revert the inappropriate replacements. Fixes: 5a11d0f7549e24a10e178a9dc8ff5e698031d9a6 Cc: Stefano Stabellini Cc: Anthony Perard Cc: Paul Durrant Cc: xen-devel@lists.xenproject.org Signed-off-by: Markus Armbruster Reviewed-by: Paul Durrant Message-Id: <20200422130719.28225-10-armbru@redhat.com> --- hw/xen/xen_pt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index b91082cb8b..81d5ad8da7 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -858,8 +858,8 @@ static void xen_pt_realize(PCIDevice *d, Error **errp) rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq); if (rc < 0) { - error_setg_errno(errp, errno, "Mapping machine irq %u to" - " pirq %i failed", machine_irq, pirq); + XEN_PT_ERR(d, "Mapping machine irq %u to pirq %i failed, (err: %d)\n", + machine_irq, pirq, errno); /* Disable PCI intx assertion (turn on bit10 of devctl) */ cmd |= PCI_COMMAND_INTX_DISABLE; @@ -880,8 +880,8 @@ static void xen_pt_realize(PCIDevice *d, Error **errp) PCI_SLOT(d->devfn), e_intx); if (rc < 0) { - error_setg_errno(errp, errno, "Binding of interrupt %u failed", - e_intx); + XEN_PT_ERR(d, "Binding of interrupt %i failed! (err: %d)\n", + e_intx, errno); /* Disable PCI intx assertion (turn on bit10 of devctl) */ cmd |= PCI_COMMAND_INTX_DISABLE; @@ -889,8 +889,8 @@ static void xen_pt_realize(PCIDevice *d, Error **errp) if (xen_pt_mapped_machine_irq[machine_irq] == 0) { if (xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq)) { - error_setg_errno(errp, errno, "Unmapping of machine" - " interrupt %u failed", machine_irq); + XEN_PT_ERR(d, "Unmapping of machine interrupt %i failed!" + " (err: %d)\n", machine_irq, errno); } } s->machine_irq = 0; From fdceb4ab4d7ba920bb094ab477df4221261b291e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:15 +0200 Subject: [PATCH 0023/2595] io: Fix qio_channel_socket_close() error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. qio_channel_socket_close() passes @errp first to socket_listen_cleanup(), and then, if closesocket() fails, to error_setg_errno(). If socket_listen_cleanup() failed, this will trip the assertion in error_setv(). Fix by ignoring a second error. Fixes: 73564c407caedf992a1c688b5fea776a8b56ba2a Cc: Daniel P. Berrangé Signed-off-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Message-Id: <20200422130719.28225-11-armbru@redhat.com> --- io/channel-socket.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/io/channel-socket.c b/io/channel-socket.c index b74f5b92a0..e1b4667087 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -704,6 +704,7 @@ qio_channel_socket_close(QIOChannel *ioc, { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); int rc = 0; + Error *err = NULL; if (sioc->fd != -1) { #ifdef WIN32 @@ -715,8 +716,8 @@ qio_channel_socket_close(QIOChannel *ioc, if (closesocket(sioc->fd) < 0) { sioc->fd = -1; - error_setg_errno(errp, errno, - "Unable to close socket"); + error_setg_errno(&err, errno, "Unable to close socket"); + error_propagate(errp, err); return -1; } sioc->fd = -1; From 735527e17907cca330ec369a13566fab2ef9adf6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:16 +0200 Subject: [PATCH 0024/2595] migration/colo: Fix qmp_xen_colo_do_checkpoint() error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. qmp_xen_colo_do_checkpoint() passes @errp first to replication_do_checkpoint_all(), and then to colo_notify_filters_event(). If both fail, this will trip the assertion in error_setv(). Similar code in secondary_vm_do_failover() calls colo_notify_filters_event() only after replication_do_checkpoint_all() succeeded. Do the same here. Fixes: 0e8818f023616677416840d6ddc880db8de3c967 Cc: Zhang Chen Cc: zhanghailiang Signed-off-by: Markus Armbruster Reviewed-by: zhanghailiang Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Zhang Chen Message-Id: <20200422130719.28225-12-armbru@redhat.com> --- migration/colo.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/migration/colo.c b/migration/colo.c index a54ac84f41..1b3493729b 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -263,7 +263,13 @@ ReplicationStatus *qmp_query_xen_replication_status(Error **errp) void qmp_xen_colo_do_checkpoint(Error **errp) { - replication_do_checkpoint_all(errp); + Error *err = NULL; + + replication_do_checkpoint_all(&err); + if (err) { + error_propagate(errp, err); + return; + } /* Notify all filters of all NIC to do checkpoint */ colo_notify_filters_event(COLO_EVENT_CHECKPOINT, errp); } From 131889924bb31a6a371ed9300efb2036edd6b40b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:17 +0200 Subject: [PATCH 0025/2595] tests/test-logging: Fix test for -dfilter 0..0xffffffffffffffff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: 58e19e6e7914354242a67442d0006f9e31684d1a Signed-off-by: Markus Armbruster Message-Id: <20200422130719.28225-13-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- tests/test-logging.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-logging.c b/tests/test-logging.c index 6387e4933f..8580b82420 100644 --- a/tests/test-logging.c +++ b/tests/test-logging.c @@ -73,10 +73,10 @@ static void test_parse_range(void) g_assert(qemu_log_in_addr_range(UINT64_MAX)); g_assert_false(qemu_log_in_addr_range(UINT64_MAX - 1)); - qemu_set_dfilter_ranges("0..0xffffffffffffffff", &err); + qemu_set_dfilter_ranges("0..0xffffffffffffffff", &error_abort); g_assert(qemu_log_in_addr_range(0)); g_assert(qemu_log_in_addr_range(UINT64_MAX)); - + qemu_set_dfilter_ranges("2..1", &err); error_free_or_abort(&err); From 4155c998b6f7618aad0e67c34c2a4aea841114cf Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:18 +0200 Subject: [PATCH 0026/2595] qga: Fix qmp_guest_get_memory_blocks() error handling The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. qmp_guest_get_memory_blocks() passes &local_err to transfer_memory_block() in a loop. If this fails in more than one iteration, it can trip error_setv()'s assertion. Fix it to break the loop. Cc: Michael Roth Signed-off-by: Markus Armbruster Message-Id: <20200422130719.28225-14-armbru@redhat.com> Reviewed-by: Eric Blake --- qga/commands-posix.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index a52af0315f..ae1348dc8f 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -2518,6 +2518,9 @@ GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp) mem_blk->phys_index = strtoul(&de->d_name[6], NULL, 10); mem_blk->has_can_offline = true; /* lolspeak ftw */ transfer_memory_block(mem_blk, true, NULL, &local_err); + if (local_err) { + break; + } entry = g_malloc0(sizeof *entry); entry->value = mem_blk; From 51bd45816615bdb22a31a86f02d601ce536034e3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:07:19 +0200 Subject: [PATCH 0027/2595] qga: Fix qmp_guest_suspend_{disk, ram}() error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second qmp_guest_suspend_disk() and qmp_guest_suspend_ram() pass @local_err first to check_suspend_mode(), then to acquire_privilege(), then to execute_async(). Continuing after errors here can only end in tears. For instance, we risk tripping error_setv()'s assertion. Fixes: aa59637ea1c6a4c83430933f9c44c43e6c3f1b69 Fixes: f54603b6aa765514b2519e74114a2f417759d727 Cc: Michael Roth Signed-off-by: Markus Armbruster Message-Id: <20200422130719.28225-15-armbru@redhat.com> Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé --- qga/commands-win32.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 9717a8d52d..5ba56327dd 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -1322,9 +1322,16 @@ void qmp_guest_suspend_disk(Error **errp) *mode = GUEST_SUSPEND_MODE_DISK; check_suspend_mode(*mode, &local_err); + if (local_err) { + goto out; + } acquire_privilege(SE_SHUTDOWN_NAME, &local_err); + if (local_err) { + goto out; + } execute_async(do_suspend, mode, &local_err); +out: if (local_err) { error_propagate(errp, local_err); g_free(mode); @@ -1338,9 +1345,16 @@ void qmp_guest_suspend_ram(Error **errp) *mode = GUEST_SUSPEND_MODE_RAM; check_suspend_mode(*mode, &local_err); + if (local_err) { + goto out; + } acquire_privilege(SE_SHUTDOWN_NAME, &local_err); + if (local_err) { + goto out; + } execute_async(do_suspend, mode, &local_err); +out: if (local_err) { error_propagate(errp, local_err); g_free(mode); From fc0cfc1decb5457058d7cbfeb7ae26ad5d6ecba4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:48:12 +0200 Subject: [PATCH 0028/2595] sam460ex: Suppress useless warning on -m 32 and -m 64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Requesting 32 or 64 MiB of RAM with the sam460ex machine type produces a useless warning: qemu-system-ppc: warning: Memory size is too small for SDRAM type, adjusting type This is because sam460ex_init() asks spd_data_generate() for DDR2, which is impossible, so spd_data_generate() corrects it to DDR. The warning goes back to commit 08fd99179a "sam460ex: Clean up SPD EEPROM creation". Make sam460ex_init() pass the correct SDRAM type to get rid of the warning. Signed-off-by: Markus Armbruster Message-Id: <20200422134815.1584-2-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/ppc/sam460ex.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 898453cf30..1e3eaac0db 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -335,7 +335,8 @@ static void sam460ex_init(MachineState *machine) dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]); i2c = PPC4xx_I2C(dev)->bus; /* SPD EEPROM on RAM module */ - spd_data = spd_data_generate(DDR2, ram_sizes[0], &err); + spd_data = spd_data_generate(ram_sizes[0] < 128 * MiB ? DDR : DDR2, + ram_sizes[0], &err); if (err) { warn_report_err(err); } From f26740c61a57f1a1556f79a49c6863479fe5aa6b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:48:13 +0200 Subject: [PATCH 0029/2595] smbus: Fix spd_data_generate() error API violation The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. spd_data_generate() can pass @errp to error_setg() more than once when it adjusts both memory size and type. Harmless, because no caller passes anything that needs adjusting. Until the previous commit, sam460ex passed types that needed adjusting, but not sizes. spd_data_generate()'s contract is rather awkward: If everything's fine, return non-null and don't set an error. Else, if memory size or type need adjusting, return non-null and set an error describing the adjustment. Else, return null and set an error reporting why no data can be generated. Its callers treat the error as a warning even when null is returned. They don't create the "smbus-eeprom" device then. Suspicious. Since the previous commit, only "everything's fine" can actually happen. Drop the unused code and simplify the callers. This gets rid of the error API violation. Signed-off-by: Markus Armbruster Message-Id: <20200422134815.1584-3-armbru@redhat.com> --- hw/i2c/smbus_eeprom.c | 30 ++++-------------------------- hw/mips/mips_fulong2e.c | 10 ++-------- hw/ppc/sam460ex.c | 12 +++--------- include/hw/i2c/smbus_eeprom.h | 2 +- 4 files changed, 10 insertions(+), 44 deletions(-) diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c index 5adf3b15b5..07fbbf87f1 100644 --- a/hw/i2c/smbus_eeprom.c +++ b/hw/i2c/smbus_eeprom.c @@ -195,8 +195,7 @@ void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, } /* Generate SDRAM SPD EEPROM data describing a module of type and size */ -uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t ram_size, - Error **errp) +uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t ram_size) { uint8_t *spd; uint8_t nbanks; @@ -222,29 +221,10 @@ uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t ram_size, g_assert_not_reached(); } size = ram_size >> 20; /* work in terms of megabytes */ - if (size < 4) { - error_setg(errp, "SDRAM size is too small"); - return NULL; - } sz_log2 = 31 - clz32(size); size = 1U << sz_log2; - if (ram_size > size * MiB) { - error_setg(errp, "SDRAM size 0x"RAM_ADDR_FMT" is not a power of 2, " - "truncating to %u MB", ram_size, size); - } - if (sz_log2 < min_log2) { - error_setg(errp, - "Memory size is too small for SDRAM type, adjusting type"); - if (size >= 32) { - type = DDR; - min_log2 = 5; - max_log2 = 12; - } else { - type = SDR; - min_log2 = 2; - max_log2 = 9; - } - } + assert(ram_size == size * MiB); + assert(sz_log2 >= min_log2); nbanks = 1; while (sz_log2 > max_log2 && nbanks < 8) { @@ -252,9 +232,7 @@ uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t ram_size, nbanks++; } - if (size > (1ULL << sz_log2) * nbanks) { - error_setg(errp, "Memory size is too big for SDRAM, truncating"); - } + assert(size == (1ULL << sz_log2) * nbanks); /* split to 2 banks if possible to avoid a bug in MIPS Malta firmware */ if (nbanks == 1 && sz_log2 > min_log2) { diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 5040afd581..ef02d54b33 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -297,7 +297,6 @@ static void mips_fulong2e_init(MachineState *machine) MemoryRegion *bios = g_new(MemoryRegion, 1); long bios_size; uint8_t *spd_data; - Error *err = NULL; int64_t kernel_entry; PCIBus *pci_bus; ISABus *isa_bus; @@ -377,13 +376,8 @@ static void mips_fulong2e_init(MachineState *machine) } /* Populate SPD eeprom data */ - spd_data = spd_data_generate(DDR, machine->ram_size, &err); - if (err) { - warn_report_err(err); - } - if (spd_data) { - smbus_eeprom_init_one(smbus, 0x50, spd_data); - } + spd_data = spd_data_generate(DDR, machine->ram_size); + smbus_eeprom_init_one(smbus, 0x50, spd_data); mc146818_rtc_init(isa_bus, 2000, NULL); diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 1e3eaac0db..42a8c9fb7f 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -292,7 +292,6 @@ static void sam460ex_init(MachineState *machine) SysBusDevice *sbdev; struct boot_info *boot_info; uint8_t *spd_data; - Error *err = NULL; int success; cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); @@ -336,14 +335,9 @@ static void sam460ex_init(MachineState *machine) i2c = PPC4xx_I2C(dev)->bus; /* SPD EEPROM on RAM module */ spd_data = spd_data_generate(ram_sizes[0] < 128 * MiB ? DDR : DDR2, - ram_sizes[0], &err); - if (err) { - warn_report_err(err); - } - if (spd_data) { - spd_data[20] = 4; /* SO-DIMM module */ - smbus_eeprom_init_one(i2c, 0x50, spd_data); - } + ram_sizes[0]); + spd_data[20] = 4; /* SO-DIMM module */ + smbus_eeprom_init_one(i2c, 0x50, spd_data); /* RTC */ i2c_create_slave(i2c, "m41t80", 0x68); diff --git a/include/hw/i2c/smbus_eeprom.h b/include/hw/i2c/smbus_eeprom.h index 15e2151b50..68b0063ab6 100644 --- a/include/hw/i2c/smbus_eeprom.h +++ b/include/hw/i2c/smbus_eeprom.h @@ -31,6 +31,6 @@ void smbus_eeprom_init(I2CBus *bus, int nb_eeprom, const uint8_t *eeprom_spd, int size); enum sdram_type { SDR = 0x4, DDR = 0x7, DDR2 = 0x8 }; -uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t size, Error **errp); +uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t size); #endif From 0f1eddf5ed7e35d8d16dfa042ced1107c762cec4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:48:14 +0200 Subject: [PATCH 0030/2595] bamboo, sam460ex: Tidy up error message for unsupported RAM size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve $ ppc-softmmu/qemu-system-ppc -M sam460ex -m 4096 qemu-system-ppc: Max 1 banks of 2048 ,1024 ,512 ,256 ,128 ,64 ,32 MB DIMM/bank supported qemu-system-ppc: Possible valid RAM size: 2048 to qemu-system-ppc: at most 1 bank of 2048, 1024, 512, 256, 128, 64, 32 MiB each supported Possible valid RAM size: 1024 MiB Signed-off-by: Markus Armbruster Message-Id: <20200422134815.1584-4-armbru@redhat.com> Reviewed-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé --- hw/ppc/ppc4xx_devs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index 3376c43ff5..f1651e04d9 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -716,11 +716,11 @@ void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, for (i = 0; sdram_bank_sizes[i]; i++) { g_string_append_printf(s, "%" PRIi64 "%s", sdram_bank_sizes[i] / MiB, - sdram_bank_sizes[i + 1] ? " ," : ""); + sdram_bank_sizes[i + 1] ? ", " : ""); } - error_report("Max %d banks of %s MB DIMM/bank supported", - nr_banks, s->str); - error_report("Possible valid RAM size: %" PRIi64, + error_report("at most %d bank%s of %s MiB each supported", + nr_banks, nr_banks == 1 ? "" : "s", s->str); + error_printf("Possible valid RAM size: %" PRIi64 " MiB \n", used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB); g_string_free(s, true); From 32c82f0eaf9919cb0268d18d86a94bfd7ff5d1b2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Apr 2020 15:48:15 +0200 Subject: [PATCH 0031/2595] smbus: Fix spd_data_generate() for number of banks > 2 spd_data_generate() splits @ram_size bytes into @nbanks RAM banks of 1 << sz_log2 MiB each, like this: size = ram_size >> 20; /* work in terms of megabytes */ [...] nbanks = 1; while (sz_log2 > max_log2 && nbanks < 8) { sz_log2--; nbanks++; } Each iteration halves the size of a bank, and increments the number of banks. Wrong: it should double the number of banks. The bug goes back all the way to commit b296b664ab "smbus: Add a helper to generate SPD EEPROM data". It can't bite because spd_data_generate()'s current users pass only @ram_size that result in *zero* iterations: machine RAM size #banks type bank size fulong2e 256 MiB 1 DDR 256 MiB sam460ex 2048 MiB 1 DDR2 2048 MiB 1024 MiB 1 DDR2 1024 MiB 512 MiB 1 DDR2 512 MiB 256 MiB 1 DDR2 256 MiB 128 MiB 1 SDR 128 MiB 64 MiB 1 SDR 64 MiB 32 MiB 1 SDR 32 MiB Apply the obvious, minimal fix. I admit I'm tempted to rip out the unused (and obviously untested) feature instead, because YAGNI. Note that this is not the final result, as spd_data_generate() next increases #banks from 1 to 2 if possible. This is done "to avoid a bug in MIPS Malta firmware". We don't even use this function with machine type malta. *Shrug* Signed-off-by: Markus Armbruster Message-Id: <20200422134815.1584-5-armbru@redhat.com> --- hw/i2c/smbus_eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c index 07fbbf87f1..e199fc8678 100644 --- a/hw/i2c/smbus_eeprom.c +++ b/hw/i2c/smbus_eeprom.c @@ -229,7 +229,7 @@ uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t ram_size) nbanks = 1; while (sz_log2 > max_log2 && nbanks < 8) { sz_log2--; - nbanks++; + nbanks *= 2; } assert(size == (1ULL << sz_log2) * nbanks); From 14b6ce68cc8658be107247544e9a287ed17aaf76 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 09:11:40 +0200 Subject: [PATCH 0032/2595] Makefile: Drop unused, broken target recurse-fuzz Target recurse-fuzz depends on pc-bios/optionrom/fuzz, which can't be made. It's not used anywhere. Added in commit c621dc3e01c, looks like cargo cult. Delete. Signed-off-by: Markus Armbruster Message-Id: <20200424071142.3525-2-armbru@redhat.com> Reviewed-by: Alexander Bulekov --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 8a9113e666..34275f57c9 100644 --- a/Makefile +++ b/Makefile @@ -582,7 +582,6 @@ $(ROM_DIRS_RULES): .PHONY: recurse-all recurse-clean recurse-install recurse-all: $(addsuffix /all, $(TARGET_DIRS) $(ROM_DIRS)) -recurse-fuzz: $(addsuffix /fuzz, $(TARGET_DIRS) $(ROM_DIRS)) recurse-clean: $(addsuffix /clean, $(TARGET_DIRS) $(ROM_DIRS)) recurse-install: $(addsuffix /install, $(TARGET_DIRS)) $(addsuffix /install, $(TARGET_DIRS)): all From a56f3cdbdf328d95398c70432bba638a6b3f63fa Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 09:11:41 +0200 Subject: [PATCH 0033/2595] fuzz: Simplify how we compute available machines and types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit apply_to_qlist(), apply_to_node() work with QObjects. This is designed for use by tests/qtest/qos-test.c, which gets the data in that form via QMP. Goes back to commit fc281c8020 "tests: qgraph API for the qtest driver framework". Commit 275ab39d86 "fuzz: add support for qos-assisted fuzz targets" added another user: qtest/fuzz/qos_fuzz.c. To get the data as QObjects, it uses qmp_marshal_query_machines() and qmp_marshal_qom_list_types(). All this code is rather cumbersome. Switch to working with generated QAPI types instead: * Replace apply_to_qlist() & friends by machines_apply_to_node() and types_apply_to_node(). * Have qos_fuzz.c use qmp_query_machines() and qmp_qom_list_types() instead. * Have qos_test.c convert from QObject to the QAPI types. Signed-off-by: Markus Armbruster Message-Id: <20200424071142.3525-3-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alexander Bulekov --- tests/qtest/fuzz/qos_fuzz.c | 34 ++++----------- tests/qtest/libqos/qos_external.c | 70 +++++++++++-------------------- tests/qtest/libqos/qos_external.h | 8 +++- tests/qtest/qos-test.c | 29 +++++++++---- 4 files changed, 59 insertions(+), 82 deletions(-) diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c index af28c92866..87eadb0889 100644 --- a/tests/qtest/fuzz/qos_fuzz.c +++ b/tests/qtest/fuzz/qos_fuzz.c @@ -36,7 +36,6 @@ #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-qom.h" -#include "qapi/qmp/qlist.h" void *fuzz_qos_obj; @@ -45,34 +44,19 @@ QGuestAllocator *fuzz_qos_alloc; static const char *fuzz_target_name; static char **fuzz_path_vec; -/* - * Replaced the qmp commands with direct qmp_marshal calls. - * Probably there is a better way to do this - */ static void qos_set_machines_devices_available(void) { - QDict *req = qdict_new(); - QObject *response; - QDict *args = qdict_new(); - QList *lst; + MachineInfoList *mach_info; + ObjectTypeInfoList *type_info; - qmp_marshal_query_machines(NULL, &response, &error_abort); - lst = qobject_to(QList, response); - apply_to_qlist(lst, true); + mach_info = qmp_query_machines(&error_abort); + machines_apply_to_node(mach_info); + qapi_free_MachineInfoList(mach_info); - qobject_unref(response); - - - qdict_put_str(req, "execute", "qom-list-types"); - qdict_put_str(args, "implements", "device"); - qdict_put_bool(args, "abstract", true); - qdict_put_obj(req, "arguments", (QObject *) args); - - qmp_marshal_qom_list_types(args, &response, &error_abort); - lst = qobject_to(QList, response); - apply_to_qlist(lst, false); - qobject_unref(response); - qobject_unref(req); + type_info = qmp_qom_list_types(true, "device", true, true, + &error_abort); + types_apply_to_node(type_info); + qapi_free_ObjectTypeInfoList(type_info); } static char **current_path; diff --git a/tests/qtest/libqos/qos_external.c b/tests/qtest/libqos/qos_external.c index 398556dde0..c707dac3b9 100644 --- a/tests/qtest/libqos/qos_external.c +++ b/tests/qtest/libqos/qos_external.c @@ -29,62 +29,40 @@ #include "libqos/qgraph_internal.h" #include "libqos/qos_external.h" - - -void apply_to_node(const char *name, bool is_machine, bool is_abstract) +static void machine_apply_to_node(const char *name) { - char *machine_name = NULL; - if (is_machine) { - const char *arch = qtest_get_arch(); - machine_name = g_strconcat(arch, "/", name, NULL); - name = machine_name; + char *machine_name = g_strconcat(qtest_get_arch(), "/", name, NULL); + + qos_graph_node_set_availability(machine_name, true); + g_free(machine_name); +} + +void machines_apply_to_node(MachineInfoList *mach_info) +{ + MachineInfoList *tail; + + for (tail = mach_info; tail; tail = tail->next) { + machine_apply_to_node(tail->value->name); + if (tail->value->alias) { + machine_apply_to_node(tail->value->alias); + } } +} + +static void type_apply_to_node(const char *name, bool is_abstract) +{ qos_graph_node_set_availability(name, true); if (is_abstract) { qos_delete_cmd_line(name); } - g_free(machine_name); } -/** - * apply_to_qlist(): using QMP queries QEMU for a list of - * machines and devices available, and sets the respective node - * as true. If a node is found, also all its produced and contained - * child are marked available. - * - * See qos_graph_node_set_availability() for more info - */ -void apply_to_qlist(QList *list, bool is_machine) +void types_apply_to_node(ObjectTypeInfoList *type_info) { - const QListEntry *p; - const char *name; - bool abstract; - QDict *minfo; - QObject *qobj; - QString *qstr; - QBool *qbool; + ObjectTypeInfoList *tail; - for (p = qlist_first(list); p; p = qlist_next(p)) { - minfo = qobject_to(QDict, qlist_entry_obj(p)); - qobj = qdict_get(minfo, "name"); - qstr = qobject_to(QString, qobj); - name = qstring_get_str(qstr); - - qobj = qdict_get(minfo, "abstract"); - if (qobj) { - qbool = qobject_to(QBool, qobj); - abstract = qbool_get_bool(qbool); - } else { - abstract = false; - } - - apply_to_node(name, is_machine, abstract); - qobj = qdict_get(minfo, "alias"); - if (qobj) { - qstr = qobject_to(QString, qobj); - name = qstring_get_str(qstr); - apply_to_node(name, is_machine, abstract); - } + for (tail = type_info; tail; tail = tail->next) { + type_apply_to_node(tail->value->name, tail->value->abstract); } } diff --git a/tests/qtest/libqos/qos_external.h b/tests/qtest/libqos/qos_external.h index 7b44930c55..f63388cb30 100644 --- a/tests/qtest/libqos/qos_external.h +++ b/tests/qtest/libqos/qos_external.h @@ -20,8 +20,12 @@ #define QOS_EXTERNAL_H #include "libqos/qgraph.h" -void apply_to_node(const char *name, bool is_machine, bool is_abstract); -void apply_to_qlist(QList *list, bool is_machine); +#include "libqos/malloc.h" +#include "qapi/qapi-types-machine.h" +#include "qapi/qapi-types-qom.h" + +void machines_apply_to_node(MachineInfoList *mach_info); +void types_apply_to_node(ObjectTypeInfoList *type_info); QGuestAllocator *get_machine_allocator(QOSGraphObject *obj); void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc); diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c index ad193f43a5..3062a13557 100644 --- a/tests/qtest/qos-test.c +++ b/tests/qtest/qos-test.c @@ -19,11 +19,12 @@ #include "qemu/osdep.h" #include #include "libqtest-single.h" +#include "qapi/error.h" #include "qapi/qmp/qdict.h" -#include "qapi/qmp/qbool.h" -#include "qapi/qmp/qstring.h" #include "qemu/module.h" -#include "qapi/qmp/qlist.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/qapi-visit-machine.h" +#include "qapi/qapi-visit-qom.h" #include "libqos/malloc.h" #include "libqos/qgraph.h" #include "libqos/qgraph_internal.h" @@ -51,13 +52,20 @@ static void qos_set_machines_devices_available(void) { QDict *response; QDict *args = qdict_new(); - QList *list; + QObject *ret; + Visitor *v; + MachineInfoList *mach_info; + ObjectTypeInfoList *type_info; qtest_start("-machine none"); response = qmp("{ 'execute': 'query-machines' }"); - list = qdict_get_qlist(response, "return"); + ret = qdict_get(response, "return"); - apply_to_qlist(list, true); + v = qobject_input_visitor_new(ret); + visit_type_MachineInfoList(v, NULL, &mach_info, &error_abort); + visit_free(v); + machines_apply_to_node(mach_info); + qapi_free_MachineInfoList(mach_info); qobject_unref(response); @@ -66,10 +74,13 @@ static void qos_set_machines_devices_available(void) response = qmp("{'execute': 'qom-list-types'," " 'arguments': %p }", args); - g_assert(qdict_haskey(response, "return")); - list = qdict_get_qlist(response, "return"); + ret = qdict_get(response, "return"); - apply_to_qlist(list, false); + v = qobject_input_visitor_new(ret); + visit_type_ObjectTypeInfoList(v, NULL, &type_info, &error_abort); + visit_free(v); + types_apply_to_node(type_info); + qapi_free_ObjectTypeInfoList(type_info); qtest_end(); qobject_unref(response); From f6528054f2ef7aab5c70664419b982b50142c25a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 09:11:42 +0200 Subject: [PATCH 0034/2595] libqos: Give get_machine_allocator() internal linkage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Message-Id: <20200424071142.3525-4-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- tests/qtest/libqos/qos_external.c | 2 +- tests/qtest/libqos/qos_external.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/qtest/libqos/qos_external.c b/tests/qtest/libqos/qos_external.c index c707dac3b9..9f5180e18d 100644 --- a/tests/qtest/libqos/qos_external.c +++ b/tests/qtest/libqos/qos_external.c @@ -66,7 +66,7 @@ void types_apply_to_node(ObjectTypeInfoList *type_info) } } -QGuestAllocator *get_machine_allocator(QOSGraphObject *obj) +static QGuestAllocator *get_machine_allocator(QOSGraphObject *obj) { return obj->get_driver(obj, "memory"); } diff --git a/tests/qtest/libqos/qos_external.h b/tests/qtest/libqos/qos_external.h index f63388cb30..72d7f91707 100644 --- a/tests/qtest/libqos/qos_external.h +++ b/tests/qtest/libqos/qos_external.h @@ -18,7 +18,6 @@ #ifndef QOS_EXTERNAL_H #define QOS_EXTERNAL_H -#include "libqos/qgraph.h" #include "libqos/malloc.h" #include "qapi/qapi-types-machine.h" @@ -26,7 +25,6 @@ void machines_apply_to_node(MachineInfoList *mach_info); void types_apply_to_node(ObjectTypeInfoList *type_info); -QGuestAllocator *get_machine_allocator(QOSGraphObject *obj); void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc); #endif From 8ef3a4be27efccd791d05e74b7b17d918f511a76 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 27 Apr 2020 09:57:04 +0900 Subject: [PATCH 0035/2595] qemu-option: pass NULL rather than 0 to the id of qemu_opts_set() The second argument 'id' is a pointer. Pass NULL rather than 0. Signed-off-by: Masahiro Yamada Message-Id: <20200427005704.2475782-1-masahiroy@kernel.org> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- softmmu/vl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index 32c0047889..afd2615fb3 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -3059,19 +3059,19 @@ void qemu_init(int argc, char **argv, char **envp) } break; case QEMU_OPTION_kernel: - qemu_opts_set(qemu_find_opts("machine"), 0, "kernel", optarg, + qemu_opts_set(qemu_find_opts("machine"), NULL, "kernel", optarg, &error_abort); break; case QEMU_OPTION_initrd: - qemu_opts_set(qemu_find_opts("machine"), 0, "initrd", optarg, + qemu_opts_set(qemu_find_opts("machine"), NULL, "initrd", optarg, &error_abort); break; case QEMU_OPTION_append: - qemu_opts_set(qemu_find_opts("machine"), 0, "append", optarg, + qemu_opts_set(qemu_find_opts("machine"), NULL, "append", optarg, &error_abort); break; case QEMU_OPTION_dtb: - qemu_opts_set(qemu_find_opts("machine"), 0, "dtb", optarg, + qemu_opts_set(qemu_find_opts("machine"), NULL, "dtb", optarg, &error_abort); break; case QEMU_OPTION_cdrom: @@ -3182,7 +3182,7 @@ void qemu_init(int argc, char **argv, char **envp) } break; case QEMU_OPTION_bios: - qemu_opts_set(qemu_find_opts("machine"), 0, "firmware", optarg, + qemu_opts_set(qemu_find_opts("machine"), NULL, "firmware", optarg, &error_abort); break; case QEMU_OPTION_singlestep: From c3347ed0d2ee42a7dcf7bfe7f9c3884a9596727a Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Mon, 23 Mar 2020 04:36:06 -0400 Subject: [PATCH 0036/2595] s390x: protvirt: Support unpack facility The unpack facility provides the means to setup a protected guest. A protected guest cannot be introspected by the hypervisor or any user/administrator of the machine it is running on. Protected guests are encrypted at rest and need a special boot mechanism via diag308 subcode 8 and 10. Code 8 sets the PV specific IPLB which is retained separately from those set via code 5. Code 10 is used to unpack the VM into protected memory, verify its integrity and start it. Signed-off-by: Janosch Frank Co-developed-by: Christian Borntraeger [Changes to machine] Reviewed-by: David Hildenbrand Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Message-Id: <20200323083606.24520-1-frankja@linux.ibm.com> [CH: fixed up KVM_PV_VM_ -> KVM_PV_] Signed-off-by: Cornelia Huck --- MAINTAINERS | 2 + hw/s390x/Makefile.objs | 1 + hw/s390x/ipl.c | 59 +++++++++++++- hw/s390x/ipl.h | 91 ++++++++++++++++++++- hw/s390x/pv.c | 98 +++++++++++++++++++++++ hw/s390x/s390-virtio-ccw.c | 119 +++++++++++++++++++++++++++- include/hw/s390x/pv.h | 55 +++++++++++++ include/hw/s390x/s390-virtio-ccw.h | 1 + target/s390x/cpu.c | 1 + target/s390x/cpu_features_def.inc.h | 1 + target/s390x/diag.c | 39 ++++++++- target/s390x/kvm-stub.c | 5 ++ target/s390x/kvm.c | 5 ++ target/s390x/kvm_s390x.h | 1 + 14 files changed, 468 insertions(+), 10 deletions(-) create mode 100644 hw/s390x/pv.c create mode 100644 include/hw/s390x/pv.h diff --git a/MAINTAINERS b/MAINTAINERS index 8cbc1fac2b..831d4b014a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -396,6 +396,8 @@ F: target/s390x/machine.c F: target/s390x/sigp.c F: target/s390x/cpu_features*.[ch] F: target/s390x/cpu_models.[ch] +F: hw/s390x/pv.c +F: include/hw/s390x/pv.h F: hw/intc/s390_flic.c F: hw/intc/s390_flic_kvm.c F: include/hw/s390x/s390_flic.h diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index e02ed80b68..a46a1c7894 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -31,6 +31,7 @@ obj-y += tod-qemu.o obj-$(CONFIG_KVM) += tod-kvm.o obj-$(CONFIG_KVM) += s390-skeys-kvm.o obj-$(CONFIG_KVM) += s390-stattrib-kvm.o +obj-$(CONFIG_KVM) += pv.o obj-y += s390-ccw.o obj-y += ap-device.o obj-y += ap-bridge.o diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 8c3e019571..ce21494c08 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -1,10 +1,11 @@ /* * bootloader support * - * Copyright IBM, Corp. 2012 + * Copyright IBM, Corp. 2012, 2020 * * Authors: * Christian Borntraeger + * Janosch Frank * * This work is licensed under the terms of the GNU GPL, version 2 or (at your * option) any later version. See the COPYING file in the top-level directory. @@ -27,6 +28,7 @@ #include "hw/s390x/vfio-ccw.h" #include "hw/s390x/css.h" #include "hw/s390x/ebcdic.h" +#include "hw/s390x/pv.h" #include "ipl.h" #include "qemu/error-report.h" #include "qemu/config-file.h" @@ -566,12 +568,31 @@ void s390_ipl_update_diag308(IplParameterBlock *iplb) { S390IPLState *ipl = get_ipl_device(); - ipl->iplb = *iplb; - ipl->iplb_valid = true; + /* + * The IPLB set and retrieved by subcodes 8/9 is completely + * separate from the one managed via subcodes 5/6. + */ + if (iplb->pbt == S390_IPL_TYPE_PV) { + ipl->iplb_pv = *iplb; + ipl->iplb_valid_pv = true; + } else { + ipl->iplb = *iplb; + ipl->iplb_valid = true; + } ipl->netboot = is_virtio_net_device(iplb); update_machine_ipl_properties(iplb); } +IplParameterBlock *s390_ipl_get_iplb_pv(void) +{ + S390IPLState *ipl = get_ipl_device(); + + if (!ipl->iplb_valid_pv) { + return NULL; + } + return &ipl->iplb_pv; +} + IplParameterBlock *s390_ipl_get_iplb(void) { S390IPLState *ipl = get_ipl_device(); @@ -660,6 +681,38 @@ static void s390_ipl_prepare_qipl(S390CPU *cpu) cpu_physical_memory_unmap(addr, len, 1, len); } +int s390_ipl_prepare_pv_header(void) +{ + IplParameterBlock *ipib = s390_ipl_get_iplb_pv(); + IPLBlockPV *ipib_pv = &ipib->pv; + void *hdr = g_malloc(ipib_pv->pv_header_len); + int rc; + + cpu_physical_memory_read(ipib_pv->pv_header_addr, hdr, + ipib_pv->pv_header_len); + rc = s390_pv_set_sec_parms((uintptr_t)hdr, + ipib_pv->pv_header_len); + g_free(hdr); + return rc; +} + +int s390_ipl_pv_unpack(void) +{ + IplParameterBlock *ipib = s390_ipl_get_iplb_pv(); + IPLBlockPV *ipib_pv = &ipib->pv; + int i, rc = 0; + + for (i = 0; i < ipib_pv->num_comp; i++) { + rc = s390_pv_unpack(ipib_pv->components[i].addr, + TARGET_PAGE_ALIGN(ipib_pv->components[i].size), + ipib_pv->components[i].tweak_pref); + if (rc) { + break; + } + } + return rc; +} + void s390_ipl_prepare_cpu(S390CPU *cpu) { S390IPLState *ipl = get_ipl_device(); diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index a5665e6bfd..89b3044d7a 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -1,8 +1,9 @@ /* * s390 IPL device * - * Copyright 2015 IBM Corp. + * Copyright 2015, 2020 IBM Corp. * Author(s): Zhang Fan + * Janosch Frank * * This work is licensed under the terms of the GNU GPL, version 2 or (at * your option) any later version. See the COPYING file in the top-level @@ -15,6 +16,24 @@ #include "cpu.h" #include "hw/qdev-core.h" +struct IPLBlockPVComp { + uint64_t tweak_pref; + uint64_t addr; + uint64_t size; +} QEMU_PACKED; +typedef struct IPLBlockPVComp IPLBlockPVComp; + +struct IPLBlockPV { + uint8_t reserved18[87]; /* 0x18 */ + uint8_t version; /* 0x6f */ + uint32_t reserved70; /* 0x70 */ + uint32_t num_comp; /* 0x74 */ + uint64_t pv_header_addr; /* 0x78 */ + uint64_t pv_header_len; /* 0x80 */ + struct IPLBlockPVComp components[]; +} QEMU_PACKED; +typedef struct IPLBlockPV IPLBlockPV; + struct IplBlockCcw { uint8_t reserved0[85]; uint8_t ssid; @@ -71,6 +90,7 @@ union IplParameterBlock { union { IplBlockCcw ccw; IplBlockFcp fcp; + IPLBlockPV pv; IplBlockQemuScsi scsi; }; } QEMU_PACKED; @@ -85,8 +105,11 @@ typedef union IplParameterBlock IplParameterBlock; int s390_ipl_set_loadparm(uint8_t *loadparm); void s390_ipl_update_diag308(IplParameterBlock *iplb); +int s390_ipl_prepare_pv_header(void); +int s390_ipl_pv_unpack(void); void s390_ipl_prepare_cpu(S390CPU *cpu); IplParameterBlock *s390_ipl_get_iplb(void); +IplParameterBlock *s390_ipl_get_iplb_pv(void); enum s390_reset { /* default is a reset not triggered by a CPU e.g. issued by QMP */ @@ -94,6 +117,7 @@ enum s390_reset { S390_RESET_REIPL, S390_RESET_MODIFIED_CLEAR, S390_RESET_LOAD_NORMAL, + S390_RESET_PV, }; void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type); void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type); @@ -133,6 +157,7 @@ struct S390IPLState { /*< private >*/ DeviceState parent_obj; IplParameterBlock iplb; + IplParameterBlock iplb_pv; QemuIplParameters qipl; uint64_t start_addr; uint64_t compat_start_addr; @@ -140,6 +165,7 @@ struct S390IPLState { uint64_t compat_bios_start_addr; bool enforce_bios; bool iplb_valid; + bool iplb_valid_pv; bool netboot; /* reset related properties don't have to be migrated or reset */ enum s390_reset reset_type; @@ -162,6 +188,8 @@ QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong"); #define DIAG_308_RC_OK 0x0001 #define DIAG_308_RC_NO_CONF 0x0102 #define DIAG_308_RC_INVALID 0x0402 +#define DIAG_308_RC_NO_PV_CONF 0x0902 +#define DIAG_308_RC_INVAL_FOR_PV 0x0a02 #define DIAG308_RESET_MOD_CLR 0 #define DIAG308_RESET_LOAD_NORM 1 @@ -169,12 +197,17 @@ QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong"); #define DIAG308_LOAD_NORMAL_DUMP 4 #define DIAG308_SET 5 #define DIAG308_STORE 6 +#define DIAG308_PV_SET 8 +#define DIAG308_PV_STORE 9 +#define DIAG308_PV_START 10 #define S390_IPL_TYPE_FCP 0x00 #define S390_IPL_TYPE_CCW 0x02 +#define S390_IPL_TYPE_PV 0x05 #define S390_IPL_TYPE_QEMU_SCSI 0xff #define S390_IPLB_HEADER_LEN 8 +#define S390_IPLB_MIN_PV_LEN 148 #define S390_IPLB_MIN_CCW_LEN 200 #define S390_IPLB_MIN_FCP_LEN 384 #define S390_IPLB_MIN_QEMU_SCSI_LEN 200 @@ -184,6 +217,62 @@ static inline bool iplb_valid_len(IplParameterBlock *iplb) return be32_to_cpu(iplb->len) <= sizeof(IplParameterBlock); } +static inline bool ipl_valid_pv_components(IplParameterBlock *iplb) +{ + IPLBlockPV *ipib_pv = &iplb->pv; + int i; + + if (ipib_pv->num_comp == 0) { + return false; + } + + for (i = 0; i < ipib_pv->num_comp; i++) { + /* Addr must be 4k aligned */ + if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) { + return false; + } + + /* Tweak prefix is monotonically increasing with each component */ + if (i < ipib_pv->num_comp - 1 && + ipib_pv->components[i].tweak_pref >= + ipib_pv->components[i + 1].tweak_pref) { + return false; + } + } + return true; +} + +static inline bool ipl_valid_pv_header(IplParameterBlock *iplb) +{ + IPLBlockPV *ipib_pv = &iplb->pv; + + if (ipib_pv->pv_header_len > 2 * TARGET_PAGE_SIZE) { + return false; + } + + if (!address_space_access_valid(&address_space_memory, + ipib_pv->pv_header_addr, + ipib_pv->pv_header_len, + false, + MEMTXATTRS_UNSPECIFIED)) { + return false; + } + + return true; +} + +static inline bool iplb_valid_pv(IplParameterBlock *iplb) +{ + if (iplb->pbt != S390_IPL_TYPE_PV || + be32_to_cpu(iplb->len) < S390_IPLB_MIN_PV_LEN) { + return false; + } + if (!ipl_valid_pv_header(iplb)) { + return false; + } + return ipl_valid_pv_components(iplb); +} + static inline bool iplb_valid(IplParameterBlock *iplb) { switch (iplb->pbt) { diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c new file mode 100644 index 0000000000..a40a844806 --- /dev/null +++ b/hw/s390x/pv.c @@ -0,0 +1,98 @@ +/* + * Protected Virtualization functions + * + * Copyright IBM Corp. 2020 + * Author(s): + * Janosch Frank + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ +#include "qemu/osdep.h" + +#include + +#include "qemu/error-report.h" +#include "sysemu/kvm.h" +#include "hw/s390x/pv.h" + +static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data) +{ + struct kvm_pv_cmd pv_cmd = { + .cmd = cmd, + .data = (uint64_t)data, + }; + int rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd); + + if (rc) { + error_report("KVM PV command %d (%s) failed: header rc %x rrc %x " + "IOCTL rc: %d", cmd, cmdname, pv_cmd.rc, pv_cmd.rrc, + rc); + } + return rc; +} + +/* + * This macro lets us pass the command as a string to the function so + * we can print it on an error. + */ +#define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data); +#define s390_pv_cmd_exit(cmd, data) \ +{ \ + int rc; \ + \ + rc = __s390_pv_cmd(cmd, #cmd, data);\ + if (rc) { \ + exit(1); \ + } \ +} + +int s390_pv_vm_enable(void) +{ + return s390_pv_cmd(KVM_PV_ENABLE, NULL); +} + +void s390_pv_vm_disable(void) +{ + s390_pv_cmd_exit(KVM_PV_DISABLE, NULL); +} + +int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) +{ + struct kvm_s390_pv_sec_parm args = { + .origin = origin, + .length = length, + }; + + return s390_pv_cmd(KVM_PV_SET_SEC_PARMS, &args); +} + +/* + * Called for each component in the SE type IPL parameter block 0. + */ +int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) +{ + struct kvm_s390_pv_unp args = { + .addr = addr, + .size = size, + .tweak = tweak, + }; + + return s390_pv_cmd(KVM_PV_UNPACK, &args); +} + +void s390_pv_perf_clear_reset(void) +{ + s390_pv_cmd_exit(KVM_PV_PREP_RESET, NULL); +} + +int s390_pv_verify(void) +{ + return s390_pv_cmd(KVM_PV_VERIFY, NULL); +} + +void s390_pv_unshare(void) +{ + s390_pv_cmd_exit(KVM_PV_UNSHARE_ALL, NULL); +} diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 0fa00a9fff..b4d681da43 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -1,9 +1,10 @@ /* * virtio ccw machine * - * Copyright 2012 IBM Corp. + * Copyright 2012, 2020 IBM Corp. * Copyright (c) 2009 Alexander Graf * Author(s): Cornelia Huck + * Janosch Frank * * This work is licensed under the terms of the GNU GPL, version 2 or (at * your option) any later version. See the COPYING file in the top-level @@ -42,6 +43,8 @@ #include "hw/qdev-properties.h" #include "hw/s390x/tod.h" #include "sysemu/sysemu.h" +#include "hw/s390x/pv.h" +#include S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) { @@ -317,10 +320,78 @@ static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg) s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); } +static void s390_machine_unprotect(S390CcwMachineState *ms) +{ + s390_pv_vm_disable(); + ms->pv = false; +} + +static int s390_machine_protect(S390CcwMachineState *ms) +{ + int rc; + + /* Create SE VM */ + rc = s390_pv_vm_enable(); + if (rc) { + return rc; + } + + ms->pv = true; + + /* Set SE header and unpack */ + rc = s390_ipl_prepare_pv_header(); + if (rc) { + goto out_err; + } + + /* Decrypt image */ + rc = s390_ipl_pv_unpack(); + if (rc) { + goto out_err; + } + + /* Verify integrity */ + rc = s390_pv_verify(); + if (rc) { + goto out_err; + } + return rc; + +out_err: + s390_machine_unprotect(ms); + return rc; +} + +static void s390_machine_inject_pv_error(CPUState *cs) +{ + int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4; + CPUS390XState *env = &S390_CPU(cs)->env; + + /* Report that we are unable to enter protected mode */ + env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; +} + +static void s390_pv_prepare_reset(S390CcwMachineState *ms) +{ + CPUState *cs; + + if (!s390_is_pv()) { + return; + } + /* Unsharing requires all cpus to be stopped */ + CPU_FOREACH(cs) { + s390_cpu_set_state(S390_CPU_STATE_STOPPED, S390_CPU(cs)); + } + s390_pv_unshare(); + s390_pv_perf_clear_reset(); +} + static void s390_machine_reset(MachineState *machine) { + S390CcwMachineState *ms = S390_CCW_MACHINE(machine); enum s390_reset reset_type; CPUState *cs, *t; + S390CPU *cpu; /* get the reset parameters, reset them once done */ s390_ipl_get_reset_request(&cs, &reset_type); @@ -328,9 +399,15 @@ static void s390_machine_reset(MachineState *machine) /* all CPUs are paused and synchronized at this point */ s390_cmma_reset(); + cpu = S390_CPU(cs); + switch (reset_type) { case S390_RESET_EXTERNAL: case S390_RESET_REIPL: + if (s390_is_pv()) { + s390_machine_unprotect(ms); + } + qemu_devices_reset(); s390_crypto_reset(); @@ -338,22 +415,56 @@ static void s390_machine_reset(MachineState *machine) run_on_cpu(cs, s390_do_cpu_ipl, RUN_ON_CPU_NULL); break; case S390_RESET_MODIFIED_CLEAR: + /* + * Susbsystem reset needs to be done before we unshare memory + * and lose access to VIRTIO structures in guest memory. + */ + subsystem_reset(); + s390_crypto_reset(); + s390_pv_prepare_reset(ms); CPU_FOREACH(t) { run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); } - subsystem_reset(); - s390_crypto_reset(); run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL); break; case S390_RESET_LOAD_NORMAL: + /* + * Susbsystem reset needs to be done before we unshare memory + * and lose access to VIRTIO structures in guest memory. + */ + subsystem_reset(); + s390_pv_prepare_reset(ms); CPU_FOREACH(t) { if (t == cs) { continue; } run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL); } - subsystem_reset(); run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL); + run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL); + break; + case S390_RESET_PV: /* Subcode 10 */ + subsystem_reset(); + s390_crypto_reset(); + + CPU_FOREACH(t) { + if (t == cs) { + continue; + } + run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); + } + run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL); + + if (s390_machine_protect(ms)) { + s390_machine_inject_pv_error(cs); + /* + * Continue after the diag308 so the guest knows something + * went wrong. + */ + s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); + return; + } + run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL); break; default: diff --git a/include/hw/s390x/pv.h b/include/hw/s390x/pv.h new file mode 100644 index 0000000000..c6cb360f2f --- /dev/null +++ b/include/hw/s390x/pv.h @@ -0,0 +1,55 @@ +/* + * Protected Virtualization header + * + * Copyright IBM Corp. 2020 + * Author(s): + * Janosch Frank + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ +#ifndef HW_S390_PV_H +#define HW_S390_PV_H + +#ifdef CONFIG_KVM +#include "hw/s390x/s390-virtio-ccw.h" + +static inline bool s390_is_pv(void) +{ + static S390CcwMachineState *ccw; + Object *obj; + + if (ccw) { + return ccw->pv; + } + + /* we have to bail out for the "none" machine */ + obj = object_dynamic_cast(qdev_get_machine(), + TYPE_S390_CCW_MACHINE); + if (!obj) { + return false; + } + ccw = S390_CCW_MACHINE(obj); + return ccw->pv; +} + +int s390_pv_vm_enable(void); +void s390_pv_vm_disable(void); +int s390_pv_set_sec_parms(uint64_t origin, uint64_t length); +int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak); +void s390_pv_perf_clear_reset(void); +int s390_pv_verify(void); +void s390_pv_unshare(void); +#else /* CONFIG_KVM */ +static inline bool s390_is_pv(void) { return false; } +static inline int s390_pv_vm_enable(void) { return 0; } +static inline void s390_pv_vm_disable(void) {} +static inline int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) { return 0; } +static inline int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) { return 0; } +static inline void s390_pv_perf_clear_reset(void) {} +static inline int s390_pv_verify(void) { return 0; } +static inline void s390_pv_unshare(void) {} +#endif /* CONFIG_KVM */ + +#endif /* HW_S390_PV_H */ diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h index 8aa27199c9..cd1dccc6e3 100644 --- a/include/hw/s390x/s390-virtio-ccw.h +++ b/include/hw/s390x/s390-virtio-ccw.h @@ -28,6 +28,7 @@ typedef struct S390CcwMachineState { /*< public >*/ bool aes_key_wrap; bool dea_key_wrap; + bool pv; uint8_t loadparm[8]; } S390CcwMachineState; diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 427a46e3e1..bb7a588e3b 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -37,6 +37,7 @@ #include "sysemu/hw_accel.h" #include "hw/qdev-properties.h" #ifndef CONFIG_USER_ONLY +#include "hw/s390x/pv.h" #include "hw/boards.h" #include "sysemu/arch_init.h" #include "sysemu/sysemu.h" diff --git a/target/s390x/cpu_features_def.inc.h b/target/s390x/cpu_features_def.inc.h index 31dff0d84e..60db28351d 100644 --- a/target/s390x/cpu_features_def.inc.h +++ b/target/s390x/cpu_features_def.inc.h @@ -107,6 +107,7 @@ DEF_FEAT(DEFLATE_BASE, "deflate-base", STFL, 151, "Deflate-conversion facility ( DEF_FEAT(VECTOR_PACKED_DECIMAL_ENH, "vxpdeh", STFL, 152, "Vector-Packed-Decimal-Enhancement Facility") DEF_FEAT(MSA_EXT_9, "msa9-base", STFL, 155, "Message-security-assist-extension-9 facility (excluding subfunctions)") DEF_FEAT(ETOKEN, "etoken", STFL, 156, "Etoken facility") +DEF_FEAT(UNPACK, "unpack", STFL, 161, "Unpack facility") /* Features exposed via SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */ DEF_FEAT(SIE_GSLS, "gsls", SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility") diff --git a/target/s390x/diag.c b/target/s390x/diag.c index 8aba6341f9..b2cbefb8cf 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -20,6 +20,8 @@ #include "sysemu/cpus.h" #include "hw/s390x/ipl.h" #include "hw/s390x/s390-virtio-ccw.h" +#include "hw/s390x/pv.h" +#include "kvm_s390x.h" int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3) { @@ -52,6 +54,10 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3) static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr, uintptr_t ra, bool write) { + /* Handled by the Ultravisor */ + if (s390_is_pv()) { + return 0; + } if ((r1 & 1) || (addr & ~TARGET_PAGE_MASK)) { s390_program_interrupt(env, PGM_SPECIFICATION, ra); return -1; @@ -67,6 +73,7 @@ static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr, void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) { + bool valid; CPUState *cs = env_cpu(env); uint64_t addr = env->regs[r1]; uint64_t subcode = env->regs[r3]; @@ -82,6 +89,11 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) return; } + if (subcode >= DIAG308_PV_SET && !s390_has_feat(S390_FEAT_UNPACK)) { + s390_program_interrupt(env, PGM_SPECIFICATION, ra); + return; + } + switch (subcode) { case DIAG308_RESET_MOD_CLR: s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR); @@ -94,6 +106,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) s390_ipl_reset_request(cs, S390_RESET_REIPL); break; case DIAG308_SET: + case DIAG308_PV_SET: if (diag308_parm_check(env, r1, addr, ra, false)) { return; } @@ -106,7 +119,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len)); - if (!iplb_valid(iplb)) { + valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb); + if (!valid) { env->regs[r1 + 1] = DIAG_308_RC_INVALID; goto out; } @@ -117,10 +131,15 @@ out: g_free(iplb); return; case DIAG308_STORE: + case DIAG308_PV_STORE: if (diag308_parm_check(env, r1, addr, ra, true)) { return; } - iplb = s390_ipl_get_iplb(); + if (subcode == DIAG308_PV_STORE) { + iplb = s390_ipl_get_iplb_pv(); + } else { + iplb = s390_ipl_get_iplb(); + } if (iplb) { cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len)); env->regs[r1 + 1] = DIAG_308_RC_OK; @@ -128,6 +147,22 @@ out: env->regs[r1 + 1] = DIAG_308_RC_NO_CONF; } return; + case DIAG308_PV_START: + iplb = s390_ipl_get_iplb_pv(); + if (!iplb) { + env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF; + return; + } + + if (kvm_s390_get_hpage_1m()) { + error_report("Protected VMs can currently not be backed with " + "huge pages"); + env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; + return; + } + + s390_ipl_reset_request(cs, S390_RESET_PV); + break; default: s390_program_interrupt(env, PGM_SPECIFICATION, ra); break; diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c index c4cd497f85..aa185017a2 100644 --- a/target/s390x/kvm-stub.c +++ b/target/s390x/kvm-stub.c @@ -39,6 +39,11 @@ int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) return 0; } +int kvm_s390_get_hpage_1m(void) +{ + return 0; +} + int kvm_s390_get_ri(void) { return 0; diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 7f7ebab842..b2b14bde2b 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -321,6 +321,11 @@ void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp) cap_hpage_1m = 1; } +int kvm_s390_get_hpage_1m(void) +{ + return cap_hpage_1m; +} + static void ccw_machine_class_foreach(ObjectClass *oc, void *opaque) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h index 0b21789796..dea813f450 100644 --- a/target/s390x/kvm_s390x.h +++ b/target/s390x/kvm_s390x.h @@ -23,6 +23,7 @@ void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code); int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); +int kvm_s390_get_hpage_1m(void); int kvm_s390_get_ri(void); int kvm_s390_get_gs(void); int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock); From 0141e1b47707d90f5bd9d252da064ebdaca698a6 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:09 -0400 Subject: [PATCH 0037/2595] s390x: protvirt: Add migration blocker Migration is not yet supported. Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Message-Id: <20200319131921.2367-5-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index b4d681da43..e00040a00b 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -45,6 +45,9 @@ #include "sysemu/sysemu.h" #include "hw/s390x/pv.h" #include +#include "migration/blocker.h" + +static Error *pv_mig_blocker; S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) { @@ -324,15 +327,30 @@ static void s390_machine_unprotect(S390CcwMachineState *ms) { s390_pv_vm_disable(); ms->pv = false; + migrate_del_blocker(pv_mig_blocker); + error_free_or_abort(&pv_mig_blocker); } static int s390_machine_protect(S390CcwMachineState *ms) { + Error *local_err = NULL; int rc; + error_setg(&pv_mig_blocker, + "protected VMs are currently not migrateable."); + rc = migrate_add_blocker(pv_mig_blocker, &local_err); + if (rc) { + error_report_err(local_err); + error_free_or_abort(&pv_mig_blocker); + return rc; + } + /* Create SE VM */ rc = s390_pv_vm_enable(); if (rc) { + error_report_err(local_err); + migrate_del_blocker(pv_mig_blocker); + error_free_or_abort(&pv_mig_blocker); return rc; } From b1697f63fd8f8201b1447bb55f595830b9cbde31 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:10 -0400 Subject: [PATCH 0038/2595] s390x: protvirt: Inhibit balloon when switching to protected mode Ballooning in protected VMs can only be done when the guest shares the pages it gives to the host. If pages are not shared, the integrity checks will fail once those pages have been altered and are given back to the guest. As we currently do not yet have a solution for this we will continue like this: 1. We block ballooning now in QEMU (with this patch). 2. Later we will provide a change to virtio that removes the blocker and adds VIRTIO_F_IOMMU_PLATFORM automatically by QEMU when doing the protvirt switch. This is OK, as the balloon driver in Linux (the only supported guest) will refuse to work with the IOMMU_PLATFORM feature bit set. 3. Later, we can fix the guest balloon driver to accept the IOMMU feature bit and correctly exercise sharing and unsharing of balloon pages. Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Message-Id: <20200319131921.2367-6-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index e00040a00b..db45249320 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -43,6 +43,7 @@ #include "hw/qdev-properties.h" #include "hw/s390x/tod.h" #include "sysemu/sysemu.h" +#include "sysemu/balloon.h" #include "hw/s390x/pv.h" #include #include "migration/blocker.h" @@ -329,6 +330,7 @@ static void s390_machine_unprotect(S390CcwMachineState *ms) ms->pv = false; migrate_del_blocker(pv_mig_blocker); error_free_or_abort(&pv_mig_blocker); + qemu_balloon_inhibit(false); } static int s390_machine_protect(S390CcwMachineState *ms) @@ -336,10 +338,18 @@ static int s390_machine_protect(S390CcwMachineState *ms) Error *local_err = NULL; int rc; + /* + * Ballooning on protected VMs needs support in the guest for + * sharing and unsharing balloon pages. Block ballooning for + * now, until we have a solution to make at least Linux guests + * either support it or fail gracefully. + */ + qemu_balloon_inhibit(true); error_setg(&pv_mig_blocker, "protected VMs are currently not migrateable."); rc = migrate_add_blocker(pv_mig_blocker, &local_err); if (rc) { + qemu_balloon_inhibit(false); error_report_err(local_err); error_free_or_abort(&pv_mig_blocker); return rc; @@ -348,6 +358,7 @@ static int s390_machine_protect(S390CcwMachineState *ms) /* Create SE VM */ rc = s390_pv_vm_enable(); if (rc) { + qemu_balloon_inhibit(false); error_report_err(local_err); migrate_del_blocker(pv_mig_blocker); error_free_or_abort(&pv_mig_blocker); From 2585e507ffa1da01b57dbea26b1e1fe507d27198 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:11 -0400 Subject: [PATCH 0039/2595] s390x: protvirt: KVM intercept changes Protected VMs no longer intercept with code 4 for an instruction interception. Instead they have codes 104 and 108 for protected instruction interception and protected instruction notification respectively. The 104 mirrors the 4 interception. The 108 is a notification interception to let KVM and QEMU know that something changed and we need to update tracking information or perform specific tasks. It's currently taken for the following instructions: * spx (To inform about the changed prefix location) * sclp (On incorrect SCCB values, so we can inject a IRQ) * sigp (All but "stop and store status") * diag308 (Subcodes 0/1) Of these exits only sclp errors, state changing sigps and diag308 will reach QEMU. QEMU will do its parts of the job, while the ultravisor has done the instruction part of the job. Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Message-Id: <20200319131921.2367-7-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- target/s390x/kvm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index b2b14bde2b..1988809ec2 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -115,6 +115,8 @@ #define ICPT_CPU_STOP 0x28 #define ICPT_OPEREXC 0x2c #define ICPT_IO 0x40 +#define ICPT_PV_INSTR 0x68 +#define ICPT_PV_INSTR_NOTIFICATION 0x6c #define NR_LOCAL_IRQS 32 /* @@ -1698,6 +1700,8 @@ static int handle_intercept(S390CPU *cpu) (long)cs->kvm_run->psw_addr); switch (icpt_code) { case ICPT_INSTRUCTION: + case ICPT_PV_INSTR: + case ICPT_PV_INSTR_NOTIFICATION: r = handle_instruction(cpu, run); break; case ICPT_PROGRAM: From 1cca8265499d394d9ed4bfb75bd6e7265b529f89 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:12 -0400 Subject: [PATCH 0040/2595] s390x: Add SIDA memory ops Protected guests save the instruction control blocks in the SIDA instead of QEMU/KVM directly accessing the guest's memory. Let's introduce new functions to access the SIDA. The memops for doing so are available with KVM_CAP_S390_PROTECTED, so let's check for that. Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Message-Id: <20200319131921.2367-8-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- target/s390x/cpu.h | 7 ++++++- target/s390x/kvm.c | 26 ++++++++++++++++++++++++++ target/s390x/kvm_s390x.h | 2 ++ target/s390x/mmu_helper.c | 14 ++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 1d17709d6e..035427521c 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -823,7 +823,12 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf, #define s390_cpu_virt_mem_check_write(cpu, laddr, ar, len) \ s390_cpu_virt_mem_rw(cpu, laddr, ar, NULL, len, true) void s390_cpu_virt_mem_handle_exc(S390CPU *cpu, uintptr_t ra); - +int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf, + int len, bool is_write); +#define s390_cpu_pv_mem_read(cpu, offset, dest, len) \ + s390_cpu_pv_mem_rw(cpu, offset, dest, len, false) +#define s390_cpu_pv_mem_write(cpu, offset, dest, len) \ + s390_cpu_pv_mem_rw(cpu, offset, dest, len, true) /* sigp.c */ int s390_cpu_restart(S390CPU *cpu); diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 1988809ec2..0e93778ed1 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -154,6 +154,7 @@ static int cap_ri; static int cap_gs; static int cap_hpage_1m; static int cap_vcpu_resets; +static int cap_protected; static int active_cmma; @@ -351,6 +352,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP); cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ); cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS); + cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED); if (!kvm_check_extension(s, KVM_CAP_S390_GMAP) || !kvm_check_extension(s, KVM_CAP_S390_COW)) { @@ -851,6 +853,30 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, return ret; } +int kvm_s390_mem_op_pv(S390CPU *cpu, uint64_t offset, void *hostbuf, + int len, bool is_write) +{ + struct kvm_s390_mem_op mem_op = { + .sida_offset = offset, + .size = len, + .op = is_write ? KVM_S390_MEMOP_SIDA_WRITE + : KVM_S390_MEMOP_SIDA_READ, + .buf = (uint64_t)hostbuf, + }; + int ret; + + if (!cap_mem_op || !cap_protected) { + return -ENOSYS; + } + + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op); + if (ret < 0) { + error_report("KVM_S390_MEM_OP failed: %s", strerror(-ret)); + abort(); + } + return ret; +} + /* * Legacy layout for s390: * Older S390 KVM requires the topmost vma of the RAM to be diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h index dea813f450..6ab17c81b7 100644 --- a/target/s390x/kvm_s390x.h +++ b/target/s390x/kvm_s390x.h @@ -19,6 +19,8 @@ void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq); void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code); int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, int len, bool is_write); +int kvm_s390_mem_op_pv(S390CPU *cpu, vaddr addr, void *hostbuf, int len, + bool is_write); void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code); int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index 0be2f300bb..7d9f3059cd 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -474,6 +474,20 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages, return 0; } +int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf, + int len, bool is_write) +{ + int ret; + + if (kvm_enabled()) { + ret = kvm_s390_mem_op_pv(cpu, offset, hostbuf, len, is_write); + } else { + /* Protected Virtualization is a KVM/Hardware only feature */ + g_assert_not_reached(); + } + return ret; +} + /** * s390_cpu_virt_mem_rw: * @laddr: the logical start address From 7c713b8acb70fb61f9650f8a7702dec546752bb6 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:13 -0400 Subject: [PATCH 0041/2595] s390x: protvirt: Move STSI data over SIDAD For protected guests, we need to put the STSI emulation results into the SIDA, so SIE will write them into the guest at the next entry. Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Message-Id: <20200319131921.2367-9-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- target/s390x/kvm.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 0e93778ed1..e0b61680ab 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -50,6 +50,7 @@ #include "exec/memattrs.h" #include "hw/s390x/s390-virtio-ccw.h" #include "hw/s390x/s390-virtio-hcall.h" +#include "hw/s390x/pv.h" #ifndef DEBUG_KVM #define DEBUG_KVM 0 @@ -1808,7 +1809,9 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar) SysIB_322 sysib; int del, i; - if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) { + if (s390_is_pv()) { + s390_cpu_pv_mem_read(cpu, 0, &sysib, sizeof(sysib)); + } else if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) { return; } /* Shift the stack of Extended Names to prepare for our own data */ @@ -1861,7 +1864,11 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar) /* Insert UUID */ memcpy(sysib.vm[0].uuid, &qemu_uuid, sizeof(sysib.vm[0].uuid)); - s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib)); + if (s390_is_pv()) { + s390_cpu_pv_mem_write(cpu, 0, &sysib, sizeof(sysib)); + } else { + s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib)); + } } static int handle_stsi(S390CPU *cpu) From 0f73c5b30b8ba6c0828608be496d2f59a5427539 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:14 -0400 Subject: [PATCH 0042/2595] s390x: protvirt: SCLP interpretation SCLP for a protected guest is done over the SIDAD, so we need to use the s390_cpu_pv_mem_* functions to access the SIDAD instead of guest memory when reading/writing SCBs. To not confuse the sclp emulation, we set 0x4000 as the SCCB address, since the function that injects the sclp external interrupt would reject a zero sccb address. Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Reviewed-by: Christian Borntraeger Message-Id: <20200319131921.2367-10-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/sclp.c | 56 +++++++++++++++++++++++++++++++++-------- include/hw/s390x/sclp.h | 2 ++ target/s390x/kvm.c | 25 ++++++++++++++---- 3 files changed, 67 insertions(+), 16 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index f0c35aa57a..ede056b3ef 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -33,6 +33,22 @@ static inline SCLPDevice *get_sclp_device(void) return sclp; } +static inline bool sclp_command_code_valid(uint32_t 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: + return true; + } + return false; +} + static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int *count) { MachineState *ms = MACHINE(qdev_get_machine()); @@ -193,6 +209,34 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code) } } +/* + * We only need the address to have something valid for the + * service_interrupt call. + */ +#define SCLP_PV_DUMMY_ADDR 0x4000 +int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb, + uint32_t code) +{ + SCLPDevice *sclp = get_sclp_device(); + SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); + SCCB work_sccb; + hwaddr sccb_len = sizeof(SCCB); + + s390_cpu_pv_mem_read(env_archcpu(env), 0, &work_sccb, sccb_len); + + if (!sclp_command_code_valid(code)) { + work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + goto out_write; + } + + sclp_c->execute(sclp, &work_sccb, code); +out_write: + s390_cpu_pv_mem_write(env_archcpu(env), 0, &work_sccb, + be16_to_cpu(work_sccb.h.length)); + sclp_c->service_interrupt(sclp, SCLP_PV_DUMMY_ADDR); + return 0; +} + int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) { SCLPDevice *sclp = get_sclp_device(); @@ -225,17 +269,7 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) return -PGM_SPECIFICATION; } - 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: + if (!sclp_command_code_valid(code)) { work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); goto out_write; } diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index cd7b24359f..822eff4396 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -217,5 +217,7 @@ void s390_sclp_init(void); void sclp_service_interrupt(uint32_t sccb); void raise_irq_cpu_hotplug(void); int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code); +int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb, + uint32_t code); #endif diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index e0b61680ab..870dd1b52b 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -1233,12 +1233,27 @@ static void kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, sccb = env->regs[ipbh0 & 0xf]; code = env->regs[(ipbh0 & 0xf0) >> 4]; - r = sclp_service_call(env, sccb, code); - if (r < 0) { - kvm_s390_program_interrupt(cpu, -r); - return; + switch (run->s390_sieic.icptcode) { + case ICPT_PV_INSTR_NOTIFICATION: + g_assert(s390_is_pv()); + /* The notification intercepts are currently handled by KVM */ + error_report("unexpected SCLP PV notification"); + exit(1); + break; + case ICPT_PV_INSTR: + g_assert(s390_is_pv()); + sclp_service_call_protected(env, sccb, code); + /* Setting the CC is done by the Ultravisor. */ + break; + case ICPT_INSTRUCTION: + g_assert(!s390_is_pv()); + r = sclp_service_call(env, sccb, code); + if (r < 0) { + kvm_s390_program_interrupt(cpu, -r); + return; + } + setcc(cpu, r); } - setcc(cpu, r); } static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) From 59181010a2ff82c3a97e9b5768ee87c38e4815f1 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:15 -0400 Subject: [PATCH 0043/2595] s390x: protvirt: Set guest IPL PSW Handling of CPU reset and setting of the IPL psw from guest storage at offset 0 is done by a Ultravisor call. Let's only fetch it if necessary. Signed-off-by: Janosch Frank Reviewed-by: Thomas Huth Reviewed-by: David Hildenbrand Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Message-Id: <20200319131921.2367-11-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- target/s390x/cpu.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index bb7a588e3b..f2ccf0a06a 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -77,16 +77,24 @@ static bool s390_cpu_has_work(CPUState *cs) static void s390_cpu_load_normal(CPUState *s) { S390CPU *cpu = S390_CPU(s); - uint64_t spsw = ldq_phys(s->as, 0); - - cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL; - /* - * Invert short psw indication, so SIE will report a specification - * exception if it was not set. - */ - cpu->env.psw.mask ^= PSW_MASK_SHORTPSW; - cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR; + uint64_t spsw; + if (!s390_is_pv()) { + spsw = ldq_phys(s->as, 0); + cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL; + /* + * Invert short psw indication, so SIE will report a specification + * exception if it was not set. + */ + cpu->env.psw.mask ^= PSW_MASK_SHORTPSW; + cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR; + } else { + /* + * Firmware requires us to set the load state before we set + * the cpu to operating on protected guests. + */ + s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu); + } s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); } #endif From 9c61e11238cfa8f70e3eb90aac5d3e5646e5432f Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:16 -0400 Subject: [PATCH 0044/2595] s390x: protvirt: Move diag 308 data over SIDA For protected guests the IPIB is written/read to/from the SIDA, so we need those accesses to go through s390_cpu_pv_mem_read/write(). Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Message-Id: <20200319131921.2367-12-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- target/s390x/diag.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/target/s390x/diag.c b/target/s390x/diag.c index b2cbefb8cf..1a48429564 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -75,6 +75,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) { bool valid; CPUState *cs = env_cpu(env); + S390CPU *cpu = S390_CPU(cs); uint64_t addr = env->regs[r1]; uint64_t subcode = env->regs[r3]; IplParameterBlock *iplb; @@ -111,13 +112,22 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) return; } iplb = g_new0(IplParameterBlock, 1); - cpu_physical_memory_read(addr, iplb, sizeof(iplb->len)); + if (!s390_is_pv()) { + cpu_physical_memory_read(addr, iplb, sizeof(iplb->len)); + } else { + s390_cpu_pv_mem_read(cpu, 0, iplb, sizeof(iplb->len)); + } + if (!iplb_valid_len(iplb)) { env->regs[r1 + 1] = DIAG_308_RC_INVALID; goto out; } - cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len)); + if (!s390_is_pv()) { + cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len)); + } else { + s390_cpu_pv_mem_read(cpu, 0, iplb, be32_to_cpu(iplb->len)); + } valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb); if (!valid) { @@ -140,12 +150,17 @@ out: } else { iplb = s390_ipl_get_iplb(); } - if (iplb) { - cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len)); - env->regs[r1 + 1] = DIAG_308_RC_OK; - } else { + if (!iplb) { env->regs[r1 + 1] = DIAG_308_RC_NO_CONF; + return; } + + if (!s390_is_pv()) { + cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len)); + } else { + s390_cpu_pv_mem_write(cpu, 0, iplb, be32_to_cpu(iplb->len)); + } + env->regs[r1 + 1] = DIAG_308_RC_OK; return; case DIAG308_PV_START: iplb = s390_ipl_get_iplb_pv(); From c10b708752e5264a85b5c3afa0a0ccfcf6503ddf Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:17 -0400 Subject: [PATCH 0045/2595] s390x: protvirt: Disable address checks for PV guest IO emulation IO instruction data is routed through SIDAD for protected guests, so adresses do not need to be checked, as this is kernel memory which is always available. Also the instruction data always starts at offset 0 of the SIDAD. Signed-off-by: Janosch Frank Reviewed-by: Thomas Huth Reviewed-by: David Hildenbrand Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Message-Id: <20200319131921.2367-13-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- target/s390x/ioinst.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index 0e840cc579..8828482eec 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -16,6 +16,25 @@ #include "hw/s390x/ioinst.h" #include "trace.h" #include "hw/s390x/s390-pci-bus.h" +#include "hw/s390x/pv.h" + +/* All I/O instructions but chsc use the s format */ +static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb, + uint8_t *ar) +{ + /* + * Addresses for protected guests are all offsets into the + * satellite block which holds the IO control structures. Those + * control structures are always starting at offset 0 and are + * always aligned and accessible. So we can return 0 here which + * will pass the following address checks. + */ + if (s390_is_pv()) { + *ar = 0; + return 0; + } + return decode_basedisp_s(env, ipb, ar); +} int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid, int *schid) @@ -114,7 +133,7 @@ void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) CPUS390XState *env = &cpu->env; uint8_t ar; - addr = decode_basedisp_s(env, ipb, &ar); + addr = get_address_from_regs(env, ipb, &ar); if (addr & 3) { s390_program_interrupt(env, PGM_SPECIFICATION, ra); return; @@ -171,7 +190,7 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) CPUS390XState *env = &cpu->env; uint8_t ar; - addr = decode_basedisp_s(env, ipb, &ar); + addr = get_address_from_regs(env, ipb, &ar); if (addr & 3) { s390_program_interrupt(env, PGM_SPECIFICATION, ra); return; @@ -203,7 +222,7 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra) CPUS390XState *env = &cpu->env; uint8_t ar; - addr = decode_basedisp_s(env, ipb, &ar); + addr = get_address_from_regs(env, ipb, &ar); if (addr & 3) { s390_program_interrupt(env, PGM_SPECIFICATION, ra); return; @@ -234,7 +253,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, CPUS390XState *env = &cpu->env; uint8_t ar; - addr = decode_basedisp_s(env, ipb, &ar); + addr = get_address_from_regs(env, ipb, &ar); if (addr & 3) { s390_program_interrupt(env, PGM_SPECIFICATION, ra); return; @@ -303,7 +322,7 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) return -EIO; } trace_ioinst_sch_id("tsch", cssid, ssid, schid); - addr = decode_basedisp_s(env, ipb, &ar); + addr = get_address_from_regs(env, ipb, &ar); if (addr & 3) { s390_program_interrupt(env, PGM_SPECIFICATION, ra); return -EIO; @@ -601,7 +620,7 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra) { ChscReq *req; ChscResp *res; - uint64_t addr; + uint64_t addr = 0; int reg; uint16_t len; uint16_t command; @@ -610,7 +629,9 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra) trace_ioinst("chsc"); reg = (ipb >> 20) & 0x00f; - addr = env->regs[reg]; + if (!s390_is_pv()) { + addr = env->regs[reg]; + } /* Page boundary? */ if (addr & 0xfff) { s390_program_interrupt(env, PGM_SPECIFICATION, ra); From fcc10c1470d6e9460ebcf4c30f5bbd37b921a041 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:18 -0400 Subject: [PATCH 0046/2595] s390x: protvirt: Move IO control structures over SIDA For protected guests, we need to put the IO emulation results into the SIDA, so SIE will write them into the guest at the next entry. Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Cornelia Huck Message-Id: <20200319131921.2367-14-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- target/s390x/ioinst.c | 61 +++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index 8828482eec..7a14c52c12 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -138,7 +138,9 @@ void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) s390_program_interrupt(env, PGM_SPECIFICATION, ra); return; } - if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) { + if (s390_is_pv()) { + s390_cpu_pv_mem_read(cpu, addr, &schib, sizeof(schib)); + } else if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) { s390_cpu_virt_mem_handle_exc(cpu, ra); return; } @@ -195,7 +197,9 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) s390_program_interrupt(env, PGM_SPECIFICATION, ra); return; } - if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) { + if (s390_is_pv()) { + s390_cpu_pv_mem_read(cpu, addr, &orig_orb, sizeof(orb)); + } else if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) { s390_cpu_virt_mem_handle_exc(cpu, ra); return; } @@ -231,14 +235,19 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra) cc = css_do_stcrw(&crw); /* 0 - crw stored, 1 - zeroes stored */ - if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) { + if (s390_is_pv()) { + s390_cpu_pv_mem_write(cpu, addr, &crw, sizeof(crw)); setcc(cpu, cc); } else { - if (cc == 0) { - /* Write failed: requeue CRW since STCRW is suppressing */ - css_undo_stcrw(&crw); + if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) { + setcc(cpu, cc); + } else { + if (cc == 0) { + /* Write failed: requeue CRW since STCRW is suppressing */ + css_undo_stcrw(&crw); + } + s390_cpu_virt_mem_handle_exc(cpu, ra); } - s390_cpu_virt_mem_handle_exc(cpu, ra); } } @@ -260,6 +269,13 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, } if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { + /* + * The Ultravisor checks schid bit 16 to be one and bits 0-12 + * to be 0 and injects a operand exception itself. + * + * Hence we should never end up here. + */ + g_assert(!s390_is_pv()); /* * As operand exceptions have a lower priority than access exceptions, * we check whether the memory area is writeable (injecting the @@ -292,14 +308,17 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, } } if (cc != 3) { - if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib, - sizeof(schib)) != 0) { + if (s390_is_pv()) { + s390_cpu_pv_mem_write(cpu, addr, &schib, sizeof(schib)); + } else if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib, + sizeof(schib)) != 0) { s390_cpu_virt_mem_handle_exc(cpu, ra); return; } } else { /* Access exceptions have a higher priority than cc3 */ - if (s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) { + if (!s390_is_pv() && + s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) { s390_cpu_virt_mem_handle_exc(cpu, ra); return; } @@ -336,7 +355,9 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) } /* 0 - status pending, 1 - not status pending, 3 - not operational */ if (cc != 3) { - if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) { + if (s390_is_pv()) { + s390_cpu_pv_mem_write(cpu, addr, &irb, irb_len); + } else if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) { s390_cpu_virt_mem_handle_exc(cpu, ra); return -EFAULT; } @@ -344,7 +365,8 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) } else { irb_len = sizeof(irb) - sizeof(irb.emw); /* Access exceptions have a higher priority than cc3 */ - if (s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) { + if (!s390_is_pv() && + s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) { s390_cpu_virt_mem_handle_exc(cpu, ra); return -EFAULT; } @@ -642,7 +664,9 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra) * present CHSC sub-handlers ... if we ever need more, we should take * care of req->len here first. */ - if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) { + if (s390_is_pv()) { + s390_cpu_pv_mem_read(cpu, addr, buf, sizeof(ChscReq)); + } else if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) { s390_cpu_virt_mem_handle_exc(cpu, ra); return; } @@ -675,11 +699,16 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra) break; } - if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res, - be16_to_cpu(res->len))) { + if (s390_is_pv()) { + s390_cpu_pv_mem_write(cpu, addr + len, res, be16_to_cpu(res->len)); setcc(cpu, 0); /* Command execution complete */ } else { - s390_cpu_virt_mem_handle_exc(cpu, ra); + if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res, + be16_to_cpu(res->len))) { + setcc(cpu, 0); /* Command execution complete */ + } else { + s390_cpu_virt_mem_handle_exc(cpu, ra); + } } } From f2a2d9a2bae8f6fdc5e9a40c1241e9428f15b4df Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:19 -0400 Subject: [PATCH 0047/2595] s390x: protvirt: Handle SIGP store status correctly For protected VMs status storing is not done by QEMU anymore. Signed-off-by: Janosch Frank Reviewed-by: Thomas Huth Reviewed-by: David Hildenbrand Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Message-Id: <20200319131921.2367-15-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target/s390x/helper.c b/target/s390x/helper.c index ed72684911..09f60406aa 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -25,6 +25,7 @@ #include "qemu/timer.h" #include "qemu/qemu-print.h" #include "hw/s390x/ioinst.h" +#include "hw/s390x/pv.h" #include "sysemu/hw_accel.h" #include "sysemu/runstate.h" #ifndef CONFIG_USER_ONLY @@ -246,6 +247,11 @@ int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch) hwaddr len = sizeof(*sa); int i; + /* For PVMs storing will occur when this cpu enters SIE again */ + if (s390_is_pv()) { + return 0; + } + sa = cpu_physical_memory_map(addr, &len, true); if (!sa) { return -EFAULT; From 42fc5eae91bb9ec08b816d33d43cc08f96d1b683 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 19 Mar 2020 09:19:20 -0400 Subject: [PATCH 0048/2595] docs: system: Add protvirt docs Let's add some documentation for the Protected VM functionality. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Acked-by: David Hildenbrand Acked-by: Christian Borntraeger Message-Id: <20200319131921.2367-16-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- docs/system/s390x/protvirt.rst | 60 ++++++++++++++++++++++++++++++++++ docs/system/target-s390x.rst | 5 +++ 2 files changed, 65 insertions(+) create mode 100644 docs/system/s390x/protvirt.rst diff --git a/docs/system/s390x/protvirt.rst b/docs/system/s390x/protvirt.rst new file mode 100644 index 0000000000..712974ad87 --- /dev/null +++ b/docs/system/s390x/protvirt.rst @@ -0,0 +1,60 @@ +Protected Virtualization on s390x +================================= + +The memory and most of the registers of Protected Virtual Machines +(PVMs) are encrypted or inaccessible to the hypervisor, effectively +prohibiting VM introspection when the VM is running. At rest, PVMs are +encrypted and can only be decrypted by the firmware, represented by an +entity called Ultravisor, of specific IBM Z machines. + + +Prerequisites +------------- + +To run PVMs, a machine with the Protected Virtualization feature, as +indicated by the Ultravisor Call facility (stfle bit 158), is +required. The Ultravisor needs to be initialized at boot by setting +`prot_virt=1` on the host's kernel command line. + +Running PVMs requires using the KVM hypervisor. + +If those requirements are met, the capability `KVM_CAP_S390_PROTECTED` +will indicate that KVM can support PVMs on that LPAR. + + +QEMU Settings +------------- + +To indicate to the VM that it can transition into protected mode, the +`Unpack facility` (stfle bit 161 represented by the feature +`unpack`/`S390_FEAT_UNPACK`) needs to be part of the cpu model of +the VM. + +All I/O devices need to use the IOMMU. +Passthrough (vfio) devices are currently not supported. + +Host huge page backings are not supported. However guests can use huge +pages as indicated by its facilities. + + +Boot Process +------------ + +A secure guest image can either be loaded from disk or supplied on the +QEMU command line. Booting from disk is done by the unmodified +s390-ccw BIOS. I.e., the bootmap is interpreted, multiple components +are read into memory and control is transferred to one of the +components (zipl stage3). Stage3 does some fixups and then transfers +control to some program residing in guest memory, which is normally +the OS kernel. The secure image has another component prepended +(stage3a) that uses the new diag308 subcodes 8 and 10 to trigger the +transition into secure mode. + +Booting from the image supplied on the QEMU command line requires that +the file passed via -kernel has the same memory layout as would result +from the disk boot. This memory layout includes the encrypted +components (kernel, initrd, cmdline), the stage3a loader and +metadata. In case this boot method is used, the command line +options -initrd and -cmdline are ineffective. The preparation of a PVM +image is done via the `genprotimg` tool from the s390-tools +collection. diff --git a/docs/system/target-s390x.rst b/docs/system/target-s390x.rst index 4c8b7cdd66..7d76ae97b4 100644 --- a/docs/system/target-s390x.rst +++ b/docs/system/target-s390x.rst @@ -24,3 +24,8 @@ or vfio-ap is also available. .. toctree:: s390x/vfio-ap +Architectural features +====================== + +.. toctree:: + s390x/protvirt From 572c0826615737f1c095b1b6d9e381ec40f72eb5 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 19 Mar 2020 09:19:21 -0400 Subject: [PATCH 0049/2595] s390x: Add unpack facility feature to GA1 The unpack facility is an indication that diagnose 308 subcodes 8-10 are available to the guest. That means, that the guest can put itself into protected mode. Once it is in protected mode, the hardware stops any attempt of VM introspection by the hypervisor. Some features are currently not supported in protected mode: * vfio devices * Migration * Huge page backings Signed-off-by: Christian Borntraeger Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Claudio Imbrenda Reviewed-by: Cornelia Huck Message-Id: <20200319131921.2367-17-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- target/s390x/gen-features.c | 1 + target/s390x/kvm.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index 6278845b12..8ddeebc544 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -562,6 +562,7 @@ static uint16_t full_GEN15_GA1[] = { S390_FEAT_GROUP_MSA_EXT_9, S390_FEAT_GROUP_MSA_EXT_9_PCKMO, S390_FEAT_ETOKEN, + S390_FEAT_UNPACK, }; /* Default features (in order of release) diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 870dd1b52b..69881a0da0 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -2425,6 +2425,14 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp) clear_bit(S390_FEAT_BPB, model->features); } + /* + * If we have support for protected virtualization, indicate + * the protected virtualization IPL unpack facility. + */ + if (cap_protected) { + set_bit(S390_FEAT_UNPACK, model->features); + } + /* We emulate a zPCI bus and AEN, therefore we don't need HW support */ set_bit(S390_FEAT_ZPCI, model->features); set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features); From 7152c9ecc6530ea145c122b0a58cc28802f630c6 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Thu, 26 Mar 2020 10:05:05 -0400 Subject: [PATCH 0050/2595] s390x: protvirt: Fix stray error_report_err in s390_machine_protect In case the protection of the machine fails at s390_pv_vm_enable(), we'll currently report the local_error variable. Problem is that there's no migration blocker error that we can report at this point so the pointer is always NULL which leads to a SEGFAULT. Let's remove the error report. Signed-off-by: Janosch Frank Reported-by: Marc Hartmayer Fixes: 0141e1b47707 ("s390x: protvirt: Add migration blocker") Message-Id: <20200326140505.2432-1-frankja@linux.ibm.com> Reviewed-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index db45249320..b268907395 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -359,7 +359,6 @@ static int s390_machine_protect(S390CcwMachineState *ms) rc = s390_pv_vm_enable(); if (rc) { qemu_balloon_inhibit(false); - error_report_err(local_err); migrate_del_blocker(pv_mig_blocker); error_free_or_abort(&pv_mig_blocker); return rc; From e8d12a55f6d3e577455b02f15907c460578c689b Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 27 Mar 2020 08:46:16 -0400 Subject: [PATCH 0051/2595] s390x/pv: Retry ioctls on -EINTR PV_ENABLE (and maybe others) might return -EINTR when a signal is pending. See the Linux kernel patch "s390/gmap: return proper error code on ksm unsharing" for details. Let us retry the ioctl in that case. Fixes: c3347ed0d2ee ("s390x: protvirt: Support unpack facility") Reported-by: Marc Hartmayer Acked-by: Janosch Frank Tested-by: Marc Hartmayer Signed-off-by: Christian Borntraeger Message-Id: <20200327124616.34866-1-borntraeger@de.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/pv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c index a40a844806..cb0dce4a4f 100644 --- a/hw/s390x/pv.c +++ b/hw/s390x/pv.c @@ -23,7 +23,11 @@ static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data) .cmd = cmd, .data = (uint64_t)data, }; - int rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd); + int rc; + + do { + rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd); + } while (rc == -EINTR); if (rc) { error_report("KVM PV command %d (%s) failed: header rc %x rrc %x " From fbc1384ccd48fa7c0c38f950adf7992a4fb6042e Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 6 Apr 2020 06:01:58 -0400 Subject: [PATCH 0052/2595] s390x/s390-virtio-ccw: Fix build on systems without KVM linux/kvm.h is not available on all platforms. Let us move s390_machine_inject_pv_error into pv.c as it uses KVM structures. Also rename the function to s390_pv_inject_reset_error. While at it, ipl.h needs an include for "exec/address-spaces.h" as it uses address_space_memory. Fixes: c3347ed0d2ee ("s390x: protvirt: Support unpack facility") Reported-by: Bruce Rogers Signed-off-by: Christian Borntraeger Message-Id: <20200406100158.5940-2-borntraeger@de.ibm.com> Reviewed-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/ipl.h | 1 + hw/s390x/pv.c | 11 +++++++++++ hw/s390x/s390-virtio-ccw.c | 12 +----------- include/hw/s390x/pv.h | 3 +++ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index 89b3044d7a..53cc9eb5ac 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -14,6 +14,7 @@ #define HW_S390_IPL_H #include "cpu.h" +#include "exec/address-spaces.h" #include "hw/qdev-core.h" struct IPLBlockPVComp { diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c index cb0dce4a4f..f11868e865 100644 --- a/hw/s390x/pv.c +++ b/hw/s390x/pv.c @@ -13,8 +13,10 @@ #include +#include "cpu.h" #include "qemu/error-report.h" #include "sysemu/kvm.h" +#include "hw/s390x/ipl.h" #include "hw/s390x/pv.h" static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data) @@ -100,3 +102,12 @@ void s390_pv_unshare(void) { s390_pv_cmd_exit(KVM_PV_UNSHARE_ALL, NULL); } + +void s390_pv_inject_reset_error(CPUState *cs) +{ + int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4; + CPUS390XState *env = &S390_CPU(cs)->env; + + /* Report that we are unable to enter protected mode */ + env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; +} diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index b268907395..45292fb5a8 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -45,7 +45,6 @@ #include "sysemu/sysemu.h" #include "sysemu/balloon.h" #include "hw/s390x/pv.h" -#include #include "migration/blocker.h" static Error *pv_mig_blocker; @@ -390,15 +389,6 @@ out_err: return rc; } -static void s390_machine_inject_pv_error(CPUState *cs) -{ - int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4; - CPUS390XState *env = &S390_CPU(cs)->env; - - /* Report that we are unable to enter protected mode */ - env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; -} - static void s390_pv_prepare_reset(S390CcwMachineState *ms) { CPUState *cs; @@ -484,7 +474,7 @@ static void s390_machine_reset(MachineState *machine) run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL); if (s390_machine_protect(ms)) { - s390_machine_inject_pv_error(cs); + s390_pv_inject_reset_error(cs); /* * Continue after the diag308 so the guest knows something * went wrong. diff --git a/include/hw/s390x/pv.h b/include/hw/s390x/pv.h index c6cb360f2f..522ca6a04e 100644 --- a/include/hw/s390x/pv.h +++ b/include/hw/s390x/pv.h @@ -13,6 +13,7 @@ #define HW_S390_PV_H #ifdef CONFIG_KVM +#include "cpu.h" #include "hw/s390x/s390-virtio-ccw.h" static inline bool s390_is_pv(void) @@ -41,6 +42,7 @@ int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak); void s390_pv_perf_clear_reset(void); int s390_pv_verify(void); void s390_pv_unshare(void); +void s390_pv_inject_reset_error(CPUState *cs); #else /* CONFIG_KVM */ static inline bool s390_is_pv(void) { return false; } static inline int s390_pv_vm_enable(void) { return 0; } @@ -50,6 +52,7 @@ static inline int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) { static inline void s390_pv_perf_clear_reset(void) {} static inline int s390_pv_verify(void) { return 0; } static inline void s390_pv_unshare(void) {} +static inline void s390_pv_inject_reset_error(CPUState *cs) {}; #endif /* CONFIG_KVM */ #endif /* HW_S390_PV_H */ From a7922a3c81f34f45b1ebc9670a7769edc4c42a43 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 29 Apr 2020 15:07:10 +0100 Subject: [PATCH 0053/2595] Open 5.1 development tree Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 0062ac9718..a480698ce5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.0 +5.0.50 From 523e34646788d877d16b422f43f23911eb0ea7cd Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 2 Mar 2020 14:57:22 -0800 Subject: [PATCH 0054/2595] riscv/sifive_u: Fix up file ordering Split the file into clear machine and SoC sections. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- hw/riscv/sifive_u.c | 108 ++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 998666c91f..7f6a3c6c15 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -312,7 +312,7 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(nodename); } -static void riscv_sifive_u_init(MachineState *machine) +static void sifive_u_machine_init(MachineState *machine) { const struct MemmapEntry *memmap = sifive_u_memmap; SiFiveUState *s = RISCV_U_MACHINE(machine); @@ -403,6 +403,59 @@ static void riscv_sifive_u_init(MachineState *machine) &address_space_memory); } +static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp) +{ + SiFiveUState *s = RISCV_U_MACHINE(obj); + + return s->start_in_flash; +} + +static void sifive_u_machine_set_start_in_flash(Object *obj, bool value, Error **errp) +{ + SiFiveUState *s = RISCV_U_MACHINE(obj); + + s->start_in_flash = value; +} + +static void sifive_u_machine_instance_init(Object *obj) +{ + SiFiveUState *s = RISCV_U_MACHINE(obj); + + s->start_in_flash = false; + object_property_add_bool(obj, "start-in-flash", sifive_u_machine_get_start_in_flash, + sifive_u_machine_set_start_in_flash, NULL); + object_property_set_description(obj, "start-in-flash", + "Set on to tell QEMU's ROM to jump to " + "flash. Otherwise QEMU will jump to DRAM", + NULL); +} + +static void sifive_u_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "RISC-V Board compatible with SiFive U SDK"; + mc->init = sifive_u_machine_init; + mc->max_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + SIFIVE_U_COMPUTE_CPU_COUNT; + mc->min_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + 1; + mc->default_cpus = mc->min_cpus; +} + +static const TypeInfo sifive_u_machine_typeinfo = { + .name = MACHINE_TYPE_NAME("sifive_u"), + .parent = TYPE_MACHINE, + .class_init = sifive_u_machine_class_init, + .instance_init = sifive_u_machine_instance_init, + .instance_size = sizeof(SiFiveUState), +}; + +static void sifive_u_machine_init_register_types(void) +{ + type_register_static(&sifive_u_machine_typeinfo); +} + +type_init(sifive_u_machine_init_register_types) + static void riscv_sifive_u_soc_init(Object *obj) { MachineState *ms = MACHINE(qdev_get_machine()); @@ -443,33 +496,6 @@ static void riscv_sifive_u_soc_init(Object *obj) TYPE_CADENCE_GEM); } -static bool sifive_u_get_start_in_flash(Object *obj, Error **errp) -{ - SiFiveUState *s = RISCV_U_MACHINE(obj); - - return s->start_in_flash; -} - -static void sifive_u_set_start_in_flash(Object *obj, bool value, Error **errp) -{ - SiFiveUState *s = RISCV_U_MACHINE(obj); - - s->start_in_flash = value; -} - -static void riscv_sifive_u_machine_instance_init(Object *obj) -{ - SiFiveUState *s = RISCV_U_MACHINE(obj); - - s->start_in_flash = false; - object_property_add_bool(obj, "start-in-flash", sifive_u_get_start_in_flash, - sifive_u_set_start_in_flash, NULL); - object_property_set_description(obj, "start-in-flash", - "Set on to tell QEMU's ROM to jump to " - "flash. Otherwise QEMU will jump to DRAM", - NULL); -} - static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); @@ -607,29 +633,3 @@ static void riscv_sifive_u_soc_register_types(void) } type_init(riscv_sifive_u_soc_register_types) - -static void riscv_sifive_u_machine_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "RISC-V Board compatible with SiFive U SDK"; - mc->init = riscv_sifive_u_init; - mc->max_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + SIFIVE_U_COMPUTE_CPU_COUNT; - mc->min_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + 1; - mc->default_cpus = mc->min_cpus; -} - -static const TypeInfo riscv_sifive_u_machine_typeinfo = { - .name = MACHINE_TYPE_NAME("sifive_u"), - .parent = TYPE_MACHINE, - .class_init = riscv_sifive_u_machine_class_init, - .instance_init = riscv_sifive_u_machine_instance_init, - .instance_size = sizeof(SiFiveUState), -}; - -static void riscv_sifive_u_machine_init_register_types(void) -{ - type_register_static(&riscv_sifive_u_machine_typeinfo); -} - -type_init(riscv_sifive_u_machine_init_register_types) From fda5b000faf401cf595c4e87809eac3378ddbfd4 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 2 Mar 2020 15:08:51 -0800 Subject: [PATCH 0055/2595] riscv/sifive_u: Add a serial property to the sifive_u SoC At present the board serial number is hard-coded to 1, and passed to OTP model during initialization. Firmware (FSBL, U-Boot) uses the serial number to generate a unique MAC address for the on-chip ethernet controller. When multiple QEMU 'sifive_u' instances are created and connected to the same subnet, they all have the same MAC address hence it creates a unusable network. A new "serial" property is introduced to the sifive_u SoC to specify the board serial number. When not given, the default serial number 1 is used. Suggested-by: Bin Meng Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Tested-by: Bin Meng --- hw/riscv/sifive_u.c | 8 +++++++- include/hw/riscv/sifive_u.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 7f6a3c6c15..6e659e986f 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -491,7 +491,6 @@ static void riscv_sifive_u_soc_init(Object *obj) TYPE_SIFIVE_U_PRCI); sysbus_init_child_obj(obj, "otp", &s->otp, sizeof(s->otp), TYPE_SIFIVE_U_OTP); - qdev_prop_set_uint32(DEVICE(&s->otp), "serial", OTP_SERIAL); sysbus_init_child_obj(obj, "gem", &s->gem, sizeof(s->gem), TYPE_CADENCE_GEM); } @@ -584,6 +583,7 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) object_property_set_bool(OBJECT(&s->prci), true, "realized", &err); sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base); + qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial); object_property_set_bool(OBJECT(&s->otp), true, "realized", &err); sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base); @@ -610,10 +610,16 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size); } +static Property riscv_sifive_u_soc_props[] = { + DEFINE_PROP_UINT32("serial", SiFiveUSoCState, serial, OTP_SERIAL), + DEFINE_PROP_END_OF_LIST() +}; + static void riscv_sifive_u_soc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + device_class_set_props(dc, riscv_sifive_u_soc_props); dc->realize = riscv_sifive_u_soc_realize; /* Reason: Uses serial_hds in realize function, thus can't be used twice */ dc->user_creatable = false; diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index 82667b5746..a2baa1de5f 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -42,6 +42,8 @@ typedef struct SiFiveUSoCState { SiFiveUPRCIState prci; SiFiveUOTPState otp; CadenceGEMState gem; + + uint32_t serial; } SiFiveUSoCState; #define TYPE_RISCV_U_MACHINE MACHINE_TYPE_NAME("sifive_u") From 3ca109c3f8d6225efdfa801252d25f3e526b004a Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sat, 16 Nov 2019 07:08:50 -0800 Subject: [PATCH 0056/2595] riscv/sifive_u: Add a serial property to the sifive_u machine At present the board serial number is hard-coded to 1, and passed to OTP model during initialization. Firmware (FSBL, U-Boot) uses the serial number to generate a unique MAC address for the on-chip ethernet controller. When multiple QEMU 'sifive_u' instances are created and connected to the same subnet, they all have the same MAC address hence it creates a unusable network. A new "serial" property is introduced to specify the board serial number. When not given, the default serial number 1 is used. Signed-off-by: Bin Meng Reviewed-by: Palmer Dabbelt Reviewed-by: Alistair Francis Message-Id: <1573916930-19068-1-git-send-email-bmeng.cn@gmail.com> [ Changed by AF: - Use the SoC's serial property to pass the info to the SoC - Fixup commit title - Rebase on file restructuring ] Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 20 ++++++++++++++++++++ include/hw/riscv/sifive_u.h | 1 + 2 files changed, 21 insertions(+) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 6e659e986f..8d0ee8b9c4 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -34,6 +34,7 @@ #include "qemu/log.h" #include "qemu/error-report.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "hw/boards.h" #include "hw/loader.h" #include "hw/sysbus.h" @@ -326,6 +327,8 @@ static void sifive_u_machine_init(MachineState *machine) object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), TYPE_RISCV_U_SOC, &error_abort, NULL); + object_property_set_uint(OBJECT(&s->soc), s->serial, "serial", + &error_abort); object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort); @@ -417,6 +420,18 @@ static void sifive_u_machine_set_start_in_flash(Object *obj, bool value, Error * s->start_in_flash = value; } +static void sifive_u_machine_get_serial(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + visit_type_uint32(v, name, (uint32_t *)opaque, errp); +} + +static void sifive_u_machine_set_serial(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + visit_type_uint32(v, name, (uint32_t *)opaque, errp); +} + static void sifive_u_machine_instance_init(Object *obj) { SiFiveUState *s = RISCV_U_MACHINE(obj); @@ -428,6 +443,11 @@ static void sifive_u_machine_instance_init(Object *obj) "Set on to tell QEMU's ROM to jump to " "flash. Otherwise QEMU will jump to DRAM", NULL); + + s->serial = OTP_SERIAL; + object_property_add(obj, "serial", "uint32", sifive_u_machine_get_serial, + sifive_u_machine_set_serial, NULL, &s->serial, NULL); + object_property_set_description(obj, "serial", "Board serial number", NULL); } static void sifive_u_machine_class_init(ObjectClass *oc, void *data) diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index a2baa1de5f..16c297ec5f 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -61,6 +61,7 @@ typedef struct SiFiveUState { int fdt_size; bool start_in_flash; + uint32_t serial; } SiFiveUState; enum { From 384728905441279e54fa3d714b11bf1b1bcbfd27 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 26 Mar 2020 15:44:07 -0700 Subject: [PATCH 0057/2595] riscv: Don't use stage-2 PTE lookup protection flags When doing the fist of a two stage lookup (Hypervisor extensions) don't set the current protection flags from the second stage lookup of the base address PTE. Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Tested-by: Anup Patel Message-id: 931db85d6890ed4bc2b527fd1011197cd28299aa.1585262586.git.alistair.francis@wdc.com Message-Id: <931db85d6890ed4bc2b527fd1011197cd28299aa.1585262586.git.alistair.francis@wdc.com> --- target/riscv/cpu_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index d3ba9efb02..f36d184b7b 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -452,10 +452,11 @@ restart: hwaddr pte_addr; if (two_stage && first_stage) { + int vbase_prot; hwaddr vbase; /* Do the second stage translation on the base PTE address. */ - get_physical_address(env, &vbase, prot, base, access_type, + get_physical_address(env, &vbase, &vbase_prot, base, access_type, mmu_idx, false, true); pte_addr = vbase + idx * ptesize; From 8f67cd6db7375f9133d900b13b300931fbc2e1d8 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 26 Mar 2020 15:44:09 -0700 Subject: [PATCH 0058/2595] riscv: AND stage-1 and stage-2 protection flags Take the result of stage-1 and stage-2 page table walks and AND the two protection flags together. This way we require both to set permissions instead of just stage-2. Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Tested-by: Anup Patel Message-id: 846f1e18f5922d818bc464ec32c144ef314ec724.1585262586.git.alistair.francis@wdc.com Message-Id: <846f1e18f5922d818bc464ec32c144ef314ec724.1585262586.git.alistair.francis@wdc.com> --- target/riscv/cpu_helper.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index f36d184b7b..50e13a064f 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -707,7 +707,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, #ifndef CONFIG_USER_ONLY vaddr im_address; hwaddr pa = 0; - int prot; + int prot, prot2; bool pmp_violation = false; bool m_mode_two_stage = false; bool hs_mode_two_stage = false; @@ -757,13 +757,15 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, /* Second stage lookup */ im_address = pa; - ret = get_physical_address(env, &pa, &prot, im_address, + ret = get_physical_address(env, &pa, &prot2, im_address, access_type, mmu_idx, false, true); qemu_log_mask(CPU_LOG_MMU, "%s 2nd-stage address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx " prot %d\n", - __func__, im_address, ret, pa, prot); + __func__, im_address, ret, pa, prot2); + + prot &= prot2; if (riscv_feature(env, RISCV_FEATURE_PMP) && (ret == TRANSLATE_SUCCESS) && From ee79e7cd47ef47074d7c20c221321c5d31d3683d Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 30 Mar 2020 13:57:24 +0530 Subject: [PATCH 0059/2595] riscv: Fix Stage2 SV32 page table walk As-per RISC-V H-Extension v0.5 draft, the Stage2 SV32 page table has 12bits of VPN[1] and 10bits of VPN[0]. The additional 2bits in VPN[1] is required to handle the 34bit intermediate physical address coming from Stage1 SV32 page table. The 12bits of VPN[1] implies that Stage2 SV32 level-0 page table will be 16KB in size with total 4096 enteries where each entry maps 4MB of memory (same as Stage1 SV32 page table). The get_physical_address() function is broken for Stage2 SV32 level-0 page table because it incorrectly computes output physical address for Stage2 SV32 level-0 page table entry. The root cause of the issue is that get_physical_address() uses the "widened" variable to compute level-0 physical address mapping which changes level-0 mapping size (instead of 4MB). We should use the "widened" variable only for computing index of Stage2 SV32 level-0 page table. Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Message-id: 20200330082724.120444-1-anup.patel@wdc.com Message-Id: <20200330082724.120444-1-anup.patel@wdc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 50e13a064f..bc80aa87cf 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -559,12 +559,7 @@ restart: /* for superpage mappings, make a fake leaf PTE for the TLB's benefit. */ target_ulong vpn = addr >> PGSHIFT; - if (i == 0) { - *physical = (ppn | (vpn & ((1L << (ptshift + widened)) - 1))) << - PGSHIFT; - } else { - *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT; - } + *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT; /* set permissions on the TLB entry */ if ((pte & PTE_R) || ((pte & PTE_X) && mxr)) { From e883e9927ae667a2473c4a4ec666df53af1b34d9 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sat, 7 Mar 2020 04:48:39 -0800 Subject: [PATCH 0060/2595] hw/riscv: Generate correct "mmu-type" for 32-bit machines 32-bit machine should have its CPU's "mmu-type" set to "riscv,sv32". Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1583585319-26603-1-git-send-email-bmeng.cn@gmail.com Message-Id: <1583585319-26603-1-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 4 ++++ hw/riscv/spike.c | 4 ++++ hw/riscv/virt.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 8d0ee8b9c4..e32355a691 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -160,7 +160,11 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_add_subnode(fdt, nodename); /* cpu 0 is the management hart that does not have mmu */ if (cpu != 0) { +#if defined(TARGET_RISCV32) + qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv32"); +#else qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48"); +#endif isa = riscv_isa_string(&s->soc.u_cpus.harts[cpu - 1]); } else { isa = riscv_isa_string(&s->soc.e_cpus.harts[0]); diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 5053fe4590..98697a244e 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -102,7 +102,11 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap, char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu); char *isa = riscv_isa_string(&s->soc.harts[cpu]); qemu_fdt_add_subnode(fdt, nodename); +#if defined(TARGET_RISCV32) + qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv32"); +#else qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48"); +#endif qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa); qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv"); qemu_fdt_setprop_string(fdt, nodename, "status", "okay"); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 85ec9e22aa..c621a970aa 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -229,7 +229,11 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu); char *isa = riscv_isa_string(&s->soc.harts[cpu]); qemu_fdt_add_subnode(fdt, nodename); +#if defined(TARGET_RISCV32) + qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv32"); +#else qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48"); +#endif qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa); qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv"); qemu_fdt_setprop_string(fdt, nodename, "status", "okay"); From 74dbba9b734b3509dc3682715187339a91fcd3fb Mon Sep 17 00:00:00 2001 From: Corey Wharton Date: Fri, 13 Mar 2020 12:34:28 -0700 Subject: [PATCH 0061/2595] riscv: sifive_e: Support changing CPU type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows the CPU to be changed from the default via the -cpu command line option. Signed-off-by: Corey Wharton Reviewed-by: Bin Meng Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200313193429.8035-2-coreyw7@fb.com Message-Id: <20200313193429.8035-2-coreyw7@fb.com> [ Changes by AF: - Set "cpu-type" from the machine and not SoC ] Signed-off-by: Alistair Francis --- hw/riscv/sifive_e.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 646553a7c3..b53109521e 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -123,8 +123,6 @@ static void riscv_sifive_e_soc_init(Object *obj) object_initialize_child(obj, "cpus", &s->cpus, sizeof(s->cpus), TYPE_RISCV_HART_ARRAY, &error_abort, NULL); - object_property_set_str(OBJECT(&s->cpus), SIFIVE_E_CPU, "cpu-type", - &error_abort); object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts", &error_abort); sysbus_init_child_obj(obj, "riscv.sifive.e.gpio0", @@ -141,6 +139,8 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) SiFiveESoCState *s = RISCV_E_SOC(dev); MemoryRegion *sys_mem = get_system_memory(); + object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type", + &error_abort); object_property_set_bool(OBJECT(&s->cpus), true, "realized", &error_abort); @@ -219,6 +219,7 @@ static void riscv_sifive_e_machine_init(MachineClass *mc) mc->desc = "RISC-V Board compatible with SiFive E SDK"; mc->init = riscv_sifive_e_init; mc->max_cpus = 1; + mc->default_cpu_type = SIFIVE_E_CPU; } DEFINE_MACHINE("sifive_e", riscv_sifive_e_machine_init) From d784733bf1875c1ba355c69739518f24d56f1260 Mon Sep 17 00:00:00 2001 From: Corey Wharton Date: Fri, 13 Mar 2020 12:34:29 -0700 Subject: [PATCH 0062/2595] target/riscv: Add a sifive-e34 cpu type The sifive-e34 cpu type is the same as the sifive-e31 with the single precision floating-point extension enabled. Signed-off-by: Corey Wharton Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Message-id: 20200313193429.8035-3-coreyw7@fb.com Message-Id: <20200313193429.8035-3-coreyw7@fb.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 10 ++++++++++ target/riscv/cpu.h | 1 + 2 files changed, 11 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 4e578239d3..059d71f2c7 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -164,6 +164,15 @@ static void rv32imacu_nommu_cpu_init(Object *obj) set_feature(env, RISCV_FEATURE_PMP); } +static void rv32imafcu_nommu_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVC | RVU); + set_priv_version(env, PRIV_VERSION_1_10_0); + set_resetvec(env, DEFAULT_RSTVEC); + set_feature(env, RISCV_FEATURE_PMP); +} + #elif defined(TARGET_RISCV64) static void riscv_base64_cpu_init(Object *obj) @@ -610,6 +619,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { #if defined(TARGET_RISCV32) DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base32_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32imafcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init), /* Depreacted */ DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 7d21addbab..d0e7f5b9c5 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -36,6 +36,7 @@ #define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32") #define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64") #define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") +#define TYPE_RISCV_CPU_SIFIVE_E34 RISCV_CPU_TYPE_NAME("sifive-e34") #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") #define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34") #define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54") From 64ce00a6c7c00c0b120270e1644009e5d521e277 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Sun, 12 Apr 2020 10:08:30 +0800 Subject: [PATCH 0063/2595] linux-user/riscv: fix up struct target_ucontext definition As struct target_ucontext will be transfered to signal handler, it must keep pace with struct ucontext_t defined in Linux kernel. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-id: 20200412020830.607-1-zhiwei_liu@c-sky.com Message-Id: <20200412020830.607-1-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- linux-user/riscv/signal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c index 83ecc6f799..67a95dbc7b 100644 --- a/linux-user/riscv/signal.c +++ b/linux-user/riscv/signal.c @@ -40,8 +40,9 @@ struct target_ucontext { unsigned long uc_flags; struct target_ucontext *uc_link; target_stack_t uc_stack; - struct target_sigcontext uc_mcontext; target_sigset_t uc_sigmask; + uint8_t __unused[1024 / 8 - sizeof(target_sigset_t)]; + struct target_sigcontext uc_mcontext QEMU_ALIGNED(16); }; struct target_rt_sigframe { From 0b2f78e524d70d40200fa1f9334b2a6db7ca10e4 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 20 Apr 2020 21:18:44 +0800 Subject: [PATCH 0064/2595] roms: opensbi: Upgrade from v0.6 to v0.7 Upgrade OpenSBI from v0.6 to v0.7 and the pre-built bios images. The v0.7 release includes the following commits: f64f4b9 lib: Add a new platform feature to bringup secondary harts b677a9b lib: Implement hart hotplug 5b48240 lib: Add possible hart status values e3f69fc lib: Implement Hart State Management (HSM) SBI extension 6704216 lib: Check MSIP bit after returning from WFI 82ae8e8 makefile: Do setup of the install target more flexible e1a5b73 platform: sifive: fu540: allow sv32 as an mmu-type 8c83fb2 lib: Fix return type of sbi_hsm_hart_started() 00d332b include: Move bits related defines and macros to sbi_bitops.h a148996 include: sbi_bitops: More useful bit operations 4a603eb platform: kendryte/k210: Set per-HART stack size to 8KB 678c3c3 include: sbi_scratch: Set per-HART scratch size to 4KB 2abc55b lib: Sort build objects in alphabetical order 6e87507 platform: ae350: Sort build objects in alphabetical order 650c0e5 lib: sbi: Fix coding style issues 078686d lib: serial: Fix coding style issues 3226bd9 lib: Simple bitmap library c741abc include: Simple hartmask library d6d7e18 lib: sbi_init: Don't allow HARTID greater than SBI_HARTMASK_MAX_BITS a4a6a81 lib: Introduce SBI_TLB_INFO_INIT() helper macro d963164 lib: sbi_tlb: Use sbi_hartmask in sbi_tlb_info 71d2b83 lib: Move all coldboot wait APIs to sbi_init.c 2b945fc lib: sbi_init: Use hartmask for coldboot wait 44ce5b9 include: Remove disabled_hart_mask from sbi_platform 2db381f lib: Introduce sbi_hsm_hart_started_mask() API 61f7768 lib: sbi_ecall_legacy: Use sbi_hsm_hart_started_mask() API 466fecb lib: sbi_system: Use sbi_hsm_hart_started_mask() API 9aad831 lib: sbi_ipi: Use sbi_hsm_hart_started_mask() API eede1aa lib: sbi_hart: Remove HART available mask and related APIs 757bb44 docs: Remove out-of-date documentation 86d37bb lib: sbi: Fix misaligned trap handling ffdc858 platform: ariane-fpga: Change license for ariane-fpga from GPL-2.0 to BSD-2 4b2f594 sbi: Add definitions for true/false 0cfe49a libfdt: Add INT32_MAX and UINT32_MAX in libfdt_env.h baac7e0 libfdt: Upgrade to v1.5.1 release f92147c include: Make sbi_hart_id_to_scratch() as macro eeae3d9 firmware: fw_base: Optimize _hartid_to_scratch() implementation 16e7071 lib: sbi_hsm: Optimize sbi_hsm_hart_get_state() implementation 823345e include: Make sbi_current_hartid() as macro in riscv_asm.h 9aabba2 Makefile: Fix distclean make target 9275ed3 platform: ariane-fpga: Set per-HART stack size to 8KB 2343efd platform: Set per-HART stack size to 8KB in the template platform codes 72a0628 platform: Use one unified per-HART stack size macro for all platforms 327ba36 scripts: Cover sifive/fu540 in the 32-bit build 5fbcd62 lib: sbi: Update pmp_get() to return decoded size directly dce8846 libfdt: Compile fdt_addresses.c fcb1ded lib: utils: Add a fdt_reserved_memory_fixup() helper 666be6d platform: Clean up include header files 6af5576 lib: utils: Move PLIC DT fix up codes to fdt_helper.c e846ce1 platform: andes/ae350: Fix up DT for reserved memory 8135520 platform: ariane-fpga: Fix up DT for reserved memory c9a5268 platform: qemu/virt: Fix up DT for reserved memory 6f9bb83 platform: sifive/fu540: Fix up DT for reserved memory 1071f05 platform: sifive/fu540: Remove "stdout-path" fix-up dd9439f lib: utils: Add a fdt_cpu_fixup() helper 3f1c847 platform: sifive/fu540: Replace cpu0 node fix-up with the new helper db6a2b5 lib: utils: Add a general device tree fix-up helper 3f8d754 platform: Update to call general DT fix-up helper 87a7ef7 lib: sbi_scratch: Introduce HART id to scratch table e23d3ba include: Simplify HART id to scratch macro 19bd531 lib: sbi_hsm: Simplify hart_get_state() and hart_started() APIs 3ebfe0e lib: sbi_tlb: Simplify sbi_tlb_entry_process() function 209134d lib: Handle failure of sbi_hartid_to_scratch() API bd6ef02 include: sbi_platform: Improve sbi_platform_hart_disabled() API c9f60fc lib: sbi_scratch: Don't set hartid_to_scratch table for disabled HART 680b098 lib: sbi_hsm: Don't use sbi_platform_hart_count() API db187d6 lib: sbi_hsm: Remove scratch parameter from hart_started_mask() API 814f38d lib: sbi_hsm: Don't use sbi_platform_hart_disabled() API 75eec9d lib: Don't use sbi_platform_hart_count() API c51f02c include: sbi_platform: Introduce HART index to HART id table 315a877 platform: sifive/fu540: Remove FU540_ENABLED_HART_MASK option a0c88dd lib: Fix sbi_ecall_register_extension to prevent extension IDs overlap 9a74a64 lib: Check MSIP bit after returning from WFI 5968894 platform: Move ariane standalone fpga project to its own project ed265b4 platform: fpga/ariane: Remove redundant plic address macros fb84879 platform: Add OpenPiton platform support d1d6560 platform: fpga/common: Add a fdt parsing helper functions 040e4e2 lib: utils: Move fdt fixup helper routines to a different file 4c37451 platform: openpiton: Read the device configurations from device tree 4d93586 lib: prevent coldboot_lottery from overflowing 550ba88 scripts: Extend create-binary-archive.sh for unified binary tar ball 160c885 lib: utils: Improve fdt_cpu_fixup() implementation 1de66d1 lib: Optimize unpriv load/store implementation 626467c lib: Remove scratch parameter from unpriv load/store functions cb78a48 lib: sbi_trap: Remove scratch parameter from sbi_trap_redirect() d11c79c lib: sbi_emulate_csr: Remove scratch and hartid parameter 5a7bd0c lib: sbi_illegal_insn: Remove mcause, scratch and hartid parameters fe37d7d lib: sbi_misaligned_ldst: Remove mcause, scratch and hartid parameters 7487116 lib: sbi_ecall: Remove mcause, scratch and hartid parameters 40b221b lib: sbi_trap: Simplify sbi_trap_handler() API 7b211ff include: sbi_platform: Remove priv parameter from hart_start() callback 5b6957e include: Use more consistent name for atomic xchg() and cmpxchg() dd0f21c lib: sbi_scratch: Introduce sbi_scratch_last_hartid() API 54b2779 include: sbi_tlb: Remove scratch parameter from sbi_tlb_request() 9e52a45 include: sbi_ipi: Remove scratch parameter from most functions ec0d80f include: sbi_system: Remove scratch parameter and redundant functions 0a28ea5 include: sbi_timer: Remove scratch parameter from most funcitons 648507a include: sbi_console: Remove scratch parameter from sbi_dprintf() e5a7f55 platform: thead/c910: Use HSM extension to boot secondary cores f281de8 lib: irqchip/plic: Fix maximum priority threshold value 6c7922e lib: Support vector extension 615587c docs: Update README about supported SBI versions 66d0184 lib: Allow overriding SBI implementation ID 9f1b72c include: Bump-up version to 0.7 Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Signed-off-by: Alistair Francis --- pc-bios/opensbi-riscv32-sifive_u-fw_jump.bin | Bin 49472 -> 49520 bytes pc-bios/opensbi-riscv32-virt-fw_jump.bin | Bin 41280 -> 49504 bytes pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin | Bin 53760 -> 57936 bytes pc-bios/opensbi-riscv64-virt-fw_jump.bin | Bin 49664 -> 57920 bytes roms/opensbi | 2 +- 5 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/opensbi-riscv32-sifive_u-fw_jump.bin b/pc-bios/opensbi-riscv32-sifive_u-fw_jump.bin index bab13f597ac9da31518f0a2bb22c2a1dbd56380d..3e0da54080ef4dbf3fbde6205c983fb25c82e114 100644 GIT binary patch literal 49520 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 VUJpdEf>!}_fBa!qfHaBM{~whEiEaP@ literal 49472 zcmcG%3tUrIwm-g4PEJmO55TC=j<%Et2yHDIA6FeMuMojU)e#+R?X;YtV`utssN=Q0 zPQm0P21L||DXq>>AE3+NkYIv|(99f+Nu*{2Pr#qgYA{!I}{%wJSXC>uaR0?=x`^{8gO6zQ+>A``?}V zWtVJ?RR8>=zWR@L)6)G2rKMwKM%-W5bBUDp!6cT=iF^2AUBHMstO}wF;>lytfurg$ ztB8&dBARkgk9UnTKEiYCqXtfM9=~M?Upg##?Bw;jzA_>vGKo4_U*h2ZDAUQV#@Toh zLa!R0)-3(P-i#5nM1A2{na6Il7Zqs3&J%6;RT79pTcmc_mL6Oc_%w5bHuC46z8I+; z-t(yh+0|bgbKZ~tBicvt-HVasSK1N4AWS9;grUQ;?U5-3+VJzTKsr2Vb0=h7)10Jz zX+CPl)n-|ARvX5XP~JVgwKK2{CQ`@toEw51^ygS|%6Vn3n!g+zSo+eVcPXt9WDbQc z>obfR=G@ie#JDwq=+>}A{Y+m*_m>|?cwYy8+0L#Zj?N!QbzfZpX3HBMk`ZkC%*Z&d zxrxJlka4&_!^h3MWfSIS5q6gh{XGcY4rSe`S)JAdiC4C&v|+#T@ln;+FZH98 zSt0XcuSLy_bwAkJnH51stA>fi3{jIF|FZEbo17!r^!}{S@XE;Q)Edo)7zLFom>rhF zvC%3{r?SfI7ce5Gq6S_S?ShsDd1)+dFhjAT}3XOWp9EfoyO>L(km z4Vx{y7EWSq$M+E1)ltM&J&Fhx8F9#f1C!7iT`YZzZyi`;4426U*3(+o!b3(6tfKV> z9+Wxp3-$km`u&I?$_Va{9O#r)DysX|_B-^zCl4M8KNfjB=ER7`QJ;@JJ>iSVXR9k~ ztLtly)E+<7SbzGHvq#P!yLkMY6F)Rw{rtx1_Affm>Ntj611&ruvD4Pa?TJrF$Vj}J zD4Vl>PI%g$w1m0G=Vr{iI!`fW+dcSjyi2#?PqVX+dugF^^m;&bAegq#E>F(;8p%1O#eW(+w7 zW=hT!CM73@NzF-Rrshm#rsYgyrsqs&X5`FZp3HeNYbF`JGJ8eZO7Hlr%$C~IafHzC z<2bU4UN!iw<~W%$UMk1wrK`UjA#rq^N&1p4CrXajA2T-|Idc3HQ0UOv+U!APCQsbC zKN@Q{Fl?=fVO`r8qw51^i{jHY34B_?dHz&EjP;$P>>)eHI!|)!K?`SemU6~JE{?5j z=2%xbXRK}I!a18}6>&5#BGsHOa{!Z|;HKyX4QI~er>wDQER5Q2W)2t3DzMG{G2YS2 zGfN9j6};ap>NO1%cjsD9SjcZg1M8Bo5Q19z87U^UA28wktb%G_Q7_UqB1OmIR-!qL zT0v#`p17IQj8Q?P$nA*>c|1oSDSF7v2}|3UP0a!MdUq zM%Q>nVDF5zCuMA{OUAmIWky%4Ebv*;!Iky}SEP0?2hHm6ehUdpPid3x#l8{W;`=sX zQb#Hv&KyngDY0)zWDKdIsMv7Oc&IRDajM7vwfU6deI{@Fd0yWssEaxTfO@qH)9UT}wU7d)}M zWAXgFR5msO&(9lONis2S-BD>YXU0)0quIdZ=+zHcn8C>!P(sb=|Db!Jop@r;&6j?QfAGYH&G&?nKb48XoZ|jfQyp*r zo!C?%a$AtRP2FoZH$(J{X)6o>8xuG$|a%P^CV*B#;{GAc?^Jki z(8?jX0Y=F@!jKnpW{4XYo>8mA~&qdt;llgF~*Ub$S&)#Ya> zrmqRDmu>X6fR_BNY{9JInQFxuuf%RBfMf(dF5uG)d|H2kk0-8j9%Srdiq|XSQ^m}O zJIX6eaVE6ugDznK5|GmRN179M}$SXurE z>mKXATpB5dQA+EF=qf%w=)%*`HiDLFjyQp%%CI5lZ?~98}+L)wBxtg9a|M>ib zr}jJ*{`C5%WecuOf9^TVWXlS}I|r7gU8-OX4@q11v7d9k($RTMd1)#1Ac?;^48k|1 zB#4v7pjkb+P#eaPo*ZY#jtYB-UUVg{yWNIVKkJn{`BN%wP}0(~Ci)>Vq2Zs*s8t+^ ztWP~eLRdo~c6KLEgdkO4U!U9FOawj8HTU)H zJANFLC|qjp9a*FeQ(;Zn@Uwd1PAb14&3MS5C`hw$cSy67=${MyYexTCd-N~IMY)7& z%6c{_meF_P9-d0EmsT5n|4{vvFp9Ibtn`N%Yjl-nKh^qjJ;tb9nRs-zxMHk3k-G(6 z<0$6Zh|=%!4{G+(wVu12GTE)?+G!89rKR5ts7Om&Trn#xy<%xvN(Fepx2lwxvR+Aw zjh=L`UT!{m?_O%;pnx0{kb?s9z_~!jMp~;V_tG(uIB7=h?3%gNBqY;mTQ-K2nQ~mV zSDjt!Zid(lhQ$2VX>lKeQ^nJs#2e1Wvth(t&q4~rWt0T?e!9whn ze)aP;#Gq3J?yuW#JzVSw3meU((6LMvB~A=aUGE)FCgpqIx**L^V{#$ZUlHps=8<7< zkG;nGAK!=CSdnPO#eZoP9q2?DJP`%G6ew8PdOd|Grc6=Mwj^z!59?}kt18(w^bJMm$D z{lCHI=cQc$KBpjGpz&Ob2sxA$5mI?AD&&y+t(MOF^FHgc$ho}nAK!1h?2tGXNSsng zobsL$=Pu*L=ySmTcVgq$%p$9yTYL9YmLgMP*#>c3nPpYn=RRH9F|Gyr*!rZ83Vpg9 z`X!Yv-MA?cT3X?>cxC*Z&zd)EN}OESyGk1#uqNNG$=m4DY0&X#Julx*36uqniweeX zdGPKK6s$9Fg{ix}e}H}}XPqukq8XHE1tq$li7qPTspdIC+yhR5wN#e1+b|keWmd5v z)-N6IyzkdAyybQqV!h9c4FTFLEM(rj#0adZpME7#!zHdtOm{{WQj5+I+Hc6=pIzF!2sUv?M1msS;73Z(%xMGS)sM zai4vq#Td;IHd+tsR5T-)_$vN#YAa9~I76ipXrSaRYX-6Wren>l$24 zZFYfriL{dSkN<7FqxmAaaneJ$s*>*5A&zDwoWdTb zIOSIa*4Ta!81!wE=Ol42xO=Ov>(GPa6#vKF-wx|4>d|^W#kNy#0^c!3b>%}7s{+=8D{edj9yI;eB+0-T!-LjWnvm+b!Qhg?}er`3@ zF{wr~zY=<;sVsMdm_Noe<-88XOYuSdu#i`=XCv03zhu5CfkA7RxuxDmC?7gyd{ax!er_j2zWZ4Etwew}|coURkO#hz9%H;O@LX{9aHr z$^4M7revfZPfeJ*XX<2;_G!NO*tp~78RoOz9o@4dOGH|K?Q8BNt~1AQsXS7w8`&|h zj%s8zRFZjD0BNr@p_^`J#z?l#SJ)r{GN>oc465enXvdIc{63xR7Ss`;LW|yYm{Lh@FQq#=*NCx}4T+v}4|VxvxWtKm zKAc-kIkC)i;46uq{9~IEg;o4O4f=?)rAL&B0>k-!xng=J3b|Z=4O&+7QPKSqR~Urn zPxdddYm0gEY4XF#C54fNp#IdKYPJ&h8B@CVge=u%RgO#2{(c-|F9g1#_@oW{d{|&F zwGq$dqZJe@?YpJn(%g7NyQEGk$IXb>EcG&lPx|$4U!g(1Q!AB)eOt)^qvg)iG8fiBnKoX^TsT2&?aBznuqd!hkh&5!TRUJ+uif zlgf85wD(E}8l!pWRvwu){v<*8kQ;pSAcho>eeX2 zriw}-gpVyVskv;qx@{cUW%YzS+ebbBHG-8#$<~^bf`$uWUE7pK*9SdXP`9?Ws^?mW zZ7$E)T3h+&j9Sxm&x2g8s*k(xk{U}O}RDa z1ErYUR=_P1_*3C(p3gp2pgxK7kw)Ov$TQlNz{q$(xpifYlJ-|?JfQ@x9fJ?rnt7SJ z^<-Cf4^9T72edrO(sH!kPj}O>i~~=J64iV|K?c8|z_zTlRbYeU#*!4$C;8KX!gGxZ zF4ZycGR;}DK|gGFEKeJG zfZ9W6oTc_pb1k)t&i-QV>G_{$V;44JwI}TI<7Ii*hJ}rev}QdLJKD?DB=#xJnH95p z^tG7c(ZWHw?0`YIVE-@sMo1a6S*f-UyR9$bEHc&osl0QX3g^NpZC$#yVNAZk&9%uk z8-&m{Sq64pM-Si4nn&$;Qi~<(?89ffV$Uqkv=ptjCDw)x>7-yH!GWO7N z8E7N>1$|KY`k?ef5WkZkI3fKm4`*vn0YVWV)B%DO5H112PC#e_gb#lK1Pd!cNM`*I zGA~LHws(3$j)kKSEc(Er4=nls``}{O38Pu`fkhwK`}d)_LxND!;fJ6B;w z>bV%JXtW%CkfRUs`}d*rssv%-RX+sogakqVohRg#5cB~MiU6Sw5UhZ32@rMyLK`4_ z_zNKL-%Ai`zw<+AIxInmxQO`>gg)RrYcS5aQgFJj!mevEc3;sr`&y1Oukqad`>?24 zf)Ls4hv0Nc5V&)g56~@60YVWV)B%DO5H112PC#e_gb#lK1lLy*1oKyZ2-~Y92u-Iv zA>=RU15U68E6@j63RJK|FNQrj8s}rn73hQF{(Xr0LV|Gd-+l<%7m8 zEtQ_v(&uYN?#F6~V|s9%ceP?`RZ7t)<~fgo2eDp_@1cQCwxrdmEe0~A>b4d)k7^8; zpdZ#LwK=DtAGRrzsO|Yu1OgUt8>M zt^RsBhBMS|hTSH`!uoNHh2uqTYjA5P z{oR80yW8ZdS=>_{joDacdAOKa(Wegne;G3YU@T8-iF$k}>kesHGJA^*vq(j5Hc;fz5OJ|<~^*9Z@ zN6*Ez75MQlv-rS=pr7K&AQr+agA51au^R!LT($z75bqxTPTeF*q`>m5bAP%jj{ic)>`nAepHjXd8 z{rjzEPz7`w*bJx{&855*5n&~ibGC74L?q(@3ks3bzE|x z9v*lyPi*B&gTKPx#eRE)zsz8#zeL#6v_#mvz!H8tGJH}(F24$I1+_|+^IeX9#a!5( zX6}v%w7RG__9r&(M%S700m(LQCJVT|Ju@$lSklpPx$U-nq#Wmju#d<#B?gl)r8Q4< zmuDUxY7@DcOBSjXim-7U69OyLAN^RAH@r0wPm2$i5B`dtkquq4S5jl@SGNme~+bpc6C5V|DQO zy^n|2{Z6vx!MDJ`!1e^(mi0IX?)Lxa#*O;HO7j;d{I&2|xKygtSU_){Ul7DifalkK zSo^agE>D!CbXLTc>E<37MC;n zbUGWcdiXH>zLZE9HqQ^haBYhp!?jHm!?g_*!?jL|;o7|v!?oKfhHDEchHFKN;o7AX z!?l?d!?kG?!?k*f;o312!?h6V#X z�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%0DMiNGf_$WkVuRX&6)lQo8YJYsn*8)V^6}pe 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­RXiwaXIAQ6O-;;7 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 literal 41280 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�V4w#!vSM-AB=_7N;pCGU3*)<*TFgm z0!vP>)TA5nnG=?q`}7mCBTaiuWFn2&MfH-IN3e!mYPbX1Bn{dm zdsIWnJ_tuF-A`f$lRg2F2UChv{W@dJE5H)j4~fc}show`<9}vfewA7E#LM6%oXo9% z-uWlLF7RAM!)r_ZK91r1aIPw6KJnc1oEYb4bg~O$h?9DE5MN_JwEOPdkFgwG$l>$0 z-g7D}M=>5^dP+H_AgP>4#?Kix$hq})`GlOU<;3*Y%9k$-wJWQUG`aHlg_A!to;!Dj zc3fz@dVG{xHQU@i4Jk(LXj44muWamaW^K6(J*%&?l`{V#&f9`wWK4jV<*tf7 z-)QGYSKDO9>)mEL3-tZ-K+^#uXLJ5Y|EiK!#FR#d5T)Y!n5}CuPq=b#>t%GkXw{zz zCLcQ})TO+2gKaosab&*!9CG$EbekF4Edx12yue=iS;UEDLq6CB~a^Y+hO0EJ=u zwGA{gF*HlH^*1y5G)v$#i(v=g{49z^ZG+9sYzDAB0i%I|_mGb$R@@e3W-4g&+923d zv<)O3V%QZ#(d-lLG(IDE$Jl9*(Fyk&xw)Le?@s4-KXGT;81TSG>!p!f1N&*aSsG5o zAnHSr#i0GOmGj@^HqEEg+L9JS{7~Zb{nM2*HqD@C-ddCaV~DH`Lgwo;5htE#D>jm~ z{n1tZp|u$Hv8mJm4Ar@j`DK;O)W6k67E95uYtk$JwuaM0Xv_=RVsW|aV|cun-pX=Z zCa~Xn>6}_jr|12I$gTKYiszk~381G|{JQ3EYqXkJ*e9$i$2i#4j)5}Z1ukb^orEwH zmTUHt0lxzKvFkkFD8ZT+PYs5^Q-oUl0q z1ukfT3);k1PwvzTOdW0)4=F;ksGOL&^&rm0wU(BfSA2kG8SRch*hw!TN{!L6=C&2+ zdguK3fOwsKBuI`^or-5`I?XijL25*@93x_L8$@`_kV^eM>>)cH4)U-ZESQXEXGX$`h2ynUKgkI*th%M(_m9s7$!Vz~-879zmk8^wW`#(G%e*0n z=q;L1Enx^84OUmZ&t%Om6_+6@xo{Wz0wrb_b&5&Ap~$i#&Tow4f4ROpR$EGq^JAUn z-JLkn#`i3Y_rkGeH`x}!+DA9SE`ikJHQ;_g&HS2C1{rv2d<0&rLk_=mSn;fwP>c!! zJKF1AVN>xsgioh>>(zMb!P;?uevO&ZyZO2g)^z{bTXW(vuh*lucXoyk>A~{S;TaW} z1~?hJW@ZwQ(r^gqAkqy!(?5kSwxW!Nhi1>knz`VZpQY1E*L zn{rIexE8K4%79x)s0+q#g^?T1i5OylCc zYGXb7OCQS!>^8?HNPR3V7LWyIL#=E}9Ge5aAR0EK37yffe=R{<;+=)3eQY&6tmi7p zr|k&*rr!Qa{8G{vM}_+SP@g+3nraNtuuXO}Tf?r}FB%f>9D2G7!~6-ue4inCn3BqA zl|RG_FsZj-3q=^|9DlPLY^3=t=ZqvIIW z8;1$i;>Ad{L{6krm#NE)Dg#IMoXyi!Cx~??=EFJA>teF*eX*`eEGAC`fd)2G3{iw) z@^}JCelwrc)xAzCMt#|-2o-lKM#4u4pQqsy37-)7Ji7zZJNL=zjikS=pCB?H$q_ycPkSjOtfANQxyyl~l!M5>gsXCuC<~4Cfv6zxNrYYxD@xTtqUS5z}77W8}&%A(2nb4U0=_v zO2sGfGVr4?H)6Z`9Z5$j_yLHvXTkZq7Q8UD;3c8IB2sWyMBwisf*7PmqsQ;Ub8>Hh zl7W)EKW!Zg_P*AtzZeN zgZP_B(*ZsB58n9jtKs%xNx9WZ&)#LVrFRX%wga#u3XnO?mI^|B%!YmNZkDg)ZF)Uk zabrzeEB6>D7_8h>ZoeK*#-INo#^h3j>_%W80^8_@1l|J|qVh7X+h(S;+CZBBpgfm+ zW>(|eQ(1_|np1pG)R;(|L$(zw}cwMhy04}J-^Mz^}P67 z#{(|^RuRVK!Bf$_`!(1D_NjPN!O2t4ae4f2>f98~9sm`Zb@61f`#engW zPlMJOZW3CHp*#S?t$6whz!2X*2-uy&TW`!vSzb=6rP#wv>kEx<2lxYa`sQLBS~YIn zD_tv7u9pS=>K(~zs&Bu|CjV@jUN79ZHSB?eo0JzgspyK^&cu1pEuMdE%8uk&zS;89^Tf%|B^26hli z=s!=(fK#K!xn1=y+7s_0&K!a;4lrS2e256C(Pj~J^o31|y>0z}C zh1%X;!ZrP`{if#cwgTGV!R~E`7}vl0VExCn;o&XFyYwKO-{IZOOSVtO*M)<^9yTBm^WjMD!NhR zeQPzYtp@4~nvr7TX{6Z3AVo2Qv}!mt{?f})To&(zk}Hrzn?M|sN!1W32cFCqfBZ6; z)19h8u8ZAexU`ZJC2jDW%6j8~u(cfpn4w0b2_(S9@-K9$yOC~w9Z12gYh4#V+=sbk z{xS$o)#8#)Ch#$nv4M0g#)&cZV(b3Qi|wh;F*d%I7vscAZ!IKAuIR1x53BC99+8bZ z(3%*nT1B^s6vbkoIIkGD;6p2hgjWy#OcM7Ow&nfy3}lME%r5JPTfUIP=K;{>9lFys zh)Cj+*Eg@gz$f`UNC|Da)%Cw6P6^K5v<~Xle?=J-G z|Ja6iG%r8ICTE&{-iAwjSY(=hvwXb$Gdmt@IQA7slJXq2!uksFUKc;yLN?TRaI)ei zF~)DTu=kopWTPJ1e1t1y+C)z4wQf7>!FHQk6q~Lf zh2;)n-KT*T*Tq*hJV=GYB1Y$X=y)YxonnVbh~jkE=Rnj(k&seCiiET{RCq6>l#n7w zVFbf&C^IbPCU5=6BbtVs+hI{ra?pEZRM@F35|C1vf5B<)9t3Ay2K;-BSc&i61bZ}_j_pTkkoY4Fs!;cvvx>vJl=1&oFDC+Ep>S*0WD6DtVR_ zQKRrpG&=9SB6au{8vfpmbg7Jr5#y+R*Toa-SPAuX;S%uJjgnDOlxw^zcG2AU7 zhPx%iI?dN&-;;|0c3Ha-1w-UcX8scJb^ra6l{xG`n2^lbF#_DtYuF*wlNht>;=4xH zk9zWUIEos&qyz3MU_xOR0};Z6+M-10(5B|qwI6-TI18J*GG|ADuLU26243LMp5EJZ zFumAsO0^X3g}FF-b#R?dV-m}x`EYLmBVx_WFkY+4%NlC8F?-?chKa$gHZvii;CBu8 zR7FIQbv``8cdtC;ZUYPz#vsH;fp0a~Zxeu`*TLWCeV;g5Z6c>Wo2S~;0D2V?u`AmU zN3(0M2H_m%TWwt`x*|qr4?@`b1^YgzJq~Sydo1FZnV!?4RqL=l1X}Si+h6MU=$i{H zaLR8az|H}u{I))){ADL_O!`4MF=8*444h&ok{<<$besl$I>4W<86dUu;{#ULpU`Ev zMMF-UR?|HKtMl9U? zG{n>2^&kG^e1f_tqh1xe>dTv*LDa?ZWu6ff)iXZopTFu9Q5SC7_)@Pl!OcC52TPw@ ziu+I|EevqgKXt`PQdfo_BoY@LJeV-RHYa5zNV}zihX5Y=a96_pE%ECeAXy6dn9ja- z9llI>=a%@wY8>6!Bh|2!gPXtbr>PvvZQs*w93{+YCV<6oRQ5j8q#QP<4Q;K;)j%rh zt>u|L^*^4aF8SuoreH^NCa|eD@AgO()v>~CZ2!=`)-3-TK|C3>(0u1kyQ{vtVQ5`u zI2z-LZ4kpb%o0zez?jT@aa3mh&~b1+Ij{q`> zg4Ec>LtvV`5b(_-tpb!LCx-IEu7^S4@z^iHDz}604aY@3kGrUch$z<%TuaIE+K_j> z(IqxOw7ngo?VCU^ZS6DWedFXGu7P;&yhy+r?M}G+0^fOYc5M}7_uQ3pel1r6)(#5n zF%-;8Z0VqUkBShpe)2i)x!#L@k9ZJjK95W)|K=_t*1$VVAgbW zcL@BL$RwX8fHs_^z7E zaG#kXq^3&|x}yunQcf~Vz&@(?!A8;rd*m)x#fP6@USnD4z555pxbP7#vo7FRm;HKO ztwCZ=ZGbaZ2UBb@x6yFJ)2Ov$vkzpG|74K)MKw`aYhFR!h-PL7um*gprN7r`P#P|K zynrvJT1{y!X4o585@AdkiX(64?6+)=H>Y-hPsaqX%S_E#XzVSYwKA-U4ADt&#Z~cCj@6W5^H6!Ty<7Fc&uI7eaCyA*WXe6_n(_l?vKHIx#{;j z<#JC4mh+bFBZrUI8jgcK+c+RQ7w!rhWnu?!5}8{aj2!qRqm@sL+C)B0Bk%w)Oa+@~ zubngu({3LO@j5i{LQA8a0`lVB>T=K@?;YUcIK@afqf>${66FtueeON05p>8-ol@U9{HpA)K{cVia5Mp$V4(n(#>UXb(WqWr*>Cv!8pO(f90~PFID0`+#!q zJ&E{^M0{5wz9*4C_0Ae1TP{a?^kYqjvg5K@k{WD&D;n;MtGTyzi75ltC8o6f9{5y^ zN37N{Y{25-G@P_bWQOI4UE_F?T0DS;bXYJ>^^PaMUXtr6AGny!aXcx-Wru*>dzgu0 zjW+Sn#ca0Y$)SrOKilzy&i(|n&<|P=2`!k^rv=BkxrPP8c-ROY-grEmg7I(#xaof_ zrDz1)Dap;y!rcVmPlZnc?y34cOB~TF!RO#4HzuOgI5HMAl}<8Te1E@1kyQex)61Hj z>tF9?H}nsHvD0Zj{i0`%spKU@qeZo-1pL)NgQ^9ZYJnz)Koj_R@;5h_?@dOziD&bq z8rJ+h3e+61^qmKtFb|HvJU9pQ;2Oj%;#2d7otbCAcmg}(T{x?~OWNfiNf>B-IAEOw zcVNx*_^o2@%Yq>SAa|CbikmVTEZO(1IiP2C0OcJ{J#+Q<={%b^7c9g)?_3oxoZeY( zKK%jAeW!`}DG=YpIisb_e0n+>p)t1`{n>%PATmtfDVHNO)zU1|TyYwYeF~%A_7BbIQ!$KLZ|&AD~bBebSHb5AL9E9*^yd-{f&KJ}vXkN_^U6 zIF8SqUcQhO;2numbE>jgF%^VIqRg-6p851M5Z&rv&RMp^OBb7|2_nVQcRII%FEc+n zS{`cQYO#!-AYwVk;ICmkk4Jbsk6Dc0z&O-8 zhD6}8Dv}la2}x;BU6Vt^=GmTrF}uk&80X{M^+^`sk=4??nyFGey`wX@NY?NS8g3dv z4WztpmRuYX`%>(uNnj0yQz`Jw5sU8?7pkO%pzFhp*A(1mU|3+7qQw2liS5nKg2FCc z;-4TsxF5s^KLhc>lYLHq9y8+5J;`=-RH7ihmux3~h7s2*v%F_JSavB!0xil@oqfhy z;^dyOhWX2nwYf0X>LPl^8q6Jir&GuL^!pT^&07GoZJ}qLg6(kc!SeMR8`om*WxHSj?Vd`J}dfOkWJJcIib3_KP--osZK zjNU!M1~5HigNM1athZ-+d#$7x<3Cu2bx5yI9lq}b`>QHK;WH9GO8CGkun*raaKm-b z#)wd6F%yOTXEFomD13jJ`Tcf(*qQ$~ua|nQW`7)N-d8WG0ZA)Wmd2K z?~lXvFYSSA?1jry`@$FhQ))l|tOqJsle|2@)cSjN1wbvx+=p>tk3Q1$aNdFi<;Lh; zJ#fLxf`_Z*CYj(Qq!`nh3>rUw5{329UV9y0xv{6QVjFyRz^52KyJ)nZ8_Vqjsy^R_ z;ogQmQ)ERz6gBQM557-(bv+7Z#s3}D7q<35&G&_R;^Y4fRF|a(D)>D2()#YEzEFL~ zz@xc(V#Duob@ckaT>axP^KyR=rYol}Ow3b$pN#hnC}6A!dMn!$tqV^=g-3ha6q=0h zZ^FG`)t>}?OU5OkF>se-60&ki?ouDEyl-F4t-&_i2`12n4atTBdaG&W_#fc*)M9u7 z>jc0#IK>waUz_)F;VtNUOp&I2V4r*F$kc-^w=0_Q1AA(2qE@Zd+zw}=bZJtgYCDVA z!HtMq5P{<8eTCRM26pRvKg5g&`(U#uMZ>G%Ri zWc-E?Uo07$a7iAx#A=DOSl~=uv8%Y=lWuDh(*5-q8rThv_i(0{FDEv~@`Ql% z_?GyMaoBU8(!gnk{;CM{*ELtsns|Q{0)9=n7svtz_7<^PpB#<>ou}2mH-{g6LYwO3 zo*r*Lyd{1}JeQ~nZbj_C(;^dCquPB&S-1mk1hT9JFC&blcl4FmalRto20rzD-!L_v zH(A~{n7jDI4BM-M)kB|`EvG~o=ZiT)&3Qb=H+brM`yg1|FoiM=wG-;r@qIZvh*nmW zp0bOu?TQ~maR26igA7vR7AcBO|FeeZ_>H+HWQ#iQk$38`?4pd(sAFPgrek_|Z938XuDS!T!SZs}?TJjs}=-R#w7aUi8te>QE^Jn+h=z?%r76TnO7 zjFB+6wfR@-us38CjpHCv^0t9jB)drtkvJJ}rcu*nPHiLhSvcbe%30NVpO>*%y85=D zWY@-c%ty0Pv&%DoBn7M4DoSEDQeuw&gpqAlqN$ttbE2I)wbO<`1WpVw)uITI6YCl0 z(7Ro1JPp38wD=Pyn?AIO@F~II5`}GD>@f;r3d|f8vX44cfa|+cw^XvzX~@O#f@A4@ z9uBWc-CXUBfaGW%XT~Saxpe1s8$?8UZN#|u|LNG`>HVEHKK;DpqpfzZ{lGku(ThLU zCh{jL+(&^$YdjR=8=WT=1XT`+;~3`(9M8+o#Ca6DxFk!2=5azw5yG>OQX=75NGVcy z7E($qJPRpB3C}`G(ZaKkQjG8{q?AN>7E($oJPRr1Cp-%&)lYa9QmVi3ETq%`;aNzj zfx@$pQvSlTkRs{^ZvS^eI*$;Zg>;@scox!mr0^`H^Tfilkj{fUZ$0pYbRI1{3+X&Y zcox!m65&}$=ShWUA)V(ZJPYZ(e!{bm&g(Bc3+cQ8!n2Uh8z?*r={$eoSxCd9D1_+^ zj|vvjFd-c;q-r5e5z-7HT`r`YkQNB(P9ZH5QoE2g2x*g$whAdl2>69GOi0HIsai-= zgfv4)mkTK;qy<8{Q%K8%)GnkALfRyxt)7$-+HVw6W(?(_%P6GGSm9Yn8I|xXq|7+s zSxA}j!n2Sv6NG0W#UaJGy+$Er{!MrmQf8v?ETqgN;aNzT$-=XcGJh7Hg_M~hJPRo^ zRd^Os=6T^+NU@aWHD8@(fkc;JkW5%3Ym7z%vbSc9xO!XpY5=#yye9f9mJS}yp4>G^ zW(cofCH5g~Qt?2UfvI5q?1SO^5Rji=u|ci$`qfx-u}!Xv(>RBmZpoX^7m>P)wZ{xB}=in6BLvw`9ECK9PFzNhZS10goFG~jZ!`Pj&*1MQD zP96O#z}$;r-aIJKF{JHQ!5vJ;Kek~yB-M3g;C1Q2n{m*DYptQLfk&nX$D%TL&ce^g z10{_wVWi>4t`JYooH7pASw~;R@Z-2IesL8&zn+JzP1stNi{IwaR{)0x;`)Q09D^sv z1Hr^Y$fYmy5VSu5k8&}D{?*!q;4)Xyj~nsRv2uXy`L@UtHNoFv=p9MaVzVT1FDni1 zH$lgq+C|GGbOlRO{n)v?#PIzvSj+m!BuYM|l@+Ym?$_J5w2kju>Z>Q9Z$}$C=41WH zd#WarO!$gLlob3ozj6+?-_H!tKwCP>b9J}}WOt*{)+|;W%&-@BA;@`+Wr7*7sO@zI z*gG==qM?;D!MY87Ew+Qr4f;CBeivW>&zF`%3h$F3WguN@gA`yVK^hL}XOJHb`MHor z<7XR}=nOt{=j$5>IH0uXsWqRLL(Z@>w+im^IX|u`gu2lHdy4l?3k?OQc)@TUI3CUe z!{8LAif+jJHV;nq@-~2uz&3-Ir$!C;1Ee4_aXH)%kb!*5RLa?_Sl=AwxewU8mh&2y z*GmZB2fYt&G$_hor&DlmkskXXz$wX>aBjZ?rBiWCT5d}2HfB+7GTg1mu9iL$qoSz8 zCjtb|YP?r+7D&6Ud(N4>@sA6R;AoJ@>^=J2q_Cv*$;F(EuE8hl0Tt6&Vm!$PhLL1g zjhmfEJ#cfT8el59R-0~QjoV43xL1MaPYT?gi%+qXC-GgL*k@$caXz{d{6-)$TQ}Vf zVT%n&m(+yF>8%KEry0Noz^#Me-+=ub%yKDlxt|VxhXs2(ls2z`lZYxB`_6BZrmQP% zj)vdo2xS^AY3tZKj{ewU#``yngW4leI#Wf>%-cpM!Tn=4dSJcT(D>`{b!`9BVjF#H zH0)Ob**~53V^3qtyBJ~#g5Z{}ad2bTND*H%3F@Zg;d?>YrfYPm-|Sen<%s0aMvrx8 z?}tZY?X16_n99YGitJyVy|8kElbfR zuwsaT1DN>S4(wcM8|L?o`J4${E%i%{b>2JDw!pxZzm{@Sn7v3sB*ymaHG9Vsz9%1R z^3bo@IIh!$_WspsifzGhRZ~=Rj_Kew5#6+4L{3w~SY3{E>M$6$DKLIB5E(xnJQ&j@ zmp%R%+bFED$I@Scs{O!M5s(qlcf>WQTFMWhcVIE(Lt33v`R-7@T*2~i*L3sB9N zUidu^ptm6}34SlD&_PM@FChg_RJ&hG!&0f&^2d)>e18HSt=?E*n2X?b0q4*#N(+!K zc_-3MFN5EKnw=h83H_yqn60ASzuR9Y0T=9&l+Nk!D+_pp)Xpc&!6qUO?r(b^d}v;W z-_rA;YB1IUt-1>ffF*?2Z@ie|l-{aZV7W=SEYz_s^BJ;s()Zl-RC zJkR-ocC$DbIX6hV%HS6o4))Aw{{CFt8kp1ILq9fWKlsq!STN=~J}0D-**dWp&u~5d z&8>itP#op0ce6oon}opp8dsOgJ>GRz;KRRb{19*w^NhqE|sPbuD!2VmfqAk zqzIp-BJo0wb1Jz9Pxi4~a5gYq?)eQi*WRZ#n;9gY(@H`ur>y;MC3w2{+R7qL*rp10 zk-hJ>S>c2k+dl?8&+q-bzsdpozn&dB-1-&3sws~Z52DkcFMIdr-d#N0lN9JJ6X;WB zB19SRF$TOZAALc2E(=*rm`jtg59Pe}Jlp}BMxlaTI3{IPG(4#(daeOKt%q1N;0;6- zd~sOk@R7~-9Wd78U>#`4+XlZaC7rPBTOIi8Isehwi8%-y(9i5(_5EPPJVRhVJMf)N zJ2@Z68StKVBYhc%D>>uiIFIA4Ead zxba;i+64F&pGWX~bWJbMS3blF&7Wdmu7mGY7}yr5CIxsM@BO^OY5>2wE;)EQ%IM-y zEDgV&5@?6n-L+oBqINM~nj7KT>pJLLc5w(UJ7CJhN;nzr3e{=d;J!JV7fLnc)#YJ3HD40vYBjyjc*W|Cy#-&)M0X0@>V)$D0=KV_ ztzwY=$?i1v8?gw>Bnp0Gfk?#PST34iGdmHE5UNkH>YY!GcVpOd1)DfO23IX?wGqip zw%&EoW8E@YfHSZMky-WoOs!8tBrZA*wtXu{z#TE4s`ydml|8*re3U@%dco^Af_4M? z6X+~~IC88;q3b06Y;j$_Yw2rpDd<^)%k zN(*A}tq2Ra5z)}5V~{?L;e1wp!Ek9(WOhb*a*o~h_Chu2w!EJm_S^^mA8wD{wb%cX zNCW0De_Mw4eC%N*-~E^`InyIKyd`-VJNHztgq_ux{>|beZywGnR! zrA^>jSha#|U5KS3_!A1zS6=_)lQZIGV%g}4{+jOR2e%|>;P*dg$ok(9c{p1Cii?N%J-eGSlsR){L4S!Y1-}lIJ(CU3*{n6iafh|DlZ-h9b*IaN?CV7@6W$(altA zwlk>pPQyZz4c5^6&hwVr;MZ7UL0i`z*{H}8qvvcl7Y?`SB5UqbJ?k^CXDm1Ze$;q% zHciN`dig1HPnvwR6>U`yAb?3?AQQdziRZds~R*3{XMsF`^*&lKf~Zk+p#7eDBsMX#Lkr2yugJFL#C2QSp3@7C8tZg(Gg@h?4iX>PLF z(;8q#(v5hZiiUVcpg<|y$1(|M{l_t^+hAYxMm*MTjJ|EvKWE2O0=Jfi5rsvpNh&_1 zcMoN|dTH$b2H&uV{W0N=(f2yK;65FZJyj8cSM~?TGNuRLw*$Xq;dyVjIsN_aW6k4i zIoyc@_jiF#0B~#5E`7 zEGnn`oH2e~lX8~ZW~L?CUQ0VzKFRc1IT?}QF6gxvfi?vDYpfAz!US6ouf0Yy1M6kX z>0jBk&7x@L)@T_M9>{KKhA2TbXs0P6uphxaA{p2w0lSKC^B~&f|7-7BfTOz3^SOK3 zhbR@qTS>&m%&k2F%wWLWAYwOSq=nVPL4tx-G7UttoV`fvt`@Nm5Fk9l@=C%}q@+92 zN}fOoQ-kX|bjl49A;nlqBw;sk>=GemCdPq9D~0f|WAq@n+J67tT_hlN$J3d1I_2(s zd(QdKf6w{P``mNy`47%V#Mwu`h`q_w=Jxb-kb}AXl&1rlm+Eu5e@us`Wqfzu433kS z!M;wb5>rC5=3*Ua&)6R}+N@_c+x#7hO^Ls$!rhg}bZ^!t<(l-v{Vavj4BxCWn zsLNJwk82pk{sA4mSIySG7!Wc06LT;Nv@S=w)0xG%#X#!?1yfdH_}us|1D*vM}fX7ZmIlA(bNp+KwV zxfKX;zF^UBG2}OrR{SISf=0WImm89JqzB(iLg(kXdYmuafiRD;%O+@J02k?)IHK>& zD`@1AVFR}tjQnN~R)c!Mg;U|W#}M-n>(Xz*PMiFuCy>V4b7{~NV#KP`e4Y4{6*|PR z)hO~S5nV8?j`o-0>5QJuj_7~hbUMU`hnU(i%2eYgS>}=YXsqPL-dyOGho+hCGK8^H z7gh|>aJXjz<*TiI$YpeYLDRBOxV-msyDdBz`TS(ZM%%j`n{9isYE%)gov0rurDm+# z;29|Qb(*hZW#@>IR(du!sm2b*!yP8Ip_lQS<5VxfX=8Yn#9a!wEr`tsO%#X?_wkA} ze1VU0#q(w@o>;*{<*M-Wft*JAIk4AKhTX8&_)6Mka*V&Ef%C(5AU0C zYOKXb@0*c6(vgAv1Fz=>UwNMK!TDk+6}>~<(IRu&Q+H2sptZ3d{NiXppR*o%Ed$e( z+v)jd-uMbedbpSSe>Ept%za)Et$(GRJtF4qMs0pk2(}U>{^HnbabY0oo3B5wfByTK ze5NAsKe1s?g;k_=VVaK?295?YGs7uLG;B=5sD_zt+LO|47XH9EK|I16+?a$XU}!}! z68-*hGB)QUPL6LGFO`J9b88|zH|g_#FZ$Kl>zUdN<(2Rz{ph8;Gg-<7+6%F71y<4- z=EZn-#8bz#eAHvCqc4II;~mXp1K7Jp`iAuR(5nn?{;f|Ke--;p5YD{7^~^T|G_Tuh zn>wFO+)wqAa+T(Di}B6a&BHg}4JM^9IqBJK%w%@7vBwYNsn6b~i+weI^YF~Da(n8W zGWM*R2>V1neYr+bJ{ZGsgl}E8aDU1djE{0;2(zR27{+1Di`Mp2xRZ51eM% z(Xg;~aRWbS_%nXHdwO;mcSjz@_Z$M}qhAXa*9n($)8;ee-O#~|keF*^_!1p^3?Fa$ z>c7gZgG?Rq=%!U>3%k-dA7Cr% zE&7cI_F>Pr5YgwVFZAjl_0{2IP3mjo3xXFK?n+(%w;7?@93yshV)aqi+%)*R;2}s@ zpOS6<*dzomCJO+CSY-BTB?PWu!oX5Y_!R->G#3s?1CLCJyAc2aE}XYvK?3q@+>Z%0Hqgz_rxW40#B z2TH$e9$`V7QBZe8M792Xu?r_L@jIier^RfTK7qtIEa zjv}nU`#REVwz-M#ImU8uj^SvOm#3Nej$@DPN`*TmSx9R7@PPHCS`uMuOONnTqkJB9 z5*LwYQqiDoI*WS=!1RXTt4u!Qhn@zamdY=g{)2_7k<}PFQ zHk=k^j7C+Q92bP=M*DW)yVdE zlUm%1nTd!pmv{E+WPKl6GTO(rV@(_U1oYV?m-*Yt(B32p>V5SEkmBww+N+dIYs)EBmNX9q1OQhNu^Zb>_dL)&O_uOz6Z`*hdG< z1BfRTy30}&hFXo%`B=ofZWy(C&p69y4K|=%@_|&oeLVH{+>BP)G@hlF4C}h|o%`gf zVVyiP3cZ6S0Xes4NXQ70j&7VI_z2%QWWJr25$a0r+@ju?VCIJ3N7eCUoU;~hhgFcI z$t23gp=`M!Sq%0=qJ~qtuGXHA+W0owf>CHWlwH1ecCZiq#TdTdGpf;&A+%hAW^JF@m4kPmeWa$gzrl^thlpTb_Qk!Q~qy3JJvhjv4*la)u ze0-2~HS<9|ILX#_ph6A%Mn>hj-Ym7Fm$iou9yn3ocGi3zZ4>P}cHh=* zo(ieZUZErck)-FObg!1bcm4CS*B41Sirwe;C|>xlFHU#d&r@Kpl8Dc%1%xnSWwgrg z@hEPelxO$&CZnJ@{8}72PEW;7yGM~McJDnhEUij+RZVAi{Wmyw-{X%YebX|Xt@pcq zPDoExqge5Ho!i_L4aKij6Px?5-P?A$S^m2G($zSLnCeYYeu1@gwRH`-R@O(OTYzEU zRp4KMTXoUs0+{*k9d?(~A^BWeq^&N$w_Nfl+x?2yC;4_&D$=*oUH;9Kh;pPY-SM0h zGh^(|t=punewT~BpD4GUMDPGNrf!#&4QgO~O^Q zc+#Gr6+g{t9KcEkOkgp1uE92mU=?31==^eS)#xCo4XNeqDh-+-S1J-|D_Y2b&zao`Q$2=G0i1^5o|D)0)h8+hck zXmkc(02pu>v@e4{fd3Y70~iJ_1HT3?03QJF0Y3%a22KGdfVY670Liq#jgATH=coP= zvIFOU4*=6!(dgg9JPr)Ne)I?M2gYHa1#=lt3A_aNFJYcI9*tfD7X4E+>I2$=d2p8l z1^MV;t-0ukjGTc?K*rnAXdysuH(-H%9&oOR)%;Ilw(Z{dobGss<$anuF}DN#F7?eyg&(7@ zQp&xaQjcPHP#wLWzSHCMQJYJ&Q>TMQ8E1S{qC4IG3hF~JP8JSDqpN}0z(QayK(wiN z0`AIKm&#mDx4&vp!o}DU^zs;iy(9LbV_~_NO|HHXF39*P_u@QS;Vli(tKa zGa7A-(}c&wzj!Aajp{(p0q+3p7vT?UG@`JS#7BO=jPv3-?LTFG=P_2}p2KP~U?!NT&rkIG*DRBC z^4I3QFuPVw((~7O@%*O^v+Qv0Bz;w3&UymfS8bi7TMP1w2t?mBg$`#DhK8iK5yqOl ON&dImSPkgfnDHNtwd)oD diff --git a/pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin b/pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin index 77f4dc8f8322212c437e7f8d7f2ddf63bae1c2cf..1acee86dc7cabc1437018a69900b1c3e7f7a7d2b 100644 GIT binary patch literal 57936 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%0D>4?*JVxq8_Mnq!cRhCnEipE4d`1!Lj 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 Z{D(gPk9a-7`2Bv-ADJfQJM34I|39KtfIk2L diff --git a/roms/opensbi b/roms/opensbi index ac5e821d50..9f1b72ce66 160000 --- a/roms/opensbi +++ b/roms/opensbi @@ -1 +1 @@ -Subproject commit ac5e821d50be631f26274765a59bc1b444ffd862 +Subproject commit 9f1b72ce66d659e91013b358939e832fb27223f5 From 02777ac3036187077c98a05843d888b4be8c51b3 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 27 Apr 2020 13:36:42 +0530 Subject: [PATCH 0065/2595] hw/riscv: Add optional symbol callback ptr to riscv_load_firmware() This patch adds an optional function pointer, "sym_cb", to riscv_load_firmware() which provides the possibility to access the symbol table during kernel loading. The pointer is ignored, if supplied with flat (non-elf) firmware image. The Spike board requires it locate the HTIF symbols from firmware ELF passed via "-bios" option. Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Message-id: 20200427080644.168461-2-anup.patel@wdc.com Message-Id: <20200427080644.168461-2-anup.patel@wdc.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 13 ++++++++----- hw/riscv/sifive_u.c | 2 +- hw/riscv/virt.c | 2 +- include/hw/riscv/boot.h | 6 ++++-- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index b8e765277d..726300a171 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -36,7 +36,8 @@ void riscv_find_and_load_firmware(MachineState *machine, const char *default_machine_firmware, - hwaddr firmware_load_addr) + hwaddr firmware_load_addr, + symbol_fn_t sym_cb) { char *firmware_filename = NULL; @@ -76,7 +77,7 @@ void riscv_find_and_load_firmware(MachineState *machine, if (firmware_filename) { /* If not "none" load the firmware */ - riscv_load_firmware(firmware_filename, firmware_load_addr); + riscv_load_firmware(firmware_filename, firmware_load_addr, sym_cb); g_free(firmware_filename); } } @@ -96,12 +97,14 @@ char *riscv_find_firmware(const char *firmware_filename) } target_ulong riscv_load_firmware(const char *firmware_filename, - hwaddr firmware_load_addr) + hwaddr firmware_load_addr, + symbol_fn_t sym_cb) { uint64_t firmware_entry, firmware_start, firmware_end; - if (load_elf(firmware_filename, NULL, NULL, NULL, &firmware_entry, - &firmware_start, &firmware_end, NULL, 0, EM_RISCV, 1, 0) > 0) { + if (load_elf_ram_sym(firmware_filename, NULL, NULL, NULL, + &firmware_entry, &firmware_start, &firmware_end, NULL, + 0, EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) { return firmware_entry; } diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index e32355a691..bed10fcfa8 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -352,7 +352,7 @@ static void sifive_u_machine_init(MachineState *machine) create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline); riscv_find_and_load_firmware(machine, BIOS_FILENAME, - memmap[SIFIVE_U_DRAM].base); + memmap[SIFIVE_U_DRAM].base, NULL); if (machine->kernel_filename) { uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename, diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index c621a970aa..daae3ebdbb 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -511,7 +511,7 @@ static void riscv_virt_board_init(MachineState *machine) mask_rom); riscv_find_and_load_firmware(machine, BIOS_FILENAME, - memmap[VIRT_DRAM].base); + memmap[VIRT_DRAM].base, NULL); if (machine->kernel_filename) { uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename, diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index df80051fbc..474a940ad5 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -24,10 +24,12 @@ void riscv_find_and_load_firmware(MachineState *machine, const char *default_machine_firmware, - hwaddr firmware_load_addr); + hwaddr firmware_load_addr, + symbol_fn_t sym_cb); char *riscv_find_firmware(const char *firmware_filename); target_ulong riscv_load_firmware(const char *firmware_filename, - hwaddr firmware_load_addr); + hwaddr firmware_load_addr, + symbol_fn_t sym_cb); target_ulong riscv_load_kernel(const char *kernel_filename, symbol_fn_t sym_cb); hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, From 5b8a986350a9ee2d9d95a76c29017c3c603bb350 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 27 Apr 2020 13:36:43 +0530 Subject: [PATCH 0066/2595] hw/riscv/spike: Allow loading firmware separately using -bios option This patch extends Spike machine support to allow loading OpenSBI firmware (fw_jump.elf) separately using -bios option. Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Message-id: 20200427080644.168461-3-anup.patel@wdc.com Message-Id: <20200427080644.168461-3-anup.patel@wdc.com> Signed-off-by: Alistair Francis --- hw/riscv/spike.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 98697a244e..e7908b88fe 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -45,6 +45,12 @@ #include +#if defined(TARGET_RISCV32) +# define BIOS_FILENAME "opensbi-riscv32-spike-fw_jump.elf" +#else +# define BIOS_FILENAME "opensbi-riscv64-spike-fw_jump.elf" +#endif + static const struct MemmapEntry { hwaddr base; hwaddr size; @@ -187,8 +193,24 @@ static void spike_board_init(MachineState *machine) memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base, mask_rom); + riscv_find_and_load_firmware(machine, BIOS_FILENAME, + memmap[SPIKE_DRAM].base, + htif_symbol_callback); + if (machine->kernel_filename) { - riscv_load_kernel(machine->kernel_filename, htif_symbol_callback); + uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename, + htif_symbol_callback); + + if (machine->initrd_filename) { + hwaddr start; + hwaddr end = riscv_load_initrd(machine->initrd_filename, + machine->ram_size, kernel_entry, + &start); + qemu_fdt_setprop_cell(s->fdt, "/chosen", + "linux,initrd-start", start); + qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end", + end); + } } /* reset vector */ From 31e6d70485b1a719ca27e9a2d21f2a61ac497cdf Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 27 Apr 2020 13:36:44 +0530 Subject: [PATCH 0067/2595] hw/riscv/spike: Allow more than one CPUs Currently, the upstream Spike ISA simulator allows more than one CPUs so we update QEMU Spike machine on similar lines to allow more than one CPUs. The maximum number of CPUs for QEMU Spike machine is kept same as QEMU Virt machine. Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Message-id: 20200427080644.168461-4-anup.patel@wdc.com Message-Id: <20200427080644.168461-4-anup.patel@wdc.com> Signed-off-by: Alistair Francis --- hw/riscv/spike.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index e7908b88fe..d0c4843712 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -476,7 +476,7 @@ static void spike_machine_init(MachineClass *mc) { mc->desc = "RISC-V Spike Board"; mc->init = spike_board_init; - mc->max_cpus = 1; + mc->max_cpus = 8; mc->is_default = true; mc->default_cpu_type = SPIKE_V1_10_0_CPU; } From 64594e2bcc9a734bfabfaa8a75e08b4c9d920569 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 10:30:44 +0200 Subject: [PATCH 0068/2595] qobject: Clean up QLIST_FOREACH_ENTRY() QLIST_FOREACH_ENTRY() traverses a tail queue manually. Use QTAILQ_FIRST() and QTAILQ_NEXT() instead. Signed-off-by: Markus Armbruster Message-Id: <20200415083048.14339-2-armbru@redhat.com> Reviewed-by: Eric Blake --- include/qapi/qmp/qlist.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h index 8d2c32ca28..07ecae81e4 100644 --- a/include/qapi/qmp/qlist.h +++ b/include/qapi/qmp/qlist.h @@ -34,10 +34,10 @@ void qlist_append_int(QList *qlist, int64_t value); void qlist_append_null(QList *qlist); void qlist_append_str(QList *qlist, const char *value); -#define QLIST_FOREACH_ENTRY(qlist, var) \ - for ((var) = ((qlist)->head.tqh_first); \ - (var); \ - (var) = ((var)->next.tqe_next)) +#define QLIST_FOREACH_ENTRY(qlist, var) \ + for ((var) = QTAILQ_FIRST(&(qlist)->head); \ + (var); \ + (var) = QTAILQ_NEXT((var), next)) static inline QObject *qlist_entry_obj(const QListEntry *entry) { From 1cd7741ef18e4333b17d64aaed3cd48e3e182a57 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 10:30:45 +0200 Subject: [PATCH 0069/2595] qobject: Factor out helper json_pretty_newline() Signed-off-by: Markus Armbruster Message-Id: <20200415083048.14339-3-armbru@redhat.com> Reviewed-by: Eric Blake [Coding style in moved code tidied up] --- qobject/qjson.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/qobject/qjson.c b/qobject/qjson.c index db36101f3b..87422f600d 100644 --- a/qobject/qjson.c +++ b/qobject/qjson.c @@ -159,21 +159,28 @@ typedef struct ToJsonIterState static void to_json(const QObject *obj, QString *str, int pretty, int indent); +static void json_pretty_newline(QString *str, bool pretty, int indent) +{ + int i; + + if (pretty) { + qstring_append(str, "\n"); + for (i = 0; i < indent; i++) { + qstring_append(str, " "); + } + } +} + static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) { ToJsonIterState *s = opaque; QString *qkey; - int j; if (s->count) { qstring_append(s->str, s->pretty ? "," : ", "); } - if (s->pretty) { - qstring_append(s->str, "\n"); - for (j = 0 ; j < s->indent ; j++) - qstring_append(s->str, " "); - } + json_pretty_newline(s->str, s->pretty, s->indent); qkey = qstring_from_str(key); to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); @@ -187,17 +194,12 @@ static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) static void to_json_list_iter(QObject *obj, void *opaque) { ToJsonIterState *s = opaque; - int j; if (s->count) { qstring_append(s->str, s->pretty ? "," : ", "); } - if (s->pretty) { - qstring_append(s->str, "\n"); - for (j = 0 ; j < s->indent ; j++) - qstring_append(s->str, " "); - } + json_pretty_newline(s->str, s->pretty, s->indent); to_json(obj, s->str, s->pretty, s->indent); s->count++; @@ -282,12 +284,7 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent) s.pretty = pretty; qstring_append(str, "{"); qdict_iter(val, to_json_dict_iter, &s); - if (pretty) { - int j; - qstring_append(str, "\n"); - for (j = 0 ; j < indent ; j++) - qstring_append(str, " "); - } + json_pretty_newline(str, pretty, indent); qstring_append(str, "}"); break; } @@ -301,12 +298,7 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent) s.pretty = pretty; qstring_append(str, "["); qlist_iter(val, (void *)to_json_list_iter, &s); - if (pretty) { - int j; - qstring_append(str, "\n"); - for (j = 0 ; j < indent ; j++) - qstring_append(str, " "); - } + json_pretty_newline(str, pretty, indent); qstring_append(str, "]"); break; } From 2f2ec111795119b2e020bc0cbf4b5f42878574b2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 10:30:46 +0200 Subject: [PATCH 0070/2595] qobject: Eliminate qlist_iter(), use QLIST_FOREACH_ENTRY() instead qlist_iter() has just three uses outside tests/. Replace by QLIST_FOREACH_ENTRY() for more concise code and less type punning. Signed-off-by: Markus Armbruster Message-Id: <20200415083048.14339-4-armbru@redhat.com> Reviewed-by: Eric Blake --- include/qapi/qmp/qlist.h | 2 -- qobject/qjson.c | 31 ++++++++++------------------ qobject/qlist.c | 44 +++++++++++----------------------------- tests/check-qlist.c | 37 +++++++++++++-------------------- 4 files changed, 37 insertions(+), 77 deletions(-) diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h index 07ecae81e4..595b7943e1 100644 --- a/include/qapi/qmp/qlist.h +++ b/include/qapi/qmp/qlist.h @@ -47,8 +47,6 @@ static inline QObject *qlist_entry_obj(const QListEntry *entry) QList *qlist_new(void); QList *qlist_copy(QList *src); void qlist_append_obj(QList *qlist, QObject *obj); -void qlist_iter(const QList *qlist, - void (*iter)(QObject *obj, void *opaque), void *opaque); QObject *qlist_pop(QList *qlist); QObject *qlist_peek(QList *qlist); int qlist_empty(const QList *qlist); diff --git a/qobject/qjson.c b/qobject/qjson.c index 87422f600d..f0eebc5fda 100644 --- a/qobject/qjson.c +++ b/qobject/qjson.c @@ -191,20 +191,6 @@ static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) s->count++; } -static void to_json_list_iter(QObject *obj, void *opaque) -{ - ToJsonIterState *s = opaque; - - if (s->count) { - qstring_append(s->str, s->pretty ? "," : ", "); - } - - json_pretty_newline(s->str, s->pretty, s->indent); - - to_json(obj, s->str, s->pretty, s->indent); - s->count++; -} - static void to_json(const QObject *obj, QString *str, int pretty, int indent) { switch (qobject_type(obj)) { @@ -289,15 +275,20 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent) break; } case QTYPE_QLIST: { - ToJsonIterState s; QList *val = qobject_to(QList, obj); + const char *comma = pretty ? "," : ", "; + const char *sep = ""; + QListEntry *entry; - s.count = 0; - s.str = str; - s.indent = indent + 1; - s.pretty = pretty; qstring_append(str, "["); - qlist_iter(val, (void *)to_json_list_iter, &s); + + QLIST_FOREACH_ENTRY(val, entry) { + qstring_append(str, sep); + json_pretty_newline(str, pretty, indent + 1); + to_json(qlist_entry_obj(entry), str, pretty, indent + 1); + sep = comma; + } + json_pretty_newline(str, pretty, indent); qstring_append(str, "]"); break; diff --git a/qobject/qlist.c b/qobject/qlist.c index b3274af88b..1be95367d1 100644 --- a/qobject/qlist.c +++ b/qobject/qlist.c @@ -34,20 +34,17 @@ QList *qlist_new(void) return qlist; } -static void qlist_copy_elem(QObject *obj, void *opaque) -{ - QList *dst = opaque; - - qobject_ref(obj); - qlist_append_obj(dst, obj); -} - QList *qlist_copy(QList *src) { QList *dst = qlist_new(); + QListEntry *entry; + QObject *elt; - qlist_iter(src, qlist_copy_elem, dst); - + QLIST_FOREACH_ENTRY(src, entry) { + elt = qlist_entry_obj(entry); + qobject_ref(elt); + qlist_append_obj(dst, elt); + } return dst; } @@ -86,21 +83,6 @@ void qlist_append_null(QList *qlist) qlist_append(qlist, qnull()); } -/** - * qlist_iter(): Iterate over all the list's stored values. - * - * This function allows the user to provide an iterator, which will be - * called for each stored value in the list. - */ -void qlist_iter(const QList *qlist, - void (*iter)(QObject *obj, void *opaque), void *opaque) -{ - QListEntry *entry; - - QTAILQ_FOREACH(entry, &qlist->head, next) - iter(entry->value, opaque); -} - QObject *qlist_pop(QList *qlist) { QListEntry *entry; @@ -137,16 +119,14 @@ int qlist_empty(const QList *qlist) return QTAILQ_EMPTY(&qlist->head); } -static void qlist_size_iter(QObject *obj, void *opaque) -{ - size_t *count = opaque; - (*count)++; -} - size_t qlist_size(const QList *qlist) { size_t count = 0; - qlist_iter(qlist, qlist_size_iter, &count); + QListEntry *entry; + + QLIST_FOREACH_ENTRY(qlist, entry) { + count++; + } return count; } diff --git a/tests/check-qlist.c b/tests/check-qlist.c index ece83e293d..3cd0ccbf19 100644 --- a/tests/check-qlist.c +++ b/tests/check-qlist.c @@ -61,40 +61,31 @@ static void qobject_to_qlist_test(void) qobject_unref(qlist); } -static int iter_called; -static const int iter_max = 42; - -static void iter_func(QObject *obj, void *opaque) -{ - QNum *qi; - int64_t val; - - g_assert(opaque == NULL); - - qi = qobject_to(QNum, obj); - g_assert(qi != NULL); - - g_assert(qnum_get_try_int(qi, &val)); - g_assert_cmpint(val, >=, 0); - g_assert_cmpint(val, <=, iter_max); - - iter_called++; -} - static void qlist_iter_test(void) { + const int iter_max = 42; int i; QList *qlist; + QListEntry *entry; + QNum *qi; + int64_t val; qlist = qlist_new(); for (i = 0; i < iter_max; i++) qlist_append_int(qlist, i); - iter_called = 0; - qlist_iter(qlist, iter_func, NULL); + i = 0; + QLIST_FOREACH_ENTRY(qlist, entry) { + qi = qobject_to(QNum, qlist_entry_obj(entry)); + g_assert(qi != NULL); - g_assert(iter_called == iter_max); + g_assert(qnum_get_try_int(qi, &val)); + g_assert_cmpint(val, ==, i); + i++; + } + + g_assert(i == iter_max); qobject_unref(qlist); } From 7b1cd1c65abad70b26fbe9b11991bd88f0d956e1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 10:30:47 +0200 Subject: [PATCH 0071/2595] qobject: Eliminate qdict_iter(), use qdict_first(), qdict_next() qdict_iter() has just three uses and no test coverage. Replace by qdict_first(), qdict_next() for more concise code and less type punning. Signed-off-by: Markus Armbruster Message-Id: <20200415083048.14339-5-armbru@redhat.com> Reviewed-by: Eric Blake --- include/qapi/qmp/qdict.h | 3 -- qapi/qobject-input-visitor.c | 21 +++++++------- qobject/qdict.c | 19 ------------- qobject/qjson.c | 54 +++++++++++++----------------------- util/qemu-option.c | 10 ++++++- 5 files changed, 40 insertions(+), 67 deletions(-) diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h index 7f3ec10a10..da942347a7 100644 --- a/include/qapi/qmp/qdict.h +++ b/include/qapi/qmp/qdict.h @@ -40,9 +40,6 @@ void qdict_del(QDict *qdict, const char *key); int qdict_haskey(const QDict *qdict, const char *key); QObject *qdict_get(const QDict *qdict, const char *key); bool qdict_is_equal(const QObject *x, const QObject *y); -void qdict_iter(const QDict *qdict, - void (*iter)(const char *key, QObject *obj, void *opaque), - void *opaque); const QDictEntry *qdict_first(const QDict *qdict); const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry); void qdict_destroy_obj(QObject *obj); diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c index 32236cbcb1..5ce3ec2e5f 100644 --- a/qapi/qobject-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -203,31 +203,32 @@ static const char *qobject_input_get_keyval(QObjectInputVisitor *qiv, return qstring_get_str(qstr); } -static void qdict_add_key(const char *key, QObject *obj, void *opaque) -{ - GHashTable *h = opaque; - g_hash_table_insert(h, (gpointer) key, NULL); -} - static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv, const char *name, QObject *obj, void *qapi) { GHashTable *h; StackObject *tos = g_new0(StackObject, 1); + QDict *qdict = qobject_to(QDict, obj); + QList *qlist = qobject_to(QList, obj); + const QDictEntry *entry; assert(obj); tos->name = name; tos->obj = obj; tos->qapi = qapi; - if (qobject_type(obj) == QTYPE_QDICT) { + if (qdict) { h = g_hash_table_new(g_str_hash, g_str_equal); - qdict_iter(qobject_to(QDict, obj), qdict_add_key, h); + for (entry = qdict_first(qdict); + entry; + entry = qdict_next(qdict, entry)) { + g_hash_table_insert(h, (void *)qdict_entry_key(entry), NULL); + } tos->h = h; } else { - assert(qobject_type(obj) == QTYPE_QLIST); - tos->entry = qlist_first(qobject_to(QList, obj)); + assert(qlist); + tos->entry = qlist_first(qlist); tos->index = -1; } diff --git a/qobject/qdict.c b/qobject/qdict.c index 3d8c2f7bbc..526de54ceb 100644 --- a/qobject/qdict.c +++ b/qobject/qdict.c @@ -298,25 +298,6 @@ const char *qdict_get_try_str(const QDict *qdict, const char *key) return qstr ? qstring_get_str(qstr) : NULL; } -/** - * qdict_iter(): Iterate over all the dictionary's stored values. - * - * This function allows the user to provide an iterator, which will be - * called for each stored value in the dictionary. - */ -void qdict_iter(const QDict *qdict, - void (*iter)(const char *key, QObject *obj, void *opaque), - void *opaque) -{ - int i; - QDictEntry *entry; - - for (i = 0; i < QDICT_BUCKET_MAX; i++) { - QLIST_FOREACH(entry, &qdict->table[i], next) - iter(entry->key, entry->value, opaque); - } -} - static QDictEntry *qdict_next_entry(const QDict *qdict, int first_bucket) { int i; diff --git a/qobject/qjson.c b/qobject/qjson.c index f0eebc5fda..f1f2c69704 100644 --- a/qobject/qjson.c +++ b/qobject/qjson.c @@ -149,14 +149,6 @@ QDict *qdict_from_jsonf_nofail(const char *string, ...) return qdict; } -typedef struct ToJsonIterState -{ - int indent; - int pretty; - int count; - QString *str; -} ToJsonIterState; - static void to_json(const QObject *obj, QString *str, int pretty, int indent); static void json_pretty_newline(QString *str, bool pretty, int indent) @@ -171,26 +163,6 @@ static void json_pretty_newline(QString *str, bool pretty, int indent) } } -static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) -{ - ToJsonIterState *s = opaque; - QString *qkey; - - if (s->count) { - qstring_append(s->str, s->pretty ? "," : ", "); - } - - json_pretty_newline(s->str, s->pretty, s->indent); - - qkey = qstring_from_str(key); - to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); - qobject_unref(qkey); - - qstring_append(s->str, ": "); - to_json(obj, s->str, s->pretty, s->indent); - s->count++; -} - static void to_json(const QObject *obj, QString *str, int pretty, int indent) { switch (qobject_type(obj)) { @@ -261,15 +233,29 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent) break; } case QTYPE_QDICT: { - ToJsonIterState s; QDict *val = qobject_to(QDict, obj); + const char *comma = pretty ? "," : ", "; + const char *sep = ""; + const QDictEntry *entry; + QString *qkey; - s.count = 0; - s.str = str; - s.indent = indent + 1; - s.pretty = pretty; qstring_append(str, "{"); - qdict_iter(val, to_json_dict_iter, &s); + + for (entry = qdict_first(val); + entry; + entry = qdict_next(val, entry)) { + qstring_append(str, sep); + json_pretty_newline(str, pretty, indent + 1); + + qkey = qstring_from_str(qdict_entry_key(entry)); + to_json(QOBJECT(qkey), str, pretty, indent + 1); + qobject_unref(qkey); + + qstring_append(str, ": "); + to_json(qdict_entry_value(entry), str, pretty, indent + 1); + sep = comma; + } + json_pretty_newline(str, pretty, indent); qstring_append(str, "}"); break; diff --git a/util/qemu-option.c b/util/qemu-option.c index 9542988183..2784757ef5 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -1013,6 +1013,7 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, OptsFromQDictState state; Error *local_err = NULL; QemuOpts *opts; + const QDictEntry *entry; opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, &local_err); @@ -1025,7 +1026,14 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, state.errp = &local_err; state.opts = opts; - qdict_iter(qdict, qemu_opts_from_qdict_1, &state); + + for (entry = qdict_first(qdict); + entry; + entry = qdict_next(qdict, entry)) { + qemu_opts_from_qdict_1(qdict_entry_key(entry), + qdict_entry_value(entry), + &state); + } if (local_err) { error_propagate(errp, local_err); qemu_opts_del(opts); From 2500f6f30b547b9c301dfe7571a16b028f7b848d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2020 10:30:48 +0200 Subject: [PATCH 0072/2595] qemu-option: Clean up after the previous commit Signed-off-by: Markus Armbruster Message-Id: <20200415083048.14339-6-armbru@redhat.com> Reviewed-by: Eric Blake --- util/qemu-option.c | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/util/qemu-option.c b/util/qemu-option.c index 2784757ef5..0ebfd97a98 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -965,18 +965,16 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params, assert(opts); } -typedef struct OptsFromQDictState { - QemuOpts *opts; - Error **errp; -} OptsFromQDictState; - -static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque) +static void qemu_opts_from_qdict_entry(QemuOpts *opts, + const QDictEntry *entry, + Error **errp) { - OptsFromQDictState *state = opaque; + const char *key = qdict_entry_key(entry); + QObject *obj = qdict_entry_value(entry); char buf[32], *tmp = NULL; const char *value; - if (!strcmp(key, "id") || *state->errp) { + if (!strcmp(key, "id")) { return; } @@ -997,7 +995,7 @@ static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque) return; } - qemu_opt_set(state->opts, key, value, state->errp); + qemu_opt_set(opts, key, value, errp); g_free(tmp); } @@ -1010,7 +1008,6 @@ static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque) QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, Error **errp) { - OptsFromQDictState state; Error *local_err = NULL; QemuOpts *opts; const QDictEntry *entry; @@ -1024,20 +1021,15 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, assert(opts != NULL); - state.errp = &local_err; - state.opts = opts; - for (entry = qdict_first(qdict); entry; entry = qdict_next(qdict, entry)) { - qemu_opts_from_qdict_1(qdict_entry_key(entry), - qdict_entry_value(entry), - &state); - } - if (local_err) { - error_propagate(errp, local_err); - qemu_opts_del(opts); - return NULL; + qemu_opts_from_qdict_entry(opts, entry, &local_err); + if (local_err) { + error_propagate(errp, local_err); + qemu_opts_del(opts); + return NULL; + } } return opts; @@ -1056,21 +1048,16 @@ void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) while (entry != NULL) { Error *local_err = NULL; - OptsFromQDictState state = { - .errp = &local_err, - .opts = opts, - }; next = qdict_next(qdict, entry); if (find_desc_by_name(opts->list->desc, entry->key)) { - qemu_opts_from_qdict_1(entry->key, entry->value, &state); + qemu_opts_from_qdict_entry(opts, entry, &local_err); if (local_err) { error_propagate(errp, local_err); return; - } else { - qdict_del(qdict, entry->key); } + qdict_del(qdict, entry->key); } entry = next; From 3777d36e674ca3b75b63413b4fb506b108309144 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:24 +0200 Subject: [PATCH 0073/2595] qapi: Belatedly update visitor.h's big comment for QAPI modules Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-2-armbru@redhat.com> --- include/qapi/visitor.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index c5b23851a1..f8a0fc1ea9 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -58,7 +58,7 @@ * * where T is FOO for scalar types, and FOO * otherwise. The scalar * visitors are declared here; the remaining visitors are generated in - * qapi-visit.h. + * qapi-visit-MODULE.h. * * The @name parameter of visit_type_FOO() describes the relation * between this QAPI value and its parent container. When visiting @@ -86,16 +86,16 @@ * by manual construction. * * For the QAPI object types (structs, unions, and alternates), there - * is an additional generated function in qapi-visit.h compatible - * with: + * is an additional generated function in qapi-visit-MODULE.h + * compatible with: * * void visit_type_FOO_members(Visitor *v, FOO *obj, Error **errp); * * for visiting the members of a type without also allocating the QAPI * struct. * - * Additionally, in qapi-types.h, all QAPI pointer types (structs, - * unions, alternates, and lists) have a generated function compatible + * Additionally, QAPI pointer types (structs, unions, alternates, and + * lists) have a generated function in qapi-types-MODULE.h compatible * with: * * void qapi_free_FOO(FOO *obj); From 294c90662ac9daae2c3bbf608296cf037925bd95 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:25 +0200 Subject: [PATCH 0074/2595] qapi: Fix the virtual walk example in visitor.h's big comment Call visit_check_list(). Missed in commit a4a1c70dc7 "qapi: Make input visitors detect unvisited list tails". Drop an irrelevant error_propagate() while there. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-3-armbru@redhat.com> --- include/qapi/visitor.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index f8a0fc1ea9..7f63e4c381 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -215,6 +215,9 @@ * goto outlist; * } * outlist: + * if (!err) { + * visit_check_list(v, &err); + * } * visit_end_list(v, NULL); * if (!err) { * visit_check_struct(v, &err); @@ -222,7 +225,6 @@ * outobj: * visit_end_struct(v, NULL); * out: - * error_propagate(errp, err); * visit_free(v); * */ From 782586c77103d297f38e78950dfbe2a31a3b2924 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:26 +0200 Subject: [PATCH 0075/2595] qapi: Fix typo in visit_start_list()'s contract Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-4-armbru@redhat.com> --- include/qapi/visitor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 7f63e4c381..c5d0ce9184 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -345,9 +345,9 @@ void visit_end_struct(Visitor *v, void **obj); * input visitors set *@list to NULL. * * After visit_start_list() succeeds, the caller may visit its members - * one after the other. A real visit (where @obj is non-NULL) uses + * one after the other. A real visit (where @list is non-NULL) uses * visit_next_list() for traversing the linked list, while a virtual - * visit (where @obj is NULL) uses other means. For each list + * visit (where @list is NULL) uses other means. For each list * element, call the appropriate visit_type_FOO() with name set to * NULL and obj set to the address of the value member of the list * element. Finally, visit_end_list() needs to be called with the From c5460d5e19b4c531e86f8be0e00ab463fae7548b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:27 +0200 Subject: [PATCH 0076/2595] qapi: Document @errp usage more thoroughly in visitor.h Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-5-armbru@redhat.com> --- include/qapi/visitor.h | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index c5d0ce9184..09df7099c6 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -284,9 +284,7 @@ void visit_free(Visitor *v); * into *@obj. @obj may also be NULL for a virtual walk, in which * case @size is ignored. * - * @errp obeys typical error usage, and reports failures such as a - * member @name is not present, or present but not an object. On - * error, input visitors set *@obj to NULL. + * On failure, set *@obj to NULL and store an error through @errp. * * After visit_start_struct() succeeds, the caller may visit its * members one after the other, passing the member's name and address @@ -303,8 +301,7 @@ void visit_start_struct(Visitor *v, const char *name, void **obj, /* * Prepare for completing an object visit. * - * @errp obeys typical error usage, and reports failures such as - * unparsed keys remaining in the input stream. + * On failure, store an error through @errp. * * Should be called prior to visit_end_struct() if all other * intermediate visit steps were successful, to allow the visitor one @@ -340,9 +337,7 @@ void visit_end_struct(Visitor *v, void **obj); * allow @list to be NULL for a virtual walk, in which case @size is * ignored. * - * @errp obeys typical error usage, and reports failures such as a - * member @name is not present, or present but not a list. On error, - * input visitors set *@list to NULL. + * On failure, set *@list to NULL and store an error through @errp. * * After visit_start_list() succeeds, the caller may visit its members * one after the other. A real visit (where @list is non-NULL) uses @@ -376,8 +371,7 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size); /* * Prepare for completing a list visit. * - * @errp obeys typical error usage, and reports failures such as - * unvisited list tail remaining in the input stream. + * On failure, store an error through @errp. * * Should be called prior to visit_end_list() if all other * intermediate visit steps were successful, to allow the visitor one @@ -409,8 +403,10 @@ void visit_end_list(Visitor *v, void **list); * * @obj must not be NULL. Input and clone visitors use @size to * determine how much memory to allocate into *@obj, then determine - * the qtype of the next thing to be visited, stored in (*@obj)->type. - * Other visitors will leave @obj unchanged. + * the qtype of the next thing to be visited, and store it in + * (*@obj)->type. Other visitors leave @obj unchanged. + * + * On failure, set *@obj to NULL and store an error through @errp. * * If successful, this must be paired with visit_end_alternate() with * the same @obj to clean up, even if visiting the contents of the @@ -463,8 +459,9 @@ bool visit_optional(Visitor *v, const char *name, bool *present); * * Currently, all input visitors parse text input, and all output * visitors produce text output. The mapping between enumeration - * values and strings is done by the visitor core, using @strings; it - * should be the ENUM_lookup array from visit-types.h. + * values and strings is done by the visitor core, using @lookup. + * + * On failure, store an error through @errp. * * May call visit_type_str() under the hood, and the enum visit may * fail even if the corresponding string visit succeeded; this implies @@ -488,6 +485,8 @@ bool visit_is_input(Visitor *v); * * @obj must be non-NULL. Input visitors set *@obj to the value; * other visitors will leave *@obj unchanged. + * + * On failure, store an error through @errp. */ void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp); @@ -564,6 +563,8 @@ void visit_type_size(Visitor *v, const char *name, uint64_t *obj, * * @obj must be non-NULL. Input visitors set *@obj to the value; * other visitors will leave *@obj unchanged. + * + * On failure, store an error through @errp. */ void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp); @@ -581,6 +582,8 @@ void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp); * It is safe to cast away const when preparing a (const char *) value * into @obj for use by an output visitor. * + * On failure, set *@obj to NULL and store an error through @errp. + * * FIXME: Callers that try to output NULL *obj should not be allowed. */ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp); @@ -594,6 +597,8 @@ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp); * @obj must be non-NULL. Input visitors set *@obj to the value; * other visitors will leave *@obj unchanged. Visitors should * document if infinity or NaN are not permitted. + * + * On failure, store an error through @errp. */ void visit_type_number(Visitor *v, const char *name, double *obj, Error **errp); @@ -608,6 +613,8 @@ void visit_type_number(Visitor *v, const char *name, double *obj, * other visitors will leave *@obj unchanged. *@obj must be non-NULL * for output visitors. * + * On failure, set *@obj to NULL and store an error through @errp. + * * Note that some kinds of input can't express arbitrary QObject. * E.g. the visitor returned by qobject_input_visitor_new_keyval() * can't create numbers or booleans, only strings. @@ -622,6 +629,8 @@ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp); * * @obj must be non-NULL. Input visitors set *@obj to the value; * other visitors ignore *@obj. + * + * On failure, set *@obj to NULL and store an error through @errp. */ void visit_type_null(Visitor *v, const char *name, QNull **obj, Error **errp); From 554d6586ae96216771fe701c9d3a321e2adb057b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:28 +0200 Subject: [PATCH 0077/2595] qapi: Polish prose in visitor.h Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-6-armbru@redhat.com> --- include/qapi/visitor.h | 104 +++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 09df7099c6..a425ea514c 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -25,19 +25,21 @@ * for doing work at each node of a QAPI graph; it can also be used * for a virtual walk, where there is no actual QAPI C struct. * - * There are four kinds of visitor classes: input visitors (QObject, - * string, and QemuOpts) parse an external representation and build - * the corresponding QAPI graph, output visitors (QObject and string) take - * a completed QAPI graph and generate an external representation, the - * dealloc visitor can take a QAPI graph (possibly partially - * constructed) and recursively free its resources, and the clone - * visitor performs a deep clone of one QAPI object to another. While - * the dealloc and QObject input/output visitors are general, the string, - * QemuOpts, and clone visitors have some implementation limitations; - * see the documentation for each visitor for more details on what it - * supports. Also, see visitor-impl.h for the callback contracts - * implemented by each visitor, and docs/devel/qapi-code-gen.txt for more - * about the QAPI code generator. + * There are four kinds of visitors: input visitors (QObject, string, + * and QemuOpts) parse an external representation and build the + * corresponding QAPI object, output visitors (QObject and string) + * take a QAPI object and generate an external representation, the + * dealloc visitor takes a QAPI object (possibly partially + * constructed) and recursively frees it, and the clone visitor + * performs a deep clone of a QAPI object. + * + * While the dealloc and QObject input/output visitors are general, + * the string, QemuOpts, and clone visitors have some implementation + * limitations; see the documentation for each visitor for more + * details on what it supports. Also, see visitor-impl.h for the + * callback contracts implemented by each visitor, and + * docs/devel/qapi-code-gen.txt for more about the QAPI code + * generator. * * All of the visitors are created via: * @@ -45,11 +47,15 @@ * * A visitor should be used for exactly one top-level visit_type_FOO() * or virtual walk; if that is successful, the caller can optionally - * call visit_complete() (for now, useful only for output visits, but - * safe to call on all visits). Then, regardless of success or - * failure, the user should call visit_free() to clean up resources. - * It is okay to free the visitor without completing the visit, if - * some other error is detected in the meantime. + * call visit_complete() (useful only for output visits, but safe to + * call on all visits). Then, regardless of success or failure, the + * user should call visit_free() to clean up resources. It is okay to + * free the visitor without completing the visit, if some other error + * is detected in the meantime. + * + * The clone and dealloc visitor should not be used directly outside + * of QAPI code. Use the qapi_free_FOO() and QAPI_CLONE() instead, + * described below. * * All QAPI types have a corresponding function with a signature * roughly compatible with this: @@ -68,22 +74,26 @@ * alternate, @name should equal the name used for visiting the * alternate. * - * The visit_type_FOO() functions expect a non-null @obj argument; - * they allocate *@obj during input visits, leave it unchanged on - * output visits, and recursively free any resources during a dealloc - * visit. Each function also takes the customary @errp argument (see + * The visit_type_FOO() functions take a non-null @obj argument; they + * allocate *@obj during input visits, leave it unchanged during + * output and clone visits, and free it (recursively) during a dealloc + * visit. + * + * Each function also takes the customary @errp argument (see * qapi/error.h for details), for reporting any errors (such as if a * member @name is not present, or is present but not the specified * type). * * If an error is detected during visit_type_FOO() with an input - * visitor, then *@obj will be NULL for pointer types, and left - * unchanged for scalar types. Using an output or clone visitor with - * an incomplete object has undefined behavior (other than a special - * case for visit_type_str() treating NULL like ""), while the dealloc - * visitor safely handles incomplete objects. Since input visitors - * never produce an incomplete object, such an object is possible only - * by manual construction. + * visitor, then *@obj will be set to NULL for pointer types, and left + * unchanged for scalar types. + * + * Using an output or clone visitor with an incomplete object has + * undefined behavior (other than a special case for visit_type_str() + * treating NULL like ""), while the dealloc visitor safely handles + * incomplete objects. Since input visitors never produce an + * incomplete object, such an object is possible only by manual + * construction. * * For the QAPI object types (structs, unions, and alternates), there * is an additional generated function in qapi-visit-MODULE.h @@ -100,23 +110,20 @@ * * void qapi_free_FOO(FOO *obj); * - * where behaves like free() in that @obj may be NULL. Such objects - * may also be used with the following macro, provided alongside the - * clone visitor: + * Does nothing when @obj is NULL. + * + * Such objects may also be used with macro * * Type *QAPI_CLONE(Type, src); * - * in order to perform a deep clone of @src. Because of the generated - * qapi_free functions and the QAPI_CLONE() macro, the clone and - * dealloc visitor should not be used directly outside of QAPI code. + * in order to perform a deep clone of @src. * - * QAPI types can also inherit from a base class; when this happens, a - * function is generated for easily going from the derived type to the - * base type: + * For QAPI types can that inherit from a base type, a function is + * generated for going from the derived type to the base type: * * BASE *qapi_CHILD_base(CHILD *obj); * - * For a real QAPI struct, typical input usage involves: + * Typical input visitor usage involves: * * * Foo *f; @@ -153,7 +160,7 @@ * qapi_free_FooList(l); * * - * Similarly, typical output usage is: + * Typical output visitor usage: * * * Foo *f = ...obtain populated object... @@ -172,17 +179,8 @@ * visit_free(v); * * - * When visiting a real QAPI struct, this file provides several - * helpers that rely on in-tree information to control the walk: - * visit_optional() for the 'has_member' field associated with - * optional 'member' in the C struct; and visit_next_list() for - * advancing through a FooList linked list. Similarly, the - * visit_is_input() helper makes it possible to write code that is - * visitor-agnostic everywhere except for cleanup. Only the generated - * visit_type functions need to use these helpers. - * * It is also possible to use the visitors to do a virtual walk, where - * no actual QAPI struct is present. In this situation, decisions + * no actual QAPI object is present. In this situation, decisions * about what needs to be walked are made by the calling code, and * structured visits are split between pairs of start and end methods * (where the end method must be called if the start function @@ -227,6 +225,12 @@ * out: * visit_free(v); * + * + * This file provides helpers for use by the generated + * visit_type_FOO(): visit_optional() for the 'has_member' field + * associated with optional 'member' in the C struct, + * visit_next_list() for advancing through a FooList linked list, and + * visit_is_input() for cleaning up on failure. */ /*** Useful types ***/ From 8e08bf4ea24c3e6e07fab2c1b5bdcc7b104012c4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:29 +0200 Subject: [PATCH 0078/2595] qapi: Assert incomplete object occurs only in dealloc visitor Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-7-armbru@redhat.com> --- docs/devel/qapi-code-gen.txt | 2 ++ include/qapi/visitor.h | 5 +++++ qapi/qapi-visit-core.c | 5 +++++ scripts/qapi/visit.py | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index 1967adfa92..c6dd1891c3 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -1446,6 +1446,8 @@ Example: goto out; } if (!*obj) { + /* incomplete */ + assert(visit_is_dealloc(v)); goto out_obj; } visit_type_UserDefOne_members(v, *obj, &err); diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index a425ea514c..2d40d2fe0f 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -479,6 +479,11 @@ void visit_type_enum(Visitor *v, const char *name, int *obj, */ bool visit_is_input(Visitor *v); +/* + * Check if visitor is a dealloc visitor. + */ +bool visit_is_dealloc(Visitor *v); + /*** Visiting built-in types ***/ /* diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 5365561b07..d4aac206cf 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -142,6 +142,11 @@ bool visit_is_input(Visitor *v) return v->type == VISITOR_INPUT; } +bool visit_is_dealloc(Visitor *v) +{ + return v->type == VISITOR_DEALLOC; +} + void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp) { assert(obj); diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index 23d9194aa4..e3467b770b 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -189,6 +189,8 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error goto out; } if (!*obj) { + /* incomplete */ + assert(visit_is_dealloc(v)); goto out_obj; } switch ((*obj)->type) { @@ -260,6 +262,8 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error goto out; } if (!*obj) { + /* incomplete */ + assert(visit_is_dealloc(v)); goto out_obj; } visit_type_%(c_name)s_members(v, *obj, &err); From 8b7ce95b46815f274aed52857260cb180f6fade3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:30 +0200 Subject: [PATCH 0079/2595] qapi: Fix Visitor contract for start_alternate() The contract demands v->start_alternate() for input and dealloc visitors, but visit_start_alternate() actually requires it for input and clone visitors. Fix the contract, and delete superfluous qapi_dealloc_start_alternate(). Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-8-armbru@redhat.com> --- include/qapi/visitor-impl.h | 5 ++--- qapi/qapi-dealloc-visitor.c | 7 ------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h index 8ccb3b6c20..252206dc0d 100644 --- a/include/qapi/visitor-impl.h +++ b/include/qapi/visitor-impl.h @@ -67,13 +67,12 @@ struct Visitor /* Must be set */ void (*end_list)(Visitor *v, void **list); - /* Must be set by input and dealloc visitors to visit alternates; - * optional for output visitors. */ + /* Must be set by input and clone visitors to visit alternates */ void (*start_alternate)(Visitor *v, const char *name, GenericAlternate **obj, size_t size, Error **errp); - /* Optional, needed for dealloc visitor */ + /* Optional */ void (*end_alternate)(Visitor *v, void **obj); /* Must be set */ diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c index d192724b13..2239fc6417 100644 --- a/qapi/qapi-dealloc-visitor.c +++ b/qapi/qapi-dealloc-visitor.c @@ -34,12 +34,6 @@ static void qapi_dealloc_end_struct(Visitor *v, void **obj) } } -static void qapi_dealloc_start_alternate(Visitor *v, const char *name, - GenericAlternate **obj, size_t size, - Error **errp) -{ -} - static void qapi_dealloc_end_alternate(Visitor *v, void **obj) { if (obj) { @@ -123,7 +117,6 @@ Visitor *qapi_dealloc_visitor_new(void) v->visitor.type = VISITOR_DEALLOC; v->visitor.start_struct = qapi_dealloc_start_struct; v->visitor.end_struct = qapi_dealloc_end_struct; - v->visitor.start_alternate = qapi_dealloc_start_alternate; v->visitor.end_alternate = qapi_dealloc_end_alternate; v->visitor.start_list = qapi_dealloc_start_list; v->visitor.next_list = qapi_dealloc_next_list; From 777d20cfa5735de298f378e9b90f0cd1caafdc2d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:31 +0200 Subject: [PATCH 0080/2595] qapi: Assert output visitors see only valid enum values output_type_enum() fails when *obj is not a valid value of the enum type. Should not happen. Drop the check, along with its unit tests. This unmasks qapi_enum_lookup()'s assertion. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-9-armbru@redhat.com> [Commit message tweaked] --- qapi/qapi-visit-core.c | 9 ------- tests/test-qobject-output-visitor.c | 39 ----------------------------- tests/test-string-output-visitor.c | 19 -------------- 3 files changed, 67 deletions(-) diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index d4aac206cf..80ca83bcb9 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -341,15 +341,6 @@ static void output_type_enum(Visitor *v, const char *name, int *obj, int value = *obj; char *enum_str; - /* - * TODO why is this an error, not an assertion? If assertion: - * delete, and rely on qapi_enum_lookup() - */ - if (value < 0 || value >= lookup->size) { - error_setg(errp, QERR_INVALID_PARAMETER, name ? name : "null"); - return; - } - enum_str = (char *)qapi_enum_lookup(lookup, value); visit_type_str(v, name, &enum_str, errp); } diff --git a/tests/test-qobject-output-visitor.c b/tests/test-qobject-output-visitor.c index d7761ebf84..1c856d9bd2 100644 --- a/tests/test-qobject-output-visitor.c +++ b/tests/test-qobject-output-visitor.c @@ -141,21 +141,6 @@ static void test_visitor_out_enum(TestOutputVisitorData *data, } } -static void test_visitor_out_enum_errors(TestOutputVisitorData *data, - const void *unused) -{ - EnumOne i, bad_values[] = { ENUM_ONE__MAX, -1 }; - - for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { - Error *err = NULL; - - visit_type_EnumOne(data->ov, "unused", &bad_values[i], &err); - error_free_or_abort(&err); - visitor_reset(data); - } -} - - static void test_visitor_out_struct(TestOutputVisitorData *data, const void *unused) { @@ -234,26 +219,6 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, qapi_free_UserDefTwo(ud2); } -static void test_visitor_out_struct_errors(TestOutputVisitorData *data, - const void *unused) -{ - EnumOne bad_values[] = { ENUM_ONE__MAX, -1 }; - UserDefOne u = {0}; - UserDefOne *pu = &u; - int i; - - for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { - Error *err = NULL; - - u.has_enum1 = true; - u.enum1 = bad_values[i]; - visit_type_UserDefOne(data->ov, "unused", &pu, &err); - error_free_or_abort(&err); - visitor_reset(data); - } -} - - static void test_visitor_out_list(TestOutputVisitorData *data, const void *unused) { @@ -821,14 +786,10 @@ int main(int argc, char **argv) &out_visitor_data, test_visitor_out_no_string); output_visitor_test_add("/visitor/output/enum", &out_visitor_data, test_visitor_out_enum); - output_visitor_test_add("/visitor/output/enum-errors", - &out_visitor_data, test_visitor_out_enum_errors); output_visitor_test_add("/visitor/output/struct", &out_visitor_data, test_visitor_out_struct); output_visitor_test_add("/visitor/output/struct-nested", &out_visitor_data, test_visitor_out_struct_nested); - output_visitor_test_add("/visitor/output/struct-errors", - &out_visitor_data, test_visitor_out_struct_errors); output_visitor_test_add("/visitor/output/list", &out_visitor_data, test_visitor_out_list); output_visitor_test_add("/visitor/output/any", diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c index 1be1540767..3bd732222c 100644 --- a/tests/test-string-output-visitor.c +++ b/tests/test-string-output-visitor.c @@ -203,19 +203,6 @@ static void test_visitor_out_enum(TestOutputVisitorData *data, } } -static void test_visitor_out_enum_errors(TestOutputVisitorData *data, - const void *unused) -{ - EnumOne i, bad_values[] = { ENUM_ONE__MAX, -1 }; - - for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { - Error *err = NULL; - - visit_type_EnumOne(data->ov, "unused", &bad_values[i], &err); - error_free_or_abort(&err); - } -} - static void output_visitor_test_add(const char *testpath, TestOutputVisitorData *data, @@ -260,12 +247,6 @@ int main(int argc, char **argv) &out_visitor_data, test_visitor_out_enum, false); output_visitor_test_add("/string-visitor/output/enum-human", &out_visitor_data, test_visitor_out_enum, true); - output_visitor_test_add("/string-visitor/output/enum-errors", - &out_visitor_data, test_visitor_out_enum_errors, - false); - output_visitor_test_add("/string-visitor/output/enum-errors-human", - &out_visitor_data, test_visitor_out_enum_errors, - true); output_visitor_test_add("/string-visitor/output/intList", &out_visitor_data, test_visitor_out_intList, false); output_visitor_test_add("/string-visitor/output/intList-human", From faad584adb48737aa3b39984786442a1a9c42aa4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:32 +0200 Subject: [PATCH 0081/2595] qapi: Assert non-input visitors see only valid narrow integers visit_type_intN() and visit_type_uintN() fail when the value is out of bounds. This is appropriate with an input visitor: the value comes from input, and input may be bad. It should never happen with the other visitors: the value comes from the caller, and callers must keep it within bounds. Assert that. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-10-armbru@redhat.com> --- qapi/qapi-visit-core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 80ca83bcb9..74aa9c04bd 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -160,10 +160,13 @@ static void visit_type_uintN(Visitor *v, uint64_t *obj, const char *name, Error *err = NULL; uint64_t value = *obj; + assert(v->type == VISITOR_INPUT || value <= max); + v->type_uint64(v, name, &value, &err); if (err) { error_propagate(errp, err); } else if (value > max) { + assert(v->type == VISITOR_INPUT); error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", type); } else { @@ -219,10 +222,13 @@ static void visit_type_intN(Visitor *v, int64_t *obj, const char *name, Error *err = NULL; int64_t value = *obj; + assert(v->type == VISITOR_INPUT || (value >= min && value <= max)); + v->type_int64(v, name, &value, &err); if (err) { error_propagate(errp, err); } else if (value < min || value > max) { + assert(v->type == VISITOR_INPUT); error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", type); } else { From c978bd5226f1ed73456ac468a7ed50af3d24dc84 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:33 +0200 Subject: [PATCH 0082/2595] qapi: Clean up visitor's recovery from input with invalid type An alternate type's visit_type_FOO() fails when it runs into an invalid ->type. If it's an input visit, we then need to free the the object we got from visit_start_alternate(). We do that with qapi_free_FOO(), which uses the dealloc visitor. Trouble is that object is in a bad state: its ->type is invalid. So the dealloc visitor will run into the same error again, and the error recovery skips deallocating the alternate's (invalid) alternative. Works, because qapi_free_FOO() ignores the error. Avoid it instead: free the messed up object with by g_free(). Signed-off-by: Markus Armbruster Message-Id: <20200424084338.26803-11-armbru@redhat.com> Reviewed-by: Eric Blake --- scripts/qapi/visit.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index e3467b770b..678109dfb5 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -234,6 +234,9 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error default: error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "%(name)s"); + /* Avoid passing invalid *obj to qapi_free_%(c_name)s() */ + g_free(*obj); + *obj = NULL; } out_obj: visit_end_alternate(v, (void **)obj); From 7111a86e1ba23ff8d59886df03d8a1cd6c5aab43 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:34 +0200 Subject: [PATCH 0083/2595] qapi: Assert non-input visitors see only valid alternate tags An alternate type's visit_type_FOO() fails when it runs into an invalid ->type. This is appropriate with an input visitor: visit_start_alternate() sets ->type according to the input, and bad input can lead to bad ->type. It should never happen with an output, clone or dealloc visitor: if it did, the alternate being output, cloned or deallocated would be messed up beyond repair. Assert that. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-12-armbru@redhat.com> --- scripts/qapi/visit.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index 678109dfb5..d5d7a1031f 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -232,6 +232,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error case QTYPE_NONE: abort(); default: + assert(visit_is_input(v)); error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "%(name)s"); /* Avoid passing invalid *obj to qapi_free_%(c_name)s() */ From 1f5842487ad5b3d59ea32742e30dc7441f413e6c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:35 +0200 Subject: [PATCH 0084/2595] qapi: Only input visitors can actually fail The previous few commits have made this more obvious, and removed the one exception. Time to clarify the documentation, and drop dead error checking. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-13-armbru@redhat.com> --- block.c | 9 +-------- block/sheepdog.c | 9 +-------- blockdev.c | 16 ++------------- hw/core/machine-hmp-cmds.c | 2 +- include/qapi/visitor-impl.h | 4 ++++ include/qapi/visitor.h | 40 ++++++++++++++++++++++--------------- monitor/hmp-cmds.c | 3 ++- 7 files changed, 35 insertions(+), 48 deletions(-) diff --git a/block.c b/block.c index 2e3905c99e..c11385ae05 100644 --- a/block.c +++ b/block.c @@ -2982,7 +2982,6 @@ BdrvChild *bdrv_open_child(const char *filename, BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) { BlockDriverState *bs = NULL; - Error *local_err = NULL; QObject *obj = NULL; QDict *qdict = NULL; const char *reference = NULL; @@ -2995,11 +2994,7 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) assert(ref->type == QTYPE_QDICT); v = qobject_output_visitor_new(&obj); - visit_type_BlockdevOptions(v, NULL, &options, &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto fail; - } + visit_type_BlockdevOptions(v, NULL, &options, &error_abort); visit_complete(v, &obj); qdict = qobject_to(QDict, obj); @@ -3017,8 +3012,6 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp); obj = NULL; - -fail: qobject_unref(obj); visit_free(v); return bs; diff --git a/block/sheepdog.c b/block/sheepdog.c index 59f7ebb171..5f3aead038 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1854,19 +1854,12 @@ static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size, Visitor *v; QObject *obj = NULL; QDict *qdict; - Error *local_err = NULL; int ret; v = qobject_output_visitor_new(&obj); - visit_type_BlockdevOptionsSheepdog(v, NULL, &location, &local_err); + visit_type_BlockdevOptionsSheepdog(v, NULL, &location, &error_abort); visit_free(v); - if (local_err) { - error_propagate(errp, local_err); - qobject_unref(obj); - return -EINVAL; - } - qdict = qobject_to(QDict, obj); qdict_flatten(qdict); diff --git a/blockdev.c b/blockdev.c index 5faddaa705..9da960b1e7 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3725,14 +3725,8 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) QObject *obj; Visitor *v = qobject_output_visitor_new(&obj); QDict *qdict; - Error *local_err = NULL; - - visit_type_BlockdevOptions(v, NULL, &options, &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto fail; - } + visit_type_BlockdevOptions(v, NULL, &options, &error_abort); visit_complete(v, &obj); qdict = qobject_to(QDict, obj); @@ -3760,7 +3754,6 @@ void qmp_x_blockdev_reopen(BlockdevOptions *options, Error **errp) AioContext *ctx; QObject *obj; Visitor *v = qobject_output_visitor_new(&obj); - Error *local_err = NULL; BlockReopenQueue *queue; QDict *qdict; @@ -3777,12 +3770,7 @@ void qmp_x_blockdev_reopen(BlockdevOptions *options, Error **errp) } /* Put all options in a QDict and flatten it */ - visit_type_BlockdevOptions(v, NULL, &options, &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto fail; - } - + visit_type_BlockdevOptions(v, NULL, &options, &error_abort); visit_complete(v, &obj); qdict = qobject_to(QDict, obj); diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c index b76f7223af..39999c47c5 100644 --- a/hw/core/machine-hmp-cmds.c +++ b/hw/core/machine-hmp-cmds.c @@ -113,7 +113,7 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict) while (m) { v = string_output_visitor_new(false, &str); - visit_type_uint16List(v, NULL, &m->value->host_nodes, NULL); + visit_type_uint16List(v, NULL, &m->value->host_nodes, &error_abort); monitor_printf(mon, "memory backend: %s\n", m->value->id); monitor_printf(mon, " size: %" PRId64 "\n", m->value->size); monitor_printf(mon, " merge: %s\n", diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h index 252206dc0d..98dc533d39 100644 --- a/include/qapi/visitor-impl.h +++ b/include/qapi/visitor-impl.h @@ -43,6 +43,10 @@ typedef enum VisitorType { struct Visitor { + /* + * Only input visitors may fail! + */ + /* Must be set to visit structs */ void (*start_struct)(Visitor *v, const char *name, void **obj, size_t size, Error **errp); diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 2d40d2fe0f..5573906966 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -82,7 +82,7 @@ * Each function also takes the customary @errp argument (see * qapi/error.h for details), for reporting any errors (such as if a * member @name is not present, or is present but not the specified - * type). + * type). Only input visitors can fail. * * If an error is detected during visit_type_FOO() with an input * visitor, then *@obj will be set to NULL for pointer types, and left @@ -164,19 +164,14 @@ * * * Foo *f = ...obtain populated object... - * Error *err = NULL; * Visitor *v; * Type *result; * * v = FOO_visitor_new(..., &result); - * visit_type_Foo(v, NULL, &f, &err); - * if (err) { - * ...handle error... - * } else { - * visit_complete(v, &result); - * ...use result... - * } + * visit_type_Foo(v, NULL, &f, &error_abort); + * visit_complete(v, &result); * visit_free(v); + * ...use result... * * * It is also possible to use the visitors to do a virtual walk, where @@ -289,6 +284,7 @@ void visit_free(Visitor *v); * case @size is ignored. * * On failure, set *@obj to NULL and store an error through @errp. + * Can happen only when @v is an input visitor. * * After visit_start_struct() succeeds, the caller may visit its * members one after the other, passing the member's name and address @@ -305,7 +301,8 @@ void visit_start_struct(Visitor *v, const char *name, void **obj, /* * Prepare for completing an object visit. * - * On failure, store an error through @errp. + * On failure, store an error through @errp. Can happen only when @v + * is an input visitor. * * Should be called prior to visit_end_struct() if all other * intermediate visit steps were successful, to allow the visitor one @@ -342,6 +339,7 @@ void visit_end_struct(Visitor *v, void **obj); * ignored. * * On failure, set *@list to NULL and store an error through @errp. + * Can happen only when @v is an input visitor. * * After visit_start_list() succeeds, the caller may visit its members * one after the other. A real visit (where @list is non-NULL) uses @@ -375,7 +373,8 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size); /* * Prepare for completing a list visit. * - * On failure, store an error through @errp. + * On failure, store an error through @errp. Can happen only when @v + * is an input visitor. * * Should be called prior to visit_end_list() if all other * intermediate visit steps were successful, to allow the visitor one @@ -411,6 +410,7 @@ void visit_end_list(Visitor *v, void **list); * (*@obj)->type. Other visitors leave @obj unchanged. * * On failure, set *@obj to NULL and store an error through @errp. + * Can happen only when @v is an input visitor. * * If successful, this must be paired with visit_end_alternate() with * the same @obj to clean up, even if visiting the contents of the @@ -465,11 +465,13 @@ bool visit_optional(Visitor *v, const char *name, bool *present); * visitors produce text output. The mapping between enumeration * values and strings is done by the visitor core, using @lookup. * - * On failure, store an error through @errp. + * On failure, store an error through @errp. Can happen only when @v + * is an input visitor. * * May call visit_type_str() under the hood, and the enum visit may * fail even if the corresponding string visit succeeded; this implies - * that visit_type_str() must have no unwelcome side effects. + * that an input visitor's visit_type_str() must have no unwelcome + * side effects. */ void visit_type_enum(Visitor *v, const char *name, int *obj, const QEnumLookup *lookup, Error **errp); @@ -495,7 +497,8 @@ bool visit_is_dealloc(Visitor *v); * @obj must be non-NULL. Input visitors set *@obj to the value; * other visitors will leave *@obj unchanged. * - * On failure, store an error through @errp. + * On failure, store an error through @errp. Can happen only when @v + * is an input visitor. */ void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp); @@ -573,7 +576,8 @@ void visit_type_size(Visitor *v, const char *name, uint64_t *obj, * @obj must be non-NULL. Input visitors set *@obj to the value; * other visitors will leave *@obj unchanged. * - * On failure, store an error through @errp. + * On failure, store an error through @errp. Can happen only when @v + * is an input visitor. */ void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp); @@ -592,6 +596,7 @@ void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp); * into @obj for use by an output visitor. * * On failure, set *@obj to NULL and store an error through @errp. + * Can happen only when @v is an input visitor. * * FIXME: Callers that try to output NULL *obj should not be allowed. */ @@ -607,7 +612,8 @@ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp); * other visitors will leave *@obj unchanged. Visitors should * document if infinity or NaN are not permitted. * - * On failure, store an error through @errp. + * On failure, store an error through @errp. Can happen only when @v + * is an input visitor. */ void visit_type_number(Visitor *v, const char *name, double *obj, Error **errp); @@ -623,6 +629,7 @@ void visit_type_number(Visitor *v, const char *name, double *obj, * for output visitors. * * On failure, set *@obj to NULL and store an error through @errp. + * Can happen only when @v is an input visitor. * * Note that some kinds of input can't express arbitrary QObject. * E.g. the visitor returned by qobject_input_visitor_new_keyval() @@ -640,6 +647,7 @@ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp); * other visitors ignore *@obj. * * On failure, set *@obj to NULL and store an error through @errp. + * Can happen only when @v is an input visitor. */ void visit_type_null(Visitor *v, const char *name, QNull **obj, Error **errp); diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 9b94e67879..7f6e982dc8 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -334,7 +334,8 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) Visitor *v; char *str; v = string_output_visitor_new(false, &str); - visit_type_uint32List(v, NULL, &info->postcopy_vcpu_blocktime, NULL); + visit_type_uint32List(v, NULL, &info->postcopy_vcpu_blocktime, + &error_abort); visit_complete(v, &str); monitor_printf(mon, "postcopy vcpu blocktime: %s\n", str); g_free(str); From ea097dff0f011c07202ea7e52a421429e01ef351 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:36 +0200 Subject: [PATCH 0085/2595] qom: Simplify object_property_get_enum() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200424084338.26803-14-armbru@redhat.com> --- qom/object.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/qom/object.c b/qom/object.c index 1812f79224..be700e831f 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1550,11 +1550,9 @@ int object_property_get_enum(Object *obj, const char *name, } visit_complete(v, &str); visit_free(v); - v = string_input_visitor_new(str); - visit_type_enum(v, name, &ret, enumprop->lookup, errp); + ret = qapi_enum_parse(enumprop->lookup, str, -1, errp); g_free(str); - visit_free(v); return ret; } From 2061487bdba7fb9077efc09210224b42fad7d18f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:37 +0200 Subject: [PATCH 0086/2595] qapi: Disallow qmp_marshal_FOO(NULL, ...) For QMP commands without arguments, gen_marshal() laboriously generates a qmp_marshal_FOO() that copes with null @args. Turns there's just one caller that passes null instead of an empty QDict. Adjust that caller, and simplify gen_marshal(). Signed-off-by: Markus Armbruster Message-Id: <20200424084338.26803-15-armbru@redhat.com> Reviewed-by: Eric Blake --- docs/devel/qapi-code-gen.txt | 2 +- monitor/qmp.c | 5 ++++- scripts/qapi/commands.py | 26 ++------------------------ 3 files changed, 7 insertions(+), 26 deletions(-) diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index c6dd1891c3..a7794ef658 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -1579,8 +1579,8 @@ Example: void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp) { Error *err = NULL; - UserDefOne *retval; Visitor *v; + UserDefOne *retval; q_obj_my_command_arg arg = {0}; v = qobject_input_visitor_new(QOBJECT(args)); diff --git a/monitor/qmp.c b/monitor/qmp.c index f89e7daf27..d433ceae5b 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -322,9 +322,12 @@ static QDict *qmp_greeting(MonitorQMP *mon) { QList *cap_list = qlist_new(); QObject *ver = NULL; + QDict *args; QMPCapability cap; - qmp_marshal_query_version(NULL, &ver, NULL); + args = qdict_new(); + qmp_marshal_query_version(args, &ver, NULL); + qobject_unref(args); for (cap = 0; cap < QMP_CAPABILITY__MAX; cap++) { if (mon->capab_offered[cap]) { diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index bc30876c88..f545903567 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -104,6 +104,7 @@ def gen_marshal(name, arg_type, boxed, ret_type): %(proto)s { Error *err = NULL; + Visitor *v; ''', proto=build_marshal_proto(name)) @@ -117,21 +118,14 @@ def gen_marshal(name, arg_type, boxed, ret_type): visit_members = ('visit_type_%s_members(v, &arg, &err);' % arg_type.c_name()) ret += mcgen(''' - Visitor *v; %(c_name)s arg = {0}; - ''', c_name=arg_type.c_name()) else: visit_members = '' - ret += mcgen(''' - Visitor *v = NULL; - - if (args) { -''') - push_indent() ret += mcgen(''' + v = qobject_input_visitor_new(QOBJECT(args)); visit_start_struct(v, NULL, NULL, 0, &err); if (err) { @@ -148,12 +142,6 @@ def gen_marshal(name, arg_type, boxed, ret_type): ''', visit_members=visit_members) - if not have_args: - pop_indent() - ret += mcgen(''' - } -''') - ret += gen_call(name, arg_type, boxed, ret_type) ret += mcgen(''' @@ -168,10 +156,6 @@ out: % arg_type.c_name()) else: visit_members = '' - ret += mcgen(''' - if (args) { -''') - push_indent() ret += mcgen(''' v = qapi_dealloc_visitor_new(); @@ -182,12 +166,6 @@ out: ''', visit_members=visit_members) - if not have_args: - pop_indent() - ret += mcgen(''' - } -''') - ret += mcgen(''' } ''') From 89bf68f933393a1bc0de4d07b59ffa8920da130f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2020 10:43:38 +0200 Subject: [PATCH 0087/2595] qapi: Generate simpler marshalling code when no arguments When command FOO has no arguments, its generated qmp_marshal_FOO() is a bit confusing. Make it simpler: visit_start_struct(v, NULL, NULL, 0, &err); if (err) { goto out; } - - if (!err) { - visit_check_struct(v, &err); - } + visit_check_struct(v, &err); visit_end_struct(v, NULL); if (err) { goto out; } Signed-off-by: Markus Armbruster Message-Id: <20200424084338.26803-16-armbru@redhat.com> Reviewed-by: Eric Blake --- scripts/qapi/commands.py | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index f545903567..6809b0fb6e 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -115,14 +115,10 @@ def gen_marshal(name, arg_type, boxed, ret_type): c_type=ret_type.c_type()) if have_args: - visit_members = ('visit_type_%s_members(v, &arg, &err);' - % arg_type.c_name()) ret += mcgen(''' %(c_name)s arg = {0}; ''', c_name=arg_type.c_name()) - else: - visit_members = '' ret += mcgen(''' @@ -131,16 +127,27 @@ def gen_marshal(name, arg_type, boxed, ret_type): if (err) { goto out; } - %(visit_members)s +''') + + if have_args: + ret += mcgen(''' + visit_type_%(c_arg_type)s_members(v, &arg, &err); if (!err) { visit_check_struct(v, &err); } +''', + c_arg_type=arg_type.c_name()) + else: + ret += mcgen(''' + visit_check_struct(v, &err); +''') + + ret += mcgen(''' visit_end_struct(v, NULL); if (err) { goto out; } -''', - visit_members=visit_members) +''') ret += gen_call(name, arg_type, boxed, ret_type) @@ -151,20 +158,21 @@ out: visit_free(v); ''') - if have_args: - visit_members = ('visit_type_%s_members(v, &arg, NULL);' - % arg_type.c_name()) - else: - visit_members = '' - ret += mcgen(''' v = qapi_dealloc_visitor_new(); visit_start_struct(v, NULL, NULL, 0, NULL); - %(visit_members)s +''') + + if have_args: + ret += mcgen(''' + visit_type_%(c_arg_type)s_members(v, &arg, NULL); +''', + c_arg_type=arg_type.c_name()) + + ret += mcgen(''' visit_end_struct(v, NULL); visit_free(v); -''', - visit_members=visit_members) +''') ret += mcgen(''' } From 1ee1bd28fcce858e6f51d2d1d6ef9048bc254b86 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 30 Oct 2019 13:49:14 +0100 Subject: [PATCH 0088/2595] target/microblaze: Add the opcode-0x0-illegal CPU property Add the opcode-0x0-illegal CPU property to control if the core should trap opcode zero as illegal. Reviewed-by: Alistair Francis Reviewed-by: Luc Michel Signed-off-by: Edgar E. Iglesias --- target/microblaze/cpu.c | 6 +++++- target/microblaze/cpu.h | 1 + target/microblaze/translate.c | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index c9cf2364ca..418a0cd1fa 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -206,7 +206,9 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) (cpu->cfg.dopb_bus_exception ? PVR2_DOPB_BUS_EXC_MASK : 0) | (cpu->cfg.iopb_bus_exception ? - PVR2_IOPB_BUS_EXC_MASK : 0); + PVR2_IOPB_BUS_EXC_MASK : 0) | + (cpu->cfg.opcode_0_illegal ? + PVR2_OPCODE_0x0_ILL_MASK : 0); env->pvr.regs[5] |= cpu->cfg.dcache_writeback ? PVR5_DCACHE_WRITEBACK_MASK : 0; @@ -274,6 +276,8 @@ static Property mb_properties[] = { /* Enables bus exceptions on failed instruction fetches. */ DEFINE_PROP_BOOL("iopb-bus-exception", MicroBlazeCPU, cfg.iopb_bus_exception, false), + DEFINE_PROP_BOOL("opcode-0x0-illegal", MicroBlazeCPU, + cfg.opcode_0_illegal, false), DEFINE_PROP_STRING("version", MicroBlazeCPU, cfg.version), DEFINE_PROP_UINT8("pvr", MicroBlazeCPU, cfg.pvr, C_PVR_FULL), DEFINE_PROP_END_OF_LIST(), diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 1a700a880c..d51587b342 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -303,6 +303,7 @@ struct MicroBlazeCPU { bool endi; bool dopb_bus_exception; bool iopb_bus_exception; + bool opcode_0_illegal; char *version; uint8_t pvr; } cfg; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 37a844db99..222632b670 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1573,7 +1573,7 @@ static inline void decode(DisasContext *dc, uint32_t ir) LOG_DIS("%8.8x\t", dc->ir); if (ir == 0) { - trap_illegal(dc, dc->cpu->env.pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK); + trap_illegal(dc, dc->cpu->cfg.opcode_0_illegal); /* Don't decode nop/zero instructions any further. */ return; } From 5143fdf36f78bd4c11c4bacedfdbd44365aa5781 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 30 Oct 2019 13:55:08 +0100 Subject: [PATCH 0089/2595] target/microblaze: Add the ill-opcode-exception property Add the ill-opcode-exception property to control if illegal instructions will raise exceptions. Reviewed-by: Alistair Francis Reviewed-by: Luc Michel Signed-off-by: Edgar E. Iglesias --- target/microblaze/cpu.c | 4 ++++ target/microblaze/cpu.h | 1 + target/microblaze/translate.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 418a0cd1fa..2cc6b1513c 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -207,6 +207,8 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) PVR2_DOPB_BUS_EXC_MASK : 0) | (cpu->cfg.iopb_bus_exception ? PVR2_IOPB_BUS_EXC_MASK : 0) | + (cpu->cfg.illegal_opcode_exception ? + PVR2_ILL_OPCODE_EXC_MASK : 0) | (cpu->cfg.opcode_0_illegal ? PVR2_OPCODE_0x0_ILL_MASK : 0); @@ -276,6 +278,8 @@ static Property mb_properties[] = { /* Enables bus exceptions on failed instruction fetches. */ DEFINE_PROP_BOOL("iopb-bus-exception", MicroBlazeCPU, cfg.iopb_bus_exception, false), + DEFINE_PROP_BOOL("ill-opcode-exception", MicroBlazeCPU, + cfg.illegal_opcode_exception, false), DEFINE_PROP_BOOL("opcode-0x0-illegal", MicroBlazeCPU, cfg.opcode_0_illegal, false), DEFINE_PROP_STRING("version", MicroBlazeCPU, cfg.version), diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index d51587b342..71d7317a58 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -303,6 +303,7 @@ struct MicroBlazeCPU { bool endi; bool dopb_bus_exception; bool iopb_bus_exception; + bool illegal_opcode_exception; bool opcode_0_illegal; char *version; uint8_t pvr; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 222632b670..b4a78551ef 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -185,7 +185,7 @@ static void write_carryi(DisasContext *dc, bool carry) static bool trap_illegal(DisasContext *dc, bool cond) { if (cond && (dc->tb_flags & MSR_EE_FLAG) - && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) { + && dc->cpu->cfg.illegal_opcode_exception) { tcg_gen_movi_i64(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP); t_gen_raise_exception(dc, EXCP_HW_EXCP); } From 622cc7305cdfe2402950d21bc2160a76646bf259 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 30 Oct 2019 14:03:38 +0100 Subject: [PATCH 0090/2595] target/microblaze: Add the div-zero-exception property Add the div-zero-exception property to control if the core traps divizions by zero. Reviewed-by: Alistair Francis Reviewed-by: Luc Michel Signed-off-by: Edgar E. Iglesias --- target/microblaze/cpu.c | 4 ++++ target/microblaze/cpu.h | 1 + target/microblaze/op_helper.c | 5 +++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 2cc6b1513c..4211f50c11 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -207,6 +207,8 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) PVR2_DOPB_BUS_EXC_MASK : 0) | (cpu->cfg.iopb_bus_exception ? PVR2_IOPB_BUS_EXC_MASK : 0) | + (cpu->cfg.div_zero_exception ? + PVR2_DIV_ZERO_EXC_MASK : 0) | (cpu->cfg.illegal_opcode_exception ? PVR2_ILL_OPCODE_EXC_MASK : 0) | (cpu->cfg.opcode_0_illegal ? @@ -280,6 +282,8 @@ static Property mb_properties[] = { cfg.iopb_bus_exception, false), DEFINE_PROP_BOOL("ill-opcode-exception", MicroBlazeCPU, cfg.illegal_opcode_exception, false), + DEFINE_PROP_BOOL("div-zero-exception", MicroBlazeCPU, + cfg.div_zero_exception, false), DEFINE_PROP_BOOL("opcode-0x0-illegal", MicroBlazeCPU, cfg.opcode_0_illegal, false), DEFINE_PROP_STRING("version", MicroBlazeCPU, cfg.version), diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 71d7317a58..3c07f9b3f7 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -305,6 +305,7 @@ struct MicroBlazeCPU { bool iopb_bus_exception; bool illegal_opcode_exception; bool opcode_0_illegal; + bool div_zero_exception; char *version; uint8_t pvr; } cfg; diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 18677ddfca..f3b17a95b3 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -132,11 +132,12 @@ uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf) static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b) { + MicroBlazeCPU *cpu = env_archcpu(env); + if (b == 0) { env->sregs[SR_MSR] |= MSR_DZ; - if ((env->sregs[SR_MSR] & MSR_EE) - && !(env->pvr.regs[2] & PVR2_DIV_ZERO_EXC_MASK)) { + if ((env->sregs[SR_MSR] & MSR_EE) && cpu->cfg.div_zero_exception) { env->sregs[SR_ESR] = ESR_EC_DIVZERO; helper_raise_exception(env, EXCP_HW_EXCP); } From 1507e5f62e047fb78700f3e14c988d16a3a52ead Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 30 Oct 2019 14:09:37 +0100 Subject: [PATCH 0091/2595] target/microblaze: Add the unaligned-exceptions property Add the unaligned-exceptions property to control if the core traps unaligned memory accesses. Reviewed-by: Alistair Francis Reviewed-by: Luc Michel Signed-off-by: Edgar E. Iglesias --- target/microblaze/cpu.c | 4 ++++ target/microblaze/cpu.h | 1 + target/microblaze/translate.c | 4 ++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 4211f50c11..585e60e817 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -211,6 +211,8 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) PVR2_DIV_ZERO_EXC_MASK : 0) | (cpu->cfg.illegal_opcode_exception ? PVR2_ILL_OPCODE_EXC_MASK : 0) | + (cpu->cfg.unaligned_exceptions ? + PVR2_UNALIGNED_EXC_MASK : 0) | (cpu->cfg.opcode_0_illegal ? PVR2_OPCODE_0x0_ILL_MASK : 0); @@ -284,6 +286,8 @@ static Property mb_properties[] = { cfg.illegal_opcode_exception, false), DEFINE_PROP_BOOL("div-zero-exception", MicroBlazeCPU, cfg.div_zero_exception, false), + DEFINE_PROP_BOOL("unaligned-exceptions", MicroBlazeCPU, + cfg.unaligned_exceptions, false), DEFINE_PROP_BOOL("opcode-0x0-illegal", MicroBlazeCPU, cfg.opcode_0_illegal, false), DEFINE_PROP_STRING("version", MicroBlazeCPU, cfg.version), diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 3c07f9b3f7..ef9081db40 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -306,6 +306,7 @@ struct MicroBlazeCPU { bool illegal_opcode_exception; bool opcode_0_illegal; bool div_zero_exception; + bool unaligned_exceptions; char *version; uint8_t pvr; } cfg; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index b4a78551ef..20b7427811 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -995,7 +995,7 @@ static void dec_load(DisasContext *dc) v = tcg_temp_new_i32(); tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); - if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) { + if (dc->cpu->cfg.unaligned_exceptions && size > 1) { TCGv_i32 t0 = tcg_const_i32(0); TCGv_i32 treg = tcg_const_i32(dc->rd); TCGv_i32 tsize = tcg_const_i32(size - 1); @@ -1110,7 +1110,7 @@ static void dec_store(DisasContext *dc) tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop); /* Verify alignment if needed. */ - if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) { + if (dc->cpu->cfg.unaligned_exceptions && size > 1) { TCGv_i32 t1 = tcg_const_i32(1); TCGv_i32 treg = tcg_const_i32(dc->rd); TCGv_i32 tsize = tcg_const_i32(size - 1); From c97673258c1f7e54260842cd0b01d24e82dd6220 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 30 Oct 2019 14:15:46 +0100 Subject: [PATCH 0092/2595] target/microblaze: Add the pvr-user1 property Add the pvr-user1 property to control the user-defined PVR0 User1 field. Reviewed-by: Alistair Francis Reviewed-by: Luc Michel Signed-off-by: Edgar E. Iglesias --- target/microblaze/cpu.c | 4 +++- target/microblaze/cpu.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 585e60e817..df5ee21dd6 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -193,7 +193,8 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) (cpu->cfg.use_mmu ? PVR0_USE_MMU_MASK : 0) | (cpu->cfg.endi ? PVR0_ENDI_MASK : 0) | (version_code << PVR0_VERSION_SHIFT) | - (cpu->cfg.pvr == C_PVR_FULL ? PVR0_PVR_FULL_MASK : 0); + (cpu->cfg.pvr == C_PVR_FULL ? PVR0_PVR_FULL_MASK : 0) | + cpu->cfg.pvr_user1; env->pvr.regs[2] |= (cpu->cfg.use_fpu ? PVR2_USE_FPU_MASK : 0) | (cpu->cfg.use_fpu > 1 ? PVR2_USE_FPU2_MASK : 0) | @@ -292,6 +293,7 @@ static Property mb_properties[] = { cfg.opcode_0_illegal, false), DEFINE_PROP_STRING("version", MicroBlazeCPU, cfg.version), DEFINE_PROP_UINT8("pvr", MicroBlazeCPU, cfg.pvr, C_PVR_FULL), + DEFINE_PROP_UINT8("pvr-user1", MicroBlazeCPU, cfg.pvr_user1, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index ef9081db40..7bb5a3d6c6 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -307,6 +307,7 @@ struct MicroBlazeCPU { bool opcode_0_illegal; bool div_zero_exception; bool unaligned_exceptions; + uint8_t pvr_user1; char *version; uint8_t pvr; } cfg; From 3ed43b5031ed2d7ef501bb81b87caed960218461 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 30 Oct 2019 14:22:15 +0100 Subject: [PATCH 0093/2595] target/microblaze: Add the pvr-user2 property Add the pvr-user2 property to control the user-defined PVR1 User2 register. Reviewed-by: Alistair Francis Reviewed-by: Luc Michel Signed-off-by: Edgar E. Iglesias --- target/microblaze/cpu.c | 2 ++ target/microblaze/cpu.h | 1 + 2 files changed, 3 insertions(+) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index df5ee21dd6..aa9983069a 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -196,6 +196,7 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) (cpu->cfg.pvr == C_PVR_FULL ? PVR0_PVR_FULL_MASK : 0) | cpu->cfg.pvr_user1; + env->pvr.regs[1] = cpu->cfg.pvr_user2; env->pvr.regs[2] |= (cpu->cfg.use_fpu ? PVR2_USE_FPU_MASK : 0) | (cpu->cfg.use_fpu > 1 ? PVR2_USE_FPU2_MASK : 0) | (cpu->cfg.use_hw_mul ? PVR2_USE_HW_MUL_MASK : 0) | @@ -294,6 +295,7 @@ static Property mb_properties[] = { DEFINE_PROP_STRING("version", MicroBlazeCPU, cfg.version), DEFINE_PROP_UINT8("pvr", MicroBlazeCPU, cfg.pvr, C_PVR_FULL), DEFINE_PROP_UINT8("pvr-user1", MicroBlazeCPU, cfg.pvr_user1, 0), + DEFINE_PROP_UINT32("pvr-user2", MicroBlazeCPU, cfg.pvr_user2, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 7bb5a3d6c6..a31134b65c 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -308,6 +308,7 @@ struct MicroBlazeCPU { bool div_zero_exception; bool unaligned_exceptions; uint8_t pvr_user1; + uint32_t pvr_user2; char *version; uint8_t pvr; } cfg; From dac717da679938d52be05c8232cd818e7902796c Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Sat, 4 Apr 2020 14:27:17 +0200 Subject: [PATCH 0094/2595] dma/xlnx-zdma: Fix descriptor loading (MEM) wrt endianness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix descriptor loading from memory wrt host endianness. Reported-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Reviewed-by: Francisco Iglesias Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200404122718.25111-2-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/dma/xlnx-zdma.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/dma/xlnx-zdma.c b/hw/dma/xlnx-zdma.c index 1c45367f3c..5f4775f663 100644 --- a/hw/dma/xlnx-zdma.c +++ b/hw/dma/xlnx-zdma.c @@ -299,19 +299,22 @@ static void zdma_put_regaddr64(XlnxZDMA *s, unsigned int basereg, uint64_t addr) s->regs[basereg + 1] = addr >> 32; } -static bool zdma_load_descriptor(XlnxZDMA *s, uint64_t addr, void *buf) +static bool zdma_load_descriptor(XlnxZDMA *s, uint64_t addr, + XlnxZDMADescr *descr) { /* ZDMA descriptors must be aligned to their own size. */ if (addr % sizeof(XlnxZDMADescr)) { qemu_log_mask(LOG_GUEST_ERROR, "zdma: unaligned descriptor at %" PRIx64, addr); - memset(buf, 0x0, sizeof(XlnxZDMADescr)); + memset(descr, 0x0, sizeof(XlnxZDMADescr)); s->error = true; return false; } - address_space_read(s->dma_as, addr, s->attr, buf, sizeof(XlnxZDMADescr)); + descr->addr = address_space_ldq_le(s->dma_as, addr, s->attr, NULL); + descr->size = address_space_ldl_le(s->dma_as, addr + 8, s->attr, NULL); + descr->attr = address_space_ldl_le(s->dma_as, addr + 12, s->attr, NULL); return true; } @@ -344,7 +347,7 @@ static void zdma_update_descr_addr(XlnxZDMA *s, bool type, } else { addr = zdma_get_regaddr64(s, basereg); addr += sizeof(s->dsc_dst); - address_space_read(s->dma_as, addr, s->attr, (void *) &next, 8); + next = address_space_ldq_le(s->dma_as, addr, s->attr, NULL); } zdma_put_regaddr64(s, basereg, next); From 1633ed1e2de68cc27a1be8ff2a63e09c37e592f5 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Sat, 4 Apr 2020 14:27:18 +0200 Subject: [PATCH 0095/2595] dma/xlnx-zdma: Fix descriptor loading (REG) wrt endianness Fix descriptor loading from registers wrt host endianness. Reported-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Reviewed-by: Francisco Iglesias Message-id: 20200404122718.25111-3-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/dma/xlnx-zdma.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hw/dma/xlnx-zdma.c b/hw/dma/xlnx-zdma.c index 5f4775f663..4121a1b489 100644 --- a/hw/dma/xlnx-zdma.c +++ b/hw/dma/xlnx-zdma.c @@ -299,6 +299,14 @@ static void zdma_put_regaddr64(XlnxZDMA *s, unsigned int basereg, uint64_t addr) s->regs[basereg + 1] = addr >> 32; } +static void zdma_load_descriptor_reg(XlnxZDMA *s, unsigned int reg, + XlnxZDMADescr *descr) +{ + descr->addr = zdma_get_regaddr64(s, reg); + descr->size = s->regs[reg + 2]; + descr->attr = s->regs[reg + 3]; +} + static bool zdma_load_descriptor(XlnxZDMA *s, uint64_t addr, XlnxZDMADescr *descr) { @@ -324,8 +332,7 @@ static void zdma_load_src_descriptor(XlnxZDMA *s) unsigned int ptype = ARRAY_FIELD_EX32(s->regs, ZDMA_CH_CTRL0, POINT_TYPE); if (ptype == PT_REG) { - memcpy(&s->dsc_src, &s->regs[R_ZDMA_CH_SRC_DSCR_WORD0], - sizeof(s->dsc_src)); + zdma_load_descriptor_reg(s, R_ZDMA_CH_SRC_DSCR_WORD0, &s->dsc_src); return; } @@ -360,8 +367,7 @@ static void zdma_load_dst_descriptor(XlnxZDMA *s) bool dst_type; if (ptype == PT_REG) { - memcpy(&s->dsc_dst, &s->regs[R_ZDMA_CH_DST_DSCR_WORD0], - sizeof(s->dsc_dst)); + zdma_load_descriptor_reg(s, R_ZDMA_CH_DST_DSCR_WORD0, &s->dsc_dst); return; } From c8aeef3aed6beef14175f9c6744b2ea30fc309d9 Mon Sep 17 00:00:00 2001 From: Cameron Esfahani Date: Tue, 14 Apr 2020 21:37:17 -0700 Subject: [PATCH 0096/2595] nrf51: Fix last GPIO CNF address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NRF51_GPIO_REG_CNF_END doesn't actually refer to the start of the last valid CNF register: it's referring to the last byte of the last valid CNF register. This hasn't been a problem up to now, as current implementation in memory.c turns an unaligned 4-byte read from 0x77f to a single byte read and the qtest only looks at the least-significant byte of the register. But when running with patches which fix unaligned accesses in memory.c, the qtest breaks. Considering NRF51 doesn't support unaligned accesses, the simplest fix is to actually set NRF51_GPIO_REG_CNF_END to the start of the last valid CNF register: 0x77c. Now, qtests work with or without the unaligned access patches. Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Reviewed-by: Joel Stanley Signed-off-by: Cameron Esfahani Message-id: 51b427f06838622da783d38ba56e3630d6d85c60.1586925392.git.dirty@apple.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- include/hw/gpio/nrf51_gpio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/gpio/nrf51_gpio.h b/include/hw/gpio/nrf51_gpio.h index 337ee534bb..1d62bbc928 100644 --- a/include/hw/gpio/nrf51_gpio.h +++ b/include/hw/gpio/nrf51_gpio.h @@ -42,7 +42,7 @@ #define NRF51_GPIO_REG_DIRSET 0x518 #define NRF51_GPIO_REG_DIRCLR 0x51C #define NRF51_GPIO_REG_CNF_START 0x700 -#define NRF51_GPIO_REG_CNF_END 0x77F +#define NRF51_GPIO_REG_CNF_END 0x77C #define NRF51_GPIO_PULLDOWN 1 #define NRF51_GPIO_PULLUP 3 From 1e11a139bfed55cb2de7b2eaa1e53f3cf6180d13 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 13 Apr 2020 17:15:50 +0800 Subject: [PATCH 0097/2595] bugfix: Use gicr_typer in arm_gicv3_icc_reset The KVM_VGIC_ATTR macro expect the second parameter as gicr_typer, of which high 32bit is constructed by mp_affinity. For most case, the high 32bit of mp_affinity is zero, so it will always access the ICC_CTLR_EL1 of CPU0. Signed-off-by: Keqian Zhu Message-id: 20200413091552.62748-2-zhukeqian1@huawei.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/arm_gicv3_kvm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 49304ca589..ca43bf87ca 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -658,13 +658,11 @@ static void kvm_arm_gicv3_get(GICv3State *s) static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) { - ARMCPU *cpu; GICv3State *s; GICv3CPUState *c; c = (GICv3CPUState *)env->gicv3state; s = c->gic; - cpu = ARM_CPU(c->cpu); c->icc_pmr_el1 = 0; c->icc_bpr[GICV3_G0] = GIC_MIN_BPR; @@ -681,7 +679,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) /* Initialize to actual HW supported configuration */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, - KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity), + KVM_VGIC_ATTR(ICC_CTLR_EL1, c->gicr_typer), &c->icc_ctlr_el1[GICV3_NS], false, &error_abort); c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; From 119a2ef1dce90ffa2b86a43fb190027fcc5cdb9a Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 13 Apr 2020 17:15:52 +0800 Subject: [PATCH 0098/2595] Typo: Correct the name of CPU hotplug memory region Replace "acpi-mem-hotplug" with "acpi-cpu-hotplug" Signed-off-by: Keqian Zhu Message-id: 20200413091552.62748-4-zhukeqian1@huawei.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/acpi/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index e2c957ce00..3d6a500fb7 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -222,7 +222,7 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, state->devs[i].arch_id = id_list->cpus[i].arch_id; } memory_region_init_io(&state->ctrl_reg, owner, &cpu_hotplug_ops, state, - "acpi-mem-hotplug", ACPI_CPU_HOTPLUG_REG_LEN); + "acpi-cpu-hotplug", ACPI_CPU_HOTPLUG_REG_LEN); memory_region_add_subregion(as, base_addr, &state->ctrl_reg); } From 1c66437879654705bbf8099d9767594668c57ce8 Mon Sep 17 00:00:00 2001 From: Subbaraya Sundeep Date: Thu, 16 Apr 2020 20:24:49 +0530 Subject: [PATCH 0099/2595] hw/net: Add Smartfusion2 emac block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modelled Ethernet MAC of Smartfusion2 SoC. Micrel KSZ8051 PHY is present on Emcraft's SOM kit hence same PHY is emulated. Signed-off-by: Subbaraya Sundeep Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 1587048891-30493-2-git-send-email-sundeep.lkml@gmail.com Signed-off-by: Peter Maydell --- MAINTAINERS | 2 + hw/net/Makefile.objs | 1 + hw/net/msf2-emac.c | 589 +++++++++++++++++++++++++++++++++++++ include/hw/net/msf2-emac.h | 53 ++++ 4 files changed, 645 insertions(+) create mode 100644 hw/net/msf2-emac.c create mode 100644 include/hw/net/msf2-emac.h diff --git a/MAINTAINERS b/MAINTAINERS index 8cbc1fac2b..cea57331fe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -919,6 +919,8 @@ F: include/hw/arm/msf2-soc.h F: include/hw/misc/msf2-sysreg.h F: include/hw/timer/mss-timer.h F: include/hw/ssi/mss-spi.h +F: hw/net/msf2-emac.c +F: include/hw/net/msf2-emac.h Emcraft M2S-FG484 M: Subbaraya Sundeep diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs index af4d194866..f2b73983ee 100644 --- a/hw/net/Makefile.objs +++ b/hw/net/Makefile.objs @@ -55,3 +55,4 @@ common-obj-$(CONFIG_ROCKER) += rocker/rocker.o rocker/rocker_fp.o \ obj-$(call lnot,$(CONFIG_ROCKER)) += rocker/qmp-norocker.o common-obj-$(CONFIG_CAN_BUS) += can/ +common-obj-$(CONFIG_MSF2) += msf2-emac.o diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c new file mode 100644 index 0000000000..32ba9e8412 --- /dev/null +++ b/hw/net/msf2-emac.c @@ -0,0 +1,589 @@ +/* + * QEMU model of the Smartfusion2 Ethernet MAC. + * + * Copyright (c) 2020 Subbaraya Sundeep . + * + * 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. + * + * Refer to section Ethernet MAC in the document: + * UG0331: SmartFusion2 Microcontroller Subsystem User Guide + * Datasheet URL: + * https://www.microsemi.com/document-portal/cat_view/56661-internal-documents/ + * 56758-soc?lang=en&limit=20&limitstart=220 + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "exec/address-spaces.h" +#include "hw/registerfields.h" +#include "hw/net/msf2-emac.h" +#include "hw/net/mii.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" + +REG32(CFG1, 0x0) + FIELD(CFG1, RESET, 31, 1) + FIELD(CFG1, RX_EN, 2, 1) + FIELD(CFG1, TX_EN, 0, 1) + FIELD(CFG1, LB_EN, 8, 1) +REG32(CFG2, 0x4) +REG32(IFG, 0x8) +REG32(HALF_DUPLEX, 0xc) +REG32(MAX_FRAME_LENGTH, 0x10) +REG32(MII_CMD, 0x24) + FIELD(MII_CMD, READ, 0, 1) +REG32(MII_ADDR, 0x28) + FIELD(MII_ADDR, REGADDR, 0, 5) + FIELD(MII_ADDR, PHYADDR, 8, 5) +REG32(MII_CTL, 0x2c) +REG32(MII_STS, 0x30) +REG32(STA1, 0x40) +REG32(STA2, 0x44) +REG32(FIFO_CFG0, 0x48) +REG32(FIFO_CFG4, 0x58) + FIELD(FIFO_CFG4, BCAST, 9, 1) + FIELD(FIFO_CFG4, MCAST, 8, 1) +REG32(FIFO_CFG5, 0x5C) + FIELD(FIFO_CFG5, BCAST, 9, 1) + FIELD(FIFO_CFG5, MCAST, 8, 1) +REG32(DMA_TX_CTL, 0x180) + FIELD(DMA_TX_CTL, EN, 0, 1) +REG32(DMA_TX_DESC, 0x184) +REG32(DMA_TX_STATUS, 0x188) + FIELD(DMA_TX_STATUS, PKTCNT, 16, 8) + FIELD(DMA_TX_STATUS, UNDERRUN, 1, 1) + FIELD(DMA_TX_STATUS, PKT_SENT, 0, 1) +REG32(DMA_RX_CTL, 0x18c) + FIELD(DMA_RX_CTL, EN, 0, 1) +REG32(DMA_RX_DESC, 0x190) +REG32(DMA_RX_STATUS, 0x194) + FIELD(DMA_RX_STATUS, PKTCNT, 16, 8) + FIELD(DMA_RX_STATUS, OVERFLOW, 2, 1) + FIELD(DMA_RX_STATUS, PKT_RCVD, 0, 1) +REG32(DMA_IRQ_MASK, 0x198) +REG32(DMA_IRQ, 0x19c) + +#define EMPTY_MASK (1 << 31) +#define PKT_SIZE 0x7FF +#define PHYADDR 0x1 +#define MAX_PKT_SIZE 2048 + +typedef struct { + uint32_t pktaddr; + uint32_t pktsize; + uint32_t next; +} EmacDesc; + +static uint32_t emac_get_isr(MSF2EmacState *s) +{ + uint32_t ier = s->regs[R_DMA_IRQ_MASK]; + uint32_t tx = s->regs[R_DMA_TX_STATUS] & 0xF; + uint32_t rx = s->regs[R_DMA_RX_STATUS] & 0xF; + uint32_t isr = (rx << 4) | tx; + + s->regs[R_DMA_IRQ] = ier & isr; + return s->regs[R_DMA_IRQ]; +} + +static void emac_update_irq(MSF2EmacState *s) +{ + bool intr = emac_get_isr(s); + + qemu_set_irq(s->irq, intr); +} + +static void emac_load_desc(MSF2EmacState *s, EmacDesc *d, hwaddr desc) +{ + address_space_read(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, d, sizeof *d); + /* Convert from LE into host endianness. */ + d->pktaddr = le32_to_cpu(d->pktaddr); + d->pktsize = le32_to_cpu(d->pktsize); + d->next = le32_to_cpu(d->next); +} + +static void emac_store_desc(MSF2EmacState *s, EmacDesc *d, hwaddr desc) +{ + /* Convert from host endianness into LE. */ + d->pktaddr = cpu_to_le32(d->pktaddr); + d->pktsize = cpu_to_le32(d->pktsize); + d->next = cpu_to_le32(d->next); + + address_space_write(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, d, sizeof *d); +} + +static void msf2_dma_tx(MSF2EmacState *s) +{ + NetClientState *nc = qemu_get_queue(s->nic); + hwaddr desc = s->regs[R_DMA_TX_DESC]; + uint8_t buf[MAX_PKT_SIZE]; + EmacDesc d; + int size; + uint8_t pktcnt; + uint32_t status; + + if (!(s->regs[R_CFG1] & R_CFG1_TX_EN_MASK)) { + return; + } + + while (1) { + emac_load_desc(s, &d, desc); + if (d.pktsize & EMPTY_MASK) { + break; + } + size = d.pktsize & PKT_SIZE; + address_space_read(&s->dma_as, d.pktaddr, MEMTXATTRS_UNSPECIFIED, + buf, size); + /* + * This is very basic way to send packets. Ideally there should be + * a FIFO and packets should be sent out from FIFO only when + * R_CFG1 bit 0 is set. + */ + if (s->regs[R_CFG1] & R_CFG1_LB_EN_MASK) { + nc->info->receive(nc, buf, size); + } else { + qemu_send_packet(nc, buf, size); + } + d.pktsize |= EMPTY_MASK; + emac_store_desc(s, &d, desc); + /* update sent packets count */ + status = s->regs[R_DMA_TX_STATUS]; + pktcnt = FIELD_EX32(status, DMA_TX_STATUS, PKTCNT); + pktcnt++; + s->regs[R_DMA_TX_STATUS] = FIELD_DP32(status, DMA_TX_STATUS, + PKTCNT, pktcnt); + s->regs[R_DMA_TX_STATUS] |= R_DMA_TX_STATUS_PKT_SENT_MASK; + desc = d.next; + } + s->regs[R_DMA_TX_STATUS] |= R_DMA_TX_STATUS_UNDERRUN_MASK; + s->regs[R_DMA_TX_CTL] &= ~R_DMA_TX_CTL_EN_MASK; +} + +static void msf2_phy_update_link(MSF2EmacState *s) +{ + /* Autonegotiation status mirrors link status. */ + if (qemu_get_queue(s->nic)->link_down) { + s->phy_regs[MII_BMSR] &= ~(MII_BMSR_AN_COMP | + MII_BMSR_LINK_ST); + } else { + s->phy_regs[MII_BMSR] |= (MII_BMSR_AN_COMP | + MII_BMSR_LINK_ST); + } +} + +static void msf2_phy_reset(MSF2EmacState *s) +{ + memset(&s->phy_regs[0], 0, sizeof(s->phy_regs)); + s->phy_regs[MII_BMCR] = 0x1140; + s->phy_regs[MII_BMSR] = 0x7968; + s->phy_regs[MII_PHYID1] = 0x0022; + s->phy_regs[MII_PHYID2] = 0x1550; + s->phy_regs[MII_ANAR] = 0x01E1; + s->phy_regs[MII_ANLPAR] = 0xCDE1; + + msf2_phy_update_link(s); +} + +static void write_to_phy(MSF2EmacState *s) +{ + uint8_t reg_addr = s->regs[R_MII_ADDR] & R_MII_ADDR_REGADDR_MASK; + uint8_t phy_addr = (s->regs[R_MII_ADDR] >> R_MII_ADDR_PHYADDR_SHIFT) & + R_MII_ADDR_REGADDR_MASK; + uint16_t data = s->regs[R_MII_CTL] & 0xFFFF; + + if (phy_addr != PHYADDR) { + return; + } + + switch (reg_addr) { + case MII_BMCR: + if (data & MII_BMCR_RESET) { + /* Phy reset */ + msf2_phy_reset(s); + data &= ~MII_BMCR_RESET; + } + if (data & MII_BMCR_AUTOEN) { + /* Complete autonegotiation immediately */ + data &= ~MII_BMCR_AUTOEN; + s->phy_regs[MII_BMSR] |= MII_BMSR_AN_COMP; + } + break; + } + + s->phy_regs[reg_addr] = data; +} + +static uint16_t read_from_phy(MSF2EmacState *s) +{ + uint8_t reg_addr = s->regs[R_MII_ADDR] & R_MII_ADDR_REGADDR_MASK; + uint8_t phy_addr = (s->regs[R_MII_ADDR] >> R_MII_ADDR_PHYADDR_SHIFT) & + R_MII_ADDR_REGADDR_MASK; + + if (phy_addr == PHYADDR) { + return s->phy_regs[reg_addr]; + } else { + return 0xFFFF; + } +} + +static void msf2_emac_do_reset(MSF2EmacState *s) +{ + memset(&s->regs[0], 0, sizeof(s->regs)); + s->regs[R_CFG1] = 0x80000000; + s->regs[R_CFG2] = 0x00007000; + s->regs[R_IFG] = 0x40605060; + s->regs[R_HALF_DUPLEX] = 0x00A1F037; + s->regs[R_MAX_FRAME_LENGTH] = 0x00000600; + s->regs[R_FIFO_CFG5] = 0X3FFFF; + + msf2_phy_reset(s); +} + +static uint64_t emac_read(void *opaque, hwaddr addr, unsigned int size) +{ + MSF2EmacState *s = opaque; + uint32_t r = 0; + + addr >>= 2; + + switch (addr) { + case R_DMA_IRQ: + r = emac_get_isr(s); + break; + default: + if (addr >= ARRAY_SIZE(s->regs)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, + addr * 4); + return r; + } + r = s->regs[addr]; + break; + } + return r; +} + +static void emac_write(void *opaque, hwaddr addr, uint64_t val64, + unsigned int size) +{ + MSF2EmacState *s = opaque; + uint32_t value = val64; + uint32_t enreqbits; + uint8_t pktcnt; + + addr >>= 2; + switch (addr) { + case R_DMA_TX_CTL: + s->regs[addr] = value; + if (value & R_DMA_TX_CTL_EN_MASK) { + msf2_dma_tx(s); + } + break; + case R_DMA_RX_CTL: + s->regs[addr] = value; + if (value & R_DMA_RX_CTL_EN_MASK) { + s->rx_desc = s->regs[R_DMA_RX_DESC]; + qemu_flush_queued_packets(qemu_get_queue(s->nic)); + } + break; + case R_CFG1: + s->regs[addr] = value; + if (value & R_CFG1_RESET_MASK) { + msf2_emac_do_reset(s); + } + break; + case R_FIFO_CFG0: + /* + * For our implementation, turning on modules is instantaneous, + * so the states requested via the *ENREQ bits appear in the + * *ENRPLY bits immediately. Also the reset bits to reset PE-MCXMAC + * module are not emulated here since it deals with start of frames, + * inter-packet gap and control frames. + */ + enreqbits = extract32(value, 8, 5); + s->regs[addr] = deposit32(value, 16, 5, enreqbits); + break; + case R_DMA_TX_DESC: + if (value & 0x3) { + qemu_log_mask(LOG_GUEST_ERROR, "Tx Descriptor address should be" + " 32 bit aligned\n"); + } + /* Ignore [1:0] bits */ + s->regs[addr] = value & ~3; + break; + case R_DMA_RX_DESC: + if (value & 0x3) { + qemu_log_mask(LOG_GUEST_ERROR, "Rx Descriptor address should be" + " 32 bit aligned\n"); + } + /* Ignore [1:0] bits */ + s->regs[addr] = value & ~3; + break; + case R_DMA_TX_STATUS: + if (value & R_DMA_TX_STATUS_UNDERRUN_MASK) { + s->regs[addr] &= ~R_DMA_TX_STATUS_UNDERRUN_MASK; + } + if (value & R_DMA_TX_STATUS_PKT_SENT_MASK) { + pktcnt = FIELD_EX32(s->regs[addr], DMA_TX_STATUS, PKTCNT); + pktcnt--; + s->regs[addr] = FIELD_DP32(s->regs[addr], DMA_TX_STATUS, + PKTCNT, pktcnt); + if (pktcnt == 0) { + s->regs[addr] &= ~R_DMA_TX_STATUS_PKT_SENT_MASK; + } + } + break; + case R_DMA_RX_STATUS: + if (value & R_DMA_RX_STATUS_OVERFLOW_MASK) { + s->regs[addr] &= ~R_DMA_RX_STATUS_OVERFLOW_MASK; + } + if (value & R_DMA_RX_STATUS_PKT_RCVD_MASK) { + pktcnt = FIELD_EX32(s->regs[addr], DMA_RX_STATUS, PKTCNT); + pktcnt--; + s->regs[addr] = FIELD_DP32(s->regs[addr], DMA_RX_STATUS, + PKTCNT, pktcnt); + if (pktcnt == 0) { + s->regs[addr] &= ~R_DMA_RX_STATUS_PKT_RCVD_MASK; + } + } + break; + case R_DMA_IRQ: + break; + case R_MII_CMD: + if (value & R_MII_CMD_READ_MASK) { + s->regs[R_MII_STS] = read_from_phy(s); + } + break; + case R_MII_CTL: + s->regs[addr] = value; + write_to_phy(s); + break; + case R_STA1: + s->regs[addr] = value; + /* + * R_STA1 [31:24] : octet 1 of mac address + * R_STA1 [23:16] : octet 2 of mac address + * R_STA1 [15:8] : octet 3 of mac address + * R_STA1 [7:0] : octet 4 of mac address + */ + stl_be_p(s->mac_addr, value); + break; + case R_STA2: + s->regs[addr] = value; + /* + * R_STA2 [31:24] : octet 5 of mac address + * R_STA2 [23:16] : octet 6 of mac address + */ + stw_be_p(s->mac_addr + 4, value >> 16); + break; + default: + if (addr >= ARRAY_SIZE(s->regs)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, + addr * 4); + return; + } + s->regs[addr] = value; + break; + } + emac_update_irq(s); +} + +static const MemoryRegionOps emac_ops = { + .read = emac_read, + .write = emac_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static bool emac_can_rx(NetClientState *nc) +{ + MSF2EmacState *s = qemu_get_nic_opaque(nc); + + return (s->regs[R_CFG1] & R_CFG1_RX_EN_MASK) && + (s->regs[R_DMA_RX_CTL] & R_DMA_RX_CTL_EN_MASK); +} + +static bool addr_filter_ok(MSF2EmacState *s, const uint8_t *buf) +{ + /* The broadcast MAC address: FF:FF:FF:FF:FF:FF */ + const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF }; + bool bcast_en = true; + bool mcast_en = true; + + if (s->regs[R_FIFO_CFG5] & R_FIFO_CFG5_BCAST_MASK) { + bcast_en = true; /* Broadcast dont care for drop circuitry */ + } else if (s->regs[R_FIFO_CFG4] & R_FIFO_CFG4_BCAST_MASK) { + bcast_en = false; + } + + if (s->regs[R_FIFO_CFG5] & R_FIFO_CFG5_MCAST_MASK) { + mcast_en = true; /* Multicast dont care for drop circuitry */ + } else if (s->regs[R_FIFO_CFG4] & R_FIFO_CFG4_MCAST_MASK) { + mcast_en = false; + } + + if (!memcmp(buf, broadcast_addr, sizeof(broadcast_addr))) { + return bcast_en; + } + + if (buf[0] & 1) { + return mcast_en; + } + + return !memcmp(buf, s->mac_addr, sizeof(s->mac_addr)); +} + +static ssize_t emac_rx(NetClientState *nc, const uint8_t *buf, size_t size) +{ + MSF2EmacState *s = qemu_get_nic_opaque(nc); + EmacDesc d; + uint8_t pktcnt; + uint32_t status; + + if (size > (s->regs[R_MAX_FRAME_LENGTH] & 0xFFFF)) { + return size; + } + if (!addr_filter_ok(s, buf)) { + return size; + } + + emac_load_desc(s, &d, s->rx_desc); + + if (d.pktsize & EMPTY_MASK) { + address_space_write(&s->dma_as, d.pktaddr, MEMTXATTRS_UNSPECIFIED, + buf, size & PKT_SIZE); + d.pktsize = size & PKT_SIZE; + emac_store_desc(s, &d, s->rx_desc); + /* update received packets count */ + status = s->regs[R_DMA_RX_STATUS]; + pktcnt = FIELD_EX32(status, DMA_RX_STATUS, PKTCNT); + pktcnt++; + s->regs[R_DMA_RX_STATUS] = FIELD_DP32(status, DMA_RX_STATUS, + PKTCNT, pktcnt); + s->regs[R_DMA_RX_STATUS] |= R_DMA_RX_STATUS_PKT_RCVD_MASK; + s->rx_desc = d.next; + } else { + s->regs[R_DMA_RX_CTL] &= ~R_DMA_RX_CTL_EN_MASK; + s->regs[R_DMA_RX_STATUS] |= R_DMA_RX_STATUS_OVERFLOW_MASK; + } + emac_update_irq(s); + return size; +} + +static void msf2_emac_reset(DeviceState *dev) +{ + MSF2EmacState *s = MSS_EMAC(dev); + + msf2_emac_do_reset(s); +} + +static void emac_set_link(NetClientState *nc) +{ + MSF2EmacState *s = qemu_get_nic_opaque(nc); + + msf2_phy_update_link(s); +} + +static NetClientInfo net_msf2_emac_info = { + .type = NET_CLIENT_DRIVER_NIC, + .size = sizeof(NICState), + .can_receive = emac_can_rx, + .receive = emac_rx, + .link_status_changed = emac_set_link, +}; + +static void msf2_emac_realize(DeviceState *dev, Error **errp) +{ + MSF2EmacState *s = MSS_EMAC(dev); + + if (!s->dma_mr) { + error_setg(errp, "MSS_EMAC 'ahb-bus' link not set"); + return; + } + + address_space_init(&s->dma_as, s->dma_mr, "emac-ahb"); + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_msf2_emac_info, &s->conf, + object_get_typename(OBJECT(dev)), dev->id, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); +} + +static void msf2_emac_init(Object *obj) +{ + MSF2EmacState *s = MSS_EMAC(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + + memory_region_init_io(&s->mmio, obj, &emac_ops, s, + "msf2-emac", R_MAX * 4); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static Property msf2_emac_properties[] = { + DEFINE_PROP_LINK("ahb-bus", MSF2EmacState, dma_mr, + TYPE_MEMORY_REGION, MemoryRegion *), + DEFINE_NIC_PROPERTIES(MSF2EmacState, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription vmstate_msf2_emac = { + .name = TYPE_MSS_EMAC, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(mac_addr, MSF2EmacState, ETH_ALEN), + VMSTATE_UINT32(rx_desc, MSF2EmacState), + VMSTATE_UINT16_ARRAY(phy_regs, MSF2EmacState, PHY_MAX_REGS), + VMSTATE_UINT32_ARRAY(regs, MSF2EmacState, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static void msf2_emac_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = msf2_emac_realize; + dc->reset = msf2_emac_reset; + dc->vmsd = &vmstate_msf2_emac; + device_class_set_props(dc, msf2_emac_properties); +} + +static const TypeInfo msf2_emac_info = { + .name = TYPE_MSS_EMAC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MSF2EmacState), + .instance_init = msf2_emac_init, + .class_init = msf2_emac_class_init, +}; + +static void msf2_emac_register_types(void) +{ + type_register_static(&msf2_emac_info); +} + +type_init(msf2_emac_register_types) diff --git a/include/hw/net/msf2-emac.h b/include/hw/net/msf2-emac.h new file mode 100644 index 0000000000..37966d3a81 --- /dev/null +++ b/include/hw/net/msf2-emac.h @@ -0,0 +1,53 @@ +/* + * QEMU model of the Smartfusion2 Ethernet MAC. + * + * Copyright (c) 2020 Subbaraya Sundeep . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/sysbus.h" +#include "exec/memory.h" +#include "net/net.h" +#include "net/eth.h" + +#define TYPE_MSS_EMAC "msf2-emac" +#define MSS_EMAC(obj) \ + OBJECT_CHECK(MSF2EmacState, (obj), TYPE_MSS_EMAC) + +#define R_MAX (0x1a0 / 4) +#define PHY_MAX_REGS 32 + +typedef struct MSF2EmacState { + SysBusDevice parent; + + MemoryRegion mmio; + MemoryRegion *dma_mr; + AddressSpace dma_as; + + qemu_irq irq; + NICState *nic; + NICConf conf; + + uint8_t mac_addr[ETH_ALEN]; + uint32_t rx_desc; + uint16_t phy_regs[PHY_MAX_REGS]; + + uint32_t regs[R_MAX]; +} MSF2EmacState; From 05b7374a58cd18aa3516e33513808896d0ac9b7b Mon Sep 17 00:00:00 2001 From: Subbaraya Sundeep Date: Thu, 16 Apr 2020 20:24:50 +0530 Subject: [PATCH 0100/2595] msf2: Add EMAC block to SmartFusion2 SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With SmartFusion2 Ethernet MAC model in place this patch adds the same to SoC. Signed-off-by: Subbaraya Sundeep Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 1587048891-30493-3-git-send-email-sundeep.lkml@gmail.com Signed-off-by: Peter Maydell --- hw/arm/msf2-soc.c | 26 ++++++++++++++++++++++++-- include/hw/arm/msf2-soc.h | 2 ++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index 588d643b8d..a455b8831f 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -1,7 +1,7 @@ /* * SmartFusion2 SoC emulation. * - * Copyright (c) 2017 Subbaraya Sundeep + * Copyright (c) 2017-2020 Subbaraya Sundeep * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,11 +35,14 @@ #define MSF2_TIMER_BASE 0x40004000 #define MSF2_SYSREG_BASE 0x40038000 +#define MSF2_EMAC_BASE 0x40041000 #define ENVM_BASE_ADDRESS 0x60000000 #define SRAM_BASE_ADDRESS 0x20000000 +#define MSF2_EMAC_IRQ 12 + #define MSF2_ENVM_MAX_SIZE (512 * KiB) /* @@ -81,6 +84,13 @@ static void m2sxxx_soc_initfn(Object *obj) sysbus_init_child_obj(obj, "spi[*]", &s->spi[i], sizeof(s->spi[i]), TYPE_MSS_SPI); } + + sysbus_init_child_obj(obj, "emac", &s->emac, sizeof(s->emac), + TYPE_MSS_EMAC); + if (nd_table[0].used) { + qemu_check_nic_model(&nd_table[0], TYPE_MSS_EMAC); + qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); + } } static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) @@ -192,6 +202,19 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) g_free(bus_name); } + dev = DEVICE(&s->emac); + object_property_set_link(OBJECT(&s->emac), OBJECT(get_system_memory()), + "ahb-bus", &error_abort); + object_property_set_bool(OBJECT(&s->emac), true, "realized", &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, MSF2_EMAC_BASE); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(armv7m, MSF2_EMAC_IRQ)); + /* Below devices are not modelled yet. */ create_unimplemented_device("i2c_0", 0x40002000, 0x1000); create_unimplemented_device("dma", 0x40003000, 0x1000); @@ -202,7 +225,6 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) create_unimplemented_device("can", 0x40015000, 0x1000); create_unimplemented_device("rtc", 0x40017000, 0x1000); create_unimplemented_device("apb_config", 0x40020000, 0x10000); - create_unimplemented_device("emac", 0x40041000, 0x1000); create_unimplemented_device("usb", 0x40043000, 0x1000); } diff --git a/include/hw/arm/msf2-soc.h b/include/hw/arm/msf2-soc.h index 3cfe5c76ee..c9cb214aa6 100644 --- a/include/hw/arm/msf2-soc.h +++ b/include/hw/arm/msf2-soc.h @@ -29,6 +29,7 @@ #include "hw/timer/mss-timer.h" #include "hw/misc/msf2-sysreg.h" #include "hw/ssi/mss-spi.h" +#include "hw/net/msf2-emac.h" #define TYPE_MSF2_SOC "msf2-soc" #define MSF2_SOC(obj) OBJECT_CHECK(MSF2State, (obj), TYPE_MSF2_SOC) @@ -62,6 +63,7 @@ typedef struct MSF2State { MSF2SysregState sysreg; MSSTimerState timer; MSSSpiState spi[MSF2_NUM_SPIS]; + MSF2EmacState emac; } MSF2State; #endif From 70d7857f935ab3fd6a5c0ff8b7586d0aef20f8b0 Mon Sep 17 00:00:00 2001 From: Subbaraya Sundeep Date: Thu, 16 Apr 2020 20:24:51 +0530 Subject: [PATCH 0101/2595] tests/boot_linux_console: Add ethernet test to SmartFusion2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In addition to simple serial test this patch uses ping to test the ethernet block modelled in SmartFusion2 SoC. Signed-off-by: Subbaraya Sundeep Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 1587048891-30493-4-git-send-email-sundeep.lkml@gmail.com Signed-off-by: Peter Maydell --- tests/acceptance/boot_linux_console.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index f825cd9ef5..c6b06a1a13 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -336,13 +336,13 @@ class BootLinuxConsole(Test): """ uboot_url = ('https://raw.githubusercontent.com/' 'Subbaraya-Sundeep/qemu-test-binaries/' - 'fa030bd77a014a0b8e360d3b7011df89283a2f0b/u-boot') - uboot_hash = 'abba5d9c24cdd2d49cdc2a8aa92976cf20737eff' + 'fe371d32e50ca682391e1e70ab98c2942aeffb01/u-boot') + uboot_hash = 'cbb8cbab970f594bf6523b9855be209c08374ae2' uboot_path = self.fetch_asset(uboot_url, asset_hash=uboot_hash) spi_url = ('https://raw.githubusercontent.com/' 'Subbaraya-Sundeep/qemu-test-binaries/' - 'fa030bd77a014a0b8e360d3b7011df89283a2f0b/spi.bin') - spi_hash = '85f698329d38de63aea6e884a86fbde70890a78a' + 'fe371d32e50ca682391e1e70ab98c2942aeffb01/spi.bin') + spi_hash = '65523a1835949b6f4553be96dec1b6a38fb05501' spi_path = self.fetch_asset(spi_url, asset_hash=spi_hash) self.vm.set_console() @@ -352,7 +352,12 @@ class BootLinuxConsole(Test): '-drive', 'file=' + spi_path + ',if=mtd,format=raw', '-no-reboot') self.vm.launch() - self.wait_for_console_pattern('init started: BusyBox') + self.wait_for_console_pattern('Enter \'help\' for a list') + + exec_command_and_wait_for_pattern(self, 'ifconfig eth0 10.0.2.15', + 'eth0: link becomes ready') + exec_command_and_wait_for_pattern(self, 'ping -c 3 10.0.2.2', + '3 packets transmitted, 3 packets received, 0% packet loss') def do_test_arm_raspi2(self, uart_id): """ From 4cba075efedde66f0a8658001da7fc09a09024e1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 17 Apr 2020 16:54:28 +0100 Subject: [PATCH 0102/2595] hw/core/clock: introduce clock object This object may be used to represent a clock inside a clock tree. A clock may be connected to another clock so that it receives update, through a callback, whenever the source/parent clock is updated. Although only the root clock of a clock tree controls the values (represented as periods) of all clocks in tree, each clock holds a local state containing the current value so that it can be fetched independently. It will allows us to fullfill migration requirements by migrating each clock independently of others. This is based on the original work of Frederic Konrad. Signed-off-by: Damien Hedde Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Message-id: 20200406135251.157596-2-damien.hedde@greensocs.com [PMM: Use uint64_t rather than unsigned long long in trace events; the dtrace backend can't handle the latter] Signed-off-by: Peter Maydell --- hw/core/Makefile.objs | 1 + hw/core/clock.c | 130 +++++++++++++++++++++++++ hw/core/trace-events | 7 ++ include/hw/clock.h | 216 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 354 insertions(+) create mode 100644 hw/core/clock.c create mode 100644 include/hw/clock.h diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 6215e7c208..1d9b0aa205 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -7,6 +7,7 @@ common-obj-y += hotplug.o common-obj-y += vmstate-if.o # irq.o needed for qdev GPIO handling: common-obj-y += irq.o +common-obj-y += clock.o common-obj-$(CONFIG_SOFTMMU) += reset.o common-obj-$(CONFIG_SOFTMMU) += qdev-fw.o diff --git a/hw/core/clock.c b/hw/core/clock.c new file mode 100644 index 0000000000..3c0daf7d4c --- /dev/null +++ b/hw/core/clock.c @@ -0,0 +1,130 @@ +/* + * Hardware Clocks + * + * Copyright GreenSocs 2016-2020 + * + * Authors: + * Frederic Konrad + * Damien Hedde + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/clock.h" +#include "trace.h" + +#define CLOCK_PATH(_clk) (_clk->canonical_path) + +void clock_setup_canonical_path(Clock *clk) +{ + g_free(clk->canonical_path); + clk->canonical_path = object_get_canonical_path(OBJECT(clk)); +} + +void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque) +{ + clk->callback = cb; + clk->callback_opaque = opaque; +} + +void clock_clear_callback(Clock *clk) +{ + clock_set_callback(clk, NULL, NULL); +} + +void clock_set(Clock *clk, uint64_t period) +{ + trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period), + CLOCK_PERIOD_TO_NS(period)); + clk->period = period; +} + +static void clock_propagate_period(Clock *clk, bool call_callbacks) +{ + Clock *child; + + QLIST_FOREACH(child, &clk->children, sibling) { + if (child->period != clk->period) { + child->period = clk->period; + trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk), + CLOCK_PERIOD_TO_NS(clk->period), + call_callbacks); + if (call_callbacks && child->callback) { + child->callback(child->callback_opaque); + } + clock_propagate_period(child, call_callbacks); + } + } +} + +void clock_propagate(Clock *clk) +{ + assert(clk->source == NULL); + trace_clock_propagate(CLOCK_PATH(clk)); + clock_propagate_period(clk, true); +} + +void clock_set_source(Clock *clk, Clock *src) +{ + /* changing clock source is not supported */ + assert(!clk->source); + + trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src)); + + clk->period = src->period; + QLIST_INSERT_HEAD(&src->children, clk, sibling); + clk->source = src; + clock_propagate_period(clk, false); +} + +static void clock_disconnect(Clock *clk) +{ + if (clk->source == NULL) { + return; + } + + trace_clock_disconnect(CLOCK_PATH(clk)); + + clk->source = NULL; + QLIST_REMOVE(clk, sibling); +} + +static void clock_initfn(Object *obj) +{ + Clock *clk = CLOCK(obj); + + QLIST_INIT(&clk->children); +} + +static void clock_finalizefn(Object *obj) +{ + Clock *clk = CLOCK(obj); + Clock *child, *next; + + /* clear our list of children */ + QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) { + clock_disconnect(child); + } + + /* remove us from source's children list */ + clock_disconnect(clk); + + g_free(clk->canonical_path); +} + +static const TypeInfo clock_info = { + .name = TYPE_CLOCK, + .parent = TYPE_OBJECT, + .instance_size = sizeof(Clock), + .instance_init = clock_initfn, + .instance_finalize = clock_finalizefn, +}; + +static void clock_register_types(void) +{ + type_register_static(&clock_info); +} + +type_init(clock_register_types) diff --git a/hw/core/trace-events b/hw/core/trace-events index aecd8e160e..1ac60ede6b 100644 --- a/hw/core/trace-events +++ b/hw/core/trace-events @@ -27,3 +27,10 @@ resettable_phase_exit_begin(void *obj, const char *objtype, unsigned count, int resettable_phase_exit_exec(void *obj, const char *objtype, int has_method) "obj=%p(%s) method=%d" resettable_phase_exit_end(void *obj, const char *objtype, unsigned count) "obj=%p(%s) count=%d" resettable_transitional_function(void *obj, const char *objtype) "obj=%p(%s)" + +# clock.c +clock_set_source(const char *clk, const char *src) "'%s', src='%s'" +clock_disconnect(const char *clk) "'%s'" +clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', ns=%"PRIu64"->%"PRIu64 +clock_propagate(const char *clk) "'%s'" +clock_update(const char *clk, const char *src, uint64_t val, int cb) "'%s', src='%s', ns=%"PRIu64", cb=%d" diff --git a/include/hw/clock.h b/include/hw/clock.h new file mode 100644 index 0000000000..e0e19db9bd --- /dev/null +++ b/include/hw/clock.h @@ -0,0 +1,216 @@ +/* + * Hardware Clocks + * + * Copyright GreenSocs 2016-2020 + * + * Authors: + * Frederic Konrad + * Damien Hedde + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_HW_CLOCK_H +#define QEMU_HW_CLOCK_H + +#include "qom/object.h" +#include "qemu/queue.h" + +#define TYPE_CLOCK "clock" +#define CLOCK(obj) OBJECT_CHECK(Clock, (obj), TYPE_CLOCK) + +typedef void ClockCallback(void *opaque); + +/* + * clock store a value representing the clock's period in 2^-32ns unit. + * It can represent: + * + periods from 2^-32ns up to 4seconds + * + frequency from ~0.25Hz 2e10Ghz + * Resolution of frequency representation decreases with frequency: + * + at 100MHz, resolution is ~2mHz + * + at 1Ghz, resolution is ~0.2Hz + * + at 10Ghz, resolution is ~20Hz + */ +#define CLOCK_PERIOD_1SEC (1000000000llu << 32) + +/* + * macro helpers to convert to hertz / nanosecond + */ +#define CLOCK_PERIOD_FROM_NS(ns) ((ns) * (CLOCK_PERIOD_1SEC / 1000000000llu)) +#define CLOCK_PERIOD_TO_NS(per) ((per) / (CLOCK_PERIOD_1SEC / 1000000000llu)) +#define CLOCK_PERIOD_FROM_HZ(hz) (((hz) != 0) ? CLOCK_PERIOD_1SEC / (hz) : 0u) +#define CLOCK_PERIOD_TO_HZ(per) (((per) != 0) ? CLOCK_PERIOD_1SEC / (per) : 0u) + +/** + * Clock: + * @parent_obj: parent class + * @period: unsigned integer representing the period of the clock + * @canonical_path: clock path string cache (used for trace purpose) + * @callback: called when clock changes + * @callback_opaque: argument for @callback + * @source: source (or parent in clock tree) of the clock + * @children: list of clocks connected to this one (it is their source) + * @sibling: structure used to form a clock list + */ + +typedef struct Clock Clock; + +struct Clock { + /*< private >*/ + Object parent_obj; + + /* all fields are private and should not be modified directly */ + + /* fields */ + uint64_t period; + char *canonical_path; + ClockCallback *callback; + void *callback_opaque; + + /* Clocks are organized in a clock tree */ + Clock *source; + QLIST_HEAD(, Clock) children; + QLIST_ENTRY(Clock) sibling; +}; + +/** + * clock_setup_canonical_path: + * @clk: clock + * + * compute the canonical path of the clock (used by log messages) + */ +void clock_setup_canonical_path(Clock *clk); + +/** + * clock_set_callback: + * @clk: the clock to register the callback into + * @cb: the callback function + * @opaque: the argument to the callback + * + * Register a callback called on every clock update. + */ +void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque); + +/** + * clock_clear_callback: + * @clk: the clock to delete the callback from + * + * Unregister the callback registered with clock_set_callback. + */ +void clock_clear_callback(Clock *clk); + +/** + * clock_set_source: + * @clk: the clock. + * @src: the source clock + * + * Setup @src as the clock source of @clk. The current @src period + * value is also copied to @clk and its subtree but no callback is + * called. + * Further @src update will be propagated to @clk and its subtree. + */ +void clock_set_source(Clock *clk, Clock *src); + +/** + * clock_set: + * @clk: the clock to initialize. + * @value: the clock's value, 0 means unclocked + * + * Set the local cached period value of @clk to @value. + */ +void clock_set(Clock *clk, uint64_t value); + +static inline void clock_set_hz(Clock *clk, unsigned hz) +{ + clock_set(clk, CLOCK_PERIOD_FROM_HZ(hz)); +} + +static inline void clock_set_ns(Clock *clk, unsigned ns) +{ + clock_set(clk, CLOCK_PERIOD_FROM_NS(ns)); +} + +/** + * clock_propagate: + * @clk: the clock + * + * Propagate the clock period that has been previously configured using + * @clock_set(). This will update recursively all connected clocks. + * It is an error to call this function on a clock which has a source. + * Note: this function must not be called during device inititialization + * or migration. + */ +void clock_propagate(Clock *clk); + +/** + * clock_update: + * @clk: the clock to update. + * @value: the new clock's value, 0 means unclocked + * + * Update the @clk to the new @value. All connected clocks will be informed + * of this update. This is equivalent to call @clock_set() then + * @clock_propagate(). + */ +static inline void clock_update(Clock *clk, uint64_t value) +{ + clock_set(clk, value); + clock_propagate(clk); +} + +static inline void clock_update_hz(Clock *clk, unsigned hz) +{ + clock_update(clk, CLOCK_PERIOD_FROM_HZ(hz)); +} + +static inline void clock_update_ns(Clock *clk, unsigned ns) +{ + clock_update(clk, CLOCK_PERIOD_FROM_NS(ns)); +} + +/** + * clock_get: + * @clk: the clk to fetch the clock + * + * @return: the current period. + */ +static inline uint64_t clock_get(const Clock *clk) +{ + return clk->period; +} + +static inline unsigned clock_get_hz(Clock *clk) +{ + return CLOCK_PERIOD_TO_HZ(clock_get(clk)); +} + +static inline unsigned clock_get_ns(Clock *clk) +{ + return CLOCK_PERIOD_TO_NS(clock_get(clk)); +} + +/** + * clock_is_enabled: + * @clk: a clock + * + * @return: true if the clock is running. + */ +static inline bool clock_is_enabled(const Clock *clk) +{ + return clock_get(clk) != 0; +} + +static inline void clock_init(Clock *clk, uint64_t value) +{ + clock_set(clk, value); +} +static inline void clock_init_hz(Clock *clk, uint64_t value) +{ + clock_set_hz(clk, value); +} +static inline void clock_init_ns(Clock *clk, uint64_t value) +{ + clock_set_ns(clk, value); +} + +#endif /* QEMU_HW_CLOCK_H */ From 59afd43daedabe672c289326a5f268f737d35252 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Tue, 28 Apr 2020 15:59:08 -0700 Subject: [PATCH 0103/2595] target/xtensa: work around missing SR definitions Xtensa configuration overlays for recent releases may have special registers for which [rwx]sr opcodes are defined, but they are not listed as SR in xtensa_sysreg_name and associated functions. As a result generic translate_[rwx]sr* functions generate access to uninitialized cpu_SR causing segfault at runtime. Don't try to access cpu_SR for such registers, ignore writes and return 0 for reads. Cc: qemu-stable@nongnu.org Signed-off-by: Max Filippov --- target/xtensa/translate.c | 48 +++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index e0beaf7abb..546d2fa2fa 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -2191,7 +2191,11 @@ static void translate_rsil(DisasContext *dc, const OpcodeArg arg[], static void translate_rsr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]); + if (sr_name[par[0]]) { + tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]); + } else { + tcg_gen_movi_i32(arg[0].out, 0); + } } static void translate_rsr_ccount(DisasContext *dc, const OpcodeArg arg[], @@ -2563,13 +2567,17 @@ static void translate_wrmsk_expstate(DisasContext *dc, const OpcodeArg arg[], static void translate_wsr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_mov_i32(cpu_SR[par[0]], arg[0].in); + if (sr_name[par[0]]) { + tcg_gen_mov_i32(cpu_SR[par[0]], arg[0].in); + } } static void translate_wsr_mask(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_andi_i32(cpu_SR[par[0]], arg[0].in, par[2]); + if (sr_name[par[0]]) { + tcg_gen_andi_i32(cpu_SR[par[0]], arg[0].in, par[2]); + } } static void translate_wsr_acchi(DisasContext *dc, const OpcodeArg arg[], @@ -2775,23 +2783,31 @@ static void translate_xor(DisasContext *dc, const OpcodeArg arg[], static void translate_xsr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 tmp = tcg_temp_new_i32(); + if (sr_name[par[0]]) { + TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_mov_i32(tmp, arg[0].in); - tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]); - tcg_gen_mov_i32(cpu_SR[par[0]], tmp); - tcg_temp_free(tmp); + tcg_gen_mov_i32(tmp, arg[0].in); + tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]); + tcg_gen_mov_i32(cpu_SR[par[0]], tmp); + tcg_temp_free(tmp); + } else { + tcg_gen_movi_i32(arg[0].out, 0); + } } static void translate_xsr_mask(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 tmp = tcg_temp_new_i32(); + if (sr_name[par[0]]) { + TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_mov_i32(tmp, arg[0].in); - tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]); - tcg_gen_andi_i32(cpu_SR[par[0]], tmp, par[2]); - tcg_temp_free(tmp); + tcg_gen_mov_i32(tmp, arg[0].in); + tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]); + tcg_gen_andi_i32(cpu_SR[par[0]], tmp, par[2]); + tcg_temp_free(tmp); + } else { + tcg_gen_movi_i32(arg[0].out, 0); + } } static void translate_xsr_ccount(DisasContext *dc, const OpcodeArg arg[], @@ -2819,7 +2835,11 @@ static void translate_xsr_ccount(DisasContext *dc, const OpcodeArg arg[], { \ TCGv_i32 tmp = tcg_temp_new_i32(); \ \ - tcg_gen_mov_i32(tmp, cpu_SR[par[0]]); \ + if (sr_name[par[0]]) { \ + tcg_gen_mov_i32(tmp, cpu_SR[par[0]]); \ + } else { \ + tcg_gen_movi_i32(tmp, 0); \ + } \ translate_wsr_##name(dc, arg, par); \ tcg_gen_mov_i32(arg[0].out, tmp); \ tcg_temp_free(tmp); \ From b8d38bd5256362355cbc115889213e4892e16ea9 Mon Sep 17 00:00:00 2001 From: Damien Hedde Date: Mon, 6 Apr 2020 15:52:44 +0200 Subject: [PATCH 0104/2595] hw/core/clock-vmstate: define a vmstate entry for clock state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Hedde Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Message-id: 20200406135251.157596-3-damien.hedde@greensocs.com Signed-off-by: Peter Maydell --- hw/core/Makefile.objs | 1 + hw/core/clock-vmstate.c | 25 +++++++++++++++++++++++++ include/hw/clock.h | 9 +++++++++ 3 files changed, 35 insertions(+) create mode 100644 hw/core/clock-vmstate.c diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 1d9b0aa205..115df55087 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -21,6 +21,7 @@ common-obj-$(CONFIG_SOFTMMU) += null-machine.o common-obj-$(CONFIG_SOFTMMU) += loader.o common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o common-obj-$(CONFIG_SOFTMMU) += numa.o +common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o diff --git a/hw/core/clock-vmstate.c b/hw/core/clock-vmstate.c new file mode 100644 index 0000000000..260b13fc2c --- /dev/null +++ b/hw/core/clock-vmstate.c @@ -0,0 +1,25 @@ +/* + * Clock migration structure + * + * Copyright GreenSocs 2019-2020 + * + * Authors: + * Damien Hedde + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "migration/vmstate.h" +#include "hw/clock.h" + +const VMStateDescription vmstate_clock = { + .name = "clock", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT64(period, Clock), + VMSTATE_END_OF_LIST() + } +}; diff --git a/include/hw/clock.h b/include/hw/clock.h index e0e19db9bd..f822a94220 100644 --- a/include/hw/clock.h +++ b/include/hw/clock.h @@ -74,6 +74,15 @@ struct Clock { QLIST_ENTRY(Clock) sibling; }; +/* + * vmstate description entry to be added in device vmsd. + */ +extern const VMStateDescription vmstate_clock; +#define VMSTATE_CLOCK(field, state) \ + VMSTATE_CLOCK_V(field, state, 0) +#define VMSTATE_CLOCK_V(field, state, version) \ + VMSTATE_STRUCT_POINTER_V(field, state, version, vmstate_clock, Clock) + /** * clock_setup_canonical_path: * @clk: clock From 0e6934f26484abef4a96946078a34746f8855801 Mon Sep 17 00:00:00 2001 From: Damien Hedde Date: Mon, 6 Apr 2020 15:52:45 +0200 Subject: [PATCH 0105/2595] qdev: add clock input&output support to devices. Add functions to easily handle clocks with devices. Clock inputs and outputs should be used to handle clock propagation between devices. The API is very similar the GPIO API. This is based on the original work of Frederic Konrad. Signed-off-by: Damien Hedde Reviewed-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Message-id: 20200406135251.157596-4-damien.hedde@greensocs.com Signed-off-by: Peter Maydell --- hw/core/Makefile.objs | 2 +- hw/core/qdev-clock.c | 168 ++++++++++++++++++++++++++++++++++++++++ hw/core/qdev.c | 12 +++ include/hw/qdev-clock.h | 104 +++++++++++++++++++++++++ include/hw/qdev-core.h | 12 +++ tests/Makefile.include | 1 + 6 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 hw/core/qdev-clock.c create mode 100644 include/hw/qdev-clock.h diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 115df55087..1d540ed6e7 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -7,7 +7,7 @@ common-obj-y += hotplug.o common-obj-y += vmstate-if.o # irq.o needed for qdev GPIO handling: common-obj-y += irq.o -common-obj-y += clock.o +common-obj-y += clock.o qdev-clock.o common-obj-$(CONFIG_SOFTMMU) += reset.o common-obj-$(CONFIG_SOFTMMU) += qdev-fw.o diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c new file mode 100644 index 0000000000..62035aef83 --- /dev/null +++ b/hw/core/qdev-clock.c @@ -0,0 +1,168 @@ +/* + * Device's clock input and output + * + * Copyright GreenSocs 2016-2020 + * + * Authors: + * Frederic Konrad + * Damien Hedde + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/qdev-clock.h" +#include "hw/qdev-core.h" +#include "qapi/error.h" + +/* + * qdev_init_clocklist: + * Add a new clock in a device + */ +static NamedClockList *qdev_init_clocklist(DeviceState *dev, const char *name, + bool output, Clock *clk) +{ + NamedClockList *ncl; + + /* + * Clock must be added before realize() so that we can compute the + * clock's canonical path during device_realize(). + */ + assert(!dev->realized); + + /* + * The ncl structure is freed by qdev_finalize_clocklist() which will + * be called during @dev's device_finalize(). + */ + ncl = g_new0(NamedClockList, 1); + ncl->name = g_strdup(name); + ncl->output = output; + ncl->alias = (clk != NULL); + + /* + * Trying to create a clock whose name clashes with some other + * clock or property is a bug in the caller and we will abort(). + */ + if (clk == NULL) { + clk = CLOCK(object_new(TYPE_CLOCK)); + object_property_add_child(OBJECT(dev), name, OBJECT(clk), &error_abort); + if (output) { + /* + * Remove object_new()'s initial reference. + * Note that for inputs, the reference created by object_new() + * will be deleted in qdev_finalize_clocklist(). + */ + object_unref(OBJECT(clk)); + } + } else { + object_property_add_link(OBJECT(dev), name, + object_get_typename(OBJECT(clk)), + (Object **) &ncl->clock, + NULL, OBJ_PROP_LINK_STRONG, &error_abort); + } + + ncl->clock = clk; + + QLIST_INSERT_HEAD(&dev->clocks, ncl, node); + return ncl; +} + +void qdev_finalize_clocklist(DeviceState *dev) +{ + /* called by @dev's device_finalize() */ + NamedClockList *ncl, *ncl_next; + + QLIST_FOREACH_SAFE(ncl, &dev->clocks, node, ncl_next) { + QLIST_REMOVE(ncl, node); + if (!ncl->output && !ncl->alias) { + /* + * We kept a reference on the input clock to ensure it lives up to + * this point so we can safely remove the callback. + * It avoids having a callback to a deleted object if ncl->clock + * is still referenced somewhere else (eg: by a clock output). + */ + clock_clear_callback(ncl->clock); + object_unref(OBJECT(ncl->clock)); + } + g_free(ncl->name); + g_free(ncl); + } +} + +Clock *qdev_init_clock_out(DeviceState *dev, const char *name) +{ + NamedClockList *ncl; + + assert(name); + + ncl = qdev_init_clocklist(dev, name, true, NULL); + + return ncl->clock; +} + +Clock *qdev_init_clock_in(DeviceState *dev, const char *name, + ClockCallback *callback, void *opaque) +{ + NamedClockList *ncl; + + assert(name); + + ncl = qdev_init_clocklist(dev, name, false, NULL); + + if (callback) { + clock_set_callback(ncl->clock, callback, opaque); + } + return ncl->clock; +} + +static NamedClockList *qdev_get_clocklist(DeviceState *dev, const char *name) +{ + NamedClockList *ncl; + + QLIST_FOREACH(ncl, &dev->clocks, node) { + if (strcmp(name, ncl->name) == 0) { + return ncl; + } + } + + return NULL; +} + +Clock *qdev_get_clock_in(DeviceState *dev, const char *name) +{ + NamedClockList *ncl; + + assert(name); + + ncl = qdev_get_clocklist(dev, name); + assert(!ncl->output); + + return ncl->clock; +} + +Clock *qdev_get_clock_out(DeviceState *dev, const char *name) +{ + NamedClockList *ncl; + + assert(name); + + ncl = qdev_get_clocklist(dev, name); + assert(ncl->output); + + return ncl->clock; +} + +Clock *qdev_alias_clock(DeviceState *dev, const char *name, + DeviceState *alias_dev, const char *alias_name) +{ + NamedClockList *ncl; + + assert(name && alias_name); + + ncl = qdev_get_clocklist(dev, name); + + qdev_init_clocklist(alias_dev, alias_name, ncl->output, ncl->clock); + + return ncl->clock; +} diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 85f062def7..dd77a56067 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -37,6 +37,7 @@ #include "hw/qdev-properties.h" #include "hw/boards.h" #include "hw/sysbus.h" +#include "hw/qdev-clock.h" #include "migration/vmstate.h" #include "trace.h" @@ -855,6 +856,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) DeviceClass *dc = DEVICE_GET_CLASS(dev); HotplugHandler *hotplug_ctrl; BusState *bus; + NamedClockList *ncl; Error *local_err = NULL; bool unattached_parent = false; static int unattached_count; @@ -902,6 +904,13 @@ static void device_set_realized(Object *obj, bool value, Error **errp) */ g_free(dev->canonical_path); dev->canonical_path = object_get_canonical_path(OBJECT(dev)); + QLIST_FOREACH(ncl, &dev->clocks, node) { + if (ncl->alias) { + continue; + } else { + clock_setup_canonical_path(ncl->clock); + } + } if (qdev_get_vmsd(dev)) { if (vmstate_register_with_alias_id(VMSTATE_IF(dev), @@ -1025,6 +1034,7 @@ static void device_initfn(Object *obj) dev->allow_unplug_during_migration = false; QLIST_INIT(&dev->gpios); + QLIST_INIT(&dev->clocks); } static void device_post_init(Object *obj) @@ -1054,6 +1064,8 @@ static void device_finalize(Object *obj) */ } + qdev_finalize_clocklist(dev); + /* Only send event if the device had been completely realized */ if (dev->pending_deleted_event) { g_assert(dev->canonical_path); diff --git a/include/hw/qdev-clock.h b/include/hw/qdev-clock.h new file mode 100644 index 0000000000..b3b3a3e021 --- /dev/null +++ b/include/hw/qdev-clock.h @@ -0,0 +1,104 @@ +/* + * Device's clock input and output + * + * Copyright GreenSocs 2016-2020 + * + * Authors: + * Frederic Konrad + * Damien Hedde + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QDEV_CLOCK_H +#define QDEV_CLOCK_H + +#include "hw/clock.h" + +/** + * qdev_init_clock_in: + * @dev: the device to add an input clock to + * @name: the name of the clock (can't be NULL). + * @callback: optional callback to be called on update or NULL. + * @opaque: argument for the callback + * @returns: a pointer to the newly added clock + * + * Add an input clock to device @dev as a clock named @name. + * This adds a child<> property. + * The callback will be called with @opaque as opaque parameter. + */ +Clock *qdev_init_clock_in(DeviceState *dev, const char *name, + ClockCallback *callback, void *opaque); + +/** + * qdev_init_clock_out: + * @dev: the device to add an output clock to + * @name: the name of the clock (can't be NULL). + * @returns: a pointer to the newly added clock + * + * Add an output clock to device @dev as a clock named @name. + * This adds a child<> property. + */ +Clock *qdev_init_clock_out(DeviceState *dev, const char *name); + +/** + * qdev_get_clock_in: + * @dev: the device which has the clock + * @name: the name of the clock (can't be NULL). + * @returns: a pointer to the clock + * + * Get the input clock @name from @dev or NULL if does not exist. + */ +Clock *qdev_get_clock_in(DeviceState *dev, const char *name); + +/** + * qdev_get_clock_out: + * @dev: the device which has the clock + * @name: the name of the clock (can't be NULL). + * @returns: a pointer to the clock + * + * Get the output clock @name from @dev or NULL if does not exist. + */ +Clock *qdev_get_clock_out(DeviceState *dev, const char *name); + +/** + * qdev_connect_clock_in: + * @dev: a device + * @name: the name of an input clock in @dev + * @source: the source clock (an output clock of another device for example) + * + * Set the source clock of input clock @name of device @dev to @source. + * @source period update will be propagated to @name clock. + */ +static inline void qdev_connect_clock_in(DeviceState *dev, const char *name, + Clock *source) +{ + clock_set_source(qdev_get_clock_in(dev, name), source); +} + +/** + * qdev_alias_clock: + * @dev: the device which has the clock + * @name: the name of the clock in @dev (can't be NULL) + * @alias_dev: the device to add the clock + * @alias_name: the name of the clock in @container + * @returns: a pointer to the clock + * + * Add a clock @alias_name in @alias_dev which is an alias of the clock @name + * in @dev. The direction _in_ or _out_ will the same as the original. + * An alias clock must not be modified or used by @alias_dev and should + * typically be only only for device composition purpose. + */ +Clock *qdev_alias_clock(DeviceState *dev, const char *name, + DeviceState *alias_dev, const char *alias_name); + +/** + * qdev_finalize_clocklist: + * @dev: the device being finalized + * + * Clear the clocklist from @dev. Only used internally in qdev. + */ +void qdev_finalize_clocklist(DeviceState *dev); + +#endif /* QDEV_CLOCK_H */ diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 1405b8a990..d87d989e72 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -149,6 +149,17 @@ struct NamedGPIOList { QLIST_ENTRY(NamedGPIOList) node; }; +typedef struct Clock Clock; +typedef struct NamedClockList NamedClockList; + +struct NamedClockList { + char *name; + Clock *clock; + bool output; + bool alias; + QLIST_ENTRY(NamedClockList) node; +}; + /** * DeviceState: * @realized: Indicates whether the device has been fully constructed. @@ -171,6 +182,7 @@ struct DeviceState { bool allow_unplug_during_migration; BusState *parent_bus; QLIST_HEAD(, NamedGPIOList) gpios; + QLIST_HEAD(, NamedClockList) clocks; QLIST_HEAD(, BusState) child_bus; int num_child_bus; int instance_id_alias; diff --git a/tests/Makefile.include b/tests/Makefile.include index 51de676298..03a74b60f6 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -439,6 +439,7 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ hw/core/fw-path-provider.o \ hw/core/reset.o \ hw/core/vmstate-if.o \ + hw/core/clock.o hw/core/qdev-clock.o \ $(test-qapi-obj-y) tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ migration/vmstate.o migration/vmstate-types.o migration/qemu-file.o \ From f0bc2a64c08b94e1333b0a210f19f1a43bd2f412 Mon Sep 17 00:00:00 2001 From: Damien Hedde Date: Mon, 6 Apr 2020 15:52:46 +0200 Subject: [PATCH 0106/2595] qdev-clock: introduce an init array to ease the device construction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a function and macro helpers to setup several clocks in a device from a static array description. An element of the array describes the clock (name and direction) as well as the related callback and an optional offset to store the created object pointer in the device state structure. The array must be terminated by a special element QDEV_CLOCK_END. This is based on the original work of Frederic Konrad. Signed-off-by: Damien Hedde Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Message-id: 20200406135251.157596-5-damien.hedde@greensocs.com Signed-off-by: Peter Maydell --- hw/core/qdev-clock.c | 17 +++++++++++++ include/hw/qdev-clock.h | 55 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c index 62035aef83..a94cc44437 100644 --- a/hw/core/qdev-clock.c +++ b/hw/core/qdev-clock.c @@ -116,6 +116,23 @@ Clock *qdev_init_clock_in(DeviceState *dev, const char *name, return ncl->clock; } +void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks) +{ + const struct ClockPortInitElem *elem; + + for (elem = &clocks[0]; elem->name != NULL; elem++) { + Clock **clkp; + /* offset cannot be inside the DeviceState part */ + assert(elem->offset > sizeof(DeviceState)); + clkp = (Clock **)(((void *) dev) + elem->offset); + if (elem->is_output) { + *clkp = qdev_init_clock_out(dev, elem->name); + } else { + *clkp = qdev_init_clock_in(dev, elem->name, elem->callback, dev); + } + } +} + static NamedClockList *qdev_get_clocklist(DeviceState *dev, const char *name) { NamedClockList *ncl; diff --git a/include/hw/qdev-clock.h b/include/hw/qdev-clock.h index b3b3a3e021..a340f65ff9 100644 --- a/include/hw/qdev-clock.h +++ b/include/hw/qdev-clock.h @@ -101,4 +101,59 @@ Clock *qdev_alias_clock(DeviceState *dev, const char *name, */ void qdev_finalize_clocklist(DeviceState *dev); +/** + * ClockPortInitElem: + * @name: name of the clock (can't be NULL) + * @output: indicates whether the clock is input or output + * @callback: for inputs, optional callback to be called on clock's update + * with device as opaque + * @offset: optional offset to store the ClockIn or ClockOut pointer in device + * state structure (0 means unused) + */ +struct ClockPortInitElem { + const char *name; + bool is_output; + ClockCallback *callback; + size_t offset; +}; + +#define clock_offset_value(devstate, field) \ + (offsetof(devstate, field) + \ + type_check(Clock *, typeof_field(devstate, field))) + +#define QDEV_CLOCK(out_not_in, devstate, field, cb) { \ + .name = (stringify(field)), \ + .is_output = out_not_in, \ + .callback = cb, \ + .offset = clock_offset_value(devstate, field), \ +} + +/** + * QDEV_CLOCK_(IN|OUT): + * @devstate: structure type. @dev argument of qdev_init_clocks below must be + * a pointer to that same type. + * @field: a field in @_devstate (must be Clock*) + * @callback: (for input only) callback (or NULL) to be called with the device + * state as argument + * + * The name of the clock will be derived from @field + */ +#define QDEV_CLOCK_IN(devstate, field, callback) \ + QDEV_CLOCK(false, devstate, field, callback) + +#define QDEV_CLOCK_OUT(devstate, field) \ + QDEV_CLOCK(true, devstate, field, NULL) + +#define QDEV_CLOCK_END { .name = NULL } + +typedef struct ClockPortInitElem ClockPortInitArray[]; + +/** + * qdev_init_clocks: + * @dev: the device to add clocks to + * @clocks: a QDEV_CLOCK_END-terminated array which contains the + * clocks information. + */ +void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks); + #endif /* QDEV_CLOCK_H */ From 31e5784a0d822269dc2674495f9f17e3ee0fb68f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 17 Apr 2020 16:56:33 +0100 Subject: [PATCH 0107/2595] docs/clocks: add device's clock documentation Add the documentation about the clock inputs and outputs in devices. This is based on the original work of Frederic Konrad. Signed-off-by: Damien Hedde Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Message-id: 20200406135251.157596-6-damien.hedde@greensocs.com [PMM: Editing pass for minor grammar, style and Sphinx formatting fixes] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- docs/devel/clocks.rst | 391 ++++++++++++++++++++++++++++++++++++++++++ docs/devel/index.rst | 1 + 2 files changed, 392 insertions(+) create mode 100644 docs/devel/clocks.rst diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst new file mode 100644 index 0000000000..e5da28e211 --- /dev/null +++ b/docs/devel/clocks.rst @@ -0,0 +1,391 @@ +Modelling a clock tree in QEMU +============================== + +What are clocks? +---------------- + +Clocks are QOM objects developed for the purpose of modelling the +distribution of clocks in QEMU. + +They allow us to model the clock distribution of a platform and detect +configuration errors in the clock tree such as badly configured PLL, clock +source selection or disabled clock. + +The object is *Clock* and its QOM name is ``clock`` (in C code, the macro +``TYPE_CLOCK``). + +Clocks are typically used with devices where they are used to model inputs +and outputs. They are created in a similar way to GPIOs. Inputs and outputs +of different devices can be connected together. + +In these cases a Clock object is a child of a Device object, but this +is not a requirement. Clocks can be independent of devices. For +example it is possible to create a clock outside of any device to +model the main clock source of a machine. + +Here is an example of clocks:: + + +---------+ +----------------------+ +--------------+ + | Clock 1 | | Device B | | Device C | + | | | +-------+ +-------+ | | +-------+ | + | |>>-+-->>|Clock 2| |Clock 3|>>--->>|Clock 6| | + +---------+ | | | (in) | | (out) | | | | (in) | | + | | +-------+ +-------+ | | +-------+ | + | | +-------+ | +--------------+ + | | |Clock 4|>> + | | | (out) | | +--------------+ + | | +-------+ | | Device D | + | | +-------+ | | +-------+ | + | | |Clock 5|>>--->>|Clock 7| | + | | | (out) | | | | (in) | | + | | +-------+ | | +-------+ | + | +----------------------+ | | + | | +-------+ | + +----------------------------->>|Clock 8| | + | | (in) | | + | +-------+ | + +--------------+ + +Clocks are defined in the ``include/hw/clock.h`` header and device +related functions are defined in the ``include/hw/qdev-clock.h`` +header. + +The clock state +--------------- + +The state of a clock is its period; it is stored as an integer +representing it in units of 2 :sup:`-32` ns. The special value of 0 is used to +represent the clock being inactive or gated. The clocks do not model +the signal itself (pin toggling) or other properties such as the duty +cycle. + +All clocks contain this state: outputs as well as inputs. This allows +the current period of a clock to be fetched at any time. When a clock +is updated, the value is immediately propagated to all connected +clocks in the tree. + +To ease interaction with clocks, helpers with a unit suffix are defined for +every clock state setter or getter. The suffixes are: + +- ``_ns`` for handling periods in nanoseconds +- ``_hz`` for handling frequencies in hertz + +The 0 period value is converted to 0 in hertz and vice versa. 0 always means +that the clock is disabled. + +Adding a new clock +------------------ + +Adding clocks to a device must be done during the init method of the Device +instance. + +To add an input clock to a device, the function ``qdev_init_clock_in()`` +must be used. It takes the name, a callback and an opaque parameter +for the callback (this will be explained in a following section). +Output is simpler; only the name is required. Typically:: + + qdev_init_clock_in(DEVICE(dev), "clk_in", clk_in_callback, dev); + qdev_init_clock_out(DEVICE(dev), "clk_out"); + +Both functions return the created Clock pointer, which should be saved in the +device's state structure for further use. + +These objects will be automatically deleted by the QOM reference mechanism. + +Note that it is possible to create a static array describing clock inputs and +outputs. The function ``qdev_init_clocks()`` must be called with the array as +parameter to initialize the clocks: it has the same behaviour as calling the +``qdev_init_clock_in/out()`` for each clock in the array. To ease the array +construction, some macros are defined in ``include/hw/qdev-clock.h``. +As an example, the following creates 2 clocks to a device: one input and one +output. + +.. code-block:: c + + /* device structure containing pointers to the clock objects */ + typedef struct MyDeviceState { + DeviceState parent_obj; + Clock *clk_in; + Clock *clk_out; + } MyDeviceState; + + /* + * callback for the input clock (see "Callback on input clock + * change" section below for more information). + */ + static void clk_in_callback(void *opaque); + + /* + * static array describing clocks: + * + a clock input named "clk_in", whose pointer is stored in + * the clk_in field of a MyDeviceState structure with callback + * clk_in_callback. + * + a clock output named "clk_out" whose pointer is stored in + * the clk_out field of a MyDeviceState structure. + */ + static const ClockPortInitArray mydev_clocks = { + QDEV_CLOCK_IN(MyDeviceState, clk_in, clk_in_callback), + QDEV_CLOCK_OUT(MyDeviceState, clk_out), + QDEV_CLOCK_END + }; + + /* device initialization function */ + static void mydev_init(Object *obj) + { + /* cast to MyDeviceState */ + MyDeviceState *mydev = MYDEVICE(obj); + /* create and fill the pointer fields in the MyDeviceState */ + qdev_init_clocks(mydev, mydev_clocks); + [...] + } + +An alternative way to create a clock is to simply call +``object_new(TYPE_CLOCK)``. In that case the clock will neither be an +input nor an output of a device. After the whole QOM hierarchy of the +clock has been set ``clock_setup_canonical_path()`` should be called. + +At creation, the period of the clock is 0: the clock is disabled. You can +change it using ``clock_set_ns()`` or ``clock_set_hz()``. + +Note that if you are creating a clock with a fixed period which will never +change (for example the main clock source of a board), then you'll have +nothing else to do. This value will be propagated to other clocks when +connecting the clocks together and devices will fetch the right value during +the first reset. + +Retrieving clocks from a device +------------------------------- + +``qdev_get_clock_in()`` and ``dev_get_clock_out()`` are available to +get the clock inputs or outputs of a device. For example: + +.. code-block:: c + + Clock *clk = qdev_get_clock_in(DEVICE(mydev), "clk_in"); + +or: + +.. code-block:: c + + Clock *clk = qdev_get_clock_out(DEVICE(mydev), "clk_out"); + +Connecting two clocks together +------------------------------ + +To connect two clocks together, use the ``clock_set_source()`` function. +Given two clocks ``clk1``, and ``clk2``, ``clock_set_source(clk2, clk1);`` +configures ``clk2`` to follow the ``clk1`` period changes. Every time ``clk1`` +is updated, ``clk2`` will be updated too. + +When connecting clock between devices, prefer using the +``qdev_connect_clock_in()`` function to set the source of an input +device clock. For example, to connect the input clock ``clk2`` of +``devB`` to the output clock ``clk1`` of ``devA``, do: + +.. code-block:: c + + qdev_connect_clock_in(devB, "clk2", qdev_get_clock_out(devA, "clk1")) + +We used ``qdev_get_clock_out()`` above, but any clock can drive an +input clock, even another input clock. The following diagram shows +some examples of connections. Note also that a clock can drive several +other clocks. + +:: + + +------------+ +--------------------------------------------------+ + | Device A | | Device B | + | | | +---------------------+ | + | | | | Device C | | + | +-------+ | | +-------+ | +-------+ +-------+ | +-------+ | + | |Clock 1|>>-->>|Clock 2|>>+-->>|Clock 3| |Clock 5|>>>>|Clock 6|>> + | | (out) | | | | (in) | | | | (in) | | (out) | | | (out) | | + | +-------+ | | +-------+ | | +-------+ +-------+ | +-------+ | + +------------+ | | +---------------------+ | + | | | + | | +--------------+ | + | | | Device D | | + | | | +-------+ | | + | +-->>|Clock 4| | | + | | | (in) | | | + | | +-------+ | | + | +--------------+ | + +--------------------------------------------------+ + +In the above example, when *Clock 1* is updated by *Device A*, three +clocks get the new clock period value: *Clock 2*, *Clock 3* and *Clock 4*. + +It is not possible to disconnect a clock or to change the clock connection +after it is connected. + +Unconnected input clocks +------------------------ + +A newly created input clock is disabled (period of 0). This means the +clock will be considered as disabled until the period is updated. If +the clock remains unconnected it will always keep its initial value +of 0. If this is not the desired behaviour, ``clock_set()``, +``clock_set_ns()`` or ``clock_set_hz()`` should be called on the Clock +object during device instance init. For example: + +.. code-block:: c + + clk = qdev_init_clock_in(DEVICE(dev), "clk-in", clk_in_callback, + dev); + /* set initial value to 10ns / 100MHz */ + clock_set_ns(clk, 10); + +Fetching clock frequency/period +------------------------------- + +To get the current state of a clock, use the functions ``clock_get()``, +``clock_get_ns()`` or ``clock_get_hz()``. + +It is also possible to register a callback on clock frequency changes. +Here is an example: + +.. code-block:: c + + void clock_callback(void *opaque) { + MyDeviceState *s = (MyDeviceState *) opaque; + /* + * 'opaque' is the argument passed to qdev_init_clock_in(); + * usually this will be the device state pointer. + */ + + /* do something with the new period */ + fprintf(stdout, "device new period is %" PRIu64 "ns\n", + clock_get_ns(dev->my_clk_input)); + } + +Changing a clock period +----------------------- + +A device can change its outputs using the ``clock_update()``, +``clock_update_ns()`` or ``clock_update_hz()`` function. It will trigger +updates on every connected input. + +For example, let's say that we have an output clock *clkout* and we +have a pointer to it in the device state because we did the following +in init phase: + +.. code-block:: c + + dev->clkout = qdev_init_clock_out(DEVICE(dev), "clkout"); + +Then at any time (apart from the cases listed below), it is possible to +change the clock value by doing: + +.. code-block:: c + + clock_update_hz(dev->clkout, 1000 * 1000 * 1000); /* 1GHz */ + +Because updating a clock may trigger any side effects through +connected clocks and their callbacks, this operation must be done +while holding the qemu io lock. + +For the same reason, one can update clocks only when it is allowed to have +side effects on other objects. In consequence, it is forbidden: + +* during migration, +* and in the enter phase of reset. + +Note that calling ``clock_update[_ns|_hz]()`` is equivalent to calling +``clock_set[_ns|_hz]()`` (with the same arguments) then +``clock_propagate()`` on the clock. Thus, setting the clock value can +be separated from triggering the side-effects. This is often required +to factorize code to handle reset and migration in devices. + +Aliasing clocks +--------------- + +Sometimes, one needs to forward, or inherit, a clock from another +device. Typically, when doing device composition, a device might +expose a sub-device's clock without interfering with it. The function +``qdev_alias_clock()`` can be used to achieve this behaviour. Note +that it is possible to expose the clock under a different name. +``qdev_alias_clock()`` works for both input and output clocks. + +For example, if device B is a child of device A, +``device_a_instance_init()`` may do something like this: + +.. code-block:: c + + void device_a_instance_init(Object *obj) + { + AState *A = DEVICE_A(obj); + BState *B; + /* create object B as child of A */ + [...] + qdev_alias_clock(B, "clk", A, "b_clk"); + /* + * Now A has a clock "b_clk" which is an alias to + * the clock "clk" of its child B. + */ + } + +This function does not return any clock object. The new clock has the +same direction (input or output) as the original one. This function +only adds a link to the existing clock. In the above example, object B +remains the only object allowed to use the clock and device A must not +try to change the clock period or set a callback to the clock. This +diagram describes the example with an input clock:: + + +--------------------------+ + | Device A | + | +--------------+ | + | | Device B | | + | | +-------+ | | + >>"b_clk">>>| "clk" | | | + | (in) | | (in) | | | + | | +-------+ | | + | +--------------+ | + +--------------------------+ + +Migration +--------- + +Clock state is not migrated automatically. Every device must handle its +clock migration. Alias clocks must not be migrated. + +To ensure clock states are restored correctly during migration, there +are two solutions. + +Clock states can be migrated by adding an entry into the device +vmstate description. You should use the ``VMSTATE_CLOCK`` macro for this. +This is typically used to migrate an input clock state. For example: + +.. code-block:: c + + MyDeviceState { + DeviceState parent_obj; + [...] /* some fields */ + Clock *clk; + }; + + VMStateDescription my_device_vmstate = { + .name = "my_device", + .fields = (VMStateField[]) { + [...], /* other migrated fields */ + VMSTATE_CLOCK(clk, MyDeviceState), + VMSTATE_END_OF_LIST() + } + }; + +The second solution is to restore the clock state using information already +at our disposal. This can be used to restore output clock states using the +device state. The functions ``clock_set[_ns|_hz]()`` can be used during the +``post_load()`` migration callback. + +When adding clock support to an existing device, if you care about +migration compatibility you will need to be careful, as simply adding +a ``VMSTATE_CLOCK()`` line will break compatibility. Instead, you can +put the ``VMSTATE_CLOCK()`` line into a vmstate subsection with a +suitable ``needed`` function, and use ``clock_set()`` in a +``pre_load()`` function to set the default value that will be used if +the source virtual machine in the migration does not send the clock +state. + +Care should be taken not to use ``clock_update[_ns|_hz]()`` or +``clock_propagate()`` during the whole migration procedure because it +will trigger side effects to other devices in an unknown state. diff --git a/docs/devel/index.rst b/docs/devel/index.rst index a9e1200dff..bb8238c5d6 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -27,3 +27,4 @@ Contents: bitops reset s390-dasd-ipl + clocks From 38867cb7ec90253289cab22c13282a3ef6530f69 Mon Sep 17 00:00:00 2001 From: Damien Hedde Date: Mon, 6 Apr 2020 15:52:48 +0200 Subject: [PATCH 0108/2595] hw/misc/zynq_slcr: add clock generation for uarts Add some clocks to zynq_slcr + the main input clock (ps_clk) + the reference clock outputs for each uart (uart0 & 1) This commit also transitional the slcr to multi-phase reset as it is required to initialize the clocks correctly. The clock frequencies are computed using the internal pll & uart configuration registers and the input ps_clk frequency. Signed-off-by: Damien Hedde Reviewed-by: Edgar E. Iglesias Acked-by: Alistair Francis Message-id: 20200406135251.157596-7-damien.hedde@greensocs.com Signed-off-by: Peter Maydell --- hw/misc/zynq_slcr.c | 172 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 168 insertions(+), 4 deletions(-) diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index b9a38272d9..f7472d1f3c 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -22,6 +22,7 @@ #include "qemu/log.h" #include "qemu/module.h" #include "hw/registerfields.h" +#include "hw/qdev-clock.h" #ifndef ZYNQ_SLCR_ERR_DEBUG #define ZYNQ_SLCR_ERR_DEBUG 0 @@ -45,6 +46,12 @@ REG32(LOCKSTA, 0x00c) REG32(ARM_PLL_CTRL, 0x100) REG32(DDR_PLL_CTRL, 0x104) REG32(IO_PLL_CTRL, 0x108) +/* fields for [ARM|DDR|IO]_PLL_CTRL registers */ + FIELD(xxx_PLL_CTRL, PLL_RESET, 0, 1) + FIELD(xxx_PLL_CTRL, PLL_PWRDWN, 1, 1) + FIELD(xxx_PLL_CTRL, PLL_BYPASS_QUAL, 3, 1) + FIELD(xxx_PLL_CTRL, PLL_BYPASS_FORCE, 4, 1) + FIELD(xxx_PLL_CTRL, PLL_FPDIV, 12, 7) REG32(PLL_STATUS, 0x10c) REG32(ARM_PLL_CFG, 0x110) REG32(DDR_PLL_CFG, 0x114) @@ -64,6 +71,10 @@ REG32(SMC_CLK_CTRL, 0x148) REG32(LQSPI_CLK_CTRL, 0x14c) REG32(SDIO_CLK_CTRL, 0x150) REG32(UART_CLK_CTRL, 0x154) + FIELD(UART_CLK_CTRL, CLKACT0, 0, 1) + FIELD(UART_CLK_CTRL, CLKACT1, 1, 1) + FIELD(UART_CLK_CTRL, SRCSEL, 4, 2) + FIELD(UART_CLK_CTRL, DIVISOR, 8, 6) REG32(SPI_CLK_CTRL, 0x158) REG32(CAN_CLK_CTRL, 0x15c) REG32(CAN_MIOCLK_CTRL, 0x160) @@ -179,11 +190,127 @@ typedef struct ZynqSLCRState { MemoryRegion iomem; uint32_t regs[ZYNQ_SLCR_NUM_REGS]; + + Clock *ps_clk; + Clock *uart0_ref_clk; + Clock *uart1_ref_clk; } ZynqSLCRState; -static void zynq_slcr_reset(DeviceState *d) +/* + * return the output frequency of ARM/DDR/IO pll + * using input frequency and PLL_CTRL register + */ +static uint64_t zynq_slcr_compute_pll(uint64_t input, uint32_t ctrl_reg) { - ZynqSLCRState *s = ZYNQ_SLCR(d); + uint32_t mult = ((ctrl_reg & R_xxx_PLL_CTRL_PLL_FPDIV_MASK) >> + R_xxx_PLL_CTRL_PLL_FPDIV_SHIFT); + + /* first, check if pll is bypassed */ + if (ctrl_reg & R_xxx_PLL_CTRL_PLL_BYPASS_FORCE_MASK) { + return input; + } + + /* is pll disabled ? */ + if (ctrl_reg & (R_xxx_PLL_CTRL_PLL_RESET_MASK | + R_xxx_PLL_CTRL_PLL_PWRDWN_MASK)) { + return 0; + } + + /* frequency multiplier -> period division */ + return input / mult; +} + +/* + * return the output period of a clock given: + * + the periods in an array corresponding to input mux selector + * + the register xxx_CLK_CTRL value + * + enable bit index in ctrl register + * + * This function makes the assumption that the ctrl_reg value is organized as + * follows: + * + bits[13:8] clock frequency divisor + * + bits[5:4] clock mux selector (index in array) + * + bits[index] clock enable + */ +static uint64_t zynq_slcr_compute_clock(const uint64_t periods[], + uint32_t ctrl_reg, + unsigned index) +{ + uint32_t srcsel = extract32(ctrl_reg, 4, 2); /* bits [5:4] */ + uint32_t divisor = extract32(ctrl_reg, 8, 6); /* bits [13:8] */ + + /* first, check if clock is disabled */ + if (((ctrl_reg >> index) & 1u) == 0) { + return 0; + } + + /* + * according to the Zynq technical ref. manual UG585 v1.12.2 in + * Clocks chapter, section 25.10.1 page 705: + * "The 6-bit divider provides a divide range of 1 to 63" + * We follow here what is implemented in linux kernel and consider + * the 0 value as a bypass (no division). + */ + /* frequency divisor -> period multiplication */ + return periods[srcsel] * (divisor ? divisor : 1u); +} + +/* + * macro helper around zynq_slcr_compute_clock to avoid repeating + * the register name. + */ +#define ZYNQ_COMPUTE_CLK(state, plls, reg, enable_field) \ + zynq_slcr_compute_clock((plls), (state)->regs[reg], \ + reg ## _ ## enable_field ## _SHIFT) + +/** + * Compute and set the ouputs clocks periods. + * But do not propagate them further. Connected clocks + * will not receive any updates (See zynq_slcr_compute_clocks()) + */ +static void zynq_slcr_compute_clocks(ZynqSLCRState *s) +{ + uint64_t ps_clk = clock_get(s->ps_clk); + + /* consider outputs clocks are disabled while in reset */ + if (device_is_in_reset(DEVICE(s))) { + ps_clk = 0; + } + + uint64_t io_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_IO_PLL_CTRL]); + uint64_t arm_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_ARM_PLL_CTRL]); + uint64_t ddr_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_DDR_PLL_CTRL]); + + uint64_t uart_mux[4] = {io_pll, io_pll, arm_pll, ddr_pll}; + + /* compute uartX reference clocks */ + clock_set(s->uart0_ref_clk, + ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT0)); + clock_set(s->uart1_ref_clk, + ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT1)); +} + +/** + * Propagate the outputs clocks. + * zynq_slcr_compute_clocks() should have been called before + * to configure them. + */ +static void zynq_slcr_propagate_clocks(ZynqSLCRState *s) +{ + clock_propagate(s->uart0_ref_clk); + clock_propagate(s->uart1_ref_clk); +} + +static void zynq_slcr_ps_clk_callback(void *opaque) +{ + ZynqSLCRState *s = (ZynqSLCRState *) opaque; + zynq_slcr_compute_clocks(s); + zynq_slcr_propagate_clocks(s); +} + +static void zynq_slcr_reset_init(Object *obj, ResetType type) +{ + ZynqSLCRState *s = ZYNQ_SLCR(obj); int i; DB_PRINT("RESET\n"); @@ -277,6 +404,23 @@ static void zynq_slcr_reset(DeviceState *d) s->regs[R_DDRIOB + 12] = 0x00000021; } +static void zynq_slcr_reset_hold(Object *obj) +{ + ZynqSLCRState *s = ZYNQ_SLCR(obj); + + /* will disable all output clocks */ + zynq_slcr_compute_clocks(s); + zynq_slcr_propagate_clocks(s); +} + +static void zynq_slcr_reset_exit(Object *obj) +{ + ZynqSLCRState *s = ZYNQ_SLCR(obj); + + /* will compute output clocks according to ps_clk and registers */ + zynq_slcr_compute_clocks(s); + zynq_slcr_propagate_clocks(s); +} static bool zynq_slcr_check_offset(hwaddr offset, bool rnw) { @@ -409,6 +553,13 @@ static void zynq_slcr_write(void *opaque, hwaddr offset, qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); } break; + case R_IO_PLL_CTRL: + case R_ARM_PLL_CTRL: + case R_DDR_PLL_CTRL: + case R_UART_CLK_CTRL: + zynq_slcr_compute_clocks(s); + zynq_slcr_propagate_clocks(s); + break; } } @@ -418,6 +569,13 @@ static const MemoryRegionOps slcr_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static const ClockPortInitArray zynq_slcr_clocks = { + QDEV_CLOCK_IN(ZynqSLCRState, ps_clk, zynq_slcr_ps_clk_callback), + QDEV_CLOCK_OUT(ZynqSLCRState, uart0_ref_clk), + QDEV_CLOCK_OUT(ZynqSLCRState, uart1_ref_clk), + QDEV_CLOCK_END +}; + static void zynq_slcr_init(Object *obj) { ZynqSLCRState *s = ZYNQ_SLCR(obj); @@ -425,14 +583,17 @@ static void zynq_slcr_init(Object *obj) memory_region_init_io(&s->iomem, obj, &slcr_ops, s, "slcr", ZYNQ_SLCR_MMIO_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); + + qdev_init_clocks(DEVICE(obj), zynq_slcr_clocks); } static const VMStateDescription vmstate_zynq_slcr = { .name = "zynq_slcr", - .version_id = 2, + .version_id = 3, .minimum_version_id = 2, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, ZynqSLCRState, ZYNQ_SLCR_NUM_REGS), + VMSTATE_CLOCK_V(ps_clk, ZynqSLCRState, 3), VMSTATE_END_OF_LIST() } }; @@ -440,9 +601,12 @@ static const VMStateDescription vmstate_zynq_slcr = { static void zynq_slcr_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); dc->vmsd = &vmstate_zynq_slcr; - dc->reset = zynq_slcr_reset; + rc->phases.enter = zynq_slcr_reset_init; + rc->phases.hold = zynq_slcr_reset_hold; + rc->phases.exit = zynq_slcr_reset_exit; } static const TypeInfo zynq_slcr_info = { From b636db306e06ee1c267d6e15e3b5bc109252617f Mon Sep 17 00:00:00 2001 From: Damien Hedde Date: Mon, 6 Apr 2020 15:52:49 +0200 Subject: [PATCH 0109/2595] hw/char/cadence_uart: add clock support Switch the cadence uart to multi-phase reset and add the reference clock input. The input clock frequency is added to the migration structure. The reference clock controls the baudrate generation. If it disabled, any input characters and events are ignored. If this clock remains unconnected, the uart behaves as before (it default to a 50MHz ref clock). Signed-off-by: Damien Hedde Reviewed-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Message-id: 20200406135251.157596-8-damien.hedde@greensocs.com Signed-off-by: Peter Maydell --- hw/char/cadence_uart.c | 73 +++++++++++++++++++++++++++++----- hw/char/trace-events | 3 ++ include/hw/char/cadence_uart.h | 1 + 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 22e47972f1..e196906c92 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -31,6 +31,8 @@ #include "qemu/module.h" #include "hw/char/cadence_uart.h" #include "hw/irq.h" +#include "hw/qdev-clock.h" +#include "trace.h" #ifdef CADENCE_UART_ERR_DEBUG #define DB_PRINT(...) do { \ @@ -97,7 +99,7 @@ #define LOCAL_LOOPBACK (0x2 << UART_MR_CHMODE_SH) #define REMOTE_LOOPBACK (0x3 << UART_MR_CHMODE_SH) -#define UART_INPUT_CLK 50000000 +#define UART_DEFAULT_REF_CLK (50 * 1000 * 1000) #define R_CR (0x00/4) #define R_MR (0x04/4) @@ -171,12 +173,15 @@ static void uart_send_breaks(CadenceUARTState *s) static void uart_parameters_setup(CadenceUARTState *s) { QEMUSerialSetParams ssp; - unsigned int baud_rate, packet_size; + unsigned int baud_rate, packet_size, input_clk; + input_clk = clock_get_hz(s->refclk); - baud_rate = (s->r[R_MR] & UART_MR_CLKS) ? - UART_INPUT_CLK / 8 : UART_INPUT_CLK; + baud_rate = (s->r[R_MR] & UART_MR_CLKS) ? input_clk / 8 : input_clk; + baud_rate /= (s->r[R_BRGR] * (s->r[R_BDIV] + 1)); + trace_cadence_uart_baudrate(baud_rate); + + ssp.speed = baud_rate; - ssp.speed = baud_rate / (s->r[R_BRGR] * (s->r[R_BDIV] + 1)); packet_size = 1; switch (s->r[R_MR] & UART_MR_PAR) { @@ -215,6 +220,13 @@ static void uart_parameters_setup(CadenceUARTState *s) } packet_size += ssp.data_bits + ssp.stop_bits; + if (ssp.speed == 0) { + /* + * Avoid division-by-zero below. + * TODO: find something better + */ + ssp.speed = 1; + } s->char_tx_time = (NANOSECONDS_PER_SECOND / ssp.speed) * packet_size; qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); } @@ -340,6 +352,11 @@ static void uart_receive(void *opaque, const uint8_t *buf, int size) CadenceUARTState *s = opaque; uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE; + /* ignore characters when unclocked or in reset */ + if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { + return; + } + if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) { uart_write_rx_fifo(opaque, buf, size); } @@ -353,6 +370,11 @@ static void uart_event(void *opaque, QEMUChrEvent event) CadenceUARTState *s = opaque; uint8_t buf = '\0'; + /* ignore characters when unclocked or in reset */ + if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { + return; + } + if (event == CHR_EVENT_BREAK) { uart_write_rx_fifo(opaque, &buf, 1); } @@ -462,9 +484,9 @@ static const MemoryRegionOps uart_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void cadence_uart_reset(DeviceState *dev) +static void cadence_uart_reset_init(Object *obj, ResetType type) { - CadenceUARTState *s = CADENCE_UART(dev); + CadenceUARTState *s = CADENCE_UART(obj); s->r[R_CR] = 0x00000128; s->r[R_IMR] = 0; @@ -473,6 +495,11 @@ static void cadence_uart_reset(DeviceState *dev) s->r[R_BRGR] = 0x0000028B; s->r[R_BDIV] = 0x0000000F; s->r[R_TTRIG] = 0x00000020; +} + +static void cadence_uart_reset_hold(Object *obj) +{ + CadenceUARTState *s = CADENCE_UART(obj); uart_rx_reset(s); uart_tx_reset(s); @@ -491,6 +518,14 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp) uart_event, NULL, s, NULL, true); } +static void cadence_uart_refclk_update(void *opaque) +{ + CadenceUARTState *s = opaque; + + /* recompute uart's speed on clock change */ + uart_parameters_setup(s); +} + static void cadence_uart_init(Object *obj) { SysBusDevice *sbd = SYS_BUS_DEVICE(obj); @@ -500,9 +535,23 @@ static void cadence_uart_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); + s->refclk = qdev_init_clock_in(DEVICE(obj), "refclk", + cadence_uart_refclk_update, s); + /* initialize the frequency in case the clock remains unconnected */ + clock_set_hz(s->refclk, UART_DEFAULT_REF_CLK); + s->char_tx_time = (NANOSECONDS_PER_SECOND / 9600) * 10; } +static int cadence_uart_pre_load(void *opaque) +{ + CadenceUARTState *s = opaque; + + /* the frequency will be overriden if the refclk field is present */ + clock_set_hz(s->refclk, UART_DEFAULT_REF_CLK); + return 0; +} + static int cadence_uart_post_load(void *opaque, int version_id) { CadenceUARTState *s = opaque; @@ -521,8 +570,9 @@ static int cadence_uart_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_cadence_uart = { .name = "cadence_uart", - .version_id = 2, + .version_id = 3, .minimum_version_id = 2, + .pre_load = cadence_uart_pre_load, .post_load = cadence_uart_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(r, CadenceUARTState, CADENCE_UART_R_MAX), @@ -534,8 +584,9 @@ static const VMStateDescription vmstate_cadence_uart = { VMSTATE_UINT32(tx_count, CadenceUARTState), VMSTATE_UINT32(rx_wpos, CadenceUARTState), VMSTATE_TIMER_PTR(fifo_trigger_handle, CadenceUARTState), + VMSTATE_CLOCK_V(refclk, CadenceUARTState, 3), VMSTATE_END_OF_LIST() - } + }, }; static Property cadence_uart_properties[] = { @@ -546,10 +597,12 @@ static Property cadence_uart_properties[] = { static void cadence_uart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); dc->realize = cadence_uart_realize; dc->vmsd = &vmstate_cadence_uart; - dc->reset = cadence_uart_reset; + rc->phases.enter = cadence_uart_reset_init; + rc->phases.hold = cadence_uart_reset_hold; device_class_set_props(dc, cadence_uart_properties); } diff --git a/hw/char/trace-events b/hw/char/trace-events index 6f938301d9..d20eafd56f 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -97,3 +97,6 @@ exynos_uart_wo_read(uint32_t channel, const char *name, uint32_t reg) "UART%d: T exynos_uart_rxsize(uint32_t channel, uint32_t size) "UART%d: Rx FIFO size: %d" exynos_uart_channel_error(uint32_t channel) "Wrong UART channel number: %d" exynos_uart_rx_timeout(uint32_t channel, uint32_t stat, uint32_t intsp) "UART%d: Rx timeout stat=0x%x intsp=0x%x" + +# hw/char/cadence_uart.c +cadence_uart_baudrate(unsigned baudrate) "baudrate %u" diff --git a/include/hw/char/cadence_uart.h b/include/hw/char/cadence_uart.h index 47cec956c4..2a179a572f 100644 --- a/include/hw/char/cadence_uart.h +++ b/include/hw/char/cadence_uart.h @@ -49,6 +49,7 @@ typedef struct { CharBackend chr; qemu_irq irq; QEMUTimer *fifo_trigger_handle; + Clock *refclk; } CadenceUARTState; static inline DeviceState *cadence_uart_create(hwaddr addr, From 5b49a34c6800d0cb917f959d8e75e5775f0fac3f Mon Sep 17 00:00:00 2001 From: Damien Hedde Date: Mon, 6 Apr 2020 15:52:50 +0200 Subject: [PATCH 0110/2595] hw/arm/xilinx_zynq: connect uart clocks to slcr Add the connection between the slcr's output clocks and the uarts inputs. Also add the main board clock 'ps_clk', which is hard-coded to 33.33MHz (the default frequency). This clock is used to feed the slcr's input clock. Signed-off-by: Damien Hedde Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Message-id: 20200406135251.157596-9-damien.hedde@greensocs.com Signed-off-by: Peter Maydell --- hw/arm/xilinx_zynq.c | 57 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 571cdcd599..91b498dd5d 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -35,6 +35,15 @@ #include "hw/char/cadence_uart.h" #include "hw/net/cadence_gem.h" #include "hw/cpu/a9mpcore.h" +#include "hw/qdev-clock.h" +#include "sysemu/reset.h" + +#define TYPE_ZYNQ_MACHINE MACHINE_TYPE_NAME("xilinx-zynq-a9") +#define ZYNQ_MACHINE(obj) \ + OBJECT_CHECK(ZynqMachineState, (obj), TYPE_ZYNQ_MACHINE) + +/* board base frequency: 33.333333 MHz */ +#define PS_CLK_FREQUENCY (100 * 1000 * 1000 / 3) #define NUM_SPI_FLASHES 4 #define NUM_QSPI_FLASHES 2 @@ -75,6 +84,11 @@ static const int dma_irqs[8] = { 0xe3401000 + ARMV7_IMM16(extract32((val), 16, 16)), /* movt r1 ... */ \ 0xe5801000 + (addr) +typedef struct ZynqMachineState { + MachineState parent; + Clock *ps_clk; +} ZynqMachineState; + static void zynq_write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info) { @@ -159,10 +173,11 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, static void zynq_init(MachineState *machine) { + ZynqMachineState *zynq_machine = ZYNQ_MACHINE(machine); ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ocm_ram = g_new(MemoryRegion, 1); - DeviceState *dev; + DeviceState *dev, *slcr; SysBusDevice *busdev; qemu_irq pic[64]; int n; @@ -206,9 +221,18 @@ static void zynq_init(MachineState *machine) 1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa, 0); - dev = qdev_create(NULL, "xilinx,zynq_slcr"); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000); + /* Create slcr, keep a pointer to connect clocks */ + slcr = qdev_create(NULL, "xilinx,zynq_slcr"); + qdev_init_nofail(slcr); + sysbus_mmio_map(SYS_BUS_DEVICE(slcr), 0, 0xF8000000); + + /* Create the main clock source, and feed slcr with it */ + zynq_machine->ps_clk = CLOCK(object_new(TYPE_CLOCK)); + object_property_add_child(OBJECT(zynq_machine), "ps_clk", + OBJECT(zynq_machine->ps_clk), &error_abort); + object_unref(OBJECT(zynq_machine->ps_clk)); + clock_set_hz(zynq_machine->ps_clk, PS_CLK_FREQUENCY); + qdev_connect_clock_in(slcr, "ps_clk", zynq_machine->ps_clk); dev = qdev_create(NULL, TYPE_A9MPCORE_PRIV); qdev_prop_set_uint32(dev, "num-cpu", 1); @@ -229,8 +253,12 @@ static void zynq_init(MachineState *machine) sysbus_create_simple(TYPE_CHIPIDEA, 0xE0002000, pic[53 - IRQ_OFFSET]); sysbus_create_simple(TYPE_CHIPIDEA, 0xE0003000, pic[76 - IRQ_OFFSET]); - cadence_uart_create(0xE0000000, pic[59 - IRQ_OFFSET], serial_hd(0)); - cadence_uart_create(0xE0001000, pic[82 - IRQ_OFFSET], serial_hd(1)); + dev = cadence_uart_create(0xE0000000, pic[59 - IRQ_OFFSET], serial_hd(0)); + qdev_connect_clock_in(dev, "refclk", + qdev_get_clock_out(slcr, "uart0_ref_clk")); + dev = cadence_uart_create(0xE0001000, pic[82 - IRQ_OFFSET], serial_hd(1)); + qdev_connect_clock_in(dev, "refclk", + qdev_get_clock_out(slcr, "uart1_ref_clk")); sysbus_create_varargs("cadence_ttc", 0xF8001000, pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL); @@ -308,8 +336,9 @@ static void zynq_init(MachineState *machine) arm_load_kernel(ARM_CPU(first_cpu), machine, &zynq_binfo); } -static void zynq_machine_init(MachineClass *mc) +static void zynq_machine_class_init(ObjectClass *oc, void *data) { + MachineClass *mc = MACHINE_CLASS(oc); mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9"; mc->init = zynq_init; mc->max_cpus = 1; @@ -319,4 +348,16 @@ static void zynq_machine_init(MachineClass *mc) mc->default_ram_id = "zynq.ext_ram"; } -DEFINE_MACHINE("xilinx-zynq-a9", zynq_machine_init) +static const TypeInfo zynq_machine_type = { + .name = TYPE_ZYNQ_MACHINE, + .parent = TYPE_MACHINE, + .class_init = zynq_machine_class_init, + .instance_size = sizeof(ZynqMachineState), +}; + +static void zynq_machine_register_types(void) +{ + type_register_static(&zynq_machine_type); +} + +type_init(zynq_machine_register_types) From 9f2ff99c7f2392fe30e9e74d3e26a4c01820f53e Mon Sep 17 00:00:00 2001 From: Damien Hedde Date: Mon, 6 Apr 2020 15:52:51 +0200 Subject: [PATCH 0111/2595] qdev-monitor: print the device's clock with info qtree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prints the clocks attached to a DeviceState when using "info qtree" monitor command. For every clock, it displays the direction, the name and if the clock is forwarded. For input clock, it displays also the frequency. This is based on the original work of Frederic Konrad. Here follows a sample of `info qtree` output on xilinx_zynq machine after linux boot with only one uart clocked: > bus: main-system-bus > type System > [...] > dev: cadence_uart, id "" > gpio-out "sysbus-irq" 1 > clock-in "refclk" freq_hz=0.000000e+00 > chardev = "" > mmio 00000000e0001000/0000000000001000 > dev: cadence_uart, id "" > gpio-out "sysbus-irq" 1 > clock-in "refclk" freq_hz=1.375661e+07 > chardev = "serial0" > mmio 00000000e0000000/0000000000001000 > [...] > dev: xilinx,zynq_slcr, id "" > clock-out "uart1_ref_clk" freq_hz=0.000000e+00 > clock-out "uart0_ref_clk" freq_hz=1.375661e+07 > clock-in "ps_clk" freq_hz=3.333333e+07 > mmio 00000000f8000000/0000000000001000 Signed-off-by: Damien Hedde Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Message-id: 20200406135251.157596-10-damien.hedde@greensocs.com Signed-off-by: Peter Maydell --- qdev-monitor.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/qdev-monitor.c b/qdev-monitor.c index 9833b33549..56cee1483f 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -38,6 +38,7 @@ #include "migration/misc.h" #include "migration/migration.h" #include "qemu/cutils.h" +#include "hw/clock.h" /* * Aliases were a bad idea from the start. Let's keep them @@ -737,6 +738,7 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent) ObjectClass *class; BusState *child; NamedGPIOList *ngl; + NamedClockList *ncl; qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)), dev->id ? dev->id : ""); @@ -751,6 +753,13 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent) ngl->num_out); } } + QLIST_FOREACH(ncl, &dev->clocks, node) { + qdev_printf("clock-%s%s \"%s\" freq_hz=%e\n", + ncl->output ? "out" : "in", + ncl->alias ? " (alias)" : "", + ncl->name, + CLOCK_PERIOD_TO_HZ(1.0 * clock_get(ncl->clock))); + } class = object_get_class(OBJECT(dev)); do { qdev_print_props(mon, dev, DEVICE_CLASS(class)->props_, indent); From 681b5bc32322fd0ff4338c550ec24612512d1a2e Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Fri, 17 Apr 2020 17:38:00 +0200 Subject: [PATCH 0112/2595] hw/arm: versal: Setup the ADMA with 128bit bus-width Setup the ADMA with 128bit bus-width. This matters when FIXED BURST mode is used. Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Reviewed-by: Luc Michel Message-id: 20200417153800.27399-2-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index cb0122a3a6..94460f2343 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -205,6 +205,8 @@ static void versal_create_admas(Versal *s, qemu_irq *pic) dev = qdev_create(NULL, "xlnx.zdma"); s->lpd.iou.adma[i] = SYS_BUS_DEVICE(dev); + object_property_set_int(OBJECT(s->lpd.iou.adma[i]), 128, "bus-width", + &error_abort); object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal); qdev_init_nofail(dev); From f1e7cb1388e46eac8285854af2abdfde41ffa226 Mon Sep 17 00:00:00 2001 From: Ramon Fried Date: Fri, 17 Apr 2020 20:17:36 +0300 Subject: [PATCH 0113/2595] Cadence: gem: fix wraparound in 64bit descriptors Wraparound of TX descriptor cyclic buffer only updated the low 32 bits of the descriptor. Fix that by checking if we're working with 64bit descriptors. Signed-off-by: Ramon Fried Reviewed-by: Edgar E. Iglesias Message-id: 20200417171736.441607-1-rfried.dev@gmail.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 51ec5a072d..b7b7985bf2 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1238,7 +1238,14 @@ static void gem_transmit(CadenceGEMState *s) /* read next descriptor */ if (tx_desc_get_wrap(desc)) { tx_desc_set_last(desc); - packet_desc_addr = s->regs[GEM_TXQBASE]; + + if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) { + packet_desc_addr = s->regs[GEM_TBQPH]; + packet_desc_addr <<= 32; + } else { + packet_desc_addr = 0; + } + packet_desc_addr |= s->regs[GEM_TXQBASE]; } else { packet_desc_addr += 4 * gem_get_desc_len(s, false); } From 59ab136a9e24f989cb7922d9cf7d1774fc497a78 Mon Sep 17 00:00:00 2001 From: Ramon Fried Date: Sat, 18 Apr 2020 11:51:45 +0300 Subject: [PATCH 0114/2595] net: cadence_gem: clear RX control descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RX ring descriptors control field is used for setting SOF and EOF (start of frame and end of frame). The SOF and EOF weren't cleared from the previous descriptors, causing inconsistencies in ring buffer. Fix that by clearing the control field of every descriptors we're processing. Signed-off-by: Ramon Fried Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Message-id: 20200418085145.489726-1-rfried.dev@gmail.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index b7b7985bf2..22a0b1b1f9 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -411,6 +411,11 @@ static inline void rx_desc_set_sof(uint32_t *desc) desc[1] |= DESC_1_RX_SOF; } +static inline void rx_desc_clear_control(uint32_t *desc) +{ + desc[1] = 0; +} + static inline void rx_desc_set_eof(uint32_t *desc) { desc[1] |= DESC_1_RX_EOF; @@ -999,6 +1004,8 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) rxbuf_ptr += MIN(bytes_to_copy, rxbufsize); bytes_to_copy -= MIN(bytes_to_copy, rxbufsize); + rx_desc_clear_control(s->rx_desc[q]); + /* Update the descriptor. */ if (first_desc) { rx_desc_set_sof(s->rx_desc[q]); From 6b375d3546b009d1e63e07397ec9c6af256e15e9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Apr 2020 09:28:08 -0700 Subject: [PATCH 0115/2595] target/arm: Vectorize integer comparison vs zero These instructions are often used in glibc's string routines. They were the final uses of the 32-bit at a time neon helpers. Signed-off-by: Richard Henderson Message-id: 20200418162808.4680-1-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.h | 27 ++-- target/arm/neon_helper.c | 24 ---- target/arm/translate-a64.c | 64 +++------- target/arm/translate.c | 256 +++++++++++++++++++++++++++++++------ target/arm/translate.h | 5 + target/arm/vec_helper.c | 25 ++++ 6 files changed, 278 insertions(+), 123 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index f37b8670a5..5817626b20 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -275,19 +275,6 @@ DEF_HELPER_2(neon_hsub_u16, i32, i32, i32) DEF_HELPER_2(neon_hsub_s32, s32, s32, s32) DEF_HELPER_2(neon_hsub_u32, i32, i32, i32) -DEF_HELPER_2(neon_cgt_u8, i32, i32, i32) -DEF_HELPER_2(neon_cgt_s8, i32, i32, i32) -DEF_HELPER_2(neon_cgt_u16, i32, i32, i32) -DEF_HELPER_2(neon_cgt_s16, i32, i32, i32) -DEF_HELPER_2(neon_cgt_u32, i32, i32, i32) -DEF_HELPER_2(neon_cgt_s32, i32, i32, i32) -DEF_HELPER_2(neon_cge_u8, i32, i32, i32) -DEF_HELPER_2(neon_cge_s8, i32, i32, i32) -DEF_HELPER_2(neon_cge_u16, i32, i32, i32) -DEF_HELPER_2(neon_cge_s16, i32, i32, i32) -DEF_HELPER_2(neon_cge_u32, i32, i32, i32) -DEF_HELPER_2(neon_cge_s32, i32, i32, i32) - DEF_HELPER_2(neon_pmin_u8, i32, i32, i32) DEF_HELPER_2(neon_pmin_s8, i32, i32, i32) DEF_HELPER_2(neon_pmin_u16, i32, i32, i32) @@ -347,9 +334,6 @@ DEF_HELPER_2(neon_mul_u16, i32, i32, i32) DEF_HELPER_2(neon_tst_u8, i32, i32, i32) DEF_HELPER_2(neon_tst_u16, i32, i32, i32) DEF_HELPER_2(neon_tst_u32, i32, i32, i32) -DEF_HELPER_2(neon_ceq_u8, i32, i32, i32) -DEF_HELPER_2(neon_ceq_u16, i32, i32, i32) -DEF_HELPER_2(neon_ceq_u32, i32, i32, i32) DEF_HELPER_1(neon_clz_u8, i32, i32) DEF_HELPER_1(neon_clz_u16, i32, i32) @@ -686,6 +670,17 @@ DEF_HELPER_FLAGS_2(frint64_s, TCG_CALL_NO_RWG, f32, f32, ptr) DEF_HELPER_FLAGS_2(frint32_d, TCG_CALL_NO_RWG, f64, f64, ptr) DEF_HELPER_FLAGS_2(frint64_d, TCG_CALL_NO_RWG, f64, f64, ptr) +DEF_HELPER_FLAGS_3(gvec_ceq0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ceq0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_clt0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_clt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cle0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cle0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cgt0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cgt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cge0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cge0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + DEF_HELPER_FLAGS_4(gvec_sshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_sshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_ushl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/neon_helper.c b/target/arm/neon_helper.c index c7a8438b42..448be93fa1 100644 --- a/target/arm/neon_helper.c +++ b/target/arm/neon_helper.c @@ -562,24 +562,6 @@ uint32_t HELPER(neon_hsub_u32)(uint32_t src1, uint32_t src2) return dest; } -#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? ~0 : 0 -NEON_VOP(cgt_s8, neon_s8, 4) -NEON_VOP(cgt_u8, neon_u8, 4) -NEON_VOP(cgt_s16, neon_s16, 2) -NEON_VOP(cgt_u16, neon_u16, 2) -NEON_VOP(cgt_s32, neon_s32, 1) -NEON_VOP(cgt_u32, neon_u32, 1) -#undef NEON_FN - -#define NEON_FN(dest, src1, src2) dest = (src1 >= src2) ? ~0 : 0 -NEON_VOP(cge_s8, neon_s8, 4) -NEON_VOP(cge_u8, neon_u8, 4) -NEON_VOP(cge_s16, neon_s16, 2) -NEON_VOP(cge_u16, neon_u16, 2) -NEON_VOP(cge_s32, neon_s32, 1) -NEON_VOP(cge_u32, neon_u32, 1) -#undef NEON_FN - #define NEON_FN(dest, src1, src2) dest = (src1 < src2) ? src1 : src2 NEON_POP(pmin_s8, neon_s8, 4) NEON_POP(pmin_u8, neon_u8, 4) @@ -1135,12 +1117,6 @@ NEON_VOP(tst_u16, neon_u16, 2) NEON_VOP(tst_u32, neon_u32, 1) #undef NEON_FN -#define NEON_FN(dest, src1, src2) dest = (src1 == src2) ? -1 : 0 -NEON_VOP(ceq_u8, neon_u8, 4) -NEON_VOP(ceq_u16, neon_u16, 2) -NEON_VOP(ceq_u32, neon_u32, 1) -#undef NEON_FN - /* Count Leading Sign/Zero Bits. */ static inline int do_clz8(uint8_t x) { diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 7580e46367..efb1c4adc4 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -594,6 +594,14 @@ static void gen_gvec_fn4(DisasContext *s, bool is_q, int rd, int rn, int rm, is_q ? 16 : 8, vec_full_reg_size(s)); } +/* Expand a 2-operand AdvSIMD vector operation using an op descriptor. */ +static void gen_gvec_op2(DisasContext *s, bool is_q, int rd, + int rn, const GVecGen2 *gvec_op) +{ + tcg_gen_gvec_2(vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn), + is_q ? 16 : 8, vec_full_reg_size(s), gvec_op); +} + /* Expand a 2-operand + immediate AdvSIMD vector operation using * an op descriptor. */ @@ -12366,6 +12374,15 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) return; } break; + case 0x8: /* CMGT, CMGE */ + gen_gvec_op2(s, is_q, rd, rn, u ? &cge0_op[size] : &cgt0_op[size]); + return; + case 0x9: /* CMEQ, CMLE */ + gen_gvec_op2(s, is_q, rd, rn, u ? &cle0_op[size] : &ceq0_op[size]); + return; + case 0xa: /* CMLT */ + gen_gvec_op2(s, is_q, rd, rn, &clt0_op[size]); + return; case 0xb: if (u) { /* ABS, NEG */ gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_neg, size); @@ -12403,29 +12420,12 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) for (pass = 0; pass < (is_q ? 4 : 2); pass++) { TCGv_i32 tcg_op = tcg_temp_new_i32(); TCGv_i32 tcg_res = tcg_temp_new_i32(); - TCGCond cond; read_vec_element_i32(s, tcg_op, rn, pass, MO_32); if (size == 2) { /* Special cases for 32 bit elements */ switch (opcode) { - case 0xa: /* CMLT */ - /* 32 bit integer comparison against zero, result is - * test ? (2^32 - 1) : 0. We implement via setcond(test) - * and inverting. - */ - cond = TCG_COND_LT; - do_cmop: - tcg_gen_setcondi_i32(cond, tcg_res, tcg_op, 0); - tcg_gen_neg_i32(tcg_res, tcg_res); - break; - case 0x8: /* CMGT, CMGE */ - cond = u ? TCG_COND_GE : TCG_COND_GT; - goto do_cmop; - case 0x9: /* CMEQ, CMLE */ - cond = u ? TCG_COND_LE : TCG_COND_EQ; - goto do_cmop; case 0x4: /* CLS */ if (u) { tcg_gen_clzi_i32(tcg_res, tcg_op, 32); @@ -12522,36 +12522,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) genfn(tcg_res, cpu_env, tcg_op); break; } - case 0x8: /* CMGT, CMGE */ - case 0x9: /* CMEQ, CMLE */ - case 0xa: /* CMLT */ - { - static NeonGenTwoOpFn * const fns[3][2] = { - { gen_helper_neon_cgt_s8, gen_helper_neon_cgt_s16 }, - { gen_helper_neon_cge_s8, gen_helper_neon_cge_s16 }, - { gen_helper_neon_ceq_u8, gen_helper_neon_ceq_u16 }, - }; - NeonGenTwoOpFn *genfn; - int comp; - bool reverse; - TCGv_i32 tcg_zero = tcg_const_i32(0); - - /* comp = index into [CMGT, CMGE, CMEQ, CMLE, CMLT] */ - comp = (opcode - 0x8) * 2 + u; - /* ...but LE, LT are implemented as reverse GE, GT */ - reverse = (comp > 2); - if (reverse) { - comp = 4 - comp; - } - genfn = fns[comp][size]; - if (reverse) { - genfn(tcg_res, tcg_zero, tcg_op); - } else { - genfn(tcg_res, tcg_op, tcg_zero); - } - tcg_temp_free_i32(tcg_zero); - break; - } case 0x4: /* CLS, CLZ */ if (u) { if (size == 0) { diff --git a/target/arm/translate.c b/target/arm/translate.c index 9f9f4e19e0..d4ad2028f1 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3917,6 +3917,205 @@ static int do_v81_helper(DisasContext *s, gen_helper_gvec_3_ptr *fn, return 1; } +static void gen_ceq0_i32(TCGv_i32 d, TCGv_i32 a) +{ + tcg_gen_setcondi_i32(TCG_COND_EQ, d, a, 0); + tcg_gen_neg_i32(d, d); +} + +static void gen_ceq0_i64(TCGv_i64 d, TCGv_i64 a) +{ + tcg_gen_setcondi_i64(TCG_COND_EQ, d, a, 0); + tcg_gen_neg_i64(d, d); +} + +static void gen_ceq0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) +{ + TCGv_vec zero = tcg_const_zeros_vec_matching(d); + tcg_gen_cmp_vec(TCG_COND_EQ, vece, d, a, zero); + tcg_temp_free_vec(zero); +} + +static const TCGOpcode vecop_list_cmp[] = { + INDEX_op_cmp_vec, 0 +}; + +const GVecGen2 ceq0_op[4] = { + { .fno = gen_helper_gvec_ceq0_b, + .fniv = gen_ceq0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_8 }, + { .fno = gen_helper_gvec_ceq0_h, + .fniv = gen_ceq0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_16 }, + { .fni4 = gen_ceq0_i32, + .fniv = gen_ceq0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_32 }, + { .fni8 = gen_ceq0_i64, + .fniv = gen_ceq0_vec, + .opt_opc = vecop_list_cmp, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .vece = MO_64 }, +}; + +static void gen_cle0_i32(TCGv_i32 d, TCGv_i32 a) +{ + tcg_gen_setcondi_i32(TCG_COND_LE, d, a, 0); + tcg_gen_neg_i32(d, d); +} + +static void gen_cle0_i64(TCGv_i64 d, TCGv_i64 a) +{ + tcg_gen_setcondi_i64(TCG_COND_LE, d, a, 0); + tcg_gen_neg_i64(d, d); +} + +static void gen_cle0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) +{ + TCGv_vec zero = tcg_const_zeros_vec_matching(d); + tcg_gen_cmp_vec(TCG_COND_LE, vece, d, a, zero); + tcg_temp_free_vec(zero); +} + +const GVecGen2 cle0_op[4] = { + { .fno = gen_helper_gvec_cle0_b, + .fniv = gen_cle0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_8 }, + { .fno = gen_helper_gvec_cle0_h, + .fniv = gen_cle0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_16 }, + { .fni4 = gen_cle0_i32, + .fniv = gen_cle0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_32 }, + { .fni8 = gen_cle0_i64, + .fniv = gen_cle0_vec, + .opt_opc = vecop_list_cmp, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .vece = MO_64 }, +}; + +static void gen_cge0_i32(TCGv_i32 d, TCGv_i32 a) +{ + tcg_gen_setcondi_i32(TCG_COND_GE, d, a, 0); + tcg_gen_neg_i32(d, d); +} + +static void gen_cge0_i64(TCGv_i64 d, TCGv_i64 a) +{ + tcg_gen_setcondi_i64(TCG_COND_GE, d, a, 0); + tcg_gen_neg_i64(d, d); +} + +static void gen_cge0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) +{ + TCGv_vec zero = tcg_const_zeros_vec_matching(d); + tcg_gen_cmp_vec(TCG_COND_GE, vece, d, a, zero); + tcg_temp_free_vec(zero); +} + +const GVecGen2 cge0_op[4] = { + { .fno = gen_helper_gvec_cge0_b, + .fniv = gen_cge0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_8 }, + { .fno = gen_helper_gvec_cge0_h, + .fniv = gen_cge0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_16 }, + { .fni4 = gen_cge0_i32, + .fniv = gen_cge0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_32 }, + { .fni8 = gen_cge0_i64, + .fniv = gen_cge0_vec, + .opt_opc = vecop_list_cmp, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .vece = MO_64 }, +}; + +static void gen_clt0_i32(TCGv_i32 d, TCGv_i32 a) +{ + tcg_gen_setcondi_i32(TCG_COND_LT, d, a, 0); + tcg_gen_neg_i32(d, d); +} + +static void gen_clt0_i64(TCGv_i64 d, TCGv_i64 a) +{ + tcg_gen_setcondi_i64(TCG_COND_LT, d, a, 0); + tcg_gen_neg_i64(d, d); +} + +static void gen_clt0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) +{ + TCGv_vec zero = tcg_const_zeros_vec_matching(d); + tcg_gen_cmp_vec(TCG_COND_LT, vece, d, a, zero); + tcg_temp_free_vec(zero); +} + +const GVecGen2 clt0_op[4] = { + { .fno = gen_helper_gvec_clt0_b, + .fniv = gen_clt0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_8 }, + { .fno = gen_helper_gvec_clt0_h, + .fniv = gen_clt0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_16 }, + { .fni4 = gen_clt0_i32, + .fniv = gen_clt0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_32 }, + { .fni8 = gen_clt0_i64, + .fniv = gen_clt0_vec, + .opt_opc = vecop_list_cmp, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .vece = MO_64 }, +}; + +static void gen_cgt0_i32(TCGv_i32 d, TCGv_i32 a) +{ + tcg_gen_setcondi_i32(TCG_COND_GT, d, a, 0); + tcg_gen_neg_i32(d, d); +} + +static void gen_cgt0_i64(TCGv_i64 d, TCGv_i64 a) +{ + tcg_gen_setcondi_i64(TCG_COND_GT, d, a, 0); + tcg_gen_neg_i64(d, d); +} + +static void gen_cgt0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) +{ + TCGv_vec zero = tcg_const_zeros_vec_matching(d); + tcg_gen_cmp_vec(TCG_COND_GT, vece, d, a, zero); + tcg_temp_free_vec(zero); +} + +const GVecGen2 cgt0_op[4] = { + { .fno = gen_helper_gvec_cgt0_b, + .fniv = gen_cgt0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_8 }, + { .fno = gen_helper_gvec_cgt0_h, + .fniv = gen_cgt0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_16 }, + { .fni4 = gen_cgt0_i32, + .fniv = gen_cgt0_vec, + .opt_opc = vecop_list_cmp, + .vece = MO_32 }, + { .fni8 = gen_cgt0_i64, + .fniv = gen_cgt0_vec, + .opt_opc = vecop_list_cmp, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .vece = MO_64 }, +}; + static void gen_ssra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift) { tcg_gen_vec_sar8i_i64(a, a, shift); @@ -6481,6 +6680,27 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_gen_gvec_abs(size, rd_ofs, rm_ofs, vec_size, vec_size); break; + case NEON_2RM_VCEQ0: + tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size, + vec_size, &ceq0_op[size]); + break; + case NEON_2RM_VCGT0: + tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size, + vec_size, &cgt0_op[size]); + break; + case NEON_2RM_VCLE0: + tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size, + vec_size, &cle0_op[size]); + break; + case NEON_2RM_VCGE0: + tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size, + vec_size, &cge0_op[size]); + break; + case NEON_2RM_VCLT0: + tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size, + vec_size, &clt0_op[size]); + break; + default: elementwise: for (pass = 0; pass < (q ? 4 : 2); pass++) { @@ -6543,42 +6763,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) default: abort(); } break; - case NEON_2RM_VCGT0: case NEON_2RM_VCLE0: - tmp2 = tcg_const_i32(0); - switch(size) { - case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break; - case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break; - case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break; - default: abort(); - } - tcg_temp_free_i32(tmp2); - if (op == NEON_2RM_VCLE0) { - tcg_gen_not_i32(tmp, tmp); - } - break; - case NEON_2RM_VCGE0: case NEON_2RM_VCLT0: - tmp2 = tcg_const_i32(0); - switch(size) { - case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break; - case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break; - case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break; - default: abort(); - } - tcg_temp_free_i32(tmp2); - if (op == NEON_2RM_VCLT0) { - tcg_gen_not_i32(tmp, tmp); - } - break; - case NEON_2RM_VCEQ0: - tmp2 = tcg_const_i32(0); - switch(size) { - case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break; - case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break; - case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break; - default: abort(); - } - tcg_temp_free_i32(tmp2); - break; case NEON_2RM_VCGT0_F: { TCGv_ptr fpstatus = get_fpstatus_ptr(1); diff --git a/target/arm/translate.h b/target/arm/translate.h index d9ea0c99cc..98b319f3f6 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -275,6 +275,11 @@ static inline void gen_swstep_exception(DisasContext *s, int isv, int ex) uint64_t vfp_expand_imm(int size, uint8_t imm8); /* Vector operations shared between ARM and AArch64. */ +extern const GVecGen2 ceq0_op[4]; +extern const GVecGen2 clt0_op[4]; +extern const GVecGen2 cgt0_op[4]; +extern const GVecGen2 cle0_op[4]; +extern const GVecGen2 cge0_op[4]; extern const GVecGen3 mla_op[4]; extern const GVecGen3 mls_op[4]; extern const GVecGen3 cmtst_op[4]; diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index 8017bd88c4..3d534188a8 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -1257,3 +1257,28 @@ void HELPER(sve2_pmull_h)(void *vd, void *vn, void *vm, uint32_t desc) } } #endif + +#define DO_CMP0(NAME, TYPE, OP) \ +void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \ +{ \ + intptr_t i, opr_sz = simd_oprsz(desc); \ + for (i = 0; i < opr_sz; i += sizeof(TYPE)) { \ + TYPE nn = *(TYPE *)(vn + i); \ + *(TYPE *)(vd + i) = -(nn OP 0); \ + } \ + clear_tail(vd, opr_sz, simd_maxsz(desc)); \ +} + +DO_CMP0(gvec_ceq0_b, int8_t, ==) +DO_CMP0(gvec_clt0_b, int8_t, <) +DO_CMP0(gvec_cle0_b, int8_t, <=) +DO_CMP0(gvec_cgt0_b, int8_t, >) +DO_CMP0(gvec_cge0_b, int8_t, >=) + +DO_CMP0(gvec_ceq0_h, int16_t, ==) +DO_CMP0(gvec_clt0_h, int16_t, <) +DO_CMP0(gvec_cle0_h, int16_t, <=) +DO_CMP0(gvec_cgt0_h, int16_t, >) +DO_CMP0(gvec_cge0_h, int16_t, >=) + +#undef DO_CMP0 From ef6a5c71c2f40e253712ad3d8826d5e84e325aeb Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Mon, 20 Apr 2020 14:18:06 +0200 Subject: [PATCH 0116/2595] hw/arm/virt: dt: move creation of /secure-chosen to create_fdt() The /secure-chosen node is currently used only by create_uart(), but this will change. Therefore move the creation of this node to create_fdt(). Signed-off-by: Jerome Forissier Message-id: 20200420121807.8204-2-jerome@forissier.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index cca5316256..0d92674f32 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -234,6 +234,10 @@ static void create_fdt(VirtMachineState *vms) /* /chosen must exist for load_dtb to fill in necessary properties later */ qemu_fdt_add_subnode(fdt, "/chosen"); + if (vms->secure) { + qemu_fdt_add_subnode(fdt, "/secure-chosen"); + } + /* Clock node, for the benefit of the UART. The kernel device tree * binding documentation claims the PL011 node clock properties are * optional but in practice if you omit them the kernel refuses to @@ -761,7 +765,6 @@ static void create_uart(const VirtMachineState *vms, int uart, qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled"); qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay"); - qemu_fdt_add_subnode(vms->fdt, "/secure-chosen"); qemu_fdt_setprop_string(vms->fdt, "/secure-chosen", "stdout-path", nodename); } From 60592cfed2b685ef114a454d176ef539528cb0cf Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Mon, 20 Apr 2020 14:18:07 +0200 Subject: [PATCH 0117/2595] hw/arm/virt: dt: add kaslr-seed property Generate random seeds to be used by the non-secure and/or secure OSes for ASLR. The seeds are 64-bit random values exported via the DT properties /chosen/kaslr-seed [1] and /secure-chosen/kaslr-seed, the latter being used by OP-TEE [2]. [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e5bc0c37c97e1 [2] https://github.com/OP-TEE/optee_os/commit/ef262691fe0e Signed-off-by: Jerome Forissier Message-id: 20200420121807.8204-3-jerome@forissier.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 0d92674f32..626822554d 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -77,6 +77,7 @@ #include "hw/acpi/generic_event_device.h" #include "hw/virtio/virtio-iommu.h" #include "hw/char/pl011.h" +#include "qemu/guest-random.h" #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ @@ -213,6 +214,18 @@ static bool cpu_type_valid(const char *cpu) return false; } +static void create_kaslr_seed(VirtMachineState *vms, const char *node) +{ + Error *err = NULL; + uint64_t seed; + + if (qemu_guest_getrandom(&seed, sizeof(seed), &err)) { + error_free(err); + return; + } + qemu_fdt_setprop_u64(vms->fdt, node, "kaslr-seed", seed); +} + static void create_fdt(VirtMachineState *vms) { MachineState *ms = MACHINE(vms); @@ -233,9 +246,11 @@ static void create_fdt(VirtMachineState *vms) /* /chosen must exist for load_dtb to fill in necessary properties later */ qemu_fdt_add_subnode(fdt, "/chosen"); + create_kaslr_seed(vms, "/chosen"); if (vms->secure) { qemu_fdt_add_subnode(fdt, "/secure-chosen"); + create_kaslr_seed(vms, "/secure-chosen"); } /* Clock node, for the benefit of the UART. The kernel device tree From 9fb005b02dbda7f47b789b7f19bf5f73622a4756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 09:33:54 +0200 Subject: [PATCH 0118/2595] target/arm: Restrict the Address Translate write operation to TCG accel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under KVM these registers are written by the hardware. Restrict the writefn handlers to TCG to avoid when building without TCG: LINK aarch64-softmmu/qemu-system-aarch64 target/arm/helper.o: In function `do_ats_write': target/arm/helper.c:3524: undefined reference to `raise_exception' Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200423073358.27155-2-philmd@redhat.com Signed-off-by: Peter Maydell --- target/arm/helper.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index 7e9ea5d20f..dfefb9b3d9 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -3442,6 +3442,7 @@ static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } +#ifdef CONFIG_TCG static uint64_t do_ats_write(CPUARMState *env, uint64_t value, MMUAccessType access_type, ARMMMUIdx mmu_idx) { @@ -3602,9 +3603,11 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, } return par64; } +#endif /* CONFIG_TCG */ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { +#ifdef CONFIG_TCG MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD; uint64_t par64; ARMMMUIdx mmu_idx; @@ -3664,17 +3667,26 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) par64 = do_ats_write(env, value, access_type, mmu_idx); A32_BANKED_CURRENT_REG_SET(env, par, par64); +#else + /* Handled by hardware accelerator. */ + g_assert_not_reached(); +#endif /* CONFIG_TCG */ } static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { +#ifdef CONFIG_TCG MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD; uint64_t par64; par64 = do_ats_write(env, value, access_type, ARMMMUIdx_E2); A32_BANKED_CURRENT_REG_SET(env, par, par64); +#else + /* Handled by hardware accelerator. */ + g_assert_not_reached(); +#endif /* CONFIG_TCG */ } static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3689,6 +3701,7 @@ static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri, static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { +#ifdef CONFIG_TCG MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD; ARMMMUIdx mmu_idx; int secure = arm_is_secure_below_el3(env); @@ -3728,6 +3741,10 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, } env->cp15.par_el[1] = do_ats_write(env, value, access_type, mmu_idx); +#else + /* Handled by hardware accelerator. */ + g_assert_not_reached(); +#endif /* CONFIG_TCG */ } #endif From 37bcf244454f4efb82e2c0c64bbd7eabcc165a0c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 23 Apr 2020 09:33:55 +0200 Subject: [PATCH 0119/2595] target/arm: Make cpu_register() available for other files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make cpu_register() (renamed to arm_cpu_register()) available from internals.h so we can register CPUs also from other files in the future. Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Reviewed-by: Eric Auger Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200423073358.27155-3-philmd@redhat.com Message-ID: <20190921150420.30743-2-thuth@redhat.com> [PMD: Only take cpu_register() from Thomas's patch] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/cpu-qom.h | 9 ++++++++- target/arm/cpu.c | 10 ++-------- target/arm/cpu64.c | 8 +------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h index d95568bf05..56395b87f6 100644 --- a/target/arm/cpu-qom.h +++ b/target/arm/cpu-qom.h @@ -35,7 +35,14 @@ struct arm_boot_info; #define TYPE_ARM_MAX_CPU "max-" TYPE_ARM_CPU -typedef struct ARMCPUInfo ARMCPUInfo; +typedef struct ARMCPUInfo { + const char *name; + void (*initfn)(Object *obj); + void (*class_init)(ObjectClass *oc, void *data); +} ARMCPUInfo; + +void arm_cpu_register(const ARMCPUInfo *info); +void aarch64_cpu_register(const ARMCPUInfo *info); /** * ARMCPUClass: diff --git a/target/arm/cpu.c b/target/arm/cpu.c index a79f233b17..47e35400da 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2693,12 +2693,6 @@ static void arm_max_initfn(Object *obj) #endif /* !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) */ -struct ARMCPUInfo { - const char *name; - void (*initfn)(Object *obj); - void (*class_init)(ObjectClass *oc, void *data); -}; - static const ARMCPUInfo arm_cpus[] = { #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) { .name = "arm926", .initfn = arm926_initfn }, @@ -2864,7 +2858,7 @@ static void cpu_register_class_init(ObjectClass *oc, void *data) acc->info = data; } -static void cpu_register(const ARMCPUInfo *info) +void arm_cpu_register(const ARMCPUInfo *info) { TypeInfo type_info = { .parent = TYPE_ARM_CPU, @@ -2905,7 +2899,7 @@ static void arm_cpu_register_types(void) type_register_static(&idau_interface_type_info); while (info->name) { - cpu_register(info); + arm_cpu_register(info); info++; } diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 95d0c8c101..74afc28d53 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -737,12 +737,6 @@ static void aarch64_max_initfn(Object *obj) cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal); } -struct ARMCPUInfo { - const char *name; - void (*initfn)(Object *obj); - void (*class_init)(ObjectClass *oc, void *data); -}; - static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, @@ -825,7 +819,7 @@ static void cpu_register_class_init(ObjectClass *oc, void *data) acc->info = data; } -static void aarch64_cpu_register(const ARMCPUInfo *info) +void aarch64_cpu_register(const ARMCPUInfo *info) { TypeInfo type_info = { .parent = TYPE_AARCH64_CPU, From 51c510aa5876a681cd0059ed3bacaa17590dc2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 09:33:57 +0200 Subject: [PATCH 0120/2595] target/arm/cpu: Update coding style to make checkpatch.pl happy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will move this code in the next commit. Clean it up first to avoid checkpatch.pl errors. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200423073358.27155-5-philmd@redhat.com Signed-off-by: Peter Maydell --- target/arm/cpu.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 47e35400da..141d947775 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -582,7 +582,8 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) CPUARMState *env = &cpu->env; bool ret = false; - /* ARMv7-M interrupt masking works differently than -A or -R. + /* + * ARMv7-M interrupt masking works differently than -A or -R. * There is no FIQ/IRQ distinction. Instead of I and F bits * masking FIQ and IRQ interrupts, an exception is taken only * if it is higher priority than the current execution priority @@ -1912,7 +1913,8 @@ static void arm1026_initfn(Object *obj) static void arm1136_r2_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); - /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an + /* + * What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an * older core than plain "arm1136". In particular this does not * have the v6K features. * These ID register values are correct for 1136 but may be wrong @@ -2698,7 +2700,8 @@ static const ARMCPUInfo arm_cpus[] = { { .name = "arm926", .initfn = arm926_initfn }, { .name = "arm946", .initfn = arm946_initfn }, { .name = "arm1026", .initfn = arm1026_initfn }, - /* What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an + /* + * What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an * older core than plain "arm1136". In particular this does not * have the v6K features. */ From 80972d3bb2dbc6a47bae84b694c14acba9c1de64 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 23 Apr 2020 14:11:11 +0200 Subject: [PATCH 0121/2595] device_tree: Allow name wildcards in qemu_fdt_node_path() Allow name wildcards in qemu_fdt_node_path(). This is useful to find all nodes with a given compatibility string. Reviewed-by: Alistair Francis Signed-off-by: Edgar E. Iglesias Message-id: 20200423121114.4274-2-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- device_tree.c | 2 +- include/sysemu/device_tree.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/device_tree.c b/device_tree.c index bba6cc2164..f5b4699aed 100644 --- a/device_tree.c +++ b/device_tree.c @@ -308,7 +308,7 @@ char **qemu_fdt_node_path(void *fdt, const char *name, char *compat, offset = len; break; } - if (!strcmp(iter_name, name)) { + if (!name || !strcmp(iter_name, name)) { char *path; path = g_malloc(path_len); diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h index c16fd69bc0..7c53ef7634 100644 --- a/include/sysemu/device_tree.h +++ b/include/sysemu/device_tree.h @@ -39,6 +39,9 @@ void *load_device_tree_from_sysfs(void); * NULL. If there is no error but no matching node was found, the * returned array contains a single element equal to NULL. If an error * was encountered when parsing the blob, the function returns NULL + * + * @name may be NULL to wildcard names and only match compatibility + * strings. */ char **qemu_fdt_node_path(void *fdt, const char *name, char *compat, Error **errp); From 958bae18b26ea7183865c8876c04441edfed3760 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 23 Apr 2020 14:11:12 +0200 Subject: [PATCH 0122/2595] device_tree: Constify compat in qemu_fdt_node_path() Make compat in qemu_fdt_node_path() const char *. Signed-off-by: Edgar E. Iglesias Message-id: 20200423121114.4274-3-edgar.iglesias@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- device_tree.c | 2 +- include/sysemu/device_tree.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/device_tree.c b/device_tree.c index f5b4699aed..b335dae707 100644 --- a/device_tree.c +++ b/device_tree.c @@ -291,7 +291,7 @@ char **qemu_fdt_node_unit_path(void *fdt, const char *name, Error **errp) return path_array; } -char **qemu_fdt_node_path(void *fdt, const char *name, char *compat, +char **qemu_fdt_node_path(void *fdt, const char *name, const char *compat, Error **errp) { int offset, len, ret; diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h index 7c53ef7634..982c89345f 100644 --- a/include/sysemu/device_tree.h +++ b/include/sysemu/device_tree.h @@ -43,7 +43,7 @@ void *load_device_tree_from_sysfs(void); * @name may be NULL to wildcard names and only match compatibility * strings. */ -char **qemu_fdt_node_path(void *fdt, const char *name, char *compat, +char **qemu_fdt_node_path(void *fdt, const char *name, const char *compat, Error **errp); /** From 4d1ac883a7635c4bd58991bc158eff0c81cb230c Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 23 Apr 2020 14:11:13 +0200 Subject: [PATCH 0123/2595] hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move arm_boot_info into XlnxZCU102. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Edgar E. Iglesias Message-id: 20200423121114.4274-4-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-zcu102.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index bd645ad818..4eb117c755 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -31,13 +31,14 @@ typedef struct XlnxZCU102 { bool secure; bool virt; + + struct arm_boot_info binfo; } XlnxZCU102; #define TYPE_ZCU102_MACHINE MACHINE_TYPE_NAME("xlnx-zcu102") #define ZCU102_MACHINE(obj) \ OBJECT_CHECK(XlnxZCU102, (obj), TYPE_ZCU102_MACHINE) -static struct arm_boot_info xlnx_zcu102_binfo; static bool zcu102_get_secure(Object *obj, Error **errp) { @@ -166,9 +167,9 @@ static void xlnx_zcu102_init(MachineState *machine) /* TODO create and connect IDE devices for ide_drive_get() */ - xlnx_zcu102_binfo.ram_size = ram_size; - xlnx_zcu102_binfo.loader_start = 0; - arm_load_kernel(s->soc.boot_cpu_ptr, machine, &xlnx_zcu102_binfo); + s->binfo.ram_size = ram_size; + s->binfo.loader_start = 0; + arm_load_kernel(s->soc.boot_cpu_ptr, machine, &s->binfo); } static void xlnx_zcu102_machine_instance_init(Object *obj) From 6f7b6947a6639fff15c6a0956adf0f5ec004b789 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 23 Apr 2020 14:11:14 +0200 Subject: [PATCH 0124/2595] hw/arm: xlnx-zcu102: Disable unsupported FDT firmware nodes Disable unsupported FDT firmware nodes if a user passes us a DTB with nodes enabled that the machine cannot support due to lack of EL3 or EL2 support. Reviewed-by: Alistair Francis Signed-off-by: Edgar E. Iglesias Message-id: 20200423121114.4274-5-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-zcu102.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 4eb117c755..a798e228b7 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -23,6 +23,7 @@ #include "qemu/error-report.h" #include "qemu/log.h" #include "sysemu/qtest.h" +#include "sysemu/device_tree.h" typedef struct XlnxZCU102 { MachineState parent_obj; @@ -68,6 +69,34 @@ static void zcu102_set_virt(Object *obj, bool value, Error **errp) s->virt = value; } +static void zcu102_modify_dtb(const struct arm_boot_info *binfo, void *fdt) +{ + XlnxZCU102 *s = container_of(binfo, XlnxZCU102, binfo); + bool method_is_hvc; + char **node_path; + const char *r; + int prop_len; + int i; + + /* If EL3 is enabled, we keep all firmware nodes active. */ + if (!s->secure) { + node_path = qemu_fdt_node_path(fdt, NULL, "xlnx,zynqmp-firmware", + &error_fatal); + + for (i = 0; node_path && node_path[i]; i++) { + r = qemu_fdt_getprop(fdt, node_path[i], "method", &prop_len, NULL); + method_is_hvc = r && !strcmp("hvc", r); + + /* Allow HVC based firmware if EL2 is enabled. */ + if (method_is_hvc && s->virt) { + continue; + } + qemu_fdt_setprop_string(fdt, node_path[i], "status", "disabled"); + } + g_strfreev(node_path); + } +} + static void xlnx_zcu102_init(MachineState *machine) { XlnxZCU102 *s = ZCU102_MACHINE(machine); @@ -169,6 +198,7 @@ static void xlnx_zcu102_init(MachineState *machine) s->binfo.ram_size = ram_size; s->binfo.loader_start = 0; + s->binfo.modify_dtb = zcu102_modify_dtb; arm_load_kernel(s->soc.boot_cpu_ptr, machine, &s->binfo); } From a50c1f57e491ba17c0fcb7d285dfe04770be0a70 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Fri, 10 Apr 2020 14:18:15 +0200 Subject: [PATCH 0125/2595] qcow2: Add incompatibility note between backing files and raw external data files Backing files and raw external data files are mutually exclusive. The documentation of the raw external data bit (in autoclear_features) already indicates that, but we should also mention it on the other side. Suggested-by: Eric Blake Signed-off-by: Alberto Garcia Message-Id: <20200410121816.8334-1-berto@igalia.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- docs/interop/qcow2.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index 640e0eca40..298a031310 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -25,6 +25,9 @@ The first cluster of a qcow2 image contains the file header: is stored (NB: The string is not null terminated). 0 if the image doesn't have a backing file. + Note: backing files are incompatible with raw external data + files (auto-clear feature bit 1). + 16 - 19: backing_file_size Length of the backing file name in bytes. Must not be longer than 1023 bytes. Undefined if the image doesn't have From 3fb61087074474b088fee23bb81ffd258cb9cb2a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 9 Apr 2020 15:10:06 -0400 Subject: [PATCH 0126/2595] qemu-iotests: allow qcow2 external discarded clusters to contain stale data Test 244 checks the expected behavior of qcow2 external data files with respect to zero and discarded clusters. Filesystems however are free to ignore discard requests, and this seems to be the case for overlayfs. Relax the tests to skip checks on the external data file for discarded areas, which implies not using qemu-img compare in the data_file_raw=on case. This fixes docker tests on RHEL8. Cc: Kevin Wolf Cc: qemu-block@nongnu.org Signed-off-by: Paolo Bonzini Message-Id: <20200409191006.24429-1-pbonzini@redhat.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/244 | 10 ++++++++-- tests/qemu-iotests/244.out | 9 ++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244 index 2ec1815e6f..efe3c0428b 100755 --- a/tests/qemu-iotests/244 +++ b/tests/qemu-iotests/244 @@ -143,7 +143,6 @@ $QEMU_IO -c 'read -P 0 0 1M' \ echo $QEMU_IO -c 'read -P 0 0 1M' \ -c 'read -P 0x11 1M 1M' \ - -c 'read -P 0 2M 2M' \ -c 'read -P 0x11 4M 1M' \ -c 'read -P 0 5M 1M' \ -f raw "$TEST_IMG.data" | @@ -180,8 +179,15 @@ $QEMU_IO -c 'read -P 0 0 1M' \ -f $IMGFMT "$TEST_IMG" | _filter_qemu_io +# Discarded clusters are only marked as such in the qcow2 metadata, but +# they can contain stale data in the external data file. Instead, zero +# clusters must be zeroed in the external data file too. echo -$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.data" +$QEMU_IO -c 'read -P 0 0 1M' \ + -c 'read -P 0x11 1M 1M' \ + -c 'read -P 0 3M 3M' \ + -f raw "$TEST_IMG".data | + _filter_qemu_io echo -n "qcow2 file size after I/O: " du -b $TEST_IMG | cut -f1 diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out index 56329deb4b..dbab7359a9 100644 --- a/tests/qemu-iotests/244.out +++ b/tests/qemu-iotests/244.out @@ -74,8 +74,6 @@ read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read 2097152/2097152 bytes at offset 2097152 -2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 1048576/1048576 bytes at offset 4194304 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 1048576/1048576 bytes at offset 5242880 @@ -108,7 +106,12 @@ read 1048576/1048576 bytes at offset 1048576 read 4194304/4194304 bytes at offset 2097152 4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Images are identical. +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 3145728/3145728 bytes at offset 3145728 +3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2 file size after I/O: 327680 === bdrv_co_block_status test for file and offset=0 === From 92b92799dc8662b6f71809100a4aabc1ae408ebb Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2020 14:54:39 +0200 Subject: [PATCH 0127/2595] block: Add flags to BlockDriver.bdrv_co_truncate() This adds a new BdrvRequestFlags parameter to the .bdrv_co_truncate() driver callbacks, and a supported_truncate_flags field in BlockDriverState that allows drivers to advertise support for request flags in the context of truncate. For now, we always pass 0 and no drivers declare support for any flag. Signed-off-by: Kevin Wolf Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Message-Id: <20200424125448.63318-2-kwolf@redhat.com> Signed-off-by: Kevin Wolf --- block/crypto.c | 3 ++- block/file-posix.c | 2 +- block/file-win32.c | 2 +- block/gluster.c | 1 + block/io.c | 8 +++++++- block/iscsi.c | 2 +- block/nfs.c | 3 ++- block/qcow2.c | 2 +- block/qed.c | 1 + block/raw-format.c | 2 +- block/rbd.c | 1 + block/sheepdog.c | 4 ++-- block/ssh.c | 2 +- include/block/block_int.h | 10 +++++++++- tests/test-block-iothread.c | 3 ++- 15 files changed, 33 insertions(+), 13 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index d577f89659..3721a8495c 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -299,7 +299,8 @@ static int block_crypto_co_create_generic(BlockDriverState *bs, static int coroutine_fn block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, - PreallocMode prealloc, Error **errp) + PreallocMode prealloc, BdrvRequestFlags flags, + Error **errp) { BlockCrypto *crypto = bs->opaque; uint64_t payload_offset = diff --git a/block/file-posix.c b/block/file-posix.c index 094e3b0212..58326a0a60 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -2080,7 +2080,7 @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset, static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, - Error **errp) + BdrvRequestFlags flags, Error **errp) { BDRVRawState *s = bs->opaque; struct stat st; diff --git a/block/file-win32.c b/block/file-win32.c index 15859839a1..a6b0dda5c3 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -469,7 +469,7 @@ static void raw_close(BlockDriverState *bs) static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, - Error **errp) + BdrvRequestFlags flags, Error **errp) { BDRVRawState *s = bs->opaque; LONG low, high; diff --git a/block/gluster.c b/block/gluster.c index 0aa1f2cda4..d06df900f6 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1228,6 +1228,7 @@ static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, + BdrvRequestFlags flags, Error **errp) { BDRVGlusterState *s = bs->opaque; diff --git a/block/io.c b/block/io.c index aba67f66b9..04ac5cf023 100644 --- a/block/io.c +++ b/block/io.c @@ -3344,6 +3344,7 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, BlockDriverState *bs = child->bs; BlockDriver *drv = bs->drv; BdrvTrackedRequest req; + BdrvRequestFlags flags = 0; int64_t old_size, new_bytes; int ret; @@ -3394,7 +3395,12 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, } if (drv->bdrv_co_truncate) { - ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp); + if (flags & ~bs->supported_truncate_flags) { + error_setg(errp, "Block driver does not support requested flags"); + ret = -ENOTSUP; + goto out; + } + ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp); } else if (bs->file && drv->is_filter) { ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp); } else { diff --git a/block/iscsi.c b/block/iscsi.c index 0b4b7210df..914a1de9fb 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2124,7 +2124,7 @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state) static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, - Error **errp) + BdrvRequestFlags flags, Error **errp) { IscsiLun *iscsilun = bs->opaque; int64_t cur_length; diff --git a/block/nfs.c b/block/nfs.c index cc2413d5ab..2393fbfe6b 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -755,7 +755,8 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs) static int coroutine_fn nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, - PreallocMode prealloc, Error **errp) + PreallocMode prealloc, BdrvRequestFlags flags, + Error **errp) { NFSClient *client = bs->opaque; int ret; diff --git a/block/qcow2.c b/block/qcow2.c index b524b0c53f..0b406b22fb 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3964,7 +3964,7 @@ fail: static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, - Error **errp) + BdrvRequestFlags flags, Error **errp) { BDRVQcow2State *s = bs->opaque; uint64_t old_length; diff --git a/block/qed.c b/block/qed.c index 1af9b3cb1d..fb6100bd20 100644 --- a/block/qed.c +++ b/block/qed.c @@ -1467,6 +1467,7 @@ static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, + BdrvRequestFlags flags, Error **errp) { BDRVQEDState *s = bs->opaque; diff --git a/block/raw-format.c b/block/raw-format.c index 93b25e1b6b..9331368f43 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -371,7 +371,7 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, - Error **errp) + BdrvRequestFlags flags, Error **errp) { BDRVRawState *s = bs->opaque; diff --git a/block/rbd.c b/block/rbd.c index e637639a07..f2d52091c7 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1108,6 +1108,7 @@ static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, + BdrvRequestFlags flags, Error **errp) { int r; diff --git a/block/sheepdog.c b/block/sheepdog.c index 5f3aead038..76729f40a4 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -2281,7 +2281,7 @@ static int64_t sd_getlength(BlockDriverState *bs) static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, - Error **errp) + BdrvRequestFlags flags, Error **errp) { BDRVSheepdogState *s = bs->opaque; int ret, fd; @@ -2597,7 +2597,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, assert(!flags); if (offset > s->inode.vdi_size) { - ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, NULL); + ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) { return ret; } diff --git a/block/ssh.c b/block/ssh.c index 84e92821c0..9eb33df859 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -1298,7 +1298,7 @@ static int64_t ssh_getlength(BlockDriverState *bs) static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, - Error **errp) + BdrvRequestFlags flags, Error **errp) { BDRVSSHState *s = bs->opaque; diff --git a/include/block/block_int.h b/include/block/block_int.h index 4c3587ea19..92335f33c7 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -355,7 +355,7 @@ struct BlockDriver { */ int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, - Error **errp); + BdrvRequestFlags flags, Error **errp); int64_t (*bdrv_getlength)(BlockDriverState *bs); bool has_variable_length; @@ -847,6 +847,14 @@ struct BlockDriverState { /* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA, * BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */ unsigned int supported_zero_flags; + /* + * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE). + * + * If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure + * that any added space reads as all zeros. If this can't be guaranteed, + * the operation must fail. + */ + unsigned int supported_truncate_flags; /* the following member gives a name to every node on the bs graph. */ char node_name[32]; diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c index 0c861809f0..2f3b76323d 100644 --- a/tests/test-block-iothread.c +++ b/tests/test-block-iothread.c @@ -46,7 +46,8 @@ static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs, static int coroutine_fn bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, - PreallocMode prealloc, Error **errp) + PreallocMode prealloc, BdrvRequestFlags flags, + Error **errp) { return 0; } From 7b8e4857426f2e2de2441749996c6161b550bada Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2020 14:54:40 +0200 Subject: [PATCH 0128/2595] block: Add flags to bdrv(_co)_truncate() Now that block drivers can support flags for .bdrv_co_truncate, expose the parameter in the node level interfaces bdrv_co_truncate() and bdrv_truncate(). Signed-off-by: Kevin Wolf Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Message-Id: <20200424125448.63318-3-kwolf@redhat.com> Signed-off-by: Kevin Wolf --- block/block-backend.c | 2 +- block/crypto.c | 2 +- block/io.c | 12 +++++++----- block/parallels.c | 6 +++--- block/qcow.c | 4 ++-- block/qcow2-refcount.c | 2 +- block/qcow2.c | 15 +++++++++------ block/raw-format.c | 2 +- block/vhdx-log.c | 2 +- block/vhdx.c | 2 +- block/vmdk.c | 2 +- include/block/block.h | 5 +++-- tests/test-block-iothread.c | 6 +++--- 13 files changed, 34 insertions(+), 28 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index 38ae413826..8be20060d3 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2144,7 +2144,7 @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, return -ENOMEDIUM; } - return bdrv_truncate(blk->root, offset, exact, prealloc, errp); + return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp); } int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, diff --git a/block/crypto.c b/block/crypto.c index 3721a8495c..ab33545c92 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -313,7 +313,7 @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, offset += payload_offset; - return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp); + return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp); } static void block_crypto_close(BlockDriverState *bs) diff --git a/block/io.c b/block/io.c index 04ac5cf023..795075954e 100644 --- a/block/io.c +++ b/block/io.c @@ -3339,12 +3339,12 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs) * 'offset' bytes in length. */ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, - PreallocMode prealloc, Error **errp) + PreallocMode prealloc, BdrvRequestFlags flags, + Error **errp) { BlockDriverState *bs = child->bs; BlockDriver *drv = bs->drv; BdrvTrackedRequest req; - BdrvRequestFlags flags = 0; int64_t old_size, new_bytes; int ret; @@ -3402,7 +3402,7 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, } ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp); } else if (bs->file && drv->is_filter) { - ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp); + ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp); } else { error_setg(errp, "Image format driver does not support resize"); ret = -ENOTSUP; @@ -3435,6 +3435,7 @@ typedef struct TruncateCo { int64_t offset; bool exact; PreallocMode prealloc; + BdrvRequestFlags flags; Error **errp; int ret; } TruncateCo; @@ -3443,12 +3444,12 @@ static void coroutine_fn bdrv_truncate_co_entry(void *opaque) { TruncateCo *tco = opaque; tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact, - tco->prealloc, tco->errp); + tco->prealloc, tco->flags, tco->errp); aio_wait_kick(); } int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, - PreallocMode prealloc, Error **errp) + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) { Coroutine *co; TruncateCo tco = { @@ -3456,6 +3457,7 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, .offset = offset, .exact = exact, .prealloc = prealloc, + .flags = flags, .errp = errp, .ret = NOT_DONE, }; diff --git a/block/parallels.c b/block/parallels.c index 6d4ed77f16..2be92cf417 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -203,7 +203,7 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, } else { ret = bdrv_truncate(bs->file, (s->data_end + space) << BDRV_SECTOR_BITS, - false, PREALLOC_MODE_OFF, NULL); + false, PREALLOC_MODE_OFF, 0, NULL); } if (ret < 0) { return ret; @@ -493,7 +493,7 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs, * That means we have to pass exact=true. */ ret = bdrv_truncate(bs->file, res->image_end_offset, true, - PREALLOC_MODE_OFF, &local_err); + PREALLOC_MODE_OFF, 0, &local_err); if (ret < 0) { error_report_err(local_err); res->check_errors++; @@ -889,7 +889,7 @@ static void parallels_close(BlockDriverState *bs) /* errors are ignored, so we might as well pass exact=true */ bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, true, - PREALLOC_MODE_OFF, NULL); + PREALLOC_MODE_OFF, 0, NULL); } g_free(s->bat_dirty_bmap); diff --git a/block/qcow.c b/block/qcow.c index 8973e4e565..6b5f2269f0 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -480,7 +480,7 @@ static int get_cluster_offset(BlockDriverState *bs, return -E2BIG; } ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size, - false, PREALLOC_MODE_OFF, NULL); + false, PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) { return ret; } @@ -1035,7 +1035,7 @@ static int qcow_make_empty(BlockDriverState *bs) l1_length) < 0) return -1; ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false, - PREALLOC_MODE_OFF, NULL); + PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) return ret; diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 7ef1c0e42a..d9650b9b6c 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -2018,7 +2018,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res, } ret = bdrv_truncate(bs->file, offset + s->cluster_size, false, - PREALLOC_MODE_OFF, &local_err); + PREALLOC_MODE_OFF, 0, &local_err); if (ret < 0) { error_report_err(local_err); goto resize_fail; diff --git a/block/qcow2.c b/block/qcow2.c index 0b406b22fb..c5b0711357 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3095,7 +3095,7 @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset, mode = PREALLOC_MODE_OFF; } ret = bdrv_co_truncate(s->data_file, host_offset + cur_bytes, false, - mode, errp); + mode, 0, errp); if (ret < 0) { return ret; } @@ -4061,7 +4061,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, * always fulfilled, so there is no need to pass it on.) */ bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size, - false, PREALLOC_MODE_OFF, &local_err); + false, PREALLOC_MODE_OFF, 0, &local_err); if (local_err) { warn_reportf_err(local_err, "Failed to truncate the tail of the image: "); @@ -4083,7 +4083,8 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, * file should be resized to the exact target size, too, * so we pass @exact here. */ - ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, errp); + ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, 0, + errp); if (ret < 0) { goto fail; } @@ -4169,7 +4170,8 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, new_file_size = allocation_start + nb_new_data_clusters * s->cluster_size; /* Image file grows, so @exact does not matter */ - ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, errp); + ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0, + errp); if (ret < 0) { error_prepend(errp, "Failed to resize underlying file: "); qcow2_free_clusters(bs, allocation_start, @@ -4348,7 +4350,8 @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs, if (len < 0) { return len; } - return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL); + return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, 0, + NULL); } if (offset_into_cluster(s, offset)) { @@ -4563,7 +4566,7 @@ static int make_completely_empty(BlockDriverState *bs) } ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size, false, - PREALLOC_MODE_OFF, &local_err); + PREALLOC_MODE_OFF, 0, &local_err); if (ret < 0) { error_report_err(local_err); goto fail; diff --git a/block/raw-format.c b/block/raw-format.c index 9331368f43..3465c9a865 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -387,7 +387,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, s->size = offset; offset += s->offset; - return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp); + return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp); } static void raw_eject(BlockDriverState *bs, bool eject_flag) diff --git a/block/vhdx-log.c b/block/vhdx-log.c index 13a49c2a33..404fb5f3cb 100644 --- a/block/vhdx-log.c +++ b/block/vhdx-log.c @@ -558,7 +558,7 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s, goto exit; } ret = bdrv_truncate(bs->file, new_file_size, false, - PREALLOC_MODE_OFF, NULL); + PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) { goto exit; } diff --git a/block/vhdx.c b/block/vhdx.c index e16fdc2f2d..3a33eda99c 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1264,7 +1264,7 @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s, } return bdrv_truncate(bs->file, *new_offset + s->block_size, false, - PREALLOC_MODE_OFF, NULL); + PREALLOC_MODE_OFF, 0, NULL); } /* diff --git a/block/vmdk.c b/block/vmdk.c index 218d9c9800..5de99fe813 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2077,7 +2077,7 @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, } length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE); ret = bdrv_truncate(s->extents[i].file, length, false, - PREALLOC_MODE_OFF, NULL); + PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) { return ret; } diff --git a/include/block/block.h b/include/block/block.h index b05995fe9c..8b62429aa4 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -339,9 +339,10 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, void bdrv_refresh_filename(BlockDriverState *bs); int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, - PreallocMode prealloc, Error **errp); + PreallocMode prealloc, BdrvRequestFlags flags, + Error **errp); int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, - PreallocMode prealloc, Error **errp); + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); int64_t bdrv_nb_sectors(BlockDriverState *bs); int64_t bdrv_getlength(BlockDriverState *bs); diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c index 2f3b76323d..71e9bce3b1 100644 --- a/tests/test-block-iothread.c +++ b/tests/test-block-iothread.c @@ -186,18 +186,18 @@ static void test_sync_op_truncate(BdrvChild *c) int ret; /* Normal success path */ - ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL); + ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL); g_assert_cmpint(ret, ==, 0); /* Early error: Negative offset */ - ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, NULL); + ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL); g_assert_cmpint(ret, ==, -EINVAL); /* Error: Read-only image */ c->bs->read_only = true; c->bs->open_flags &= ~BDRV_O_RDWR; - ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL); + ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL); g_assert_cmpint(ret, ==, -EACCES); c->bs->read_only = false; From 8c6242b6f383e43fd11d2c50f8bcdd2bba1100fc Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2020 14:54:41 +0200 Subject: [PATCH 0129/2595] block-backend: Add flags to blk_truncate() Now that node level interface bdrv_truncate() supports passing request flags to the block driver, expose this on the BlockBackend level, too. Signed-off-by: Kevin Wolf Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Message-Id: <20200424125448.63318-4-kwolf@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 3 ++- block/block-backend.c | 4 ++-- block/commit.c | 4 ++-- block/crypto.c | 2 +- block/mirror.c | 2 +- block/qcow2.c | 4 ++-- block/qed.c | 2 +- block/vdi.c | 2 +- block/vhdx.c | 4 ++-- block/vmdk.c | 6 +++--- block/vpc.c | 2 +- blockdev.c | 2 +- include/sysemu/block-backend.h | 2 +- qemu-img.c | 2 +- qemu-io-cmds.c | 2 +- 15 files changed, 22 insertions(+), 21 deletions(-) diff --git a/block.c b/block.c index c11385ae05..301ec588bd 100644 --- a/block.c +++ b/block.c @@ -548,7 +548,8 @@ static int64_t create_file_fallback_truncate(BlockBackend *blk, int64_t size; int ret; - ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err); + ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0, + &local_err); if (ret < 0 && ret != -ENOTSUP) { error_propagate(errp, local_err); return ret; diff --git a/block/block-backend.c b/block/block-backend.c index 8be20060d3..17ed6d8c5b 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2137,14 +2137,14 @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, } int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, - PreallocMode prealloc, Error **errp) + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) { if (!blk_is_available(blk)) { error_setg(errp, "No medium inserted"); return -ENOMEDIUM; } - return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp); + return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp); } int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, diff --git a/block/commit.c b/block/commit.c index 8e672799af..87f6096d90 100644 --- a/block/commit.c +++ b/block/commit.c @@ -133,7 +133,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp) } if (base_len < len) { - ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL); + ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL); if (ret) { goto out; } @@ -458,7 +458,7 @@ int bdrv_commit(BlockDriverState *bs) * grow the backing file image if possible. If not possible, * we must return an error */ if (length > backing_length) { - ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, + ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0, &local_err); if (ret < 0) { error_report_err(local_err); diff --git a/block/crypto.c b/block/crypto.c index ab33545c92..e02f343590 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -115,7 +115,7 @@ static ssize_t block_crypto_init_func(QCryptoBlock *block, * which will be used by the crypto header */ return blk_truncate(data->blk, data->size + headerlen, false, - data->prealloc, errp); + data->prealloc, 0, errp); } diff --git a/block/mirror.c b/block/mirror.c index c26fd9260d..aca95c9bc9 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -900,7 +900,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) if (s->bdev_length > base_length) { ret = blk_truncate(s->target, s->bdev_length, false, - PREALLOC_MODE_OFF, NULL); + PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) { goto immediate_exit; } diff --git a/block/qcow2.c b/block/qcow2.c index c5b0711357..9cfbdfc939 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3511,7 +3511,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) /* Okay, now that we have a valid image, let's give it the right size */ ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation, - errp); + 0, errp); if (ret < 0) { error_prepend(errp, "Could not resize image: "); goto out; @@ -5374,7 +5374,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, * Amending image options should ensure that the image has * exactly the given new values, so pass exact=true here. */ - ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, errp); + ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, 0, errp); blk_unref(blk); if (ret < 0) { return ret; diff --git a/block/qed.c b/block/qed.c index fb6100bd20..b0fdb8f565 100644 --- a/block/qed.c +++ b/block/qed.c @@ -677,7 +677,7 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts, * The QED format associates file length with allocation status, * so a new file (which is empty) must have a length of 0. */ - ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, errp); + ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp); if (ret < 0) { goto out; } diff --git a/block/vdi.c b/block/vdi.c index e1a11f2aa0..0c7835ae70 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -875,7 +875,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, if (image_type == VDI_TYPE_STATIC) { ret = blk_truncate(blk, offset + blocks * block_size, false, - PREALLOC_MODE_OFF, errp); + PREALLOC_MODE_OFF, 0, errp); if (ret < 0) { error_prepend(errp, "Failed to statically allocate file"); goto exit; diff --git a/block/vhdx.c b/block/vhdx.c index 3a33eda99c..45be0a4321 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1703,13 +1703,13 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s, /* All zeroes, so we can just extend the file - the end of the BAT * is the furthest thing we have written yet */ ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF, - errp); + 0, errp); if (ret < 0) { goto exit; } } else if (type == VHDX_TYPE_FIXED) { ret = blk_truncate(blk, data_file_offset + image_size, false, - PREALLOC_MODE_OFF, errp); + PREALLOC_MODE_OFF, 0, errp); if (ret < 0) { goto exit; } diff --git a/block/vmdk.c b/block/vmdk.c index 5de99fe813..8ec18f35a5 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2118,7 +2118,7 @@ static int vmdk_init_extent(BlockBackend *blk, int gd_buf_size; if (flat) { - ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, errp); + ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp); goto exit; } magic = cpu_to_be32(VMDK4_MAGIC); @@ -2182,7 +2182,7 @@ static int vmdk_init_extent(BlockBackend *blk, } ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false, - PREALLOC_MODE_OFF, errp); + PREALLOC_MODE_OFF, 0, errp); if (ret < 0) { goto exit; } @@ -2523,7 +2523,7 @@ static int coroutine_fn vmdk_co_do_create(int64_t size, /* bdrv_pwrite write padding zeros to align to sector, we don't need that * for description file */ if (desc_offset == 0) { - ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, errp); + ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp); if (ret < 0) { goto exit; } diff --git a/block/vpc.c b/block/vpc.c index d8141b52da..2d1eade146 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -898,7 +898,7 @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf, /* Add footer to total size */ total_size += HEADER_SIZE; - ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, errp); + ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp); if (ret < 0) { return ret; } diff --git a/blockdev.c b/blockdev.c index 9da960b1e7..dc1a0c7c2f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2741,7 +2741,7 @@ void qmp_block_resize(bool has_device, const char *device, } bdrv_drained_begin(bs); - ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp); + ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp); bdrv_drained_end(bs); out: diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 9bbdbd63d7..34de7faa81 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -237,7 +237,7 @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, int bytes); int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, - PreallocMode prealloc, Error **errp); + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes); int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, int64_t pos, int size); diff --git a/qemu-img.c b/qemu-img.c index a2369766f0..6a4327aaba 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -3897,7 +3897,7 @@ static int img_resize(int argc, char **argv) * resizing, so pass @exact=true. It is of no use to report * success when the image has not actually been resized. */ - ret = blk_truncate(blk, total_size, true, prealloc, &err); + ret = blk_truncate(blk, total_size, true, prealloc, 0, &err); if (!ret) { qprintf(quiet, "Image resized.\n"); } else { diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 1b7e700020..851f07e8f8 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -1715,7 +1715,7 @@ static int truncate_f(BlockBackend *blk, int argc, char **argv) * exact=true. It is better to err on the "emit more errors" side * than to be overly permissive. */ - ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, &local_err); + ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, 0, &local_err); if (ret < 0) { error_report_err(local_err); return ret; From f01643fb8b47e8a70c04bbf45e0f12a9e5bc54de Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2020 14:54:42 +0200 Subject: [PATCH 0130/2595] qcow2: Support BDRV_REQ_ZERO_WRITE for truncate If BDRV_REQ_ZERO_WRITE is set and we're extending the image, calling qcow2_cluster_zeroize() with flags=0 does the right thing: It doesn't undo any previous preallocation, but just adds the zero flag to all relevant L2 entries. If an external data file is in use, a write_zeroes request to the data file is made instead. Signed-off-by: Kevin Wolf Message-Id: <20200424125448.63318-5-kwolf@redhat.com> Reviewed-by: Eric Blake Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block/qcow2-cluster.c | 2 +- block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 17f1363279..4b5fc8c4a7 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1795,7 +1795,7 @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset, /* Caller must pass aligned values, except at image end */ assert(QEMU_IS_ALIGNED(offset, s->cluster_size)); assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) || - end_offset == bs->total_sectors << BDRV_SECTOR_BITS); + end_offset >= bs->total_sectors << BDRV_SECTOR_BITS); /* The zero flag is only supported by version 3 and newer */ if (s->qcow_version < 3) { diff --git a/block/qcow2.c b/block/qcow2.c index 9cfbdfc939..98065d7808 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1726,6 +1726,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, bs->supported_zero_flags = header.version >= 3 ? BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0; + bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; /* Repair image if dirty */ if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only && @@ -4214,6 +4215,39 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, g_assert_not_reached(); } + if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) { + uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size); + + /* + * Use zero clusters as much as we can. qcow2_cluster_zeroize() + * requires a cluster-aligned start. The end may be unaligned if it is + * at the end of the image (which it is here). + */ + ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to zero out new clusters"); + goto fail; + } + + /* Write explicit zeros for the unaligned head */ + if (zero_start > old_length) { + uint64_t len = zero_start - old_length; + uint8_t *buf = qemu_blockalign0(bs, len); + QEMUIOVector qiov; + qemu_iovec_init_buf(&qiov, buf, len); + + qemu_co_mutex_unlock(&s->lock); + ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0); + qemu_co_mutex_lock(&s->lock); + + qemu_vfree(buf); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to zero out the new area"); + goto fail; + } + } + } + if (prealloc != PREALLOC_MODE_OFF) { /* Flush metadata before actually changing the image size */ ret = qcow2_write_caches(bs); From 1ddaabaecb7eaeb6d8948a32340af95db44c54a1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2020 14:54:43 +0200 Subject: [PATCH 0131/2595] raw-format: Support BDRV_REQ_ZERO_WRITE for truncate The raw format driver can simply forward the flag and let its bs->file child take care of actually providing the zeros. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200424125448.63318-6-kwolf@redhat.com> Signed-off-by: Kevin Wolf --- block/raw-format.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block/raw-format.c b/block/raw-format.c index 3465c9a865..351f2d91c6 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -387,7 +387,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, s->size = offset; offset += s->offset; - return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp); + return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp); } static void raw_eject(BlockDriverState *bs, bool eject_flag) @@ -445,6 +445,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & bs->file->bs->supported_zero_flags); + bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags & + BDRV_REQ_ZERO_WRITE; if (bs->probed && !bdrv_is_read_only(bs)) { bdrv_refresh_filename(bs->file->bs); From 2f0c6e7a650de133eccd94e9bb6cf7b2070f07f1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2020 14:54:44 +0200 Subject: [PATCH 0132/2595] file-posix: Support BDRV_REQ_ZERO_WRITE for truncate For regular files, we always get BDRV_REQ_ZERO_WRITE behaviour from the OS, so we can advertise the flag and just ignore it. Signed-off-by: Kevin Wolf Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Message-Id: <20200424125448.63318-7-kwolf@redhat.com> Signed-off-by: Kevin Wolf --- block/file-posix.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block/file-posix.c b/block/file-posix.c index 58326a0a60..bf09ad8bc0 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -702,6 +702,10 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, #endif bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK; + if (S_ISREG(st.st_mode)) { + /* When extending regular files, we get zeros from the OS */ + bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; + } ret = 0; fail: if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) { From 955c7d6687fefcd903900a1e597fcbc896c661cd Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2020 14:54:45 +0200 Subject: [PATCH 0133/2595] block: truncate: Don't make backing file data visible When extending the size of an image that has a backing file larger than its old size, make sure that the backing file data doesn't become visible in the guest, but the added area is properly zeroed out. Consider the following scenario where the overlay is shorter than its backing file: base.qcow2: AAAAAAAA overlay.qcow2: BBBB When resizing (extending) overlay.qcow2, the new blocks should not stay unallocated and make the additional As from base.qcow2 visible like before this patch, but zeros should be read. A similar case happens with the various variants of a commit job when an intermediate file is short (- for unallocated): base.qcow2: A-A-AAAA mid.qcow2: BB-B top.qcow2: C--C--C- After commit top.qcow2 to mid.qcow2, the following happens: mid.qcow2: CB-C00C0 (correct result) mid.qcow2: CB-C--C- (before this fix) Without the fix, blocks that previously read as zeros on top.qcow2 suddenly turn into A. Signed-off-by: Kevin Wolf Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200424125448.63318-8-kwolf@redhat.com> Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block/io.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/block/io.c b/block/io.c index 795075954e..a4f9714230 100644 --- a/block/io.c +++ b/block/io.c @@ -3394,6 +3394,31 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, goto out; } + /* + * If the image has a backing file that is large enough that it would + * provide data for the new area, we cannot leave it unallocated because + * then the backing file content would become visible. Instead, zero-fill + * the new area. + * + * Note that if the image has a backing file, but was opened without the + * backing file, taking care of keeping things consistent with that backing + * file is the user's responsibility. + */ + if (new_bytes && bs->backing) { + int64_t backing_len; + + backing_len = bdrv_getlength(backing_bs(bs)); + if (backing_len < 0) { + ret = backing_len; + error_setg_errno(errp, -ret, "Could not get backing file size"); + goto out; + } + + if (backing_len > old_size) { + flags |= BDRV_REQ_ZERO_WRITE; + } + } + if (drv->bdrv_co_truncate) { if (flags & ~bs->supported_truncate_flags) { error_setg(errp, "Block driver does not support requested flags"); From fd586ce8bee50d98773436214dc9e644ddda54aa Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2020 14:54:46 +0200 Subject: [PATCH 0134/2595] iotests: Filter testfiles out in filter_img_info() We want to keep TEST_IMG for the full path of the main test image, but filter_testfiles() must be called for other test images before replacing other things like the image format because the test directory path could contain the format as a substring. Insert a filter_testfiles() call between both. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200424125448.63318-9-kwolf@redhat.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/iotests.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 7bc4934cd2..5f8c263d59 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -338,8 +338,9 @@ def filter_img_info(output, filename): for line in output.split('\n'): if 'disk size' in line or 'actual-size' in line: continue - line = line.replace(filename, 'TEST_IMG') \ - .replace(imgfmt, 'IMGFMT') + line = line.replace(filename, 'TEST_IMG') + line = filter_testfiles(line) + line = line.replace(imgfmt, 'IMGFMT') line = re.sub('iters: [0-9]+', 'iters: XXX', line) line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line) line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line) From bf03dede475e29a16f9188ea85a4d77cd3dcf2b7 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2020 14:54:47 +0200 Subject: [PATCH 0135/2595] iotests: Test committing to short backing file Signed-off-by: Kevin Wolf Message-Id: <20200424125448.63318-10-kwolf@redhat.com> Reviewed-by: Max Reitz Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- tests/qemu-iotests/274 | 155 +++++++++++++++++++++ tests/qemu-iotests/274.out | 268 +++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 424 insertions(+) create mode 100755 tests/qemu-iotests/274 create mode 100644 tests/qemu-iotests/274.out diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274 new file mode 100755 index 0000000000..e951f723b8 --- /dev/null +++ b/tests/qemu-iotests/274 @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# +# 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 . +# +# Creator/Owner: Kevin Wolf +# +# Some tests for short backing files and short overlays + +import iotests + +iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.verify_platform(['linux']) + +size_short = 1 * 1024 * 1024 +size_long = 2 * 1024 * 1024 +size_diff = size_long - size_short + +def create_chain() -> None: + iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, + str(size_long)) + iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid, + str(size_short)) + iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top, + str(size_long)) + + iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base) + +def create_vm() -> iotests.VM: + vm = iotests.VM() + vm.add_blockdev('file,filename=%s,node-name=base-file' % base) + vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt) + vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid) + vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base' + % iotests.imgfmt) + vm.add_drive(top, 'backing=mid,node-name=top') + return vm + +with iotests.FilePath('base') as base, \ + iotests.FilePath('mid') as mid, \ + iotests.FilePath('top') as top: + + iotests.log('== Commit tests ==') + + create_chain() + + iotests.log('=== Check visible data ===') + + iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top) + iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top) + + iotests.log('=== Checking allocation status ===') + + iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short, + '-c', 'alloc %d %d' % (size_short, size_diff), + base) + + iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short, + '-c', 'alloc %d %d' % (size_short, size_diff), + mid) + + iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short, + '-c', 'alloc %d %d' % (size_short, size_diff), + top) + + iotests.log('=== Checking map ===') + + iotests.qemu_img_log('map', '--output=json', base) + iotests.qemu_img_log('map', '--output=human', base) + iotests.qemu_img_log('map', '--output=json', mid) + iotests.qemu_img_log('map', '--output=human', mid) + iotests.qemu_img_log('map', '--output=json', top) + iotests.qemu_img_log('map', '--output=human', top) + + iotests.log('=== Testing qemu-img commit (top -> mid) ===') + + iotests.qemu_img_log('commit', top) + iotests.img_info_log(mid) + iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid) + iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid) + + iotests.log('=== Testing HMP commit (top -> mid) ===') + + create_chain() + with create_vm() as vm: + vm.launch() + vm.qmp_log('human-monitor-command', command_line='commit drive0') + + iotests.img_info_log(mid) + iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid) + iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid) + + iotests.log('=== Testing QMP active commit (top -> mid) ===') + + create_chain() + with create_vm() as vm: + vm.launch() + vm.qmp_log('block-commit', device='top', base_node='mid', + job_id='job0', auto_dismiss=False) + vm.run_job('job0', wait=5) + + iotests.img_info_log(mid) + iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid) + iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid) + + + iotests.log('== Resize tests ==') + + # Use different sizes for different allocation modes: + # + # We want to have at least one test where 32 bit truncation in the size of + # the overlapping area becomes visible. This is covered by the + # prealloc='off' case (1G to 6G is an overlap of 5G). + # + # However, we can only do this for modes that don't preallocate data + # because otherwise we might run out of space on the test host. + # + # We also want to test some unaligned combinations. + for (prealloc, base_size, top_size_old, top_size_new, off) in [ + ('off', '6G', '1G', '8G', '5G'), + ('metadata', '32G', '30G', '33G', '31G'), + ('falloc', '10M', '5M', '15M', '9M'), + ('full', '16M', '8M', '12M', '11M'), + ('off', '384k', '253k', '512k', '253k'), + ('off', '400k', '256k', '512k', '336k'), + ('off', '512k', '256k', '500k', '436k')]: + + iotests.log('=== preallocation=%s ===' % prealloc) + iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size) + iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top, + top_size_old) + iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base) + + # After this, top_size_old to base_size should be allocated/zeroed. + # + # In theory, leaving base_size to top_size_new unallocated would be + # correct, but in practice, if we zero out anything, we zero out + # everything up to top_size_new. + iotests.qemu_img_log('resize', '-f', iotests.imgfmt, + '--preallocation', prealloc, top, top_size_new) + iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top) + iotests.qemu_io_log('-c', 'map', top) + iotests.qemu_img_log('map', '--output=json', top) diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out new file mode 100644 index 0000000000..1a796fd07c --- /dev/null +++ b/tests/qemu-iotests/274.out @@ -0,0 +1,268 @@ +== Commit tests == +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +wrote 2097152/2097152 bytes at offset 0 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +=== Check visible data === +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +=== Checking allocation status === +1048576/1048576 bytes allocated at offset 0 bytes +1048576/1048576 bytes allocated at offset 1 MiB + +0/1048576 bytes allocated at offset 0 bytes +0/0 bytes allocated at offset 1 MiB + +0/1048576 bytes allocated at offset 0 bytes +0/1048576 bytes allocated at offset 1 MiB + +=== Checking map === +[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}] + +Offset Length Mapped to File +0 0x200000 0x50000 TEST_DIR/PID-base + +[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}] + +Offset Length Mapped to File +0 0x100000 0x50000 TEST_DIR/PID-base + +[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680}, +{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}] + +Offset Length Mapped to File +0 0x100000 0x50000 TEST_DIR/PID-base + +=== Testing qemu-img commit (top -> mid) === +Image committed. + +image: TEST_IMG +file format: IMGFMT +virtual size: 2 MiB (2097152 bytes) +cluster_size: 65536 +backing file: TEST_DIR/PID-base +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + corrupt: false + +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +=== Testing HMP commit (top -> mid) === +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +wrote 2097152/2097152 bytes at offset 0 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +{"execute": "human-monitor-command", "arguments": {"command-line": "commit drive0"}} +{"return": ""} +image: TEST_IMG +file format: IMGFMT +virtual size: 2 MiB (2097152 bytes) +cluster_size: 65536 +backing file: TEST_DIR/PID-base +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + corrupt: false + +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +=== Testing QMP active commit (top -> mid) === +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +wrote 2097152/2097152 bytes at offset 0 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "mid", "device": "top", "job-id": "job0"}} +{"return": {}} +{"execute": "job-complete", "arguments": {"id": "job0"}} +{"return": {}} +{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} +image: TEST_IMG +file format: IMGFMT +virtual size: 2 MiB (2097152 bytes) +cluster_size: 65536 +backing file: TEST_DIR/PID-base +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + corrupt: false + +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Resize tests == +=== preallocation=off === +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +wrote 65536/65536 bytes at offset 5368709120 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +Image resized. + +read 65536/65536 bytes at offset 5368709120 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0) +7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000) + +[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false}, +{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}] + +=== preallocation=metadata === +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +wrote 65536/65536 bytes at offset 33285996544 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +Image resized. + +read 65536/65536 bytes at offset 33285996544 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0) +3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000) + +[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false}, +{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680}, +{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128}, +{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576}, +{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024}, +{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008}, +{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}] + +=== preallocation=falloc === +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +wrote 65536/65536 bytes at offset 9437184 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +Image resized. + +read 65536/65536 bytes at offset 9437184 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0) +10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000) + +[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false}, +{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}] + +=== preallocation=full === +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +wrote 65536/65536 bytes at offset 11534336 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +Image resized. + +read 65536/65536 bytes at offset 11534336 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0) +4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000) + +[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false}, +{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}] + +=== preallocation=off === +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +wrote 65536/65536 bytes at offset 259072 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +Image resized. + +read 65536/65536 bytes at offset 259072 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0) +320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000) + +[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false}, +{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680}, +{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}] + +=== preallocation=off === +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +wrote 65536/65536 bytes at offset 344064 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +Image resized. + +read 65536/65536 bytes at offset 344064 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0) +256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000) + +[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false}, +{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}] + +=== preallocation=off === +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 + +wrote 65536/65536 bytes at offset 446464 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +Image resized. + +read 65536/65536 bytes at offset 446464 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0) +244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000) + +[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false}, +{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}] + diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 435dccd5af..1710470e70 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -286,6 +286,7 @@ 270 rw backing quick 272 rw 273 backing quick +274 rw backing 277 rw quick 279 rw backing quick 280 rw migration quick From eb8a0cf3ba26611f3981f8f45ac6a868975a68cc Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2020 16:27:01 +0200 Subject: [PATCH 0136/2595] qcow2: Forward ZERO_WRITE flag for full preallocation The BDRV_REQ_ZERO_WRITE is currently implemented in a way that first the image is possibly preallocated and then the zero flag is added to all clusters. This means that a copy-on-write operation may be needed when writing to these clusters, despite having used preallocation, negating one of the major benefits of preallocation. Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver, and if the protocol driver can ensure that the new area reads as zeros, we can skip setting the zero flag in the qcow2 layer. Unfortunately, the same approach doesn't work for metadata preallocation, so we'll still set the zero flag there. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz Message-Id: <20200424142701.67053-1-kwolf@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- block/qcow2.c | 22 +++++++++++++++++++--- tests/qemu-iotests/274.out | 4 ++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 98065d7808..2ba0b17c39 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -4170,9 +4170,25 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, /* Allocate the data area */ new_file_size = allocation_start + nb_new_data_clusters * s->cluster_size; - /* Image file grows, so @exact does not matter */ - ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0, - errp); + /* + * Image file grows, so @exact does not matter. + * + * If we need to zero out the new area, try first whether the protocol + * driver can already take care of this. + */ + if (flags & BDRV_REQ_ZERO_WRITE) { + ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, + BDRV_REQ_ZERO_WRITE, NULL); + if (ret >= 0) { + flags &= ~BDRV_REQ_ZERO_WRITE; + } + } else { + ret = -1; + } + if (ret < 0) { + ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0, + errp); + } if (ret < 0) { error_prepend(errp, "Failed to resize underlying file: "); qcow2_free_clusters(bs, allocation_start, diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out index 1a796fd07c..9d6fdeb1f7 100644 --- a/tests/qemu-iotests/274.out +++ b/tests/qemu-iotests/274.out @@ -187,7 +187,7 @@ read 65536/65536 bytes at offset 9437184 10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000) [{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false}, -{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}] +{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}] === preallocation=full === Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 @@ -206,7 +206,7 @@ read 65536/65536 bytes at offset 11534336 4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000) [{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false}, -{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}] +{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}] === preallocation=off === Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 From 6cf94132293adb5c76d336ab7ff5924afe2cb147 Mon Sep 17 00:00:00 2001 From: Andrzej Jakowski Date: Mon, 30 Mar 2020 09:46:56 -0700 Subject: [PATCH 0137/2595] nvme: introduce PMR support from NVMe 1.4 spec This patch introduces support for PMR that has been defined as part of NVMe 1.4 spec. User can now specify a pmrdev option that should point to HostMemoryBackend. pmrdev memory region will subsequently be exposed as PCI BAR 2 in emulated NVMe device. Guest OS can perform mmio read and writes to the PMR region that will stay persistent across system reboot. Signed-off-by: Andrzej Jakowski Reviewed-by: Klaus Jensen Reviewed-by: Stefan Hajnoczi Message-Id: <20200330164656.9348-1-andrzej.jakowski@linux.intel.com> Reviewed-by: Keith Busch Signed-off-by: Kevin Wolf --- hw/block/Makefile.objs | 2 +- hw/block/nvme.c | 109 ++++++++++++++++++++++++++ hw/block/nvme.h | 2 + hw/block/trace-events | 4 + include/block/nvme.h | 172 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 288 insertions(+), 1 deletion(-) diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs index 4b4a2b338d..47960b5f0d 100644 --- a/hw/block/Makefile.objs +++ b/hw/block/Makefile.objs @@ -7,12 +7,12 @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o common-obj-$(CONFIG_XEN) += xen-block.o common-obj-$(CONFIG_ECC) += ecc.o common-obj-$(CONFIG_ONENAND) += onenand.o -common-obj-$(CONFIG_NVME_PCI) += nvme.o common-obj-$(CONFIG_SWIM) += swim.o common-obj-$(CONFIG_SH4) += tc58128.o obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o +obj-$(CONFIG_NVME_PCI) += nvme.o obj-y += dataplane/ diff --git a/hw/block/nvme.c b/hw/block/nvme.c index d28335cbf3..9b453423cf 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -19,10 +19,19 @@ * -drive file=,if=none,id= * -device nvme,drive=,serial=,id=, \ * cmb_size_mb=, \ + * [pmrdev=,] \ * num_queues= * * Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at * offset 0 in BAR2 and supports only WDS, RDS and SQS for now. + * + * cmb_size_mb= and pmrdev= options are mutually exclusive due to limitation + * in available BAR's. cmb_size_mb= will take precedence over pmrdev= when + * both provided. + * Enabling pmr emulation can be achieved by pointing to memory-backend-file. + * For example: + * -object memory-backend-file,id=,share=on,mem-path=, \ + * size= .... -device nvme,...,pmrdev= */ #include "qemu/osdep.h" @@ -35,7 +44,9 @@ #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qapi/visitor.h" +#include "sysemu/hostmem.h" #include "sysemu/block-backend.h" +#include "exec/ram_addr.h" #include "qemu/log.h" #include "qemu/module.h" @@ -1141,6 +1152,26 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly, "invalid write to read only CMBSZ, ignored"); return; + case 0xE00: /* PMRCAP */ + NVME_GUEST_ERR(nvme_ub_mmiowr_pmrcap_readonly, + "invalid write to PMRCAP register, ignored"); + return; + case 0xE04: /* TODO PMRCTL */ + break; + case 0xE08: /* PMRSTS */ + NVME_GUEST_ERR(nvme_ub_mmiowr_pmrsts_readonly, + "invalid write to PMRSTS register, ignored"); + return; + case 0xE0C: /* PMREBS */ + NVME_GUEST_ERR(nvme_ub_mmiowr_pmrebs_readonly, + "invalid write to PMREBS register, ignored"); + return; + case 0xE10: /* PMRSWTP */ + NVME_GUEST_ERR(nvme_ub_mmiowr_pmrswtp_readonly, + "invalid write to PMRSWTP register, ignored"); + return; + case 0xE14: /* TODO PMRMSC */ + break; default: NVME_GUEST_ERR(nvme_ub_mmiowr_invalid, "invalid MMIO write," @@ -1169,6 +1200,16 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) } if (addr < sizeof(n->bar)) { + /* + * When PMRWBM bit 1 is set then read from + * from PMRSTS should ensure prior writes + * made it to persistent media + */ + if (addr == 0xE08 && + (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) { + qemu_ram_writeback(n->pmrdev->mr.ram_block, + 0, n->pmrdev->size); + } memcpy(&val, ptr + addr, size); } else { NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs, @@ -1332,6 +1373,23 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) error_setg(errp, "serial property not set"); return; } + + if (!n->cmb_size_mb && n->pmrdev) { + if (host_memory_backend_is_mapped(n->pmrdev)) { + char *path = object_get_canonical_path_component(OBJECT(n->pmrdev)); + error_setg(errp, "can't use already busy memdev: %s", path); + g_free(path); + return; + } + + if (!is_power_of_2(n->pmrdev->size)) { + error_setg(errp, "pmr backend size needs to be power of 2 in size"); + return; + } + + host_memory_backend_set_mapped(n->pmrdev, true); + } + blkconf_blocksizes(&n->conf); if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk), false, errp)) { @@ -1415,6 +1473,51 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem); + } else if (n->pmrdev) { + /* Controller Capabilities register */ + NVME_CAP_SET_PMRS(n->bar.cap, 1); + + /* PMR Capabities register */ + n->bar.pmrcap = 0; + NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 0); + NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 0); + NVME_PMRCAP_SET_BIR(n->bar.pmrcap, 2); + NVME_PMRCAP_SET_PMRTU(n->bar.pmrcap, 0); + /* Turn on bit 1 support */ + NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02); + NVME_PMRCAP_SET_PMRTO(n->bar.pmrcap, 0); + NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 0); + + /* PMR Control register */ + n->bar.pmrctl = 0; + NVME_PMRCTL_SET_EN(n->bar.pmrctl, 0); + + /* PMR Status register */ + n->bar.pmrsts = 0; + NVME_PMRSTS_SET_ERR(n->bar.pmrsts, 0); + NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 0); + NVME_PMRSTS_SET_HSTS(n->bar.pmrsts, 0); + NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 0); + + /* PMR Elasticity Buffer Size register */ + n->bar.pmrebs = 0; + NVME_PMREBS_SET_PMRSZU(n->bar.pmrebs, 0); + NVME_PMREBS_SET_RBB(n->bar.pmrebs, 0); + NVME_PMREBS_SET_PMRWBZ(n->bar.pmrebs, 0); + + /* PMR Sustained Write Throughput register */ + n->bar.pmrswtp = 0; + NVME_PMRSWTP_SET_PMRSWTU(n->bar.pmrswtp, 0); + NVME_PMRSWTP_SET_PMRSWTV(n->bar.pmrswtp, 0); + + /* PMR Memory Space Control register */ + n->bar.pmrmsc = 0; + NVME_PMRMSC_SET_CMSE(n->bar.pmrmsc, 0); + NVME_PMRMSC_SET_CBA(n->bar.pmrmsc, 0); + + pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap), + PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 | + PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr); } for (i = 0; i < n->num_namespaces; i++) { @@ -1445,11 +1548,17 @@ static void nvme_exit(PCIDevice *pci_dev) if (n->cmb_size_mb) { g_free(n->cmbuf); } + + if (n->pmrdev) { + host_memory_backend_set_mapped(n->pmrdev, false); + } msix_uninit_exclusive_bar(pci_dev); } static Property nvme_props[] = { DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf), + DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND, + HostMemoryBackend *), DEFINE_PROP_STRING("serial", NvmeCtrl, serial), DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0), DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64), diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 557194ee19..6520a9f0be 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -83,6 +83,8 @@ typedef struct NvmeCtrl { uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */ char *serial; + HostMemoryBackend *pmrdev; + NvmeNamespace *namespaces; NvmeSQueue **sq; NvmeCQueue **cq; diff --git a/hw/block/trace-events b/hw/block/trace-events index bf6d11b58b..aca54bda14 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -110,6 +110,10 @@ nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CA nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)" nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored" nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored" +nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored" +nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored" +nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored" +nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored" nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64"" nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64"" nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64"" diff --git a/include/block/nvme.h b/include/block/nvme.h index 8fb941c653..5525c8e343 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -15,6 +15,13 @@ typedef struct NvmeBar { uint64_t acq; uint32_t cmbloc; uint32_t cmbsz; + uint8_t padding[3520]; /* not used by QEMU */ + uint32_t pmrcap; + uint32_t pmrctl; + uint32_t pmrsts; + uint32_t pmrebs; + uint32_t pmrswtp; + uint32_t pmrmsc; } NvmeBar; enum NvmeCapShift { @@ -27,6 +34,7 @@ enum NvmeCapShift { CAP_CSS_SHIFT = 37, CAP_MPSMIN_SHIFT = 48, CAP_MPSMAX_SHIFT = 52, + CAP_PMR_SHIFT = 56, }; enum NvmeCapMask { @@ -39,6 +47,7 @@ enum NvmeCapMask { CAP_CSS_MASK = 0xff, CAP_MPSMIN_MASK = 0xf, CAP_MPSMAX_MASK = 0xf, + CAP_PMR_MASK = 0x1, }; #define NVME_CAP_MQES(cap) (((cap) >> CAP_MQES_SHIFT) & CAP_MQES_MASK) @@ -69,6 +78,8 @@ enum NvmeCapMask { << CAP_MPSMIN_SHIFT) #define NVME_CAP_SET_MPSMAX(cap, val) (cap |= (uint64_t)(val & CAP_MPSMAX_MASK)\ << CAP_MPSMAX_SHIFT) +#define NVME_CAP_SET_PMRS(cap, val) (cap |= (uint64_t)(val & CAP_PMR_MASK)\ + << CAP_PMR_SHIFT) enum NvmeCcShift { CC_EN_SHIFT = 0, @@ -205,6 +216,167 @@ enum NvmeCmbszMask { #define NVME_CMBSZ_GETSIZE(cmbsz) \ (NVME_CMBSZ_SZ(cmbsz) * (1 << (12 + 4 * NVME_CMBSZ_SZU(cmbsz)))) +enum NvmePmrcapShift { + PMRCAP_RDS_SHIFT = 3, + PMRCAP_WDS_SHIFT = 4, + PMRCAP_BIR_SHIFT = 5, + PMRCAP_PMRTU_SHIFT = 8, + PMRCAP_PMRWBM_SHIFT = 10, + PMRCAP_PMRTO_SHIFT = 16, + PMRCAP_CMSS_SHIFT = 24, +}; + +enum NvmePmrcapMask { + PMRCAP_RDS_MASK = 0x1, + PMRCAP_WDS_MASK = 0x1, + PMRCAP_BIR_MASK = 0x7, + PMRCAP_PMRTU_MASK = 0x3, + PMRCAP_PMRWBM_MASK = 0xf, + PMRCAP_PMRTO_MASK = 0xff, + PMRCAP_CMSS_MASK = 0x1, +}; + +#define NVME_PMRCAP_RDS(pmrcap) \ + ((pmrcap >> PMRCAP_RDS_SHIFT) & PMRCAP_RDS_MASK) +#define NVME_PMRCAP_WDS(pmrcap) \ + ((pmrcap >> PMRCAP_WDS_SHIFT) & PMRCAP_WDS_MASK) +#define NVME_PMRCAP_BIR(pmrcap) \ + ((pmrcap >> PMRCAP_BIR_SHIFT) & PMRCAP_BIR_MASK) +#define NVME_PMRCAP_PMRTU(pmrcap) \ + ((pmrcap >> PMRCAP_PMRTU_SHIFT) & PMRCAP_PMRTU_MASK) +#define NVME_PMRCAP_PMRWBM(pmrcap) \ + ((pmrcap >> PMRCAP_PMRWBM_SHIFT) & PMRCAP_PMRWBM_MASK) +#define NVME_PMRCAP_PMRTO(pmrcap) \ + ((pmrcap >> PMRCAP_PMRTO_SHIFT) & PMRCAP_PMRTO_MASK) +#define NVME_PMRCAP_CMSS(pmrcap) \ + ((pmrcap >> PMRCAP_CMSS_SHIFT) & PMRCAP_CMSS_MASK) + +#define NVME_PMRCAP_SET_RDS(pmrcap, val) \ + (pmrcap |= (uint64_t)(val & PMRCAP_RDS_MASK) << PMRCAP_RDS_SHIFT) +#define NVME_PMRCAP_SET_WDS(pmrcap, val) \ + (pmrcap |= (uint64_t)(val & PMRCAP_WDS_MASK) << PMRCAP_WDS_SHIFT) +#define NVME_PMRCAP_SET_BIR(pmrcap, val) \ + (pmrcap |= (uint64_t)(val & PMRCAP_BIR_MASK) << PMRCAP_BIR_SHIFT) +#define NVME_PMRCAP_SET_PMRTU(pmrcap, val) \ + (pmrcap |= (uint64_t)(val & PMRCAP_PMRTU_MASK) << PMRCAP_PMRTU_SHIFT) +#define NVME_PMRCAP_SET_PMRWBM(pmrcap, val) \ + (pmrcap |= (uint64_t)(val & PMRCAP_PMRWBM_MASK) << PMRCAP_PMRWBM_SHIFT) +#define NVME_PMRCAP_SET_PMRTO(pmrcap, val) \ + (pmrcap |= (uint64_t)(val & PMRCAP_PMRTO_MASK) << PMRCAP_PMRTO_SHIFT) +#define NVME_PMRCAP_SET_CMSS(pmrcap, val) \ + (pmrcap |= (uint64_t)(val & PMRCAP_CMSS_MASK) << PMRCAP_CMSS_SHIFT) + +enum NvmePmrctlShift { + PMRCTL_EN_SHIFT = 0, +}; + +enum NvmePmrctlMask { + PMRCTL_EN_MASK = 0x1, +}; + +#define NVME_PMRCTL_EN(pmrctl) ((pmrctl >> PMRCTL_EN_SHIFT) & PMRCTL_EN_MASK) + +#define NVME_PMRCTL_SET_EN(pmrctl, val) \ + (pmrctl |= (uint64_t)(val & PMRCTL_EN_MASK) << PMRCTL_EN_SHIFT) + +enum NvmePmrstsShift { + PMRSTS_ERR_SHIFT = 0, + PMRSTS_NRDY_SHIFT = 8, + PMRSTS_HSTS_SHIFT = 9, + PMRSTS_CBAI_SHIFT = 12, +}; + +enum NvmePmrstsMask { + PMRSTS_ERR_MASK = 0xff, + PMRSTS_NRDY_MASK = 0x1, + PMRSTS_HSTS_MASK = 0x7, + PMRSTS_CBAI_MASK = 0x1, +}; + +#define NVME_PMRSTS_ERR(pmrsts) \ + ((pmrsts >> PMRSTS_ERR_SHIFT) & PMRSTS_ERR_MASK) +#define NVME_PMRSTS_NRDY(pmrsts) \ + ((pmrsts >> PMRSTS_NRDY_SHIFT) & PMRSTS_NRDY_MASK) +#define NVME_PMRSTS_HSTS(pmrsts) \ + ((pmrsts >> PMRSTS_HSTS_SHIFT) & PMRSTS_HSTS_MASK) +#define NVME_PMRSTS_CBAI(pmrsts) \ + ((pmrsts >> PMRSTS_CBAI_SHIFT) & PMRSTS_CBAI_MASK) + +#define NVME_PMRSTS_SET_ERR(pmrsts, val) \ + (pmrsts |= (uint64_t)(val & PMRSTS_ERR_MASK) << PMRSTS_ERR_SHIFT) +#define NVME_PMRSTS_SET_NRDY(pmrsts, val) \ + (pmrsts |= (uint64_t)(val & PMRSTS_NRDY_MASK) << PMRSTS_NRDY_SHIFT) +#define NVME_PMRSTS_SET_HSTS(pmrsts, val) \ + (pmrsts |= (uint64_t)(val & PMRSTS_HSTS_MASK) << PMRSTS_HSTS_SHIFT) +#define NVME_PMRSTS_SET_CBAI(pmrsts, val) \ + (pmrsts |= (uint64_t)(val & PMRSTS_CBAI_MASK) << PMRSTS_CBAI_SHIFT) + +enum NvmePmrebsShift { + PMREBS_PMRSZU_SHIFT = 0, + PMREBS_RBB_SHIFT = 4, + PMREBS_PMRWBZ_SHIFT = 8, +}; + +enum NvmePmrebsMask { + PMREBS_PMRSZU_MASK = 0xf, + PMREBS_RBB_MASK = 0x1, + PMREBS_PMRWBZ_MASK = 0xffffff, +}; + +#define NVME_PMREBS_PMRSZU(pmrebs) \ + ((pmrebs >> PMREBS_PMRSZU_SHIFT) & PMREBS_PMRSZU_MASK) +#define NVME_PMREBS_RBB(pmrebs) \ + ((pmrebs >> PMREBS_RBB_SHIFT) & PMREBS_RBB_MASK) +#define NVME_PMREBS_PMRWBZ(pmrebs) \ + ((pmrebs >> PMREBS_PMRWBZ_SHIFT) & PMREBS_PMRWBZ_MASK) + +#define NVME_PMREBS_SET_PMRSZU(pmrebs, val) \ + (pmrebs |= (uint64_t)(val & PMREBS_PMRSZU_MASK) << PMREBS_PMRSZU_SHIFT) +#define NVME_PMREBS_SET_RBB(pmrebs, val) \ + (pmrebs |= (uint64_t)(val & PMREBS_RBB_MASK) << PMREBS_RBB_SHIFT) +#define NVME_PMREBS_SET_PMRWBZ(pmrebs, val) \ + (pmrebs |= (uint64_t)(val & PMREBS_PMRWBZ_MASK) << PMREBS_PMRWBZ_SHIFT) + +enum NvmePmrswtpShift { + PMRSWTP_PMRSWTU_SHIFT = 0, + PMRSWTP_PMRSWTV_SHIFT = 8, +}; + +enum NvmePmrswtpMask { + PMRSWTP_PMRSWTU_MASK = 0xf, + PMRSWTP_PMRSWTV_MASK = 0xffffff, +}; + +#define NVME_PMRSWTP_PMRSWTU(pmrswtp) \ + ((pmrswtp >> PMRSWTP_PMRSWTU_SHIFT) & PMRSWTP_PMRSWTU_MASK) +#define NVME_PMRSWTP_PMRSWTV(pmrswtp) \ + ((pmrswtp >> PMRSWTP_PMRSWTV_SHIFT) & PMRSWTP_PMRSWTV_MASK) + +#define NVME_PMRSWTP_SET_PMRSWTU(pmrswtp, val) \ + (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTU_MASK) << PMRSWTP_PMRSWTU_SHIFT) +#define NVME_PMRSWTP_SET_PMRSWTV(pmrswtp, val) \ + (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTV_MASK) << PMRSWTP_PMRSWTV_SHIFT) + +enum NvmePmrmscShift { + PMRMSC_CMSE_SHIFT = 1, + PMRMSC_CBA_SHIFT = 12, +}; + +enum NvmePmrmscMask { + PMRMSC_CMSE_MASK = 0x1, + PMRMSC_CBA_MASK = 0xfffffffffffff, +}; + +#define NVME_PMRMSC_CMSE(pmrmsc) \ + ((pmrmsc >> PMRMSC_CMSE_SHIFT) & PMRMSC_CMSE_MASK) +#define NVME_PMRMSC_CBA(pmrmsc) \ + ((pmrmsc >> PMRMSC_CBA_SHIFT) & PMRMSC_CBA_MASK) + +#define NVME_PMRMSC_SET_CMSE(pmrmsc, val) \ + (pmrmsc |= (uint64_t)(val & PMRMSC_CMSE_MASK) << PMRMSC_CMSE_SHIFT) +#define NVME_PMRMSC_SET_CBA(pmrmsc, val) \ + (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT) + typedef struct NvmeCmd { uint8_t opcode; uint8_t fuse; From d6a5beeb2bbf4f5ce6e6396051fb4c5fcced56a4 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 16 Apr 2020 17:04:20 +0200 Subject: [PATCH 0138/2595] qom: Factor out user_creatable_add_dict() The QMP handler qmp_object_add() and the implementation of --object in qemu-storage-daemon can share most of the code. Currently, qemu-storage-daemon calls qmp_object_add(), but this is not correct because different visitors need to be used. As a first step towards a fix, make qmp_object_add() a wrapper around a new function user_creatable_add_dict() that can get an additional parameter. The handling of "props" is only required for compatibility and not required for the qemu-storage-daemon command line, so it stays in qmp_object_add(). Signed-off-by: Kevin Wolf --- include/qom/object_interfaces.h | 12 ++++++++++++ qom/object_interfaces.c | 27 +++++++++++++++++++++++++++ qom/qom-qmp-cmds.c | 24 +----------------------- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h index 6f92f3cebb..a0037968a4 100644 --- a/include/qom/object_interfaces.h +++ b/include/qom/object_interfaces.h @@ -87,6 +87,18 @@ Object *user_creatable_add_type(const char *type, const char *id, const QDict *qdict, Visitor *v, Error **errp); +/** + * user_creatable_add_dict: + * @qdict: the object definition + * @errp: if an error occurs, a pointer to an area to store the error + * + * Create an instance of the user creatable object that is defined by + * @qdict. The object type is taken from the QDict key 'qom-type', its + * ID from the key 'id'. The remaining entries in @qdict are used to + * initialize the object properties. + */ +void user_creatable_add_dict(QDict *qdict, Error **errp); + /** * user_creatable_add_opts: * @opts: the object definition diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 72cb9e32a9..739e3e5172 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -6,6 +6,7 @@ #include "qapi/qmp/qerror.h" #include "qapi/qmp/qjson.h" #include "qapi/qmp/qstring.h" +#include "qapi/qobject-input-visitor.h" #include "qom/object_interfaces.h" #include "qemu/help_option.h" #include "qemu/module.h" @@ -105,6 +106,32 @@ out: return obj; } +void user_creatable_add_dict(QDict *qdict, Error **errp) +{ + Visitor *v; + Object *obj; + g_autofree char *type = NULL; + g_autofree char *id = NULL; + + type = g_strdup(qdict_get_try_str(qdict, "qom-type")); + if (!type) { + error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); + return; + } + qdict_del(qdict, "qom-type"); + + id = g_strdup(qdict_get_try_str(qdict, "id")); + if (!id) { + error_setg(errp, QERR_MISSING_PARAMETER, "id"); + return; + } + qdict_del(qdict, "id"); + + v = qobject_input_visitor_new(QOBJECT(qdict)); + obj = user_creatable_add_type(type, id, qdict, v, errp); + visit_free(v); + object_unref(obj); +} Object *user_creatable_add_opts(QemuOpts *opts, Error **errp) { diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c index e47ebe8ed1..35db44b50e 100644 --- a/qom/qom-qmp-cmds.c +++ b/qom/qom-qmp-cmds.c @@ -21,7 +21,6 @@ #include "qapi/qapi-commands-qom.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" -#include "qapi/qobject-input-visitor.h" #include "qemu/cutils.h" #include "qom/object_interfaces.h" #include "qom/qom-qobject.h" @@ -245,24 +244,6 @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp) { QObject *props; QDict *pdict; - Visitor *v; - Object *obj; - g_autofree char *type = NULL; - g_autofree char *id = NULL; - - type = g_strdup(qdict_get_try_str(qdict, "qom-type")); - if (!type) { - error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); - return; - } - qdict_del(qdict, "qom-type"); - - id = g_strdup(qdict_get_try_str(qdict, "id")); - if (!id) { - error_setg(errp, QERR_MISSING_PARAMETER, "id"); - return; - } - qdict_del(qdict, "id"); props = qdict_get(qdict, "props"); if (props) { @@ -282,10 +263,7 @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp) qobject_unref(pdict); } - v = qobject_input_visitor_new(QOBJECT(qdict)); - obj = user_creatable_add_type(type, id, qdict, v, errp); - visit_free(v); - object_unref(obj); + user_creatable_add_dict(qdict, errp); } void qmp_object_del(const char *id, Error **errp) From eaae29ef89d498d0eac553c77b554f310a47f809 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 16 Apr 2020 17:26:06 +0200 Subject: [PATCH 0139/2595] qemu-storage-daemon: Fix non-string --object properties After processing the option string with the keyval parser, we get a QDict that contains only strings. This QDict must be fed to a keyval visitor which converts the strings into the right data types. qmp_object_add(), however, uses the normal QObject input visitor, which expects a QDict where all properties already have the QType that matches the data type required by the QOM object type. Change the --object implementation in qemu-storage-daemon so that it doesn't call qmp_object_add(), but calls user_creatable_add_dict() directly instead and pass it a new keyval boolean that decides which visitor must be used. Reported-by: Coiby Xu Signed-off-by: Kevin Wolf --- include/qom/object_interfaces.h | 6 +++++- qemu-storage-daemon.c | 4 +--- qom/object_interfaces.c | 8 ++++++-- qom/qom-qmp-cmds.c | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h index a0037968a4..65172120fa 100644 --- a/include/qom/object_interfaces.h +++ b/include/qom/object_interfaces.h @@ -90,6 +90,10 @@ Object *user_creatable_add_type(const char *type, const char *id, /** * user_creatable_add_dict: * @qdict: the object definition + * @keyval: if true, use a keyval visitor for processing @qdict (i.e. + * assume that all @qdict values are strings); otherwise, use + * the normal QObject visitor (i.e. assume all @qdict values + * have the QType expected by the QOM object type) * @errp: if an error occurs, a pointer to an area to store the error * * Create an instance of the user creatable object that is defined by @@ -97,7 +101,7 @@ Object *user_creatable_add_type(const char *type, const char *id, * ID from the key 'id'. The remaining entries in @qdict are used to * initialize the object properties. */ -void user_creatable_add_dict(QDict *qdict, Error **errp); +void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp); /** * user_creatable_add_opts: diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c index dd128978cc..9e7adfe3a6 100644 --- a/qemu-storage-daemon.c +++ b/qemu-storage-daemon.c @@ -278,7 +278,6 @@ static void process_options(int argc, char *argv[]) QemuOpts *opts; const char *type; QDict *args; - QObject *ret_data = NULL; /* FIXME The keyval parser rejects 'help' arguments, so we must * unconditionall try QemuOpts first. */ @@ -291,9 +290,8 @@ static void process_options(int argc, char *argv[]) qemu_opts_del(opts); args = keyval_parse(optarg, "qom-type", &error_fatal); - qmp_object_add(args, &ret_data, &error_fatal); + user_creatable_add_dict(args, true, &error_fatal); qobject_unref(args); - qobject_unref(ret_data); break; } default: diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 739e3e5172..bc36f96e47 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -106,7 +106,7 @@ out: return obj; } -void user_creatable_add_dict(QDict *qdict, Error **errp) +void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp) { Visitor *v; Object *obj; @@ -127,7 +127,11 @@ void user_creatable_add_dict(QDict *qdict, Error **errp) } qdict_del(qdict, "id"); - v = qobject_input_visitor_new(QOBJECT(qdict)); + if (keyval) { + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + } else { + v = qobject_input_visitor_new(QOBJECT(qdict)); + } obj = user_creatable_add_type(type, id, qdict, v, errp); visit_free(v); object_unref(obj); diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c index 35db44b50e..c5249e44d0 100644 --- a/qom/qom-qmp-cmds.c +++ b/qom/qom-qmp-cmds.c @@ -263,7 +263,7 @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp) qobject_unref(pdict); } - user_creatable_add_dict(qdict, errp); + user_creatable_add_dict(qdict, false, errp); } void qmp_object_del(const char *id, Error **errp) From 6dbb716877728ce4eb51619885ef6ef4ada9565f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 1 May 2020 15:06:43 +0100 Subject: [PATCH 0140/2595] virtiofsd: add --rlimit-nofile=NUM option Make it possible to specify the RLIMIT_NOFILE on the command-line. Users running multiple virtiofsd processes should allocate a certain number to each process so that the system-wide limit can never be exhausted. When this option is set to 0 the rlimit is left at its current value. This is useful when a management tool wants to configure the rlimit itself. The default behavior remains unchanged: try to set the limit to 1,000,000 file descriptors if the current rlimit is lower. Signed-off-by: Stefan Hajnoczi Reviewed-by: Dr. David Alan Gilbert Message-Id: <20200501140644.220940-2-stefanha@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/fuse_lowlevel.h | 1 + tools/virtiofsd/helper.c | 23 +++++++++++++++++++++++ tools/virtiofsd/passthrough_ll.c | 22 ++++++++-------------- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h index 8f6d705b5c..562fd5241e 100644 --- a/tools/virtiofsd/fuse_lowlevel.h +++ b/tools/virtiofsd/fuse_lowlevel.h @@ -1777,6 +1777,7 @@ struct fuse_cmdline_opts { int syslog; int log_level; unsigned int max_idle_threads; + unsigned long rlimit_nofile; }; /** diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c index 819c2bc13c..dc59f38af0 100644 --- a/tools/virtiofsd/helper.c +++ b/tools/virtiofsd/helper.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #define FUSE_HELPER_OPT(t, p) \ @@ -53,6 +55,7 @@ static const struct fuse_opt fuse_helper_opts[] = { FUSE_HELPER_OPT("subtype=", nodefault_subtype), FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads), + FUSE_HELPER_OPT("--rlimit-nofile=%lu", rlimit_nofile), FUSE_HELPER_OPT("--syslog", syslog), FUSE_HELPER_OPT_VALUE("log_level=debug", log_level, FUSE_LOG_DEBUG), FUSE_HELPER_OPT_VALUE("log_level=info", log_level, FUSE_LOG_INFO), @@ -171,6 +174,9 @@ void fuse_cmdline_help(void) " default: no_writeback\n" " -o xattr|no_xattr enable/disable xattr\n" " default: no_xattr\n" + " --rlimit-nofile= set maximum number of file descriptors\n" + " (0 leaves rlimit unchanged)\n" + " default: 1,000,000 if the current rlimit is lower\n" ); } @@ -191,11 +197,28 @@ static int fuse_helper_opt_proc(void *data, const char *arg, int key, } } +static unsigned long get_default_rlimit_nofile(void) +{ + rlim_t max_fds = 1000000; /* our default RLIMIT_NOFILE target */ + struct rlimit rlim; + + if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { + fuse_log(FUSE_LOG_ERR, "getrlimit(RLIMIT_NOFILE): %m\n"); + exit(1); + } + + if (rlim.rlim_cur >= max_fds) { + return 0; /* we have more fds available than required! */ + } + return max_fds; +} + int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts) { memset(opts, 0, sizeof(struct fuse_cmdline_opts)); opts->max_idle_threads = 10; + opts->rlimit_nofile = get_default_rlimit_nofile(); opts->foreground = 1; if (fuse_opt_parse(args, opts, fuse_helper_opts, fuse_helper_opt_proc) == diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index 4c35c95b25..f7b9c1d20c 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -2707,24 +2707,18 @@ static void setup_sandbox(struct lo_data *lo, struct fuse_session *se, setup_seccomp(enable_syslog); } -/* Raise the maximum number of open file descriptors */ -static void setup_nofile_rlimit(void) +/* Set the maximum number of open file descriptors */ +static void setup_nofile_rlimit(unsigned long rlimit_nofile) { - const rlim_t max_fds = 1000000; - struct rlimit rlim; + struct rlimit rlim = { + .rlim_cur = rlimit_nofile, + .rlim_max = rlimit_nofile, + }; - if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { - fuse_log(FUSE_LOG_ERR, "getrlimit(RLIMIT_NOFILE): %m\n"); - exit(1); - } - - if (rlim.rlim_cur >= max_fds) { + if (rlimit_nofile == 0) { return; /* nothing to do */ } - rlim.rlim_cur = max_fds; - rlim.rlim_max = max_fds; - if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { /* Ignore SELinux denials */ if (errno == EPERM) { @@ -2977,7 +2971,7 @@ int main(int argc, char *argv[]) fuse_daemonize(opts.foreground); - setup_nofile_rlimit(); + setup_nofile_rlimit(opts.rlimit_nofile); /* Must be before sandbox since it wants /proc */ setup_capng(); From 8c1d353d107b4fc344e27f2f08ea7fa25de2eea2 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 1 May 2020 15:06:44 +0100 Subject: [PATCH 0141/2595] virtiofsd: stay below fs.file-max sysctl value (CVE-2020-10717) The system-wide fs.file-max sysctl value determines how many files can be open. It defaults to a value calculated based on the machine's RAM size. Previously virtiofsd would try to set RLIMIT_NOFILE to 1,000,000 and this allowed the FUSE client to exhaust the number of open files system-wide on Linux hosts with less than 10 GB of RAM! Take fs.file-max into account when choosing the default RLIMIT_NOFILE value. Fixes: CVE-2020-10717 Reported-by: Yuval Avrahami Signed-off-by: Stefan Hajnoczi Reviewed-by: Dr. David Alan Gilbert Message-Id: <20200501140644.220940-3-stefanha@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/helper.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c index dc59f38af0..00a1ef666a 100644 --- a/tools/virtiofsd/helper.c +++ b/tools/virtiofsd/helper.c @@ -176,7 +176,8 @@ void fuse_cmdline_help(void) " default: no_xattr\n" " --rlimit-nofile= set maximum number of file descriptors\n" " (0 leaves rlimit unchanged)\n" - " default: 1,000,000 if the current rlimit is lower\n" + " default: min(1000000, fs.file-max - 16384)\n" + " if the current rlimit is lower\n" ); } @@ -199,9 +200,32 @@ static int fuse_helper_opt_proc(void *data, const char *arg, int key, static unsigned long get_default_rlimit_nofile(void) { + g_autofree gchar *file_max_str = NULL; + const rlim_t reserved_fds = 16384; /* leave at least this many fds free */ rlim_t max_fds = 1000000; /* our default RLIMIT_NOFILE target */ + rlim_t file_max; struct rlimit rlim; + /* + * Reduce max_fds below the system-wide maximum, if necessary. This + * ensures there are fds available for other processes so we don't + * cause resource exhaustion. + */ + if (!g_file_get_contents("/proc/sys/fs/file-max", &file_max_str, + NULL, NULL)) { + fuse_log(FUSE_LOG_ERR, "can't read /proc/sys/fs/file-max\n"); + exit(1); + } + file_max = g_ascii_strtoull(file_max_str, NULL, 10); + if (file_max < 2 * reserved_fds) { + fuse_log(FUSE_LOG_ERR, + "The fs.file-max sysctl is too low (%lu) to allow a " + "reasonable number of open files.\n", + (unsigned long)file_max); + exit(1); + } + max_fds = MIN(file_max - reserved_fds, max_fds); + if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { fuse_log(FUSE_LOG_ERR, "getrlimit(RLIMIT_NOFILE): %m\n"); exit(1); From 397ae982f4df46e7d4b2625c431062c9146f3b83 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 29 Apr 2020 14:47:33 +0200 Subject: [PATCH 0142/2595] virtiofsd: jail lo->proc_self_fd While it's not possible to escape the proc filesystem through lo->proc_self_fd, it is possible to escape to the root of the proc filesystem itself through "../..". Use a temporary mount for opening lo->proc_self_fd, that has it's root at /proc/self/fd/, preventing access to the ancestor directories. Signed-off-by: Miklos Szeredi Message-Id: <20200429124733.22488-1-mszeredi@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/passthrough_ll.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index f7b9c1d20c..d7a6474b6e 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -2536,6 +2536,8 @@ static void print_capabilities(void) static void setup_namespaces(struct lo_data *lo, struct fuse_session *se) { pid_t child; + char template[] = "virtiofsd-XXXXXX"; + char *tmpdir; /* * Create a new pid namespace for *child* processes. We'll have to @@ -2597,12 +2599,33 @@ static void setup_namespaces(struct lo_data *lo, struct fuse_session *se) exit(1); } - /* Now we can get our /proc/self/fd directory file descriptor */ - lo->proc_self_fd = open("/proc/self/fd", O_PATH); - if (lo->proc_self_fd == -1) { - fuse_log(FUSE_LOG_ERR, "open(/proc/self/fd, O_PATH): %m\n"); + tmpdir = mkdtemp(template); + if (!tmpdir) { + fuse_log(FUSE_LOG_ERR, "tmpdir(%s): %m\n", template); exit(1); } + + if (mount("/proc/self/fd", tmpdir, NULL, MS_BIND, NULL) < 0) { + fuse_log(FUSE_LOG_ERR, "mount(/proc/self/fd, %s, MS_BIND): %m\n", + tmpdir); + exit(1); + } + + /* Now we can get our /proc/self/fd directory file descriptor */ + lo->proc_self_fd = open(tmpdir, O_PATH); + if (lo->proc_self_fd == -1) { + fuse_log(FUSE_LOG_ERR, "open(%s, O_PATH): %m\n", tmpdir); + exit(1); + } + + if (umount2(tmpdir, MNT_DETACH) < 0) { + fuse_log(FUSE_LOG_ERR, "umount2(%s, MNT_DETACH): %m\n", tmpdir); + exit(1); + } + + if (rmdir(tmpdir) < 0) { + fuse_log(FUSE_LOG_ERR, "rmdir(%s): %m\n", tmpdir); + } } /* From ace0829c0d08f0e5f1451e402e94495bc2166772 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Fri, 24 Apr 2020 15:35:16 +0200 Subject: [PATCH 0143/2595] virtiofsd: Show submounts Currently, setup_mounts() bind-mounts the shared directory without MS_REC. This makes all submounts disappear. Pass MS_REC so that the guest can see submounts again. Fixes: 5baa3b8e95064c2434bd9e2f312edd5e9ae275dc Signed-off-by: Max Reitz Message-Id: <20200424133516.73077-1-mreitz@redhat.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert Changed Fixes to point to the commit with the problem rather than the commit that turned it on --- tools/virtiofsd/passthrough_ll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index d7a6474b6e..7873692168 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -2666,7 +2666,7 @@ static void setup_mounts(const char *source) int oldroot; int newroot; - if (mount(source, source, NULL, MS_BIND, NULL) < 0) { + if (mount(source, source, NULL, MS_BIND | MS_REC, NULL) < 0) { fuse_log(FUSE_LOG_ERR, "mount(%s, %s, MS_BIND): %m\n", source, source); exit(1); } From a59feb483b8fae24d043569ccfcc97ea23d54a02 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 16 Apr 2020 17:49:06 +0100 Subject: [PATCH 0144/2595] virtiofsd: only retain file system capabilities virtiofsd runs as root but only needs a subset of root's Linux capabilities(7). As a file server its purpose is to create and access files on behalf of a client. It needs to be able to access files with arbitrary uid/gid owners. It also needs to be create device nodes. Introduce a Linux capabilities(7) whitelist and drop all capabilities that we don't need, making the virtiofsd process less powerful than a regular uid root process. # cat /proc/PID/status ... Before After CapInh: 0000000000000000 0000000000000000 CapPrm: 0000003fffffffff 00000000880000df CapEff: 0000003fffffffff 00000000880000df CapBnd: 0000003fffffffff 0000000000000000 CapAmb: 0000000000000000 0000000000000000 Note that file capabilities cannot be used to achieve the same effect on the virtiofsd executable because mount is used during sandbox setup. Therefore we drop capabilities programmatically at the right point during startup. This patch only affects the sandboxed child process. The parent process that sits in waitpid(2) still has full root capabilities and will be addressed in the next patch. Signed-off-by: Stefan Hajnoczi Message-Id: <20200416164907.244868-2-stefanha@redhat.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/passthrough_ll.c | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index 7873692168..e49650b63d 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -2718,6 +2718,43 @@ static void setup_mounts(const char *source) close(oldroot); } +/* + * Only keep whitelisted capabilities that are needed for file system operation + */ +static void setup_capabilities(void) +{ + pthread_mutex_lock(&cap.mutex); + capng_restore_state(&cap.saved); + + /* + * Whitelist file system-related capabilities that are needed for a file + * server to act like root. Drop everything else like networking and + * sysadmin capabilities. + * + * Exclusions: + * 1. CAP_LINUX_IMMUTABLE is not included because it's only used via ioctl + * and we don't support that. + * 2. CAP_MAC_OVERRIDE is not included because it only seems to be + * used by the Smack LSM. Omit it until there is demand for it. + */ + capng_setpid(syscall(SYS_gettid)); + capng_clear(CAPNG_SELECT_BOTH); + capng_updatev(CAPNG_ADD, CAPNG_PERMITTED | CAPNG_EFFECTIVE, + CAP_CHOWN, + CAP_DAC_OVERRIDE, + CAP_DAC_READ_SEARCH, + CAP_FOWNER, + CAP_FSETID, + CAP_SETGID, + CAP_SETUID, + CAP_MKNOD, + CAP_SETFCAP); + capng_apply(CAPNG_SELECT_BOTH); + + cap.saved = capng_save_state(); + pthread_mutex_unlock(&cap.mutex); +} + /* * Lock down this process to prevent access to other processes or files outside * source directory. This reduces the impact of arbitrary code execution bugs. @@ -2728,6 +2765,7 @@ static void setup_sandbox(struct lo_data *lo, struct fuse_session *se, setup_namespaces(lo, se); setup_mounts(lo->source); setup_seccomp(enable_syslog); + setup_capabilities(); } /* Set the maximum number of open file descriptors */ From 66502bbca37ca7a3bfa57e82cfc03b89a7a11eae Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 16 Apr 2020 17:49:07 +0100 Subject: [PATCH 0145/2595] virtiofsd: drop all capabilities in the wait parent process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All this process does is wait for its child. No capabilities are needed. Signed-off-by: Stefan Hajnoczi Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/passthrough_ll.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index e49650b63d..3ba1d90984 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -2530,6 +2530,17 @@ static void print_capabilities(void) printf("}\n"); } +/* + * Drop all Linux capabilities because the wait parent process only needs to + * sit in waitpid(2) and terminate. + */ +static void setup_wait_parent_capabilities(void) +{ + capng_setpid(syscall(SYS_gettid)); + capng_clear(CAPNG_SELECT_BOTH); + capng_apply(CAPNG_SELECT_BOTH); +} + /* * Move to a new mount, net, and pid namespaces to isolate this process. */ @@ -2563,6 +2574,8 @@ static void setup_namespaces(struct lo_data *lo, struct fuse_session *se) pid_t waited; int wstatus; + setup_wait_parent_capabilities(); + /* The parent waits for the child */ do { waited = waitpid(child, &wstatus, 0); From a5cde048e865da81fdc9077f3af28a43bff78d35 Mon Sep 17 00:00:00 2001 From: Yuval Shaia Date: Mon, 13 Apr 2020 11:57:38 +0300 Subject: [PATCH 0146/2595] hw/rdma: Destroy list mutex when list is destroyed List mutex should be destroyed when gs list gets destroyed. Reported-by: Peter Maydell Signed-off-by: Yuval Shaia Message-Id: <20200413085738.11145-1-yuval.shaia.ml@gmail.com> Reviewed-by: Marcel Apfelbaum Signed-off-by: Marcel Apfelbaum --- hw/rdma/rdma_utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/rdma/rdma_utils.c b/hw/rdma/rdma_utils.c index 73f279104c..698ed4716c 100644 --- a/hw/rdma/rdma_utils.c +++ b/hw/rdma/rdma_utils.c @@ -100,6 +100,7 @@ void rdma_protected_gslist_destroy(RdmaProtectedGSList *list) { if (list->list) { g_slist_free(list->list); + qemu_mutex_destroy(&list->lock); list->list = NULL; } } From d58f8860ddba8a316bdcdc1010ca4d2ed0b41941 Mon Sep 17 00:00:00 2001 From: Chen Qun Date: Wed, 25 Mar 2020 10:59:17 +0800 Subject: [PATCH 0147/2595] scsi/esp-pci: add g_assert() for fix clang analyzer warning in esp_pci_io_write() Clang static code analyzer show warning: hw/scsi/esp-pci.c:198:9: warning: Value stored to 'size' is never read size = 4; ^ ~ Reported-by: Euler Robot Signed-off-by: Chen Qun Reviewed-by: Laurent Vivier Message-Id: <20200325025919.21316-2-kuhn.chenqun@huawei.com> Signed-off-by: Laurent Vivier --- hw/scsi/esp-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c index d5a1f9e017..497a8d5901 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -197,6 +197,7 @@ static void esp_pci_io_write(void *opaque, hwaddr addr, addr &= ~3; size = 4; } + g_assert(size >= 4); if (addr < 0x40) { /* SCSI core reg */ From fd1c220395eab1712e67238d876c72bf3292c153 Mon Sep 17 00:00:00 2001 From: Chen Qun Date: Wed, 25 Mar 2020 10:59:18 +0800 Subject: [PATCH 0148/2595] display/blizzard: use extract16() for fix clang analyzer warning in blizzard_draw_line16_32() Clang static code analyzer show warning: hw/display/blizzard.c:940:9: warning: Value stored to 'data' is never read data >>= 5; ^ ~ Reported-by: Euler Robot Signed-off-by: Chen Qun Reviewed-by: Laurent Vivier Message-Id: <20200325025919.21316-3-kuhn.chenqun@huawei.com> Signed-off-by: Laurent Vivier --- hw/display/blizzard.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c index 359e399c2a..105241577d 100644 --- a/hw/display/blizzard.c +++ b/hw/display/blizzard.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/bitops.h" #include "ui/console.h" #include "hw/display/blizzard.h" #include "ui/pixel_ops.h" @@ -932,12 +933,9 @@ static void blizzard_draw_line16_32(uint32_t *dest, const uint16_t *end = (const void *) src + width; while (src < end) { data = *src ++; - b = (data & 0x1f) << 3; - data >>= 5; - g = (data & 0x3f) << 2; - data >>= 6; - r = (data & 0x1f) << 3; - data >>= 5; + b = extract16(data, 0, 5) << 3; + g = extract16(data, 5, 6) << 2; + r = extract16(data, 11, 5) << 3; *dest++ = rgb_to_pixel32(r, g, b); } } From 237d8f09635e01ff2c4e4c8ca28d14b92dfcd8bf Mon Sep 17 00:00:00 2001 From: Chen Qun Date: Wed, 25 Mar 2020 10:59:19 +0800 Subject: [PATCH 0149/2595] timer/exynos4210_mct: Remove redundant statement in exynos4210_mct_write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang static code analyzer show warning: hw/timer/exynos4210_mct.c:1370:9: warning: Value stored to 'index' is never read index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ hw/timer/exynos4210_mct.c:1399:9: warning: Value stored to 'index' is never read index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ hw/timer/exynos4210_mct.c:1441:9: warning: Value stored to 'index' is never read index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Reported-by: Euler Robot Signed-off-by: Chen Qun Reviewed-by: Laurent Vivier Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200325025919.21316-4-kuhn.chenqun@huawei.com> Signed-off-by: Laurent Vivier --- hw/timer/exynos4210_mct.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index 944120aea5..570cf7075b 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -1367,7 +1367,6 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, case L0_TCNTB: case L1_TCNTB: lt_i = GET_L_TIMER_IDX(offset); - index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); /* * TCNTB is updated to internal register only after CNT expired. @@ -1396,7 +1395,6 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, case L0_ICNTB: case L1_ICNTB: lt_i = GET_L_TIMER_IDX(offset); - index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); s->l_timer[lt_i].reg.wstat |= L_WSTAT_ICNTB_WRITE; s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = value & @@ -1438,8 +1436,6 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, case L0_FRCNTB: case L1_FRCNTB: lt_i = GET_L_TIMER_IDX(offset); - index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); - DPRINTF("local timer[%d] FRCNTB write %llx\n", lt_i, value); s->l_timer[lt_i].reg.wstat |= L_WSTAT_FRCCNTB_WRITE; From ab553ef74ee52c0889679d0bd0da084aaf938f5c Mon Sep 17 00:00:00 2001 From: Fredrik Strupe Date: Wed, 8 Apr 2020 13:59:53 +0200 Subject: [PATCH 0150/2595] target/arm: Make VQDMULL undefined when U=1 According to Arm ARM, VQDMULL is only valid when U=0, while having U=1 is unallocated. Signed-off-by: Fredrik Strupe Fixes: 695272dcb976 ("target-arm: Handle UNDEF cases for Neon 3-regs-different-widths") Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index d4ad2028f1..e3fc792442 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -6016,7 +6016,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) {0, 0, 0, 0}, /* VMLSL */ {0, 0, 0, 9}, /* VQDMLSL */ {0, 0, 0, 0}, /* Integer VMULL */ - {0, 0, 0, 1}, /* VQDMULL */ + {0, 0, 0, 9}, /* VQDMULL */ {0, 0, 0, 0xa}, /* Polynomial VMULL */ {0, 0, 0, 7}, /* Reserved: always UNDEF */ }; From 2e256c04c1852efd6a9b48e61fbcaced4b074c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Apr 2020 17:46:50 +0200 Subject: [PATCH 0151/2595] hw/arm/mps2-tz: Use TYPE_IOTKIT instead of hardcoded string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using the TYPE_* definitions for devices, we can: - quickly find where devices are used with 'git-grep' - easily rename a device (one-line change). Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200428154650.21991-1-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mps2-tz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index a8dea7dde1..2c43041564 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -395,7 +395,7 @@ static void mps2tz_common_init(MachineState *machine) exit(EXIT_FAILURE); } - sysbus_init_child_obj(OBJECT(machine), "iotkit", &mms->iotkit, + sysbus_init_child_obj(OBJECT(machine), TYPE_IOTKIT, &mms->iotkit, sizeof(mms->iotkit), mmc->armsse_type); iotkitdev = DEVICE(&mms->iotkit); object_property_set_link(OBJECT(&mms->iotkit), OBJECT(system_memory), From bf05340cb655637451162c02dadcd6581a05c02c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Mar 2020 22:03:57 +0100 Subject: [PATCH 0152/2595] target/arm: Don't use a TLB for ARMMMUIdx_Stage2 We define ARMMMUIdx_Stage2 as being an MMU index which uses a QEMU TLB. However we never actually use the TLB -- all stage 2 lookups are done by direct calls to get_phys_addr_lpae() followed by a physical address load via address_space_ld*(). Remove Stage2 from the list of ARM MMU indexes which correspond to real core MMU indexes, and instead put it in the set of "NOTLB" ARM MMU indexes. This allows us to drop NB_MMU_MODES to 11. It also means we can safely add support for the ARMv8.3-TTS2UXN extension, which adds permission bits to the stage 2 descriptors which define execute permission separatel for EL0 and EL1; supporting that while keeping Stage2 in a QEMU TLB would require us to use separate TLBs for "Stage2 for an EL0 access" and "Stage2 for an EL1 access", which is a lot of extra complication given we aren't even using the QEMU TLB. In the process of updating the comment on our MMU index use, fix a couple of other minor errors: * NS EL2 EL2&0 was missing from the list in the comment * some text hadn't been updated from when we bumped NB_MMU_MODES above 8 Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Message-id: 20200330210400.11724-2-peter.maydell@linaro.org --- target/arm/cpu-param.h | 2 +- target/arm/cpu.h | 21 +++++--- target/arm/helper.c | 112 ++++------------------------------------- 3 files changed, 27 insertions(+), 108 deletions(-) diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h index d593b60b28..6321385b46 100644 --- a/target/arm/cpu-param.h +++ b/target/arm/cpu-param.h @@ -29,6 +29,6 @@ # define TARGET_PAGE_BITS_MIN 10 #endif -#define NB_MMU_MODES 12 +#define NB_MMU_MODES 11 #endif diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 8b9f2961ba..fe03a74bf0 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2801,6 +2801,9 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync); * handling via the TLB. The only way to do a stage 1 translation without * the immediate stage 2 translation is via the ATS or AT system insns, * which can be slow-pathed and always do a page table walk. + * The only use of stage 2 translations is either as part of an s1+2 + * lookup or when loading the descriptors during a stage 1 page table walk, + * and in both those cases we don't use the TLB. * 4. we can also safely fold together the "32 bit EL3" and "64 bit EL3" * translation regimes, because they map reasonably well to each other * and they can't both be active at the same time. @@ -2816,15 +2819,15 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync); * NS EL1 EL1&0 stage 1+2 (aka NS PL1) * NS EL1 EL1&0 stage 1+2 +PAN * NS EL0 EL2&0 + * NS EL2 EL2&0 * NS EL2 EL2&0 +PAN * NS EL2 (aka NS PL2) * S EL0 EL1&0 (aka S PL0) * S EL1 EL1&0 (not used if EL3 is 32 bit) * S EL1 EL1&0 +PAN * S EL3 (aka S PL1) - * NS EL1&0 stage 2 * - * for a total of 12 different mmu_idx. + * for a total of 11 different mmu_idx. * * R profile CPUs have an MPU, but can use the same set of MMU indexes * as A profile. They only need to distinguish NS EL0 and NS EL1 (and @@ -2846,7 +2849,8 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync); * are not quite the same -- different CPU types (most notably M profile * vs A/R profile) would like to use MMU indexes with different semantics, * but since we don't ever need to use all of those in a single CPU we - * can avoid setting NB_MMU_MODES to more than 8. The lower bits of + * can avoid having to set NB_MMU_MODES to "total number of A profile MMU + * modes + total number of M profile MMU modes". The lower bits of * ARMMMUIdx are the core TLB mmu index, and the higher bits are always * the same for any particular CPU. * Variables of type ARMMUIdx are always full values, and the core @@ -2894,8 +2898,6 @@ typedef enum ARMMMUIdx { ARMMMUIdx_SE10_1_PAN = 9 | ARM_MMU_IDX_A, ARMMMUIdx_SE3 = 10 | ARM_MMU_IDX_A, - ARMMMUIdx_Stage2 = 11 | ARM_MMU_IDX_A, - /* * These are not allocated TLBs and are used only for AT system * instructions or for the first stage of an S12 page table walk. @@ -2903,6 +2905,14 @@ typedef enum ARMMMUIdx { ARMMMUIdx_Stage1_E0 = 0 | ARM_MMU_IDX_NOTLB, ARMMMUIdx_Stage1_E1 = 1 | ARM_MMU_IDX_NOTLB, ARMMMUIdx_Stage1_E1_PAN = 2 | ARM_MMU_IDX_NOTLB, + /* + * Not allocated a TLB: used only for second stage of an S12 page + * table walk, or for descriptor loads during first stage of an S1 + * page table walk. Note that if we ever want to have a TLB for this + * then various TLB flush insns which currently are no-ops or flush + * only stage 1 MMU indexes will need to change to flush stage 2. + */ + ARMMMUIdx_Stage2 = 3 | ARM_MMU_IDX_NOTLB, /* * M-profile. @@ -2936,7 +2946,6 @@ typedef enum ARMMMUIdxBit { TO_CORE_BIT(SE10_1), TO_CORE_BIT(SE10_1_PAN), TO_CORE_BIT(SE3), - TO_CORE_BIT(Stage2), TO_CORE_BIT(MUser), TO_CORE_BIT(MPriv), diff --git a/target/arm/helper.c b/target/arm/helper.c index dfefb9b3d9..f785e012cd 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -814,8 +814,7 @@ static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri, tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_1_PAN | - ARMMMUIdxBit_E10_0 | - ARMMMUIdxBit_Stage2); + ARMMMUIdxBit_E10_0); } static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -826,46 +825,9 @@ static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri, tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_1_PAN | - ARMMMUIdxBit_E10_0 | - ARMMMUIdxBit_Stage2); + ARMMMUIdxBit_E10_0); } -static void tlbiipas2_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - /* Invalidate by IPA. This has to invalidate any structures that - * contain only stage 2 translation information, but does not need - * to apply to structures that contain combined stage 1 and stage 2 - * translation information. - * This must NOP if EL2 isn't implemented or SCR_EL3.NS is zero. - */ - CPUState *cs = env_cpu(env); - uint64_t pageaddr; - - if (!arm_feature(env, ARM_FEATURE_EL2) || !(env->cp15.scr_el3 & SCR_NS)) { - return; - } - - pageaddr = sextract64(value << 12, 0, 40); - - tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_Stage2); -} - -static void tlbiipas2_is_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - CPUState *cs = env_cpu(env); - uint64_t pageaddr; - - if (!arm_feature(env, ARM_FEATURE_EL2) || !(env->cp15.scr_el3 & SCR_NS)) { - return; - } - - pageaddr = sextract64(value << 12, 0, 40); - - tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, - ARMMMUIdxBit_Stage2); -} static void tlbiall_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) @@ -4055,8 +4017,7 @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_1_PAN | - ARMMMUIdxBit_E10_0 | - ARMMMUIdxBit_Stage2); + ARMMMUIdxBit_E10_0); raw_write(env, ri, value); } } @@ -4538,11 +4499,6 @@ static int alle1_tlbmask(CPUARMState *env) return ARMMMUIdxBit_SE10_1 | ARMMMUIdxBit_SE10_1_PAN | ARMMMUIdxBit_SE10_0; - } else if (arm_feature(env, ARM_FEATURE_EL2)) { - return ARMMMUIdxBit_E10_1 | - ARMMMUIdxBit_E10_1_PAN | - ARMMMUIdxBit_E10_0 | - ARMMMUIdxBit_Stage2; } else { return ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_1_PAN | @@ -4689,44 +4645,6 @@ static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri, ARMMMUIdxBit_SE3); } -static void tlbi_aa64_ipas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - /* Invalidate by IPA. This has to invalidate any structures that - * contain only stage 2 translation information, but does not need - * to apply to structures that contain combined stage 1 and stage 2 - * translation information. - * This must NOP if EL2 isn't implemented or SCR_EL3.NS is zero. - */ - ARMCPU *cpu = env_archcpu(env); - CPUState *cs = CPU(cpu); - uint64_t pageaddr; - - if (!arm_feature(env, ARM_FEATURE_EL2) || !(env->cp15.scr_el3 & SCR_NS)) { - return; - } - - pageaddr = sextract64(value << 12, 0, 48); - - tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_Stage2); -} - -static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - CPUState *cs = env_cpu(env); - uint64_t pageaddr; - - if (!arm_feature(env, ARM_FEATURE_EL2) || !(env->cp15.scr_el3 & SCR_NS)) { - return; - } - - pageaddr = sextract64(value << 12, 0, 48); - - tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, - ARMMMUIdxBit_Stage2); -} - static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { @@ -4965,12 +4883,10 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .writefn = tlbi_aa64_vae1_write }, { .name = "TLBI_IPAS2E1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, - .writefn = tlbi_aa64_ipas2e1is_write }, + .access = PL2_W, .type = ARM_CP_NOP }, { .name = "TLBI_IPAS2LE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, - .writefn = tlbi_aa64_ipas2e1is_write }, + .access = PL2_W, .type = ARM_CP_NOP }, { .name = "TLBI_ALLE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 4, .access = PL2_W, .type = ARM_CP_NO_RAW, @@ -4981,12 +4897,10 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .writefn = tlbi_aa64_alle1is_write }, { .name = "TLBI_IPAS2E1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1, - .access = PL2_W, .type = ARM_CP_NO_RAW, - .writefn = tlbi_aa64_ipas2e1_write }, + .access = PL2_W, .type = ARM_CP_NOP }, { .name = "TLBI_IPAS2LE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, - .writefn = tlbi_aa64_ipas2e1_write }, + .access = PL2_W, .type = ARM_CP_NOP }, { .name = "TLBI_ALLE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 4, .access = PL2_W, .type = ARM_CP_NO_RAW, @@ -5067,20 +4981,16 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .writefn = tlbimva_hyp_is_write }, { .name = "TLBIIPAS2", .cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL2_W, - .writefn = tlbiipas2_write }, + .type = ARM_CP_NOP, .access = PL2_W }, { .name = "TLBIIPAS2IS", .cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL2_W, - .writefn = tlbiipas2_is_write }, + .type = ARM_CP_NOP, .access = PL2_W }, { .name = "TLBIIPAS2L", .cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5, - .type = ARM_CP_NO_RAW, .access = PL2_W, - .writefn = tlbiipas2_write }, + .type = ARM_CP_NOP, .access = PL2_W }, { .name = "TLBIIPAS2LIS", .cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5, - .type = ARM_CP_NO_RAW, .access = PL2_W, - .writefn = tlbiipas2_is_write }, + .type = ARM_CP_NOP, .access = PL2_W }, /* 32 bit cache operations */ { .name = "ICIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, From 59dff859cd850876df2cfa561c7bcfc4bdda4599 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Mar 2020 22:03:58 +0100 Subject: [PATCH 0153/2595] target/arm: Use enum constant in get_phys_addr_lpae() call The access_type argument to get_phys_addr_lpae() is an MMUAccessType; use the enum constant MMU_DATA_LOAD rather than a literal 0 when we call it in S1_ptw_translate(). Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Message-id: 20200330210400.11724-3-peter.maydell@linaro.org --- target/arm/helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index f785e012cd..f17841ec24 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10052,8 +10052,9 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, pcacheattrs = &cacheattrs; } - ret = get_phys_addr_lpae(env, addr, 0, ARMMMUIdx_Stage2, &s2pa, - &txattrs, &s2prot, &s2size, fi, pcacheattrs); + ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, ARMMMUIdx_Stage2, + &s2pa, &txattrs, &s2prot, &s2size, fi, + pcacheattrs); if (ret) { assert(fi->type != ARMFault_None); fi->s2addr = addr; From ff7de2fc2c994030bfb83af9ddc9a3cd70ce3e88 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Mar 2020 22:03:59 +0100 Subject: [PATCH 0154/2595] target/arm: Add new 's1_is_el0' argument to get_phys_addr_lpae() For ARMv8.2-TTS2UXN, the stage 2 page table walk wants to know whether the stage 1 access is for EL0 or not, because whether exec permission is given can depend on whether this is an EL0 or EL1 access. Add a new argument to get_phys_addr_lpae() so the call sites can pass this information in. Since get_phys_addr_lpae() doesn't already have a doc comment, add one so we have a place to put the documentation of the semantics of the new s1_is_el0 argument. Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Message-id: 20200330210400.11724-4-peter.maydell@linaro.org --- target/arm/helper.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index f17841ec24..b26f580194 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -41,6 +41,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool s1_is_el0, hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, target_ulong *page_size_ptr, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs); @@ -10053,6 +10054,7 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, } ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, ARMMMUIdx_Stage2, + false, &s2pa, &txattrs, &s2prot, &s2size, fi, pcacheattrs); if (ret) { @@ -10655,8 +10657,32 @@ static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va, }; } +/** + * get_phys_addr_lpae: perform one stage of page table walk, LPAE format + * + * Returns false if the translation was successful. Otherwise, phys_ptr, attrs, + * prot and page_size may not be filled in, and the populated fsr value provides + * information on why the translation aborted, in the format of a long-format + * DFSR/IFSR fault register, with the following caveats: + * * the WnR bit is never set (the caller must do this). + * + * @env: CPUARMState + * @address: virtual address to get physical address for + * @access_type: MMU_DATA_LOAD, MMU_DATA_STORE or MMU_INST_FETCH + * @mmu_idx: MMU index indicating required translation regime + * @s1_is_el0: if @mmu_idx is ARMMMUIdx_Stage2 (so this is a stage 2 page table + * walk), must be true if this is stage 2 of a stage 1+2 walk for an + * EL0 access). If @mmu_idx is anything else, @s1_is_el0 is ignored. + * @phys_ptr: set to the physical address corresponding to the virtual address + * @attrs: set to the memory transaction attributes to use + * @prot: set to the permissions for the page containing phys_ptr + * @page_size_ptr: set to the size of the page containing phys_ptr + * @fi: set to fault info if the translation fails + * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes + */ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool s1_is_el0, hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, target_ulong *page_size_ptr, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) @@ -11748,6 +11774,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, /* S1 is done. Now do S2 translation. */ ret = get_phys_addr_lpae(env, ipa, access_type, ARMMMUIdx_Stage2, + mmu_idx == ARMMMUIdx_E10_0, phys_ptr, attrs, &s2_prot, page_size, fi, cacheattrs != NULL ? &cacheattrs2 : NULL); @@ -11872,7 +11899,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, } if (regime_using_lpae_format(env, mmu_idx)) { - return get_phys_addr_lpae(env, address, access_type, mmu_idx, + return get_phys_addr_lpae(env, address, access_type, mmu_idx, false, phys_ptr, attrs, prot, page_size, fi, cacheattrs); } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) { From ce3125bed935a12e619a8253c19340ecaa899347 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Mar 2020 22:04:00 +0100 Subject: [PATCH 0155/2595] target/arm: Implement ARMv8.2-TTS2UXN The ARMv8.2-TTS2UXN feature extends the XN field in stage 2 translation table descriptors from just bit [54] to bits [54:53], allowing stage 2 to control execution permissions separately for EL0 and EL1. Implement the new semantics of the XN field and enable the feature for our 'max' CPU. Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Message-id: 20200330210400.11724-5-peter.maydell@linaro.org --- target/arm/cpu.c | 1 + target/arm/cpu.h | 15 +++++++++++++++ target/arm/cpu64.c | 2 ++ target/arm/helper.c | 37 +++++++++++++++++++++++++++++++------ 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 141d947775..f588344df8 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2686,6 +2686,7 @@ static void arm_max_initfn(Object *obj) t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ + t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */ cpu->isar.id_mmfr4 = t; } #endif diff --git a/target/arm/cpu.h b/target/arm/cpu.h index fe03a74bf0..9aae324d0f 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3610,6 +3610,11 @@ static inline bool isar_feature_aa32_ccidx(const ARMISARegisters *id) return FIELD_EX32(id->id_mmfr4, ID_MMFR4, CCIDX) != 0; } +static inline bool isar_feature_aa32_tts2uxn(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_mmfr4, ID_MMFR4, XNX) != 0; +} + /* * 64-bit feature tests via id registers. */ @@ -3822,6 +3827,11 @@ static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0; } +static inline bool isar_feature_aa64_tts2uxn(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, XNX) != 0; +} + /* * Feature tests for "does this exist in either 32-bit or 64-bit?" */ @@ -3850,6 +3860,11 @@ static inline bool isar_feature_any_ccidx(const ARMISARegisters *id) return isar_feature_aa64_ccidx(id) || isar_feature_aa32_ccidx(id); } +static inline bool isar_feature_any_tts2uxn(const ARMISARegisters *id) +{ + return isar_feature_aa64_tts2uxn(id) || isar_feature_aa32_tts2uxn(id); +} + /* * Forward to the above feature tests given an ARMCPU pointer. */ diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 74afc28d53..e232c0ea12 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -673,6 +673,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */ t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* VMID16 */ + t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* TTS2UXN */ cpu->isar.id_aa64mmfr1 = t; t = cpu->isar.id_aa64mmfr2; @@ -706,6 +707,7 @@ static void aarch64_max_initfn(Object *obj) u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */ u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ u = FIELD_DP32(u, ID_MMFR4, CNP, 1); /* TTCNP */ + u = FIELD_DP32(u, ID_MMFR4, XNX, 1); /* TTS2UXN */ cpu->isar.id_mmfr4 = u; u = cpu->isar.id_aa64dfr0; diff --git a/target/arm/helper.c b/target/arm/helper.c index b26f580194..a94f650795 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9908,9 +9908,10 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) * * @env: CPUARMState * @s2ap: The 2-bit stage2 access permissions (S2AP) - * @xn: XN (execute-never) bit + * @xn: XN (execute-never) bits + * @s1_is_el0: true if this is S2 of an S1+2 walk for EL0 */ -static int get_S2prot(CPUARMState *env, int s2ap, int xn) +static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) { int prot = 0; @@ -9920,9 +9921,32 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn) if (s2ap & 2) { prot |= PAGE_WRITE; } - if (!xn) { - if (arm_el_is_aa64(env, 2) || prot & PAGE_READ) { + + if (cpu_isar_feature(any_tts2uxn, env_archcpu(env))) { + switch (xn) { + case 0: prot |= PAGE_EXEC; + break; + case 1: + if (s1_is_el0) { + prot |= PAGE_EXEC; + } + break; + case 2: + break; + case 3: + if (!s1_is_el0) { + prot |= PAGE_EXEC; + } + break; + default: + g_assert_not_reached(); + } + } else { + if (!extract32(xn, 1, 1)) { + if (arm_el_is_aa64(env, 2) || prot & PAGE_READ) { + prot |= PAGE_EXEC; + } } } return prot; @@ -10901,13 +10925,14 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, } ap = extract32(attrs, 4, 2); - xn = extract32(attrs, 12, 1); if (mmu_idx == ARMMMUIdx_Stage2) { ns = true; - *prot = get_S2prot(env, ap, xn); + xn = extract32(attrs, 11, 2); + *prot = get_S2prot(env, ap, xn, s1_is_el0); } else { ns = extract32(attrs, 3, 1); + xn = extract32(attrs, 12, 1); pxn = extract32(attrs, 11, 1); *prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); } From 5a89dd2385a193aa954a7c9bf4e381f2ba6ae359 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 23 Apr 2020 12:09:15 +0100 Subject: [PATCH 0156/2595] target/arm: Use correct variable for setting 'max' cpu's ID_AA64DFR0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In aarch64_max_initfn() we update both 32-bit and 64-bit ID registers. The intended pattern is that for 64-bit ID registers we use FIELD_DP64 and the uint64_t 't' register, while 32-bit ID registers use FIELD_DP32 and the uint32_t 'u' register. For ID_AA64DFR0 we accidentally used 'u', meaning that the top 32 bits of this 64-bit ID register would end up always zero. Luckily at the moment that's what they should be anyway, so this bug has no visible effects. Use the right-sized variable. Fixes: 3bec78447a958d481991 Signed-off-by: Peter Maydell Reviewed-by: Laurent Desnogues Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200423110915.10527-1-peter.maydell@linaro.org --- target/arm/cpu64.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index e232c0ea12..9bdf75b1ab 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -710,9 +710,9 @@ static void aarch64_max_initfn(Object *obj) u = FIELD_DP32(u, ID_MMFR4, XNX, 1); /* TTS2UXN */ cpu->isar.id_mmfr4 = u; - u = cpu->isar.id_aa64dfr0; - u = FIELD_DP64(u, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */ - cpu->isar.id_aa64dfr0 = u; + t = cpu->isar.id_aa64dfr0; + t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */ + cpu->isar.id_aa64dfr0 = t; u = cpu->isar.id_dfr0; u = FIELD_DP32(u, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ From e544f80030121040c8932ff1bd4006f390266c0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Apr 2020 19:26:34 +0200 Subject: [PATCH 0157/2595] target/arm: Use uint64_t for midr field in CPU state struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MIDR_EL1 is a 64-bit system register with the top 32-bit being RES0. Represent it in QEMU's ARMCPU struct with a uint64_t, not a uint32_t. This fixes an error when compiling with -Werror=conversion because we were manipulating the register value using a local uint64_t variable: target/arm/cpu64.c: In function ‘aarch64_max_initfn’: target/arm/cpu64.c:628:21: error: conversion from ‘uint64_t’ {aka ‘long unsigned int’} to ‘uint32_t’ {aka ‘unsigned int’} may change value [-Werror=conversion] 628 | cpu->midr = t; | ^ and future-proofs us against a possible future architecture change using some of the top 32 bits. Suggested-by: Laurent Desnogues Suggested-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Desnogues Message-id: 20200428172634.29707-1-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu.c | 2 +- target/arm/cpu.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index f588344df8..5d64adfe76 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2755,7 +2755,7 @@ static const ARMCPUInfo arm_cpus[] = { static Property arm_cpu_properties[] = { DEFINE_PROP_BOOL("start-powered-off", ARMCPU, start_powered_off, false), DEFINE_PROP_UINT32("psci-conduit", ARMCPU, psci_conduit, 0), - DEFINE_PROP_UINT32("midr", ARMCPU, midr, 0), + DEFINE_PROP_UINT64("midr", ARMCPU, midr, 0), DEFINE_PROP_UINT64("mp-affinity", ARMCPU, mp_affinity, ARM64_AFFINITY_INVALID), DEFINE_PROP_INT32("node-id", ARMCPU, node_id, CPU_UNSET_NUMA_NODE_ID), diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 9aae324d0f..8608da6b6f 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -894,7 +894,7 @@ struct ARMCPU { uint64_t id_aa64dfr0; uint64_t id_aa64dfr1; } isar; - uint32_t midr; + uint64_t midr; uint32_t revidr; uint32_t reset_fpsid; uint32_t ctr; From 5995a02511cd147212353ee377905112359b6fc1 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 27 Apr 2020 20:16:39 +0200 Subject: [PATCH 0158/2595] hw/arm: versal: Remove inclusion of arm_gicv3_common.h Remove inclusion of arm_gicv3_common.h, this already gets included via xlnx-versal.h. Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Reviewed-by: Luc Michel Message-id: 20200427181649.26851-2-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 94460f2343..c73b2fe755 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -20,7 +20,6 @@ #include "hw/arm/boot.h" #include "kvm_arm.h" #include "hw/misc/unimp.h" -#include "hw/intc/arm_gicv3_common.h" #include "hw/arm/xlnx-versal.h" #include "hw/char/pl011.h" From c07c0c37ad45c6cd1cd9ef94988a4790bb78e287 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 27 Apr 2020 20:16:40 +0200 Subject: [PATCH 0159/2595] hw/arm: versal: Move misplaced comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move misplaced comment. Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Luc Michel Message-id: 20200427181649.26851-3-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index c73b2fe755..cc696e44c0 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -36,7 +36,6 @@ static void versal_create_apu_cpus(Versal *s) obj = object_new(XLNX_VERSAL_ACPU_TYPE); if (!obj) { - /* Secondary CPUs start in PSCI powered-down state */ error_report("Unable to create apu.cpu[%d] of type %s", i, XLNX_VERSAL_ACPU_TYPE); exit(EXIT_FAILURE); @@ -49,6 +48,7 @@ static void versal_create_apu_cpus(Versal *s) object_property_set_int(obj, s->cfg.psci_conduit, "psci-conduit", &error_abort); if (i) { + /* Secondary CPUs start in PSCI powered-down state */ object_property_set_bool(obj, true, "start-powered-off", &error_abort); } From 0b79d1baeec2044ff3c7f315aff91729d698e24a Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 27 Apr 2020 20:16:41 +0200 Subject: [PATCH 0160/2595] hw/arm: versal-virt: Fix typo xlnx-ve -> xlnx-versal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix typo xlnx-ve -> xlnx-versal. Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Luc Michel Message-id: 20200427181649.26851-4-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal-virt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 878a275140..8a608074d1 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -440,7 +440,7 @@ static void versal_virt_init(MachineState *machine) psci_conduit = QEMU_PSCI_CONDUIT_SMC; } - sysbus_init_child_obj(OBJECT(machine), "xlnx-ve", &s->soc, + sysbus_init_child_obj(OBJECT(machine), "xlnx-versal", &s->soc, sizeof(s->soc), TYPE_XLNX_VERSAL); object_property_set_link(OBJECT(&s->soc), OBJECT(machine->ram), "ddr", &error_abort); From 88052ffdd1df6cfe8160662fd4a8cc69f7be63bc Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 27 Apr 2020 20:16:42 +0200 Subject: [PATCH 0161/2595] hw/arm: versal: Embed the UARTs into the SoC type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Embed the UARTs into the SoC type. Suggested-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Luc Michel Message-id: 20200427181649.26851-5-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal.c | 12 ++++++------ include/hw/arm/xlnx-versal.h | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index cc696e44c0..dbde03b7e6 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -21,7 +21,6 @@ #include "kvm_arm.h" #include "hw/misc/unimp.h" #include "hw/arm/xlnx-versal.h" -#include "hw/char/pl011.h" #define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72") #define GEM_REVISION 0x40070106 @@ -144,16 +143,17 @@ static void versal_create_uarts(Versal *s, qemu_irq *pic) DeviceState *dev; MemoryRegion *mr; - dev = qdev_create(NULL, TYPE_PL011); - s->lpd.iou.uart[i] = SYS_BUS_DEVICE(dev); + sysbus_init_child_obj(OBJECT(s), name, + &s->lpd.iou.uart[i], sizeof(s->lpd.iou.uart[i]), + TYPE_PL011); + dev = DEVICE(&s->lpd.iou.uart[i]); qdev_prop_set_chr(dev, "chardev", serial_hd(i)); - object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal); qdev_init_nofail(dev); - mr = sysbus_mmio_get_region(s->lpd.iou.uart[i], 0); + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(&s->mr_ps, addrs[i], mr); - sysbus_connect_irq(s->lpd.iou.uart[i], 0, pic[irqs[i]]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irqs[i]]); g_free(name); } } diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index 6c0a692b2f..a3dfd064b3 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -15,6 +15,7 @@ #include "hw/sysbus.h" #include "hw/arm/boot.h" #include "hw/intc/arm_gicv3.h" +#include "hw/char/pl011.h" #define TYPE_XLNX_VERSAL "xlnx-versal" #define XLNX_VERSAL(obj) OBJECT_CHECK(Versal, (obj), TYPE_XLNX_VERSAL) @@ -49,7 +50,7 @@ typedef struct Versal { MemoryRegion mr_ocm; struct { - SysBusDevice *uart[XLNX_VERSAL_NR_UARTS]; + PL011State uart[XLNX_VERSAL_NR_UARTS]; SysBusDevice *gem[XLNX_VERSAL_NR_GEMS]; SysBusDevice *adma[XLNX_VERSAL_NR_ADMAS]; } iou; From 4bd9b59c05bda9c5a8df84ea63292a9471120b02 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 27 Apr 2020 20:16:43 +0200 Subject: [PATCH 0162/2595] hw/arm: versal: Embed the GEMs into the SoC type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Embed the GEMs into the SoC type. Suggested-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Luc Michel Message-id: 20200427181649.26851-6-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal.c | 15 ++++++++------- include/hw/arm/xlnx-versal.h | 3 ++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index dbde03b7e6..e424aa789e 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -170,25 +170,26 @@ static void versal_create_gems(Versal *s, qemu_irq *pic) DeviceState *dev; MemoryRegion *mr; - dev = qdev_create(NULL, "cadence_gem"); - s->lpd.iou.gem[i] = SYS_BUS_DEVICE(dev); - object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal); + sysbus_init_child_obj(OBJECT(s), name, + &s->lpd.iou.gem[i], sizeof(s->lpd.iou.gem[i]), + TYPE_CADENCE_GEM); + dev = DEVICE(&s->lpd.iou.gem[i]); if (nd->used) { qemu_check_nic_model(nd, "cadence_gem"); qdev_set_nic_properties(dev, nd); } - object_property_set_int(OBJECT(s->lpd.iou.gem[i]), + object_property_set_int(OBJECT(dev), 2, "num-priority-queues", &error_abort); - object_property_set_link(OBJECT(s->lpd.iou.gem[i]), + object_property_set_link(OBJECT(dev), OBJECT(&s->mr_ps), "dma", &error_abort); qdev_init_nofail(dev); - mr = sysbus_mmio_get_region(s->lpd.iou.gem[i], 0); + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(&s->mr_ps, addrs[i], mr); - sysbus_connect_irq(s->lpd.iou.gem[i], 0, pic[irqs[i]]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irqs[i]]); g_free(name); } } diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index a3dfd064b3..01da736a5b 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -16,6 +16,7 @@ #include "hw/arm/boot.h" #include "hw/intc/arm_gicv3.h" #include "hw/char/pl011.h" +#include "hw/net/cadence_gem.h" #define TYPE_XLNX_VERSAL "xlnx-versal" #define XLNX_VERSAL(obj) OBJECT_CHECK(Versal, (obj), TYPE_XLNX_VERSAL) @@ -51,7 +52,7 @@ typedef struct Versal { struct { PL011State uart[XLNX_VERSAL_NR_UARTS]; - SysBusDevice *gem[XLNX_VERSAL_NR_GEMS]; + CadenceGEMState gem[XLNX_VERSAL_NR_GEMS]; SysBusDevice *adma[XLNX_VERSAL_NR_ADMAS]; } iou; } lpd; From f4e3fa3726244460c1f3b52e72be6e1e9547f445 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 27 Apr 2020 20:16:44 +0200 Subject: [PATCH 0163/2595] hw/arm: versal: Embed the ADMAs into the SoC type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Embed the ADMAs into the SoC type. Suggested-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Luc Michel Message-id: 20200427181649.26851-7-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal.c | 14 +++++++------- include/hw/arm/xlnx-versal.h | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index e424aa789e..ebd2dc51be 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -203,18 +203,18 @@ static void versal_create_admas(Versal *s, qemu_irq *pic) DeviceState *dev; MemoryRegion *mr; - dev = qdev_create(NULL, "xlnx.zdma"); - s->lpd.iou.adma[i] = SYS_BUS_DEVICE(dev); - object_property_set_int(OBJECT(s->lpd.iou.adma[i]), 128, "bus-width", - &error_abort); - object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal); + sysbus_init_child_obj(OBJECT(s), name, + &s->lpd.iou.adma[i], sizeof(s->lpd.iou.adma[i]), + TYPE_XLNX_ZDMA); + dev = DEVICE(&s->lpd.iou.adma[i]); + object_property_set_int(OBJECT(dev), 128, "bus-width", &error_abort); qdev_init_nofail(dev); - mr = sysbus_mmio_get_region(s->lpd.iou.adma[i], 0); + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(&s->mr_ps, MM_ADMA_CH0 + i * MM_ADMA_CH0_SIZE, mr); - sysbus_connect_irq(s->lpd.iou.adma[i], 0, pic[VERSAL_ADMA_IRQ_0 + i]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[VERSAL_ADMA_IRQ_0 + i]); g_free(name); } } diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index 01da736a5b..94b7826fd4 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -16,6 +16,7 @@ #include "hw/arm/boot.h" #include "hw/intc/arm_gicv3.h" #include "hw/char/pl011.h" +#include "hw/dma/xlnx-zdma.h" #include "hw/net/cadence_gem.h" #define TYPE_XLNX_VERSAL "xlnx-versal" @@ -53,7 +54,7 @@ typedef struct Versal { struct { PL011State uart[XLNX_VERSAL_NR_UARTS]; CadenceGEMState gem[XLNX_VERSAL_NR_GEMS]; - SysBusDevice *adma[XLNX_VERSAL_NR_ADMAS]; + XlnxZDMA adma[XLNX_VERSAL_NR_ADMAS]; } iou; } lpd; From ced18d5e500eada554b42f39adc1f97b993bc324 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 27 Apr 2020 20:16:45 +0200 Subject: [PATCH 0164/2595] hw/arm: versal: Embed the APUs into the SoC type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Embed the APUs into the SoC type. Suggested-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Luc Michel Message-id: 20200427181649.26851-8-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal-virt.c | 4 ++-- hw/arm/xlnx-versal.c | 19 +++++-------------- include/hw/arm/xlnx-versal.h | 2 +- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 8a608074d1..d7be1ad494 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -469,9 +469,9 @@ static void versal_virt_init(MachineState *machine) s->binfo.get_dtb = versal_virt_get_dtb; s->binfo.modify_dtb = versal_virt_modify_dtb; if (machine->kernel_filename) { - arm_load_kernel(s->soc.fpd.apu.cpu[0], machine, &s->binfo); + arm_load_kernel(&s->soc.fpd.apu.cpu[0], machine, &s->binfo); } else { - AddressSpace *as = arm_boot_address_space(s->soc.fpd.apu.cpu[0], + AddressSpace *as = arm_boot_address_space(&s->soc.fpd.apu.cpu[0], &s->binfo); /* Some boot-loaders (e.g u-boot) don't like blobs at address 0 (NULL). * Offset things by 4K. */ diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index ebd2dc51be..c8a296e2e0 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -31,19 +31,11 @@ static void versal_create_apu_cpus(Versal *s) for (i = 0; i < ARRAY_SIZE(s->fpd.apu.cpu); i++) { Object *obj; - char *name; - - obj = object_new(XLNX_VERSAL_ACPU_TYPE); - if (!obj) { - error_report("Unable to create apu.cpu[%d] of type %s", - i, XLNX_VERSAL_ACPU_TYPE); - exit(EXIT_FAILURE); - } - - name = g_strdup_printf("apu-cpu[%d]", i); - object_property_add_child(OBJECT(s), name, obj, &error_fatal); - g_free(name); + object_initialize_child(OBJECT(s), "apu-cpu[*]", + &s->fpd.apu.cpu[i], sizeof(s->fpd.apu.cpu[i]), + XLNX_VERSAL_ACPU_TYPE, &error_abort, NULL); + obj = OBJECT(&s->fpd.apu.cpu[i]); object_property_set_int(obj, s->cfg.psci_conduit, "psci-conduit", &error_abort); if (i) { @@ -57,7 +49,6 @@ static void versal_create_apu_cpus(Versal *s) object_property_set_link(obj, OBJECT(&s->fpd.apu.mr), "memory", &error_abort); object_property_set_bool(obj, true, "realized", &error_fatal); - s->fpd.apu.cpu[i] = ARM_CPU(obj); } } @@ -95,7 +86,7 @@ static void versal_create_apu_gic(Versal *s, qemu_irq *pic) } for (i = 0; i < nr_apu_cpus; i++) { - DeviceState *cpudev = DEVICE(s->fpd.apu.cpu[i]); + DeviceState *cpudev = DEVICE(&s->fpd.apu.cpu[i]); int ppibase = XLNX_VERSAL_NR_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; qemu_irq maint_irq; int ti; diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index 94b7826fd4..426b66449d 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -36,7 +36,7 @@ typedef struct Versal { struct { struct { MemoryRegion mr; - ARMCPU *cpu[XLNX_VERSAL_NR_ACPUS]; + ARMCPU cpu[XLNX_VERSAL_NR_ACPUS]; GICv3State gic; } apu; } fpd; From 724c6e12dd77a5e2bacd50fd3e7fb32244b491c1 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 27 Apr 2020 20:16:46 +0200 Subject: [PATCH 0165/2595] hw/arm: versal: Add support for SD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for SD. Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Luc Michel Message-id: 20200427181649.26851-9-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal.c | 31 +++++++++++++++++++++++++++++++ include/hw/arm/xlnx-versal.h | 12 ++++++++++++ 2 files changed, 43 insertions(+) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index c8a296e2e0..e263bdf77a 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -210,6 +210,36 @@ static void versal_create_admas(Versal *s, qemu_irq *pic) } } +#define SDHCI_CAPABILITIES 0x280737ec6481 /* Same as on ZynqMP. */ +static void versal_create_sds(Versal *s, qemu_irq *pic) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(s->pmc.iou.sd); i++) { + DeviceState *dev; + MemoryRegion *mr; + + sysbus_init_child_obj(OBJECT(s), "sd[*]", + &s->pmc.iou.sd[i], sizeof(s->pmc.iou.sd[i]), + TYPE_SYSBUS_SDHCI); + dev = DEVICE(&s->pmc.iou.sd[i]); + + object_property_set_uint(OBJECT(dev), + 3, "sd-spec-version", &error_fatal); + object_property_set_uint(OBJECT(dev), SDHCI_CAPABILITIES, "capareg", + &error_fatal); + object_property_set_uint(OBJECT(dev), UHS_I, "uhs", &error_fatal); + qdev_init_nofail(dev); + + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + memory_region_add_subregion(&s->mr_ps, + MM_PMC_SD0 + i * MM_PMC_SD0_SIZE, mr); + + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, + pic[VERSAL_SD0_IRQ_0 + i * 2]); + } +} + /* This takes the board allocated linear DDR memory and creates aliases * for each split DDR range/aperture on the Versal address map. */ @@ -292,6 +322,7 @@ static void versal_realize(DeviceState *dev, Error **errp) versal_create_uarts(s, pic); versal_create_gems(s, pic); versal_create_admas(s, pic); + versal_create_sds(s, pic); versal_map_ddr(s); versal_unimp(s); diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index 426b66449d..e11693e29d 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -14,6 +14,7 @@ #include "hw/sysbus.h" #include "hw/arm/boot.h" +#include "hw/sd/sdhci.h" #include "hw/intc/arm_gicv3.h" #include "hw/char/pl011.h" #include "hw/dma/xlnx-zdma.h" @@ -26,6 +27,7 @@ #define XLNX_VERSAL_NR_UARTS 2 #define XLNX_VERSAL_NR_GEMS 2 #define XLNX_VERSAL_NR_ADMAS 8 +#define XLNX_VERSAL_NR_SDS 2 #define XLNX_VERSAL_NR_IRQS 192 typedef struct Versal { @@ -58,6 +60,13 @@ typedef struct Versal { } iou; } lpd; + /* The Platform Management Controller subsystem. */ + struct { + struct { + SDHCIState sd[XLNX_VERSAL_NR_SDS]; + } iou; + } pmc; + struct { MemoryRegion *mr_ddr; uint32_t psci_conduit; @@ -80,6 +89,7 @@ typedef struct Versal { #define VERSAL_GEM1_IRQ_0 58 #define VERSAL_GEM1_WAKE_IRQ_0 59 #define VERSAL_ADMA_IRQ_0 60 +#define VERSAL_SD0_IRQ_0 126 /* Architecturally reserved IRQs suitable for virtualization. */ #define VERSAL_RSVD_IRQ_FIRST 111 @@ -129,6 +139,8 @@ typedef struct Versal { #define MM_FPD_CRF 0xfd1a0000U #define MM_FPD_CRF_SIZE 0x140000 +#define MM_PMC_SD0 0xf1040000U +#define MM_PMC_SD0_SIZE 0x10000 #define MM_PMC_CRP 0xf1260000U #define MM_PMC_CRP_SIZE 0x10000 #endif From eb1221c52de6a646942a28422a5c56c84364d5b6 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 27 Apr 2020 20:16:47 +0200 Subject: [PATCH 0166/2595] hw/arm: versal: Add support for the RTC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw/arm: versal: Add support for the RTC. Signed-off-by: Edgar E. Iglesias Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Luc Michel Message-id: 20200427181649.26851-10-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal.c | 21 +++++++++++++++++++++ include/hw/arm/xlnx-versal.h | 8 ++++++++ 2 files changed, 29 insertions(+) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index e263bdf77a..321171bcce 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -240,6 +240,26 @@ static void versal_create_sds(Versal *s, qemu_irq *pic) } } +static void versal_create_rtc(Versal *s, qemu_irq *pic) +{ + SysBusDevice *sbd; + MemoryRegion *mr; + + sysbus_init_child_obj(OBJECT(s), "rtc", &s->pmc.rtc, sizeof(s->pmc.rtc), + TYPE_XLNX_ZYNQMP_RTC); + sbd = SYS_BUS_DEVICE(&s->pmc.rtc); + qdev_init_nofail(DEVICE(sbd)); + + mr = sysbus_mmio_get_region(sbd, 0); + memory_region_add_subregion(&s->mr_ps, MM_PMC_RTC, mr); + + /* + * TODO: Connect the ALARM and SECONDS interrupts once our RTC model + * supports them. + */ + sysbus_connect_irq(sbd, 1, pic[VERSAL_RTC_APB_ERR_IRQ]); +} + /* This takes the board allocated linear DDR memory and creates aliases * for each split DDR range/aperture on the Versal address map. */ @@ -323,6 +343,7 @@ static void versal_realize(DeviceState *dev, Error **errp) versal_create_gems(s, pic); versal_create_admas(s, pic); versal_create_sds(s, pic); + versal_create_rtc(s, pic); versal_map_ddr(s); versal_unimp(s); diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index e11693e29d..9c9f47ba9d 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -19,6 +19,7 @@ #include "hw/char/pl011.h" #include "hw/dma/xlnx-zdma.h" #include "hw/net/cadence_gem.h" +#include "hw/rtc/xlnx-zynqmp-rtc.h" #define TYPE_XLNX_VERSAL "xlnx-versal" #define XLNX_VERSAL(obj) OBJECT_CHECK(Versal, (obj), TYPE_XLNX_VERSAL) @@ -65,6 +66,8 @@ typedef struct Versal { struct { SDHCIState sd[XLNX_VERSAL_NR_SDS]; } iou; + + XlnxZynqMPRTC rtc; } pmc; struct { @@ -89,7 +92,10 @@ typedef struct Versal { #define VERSAL_GEM1_IRQ_0 58 #define VERSAL_GEM1_WAKE_IRQ_0 59 #define VERSAL_ADMA_IRQ_0 60 +#define VERSAL_RTC_APB_ERR_IRQ 121 #define VERSAL_SD0_IRQ_0 126 +#define VERSAL_RTC_ALARM_IRQ 142 +#define VERSAL_RTC_SECONDS_IRQ 143 /* Architecturally reserved IRQs suitable for virtualization. */ #define VERSAL_RSVD_IRQ_FIRST 111 @@ -143,4 +149,6 @@ typedef struct Versal { #define MM_PMC_SD0_SIZE 0x10000 #define MM_PMC_CRP 0xf1260000U #define MM_PMC_CRP_SIZE 0x10000 +#define MM_PMC_RTC 0xf12a0000 +#define MM_PMC_RTC_SIZE 0x10000 #endif From 3afec85c2e635d1ee06ef2884f13602db733cd5a Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 27 Apr 2020 20:16:48 +0200 Subject: [PATCH 0167/2595] hw/arm: versal-virt: Add support for SD Add support for SD. Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Reviewed-by: Luc Michel Message-id: 20200427181649.26851-11-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal-virt.c | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index d7be1ad494..0afee48672 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -20,6 +20,7 @@ #include "hw/arm/sysbus-fdt.h" #include "hw/arm/fdt.h" #include "cpu.h" +#include "hw/qdev-properties.h" #include "hw/arm/xlnx-versal.h" #define TYPE_XLNX_VERSAL_VIRT_MACHINE MACHINE_TYPE_NAME("xlnx-versal-virt") @@ -256,6 +257,32 @@ static void fdt_add_zdma_nodes(VersalVirt *s) } } +static void fdt_add_sd_nodes(VersalVirt *s) +{ + const char clocknames[] = "clk_xin\0clk_ahb"; + const char compat[] = "arasan,sdhci-8.9a"; + int i; + + for (i = ARRAY_SIZE(s->soc.pmc.iou.sd) - 1; i >= 0; i--) { + uint64_t addr = MM_PMC_SD0 + MM_PMC_SD0_SIZE * i; + char *name = g_strdup_printf("/sdhci@%" PRIx64, addr); + + qemu_fdt_add_subnode(s->fdt, name); + + qemu_fdt_setprop_cells(s->fdt, name, "clocks", + s->phandle.clk_25Mhz, s->phandle.clk_25Mhz); + qemu_fdt_setprop(s->fdt, name, "clock-names", + clocknames, sizeof(clocknames)); + qemu_fdt_setprop_cells(s->fdt, name, "interrupts", + GIC_FDT_IRQ_TYPE_SPI, VERSAL_SD0_IRQ_0 + i * 2, + GIC_FDT_IRQ_FLAGS_LEVEL_HI); + qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", + 2, addr, 2, MM_PMC_SD0_SIZE); + qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat)); + g_free(name); + } +} + static void fdt_nop_memory_nodes(void *fdt, Error **errp) { Error *err = NULL; @@ -411,10 +438,23 @@ static void create_virtio_regions(VersalVirt *s) } } +static void sd_plugin_card(SDHCIState *sd, DriveInfo *di) +{ + BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL; + DeviceState *card; + + card = qdev_create(qdev_get_child_bus(DEVICE(sd), "sd-bus"), TYPE_SD_CARD); + object_property_add_child(OBJECT(sd), "card[*]", OBJECT(card), + &error_fatal); + qdev_prop_set_drive(card, "drive", blk, &error_fatal); + object_property_set_bool(OBJECT(card), true, "realized", &error_fatal); +} + static void versal_virt_init(MachineState *machine) { VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(machine); int psci_conduit = QEMU_PSCI_CONDUIT_DISABLED; + int i; /* * If the user provides an Operating System to be loaded, we expect them @@ -455,6 +495,7 @@ static void versal_virt_init(MachineState *machine) fdt_add_gic_nodes(s); fdt_add_timer_nodes(s); fdt_add_zdma_nodes(s); + fdt_add_sd_nodes(s); fdt_add_cpu_nodes(s, psci_conduit); fdt_add_clk_node(s, "/clk125", 125000000, s->phandle.clk_125Mhz); fdt_add_clk_node(s, "/clk25", 25000000, s->phandle.clk_25Mhz); @@ -464,6 +505,11 @@ static void versal_virt_init(MachineState *machine) memory_region_add_subregion_overlap(get_system_memory(), 0, &s->soc.fpd.apu.mr, 0); + /* Plugin SD cards. */ + for (i = 0; i < ARRAY_SIZE(s->soc.pmc.iou.sd); i++) { + sd_plugin_card(&s->soc.pmc.iou.sd[i], drive_get_next(IF_SD)); + } + s->binfo.ram_size = machine->ram_size; s->binfo.loader_start = 0x0; s->binfo.get_dtb = versal_virt_get_dtb; From 2aca5284b14b7f3bedec7c59e7cc68da26944585 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 27 Apr 2020 20:16:49 +0200 Subject: [PATCH 0168/2595] hw/arm: versal-virt: Add support for the RTC Add support for the RTC. Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Reviewed-by: Luc Michel Message-id: 20200427181649.26851-12-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal-virt.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 0afee48672..7e749e1926 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -283,6 +283,27 @@ static void fdt_add_sd_nodes(VersalVirt *s) } } +static void fdt_add_rtc_node(VersalVirt *s) +{ + const char compat[] = "xlnx,zynqmp-rtc"; + const char interrupt_names[] = "alarm\0sec"; + char *name = g_strdup_printf("/rtc@%x", MM_PMC_RTC); + + qemu_fdt_add_subnode(s->fdt, name); + + qemu_fdt_setprop_cells(s->fdt, name, "interrupts", + GIC_FDT_IRQ_TYPE_SPI, VERSAL_RTC_ALARM_IRQ, + GIC_FDT_IRQ_FLAGS_LEVEL_HI, + GIC_FDT_IRQ_TYPE_SPI, VERSAL_RTC_SECONDS_IRQ, + GIC_FDT_IRQ_FLAGS_LEVEL_HI); + qemu_fdt_setprop(s->fdt, name, "interrupt-names", + interrupt_names, sizeof(interrupt_names)); + qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", + 2, MM_PMC_RTC, 2, MM_PMC_RTC_SIZE); + qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat)); + g_free(name); +} + static void fdt_nop_memory_nodes(void *fdt, Error **errp) { Error *err = NULL; @@ -496,6 +517,7 @@ static void versal_virt_init(MachineState *machine) fdt_add_timer_nodes(s); fdt_add_zdma_nodes(s); fdt_add_sd_nodes(s); + fdt_add_rtc_node(s); fdt_add_cpu_nodes(s, psci_conduit); fdt_add_clk_node(s, "/clk125", 125000000, s->phandle.clk_125Mhz); fdt_add_clk_node(s, "/clk25", 25000000, s->phandle.clk_25Mhz); From 0d787cf1f3c88fa29477e054f8523f6d82d91c98 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:28 +0100 Subject: [PATCH 0169/2595] target/arm/translate-vfp.inc.c: Remove duplicate simd_r32 check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Somewhere along theline we accidentally added a duplicate "using D16-D31 when they don't exist" check to do_vfm_dp() (probably an artifact of a patchseries rebase). Remove it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200430181003.21682-2-peter.maydell@linaro.org --- target/arm/translate-vfp.inc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c index b087bbd812..e1a9017598 100644 --- a/target/arm/translate-vfp.inc.c +++ b/target/arm/translate-vfp.inc.c @@ -1872,12 +1872,6 @@ static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d) return false; } - /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { - return false; - } - if (!vfp_access_check(s)) { return true; } From d1a6d3b594157425232a1ae5ea7f51b7a1c1aa2e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:29 +0100 Subject: [PATCH 0170/2595] target/arm: Don't allow Thumb Neon insns without FEATURE_NEON MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were accidentally permitting decode of Thumb Neon insns even if the CPU didn't have the FEATURE_NEON bit set, because the feature check was being done before the call to disas_neon_data_insn() and disas_neon_ls_insn() in the Arm decoder but was omitted from the Thumb decoder. Push the feature bit check down into the called functions so it is done for both Arm and Thumb encodings. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200430181003.21682-3-peter.maydell@linaro.org --- target/arm/translate.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index e3fc792442..4cf5267be0 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3258,6 +3258,10 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn) TCGv_i32 tmp2; TCGv_i64 tmp64; + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return 1; + } + /* FIXME: this access check should not take precedence over UNDEF * for invalid encodings; we will generate incorrect syndrome information * for attempts to execute invalid vfp/neon encodings with FP disabled. @@ -5002,6 +5006,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) TCGv_ptr ptr1, ptr2, ptr3; TCGv_i64 tmp64; + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return 1; + } + /* FIXME: this access check should not take precedence over UNDEF * for invalid encodings; we will generate incorrect syndrome information * for attempts to execute invalid vfp/neon encodings with FP disabled. @@ -10948,10 +10956,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) if (((insn >> 25) & 7) == 1) { /* NEON Data processing. */ - if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { - goto illegal_op; - } - if (disas_neon_data_insn(s, insn)) { goto illegal_op; } @@ -10959,10 +10963,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } if ((insn & 0x0f100000) == 0x04000000) { /* NEON load/store. */ - if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { - goto illegal_op; - } - if (disas_neon_ls_insn(s, insn)) { goto illegal_op; } From 625e3dd44a15dfbe9532daa6454df3f86cf04d3e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:30 +0100 Subject: [PATCH 0171/2595] target/arm: Add stubs for AArch32 Neon decodetree Add the infrastructure for building and invoking a decodetree decoder for the AArch32 Neon encodings. At the moment the new decoder covers nothing, so we always fall back to the existing hand-written decode. We follow the same pattern we did for the VFP decodetree conversion (commit 78e138bc1f672c145ef6ace74617d and following): code that deals with Neon will be moving gradually out to translate-neon.vfp.inc, which we #include into translate.c. In order to share the decode files between A32 and T32, we split Neon into 3 parts: * data-processing * load-store * 'shared' encodings The first two groups of instructions have similar but not identical A32 and T32 encodings, so we need to manually transform the T32 encoding into the A32 one before calling the decoder; the third group covers the Neon instructions which are identical in A32 and T32. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-4-peter.maydell@linaro.org --- target/arm/Makefile.objs | 18 +++++++++++++++++ target/arm/neon-dp.decode | 29 ++++++++++++++++++++++++++ target/arm/neon-ls.decode | 29 ++++++++++++++++++++++++++ target/arm/neon-shared.decode | 27 +++++++++++++++++++++++++ target/arm/translate-neon.inc.c | 32 +++++++++++++++++++++++++++++ target/arm/translate.c | 36 +++++++++++++++++++++++++++++++-- 6 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 target/arm/neon-dp.decode create mode 100644 target/arm/neon-ls.decode create mode 100644 target/arm/neon-shared.decode create mode 100644 target/arm/translate-neon.inc.c diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs index cf26c16f5f..775b3e24f2 100644 --- a/target/arm/Makefile.objs +++ b/target/arm/Makefile.objs @@ -18,6 +18,21 @@ target/arm/decode-sve.inc.c: $(SRC_PATH)/target/arm/sve.decode $(DECODETREE) $(PYTHON) $(DECODETREE) --decode disas_sve -o $@ $<,\ "GEN", $(TARGET_DIR)$@) +target/arm/decode-neon-shared.inc.c: $(SRC_PATH)/target/arm/neon-shared.decode $(DECODETREE) + $(call quiet-command,\ + $(PYTHON) $(DECODETREE) --static-decode disas_neon_shared -o $@ $<,\ + "GEN", $(TARGET_DIR)$@) + +target/arm/decode-neon-dp.inc.c: $(SRC_PATH)/target/arm/neon-dp.decode $(DECODETREE) + $(call quiet-command,\ + $(PYTHON) $(DECODETREE) --static-decode disas_neon_dp -o $@ $<,\ + "GEN", $(TARGET_DIR)$@) + +target/arm/decode-neon-ls.inc.c: $(SRC_PATH)/target/arm/neon-ls.decode $(DECODETREE) + $(call quiet-command,\ + $(PYTHON) $(DECODETREE) --static-decode disas_neon_ls -o $@ $<,\ + "GEN", $(TARGET_DIR)$@) + target/arm/decode-vfp.inc.c: $(SRC_PATH)/target/arm/vfp.decode $(DECODETREE) $(call quiet-command,\ $(PYTHON) $(DECODETREE) --static-decode disas_vfp -o $@ $<,\ @@ -49,6 +64,9 @@ target/arm/decode-t16.inc.c: $(SRC_PATH)/target/arm/t16.decode $(DECODETREE) "GEN", $(TARGET_DIR)$@) target/arm/translate-sve.o: target/arm/decode-sve.inc.c +target/arm/translate.o: target/arm/decode-neon-shared.inc.c +target/arm/translate.o: target/arm/decode-neon-dp.inc.c +target/arm/translate.o: target/arm/decode-neon-ls.inc.c target/arm/translate.o: target/arm/decode-vfp.inc.c target/arm/translate.o: target/arm/decode-vfp-uncond.inc.c target/arm/translate.o: target/arm/decode-a32.inc.c diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode new file mode 100644 index 0000000000..c89a1a5859 --- /dev/null +++ b/target/arm/neon-dp.decode @@ -0,0 +1,29 @@ +# AArch32 Neon data-processing instruction descriptions +# +# Copyright (c) 2020 Linaro, Ltd +# +# 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 . + +# +# This file is processed by scripts/decodetree.py +# + +# Encodings for Neon data processing instructions where the T32 encoding +# is a simple transformation of the A32 encoding. +# More specifically, this file covers instructions where the A32 encoding is +# 0b1111_001p_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq +# and the T32 encoding is +# 0b111p_1111_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq +# This file works on the A32 encoding only; calling code for T32 has to +# transform the insn into the A32 version first. diff --git a/target/arm/neon-ls.decode b/target/arm/neon-ls.decode new file mode 100644 index 0000000000..2b16c9256d --- /dev/null +++ b/target/arm/neon-ls.decode @@ -0,0 +1,29 @@ +# AArch32 Neon load/store instruction descriptions +# +# Copyright (c) 2020 Linaro, Ltd +# +# 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 . + +# +# This file is processed by scripts/decodetree.py +# + +# Encodings for Neon load/store instructions where the T32 encoding +# is a simple transformation of the A32 encoding. +# More specifically, this file covers instructions where the A32 encoding is +# 0b1111_0100_xxx0_xxxx_xxxx_xxxx_xxxx_xxxx +# and the T32 encoding is +# 0b1111_1001_xxx0_xxxx_xxxx_xxxx_xxxx_xxxx +# This file works on the A32 encoding only; calling code for T32 has to +# transform the insn into the A32 version first. diff --git a/target/arm/neon-shared.decode b/target/arm/neon-shared.decode new file mode 100644 index 0000000000..3aea7c5e18 --- /dev/null +++ b/target/arm/neon-shared.decode @@ -0,0 +1,27 @@ +# AArch32 Neon instruction descriptions +# +# Copyright (c) 2020 Linaro, Ltd +# +# 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 . + +# +# This file is processed by scripts/decodetree.py +# + +# Encodings for Neon instructions whose encoding is the same for +# both A32 and T32. + +# More specifically, this covers: +# 2reg scalar ext: 0b1111_1110_xxxx_xxxx_xxxx_1x0x_xxxx_xxxx +# 3same ext: 0b1111_110x_xxxx_xxxx_xxxx_1x0x_xxxx_xxxx diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c new file mode 100644 index 0000000000..a33e81ba3a --- /dev/null +++ b/target/arm/translate-neon.inc.c @@ -0,0 +1,32 @@ +/* + * ARM translation: AArch32 Neon instructions + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2005-2007 CodeSourcery + * Copyright (c) 2007 OpenedHand, Ltd. + * Copyright (c) 2020 Linaro, Ltd. + * + * 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 . + */ + +/* + * This file is intended to be included from translate.c; it uses + * some macros and definitions provided by that file. + * It might be possible to convert it to a standalone .c file eventually. + */ + +/* Include the generated Neon decoder */ +#include "decode-neon-dp.inc.c" +#include "decode-neon-ls.inc.c" +#include "decode-neon-shared.inc.c" diff --git a/target/arm/translate.c b/target/arm/translate.c index 4cf5267be0..5a82a56e8e 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -1313,8 +1313,9 @@ static TCGv_ptr vfp_reg_ptr(bool dp, int reg) #define ARM_CP_RW_BIT (1 << 20) -/* Include the VFP decoder */ +/* Include the VFP and Neon decoders */ #include "translate-vfp.inc.c" +#include "translate-neon.inc.c" static inline void iwmmxt_load_reg(TCGv_i64 var, int reg) { @@ -10949,7 +10950,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) /* Unconditional instructions. */ /* TODO: Perhaps merge these into one decodetree output file. */ if (disas_a32_uncond(s, insn) || - disas_vfp_uncond(s, insn)) { + disas_vfp_uncond(s, insn) || + disas_neon_dp(s, insn) || + disas_neon_ls(s, insn) || + disas_neon_shared(s, insn)) { return; } /* fall back to legacy decoder */ @@ -11102,6 +11106,33 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) ARCH(6T2); } + if ((insn & 0xef000000) == 0xef000000) { + /* + * T32 encodings 0b111p_1111_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq + * transform into + * A32 encodings 0b1111_001p_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq + */ + uint32_t a32_insn = (insn & 0xe2ffffff) | + ((insn & (1 << 28)) >> 4) | (1 << 28); + + if (disas_neon_dp(s, a32_insn)) { + return; + } + } + + if ((insn & 0xff100000) == 0xf9000000) { + /* + * T32 encodings 0b1111_1001_ppp0_qqqq_qqqq_qqqq_qqqq_qqqq + * transform into + * A32 encodings 0b1111_0100_ppp0_qqqq_qqqq_qqqq_qqqq_qqqq + */ + uint32_t a32_insn = (insn & 0x00ffffff) | 0xf4000000; + + if (disas_neon_ls(s, a32_insn)) { + return; + } + } + /* * TODO: Perhaps merge these into one decodetree output file. * Note disas_vfp is written for a32 with cond field in the @@ -11109,6 +11140,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) */ if (disas_t32(s, insn) || disas_vfp_uncond(s, insn) || + disas_neon_shared(s, insn) || ((insn >> 28) == 0xe && disas_vfp(s, insn))) { return; } From afff8de0d4d55b4ce7c36eb9cdfafe477a35dd75 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:31 +0100 Subject: [PATCH 0172/2595] target/arm: Convert VCMLA (vector) to decodetree Convert the VCMLA (vector) insns in the 3same extension group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-5-peter.maydell@linaro.org --- target/arm/neon-shared.decode | 11 ++++++++++ target/arm/translate-neon.inc.c | 37 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 11 +--------- 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/target/arm/neon-shared.decode b/target/arm/neon-shared.decode index 3aea7c5e18..d1d707a56d 100644 --- a/target/arm/neon-shared.decode +++ b/target/arm/neon-shared.decode @@ -25,3 +25,14 @@ # More specifically, this covers: # 2reg scalar ext: 0b1111_1110_xxxx_xxxx_xxxx_1x0x_xxxx_xxxx # 3same ext: 0b1111_110x_xxxx_xxxx_xxxx_1x0x_xxxx_xxxx + +# VFP/Neon register fields; same as vfp.decode +%vm_dp 5:1 0:4 +%vm_sp 0:4 5:1 +%vn_dp 7:1 16:4 +%vn_sp 16:4 7:1 +%vd_dp 22:1 12:4 +%vd_sp 12:4 22:1 + +VCMLA 1111 110 rot:2 . 1 size:1 .... .... 1000 . q:1 . 0 .... \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index a33e81ba3a..0baae1338a 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -30,3 +30,40 @@ #include "decode-neon-dp.inc.c" #include "decode-neon-ls.inc.c" #include "decode-neon-shared.inc.c" + +static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) +{ + int opr_sz; + TCGv_ptr fpst; + gen_helper_gvec_3_ptr *fn_gvec_ptr; + + if (!dc_isar_feature(aa32_vcma, s) + || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if ((a->vn | a->vm | a->vd) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + opr_sz = (1 + a->q) * 8; + fpst = get_fpstatus_ptr(1); + fn_gvec_ptr = a->size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah; + tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), + vfp_reg_offset(1, a->vn), + vfp_reg_offset(1, a->vm), + fpst, opr_sz, opr_sz, a->rot, + fn_gvec_ptr); + tcg_temp_free_ptr(fpst); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 5a82a56e8e..ae6799c6ae 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -7048,16 +7048,7 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn) bool is_long = false, q = extract32(insn, 6, 1); bool ptr_is_env = false; - if ((insn & 0xfe200f10) == 0xfc200800) { - /* VCMLA -- 1111 110R R.1S .... .... 1000 ...0 .... */ - int size = extract32(insn, 20, 1); - data = extract32(insn, 23, 2); /* rot */ - if (!dc_isar_feature(aa32_vcma, s) - || (!size && !dc_isar_feature(aa32_fp16_arith, s))) { - return 1; - } - fn_gvec_ptr = size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah; - } else if ((insn & 0xfea00f10) == 0xfc800800) { + if ((insn & 0xfea00f10) == 0xfc800800) { /* VCADD -- 1111 110R 1.0S .... .... 1000 ...0 .... */ int size = extract32(insn, 20, 1); data = extract32(insn, 24, 1); /* rot */ From 94d5eb7b3f72fbbdee55d7908e9cb6de95949f4b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:32 +0100 Subject: [PATCH 0173/2595] target/arm: Convert VCADD (vector) to decodetree Convert the VCADD (vector) insns to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-6-peter.maydell@linaro.org --- target/arm/neon-shared.decode | 3 +++ target/arm/translate-neon.inc.c | 37 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 11 +--------- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/target/arm/neon-shared.decode b/target/arm/neon-shared.decode index d1d707a56d..ed65dae180 100644 --- a/target/arm/neon-shared.decode +++ b/target/arm/neon-shared.decode @@ -36,3 +36,6 @@ VCMLA 1111 110 rot:2 . 1 size:1 .... .... 1000 . q:1 . 0 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp + +VCADD 1111 110 rot:1 1 . 0 size:1 .... .... 1000 . q:1 . 0 .... \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 0baae1338a..28011e88d9 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -67,3 +67,40 @@ static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) tcg_temp_free_ptr(fpst); return true; } + +static bool trans_VCADD(DisasContext *s, arg_VCADD *a) +{ + int opr_sz; + TCGv_ptr fpst; + gen_helper_gvec_3_ptr *fn_gvec_ptr; + + if (!dc_isar_feature(aa32_vcma, s) + || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if ((a->vn | a->vm | a->vd) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + opr_sz = (1 + a->q) * 8; + fpst = get_fpstatus_ptr(1); + fn_gvec_ptr = a->size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh; + tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), + vfp_reg_offset(1, a->vn), + vfp_reg_offset(1, a->vm), + fpst, opr_sz, opr_sz, a->rot, + fn_gvec_ptr); + tcg_temp_free_ptr(fpst); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index ae6799c6ae..993bead82f 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -7048,16 +7048,7 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn) bool is_long = false, q = extract32(insn, 6, 1); bool ptr_is_env = false; - if ((insn & 0xfea00f10) == 0xfc800800) { - /* VCADD -- 1111 110R 1.0S .... .... 1000 ...0 .... */ - int size = extract32(insn, 20, 1); - data = extract32(insn, 24, 1); /* rot */ - if (!dc_isar_feature(aa32_vcma, s) - || (!size && !dc_isar_feature(aa32_fp16_arith, s))) { - return 1; - } - fn_gvec_ptr = size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh; - } else if ((insn & 0xfeb00f00) == 0xfc200d00) { + if ((insn & 0xfeb00f00) == 0xfc200d00) { /* V[US]DOT -- 1111 1100 0.10 .... .... 1101 .Q.U .... */ bool u = extract32(insn, 4, 1); if (!dc_isar_feature(aa32_dp, s)) { From 32da0e330d3e5218b669079826496751fb52c1ca Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:33 +0100 Subject: [PATCH 0174/2595] target/arm: Convert V[US]DOT (vector) to decodetree Convert the V[US]DOT (vector) insns to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-7-peter.maydell@linaro.org --- target/arm/neon-shared.decode | 4 ++++ target/arm/translate-neon.inc.c | 32 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 9 +-------- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/target/arm/neon-shared.decode b/target/arm/neon-shared.decode index ed65dae180..c9c641905d 100644 --- a/target/arm/neon-shared.decode +++ b/target/arm/neon-shared.decode @@ -39,3 +39,7 @@ VCMLA 1111 110 rot:2 . 1 size:1 .... .... 1000 . q:1 . 0 .... \ VCADD 1111 110 rot:1 1 . 0 size:1 .... .... 1000 . q:1 . 0 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp + +# VUDOT and VSDOT +VDOT 1111 110 00 . 10 .... .... 1101 . q:1 . u:1 .... \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 28011e88d9..6537506c5b 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -104,3 +104,35 @@ static bool trans_VCADD(DisasContext *s, arg_VCADD *a) tcg_temp_free_ptr(fpst); return true; } + +static bool trans_VDOT(DisasContext *s, arg_VDOT *a) +{ + int opr_sz; + gen_helper_gvec_3 *fn_gvec; + + if (!dc_isar_feature(aa32_dp, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if ((a->vn | a->vm | a->vd) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + opr_sz = (1 + a->q) * 8; + fn_gvec = a->u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b; + tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd), + vfp_reg_offset(1, a->vn), + vfp_reg_offset(1, a->vm), + opr_sz, opr_sz, 0, fn_gvec); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 993bead82f..7d3aea8c98 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -7048,14 +7048,7 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn) bool is_long = false, q = extract32(insn, 6, 1); bool ptr_is_env = false; - if ((insn & 0xfeb00f00) == 0xfc200d00) { - /* V[US]DOT -- 1111 1100 0.10 .... .... 1101 .Q.U .... */ - bool u = extract32(insn, 4, 1); - if (!dc_isar_feature(aa32_dp, s)) { - return 1; - } - fn_gvec = u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b; - } else if ((insn & 0xff300f10) == 0xfc200810) { + if ((insn & 0xff300f10) == 0xfc200810) { /* VFM[AS]L -- 1111 1100 S.10 .... .... 1000 .Q.1 .... */ int is_s = extract32(insn, 23, 1); if (!dc_isar_feature(aa32_fhm, s)) { From 9a107e7b8a3c87ab63ec830d3d60f319fc577ff7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:34 +0100 Subject: [PATCH 0175/2595] target/arm: Convert VFM[AS]L (vector) to decodetree Convert the VFM[AS]L (vector) insns to decodetree. This is the last insn in the legacy decoder for the 3same_ext group, so we can delete the legacy decoder function for the group entirely. Note that in disas_thumb2_insn() the parts of this encoding space where the decodetree decoder returns false will correctly be directed to illegal_op by the "(insn & (1 << 28))" check so they won't fall into disas_coproc_insn() by mistake. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-8-peter.maydell@linaro.org --- target/arm/neon-shared.decode | 6 +++ target/arm/translate-neon.inc.c | 31 +++++++++++ target/arm/translate.c | 92 +-------------------------------- 3 files changed, 38 insertions(+), 91 deletions(-) diff --git a/target/arm/neon-shared.decode b/target/arm/neon-shared.decode index c9c641905d..90cd5c871e 100644 --- a/target/arm/neon-shared.decode +++ b/target/arm/neon-shared.decode @@ -43,3 +43,9 @@ VCADD 1111 110 rot:1 1 . 0 size:1 .... .... 1000 . q:1 . 0 .... \ # VUDOT and VSDOT VDOT 1111 110 00 . 10 .... .... 1101 . q:1 . u:1 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp + +# VFM[AS]L +VFML 1111 110 0 s:1 . 10 .... .... 1000 . 0 . 1 .... \ + vm=%vm_sp vn=%vn_sp vd=%vd_dp q=0 +VFML 1111 110 0 s:1 . 10 .... .... 1000 . 1 . 1 .... \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp q=1 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 6537506c5b..6c58abc54b 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -136,3 +136,34 @@ static bool trans_VDOT(DisasContext *s, arg_VDOT *a) opr_sz, opr_sz, 0, fn_gvec); return true; } + +static bool trans_VFML(DisasContext *s, arg_VFML *a) +{ + int opr_sz; + + if (!dc_isar_feature(aa32_fhm, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + (a->vd & 0x10)) { + return false; + } + + if (a->vd & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + opr_sz = (1 + a->q) * 8; + tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), + vfp_reg_offset(a->q, a->vn), + vfp_reg_offset(a->q, a->vm), + cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */ + gen_helper_gvec_fmlal_a32); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 7d3aea8c98..79cd9138fe 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -7032,84 +7032,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 0; } -/* Advanced SIMD three registers of the same length extension. - * 31 25 23 22 20 16 12 11 10 9 8 3 0 - * +---------------+-----+---+-----+----+----+---+----+---+----+---------+----+ - * | 1 1 1 1 1 1 0 | op1 | D | op2 | Vn | Vd | 1 | o3 | 0 | o4 | N Q M U | Vm | - * +---------------+-----+---+-----+----+----+---+----+---+----+---------+----+ - */ -static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn) -{ - gen_helper_gvec_3 *fn_gvec = NULL; - gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL; - int rd, rn, rm, opr_sz; - int data = 0; - int off_rn, off_rm; - bool is_long = false, q = extract32(insn, 6, 1); - bool ptr_is_env = false; - - if ((insn & 0xff300f10) == 0xfc200810) { - /* VFM[AS]L -- 1111 1100 S.10 .... .... 1000 .Q.1 .... */ - int is_s = extract32(insn, 23, 1); - if (!dc_isar_feature(aa32_fhm, s)) { - return 1; - } - is_long = true; - data = is_s; /* is_2 == 0 */ - fn_gvec_ptr = gen_helper_gvec_fmlal_a32; - ptr_is_env = true; - } else { - return 1; - } - - VFP_DREG_D(rd, insn); - if (rd & q) { - return 1; - } - if (q || !is_long) { - VFP_DREG_N(rn, insn); - VFP_DREG_M(rm, insn); - if ((rn | rm) & q & !is_long) { - return 1; - } - off_rn = vfp_reg_offset(1, rn); - off_rm = vfp_reg_offset(1, rm); - } else { - rn = VFP_SREG_N(insn); - rm = VFP_SREG_M(insn); - off_rn = vfp_reg_offset(0, rn); - off_rm = vfp_reg_offset(0, rm); - } - - if (s->fp_excp_el) { - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_simd_access_trap(1, 0xe, false), s->fp_excp_el); - return 0; - } - if (!s->vfp_enabled) { - return 1; - } - - opr_sz = (1 + q) * 8; - if (fn_gvec_ptr) { - TCGv_ptr ptr; - if (ptr_is_env) { - ptr = cpu_env; - } else { - ptr = get_fpstatus_ptr(1); - } - tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, ptr, - opr_sz, opr_sz, data, fn_gvec_ptr); - if (!ptr_is_env) { - tcg_temp_free_ptr(ptr); - } - } else { - tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm, - opr_sz, opr_sz, data, fn_gvec); - } - return 0; -} - /* Advanced SIMD two registers and a scalar extension. * 31 24 23 22 20 16 12 11 10 9 8 3 0 * +-----------------+----+---+----+----+----+---+----+---+----+---------+----+ @@ -10956,12 +10878,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } } } - } else if ((insn & 0x0e000a00) == 0x0c000800 - && arm_dc_feature(s, ARM_FEATURE_V8)) { - if (disas_neon_insn_3same_ext(s, insn)) { - goto illegal_op; - } - return; } else if ((insn & 0x0f000a00) == 0x0e000800 && arm_dc_feature(s, ARM_FEATURE_V8)) { if (disas_neon_insn_2reg_scalar_ext(s, insn)) { @@ -11145,15 +11061,9 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) } break; } - if ((insn & 0xfe000a00) == 0xfc000800 + if ((insn & 0xff000a00) == 0xfe000800 && arm_dc_feature(s, ARM_FEATURE_V8)) { /* The Thumb2 and ARM encodings are identical. */ - if (disas_neon_insn_3same_ext(s, insn)) { - goto illegal_op; - } - } else if ((insn & 0xff000a00) == 0xfe000800 - && arm_dc_feature(s, ARM_FEATURE_V8)) { - /* The Thumb2 and ARM encodings are identical. */ if (disas_neon_insn_2reg_scalar_ext(s, insn)) { goto illegal_op; } From 7e1b5d615361bb0038cda0e08af41e350e42d081 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:35 +0100 Subject: [PATCH 0176/2595] target/arm: Convert VCMLA (scalar) to decodetree Convert VCMLA (scalar) in the 2reg-scalar-ext group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-9-peter.maydell@linaro.org --- target/arm/neon-shared.decode | 5 +++++ target/arm/translate-neon.inc.c | 40 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 26 +-------------------- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/target/arm/neon-shared.decode b/target/arm/neon-shared.decode index 90cd5c871e..c11d755ed1 100644 --- a/target/arm/neon-shared.decode +++ b/target/arm/neon-shared.decode @@ -49,3 +49,8 @@ VFML 1111 110 0 s:1 . 10 .... .... 1000 . 0 . 1 .... \ vm=%vm_sp vn=%vn_sp vd=%vd_dp q=0 VFML 1111 110 0 s:1 . 10 .... .... 1000 . 1 . 1 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp q=1 + +VCMLA_scalar 1111 1110 0 . rot:2 .... .... 1000 . q:1 index:1 0 vm:4 \ + vn=%vn_dp vd=%vd_dp size=0 +VCMLA_scalar 1111 1110 1 . rot:2 .... .... 1000 . q:1 . 0 .... \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp size=1 index=0 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 6c58abc54b..92eccbf823 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -167,3 +167,43 @@ static bool trans_VFML(DisasContext *s, arg_VFML *a) gen_helper_gvec_fmlal_a32); return true; } + +static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a) +{ + gen_helper_gvec_3_ptr *fn_gvec_ptr; + int opr_sz; + TCGv_ptr fpst; + + if (!dc_isar_feature(aa32_vcma, s)) { + return false; + } + if (a->size == 0 && !dc_isar_feature(aa32_fp16_arith, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if ((a->vd | a->vn) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fn_gvec_ptr = (a->size ? gen_helper_gvec_fcmlas_idx + : gen_helper_gvec_fcmlah_idx); + opr_sz = (1 + a->q) * 8; + fpst = get_fpstatus_ptr(1); + tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), + vfp_reg_offset(1, a->vn), + vfp_reg_offset(1, a->vm), + fpst, opr_sz, opr_sz, + (a->index << 2) | a->rot, fn_gvec_ptr); + tcg_temp_free_ptr(fpst); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 79cd9138fe..4cb8c6d55b 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -7049,31 +7049,7 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn) bool is_long = false, q = extract32(insn, 6, 1); bool ptr_is_env = false; - if ((insn & 0xff000f10) == 0xfe000800) { - /* VCMLA (indexed) -- 1111 1110 S.RR .... .... 1000 ...0 .... */ - int rot = extract32(insn, 20, 2); - int size = extract32(insn, 23, 1); - int index; - - if (!dc_isar_feature(aa32_vcma, s)) { - return 1; - } - if (size == 0) { - if (!dc_isar_feature(aa32_fp16_arith, s)) { - return 1; - } - /* For fp16, rm is just Vm, and index is M. */ - rm = extract32(insn, 0, 4); - index = extract32(insn, 5, 1); - } else { - /* For fp32, rm is the usual M:Vm, and index is 0. */ - VFP_DREG_M(rm, insn); - index = 0; - } - data = (index << 2) | rot; - fn_gvec_ptr = (size ? gen_helper_gvec_fcmlas_idx - : gen_helper_gvec_fcmlah_idx); - } else if ((insn & 0xffb00f00) == 0xfe200d00) { + if ((insn & 0xffb00f00) == 0xfe200d00) { /* V[US]DOT -- 1111 1110 0.10 .... .... 1101 .Q.U .... */ int u = extract32(insn, 4, 1); From 35f5d4d1747558c6af2d914bcd848dcc30c3b531 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:36 +0100 Subject: [PATCH 0177/2595] target/arm: Convert V[US]DOT (scalar) to decodetree Convert the V[US]DOT (scalar) insns in the 2reg-scalar-ext group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-10-peter.maydell@linaro.org --- target/arm/neon-shared.decode | 3 +++ target/arm/translate-neon.inc.c | 35 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 13 +----------- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/target/arm/neon-shared.decode b/target/arm/neon-shared.decode index c11d755ed1..63a46c63c0 100644 --- a/target/arm/neon-shared.decode +++ b/target/arm/neon-shared.decode @@ -54,3 +54,6 @@ VCMLA_scalar 1111 1110 0 . rot:2 .... .... 1000 . q:1 index:1 0 vm:4 \ vn=%vn_dp vd=%vd_dp size=0 VCMLA_scalar 1111 1110 1 . rot:2 .... .... 1000 . q:1 . 0 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp size=1 index=0 + +VDOT_scalar 1111 1110 0 . 10 .... .... 1101 . q:1 index:1 u:1 rm:4 \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 92eccbf823..7cc6ccb069 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -207,3 +207,38 @@ static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a) tcg_temp_free_ptr(fpst); return true; } + +static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a) +{ + gen_helper_gvec_3 *fn_gvec; + int opr_sz; + TCGv_ptr fpst; + + if (!dc_isar_feature(aa32_dp, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn) & 0x10)) { + return false; + } + + if ((a->vd | a->vn) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fn_gvec = a->u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b; + opr_sz = (1 + a->q) * 8; + fpst = get_fpstatus_ptr(1); + tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd), + vfp_reg_offset(1, a->vn), + vfp_reg_offset(1, a->rm), + opr_sz, opr_sz, a->index, fn_gvec); + tcg_temp_free_ptr(fpst); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 4cb8c6d55b..8574d0964f 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -7049,18 +7049,7 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn) bool is_long = false, q = extract32(insn, 6, 1); bool ptr_is_env = false; - if ((insn & 0xffb00f00) == 0xfe200d00) { - /* V[US]DOT -- 1111 1110 0.10 .... .... 1101 .Q.U .... */ - int u = extract32(insn, 4, 1); - - if (!dc_isar_feature(aa32_dp, s)) { - return 1; - } - fn_gvec = u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b; - /* rm is just Vm, and index is M. */ - data = extract32(insn, 5, 1); /* index */ - rm = extract32(insn, 0, 4); - } else if ((insn & 0xffa00f10) == 0xfe000810) { + if ((insn & 0xffa00f10) == 0xfe000810) { /* VFM[AS]L -- 1111 1110 0.0S .... .... 1000 .Q.1 .... */ int is_s = extract32(insn, 20, 1); int vm20 = extract32(insn, 0, 3); From d27e82f7d02f35e5919bd9cbbcb157f3537069a0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:37 +0100 Subject: [PATCH 0178/2595] target/arm: Convert VFM[AS]L (scalar) to decodetree Convert the VFM[AS]L (scalar) insns in the 2reg-scalar-ext group to decodetree. These are the last ones in the group so we can remove all the legacy decode for the group. Note that in disas_thumb2_insn() the parts of this encoding space where the decodetree decoder returns false will correctly be directed to illegal_op by the "(insn & (1 << 28))" check so they won't fall into disas_coproc_insn() by mistake. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-11-peter.maydell@linaro.org --- target/arm/neon-shared.decode | 7 +++ target/arm/translate-neon.inc.c | 32 ++++++++++ target/arm/translate.c | 107 +------------------------------- 3 files changed, 40 insertions(+), 106 deletions(-) diff --git a/target/arm/neon-shared.decode b/target/arm/neon-shared.decode index 63a46c63c0..f297ba8cdf 100644 --- a/target/arm/neon-shared.decode +++ b/target/arm/neon-shared.decode @@ -57,3 +57,10 @@ VCMLA_scalar 1111 1110 1 . rot:2 .... .... 1000 . q:1 . 0 .... \ VDOT_scalar 1111 1110 0 . 10 .... .... 1101 . q:1 index:1 u:1 rm:4 \ vm=%vm_dp vn=%vn_dp vd=%vd_dp + +%vfml_scalar_q0_rm 0:3 5:1 +%vfml_scalar_q1_index 5:1 3:1 +VFML_scalar 1111 1110 0 . 0 s:1 .... .... 1000 . 0 . 1 index:1 ... \ + rm=%vfml_scalar_q0_rm vn=%vn_sp vd=%vd_dp q=0 +VFML_scalar 1111 1110 0 . 0 s:1 .... .... 1000 . 1 . 1 . rm:3 \ + index=%vfml_scalar_q1_index vn=%vn_dp vd=%vd_dp q=1 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 7cc6ccb069..b06542b8b8 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -242,3 +242,35 @@ static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a) tcg_temp_free_ptr(fpst); return true; } + +static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) +{ + int opr_sz; + + if (!dc_isar_feature(aa32_fhm, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) { + return false; + } + + if (a->vd & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + opr_sz = (1 + a->q) * 8; + tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), + vfp_reg_offset(a->q, a->vn), + vfp_reg_offset(a->q, a->rm), + cpu_env, opr_sz, opr_sz, + (a->index << 2) | a->s, /* is_2 == 0 */ + gen_helper_gvec_fmlal_idx_a32); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 8574d0964f..e269642a48 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2610,8 +2610,6 @@ static int disas_dsp_insn(DisasContext *s, uint32_t insn) } #define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n)) -#define VFP_SREG(insn, bigbit, smallbit) \ - ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1)) #define VFP_DREG(reg, insn, bigbit, smallbit) do { \ if (dc_isar_feature(aa32_simd_r32, s)) { \ reg = (((insn) >> (bigbit)) & 0x0f) \ @@ -2622,11 +2620,8 @@ static int disas_dsp_insn(DisasContext *s, uint32_t insn) reg = ((insn) >> (bigbit)) & 0x0f; \ }} while (0) -#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22) #define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22) -#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7) #define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7) -#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5) #define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5) static void gen_neon_dup_low16(TCGv_i32 var) @@ -7032,94 +7027,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 0; } -/* Advanced SIMD two registers and a scalar extension. - * 31 24 23 22 20 16 12 11 10 9 8 3 0 - * +-----------------+----+---+----+----+----+---+----+---+----+---------+----+ - * | 1 1 1 1 1 1 1 0 | o1 | D | o2 | Vn | Vd | 1 | o3 | 0 | o4 | N Q M U | Vm | - * +-----------------+----+---+----+----+----+---+----+---+----+---------+----+ - * - */ - -static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn) -{ - gen_helper_gvec_3 *fn_gvec = NULL; - gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL; - int rd, rn, rm, opr_sz, data; - int off_rn, off_rm; - bool is_long = false, q = extract32(insn, 6, 1); - bool ptr_is_env = false; - - if ((insn & 0xffa00f10) == 0xfe000810) { - /* VFM[AS]L -- 1111 1110 0.0S .... .... 1000 .Q.1 .... */ - int is_s = extract32(insn, 20, 1); - int vm20 = extract32(insn, 0, 3); - int vm3 = extract32(insn, 3, 1); - int m = extract32(insn, 5, 1); - int index; - - if (!dc_isar_feature(aa32_fhm, s)) { - return 1; - } - if (q) { - rm = vm20; - index = m * 2 + vm3; - } else { - rm = vm20 * 2 + m; - index = vm3; - } - is_long = true; - data = (index << 2) | is_s; /* is_2 == 0 */ - fn_gvec_ptr = gen_helper_gvec_fmlal_idx_a32; - ptr_is_env = true; - } else { - return 1; - } - - VFP_DREG_D(rd, insn); - if (rd & q) { - return 1; - } - if (q || !is_long) { - VFP_DREG_N(rn, insn); - if (rn & q & !is_long) { - return 1; - } - off_rn = vfp_reg_offset(1, rn); - off_rm = vfp_reg_offset(1, rm); - } else { - rn = VFP_SREG_N(insn); - off_rn = vfp_reg_offset(0, rn); - off_rm = vfp_reg_offset(0, rm); - } - if (s->fp_excp_el) { - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_simd_access_trap(1, 0xe, false), s->fp_excp_el); - return 0; - } - if (!s->vfp_enabled) { - return 1; - } - - opr_sz = (1 + q) * 8; - if (fn_gvec_ptr) { - TCGv_ptr ptr; - if (ptr_is_env) { - ptr = cpu_env; - } else { - ptr = get_fpstatus_ptr(1); - } - tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, ptr, - opr_sz, opr_sz, data, fn_gvec_ptr); - if (!ptr_is_env) { - tcg_temp_free_ptr(ptr); - } - } else { - tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm, - opr_sz, opr_sz, data, fn_gvec); - } - return 0; -} - static int disas_coproc_insn(DisasContext *s, uint32_t insn) { int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2; @@ -10843,12 +10750,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } } } - } else if ((insn & 0x0f000a00) == 0x0e000800 - && arm_dc_feature(s, ARM_FEATURE_V8)) { - if (disas_neon_insn_2reg_scalar_ext(s, insn)) { - goto illegal_op; - } - return; } goto illegal_op; } @@ -11026,13 +10927,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) } break; } - if ((insn & 0xff000a00) == 0xfe000800 - && arm_dc_feature(s, ARM_FEATURE_V8)) { - /* The Thumb2 and ARM encodings are identical. */ - if (disas_neon_insn_2reg_scalar_ext(s, insn)) { - goto illegal_op; - } - } else if (((insn >> 24) & 3) == 3) { + if (((insn >> 24) & 3) == 3) { /* Translate into the equivalent ARM encoding. */ insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28); if (disas_neon_data_insn(s, insn)) { From a27b46304352a0eced45e560e96515dbe3cc174f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:38 +0100 Subject: [PATCH 0179/2595] target/arm: Convert Neon load/store multiple structures to decodetree Convert the Neon "load/store multiple structures" insns to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-12-peter.maydell@linaro.org --- target/arm/neon-ls.decode | 7 ++ target/arm/translate-neon.inc.c | 124 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 91 +---------------------- 3 files changed, 133 insertions(+), 89 deletions(-) diff --git a/target/arm/neon-ls.decode b/target/arm/neon-ls.decode index 2b16c9256d..dd03d5a37b 100644 --- a/target/arm/neon-ls.decode +++ b/target/arm/neon-ls.decode @@ -27,3 +27,10 @@ # 0b1111_1001_xxx0_xxxx_xxxx_xxxx_xxxx_xxxx # This file works on the A32 encoding only; calling code for T32 has to # transform the insn into the A32 version first. + +%vd_dp 22:1 12:4 + +# Neon load/store multiple structures + +VLDST_multiple 1111 0100 0 . l:1 0 rn:4 .... itype:4 size:2 align:2 rm:4 \ + vd=%vd_dp diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index b06542b8b8..966c0d9201 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -274,3 +274,127 @@ static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) gen_helper_gvec_fmlal_idx_a32); return true; } + +static struct { + int nregs; + int interleave; + int spacing; +} const neon_ls_element_type[11] = { + {1, 4, 1}, + {1, 4, 2}, + {4, 1, 1}, + {2, 2, 2}, + {1, 3, 1}, + {1, 3, 2}, + {3, 1, 1}, + {1, 1, 1}, + {1, 2, 1}, + {1, 2, 2}, + {2, 1, 1} +}; + +static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn, + int stride) +{ + if (rm != 15) { + TCGv_i32 base; + + base = load_reg(s, rn); + if (rm == 13) { + tcg_gen_addi_i32(base, base, stride); + } else { + TCGv_i32 index; + index = load_reg(s, rm); + tcg_gen_add_i32(base, base, index); + tcg_temp_free_i32(index); + } + store_reg(s, rn, base); + } +} + +static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) +{ + /* Neon load/store multiple structures */ + int nregs, interleave, spacing, reg, n; + MemOp endian = s->be_data; + int mmu_idx = get_mem_index(s); + int size = a->size; + TCGv_i64 tmp64; + TCGv_i32 addr, tmp; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist */ + if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + return false; + } + if (a->itype > 10) { + return false; + } + /* Catch UNDEF cases for bad values of align field */ + switch (a->itype & 0xc) { + case 4: + if (a->align >= 2) { + return false; + } + break; + case 8: + if (a->align == 3) { + return false; + } + break; + default: + break; + } + nregs = neon_ls_element_type[a->itype].nregs; + interleave = neon_ls_element_type[a->itype].interleave; + spacing = neon_ls_element_type[a->itype].spacing; + if (size == 3 && (interleave | spacing) != 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + /* For our purposes, bytes are always little-endian. */ + if (size == 0) { + endian = MO_LE; + } + /* + * Consecutive little-endian elements from a single register + * can be promoted to a larger little-endian operation. + */ + if (interleave == 1 && endian == MO_LE) { + size = 3; + } + tmp64 = tcg_temp_new_i64(); + addr = tcg_temp_new_i32(); + tmp = tcg_const_i32(1 << size); + load_reg_var(s, addr, a->rn); + for (reg = 0; reg < nregs; reg++) { + for (n = 0; n < 8 >> size; n++) { + int xs; + for (xs = 0; xs < interleave; xs++) { + int tt = a->vd + reg + spacing * xs; + + if (a->l) { + gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size); + neon_store_element64(tt, n, size, tmp64); + } else { + neon_load_element64(tmp64, tt, n, size); + gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size); + } + tcg_gen_add_i32(addr, addr, tmp); + } + } + } + tcg_temp_free_i32(addr); + tcg_temp_free_i32(tmp); + tcg_temp_free_i64(tmp64); + + gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index e269642a48..be56cbb061 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3214,45 +3214,19 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) } -static struct { - int nregs; - int interleave; - int spacing; -} const neon_ls_element_type[11] = { - {1, 4, 1}, - {1, 4, 2}, - {4, 1, 1}, - {2, 2, 2}, - {1, 3, 1}, - {1, 3, 2}, - {3, 1, 1}, - {1, 1, 1}, - {1, 2, 1}, - {1, 2, 2}, - {2, 1, 1} -}; - /* Translate a NEON load/store element instruction. Return nonzero if the instruction is invalid. */ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn) { int rd, rn, rm; - int op; int nregs; - int interleave; - int spacing; int stride; int size; int reg; int load; - int n; int vec_size; - int mmu_idx; - MemOp endian; TCGv_i32 addr; TCGv_i32 tmp; - TCGv_i32 tmp2; - TCGv_i64 tmp64; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { return 1; @@ -3274,70 +3248,9 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn) rn = (insn >> 16) & 0xf; rm = insn & 0xf; load = (insn & (1 << 21)) != 0; - endian = s->be_data; - mmu_idx = get_mem_index(s); if ((insn & (1 << 23)) == 0) { - /* Load store all elements. */ - op = (insn >> 8) & 0xf; - size = (insn >> 6) & 3; - if (op > 10) - return 1; - /* Catch UNDEF cases for bad values of align field */ - switch (op & 0xc) { - case 4: - if (((insn >> 5) & 1) == 1) { - return 1; - } - break; - case 8: - if (((insn >> 4) & 3) == 3) { - return 1; - } - break; - default: - break; - } - nregs = neon_ls_element_type[op].nregs; - interleave = neon_ls_element_type[op].interleave; - spacing = neon_ls_element_type[op].spacing; - if (size == 3 && (interleave | spacing) != 1) { - return 1; - } - /* For our purposes, bytes are always little-endian. */ - if (size == 0) { - endian = MO_LE; - } - /* Consecutive little-endian elements from a single register - * can be promoted to a larger little-endian operation. - */ - if (interleave == 1 && endian == MO_LE) { - size = 3; - } - tmp64 = tcg_temp_new_i64(); - addr = tcg_temp_new_i32(); - tmp2 = tcg_const_i32(1 << size); - load_reg_var(s, addr, rn); - for (reg = 0; reg < nregs; reg++) { - for (n = 0; n < 8 >> size; n++) { - int xs; - for (xs = 0; xs < interleave; xs++) { - int tt = rd + reg + spacing * xs; - - if (load) { - gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size); - neon_store_element64(tt, n, size, tmp64); - } else { - neon_load_element64(tmp64, tt, n, size); - gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size); - } - tcg_gen_add_i32(addr, addr, tmp2); - } - } - } - tcg_temp_free_i32(addr); - tcg_temp_free_i32(tmp2); - tcg_temp_free_i64(tmp64); - stride = nregs * interleave * 8; + /* Load store all elements -- handled already by decodetree */ + return 1; } else { size = (insn >> 10) & 3; if (size == 3) { From 3698747c48db871d876a398592c5a23d7580ed4a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:39 +0100 Subject: [PATCH 0180/2595] target/arm: Convert Neon 'load single structure to all lanes' to decodetree Convert the Neon "load single structure to all lanes" insns to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-13-peter.maydell@linaro.org --- target/arm/neon-ls.decode | 5 +++ target/arm/translate-neon.inc.c | 73 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 55 +------------------------ 3 files changed, 80 insertions(+), 53 deletions(-) diff --git a/target/arm/neon-ls.decode b/target/arm/neon-ls.decode index dd03d5a37b..f0ab6d2c98 100644 --- a/target/arm/neon-ls.decode +++ b/target/arm/neon-ls.decode @@ -34,3 +34,8 @@ VLDST_multiple 1111 0100 0 . l:1 0 rn:4 .... itype:4 size:2 align:2 rm:4 \ vd=%vd_dp + +# Neon load single element to all lanes + +VLD_all_lanes 1111 0100 1 . 1 0 rn:4 .... 11 n:2 size:2 t:1 a:1 rm:4 \ + vd=%vd_dp diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 966c0d9201..e60e9559ba 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -398,3 +398,76 @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8); return true; } + +static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) +{ + /* Neon load single structure to all lanes */ + int reg, stride, vec_size; + int vd = a->vd; + int size = a->size; + int nregs = a->n + 1; + TCGv_i32 addr, tmp; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist */ + if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + return false; + } + + if (size == 3) { + if (nregs != 4 || a->a == 0) { + return false; + } + /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */ + size = 2; + } + if (nregs == 1 && a->a == 1 && size == 0) { + return false; + } + if (nregs == 3 && a->a == 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + /* + * VLD1 to all lanes: T bit indicates how many Dregs to write. + * VLD2/3/4 to all lanes: T bit indicates register stride. + */ + stride = a->t ? 2 : 1; + vec_size = nregs == 1 ? stride * 8 : 8; + + tmp = tcg_temp_new_i32(); + addr = tcg_temp_new_i32(); + load_reg_var(s, addr, a->rn); + for (reg = 0; reg < nregs; reg++) { + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), + s->be_data | size); + if ((vd & 1) && vec_size == 16) { + /* + * We cannot write 16 bytes at once because the + * destination is unaligned. + */ + tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0), + 8, 8, tmp); + tcg_gen_gvec_mov(0, neon_reg_offset(vd + 1, 0), + neon_reg_offset(vd, 0), 8, 8); + } else { + tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0), + vec_size, vec_size, tmp); + } + tcg_gen_addi_i32(addr, addr, 1 << size); + vd += stride; + } + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(addr); + + gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs); + + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index be56cbb061..7099274c92 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3224,7 +3224,6 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn) int size; int reg; int load; - int vec_size; TCGv_i32 addr; TCGv_i32 tmp; @@ -3254,58 +3253,8 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn) } else { size = (insn >> 10) & 3; if (size == 3) { - /* Load single element to all lanes. */ - int a = (insn >> 4) & 1; - if (!load) { - return 1; - } - size = (insn >> 6) & 3; - nregs = ((insn >> 8) & 3) + 1; - - if (size == 3) { - if (nregs != 4 || a == 0) { - return 1; - } - /* For VLD4 size==3 a == 1 means 32 bits at 16 byte alignment */ - size = 2; - } - if (nregs == 1 && a == 1 && size == 0) { - return 1; - } - if (nregs == 3 && a == 1) { - return 1; - } - addr = tcg_temp_new_i32(); - load_reg_var(s, addr, rn); - - /* VLD1 to all lanes: bit 5 indicates how many Dregs to write. - * VLD2/3/4 to all lanes: bit 5 indicates register stride. - */ - stride = (insn & (1 << 5)) ? 2 : 1; - vec_size = nregs == 1 ? stride * 8 : 8; - - tmp = tcg_temp_new_i32(); - for (reg = 0; reg < nregs; reg++) { - gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), - s->be_data | size); - if ((rd & 1) && vec_size == 16) { - /* We cannot write 16 bytes at once because the - * destination is unaligned. - */ - tcg_gen_gvec_dup_i32(size, neon_reg_offset(rd, 0), - 8, 8, tmp); - tcg_gen_gvec_mov(0, neon_reg_offset(rd + 1, 0), - neon_reg_offset(rd, 0), 8, 8); - } else { - tcg_gen_gvec_dup_i32(size, neon_reg_offset(rd, 0), - vec_size, vec_size, tmp); - } - tcg_gen_addi_i32(addr, addr, 1 << size); - rd += stride; - } - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(addr); - stride = (1 << size) * nregs; + /* Load single element to all lanes -- handled by decodetree */ + return 1; } else { /* Single element. */ int idx = (insn >> 4) & 0xf; From 123ce4e3daba26b760b472687e1fb1ad82cf1993 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:40 +0100 Subject: [PATCH 0181/2595] target/arm: Convert Neon 'load/store single structure' to decodetree Convert the Neon "load/store single structure to one lane" insns to decodetree. As this is the last set of insns in the neon load/store group, we can remove the whole disas_neon_ls_insn() function. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-14-peter.maydell@linaro.org --- target/arm/neon-ls.decode | 11 +++ target/arm/translate-neon.inc.c | 89 +++++++++++++++++++ target/arm/translate.c | 147 -------------------------------- 3 files changed, 100 insertions(+), 147 deletions(-) diff --git a/target/arm/neon-ls.decode b/target/arm/neon-ls.decode index f0ab6d2c98..c7b03a72e8 100644 --- a/target/arm/neon-ls.decode +++ b/target/arm/neon-ls.decode @@ -39,3 +39,14 @@ VLDST_multiple 1111 0100 0 . l:1 0 rn:4 .... itype:4 size:2 align:2 rm:4 \ VLD_all_lanes 1111 0100 1 . 1 0 rn:4 .... 11 n:2 size:2 t:1 a:1 rm:4 \ vd=%vd_dp + +# Neon load/store single structure to one lane +%imm1_5_p1 5:1 !function=plus1 +%imm1_6_p1 6:1 !function=plus1 + +VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 00 n:2 reg_idx:3 align:1 rm:4 \ + vd=%vd_dp size=0 stride=1 +VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 01 n:2 reg_idx:2 align:2 rm:4 \ + vd=%vd_dp size=1 stride=%imm1_5_p1 +VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 10 n:2 reg_idx:1 align:3 rm:4 \ + vd=%vd_dp size=2 stride=%imm1_6_p1 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index e60e9559ba..c881d1cf60 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -26,6 +26,11 @@ * It might be possible to convert it to a standalone .c file eventually. */ +static inline int plus1(DisasContext *s, int x) +{ + return x + 1; +} + /* Include the generated Neon decoder */ #include "decode-neon-dp.inc.c" #include "decode-neon-ls.inc.c" @@ -471,3 +476,87 @@ static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) return true; } + +static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) +{ + /* Neon load/store single structure to one lane */ + int reg; + int nregs = a->n + 1; + int vd = a->vd; + TCGv_i32 addr, tmp; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist */ + if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + return false; + } + + /* Catch the UNDEF cases. This is unavoidably a bit messy. */ + switch (nregs) { + case 1: + if (((a->align & (1 << a->size)) != 0) || + (a->size == 2 && ((a->align & 3) == 1 || (a->align & 3) == 2))) { + return false; + } + break; + case 3: + if ((a->align & 1) != 0) { + return false; + } + /* fall through */ + case 2: + if (a->size == 2 && (a->align & 2) != 0) { + return false; + } + break; + case 4: + if ((a->size == 2) && ((a->align & 3) == 3)) { + return false; + } + break; + default: + abort(); + } + if ((vd + a->stride * (nregs - 1)) > 31) { + /* + * Attempts to write off the end of the register file are + * UNPREDICTABLE; we choose to UNDEF because otherwise we would + * access off the end of the array that holds the register data. + */ + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + tmp = tcg_temp_new_i32(); + addr = tcg_temp_new_i32(); + load_reg_var(s, addr, a->rn); + /* + * TODO: if we implemented alignment exceptions, we should check + * addr against the alignment encoded in a->align here. + */ + for (reg = 0; reg < nregs; reg++) { + if (a->l) { + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), + s->be_data | a->size); + neon_store_element(vd, a->reg_idx, a->size, tmp); + } else { /* Store */ + neon_load_element(tmp, vd, a->reg_idx, a->size); + gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), + s->be_data | a->size); + } + vd += a->stride; + tcg_gen_addi_i32(addr, addr, 1 << a->size); + } + tcg_temp_free_i32(addr); + tcg_temp_free_i32(tmp); + + gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs); + + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 7099274c92..613be39ef3 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3213,140 +3213,6 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) tcg_temp_free_i32(rd); } - -/* Translate a NEON load/store element instruction. Return nonzero if the - instruction is invalid. */ -static int disas_neon_ls_insn(DisasContext *s, uint32_t insn) -{ - int rd, rn, rm; - int nregs; - int stride; - int size; - int reg; - int load; - TCGv_i32 addr; - TCGv_i32 tmp; - - if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { - return 1; - } - - /* FIXME: this access check should not take precedence over UNDEF - * for invalid encodings; we will generate incorrect syndrome information - * for attempts to execute invalid vfp/neon encodings with FP disabled. - */ - if (s->fp_excp_el) { - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_simd_access_trap(1, 0xe, false), s->fp_excp_el); - return 0; - } - - if (!s->vfp_enabled) - return 1; - VFP_DREG_D(rd, insn); - rn = (insn >> 16) & 0xf; - rm = insn & 0xf; - load = (insn & (1 << 21)) != 0; - if ((insn & (1 << 23)) == 0) { - /* Load store all elements -- handled already by decodetree */ - return 1; - } else { - size = (insn >> 10) & 3; - if (size == 3) { - /* Load single element to all lanes -- handled by decodetree */ - return 1; - } else { - /* Single element. */ - int idx = (insn >> 4) & 0xf; - int reg_idx; - switch (size) { - case 0: - reg_idx = (insn >> 5) & 7; - stride = 1; - break; - case 1: - reg_idx = (insn >> 6) & 3; - stride = (insn & (1 << 5)) ? 2 : 1; - break; - case 2: - reg_idx = (insn >> 7) & 1; - stride = (insn & (1 << 6)) ? 2 : 1; - break; - default: - abort(); - } - nregs = ((insn >> 8) & 3) + 1; - /* Catch the UNDEF cases. This is unavoidably a bit messy. */ - switch (nregs) { - case 1: - if (((idx & (1 << size)) != 0) || - (size == 2 && ((idx & 3) == 1 || (idx & 3) == 2))) { - return 1; - } - break; - case 3: - if ((idx & 1) != 0) { - return 1; - } - /* fall through */ - case 2: - if (size == 2 && (idx & 2) != 0) { - return 1; - } - break; - case 4: - if ((size == 2) && ((idx & 3) == 3)) { - return 1; - } - break; - default: - abort(); - } - if ((rd + stride * (nregs - 1)) > 31) { - /* Attempts to write off the end of the register file - * are UNPREDICTABLE; we choose to UNDEF because otherwise - * the neon_load_reg() would write off the end of the array. - */ - return 1; - } - tmp = tcg_temp_new_i32(); - addr = tcg_temp_new_i32(); - load_reg_var(s, addr, rn); - for (reg = 0; reg < nregs; reg++) { - if (load) { - gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), - s->be_data | size); - neon_store_element(rd, reg_idx, size, tmp); - } else { /* Store */ - neon_load_element(tmp, rd, reg_idx, size); - gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), - s->be_data | size); - } - rd += stride; - tcg_gen_addi_i32(addr, addr, 1 << size); - } - tcg_temp_free_i32(addr); - tcg_temp_free_i32(tmp); - stride = nregs * (1 << size); - } - } - if (rm != 15) { - TCGv_i32 base; - - base = load_reg(s, rn); - if (rm == 13) { - tcg_gen_addi_i32(base, base, stride); - } else { - TCGv_i32 index; - index = load_reg(s, rm); - tcg_gen_add_i32(base, base, index); - tcg_temp_free_i32(index); - } - store_reg(s, rn, base); - } - return 0; -} - static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src) { switch (size) { @@ -10596,13 +10462,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } return; } - if ((insn & 0x0f100000) == 0x04000000) { - /* NEON load/store. */ - if (disas_neon_ls_insn(s, insn)) { - goto illegal_op; - } - return; - } if ((insn & 0x0e000f00) == 0x0c000100) { if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) { /* iWMMXt register transfer. */ @@ -10807,12 +10666,6 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) } break; case 12: - if ((insn & 0x01100000) == 0x01000000) { - if (disas_neon_ls_insn(s, insn)) { - goto illegal_op; - } - break; - } goto illegal_op; default: illegal_op: From a4e143ac5b9185f670d2f17ee9cc1a430047cb65 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:41 +0100 Subject: [PATCH 0182/2595] target/arm: Convert Neon 3-reg-same VADD/VSUB to decodetree Convert the Neon 3-reg-same VADD and VSUB insns to decodetree. Note that we don't need the neon_3r_sizes[op] check here because all size values are OK for VADD and VSUB; we'll add this when we convert the first insn that has size restrictions. For this we need one of the GVecGen*Fn typedefs currently in translate-a64.h; move them all to translate.h as a block so they are visible to the 32-bit decoder. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-15-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 17 +++++++++++++++ target/arm/translate-a64.h | 9 -------- target/arm/translate-neon.inc.c | 38 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 14 ++++-------- target/arm/translate.h | 9 ++++++++ 5 files changed, 68 insertions(+), 19 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index c89a1a5859..a61b1e8847 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -18,6 +18,10 @@ # # This file is processed by scripts/decodetree.py # +# VFP/Neon register fields; same as vfp.decode +%vm_dp 5:1 0:4 +%vn_dp 7:1 16:4 +%vd_dp 22:1 12:4 # Encodings for Neon data processing instructions where the T32 encoding # is a simple transformation of the A32 encoding. @@ -27,3 +31,16 @@ # 0b111p_1111_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq # This file works on the A32 encoding only; calling code for T32 has to # transform the insn into the A32 version first. + +###################################################################### +# 3-reg-same grouping: +# 1111 001 U 0 D sz:2 Vn:4 Vd:4 opc:4 N Q M op Vm:4 +###################################################################### + +&3same vm vn vd q size + +@3same .... ... . . . size:2 .... .... .... . q:1 . . .... \ + &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp + +VADD_3s 1111 001 0 0 . .. .... .... 1000 . . . 0 .... @3same +VSUB_3s 1111 001 1 0 . .. .... .... 1000 . . . 0 .... @3same diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index 4c2c91ae1b..f02fbb63a4 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -115,13 +115,4 @@ static inline int vec_full_reg_size(DisasContext *s) bool disas_sve(DisasContext *, uint32_t); -/* Note that the gvec expanders operate on offsets + sizes. */ -typedef void GVecGen2Fn(unsigned, uint32_t, uint32_t, uint32_t, uint32_t); -typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t, - uint32_t, uint32_t); -typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, - uint32_t, uint32_t, uint32_t); -typedef void GVecGen4Fn(unsigned, uint32_t, uint32_t, uint32_t, - uint32_t, uint32_t, uint32_t); - #endif /* TARGET_ARM_TRANSLATE_A64_H */ diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index c881d1cf60..bd9e697b3e 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -560,3 +560,41 @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) return true; } + +static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) +{ + int vec_size = a->q ? 16 : 8; + int rd_ofs = neon_reg_offset(a->vd, 0); + int rn_ofs = neon_reg_offset(a->vn, 0); + int rm_ofs = neon_reg_offset(a->vm, 0); + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if ((a->vn | a->vm | a->vd) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); + return true; +} + +#define DO_3SAME(INSN, FUNC) \ + static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ + { \ + return do_3same(s, a, FUNC); \ + } + +DO_3SAME(VADD, tcg_gen_gvec_add) +DO_3SAME(VSUB, tcg_gen_gvec_sub) diff --git a/target/arm/translate.c b/target/arm/translate.c index 613be39ef3..061bc7c31c 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4885,16 +4885,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } return 0; - case NEON_3R_VADD_VSUB: - if (u) { - tcg_gen_gvec_sub(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } else { - tcg_gen_gvec_add(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } - return 0; - case NEON_3R_VQADD: tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), rn_ofs, rm_ofs, vec_size, vec_size, @@ -4970,6 +4960,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_gen_gvec_3(rd_ofs, rm_ofs, rn_ofs, vec_size, vec_size, u ? &ushl_op[size] : &sshl_op[size]); return 0; + + case NEON_3R_VADD_VSUB: + /* Already handled by decodetree */ + return 1; } if (size == 3) { diff --git a/target/arm/translate.h b/target/arm/translate.h index 98b319f3f6..95b43e7ab6 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -305,4 +305,13 @@ void gen_sshl_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b); #define dc_isar_feature(name, ctx) \ ({ DisasContext *ctx_ = (ctx); isar_feature_##name(ctx_->isar); }) +/* Note that the gvec expanders operate on offsets + sizes. */ +typedef void GVecGen2Fn(unsigned, uint32_t, uint32_t, uint32_t, uint32_t); +typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t, + uint32_t, uint32_t); +typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t); +typedef void GVecGen4Fn(unsigned, uint32_t, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t); + #endif /* TARGET_ARM_TRANSLATE_H */ From 35a548edb6f5043386183b9f6b4139d99d1f130a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:42 +0100 Subject: [PATCH 0183/2595] target/arm: Convert Neon 3-reg-same logic ops to decodetree Convert the Neon logic ops in the 3-reg-same grouping to decodetree. Note that for the logic ops the 'size' field forms part of their decode and the actual operations are always bitwise. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-16-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 12 +++++++++++ target/arm/translate-neon.inc.c | 19 +++++++++++++++++ target/arm/translate.c | 38 +-------------------------------- 3 files changed, 32 insertions(+), 37 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index a61b1e8847..f62dbaa72d 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -42,5 +42,17 @@ @3same .... ... . . . size:2 .... .... .... . q:1 . . .... \ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp +@3same_logic .... ... . . . .. .... .... .... . q:1 .. .... \ + &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp size=0 + +VAND_3s 1111 001 0 0 . 00 .... .... 0001 ... 1 .... @3same_logic +VBIC_3s 1111 001 0 0 . 01 .... .... 0001 ... 1 .... @3same_logic +VORR_3s 1111 001 0 0 . 10 .... .... 0001 ... 1 .... @3same_logic +VORN_3s 1111 001 0 0 . 11 .... .... 0001 ... 1 .... @3same_logic +VEOR_3s 1111 001 1 0 . 00 .... .... 0001 ... 1 .... @3same_logic +VBSL_3s 1111 001 1 0 . 01 .... .... 0001 ... 1 .... @3same_logic +VBIT_3s 1111 001 1 0 . 10 .... .... 0001 ... 1 .... @3same_logic +VBIF_3s 1111 001 1 0 . 11 .... .... 0001 ... 1 .... @3same_logic + VADD_3s 1111 001 0 0 . .. .... .... 1000 . . . 0 .... @3same VSUB_3s 1111 001 1 0 . .. .... .... 1000 . . . 0 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index bd9e697b3e..507f0abe80 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -598,3 +598,22 @@ static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) DO_3SAME(VADD, tcg_gen_gvec_add) DO_3SAME(VSUB, tcg_gen_gvec_sub) +DO_3SAME(VAND, tcg_gen_gvec_and) +DO_3SAME(VBIC, tcg_gen_gvec_andc) +DO_3SAME(VORR, tcg_gen_gvec_or) +DO_3SAME(VORN, tcg_gen_gvec_orc) +DO_3SAME(VEOR, tcg_gen_gvec_xor) + +/* These insns are all gvec_bitsel but with the inputs in various orders. */ +#define DO_3SAME_BITSEL(INSN, O1, O2, O3) \ + static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ + uint32_t rn_ofs, uint32_t rm_ofs, \ + uint32_t oprsz, uint32_t maxsz) \ + { \ + tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz); \ + } \ + DO_3SAME(INSN, gen_##INSN##_3s) + +DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs) +DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs) +DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs) diff --git a/target/arm/translate.c b/target/arm/translate.c index 061bc7c31c..9affa92cbe 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4848,43 +4848,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } return 1; - case NEON_3R_LOGIC: /* Logic ops. */ - switch ((u << 2) | size) { - case 0: /* VAND */ - tcg_gen_gvec_and(0, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - break; - case 1: /* VBIC */ - tcg_gen_gvec_andc(0, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - break; - case 2: /* VORR */ - tcg_gen_gvec_or(0, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - break; - case 3: /* VORN */ - tcg_gen_gvec_orc(0, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - break; - case 4: /* VEOR */ - tcg_gen_gvec_xor(0, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - break; - case 5: /* VBSL */ - tcg_gen_gvec_bitsel(MO_8, rd_ofs, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - break; - case 6: /* VBIT */ - tcg_gen_gvec_bitsel(MO_8, rd_ofs, rm_ofs, rn_ofs, rd_ofs, - vec_size, vec_size); - break; - case 7: /* VBIF */ - tcg_gen_gvec_bitsel(MO_8, rd_ofs, rm_ofs, rd_ofs, rn_ofs, - vec_size, vec_size); - break; - } - return 0; - case NEON_3R_VQADD: tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), rn_ofs, rm_ofs, vec_size, vec_size, @@ -4962,6 +4925,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 0; case NEON_3R_VADD_VSUB: + case NEON_3R_LOGIC: /* Already handled by decodetree */ return 1; } From 36b59310c38d45213bf860affa90618aa5eeca93 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:43 +0100 Subject: [PATCH 0184/2595] target/arm: Convert Neon 3-reg-same VMAX/VMIN to decodetree Convert the Neon 3-reg-same VMAX and VMIN insns to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-17-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 5 +++++ target/arm/translate-neon.inc.c | 14 ++++++++++++++ target/arm/translate.c | 21 ++------------------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index f62dbaa72d..b721d39c7b 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -54,5 +54,10 @@ VBSL_3s 1111 001 1 0 . 01 .... .... 0001 ... 1 .... @3same_logic VBIT_3s 1111 001 1 0 . 10 .... .... 0001 ... 1 .... @3same_logic VBIF_3s 1111 001 1 0 . 11 .... .... 0001 ... 1 .... @3same_logic +VMAX_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 0 .... @3same +VMAX_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 0 .... @3same +VMIN_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 1 .... @3same +VMIN_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 1 .... @3same + VADD_3s 1111 001 0 0 . .. .... .... 1000 . . . 0 .... @3same VSUB_3s 1111 001 1 0 . .. .... .... 1000 . . . 0 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 507f0abe80..ab1740201c 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -617,3 +617,17 @@ DO_3SAME(VEOR, tcg_gen_gvec_xor) DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs) DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs) DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs) + +#define DO_3SAME_NO_SZ_3(INSN, FUNC) \ + static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ + { \ + if (a->size == 3) { \ + return false; \ + } \ + return do_3same(s, a, FUNC); \ + } + +DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax) +DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) +DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) +DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) diff --git a/target/arm/translate.c b/target/arm/translate.c index 9affa92cbe..2f054cfa78 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4899,25 +4899,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); return 0; - case NEON_3R_VMAX: - if (u) { - tcg_gen_gvec_umax(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } else { - tcg_gen_gvec_smax(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } - return 0; - case NEON_3R_VMIN: - if (u) { - tcg_gen_gvec_umin(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } else { - tcg_gen_gvec_smin(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } - return 0; - case NEON_3R_VSHL: /* Note the operation is vshl vd,vm,vn */ tcg_gen_gvec_3(rd_ofs, rm_ofs, rn_ofs, vec_size, vec_size, @@ -4926,6 +4907,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VADD_VSUB: case NEON_3R_LOGIC: + case NEON_3R_VMAX: + case NEON_3R_VMIN: /* Already handled by decodetree */ return 1; } From 02bd0cdb64b3e79419ba3a8746cb86430883b3ae Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:44 +0100 Subject: [PATCH 0185/2595] target/arm: Convert Neon 3-reg-same comparisons to decodetree Convert the Neon comparison ops in the 3-reg-same grouping to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-18-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 8 ++++++++ target/arm/translate-neon.inc.c | 22 ++++++++++++++++++++++ target/arm/translate.c | 23 +++-------------------- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index b721d39c7b..b89ea6819a 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -54,6 +54,11 @@ VBSL_3s 1111 001 1 0 . 01 .... .... 0001 ... 1 .... @3same_logic VBIT_3s 1111 001 1 0 . 10 .... .... 0001 ... 1 .... @3same_logic VBIF_3s 1111 001 1 0 . 11 .... .... 0001 ... 1 .... @3same_logic +VCGT_S_3s 1111 001 0 0 . .. .... .... 0011 . . . 0 .... @3same +VCGT_U_3s 1111 001 1 0 . .. .... .... 0011 . . . 0 .... @3same +VCGE_S_3s 1111 001 0 0 . .. .... .... 0011 . . . 1 .... @3same +VCGE_U_3s 1111 001 1 0 . .. .... .... 0011 . . . 1 .... @3same + VMAX_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 0 .... @3same VMAX_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 0 .... @3same VMIN_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 1 .... @3same @@ -61,3 +66,6 @@ VMIN_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 1 .... @3same VADD_3s 1111 001 0 0 . .. .... .... 1000 . . . 0 .... @3same VSUB_3s 1111 001 1 0 . .. .... .... 1000 . . . 0 .... @3same + +VTST_3s 1111 001 0 0 . .. .... .... 1000 . . . 1 .... @3same +VCEQ_3s 1111 001 1 0 . .. .... .... 1000 . . . 1 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index ab1740201c..952e4456f5 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -631,3 +631,25 @@ DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax) DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) + +#define DO_3SAME_CMP(INSN, COND) \ + static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ + uint32_t rn_ofs, uint32_t rm_ofs, \ + uint32_t oprsz, uint32_t maxsz) \ + { \ + tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \ + } \ + DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s) + +DO_3SAME_CMP(VCGT_S, TCG_COND_GT) +DO_3SAME_CMP(VCGT_U, TCG_COND_GTU) +DO_3SAME_CMP(VCGE_S, TCG_COND_GE) +DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) +DO_3SAME_CMP(VCEQ, TCG_COND_EQ) + +static void gen_VTST_3s(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) +{ + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &cmtst_op[vece]); +} +DO_3SAME_NO_SZ_3(VTST, gen_VTST_3s) diff --git a/target/arm/translate.c b/target/arm/translate.c index 2f054cfa78..0e6ecc0969 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4879,26 +4879,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) u ? &mls_op[size] : &mla_op[size]); return 0; - case NEON_3R_VTST_VCEQ: - if (u) { /* VCEQ */ - tcg_gen_gvec_cmp(TCG_COND_EQ, size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } else { /* VTST */ - tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size, &cmtst_op[size]); - } - return 0; - - case NEON_3R_VCGT: - tcg_gen_gvec_cmp(u ? TCG_COND_GTU : TCG_COND_GT, size, - rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); - return 0; - - case NEON_3R_VCGE: - tcg_gen_gvec_cmp(u ? TCG_COND_GEU : TCG_COND_GE, size, - rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); - return 0; - case NEON_3R_VSHL: /* Note the operation is vshl vd,vm,vn */ tcg_gen_gvec_3(rd_ofs, rm_ofs, rn_ofs, vec_size, vec_size, @@ -4909,6 +4889,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_LOGIC: case NEON_3R_VMAX: case NEON_3R_VMIN: + case NEON_3R_VTST_VCEQ: + case NEON_3R_VCGT: + case NEON_3R_VCGE: /* Already handled by decodetree */ return 1; } From 7a9497f1cf73667a4744d09673b808c20e067915 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:45 +0100 Subject: [PATCH 0186/2595] target/arm: Convert Neon 3-reg-same VQADD/VQSUB to decodetree Convert the Neon VQADD/VQSUB insns in the 3-reg-same grouping to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-19-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 6 ++++++ target/arm/translate-neon.inc.c | 15 +++++++++++++++ target/arm/translate.c | 14 ++------------ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index b89ea6819a..ab59b349aa 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -42,6 +42,9 @@ @3same .... ... . . . size:2 .... .... .... . q:1 . . .... \ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp +VQADD_S_3s 1111 001 0 0 . .. .... .... 0000 . . . 1 .... @3same +VQADD_U_3s 1111 001 1 0 . .. .... .... 0000 . . . 1 .... @3same + @3same_logic .... ... . . . .. .... .... .... . q:1 .. .... \ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp size=0 @@ -54,6 +57,9 @@ VBSL_3s 1111 001 1 0 . 01 .... .... 0001 ... 1 .... @3same_logic VBIT_3s 1111 001 1 0 . 10 .... .... 0001 ... 1 .... @3same_logic VBIF_3s 1111 001 1 0 . 11 .... .... 0001 ... 1 .... @3same_logic +VQSUB_S_3s 1111 001 0 0 . .. .... .... 0010 . . . 1 .... @3same +VQSUB_U_3s 1111 001 1 0 . .. .... .... 0010 . . . 1 .... @3same + VCGT_S_3s 1111 001 0 0 . .. .... .... 0011 . . . 0 .... @3same VCGT_U_3s 1111 001 1 0 . .. .... .... 0011 . . . 0 .... @3same VCGE_S_3s 1111 001 0 0 . .. .... .... 0011 . . . 1 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 952e4456f5..854ab70cd7 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -653,3 +653,18 @@ static void gen_VTST_3s(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &cmtst_op[vece]); } DO_3SAME_NO_SZ_3(VTST, gen_VTST_3s) + +#define DO_3SAME_GVEC4(INSN, OPARRAY) \ + static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ + uint32_t rn_ofs, uint32_t rm_ofs, \ + uint32_t oprsz, uint32_t maxsz) \ + { \ + tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), \ + rn_ofs, rm_ofs, oprsz, maxsz, &OPARRAY[vece]); \ + } \ + DO_3SAME(INSN, gen_##INSN##_3s) + +DO_3SAME_GVEC4(VQADD_S, sqadd_op) +DO_3SAME_GVEC4(VQADD_U, uqadd_op) +DO_3SAME_GVEC4(VQSUB_S, sqsub_op) +DO_3SAME_GVEC4(VQSUB_U, uqsub_op) diff --git a/target/arm/translate.c b/target/arm/translate.c index 0e6ecc0969..13ce1a5fc1 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4848,18 +4848,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } return 1; - case NEON_3R_VQADD: - tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), - rn_ofs, rm_ofs, vec_size, vec_size, - (u ? uqadd_op : sqadd_op) + size); - return 0; - - case NEON_3R_VQSUB: - tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), - rn_ofs, rm_ofs, vec_size, vec_size, - (u ? uqsub_op : sqsub_op) + size); - return 0; - case NEON_3R_VMUL: /* VMUL */ if (u) { /* Polynomial case allows only P8. */ @@ -4892,6 +4880,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VTST_VCEQ: case NEON_3R_VCGT: case NEON_3R_VCGE: + case NEON_3R_VQADD: + case NEON_3R_VQSUB: /* Already handled by decodetree */ return 1; } From 0de34fd48ad4e44bf5caa2330657ebefa93cea7d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:46 +0100 Subject: [PATCH 0187/2595] target/arm: Convert Neon 3-reg-same VMUL, VMLA, VMLS, VSHL to decodetree Convert the Neon VMUL, VMLA, VMLS and VSHL insns in the 3-reg-same grouping to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-20-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 9 +++++++ target/arm/translate-neon.inc.c | 44 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 28 +++------------------ 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index ab59b349aa..ec3a92fe75 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -65,6 +65,9 @@ VCGT_U_3s 1111 001 1 0 . .. .... .... 0011 . . . 0 .... @3same VCGE_S_3s 1111 001 0 0 . .. .... .... 0011 . . . 1 .... @3same VCGE_U_3s 1111 001 1 0 . .. .... .... 0011 . . . 1 .... @3same +VSHL_S_3s 1111 001 0 0 . .. .... .... 0100 . . . 0 .... @3same +VSHL_U_3s 1111 001 1 0 . .. .... .... 0100 . . . 0 .... @3same + VMAX_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 0 .... @3same VMAX_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 0 .... @3same VMIN_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 1 .... @3same @@ -75,3 +78,9 @@ VSUB_3s 1111 001 1 0 . .. .... .... 1000 . . . 0 .... @3same VTST_3s 1111 001 0 0 . .. .... .... 1000 . . . 1 .... @3same VCEQ_3s 1111 001 1 0 . .. .... .... 1000 . . . 1 .... @3same + +VMLA_3s 1111 001 0 0 . .. .... .... 1001 . . . 0 .... @3same +VMLS_3s 1111 001 1 0 . .. .... .... 1001 . . . 0 .... @3same + +VMUL_3s 1111 001 0 0 . .. .... .... 1001 . . . 1 .... @3same +VMUL_p_3s 1111 001 1 0 . .. .... .... 1001 . . . 1 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 854ab70cd7..50b77b6d71 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -631,6 +631,7 @@ DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax) DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) +DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) #define DO_3SAME_CMP(INSN, COND) \ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ @@ -668,3 +669,46 @@ DO_3SAME_GVEC4(VQADD_S, sqadd_op) DO_3SAME_GVEC4(VQADD_U, uqadd_op) DO_3SAME_GVEC4(VQSUB_S, sqsub_op) DO_3SAME_GVEC4(VQSUB_U, uqsub_op) + +static void gen_VMUL_p_3s(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) +{ + tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, + 0, gen_helper_gvec_pmul_b); +} + +static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) +{ + if (a->size != 0) { + return false; + } + return do_3same(s, a, gen_VMUL_p_3s); +} + +#define DO_3SAME_GVEC3_NO_SZ_3(INSN, OPARRAY) \ + static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ + uint32_t rn_ofs, uint32_t rm_ofs, \ + uint32_t oprsz, uint32_t maxsz) \ + { \ + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, \ + oprsz, maxsz, &OPARRAY[vece]); \ + } \ + DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s) + + +DO_3SAME_GVEC3_NO_SZ_3(VMLA, mla_op) +DO_3SAME_GVEC3_NO_SZ_3(VMLS, mls_op) + +#define DO_3SAME_GVEC3_SHIFT(INSN, OPARRAY) \ + static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ + uint32_t rn_ofs, uint32_t rm_ofs, \ + uint32_t oprsz, uint32_t maxsz) \ + { \ + /* Note the operation is vshl vd,vm,vn */ \ + tcg_gen_gvec_3(rd_ofs, rm_ofs, rn_ofs, \ + oprsz, maxsz, &OPARRAY[vece]); \ + } \ + DO_3SAME(INSN, gen_##INSN##_3s) + +DO_3SAME_GVEC3_SHIFT(VSHL_S, sshl_op) +DO_3SAME_GVEC3_SHIFT(VSHL_U, ushl_op) diff --git a/target/arm/translate.c b/target/arm/translate.c index 13ce1a5fc1..025747c0bd 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4848,31 +4848,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } return 1; - case NEON_3R_VMUL: /* VMUL */ - if (u) { - /* Polynomial case allows only P8. */ - if (size != 0) { - return 1; - } - tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size, - 0, gen_helper_gvec_pmul_b); - } else { - tcg_gen_gvec_mul(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } - return 0; - - case NEON_3R_VML: /* VMLA, VMLS */ - tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size, - u ? &mls_op[size] : &mla_op[size]); - return 0; - - case NEON_3R_VSHL: - /* Note the operation is vshl vd,vm,vn */ - tcg_gen_gvec_3(rd_ofs, rm_ofs, rn_ofs, vec_size, vec_size, - u ? &ushl_op[size] : &sshl_op[size]); - return 0; - case NEON_3R_VADD_VSUB: case NEON_3R_LOGIC: case NEON_3R_VMAX: @@ -4882,6 +4857,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VCGE: case NEON_3R_VQADD: case NEON_3R_VQSUB: + case NEON_3R_VMUL: + case NEON_3R_VML: + case NEON_3R_VSHL: /* Already handled by decodetree */ return 1; } From 9aefc6cf9b73f66062d2f914a0136756e7a28211 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 30 Apr 2020 19:09:49 +0100 Subject: [PATCH 0188/2595] target/arm: Move gen_ function typedefs to translate.h We're going to want at least some of the NeonGen* typedefs for the refactored 32-bit Neon decoder, so move them all to translate.h since it makes more sense to keep them in one group. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200430181003.21682-23-peter.maydell@linaro.org --- target/arm/translate-a64.c | 17 ----------------- target/arm/translate.h | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index efb1c4adc4..a896f9c4b8 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -70,23 +70,6 @@ typedef struct AArch64DecodeTable { AArch64DecodeFn *disas_fn; } AArch64DecodeTable; -/* Function prototype for gen_ functions for calling Neon helpers */ -typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32); -typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32); -typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32); -typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64); -typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64); -typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); -typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64); -typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32); -typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); -typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); -typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64); -typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr); -typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32); -typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr); -typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, MemOp); - /* initialize TCG globals. */ void a64_translate_init(void) { diff --git a/target/arm/translate.h b/target/arm/translate.h index 95b43e7ab6..cb7925ea46 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -314,4 +314,21 @@ typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, typedef void GVecGen4Fn(unsigned, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); +/* Function prototype for gen_ functions for calling Neon helpers */ +typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32); +typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32); +typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32); +typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64); +typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64); +typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); +typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64); +typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32); +typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); +typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); +typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64); +typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr); +typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32); +typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr); +typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, MemOp); + #endif /* TARGET_ARM_TRANSLATE_H */ From 4b4d96c776f552e4a7ffe2b686ef1dfc9ad3f98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Mar 2020 15:28:27 +0100 Subject: [PATCH 0189/2595] MAINTAINERS: Mark the LatticeMico32 target as orphan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Michael Walle expressed his desire to orphan the lm32 target [*]: I guess it is time to pull the plug. Mainly, because I have no time for this anymore. I've always worked on this on my spare time and life changed. And secondly, I guess RISC-V is taking over ;) It has a far better ecosystem. Also, to my knowledge the only (public) user of LM32 is milkymist and this project is dead for years now.. So time to say goodbye. It was fun and I've learned a lot - technically and also how a huge open source project works. Thank you everyone for that :) Basically everything still works and there are even TCG test cases which covers all instructions the processor has. Many thanks to Michael for his substantial contributions to QEMU, and for maintaining the LM32 target for various years! [*] https://www.mail-archive.com/qemu-devel@nongnu.org/msg605024.html Acked-by: Michael Walle Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200316142827.20867-1-philmd@redhat.com> Signed-off-by: Laurent Vivier --- MAINTAINERS | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 8aa8efaf1d..d6886be131 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -184,8 +184,8 @@ F: hw/net/*i82596* F: include/hw/net/lasi_82596.h LM32 TCG CPUs -M: Michael Walle -S: Maintained +R: Michael Walle +S: Orphan F: target/lm32/ F: disas/lm32.c F: hw/lm32/ @@ -977,13 +977,13 @@ F: pc-bios/hppa-firmware.img LM32 Machines ------------- EVR32 and uclinux BSP -M: Michael Walle -S: Maintained +R: Michael Walle +S: Orphan F: hw/lm32/lm32_boards.c milkymist -M: Michael Walle -S: Maintained +R: Michael Walle +S: Orphan F: hw/lm32/milkymist.c M68K Machines From f4eaf69e45c74b33d092ab53903a8458d197e240 Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Tue, 10 Mar 2020 15:05:09 -0300 Subject: [PATCH 0190/2595] hw/mem/pc-dimm: Print slot number on error at pc_dimm_pre_plug() The error report in pc_dimm_pre_plug() now has the slot number printed. Signed-off-by: Wainer dos Santos Moschetta Message-Id: <20200310180510.19489-2-wainersm@redhat.com> Signed-off-by: Laurent Vivier --- hw/mem/pc-dimm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 8f50b8afea..36edfcf467 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -44,8 +44,8 @@ void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine, &error_abort); if ((slot < 0 || slot >= machine->ram_slots) && slot != PC_DIMM_UNASSIGNED_SLOT) { - error_setg(&local_err, "invalid slot number, valid range is [0-%" - PRIu64 "]", machine->ram_slots - 1); + error_setg(&local_err, "invalid slot number %d, valid range is [0-%" + PRIu64 "]", slot, machine->ram_slots - 1); goto out; } From 12d814e901a21fbecc7d34765c02813f187aecef Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Tue, 10 Mar 2020 15:05:10 -0300 Subject: [PATCH 0191/2595] hw/mem/pc-dimm: Fix line over 80 characters warning Signed-off-by: Wainer dos Santos Moschetta Message-Id: <20200310180510.19489-3-wainersm@redhat.com> Signed-off-by: Laurent Vivier --- hw/mem/pc-dimm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 36edfcf467..6d62588fea 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -218,7 +218,8 @@ static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm, Error **errp) static uint64_t pc_dimm_md_get_addr(const MemoryDeviceState *md) { - return object_property_get_uint(OBJECT(md), PC_DIMM_ADDR_PROP, &error_abort); + return object_property_get_uint(OBJECT(md), PC_DIMM_ADDR_PROP, + &error_abort); } static void pc_dimm_md_set_addr(MemoryDeviceState *md, uint64_t addr, From a1ecb4381829d7eb302bc2d9cb69842c2585601d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 23 Apr 2020 21:20:11 +0100 Subject: [PATCH 0192/2595] elf_ops: Don't try to g_mapped_file_unref(NULL) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling g_mapped_file_unref() on a NULL pointer is not valid, and glib will assert if you try it. $ qemu-system-arm -M virt -display none -device loader,file=/tmp/bad.elf qemu-system-arm: -device loader,file=/tmp/bad.elf: GLib: g_mapped_file_unref: assertion 'file != NULL' failed (One way to produce an ELF file that fails like this is to copy just the first 16 bytes of a valid ELF file; this is sufficient to fool the code in load_elf_ram_sym() into thinking it's an ELF file and calling load_elf32() or load_elf64().) The failure-exit path in load_elf can be reached from various points in execution, and for some of those we haven't yet called g_mapped_file_new_from_fd(). Add a condition to the unref call so we only call it if we successfully created the GMappedFile to start with. This will fix the assertion; for the specific case of the generic loader it will then fall back from "guess this is an ELF file" to "maybe it's a uImage or a hex file" and eventually to "just load as a raw data file". Reported-by: Randy Yates Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefano Garzarella Message-Id: <20200423202011.32686-1-peter.maydell@linaro.org> Signed-off-by: Laurent Vivier --- include/hw/elf_ops.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index e0bb47bb67..398a4a2c85 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -606,7 +606,9 @@ static int glue(load_elf, SZ)(const char *name, int fd, *highaddr = (uint64_t)(elf_sword)high; ret = total_size; fail: - g_mapped_file_unref(mapped_file); + if (mapped_file) { + g_mapped_file_unref(mapped_file); + } g_free(phdr); return ret; } From 8261cc171f98e89714a0578412e7880396a4f4a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 21 Apr 2020 14:22:36 +0200 Subject: [PATCH 0193/2595] MAINTAINERS: Update Keith Busch's email address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit keith.busch@intel.com address is being rejected. Replace by the email address Keith is actively using. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Keith Busch Message-Id: <20200421122236.24867-1-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index d6886be131..1f84e3ae2c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1735,7 +1735,7 @@ F: hw/virtio/virtio-crypto-pci.c F: include/hw/virtio/virtio-crypto.h nvme -M: Keith Busch +M: Keith Busch L: qemu-block@nongnu.org S: Supported F: hw/block/nvme* From 949da1eb9db9df0d998ad2f3086979e4e23a44a1 Mon Sep 17 00:00:00 2001 From: Mikhail Gusarov Date: Sun, 26 Apr 2020 23:09:58 +0200 Subject: [PATCH 0194/2595] chardev: Add macOS to list of OSes that support -chardev serial MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macOS API for dealing with serial ports/ttys is identical to BSDs. Signed-off-by: Mikhail Gusarov Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20200426210956.17324-1-dottedmag@dottedmag.net> Signed-off-by: Laurent Vivier --- chardev/char-serial.c | 2 +- include/qemu/osdep.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/chardev/char-serial.c b/chardev/char-serial.c index 5b833ea077..7c3d84ae24 100644 --- a/chardev/char-serial.c +++ b/chardev/char-serial.c @@ -53,7 +53,7 @@ static void qmp_chardev_open_serial(Chardev *chr, #elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ - || defined(__GLIBC__) + || defined(__GLIBC__) || defined(__APPLE__) static void tty_serial_init(int fd, int speed, int parity, int data_bits, int stop_bits) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 20f5c5f197..ff7c17b857 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -379,7 +379,7 @@ void qemu_anon_ram_free(void *ptr, size_t size); #define HAVE_CHARDEV_SERIAL 1 #elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ - || defined(__GLIBC__) + || defined(__GLIBC__) || defined(__APPLE__) #define HAVE_CHARDEV_SERIAL 1 #endif From b3ac2b94cdc939a90d5a22338ae507689e2cfab0 Mon Sep 17 00:00:00 2001 From: Simran Singhal Date: Wed, 1 Apr 2020 22:23:14 +0530 Subject: [PATCH 0195/2595] Compress lines for immediate return Compress two lines into a single line if immediate return statement is found. It also remove variables progress, val, data, ret and sock as they are no longer needed. Remove space between function "mixer_load" and '(' to fix the checkpatch.pl error:- ERROR: space prohibited between function name and open parenthesis '(' Done using following coccinelle script: @@ local idexpression ret; expression e; @@ -ret = +return e; -return ret; Signed-off-by: Simran Singhal Reviewed-by: Stefan Hajnoczi Message-Id: <20200401165314.GA3213@simran-Inspiron-5558> [lv: in handle_aiocb_write_zeroes_unmap() move "int ret" inside the #ifdef] Signed-off-by: Laurent Vivier --- block/file-posix.c | 8 +++----- block/nfs.c | 3 +-- block/nvme.c | 4 +--- block/vhdx.c | 3 +-- hw/audio/ac97.c | 4 +--- hw/audio/adlib.c | 5 +---- hw/display/cirrus_vga.c | 4 +--- migration/ram.c | 4 +--- ui/gtk.c | 3 +-- util/qemu-sockets.c | 5 +---- 10 files changed, 12 insertions(+), 31 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index bf09ad8bc0..05e094be29 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1617,13 +1617,12 @@ static int handle_aiocb_write_zeroes_unmap(void *opaque) { RawPosixAIOData *aiocb = opaque; BDRVRawState *s G_GNUC_UNUSED = aiocb->bs->opaque; - int ret; /* First try to write zeros and unmap at the same time */ #ifdef CONFIG_FALLOCATE_PUNCH_HOLE - ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, - aiocb->aio_offset, aiocb->aio_nbytes); + int ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + aiocb->aio_offset, aiocb->aio_nbytes); if (ret != -ENOTSUP) { return ret; } @@ -1631,8 +1630,7 @@ static int handle_aiocb_write_zeroes_unmap(void *opaque) /* If we couldn't manage to unmap while guaranteed that the area reads as * all-zero afterwards, just write zeroes without unmapping */ - ret = handle_aiocb_write_zeroes(aiocb); - return ret; + return handle_aiocb_write_zeroes(aiocb); } #ifndef HAVE_COPY_FILE_RANGE diff --git a/block/nfs.c b/block/nfs.c index 2393fbfe6b..18c0a73694 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -623,8 +623,7 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags, } bs->total_sectors = ret; - ret = 0; - return ret; + return 0; } static QemuOptsList nfs_create_opts = { diff --git a/block/nvme.c b/block/nvme.c index 7b7c0cc5d6..eb2f54dd9d 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -575,11 +575,9 @@ static bool nvme_poll_cb(void *opaque) { EventNotifier *e = opaque; BDRVNVMeState *s = container_of(e, BDRVNVMeState, irq_notifier); - bool progress = false; trace_nvme_poll_cb(s); - progress = nvme_poll_queues(s); - return progress; + return nvme_poll_queues(s); } static int nvme_init(BlockDriverState *bs, const char *device, int namespace, diff --git a/block/vhdx.c b/block/vhdx.c index 45be0a4321..aedd782604 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -411,8 +411,7 @@ int vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, if (ret < 0) { return ret; } - ret = vhdx_update_header(bs, s, generate_data_write_guid, log_guid); - return ret; + return vhdx_update_header(bs, s, generate_data_write_guid, log_guid); } /* opens the specified header block from the VHDX file header section */ diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 1ec87feec0..8a9b9924c4 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -573,11 +573,9 @@ static uint32_t nam_readb (void *opaque, uint32_t addr) static uint32_t nam_readw (void *opaque, uint32_t addr) { AC97LinkState *s = opaque; - uint32_t val = ~0U; uint32_t index = addr; s->cas = 0; - val = mixer_load (s, index); - return val; + return mixer_load(s, index); } static uint32_t nam_readl (void *opaque, uint32_t addr) diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index d6c1fb0586..7c3b67dcfb 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -120,13 +120,10 @@ static void adlib_write(void *opaque, uint32_t nport, uint32_t val) static uint32_t adlib_read(void *opaque, uint32_t nport) { AdlibState *s = opaque; - uint8_t data; int a = nport & 3; adlib_kill_timers (s); - data = OPLRead (s->opl, a); - - return data; + return OPLRead (s->opl, a); } static void timer_handler (void *opaque, int c, double interval_Sec) diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 0d391e1300..1f29731ffe 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -2411,12 +2411,10 @@ static uint64_t cirrus_linear_bitblt_read(void *opaque, unsigned size) { CirrusVGAState *s = opaque; - uint32_t ret; /* XXX handle bitblt */ (void)s; - ret = 0xff; - return ret; + return 0xff; } static void cirrus_linear_bitblt_write(void *opaque, diff --git a/migration/ram.c b/migration/ram.c index 04f13feb2e..06cba88632 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2135,9 +2135,7 @@ int ram_postcopy_send_discard_bitmap(MigrationState *ms) } trace_ram_postcopy_send_discard_bitmap(); - ret = postcopy_each_ram_send_discard(ms); - - return ret; + return postcopy_each_ram_send_discard(ms); } /** diff --git a/ui/gtk.c b/ui/gtk.c index 030b251c61..83f2f5d49b 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1650,8 +1650,7 @@ static GSList *gd_vc_menu_init(GtkDisplayState *s, VirtualConsole *vc, G_CALLBACK(gd_menu_switch_vc), s); gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), vc->menu_item); - group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item)); - return group; + return gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item)); } #if defined(CONFIG_VTE) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index bcc06d0e01..86c48b9fa5 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -765,15 +765,12 @@ static int vsock_connect_addr(const struct sockaddr_vm *svm, Error **errp) static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp) { struct sockaddr_vm svm; - int sock = -1; if (!vsock_parse_vaddr_to_sockaddr(vaddr, &svm, errp)) { return -1; } - sock = vsock_connect_addr(&svm, errp); - - return sock; + return vsock_connect_addr(&svm, errp); } static int vsock_listen_saddr(VsockSocketAddress *vaddr, From dfde483ea38ce221e8e634823620308550b8f7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 22 Apr 2020 15:31:44 +0200 Subject: [PATCH 0196/2595] block: Avoid dead assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warning reported by Clang static code analyzer: block.c:3167:5: warning: Value stored to 'ret' is never read ret = bdrv_fill_options(&options, filename, &flags, &local_err); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fixes: 462f5bcf6 Reported-by: Clang Static Analyzer Suggested-by: Markus Armbruster Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Max Reitz Message-Id: <20200422133152.16770-2-philmd@redhat.com> Signed-off-by: Laurent Vivier --- block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block.c b/block.c index 301ec588bd..cf5c19b1db 100644 --- a/block.c +++ b/block.c @@ -3165,7 +3165,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, } ret = bdrv_fill_options(&options, filename, &flags, &local_err); - if (local_err) { + if (ret < 0) { goto fail; } From 1fe5a8c2cd5dc0da03a4246474abf37f0e8cc8c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 22 Apr 2020 15:31:45 +0200 Subject: [PATCH 0197/2595] blockdev: Remove dead assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warning reported by Clang static code analyzer: CC blockdev.o blockdev.c:2744:5: warning: Value stored to 'ret' is never read ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Reported-by: Clang Static Analyzer Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Max Reitz Message-Id: <20200422133152.16770-3-philmd@redhat.com> [lv: fix conflict because of "Add flags to blk_truncate()"] Signed-off-by: Laurent Vivier --- blockdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockdev.c b/blockdev.c index dc1a0c7c2f..708d0c323f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2741,7 +2741,7 @@ void qmp_block_resize(bool has_device, const char *device, } bdrv_drained_begin(bs); - ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp); + blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp); bdrv_drained_end(bs); out: From 00d1d29b768d920342c5e33cc56a9e0be596b2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 22 Apr 2020 15:31:46 +0200 Subject: [PATCH 0198/2595] hw/i2c/pm_smbus: Remove dead assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warning reported by Clang static code analyzer: CC hw/i2c/pm_smbus.o hw/i2c/pm_smbus.c:187:17: warning: Value stored to 'ret' is never read ret = 0; ^ ~ Reported-by: Clang Static Analyzer Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200422133152.16770-4-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/i2c/pm_smbus.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c index 36994ff585..4728540c37 100644 --- a/hw/i2c/pm_smbus.c +++ b/hw/i2c/pm_smbus.c @@ -184,7 +184,6 @@ static void smb_transaction(PMSMBus *s) s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE; s->smb_data[0] = s->smb_blkdata; s->smb_index = 0; - ret = 0; } goto out; } From 1cf5ae5129a8e78b9eb2d6545bcc56a8b136eb79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 22 Apr 2020 15:31:47 +0200 Subject: [PATCH 0199/2595] hw/input/adb-kbd: Remove dead assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 5a1f49718 the 'olen' variable is not really used. Remove it to fix a warning reported by Clang static code analyzer: CC hw/input/adb-kbd.o hw/input/adb-kbd.c:200:5: warning: Value stored to 'olen' is never read olen = 0; ^ ~ Fixes: 5a1f49718 (adb: add support for QKeyCode) Reported-by: Clang Static Analyzer Suggested-by: BALATON Zoltan Acked-by: David Gibson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200422133152.16770-5-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/input/adb-kbd.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c index 0ba8207589..a6d5c9b7c9 100644 --- a/hw/input/adb-kbd.c +++ b/hw/input/adb-kbd.c @@ -195,9 +195,7 @@ static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) { KBDState *s = ADB_KEYBOARD(d); int keycode; - int olen; - olen = 0; if (s->count == 0) { return 0; } @@ -216,7 +214,6 @@ static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) if (keycode == 0x7f) { obuf[0] = 0x7f; obuf[1] = 0x7f; - olen = 2; } else { obuf[0] = keycode; /* NOTE: the power key key-up is the two byte sequence 0xff 0xff; @@ -224,10 +221,9 @@ static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) * byte, but choose not to bother. */ obuf[1] = 0xff; - olen = 2; } - return olen; + return 2; } static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, From 22c9336d3a82d1469796b7421cb5bd5f9bfd9748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 22 Apr 2020 15:31:48 +0200 Subject: [PATCH 0200/2595] hw/ide/sii3112: Remove dead assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warning reported by Clang static code analyzer: CC hw/ide/sii3112.o hw/ide/sii3112.c:204:9: warning: Value stored to 'val' is never read val = 0; ^ ~ Fixes: a9dd6604 Reported-by: Clang Static Analyzer Reviewed-by: BALATON Zoltan Acked-by: John Snow Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200422133152.16770-6-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/ide/sii3112.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/ide/sii3112.c b/hw/ide/sii3112.c index d69079c3d9..94d2b57f95 100644 --- a/hw/ide/sii3112.c +++ b/hw/ide/sii3112.c @@ -42,7 +42,7 @@ static uint64_t sii3112_reg_read(void *opaque, hwaddr addr, unsigned int size) { SiI3112PCIState *d = opaque; - uint64_t val = 0; + uint64_t val; switch (addr) { case 0x00: @@ -126,6 +126,7 @@ static uint64_t sii3112_reg_read(void *opaque, hwaddr addr, break; default: val = 0; + break; } trace_sii3112_read(size, addr, val); return val; @@ -201,7 +202,7 @@ static void sii3112_reg_write(void *opaque, hwaddr addr, d->regs[1].sien = (val >> 16) & 0x3eed; break; default: - val = 0; + break; } } From 2c8ed55f0f615ea825cb30e80e74a07d6945bcf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 22 Apr 2020 15:31:49 +0200 Subject: [PATCH 0201/2595] hw/isa/i82378: Remove dead assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the unique variable assigned as 'pit' which better represents what it holds, to fix a warning reported by the Clang static code analyzer: CC hw/isa/i82378.o hw/isa/i82378.c:108:5: warning: Value stored to 'isa' is never read isa = isa_create_simple(isabus, "i82374"); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Reported-by: Clang Static Analyzer Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200422133152.16770-7-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/isa/i82378.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index dcb6b479ea..d9e6c7fa00 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -67,7 +67,7 @@ static void i82378_realize(PCIDevice *pci, Error **errp) I82378State *s = I82378(dev); uint8_t *pci_conf; ISABus *isabus; - ISADevice *isa; + ISADevice *pit; pci_conf = pci->config; pci_set_word(pci_conf + PCI_COMMAND, @@ -99,13 +99,13 @@ static void i82378_realize(PCIDevice *pci, Error **errp) isa_bus_irqs(isabus, s->i8259); /* 1 82C54 (pit) */ - isa = i8254_pit_init(isabus, 0x40, 0, NULL); + pit = i8254_pit_init(isabus, 0x40, 0, NULL); /* speaker */ - pcspk_init(isabus, isa); + pcspk_init(isabus, pit); /* 2 82C37 (dma) */ - isa = isa_create_simple(isabus, "i82374"); + isa_create_simple(isabus, "i82374"); } static void i82378_init(Object *obj) From 6ae1a5a37711c80166b92019174877fc6f73030a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 22 Apr 2020 15:31:50 +0200 Subject: [PATCH 0202/2595] hw/gpio/aspeed_gpio: Remove dead assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warning reported by Clang static code analyzer: hw/gpio/aspeed_gpio.c:717:18: warning: Value stored to 'g_idx' during its initialization is never read int set_idx, g_idx = *group_idx; ^~~~~ ~~~~~~~~~~ Reported-by: Clang Static Analyzer Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200422133152.16770-8-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/gpio/aspeed_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index e52fcfd9a0..4c75b5c80c 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -712,7 +712,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, static int get_set_idx(AspeedGPIOState *s, const char *group, int *group_idx) { AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s); - int set_idx, g_idx = *group_idx; + int set_idx, g_idx; for (set_idx = 0; set_idx < agc->nr_gpio_sets; set_idx++) { const GPIOSetProperties *set_props = &agc->props[set_idx]; From dd1545a3f03f6e821a4ef588acbd99fb4328bcc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 22 Apr 2020 15:31:51 +0200 Subject: [PATCH 0203/2595] hw/timer/stm32f2xx_timer: Remove dead assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warning reported by Clang static code analyzer: CC hw/timer/stm32f2xx_timer.o hw/timer/stm32f2xx_timer.c:225:9: warning: Value stored to 'value' is never read value = timer_val; ^ ~~~~~~~~~ Reported-by: Clang Static Analyzer Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200422133152.16770-9-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/timer/stm32f2xx_timer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c index 06ec8a02c2..ba8694dcd3 100644 --- a/hw/timer/stm32f2xx_timer.c +++ b/hw/timer/stm32f2xx_timer.c @@ -222,7 +222,6 @@ static void stm32f2xx_timer_write(void *opaque, hwaddr offset, case TIM_PSC: timer_val = stm32f2xx_ns_to_ticks(s, now) - s->tick_offset; s->tim_psc = value & 0xFFFF; - value = timer_val; break; case TIM_CNT: timer_val = value; From e702fba83108519618046a2a09235a62e3a81595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 22 Apr 2020 15:31:52 +0200 Subject: [PATCH 0204/2595] hw/timer/pxa2xx_timer: Add assertion to silent static analyzer warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pxa2xx_timer_tick4() takes an opaque pointer, then calls pxa2xx_timer_update4(), so the static analyzer can not verify that the 'n < 8': 425 static void pxa2xx_timer_tick4(void *opaque) 426 { 427 PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque; 428 PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info; 429 430 pxa2xx_timer_tick(&t->tm); 433 if (t->control & (1 << 6)) 434 pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4); 135 static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) 136 { 137 PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 140 static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 }; 142 143 if (s->tm4[n].control & (1 << 7)) 144 counter = n; 145 else 146 counter = counters[n]; Add an assert() to give the static analyzer a hint, this fixes a warning reported by Clang static code analyzer: CC hw/timer/pxa2xx_timer.o hw/timer/pxa2xx_timer.c:146:17: warning: Assigned value is garbage or undefined counter = counters[n]; ^ ~~~~~~~~~~~ Reported-by: Clang Static Analyzer Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200422133152.16770-10-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/timer/pxa2xx_timer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c index cd172cc1e9..944c165889 100644 --- a/hw/timer/pxa2xx_timer.c +++ b/hw/timer/pxa2xx_timer.c @@ -140,6 +140,7 @@ static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 }; int counter; + assert(n < ARRAY_SIZE(counters)); if (s->tm4[n].control & (1 << 7)) counter = n; else From 0501e1aa1d32a6e02dd06a79bba97fbe9d557cb5 Mon Sep 17 00:00:00 2001 From: Julia Suvorova Date: Mon, 27 Apr 2020 20:24:39 +0200 Subject: [PATCH 0205/2595] hw/pci/pcie: Forbid hot-plug if it's disabled on the slot Raise an error when trying to hot-plug/unplug a device through QMP to a device with disabled hot-plug capability. This makes the device behaviour more consistent and provides an explanation of the failure in the case of asynchronous unplug. Signed-off-by: Julia Suvorova Message-Id: <20200427182440.92433-2-jusual@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/pci/pcie.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 0eb3a2a5d2..6b48d04d2c 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -415,6 +415,7 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, { PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev); uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap; + uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP); PCIDevice *pci_dev = PCI_DEVICE(dev); /* Don't send event when device is enabled during qemu machine creation: @@ -430,6 +431,13 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, return; } + /* Check if hot-plug is disabled on the slot */ + if ((sltcap & PCI_EXP_SLTCAP_HPC) == 0) { + error_setg(errp, "Hot-plug failed: unsupported by the port device '%s'", + DEVICE(hotplug_pdev)->id); + return; + } + /* To enable multifunction hot-plug, we just ensure the function * 0 added last. When function 0 is added, we set the sltsta and * inform OS via event notification. @@ -470,6 +478,17 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, Error *local_err = NULL; PCIDevice *pci_dev = PCI_DEVICE(dev); PCIBus *bus = pci_get_bus(pci_dev); + PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev); + uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap; + uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP); + + /* Check if hot-unplug is disabled on the slot */ + if ((sltcap & PCI_EXP_SLTCAP_HPC) == 0) { + error_setg(errp, "Hot-unplug failed: " + "unsupported by the port device '%s'", + DEVICE(hotplug_pdev)->id); + return; + } pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &local_err); if (local_err) { From 6a1e073378353eb6ac0565e0dc649b3db76ed5dc Mon Sep 17 00:00:00 2001 From: Julia Suvorova Date: Mon, 27 Apr 2020 20:24:40 +0200 Subject: [PATCH 0206/2595] hw/pci/pcie: Replace PCI_DEVICE() casts with existing variable A little cleanup is possible because of hotplug_pdev introduction. Signed-off-by: Julia Suvorova Message-Id: <20200427182440.92433-3-jusual@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/pci/pcie.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 6b48d04d2c..abc99b6eff 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -449,7 +449,7 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, PCI_EXP_LNKSTA_DLLLA); } - pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), + pcie_cap_slot_event(hotplug_pdev, PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP); } } @@ -490,7 +490,7 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, return; } - pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &local_err); + pcie_cap_slot_plug_common(hotplug_pdev, dev, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -509,7 +509,7 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, return; } - pcie_cap_slot_push_attention_button(PCI_DEVICE(hotplug_dev)); + pcie_cap_slot_push_attention_button(hotplug_pdev); } /* pci express slot for pci express root/downstream port From 0f8d656b3b8ef31ebfbd4a24003d9a58d987a605 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 15:59:49 +0200 Subject: [PATCH 0207/2595] move 'typedef Aml' to qemu/types.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Message-Id: <20200429140003.7336-2-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé --- include/hw/acpi/aml-build.h | 1 - include/qemu/typedefs.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index 0f4ed53d7f..1539fe0667 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -33,7 +33,6 @@ struct Aml { uint8_t op; AmlBlockFlags block_flags; }; -typedef struct Aml Aml; typedef enum { AML_COMPATIBILITY = 0, diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 375770a80f..ecf3cde26c 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -24,6 +24,7 @@ typedef struct AdapterInfo AdapterInfo; typedef struct AddressSpace AddressSpace; typedef struct AioContext AioContext; +typedef struct Aml Aml; typedef struct AnnounceTimer AnnounceTimer; typedef struct BdrvDirtyBitmap BdrvDirtyBitmap; typedef struct BdrvDirtyBitmapIter BdrvDirtyBitmapIter; From 17d08ba4659dc66a51a7eab83aeafcc9765d0a87 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 15:59:50 +0200 Subject: [PATCH 0208/2595] acpi: add aml builder stubs Needed when moving aml builder code to devices. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Message-Id: <20200429140003.7336-3-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/Makefile.objs | 4 +- hw/acpi/aml-build-stub.c | 79 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 hw/acpi/aml-build-stub.c diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs index 777da07f4d..cab9bcd457 100644 --- a/hw/acpi/Makefile.objs +++ b/hw/acpi/Makefile.objs @@ -20,6 +20,6 @@ common-obj-$(CONFIG_TPM) += tpm.o common-obj-$(CONFIG_IPMI) += ipmi.o common-obj-$(call lnot,$(CONFIG_IPMI)) += ipmi-stub.o else -common-obj-y += acpi-stub.o +common-obj-y += acpi-stub.o aml-build-stub.o endif -common-obj-$(CONFIG_ALL) += acpi-stub.o acpi-x86-stub.o ipmi-stub.o +common-obj-$(CONFIG_ALL) += acpi-stub.o aml-build-stub.o acpi-x86-stub.o ipmi-stub.o diff --git a/hw/acpi/aml-build-stub.c b/hw/acpi/aml-build-stub.c new file mode 100644 index 0000000000..58b2e16227 --- /dev/null +++ b/hw/acpi/aml-build-stub.c @@ -0,0 +1,79 @@ +/* + * ACPI aml builder stubs for platforms that don't support ACPI. + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2016 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 . + */ + +#include "qemu/osdep.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/aml-build.h" + +void aml_append(Aml *parent_ctx, Aml *child) +{ +} + +Aml *aml_resource_template(void) +{ + return NULL; +} + +Aml *aml_device(const char *name_format, ...) +{ + return NULL; +} + +Aml *aml_eisaid(const char *str) +{ + return NULL; +} + +Aml *aml_name_decl(const char *name, Aml *val) +{ + return NULL; +} + +Aml *aml_io(AmlIODecode dec, uint16_t min_base, uint16_t max_base, + uint8_t aln, uint8_t len) +{ + return NULL; +} + +Aml *aml_irq_no_flags(uint8_t irq) +{ + return NULL; +} + +Aml *aml_int(const uint64_t val) +{ + return NULL; +} + +Aml *aml_package(uint8_t num_elements) +{ + return NULL; +} + +Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTransferSize sz, + uint8_t channel) +{ + return NULL; +} + +Aml *aml_buffer(int buffer_size, uint8_t *byte_list) +{ + return NULL; +} From 9604980303579ac351e1611d1b0ea8a89c3e9e6b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 15:59:51 +0200 Subject: [PATCH 0209/2595] qtest: allow DSDT acpi table changes Signed-off-by: Gerd Hoffmann Message-Id: <20200429140003.7336-4-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..6a052c5044 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,18 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT", +"tests/data/acpi/pc/DSDT.acpihmat", +"tests/data/acpi/pc/DSDT.bridge", +"tests/data/acpi/pc/DSDT.cphp", +"tests/data/acpi/pc/DSDT.dimmpxm", +"tests/data/acpi/pc/DSDT.ipmikcs", +"tests/data/acpi/pc/DSDT.memhp", +"tests/data/acpi/pc/DSDT.numamem", +"tests/data/acpi/q35/DSDT", +"tests/data/acpi/q35/DSDT.acpihmat", +"tests/data/acpi/q35/DSDT.bridge", +"tests/data/acpi/q35/DSDT.cphp", +"tests/data/acpi/q35/DSDT.dimmpxm", +"tests/data/acpi/q35/DSDT.ipmibt", +"tests/data/acpi/q35/DSDT.memhp", +"tests/data/acpi/q35/DSDT.mmio64", +"tests/data/acpi/q35/DSDT.numamem", From 88b3648f557855f7da85b5d32f1a08c5a66c2a01 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 15:59:52 +0200 Subject: [PATCH 0210/2595] acpi: drop pointless _STA method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When returning a constant there is no point in having a method in the first place, _STA can be a simple integer instead. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Message-Id: <20200429140003.7336-5-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé --- hw/i386/acpi-build.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 23c77eeb95..3a046b03e4 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1151,14 +1151,11 @@ static Aml *build_kbd_device_aml(void) { Aml *dev; Aml *crs; - Aml *method; dev = aml_device("KBD"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0303"))); - method = aml_method("_STA", 0, AML_NOTSERIALIZED); - aml_append(method, aml_return(aml_int(0x0f))); - aml_append(dev, method); + aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); crs = aml_resource_template(); aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01)); @@ -1173,14 +1170,11 @@ static Aml *build_mouse_device_aml(void) { Aml *dev; Aml *crs; - Aml *method; dev = aml_device("MOU"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0F13"))); - method = aml_method("_STA", 0, AML_NOTSERIALIZED); - aml_append(method, aml_return(aml_int(0x0f))); - aml_append(dev, method); + aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); crs = aml_resource_template(); aml_append(crs, aml_irq_no_flags(12)); @@ -2238,9 +2232,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, TPM_CRB_ADDR_SIZE, AML_READ_WRITE)); aml_append(dev, aml_name_decl("_CRS", crs)); - method = aml_method("_STA", 0, AML_NOTSERIALIZED); - aml_append(method, aml_return(aml_int(0x0f))); - aml_append(dev, method); + aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); tpm_build_ppi_acpi(tpm, dev); From a53e581ee818d44bea9dcd2c543c2d08a5934fae Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 15:59:53 +0200 Subject: [PATCH 0211/2595] acpi: add ISADeviceClass->build_aml() Also add isa_aml_build() function which walks all isa devices. This allows to move aml builder code to isa devices. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Message-Id: <20200429140003.7336-6-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 1 + hw/isa/isa-bus.c | 15 +++++++++++++++ include/hw/isa/isa.h | 2 ++ 3 files changed, 18 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 3a046b03e4..97f3c75cd9 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1288,6 +1288,7 @@ static void build_isa_devices_aml(Aml *table) error_report("No ISA bus, unable to define IPMI ACPI data"); } else { build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA"); + isa_build_aml(ISA_BUS(obj), scope); } aml_append(table, scope); diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 798dd9194e..1f2189f4d5 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -207,6 +207,21 @@ ISADevice *isa_vga_init(ISABus *bus) } } +void isa_build_aml(ISABus *bus, Aml *scope) +{ + BusChild *kid; + ISADevice *dev; + ISADeviceClass *dc; + + QTAILQ_FOREACH(kid, &bus->parent_obj.children, sibling) { + dev = ISA_DEVICE(kid->child); + dc = ISA_DEVICE_GET_CLASS(dev); + if (dc->build_aml) { + dc->build_aml(dev, scope); + } + } +} + static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent) { ISADevice *d = ISA_DEVICE(dev); diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index 59a4d4b50a..02c2350274 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -69,6 +69,7 @@ typedef struct IsaDmaClass { typedef struct ISADeviceClass { DeviceClass parent_class; + void (*build_aml)(ISADevice *dev, Aml *scope); } ISADeviceClass; struct ISABus { @@ -107,6 +108,7 @@ ISADevice *isa_try_create(ISABus *bus, const char *name); ISADevice *isa_create_simple(ISABus *bus, const char *name); ISADevice *isa_vga_init(ISABus *bus); +void isa_build_aml(ISABus *bus, Aml *scope); /** * isa_register_ioport: Install an I/O port region on the ISA bus. From ba480fa6264b161697009448c3cbc0730485379e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 15:59:54 +0200 Subject: [PATCH 0212/2595] rtc: add RTC_ISA_BASE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add and use RTC_ISA_BASE define instead of hardcoding 0x70. Signed-off-by: Gerd Hoffmann Message-Id: <20200429140003.7336-7-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov --- hw/rtc/mc146818rtc.c | 5 ++--- include/hw/rtc/mc146818rtc.h | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index dc4269cc55..d18c09911b 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -908,7 +908,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) { ISADevice *isadev = ISA_DEVICE(dev); RTCState *s = MC146818_RTC(dev); - int base = 0x70; s->cmos_data[RTC_REG_A] = 0x26; s->cmos_data[RTC_REG_B] = 0x02; @@ -951,7 +950,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) qemu_register_suspend_notifier(&s->suspend_notifier); memory_region_init_io(&s->io, OBJECT(s), &cmos_ops, s, "rtc", 2); - isa_register_ioport(isadev, &s->io, base); + isa_register_ioport(isadev, &s->io, RTC_ISA_BASE); /* register rtc 0x70 port for coalesced_pio */ memory_region_set_flush_coalesced(&s->io); @@ -960,7 +959,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) memory_region_add_subregion(&s->io, 0, &s->coalesced_io); memory_region_add_coalescing(&s->coalesced_io, 0, 1); - qdev_set_legacy_instance_id(dev, base, 3); + qdev_set_legacy_instance_id(dev, RTC_ISA_BASE, 3); qemu_register_reset(rtc_reset, s); object_property_add_tm(OBJECT(s), "date", rtc_get_date, NULL); diff --git a/include/hw/rtc/mc146818rtc.h b/include/hw/rtc/mc146818rtc.h index 10c93a096a..3713181b56 100644 --- a/include/hw/rtc/mc146818rtc.h +++ b/include/hw/rtc/mc146818rtc.h @@ -47,6 +47,7 @@ typedef struct RTCState { } RTCState; #define RTC_ISA_IRQ 8 +#define RTC_ISA_BASE 0x70 ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq); From 15138b5e6ff28a8e68a2e1cb6f4ca2fb7e5b057c Mon Sep 17 00:00:00 2001 From: Anthoine Bourgeois Date: Wed, 22 Apr 2020 23:54:54 +0200 Subject: [PATCH 0213/2595] virtio-vga: fix virtio-vga bar ordering With virtio-vga, pci bar are reordered. Bar #2 is used for compatibility with stdvga. By default, bar #2 is used by virtio modern io bar. This bar is the last one introduce in the virtio pci bar layout and it's crushed by the virtio-vga reordering. So virtio-vga and modern-pio-notify are incompatible because virtio-vga failed to initialize with this option. This fix sets the modern io bar to the bar #5 to avoid conflict. Signed-off-by: Anthoine Bourgeois Message-Id: <20200422215455.10244-1-anthoine.bourgeois@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Gerd Hoffmann --- hw/display/virtio-vga.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 2b4c2aa126..95757a6619 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -114,6 +114,7 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) */ vpci_dev->modern_mem_bar_idx = 2; vpci_dev->msix_bar_idx = 4; + vpci_dev->modern_io_bar_idx = 5; if (!(vpci_dev->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ)) { /* From e6779156a44846053f662157a12ed366568c2cff Mon Sep 17 00:00:00 2001 From: Anthoine Bourgeois Date: Wed, 22 Apr 2020 23:54:55 +0200 Subject: [PATCH 0214/2595] virtio-pci: update virtio pci bar layout documentation The modern io bar was never documented. Signed-off-by: Anthoine Bourgeois Message-Id: <20200422215455.10244-2-anthoine.bourgeois@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Gerd Hoffmann --- hw/virtio/virtio-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 4cb784389c..d028c17c24 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1705,6 +1705,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) * * region 0 -- virtio legacy io bar * region 1 -- msi-x bar + * region 2 -- virtio modern io bar (off by default) * region 4+5 -- virtio modern memory (64bit) bar * */ From 0ac2e63575b5af918e333cc687bbd8e1ab7bb6fe Mon Sep 17 00:00:00 2001 From: Li Feng Date: Fri, 17 Apr 2020 18:17:07 +0800 Subject: [PATCH 0215/2595] vhost-user-blk: fix invalid memory access when s->inflight is freed, vhost_dev_free_inflight may try to access s->inflight->addr, it will retrigger the following issue. ==7309==ERROR: AddressSanitizer: heap-use-after-free on address 0x604001020d18 at pc 0x555555ce948a bp 0x7fffffffb170 sp 0x7fffffffb160 READ of size 8 at 0x604001020d18 thread T0 #0 0x555555ce9489 in vhost_dev_free_inflight /root/smartx/qemu-el7/qemu-test/hw/virtio/vhost.c:1473 #1 0x555555cd86eb in virtio_reset /root/smartx/qemu-el7/qemu-test/hw/virtio/virtio.c:1214 #2 0x5555560d3eff in virtio_pci_reset hw/virtio/virtio-pci.c:1859 #3 0x555555f2ac53 in device_set_realized hw/core/qdev.c:893 #4 0x5555561d572c in property_set_bool qom/object.c:1925 #5 0x5555561de8de in object_property_set_qobject qom/qom-qobject.c:27 #6 0x5555561d99f4 in object_property_set_bool qom/object.c:1188 #7 0x555555e50ae7 in qdev_device_add /root/smartx/qemu-el7/qemu-test/qdev-monitor.c:626 #8 0x555555e51213 in qmp_device_add /root/smartx/qemu-el7/qemu-test/qdev-monitor.c:806 #9 0x555555e8ff40 in hmp_device_add /root/smartx/qemu-el7/qemu-test/hmp.c:1951 #10 0x555555be889a in handle_hmp_command /root/smartx/qemu-el7/qemu-test/monitor.c:3404 #11 0x555555beac8b in monitor_command_cb /root/smartx/qemu-el7/qemu-test/monitor.c:4296 #12 0x555556433eb7 in readline_handle_byte util/readline.c:393 #13 0x555555be89ec in monitor_read /root/smartx/qemu-el7/qemu-test/monitor.c:4279 #14 0x5555563285cc in tcp_chr_read chardev/char-socket.c:470 #15 0x7ffff670b968 in g_main_context_dispatch (/lib64/libglib-2.0.so.0+0x4a968) #16 0x55555640727c in glib_pollfds_poll util/main-loop.c:215 #17 0x55555640727c in os_host_main_loop_wait util/main-loop.c:238 #18 0x55555640727c in main_loop_wait util/main-loop.c:497 #19 0x555555b2d0bf in main_loop /root/smartx/qemu-el7/qemu-test/vl.c:2013 #20 0x555555b2d0bf in main /root/smartx/qemu-el7/qemu-test/vl.c:4776 #21 0x7fffdd2eb444 in __libc_start_main (/lib64/libc.so.6+0x22444) #22 0x555555b3767a (/root/smartx/qemu-el7/qemu-test/x86_64-softmmu/qemu-system-x86_64+0x5e367a) 0x604001020d18 is located 8 bytes inside of 40-byte region [0x604001020d10,0x604001020d38) freed by thread T0 here: #0 0x7ffff6f00508 in __interceptor_free (/lib64/libasan.so.4+0xde508) #1 0x7ffff671107d in g_free (/lib64/libglib-2.0.so.0+0x5007d) previously allocated by thread T0 here: #0 0x7ffff6f00a88 in __interceptor_calloc (/lib64/libasan.so.4+0xdea88) #1 0x7ffff6710fc5 in g_malloc0 (/lib64/libglib-2.0.so.0+0x4ffc5) SUMMARY: AddressSanitizer: heap-use-after-free /root/smartx/qemu-el7/qemu-test/hw/virtio/vhost.c:1473 in vhost_dev_free_inflight Shadow bytes around the buggy address: 0x0c08801fc150: fa fa 00 00 00 00 04 fa fa fa fd fd fd fd fd fa 0x0c08801fc160: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 04 fa 0x0c08801fc170: fa fa 00 00 00 00 00 01 fa fa 00 00 00 00 04 fa 0x0c08801fc180: fa fa 00 00 00 00 00 01 fa fa 00 00 00 00 00 01 0x0c08801fc190: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 04 fa =>0x0c08801fc1a0: fa fa fd[fd]fd fd fd fa fa fa fd fd fd fd fd fa 0x0c08801fc1b0: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa 0x0c08801fc1c0: fa fa 00 00 00 00 00 fa fa fa fd fd fd fd fd fd 0x0c08801fc1d0: fa fa 00 00 00 00 00 01 fa fa fd fd fd fd fd fa 0x0c08801fc1e0: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fd 0x0c08801fc1f0: fa fa 00 00 00 00 00 01 fa fa fd fd fd fd fd fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==7309==ABORTING Signed-off-by: Li Feng Message-Id: <20200417101707.14467-1-fengli@smartx.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Raphael Norwitz --- hw/block/vhost-user-blk.c | 4 ++++ hw/virtio/vhost.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 17df5338e7..6c485d1c9e 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -441,7 +441,9 @@ reconnect: virtio_err: g_free(s->vhost_vqs); + s->vhost_vqs = NULL; g_free(s->inflight); + s->inflight = NULL; for (i = 0; i < s->num_queues; i++) { virtio_delete_queue(s->virtqs[i]); } @@ -462,7 +464,9 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) vhost_dev_cleanup(&s->dev); vhost_dev_free_inflight(s->inflight); g_free(s->vhost_vqs); + s->vhost_vqs = NULL; g_free(s->inflight); + s->inflight = NULL; for (i = 0; i < s->num_queues; i++) { virtio_delete_queue(s->virtqs[i]); diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 01ebe12f28..aff98a0ede 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1514,7 +1514,7 @@ void vhost_dev_set_config_notifier(struct vhost_dev *hdev, void vhost_dev_free_inflight(struct vhost_inflight *inflight) { - if (inflight->addr) { + if (inflight && inflight->addr) { qemu_memfd_free(inflight->addr, inflight->size, inflight->fd); inflight->addr = NULL; inflight->fd = -1; From e625ba2a413f2bfdbb71c71008b627fede20fcbb Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 4 May 2020 07:22:49 -0400 Subject: [PATCH 0216/2595] checkpatch: fix acpi check with multiple file name Using global expected/nonexpected values causes false positives when testing multiple patches in one checkpatch run: one patch can change expected, another one non-expected. Use local variables within process() to fix that. Signed-off-by: Michael S. Tsirkin --- scripts/checkpatch.pl | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index e658e6546f..c3d08aa99f 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -35,8 +35,6 @@ my $summary_file = 0; my $root; my %debug; my $help = 0; -my $acpi_testexpected; -my $acpi_nontestexpected; sub help { my ($exitcode) = @_; @@ -1261,21 +1259,22 @@ sub WARN { # According to tests/qtest/bios-tables-test.c: do not # change expected file in the same commit with adding test sub checkfilename { - my ($name) = @_; + my ($name, $acpi_testexpected, $acpi_nontestexpected) = @_; + if ($name =~ m#^tests/data/acpi/# and # make exception for a shell script that rebuilds the files not $name =~ m#^\.sh$# or $name =~ m#^tests/qtest/bios-tables-test-allowed-diff.h$#) { - $acpi_testexpected = $name; + $$acpi_testexpected = $name; } else { - $acpi_nontestexpected = $name; + $$acpi_nontestexpected = $name; } - if (defined $acpi_testexpected and defined $acpi_nontestexpected) { + if (defined $$acpi_testexpected and defined $$acpi_nontestexpected) { ERROR("Do not add expected files together with tests, " . "follow instructions in " . "tests/qtest/bios-tables-test.c: both " . - $acpi_testexpected . " and " . - $acpi_nontestexpected . " found\n"); + $$acpi_testexpected . " and " . + $$acpi_nontestexpected . " found\n"); } } @@ -1325,6 +1324,9 @@ sub process { my %suppress_whiletrailers; my %suppress_export; + my $acpi_testexpected; + my $acpi_nontestexpected; + # Pre-scan the patch sanitizing the lines. sanitise_line_reset(); @@ -1454,11 +1456,11 @@ sub process { if ($line =~ /^diff --git.*?(\S+)$/) { $realfile = $1; $realfile =~ s@^([^/]*)/@@ if (!$file); - checkfilename($realfile); + checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected); } elsif ($line =~ /^\+\+\+\s+(\S+)/) { $realfile = $1; $realfile =~ s@^([^/]*)/@@ if (!$file); - checkfilename($realfile); + checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected); $p1_prefix = $1; if (!$file && $tree && $p1_prefix ne '' && From e11b06a880caa1630fcfdca7d2fc3c9e597792a1 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 4 May 2020 07:47:17 -0400 Subject: [PATCH 0217/2595] checkpatch: ignore allowed diff list Allow changing allowed diff list at any point: - when changing code under test - when adding expected files It's just a list of files so easy to review and merge anyway. Signed-off-by: Michael S. Tsirkin --- scripts/checkpatch.pl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index c3d08aa99f..0ba213e9f2 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1261,12 +1261,13 @@ sub WARN { sub checkfilename { my ($name, $acpi_testexpected, $acpi_nontestexpected) = @_; - if ($name =~ m#^tests/data/acpi/# and - # make exception for a shell script that rebuilds the files - not $name =~ m#^\.sh$# or - $name =~ m#^tests/qtest/bios-tables-test-allowed-diff.h$#) { + # Note: shell script that rebuilds the expected files is in the same + # directory as files themselves. + # Note: allowed diff list can be changed both when changing expected + # files and when changing tests. + if ($name =~ m#^tests/data/acpi/# and not $name =~ m#^\.sh$#) { $$acpi_testexpected = $name; - } else { + } elsif ($name =~ m#^tests/qtest/bios-tables-test-allowed-diff.h$#) { $$acpi_nontestexpected = $name; } if (defined $$acpi_testexpected and defined $$acpi_nontestexpected) { From e3a99063af7bc78e51c19cb007acb646d381a9c7 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 4 May 2020 08:47:02 -0400 Subject: [PATCH 0218/2595] acpi: DSDT without _STA commit f6595976e699 ("acpi: drop pointless _STA method") replaced _STA method with simple name object. Update DSDT accordingly. Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/pc/DSDT | Bin 5131 -> 5125 bytes tests/data/acpi/pc/DSDT.acpihmat | Bin 6455 -> 6449 bytes tests/data/acpi/pc/DSDT.bridge | Bin 6990 -> 6984 bytes tests/data/acpi/pc/DSDT.cphp | Bin 5594 -> 5588 bytes tests/data/acpi/pc/DSDT.dimmpxm | Bin 6784 -> 6778 bytes tests/data/acpi/pc/DSDT.ipmikcs | Bin 5203 -> 5197 bytes tests/data/acpi/pc/DSDT.memhp | Bin 6490 -> 6484 bytes tests/data/acpi/pc/DSDT.numamem | Bin 5137 -> 5131 bytes tests/data/acpi/q35/DSDT | Bin 7869 -> 7863 bytes tests/data/acpi/q35/DSDT.acpihmat | Bin 9193 -> 9187 bytes tests/data/acpi/q35/DSDT.bridge | Bin 7886 -> 7880 bytes tests/data/acpi/q35/DSDT.cphp | Bin 8332 -> 8326 bytes tests/data/acpi/q35/DSDT.dimmpxm | Bin 9522 -> 9516 bytes tests/data/acpi/q35/DSDT.ipmibt | Bin 7944 -> 7938 bytes tests/data/acpi/q35/DSDT.memhp | Bin 9228 -> 9222 bytes tests/data/acpi/q35/DSDT.mmio64 | Bin 8999 -> 8993 bytes tests/data/acpi/q35/DSDT.numamem | Bin 7875 -> 7869 bytes tests/qtest/bios-tables-test-allowed-diff.h | 17 ----------------- 18 files changed, 17 deletions(-) diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT index c6adfe32d5ba6a5db2ca3e210766839547e122c8..ad4b2d46cc7865e8bafcca2e4e888a03cc5483b5 100644 GIT binary patch delta 77 zcmeCyXw~3y33dr#6=7gtRNKha%gE#_H+d$by@-jolS@2DyoaX?kK+YqW{&va5XZ^y W8I?p-eEmb=68yqoiOm{Jj|BnUDii7e delta 83 zcmZqG=+@wJ33dtL7GYpu+_;gemyyX?e)3F4dvSAbCzp7Rcn?n(9>)vJ%p#oe!6A+e aOD4ZzR1#PB^$&&1@e9M`HY+hb76brx%@yYW diff --git a/tests/data/acpi/pc/DSDT.acpihmat b/tests/data/acpi/pc/DSDT.acpihmat index ad890e09aab12dd280c3d2465540db82ca1b430b..eff7aadfabe431c3ac2d28e0c6721eb6e322af66 100644 GIT binary patch delta 77 zcmdmPw9$ymCD5r@gANoJdPKbnMF9`gF_q{ amP~%bs3flL>mLf2;}?d>ZB}C97Y6{CS`~x< diff --git a/tests/data/acpi/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge index f01fa3ad4ee6aed5262daef464a1ade41e06975d..92ae808e2e071e367f0b68b3553239bd56b4b766 100644 GIT binary patch delta 77 zcmX?ScEXIyCDz_975r@gANoJdPKbnK|NvLmVf+ XXH*hV@%0adOYjSWB{pj?sYwC=F2ZuN^ aESda56e#n(R+F2OGhme{Ppv`H8MV#pP# delta 83 zcmcbjeM_6mCD2ZuN^ aESda3 diff --git a/tests/data/acpi/pc/DSDT.dimmpxm b/tests/data/acpi/pc/DSDT.dimmpxm index ad2800de672534dc87012f03e27b19671a330083..7fa09463c16c2f6b60114591785918b9d96b4f17 100644 GIT binary patch delta 77 zcmZoL{bj=C66_LECB?wN*uIggmyyX=Zt_e)vJ%pCE-A&!&Z WGb)Lw`1*&!CHRHG5}P%cA|wDh`xM0h delta 83 zcmexm(qPKv66_MvAjQDID72BQmyyX?e)3F4dvSAbCzp7Rcn?n(9>)vJ%p#oe!6A+e aOD4ZzR1#PB^$&&1@e9M`HY+hjNB{ts#}&c= diff --git a/tests/data/acpi/pc/DSDT.ipmikcs b/tests/data/acpi/pc/DSDT.ipmikcs index 2633a8cecf017bfce01ba8377428b8c5433e0be2..469d13e1f6b873bb9cfa0b3af32d1a3bc58e8f77 100644 GIT binary patch delta 76 zcmcbtaaM!NCDCqao0w!UPeaO$uk%oL`=M$T;e(6Jv?1_94|04bHoRSI8J`g Ws3fA|>mLf2;1>oz_975r@gANoJdPKbnK|NvLmVf+ XXH*hV@%0adOYjSWB{pj?8Hob`BYG4! delta 83 zcmca&bjyg#CD2ZuN^ aESdaz_975r@gANoJdPKbnK|NvLmVf+ XXH*hV@%0adOYjSWB{pj?y%Yoh3_}#G delta 83 zcmeCyn5e6JmyyX?e)3F4dvSAbCzp7Rcn?n(9>)vJ%p#oe!6A+e aOD4ZzR1#PB^$&&1@e9M`HY+i`6a)ZeKNYC} diff --git a/tests/data/acpi/q35/DSDT b/tests/data/acpi/q35/DSDT index 1f91888d7a485850cf27f152e247a90b208003dc..9fa4d5a405c2bcd9313b13894917622bf156013e 100644 GIT binary patch delta 77 zcmdmMyWN({CD5r@gANoJdPKbnK|NvLmVd; XF)4|t`1*&!CHRHG5}Q{u3CREe1yK{h delta 83 zcmdmPyVsV>CD5r@gANoJdPKbnMF9`gF_q{ amQ2oPQW979^$&&1@e9M`HZNrok^ul)^%TAU diff --git a/tests/data/acpi/q35/DSDT.acpihmat b/tests/data/acpi/q35/DSDT.acpihmat index 3586f6368a77d1497c35a7571c9f6c460221d9ab..2d834a854ccddc17afd0bc4b4a9e0886feff8e65 100644 GIT binary patch delta 77 zcmaFq{@9(%CD5r@gANoJdPKbnK|NvLmVd; XF)4|t`1*&!CHRHG5}Q{u*(m}5CR-F; delta 83 zcmaFt{?eVxCD2ZuN^ aESa3oq$IBH>mLf2;}?d>ZC=V`rw9PVffiZ- diff --git a/tests/data/acpi/q35/DSDT.bridge b/tests/data/acpi/q35/DSDT.bridge index eae3a2a8657e9986d8ac592958503c0b516faaef..b75122b24a41b8fd58b9e7071032298e0fc2284b 100644 GIT binary patch delta 77 zcmX?Sd%~8>CD5r@gANoJdPKbnK|NvLmVd; XF)4|t`1*&!CHRHG5}Q{uDa!x={9qHM delta 83 zcmX?Md(M{2CD2ZuN^ aESa3oq$IBH>mLf2;}?d>ZC=WxECT?S1r?$I diff --git a/tests/data/acpi/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp index 53d735a4de25c4d8e23eed102fcd01376168c5b3..c59c19ff46b9bb4fa3e06e9ffbcbeba308a80cd0 100644 GIT binary patch delta 77 zcmeBiY;)vt33dr-Q($0Ve7BKHfQiXVY_bfKy@-jolS@2DyoaX?kK+YqW{&va5XZ?y WOiCguzW$+b34UR)#OBpZ4`l)UY7~J0 delta 83 zcmZp3>~Z9B33dtTQD9(TtlY>Yz{KPrK3RszUfkT<$t9j6-ow*{$MFI)vj}H=aEK$r ZlF9i@O5*Ci{-JO=eqos0=A}#zWdT#Y6@CB! diff --git a/tests/data/acpi/q35/DSDT.dimmpxm b/tests/data/acpi/q35/DSDT.dimmpxm index 02ccdd5f38d5b2356dcca89398c41dcf2595dfff..9edc104ee6b06dd9d909b65b83c99494d03a137d 100644 GIT binary patch delta 77 zcmdnwwZ@CfCD5r@gANoJdPKbnK|NvLmVd; XF)4|t`1*&!CHRHG5}Q{uwJQMt^luaX delta 83 zcmZ4EwaJUiCD027mg_+%L-dvSAbCzp7Rcn?n(9>)vJ%p#oe!6A+e aOD5+tDT%B5`iH{h_=RC|o0l@RD**sWt`z$K diff --git a/tests/data/acpi/q35/DSDT.ipmibt b/tests/data/acpi/q35/DSDT.ipmibt index 9e2d4f785c54629d233924a503cfe81199e22aa0..3910e9b767808962b46501da51945229359e3d1d 100644 GIT binary patch delta 76 zcmeCMYqH~V33dr#l4oFGT(OZ$fQiv{vNV%}h>5q8OFT!sho=jV;{|4Bj`-jZ$H_%Z VN+K%0{-JOQeqpf0=G9EGG61;j69)hQ delta 82 zcmZp&>#*Z;33dtLkY`|ERN2TSz{Kc1S(?c~+}zvAC7vVR!_$Sw@d7im2xok7h$F+2 Y$@xr5;_ANsp>R2VVVK-Ih~wlU WCM6LSU;j|J1ivs?V)JUIL`49;91{-! delta 83 zcmZqk=<(ok33dtLQDI)vJ%pCE-A&!%a Wn3P0ReEmb=68yqoiOs8-Y7_v&S`#q< delta 83 zcmZ4Jw%m=&CD5r@gANoJdPKbnMF9`gF_q{ amQ2oPQW979^$&&1@e9M`HZNtWQ2+p085J%7 diff --git a/tests/data/acpi/q35/DSDT.numamem b/tests/data/acpi/q35/DSDT.numamem index 859a2e08710ba37f56c9c32b0235ff90cedb1905..498c843be1695a0fe1d31d88873b57206d17d758 100644 GIT binary patch delta 77 zcmX?XyVsV>CD5r@gANoJdPKbnK|NvLmVd; XF)4|t`1*&!CHRHG5}Q{uNyq>I^-L3k delta 83 zcmdmMd)SuCCD2ZuN^ aESa3oq$IBH>mLf2;}?d>ZC=VGAp-!9XBB_| diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 6a052c5044..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,18 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/pc/DSDT", -"tests/data/acpi/pc/DSDT.acpihmat", -"tests/data/acpi/pc/DSDT.bridge", -"tests/data/acpi/pc/DSDT.cphp", -"tests/data/acpi/pc/DSDT.dimmpxm", -"tests/data/acpi/pc/DSDT.ipmikcs", -"tests/data/acpi/pc/DSDT.memhp", -"tests/data/acpi/pc/DSDT.numamem", -"tests/data/acpi/q35/DSDT", -"tests/data/acpi/q35/DSDT.acpihmat", -"tests/data/acpi/q35/DSDT.bridge", -"tests/data/acpi/q35/DSDT.cphp", -"tests/data/acpi/q35/DSDT.dimmpxm", -"tests/data/acpi/q35/DSDT.ipmibt", -"tests/data/acpi/q35/DSDT.memhp", -"tests/data/acpi/q35/DSDT.mmio64", -"tests/data/acpi/q35/DSDT.numamem", From 71b0269ae9a80cfd28c3b5946748b92ac8821334 Mon Sep 17 00:00:00 2001 From: Shameer Kolothum Date: Tue, 21 Apr 2020 13:59:28 +0100 Subject: [PATCH 0219/2595] hw/acpi/nvdimm: Fix for NVDIMM incorrect DSM output buffer length As per ACPI spec 6.3, Table 19-419 Object Conversion Rules, if the Buffer Field <= to the size of an Integer (in bits), it will be treated as an integer. Moreover, the integer size depends on DSDT tables revision number. If revision number is < 2, integer size is 32 bits, otherwise it is 64 bits. Current NVDIMM common DSM aml code (NCAL) uses CreateField() for creating DSM output buffer. This creates an issue in arm/virt platform where DSDT revision number is 2 and results in DSM buffer with a wrong size(8 bytes) gets returned when actual length is < 8 bytes. This causes guest kernel to report, "nfit ACPI0012:00: found a zero length table '0' parsing nfit" In order to fix this, aml code is now modified such that it builds the DSM output buffer in a byte by byte fashion when length is smaller than Integer size. Suggested-by: Igor Mammedov Signed-off-by: Shameer Kolothum Reviewed-by: Igor Mammedov Message-Id: <20200421125934.14952-2-shameerali.kolothum.thodi@huawei.com> Acked-by: Peter Maydell Tested-by: Eric Auger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/nvdimm.c | 40 +++++++++++++++++++-- tests/qtest/bios-tables-test-allowed-diff.h | 2 ++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index eb6a37b14e..df0790719a 100644 --- a/hw/acpi/nvdimm.c +++ b/hw/acpi/nvdimm.c @@ -938,6 +938,7 @@ static void nvdimm_build_common_dsm(Aml *dev) Aml *method, *ifctx, *function, *handle, *uuid, *dsm_mem, *elsectx2; Aml *elsectx, *unsupport, *unpatched, *expected_uuid, *uuid_invalid; Aml *pckg, *pckg_index, *pckg_buf, *field, *dsm_out_buf, *dsm_out_buf_size; + Aml *whilectx, *offset; uint8_t byte_list[1]; method = aml_method(NVDIMM_COMMON_DSM, 5, AML_SERIALIZED); @@ -1091,13 +1092,46 @@ static void nvdimm_build_common_dsm(Aml *dev) /* RLEN is not included in the payload returned to guest. */ aml_append(method, aml_subtract(aml_name(NVDIMM_DSM_OUT_BUF_SIZE), aml_int(4), dsm_out_buf_size)); + + /* + * As per ACPI spec 6.3, Table 19-419 Object Conversion Rules, if + * the Buffer Field <= to the size of an Integer (in bits), it will + * be treated as an integer. Moreover, the integer size depends on + * DSDT tables revision number. If revision number is < 2, integer + * size is 32 bits, otherwise it is 64 bits. + * Because of this CreateField() canot be used if RLEN < Integer Size. + * + * Also please note that APCI ASL operator SizeOf() doesn't support + * Integer and there isn't any other way to figure out the Integer + * size. Hence we assume 8 byte as Integer size and if RLEN < 8 bytes, + * build dsm_out_buf byte by byte. + */ + ifctx = aml_if(aml_lless(dsm_out_buf_size, aml_int(8))); + offset = aml_local(2); + aml_append(ifctx, aml_store(aml_int(0), offset)); + aml_append(ifctx, aml_name_decl("TBUF", aml_buffer(1, NULL))); + aml_append(ifctx, aml_store(aml_buffer(0, NULL), dsm_out_buf)); + + whilectx = aml_while(aml_lless(offset, dsm_out_buf_size)); + /* Copy 1 byte at offset from ODAT to temporary buffer(TBUF). */ + aml_append(whilectx, aml_store(aml_derefof(aml_index( + aml_name(NVDIMM_DSM_OUT_BUF), offset)), + aml_index(aml_name("TBUF"), aml_int(0)))); + aml_append(whilectx, aml_concatenate(dsm_out_buf, aml_name("TBUF"), + dsm_out_buf)); + aml_append(whilectx, aml_increment(offset)); + aml_append(ifctx, whilectx); + + aml_append(ifctx, aml_return(dsm_out_buf)); + aml_append(method, ifctx); + + /* If RLEN >= Integer size, just use CreateField() operator */ aml_append(method, aml_store(aml_shiftleft(dsm_out_buf_size, aml_int(3)), dsm_out_buf_size)); aml_append(method, aml_create_field(aml_name(NVDIMM_DSM_OUT_BUF), aml_int(0), dsm_out_buf_size, "OBUF")); - aml_append(method, aml_concatenate(aml_buffer(0, NULL), aml_name("OBUF"), - dsm_out_buf)); - aml_append(method, aml_return(dsm_out_buf)); + aml_append(method, aml_return(aml_name("OBUF"))); + aml_append(dev, method); } diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..eb8bae1407 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,3 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/SSDT.dimmpxm", +"tests/data/acpi/q35/SSDT.dimmpxm", From 5c94b82662a815d8430b81090200178b5377a62e Mon Sep 17 00:00:00 2001 From: Kwangwoo Lee Date: Tue, 21 Apr 2020 13:59:29 +0100 Subject: [PATCH 0220/2595] nvdimm: Use configurable ACPI IO base and size This patch makes IO base and size configurable to create NPIO AML for ACPI NFIT. Since a different architecture like AArch64 does not use port-mapped IO, a configurable IO base is required to create correct mapping of ACPI IO address and size. Signed-off-by: Kwangwoo Lee Signed-off-by: Eric Auger Signed-off-by: Shameer Kolothum Reviewed-by: Igor Mammedov Message-Id: <20200421125934.14952-3-shameerali.kolothum.thodi@huawei.com> Acked-by: Peter Maydell Tested-by: Eric Auger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/nvdimm.c | 32 ++++++++++++++++++++++---------- hw/i386/acpi-build.c | 6 ++++++ hw/i386/acpi-build.h | 3 +++ hw/i386/pc_piix.c | 2 ++ hw/i386/pc_q35.c | 2 ++ include/hw/mem/nvdimm.h | 3 +++ 6 files changed, 38 insertions(+), 10 deletions(-) diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index df0790719a..fa7bf8b507 100644 --- a/hw/acpi/nvdimm.c +++ b/hw/acpi/nvdimm.c @@ -900,11 +900,13 @@ void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev) } void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io, + struct AcpiGenericAddress dsm_io, FWCfgState *fw_cfg, Object *owner) { + state->dsm_io = dsm_io; memory_region_init_io(&state->io_mr, owner, &nvdimm_dsm_ops, state, - "nvdimm-acpi-io", NVDIMM_ACPI_IO_LEN); - memory_region_add_subregion(io, NVDIMM_ACPI_IO_BASE, &state->io_mr); + "nvdimm-acpi-io", dsm_io.bit_width >> 3); + memory_region_add_subregion(io, dsm_io.address, &state->io_mr); state->dsm_mem = g_array_new(false, true /* clear */, 1); acpi_data_push(state->dsm_mem, sizeof(NvdimmDsmIn)); @@ -933,13 +935,15 @@ void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io, #define NVDIMM_QEMU_RSVD_UUID "648B9CF2-CDA1-4312-8AD9-49C4AF32BD62" -static void nvdimm_build_common_dsm(Aml *dev) +static void nvdimm_build_common_dsm(Aml *dev, + NVDIMMState *nvdimm_state) { Aml *method, *ifctx, *function, *handle, *uuid, *dsm_mem, *elsectx2; Aml *elsectx, *unsupport, *unpatched, *expected_uuid, *uuid_invalid; Aml *pckg, *pckg_index, *pckg_buf, *field, *dsm_out_buf, *dsm_out_buf_size; Aml *whilectx, *offset; uint8_t byte_list[1]; + AmlRegionSpace rs; method = aml_method(NVDIMM_COMMON_DSM, 5, AML_SERIALIZED); uuid = aml_arg(0); @@ -950,9 +954,16 @@ static void nvdimm_build_common_dsm(Aml *dev) aml_append(method, aml_store(aml_name(NVDIMM_ACPI_MEM_ADDR), dsm_mem)); + if (nvdimm_state->dsm_io.space_id == AML_AS_SYSTEM_IO) { + rs = AML_SYSTEM_IO; + } else { + rs = AML_SYSTEM_MEMORY; + } + /* map DSM memory and IO into ACPI namespace. */ - aml_append(method, aml_operation_region(NVDIMM_DSM_IOPORT, AML_SYSTEM_IO, - aml_int(NVDIMM_ACPI_IO_BASE), NVDIMM_ACPI_IO_LEN)); + aml_append(method, aml_operation_region(NVDIMM_DSM_IOPORT, rs, + aml_int(nvdimm_state->dsm_io.address), + nvdimm_state->dsm_io.bit_width >> 3)); aml_append(method, aml_operation_region(NVDIMM_DSM_MEMORY, AML_SYSTEM_MEMORY, dsm_mem, sizeof(NvdimmDsmIn))); @@ -967,7 +978,7 @@ static void nvdimm_build_common_dsm(Aml *dev) field = aml_field(NVDIMM_DSM_IOPORT, AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE); aml_append(field, aml_named_field(NVDIMM_DSM_NOTIFY, - NVDIMM_ACPI_IO_LEN * BITS_PER_BYTE)); + nvdimm_state->dsm_io.bit_width)); aml_append(method, field); /* @@ -1268,7 +1279,8 @@ static void nvdimm_build_nvdimm_devices(Aml *root_dev, uint32_t ram_slots) } static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data, - BIOSLinker *linker, GArray *dsm_dma_area, + BIOSLinker *linker, + NVDIMMState *nvdimm_state, uint32_t ram_slots) { Aml *ssdt, *sb_scope, *dev; @@ -1296,7 +1308,7 @@ static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data, */ aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0012"))); - nvdimm_build_common_dsm(dev); + nvdimm_build_common_dsm(dev, nvdimm_state); /* 0 is reserved for root device. */ nvdimm_build_device_dsm(dev, 0); @@ -1315,7 +1327,7 @@ static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data, NVDIMM_ACPI_MEM_ADDR); bios_linker_loader_alloc(linker, - NVDIMM_DSM_MEM_FILE, dsm_dma_area, + NVDIMM_DSM_MEM_FILE, nvdimm_state->dsm_mem, sizeof(NvdimmDsmIn), false /* high memory */); bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, mem_addr_offset, sizeof(uint32_t), @@ -1337,7 +1349,7 @@ void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data, return; } - nvdimm_build_ssdt(table_offsets, table_data, linker, state->dsm_mem, + nvdimm_build_ssdt(table_offsets, table_data, linker, state, ram_slots); device_list = nvdimm_get_device_list(); diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 97f3c75cd9..7d880bec4a 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -128,6 +128,12 @@ typedef struct FwCfgTPMConfig { static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg); +const struct AcpiGenericAddress x86_nvdimm_acpi_dsmio = { + .space_id = AML_AS_SYSTEM_IO, + .address = NVDIMM_ACPI_IO_BASE, + .bit_width = NVDIMM_ACPI_IO_LEN << 3 +}; + static void init_common_fadt_data(MachineState *ms, Object *o, AcpiFadtData *data) { diff --git a/hw/i386/acpi-build.h b/hw/i386/acpi-build.h index 007332e51c..74df5fc612 100644 --- a/hw/i386/acpi-build.h +++ b/hw/i386/acpi-build.h @@ -1,6 +1,9 @@ #ifndef HW_I386_ACPI_BUILD_H #define HW_I386_ACPI_BUILD_H +#include "hw/acpi/acpi-defs.h" + +extern const struct AcpiGenericAddress x86_nvdimm_acpi_dsmio; void acpi_setup(void); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 22dee0e76c..b75087d71b 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -61,6 +61,7 @@ #include "migration/misc.h" #include "sysemu/numa.h" #include "hw/mem/nvdimm.h" +#include "hw/i386/acpi-build.h" #define MAX_IDE_BUS 2 @@ -297,6 +298,7 @@ static void pc_init1(MachineState *machine, if (machine->nvdimms_state->is_enabled) { nvdimm_init_acpi_state(machine->nvdimms_state, system_io, + x86_nvdimm_acpi_dsmio, x86ms->fw_cfg, OBJECT(pcms)); } } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index d37c425e22..d2806c1b29 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -54,6 +54,7 @@ #include "qemu/error-report.h" #include "sysemu/numa.h" #include "hw/mem/nvdimm.h" +#include "hw/i386/acpi-build.h" /* ICH9 AHCI has 6 ports */ #define MAX_SATA_PORTS 6 @@ -315,6 +316,7 @@ static void pc_q35_init(MachineState *machine) if (machine->nvdimms_state->is_enabled) { nvdimm_init_acpi_state(machine->nvdimms_state, system_io, + x86_nvdimm_acpi_dsmio, x86ms->fw_cfg, OBJECT(pcms)); } } diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h index 4807ca615b..a3c08955e8 100644 --- a/include/hw/mem/nvdimm.h +++ b/include/hw/mem/nvdimm.h @@ -26,6 +26,7 @@ #include "hw/mem/pc-dimm.h" #include "hw/acpi/bios-linker-loader.h" #include "qemu/uuid.h" +#include "hw/acpi/aml-build.h" #define NVDIMM_DEBUG 0 #define nvdimm_debug(fmt, ...) \ @@ -147,10 +148,12 @@ struct NVDIMMState { */ int32_t persistence; char *persistence_string; + struct AcpiGenericAddress dsm_io; }; typedef struct NVDIMMState NVDIMMState; void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io, + struct AcpiGenericAddress dsm_io, FWCfgState *fw_cfg, Object *owner); void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data, BIOSLinker *linker, NVDIMMState *state, From b5a60bee7425ec2ce9b1aa0577585e8328c1b768 Mon Sep 17 00:00:00 2001 From: Kwangwoo Lee Date: Tue, 21 Apr 2020 13:59:30 +0100 Subject: [PATCH 0221/2595] hw/arm/virt: Add nvdimm hot-plug infrastructure This adds support to init nvdimm acpi state and build nvdimm acpi tables. Please note nvdimm_support is not yet enabled. Signed-off-by: Kwangwoo Lee Signed-off-by: Eric Auger Signed-off-by: Shameer Kolothum Reviewed-by: Igor Mammedov Message-Id: <20200421125934.14952-4-shameerali.kolothum.thodi@huawei.com> Acked-by: Peter Maydell Tested-by: Eric Auger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/Kconfig | 1 + hw/arm/virt-acpi-build.c | 6 ++++++ hw/arm/virt.c | 19 +++++++++++++++++++ hw/mem/Kconfig | 2 +- include/hw/arm/virt.h | 1 + 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 188419dc1e..5364172537 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -25,6 +25,7 @@ config ARM_VIRT select DIMM select ACPI_MEMORY_HOTPLUG select ACPI_HW_REDUCED + select ACPI_NVDIMM config CHEETAH bool diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 81d41a3990..f22b1e6097 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -44,6 +44,7 @@ #include "hw/pci/pcie_host.h" #include "hw/pci/pci.h" #include "hw/arm/virt.h" +#include "hw/mem/nvdimm.h" #include "sysemu/numa.h" #include "sysemu/reset.h" #include "kvm_arm.h" @@ -826,6 +827,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) } } + if (ms->nvdimms_state->is_enabled) { + nvdimm_build_acpi(table_offsets, tables_blob, tables->linker, + ms->nvdimms_state, ms->ram_slots); + } + if (its_class_name() && !vmc->no_its) { acpi_add_table(table_offsets, tables_blob); build_iort(tables_blob, tables->linker, vms); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 626822554d..87f29953c4 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -150,6 +150,7 @@ static const MemMapEntry base_memmap[] = { [VIRT_SMMU] = { 0x09050000, 0x00020000 }, [VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN }, [VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN }, + [VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN}, [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, @@ -1884,6 +1885,18 @@ static void machvirt_init(MachineState *machine) create_platform_bus(vms); + if (machine->nvdimms_state->is_enabled) { + const struct AcpiGenericAddress arm_virt_nvdimm_acpi_dsmio = { + .space_id = AML_AS_SYSTEM_MEMORY, + .address = vms->memmap[VIRT_NVDIMM_ACPI].base, + .bit_width = NVDIMM_ACPI_IO_LEN << 3 + }; + + nvdimm_init_acpi_state(machine->nvdimms_state, sysmem, + arm_virt_nvdimm_acpi_dsmio, + vms->fw_cfg, OBJECT(vms)); + } + vms->bootinfo.ram_size = machine->ram_size; vms->bootinfo.nb_cpus = smp_cpus; vms->bootinfo.board_id = -1; @@ -2095,6 +2108,8 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + MachineState *ms = MACHINE(hotplug_dev); + bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM); Error *local_err = NULL; pc_dimm_plug(PC_DIMM(dev), MACHINE(vms), &local_err); @@ -2102,6 +2117,10 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev, goto out; } + if (is_nvdimm) { + nvdimm_plug(ms->nvdimms_state); + } + hotplug_handler_plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &error_abort); diff --git a/hw/mem/Kconfig b/hw/mem/Kconfig index 2ad052a536..c27844900d 100644 --- a/hw/mem/Kconfig +++ b/hw/mem/Kconfig @@ -8,4 +8,4 @@ config MEM_DEVICE config NVDIMM bool default y - depends on (PC || PSERIES) + depends on (PC || PSERIES || ARM_VIRT) diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 60b2f521eb..6d67ace76e 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -79,6 +79,7 @@ enum { VIRT_SECURE_MEM, VIRT_PCDIMM_ACPI, VIRT_ACPI_GED, + VIRT_NVDIMM_ACPI, VIRT_LOWMEMMAP_LAST, }; From c2505d1c56fc4959974985f57f100d90bc82f0ee Mon Sep 17 00:00:00 2001 From: Shameer Kolothum Date: Tue, 21 Apr 2020 13:59:31 +0100 Subject: [PATCH 0222/2595] hw/arm/virt: Add nvdimm hotplug support This adds support for nvdimm hotplug events through GED and enables nvdimm for the arm/virt. Now Guests with ACPI can have both cold and hot plug of nvdimms. Hot removal functionality is not yet supported. Signed-off-by: Shameer Kolothum Reviewed-by: Igor Mammedov Reviewed-by: Eric Auger Message-Id: <20200421125934.14952-5-shameerali.kolothum.thodi@huawei.com> Acked-by: Peter Maydell Tested-by: Eric Auger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/specs/acpi_hw_reduced_hotplug.rst | 3 ++- hw/acpi/generic_event_device.c | 15 ++++++++++++++- hw/arm/virt.c | 16 +++++++++++----- include/hw/acpi/generic_event_device.h | 1 + 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst index 911a98255b..0bd3f9399f 100644 --- a/docs/specs/acpi_hw_reduced_hotplug.rst +++ b/docs/specs/acpi_hw_reduced_hotplug.rst @@ -63,7 +63,8 @@ GED IO interface (4 byte access) bits: 0: Memory hotplug event 1: System power down event - 2-31: Reserved + 2: NVDIMM hotplug event + 3-31: Reserved **write_access:** diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index 021ed2bf23..5d17f78a1e 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -16,6 +16,7 @@ #include "hw/acpi/generic_event_device.h" #include "hw/irq.h" #include "hw/mem/pc-dimm.h" +#include "hw/mem/nvdimm.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qemu/error-report.h" @@ -23,6 +24,7 @@ static const uint32_t ged_supported_events[] = { ACPI_GED_MEM_HOTPLUG_EVT, ACPI_GED_PWR_DOWN_EVT, + ACPI_GED_NVDIMM_HOTPLUG_EVT, }; /* @@ -110,6 +112,11 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), aml_int(0x80))); break; + case ACPI_GED_NVDIMM_HOTPLUG_EVT: + aml_append(if_ctx, + aml_notify(aml_name("\\_SB.NVDR"), + aml_int(0x80))); + break; default: /* * Please make sure all the events in ged_supported_events[] @@ -175,7 +182,11 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, AcpiGedState *s = ACPI_GED(hotplug_dev); if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp); + if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { + nvdimm_acpi_plug_cb(hotplug_dev, dev); + } else { + acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp); + } } else { error_setg(errp, "virt: device plug request for unsupported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -192,6 +203,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) sel = ACPI_GED_MEM_HOTPLUG_EVT; } else if (ev & ACPI_POWER_DOWN_STATUS) { sel = ACPI_GED_PWR_DOWN_EVT; + } else if (ev & ACPI_NVDIMM_HOTPLUG_STATUS) { + sel = ACPI_GED_NVDIMM_HOTPLUG_EVT; } else { /* Unknown event. Return without generating interrupt. */ warn_report("GED: Unsupported event %d. No irq injected", ev); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 87f29953c4..171e6908ec 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -568,6 +568,10 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) event |= ACPI_GED_MEM_HOTPLUG_EVT; } + if (ms->nvdimms_state->is_enabled) { + event |= ACPI_GED_NVDIMM_HOTPLUG_EVT; + } + dev = qdev_create(NULL, TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", event); @@ -2088,19 +2092,20 @@ static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + const MachineState *ms = MACHINE(hotplug_dev); const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM); - if (is_nvdimm) { - error_setg(errp, "nvdimm is not yet supported"); - return; - } - if (!vms->acpi_dev) { error_setg(errp, "memory hotplug is not enabled: missing acpi-ged device"); return; } + if (is_nvdimm && !ms->nvdimms_state->is_enabled) { + error_setg(errp, "nvdimm is not enabled: add 'nvdimm=on' to '-M'"); + return; + } + pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), NULL, errp); } @@ -2245,6 +2250,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) hc->plug = virt_machine_device_plug_cb; hc->unplug_request = virt_machine_device_unplug_request_cb; mc->numa_mem_supported = true; + mc->nvdimm_supported = true; mc->auto_enable_numa_with_memhp = true; mc->default_ram_id = "mach-virt.ram"; diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h index d157eac088..9eb86ca4fd 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h @@ -82,6 +82,7 @@ */ #define ACPI_GED_MEM_HOTPLUG_EVT 0x1 #define ACPI_GED_PWR_DOWN_EVT 0x2 +#define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4 typedef struct GEDState { MemoryRegion io; From 122752d267cb43ee29b5f0acac1057198797c45c Mon Sep 17 00:00:00 2001 From: Shameer Kolothum Date: Tue, 21 Apr 2020 13:59:32 +0100 Subject: [PATCH 0223/2595] tests: Update ACPI tables list for upcoming arm/virt test changes This is in preparation to update test_acpi_virt_tcg_memhp() with pc-dimm and nvdimm. Update the bios-tables-test-allowed-diff.h with the affected ACPI tables so that "make check" doesn't fail. Also add empty files for new tables required for new test. Signed-off-by: Shameer Kolothum Message-Id: <20200421125934.14952-6-shameerali.kolothum.thodi@huawei.com> Acked-by: Peter Maydell Tested-by: Eric Auger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/virt/NFIT.memhp | 0 tests/data/acpi/virt/SSDT.memhp | 0 tests/qtest/bios-tables-test-allowed-diff.h | 3 +++ 3 files changed, 3 insertions(+) create mode 100644 tests/data/acpi/virt/NFIT.memhp create mode 100644 tests/data/acpi/virt/SSDT.memhp diff --git a/tests/data/acpi/virt/NFIT.memhp b/tests/data/acpi/virt/NFIT.memhp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/virt/SSDT.memhp b/tests/data/acpi/virt/SSDT.memhp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index eb8bae1407..862c49e675 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,3 +1,6 @@ /* List of comma-separated changed AML files to ignore */ "tests/data/acpi/pc/SSDT.dimmpxm", "tests/data/acpi/q35/SSDT.dimmpxm", +"tests/data/acpi/virt/DSDT.memhp", +"tests/data/acpi/virt/SSDT.memhp", +"tests/data/acpi/virt/NFIT.memhp", From 62293b4f58276d9f0a25ec35f4bc2e97540ba98f Mon Sep 17 00:00:00 2001 From: Shameer Kolothum Date: Tue, 21 Apr 2020 13:59:33 +0100 Subject: [PATCH 0224/2595] bios-tables-test: test pc-dimm and nvdimm coldplug for arm/virt Since we now have both pc-dimm and nvdimm support, update test_acpi_virt_tcg_memhp() to include those. Signed-off-by: Shameer Kolothum Message-Id: <20200421125934.14952-7-shameerali.kolothum.thodi@huawei.com> Acked-by: Peter Maydell Tested-by: Eric Auger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 0a597bbacf..c9843829b3 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -927,12 +927,17 @@ static void test_acpi_virt_tcg_memhp(void) }; data.variant = ".memhp"; - test_acpi_one(" -cpu cortex-a57" + test_acpi_one(" -machine nvdimm=on" + " -cpu cortex-a57" " -m 256M,slots=3,maxmem=1G" " -object memory-backend-ram,id=ram0,size=128M" " -object memory-backend-ram,id=ram1,size=128M" " -numa node,memdev=ram0 -numa node,memdev=ram1" - " -numa dist,src=0,dst=1,val=21", + " -numa dist,src=0,dst=1,val=21" + " -object memory-backend-ram,id=ram2,size=128M" + " -object memory-backend-ram,id=nvm0,size=128M" + " -device pc-dimm,id=dimm0,memdev=ram2,node=0" + " -device nvdimm,id=dimm1,memdev=nvm0,node=1", &data); free_test_data(&data); From e302bb3da6b59ad22c2157bbaac299a301780ba1 Mon Sep 17 00:00:00 2001 From: Shameer Kolothum Date: Tue, 21 Apr 2020 13:59:34 +0100 Subject: [PATCH 0225/2595] tests/acpi: add expected tables for bios-tables-test Because of the following changes, the expeacted tables for bios-tables-test needs to be updated. 1. Changed NVDIM DSM output buffer AML code. 2. Updated arm/virt test_acpi_virt_tcg_memhp() to add pc-dimm/nvdimm Signed-off-by: Shameer Kolothum Message-Id: <20200421125934.14952-8-shameerali.kolothum.thodi@huawei.com> Acked-by: Peter Maydell Tested-by: Eric Auger Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/pc/SSDT.dimmpxm | Bin 685 -> 734 bytes tests/data/acpi/q35/SSDT.dimmpxm | Bin 685 -> 734 bytes tests/data/acpi/virt/DSDT.memhp | Bin 6644 -> 6668 bytes tests/data/acpi/virt/NFIT.memhp | Bin 0 -> 224 bytes tests/data/acpi/virt/SSDT.memhp | Bin 0 -> 736 bytes tests/qtest/bios-tables-test-allowed-diff.h | 5 ----- 6 files changed, 5 deletions(-) diff --git a/tests/data/acpi/pc/SSDT.dimmpxm b/tests/data/acpi/pc/SSDT.dimmpxm index 8ba0e67cb72daa81a65da4906d37a5e0f4af1fd4..ac55387d57e48adb99eb738a102308688a262fb8 100644 GIT binary patch delta 125 zcmZ3>dXJSWIM^lR9uortW7tG4X>Nb5nD}6)_~<4#t%(LAOunKU-FO)N7nn^=sUGbBa} TgA_0%`UAz6fQZcnjJAvbW$GgJ delta 76 zcmcb|x|WqIIM^j*EfWI+W57f%X>LFDnD}6)_~<5A^@#=|Og=&z-FO(~3Mv!1m>CkI dh5cO|Ll_eMokHD;1(_H?bo!F?%?lZA83Fei6ZHT9 diff --git a/tests/data/acpi/q35/SSDT.dimmpxm b/tests/data/acpi/q35/SSDT.dimmpxm index 2d5b721bcf9c398feb6d005761f898015042e8a4..98e6f0e3f3bb02dd419e36bdd1db9b94c728c406 100644 GIT binary patch delta 125 zcmZ3>dXJSWIM^lR9uortquWF-X>Nb5nD}6)_~<4#t%(LAOunKU-FO)N7nn^=sUGbBa} TgA_0%`UAz6fQZcnjJAvbUiu>C delta 76 zcmcb|x|WqIIM^j*EfWI+qr*flX>LFDnD}6)_~<5A^@#=|Og=&z-FO(~3Mv!1m>CkI dh5cO|Ll_eMokHD;1(_H?bo!F?%?lZA83FS;6XgH^ diff --git a/tests/data/acpi/virt/DSDT.memhp b/tests/data/acpi/virt/DSDT.memhp index c527ac4739af3df3c3e042bf91c412033a2b73c3..730e95a46d2cce0af011ffc051d7342beb8f1328 100644 GIT binary patch delta 66 zcmexj++)J!66_MfBgMeL^l>7WG*kP$jq2jB1F=Cg1XwVzFffCeAhF8JAJRT=DREfi z%xf&Mz2`Pir~{&ofdfQyG(dQa3da8 literal 0 HcmV?d00001 diff --git a/tests/data/acpi/virt/SSDT.memhp b/tests/data/acpi/virt/SSDT.memhp index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..db61d6733284c90153e0e2c1d6c2ac25c22b1d84 100644 GIT binary patch literal 736 zcmZWnJ&4m_7=F{1Ynryuv=ve6ky!_O6-025G-+(0NlTIzAqUNmw7s^&hj$JlLfadz zo*?wXEh3U083lL2&DF`tL2x*5cM%-K?@e*=T;7-Od*1JPpXcE-P1*XE0AOy_+fvgM z^q#D08a)F*{Xs{_tQJ#O0FU+9ezSw@vROEagI9HnmiQA&>UP6JQO~5}~Z64Mnvw zY+ErcAR}x9XE39S5im?~i@}LFCFj@yO3@`)kSxrd1o2Hog_0x3J#f(n8@M!%1lT2q z6Jm8#juK%h-|N%mEE@9&_-9pypc>!7*C8JuYZjQl__`2oA({8ccl~|O@$5xK?^Ua8 nUz82zqC>`BY*Tb6M!7_p|2F_GvB7H_Joz7 Date: Wed, 25 Mar 2020 06:35:06 -0400 Subject: [PATCH 0226/2595] Refactor vhost_user_set_mem_table functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vhost_user_set_mem_table() and vhost_user_set_mem_table_postcopy() have gotten convoluted, and have some identical code. This change moves the logic populating the VhostUserMemory struct and fds array from vhost_user_set_mem_table() and vhost_user_set_mem_table_postcopy() to a new function, vhost_user_fill_set_mem_table_msg(). No functionality is impacted. Signed-off-by: Raphael Norwitz Signed-off-by: Peter Turschmid Message-Id: <1585132506-13316-1-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 143 +++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 76 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 08e7e63790..ec21e8fbe8 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -407,18 +407,79 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, return 0; } +static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, + struct vhost_dev *dev, + VhostUserMsg *msg, + int *fds, size_t *fd_num, + bool track_ramblocks) +{ + int i, fd; + ram_addr_t offset; + MemoryRegion *mr; + struct vhost_memory_region *reg; + + msg->hdr.request = VHOST_USER_SET_MEM_TABLE; + + for (i = 0; i < dev->mem->nregions; ++i) { + reg = dev->mem->regions + i; + + assert((uintptr_t)reg->userspace_addr == reg->userspace_addr); + mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr, + &offset); + fd = memory_region_get_fd(mr); + if (fd > 0) { + if (track_ramblocks) { + assert(*fd_num < VHOST_MEMORY_MAX_NREGIONS); + trace_vhost_user_set_mem_table_withfd(*fd_num, mr->name, + reg->memory_size, + reg->guest_phys_addr, + reg->userspace_addr, + offset); + u->region_rb_offset[i] = offset; + u->region_rb[i] = mr->ram_block; + } else if (*fd_num == VHOST_MEMORY_MAX_NREGIONS) { + error_report("Failed preparing vhost-user memory table msg"); + return -1; + } + msg->payload.memory.regions[*fd_num].userspace_addr = + reg->userspace_addr; + msg->payload.memory.regions[*fd_num].memory_size = + reg->memory_size; + msg->payload.memory.regions[*fd_num].guest_phys_addr = + reg->guest_phys_addr; + msg->payload.memory.regions[*fd_num].mmap_offset = offset; + fds[(*fd_num)++] = fd; + } else if (track_ramblocks) { + u->region_rb_offset[i] = 0; + u->region_rb[i] = NULL; + } + } + + msg->payload.memory.nregions = *fd_num; + + if (!*fd_num) { + error_report("Failed initializing vhost-user memory map, " + "consider using -object memory-backend-file share=on"); + return -1; + } + + msg->hdr.size = sizeof(msg->payload.memory.nregions); + msg->hdr.size += sizeof(msg->payload.memory.padding); + msg->hdr.size += *fd_num * sizeof(VhostUserMemoryRegion); + + return 1; +} + static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, struct vhost_memory *mem) { struct vhost_user *u = dev->opaque; int fds[VHOST_MEMORY_MAX_NREGIONS]; - int i, fd; size_t fd_num = 0; VhostUserMsg msg_reply; int region_i, msg_i; VhostUserMsg msg = { - .hdr.request = VHOST_USER_SET_MEM_TABLE, .hdr.flags = VHOST_USER_VERSION, }; @@ -433,48 +494,11 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, u->region_rb_len = dev->mem->nregions; } - for (i = 0; i < dev->mem->nregions; ++i) { - struct vhost_memory_region *reg = dev->mem->regions + i; - ram_addr_t offset; - MemoryRegion *mr; - - assert((uintptr_t)reg->userspace_addr == reg->userspace_addr); - mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr, - &offset); - fd = memory_region_get_fd(mr); - if (fd > 0) { - assert(fd_num < VHOST_MEMORY_MAX_NREGIONS); - trace_vhost_user_set_mem_table_withfd(fd_num, mr->name, - reg->memory_size, - reg->guest_phys_addr, - reg->userspace_addr, offset); - u->region_rb_offset[i] = offset; - u->region_rb[i] = mr->ram_block; - msg.payload.memory.regions[fd_num].userspace_addr = - reg->userspace_addr; - msg.payload.memory.regions[fd_num].memory_size = reg->memory_size; - msg.payload.memory.regions[fd_num].guest_phys_addr = - reg->guest_phys_addr; - msg.payload.memory.regions[fd_num].mmap_offset = offset; - fds[fd_num++] = fd; - } else { - u->region_rb_offset[i] = 0; - u->region_rb[i] = NULL; - } - } - - msg.payload.memory.nregions = fd_num; - - if (!fd_num) { - error_report("Failed initializing vhost-user memory map, " - "consider using -object memory-backend-file share=on"); + if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, + true) < 0) { return -1; } - msg.hdr.size = sizeof(msg.payload.memory.nregions); - msg.hdr.size += sizeof(msg.payload.memory.padding); - msg.hdr.size += fd_num * sizeof(VhostUserMemoryRegion); - if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { return -1; } @@ -545,7 +569,6 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, { struct vhost_user *u = dev->opaque; int fds[VHOST_MEMORY_MAX_NREGIONS]; - int i, fd; size_t fd_num = 0; bool do_postcopy = u->postcopy_listen && u->postcopy_fd.handler; bool reply_supported = virtio_has_feature(dev->protocol_features, @@ -559,7 +582,6 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, } VhostUserMsg msg = { - .hdr.request = VHOST_USER_SET_MEM_TABLE, .hdr.flags = VHOST_USER_VERSION, }; @@ -567,42 +589,11 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; } - for (i = 0; i < dev->mem->nregions; ++i) { - struct vhost_memory_region *reg = dev->mem->regions + i; - ram_addr_t offset; - MemoryRegion *mr; - - assert((uintptr_t)reg->userspace_addr == reg->userspace_addr); - mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr, - &offset); - fd = memory_region_get_fd(mr); - if (fd > 0) { - if (fd_num == VHOST_MEMORY_MAX_NREGIONS) { - error_report("Failed preparing vhost-user memory table msg"); - return -1; - } - msg.payload.memory.regions[fd_num].userspace_addr = - reg->userspace_addr; - msg.payload.memory.regions[fd_num].memory_size = reg->memory_size; - msg.payload.memory.regions[fd_num].guest_phys_addr = - reg->guest_phys_addr; - msg.payload.memory.regions[fd_num].mmap_offset = offset; - fds[fd_num++] = fd; - } - } - - msg.payload.memory.nregions = fd_num; - - if (!fd_num) { - error_report("Failed initializing vhost-user memory map, " - "consider using -object memory-backend-file share=on"); + if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, + false) < 0) { return -1; } - msg.hdr.size = sizeof(msg.payload.memory.nregions); - msg.hdr.size += sizeof(msg.payload.memory.padding); - msg.hdr.size += fd_num * sizeof(VhostUserMemoryRegion); - if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { return -1; } From 4b773fc2f7e56cddc9c192e0c95b3097dbbcf1e9 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Fri, 13 Mar 2020 16:50:07 +0200 Subject: [PATCH 0227/2595] acpi: unit-test: Ignore diff in WAET ACPI table This is done as a preparation for the following patch to expose WAET ACPI table to guest. This patch performs steps 1-3 as describes in tests/qtest/bios-tables-test.c. Signed-off-by: Liran Alon Message-Id: <20200313145009.144820-2-liran.alon@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/pc/WAET | 0 tests/data/acpi/q35/WAET | 0 tests/qtest/bios-tables-test-allowed-diff.h | 2 ++ 3 files changed, 2 insertions(+) create mode 100644 tests/data/acpi/pc/WAET create mode 100644 tests/data/acpi/q35/WAET diff --git a/tests/data/acpi/pc/WAET b/tests/data/acpi/pc/WAET new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/q35/WAET b/tests/data/acpi/q35/WAET new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..b269a1e3e5 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,3 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/WAET", +"tests/data/acpi/q35/WAET", From 14cda3503dc00754bab9ce6c688ea21f791c4a33 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Fri, 13 Mar 2020 16:50:08 +0200 Subject: [PATCH 0228/2595] acpi: Add Windows ACPI Emulated Device Table (WAET) Microsoft introduced this ACPI table to avoid Windows guests performing various workarounds for device erratas. As the virtual device emulated by VMM may not have the errata. Currently, WAET allows hypervisor to inform guest about two specific behaviors: One for RTC and the other for ACPI PM timer. Support for WAET have been introduced since Windows Vista. This ACPI table is also exposed by other common hypervisors by default, including: VMware, GCP and AWS. This patch adds WAET ACPI Table to QEMU. We set "ACPI PM timer good" bit in "Emualted Device Flags" field to indicate that the ACPI PM timer has been enhanced to not require multiple reads to obtain a reliable value. This results in improving the performance of Windows guests that use ACPI PM timer by avoiding unnecessary VMExits caused by these multiple reads. Co-developed-by: Elad Gabay Signed-off-by: Liran Alon Message-Id: <20200313145009.144820-3-liran.alon@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Igor Mammedov --- hw/i386/acpi-build.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 7d880bec4a..2e15f6848e 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2512,6 +2512,34 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker) build_header(linker, table_data, (void *)(table_data->data + dmar_start), "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } + +/* + * Windows ACPI Emulated Devices Table + * (Version 1.0 - April 6, 2009) + * Spec: http://download.microsoft.com/download/7/E/7/7E7662CF-CBEA-470B-A97E-CE7CE0D98DC2/WAET.docx + * + * Helpful to speedup Windows guests and ignored by others. + */ +static void +build_waet(GArray *table_data, BIOSLinker *linker) +{ + int waet_start = table_data->len; + + /* WAET header */ + acpi_data_push(table_data, sizeof(AcpiTableHeader)); + /* + * Set "ACPI PM timer good" flag. + * + * Tells Windows guests that our ACPI PM timer is reliable in the + * sense that guest can read it only once to obtain a reliable value. + * Which avoids costly VMExits caused by guest re-reading it unnecessarily. + */ + build_append_int_noprefix(table_data, 1 << 1 /* ACPI PM timer good */, 4); + + build_header(linker, table_data, (void *)(table_data->data + waet_start), + "WAET", table_data->len - waet_start, 1, NULL, NULL); +} + /* * IVRS table as specified in AMD IOMMU Specification v2.62, Section 5.2 * accessible here http://support.amd.com/TechDocs/48882_IOMMU.pdf @@ -2859,6 +2887,9 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) machine->nvdimms_state, machine->ram_slots); } + acpi_add_table(table_offsets, tables_blob); + build_waet(tables_blob, tables->linker); + /* Add tables supplied by user (if any) */ for (u = acpi_table_first(); u; u = acpi_table_next(u)) { unsigned len = acpi_table_len(u); From 1aaef7d809280388e4e0b73cd21f5aa0a6443b75 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Fri, 13 Mar 2020 16:50:09 +0200 Subject: [PATCH 0229/2595] acpi: unit-test: Update WAET ACPI Table expected binaries This is done according to step (6) in the process described at tests/qtest/bios-tables-test.c. Expected WAET.dsl: [000h 0000 4] Signature : "WAET" [Windows ACPI Emulated Devices Table] [004h 0004 4] Table Length : 00000028 [008h 0008 1] Revision : 01 [009h 0009 1] Checksum : 88 [00Ah 0010 6] Oem ID : "BOCHS " [010h 0016 8] Oem Table ID : "BXPCWAET" [018h 0024 4] Oem Revision : 00000001 [01Ch 0028 4] Asl Compiler ID : "BXPC" [020h 0032 4] Asl Compiler Revision : 00000001 [024h 0036 4] Flags (decoded below) : 00000002 RTC needs no INT ack : 0 PM timer, one read only : 1 Raw Table Data: Length 40 (0x28) 0000: 57 41 45 54 28 00 00 00 01 88 42 4F 43 48 53 20 // WAET(.....BOCHS 0010: 42 58 50 43 57 41 45 54 01 00 00 00 42 58 50 43 // BXPCWAET....BXPC 0020: 01 00 00 00 02 00 00 00 // ........ Signed-off-by: Liran Alon Message-Id: <20200313145009.144820-4-liran.alon@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/pc/WAET | Bin 0 -> 40 bytes tests/data/acpi/q35/WAET | Bin 0 -> 40 bytes tests/qtest/bios-tables-test-allowed-diff.h | 2 -- 3 files changed, 2 deletions(-) diff --git a/tests/data/acpi/pc/WAET b/tests/data/acpi/pc/WAET index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c2240f58dff6b2f765386b5a2e506fda4800be3e 100644 GIT binary patch literal 40 mcmWG{bPds9U|?YEaPoKd2v%^42yhMuiZKGkKx`1r1jGQWX$JuS literal 0 HcmV?d00001 diff --git a/tests/data/acpi/q35/WAET b/tests/data/acpi/q35/WAET index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c2240f58dff6b2f765386b5a2e506fda4800be3e 100644 GIT binary patch literal 40 mcmWG{bPds9U|?YEaPoKd2v%^42yhMuiZKGkKx`1r1jGQWX$JuS literal 0 HcmV?d00001 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index b269a1e3e5..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,3 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/pc/WAET", -"tests/data/acpi/q35/WAET", From b4fa79eab5eeaaa6fbebeb03723b9b70dd4563c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 10:33:39 +0200 Subject: [PATCH 0230/2595] hw/i386/pc: Create 'vmport' device in place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200504083342.24273-2-f4bug@amsat.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 2 +- include/hw/i386/pc.h | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 5143c51653..84669ddc84 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1152,7 +1152,7 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport) i8042 = isa_create_simple(isa_bus, "i8042"); if (!no_vmport) { - vmport_init(isa_bus); + isa_create_simple(isa_bus, TYPE_VMPORT); vmmouse = isa_try_create(isa_bus, "vmmouse"); } else { vmmouse = NULL; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 6ab6eda046..26e2a3d92b 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -132,12 +132,6 @@ GSIState *pc_gsi_create(qemu_irq **irqs, bool pci_enabled); /* vmport.c */ #define TYPE_VMPORT "vmport" typedef uint32_t (VMPortReadFunc)(void *opaque, uint32_t address); - -static inline void vmport_init(ISABus *bus) -{ - isa_create_simple(bus, TYPE_VMPORT); -} - void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque); void vmmouse_get_data(uint32_t *data); void vmmouse_set_data(const uint32_t *data); From c7358f4ee13de0e546ff457da95a9026098e37a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 10:33:40 +0200 Subject: [PATCH 0231/2595] hw/i386/vmport: Remove unused 'hw/input/i8042.h' include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unused "hw/input/i8042.h" include. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200504083342.24273-3-f4bug@amsat.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/vmport.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 1f31e27c8a..114141c6f3 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "hw/isa/isa.h" #include "hw/i386/pc.h" -#include "hw/input/i8042.h" #include "sysemu/hw_accel.h" #include "qemu/log.h" #include "trace.h" From e5951129851798620c4f5179dca503a4d6077f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 10:33:41 +0200 Subject: [PATCH 0232/2595] hw/i386: Add 'vmport.h' local header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move 'vmport' related declarations in a target-specific header. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200504083342.24273-4-f4bug@amsat.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 1 + hw/i386/vmmouse.c | 1 + hw/i386/vmport.c | 1 + hw/i386/vmport.h | 34 ++++++++++++++++++++++++++++++++++ include/hw/i386/pc.h | 3 --- 5 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 hw/i386/vmport.h diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 84669ddc84..f6b8431c8b 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -91,6 +91,7 @@ #include "qapi/qmp/qerror.h" #include "config-devices.h" #include "e820_memory_layout.h" +#include "vmport.h" #include "fw_cfg.h" #include "trace.h" diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c index e8e62bd96b..78b36f6f5d 100644 --- a/hw/i386/vmmouse.c +++ b/hw/i386/vmmouse.c @@ -29,6 +29,7 @@ #include "hw/input/i8042.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" +#include "vmport.h" /* debug only vmmouse */ //#define DEBUG_VMMOUSE diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 114141c6f3..00d47e0c4c 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -26,6 +26,7 @@ #include "hw/i386/pc.h" #include "sysemu/hw_accel.h" #include "qemu/log.h" +#include "vmport.h" #include "trace.h" #define VMPORT_CMD_GETVERSION 0x0a diff --git a/hw/i386/vmport.h b/hw/i386/vmport.h new file mode 100644 index 0000000000..47eda7a22b --- /dev/null +++ b/hw/i386/vmport.h @@ -0,0 +1,34 @@ +/* + * QEMU VMPort emulation + * + * Copyright (C) 2007 Hervé Poussineau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_I386_VMPORT_H +#define HW_I386_VMPORT_H + +#define TYPE_VMPORT "vmport" + +typedef uint32_t (VMPortReadFunc)(void *opaque, uint32_t address); + +void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque); + +#endif diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 26e2a3d92b..de49a57506 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -130,9 +130,6 @@ typedef struct PCMachineClass { GSIState *pc_gsi_create(qemu_irq **irqs, bool pci_enabled); /* vmport.c */ -#define TYPE_VMPORT "vmport" -typedef uint32_t (VMPortReadFunc)(void *opaque, uint32_t address); -void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque); void vmmouse_get_data(uint32_t *data); void vmmouse_set_data(const uint32_t *data); From d8a05995bd64117bf5219d3ba7956277e608e3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 10:33:42 +0200 Subject: [PATCH 0233/2595] hw/i386: Make vmmouse helpers static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vmmouse helpers are only used in hw/i386/vmmouse.c, make them static. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200504083342.24273-5-f4bug@amsat.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/vmmouse.c | 22 +++++++++++++++++++++- hw/i386/vmport.c | 23 +---------------------- include/hw/i386/pc.h | 4 ---- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c index 78b36f6f5d..b3aef41327 100644 --- a/hw/i386/vmmouse.c +++ b/hw/i386/vmmouse.c @@ -25,11 +25,11 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "ui/console.h" -#include "hw/i386/pc.h" #include "hw/input/i8042.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "vmport.h" +#include "cpu.h" /* debug only vmmouse */ //#define DEBUG_VMMOUSE @@ -71,6 +71,26 @@ typedef struct VMMouseState ISAKBDState *i8042; } VMMouseState; +static void vmmouse_get_data(uint32_t *data) +{ + X86CPU *cpu = X86_CPU(current_cpu); + CPUX86State *env = &cpu->env; + + data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX]; + data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX]; + data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI]; +} + +static void vmmouse_set_data(const uint32_t *data) +{ + X86CPU *cpu = X86_CPU(current_cpu); + CPUX86State *env = &cpu->env; + + env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1]; + env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3]; + env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5]; +} + static uint32_t vmmouse_get_status(VMMouseState *s) { DPRINTF("vmmouse_get_status()\n"); diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 00d47e0c4c..1aaaab691a 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -23,10 +23,10 @@ */ #include "qemu/osdep.h" #include "hw/isa/isa.h" -#include "hw/i386/pc.h" #include "sysemu/hw_accel.h" #include "qemu/log.h" #include "vmport.h" +#include "cpu.h" #include "trace.h" #define VMPORT_CMD_GETVERSION 0x0a @@ -109,27 +109,6 @@ static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) return ram_size; } -/* vmmouse helpers */ -void vmmouse_get_data(uint32_t *data) -{ - X86CPU *cpu = X86_CPU(current_cpu); - CPUX86State *env = &cpu->env; - - data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX]; - data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX]; - data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI]; -} - -void vmmouse_set_data(const uint32_t *data) -{ - X86CPU *cpu = X86_CPU(current_cpu); - CPUX86State *env = &cpu->env; - - env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1]; - env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3]; - env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5]; -} - static const MemoryRegionOps vmport_ops = { .read = vmport_ioport_read, .write = vmport_ioport_write, diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index de49a57506..05e19455bb 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -129,10 +129,6 @@ typedef struct PCMachineClass { GSIState *pc_gsi_create(qemu_irq **irqs, bool pci_enabled); -/* vmport.c */ -void vmmouse_get_data(uint32_t *data); -void vmmouse_set_data(const uint32_t *data); - /* pc.c */ extern int fd_bootchk; From 05509c8e6def8a23878b93eda3163b7b405a5d57 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Tue, 21 Apr 2020 14:22:30 -0400 Subject: [PATCH 0234/2595] fuzz: select fuzz target using executable name The fuzzers are built into a binary (e.g. qemu-fuzz-i386). To select the device to fuzz/fuzz target, we usually use the --fuzz-target= argument. This commit allows the fuzz-target to be specified using the name of the executable. If the executable name ends with -target-FUZZ_TARGET, then we select the fuzz target based on this name, rather than the --fuzz-target argument. This is useful for systems such as oss-fuzz where we don't have control of the arguments passed to the fuzzer. [Fixed incorrect indentation. --Stefan] Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny Message-id: 20200421182230.6313-1-alxndr@bu.edu Signed-off-by: Stefan Hajnoczi --- tests/qtest/fuzz/fuzz.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 0d78ac8d36..f5c923852e 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -91,6 +91,7 @@ static void usage(char *path) printf(" * %s : %s\n", tmp->target->name, tmp->target->description); } + printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n"); exit(0); } @@ -143,18 +144,20 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) module_call_init(MODULE_INIT_QOM); module_call_init(MODULE_INIT_LIBQOS); - if (*argc <= 1) { + target_name = strstr(**argv, "-target-"); + if (target_name) { /* The binary name specifies the target */ + target_name += strlen("-target-"); + } else if (*argc > 1) { /* The target is specified as an argument */ + target_name = (*argv)[1]; + if (!strstr(target_name, "--fuzz-target=")) { + usage(**argv); + } + target_name += strlen("--fuzz-target="); + } else { usage(**argv); } /* Identify the fuzz target */ - target_name = (*argv)[1]; - if (!strstr(target_name, "--fuzz-target=")) { - usage(**argv); - } - - target_name += strlen("--fuzz-target="); - fuzz_target = fuzz_get_target(target_name); if (!fuzz_target) { usage(**argv); From 56f21718b8767a1b523f2a14107d6307336ca51d Mon Sep 17 00:00:00 2001 From: Daniel Brodsky Date: Fri, 3 Apr 2020 21:21:07 -0700 Subject: [PATCH 0235/2595] lockable: fix __COUNTER__ macro to be referenced properly - __COUNTER__ doesn't work with ## concat - replaced ## with glue() macro so __COUNTER__ is evaluated Fixes: 3284c3ddc4 Signed-off-by: Daniel Brodsky Message-id: 20200404042108.389635-2-dnbrdsky@gmail.com Signed-off-by: Stefan Hajnoczi --- include/qemu/lockable.h | 7 ++++--- include/qemu/rcu.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/qemu/lockable.h b/include/qemu/lockable.h index 1aeb2cb1a6..b620023141 100644 --- a/include/qemu/lockable.h +++ b/include/qemu/lockable.h @@ -152,7 +152,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock) * } */ #define WITH_QEMU_LOCK_GUARD(x) \ - WITH_QEMU_LOCK_GUARD_((x), qemu_lockable_auto##__COUNTER__) + WITH_QEMU_LOCK_GUARD_((x), glue(qemu_lockable_auto, __COUNTER__)) /** * QEMU_LOCK_GUARD - Lock an object until the end of the scope @@ -169,8 +169,9 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock) * return; <-- mutex is automatically unlocked * } */ -#define QEMU_LOCK_GUARD(x) \ - g_autoptr(QemuLockable) qemu_lockable_auto##__COUNTER__ = \ +#define QEMU_LOCK_GUARD(x) \ + g_autoptr(QemuLockable) \ + glue(qemu_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \ qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x))) #endif diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h index 9c82683e37..570aa603eb 100644 --- a/include/qemu/rcu.h +++ b/include/qemu/rcu.h @@ -170,7 +170,7 @@ static inline void rcu_read_auto_unlock(RCUReadAuto *r) G_DEFINE_AUTOPTR_CLEANUP_FUNC(RCUReadAuto, rcu_read_auto_unlock) #define WITH_RCU_READ_LOCK_GUARD() \ - WITH_RCU_READ_LOCK_GUARD_(_rcu_read_auto##__COUNTER__) + WITH_RCU_READ_LOCK_GUARD_(glue(_rcu_read_auto, __COUNTER__)) #define WITH_RCU_READ_LOCK_GUARD_(var) \ for (g_autoptr(RCUReadAuto) var = rcu_read_auto_lock(); \ From 6e8a355de6c4d32e9df336cdafb009cd78262836 Mon Sep 17 00:00:00 2001 From: Daniel Brodsky Date: Fri, 3 Apr 2020 21:21:08 -0700 Subject: [PATCH 0236/2595] lockable: replaced locks with lock guard macros where appropriate - ran regexp "qemu_mutex_lock\(.*\).*\n.*if" to find targets - replaced result with QEMU_LOCK_GUARD if all unlocks at function end - replaced result with WITH_QEMU_LOCK_GUARD if unlock not at end Signed-off-by: Daniel Brodsky Reviewed-by: Juan Quintela Message-id: 20200404042108.389635-3-dnbrdsky@gmail.com Signed-off-by: Stefan Hajnoczi --- block/iscsi.c | 7 ++---- block/nfs.c | 51 ++++++++++++++++++++----------------------- cpus-common.c | 14 +++++------- hw/display/qxl.c | 43 +++++++++++++++++------------------- hw/vfio/platform.c | 5 ++--- migration/migration.c | 3 +-- migration/multifd.c | 8 +++---- migration/ram.c | 3 +-- monitor/misc.c | 4 +--- ui/spice-display.c | 14 ++++++------ util/log.c | 4 ++-- util/qemu-timer.c | 17 +++++++-------- util/rcu.c | 8 +++---- util/thread-pool.c | 3 +-- util/vfio-helpers.c | 5 ++--- 15 files changed, 83 insertions(+), 106 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index 914a1de9fb..a8b76979d8 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1394,20 +1394,17 @@ static void iscsi_nop_timed_event(void *opaque) { IscsiLun *iscsilun = opaque; - qemu_mutex_lock(&iscsilun->mutex); + QEMU_LOCK_GUARD(&iscsilun->mutex); if (iscsi_get_nops_in_flight(iscsilun->iscsi) >= MAX_NOP_FAILURES) { error_report("iSCSI: NOP timeout. Reconnecting..."); iscsilun->request_timed_out = true; } else if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) { error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages."); - goto out; + return; } timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL); iscsi_set_events(iscsilun); - -out: - qemu_mutex_unlock(&iscsilun->mutex); } static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp) diff --git a/block/nfs.c b/block/nfs.c index 2393fbfe6b..b86ba5bfa1 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -273,15 +273,14 @@ static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset, nfs_co_init_task(bs, &task); task.iov = iov; - qemu_mutex_lock(&client->mutex); - if (nfs_pread_async(client->context, client->fh, - offset, bytes, nfs_co_generic_cb, &task) != 0) { - qemu_mutex_unlock(&client->mutex); - return -ENOMEM; - } + WITH_QEMU_LOCK_GUARD(&client->mutex) { + if (nfs_pread_async(client->context, client->fh, + offset, bytes, nfs_co_generic_cb, &task) != 0) { + return -ENOMEM; + } - nfs_set_events(client); - qemu_mutex_unlock(&client->mutex); + nfs_set_events(client); + } while (!task.complete) { qemu_coroutine_yield(); } @@ -320,19 +319,18 @@ static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, uint64_t offset, buf = iov->iov[0].iov_base; } - qemu_mutex_lock(&client->mutex); - if (nfs_pwrite_async(client->context, client->fh, - offset, bytes, buf, - nfs_co_generic_cb, &task) != 0) { - qemu_mutex_unlock(&client->mutex); - if (my_buffer) { - g_free(buf); + WITH_QEMU_LOCK_GUARD(&client->mutex) { + if (nfs_pwrite_async(client->context, client->fh, + offset, bytes, buf, + nfs_co_generic_cb, &task) != 0) { + if (my_buffer) { + g_free(buf); + } + return -ENOMEM; } - return -ENOMEM; - } - nfs_set_events(client); - qemu_mutex_unlock(&client->mutex); + nfs_set_events(client); + } while (!task.complete) { qemu_coroutine_yield(); } @@ -355,15 +353,14 @@ static int coroutine_fn nfs_co_flush(BlockDriverState *bs) nfs_co_init_task(bs, &task); - qemu_mutex_lock(&client->mutex); - if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb, - &task) != 0) { - qemu_mutex_unlock(&client->mutex); - return -ENOMEM; - } + WITH_QEMU_LOCK_GUARD(&client->mutex) { + if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb, + &task) != 0) { + return -ENOMEM; + } - nfs_set_events(client); - qemu_mutex_unlock(&client->mutex); + nfs_set_events(client); + } while (!task.complete) { qemu_coroutine_yield(); } diff --git a/cpus-common.c b/cpus-common.c index eaf590cb38..55d5df8923 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -22,6 +22,7 @@ #include "exec/cpu-common.h" #include "hw/core/cpu.h" #include "sysemu/cpus.h" +#include "qemu/lockable.h" static QemuMutex qemu_cpu_list_lock; static QemuCond exclusive_cond; @@ -71,7 +72,7 @@ static int cpu_get_free_index(void) void cpu_list_add(CPUState *cpu) { - qemu_mutex_lock(&qemu_cpu_list_lock); + QEMU_LOCK_GUARD(&qemu_cpu_list_lock); if (cpu->cpu_index == UNASSIGNED_CPU_INDEX) { cpu->cpu_index = cpu_get_free_index(); assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX); @@ -79,15 +80,13 @@ void cpu_list_add(CPUState *cpu) assert(!cpu_index_auto_assigned); } QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node); - qemu_mutex_unlock(&qemu_cpu_list_lock); } void cpu_list_remove(CPUState *cpu) { - qemu_mutex_lock(&qemu_cpu_list_lock); + QEMU_LOCK_GUARD(&qemu_cpu_list_lock); if (!QTAILQ_IN_USE(cpu, node)) { /* there is nothing to undo since cpu_exec_init() hasn't been called */ - qemu_mutex_unlock(&qemu_cpu_list_lock); return; } @@ -95,7 +94,6 @@ void cpu_list_remove(CPUState *cpu) QTAILQ_REMOVE_RCU(&cpus, cpu, node); cpu->cpu_index = UNASSIGNED_CPU_INDEX; - qemu_mutex_unlock(&qemu_cpu_list_lock); } struct qemu_work_item { @@ -237,7 +235,7 @@ void cpu_exec_start(CPUState *cpu) * see cpu->running == true, and it will kick the CPU. */ if (unlikely(atomic_read(&pending_cpus))) { - qemu_mutex_lock(&qemu_cpu_list_lock); + QEMU_LOCK_GUARD(&qemu_cpu_list_lock); if (!cpu->has_waiter) { /* Not counted in pending_cpus, let the exclusive item * run. Since we have the lock, just set cpu->running to true @@ -252,7 +250,6 @@ void cpu_exec_start(CPUState *cpu) * waiter at cpu_exec_end. */ } - qemu_mutex_unlock(&qemu_cpu_list_lock); } } @@ -280,7 +277,7 @@ void cpu_exec_end(CPUState *cpu) * next cpu_exec_start. */ if (unlikely(atomic_read(&pending_cpus))) { - qemu_mutex_lock(&qemu_cpu_list_lock); + QEMU_LOCK_GUARD(&qemu_cpu_list_lock); if (cpu->has_waiter) { cpu->has_waiter = false; atomic_set(&pending_cpus, pending_cpus - 1); @@ -288,7 +285,6 @@ void cpu_exec_end(CPUState *cpu) qemu_cond_signal(&exclusive_cond); } } - qemu_mutex_unlock(&qemu_cpu_list_lock); } } diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 227da69a50..d5627119ec 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -478,18 +478,19 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) cmd->u.surface_create.stride); return 1; } - qemu_mutex_lock(&qxl->track_lock); - if (cmd->type == QXL_SURFACE_CMD_CREATE) { - qxl->guest_surfaces.cmds[id] = ext->cmd.data; - qxl->guest_surfaces.count++; - if (qxl->guest_surfaces.max < qxl->guest_surfaces.count) - qxl->guest_surfaces.max = qxl->guest_surfaces.count; + WITH_QEMU_LOCK_GUARD(&qxl->track_lock) { + if (cmd->type == QXL_SURFACE_CMD_CREATE) { + qxl->guest_surfaces.cmds[id] = ext->cmd.data; + qxl->guest_surfaces.count++; + if (qxl->guest_surfaces.max < qxl->guest_surfaces.count) { + qxl->guest_surfaces.max = qxl->guest_surfaces.count; + } + } + if (cmd->type == QXL_SURFACE_CMD_DESTROY) { + qxl->guest_surfaces.cmds[id] = 0; + qxl->guest_surfaces.count--; + } } - if (cmd->type == QXL_SURFACE_CMD_DESTROY) { - qxl->guest_surfaces.cmds[id] = 0; - qxl->guest_surfaces.count--; - } - qemu_mutex_unlock(&qxl->track_lock); break; } case QXL_CMD_CURSOR: @@ -958,10 +959,9 @@ static void interface_update_area_complete(QXLInstance *sin, int i; int qxl_i; - qemu_mutex_lock(&qxl->ssd.lock); + QEMU_LOCK_GUARD(&qxl->ssd.lock); if (surface_id != 0 || !num_updated_rects || !qxl->render_update_cookie_num) { - qemu_mutex_unlock(&qxl->ssd.lock); return; } trace_qxl_interface_update_area_complete(qxl->id, surface_id, dirty->left, @@ -980,7 +980,6 @@ static void interface_update_area_complete(QXLInstance *sin, * Don't bother copying or scheduling the bh since we will flip * the whole area anyway on completion of the update_area async call */ - qemu_mutex_unlock(&qxl->ssd.lock); return; } qxl_i = qxl->num_dirty_rects; @@ -991,7 +990,6 @@ static void interface_update_area_complete(QXLInstance *sin, trace_qxl_interface_update_area_complete_schedule_bh(qxl->id, qxl->num_dirty_rects); qemu_bh_schedule(qxl->update_area_bh); - qemu_mutex_unlock(&qxl->ssd.lock); } /* called from spice server thread context only */ @@ -1694,15 +1692,14 @@ static void ioport_write(void *opaque, hwaddr addr, case QXL_IO_MONITORS_CONFIG_ASYNC: async_common: async = QXL_ASYNC; - qemu_mutex_lock(&d->async_lock); - if (d->current_async != QXL_UNDEFINED_IO) { - qxl_set_guest_bug(d, "%d async started before last (%d) complete", - io_port, d->current_async); - qemu_mutex_unlock(&d->async_lock); - return; + WITH_QEMU_LOCK_GUARD(&d->async_lock) { + if (d->current_async != QXL_UNDEFINED_IO) { + qxl_set_guest_bug(d, "%d async started before last (%d) complete", + io_port, d->current_async); + return; + } + d->current_async = orig_io_port; } - d->current_async = orig_io_port; - qemu_mutex_unlock(&d->async_lock); break; default: break; diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index 6b2952c034..ac2cefc9b1 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -22,6 +22,7 @@ #include "hw/vfio/vfio-platform.h" #include "migration/vmstate.h" #include "qemu/error-report.h" +#include "qemu/lockable.h" #include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/range.h" @@ -216,7 +217,7 @@ static void vfio_intp_interrupt(VFIOINTp *intp) VFIOPlatformDevice *vdev = intp->vdev; bool delay_handling = false; - qemu_mutex_lock(&vdev->intp_mutex); + QEMU_LOCK_GUARD(&vdev->intp_mutex); if (intp->state == VFIO_IRQ_INACTIVE) { QLIST_FOREACH(tmp, &vdev->intp_list, next) { if (tmp->state == VFIO_IRQ_ACTIVE || @@ -236,7 +237,6 @@ static void vfio_intp_interrupt(VFIOINTp *intp) QSIMPLEQ_INSERT_TAIL(&vdev->pending_intp_queue, intp, pqnext); ret = event_notifier_test_and_clear(intp->interrupt); - qemu_mutex_unlock(&vdev->intp_mutex); return; } @@ -266,7 +266,6 @@ static void vfio_intp_interrupt(VFIOINTp *intp) qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + vdev->mmap_timeout); } - qemu_mutex_unlock(&vdev->intp_mutex); } /** diff --git a/migration/migration.c b/migration/migration.c index 187ac0410c..177cce9e95 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1653,11 +1653,10 @@ static void migrate_fd_cleanup_bh(void *opaque) void migrate_set_error(MigrationState *s, const Error *error) { - qemu_mutex_lock(&s->error_mutex); + QEMU_LOCK_GUARD(&s->error_mutex); if (!s->error) { s->error = error_copy(error); } - qemu_mutex_unlock(&s->error_mutex); } void migrate_fd_error(MigrationState *s, const Error *error) diff --git a/migration/multifd.c b/migration/multifd.c index cb6a4a3ab8..9123c111a3 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -894,11 +894,11 @@ void multifd_recv_sync_main(void) for (i = 0; i < migrate_multifd_channels(); i++) { MultiFDRecvParams *p = &multifd_recv_state->params[i]; - qemu_mutex_lock(&p->mutex); - if (multifd_recv_state->packet_num < p->packet_num) { - multifd_recv_state->packet_num = p->packet_num; + WITH_QEMU_LOCK_GUARD(&p->mutex) { + if (multifd_recv_state->packet_num < p->packet_num) { + multifd_recv_state->packet_num = p->packet_num; + } } - qemu_mutex_unlock(&p->mutex); trace_multifd_recv_sync_main_signal(p->id); qemu_sem_post(&p->sem_sync); } diff --git a/migration/ram.c b/migration/ram.c index 04f13feb2e..580ec24522 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1369,7 +1369,7 @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset) return NULL; } - qemu_mutex_lock(&rs->src_page_req_mutex); + QEMU_LOCK_GUARD(&rs->src_page_req_mutex); if (!QSIMPLEQ_EMPTY(&rs->src_page_requests)) { struct RAMSrcPageRequest *entry = QSIMPLEQ_FIRST(&rs->src_page_requests); @@ -1386,7 +1386,6 @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset) migration_consume_urgent_request(); } } - qemu_mutex_unlock(&rs->src_page_req_mutex); return block; } diff --git a/monitor/misc.c b/monitor/misc.c index 6c45fa490f..9723b466cd 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -1473,7 +1473,7 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, MonFdsetFd *mon_fdset_fd; AddfdInfo *fdinfo; - qemu_mutex_lock(&mon_fdsets_lock); + QEMU_LOCK_GUARD(&mon_fdsets_lock); if (has_fdset_id) { QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { /* Break if match found or match impossible due to ordering by ID */ @@ -1494,7 +1494,6 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, if (fdset_id < 0) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id", "a non-negative value"); - qemu_mutex_unlock(&mon_fdsets_lock); return NULL; } /* Use specified fdset ID */ @@ -1545,7 +1544,6 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, fdinfo->fdset_id = mon_fdset->id; fdinfo->fd = mon_fdset_fd->fd; - qemu_mutex_unlock(&mon_fdsets_lock); return fdinfo; } diff --git a/ui/spice-display.c b/ui/spice-display.c index 6babe24909..19632fdf6c 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -18,6 +18,7 @@ #include "qemu/osdep.h" #include "ui/qemu-spice.h" #include "qemu/timer.h" +#include "qemu/lockable.h" #include "qemu/main-loop.h" #include "qemu/option.h" #include "qemu/queue.h" @@ -483,12 +484,12 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) { graphic_hw_update(ssd->dcl.con); - qemu_mutex_lock(&ssd->lock); - if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) { - qemu_spice_create_update(ssd); - ssd->notify++; + WITH_QEMU_LOCK_GUARD(&ssd->lock) { + if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) { + qemu_spice_create_update(ssd); + ssd->notify++; + } } - qemu_mutex_unlock(&ssd->lock); trace_qemu_spice_display_refresh(ssd->qxl.id, ssd->notify); if (ssd->notify) { @@ -580,7 +581,7 @@ static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext) SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); int ret; - qemu_mutex_lock(&ssd->lock); + QEMU_LOCK_GUARD(&ssd->lock); if (ssd->ptr_define) { *ext = ssd->ptr_define->ext; ssd->ptr_define = NULL; @@ -592,7 +593,6 @@ static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext) } else { ret = false; } - qemu_mutex_unlock(&ssd->lock); return ret; } diff --git a/util/log.c b/util/log.c index 2da6cb31dc..bdb3d712e8 100644 --- a/util/log.c +++ b/util/log.c @@ -25,6 +25,7 @@ #include "qemu/cutils.h" #include "trace/control.h" #include "qemu/thread.h" +#include "qemu/lockable.h" static char *logfilename; static QemuMutex qemu_logfile_mutex; @@ -94,7 +95,7 @@ void qemu_set_log(int log_flags) if (qemu_loglevel && (!is_daemonized() || logfilename)) { need_to_open_file = true; } - qemu_mutex_lock(&qemu_logfile_mutex); + QEMU_LOCK_GUARD(&qemu_logfile_mutex); if (qemu_logfile && !need_to_open_file) { logfile = qemu_logfile; atomic_rcu_set(&qemu_logfile, NULL); @@ -136,7 +137,6 @@ void qemu_set_log(int log_flags) } atomic_rcu_set(&qemu_logfile, logfile); } - qemu_mutex_unlock(&qemu_logfile_mutex); } void qemu_log_needs_buffers(void) diff --git a/util/qemu-timer.c b/util/qemu-timer.c index d548d3c1ad..b6575a2cd5 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -459,17 +459,16 @@ void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time) QEMUTimerList *timer_list = ts->timer_list; bool rearm; - qemu_mutex_lock(&timer_list->active_timers_lock); - if (ts->expire_time == -1 || ts->expire_time > expire_time) { - if (ts->expire_time != -1) { - timer_del_locked(timer_list, ts); + WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) { + if (ts->expire_time == -1 || ts->expire_time > expire_time) { + if (ts->expire_time != -1) { + timer_del_locked(timer_list, ts); + } + rearm = timer_mod_ns_locked(timer_list, ts, expire_time); + } else { + rearm = false; } - rearm = timer_mod_ns_locked(timer_list, ts, expire_time); - } else { - rearm = false; } - qemu_mutex_unlock(&timer_list->active_timers_lock); - if (rearm) { timerlist_rearm(timer_list); } diff --git a/util/rcu.c b/util/rcu.c index 177a675619..60a37f72c3 100644 --- a/util/rcu.c +++ b/util/rcu.c @@ -31,6 +31,7 @@ #include "qemu/atomic.h" #include "qemu/thread.h" #include "qemu/main-loop.h" +#include "qemu/lockable.h" #if defined(CONFIG_MALLOC_TRIM) #include #endif @@ -141,14 +142,14 @@ static void wait_for_readers(void) void synchronize_rcu(void) { - qemu_mutex_lock(&rcu_sync_lock); + QEMU_LOCK_GUARD(&rcu_sync_lock); /* Write RCU-protected pointers before reading p_rcu_reader->ctr. * Pairs with smp_mb_placeholder() in rcu_read_lock(). */ smp_mb_global(); - qemu_mutex_lock(&rcu_registry_lock); + QEMU_LOCK_GUARD(&rcu_registry_lock); if (!QLIST_EMPTY(®istry)) { /* In either case, the atomic_mb_set below blocks stores that free * old RCU-protected pointers. @@ -169,9 +170,6 @@ void synchronize_rcu(void) wait_for_readers(); } - - qemu_mutex_unlock(&rcu_registry_lock); - qemu_mutex_unlock(&rcu_sync_lock); } diff --git a/util/thread-pool.c b/util/thread-pool.c index 4ed9b89ab2..d763cea505 100644 --- a/util/thread-pool.c +++ b/util/thread-pool.c @@ -210,7 +210,7 @@ static void thread_pool_cancel(BlockAIOCB *acb) trace_thread_pool_cancel(elem, elem->common.opaque); - qemu_mutex_lock(&pool->lock); + QEMU_LOCK_GUARD(&pool->lock); if (elem->state == THREAD_QUEUED && /* No thread has yet started working on elem. we can try to "steal" * the item from the worker if we can get a signal from the @@ -225,7 +225,6 @@ static void thread_pool_cancel(BlockAIOCB *acb) elem->ret = -ECANCELED; } - qemu_mutex_unlock(&pool->lock); } static AioContext *thread_pool_get_aio_context(BlockAIOCB *acb) diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c index ddd9a96e76..e399e330e2 100644 --- a/util/vfio-helpers.c +++ b/util/vfio-helpers.c @@ -21,6 +21,7 @@ #include "standard-headers/linux/pci_regs.h" #include "qemu/event_notifier.h" #include "qemu/vfio-helpers.h" +#include "qemu/lockable.h" #include "trace.h" #define QEMU_VFIO_DEBUG 0 @@ -667,14 +668,12 @@ int qemu_vfio_dma_reset_temporary(QEMUVFIOState *s) .size = QEMU_VFIO_IOVA_MAX - s->high_water_mark, }; trace_qemu_vfio_dma_reset_temporary(s); - qemu_mutex_lock(&s->lock); + QEMU_LOCK_GUARD(&s->lock); if (ioctl(s->container, VFIO_IOMMU_UNMAP_DMA, &unmap)) { error_report("VFIO_UNMAP_DMA failed: %s", strerror(errno)); - qemu_mutex_unlock(&s->lock); return -errno; } s->high_water_mark = QEMU_VFIO_IOVA_MAX; - qemu_mutex_unlock(&s->lock); return 0; } From 08b689aa6b521964b8275dd7a2564aefa5d68129 Mon Sep 17 00:00:00 2001 From: Simran Singhal Date: Thu, 2 Apr 2020 12:20:35 +0530 Subject: [PATCH 0237/2595] lockable: Replace locks with lock guard macros Replace manual lock()/unlock() calls with lock guard macros (QEMU_LOCK_GUARD/WITH_QEMU_LOCK_GUARD). Signed-off-by: Simran Singhal Reviewed-by: Yuval Shaia Reviewed-by: Marcel Apfelbaum Tested-by: Yuval Shaia Message-id: 20200402065035.GA15477@simran-Inspiron-5558 Signed-off-by: Stefan Hajnoczi --- hw/hyperv/hyperv.c | 15 ++++++------ hw/rdma/rdma_backend.c | 54 +++++++++++++++++++++--------------------- hw/rdma/rdma_rm.c | 3 +-- 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index 8ca3706f5b..4ddafe1de1 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -15,6 +15,7 @@ #include "sysemu/kvm.h" #include "qemu/bitops.h" #include "qemu/error-report.h" +#include "qemu/lockable.h" #include "qemu/queue.h" #include "qemu/rcu.h" #include "qemu/rcu_queue.h" @@ -491,7 +492,7 @@ int hyperv_set_msg_handler(uint32_t conn_id, HvMsgHandler handler, void *data) int ret; MsgHandler *mh; - qemu_mutex_lock(&handlers_mutex); + QEMU_LOCK_GUARD(&handlers_mutex); QLIST_FOREACH(mh, &msg_handlers, link) { if (mh->conn_id == conn_id) { if (handler) { @@ -501,7 +502,7 @@ int hyperv_set_msg_handler(uint32_t conn_id, HvMsgHandler handler, void *data) g_free_rcu(mh, rcu); ret = 0; } - goto unlock; + return ret; } } @@ -515,8 +516,7 @@ int hyperv_set_msg_handler(uint32_t conn_id, HvMsgHandler handler, void *data) } else { ret = -ENOENT; } -unlock: - qemu_mutex_unlock(&handlers_mutex); + return ret; } @@ -565,7 +565,7 @@ static int set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier) int ret; EventFlagHandler *handler; - qemu_mutex_lock(&handlers_mutex); + QEMU_LOCK_GUARD(&handlers_mutex); QLIST_FOREACH(handler, &event_flag_handlers, link) { if (handler->conn_id == conn_id) { if (notifier) { @@ -575,7 +575,7 @@ static int set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier) g_free_rcu(handler, rcu); ret = 0; } - goto unlock; + return ret; } } @@ -588,8 +588,7 @@ static int set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier) } else { ret = -ENOENT; } -unlock: - qemu_mutex_unlock(&handlers_mutex); + return ret; } diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c index 3dd39fe1a7..db7e5c8be5 100644 --- a/hw/rdma/rdma_backend.c +++ b/hw/rdma/rdma_backend.c @@ -95,36 +95,36 @@ static int rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) struct ibv_wc wc[2]; RdmaProtectedGSList *cqe_ctx_list; - qemu_mutex_lock(&rdma_dev_res->lock); - do { - ne = ibv_poll_cq(ibcq, ARRAY_SIZE(wc), wc); + WITH_QEMU_LOCK_GUARD(&rdma_dev_res->lock) { + do { + ne = ibv_poll_cq(ibcq, ARRAY_SIZE(wc), wc); - trace_rdma_poll_cq(ne, ibcq); + trace_rdma_poll_cq(ne, ibcq); - for (i = 0; i < ne; i++) { - bctx = rdma_rm_get_cqe_ctx(rdma_dev_res, wc[i].wr_id); - if (unlikely(!bctx)) { - rdma_error_report("No matching ctx for req %"PRId64, - wc[i].wr_id); - continue; + for (i = 0; i < ne; i++) { + bctx = rdma_rm_get_cqe_ctx(rdma_dev_res, wc[i].wr_id); + if (unlikely(!bctx)) { + rdma_error_report("No matching ctx for req %"PRId64, + wc[i].wr_id); + continue; + } + + comp_handler(bctx->up_ctx, &wc[i]); + + if (bctx->backend_qp) { + cqe_ctx_list = &bctx->backend_qp->cqe_ctx_list; + } else { + cqe_ctx_list = &bctx->backend_srq->cqe_ctx_list; + } + + rdma_protected_gslist_remove_int32(cqe_ctx_list, wc[i].wr_id); + rdma_rm_dealloc_cqe_ctx(rdma_dev_res, wc[i].wr_id); + g_free(bctx); } - - comp_handler(bctx->up_ctx, &wc[i]); - - if (bctx->backend_qp) { - cqe_ctx_list = &bctx->backend_qp->cqe_ctx_list; - } else { - cqe_ctx_list = &bctx->backend_srq->cqe_ctx_list; - } - - rdma_protected_gslist_remove_int32(cqe_ctx_list, wc[i].wr_id); - rdma_rm_dealloc_cqe_ctx(rdma_dev_res, wc[i].wr_id); - g_free(bctx); - } - total_ne += ne; - } while (ne > 0); - atomic_sub(&rdma_dev_res->stats.missing_cqe, total_ne); - qemu_mutex_unlock(&rdma_dev_res->lock); + total_ne += ne; + } while (ne > 0); + atomic_sub(&rdma_dev_res->stats.missing_cqe, total_ne); + } if (ne < 0) { rdma_error_report("ibv_poll_cq fail, rc=%d, errno=%d", ne, errno); diff --git a/hw/rdma/rdma_rm.c b/hw/rdma/rdma_rm.c index 7e9ea283c9..60957f88db 100644 --- a/hw/rdma/rdma_rm.c +++ b/hw/rdma/rdma_rm.c @@ -147,14 +147,13 @@ static inline void rdma_res_tbl_dealloc(RdmaRmResTbl *tbl, uint32_t handle) { trace_rdma_res_tbl_dealloc(tbl->name, handle); - qemu_mutex_lock(&tbl->lock); + QEMU_LOCK_GUARD(&tbl->lock); if (handle < tbl->tbl_sz) { clear_bit(handle, tbl->bitmap); tbl->used--; } - qemu_mutex_unlock(&tbl->lock); } int rdma_rm_alloc_pd(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev, From 474a6e64f2c3c17718b853b9d70e054ee8d26f37 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 20 Apr 2020 12:53:08 -0500 Subject: [PATCH 0238/2595] tools: Fix use of fcntl(F_SETFD) during socket activation Blindly setting FD_CLOEXEC without a read-modify-write will inadvertently clear any other intentionally-set bits, such as a proposed new bit for designating a fd that must behave in 32-bit mode. However, we cannot use our wrapper qemu_set_cloexec(), because that wrapper intentionally abort()s on failure, whereas the probe here intentionally tolerates failure to deal with incorrect socket activation gracefully. Instead, fix the code to do the proper read-modify-write. Signed-off-by: Eric Blake Message-Id: <20200420175309.75894-3-eblake@redhat.com> Reviewed-by: Peter Maydell --- util/systemd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/util/systemd.c b/util/systemd.c index 1dd0367d9a..5bcac9b401 100644 --- a/util/systemd.c +++ b/util/systemd.c @@ -23,6 +23,7 @@ unsigned int check_socket_activation(void) unsigned long nr_fds; unsigned int i; int fd; + int f; int err; s = getenv("LISTEN_PID"); @@ -54,7 +55,8 @@ unsigned int check_socket_activation(void) /* So the file descriptors don't leak into child processes. */ for (i = 0; i < nr_fds; ++i) { fd = FIRST_SOCKET_ACTIVATION_FD + i; - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { + f = fcntl(fd, F_GETFD); + if (f == -1 || fcntl(fd, F_SETFD, f | FD_CLOEXEC) == -1) { /* If we cannot set FD_CLOEXEC then it probably means the file * descriptor is invalid, so socket activation has gone wrong * and we should exit. From e5ac52d8d405f46843465128410a8f1362458eb6 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Fri, 24 Apr 2020 15:46:26 +0200 Subject: [PATCH 0239/2595] iotests/041: Fix NBD socket path We should put all UNIX socket files into the sock_dir, not test_dir. Reported-by: Elena Ufimtseva Signed-off-by: Max Reitz Message-Id: <20200424134626.78945-1-mreitz@redhat.com> Reviewed-by: Eric Blake Fixes: a1da1878607a Reviewed-by: Stefan Hajnoczi Signed-off-by: Eric Blake --- tests/qemu-iotests/041 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 5d67bf14bf..46bf1f6c81 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -35,7 +35,7 @@ quorum_img3 = os.path.join(iotests.test_dir, 'quorum3.img') quorum_repair_img = os.path.join(iotests.test_dir, 'quorum_repair.img') quorum_snapshot_file = os.path.join(iotests.test_dir, 'quorum_snapshot.img') -nbd_sock_path = os.path.join(iotests.test_dir, 'nbd.sock') +nbd_sock_path = os.path.join(iotests.sock_dir, 'nbd.sock') class TestSingleDrive(iotests.QMPTestCase): image_len = 1 * 1024 * 1024 # MB From 6bf792b4643bd88153b2d473f735f93638cac521 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 1 Apr 2020 18:01:07 +0300 Subject: [PATCH 0240/2595] block/nbd-client: drop max_block restriction from block_status The NBD spec was updated (see nbd.git commit 9f30fedb) so that max_block doesn't relate to NBD_CMD_BLOCK_STATUS. So, drop the restriction. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200401150112.9557-2-vsementsov@virtuozzo.com> [eblake: tweak commit message to call out NBD commit] Signed-off-by: Eric Blake --- block/nbd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index 2160859f64..d4d518a780 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1320,9 +1320,7 @@ static int coroutine_fn nbd_client_co_block_status( NBDRequest request = { .type = NBD_CMD_BLOCK_STATUS, .from = offset, - .len = MIN(MIN_NON_ZERO(QEMU_ALIGN_DOWN(INT_MAX, - bs->bl.request_alignment), - s->info.max_block), + .len = MIN(QEMU_ALIGN_DOWN(INT_MAX, bs->bl.request_alignment), MIN(bytes, s->info.size - offset)), .flags = NBD_CMD_FLAG_REQ_ONE, }; From 714eb0dbc5480c8a9d9f39eb931cb5d2acc1b6c6 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 1 Apr 2020 18:01:08 +0300 Subject: [PATCH 0241/2595] block/nbd-client: drop max_block restriction from discard The NBD spec was updated (see nbd.git commit 9f30fedb) so that max_block doesn't relate to NBD_CMD_TRIM. So, drop the restriction. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200401150112.9557-3-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake [eblake: tweak commit message to call out NBD commit] Signed-off-by: Eric Blake --- block/nbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/nbd.c b/block/nbd.c index d4d518a780..4ac23c8f62 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1955,7 +1955,7 @@ static void nbd_refresh_limits(BlockDriverState *bs, Error **errp) } bs->bl.request_alignment = min; - bs->bl.max_pdiscard = max; + bs->bl.max_pdiscard = QEMU_ALIGN_DOWN(INT_MAX, min); bs->bl.max_pwrite_zeroes = max; bs->bl.max_transfer = max; From 6a96d87cf40ddcd7b0e7ff398e8d2cd03c9be58d Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:01 -0400 Subject: [PATCH 0242/2595] iotests: do a light delinting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This doesn't fix everything in here, but it does help clean up the pylint report considerably. This should be 100% style changes only; the intent is to make pylint more useful by working on establishing a baseline for iotests that we can gate against in the future. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Max Reitz Message-Id: <20200331000014.11581-2-jsnow@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 83 ++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 5f8c263d59..6f6363f3ec 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -16,11 +16,9 @@ # along with this program. If not, see . # -import errno import os import re import subprocess -import string import unittest import sys import struct @@ -35,7 +33,7 @@ import faulthandler sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu import qtest -assert sys.version_info >= (3,6) +assert sys.version_info >= (3, 6) faulthandler.enable() @@ -141,11 +139,11 @@ def qemu_img_log(*args): return result def img_info_log(filename, filter_path=None, imgopts=False, extra_args=[]): - args = [ 'info' ] + args = ['info'] if imgopts: args.append('--image-opts') else: - args += [ '-f', imgfmt ] + args += ['-f', imgfmt] args += extra_args args.append(filename) @@ -224,7 +222,7 @@ class QemuIoInteractive: # quit command is in close(), '\n' is added automatically assert '\n' not in cmd cmd = cmd.strip() - assert cmd != 'q' and cmd != 'quit' + assert cmd not in ('q', 'quit') self._p.stdin.write(cmd + '\n') self._p.stdin.flush() return self._read_output() @@ -246,10 +244,8 @@ def qemu_nbd_early_pipe(*args): sys.stderr.write('qemu-nbd received signal %i: %s\n' % (-exitcode, ' '.join(qemu_nbd_args + ['--fork'] + list(args)))) - if exitcode == 0: - return exitcode, '' - else: - return exitcode, subp.communicate()[0] + + return exitcode, subp.communicate()[0] if exitcode else '' def qemu_nbd_popen(*args): '''Run qemu-nbd in daemon mode and return the parent's exit code''' @@ -313,7 +309,7 @@ def filter_qmp(qmsg, filter_fn): items = qmsg.items() for k, v in items: - if isinstance(v, list) or isinstance(v, dict): + if isinstance(v, (dict, list)): qmsg[k] = filter_qmp(v, filter_fn) else: qmsg[k] = filter_fn(k, v) @@ -324,7 +320,7 @@ def filter_testfiles(msg): return msg.replace(prefix, 'TEST_DIR/PID-') def filter_qmp_testfiles(qmsg): - def _filter(key, value): + def _filter(_key, value): if is_str(value): return filter_testfiles(value) return value @@ -351,7 +347,7 @@ def filter_imgfmt(msg): return msg.replace(imgfmt, 'IMGFMT') def filter_qmp_imgfmt(qmsg): - def _filter(key, value): + def _filter(_key, value): if is_str(value): return filter_imgfmt(value) return value @@ -362,7 +358,7 @@ def log(msg, filters=[], indent=None): If indent is provided, JSON serializable messages are pretty-printed.''' for flt in filters: msg = flt(msg) - if isinstance(msg, dict) or isinstance(msg, list): + if isinstance(msg, (dict, list)): # Python < 3.4 needs to know not to add whitespace when pretty-printing: separators = (', ', ': ') if indent is None else (',', ': ') # Don't sort if it's already sorted @@ -373,14 +369,14 @@ def log(msg, filters=[], indent=None): print(msg) class Timeout: - def __init__(self, seconds, errmsg = "Timeout"): + def __init__(self, seconds, errmsg="Timeout"): self.seconds = seconds self.errmsg = errmsg def __enter__(self): signal.signal(signal.SIGALRM, self.timeout) signal.setitimer(signal.ITIMER_REAL, self.seconds) return self - def __exit__(self, type, value, traceback): + def __exit__(self, exc_type, value, traceback): signal.setitimer(signal.ITIMER_REAL, 0) return False def timeout(self, signum, frame): @@ -389,7 +385,7 @@ class Timeout: def file_pattern(name): return "{0}-{1}".format(os.getpid(), name) -class FilePaths(object): +class FilePaths: """ FilePaths is an auto-generated filename that cleans itself up. @@ -536,11 +532,11 @@ class VM(qtest.QEMUQtestMachine): self.pause_drive(drive, "write_aio") return self.qmp('human-monitor-command', - command_line='qemu-io %s "break %s bp_%s"' % (drive, event, drive)) + command_line='qemu-io %s "break %s bp_%s"' % (drive, event, drive)) def resume_drive(self, drive): self.qmp('human-monitor-command', - command_line='qemu-io %s "remove_break bp_%s"' % (drive, drive)) + command_line='qemu-io %s "remove_break bp_%s"' % (drive, drive)) def hmp_qemu_io(self, drive, cmd): '''Write to a given drive using an HMP command''' @@ -551,8 +547,8 @@ class VM(qtest.QEMUQtestMachine): if output is None: output = dict() if isinstance(obj, list): - for i in range(len(obj)): - self.flatten_qmp_object(obj[i], output, basestr + str(i) + '.') + for i, item in enumerate(obj): + self.flatten_qmp_object(item, output, basestr + str(i) + '.') elif isinstance(obj, dict): for key in obj: self.flatten_qmp_object(obj[key], output, basestr + key + '.') @@ -710,9 +706,7 @@ class VM(qtest.QEMUQtestMachine): for bitmap in bitmaps[node_name]: if bitmap.get('name', '') == bitmap_name: - if recording is None: - return bitmap - elif bitmap.get('recording') == recording: + if recording is None or bitmap.get('recording') == recording: return bitmap return None @@ -763,12 +757,13 @@ class VM(qtest.QEMUQtestMachine): assert node is not None, 'Cannot follow path %s%s' % (root, path) try: - node_id = next(edge['child'] for edge in graph['edges'] \ - if edge['parent'] == node['id'] and - edge['name'] == child_name) + node_id = next(edge['child'] for edge in graph['edges'] + if (edge['parent'] == node['id'] and + edge['name'] == child_name)) + + node = next(node for node in graph['nodes'] + if node['id'] == node_id) - node = next(node for node in graph['nodes'] \ - if node['id'] == node_id) except StopIteration: node = None @@ -786,6 +781,12 @@ index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') class QMPTestCase(unittest.TestCase): '''Abstract base class for QMP test cases''' + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Many users of this class set a VM property we rely on heavily + # in the methods below. + self.vm = None + def dictpath(self, d, path): '''Traverse a path in a nested dict''' for component in path.split('/'): @@ -831,7 +832,7 @@ class QMPTestCase(unittest.TestCase): else: self.assertEqual(result, value, '"%s" is "%s", expected "%s"' - % (path, str(result), str(value))) + % (path, str(result), str(value))) def assert_no_active_block_jobs(self): result = self.vm.qmp('query-block-jobs') @@ -841,15 +842,15 @@ class QMPTestCase(unittest.TestCase): """Issue a query-named-block-nodes and assert node_name and/or file_name is present in the result""" def check_equal_or_none(a, b): - return a == None or b == None or a == b + return a is None or b is None or a == b assert node_name or file_name result = self.vm.qmp('query-named-block-nodes') for x in result["return"]: if check_equal_or_none(x.get("node-name"), node_name) and \ check_equal_or_none(x.get("file"), file_name): return - self.assertTrue(False, "Cannot find %s %s in result:\n%s" % \ - (node_name, file_name, result)) + self.fail("Cannot find %s %s in result:\n%s" % + (node_name, file_name, result)) def assert_json_filename_equal(self, json_filename, reference): '''Asserts that the given filename is a json: filename and that its @@ -898,13 +899,13 @@ class QMPTestCase(unittest.TestCase): self.assert_qmp(event, 'data/error', error) self.assert_no_active_block_jobs() return event - elif event['event'] == 'JOB_STATUS_CHANGE': + if event['event'] == 'JOB_STATUS_CHANGE': self.assert_qmp(event, 'data/id', drive) def wait_ready(self, drive='drive0'): - '''Wait until a block job BLOCK_JOB_READY event''' - f = {'data': {'type': 'mirror', 'device': drive } } - event = self.vm.event_wait(name='BLOCK_JOB_READY', match=f) + """Wait until a BLOCK_JOB_READY event, and return the event.""" + f = {'data': {'type': 'mirror', 'device': drive}} + return self.vm.event_wait(name='BLOCK_JOB_READY', match=f) def wait_ready_and_cancel(self, drive='drive0'): self.wait_ready(drive=drive) @@ -933,7 +934,7 @@ class QMPTestCase(unittest.TestCase): for job in result['return']: if job['device'] == job_id: found = True - if job['paused'] == True and job['busy'] == False: + if job['paused'] and not job['busy']: return job break assert found @@ -1030,8 +1031,8 @@ def qemu_pipe(*args): universal_newlines=True) exitcode = subp.wait() if exitcode < 0: - sys.stderr.write('qemu received signal %i: %s\n' % (-exitcode, - ' '.join(args))) + sys.stderr.write('qemu received signal %i: %s\n' % + (-exitcode, ' '.join(args))) return subp.communicate()[0] def supported_formats(read_only=False): @@ -1063,6 +1064,7 @@ def skip_if_unsupported(required_formats=[], read_only=False): if usf_list: test_case.case_skip('{}: formats {} are not whitelisted'.format( test_case, usf_list)) + return None else: return func(test_case, *args, **kwargs) return func_wrapper @@ -1074,6 +1076,7 @@ def skip_if_user_is_root(func): def func_wrapper(*args, **kwargs): if os.getuid() == 0: case_notrun('{}: cannot be run as root'.format(args[0])) + return None else: return func(*args, **kwargs) return func_wrapper From 1d3d4b630c6ea8b19420c097f0c448b6ded95072 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:02 -0400 Subject: [PATCH 0243/2595] iotests: don't use 'format' for drive_add MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It shadows (with a different type) the built-in format. Use something else. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Max Reitz Message-Id: <20200331000014.11581-3-jsnow@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/055 | 3 ++- tests/qemu-iotests/iotests.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index 82b9f5f47d..4175fff5e4 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -469,7 +469,8 @@ class TestDriveCompression(iotests.QMPTestCase): qemu_img('create', '-f', fmt, blockdev_target_img, str(TestDriveCompression.image_len), *args) if attach_target: - self.vm.add_drive(blockdev_target_img, format=fmt, interface="none") + self.vm.add_drive(blockdev_target_img, + img_format=fmt, interface="none") self.vm.launch() diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 6f6363f3ec..aca7d50524 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -486,21 +486,21 @@ class VM(qtest.QEMUQtestMachine): self._args.append(opts) return self - def add_drive(self, path, opts='', interface='virtio', format=imgfmt): + def add_drive(self, path, opts='', interface='virtio', img_format=imgfmt): '''Add a virtio-blk drive to the VM''' options = ['if=%s' % interface, 'id=drive%d' % self._num_drives] if path is not None: options.append('file=%s' % path) - options.append('format=%s' % format) + options.append('format=%s' % img_format) options.append('cache=%s' % cachemode) options.append('aio=%s' % aiomode) if opts: options.append(opts) - if format == 'luks' and 'key-secret' not in opts: + if img_format == 'luks' and 'key-secret' not in opts: # default luks support if luks_default_secret_object not in self._args: self.add_object(luks_default_secret_object) From 368e06200320fd1c046788832531c0148ccbdf11 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:03 -0400 Subject: [PATCH 0244/2595] iotests: ignore import warnings from pylint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The right way to solve this is to come up with a virtual environment infrastructure that sets all the paths correctly, and/or to create installable python modules that can be imported normally. That's hard, so just silence this error for now. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Max Reitz Signed-off-by: John Snow Message-Id: <20200331000014.11581-4-jsnow@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index aca7d50524..37a32c7461 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -30,6 +30,7 @@ import io from collections import OrderedDict import faulthandler +# pylint: disable=import-error, wrong-import-position sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu import qtest From 4eabe0515ad7947da566fa52f9bd29e6fc1e6dcc Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:04 -0400 Subject: [PATCH 0245/2595] iotests: replace mutable list default args MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's bad hygiene: if we modify this list, it will be modified across all invocations. (Remaining bad usages are fixed in a subsequent patch which changes the function signature anyway.) Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Max Reitz Message-Id: <20200331000014.11581-5-jsnow@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 37a32c7461..d8dc60275b 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -139,7 +139,7 @@ def qemu_img_log(*args): log(result, filters=[filter_testfiles]) return result -def img_info_log(filename, filter_path=None, imgopts=False, extra_args=[]): +def img_info_log(filename, filter_path=None, imgopts=False, extra_args=()): args = ['info'] if imgopts: args.append('--image-opts') @@ -354,7 +354,7 @@ def filter_qmp_imgfmt(qmsg): return value return filter_qmp(qmsg, _filter) -def log(msg, filters=[], indent=None): +def log(msg, filters=(), indent=None): '''Logs either a string message or a JSON serializable message (like QMP). If indent is provided, JSON serializable messages are pretty-printed.''' for flt in filters: @@ -570,7 +570,7 @@ class VM(qtest.QEMUQtestMachine): result.append(filter_qmp_event(ev)) return result - def qmp_log(self, cmd, filters=[], indent=None, **kwargs): + def qmp_log(self, cmd, filters=(), indent=None, **kwargs): full_cmd = OrderedDict(( ("execute", cmd), ("arguments", ordered_qmp(kwargs)) @@ -974,7 +974,7 @@ def case_notrun(reason): open('%s/%s.casenotrun' % (output_dir, seq), 'a').write( ' [case not run] ' + reason + '\n') -def verify_image_format(supported_fmts=[], unsupported_fmts=[]): +def verify_image_format(supported_fmts=(), unsupported_fmts=()): assert not (supported_fmts and unsupported_fmts) if 'generic' in supported_fmts and \ @@ -988,7 +988,7 @@ def verify_image_format(supported_fmts=[], unsupported_fmts=[]): if not_sup or (imgfmt in unsupported_fmts): notrun('not suitable for this image format: %s' % imgfmt) -def verify_protocol(supported=[], unsupported=[]): +def verify_protocol(supported=(), unsupported=()): assert not (supported and unsupported) if 'generic' in supported: @@ -1007,11 +1007,11 @@ def verify_platform(supported=None, unsupported=None): if not any((sys.platform.startswith(x) for x in supported)): notrun('not suitable for this OS: %s' % sys.platform) -def verify_cache_mode(supported_cache_modes=[]): +def verify_cache_mode(supported_cache_modes=()): if supported_cache_modes and (cachemode not in supported_cache_modes): notrun('not suitable for this cache mode: %s' % cachemode) -def verify_aio_mode(supported_aio_modes=[]): +def verify_aio_mode(supported_aio_modes=()): if supported_aio_modes and (aiomode not in supported_aio_modes): notrun('not suitable for this aio mode: %s' % aiomode) @@ -1051,7 +1051,7 @@ def supported_formats(read_only=False): return supported_formats.formats[read_only] -def skip_if_unsupported(required_formats=[], read_only=False): +def skip_if_unsupported(required_formats=(), read_only=False): '''Skip Test Decorator Runs the test if all the required formats are whitelisted''' def skip_test_decorator(func): @@ -1102,11 +1102,11 @@ def execute_unittest(output, verbosity, debug): sys.stderr.write(out) def execute_test(test_function=None, - supported_fmts=[], + supported_fmts=(), supported_platforms=None, - supported_cache_modes=[], supported_aio_modes={}, - unsupported_fmts=[], supported_protocols=[], - unsupported_protocols=[]): + supported_cache_modes=(), supported_aio_modes=(), + unsupported_fmts=(), supported_protocols=(), + unsupported_protocols=()): """Run either unittest or script-style tests.""" # We are using TEST_DIR and QEMU_DEFAULT_MACHINE as proxies to From 576dc22be11d3cd95eec0e75ec5603cde671a370 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:05 -0400 Subject: [PATCH 0246/2595] iotests: add pylintrc file This allows others to get repeatable results with pylint. If you run `pylint iotests.py`, you should see a 100% pass. Signed-off-by: John Snow Reviewed-by: Max Reitz Message-Id: <20200331000014.11581-6-jsnow@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/pylintrc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/qemu-iotests/pylintrc diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc new file mode 100644 index 0000000000..daec2c4942 --- /dev/null +++ b/tests/qemu-iotests/pylintrc @@ -0,0 +1,22 @@ +[MESSAGES CONTROL] + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=invalid-name, + no-else-return, + too-few-public-methods, + too-many-arguments, + too-many-branches, + too-many-lines, + too-many-locals, + too-many-public-methods, + # These are temporary, and should be removed: + line-too-long, + missing-docstring, From b404b13bd519301c99e603ac660122158ea5b93b Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:06 -0400 Subject: [PATCH 0247/2595] iotests: alphabetize standard imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I had to fix a merge conflict, so do this tiny harmless thing while I'm here. Signed-off-by: John Snow Reviewed-by: Max Reitz Message-Id: <20200331000014.11581-7-jsnow@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index d8dc60275b..dae124872e 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -16,19 +16,19 @@ # along with this program. If not, see . # -import os -import re -import subprocess -import unittest -import sys -import struct -import json -import signal -import logging import atexit -import io from collections import OrderedDict import faulthandler +import io +import json +import logging +import os +import re +import signal +import struct +import subprocess +import sys +import unittest # pylint: disable=import-error, wrong-import-position sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) From 229fc0742a727c1733dd4d0c405c4c590f8dc627 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:07 -0400 Subject: [PATCH 0248/2595] iotests: drop pre-Python 3.4 compatibility code We no longer need to accommodate <3.4, drop this code. (The lines were > 79 chars and it stood out.) Signed-off-by: John Snow Reviewed-by: Max Reitz Message-Id: <20200331000014.11581-8-jsnow@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index dae124872e..374a8f6077 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -360,12 +360,9 @@ def log(msg, filters=(), indent=None): for flt in filters: msg = flt(msg) if isinstance(msg, (dict, list)): - # Python < 3.4 needs to know not to add whitespace when pretty-printing: - separators = (', ', ': ') if indent is None else (',', ': ') # Don't sort if it's already sorted do_sort = not isinstance(msg, OrderedDict) - print(json.dumps(msg, sort_keys=do_sort, - indent=indent, separators=separators)) + print(json.dumps(msg, sort_keys=do_sort, indent=indent)) else: print(msg) From 1cd0dbfc12019fcd5f0529094a939a1557dfc2df Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:08 -0400 Subject: [PATCH 0249/2595] iotests: touch up log function signature Representing nested, recursive data structures in mypy is notoriously difficult; the best we can reliably do right now is denote the leaf types as "Any" while describing the general shape of the data. Regardless, this fully annotates the log() function. Typing notes: TypeVar is a Type variable that can optionally be constrained by a sequence of possible types. This variable is bound to a specific type per-invocation, like a Generic. log() behaves as log() now, where the incoming type informs the signature it expects for any filter arguments passed in. If Msg is a str, then filter should take and return a str. Signed-off-by: John Snow Reviewed-by: Max Reitz Message-Id: <20200331000014.11581-9-jsnow@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 374a8f6077..69f24223d2 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -28,6 +28,7 @@ import signal import struct import subprocess import sys +from typing import (Any, Callable, Dict, Iterable, List, Optional, TypeVar) import unittest # pylint: disable=import-error, wrong-import-position @@ -354,9 +355,16 @@ def filter_qmp_imgfmt(qmsg): return value return filter_qmp(qmsg, _filter) -def log(msg, filters=(), indent=None): - '''Logs either a string message or a JSON serializable message (like QMP). - If indent is provided, JSON serializable messages are pretty-printed.''' + +Msg = TypeVar('Msg', Dict[str, Any], List[Any], str) + +def log(msg: Msg, + filters: Iterable[Callable[[Msg], Msg]] = (), + indent: Optional[int] = None) -> None: + """ + Logs either a string message or a JSON serializable message (like QMP). + If indent is provided, JSON serializable messages are pretty-printed. + """ for flt in filters: msg = flt(msg) if isinstance(msg, (dict, list)): From b031e9a5a65ceef722ba506bc5ee69ec785dc5c5 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:09 -0400 Subject: [PATCH 0250/2595] iotests: limit line length to 79 chars 79 is the PEP8 recommendation. This recommendation works well for reading patch diffs in TUI email clients. Signed-off-by: John Snow Reviewed-by: Max Reitz Message-Id: <20200331000014.11581-10-jsnow@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 64 +++++++++++++++++++++++------------ tests/qemu-iotests/pylintrc | 6 +++- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 69f24223d2..9f5da32dae 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -80,9 +80,11 @@ luks_default_key_secret_opt = 'key-secret=keysec0' def qemu_img(*args): '''Run qemu-img and return the exit code''' devnull = open('/dev/null', 'r+') - exitcode = subprocess.call(qemu_img_args + list(args), stdin=devnull, stdout=devnull) + exitcode = subprocess.call(qemu_img_args + list(args), + stdin=devnull, stdout=devnull) if exitcode < 0: - sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args)))) + sys.stderr.write('qemu-img received signal %i: %s\n' + % (-exitcode, ' '.join(qemu_img_args + list(args)))) return exitcode def ordered_qmp(qmsg, conv_keys=True): @@ -121,7 +123,8 @@ def qemu_img_verbose(*args): '''Run qemu-img without suppressing its output and return the exit code''' exitcode = subprocess.call(qemu_img_args + list(args)) if exitcode < 0: - sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args)))) + sys.stderr.write('qemu-img received signal %i: %s\n' + % (-exitcode, ' '.join(qemu_img_args + list(args)))) return exitcode def qemu_img_pipe(*args): @@ -132,7 +135,8 @@ def qemu_img_pipe(*args): universal_newlines=True) exitcode = subp.wait() if exitcode < 0: - sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args)))) + sys.stderr.write('qemu-img received signal %i: %s\n' + % (-exitcode, ' '.join(qemu_img_args + list(args)))) return subp.communicate()[0] def qemu_img_log(*args): @@ -162,7 +166,8 @@ def qemu_io(*args): universal_newlines=True) exitcode = subp.wait() if exitcode < 0: - sys.stderr.write('qemu-io received signal %i: %s\n' % (-exitcode, ' '.join(args))) + sys.stderr.write('qemu-io received signal %i: %s\n' + % (-exitcode, ' '.join(args))) return subp.communicate()[0] def qemu_io_log(*args): @@ -284,10 +289,13 @@ win32_re = re.compile(r"\r") def filter_win32(msg): return win32_re.sub("", msg) -qemu_io_re = re.compile(r"[0-9]* ops; [0-9\/:. sec]* \([0-9\/.inf]* [EPTGMKiBbytes]*\/sec and [0-9\/.inf]* ops\/sec\)") +qemu_io_re = re.compile(r"[0-9]* ops; [0-9\/:. sec]* " + r"\([0-9\/.inf]* [EPTGMKiBbytes]*\/sec " + r"and [0-9\/.inf]* ops\/sec\)") def filter_qemu_io(msg): msg = filter_win32(msg) - return qemu_io_re.sub("X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)", msg) + return qemu_io_re.sub("X ops; XX:XX:XX.X " + "(XXX YYY/sec and XXX ops/sec)", msg) chown_re = re.compile(r"chown [0-9]+:[0-9]+") def filter_chown(msg): @@ -340,7 +348,9 @@ def filter_img_info(output, filename): line = filter_testfiles(line) line = line.replace(imgfmt, 'IMGFMT') line = re.sub('iters: [0-9]+', 'iters: XXX', line) - line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line) + line = re.sub('uuid: [-a-f0-9]+', + 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', + line) line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line) lines.append(line) return '\n'.join(lines) @@ -538,11 +548,13 @@ class VM(qtest.QEMUQtestMachine): self.pause_drive(drive, "write_aio") return self.qmp('human-monitor-command', - command_line='qemu-io %s "break %s bp_%s"' % (drive, event, drive)) + command_line='qemu-io %s "break %s bp_%s"' + % (drive, event, drive)) def resume_drive(self, drive): self.qmp('human-monitor-command', - command_line='qemu-io %s "remove_break bp_%s"' % (drive, drive)) + command_line='qemu-io %s "remove_break bp_%s"' + % (drive, drive)) def hmp_qemu_io(self, drive, cmd): '''Write to a given drive using an HMP command''' @@ -802,16 +814,18 @@ class QMPTestCase(unittest.TestCase): idx = int(idx) if not isinstance(d, dict) or component not in d: - self.fail('failed path traversal for "%s" in "%s"' % (path, str(d))) + self.fail(f'failed path traversal for "{path}" in "{d}"') d = d[component] if m: if not isinstance(d, list): - self.fail('path component "%s" in "%s" is not a list in "%s"' % (component, path, str(d))) + self.fail(f'path component "{component}" in "{path}" ' + f'is not a list in "{d}"') try: d = d[idx] except IndexError: - self.fail('invalid index "%s" in path "%s" in "%s"' % (idx, path, str(d))) + self.fail(f'invalid index "{idx}" in path "{path}" ' + f'in "{d}"') return d def assert_qmp_absent(self, d, path): @@ -862,10 +876,13 @@ class QMPTestCase(unittest.TestCase): '''Asserts that the given filename is a json: filename and that its content is equal to the given reference object''' self.assertEqual(json_filename[:5], 'json:') - self.assertEqual(self.vm.flatten_qmp_object(json.loads(json_filename[5:])), - self.vm.flatten_qmp_object(reference)) + self.assertEqual( + self.vm.flatten_qmp_object(json.loads(json_filename[5:])), + self.vm.flatten_qmp_object(reference) + ) - def cancel_and_wait(self, drive='drive0', force=False, resume=False, wait=60.0): + def cancel_and_wait(self, drive='drive0', force=False, + resume=False, wait=60.0): '''Cancel a block job and wait for it to finish, returning the event''' result = self.vm.qmp('block-job-cancel', device=drive, force=force) self.assert_qmp(result, 'return', {}) @@ -889,8 +906,8 @@ class QMPTestCase(unittest.TestCase): self.assert_no_active_block_jobs() return result - def wait_until_completed(self, drive='drive0', check_offset=True, wait=60.0, - error=None): + def wait_until_completed(self, drive='drive0', check_offset=True, + wait=60.0, error=None): '''Wait for a block job to finish, returning the event''' while True: for event in self.vm.get_qmp_events(wait=wait): @@ -1029,8 +1046,11 @@ def verify_quorum(): notrun('quorum support missing') def qemu_pipe(*args): - '''Run qemu with an option to print something and exit (e.g. a help option), - and return its output''' + """ + Run qemu with an option to print something and exit (e.g. a help option). + + :return: QEMU's stdout output. + """ args = [qemu_prog] + qemu_opts + list(args) subp = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, @@ -1068,8 +1088,8 @@ def skip_if_unsupported(required_formats=(), read_only=False): usf_list = list(set(fmts) - set(supported_formats(read_only))) if usf_list: - test_case.case_skip('{}: formats {} are not whitelisted'.format( - test_case, usf_list)) + msg = f'{test_case}: formats {usf_list} are not whitelisted' + test_case.case_skip(msg) return None else: return func(test_case, *args, **kwargs) diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc index daec2c4942..5481afe528 100644 --- a/tests/qemu-iotests/pylintrc +++ b/tests/qemu-iotests/pylintrc @@ -18,5 +18,9 @@ disable=invalid-name, too-many-locals, too-many-public-methods, # These are temporary, and should be removed: - line-too-long, missing-docstring, + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=79 From 239bbcc0ae6ba24733839150955bdf8402e9ec55 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:10 -0400 Subject: [PATCH 0251/2595] iotests: add hmp helper with logging Minor cleanup for HMP functions; helps with line length and consolidates HMP helpers through one implementation function. Although we are adding a universal toggle to turn QMP logging on or off, many existing callers to hmp functions don't expect that output to be logged, which causes quite a few changes in the test output. For now, offer a use_log parameter. Typing notes: QMPResponse is just an alias for Dict[str, Any]. It holds no special meanings and it is not a formal subtype of Dict[str, Any]. It is best thought of as a lexical synonym. We may well wish to add stricter subtypes in the future for certain shapes of data that are not formalized as Python objects, at which point we can simply retire the alias and allow mypy to more strictly check usages of the name. Signed-off-by: John Snow Message-Id: <20200331000014.11581-11-jsnow@redhat.com> Reviewed-by: Max Reitz Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 9f5da32dae..cf10c428b5 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -37,6 +37,10 @@ from qemu import qtest assert sys.version_info >= (3, 6) +# Type Aliases +QMPResponse = Dict[str, Any] + + faulthandler.enable() # This will not work if arguments contain spaces but is necessary if we @@ -541,25 +545,30 @@ class VM(qtest.QEMUQtestMachine): self._args.append(addr) return self - def pause_drive(self, drive, event=None): - '''Pause drive r/w operations''' + def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse: + cmd = 'human-monitor-command' + kwargs = {'command-line': command_line} + if use_log: + return self.qmp_log(cmd, **kwargs) + else: + return self.qmp(cmd, **kwargs) + + def pause_drive(self, drive: str, event: Optional[str] = None) -> None: + """Pause drive r/w operations""" if not event: self.pause_drive(drive, "read_aio") self.pause_drive(drive, "write_aio") return - self.qmp('human-monitor-command', - command_line='qemu-io %s "break %s bp_%s"' - % (drive, event, drive)) + self.hmp(f'qemu-io {drive} "break {event} bp_{drive}"') - def resume_drive(self, drive): - self.qmp('human-monitor-command', - command_line='qemu-io %s "remove_break bp_%s"' - % (drive, drive)) + def resume_drive(self, drive: str) -> None: + """Resume drive r/w operations""" + self.hmp(f'qemu-io {drive} "remove_break bp_{drive}"') - def hmp_qemu_io(self, drive, cmd): - '''Write to a given drive using an HMP command''' - return self.qmp('human-monitor-command', - command_line='qemu-io %s "%s"' % (drive, cmd)) + def hmp_qemu_io(self, drive: str, cmd: str, + use_log: bool = False) -> QMPResponse: + """Write to a given drive using an HMP command""" + return self.hmp(f'qemu-io {drive} "{cmd}"', use_log=use_log) def flatten_qmp_object(self, obj, output=None, basestr=''): if output is None: From 7d8140595f1e131935ba1c98a55af7d066660707 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:11 -0400 Subject: [PATCH 0252/2595] iotests: add script_initialize Like script_main, but doesn't require a single point of entry. Replace all existing initialization sections with this drop-in replacement. This brings debug support to all existing script-style iotests. Signed-off-by: John Snow Reviewed-by: Max Reitz Message-Id: <20200331000014.11581-12-jsnow@redhat.com> Reviewed-by: Kevin Wolf [mreitz: Give 274 the same treatment] Signed-off-by: Max Reitz --- tests/qemu-iotests/149 | 3 +- tests/qemu-iotests/194 | 4 +- tests/qemu-iotests/202 | 4 +- tests/qemu-iotests/203 | 4 +- tests/qemu-iotests/206 | 2 +- tests/qemu-iotests/207 | 6 ++- tests/qemu-iotests/208 | 2 +- tests/qemu-iotests/209 | 2 +- tests/qemu-iotests/210 | 6 ++- tests/qemu-iotests/211 | 6 ++- tests/qemu-iotests/212 | 6 ++- tests/qemu-iotests/213 | 6 ++- tests/qemu-iotests/216 | 4 +- tests/qemu-iotests/218 | 2 +- tests/qemu-iotests/219 | 2 +- tests/qemu-iotests/222 | 7 ++-- tests/qemu-iotests/224 | 4 +- tests/qemu-iotests/228 | 6 ++- tests/qemu-iotests/234 | 4 +- tests/qemu-iotests/235 | 4 +- tests/qemu-iotests/236 | 2 +- tests/qemu-iotests/237 | 2 +- tests/qemu-iotests/238 | 2 + tests/qemu-iotests/242 | 2 +- tests/qemu-iotests/246 | 2 +- tests/qemu-iotests/248 | 2 +- tests/qemu-iotests/254 | 2 +- tests/qemu-iotests/255 | 2 +- tests/qemu-iotests/256 | 2 +- tests/qemu-iotests/258 | 7 ++-- tests/qemu-iotests/260 | 4 +- tests/qemu-iotests/262 | 4 +- tests/qemu-iotests/264 | 4 +- tests/qemu-iotests/274 | 4 +- tests/qemu-iotests/277 | 2 + tests/qemu-iotests/280 | 8 ++-- tests/qemu-iotests/283 | 4 +- tests/qemu-iotests/iotests.py | 76 +++++++++++++++++++++++------------ 38 files changed, 132 insertions(+), 83 deletions(-) diff --git a/tests/qemu-iotests/149 b/tests/qemu-iotests/149 index b4a21bf7b7..852768f80a 100755 --- a/tests/qemu-iotests/149 +++ b/tests/qemu-iotests/149 @@ -382,8 +382,7 @@ def test_once(config, qemu_img=False): # Obviously we only work with the luks image format -iotests.verify_image_format(supported_fmts=['luks']) -iotests.verify_platform() +iotests.script_initialize(supported_fmts=['luks']) # We need sudo in order to run cryptsetup to create # dm-crypt devices. This is safe to use on any diff --git a/tests/qemu-iotests/194 b/tests/qemu-iotests/194 index 9dc1bd3510..8b1f720af4 100755 --- a/tests/qemu-iotests/194 +++ b/tests/qemu-iotests/194 @@ -21,8 +21,8 @@ import iotests -iotests.verify_image_format(supported_fmts=['qcow2', 'qed', 'raw']) -iotests.verify_platform(['linux']) +iotests.script_initialize(supported_fmts=['qcow2', 'qed', 'raw'], + supported_platforms=['linux']) with iotests.FilePath('source.img') as source_img_path, \ iotests.FilePath('dest.img') as dest_img_path, \ diff --git a/tests/qemu-iotests/202 b/tests/qemu-iotests/202 index 920a8683ef..e3900a44d1 100755 --- a/tests/qemu-iotests/202 +++ b/tests/qemu-iotests/202 @@ -24,8 +24,8 @@ import iotests -iotests.verify_image_format(supported_fmts=['qcow2']) -iotests.verify_platform(['linux']) +iotests.script_initialize(supported_fmts=['qcow2'], + supported_platforms=['linux']) with iotests.FilePath('disk0.img') as disk0_img_path, \ iotests.FilePath('disk1.img') as disk1_img_path, \ diff --git a/tests/qemu-iotests/203 b/tests/qemu-iotests/203 index 49eff5d405..4b4bd3307d 100755 --- a/tests/qemu-iotests/203 +++ b/tests/qemu-iotests/203 @@ -24,8 +24,8 @@ import iotests -iotests.verify_image_format(supported_fmts=['qcow2']) -iotests.verify_platform(['linux']) +iotests.script_initialize(supported_fmts=['qcow2'], + supported_platforms=['linux']) with iotests.FilePath('disk0.img') as disk0_img_path, \ iotests.FilePath('disk1.img') as disk1_img_path, \ diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206 index e2b50ae24d..f42432a838 100755 --- a/tests/qemu-iotests/206 +++ b/tests/qemu-iotests/206 @@ -23,7 +23,7 @@ import iotests from iotests import imgfmt -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize(supported_fmts=['qcow2']) with iotests.FilePath('t.qcow2') as disk_path, \ iotests.FilePath('t.qcow2.base') as backing_path, \ diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207 index 3d9c1208ca..a6621410da 100755 --- a/tests/qemu-iotests/207 +++ b/tests/qemu-iotests/207 @@ -24,8 +24,10 @@ import iotests import subprocess import re -iotests.verify_image_format(supported_fmts=['raw']) -iotests.verify_protocol(supported=['ssh']) +iotests.script_initialize( + supported_fmts=['raw'], + supported_protocols=['ssh'], +) def filter_hash(qmsg): def _filter(key, value): diff --git a/tests/qemu-iotests/208 b/tests/qemu-iotests/208 index 1c3fc8c7fd..6cb642f821 100755 --- a/tests/qemu-iotests/208 +++ b/tests/qemu-iotests/208 @@ -22,7 +22,7 @@ import iotests -iotests.verify_image_format(supported_fmts=['generic']) +iotests.script_initialize(supported_fmts=['generic']) with iotests.FilePath('disk.img') as disk_img_path, \ iotests.FilePath('disk-snapshot.img') as disk_snapshot_img_path, \ diff --git a/tests/qemu-iotests/209 b/tests/qemu-iotests/209 index 65c1a1e70a..8c804f4a30 100755 --- a/tests/qemu-iotests/209 +++ b/tests/qemu-iotests/209 @@ -22,7 +22,7 @@ import iotests from iotests import qemu_img_create, qemu_io, qemu_img_verbose, qemu_nbd, \ file_path -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize(supported_fmts=['qcow2']) disk = file_path('disk') nbd_sock = file_path('nbd-sock', base_dir=iotests.sock_dir) diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210 index e49896e23d..7bf591f313 100755 --- a/tests/qemu-iotests/210 +++ b/tests/qemu-iotests/210 @@ -23,8 +23,10 @@ import iotests from iotests import imgfmt -iotests.verify_image_format(supported_fmts=['luks']) -iotests.verify_protocol(supported=['file']) +iotests.script_initialize( + supported_fmts=['luks'], + supported_protocols=['file'], +) with iotests.FilePath('t.luks') as disk_path, \ iotests.VM() as vm: diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211 index 163994d559..4969edb00c 100755 --- a/tests/qemu-iotests/211 +++ b/tests/qemu-iotests/211 @@ -23,8 +23,10 @@ import iotests from iotests import imgfmt -iotests.verify_image_format(supported_fmts=['vdi']) -iotests.verify_protocol(supported=['file']) +iotests.script_initialize( + supported_fmts=['vdi'], + supported_protocols=['file'], +) def blockdev_create(vm, options): error = vm.blockdev_create(options) diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212 index 800f92dd84..45d08842bb 100755 --- a/tests/qemu-iotests/212 +++ b/tests/qemu-iotests/212 @@ -23,8 +23,10 @@ import iotests from iotests import imgfmt -iotests.verify_image_format(supported_fmts=['parallels']) -iotests.verify_protocol(supported=['file']) +iotests.script_initialize( + supported_fmts=['parallels'], + supported_protocols=['file'], +) with iotests.FilePath('t.parallels') as disk_path, \ iotests.VM() as vm: diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213 index 1eee45276a..cf638eb927 100755 --- a/tests/qemu-iotests/213 +++ b/tests/qemu-iotests/213 @@ -23,8 +23,10 @@ import iotests from iotests import imgfmt -iotests.verify_image_format(supported_fmts=['vhdx']) -iotests.verify_protocol(supported=['file']) +iotests.script_initialize( + supported_fmts=['vhdx'], + supported_protocols=['file'], +) with iotests.FilePath('t.vhdx') as disk_path, \ iotests.VM() as vm: diff --git a/tests/qemu-iotests/216 b/tests/qemu-iotests/216 index 372f042d3e..de11d85b5d 100755 --- a/tests/qemu-iotests/216 +++ b/tests/qemu-iotests/216 @@ -23,8 +23,8 @@ import iotests from iotests import log, qemu_img, qemu_io_silent # Need backing file support -iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk']) -iotests.verify_platform(['linux']) +iotests.script_initialize(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk'], + supported_platforms=['linux']) log('') log('=== Copy-on-read across nodes ===') diff --git a/tests/qemu-iotests/218 b/tests/qemu-iotests/218 index 1325ba9eaa..5586870456 100755 --- a/tests/qemu-iotests/218 +++ b/tests/qemu-iotests/218 @@ -29,7 +29,7 @@ import iotests from iotests import log, qemu_img, qemu_io_silent -iotests.verify_image_format(supported_fmts=['qcow2', 'raw']) +iotests.script_initialize(supported_fmts=['qcow2', 'raw']) # Launches the VM, adds two null-co nodes (source and target), and diff --git a/tests/qemu-iotests/219 b/tests/qemu-iotests/219 index b8774770c4..db272c5249 100755 --- a/tests/qemu-iotests/219 +++ b/tests/qemu-iotests/219 @@ -21,7 +21,7 @@ import iotests -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize(supported_fmts=['qcow2']) img_size = 4 * 1024 * 1024 diff --git a/tests/qemu-iotests/222 b/tests/qemu-iotests/222 index bf1718e179..6602f6b4ba 100755 --- a/tests/qemu-iotests/222 +++ b/tests/qemu-iotests/222 @@ -24,9 +24,10 @@ import iotests from iotests import log, qemu_img, qemu_io, qemu_io_silent -iotests.verify_platform(['linux']) -iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk', - 'vhdx', 'raw']) +iotests.script_initialize( + supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk', 'vhdx', 'raw'], + supported_platforms=['linux'], +) patterns = [("0x5d", "0", "64k"), ("0xd5", "1M", "64k"), diff --git a/tests/qemu-iotests/224 b/tests/qemu-iotests/224 index e91fb26fd8..81ca1e4898 100755 --- a/tests/qemu-iotests/224 +++ b/tests/qemu-iotests/224 @@ -26,8 +26,8 @@ from iotests import log, qemu_img, qemu_io_silent, filter_qmp_testfiles, \ import json # Need backing file support (for arbitrary backing formats) -iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed']) -iotests.verify_platform(['linux']) +iotests.script_initialize(supported_fmts=['qcow2', 'qcow', 'qed'], + supported_platforms=['linux']) # There are two variations of this test: diff --git a/tests/qemu-iotests/228 b/tests/qemu-iotests/228 index 64bc82ee23..da0900fb82 100755 --- a/tests/qemu-iotests/228 +++ b/tests/qemu-iotests/228 @@ -25,8 +25,10 @@ from iotests import log, qemu_img, filter_testfiles, filter_imgfmt, \ filter_qmp_testfiles, filter_qmp_imgfmt # Need backing file and change-backing-file support -iotests.verify_image_format(supported_fmts=['qcow2', 'qed']) -iotests.verify_platform(['linux']) +iotests.script_initialize( + supported_fmts=['qcow2', 'qed'], + supported_platforms=['linux'], +) def log_node_info(node): diff --git a/tests/qemu-iotests/234 b/tests/qemu-iotests/234 index 324c1549fd..73c899ddae 100755 --- a/tests/qemu-iotests/234 +++ b/tests/qemu-iotests/234 @@ -23,8 +23,8 @@ import iotests import os -iotests.verify_image_format(supported_fmts=['qcow2']) -iotests.verify_platform(['linux']) +iotests.script_initialize(supported_fmts=['qcow2'], + supported_platforms=['linux']) with iotests.FilePath('img') as img_path, \ iotests.FilePath('backing') as backing_path, \ diff --git a/tests/qemu-iotests/235 b/tests/qemu-iotests/235 index 760826128e..d1b10ac36b 100755 --- a/tests/qemu-iotests/235 +++ b/tests/qemu-iotests/235 @@ -27,6 +27,8 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu.machine import QEMUMachine +iotests.script_initialize(supported_fmts=['qcow2']) + # Note: # This test was added to check that mirror dead-lock was fixed (see previous # commit before this test addition). @@ -40,8 +42,6 @@ from qemu.machine import QEMUMachine size = 1 * 1024 * 1024 * 1024 -iotests.verify_image_format(supported_fmts=['qcow2']) - disk = file_path('disk') # prepare source image diff --git a/tests/qemu-iotests/236 b/tests/qemu-iotests/236 index 8ce927a16c..6f5cee2444 100755 --- a/tests/qemu-iotests/236 +++ b/tests/qemu-iotests/236 @@ -22,7 +22,7 @@ import iotests from iotests import log -iotests.verify_image_format(supported_fmts=['generic']) +iotests.script_initialize(supported_fmts=['generic']) size = 64 * 1024 * 1024 granularity = 64 * 1024 diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237 index 50ba364a3e..5b21ad3509 100755 --- a/tests/qemu-iotests/237 +++ b/tests/qemu-iotests/237 @@ -24,7 +24,7 @@ import math import iotests from iotests import imgfmt -iotests.verify_image_format(supported_fmts=['vmdk']) +iotests.script_initialize(supported_fmts=['vmdk']) with iotests.FilePath('t.vmdk') as disk_path, \ iotests.FilePath('t.vmdk.1') as extent1_path, \ diff --git a/tests/qemu-iotests/238 b/tests/qemu-iotests/238 index d4e060228c..b8fcf15a1f 100755 --- a/tests/qemu-iotests/238 +++ b/tests/qemu-iotests/238 @@ -23,6 +23,8 @@ import os import iotests from iotests import log +iotests.script_initialize() + virtio_scsi_device = iotests.get_virtio_scsi_device() vm = iotests.VM() diff --git a/tests/qemu-iotests/242 b/tests/qemu-iotests/242 index 97617876bc..64f1bd95e4 100755 --- a/tests/qemu-iotests/242 +++ b/tests/qemu-iotests/242 @@ -24,7 +24,7 @@ import struct from iotests import qemu_img_create, qemu_io, qemu_img_pipe, \ file_path, img_info_log, log, filter_qemu_io -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize(supported_fmts=['qcow2']) disk = file_path('disk') chunk = 256 * 1024 diff --git a/tests/qemu-iotests/246 b/tests/qemu-iotests/246 index 59a216a839..58a479cc1f 100755 --- a/tests/qemu-iotests/246 +++ b/tests/qemu-iotests/246 @@ -22,7 +22,7 @@ import iotests from iotests import log -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize(supported_fmts=['qcow2']) size = 64 * 1024 * 1024 * 1024 gran_small = 32 * 1024 gran_large = 128 * 1024 diff --git a/tests/qemu-iotests/248 b/tests/qemu-iotests/248 index 68c374692e..18ba03467e 100755 --- a/tests/qemu-iotests/248 +++ b/tests/qemu-iotests/248 @@ -21,7 +21,7 @@ import iotests from iotests import qemu_img_create, qemu_io, file_path, filter_qmp_testfiles -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize(supported_fmts=['qcow2']) source, target = file_path('source', 'target') size = 5 * 1024 * 1024 diff --git a/tests/qemu-iotests/254 b/tests/qemu-iotests/254 index ee66c986db..150e58be8e 100755 --- a/tests/qemu-iotests/254 +++ b/tests/qemu-iotests/254 @@ -21,7 +21,7 @@ import iotests from iotests import qemu_img_create, file_path, log -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize(supported_fmts=['qcow2']) disk, top = file_path('disk', 'top') size = 1024 * 1024 diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255 index 4a4818bafb..8f08f741da 100755 --- a/tests/qemu-iotests/255 +++ b/tests/qemu-iotests/255 @@ -23,7 +23,7 @@ import iotests from iotests import imgfmt -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize(supported_fmts=['qcow2']) iotests.log('Finishing a commit job with background reads') iotests.log('============================================') diff --git a/tests/qemu-iotests/256 b/tests/qemu-iotests/256 index e34074c83e..db8d6f31cf 100755 --- a/tests/qemu-iotests/256 +++ b/tests/qemu-iotests/256 @@ -23,7 +23,7 @@ import os import iotests from iotests import log -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize(supported_fmts=['qcow2']) size = 64 * 1024 * 1024 with iotests.FilePath('img0') as img0_path, \ diff --git a/tests/qemu-iotests/258 b/tests/qemu-iotests/258 index 091755a45c..a65151dda6 100755 --- a/tests/qemu-iotests/258 +++ b/tests/qemu-iotests/258 @@ -24,9 +24,10 @@ from iotests import log, qemu_img, qemu_io_silent, \ filter_qmp_testfiles, filter_qmp_imgfmt # Need backing file and change-backing-file support -iotests.verify_image_format(supported_fmts=['qcow2', 'qed']) -iotests.verify_platform(['linux']) - +iotests.script_initialize( + supported_fmts=['qcow2', 'qed'], + supported_platforms=['linux'], +) # Returns a node for blockdev-add def node(node_name, path, backing=None, fmt=None, throttle=None): diff --git a/tests/qemu-iotests/260 b/tests/qemu-iotests/260 index 30c0de380d..804a7addb9 100755 --- a/tests/qemu-iotests/260 +++ b/tests/qemu-iotests/260 @@ -21,7 +21,9 @@ import iotests from iotests import qemu_img_create, file_path, log, filter_qmp_event -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize( + supported_fmts=['qcow2'] +) base, top = file_path('base', 'top') size = 64 * 1024 * 3 diff --git a/tests/qemu-iotests/262 b/tests/qemu-iotests/262 index 8835dce7be..03af061f94 100755 --- a/tests/qemu-iotests/262 +++ b/tests/qemu-iotests/262 @@ -23,8 +23,8 @@ import iotests import os -iotests.verify_image_format(supported_fmts=['qcow2']) -iotests.verify_platform(['linux']) +iotests.script_initialize(supported_fmts=['qcow2'], + supported_platforms=['linux']) with iotests.FilePath('img') as img_path, \ iotests.FilePath('mig_fifo') as fifo, \ diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264 index 879123a343..304a7443d7 100755 --- a/tests/qemu-iotests/264 +++ b/tests/qemu-iotests/264 @@ -24,7 +24,9 @@ import iotests from iotests import qemu_img_create, qemu_io_silent_check, file_path, \ qemu_nbd_popen, log -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize( + supported_fmts=['qcow2'], +) disk_a, disk_b, nbd_sock = file_path('disk_a', 'disk_b', 'nbd-sock') nbd_uri = 'nbd+unix:///?socket=' + nbd_sock diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274 index e951f723b8..5d1bf34dff 100755 --- a/tests/qemu-iotests/274 +++ b/tests/qemu-iotests/274 @@ -21,8 +21,8 @@ import iotests -iotests.verify_image_format(supported_fmts=['qcow2']) -iotests.verify_platform(['linux']) +iotests.script_initialize(supported_fmts=['qcow2'], + supported_platforms=['linux']) size_short = 1 * 1024 * 1024 size_long = 2 * 1024 * 1024 diff --git a/tests/qemu-iotests/277 b/tests/qemu-iotests/277 index 04aa15a3d5..d34f87021f 100755 --- a/tests/qemu-iotests/277 +++ b/tests/qemu-iotests/277 @@ -23,6 +23,8 @@ import subprocess import iotests from iotests import file_path, log +iotests.script_initialize() + nbd_sock, conf_file = file_path('nbd-sock', 'nbd-fault-injector.conf') diff --git a/tests/qemu-iotests/280 b/tests/qemu-iotests/280 index 69288fdd0e..f594bb9ed2 100755 --- a/tests/qemu-iotests/280 +++ b/tests/qemu-iotests/280 @@ -22,9 +22,11 @@ import iotests import os -iotests.verify_image_format(supported_fmts=['qcow2']) -iotests.verify_protocol(supported=['file']) -iotests.verify_platform(['linux']) +iotests.script_initialize( + supported_fmts=['qcow2'], + supported_protocols=['file'], + supported_platforms=['linux'], +) with iotests.FilePath('base') as base_path , \ iotests.FilePath('top') as top_path, \ diff --git a/tests/qemu-iotests/283 b/tests/qemu-iotests/283 index 55b7cff953..e17b953333 100644 --- a/tests/qemu-iotests/283 +++ b/tests/qemu-iotests/283 @@ -21,7 +21,9 @@ import iotests # The test is unrelated to formats, restrict it to qcow2 to avoid extra runs -iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.script_initialize( + supported_fmts=['qcow2'], +) size = 1024 * 1024 diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index cf10c428b5..9f85e1fba3 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -28,7 +28,8 @@ import signal import struct import subprocess import sys -from typing import (Any, Callable, Dict, Iterable, List, Optional, TypeVar) +from typing import (Any, Callable, Dict, Iterable, + List, Optional, Sequence, TypeVar) import unittest # pylint: disable=import-error, wrong-import-position @@ -1029,12 +1030,11 @@ def verify_protocol(supported=(), unsupported=()): if not_sup or (imgproto in unsupported): notrun('not suitable for this protocol: %s' % imgproto) -def verify_platform(supported=None, unsupported=None): - if unsupported is not None: - if any((sys.platform.startswith(x) for x in unsupported)): - notrun('not suitable for this OS: %s' % sys.platform) +def verify_platform(supported=(), unsupported=()): + if any((sys.platform.startswith(x) for x in unsupported)): + notrun('not suitable for this OS: %s' % sys.platform) - if supported is not None: + if supported: if not any((sys.platform.startswith(x) for x in supported)): notrun('not suitable for this OS: %s' % sys.platform) @@ -1116,7 +1116,18 @@ def skip_if_user_is_root(func): return func(*args, **kwargs) return func_wrapper -def execute_unittest(output, verbosity, debug): +def execute_unittest(debug=False): + """Executes unittests within the calling module.""" + + verbosity = 2 if debug else 1 + + if debug: + output = sys.stdout + else: + # We need to filter out the time taken from the output so that + # qemu-iotest can reliably diff the results against master output. + output = io.StringIO() + runner = unittest.TextTestRunner(stream=output, descriptions=True, verbosity=verbosity) try: @@ -1124,6 +1135,8 @@ def execute_unittest(output, verbosity, debug): # exception unittest.main(testRunner=runner) finally: + # We need to filter out the time taken from the output so that + # qemu-iotest can reliably diff the results against master output. if not debug: out = output.getvalue() out = re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', out) @@ -1135,13 +1148,19 @@ def execute_unittest(output, verbosity, debug): sys.stderr.write(out) -def execute_test(test_function=None, - supported_fmts=(), - supported_platforms=None, - supported_cache_modes=(), supported_aio_modes=(), - unsupported_fmts=(), supported_protocols=(), - unsupported_protocols=()): - """Run either unittest or script-style tests.""" +def execute_setup_common(supported_fmts: Sequence[str] = (), + supported_platforms: Sequence[str] = (), + supported_cache_modes: Sequence[str] = (), + supported_aio_modes: Sequence[str] = (), + unsupported_fmts: Sequence[str] = (), + supported_protocols: Sequence[str] = (), + unsupported_protocols: Sequence[str] = ()) -> bool: + """ + Perform necessary setup for either script-style or unittest-style tests. + + :return: Bool; Whether or not debug mode has been requested via the CLI. + """ + # Note: Python 3.6 and pylint do not like 'Collection' so use 'Sequence'. # We are using TEST_DIR and QEMU_DEFAULT_MACHINE as proxies to # indicate that we're not being run via "check". There may be @@ -1151,34 +1170,39 @@ def execute_test(test_function=None, sys.stderr.write('Please run this test via the "check" script\n') sys.exit(os.EX_USAGE) - debug = '-d' in sys.argv - verbosity = 1 verify_image_format(supported_fmts, unsupported_fmts) verify_protocol(supported_protocols, unsupported_protocols) verify_platform(supported=supported_platforms) verify_cache_mode(supported_cache_modes) verify_aio_mode(supported_aio_modes) + debug = '-d' in sys.argv if debug: - output = sys.stdout - verbosity = 2 sys.argv.remove('-d') - else: - # We need to filter out the time taken from the output so that - # qemu-iotest can reliably diff the results against master output. - output = io.StringIO() - logging.basicConfig(level=(logging.DEBUG if debug else logging.WARN)) + return debug + +def execute_test(*args, test_function=None, **kwargs): + """Run either unittest or script-style tests.""" + + debug = execute_setup_common(*args, **kwargs) if not test_function: - execute_unittest(output, verbosity, debug) + execute_unittest(debug) else: test_function() +# This is called from script-style iotests without a single point of entry +def script_initialize(*args, **kwargs): + """Initialize script-style tests without running any tests.""" + execute_setup_common(*args, **kwargs) + +# This is called from script-style iotests with a single point of entry def script_main(test_function, *args, **kwargs): """Run script-style tests outside of the unittest framework""" - execute_test(test_function, *args, **kwargs) + execute_test(*args, test_function=test_function, **kwargs) +# This is called from unittest style iotests def main(*args, **kwargs): """Run tests using the unittest framework""" - execute_test(None, *args, **kwargs) + execute_test(*args, **kwargs) From 5e089feb93e1c0ce55a5900b00b03d772587c396 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:12 -0400 Subject: [PATCH 0253/2595] iotest 258: use script_main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since this one is nicely factored to use a single entry point, use script_main to run the tests. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Max Reitz Message-Id: <20200331000014.11581-13-jsnow@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/258 | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/qemu-iotests/258 b/tests/qemu-iotests/258 index a65151dda6..e305a1502f 100755 --- a/tests/qemu-iotests/258 +++ b/tests/qemu-iotests/258 @@ -23,12 +23,6 @@ import iotests from iotests import log, qemu_img, qemu_io_silent, \ filter_qmp_testfiles, filter_qmp_imgfmt -# Need backing file and change-backing-file support -iotests.script_initialize( - supported_fmts=['qcow2', 'qed'], - supported_platforms=['linux'], -) - # Returns a node for blockdev-add def node(node_name, path, backing=None, fmt=None, throttle=None): if fmt is None: @@ -161,4 +155,7 @@ def main(): test_concurrent_finish(False) if __name__ == '__main__': - main() + # Need backing file and change-backing-file support + iotests.script_main(main, + supported_fmts=['qcow2', 'qed'], + supported_platforms=['linux']) From 59c29869e0c5e8875edc50a0e3073eeaa8fe6143 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:13 -0400 Subject: [PATCH 0254/2595] iotests: Mark verify functions as private Mark the verify functions as "private" with a leading underscore, to discourage their use. Update type signatures while we're here. (Also, make pending patches not yet using the new entry points fail in a very obvious way.) Signed-off-by: John Snow Message-Id: <20200331000014.11581-14-jsnow@redhat.com> Reviewed-by: Max Reitz Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 9f85e1fba3..35d8cae997 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -1006,7 +1006,8 @@ def case_notrun(reason): open('%s/%s.casenotrun' % (output_dir, seq), 'a').write( ' [case not run] ' + reason + '\n') -def verify_image_format(supported_fmts=(), unsupported_fmts=()): +def _verify_image_format(supported_fmts: Sequence[str] = (), + unsupported_fmts: Sequence[str] = ()) -> None: assert not (supported_fmts and unsupported_fmts) if 'generic' in supported_fmts and \ @@ -1020,7 +1021,8 @@ def verify_image_format(supported_fmts=(), unsupported_fmts=()): if not_sup or (imgfmt in unsupported_fmts): notrun('not suitable for this image format: %s' % imgfmt) -def verify_protocol(supported=(), unsupported=()): +def _verify_protocol(supported: Sequence[str] = (), + unsupported: Sequence[str] = ()) -> None: assert not (supported and unsupported) if 'generic' in supported: @@ -1030,7 +1032,8 @@ def verify_protocol(supported=(), unsupported=()): if not_sup or (imgproto in unsupported): notrun('not suitable for this protocol: %s' % imgproto) -def verify_platform(supported=(), unsupported=()): +def _verify_platform(supported: Sequence[str] = (), + unsupported: Sequence[str] = ()) -> None: if any((sys.platform.startswith(x) for x in unsupported)): notrun('not suitable for this OS: %s' % sys.platform) @@ -1038,11 +1041,11 @@ def verify_platform(supported=(), unsupported=()): if not any((sys.platform.startswith(x) for x in supported)): notrun('not suitable for this OS: %s' % sys.platform) -def verify_cache_mode(supported_cache_modes=()): +def _verify_cache_mode(supported_cache_modes: Sequence[str] = ()) -> None: if supported_cache_modes and (cachemode not in supported_cache_modes): notrun('not suitable for this cache mode: %s' % cachemode) -def verify_aio_mode(supported_aio_modes=()): +def _verify_aio_mode(supported_aio_modes: Sequence[str] = ()): if supported_aio_modes and (aiomode not in supported_aio_modes): notrun('not suitable for this aio mode: %s' % aiomode) @@ -1170,11 +1173,11 @@ def execute_setup_common(supported_fmts: Sequence[str] = (), sys.stderr.write('Please run this test via the "check" script\n') sys.exit(os.EX_USAGE) - verify_image_format(supported_fmts, unsupported_fmts) - verify_protocol(supported_protocols, unsupported_protocols) - verify_platform(supported=supported_platforms) - verify_cache_mode(supported_cache_modes) - verify_aio_mode(supported_aio_modes) + _verify_image_format(supported_fmts, unsupported_fmts) + _verify_protocol(supported_protocols, unsupported_protocols) + _verify_platform(supported=supported_platforms) + _verify_cache_mode(supported_cache_modes) + _verify_aio_mode(supported_aio_modes) debug = '-d' in sys.argv if debug: From 52ea799e9631ff00c230f1fed50986246149d8f2 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 30 Mar 2020 20:00:14 -0400 Subject: [PATCH 0255/2595] iotests: use python logging for iotests.log() We can turn logging on/off globally instead of per-function. Remove use_log from run_job, and use python logging to turn on diffable output when we run through a script entry point. iotest 245 changes output order due to buffering reasons. An extended note on python logging: A NullHandler is added to `qemu.iotests` to stop output from being generated if this code is used as a library without configuring logging. A NullHandler is only needed at the root, so a duplicate handler is not needed for `qemu.iotests.diff_io`. When logging is not configured, messages at the 'WARNING' levels or above are printed with default settings. The NullHandler stops this from occurring, which is considered good hygiene for code used as a library. See https://docs.python.org/3/howto/logging.html#library-config When logging is actually enabled (always at the behest of an explicit call by a client script), a root logger is implicitly created at the root, which allows messages to propagate upwards and be handled/emitted from the root logger with default settings. When we want iotest logging, we attach a handler to the qemu.iotests.diff_io logger and disable propagation to avoid possible double-printing. For more information on python logging infrastructure, I highly recommend downloading the pip package `logging_tree`, which provides convenient visualizations of the hierarchical logging configuration under different circumstances. See https://pypi.org/project/logging_tree/ for more information. Signed-off-by: John Snow Reviewed-by: Max Reitz Message-Id: <20200331000014.11581-15-jsnow@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/030 | 4 +-- tests/qemu-iotests/155 | 2 +- tests/qemu-iotests/245 | 1 + tests/qemu-iotests/245.out | 10 +++---- tests/qemu-iotests/iotests.py | 53 ++++++++++++++++++++--------------- 5 files changed, 39 insertions(+), 31 deletions(-) diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index aa911d266a..104e3cee1b 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -411,8 +411,8 @@ class TestParallelOps(iotests.QMPTestCase): result = self.vm.qmp('block-job-set-speed', device='drive0', speed=0) self.assert_qmp(result, 'return', {}) - self.vm.run_job(job='drive0', auto_dismiss=True, use_log=False) - self.vm.run_job(job='node4', auto_dismiss=True, use_log=False) + self.vm.run_job(job='drive0', auto_dismiss=True) + self.vm.run_job(job='node4', auto_dismiss=True) self.assert_no_active_block_jobs() # Test a block-stream and a block-commit job in parallel diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155 index 571bce9de4..cb371d4649 100755 --- a/tests/qemu-iotests/155 +++ b/tests/qemu-iotests/155 @@ -188,7 +188,7 @@ class MirrorBaseClass(BaseClass): self.assert_qmp(result, 'return', {}) - self.vm.run_job('mirror-job', use_log=False, auto_finalize=False, + self.vm.run_job('mirror-job', auto_finalize=False, pre_finalize=self.openBacking, auto_dismiss=True) def testFull(self): diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245 index 1001275a44..4f5f0bb901 100755 --- a/tests/qemu-iotests/245 +++ b/tests/qemu-iotests/245 @@ -1027,5 +1027,6 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.run_test_iothreads(None, 'iothread0') if __name__ == '__main__': + iotests.activate_logging() iotests.main(supported_fmts=["qcow2"], supported_protocols=["file"]) diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out index 682b93394d..4b33dcaf5c 100644 --- a/tests/qemu-iotests/245.out +++ b/tests/qemu-iotests/245.out @@ -1,8 +1,3 @@ -..................... ----------------------------------------------------------------------- -Ran 21 tests - -OK {"execute": "job-finalize", "arguments": {"id": "commit0"}} {"return": {}} {"data": {"id": "commit0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} @@ -15,3 +10,8 @@ OK {"return": {}} {"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +..................... +---------------------------------------------------------------------- +Ran 21 tests + +OK diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 35d8cae997..6c0e781af7 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -42,6 +42,14 @@ assert sys.version_info >= (3, 6) QMPResponse = Dict[str, Any] +# Use this logger for logging messages directly from the iotests module +logger = logging.getLogger('qemu.iotests') +logger.addHandler(logging.NullHandler()) + +# Use this logger for messages that ought to be used for diff output. +test_logger = logging.getLogger('qemu.iotests.diff_io') + + faulthandler.enable() # This will not work if arguments contain spaces but is necessary if we @@ -385,9 +393,9 @@ def log(msg: Msg, if isinstance(msg, (dict, list)): # Don't sort if it's already sorted do_sort = not isinstance(msg, OrderedDict) - print(json.dumps(msg, sort_keys=do_sort, indent=indent)) + test_logger.info(json.dumps(msg, sort_keys=do_sort, indent=indent)) else: - print(msg) + test_logger.info(msg) class Timeout: def __init__(self, seconds, errmsg="Timeout"): @@ -609,7 +617,7 @@ class VM(qtest.QEMUQtestMachine): # Returns None on success, and an error string on failure def run_job(self, job, auto_finalize=True, auto_dismiss=False, - pre_finalize=None, cancel=False, use_log=True, wait=60.0): + pre_finalize=None, cancel=False, wait=60.0): """ run_job moves a job from creation through to dismissal. @@ -622,7 +630,6 @@ class VM(qtest.QEMUQtestMachine): invoked prior to issuing job-finalize, if any. :param cancel: Bool. When true, cancels the job after the pre_finalize callback. - :param use_log: Bool. When false, does not log QMP messages. :param wait: Float. Timeout value specifying how long to wait for any event, in seconds. Defaults to 60.0. """ @@ -640,8 +647,7 @@ class VM(qtest.QEMUQtestMachine): while True: ev = filter_qmp_event(self.events_wait(events, timeout=wait)) if ev['event'] != 'JOB_STATUS_CHANGE': - if use_log: - log(ev) + log(ev) continue status = ev['data']['status'] if status == 'aborting': @@ -649,29 +655,18 @@ class VM(qtest.QEMUQtestMachine): for j in result['return']: if j['id'] == job: error = j['error'] - if use_log: - log('Job failed: %s' % (j['error'])) + log('Job failed: %s' % (j['error'])) elif status == 'ready': - if use_log: - self.qmp_log('job-complete', id=job) - else: - self.qmp('job-complete', id=job) + self.qmp_log('job-complete', id=job) elif status == 'pending' and not auto_finalize: if pre_finalize: pre_finalize() - if cancel and use_log: + if cancel: self.qmp_log('job-cancel', id=job) - elif cancel: - self.qmp('job-cancel', id=job) - elif use_log: + else: self.qmp_log('job-finalize', id=job) - else: - self.qmp('job-finalize', id=job) elif status == 'concluded' and not auto_dismiss: - if use_log: - self.qmp_log('job-dismiss', id=job) - else: - self.qmp('job-dismiss', id=job) + self.qmp_log('job-dismiss', id=job) elif status == 'null': return error @@ -991,7 +986,7 @@ def notrun(reason): seq = os.path.basename(sys.argv[0]) open('%s/%s.notrun' % (output_dir, seq), 'w').write(reason + '\n') - print('%s not run: %s' % (seq, reason)) + logger.warning("%s not run: %s", seq, reason) sys.exit(0) def case_notrun(reason): @@ -1183,6 +1178,7 @@ def execute_setup_common(supported_fmts: Sequence[str] = (), if debug: sys.argv.remove('-d') logging.basicConfig(level=(logging.DEBUG if debug else logging.WARN)) + logger.debug("iotests debugging messages active") return debug @@ -1195,14 +1191,25 @@ def execute_test(*args, test_function=None, **kwargs): else: test_function() +def activate_logging(): + """Activate iotests.log() output to stdout for script-style tests.""" + handler = logging.StreamHandler(stream=sys.stdout) + formatter = logging.Formatter('%(message)s') + handler.setFormatter(formatter) + test_logger.addHandler(handler) + test_logger.setLevel(logging.INFO) + test_logger.propagate = False + # This is called from script-style iotests without a single point of entry def script_initialize(*args, **kwargs): """Initialize script-style tests without running any tests.""" + activate_logging() execute_setup_common(*args, **kwargs) # This is called from script-style iotests with a single point of entry def script_main(test_function, *args, **kwargs): """Run script-style tests outside of the unittest framework""" + activate_logging() execute_test(*args, test_function=test_function, **kwargs) # This is called from unittest style iotests From a3aeeab557f08285c4fcf537fca575b069eb67ef Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 14:26:46 -0500 Subject: [PATCH 0256/2595] block: Add blk_new_with_bs() helper There are several callers that need to create a new block backend from an existing BDS; make the task slightly easier with a common helper routine. Suggested-by: Max Reitz Signed-off-by: Eric Blake Message-Id: <20200424190903.522087-2-eblake@redhat.com> [mreitz: Set @ret only in error paths, see https://lists.nongnu.org/archive/html/qemu-block/2020-04/msg01216.html] Signed-off-by: Max Reitz Message-Id: <20200428192648.749066-2-eblake@redhat.com> Signed-off-by: Max Reitz --- block/block-backend.c | 23 +++++++++++++++++++++++ block/crypto.c | 9 ++++----- block/parallels.c | 8 ++++---- block/qcow.c | 8 ++++---- block/qcow2.c | 18 ++++++++---------- block/qed.c | 8 ++++---- block/sheepdog.c | 10 +++++----- block/vdi.c | 8 ++++---- block/vhdx.c | 8 ++++---- block/vmdk.c | 9 ++++----- block/vpc.c | 8 ++++---- blockdev.c | 8 +++----- blockjob.c | 7 ++----- include/sysemu/block-backend.h | 2 ++ 14 files changed, 75 insertions(+), 59 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index 17ed6d8c5b..f4944861fa 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -355,6 +355,29 @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm) return blk; } +/* + * Create a new BlockBackend connected to an existing BlockDriverState. + * + * @perm is a bitmasks of BLK_PERM_* constants which describes the + * permissions to request for @bs that is attached to this + * BlockBackend. @shared_perm is a bitmask which describes which + * permissions may be granted to other users of the attached node. + * Both sets of permissions can be changed later using blk_set_perm(). + * + * Return the new BlockBackend on success, null on failure. + */ +BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm, + uint64_t shared_perm, Error **errp) +{ + BlockBackend *blk = blk_new(bdrv_get_aio_context(bs), perm, shared_perm); + + if (blk_insert_bs(blk, bs, errp) < 0) { + blk_unref(blk); + return NULL; + } + return blk; +} + /* * Creates a new BlockBackend, opens a new BlockDriverState, and connects both. * The new BlockBackend is in the main AioContext. diff --git a/block/crypto.c b/block/crypto.c index e02f343590..ca44dae4f7 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -261,11 +261,10 @@ static int block_crypto_co_create_generic(BlockDriverState *bs, QCryptoBlock *crypto = NULL; struct BlockCryptoCreateData data; - blk = blk_new(bdrv_get_aio_context(bs), - BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); - - ret = blk_insert_bs(blk, bs, errp); - if (ret < 0) { + blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); + if (!blk) { + ret = -EPERM; goto cleanup; } diff --git a/block/parallels.c b/block/parallels.c index 2be92cf417..8db64a55e3 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -559,10 +559,10 @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts, return -EIO; } - blk = blk_new(bdrv_get_aio_context(bs), - BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs, errp); - if (ret < 0) { + blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); + if (!blk) { + ret = -EPERM; goto out; } blk_set_allow_write_beyond_eof(blk, true); diff --git a/block/qcow.c b/block/qcow.c index 6b5f2269f0..b0475b73a5 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -849,10 +849,10 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts, return -EIO; } - qcow_blk = blk_new(bdrv_get_aio_context(bs), - BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); - ret = blk_insert_bs(qcow_blk, bs, errp); - if (ret < 0) { + qcow_blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, + BLK_PERM_ALL, errp); + if (!qcow_blk) { + ret = -EPERM; goto exit; } blk_set_allow_write_beyond_eof(qcow_blk, true); diff --git a/block/qcow2.c b/block/qcow2.c index 2ba0b17c39..0edc7f4643 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3405,10 +3405,10 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } /* Create BlockBackend to write to the image */ - blk = blk_new(bdrv_get_aio_context(bs), - BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs, errp); - if (ret < 0) { + blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); + if (!blk) { + ret = -EPERM; goto out; } blk_set_allow_write_beyond_eof(blk, true); @@ -5412,12 +5412,10 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, } if (new_size) { - BlockBackend *blk = blk_new(bdrv_get_aio_context(bs), - BLK_PERM_RESIZE, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs, errp); - if (ret < 0) { - blk_unref(blk); - return ret; + BlockBackend *blk = blk_new_with_bs(bs, BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); + if (!blk) { + return -EPERM; } /* diff --git a/block/qed.c b/block/qed.c index b0fdb8f565..fb609cfba1 100644 --- a/block/qed.c +++ b/block/qed.c @@ -651,10 +651,10 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts, return -EIO; } - blk = blk_new(bdrv_get_aio_context(bs), - BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs, errp); - if (ret < 0) { + blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); + if (!blk) { + ret = -EPERM; goto out; } blk_set_allow_write_beyond_eof(blk, true); diff --git a/block/sheepdog.c b/block/sheepdog.c index 76729f40a4..2eb61938ff 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1803,12 +1803,12 @@ static int sd_prealloc(BlockDriverState *bs, int64_t old_size, int64_t new_size, void *buf = NULL; int ret; - blk = blk_new(bdrv_get_aio_context(bs), - BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE, - BLK_PERM_ALL); + blk = blk_new_with_bs(bs, + BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE, + BLK_PERM_ALL, errp); - ret = blk_insert_bs(blk, bs, errp); - if (ret < 0) { + if (!blk) { + ret = -EPERM; goto out_with_err_set; } diff --git a/block/vdi.c b/block/vdi.c index 0c7835ae70..2d28046615 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -804,10 +804,10 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, goto exit; } - blk = blk_new(bdrv_get_aio_context(bs_file), - BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs_file, errp); - if (ret < 0) { + blk = blk_new_with_bs(bs_file, BLK_PERM_WRITE | BLK_PERM_RESIZE, + BLK_PERM_ALL, errp); + if (!blk) { + ret = -EPERM; goto exit; } diff --git a/block/vhdx.c b/block/vhdx.c index 45be0a4321..9d3951f4ee 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1984,10 +1984,10 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts, return -EIO; } - blk = blk_new(bdrv_get_aio_context(bs), - BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs, errp); - if (ret < 0) { + blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); + if (!blk) { + ret = -EPERM; goto delete_and_exit; } blk_set_allow_write_beyond_eof(blk, true); diff --git a/block/vmdk.c b/block/vmdk.c index 8ec18f35a5..b02fdd14b2 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2717,11 +2717,10 @@ static BlockBackend *vmdk_co_create_cb(int64_t size, int idx, if (!bs) { return NULL; } - blk = blk_new(bdrv_get_aio_context(bs), - BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE, - BLK_PERM_ALL); - if (blk_insert_bs(blk, bs, errp)) { - bdrv_unref(bs); + blk = blk_new_with_bs(bs, + BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE, + BLK_PERM_ALL, errp); + if (!blk) { return NULL; } blk_set_allow_write_beyond_eof(blk, true); diff --git a/block/vpc.c b/block/vpc.c index 2d1eade146..5e31dd1e47 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -1012,10 +1012,10 @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts, return -EIO; } - blk = blk_new(bdrv_get_aio_context(bs), - BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs, errp); - if (ret < 0) { + blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); + if (!blk) { + ret = -EPERM; goto out; } blk_set_allow_write_beyond_eof(blk, true); diff --git a/blockdev.c b/blockdev.c index dc1a0c7c2f..b3c840ec03 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2711,7 +2711,6 @@ void qmp_block_resize(bool has_device, const char *device, BlockBackend *blk = NULL; BlockDriverState *bs; AioContext *aio_context; - int ret; bs = bdrv_lookup_bs(has_device ? device : NULL, has_node_name ? node_name : NULL, @@ -2734,14 +2733,13 @@ void qmp_block_resize(bool has_device, const char *device, goto out; } - blk = blk_new(bdrv_get_aio_context(bs), BLK_PERM_RESIZE, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs, errp); - if (ret < 0) { + blk = blk_new_with_bs(bs, BLK_PERM_RESIZE, BLK_PERM_ALL, errp); + if (!blk) { goto out; } bdrv_drained_begin(bs); - ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp); + blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp); bdrv_drained_end(bs); out: diff --git a/blockjob.c b/blockjob.c index fc850312c1..2affa1844d 100644 --- a/blockjob.c +++ b/blockjob.c @@ -397,16 +397,13 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, { BlockBackend *blk; BlockJob *job; - int ret; if (job_id == NULL && !(flags & JOB_INTERNAL)) { job_id = bdrv_get_device_name(bs); } - blk = blk_new(bdrv_get_aio_context(bs), perm, shared_perm); - ret = blk_insert_bs(blk, bs, errp); - if (ret < 0) { - blk_unref(blk); + blk = blk_new_with_bs(bs, perm, shared_perm, errp); + if (!blk) { return NULL; } diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 34de7faa81..0917663d89 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -77,6 +77,8 @@ typedef struct BlockBackendPublic { } BlockBackendPublic; BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm); +BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm, + uint64_t shared_perm, Error **errp); BlockBackend *blk_new_open(const char *filename, const char *reference, QDict *options, int flags, Error **errp); int blk_get_refcnt(BlockBackend *blk); From 7fa140abf69675b7b83af32de07fa8075c1da298 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 14:26:47 -0500 Subject: [PATCH 0257/2595] qcow2: Allow resize of images with internal snapshots We originally refused to allow resize of images with internal snapshots because the v2 image format did not require the tracking of snapshot size, making it impossible to safely revert to a snapshot with a different size than the current view of the image. But the snapshot size tracking was rectified in v3, and our recent fixes to qemu-img amend (see 0a85af35) guarantee that we always have a valid snapshot size. Thus, we no longer need to artificially limit image resizes, but it does become one more thing that would prevent a downgrade back to v2. And now that we support different-sized snapshots, it's also easy to fix reverting to a snapshot to apply the new size. Upgrade iotest 61 to cover this (we previously had NO coverage of refusal to resize while snapshots exist). Note that the amend process can fail but still have effects: in particular, since we break things into upgrade, resize, downgrade, a failure during resize does not roll back changes made during upgrade, nor does failure in downgrade roll back a resize. But this situation is pre-existing even without this patch; and without journaling, the best we could do is minimize the chance of partial failure by collecting all changes prior to doing any writes - which adds a lot of complexity but could still fail with EIO. On the other hand, we are careful that even if we have partial modification but then fail, the image is left viable (that is, we are careful to sequence things so that after each successful cluster write, there may be transient leaked clusters but no corrupt metadata). And complicating the code to make it more transaction-like is not worth the effort: a user can always request multiple 'qemu-img amend' changing one thing each, if they need finer-grained control over detecting the first failure than what they get by letting qemu decide how to sequence multiple changes. Signed-off-by: Eric Blake Reviewed-by: Max Reitz Message-Id: <20200428192648.749066-3-eblake@redhat.com> Signed-off-by: Max Reitz --- block/qcow2-snapshot.c | 20 ++++++++++++++++---- block/qcow2.c | 25 ++++++++++++++++++++++--- tests/qemu-iotests/061 | 35 +++++++++++++++++++++++++++++++++++ tests/qemu-iotests/061.out | 28 ++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 7 deletions(-) diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 82c32d4c9b..2756b37d24 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "sysemu/block-backend.h" #include "qapi/error.h" #include "qcow2.h" #include "qemu/bswap.h" @@ -775,10 +776,21 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) } if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) { - error_report("qcow2: Loading snapshots with different disk " - "size is not implemented"); - ret = -ENOTSUP; - goto fail; + BlockBackend *blk = blk_new_with_bs(bs, BLK_PERM_RESIZE, BLK_PERM_ALL, + &local_err); + if (!blk) { + error_report_err(local_err); + ret = -ENOTSUP; + goto fail; + } + + ret = blk_truncate(blk, sn->disk_size, true, PREALLOC_MODE_OFF, 0, + &local_err); + blk_unref(blk); + if (ret < 0) { + error_report_err(local_err); + goto fail; + } } /* diff --git a/block/qcow2.c b/block/qcow2.c index 0edc7f4643..3e8b3d022b 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3989,9 +3989,12 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, qemu_co_mutex_lock(&s->lock); - /* cannot proceed if image has snapshots */ - if (s->nb_snapshots) { - error_setg(errp, "Can't resize an image which has snapshots"); + /* + * Even though we store snapshot size for all images, it was not + * required until v3, so it is not safe to proceed for v2. + */ + if (s->nb_snapshots && s->qcow_version < 3) { + error_setg(errp, "Can't resize a v2 image which has snapshots"); ret = -ENOTSUP; goto fail; } @@ -5005,6 +5008,7 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, BDRVQcow2State *s = bs->opaque; int current_version = s->qcow_version; int ret; + int i; /* This is qcow2_downgrade(), not qcow2_upgrade() */ assert(target_version < current_version); @@ -5022,6 +5026,21 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, return -ENOTSUP; } + /* + * If any internal snapshot has a different size than the current + * image size, or VM state size that exceeds 32 bits, downgrading + * is unsafe. Even though we would still use v3-compliant output + * to preserve that data, other v2 programs might not realize + * those optional fields are important. + */ + for (i = 0; i < s->nb_snapshots; i++) { + if (s->snapshots[i].vm_state_size > UINT32_MAX || + s->snapshots[i].disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) { + error_setg(errp, "Internal snapshots prevent downgrade of image"); + return -ENOTSUP; + } + } + /* clear incompatible features */ if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) { ret = qcow2_mark_clean(bs); diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061 index ce285d3084..10eb243164 100755 --- a/tests/qemu-iotests/061 +++ b/tests/qemu-iotests/061 @@ -111,6 +111,41 @@ $PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IO -c "read -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io _check_test_img +echo +echo "=== Testing resize with snapshots ===" +echo +_make_test_img -o "compat=0.10" 32M +$QEMU_IO -c "write -P 0x2a 24M 64k" "$TEST_IMG" | _filter_qemu_io +$QEMU_IMG snapshot -c foo "$TEST_IMG" +$QEMU_IMG resize "$TEST_IMG" 64M && + echo "unexpected pass" +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)' + +$QEMU_IMG amend -o "compat=1.1,size=128M" "$TEST_IMG" || + echo "unexpected fail" +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)' + +$QEMU_IMG snapshot -c bar "$TEST_IMG" +$QEMU_IMG resize --shrink "$TEST_IMG" 64M || + echo "unexpected fail" +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)' + +$QEMU_IMG amend -o "compat=0.10,size=32M" "$TEST_IMG" && + echo "unexpected pass" +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)' + +$QEMU_IMG snapshot -a bar "$TEST_IMG" || + echo "unexpected fail" +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)' + +$QEMU_IMG snapshot -d bar "$TEST_IMG" +$QEMU_IMG amend -o "compat=0.10,size=32M" "$TEST_IMG" || + echo "unexpected fail" +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)' + +_check_test_img + + echo echo "=== Testing dirty lazy_refcounts=off ===" echo diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index 413cc4e0f4..5a8d36d005 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -271,6 +271,34 @@ read 65536/65536 bytes at offset 44040192 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. +=== Testing resize with snapshots === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 +wrote 65536/65536 bytes at offset 25165824 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: Can't resize a v2 image which has snapshots +version 2 +size 33554432 +nb_snapshots 1 +version 3 +size 134217728 +nb_snapshots 1 +Image resized. +version 3 +size 67108864 +nb_snapshots 2 +qemu-img: Internal snapshots prevent downgrade of image +version 3 +size 33554432 +nb_snapshots 2 +version 3 +size 134217728 +nb_snapshots 2 +version 2 +size 33554432 +nb_snapshots 1 +No errors were found on the image. + === Testing dirty lazy_refcounts=off === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 From ee1244a2e96288ba3c2f3a9a82b97f5617939d9f Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 14:26:48 -0500 Subject: [PATCH 0258/2595] qcow2: Tweak comment about bitmaps vs. resize Our comment did not actually match the code. Rewrite the comment to be less sensitive to any future changes to qcow2-bitmap.c that might implement scenarios that we currently reject. Signed-off-by: Eric Blake Reviewed-by: Max Reitz Message-Id: <20200428192648.749066-4-eblake@redhat.com> Signed-off-by: Max Reitz --- block/qcow2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/qcow2.c b/block/qcow2.c index 3e8b3d022b..ad934109a8 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3999,7 +3999,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, goto fail; } - /* cannot proceed if image has bitmaps */ + /* See qcow2-bitmap.c for which bitmap scenarios prevent a resize. */ if (qcow2_truncate_bitmaps_check(bs, errp)) { ret = -ENOTSUP; goto fail; From f4649069517b71c4038add8d977a41644fb117dc Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 16:38:07 -0500 Subject: [PATCH 0259/2595] block: Comment cleanups It's been a while since we got rid of the sector-based bdrv_read and bdrv_write (commit 2e11d756); let's finish the job on a few remaining comments. Signed-off-by: Eric Blake Message-Id: <20200428213807.776655-1-eblake@redhat.com> Reviewed-by: Alberto Garcia Signed-off-by: Max Reitz --- block/io.c | 3 ++- block/qcow2-refcount.c | 2 +- block/vvfat.c | 10 +++++----- tests/qemu-iotests/001 | 2 +- tests/qemu-iotests/052 | 2 +- tests/qemu-iotests/134 | 2 +- tests/qemu-iotests/188 | 2 +- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/block/io.c b/block/io.c index a4f9714230..7d30e61edc 100644 --- a/block/io.c +++ b/block/io.c @@ -960,7 +960,7 @@ int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, * flags are passed through to bdrv_pwrite_zeroes (e.g. BDRV_REQ_MAY_UNMAP, * BDRV_REQ_FUA). * - * Returns < 0 on error, 0 on success. For error codes see bdrv_write(). + * Returns < 0 on error, 0 on success. For error codes see bdrv_pwrite(). */ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) { @@ -994,6 +994,7 @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) } } +/* return < 0 if error. See bdrv_pwrite() for the return codes */ int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov) { int ret; diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index d9650b9b6c..0457a6060d 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -2660,7 +2660,7 @@ fail: * - 0 if writing to this offset will not affect the mentioned metadata * - a positive QCow2MetadataOverlap value indicating one overlapping section * - a negative value (-errno) indicating an error while performing a check, - * e.g. when bdrv_read failed on QCOW2_OL_INACTIVE_L2 + * e.g. when bdrv_pread failed on QCOW2_OL_INACTIVE_L2 */ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset, int64_t size) diff --git a/block/vvfat.c b/block/vvfat.c index ab800c4887..6d5c090dec 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2148,7 +2148,7 @@ DLOG(checkpoint()); * - get modified FAT * - compare the two FATs (TODO) * - get buffer for marking used clusters - * - recurse direntries from root (using bs->bdrv_read to make + * - recurse direntries from root (using bs->bdrv_pread to make * sure to get the new data) * - check that the FAT agrees with the size * - count the number of clusters occupied by this directory and @@ -2913,9 +2913,9 @@ static int handle_deletes(BDRVVVFATState* s) /* * synchronize mapping with new state: * - * - copy FAT (with bdrv_read) + * - copy FAT (with bdrv_pread) * - mark all filenames corresponding to mappings as deleted - * - recurse direntries from root (using bs->bdrv_read) + * - recurse direntries from root (using bs->bdrv_pread) * - delete files corresponding to mappings marked as deleted */ static int do_commit(BDRVVVFATState* s) @@ -2935,10 +2935,10 @@ static int do_commit(BDRVVVFATState* s) return ret; } - /* copy FAT (with bdrv_read) */ + /* copy FAT (with bdrv_pread) */ memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat); - /* recurse direntries from root (using bs->bdrv_read) */ + /* recurse direntries from root (using bs->bdrv_pread) */ ret = commit_direntries(s, 0, -1); if (ret) { fprintf(stderr, "Fatal: error while committing (%d)\n", ret); diff --git a/tests/qemu-iotests/001 b/tests/qemu-iotests/001 index d87a535c33..696726e45f 100755 --- a/tests/qemu-iotests/001 +++ b/tests/qemu-iotests/001 @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Test simple read/write using plain bdrv_read/bdrv_write +# Test simple read/write using plain bdrv_pread/bdrv_pwrite # # Copyright (C) 2009 Red Hat, Inc. # diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052 index 45a140910d..8d5c10601f 100755 --- a/tests/qemu-iotests/052 +++ b/tests/qemu-iotests/052 @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Test bdrv_read/bdrv_write using BDRV_O_SNAPSHOT +# Test bdrv_pread/bdrv_pwrite using BDRV_O_SNAPSHOT # # Copyright (C) 2013 Red Hat, Inc. # diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134 index 5f0fb86211..5162d21662 100755 --- a/tests/qemu-iotests/134 +++ b/tests/qemu-iotests/134 @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Test encrypted read/write using plain bdrv_read/bdrv_write +# Test encrypted read/write using plain bdrv_pread/bdrv_pwrite # # Copyright (C) 2015 Red Hat, Inc. # diff --git a/tests/qemu-iotests/188 b/tests/qemu-iotests/188 index afca44df54..09b9b6083a 100755 --- a/tests/qemu-iotests/188 +++ b/tests/qemu-iotests/188 @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Test encrypted read/write using plain bdrv_read/bdrv_write +# Test encrypted read/write using plain bdrv_pread/bdrv_pwrite # # Copyright (C) 2017 Red Hat, Inc. # From 44e808c13045b1032143ab8e144b4d48264ad609 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 4 May 2020 16:19:59 +0300 Subject: [PATCH 0260/2595] Fix iotest 153 Commit f62514b3def5fb2acbef64d0e053c0c31fa45aff made qemu-img reject -o "" but this test uses it. Since this test only tries to do a dry-run run of qemu-img amend, replace the -o "" with dummy -o "size=$size". Fixes: f62514b3def5fb2acbef64d0e053c0c31fa45aff Signed-off-by: Maxim Levitsky Message-Id: <20200504131959.9533-1-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- tests/qemu-iotests/153 | 2 +- tests/qemu-iotests/153.out | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 index 2b13111768..cf961d3609 100755 --- a/tests/qemu-iotests/153 +++ b/tests/qemu-iotests/153 @@ -122,7 +122,7 @@ for opts1 in "" "read-only=on" "read-only=on,force-share=on"; do _run_cmd $QEMU_IMG check $L "${TEST_IMG}" _run_cmd $QEMU_IMG compare $L "${TEST_IMG}" "${TEST_IMG}" _run_cmd $QEMU_IMG map $L "${TEST_IMG}" - _run_cmd $QEMU_IMG amend -o "" $L "${TEST_IMG}" + _run_cmd $QEMU_IMG amend -o "size=$size" $L "${TEST_IMG}" _run_cmd $QEMU_IMG commit $L "${TEST_IMG}" _run_cmd $QEMU_IMG resize $L "${TEST_IMG}" $size _run_cmd $QEMU_IMG rebase $L "${TEST_IMG}" -b "${TEST_IMG}.base" diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out index f7464dd8d3..b2a90caa6b 100644 --- a/tests/qemu-iotests/153.out +++ b/tests/qemu-iotests/153.out @@ -56,7 +56,7 @@ _qemu_img_wrapper map TEST_DIR/t.qcow2 qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get shared "write" lock Is another process using the image [TEST_DIR/t.qcow2]? -_qemu_img_wrapper amend -o TEST_DIR/t.qcow2 +_qemu_img_wrapper amend -o size=32M TEST_DIR/t.qcow2 qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? @@ -118,7 +118,7 @@ _qemu_img_wrapper compare -U TEST_DIR/t.qcow2 TEST_DIR/t.qcow2 _qemu_img_wrapper map -U TEST_DIR/t.qcow2 -_qemu_img_wrapper amend -o -U TEST_DIR/t.qcow2 +_qemu_img_wrapper amend -o size=32M -U TEST_DIR/t.qcow2 qemu-img: unrecognized option '-U' Try 'qemu-img --help' for more information @@ -187,7 +187,7 @@ _qemu_img_wrapper compare TEST_DIR/t.qcow2 TEST_DIR/t.qcow2 _qemu_img_wrapper map TEST_DIR/t.qcow2 -_qemu_img_wrapper amend -o TEST_DIR/t.qcow2 +_qemu_img_wrapper amend -o size=32M TEST_DIR/t.qcow2 qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? @@ -241,7 +241,7 @@ _qemu_img_wrapper compare -U TEST_DIR/t.qcow2 TEST_DIR/t.qcow2 _qemu_img_wrapper map -U TEST_DIR/t.qcow2 -_qemu_img_wrapper amend -o -U TEST_DIR/t.qcow2 +_qemu_img_wrapper amend -o size=32M -U TEST_DIR/t.qcow2 qemu-img: unrecognized option '-U' Try 'qemu-img --help' for more information @@ -303,7 +303,7 @@ _qemu_img_wrapper compare TEST_DIR/t.qcow2 TEST_DIR/t.qcow2 _qemu_img_wrapper map TEST_DIR/t.qcow2 -_qemu_img_wrapper amend -o TEST_DIR/t.qcow2 +_qemu_img_wrapper amend -o size=32M TEST_DIR/t.qcow2 _qemu_img_wrapper commit TEST_DIR/t.qcow2 @@ -345,7 +345,7 @@ _qemu_img_wrapper compare -U TEST_DIR/t.qcow2 TEST_DIR/t.qcow2 _qemu_img_wrapper map -U TEST_DIR/t.qcow2 -_qemu_img_wrapper amend -o -U TEST_DIR/t.qcow2 +_qemu_img_wrapper amend -o size=32M -U TEST_DIR/t.qcow2 qemu-img: unrecognized option '-U' Try 'qemu-img --help' for more information From e9407785cce67cab85a76727d393dbf7d924f6d7 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 29 Apr 2020 16:08:43 +0300 Subject: [PATCH 0261/2595] block/block-copy: rename in-flight requests to tasks We are going to use aio-task-pool API and extend in-flight request structure to be a successor of AioTask, so rename things appropriately. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-Id: <20200429130847.28124-2-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/block-copy.c | 98 +++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/block/block-copy.c b/block/block-copy.c index 05227e18bf..bbb29366dc 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -24,12 +24,12 @@ #define BLOCK_COPY_MAX_BUFFER (1 * MiB) #define BLOCK_COPY_MAX_MEM (128 * MiB) -typedef struct BlockCopyInFlightReq { +typedef struct BlockCopyTask { int64_t offset; int64_t bytes; - QLIST_ENTRY(BlockCopyInFlightReq) list; - CoQueue wait_queue; /* coroutines blocked on this request */ -} BlockCopyInFlightReq; + QLIST_ENTRY(BlockCopyTask) list; + CoQueue wait_queue; /* coroutines blocked on this task */ +} BlockCopyTask; typedef struct BlockCopyState { /* @@ -45,7 +45,7 @@ typedef struct BlockCopyState { bool use_copy_range; int64_t copy_size; uint64_t len; - QLIST_HEAD(, BlockCopyInFlightReq) inflight_reqs; + QLIST_HEAD(, BlockCopyTask) tasks; BdrvRequestFlags write_flags; @@ -73,15 +73,14 @@ typedef struct BlockCopyState { SharedResource *mem; } BlockCopyState; -static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s, - int64_t offset, - int64_t bytes) +static BlockCopyTask *find_conflicting_task(BlockCopyState *s, + int64_t offset, int64_t bytes) { - BlockCopyInFlightReq *req; + BlockCopyTask *t; - QLIST_FOREACH(req, &s->inflight_reqs, list) { - if (offset + bytes > req->offset && offset < req->offset + req->bytes) { - return req; + QLIST_FOREACH(t, &s->tasks, list) { + if (offset + bytes > t->offset && offset < t->offset + t->bytes) { + return t; } } @@ -89,73 +88,72 @@ static BlockCopyInFlightReq *find_conflicting_inflight_req(BlockCopyState *s, } /* - * If there are no intersecting requests return false. Otherwise, wait for the - * first found intersecting request to finish and return true. + * If there are no intersecting tasks return false. Otherwise, wait for the + * first found intersecting tasks to finish and return true. */ static bool coroutine_fn block_copy_wait_one(BlockCopyState *s, int64_t offset, int64_t bytes) { - BlockCopyInFlightReq *req = find_conflicting_inflight_req(s, offset, bytes); + BlockCopyTask *task = find_conflicting_task(s, offset, bytes); - if (!req) { + if (!task) { return false; } - qemu_co_queue_wait(&req->wait_queue, NULL); + qemu_co_queue_wait(&task->wait_queue, NULL); return true; } /* Called only on full-dirty region */ -static void block_copy_inflight_req_begin(BlockCopyState *s, - BlockCopyInFlightReq *req, - int64_t offset, int64_t bytes) +static void block_copy_task_begin(BlockCopyState *s, BlockCopyTask *task, + int64_t offset, int64_t bytes) { - assert(!find_conflicting_inflight_req(s, offset, bytes)); + assert(!find_conflicting_task(s, offset, bytes)); bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes); s->in_flight_bytes += bytes; - req->offset = offset; - req->bytes = bytes; - qemu_co_queue_init(&req->wait_queue); - QLIST_INSERT_HEAD(&s->inflight_reqs, req, list); + task->offset = offset; + task->bytes = bytes; + qemu_co_queue_init(&task->wait_queue); + QLIST_INSERT_HEAD(&s->tasks, task, list); } /* - * block_copy_inflight_req_shrink + * block_copy_task_shrink * - * Drop the tail of the request to be handled later. Set dirty bits back and - * wake up all requests waiting for us (may be some of them are not intersecting - * with shrunk request) + * Drop the tail of the task to be handled later. Set dirty bits back and + * wake up all tasks waiting for us (may be some of them are not intersecting + * with shrunk task) */ -static void coroutine_fn block_copy_inflight_req_shrink(BlockCopyState *s, - BlockCopyInFlightReq *req, int64_t new_bytes) +static void coroutine_fn block_copy_task_shrink(BlockCopyState *s, + BlockCopyTask *task, + int64_t new_bytes) { - if (new_bytes == req->bytes) { + if (new_bytes == task->bytes) { return; } - assert(new_bytes > 0 && new_bytes < req->bytes); + assert(new_bytes > 0 && new_bytes < task->bytes); - s->in_flight_bytes -= req->bytes - new_bytes; + s->in_flight_bytes -= task->bytes - new_bytes; bdrv_set_dirty_bitmap(s->copy_bitmap, - req->offset + new_bytes, req->bytes - new_bytes); + task->offset + new_bytes, task->bytes - new_bytes); - req->bytes = new_bytes; - qemu_co_queue_restart_all(&req->wait_queue); + task->bytes = new_bytes; + qemu_co_queue_restart_all(&task->wait_queue); } -static void coroutine_fn block_copy_inflight_req_end(BlockCopyState *s, - BlockCopyInFlightReq *req, - int ret) +static void coroutine_fn block_copy_task_end(BlockCopyState *s, + BlockCopyTask *task, int ret) { - s->in_flight_bytes -= req->bytes; + s->in_flight_bytes -= task->bytes; if (ret < 0) { - bdrv_set_dirty_bitmap(s->copy_bitmap, req->offset, req->bytes); + bdrv_set_dirty_bitmap(s->copy_bitmap, task->offset, task->bytes); } - QLIST_REMOVE(req, list); - qemu_co_queue_restart_all(&req->wait_queue); + QLIST_REMOVE(task, list); + qemu_co_queue_restart_all(&task->wait_queue); } void block_copy_state_free(BlockCopyState *s) @@ -223,7 +221,7 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER); } - QLIST_INIT(&s->inflight_reqs); + QLIST_INIT(&s->tasks); return s; } @@ -474,7 +472,7 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, assert(QEMU_IS_ALIGNED(bytes, s->cluster_size)); while (bytes) { - BlockCopyInFlightReq req; + BlockCopyTask task; int64_t next_zero, cur_bytes, status_bytes; if (!bdrv_dirty_bitmap_get(s->copy_bitmap, offset)) { @@ -495,14 +493,14 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, assert(next_zero < offset + cur_bytes); /* no need to do MIN() */ cur_bytes = next_zero - offset; } - block_copy_inflight_req_begin(s, &req, offset, cur_bytes); + block_copy_task_begin(s, &task, offset, cur_bytes); ret = block_copy_block_status(s, offset, cur_bytes, &status_bytes); assert(ret >= 0); /* never fail */ cur_bytes = MIN(cur_bytes, status_bytes); - block_copy_inflight_req_shrink(s, &req, cur_bytes); + block_copy_task_shrink(s, &task, cur_bytes); if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) { - block_copy_inflight_req_end(s, &req, 0); + block_copy_task_end(s, &task, 0); progress_set_remaining(s->progress, bdrv_get_dirty_count(s->copy_bitmap) + s->in_flight_bytes); @@ -518,7 +516,7 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, ret = block_copy_do_copy(s, offset, cur_bytes, ret & BDRV_BLOCK_ZERO, error_is_read); co_put_to_shres(s->mem, cur_bytes); - block_copy_inflight_req_end(s, &req, ret); + block_copy_task_end(s, &task, ret); if (ret < 0) { return ret; } From f13e60a973216edc1d793555607533305713c74d Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 29 Apr 2020 16:08:44 +0300 Subject: [PATCH 0262/2595] block/block-copy: alloc task on each iteration We are going to use aio-task-pool API, so tasks will be handled in parallel. We need therefore separate allocated task on each iteration. Introduce this logic now. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-Id: <20200429130847.28124-3-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/block-copy.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/block/block-copy.c b/block/block-copy.c index bbb29366dc..8d1b9ab9f0 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -106,9 +106,11 @@ static bool coroutine_fn block_copy_wait_one(BlockCopyState *s, int64_t offset, } /* Called only on full-dirty region */ -static void block_copy_task_begin(BlockCopyState *s, BlockCopyTask *task, - int64_t offset, int64_t bytes) +static BlockCopyTask *block_copy_task_create(BlockCopyState *s, + int64_t offset, int64_t bytes) { + BlockCopyTask *task = g_new(BlockCopyTask, 1); + assert(!find_conflicting_task(s, offset, bytes)); bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes); @@ -118,6 +120,8 @@ static void block_copy_task_begin(BlockCopyState *s, BlockCopyTask *task, task->bytes = bytes; qemu_co_queue_init(&task->wait_queue); QLIST_INSERT_HEAD(&s->tasks, task, list); + + return task; } /* @@ -472,7 +476,7 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, assert(QEMU_IS_ALIGNED(bytes, s->cluster_size)); while (bytes) { - BlockCopyTask task; + g_autofree BlockCopyTask *task = NULL; int64_t next_zero, cur_bytes, status_bytes; if (!bdrv_dirty_bitmap_get(s->copy_bitmap, offset)) { @@ -493,14 +497,14 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, assert(next_zero < offset + cur_bytes); /* no need to do MIN() */ cur_bytes = next_zero - offset; } - block_copy_task_begin(s, &task, offset, cur_bytes); + task = block_copy_task_create(s, offset, cur_bytes); ret = block_copy_block_status(s, offset, cur_bytes, &status_bytes); assert(ret >= 0); /* never fail */ cur_bytes = MIN(cur_bytes, status_bytes); - block_copy_task_shrink(s, &task, cur_bytes); + block_copy_task_shrink(s, task, cur_bytes); if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) { - block_copy_task_end(s, &task, 0); + block_copy_task_end(s, task, 0); progress_set_remaining(s->progress, bdrv_get_dirty_count(s->copy_bitmap) + s->in_flight_bytes); @@ -516,7 +520,7 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, ret = block_copy_do_copy(s, offset, cur_bytes, ret & BDRV_BLOCK_ZERO, error_is_read); co_put_to_shres(s->mem, cur_bytes); - block_copy_task_end(s, &task, ret); + block_copy_task_end(s, task, ret); if (ret < 0) { return ret; } From 1348a65774d2a5bfbf8ba5c52a07b02126326e17 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 29 Apr 2020 16:08:45 +0300 Subject: [PATCH 0263/2595] block/block-copy: add state pointer to BlockCopyTask We are going to use aio-task-pool API, so we'll need state pointer in BlockCopyTask anyway. Add it now and use where possible. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-Id: <20200429130847.28124-4-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/block-copy.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/block/block-copy.c b/block/block-copy.c index 8d1b9ab9f0..35ff9cc3ef 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -25,6 +25,7 @@ #define BLOCK_COPY_MAX_MEM (128 * MiB) typedef struct BlockCopyTask { + BlockCopyState *s; int64_t offset; int64_t bytes; QLIST_ENTRY(BlockCopyTask) list; @@ -116,8 +117,11 @@ static BlockCopyTask *block_copy_task_create(BlockCopyState *s, bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes); s->in_flight_bytes += bytes; - task->offset = offset; - task->bytes = bytes; + *task = (BlockCopyTask) { + .s = s, + .offset = offset, + .bytes = bytes, + }; qemu_co_queue_init(&task->wait_queue); QLIST_INSERT_HEAD(&s->tasks, task, list); @@ -131,8 +135,7 @@ static BlockCopyTask *block_copy_task_create(BlockCopyState *s, * wake up all tasks waiting for us (may be some of them are not intersecting * with shrunk task) */ -static void coroutine_fn block_copy_task_shrink(BlockCopyState *s, - BlockCopyTask *task, +static void coroutine_fn block_copy_task_shrink(BlockCopyTask *task, int64_t new_bytes) { if (new_bytes == task->bytes) { @@ -141,20 +144,19 @@ static void coroutine_fn block_copy_task_shrink(BlockCopyState *s, assert(new_bytes > 0 && new_bytes < task->bytes); - s->in_flight_bytes -= task->bytes - new_bytes; - bdrv_set_dirty_bitmap(s->copy_bitmap, + task->s->in_flight_bytes -= task->bytes - new_bytes; + bdrv_set_dirty_bitmap(task->s->copy_bitmap, task->offset + new_bytes, task->bytes - new_bytes); task->bytes = new_bytes; qemu_co_queue_restart_all(&task->wait_queue); } -static void coroutine_fn block_copy_task_end(BlockCopyState *s, - BlockCopyTask *task, int ret) +static void coroutine_fn block_copy_task_end(BlockCopyTask *task, int ret) { - s->in_flight_bytes -= task->bytes; + task->s->in_flight_bytes -= task->bytes; if (ret < 0) { - bdrv_set_dirty_bitmap(s->copy_bitmap, task->offset, task->bytes); + bdrv_set_dirty_bitmap(task->s->copy_bitmap, task->offset, task->bytes); } QLIST_REMOVE(task, list); qemu_co_queue_restart_all(&task->wait_queue); @@ -502,9 +504,9 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, ret = block_copy_block_status(s, offset, cur_bytes, &status_bytes); assert(ret >= 0); /* never fail */ cur_bytes = MIN(cur_bytes, status_bytes); - block_copy_task_shrink(s, task, cur_bytes); + block_copy_task_shrink(task, cur_bytes); if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) { - block_copy_task_end(s, task, 0); + block_copy_task_end(task, 0); progress_set_remaining(s->progress, bdrv_get_dirty_count(s->copy_bitmap) + s->in_flight_bytes); @@ -520,7 +522,7 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, ret = block_copy_do_copy(s, offset, cur_bytes, ret & BDRV_BLOCK_ZERO, error_is_read); co_put_to_shres(s->mem, cur_bytes); - block_copy_task_end(s, task, ret); + block_copy_task_end(task, ret); if (ret < 0) { return ret; } From 42ac214406e092038b13f02c2ff9768d4dd41e1b Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 29 Apr 2020 16:08:46 +0300 Subject: [PATCH 0264/2595] block/block-copy: refactor task creation Instead of just relying on the comment "Called only on full-dirty region" in block_copy_task_create() let's move initial dirty area search directly to block_copy_task_create(). Let's also use effective bdrv_dirty_bitmap_next_dirty_area instead of looping through all non-dirty clusters. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-Id: <20200429130847.28124-5-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/block-copy.c | 80 ++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/block/block-copy.c b/block/block-copy.c index 35ff9cc3ef..f560338647 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -32,6 +32,11 @@ typedef struct BlockCopyTask { CoQueue wait_queue; /* coroutines blocked on this task */ } BlockCopyTask; +static int64_t task_end(BlockCopyTask *task) +{ + return task->offset + task->bytes; +} + typedef struct BlockCopyState { /* * BdrvChild objects are not owned or managed by block-copy. They are @@ -106,17 +111,29 @@ static bool coroutine_fn block_copy_wait_one(BlockCopyState *s, int64_t offset, return true; } -/* Called only on full-dirty region */ +/* + * Search for the first dirty area in offset/bytes range and create task at + * the beginning of it. + */ static BlockCopyTask *block_copy_task_create(BlockCopyState *s, int64_t offset, int64_t bytes) { - BlockCopyTask *task = g_new(BlockCopyTask, 1); + BlockCopyTask *task; + if (!bdrv_dirty_bitmap_next_dirty_area(s->copy_bitmap, + offset, offset + bytes, + s->copy_size, &offset, &bytes)) + { + return NULL; + } + + /* region is dirty, so no existent tasks possible in it */ assert(!find_conflicting_task(s, offset, bytes)); bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes); s->in_flight_bytes += bytes; + task = g_new(BlockCopyTask, 1); *task = (BlockCopyTask) { .s = s, .offset = offset, @@ -466,6 +483,7 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, { int ret = 0; bool found_dirty = false; + int64_t end = offset + bytes; /* * block_copy() user is responsible for keeping source and target in same @@ -479,58 +497,52 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, while (bytes) { g_autofree BlockCopyTask *task = NULL; - int64_t next_zero, cur_bytes, status_bytes; + int64_t status_bytes; - if (!bdrv_dirty_bitmap_get(s->copy_bitmap, offset)) { - trace_block_copy_skip(s, offset); - offset += s->cluster_size; - bytes -= s->cluster_size; - continue; /* already copied */ + task = block_copy_task_create(s, offset, bytes); + if (!task) { + /* No more dirty bits in the bitmap */ + trace_block_copy_skip_range(s, offset, bytes); + break; + } + if (task->offset > offset) { + trace_block_copy_skip_range(s, offset, task->offset - offset); } found_dirty = true; - cur_bytes = MIN(bytes, s->copy_size); - - next_zero = bdrv_dirty_bitmap_next_zero(s->copy_bitmap, offset, - cur_bytes); - if (next_zero >= 0) { - assert(next_zero > offset); /* offset is dirty */ - assert(next_zero < offset + cur_bytes); /* no need to do MIN() */ - cur_bytes = next_zero - offset; - } - task = block_copy_task_create(s, offset, cur_bytes); - - ret = block_copy_block_status(s, offset, cur_bytes, &status_bytes); + ret = block_copy_block_status(s, task->offset, task->bytes, + &status_bytes); assert(ret >= 0); /* never fail */ - cur_bytes = MIN(cur_bytes, status_bytes); - block_copy_task_shrink(task, cur_bytes); + if (status_bytes < task->bytes) { + block_copy_task_shrink(task, status_bytes); + } if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) { block_copy_task_end(task, 0); progress_set_remaining(s->progress, bdrv_get_dirty_count(s->copy_bitmap) + s->in_flight_bytes); - trace_block_copy_skip_range(s, offset, status_bytes); - offset += status_bytes; - bytes -= status_bytes; + trace_block_copy_skip_range(s, task->offset, task->bytes); + offset = task_end(task); + bytes = end - offset; continue; } - trace_block_copy_process(s, offset); + trace_block_copy_process(s, task->offset); - co_get_from_shres(s->mem, cur_bytes); - ret = block_copy_do_copy(s, offset, cur_bytes, ret & BDRV_BLOCK_ZERO, - error_is_read); - co_put_to_shres(s->mem, cur_bytes); + co_get_from_shres(s->mem, task->bytes); + ret = block_copy_do_copy(s, task->offset, task->bytes, + ret & BDRV_BLOCK_ZERO, error_is_read); + co_put_to_shres(s->mem, task->bytes); block_copy_task_end(task, ret); if (ret < 0) { return ret; } - progress_work_done(s->progress, cur_bytes); - s->progress_bytes_callback(cur_bytes, s->progress_opaque); - offset += cur_bytes; - bytes -= cur_bytes; + progress_work_done(s->progress, task->bytes); + s->progress_bytes_callback(task->bytes, s->progress_opaque); + offset = task_end(task); + bytes = end - offset; } return found_dirty; From 4ce5dd3e9b5ee0fac18625860eb3727399ee965e Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 29 Apr 2020 16:08:47 +0300 Subject: [PATCH 0265/2595] block/block-copy: use aio-task-pool API Run block_copy iterations in parallel in aio tasks. Changes: - BlockCopyTask becomes aio task structure. Add zeroes field to pass it to block_copy_do_copy - add call state - it's a state of one call of block_copy(), shared between parallel tasks. For now used only to keep information about first error: is it read or not. - convert block_copy_dirty_clusters to aio-task loop. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200429130847.28124-6-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/block-copy.c | 119 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 13 deletions(-) diff --git a/block/block-copy.c b/block/block-copy.c index f560338647..03500680f7 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -19,15 +19,29 @@ #include "block/block-copy.h" #include "sysemu/block-backend.h" #include "qemu/units.h" +#include "qemu/coroutine.h" +#include "block/aio_task.h" #define BLOCK_COPY_MAX_COPY_RANGE (16 * MiB) #define BLOCK_COPY_MAX_BUFFER (1 * MiB) #define BLOCK_COPY_MAX_MEM (128 * MiB) +#define BLOCK_COPY_MAX_WORKERS 64 + +static coroutine_fn int block_copy_task_entry(AioTask *task); + +typedef struct BlockCopyCallState { + bool failed; + bool error_is_read; +} BlockCopyCallState; typedef struct BlockCopyTask { + AioTask task; + BlockCopyState *s; + BlockCopyCallState *call_state; int64_t offset; int64_t bytes; + bool zeroes; QLIST_ENTRY(BlockCopyTask) list; CoQueue wait_queue; /* coroutines blocked on this task */ } BlockCopyTask; @@ -116,6 +130,7 @@ static bool coroutine_fn block_copy_wait_one(BlockCopyState *s, int64_t offset, * the beginning of it. */ static BlockCopyTask *block_copy_task_create(BlockCopyState *s, + BlockCopyCallState *call_state, int64_t offset, int64_t bytes) { BlockCopyTask *task; @@ -135,7 +150,9 @@ static BlockCopyTask *block_copy_task_create(BlockCopyState *s, task = g_new(BlockCopyTask, 1); *task = (BlockCopyTask) { + .task.func = block_copy_task_entry, .s = s, + .call_state = call_state, .offset = offset, .bytes = bytes, }; @@ -263,6 +280,38 @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm) s->progress = pm; } +/* + * Takes ownership of @task + * + * If pool is NULL directly run the task, otherwise schedule it into the pool. + * + * Returns: task.func return code if pool is NULL + * otherwise -ECANCELED if pool status is bad + * otherwise 0 (successfully scheduled) + */ +static coroutine_fn int block_copy_task_run(AioTaskPool *pool, + BlockCopyTask *task) +{ + if (!pool) { + int ret = task->task.func(&task->task); + + g_free(task); + return ret; + } + + aio_task_pool_wait_slot(pool); + if (aio_task_pool_status(pool) < 0) { + co_put_to_shres(task->s->mem, task->bytes); + block_copy_task_end(task, -ECANCELED); + g_free(task); + return -ECANCELED; + } + + aio_task_pool_start_task(pool, &task->task); + + return 0; +} + /* * block_copy_do_copy * @@ -366,6 +415,27 @@ out: return ret; } +static coroutine_fn int block_copy_task_entry(AioTask *task) +{ + BlockCopyTask *t = container_of(task, BlockCopyTask, task); + bool error_is_read; + int ret; + + ret = block_copy_do_copy(t->s, t->offset, t->bytes, t->zeroes, + &error_is_read); + if (ret < 0 && !t->call_state->failed) { + t->call_state->failed = true; + t->call_state->error_is_read = error_is_read; + } else { + progress_work_done(t->s->progress, t->bytes); + t->s->progress_bytes_callback(t->bytes, t->s->progress_opaque); + } + co_put_to_shres(t->s->mem, t->bytes); + block_copy_task_end(t, ret); + + return ret; +} + static int block_copy_block_status(BlockCopyState *s, int64_t offset, int64_t bytes, int64_t *pnum) { @@ -484,6 +554,8 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, int ret = 0; bool found_dirty = false; int64_t end = offset + bytes; + AioTaskPool *aio = NULL; + BlockCopyCallState call_state = {false, false}; /* * block_copy() user is responsible for keeping source and target in same @@ -495,11 +567,11 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, assert(QEMU_IS_ALIGNED(offset, s->cluster_size)); assert(QEMU_IS_ALIGNED(bytes, s->cluster_size)); - while (bytes) { - g_autofree BlockCopyTask *task = NULL; + while (bytes && aio_task_pool_status(aio) == 0) { + BlockCopyTask *task; int64_t status_bytes; - task = block_copy_task_create(s, offset, bytes); + task = block_copy_task_create(s, &call_state, offset, bytes); if (!task) { /* No more dirty bits in the bitmap */ trace_block_copy_skip_range(s, offset, bytes); @@ -519,6 +591,7 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, } if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) { block_copy_task_end(task, 0); + g_free(task); progress_set_remaining(s->progress, bdrv_get_dirty_count(s->copy_bitmap) + s->in_flight_bytes); @@ -527,25 +600,45 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, bytes = end - offset; continue; } + task->zeroes = ret & BDRV_BLOCK_ZERO; trace_block_copy_process(s, task->offset); co_get_from_shres(s->mem, task->bytes); - ret = block_copy_do_copy(s, task->offset, task->bytes, - ret & BDRV_BLOCK_ZERO, error_is_read); - co_put_to_shres(s->mem, task->bytes); - block_copy_task_end(task, ret); - if (ret < 0) { - return ret; - } - progress_work_done(s->progress, task->bytes); - s->progress_bytes_callback(task->bytes, s->progress_opaque); offset = task_end(task); bytes = end - offset; + + if (!aio && bytes) { + aio = aio_task_pool_new(BLOCK_COPY_MAX_WORKERS); + } + + ret = block_copy_task_run(aio, task); + if (ret < 0) { + goto out; + } } - return found_dirty; +out: + if (aio) { + aio_task_pool_wait_all(aio); + + /* + * We are not really interested in -ECANCELED returned from + * block_copy_task_run. If it fails, it means some task already failed + * for real reason, let's return first failure. + * Still, assert that we don't rewrite failure by success. + */ + assert(ret == 0 || aio_task_pool_status(aio) < 0); + ret = aio_task_pool_status(aio); + + aio_task_pool_free(aio); + } + if (error_is_read && ret < 0) { + *error_is_read = call_state.error_is_read; + } + + return ret < 0 ? ret : found_dirty; } /* From f08085f49fb66a5cdc86653bd896d0e728bcee50 Mon Sep 17 00:00:00 2001 From: Joaquin de Andres Date: Thu, 2 Apr 2020 18:28:39 +0200 Subject: [PATCH 0266/2595] hw/core/register: Add register_init_block8 helper. There was no support for 8 bits block registers. Changed register_init_block32 to be generic and static, adding register size in bits as parameter. Created one helper for each size. Signed-off-by: Joaquin de Andres Message-Id: <20200402162839.76636-1-me@xcancerberox.com.ar> Reviewed-by: Alistair Francis Signed-off-by: Alistair Francis --- hw/core/register.c | 46 +++++++++++++++++++++++++++++++++---------- include/hw/register.h | 8 ++++++++ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/hw/core/register.c b/hw/core/register.c index 3c77396587..ddf91eb445 100644 --- a/hw/core/register.c +++ b/hw/core/register.c @@ -246,16 +246,18 @@ uint64_t register_read_memory(void *opaque, hwaddr addr, return extract64(read_val, 0, size * 8); } -RegisterInfoArray *register_init_block32(DeviceState *owner, - const RegisterAccessInfo *rae, - int num, RegisterInfo *ri, - uint32_t *data, - const MemoryRegionOps *ops, - bool debug_enabled, - uint64_t memory_size) +static RegisterInfoArray *register_init_block(DeviceState *owner, + const RegisterAccessInfo *rae, + int num, RegisterInfo *ri, + void *data, + const MemoryRegionOps *ops, + bool debug_enabled, + uint64_t memory_size, + size_t data_size_bits) { const char *device_prefix = object_get_typename(OBJECT(owner)); RegisterInfoArray *r_array = g_new0(RegisterInfoArray, 1); + int data_size = data_size_bits >> 3; int i; r_array->r = g_new0(RegisterInfo *, num); @@ -264,12 +266,12 @@ RegisterInfoArray *register_init_block32(DeviceState *owner, r_array->prefix = device_prefix; for (i = 0; i < num; i++) { - int index = rae[i].addr / 4; + int index = rae[i].addr / data_size; RegisterInfo *r = &ri[index]; *r = (RegisterInfo) { - .data = &data[index], - .data_size = sizeof(uint32_t), + .data = data + data_size * index, + .data_size = data_size, .access = &rae[i], .opaque = owner, }; @@ -284,6 +286,30 @@ RegisterInfoArray *register_init_block32(DeviceState *owner, return r_array; } +RegisterInfoArray *register_init_block8(DeviceState *owner, + const RegisterAccessInfo *rae, + int num, RegisterInfo *ri, + uint8_t *data, + const MemoryRegionOps *ops, + bool debug_enabled, + uint64_t memory_size) +{ + return register_init_block(owner, rae, num, ri, (void *) + data, ops, debug_enabled, memory_size, 8); +} + +RegisterInfoArray *register_init_block32(DeviceState *owner, + const RegisterAccessInfo *rae, + int num, RegisterInfo *ri, + uint32_t *data, + const MemoryRegionOps *ops, + bool debug_enabled, + uint64_t memory_size) +{ + return register_init_block(owner, rae, num, ri, (void *) + data, ops, debug_enabled, memory_size, 32); +} + void register_finalize_block(RegisterInfoArray *r_array) { object_unparent(OBJECT(&r_array->mem)); diff --git a/include/hw/register.h b/include/hw/register.h index 5796584588..5d2c565ae0 100644 --- a/include/hw/register.h +++ b/include/hw/register.h @@ -185,6 +185,14 @@ uint64_t register_read_memory(void *opaque, hwaddr addr, unsigned size); * memory region (r_array->mem) the caller should add to a container. */ +RegisterInfoArray *register_init_block8(DeviceState *owner, + const RegisterAccessInfo *rae, + int num, RegisterInfo *ri, + uint8_t *data, + const MemoryRegionOps *ops, + bool debug_enabled, + uint64_t memory_size); + RegisterInfoArray *register_init_block32(DeviceState *owner, const RegisterAccessInfo *rae, int num, RegisterInfo *ri, From 4f8bde527626930421675411c58e9603bf205f3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 1 May 2020 12:15:02 +0100 Subject: [PATCH 0267/2595] .travis.yml: show free disk space at end of run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200501111505.4225-2-alex.bennee@linaro.org> --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 2fd63eceaa..a4c3c6c805 100644 --- a/.travis.yml +++ b/.travis.yml @@ -113,6 +113,7 @@ script: $(exit $BUILD_RC); fi after_script: + - df -h - if command -v ccache ; then ccache --show-stats ; fi From 22a231950c50d339fb699c09d81ab9c2b5a28279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 1 May 2020 12:15:03 +0100 Subject: [PATCH 0268/2595] .travis.yml: drop MacOSX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This keeps breaking on Travis so lets just fall back to the Cirrus CI builds which seem to be better maintained. Fix up the comments while we are doing this as we never had a windows build. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Acked-by: Richard Henderson Message-Id: <20200501111505.4225-3-alex.bennee@linaro.org> --- .travis.yml | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/.travis.yml b/.travis.yml index a4c3c6c805..49267b73b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,8 @@ compiler: cache: # There is one cache per branch and compiler version. # characteristics of each job are used to identify the cache: - # - OS name (currently, linux, osx, or windows) + # - OS name (currently only linux) # - OS distribution (for Linux, xenial, trusty, or precise) - # - macOS image name (e.g., xcode7.2) # - Names and values of visible environment variables set in .travis.yml or Settings panel timeout: 1200 ccache: true @@ -271,31 +270,6 @@ jobs: - TEST_CMD="" - # MacOSX builds - cirrus.yml also tests some MacOS builds including latest Xcode - - - name: "OSX Xcode 10.3" - env: - - BASE_CONFIG="--disable-docs --enable-tools" - - CONFIG="--target-list=i386-softmmu,ppc-softmmu,ppc64-softmmu,m68k-softmmu,x86_64-softmmu" - os: osx - osx_image: xcode10.3 - compiler: clang - addons: - homebrew: - packages: - - ccache - - glib - - pixman - - gnu-sed - - python - update: true - before_script: - - brew link --overwrite python - - export PATH="/usr/local/opt/ccache/libexec:$PATH" - - mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR} - - ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; } - - # Python builds - name: "GCC Python 3.5 (x86_64-softmmu)" env: From 8f3e2968f696968787d7607adc5d2b31fc7fe1a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 1 May 2020 12:15:04 +0100 Subject: [PATCH 0269/2595] .cirrus.yml: bump FreeBSD to the current stable release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hopefully this will un-stick the test which has been broken for a long time. Signed-off-by: Alex Bennée Reviewed-by: Li-Wen Hsu Tested-by: Li-Wen Hsu Message-Id: <20200501111505.4225-4-alex.bennee@linaro.org> --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 90645fede6..f06f5af2b9 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -3,7 +3,7 @@ env: freebsd_12_task: freebsd_instance: - image: freebsd-12-0-release-amd64 + image_family: freebsd-12-1 cpu: 8 memory: 8G install_script: pkg install -y From ae52862970bb9f372d6ddebd0e34dc7927b6a7f7 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Mon, 4 May 2020 17:23:50 +0800 Subject: [PATCH 0270/2595] .cirrus.yml: bootstrap pkg unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ensures compatibility with pkg repo so a change in upstream doesn't break setup. See: https://lists.freebsd.org/pipermail/freebsd-cloud/2020-April/000234.html Message-Id: Signed-off-by: Li-Wen Hsu [AJB: applied from Li-Wen's github, applied sob, tweaked commit message] Signed-off-by: Alex Bennée --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index f06f5af2b9..de0727cb09 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -6,7 +6,7 @@ freebsd_12_task: image_family: freebsd-12-1 cpu: 8 memory: 8G - install_script: pkg install -y + install_script: ASSUME_ALWAYS_YES=yes pkg bootstrap -f ; pkg install -y bash bison curl cyrus-sasl git glib gmake gnutls gsed nettle perl5 pixman pkgconf png usbredir script: From daee97f618e1831e38fec01c47bf2881ecf5bded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 1 May 2020 12:15:05 +0100 Subject: [PATCH 0271/2595] .travis.yml: reduce the load on [ppc64] GCC check-tcg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This seems to be timing out quite often and occasionally running out of disk space. Relegate it to light duties. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200501111505.4225-5-alex.bennee@linaro.org> --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 49267b73b3..fe708792ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -458,7 +458,7 @@ jobs: - genisoimage env: - TEST_CMD="make check check-tcg V=1" - - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},ppc64le-linux-user" + - CONFIG="--disable-containers --target-list=ppc64-softmmu,ppc64le-linux-user" - name: "[s390x] GCC check-tcg" arch: s390x From f2385398b2f02eec9ea78ea4aa88c5ee66cd1ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 30 Apr 2020 20:01:14 +0100 Subject: [PATCH 0272/2595] configure: favour gdb-multiarch if we have it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As gdb will generally be talking to "foreign" guests lets use that if we can. Otherwise the chances of gdb barfing are considerably higher. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200430190122.4592-2-alex.bennee@linaro.org> --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 23b5e93752..c58787100f 100755 --- a/configure +++ b/configure @@ -303,7 +303,7 @@ libs_qga="" debug_info="yes" stack_protector="" use_containers="yes" -gdb_bin=$(command -v "gdb") +gdb_bin=$(command -v "gdb-multiarch" || command -v "gdb") if test -e "$source_path/.git" then From 38c1c09839c90317314be48f8758e9001ee40b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 30 Apr 2020 20:01:15 +0100 Subject: [PATCH 0273/2595] gdbstub: Introduce gdb_get_float64() to get 64-bit float registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When converted to use GByteArray in commits 462474d760c and a010bdbe719, the call to stfq_p() was removed. This call serialize a float. Since we now use a GByteArray, we can not use stfq_p() directly. Introduce the gdb_get_float64() helper to load a float64 register. Fixes: 462474d760c ("target/m68k: use gdb_get_reg helpers") Fixes: a010bdbe719 ("extend GByteArray to read register helpers") Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200414163853.12164-3-philmd@redhat.com> Message-Id: <20200430190122.4592-3-alex.bennee@linaro.org> --- include/exec/gdbstub.h | 11 +++++++++++ target/m68k/helper.c | 3 ++- target/ppc/gdbstub.c | 4 ++-- target/ppc/translate_init.inc.c | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 20e1072692..4a2b8e3089 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -134,6 +134,17 @@ static inline int gdb_get_float32(GByteArray *array, float32 val) return sizeof(buf); } + +static inline int gdb_get_float64(GByteArray *array, float64 val) +{ + uint8_t buf[sizeof(CPU_DoubleU)]; + + stfq_p(buf, val); + g_byte_array_append(array, buf, sizeof(buf)); + + return sizeof(buf); +} + static inline int gdb_get_zeroes(GByteArray *array, size_t len) { guint oldlen = array->len; diff --git a/target/m68k/helper.c b/target/m68k/helper.c index cad4083895..79b0b10ea9 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -72,7 +72,8 @@ static int cf_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n) { if (n < 8) { float_status s; - return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s)); + return gdb_get_float64(mem_buf, + floatx80_to_float64(env->fregs[n].d, &s)); } switch (n) { case 8: /* fpcontrol */ diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index eb362dd9ae..5c11c88b2a 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -130,7 +130,7 @@ int ppc_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int n) gdb_get_regl(buf, env->gpr[n]); } else if (n < 64) { /* fprs */ - gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32)); + gdb_get_float64(buf, *cpu_fpr_ptr(env, n - 32)); } else { switch (n) { case 64: @@ -184,7 +184,7 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, GByteArray *buf, int n) gdb_get_reg64(buf, env->gpr[n]); } else if (n < 64) { /* fprs */ - gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32)); + gdb_get_float64(buf, *cpu_fpr_ptr(env, n - 32)); } else if (n < 96) { /* Altivec */ gdb_get_reg64(buf, n - 64); diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index fd763e588e..2b6e832c4c 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -9881,7 +9881,7 @@ static int gdb_get_float_reg(CPUPPCState *env, GByteArray *buf, int n) { uint8_t *mem_buf; if (n < 32) { - gdb_get_reg64(buf, *cpu_fpr_ptr(env, n)); + gdb_get_float64(buf, *cpu_fpr_ptr(env, n)); mem_buf = gdb_get_reg_ptr(buf, 8); ppc_maybe_bswap_register(env, mem_buf, 8); return 8; From d2fefdedd3a65eaf22d8546835c225c3661e23d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 30 Apr 2020 20:01:16 +0100 Subject: [PATCH 0274/2595] tests/tcg: better trap gdb failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems older and non-multiarach aware GDBs might not fail gracefully when faced with something they don't know. For example when faced with a target XML for s390x the Ubuntu 18.04 gdb will generate an internal fault and prompt for a core dump. Work around this by invoking GDB in a more batch orientated way and then trying to filter out between test failures and gdb failures. Signed-off-by: Alex Bennée Message-Id: <20200430190122.4592-4-alex.bennee@linaro.org> --- tests/guest-debug/run-test.py | 19 ++++++++++++++++++- tests/tcg/aarch64/gdbstub/test-sve-ioctl.py | 1 - tests/tcg/aarch64/gdbstub/test-sve.py | 1 - 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py index 8c49ee2f22..2bbb8fbaa3 100755 --- a/tests/guest-debug/run-test.py +++ b/tests/guest-debug/run-test.py @@ -50,8 +50,25 @@ if __name__ == '__main__': inferior = subprocess.Popen(shlex.split(cmd)) # Now launch gdb with our test and collect the result - gdb_cmd = "%s %s -ex 'target remote localhost:1234' -x %s" % (args.gdb, args.binary, args.test) + gdb_cmd = "%s %s" % (args.gdb, args.binary) + # run quietly and ignore .gdbinit + gdb_cmd += " -q -n -batch" + # disable prompts in case of crash + gdb_cmd += " -ex 'set confirm off'" + # connect to remote + gdb_cmd += " -ex 'target remote localhost:1234'" + # finally the test script itself + gdb_cmd += " -x %s" % (args.test) + + print("GDB CMD: %s" % (gdb_cmd)) result = subprocess.call(gdb_cmd, shell=True); + # A negative result is the result of an internal gdb failure like + # a crash. We force a return of 0 so we don't fail the test on + # account of broken external tools. + if result < 0: + print("GDB crashed? SKIPPING") + exit(0) + exit(result) diff --git a/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py b/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py index 984fbeb277..387b2fc20a 100644 --- a/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py +++ b/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py @@ -70,7 +70,6 @@ except (gdb.error, AttributeError): try: # These are not very useful in scripts gdb.execute("set pagination off") - gdb.execute("set confirm off") # Run the actual tests run_test() diff --git a/tests/tcg/aarch64/gdbstub/test-sve.py b/tests/tcg/aarch64/gdbstub/test-sve.py index dbe7f2aa93..5995689625 100644 --- a/tests/tcg/aarch64/gdbstub/test-sve.py +++ b/tests/tcg/aarch64/gdbstub/test-sve.py @@ -71,7 +71,6 @@ except (gdb.error, AttributeError): try: # These are not very useful in scripts gdb.execute("set pagination off") - gdb.execute("set confirm off") # Run the actual tests run_test() From 744f1b0f6888b07c9870329ae9f40b8e641db0ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 30 Apr 2020 20:01:17 +0100 Subject: [PATCH 0275/2595] tests/tcg: drop inferior.was_attached() test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test seems flaky and reports attachment even when we failed to negotiate the architecture. However the fetching of the guest architecture will fail tripping up the gdb AttributeError which will trigger our early no error status exit from the test Signed-off-by: Alex Bennée Message-Id: <20200430190122.4592-5-alex.bennee@linaro.org> --- tests/tcg/aarch64/gdbstub/test-sve-ioctl.py | 3 --- tests/tcg/aarch64/gdbstub/test-sve.py | 3 --- 2 files changed, 6 deletions(-) diff --git a/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py b/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py index 387b2fc20a..972cf73c31 100644 --- a/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py +++ b/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py @@ -58,9 +58,6 @@ def run_test(): # try: inferior = gdb.selected_inferior() - if inferior.was_attached == False: - print("SKIPPING (failed to attach)", file=sys.stderr) - exit(0) arch = inferior.architecture() report(arch.name() == "aarch64", "connected to aarch64") except (gdb.error, AttributeError): diff --git a/tests/tcg/aarch64/gdbstub/test-sve.py b/tests/tcg/aarch64/gdbstub/test-sve.py index 5995689625..b96bdbb99a 100644 --- a/tests/tcg/aarch64/gdbstub/test-sve.py +++ b/tests/tcg/aarch64/gdbstub/test-sve.py @@ -59,9 +59,6 @@ def run_test(): # try: inferior = gdb.selected_inferior() - if inferior.was_attached == False: - print("SKIPPING (failed to attach)", file=sys.stderr) - exit(0) arch = inferior.architecture() report(arch.name() == "aarch64", "connected to aarch64") except (gdb.error, AttributeError): From e0a1e2084779fec1adc72866212bda3549fc4c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 30 Apr 2020 20:01:18 +0100 Subject: [PATCH 0276/2595] gdbstub: eliminate gdbserver_fd global MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't really need to track this fd beyond the initial creation of the socket. We already know if the system has been initialised by virtue of the gdbserver_state so lets remove it. This makes the later re-factoring easier. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200430190122.4592-6-alex.bennee@linaro.org> --- gdbstub.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 171e150950..b5381aa520 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -398,8 +398,6 @@ static void reset_gdbserver_state(void) bool gdb_has_xml; #ifdef CONFIG_USER_ONLY -/* XXX: This is not thread safe. Do we care? */ -static int gdbserver_fd = -1; static int get_char(void) { @@ -2964,7 +2962,7 @@ void gdb_exit(CPUArchState *env, int code) return; } #ifdef CONFIG_USER_ONLY - if (gdbserver_fd < 0 || gdbserver_state.fd < 0) { + if (gdbserver_state.fd < 0) { return; } #endif @@ -3011,7 +3009,7 @@ gdb_handlesig(CPUState *cpu, int sig) char buf[256]; int n; - if (gdbserver_fd < 0 || gdbserver_state.fd < 0) { + if (!gdbserver_state.init || gdbserver_state.fd < 0) { return sig; } @@ -3060,7 +3058,7 @@ void gdb_signalled(CPUArchState *env, int sig) { char buf[4]; - if (gdbserver_fd < 0 || gdbserver_state.fd < 0) { + if (!gdbserver_state.init || gdbserver_state.fd < 0) { return; } @@ -3068,7 +3066,7 @@ void gdb_signalled(CPUArchState *env, int sig) put_packet(buf); } -static bool gdb_accept(void) +static bool gdb_accept(int gdb_fd) { struct sockaddr_in sockaddr; socklen_t len; @@ -3076,7 +3074,7 @@ static bool gdb_accept(void) for(;;) { len = sizeof(sockaddr); - fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len); + fd = accept(gdb_fd, (struct sockaddr *)&sockaddr, &len); if (fd < 0 && errno != EINTR) { perror("accept"); return false; @@ -3137,13 +3135,13 @@ static int gdbserver_open(int port) int gdbserver_start(int port) { - gdbserver_fd = gdbserver_open(port); - if (gdbserver_fd < 0) + int gdb_fd = gdbserver_open(port); + if (gdb_fd < 0) { return -1; + } /* accept connections */ - if (!gdb_accept()) { - close(gdbserver_fd); - gdbserver_fd = -1; + if (!gdb_accept(gdb_fd)) { + close(gdb_fd); return -1; } return 0; @@ -3152,7 +3150,7 @@ int gdbserver_start(int port) /* Disable gdb stub for child processes. */ void gdbserver_fork(CPUState *cpu) { - if (gdbserver_fd < 0 || gdbserver_state.fd < 0) { + if (!gdbserver_state.init || gdbserver_state.fd < 0) { return; } close(gdbserver_state.fd); From fcedd920867b8eb26ec803901a24db53a38882c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 30 Apr 2020 20:01:19 +0100 Subject: [PATCH 0277/2595] gdbstub/linux-user: support debugging over a unix socket MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While debugging over TCP is fairly straightforward now we have test cases that want to orchestrate via make and currently a parallel build fails as two processes can't use the same listening port. While system emulation offers a wide cornucopia of connection methods thanks to the chardev abstraction we are a little more limited for linux user. Thankfully the programming API for a TCP socket and a local UNIX socket is pretty much the same once it's set up. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200430190122.4592-7-alex.bennee@linaro.org> --- bsd-user/main.c | 8 ++-- gdbstub.c | 103 ++++++++++++++++++++++++++++++++++------- include/exec/gdbstub.h | 14 ++++-- linux-user/main.c | 12 ++--- 4 files changed, 106 insertions(+), 31 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 770c2b267a..28f122b80e 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -738,7 +738,7 @@ int main(int argc, char **argv) CPUState *cpu; int optind; const char *r; - int gdbstub_port = 0; + const char *gdbstub = NULL; char **target_environ, **wrk; envlist_t *envlist = NULL; char *trace_file = NULL; @@ -814,7 +814,7 @@ int main(int argc, char **argv) exit(1); } } else if (!strcmp(r, "g")) { - gdbstub_port = atoi(argv[optind++]); + gdbstub = g_strdup(argv[optind++]); } else if (!strcmp(r, "r")) { qemu_uname_release = argv[optind++]; } else if (!strcmp(r, "cpu")) { @@ -1124,8 +1124,8 @@ int main(int argc, char **argv) #error unsupported target CPU #endif - if (gdbstub_port) { - gdbserver_start (gdbstub_port); + if (gdbstub) { + gdbserver_start(gdbstub); gdb_handlesig(cpu, 0); } cpu_loop(env); diff --git a/gdbstub.c b/gdbstub.c index b5381aa520..6950fd243f 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -355,6 +355,7 @@ typedef struct GDBState { int signal; #ifdef CONFIG_USER_ONLY int fd; + char *socket_path; int running_state; #else CharBackend chr; @@ -2962,6 +2963,9 @@ void gdb_exit(CPUArchState *env, int code) return; } #ifdef CONFIG_USER_ONLY + if (gdbserver_state.socket_path) { + unlink(gdbserver_state.socket_path); + } if (gdbserver_state.fd < 0) { return; } @@ -3066,7 +3070,66 @@ void gdb_signalled(CPUArchState *env, int sig) put_packet(buf); } -static bool gdb_accept(int gdb_fd) +static void gdb_accept_init(int fd) +{ + init_gdbserver_state(); + create_default_process(&gdbserver_state); + gdbserver_state.processes[0].attached = true; + gdbserver_state.c_cpu = gdb_first_attached_cpu(); + gdbserver_state.g_cpu = gdbserver_state.c_cpu; + gdbserver_state.fd = fd; + gdb_has_xml = false; +} + +static bool gdb_accept_socket(int gdb_fd) +{ + int fd; + + for(;;) { + fd = accept(gdb_fd, NULL, NULL); + if (fd < 0 && errno != EINTR) { + perror("accept socket"); + return false; + } else if (fd >= 0) { + qemu_set_cloexec(fd); + break; + } + } + + gdb_accept_init(fd); + return true; +} + +static int gdbserver_open_socket(const char *path) +{ + struct sockaddr_un sockaddr; + int fd, ret; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + perror("create socket"); + return -1; + } + + sockaddr.sun_family = AF_UNIX; + pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path); + ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); + if (ret < 0) { + perror("bind socket"); + close(fd); + return -1; + } + ret = listen(fd, 1); + if (ret < 0) { + perror("listen socket"); + close(fd); + return -1; + } + + return fd; +} + +static bool gdb_accept_tcp(int gdb_fd) { struct sockaddr_in sockaddr; socklen_t len; @@ -3091,17 +3154,11 @@ static bool gdb_accept(int gdb_fd) return false; } - init_gdbserver_state(); - create_default_process(&gdbserver_state); - gdbserver_state.processes[0].attached = true; - gdbserver_state.c_cpu = gdb_first_attached_cpu(); - gdbserver_state.g_cpu = gdbserver_state.c_cpu; - gdbserver_state.fd = fd; - gdb_has_xml = false; + gdb_accept_init(fd); return true; } -static int gdbserver_open(int port) +static int gdbserver_open_port(int port) { struct sockaddr_in sockaddr; int fd, ret; @@ -3130,21 +3187,35 @@ static int gdbserver_open(int port) close(fd); return -1; } + return fd; } -int gdbserver_start(int port) +int gdbserver_start(const char *port_or_path) { - int gdb_fd = gdbserver_open(port); + int port = g_ascii_strtoull(port_or_path, NULL, 10); + int gdb_fd; + + if (port > 0) { + gdb_fd = gdbserver_open_port(port); + } else { + gdb_fd = gdbserver_open_socket(port_or_path); + } + if (gdb_fd < 0) { return -1; } - /* accept connections */ - if (!gdb_accept(gdb_fd)) { - close(gdb_fd); - return -1; + + if (port > 0 && gdb_accept_tcp(gdb_fd)) { + return 0; + } else if (gdb_accept_socket(gdb_fd)) { + gdbserver_state.socket_path = g_strdup(port_or_path); + return 0; } - return 0; + + /* gone wrong */ + close(gdb_fd); + return -1; } /* Disable gdb stub for child processes. */ diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 4a2b8e3089..94d8f83e92 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -177,11 +177,15 @@ static inline uint8_t * gdb_get_reg_ptr(GByteArray *buf, int len) #endif -#ifdef CONFIG_USER_ONLY -int gdbserver_start(int); -#else -int gdbserver_start(const char *port); -#endif +/** + * gdbserver_start: start the gdb server + * @port_or_device: connection spec for gdb + * + * For CONFIG_USER this is either a tcp port or a path to a fifo. For + * system emulation you can use a full chardev spec for your gdbserver + * port. + */ +int gdbserver_start(const char *port_or_device); void gdbserver_cleanup(void); diff --git a/linux-user/main.c b/linux-user/main.c index 22578b1633..2cd443237d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -51,7 +51,7 @@ char *exec_path; int singlestep; static const char *argv0; -static int gdbstub_port; +static const char *gdbstub; static envlist_t *envlist; static const char *cpu_model; static const char *cpu_type; @@ -310,7 +310,7 @@ static void handle_arg_seed(const char *arg) static void handle_arg_gdb(const char *arg) { - gdbstub_port = atoi(arg); + gdbstub = g_strdup(arg); } static void handle_arg_uname(const char *arg) @@ -861,10 +861,10 @@ int main(int argc, char **argv, char **envp) target_cpu_copy_regs(env, regs); - if (gdbstub_port) { - if (gdbserver_start(gdbstub_port) < 0) { - fprintf(stderr, "qemu: could not open gdbserver on port %d\n", - gdbstub_port); + if (gdbstub) { + if (gdbserver_start(gdbstub) < 0) { + fprintf(stderr, "qemu: could not open gdbserver on %s\n", + gdbstub); exit(EXIT_FAILURE); } gdb_handlesig(cpu, 0); From b0dc2a8ba5709fe10a57e1ff5ee7d6004942e614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 30 Apr 2020 20:01:20 +0100 Subject: [PATCH 0278/2595] tests/guest-debug: use the unix socket for linux-user tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now we have support for debugging over a unix socket for linux-user lets use it in our test harness. Signed-off-by: Alex Bennée Message-Id: <20200430190122.4592-8-alex.bennee@linaro.org> --- tests/guest-debug/run-test.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py index 2bbb8fbaa3..d9af9573b9 100755 --- a/tests/guest-debug/run-test.py +++ b/tests/guest-debug/run-test.py @@ -15,6 +15,8 @@ import argparse import subprocess import shutil import shlex +import os +from tempfile import TemporaryDirectory def get_args(): parser = argparse.ArgumentParser(description="A gdbstub test runner") @@ -41,11 +43,15 @@ if __name__ == '__main__': print("We need gdb to run the test") exit(-1) + socket_dir = TemporaryDirectory("qemu-gdbstub") + socket_name = os.path.join(socket_dir.name, "gdbstub.socket") + # Launch QEMU with binary if "system" in args.qemu: cmd = "%s %s %s -s -S" % (args.qemu, args.qargs, args.binary) else: - cmd = "%s %s -g 1234 %s" % (args.qemu, args.qargs, args.binary) + cmd = "%s %s -g %s %s" % (args.qemu, args.qargs, socket_name, + args.binary) inferior = subprocess.Popen(shlex.split(cmd)) @@ -56,7 +62,10 @@ if __name__ == '__main__': # disable prompts in case of crash gdb_cmd += " -ex 'set confirm off'" # connect to remote - gdb_cmd += " -ex 'target remote localhost:1234'" + if "system" in args.qemu: + gdb_cmd += " -ex 'target remote localhost:1234'" + else: + gdb_cmd += " -ex 'target remote %s'" % (socket_name) # finally the test script itself gdb_cmd += " -x %s" % (args.test) From df3ca22318c01428e82cbe4d2777cdf97c9c1f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 30 Apr 2020 20:01:21 +0100 Subject: [PATCH 0279/2595] tests/tcg: add a multiarch linux-user gdb test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the gdbstub code was converted to the new API we missed a few snafus in the various guests. Add a simple gdb test script which can be used on all our linux-user guests to check for obvious failures. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200430190122.4592-9-alex.bennee@linaro.org> --- tests/tcg/aarch64/Makefile.target | 5 +- tests/tcg/cris/Makefile.target | 1 + tests/tcg/multiarch/Makefile.target | 14 +++++ tests/tcg/multiarch/gdbstub/sha1.py | 81 +++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 tests/tcg/multiarch/gdbstub/sha1.py diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index d99b2a9ece..312f36cde5 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -54,9 +54,6 @@ sve-ioctls: CFLAGS+=-march=armv8.1-a+sve ifneq ($(HAVE_GDB_BIN),) GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py -AARCH64_TESTS += gdbstub-sysregs gdbstub-sve-ioctls - -.PHONY: gdbstub-sysregs gdbstub-sve-ioctls run-gdbstub-sysregs: sysregs $(call run-test, $@, $(GDB_SCRIPT) \ --gdb $(HAVE_GDB_BIN) \ @@ -70,6 +67,8 @@ run-gdbstub-sve-ioctls: sve-ioctls --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(AARCH64_SRC)/gdbstub/test-sve-ioctl.py, \ "basic gdbstub SVE ZLEN support") + +EXTRA_RUNS += run-gdbstub-sysregs run-gdbstub-sve-ioctls endif endif diff --git a/tests/tcg/cris/Makefile.target b/tests/tcg/cris/Makefile.target index 24c7f2e761..e72d3cbdb2 100644 --- a/tests/tcg/cris/Makefile.target +++ b/tests/tcg/cris/Makefile.target @@ -23,6 +23,7 @@ CRIS_RUNS = $(patsubst %, run-%, $(CRIS_USABLE_TESTS)) # override the list of tests, as we can't build the multiarch tests TESTS = $(CRIS_USABLE_TESTS) +EXTRA_RUNS = VPATH = $(CRIS_SRC) AS = $(CC) -x assembler-with-cpp diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index 035b09c853..51fb75ecfd 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -42,5 +42,19 @@ run-test-mmap-%: test-mmap $(call run-test, test-mmap-$*, $(QEMU) -p $* $<,\ "$< ($* byte pages) on $(TARGET_NAME)") +ifneq ($(HAVE_GDB_BIN),) +GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py + +run-gdbstub-sha1: sha1 + $(call run-test, $@, $(GDB_SCRIPT) \ + --gdb $(HAVE_GDB_BIN) \ + --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ + --bin $< --test $(MULTIARCH_SRC)/gdbstub/sha1.py, \ + "basic gdbstub support") + +EXTRA_RUNS += run-gdbstub-sha1 +endif + + # Update TESTS TESTS += $(MULTIARCH_TESTS) diff --git a/tests/tcg/multiarch/gdbstub/sha1.py b/tests/tcg/multiarch/gdbstub/sha1.py new file mode 100644 index 0000000000..734553b98b --- /dev/null +++ b/tests/tcg/multiarch/gdbstub/sha1.py @@ -0,0 +1,81 @@ +from __future__ import print_function +# +# A very simple smoke test for debugging the SHA1 userspace test on +# each target. +# +# This is launched via tests/guest-debug/run-test.py +# + +import gdb +import sys + +initial_vlen = 0 +failcount = 0 + +def report(cond, msg): + "Report success/fail of test" + if cond: + print("PASS: %s" % (msg)) + else: + print("FAIL: %s" % (msg)) + global failcount + failcount += 1 + +def check_break(sym_name): + "Setup breakpoint, continue and check we stopped." + sym, ok = gdb.lookup_symbol(sym_name) + bp = gdb.Breakpoint(sym_name) + + gdb.execute("c") + + # hopefully we came back + end_pc = gdb.parse_and_eval('$pc') + report(bp.hit_count == 1, + "break @ %s (%s %d hits)" % (end_pc, sym.value(), bp.hit_count)) + + bp.delete() + +def run_test(): + "Run through the tests one by one" + + check_break("SHA1Init") + + # check step and inspect values + gdb.execute("next") + val_ctx = gdb.parse_and_eval("context->state[0]") + exp_ctx = 0x67452301 + report(int(val_ctx) == exp_ctx, "context->state[0] == %x" % exp_ctx); + + gdb.execute("next") + val_ctx = gdb.parse_and_eval("context->state[1]") + exp_ctx = 0xEFCDAB89 + report(int(val_ctx) == exp_ctx, "context->state[1] == %x" % exp_ctx); + + # finally check we don't barf inspecting registers + gdb.execute("info registers") + +# +# This runs as the script it sourced (via -x, via run-test.py) +# +try: + inferior = gdb.selected_inferior() + arch = inferior.architecture() + print("ATTACHED: %s" % arch.name()) +except (gdb.error, AttributeError): + print("SKIPPING (not connected)", file=sys.stderr) + exit(0) + +try: + # These are not very useful in scripts + gdb.execute("set pagination off") + gdb.execute("set confirm off") + + # Run the actual tests + run_test() +except (gdb.error): + print ("GDB Exception: %s" % (sys.exc_info()[0])) + failcount += 1 + pass + +print("All tests complete: %d failures" % failcount) +exit(failcount) From a976ed3ffdede7f64c89ac235d0154d048981b5f Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Thu, 30 Apr 2020 20:01:22 +0100 Subject: [PATCH 0280/2595] target/m68k: fix gdb for m68xxx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently "cf-core.xml" is sent to GDB when using any m68k flavor. Thing is it uses the "org.gnu.gdb.coldfire.core" feature name and gdb 8.3 then expects a coldfire FPU instead of the default m68881 FPU. This is not OK because the m68881 floats registers are 96 bits wide so it crashes GDB with the following error message: (gdb) target remote localhost:7960 Remote debugging using localhost:7960 warning: Register "fp0" has an unsupported size (96 bits) warning: Register "fp1" has an unsupported size (96 bits) ... Remote 'g' packet reply is too long (expected 148 bytes, got 180 bytes): \ 00000000000[...]0000 With this patch: qemu-system-m68k -M none -cpu m68020 -s -S (gdb) tar rem :1234 Remote debugging using :1234 warning: No executable has been specified and target does not support determining executable automatically. Try using the "file" command. 0x00000000 in ?? () (gdb) p $fp0 $1 = nan(0xffffffffffffffff) Signed-off-by: KONRAD Frederic Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-Id: <1588094279-17913-3-git-send-email-frederic.konrad@adacore.com> Message-Id: <20200430190122.4592-10-alex.bennee@linaro.org> --- configure | 2 +- gdb-xml/m68k-core.xml | 29 ++++++++++++++++++++++++ target/m68k/cpu.c | 52 ++++++++++++++++++++++++++++++------------- 3 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 gdb-xml/m68k-core.xml diff --git a/configure b/configure index c58787100f..0d69c360c0 100755 --- a/configure +++ b/configure @@ -7825,7 +7825,7 @@ case "$target_name" in ;; m68k) bflt="yes" - gdb_xml_files="cf-core.xml cf-fp.xml m68k-fp.xml" + gdb_xml_files="cf-core.xml cf-fp.xml m68k-core.xml m68k-fp.xml" TARGET_SYSTBL_ABI=common ;; microblaze|microblazeel) diff --git a/gdb-xml/m68k-core.xml b/gdb-xml/m68k-core.xml new file mode 100644 index 0000000000..5b092d26de --- /dev/null +++ b/gdb-xml/m68k-core.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 9445fcd6df..72c545149e 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -292,16 +292,38 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) cc->tcg_initialize = m68k_tcg_init; cc->gdb_num_core_regs = 18; - cc->gdb_core_xml_file = "cf-core.xml"; dc->vmsd = &vmstate_m68k_cpu; } -#define DEFINE_M68K_CPU_TYPE(cpu_model, initfn) \ - { \ - .name = M68K_CPU_TYPE_NAME(cpu_model), \ - .instance_init = initfn, \ - .parent = TYPE_M68K_CPU, \ +static void m68k_cpu_class_init_cf_core(ObjectClass *c, void *data) +{ + CPUClass *cc = CPU_CLASS(c); + + cc->gdb_core_xml_file = "cf-core.xml"; +} + +#define DEFINE_M68K_CPU_TYPE_CF(model) \ + { \ + .name = M68K_CPU_TYPE_NAME(#model), \ + .instance_init = model##_cpu_initfn, \ + .parent = TYPE_M68K_CPU, \ + .class_init = m68k_cpu_class_init_cf_core \ + } + +static void m68k_cpu_class_init_m68k_core(ObjectClass *c, void *data) +{ + CPUClass *cc = CPU_CLASS(c); + + cc->gdb_core_xml_file = "m68k-core.xml"; +} + +#define DEFINE_M68K_CPU_TYPE_M68K(model) \ + { \ + .name = M68K_CPU_TYPE_NAME(#model), \ + .instance_init = model##_cpu_initfn, \ + .parent = TYPE_M68K_CPU, \ + .class_init = m68k_cpu_class_init_m68k_core \ } static const TypeInfo m68k_cpus_type_infos[] = { @@ -314,15 +336,15 @@ static const TypeInfo m68k_cpus_type_infos[] = { .class_size = sizeof(M68kCPUClass), .class_init = m68k_cpu_class_init, }, - DEFINE_M68K_CPU_TYPE("m68000", m68000_cpu_initfn), - DEFINE_M68K_CPU_TYPE("m68020", m68020_cpu_initfn), - DEFINE_M68K_CPU_TYPE("m68030", m68030_cpu_initfn), - DEFINE_M68K_CPU_TYPE("m68040", m68040_cpu_initfn), - DEFINE_M68K_CPU_TYPE("m68060", m68060_cpu_initfn), - DEFINE_M68K_CPU_TYPE("m5206", m5206_cpu_initfn), - DEFINE_M68K_CPU_TYPE("m5208", m5208_cpu_initfn), - DEFINE_M68K_CPU_TYPE("cfv4e", cfv4e_cpu_initfn), - DEFINE_M68K_CPU_TYPE("any", any_cpu_initfn), + DEFINE_M68K_CPU_TYPE_M68K(m68000), + DEFINE_M68K_CPU_TYPE_M68K(m68020), + DEFINE_M68K_CPU_TYPE_M68K(m68030), + DEFINE_M68K_CPU_TYPE_M68K(m68040), + DEFINE_M68K_CPU_TYPE_M68K(m68060), + DEFINE_M68K_CPU_TYPE_CF(m5206), + DEFINE_M68K_CPU_TYPE_CF(m5208), + DEFINE_M68K_CPU_TYPE_CF(cfv4e), + DEFINE_M68K_CPU_TYPE_CF(any), }; DEFINE_TYPES(m68k_cpus_type_infos) From ca14ba5b9af493471e10eaebb86709e98cfcd897 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 27 Apr 2020 16:31:44 +0200 Subject: [PATCH 0281/2595] tpm: tpm-tis-device: set PPI to false by default The tpm-tis-device device does not support PPI. Let's change the default value for the corresponding property instead of tricking this latter in the mach-virt machine. Signed-off-by: Eric Auger Reviewed-by: Cornelia Huck Reviewed-by: Stefan Berger Reviewed-by: Peter Maydell Signed-off-by: Stefan Berger Message-id: 20200427143145.16251-2-eric.auger@redhat.com --- hw/tpm/tpm_tis_sysbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c index 18c02aed67..eced1fc843 100644 --- a/hw/tpm/tpm_tis_sysbus.c +++ b/hw/tpm/tpm_tis_sysbus.c @@ -91,7 +91,7 @@ static void tpm_tis_sysbus_reset(DeviceState *dev) static Property tpm_tis_sysbus_properties[] = { DEFINE_PROP_UINT32("irq", TPMStateSysBus, state.irq_num, TPM_TIS_IRQ), DEFINE_PROP_TPMBE("tpmdev", TPMStateSysBus, state.be_driver), - DEFINE_PROP_BOOL("ppi", TPMStateSysBus, state.ppi_enabled, true), + DEFINE_PROP_BOOL("ppi", TPMStateSysBus, state.ppi_enabled, false), DEFINE_PROP_END_OF_LIST(), }; From b13d31ca17cc22c79b2dc29abd030802e4cc36f4 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 27 Apr 2020 16:31:45 +0200 Subject: [PATCH 0282/2595] hw/arm/virt: Remove the compat forcing tpm-tis-device PPI to off Now that the tpm-tis-device device PPI property is off by default, we can remove the compat used for the same goal. Signed-off-by: Eric Auger Reviewed-by: Cornelia Huck Reviewed-by: Stefan Berger Reviewed-by: Peter Maydell Signed-off-by: Stefan Berger Message-id: 20200427143145.16251-3-eric.auger@redhat.com --- hw/arm/virt.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 171e6908ec..dd024d0780 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2354,11 +2354,6 @@ type_init(machvirt_machine_init); static void virt_machine_5_0_options(MachineClass *mc) { - static GlobalProperty compat[] = { - { TYPE_TPM_TIS_SYSBUS, "ppi", "false" }, - }; - - compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); } DEFINE_VIRT_MACHINE_AS_LATEST(5, 0) From 541aaa1df80df465c7dc934dc8cf57c0e3dfd6c3 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 29 Apr 2020 16:46:05 +0200 Subject: [PATCH 0283/2595] hw: add compat machines for 5.1 Add 5.1 machine types for arm/i440fx/q35/s390x/spapr. Acked-by: David Gibson Reviewed-by: Michael S. Tsirkin Signed-off-by: Cornelia Huck Message-id: 20200429144605.7262-1-cohuck@redhat.com --- hw/arm/virt.c | 10 ++++++++-- hw/core/machine.c | 3 +++ hw/i386/pc.c | 3 +++ hw/i386/pc_piix.c | 14 +++++++++++++- hw/i386/pc_q35.c | 13 ++++++++++++- hw/ppc/spapr.c | 17 ++++++++++++++--- hw/s390x/s390-virtio-ccw.c | 14 +++++++++++++- include/hw/boards.h | 3 +++ include/hw/i386/pc.h | 3 +++ 9 files changed, 72 insertions(+), 8 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index dd024d0780..634db0cfe9 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2352,10 +2352,16 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); -static void virt_machine_5_0_options(MachineClass *mc) +static void virt_machine_5_1_options(MachineClass *mc) { } -DEFINE_VIRT_MACHINE_AS_LATEST(5, 0) +DEFINE_VIRT_MACHINE_AS_LATEST(5, 1) + +static void virt_machine_5_0_options(MachineClass *mc) +{ + virt_machine_5_1_options(mc); +} +DEFINE_VIRT_MACHINE(5, 0) static void virt_machine_4_2_options(MachineClass *mc) { diff --git a/hw/core/machine.c b/hw/core/machine.c index c1a444cb75..7a50dd518f 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -28,6 +28,9 @@ #include "hw/mem/nvdimm.h" #include "migration/vmstate.h" +GlobalProperty hw_compat_5_0[] = {}; +const size_t hw_compat_5_0_len = G_N_ELEMENTS(hw_compat_5_0); + GlobalProperty hw_compat_4_2[] = { { "virtio-blk-device", "queue-size", "128"}, { "virtio-scsi-device", "virtqueue_size", "128"}, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index f6b8431c8b..97e345faea 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -95,6 +95,9 @@ #include "fw_cfg.h" #include "trace.h" +GlobalProperty pc_compat_5_0[] = {}; +const size_t pc_compat_5_0_len = G_N_ELEMENTS(pc_compat_5_0); + GlobalProperty pc_compat_4_2[] = { { "mch", "smbase-smram", "off" }, }; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index b75087d71b..3862e5120e 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -421,7 +421,7 @@ static void pc_i440fx_machine_options(MachineClass *m) machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE); } -static void pc_i440fx_5_0_machine_options(MachineClass *m) +static void pc_i440fx_5_1_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_machine_options(m); @@ -430,6 +430,18 @@ static void pc_i440fx_5_0_machine_options(MachineClass *m) pcmc->default_cpu_version = 1; } +DEFINE_I440FX_MACHINE(v5_1, "pc-i440fx-5.1", NULL, + pc_i440fx_5_1_machine_options); + +static void pc_i440fx_5_0_machine_options(MachineClass *m) +{ + pc_i440fx_5_1_machine_options(m); + m->alias = NULL; + m->is_default = false; + compat_props_add(m->compat_props, hw_compat_5_0, hw_compat_5_0_len); + compat_props_add(m->compat_props, pc_compat_5_0, pc_compat_5_0_len); +} + DEFINE_I440FX_MACHINE(v5_0, "pc-i440fx-5.0", NULL, pc_i440fx_5_0_machine_options); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index d2806c1b29..3349e38a4c 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -351,7 +351,7 @@ static void pc_q35_machine_options(MachineClass *m) m->max_cpus = 288; } -static void pc_q35_5_0_machine_options(MachineClass *m) +static void pc_q35_5_1_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_machine_options(m); @@ -359,6 +359,17 @@ static void pc_q35_5_0_machine_options(MachineClass *m) pcmc->default_cpu_version = 1; } +DEFINE_Q35_MACHINE(v5_1, "pc-q35-5.1", NULL, + pc_q35_5_1_machine_options); + +static void pc_q35_5_0_machine_options(MachineClass *m) +{ + pc_q35_5_1_machine_options(m); + m->alias = NULL; + compat_props_add(m->compat_props, hw_compat_5_0, hw_compat_5_0_len); + compat_props_add(m->compat_props, pc_compat_5_0, pc_compat_5_0_len); +} + DEFINE_Q35_MACHINE(v5_0, "pc-q35-5.0", NULL, pc_q35_5_0_machine_options); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 9a2bd501aa..fd5bfd11a8 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4600,14 +4600,25 @@ static void spapr_machine_latest_class_options(MachineClass *mc) type_init(spapr_machine_register_##suffix) /* - * pseries-5.0 + * pseries-5.1 */ -static void spapr_machine_5_0_class_options(MachineClass *mc) +static void spapr_machine_5_1_class_options(MachineClass *mc) { /* Defaults for the latest behaviour inherited from the base class */ } -DEFINE_SPAPR_MACHINE(5_0, "5.0", true); +DEFINE_SPAPR_MACHINE(5_1, "5.1", true); + +/* + * pseries-5.0 + */ +static void spapr_machine_5_0_class_options(MachineClass *mc) +{ + spapr_machine_5_1_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len); +} + +DEFINE_SPAPR_MACHINE(5_0, "5.0", false); /* * pseries-4.2 diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 45292fb5a8..f660070d22 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -801,14 +801,26 @@ bool css_migration_enabled(void) } \ type_init(ccw_machine_register_##suffix) +static void ccw_machine_5_1_instance_options(MachineState *machine) +{ +} + +static void ccw_machine_5_1_class_options(MachineClass *mc) +{ +} +DEFINE_CCW_MACHINE(5_1, "5.1", true); + static void ccw_machine_5_0_instance_options(MachineState *machine) { + ccw_machine_5_1_instance_options(machine); } static void ccw_machine_5_0_class_options(MachineClass *mc) { + ccw_machine_5_1_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len); } -DEFINE_CCW_MACHINE(5_0, "5.0", true); +DEFINE_CCW_MACHINE(5_0, "5.0", false); static void ccw_machine_4_2_instance_options(MachineState *machine) { diff --git a/include/hw/boards.h b/include/hw/boards.h index fd4d62b501..18815d9be2 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -318,6 +318,9 @@ struct MachineState { } \ type_init(machine_initfn##_register_types) +extern GlobalProperty hw_compat_5_0[]; +extern const size_t hw_compat_5_0_len; + extern GlobalProperty hw_compat_4_2[]; extern const size_t hw_compat_4_2_len; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 05e19455bb..8d764f965c 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -191,6 +191,9 @@ void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory); void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, const CPUArchIdList *apic_ids, GArray *entry); +extern GlobalProperty pc_compat_5_0[]; +extern const size_t pc_compat_5_0_len; + extern GlobalProperty pc_compat_4_2[]; extern const size_t pc_compat_4_2_len; From 44c94677febd15488f9190b11eaa4a08e8ac696b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 28 Mar 2020 14:17:11 -0700 Subject: [PATCH 0284/2595] tcg: Add tcg_gen_gvec_dup_imm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a version of tcg_gen_dup_* that takes both immediate and a vector element size operand. This will replace the set of tcg_gen_gvec_dup{8,16,32,64}i functions that encode the element size within the function name. Reviewed-by: LIU Zhiwei Reviewed-by: David Hildenbrand Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- include/tcg/tcg-op-gvec.h | 2 ++ tcg/tcg-op-gvec.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/include/tcg/tcg-op-gvec.h b/include/tcg/tcg-op-gvec.h index 74534e2480..eb0d47a42b 100644 --- a/include/tcg/tcg-op-gvec.h +++ b/include/tcg/tcg-op-gvec.h @@ -313,6 +313,8 @@ void tcg_gen_gvec_ors(unsigned vece, uint32_t dofs, uint32_t aofs, void tcg_gen_gvec_dup_mem(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t s, uint32_t m); +void tcg_gen_gvec_dup_imm(unsigned vece, uint32_t dofs, uint32_t s, + uint32_t m, uint64_t imm); void tcg_gen_gvec_dup_i32(unsigned vece, uint32_t dofs, uint32_t s, uint32_t m, TCGv_i32); void tcg_gen_gvec_dup_i64(unsigned vece, uint32_t dofs, uint32_t s, diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 327d9588e0..593bb4542e 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -1569,6 +1569,13 @@ void tcg_gen_gvec_dup8i(uint32_t dofs, uint32_t oprsz, do_dup(MO_8, dofs, oprsz, maxsz, NULL, NULL, x); } +void tcg_gen_gvec_dup_imm(unsigned vece, uint32_t dofs, uint32_t oprsz, + uint32_t maxsz, uint64_t x) +{ + check_size_align(oprsz, maxsz, dofs); + do_dup(vece, dofs, oprsz, maxsz, NULL, NULL, x); +} + void tcg_gen_gvec_not(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t oprsz, uint32_t maxsz) { From 8703cfbf98b5d4adea4e715a76b1c79a7a09e060 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 28 Mar 2020 14:42:19 -0700 Subject: [PATCH 0285/2595] target/s390x: Use tcg_gen_gvec_dup_imm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gen_gvec_dupi switch is unnecessary with the new function. Replace it with a local gen_gvec_dup_imm that takes care of the register to offset conversion and length arguments. Drop zero_vec and use use gen_gvec_dup_imm with 0. Reviewed-by: David Hildenbrand Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- target/s390x/translate_vx.inc.c | 41 +++++++-------------------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/target/s390x/translate_vx.inc.c b/target/s390x/translate_vx.inc.c index 24558cce80..12347f8a03 100644 --- a/target/s390x/translate_vx.inc.c +++ b/target/s390x/translate_vx.inc.c @@ -231,8 +231,8 @@ static void get_vec_element_ptr_i64(TCGv_ptr ptr, uint8_t reg, TCGv_i64 enr, #define gen_gvec_mov(v1, v2) \ tcg_gen_gvec_mov(0, vec_full_reg_offset(v1), vec_full_reg_offset(v2), 16, \ 16) -#define gen_gvec_dup64i(v1, c) \ - tcg_gen_gvec_dup64i(vec_full_reg_offset(v1), 16, 16, c) +#define gen_gvec_dup_imm(es, v1, c) \ + tcg_gen_gvec_dup_imm(es, vec_full_reg_offset(v1), 16, 16, c); #define gen_gvec_fn_2(fn, es, v1, v2) \ tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \ 16, 16) @@ -316,31 +316,6 @@ static void gen_gvec128_4_i64(gen_gvec128_4_i64_fn fn, uint8_t d, uint8_t a, tcg_temp_free_i64(cl); } -static void gen_gvec_dupi(uint8_t es, uint8_t reg, uint64_t c) -{ - switch (es) { - case ES_8: - tcg_gen_gvec_dup8i(vec_full_reg_offset(reg), 16, 16, c); - break; - case ES_16: - tcg_gen_gvec_dup16i(vec_full_reg_offset(reg), 16, 16, c); - break; - case ES_32: - tcg_gen_gvec_dup32i(vec_full_reg_offset(reg), 16, 16, c); - break; - case ES_64: - gen_gvec_dup64i(reg, c); - break; - default: - g_assert_not_reached(); - } -} - -static void zero_vec(uint8_t reg) -{ - tcg_gen_gvec_dup8i(vec_full_reg_offset(reg), 16, 16, 0); -} - static void gen_addi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah, uint64_t b) { @@ -396,8 +371,8 @@ static DisasJumpType op_vgbm(DisasContext *s, DisasOps *o) * Masks for both 64 bit elements of the vector are the same. * Trust tcg to produce a good constant loading. */ - gen_gvec_dup64i(get_field(s, v1), - generate_byte_mask(i2 & 0xff)); + gen_gvec_dup_imm(ES_64, get_field(s, v1), + generate_byte_mask(i2 & 0xff)); } else { TCGv_i64 t = tcg_temp_new_i64(); @@ -432,7 +407,7 @@ static DisasJumpType op_vgm(DisasContext *s, DisasOps *o) } } - gen_gvec_dupi(es, get_field(s, v1), mask); + gen_gvec_dup_imm(es, get_field(s, v1), mask); return DISAS_NEXT; } @@ -585,7 +560,7 @@ static DisasJumpType op_vllez(DisasContext *s, DisasOps *o) t = tcg_temp_new_i64(); tcg_gen_qemu_ld_i64(t, o->addr1, get_mem_index(s), MO_TE | es); - zero_vec(get_field(s, v1)); + gen_gvec_dup_imm(es, get_field(s, v1), 0); write_vec_element_i64(t, get_field(s, v1), enr, es); tcg_temp_free_i64(t); return DISAS_NEXT; @@ -892,7 +867,7 @@ static DisasJumpType op_vrepi(DisasContext *s, DisasOps *o) return DISAS_NORETURN; } - gen_gvec_dupi(es, get_field(s, v1), data); + gen_gvec_dup_imm(es, get_field(s, v1), data); return DISAS_NEXT; } @@ -1372,7 +1347,7 @@ static DisasJumpType op_vcksm(DisasContext *s, DisasOps *o) read_vec_element_i32(tmp, get_field(s, v2), i, ES_32); tcg_gen_add2_i32(tmp, sum, sum, sum, tmp, tmp); } - zero_vec(get_field(s, v1)); + gen_gvec_dup_imm(ES_32, get_field(s, v1), 0); write_vec_element_i32(sum, get_field(s, v1), 1, ES_32); tcg_temp_free_i32(tmp); From 36af59d062768d8f86c30801c4192cb4e36034b8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 28 Mar 2020 14:58:36 -0700 Subject: [PATCH 0286/2595] target/ppc: Use tcg_gen_gvec_dup_imm We can now unify the implementation of the 3 VSPLTI instructions. Acked-by: David Gibson Signed-off-by: Richard Henderson --- target/ppc/translate/vmx-impl.inc.c | 32 ++++++++++++++++------------- target/ppc/translate/vsx-impl.inc.c | 2 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c index 81d5a7a341..403ed3a01c 100644 --- a/target/ppc/translate/vmx-impl.inc.c +++ b/target/ppc/translate/vmx-impl.inc.c @@ -1035,21 +1035,25 @@ GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \ GEN_VXRFORM_DUAL(vcmpgtfp, PPC_ALTIVEC, PPC_NONE, \ vcmpgtud, PPC_NONE, PPC2_ALTIVEC_207) -#define GEN_VXFORM_DUPI(name, tcg_op, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ - { \ - int simm; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - simm = SIMM5(ctx->opcode); \ - tcg_op(avr_full_offset(rD(ctx->opcode)), 16, 16, simm); \ +static void gen_vsplti(DisasContext *ctx, int vece) +{ + int simm; + + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; } -GEN_VXFORM_DUPI(vspltisb, tcg_gen_gvec_dup8i, 6, 12); -GEN_VXFORM_DUPI(vspltish, tcg_gen_gvec_dup16i, 6, 13); -GEN_VXFORM_DUPI(vspltisw, tcg_gen_gvec_dup32i, 6, 14); + simm = SIMM5(ctx->opcode); + tcg_gen_gvec_dup_imm(vece, avr_full_offset(rD(ctx->opcode)), 16, 16, simm); +} + +#define GEN_VXFORM_VSPLTI(name, vece, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) { gen_vsplti(ctx, vece); } + +GEN_VXFORM_VSPLTI(vspltisb, MO_8, 6, 12); +GEN_VXFORM_VSPLTI(vspltish, MO_16, 6, 13); +GEN_VXFORM_VSPLTI(vspltisw, MO_32, 6, 14); #define GEN_VXFORM_NOA(name, opc2, opc3) \ static void glue(gen_, name)(DisasContext *ctx) \ @@ -1559,7 +1563,7 @@ GEN_VXFORM_DUAL(vsldoi, PPC_ALTIVEC, PPC_NONE, #undef GEN_VXRFORM_DUAL #undef GEN_VXRFORM1 #undef GEN_VXRFORM -#undef GEN_VXFORM_DUPI +#undef GEN_VXFORM_VSPLTI #undef GEN_VXFORM_NOA #undef GEN_VXFORM_UIMM #undef GEN_VAFORM_PAIRED diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c index 8287e272f5..b518de46db 100644 --- a/target/ppc/translate/vsx-impl.inc.c +++ b/target/ppc/translate/vsx-impl.inc.c @@ -1579,7 +1579,7 @@ static void gen_xxspltib(DisasContext *ctx) return; } } - tcg_gen_gvec_dup8i(vsr_full_offset(rt), 16, 16, uim8); + tcg_gen_gvec_dup_imm(MO_8, vsr_full_offset(rt), 16, 16, uim8); } static void gen_xxsldwi(DisasContext *ctx) From 8711e71f9cbb692d614e6ecf5d51222372f7b77e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 28 Mar 2020 15:12:52 -0700 Subject: [PATCH 0287/2595] target/arm: Use tcg_gen_gvec_dup_imm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In a few cases, we're able to remove some manual replication. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- target/arm/translate-a64.c | 10 +++++----- target/arm/translate-sve.c | 12 +++++------- target/arm/translate.c | 9 ++++++--- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index a896f9c4b8..62e5729904 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -502,7 +502,7 @@ static void clear_vec_high(DisasContext *s, bool is_q, int rd) tcg_temp_free_i64(tcg_zero); } if (vsz > 16) { - tcg_gen_gvec_dup8i(ofs + 16, vsz - 16, vsz - 16, 0); + tcg_gen_gvec_dup_imm(MO_64, ofs + 16, vsz - 16, vsz - 16, 0); } } @@ -7785,8 +7785,8 @@ static void disas_simd_mod_imm(DisasContext *s, uint32_t insn) if (!((cmode & 0x9) == 0x1 || (cmode & 0xd) == 0x9)) { /* MOVI or MVNI, with MVNI negation handled above. */ - tcg_gen_gvec_dup64i(vec_full_reg_offset(s, rd), is_q ? 16 : 8, - vec_full_reg_size(s), imm); + tcg_gen_gvec_dup_imm(MO_64, vec_full_reg_offset(s, rd), is_q ? 16 : 8, + vec_full_reg_size(s), imm); } else { /* ORR or BIC, with BIC negation to AND handled above. */ if (is_neg) { @@ -10214,8 +10214,8 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, if (is_u) { if (shift == 8 << size) { /* Shift count the same size as element size produces zero. */ - tcg_gen_gvec_dup8i(vec_full_reg_offset(s, rd), - is_q ? 16 : 8, vec_full_reg_size(s), 0); + tcg_gen_gvec_dup_imm(size, vec_full_reg_offset(s, rd), + is_q ? 16 : 8, vec_full_reg_size(s), 0); } else { gen_gvec_fn2i(s, is_q, rd, rn, shift, tcg_gen_gvec_shri, size); } diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index b35bad245e..6c8bda4e4c 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -177,7 +177,7 @@ static bool do_mov_z(DisasContext *s, int rd, int rn) static void do_dupi_z(DisasContext *s, int rd, uint64_t word) { unsigned vsz = vec_full_reg_size(s); - tcg_gen_gvec_dup64i(vec_full_reg_offset(s, rd), vsz, vsz, word); + tcg_gen_gvec_dup_imm(MO_64, vec_full_reg_offset(s, rd), vsz, vsz, word); } /* Invoke a vector expander on two Pregs. */ @@ -1453,7 +1453,7 @@ static bool do_predset(DisasContext *s, int esz, int rd, int pat, bool setflag) unsigned oprsz = size_for_gvec(setsz / 8); if (oprsz * 8 == setsz) { - tcg_gen_gvec_dup64i(ofs, oprsz, maxsz, word); + tcg_gen_gvec_dup_imm(MO_64, ofs, oprsz, maxsz, word); goto done; } } @@ -2044,7 +2044,7 @@ static bool trans_DUP_x(DisasContext *s, arg_DUP_x *a) unsigned nofs = vec_reg_offset(s, a->rn, index, esz); tcg_gen_gvec_dup_mem(esz, dofs, nofs, vsz, vsz); } else { - tcg_gen_gvec_dup64i(dofs, vsz, vsz, 0); + tcg_gen_gvec_dup_imm(esz, dofs, vsz, vsz, 0); } } return true; @@ -3260,9 +3260,7 @@ static bool trans_FDUP(DisasContext *s, arg_FDUP *a) /* Decode the VFP immediate. */ imm = vfp_expand_imm(a->esz, a->imm); - imm = dup_const(a->esz, imm); - - tcg_gen_gvec_dup64i(dofs, vsz, vsz, imm); + tcg_gen_gvec_dup_imm(a->esz, dofs, vsz, vsz, imm); } return true; } @@ -3276,7 +3274,7 @@ static bool trans_DUP_i(DisasContext *s, arg_DUP_i *a) unsigned vsz = vec_full_reg_size(s); int dofs = vec_full_reg_offset(s, a->rd); - tcg_gen_gvec_dup64i(dofs, vsz, vsz, dup_const(a->esz, a->imm)); + tcg_gen_gvec_dup_imm(a->esz, dofs, vsz, vsz, a->imm); } return true; } diff --git a/target/arm/translate.c b/target/arm/translate.c index 025747c0bd..74fac1d09c 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5209,7 +5209,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) MIN(shift, (8 << size) - 1), vec_size, vec_size); } else if (shift >= 8 << size) { - tcg_gen_gvec_dup8i(rd_ofs, vec_size, vec_size, 0); + tcg_gen_gvec_dup_imm(MO_8, rd_ofs, vec_size, + vec_size, 0); } else { tcg_gen_gvec_shri(size, rd_ofs, rm_ofs, shift, vec_size, vec_size); @@ -5260,7 +5261,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) * architecturally valid and results in zero. */ if (shift >= 8 << size) { - tcg_gen_gvec_dup8i(rd_ofs, vec_size, vec_size, 0); + tcg_gen_gvec_dup_imm(size, rd_ofs, + vec_size, vec_size, 0); } else { tcg_gen_gvec_shli(size, rd_ofs, rm_ofs, shift, vec_size, vec_size); @@ -5606,7 +5608,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } tcg_temp_free_i64(t64); } else { - tcg_gen_gvec_dup32i(reg_ofs, vec_size, vec_size, imm); + tcg_gen_gvec_dup_imm(MO_32, reg_ofs, vec_size, + vec_size, imm); } } } From 03ddb6f315ca6d02dfdba0aecc43aa97c728c428 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 28 Mar 2020 16:10:42 -0700 Subject: [PATCH 0288/2595] tcg: Use tcg_gen_gvec_dup_imm in logical simplifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the outgoing interface. Reviewed-by: LIU Zhiwei Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/tcg-op-gvec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 593bb4542e..de16c027b3 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -2326,7 +2326,7 @@ void tcg_gen_gvec_xor(unsigned vece, uint32_t dofs, uint32_t aofs, }; if (aofs == bofs) { - tcg_gen_gvec_dup8i(dofs, oprsz, maxsz, 0); + tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, 0); } else { tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g); } @@ -2343,7 +2343,7 @@ void tcg_gen_gvec_andc(unsigned vece, uint32_t dofs, uint32_t aofs, }; if (aofs == bofs) { - tcg_gen_gvec_dup8i(dofs, oprsz, maxsz, 0); + tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, 0); } else { tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g); } @@ -2360,7 +2360,7 @@ void tcg_gen_gvec_orc(unsigned vece, uint32_t dofs, uint32_t aofs, }; if (aofs == bofs) { - tcg_gen_gvec_dup8i(dofs, oprsz, maxsz, -1); + tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, -1); } else { tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g); } @@ -2411,7 +2411,7 @@ void tcg_gen_gvec_eqv(unsigned vece, uint32_t dofs, uint32_t aofs, }; if (aofs == bofs) { - tcg_gen_gvec_dup8i(dofs, oprsz, maxsz, -1); + tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, -1); } else { tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g); } From 398f21412aeec158338963e3f71c9313bc126a71 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 28 Mar 2020 16:10:51 -0700 Subject: [PATCH 0289/2595] tcg: Remove tcg_gen_gvec_dup{8,16,32,64}i MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These interfaces are now unused. Reviewed-by: LIU Zhiwei Reviewed-by: David Hildenbrand Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- include/tcg/tcg-op-gvec.h | 5 ----- tcg/tcg-op-gvec.c | 28 ---------------------------- 2 files changed, 33 deletions(-) diff --git a/include/tcg/tcg-op-gvec.h b/include/tcg/tcg-op-gvec.h index eb0d47a42b..fa8a0c8d03 100644 --- a/include/tcg/tcg-op-gvec.h +++ b/include/tcg/tcg-op-gvec.h @@ -320,11 +320,6 @@ void tcg_gen_gvec_dup_i32(unsigned vece, uint32_t dofs, uint32_t s, void tcg_gen_gvec_dup_i64(unsigned vece, uint32_t dofs, uint32_t s, uint32_t m, TCGv_i64); -void tcg_gen_gvec_dup8i(uint32_t dofs, uint32_t s, uint32_t m, uint8_t x); -void tcg_gen_gvec_dup16i(uint32_t dofs, uint32_t s, uint32_t m, uint16_t x); -void tcg_gen_gvec_dup32i(uint32_t dofs, uint32_t s, uint32_t m, uint32_t x); -void tcg_gen_gvec_dup64i(uint32_t dofs, uint32_t s, uint32_t m, uint64_t x); - void tcg_gen_gvec_shli(unsigned vece, uint32_t dofs, uint32_t aofs, int64_t shift, uint32_t oprsz, uint32_t maxsz); void tcg_gen_gvec_shri(unsigned vece, uint32_t dofs, uint32_t aofs, diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index de16c027b3..5a6cc19812 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -1541,34 +1541,6 @@ void tcg_gen_gvec_dup_mem(unsigned vece, uint32_t dofs, uint32_t aofs, } } -void tcg_gen_gvec_dup64i(uint32_t dofs, uint32_t oprsz, - uint32_t maxsz, uint64_t x) -{ - check_size_align(oprsz, maxsz, dofs); - do_dup(MO_64, dofs, oprsz, maxsz, NULL, NULL, x); -} - -void tcg_gen_gvec_dup32i(uint32_t dofs, uint32_t oprsz, - uint32_t maxsz, uint32_t x) -{ - check_size_align(oprsz, maxsz, dofs); - do_dup(MO_32, dofs, oprsz, maxsz, NULL, NULL, x); -} - -void tcg_gen_gvec_dup16i(uint32_t dofs, uint32_t oprsz, - uint32_t maxsz, uint16_t x) -{ - check_size_align(oprsz, maxsz, dofs); - do_dup(MO_16, dofs, oprsz, maxsz, NULL, NULL, x); -} - -void tcg_gen_gvec_dup8i(uint32_t dofs, uint32_t oprsz, - uint32_t maxsz, uint8_t x) -{ - check_size_align(oprsz, maxsz, dofs); - do_dup(MO_8, dofs, oprsz, maxsz, NULL, NULL, x); -} - void tcg_gen_gvec_dup_imm(unsigned vece, uint32_t dofs, uint32_t oprsz, uint32_t maxsz, uint64_t x) { From 0f039e3ad9131966d9fe509c231b756868b015e2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 28 Mar 2020 16:17:45 -0700 Subject: [PATCH 0290/2595] tcg: Add tcg_gen_gvec_dup_tl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For use when a target needs to pass a configure-specific target_ulong value to duplicate. Reviewed-by: LIU Zhiwei Reviewed-by: David Hildenbrand Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- include/tcg/tcg-op-gvec.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/tcg/tcg-op-gvec.h b/include/tcg/tcg-op-gvec.h index fa8a0c8d03..d89f91f40e 100644 --- a/include/tcg/tcg-op-gvec.h +++ b/include/tcg/tcg-op-gvec.h @@ -320,6 +320,12 @@ void tcg_gen_gvec_dup_i32(unsigned vece, uint32_t dofs, uint32_t s, void tcg_gen_gvec_dup_i64(unsigned vece, uint32_t dofs, uint32_t s, uint32_t m, TCGv_i64); +#if TARGET_LONG_BITS == 64 +# define tcg_gen_gvec_dup_tl tcg_gen_gvec_dup_i64 +#else +# define tcg_gen_gvec_dup_tl tcg_gen_gvec_dup_i32 +#endif + void tcg_gen_gvec_shli(unsigned vece, uint32_t dofs, uint32_t aofs, int64_t shift, uint32_t oprsz, uint32_t maxsz); void tcg_gen_gvec_shri(unsigned vece, uint32_t dofs, uint32_t aofs, From f47db80cc073c0a7a22136c8296b5eca20c0e199 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 28 Mar 2020 19:47:07 -0700 Subject: [PATCH 0291/2595] tcg: Improve vector tail clearing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Better handling of non-power-of-2 tails as seen with Arm 8-byte vector operations. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/tcg-op-gvec.c | 82 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 5a6cc19812..43cac1a0bf 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -326,11 +326,34 @@ void tcg_gen_gvec_5_ptr(uint32_t dofs, uint32_t aofs, uint32_t bofs, in units of LNSZ. This limits the expansion of inline code. */ static inline bool check_size_impl(uint32_t oprsz, uint32_t lnsz) { - if (oprsz % lnsz == 0) { - uint32_t lnct = oprsz / lnsz; - return lnct >= 1 && lnct <= MAX_UNROLL; + uint32_t q, r; + + if (oprsz < lnsz) { + return false; } - return false; + + q = oprsz / lnsz; + r = oprsz % lnsz; + tcg_debug_assert((r & 7) == 0); + + if (lnsz < 16) { + /* For sizes below 16, accept no remainder. */ + if (r != 0) { + return false; + } + } else { + /* + * Recall that ARM SVE allows vector sizes that are not a + * power of 2, but always a multiple of 16. The intent is + * that e.g. size == 80 would be expanded with 2x32 + 1x16. + * In addition, expand_clr needs to handle a multiple of 8. + * Thus we can handle the tail with one more operation per + * diminishing power of 2. + */ + q += ctpop32(r); + } + + return q <= MAX_UNROLL; } static void expand_clr(uint32_t dofs, uint32_t maxsz); @@ -402,22 +425,31 @@ static void gen_dup_i64(unsigned vece, TCGv_i64 out, TCGv_i64 in) static TCGType choose_vector_type(const TCGOpcode *list, unsigned vece, uint32_t size, bool prefer_i64) { - if (TCG_TARGET_HAS_v256 && check_size_impl(size, 32)) { - /* - * Recall that ARM SVE allows vector sizes that are not a - * power of 2, but always a multiple of 16. The intent is - * that e.g. size == 80 would be expanded with 2x32 + 1x16. - * It is hard to imagine a case in which v256 is supported - * but v128 is not, but check anyway. - */ - if (tcg_can_emit_vecop_list(list, TCG_TYPE_V256, vece) - && (size % 32 == 0 - || tcg_can_emit_vecop_list(list, TCG_TYPE_V128, vece))) { - return TCG_TYPE_V256; - } + /* + * Recall that ARM SVE allows vector sizes that are not a + * power of 2, but always a multiple of 16. The intent is + * that e.g. size == 80 would be expanded with 2x32 + 1x16. + * It is hard to imagine a case in which v256 is supported + * but v128 is not, but check anyway. + * In addition, expand_clr needs to handle a multiple of 8. + */ + if (TCG_TARGET_HAS_v256 && + check_size_impl(size, 32) && + tcg_can_emit_vecop_list(list, TCG_TYPE_V256, vece) && + (!(size & 16) || + (TCG_TARGET_HAS_v128 && + tcg_can_emit_vecop_list(list, TCG_TYPE_V128, vece))) && + (!(size & 8) || + (TCG_TARGET_HAS_v64 && + tcg_can_emit_vecop_list(list, TCG_TYPE_V64, vece)))) { + return TCG_TYPE_V256; } - if (TCG_TARGET_HAS_v128 && check_size_impl(size, 16) - && tcg_can_emit_vecop_list(list, TCG_TYPE_V128, vece)) { + if (TCG_TARGET_HAS_v128 && + check_size_impl(size, 16) && + tcg_can_emit_vecop_list(list, TCG_TYPE_V128, vece) && + (!(size & 8) || + (TCG_TARGET_HAS_v64 && + tcg_can_emit_vecop_list(list, TCG_TYPE_V64, vece)))) { return TCG_TYPE_V128; } if (TCG_TARGET_HAS_v64 && !prefer_i64 && check_size_impl(size, 8) @@ -432,6 +464,18 @@ static void do_dup_store(TCGType type, uint32_t dofs, uint32_t oprsz, { uint32_t i = 0; + tcg_debug_assert(oprsz >= 8); + + /* + * This may be expand_clr for the tail of an operation, e.g. + * oprsz == 8 && maxsz == 64. The first 8 bytes of this store + * are misaligned wrt the maximum vector size, so do that first. + */ + if (dofs & 8) { + tcg_gen_stl_vec(t_vec, cpu_env, dofs + i, TCG_TYPE_V64); + i += 8; + } + switch (type) { case TCG_TYPE_V256: /* From ac09ae627e9a2c65c8a452b69c3dac33c29d0719 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Apr 2020 15:22:47 -0700 Subject: [PATCH 0292/2595] tcg: Add load_dest parameter to GVecGen2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have this same parameter for GVecGen2i, GVecGen3, and GVecGen3i. This will make some SVE2 insns easier to parameterize. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- include/tcg/tcg-op-gvec.h | 2 ++ tcg/tcg-op-gvec.c | 45 ++++++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/include/tcg/tcg-op-gvec.h b/include/tcg/tcg-op-gvec.h index d89f91f40e..cea6497341 100644 --- a/include/tcg/tcg-op-gvec.h +++ b/include/tcg/tcg-op-gvec.h @@ -109,6 +109,8 @@ typedef struct { uint8_t vece; /* Prefer i64 to v64. */ bool prefer_i64; + /* Load dest as a 2nd source operand. */ + bool load_dest; } GVecGen2; typedef struct { diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 43cac1a0bf..049a55e700 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -663,17 +663,22 @@ static void expand_clr(uint32_t dofs, uint32_t maxsz) /* Expand OPSZ bytes worth of two-operand operations using i32 elements. */ static void expand_2_i32(uint32_t dofs, uint32_t aofs, uint32_t oprsz, - void (*fni)(TCGv_i32, TCGv_i32)) + bool load_dest, void (*fni)(TCGv_i32, TCGv_i32)) { TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); uint32_t i; for (i = 0; i < oprsz; i += 4) { tcg_gen_ld_i32(t0, cpu_env, aofs + i); - fni(t0, t0); - tcg_gen_st_i32(t0, cpu_env, dofs + i); + if (load_dest) { + tcg_gen_ld_i32(t1, cpu_env, dofs + i); + } + fni(t1, t0); + tcg_gen_st_i32(t1, cpu_env, dofs + i); } tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); } static void expand_2i_i32(uint32_t dofs, uint32_t aofs, uint32_t oprsz, @@ -793,17 +798,22 @@ static void expand_4_i32(uint32_t dofs, uint32_t aofs, uint32_t bofs, /* Expand OPSZ bytes worth of two-operand operations using i64 elements. */ static void expand_2_i64(uint32_t dofs, uint32_t aofs, uint32_t oprsz, - void (*fni)(TCGv_i64, TCGv_i64)) + bool load_dest, void (*fni)(TCGv_i64, TCGv_i64)) { TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); uint32_t i; for (i = 0; i < oprsz; i += 8) { tcg_gen_ld_i64(t0, cpu_env, aofs + i); - fni(t0, t0); - tcg_gen_st_i64(t0, cpu_env, dofs + i); + if (load_dest) { + tcg_gen_ld_i64(t1, cpu_env, dofs + i); + } + fni(t1, t0); + tcg_gen_st_i64(t1, cpu_env, dofs + i); } tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } static void expand_2i_i64(uint32_t dofs, uint32_t aofs, uint32_t oprsz, @@ -924,17 +934,23 @@ static void expand_4_i64(uint32_t dofs, uint32_t aofs, uint32_t bofs, /* Expand OPSZ bytes worth of two-operand operations using host vectors. */ static void expand_2_vec(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t oprsz, uint32_t tysz, TCGType type, + bool load_dest, void (*fni)(unsigned, TCGv_vec, TCGv_vec)) { TCGv_vec t0 = tcg_temp_new_vec(type); + TCGv_vec t1 = tcg_temp_new_vec(type); uint32_t i; for (i = 0; i < oprsz; i += tysz) { tcg_gen_ld_vec(t0, cpu_env, aofs + i); - fni(vece, t0, t0); - tcg_gen_st_vec(t0, cpu_env, dofs + i); + if (load_dest) { + tcg_gen_ld_vec(t1, cpu_env, dofs + i); + } + fni(vece, t1, t0); + tcg_gen_st_vec(t1, cpu_env, dofs + i); } tcg_temp_free_vec(t0); + tcg_temp_free_vec(t1); } /* Expand OPSZ bytes worth of two-vector operands and an immediate operand @@ -1088,7 +1104,8 @@ void tcg_gen_gvec_2(uint32_t dofs, uint32_t aofs, * that e.g. size == 80 would be expanded with 2x32 + 1x16. */ some = QEMU_ALIGN_DOWN(oprsz, 32); - expand_2_vec(g->vece, dofs, aofs, some, 32, TCG_TYPE_V256, g->fniv); + expand_2_vec(g->vece, dofs, aofs, some, 32, TCG_TYPE_V256, + g->load_dest, g->fniv); if (some == oprsz) { break; } @@ -1098,17 +1115,19 @@ void tcg_gen_gvec_2(uint32_t dofs, uint32_t aofs, maxsz -= some; /* fallthru */ case TCG_TYPE_V128: - expand_2_vec(g->vece, dofs, aofs, oprsz, 16, TCG_TYPE_V128, g->fniv); + expand_2_vec(g->vece, dofs, aofs, oprsz, 16, TCG_TYPE_V128, + g->load_dest, g->fniv); break; case TCG_TYPE_V64: - expand_2_vec(g->vece, dofs, aofs, oprsz, 8, TCG_TYPE_V64, g->fniv); + expand_2_vec(g->vece, dofs, aofs, oprsz, 8, TCG_TYPE_V64, + g->load_dest, g->fniv); break; case 0: if (g->fni8 && check_size_impl(oprsz, 8)) { - expand_2_i64(dofs, aofs, oprsz, g->fni8); + expand_2_i64(dofs, aofs, oprsz, g->load_dest, g->fni8); } else if (g->fni4 && check_size_impl(oprsz, 4)) { - expand_2_i32(dofs, aofs, oprsz, g->fni4); + expand_2_i32(dofs, aofs, oprsz, g->load_dest, g->fni4); } else { assert(g->fno != NULL); tcg_gen_gvec_2_ool(dofs, aofs, oprsz, maxsz, g->data, g->fno); From 07dada0336a83002dfa8673a9220a88e13d9a45c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 19 Apr 2020 17:58:23 -0700 Subject: [PATCH 0293/2595] tcg: Fix integral argument type to tcg_gen_rot[rl]i_i{32,64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the benefit of compatibility of function pointer types, we have standardized on int32_t and int64_t as the integral argument to tcg expanders. We converted most of them in 474b2e8f0f7, but missed the rotates. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/tcg/tcg-op.h | 8 ++++---- tcg/tcg-op.c | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index 230db6e022..e3399d6a5e 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -297,9 +297,9 @@ void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2); void tcg_gen_clrsb_i32(TCGv_i32 ret, TCGv_i32 arg); void tcg_gen_ctpop_i32(TCGv_i32 a1, TCGv_i32 a2); void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2); -void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2); +void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2); void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2); -void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2); +void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2); void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2, unsigned int ofs, unsigned int len); void tcg_gen_deposit_z_i32(TCGv_i32 ret, TCGv_i32 arg, @@ -493,9 +493,9 @@ void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2); void tcg_gen_clrsb_i64(TCGv_i64 ret, TCGv_i64 arg); void tcg_gen_ctpop_i64(TCGv_i64 a1, TCGv_i64 a2); void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2); -void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2); +void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2); void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2); -void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2); +void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2); void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2, unsigned int ofs, unsigned int len); void tcg_gen_deposit_z_i64(TCGv_i64 ret, TCGv_i64 arg, diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index e2e25ebf7d..e60b74fb82 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -540,9 +540,9 @@ void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) } } -void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2) +void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) { - tcg_debug_assert(arg2 < 32); + tcg_debug_assert(arg2 >= 0 && arg2 < 32); /* some cases can be optimized here */ if (arg2 == 0) { tcg_gen_mov_i32(ret, arg1); @@ -580,9 +580,9 @@ void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) } } -void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2) +void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) { - tcg_debug_assert(arg2 < 32); + tcg_debug_assert(arg2 >= 0 && arg2 < 32); /* some cases can be optimized here */ if (arg2 == 0) { tcg_gen_mov_i32(ret, arg1); @@ -1962,9 +1962,9 @@ void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) } } -void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2) +void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) { - tcg_debug_assert(arg2 < 64); + tcg_debug_assert(arg2 >= 0 && arg2 < 64); /* some cases can be optimized here */ if (arg2 == 0) { tcg_gen_mov_i64(ret, arg1); @@ -2001,9 +2001,9 @@ void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) } } -void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2) +void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) { - tcg_debug_assert(arg2 < 64); + tcg_debug_assert(arg2 >= 0 && arg2 < 64); /* some cases can be optimized here */ if (arg2 == 0) { tcg_gen_mov_i64(ret, arg1); From 6dc6b557913f29e012880e381c0a3f452b415f1d Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 17 Mar 2020 15:49:17 +1000 Subject: [PATCH 0294/2595] target/ppc: Improve syscall exception logging system calls (at least in Linux) use registers r3-r8 for inputs, so include those registers in the dump. This also adds a mode for PAPR hcalls, which have a different calling convention. Signed-off-by: Nicholas Piggin Message-Id: <20200317054918.199161-1-npiggin@gmail.com> Signed-off-by: David Gibson --- target/ppc/excp_helper.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 08bc885ca6..81ee19ebae 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -57,12 +57,29 @@ static void ppc_hw_interrupt(CPUPPCState *env) #else /* defined(CONFIG_USER_ONLY) */ static inline void dump_syscall(CPUPPCState *env) { - qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64 - " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 + qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 + " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64 + " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64 " nip=" TARGET_FMT_lx "\n", ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), - ppc_dump_gpr(env, 6), env->nip); + ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7), + ppc_dump_gpr(env, 8), env->nip); +} + +static inline void dump_hcall(CPUPPCState *env) +{ + qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64 + " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 + " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64 + " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64 + " nip=" TARGET_FMT_lx "\n", + ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4), + ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6), + ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8), + ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10), + ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12), + env->nip); } static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, @@ -379,9 +396,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } break; case POWERPC_EXCP_SYSCALL: /* System call exception */ - dump_syscall(env); lev = env->error_code; + if ((lev == 1) && cpu->vhyp) { + dump_hcall(env); + } else { + dump_syscall(env); + } + /* * We need to correct the NIP which in this case is supposed * to point to the next instruction From 86962462f89b2abbba18e5c2243d59bd408f04d4 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 25 Mar 2020 16:25:30 +0100 Subject: [PATCH 0295/2595] spapr: Don't check capabilities removed between CAS calls We currently check if some capability in OV5 was removed by the guest since the previous CAS, and we trigger a CAS reboot in that case. This was required because it could call for a device-tree property or node removal, that we didn't support until recently (see commit 6787d27b04a7 "spapr: add option vector handling in CAS-generated resets" for details). Now that we render a full FDT at CAS and that SLOF is able to handle node removal, we don't need to do a CAS reset in this case anymore. Also, this check can only return true if the guest has already called CAS since the last full system reset (otherwise spapr->ov5_cas is empty). Linux doesn't do that so this can be considered as dead code for the vast majority of existing setups. Drop the check. Since the only use of the ov5_cas_old variable is precisely the check itself, drop the variable as well. Signed-off-by: Greg Kurz Message-Id: <158514993021.478799.10928618293640651819.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/spapr_hcall.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 0d50fc9117..e8ee447537 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1676,7 +1676,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, target_ulong fdt_bufsize = args[2]; target_ulong ov_table; uint32_t cas_pvr; - SpaprOptionVector *ov1_guest, *ov5_guest, *ov5_cas_old; + SpaprOptionVector *ov1_guest, *ov5_guest; bool guest_radix; Error *local_err = NULL; bool raw_mode_supported = false; @@ -1782,22 +1782,10 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, * by LoPAPR 1.1, 14.5.4.8, which QEMU doesn't implement, we don't need * to worry about this for now. */ - ov5_cas_old = spapr_ovec_clone(spapr->ov5_cas); - - /* also clear the radix/hash bit from the current ov5_cas bits to - * be in sync with the newly ov5 bits. Else the radix bit will be - * seen as being removed and this will generate a reset loop - */ - spapr_ovec_clear(ov5_cas_old, OV5_MMU_RADIX_300); /* full range of negotiated ov5 capabilities */ spapr_ovec_intersect(spapr->ov5_cas, spapr->ov5, ov5_guest); spapr_ovec_cleanup(ov5_guest); - /* capabilities that have been added since CAS-generated guest reset. - * if capabilities have since been removed, generate another reset - */ - spapr->cas_reboot = !spapr_ovec_subset(ov5_cas_old, spapr->ov5_cas); - spapr_ovec_cleanup(ov5_cas_old); /* Now that processing is finished, set the radix/hash bit for the * guest if it requested a valid mode; otherwise terminate the boot. */ if (guest_radix) { From b5b7f391817558f645034ea2e26bbed1e75eb731 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 26 Mar 2020 00:41:43 +1000 Subject: [PATCH 0296/2595] ppc/spapr: tweak change system reset helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than have the helper take an optional vector address override, instead have its caller modify env->nip itself. This is more consistent when adding pnv nmi support, and also with mce injection added later. Signed-off-by: Nicholas Piggin Message-Id: <20200325144147.221875-2-npiggin@gmail.com> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr.c | 9 ++++++--- target/ppc/cpu.h | 2 +- target/ppc/excp_helper.c | 5 +---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 9a2bd501aa..785c41d205 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3385,13 +3385,13 @@ static void spapr_machine_finalizefn(Object *obj) void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg) { SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; cpu_synchronize_state(cs); /* If FWNMI is inactive, addr will be -1, which will deliver to 0x100 */ if (spapr->fwnmi_system_reset_addr != -1) { uint64_t rtas_addr, addr; - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; /* get rtas addr from fdt */ rtas_addr = spapr_get_rtas_addr(); @@ -3405,7 +3405,10 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg) stq_be_phys(&address_space_memory, addr + sizeof(uint64_t), 0); env->gpr[3] = addr; } - ppc_cpu_do_system_reset(cs, spapr->fwnmi_system_reset_addr); + ppc_cpu_do_system_reset(cs); + if (spapr->fwnmi_system_reset_addr != -1) { + env->nip = spapr->fwnmi_system_reset_addr; + } } static void spapr_nmi(NMIState *n, int cpu_index, Error **errp) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 88d9449555..f4a5304d43 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1220,7 +1220,7 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, int cpuid, void *opaque); #ifndef CONFIG_USER_ONLY -void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector); +void ppc_cpu_do_system_reset(CPUState *cs); void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector); extern const VMStateDescription vmstate_ppc_cpu; #endif diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 81ee19ebae..1acc3786de 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -983,15 +983,12 @@ static void ppc_hw_interrupt(CPUPPCState *env) } } -void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector) +void ppc_cpu_do_system_reset(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); - if (vector != -1) { - env->nip = vector; - } } void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector) From 01b552b05b0f21f8ff57a508f7ad26f7abbcd123 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 26 Mar 2020 00:41:44 +1000 Subject: [PATCH 0297/2595] ppc/pnv: Add support for NMI interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements the NMI interface for the PNV machine, similarly to commit 3431648272d ("spapr: Add support for new NMI interface") for SPAPR. Signed-off-by: Nicholas Piggin Message-Id: <20200325144147.221875-3-npiggin@gmail.com> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/pnv.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index c9cb6fa357..a3b7a8d0ff 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -27,6 +27,7 @@ #include "sysemu/runstate.h" #include "sysemu/cpus.h" #include "sysemu/device_tree.h" +#include "sysemu/hw_accel.h" #include "target/ppc/cpu.h" #include "qemu/log.h" #include "hw/ppc/fdt.h" @@ -34,6 +35,7 @@ #include "hw/ppc/pnv.h" #include "hw/ppc/pnv_core.h" #include "hw/loader.h" +#include "hw/nmi.h" #include "exec/address-spaces.h" #include "qapi/visitor.h" #include "monitor/monitor.h" @@ -1977,10 +1979,35 @@ static void pnv_machine_set_hb(Object *obj, bool value, Error **errp) } } +static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + cpu_synchronize_state(cs); + ppc_cpu_do_system_reset(cs); + /* + * SRR1[42:45] is set to 0100 which the ISA defines as implementation + * dependent. POWER processors use this for xscom triggered interrupts, + * which come from the BMC or NMI IPIs. + */ + env->spr[SPR_SRR1] |= PPC_BIT(43); +} + +static void pnv_nmi(NMIState *n, int cpu_index, Error **errp) +{ + CPUState *cs; + + CPU_FOREACH(cs) { + async_run_on_cpu(cs, pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL); + } +} + static void pnv_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); + NMIClass *nc = NMI_CLASS(oc); mc->desc = "IBM PowerNV (Non-Virtualized)"; mc->init = pnv_init; @@ -1997,6 +2024,7 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_size = INITRD_LOAD_ADDR + INITRD_MAX_SIZE; mc->default_ram_id = "pnv.ram"; ispc->print_info = pnv_pic_print_info; + nc->nmi_monitor_handler = pnv_nmi; object_class_property_add_bool(oc, "hb-mode", pnv_machine_get_hb, pnv_machine_set_hb, @@ -2060,6 +2088,7 @@ static const TypeInfo types[] = { .class_size = sizeof(PnvMachineClass), .interfaces = (InterfaceInfo[]) { { TYPE_INTERRUPT_STATS_PROVIDER }, + { TYPE_NMI }, { }, }, }, From b4b83312e72461540ee155006f0d49e33bf0c58d Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 25 Mar 2020 16:25:36 +0100 Subject: [PATCH 0298/2595] spapr: Simplify selection of radix/hash during CAS The guest can select the MMU mode by setting bits 0-1 of byte 24 in OV5 to to 0b00 for hash or 0b01 for radix. As required by the architecture, we terminate the boot process if any other value is found there. The usual way to negotiate features in OV5 is basically ANDing the bitfield provided by the guest and the bitfield of features supported by QEMU, previously populated at machine init. For some not documented reason, MMU is treated differently : bit 1 of byte 24 (the radix/hash bit) is cleared from the guest OV5 and explicitely set in the final negotiated OV5 if radix was requested. Since the only expected input from the guest is the radix/hash bit being set or not, it seems more appropriate to handle this like we do for XIVE. Set the radix bit in spapr->ov5 at machine init if it has a chance to work (ie. power9, either TCG or a radix capable KVM) and rely exclusively on spapr_ovec_intersect() to set the radix bit in spapr->ov5_cas. Signed-off-by: Greg Kurz Message-Id: <158514993621.478799.4204740354545734293.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 1 + hw/ppc/spapr_hcall.c | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 785c41d205..167b1216ba 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2837,6 +2837,7 @@ static void spapr_machine_init(MachineState *machine) 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)) { + spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_300); /* KVM and TCG always allow GTSE with radix... */ spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE); } diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index e8ee447537..fb4fdd4a0c 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1739,9 +1739,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, exit(EXIT_FAILURE); } - /* The radix/hash bit in byte 24 requires special handling: */ guest_radix = spapr_ovec_test(ov5_guest, OV5_MMU_RADIX_300); - spapr_ovec_clear(ov5_guest, OV5_MMU_RADIX_300); guest_xive = spapr_ovec_test(ov5_guest, OV5_XIVE_EXPLOIT); @@ -1786,14 +1784,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, /* full range of negotiated ov5 capabilities */ spapr_ovec_intersect(spapr->ov5_cas, spapr->ov5, ov5_guest); spapr_ovec_cleanup(ov5_guest); - /* Now that processing is finished, set the radix/hash bit for the - * guest if it requested a valid mode; otherwise terminate the boot. */ + if (guest_radix) { if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) { error_report("Guest requested unavailable MMU mode (radix)."); exit(EXIT_FAILURE); } - spapr_ovec_set(spapr->ov5_cas, OV5_MMU_RADIX_300); } else { if (kvm_enabled() && kvmppc_has_cap_mmu_radix() && !kvmppc_has_cap_mmu_hash_v3()) { From 91067db1abcdc6caf951494b8d7e4bfaaa0cb61d Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 25 Mar 2020 16:25:42 +0100 Subject: [PATCH 0299/2595] spapr/cas: Separate CAS handling from rebuilding the FDT At the moment "ibm,client-architecture-support" ("CAS") is implemented in SLOF and QEMU assists via the custom H_CAS hypercall which copies an updated flatten device tree (FDT) blob to the SLOF memory which it then uses to update its internal tree. When we enable the OpenFirmware client interface in QEMU, we won't need to copy the FDT to the guest as the client is expected to fetch the device tree using the client interface. This moves FDT rebuild out to a separate helper which is going to be called from the "ibm,client-architecture-support" handler and leaves writing FDT to the guest in the H_CAS handler. This should not cause any behavioral change. Signed-off-by: Alexey Kardashevskiy Message-Id: <20200310050733.29805-3-aik@ozlabs.ru> Signed-off-by: Greg Kurz Message-Id: <158514994229.478799.2178881312094922324.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 1 - hw/ppc/spapr_hcall.c | 67 ++++++++++++++++++++++++++---------------- include/hw/ppc/spapr.h | 7 +++++ 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 167b1216ba..f52488d397 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -96,7 +96,6 @@ * * We load our kernel at 4M, leaving space for SLOF initial image */ -#define FDT_MAX_SIZE 0x100000 #define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */ #define FW_MAX_SIZE 0x400000 #define FW_FILE_NAME "slof.bin" diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index fb4fdd4a0c..48a8745514 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1665,16 +1665,12 @@ static void spapr_handle_transient_dev_before_cas(SpaprMachineState *spapr) spapr_clear_pending_hotplug_events(spapr); } -static target_ulong h_client_architecture_support(PowerPCCPU *cpu, - SpaprMachineState *spapr, - target_ulong opcode, - target_ulong *args) +target_ulong do_client_architecture_support(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong vec, + target_ulong fdt_bufsize) { - /* Working address in data buffer */ - target_ulong addr = ppc64_phys_to_real(args[0]); - target_ulong fdt_buf = args[1]; - target_ulong fdt_bufsize = args[2]; - target_ulong ov_table; + target_ulong ov_table; /* Working address in data buffer */ uint32_t cas_pvr; SpaprOptionVector *ov1_guest, *ov5_guest; bool guest_radix; @@ -1694,7 +1690,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, } } - cas_pvr = cas_check_pvr(spapr, cpu, &addr, &raw_mode_supported, &local_err); + cas_pvr = cas_check_pvr(spapr, cpu, &vec, &raw_mode_supported, &local_err); if (local_err) { error_report_err(local_err); return H_HARDWARE; @@ -1717,7 +1713,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, } /* For the future use: here @ov_table points to the first option vector */ - ov_table = addr; + ov_table = vec; ov1_guest = spapr_ovec_parse_vector(ov_table, 1); if (!ov1_guest) { @@ -1824,7 +1820,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, if (!spapr->cas_reboot) { void *fdt; - SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 }; /* If spapr_machine_reset() did not set up a HPT but one is necessary * (because the guest isn't going to use radix) then set it up here. */ @@ -1833,21 +1828,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, spapr_setup_hpt(spapr); } - if (fdt_bufsize < sizeof(hdr)) { - error_report("SLOF provided insufficient CAS buffer " - TARGET_FMT_lu " (min: %zu)", fdt_bufsize, sizeof(hdr)); - exit(EXIT_FAILURE); - } - - fdt_bufsize -= sizeof(hdr); - fdt = spapr_build_fdt(spapr, false, fdt_bufsize); - _FDT((fdt_pack(fdt))); - - cpu_physical_memory_write(fdt_buf, &hdr, sizeof(hdr)); - cpu_physical_memory_write(fdt_buf + sizeof(hdr), fdt, - fdt_totalsize(fdt)); - trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr)); g_free(spapr->fdt_blob); spapr->fdt_size = fdt_totalsize(fdt); @@ -1862,6 +1843,40 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, return H_SUCCESS; } +static target_ulong h_client_architecture_support(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong vec = ppc64_phys_to_real(args[0]); + target_ulong fdt_buf = args[1]; + target_ulong fdt_bufsize = args[2]; + target_ulong ret; + SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 }; + + if (fdt_bufsize < sizeof(hdr)) { + error_report("SLOF provided insufficient CAS buffer " + TARGET_FMT_lu " (min: %zu)", fdt_bufsize, sizeof(hdr)); + exit(EXIT_FAILURE); + } + + fdt_bufsize -= sizeof(hdr); + + ret = do_client_architecture_support(cpu, spapr, vec, fdt_bufsize); + if (ret == H_SUCCESS) { + _FDT((fdt_pack(spapr->fdt_blob))); + spapr->fdt_size = fdt_totalsize(spapr->fdt_blob); + spapr->fdt_initial_size = spapr->fdt_size; + + cpu_physical_memory_write(fdt_buf, &hdr, sizeof(hdr)); + cpu_physical_memory_write(fdt_buf + sizeof(hdr), spapr->fdt_blob, + spapr->fdt_size); + trace_spapr_cas_continue(spapr->fdt_size + sizeof(hdr)); + } + + return ret; +} + static target_ulong h_home_node_associativity(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong opcode, diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 42d64a0368..b7e13e5aaf 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -102,6 +102,8 @@ typedef enum { #define SPAPR_CAP_FIXED_CCD 0x03 #define SPAPR_CAP_FIXED_NA 0x10 /* Lets leave a bit of a gap... */ +#define FDT_MAX_SIZE 0x100000 + typedef struct SpaprCapabilities SpaprCapabilities; struct SpaprCapabilities { uint8_t caps[SPAPR_CAP_NUM]; @@ -566,6 +568,11 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, target_ulong *args); +target_ulong do_client_architecture_support(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong addr, + target_ulong fdt_bufsize); + /* Virtual Processor Area structure constants */ #define VPA_MIN_SIZE 640 #define VPA_SIZE_OFFSET 0x4 From 087820e37f05c391c1ea77b1761ed489c928872e Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 25 Mar 2020 16:25:49 +0100 Subject: [PATCH 0300/2595] spapr: Drop CAS reboot flag The CAS reboot flag is false by default and all the locations that could set it to true have been dropped. This means that all code blocks depending on the flag being set is dead code and the other code blocks should be executed always. Just do that and drop the now uneeded CAS reboot flag. Fix a comment on the way to make checkpatch happy. Signed-off-by: Greg Kurz Message-Id: <158514994893.478799.11772512888322840990.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 18 ++++-------------- hw/ppc/spapr_hcall.c | 33 ++++++++++++++------------------- include/hw/ppc/spapr.h | 1 - 3 files changed, 18 insertions(+), 34 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index f52488d397..841b5ec59b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1579,9 +1579,7 @@ void spapr_setup_hpt(SpaprMachineState *spapr) { int hpt_shift; - if ((spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) - || (spapr->cas_reboot - && !spapr_ovec_test(spapr->ov5_cas, OV5_HPT_RESIZE))) { + if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) { hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size); } else { uint64_t current_ram_size; @@ -1645,16 +1643,10 @@ static void spapr_machine_reset(MachineState *machine) qemu_devices_reset(); - /* - * If this reset wasn't generated by CAS, we should reset our - * negotiated options and start from scratch - */ - if (!spapr->cas_reboot) { - spapr_ovec_cleanup(spapr->ov5_cas); - spapr->ov5_cas = spapr_ovec_new(); + spapr_ovec_cleanup(spapr->ov5_cas); + spapr->ov5_cas = spapr_ovec_new(); - ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal); - } + ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal); /* * This is fixing some of the default configuration of the XIVE @@ -1707,8 +1699,6 @@ static void spapr_machine_reset(MachineState *machine) spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, 0, fdt_addr, 0); first_ppc_cpu->env.gpr[5] = 0; - spapr->cas_reboot = false; - spapr->fwnmi_system_reset_addr = -1; spapr->fwnmi_machine_check_addr = -1; spapr->fwnmi_machine_check_interlock = -1; diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 48a8745514..0f54988f2e 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1678,6 +1678,7 @@ target_ulong do_client_architecture_support(PowerPCCPU *cpu, bool raw_mode_supported = false; bool guest_xive; CPUState *cs; + void *fdt; /* CAS is supposed to be called early when only the boot vCPU is active. */ CPU_FOREACH(cs) { @@ -1818,27 +1819,21 @@ target_ulong do_client_architecture_support(PowerPCCPU *cpu, spapr_handle_transient_dev_before_cas(spapr); - if (!spapr->cas_reboot) { - void *fdt; - - /* If spapr_machine_reset() did not set up a HPT but one is necessary - * (because the guest isn't going to use radix) then set it up here. */ - if ((spapr->patb_entry & PATE1_GR) && !guest_radix) { - /* legacy hash or new hash: */ - spapr_setup_hpt(spapr); - } - - fdt = spapr_build_fdt(spapr, false, fdt_bufsize); - - g_free(spapr->fdt_blob); - spapr->fdt_size = fdt_totalsize(fdt); - spapr->fdt_initial_size = spapr->fdt_size; - spapr->fdt_blob = fdt; + /* + * If spapr_machine_reset() did not set up a HPT but one is necessary + * (because the guest isn't going to use radix) then set it up here. + */ + if ((spapr->patb_entry & PATE1_GR) && !guest_radix) { + /* legacy hash or new hash: */ + spapr_setup_hpt(spapr); } - if (spapr->cas_reboot) { - qemu_system_reset_request(SHUTDOWN_CAUSE_SUBSYSTEM_RESET); - } + fdt = spapr_build_fdt(spapr, false, fdt_bufsize); + + g_free(spapr->fdt_blob); + spapr->fdt_size = fdt_totalsize(fdt); + spapr->fdt_initial_size = spapr->fdt_size; + spapr->fdt_blob = fdt; return H_SUCCESS; } diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index b7e13e5aaf..e579eaf28c 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -178,7 +178,6 @@ struct SpaprMachineState { SpaprEventSource *event_sources; /* ibm,client-architecture-support option negotiation */ - bool cas_reboot; bool cas_pre_isa3_guest; SpaprOptionVector *ov5; /* QEMU-supported option vectors */ SpaprOptionVector *ov5_cas; /* negotiated (via CAS) option vectors */ From 933abb9c238726c3f2862affd0d46b043a22c3e0 Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Mon, 30 Mar 2020 11:49:40 +0200 Subject: [PATCH 0301/2595] target/ppc: Enforce that the root page directory size must be at least 5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the ISA the root page directory size of a radix tree for either process- or partition-scoped translation must be >= 5. Thus add this to the list of conditions checked when validating the partition table entry in validate_pate(); Signed-off-by: Suraj Jitindar Singh Reviewed-by: David Gibson Signed-off-by: Cédric Le Goater Message-Id: <20200330094946.24678-2-clg@kaod.org> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 224e646c50..9967857058 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -212,6 +212,9 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) if (lpid == 0 && !msr_hv) { return false; } + if ((pate->dw0 & PATE1_R_PRTS) < 5) { + return false; + } /* More checks ... */ return true; } From f208ec7160145a77647af9b01a393615e7a9f8c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 30 Mar 2020 11:49:41 +0200 Subject: [PATCH 0302/2595] target/ppc: Introduce a relocation bool in ppc_radix64_handle_mmu_fault() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will ease the introduction of new routines for partition-scoped Radix translation. Signed-off-by: Suraj Jitindar Singh Signed-off-by: Cédric Le Goater Message-Id: <20200330094946.24678-3-clg@kaod.org> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 9967857058..f6007e9565 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -229,12 +229,13 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte; int page_size, prot, fault_cause = 0; ppc_v3_pate_t pate; + bool relocation; assert((rwx == 0) || (rwx == 1) || (rwx == 2)); + relocation = ((rwx == 2) && (msr_ir == 1)) || ((rwx != 2) && (msr_dr == 1)); /* HV or virtual hypervisor Real Mode Access */ - if ((msr_hv || cpu->vhyp) && - (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0)))) { + if (!relocation && (msr_hv || cpu->vhyp)) { /* In real mode top 4 effective addr bits (mostly) ignored */ raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL; From beae5e9dc6eedc7d7fda333a3b71aa9f7e6b4a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 30 Mar 2020 11:49:42 +0200 Subject: [PATCH 0303/2595] target/ppc: Assert if HV mode is set when running under a pseries machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Suraj Jitindar Singh Signed-off-by: Cédric Le Goater Message-Id: <20200330094946.24678-4-clg@kaod.org> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index f6007e9565..d2422d1c54 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -231,6 +231,7 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, ppc_v3_pate_t pate; bool relocation; + assert(!(msr_hv && cpu->vhyp)); assert((rwx == 0) || (rwx == 1) || (rwx == 2)); relocation = ((rwx == 2) && (msr_ir == 1)) || ((rwx != 2) && (msr_dr == 1)); From 05af7c77f5f24ef2bec25f2cab22170c29edaf37 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 26 Mar 2020 16:27:37 +1100 Subject: [PATCH 0304/2595] spapr: Don't allow unplug of NVLink2 devices Currently, we can't properly handle unplug of NVLink2 devices, because we don't have code to tear down their special memory resources. There's not a lot of impetus to implement that: since hardware NVLink2 devices can't be hot unplugged, the guest side drivers don't usually support unplug anyway. Therefore, simply prevent unplug of NVLink2 devices. Signed-off-by: David Gibson Reviewed-by: Alexey Kardashevskiy --- hw/ppc/spapr_pci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 55ca9dee1e..61b84a392d 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1665,6 +1665,10 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, error_setg(errp, "PCI: Hot unplug of PCI bridges not supported"); return; } + if (object_property_get_uint(OBJECT(pdev), "nvlink2-tgt", NULL)) { + error_setg(errp, "PCI: Cannot unplug NVLink2 devices"); + return; + } /* ensure any other present functions are pending unplug */ if (PCI_FUNC(pdev->devfn) == 0) { From d92baf00aad9bba521c2b3cb23fe388c2067aaa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 3 Apr 2020 16:00:53 +0200 Subject: [PATCH 0305/2595] target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is moving code under a new ppc_radix64_xlate() routine shared by the MMU Radix page fault handler and the 'get_phys_page_debug' PPC callback. The difference being that 'get_phys_page_debug' does not generate exceptions. The specific part of process-scoped Radix translation is moved under ppc_radix64_process_scoped_xlate() in preparation of the future support for partition-scoped Radix translation. Routines raising the exceptions now take a 'cause_excp' bool to cover the 'get_phys_page_debug' case. It should be functionally equivalent. Signed-off-by: Suraj Jitindar Singh Signed-off-by: Cédric Le Goater Message-Id: <20200403140056.59465-2-clg@kaod.org> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 219 ++++++++++++++++++++++----------------- 1 file changed, 123 insertions(+), 96 deletions(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index d2422d1c54..4b0d0ff50a 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -219,17 +219,127 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) return true; } +static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, + vaddr eaddr, uint64_t pid, + ppc_v3_pate_t pate, hwaddr *g_raddr, + int *g_prot, int *g_page_size, + bool cause_excp) +{ + CPUState *cs = CPU(cpu); + uint64_t offset, size, prtbe_addr, prtbe0, pte; + int fault_cause = 0; + hwaddr pte_addr; + + /* Index Process Table by PID to Find Corresponding Process Table Entry */ + offset = pid * sizeof(struct prtb_entry); + size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12); + if (offset >= size) { + /* offset exceeds size of the process table */ + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); + } + return 1; + } + prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset; + prtbe0 = ldq_phys(cs->as, prtbe_addr); + + /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ + *g_page_size = PRTBE_R_GET_RTS(prtbe0); + pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK, + prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS, + g_raddr, g_page_size, &fault_cause, &pte_addr); + + if (!(pte & R_PTE_VALID) || + ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot)) { + /* No valid pte or access denied due to protection */ + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); + } + return 1; + } + + ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot); + + return 0; +} + +static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, + bool relocation, + hwaddr *raddr, int *psizep, int *protp, + bool cause_excp) +{ + uint64_t lpid = 0, pid = 0; + ppc_v3_pate_t pate; + int psize, prot; + hwaddr g_raddr; + + /* Virtual Mode Access - get the fully qualified address */ + if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) { + if (cause_excp) { + ppc_radix64_raise_segi(cpu, rwx, eaddr); + } + return 1; + } + + /* Get Process Table */ + if (cpu->vhyp) { + PPCVirtualHypervisorClass *vhc; + vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + vhc->get_pate(cpu->vhyp, &pate); + } else { + if (!ppc64_v3_get_pate(cpu, lpid, &pate)) { + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); + } + return 1; + } + if (!validate_pate(cpu, lpid, &pate)) { + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG); + } + return 1; + } + /* We don't support guest mode yet */ + if (lpid != 0) { + error_report("PowerNV guest support Unimplemented"); + exit(1); + } + } + + *psizep = INT_MAX; + *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + + /* + * Perform process-scoped translation if relocation enabled. + * + * - Translates an effective address to a host real address in + * quadrants 0 and 3 when HV=1. + */ + if (relocation) { + int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid, + pate, &g_raddr, &prot, + &psize, cause_excp); + if (ret) { + return ret; + } + *psizep = MIN(*psizep, psize); + *protp &= prot; + } else { + g_raddr = eaddr & R_EADDR_MASK; + } + + *raddr = g_raddr; + return 0; +} + int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - PPCVirtualHypervisorClass *vhc; - hwaddr raddr, pte_addr; - uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte; - int page_size, prot, fault_cause = 0; - ppc_v3_pate_t pate; + int page_size, prot; bool relocation; + hwaddr raddr; assert(!(msr_hv && cpu->vhyp)); assert((rwx == 0) || (rwx == 1) || (rwx == 2)); @@ -262,55 +372,12 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, TARGET_FMT_lx "\n", env->spr[SPR_LPCR]); } - /* Virtual Mode Access - get the fully qualified address */ - if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) { - ppc_radix64_raise_segi(cpu, rwx, eaddr); + /* Translate eaddr to raddr (where raddr is addr qemu needs for access) */ + if (ppc_radix64_xlate(cpu, eaddr, rwx, relocation, &raddr, + &page_size, &prot, true)) { return 1; } - /* Get Process Table */ - if (cpu->vhyp) { - vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); - vhc->get_pate(cpu->vhyp, &pate); - } else { - if (!ppc64_v3_get_pate(cpu, lpid, &pate)) { - ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); - return 1; - } - if (!validate_pate(cpu, lpid, &pate)) { - ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG); - } - /* We don't support guest mode yet */ - if (lpid != 0) { - error_report("PowerNV guest support Unimplemented"); - exit(1); - } - } - - /* Index Process Table by PID to Find Corresponding Process Table Entry */ - offset = pid * sizeof(struct prtb_entry); - size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12); - if (offset >= size) { - /* offset exceeds size of the process table */ - ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); - return 1; - } - prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset); - - /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ - page_size = PRTBE_R_GET_RTS(prtbe0); - pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK, - prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS, - &raddr, &page_size, &fault_cause, &pte_addr); - if (!pte || ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, &prot)) { - /* Couldn't get pte or access denied due to protection */ - ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); - return 1; - } - - /* Update Reference and Change Bits */ - ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, &prot); - tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, prot, mmu_idx, 1UL << page_size); return 0; @@ -318,58 +385,18 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, hwaddr ppc_radix64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr) { - CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - PPCVirtualHypervisorClass *vhc; - hwaddr raddr, pte_addr; - uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte; - int page_size, fault_cause = 0; - ppc_v3_pate_t pate; + int psize, prot; + hwaddr raddr; /* Handle Real Mode */ - if (msr_dr == 0) { + if ((msr_dr == 0) && (msr_hv || cpu->vhyp)) { /* In real mode top 4 effective addr bits (mostly) ignored */ return eaddr & 0x0FFFFFFFFFFFFFFFULL; } - /* Virtual Mode Access - get the fully qualified address */ - if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) { - return -1; - } - - /* Get Process Table */ - if (cpu->vhyp) { - vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); - vhc->get_pate(cpu->vhyp, &pate); - } else { - if (!ppc64_v3_get_pate(cpu, lpid, &pate)) { - return -1; - } - if (!validate_pate(cpu, lpid, &pate)) { - return -1; - } - /* We don't support guest mode yet */ - if (lpid != 0) { - error_report("PowerNV guest support Unimplemented"); - exit(1); - } - } - - /* Index Process Table by PID to Find Corresponding Process Table Entry */ - offset = pid * sizeof(struct prtb_entry); - size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12); - if (offset >= size) { - /* offset exceeds size of the process table */ - return -1; - } - prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset); - - /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ - page_size = PRTBE_R_GET_RTS(prtbe0); - pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK, - prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS, - &raddr, &page_size, &fault_cause, &pte_addr); - if (!pte) { + if (ppc_radix64_xlate(cpu, eaddr, 0, msr_dr, &raddr, &psize, + &prot, false)) { return -1; } From 522ad21875ac48426c282ef2b7dfe87adb40afb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 3 Apr 2020 16:00:54 +0200 Subject: [PATCH 0306/2595] target/ppc: Extend ppc_radix64_check_prot() with a 'partition_scoped' bool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prepares ground for partition-scoped Radix translation. Signed-off-by: Suraj Jitindar Singh Signed-off-by: Cédric Le Goater Reviewed-by: Greg Kurz Message-Id: <20200403140056.59465-3-clg@kaod.org> Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 4b0d0ff50a..11b3c6d48c 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -105,7 +105,8 @@ static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr, static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte, - int *fault_cause, int *prot) + int *fault_cause, int *prot, + bool partition_scoped) { CPUPPCState *env = &cpu->env; const int need_prot[] = { PAGE_READ, PAGE_WRITE, PAGE_EXEC }; @@ -121,11 +122,11 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte, } /* Determine permissions allowed by Encoded Access Authority */ - if ((pte & R_PTE_EAA_PRIV) && msr_pr) { /* Insufficient Privilege */ + if (!partition_scoped && (pte & R_PTE_EAA_PRIV) && msr_pr) { *prot = 0; - } else if (msr_pr || (pte & R_PTE_EAA_PRIV)) { + } else if (msr_pr || (pte & R_PTE_EAA_PRIV) || partition_scoped) { *prot = ppc_radix64_get_prot_eaa(pte); - } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) */ + } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */ *prot = ppc_radix64_get_prot_eaa(pte); *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */ } @@ -250,7 +251,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, g_raddr, g_page_size, &fault_cause, &pte_addr); if (!(pte & R_PTE_VALID) || - ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot)) { + ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) { /* No valid pte or access denied due to protection */ if (cause_excp) { ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); From 6bffd48b9e8efcd6977c86f2ea8437771d15043c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 3 Apr 2020 16:00:55 +0200 Subject: [PATCH 0307/2595] target/ppc: Rework ppc_radix64_walk_tree() for partition-scoped translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ppc_radix64_walk_tree() routine walks through the nested radix tables to look for a PTE. Split it in two and introduce a new routine ppc_radix64_next_level() which we will use for partition-scoped Radix translation when translating the process tree addresses. The prototypes are slightly change to use a 'AddressSpace *' parameter, instead of a 'PowerPCCPU *' which is not required, and to return an error code instead of a PTE value. It clarifies error handling in the callers. Signed-off-by: Suraj Jitindar Singh Signed-off-by: Greg Kurz Signed-off-by: Cédric Le Goater Message-Id: <20200403140056.59465-4-clg@kaod.org> Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 79 ++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 11b3c6d48c..2400da41e0 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -163,44 +163,67 @@ static void ppc_radix64_set_rc(PowerPCCPU *cpu, int rwx, uint64_t pte, } } -static uint64_t ppc_radix64_walk_tree(PowerPCCPU *cpu, vaddr eaddr, - uint64_t base_addr, uint64_t nls, - hwaddr *raddr, int *psize, - int *fault_cause, hwaddr *pte_addr) +static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr, + uint64_t *pte_addr, uint64_t *nls, + int *psize, uint64_t *pte, int *fault_cause) { - CPUState *cs = CPU(cpu); uint64_t index, pde; - if (nls < 5) { /* Directory maps less than 2**5 entries */ + if (*nls < 5) { /* Directory maps less than 2**5 entries */ *fault_cause |= DSISR_R_BADCONFIG; - return 0; + return 1; } /* Read page entry from guest address space */ - index = eaddr >> (*psize - nls); /* Shift */ - index &= ((1UL << nls) - 1); /* Mask */ - pde = ldq_phys(cs->as, base_addr + (index * sizeof(pde))); - if (!(pde & R_PTE_VALID)) { /* Invalid Entry */ + pde = ldq_phys(as, *pte_addr); + if (!(pde & R_PTE_VALID)) { /* Invalid Entry */ *fault_cause |= DSISR_NOPTE; - return 0; + return 1; } - *psize -= nls; + *pte = pde; + *psize -= *nls; + if (!(pde & R_PTE_LEAF)) { /* Prepare for next iteration */ + *nls = pde & R_PDE_NLS; + index = eaddr >> (*psize - *nls); /* Shift */ + index &= ((1UL << *nls) - 1); /* Mask */ + *pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde)); + } + return 0; +} - /* Check if Leaf Entry -> Page Table Entry -> Stop the Search */ - if (pde & R_PTE_LEAF) { - uint64_t rpn = pde & R_PTE_RPN; - uint64_t mask = (1UL << *psize) - 1; +static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr, + uint64_t base_addr, uint64_t nls, + hwaddr *raddr, int *psize, uint64_t *pte, + int *fault_cause, hwaddr *pte_addr) +{ + uint64_t index, pde, rpn , mask; - /* Or high bits of rpn and low bits to ea to form whole real addr */ - *raddr = (rpn & ~mask) | (eaddr & mask); - *pte_addr = base_addr + (index * sizeof(pde)); - return pde; + if (nls < 5) { /* Directory maps less than 2**5 entries */ + *fault_cause |= DSISR_R_BADCONFIG; + return 1; } - /* Next Level of Radix Tree */ - return ppc_radix64_walk_tree(cpu, eaddr, pde & R_PDE_NLB, pde & R_PDE_NLS, - raddr, psize, fault_cause, pte_addr); + index = eaddr >> (*psize - nls); /* Shift */ + index &= ((1UL << nls) - 1); /* Mask */ + *pte_addr = base_addr + (index * sizeof(pde)); + do { + int ret; + + ret = ppc_radix64_next_level(as, eaddr, pte_addr, &nls, psize, &pde, + fault_cause); + if (ret) { + return ret; + } + } while (!(pde & R_PTE_LEAF)); + + *pte = pde; + rpn = pde & R_PTE_RPN; + mask = (1UL << *psize) - 1; + + /* Or high bits of rpn and low bits to ea to form whole real addr */ + *raddr = (rpn & ~mask) | (eaddr & mask); + return 0; } static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) @@ -230,6 +253,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, uint64_t offset, size, prtbe_addr, prtbe0, pte; int fault_cause = 0; hwaddr pte_addr; + int ret; /* Index Process Table by PID to Find Corresponding Process Table Entry */ offset = pid * sizeof(struct prtb_entry); @@ -246,11 +270,12 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ *g_page_size = PRTBE_R_GET_RTS(prtbe0); - pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK, + ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS, - g_raddr, g_page_size, &fault_cause, &pte_addr); + g_raddr, g_page_size, &pte, &fault_cause, + &pte_addr); - if (!(pte & R_PTE_VALID) || + if (ret || ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) { /* No valid pte or access denied due to protection */ if (cause_excp) { From d04ea940c597201a6610c5d1712809ed35dd77ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 3 Apr 2020 16:00:56 +0200 Subject: [PATCH 0308/2595] target/ppc: Add support for Radix partition-scoped translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Radix tree translation model currently supports process-scoped translation for the PowerNV machine (Hypervisor mode) and for the pSeries machine (Guest mode). Guests running under an emulated Hypervisor (PowerNV machine) require a new type of Radix translation, called partition-scoped, which is missing today. The Radix tree translation is a 2 steps process. The first step, process-scoped translation, converts an effective Address to a guest real address, and the second step, partition-scoped translation, converts a guest real address to a host real address. There are difference cases to covers : * Hypervisor real mode access: no Radix translation. * Hypervisor or host application access (quadrant 0 and 3) with relocation on: process-scoped translation. * Guest OS real mode access: only partition-scoped translation. * Guest OS real or guest application access (quadrant 0 and 3) with relocation on: both process-scoped translation and partition-scoped translations. * Hypervisor access in quadrant 1 and 2 with relocation on: both process-scoped translation and partition-scoped translations. The radix tree partition-scoped translation is performed using tables pointed to by the first double-word of the Partition Table Entries and process-scoped translation uses tables pointed to by the Process Table Entries (second double-word of the Partition Table Entries). Both partition-scoped and process-scoped translations process are identical and thus the radix tree traversing code is largely reused. However, errors in partition-scoped translations generate hypervisor exceptions. Signed-off-by: Suraj Jitindar Singh Signed-off-by: Greg Kurz Signed-off-by: Cédric Le Goater Message-Id: <20200403140056.59465-5-clg@kaod.org> [dwg: Fixup from Greg Kurz folded in] Signed-off-by: David Gibson --- target/ppc/cpu.h | 3 + target/ppc/excp_helper.c | 3 +- target/ppc/mmu-radix64.c | 192 +++++++++++++++++++++++++++++++++++---- 3 files changed, 180 insertions(+), 18 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index f4a5304d43..6b6dd7e483 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -463,6 +463,9 @@ typedef struct ppc_v3_pate_t { #define DSISR_AMR 0x00200000 /* Unsupported Radix Tree Configuration */ #define DSISR_R_BADCONFIG 0x00080000 +#define DSISR_ATOMIC_RC 0x00040000 +/* Unable to translate address of (guest) pde or process/page table entry */ +#define DSISR_PRTABLE_FAULT 0x00020000 /* SRR1 error code fields */ diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 1acc3786de..f052979664 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -506,9 +506,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) case POWERPC_EXCP_ISEG: /* Instruction segment exception */ case POWERPC_EXCP_TRACE: /* Trace exception */ break; + case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ + msr |= env->error_code; case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ - case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 2400da41e0..1404e53dec 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -103,6 +103,27 @@ static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr, } } +static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, int rwx, vaddr eaddr, + hwaddr g_raddr, uint32_t cause) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + + if (rwx == 2) { /* H Instruction Storage Interrupt */ + cs->exception_index = POWERPC_EXCP_HISI; + env->spr[SPR_ASDR] = g_raddr; + env->error_code = cause; + } else { /* H Data Storage Interrupt */ + cs->exception_index = POWERPC_EXCP_HDSI; + if (rwx == 1) { /* Write -> Store */ + cause |= DSISR_ISSTORE; + } + env->spr[SPR_HDSISR] = cause; + env->spr[SPR_HDAR] = eaddr; + env->spr[SPR_ASDR] = g_raddr; + env->error_code = 0; + } +} static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte, int *fault_cause, int *prot, @@ -243,6 +264,37 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) return true; } +static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx, + vaddr eaddr, hwaddr g_raddr, + ppc_v3_pate_t pate, + hwaddr *h_raddr, int *h_prot, + int *h_page_size, bool pde_addr, + bool cause_excp) +{ + int fault_cause = 0; + hwaddr pte_addr; + uint64_t pte; + + *h_page_size = PRTBE_R_GET_RTS(pate.dw0); + /* No valid pte or access denied due to protection */ + if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB, + pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size, + &pte, &fault_cause, &pte_addr) || + ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, h_prot, true)) { + if (pde_addr) /* address being translated was that of a guest pde */ + fault_cause |= DSISR_PRTABLE_FAULT; + if (cause_excp) { + ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause); + } + return 1; + } + + /* Update Reference and Change Bits */ + ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot); + + return 0; +} + static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, vaddr eaddr, uint64_t pid, ppc_v3_pate_t pate, hwaddr *g_raddr, @@ -250,9 +302,10 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, bool cause_excp) { CPUState *cs = CPU(cpu); - uint64_t offset, size, prtbe_addr, prtbe0, pte; - int fault_cause = 0; - hwaddr pte_addr; + CPUPPCState *env = &cpu->env; + uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte; + int fault_cause = 0, h_page_size, h_prot; + hwaddr h_raddr, pte_addr; int ret; /* Index Process Table by PID to Find Corresponding Process Table Entry */ @@ -266,18 +319,85 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, return 1; } prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset; - prtbe0 = ldq_phys(cs->as, prtbe_addr); + + if (cpu->vhyp) { + prtbe0 = ldq_phys(cs->as, prtbe_addr); + } else { + /* + * Process table addresses are subject to partition-scoped + * translation + * + * On a Radix host, the partition-scoped page table for LPID=0 + * is only used to translate the effective addresses of the + * process table entries. + */ + ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr, + pate, &h_raddr, &h_prot, + &h_page_size, 1, 1); + if (ret) { + return ret; + } + prtbe0 = ldq_phys(cs->as, h_raddr); + } /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ *g_page_size = PRTBE_R_GET_RTS(prtbe0); - ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, - prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS, - g_raddr, g_page_size, &pte, &fault_cause, - &pte_addr); + base_addr = prtbe0 & PRTBE_R_RPDB; + nls = prtbe0 & PRTBE_R_RPDS; + if (msr_hv || cpu->vhyp) { + /* + * Can treat process table addresses as real addresses + */ + ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, base_addr, + nls, g_raddr, g_page_size, &pte, + &fault_cause, &pte_addr); + if (ret) { + /* No valid PTE */ + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); + } + return ret; + } + } else { + uint64_t rpn, mask; - if (ret || - ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) { - /* No valid pte or access denied due to protection */ + index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */ + index &= ((1UL << nls) - 1); /* Mask */ + pte_addr = base_addr + (index * sizeof(pte)); + + /* + * Each process table address is subject to a partition-scoped + * translation + */ + do { + ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr, + pate, &h_raddr, &h_prot, + &h_page_size, 1, 1); + if (ret) { + return ret; + } + + ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr, + &nls, g_page_size, &pte, &fault_cause); + if (ret) { + /* No valid pte */ + if (cause_excp) { + ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); + } + return ret; + } + pte_addr = h_raddr; + } while (!(pte & R_PTE_LEAF)); + + rpn = pte & R_PTE_RPN; + mask = (1UL << *g_page_size) - 1; + + /* Or high bits of rpn and low bits to ea to form whole real addr */ + *g_raddr = (rpn & ~mask) | (eaddr & mask); + } + + if (ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) { + /* Access denied due to protection */ if (cause_excp) { ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); } @@ -289,11 +409,29 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, return 0; } +/* + * Radix tree translation is a 2 steps translation process: + * + * 1. Process-scoped translation: Guest Eff Addr -> Guest Real Addr + * 2. Partition-scoped translation: Guest Real Addr -> Host Real Addr + * + * MSR[HV] + * +-------------+----------------+---------------+ + * | | HV = 0 | HV = 1 | + * +-------------+----------------+---------------+ + * | Relocation | Partition | No | + * | = Off | Scoped | Translation | + * Relocation +-------------+----------------+---------------+ + * | Relocation | Partition & | Process | + * | = On | Process Scoped | Scoped | + * +-------------+----------------+---------------+ + */ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, bool relocation, hwaddr *raddr, int *psizep, int *protp, bool cause_excp) { + CPUPPCState *env = &cpu->env; uint64_t lpid = 0, pid = 0; ppc_v3_pate_t pate; int psize, prot; @@ -325,11 +463,6 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, } return 1; } - /* We don't support guest mode yet */ - if (lpid != 0) { - error_report("PowerNV guest support Unimplemented"); - exit(1); - } } *psizep = INT_MAX; @@ -340,6 +473,8 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, * * - Translates an effective address to a host real address in * quadrants 0 and 3 when HV=1. + * + * - Translates an effective address to a guest real address. */ if (relocation) { int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid, @@ -354,7 +489,30 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, g_raddr = eaddr & R_EADDR_MASK; } - *raddr = g_raddr; + if (cpu->vhyp) { + *raddr = g_raddr; + } else { + /* + * Perform partition-scoped translation if !HV or HV access to + * quadrants 1 or 2. Translates a guest real address to a host + * real address. + */ + if (lpid || !msr_hv) { + int ret; + + ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr, + pate, raddr, &prot, &psize, + 0, cause_excp); + if (ret) { + return ret; + } + *psizep = MIN(*psizep, psize); + *protp &= prot; + } else { + *raddr = g_raddr; + } + } + return 0; } From 70fc9cb0920fce3c2c0a090e69bf06d39f4b2362 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 13 Apr 2020 17:36:28 -0300 Subject: [PATCH 0309/2595] spapr_nvdimm.c: make 'label-size' mandatory The pseries machine does not support NVDIMM modules without label. Attempting to do so, even if the overall block size is aligned with 256MB, will seg fault the guest kernel during NVDIMM probe. This can be avoided by forcing 'label-size' to always be present for sPAPR NVDIMMs. The verification was put before the alignment check because the presence of label-size affects the alignment calculation, so it's not optimal to warn the user about an alignment error, then about the lack of label-size, then about a new alignment error when the user sets a label-size. Signed-off-by: Daniel Henrique Barboza Message-Id: <20200413203628.31636-1-danielhb413@gmail.com> Signed-off-by: David Gibson --- hw/ppc/spapr_nvdimm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index 25be8082d7..9abcdcc26b 100644 --- a/hw/ppc/spapr_nvdimm.c +++ b/hw/ppc/spapr_nvdimm.c @@ -37,6 +37,12 @@ void spapr_nvdimm_validate_opts(NVDIMMDevice *nvdimm, uint64_t size, QemuUUID uuid; int ret; + if (object_property_get_int(OBJECT(nvdimm), NVDIMM_LABEL_SIZE_PROP, + &error_abort) == 0) { + error_setg(errp, "NVDIMM device requires label-size to be set"); + return; + } + if (size % SPAPR_MINIMUM_SCM_BLOCK_SIZE) { error_setg(errp, "NVDIMM memory size excluding the label area" " must be a multiple of %" PRIu64 "MB", From 6c0f0cb319bd9f906d461a2e12a2b5d1eb588fa2 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 24 Apr 2020 11:56:17 +1000 Subject: [PATCH 0310/2595] spapr_nvdimm: Tweak error messages The restrictions here (which are checked at pre-plug time) are PAPR specific, rather than being inherent to the NVDIMM devices. Adjust the error messages to be clearer about this. Signed-off-by: David Gibson --- hw/ppc/spapr_nvdimm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index 9abcdcc26b..81410aa63f 100644 --- a/hw/ppc/spapr_nvdimm.c +++ b/hw/ppc/spapr_nvdimm.c @@ -39,13 +39,13 @@ void spapr_nvdimm_validate_opts(NVDIMMDevice *nvdimm, uint64_t size, if (object_property_get_int(OBJECT(nvdimm), NVDIMM_LABEL_SIZE_PROP, &error_abort) == 0) { - error_setg(errp, "NVDIMM device requires label-size to be set"); + error_setg(errp, "PAPR requires NVDIMM devices to have label-size set"); return; } if (size % SPAPR_MINIMUM_SCM_BLOCK_SIZE) { - error_setg(errp, "NVDIMM memory size excluding the label area" - " must be a multiple of %" PRIu64 "MB", + error_setg(errp, "PAPR requires NVDIMM memory size (excluding label)" + " to be a multiple of %" PRIu64 "MB", SPAPR_MINIMUM_SCM_BLOCK_SIZE / MiB); return; } From c4f6a4a3dd5f2aa15329b8158de25f50b5ba3252 Mon Sep 17 00:00:00 2001 From: Daniele Buono Date: Tue, 5 May 2020 14:38:17 -0400 Subject: [PATCH 0311/2595] target-ppc: fix rlwimi, rlwinm, rlwnm for Clang-9 Starting with Clang v9, -Wtype-limits is implemented and triggers a few "result of comparison is always true" errors when compiling PPC32 targets. The comparisons seem to be necessary only on PPC64, since the else branch in PPC32 only has a "g_assert_not_reached();" in all cases. This patch restructures the code so that the actual if/else is done on a local flag variable, that is set accordingly for PPC64, and always true for PPC32. Signed-off-by: Daniele Buono Message-Id: <20200505183818.32688-2-dbuono@linux.vnet.ibm.com> Signed-off-by: David Gibson --- target/ppc/translate.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 807d14faaa..338529879f 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -1882,6 +1882,7 @@ static void gen_rlwimi(DisasContext *ctx) tcg_gen_deposit_tl(t_ra, t_ra, t_rs, sh, me - mb + 1); } else { target_ulong mask; + bool mask_in_32b = true; TCGv t1; #if defined(TARGET_PPC64) @@ -1890,8 +1891,13 @@ static void gen_rlwimi(DisasContext *ctx) #endif mask = MASK(mb, me); +#if defined(TARGET_PPC64) + if (mask > 0xffffffffu) { + mask_in_32b = false; + } +#endif t1 = tcg_temp_new(); - if (mask <= 0xffffffffu) { + if (mask_in_32b) { TCGv_i32 t0 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(t0, t_rs); tcg_gen_rotli_i32(t0, t0, sh); @@ -1933,12 +1939,18 @@ static void gen_rlwinm(DisasContext *ctx) tcg_gen_extract_tl(t_ra, t_rs, rsh, len); } else { target_ulong mask; + bool mask_in_32b = true; #if defined(TARGET_PPC64) mb += 32; me += 32; #endif mask = MASK(mb, me); - if (mask <= 0xffffffffu) { +#if defined(TARGET_PPC64) + if (mask > 0xffffffffu) { + mask_in_32b = false; + } +#endif + if (mask_in_32b) { if (sh == 0) { tcg_gen_andi_tl(t_ra, t_rs, mask); } else { @@ -1973,6 +1985,7 @@ static void gen_rlwnm(DisasContext *ctx) uint32_t mb = MB(ctx->opcode); uint32_t me = ME(ctx->opcode); target_ulong mask; + bool mask_in_32b = true; #if defined(TARGET_PPC64) mb += 32; @@ -1980,7 +1993,12 @@ static void gen_rlwnm(DisasContext *ctx) #endif mask = MASK(mb, me); - if (mask <= 0xffffffffu) { +#if defined(TARGET_PPC64) + if (mask > 0xffffffffu) { + mask_in_32b = false; + } +#endif + if (mask_in_32b) { TCGv_i32 t0 = tcg_temp_new_i32(); TCGv_i32 t1 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(t0, t_rb); From 569644f761f704901b70bd259762c60b7cb28634 Mon Sep 17 00:00:00 2001 From: Tong Ho Date: Thu, 9 Jan 2020 12:09:58 -0800 Subject: [PATCH 0312/2595] crypto: fix getter of a QCryptoSecret's property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the condition-check done by the "loaded" property getter, such that the property returns true even when the secret is loaded by the 'file' option. Signed-off-by: Tong Ho Signed-off-by: Daniel P. Berrangé --- crypto/secret.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/secret.c b/crypto/secret.c index 1cf0ad0ce8..5fb6bbe59c 100644 --- a/crypto/secret.c +++ b/crypto/secret.c @@ -221,6 +221,7 @@ qcrypto_secret_prop_set_loaded(Object *obj, secret->rawlen = inputlen; } else { g_free(secret->rawdata); + secret->rawdata = NULL; secret->rawlen = 0; } } @@ -231,7 +232,7 @@ qcrypto_secret_prop_get_loaded(Object *obj, Error **errp G_GNUC_UNUSED) { QCryptoSecret *secret = QCRYPTO_SECRET(obj); - return secret->data != NULL; + return secret->rawdata != NULL; } From 861c50bf5db3c18f5cd74ea929d4e018fdcedc64 Mon Sep 17 00:00:00 2001 From: Alexey Krasikov Date: Wed, 15 Apr 2020 23:13:35 +0300 Subject: [PATCH 0313/2595] crypto/secret: fix inconsequential errors. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change condition from QCRYPTO_SECRET_FORMAT_RAW to QCRYPTO_SECRET_FORMAT_BASE64 in if-operator, because this is potential error if you add another format value. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alexey Krasikov Signed-off-by: Daniel P. Berrangé --- crypto/secret.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/secret.c b/crypto/secret.c index 5fb6bbe59c..a846a3c87c 100644 --- a/crypto/secret.c +++ b/crypto/secret.c @@ -204,7 +204,7 @@ qcrypto_secret_prop_set_loaded(Object *obj, input = output; inputlen = outputlen; } else { - if (secret->format != QCRYPTO_SECRET_FORMAT_RAW) { + if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { qcrypto_secret_decode(input, inputlen, &output, &outputlen, &local_err); g_free(input); From ccebb5f3735edcbcbf9429b605fcb9399a0dd72c Mon Sep 17 00:00:00 2001 From: Chen Qun Date: Tue, 5 May 2020 16:59:40 +0800 Subject: [PATCH 0314/2595] crypto: Redundant type conversion for AES_KEY pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can delete the redundant type conversion if we set the the AES_KEY parameter with 'const' in qcrypto_cipher_aes_ecb_(en|de)crypt() function. Reported-by: Euler Robot Signed-off-by: Chen Qun Signed-off-by: Daniel P. Berrangé --- crypto/cipher-builtin.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/crypto/cipher-builtin.c b/crypto/cipher-builtin.c index bf8413e71a..35cf7820d9 100644 --- a/crypto/cipher-builtin.c +++ b/crypto/cipher-builtin.c @@ -74,7 +74,7 @@ static void qcrypto_cipher_free_aes(QCryptoCipher *cipher) } -static void qcrypto_cipher_aes_ecb_encrypt(AES_KEY *key, +static void qcrypto_cipher_aes_ecb_encrypt(const AES_KEY *key, const void *in, void *out, size_t len) @@ -100,7 +100,7 @@ static void qcrypto_cipher_aes_ecb_encrypt(AES_KEY *key, } -static void qcrypto_cipher_aes_ecb_decrypt(AES_KEY *key, +static void qcrypto_cipher_aes_ecb_decrypt(const AES_KEY *key, const void *in, void *out, size_t len) @@ -133,8 +133,7 @@ static void qcrypto_cipher_aes_xts_encrypt(const void *ctx, { const QCryptoCipherBuiltinAESContext *aesctx = ctx; - qcrypto_cipher_aes_ecb_encrypt((AES_KEY *)&aesctx->enc, - src, dst, length); + qcrypto_cipher_aes_ecb_encrypt(&aesctx->enc, src, dst, length); } @@ -145,8 +144,7 @@ static void qcrypto_cipher_aes_xts_decrypt(const void *ctx, { const QCryptoCipherBuiltinAESContext *aesctx = ctx; - qcrypto_cipher_aes_ecb_decrypt((AES_KEY *)&aesctx->dec, - src, dst, length); + qcrypto_cipher_aes_ecb_decrypt(&aesctx->dec, src, dst, length); } From 3d1900a471c89ebdd9ea7f3582fe487e2f494419 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 26 Sep 2019 00:35:27 +0300 Subject: [PATCH 0315/2595] block: luks: better error message when creating too large files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently if you attampt to create too large file with luks you get the following error message: Formatting 'test.luks', fmt=luks size=17592186044416 key-secret=sec0 qemu-img: test.luks: Could not resize file: File too large While for raw format the error message is qemu-img: test.img: The image size is too large for file format 'raw' The reason for this is that qemu-img checks for errono of the failure, and presents the later error when it is -EFBIG However crypto generic code 'swallows' the errno and replaces it with -EIO. As an attempt to make it better, we can make luks driver, detect -EFBIG and in this case present a better error message, which is what this patch does The new error message is: qemu-img: error creating test.luks: The requested file size is too large Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1534898 Signed-off-by: Maxim Levitsky Signed-off-by: Daniel P. Berrangé --- block/crypto.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index ca44dae4f7..6b21d6bf6c 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -104,18 +104,35 @@ static ssize_t block_crypto_init_func(QCryptoBlock *block, Error **errp) { struct BlockCryptoCreateData *data = opaque; + Error *local_error = NULL; + int ret; if (data->size > INT64_MAX || headerlen > INT64_MAX - data->size) { - error_setg(errp, "The requested file size is too large"); - return -EFBIG; + ret = -EFBIG; + goto error; } /* User provided size should reflect amount of space made * available to the guest, so we must take account of that * which will be used by the crypto header */ - return blk_truncate(data->blk, data->size + headerlen, false, - data->prealloc, 0, errp); + ret = blk_truncate(data->blk, data->size + headerlen, false, + data->prealloc, 0, &local_error); + + if (ret >= 0) { + return ret; + } + +error: + if (ret == -EFBIG) { + /* Replace the error message with a better one */ + error_free(local_error); + error_setg(errp, "The requested file size is too large"); + } else { + error_propagate(errp, local_error); + } + + return ret; } From 6022e15d146d8bba9610a9d134afa4bc6e5d9275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 22 Aug 2019 16:40:03 +0100 Subject: [PATCH 0316/2595] crypto: extend hash benchmark to cover more algorithms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the hash benchmark so that it can validate all algorithms supported by QEMU instead of being limited to sha256. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrangé --- tests/benchmark-crypto-hash.c | 73 ++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 14 deletions(-) diff --git a/tests/benchmark-crypto-hash.c b/tests/benchmark-crypto-hash.c index 7f659f7323..d16837d00a 100644 --- a/tests/benchmark-crypto-hash.c +++ b/tests/benchmark-crypto-hash.c @@ -15,9 +15,14 @@ #include "crypto/init.h" #include "crypto/hash.h" +typedef struct QCryptoHashOpts { + size_t chunk_size; + QCryptoHashAlgorithm alg; +} QCryptoHashOpts; + static void test_hash_speed(const void *opaque) { - size_t chunk_size = (size_t)opaque; + const QCryptoHashOpts *opts = opaque; uint8_t *in = NULL, *out = NULL; size_t out_len = 0; const size_t total = 2 * GiB; @@ -25,26 +30,24 @@ static void test_hash_speed(const void *opaque) struct iovec iov; int ret; - in = g_new0(uint8_t, chunk_size); - memset(in, g_test_rand_int(), chunk_size); + in = g_new0(uint8_t, opts->chunk_size); + memset(in, g_test_rand_int(), opts->chunk_size); iov.iov_base = (char *)in; - iov.iov_len = chunk_size; + iov.iov_len = opts->chunk_size; g_test_timer_start(); remain = total; while (remain) { - ret = qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256, + ret = qcrypto_hash_bytesv(opts->alg, &iov, 1, &out, &out_len, NULL); g_assert(ret == 0); - remain -= chunk_size; + remain -= opts->chunk_size; } g_test_timer_elapsed(); - g_print("sha256: "); - g_print("Hash %zu GB chunk size %zu bytes ", total / GiB, chunk_size); g_print("%.2f MB/sec ", (double)total / MiB / g_test_timer_last()); g_free(out); @@ -53,17 +56,59 @@ static void test_hash_speed(const void *opaque) int main(int argc, char **argv) { - size_t i; char name[64]; g_test_init(&argc, &argv, NULL); g_assert(qcrypto_init(NULL) == 0); - for (i = 512; i <= 64 * KiB; i *= 2) { - memset(name, 0 , sizeof(name)); - snprintf(name, sizeof(name), "/crypto/hash/speed-%zu", i); - g_test_add_data_func(name, (void *)i, test_hash_speed); - } +#define TEST_ONE(a, c) \ + QCryptoHashOpts opts ## a ## c = { \ + .alg = QCRYPTO_HASH_ALG_ ## a, .chunk_size = c, \ + }; \ + memset(name, 0 , sizeof(name)); \ + snprintf(name, sizeof(name), \ + "/crypto/benchmark/hash/%s/bufsize-%d", \ + QCryptoHashAlgorithm_str(QCRYPTO_HASH_ALG_ ## a), \ + c); \ + if (qcrypto_hash_supports(QCRYPTO_HASH_ALG_ ## a)) \ + g_test_add_data_func(name, \ + &opts ## a ## c, \ + test_hash_speed); + + TEST_ONE(MD5, 512); + TEST_ONE(MD5, 1024); + TEST_ONE(MD5, 4096); + TEST_ONE(MD5, 16384); + + TEST_ONE(SHA1, 512); + TEST_ONE(SHA1, 1024); + TEST_ONE(SHA1, 4096); + TEST_ONE(SHA1, 16384); + + TEST_ONE(SHA224, 512); + TEST_ONE(SHA224, 1024); + TEST_ONE(SHA224, 4096); + TEST_ONE(SHA224, 16384); + + TEST_ONE(SHA384, 512); + TEST_ONE(SHA384, 1024); + TEST_ONE(SHA384, 4096); + TEST_ONE(SHA384, 16384); + + TEST_ONE(SHA256, 512); + TEST_ONE(SHA256, 1024); + TEST_ONE(SHA256, 4096); + TEST_ONE(SHA256, 16384); + + TEST_ONE(SHA512, 512); + TEST_ONE(SHA512, 1024); + TEST_ONE(SHA512, 4096); + TEST_ONE(SHA512, 16384); + + TEST_ONE(RIPEMD160, 512); + TEST_ONE(RIPEMD160, 1024); + TEST_ONE(RIPEMD160, 4096); + TEST_ONE(RIPEMD160, 16384); return g_test_run(); } From ed8b2828ccc9f94b2ea846a2adb6790edab393c3 Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Sat, 28 Mar 2020 01:19:08 +0800 Subject: [PATCH 0317/2595] migration: fix bad indentation in error_report() bad indentation conflicts with CODING_STYLE doc. Signed-off-by: Mao Zhongyi Message-Id: <09f7529c665cac0c6a5e032ac6fdb6ca701f7e37.1585329482.git.maozhongyi@cmss.chinamobile.com> Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Juan Quintela Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 177cce9e95..8f27174ff6 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -2494,7 +2494,7 @@ retry: if (header_type >= MIG_RP_MSG_MAX || header_type == MIG_RP_MSG_INVALID) { error_report("RP: Received invalid message 0x%04x length 0x%04x", - header_type, header_len); + header_type, header_len); mark_source_rp_bad(ms); goto out; } @@ -2503,9 +2503,9 @@ retry: header_len != rp_cmd_args[header_type].len) || header_len > sizeof(buf)) { error_report("RP: Received '%s' message (0x%04x) with" - "incorrect length %d expecting %zu", - rp_cmd_args[header_type].name, header_type, header_len, - (size_t)rp_cmd_args[header_type].len); + "incorrect length %d expecting %zu", + rp_cmd_args[header_type].name, header_type, header_len, + (size_t)rp_cmd_args[header_type].len); mark_source_rp_bad(ms); goto out; } @@ -2560,7 +2560,7 @@ retry: } if (header_len != expected_len) { error_report("RP: Req_Page_id with length %d expecting %zd", - header_len, expected_len); + header_len, expected_len); mark_source_rp_bad(ms); goto out; } From 2ee30cf078006f60bb59af8090a238e98dc7cfe5 Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Tue, 31 Mar 2020 16:22:05 +0800 Subject: [PATCH 0318/2595] migration/migration: improve error reporting for migrate parameters use QERR_INVALID_PARAMETER_VALUE instead of "Parameter '%s' expects" for consistency. Signed-off-by: Mao Zhongyi Message-Id: <4ce71da4a5f98ad6ead0806ec71043473dcb4c07.1585641083.git.maozhongyi@cmss.chinamobile.com> Reviewed-by: Juan Quintela Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 8f27174ff6..6e079efdcc 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1202,16 +1202,19 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp) } if (params->has_max_bandwidth && (params->max_bandwidth > SIZE_MAX)) { - error_setg(errp, "Parameter 'max_bandwidth' expects an integer in the" - " range of 0 to %zu bytes/second", SIZE_MAX); + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + "max_bandwidth", + "an integer in the range of 0 to "stringify(SIZE_MAX) + " bytes/second"); return false; } if (params->has_downtime_limit && (params->downtime_limit > MAX_MIGRATE_DOWNTIME)) { - error_setg(errp, "Parameter 'downtime_limit' expects an integer in " - "the range of 0 to %d milliseconds", - MAX_MIGRATE_DOWNTIME); + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + "downtime_limit", + "an integer in the range of 0 to " + stringify(MAX_MIGRATE_DOWNTIME)" milliseconds"); return false; } @@ -2107,9 +2110,10 @@ void qmp_migrate_set_speed(int64_t value, Error **errp) void qmp_migrate_set_downtime(double value, Error **errp) { if (value < 0 || value > MAX_MIGRATE_DOWNTIME_SECONDS) { - error_setg(errp, "Parameter 'downtime_limit' expects an integer in " - "the range of 0 to %d seconds", - MAX_MIGRATE_DOWNTIME_SECONDS); + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + "downtime_limit", + "an integer in the range of 0 to " + stringify(MAX_MIGRATE_DOWNTIME_SECONDS)" seconds"); return; } From f96c6a8736517af2a2d9e1fae3c1368d5b9adc4a Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Tue, 31 Mar 2020 16:22:06 +0800 Subject: [PATCH 0319/2595] monitor/hmp-cmds: add hmp_handle_error() for hmp_migrate_set_speed() Signed-off-by: Mao Zhongyi Reviewed-by: Juan Quintela Message-Id: <305323f835436023c53d759f5ab18af3ec874183.1585641083.git.maozhongyi@cmss.chinamobile.com> Signed-off-by: Dr. David Alan Gilbert --- monitor/hmp-cmds.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 7f6e982dc8..9bb6946fbf 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -1198,8 +1198,11 @@ void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict) /* Kept for backwards compatibility */ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict) { + Error *err = NULL; + int64_t value = qdict_get_int(qdict, "value"); - qmp_migrate_set_speed(value, NULL); + qmp_migrate_set_speed(value, &err); + hmp_handle_error(mon, err); } void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict) From 7ac5529afba7b4e9c4d9d1cbeb2b607208af97c1 Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Tue, 31 Mar 2020 16:22:07 +0800 Subject: [PATCH 0320/2595] migration: move the units of migrate parameters from milliseconds to ms Signed-off-by: Mao Zhongyi Reviewed-by: Juan Quintela Message-Id: <474bb6cf67defb8be9de5035c11aee57a680557a.1585641083.git.maozhongyi@cmss.chinamobile.com> Reviewed-by: Stefano Garzarella Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 2 +- monitor/hmp-cmds.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 6e079efdcc..79f16f6625 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1214,7 +1214,7 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp) error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "downtime_limit", "an integer in the range of 0 to " - stringify(MAX_MIGRATE_DOWNTIME)" milliseconds"); + stringify(MAX_MIGRATE_DOWNTIME)" ms"); return false; } diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 9bb6946fbf..1552dee489 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -231,18 +231,18 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) monitor_printf(mon, "\n"); } - monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n", + monitor_printf(mon, "total time: %" PRIu64 " ms\n", info->total_time); if (info->has_expected_downtime) { - monitor_printf(mon, "expected downtime: %" PRIu64 " milliseconds\n", + monitor_printf(mon, "expected downtime: %" PRIu64 " ms\n", info->expected_downtime); } if (info->has_downtime) { - monitor_printf(mon, "downtime: %" PRIu64 " milliseconds\n", + monitor_printf(mon, "downtime: %" PRIu64 " ms\n", info->downtime); } if (info->has_setup_time) { - monitor_printf(mon, "setup: %" PRIu64 " milliseconds\n", + monitor_printf(mon, "setup: %" PRIu64 " ms\n", info->setup_time); } } From 979da8b357903ee8a43017cbf640f43460d1e2f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 30 Mar 2020 19:48:52 +0200 Subject: [PATCH 0321/2595] docs/devel/migration: start a debugging section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explain how to use analyze-migration.py, this may help. Signed-off-by: Marc-André Lureau Message-Id: <20200330174852.456148-1-marcandre.lureau@redhat.com> Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Daniel P. Berrangé Signed-off-by: Dr. David Alan Gilbert --- docs/devel/migration.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst index e88918f763..2eb08624fc 100644 --- a/docs/devel/migration.rst +++ b/docs/devel/migration.rst @@ -50,6 +50,26 @@ All these migration protocols use the same infrastructure to save/restore state devices. This infrastructure is shared with the savevm/loadvm functionality. +Debugging +========= + +The migration stream can be analyzed thanks to `scripts/analyze_migration.py`. + +Example usage: + +.. code-block:: shell + + $ qemu-system-x86_64 + (qemu) migrate "exec:cat > mig" + $ ./scripts/analyze_migration.py -f mig + { + "ram (3)": { + "section sizes": { + "pc.ram": "0x0000000008000000", + ... + +See also ``analyze_migration.py -h`` help for more options. + Common infrastructure ===================== From 58602676dfd00f519248d4936b0711b7967cbf62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 13 Apr 2020 22:52:49 +0200 Subject: [PATCH 0322/2595] migration/colo: Add missing error-propagation code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running the coccinelle script produced: $ spatch \ --macro-file scripts/cocci-macro-file.h --include-headers \ --sp-file scripts/coccinelle/find-missing-error_propagate.cocci \ --keep-comments --smpl-spacing --dir . HANDLING: ./migration/colo.c [[manual check required: error_propagate() might be missing in migrate_set_block_enabled() ./migration/colo.c:439:4]] Add the missing error_propagate() after review. Reviewed-by: Juan Quintela Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200413205250.687-1-f4bug@amsat.org> Signed-off-by: Dr. David Alan Gilbert --- migration/colo.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/migration/colo.c b/migration/colo.c index 1b3493729b..d015d4f84e 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -443,6 +443,9 @@ static int colo_do_checkpoint_transaction(MigrationState *s, /* Disable block migration */ migrate_set_block_enabled(false, &local_err); + if (local_err) { + goto out; + } qemu_mutex_lock_iothread(); #ifdef CONFIG_REPLICATION From cbbf818224faf5ede75c876e4900c9f8e6b6c0db Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 13 Apr 2020 18:15:08 +0800 Subject: [PATCH 0323/2595] migration/throttle: Add cpu-throttle-tailslow migration parameter At the tail stage of throttling, the Guest is very sensitive to CPU percentage while the @cpu-throttle-increment is excessive usually at tail stage. If this parameter is true, we will compute the ideal CPU percentage used by the Guest, which may exactly make the dirty rate match the dirty rate threshold. Then we will choose a smaller throttle increment between the one specified by @cpu-throttle-increment and the one generated by ideal CPU percentage. Therefore, it is compatible to traditional throttling, meanwhile the throttle increment won't be excessive at tail stage. This may make migration time longer, and is disabled by default. Signed-off-by: Keqian Zhu Message-Id: <20200413101508.54793-1-zhukeqian1@huawei.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 13 ++++++++++++ migration/ram.c | 25 +++++++++++++++++----- monitor/hmp-cmds.c | 8 ++++++++ qapi/migration.json | 48 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 5 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 79f16f6625..f5dbffc442 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -785,6 +785,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->cpu_throttle_initial = s->parameters.cpu_throttle_initial; params->has_cpu_throttle_increment = true; params->cpu_throttle_increment = s->parameters.cpu_throttle_increment; + params->has_cpu_throttle_tailslow = true; + params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow; params->has_tls_creds = true; params->tls_creds = g_strdup(s->parameters.tls_creds); params->has_tls_hostname = true; @@ -1327,6 +1329,10 @@ static void migrate_params_test_apply(MigrateSetParameters *params, dest->cpu_throttle_increment = params->cpu_throttle_increment; } + if (params->has_cpu_throttle_tailslow) { + dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow; + } + if (params->has_tls_creds) { assert(params->tls_creds->type == QTYPE_QSTRING); dest->tls_creds = g_strdup(params->tls_creds->u.s); @@ -1415,6 +1421,10 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) s->parameters.cpu_throttle_increment = params->cpu_throttle_increment; } + if (params->has_cpu_throttle_tailslow) { + s->parameters.cpu_throttle_tailslow = params->cpu_throttle_tailslow; + } + if (params->has_tls_creds) { g_free(s->parameters.tls_creds); assert(params->tls_creds->type == QTYPE_QSTRING); @@ -3597,6 +3607,8 @@ static Property migration_properties[] = { DEFINE_PROP_UINT8("x-cpu-throttle-increment", MigrationState, parameters.cpu_throttle_increment, DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT), + DEFINE_PROP_BOOL("x-cpu-throttle-tailslow", MigrationState, + parameters.cpu_throttle_tailslow, false), DEFINE_PROP_SIZE("x-max-bandwidth", MigrationState, parameters.max_bandwidth, MAX_THROTTLE), DEFINE_PROP_UINT64("x-downtime-limit", MigrationState, @@ -3703,6 +3715,7 @@ static void migration_instance_init(Object *obj) params->has_throttle_trigger_threshold = true; params->has_cpu_throttle_initial = true; params->has_cpu_throttle_increment = true; + params->has_cpu_throttle_tailslow = true; params->has_max_bandwidth = true; params->has_downtime_limit = true; params->has_x_checkpoint_delay = true; diff --git a/migration/ram.c b/migration/ram.c index 53166fc279..52fc032b83 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -616,20 +616,34 @@ static size_t save_page_header(RAMState *rs, QEMUFile *f, RAMBlock *block, * able to complete migration. Some workloads dirty memory way too * fast and will not effectively converge, even with auto-converge. */ -static void mig_throttle_guest_down(void) +static void mig_throttle_guest_down(uint64_t bytes_dirty_period, + uint64_t bytes_dirty_threshold) { MigrationState *s = migrate_get_current(); uint64_t pct_initial = s->parameters.cpu_throttle_initial; - uint64_t pct_icrement = s->parameters.cpu_throttle_increment; + uint64_t pct_increment = s->parameters.cpu_throttle_increment; + bool pct_tailslow = s->parameters.cpu_throttle_tailslow; int pct_max = s->parameters.max_cpu_throttle; + uint64_t throttle_now = cpu_throttle_get_percentage(); + uint64_t cpu_now, cpu_ideal, throttle_inc; + /* We have not started throttling yet. Let's start it. */ if (!cpu_throttle_active()) { cpu_throttle_set(pct_initial); } else { /* Throttling already on, just increase the rate */ - cpu_throttle_set(MIN(cpu_throttle_get_percentage() + pct_icrement, - pct_max)); + if (!pct_tailslow) { + throttle_inc = pct_increment; + } else { + /* Compute the ideal CPU percentage used by Guest, which may + * make the dirty rate match the dirty rate threshold. */ + cpu_now = 100 - throttle_now; + cpu_ideal = cpu_now * (bytes_dirty_threshold * 1.0 / + bytes_dirty_period); + throttle_inc = MIN(cpu_now - cpu_ideal, pct_increment); + } + cpu_throttle_set(MIN(throttle_now + throttle_inc, pct_max)); } } @@ -919,7 +933,8 @@ static void migration_trigger_throttle(RAMState *rs) (++rs->dirty_rate_high_cnt >= 2)) { trace_migration_throttle(); rs->dirty_rate_high_cnt = 0; - mig_throttle_guest_down(); + mig_throttle_guest_down(bytes_dirty_period, + bytes_dirty_threshold); } } } diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 1552dee489..ade1f85e0c 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -420,6 +420,10 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%s: %u\n", MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT), params->cpu_throttle_increment); + assert(params->has_cpu_throttle_tailslow); + monitor_printf(mon, "%s: %s\n", + MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW), + params->cpu_throttle_tailslow ? "on" : "off"); assert(params->has_max_cpu_throttle); monitor_printf(mon, "%s: %u\n", MigrationParameter_str(MIGRATION_PARAMETER_MAX_CPU_THROTTLE), @@ -1275,6 +1279,10 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) p->has_cpu_throttle_increment = true; visit_type_int(v, param, &p->cpu_throttle_increment, &err); break; + case MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW: + p->has_cpu_throttle_tailslow = true; + visit_type_bool(v, param, &p->cpu_throttle_tailslow, &err); + break; case MIGRATION_PARAMETER_MAX_CPU_THROTTLE: p->has_max_cpu_throttle = true; visit_type_int(v, param, &p->max_cpu_throttle, &err); diff --git a/qapi/migration.json b/qapi/migration.json index eca2981d0a..ee6c5a0cae 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -552,6 +552,21 @@ # auto-converge detects that migration is not making # progress. The default value is 10. (Since 2.7) # +# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage +# At the tail stage of throttling, the Guest is very +# sensitive to CPU percentage while the @cpu-throttle +# -increment is excessive usually at tail stage. +# If this parameter is true, we will compute the ideal +# CPU percentage used by the Guest, which may exactly make +# the dirty rate match the dirty rate threshold. Then we +# will choose a smaller throttle increment between the +# one specified by @cpu-throttle-increment and the one +# generated by ideal CPU percentage. +# Therefore, it is compatible to traditional throttling, +# meanwhile the throttle increment won't be excessive +# at tail stage. +# The default value is false. (Since 5.1) +# # @tls-creds: ID of the 'tls-creds' object that provides credentials for # establishing a TLS connection over the migration data channel. # On the outgoing side of the migration, the credentials must @@ -631,6 +646,7 @@ 'compress-level', 'compress-threads', 'decompress-threads', 'compress-wait-thread', 'throttle-trigger-threshold', 'cpu-throttle-initial', 'cpu-throttle-increment', + 'cpu-throttle-tailslow', 'tls-creds', 'tls-hostname', 'tls-authz', 'max-bandwidth', 'downtime-limit', 'x-checkpoint-delay', 'block-incremental', 'multifd-channels', @@ -676,6 +692,21 @@ # auto-converge detects that migration is not making # progress. The default value is 10. (Since 2.7) # +# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage +# At the tail stage of throttling, the Guest is very +# sensitive to CPU percentage while the @cpu-throttle +# -increment is excessive usually at tail stage. +# If this parameter is true, we will compute the ideal +# CPU percentage used by the Guest, which may exactly make +# the dirty rate match the dirty rate threshold. Then we +# will choose a smaller throttle increment between the +# one specified by @cpu-throttle-increment and the one +# generated by ideal CPU percentage. +# Therefore, it is compatible to traditional throttling, +# meanwhile the throttle increment won't be excessive +# at tail stage. +# The default value is false. (Since 5.1) +# # @tls-creds: ID of the 'tls-creds' object that provides credentials # for establishing a TLS connection over the migration data # channel. On the outgoing side of the migration, the credentials @@ -763,6 +794,7 @@ '*throttle-trigger-threshold': 'int', '*cpu-throttle-initial': 'int', '*cpu-throttle-increment': 'int', + '*cpu-throttle-tailslow': 'bool', '*tls-creds': 'StrOrNull', '*tls-hostname': 'StrOrNull', '*tls-authz': 'StrOrNull', @@ -834,6 +866,21 @@ # auto-converge detects that migration is not making # progress. (Since 2.7) # +# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage +# At the tail stage of throttling, the Guest is very +# sensitive to CPU percentage while the @cpu-throttle +# -increment is excessive usually at tail stage. +# If this parameter is true, we will compute the ideal +# CPU percentage used by the Guest, which may exactly make +# the dirty rate match the dirty rate threshold. Then we +# will choose a smaller throttle increment between the +# one specified by @cpu-throttle-increment and the one +# generated by ideal CPU percentage. +# Therefore, it is compatible to traditional throttling, +# meanwhile the throttle increment won't be excessive +# at tail stage. +# The default value is false. (Since 5.1) +# # @tls-creds: ID of the 'tls-creds' object that provides credentials # for establishing a TLS connection over the migration data # channel. On the outgoing side of the migration, the credentials @@ -921,6 +968,7 @@ '*throttle-trigger-threshold': 'uint8', '*cpu-throttle-initial': 'uint8', '*cpu-throttle-increment': 'uint8', + '*cpu-throttle-tailslow': 'bool', '*tls-creds': 'str', '*tls-hostname': 'str', '*tls-authz': 'str', From ddf35bdf0ab4282dfc6c326da98b54d84f140a68 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 21 Apr 2020 10:52:56 +0200 Subject: [PATCH 0324/2595] migration/ram: Consolidate variable reset after placement in ram_load_postcopy() Let's consolidate resetting the variables. Cc: "Dr. David Alan Gilbert" Cc: Juan Quintela Cc: Peter Xu Signed-off-by: David Hildenbrand Message-Id: <20200421085300.7734-10-david@redhat.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert Fixup for context conflicts with 91ba442 --- migration/ram.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 52fc032b83..08eb382f53 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3147,7 +3147,7 @@ static int ram_load_postcopy(QEMUFile *f) /* Temporary page that is later 'placed' */ void *postcopy_host_page = mis->postcopy_tmp_page; void *this_host = NULL; - bool all_zero = false; + bool all_zero = true; int target_pages = 0; while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) { @@ -3174,7 +3174,6 @@ static int ram_load_postcopy(QEMUFile *f) addr &= TARGET_PAGE_MASK; trace_ram_load_postcopy_loop((uint64_t)addr, flags); - place_needed = false; if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE | RAM_SAVE_FLAG_COMPRESS_PAGE)) { block = ram_block_from_stream(f, flags); @@ -3199,9 +3198,7 @@ static int ram_load_postcopy(QEMUFile *f) */ page_buffer = postcopy_host_page + ((uintptr_t)host & (block->page_size - 1)); - /* If all TP are zero then we can optimise the place */ if (target_pages == 1) { - all_zero = true; this_host = (void *)QEMU_ALIGN_DOWN((uintptr_t)host, block->page_size); } else { @@ -3221,7 +3218,6 @@ static int ram_load_postcopy(QEMUFile *f) */ if (target_pages == (block->page_size / TARGET_PAGE_SIZE)) { place_needed = true; - target_pages = 0; } place_source = postcopy_host_page; } @@ -3303,6 +3299,10 @@ static int ram_load_postcopy(QEMUFile *f) ret = postcopy_place_page(mis, place_dest, place_source, block); } + place_needed = false; + target_pages = 0; + /* Assume we have a zero page until we detect something different */ + all_zero = true; } } From 59c59c67ee6b0327ae932deb303caa47919aeb1e Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Mon, 20 Apr 2020 06:27:27 -0400 Subject: [PATCH 0325/2595] migration/rdma: fix a memleak on error path in rdma_start_incoming_migration 'rdma->host' is malloced in qemu_rdma_data_init, but forgot to free on the error path in rdma_start_incoming_migration(), this patch fix that. The leak stack: Direct leak of 2 byte(s) in 1 object(s) allocated from: #0 0x7fb7add18ae8 in __interceptor_malloc (/lib64/libasan.so.5+0xefae8) #1 0x7fb7ad0df1d5 in g_malloc (/lib64/libglib-2.0.so.0+0x531d5) #2 0x7fb7ad0f8b32 in g_strdup (/lib64/libglib-2.0.so.0+0x6cb32) #3 0x55a0464a0f6f in qemu_rdma_data_init /mnt/sdb/qemu/migration/rdma.c:2647 #4 0x55a0464b0e76 in rdma_start_incoming_migration /mnt/sdb/qemu/migration/rdma.c:4020 #5 0x55a0463f898a in qemu_start_incoming_migration /mnt/sdb/qemu/migration/migration.c:365 #6 0x55a0458c75d3 in qemu_init /mnt/sdb/qemu/softmmu/vl.c:4438 #7 0x55a046a3d811 in main /mnt/sdb/qemu/softmmu/main.c:48 #8 0x7fb7a8417872 in __libc_start_main (/lib64/libc.so.6+0x23872) #9 0x55a04536b26d in _start (/mnt/sdb/qemu/build/x86_64-softmmu/qemu-system-x86_64+0x286926d) Reported-by: Euler Robot Signed-off-by: Pan Nengyuan Message-Id: <20200420102727.17339-1-pannengyuan@huawei.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- migration/rdma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/migration/rdma.c b/migration/rdma.c index f61587891b..967fda5b0c 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -4056,6 +4056,7 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) return; err: error_propagate(errp, local_err); + g_free(rdma->host); g_free(rdma); g_free(rdma_return_path); } From e460a4b1a4c0e0aeea2c56bfc2407a9a1d1a3ae2 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 30 Apr 2020 08:59:35 +0800 Subject: [PATCH 0326/2595] migration/xbzrle: add encoding rate Users may need to check the xbzrle encoding rate to know if the guest memory is xbzrle encoding-friendly, and dynamically turn off the encoding if the encoding rate is low. Signed-off-by: Yi Sun Signed-off-by: Wei Wang Message-Id: <1588208375-19556-1-git-send-email-wei.w.wang@intel.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 1 + migration/ram.c | 39 +++++++++++++++++++++++++++++++++++++-- monitor/hmp-cmds.c | 2 ++ qapi/migration.json | 5 ++++- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index f5dbffc442..0bb042a0f7 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -932,6 +932,7 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s) info->xbzrle_cache->pages = xbzrle_counters.pages; info->xbzrle_cache->cache_miss = xbzrle_counters.cache_miss; info->xbzrle_cache->cache_miss_rate = xbzrle_counters.cache_miss_rate; + info->xbzrle_cache->encoding_rate = xbzrle_counters.encoding_rate; info->xbzrle_cache->overflow = xbzrle_counters.overflow; } diff --git a/migration/ram.c b/migration/ram.c index 08eb382f53..859f835f1a 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -327,6 +327,10 @@ struct RAMState { uint64_t num_dirty_pages_period; /* xbzrle misses since the beginning of the period */ uint64_t xbzrle_cache_miss_prev; + /* Amount of xbzrle pages since the beginning of the period */ + uint64_t xbzrle_pages_prev; + /* Amount of xbzrle encoded bytes since the beginning of the period */ + uint64_t xbzrle_bytes_prev; /* compression statistics since the beginning of the period */ /* amount of count that no free thread to compress data */ @@ -710,6 +714,18 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data, return -1; } + /* + * Reaching here means the page has hit the xbzrle cache, no matter what + * encoding result it is (normal encoding, overflow or skipping the page), + * count the page as encoded. This is used to caculate the encoding rate. + * + * Example: 2 pages (8KB) being encoded, first page encoding generates 2KB, + * 2nd page turns out to be skipped (i.e. no new bytes written to the + * page), the overall encoding rate will be 8KB / 2KB = 4, which has the + * skipped page included. In this way, the encoding rate can tell if the + * guest page is good for xbzrle encoding. + */ + xbzrle_counters.pages++; prev_cached_page = get_cached_data(XBZRLE.cache, current_addr); /* save current buffer into memory */ @@ -740,6 +756,7 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data, } else if (encoded_len == -1) { trace_save_xbzrle_page_overflow(); xbzrle_counters.overflow++; + xbzrle_counters.bytes += TARGET_PAGE_SIZE; return -1; } @@ -750,8 +767,12 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data, qemu_put_be16(rs->f, encoded_len); qemu_put_buffer(rs->f, XBZRLE.encoded_buf, encoded_len); bytes_xbzrle += encoded_len + 1 + 2; - xbzrle_counters.pages++; - xbzrle_counters.bytes += bytes_xbzrle; + /* + * Like compressed_size (please see update_compress_thread_counts), + * the xbzrle encoded bytes don't count the 8 byte header with + * RAM_SAVE_FLAG_CONTINUE. + */ + xbzrle_counters.bytes += bytes_xbzrle - 8; ram_counters.transferred += bytes_xbzrle; return 1; @@ -884,9 +905,23 @@ static void migration_update_rates(RAMState *rs, int64_t end_time) } if (migrate_use_xbzrle()) { + double encoded_size, unencoded_size; + xbzrle_counters.cache_miss_rate = (double)(xbzrle_counters.cache_miss - rs->xbzrle_cache_miss_prev) / page_count; rs->xbzrle_cache_miss_prev = xbzrle_counters.cache_miss; + unencoded_size = (xbzrle_counters.pages - rs->xbzrle_pages_prev) * + TARGET_PAGE_SIZE; + encoded_size = xbzrle_counters.bytes - rs->xbzrle_bytes_prev; + if (xbzrle_counters.pages == rs->xbzrle_pages_prev) { + xbzrle_counters.encoding_rate = 0; + } else if (!encoded_size) { + xbzrle_counters.encoding_rate = UINT64_MAX; + } else { + xbzrle_counters.encoding_rate = unencoded_size / encoded_size; + } + rs->xbzrle_pages_prev = xbzrle_counters.pages; + rs->xbzrle_bytes_prev = xbzrle_counters.bytes; } if (migrate_use_compression()) { diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index ade1f85e0c..9c61e769ca 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -303,6 +303,8 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) info->xbzrle_cache->cache_miss); monitor_printf(mon, "xbzrle cache miss rate: %0.2f\n", info->xbzrle_cache->cache_miss_rate); + monitor_printf(mon, "xbzrle encoding rate: %0.2f\n", + info->xbzrle_cache->encoding_rate); monitor_printf(mon, "xbzrle overflow: %" PRIu64 "\n", info->xbzrle_cache->overflow); } diff --git a/qapi/migration.json b/qapi/migration.json index ee6c5a0cae..d5000558c6 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -70,6 +70,8 @@ # # @cache-miss-rate: rate of cache miss (since 2.1) # +# @encoding-rate: rate of encoded bytes (since 5.1) +# # @overflow: number of overflows # # Since: 1.2 @@ -77,7 +79,7 @@ { 'struct': 'XBZRLECacheStats', 'data': {'cache-size': 'int', 'bytes': 'int', 'pages': 'int', 'cache-miss': 'int', 'cache-miss-rate': 'number', - 'overflow': 'int' } } + 'encoding-rate': 'number', 'overflow': 'int' } } ## # @CompressionStats: @@ -337,6 +339,7 @@ # "pages":2444343, # "cache-miss":2244, # "cache-miss-rate":0.123, +# "encoding-rate":80.1, # "overflow":34434 # } # } From ad31b8af73b8c5df62bd5c82fb543e44aa856cd4 Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Wed, 6 May 2020 05:54:15 -0400 Subject: [PATCH 0327/2595] migration/multifd: fix memleaks in multifd_new_send_channel_async When error happen in multifd_new_send_channel_async, 'sioc' will not be used to create the multifd_send_thread. Let's free it to avoid a memleak. And also do error_free after migrate_set_error() to avoid another leak in the same place. The leak stack: Direct leak of 2880 byte(s) in 8 object(s) allocated from: #0 0x7f20b5118ae8 in __interceptor_malloc (/lib64/libasan.so.5+0xefae8) #1 0x7f20b44df1d5 in g_malloc (/lib64/libglib-2.0.so.0+0x531d5) #2 0x564133bce18b in object_new_with_type /mnt/sdb/backup/qemu/qom/object.c:683 #3 0x564133eea950 in qio_channel_socket_new /mnt/sdb/backup/qemu/io/channel-socket.c:56 #4 0x5641339cfe4f in socket_send_channel_create /mnt/sdb/backup/qemu/migration/socket.c:37 #5 0x564133a10328 in multifd_save_setup /mnt/sdb/backup/qemu/migration/multifd.c:772 #6 0x5641339cebed in migrate_fd_connect /mnt/sdb/backup/qemu/migration/migration.c:3530 #7 0x5641339d15e4 in migration_channel_connect /mnt/sdb/backup/qemu/migration/channel.c:92 #8 0x5641339cf5b7 in socket_outgoing_migration /mnt/sdb/backup/qemu/migration/socket.c:108 Direct leak of 384 byte(s) in 8 object(s) allocated from: #0 0x7f20b5118cf0 in calloc (/lib64/libasan.so.5+0xefcf0) #1 0x7f20b44df22d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5322d) #2 0x56413406fc17 in error_setv /mnt/sdb/backup/qemu/util/error.c:61 #3 0x564134070464 in error_setg_errno_internal /mnt/sdb/backup/qemu/util/error.c:109 #4 0x5641340851be in inet_connect_addr /mnt/sdb/backup/qemu/util/qemu-sockets.c:379 #5 0x5641340851be in inet_connect_saddr /mnt/sdb/backup/qemu/util/qemu-sockets.c:458 #6 0x5641340870ab in socket_connect /mnt/sdb/backup/qemu/util/qemu-sockets.c:1105 #7 0x564133eeaabf in qio_channel_socket_connect_sync /mnt/sdb/backup/qemu/io/channel-socket.c:145 #8 0x564133eeabf5 in qio_channel_socket_connect_worker /mnt/sdb/backup/qemu/io/channel-socket.c:168 Indirect leak of 360 byte(s) in 8 object(s) allocated from: #0 0x7f20b5118ae8 in __interceptor_malloc (/lib64/libasan.so.5+0xefae8) #1 0x7f20af901817 in __GI___vasprintf_chk (/lib64/libc.so.6+0x10d817) #2 0x7f20b451fa6c in g_vasprintf (/lib64/libglib-2.0.so.0+0x93a6c) #3 0x7f20b44f8cd0 in g_strdup_vprintf (/lib64/libglib-2.0.so.0+0x6ccd0) #4 0x7f20b44f8d8c in g_strdup_printf (/lib64/libglib-2.0.so.0+0x6cd8c) #5 0x56413406fc86 in error_setv /mnt/sdb/backup/qemu/util/error.c:65 #6 0x564134070464 in error_setg_errno_internal /mnt/sdb/backup/qemu/util/error.c:109 #7 0x5641340851be in inet_connect_addr /mnt/sdb/backup/qemu/util/qemu-sockets.c:379 #8 0x5641340851be in inet_connect_saddr /mnt/sdb/backup/qemu/util/qemu-sockets.c:458 #9 0x5641340870ab in socket_connect /mnt/sdb/backup/qemu/util/qemu-sockets.c:1105 #10 0x564133eeaabf in qio_channel_socket_connect_sync /mnt/sdb/backup/qemu/io/channel-socket.c:145 #11 0x564133eeabf5 in qio_channel_socket_connect_worker /mnt/sdb/backup/qemu/io/channel-socket.c:168 Reported-by: Euler Robot Signed-off-by: Pan Nengyuan Message-Id: <20200506095416.26099-2-pannengyuan@huawei.com> Reviewed-by: Juan Quintela Signed-off-by: Dr. David Alan Gilbert --- migration/multifd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/migration/multifd.c b/migration/multifd.c index 9123c111a3..e3efd33a0d 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -727,6 +727,8 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) * its status. */ p->quit = true; + object_unref(OBJECT(sioc)); + error_free(local_err); } else { p->c = QIO_CHANNEL(sioc); qio_channel_set_delay(p->c, false); From 13f2cb21e5fb33e9f8d7db8eee48edc1c67b812f Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Wed, 6 May 2020 05:54:16 -0400 Subject: [PATCH 0328/2595] migration/multifd: Do error_free after migrate_set_error to avoid memleaks When error happen in multifd_send_thread, it use error_copy to set migrate error in multifd_send_terminate_threads(). We should call error_free after it. Similarly, fix another two places in multifd_recv_thread/multifd_save_cleanup. The leak stack: Direct leak of 48 byte(s) in 1 object(s) allocated from: #0 0x7f781af07cf0 in calloc (/lib64/libasan.so.5+0xefcf0) #1 0x7f781a2ce22d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5322d) #2 0x55ee1d075c17 in error_setv /mnt/sdb/backup/qemu/util/error.c:61 #3 0x55ee1d076464 in error_setg_errno_internal /mnt/sdb/backup/qemu/util/error.c:109 #4 0x55ee1cef066e in qio_channel_socket_writev /mnt/sdb/backup/qemu/io/channel-socket.c:569 #5 0x55ee1cee806b in qio_channel_writev /mnt/sdb/backup/qemu/io/channel.c:207 #6 0x55ee1cee806b in qio_channel_writev_all /mnt/sdb/backup/qemu/io/channel.c:171 #7 0x55ee1cee8248 in qio_channel_write_all /mnt/sdb/backup/qemu/io/channel.c:257 #8 0x55ee1ca12c9a in multifd_send_thread /mnt/sdb/backup/qemu/migration/multifd.c:657 #9 0x55ee1d0607fc in qemu_thread_start /mnt/sdb/backup/qemu/util/qemu-thread-posix.c:519 #10 0x7f78159ae2dd in start_thread (/lib64/libpthread.so.0+0x82dd) #11 0x7f78156df4b2 in __GI___clone (/lib64/libc.so.6+0xfc4b2) Indirect leak of 52 byte(s) in 1 object(s) allocated from: #0 0x7f781af07f28 in __interceptor_realloc (/lib64/libasan.so.5+0xeff28) #1 0x7f78156f07d9 in __GI___vasprintf_chk (/lib64/libc.so.6+0x10d7d9) #2 0x7f781a30ea6c in g_vasprintf (/lib64/libglib-2.0.so.0+0x93a6c) #3 0x7f781a2e7cd0 in g_strdup_vprintf (/lib64/libglib-2.0.so.0+0x6ccd0) #4 0x7f781a2e7d8c in g_strdup_printf (/lib64/libglib-2.0.so.0+0x6cd8c) #5 0x55ee1d075c86 in error_setv /mnt/sdb/backup/qemu/util/error.c:65 #6 0x55ee1d076464 in error_setg_errno_internal /mnt/sdb/backup/qemu/util/error.c:109 #7 0x55ee1cef066e in qio_channel_socket_writev /mnt/sdb/backup/qemu/io/channel-socket.c:569 #8 0x55ee1cee806b in qio_channel_writev /mnt/sdb/backup/qemu/io/channel.c:207 #9 0x55ee1cee806b in qio_channel_writev_all /mnt/sdb/backup/qemu/io/channel.c:171 #10 0x55ee1cee8248 in qio_channel_write_all /mnt/sdb/backup/qemu/io/channel.c:257 #11 0x55ee1ca12c9a in multifd_send_thread /mnt/sdb/backup/qemu/migration/multifd.c:657 #12 0x55ee1d0607fc in qemu_thread_start /mnt/sdb/backup/qemu/util/qemu-thread-posix.c:519 #13 0x7f78159ae2dd in start_thread (/lib64/libpthread.so.0+0x82dd) #14 0x7f78156df4b2 in __GI___clone (/lib64/libc.so.6+0xfc4b2) Reported-by: Euler Robot Signed-off-by: Pan Nengyuan Message-Id: <20200506095416.26099-3-pannengyuan@huawei.com> Reviewed-by: Juan Quintela Signed-off-by: Dr. David Alan Gilbert --- migration/multifd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/migration/multifd.c b/migration/multifd.c index e3efd33a0d..5a3e4d0d46 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -550,6 +550,7 @@ void multifd_save_cleanup(void) multifd_send_state->ops->send_cleanup(p, &local_err); if (local_err) { migrate_set_error(migrate_get_current(), local_err); + error_free(local_err); } } qemu_sem_destroy(&multifd_send_state->channels_ready); @@ -688,6 +689,7 @@ out: if (local_err) { trace_multifd_send_error(p->id); multifd_send_terminate_threads(local_err); + error_free(local_err); } /* @@ -965,6 +967,7 @@ static void *multifd_recv_thread(void *opaque) if (local_err) { multifd_recv_terminate_threads(local_err); + error_free(local_err); } qemu_mutex_lock(&p->mutex); p->running = false; From cfdca2b9f9d4ca26bb2b2dfe8de3149092e39170 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 30 Apr 2020 15:47:06 +0300 Subject: [PATCH 0329/2595] iotests: handle tmpfs Some tests requires O_DIRECT, or want it by default. Introduce smarter O_DIRECT handling: - Check O_DIRECT in common.rc, if it is requested by selected cache-mode. - Support second fall-through argument in _default_cache_mode Inspired-by: Max's 23e1d054112cec1e Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200430124713.3067-2-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/091 | 2 +- tests/qemu-iotests/common.rc | 37 ++++++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091 index d2a2aca347..68fbfd777b 100755 --- a/tests/qemu-iotests/091 +++ b/tests/qemu-iotests/091 @@ -46,8 +46,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file _supported_os Linux -_default_cache_mode none _supported_cache_modes writethrough none writeback +_default_cache_mode none writeback size=1G diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index bf3b9fdea0..ba912555ca 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -673,11 +673,44 @@ _supported_cache_modes() _notrun "not suitable for cache mode: $CACHEMODE" } +# Check whether the filesystem supports O_DIRECT +_check_o_direct() +{ + $QEMU_IMG create -f raw "$TEST_IMG".test_o_direct 1M > /dev/null + out=$($QEMU_IO -f raw -t none -c quit "$TEST_IMG".test_o_direct 2>&1) + rm -f "$TEST_IMG".test_o_direct + + [[ "$out" != *"O_DIRECT"* ]] +} + +_require_o_direct() +{ + if ! _check_o_direct; then + _notrun "file system on $TEST_DIR does not support O_DIRECT" + fi +} + +_check_cache_mode() +{ + if [ $CACHEMODE == "none" ] || [ $CACHEMODE == "directsync" ]; then + _require_o_direct + fi +} + +_check_cache_mode + +# $1 - cache mode to use by default +# $2 - (optional) cache mode to use by default if O_DIRECT is not supported _default_cache_mode() { if $CACHEMODE_IS_DEFAULT; then - CACHEMODE="$1" - QEMU_IO="$QEMU_IO --cache $1" + if [ -z "$2" ] || _check_o_direct; then + CACHEMODE="$1" + else + CACHEMODE="$2" + fi + QEMU_IO="$QEMU_IO --cache $CACHEMODE" + _check_cache_mode return fi } From f03a8c73354f9f52364c528c3bdb4c42f08082e4 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 30 Apr 2020 15:47:07 +0300 Subject: [PATCH 0330/2595] iotests/082: require bochs Test fails if bochs not whitelisted, so, skip it in this case. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200430124713.3067-3-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/082 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082 index 3286c2c6db..1998965ed4 100755 --- a/tests/qemu-iotests/082 +++ b/tests/qemu-iotests/082 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file nfs +_require_drivers bochs run_qemu_img() { From 50bb041a3d0c611de38e1afbd8a6ac58e096da55 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 30 Apr 2020 15:47:08 +0300 Subject: [PATCH 0331/2595] iotests/148: use skip_if_unsupported Skip test-case with quorum if quorum is not whitelisted. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200430124713.3067-4-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/148 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qemu-iotests/148 b/tests/qemu-iotests/148 index 90931948e3..5e14a455b1 100755 --- a/tests/qemu-iotests/148 +++ b/tests/qemu-iotests/148 @@ -47,6 +47,7 @@ sector = "%d" ''' % bad_sector) file.close() + @iotests.skip_if_unsupported(['quorum']) def setUp(self): driveopts = ['driver=quorum', 'vote-threshold=2'] driveopts.append('read-pattern=%s' % self.read_pattern) From 4b4083d53f7b6da14a96eee2636fff2d1b197649 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 30 Apr 2020 15:47:09 +0300 Subject: [PATCH 0332/2595] iotests/041: drop self.assert_no_active_block_jobs() Drop check for no block-jobs: it's obvious that there no jobs immediately after vm.launch(). Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200430124713.3067-5-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/041 | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 46bf1f6c81..1812dd8479 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -904,8 +904,6 @@ class TestRepairQuorum(iotests.QMPTestCase): pass def test_complete(self): - self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', sync='full', node_name="repair0", replaces="img1", target=quorum_repair_img, format=iotests.imgfmt) @@ -919,8 +917,6 @@ class TestRepairQuorum(iotests.QMPTestCase): 'target image does not match source after mirroring') def test_cancel(self): - self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', sync='full', node_name="repair0", replaces="img1", target=quorum_repair_img, format=iotests.imgfmt) @@ -932,8 +928,6 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_has_block_node(None, quorum_img3) def test_cancel_after_ready(self): - self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', sync='full', node_name="repair0", replaces="img1", target=quorum_repair_img, format=iotests.imgfmt) @@ -948,8 +942,6 @@ class TestRepairQuorum(iotests.QMPTestCase): 'target image does not match source after mirroring') def test_pause(self): - self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', sync='full', node_name="repair0", replaces="img1", target=quorum_repair_img, format=iotests.imgfmt) From 8e8372944e5e097e98844b4db10f867689065e16 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 30 Apr 2020 15:47:10 +0300 Subject: [PATCH 0333/2595] iotests/055: refactor compressed backup to vmdk Instead of looping in each test, let's better refactor vmdk target case as a subclass. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200430124713.3067-6-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/055 | 70 ++++++++++++++++++++------------------ tests/qemu-iotests/055.out | 4 +-- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index 4175fff5e4..d9e8985167 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -450,10 +450,9 @@ class TestSingleTransaction(iotests.QMPTestCase): self.assert_no_active_block_jobs() -class TestDriveCompression(iotests.QMPTestCase): +class TestCompressedToQcow2(iotests.QMPTestCase): image_len = 64 * 1024 * 1024 # MB - fmt_supports_compression = [{'type': 'qcow2', 'args': ()}, - {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized')}] + target_fmt = {'type': 'qcow2', 'args': ()} def tearDown(self): self.vm.shutdown() @@ -463,19 +462,20 @@ class TestDriveCompression(iotests.QMPTestCase): except OSError: pass - def do_prepare_drives(self, fmt, args, attach_target): + def do_prepare_drives(self, attach_target): self.vm = iotests.VM().add_drive('blkdebug::' + test_img) - qemu_img('create', '-f', fmt, blockdev_target_img, - str(TestDriveCompression.image_len), *args) + qemu_img('create', '-f', self.target_fmt['type'], blockdev_target_img, + str(self.image_len), *self.target_fmt['args']) if attach_target: self.vm.add_drive(blockdev_target_img, - img_format=fmt, interface="none") + img_format=self.target_fmt['type'], + interface="none") self.vm.launch() - def do_test_compress_complete(self, cmd, format, attach_target, **args): - self.do_prepare_drives(format['type'], format['args'], attach_target) + def do_test_compress_complete(self, cmd, attach_target, **args): + self.do_prepare_drives(attach_target) self.assert_no_active_block_jobs() @@ -486,21 +486,21 @@ class TestDriveCompression(iotests.QMPTestCase): self.vm.shutdown() self.assertTrue(iotests.compare_images(test_img, blockdev_target_img, - iotests.imgfmt, format['type']), + iotests.imgfmt, + self.target_fmt['type']), 'target image does not match source after backup') def test_complete_compress_drive_backup(self): - for format in TestDriveCompression.fmt_supports_compression: - self.do_test_compress_complete('drive-backup', format, False, - target=blockdev_target_img, mode='existing') + self.do_test_compress_complete('drive-backup', False, + target=blockdev_target_img, + mode='existing') def test_complete_compress_blockdev_backup(self): - for format in TestDriveCompression.fmt_supports_compression: - self.do_test_compress_complete('blockdev-backup', format, True, - target='drive1') + self.do_test_compress_complete('blockdev-backup', + True, target='drive1') - def do_test_compress_cancel(self, cmd, format, attach_target, **args): - self.do_prepare_drives(format['type'], format['args'], attach_target) + def do_test_compress_cancel(self, cmd, attach_target, **args): + self.do_prepare_drives(attach_target) self.assert_no_active_block_jobs() @@ -514,17 +514,16 @@ class TestDriveCompression(iotests.QMPTestCase): self.vm.shutdown() def test_compress_cancel_drive_backup(self): - for format in TestDriveCompression.fmt_supports_compression: - self.do_test_compress_cancel('drive-backup', format, False, - target=blockdev_target_img, mode='existing') + self.do_test_compress_cancel('drive-backup', False, + target=blockdev_target_img, + mode='existing') def test_compress_cancel_blockdev_backup(self): - for format in TestDriveCompression.fmt_supports_compression: - self.do_test_compress_cancel('blockdev-backup', format, True, - target='drive1') + self.do_test_compress_cancel('blockdev-backup', True, + target='drive1') - def do_test_compress_pause(self, cmd, format, attach_target, **args): - self.do_prepare_drives(format['type'], format['args'], attach_target) + def do_test_compress_pause(self, cmd, attach_target, **args): + self.do_prepare_drives(attach_target) self.assert_no_active_block_jobs() @@ -550,18 +549,23 @@ class TestDriveCompression(iotests.QMPTestCase): self.vm.shutdown() self.assertTrue(iotests.compare_images(test_img, blockdev_target_img, - iotests.imgfmt, format['type']), + iotests.imgfmt, + self.target_fmt['type']), 'target image does not match source after backup') def test_compress_pause_drive_backup(self): - for format in TestDriveCompression.fmt_supports_compression: - self.do_test_compress_pause('drive-backup', format, False, - target=blockdev_target_img, mode='existing') + self.do_test_compress_pause('drive-backup', False, + target=blockdev_target_img, + mode='existing') def test_compress_pause_blockdev_backup(self): - for format in TestDriveCompression.fmt_supports_compression: - self.do_test_compress_pause('blockdev-backup', format, True, - target='drive1') + self.do_test_compress_pause('blockdev-backup', True, + target='drive1') + + +class TestCompressedToVmdk(TestCompressedToQcow2): + target_fmt = {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized')} + if __name__ == '__main__': iotests.main(supported_fmts=['raw', 'qcow2'], diff --git a/tests/qemu-iotests/055.out b/tests/qemu-iotests/055.out index 5ce2f9a2ed..5c26d15c0d 100644 --- a/tests/qemu-iotests/055.out +++ b/tests/qemu-iotests/055.out @@ -1,5 +1,5 @@ -.............................. +.................................... ---------------------------------------------------------------------- -Ran 30 tests +Ran 36 tests OK From 761cd2e791eae38c3d08ea5f83309ce58bb85ff7 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 30 Apr 2020 15:47:11 +0300 Subject: [PATCH 0334/2595] iotests/055: skip vmdk target tests if vmdk is not whitelisted Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200430124713.3067-7-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/055 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index d9e8985167..e250f798f9 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -566,6 +566,10 @@ class TestCompressedToQcow2(iotests.QMPTestCase): class TestCompressedToVmdk(TestCompressedToQcow2): target_fmt = {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized')} + @iotests.skip_if_unsupported(['vmdk']) + def setUp(self): + pass + if __name__ == '__main__': iotests.main(supported_fmts=['raw', 'qcow2'], From 503034efc8c443c9eee7d6c0d3850f9086d1dde4 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 30 Apr 2020 15:47:12 +0300 Subject: [PATCH 0335/2595] iotests/109: mark required formats as required to support whitelisting Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200430124713.3067-8-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/109 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109 index a51dd84b3d..5bc2e9b001 100755 --- a/tests/qemu-iotests/109 +++ b/tests/qemu-iotests/109 @@ -42,6 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt raw _supported_proto file _supported_os Linux +_require_drivers qcow qcow2 qed vdi vmdk vpc qemu_comm_method=qmp From 5fc2b4f21811668c7cbbe907bdddab839fb50fe9 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 30 Apr 2020 15:47:13 +0300 Subject: [PATCH 0336/2595] iotests/113: mark bochs as required to support whitelisting Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200430124713.3067-9-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/113 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/113 b/tests/qemu-iotests/113 index f2703a2c50..71a65de2e7 100755 --- a/tests/qemu-iotests/113 +++ b/tests/qemu-iotests/113 @@ -37,8 +37,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 . ./common.rc . ./common.filter -# Some of these test cases use bochs, but others do use raw, so this -# is only half a lie. +# Some of these test cases use bochs, but others do use raw +_require_drivers bochs _supported_fmt raw _supported_proto file _supported_os Linux From e4d7019e1a81c61de6a925c3ac5bb6e62ea21b29 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Mon, 4 May 2020 17:52:17 +0200 Subject: [PATCH 0337/2595] qcow2: Avoid integer wraparound in qcow2_co_truncate() After commit f01643fb8b47e8a70c04bbf45e0f12a9e5bc54de when an image is extended and BDRV_REQ_ZERO_WRITE is set then the new clusters are zeroized. The code however does not detect correctly situations when the old and the new end of the image are within the same cluster. The problem can be reproduced with these steps: qemu-img create -f qcow2 backing.qcow2 1M qemu-img create -f qcow2 -F qcow2 -b backing.qcow2 top.qcow2 qemu-img resize --shrink top.qcow2 520k qemu-img resize top.qcow2 567k In the last step offset - zero_start causes an integer wraparound. Signed-off-by: Alberto Garcia Message-Id: <20200504155217.10325-1-berto@igalia.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/qcow2.c | 12 ++++--- tests/qemu-iotests/292 | 73 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/292.out | 24 +++++++++++++ tests/qemu-iotests/group | 1 + 4 files changed, 105 insertions(+), 5 deletions(-) create mode 100755 tests/qemu-iotests/292 create mode 100644 tests/qemu-iotests/292.out diff --git a/block/qcow2.c b/block/qcow2.c index ad934109a8..fc7d4b185e 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -4242,15 +4242,17 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, * requires a cluster-aligned start. The end may be unaligned if it is * at the end of the image (which it is here). */ - ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0); - if (ret < 0) { - error_setg_errno(errp, -ret, "Failed to zero out new clusters"); - goto fail; + if (offset > zero_start) { + ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to zero out new clusters"); + goto fail; + } } /* Write explicit zeros for the unaligned head */ if (zero_start > old_length) { - uint64_t len = zero_start - old_length; + uint64_t len = MIN(zero_start, offset) - old_length; uint8_t *buf = qemu_blockalign0(bs, len); QEMUIOVector qiov; qemu_iovec_init_buf(&qiov, buf, len); diff --git a/tests/qemu-iotests/292 b/tests/qemu-iotests/292 new file mode 100755 index 0000000000..a2de27cca4 --- /dev/null +++ b/tests/qemu-iotests/292 @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# +# Test resizing a qcow2 image with a backing file +# +# Copyright (C) 2020 Igalia, S.L. +# Author: Alberto Garcia +# +# 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 . +# + +# creator +owner=berto@igalia.com + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +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 + +echo '### Create the backing image' +BACKING_IMG="$TEST_IMG.base" +TEST_IMG="$BACKING_IMG" _make_test_img 1M + +echo '### Fill the backing image with data (0x11)' +$QEMU_IO -c 'write -P 0x11 0 1M' "$BACKING_IMG" | _filter_qemu_io + +echo '### Create the top image' +_make_test_img -F "$IMGFMT" -b "$BACKING_IMG" + +echo '### Fill the top image with data (0x22)' +$QEMU_IO -c 'write -P 0x22 0 1M' "$TEST_IMG" | _filter_qemu_io + +# Both offsets are part of the same cluster. +echo '### Shrink the image to 520k' +$QEMU_IMG resize --shrink "$TEST_IMG" 520k +echo '### Grow the image to 567k' +$QEMU_IMG resize "$TEST_IMG" 567k + +echo '### Check that the tail of the image reads as zeroes' +$QEMU_IO -c 'read -P 0x22 0 520k' "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c 'read -P 0x00 520k 47k' "$TEST_IMG" | _filter_qemu_io + +echo '### Show output of qemu-img map' +$QEMU_IMG map "$TEST_IMG" | _filter_testdir + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/292.out b/tests/qemu-iotests/292.out new file mode 100644 index 0000000000..807e0530c3 --- /dev/null +++ b/tests/qemu-iotests/292.out @@ -0,0 +1,24 @@ +QA output created by 292 +### Create the backing image +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576 +### Fill the backing image with data (0x11) +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +### Create the top image +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +### Fill the top image with data (0x22) +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +### Shrink the image to 520k +Image resized. +### Grow the image to 567k +Image resized. +### Check that the tail of the image reads as zeroes +read 532480/532480 bytes at offset 0 +520 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 48128/48128 bytes at offset 532480 +47 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +### Show output of qemu-img map +Offset Length Mapped to File +0 0x8dc00 0x50000 TEST_DIR/t.qcow2 +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 1710470e70..fe649c5b73 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -298,3 +298,4 @@ 288 quick 289 rw quick 290 rw auto quick +292 rw auto quick From 4dc20e6465eccd2466a449d3fb49539f5d9f53dd Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 30 Apr 2020 15:30:02 +0200 Subject: [PATCH 0338/2595] vmdk: Rename VmdkMetaData.valid to new_allocation m_data is used for zero clusters even though valid == 0. It really only means that a new cluster was allocated in the image file. Rename it to reflect this. While at it, change it from int to bool, too. Signed-off-by: Kevin Wolf Message-Id: <20200430133007.170335-2-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/vmdk.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index b02fdd14b2..ecfb4a86d2 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -180,7 +180,7 @@ typedef struct VmdkMetaData { unsigned int l1_index; unsigned int l2_index; unsigned int l2_offset; - int valid; + bool new_allocation; uint32_t *l2_cache_entry; } VmdkMetaData; @@ -1492,7 +1492,7 @@ static int get_cluster_offset(BlockDriverState *bs, unsigned int l2_size_bytes = extent->l2_size * extent->entry_size; if (m_data) { - m_data->valid = 0; + m_data->new_allocation = false; } if (extent->flat) { *cluster_offset = extent->flat_start_offset; @@ -1630,7 +1630,7 @@ static int get_cluster_offset(BlockDriverState *bs, return ret; } if (m_data) { - m_data->valid = 1; + m_data->new_allocation = true; m_data->l1_index = l1_index; m_data->l2_index = l2_index; m_data->l2_offset = l2_offset; @@ -2021,7 +2021,7 @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset, if (ret) { return ret; } - if (m_data.valid) { + if (m_data.new_allocation) { /* update L2 tables */ if (vmdk_L2update(extent, &m_data, cluster_offset >> BDRV_SECTOR_BITS) From 2821c1cc0f8cbfcc332387e83be746af6f27cb4f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 30 Apr 2020 15:30:03 +0200 Subject: [PATCH 0339/2595] vmdk: Fix zero cluster allocation m_data must contain valid data even for zero clusters when no cluster was allocated in the image file. Without this, zero writes segfault with images that have zeroed_grain=on. For zero writes, we don't want to allocate a cluster in the image file even in compressed files. Fixes: 524089bce43fd1cd3daaca979872451efa2cf7c6 Signed-off-by: Kevin Wolf Message-Id: <20200430133007.170335-3-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/vmdk.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index ecfb4a86d2..fcd6b38d64 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1572,6 +1572,12 @@ static int get_cluster_offset(BlockDriverState *bs, extent->l2_cache_counts[min_index] = 1; found: l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size; + if (m_data) { + m_data->l1_index = l1_index; + m_data->l2_index = l2_index; + m_data->l2_offset = l2_offset; + m_data->l2_cache_entry = ((uint32_t *)l2_table) + l2_index; + } if (extent->sesparse) { cluster_sector = le64_to_cpu(((uint64_t *)l2_table)[l2_index]); @@ -1631,10 +1637,6 @@ static int get_cluster_offset(BlockDriverState *bs, } if (m_data) { m_data->new_allocation = true; - m_data->l1_index = l1_index; - m_data->l2_index = l2_index; - m_data->l2_offset = l2_offset; - m_data->l2_cache_entry = ((uint32_t *)l2_table) + l2_index; } } *cluster_offset = cluster_sector << BDRV_SECTOR_BITS; @@ -1990,7 +1992,7 @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset, error_report("Could not write to allocated cluster" " for streamOptimized"); return -EIO; - } else { + } else if (!zeroed) { /* allocate */ ret = get_cluster_offset(bs, extent, &m_data, offset, true, &cluster_offset, 0, 0); From 4823cde58eb507fcdcc0225b087343439a6cb43c Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 30 Apr 2020 15:30:04 +0200 Subject: [PATCH 0340/2595] vmdk: Fix partial overwrite of zero cluster When overwriting a zero cluster, we must not perform copy-on-write from the backing file, but from a zeroed buffer. Signed-off-by: Kevin Wolf Message-Id: <20200430133007.170335-4-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/vmdk.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index fcd6b38d64..ab8eec1f27 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1340,7 +1340,9 @@ static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp) * get_whole_cluster * * Copy backing file's cluster that covers @sector_num, otherwise write zero, - * to the cluster at @cluster_sector_num. + * to the cluster at @cluster_sector_num. If @zeroed is true, we're overwriting + * a zeroed cluster in the current layer and must not copy data from the + * backing file. * * If @skip_start_sector < @skip_end_sector, the relative range * [@skip_start_sector, @skip_end_sector) is not copied or written, and leave @@ -1351,18 +1353,21 @@ static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset, uint64_t offset, uint64_t skip_start_bytes, - uint64_t skip_end_bytes) + uint64_t skip_end_bytes, + bool zeroed) { int ret = VMDK_OK; int64_t cluster_bytes; uint8_t *whole_grain; + bool copy_from_backing; /* For COW, align request sector_num to cluster start */ cluster_bytes = extent->cluster_sectors << BDRV_SECTOR_BITS; offset = QEMU_ALIGN_DOWN(offset, cluster_bytes); whole_grain = qemu_blockalign(bs, cluster_bytes); + copy_from_backing = bs->backing && !zeroed; - if (!bs->backing) { + if (!copy_from_backing) { memset(whole_grain, 0, skip_start_bytes); memset(whole_grain + skip_end_bytes, 0, cluster_bytes - skip_end_bytes); } @@ -1377,7 +1382,7 @@ static int get_whole_cluster(BlockDriverState *bs, /* Read backing data before skip range */ if (skip_start_bytes > 0) { - if (bs->backing) { + if (copy_from_backing) { /* qcow2 emits this on bs->file instead of bs->backing */ BLKDBG_EVENT(extent->file, BLKDBG_COW_READ); ret = bdrv_pread(bs->backing, offset, whole_grain, @@ -1397,7 +1402,7 @@ static int get_whole_cluster(BlockDriverState *bs, } /* Read backing data after skip range */ if (skip_end_bytes < cluster_bytes) { - if (bs->backing) { + if (copy_from_backing) { /* qcow2 emits this on bs->file instead of bs->backing */ BLKDBG_EVENT(extent->file, BLKDBG_COW_READ); ret = bdrv_pread(bs->backing, offset + skip_end_bytes, @@ -1631,7 +1636,8 @@ static int get_cluster_offset(BlockDriverState *bs, * or inappropriate VM shutdown. */ ret = get_whole_cluster(bs, extent, cluster_sector * BDRV_SECTOR_SIZE, - offset, skip_start_bytes, skip_end_bytes); + offset, skip_start_bytes, skip_end_bytes, + zeroed); if (ret) { return ret; } From 78cae78dbcf94a151203ab5c6e418d9d9094a59e Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 30 Apr 2020 15:30:05 +0200 Subject: [PATCH 0341/2595] vmdk: Don't update L2 table for zero write on zero cluster If a cluster is already zeroed, we don't have to call vmdk_L2update(), which is rather slow because it flushes the image file. Signed-off-by: Kevin Wolf Message-Id: <20200430133007.170335-5-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/vmdk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/vmdk.c b/block/vmdk.c index ab8eec1f27..2880d88dea 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2013,7 +2013,7 @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset, offset_in_cluster == 0 && n_bytes >= extent->cluster_sectors * BDRV_SECTOR_SIZE) { n_bytes = extent->cluster_sectors * BDRV_SECTOR_SIZE; - if (!zero_dry_run) { + if (!zero_dry_run && ret != VMDK_ZEROED) { /* update L2 tables */ if (vmdk_L2update(extent, &m_data, VMDK_GTE_ZEROED) != VMDK_OK) { From 2758be056ba814cd5a878b71c231af79a863b058 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 30 Apr 2020 15:30:06 +0200 Subject: [PATCH 0342/2595] vmdk: Flush only once in vmdk_L2update() If we have a backup L2 table, we currently flush once after writing to the active L2 table and again after writing to the backup table. A single flush is enough and makes things a little less slow. Signed-off-by: Kevin Wolf Message-Id: <20200430133007.170335-6-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/vmdk.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index 2880d88dea..b18f128816 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1435,7 +1435,7 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, offset = cpu_to_le32(offset); /* update L2 table */ BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE); - if (bdrv_pwrite_sync(extent->file, + if (bdrv_pwrite(extent->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(offset)), &offset, sizeof(offset)) < 0) { @@ -1444,13 +1444,16 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, /* update backup L2 table */ if (extent->l1_backup_table_offset != 0) { m_data->l2_offset = extent->l1_backup_table[m_data->l1_index]; - if (bdrv_pwrite_sync(extent->file, + if (bdrv_pwrite(extent->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(offset)), &offset, sizeof(offset)) < 0) { return VMDK_ERROR; } } + if (bdrv_flush(extent->file->bs) < 0) { + return VMDK_ERROR; + } if (m_data->l2_cache_entry) { *m_data->l2_cache_entry = offset; } From c1eafd27b136b6717f8271e842372565d9b8c178 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 30 Apr 2020 15:30:07 +0200 Subject: [PATCH 0343/2595] iotests: vmdk: Enable zeroed_grained=on by default In order to avoid bitrot in the zero cluster code in VMDK, enable zeroed_grain=on by default for the tests. 059 now unsets the default options because zeroed_grain=on works only with some subformats and the test case tests many different subformats, including those for which it doesn't work. Signed-off-by: Kevin Wolf Message-Id: <20200430133007.170335-7-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- tests/qemu-iotests/059 | 6 +++--- tests/qemu-iotests/check | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index 5438025285..4c90fc0363 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -41,9 +41,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt vmdk _supported_proto file _supported_os Linux -_unsupported_imgopts "subformat=monolithicFlat" \ - "subformat=twoGbMaxExtentFlat" \ - "subformat=twoGbMaxExtentSparse" + +# We test all kinds of VMDK options here, so ignore user-specified options +IMGOPTS="" capacity_offset=16 granularity_offset=20 diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index f7a2d3d6c3..9c461cf76d 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -546,6 +546,9 @@ fi if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10") fi +if [ "$IMGFMT" == "vmdk" ] && ! (echo "$IMGOPTS" | grep "zeroed_grain=" > /dev/null); then + IMGOPTS=$(_optstr_add "$IMGOPTS" "zeroed_grain=on") +fi if [ -z "$SAMPLE_IMG_DIR" ]; then SAMPLE_IMG_DIR="$source_iotests/sample_images" From 813cc2545b82409fd504509f0ba2e96fab6edb9e Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 30 Apr 2020 16:27:52 +0200 Subject: [PATCH 0344/2595] iotests/283: Use consistent size for source and target The test case forgot to specify the null-co size for the target node. When adding a check to backup that both sizes match, this would fail because of the size mismatch and not the behaviour that the test really wanted to test. Fixes: a541fcc27c98b96da187c7d4573f3270f3ddd283 Signed-off-by: Kevin Wolf Message-Id: <20200430142755.315494-2-kwolf@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- tests/qemu-iotests/283 | 6 +++++- tests/qemu-iotests/283.out | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/283 b/tests/qemu-iotests/283 index e17b953333..383797ed62 100644 --- a/tests/qemu-iotests/283 +++ b/tests/qemu-iotests/283 @@ -74,7 +74,11 @@ to check that crash is fixed :) vm = iotests.VM() vm.launch() -vm.qmp_log('blockdev-add', **{'node-name': 'target', 'driver': 'null-co'}) +vm.qmp_log('blockdev-add', **{ + 'node-name': 'target', + 'driver': 'null-co', + 'size': size, +}) vm.qmp_log('blockdev-add', **{ 'node-name': 'source', diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out index daaf5828c1..d8cff22cc1 100644 --- a/tests/qemu-iotests/283.out +++ b/tests/qemu-iotests/283.out @@ -1,4 +1,4 @@ -{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "target"}} +{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "target", "size": 1048576}} {"return": {}} {"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": {"driver": "null-co", "node-name": "base", "size": 1048576}, "node-name": "source"}} {"return": {}} From 58226634c4b02af7b10862f7fbd3610a344bfb7f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 30 Apr 2020 16:27:53 +0200 Subject: [PATCH 0345/2595] backup: Improve error for bdrv_getlength() failure bdrv_get_device_name() will be an empty string with modern management tools that don't use -drive. Use bdrv_get_device_or_node_name() instead so that the node name is used if the BlockBackend is anonymous. While at it, start with upper case to make the message consistent with the rest of the function. Signed-off-by: Kevin Wolf Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Message-Id: <20200430142755.315494-3-kwolf@redhat.com> Signed-off-by: Kevin Wolf --- block/backup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/backup.c b/block/backup.c index a7a7dcaf4c..c4c3b8cd46 100644 --- a/block/backup.c +++ b/block/backup.c @@ -400,8 +400,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, len = bdrv_getlength(bs); if (len < 0) { - error_setg_errno(errp, -len, "unable to get length for '%s'", - bdrv_get_device_name(bs)); + error_setg_errno(errp, -len, "Unable to get length for '%s'", + bdrv_get_device_or_node_name(bs)); goto error; } From 958a04bd32af18d9a207bcc78046e56a202aebc2 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 30 Apr 2020 16:27:54 +0200 Subject: [PATCH 0346/2595] backup: Make sure that source and target size match Since the introduction of a backup filter node in commit 00e30f05d, the backup block job crashes when the target image is smaller than the source image because it will try to write after the end of the target node without having BLK_PERM_RESIZE. (Previously, the BlockBackend layer would have caught this and errored out gracefully.) We can fix this and even do better than the old behaviour: Check that source and target have the same image size at the start of the block job and unshare BLK_PERM_RESIZE. (This permission was already unshared before the same commit 00e30f05d, but the BlockBackend that was used to make the restriction was removed without a replacement.) This will immediately error out when starting the job instead of only when writing to a block that doesn't exist in the target. Longer target than source would technically work because we would never write to blocks that don't exist, but semantically these are invalid, too, because a backup is supposed to create a copy, not just an image that starts with a copy. Fixes: 00e30f05de1d19586345ec373970ef4c192c6270 Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1778593 Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf Message-Id: <20200430142755.315494-4-kwolf@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- block/backup-top.c | 14 +++++++++----- block/backup.c | 14 +++++++++++++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/block/backup-top.c b/block/backup-top.c index 3b50c06e2c..79b268e6dc 100644 --- a/block/backup-top.c +++ b/block/backup-top.c @@ -148,8 +148,10 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, * * Share write to target (child_file), to not interfere * with guest writes to its disk which may be in target backing chain. + * Can't resize during a backup block job because we check the size + * only upfront. */ - *nshared = BLK_PERM_ALL; + *nshared = BLK_PERM_ALL & ~BLK_PERM_RESIZE; *nperm = BLK_PERM_WRITE; } else { /* Source child */ @@ -159,7 +161,7 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, if (perm & BLK_PERM_WRITE) { *nperm = *nperm | BLK_PERM_CONSISTENT_READ; } - *nshared &= ~BLK_PERM_WRITE; + *nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); } } @@ -192,11 +194,13 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, { Error *local_err = NULL; BDRVBackupTopState *state; - BlockDriverState *top = bdrv_new_open_driver(&bdrv_backup_top_filter, - filter_node_name, - BDRV_O_RDWR, errp); + BlockDriverState *top; bool appended = false; + assert(source->total_sectors == target->total_sectors); + + top = bdrv_new_open_driver(&bdrv_backup_top_filter, filter_node_name, + BDRV_O_RDWR, errp); if (!top) { return NULL; } diff --git a/block/backup.c b/block/backup.c index c4c3b8cd46..4f13bb20a5 100644 --- a/block/backup.c +++ b/block/backup.c @@ -340,7 +340,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, BlockCompletionFunc *cb, void *opaque, JobTxn *txn, Error **errp) { - int64_t len; + int64_t len, target_len; BackupBlockJob *job = NULL; int64_t cluster_size; BdrvRequestFlags write_flags; @@ -405,6 +405,18 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, goto error; } + target_len = bdrv_getlength(target); + if (target_len < 0) { + error_setg_errno(errp, -target_len, "Unable to get length for '%s'", + bdrv_get_device_or_node_name(bs)); + goto error; + } + + if (target_len != len) { + error_setg(errp, "Source and target image have different sizes"); + goto error; + } + cluster_size = backup_calculate_cluster_size(target, errp); if (cluster_size < 0) { goto error; From 0a82a9273062d05764e3df3637b3aa95ad8291c6 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 30 Apr 2020 16:27:55 +0200 Subject: [PATCH 0347/2595] iotests: Backup with different source/target size This tests that the backup job catches situations where the target node has a different size than the source node. It must also forbid resize operations when the job is already running. Signed-off-by: Kevin Wolf Message-Id: <20200430142755.315494-5-kwolf@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- tests/qemu-iotests/055 | 41 ++++++++++++++++++++++++++++++++++++-- tests/qemu-iotests/055.out | 4 ++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index e250f798f9..7f8e630de3 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -48,8 +48,10 @@ class TestSingleDrive(iotests.QMPTestCase): def setUp(self): qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len)) - self.vm = iotests.VM().add_drive('blkdebug::' + test_img) - self.vm.add_drive(blockdev_target_img, interface="none") + self.vm = iotests.VM() + self.vm.add_drive('blkdebug::' + test_img, 'node-name=source') + self.vm.add_drive(blockdev_target_img, 'node-name=target', + interface="none") if iotests.qemu_default_machine == 'pc': self.vm.add_drive(None, 'media=cdrom', 'ide') self.vm.launch() @@ -112,6 +114,41 @@ class TestSingleDrive(iotests.QMPTestCase): def test_pause_blockdev_backup(self): self.do_test_pause('blockdev-backup', 'drive1', blockdev_target_img) + def do_test_resize_blockdev_backup(self, device, node): + def pre_finalize(): + result = self.vm.qmp('block_resize', device=device, size=65536) + self.assert_qmp(result, 'error/class', 'GenericError') + + result = self.vm.qmp('block_resize', node_name=node, size=65536) + self.assert_qmp(result, 'error/class', 'GenericError') + + result = self.vm.qmp('blockdev-backup', job_id='job0', device='drive0', + target='drive1', sync='full', auto_finalize=False, + auto_dismiss=False) + self.assert_qmp(result, 'return', {}) + + self.vm.run_job('job0', auto_finalize=False, pre_finalize=pre_finalize) + + def test_source_resize_blockdev_backup(self): + self.do_test_resize_blockdev_backup('drive0', 'source') + + def test_target_resize_blockdev_backup(self): + self.do_test_resize_blockdev_backup('drive1', 'target') + + def do_test_target_size(self, size): + result = self.vm.qmp('block_resize', device='drive1', size=size) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('blockdev-backup', job_id='job0', device='drive0', + target='drive1', sync='full') + self.assert_qmp(result, 'error/class', 'GenericError') + + def test_small_target(self): + self.do_test_target_size(image_len // 2) + + def test_large_target(self): + self.do_test_target_size(image_len * 2) + def test_medium_not_found(self): if iotests.qemu_default_machine != 'pc': return diff --git a/tests/qemu-iotests/055.out b/tests/qemu-iotests/055.out index 5c26d15c0d..0a5e9583a4 100644 --- a/tests/qemu-iotests/055.out +++ b/tests/qemu-iotests/055.out @@ -1,5 +1,5 @@ -.................................... +........................................ ---------------------------------------------------------------------- -Ran 36 tests +Ran 40 tests OK From 6a9d73bdd061d9eb7001d38147f73f4b6987f00b Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 5 May 2020 08:46:18 +0200 Subject: [PATCH 0348/2595] iotests/055: Use cache.no-flush for vmdk target 055 uses the backup block job to create a compressed backup of an $IMGFMT image with both qcow2 and vmdk targets. However, cluster allocation in vmdk is very slow because it flushes the image file after each L2 update. There is no reason why we need this level of safety in this test, so let's disable flushes for vmdk. For the blockdev-backup tests this is achieved by simply adding the cache.no-flush=on to the drive_add() for the target. For drive-backup, the caching flags are copied from the source node, so we'll also add the flag to the source node, even though it is not vmdk. This can make the test run significantly faster (though it doesn't make a difference on tmpfs). In my usual setup it goes from ~45s to ~15s. Signed-off-by: Kevin Wolf Message-Id: <20200505064618.16267-1-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- tests/qemu-iotests/055 | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index 7f8e630de3..4d3744b0d3 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -489,7 +489,7 @@ class TestSingleTransaction(iotests.QMPTestCase): class TestCompressedToQcow2(iotests.QMPTestCase): image_len = 64 * 1024 * 1024 # MB - target_fmt = {'type': 'qcow2', 'args': ()} + target_fmt = {'type': 'qcow2', 'args': (), 'drive-opts': ''} def tearDown(self): self.vm.shutdown() @@ -500,14 +500,16 @@ class TestCompressedToQcow2(iotests.QMPTestCase): pass def do_prepare_drives(self, attach_target): - self.vm = iotests.VM().add_drive('blkdebug::' + test_img) + self.vm = iotests.VM().add_drive('blkdebug::' + test_img, + opts=self.target_fmt['drive-opts']) qemu_img('create', '-f', self.target_fmt['type'], blockdev_target_img, str(self.image_len), *self.target_fmt['args']) if attach_target: self.vm.add_drive(blockdev_target_img, img_format=self.target_fmt['type'], - interface="none") + interface="none", + opts=self.target_fmt['drive-opts']) self.vm.launch() @@ -601,7 +603,8 @@ class TestCompressedToQcow2(iotests.QMPTestCase): class TestCompressedToVmdk(TestCompressedToQcow2): - target_fmt = {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized')} + target_fmt = {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized'), + 'drive-opts': 'cache.no-flush=on'} @iotests.skip_if_unsupported(['vmdk']) def setUp(self): From 4b96fa3846f001981ef6f33673cdb65f619b2997 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 5 May 2020 16:18:01 +0200 Subject: [PATCH 0349/2595] qcow2: Fix preallocation on block devices Calling bdrv_getlength() to get the pre-truncate file size will not really work on block devices, because they have always the same length, and trying to write beyond it will fail with a rather cryptic error message. Instead, we should use qcow2_get_last_cluster() and bdrv_getlength() only as a fallback. Before this patch: $ truncate -s 1G test.img $ sudo losetup -f --show test.img /dev/loop0 $ sudo qemu-img create -f qcow2 -o preallocation=full /dev/loop0 64M Formatting '/dev/loop0', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=full lazy_refcounts=off refcount_bits=16 qemu-img: /dev/loop0: Could not resize image: Failed to resize refcount structures: No space left on device With this patch: $ sudo qemu-img create -f qcow2 -o preallocation=full /dev/loop0 64M Formatting '/dev/loop0', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=full lazy_refcounts=off refcount_bits=16 qemu-img: /dev/loop0: Could not resize image: Failed to resize underlying file: Preallocation mode 'full' unsupported for this non-regular file So as you can see, it still fails, but now the problem is missing support on the block device level, so we at least get a better error message. Note that we cannot preallocate block devices on truncate by design, because we do not know what area to preallocate. Their length is always the same, the truncate operation does not change it. Signed-off-by: Max Reitz Message-Id: <20200505141801.1096763-1-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block/qcow2.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index fc7d4b185e..11903fb547 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -4107,7 +4107,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, { int64_t allocation_start, host_offset, guest_offset; int64_t clusters_allocated; - int64_t old_file_size, new_file_size; + int64_t old_file_size, last_cluster, new_file_size; uint64_t nb_new_data_clusters, nb_new_l2_tables; /* With a data file, preallocation means just allocating the metadata @@ -4127,7 +4127,13 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, ret = old_file_size; goto fail; } - old_file_size = ROUND_UP(old_file_size, s->cluster_size); + + last_cluster = qcow2_get_last_cluster(bs, old_file_size); + if (last_cluster >= 0) { + old_file_size = (last_cluster + 1) * s->cluster_size; + } else { + old_file_size = ROUND_UP(old_file_size, s->cluster_size); + } nb_new_data_clusters = DIV_ROUND_UP(offset - old_length, s->cluster_size); From 5e09bcee5ba2c69f79d59513436fc92db49ec302 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 15:28:57 -0500 Subject: [PATCH 0350/2595] gluster: Drop useless has_zero_init callback block.c already defaults to 0 if we don't provide a callback; there's no need to write a callback that always fails. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Message-Id: <20200428202905.770727-2-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block/gluster.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/block/gluster.c b/block/gluster.c index d06df900f6..31233cac69 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1359,12 +1359,6 @@ static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs) } } -static int qemu_gluster_has_zero_init(BlockDriverState *bs) -{ - /* GlusterFS volume could be backed by a block device */ - return 0; -} - /* * Find allocation range in @bs around offset @start. * May change underlying file descriptor's file offset. @@ -1569,8 +1563,6 @@ static BlockDriver bdrv_gluster = { .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, - .bdrv_has_zero_init = qemu_gluster_has_zero_init, - .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init, #ifdef CONFIG_GLUSTERFS_DISCARD .bdrv_co_pdiscard = qemu_gluster_co_pdiscard, #endif @@ -1601,8 +1593,6 @@ static BlockDriver bdrv_gluster_tcp = { .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, - .bdrv_has_zero_init = qemu_gluster_has_zero_init, - .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init, #ifdef CONFIG_GLUSTERFS_DISCARD .bdrv_co_pdiscard = qemu_gluster_co_pdiscard, #endif @@ -1633,8 +1623,6 @@ static BlockDriver bdrv_gluster_unix = { .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, - .bdrv_has_zero_init = qemu_gluster_has_zero_init, - .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init, #ifdef CONFIG_GLUSTERFS_DISCARD .bdrv_co_pdiscard = qemu_gluster_co_pdiscard, #endif @@ -1671,8 +1659,6 @@ static BlockDriver bdrv_gluster_rdma = { .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, - .bdrv_has_zero_init = qemu_gluster_has_zero_init, - .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init, #ifdef CONFIG_GLUSTERFS_DISCARD .bdrv_co_pdiscard = qemu_gluster_co_pdiscard, #endif From 8e519795041e3293ab6b4e67f5416fa80dc0efc4 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 15:28:58 -0500 Subject: [PATCH 0351/2595] file-win32: Support BDRV_REQ_ZERO_WRITE for truncate When using bdrv_file, .bdrv_has_zero_init_truncate always returns 1; therefore, we can behave just like file-posix, and always implement BDRV_REQ_ZERO_WRITE by ignoring it since the OS gives it to us for free (note that file-posix.c had to use an 'if' because it shared code between regular files and block devices, but in file-win32.c, bdrv_host_device uses a separate .bdrv_file_open). Signed-off-by: Eric Blake Message-Id: <20200428202905.770727-3-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block/file-win32.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block/file-win32.c b/block/file-win32.c index a6b0dda5c3..fa569685d8 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -408,6 +408,9 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, win32_aio_attach_aio_context(s->aio, bdrv_get_aio_context(bs)); } + /* When extending regular files, we get zeros from the OS */ + bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; + ret = 0; fail: qemu_opts_del(opts); From 8f23aaf5d6a5458e251c5d5d0555d9e515355e35 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 15:28:59 -0500 Subject: [PATCH 0352/2595] nfs: Support BDRV_REQ_ZERO_WRITE for truncate Our .bdrv_has_zero_init_truncate returns 1 if we detect that the OS always 0-fills; we can use that same knowledge to implement BDRV_REQ_ZERO_WRITE by ignoring it when the OS gives it to us for free. Signed-off-by: Eric Blake Message-Id: <20200428202905.770727-4-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block/nfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block/nfs.c b/block/nfs.c index 385d756e1d..76daa7c9f6 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -620,6 +620,9 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags, } bs->total_sectors = ret; + if (client->has_zero_init) { + bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; + } return 0; } From 2f98910d5b89733b1a5df06c6d2a7056da32a7b7 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 15:29:00 -0500 Subject: [PATCH 0353/2595] rbd: Support BDRV_REQ_ZERO_WRITE for truncate Our .bdrv_has_zero_init_truncate always returns 1 because rbd always 0-fills; we can use that same knowledge to implement BDRV_REQ_ZERO_WRITE by ignoring it. Signed-off-by: Eric Blake Message-Id: <20200428202905.770727-5-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block/rbd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block/rbd.c b/block/rbd.c index f2d52091c7..331c45adb2 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -817,6 +817,9 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, } } + /* When extending regular files, we get zeros from the OS */ + bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; + r = 0; goto out; From fec00559e71c94749deac176f6c4bebf81fbe7b8 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 15:29:01 -0500 Subject: [PATCH 0354/2595] sheepdog: Support BDRV_REQ_ZERO_WRITE for truncate Our .bdrv_has_zero_init_truncate always returns 1 because sheepdog always 0-fills; we can use that same knowledge to implement BDRV_REQ_ZERO_WRITE by ignoring it. Signed-off-by: Eric Blake Message-Id: <20200428202905.770727-6-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block/sheepdog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/sheepdog.c b/block/sheepdog.c index 2eb61938ff..739e6dee30 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1654,6 +1654,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags, memcpy(&s->inode, buf, sizeof(s->inode)); bs->total_sectors = s->inode.vdi_size / BDRV_SECTOR_SIZE; + bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; pstrcpy(s->name, sizeof(s->name), vdi); qemu_co_mutex_init(&s->lock); qemu_co_mutex_init(&s->queue_lock); From be9c9404db7e6992946fa55c75ca61dfb20926eb Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 15:29:02 -0500 Subject: [PATCH 0355/2595] ssh: Support BDRV_REQ_ZERO_WRITE for truncate Our .bdrv_has_zero_init_truncate can detect when the remote side always zero fills; we can reuse that same knowledge to implement BDRV_REQ_ZERO_WRITE by ignoring it when the server gives it to us for free. Signed-off-by: Eric Blake Message-Id: <20200428202905.770727-7-eblake@redhat.com> Reviewed-by: Richard W.M. Jones Signed-off-by: Kevin Wolf --- block/ssh.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block/ssh.c b/block/ssh.c index 9eb33df859..f9e08a4900 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -883,6 +883,10 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags, /* Go non-blocking. */ ssh_set_blocking(s->session, 0); + if (s->attrs->type == SSH_FILEXFER_TYPE_REGULAR) { + bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; + } + qapi_free_BlockdevOptionsSsh(opts); return 0; From bda4cdcbb997d34762e2af27e1f475357a9b4453 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 15:29:03 -0500 Subject: [PATCH 0356/2595] parallels: Rework truncation logic The parallels driver tries to use truncation for image growth, but can only do so when reads are guaranteed as zero. Now that we have a way to request zero contents from truncation, we can defer the decision to actual allocation attempts rather than up front, reducing the number of places that still use bdrv_has_zero_init_truncate. Signed-off-by: Eric Blake Message-Id: <20200428202905.770727-8-eblake@redhat.com> Reviewed-by: Denis V. Lunev Signed-off-by: Kevin Wolf --- block/parallels.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/block/parallels.c b/block/parallels.c index 8db64a55e3..e7717c508e 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -166,7 +166,7 @@ static int64_t block_status(BDRVParallelsState *s, int64_t sector_num, static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { - int ret; + int ret = 0; BDRVParallelsState *s = bs->opaque; int64_t pos, space, idx, to_allocate, i, len; @@ -196,14 +196,24 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, } if (s->data_end + space > (len >> BDRV_SECTOR_BITS)) { space += s->prealloc_size; + /* + * We require the expanded size to read back as zero. If the + * user permitted truncation, we try that; but if it fails, we + * force the safer-but-slower fallocate. + */ + if (s->prealloc_mode == PRL_PREALLOC_MODE_TRUNCATE) { + ret = bdrv_truncate(bs->file, + (s->data_end + space) << BDRV_SECTOR_BITS, + false, PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE, + NULL); + if (ret == -ENOTSUP) { + s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE; + } + } if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) { ret = bdrv_pwrite_zeroes(bs->file, s->data_end << BDRV_SECTOR_BITS, space << BDRV_SECTOR_BITS, 0); - } else { - ret = bdrv_truncate(bs->file, - (s->data_end + space) << BDRV_SECTOR_BITS, - false, PREALLOC_MODE_OFF, 0, NULL); } if (ret < 0) { return ret; @@ -828,6 +838,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, qemu_opt_get_size_del(opts, PARALLELS_OPT_PREALLOC_SIZE, 0); s->prealloc_size = MAX(s->tracks, s->prealloc_size >> BDRV_SECTOR_BITS); buf = qemu_opt_get_del(opts, PARALLELS_OPT_PREALLOC_MODE); + /* prealloc_mode can be downgraded later during allocate_clusters */ s->prealloc_mode = qapi_enum_parse(&prealloc_mode_lookup, buf, PRL_PREALLOC_MODE_FALLOCATE, &local_err); @@ -836,10 +847,6 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, goto fail_options; } - if (!bdrv_has_zero_init_truncate(bs->file->bs)) { - s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE; - } - if ((flags & BDRV_O_RDWR) && !(flags & BDRV_O_INACTIVE)) { s->header->inuse = cpu_to_le32(HEADER_INUSE_MAGIC); ret = parallels_update_header(bs); From dbc636e791ad04b6bcdec982d2b9c45d7182e037 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 15:29:04 -0500 Subject: [PATCH 0357/2595] vhdx: Rework truncation logic The vhdx driver uses truncation for image growth, with a special case for blocks that already read as zero but which are only being partially written. But with a bit of rearranging, it's just as easy to defer the decision on whether truncation resulted in zeroes to the actual allocation attempt, reducing the number of places that still use bdrv_has_zero_init_truncate. Signed-off-by: Eric Blake Message-Id: <20200428202905.770727-9-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block/vhdx.c | 89 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 38 deletions(-) diff --git a/block/vhdx.c b/block/vhdx.c index e11fb7413a..53e756438a 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1240,12 +1240,16 @@ exit: /* * Allocate a new payload block at the end of the file. * - * Allocation will happen at 1MB alignment inside the file + * Allocation will happen at 1MB alignment inside the file. + * + * If @need_zero is set on entry but not cleared on return, then truncation + * could not guarantee that the new portion reads as zero, and the caller + * will take care of it instead. * * Returns the file offset start of the new payload block */ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s, - uint64_t *new_offset) + uint64_t *new_offset, bool *need_zero) { int64_t current_len; @@ -1262,6 +1266,17 @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s, return -EINVAL; } + if (*need_zero) { + int ret; + + ret = bdrv_truncate(bs->file, *new_offset + s->block_size, false, + PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE, NULL); + if (ret != -ENOTSUP) { + *need_zero = false; + return ret; + } + } + return bdrv_truncate(bs->file, *new_offset + s->block_size, false, PREALLOC_MODE_OFF, 0, NULL); } @@ -1355,18 +1370,38 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, /* in this case, we need to preserve zero writes for * data that is not part of this write, so we must pad * the rest of the buffer to zeroes */ - - /* if we are on a posix system with ftruncate() that extends - * a file, then it is zero-filled for us. On Win32, the raw - * layer uses SetFilePointer and SetFileEnd, which does not - * zero fill AFAIK */ - - /* Queue another write of zero buffers if the underlying file - * does not zero-fill on file extension */ - - if (bdrv_has_zero_init_truncate(bs->file->bs) == 0) { - use_zero_buffers = true; - + use_zero_buffers = true; + /* fall through */ + case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */ + case PAYLOAD_BLOCK_UNMAPPED: + case PAYLOAD_BLOCK_UNMAPPED_v095: + case PAYLOAD_BLOCK_UNDEFINED: + bat_prior_offset = sinfo.file_offset; + ret = vhdx_allocate_block(bs, s, &sinfo.file_offset, + &use_zero_buffers); + if (ret < 0) { + goto exit; + } + /* + * once we support differencing files, this may also be + * partially present + */ + /* update block state to the newly specified state */ + vhdx_update_bat_table_entry(bs, s, &sinfo, &bat_entry, + &bat_entry_offset, + PAYLOAD_BLOCK_FULLY_PRESENT); + bat_update = true; + /* + * Since we just allocated a block, file_offset is the + * beginning of the payload block. It needs to be the + * write address, which includes the offset into the + * block, unless the entire block needs to read as + * zeroes but truncation was not able to provide them, + * in which case we need to fill in the rest. + */ + if (!use_zero_buffers) { + sinfo.file_offset += sinfo.block_offset; + } else { /* zero fill the front, if any */ if (sinfo.block_offset) { iov1.iov_len = sinfo.block_offset; @@ -1378,7 +1413,7 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, } /* our actual data */ - qemu_iovec_concat(&hd_qiov, qiov, bytes_done, + qemu_iovec_concat(&hd_qiov, qiov, bytes_done, sinfo.bytes_avail); /* zero fill the back, if any */ @@ -1393,29 +1428,7 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, sectors_to_write += iov2.iov_len >> BDRV_SECTOR_BITS; } } - /* fall through */ - case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */ - case PAYLOAD_BLOCK_UNMAPPED: - case PAYLOAD_BLOCK_UNMAPPED_v095: - case PAYLOAD_BLOCK_UNDEFINED: - bat_prior_offset = sinfo.file_offset; - ret = vhdx_allocate_block(bs, s, &sinfo.file_offset); - if (ret < 0) { - goto exit; - } - /* once we support differencing files, this may also be - * partially present */ - /* update block state to the newly specified state */ - vhdx_update_bat_table_entry(bs, s, &sinfo, &bat_entry, - &bat_entry_offset, - PAYLOAD_BLOCK_FULLY_PRESENT); - bat_update = true; - /* since we just allocated a block, file_offset is the - * beginning of the payload block. It needs to be the - * write address, which includes the offset into the block */ - if (!use_zero_buffers) { - sinfo.file_offset += sinfo.block_offset; - } + /* fall through */ case PAYLOAD_BLOCK_FULLY_PRESENT: /* if the file offset address is in the header zone, From 47e0b38a13935cb666f88964c3096654092f42d6 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 28 Apr 2020 15:29:05 -0500 Subject: [PATCH 0358/2595] block: Drop unused .bdrv_has_zero_init_truncate Now that there are no clients of bdrv_has_zero_init_truncate, none of the drivers need to worry about providing it. What's more, this eliminates a source of some confusion: a literal reading of the documentation as written in ceaca56f and implemented in commit 1dcaf527 claims that a driver which returns 0 for bdrv_has_zero_init_truncate() must not return 1 for bdrv_has_zero_init(); this condition was violated for parallels, qcow, and sometimes for vdi, although in practice it did not matter since those drivers also lacked .bdrv_co_truncate. Signed-off-by: Eric Blake Message-Id: <20200428202905.770727-10-eblake@redhat.com> Acked-by: Richard W.M. Jones Signed-off-by: Kevin Wolf --- block.c | 21 --------------------- block/file-posix.c | 1 - block/file-win32.c | 1 - block/nfs.c | 1 - block/qcow2.c | 1 - block/qed.c | 1 - block/raw-format.c | 6 ------ block/rbd.c | 1 - block/sheepdog.c | 3 --- block/ssh.c | 1 - include/block/block.h | 1 - include/block/block_int.h | 7 ------- 12 files changed, 45 deletions(-) diff --git a/block.c b/block.c index cf5c19b1db..0653ccb913 100644 --- a/block.c +++ b/block.c @@ -5284,27 +5284,6 @@ int bdrv_has_zero_init(BlockDriverState *bs) return 0; } -int bdrv_has_zero_init_truncate(BlockDriverState *bs) -{ - if (!bs->drv) { - return 0; - } - - if (bs->backing) { - /* Depends on the backing image length, but better safe than sorry */ - return 0; - } - if (bs->drv->bdrv_has_zero_init_truncate) { - return bs->drv->bdrv_has_zero_init_truncate(bs); - } - if (bs->file && bs->drv->is_filter) { - return bdrv_has_zero_init_truncate(bs->file->bs); - } - - /* safe default */ - return 0; -} - bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs) { BlockDriverInfo bdi; diff --git a/block/file-posix.c b/block/file-posix.c index 05e094be29..3ab8f5a0fa 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -3100,7 +3100,6 @@ BlockDriver bdrv_file = { .bdrv_co_create = raw_co_create, .bdrv_co_create_opts = raw_co_create_opts, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1, .bdrv_co_block_status = raw_co_block_status, .bdrv_co_invalidate_cache = raw_co_invalidate_cache, .bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes, diff --git a/block/file-win32.c b/block/file-win32.c index fa569685d8..221aaf713e 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -641,7 +641,6 @@ BlockDriver bdrv_file = { .bdrv_close = raw_close, .bdrv_co_create_opts = raw_co_create_opts, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1, .bdrv_aio_preadv = raw_aio_preadv, .bdrv_aio_pwritev = raw_aio_pwritev, diff --git a/block/nfs.c b/block/nfs.c index 76daa7c9f6..b1718d125a 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -872,7 +872,6 @@ static BlockDriver bdrv_nfs = { .create_opts = &nfs_create_opts, .bdrv_has_zero_init = nfs_has_zero_init, - .bdrv_has_zero_init_truncate = nfs_has_zero_init, .bdrv_get_allocated_file_size = nfs_get_allocated_file_size, .bdrv_co_truncate = nfs_file_co_truncate, diff --git a/block/qcow2.c b/block/qcow2.c index 11903fb547..1ad95ff048 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5621,7 +5621,6 @@ BlockDriver bdrv_qcow2 = { .bdrv_co_create_opts = qcow2_co_create_opts, .bdrv_co_create = qcow2_co_create, .bdrv_has_zero_init = qcow2_has_zero_init, - .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1, .bdrv_co_block_status = qcow2_co_block_status, .bdrv_co_preadv_part = qcow2_co_preadv_part, diff --git a/block/qed.c b/block/qed.c index fb609cfba1..5da9726518 100644 --- a/block/qed.c +++ b/block/qed.c @@ -1675,7 +1675,6 @@ static BlockDriver bdrv_qed = { .bdrv_co_create = bdrv_qed_co_create, .bdrv_co_create_opts = bdrv_qed_co_create_opts, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1, .bdrv_co_block_status = bdrv_qed_co_block_status, .bdrv_co_readv = bdrv_qed_co_readv, .bdrv_co_writev = bdrv_qed_co_writev, diff --git a/block/raw-format.c b/block/raw-format.c index 351f2d91c6..9108e43696 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -414,11 +414,6 @@ static int raw_has_zero_init(BlockDriverState *bs) return bdrv_has_zero_init(bs->file->bs); } -static int raw_has_zero_init_truncate(BlockDriverState *bs) -{ - return bdrv_has_zero_init_truncate(bs->file->bs); -} - static int coroutine_fn raw_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts, @@ -582,7 +577,6 @@ BlockDriver bdrv_raw = { .bdrv_co_ioctl = &raw_co_ioctl, .create_opts = &raw_create_opts, .bdrv_has_zero_init = &raw_has_zero_init, - .bdrv_has_zero_init_truncate = &raw_has_zero_init_truncate, .strong_runtime_opts = raw_strong_runtime_opts, .mutable_opts = mutable_opts, }; diff --git a/block/rbd.c b/block/rbd.c index 331c45adb2..617553b022 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1313,7 +1313,6 @@ static BlockDriver bdrv_rbd = { .bdrv_co_create = qemu_rbd_co_create, .bdrv_co_create_opts = qemu_rbd_co_create_opts, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1, .bdrv_get_info = qemu_rbd_getinfo, .create_opts = &qemu_rbd_create_opts, .bdrv_getlength = qemu_rbd_getlength, diff --git a/block/sheepdog.c b/block/sheepdog.c index 739e6dee30..27a30d17f4 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -3226,7 +3226,6 @@ static BlockDriver bdrv_sheepdog = { .bdrv_co_create = sd_co_create, .bdrv_co_create_opts = sd_co_create_opts, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1, .bdrv_getlength = sd_getlength, .bdrv_get_allocated_file_size = sd_get_allocated_file_size, .bdrv_co_truncate = sd_co_truncate, @@ -3265,7 +3264,6 @@ static BlockDriver bdrv_sheepdog_tcp = { .bdrv_co_create = sd_co_create, .bdrv_co_create_opts = sd_co_create_opts, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1, .bdrv_getlength = sd_getlength, .bdrv_get_allocated_file_size = sd_get_allocated_file_size, .bdrv_co_truncate = sd_co_truncate, @@ -3304,7 +3302,6 @@ static BlockDriver bdrv_sheepdog_unix = { .bdrv_co_create = sd_co_create, .bdrv_co_create_opts = sd_co_create_opts, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1, .bdrv_getlength = sd_getlength, .bdrv_get_allocated_file_size = sd_get_allocated_file_size, .bdrv_co_truncate = sd_co_truncate, diff --git a/block/ssh.c b/block/ssh.c index f9e08a4900..098dbe03c1 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -1397,7 +1397,6 @@ static BlockDriver bdrv_ssh = { .bdrv_co_create_opts = ssh_co_create_opts, .bdrv_close = ssh_close, .bdrv_has_zero_init = ssh_has_zero_init, - .bdrv_has_zero_init_truncate = ssh_has_zero_init, .bdrv_co_readv = ssh_co_readv, .bdrv_co_writev = ssh_co_writev, .bdrv_getlength = ssh_getlength, diff --git a/include/block/block.h b/include/block/block.h index 8b62429aa4..4de8d8f8a6 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -430,7 +430,6 @@ int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes); int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes); int bdrv_has_zero_init_1(BlockDriverState *bs); int bdrv_has_zero_init(BlockDriverState *bs); -int bdrv_has_zero_init_truncate(BlockDriverState *bs); bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs); bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); int bdrv_block_status(BlockDriverState *bs, int64_t offset, diff --git a/include/block/block_int.h b/include/block/block_int.h index 92335f33c7..df6d0273d6 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -449,16 +449,9 @@ struct BlockDriver { /* * Returns 1 if newly created images are guaranteed to contain only * zeros, 0 otherwise. - * Must return 0 if .bdrv_has_zero_init_truncate() returns 0. */ int (*bdrv_has_zero_init)(BlockDriverState *bs); - /* - * Returns 1 if new areas added by growing the image with - * PREALLOC_MODE_OFF contain only zeros, 0 otherwise. - */ - int (*bdrv_has_zero_init_truncate)(BlockDriverState *bs); - /* Remove fd handlers, timers, and other event loop callbacks so the event * loop is no longer in use. Called with no in-flight requests and in * depth-first traversal order with parents before child nodes. From 9bb6d14081ce0859480168b1c322b6a88706161e Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Thu, 9 Apr 2020 16:01:37 +0930 Subject: [PATCH 0359/2595] aspeed: Add boot stub for smp booting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a boot stub that is similar to the code u-boot runs, allowing the kernel to boot the secondary CPU. u-boot works as follows: 1. Initialises the SMP mailbox area in the SCU at 0x1e6e2180 with default values 2. Copies a stub named 'mailbox_insn' from flash to the SCU, just above the mailbox area 3. Sets AST_SMP_MBOX_FIELD_READY to a magic value to indicate the secondary can begin execution from the stub 4. The stub waits until the AST_SMP_MBOX_FIELD_GOSIGN register is set to a magic value 5. Jumps to the address in AST_SMP_MBOX_FIELD_ENTRY, starting Linux Linux indicates it is ready by writing the address of its entrypoint function to AST_SMP_MBOX_FIELD_ENTRY and the 'go' magic number to AST_SMP_MBOX_FIELD_GOSIGN. The secondary CPU sees this at step 4 and breaks out of it's loop. To be compatible, a fixed qemu stub is loaded into the mailbox area. As qemu can ensure the stub is loaded before execution starts, we do not need to emulate the AST_SMP_MBOX_FIELD_READY behaviour of u-boot. The secondary CPU's program counter points to the beginning of the stub, allowing qemu to start secondaries at step four. Reboot behaviour is preserved by resetting AST_SMP_MBOX_FIELD_GOSIGN when the secondaries are reset. This is only configured when the system is booted with -kernel and qemu does not execute u-boot first. Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Signed-off-by: Joel Stanley Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index a6a2102a93..a3a8cd0a58 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -116,6 +116,58 @@ static const MemoryRegionOps max_ram_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +#define AST_SMP_MAILBOX_BASE 0x1e6e2180 +#define AST_SMP_MBOX_FIELD_ENTRY (AST_SMP_MAILBOX_BASE + 0x0) +#define AST_SMP_MBOX_FIELD_GOSIGN (AST_SMP_MAILBOX_BASE + 0x4) +#define AST_SMP_MBOX_FIELD_READY (AST_SMP_MAILBOX_BASE + 0x8) +#define AST_SMP_MBOX_FIELD_POLLINSN (AST_SMP_MAILBOX_BASE + 0xc) +#define AST_SMP_MBOX_CODE (AST_SMP_MAILBOX_BASE + 0x10) +#define AST_SMP_MBOX_GOSIGN 0xabbaab00 + +static void aspeed_write_smpboot(ARMCPU *cpu, + const struct arm_boot_info *info) +{ + static const uint32_t poll_mailbox_ready[] = { + /* + * r2 = per-cpu go sign value + * r1 = AST_SMP_MBOX_FIELD_ENTRY + * r0 = AST_SMP_MBOX_FIELD_GOSIGN + */ + 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 */ + 0xe21000ff, /* ands r0, r0, #255 */ + 0xe59f201c, /* ldr r2, [pc, #28] */ + 0xe1822000, /* orr r2, r2, r0 */ + + 0xe59f1018, /* ldr r1, [pc, #24] */ + 0xe59f0018, /* ldr r0, [pc, #24] */ + + 0xe320f002, /* wfe */ + 0xe5904000, /* ldr r4, [r0] */ + 0xe1520004, /* cmp r2, r4 */ + 0x1afffffb, /* bne */ + 0xe591f000, /* ldr pc, [r1] */ + AST_SMP_MBOX_GOSIGN, + AST_SMP_MBOX_FIELD_ENTRY, + AST_SMP_MBOX_FIELD_GOSIGN, + }; + + rom_add_blob_fixed("aspeed.smpboot", poll_mailbox_ready, + sizeof(poll_mailbox_ready), + info->smp_loader_start); +} + +static void aspeed_reset_secondary(ARMCPU *cpu, + const struct arm_boot_info *info) +{ + AddressSpace *as = arm_boot_address_space(cpu, info); + CPUState *cs = CPU(cpu); + + /* info->smp_bootreg_addr */ + address_space_stl_notdirty(as, AST_SMP_MBOX_FIELD_GOSIGN, 0, + MEMTXATTRS_UNSPECIFIED, NULL); + cpu_set_pc(cs, info->smp_loader_start); +} + #define FIRMWARE_ADDR 0x0 static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size, @@ -270,6 +322,19 @@ static void aspeed_machine_init(MachineState *machine) } } + if (machine->kernel_filename && bmc->soc.num_cpus > 1) { + /* With no u-boot we must set up a boot stub for the secondary CPU */ + MemoryRegion *smpboot = g_new(MemoryRegion, 1); + memory_region_init_ram(smpboot, OBJECT(bmc), "aspeed.smpboot", + 0x80, &error_abort); + memory_region_add_subregion(get_system_memory(), + AST_SMP_MAILBOX_BASE, smpboot); + + aspeed_board_binfo.write_secondary_boot = aspeed_write_smpboot; + aspeed_board_binfo.secondary_cpu_reset_hook = aspeed_reset_secondary; + aspeed_board_binfo.smp_loader_start = AST_SMP_MBOX_CODE; + } + aspeed_board_binfo.ram_size = ram_size; aspeed_board_binfo.loader_start = sc->memmap[ASPEED_SDRAM]; aspeed_board_binfo.nb_cpus = bmc->soc.num_cpus; From 93dd1e6140e2652347cfe7208591d4cd32762d08 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Tue, 5 May 2020 16:17:29 +0200 Subject: [PATCH 0360/2595] target/arm: Drop access_el3_aa32ns_aa64any() Calling access_el3_aa32ns() works for AArch32 only cores but it does not handle 32-bit EL2 on top of 64-bit EL3 for mixed 32/64-bit cores. Merge access_el3_aa32ns_aa64any() into access_el3_aa32ns() and only use the latter. Fixes: 68e9c2fe65 ("target-arm: Add VTCR_EL2") Reported-by: Laurent Desnogues Signed-off-by: Edgar E. Iglesias Message-id: 20200505141729.31930-2-edgar.iglesias@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index a94f650795..b88d27819d 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -503,35 +503,19 @@ void init_cpreg_list(ARMCPU *cpu) } /* - * Some registers are not accessible if EL3.NS=0 and EL3 is using AArch32 but - * they are accessible when EL3 is using AArch64 regardless of EL3.NS. - * - * access_el3_aa32ns: Used to check AArch32 register views. - * access_el3_aa32ns_aa64any: Used to check both AArch32/64 register views. + * Some registers are not accessible from AArch32 EL3 if SCR.NS == 0. */ static CPAccessResult access_el3_aa32ns(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { - bool secure = arm_is_secure_below_el3(env); - - assert(!arm_el_is_aa64(env, 3)); - if (secure) { + if (!is_a64(env) && arm_current_el(env) == 3 && + arm_is_secure_below_el3(env)) { return CP_ACCESS_TRAP_UNCATEGORIZED; } return CP_ACCESS_OK; } -static CPAccessResult access_el3_aa32ns_aa64any(CPUARMState *env, - const ARMCPRegInfo *ri, - bool isread) -{ - if (!arm_el_is_aa64(env, 3)) { - return access_el3_aa32ns(env, ri, isread); - } - return CP_ACCESS_OK; -} - /* Some secure-only AArch32 registers trap to EL3 if used from * Secure EL1 (but are just ordinary UNDEF in other non-EL3 contexts). * Note that an access from Secure EL1 can only happen if EL3 is AArch64. @@ -5147,7 +5131,7 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = { .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "VTCR_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2, - .access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any, + .access = PL2_RW, .accessfn = access_el3_aa32ns, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "VTTBR", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 6, .crm = 2, @@ -5195,7 +5179,7 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = { .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "HPFAR_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, - .access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any, + .access = PL2_RW, .accessfn = access_el3_aa32ns, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "HSTR_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3, @@ -7537,12 +7521,12 @@ void register_cp_regs_for_features(ARMCPU *cpu) ARMCPRegInfo vpidr_regs[] = { { .name = "VPIDR_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0, - .access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any, + .access = PL2_RW, .accessfn = access_el3_aa32ns, .type = ARM_CP_CONST, .resetvalue = cpu->midr, .fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) }, { .name = "VMPIDR_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, - .access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any, + .access = PL2_RW, .accessfn = access_el3_aa32ns, .type = ARM_CP_NO_RAW, .writefn = arm_cp_write_ignore, .readfn = mpidr_read }, REGINFO_SENTINEL From 7582591ae745f224a58fd9a36e3b9230fb03bfc2 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Mon, 4 May 2020 19:07:03 +0930 Subject: [PATCH 0361/2595] aspeed: Support AST2600A1 silicon revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are minimal differences from Qemu's point of view between the A0 and A1 silicon revisions. As the A1 exercises different code paths in u-boot it is desirable to emulate that instead. Signed-off-by: Joel Stanley Reviewed-by: Andrew Jeffery Reviewed-by: Cédric Le Goater Message-id: 20200504093703.261135-1-joel@jms.id.au Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 8 ++++---- hw/arm/aspeed_ast2600.c | 6 +++--- hw/misc/aspeed_scu.c | 11 +++++------ include/hw/misc/aspeed_scu.h | 1 + 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index a3a8cd0a58..1eacb2fc17 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -93,7 +93,7 @@ struct AspeedBoardState { /* Tacoma hardware value */ #define TACOMA_BMC_HW_STRAP1 0x00000000 -#define TACOMA_BMC_HW_STRAP2 0x00000000 +#define TACOMA_BMC_HW_STRAP2 0x00000040 /* * The max ram region is for firmwares that scan the address space @@ -585,7 +585,7 @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data) AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); mc->desc = "Aspeed AST2600 EVB (Cortex A7)"; - amc->soc_name = "ast2600-a0"; + amc->soc_name = "ast2600-a1"; amc->hw_strap1 = AST2600_EVB_HW_STRAP1; amc->hw_strap2 = AST2600_EVB_HW_STRAP2; amc->fmc_model = "w25q512jv"; @@ -600,8 +600,8 @@ static void aspeed_machine_tacoma_class_init(ObjectClass *oc, void *data) MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); - mc->desc = "Aspeed AST2600 EVB (Cortex A7)"; - amc->soc_name = "ast2600-a0"; + mc->desc = "OpenPOWER Tacoma BMC (Cortex A7)"; + amc->soc_name = "ast2600-a1"; amc->hw_strap1 = TACOMA_BMC_HW_STRAP1; amc->hw_strap2 = TACOMA_BMC_HW_STRAP2; amc->fmc_model = "mx66l1g45g"; diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 1a869e09b9..c6e0ab84ac 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -557,9 +557,9 @@ static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) dc->realize = aspeed_soc_ast2600_realize; - sc->name = "ast2600-a0"; + sc->name = "ast2600-a1"; sc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"); - sc->silicon_rev = AST2600_A0_SILICON_REV; + sc->silicon_rev = AST2600_A1_SILICON_REV; sc->sram_size = 0x10000; sc->spis_num = 2; sc->ehcis_num = 2; @@ -571,7 +571,7 @@ static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) } static const TypeInfo aspeed_soc_ast2600_type_info = { - .name = "ast2600-a0", + .name = "ast2600-a1", .parent = TYPE_ASPEED_SOC, .instance_size = sizeof(AspeedSoCState), .instance_init = aspeed_soc_ast2600_init, diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index 9d7482a9df..ec4fef900e 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -431,6 +431,7 @@ static uint32_t aspeed_silicon_revs[] = { AST2500_A0_SILICON_REV, AST2500_A1_SILICON_REV, AST2600_A0_SILICON_REV, + AST2600_A1_SILICON_REV, }; bool is_supported_silicon_rev(uint32_t silicon_rev) @@ -649,12 +650,10 @@ static const MemoryRegionOps aspeed_ast2600_scu_ops = { .valid.unaligned = false, }; -static const uint32_t ast2600_a0_resets[ASPEED_AST2600_SCU_NR_REGS] = { - [AST2600_SILICON_REV] = AST2600_SILICON_REV, - [AST2600_SILICON_REV2] = AST2600_SILICON_REV, - [AST2600_SYS_RST_CTRL] = 0xF7CFFEDC | 0x100, +static const uint32_t ast2600_a1_resets[ASPEED_AST2600_SCU_NR_REGS] = { + [AST2600_SYS_RST_CTRL] = 0xF7C3FED8, [AST2600_SYS_RST_CTRL2] = 0xFFFFFFFC, - [AST2600_CLK_STOP_CTRL] = 0xEFF43E8B, + [AST2600_CLK_STOP_CTRL] = 0xFFFF7F8A, [AST2600_CLK_STOP_CTRL2] = 0xFFF0FFF0, [AST2600_SDRAM_HANDSHAKE] = 0x00000040, /* SoC completed DRAM init */ [AST2600_HPLL_PARAM] = 0x1000405F, @@ -684,7 +683,7 @@ static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data) dc->desc = "ASPEED 2600 System Control Unit"; dc->reset = aspeed_ast2600_scu_reset; - asc->resets = ast2600_a0_resets; + asc->resets = ast2600_a1_resets; asc->calc_hpll = aspeed_2500_scu_calc_hpll; /* No change since AST2500 */ asc->apb_divider = 4; asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS; diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h index 1d7f7ffc15..a6739bb846 100644 --- a/include/hw/misc/aspeed_scu.h +++ b/include/hw/misc/aspeed_scu.h @@ -41,6 +41,7 @@ typedef struct AspeedSCUState { #define AST2500_A0_SILICON_REV 0x04000303U #define AST2500_A1_SILICON_REV 0x04010303U #define AST2600_A0_SILICON_REV 0x05000303U +#define AST2600_A1_SILICON_REV 0x05010303U #define ASPEED_IS_AST2500(si_rev) ((((si_rev) >> 24) & 0xff) == 0x04) From f4ab4f8e772700dcef1c99b75b0704bd5ca96b6a Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 5 May 2020 18:31:36 +0930 Subject: [PATCH 0362/2595] aspeed: sdmc: Implement AST2600 locking behaviour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2600 handles this differently with the extra 'hardlock' state, so move the testing to the soc specific class' write callback. Signed-off-by: Joel Stanley Reviewed-by: Cédric Le Goater Message-id: 20200505090136.341426-1-joel@jms.id.au Signed-off-by: Peter Maydell --- hw/misc/aspeed_sdmc.c | 55 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index 7b466bf19a..14db9cfc1f 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -23,7 +23,12 @@ /* Protection Key Register */ #define R_PROT (0x00 / 4) +#define PROT_UNLOCKED 0x01 +#define PROT_HARDLOCKED 0x10 /* AST2600 */ +#define PROT_SOFTLOCKED 0x00 + #define PROT_KEY_UNLOCK 0xFC600309 +#define PROT_KEY_HARDLOCK 0xDEADDEAD /* AST2600 */ /* Configuration Register */ #define R_CONF (0x04 / 4) @@ -130,16 +135,6 @@ static void aspeed_sdmc_write(void *opaque, hwaddr addr, uint64_t data, return; } - if (addr == R_PROT) { - s->regs[addr] = (data == PROT_KEY_UNLOCK) ? 1 : 0; - return; - } - - if (!s->regs[R_PROT]) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked!\n", __func__); - return; - } - asc->write(s, addr, data); } @@ -320,6 +315,16 @@ static uint32_t aspeed_2400_sdmc_compute_conf(AspeedSDMCState *s, uint32_t data) static void aspeed_2400_sdmc_write(AspeedSDMCState *s, uint32_t reg, uint32_t data) { + if (reg == R_PROT) { + s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED; + return; + } + + if (!s->regs[R_PROT]) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked!\n", __func__); + return; + } + switch (reg) { case R_CONF: data = aspeed_2400_sdmc_compute_conf(s, data); @@ -368,6 +373,16 @@ static uint32_t aspeed_2500_sdmc_compute_conf(AspeedSDMCState *s, uint32_t data) static void aspeed_2500_sdmc_write(AspeedSDMCState *s, uint32_t reg, uint32_t data) { + if (reg == R_PROT) { + s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED; + return; + } + + if (!s->regs[R_PROT]) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked!\n", __func__); + return; + } + switch (reg) { case R_CONF: data = aspeed_2500_sdmc_compute_conf(s, data); @@ -424,7 +439,27 @@ static uint32_t aspeed_2600_sdmc_compute_conf(AspeedSDMCState *s, uint32_t data) static void aspeed_2600_sdmc_write(AspeedSDMCState *s, uint32_t reg, uint32_t data) { + if (s->regs[R_PROT] == PROT_HARDLOCKED) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked until system reset!\n", + __func__); + return; + } + + if (reg != R_PROT && s->regs[R_PROT] == PROT_SOFTLOCKED) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked!\n", __func__); + return; + } + switch (reg) { + case R_PROT: + if (data == PROT_KEY_UNLOCK) { + data = PROT_UNLOCKED; + } else if (data == PROT_KEY_HARDLOCK) { + data = PROT_HARDLOCKED; + } else { + data = PROT_SOFTLOCKED; + } + break; case R_CONF: data = aspeed_2600_sdmc_compute_conf(s, data); break; From 54595a5731ed7c94491008b0d3835ad3f786dbcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 09:28:19 +0200 Subject: [PATCH 0363/2595] hw/arm/nrf51: Add NRF51_PERIPHERAL_SIZE definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the NRF51 series, all peripherals have a fixed I/O size of 4KiB. Define NRF51_PERIPHERAL_SIZE and use it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20200504072822.18799-2-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/nrf51_soc.c | 4 ++-- hw/i2c/microbit_i2c.c | 2 +- hw/timer/nrf51_timer.c | 2 +- include/hw/arm/nrf51.h | 3 +-- include/hw/i2c/microbit_i2c.h | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index 57eff63f0d..e50473fd19 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -156,7 +156,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) return; } - base_addr = NRF51_TIMER_BASE + i * NRF51_TIMER_SIZE; + base_addr = NRF51_TIMER_BASE + i * NRF51_PERIPHERAL_SIZE; sysbus_mmio_map(SYS_BUS_DEVICE(&s->timer[i]), 0, base_addr); sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer[i]), 0, @@ -166,7 +166,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) /* STUB Peripherals */ memory_region_init_io(&s->clock, OBJECT(dev_soc), &clock_ops, NULL, - "nrf51_soc.clock", 0x1000); + "nrf51_soc.clock", NRF51_PERIPHERAL_SIZE); memory_region_add_subregion_overlap(&s->container, NRF51_IOMEM_BASE, &s->clock, -1); diff --git a/hw/i2c/microbit_i2c.c b/hw/i2c/microbit_i2c.c index 4661f05253..8024739820 100644 --- a/hw/i2c/microbit_i2c.c +++ b/hw/i2c/microbit_i2c.c @@ -100,7 +100,7 @@ static void microbit_i2c_realize(DeviceState *dev, Error **errp) MicrobitI2CState *s = MICROBIT_I2C(dev); memory_region_init_io(&s->iomem, OBJECT(s), µbit_i2c_ops, s, - "microbit.twi", NRF51_TWI_SIZE); + "microbit.twi", NRF51_PERIPHERAL_SIZE); sysbus_init_mmio(sbd, &s->iomem); } diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c index e04046eb15..bc82c85a6f 100644 --- a/hw/timer/nrf51_timer.c +++ b/hw/timer/nrf51_timer.c @@ -313,7 +313,7 @@ static void nrf51_timer_init(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); memory_region_init_io(&s->iomem, obj, &rng_ops, s, - TYPE_NRF51_TIMER, NRF51_TIMER_SIZE); + TYPE_NRF51_TIMER, NRF51_PERIPHERAL_SIZE); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); diff --git a/include/hw/arm/nrf51.h b/include/hw/arm/nrf51.h index 1008fee6c9..de836beaa4 100644 --- a/include/hw/arm/nrf51.h +++ b/include/hw/arm/nrf51.h @@ -24,11 +24,10 @@ #define NRF51_IOMEM_BASE 0x40000000 #define NRF51_IOMEM_SIZE 0x20000000 +#define NRF51_PERIPHERAL_SIZE 0x00001000 #define NRF51_UART_BASE 0x40002000 #define NRF51_TWI_BASE 0x40003000 -#define NRF51_TWI_SIZE 0x00001000 #define NRF51_TIMER_BASE 0x40008000 -#define NRF51_TIMER_SIZE 0x00001000 #define NRF51_RNG_BASE 0x4000D000 #define NRF51_NVMC_BASE 0x4001E000 #define NRF51_GPIO_BASE 0x50000000 diff --git a/include/hw/i2c/microbit_i2c.h b/include/hw/i2c/microbit_i2c.h index aad636127e..2bff36680c 100644 --- a/include/hw/i2c/microbit_i2c.h +++ b/include/hw/i2c/microbit_i2c.h @@ -29,7 +29,7 @@ #define MICROBIT_I2C(obj) \ OBJECT_CHECK(MicrobitI2CState, (obj), TYPE_MICROBIT_I2C) -#define MICROBIT_I2C_NREGS (NRF51_TWI_SIZE / sizeof(uint32_t)) +#define MICROBIT_I2C_NREGS (NRF51_PERIPHERAL_SIZE / sizeof(uint32_t)) typedef struct { SysBusDevice parent_obj; From 27d6dea3d702b4f9cefacfc8438a9478c03092e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 09:28:21 +0200 Subject: [PATCH 0364/2595] hw/timer/nrf51_timer: Display timer ID in trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NRF51 series SoC have 3 timer peripherals, each having 4 counters. To help differentiate which peripheral is accessed, display the timer ID in the trace events. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20200504072822.18799-4-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/nrf51_soc.c | 5 +++++ hw/timer/nrf51_timer.c | 11 +++++++++-- hw/timer/trace-events | 4 ++-- include/hw/timer/nrf51_timer.h | 1 + 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index e50473fd19..71309e53cc 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -150,6 +150,11 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) /* TIMER */ for (i = 0; i < NRF51_NUM_TIMERS; i++) { + object_property_set_uint(OBJECT(&s->timer[i]), i, "id", &err); + if (err) { + error_propagate(errp, err); + return; + } object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err); if (err) { error_propagate(errp, err); diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c index bc82c85a6f..38cea0542e 100644 --- a/hw/timer/nrf51_timer.c +++ b/hw/timer/nrf51_timer.c @@ -17,6 +17,7 @@ #include "hw/arm/nrf51.h" #include "hw/irq.h" #include "hw/timer/nrf51_timer.h" +#include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "trace.h" @@ -185,7 +186,7 @@ static uint64_t nrf51_timer_read(void *opaque, hwaddr offset, unsigned int size) __func__, offset); } - trace_nrf51_timer_read(offset, r, size); + trace_nrf51_timer_read(s->id, offset, r, size); return r; } @@ -197,7 +198,7 @@ static void nrf51_timer_write(void *opaque, hwaddr offset, uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); size_t idx; - trace_nrf51_timer_write(offset, value, size); + trace_nrf51_timer_write(s->id, offset, value, size); switch (offset) { case NRF51_TIMER_TASK_START: @@ -372,12 +373,18 @@ static const VMStateDescription vmstate_nrf51_timer = { } }; +static Property nrf51_timer_properties[] = { + DEFINE_PROP_UINT8("id", NRF51TimerState, id, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void nrf51_timer_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->reset = nrf51_timer_reset; dc->vmsd = &vmstate_nrf51_timer; + device_class_set_props(dc, nrf51_timer_properties); } static const TypeInfo nrf51_timer_info = { diff --git a/hw/timer/trace-events b/hw/timer/trace-events index 29fda7870e..43b605cc75 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -67,8 +67,8 @@ cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset" # nrf51_timer.c -nrf51_timer_read(uint64_t addr, uint32_t value, unsigned size) "read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" -nrf51_timer_write(uint64_t addr, uint32_t value, unsigned size) "write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" +nrf51_timer_read(uint8_t timer_id, uint64_t addr, uint32_t value, unsigned size) "timer %u read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" +nrf51_timer_write(uint8_t timer_id, uint64_t addr, uint32_t value, unsigned size) "timer %u write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" # bcm2835_systmr.c bcm2835_systmr_irq(bool enable) "timer irq state %u" diff --git a/include/hw/timer/nrf51_timer.h b/include/hw/timer/nrf51_timer.h index 85cad2300d..eb6815f21d 100644 --- a/include/hw/timer/nrf51_timer.h +++ b/include/hw/timer/nrf51_timer.h @@ -59,6 +59,7 @@ typedef struct NRF51TimerState { MemoryRegion iomem; qemu_irq irq; + uint8_t id; QEMUTimer timer; int64_t timer_start_ns; int64_t update_counter_ns; From 602ab789363741aee29aeacc6b024af72161f3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 09:28:22 +0200 Subject: [PATCH 0365/2595] hw/timer/nrf51_timer: Add trace event of counter value update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add trace event to display timer's counter value updates. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20200504072822.18799-5-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/timer/nrf51_timer.c | 1 + hw/timer/trace-events | 1 + 2 files changed, 2 insertions(+) diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c index 38cea0542e..42be79c736 100644 --- a/hw/timer/nrf51_timer.c +++ b/hw/timer/nrf51_timer.c @@ -240,6 +240,7 @@ static void nrf51_timer_write(void *opaque, hwaddr offset, idx = (offset - NRF51_TIMER_TASK_CAPTURE_0) / 4; s->cc[idx] = s->counter; + trace_nrf51_timer_set_count(s->id, idx, s->counter); } break; case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3: diff --git a/hw/timer/trace-events b/hw/timer/trace-events index 43b605cc75..80ea197594 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -69,6 +69,7 @@ cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset" # nrf51_timer.c nrf51_timer_read(uint8_t timer_id, uint64_t addr, uint32_t value, unsigned size) "timer %u read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" nrf51_timer_write(uint8_t timer_id, uint64_t addr, uint32_t value, unsigned size) "timer %u write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" +nrf51_timer_set_count(uint8_t timer_id, uint8_t counter_id, uint32_t value) "timer %u counter %u count 0x%" PRIx32 # bcm2835_systmr.c bcm2835_systmr_irq(bool enable) "timer irq state %u" From 390734a42d003848efc6b73f6b7d8cd8aff8bdab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:41 -0700 Subject: [PATCH 0366/2595] exec: Add block comments for watchpoint routines Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- include/hw/core/cpu.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 5bf94d28cf..07f7698155 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -1100,8 +1100,31 @@ int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, vaddr len, int flags); void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint); void cpu_watchpoint_remove_all(CPUState *cpu, int mask); + +/** + * cpu_check_watchpoint: + * @cpu: cpu context + * @addr: guest virtual address + * @len: access length + * @attrs: memory access attributes + * @flags: watchpoint access type + * @ra: unwind return address + * + * Check for a watchpoint hit in [addr, addr+len) of the type + * specified by @flags. Exit via exception with a hit. + */ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, MemTxAttrs attrs, int flags, uintptr_t ra); + +/** + * cpu_watchpoint_address_matches: + * @cpu: cpu context + * @addr: guest virtual address + * @len: access length + * + * Return the watchpoint flags that apply to [addr, addr+len). + * If no watchpoint is registered for the range, the result is 0. + */ int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len); #endif From 9835936d4450dccd5e6fabd3c34330420036b028 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:42 -0700 Subject: [PATCH 0367/2595] exec: Fix cpu_watchpoint_address_matches address length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only caller of cpu_watchpoint_address_matches passes TARGET_PAGE_SIZE, so the bug is not currently visible. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200508154359.7494-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 2874bb5088..5162f0d12f 100644 --- a/exec.c +++ b/exec.c @@ -1127,7 +1127,7 @@ int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len) int ret = 0; QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) { - if (watchpoint_address_matches(wp, addr, TARGET_PAGE_SIZE)) { + if (watchpoint_address_matches(wp, addr, len)) { ret |= wp->flags; } } From 857129b34190a4c2e782006dc255352a6cd3934b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:43 -0700 Subject: [PATCH 0368/2595] accel/tcg: Add block comment for probe_access Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- include/exec/exec-all.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 350c4b451b..d656a1f05c 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -330,6 +330,23 @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu, { } #endif +/** + * probe_access: + * @env: CPUArchState + * @addr: guest virtual address to look up + * @size: size of the access + * @access_type: read, write or execute permission + * @mmu_idx: MMU index to use for lookup + * @retaddr: return address for unwinding + * + * Look up the guest virtual address @addr. Raise an exception if the + * page does not satisfy @access_type. Raise an exception if the + * access (@addr, @size) hits a watchpoint. For writes, mark a clean + * page as dirty. + * + * Finally, return the host address for a page that is backed by RAM, + * or NULL if the page requires I/O. + */ void *probe_access(CPUArchState *env, target_ulong addr, int size, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); From 7a1bfee682d8474340ec0fced19b9f0faef9f568 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:44 -0700 Subject: [PATCH 0369/2595] accel/tcg: Adjust probe_access call to page_check_range We have validated that addr+size does not cross a page boundary. Therefore we need to validate exactly one page. We can achieve that passing any value 1 <= x <= size to page_check_range. Passing 1 will simplify the next patch. Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-5-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- accel/tcg/user-exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 4be78eb9b3..03538e2a38 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -211,7 +211,7 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size, g_assert_not_reached(); } - if (!guest_addr_valid(addr) || page_check_range(addr, size, flags) < 0) { + if (!guest_addr_valid(addr) || page_check_range(addr, 1, flags) < 0) { CPUState *cpu = env_cpu(env); CPUClass *cc = CPU_GET_CLASS(cpu); cc->tlb_fill(cpu, addr, size, access_type, MMU_USER_IDX, false, From 069cfe77d63e06e2b25912aea9fea6ea14bb246a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:45 -0700 Subject: [PATCH 0370/2595] accel/tcg: Add probe_access_flags This new interface will allow targets to probe for a page and then handle watchpoints themselves. This will be most useful for vector predicated memory operations, where one page lookup can be used for many operations, and one test can avoid many watchpoint checks. Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-6-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- accel/tcg/cputlb.c | 177 ++++++++++++++++++++-------------------- accel/tcg/user-exec.c | 43 ++++++++-- include/exec/cpu-all.h | 13 ++- include/exec/exec-all.h | 22 +++++ 4 files changed, 158 insertions(+), 97 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index e3b5750c3b..c708e9785f 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1231,86 +1231,16 @@ static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size, } } -/* - * 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 - * were a real access (and we will not return). - * If the size is 0 or the page requires I/O access, returns NULL; otherwise, - * returns the address of the host page similar to tlb_vaddr_to_host(). - */ -void *probe_access(CPUArchState *env, target_ulong addr, int size, - MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) +static int probe_access_internal(CPUArchState *env, target_ulong addr, + int fault_size, MMUAccessType access_type, + int mmu_idx, bool nonfault, + void **phost, uintptr_t retaddr) { uintptr_t index = tlb_index(env, mmu_idx, addr); CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); - target_ulong tlb_addr; - size_t elt_ofs; - int wp_access; - - g_assert(-(addr | TARGET_PAGE_MASK) >= size); - - switch (access_type) { - case MMU_DATA_LOAD: - elt_ofs = offsetof(CPUTLBEntry, addr_read); - wp_access = BP_MEM_READ; - break; - case MMU_DATA_STORE: - elt_ofs = offsetof(CPUTLBEntry, addr_write); - wp_access = BP_MEM_WRITE; - break; - case MMU_INST_FETCH: - elt_ofs = offsetof(CPUTLBEntry, addr_code); - wp_access = BP_MEM_READ; - break; - default: - g_assert_not_reached(); - } - tlb_addr = tlb_read_ofs(entry, elt_ofs); - - if (unlikely(!tlb_hit(tlb_addr, addr))) { - if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs, - addr & TARGET_PAGE_MASK)) { - tlb_fill(env_cpu(env), addr, size, access_type, mmu_idx, retaddr); - /* TLB resize via tlb_fill may have moved the entry. */ - index = tlb_index(env, mmu_idx, addr); - entry = tlb_entry(env, mmu_idx, addr); - } - tlb_addr = tlb_read_ofs(entry, elt_ofs); - } - - if (!size) { - return NULL; - } - - if (unlikely(tlb_addr & TLB_FLAGS_MASK)) { - CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; - - /* 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); -} - -void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, - MMUAccessType access_type, int mmu_idx) -{ - CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); - target_ulong tlb_addr, page; + target_ulong tlb_addr, page_addr; size_t elt_ofs; + int flags; switch (access_type) { case MMU_DATA_LOAD: @@ -1325,20 +1255,19 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, default: g_assert_not_reached(); } - - page = addr & TARGET_PAGE_MASK; tlb_addr = tlb_read_ofs(entry, elt_ofs); - if (!tlb_hit_page(tlb_addr, page)) { - uintptr_t index = tlb_index(env, mmu_idx, addr); - - if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs, page)) { + page_addr = addr & TARGET_PAGE_MASK; + if (!tlb_hit_page(tlb_addr, page_addr)) { + if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs, page_addr)) { CPUState *cs = env_cpu(env); CPUClass *cc = CPU_GET_CLASS(cs); - if (!cc->tlb_fill(cs, addr, 0, access_type, mmu_idx, true, 0)) { + if (!cc->tlb_fill(cs, addr, fault_size, access_type, + mmu_idx, nonfault, retaddr)) { /* Non-faulting page table read failed. */ - return NULL; + *phost = NULL; + return TLB_INVALID_MASK; } /* TLB resize via tlb_fill may have moved the entry. */ @@ -1346,15 +1275,89 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, } tlb_addr = tlb_read_ofs(entry, elt_ofs); } + flags = tlb_addr & TLB_FLAGS_MASK; - if (tlb_addr & ~TARGET_PAGE_MASK) { - /* IO access */ + /* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */ + if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))) { + *phost = NULL; + return TLB_MMIO; + } + + /* Everything else is RAM. */ + *phost = (void *)((uintptr_t)addr + entry->addend); + return flags; +} + +int probe_access_flags(CPUArchState *env, target_ulong addr, + MMUAccessType access_type, int mmu_idx, + bool nonfault, void **phost, uintptr_t retaddr) +{ + int flags; + + flags = probe_access_internal(env, addr, 0, access_type, mmu_idx, + nonfault, phost, retaddr); + + /* Handle clean RAM pages. */ + if (unlikely(flags & TLB_NOTDIRTY)) { + uintptr_t index = tlb_index(env, mmu_idx, addr); + CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; + + notdirty_write(env_cpu(env), addr, 1, iotlbentry, retaddr); + flags &= ~TLB_NOTDIRTY; + } + + return flags; +} + +void *probe_access(CPUArchState *env, target_ulong addr, int size, + MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) +{ + void *host; + int flags; + + g_assert(-(addr | TARGET_PAGE_MASK) >= size); + + flags = probe_access_internal(env, addr, size, access_type, mmu_idx, + false, &host, retaddr); + + /* Per the interface, size == 0 merely faults the access. */ + if (size == 0) { return NULL; } - return (void *)((uintptr_t)addr + entry->addend); + if (unlikely(flags & (TLB_NOTDIRTY | TLB_WATCHPOINT))) { + uintptr_t index = tlb_index(env, mmu_idx, addr); + CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; + + /* Handle watchpoints. */ + if (flags & TLB_WATCHPOINT) { + int wp_access = (access_type == MMU_DATA_STORE + ? BP_MEM_WRITE : BP_MEM_READ); + cpu_check_watchpoint(env_cpu(env), addr, size, + iotlbentry->attrs, wp_access, retaddr); + } + + /* Handle clean RAM pages. */ + if (flags & TLB_NOTDIRTY) { + notdirty_write(env_cpu(env), addr, 1, iotlbentry, retaddr); + } + } + + return host; } +void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, + MMUAccessType access_type, int mmu_idx) +{ + void *host; + int flags; + + flags = probe_access_internal(env, addr, 0, access_type, + mmu_idx, true, &host, 0); + + /* No combination of flags are expected by the caller. */ + return flags ? NULL : host; +} #ifdef CONFIG_PLUGIN /* diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 03538e2a38..987342c50c 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -190,13 +190,12 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info, g_assert_not_reached(); } -void *probe_access(CPUArchState *env, target_ulong addr, int size, - MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) +static int probe_access_internal(CPUArchState *env, target_ulong addr, + int fault_size, MMUAccessType access_type, + bool nonfault, uintptr_t ra) { int flags; - g_assert(-(addr | TARGET_PAGE_MASK) >= size); - switch (access_type) { case MMU_DATA_STORE: flags = PAGE_WRITE; @@ -212,12 +211,38 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size, } if (!guest_addr_valid(addr) || page_check_range(addr, 1, flags) < 0) { - CPUState *cpu = env_cpu(env); - CPUClass *cc = CPU_GET_CLASS(cpu); - cc->tlb_fill(cpu, addr, size, access_type, MMU_USER_IDX, false, - retaddr); - g_assert_not_reached(); + if (nonfault) { + return TLB_INVALID_MASK; + } else { + CPUState *cpu = env_cpu(env); + CPUClass *cc = CPU_GET_CLASS(cpu); + cc->tlb_fill(cpu, addr, fault_size, access_type, + MMU_USER_IDX, false, ra); + g_assert_not_reached(); + } } + return 0; +} + +int probe_access_flags(CPUArchState *env, target_ulong addr, + MMUAccessType access_type, int mmu_idx, + bool nonfault, void **phost, uintptr_t ra) +{ + int flags; + + flags = probe_access_internal(env, addr, 0, access_type, nonfault, ra); + *phost = flags ? NULL : g2h(addr); + return flags; +} + +void *probe_access(CPUArchState *env, target_ulong addr, int size, + MMUAccessType access_type, int mmu_idx, uintptr_t ra) +{ + int flags; + + g_assert(-(addr | TARGET_PAGE_MASK) >= size); + flags = probe_access_internal(env, addr, size, access_type, false, ra); + g_assert(flags == 0); return size ? g2h(addr) : NULL; } diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 49384bb66a..43ddcf024c 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -328,7 +328,18 @@ CPUArchState *cpu_copy(CPUArchState *env); | CPU_INTERRUPT_TGT_EXT_3 \ | CPU_INTERRUPT_TGT_EXT_4) -#if !defined(CONFIG_USER_ONLY) +#ifdef CONFIG_USER_ONLY + +/* + * Allow some level of source compatibility with softmmu. We do not + * support any of the more exotic features, so only invalid pages may + * be signaled by probe_access_flags(). + */ +#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1)) +#define TLB_MMIO 0 +#define TLB_WATCHPOINT 0 + +#else /* * Flags stored in the low bits of the TLB virtual address. diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index d656a1f05c..8792bea07a 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -362,6 +362,28 @@ static inline void *probe_read(CPUArchState *env, target_ulong addr, int size, return probe_access(env, addr, size, MMU_DATA_LOAD, mmu_idx, retaddr); } +/** + * probe_access_flags: + * @env: CPUArchState + * @addr: guest virtual address to look up + * @access_type: read, write or execute permission + * @mmu_idx: MMU index to use for lookup + * @nonfault: suppress the fault + * @phost: return value for host address + * @retaddr: return address for unwinding + * + * Similar to probe_access, loosely returning the TLB_FLAGS_MASK for + * the page, and storing the host address for RAM in @phost. + * + * If @nonfault is set, do not raise an exception but return TLB_INVALID_MASK. + * Do not handle watchpoints, but include TLB_WATCHPOINT in the returned flags. + * Do handle clean pages, so exclude TLB_NOTDIRY from the returned flags. + * For simplicity, all "mmio-like" flags are folded to TLB_MMIO. + */ +int probe_access_flags(CPUArchState *env, target_ulong addr, + MMUAccessType access_type, int mmu_idx, + bool nonfault, void **phost, uintptr_t retaddr); + #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ /* Estimated block size for TB allocation. */ From b9e60257c10a0116318dc4e23148f7e4d85811a8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:46 -0700 Subject: [PATCH 0371/2595] accel/tcg: Add endian-specific cpu_{ld, st}* operations We currently have target-endian versions of these operations, but no easy way to force a specific endianness. This can be helpful if the target has endian-specific operations, or a mode that swaps endianness. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- accel/tcg/cputlb.c | 236 ++++++++++++++++++++++-------- accel/tcg/user-exec.c | 211 ++++++++++++++++++++++----- docs/devel/loads-stores.rst | 39 +++-- include/exec/cpu_ldst.h | 283 +++++++++++++++++++++++++++--------- 4 files changed, 587 insertions(+), 182 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index c708e9785f..eb2cf9de5e 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1772,36 +1772,54 @@ int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr, full_ldub_mmu); } -uint32_t cpu_lduw_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) +uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) { - return cpu_load_helper(env, addr, mmu_idx, ra, MO_TEUW, - MO_TE == MO_LE - ? full_le_lduw_mmu : full_be_lduw_mmu); + return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEUW, full_be_lduw_mmu); } -int cpu_ldsw_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) +int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) { - return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_TESW, - MO_TE == MO_LE - ? full_le_lduw_mmu : full_be_lduw_mmu); + return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_BESW, + full_be_lduw_mmu); } -uint32_t cpu_ldl_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) +uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) { - return cpu_load_helper(env, addr, mmu_idx, ra, MO_TEUL, - MO_TE == MO_LE - ? full_le_ldul_mmu : full_be_ldul_mmu); + return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEUL, full_be_ldul_mmu); } -uint64_t cpu_ldq_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) +uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) { - return cpu_load_helper(env, addr, mmu_idx, ra, MO_TEQ, - MO_TE == MO_LE - ? helper_le_ldq_mmu : helper_be_ldq_mmu); + return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEQ, helper_be_ldq_mmu); +} + +uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEUW, full_le_lduw_mmu); +} + +int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_LESW, + full_le_lduw_mmu); +} + +uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEUL, full_le_ldul_mmu); +} + +uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEQ, helper_le_ldq_mmu); } uint32_t cpu_ldub_data_ra(CPUArchState *env, target_ulong ptr, @@ -1815,25 +1833,50 @@ int cpu_ldsb_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr) return cpu_ldsb_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); } -uint32_t cpu_lduw_data_ra(CPUArchState *env, target_ulong ptr, - uintptr_t retaddr) +uint32_t cpu_lduw_be_data_ra(CPUArchState *env, target_ulong ptr, + uintptr_t retaddr) { - return cpu_lduw_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); + return cpu_lduw_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); } -int cpu_ldsw_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr) +int cpu_ldsw_be_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr) { - return cpu_ldsw_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); + return cpu_ldsw_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); } -uint32_t cpu_ldl_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr) +uint32_t cpu_ldl_be_data_ra(CPUArchState *env, target_ulong ptr, + uintptr_t retaddr) { - return cpu_ldl_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); + return cpu_ldl_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); } -uint64_t cpu_ldq_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr) +uint64_t cpu_ldq_be_data_ra(CPUArchState *env, target_ulong ptr, + uintptr_t retaddr) { - return cpu_ldq_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); + return cpu_ldq_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); +} + +uint32_t cpu_lduw_le_data_ra(CPUArchState *env, target_ulong ptr, + uintptr_t retaddr) +{ + return cpu_lduw_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); +} + +int cpu_ldsw_le_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr) +{ + return cpu_ldsw_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); +} + +uint32_t cpu_ldl_le_data_ra(CPUArchState *env, target_ulong ptr, + uintptr_t retaddr) +{ + return cpu_ldl_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); +} + +uint64_t cpu_ldq_le_data_ra(CPUArchState *env, target_ulong ptr, + uintptr_t retaddr) +{ + return cpu_ldq_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); } uint32_t cpu_ldub_data(CPUArchState *env, target_ulong ptr) @@ -1846,24 +1889,44 @@ int cpu_ldsb_data(CPUArchState *env, target_ulong ptr) return cpu_ldsb_data_ra(env, ptr, 0); } -uint32_t cpu_lduw_data(CPUArchState *env, target_ulong ptr) +uint32_t cpu_lduw_be_data(CPUArchState *env, target_ulong ptr) { - return cpu_lduw_data_ra(env, ptr, 0); + return cpu_lduw_be_data_ra(env, ptr, 0); } -int cpu_ldsw_data(CPUArchState *env, target_ulong ptr) +int cpu_ldsw_be_data(CPUArchState *env, target_ulong ptr) { - return cpu_ldsw_data_ra(env, ptr, 0); + return cpu_ldsw_be_data_ra(env, ptr, 0); } -uint32_t cpu_ldl_data(CPUArchState *env, target_ulong ptr) +uint32_t cpu_ldl_be_data(CPUArchState *env, target_ulong ptr) { - return cpu_ldl_data_ra(env, ptr, 0); + return cpu_ldl_be_data_ra(env, ptr, 0); } -uint64_t cpu_ldq_data(CPUArchState *env, target_ulong ptr) +uint64_t cpu_ldq_be_data(CPUArchState *env, target_ulong ptr) { - return cpu_ldq_data_ra(env, ptr, 0); + return cpu_ldq_be_data_ra(env, ptr, 0); +} + +uint32_t cpu_lduw_le_data(CPUArchState *env, target_ulong ptr) +{ + return cpu_lduw_le_data_ra(env, ptr, 0); +} + +int cpu_ldsw_le_data(CPUArchState *env, target_ulong ptr) +{ + return cpu_ldsw_le_data_ra(env, ptr, 0); +} + +uint32_t cpu_ldl_le_data(CPUArchState *env, target_ulong ptr) +{ + return cpu_ldl_le_data_ra(env, ptr, 0); +} + +uint64_t cpu_ldq_le_data(CPUArchState *env, target_ulong ptr) +{ + return cpu_ldq_le_data_ra(env, ptr, 0); } /* @@ -2121,22 +2184,40 @@ void cpu_stb_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_UB); } -void cpu_stw_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, - int mmu_idx, uintptr_t retaddr) +void cpu_stw_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, + int mmu_idx, uintptr_t retaddr) { - cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_TEUW); + cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEUW); } -void cpu_stl_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, - int mmu_idx, uintptr_t retaddr) +void cpu_stl_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, + int mmu_idx, uintptr_t retaddr) { - cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_TEUL); + cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEUL); } -void cpu_stq_mmuidx_ra(CPUArchState *env, target_ulong addr, uint64_t val, - int mmu_idx, uintptr_t retaddr) +void cpu_stq_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint64_t val, + int mmu_idx, uintptr_t retaddr) { - cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_TEQ); + cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEQ); +} + +void cpu_stw_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, + int mmu_idx, uintptr_t retaddr) +{ + cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEUW); +} + +void cpu_stl_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, + int mmu_idx, uintptr_t retaddr) +{ + cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEUL); +} + +void cpu_stq_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint64_t val, + int mmu_idx, uintptr_t retaddr) +{ + cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEQ); } void cpu_stb_data_ra(CPUArchState *env, target_ulong ptr, @@ -2145,22 +2226,40 @@ void cpu_stb_data_ra(CPUArchState *env, target_ulong ptr, cpu_stb_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); } -void cpu_stw_data_ra(CPUArchState *env, target_ulong ptr, - uint32_t val, uintptr_t retaddr) +void cpu_stw_be_data_ra(CPUArchState *env, target_ulong ptr, + uint32_t val, uintptr_t retaddr) { - cpu_stw_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); + cpu_stw_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); } -void cpu_stl_data_ra(CPUArchState *env, target_ulong ptr, - uint32_t val, uintptr_t retaddr) +void cpu_stl_be_data_ra(CPUArchState *env, target_ulong ptr, + uint32_t val, uintptr_t retaddr) { - cpu_stl_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); + cpu_stl_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); } -void cpu_stq_data_ra(CPUArchState *env, target_ulong ptr, - uint64_t val, uintptr_t retaddr) +void cpu_stq_be_data_ra(CPUArchState *env, target_ulong ptr, + uint64_t val, uintptr_t retaddr) { - cpu_stq_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); + cpu_stq_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); +} + +void cpu_stw_le_data_ra(CPUArchState *env, target_ulong ptr, + uint32_t val, uintptr_t retaddr) +{ + cpu_stw_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); +} + +void cpu_stl_le_data_ra(CPUArchState *env, target_ulong ptr, + uint32_t val, uintptr_t retaddr) +{ + cpu_stl_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); +} + +void cpu_stq_le_data_ra(CPUArchState *env, target_ulong ptr, + uint64_t val, uintptr_t retaddr) +{ + cpu_stq_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); } void cpu_stb_data(CPUArchState *env, target_ulong ptr, uint32_t val) @@ -2168,19 +2267,34 @@ void cpu_stb_data(CPUArchState *env, target_ulong ptr, uint32_t val) cpu_stb_data_ra(env, ptr, val, 0); } -void cpu_stw_data(CPUArchState *env, target_ulong ptr, uint32_t val) +void cpu_stw_be_data(CPUArchState *env, target_ulong ptr, uint32_t val) { - cpu_stw_data_ra(env, ptr, val, 0); + cpu_stw_be_data_ra(env, ptr, val, 0); } -void cpu_stl_data(CPUArchState *env, target_ulong ptr, uint32_t val) +void cpu_stl_be_data(CPUArchState *env, target_ulong ptr, uint32_t val) { - cpu_stl_data_ra(env, ptr, val, 0); + cpu_stl_be_data_ra(env, ptr, val, 0); } -void cpu_stq_data(CPUArchState *env, target_ulong ptr, uint64_t val) +void cpu_stq_be_data(CPUArchState *env, target_ulong ptr, uint64_t val) { - cpu_stq_data_ra(env, ptr, val, 0); + cpu_stq_be_data_ra(env, ptr, val, 0); +} + +void cpu_stw_le_data(CPUArchState *env, target_ulong ptr, uint32_t val) +{ + cpu_stw_le_data_ra(env, ptr, val, 0); +} + +void cpu_stl_le_data(CPUArchState *env, target_ulong ptr, uint32_t val) +{ + cpu_stl_le_data_ra(env, ptr, val, 0); +} + +void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val) +{ + cpu_stq_le_data_ra(env, ptr, val, 0); } /* First set of helpers allows passing in of OI and RETADDR. This makes diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 987342c50c..52359949df 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -783,46 +783,90 @@ int cpu_ldsb_data(CPUArchState *env, abi_ptr ptr) return ret; } -uint32_t cpu_lduw_data(CPUArchState *env, abi_ptr ptr) +uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr ptr) { uint32_t ret; - uint16_t meminfo = trace_mem_get_info(MO_TEUW, MMU_USER_IDX, false); + uint16_t meminfo = trace_mem_get_info(MO_BEUW, MMU_USER_IDX, false); trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); - ret = lduw_p(g2h(ptr)); + ret = lduw_be_p(g2h(ptr)); qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); return ret; } -int cpu_ldsw_data(CPUArchState *env, abi_ptr ptr) +int cpu_ldsw_be_data(CPUArchState *env, abi_ptr ptr) { int ret; - uint16_t meminfo = trace_mem_get_info(MO_TESW, MMU_USER_IDX, false); + uint16_t meminfo = trace_mem_get_info(MO_BESW, MMU_USER_IDX, false); trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); - ret = ldsw_p(g2h(ptr)); + ret = ldsw_be_p(g2h(ptr)); qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); return ret; } -uint32_t cpu_ldl_data(CPUArchState *env, abi_ptr ptr) +uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr ptr) { uint32_t ret; - uint16_t meminfo = trace_mem_get_info(MO_TEUL, MMU_USER_IDX, false); + uint16_t meminfo = trace_mem_get_info(MO_BEUL, MMU_USER_IDX, false); trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); - ret = ldl_p(g2h(ptr)); + ret = ldl_be_p(g2h(ptr)); qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); return ret; } -uint64_t cpu_ldq_data(CPUArchState *env, abi_ptr ptr) +uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr ptr) { uint64_t ret; - uint16_t meminfo = trace_mem_get_info(MO_TEQ, MMU_USER_IDX, false); + uint16_t meminfo = trace_mem_get_info(MO_BEQ, MMU_USER_IDX, false); trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); - ret = ldq_p(g2h(ptr)); + ret = ldq_be_p(g2h(ptr)); + qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); + return ret; +} + +uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr ptr) +{ + uint32_t ret; + uint16_t meminfo = trace_mem_get_info(MO_LEUW, MMU_USER_IDX, false); + + trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); + ret = lduw_le_p(g2h(ptr)); + qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); + return ret; +} + +int cpu_ldsw_le_data(CPUArchState *env, abi_ptr ptr) +{ + int ret; + uint16_t meminfo = trace_mem_get_info(MO_LESW, MMU_USER_IDX, false); + + trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); + ret = ldsw_le_p(g2h(ptr)); + qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); + return ret; +} + +uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr ptr) +{ + uint32_t ret; + uint16_t meminfo = trace_mem_get_info(MO_LEUL, MMU_USER_IDX, false); + + trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); + ret = ldl_le_p(g2h(ptr)); + qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); + return ret; +} + +uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr ptr) +{ + uint64_t ret; + uint16_t meminfo = trace_mem_get_info(MO_LEQ, MMU_USER_IDX, false); + + trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); + ret = ldq_le_p(g2h(ptr)); qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); return ret; } @@ -847,42 +891,82 @@ int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) return ret; } -uint32_t cpu_lduw_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) +uint32_t cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) { uint32_t ret; set_helper_retaddr(retaddr); - ret = cpu_lduw_data(env, ptr); + ret = cpu_lduw_be_data(env, ptr); clear_helper_retaddr(); return ret; } -int cpu_ldsw_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) +int cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) { int ret; set_helper_retaddr(retaddr); - ret = cpu_ldsw_data(env, ptr); + ret = cpu_ldsw_be_data(env, ptr); clear_helper_retaddr(); return ret; } -uint32_t cpu_ldl_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) +uint32_t cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) { uint32_t ret; set_helper_retaddr(retaddr); - ret = cpu_ldl_data(env, ptr); + ret = cpu_ldl_be_data(env, ptr); clear_helper_retaddr(); return ret; } -uint64_t cpu_ldq_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) +uint64_t cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) { uint64_t ret; set_helper_retaddr(retaddr); - ret = cpu_ldq_data(env, ptr); + ret = cpu_ldq_be_data(env, ptr); + clear_helper_retaddr(); + return ret; +} + +uint32_t cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) +{ + uint32_t ret; + + set_helper_retaddr(retaddr); + ret = cpu_lduw_le_data(env, ptr); + clear_helper_retaddr(); + return ret; +} + +int cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) +{ + int ret; + + set_helper_retaddr(retaddr); + ret = cpu_ldsw_le_data(env, ptr); + clear_helper_retaddr(); + return ret; +} + +uint32_t cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) +{ + uint32_t ret; + + set_helper_retaddr(retaddr); + ret = cpu_ldl_le_data(env, ptr); + clear_helper_retaddr(); + return ret; +} + +uint64_t cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr) +{ + uint64_t ret; + + set_helper_retaddr(retaddr); + ret = cpu_ldq_le_data(env, ptr); clear_helper_retaddr(); return ret; } @@ -896,30 +980,57 @@ void cpu_stb_data(CPUArchState *env, abi_ptr ptr, uint32_t val) qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); } -void cpu_stw_data(CPUArchState *env, abi_ptr ptr, uint32_t val) +void cpu_stw_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val) { - uint16_t meminfo = trace_mem_get_info(MO_TEUW, MMU_USER_IDX, true); + uint16_t meminfo = trace_mem_get_info(MO_BEUW, MMU_USER_IDX, true); trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); - stw_p(g2h(ptr), val); + stw_be_p(g2h(ptr), val); qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); } -void cpu_stl_data(CPUArchState *env, abi_ptr ptr, uint32_t val) +void cpu_stl_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val) { - uint16_t meminfo = trace_mem_get_info(MO_TEUL, MMU_USER_IDX, true); + uint16_t meminfo = trace_mem_get_info(MO_BEUL, MMU_USER_IDX, true); trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); - stl_p(g2h(ptr), val); + stl_be_p(g2h(ptr), val); qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); } -void cpu_stq_data(CPUArchState *env, abi_ptr ptr, uint64_t val) +void cpu_stq_be_data(CPUArchState *env, abi_ptr ptr, uint64_t val) { - uint16_t meminfo = trace_mem_get_info(MO_TEQ, MMU_USER_IDX, true); + uint16_t meminfo = trace_mem_get_info(MO_BEQ, MMU_USER_IDX, true); trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); - stq_p(g2h(ptr), val); + stq_be_p(g2h(ptr), val); + qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); +} + +void cpu_stw_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val) +{ + uint16_t meminfo = trace_mem_get_info(MO_LEUW, MMU_USER_IDX, true); + + trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); + stw_le_p(g2h(ptr), val); + qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); +} + +void cpu_stl_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val) +{ + uint16_t meminfo = trace_mem_get_info(MO_LEUL, MMU_USER_IDX, true); + + trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); + stl_le_p(g2h(ptr), val); + qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); +} + +void cpu_stq_le_data(CPUArchState *env, abi_ptr ptr, uint64_t val) +{ + uint16_t meminfo = trace_mem_get_info(MO_LEQ, MMU_USER_IDX, true); + + trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo); + stq_le_p(g2h(ptr), val); qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo); } @@ -931,27 +1042,51 @@ void cpu_stb_data_ra(CPUArchState *env, abi_ptr ptr, clear_helper_retaddr(); } -void cpu_stw_data_ra(CPUArchState *env, abi_ptr ptr, - uint32_t val, uintptr_t retaddr) +void cpu_stw_be_data_ra(CPUArchState *env, abi_ptr ptr, + uint32_t val, uintptr_t retaddr) { set_helper_retaddr(retaddr); - cpu_stw_data(env, ptr, val); + cpu_stw_be_data(env, ptr, val); clear_helper_retaddr(); } -void cpu_stl_data_ra(CPUArchState *env, abi_ptr ptr, - uint32_t val, uintptr_t retaddr) +void cpu_stl_be_data_ra(CPUArchState *env, abi_ptr ptr, + uint32_t val, uintptr_t retaddr) { set_helper_retaddr(retaddr); - cpu_stl_data(env, ptr, val); + cpu_stl_be_data(env, ptr, val); clear_helper_retaddr(); } -void cpu_stq_data_ra(CPUArchState *env, abi_ptr ptr, - uint64_t val, uintptr_t retaddr) +void cpu_stq_be_data_ra(CPUArchState *env, abi_ptr ptr, + uint64_t val, uintptr_t retaddr) { set_helper_retaddr(retaddr); - cpu_stq_data(env, ptr, val); + cpu_stq_be_data(env, ptr, val); + clear_helper_retaddr(); +} + +void cpu_stw_le_data_ra(CPUArchState *env, abi_ptr ptr, + uint32_t val, uintptr_t retaddr) +{ + set_helper_retaddr(retaddr); + cpu_stw_le_data(env, ptr, val); + clear_helper_retaddr(); +} + +void cpu_stl_le_data_ra(CPUArchState *env, abi_ptr ptr, + uint32_t val, uintptr_t retaddr) +{ + set_helper_retaddr(retaddr); + cpu_stl_le_data(env, ptr, val); + clear_helper_retaddr(); +} + +void cpu_stq_le_data_ra(CPUArchState *env, abi_ptr ptr, + uint64_t val, uintptr_t retaddr) +{ + set_helper_retaddr(retaddr); + cpu_stq_le_data(env, ptr, val); clear_helper_retaddr(); } diff --git a/docs/devel/loads-stores.rst b/docs/devel/loads-stores.rst index 0d99eb24c1..9a944ef1af 100644 --- a/docs/devel/loads-stores.rst +++ b/docs/devel/loads-stores.rst @@ -97,9 +97,9 @@ function, which is a return address into the generated code. Function names follow the pattern: -load: ``cpu_ld{sign}{size}_mmuidx_ra(env, ptr, mmuidx, retaddr)`` +load: ``cpu_ld{sign}{size}{end}_mmuidx_ra(env, ptr, mmuidx, retaddr)`` -store: ``cpu_st{size}_mmuidx_ra(env, ptr, val, mmuidx, retaddr)`` +store: ``cpu_st{size}{end}_mmuidx_ra(env, ptr, val, mmuidx, retaddr)`` ``sign`` - (empty) : for 32 or 64 bit sizes @@ -112,9 +112,14 @@ store: ``cpu_st{size}_mmuidx_ra(env, ptr, val, mmuidx, retaddr)`` - ``l`` : 32 bits - ``q`` : 64 bits +``end`` + - (empty) : for target endian, or 8 bit sizes + - ``_be`` : big endian + - ``_le`` : little endian + Regexes for git grep: - - ``\`` - - ``\`` + - ``\`` + - ``\`` ``cpu_{ld,st}*_data_ra`` ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -129,9 +134,9 @@ be performed with a context other than the default. Function names follow the pattern: -load: ``cpu_ld{sign}{size}_data_ra(env, ptr, ra)`` +load: ``cpu_ld{sign}{size}{end}_data_ra(env, ptr, ra)`` -store: ``cpu_st{size}_data_ra(env, ptr, val, ra)`` +store: ``cpu_st{size}{end}_data_ra(env, ptr, val, ra)`` ``sign`` - (empty) : for 32 or 64 bit sizes @@ -144,9 +149,14 @@ store: ``cpu_st{size}_data_ra(env, ptr, val, ra)`` - ``l`` : 32 bits - ``q`` : 64 bits +``end`` + - (empty) : for target endian, or 8 bit sizes + - ``_be`` : big endian + - ``_le`` : little endian + Regexes for git grep: - - ``\`` - - ``\`` + - ``\`` + - ``\`` ``cpu_{ld,st}*_data`` ~~~~~~~~~~~~~~~~~~~~~ @@ -163,9 +173,9 @@ the CPU state anyway. Function names follow the pattern: -load: ``cpu_ld{sign}{size}_data(env, ptr)`` +load: ``cpu_ld{sign}{size}{end}_data(env, ptr)`` -store: ``cpu_st{size}_data(env, ptr, val)`` +store: ``cpu_st{size}{end}_data(env, ptr, val)`` ``sign`` - (empty) : for 32 or 64 bit sizes @@ -178,9 +188,14 @@ store: ``cpu_st{size}_data(env, ptr, val)`` - ``l`` : 32 bits - ``q`` : 64 bits +``end`` + - (empty) : for target endian, or 8 bit sizes + - ``_be`` : big endian + - ``_le`` : little endian + Regexes for git grep - - ``\`` - - ``\`` + - ``\`` + - ``\`` ``cpu_ld*_code`` ~~~~~~~~~~~~~~~~ diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 53de19753a..c14a48f65e 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -25,13 +25,13 @@ * * The syntax for the accessors is: * - * load: cpu_ld{sign}{size}_{mmusuffix}(env, ptr) - * cpu_ld{sign}{size}_{mmusuffix}_ra(env, ptr, retaddr) - * cpu_ld{sign}{size}_mmuidx_ra(env, ptr, mmu_idx, retaddr) + * load: cpu_ld{sign}{size}{end}_{mmusuffix}(env, ptr) + * cpu_ld{sign}{size}{end}_{mmusuffix}_ra(env, ptr, retaddr) + * cpu_ld{sign}{size}{end}_mmuidx_ra(env, ptr, mmu_idx, retaddr) * - * store: cpu_st{size}_{mmusuffix}(env, ptr, val) - * cpu_st{size}_{mmusuffix}_ra(env, ptr, val, retaddr) - * cpu_st{size}_mmuidx_ra(env, ptr, val, mmu_idx, retaddr) + * store: cpu_st{size}{end}_{mmusuffix}(env, ptr, val) + * cpu_st{size}{end}_{mmusuffix}_ra(env, ptr, val, retaddr) + * cpu_st{size}{end}_mmuidx_ra(env, ptr, val, mmu_idx, retaddr) * * sign is: * (empty): for 32 and 64 bit sizes @@ -44,6 +44,11 @@ * l: 32 bits * q: 64 bits * + * end is: + * (empty): for target native endian, or for 8 bit access + * _be: for forced big endian + * _le: for forced little endian + * * mmusuffix is one of the generic suffixes "data" or "code", or "mmuidx". * The "mmuidx" suffix carries an extra mmu_idx argument that specifies * the index to use; the "data" and "code" suffixes take the index from @@ -95,32 +100,57 @@ typedef target_ulong abi_ptr; #endif uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr); -uint32_t cpu_lduw_data(CPUArchState *env, abi_ptr ptr); -uint32_t cpu_ldl_data(CPUArchState *env, abi_ptr ptr); -uint64_t cpu_ldq_data(CPUArchState *env, abi_ptr ptr); int cpu_ldsb_data(CPUArchState *env, abi_ptr ptr); -int cpu_ldsw_data(CPUArchState *env, abi_ptr ptr); -uint32_t cpu_ldub_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr); -uint32_t cpu_lduw_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr); -uint32_t cpu_ldl_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr); -uint64_t cpu_ldq_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr); -int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr); -int cpu_ldsw_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr); +uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr ptr); +int cpu_ldsw_be_data(CPUArchState *env, abi_ptr ptr); +uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr ptr); +uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr ptr); + +uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr ptr); +int cpu_ldsw_le_data(CPUArchState *env, abi_ptr ptr); +uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr ptr); +uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr ptr); + +uint32_t cpu_ldub_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); +int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); + +uint32_t cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); +int cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); +uint32_t cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); +uint64_t cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); + +uint32_t cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); +int cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); +uint32_t cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); +uint64_t cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); void cpu_stb_data(CPUArchState *env, abi_ptr ptr, uint32_t val); -void cpu_stw_data(CPUArchState *env, abi_ptr ptr, uint32_t val); -void cpu_stl_data(CPUArchState *env, abi_ptr ptr, uint32_t val); -void cpu_stq_data(CPUArchState *env, abi_ptr ptr, uint64_t val); + +void cpu_stw_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val); +void cpu_stl_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val); +void cpu_stq_be_data(CPUArchState *env, abi_ptr ptr, uint64_t val); + +void cpu_stw_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val); +void cpu_stl_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val); +void cpu_stq_le_data(CPUArchState *env, abi_ptr ptr, uint64_t val); void cpu_stb_data_ra(CPUArchState *env, abi_ptr ptr, - uint32_t val, uintptr_t retaddr); -void cpu_stw_data_ra(CPUArchState *env, abi_ptr ptr, - uint32_t val, uintptr_t retaddr); -void cpu_stl_data_ra(CPUArchState *env, abi_ptr ptr, - uint32_t val, uintptr_t retaddr); -void cpu_stq_data_ra(CPUArchState *env, abi_ptr ptr, - uint64_t val, uintptr_t retaddr); + uint32_t val, uintptr_t ra); + +void cpu_stw_be_data_ra(CPUArchState *env, abi_ptr ptr, + uint32_t val, uintptr_t ra); +void cpu_stl_be_data_ra(CPUArchState *env, abi_ptr ptr, + uint32_t val, uintptr_t ra); +void cpu_stq_be_data_ra(CPUArchState *env, abi_ptr ptr, + uint64_t val, uintptr_t ra); + +void cpu_stw_le_data_ra(CPUArchState *env, abi_ptr ptr, + uint32_t val, uintptr_t ra); +void cpu_stl_le_data_ra(CPUArchState *env, abi_ptr ptr, + uint32_t val, uintptr_t ra); +void cpu_stq_le_data_ra(CPUArchState *env, abi_ptr ptr, + uint64_t val, uintptr_t ra); #if defined(CONFIG_USER_ONLY) @@ -157,34 +187,58 @@ static inline uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr, return cpu_ldub_data_ra(env, addr, ra); } -static inline uint32_t cpu_lduw_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - return cpu_lduw_data_ra(env, addr, ra); -} - -static inline uint32_t cpu_ldl_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - return cpu_ldl_data_ra(env, addr, ra); -} - -static inline uint64_t cpu_ldq_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - return cpu_ldq_data_ra(env, addr, ra); -} - static inline int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr, int mmu_idx, uintptr_t ra) { return cpu_ldsb_data_ra(env, addr, ra); } -static inline int cpu_ldsw_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) +static inline uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) { - return cpu_ldsw_data_ra(env, addr, ra); + return cpu_lduw_be_data_ra(env, addr, ra); +} + +static inline int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return cpu_ldsw_be_data_ra(env, addr, ra); +} + +static inline uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return cpu_ldl_be_data_ra(env, addr, ra); +} + +static inline uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return cpu_ldq_be_data_ra(env, addr, ra); +} + +static inline uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return cpu_lduw_le_data_ra(env, addr, ra); +} + +static inline int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return cpu_ldsw_le_data_ra(env, addr, ra); +} + +static inline uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return cpu_ldl_le_data_ra(env, addr, ra); +} + +static inline uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return cpu_ldq_le_data_ra(env, addr, ra); } static inline void cpu_stb_mmuidx_ra(CPUArchState *env, abi_ptr addr, @@ -193,22 +247,46 @@ static inline void cpu_stb_mmuidx_ra(CPUArchState *env, abi_ptr addr, cpu_stb_data_ra(env, addr, val, ra); } -static inline void cpu_stw_mmuidx_ra(CPUArchState *env, abi_ptr addr, - uint32_t val, int mmu_idx, uintptr_t ra) +static inline void cpu_stw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + uint32_t val, int mmu_idx, + uintptr_t ra) { - cpu_stw_data_ra(env, addr, val, ra); + cpu_stw_be_data_ra(env, addr, val, ra); } -static inline void cpu_stl_mmuidx_ra(CPUArchState *env, abi_ptr addr, - uint32_t val, int mmu_idx, uintptr_t ra) +static inline void cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + uint32_t val, int mmu_idx, + uintptr_t ra) { - cpu_stl_data_ra(env, addr, val, ra); + cpu_stl_be_data_ra(env, addr, val, ra); } -static inline void cpu_stq_mmuidx_ra(CPUArchState *env, abi_ptr addr, - uint64_t val, int mmu_idx, uintptr_t ra) +static inline void cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + uint64_t val, int mmu_idx, + uintptr_t ra) { - cpu_stq_data_ra(env, addr, val, ra); + cpu_stq_be_data_ra(env, addr, val, ra); +} + +static inline void cpu_stw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + uint32_t val, int mmu_idx, + uintptr_t ra) +{ + cpu_stw_le_data_ra(env, addr, val, ra); +} + +static inline void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + uint32_t val, int mmu_idx, + uintptr_t ra) +{ + cpu_stl_le_data_ra(env, addr, val, ra); +} + +static inline void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + uint64_t val, int mmu_idx, + uintptr_t ra) +{ + cpu_stq_le_data_ra(env, addr, val, ra); } #else @@ -243,29 +321,92 @@ static inline CPUTLBEntry *tlb_entry(CPUArchState *env, uintptr_t mmu_idx, uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr, int mmu_idx, uintptr_t ra); -uint32_t cpu_lduw_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra); -uint32_t cpu_ldl_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra); -uint64_t cpu_ldq_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra); - int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr, int mmu_idx, uintptr_t ra); -int cpu_ldsw_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra); + +uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra); +int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra); +uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra); +uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra); + +uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra); +int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra); +uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra); +uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra); void cpu_stb_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, int mmu_idx, uintptr_t retaddr); -void cpu_stw_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, - int mmu_idx, uintptr_t retaddr); -void cpu_stl_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, - int mmu_idx, uintptr_t retaddr); -void cpu_stq_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val, - int mmu_idx, uintptr_t retaddr); + +void cpu_stw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, + int mmu_idx, uintptr_t retaddr); +void cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, + int mmu_idx, uintptr_t retaddr); +void cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val, + int mmu_idx, uintptr_t retaddr); + +void cpu_stw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, + int mmu_idx, uintptr_t retaddr); +void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, + int mmu_idx, uintptr_t retaddr); +void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val, + int mmu_idx, uintptr_t retaddr); #endif /* defined(CONFIG_USER_ONLY) */ +#ifdef TARGET_WORDS_BIGENDIAN +# define cpu_lduw_data cpu_lduw_be_data +# define cpu_ldsw_data cpu_ldsw_be_data +# define cpu_ldl_data cpu_ldl_be_data +# define cpu_ldq_data cpu_ldq_be_data +# define cpu_lduw_data_ra cpu_lduw_be_data_ra +# define cpu_ldsw_data_ra cpu_ldsw_be_data_ra +# define cpu_ldl_data_ra cpu_ldl_be_data_ra +# define cpu_ldq_data_ra cpu_ldq_be_data_ra +# define cpu_lduw_mmuidx_ra cpu_lduw_be_mmuidx_ra +# define cpu_ldsw_mmuidx_ra cpu_ldsw_be_mmuidx_ra +# define cpu_ldl_mmuidx_ra cpu_ldl_be_mmuidx_ra +# define cpu_ldq_mmuidx_ra cpu_ldq_be_mmuidx_ra +# define cpu_stw_data cpu_stw_be_data +# define cpu_stl_data cpu_stl_be_data +# define cpu_stq_data cpu_stq_be_data +# define cpu_stw_data_ra cpu_stw_be_data_ra +# define cpu_stl_data_ra cpu_stl_be_data_ra +# define cpu_stq_data_ra cpu_stq_be_data_ra +# define cpu_stw_mmuidx_ra cpu_stw_be_mmuidx_ra +# define cpu_stl_mmuidx_ra cpu_stl_be_mmuidx_ra +# define cpu_stq_mmuidx_ra cpu_stq_be_mmuidx_ra +#else +# define cpu_lduw_data cpu_lduw_le_data +# define cpu_ldsw_data cpu_ldsw_le_data +# define cpu_ldl_data cpu_ldl_le_data +# define cpu_ldq_data cpu_ldq_le_data +# define cpu_lduw_data_ra cpu_lduw_le_data_ra +# define cpu_ldsw_data_ra cpu_ldsw_le_data_ra +# define cpu_ldl_data_ra cpu_ldl_le_data_ra +# define cpu_ldq_data_ra cpu_ldq_le_data_ra +# define cpu_lduw_mmuidx_ra cpu_lduw_le_mmuidx_ra +# define cpu_ldsw_mmuidx_ra cpu_ldsw_le_mmuidx_ra +# define cpu_ldl_mmuidx_ra cpu_ldl_le_mmuidx_ra +# define cpu_ldq_mmuidx_ra cpu_ldq_le_mmuidx_ra +# define cpu_stw_data cpu_stw_le_data +# define cpu_stl_data cpu_stl_le_data +# define cpu_stq_data cpu_stq_le_data +# define cpu_stw_data_ra cpu_stw_le_data_ra +# define cpu_stl_data_ra cpu_stl_le_data_ra +# define cpu_stq_data_ra cpu_stq_le_data_ra +# define cpu_stw_mmuidx_ra cpu_stw_le_mmuidx_ra +# define cpu_stl_mmuidx_ra cpu_stl_le_mmuidx_ra +# define cpu_stq_mmuidx_ra cpu_stq_le_mmuidx_ra +#endif + uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr); uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr); uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr); From 6799ce7b0e11f4b08c5cf26d08707b829f69449c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:47 -0700 Subject: [PATCH 0372/2595] target/arm: Use cpu_*_data_ra for sve_ldst_tlb_fn Use the "normal" memory access functions, rather than the softmmu internal helper functions directly. Since fb901c905dc3, cpu_mem_index is now a simple extract from env->hflags and not a large computation. Which means that it's now more work to pass around this value than it is to recompute it. This only adjusts the primitives, and does not clean up all of the uses within sve_helper.c. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 221 ++++++++++++++++------------------------ 1 file changed, 86 insertions(+), 135 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index fdfa652094..655bc9476f 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -3991,9 +3991,8 @@ typedef intptr_t sve_ld1_host_fn(void *vd, void *vg, void *host, * Load one element into @vd + @reg_off from (@env, @vaddr, @ra). * The controlling predicate is known to be true. */ -typedef void sve_ld1_tlb_fn(CPUARMState *env, void *vd, intptr_t reg_off, - target_ulong vaddr, TCGMemOpIdx oi, uintptr_t ra); -typedef sve_ld1_tlb_fn sve_st1_tlb_fn; +typedef void sve_ldst1_tlb_fn(CPUARMState *env, void *vd, intptr_t reg_off, + target_ulong vaddr, uintptr_t retaddr); /* * Generate the above primitives. @@ -4016,27 +4015,23 @@ static intptr_t sve_##NAME##_host(void *vd, void *vg, void *host, \ return mem_off; \ } -#ifdef CONFIG_SOFTMMU -#define DO_LD_TLB(NAME, H, TYPEE, TYPEM, HOST, MOEND, TLB) \ +#define DO_LD_TLB(NAME, H, TYPEE, TYPEM, TLB) \ static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \ - target_ulong addr, TCGMemOpIdx oi, uintptr_t ra) \ + target_ulong addr, uintptr_t ra) \ { \ - TYPEM val = TLB(env, addr, oi, ra); \ - *(TYPEE *)(vd + H(reg_off)) = val; \ + *(TYPEE *)(vd + H(reg_off)) = (TYPEM)TLB(env, addr, ra); \ } -#else -#define DO_LD_TLB(NAME, H, TYPEE, TYPEM, HOST, MOEND, TLB) \ + +#define DO_ST_TLB(NAME, H, TYPEE, TYPEM, TLB) \ static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \ - target_ulong addr, TCGMemOpIdx oi, uintptr_t ra) \ + target_ulong addr, uintptr_t ra) \ { \ - TYPEM val = HOST(g2h(addr)); \ - *(TYPEE *)(vd + H(reg_off)) = val; \ + TLB(env, addr, (TYPEM)*(TYPEE *)(vd + H(reg_off)), ra); \ } -#endif #define DO_LD_PRIM_1(NAME, H, TE, TM) \ DO_LD_HOST(NAME, H, TE, TM, ldub_p) \ - DO_LD_TLB(NAME, H, TE, TM, ldub_p, 0, helper_ret_ldub_mmu) + DO_LD_TLB(NAME, H, TE, TM, cpu_ldub_data_ra) DO_LD_PRIM_1(ld1bb, H1, uint8_t, uint8_t) DO_LD_PRIM_1(ld1bhu, H1_2, uint16_t, uint8_t) @@ -4046,39 +4041,51 @@ DO_LD_PRIM_1(ld1bss, H1_4, uint32_t, int8_t) DO_LD_PRIM_1(ld1bdu, , uint64_t, uint8_t) DO_LD_PRIM_1(ld1bds, , uint64_t, int8_t) -#define DO_LD_PRIM_2(NAME, end, MOEND, H, TE, TM, PH, PT) \ - DO_LD_HOST(NAME##_##end, H, TE, TM, PH##_##end##_p) \ - DO_LD_TLB(NAME##_##end, H, TE, TM, PH##_##end##_p, \ - MOEND, helper_##end##_##PT##_mmu) +#define DO_ST_PRIM_1(NAME, H, TE, TM) \ + DO_ST_TLB(st1##NAME, H, TE, TM, cpu_stb_data_ra) -DO_LD_PRIM_2(ld1hh, le, MO_LE, H1_2, uint16_t, uint16_t, lduw, lduw) -DO_LD_PRIM_2(ld1hsu, le, MO_LE, H1_4, uint32_t, uint16_t, lduw, lduw) -DO_LD_PRIM_2(ld1hss, le, MO_LE, H1_4, uint32_t, int16_t, lduw, lduw) -DO_LD_PRIM_2(ld1hdu, le, MO_LE, , uint64_t, uint16_t, lduw, lduw) -DO_LD_PRIM_2(ld1hds, le, MO_LE, , uint64_t, int16_t, lduw, lduw) +DO_ST_PRIM_1(bb, H1, uint8_t, uint8_t) +DO_ST_PRIM_1(bh, H1_2, uint16_t, uint8_t) +DO_ST_PRIM_1(bs, H1_4, uint32_t, uint8_t) +DO_ST_PRIM_1(bd, , uint64_t, uint8_t) -DO_LD_PRIM_2(ld1ss, le, MO_LE, H1_4, uint32_t, uint32_t, ldl, ldul) -DO_LD_PRIM_2(ld1sdu, le, MO_LE, , uint64_t, uint32_t, ldl, ldul) -DO_LD_PRIM_2(ld1sds, le, MO_LE, , uint64_t, int32_t, ldl, ldul) +#define DO_LD_PRIM_2(NAME, H, TE, TM, LD) \ + DO_LD_HOST(ld1##NAME##_be, H, TE, TM, LD##_be_p) \ + DO_LD_HOST(ld1##NAME##_le, H, TE, TM, LD##_le_p) \ + DO_LD_TLB(ld1##NAME##_be, H, TE, TM, cpu_##LD##_be_data_ra) \ + DO_LD_TLB(ld1##NAME##_le, H, TE, TM, cpu_##LD##_le_data_ra) -DO_LD_PRIM_2(ld1dd, le, MO_LE, , uint64_t, uint64_t, ldq, ldq) +#define DO_ST_PRIM_2(NAME, H, TE, TM, ST) \ + DO_ST_TLB(st1##NAME##_be, H, TE, TM, cpu_##ST##_be_data_ra) \ + DO_ST_TLB(st1##NAME##_le, H, TE, TM, cpu_##ST##_le_data_ra) -DO_LD_PRIM_2(ld1hh, be, MO_BE, H1_2, uint16_t, uint16_t, lduw, lduw) -DO_LD_PRIM_2(ld1hsu, be, MO_BE, H1_4, uint32_t, uint16_t, lduw, lduw) -DO_LD_PRIM_2(ld1hss, be, MO_BE, H1_4, uint32_t, int16_t, lduw, lduw) -DO_LD_PRIM_2(ld1hdu, be, MO_BE, , uint64_t, uint16_t, lduw, lduw) -DO_LD_PRIM_2(ld1hds, be, MO_BE, , uint64_t, int16_t, lduw, lduw) +DO_LD_PRIM_2(hh, H1_2, uint16_t, uint16_t, lduw) +DO_LD_PRIM_2(hsu, H1_4, uint32_t, uint16_t, lduw) +DO_LD_PRIM_2(hss, H1_4, uint32_t, int16_t, lduw) +DO_LD_PRIM_2(hdu, , uint64_t, uint16_t, lduw) +DO_LD_PRIM_2(hds, , uint64_t, int16_t, lduw) -DO_LD_PRIM_2(ld1ss, be, MO_BE, H1_4, uint32_t, uint32_t, ldl, ldul) -DO_LD_PRIM_2(ld1sdu, be, MO_BE, , uint64_t, uint32_t, ldl, ldul) -DO_LD_PRIM_2(ld1sds, be, MO_BE, , uint64_t, int32_t, ldl, ldul) +DO_ST_PRIM_2(hh, H1_2, uint16_t, uint16_t, stw) +DO_ST_PRIM_2(hs, H1_4, uint32_t, uint16_t, stw) +DO_ST_PRIM_2(hd, , uint64_t, uint16_t, stw) -DO_LD_PRIM_2(ld1dd, be, MO_BE, , uint64_t, uint64_t, ldq, ldq) +DO_LD_PRIM_2(ss, H1_4, uint32_t, uint32_t, ldl) +DO_LD_PRIM_2(sdu, , uint64_t, uint32_t, ldl) +DO_LD_PRIM_2(sds, , uint64_t, int32_t, ldl) + +DO_ST_PRIM_2(ss, H1_4, uint32_t, uint32_t, stl) +DO_ST_PRIM_2(sd, , uint64_t, uint32_t, stl) + +DO_LD_PRIM_2(dd, , uint64_t, uint64_t, ldq) +DO_ST_PRIM_2(dd, , uint64_t, uint64_t, stq) #undef DO_LD_TLB +#undef DO_ST_TLB #undef DO_LD_HOST #undef DO_LD_PRIM_1 +#undef DO_ST_PRIM_1 #undef DO_LD_PRIM_2 +#undef DO_ST_PRIM_2 /* * Skip through a sequence of inactive elements in the guarding predicate @vg, @@ -4152,7 +4159,7 @@ static void sve_ld1_r(CPUARMState *env, void *vg, const target_ulong addr, uint32_t desc, const uintptr_t retaddr, const int esz, const int msz, sve_ld1_host_fn *host_fn, - sve_ld1_tlb_fn *tlb_fn) + sve_ldst1_tlb_fn *tlb_fn) { const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const int mmu_idx = get_mmuidx(oi); @@ -4234,7 +4241,7 @@ static void sve_ld1_r(CPUARMState *env, void *vg, const target_ulong addr, * on I/O memory, it may succeed but not bring in the TLB entry. * But even then we have still made forward progress. */ - tlb_fn(env, &scratch, reg_off, addr + mem_off, oi, retaddr); + tlb_fn(env, &scratch, reg_off, addr + mem_off, retaddr); reg_off += 1 << esz; } #endif @@ -4293,9 +4300,8 @@ DO_LD1_2(ld1dd, 3, 3) */ static void sve_ld2_r(CPUARMState *env, void *vg, target_ulong addr, uint32_t desc, int size, uintptr_t ra, - sve_ld1_tlb_fn *tlb_fn) + sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); intptr_t i, oprsz = simd_oprsz(desc); ARMVectorReg scratch[2] = { }; @@ -4305,8 +4311,8 @@ static void sve_ld2_r(CPUARMState *env, void *vg, target_ulong addr, uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { if (pg & 1) { - tlb_fn(env, &scratch[0], i, addr, oi, ra); - tlb_fn(env, &scratch[1], i, addr + size, oi, ra); + tlb_fn(env, &scratch[0], i, addr, ra); + tlb_fn(env, &scratch[1], i, addr + size, ra); } i += size, pg >>= size; addr += 2 * size; @@ -4321,9 +4327,8 @@ static void sve_ld2_r(CPUARMState *env, void *vg, target_ulong addr, static void sve_ld3_r(CPUARMState *env, void *vg, target_ulong addr, uint32_t desc, int size, uintptr_t ra, - sve_ld1_tlb_fn *tlb_fn) + sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); intptr_t i, oprsz = simd_oprsz(desc); ARMVectorReg scratch[3] = { }; @@ -4333,9 +4338,9 @@ static void sve_ld3_r(CPUARMState *env, void *vg, target_ulong addr, uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { if (pg & 1) { - tlb_fn(env, &scratch[0], i, addr, oi, ra); - tlb_fn(env, &scratch[1], i, addr + size, oi, ra); - tlb_fn(env, &scratch[2], i, addr + 2 * size, oi, ra); + tlb_fn(env, &scratch[0], i, addr, ra); + tlb_fn(env, &scratch[1], i, addr + size, ra); + tlb_fn(env, &scratch[2], i, addr + 2 * size, ra); } i += size, pg >>= size; addr += 3 * size; @@ -4351,9 +4356,8 @@ static void sve_ld3_r(CPUARMState *env, void *vg, target_ulong addr, static void sve_ld4_r(CPUARMState *env, void *vg, target_ulong addr, uint32_t desc, int size, uintptr_t ra, - sve_ld1_tlb_fn *tlb_fn) + sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); intptr_t i, oprsz = simd_oprsz(desc); ARMVectorReg scratch[4] = { }; @@ -4363,10 +4367,10 @@ static void sve_ld4_r(CPUARMState *env, void *vg, target_ulong addr, uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { if (pg & 1) { - tlb_fn(env, &scratch[0], i, addr, oi, ra); - tlb_fn(env, &scratch[1], i, addr + size, oi, ra); - tlb_fn(env, &scratch[2], i, addr + 2 * size, oi, ra); - tlb_fn(env, &scratch[3], i, addr + 3 * size, oi, ra); + tlb_fn(env, &scratch[0], i, addr, ra); + tlb_fn(env, &scratch[1], i, addr + size, ra); + tlb_fn(env, &scratch[2], i, addr + 2 * size, ra); + tlb_fn(env, &scratch[3], i, addr + 3 * size, ra); } i += size, pg >>= size; addr += 4 * size; @@ -4459,7 +4463,7 @@ static void sve_ldff1_r(CPUARMState *env, void *vg, const target_ulong addr, uint32_t desc, const uintptr_t retaddr, const int esz, const int msz, sve_ld1_host_fn *host_fn, - sve_ld1_tlb_fn *tlb_fn) + sve_ldst1_tlb_fn *tlb_fn) { const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const int mmu_idx = get_mmuidx(oi); @@ -4519,7 +4523,7 @@ static void sve_ldff1_r(CPUARMState *env, void *vg, const target_ulong addr, * Perform one normal read, which will fault or not. * But it is likely to bring the page into the tlb. */ - tlb_fn(env, vd, reg_off, addr + mem_off, oi, retaddr); + tlb_fn(env, vd, reg_off, addr + mem_off, retaddr); /* After any fault, zero any leading predicated false elts. */ swap_memzero(vd, reg_off); @@ -4671,60 +4675,14 @@ DO_LDFF1_LDNF1_2(dd, 3, 3) #undef DO_LDFF1_LDNF1_1 #undef DO_LDFF1_LDNF1_2 -/* - * Store contiguous data, protected by a governing predicate. - */ - -#ifdef CONFIG_SOFTMMU -#define DO_ST_TLB(NAME, H, TYPEM, HOST, MOEND, TLB) \ -static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \ - target_ulong addr, TCGMemOpIdx oi, uintptr_t ra) \ -{ \ - TLB(env, addr, *(TYPEM *)(vd + H(reg_off)), oi, ra); \ -} -#else -#define DO_ST_TLB(NAME, H, TYPEM, HOST, MOEND, TLB) \ -static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \ - target_ulong addr, TCGMemOpIdx oi, uintptr_t ra) \ -{ \ - HOST(g2h(addr), *(TYPEM *)(vd + H(reg_off))); \ -} -#endif - -DO_ST_TLB(st1bb, H1, uint8_t, stb_p, 0, helper_ret_stb_mmu) -DO_ST_TLB(st1bh, H1_2, uint16_t, stb_p, 0, helper_ret_stb_mmu) -DO_ST_TLB(st1bs, H1_4, uint32_t, stb_p, 0, helper_ret_stb_mmu) -DO_ST_TLB(st1bd, , uint64_t, stb_p, 0, helper_ret_stb_mmu) - -DO_ST_TLB(st1hh_le, H1_2, uint16_t, stw_le_p, MO_LE, helper_le_stw_mmu) -DO_ST_TLB(st1hs_le, H1_4, uint32_t, stw_le_p, MO_LE, helper_le_stw_mmu) -DO_ST_TLB(st1hd_le, , uint64_t, stw_le_p, MO_LE, helper_le_stw_mmu) - -DO_ST_TLB(st1ss_le, H1_4, uint32_t, stl_le_p, MO_LE, helper_le_stl_mmu) -DO_ST_TLB(st1sd_le, , uint64_t, stl_le_p, MO_LE, helper_le_stl_mmu) - -DO_ST_TLB(st1dd_le, , uint64_t, stq_le_p, MO_LE, helper_le_stq_mmu) - -DO_ST_TLB(st1hh_be, H1_2, uint16_t, stw_be_p, MO_BE, helper_be_stw_mmu) -DO_ST_TLB(st1hs_be, H1_4, uint32_t, stw_be_p, MO_BE, helper_be_stw_mmu) -DO_ST_TLB(st1hd_be, , uint64_t, stw_be_p, MO_BE, helper_be_stw_mmu) - -DO_ST_TLB(st1ss_be, H1_4, uint32_t, stl_be_p, MO_BE, helper_be_stl_mmu) -DO_ST_TLB(st1sd_be, , uint64_t, stl_be_p, MO_BE, helper_be_stl_mmu) - -DO_ST_TLB(st1dd_be, , uint64_t, stq_be_p, MO_BE, helper_be_stq_mmu) - -#undef DO_ST_TLB - /* * Common helpers for all contiguous 1,2,3,4-register predicated stores. */ static void sve_st1_r(CPUARMState *env, void *vg, target_ulong addr, uint32_t desc, const uintptr_t ra, const int esize, const int msize, - sve_st1_tlb_fn *tlb_fn) + sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); intptr_t i, oprsz = simd_oprsz(desc); void *vd = &env->vfp.zregs[rd]; @@ -4734,7 +4692,7 @@ static void sve_st1_r(CPUARMState *env, void *vg, target_ulong addr, uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { if (pg & 1) { - tlb_fn(env, vd, i, addr, oi, ra); + tlb_fn(env, vd, i, addr, ra); } i += esize, pg >>= esize; addr += msize; @@ -4746,9 +4704,8 @@ static void sve_st1_r(CPUARMState *env, void *vg, target_ulong addr, static void sve_st2_r(CPUARMState *env, void *vg, target_ulong addr, uint32_t desc, const uintptr_t ra, const int esize, const int msize, - sve_st1_tlb_fn *tlb_fn) + sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); intptr_t i, oprsz = simd_oprsz(desc); void *d1 = &env->vfp.zregs[rd]; @@ -4759,8 +4716,8 @@ static void sve_st2_r(CPUARMState *env, void *vg, target_ulong addr, uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { if (pg & 1) { - tlb_fn(env, d1, i, addr, oi, ra); - tlb_fn(env, d2, i, addr + msize, oi, ra); + tlb_fn(env, d1, i, addr, ra); + tlb_fn(env, d2, i, addr + msize, ra); } i += esize, pg >>= esize; addr += 2 * msize; @@ -4772,9 +4729,8 @@ static void sve_st2_r(CPUARMState *env, void *vg, target_ulong addr, static void sve_st3_r(CPUARMState *env, void *vg, target_ulong addr, uint32_t desc, const uintptr_t ra, const int esize, const int msize, - sve_st1_tlb_fn *tlb_fn) + sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); intptr_t i, oprsz = simd_oprsz(desc); void *d1 = &env->vfp.zregs[rd]; @@ -4786,9 +4742,9 @@ static void sve_st3_r(CPUARMState *env, void *vg, target_ulong addr, uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { if (pg & 1) { - tlb_fn(env, d1, i, addr, oi, ra); - tlb_fn(env, d2, i, addr + msize, oi, ra); - tlb_fn(env, d3, i, addr + 2 * msize, oi, ra); + tlb_fn(env, d1, i, addr, ra); + tlb_fn(env, d2, i, addr + msize, ra); + tlb_fn(env, d3, i, addr + 2 * msize, ra); } i += esize, pg >>= esize; addr += 3 * msize; @@ -4800,9 +4756,8 @@ static void sve_st3_r(CPUARMState *env, void *vg, target_ulong addr, static void sve_st4_r(CPUARMState *env, void *vg, target_ulong addr, uint32_t desc, const uintptr_t ra, const int esize, const int msize, - sve_st1_tlb_fn *tlb_fn) + sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); intptr_t i, oprsz = simd_oprsz(desc); void *d1 = &env->vfp.zregs[rd]; @@ -4815,10 +4770,10 @@ static void sve_st4_r(CPUARMState *env, void *vg, target_ulong addr, uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { if (pg & 1) { - tlb_fn(env, d1, i, addr, oi, ra); - tlb_fn(env, d2, i, addr + msize, oi, ra); - tlb_fn(env, d3, i, addr + 2 * msize, oi, ra); - tlb_fn(env, d4, i, addr + 3 * msize, oi, ra); + tlb_fn(env, d1, i, addr, ra); + tlb_fn(env, d2, i, addr + msize, ra); + tlb_fn(env, d3, i, addr + 2 * msize, ra); + tlb_fn(env, d4, i, addr + 3 * msize, ra); } i += esize, pg >>= esize; addr += 4 * msize; @@ -4914,9 +4869,8 @@ static target_ulong off_zd_d(void *reg, intptr_t reg_ofs) static void sve_ld1_zs(CPUARMState *env, void *vd, void *vg, void *vm, target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ld1_tlb_fn *tlb_fn) + zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); intptr_t i, oprsz = simd_oprsz(desc); ARMVectorReg scratch = { }; @@ -4927,7 +4881,7 @@ static void sve_ld1_zs(CPUARMState *env, void *vd, void *vg, void *vm, do { if (likely(pg & 1)) { target_ulong off = off_fn(vm, i); - tlb_fn(env, &scratch, i, base + (off << scale), oi, ra); + tlb_fn(env, &scratch, i, base + (off << scale), ra); } i += 4, pg >>= 4; } while (i & 15); @@ -4940,9 +4894,8 @@ static void sve_ld1_zs(CPUARMState *env, void *vd, void *vg, void *vm, static void sve_ld1_zd(CPUARMState *env, void *vd, void *vg, void *vm, target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ld1_tlb_fn *tlb_fn) + zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); intptr_t i, oprsz = simd_oprsz(desc) / 8; ARMVectorReg scratch = { }; @@ -4952,7 +4905,7 @@ static void sve_ld1_zd(CPUARMState *env, void *vd, void *vg, void *vm, uint8_t pg = *(uint8_t *)(vg + H1(i)); if (likely(pg & 1)) { target_ulong off = off_fn(vm, i * 8); - tlb_fn(env, &scratch, i * 8, base + (off << scale), oi, ra); + tlb_fn(env, &scratch, i * 8, base + (off << scale), ra); } } clear_helper_retaddr(); @@ -5114,7 +5067,7 @@ DO_LD_NF(dd_be, , uint64_t, uint64_t, ldq_be_p) */ static inline void sve_ldff1_zs(CPUARMState *env, void *vd, void *vg, void *vm, target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ld1_tlb_fn *tlb_fn, + zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn, sve_ld1_nf_fn *nonfault_fn) { const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); @@ -5130,7 +5083,7 @@ static inline void sve_ldff1_zs(CPUARMState *env, void *vd, void *vg, void *vm, set_helper_retaddr(ra); addr = off_fn(vm, reg_off); addr = base + (addr << scale); - tlb_fn(env, vd, reg_off, addr, oi, ra); + tlb_fn(env, vd, reg_off, addr, ra); /* The rest of the reads will be non-faulting. */ clear_helper_retaddr(); @@ -5156,7 +5109,7 @@ static inline void sve_ldff1_zs(CPUARMState *env, void *vd, void *vg, void *vm, static inline void sve_ldff1_zd(CPUARMState *env, void *vd, void *vg, void *vm, target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ld1_tlb_fn *tlb_fn, + zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn, sve_ld1_nf_fn *nonfault_fn) { const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); @@ -5172,7 +5125,7 @@ static inline void sve_ldff1_zd(CPUARMState *env, void *vd, void *vg, void *vm, set_helper_retaddr(ra); addr = off_fn(vm, reg_off); addr = base + (addr << scale); - tlb_fn(env, vd, reg_off, addr, oi, ra); + tlb_fn(env, vd, reg_off, addr, ra); /* The rest of the reads will be non-faulting. */ clear_helper_retaddr(); @@ -5282,9 +5235,8 @@ DO_LDFF1_ZPZ_D(dd_be, zd) static void sve_st1_zs(CPUARMState *env, void *vd, void *vg, void *vm, target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ld1_tlb_fn *tlb_fn) + zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); intptr_t i, oprsz = simd_oprsz(desc); @@ -5294,7 +5246,7 @@ static void sve_st1_zs(CPUARMState *env, void *vd, void *vg, void *vm, do { if (likely(pg & 1)) { target_ulong off = off_fn(vm, i); - tlb_fn(env, vd, i, base + (off << scale), oi, ra); + tlb_fn(env, vd, i, base + (off << scale), ra); } i += 4, pg >>= 4; } while (i & 15); @@ -5304,9 +5256,8 @@ static void sve_st1_zs(CPUARMState *env, void *vd, void *vg, void *vm, static void sve_st1_zd(CPUARMState *env, void *vd, void *vg, void *vm, target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ld1_tlb_fn *tlb_fn) + zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); intptr_t i, oprsz = simd_oprsz(desc) / 8; @@ -5315,7 +5266,7 @@ static void sve_st1_zd(CPUARMState *env, void *vd, void *vg, void *vm, uint8_t pg = *(uint8_t *)(vg + H1(i)); if (likely(pg & 1)) { target_ulong off = off_fn(vm, i * 8); - tlb_fn(env, vd, i * 8, base + (off << scale), oi, ra); + tlb_fn(env, vd, i * 8, base + (off << scale), ra); } } clear_helper_retaddr(); From f32e2ab65f3a0fc03d58936709e5a565c4b0db50 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:48 -0700 Subject: [PATCH 0373/2595] target/arm: Drop manual handling of set/clear_helper_retaddr Since we converted back to cpu_*_data_ra, we do not need to do this ourselves. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 655bc9476f..aad2c8c237 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -4133,12 +4133,6 @@ static intptr_t max_for_page(target_ulong base, intptr_t mem_off, return MIN(split, mem_max - mem_off) + mem_off; } -#ifndef CONFIG_USER_ONLY -/* These are normally defined only for CONFIG_USER_ONLY in */ -static inline void set_helper_retaddr(uintptr_t ra) { } -static inline void clear_helper_retaddr(void) { } -#endif - /* * The result of tlb_vaddr_to_host for user-only is just g2h(x), * which is always non-null. Elide the useless test. @@ -4180,7 +4174,6 @@ static void sve_ld1_r(CPUARMState *env, void *vg, const target_ulong addr, return; } mem_off = reg_off >> diffsz; - set_helper_retaddr(retaddr); /* * If the (remaining) load is entirely within a single page, then: @@ -4195,7 +4188,6 @@ static void sve_ld1_r(CPUARMState *env, void *vg, const target_ulong addr, if (test_host_page(host)) { mem_off = host_fn(vd, vg, host - mem_off, mem_off, mem_max); tcg_debug_assert(mem_off == mem_max); - clear_helper_retaddr(); /* After having taken any fault, zero leading inactive elements. */ swap_memzero(vd, reg_off); return; @@ -4246,7 +4238,6 @@ static void sve_ld1_r(CPUARMState *env, void *vg, const target_ulong addr, } #endif - clear_helper_retaddr(); memcpy(vd, &scratch, reg_max); } @@ -4306,7 +4297,6 @@ static void sve_ld2_r(CPUARMState *env, void *vg, target_ulong addr, intptr_t i, oprsz = simd_oprsz(desc); ARMVectorReg scratch[2] = { }; - set_helper_retaddr(ra); for (i = 0; i < oprsz; ) { uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { @@ -4318,7 +4308,6 @@ static void sve_ld2_r(CPUARMState *env, void *vg, target_ulong addr, addr += 2 * size; } while (i & 15); } - clear_helper_retaddr(); /* Wait until all exceptions have been raised to write back. */ memcpy(&env->vfp.zregs[rd], &scratch[0], oprsz); @@ -4333,7 +4322,6 @@ static void sve_ld3_r(CPUARMState *env, void *vg, target_ulong addr, intptr_t i, oprsz = simd_oprsz(desc); ARMVectorReg scratch[3] = { }; - set_helper_retaddr(ra); for (i = 0; i < oprsz; ) { uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { @@ -4346,7 +4334,6 @@ static void sve_ld3_r(CPUARMState *env, void *vg, target_ulong addr, addr += 3 * size; } while (i & 15); } - clear_helper_retaddr(); /* Wait until all exceptions have been raised to write back. */ memcpy(&env->vfp.zregs[rd], &scratch[0], oprsz); @@ -4362,7 +4349,6 @@ static void sve_ld4_r(CPUARMState *env, void *vg, target_ulong addr, intptr_t i, oprsz = simd_oprsz(desc); ARMVectorReg scratch[4] = { }; - set_helper_retaddr(ra); for (i = 0; i < oprsz; ) { uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { @@ -4376,7 +4362,6 @@ static void sve_ld4_r(CPUARMState *env, void *vg, target_ulong addr, addr += 4 * size; } while (i & 15); } - clear_helper_retaddr(); /* Wait until all exceptions have been raised to write back. */ memcpy(&env->vfp.zregs[rd], &scratch[0], oprsz); @@ -4483,7 +4468,6 @@ static void sve_ldff1_r(CPUARMState *env, void *vg, const target_ulong addr, return; } mem_off = reg_off >> diffsz; - set_helper_retaddr(retaddr); /* * If the (remaining) load is entirely within a single page, then: @@ -4498,7 +4482,6 @@ static void sve_ldff1_r(CPUARMState *env, void *vg, const target_ulong addr, if (test_host_page(host)) { mem_off = host_fn(vd, vg, host - mem_off, mem_off, mem_max); tcg_debug_assert(mem_off == mem_max); - clear_helper_retaddr(); /* After any fault, zero any leading inactive elements. */ swap_memzero(vd, reg_off); return; @@ -4541,7 +4524,6 @@ static void sve_ldff1_r(CPUARMState *env, void *vg, const target_ulong addr, } #endif - clear_helper_retaddr(); record_fault(env, reg_off, reg_max); } @@ -4687,7 +4669,6 @@ static void sve_st1_r(CPUARMState *env, void *vg, target_ulong addr, intptr_t i, oprsz = simd_oprsz(desc); void *vd = &env->vfp.zregs[rd]; - set_helper_retaddr(ra); for (i = 0; i < oprsz; ) { uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { @@ -4698,7 +4679,6 @@ static void sve_st1_r(CPUARMState *env, void *vg, target_ulong addr, addr += msize; } while (i & 15); } - clear_helper_retaddr(); } static void sve_st2_r(CPUARMState *env, void *vg, target_ulong addr, @@ -4711,7 +4691,6 @@ static void sve_st2_r(CPUARMState *env, void *vg, target_ulong addr, void *d1 = &env->vfp.zregs[rd]; void *d2 = &env->vfp.zregs[(rd + 1) & 31]; - set_helper_retaddr(ra); for (i = 0; i < oprsz; ) { uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { @@ -4723,7 +4702,6 @@ static void sve_st2_r(CPUARMState *env, void *vg, target_ulong addr, addr += 2 * msize; } while (i & 15); } - clear_helper_retaddr(); } static void sve_st3_r(CPUARMState *env, void *vg, target_ulong addr, @@ -4737,7 +4715,6 @@ static void sve_st3_r(CPUARMState *env, void *vg, target_ulong addr, void *d2 = &env->vfp.zregs[(rd + 1) & 31]; void *d3 = &env->vfp.zregs[(rd + 2) & 31]; - set_helper_retaddr(ra); for (i = 0; i < oprsz; ) { uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { @@ -4750,7 +4727,6 @@ static void sve_st3_r(CPUARMState *env, void *vg, target_ulong addr, addr += 3 * msize; } while (i & 15); } - clear_helper_retaddr(); } static void sve_st4_r(CPUARMState *env, void *vg, target_ulong addr, @@ -4765,7 +4741,6 @@ static void sve_st4_r(CPUARMState *env, void *vg, target_ulong addr, void *d3 = &env->vfp.zregs[(rd + 2) & 31]; void *d4 = &env->vfp.zregs[(rd + 3) & 31]; - set_helper_retaddr(ra); for (i = 0; i < oprsz; ) { uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { @@ -4779,7 +4754,6 @@ static void sve_st4_r(CPUARMState *env, void *vg, target_ulong addr, addr += 4 * msize; } while (i & 15); } - clear_helper_retaddr(); } #define DO_STN_1(N, NAME, ESIZE) \ @@ -4875,7 +4849,6 @@ static void sve_ld1_zs(CPUARMState *env, void *vd, void *vg, void *vm, intptr_t i, oprsz = simd_oprsz(desc); ARMVectorReg scratch = { }; - set_helper_retaddr(ra); for (i = 0; i < oprsz; ) { uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { @@ -4886,7 +4859,6 @@ static void sve_ld1_zs(CPUARMState *env, void *vd, void *vg, void *vm, i += 4, pg >>= 4; } while (i & 15); } - clear_helper_retaddr(); /* Wait until all exceptions have been raised to write back. */ memcpy(vd, &scratch, oprsz); @@ -4900,7 +4872,6 @@ static void sve_ld1_zd(CPUARMState *env, void *vd, void *vg, void *vm, intptr_t i, oprsz = simd_oprsz(desc) / 8; ARMVectorReg scratch = { }; - set_helper_retaddr(ra); for (i = 0; i < oprsz; i++) { uint8_t pg = *(uint8_t *)(vg + H1(i)); if (likely(pg & 1)) { @@ -4908,7 +4879,6 @@ static void sve_ld1_zd(CPUARMState *env, void *vd, void *vg, void *vm, tlb_fn(env, &scratch, i * 8, base + (off << scale), ra); } } - clear_helper_retaddr(); /* Wait until all exceptions have been raised to write back. */ memcpy(vd, &scratch, oprsz * 8); @@ -5080,13 +5050,11 @@ static inline void sve_ldff1_zs(CPUARMState *env, void *vd, void *vg, void *vm, reg_off = find_next_active(vg, 0, reg_max, MO_32); if (likely(reg_off < reg_max)) { /* Perform one normal read, which will fault or not. */ - set_helper_retaddr(ra); addr = off_fn(vm, reg_off); addr = base + (addr << scale); tlb_fn(env, vd, reg_off, addr, ra); /* The rest of the reads will be non-faulting. */ - clear_helper_retaddr(); } /* After any fault, zero the leading predicated false elements. */ @@ -5122,13 +5090,11 @@ static inline void sve_ldff1_zd(CPUARMState *env, void *vd, void *vg, void *vm, reg_off = find_next_active(vg, 0, reg_max, MO_64); if (likely(reg_off < reg_max)) { /* Perform one normal read, which will fault or not. */ - set_helper_retaddr(ra); addr = off_fn(vm, reg_off); addr = base + (addr << scale); tlb_fn(env, vd, reg_off, addr, ra); /* The rest of the reads will be non-faulting. */ - clear_helper_retaddr(); } /* After any fault, zero the leading predicated false elements. */ @@ -5240,7 +5206,6 @@ static void sve_st1_zs(CPUARMState *env, void *vd, void *vg, void *vm, const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); intptr_t i, oprsz = simd_oprsz(desc); - set_helper_retaddr(ra); for (i = 0; i < oprsz; ) { uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); do { @@ -5251,7 +5216,6 @@ static void sve_st1_zs(CPUARMState *env, void *vd, void *vg, void *vm, i += 4, pg >>= 4; } while (i & 15); } - clear_helper_retaddr(); } static void sve_st1_zd(CPUARMState *env, void *vd, void *vg, void *vm, @@ -5261,7 +5225,6 @@ static void sve_st1_zd(CPUARMState *env, void *vd, void *vg, void *vm, const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); intptr_t i, oprsz = simd_oprsz(desc) / 8; - set_helper_retaddr(ra); for (i = 0; i < oprsz; i++) { uint8_t pg = *(uint8_t *)(vg + H1(i)); if (likely(pg & 1)) { @@ -5269,7 +5232,6 @@ static void sve_st1_zd(CPUARMState *env, void *vd, void *vg, void *vm, tlb_fn(env, vd, i * 8, base + (off << scale), ra); } } - clear_helper_retaddr(); } #define DO_ST1_ZPZ_S(MEM, OFS) \ From b4cd95d2f4c7197b844f51b29871d888063ea3e7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:49 -0700 Subject: [PATCH 0374/2595] target/arm: Add sve infrastructure for page lookup For contiguous predicated memory operations, we want to minimize the number of tlb lookups performed. We have open-coded this for sve_ld1_r, but for correctness with MTE we will need this for all of the memory operations. Create a structure that holds the bounds of active elements, and metadata for two pages. Add routines to find those active elements, lookup the pages, and run watchpoints for those pages. Temporarily mark the functions unused to avoid Werror. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 263 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 261 insertions(+), 2 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index aad2c8c237..2f053a9152 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -1630,7 +1630,7 @@ void HELPER(sve_cpy_z_d)(void *vd, void *vg, uint64_t val, uint32_t desc) } } -/* Big-endian hosts need to frob the byte indicies. If the copy +/* Big-endian hosts need to frob the byte indices. If the copy * happens to be 8-byte aligned, then no frobbing necessary. */ static void swap_memmove(void *vd, void *vs, size_t n) @@ -3974,7 +3974,7 @@ void HELPER(sve_fcmla_zpzzz_d)(CPUARMState *env, void *vg, uint32_t desc) /* * Load elements into @vd, controlled by @vg, from @host + @mem_ofs. * Memory is valid through @host + @mem_max. The register element - * indicies are inferred from @mem_ofs, as modified by the types for + * indices are inferred from @mem_ofs, as modified by the types for * which the helper is built. Return the @mem_ofs of the first element * not loaded (which is @mem_max if they are all loaded). * @@ -4133,6 +4133,265 @@ static intptr_t max_for_page(target_ulong base, intptr_t mem_off, return MIN(split, mem_max - mem_off) + mem_off; } +/* + * Resolve the guest virtual address to info->host and info->flags. + * If @nofault, return false if the page is invalid, otherwise + * exit via page fault exception. + */ + +typedef struct { + void *host; + int flags; + MemTxAttrs attrs; +} SVEHostPage; + +static bool sve_probe_page(SVEHostPage *info, bool nofault, + CPUARMState *env, target_ulong addr, + int mem_off, MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr) +{ + int flags; + + addr += mem_off; + flags = probe_access_flags(env, addr, access_type, mmu_idx, nofault, + &info->host, retaddr); + info->flags = flags; + + if (flags & TLB_INVALID_MASK) { + g_assert(nofault); + return false; + } + + /* Ensure that info->host[] is relative to addr, not addr + mem_off. */ + info->host -= mem_off; + +#ifdef CONFIG_USER_ONLY + memset(&info->attrs, 0, sizeof(info->attrs)); +#else + /* + * Find the iotlbentry for addr and return the transaction attributes. + * This *must* be present in the TLB because we just found the mapping. + */ + { + uintptr_t index = tlb_index(env, mmu_idx, addr); + +# ifdef CONFIG_DEBUG_TCG + CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); + target_ulong comparator = (access_type == MMU_DATA_LOAD + ? entry->addr_read + : tlb_addr_write(entry)); + g_assert(tlb_hit(comparator, addr)); +# endif + + CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; + info->attrs = iotlbentry->attrs; + } +#endif + + return true; +} + + +/* + * Analyse contiguous data, protected by a governing predicate. + */ + +typedef enum { + FAULT_NO, + FAULT_FIRST, + FAULT_ALL, +} SVEContFault; + +typedef struct { + /* + * First and last element wholly contained within the two pages. + * mem_off_first[0] and reg_off_first[0] are always set >= 0. + * reg_off_last[0] may be < 0 if the first element crosses pages. + * All of mem_off_first[1], reg_off_first[1] and reg_off_last[1] + * are set >= 0 only if there are complete elements on a second page. + * + * The reg_off_* offsets are relative to the internal vector register. + * The mem_off_first offset is relative to the memory address; the + * two offsets are different when a load operation extends, a store + * operation truncates, or for multi-register operations. + */ + int16_t mem_off_first[2]; + int16_t reg_off_first[2]; + int16_t reg_off_last[2]; + + /* + * One element that is misaligned and spans both pages, + * or -1 if there is no such active element. + */ + int16_t mem_off_split; + int16_t reg_off_split; + + /* + * The byte offset at which the entire operation crosses a page boundary. + * Set >= 0 if and only if the entire operation spans two pages. + */ + int16_t page_split; + + /* TLB data for the two pages. */ + SVEHostPage page[2]; +} SVEContLdSt; + +/* + * Find first active element on each page, and a loose bound for the + * final element on each page. Identify any single element that spans + * the page boundary. Return true if there are any active elements. + */ +static bool __attribute__((unused)) +sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg, + intptr_t reg_max, int esz, int msize) +{ + const int esize = 1 << esz; + const uint64_t pg_mask = pred_esz_masks[esz]; + intptr_t reg_off_first = -1, reg_off_last = -1, reg_off_split; + intptr_t mem_off_last, mem_off_split; + intptr_t page_split, elt_split; + intptr_t i; + + /* Set all of the element indices to -1, and the TLB data to 0. */ + memset(info, -1, offsetof(SVEContLdSt, page)); + memset(info->page, 0, sizeof(info->page)); + + /* Gross scan over the entire predicate to find bounds. */ + i = 0; + do { + uint64_t pg = vg[i] & pg_mask; + if (pg) { + reg_off_last = i * 64 + 63 - clz64(pg); + if (reg_off_first < 0) { + reg_off_first = i * 64 + ctz64(pg); + } + } + } while (++i * 64 < reg_max); + + if (unlikely(reg_off_first < 0)) { + /* No active elements, no pages touched. */ + return false; + } + tcg_debug_assert(reg_off_last >= 0 && reg_off_last < reg_max); + + info->reg_off_first[0] = reg_off_first; + info->mem_off_first[0] = (reg_off_first >> esz) * msize; + mem_off_last = (reg_off_last >> esz) * msize; + + page_split = -(addr | TARGET_PAGE_MASK); + if (likely(mem_off_last + msize <= page_split)) { + /* The entire operation fits within a single page. */ + info->reg_off_last[0] = reg_off_last; + return true; + } + + info->page_split = page_split; + elt_split = page_split / msize; + reg_off_split = elt_split << esz; + mem_off_split = elt_split * msize; + + /* + * This is the last full element on the first page, but it is not + * necessarily active. If there is no full element, i.e. the first + * active element is the one that's split, this value remains -1. + * It is useful as iteration bounds. + */ + if (elt_split != 0) { + info->reg_off_last[0] = reg_off_split - esize; + } + + /* Determine if an unaligned element spans the pages. */ + if (page_split % msize != 0) { + /* It is helpful to know if the split element is active. */ + if ((vg[reg_off_split >> 6] >> (reg_off_split & 63)) & 1) { + info->reg_off_split = reg_off_split; + info->mem_off_split = mem_off_split; + + if (reg_off_split == reg_off_last) { + /* The page crossing element is last. */ + return true; + } + } + reg_off_split += esize; + mem_off_split += msize; + } + + /* + * We do want the first active element on the second page, because + * this may affect the address reported in an exception. + */ + reg_off_split = find_next_active(vg, reg_off_split, reg_max, esz); + tcg_debug_assert(reg_off_split <= reg_off_last); + info->reg_off_first[1] = reg_off_split; + info->mem_off_first[1] = (reg_off_split >> esz) * msize; + info->reg_off_last[1] = reg_off_last; + return true; +} + +/* + * Resolve the guest virtual addresses to info->page[]. + * Control the generation of page faults with @fault. Return false if + * there is no work to do, which can only happen with @fault == FAULT_NO. + */ +static bool __attribute__((unused)) +sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, CPUARMState *env, + target_ulong addr, MMUAccessType access_type, + uintptr_t retaddr) +{ + int mmu_idx = cpu_mmu_index(env, false); + int mem_off = info->mem_off_first[0]; + bool nofault = fault == FAULT_NO; + bool have_work = true; + + if (!sve_probe_page(&info->page[0], nofault, env, addr, mem_off, + access_type, mmu_idx, retaddr)) { + /* No work to be done. */ + return false; + } + + if (likely(info->page_split < 0)) { + /* The entire operation was on the one page. */ + return true; + } + + /* + * If the second page is invalid, then we want the fault address to be + * the first byte on that page which is accessed. + */ + if (info->mem_off_split >= 0) { + /* + * There is an element split across the pages. The fault address + * should be the first byte of the second page. + */ + mem_off = info->page_split; + /* + * If the split element is also the first active element + * of the vector, then: For first-fault we should continue + * to generate faults for the second page. For no-fault, + * we have work only if the second page is valid. + */ + if (info->mem_off_first[0] < info->mem_off_split) { + nofault = FAULT_FIRST; + have_work = false; + } + } else { + /* + * There is no element split across the pages. The fault address + * should be the first active element on the second page. + */ + mem_off = info->mem_off_first[1]; + /* + * There must have been one active element on the first page, + * so we're out of first-fault territory. + */ + nofault = fault != FAULT_ALL; + } + + have_work |= sve_probe_page(&info->page[1], nofault, env, addr, mem_off, + access_type, mmu_idx, retaddr); + return have_work; +} + /* * The result of tlb_vaddr_to_host for user-only is just g2h(x), * which is always non-null. Elide the useless test. From cf4a49b71b1712142d7122025a8ca7ea5b59d73f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:50 -0700 Subject: [PATCH 0375/2595] target/arm: Adjust interface of sve_ld1_host_fn The current interface includes a loop; change it to load a single element. We will then be able to use the function for ld{2,3,4} where individual vector elements are not adjacent. Replace each call with the simplest possible loop over active elements. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 124 ++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 61 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 2f053a9152..d007137735 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -3972,20 +3972,10 @@ void HELPER(sve_fcmla_zpzzz_d)(CPUARMState *env, void *vg, uint32_t desc) */ /* - * Load elements into @vd, controlled by @vg, from @host + @mem_ofs. - * Memory is valid through @host + @mem_max. The register element - * indices are inferred from @mem_ofs, as modified by the types for - * which the helper is built. Return the @mem_ofs of the first element - * not loaded (which is @mem_max if they are all loaded). - * - * For softmmu, we have fully validated the guest page. For user-only, - * we cannot fully validate without taking the mmap lock, but since we - * know the access is within one host page, if any access is valid they - * all must be valid. However, when @vg is all false, it may be that - * no access is valid. + * Load one element into @vd + @reg_off from @host. + * The controlling predicate is known to be true. */ -typedef intptr_t sve_ld1_host_fn(void *vd, void *vg, void *host, - intptr_t mem_ofs, intptr_t mem_max); +typedef void sve_ldst1_host_fn(void *vd, intptr_t reg_off, void *host); /* * Load one element into @vd + @reg_off from (@env, @vaddr, @ra). @@ -3999,20 +3989,10 @@ typedef void sve_ldst1_tlb_fn(CPUARMState *env, void *vd, intptr_t reg_off, */ #define DO_LD_HOST(NAME, H, TYPEE, TYPEM, HOST) \ -static intptr_t sve_##NAME##_host(void *vd, void *vg, void *host, \ - intptr_t mem_off, const intptr_t mem_max) \ -{ \ - intptr_t reg_off = mem_off * (sizeof(TYPEE) / sizeof(TYPEM)); \ - uint64_t *pg = vg; \ - while (mem_off + sizeof(TYPEM) <= mem_max) { \ - TYPEM val = 0; \ - if (likely((pg[reg_off >> 6] >> (reg_off & 63)) & 1)) { \ - val = HOST(host + mem_off); \ - } \ - *(TYPEE *)(vd + H(reg_off)) = val; \ - mem_off += sizeof(TYPEM), reg_off += sizeof(TYPEE); \ - } \ - return mem_off; \ +static void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ +{ \ + TYPEM val = HOST(host); \ + *(TYPEE *)(vd + H(reg_off)) = val; \ } #define DO_LD_TLB(NAME, H, TYPEE, TYPEM, TLB) \ @@ -4411,7 +4391,7 @@ static inline bool test_host_page(void *host) static void sve_ld1_r(CPUARMState *env, void *vg, const target_ulong addr, uint32_t desc, const uintptr_t retaddr, const int esz, const int msz, - sve_ld1_host_fn *host_fn, + sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) { const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); @@ -4445,8 +4425,12 @@ static void sve_ld1_r(CPUARMState *env, void *vg, const target_ulong addr, if (likely(split == mem_max)) { host = tlb_vaddr_to_host(env, addr + mem_off, MMU_DATA_LOAD, mmu_idx); if (test_host_page(host)) { - mem_off = host_fn(vd, vg, host - mem_off, mem_off, mem_max); - tcg_debug_assert(mem_off == mem_max); + intptr_t i = reg_off; + host -= mem_off; + do { + host_fn(vd, i, host + (i >> diffsz)); + i = find_next_active(vg, i + (1 << esz), reg_max, esz); + } while (i < reg_max); /* After having taken any fault, zero leading inactive elements. */ swap_memzero(vd, reg_off); return; @@ -4459,7 +4443,12 @@ static void sve_ld1_r(CPUARMState *env, void *vg, const target_ulong addr, */ #ifdef CONFIG_USER_ONLY swap_memzero(&scratch, reg_off); - host_fn(&scratch, vg, g2h(addr), mem_off, mem_max); + host = g2h(addr); + do { + host_fn(&scratch, reg_off, host + (reg_off >> diffsz)); + reg_off += 1 << esz; + reg_off = find_next_active(vg, reg_off, reg_max, esz); + } while (reg_off < reg_max); #else memset(&scratch, 0, reg_max); goto start; @@ -4477,9 +4466,13 @@ static void sve_ld1_r(CPUARMState *env, void *vg, const target_ulong addr, host = tlb_vaddr_to_host(env, addr + mem_off, MMU_DATA_LOAD, mmu_idx); if (host) { - mem_off = host_fn(&scratch, vg, host - mem_off, - mem_off, split); - reg_off = mem_off << diffsz; + host -= mem_off; + do { + host_fn(&scratch, reg_off, host + mem_off); + reg_off += 1 << esz; + reg_off = find_next_active(vg, reg_off, reg_max, esz); + mem_off = reg_off >> diffsz; + } while (split - mem_off >= (1 << msz)); continue; } } @@ -4706,7 +4699,7 @@ static void record_fault(CPUARMState *env, uintptr_t i, uintptr_t oprsz) static void sve_ldff1_r(CPUARMState *env, void *vg, const target_ulong addr, uint32_t desc, const uintptr_t retaddr, const int esz, const int msz, - sve_ld1_host_fn *host_fn, + sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) { const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); @@ -4716,7 +4709,7 @@ static void sve_ldff1_r(CPUARMState *env, void *vg, const target_ulong addr, const int diffsz = esz - msz; const intptr_t reg_max = simd_oprsz(desc); const intptr_t mem_max = reg_max >> diffsz; - intptr_t split, reg_off, mem_off; + intptr_t split, reg_off, mem_off, i; void *host; /* Skip to the first active element. */ @@ -4739,28 +4732,18 @@ static void sve_ldff1_r(CPUARMState *env, void *vg, const target_ulong addr, if (likely(split == mem_max)) { host = tlb_vaddr_to_host(env, addr + mem_off, MMU_DATA_LOAD, mmu_idx); if (test_host_page(host)) { - mem_off = host_fn(vd, vg, host - mem_off, mem_off, mem_max); - tcg_debug_assert(mem_off == mem_max); + i = reg_off; + host -= mem_off; + do { + host_fn(vd, i, host + (i >> diffsz)); + i = find_next_active(vg, i + (1 << esz), reg_max, esz); + } while (i < reg_max); /* After any fault, zero any leading inactive elements. */ swap_memzero(vd, reg_off); return; } } -#ifdef CONFIG_USER_ONLY - /* - * The page(s) containing this first element at ADDR+MEM_OFF must - * be valid. Considering that this first element may be misaligned - * and cross a page boundary itself, take the rest of the page from - * the last byte of the element. - */ - split = max_for_page(addr, mem_off + (1 << msz) - 1, mem_max); - mem_off = host_fn(vd, vg, g2h(addr), mem_off, split); - - /* After any fault, zero any leading inactive elements. */ - swap_memzero(vd, reg_off); - reg_off = mem_off << diffsz; -#else /* * Perform one normal read, which will fault or not. * But it is likely to bring the page into the tlb. @@ -4777,11 +4760,15 @@ static void sve_ldff1_r(CPUARMState *env, void *vg, const target_ulong addr, if (split >= (1 << msz)) { host = tlb_vaddr_to_host(env, addr + mem_off, MMU_DATA_LOAD, mmu_idx); if (host) { - mem_off = host_fn(vd, vg, host - mem_off, mem_off, split); - reg_off = mem_off << diffsz; + host -= mem_off; + do { + host_fn(vd, reg_off, host + mem_off); + reg_off += 1 << esz; + reg_off = find_next_active(vg, reg_off, reg_max, esz); + mem_off = reg_off >> diffsz; + } while (split - mem_off >= (1 << msz)); } } -#endif record_fault(env, reg_off, reg_max); } @@ -4791,7 +4778,7 @@ static void sve_ldff1_r(CPUARMState *env, void *vg, const target_ulong addr, */ static void sve_ldnf1_r(CPUARMState *env, void *vg, const target_ulong addr, uint32_t desc, const int esz, const int msz, - sve_ld1_host_fn *host_fn) + sve_ldst1_host_fn *host_fn) { const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); void *vd = &env->vfp.zregs[rd]; @@ -4806,7 +4793,13 @@ static void sve_ldnf1_r(CPUARMState *env, void *vg, const target_ulong addr, host = tlb_vaddr_to_host(env, addr, MMU_DATA_LOAD, mmu_idx); if (likely(page_check_range(addr, mem_max, PAGE_READ) == 0)) { /* The entire operation is valid and will not fault. */ - host_fn(vd, vg, host, 0, mem_max); + reg_off = 0; + do { + mem_off = reg_off >> diffsz; + host_fn(vd, reg_off, host + mem_off); + reg_off += 1 << esz; + reg_off = find_next_active(vg, reg_off, reg_max, esz); + } while (reg_off < reg_max); return; } #endif @@ -4826,8 +4819,12 @@ static void sve_ldnf1_r(CPUARMState *env, void *vg, const target_ulong addr, if (page_check_range(addr + mem_off, 1 << msz, PAGE_READ) == 0) { /* At least one load is valid; take the rest of the page. */ split = max_for_page(addr, mem_off + (1 << msz) - 1, mem_max); - mem_off = host_fn(vd, vg, host, mem_off, split); - reg_off = mem_off << diffsz; + do { + host_fn(vd, reg_off, host + mem_off); + reg_off += 1 << esz; + reg_off = find_next_active(vg, reg_off, reg_max, esz); + mem_off = reg_off >> diffsz; + } while (split - mem_off >= (1 << msz)); } #else /* @@ -4848,8 +4845,13 @@ static void sve_ldnf1_r(CPUARMState *env, void *vg, const target_ulong addr, host = tlb_vaddr_to_host(env, addr + mem_off, MMU_DATA_LOAD, mmu_idx); split = max_for_page(addr, mem_off, mem_max); if (host && split >= (1 << msz)) { - mem_off = host_fn(vd, vg, host - mem_off, mem_off, split); - reg_off = mem_off << diffsz; + host -= mem_off; + do { + host_fn(vd, reg_off, host + mem_off); + reg_off += 1 << esz; + reg_off = find_next_active(vg, reg_off, reg_max, esz); + mem_off = reg_off >> diffsz; + } while (split - mem_off >= (1 << msz)); } #endif From b854fd06a868e0308bcfe05ad0a71210705814c7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:51 -0700 Subject: [PATCH 0376/2595] target/arm: Use SVEContLdSt in sve_ld1_r First use of the new helper functions, so we can remove the unused markup. No longer need a scratch for user-only, as we completely probe the page set before reading; system mode still requires a scratch for MMIO. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 188 +++++++++++++++++++++------------------- 1 file changed, 97 insertions(+), 91 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index d007137735..6bae342a17 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -4221,9 +4221,9 @@ typedef struct { * final element on each page. Identify any single element that spans * the page boundary. Return true if there are any active elements. */ -static bool __attribute__((unused)) -sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg, - intptr_t reg_max, int esz, int msize) +static bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, + uint64_t *vg, intptr_t reg_max, + int esz, int msize) { const int esize = 1 << esz; const uint64_t pg_mask = pred_esz_masks[esz]; @@ -4313,10 +4313,9 @@ sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg, * Control the generation of page faults with @fault. Return false if * there is no work to do, which can only happen with @fault == FAULT_NO. */ -static bool __attribute__((unused)) -sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, CPUARMState *env, - target_ulong addr, MMUAccessType access_type, - uintptr_t retaddr) +static bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, + CPUARMState *env, target_ulong addr, + MMUAccessType access_type, uintptr_t retaddr) { int mmu_idx = cpu_mmu_index(env, false); int mem_off = info->mem_off_first[0]; @@ -4388,109 +4387,116 @@ static inline bool test_host_page(void *host) /* * Common helper for all contiguous one-register predicated loads. */ -static void sve_ld1_r(CPUARMState *env, void *vg, const target_ulong addr, - uint32_t desc, const uintptr_t retaddr, - const int esz, const int msz, - sve_ldst1_host_fn *host_fn, - sve_ldst1_tlb_fn *tlb_fn) +static inline QEMU_ALWAYS_INLINE +void sve_ld1_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, + uint32_t desc, const uintptr_t retaddr, + const int esz, const int msz, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); - const int mmu_idx = get_mmuidx(oi); const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); void *vd = &env->vfp.zregs[rd]; - const int diffsz = esz - msz; const intptr_t reg_max = simd_oprsz(desc); - const intptr_t mem_max = reg_max >> diffsz; - ARMVectorReg scratch; + intptr_t reg_off, reg_last, mem_off; + SVEContLdSt info; void *host; - intptr_t split, reg_off, mem_off; + int flags; - /* Find the first active element. */ - reg_off = find_next_active(vg, 0, reg_max, esz); - if (unlikely(reg_off == reg_max)) { + /* Find the active elements. */ + if (!sve_cont_ldst_elements(&info, addr, vg, reg_max, esz, 1 << msz)) { /* The entire predicate was false; no load occurs. */ memset(vd, 0, reg_max); return; } - mem_off = reg_off >> diffsz; - /* - * If the (remaining) load is entirely within a single page, then: - * For softmmu, and the tlb hits, then no faults will occur; - * For user-only, either the first load will fault or none will. - * We can thus perform the load directly to the destination and - * Vd will be unmodified on any exception path. - */ - split = max_for_page(addr, mem_off, mem_max); - if (likely(split == mem_max)) { - host = tlb_vaddr_to_host(env, addr + mem_off, MMU_DATA_LOAD, mmu_idx); - if (test_host_page(host)) { - intptr_t i = reg_off; - host -= mem_off; - do { - host_fn(vd, i, host + (i >> diffsz)); - i = find_next_active(vg, i + (1 << esz), reg_max, esz); - } while (i < reg_max); - /* After having taken any fault, zero leading inactive elements. */ - swap_memzero(vd, reg_off); - return; - } - } + /* Probe the page(s). Exit with exception for any invalid page. */ + sve_cont_ldst_pages(&info, FAULT_ALL, env, addr, MMU_DATA_LOAD, retaddr); - /* - * Perform the predicated read into a temporary, thus ensuring - * if the load of the last element faults, Vd is not modified. - */ + flags = info.page[0].flags | info.page[1].flags; + if (unlikely(flags != 0)) { #ifdef CONFIG_USER_ONLY - swap_memzero(&scratch, reg_off); - host = g2h(addr); - do { - host_fn(&scratch, reg_off, host + (reg_off >> diffsz)); - reg_off += 1 << esz; - reg_off = find_next_active(vg, reg_off, reg_max, esz); - } while (reg_off < reg_max); + g_assert_not_reached(); #else - memset(&scratch, 0, reg_max); - goto start; - while (1) { - reg_off = find_next_active(vg, reg_off, reg_max, esz); - if (reg_off >= reg_max) { - break; - } - mem_off = reg_off >> diffsz; - split = max_for_page(addr, mem_off, mem_max); + /* + * At least one page includes MMIO (or watchpoints). + * Any bus operation can fail with cpu_transaction_failed, + * which for ARM will raise SyncExternal. Perform the load + * into scratch memory to preserve register state until the end. + */ + ARMVectorReg scratch; - start: - if (split - mem_off >= (1 << msz)) { - /* At least one whole element on this page. */ - host = tlb_vaddr_to_host(env, addr + mem_off, - MMU_DATA_LOAD, mmu_idx); - if (host) { - host -= mem_off; - do { - host_fn(&scratch, reg_off, host + mem_off); - reg_off += 1 << esz; - reg_off = find_next_active(vg, reg_off, reg_max, esz); - mem_off = reg_off >> diffsz; - } while (split - mem_off >= (1 << msz)); - continue; + memset(&scratch, 0, reg_max); + mem_off = info.mem_off_first[0]; + reg_off = info.reg_off_first[0]; + reg_last = info.reg_off_last[1]; + if (reg_last < 0) { + reg_last = info.reg_off_split; + if (reg_last < 0) { + reg_last = info.reg_off_last[0]; } } - /* - * Perform one normal read. This may fault, longjmping out to the - * main loop in order to raise an exception. It may succeed, and - * as a side-effect load the TLB entry for the next round. Finally, - * in the extremely unlikely case we're performing this operation - * on I/O memory, it may succeed but not bring in the TLB entry. - * But even then we have still made forward progress. - */ - tlb_fn(env, &scratch, reg_off, addr + mem_off, retaddr); - reg_off += 1 << esz; - } -#endif + do { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + tlb_fn(env, &scratch, reg_off, addr + mem_off, retaddr); + } + reg_off += 1 << esz; + mem_off += 1 << msz; + } while (reg_off & 63); + } while (reg_off <= reg_last); - memcpy(vd, &scratch, reg_max); + memcpy(vd, &scratch, reg_max); + return; +#endif + } + + /* The entire operation is in RAM, on valid pages. */ + + memset(vd, 0, reg_max); + mem_off = info.mem_off_first[0]; + reg_off = info.reg_off_first[0]; + reg_last = info.reg_off_last[0]; + host = info.page[0].host; + + while (reg_off <= reg_last) { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + host_fn(vd, reg_off, host + mem_off); + } + reg_off += 1 << esz; + mem_off += 1 << msz; + } while (reg_off <= reg_last && (reg_off & 63)); + } + + /* + * Use the slow path to manage the cross-page misalignment. + * But we know this is RAM and cannot trap. + */ + mem_off = info.mem_off_split; + if (unlikely(mem_off >= 0)) { + tlb_fn(env, vd, info.reg_off_split, addr + mem_off, retaddr); + } + + mem_off = info.mem_off_first[1]; + if (unlikely(mem_off >= 0)) { + reg_off = info.reg_off_first[1]; + reg_last = info.reg_off_last[1]; + host = info.page[1].host; + + do { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + host_fn(vd, reg_off, host + mem_off); + } + reg_off += 1 << esz; + mem_off += 1 << msz; + } while (reg_off & 63); + } while (reg_off <= reg_last); + } } #define DO_LD1_1(NAME, ESZ) \ From 4bcc3f0ff8e5ae2b17b5aab9aa613ff1b8025896 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:52 -0700 Subject: [PATCH 0377/2595] target/arm: Handle watchpoints in sve_ld1_r Handle all of the watchpoints for active elements all at once, before we've modified the vector register. This removes the TLB_WATCHPOINT bit from page[].flags, which means that we can use the normal fast path via RAM. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 72 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 6bae342a17..7992a569b0 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -4371,6 +4371,70 @@ static bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault, return have_work; } +static void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, + int esize, int msize, int wp_access, + uintptr_t retaddr) +{ +#ifndef CONFIG_USER_ONLY + intptr_t mem_off, reg_off, reg_last; + int flags0 = info->page[0].flags; + int flags1 = info->page[1].flags; + + if (likely(!((flags0 | flags1) & TLB_WATCHPOINT))) { + return; + } + + /* Indicate that watchpoints are handled. */ + info->page[0].flags = flags0 & ~TLB_WATCHPOINT; + info->page[1].flags = flags1 & ~TLB_WATCHPOINT; + + if (flags0 & TLB_WATCHPOINT) { + mem_off = info->mem_off_first[0]; + reg_off = info->reg_off_first[0]; + reg_last = info->reg_off_last[0]; + + while (reg_off <= reg_last) { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + cpu_check_watchpoint(env_cpu(env), addr + mem_off, + msize, info->page[0].attrs, + wp_access, retaddr); + } + reg_off += esize; + mem_off += msize; + } while (reg_off <= reg_last && (reg_off & 63)); + } + } + + mem_off = info->mem_off_split; + if (mem_off >= 0) { + cpu_check_watchpoint(env_cpu(env), addr + mem_off, msize, + info->page[0].attrs, wp_access, retaddr); + } + + mem_off = info->mem_off_first[1]; + if ((flags1 & TLB_WATCHPOINT) && mem_off >= 0) { + reg_off = info->reg_off_first[1]; + reg_last = info->reg_off_last[1]; + + do { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + cpu_check_watchpoint(env_cpu(env), addr + mem_off, + msize, info->page[1].attrs, + wp_access, retaddr); + } + reg_off += esize; + mem_off += msize; + } while (reg_off & 63); + } while (reg_off <= reg_last); + } +#endif +} + /* * The result of tlb_vaddr_to_host for user-only is just g2h(x), * which is always non-null. Elide the useless test. @@ -4412,13 +4476,19 @@ void sve_ld1_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, /* Probe the page(s). Exit with exception for any invalid page. */ sve_cont_ldst_pages(&info, FAULT_ALL, env, addr, MMU_DATA_LOAD, retaddr); + /* Handle watchpoints for all active elements. */ + sve_cont_ldst_watchpoints(&info, env, vg, addr, 1 << esz, 1 << msz, + BP_MEM_READ, retaddr); + + /* TODO: MTE check. */ + flags = info.page[0].flags | info.page[1].flags; if (unlikely(flags != 0)) { #ifdef CONFIG_USER_ONLY g_assert_not_reached(); #else /* - * At least one page includes MMIO (or watchpoints). + * At least one page includes MMIO. * Any bus operation can fail with cpu_transaction_failed, * which for ARM will raise SyncExternal. Perform the load * into scratch memory to preserve register state until the end. From 5c9b8458a0b3008d24d84b67e1c9b6d5f39f4d66 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:53 -0700 Subject: [PATCH 0378/2595] target/arm: Use SVEContLdSt for multi-register contiguous loads Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-14-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 223 ++++++++++++++-------------------------- 1 file changed, 79 insertions(+), 144 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 7992a569b0..9365e32646 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -4449,27 +4449,28 @@ static inline bool test_host_page(void *host) } /* - * Common helper for all contiguous one-register predicated loads. + * Common helper for all contiguous 1,2,3,4-register predicated stores. */ static inline QEMU_ALWAYS_INLINE -void sve_ld1_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, +void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, uint32_t desc, const uintptr_t retaddr, - const int esz, const int msz, + const int esz, const int msz, const int N, sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) { const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); - void *vd = &env->vfp.zregs[rd]; const intptr_t reg_max = simd_oprsz(desc); intptr_t reg_off, reg_last, mem_off; SVEContLdSt info; void *host; - int flags; + int flags, i; /* Find the active elements. */ - if (!sve_cont_ldst_elements(&info, addr, vg, reg_max, esz, 1 << msz)) { + if (!sve_cont_ldst_elements(&info, addr, vg, reg_max, esz, N << msz)) { /* The entire predicate was false; no load occurs. */ - memset(vd, 0, reg_max); + for (i = 0; i < N; ++i) { + memset(&env->vfp.zregs[(rd + i) & 31], 0, reg_max); + } return; } @@ -4477,7 +4478,7 @@ void sve_ld1_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, sve_cont_ldst_pages(&info, FAULT_ALL, env, addr, MMU_DATA_LOAD, retaddr); /* Handle watchpoints for all active elements. */ - sve_cont_ldst_watchpoints(&info, env, vg, addr, 1 << esz, 1 << msz, + sve_cont_ldst_watchpoints(&info, env, vg, addr, 1 << esz, N << msz, BP_MEM_READ, retaddr); /* TODO: MTE check. */ @@ -4493,9 +4494,8 @@ void sve_ld1_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, * which for ARM will raise SyncExternal. Perform the load * into scratch memory to preserve register state until the end. */ - ARMVectorReg scratch; + ARMVectorReg scratch[4] = { }; - memset(&scratch, 0, reg_max); mem_off = info.mem_off_first[0]; reg_off = info.reg_off_first[0]; reg_last = info.reg_off_last[1]; @@ -4510,21 +4510,29 @@ void sve_ld1_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, uint64_t pg = vg[reg_off >> 6]; do { if ((pg >> (reg_off & 63)) & 1) { - tlb_fn(env, &scratch, reg_off, addr + mem_off, retaddr); + for (i = 0; i < N; ++i) { + tlb_fn(env, &scratch[i], reg_off, + addr + mem_off + (i << msz), retaddr); + } } reg_off += 1 << esz; - mem_off += 1 << msz; + mem_off += N << msz; } while (reg_off & 63); } while (reg_off <= reg_last); - memcpy(vd, &scratch, reg_max); + for (i = 0; i < N; ++i) { + memcpy(&env->vfp.zregs[(rd + i) & 31], &scratch[i], reg_max); + } return; #endif } /* The entire operation is in RAM, on valid pages. */ - memset(vd, 0, reg_max); + for (i = 0; i < N; ++i) { + memset(&env->vfp.zregs[(rd + i) & 31], 0, reg_max); + } + mem_off = info.mem_off_first[0]; reg_off = info.reg_off_first[0]; reg_last = info.reg_off_last[0]; @@ -4534,10 +4542,13 @@ void sve_ld1_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, uint64_t pg = vg[reg_off >> 6]; do { if ((pg >> (reg_off & 63)) & 1) { - host_fn(vd, reg_off, host + mem_off); + for (i = 0; i < N; ++i) { + host_fn(&env->vfp.zregs[(rd + i) & 31], reg_off, + host + mem_off + (i << msz)); + } } reg_off += 1 << esz; - mem_off += 1 << msz; + mem_off += N << msz; } while (reg_off <= reg_last && (reg_off & 63)); } @@ -4547,7 +4558,11 @@ void sve_ld1_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, */ mem_off = info.mem_off_split; if (unlikely(mem_off >= 0)) { - tlb_fn(env, vd, info.reg_off_split, addr + mem_off, retaddr); + reg_off = info.reg_off_split; + for (i = 0; i < N; ++i) { + tlb_fn(env, &env->vfp.zregs[(rd + i) & 31], reg_off, + addr + mem_off + (i << msz), retaddr); + } } mem_off = info.mem_off_first[1]; @@ -4560,10 +4575,13 @@ void sve_ld1_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, uint64_t pg = vg[reg_off >> 6]; do { if ((pg >> (reg_off & 63)) & 1) { - host_fn(vd, reg_off, host + mem_off); + for (i = 0; i < N; ++i) { + host_fn(&env->vfp.zregs[(rd + i) & 31], reg_off, + host + mem_off + (i << msz)); + } } reg_off += 1 << esz; - mem_off += 1 << msz; + mem_off += N << msz; } while (reg_off & 63); } while (reg_off <= reg_last); } @@ -4573,7 +4591,7 @@ void sve_ld1_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, void HELPER(sve_##NAME##_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ld1_r(env, vg, addr, desc, GETPC(), ESZ, 0, \ + sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, 1, \ sve_##NAME##_host, sve_##NAME##_tlb); \ } @@ -4581,159 +4599,76 @@ void HELPER(sve_##NAME##_r)(CPUARMState *env, void *vg, \ void HELPER(sve_##NAME##_le_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ld1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, \ + sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \ sve_##NAME##_le_host, sve_##NAME##_le_tlb); \ } \ void HELPER(sve_##NAME##_be_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ld1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, \ + sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \ sve_##NAME##_be_host, sve_##NAME##_be_tlb); \ } -DO_LD1_1(ld1bb, 0) -DO_LD1_1(ld1bhu, 1) -DO_LD1_1(ld1bhs, 1) -DO_LD1_1(ld1bsu, 2) -DO_LD1_1(ld1bss, 2) -DO_LD1_1(ld1bdu, 3) -DO_LD1_1(ld1bds, 3) +DO_LD1_1(ld1bb, MO_8) +DO_LD1_1(ld1bhu, MO_16) +DO_LD1_1(ld1bhs, MO_16) +DO_LD1_1(ld1bsu, MO_32) +DO_LD1_1(ld1bss, MO_32) +DO_LD1_1(ld1bdu, MO_64) +DO_LD1_1(ld1bds, MO_64) -DO_LD1_2(ld1hh, 1, 1) -DO_LD1_2(ld1hsu, 2, 1) -DO_LD1_2(ld1hss, 2, 1) -DO_LD1_2(ld1hdu, 3, 1) -DO_LD1_2(ld1hds, 3, 1) +DO_LD1_2(ld1hh, MO_16, MO_16) +DO_LD1_2(ld1hsu, MO_32, MO_16) +DO_LD1_2(ld1hss, MO_32, MO_16) +DO_LD1_2(ld1hdu, MO_64, MO_16) +DO_LD1_2(ld1hds, MO_64, MO_16) -DO_LD1_2(ld1ss, 2, 2) -DO_LD1_2(ld1sdu, 3, 2) -DO_LD1_2(ld1sds, 3, 2) +DO_LD1_2(ld1ss, MO_32, MO_32) +DO_LD1_2(ld1sdu, MO_64, MO_32) +DO_LD1_2(ld1sds, MO_64, MO_32) -DO_LD1_2(ld1dd, 3, 3) +DO_LD1_2(ld1dd, MO_64, MO_64) #undef DO_LD1_1 #undef DO_LD1_2 -/* - * Common helpers for all contiguous 2,3,4-register predicated loads. - */ -static void sve_ld2_r(CPUARMState *env, void *vg, target_ulong addr, - uint32_t desc, int size, uintptr_t ra, - sve_ldst1_tlb_fn *tlb_fn) -{ - const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); - intptr_t i, oprsz = simd_oprsz(desc); - ARMVectorReg scratch[2] = { }; - - for (i = 0; i < oprsz; ) { - uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); - do { - if (pg & 1) { - tlb_fn(env, &scratch[0], i, addr, ra); - tlb_fn(env, &scratch[1], i, addr + size, ra); - } - i += size, pg >>= size; - addr += 2 * size; - } while (i & 15); - } - - /* Wait until all exceptions have been raised to write back. */ - memcpy(&env->vfp.zregs[rd], &scratch[0], oprsz); - memcpy(&env->vfp.zregs[(rd + 1) & 31], &scratch[1], oprsz); -} - -static void sve_ld3_r(CPUARMState *env, void *vg, target_ulong addr, - uint32_t desc, int size, uintptr_t ra, - sve_ldst1_tlb_fn *tlb_fn) -{ - const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); - intptr_t i, oprsz = simd_oprsz(desc); - ARMVectorReg scratch[3] = { }; - - for (i = 0; i < oprsz; ) { - uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); - do { - if (pg & 1) { - tlb_fn(env, &scratch[0], i, addr, ra); - tlb_fn(env, &scratch[1], i, addr + size, ra); - tlb_fn(env, &scratch[2], i, addr + 2 * size, ra); - } - i += size, pg >>= size; - addr += 3 * size; - } while (i & 15); - } - - /* Wait until all exceptions have been raised to write back. */ - memcpy(&env->vfp.zregs[rd], &scratch[0], oprsz); - memcpy(&env->vfp.zregs[(rd + 1) & 31], &scratch[1], oprsz); - memcpy(&env->vfp.zregs[(rd + 2) & 31], &scratch[2], oprsz); -} - -static void sve_ld4_r(CPUARMState *env, void *vg, target_ulong addr, - uint32_t desc, int size, uintptr_t ra, - sve_ldst1_tlb_fn *tlb_fn) -{ - const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); - intptr_t i, oprsz = simd_oprsz(desc); - ARMVectorReg scratch[4] = { }; - - for (i = 0; i < oprsz; ) { - uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); - do { - if (pg & 1) { - tlb_fn(env, &scratch[0], i, addr, ra); - tlb_fn(env, &scratch[1], i, addr + size, ra); - tlb_fn(env, &scratch[2], i, addr + 2 * size, ra); - tlb_fn(env, &scratch[3], i, addr + 3 * size, ra); - } - i += size, pg >>= size; - addr += 4 * size; - } while (i & 15); - } - - /* Wait until all exceptions have been raised to write back. */ - memcpy(&env->vfp.zregs[rd], &scratch[0], oprsz); - memcpy(&env->vfp.zregs[(rd + 1) & 31], &scratch[1], oprsz); - memcpy(&env->vfp.zregs[(rd + 2) & 31], &scratch[2], oprsz); - memcpy(&env->vfp.zregs[(rd + 3) & 31], &scratch[3], oprsz); -} - #define DO_LDN_1(N) \ -void QEMU_FLATTEN HELPER(sve_ld##N##bb_r) \ - (CPUARMState *env, void *vg, target_ulong addr, uint32_t desc) \ -{ \ - sve_ld##N##_r(env, vg, addr, desc, 1, GETPC(), sve_ld1bb_tlb); \ +void HELPER(sve_ld##N##bb_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r(env, vg, addr, desc, GETPC(), MO_8, MO_8, N, \ + sve_ld1bb_host, sve_ld1bb_tlb); \ } -#define DO_LDN_2(N, SUFF, SIZE) \ -void QEMU_FLATTEN HELPER(sve_ld##N##SUFF##_le_r) \ - (CPUARMState *env, void *vg, target_ulong addr, uint32_t desc) \ +#define DO_LDN_2(N, SUFF, ESZ) \ +void HELPER(sve_ld##N##SUFF##_le_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ { \ - sve_ld##N##_r(env, vg, addr, desc, SIZE, GETPC(), \ - sve_ld1##SUFF##_le_tlb); \ + sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, \ + sve_ld1##SUFF##_le_host, sve_ld1##SUFF##_le_tlb); \ } \ -void QEMU_FLATTEN HELPER(sve_ld##N##SUFF##_be_r) \ - (CPUARMState *env, void *vg, target_ulong addr, uint32_t desc) \ +void HELPER(sve_ld##N##SUFF##_be_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ { \ - sve_ld##N##_r(env, vg, addr, desc, SIZE, GETPC(), \ - sve_ld1##SUFF##_be_tlb); \ + sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, \ + sve_ld1##SUFF##_be_host, sve_ld1##SUFF##_be_tlb); \ } DO_LDN_1(2) DO_LDN_1(3) DO_LDN_1(4) -DO_LDN_2(2, hh, 2) -DO_LDN_2(3, hh, 2) -DO_LDN_2(4, hh, 2) +DO_LDN_2(2, hh, MO_16) +DO_LDN_2(3, hh, MO_16) +DO_LDN_2(4, hh, MO_16) -DO_LDN_2(2, ss, 4) -DO_LDN_2(3, ss, 4) -DO_LDN_2(4, ss, 4) +DO_LDN_2(2, ss, MO_32) +DO_LDN_2(3, ss, MO_32) +DO_LDN_2(4, ss, MO_32) -DO_LDN_2(2, dd, 8) -DO_LDN_2(3, dd, 8) -DO_LDN_2(4, dd, 8) +DO_LDN_2(2, dd, MO_64) +DO_LDN_2(3, dd, MO_64) +DO_LDN_2(4, dd, MO_64) #undef DO_LDN_1 #undef DO_LDN_2 From c647673ce4d72a8789703c62a7f3cbc732cb1ea8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:54 -0700 Subject: [PATCH 0379/2595] target/arm: Update contiguous first-fault and no-fault loads With sve_cont_ldst_pages, the differences between first-fault and no-fault are minimal, so unify the routines. With cpu_probe_watchpoint, we are able to make progress through pages with TLB_WATCHPOINT set when the watchpoint does not actually fire. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-15-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 346 +++++++++++++++++++--------------------- 1 file changed, 162 insertions(+), 184 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 9365e32646..f4969347d4 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -4101,18 +4101,6 @@ static intptr_t find_next_active(uint64_t *vg, intptr_t reg_off, return reg_off; } -/* - * Return the maximum offset <= @mem_max which is still within the page - * referenced by @base + @mem_off. - */ -static intptr_t max_for_page(target_ulong base, intptr_t mem_off, - intptr_t mem_max) -{ - target_ulong addr = base + mem_off; - intptr_t split = -(intptr_t)(addr | TARGET_PAGE_MASK); - return MIN(split, mem_max - mem_off) + mem_off; -} - /* * Resolve the guest virtual address to info->host and info->flags. * If @nofault, return false if the page is invalid, otherwise @@ -4435,19 +4423,6 @@ static void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, #endif } -/* - * The result of tlb_vaddr_to_host for user-only is just g2h(x), - * which is always non-null. Elide the useless test. - */ -static inline bool test_host_page(void *host) -{ -#ifdef CONFIG_USER_ONLY - return true; -#else - return likely(host != NULL); -#endif -} - /* * Common helper for all contiguous 1,2,3,4-register predicated stores. */ @@ -4705,167 +4680,167 @@ static void record_fault(CPUARMState *env, uintptr_t i, uintptr_t oprsz) } /* - * Common helper for all contiguous first-fault loads. + * Common helper for all contiguous no-fault and first-fault loads. */ -static void sve_ldff1_r(CPUARMState *env, void *vg, const target_ulong addr, - uint32_t desc, const uintptr_t retaddr, - const int esz, const int msz, - sve_ldst1_host_fn *host_fn, - sve_ldst1_tlb_fn *tlb_fn) +static inline QEMU_ALWAYS_INLINE +void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr, + uint32_t desc, const uintptr_t retaddr, + const int esz, const int msz, const SVEContFault fault, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); - const int mmu_idx = get_mmuidx(oi); const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); void *vd = &env->vfp.zregs[rd]; - const int diffsz = esz - msz; const intptr_t reg_max = simd_oprsz(desc); - const intptr_t mem_max = reg_max >> diffsz; - intptr_t split, reg_off, mem_off, i; + intptr_t reg_off, mem_off, reg_last; + SVEContLdSt info; + int flags; void *host; - /* Skip to the first active element. */ - reg_off = find_next_active(vg, 0, reg_max, esz); - if (unlikely(reg_off == reg_max)) { + /* Find the active elements. */ + if (!sve_cont_ldst_elements(&info, addr, vg, reg_max, esz, 1 << msz)) { /* The entire predicate was false; no load occurs. */ memset(vd, 0, reg_max); return; } - mem_off = reg_off >> diffsz; + reg_off = info.reg_off_first[0]; - /* - * If the (remaining) load is entirely within a single page, then: - * For softmmu, and the tlb hits, then no faults will occur; - * For user-only, either the first load will fault or none will. - * We can thus perform the load directly to the destination and - * Vd will be unmodified on any exception path. - */ - split = max_for_page(addr, mem_off, mem_max); - if (likely(split == mem_max)) { - host = tlb_vaddr_to_host(env, addr + mem_off, MMU_DATA_LOAD, mmu_idx); - if (test_host_page(host)) { - i = reg_off; - host -= mem_off; - do { - host_fn(vd, i, host + (i >> diffsz)); - i = find_next_active(vg, i + (1 << esz), reg_max, esz); - } while (i < reg_max); - /* After any fault, zero any leading inactive elements. */ + /* Probe the page(s). */ + if (!sve_cont_ldst_pages(&info, fault, env, addr, MMU_DATA_LOAD, retaddr)) { + /* Fault on first element. */ + tcg_debug_assert(fault == FAULT_NO); + memset(vd, 0, reg_max); + goto do_fault; + } + + mem_off = info.mem_off_first[0]; + flags = info.page[0].flags; + + if (fault == FAULT_FIRST) { + /* + * Special handling of the first active element, + * if it crosses a page boundary or is MMIO. + */ + bool is_split = mem_off == info.mem_off_split; + /* TODO: MTE check. */ + if (unlikely(flags != 0) || unlikely(is_split)) { + /* + * Use the slow path for cross-page handling. + * Might trap for MMIO or watchpoints. + */ + tlb_fn(env, vd, reg_off, addr + mem_off, retaddr); + + /* After any fault, zero the other elements. */ swap_memzero(vd, reg_off); - return; + reg_off += 1 << esz; + mem_off += 1 << msz; + swap_memzero(vd + reg_off, reg_max - reg_off); + + if (is_split) { + goto second_page; + } + } else { + memset(vd, 0, reg_max); + } + } else { + memset(vd, 0, reg_max); + if (unlikely(mem_off == info.mem_off_split)) { + /* The first active element crosses a page boundary. */ + flags |= info.page[1].flags; + if (unlikely(flags & TLB_MMIO)) { + /* Some page is MMIO, see below. */ + goto do_fault; + } + if (unlikely(flags & TLB_WATCHPOINT) && + (cpu_watchpoint_address_matches + (env_cpu(env), addr + mem_off, 1 << msz) + & BP_MEM_READ)) { + /* Watchpoint hit, see below. */ + goto do_fault; + } + /* TODO: MTE check. */ + /* + * Use the slow path for cross-page handling. + * This is RAM, without a watchpoint, and will not trap. + */ + tlb_fn(env, vd, reg_off, addr + mem_off, retaddr); + goto second_page; } } /* - * Perform one normal read, which will fault or not. - * But it is likely to bring the page into the tlb. + * From this point on, all memory operations are MemSingleNF. + * + * Per the MemSingleNF pseudocode, a no-fault load from Device memory + * must not actually hit the bus -- it returns (UNKNOWN, FAULT) instead. + * + * Unfortuately we do not have access to the memory attributes from the + * PTE to tell Device memory from Normal memory. So we make a mostly + * correct check, and indicate (UNKNOWN, FAULT) for any MMIO. + * This gives the right answer for the common cases of "Normal memory, + * backed by host RAM" and "Device memory, backed by MMIO". + * The architecture allows us to suppress an NF load and return + * (UNKNOWN, FAULT) for any reason, so our behaviour for the corner + * case of "Normal memory, backed by MMIO" is permitted. The case we + * get wrong is "Device memory, backed by host RAM", for which we + * should return (UNKNOWN, FAULT) for but do not. + * + * Similarly, CPU_BP breakpoints would raise exceptions, and so + * return (UNKNOWN, FAULT). For simplicity, we consider gdb and + * architectural breakpoints the same. */ - tlb_fn(env, vd, reg_off, addr + mem_off, retaddr); + if (unlikely(flags & TLB_MMIO)) { + goto do_fault; + } - /* After any fault, zero any leading predicated false elts. */ - swap_memzero(vd, reg_off); - mem_off += 1 << msz; - reg_off += 1 << esz; + reg_last = info.reg_off_last[0]; + host = info.page[0].host; - /* Try again to read the balance of the page. */ - split = max_for_page(addr, mem_off - 1, mem_max); - if (split >= (1 << msz)) { - host = tlb_vaddr_to_host(env, addr + mem_off, MMU_DATA_LOAD, mmu_idx); - if (host) { - host -= mem_off; - do { + do { + uint64_t pg = *(uint64_t *)(vg + (reg_off >> 3)); + do { + if ((pg >> (reg_off & 63)) & 1) { + if (unlikely(flags & TLB_WATCHPOINT) && + (cpu_watchpoint_address_matches + (env_cpu(env), addr + mem_off, 1 << msz) + & BP_MEM_READ)) { + goto do_fault; + } + /* TODO: MTE check. */ host_fn(vd, reg_off, host + mem_off); - reg_off += 1 << esz; - reg_off = find_next_active(vg, reg_off, reg_max, esz); - mem_off = reg_off >> diffsz; - } while (split - mem_off >= (1 << msz)); - } - } - - record_fault(env, reg_off, reg_max); -} - -/* - * Common helper for all contiguous no-fault loads. - */ -static void sve_ldnf1_r(CPUARMState *env, void *vg, const target_ulong addr, - uint32_t desc, const int esz, const int msz, - sve_ldst1_host_fn *host_fn) -{ - const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); - void *vd = &env->vfp.zregs[rd]; - const int diffsz = esz - msz; - const intptr_t reg_max = simd_oprsz(desc); - const intptr_t mem_max = reg_max >> diffsz; - const int mmu_idx = cpu_mmu_index(env, false); - intptr_t split, reg_off, mem_off; - void *host; - -#ifdef CONFIG_USER_ONLY - host = tlb_vaddr_to_host(env, addr, MMU_DATA_LOAD, mmu_idx); - if (likely(page_check_range(addr, mem_max, PAGE_READ) == 0)) { - /* The entire operation is valid and will not fault. */ - reg_off = 0; - do { - mem_off = reg_off >> diffsz; - host_fn(vd, reg_off, host + mem_off); + } reg_off += 1 << esz; - reg_off = find_next_active(vg, reg_off, reg_max, esz); - } while (reg_off < reg_max); - return; - } -#endif + mem_off += 1 << msz; + } while (reg_off <= reg_last && (reg_off & 63)); + } while (reg_off <= reg_last); - /* There will be no fault, so we may modify in advance. */ - memset(vd, 0, reg_max); - - /* Skip to the first active element. */ - reg_off = find_next_active(vg, 0, reg_max, esz); - if (unlikely(reg_off == reg_max)) { - /* The entire predicate was false; no load occurs. */ - return; - } - mem_off = reg_off >> diffsz; - -#ifdef CONFIG_USER_ONLY - if (page_check_range(addr + mem_off, 1 << msz, PAGE_READ) == 0) { - /* At least one load is valid; take the rest of the page. */ - split = max_for_page(addr, mem_off + (1 << msz) - 1, mem_max); - do { - host_fn(vd, reg_off, host + mem_off); - reg_off += 1 << esz; - reg_off = find_next_active(vg, reg_off, reg_max, esz); - mem_off = reg_off >> diffsz; - } while (split - mem_off >= (1 << msz)); - } -#else /* - * If the address is not in the TLB, we have no way to bring the - * entry into the TLB without also risking a fault. Note that - * the corollary is that we never load from an address not in RAM. - * - * This last is out of spec, in a weird corner case. - * Per the MemNF/MemSingleNF pseudocode, a NF load from Device memory - * must not actually hit the bus -- it returns UNKNOWN data instead. - * But if you map non-RAM with Normal memory attributes and do a NF - * load then it should access the bus. (Nobody ought actually do this - * in the real world, obviously.) - * - * Then there are the annoying special cases with watchpoints... - * TODO: Add a form of non-faulting loads using cc->tlb_fill(probe=true). + * MemSingleNF is allowed to fail for any reason. We have special + * code above to handle the first element crossing a page boundary. + * As an implementation choice, decline to handle a cross-page element + * in any other position. */ - host = tlb_vaddr_to_host(env, addr + mem_off, MMU_DATA_LOAD, mmu_idx); - split = max_for_page(addr, mem_off, mem_max); - if (host && split >= (1 << msz)) { - host -= mem_off; - do { - host_fn(vd, reg_off, host + mem_off); - reg_off += 1 << esz; - reg_off = find_next_active(vg, reg_off, reg_max, esz); - mem_off = reg_off >> diffsz; - } while (split - mem_off >= (1 << msz)); + reg_off = info.reg_off_split; + if (reg_off >= 0) { + goto do_fault; } -#endif + second_page: + reg_off = info.reg_off_first[1]; + if (likely(reg_off < 0)) { + /* No active elements on the second page. All done. */ + return; + } + + /* + * MemSingleNF is allowed to fail for any reason. As an implementation + * choice, decline to handle elements on the second page. This should + * be low frequency as the guest walks through memory -- the next + * iteration of the guest's loop should be aligned on the page boundary, + * and then all following iterations will stay aligned. + */ + + do_fault: record_fault(env, reg_off, reg_max); } @@ -4873,58 +4848,61 @@ static void sve_ldnf1_r(CPUARMState *env, void *vg, const target_ulong addr, void HELPER(sve_ldff1##PART##_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldff1_r(env, vg, addr, desc, GETPC(), ESZ, 0, \ - sve_ld1##PART##_host, sve_ld1##PART##_tlb); \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, FAULT_FIRST, \ + sve_ld1##PART##_host, sve_ld1##PART##_tlb); \ } \ void HELPER(sve_ldnf1##PART##_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldnf1_r(env, vg, addr, desc, ESZ, 0, sve_ld1##PART##_host); \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, FAULT_NO, \ + sve_ld1##PART##_host, sve_ld1##PART##_tlb); \ } #define DO_LDFF1_LDNF1_2(PART, ESZ, MSZ) \ void HELPER(sve_ldff1##PART##_le_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldff1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, \ - sve_ld1##PART##_le_host, sve_ld1##PART##_le_tlb); \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_FIRST, \ + sve_ld1##PART##_le_host, sve_ld1##PART##_le_tlb); \ } \ void HELPER(sve_ldnf1##PART##_le_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldnf1_r(env, vg, addr, desc, ESZ, MSZ, sve_ld1##PART##_le_host); \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_NO, \ + sve_ld1##PART##_le_host, sve_ld1##PART##_le_tlb); \ } \ void HELPER(sve_ldff1##PART##_be_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldff1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, \ - sve_ld1##PART##_be_host, sve_ld1##PART##_be_tlb); \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_FIRST, \ + sve_ld1##PART##_be_host, sve_ld1##PART##_be_tlb); \ } \ void HELPER(sve_ldnf1##PART##_be_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldnf1_r(env, vg, addr, desc, ESZ, MSZ, sve_ld1##PART##_be_host); \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_NO, \ + sve_ld1##PART##_be_host, sve_ld1##PART##_be_tlb); \ } -DO_LDFF1_LDNF1_1(bb, 0) -DO_LDFF1_LDNF1_1(bhu, 1) -DO_LDFF1_LDNF1_1(bhs, 1) -DO_LDFF1_LDNF1_1(bsu, 2) -DO_LDFF1_LDNF1_1(bss, 2) -DO_LDFF1_LDNF1_1(bdu, 3) -DO_LDFF1_LDNF1_1(bds, 3) +DO_LDFF1_LDNF1_1(bb, MO_8) +DO_LDFF1_LDNF1_1(bhu, MO_16) +DO_LDFF1_LDNF1_1(bhs, MO_16) +DO_LDFF1_LDNF1_1(bsu, MO_32) +DO_LDFF1_LDNF1_1(bss, MO_32) +DO_LDFF1_LDNF1_1(bdu, MO_64) +DO_LDFF1_LDNF1_1(bds, MO_64) -DO_LDFF1_LDNF1_2(hh, 1, 1) -DO_LDFF1_LDNF1_2(hsu, 2, 1) -DO_LDFF1_LDNF1_2(hss, 2, 1) -DO_LDFF1_LDNF1_2(hdu, 3, 1) -DO_LDFF1_LDNF1_2(hds, 3, 1) +DO_LDFF1_LDNF1_2(hh, MO_16, MO_16) +DO_LDFF1_LDNF1_2(hsu, MO_32, MO_16) +DO_LDFF1_LDNF1_2(hss, MO_32, MO_16) +DO_LDFF1_LDNF1_2(hdu, MO_64, MO_16) +DO_LDFF1_LDNF1_2(hds, MO_64, MO_16) -DO_LDFF1_LDNF1_2(ss, 2, 2) -DO_LDFF1_LDNF1_2(sdu, 3, 2) -DO_LDFF1_LDNF1_2(sds, 3, 2) +DO_LDFF1_LDNF1_2(ss, MO_32, MO_32) +DO_LDFF1_LDNF1_2(sdu, MO_64, MO_32) +DO_LDFF1_LDNF1_2(sds, MO_64, MO_32) -DO_LDFF1_LDNF1_2(dd, 3, 3) +DO_LDFF1_LDNF1_2(dd, MO_64, MO_64) #undef DO_LDFF1_LDNF1_1 #undef DO_LDFF1_LDNF1_2 From 0fa476c1bb37a70df7eeff1e5bfb4791feb37e0e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:55 -0700 Subject: [PATCH 0380/2595] target/arm: Use SVEContLdSt for contiguous stores Follow the model set up for contiguous loads. This handles watchpoints correctly for contiguous stores, recognizing the exception before any changes to memory. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 285 ++++++++++++++++++++++------------------ 1 file changed, 159 insertions(+), 126 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index f4969347d4..4ed9bbe1ee 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -3995,6 +3995,10 @@ static void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ *(TYPEE *)(vd + H(reg_off)) = val; \ } +#define DO_ST_HOST(NAME, H, TYPEE, TYPEM, HOST) \ +static void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ +{ HOST(host, (TYPEM)*(TYPEE *)(vd + H(reg_off))); } + #define DO_LD_TLB(NAME, H, TYPEE, TYPEM, TLB) \ static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \ target_ulong addr, uintptr_t ra) \ @@ -4022,6 +4026,7 @@ DO_LD_PRIM_1(ld1bdu, , uint64_t, uint8_t) DO_LD_PRIM_1(ld1bds, , uint64_t, int8_t) #define DO_ST_PRIM_1(NAME, H, TE, TM) \ + DO_ST_HOST(st1##NAME, H, TE, TM, stb_p) \ DO_ST_TLB(st1##NAME, H, TE, TM, cpu_stb_data_ra) DO_ST_PRIM_1(bb, H1, uint8_t, uint8_t) @@ -4036,6 +4041,8 @@ DO_ST_PRIM_1(bd, , uint64_t, uint8_t) DO_LD_TLB(ld1##NAME##_le, H, TE, TM, cpu_##LD##_le_data_ra) #define DO_ST_PRIM_2(NAME, H, TE, TM, ST) \ + DO_ST_HOST(st1##NAME##_be, H, TE, TM, ST##_be_p) \ + DO_ST_HOST(st1##NAME##_le, H, TE, TM, ST##_le_p) \ DO_ST_TLB(st1##NAME##_be, H, TE, TM, cpu_##ST##_be_data_ra) \ DO_ST_TLB(st1##NAME##_le, H, TE, TM, cpu_##ST##_le_data_ra) @@ -4908,151 +4915,177 @@ DO_LDFF1_LDNF1_2(dd, MO_64, MO_64) #undef DO_LDFF1_LDNF1_2 /* - * Common helpers for all contiguous 1,2,3,4-register predicated stores. + * Common helper for all contiguous 1,2,3,4-register predicated stores. */ -static void sve_st1_r(CPUARMState *env, void *vg, target_ulong addr, - uint32_t desc, const uintptr_t ra, - const int esize, const int msize, - sve_ldst1_tlb_fn *tlb_fn) + +static inline QEMU_ALWAYS_INLINE +void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, uint32_t desc, + const uintptr_t retaddr, const int esz, + const int msz, const int N, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) { const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); - intptr_t i, oprsz = simd_oprsz(desc); - void *vd = &env->vfp.zregs[rd]; + const intptr_t reg_max = simd_oprsz(desc); + intptr_t reg_off, reg_last, mem_off; + SVEContLdSt info; + void *host; + int i, flags; - for (i = 0; i < oprsz; ) { - uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); - do { - if (pg & 1) { - tlb_fn(env, vd, i, addr, ra); + /* Find the active elements. */ + if (!sve_cont_ldst_elements(&info, addr, vg, reg_max, esz, N << msz)) { + /* The entire predicate was false; no store occurs. */ + return; + } + + /* Probe the page(s). Exit with exception for any invalid page. */ + sve_cont_ldst_pages(&info, FAULT_ALL, env, addr, MMU_DATA_STORE, retaddr); + + /* Handle watchpoints for all active elements. */ + sve_cont_ldst_watchpoints(&info, env, vg, addr, 1 << esz, N << msz, + BP_MEM_WRITE, retaddr); + + /* TODO: MTE check. */ + + flags = info.page[0].flags | info.page[1].flags; + if (unlikely(flags != 0)) { +#ifdef CONFIG_USER_ONLY + g_assert_not_reached(); +#else + /* + * At least one page includes MMIO. + * Any bus operation can fail with cpu_transaction_failed, + * which for ARM will raise SyncExternal. We cannot avoid + * this fault and will leave with the store incomplete. + */ + mem_off = info.mem_off_first[0]; + reg_off = info.reg_off_first[0]; + reg_last = info.reg_off_last[1]; + if (reg_last < 0) { + reg_last = info.reg_off_split; + if (reg_last < 0) { + reg_last = info.reg_off_last[0]; } - i += esize, pg >>= esize; - addr += msize; - } while (i & 15); + } + + do { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + for (i = 0; i < N; ++i) { + tlb_fn(env, &env->vfp.zregs[(rd + i) & 31], reg_off, + addr + mem_off + (i << msz), retaddr); + } + } + reg_off += 1 << esz; + mem_off += N << msz; + } while (reg_off & 63); + } while (reg_off <= reg_last); + return; +#endif + } + + mem_off = info.mem_off_first[0]; + reg_off = info.reg_off_first[0]; + reg_last = info.reg_off_last[0]; + host = info.page[0].host; + + while (reg_off <= reg_last) { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + for (i = 0; i < N; ++i) { + host_fn(&env->vfp.zregs[(rd + i) & 31], reg_off, + host + mem_off + (i << msz)); + } + } + reg_off += 1 << esz; + mem_off += N << msz; + } while (reg_off <= reg_last && (reg_off & 63)); + } + + /* + * Use the slow path to manage the cross-page misalignment. + * But we know this is RAM and cannot trap. + */ + mem_off = info.mem_off_split; + if (unlikely(mem_off >= 0)) { + reg_off = info.reg_off_split; + for (i = 0; i < N; ++i) { + tlb_fn(env, &env->vfp.zregs[(rd + i) & 31], reg_off, + addr + mem_off + (i << msz), retaddr); + } + } + + mem_off = info.mem_off_first[1]; + if (unlikely(mem_off >= 0)) { + reg_off = info.reg_off_first[1]; + reg_last = info.reg_off_last[1]; + host = info.page[1].host; + + do { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + for (i = 0; i < N; ++i) { + host_fn(&env->vfp.zregs[(rd + i) & 31], reg_off, + host + mem_off + (i << msz)); + } + } + reg_off += 1 << esz; + mem_off += N << msz; + } while (reg_off & 63); + } while (reg_off <= reg_last); } } -static void sve_st2_r(CPUARMState *env, void *vg, target_ulong addr, - uint32_t desc, const uintptr_t ra, - const int esize, const int msize, - sve_ldst1_tlb_fn *tlb_fn) -{ - const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); - intptr_t i, oprsz = simd_oprsz(desc); - void *d1 = &env->vfp.zregs[rd]; - void *d2 = &env->vfp.zregs[(rd + 1) & 31]; - - for (i = 0; i < oprsz; ) { - uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); - do { - if (pg & 1) { - tlb_fn(env, d1, i, addr, ra); - tlb_fn(env, d2, i, addr + msize, ra); - } - i += esize, pg >>= esize; - addr += 2 * msize; - } while (i & 15); - } -} - -static void sve_st3_r(CPUARMState *env, void *vg, target_ulong addr, - uint32_t desc, const uintptr_t ra, - const int esize, const int msize, - sve_ldst1_tlb_fn *tlb_fn) -{ - const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); - intptr_t i, oprsz = simd_oprsz(desc); - void *d1 = &env->vfp.zregs[rd]; - void *d2 = &env->vfp.zregs[(rd + 1) & 31]; - void *d3 = &env->vfp.zregs[(rd + 2) & 31]; - - for (i = 0; i < oprsz; ) { - uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); - do { - if (pg & 1) { - tlb_fn(env, d1, i, addr, ra); - tlb_fn(env, d2, i, addr + msize, ra); - tlb_fn(env, d3, i, addr + 2 * msize, ra); - } - i += esize, pg >>= esize; - addr += 3 * msize; - } while (i & 15); - } -} - -static void sve_st4_r(CPUARMState *env, void *vg, target_ulong addr, - uint32_t desc, const uintptr_t ra, - const int esize, const int msize, - sve_ldst1_tlb_fn *tlb_fn) -{ - const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); - intptr_t i, oprsz = simd_oprsz(desc); - void *d1 = &env->vfp.zregs[rd]; - void *d2 = &env->vfp.zregs[(rd + 1) & 31]; - void *d3 = &env->vfp.zregs[(rd + 2) & 31]; - void *d4 = &env->vfp.zregs[(rd + 3) & 31]; - - for (i = 0; i < oprsz; ) { - uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); - do { - if (pg & 1) { - tlb_fn(env, d1, i, addr, ra); - tlb_fn(env, d2, i, addr + msize, ra); - tlb_fn(env, d3, i, addr + 2 * msize, ra); - tlb_fn(env, d4, i, addr + 3 * msize, ra); - } - i += esize, pg >>= esize; - addr += 4 * msize; - } while (i & 15); - } -} - -#define DO_STN_1(N, NAME, ESIZE) \ -void QEMU_FLATTEN HELPER(sve_st##N##NAME##_r) \ - (CPUARMState *env, void *vg, target_ulong addr, uint32_t desc) \ +#define DO_STN_1(N, NAME, ESZ) \ +void HELPER(sve_st##N##NAME##_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ { \ - sve_st##N##_r(env, vg, addr, desc, GETPC(), ESIZE, 1, \ - sve_st1##NAME##_tlb); \ + sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, N, \ + sve_st1##NAME##_host, sve_st1##NAME##_tlb); \ } -#define DO_STN_2(N, NAME, ESIZE, MSIZE) \ -void QEMU_FLATTEN HELPER(sve_st##N##NAME##_le_r) \ - (CPUARMState *env, void *vg, target_ulong addr, uint32_t desc) \ +#define DO_STN_2(N, NAME, ESZ, MSZ) \ +void HELPER(sve_st##N##NAME##_le_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ { \ - sve_st##N##_r(env, vg, addr, desc, GETPC(), ESIZE, MSIZE, \ - sve_st1##NAME##_le_tlb); \ + sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, \ + sve_st1##NAME##_le_host, sve_st1##NAME##_le_tlb); \ } \ -void QEMU_FLATTEN HELPER(sve_st##N##NAME##_be_r) \ - (CPUARMState *env, void *vg, target_ulong addr, uint32_t desc) \ +void HELPER(sve_st##N##NAME##_be_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ { \ - sve_st##N##_r(env, vg, addr, desc, GETPC(), ESIZE, MSIZE, \ - sve_st1##NAME##_be_tlb); \ + sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, \ + sve_st1##NAME##_be_host, sve_st1##NAME##_be_tlb); \ } -DO_STN_1(1, bb, 1) -DO_STN_1(1, bh, 2) -DO_STN_1(1, bs, 4) -DO_STN_1(1, bd, 8) -DO_STN_1(2, bb, 1) -DO_STN_1(3, bb, 1) -DO_STN_1(4, bb, 1) +DO_STN_1(1, bb, MO_8) +DO_STN_1(1, bh, MO_16) +DO_STN_1(1, bs, MO_32) +DO_STN_1(1, bd, MO_64) +DO_STN_1(2, bb, MO_8) +DO_STN_1(3, bb, MO_8) +DO_STN_1(4, bb, MO_8) -DO_STN_2(1, hh, 2, 2) -DO_STN_2(1, hs, 4, 2) -DO_STN_2(1, hd, 8, 2) -DO_STN_2(2, hh, 2, 2) -DO_STN_2(3, hh, 2, 2) -DO_STN_2(4, hh, 2, 2) +DO_STN_2(1, hh, MO_16, MO_16) +DO_STN_2(1, hs, MO_32, MO_16) +DO_STN_2(1, hd, MO_64, MO_16) +DO_STN_2(2, hh, MO_16, MO_16) +DO_STN_2(3, hh, MO_16, MO_16) +DO_STN_2(4, hh, MO_16, MO_16) -DO_STN_2(1, ss, 4, 4) -DO_STN_2(1, sd, 8, 4) -DO_STN_2(2, ss, 4, 4) -DO_STN_2(3, ss, 4, 4) -DO_STN_2(4, ss, 4, 4) +DO_STN_2(1, ss, MO_32, MO_32) +DO_STN_2(1, sd, MO_64, MO_32) +DO_STN_2(2, ss, MO_32, MO_32) +DO_STN_2(3, ss, MO_32, MO_32) +DO_STN_2(4, ss, MO_32, MO_32) -DO_STN_2(1, dd, 8, 8) -DO_STN_2(2, dd, 8, 8) -DO_STN_2(3, dd, 8, 8) -DO_STN_2(4, dd, 8, 8) +DO_STN_2(1, dd, MO_64, MO_64) +DO_STN_2(2, dd, MO_64, MO_64) +DO_STN_2(3, dd, MO_64, MO_64) +DO_STN_2(4, dd, MO_64, MO_64) #undef DO_STN_1 #undef DO_STN_2 From 50de9b78cec06e6d16e92a114a505779359ca532 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:56 -0700 Subject: [PATCH 0381/2595] target/arm: Reuse sve_probe_page for gather first-fault loads This avoids the need for a separate set of helpers to implement no-fault semantics, and will enable MTE in the future. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-17-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 323 ++++++++++++++++------------------------ 1 file changed, 127 insertions(+), 196 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 4ed9bbe1ee..1560129b08 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -5254,231 +5254,162 @@ DO_LD1_ZPZ_D(dd_be, zd) /* First fault loads with a vector index. */ -/* Load one element into VD+REG_OFF from (ENV,VADDR) without faulting. - * The controlling predicate is known to be true. Return true if the - * load was successful. - */ -typedef bool sve_ld1_nf_fn(CPUARMState *env, void *vd, intptr_t reg_off, - target_ulong vaddr, int mmu_idx); - -#ifdef CONFIG_SOFTMMU -#define DO_LD_NF(NAME, H, TYPEE, TYPEM, HOST) \ -static bool sve_ld##NAME##_nf(CPUARMState *env, void *vd, intptr_t reg_off, \ - target_ulong addr, int mmu_idx) \ -{ \ - target_ulong next_page = -(addr | TARGET_PAGE_MASK); \ - if (likely(next_page - addr >= sizeof(TYPEM))) { \ - void *host = tlb_vaddr_to_host(env, addr, MMU_DATA_LOAD, mmu_idx); \ - if (likely(host)) { \ - TYPEM val = HOST(host); \ - *(TYPEE *)(vd + H(reg_off)) = val; \ - return true; \ - } \ - } \ - return false; \ -} -#else -#define DO_LD_NF(NAME, H, TYPEE, TYPEM, HOST) \ -static bool sve_ld##NAME##_nf(CPUARMState *env, void *vd, intptr_t reg_off, \ - target_ulong addr, int mmu_idx) \ -{ \ - if (likely(page_check_range(addr, sizeof(TYPEM), PAGE_READ))) { \ - TYPEM val = HOST(g2h(addr)); \ - *(TYPEE *)(vd + H(reg_off)) = val; \ - return true; \ - } \ - return false; \ -} -#endif - -DO_LD_NF(bsu, H1_4, uint32_t, uint8_t, ldub_p) -DO_LD_NF(bss, H1_4, uint32_t, int8_t, ldsb_p) -DO_LD_NF(bdu, , uint64_t, uint8_t, ldub_p) -DO_LD_NF(bds, , uint64_t, int8_t, ldsb_p) - -DO_LD_NF(hsu_le, H1_4, uint32_t, uint16_t, lduw_le_p) -DO_LD_NF(hss_le, H1_4, uint32_t, int16_t, ldsw_le_p) -DO_LD_NF(hsu_be, H1_4, uint32_t, uint16_t, lduw_be_p) -DO_LD_NF(hss_be, H1_4, uint32_t, int16_t, ldsw_be_p) -DO_LD_NF(hdu_le, , uint64_t, uint16_t, lduw_le_p) -DO_LD_NF(hds_le, , uint64_t, int16_t, ldsw_le_p) -DO_LD_NF(hdu_be, , uint64_t, uint16_t, lduw_be_p) -DO_LD_NF(hds_be, , uint64_t, int16_t, ldsw_be_p) - -DO_LD_NF(ss_le, H1_4, uint32_t, uint32_t, ldl_le_p) -DO_LD_NF(ss_be, H1_4, uint32_t, uint32_t, ldl_be_p) -DO_LD_NF(sdu_le, , uint64_t, uint32_t, ldl_le_p) -DO_LD_NF(sds_le, , uint64_t, int32_t, ldl_le_p) -DO_LD_NF(sdu_be, , uint64_t, uint32_t, ldl_be_p) -DO_LD_NF(sds_be, , uint64_t, int32_t, ldl_be_p) - -DO_LD_NF(dd_le, , uint64_t, uint64_t, ldq_le_p) -DO_LD_NF(dd_be, , uint64_t, uint64_t, ldq_be_p) - /* - * Common helper for all gather first-faulting loads. + * Common helpers for all gather first-faulting loads. */ -static inline void sve_ldff1_zs(CPUARMState *env, void *vd, void *vg, void *vm, - target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn, - sve_ld1_nf_fn *nonfault_fn) + +static inline QEMU_ALWAYS_INLINE +void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, + target_ulong base, uint32_t desc, uintptr_t retaddr, + const int esz, const int msz, zreg_off_fn *off_fn, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) { - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); - const int mmu_idx = get_mmuidx(oi); + const int mmu_idx = cpu_mmu_index(env, false); const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); - intptr_t reg_off, reg_max = simd_oprsz(desc); - target_ulong addr; + const int esize = 1 << esz; + const int msize = 1 << msz; + const intptr_t reg_max = simd_oprsz(desc); + intptr_t reg_off; + SVEHostPage info; + target_ulong addr, in_page; /* Skip to the first true predicate. */ - reg_off = find_next_active(vg, 0, reg_max, MO_32); - if (likely(reg_off < reg_max)) { - /* Perform one normal read, which will fault or not. */ - addr = off_fn(vm, reg_off); - addr = base + (addr << scale); - tlb_fn(env, vd, reg_off, addr, ra); - - /* The rest of the reads will be non-faulting. */ + reg_off = find_next_active(vg, 0, reg_max, esz); + if (unlikely(reg_off >= reg_max)) { + /* The entire predicate was false; no load occurs. */ + memset(vd, 0, reg_max); + return; } - /* After any fault, zero the leading predicated false elements. */ + /* + * Probe the first element, allowing faults. + */ + addr = base + (off_fn(vm, reg_off) << scale); + tlb_fn(env, vd, reg_off, addr, retaddr); + + /* After any fault, zero the other elements. */ swap_memzero(vd, reg_off); + reg_off += esize; + swap_memzero(vd + reg_off, reg_max - reg_off); - while (likely((reg_off += 4) < reg_max)) { - uint64_t pg = *(uint64_t *)(vg + (reg_off >> 6) * 8); - if (likely((pg >> (reg_off & 63)) & 1)) { - addr = off_fn(vm, reg_off); - addr = base + (addr << scale); - if (!nonfault_fn(env, vd, reg_off, addr, mmu_idx)) { - record_fault(env, reg_off, reg_max); - break; + /* + * Probe the remaining elements, not allowing faults. + */ + while (reg_off < reg_max) { + uint64_t pg = vg[reg_off >> 6]; + do { + if (likely((pg >> (reg_off & 63)) & 1)) { + addr = base + (off_fn(vm, reg_off) << scale); + in_page = -(addr | TARGET_PAGE_MASK); + + if (unlikely(in_page < msize)) { + /* Stop if the element crosses a page boundary. */ + goto fault; + } + + sve_probe_page(&info, true, env, addr, 0, MMU_DATA_LOAD, + mmu_idx, retaddr); + if (unlikely(info.flags & (TLB_INVALID_MASK | TLB_MMIO))) { + goto fault; + } + if (unlikely(info.flags & TLB_WATCHPOINT) && + (cpu_watchpoint_address_matches + (env_cpu(env), addr, msize) & BP_MEM_READ)) { + goto fault; + } + /* TODO: MTE check. */ + + host_fn(vd, reg_off, info.host); } - } else { - *(uint32_t *)(vd + H1_4(reg_off)) = 0; - } + reg_off += esize; + } while (reg_off & 63); } + return; + + fault: + record_fault(env, reg_off, reg_max); } -static inline void sve_ldff1_zd(CPUARMState *env, void *vd, void *vg, void *vm, - target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn, - sve_ld1_nf_fn *nonfault_fn) -{ - const TCGMemOpIdx oi = extract32(desc, SIMD_DATA_SHIFT, MEMOPIDX_SHIFT); - const int mmu_idx = get_mmuidx(oi); - const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); - intptr_t reg_off, reg_max = simd_oprsz(desc); - target_ulong addr; - - /* Skip to the first true predicate. */ - reg_off = find_next_active(vg, 0, reg_max, MO_64); - if (likely(reg_off < reg_max)) { - /* Perform one normal read, which will fault or not. */ - addr = off_fn(vm, reg_off); - addr = base + (addr << scale); - tlb_fn(env, vd, reg_off, addr, ra); - - /* The rest of the reads will be non-faulting. */ - } - - /* After any fault, zero the leading predicated false elements. */ - swap_memzero(vd, reg_off); - - while (likely((reg_off += 8) < reg_max)) { - uint8_t pg = *(uint8_t *)(vg + H1(reg_off >> 3)); - if (likely(pg & 1)) { - addr = off_fn(vm, reg_off); - addr = base + (addr << scale); - if (!nonfault_fn(env, vd, reg_off, addr, mmu_idx)) { - record_fault(env, reg_off, reg_max); - break; - } - } else { - *(uint64_t *)(vd + reg_off) = 0; - } - } +#define DO_LDFF1_ZPZ_S(MEM, OFS, MSZ) \ +void HELPER(sve_ldff##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_ldff1_z(env, vd, vg, vm, base, desc, GETPC(), MO_32, MSZ, \ + off_##OFS##_s, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ } -#define DO_LDFF1_ZPZ_S(MEM, OFS) \ -void HELPER(sve_ldff##MEM##_##OFS) \ - (CPUARMState *env, void *vd, void *vg, void *vm, \ - target_ulong base, uint32_t desc) \ -{ \ - sve_ldff1_zs(env, vd, vg, vm, base, desc, GETPC(), \ - off_##OFS##_s, sve_ld1##MEM##_tlb, sve_ld##MEM##_nf); \ +#define DO_LDFF1_ZPZ_D(MEM, OFS, MSZ) \ +void HELPER(sve_ldff##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_ldff1_z(env, vd, vg, vm, base, desc, GETPC(), MO_64, MSZ, \ + off_##OFS##_d, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ } -#define DO_LDFF1_ZPZ_D(MEM, OFS) \ -void HELPER(sve_ldff##MEM##_##OFS) \ - (CPUARMState *env, void *vd, void *vg, void *vm, \ - target_ulong base, uint32_t desc) \ -{ \ - sve_ldff1_zd(env, vd, vg, vm, base, desc, GETPC(), \ - off_##OFS##_d, sve_ld1##MEM##_tlb, sve_ld##MEM##_nf); \ -} +DO_LDFF1_ZPZ_S(bsu, zsu, MO_8) +DO_LDFF1_ZPZ_S(bsu, zss, MO_8) +DO_LDFF1_ZPZ_D(bdu, zsu, MO_8) +DO_LDFF1_ZPZ_D(bdu, zss, MO_8) +DO_LDFF1_ZPZ_D(bdu, zd, MO_8) -DO_LDFF1_ZPZ_S(bsu, zsu) -DO_LDFF1_ZPZ_S(bsu, zss) -DO_LDFF1_ZPZ_D(bdu, zsu) -DO_LDFF1_ZPZ_D(bdu, zss) -DO_LDFF1_ZPZ_D(bdu, zd) +DO_LDFF1_ZPZ_S(bss, zsu, MO_8) +DO_LDFF1_ZPZ_S(bss, zss, MO_8) +DO_LDFF1_ZPZ_D(bds, zsu, MO_8) +DO_LDFF1_ZPZ_D(bds, zss, MO_8) +DO_LDFF1_ZPZ_D(bds, zd, MO_8) -DO_LDFF1_ZPZ_S(bss, zsu) -DO_LDFF1_ZPZ_S(bss, zss) -DO_LDFF1_ZPZ_D(bds, zsu) -DO_LDFF1_ZPZ_D(bds, zss) -DO_LDFF1_ZPZ_D(bds, zd) +DO_LDFF1_ZPZ_S(hsu_le, zsu, MO_16) +DO_LDFF1_ZPZ_S(hsu_le, zss, MO_16) +DO_LDFF1_ZPZ_D(hdu_le, zsu, MO_16) +DO_LDFF1_ZPZ_D(hdu_le, zss, MO_16) +DO_LDFF1_ZPZ_D(hdu_le, zd, MO_16) -DO_LDFF1_ZPZ_S(hsu_le, zsu) -DO_LDFF1_ZPZ_S(hsu_le, zss) -DO_LDFF1_ZPZ_D(hdu_le, zsu) -DO_LDFF1_ZPZ_D(hdu_le, zss) -DO_LDFF1_ZPZ_D(hdu_le, zd) +DO_LDFF1_ZPZ_S(hsu_be, zsu, MO_16) +DO_LDFF1_ZPZ_S(hsu_be, zss, MO_16) +DO_LDFF1_ZPZ_D(hdu_be, zsu, MO_16) +DO_LDFF1_ZPZ_D(hdu_be, zss, MO_16) +DO_LDFF1_ZPZ_D(hdu_be, zd, MO_16) -DO_LDFF1_ZPZ_S(hsu_be, zsu) -DO_LDFF1_ZPZ_S(hsu_be, zss) -DO_LDFF1_ZPZ_D(hdu_be, zsu) -DO_LDFF1_ZPZ_D(hdu_be, zss) -DO_LDFF1_ZPZ_D(hdu_be, zd) +DO_LDFF1_ZPZ_S(hss_le, zsu, MO_16) +DO_LDFF1_ZPZ_S(hss_le, zss, MO_16) +DO_LDFF1_ZPZ_D(hds_le, zsu, MO_16) +DO_LDFF1_ZPZ_D(hds_le, zss, MO_16) +DO_LDFF1_ZPZ_D(hds_le, zd, MO_16) -DO_LDFF1_ZPZ_S(hss_le, zsu) -DO_LDFF1_ZPZ_S(hss_le, zss) -DO_LDFF1_ZPZ_D(hds_le, zsu) -DO_LDFF1_ZPZ_D(hds_le, zss) -DO_LDFF1_ZPZ_D(hds_le, zd) +DO_LDFF1_ZPZ_S(hss_be, zsu, MO_16) +DO_LDFF1_ZPZ_S(hss_be, zss, MO_16) +DO_LDFF1_ZPZ_D(hds_be, zsu, MO_16) +DO_LDFF1_ZPZ_D(hds_be, zss, MO_16) +DO_LDFF1_ZPZ_D(hds_be, zd, MO_16) -DO_LDFF1_ZPZ_S(hss_be, zsu) -DO_LDFF1_ZPZ_S(hss_be, zss) -DO_LDFF1_ZPZ_D(hds_be, zsu) -DO_LDFF1_ZPZ_D(hds_be, zss) -DO_LDFF1_ZPZ_D(hds_be, zd) +DO_LDFF1_ZPZ_S(ss_le, zsu, MO_32) +DO_LDFF1_ZPZ_S(ss_le, zss, MO_32) +DO_LDFF1_ZPZ_D(sdu_le, zsu, MO_32) +DO_LDFF1_ZPZ_D(sdu_le, zss, MO_32) +DO_LDFF1_ZPZ_D(sdu_le, zd, MO_32) -DO_LDFF1_ZPZ_S(ss_le, zsu) -DO_LDFF1_ZPZ_S(ss_le, zss) -DO_LDFF1_ZPZ_D(sdu_le, zsu) -DO_LDFF1_ZPZ_D(sdu_le, zss) -DO_LDFF1_ZPZ_D(sdu_le, zd) +DO_LDFF1_ZPZ_S(ss_be, zsu, MO_32) +DO_LDFF1_ZPZ_S(ss_be, zss, MO_32) +DO_LDFF1_ZPZ_D(sdu_be, zsu, MO_32) +DO_LDFF1_ZPZ_D(sdu_be, zss, MO_32) +DO_LDFF1_ZPZ_D(sdu_be, zd, MO_32) -DO_LDFF1_ZPZ_S(ss_be, zsu) -DO_LDFF1_ZPZ_S(ss_be, zss) -DO_LDFF1_ZPZ_D(sdu_be, zsu) -DO_LDFF1_ZPZ_D(sdu_be, zss) -DO_LDFF1_ZPZ_D(sdu_be, zd) +DO_LDFF1_ZPZ_D(sds_le, zsu, MO_32) +DO_LDFF1_ZPZ_D(sds_le, zss, MO_32) +DO_LDFF1_ZPZ_D(sds_le, zd, MO_32) -DO_LDFF1_ZPZ_D(sds_le, zsu) -DO_LDFF1_ZPZ_D(sds_le, zss) -DO_LDFF1_ZPZ_D(sds_le, zd) +DO_LDFF1_ZPZ_D(sds_be, zsu, MO_32) +DO_LDFF1_ZPZ_D(sds_be, zss, MO_32) +DO_LDFF1_ZPZ_D(sds_be, zd, MO_32) -DO_LDFF1_ZPZ_D(sds_be, zsu) -DO_LDFF1_ZPZ_D(sds_be, zss) -DO_LDFF1_ZPZ_D(sds_be, zd) +DO_LDFF1_ZPZ_D(dd_le, zsu, MO_64) +DO_LDFF1_ZPZ_D(dd_le, zss, MO_64) +DO_LDFF1_ZPZ_D(dd_le, zd, MO_64) -DO_LDFF1_ZPZ_D(dd_le, zsu) -DO_LDFF1_ZPZ_D(dd_le, zss) -DO_LDFF1_ZPZ_D(dd_le, zd) - -DO_LDFF1_ZPZ_D(dd_be, zsu) -DO_LDFF1_ZPZ_D(dd_be, zss) -DO_LDFF1_ZPZ_D(dd_be, zd) +DO_LDFF1_ZPZ_D(dd_be, zsu, MO_64) +DO_LDFF1_ZPZ_D(dd_be, zss, MO_64) +DO_LDFF1_ZPZ_D(dd_be, zd, MO_64) /* Stores with a vector index. */ From 88a660a48ef513ce9875b595e19b2a820b3f3fca Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:57 -0700 Subject: [PATCH 0382/2595] target/arm: Reuse sve_probe_page for scatter stores Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-18-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 182 ++++++++++++++++++++++++---------------- 1 file changed, 111 insertions(+), 71 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 1560129b08..ad7e10f1e7 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -5413,94 +5413,134 @@ DO_LDFF1_ZPZ_D(dd_be, zd, MO_64) /* Stores with a vector index. */ -static void sve_st1_zs(CPUARMState *env, void *vd, void *vg, void *vm, - target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn) +static inline QEMU_ALWAYS_INLINE +void sve_st1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, + target_ulong base, uint32_t desc, uintptr_t retaddr, + int esize, int msize, zreg_off_fn *off_fn, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) { const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); - intptr_t i, oprsz = simd_oprsz(desc); + const int mmu_idx = cpu_mmu_index(env, false); + const intptr_t reg_max = simd_oprsz(desc); + void *host[ARM_MAX_VQ * 4]; + intptr_t reg_off, i; + SVEHostPage info, info2; - for (i = 0; i < oprsz; ) { - uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); + /* + * Probe all of the elements for host addresses and flags. + */ + i = reg_off = 0; + do { + uint64_t pg = vg[reg_off >> 6]; do { - if (likely(pg & 1)) { - target_ulong off = off_fn(vm, i); - tlb_fn(env, vd, i, base + (off << scale), ra); + target_ulong addr = base + (off_fn(vm, reg_off) << scale); + target_ulong in_page = -(addr | TARGET_PAGE_MASK); + + host[i] = NULL; + if (likely((pg >> (reg_off & 63)) & 1)) { + if (likely(in_page >= msize)) { + sve_probe_page(&info, false, env, addr, 0, MMU_DATA_STORE, + mmu_idx, retaddr); + host[i] = info.host; + } else { + /* + * Element crosses the page boundary. + * Probe both pages, but do not record the host address, + * so that we use the slow path. + */ + sve_probe_page(&info, false, env, addr, 0, + MMU_DATA_STORE, mmu_idx, retaddr); + sve_probe_page(&info2, false, env, addr + in_page, 0, + MMU_DATA_STORE, mmu_idx, retaddr); + info.flags |= info2.flags; + } + + if (unlikely(info.flags & TLB_WATCHPOINT)) { + cpu_check_watchpoint(env_cpu(env), addr, msize, + info.attrs, BP_MEM_WRITE, retaddr); + } + /* TODO: MTE check. */ } - i += 4, pg >>= 4; - } while (i & 15); - } -} + i += 1; + reg_off += esize; + } while (reg_off & 63); + } while (reg_off < reg_max); -static void sve_st1_zd(CPUARMState *env, void *vd, void *vg, void *vm, - target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn) -{ - const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); - intptr_t i, oprsz = simd_oprsz(desc) / 8; - - for (i = 0; i < oprsz; i++) { - uint8_t pg = *(uint8_t *)(vg + H1(i)); - if (likely(pg & 1)) { - target_ulong off = off_fn(vm, i * 8); - tlb_fn(env, vd, i * 8, base + (off << scale), ra); + /* + * Now that we have recognized all exceptions except SyncExternal + * (from TLB_MMIO), which we cannot avoid, perform all of the stores. + * + * Note for the common case of an element in RAM, not crossing a page + * boundary, we have stored the host address in host[]. This doubles + * as a first-level check against the predicate, since only enabled + * elements have non-null host addresses. + */ + i = reg_off = 0; + do { + void *h = host[i]; + if (likely(h != NULL)) { + host_fn(vd, reg_off, h); + } else if ((vg[reg_off >> 6] >> (reg_off & 63)) & 1) { + target_ulong addr = base + (off_fn(vm, reg_off) << scale); + tlb_fn(env, vd, reg_off, addr, retaddr); } - } + i += 1; + reg_off += esize; + } while (reg_off < reg_max); } -#define DO_ST1_ZPZ_S(MEM, OFS) \ -void QEMU_FLATTEN HELPER(sve_st##MEM##_##OFS) \ - (CPUARMState *env, void *vd, void *vg, void *vm, \ - target_ulong base, uint32_t desc) \ -{ \ - sve_st1_zs(env, vd, vg, vm, base, desc, GETPC(), \ - off_##OFS##_s, sve_st1##MEM##_tlb); \ +#define DO_ST1_ZPZ_S(MEM, OFS, MSZ) \ +void HELPER(sve_st##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_st1_z(env, vd, vg, vm, base, desc, GETPC(), 4, 1 << MSZ, \ + off_##OFS##_s, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \ } -#define DO_ST1_ZPZ_D(MEM, OFS) \ -void QEMU_FLATTEN HELPER(sve_st##MEM##_##OFS) \ - (CPUARMState *env, void *vd, void *vg, void *vm, \ - target_ulong base, uint32_t desc) \ -{ \ - sve_st1_zd(env, vd, vg, vm, base, desc, GETPC(), \ - off_##OFS##_d, sve_st1##MEM##_tlb); \ +#define DO_ST1_ZPZ_D(MEM, OFS, MSZ) \ +void HELPER(sve_st##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_st1_z(env, vd, vg, vm, base, desc, GETPC(), 8, 1 << MSZ, \ + off_##OFS##_d, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \ } -DO_ST1_ZPZ_S(bs, zsu) -DO_ST1_ZPZ_S(hs_le, zsu) -DO_ST1_ZPZ_S(hs_be, zsu) -DO_ST1_ZPZ_S(ss_le, zsu) -DO_ST1_ZPZ_S(ss_be, zsu) +DO_ST1_ZPZ_S(bs, zsu, MO_8) +DO_ST1_ZPZ_S(hs_le, zsu, MO_16) +DO_ST1_ZPZ_S(hs_be, zsu, MO_16) +DO_ST1_ZPZ_S(ss_le, zsu, MO_32) +DO_ST1_ZPZ_S(ss_be, zsu, MO_32) -DO_ST1_ZPZ_S(bs, zss) -DO_ST1_ZPZ_S(hs_le, zss) -DO_ST1_ZPZ_S(hs_be, zss) -DO_ST1_ZPZ_S(ss_le, zss) -DO_ST1_ZPZ_S(ss_be, zss) +DO_ST1_ZPZ_S(bs, zss, MO_8) +DO_ST1_ZPZ_S(hs_le, zss, MO_16) +DO_ST1_ZPZ_S(hs_be, zss, MO_16) +DO_ST1_ZPZ_S(ss_le, zss, MO_32) +DO_ST1_ZPZ_S(ss_be, zss, MO_32) -DO_ST1_ZPZ_D(bd, zsu) -DO_ST1_ZPZ_D(hd_le, zsu) -DO_ST1_ZPZ_D(hd_be, zsu) -DO_ST1_ZPZ_D(sd_le, zsu) -DO_ST1_ZPZ_D(sd_be, zsu) -DO_ST1_ZPZ_D(dd_le, zsu) -DO_ST1_ZPZ_D(dd_be, zsu) +DO_ST1_ZPZ_D(bd, zsu, MO_8) +DO_ST1_ZPZ_D(hd_le, zsu, MO_16) +DO_ST1_ZPZ_D(hd_be, zsu, MO_16) +DO_ST1_ZPZ_D(sd_le, zsu, MO_32) +DO_ST1_ZPZ_D(sd_be, zsu, MO_32) +DO_ST1_ZPZ_D(dd_le, zsu, MO_64) +DO_ST1_ZPZ_D(dd_be, zsu, MO_64) -DO_ST1_ZPZ_D(bd, zss) -DO_ST1_ZPZ_D(hd_le, zss) -DO_ST1_ZPZ_D(hd_be, zss) -DO_ST1_ZPZ_D(sd_le, zss) -DO_ST1_ZPZ_D(sd_be, zss) -DO_ST1_ZPZ_D(dd_le, zss) -DO_ST1_ZPZ_D(dd_be, zss) +DO_ST1_ZPZ_D(bd, zss, MO_8) +DO_ST1_ZPZ_D(hd_le, zss, MO_16) +DO_ST1_ZPZ_D(hd_be, zss, MO_16) +DO_ST1_ZPZ_D(sd_le, zss, MO_32) +DO_ST1_ZPZ_D(sd_be, zss, MO_32) +DO_ST1_ZPZ_D(dd_le, zss, MO_64) +DO_ST1_ZPZ_D(dd_be, zss, MO_64) -DO_ST1_ZPZ_D(bd, zd) -DO_ST1_ZPZ_D(hd_le, zd) -DO_ST1_ZPZ_D(hd_be, zd) -DO_ST1_ZPZ_D(sd_le, zd) -DO_ST1_ZPZ_D(sd_be, zd) -DO_ST1_ZPZ_D(dd_le, zd) -DO_ST1_ZPZ_D(dd_be, zd) +DO_ST1_ZPZ_D(bd, zd, MO_8) +DO_ST1_ZPZ_D(hd_le, zd, MO_16) +DO_ST1_ZPZ_D(hd_be, zd, MO_16) +DO_ST1_ZPZ_D(sd_le, zd, MO_32) +DO_ST1_ZPZ_D(sd_be, zd, MO_32) +DO_ST1_ZPZ_D(dd_le, zd, MO_64) +DO_ST1_ZPZ_D(dd_be, zd, MO_64) #undef DO_ST1_ZPZ_S #undef DO_ST1_ZPZ_D From 10a85e2c8ab6e004e7f3f1dcfea8cb0bf58fb9fb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:58 -0700 Subject: [PATCH 0383/2595] target/arm: Reuse sve_probe_page for gather loads Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-19-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 208 +++++++++++++++++++++------------------- 1 file changed, 109 insertions(+), 99 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index ad7e10f1e7..f1870aabc2 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -5124,130 +5124,140 @@ static target_ulong off_zd_d(void *reg, intptr_t reg_ofs) return *(uint64_t *)(reg + reg_ofs); } -static void sve_ld1_zs(CPUARMState *env, void *vd, void *vg, void *vm, - target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn) +static inline QEMU_ALWAYS_INLINE +void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, + target_ulong base, uint32_t desc, uintptr_t retaddr, + int esize, int msize, zreg_off_fn *off_fn, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) { const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); - intptr_t i, oprsz = simd_oprsz(desc); - ARMVectorReg scratch = { }; + const int mmu_idx = cpu_mmu_index(env, false); + const intptr_t reg_max = simd_oprsz(desc); + ARMVectorReg scratch; + intptr_t reg_off; + SVEHostPage info, info2; - for (i = 0; i < oprsz; ) { - uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); + memset(&scratch, 0, reg_max); + reg_off = 0; + do { + uint64_t pg = vg[reg_off >> 6]; do { if (likely(pg & 1)) { - target_ulong off = off_fn(vm, i); - tlb_fn(env, &scratch, i, base + (off << scale), ra); + target_ulong addr = base + (off_fn(vm, reg_off) << scale); + target_ulong in_page = -(addr | TARGET_PAGE_MASK); + + sve_probe_page(&info, false, env, addr, 0, MMU_DATA_LOAD, + mmu_idx, retaddr); + + if (likely(in_page >= msize)) { + if (unlikely(info.flags & TLB_WATCHPOINT)) { + cpu_check_watchpoint(env_cpu(env), addr, msize, + info.attrs, BP_MEM_READ, retaddr); + } + /* TODO: MTE check */ + host_fn(&scratch, reg_off, info.host); + } else { + /* Element crosses the page boundary. */ + sve_probe_page(&info2, false, env, addr + in_page, 0, + MMU_DATA_LOAD, mmu_idx, retaddr); + if (unlikely((info.flags | info2.flags) & TLB_WATCHPOINT)) { + cpu_check_watchpoint(env_cpu(env), addr, + msize, info.attrs, + BP_MEM_READ, retaddr); + } + /* TODO: MTE check */ + tlb_fn(env, &scratch, reg_off, addr, retaddr); + } } - i += 4, pg >>= 4; - } while (i & 15); - } + reg_off += esize; + pg >>= esize; + } while (reg_off & 63); + } while (reg_off < reg_max); /* Wait until all exceptions have been raised to write back. */ - memcpy(vd, &scratch, oprsz); + memcpy(vd, &scratch, reg_max); } -static void sve_ld1_zd(CPUARMState *env, void *vd, void *vg, void *vm, - target_ulong base, uint32_t desc, uintptr_t ra, - zreg_off_fn *off_fn, sve_ldst1_tlb_fn *tlb_fn) -{ - const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); - intptr_t i, oprsz = simd_oprsz(desc) / 8; - ARMVectorReg scratch = { }; - - for (i = 0; i < oprsz; i++) { - uint8_t pg = *(uint8_t *)(vg + H1(i)); - if (likely(pg & 1)) { - target_ulong off = off_fn(vm, i * 8); - tlb_fn(env, &scratch, i * 8, base + (off << scale), ra); - } - } - - /* Wait until all exceptions have been raised to write back. */ - memcpy(vd, &scratch, oprsz * 8); +#define DO_LD1_ZPZ_S(MEM, OFS, MSZ) \ +void HELPER(sve_ld##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_ld1_z(env, vd, vg, vm, base, desc, GETPC(), 4, 1 << MSZ, \ + off_##OFS##_s, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ } -#define DO_LD1_ZPZ_S(MEM, OFS) \ -void QEMU_FLATTEN HELPER(sve_ld##MEM##_##OFS) \ - (CPUARMState *env, void *vd, void *vg, void *vm, \ - target_ulong base, uint32_t desc) \ -{ \ - sve_ld1_zs(env, vd, vg, vm, base, desc, GETPC(), \ - off_##OFS##_s, sve_ld1##MEM##_tlb); \ +#define DO_LD1_ZPZ_D(MEM, OFS, MSZ) \ +void HELPER(sve_ld##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_ld1_z(env, vd, vg, vm, base, desc, GETPC(), 8, 1 << MSZ, \ + off_##OFS##_d, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ } -#define DO_LD1_ZPZ_D(MEM, OFS) \ -void QEMU_FLATTEN HELPER(sve_ld##MEM##_##OFS) \ - (CPUARMState *env, void *vd, void *vg, void *vm, \ - target_ulong base, uint32_t desc) \ -{ \ - sve_ld1_zd(env, vd, vg, vm, base, desc, GETPC(), \ - off_##OFS##_d, sve_ld1##MEM##_tlb); \ -} +DO_LD1_ZPZ_S(bsu, zsu, MO_8) +DO_LD1_ZPZ_S(bsu, zss, MO_8) +DO_LD1_ZPZ_D(bdu, zsu, MO_8) +DO_LD1_ZPZ_D(bdu, zss, MO_8) +DO_LD1_ZPZ_D(bdu, zd, MO_8) -DO_LD1_ZPZ_S(bsu, zsu) -DO_LD1_ZPZ_S(bsu, zss) -DO_LD1_ZPZ_D(bdu, zsu) -DO_LD1_ZPZ_D(bdu, zss) -DO_LD1_ZPZ_D(bdu, zd) +DO_LD1_ZPZ_S(bss, zsu, MO_8) +DO_LD1_ZPZ_S(bss, zss, MO_8) +DO_LD1_ZPZ_D(bds, zsu, MO_8) +DO_LD1_ZPZ_D(bds, zss, MO_8) +DO_LD1_ZPZ_D(bds, zd, MO_8) -DO_LD1_ZPZ_S(bss, zsu) -DO_LD1_ZPZ_S(bss, zss) -DO_LD1_ZPZ_D(bds, zsu) -DO_LD1_ZPZ_D(bds, zss) -DO_LD1_ZPZ_D(bds, zd) +DO_LD1_ZPZ_S(hsu_le, zsu, MO_16) +DO_LD1_ZPZ_S(hsu_le, zss, MO_16) +DO_LD1_ZPZ_D(hdu_le, zsu, MO_16) +DO_LD1_ZPZ_D(hdu_le, zss, MO_16) +DO_LD1_ZPZ_D(hdu_le, zd, MO_16) -DO_LD1_ZPZ_S(hsu_le, zsu) -DO_LD1_ZPZ_S(hsu_le, zss) -DO_LD1_ZPZ_D(hdu_le, zsu) -DO_LD1_ZPZ_D(hdu_le, zss) -DO_LD1_ZPZ_D(hdu_le, zd) +DO_LD1_ZPZ_S(hsu_be, zsu, MO_16) +DO_LD1_ZPZ_S(hsu_be, zss, MO_16) +DO_LD1_ZPZ_D(hdu_be, zsu, MO_16) +DO_LD1_ZPZ_D(hdu_be, zss, MO_16) +DO_LD1_ZPZ_D(hdu_be, zd, MO_16) -DO_LD1_ZPZ_S(hsu_be, zsu) -DO_LD1_ZPZ_S(hsu_be, zss) -DO_LD1_ZPZ_D(hdu_be, zsu) -DO_LD1_ZPZ_D(hdu_be, zss) -DO_LD1_ZPZ_D(hdu_be, zd) +DO_LD1_ZPZ_S(hss_le, zsu, MO_16) +DO_LD1_ZPZ_S(hss_le, zss, MO_16) +DO_LD1_ZPZ_D(hds_le, zsu, MO_16) +DO_LD1_ZPZ_D(hds_le, zss, MO_16) +DO_LD1_ZPZ_D(hds_le, zd, MO_16) -DO_LD1_ZPZ_S(hss_le, zsu) -DO_LD1_ZPZ_S(hss_le, zss) -DO_LD1_ZPZ_D(hds_le, zsu) -DO_LD1_ZPZ_D(hds_le, zss) -DO_LD1_ZPZ_D(hds_le, zd) +DO_LD1_ZPZ_S(hss_be, zsu, MO_16) +DO_LD1_ZPZ_S(hss_be, zss, MO_16) +DO_LD1_ZPZ_D(hds_be, zsu, MO_16) +DO_LD1_ZPZ_D(hds_be, zss, MO_16) +DO_LD1_ZPZ_D(hds_be, zd, MO_16) -DO_LD1_ZPZ_S(hss_be, zsu) -DO_LD1_ZPZ_S(hss_be, zss) -DO_LD1_ZPZ_D(hds_be, zsu) -DO_LD1_ZPZ_D(hds_be, zss) -DO_LD1_ZPZ_D(hds_be, zd) +DO_LD1_ZPZ_S(ss_le, zsu, MO_32) +DO_LD1_ZPZ_S(ss_le, zss, MO_32) +DO_LD1_ZPZ_D(sdu_le, zsu, MO_32) +DO_LD1_ZPZ_D(sdu_le, zss, MO_32) +DO_LD1_ZPZ_D(sdu_le, zd, MO_32) -DO_LD1_ZPZ_S(ss_le, zsu) -DO_LD1_ZPZ_S(ss_le, zss) -DO_LD1_ZPZ_D(sdu_le, zsu) -DO_LD1_ZPZ_D(sdu_le, zss) -DO_LD1_ZPZ_D(sdu_le, zd) +DO_LD1_ZPZ_S(ss_be, zsu, MO_32) +DO_LD1_ZPZ_S(ss_be, zss, MO_32) +DO_LD1_ZPZ_D(sdu_be, zsu, MO_32) +DO_LD1_ZPZ_D(sdu_be, zss, MO_32) +DO_LD1_ZPZ_D(sdu_be, zd, MO_32) -DO_LD1_ZPZ_S(ss_be, zsu) -DO_LD1_ZPZ_S(ss_be, zss) -DO_LD1_ZPZ_D(sdu_be, zsu) -DO_LD1_ZPZ_D(sdu_be, zss) -DO_LD1_ZPZ_D(sdu_be, zd) +DO_LD1_ZPZ_D(sds_le, zsu, MO_32) +DO_LD1_ZPZ_D(sds_le, zss, MO_32) +DO_LD1_ZPZ_D(sds_le, zd, MO_32) -DO_LD1_ZPZ_D(sds_le, zsu) -DO_LD1_ZPZ_D(sds_le, zss) -DO_LD1_ZPZ_D(sds_le, zd) +DO_LD1_ZPZ_D(sds_be, zsu, MO_32) +DO_LD1_ZPZ_D(sds_be, zss, MO_32) +DO_LD1_ZPZ_D(sds_be, zd, MO_32) -DO_LD1_ZPZ_D(sds_be, zsu) -DO_LD1_ZPZ_D(sds_be, zss) -DO_LD1_ZPZ_D(sds_be, zd) +DO_LD1_ZPZ_D(dd_le, zsu, MO_64) +DO_LD1_ZPZ_D(dd_le, zss, MO_64) +DO_LD1_ZPZ_D(dd_le, zd, MO_64) -DO_LD1_ZPZ_D(dd_le, zsu) -DO_LD1_ZPZ_D(dd_le, zss) -DO_LD1_ZPZ_D(dd_le, zd) - -DO_LD1_ZPZ_D(dd_be, zsu) -DO_LD1_ZPZ_D(dd_be, zss) -DO_LD1_ZPZ_D(dd_be, zd) +DO_LD1_ZPZ_D(dd_be, zsu, MO_64) +DO_LD1_ZPZ_D(dd_be, zss, MO_64) +DO_LD1_ZPZ_D(dd_be, zd, MO_64) #undef DO_LD1_ZPZ_S #undef DO_LD1_ZPZ_D From ba080b8682fc6bde7f2d9dedddb519d63cbe138f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 8 May 2020 08:43:59 -0700 Subject: [PATCH 0384/2595] target/arm: Remove sve_memopidx None of the sve helpers use TCGMemOpIdx any longer, so we can stop passing it. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200508154359.7494-20-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/internals.h | 5 ----- target/arm/sve_helper.c | 14 +++++++------- target/arm/translate-sve.c | 17 +++-------------- 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index e633aff36e..a833e3941d 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -979,11 +979,6 @@ static inline int arm_num_ctx_cmps(ARMCPU *cpu) } } -/* Note make_memop_idx reserves 4 bits for mmu_idx, and MO_BSWAP is bit 3. - * Thus a TCGMemOpIdx, without any MO_ALIGN bits, fits in 8 bits. - */ -#define MEMOPIDX_SHIFT 8 - /** * v7m_using_psp: Return true if using process stack pointer * Return true if the CPU is currently using the process stack diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index f1870aabc2..116d535fa5 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -4440,7 +4440,7 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) { - const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); + const unsigned rd = simd_data(desc); const intptr_t reg_max = simd_oprsz(desc); intptr_t reg_off, reg_last, mem_off; SVEContLdSt info; @@ -4696,7 +4696,7 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr, sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) { - const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); + const unsigned rd = simd_data(desc); void *vd = &env->vfp.zregs[rd]; const intptr_t reg_max = simd_oprsz(desc); intptr_t reg_off, mem_off, reg_last; @@ -4925,7 +4925,7 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, uint32_t desc, sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) { - const unsigned rd = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 5); + const unsigned rd = simd_data(desc); const intptr_t reg_max = simd_oprsz(desc); intptr_t reg_off, reg_last, mem_off; SVEContLdSt info; @@ -5131,9 +5131,9 @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) { - const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); const int mmu_idx = cpu_mmu_index(env, false); const intptr_t reg_max = simd_oprsz(desc); + const int scale = simd_data(desc); ARMVectorReg scratch; intptr_t reg_off; SVEHostPage info, info2; @@ -5276,10 +5276,10 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, sve_ldst1_tlb_fn *tlb_fn) { const int mmu_idx = cpu_mmu_index(env, false); - const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); + const intptr_t reg_max = simd_oprsz(desc); + const int scale = simd_data(desc); const int esize = 1 << esz; const int msize = 1 << msz; - const intptr_t reg_max = simd_oprsz(desc); intptr_t reg_off; SVEHostPage info; target_ulong addr, in_page; @@ -5430,9 +5430,9 @@ void sve_st1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) { - const int scale = extract32(desc, SIMD_DATA_SHIFT + MEMOPIDX_SHIFT, 2); const int mmu_idx = cpu_mmu_index(env, false); const intptr_t reg_max = simd_oprsz(desc); + const int scale = simd_data(desc); void *host[ARM_MAX_VQ * 4]; intptr_t reg_off, i; SVEHostPage info, info2; diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 6c8bda4e4c..36816aafaf 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4582,11 +4582,6 @@ static const uint8_t dtype_esz[16] = { 3, 2, 1, 3 }; -static TCGMemOpIdx sve_memopidx(DisasContext *s, int dtype) -{ - return make_memop_idx(s->be_data | dtype_mop[dtype], get_mem_index(s)); -} - static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype, gen_helper_gvec_mem *fn) { @@ -4599,9 +4594,7 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, * registers as pointers, so encode the regno into the data field. * For consistency, do this even for LD1. */ - desc = sve_memopidx(s, dtype); - desc |= zt << MEMOPIDX_SHIFT; - desc = simd_desc(vsz, vsz, desc); + desc = simd_desc(vsz, vsz, zt); t_desc = tcg_const_i32(desc); t_pg = tcg_temp_new_ptr(); @@ -4833,9 +4826,7 @@ static void do_ldrq(DisasContext *s, int zt, int pg, TCGv_i64 addr, int msz) int desc, poff; /* Load the first quadword using the normal predicated load helpers. */ - desc = sve_memopidx(s, msz_dtype(s, msz)); - desc |= zt << MEMOPIDX_SHIFT; - desc = simd_desc(16, 16, desc); + desc = simd_desc(16, 16, zt); t_desc = tcg_const_i32(desc); poff = pred_full_reg_offset(s, pg); @@ -5064,9 +5055,7 @@ static void do_mem_zpz(DisasContext *s, int zt, int pg, int zm, TCGv_i32 t_desc; int desc; - desc = sve_memopidx(s, msz_dtype(s, msz)); - desc |= scale << MEMOPIDX_SHIFT; - desc = simd_desc(vsz, vsz, desc); + desc = simd_desc(vsz, vsz, scale); t_desc = tcg_const_i32(desc); tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg)); From f5cbb280bdd2cb5b8f44db015571591ef3c42665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 19:24:44 +0200 Subject: [PATCH 0385/2595] target/arm/kvm: Inline set_feature() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to move the inlined declarations of set_feature() from cpu*.c to cpu.h. To avoid clashing with the KVM declarations, inline the few KVM calls. Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200504172448.9402-2-philmd@redhat.com Signed-off-by: Peter Maydell --- target/arm/kvm32.c | 13 ++++--------- target/arm/kvm64.c | 22 ++++++---------------- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c index f271181ab8..7b3a19e9ae 100644 --- a/target/arm/kvm32.c +++ b/target/arm/kvm32.c @@ -22,11 +22,6 @@ #include "internals.h" #include "qemu/log.h" -static inline void set_feature(uint64_t *features, int feature) -{ - *features |= 1ULL << feature; -} - static int read_sys_reg32(int fd, uint32_t *pret, uint64_t id) { struct kvm_one_reg idreg = { .id = id, .addr = (uintptr_t)pret }; @@ -146,14 +141,14 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) * timers; this in turn implies most of the other feature * bits, but a few must be tested. */ - set_feature(&features, ARM_FEATURE_V7VE); - set_feature(&features, ARM_FEATURE_GENERIC_TIMER); + features |= 1ULL << ARM_FEATURE_V7VE; + features |= 1ULL << ARM_FEATURE_GENERIC_TIMER; if (extract32(id_pfr0, 12, 4) == 1) { - set_feature(&features, ARM_FEATURE_THUMB2EE); + features |= 1ULL << ARM_FEATURE_THUMB2EE; } if (extract32(ahcf->isar.mvfr1, 12, 4) == 1) { - set_feature(&features, ARM_FEATURE_NEON); + features |= 1ULL << ARM_FEATURE_NEON; } ahcf->features = features; diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index be5b31c2b0..cd8ab6b8ae 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -447,16 +447,6 @@ void kvm_arm_pmu_set_irq(CPUState *cs, int irq) } } -static inline void set_feature(uint64_t *features, int feature) -{ - *features |= 1ULL << feature; -} - -static inline void unset_feature(uint64_t *features, int feature) -{ - *features &= ~(1ULL << feature); -} - static int read_sys_reg32(int fd, uint32_t *pret, uint64_t id) { uint64_t ret; @@ -648,11 +638,11 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) * with VFPv4+Neon; this in turn implies most of the other * feature bits. */ - set_feature(&features, ARM_FEATURE_V8); - set_feature(&features, ARM_FEATURE_NEON); - set_feature(&features, ARM_FEATURE_AARCH64); - set_feature(&features, ARM_FEATURE_PMU); - set_feature(&features, ARM_FEATURE_GENERIC_TIMER); + features |= 1ULL << ARM_FEATURE_V8; + features |= 1ULL << ARM_FEATURE_NEON; + features |= 1ULL << ARM_FEATURE_AARCH64; + features |= 1ULL << ARM_FEATURE_PMU; + features |= 1ULL << ARM_FEATURE_GENERIC_TIMER; ahcf->features = features; @@ -802,7 +792,7 @@ int kvm_arch_init_vcpu(CPUState *cs) if (cpu->has_pmu) { cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3; } else { - unset_feature(&env->features, ARM_FEATURE_PMU); + env->features &= ~(1ULL << ARM_FEATURE_PMU); } if (cpu_isar_feature(aa64_sve, cpu)) { assert(kvm_arm_sve_supported(cs)); From 5fda95041d7237ab35733ceb66e0cb89f6107169 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 4 May 2020 19:24:45 +0200 Subject: [PATCH 0386/2595] target/arm: Make set_feature() available for other files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the common set_feature() and unset_feature() functions from cpu.c and cpu64.c to cpu.h. Suggested-by: Peter Maydell Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Reviewed-by: Eric Auger Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200504172448.9402-3-philmd@redhat.com Message-ID: <20190921150420.30743-2-thuth@redhat.com> [PMD: Split Thomas's patch in two: set_feature, cpu_register] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/cpu.c | 10 ---------- target/arm/cpu.h | 10 ++++++++++ target/arm/cpu64.c | 10 ---------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 5d64adfe76..13959cb643 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -725,16 +725,6 @@ static bool arm_cpu_virtio_is_big_endian(CPUState *cs) #endif -static inline void set_feature(CPUARMState *env, int feature) -{ - env->features |= 1ULL << feature; -} - -static inline void unset_feature(CPUARMState *env, int feature) -{ - env->features &= ~(1ULL << feature); -} - static int print_insn_thumb1(bfd_vma pc, disassemble_info *info) { diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 8608da6b6f..676f216b67 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -696,6 +696,16 @@ typedef struct CPUARMState { void *gicv3state; } CPUARMState; +static inline void set_feature(CPUARMState *env, int feature) +{ + env->features |= 1ULL << feature; +} + +static inline void unset_feature(CPUARMState *env, int feature) +{ + env->features &= ~(1ULL << feature); +} + /** * ARMELChangeHookFn: * type of a function which can be registered via arm_register_el_change_hook() diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 9bdf75b1ab..cbaa5ed228 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -29,16 +29,6 @@ #include "kvm_arm.h" #include "qapi/visitor.h" -static inline void set_feature(CPUARMState *env, int feature) -{ - env->features |= 1ULL << feature; -} - -static inline void unset_feature(CPUARMState *env, int feature) -{ - env->features &= ~(1ULL << feature); -} - #ifndef CONFIG_USER_ONLY static uint64_t a57_a53_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) { From 92b6a659388ab3735e5fbb17ac486923b681f57f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 19:24:46 +0200 Subject: [PATCH 0387/2595] target/arm/cpu: Use ARRAY_SIZE() to iterate over ARMCPUInfo[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use ARRAY_SIZE() to iterate over ARMCPUInfo[]. Since on the aarch64-linux-user build, arm_cpus[] is empty, add the cpu_count variable and only iterate when it is non-zero. Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200504172448.9402-4-philmd@redhat.com Signed-off-by: Peter Maydell --- target/arm/cpu.c | 16 +++++++++------- target/arm/cpu64.c | 8 +++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 13959cb643..b4d73dd47c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2739,7 +2739,6 @@ static const ARMCPUInfo arm_cpus[] = { { .name = "any", .initfn = arm_max_initfn }, #endif #endif - { .name = NULL } }; static Property arm_cpu_properties[] = { @@ -2887,19 +2886,22 @@ static const TypeInfo idau_interface_type_info = { static void arm_cpu_register_types(void) { - const ARMCPUInfo *info = arm_cpus; + const size_t cpu_count = ARRAY_SIZE(arm_cpus); type_register_static(&arm_cpu_type_info); type_register_static(&idau_interface_type_info); - while (info->name) { - arm_cpu_register(info); - info++; - } - #ifdef CONFIG_KVM type_register_static(&host_arm_cpu_type_info); #endif + + if (cpu_count) { + size_t i; + + for (i = 0; i < cpu_count; ++i) { + arm_cpu_register(&arm_cpus[i]); + } + } } type_init(arm_cpu_register_types) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index cbaa5ed228..f5c49ee32d 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -734,7 +734,6 @@ static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, { .name = "max", .initfn = aarch64_max_initfn }, - { .name = NULL } }; static bool aarch64_cpu_get_aarch64(Object *obj, Error **errp) @@ -840,13 +839,12 @@ static const TypeInfo aarch64_cpu_type_info = { static void aarch64_cpu_register_types(void) { - const ARMCPUInfo *info = aarch64_cpus; + size_t i; type_register_static(&aarch64_cpu_type_info); - while (info->name) { - aarch64_cpu_register(info); - info++; + for (i = 0; i < ARRAY_SIZE(aarch64_cpus); ++i) { + aarch64_cpu_register(&aarch64_cpus[i]); } } From fcdf0a90f791038c7e0a8546d00ca3168a7f3891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 19:24:47 +0200 Subject: [PATCH 0388/2595] target/arm/cpu: Restrict v8M IDAU interface to Aarch32 CPUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As IDAU is a v8M feature, restrict it to the Aarch32 CPUs. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20200504172448.9402-5-philmd@redhat.com Signed-off-by: Peter Maydell --- target/arm/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index b4d73dd47c..a10f8c4044 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2889,7 +2889,6 @@ static void arm_cpu_register_types(void) const size_t cpu_count = ARRAY_SIZE(arm_cpus); type_register_static(&arm_cpu_type_info); - type_register_static(&idau_interface_type_info); #ifdef CONFIG_KVM type_register_static(&host_arm_cpu_type_info); @@ -2898,6 +2897,7 @@ static void arm_cpu_register_types(void) if (cpu_count) { size_t i; + type_register_static(&idau_interface_type_info); for (i = 0; i < cpu_count; ++i) { arm_cpu_register(&arm_cpus[i]); } From 2465b07c0bd4f7a97bbcbefbd7f7432230485bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 19:24:48 +0200 Subject: [PATCH 0389/2595] target/arm: Restrict TCG cpus to TCG accel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A KVM-only build won't be able to run TCG cpus. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200504172448.9402-6-philmd@redhat.com Signed-off-by: Peter Maydell --- target/arm/Makefile.objs | 1 + target/arm/cpu.c | 634 ------------------------------------- target/arm/cpu_tcg.c | 664 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 665 insertions(+), 634 deletions(-) create mode 100644 target/arm/cpu_tcg.c diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs index 775b3e24f2..83febd232c 100644 --- a/target/arm/Makefile.objs +++ b/target/arm/Makefile.objs @@ -79,6 +79,7 @@ obj-y += translate.o op_helper.o obj-y += crypto_helper.o obj-y += iwmmxt_helper.o vec_helper.o neon_helper.o obj-y += m_helper.o +obj-y += cpu_tcg.o obj-$(CONFIG_SOFTMMU) += psci.o diff --git a/target/arm/cpu.c b/target/arm/cpu.c index a10f8c4044..3794f0dbc4 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -574,32 +574,6 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request) return true; } -#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) -static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -{ - CPUClass *cc = CPU_GET_CLASS(cs); - ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - bool ret = false; - - /* - * ARMv7-M interrupt masking works differently than -A or -R. - * There is no FIQ/IRQ distinction. Instead of I and F bits - * masking FIQ and IRQ interrupts, an exception is taken only - * if it is higher priority than the current execution priority - * (which depends on state like BASEPRI, FAULTMASK and the - * currently active exception). - */ - if (interrupt_request & CPU_INTERRUPT_HARD - && (armv7m_nvic_can_take_pending_exception(env->nvic))) { - cs->exception_index = EXCP_IRQ; - cc->do_interrupt(cs); - ret = true; - } - return ret; -} -#endif - void arm_cpu_update_virq(ARMCPU *cpu) { /* @@ -1820,406 +1794,6 @@ static ObjectClass *arm_cpu_class_by_name(const char *cpu_model) /* CPU models. These are not needed for the AArch64 linux-user build. */ #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) -static void arm926_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,arm926"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); - cpu->midr = 0x41069265; - cpu->reset_fpsid = 0x41011090; - cpu->ctr = 0x1dd20d2; - cpu->reset_sctlr = 0x00090078; - - /* - * ARMv5 does not have the ID_ISAR registers, but we can still - * set the field to indicate Jazelle support within QEMU. - */ - cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); - /* - * Similarly, we need to set MVFR0 fields to enable vfp and short vector - * support even though ARMv5 doesn't have this register. - */ - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSP, 1); - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); -} - -static void arm946_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,arm946"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_PMSA); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - cpu->midr = 0x41059461; - cpu->ctr = 0x0f004006; - cpu->reset_sctlr = 0x00000078; -} - -static void arm1026_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,arm1026"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_AUXCR); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); - cpu->midr = 0x4106a262; - cpu->reset_fpsid = 0x410110a0; - cpu->ctr = 0x1dd20d2; - cpu->reset_sctlr = 0x00090078; - cpu->reset_auxcr = 1; - - /* - * ARMv5 does not have the ID_ISAR registers, but we can still - * set the field to indicate Jazelle support within QEMU. - */ - cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); - /* - * Similarly, we need to set MVFR0 fields to enable vfp and short vector - * support even though ARMv5 doesn't have this register. - */ - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSP, 1); - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); - - { - /* The 1026 had an IFAR at c6,c0,0,1 rather than the ARMv6 c6,c0,0,2 */ - ARMCPRegInfo ifar = { - .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1, - .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.ifar_ns), - .resetvalue = 0 - }; - define_one_arm_cp_reg(cpu, &ifar); - } -} - -static void arm1136_r2_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - /* - * What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an - * older core than plain "arm1136". In particular this does not - * have the v6K features. - * These ID register values are correct for 1136 but may be wrong - * for 1136_r2 (in particular r0p2 does not actually implement most - * of the ID registers). - */ - - cpu->dtb_compatible = "arm,arm1136"; - set_feature(&cpu->env, ARM_FEATURE_V6); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); - set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); - cpu->midr = 0x4107b362; - cpu->reset_fpsid = 0x410120b4; - cpu->isar.mvfr0 = 0x11111111; - cpu->isar.mvfr1 = 0x00000000; - cpu->ctr = 0x1dd20d2; - cpu->reset_sctlr = 0x00050078; - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x1; - cpu->isar.id_dfr0 = 0x2; - cpu->id_afr0 = 0x3; - cpu->isar.id_mmfr0 = 0x01130003; - cpu->isar.id_mmfr1 = 0x10030302; - cpu->isar.id_mmfr2 = 0x01222110; - cpu->isar.id_isar0 = 0x00140011; - cpu->isar.id_isar1 = 0x12002111; - cpu->isar.id_isar2 = 0x11231111; - cpu->isar.id_isar3 = 0x01102131; - cpu->isar.id_isar4 = 0x141; - cpu->reset_auxcr = 7; -} - -static void arm1136_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,arm1136"; - set_feature(&cpu->env, ARM_FEATURE_V6K); - set_feature(&cpu->env, ARM_FEATURE_V6); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); - set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); - cpu->midr = 0x4117b363; - cpu->reset_fpsid = 0x410120b4; - cpu->isar.mvfr0 = 0x11111111; - cpu->isar.mvfr1 = 0x00000000; - cpu->ctr = 0x1dd20d2; - cpu->reset_sctlr = 0x00050078; - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x1; - cpu->isar.id_dfr0 = 0x2; - cpu->id_afr0 = 0x3; - cpu->isar.id_mmfr0 = 0x01130003; - cpu->isar.id_mmfr1 = 0x10030302; - cpu->isar.id_mmfr2 = 0x01222110; - cpu->isar.id_isar0 = 0x00140011; - cpu->isar.id_isar1 = 0x12002111; - cpu->isar.id_isar2 = 0x11231111; - cpu->isar.id_isar3 = 0x01102131; - cpu->isar.id_isar4 = 0x141; - cpu->reset_auxcr = 7; -} - -static void arm1176_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,arm1176"; - set_feature(&cpu->env, ARM_FEATURE_V6K); - set_feature(&cpu->env, ARM_FEATURE_VAPA); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); - set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); - set_feature(&cpu->env, ARM_FEATURE_EL3); - cpu->midr = 0x410fb767; - cpu->reset_fpsid = 0x410120b5; - cpu->isar.mvfr0 = 0x11111111; - cpu->isar.mvfr1 = 0x00000000; - cpu->ctr = 0x1dd20d2; - cpu->reset_sctlr = 0x00050078; - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x11; - cpu->isar.id_dfr0 = 0x33; - cpu->id_afr0 = 0; - cpu->isar.id_mmfr0 = 0x01130003; - cpu->isar.id_mmfr1 = 0x10030302; - cpu->isar.id_mmfr2 = 0x01222100; - cpu->isar.id_isar0 = 0x0140011; - cpu->isar.id_isar1 = 0x12002111; - cpu->isar.id_isar2 = 0x11231121; - cpu->isar.id_isar3 = 0x01102131; - cpu->isar.id_isar4 = 0x01141; - cpu->reset_auxcr = 7; -} - -static void arm11mpcore_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,arm11mpcore"; - set_feature(&cpu->env, ARM_FEATURE_V6K); - set_feature(&cpu->env, ARM_FEATURE_VAPA); - set_feature(&cpu->env, ARM_FEATURE_MPIDR); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - cpu->midr = 0x410fb022; - cpu->reset_fpsid = 0x410120b4; - cpu->isar.mvfr0 = 0x11111111; - cpu->isar.mvfr1 = 0x00000000; - cpu->ctr = 0x1d192992; /* 32K icache 32K dcache */ - cpu->id_pfr0 = 0x111; - cpu->id_pfr1 = 0x1; - cpu->isar.id_dfr0 = 0; - cpu->id_afr0 = 0x2; - cpu->isar.id_mmfr0 = 0x01100103; - cpu->isar.id_mmfr1 = 0x10020302; - cpu->isar.id_mmfr2 = 0x01222000; - cpu->isar.id_isar0 = 0x00100011; - cpu->isar.id_isar1 = 0x12002111; - cpu->isar.id_isar2 = 0x11221011; - cpu->isar.id_isar3 = 0x01102131; - cpu->isar.id_isar4 = 0x141; - cpu->reset_auxcr = 1; -} - -static void cortex_m0_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - set_feature(&cpu->env, ARM_FEATURE_V6); - set_feature(&cpu->env, ARM_FEATURE_M); - - cpu->midr = 0x410cc200; -} - -static void cortex_m3_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - set_feature(&cpu->env, ARM_FEATURE_V7); - set_feature(&cpu->env, ARM_FEATURE_M); - set_feature(&cpu->env, ARM_FEATURE_M_MAIN); - cpu->midr = 0x410fc231; - cpu->pmsav7_dregion = 8; - cpu->id_pfr0 = 0x00000030; - cpu->id_pfr1 = 0x00000200; - cpu->isar.id_dfr0 = 0x00100000; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_mmfr0 = 0x00000030; - cpu->isar.id_mmfr1 = 0x00000000; - cpu->isar.id_mmfr2 = 0x00000000; - cpu->isar.id_mmfr3 = 0x00000000; - cpu->isar.id_isar0 = 0x01141110; - cpu->isar.id_isar1 = 0x02111000; - cpu->isar.id_isar2 = 0x21112231; - cpu->isar.id_isar3 = 0x01111110; - cpu->isar.id_isar4 = 0x01310102; - cpu->isar.id_isar5 = 0x00000000; - cpu->isar.id_isar6 = 0x00000000; -} - -static void cortex_m4_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - set_feature(&cpu->env, ARM_FEATURE_V7); - set_feature(&cpu->env, ARM_FEATURE_M); - set_feature(&cpu->env, ARM_FEATURE_M_MAIN); - set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); - cpu->midr = 0x410fc240; /* r0p0 */ - cpu->pmsav7_dregion = 8; - cpu->isar.mvfr0 = 0x10110021; - cpu->isar.mvfr1 = 0x11000011; - cpu->isar.mvfr2 = 0x00000000; - cpu->id_pfr0 = 0x00000030; - cpu->id_pfr1 = 0x00000200; - cpu->isar.id_dfr0 = 0x00100000; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_mmfr0 = 0x00000030; - cpu->isar.id_mmfr1 = 0x00000000; - cpu->isar.id_mmfr2 = 0x00000000; - cpu->isar.id_mmfr3 = 0x00000000; - cpu->isar.id_isar0 = 0x01141110; - cpu->isar.id_isar1 = 0x02111000; - cpu->isar.id_isar2 = 0x21112231; - cpu->isar.id_isar3 = 0x01111110; - cpu->isar.id_isar4 = 0x01310102; - cpu->isar.id_isar5 = 0x00000000; - cpu->isar.id_isar6 = 0x00000000; -} - -static void cortex_m7_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - set_feature(&cpu->env, ARM_FEATURE_V7); - set_feature(&cpu->env, ARM_FEATURE_M); - set_feature(&cpu->env, ARM_FEATURE_M_MAIN); - set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); - cpu->midr = 0x411fc272; /* r1p2 */ - cpu->pmsav7_dregion = 8; - cpu->isar.mvfr0 = 0x10110221; - cpu->isar.mvfr1 = 0x12000011; - cpu->isar.mvfr2 = 0x00000040; - cpu->id_pfr0 = 0x00000030; - cpu->id_pfr1 = 0x00000200; - cpu->isar.id_dfr0 = 0x00100000; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_mmfr0 = 0x00100030; - cpu->isar.id_mmfr1 = 0x00000000; - cpu->isar.id_mmfr2 = 0x01000000; - cpu->isar.id_mmfr3 = 0x00000000; - cpu->isar.id_isar0 = 0x01101110; - cpu->isar.id_isar1 = 0x02112000; - cpu->isar.id_isar2 = 0x20232231; - cpu->isar.id_isar3 = 0x01111131; - cpu->isar.id_isar4 = 0x01310132; - cpu->isar.id_isar5 = 0x00000000; - cpu->isar.id_isar6 = 0x00000000; -} - -static void cortex_m33_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_M); - set_feature(&cpu->env, ARM_FEATURE_M_MAIN); - set_feature(&cpu->env, ARM_FEATURE_M_SECURITY); - set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); - cpu->midr = 0x410fd213; /* r0p3 */ - cpu->pmsav7_dregion = 16; - cpu->sau_sregion = 8; - cpu->isar.mvfr0 = 0x10110021; - cpu->isar.mvfr1 = 0x11000011; - cpu->isar.mvfr2 = 0x00000040; - cpu->id_pfr0 = 0x00000030; - cpu->id_pfr1 = 0x00000210; - cpu->isar.id_dfr0 = 0x00200000; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_mmfr0 = 0x00101F40; - cpu->isar.id_mmfr1 = 0x00000000; - cpu->isar.id_mmfr2 = 0x01000000; - cpu->isar.id_mmfr3 = 0x00000000; - cpu->isar.id_isar0 = 0x01101110; - cpu->isar.id_isar1 = 0x02212000; - cpu->isar.id_isar2 = 0x20232232; - cpu->isar.id_isar3 = 0x01111131; - cpu->isar.id_isar4 = 0x01310132; - cpu->isar.id_isar5 = 0x00000000; - cpu->isar.id_isar6 = 0x00000000; - cpu->clidr = 0x00000000; - cpu->ctr = 0x8000c000; -} - -static void arm_v7m_class_init(ObjectClass *oc, void *data) -{ - ARMCPUClass *acc = ARM_CPU_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); - - acc->info = data; -#ifndef CONFIG_USER_ONLY - cc->do_interrupt = arm_v7m_cpu_do_interrupt; -#endif - - cc->cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt; -} - -static const ARMCPRegInfo cortexr5_cp_reginfo[] = { - /* Dummy the TCM region regs for the moment */ - { .name = "ATCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST }, - { .name = "BTCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST }, - { .name = "DCACHE_INVAL", .cp = 15, .opc1 = 0, .crn = 15, .crm = 5, - .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP }, - REGINFO_SENTINEL -}; - -static void cortex_r5_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - set_feature(&cpu->env, ARM_FEATURE_V7); - set_feature(&cpu->env, ARM_FEATURE_V7MP); - set_feature(&cpu->env, ARM_FEATURE_PMSA); - set_feature(&cpu->env, ARM_FEATURE_PMU); - cpu->midr = 0x411fc153; /* r1p3 */ - cpu->id_pfr0 = 0x0131; - cpu->id_pfr1 = 0x001; - cpu->isar.id_dfr0 = 0x010400; - cpu->id_afr0 = 0x0; - cpu->isar.id_mmfr0 = 0x0210030; - cpu->isar.id_mmfr1 = 0x00000000; - cpu->isar.id_mmfr2 = 0x01200000; - cpu->isar.id_mmfr3 = 0x0211; - cpu->isar.id_isar0 = 0x02101111; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232141; - cpu->isar.id_isar3 = 0x01112131; - cpu->isar.id_isar4 = 0x0010142; - cpu->isar.id_isar5 = 0x0; - cpu->isar.id_isar6 = 0x0; - cpu->mp_is_up = true; - cpu->pmsav7_dregion = 16; - define_arm_cp_regs(cpu, cortexr5_cp_reginfo); -} - -static void cortex_r5f_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cortex_r5_initfn(obj); - cpu->isar.mvfr0 = 0x10110221; - cpu->isar.mvfr1 = 0x00000011; -} - static const ARMCPRegInfo cortexa8_cp_reginfo[] = { { .name = "L2LOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, @@ -2446,174 +2020,6 @@ static void cortex_a15_initfn(Object *obj) define_arm_cp_regs(cpu, cortexa15_cp_reginfo); } -static void ti925t_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - set_feature(&cpu->env, ARM_FEATURE_V4T); - set_feature(&cpu->env, ARM_FEATURE_OMAPCP); - cpu->midr = ARM_CPUID_TI925T; - cpu->ctr = 0x5109149; - cpu->reset_sctlr = 0x00000070; -} - -static void sa1100_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "intel,sa1100"; - set_feature(&cpu->env, ARM_FEATURE_STRONGARM); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - cpu->midr = 0x4401A11B; - cpu->reset_sctlr = 0x00000070; -} - -static void sa1110_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - set_feature(&cpu->env, ARM_FEATURE_STRONGARM); - set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); - cpu->midr = 0x6901B119; - cpu->reset_sctlr = 0x00000070; -} - -static void pxa250_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "marvell,xscale"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_XSCALE); - cpu->midr = 0x69052100; - cpu->ctr = 0xd172172; - cpu->reset_sctlr = 0x00000078; -} - -static void pxa255_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "marvell,xscale"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_XSCALE); - cpu->midr = 0x69052d00; - cpu->ctr = 0xd172172; - cpu->reset_sctlr = 0x00000078; -} - -static void pxa260_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "marvell,xscale"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_XSCALE); - cpu->midr = 0x69052903; - cpu->ctr = 0xd172172; - cpu->reset_sctlr = 0x00000078; -} - -static void pxa261_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "marvell,xscale"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_XSCALE); - cpu->midr = 0x69052d05; - cpu->ctr = 0xd172172; - cpu->reset_sctlr = 0x00000078; -} - -static void pxa262_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "marvell,xscale"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_XSCALE); - cpu->midr = 0x69052d06; - cpu->ctr = 0xd172172; - cpu->reset_sctlr = 0x00000078; -} - -static void pxa270a0_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "marvell,xscale"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_XSCALE); - set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = 0x69054110; - cpu->ctr = 0xd172172; - cpu->reset_sctlr = 0x00000078; -} - -static void pxa270a1_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "marvell,xscale"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_XSCALE); - set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = 0x69054111; - cpu->ctr = 0xd172172; - cpu->reset_sctlr = 0x00000078; -} - -static void pxa270b0_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "marvell,xscale"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_XSCALE); - set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = 0x69054112; - cpu->ctr = 0xd172172; - cpu->reset_sctlr = 0x00000078; -} - -static void pxa270b1_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "marvell,xscale"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_XSCALE); - set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = 0x69054113; - cpu->ctr = 0xd172172; - cpu->reset_sctlr = 0x00000078; -} - -static void pxa270c0_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "marvell,xscale"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_XSCALE); - set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = 0x69054114; - cpu->ctr = 0xd172172; - cpu->reset_sctlr = 0x00000078; -} - -static void pxa270c5_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "marvell,xscale"; - set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_XSCALE); - set_feature(&cpu->env, ARM_FEATURE_IWMMXT); - cpu->midr = 0x69054117; - cpu->ctr = 0xd172172; - cpu->reset_sctlr = 0x00000078; -} - #ifndef TARGET_AARCH64 /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); * otherwise, a CPU with as many features enabled as our emulation supports. @@ -2688,50 +2094,10 @@ static void arm_max_initfn(Object *obj) static const ARMCPUInfo arm_cpus[] = { #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) - { .name = "arm926", .initfn = arm926_initfn }, - { .name = "arm946", .initfn = arm946_initfn }, - { .name = "arm1026", .initfn = arm1026_initfn }, - /* - * What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an - * older core than plain "arm1136". In particular this does not - * have the v6K features. - */ - { .name = "arm1136-r2", .initfn = arm1136_r2_initfn }, - { .name = "arm1136", .initfn = arm1136_initfn }, - { .name = "arm1176", .initfn = arm1176_initfn }, - { .name = "arm11mpcore", .initfn = arm11mpcore_initfn }, - { .name = "cortex-m0", .initfn = cortex_m0_initfn, - .class_init = arm_v7m_class_init }, - { .name = "cortex-m3", .initfn = cortex_m3_initfn, - .class_init = arm_v7m_class_init }, - { .name = "cortex-m4", .initfn = cortex_m4_initfn, - .class_init = arm_v7m_class_init }, - { .name = "cortex-m7", .initfn = cortex_m7_initfn, - .class_init = arm_v7m_class_init }, - { .name = "cortex-m33", .initfn = cortex_m33_initfn, - .class_init = arm_v7m_class_init }, - { .name = "cortex-r5", .initfn = cortex_r5_initfn }, - { .name = "cortex-r5f", .initfn = cortex_r5f_initfn }, { .name = "cortex-a7", .initfn = cortex_a7_initfn }, { .name = "cortex-a8", .initfn = cortex_a8_initfn }, { .name = "cortex-a9", .initfn = cortex_a9_initfn }, { .name = "cortex-a15", .initfn = cortex_a15_initfn }, - { .name = "ti925t", .initfn = ti925t_initfn }, - { .name = "sa1100", .initfn = sa1100_initfn }, - { .name = "sa1110", .initfn = sa1110_initfn }, - { .name = "pxa250", .initfn = pxa250_initfn }, - { .name = "pxa255", .initfn = pxa255_initfn }, - { .name = "pxa260", .initfn = pxa260_initfn }, - { .name = "pxa261", .initfn = pxa261_initfn }, - { .name = "pxa262", .initfn = pxa262_initfn }, - /* "pxa270" is an alias for "pxa270-a0" */ - { .name = "pxa270", .initfn = pxa270a0_initfn }, - { .name = "pxa270-a0", .initfn = pxa270a0_initfn }, - { .name = "pxa270-a1", .initfn = pxa270a1_initfn }, - { .name = "pxa270-b0", .initfn = pxa270b0_initfn }, - { .name = "pxa270-b1", .initfn = pxa270b1_initfn }, - { .name = "pxa270-c0", .initfn = pxa270c0_initfn }, - { .name = "pxa270-c5", .initfn = pxa270c5_initfn }, #ifndef TARGET_AARCH64 { .name = "max", .initfn = arm_max_initfn }, #endif diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c new file mode 100644 index 0000000000..591baef535 --- /dev/null +++ b/target/arm/cpu_tcg.c @@ -0,0 +1,664 @@ +/* + * QEMU ARM TCG CPUs. + * + * Copyright (c) 2012 SUSE LINUX Products GmbH + * + * This code is licensed under the GNU GPL v2 or later. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internals.h" + +/* CPU models. These are not needed for the AArch64 linux-user build. */ +#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) + +static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + CPUClass *cc = CPU_GET_CLASS(cs); + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + bool ret = false; + + /* + * ARMv7-M interrupt masking works differently than -A or -R. + * There is no FIQ/IRQ distinction. Instead of I and F bits + * masking FIQ and IRQ interrupts, an exception is taken only + * if it is higher priority than the current execution priority + * (which depends on state like BASEPRI, FAULTMASK and the + * currently active exception). + */ + if (interrupt_request & CPU_INTERRUPT_HARD + && (armv7m_nvic_can_take_pending_exception(env->nvic))) { + cs->exception_index = EXCP_IRQ; + cc->do_interrupt(cs); + ret = true; + } + return ret; +} + +static void arm926_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,arm926"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); + cpu->midr = 0x41069265; + cpu->reset_fpsid = 0x41011090; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00090078; + + /* + * ARMv5 does not have the ID_ISAR registers, but we can still + * set the field to indicate Jazelle support within QEMU. + */ + cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); + /* + * Similarly, we need to set MVFR0 fields to enable vfp and short vector + * support even though ARMv5 doesn't have this register. + */ + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSP, 1); + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); +} + +static void arm946_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,arm946"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_PMSA); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + cpu->midr = 0x41059461; + cpu->ctr = 0x0f004006; + cpu->reset_sctlr = 0x00000078; +} + +static void arm1026_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,arm1026"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_AUXCR); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); + cpu->midr = 0x4106a262; + cpu->reset_fpsid = 0x410110a0; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00090078; + cpu->reset_auxcr = 1; + + /* + * ARMv5 does not have the ID_ISAR registers, but we can still + * set the field to indicate Jazelle support within QEMU. + */ + cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); + /* + * Similarly, we need to set MVFR0 fields to enable vfp and short vector + * support even though ARMv5 doesn't have this register. + */ + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSP, 1); + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); + + { + /* The 1026 had an IFAR at c6,c0,0,1 rather than the ARMv6 c6,c0,0,2 */ + ARMCPRegInfo ifar = { + .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.ifar_ns), + .resetvalue = 0 + }; + define_one_arm_cp_reg(cpu, &ifar); + } +} + +static void arm1136_r2_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + /* + * What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an + * older core than plain "arm1136". In particular this does not + * have the v6K features. + * These ID register values are correct for 1136 but may be wrong + * for 1136_r2 (in particular r0p2 does not actually implement most + * of the ID registers). + */ + + cpu->dtb_compatible = "arm,arm1136"; + set_feature(&cpu->env, ARM_FEATURE_V6); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); + cpu->midr = 0x4107b362; + cpu->reset_fpsid = 0x410120b4; + cpu->isar.mvfr0 = 0x11111111; + cpu->isar.mvfr1 = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x1; + cpu->isar.id_dfr0 = 0x2; + cpu->id_afr0 = 0x3; + cpu->isar.id_mmfr0 = 0x01130003; + cpu->isar.id_mmfr1 = 0x10030302; + cpu->isar.id_mmfr2 = 0x01222110; + cpu->isar.id_isar0 = 0x00140011; + cpu->isar.id_isar1 = 0x12002111; + cpu->isar.id_isar2 = 0x11231111; + cpu->isar.id_isar3 = 0x01102131; + cpu->isar.id_isar4 = 0x141; + cpu->reset_auxcr = 7; +} + +static void arm1136_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,arm1136"; + set_feature(&cpu->env, ARM_FEATURE_V6K); + set_feature(&cpu->env, ARM_FEATURE_V6); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); + cpu->midr = 0x4117b363; + cpu->reset_fpsid = 0x410120b4; + cpu->isar.mvfr0 = 0x11111111; + cpu->isar.mvfr1 = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x1; + cpu->isar.id_dfr0 = 0x2; + cpu->id_afr0 = 0x3; + cpu->isar.id_mmfr0 = 0x01130003; + cpu->isar.id_mmfr1 = 0x10030302; + cpu->isar.id_mmfr2 = 0x01222110; + cpu->isar.id_isar0 = 0x00140011; + cpu->isar.id_isar1 = 0x12002111; + cpu->isar.id_isar2 = 0x11231111; + cpu->isar.id_isar3 = 0x01102131; + cpu->isar.id_isar4 = 0x141; + cpu->reset_auxcr = 7; +} + +static void arm1176_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,arm1176"; + set_feature(&cpu->env, ARM_FEATURE_V6K); + set_feature(&cpu->env, ARM_FEATURE_VAPA); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); + set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); + set_feature(&cpu->env, ARM_FEATURE_EL3); + cpu->midr = 0x410fb767; + cpu->reset_fpsid = 0x410120b5; + cpu->isar.mvfr0 = 0x11111111; + cpu->isar.mvfr1 = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x11; + cpu->isar.id_dfr0 = 0x33; + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x01130003; + cpu->isar.id_mmfr1 = 0x10030302; + cpu->isar.id_mmfr2 = 0x01222100; + cpu->isar.id_isar0 = 0x0140011; + cpu->isar.id_isar1 = 0x12002111; + cpu->isar.id_isar2 = 0x11231121; + cpu->isar.id_isar3 = 0x01102131; + cpu->isar.id_isar4 = 0x01141; + cpu->reset_auxcr = 7; +} + +static void arm11mpcore_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,arm11mpcore"; + set_feature(&cpu->env, ARM_FEATURE_V6K); + set_feature(&cpu->env, ARM_FEATURE_VAPA); + set_feature(&cpu->env, ARM_FEATURE_MPIDR); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + cpu->midr = 0x410fb022; + cpu->reset_fpsid = 0x410120b4; + cpu->isar.mvfr0 = 0x11111111; + cpu->isar.mvfr1 = 0x00000000; + cpu->ctr = 0x1d192992; /* 32K icache 32K dcache */ + cpu->id_pfr0 = 0x111; + cpu->id_pfr1 = 0x1; + cpu->isar.id_dfr0 = 0; + cpu->id_afr0 = 0x2; + cpu->isar.id_mmfr0 = 0x01100103; + cpu->isar.id_mmfr1 = 0x10020302; + cpu->isar.id_mmfr2 = 0x01222000; + cpu->isar.id_isar0 = 0x00100011; + cpu->isar.id_isar1 = 0x12002111; + cpu->isar.id_isar2 = 0x11221011; + cpu->isar.id_isar3 = 0x01102131; + cpu->isar.id_isar4 = 0x141; + cpu->reset_auxcr = 1; +} + +static void cortex_m0_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + set_feature(&cpu->env, ARM_FEATURE_V6); + set_feature(&cpu->env, ARM_FEATURE_M); + + cpu->midr = 0x410cc200; +} + +static void cortex_m3_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_M); + set_feature(&cpu->env, ARM_FEATURE_M_MAIN); + cpu->midr = 0x410fc231; + cpu->pmsav7_dregion = 8; + cpu->id_pfr0 = 0x00000030; + cpu->id_pfr1 = 0x00000200; + cpu->isar.id_dfr0 = 0x00100000; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00000030; + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x00000000; + cpu->isar.id_mmfr3 = 0x00000000; + cpu->isar.id_isar0 = 0x01141110; + cpu->isar.id_isar1 = 0x02111000; + cpu->isar.id_isar2 = 0x21112231; + cpu->isar.id_isar3 = 0x01111110; + cpu->isar.id_isar4 = 0x01310102; + cpu->isar.id_isar5 = 0x00000000; + cpu->isar.id_isar6 = 0x00000000; +} + +static void cortex_m4_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_M); + set_feature(&cpu->env, ARM_FEATURE_M_MAIN); + set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); + cpu->midr = 0x410fc240; /* r0p0 */ + cpu->pmsav7_dregion = 8; + cpu->isar.mvfr0 = 0x10110021; + cpu->isar.mvfr1 = 0x11000011; + cpu->isar.mvfr2 = 0x00000000; + cpu->id_pfr0 = 0x00000030; + cpu->id_pfr1 = 0x00000200; + cpu->isar.id_dfr0 = 0x00100000; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00000030; + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x00000000; + cpu->isar.id_mmfr3 = 0x00000000; + cpu->isar.id_isar0 = 0x01141110; + cpu->isar.id_isar1 = 0x02111000; + cpu->isar.id_isar2 = 0x21112231; + cpu->isar.id_isar3 = 0x01111110; + cpu->isar.id_isar4 = 0x01310102; + cpu->isar.id_isar5 = 0x00000000; + cpu->isar.id_isar6 = 0x00000000; +} + +static void cortex_m7_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_M); + set_feature(&cpu->env, ARM_FEATURE_M_MAIN); + set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); + cpu->midr = 0x411fc272; /* r1p2 */ + cpu->pmsav7_dregion = 8; + cpu->isar.mvfr0 = 0x10110221; + cpu->isar.mvfr1 = 0x12000011; + cpu->isar.mvfr2 = 0x00000040; + cpu->id_pfr0 = 0x00000030; + cpu->id_pfr1 = 0x00000200; + cpu->isar.id_dfr0 = 0x00100000; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00100030; + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x01000000; + cpu->isar.id_mmfr3 = 0x00000000; + cpu->isar.id_isar0 = 0x01101110; + cpu->isar.id_isar1 = 0x02112000; + cpu->isar.id_isar2 = 0x20232231; + cpu->isar.id_isar3 = 0x01111131; + cpu->isar.id_isar4 = 0x01310132; + cpu->isar.id_isar5 = 0x00000000; + cpu->isar.id_isar6 = 0x00000000; +} + +static void cortex_m33_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_M); + set_feature(&cpu->env, ARM_FEATURE_M_MAIN); + set_feature(&cpu->env, ARM_FEATURE_M_SECURITY); + set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); + cpu->midr = 0x410fd213; /* r0p3 */ + cpu->pmsav7_dregion = 16; + cpu->sau_sregion = 8; + cpu->isar.mvfr0 = 0x10110021; + cpu->isar.mvfr1 = 0x11000011; + cpu->isar.mvfr2 = 0x00000040; + cpu->id_pfr0 = 0x00000030; + cpu->id_pfr1 = 0x00000210; + cpu->isar.id_dfr0 = 0x00200000; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00101F40; + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x01000000; + cpu->isar.id_mmfr3 = 0x00000000; + cpu->isar.id_isar0 = 0x01101110; + cpu->isar.id_isar1 = 0x02212000; + cpu->isar.id_isar2 = 0x20232232; + cpu->isar.id_isar3 = 0x01111131; + cpu->isar.id_isar4 = 0x01310132; + cpu->isar.id_isar5 = 0x00000000; + cpu->isar.id_isar6 = 0x00000000; + cpu->clidr = 0x00000000; + cpu->ctr = 0x8000c000; +} + +static const ARMCPRegInfo cortexr5_cp_reginfo[] = { + /* Dummy the TCM region regs for the moment */ + { .name = "ATCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_CONST }, + { .name = "BTCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_CONST }, + { .name = "DCACHE_INVAL", .cp = 15, .opc1 = 0, .crn = 15, .crm = 5, + .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP }, + REGINFO_SENTINEL +}; + +static void cortex_r5_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_V7MP); + set_feature(&cpu->env, ARM_FEATURE_PMSA); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->midr = 0x411fc153; /* r1p3 */ + cpu->id_pfr0 = 0x0131; + cpu->id_pfr1 = 0x001; + cpu->isar.id_dfr0 = 0x010400; + cpu->id_afr0 = 0x0; + cpu->isar.id_mmfr0 = 0x0210030; + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x01200000; + cpu->isar.id_mmfr3 = 0x0211; + cpu->isar.id_isar0 = 0x02101111; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232141; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x0010142; + cpu->isar.id_isar5 = 0x0; + cpu->isar.id_isar6 = 0x0; + cpu->mp_is_up = true; + cpu->pmsav7_dregion = 16; + define_arm_cp_regs(cpu, cortexr5_cp_reginfo); +} + +static void cortex_r5f_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cortex_r5_initfn(obj); + cpu->isar.mvfr0 = 0x10110221; + cpu->isar.mvfr1 = 0x00000011; +} + +static void ti925t_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + set_feature(&cpu->env, ARM_FEATURE_V4T); + set_feature(&cpu->env, ARM_FEATURE_OMAPCP); + cpu->midr = ARM_CPUID_TI925T; + cpu->ctr = 0x5109149; + cpu->reset_sctlr = 0x00000070; +} + +static void sa1100_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "intel,sa1100"; + set_feature(&cpu->env, ARM_FEATURE_STRONGARM); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + cpu->midr = 0x4401A11B; + cpu->reset_sctlr = 0x00000070; +} + +static void sa1110_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + set_feature(&cpu->env, ARM_FEATURE_STRONGARM); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + cpu->midr = 0x6901B119; + cpu->reset_sctlr = 0x00000070; +} + +static void pxa250_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "marvell,xscale"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_XSCALE); + cpu->midr = 0x69052100; + cpu->ctr = 0xd172172; + cpu->reset_sctlr = 0x00000078; +} + +static void pxa255_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "marvell,xscale"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_XSCALE); + cpu->midr = 0x69052d00; + cpu->ctr = 0xd172172; + cpu->reset_sctlr = 0x00000078; +} + +static void pxa260_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "marvell,xscale"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_XSCALE); + cpu->midr = 0x69052903; + cpu->ctr = 0xd172172; + cpu->reset_sctlr = 0x00000078; +} + +static void pxa261_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "marvell,xscale"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_XSCALE); + cpu->midr = 0x69052d05; + cpu->ctr = 0xd172172; + cpu->reset_sctlr = 0x00000078; +} + +static void pxa262_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "marvell,xscale"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_XSCALE); + cpu->midr = 0x69052d06; + cpu->ctr = 0xd172172; + cpu->reset_sctlr = 0x00000078; +} + +static void pxa270a0_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "marvell,xscale"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_XSCALE); + set_feature(&cpu->env, ARM_FEATURE_IWMMXT); + cpu->midr = 0x69054110; + cpu->ctr = 0xd172172; + cpu->reset_sctlr = 0x00000078; +} + +static void pxa270a1_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "marvell,xscale"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_XSCALE); + set_feature(&cpu->env, ARM_FEATURE_IWMMXT); + cpu->midr = 0x69054111; + cpu->ctr = 0xd172172; + cpu->reset_sctlr = 0x00000078; +} + +static void pxa270b0_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "marvell,xscale"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_XSCALE); + set_feature(&cpu->env, ARM_FEATURE_IWMMXT); + cpu->midr = 0x69054112; + cpu->ctr = 0xd172172; + cpu->reset_sctlr = 0x00000078; +} + +static void pxa270b1_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "marvell,xscale"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_XSCALE); + set_feature(&cpu->env, ARM_FEATURE_IWMMXT); + cpu->midr = 0x69054113; + cpu->ctr = 0xd172172; + cpu->reset_sctlr = 0x00000078; +} + +static void pxa270c0_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "marvell,xscale"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_XSCALE); + set_feature(&cpu->env, ARM_FEATURE_IWMMXT); + cpu->midr = 0x69054114; + cpu->ctr = 0xd172172; + cpu->reset_sctlr = 0x00000078; +} + +static void pxa270c5_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "marvell,xscale"; + set_feature(&cpu->env, ARM_FEATURE_V5); + set_feature(&cpu->env, ARM_FEATURE_XSCALE); + set_feature(&cpu->env, ARM_FEATURE_IWMMXT); + cpu->midr = 0x69054117; + cpu->ctr = 0xd172172; + cpu->reset_sctlr = 0x00000078; +} + +static void arm_v7m_class_init(ObjectClass *oc, void *data) +{ + ARMCPUClass *acc = ARM_CPU_CLASS(oc); + CPUClass *cc = CPU_CLASS(oc); + + acc->info = data; +#ifndef CONFIG_USER_ONLY + cc->do_interrupt = arm_v7m_cpu_do_interrupt; +#endif + + cc->cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt; +} + +static const ARMCPUInfo arm_tcg_cpus[] = { + { .name = "arm926", .initfn = arm926_initfn }, + { .name = "arm946", .initfn = arm946_initfn }, + { .name = "arm1026", .initfn = arm1026_initfn }, + /* + * What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an + * older core than plain "arm1136". In particular this does not + * have the v6K features. + */ + { .name = "arm1136-r2", .initfn = arm1136_r2_initfn }, + { .name = "arm1136", .initfn = arm1136_initfn }, + { .name = "arm1176", .initfn = arm1176_initfn }, + { .name = "arm11mpcore", .initfn = arm11mpcore_initfn }, + { .name = "cortex-m0", .initfn = cortex_m0_initfn, + .class_init = arm_v7m_class_init }, + { .name = "cortex-m3", .initfn = cortex_m3_initfn, + .class_init = arm_v7m_class_init }, + { .name = "cortex-m4", .initfn = cortex_m4_initfn, + .class_init = arm_v7m_class_init }, + { .name = "cortex-m7", .initfn = cortex_m7_initfn, + .class_init = arm_v7m_class_init }, + { .name = "cortex-m33", .initfn = cortex_m33_initfn, + .class_init = arm_v7m_class_init }, + { .name = "cortex-r5", .initfn = cortex_r5_initfn }, + { .name = "cortex-r5f", .initfn = cortex_r5f_initfn }, + { .name = "ti925t", .initfn = ti925t_initfn }, + { .name = "sa1100", .initfn = sa1100_initfn }, + { .name = "sa1110", .initfn = sa1110_initfn }, + { .name = "pxa250", .initfn = pxa250_initfn }, + { .name = "pxa255", .initfn = pxa255_initfn }, + { .name = "pxa260", .initfn = pxa260_initfn }, + { .name = "pxa261", .initfn = pxa261_initfn }, + { .name = "pxa262", .initfn = pxa262_initfn }, + /* "pxa270" is an alias for "pxa270-a0" */ + { .name = "pxa270", .initfn = pxa270a0_initfn }, + { .name = "pxa270-a0", .initfn = pxa270a0_initfn }, + { .name = "pxa270-a1", .initfn = pxa270a1_initfn }, + { .name = "pxa270-b0", .initfn = pxa270b0_initfn }, + { .name = "pxa270-b1", .initfn = pxa270b1_initfn }, + { .name = "pxa270-c0", .initfn = pxa270c0_initfn }, + { .name = "pxa270-c5", .initfn = pxa270c5_initfn }, +}; + +static void arm_tcg_cpu_register_types(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(arm_tcg_cpus); ++i) { + arm_cpu_register(&arm_tcg_cpus[i]); + } +} + +type_init(arm_tcg_cpu_register_types) + +#endif /* !CONFIG_USER_ONLY || !TARGET_AARCH64 */ From 4758567bc00ee52e0861202206f4b8fab5e1af90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 5 May 2020 11:59:45 +0200 Subject: [PATCH 0390/2595] hw/arm/musicpal: Map the UART devices unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I can't find proper documentation or datasheet, but it is likely a MMIO mapped serial device mapped in the 0x80000000..0x8000ffff range belongs to the SoC address space, thus is always mapped in the memory bus. Map the devices on the bus regardless a chardev is attached to it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Jan Kiszka Message-id: 20200505095945.23146-1-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/musicpal.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index b2d0cfdac8..92f33ed87e 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -1619,14 +1619,10 @@ static void musicpal_init(MachineState *machine) pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ], pic[MP_TIMER4_IRQ], NULL); - if (serial_hd(0)) { - serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ], - 1825000, serial_hd(0), DEVICE_NATIVE_ENDIAN); - } - if (serial_hd(1)) { - serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ], - 1825000, serial_hd(1), DEVICE_NATIVE_ENDIAN); - } + serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ], + 1825000, serial_hd(0), DEVICE_NATIVE_ENDIAN); + serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ], + 1825000, serial_hd(1), DEVICE_NATIVE_ENDIAN); /* Register flash */ dinfo = drive_get(IF_PFLASH, 0, 0); From 08975da9f0bfcfa654628cae71201a351ba5449a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 7 May 2020 10:23:49 -0700 Subject: [PATCH 0391/2595] target/arm: Use tcg_gen_gvec_5_ptr for sve FMLA/FCMLA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we can pass 7 parameters, do not encode register operands within simd_data. Reviewed-by: Alex Bennée Reviewed-by: Taylor Simpson Signed-off-by: Richard Henderson Message-id: 20200507172352.15418-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-sve.h | 45 +++++++---- target/arm/sve_helper.c | 157 ++++++++++++++----------------------- target/arm/translate-sve.c | 70 ++++++----------- 3 files changed, 114 insertions(+), 158 deletions(-) diff --git a/target/arm/helper-sve.h b/target/arm/helper-sve.h index 2f47279155..7a200755ac 100644 --- a/target/arm/helper-sve.h +++ b/target/arm/helper-sve.h @@ -1099,25 +1099,40 @@ DEF_HELPER_FLAGS_6(sve_fcadd_s, TCG_CALL_NO_RWG, DEF_HELPER_FLAGS_6(sve_fcadd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fmla_zpzzz_h, TCG_CALL_NO_RWG, void, env, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fmla_zpzzz_s, TCG_CALL_NO_RWG, void, env, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fmla_zpzzz_d, TCG_CALL_NO_RWG, void, env, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fmla_zpzzz_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fmla_zpzzz_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fmla_zpzzz_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fmls_zpzzz_h, TCG_CALL_NO_RWG, void, env, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fmls_zpzzz_s, TCG_CALL_NO_RWG, void, env, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fmls_zpzzz_d, TCG_CALL_NO_RWG, void, env, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fmls_zpzzz_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fmls_zpzzz_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fmls_zpzzz_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fnmla_zpzzz_h, TCG_CALL_NO_RWG, void, env, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fnmla_zpzzz_s, TCG_CALL_NO_RWG, void, env, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fnmla_zpzzz_d, TCG_CALL_NO_RWG, void, env, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fnmla_zpzzz_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fnmla_zpzzz_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fnmla_zpzzz_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fnmls_zpzzz_h, TCG_CALL_NO_RWG, void, env, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fnmls_zpzzz_s, TCG_CALL_NO_RWG, void, env, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fnmls_zpzzz_d, TCG_CALL_NO_RWG, void, env, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fnmls_zpzzz_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fnmls_zpzzz_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fnmls_zpzzz_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fcmla_zpzzz_h, TCG_CALL_NO_RWG, void, env, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fcmla_zpzzz_s, TCG_CALL_NO_RWG, void, env, ptr, i32) -DEF_HELPER_FLAGS_3(sve_fcmla_zpzzz_d, TCG_CALL_NO_RWG, void, env, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fcmla_zpzzz_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fcmla_zpzzz_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_7(sve_fcmla_zpzzz_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(sve_ftmad_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(sve_ftmad_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 116d535fa5..0da254d402 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -3372,23 +3372,11 @@ DO_ZPZ_FP(sve_ucvt_dd, uint64_t, , uint64_to_float64) #undef DO_ZPZ_FP -/* 4-operand predicated multiply-add. This requires 7 operands to pass - * "properly", so we need to encode some of the registers into DESC. - */ -QEMU_BUILD_BUG_ON(SIMD_DATA_SHIFT + 20 > 32); - -static void do_fmla_zpzzz_h(CPUARMState *env, void *vg, uint32_t desc, +static void do_fmla_zpzzz_h(void *vd, void *vn, void *vm, void *va, void *vg, + float_status *status, uint32_t desc, uint16_t neg1, uint16_t neg3) { intptr_t i = simd_oprsz(desc); - unsigned rd = extract32(desc, SIMD_DATA_SHIFT, 5); - unsigned rn = extract32(desc, SIMD_DATA_SHIFT + 5, 5); - unsigned rm = extract32(desc, SIMD_DATA_SHIFT + 10, 5); - unsigned ra = extract32(desc, SIMD_DATA_SHIFT + 15, 5); - void *vd = &env->vfp.zregs[rd]; - void *vn = &env->vfp.zregs[rn]; - void *vm = &env->vfp.zregs[rm]; - void *va = &env->vfp.zregs[ra]; uint64_t *g = vg; do { @@ -3401,45 +3389,42 @@ static void do_fmla_zpzzz_h(CPUARMState *env, void *vg, uint32_t desc, e1 = *(uint16_t *)(vn + H1_2(i)) ^ neg1; e2 = *(uint16_t *)(vm + H1_2(i)); e3 = *(uint16_t *)(va + H1_2(i)) ^ neg3; - r = float16_muladd(e1, e2, e3, 0, &env->vfp.fp_status_f16); + r = float16_muladd(e1, e2, e3, 0, status); *(uint16_t *)(vd + H1_2(i)) = r; } } while (i & 63); } while (i != 0); } -void HELPER(sve_fmla_zpzzz_h)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fmla_zpzzz_h)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_h(env, vg, desc, 0, 0); + do_fmla_zpzzz_h(vd, vn, vm, va, vg, status, desc, 0, 0); } -void HELPER(sve_fmls_zpzzz_h)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fmls_zpzzz_h)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_h(env, vg, desc, 0x8000, 0); + do_fmla_zpzzz_h(vd, vn, vm, va, vg, status, desc, 0x8000, 0); } -void HELPER(sve_fnmla_zpzzz_h)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fnmla_zpzzz_h)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_h(env, vg, desc, 0x8000, 0x8000); + do_fmla_zpzzz_h(vd, vn, vm, va, vg, status, desc, 0x8000, 0x8000); } -void HELPER(sve_fnmls_zpzzz_h)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fnmls_zpzzz_h)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_h(env, vg, desc, 0, 0x8000); + do_fmla_zpzzz_h(vd, vn, vm, va, vg, status, desc, 0, 0x8000); } -static void do_fmla_zpzzz_s(CPUARMState *env, void *vg, uint32_t desc, +static void do_fmla_zpzzz_s(void *vd, void *vn, void *vm, void *va, void *vg, + float_status *status, uint32_t desc, uint32_t neg1, uint32_t neg3) { intptr_t i = simd_oprsz(desc); - unsigned rd = extract32(desc, SIMD_DATA_SHIFT, 5); - unsigned rn = extract32(desc, SIMD_DATA_SHIFT + 5, 5); - unsigned rm = extract32(desc, SIMD_DATA_SHIFT + 10, 5); - unsigned ra = extract32(desc, SIMD_DATA_SHIFT + 15, 5); - void *vd = &env->vfp.zregs[rd]; - void *vn = &env->vfp.zregs[rn]; - void *vm = &env->vfp.zregs[rm]; - void *va = &env->vfp.zregs[ra]; uint64_t *g = vg; do { @@ -3452,45 +3437,42 @@ static void do_fmla_zpzzz_s(CPUARMState *env, void *vg, uint32_t desc, e1 = *(uint32_t *)(vn + H1_4(i)) ^ neg1; e2 = *(uint32_t *)(vm + H1_4(i)); e3 = *(uint32_t *)(va + H1_4(i)) ^ neg3; - r = float32_muladd(e1, e2, e3, 0, &env->vfp.fp_status); + r = float32_muladd(e1, e2, e3, 0, status); *(uint32_t *)(vd + H1_4(i)) = r; } } while (i & 63); } while (i != 0); } -void HELPER(sve_fmla_zpzzz_s)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fmla_zpzzz_s)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_s(env, vg, desc, 0, 0); + do_fmla_zpzzz_s(vd, vn, vm, va, vg, status, desc, 0, 0); } -void HELPER(sve_fmls_zpzzz_s)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fmls_zpzzz_s)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_s(env, vg, desc, 0x80000000, 0); + do_fmla_zpzzz_s(vd, vn, vm, va, vg, status, desc, 0x80000000, 0); } -void HELPER(sve_fnmla_zpzzz_s)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fnmla_zpzzz_s)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_s(env, vg, desc, 0x80000000, 0x80000000); + do_fmla_zpzzz_s(vd, vn, vm, va, vg, status, desc, 0x80000000, 0x80000000); } -void HELPER(sve_fnmls_zpzzz_s)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fnmls_zpzzz_s)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_s(env, vg, desc, 0, 0x80000000); + do_fmla_zpzzz_s(vd, vn, vm, va, vg, status, desc, 0, 0x80000000); } -static void do_fmla_zpzzz_d(CPUARMState *env, void *vg, uint32_t desc, +static void do_fmla_zpzzz_d(void *vd, void *vn, void *vm, void *va, void *vg, + float_status *status, uint32_t desc, uint64_t neg1, uint64_t neg3) { intptr_t i = simd_oprsz(desc); - unsigned rd = extract32(desc, SIMD_DATA_SHIFT, 5); - unsigned rn = extract32(desc, SIMD_DATA_SHIFT + 5, 5); - unsigned rm = extract32(desc, SIMD_DATA_SHIFT + 10, 5); - unsigned ra = extract32(desc, SIMD_DATA_SHIFT + 15, 5); - void *vd = &env->vfp.zregs[rd]; - void *vn = &env->vfp.zregs[rn]; - void *vm = &env->vfp.zregs[rm]; - void *va = &env->vfp.zregs[ra]; uint64_t *g = vg; do { @@ -3503,31 +3485,35 @@ static void do_fmla_zpzzz_d(CPUARMState *env, void *vg, uint32_t desc, e1 = *(uint64_t *)(vn + i) ^ neg1; e2 = *(uint64_t *)(vm + i); e3 = *(uint64_t *)(va + i) ^ neg3; - r = float64_muladd(e1, e2, e3, 0, &env->vfp.fp_status); + r = float64_muladd(e1, e2, e3, 0, status); *(uint64_t *)(vd + i) = r; } } while (i & 63); } while (i != 0); } -void HELPER(sve_fmla_zpzzz_d)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fmla_zpzzz_d)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_d(env, vg, desc, 0, 0); + do_fmla_zpzzz_d(vd, vn, vm, va, vg, status, desc, 0, 0); } -void HELPER(sve_fmls_zpzzz_d)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fmls_zpzzz_d)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_d(env, vg, desc, INT64_MIN, 0); + do_fmla_zpzzz_d(vd, vn, vm, va, vg, status, desc, INT64_MIN, 0); } -void HELPER(sve_fnmla_zpzzz_d)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fnmla_zpzzz_d)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_d(env, vg, desc, INT64_MIN, INT64_MIN); + do_fmla_zpzzz_d(vd, vn, vm, va, vg, status, desc, INT64_MIN, INT64_MIN); } -void HELPER(sve_fnmls_zpzzz_d)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fnmls_zpzzz_d)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { - do_fmla_zpzzz_d(env, vg, desc, 0, INT64_MIN); + do_fmla_zpzzz_d(vd, vn, vm, va, vg, status, desc, 0, INT64_MIN); } /* Two operand floating-point comparison controlled by a predicate. @@ -3809,22 +3795,13 @@ void HELPER(sve_fcadd_d)(void *vd, void *vn, void *vm, void *vg, * FP Complex Multiply */ -QEMU_BUILD_BUG_ON(SIMD_DATA_SHIFT + 22 > 32); - -void HELPER(sve_fcmla_zpzzz_h)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fcmla_zpzzz_h)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { intptr_t j, i = simd_oprsz(desc); - unsigned rd = extract32(desc, SIMD_DATA_SHIFT, 5); - unsigned rn = extract32(desc, SIMD_DATA_SHIFT + 5, 5); - unsigned rm = extract32(desc, SIMD_DATA_SHIFT + 10, 5); - unsigned ra = extract32(desc, SIMD_DATA_SHIFT + 15, 5); - unsigned rot = extract32(desc, SIMD_DATA_SHIFT + 20, 2); + unsigned rot = simd_data(desc); bool flip = rot & 1; float16 neg_imag, neg_real; - void *vd = &env->vfp.zregs[rd]; - void *vn = &env->vfp.zregs[rn]; - void *vm = &env->vfp.zregs[rm]; - void *va = &env->vfp.zregs[ra]; uint64_t *g = vg; neg_imag = float16_set_sign(0, (rot & 2) != 0); @@ -3851,32 +3828,25 @@ void HELPER(sve_fcmla_zpzzz_h)(CPUARMState *env, void *vg, uint32_t desc) if (likely((pg >> (i & 63)) & 1)) { d = *(float16 *)(va + H1_2(i)); - d = float16_muladd(e2, e1, d, 0, &env->vfp.fp_status_f16); + d = float16_muladd(e2, e1, d, 0, status); *(float16 *)(vd + H1_2(i)) = d; } if (likely((pg >> (j & 63)) & 1)) { d = *(float16 *)(va + H1_2(j)); - d = float16_muladd(e4, e3, d, 0, &env->vfp.fp_status_f16); + d = float16_muladd(e4, e3, d, 0, status); *(float16 *)(vd + H1_2(j)) = d; } } while (i & 63); } while (i != 0); } -void HELPER(sve_fcmla_zpzzz_s)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fcmla_zpzzz_s)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { intptr_t j, i = simd_oprsz(desc); - unsigned rd = extract32(desc, SIMD_DATA_SHIFT, 5); - unsigned rn = extract32(desc, SIMD_DATA_SHIFT + 5, 5); - unsigned rm = extract32(desc, SIMD_DATA_SHIFT + 10, 5); - unsigned ra = extract32(desc, SIMD_DATA_SHIFT + 15, 5); - unsigned rot = extract32(desc, SIMD_DATA_SHIFT + 20, 2); + unsigned rot = simd_data(desc); bool flip = rot & 1; float32 neg_imag, neg_real; - void *vd = &env->vfp.zregs[rd]; - void *vn = &env->vfp.zregs[rn]; - void *vm = &env->vfp.zregs[rm]; - void *va = &env->vfp.zregs[ra]; uint64_t *g = vg; neg_imag = float32_set_sign(0, (rot & 2) != 0); @@ -3903,32 +3873,25 @@ void HELPER(sve_fcmla_zpzzz_s)(CPUARMState *env, void *vg, uint32_t desc) if (likely((pg >> (i & 63)) & 1)) { d = *(float32 *)(va + H1_2(i)); - d = float32_muladd(e2, e1, d, 0, &env->vfp.fp_status); + d = float32_muladd(e2, e1, d, 0, status); *(float32 *)(vd + H1_2(i)) = d; } if (likely((pg >> (j & 63)) & 1)) { d = *(float32 *)(va + H1_2(j)); - d = float32_muladd(e4, e3, d, 0, &env->vfp.fp_status); + d = float32_muladd(e4, e3, d, 0, status); *(float32 *)(vd + H1_2(j)) = d; } } while (i & 63); } while (i != 0); } -void HELPER(sve_fcmla_zpzzz_d)(CPUARMState *env, void *vg, uint32_t desc) +void HELPER(sve_fcmla_zpzzz_d)(void *vd, void *vn, void *vm, void *va, + void *vg, void *status, uint32_t desc) { intptr_t j, i = simd_oprsz(desc); - unsigned rd = extract32(desc, SIMD_DATA_SHIFT, 5); - unsigned rn = extract32(desc, SIMD_DATA_SHIFT + 5, 5); - unsigned rm = extract32(desc, SIMD_DATA_SHIFT + 10, 5); - unsigned ra = extract32(desc, SIMD_DATA_SHIFT + 15, 5); - unsigned rot = extract32(desc, SIMD_DATA_SHIFT + 20, 2); + unsigned rot = simd_data(desc); bool flip = rot & 1; float64 neg_imag, neg_real; - void *vd = &env->vfp.zregs[rd]; - void *vn = &env->vfp.zregs[rn]; - void *vm = &env->vfp.zregs[rm]; - void *va = &env->vfp.zregs[ra]; uint64_t *g = vg; neg_imag = float64_set_sign(0, (rot & 2) != 0); @@ -3955,12 +3918,12 @@ void HELPER(sve_fcmla_zpzzz_d)(CPUARMState *env, void *vg, uint32_t desc) if (likely((pg >> (i & 63)) & 1)) { d = *(float64 *)(va + H1_2(i)); - d = float64_muladd(e2, e1, d, 0, &env->vfp.fp_status); + d = float64_muladd(e2, e1, d, 0, status); *(float64 *)(vd + H1_2(i)) = d; } if (likely((pg >> (j & 63)) & 1)) { d = *(float64 *)(va + H1_2(j)); - d = float64_muladd(e4, e3, d, 0, &env->vfp.fp_status); + d = float64_muladd(e4, e3, d, 0, status); *(float64 *)(vd + H1_2(j)) = d; } } while (i & 63); diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 36816aafaf..8398c32362 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -3946,42 +3946,30 @@ static bool trans_FCADD(DisasContext *s, arg_FCADD *a) return true; } -typedef void gen_helper_sve_fmla(TCGv_env, TCGv_ptr, TCGv_i32); - -static bool do_fmla(DisasContext *s, arg_rprrr_esz *a, gen_helper_sve_fmla *fn) +static bool do_fmla(DisasContext *s, arg_rprrr_esz *a, + gen_helper_gvec_5_ptr *fn) { - if (fn == NULL) { + if (a->esz == 0) { return false; } - if (!sve_access_check(s)) { - return true; + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr status = get_fpstatus_ptr(a->esz == MO_16); + tcg_gen_gvec_5_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + vec_full_reg_offset(s, a->ra), + pred_full_reg_offset(s, a->pg), + status, vsz, vsz, 0, fn); + tcg_temp_free_ptr(status); } - - unsigned vsz = vec_full_reg_size(s); - unsigned desc; - TCGv_i32 t_desc; - TCGv_ptr pg = tcg_temp_new_ptr(); - - /* We would need 7 operands to pass these arguments "properly". - * So we encode all the register numbers into the descriptor. - */ - desc = deposit32(a->rd, 5, 5, a->rn); - desc = deposit32(desc, 10, 5, a->rm); - desc = deposit32(desc, 15, 5, a->ra); - desc = simd_desc(vsz, vsz, desc); - - t_desc = tcg_const_i32(desc); - tcg_gen_addi_ptr(pg, cpu_env, pred_full_reg_offset(s, a->pg)); - fn(cpu_env, pg, t_desc); - tcg_temp_free_i32(t_desc); - tcg_temp_free_ptr(pg); return true; } #define DO_FMLA(NAME, name) \ static bool trans_##NAME(DisasContext *s, arg_rprrr_esz *a) \ { \ - static gen_helper_sve_fmla * const fns[4] = { \ + static gen_helper_gvec_5_ptr * const fns[4] = { \ NULL, gen_helper_sve_##name##_h, \ gen_helper_sve_##name##_s, gen_helper_sve_##name##_d \ }; \ @@ -3997,7 +3985,8 @@ DO_FMLA(FNMLS_zpzzz, fnmls_zpzzz) static bool trans_FCMLA_zpzzz(DisasContext *s, arg_FCMLA_zpzzz *a) { - static gen_helper_sve_fmla * const fns[3] = { + static gen_helper_gvec_5_ptr * const fns[4] = { + NULL, gen_helper_sve_fcmla_zpzzz_h, gen_helper_sve_fcmla_zpzzz_s, gen_helper_sve_fcmla_zpzzz_d, @@ -4008,25 +3997,14 @@ static bool trans_FCMLA_zpzzz(DisasContext *s, arg_FCMLA_zpzzz *a) } if (sve_access_check(s)) { unsigned vsz = vec_full_reg_size(s); - unsigned desc; - TCGv_i32 t_desc; - TCGv_ptr pg = tcg_temp_new_ptr(); - - /* We would need 7 operands to pass these arguments "properly". - * So we encode all the register numbers into the descriptor. - */ - desc = deposit32(a->rd, 5, 5, a->rn); - desc = deposit32(desc, 10, 5, a->rm); - desc = deposit32(desc, 15, 5, a->ra); - desc = deposit32(desc, 20, 2, a->rot); - desc = sextract32(desc, 0, 22); - desc = simd_desc(vsz, vsz, desc); - - t_desc = tcg_const_i32(desc); - tcg_gen_addi_ptr(pg, cpu_env, pred_full_reg_offset(s, a->pg)); - fns[a->esz - 1](cpu_env, pg, t_desc); - tcg_temp_free_i32(t_desc); - tcg_temp_free_ptr(pg); + TCGv_ptr status = get_fpstatus_ptr(a->esz == MO_16); + tcg_gen_gvec_5_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + vec_full_reg_offset(s, a->ra), + pred_full_reg_offset(s, a->pg), + status, vsz, vsz, a->rot, fns[a->esz]); + tcg_temp_free_ptr(status); } return true; } From 7e17d50ebd359ee5fa3d65d7fdc0fe0336d60694 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 7 May 2020 10:23:52 -0700 Subject: [PATCH 0392/2595] target/arm: Fix tcg_gen_gvec_dup_imm vs DUP (indexed) DUP (indexed) can duplicate 128-bit elements, so using esz unconditionally can assert in tcg_gen_gvec_dup_imm. Fixes: 8711e71f9cbb Reported-by: Laurent Desnogues Signed-off-by: Richard Henderson Reviewed-by: Laurent Desnogues Tested-by: Laurent Desnogues Message-id: 20200507172352.15418-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 8398c32362..ac7b3119e5 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -2044,7 +2044,11 @@ static bool trans_DUP_x(DisasContext *s, arg_DUP_x *a) unsigned nofs = vec_reg_offset(s, a->rn, index, esz); tcg_gen_gvec_dup_mem(esz, dofs, nofs, vsz, vsz); } else { - tcg_gen_gvec_dup_imm(esz, dofs, vsz, vsz, 0); + /* + * While dup_mem handles 128-bit elements, dup_imm does not. + * Thankfully element size doesn't matter for splatting zero. + */ + tcg_gen_gvec_dup_imm(MO_64, dofs, vsz, vsz, 0); } } return true; From aadad398e7dc21fe177278498c1be31b8c7d5078 Mon Sep 17 00:00:00 2001 From: Jafar Abdi Date: Sat, 23 Mar 2019 17:26:37 +0300 Subject: [PATCH 0393/2595] hw/tpm: fix usage of bool in tpm-tis.c Clean up wrong usage of FALSE and TRUE in places that use "bool" from stdbool.h. FALSE and TRUE (with capital letters) are the constants defined by glib for being used with the "gboolean" type of glib. But some parts of the code also use TRUE and FALSE for variables that are declared as "bool" (the type from ). Signed-off-by: Jafar Abdi Reviewed-by: Thomas Huth Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c index 9ce64d4836..1af4bce139 100644 --- a/hw/tpm/tpm_tis_common.c +++ b/hw/tpm/tpm_tis_common.c @@ -536,7 +536,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, while ((TPM_TIS_IS_VALID_LOCTY(s->active_locty) && locty > s->active_locty) || !TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { - bool higher_seize = FALSE; + bool higher_seize = false; /* already a pending SEIZE ? */ if ((s->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) { @@ -546,7 +546,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, /* check for ongoing seize by a higher locality */ for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) { if ((s->loc[l].access & TPM_TIS_ACCESS_SEIZE)) { - higher_seize = TRUE; + higher_seize = true; break; } } From 70b6d525dfb51d5e523d568d1139fc051bc223c5 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 30 Apr 2020 11:46:06 -0400 Subject: [PATCH 0394/2595] hostmem: don't use mbind() if host-nodes is empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 5.0 QEMU uses hostmem backend for allocating main guest RAM. The backend however calls mbind() which is typically NOP in case of default policy/absent host-nodes bitmap. However when runing in container with black-listed mbind() syscall, QEMU fails to start with error "cannot bind memory to host NUMA nodes: Operation not permitted" even when user hasn't provided host-nodes to pin to explictly (which is the case with -m option) To fix issue, call mbind() only in case when user has provided host-nodes explicitly (i.e. host_nodes bitmap is not empty). That should allow to run QEMU in containers with black-listed mbind() without memory pinning. If QEMU provided memory-pinning is required user still has to white-list mbind() in container configuration. Reported-by: Manuel Hohmann Signed-off-by: Igor Mammedov Message-Id: <20200430154606.6421-1-imammedo@redhat.com> Tested-by: Philippe Mathieu-Daudé Cc: qemu-stable@nongnu.org Signed-off-by: Eduardo Habkost --- backends/hostmem.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backends/hostmem.c b/backends/hostmem.c index 327f9eebc3..0efd7b7bd6 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -383,8 +383,10 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp) assert(sizeof(backend->host_nodes) >= BITS_TO_LONGS(MAX_NODES + 1) * sizeof(unsigned long)); assert(maxnode <= MAX_NODES); - if (mbind(ptr, sz, backend->policy, - maxnode ? backend->host_nodes : NULL, maxnode + 1, flags)) { + + if (maxnode && + mbind(ptr, sz, backend->policy, backend->host_nodes, maxnode + 1, + flags)) { if (backend->policy != MPOL_DEFAULT || errno != ENOSYS) { error_setg_errno(errp, errno, "cannot bind memory to host NUMA nodes"); From 572ad9783f3e728a70617ce6bf144c09de3add50 Mon Sep 17 00:00:00 2001 From: Denis Plotnikov Date: Thu, 7 May 2020 11:25:18 +0300 Subject: [PATCH 0395/2595] qcow2: introduce compression type feature The patch adds some preparation parts for incompatible compression type feature to qcow2 allowing the use different compression methods for image clusters (de)compressing. It is implied that the compression type is set on the image creation and can be changed only later by image conversion, thus compression type defines the only compression algorithm used for the image, and thus, for all image clusters. The goal of the feature is to add support of other compression methods to qcow2. For example, ZSTD which is more effective on compression than ZLIB. The default compression is ZLIB. Images created with ZLIB compression type are backward compatible with older qemu versions. Adding of the compression type breaks a number of tests because now the compression type is reported on image creation and there are some changes in the qcow2 header in size and offsets. The tests are fixed in the following ways: * filter out compression_type for many tests * fix header size, feature table size and backing file offset affected tests: 031, 036, 061, 080 header_size +=8: 1 byte compression type 7 bytes padding feature_table += 48: incompatible feature compression type backing_file_offset += 56 (8 + 48 -> header_change + feature_table_change) * add "compression type" for test output matching when it isn't filtered affected tests: 049, 060, 061, 065, 082, 085, 144, 182, 185, 198, 206, 242, 255, 274, 280 Signed-off-by: Denis Plotnikov Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Reviewed-by: Max Reitz QAPI part: Acked-by: Markus Armbruster Message-Id: <20200507082521.29210-2-dplotnikov@virtuozzo.com> Signed-off-by: Max Reitz --- block/qcow2.c | 113 +++++++++++++++++++++++++++++++ block/qcow2.h | 20 +++++- include/block/block_int.h | 1 + qapi/block-core.json | 22 +++++- tests/qemu-iotests/031.out | 14 ++-- tests/qemu-iotests/036.out | 4 +- tests/qemu-iotests/049.out | 102 ++++++++++++++-------------- tests/qemu-iotests/060.out | 1 + tests/qemu-iotests/061.out | 34 ++++++---- tests/qemu-iotests/065 | 28 +++++--- tests/qemu-iotests/080 | 2 +- tests/qemu-iotests/082.out | 48 +++++++++++-- tests/qemu-iotests/085.out | 38 +++++------ tests/qemu-iotests/144.out | 4 +- tests/qemu-iotests/182.out | 2 +- tests/qemu-iotests/185.out | 8 +-- tests/qemu-iotests/198.out | 2 + tests/qemu-iotests/206.out | 5 ++ tests/qemu-iotests/242.out | 5 ++ tests/qemu-iotests/255.out | 8 +-- tests/qemu-iotests/274.out | 49 +++++++------- tests/qemu-iotests/280.out | 2 +- tests/qemu-iotests/common.filter | 3 +- 23 files changed, 365 insertions(+), 150 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 1ad95ff048..b878a6a474 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1242,6 +1242,39 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options, return ret; } +static int validate_compression_type(BDRVQcow2State *s, Error **errp) +{ + switch (s->compression_type) { + case QCOW2_COMPRESSION_TYPE_ZLIB: + break; + + default: + error_setg(errp, "qcow2: unknown compression type: %u", + s->compression_type); + return -ENOTSUP; + } + + /* + * if the compression type differs from QCOW2_COMPRESSION_TYPE_ZLIB + * the incompatible feature flag must be set + */ + if (s->compression_type == QCOW2_COMPRESSION_TYPE_ZLIB) { + if (s->incompatible_features & QCOW2_INCOMPAT_COMPRESSION) { + error_setg(errp, "qcow2: Compression type incompatible feature " + "bit must not be set"); + return -EINVAL; + } + } else { + if (!(s->incompatible_features & QCOW2_INCOMPAT_COMPRESSION)) { + error_setg(errp, "qcow2: Compression type incompatible feature " + "bit must be set"); + return -EINVAL; + } + } + + return 0; +} + /* Called with s->lock held. */ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) @@ -1357,6 +1390,23 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, s->compatible_features = header.compatible_features; s->autoclear_features = header.autoclear_features; + /* + * Handle compression type + * Older qcow2 images don't contain the compression type header. + * Distinguish them by the header length and use + * the only valid (default) compression type in that case + */ + if (header.header_length > offsetof(QCowHeader, compression_type)) { + s->compression_type = header.compression_type; + } else { + s->compression_type = QCOW2_COMPRESSION_TYPE_ZLIB; + } + + ret = validate_compression_type(s, errp); + if (ret) { + goto fail; + } + if (s->incompatible_features & ~QCOW2_INCOMPAT_MASK) { void *feature_table = NULL; qcow2_read_extensions(bs, header.header_length, ext_end, @@ -2728,6 +2778,11 @@ int qcow2_update_header(BlockDriverState *bs) total_size = bs->total_sectors * BDRV_SECTOR_SIZE; refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3); + ret = validate_compression_type(s, NULL); + if (ret) { + goto fail; + } + *header = (QCowHeader) { /* Version 2 fields */ .magic = cpu_to_be32(QCOW_MAGIC), @@ -2750,6 +2805,7 @@ int qcow2_update_header(BlockDriverState *bs) .autoclear_features = cpu_to_be64(s->autoclear_features), .refcount_order = cpu_to_be32(s->refcount_order), .header_length = cpu_to_be32(header_length), + .compression_type = s->compression_type, }; /* For older versions, write a shorter header */ @@ -2849,6 +2905,11 @@ int qcow2_update_header(BlockDriverState *bs) .bit = QCOW2_INCOMPAT_DATA_FILE_BITNR, .name = "external data file", }, + { + .type = QCOW2_FEAT_TYPE_INCOMPATIBLE, + .bit = QCOW2_INCOMPAT_COMPRESSION_BITNR, + .name = "compression type", + }, { .type = QCOW2_FEAT_TYPE_COMPATIBLE, .bit = QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR, @@ -3287,6 +3348,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) uint64_t* refcount_table; Error *local_err = NULL; int ret; + uint8_t compression_type = QCOW2_COMPRESSION_TYPE_ZLIB; assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2); qcow2_opts = &create_options->u.qcow2; @@ -3404,6 +3466,27 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } } + if (qcow2_opts->has_compression_type && + qcow2_opts->compression_type != QCOW2_COMPRESSION_TYPE_ZLIB) { + + ret = -EINVAL; + + if (version < 3) { + error_setg(errp, "Non-zlib compression type is only supported with " + "compatibility level 1.1 and above (use version=v3 or " + "greater)"); + goto out; + } + + switch (qcow2_opts->compression_type) { + default: + error_setg(errp, "Unknown compression type"); + goto out; + } + + compression_type = qcow2_opts->compression_type; + } + /* Create BlockBackend to write to the image */ blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, errp); @@ -3426,6 +3509,8 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) .refcount_table_offset = cpu_to_be64(cluster_size), .refcount_table_clusters = cpu_to_be32(1), .refcount_order = cpu_to_be32(refcount_order), + /* don't deal with endianness since compression_type is 1 byte long */ + .compression_type = compression_type, .header_length = cpu_to_be32(sizeof(*header)), }; @@ -3444,6 +3529,10 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) header->autoclear_features |= cpu_to_be64(QCOW2_AUTOCLEAR_DATA_FILE_RAW); } + if (compression_type != QCOW2_COMPRESSION_TYPE_ZLIB) { + header->incompatible_features |= + cpu_to_be64(QCOW2_INCOMPAT_COMPRESSION); + } ret = blk_pwrite(blk, 0, header, cluster_size, 0); g_free(header); @@ -3629,6 +3718,7 @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv, { BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT }, { BLOCK_OPT_COMPAT_LEVEL, "version" }, { BLOCK_OPT_DATA_FILE_RAW, "data-file-raw" }, + { BLOCK_OPT_COMPRESSION_TYPE, "compression-type" }, { NULL, NULL }, }; @@ -4925,6 +5015,7 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, .data_file = g_strdup(s->image_data_file), .has_data_file_raw = has_data_file(bs), .data_file_raw = data_file_is_raw(bs), + .compression_type = s->compression_type, }; } else { /* if this assertion fails, this probably means a new version was @@ -5330,6 +5421,22 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, "images"); return -EINVAL; } + } else if (!strcmp(desc->name, BLOCK_OPT_COMPRESSION_TYPE)) { + const char *ct_name = + qemu_opt_get(opts, BLOCK_OPT_COMPRESSION_TYPE); + int compression_type = + qapi_enum_parse(&Qcow2CompressionType_lookup, ct_name, -1, + NULL); + if (compression_type == -1) { + error_setg(errp, "Unknown compression type: %s", ct_name); + return -ENOTSUP; + } + + if (compression_type != s->compression_type) { + error_setg(errp, "Changing the compression type " + "is not supported"); + return -ENOTSUP; + } } else { /* if this point is reached, this probably means a new option was * added without having it covered here */ @@ -5596,6 +5703,12 @@ static QemuOptsList qcow2_create_opts = { .help = "Width of a reference count entry in bits", .def_value_str = "16" }, + { + .name = BLOCK_OPT_COMPRESSION_TYPE, + .type = QEMU_OPT_STRING, + .help = "Compression method used for image cluster compression", + .def_value_str = "zlib" + }, { /* end of list */ } } }; diff --git a/block/qcow2.h b/block/qcow2.h index f4de0a27d5..6a8b82e6cc 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -146,8 +146,16 @@ typedef struct QCowHeader { uint32_t refcount_order; uint32_t header_length; + + /* Additional fields */ + uint8_t compression_type; + + /* header must be a multiple of 8 */ + uint8_t padding[7]; } QEMU_PACKED QCowHeader; +QEMU_BUILD_BUG_ON(!QEMU_IS_ALIGNED(sizeof(QCowHeader), 8)); + typedef struct QEMU_PACKED QCowSnapshotHeader { /* header is 8 byte aligned */ uint64_t l1_table_offset; @@ -216,13 +224,16 @@ enum { QCOW2_INCOMPAT_DIRTY_BITNR = 0, QCOW2_INCOMPAT_CORRUPT_BITNR = 1, QCOW2_INCOMPAT_DATA_FILE_BITNR = 2, + QCOW2_INCOMPAT_COMPRESSION_BITNR = 3, QCOW2_INCOMPAT_DIRTY = 1 << QCOW2_INCOMPAT_DIRTY_BITNR, QCOW2_INCOMPAT_CORRUPT = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR, QCOW2_INCOMPAT_DATA_FILE = 1 << QCOW2_INCOMPAT_DATA_FILE_BITNR, + QCOW2_INCOMPAT_COMPRESSION = 1 << QCOW2_INCOMPAT_COMPRESSION_BITNR, QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY | QCOW2_INCOMPAT_CORRUPT - | QCOW2_INCOMPAT_DATA_FILE, + | QCOW2_INCOMPAT_DATA_FILE + | QCOW2_INCOMPAT_COMPRESSION, }; /* Compatible feature bits */ @@ -366,6 +377,13 @@ typedef struct BDRVQcow2State { bool metadata_preallocation_checked; bool metadata_preallocation; + /* + * Compression type used for the image. Default: 0 - ZLIB + * The image compression type is set on image creation. + * For now, the only way to change the compression type + * is to convert the image with the desired compression type set. + */ + Qcow2CompressionType compression_type; } BDRVQcow2State; typedef struct Qcow2COWRegion { diff --git a/include/block/block_int.h b/include/block/block_int.h index df6d0273d6..7ba8c89036 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -57,6 +57,7 @@ #define BLOCK_OPT_REFCOUNT_BITS "refcount_bits" #define BLOCK_OPT_DATA_FILE "data_file" #define BLOCK_OPT_DATA_FILE_RAW "data_file_raw" +#define BLOCK_OPT_COMPRESSION_TYPE "compression_type" #define BLOCK_PROBE_BUF_SIZE 512 diff --git a/qapi/block-core.json b/qapi/block-core.json index 943df1926a..1522e2983f 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -78,6 +78,8 @@ # # @bitmaps: A list of qcow2 bitmap details (since 4.0) # +# @compression-type: the image cluster compression method (since 5.1) +# # Since: 1.7 ## { 'struct': 'ImageInfoSpecificQCow2', @@ -89,7 +91,8 @@ '*corrupt': 'bool', 'refcount-bits': 'int', '*encrypt': 'ImageInfoSpecificQCow2Encryption', - '*bitmaps': ['Qcow2BitmapInfo'] + '*bitmaps': ['Qcow2BitmapInfo'], + 'compression-type': 'Qcow2CompressionType' } } ## @@ -4284,6 +4287,18 @@ 'data': [ 'v2', 'v3' ] } +## +# @Qcow2CompressionType: +# +# Compression type used in qcow2 image file +# +# @zlib: zlib compression, see +# +# Since: 5.1 +## +{ 'enum': 'Qcow2CompressionType', + 'data': [ 'zlib' ] } + ## # @BlockdevCreateOptionsQcow2: # @@ -4307,6 +4322,8 @@ # allowed values: off, falloc, full, metadata) # @lazy-refcounts: True if refcounts may be updated lazily (default: off) # @refcount-bits: Width of reference counts in bits (default: 16) +# @compression-type: The image cluster compression method +# (default: zlib, since 5.1) # # Since: 2.12 ## @@ -4322,7 +4339,8 @@ '*cluster-size': 'size', '*preallocation': 'PreallocMode', '*lazy-refcounts': 'bool', - '*refcount-bits': 'int' } } + '*refcount-bits': 'int', + '*compression-type':'Qcow2CompressionType' } } ## # @BlockdevCreateOptionsQed: diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out index 46f97c5a4e..5a4beda6a2 100644 --- a/tests/qemu-iotests/031.out +++ b/tests/qemu-iotests/031.out @@ -113,11 +113,11 @@ incompatible_features [] compatible_features [] autoclear_features [] refcount_order 4 -header_length 104 +header_length 112 Header extension: magic 0x6803f857 -length 288 +length 336 data Header extension: @@ -146,11 +146,11 @@ incompatible_features [] compatible_features [] autoclear_features [] refcount_order 4 -header_length 104 +header_length 112 Header extension: magic 0x6803f857 -length 288 +length 336 data Header extension: @@ -164,7 +164,7 @@ No errors were found on the image. magic 0x514649fb version 3 -backing_file_offset 0x1d8 +backing_file_offset 0x210 backing_file_size 0x17 cluster_bits 16 size 67108864 @@ -179,7 +179,7 @@ incompatible_features [] compatible_features [] autoclear_features [] refcount_order 4 -header_length 104 +header_length 112 Header extension: magic 0xe2792aca @@ -188,7 +188,7 @@ data 'host_device' Header extension: magic 0x6803f857 -length 288 +length 336 data Header extension: diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out index 23b699ce06..e409acf60e 100644 --- a/tests/qemu-iotests/036.out +++ b/tests/qemu-iotests/036.out @@ -26,7 +26,7 @@ compatible_features [] autoclear_features [63] Header extension: magic 0x6803f857 -length 288 +length 336 data @@ -38,7 +38,7 @@ compatible_features [] autoclear_features [] Header extension: magic 0x6803f857 -length 288 +length 336 data *** done diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out index affa55b341..a5cfba1756 100644 --- a/tests/qemu-iotests/049.out +++ b/tests/qemu-iotests/049.out @@ -4,90 +4,90 @@ QA output created by 049 == 1. Traditional size parameter == qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib == 2. Specifying size via -o == qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib == 3. Invalid sizes == @@ -129,84 +129,84 @@ qemu-img: TEST_DIR/t.qcow2: The image size must be specified only once == Check correct interpretation of suffixes for cluster size == qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1048576 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1048576 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=524288 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=524288 lazy_refcounts=off refcount_bits=16 compression_type=zlib == Check compat level option == qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M qemu-img: TEST_DIR/t.qcow2: Invalid parameter '0.42' -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M qemu-img: TEST_DIR/t.qcow2: Invalid parameter 'foobar' -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib == Check preallocation option == qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=off lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=off lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M qemu-img: TEST_DIR/t.qcow2: Invalid parameter '1234' -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16 compression_type=zlib == Check encryption option == qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on encrypt.key-secret=sec0 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on encrypt.key-secret=sec0 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib == Check lazy_refcounts option (only with v3) == qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=on refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=on refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater) -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=on refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=on refcount_bits=16 compression_type=zlib *** done diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index 09caaea865..be5f8707a3 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -17,6 +17,7 @@ virtual size: 64 MiB (67108864 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 corrupt: true diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index 5a8d36d005..a51ad1b5ba 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -22,11 +22,11 @@ incompatible_features [] compatible_features [0] autoclear_features [] refcount_order 4 -header_length 104 +header_length 112 Header extension: magic 0x6803f857 -length 288 +length 336 data magic 0x514649fb @@ -80,11 +80,11 @@ incompatible_features [] compatible_features [0] autoclear_features [] refcount_order 4 -header_length 104 +header_length 112 Header extension: magic 0x6803f857 -length 288 +length 336 data magic 0x514649fb @@ -136,11 +136,11 @@ incompatible_features [0] compatible_features [0] autoclear_features [] refcount_order 4 -header_length 104 +header_length 112 Header extension: magic 0x6803f857 -length 288 +length 336 data ERROR cluster 5 refcount=0 reference=1 @@ -191,11 +191,11 @@ incompatible_features [] compatible_features [42] autoclear_features [42] refcount_order 4 -header_length 104 +header_length 112 Header extension: magic 0x6803f857 -length 288 +length 336 data magic 0x514649fb @@ -260,11 +260,11 @@ incompatible_features [] compatible_features [0] autoclear_features [] refcount_order 4 -header_length 104 +header_length 112 Header extension: magic 0x6803f857 -length 288 +length 336 data read 65536/65536 bytes at offset 44040192 @@ -322,11 +322,11 @@ incompatible_features [0] compatible_features [0] autoclear_features [] refcount_order 4 -header_length 104 +header_length 112 Header extension: magic 0x6803f857 -length 288 +length 336 data ERROR cluster 5 refcount=0 reference=1 @@ -351,11 +351,11 @@ incompatible_features [] compatible_features [] autoclear_features [] refcount_order 4 -header_length 104 +header_length 112 Header extension: magic 0x6803f857 -length 288 +length 336 data read 131072/131072 bytes at offset 0 @@ -519,6 +519,7 @@ virtual size: 64 MiB (67108864 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 data file: TEST_DIR/t.IMGFMT.data @@ -539,6 +540,7 @@ virtual size: 64 MiB (67108864 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 data file: foo @@ -552,6 +554,7 @@ virtual size: 64 MiB (67108864 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 data file raw: false @@ -566,6 +569,7 @@ virtual size: 64 MiB (67108864 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 data file: TEST_DIR/t.IMGFMT.data @@ -578,6 +582,7 @@ virtual size: 64 MiB (67108864 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 data file: TEST_DIR/t.IMGFMT.data @@ -591,6 +596,7 @@ virtual size: 64 MiB (67108864 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 data file: TEST_DIR/t.IMGFMT.data diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065 index 6426474271..18dc488c7a 100755 --- a/tests/qemu-iotests/065 +++ b/tests/qemu-iotests/065 @@ -88,24 +88,30 @@ class TestQMP(TestImageInfoSpecific): class TestQCow2(TestQemuImgInfo): '''Testing a qcow2 version 2 image''' img_options = 'compat=0.10' - json_compare = { 'compat': '0.10', 'refcount-bits': 16 } - human_compare = [ 'compat: 0.10', 'refcount bits: 16' ] + json_compare = { 'compat': '0.10', 'refcount-bits': 16, + 'compression-type': 'zlib' } + human_compare = [ 'compat: 0.10', 'compression type: zlib', + 'refcount bits: 16' ] class TestQCow3NotLazy(TestQemuImgInfo): '''Testing a qcow2 version 3 image with lazy refcounts disabled''' img_options = 'compat=1.1,lazy_refcounts=off' json_compare = { 'compat': '1.1', 'lazy-refcounts': False, - 'refcount-bits': 16, 'corrupt': False } - human_compare = [ 'compat: 1.1', 'lazy refcounts: false', - 'refcount bits: 16', 'corrupt: false' ] + 'refcount-bits': 16, 'corrupt': False, + 'compression-type': 'zlib' } + human_compare = [ 'compat: 1.1', 'compression type: zlib', + 'lazy refcounts: false', 'refcount bits: 16', + 'corrupt: false' ] class TestQCow3Lazy(TestQemuImgInfo): '''Testing a qcow2 version 3 image with lazy refcounts enabled''' img_options = 'compat=1.1,lazy_refcounts=on' json_compare = { 'compat': '1.1', 'lazy-refcounts': True, - 'refcount-bits': 16, 'corrupt': False } - human_compare = [ 'compat: 1.1', 'lazy refcounts: true', - 'refcount bits: 16', 'corrupt: false' ] + 'refcount-bits': 16, 'corrupt': False, + 'compression-type': 'zlib' } + human_compare = [ 'compat: 1.1', 'compression type: zlib', + 'lazy refcounts: true', 'refcount bits: 16', + 'corrupt: false' ] class TestQCow3NotLazyQMP(TestQMP): '''Testing a qcow2 version 3 image with lazy refcounts disabled, opening @@ -113,7 +119,8 @@ class TestQCow3NotLazyQMP(TestQMP): img_options = 'compat=1.1,lazy_refcounts=off' qemu_options = 'lazy-refcounts=on' compare = { 'compat': '1.1', 'lazy-refcounts': False, - 'refcount-bits': 16, 'corrupt': False } + 'refcount-bits': 16, 'corrupt': False, + 'compression-type': 'zlib' } class TestQCow3LazyQMP(TestQMP): @@ -122,7 +129,8 @@ class TestQCow3LazyQMP(TestQMP): img_options = 'compat=1.1,lazy_refcounts=on' qemu_options = 'lazy-refcounts=off' compare = { 'compat': '1.1', 'lazy-refcounts': True, - 'refcount-bits': 16, 'corrupt': False } + 'refcount-bits': 16, 'corrupt': False, + 'compression-type': 'zlib' } TestImageInfoSpecific = None TestQemuImgInfo = None diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080 index a3d13c414e..7588c63b6c 100755 --- a/tests/qemu-iotests/080 +++ b/tests/qemu-iotests/080 @@ -45,7 +45,7 @@ _supported_os Linux # - This is generally a test for compat=1.1 images _unsupported_imgopts 'refcount_bits=1[^0-9]' data_file 'compat=0.10' -header_size=104 +header_size=112 offset_backing_file_offset=8 offset_backing_file_size=16 diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index 9d4ed4dc9d..529a1214e1 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -3,38 +3,40 @@ QA output created by 082 === create: Options specified more than once === Testing: create -f foo -f qcow2 TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 128 MiB (134217728 bytes) cluster_size: 65536 Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=4096 lazy_refcounts=on refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=4096 lazy_refcounts=on refcount_bits=16 compression_type=zlib image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 128 MiB (134217728 bytes) cluster_size: 4096 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: true refcount bits: 16 corrupt: false Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=on refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=on refcount_bits=16 compression_type=zlib image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 128 MiB (134217728 bytes) cluster_size: 8192 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: true refcount bits: 16 corrupt: false Testing: create -f qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=off refcount_bits=16 compression_type=zlib image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 128 MiB (134217728 bytes) @@ -48,6 +50,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -71,6 +74,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -94,6 +98,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -117,6 +122,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -140,6 +146,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -163,6 +170,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -186,6 +194,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -209,6 +218,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -227,10 +237,10 @@ Supported options: size= - Virtual disk size Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 128M qemu-img: Invalid option list: backing_file=TEST_DIR/t.qcow2, @@ -247,6 +257,7 @@ Supported qcow2 options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -279,7 +290,7 @@ qemu-img: Format driver 'bochs' does not support image creation === convert: Options specified more than once === Testing: create -f qcow2 TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib Testing: convert -f foo -f qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base image: TEST_DIR/t.IMGFMT.base @@ -299,6 +310,7 @@ virtual size: 128 MiB (134217728 bytes) cluster_size: 4096 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: true refcount bits: 16 corrupt: false @@ -310,6 +322,7 @@ virtual size: 128 MiB (134217728 bytes) cluster_size: 8192 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: true refcount bits: 16 corrupt: false @@ -328,6 +341,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -351,6 +365,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -374,6 +389,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -397,6 +413,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -420,6 +437,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -443,6 +461,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -466,6 +485,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -489,6 +509,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -527,6 +548,7 @@ Supported qcow2 options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -579,6 +601,7 @@ virtual size: 128 MiB (134217728 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: true refcount bits: 16 corrupt: false @@ -590,6 +613,7 @@ virtual size: 130 MiB (136314880 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 corrupt: false @@ -601,6 +625,7 @@ virtual size: 132 MiB (138412032 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: true refcount bits: 16 corrupt: false @@ -619,6 +644,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -643,6 +669,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -667,6 +694,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -691,6 +719,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -715,6 +744,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -739,6 +769,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -763,6 +794,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -787,6 +819,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm @@ -828,6 +861,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) + compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out index fd11aae678..a822ff4ef6 100644 --- a/tests/qemu-iotests/085.out +++ b/tests/qemu-iotests/085.out @@ -13,7 +13,7 @@ Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=134217728 === Create a single snapshot on virtio0 === { 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/1-snapshot-v0.IMGFMT', 'format': 'IMGFMT' } } -Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} === Invalid command - missing device and nodename === @@ -30,40 +30,40 @@ Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file === Create several transactional group snapshots === { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/2-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/2-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/3-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/3-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/4-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/4-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/5-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/5-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/6-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/6-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/7-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/7-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/8-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/8-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/9-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/9-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/10-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/10-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} === Create a couple of snapshots using blockdev-snapshot === diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out index c7aa2e4820..885a8874a5 100644 --- a/tests/qemu-iotests/144.out +++ b/tests/qemu-iotests/144.out @@ -9,7 +9,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=536870912 { 'execute': 'qmp_capabilities' } {"return": {}} { 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/tmp.IMGFMT', 'format': 'IMGFMT' } } -Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} === Performing block-commit on active layer === @@ -31,6 +31,6 @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/ === Performing Live Snapshot 2 === { 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/tmp2.IMGFMT', 'format': 'IMGFMT' } } -Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} *** done diff --git a/tests/qemu-iotests/182.out b/tests/qemu-iotests/182.out index a8eea166c3..ae43654d32 100644 --- a/tests/qemu-iotests/182.out +++ b/tests/qemu-iotests/182.out @@ -13,7 +13,7 @@ Is another process using the image [TEST_DIR/t.qcow2]? {'execute': 'blockdev-add', 'arguments': { 'node-name': 'node0', 'driver': 'file', 'filename': 'TEST_DIR/t.IMGFMT', 'locking': 'on' } } {"return": {}} {'execute': 'blockdev-snapshot-sync', 'arguments': { 'node-name': 'node0', 'snapshot-file': 'TEST_DIR/t.IMGFMT.overlay', 'snapshot-node-name': 'node1' } } -Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 size=197120 backing_file=TEST_DIR/t.qcow2 backing_fmt=file cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 size=197120 backing_file=TEST_DIR/t.qcow2 backing_fmt=file cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} {'execute': 'blockdev-add', 'arguments': { 'node-name': 'node1', 'driver': 'file', 'filename': 'TEST_DIR/t.IMGFMT', 'locking': 'on' } } {"return": {}} diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out index 9a3b65782b..ac5ab16bc8 100644 --- a/tests/qemu-iotests/185.out +++ b/tests/qemu-iotests/185.out @@ -9,14 +9,14 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 === Creating backing chain === { 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'disk', 'snapshot-file': 'TEST_DIR/t.IMGFMT.mid', 'format': 'IMGFMT', 'mode': 'absolute-paths' } } -Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} { 'execute': 'human-monitor-command', 'arguments': { 'command-line': 'qemu-io disk "write 0 4M"' } } wrote 4194304/4194304 bytes at offset 0 4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) {"return": ""} { 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'disk', 'snapshot-file': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'absolute-paths' } } -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"return": {}} === Start commit job and exit qemu === @@ -48,7 +48,7 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q { 'execute': 'qmp_capabilities' } {"return": {}} { 'execute': 'drive-mirror', 'arguments': { 'device': 'disk', 'target': 'TEST_DIR/t.IMGFMT.copy', 'format': 'IMGFMT', 'sync': 'full', 'speed': 65536 } } -Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} {"return": {}} @@ -62,7 +62,7 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l { 'execute': 'qmp_capabilities' } {"return": {}} { 'execute': 'drive-backup', 'arguments': { 'device': 'disk', 'target': 'TEST_DIR/t.IMGFMT.copy', 'format': 'IMGFMT', 'sync': 'full', 'speed': 65536 } } -Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} diff --git a/tests/qemu-iotests/198.out b/tests/qemu-iotests/198.out index 831ce3a289..6280ae6eed 100644 --- a/tests/qemu-iotests/198.out +++ b/tests/qemu-iotests/198.out @@ -36,6 +36,7 @@ image: json:{ /* filtered */ } file format: IMGFMT virtual size: 16 MiB (16777216 bytes) Format specific information: + compression type: zlib encrypt: ivgen alg: plain64 hash alg: sha256 @@ -79,6 +80,7 @@ file format: IMGFMT virtual size: 16 MiB (16777216 bytes) backing file: TEST_DIR/t.IMGFMT.base Format specific information: + compression type: zlib encrypt: ivgen alg: plain64 hash alg: sha256 diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out index 61e7241e0b..1a14255a83 100644 --- a/tests/qemu-iotests/206.out +++ b/tests/qemu-iotests/206.out @@ -18,6 +18,7 @@ virtual size: 128 MiB (134217728 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 corrupt: false @@ -40,6 +41,7 @@ virtual size: 64 MiB (67108864 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 corrupt: false @@ -62,6 +64,7 @@ virtual size: 32 MiB (33554432 bytes) cluster_size: 2097152 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: true refcount bits: 1 corrupt: false @@ -86,6 +89,7 @@ backing file: TEST_IMG.base backing file format: IMGFMT Format specific information: compat: 0.10 + compression type: zlib refcount bits: 16 === Successful image creation (encrypted) === @@ -102,6 +106,7 @@ encrypted: yes cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 encrypt: diff --git a/tests/qemu-iotests/242.out b/tests/qemu-iotests/242.out index 7ac8404d11..091b9126ce 100644 --- a/tests/qemu-iotests/242.out +++ b/tests/qemu-iotests/242.out @@ -12,6 +12,7 @@ virtual size: 1 MiB (1048576 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 corrupt: false @@ -32,6 +33,7 @@ virtual size: 1 MiB (1048576 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false bitmaps: [0]: @@ -64,6 +66,7 @@ virtual size: 1 MiB (1048576 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false bitmaps: [0]: @@ -104,6 +107,7 @@ virtual size: 1 MiB (1048576 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false bitmaps: [0]: @@ -153,6 +157,7 @@ virtual size: 1 MiB (1048576 bytes) cluster_size: 65536 Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false bitmaps: [0]: diff --git a/tests/qemu-iotests/255.out b/tests/qemu-iotests/255.out index 348909fdef..a3c99fd62e 100644 --- a/tests/qemu-iotests/255.out +++ b/tests/qemu-iotests/255.out @@ -3,9 +3,9 @@ Finishing a commit job with background reads === Create backing chain and start VM === -Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib === Start background read requests === @@ -23,9 +23,9 @@ Closing the VM while a job is being cancelled === Create images and start VM === -Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out index 9d6fdeb1f7..d24ff681af 100644 --- a/tests/qemu-iotests/274.out +++ b/tests/qemu-iotests/274.out @@ -1,9 +1,9 @@ == Commit tests == -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib wrote 2097152/2097152 bytes at offset 0 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -52,6 +52,7 @@ cluster_size: 65536 backing file: TEST_DIR/PID-base Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 corrupt: false @@ -63,11 +64,11 @@ read 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Testing HMP commit (top -> mid) === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib wrote 2097152/2097152 bytes at offset 0 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -81,6 +82,7 @@ cluster_size: 65536 backing file: TEST_DIR/PID-base Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 corrupt: false @@ -92,11 +94,11 @@ read 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Testing QMP active commit (top -> mid) === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib wrote 2097152/2097152 bytes at offset 0 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -116,6 +118,7 @@ cluster_size: 65536 backing file: TEST_DIR/PID-base Format specific information: compat: 1.1 + compression type: zlib lazy refcounts: false refcount bits: 16 corrupt: false @@ -128,9 +131,9 @@ read 1048576/1048576 bytes at offset 1048576 == Resize tests == === preallocation=off === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib wrote 65536/65536 bytes at offset 5368709120 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -147,9 +150,9 @@ read 65536/65536 bytes at offset 5368709120 { "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}] === preallocation=metadata === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib wrote 65536/65536 bytes at offset 33285996544 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -171,9 +174,9 @@ read 65536/65536 bytes at offset 33285996544 { "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}] === preallocation=falloc === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib wrote 65536/65536 bytes at offset 9437184 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -190,9 +193,9 @@ read 65536/65536 bytes at offset 9437184 { "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}] === preallocation=full === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib wrote 65536/65536 bytes at offset 11534336 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -209,9 +212,9 @@ read 65536/65536 bytes at offset 11534336 { "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}] === preallocation=off === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib wrote 65536/65536 bytes at offset 259072 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -229,9 +232,9 @@ read 65536/65536 bytes at offset 259072 { "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}] === preallocation=off === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib wrote 65536/65536 bytes at offset 344064 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -248,9 +251,9 @@ read 65536/65536 bytes at offset 344064 { "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}] === preallocation=off === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib wrote 65536/65536 bytes at offset 446464 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/280.out b/tests/qemu-iotests/280.out index 5d382faaa8..92e4d14079 100644 --- a/tests/qemu-iotests/280.out +++ b/tests/qemu-iotests/280.out @@ -1,4 +1,4 @@ -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib === Launch VM === Enabling migration QMP events on VM... diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 3f8ee3e5f7..279e0bbb0d 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -152,7 +152,8 @@ _filter_img_create() -e "s# refcount_bits=[0-9]\\+##g" \ -e "s# key-secret=[a-zA-Z0-9]\\+##g" \ -e "s# iter-time=[0-9]\\+##g" \ - -e "s# force_size=\\(on\\|off\\)##g" + -e "s# force_size=\\(on\\|off\\)##g" \ + -e "s# compression_type=[a-zA-Z0-9]\\+##g" } _filter_img_info() From 25dd077d1d0aaef23f8608468cbef9a396583b1b Mon Sep 17 00:00:00 2001 From: Denis Plotnikov Date: Thu, 7 May 2020 11:25:19 +0300 Subject: [PATCH 0396/2595] qcow2: rework the cluster compression routine The patch enables processing the image compression type defined for the image and chooses an appropriate method for image clusters (de)compression. Signed-off-by: Denis Plotnikov Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Message-Id: <20200507082521.29210-3-dplotnikov@virtuozzo.com> Signed-off-by: Max Reitz --- block/qcow2-threads.c | 71 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c index a68126f291..7dbaf53489 100644 --- a/block/qcow2-threads.c +++ b/block/qcow2-threads.c @@ -74,7 +74,9 @@ typedef struct Qcow2CompressData { } Qcow2CompressData; /* - * qcow2_compress() + * qcow2_zlib_compress() + * + * Compress @src_size bytes of data using zlib compression method * * @dest - destination buffer, @dest_size bytes * @src - source buffer, @src_size bytes @@ -83,8 +85,8 @@ typedef struct Qcow2CompressData { * -ENOMEM destination buffer is not enough to store compressed data * -EIO on any other error */ -static ssize_t qcow2_compress(void *dest, size_t dest_size, - const void *src, size_t src_size) +static ssize_t qcow2_zlib_compress(void *dest, size_t dest_size, + const void *src, size_t src_size) { ssize_t ret; z_stream strm; @@ -119,10 +121,10 @@ static ssize_t qcow2_compress(void *dest, size_t dest_size, } /* - * qcow2_decompress() + * qcow2_zlib_decompress() * * Decompress some data (not more than @src_size bytes) to produce exactly - * @dest_size bytes. + * @dest_size bytes using zlib compression method * * @dest - destination buffer, @dest_size bytes * @src - source buffer, @src_size bytes @@ -130,8 +132,8 @@ static ssize_t qcow2_compress(void *dest, size_t dest_size, * Returns: 0 on success * -EIO on fail */ -static ssize_t qcow2_decompress(void *dest, size_t dest_size, - const void *src, size_t src_size) +static ssize_t qcow2_zlib_decompress(void *dest, size_t dest_size, + const void *src, size_t src_size) { int ret; z_stream strm; @@ -191,20 +193,67 @@ qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size, return arg.ret; } +/* + * qcow2_co_compress() + * + * Compress @src_size bytes of data using the compression + * method defined by the image compression type + * + * @dest - destination buffer, @dest_size bytes + * @src - source buffer, @src_size bytes + * + * Returns: compressed size on success + * a negative error code on failure + */ ssize_t coroutine_fn qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size, const void *src, size_t src_size) { - return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, - qcow2_compress); + BDRVQcow2State *s = bs->opaque; + Qcow2CompressFunc fn; + + switch (s->compression_type) { + case QCOW2_COMPRESSION_TYPE_ZLIB: + fn = qcow2_zlib_compress; + break; + + default: + abort(); + } + + return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, fn); } +/* + * qcow2_co_decompress() + * + * Decompress some data (not more than @src_size bytes) to produce exactly + * @dest_size bytes using the compression method defined by the image + * compression type + * + * @dest - destination buffer, @dest_size bytes + * @src - source buffer, @src_size bytes + * + * Returns: 0 on success + * a negative error code on failure + */ ssize_t coroutine_fn qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size, const void *src, size_t src_size) { - return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, - qcow2_decompress); + BDRVQcow2State *s = bs->opaque; + Qcow2CompressFunc fn; + + switch (s->compression_type) { + case QCOW2_COMPRESSION_TYPE_ZLIB: + fn = qcow2_zlib_decompress; + break; + + default: + abort(); + } + + return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, fn); } From d298ac10add95e2b7f8850332f3b755c8a23d925 Mon Sep 17 00:00:00 2001 From: Denis Plotnikov Date: Thu, 7 May 2020 11:25:20 +0300 Subject: [PATCH 0397/2595] qcow2: add zstd cluster compression zstd significantly reduces cluster compression time. It provides better compression performance maintaining the same level of the compression ratio in comparison with zlib, which, at the moment, is the only compression method available. The performance test results: Test compresses and decompresses qemu qcow2 image with just installed rhel-7.6 guest. Image cluster size: 64K. Image on disk size: 2.2G The test was conducted with brd disk to reduce the influence of disk subsystem to the test results. The results is given in seconds. compress cmd: time ./qemu-img convert -O qcow2 -c -o compression_type=[zlib|zstd] src.img [zlib|zstd]_compressed.img decompress cmd time ./qemu-img convert -O qcow2 [zlib|zstd]_compressed.img uncompressed.img compression decompression zlib zstd zlib zstd ------------------------------------------------------------ real 65.5 16.3 (-75 %) 1.9 1.6 (-16 %) user 65.0 15.8 5.3 2.5 sys 3.3 0.2 2.0 2.0 Both ZLIB and ZSTD gave the same compression ratio: 1.57 compressed image size in both cases: 1.4G Signed-off-by: Denis Plotnikov QAPI part: Acked-by: Markus Armbruster Message-Id: <20200507082521.29210-4-dplotnikov@virtuozzo.com> Signed-off-by: Max Reitz --- block/qcow2-threads.c | 169 +++++++++++++++++++++++++++++++++++++++++ block/qcow2.c | 7 ++ configure | 2 +- docs/interop/qcow2.txt | 1 + qapi/block-core.json | 3 +- 5 files changed, 180 insertions(+), 2 deletions(-) diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c index 7dbaf53489..1914baf456 100644 --- a/block/qcow2-threads.c +++ b/block/qcow2-threads.c @@ -28,6 +28,11 @@ #define ZLIB_CONST #include +#ifdef CONFIG_ZSTD +#include +#include +#endif + #include "qcow2.h" #include "block/thread-pool.h" #include "crypto.h" @@ -166,6 +171,160 @@ static ssize_t qcow2_zlib_decompress(void *dest, size_t dest_size, return ret; } +#ifdef CONFIG_ZSTD + +/* + * qcow2_zstd_compress() + * + * Compress @src_size bytes of data using zstd compression method + * + * @dest - destination buffer, @dest_size bytes + * @src - source buffer, @src_size bytes + * + * Returns: compressed size on success + * -ENOMEM destination buffer is not enough to store compressed data + * -EIO on any other error + */ +static ssize_t qcow2_zstd_compress(void *dest, size_t dest_size, + const void *src, size_t src_size) +{ + ssize_t ret; + size_t zstd_ret; + ZSTD_outBuffer output = { + .dst = dest, + .size = dest_size, + .pos = 0 + }; + ZSTD_inBuffer input = { + .src = src, + .size = src_size, + .pos = 0 + }; + ZSTD_CCtx *cctx = ZSTD_createCCtx(); + + if (!cctx) { + return -EIO; + } + /* + * Use the zstd streamed interface for symmetry with decompression, + * where streaming is essential since we don't record the exact + * compressed size. + * + * ZSTD_compressStream2() tries to compress everything it could + * with a single call. Although, ZSTD docs says that: + * "You must continue calling ZSTD_compressStream2() with ZSTD_e_end + * until it returns 0, at which point you are free to start a new frame", + * in out tests we saw the only case when it returned with >0 - + * when the output buffer was too small. In that case, + * ZSTD_compressStream2() expects a bigger buffer on the next call. + * We can't provide a bigger buffer because we are limited with dest_size + * which we pass to the ZSTD_compressStream2() at once. + * So, we don't need any loops and just abort the compression when we + * don't get 0 result on the first call. + */ + zstd_ret = ZSTD_compressStream2(cctx, &output, &input, ZSTD_e_end); + + if (zstd_ret) { + if (zstd_ret > output.size - output.pos) { + ret = -ENOMEM; + } else { + ret = -EIO; + } + goto out; + } + + /* make sure that zstd didn't overflow the dest buffer */ + assert(output.pos <= dest_size); + ret = output.pos; +out: + ZSTD_freeCCtx(cctx); + return ret; +} + +/* + * qcow2_zstd_decompress() + * + * Decompress some data (not more than @src_size bytes) to produce exactly + * @dest_size bytes using zstd compression method + * + * @dest - destination buffer, @dest_size bytes + * @src - source buffer, @src_size bytes + * + * Returns: 0 on success + * -EIO on any error + */ +static ssize_t qcow2_zstd_decompress(void *dest, size_t dest_size, + const void *src, size_t src_size) +{ + size_t zstd_ret = 0; + ssize_t ret = 0; + ZSTD_outBuffer output = { + .dst = dest, + .size = dest_size, + .pos = 0 + }; + ZSTD_inBuffer input = { + .src = src, + .size = src_size, + .pos = 0 + }; + ZSTD_DCtx *dctx = ZSTD_createDCtx(); + + if (!dctx) { + return -EIO; + } + + /* + * The compressed stream from the input buffer may consist of more + * than one zstd frame. So we iterate until we get a fully + * uncompressed cluster. + * From zstd docs related to ZSTD_decompressStream: + * "return : 0 when a frame is completely decoded and fully flushed" + * We suppose that this means: each time ZSTD_decompressStream reads + * only ONE full frame and returns 0 if and only if that frame + * is completely decoded and flushed. Only after returning 0, + * ZSTD_decompressStream reads another ONE full frame. + */ + while (output.pos < output.size) { + size_t last_in_pos = input.pos; + size_t last_out_pos = output.pos; + zstd_ret = ZSTD_decompressStream(dctx, &output, &input); + + if (ZSTD_isError(zstd_ret)) { + ret = -EIO; + break; + } + + /* + * The ZSTD manual is vague about what to do if it reads + * the buffer partially, and we don't want to get stuck + * in an infinite loop where ZSTD_decompressStream + * returns > 0 waiting for another input chunk. So, we add + * a check which ensures that the loop makes some progress + * on each step. + */ + if (last_in_pos >= input.pos && + last_out_pos >= output.pos) { + ret = -EIO; + break; + } + } + /* + * Make sure that we have the frame fully flushed here + * if not, we somehow managed to get uncompressed cluster + * greater then the cluster size, possibly because of its + * damage. + */ + if (zstd_ret > 0) { + ret = -EIO; + } + + ZSTD_freeDCtx(dctx); + assert(ret == 0 || ret == -EIO); + return ret; +} +#endif + static int qcow2_compress_pool_func(void *opaque) { Qcow2CompressData *data = opaque; @@ -217,6 +376,11 @@ qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size, fn = qcow2_zlib_compress; break; +#ifdef CONFIG_ZSTD + case QCOW2_COMPRESSION_TYPE_ZSTD: + fn = qcow2_zstd_compress; + break; +#endif default: abort(); } @@ -249,6 +413,11 @@ qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size, fn = qcow2_zlib_decompress; break; +#ifdef CONFIG_ZSTD + case QCOW2_COMPRESSION_TYPE_ZSTD: + fn = qcow2_zstd_decompress; + break; +#endif default: abort(); } diff --git a/block/qcow2.c b/block/qcow2.c index b878a6a474..ad9ab4fafa 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1246,6 +1246,9 @@ static int validate_compression_type(BDRVQcow2State *s, Error **errp) { switch (s->compression_type) { case QCOW2_COMPRESSION_TYPE_ZLIB: +#ifdef CONFIG_ZSTD + case QCOW2_COMPRESSION_TYPE_ZSTD: +#endif break; default: @@ -3479,6 +3482,10 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } switch (qcow2_opts->compression_type) { +#ifdef CONFIG_ZSTD + case QCOW2_COMPRESSION_TYPE_ZSTD: + break; +#endif default: error_setg(errp, "Unknown compression type"); goto out; diff --git a/configure b/configure index 0d69c360c0..c50c006b86 100755 --- a/configure +++ b/configure @@ -1861,7 +1861,7 @@ disabled with --disable-FEATURE, default is enabled if available: lzfse support of lzfse compression library (for reading lzfse-compressed dmg images) zstd support for zstd compression library - (for migration compression) + (for migration compression and qcow2 cluster compression) seccomp seccomp support coroutine-pool coroutine freelist (better performance) glusterfs GlusterFS backend diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index 298a031310..cb723463f2 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -212,6 +212,7 @@ version 2. Available compression type values: 0: zlib + 1: zstd === Header padding === diff --git a/qapi/block-core.json b/qapi/block-core.json index 1522e2983f..6fbacddab2 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4293,11 +4293,12 @@ # Compression type used in qcow2 image file # # @zlib: zlib compression, see +# @zstd: zstd compression, see # # Since: 5.1 ## { 'enum': 'Qcow2CompressionType', - 'data': [ 'zlib' ] } + 'data': [ 'zlib', { 'name': 'zstd', 'if': 'defined(CONFIG_ZSTD)' } ] } ## # @BlockdevCreateOptionsQcow2: From dd488fc1c000700741355426198d240c6f25ccb7 Mon Sep 17 00:00:00 2001 From: Denis Plotnikov Date: Thu, 7 May 2020 11:25:21 +0300 Subject: [PATCH 0398/2595] iotests: 287: add qcow2 compression type test The test checks fulfilling qcow2 requirements for the compression type feature and zstd compression type operability. Signed-off-by: Denis Plotnikov Reviewed-by: Vladimir Sementsov-Ogievskiy Tested-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200507082521.29210-5-dplotnikov@virtuozzo.com> Signed-off-by: Max Reitz --- tests/qemu-iotests/287 | 152 +++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/287.out | 67 ++++++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 220 insertions(+) create mode 100755 tests/qemu-iotests/287 create mode 100644 tests/qemu-iotests/287.out diff --git a/tests/qemu-iotests/287 b/tests/qemu-iotests/287 new file mode 100755 index 0000000000..f98a4cadc1 --- /dev/null +++ b/tests/qemu-iotests/287 @@ -0,0 +1,152 @@ +#!/usr/bin/env bash +# +# Test case for an image using zstd compression +# +# Copyright (c) 2020 Virtuozzo International GmbH +# +# 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 . +# + +# creator +owner=dplotnikov@virtuozzo.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +status=1 # failure is the default! + +# standard environment +. ./common.rc +. ./common.filter + +# This tests qocw2-specific low-level functionality +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux +_unsupported_imgopts 'compat=0.10' data_file + +COMPR_IMG="$TEST_IMG.compressed" +RAND_FILE="$TEST_DIR/rand_data" + +_cleanup() +{ + _cleanup_test_img + _rm_test_img "$COMPR_IMG" + rm -f "$RAND_FILE" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# for all the cases +CLUSTER_SIZE=65536 + +# Check if we can run this test. +if IMGOPTS='compression_type=zstd' _make_test_img 64M | + grep "Invalid parameter 'zstd'"; then + _notrun "ZSTD is disabled" +fi + +echo +echo "=== Testing compression type incompatible bit setting for zlib ===" +echo +_make_test_img -o compression_type=zlib 64M +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features + +echo +echo "=== Testing compression type incompatible bit setting for zstd ===" +echo +_make_test_img -o compression_type=zstd 64M +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features + +echo +echo "=== Testing zlib with incompatible bit set ===" +echo +_make_test_img -o compression_type=zlib 64M +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 3 +# to make sure the bit was actually set +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features + +if $QEMU_IMG info "$TEST_IMG" >/dev/null 2>&1 ; then + echo "Error: The image opened successfully. The image must not be opened." +fi + +echo +echo "=== Testing zstd with incompatible bit unset ===" +echo +_make_test_img -o compression_type=zstd 64M +$PYTHON qcow2.py "$TEST_IMG" set-header incompatible_features 0 +# to make sure the bit was actually unset +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features + +if $QEMU_IMG info "$TEST_IMG" >/dev/null 2>&1 ; then + echo "Error: The image opened successfully. The image must not be opened." +fi + +echo +echo "=== Testing compression type values ===" +echo +# zlib=0 +_make_test_img -o compression_type=zlib 64M +peek_file_be "$TEST_IMG" 104 1 +echo + +# zstd=1 +_make_test_img -o compression_type=zstd 64M +peek_file_be "$TEST_IMG" 104 1 +echo + +echo +echo "=== Testing simple reading and writing with zstd ===" +echo +_make_test_img -o compression_type=zstd 64M +$QEMU_IO -c "write -c -P 0xAC 64K 64K " "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c "read -P 0xAC 64K 64K " "$TEST_IMG" | _filter_qemu_io +# read on the cluster boundaries +$QEMU_IO -c "read -v 131070 8 " "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c "read -v 65534 8" "$TEST_IMG" | _filter_qemu_io + +echo +echo "=== Testing adjacent clusters reading and writing with zstd ===" +echo +_make_test_img -o compression_type=zstd 64M +$QEMU_IO -c "write -c -P 0xAB 0 64K " "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c "write -c -P 0xAC 64K 64K " "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c "write -c -P 0xAD 128K 64K " "$TEST_IMG" | _filter_qemu_io + +$QEMU_IO -c "read -P 0xAB 0 64k " "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c "read -P 0xAC 64K 64k " "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c "read -P 0xAD 128K 64k " "$TEST_IMG" | _filter_qemu_io + +echo +echo "=== Testing incompressible cluster processing with zstd ===" +echo +# create a 2M image and fill it with 1M likely incompressible data +# and 1M compressible data +dd if=/dev/urandom of="$RAND_FILE" bs=1M count=1 seek=1 +QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS_NO_FMT" \ +$QEMU_IO -f raw -c "write -P 0xFA 0 1M" "$RAND_FILE" | _filter_qemu_io + +$QEMU_IMG convert -f raw -O $IMGFMT -c \ +-o "$(_optstr_add "$IMGOPTS" "compression_type=zlib")" "$RAND_FILE" \ +"$TEST_IMG" | _filter_qemu_io + +$QEMU_IMG convert -O $IMGFMT -c \ +-o "$(_optstr_add "$IMGOPTS" "compression_type=zstd")" "$TEST_IMG" \ +"$COMPR_IMG" | _filter_qemu_io + +$QEMU_IMG compare "$TEST_IMG" "$COMPR_IMG" + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/287.out b/tests/qemu-iotests/287.out new file mode 100644 index 0000000000..6b9dfb4af0 --- /dev/null +++ b/tests/qemu-iotests/287.out @@ -0,0 +1,67 @@ +QA output created by 287 + +=== Testing compression type incompatible bit setting for zlib === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +incompatible_features [] + +=== Testing compression type incompatible bit setting for zstd === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +incompatible_features [3] + +=== Testing zlib with incompatible bit set === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +incompatible_features [3] + +=== Testing zstd with incompatible bit unset === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +incompatible_features [] + +=== Testing compression type values === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + 0 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + 1 + +=== Testing simple reading and writing with zstd === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +0001fffe: ac ac 00 00 00 00 00 00 ........ +read 8/8 bytes at offset 131070 +8 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +0000fffe: 00 00 ac ac ac ac ac ac ........ +read 8/8 bytes at offset 65534 +8 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +=== Testing adjacent clusters reading and writing with zstd === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 131072 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 131072 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +=== Testing incompressible cluster processing with zstd === + +1+0 records in +1+0 records out +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Images are identical. +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index fe649c5b73..34175fd437 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -295,6 +295,7 @@ 283 auto quick 284 rw 286 rw quick +287 auto quick 288 quick 289 rw quick 290 rw auto quick From fc9aefc8c0d3c6392656ea661ce72c1583b70bbd Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 7 May 2020 21:38:00 +0300 Subject: [PATCH 0399/2595] block/block-copy: fix use-after-free of task pointer Obviously, we should g_free the task after trace point and offset update. Reported-by: Coverity (CID 1428756) Fixes: 4ce5dd3e9b5ee0fac18625860eb3727399ee965e Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200507183800.22626-1-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake Signed-off-by: Max Reitz --- block/block-copy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/block-copy.c b/block/block-copy.c index 03500680f7..4713c8f2a3 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -591,13 +591,13 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s, } if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) { block_copy_task_end(task, 0); - g_free(task); progress_set_remaining(s->progress, bdrv_get_dirty_count(s->copy_bitmap) + s->in_flight_bytes); trace_block_copy_skip_range(s, task->offset, task->bytes); offset = task_end(task); bytes = end - offset; + g_free(task); continue; } task->zeroes = ret & BDRV_BLOCK_ZERO; From 233982af53915bd9fbfa604e3b566b50af6fe5a7 Mon Sep 17 00:00:00 2001 From: Christian Schoenebeck Date: Thu, 14 May 2020 08:06:43 +0200 Subject: [PATCH 0400/2595] MAINTAINERS: Upgrade myself as 9pfs co-maintainer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As suggested by Greg, let's upgrade myself as co-maintainer of 9pfs. Signed-off-by: Christian Schoenebeck Reviewed-by: Philippe Mathieu-Daudé Message-Id: Signed-off-by: Greg Kurz --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1f84e3ae2c..005ee98a59 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1657,7 +1657,7 @@ F: include/sysemu/balloon.h virtio-9p M: Greg Kurz -R: Christian Schoenebeck +M: Christian Schoenebeck S: Odd Fixes F: hw/9pfs/ X: hw/9pfs/xen-9p* From 65abaa01ee5781f525e1b9a0d6e6e5a3d8696d5f Mon Sep 17 00:00:00 2001 From: Christian Schoenebeck Date: Thu, 14 May 2020 08:06:43 +0200 Subject: [PATCH 0401/2595] qemu-options.hx: 9p: clarify -virtfs vs. -fsdev The docs are ambiguous about the difference (or actually their equality) between options '-virtfs' vs. '-fsdev'. So clarify that '-virtfs' is actually just a convenience shortcut for its generalized form '-fsdev' in conjunction with '-device virtio-9p-pci'. And as we're at it, also be a bit more descriptive what 9pfs is actually used for. Signed-off-by: Christian Schoenebeck Acked-by: Cornelia Huck Message-Id: <208f1fceffce2feaf7c900b29e326b967dce7762.1585661532.git.qemu_oss@crudebyte.com> Signed-off-by: Greg Kurz --- qemu-options.hx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 292d4e7c0c..e2dca8a4e9 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1542,9 +1542,17 @@ SRST ``-virtfs proxy,sock_fd=sock_fd,mount_tag=mount_tag [,writeout=writeout][,readonly]`` \ ``-virtfs synth,mount_tag=mount_tag`` - Define a new filesystem device and expose it to the guest using a - virtio-9p-device. The general form of a Virtual File system - pass-through options are: + Define a new virtual filesystem device and expose it to the guest using + a virtio-9p-device (a.k.a. 9pfs), which essentially means that a certain + directory on host is made directly accessible by guest as a pass-through + file system by using the 9P network protocol for communication between + host and guests, if desired even accessible, shared by several guests + simultaniously. + + Note that ``-virtfs`` is actually just a convenience shortcut for its + generalized form ``-fsdev -device virtio-9p-pci``. + + The general form of pass-through file system options are: ``local`` Accesses to the filesystem are done by QEMU. From a5804fcf7b22fc7d1f9ec794dd284c7d504bd16b Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Thu, 14 May 2020 08:06:43 +0200 Subject: [PATCH 0402/2595] 9pfs: local: ignore O_NOATIME if we don't have permissions QEMU's local 9pfs server passes through O_NOATIME from the client. If the QEMU process doesn't have permissions to use O_NOATIME (namely, it does not own the file nor have the CAP_FOWNER capability), the open will fail. This causes issues when from the client's point of view, it believes it has permissions to use O_NOATIME (e.g., a process running as root in the virtual machine). Additionally, overlayfs on Linux opens files on the lower layer using O_NOATIME, so in this case a 9pfs mount can't be used as a lower layer for overlayfs (cf. https://github.com/osandov/drgn/blob/dabfe1971951701da13863dbe6d8a1d172ad9650/vmtest/onoatimehack.c and https://github.com/NixOS/nixpkgs/issues/54509). Luckily, O_NOATIME is effectively a hint, and is often ignored by, e.g., network filesystems. open(2) notes that O_NOATIME "may not be effective on all filesystems. One example is NFS, where the server maintains the access time." This means that we can honor it when possible but fall back to ignoring it. Acked-by: Christian Schoenebeck Signed-off-by: Omar Sandoval Message-Id: Signed-off-by: Greg Kurz --- hw/9pfs/9p-util.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index 79ed6b233e..546f46dc7d 100644 --- a/hw/9pfs/9p-util.h +++ b/hw/9pfs/9p-util.h @@ -37,9 +37,22 @@ static inline int openat_file(int dirfd, const char *name, int flags, { int fd, serrno, ret; +again: fd = openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK, mode); if (fd == -1) { + if (errno == EPERM && (flags & O_NOATIME)) { + /* + * The client passed O_NOATIME but we lack permissions to honor it. + * Rather than failing the open, fall back without O_NOATIME. This + * doesn't break the semantics on the client side, as the Linux + * open(2) man page notes that O_NOATIME "may not be effective on + * all filesystems". In particular, NFS and other network + * filesystems ignore it entirely. + */ + flags &= ~O_NOATIME; + goto again; + } return -1; } From 9bbb7e0fe081efff2e41f8517c256b72a284fe9b Mon Sep 17 00:00:00 2001 From: Christian Schoenebeck Date: Thu, 14 May 2020 08:06:43 +0200 Subject: [PATCH 0403/2595] xen-9pfs: Fix log messages of reply errors If delivery of some 9pfs response fails for some reason, log the error message by mentioning the 9P protocol reply type, not by client's request type. The latter could be misleading that the error occurred already when handling the request input. Signed-off-by: Christian Schoenebeck Acked-by: Stefano Stabellini Message-Id: Signed-off-by: Greg Kurz --- hw/9pfs/xen-9p-backend.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index 18fe5b7c92..f04caabfe5 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -137,7 +137,8 @@ static ssize_t xen_9pfs_pdu_vmarshal(V9fsPDU *pdu, ret = v9fs_iov_vmarshal(in_sg, num, offset, 0, fmt, ap); if (ret < 0) { xen_pv_printf(&xen_9pfs->xendev, 0, - "Failed to encode VirtFS request type %d\n", pdu->id + 1); + "Failed to encode VirtFS reply type %d\n", + pdu->id + 1); xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing); xen_9pfs_disconnect(&xen_9pfs->xendev); } @@ -201,9 +202,9 @@ static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu, buf_size = iov_size(ring->sg, num); if (buf_size < P9_IOHDRSZ) { - xen_pv_printf(&xen_9pfs->xendev, 0, "Xen 9pfs request type %d" - "needs %zu bytes, buffer has %zu, less than minimum\n", - pdu->id, *size, buf_size); + xen_pv_printf(&xen_9pfs->xendev, 0, "Xen 9pfs reply type %d needs " + "%zu bytes, buffer has %zu, less than minimum\n", + pdu->id + 1, *size, buf_size); xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing); xen_9pfs_disconnect(&xen_9pfs->xendev); } From 3e2a0cb99d26fd5fb34ab8c50f90d4292363245d Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 6 May 2020 10:25:05 +0200 Subject: [PATCH 0404/2595] hw/net/xilinx_axienet: Auto-clear PHY Autoneg Auto-clear PHY CR Autoneg bits. This makes this model work with recent Linux kernels. Reviewed-by: Francisco Iglesias Signed-off-by: Edgar E. Iglesias Message-Id: <20200506082513.18751-2-edgar.iglesias@gmail.com> --- hw/net/xilinx_axienet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 704788811a..0f97510d8a 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -149,8 +149,8 @@ tdk_write(struct PHY *phy, unsigned int req, unsigned int data) break; } - /* Unconditionally clear regs[BMCR][BMCR_RESET] */ - phy->regs[0] &= ~0x8000; + /* Unconditionally clear regs[BMCR][BMCR_RESET] and auto-neg */ + phy->regs[0] &= ~0x8200; } static void From 0d9047c4d999add0be60b12f204ce4c14c457415 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 6 May 2020 10:25:06 +0200 Subject: [PATCH 0405/2595] hw/net/xilinx_axienet: Cleanup stream->push assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the shared stream_class_init function to assign stream->push with better type-safety. Reviewed-by: Alistair Francis Reviewed-by: Francisco Iglesias Signed-off-by: Edgar E. Iglesias Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200506082513.18751-3-edgar.iglesias@gmail.com> --- hw/net/xilinx_axienet.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 0f97510d8a..84073753d7 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -1029,11 +1029,19 @@ static void xilinx_enet_class_init(ObjectClass *klass, void *data) dc->reset = xilinx_axienet_reset; } -static void xilinx_enet_stream_class_init(ObjectClass *klass, void *data) +static void xilinx_enet_control_stream_class_init(ObjectClass *klass, + void *data) { StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass); - ssc->push = data; + ssc->push = xilinx_axienet_control_stream_push; +} + +static void xilinx_enet_data_stream_class_init(ObjectClass *klass, void *data) +{ + StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass); + + ssc->push = xilinx_axienet_data_stream_push; } static const TypeInfo xilinx_enet_info = { @@ -1048,8 +1056,7 @@ static const TypeInfo xilinx_enet_data_stream_info = { .name = TYPE_XILINX_AXI_ENET_DATA_STREAM, .parent = TYPE_OBJECT, .instance_size = sizeof(struct XilinxAXIEnetStreamSlave), - .class_init = xilinx_enet_stream_class_init, - .class_data = xilinx_axienet_data_stream_push, + .class_init = xilinx_enet_data_stream_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_STREAM_SLAVE }, { } @@ -1060,8 +1067,7 @@ static const TypeInfo xilinx_enet_control_stream_info = { .name = TYPE_XILINX_AXI_ENET_CONTROL_STREAM, .parent = TYPE_OBJECT, .instance_size = sizeof(struct XilinxAXIEnetStreamSlave), - .class_init = xilinx_enet_stream_class_init, - .class_data = xilinx_axienet_control_stream_push, + .class_init = xilinx_enet_control_stream_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_STREAM_SLAVE }, { } From da59e178d743b8fdb44518f2e58590467ba5ec9e Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 6 May 2020 10:25:07 +0200 Subject: [PATCH 0406/2595] hw/net/xilinx_axienet: Remove unncessary cast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unncessary cast, buf is already uint8_t *. No functional change. Reviewed-by: Alistair Francis Reviewed-by: Francisco Iglesias Signed-off-by: Edgar E. Iglesias Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200506082513.18751-4-edgar.iglesias@gmail.com> --- hw/net/xilinx_axienet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 84073753d7..c8dfcda3ee 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -918,7 +918,7 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size) uint16_t csum; tmp_csum = net_checksum_add(size - start_off, - (uint8_t *)buf + start_off); + buf + start_off); /* Accumulate the seed. */ tmp_csum += s->hdr[2] & 0xffff; From e3a8926d0e91e6783157a9934bd6f59c7efaa992 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 6 May 2020 10:25:08 +0200 Subject: [PATCH 0407/2595] hw/dma/xilinx_axidma: Add DMA memory-region property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DMA memory-region property to externally control what address-space this DMA operates on. Reviewed-by: Alistair Francis Reviewed-by: Francisco Iglesias Signed-off-by: Edgar E. Iglesias Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200506082513.18751-5-edgar.iglesias@gmail.com> --- hw/dma/xilinx_axidma.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 018f36991b..4540051448 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -33,6 +33,7 @@ #include "qemu/log.h" #include "qemu/module.h" +#include "sysemu/dma.h" #include "hw/stream.h" #define D(x) @@ -103,6 +104,7 @@ enum { }; struct Stream { + struct XilinxAXIDMA *dma; ptimer_state *ptimer; qemu_irq irq; @@ -125,6 +127,9 @@ struct XilinxAXIDMAStreamSlave { struct XilinxAXIDMA { SysBusDevice busdev; MemoryRegion iomem; + MemoryRegion *dma_mr; + AddressSpace as; + uint32_t freqhz; StreamSlave *tx_data_dev; StreamSlave *tx_control_dev; @@ -186,7 +191,7 @@ static void stream_desc_load(struct Stream *s, hwaddr addr) { struct SDesc *d = &s->desc; - cpu_physical_memory_read(addr, d, sizeof *d); + address_space_read(&s->dma->as, addr, MEMTXATTRS_UNSPECIFIED, d, sizeof *d); /* Convert from LE into host endianness. */ d->buffer_address = le64_to_cpu(d->buffer_address); @@ -204,7 +209,8 @@ static void stream_desc_store(struct Stream *s, hwaddr addr) d->nxtdesc = cpu_to_le64(d->nxtdesc); d->control = cpu_to_le32(d->control); d->status = cpu_to_le32(d->status); - cpu_physical_memory_write(addr, d, sizeof *d); + address_space_write(&s->dma->as, addr, MEMTXATTRS_UNSPECIFIED, + d, sizeof *d); } static void stream_update_irq(struct Stream *s) @@ -286,8 +292,9 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev, txlen + s->pos); } - cpu_physical_memory_read(s->desc.buffer_address, - s->txbuf + s->pos, txlen); + address_space_read(&s->dma->as, s->desc.buffer_address, + MEMTXATTRS_UNSPECIFIED, + s->txbuf + s->pos, txlen); s->pos += txlen; if (stream_desc_eof(&s->desc)) { @@ -336,7 +343,8 @@ static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf, rxlen = len; } - cpu_physical_memory_write(s->desc.buffer_address, buf + pos, rxlen); + address_space_write(&s->dma->as, s->desc.buffer_address, + MEMTXATTRS_UNSPECIFIED, buf + pos, rxlen); len -= rxlen; pos += rxlen; @@ -525,6 +533,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM( &s->rx_control_dev); Error *local_err = NULL; + int i; object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA, (Object **)&ds->dma, @@ -545,17 +554,19 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) goto xilinx_axidma_realize_fail; } - int i; - for (i = 0; i < 2; i++) { struct Stream *st = &s->streams[i]; + st->dma = s; st->nr = i; st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_DEFAULT); ptimer_transaction_begin(st->ptimer); ptimer_set_freq(st->ptimer, s->freqhz); ptimer_transaction_commit(st->ptimer); } + + address_space_init(&s->as, + s->dma_mr ? s->dma_mr : get_system_memory(), "dma"); return; xilinx_axidma_realize_fail: @@ -575,6 +586,11 @@ static void xilinx_axidma_init(Object *obj) &s->rx_control_dev, sizeof(s->rx_control_dev), TYPE_XILINX_AXI_DMA_CONTROL_STREAM, &error_abort, NULL); + object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, + (Object **)&s->dma_mr, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG, + &error_abort); sysbus_init_irq(sbd, &s->streams[0].irq); sysbus_init_irq(sbd, &s->streams[1].irq); From 51b19950ca62abce05b00eef30d9ebbfb8b15f46 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 6 May 2020 10:25:09 +0200 Subject: [PATCH 0408/2595] hw/core: stream: Add an end-of-packet flag Some stream clients stream an endless stream of data while other clients stream data in packets. Stream interfaces usually have a way to signal the end of a packet or the last beat of a transfer. This adds an end-of-packet flag to the push interface. Reviewed-by: Alistair Francis Reviewed-by: Francisco Iglesias Signed-off-by: Edgar E. Iglesias Message-Id: <20200506082513.18751-6-edgar.iglesias@gmail.com> --- hw/core/stream.c | 4 ++-- hw/dma/xilinx_axidma.c | 10 ++++++---- hw/net/xilinx_axienet.c | 14 ++++++++++---- hw/ssi/xilinx_spips.c | 2 +- include/hw/stream.h | 5 +++-- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/hw/core/stream.c b/hw/core/stream.c index 39b1e595cd..a65ad1208d 100644 --- a/hw/core/stream.c +++ b/hw/core/stream.c @@ -3,11 +3,11 @@ #include "qemu/module.h" size_t -stream_push(StreamSlave *sink, uint8_t *buf, size_t len) +stream_push(StreamSlave *sink, uint8_t *buf, size_t len, bool eop) { StreamSlaveClass *k = STREAM_SLAVE_GET_CLASS(sink); - return k->push(sink, buf, len); + return k->push(sink, buf, len, eop); } bool diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 4540051448..a770e12c96 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -283,7 +283,7 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev, if (stream_desc_sof(&s->desc)) { s->pos = 0; - stream_push(tx_control_dev, s->desc.app, sizeof(s->desc.app)); + stream_push(tx_control_dev, s->desc.app, sizeof(s->desc.app), true); } txlen = s->desc.control & SDESC_CTRL_LEN_MASK; @@ -298,7 +298,7 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev, s->pos += txlen; if (stream_desc_eof(&s->desc)) { - stream_push(tx_data_dev, s->txbuf, s->pos); + stream_push(tx_data_dev, s->txbuf, s->pos, true); s->pos = 0; stream_complete(s); } @@ -384,7 +384,7 @@ static void xilinx_axidma_reset(DeviceState *dev) static size_t xilinx_axidma_control_stream_push(StreamSlave *obj, unsigned char *buf, - size_t len) + size_t len, bool eop) { XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(obj); struct Stream *s = &cs->dma->streams[1]; @@ -416,12 +416,14 @@ xilinx_axidma_data_stream_can_push(StreamSlave *obj, } static size_t -xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len) +xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len, + bool eop) { XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(obj); struct Stream *s = &ds->dma->streams[1]; size_t ret; + assert(eop); ret = stream_process_s2mem(s, buf, len); stream_update_irq(s); return ret; diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index c8dfcda3ee..bd48305577 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -697,14 +697,14 @@ static void axienet_eth_rx_notify(void *opaque) axienet_eth_rx_notify, s)) { size_t ret = stream_push(s->tx_control_dev, (void *)s->rxapp + CONTROL_PAYLOAD_SIZE - - s->rxappsize, s->rxappsize); + - s->rxappsize, s->rxappsize, true); s->rxappsize -= ret; } while (s->rxsize && stream_can_push(s->tx_data_dev, axienet_eth_rx_notify, s)) { size_t ret = stream_push(s->tx_data_dev, (void *)s->rxmem + s->rxpos, - s->rxsize); + s->rxsize, true); s->rxsize -= ret; s->rxpos += ret; if (!s->rxsize) { @@ -874,12 +874,14 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) } static size_t -xilinx_axienet_control_stream_push(StreamSlave *obj, uint8_t *buf, size_t len) +xilinx_axienet_control_stream_push(StreamSlave *obj, uint8_t *buf, size_t len, + bool eop) { int i; XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(obj); XilinxAXIEnet *s = cs->enet; + assert(eop); if (len != CONTROL_PAYLOAD_SIZE) { hw_error("AXI Enet requires %d byte control stream payload\n", (int)CONTROL_PAYLOAD_SIZE); @@ -894,11 +896,15 @@ xilinx_axienet_control_stream_push(StreamSlave *obj, uint8_t *buf, size_t len) } static size_t -xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size) +xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, + bool eop) { XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(obj); XilinxAXIEnet *s = ds->enet; + /* We don't support fragmented packets yet. */ + assert(eop); + /* TX enable ? */ if (!(s->tc & TC_TX)) { return size; diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index c57850a505..4cfce882ab 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -868,7 +868,7 @@ static void xlnx_zynqmp_qspips_notify(void *opaque) memcpy(rq->dma_buf, rxd, num); - ret = stream_push(rq->dma, rq->dma_buf, num); + ret = stream_push(rq->dma, rq->dma_buf, num, false); assert(ret == num); xlnx_zynqmp_qspips_check_flush(rq); } diff --git a/include/hw/stream.h b/include/hw/stream.h index d02f62ca89..ed09e83683 100644 --- a/include/hw/stream.h +++ b/include/hw/stream.h @@ -39,12 +39,13 @@ typedef struct StreamSlaveClass { * @obj: Stream slave to push to * @buf: Data to write * @len: Maximum number of bytes to write + * @eop: End of packet flag */ - size_t (*push)(StreamSlave *obj, unsigned char *buf, size_t len); + size_t (*push)(StreamSlave *obj, unsigned char *buf, size_t len, bool eop); } StreamSlaveClass; size_t -stream_push(StreamSlave *sink, uint8_t *buf, size_t len); +stream_push(StreamSlave *sink, uint8_t *buf, size_t len, bool eop); bool stream_can_push(StreamSlave *sink, StreamCanPushNotifyFn notify, From 2a4f26350c53f9f48d0245254d7af0c55a1d22fe Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 6 May 2020 10:25:10 +0200 Subject: [PATCH 0409/2595] hw/net/xilinx_axienet: Handle fragmented packets from DMA Add support for fragmented packets from the DMA. Reviewed-by: Francisco Iglesias Signed-off-by: Edgar E. Iglesias Message-Id: <20200506082513.18751-7-edgar.iglesias@gmail.com> --- hw/net/xilinx_axienet.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index bd48305577..498afe2f54 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -402,6 +402,9 @@ struct XilinxAXIEnet { uint32_t hdr[CONTROL_PAYLOAD_WORDS]; + uint8_t *txmem; + uint32_t txpos; + uint8_t *rxmem; uint32_t rxsize; uint32_t rxpos; @@ -421,6 +424,7 @@ static void axienet_rx_reset(XilinxAXIEnet *s) static void axienet_tx_reset(XilinxAXIEnet *s) { s->tc = TC_JUM | TC_TX | TC_VLAN; + s->txpos = 0; } static inline int axienet_rx_resetting(XilinxAXIEnet *s) @@ -902,17 +906,35 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(obj); XilinxAXIEnet *s = ds->enet; - /* We don't support fragmented packets yet. */ - assert(eop); - /* TX enable ? */ if (!(s->tc & TC_TX)) { return size; } + if (s->txpos + size > s->c_txmem) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Packet larger than txmem\n", + TYPE_XILINX_AXI_ENET); + s->txpos = 0; + return size; + } + + if (s->txpos == 0 && eop) { + /* Fast path single fragment. */ + s->txpos = size; + } else { + memcpy(s->txmem + s->txpos, buf, size); + buf = s->txmem; + s->txpos += size; + + if (!eop) { + return size; + } + } + /* Jumbo or vlan sizes ? */ if (!(s->tc & TC_JUM)) { - if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) { + if (s->txpos > 1518 && s->txpos <= 1522 && !(s->tc & TC_VLAN)) { + s->txpos = 0; return size; } } @@ -923,7 +945,7 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t tmp_csum; uint16_t csum; - tmp_csum = net_checksum_add(size - start_off, + tmp_csum = net_checksum_add(s->txpos - start_off, buf + start_off); /* Accumulate the seed. */ tmp_csum += s->hdr[2] & 0xffff; @@ -936,12 +958,13 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, buf[write_off + 1] = csum & 0xff; } - qemu_send_packet(qemu_get_queue(s->nic), buf, size); + qemu_send_packet(qemu_get_queue(s->nic), buf, s->txpos); - s->stats.tx_bytes += size; + s->stats.tx_bytes += s->txpos; s->regs[R_IS] |= IS_TX_COMPLETE; enet_update_irq(s); + s->txpos = 0; return size; } @@ -989,6 +1012,7 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) s->TEMAC.parent = s; s->rxmem = g_malloc(s->c_rxmem); + s->txmem = g_malloc(s->c_txmem); return; xilinx_enet_realize_fail: From 471fe8a2520272253adec1cc099e26f04958e301 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 6 May 2020 10:25:11 +0200 Subject: [PATCH 0410/2595] hw/dma/xilinx_axidma: mm2s: Stream descriptor by descriptor Stream descriptor by descriptor from memory instead of buffering entire packets before pushing. This enables non-packet streaming clients to work and also lifts the limitation that our internal DMA buffer needs to be able to hold entire packets. Reviewed-by: Alistair Francis Signed-off-by: Edgar E. Iglesias Message-Id: <20200506082513.18751-8-edgar.iglesias@gmail.com> --- hw/dma/xilinx_axidma.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index a770e12c96..101d32a965 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -111,7 +111,6 @@ struct Stream { int nr; struct SDesc desc; - int pos; unsigned int complete_cnt; uint32_t regs[R_MAX]; uint8_t app[20]; @@ -267,7 +266,9 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev, StreamSlave *tx_control_dev) { uint32_t prev_d; - unsigned int txlen; + uint32_t txlen; + uint64_t addr; + bool eop; if (!stream_running(s) || stream_idle(s)) { return; @@ -282,24 +283,26 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev, } if (stream_desc_sof(&s->desc)) { - s->pos = 0; stream_push(tx_control_dev, s->desc.app, sizeof(s->desc.app), true); } txlen = s->desc.control & SDESC_CTRL_LEN_MASK; - if ((txlen + s->pos) > sizeof s->txbuf) { - hw_error("%s: too small internal txbuf! %d\n", __func__, - txlen + s->pos); + + eop = stream_desc_eof(&s->desc); + addr = s->desc.buffer_address; + while (txlen) { + unsigned int len; + + len = txlen > sizeof s->txbuf ? sizeof s->txbuf : txlen; + address_space_read(&s->dma->as, addr, + MEMTXATTRS_UNSPECIFIED, + s->txbuf, len); + stream_push(tx_data_dev, s->txbuf, len, eop && len == txlen); + txlen -= len; + addr += len; } - address_space_read(&s->dma->as, s->desc.buffer_address, - MEMTXATTRS_UNSPECIFIED, - s->txbuf + s->pos, txlen); - s->pos += txlen; - - if (stream_desc_eof(&s->desc)) { - stream_push(tx_data_dev, s->txbuf, s->pos, true); - s->pos = 0; + if (eop) { stream_complete(s); } From 734e3befc20b699c69a6e20feade8073b1c19838 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 6 May 2020 10:25:12 +0200 Subject: [PATCH 0411/2595] hw/dma/xilinx_axidma: s2mm: Support stream fragments Add support for stream fragments. Reviewed-by: Alistair Francis Signed-off-by: Edgar E. Iglesias Message-Id: <20200506082513.18751-9-edgar.iglesias@gmail.com> --- hw/dma/xilinx_axidma.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 101d32a965..87be9cade7 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -110,6 +110,7 @@ struct Stream { int nr; + bool sof; struct SDesc desc; unsigned int complete_cnt; uint32_t regs[R_MAX]; @@ -174,6 +175,7 @@ static void stream_reset(struct Stream *s) { s->regs[R_DMASR] = DMASR_HALTED; /* starts up halted. */ s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold. */ + s->sof = true; } /* Map an offset addr into a channel index. */ @@ -321,12 +323,11 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev, } static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf, - size_t len) + size_t len, bool eop) { uint32_t prev_d; unsigned int rxlen; size_t pos = 0; - int sof = 1; if (!stream_running(s) || stream_idle(s)) { return 0; @@ -352,16 +353,16 @@ static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf, pos += rxlen; /* Update the descriptor. */ - if (!len) { + if (eop) { stream_complete(s); memcpy(s->desc.app, s->app, sizeof(s->desc.app)); s->desc.status |= SDESC_STATUS_EOF; } - s->desc.status |= sof << SDESC_STATUS_SOF_BIT; + s->desc.status |= s->sof << SDESC_STATUS_SOF_BIT; s->desc.status |= SDESC_STATUS_COMPLETE; stream_desc_store(s, s->regs[R_CURDESC]); - sof = 0; + s->sof = eop; /* Advance. */ prev_d = s->regs[R_CURDESC]; @@ -426,8 +427,7 @@ xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len, struct Stream *s = &ds->dma->streams[1]; size_t ret; - assert(eop); - ret = stream_process_s2mem(s, buf, len); + ret = stream_process_s2mem(s, buf, len, eop); stream_update_irq(s); return ret; } From 6d0af39f81cd22c7d26fd00e262d722e0003014f Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 6 May 2020 10:25:13 +0200 Subject: [PATCH 0412/2595] MAINTAINERS: Add myself as streams maintainer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we're missing a maintainer, add myself. Reviewed-by: Alistair Francis Signed-off-by: Edgar E. Iglesias Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200506082513.18751-10-edgar.iglesias@gmail.com> --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 005ee98a59..d11f3cb976 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2315,6 +2315,12 @@ F: net/slirp.c F: include/net/slirp.h T: git https://people.debian.org/~sthibault/qemu.git slirp +Streams +M: Edgar E. Iglesias +S: Maintained +F: hw/core/stream.c +F: include/hw/stream.h + Stubs M: Paolo Bonzini S: Maintained From 7cdae31d3a654d6487727809b27dd8e88874fd50 Mon Sep 17 00:00:00 2001 From: Tong Ho Date: Tue, 12 May 2020 16:36:49 +0200 Subject: [PATCH 0413/2595] target/microblaze: Add MFS Rd,EDR translation This is to fix cpu-abort with 'qemu: fatal: unknown mfs reg d' (in the default case) when microblaze guest issues 'MFS Rd,EDR' instruction. Since embeddedsw release 2019.2, XPlm_ExceptionHandler() issues the instruction on exception, and microblaze model aborts when PLM firmware guest encounters an exception. Signed-off-by: Tong Ho Reviewed-by: Edgar E. Iglesias Reviewed-by: Luc Michel Message-Id: <20200512143649.21655-2-edgar.iglesias@gmail.com> Signed-off-by: Edgar E. Iglesias --- target/microblaze/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 20b7427811..92b3630804 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -581,6 +581,7 @@ static void dec_msr(DisasContext *dc) case SR_ESR: case SR_FSR: case SR_BTR: + case SR_EDR: tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_SR[sr]); break; case 0x800: From 2016a6a765ad5283609183a5aa14d14285aaca6e Mon Sep 17 00:00:00 2001 From: Joe Komlodi Date: Mon, 11 May 2020 10:49:06 -0700 Subject: [PATCH 0414/2595] target/microblaze: Fix FPU2 instruction check The check to see if we can use FPU2 instructions would return 0 if cfg.use_fpu == 2, rather than returning the PVR2_USE_FPU2_MASK. This would cause all FPU2 instructions (fsqrt, flt, fint) to not be used. Signed-off-by: Joe Komlodi Reviewed-by: Edgar E. Iglesias Message-Id: <1589219346-106769-2-git-send-email-komlodi@xilinx.com> Signed-off-by: Edgar E. Iglesias --- target/microblaze/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 92b3630804..8079724f32 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1392,7 +1392,7 @@ static int dec_check_fpuv2(DisasContext *dc) tcg_gen_movi_i64(cpu_SR[SR_ESR], ESR_EC_FPU); t_gen_raise_exception(dc, EXCP_HW_EXCP); } - return (dc->cpu->cfg.use_fpu == 2) ? 0 : PVR2_USE_FPU2_MASK; + return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0; } static void dec_fpu(DisasContext *dc) From df2ac3cc12d251dcdd268038682fd27882e91bb2 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 7 Apr 2020 11:36:17 +0200 Subject: [PATCH 0415/2595] ui: improve -show-cursor deprecation message Specifically explain what users should do in case they don't use -display yet and depend on the qemu picking the ui for them. Signed-off-by: Gerd Hoffmann Message-id: 20200407093617.10058-1-kraxel@redhat.com --- softmmu/vl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index afd2615fb3..63eeb6ae1b 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -3531,8 +3531,10 @@ void qemu_init(int argc, char **argv, char **envp) no_shutdown = 1; break; case QEMU_OPTION_show_cursor: - warn_report("The -show-cursor option is deprecated, " - "use -display {sdl,gtk},show-cursor=on instead"); + warn_report("The -show-cursor option is deprecated. Please " + "add show-cursor=on to your -display options."); + warn_report("When using the default display you can use " + "-display default,show-cursor=on"); dpy.has_show_cursor = true; dpy.show_cursor = true; break; From 32ec9839d89d2b814ada20b041b25feae23596bc Mon Sep 17 00:00:00 2001 From: Changbin Du Date: Mon, 27 Apr 2020 21:24:12 +0800 Subject: [PATCH 0416/2595] ui/sdl2: fix segment fault caused by null pointer dereference I found SDL_GetWindowFromID() sometimes return NULL when I start qemu via ssh forwarding even the window has been crated already. I am not sure whether this is a bug of SDL, but we'd better check it carefully. Signed-off-by: Changbin Du Message-id: 20200427132412.17909-1-changbin.du@gmail.com Signed-off-by: Gerd Hoffmann --- ui/sdl2.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ui/sdl2.c b/ui/sdl2.c index 3c9424eb42..61c7956da3 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -332,6 +332,10 @@ static void handle_keydown(SDL_Event *ev) int gui_key_modifier_pressed = get_mod_state(); int gui_keysym = 0; + if (!scon) { + return; + } + if (!scon->ignore_hotkeys && gui_key_modifier_pressed && !ev->key.repeat) { switch (ev->key.keysym.scancode) { case SDL_SCANCODE_2: @@ -412,6 +416,10 @@ static void handle_keyup(SDL_Event *ev) { struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + if (!scon) { + return; + } + scon->ignore_hotkeys = false; sdl2_process_key(scon, &ev->key); } @@ -421,6 +429,10 @@ static void handle_textinput(SDL_Event *ev) struct sdl2_console *scon = get_scon_from_window(ev->text.windowID); QemuConsole *con = scon ? scon->dcl.con : NULL; + if (!con) { + return; + } + if (qemu_console_is_graphic(con)) { return; } From a44e82db0c0bada34af613029cf976f8bb7859d9 Mon Sep 17 00:00:00 2001 From: Joe Komlodi Date: Wed, 13 May 2020 11:08:46 -0700 Subject: [PATCH 0417/2595] target/microblaze: gdb: Extend the number of registers presented to GDB Increase the number of Microblaze registers QEMU will report when talking to GDB. Signed-off-by: Joe Komlodi Reviewed-by: Edgar E. Iglesias Message-Id: <1589393329-223076-2-git-send-email-komlodi@xilinx.com> Signed-off-by: Edgar E. Iglesias --- target/microblaze/cpu.c | 2 +- target/microblaze/gdbstub.c | 52 ++++++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index aa9983069a..51e5c85b10 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -329,7 +329,7 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) #endif dc->vmsd = &vmstate_mb_cpu; device_class_set_props(dc, mb_properties); - cc->gdb_num_core_regs = 32 + 5; + cc->gdb_num_core_regs = 32 + 27; cc->disas_set_info = mb_disas_set_info; cc->tcg_initialize = mb_tcg_init; diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index f41ebf1f33..54cc7857d1 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -26,12 +26,37 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; + /* + * GDB expects registers to be reported in this order: + * R0-R31 + * PC-BTR + * PVR0-PVR11 + * EDR-TLBHI + * SLR-SHR + */ if (n < 32) { return gdb_get_reg32(mem_buf, env->regs[n]); } else { - return gdb_get_reg32(mem_buf, env->sregs[n - 32]); + n -= 32; + switch (n) { + case 0 ... 5: + return gdb_get_reg32(mem_buf, env->sregs[n]); + /* PVR12 is intentionally skipped */ + case 6 ... 17: + n -= 6; + return gdb_get_reg32(mem_buf, env->pvr.regs[n]); + case 18 ... 24: + /* Add an offset of 6 to resume where we left off with SRegs */ + n = n - 18 + 6; + return gdb_get_reg32(mem_buf, env->sregs[n]); + case 25: + return gdb_get_reg32(mem_buf, env->slr); + case 26: + return gdb_get_reg32(mem_buf, env->shr); + default: + return 0; + } } - return 0; } int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) @@ -50,7 +75,28 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) if (n < 32) { env->regs[n] = tmp; } else { - env->sregs[n - 32] = tmp; + n -= 32; + switch (n) { + case 0 ... 5: + env->sregs[n] = tmp; + break; + /* PVR12 is intentionally skipped */ + case 6 ... 17: + n -= 6; + env->pvr.regs[n] = tmp; + break; + case 18 ... 24: + /* Add an offset of 6 to resume where we left off with SRegs */ + n = n - 18 + 6; + env->sregs[n] = tmp; + break; + case 25: + env->slr = tmp; + break; + case 26: + env->shr = tmp; + break; + } } return 4; } From 201dd7d37b654621c5727e49c666cbfc56e61d58 Mon Sep 17 00:00:00 2001 From: Joe Komlodi Date: Wed, 13 May 2020 11:08:47 -0700 Subject: [PATCH 0418/2595] target/microblaze: gdb: Fix incorrect SReg reporting SRegs used to be reported to GDB by iterating over the SRegs array, however we do not store them in an order that allows them to be reported to GDB in that way. To fix this, a simple map is used to map the register GDB wants to its location in the SRegs array. Signed-off-by: Joe Komlodi Reviewed-by: Edgar E. Iglesias Message-Id: <1589393329-223076-3-git-send-email-komlodi@xilinx.com> Signed-off-by: Edgar E. Iglesias --- target/microblaze/gdbstub.c | 59 ++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index 54cc7857d1..73e8973597 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -25,6 +25,21 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; + /* + * GDB expects SREGs in the following order: + * PC, MSR, EAR, ESR, FSR, BTR, EDR, PID, ZPR, TLBX, TLBSX, TLBLO, TLBHI. + * They aren't stored in this order, so make a map. + * PID, ZPR, TLBx, TLBsx, TLBLO, and TLBHI aren't modeled, so we don't + * map them to anything and return a value of 0 instead. + */ + static const uint8_t sreg_map[6] = { + SR_PC, + SR_MSR, + SR_EAR, + SR_ESR, + SR_FSR, + SR_BTR + }; /* * GDB expects registers to be reported in this order: @@ -40,15 +55,16 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) n -= 32; switch (n) { case 0 ... 5: - return gdb_get_reg32(mem_buf, env->sregs[n]); + return gdb_get_reg32(mem_buf, env->sregs[sreg_map[n]]); /* PVR12 is intentionally skipped */ case 6 ... 17: n -= 6; return gdb_get_reg32(mem_buf, env->pvr.regs[n]); - case 18 ... 24: - /* Add an offset of 6 to resume where we left off with SRegs */ - n = n - 18 + 6; - return gdb_get_reg32(mem_buf, env->sregs[n]); + case 18: + return gdb_get_reg32(mem_buf, env->sregs[SR_EDR]); + /* Other SRegs aren't modeled, so report a value of 0 */ + case 19 ... 24: + return gdb_get_reg32(mem_buf, 0); case 25: return gdb_get_reg32(mem_buf, env->slr); case 26: @@ -66,29 +82,52 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) CPUMBState *env = &cpu->env; uint32_t tmp; + /* + * GDB expects SREGs in the following order: + * PC, MSR, EAR, ESR, FSR, BTR, EDR, PID, ZPR, TLBX, TLBSX, TLBLO, TLBHI. + * They aren't stored in this order, so make a map. + * PID, ZPR, TLBx, TLBsx, TLBLO, and TLBHI aren't modeled, so we don't + * map them to anything. + */ + static const uint8_t sreg_map[6] = { + SR_PC, + SR_MSR, + SR_EAR, + SR_ESR, + SR_FSR, + SR_BTR + }; + if (n > cc->gdb_num_core_regs) { return 0; } tmp = ldl_p(mem_buf); + /* + * GDB expects registers to be reported in this order: + * R0-R31 + * PC-BTR + * PVR0-PVR11 + * EDR-TLBHI + * SLR-SHR + */ if (n < 32) { env->regs[n] = tmp; } else { n -= 32; switch (n) { case 0 ... 5: - env->sregs[n] = tmp; + env->sregs[sreg_map[n]] = tmp; break; /* PVR12 is intentionally skipped */ case 6 ... 17: n -= 6; env->pvr.regs[n] = tmp; break; - case 18 ... 24: - /* Add an offset of 6 to resume where we left off with SRegs */ - n = n - 18 + 6; - env->sregs[n] = tmp; + /* Only EDR is modeled in these indeces, so ignore the rest */ + case 18: + env->sregs[SR_EDR] = tmp; break; case 25: env->slr = tmp; From 2ead1b18ca1bbc41c09a82d980e1e5f53afa08eb Mon Sep 17 00:00:00 2001 From: Joe Komlodi Date: Wed, 13 May 2020 11:08:48 -0700 Subject: [PATCH 0419/2595] target/microblaze: monitor: Increase the number of registers reported Increase the number of registers reported to match GDB. Registers that aren't modeled are reported as 0. Signed-off-by: Joe Komlodi Reviewed-by: Edgar E. Iglesias Message-Id: <1589393329-223076-4-git-send-email-komlodi@xilinx.com> Signed-off-by: Edgar E. Iglesias --- target/microblaze/translate.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 8079724f32..f6ff2591c3 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1789,9 +1789,11 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, "IN: PC=%" PRIx64 " %s\n", env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC])); qemu_fprintf(f, "rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " - "debug=%x imm=%x iflags=%x fsr=%" PRIx64 "\n", + "debug=%x imm=%x iflags=%x fsr=%" PRIx64 " " + "rbtr=%" PRIx64 "\n", env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR], - env->debug, env->imm, env->iflags, env->sregs[SR_FSR]); + env->debug, env->imm, env->iflags, env->sregs[SR_FSR], + env->sregs[SR_BTR]); qemu_fprintf(f, "btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) " "eip=%d ie=%d\n", env->btaken, env->btarget, @@ -1799,7 +1801,17 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel", (bool)(env->sregs[SR_MSR] & MSR_EIP), (bool)(env->sregs[SR_MSR] & MSR_IE)); + for (i = 0; i < 12; i++) { + qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]); + if ((i + 1) % 4 == 0) { + qemu_fprintf(f, "\n"); + } + } + /* Registers that aren't modeled are reported as 0 */ + qemu_fprintf(f, "redr=%" PRIx64 " rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " + "rtlblo=0 rtlbhi=0\n", env->sregs[SR_EDR]); + qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr); for (i = 0; i < 32; i++) { qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); if ((i + 1) % 4 == 0) From c888f7e0fdcc09c86004330ab5cad62bf98cc71c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 7 May 2020 14:47:55 +0100 Subject: [PATCH 0420/2595] target/arm: Use correct GDB XML for M-profile cores MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GDB's remote protocol requires M-profile cores to use the feature name 'org.gnu.gdb.arm.m-profile' instead of the 'org.gnu.gdb.arm.core' feature used for A- and R-profile cores. We weren't doing this, which meant GDB treated our M-profile cores like A-profile ones. This mostly doesn't matter, but for instance means that it doesn't correctly handle backtraces where an M-profile exception frame is involved. Ship a copy of GDB's arm-m-profile.xml and use it on the M-profile cores. The integer registers have the same offsets as the arm-core.xml, but register 25 is the M-profile XPSR rather than the A-profile CPSR, so we need to update arm_cpu_gdb_read_register() and arm_cpu_gdb_write_register() to handle XSPR reads and writes. Fixes: https://bugs.launchpad.net/qemu/+bug/1877136 Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200507134755.13997-1-peter.maydell@linaro.org --- configure | 4 ++-- gdb-xml/arm-m-profile.xml | 27 +++++++++++++++++++++++++++ target/arm/cpu_tcg.c | 1 + target/arm/gdbstub.c | 22 ++++++++++++++++++---- 4 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 gdb-xml/arm-m-profile.xml diff --git a/configure b/configure index c50c006b86..26084fc53a 100755 --- a/configure +++ b/configure @@ -7806,14 +7806,14 @@ case "$target_name" in TARGET_SYSTBL_ABI=common,oabi bflt="yes" mttcg="yes" - gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" + gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml arm-m-profile.xml" ;; aarch64|aarch64_be) TARGET_ARCH=aarch64 TARGET_BASE_ARCH=arm bflt="yes" mttcg="yes" - gdb_xml_files="aarch64-core.xml aarch64-fpu.xml arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" + gdb_xml_files="aarch64-core.xml aarch64-fpu.xml arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml arm-m-profile.xml" ;; cris) ;; diff --git a/gdb-xml/arm-m-profile.xml b/gdb-xml/arm-m-profile.xml new file mode 100644 index 0000000000..5319d764ee --- /dev/null +++ b/gdb-xml/arm-m-profile.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 591baef535..00b0e08f33 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -605,6 +605,7 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data) #endif cc->cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt; + cc->gdb_core_xml_file = "arm-m-profile.xml"; } static const ARMCPUInfo arm_tcg_cpus[] = { diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index 063551df23..ecfa88f8e6 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -57,8 +57,12 @@ int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) } return gdb_get_reg32(mem_buf, 0); case 25: - /* CPSR */ - return gdb_get_reg32(mem_buf, cpsr_read(env)); + /* CPSR, or XPSR for M-profile */ + if (arm_feature(env, ARM_FEATURE_M)) { + return gdb_get_reg32(mem_buf, xpsr_read(env)); + } else { + return gdb_get_reg32(mem_buf, cpsr_read(env)); + } } /* Unknown register. */ return 0; @@ -98,8 +102,18 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) } return 4; case 25: - /* CPSR */ - cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub); + /* CPSR, or XPSR for M-profile */ + if (arm_feature(env, ARM_FEATURE_M)) { + /* + * Don't allow writing to XPSR.Exception as it can cause + * a transition into or out of handler mode (it's not + * writeable via the MSR insn so this is a reasonable + * restriction). Other fields are safe to update. + */ + xpsr_write(env, tmp, ~XPSR_EXCP); + } else { + cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub); + } return 4; } /* Unknown register. */ From 631e565450c483e0622eec3d8b61d7fa41d16bca Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:30 -0700 Subject: [PATCH 0421/2595] target/arm: Create gen_gvec_[us]sra The functions eliminate duplication of the special cases for this operation. They match up with the GVecGen2iFn typedef. Add out-of-line helpers. We got away with only having inline expanders because the neon vector size is only 16 bytes, and we know that the inline expansion will always succeed. When we reuse this for SVE, tcg-gvec-op may decide to use an out-of-line helper due to longer vector lengths. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.h | 10 +++ target/arm/translate-a64.c | 15 +--- target/arm/translate.c | 161 ++++++++++++++++++++++--------------- target/arm/translate.h | 7 +- target/arm/vec_helper.c | 25 ++++++ 5 files changed, 139 insertions(+), 79 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 5817626b20..9bc162345c 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -691,6 +691,16 @@ DEF_HELPER_FLAGS_4(gvec_pmull_q, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(neon_pmull_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ssra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ssra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ssra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ssra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_usra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_usra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_usra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_usra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + #ifdef TARGET_AARCH64 #include "helper-a64.h" #include "helper-sve.h" diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 62e5729904..315de9a9b6 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -10188,19 +10188,8 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, switch (opcode) { case 0x02: /* SSRA / USRA (accumulate) */ - if (is_u) { - /* Shift count same as element size produces zero to add. */ - if (shift == 8 << size) { - goto done; - } - gen_gvec_op2i(s, is_q, rd, rn, shift, &usra_op[size]); - } else { - /* Shift count same as element size produces all sign to add. */ - if (shift == 8 << size) { - shift -= 1; - } - gen_gvec_op2i(s, is_q, rd, rn, shift, &ssra_op[size]); - } + gen_gvec_fn2i(s, is_q, rd, rn, shift, + is_u ? gen_gvec_usra : gen_gvec_ssra, size); return; case 0x08: /* SRI */ /* Shift count same as element size is valid but does nothing. */ diff --git a/target/arm/translate.c b/target/arm/translate.c index 74fac1d09c..c18140f2e6 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3874,33 +3874,51 @@ static void gen_ssra_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh) tcg_gen_add_vec(vece, d, d, a); } -static const TCGOpcode vecop_list_ssra[] = { - INDEX_op_sari_vec, INDEX_op_add_vec, 0 -}; +void gen_gvec_ssra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_sari_vec, INDEX_op_add_vec, 0 + }; + static const GVecGen2i ops[4] = { + { .fni8 = gen_ssra8_i64, + .fniv = gen_ssra_vec, + .fno = gen_helper_gvec_ssra_b, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fni8 = gen_ssra16_i64, + .fniv = gen_ssra_vec, + .fno = gen_helper_gvec_ssra_h, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_ssra32_i32, + .fniv = gen_ssra_vec, + .fno = gen_helper_gvec_ssra_s, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_ssra64_i64, + .fniv = gen_ssra_vec, + .fno = gen_helper_gvec_ssra_b, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_64 }, + }; -const GVecGen2i ssra_op[4] = { - { .fni8 = gen_ssra8_i64, - .fniv = gen_ssra_vec, - .load_dest = true, - .opt_opc = vecop_list_ssra, - .vece = MO_8 }, - { .fni8 = gen_ssra16_i64, - .fniv = gen_ssra_vec, - .load_dest = true, - .opt_opc = vecop_list_ssra, - .vece = MO_16 }, - { .fni4 = gen_ssra32_i32, - .fniv = gen_ssra_vec, - .load_dest = true, - .opt_opc = vecop_list_ssra, - .vece = MO_32 }, - { .fni8 = gen_ssra64_i64, - .fniv = gen_ssra_vec, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .opt_opc = vecop_list_ssra, - .load_dest = true, - .vece = MO_64 }, -}; + /* tszimm encoding produces immediates in the range [1..esize]. */ + tcg_debug_assert(shift > 0); + tcg_debug_assert(shift <= (8 << vece)); + + /* + * Shifts larger than the element size are architecturally valid. + * Signed results in all sign bits. + */ + shift = MIN(shift, (8 << vece) - 1); + tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]); +} static void gen_usra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift) { @@ -3932,33 +3950,55 @@ static void gen_usra_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh) tcg_gen_add_vec(vece, d, d, a); } -static const TCGOpcode vecop_list_usra[] = { - INDEX_op_shri_vec, INDEX_op_add_vec, 0 -}; +void gen_gvec_usra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_shri_vec, INDEX_op_add_vec, 0 + }; + static const GVecGen2i ops[4] = { + { .fni8 = gen_usra8_i64, + .fniv = gen_usra_vec, + .fno = gen_helper_gvec_usra_b, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_8, }, + { .fni8 = gen_usra16_i64, + .fniv = gen_usra_vec, + .fno = gen_helper_gvec_usra_h, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_16, }, + { .fni4 = gen_usra32_i32, + .fniv = gen_usra_vec, + .fno = gen_helper_gvec_usra_s, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_32, }, + { .fni8 = gen_usra64_i64, + .fniv = gen_usra_vec, + .fno = gen_helper_gvec_usra_d, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_64, }, + }; -const GVecGen2i usra_op[4] = { - { .fni8 = gen_usra8_i64, - .fniv = gen_usra_vec, - .load_dest = true, - .opt_opc = vecop_list_usra, - .vece = MO_8, }, - { .fni8 = gen_usra16_i64, - .fniv = gen_usra_vec, - .load_dest = true, - .opt_opc = vecop_list_usra, - .vece = MO_16, }, - { .fni4 = gen_usra32_i32, - .fniv = gen_usra_vec, - .load_dest = true, - .opt_opc = vecop_list_usra, - .vece = MO_32, }, - { .fni8 = gen_usra64_i64, - .fniv = gen_usra_vec, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .load_dest = true, - .opt_opc = vecop_list_usra, - .vece = MO_64, }, -}; + /* tszimm encoding produces immediates in the range [1..esize]. */ + tcg_debug_assert(shift > 0); + tcg_debug_assert(shift <= (8 << vece)); + + /* + * Shifts larger than the element size are architecturally valid. + * Unsigned results in all zeros as input to accumulate: nop. + */ + if (shift < (8 << vece)) { + tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]); + } else { + /* Nop, but we do need to clear the tail. */ + tcg_gen_gvec_mov(vece, rd_ofs, rd_ofs, opr_sz, max_sz); + } +} static void gen_shr8_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift) { @@ -5220,19 +5260,12 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case 1: /* VSRA */ /* Right shift comes here negative. */ shift = -shift; - /* Shifts larger than the element size are architecturally - * valid. Unsigned results in all zeros; signed results - * in all sign bits. - */ - if (!u) { - tcg_gen_gvec_2i(rd_ofs, rm_ofs, vec_size, vec_size, - MIN(shift, (8 << size) - 1), - &ssra_op[size]); - } else if (shift >= 8 << size) { - /* rd += 0 */ + if (u) { + gen_gvec_usra(size, rd_ofs, rm_ofs, shift, + vec_size, vec_size); } else { - tcg_gen_gvec_2i(rd_ofs, rm_ofs, vec_size, vec_size, - shift, &usra_op[size]); + gen_gvec_ssra(size, rd_ofs, rm_ofs, shift, + vec_size, vec_size); } return 0; diff --git a/target/arm/translate.h b/target/arm/translate.h index cb7925ea46..1839a59a8e 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -285,8 +285,6 @@ extern const GVecGen3 mls_op[4]; extern const GVecGen3 cmtst_op[4]; extern const GVecGen3 sshl_op[4]; extern const GVecGen3 ushl_op[4]; -extern const GVecGen2i ssra_op[4]; -extern const GVecGen2i usra_op[4]; extern const GVecGen2i sri_op[4]; extern const GVecGen2i sli_op[4]; extern const GVecGen4 uqadd_op[4]; @@ -299,6 +297,11 @@ void gen_sshl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b); void gen_ushl_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b); void gen_sshl_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b); +void gen_gvec_ssra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_usra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz); + /* * Forward to the isar_feature_* tests given a DisasContext pointer. */ diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index 3d534188a8..230085b35e 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -899,6 +899,31 @@ void HELPER(gvec_sqsub_d)(void *vd, void *vq, void *vn, clear_tail(d, oprsz, simd_maxsz(desc)); } + +#define DO_SRA(NAME, TYPE) \ +void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \ +{ \ + intptr_t i, oprsz = simd_oprsz(desc); \ + int shift = simd_data(desc); \ + TYPE *d = vd, *n = vn; \ + for (i = 0; i < oprsz / sizeof(TYPE); i++) { \ + d[i] += n[i] >> shift; \ + } \ + clear_tail(d, oprsz, simd_maxsz(desc)); \ +} + +DO_SRA(gvec_ssra_b, int8_t) +DO_SRA(gvec_ssra_h, int16_t) +DO_SRA(gvec_ssra_s, int32_t) +DO_SRA(gvec_ssra_d, int64_t) + +DO_SRA(gvec_usra_b, uint8_t) +DO_SRA(gvec_usra_h, uint16_t) +DO_SRA(gvec_usra_s, uint32_t) +DO_SRA(gvec_usra_d, uint64_t) + +#undef DO_SRA + /* * Convert float16 to float32, raising no exceptions and * preserving exceptional values, including SNaN. From 6ccd48d4ea244c1c46a24dfa50bfb547f11422dd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:31 -0700 Subject: [PATCH 0422/2595] target/arm: Create gen_gvec_{u,s}{rshr,rsra} Create vectorized versions of handle_shri_with_rndacc for shift+round and shift+round+accumulate. Add out-of-line helpers in preparation for longer vector lengths from SVE. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.h | 20 ++ target/arm/translate-a64.c | 11 +- target/arm/translate.c | 463 +++++++++++++++++++++++++++++++++++-- target/arm/translate.h | 9 + target/arm/vec_helper.c | 50 ++++ 5 files changed, 527 insertions(+), 26 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 9bc162345c..aeb1f52455 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -701,6 +701,26 @@ DEF_HELPER_FLAGS_3(gvec_usra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(gvec_usra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(gvec_usra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srshr_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srshr_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srshr_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srshr_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_urshr_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_urshr_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_urshr_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_urshr_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_srsra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srsra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srsra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srsra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_ursra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ursra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ursra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ursra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + #ifdef TARGET_AARCH64 #include "helper-a64.h" #include "helper-sve.h" diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 315de9a9b6..50949d306b 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -10218,10 +10218,15 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, return; case 0x04: /* SRSHR / URSHR (rounding) */ - break; + gen_gvec_fn2i(s, is_q, rd, rn, shift, + is_u ? gen_gvec_urshr : gen_gvec_srshr, size); + return; + case 0x06: /* SRSRA / URSRA (accum + rounding) */ - accumulate = true; - break; + gen_gvec_fn2i(s, is_q, rd, rn, shift, + is_u ? gen_gvec_ursra : gen_gvec_srsra, size); + return; + default: g_assert_not_reached(); } diff --git a/target/arm/translate.c b/target/arm/translate.c index c18140f2e6..aa03dc236b 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4000,6 +4000,422 @@ void gen_gvec_usra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, } } +/* + * Shift one less than the requested amount, and the low bit is + * the rounding bit. For the 8 and 16-bit operations, because we + * mask the low bit, we can perform a normal integer shift instead + * of a vector shift. + */ +static void gen_srshr8_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_shri_i64(t, a, sh - 1); + tcg_gen_andi_i64(t, t, dup_const(MO_8, 1)); + tcg_gen_vec_sar8i_i64(d, a, sh); + tcg_gen_vec_add8_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_srshr16_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_shri_i64(t, a, sh - 1); + tcg_gen_andi_i64(t, t, dup_const(MO_16, 1)); + tcg_gen_vec_sar16i_i64(d, a, sh); + tcg_gen_vec_add16_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_srshr32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh) +{ + TCGv_i32 t = tcg_temp_new_i32(); + + tcg_gen_extract_i32(t, a, sh - 1, 1); + tcg_gen_sari_i32(d, a, sh); + tcg_gen_add_i32(d, d, t); + tcg_temp_free_i32(t); +} + +static void gen_srshr64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_extract_i64(t, a, sh - 1, 1); + tcg_gen_sari_i64(d, a, sh); + tcg_gen_add_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_srshr_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + TCGv_vec ones = tcg_temp_new_vec_matching(d); + + tcg_gen_shri_vec(vece, t, a, sh - 1); + tcg_gen_dupi_vec(vece, ones, 1); + tcg_gen_and_vec(vece, t, t, ones); + tcg_gen_sari_vec(vece, d, a, sh); + tcg_gen_add_vec(vece, d, d, t); + + tcg_temp_free_vec(t); + tcg_temp_free_vec(ones); +} + +void gen_gvec_srshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_shri_vec, INDEX_op_sari_vec, INDEX_op_add_vec, 0 + }; + static const GVecGen2i ops[4] = { + { .fni8 = gen_srshr8_i64, + .fniv = gen_srshr_vec, + .fno = gen_helper_gvec_srshr_b, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fni8 = gen_srshr16_i64, + .fniv = gen_srshr_vec, + .fno = gen_helper_gvec_srshr_h, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_srshr32_i32, + .fniv = gen_srshr_vec, + .fno = gen_helper_gvec_srshr_s, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_srshr64_i64, + .fniv = gen_srshr_vec, + .fno = gen_helper_gvec_srshr_d, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; + + /* tszimm encoding produces immediates in the range [1..esize] */ + tcg_debug_assert(shift > 0); + tcg_debug_assert(shift <= (8 << vece)); + + if (shift == (8 << vece)) { + /* + * Shifts larger than the element size are architecturally valid. + * Signed results in all sign bits. With rounding, this produces + * (-1 + 1) >> 1 == 0, or (0 + 1) >> 1 == 0. + * I.e. always zero. + */ + tcg_gen_gvec_dup_imm(vece, rd_ofs, opr_sz, max_sz, 0); + } else { + tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]); + } +} + +static void gen_srsra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + gen_srshr8_i64(t, a, sh); + tcg_gen_vec_add8_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_srsra16_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + gen_srshr16_i64(t, a, sh); + tcg_gen_vec_add16_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_srsra32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh) +{ + TCGv_i32 t = tcg_temp_new_i32(); + + gen_srshr32_i32(t, a, sh); + tcg_gen_add_i32(d, d, t); + tcg_temp_free_i32(t); +} + +static void gen_srsra64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + gen_srshr64_i64(t, a, sh); + tcg_gen_add_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_srsra_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + + gen_srshr_vec(vece, t, a, sh); + tcg_gen_add_vec(vece, d, d, t); + tcg_temp_free_vec(t); +} + +void gen_gvec_srsra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_shri_vec, INDEX_op_sari_vec, INDEX_op_add_vec, 0 + }; + static const GVecGen2i ops[4] = { + { .fni8 = gen_srsra8_i64, + .fniv = gen_srsra_vec, + .fno = gen_helper_gvec_srsra_b, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_8 }, + { .fni8 = gen_srsra16_i64, + .fniv = gen_srsra_vec, + .fno = gen_helper_gvec_srsra_h, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_16 }, + { .fni4 = gen_srsra32_i32, + .fniv = gen_srsra_vec, + .fno = gen_helper_gvec_srsra_s, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_32 }, + { .fni8 = gen_srsra64_i64, + .fniv = gen_srsra_vec, + .fno = gen_helper_gvec_srsra_d, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_64 }, + }; + + /* tszimm encoding produces immediates in the range [1..esize] */ + tcg_debug_assert(shift > 0); + tcg_debug_assert(shift <= (8 << vece)); + + /* + * Shifts larger than the element size are architecturally valid. + * Signed results in all sign bits. With rounding, this produces + * (-1 + 1) >> 1 == 0, or (0 + 1) >> 1 == 0. + * I.e. always zero. With accumulation, this leaves D unchanged. + */ + if (shift == (8 << vece)) { + /* Nop, but we do need to clear the tail. */ + tcg_gen_gvec_mov(vece, rd_ofs, rd_ofs, opr_sz, max_sz); + } else { + tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]); + } +} + +static void gen_urshr8_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_shri_i64(t, a, sh - 1); + tcg_gen_andi_i64(t, t, dup_const(MO_8, 1)); + tcg_gen_vec_shr8i_i64(d, a, sh); + tcg_gen_vec_add8_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_urshr16_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_shri_i64(t, a, sh - 1); + tcg_gen_andi_i64(t, t, dup_const(MO_16, 1)); + tcg_gen_vec_shr16i_i64(d, a, sh); + tcg_gen_vec_add16_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_urshr32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh) +{ + TCGv_i32 t = tcg_temp_new_i32(); + + tcg_gen_extract_i32(t, a, sh - 1, 1); + tcg_gen_shri_i32(d, a, sh); + tcg_gen_add_i32(d, d, t); + tcg_temp_free_i32(t); +} + +static void gen_urshr64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_extract_i64(t, a, sh - 1, 1); + tcg_gen_shri_i64(d, a, sh); + tcg_gen_add_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_urshr_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t shift) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + TCGv_vec ones = tcg_temp_new_vec_matching(d); + + tcg_gen_shri_vec(vece, t, a, shift - 1); + tcg_gen_dupi_vec(vece, ones, 1); + tcg_gen_and_vec(vece, t, t, ones); + tcg_gen_shri_vec(vece, d, a, shift); + tcg_gen_add_vec(vece, d, d, t); + + tcg_temp_free_vec(t); + tcg_temp_free_vec(ones); +} + +void gen_gvec_urshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_shri_vec, INDEX_op_add_vec, 0 + }; + static const GVecGen2i ops[4] = { + { .fni8 = gen_urshr8_i64, + .fniv = gen_urshr_vec, + .fno = gen_helper_gvec_urshr_b, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fni8 = gen_urshr16_i64, + .fniv = gen_urshr_vec, + .fno = gen_helper_gvec_urshr_h, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_urshr32_i32, + .fniv = gen_urshr_vec, + .fno = gen_helper_gvec_urshr_s, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_urshr64_i64, + .fniv = gen_urshr_vec, + .fno = gen_helper_gvec_urshr_d, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; + + /* tszimm encoding produces immediates in the range [1..esize] */ + tcg_debug_assert(shift > 0); + tcg_debug_assert(shift <= (8 << vece)); + + if (shift == (8 << vece)) { + /* + * Shifts larger than the element size are architecturally valid. + * Unsigned results in zero. With rounding, this produces a + * copy of the most significant bit. + */ + tcg_gen_gvec_shri(vece, rd_ofs, rm_ofs, shift - 1, opr_sz, max_sz); + } else { + tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]); + } +} + +static void gen_ursra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + if (sh == 8) { + tcg_gen_vec_shr8i_i64(t, a, 7); + } else { + gen_urshr8_i64(t, a, sh); + } + tcg_gen_vec_add8_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_ursra16_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + if (sh == 16) { + tcg_gen_vec_shr16i_i64(t, a, 15); + } else { + gen_urshr16_i64(t, a, sh); + } + tcg_gen_vec_add16_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_ursra32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh) +{ + TCGv_i32 t = tcg_temp_new_i32(); + + if (sh == 32) { + tcg_gen_shri_i32(t, a, 31); + } else { + gen_urshr32_i32(t, a, sh); + } + tcg_gen_add_i32(d, d, t); + tcg_temp_free_i32(t); +} + +static void gen_ursra64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + if (sh == 64) { + tcg_gen_shri_i64(t, a, 63); + } else { + gen_urshr64_i64(t, a, sh); + } + tcg_gen_add_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_ursra_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + + if (sh == (8 << vece)) { + tcg_gen_shri_vec(vece, t, a, sh - 1); + } else { + gen_urshr_vec(vece, t, a, sh); + } + tcg_gen_add_vec(vece, d, d, t); + tcg_temp_free_vec(t); +} + +void gen_gvec_ursra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_shri_vec, INDEX_op_add_vec, 0 + }; + static const GVecGen2i ops[4] = { + { .fni8 = gen_ursra8_i64, + .fniv = gen_ursra_vec, + .fno = gen_helper_gvec_ursra_b, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_8 }, + { .fni8 = gen_ursra16_i64, + .fniv = gen_ursra_vec, + .fno = gen_helper_gvec_ursra_h, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_16 }, + { .fni4 = gen_ursra32_i32, + .fniv = gen_ursra_vec, + .fno = gen_helper_gvec_ursra_s, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_32 }, + { .fni8 = gen_ursra64_i64, + .fniv = gen_ursra_vec, + .fno = gen_helper_gvec_ursra_d, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_64 }, + }; + + /* tszimm encoding produces immediates in the range [1..esize] */ + tcg_debug_assert(shift > 0); + tcg_debug_assert(shift <= (8 << vece)); + + tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]); +} + static void gen_shr8_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift) { uint64_t mask = dup_const(MO_8, 0xff >> shift); @@ -5269,6 +5685,30 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } return 0; + case 2: /* VRSHR */ + /* Right shift comes here negative. */ + shift = -shift; + if (u) { + gen_gvec_urshr(size, rd_ofs, rm_ofs, shift, + vec_size, vec_size); + } else { + gen_gvec_srshr(size, rd_ofs, rm_ofs, shift, + vec_size, vec_size); + } + return 0; + + case 3: /* VRSRA */ + /* Right shift comes here negative. */ + shift = -shift; + if (u) { + gen_gvec_ursra(size, rd_ofs, rm_ofs, shift, + vec_size, vec_size); + } else { + gen_gvec_srsra(size, rd_ofs, rm_ofs, shift, + vec_size, vec_size); + } + return 0; + case 4: /* VSRI */ if (!u) { return 1; @@ -5320,13 +5760,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) neon_load_reg64(cpu_V0, rm + pass); tcg_gen_movi_i64(cpu_V1, imm); switch (op) { - case 2: /* VRSHR */ - case 3: /* VRSRA */ - if (u) - gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1); - else - gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1); - break; case 6: /* VQSHLU */ gen_helper_neon_qshlu_s64(cpu_V0, cpu_env, cpu_V0, cpu_V1); @@ -5343,11 +5776,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) default: g_assert_not_reached(); } - if (op == 3) { - /* Accumulate. */ - neon_load_reg64(cpu_V1, rd + pass); - tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1); - } neon_store_reg64(cpu_V0, rd + pass); } else { /* size < 3 */ /* Operands in T0 and T1. */ @@ -5355,10 +5783,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp2 = tcg_temp_new_i32(); tcg_gen_movi_i32(tmp2, imm); switch (op) { - case 2: /* VRSHR */ - case 3: /* VRSRA */ - GEN_NEON_INTEGER_OP(rshl); - break; case 6: /* VQSHLU */ switch (size) { case 0: @@ -5384,13 +5808,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) g_assert_not_reached(); } tcg_temp_free_i32(tmp2); - - if (op == 3) { - /* Accumulate. */ - tmp2 = neon_load_reg(rd, pass); - gen_neon_add(size, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } neon_store_reg(rd, pass, tmp); } } /* for pass */ diff --git a/target/arm/translate.h b/target/arm/translate.h index 1839a59a8e..1db3b43a61 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -302,6 +302,15 @@ void gen_gvec_ssra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, void gen_gvec_usra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, int64_t shift, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_srshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_urshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_srsra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_ursra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz); + /* * Forward to the isar_feature_* tests given a DisasContext pointer. */ diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index 230085b35e..fd8b2bff49 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -924,6 +924,56 @@ DO_SRA(gvec_usra_d, uint64_t) #undef DO_SRA +#define DO_RSHR(NAME, TYPE) \ +void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \ +{ \ + intptr_t i, oprsz = simd_oprsz(desc); \ + int shift = simd_data(desc); \ + TYPE *d = vd, *n = vn; \ + for (i = 0; i < oprsz / sizeof(TYPE); i++) { \ + TYPE tmp = n[i] >> (shift - 1); \ + d[i] = (tmp >> 1) + (tmp & 1); \ + } \ + clear_tail(d, oprsz, simd_maxsz(desc)); \ +} + +DO_RSHR(gvec_srshr_b, int8_t) +DO_RSHR(gvec_srshr_h, int16_t) +DO_RSHR(gvec_srshr_s, int32_t) +DO_RSHR(gvec_srshr_d, int64_t) + +DO_RSHR(gvec_urshr_b, uint8_t) +DO_RSHR(gvec_urshr_h, uint16_t) +DO_RSHR(gvec_urshr_s, uint32_t) +DO_RSHR(gvec_urshr_d, uint64_t) + +#undef DO_RSHR + +#define DO_RSRA(NAME, TYPE) \ +void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \ +{ \ + intptr_t i, oprsz = simd_oprsz(desc); \ + int shift = simd_data(desc); \ + TYPE *d = vd, *n = vn; \ + for (i = 0; i < oprsz / sizeof(TYPE); i++) { \ + TYPE tmp = n[i] >> (shift - 1); \ + d[i] += (tmp >> 1) + (tmp & 1); \ + } \ + clear_tail(d, oprsz, simd_maxsz(desc)); \ +} + +DO_RSRA(gvec_srsra_b, int8_t) +DO_RSRA(gvec_srsra_h, int16_t) +DO_RSRA(gvec_srsra_s, int32_t) +DO_RSRA(gvec_srsra_d, int64_t) + +DO_RSRA(gvec_ursra_b, uint8_t) +DO_RSRA(gvec_ursra_h, uint16_t) +DO_RSRA(gvec_ursra_s, uint32_t) +DO_RSRA(gvec_ursra_d, uint64_t) + +#undef DO_RSRA + /* * Convert float16 to float32, raising no exceptions and * preserving exceptional values, including SNaN. From 893ab0542aa385a287cbe46d5535c8b9e95ce699 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:32 -0700 Subject: [PATCH 0423/2595] target/arm: Create gen_gvec_{sri,sli} The functions eliminate duplication of the special cases for this operation. They match up with the GVecGen2iFn typedef. Add out-of-line helpers. We got away with only having inline expanders because the neon vector size is only 16 bytes, and we know that the inline expansion will always succeed. When we reuse this for SVE, tcg-gvec-op may decide to use an out-of-line helper due to longer vector lengths. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.h | 10 ++ target/arm/translate-a64.c | 20 +--- target/arm/translate.c | 186 +++++++++++++++++++++---------------- target/arm/translate.h | 7 +- target/arm/vec_helper.c | 38 ++++++++ 5 files changed, 160 insertions(+), 101 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index aeb1f52455..33c76192d2 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -721,6 +721,16 @@ DEF_HELPER_FLAGS_3(gvec_ursra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(gvec_ursra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(gvec_ursra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sri_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sri_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sri_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sri_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_sli_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sli_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sli_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sli_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + #ifdef TARGET_AARCH64 #include "helper-a64.h" #include "helper-sve.h" diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 50949d306b..2d7dad6c3f 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -585,16 +585,6 @@ static void gen_gvec_op2(DisasContext *s, bool is_q, int rd, is_q ? 16 : 8, vec_full_reg_size(s), gvec_op); } -/* Expand a 2-operand + immediate AdvSIMD vector operation using - * an op descriptor. - */ -static void gen_gvec_op2i(DisasContext *s, bool is_q, int rd, - int rn, int64_t imm, const GVecGen2i *gvec_op) -{ - tcg_gen_gvec_2i(vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn), - is_q ? 16 : 8, vec_full_reg_size(s), imm, gvec_op); -} - /* Expand a 3-operand AdvSIMD vector operation using an op descriptor. */ static void gen_gvec_op3(DisasContext *s, bool is_q, int rd, int rn, int rm, const GVecGen3 *gvec_op) @@ -10191,12 +10181,9 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, gen_gvec_fn2i(s, is_q, rd, rn, shift, is_u ? gen_gvec_usra : gen_gvec_ssra, size); return; + case 0x08: /* SRI */ - /* Shift count same as element size is valid but does nothing. */ - if (shift == 8 << size) { - goto done; - } - gen_gvec_op2i(s, is_q, rd, rn, shift, &sri_op[size]); + gen_gvec_fn2i(s, is_q, rd, rn, shift, gen_gvec_sri, size); return; case 0x00: /* SSHR / USHR */ @@ -10247,7 +10234,6 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, } tcg_temp_free_i64(tcg_round); - done: clear_vec_high(s, is_q, rd); } @@ -10272,7 +10258,7 @@ static void handle_vec_simd_shli(DisasContext *s, bool is_q, bool insert, } if (insert) { - gen_gvec_op2i(s, is_q, rd, rn, shift, &sli_op[size]); + gen_gvec_fn2i(s, is_q, rd, rn, shift, gen_gvec_sli, size); } else { gen_gvec_fn2i(s, is_q, rd, rn, shift, tcg_gen_gvec_shli, size); } diff --git a/target/arm/translate.c b/target/arm/translate.c index aa03dc236b..3c489852dc 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4454,47 +4454,62 @@ static void gen_shr64_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift) static void gen_shr_ins_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh) { - if (sh == 0) { - tcg_gen_mov_vec(d, a); - } else { - TCGv_vec t = tcg_temp_new_vec_matching(d); - TCGv_vec m = tcg_temp_new_vec_matching(d); + TCGv_vec t = tcg_temp_new_vec_matching(d); + TCGv_vec m = tcg_temp_new_vec_matching(d); - tcg_gen_dupi_vec(vece, m, MAKE_64BIT_MASK((8 << vece) - sh, sh)); - tcg_gen_shri_vec(vece, t, a, sh); - tcg_gen_and_vec(vece, d, d, m); - tcg_gen_or_vec(vece, d, d, t); + tcg_gen_dupi_vec(vece, m, MAKE_64BIT_MASK((8 << vece) - sh, sh)); + tcg_gen_shri_vec(vece, t, a, sh); + tcg_gen_and_vec(vece, d, d, m); + tcg_gen_or_vec(vece, d, d, t); - tcg_temp_free_vec(t); - tcg_temp_free_vec(m); - } + tcg_temp_free_vec(t); + tcg_temp_free_vec(m); } -static const TCGOpcode vecop_list_sri[] = { INDEX_op_shri_vec, 0 }; +void gen_gvec_sri(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { INDEX_op_shri_vec, 0 }; + const GVecGen2i ops[4] = { + { .fni8 = gen_shr8_ins_i64, + .fniv = gen_shr_ins_vec, + .fno = gen_helper_gvec_sri_b, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fni8 = gen_shr16_ins_i64, + .fniv = gen_shr_ins_vec, + .fno = gen_helper_gvec_sri_h, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_shr32_ins_i32, + .fniv = gen_shr_ins_vec, + .fno = gen_helper_gvec_sri_s, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_shr64_ins_i64, + .fniv = gen_shr_ins_vec, + .fno = gen_helper_gvec_sri_d, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; -const GVecGen2i sri_op[4] = { - { .fni8 = gen_shr8_ins_i64, - .fniv = gen_shr_ins_vec, - .load_dest = true, - .opt_opc = vecop_list_sri, - .vece = MO_8 }, - { .fni8 = gen_shr16_ins_i64, - .fniv = gen_shr_ins_vec, - .load_dest = true, - .opt_opc = vecop_list_sri, - .vece = MO_16 }, - { .fni4 = gen_shr32_ins_i32, - .fniv = gen_shr_ins_vec, - .load_dest = true, - .opt_opc = vecop_list_sri, - .vece = MO_32 }, - { .fni8 = gen_shr64_ins_i64, - .fniv = gen_shr_ins_vec, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .load_dest = true, - .opt_opc = vecop_list_sri, - .vece = MO_64 }, -}; + /* tszimm encoding produces immediates in the range [1..esize]. */ + tcg_debug_assert(shift > 0); + tcg_debug_assert(shift <= (8 << vece)); + + /* Shift of esize leaves destination unchanged. */ + if (shift < (8 << vece)) { + tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]); + } else { + /* Nop, but we do need to clear the tail. */ + tcg_gen_gvec_mov(vece, rd_ofs, rd_ofs, opr_sz, max_sz); + } +} static void gen_shl8_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift) { @@ -4532,47 +4547,60 @@ static void gen_shl64_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift) static void gen_shl_ins_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh) { - if (sh == 0) { - tcg_gen_mov_vec(d, a); - } else { - TCGv_vec t = tcg_temp_new_vec_matching(d); - TCGv_vec m = tcg_temp_new_vec_matching(d); + TCGv_vec t = tcg_temp_new_vec_matching(d); + TCGv_vec m = tcg_temp_new_vec_matching(d); - tcg_gen_dupi_vec(vece, m, MAKE_64BIT_MASK(0, sh)); - tcg_gen_shli_vec(vece, t, a, sh); - tcg_gen_and_vec(vece, d, d, m); - tcg_gen_or_vec(vece, d, d, t); + tcg_gen_shli_vec(vece, t, a, sh); + tcg_gen_dupi_vec(vece, m, MAKE_64BIT_MASK(0, sh)); + tcg_gen_and_vec(vece, d, d, m); + tcg_gen_or_vec(vece, d, d, t); - tcg_temp_free_vec(t); - tcg_temp_free_vec(m); - } + tcg_temp_free_vec(t); + tcg_temp_free_vec(m); } -static const TCGOpcode vecop_list_sli[] = { INDEX_op_shli_vec, 0 }; +void gen_gvec_sli(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { INDEX_op_shli_vec, 0 }; + const GVecGen2i ops[4] = { + { .fni8 = gen_shl8_ins_i64, + .fniv = gen_shl_ins_vec, + .fno = gen_helper_gvec_sli_b, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fni8 = gen_shl16_ins_i64, + .fniv = gen_shl_ins_vec, + .fno = gen_helper_gvec_sli_h, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_shl32_ins_i32, + .fniv = gen_shl_ins_vec, + .fno = gen_helper_gvec_sli_s, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_shl64_ins_i64, + .fniv = gen_shl_ins_vec, + .fno = gen_helper_gvec_sli_d, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; -const GVecGen2i sli_op[4] = { - { .fni8 = gen_shl8_ins_i64, - .fniv = gen_shl_ins_vec, - .load_dest = true, - .opt_opc = vecop_list_sli, - .vece = MO_8 }, - { .fni8 = gen_shl16_ins_i64, - .fniv = gen_shl_ins_vec, - .load_dest = true, - .opt_opc = vecop_list_sli, - .vece = MO_16 }, - { .fni4 = gen_shl32_ins_i32, - .fniv = gen_shl_ins_vec, - .load_dest = true, - .opt_opc = vecop_list_sli, - .vece = MO_32 }, - { .fni8 = gen_shl64_ins_i64, - .fniv = gen_shl_ins_vec, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .load_dest = true, - .opt_opc = vecop_list_sli, - .vece = MO_64 }, -}; + /* tszimm encoding produces immediates in the range [0..esize-1]. */ + tcg_debug_assert(shift >= 0); + tcg_debug_assert(shift < (8 << vece)); + + if (shift == 0) { + tcg_gen_gvec_mov(vece, rd_ofs, rm_ofs, opr_sz, max_sz); + } else { + tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]); + } +} static void gen_mla8_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) { @@ -5715,20 +5743,14 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } /* Right shift comes here negative. */ shift = -shift; - /* Shift out of range leaves destination unchanged. */ - if (shift < 8 << size) { - tcg_gen_gvec_2i(rd_ofs, rm_ofs, vec_size, vec_size, - shift, &sri_op[size]); - } + gen_gvec_sri(size, rd_ofs, rm_ofs, shift, + vec_size, vec_size); return 0; case 5: /* VSHL, VSLI */ if (u) { /* VSLI */ - /* Shift out of range leaves destination unchanged. */ - if (shift < 8 << size) { - tcg_gen_gvec_2i(rd_ofs, rm_ofs, vec_size, - vec_size, shift, &sli_op[size]); - } + gen_gvec_sli(size, rd_ofs, rm_ofs, shift, + vec_size, vec_size); } else { /* VSHL */ /* Shifts larger than the element size are * architecturally valid and results in zero. diff --git a/target/arm/translate.h b/target/arm/translate.h index 1db3b43a61..fa5c3f12b9 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -285,8 +285,6 @@ extern const GVecGen3 mls_op[4]; extern const GVecGen3 cmtst_op[4]; extern const GVecGen3 sshl_op[4]; extern const GVecGen3 ushl_op[4]; -extern const GVecGen2i sri_op[4]; -extern const GVecGen2i sli_op[4]; extern const GVecGen4 uqadd_op[4]; extern const GVecGen4 sqadd_op[4]; extern const GVecGen4 uqsub_op[4]; @@ -311,6 +309,11 @@ void gen_gvec_srsra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, void gen_gvec_ursra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, int64_t shift, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_sri(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_sli(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t opr_sz, uint32_t max_sz); + /* * Forward to the isar_feature_* tests given a DisasContext pointer. */ diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index fd8b2bff49..096fea67ef 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -974,6 +974,44 @@ DO_RSRA(gvec_ursra_d, uint64_t) #undef DO_RSRA +#define DO_SRI(NAME, TYPE) \ +void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \ +{ \ + intptr_t i, oprsz = simd_oprsz(desc); \ + int shift = simd_data(desc); \ + TYPE *d = vd, *n = vn; \ + for (i = 0; i < oprsz / sizeof(TYPE); i++) { \ + d[i] = deposit64(d[i], 0, sizeof(TYPE) * 8 - shift, n[i] >> shift); \ + } \ + clear_tail(d, oprsz, simd_maxsz(desc)); \ +} + +DO_SRI(gvec_sri_b, uint8_t) +DO_SRI(gvec_sri_h, uint16_t) +DO_SRI(gvec_sri_s, uint32_t) +DO_SRI(gvec_sri_d, uint64_t) + +#undef DO_SRI + +#define DO_SLI(NAME, TYPE) \ +void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \ +{ \ + intptr_t i, oprsz = simd_oprsz(desc); \ + int shift = simd_data(desc); \ + TYPE *d = vd, *n = vn; \ + for (i = 0; i < oprsz / sizeof(TYPE); i++) { \ + d[i] = deposit64(d[i], shift, sizeof(TYPE) * 8 - shift, n[i]); \ + } \ + clear_tail(d, oprsz, simd_maxsz(desc)); \ +} + +DO_SLI(gvec_sli_b, uint8_t) +DO_SLI(gvec_sli_h, uint16_t) +DO_SLI(gvec_sli_s, uint32_t) +DO_SLI(gvec_sli_d, uint64_t) + +#undef DO_SLI + /* * Convert float16 to float32, raising no exceptions and * preserving exceptional values, including SNaN. From 2f27c5244db300387f15d9ffa5067a204ffd625d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:33 -0700 Subject: [PATCH 0424/2595] target/arm: Remove unnecessary range check for VSHL In 1dc8425e551, while converting to gvec, I added an extra range check against the shift count. This was unnecessary because the encoding of the shift count produces 0 to the element size - 1. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 3c489852dc..2eec689c5e 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5752,16 +5752,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) gen_gvec_sli(size, rd_ofs, rm_ofs, shift, vec_size, vec_size); } else { /* VSHL */ - /* Shifts larger than the element size are - * architecturally valid and results in zero. - */ - if (shift >= 8 << size) { - tcg_gen_gvec_dup_imm(size, rd_ofs, - vec_size, vec_size, 0); - } else { - tcg_gen_gvec_shli(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } + tcg_gen_gvec_shli(size, rd_ofs, rm_ofs, shift, + vec_size, vec_size); } return 0; } From 3f08f0bce841e7857ec98ce7909629d0c335005e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:34 -0700 Subject: [PATCH 0425/2595] target/arm: Tidy handle_vec_simd_shri Now that we've converted all cases to gvec, there is quite a bit of dead code at the end of the function. Remove it. Sink the call to gen_gvec_fn2i to the end, loading a function pointer within the switch statement. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 56 ++++++++++---------------------------- 1 file changed, 14 insertions(+), 42 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 2d7dad6c3f..d5e77f34a7 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -10155,16 +10155,7 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, int size = 32 - clz32(immh) - 1; int immhb = immh << 3 | immb; int shift = 2 * (8 << size) - immhb; - bool accumulate = false; - int dsize = is_q ? 128 : 64; - int esize = 8 << size; - int elements = dsize/esize; - MemOp memop = size | (is_u ? 0 : MO_SIGN); - TCGv_i64 tcg_rn = new_tmp_a64(s); - TCGv_i64 tcg_rd = new_tmp_a64(s); - TCGv_i64 tcg_round; - uint64_t round_const; - int i; + GVecGen2iFn *gvec_fn; if (extract32(immh, 3, 1) && !is_q) { unallocated_encoding(s); @@ -10178,13 +10169,12 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, switch (opcode) { case 0x02: /* SSRA / USRA (accumulate) */ - gen_gvec_fn2i(s, is_q, rd, rn, shift, - is_u ? gen_gvec_usra : gen_gvec_ssra, size); - return; + gvec_fn = is_u ? gen_gvec_usra : gen_gvec_ssra; + break; case 0x08: /* SRI */ - gen_gvec_fn2i(s, is_q, rd, rn, shift, gen_gvec_sri, size); - return; + gvec_fn = gen_gvec_sri; + break; case 0x00: /* SSHR / USHR */ if (is_u) { @@ -10192,49 +10182,31 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, /* Shift count the same size as element size produces zero. */ tcg_gen_gvec_dup_imm(size, vec_full_reg_offset(s, rd), is_q ? 16 : 8, vec_full_reg_size(s), 0); - } else { - gen_gvec_fn2i(s, is_q, rd, rn, shift, tcg_gen_gvec_shri, size); + return; } + gvec_fn = tcg_gen_gvec_shri; } else { /* Shift count the same size as element size produces all sign. */ if (shift == 8 << size) { shift -= 1; } - gen_gvec_fn2i(s, is_q, rd, rn, shift, tcg_gen_gvec_sari, size); + gvec_fn = tcg_gen_gvec_sari; } - return; + break; case 0x04: /* SRSHR / URSHR (rounding) */ - gen_gvec_fn2i(s, is_q, rd, rn, shift, - is_u ? gen_gvec_urshr : gen_gvec_srshr, size); - return; + gvec_fn = is_u ? gen_gvec_urshr : gen_gvec_srshr; + break; case 0x06: /* SRSRA / URSRA (accum + rounding) */ - gen_gvec_fn2i(s, is_q, rd, rn, shift, - is_u ? gen_gvec_ursra : gen_gvec_srsra, size); - return; + gvec_fn = is_u ? gen_gvec_ursra : gen_gvec_srsra; + break; default: g_assert_not_reached(); } - round_const = 1ULL << (shift - 1); - tcg_round = tcg_const_i64(round_const); - - for (i = 0; i < elements; i++) { - read_vec_element(s, tcg_rn, rn, i, memop); - if (accumulate) { - read_vec_element(s, tcg_rd, rd, i, memop); - } - - handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round, - accumulate, is_u, size, shift); - - write_vec_element(s, tcg_rd, rd, i, size); - } - tcg_temp_free_i64(tcg_round); - - clear_vec_high(s, is_q, rd); + gen_gvec_fn2i(s, is_q, rd, rn, shift, gvec_fn, size); } /* SHL/SLI - Vector shift left */ From 69d5e2bf8c3cefedbfa1c1670137e636dbd7faa5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:35 -0700 Subject: [PATCH 0426/2595] target/arm: Create gen_gvec_{ceq,clt,cle,cgt,cge}0 Provide a functional interface for the vector expansion. This fits better with the existing set of helpers that we provide for other operations. Macro-ize the 5 nearly identical comparisons. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 22 ++-- target/arm/translate.c | 254 ++++++++----------------------------- target/arm/translate.h | 16 ++- 3 files changed, 74 insertions(+), 218 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index d5e77f34a7..fef93dc27a 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -577,14 +577,6 @@ static void gen_gvec_fn4(DisasContext *s, bool is_q, int rd, int rn, int rm, is_q ? 16 : 8, vec_full_reg_size(s)); } -/* Expand a 2-operand AdvSIMD vector operation using an op descriptor. */ -static void gen_gvec_op2(DisasContext *s, bool is_q, int rd, - int rn, const GVecGen2 *gvec_op) -{ - tcg_gen_gvec_2(vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn), - is_q ? 16 : 8, vec_full_reg_size(s), gvec_op); -} - /* Expand a 3-operand AdvSIMD vector operation using an op descriptor. */ static void gen_gvec_op3(DisasContext *s, bool is_q, int rd, int rn, int rm, const GVecGen3 *gvec_op) @@ -12310,13 +12302,21 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) } break; case 0x8: /* CMGT, CMGE */ - gen_gvec_op2(s, is_q, rd, rn, u ? &cge0_op[size] : &cgt0_op[size]); + if (u) { + gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cge0, size); + } else { + gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cgt0, size); + } return; case 0x9: /* CMEQ, CMLE */ - gen_gvec_op2(s, is_q, rd, rn, u ? &cle0_op[size] : &ceq0_op[size]); + if (u) { + gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cle0, size); + } else { + gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_ceq0, size); + } return; case 0xa: /* CMLT */ - gen_gvec_op2(s, is_q, rd, rn, &clt0_op[size]); + gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_clt0, size); return; case 0xb: if (u) { /* ABS, NEG */ diff --git a/target/arm/translate.c b/target/arm/translate.c index 2eec689c5e..010a158e63 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3645,204 +3645,59 @@ static int do_v81_helper(DisasContext *s, gen_helper_gvec_3_ptr *fn, return 1; } -static void gen_ceq0_i32(TCGv_i32 d, TCGv_i32 a) -{ - tcg_gen_setcondi_i32(TCG_COND_EQ, d, a, 0); - tcg_gen_neg_i32(d, d); -} - -static void gen_ceq0_i64(TCGv_i64 d, TCGv_i64 a) -{ - tcg_gen_setcondi_i64(TCG_COND_EQ, d, a, 0); - tcg_gen_neg_i64(d, d); -} - -static void gen_ceq0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) -{ - TCGv_vec zero = tcg_const_zeros_vec_matching(d); - tcg_gen_cmp_vec(TCG_COND_EQ, vece, d, a, zero); - tcg_temp_free_vec(zero); -} +#define GEN_CMP0(NAME, COND) \ + static void gen_##NAME##0_i32(TCGv_i32 d, TCGv_i32 a) \ + { \ + tcg_gen_setcondi_i32(COND, d, a, 0); \ + tcg_gen_neg_i32(d, d); \ + } \ + static void gen_##NAME##0_i64(TCGv_i64 d, TCGv_i64 a) \ + { \ + tcg_gen_setcondi_i64(COND, d, a, 0); \ + tcg_gen_neg_i64(d, d); \ + } \ + static void gen_##NAME##0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) \ + { \ + TCGv_vec zero = tcg_const_zeros_vec_matching(d); \ + tcg_gen_cmp_vec(COND, vece, d, a, zero); \ + tcg_temp_free_vec(zero); \ + } \ + void gen_gvec_##NAME##0(unsigned vece, uint32_t d, uint32_t m, \ + uint32_t opr_sz, uint32_t max_sz) \ + { \ + const GVecGen2 op[4] = { \ + { .fno = gen_helper_gvec_##NAME##0_b, \ + .fniv = gen_##NAME##0_vec, \ + .opt_opc = vecop_list_cmp, \ + .vece = MO_8 }, \ + { .fno = gen_helper_gvec_##NAME##0_h, \ + .fniv = gen_##NAME##0_vec, \ + .opt_opc = vecop_list_cmp, \ + .vece = MO_16 }, \ + { .fni4 = gen_##NAME##0_i32, \ + .fniv = gen_##NAME##0_vec, \ + .opt_opc = vecop_list_cmp, \ + .vece = MO_32 }, \ + { .fni8 = gen_##NAME##0_i64, \ + .fniv = gen_##NAME##0_vec, \ + .opt_opc = vecop_list_cmp, \ + .prefer_i64 = TCG_TARGET_REG_BITS == 64, \ + .vece = MO_64 }, \ + }; \ + tcg_gen_gvec_2(d, m, opr_sz, max_sz, &op[vece]); \ + } static const TCGOpcode vecop_list_cmp[] = { INDEX_op_cmp_vec, 0 }; -const GVecGen2 ceq0_op[4] = { - { .fno = gen_helper_gvec_ceq0_b, - .fniv = gen_ceq0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_8 }, - { .fno = gen_helper_gvec_ceq0_h, - .fniv = gen_ceq0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_16 }, - { .fni4 = gen_ceq0_i32, - .fniv = gen_ceq0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_32 }, - { .fni8 = gen_ceq0_i64, - .fniv = gen_ceq0_vec, - .opt_opc = vecop_list_cmp, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .vece = MO_64 }, -}; +GEN_CMP0(ceq, TCG_COND_EQ) +GEN_CMP0(cle, TCG_COND_LE) +GEN_CMP0(cge, TCG_COND_GE) +GEN_CMP0(clt, TCG_COND_LT) +GEN_CMP0(cgt, TCG_COND_GT) -static void gen_cle0_i32(TCGv_i32 d, TCGv_i32 a) -{ - tcg_gen_setcondi_i32(TCG_COND_LE, d, a, 0); - tcg_gen_neg_i32(d, d); -} - -static void gen_cle0_i64(TCGv_i64 d, TCGv_i64 a) -{ - tcg_gen_setcondi_i64(TCG_COND_LE, d, a, 0); - tcg_gen_neg_i64(d, d); -} - -static void gen_cle0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) -{ - TCGv_vec zero = tcg_const_zeros_vec_matching(d); - tcg_gen_cmp_vec(TCG_COND_LE, vece, d, a, zero); - tcg_temp_free_vec(zero); -} - -const GVecGen2 cle0_op[4] = { - { .fno = gen_helper_gvec_cle0_b, - .fniv = gen_cle0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_8 }, - { .fno = gen_helper_gvec_cle0_h, - .fniv = gen_cle0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_16 }, - { .fni4 = gen_cle0_i32, - .fniv = gen_cle0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_32 }, - { .fni8 = gen_cle0_i64, - .fniv = gen_cle0_vec, - .opt_opc = vecop_list_cmp, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .vece = MO_64 }, -}; - -static void gen_cge0_i32(TCGv_i32 d, TCGv_i32 a) -{ - tcg_gen_setcondi_i32(TCG_COND_GE, d, a, 0); - tcg_gen_neg_i32(d, d); -} - -static void gen_cge0_i64(TCGv_i64 d, TCGv_i64 a) -{ - tcg_gen_setcondi_i64(TCG_COND_GE, d, a, 0); - tcg_gen_neg_i64(d, d); -} - -static void gen_cge0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) -{ - TCGv_vec zero = tcg_const_zeros_vec_matching(d); - tcg_gen_cmp_vec(TCG_COND_GE, vece, d, a, zero); - tcg_temp_free_vec(zero); -} - -const GVecGen2 cge0_op[4] = { - { .fno = gen_helper_gvec_cge0_b, - .fniv = gen_cge0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_8 }, - { .fno = gen_helper_gvec_cge0_h, - .fniv = gen_cge0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_16 }, - { .fni4 = gen_cge0_i32, - .fniv = gen_cge0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_32 }, - { .fni8 = gen_cge0_i64, - .fniv = gen_cge0_vec, - .opt_opc = vecop_list_cmp, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .vece = MO_64 }, -}; - -static void gen_clt0_i32(TCGv_i32 d, TCGv_i32 a) -{ - tcg_gen_setcondi_i32(TCG_COND_LT, d, a, 0); - tcg_gen_neg_i32(d, d); -} - -static void gen_clt0_i64(TCGv_i64 d, TCGv_i64 a) -{ - tcg_gen_setcondi_i64(TCG_COND_LT, d, a, 0); - tcg_gen_neg_i64(d, d); -} - -static void gen_clt0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) -{ - TCGv_vec zero = tcg_const_zeros_vec_matching(d); - tcg_gen_cmp_vec(TCG_COND_LT, vece, d, a, zero); - tcg_temp_free_vec(zero); -} - -const GVecGen2 clt0_op[4] = { - { .fno = gen_helper_gvec_clt0_b, - .fniv = gen_clt0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_8 }, - { .fno = gen_helper_gvec_clt0_h, - .fniv = gen_clt0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_16 }, - { .fni4 = gen_clt0_i32, - .fniv = gen_clt0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_32 }, - { .fni8 = gen_clt0_i64, - .fniv = gen_clt0_vec, - .opt_opc = vecop_list_cmp, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .vece = MO_64 }, -}; - -static void gen_cgt0_i32(TCGv_i32 d, TCGv_i32 a) -{ - tcg_gen_setcondi_i32(TCG_COND_GT, d, a, 0); - tcg_gen_neg_i32(d, d); -} - -static void gen_cgt0_i64(TCGv_i64 d, TCGv_i64 a) -{ - tcg_gen_setcondi_i64(TCG_COND_GT, d, a, 0); - tcg_gen_neg_i64(d, d); -} - -static void gen_cgt0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) -{ - TCGv_vec zero = tcg_const_zeros_vec_matching(d); - tcg_gen_cmp_vec(TCG_COND_GT, vece, d, a, zero); - tcg_temp_free_vec(zero); -} - -const GVecGen2 cgt0_op[4] = { - { .fno = gen_helper_gvec_cgt0_b, - .fniv = gen_cgt0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_8 }, - { .fno = gen_helper_gvec_cgt0_h, - .fniv = gen_cgt0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_16 }, - { .fni4 = gen_cgt0_i32, - .fniv = gen_cgt0_vec, - .opt_opc = vecop_list_cmp, - .vece = MO_32 }, - { .fni8 = gen_cgt0_i64, - .fniv = gen_cgt0_vec, - .opt_opc = vecop_list_cmp, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .vece = MO_64 }, -}; +#undef GEN_CMP0 static void gen_ssra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift) { @@ -6772,24 +6627,19 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) break; case NEON_2RM_VCEQ0: - tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size, - vec_size, &ceq0_op[size]); + gen_gvec_ceq0(size, rd_ofs, rm_ofs, vec_size, vec_size); break; case NEON_2RM_VCGT0: - tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size, - vec_size, &cgt0_op[size]); + gen_gvec_cgt0(size, rd_ofs, rm_ofs, vec_size, vec_size); break; case NEON_2RM_VCLE0: - tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size, - vec_size, &cle0_op[size]); + gen_gvec_cle0(size, rd_ofs, rm_ofs, vec_size, vec_size); break; case NEON_2RM_VCGE0: - tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size, - vec_size, &cge0_op[size]); + gen_gvec_cge0(size, rd_ofs, rm_ofs, vec_size, vec_size); break; case NEON_2RM_VCLT0: - tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size, - vec_size, &clt0_op[size]); + gen_gvec_clt0(size, rd_ofs, rm_ofs, vec_size, vec_size); break; default: diff --git a/target/arm/translate.h b/target/arm/translate.h index fa5c3f12b9..e35c812cc5 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -275,11 +275,17 @@ static inline void gen_swstep_exception(DisasContext *s, int isv, int ex) uint64_t vfp_expand_imm(int size, uint8_t imm8); /* Vector operations shared between ARM and AArch64. */ -extern const GVecGen2 ceq0_op[4]; -extern const GVecGen2 clt0_op[4]; -extern const GVecGen2 cgt0_op[4]; -extern const GVecGen2 cle0_op[4]; -extern const GVecGen2 cge0_op[4]; +void gen_gvec_ceq0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_clt0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_cgt0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_cle0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_cge0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + uint32_t opr_sz, uint32_t max_sz); + extern const GVecGen3 mla_op[4]; extern const GVecGen3 mls_op[4]; extern const GVecGen3 cmtst_op[4]; From 271063206a46062a45fc6bab8dabe45f0b88159d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:36 -0700 Subject: [PATCH 0427/2595] target/arm: Create gen_gvec_{mla,mls} Provide a functional interface for the vector expansion. This fits better with the existing set of helpers that we provide for other operations. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 4 +- target/arm/translate-neon.inc.c | 16 +---- target/arm/translate.c | 117 +++++++++++++++++--------------- target/arm/translate.h | 7 +- 4 files changed, 71 insertions(+), 73 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index fef93dc27a..ab9df12e44 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -11226,9 +11226,9 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) return; case 0x12: /* MLA, MLS */ if (u) { - gen_gvec_op3(s, is_q, rd, rn, rm, &mls_op[size]); + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_mls, size); } else { - gen_gvec_op3(s, is_q, rd, rn, rm, &mla_op[size]); + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_mla, size); } return; case 0x11: diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 50b77b6d71..aefeff498a 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -632,6 +632,8 @@ DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) +DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla) +DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls) #define DO_3SAME_CMP(INSN, COND) \ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ @@ -685,20 +687,6 @@ static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) return do_3same(s, a, gen_VMUL_p_3s); } -#define DO_3SAME_GVEC3_NO_SZ_3(INSN, OPARRAY) \ - static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ - uint32_t rn_ofs, uint32_t rm_ofs, \ - uint32_t oprsz, uint32_t maxsz) \ - { \ - tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, \ - oprsz, maxsz, &OPARRAY[vece]); \ - } \ - DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s) - - -DO_3SAME_GVEC3_NO_SZ_3(VMLA, mla_op) -DO_3SAME_GVEC3_NO_SZ_3(VMLS, mls_op) - #define DO_3SAME_GVEC3_SHIFT(INSN, OPARRAY) \ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ uint32_t rn_ofs, uint32_t rm_ofs, \ diff --git a/target/arm/translate.c b/target/arm/translate.c index 010a158e63..face89a1f7 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4520,62 +4520,69 @@ static void gen_mls_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b) /* Note that while NEON does not support VMLA and VMLS as 64-bit ops, * these tables are shared with AArch64 which does support them. */ +void gen_gvec_mla(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_mul_vec, INDEX_op_add_vec, 0 + }; + static const GVecGen3 ops[4] = { + { .fni4 = gen_mla8_i32, + .fniv = gen_mla_vec, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fni4 = gen_mla16_i32, + .fniv = gen_mla_vec, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_mla32_i32, + .fniv = gen_mla_vec, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_mla64_i64, + .fniv = gen_mla_vec, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} -static const TCGOpcode vecop_list_mla[] = { - INDEX_op_mul_vec, INDEX_op_add_vec, 0 -}; - -static const TCGOpcode vecop_list_mls[] = { - INDEX_op_mul_vec, INDEX_op_sub_vec, 0 -}; - -const GVecGen3 mla_op[4] = { - { .fni4 = gen_mla8_i32, - .fniv = gen_mla_vec, - .load_dest = true, - .opt_opc = vecop_list_mla, - .vece = MO_8 }, - { .fni4 = gen_mla16_i32, - .fniv = gen_mla_vec, - .load_dest = true, - .opt_opc = vecop_list_mla, - .vece = MO_16 }, - { .fni4 = gen_mla32_i32, - .fniv = gen_mla_vec, - .load_dest = true, - .opt_opc = vecop_list_mla, - .vece = MO_32 }, - { .fni8 = gen_mla64_i64, - .fniv = gen_mla_vec, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .load_dest = true, - .opt_opc = vecop_list_mla, - .vece = MO_64 }, -}; - -const GVecGen3 mls_op[4] = { - { .fni4 = gen_mls8_i32, - .fniv = gen_mls_vec, - .load_dest = true, - .opt_opc = vecop_list_mls, - .vece = MO_8 }, - { .fni4 = gen_mls16_i32, - .fniv = gen_mls_vec, - .load_dest = true, - .opt_opc = vecop_list_mls, - .vece = MO_16 }, - { .fni4 = gen_mls32_i32, - .fniv = gen_mls_vec, - .load_dest = true, - .opt_opc = vecop_list_mls, - .vece = MO_32 }, - { .fni8 = gen_mls64_i64, - .fniv = gen_mls_vec, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .load_dest = true, - .opt_opc = vecop_list_mls, - .vece = MO_64 }, -}; +void gen_gvec_mls(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_mul_vec, INDEX_op_sub_vec, 0 + }; + static const GVecGen3 ops[4] = { + { .fni4 = gen_mls8_i32, + .fniv = gen_mls_vec, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fni4 = gen_mls16_i32, + .fniv = gen_mls_vec, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_mls32_i32, + .fniv = gen_mls_vec, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_mls64_i64, + .fniv = gen_mls_vec, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .load_dest = true, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} /* CMTST : test is "if (X & Y != 0)". */ static void gen_cmtst_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) diff --git a/target/arm/translate.h b/target/arm/translate.h index e35c812cc5..9354ceba35 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -286,8 +286,11 @@ void gen_gvec_cle0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, void gen_gvec_cge0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); -extern const GVecGen3 mla_op[4]; -extern const GVecGen3 mls_op[4]; +void gen_gvec_mla(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_mls(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); + extern const GVecGen3 cmtst_op[4]; extern const GVecGen3 sshl_op[4]; extern const GVecGen3 ushl_op[4]; From e9eee5316ffec5f37643de806b2e5577c5c189cf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:37 -0700 Subject: [PATCH 0428/2595] target/arm: Swap argument order for VSHL during decode Rather than perform the argument swap during code generation, perform it during decode. This means it doesn't have to be special cased later, and we can share code with aarch64 code generation. Hopefully the decode comment addresses any confusion that might arise in between. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/neon-dp.decode | 17 +++++++++++++++-- target/arm/translate-neon.inc.c | 3 +-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index ec3a92fe75..593f7fff03 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -65,8 +65,21 @@ VCGT_U_3s 1111 001 1 0 . .. .... .... 0011 . . . 0 .... @3same VCGE_S_3s 1111 001 0 0 . .. .... .... 0011 . . . 1 .... @3same VCGE_U_3s 1111 001 1 0 . .. .... .... 0011 . . . 1 .... @3same -VSHL_S_3s 1111 001 0 0 . .. .... .... 0100 . . . 0 .... @3same -VSHL_U_3s 1111 001 1 0 . .. .... .... 0100 . . . 0 .... @3same +# The _rev suffix indicates that Vn and Vm are reversed. This is +# the case for shifts. In the Arm ARM these insns are documented +# with the Vm and Vn fields in their usual places, but in the +# assembly the operands are listed "backwards", ie in the order +# Dd, Dm, Dn where other insns use Dd, Dn, Dm. For QEMU we choose +# to consider Vm and Vn as being in different fields in the insn, +# which allows us to avoid special-casing shifts in the trans_ +# function code. We would otherwise need to manually swap the operands +# over to call Neon helper functions that are shared with AArch64, +# which does not have this odd reversed-operand situation. +@3same_rev .... ... . . . size:2 .... .... .... . q:1 . . .... \ + &3same vn=%vm_dp vm=%vn_dp vd=%vd_dp + +VSHL_S_3s 1111 001 0 0 . .. .... .... 0100 . . . 0 .... @3same_rev +VSHL_U_3s 1111 001 1 0 . .. .... .... 0100 . . . 0 .... @3same_rev VMAX_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 0 .... @3same VMAX_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 0 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index aefeff498a..416302bcc7 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -692,8 +692,7 @@ static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) uint32_t rn_ofs, uint32_t rm_ofs, \ uint32_t oprsz, uint32_t maxsz) \ { \ - /* Note the operation is vshl vd,vm,vn */ \ - tcg_gen_gvec_3(rd_ofs, rm_ofs, rn_ofs, \ + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, \ oprsz, maxsz, &OPARRAY[vece]); \ } \ DO_3SAME(INSN, gen_##INSN##_3s) From 8161b75357095fef54c76b1a6ed1e54d0e8655e0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:38 -0700 Subject: [PATCH 0429/2595] target/arm: Create gen_gvec_{cmtst,ushl,sshl} Provide a functional interface for the vector expansion. This fits better with the existing set of helpers that we provide for other operations. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 18 ++-- target/arm/translate-neon.inc.c | 23 +---- target/arm/translate.c | 146 +++++++++++++++++--------------- target/arm/translate.h | 10 ++- 4 files changed, 95 insertions(+), 102 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index ab9df12e44..3956c19ed8 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -577,15 +577,6 @@ static void gen_gvec_fn4(DisasContext *s, bool is_q, int rd, int rn, int rm, is_q ? 16 : 8, vec_full_reg_size(s)); } -/* Expand a 3-operand AdvSIMD vector operation using an op descriptor. */ -static void gen_gvec_op3(DisasContext *s, bool is_q, int rd, - int rn, int rm, const GVecGen3 *gvec_op) -{ - tcg_gen_gvec_3(vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), is_q ? 16 : 8, - vec_full_reg_size(s), gvec_op); -} - /* Expand a 3-operand operation using an out-of-line helper. */ static void gen_gvec_op3_ool(DisasContext *s, bool is_q, int rd, int rn, int rm, int data, gen_helper_gvec_3 *fn) @@ -11193,8 +11184,11 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) (u ? uqsub_op : sqsub_op) + size); return; case 0x08: /* SSHL, USHL */ - gen_gvec_op3(s, is_q, rd, rn, rm, - u ? &ushl_op[size] : &sshl_op[size]); + if (u) { + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_ushl, size); + } else { + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sshl, size); + } return; case 0x0c: /* SMAX, UMAX */ if (u) { @@ -11233,7 +11227,7 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) return; case 0x11: if (!u) { /* CMTST */ - gen_gvec_op3(s, is_q, rd, rn, rm, &cmtst_op[size]); + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_cmtst, size); return; } /* else CMEQ */ diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 416302bcc7..e16475c212 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -603,6 +603,8 @@ DO_3SAME(VBIC, tcg_gen_gvec_andc) DO_3SAME(VORR, tcg_gen_gvec_or) DO_3SAME(VORN, tcg_gen_gvec_orc) DO_3SAME(VEOR, tcg_gen_gvec_xor) +DO_3SAME(VSHL_S, gen_gvec_sshl) +DO_3SAME(VSHL_U, gen_gvec_ushl) /* These insns are all gvec_bitsel but with the inputs in various orders. */ #define DO_3SAME_BITSEL(INSN, O1, O2, O3) \ @@ -634,6 +636,7 @@ DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla) DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls) +DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst) #define DO_3SAME_CMP(INSN, COND) \ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ @@ -650,13 +653,6 @@ DO_3SAME_CMP(VCGE_S, TCG_COND_GE) DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) DO_3SAME_CMP(VCEQ, TCG_COND_EQ) -static void gen_VTST_3s(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, - uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) -{ - tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &cmtst_op[vece]); -} -DO_3SAME_NO_SZ_3(VTST, gen_VTST_3s) - #define DO_3SAME_GVEC4(INSN, OPARRAY) \ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ uint32_t rn_ofs, uint32_t rm_ofs, \ @@ -686,16 +682,3 @@ static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) } return do_3same(s, a, gen_VMUL_p_3s); } - -#define DO_3SAME_GVEC3_SHIFT(INSN, OPARRAY) \ - static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ - uint32_t rn_ofs, uint32_t rm_ofs, \ - uint32_t oprsz, uint32_t maxsz) \ - { \ - tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, \ - oprsz, maxsz, &OPARRAY[vece]); \ - } \ - DO_3SAME(INSN, gen_##INSN##_3s) - -DO_3SAME_GVEC3_SHIFT(VSHL_S, sshl_op) -DO_3SAME_GVEC3_SHIFT(VSHL_U, ushl_op) diff --git a/target/arm/translate.c b/target/arm/translate.c index face89a1f7..df91ff73e3 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4606,27 +4606,31 @@ static void gen_cmtst_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b) tcg_gen_cmp_vec(TCG_COND_NE, vece, d, d, a); } -static const TCGOpcode vecop_list_cmtst[] = { INDEX_op_cmp_vec, 0 }; - -const GVecGen3 cmtst_op[4] = { - { .fni4 = gen_helper_neon_tst_u8, - .fniv = gen_cmtst_vec, - .opt_opc = vecop_list_cmtst, - .vece = MO_8 }, - { .fni4 = gen_helper_neon_tst_u16, - .fniv = gen_cmtst_vec, - .opt_opc = vecop_list_cmtst, - .vece = MO_16 }, - { .fni4 = gen_cmtst_i32, - .fniv = gen_cmtst_vec, - .opt_opc = vecop_list_cmtst, - .vece = MO_32 }, - { .fni8 = gen_cmtst_i64, - .fniv = gen_cmtst_vec, - .prefer_i64 = TCG_TARGET_REG_BITS == 64, - .opt_opc = vecop_list_cmtst, - .vece = MO_64 }, -}; +void gen_gvec_cmtst(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { INDEX_op_cmp_vec, 0 }; + static const GVecGen3 ops[4] = { + { .fni4 = gen_helper_neon_tst_u8, + .fniv = gen_cmtst_vec, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fni4 = gen_helper_neon_tst_u16, + .fniv = gen_cmtst_vec, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_cmtst_i32, + .fniv = gen_cmtst_vec, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_cmtst_i64, + .fniv = gen_cmtst_vec, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} void gen_ushl_i32(TCGv_i32 dst, TCGv_i32 src, TCGv_i32 shift) { @@ -4744,29 +4748,33 @@ static void gen_ushl_vec(unsigned vece, TCGv_vec dst, tcg_temp_free_vec(rsh); } -static const TCGOpcode ushl_list[] = { - INDEX_op_neg_vec, INDEX_op_shlv_vec, - INDEX_op_shrv_vec, INDEX_op_cmp_vec, 0 -}; - -const GVecGen3 ushl_op[4] = { - { .fniv = gen_ushl_vec, - .fno = gen_helper_gvec_ushl_b, - .opt_opc = ushl_list, - .vece = MO_8 }, - { .fniv = gen_ushl_vec, - .fno = gen_helper_gvec_ushl_h, - .opt_opc = ushl_list, - .vece = MO_16 }, - { .fni4 = gen_ushl_i32, - .fniv = gen_ushl_vec, - .opt_opc = ushl_list, - .vece = MO_32 }, - { .fni8 = gen_ushl_i64, - .fniv = gen_ushl_vec, - .opt_opc = ushl_list, - .vece = MO_64 }, -}; +void gen_gvec_ushl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_neg_vec, INDEX_op_shlv_vec, + INDEX_op_shrv_vec, INDEX_op_cmp_vec, 0 + }; + static const GVecGen3 ops[4] = { + { .fniv = gen_ushl_vec, + .fno = gen_helper_gvec_ushl_b, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fniv = gen_ushl_vec, + .fno = gen_helper_gvec_ushl_h, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_ushl_i32, + .fniv = gen_ushl_vec, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_ushl_i64, + .fniv = gen_ushl_vec, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} void gen_sshl_i32(TCGv_i32 dst, TCGv_i32 src, TCGv_i32 shift) { @@ -4878,29 +4886,33 @@ static void gen_sshl_vec(unsigned vece, TCGv_vec dst, tcg_temp_free_vec(tmp); } -static const TCGOpcode sshl_list[] = { - INDEX_op_neg_vec, INDEX_op_umin_vec, INDEX_op_shlv_vec, - INDEX_op_sarv_vec, INDEX_op_cmp_vec, INDEX_op_cmpsel_vec, 0 -}; - -const GVecGen3 sshl_op[4] = { - { .fniv = gen_sshl_vec, - .fno = gen_helper_gvec_sshl_b, - .opt_opc = sshl_list, - .vece = MO_8 }, - { .fniv = gen_sshl_vec, - .fno = gen_helper_gvec_sshl_h, - .opt_opc = sshl_list, - .vece = MO_16 }, - { .fni4 = gen_sshl_i32, - .fniv = gen_sshl_vec, - .opt_opc = sshl_list, - .vece = MO_32 }, - { .fni8 = gen_sshl_i64, - .fniv = gen_sshl_vec, - .opt_opc = sshl_list, - .vece = MO_64 }, -}; +void gen_gvec_sshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_neg_vec, INDEX_op_umin_vec, INDEX_op_shlv_vec, + INDEX_op_sarv_vec, INDEX_op_cmp_vec, INDEX_op_cmpsel_vec, 0 + }; + static const GVecGen3 ops[4] = { + { .fniv = gen_sshl_vec, + .fno = gen_helper_gvec_sshl_b, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fniv = gen_sshl_vec, + .fno = gen_helper_gvec_sshl_h, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_sshl_i32, + .fniv = gen_sshl_vec, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_sshl_i64, + .fniv = gen_sshl_vec, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} static void gen_uqadd_vec(unsigned vece, TCGv_vec t, TCGv_vec sat, TCGv_vec a, TCGv_vec b) diff --git a/target/arm/translate.h b/target/arm/translate.h index 9354ceba35..a02a54cabf 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -291,9 +291,13 @@ void gen_gvec_mla(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, void gen_gvec_mls(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); -extern const GVecGen3 cmtst_op[4]; -extern const GVecGen3 sshl_op[4]; -extern const GVecGen3 ushl_op[4]; +void gen_gvec_cmtst(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_sshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_ushl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); + extern const GVecGen4 uqadd_op[4]; extern const GVecGen4 sqadd_op[4]; extern const GVecGen4 uqsub_op[4]; From c7715b6b51a6f7a5412c5fcb40a4c8586105e597 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:39 -0700 Subject: [PATCH 0430/2595] target/arm: Create gen_gvec_{uqadd, sqadd, uqsub, sqsub} Provide a functional interface for the vector expansion. This fits better with the existing set of helpers that we provide for other operations. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 22 ++- target/arm/translate-neon.inc.c | 19 +-- target/arm/translate.c | 228 +++++++++++++++++--------------- target/arm/translate.h | 13 +- 4 files changed, 147 insertions(+), 135 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 3956c19ed8..ea5f6ceadc 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -11168,20 +11168,18 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) switch (opcode) { case 0x01: /* SQADD, UQADD */ - tcg_gen_gvec_4(vec_full_reg_offset(s, rd), - offsetof(CPUARMState, vfp.qc), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - is_q ? 16 : 8, vec_full_reg_size(s), - (u ? uqadd_op : sqadd_op) + size); + if (u) { + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_uqadd_qc, size); + } else { + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sqadd_qc, size); + } return; case 0x05: /* SQSUB, UQSUB */ - tcg_gen_gvec_4(vec_full_reg_offset(s, rd), - offsetof(CPUARMState, vfp.qc), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), - is_q ? 16 : 8, vec_full_reg_size(s), - (u ? uqsub_op : sqsub_op) + size); + if (u) { + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_uqsub_qc, size); + } else { + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sqsub_qc, size); + } return; case 0x08: /* SSHL, USHL */ if (u) { diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index e16475c212..099491b16f 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -605,6 +605,10 @@ DO_3SAME(VORN, tcg_gen_gvec_orc) DO_3SAME(VEOR, tcg_gen_gvec_xor) DO_3SAME(VSHL_S, gen_gvec_sshl) DO_3SAME(VSHL_U, gen_gvec_ushl) +DO_3SAME(VQADD_S, gen_gvec_sqadd_qc) +DO_3SAME(VQADD_U, gen_gvec_uqadd_qc) +DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc) +DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc) /* These insns are all gvec_bitsel but with the inputs in various orders. */ #define DO_3SAME_BITSEL(INSN, O1, O2, O3) \ @@ -653,21 +657,6 @@ DO_3SAME_CMP(VCGE_S, TCG_COND_GE) DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) DO_3SAME_CMP(VCEQ, TCG_COND_EQ) -#define DO_3SAME_GVEC4(INSN, OPARRAY) \ - static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ - uint32_t rn_ofs, uint32_t rm_ofs, \ - uint32_t oprsz, uint32_t maxsz) \ - { \ - tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), \ - rn_ofs, rm_ofs, oprsz, maxsz, &OPARRAY[vece]); \ - } \ - DO_3SAME(INSN, gen_##INSN##_3s) - -DO_3SAME_GVEC4(VQADD_S, sqadd_op) -DO_3SAME_GVEC4(VQADD_U, uqadd_op) -DO_3SAME_GVEC4(VQSUB_S, sqsub_op) -DO_3SAME_GVEC4(VQSUB_U, uqsub_op) - static void gen_VMUL_p_3s(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) { diff --git a/target/arm/translate.c b/target/arm/translate.c index df91ff73e3..7eb30cde60 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4925,32 +4925,37 @@ static void gen_uqadd_vec(unsigned vece, TCGv_vec t, TCGv_vec sat, tcg_temp_free_vec(x); } -static const TCGOpcode vecop_list_uqadd[] = { - INDEX_op_usadd_vec, INDEX_op_cmp_vec, INDEX_op_add_vec, 0 -}; - -const GVecGen4 uqadd_op[4] = { - { .fniv = gen_uqadd_vec, - .fno = gen_helper_gvec_uqadd_b, - .write_aofs = true, - .opt_opc = vecop_list_uqadd, - .vece = MO_8 }, - { .fniv = gen_uqadd_vec, - .fno = gen_helper_gvec_uqadd_h, - .write_aofs = true, - .opt_opc = vecop_list_uqadd, - .vece = MO_16 }, - { .fniv = gen_uqadd_vec, - .fno = gen_helper_gvec_uqadd_s, - .write_aofs = true, - .opt_opc = vecop_list_uqadd, - .vece = MO_32 }, - { .fniv = gen_uqadd_vec, - .fno = gen_helper_gvec_uqadd_d, - .write_aofs = true, - .opt_opc = vecop_list_uqadd, - .vece = MO_64 }, -}; +void gen_gvec_uqadd_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_usadd_vec, INDEX_op_cmp_vec, INDEX_op_add_vec, 0 + }; + static const GVecGen4 ops[4] = { + { .fniv = gen_uqadd_vec, + .fno = gen_helper_gvec_uqadd_b, + .write_aofs = true, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fniv = gen_uqadd_vec, + .fno = gen_helper_gvec_uqadd_h, + .write_aofs = true, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fniv = gen_uqadd_vec, + .fno = gen_helper_gvec_uqadd_s, + .write_aofs = true, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fniv = gen_uqadd_vec, + .fno = gen_helper_gvec_uqadd_d, + .write_aofs = true, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; + tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), + rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} static void gen_sqadd_vec(unsigned vece, TCGv_vec t, TCGv_vec sat, TCGv_vec a, TCGv_vec b) @@ -4963,32 +4968,37 @@ static void gen_sqadd_vec(unsigned vece, TCGv_vec t, TCGv_vec sat, tcg_temp_free_vec(x); } -static const TCGOpcode vecop_list_sqadd[] = { - INDEX_op_ssadd_vec, INDEX_op_cmp_vec, INDEX_op_add_vec, 0 -}; - -const GVecGen4 sqadd_op[4] = { - { .fniv = gen_sqadd_vec, - .fno = gen_helper_gvec_sqadd_b, - .opt_opc = vecop_list_sqadd, - .write_aofs = true, - .vece = MO_8 }, - { .fniv = gen_sqadd_vec, - .fno = gen_helper_gvec_sqadd_h, - .opt_opc = vecop_list_sqadd, - .write_aofs = true, - .vece = MO_16 }, - { .fniv = gen_sqadd_vec, - .fno = gen_helper_gvec_sqadd_s, - .opt_opc = vecop_list_sqadd, - .write_aofs = true, - .vece = MO_32 }, - { .fniv = gen_sqadd_vec, - .fno = gen_helper_gvec_sqadd_d, - .opt_opc = vecop_list_sqadd, - .write_aofs = true, - .vece = MO_64 }, -}; +void gen_gvec_sqadd_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_ssadd_vec, INDEX_op_cmp_vec, INDEX_op_add_vec, 0 + }; + static const GVecGen4 ops[4] = { + { .fniv = gen_sqadd_vec, + .fno = gen_helper_gvec_sqadd_b, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_8 }, + { .fniv = gen_sqadd_vec, + .fno = gen_helper_gvec_sqadd_h, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_16 }, + { .fniv = gen_sqadd_vec, + .fno = gen_helper_gvec_sqadd_s, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_32 }, + { .fniv = gen_sqadd_vec, + .fno = gen_helper_gvec_sqadd_d, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_64 }, + }; + tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), + rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} static void gen_uqsub_vec(unsigned vece, TCGv_vec t, TCGv_vec sat, TCGv_vec a, TCGv_vec b) @@ -5001,32 +5011,37 @@ static void gen_uqsub_vec(unsigned vece, TCGv_vec t, TCGv_vec sat, tcg_temp_free_vec(x); } -static const TCGOpcode vecop_list_uqsub[] = { - INDEX_op_ussub_vec, INDEX_op_cmp_vec, INDEX_op_sub_vec, 0 -}; - -const GVecGen4 uqsub_op[4] = { - { .fniv = gen_uqsub_vec, - .fno = gen_helper_gvec_uqsub_b, - .opt_opc = vecop_list_uqsub, - .write_aofs = true, - .vece = MO_8 }, - { .fniv = gen_uqsub_vec, - .fno = gen_helper_gvec_uqsub_h, - .opt_opc = vecop_list_uqsub, - .write_aofs = true, - .vece = MO_16 }, - { .fniv = gen_uqsub_vec, - .fno = gen_helper_gvec_uqsub_s, - .opt_opc = vecop_list_uqsub, - .write_aofs = true, - .vece = MO_32 }, - { .fniv = gen_uqsub_vec, - .fno = gen_helper_gvec_uqsub_d, - .opt_opc = vecop_list_uqsub, - .write_aofs = true, - .vece = MO_64 }, -}; +void gen_gvec_uqsub_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_ussub_vec, INDEX_op_cmp_vec, INDEX_op_sub_vec, 0 + }; + static const GVecGen4 ops[4] = { + { .fniv = gen_uqsub_vec, + .fno = gen_helper_gvec_uqsub_b, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_8 }, + { .fniv = gen_uqsub_vec, + .fno = gen_helper_gvec_uqsub_h, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_16 }, + { .fniv = gen_uqsub_vec, + .fno = gen_helper_gvec_uqsub_s, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_32 }, + { .fniv = gen_uqsub_vec, + .fno = gen_helper_gvec_uqsub_d, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_64 }, + }; + tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), + rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} static void gen_sqsub_vec(unsigned vece, TCGv_vec t, TCGv_vec sat, TCGv_vec a, TCGv_vec b) @@ -5039,32 +5054,37 @@ static void gen_sqsub_vec(unsigned vece, TCGv_vec t, TCGv_vec sat, tcg_temp_free_vec(x); } -static const TCGOpcode vecop_list_sqsub[] = { - INDEX_op_sssub_vec, INDEX_op_cmp_vec, INDEX_op_sub_vec, 0 -}; - -const GVecGen4 sqsub_op[4] = { - { .fniv = gen_sqsub_vec, - .fno = gen_helper_gvec_sqsub_b, - .opt_opc = vecop_list_sqsub, - .write_aofs = true, - .vece = MO_8 }, - { .fniv = gen_sqsub_vec, - .fno = gen_helper_gvec_sqsub_h, - .opt_opc = vecop_list_sqsub, - .write_aofs = true, - .vece = MO_16 }, - { .fniv = gen_sqsub_vec, - .fno = gen_helper_gvec_sqsub_s, - .opt_opc = vecop_list_sqsub, - .write_aofs = true, - .vece = MO_32 }, - { .fniv = gen_sqsub_vec, - .fno = gen_helper_gvec_sqsub_d, - .opt_opc = vecop_list_sqsub, - .write_aofs = true, - .vece = MO_64 }, -}; +void gen_gvec_sqsub_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_sssub_vec, INDEX_op_cmp_vec, INDEX_op_sub_vec, 0 + }; + static const GVecGen4 ops[4] = { + { .fniv = gen_sqsub_vec, + .fno = gen_helper_gvec_sqsub_b, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_8 }, + { .fniv = gen_sqsub_vec, + .fno = gen_helper_gvec_sqsub_h, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_16 }, + { .fniv = gen_sqsub_vec, + .fno = gen_helper_gvec_sqsub_s, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_32 }, + { .fniv = gen_sqsub_vec, + .fno = gen_helper_gvec_sqsub_d, + .opt_opc = vecop_list, + .write_aofs = true, + .vece = MO_64 }, + }; + tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), + rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} /* Translate a NEON data processing instruction. Return nonzero if the instruction is invalid. diff --git a/target/arm/translate.h b/target/arm/translate.h index a02a54cabf..4e1778c5e0 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -298,16 +298,21 @@ void gen_gvec_sshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, void gen_gvec_ushl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); -extern const GVecGen4 uqadd_op[4]; -extern const GVecGen4 sqadd_op[4]; -extern const GVecGen4 uqsub_op[4]; -extern const GVecGen4 sqsub_op[4]; void gen_cmtst_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b); void gen_ushl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b); void gen_sshl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b); void gen_ushl_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b); void gen_sshl_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b); +void gen_gvec_uqadd_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_sqadd_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_uqsub_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_sqsub_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); + void gen_gvec_ssra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, int64_t shift, uint32_t opr_sz, uint32_t max_sz); void gen_gvec_usra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, From fe6fb4beb2f9bb0afc813e565504b66a92bbf04b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:40 -0700 Subject: [PATCH 0431/2595] target/arm: Remove fp_status from helper_{recpe, rsqrte}_u32 These operations do not touch fp_status. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.h | 4 ++-- target/arm/translate-a64.c | 5 ++--- target/arm/translate.c | 12 ++---------- target/arm/vfp_helper.c | 5 ++--- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 33c76192d2..aed3050965 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -211,8 +211,8 @@ DEF_HELPER_FLAGS_2(recpe_f64, TCG_CALL_NO_RWG, f64, f64, ptr) DEF_HELPER_FLAGS_2(rsqrte_f16, TCG_CALL_NO_RWG, f16, f16, ptr) DEF_HELPER_FLAGS_2(rsqrte_f32, TCG_CALL_NO_RWG, f32, f32, ptr) DEF_HELPER_FLAGS_2(rsqrte_f64, TCG_CALL_NO_RWG, f64, f64, ptr) -DEF_HELPER_2(recpe_u32, i32, i32, ptr) -DEF_HELPER_FLAGS_2(rsqrte_u32, TCG_CALL_NO_RWG, i32, i32, ptr) +DEF_HELPER_FLAGS_1(recpe_u32, TCG_CALL_NO_RWG, i32, i32) +DEF_HELPER_FLAGS_1(rsqrte_u32, TCG_CALL_NO_RWG, i32, i32) DEF_HELPER_FLAGS_4(neon_tbl, TCG_CALL_NO_RWG, i32, i32, i32, ptr, i32) DEF_HELPER_3(shl_cc, i32, env, i32, i32) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index ea5f6ceadc..367fa403ae 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -9699,7 +9699,7 @@ static void handle_2misc_reciprocal(DisasContext *s, int opcode, switch (opcode) { case 0x3c: /* URECPE */ - gen_helper_recpe_u32(tcg_res, tcg_op, fpst); + gen_helper_recpe_u32(tcg_res, tcg_op); break; case 0x3d: /* FRECPE */ gen_helper_recpe_f32(tcg_res, tcg_op, fpst); @@ -12244,7 +12244,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) unallocated_encoding(s); return; } - need_fpstatus = true; break; case 0x1e: /* FRINT32Z */ case 0x1f: /* FRINT64Z */ @@ -12412,7 +12411,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) gen_helper_rints_exact(tcg_res, tcg_op, tcg_fpstatus); break; case 0x7c: /* URSQRTE */ - gen_helper_rsqrte_u32(tcg_res, tcg_op, tcg_fpstatus); + gen_helper_rsqrte_u32(tcg_res, tcg_op); break; case 0x1e: /* FRINT32Z */ case 0x5e: /* FRINT32X */ diff --git a/target/arm/translate.c b/target/arm/translate.c index 7eb30cde60..391a09b439 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -6875,19 +6875,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) break; } case NEON_2RM_VRECPE: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_recpe_u32(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); + gen_helper_recpe_u32(tmp, tmp); break; - } case NEON_2RM_VRSQRTE: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_rsqrte_u32(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); + gen_helper_rsqrte_u32(tmp, tmp); break; - } case NEON_2RM_VRECPE_F: { TCGv_ptr fpstatus = get_fpstatus_ptr(1); diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index 930d6e747f..ec007fce25 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -1023,9 +1023,8 @@ float64 HELPER(rsqrte_f64)(float64 input, void *fpstp) return make_float64(val); } -uint32_t HELPER(recpe_u32)(uint32_t a, void *fpstp) +uint32_t HELPER(recpe_u32)(uint32_t a) { - /* float_status *s = fpstp; */ int input, estimate; if ((a & 0x80000000) == 0) { @@ -1038,7 +1037,7 @@ uint32_t HELPER(recpe_u32)(uint32_t a, void *fpstp) return deposit32(0, (32 - 9), 9, estimate); } -uint32_t HELPER(rsqrte_u32)(uint32_t a, void *fpstp) +uint32_t HELPER(rsqrte_u32)(uint32_t a) { int estimate; From 146aa66ce58b686b8037d0eb3921c1125942dbde Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:41 -0700 Subject: [PATCH 0432/2595] target/arm: Create gen_gvec_{qrdmla,qrdmls} Provide a functional interface for the vector expansion. This fits better with the existing set of helpers that we provide for other operations. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 34 ++---------------------- target/arm/translate.c | 54 +++++++++++++++++++------------------- target/arm/translate.h | 5 ++++ 3 files changed, 34 insertions(+), 59 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 367fa403ae..4577df3cf4 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -587,18 +587,6 @@ static void gen_gvec_op3_ool(DisasContext *s, bool is_q, int rd, is_q ? 16 : 8, vec_full_reg_size(s), data, fn); } -/* Expand a 3-operand + env pointer operation using - * an out-of-line helper. - */ -static void gen_gvec_op3_env(DisasContext *s, bool is_q, int rd, - int rn, int rm, gen_helper_gvec_3_ptr *fn) -{ - tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), - vec_full_reg_offset(s, rn), - vec_full_reg_offset(s, rm), cpu_env, - is_q ? 16 : 8, vec_full_reg_size(s), 0, fn); -} - /* Expand a 3-operand + fpstatus pointer + simd data value operation using * an out-of-line helper. */ @@ -11693,29 +11681,11 @@ static void disas_simd_three_reg_same_extra(DisasContext *s, uint32_t insn) switch (opcode) { case 0x0: /* SQRDMLAH (vector) */ - switch (size) { - case 1: - gen_gvec_op3_env(s, is_q, rd, rn, rm, gen_helper_gvec_qrdmlah_s16); - break; - case 2: - gen_gvec_op3_env(s, is_q, rd, rn, rm, gen_helper_gvec_qrdmlah_s32); - break; - default: - g_assert_not_reached(); - } + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sqrdmlah_qc, size); return; case 0x1: /* SQRDMLSH (vector) */ - switch (size) { - case 1: - gen_gvec_op3_env(s, is_q, rd, rn, rm, gen_helper_gvec_qrdmlsh_s16); - break; - case 2: - gen_gvec_op3_env(s, is_q, rd, rn, rm, gen_helper_gvec_qrdmlsh_s32); - break; - default: - g_assert_not_reached(); - } + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sqrdmlsh_qc, size); return; case 0x2: /* SDOT / UDOT */ diff --git a/target/arm/translate.c b/target/arm/translate.c index 391a09b439..39626e0df9 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3629,20 +3629,26 @@ static const uint8_t neon_2rm_sizes[] = { [NEON_2RM_VCVT_UF] = 0x4, }; - -/* Expand v8.1 simd helper. */ -static int do_v81_helper(DisasContext *s, gen_helper_gvec_3_ptr *fn, - int q, int rd, int rn, int rm) +void gen_gvec_sqrdmlah_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) { - if (dc_isar_feature(aa32_rdm, s)) { - int opr_sz = (1 + q) * 8; - tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), - vfp_reg_offset(1, rn), - vfp_reg_offset(1, rm), cpu_env, - opr_sz, opr_sz, 0, fn); - return 0; - } - return 1; + static gen_helper_gvec_3_ptr * const fns[2] = { + gen_helper_gvec_qrdmlah_s16, gen_helper_gvec_qrdmlah_s32 + }; + tcg_debug_assert(vece >= 1 && vece <= 2); + tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, cpu_env, + opr_sz, max_sz, 0, fns[vece - 1]); +} + +void gen_gvec_sqrdmlsh_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static gen_helper_gvec_3_ptr * const fns[2] = { + gen_helper_gvec_qrdmlsh_s16, gen_helper_gvec_qrdmlsh_s32 + }; + tcg_debug_assert(vece >= 1 && vece <= 2); + tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, cpu_env, + opr_sz, max_sz, 0, fns[vece - 1]); } #define GEN_CMP0(NAME, COND) \ @@ -5197,13 +5203,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) break; /* VPADD */ } /* VQRDMLAH */ - switch (size) { - case 1: - return do_v81_helper(s, gen_helper_gvec_qrdmlah_s16, - q, rd, rn, rm); - case 2: - return do_v81_helper(s, gen_helper_gvec_qrdmlah_s32, - q, rd, rn, rm); + if (dc_isar_feature(aa32_rdm, s) && (size == 1 || size == 2)) { + gen_gvec_sqrdmlah_qc(size, rd_ofs, rn_ofs, rm_ofs, + vec_size, vec_size); + return 0; } return 1; @@ -5216,13 +5219,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) break; } /* VQRDMLSH */ - switch (size) { - case 1: - return do_v81_helper(s, gen_helper_gvec_qrdmlsh_s16, - q, rd, rn, rm); - case 2: - return do_v81_helper(s, gen_helper_gvec_qrdmlsh_s32, - q, rd, rn, rm); + if (dc_isar_feature(aa32_rdm, s) && (size == 1 || size == 2)) { + gen_gvec_sqrdmlsh_qc(size, rd_ofs, rn_ofs, rm_ofs, + vec_size, vec_size); + return 0; } return 1; diff --git a/target/arm/translate.h b/target/arm/translate.h index 4e1778c5e0..aea8a9759d 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -332,6 +332,11 @@ void gen_gvec_sri(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, void gen_gvec_sli(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, int64_t shift, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_sqrdmlah_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_sqrdmlsh_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); + /* * Forward to the isar_feature_* tests given a DisasContext pointer. */ From e286bf4a72fe3a60490b8d6e3f28d6335677e08c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:42 -0700 Subject: [PATCH 0433/2595] target/arm: Pass pointer to qc to qrdmla/qrdmls Pass a pointer directly to env->vfp.qc[0], rather than env. This will allow SVE2, which does not modify QC, to pass a pointer to dummy storage. Change the return type of inl_qrdml.h_s16 to match the sense of the operation: signed. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-14-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate.c | 18 ++++++++--- target/arm/vec_helper.c | 70 +++++++++++++++++++++++------------------ 2 files changed, 54 insertions(+), 34 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 39626e0df9..21529a9b8f 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3629,6 +3629,18 @@ static const uint8_t neon_2rm_sizes[] = { [NEON_2RM_VCVT_UF] = 0x4, }; +static void gen_gvec_fn3_qc(uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, + uint32_t opr_sz, uint32_t max_sz, + gen_helper_gvec_3_ptr *fn) +{ + TCGv_ptr qc_ptr = tcg_temp_new_ptr(); + + tcg_gen_addi_ptr(qc_ptr, cpu_env, offsetof(CPUARMState, vfp.qc)); + tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, qc_ptr, + opr_sz, max_sz, 0, fn); + tcg_temp_free_ptr(qc_ptr); +} + void gen_gvec_sqrdmlah_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) { @@ -3636,8 +3648,7 @@ void gen_gvec_sqrdmlah_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, gen_helper_gvec_qrdmlah_s16, gen_helper_gvec_qrdmlah_s32 }; tcg_debug_assert(vece >= 1 && vece <= 2); - tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, cpu_env, - opr_sz, max_sz, 0, fns[vece - 1]); + gen_gvec_fn3_qc(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, fns[vece - 1]); } void gen_gvec_sqrdmlsh_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, @@ -3647,8 +3658,7 @@ void gen_gvec_sqrdmlsh_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, gen_helper_gvec_qrdmlsh_s16, gen_helper_gvec_qrdmlsh_s32 }; tcg_debug_assert(vece >= 1 && vece <= 2); - tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, cpu_env, - opr_sz, max_sz, 0, fns[vece - 1]); + gen_gvec_fn3_qc(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, fns[vece - 1]); } #define GEN_CMP0(NAME, COND) \ diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index 096fea67ef..6aa2ca0827 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -36,8 +36,6 @@ #define H4(x) (x) #endif -#define SET_QC() env->vfp.qc[0] = 1 - static void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz) { uint64_t *d = vd + opr_sz; @@ -49,8 +47,8 @@ static void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz) } /* Signed saturating rounding doubling multiply-accumulate high half, 16-bit */ -static uint16_t inl_qrdmlah_s16(CPUARMState *env, int16_t src1, - int16_t src2, int16_t src3) +static int16_t inl_qrdmlah_s16(int16_t src1, int16_t src2, + int16_t src3, uint32_t *sat) { /* Simplify: * = ((a3 << 16) + ((e1 * e2) << 1) + (1 << 15)) >> 16 @@ -60,7 +58,7 @@ static uint16_t inl_qrdmlah_s16(CPUARMState *env, int16_t src1, ret = ((int32_t)src3 << 15) + ret + (1 << 14); ret >>= 15; if (ret != (int16_t)ret) { - SET_QC(); + *sat = 1; ret = (ret < 0 ? -0x8000 : 0x7fff); } return ret; @@ -69,30 +67,30 @@ static uint16_t inl_qrdmlah_s16(CPUARMState *env, int16_t src1, uint32_t HELPER(neon_qrdmlah_s16)(CPUARMState *env, uint32_t src1, uint32_t src2, uint32_t src3) { - uint16_t e1 = inl_qrdmlah_s16(env, src1, src2, src3); - uint16_t e2 = inl_qrdmlah_s16(env, src1 >> 16, src2 >> 16, src3 >> 16); + uint32_t *sat = &env->vfp.qc[0]; + uint16_t e1 = inl_qrdmlah_s16(src1, src2, src3, sat); + uint16_t e2 = inl_qrdmlah_s16(src1 >> 16, src2 >> 16, src3 >> 16, sat); return deposit32(e1, 16, 16, e2); } void HELPER(gvec_qrdmlah_s16)(void *vd, void *vn, void *vm, - void *ve, uint32_t desc) + void *vq, uint32_t desc) { uintptr_t opr_sz = simd_oprsz(desc); int16_t *d = vd; int16_t *n = vn; int16_t *m = vm; - CPUARMState *env = ve; uintptr_t i; for (i = 0; i < opr_sz / 2; ++i) { - d[i] = inl_qrdmlah_s16(env, n[i], m[i], d[i]); + d[i] = inl_qrdmlah_s16(n[i], m[i], d[i], vq); } clear_tail(d, opr_sz, simd_maxsz(desc)); } /* Signed saturating rounding doubling multiply-subtract high half, 16-bit */ -static uint16_t inl_qrdmlsh_s16(CPUARMState *env, int16_t src1, - int16_t src2, int16_t src3) +static int16_t inl_qrdmlsh_s16(int16_t src1, int16_t src2, + int16_t src3, uint32_t *sat) { /* Similarly, using subtraction: * = ((a3 << 16) - ((e1 * e2) << 1) + (1 << 15)) >> 16 @@ -102,7 +100,7 @@ static uint16_t inl_qrdmlsh_s16(CPUARMState *env, int16_t src1, ret = ((int32_t)src3 << 15) - ret + (1 << 14); ret >>= 15; if (ret != (int16_t)ret) { - SET_QC(); + *sat = 1; ret = (ret < 0 ? -0x8000 : 0x7fff); } return ret; @@ -111,85 +109,97 @@ static uint16_t inl_qrdmlsh_s16(CPUARMState *env, int16_t src1, uint32_t HELPER(neon_qrdmlsh_s16)(CPUARMState *env, uint32_t src1, uint32_t src2, uint32_t src3) { - uint16_t e1 = inl_qrdmlsh_s16(env, src1, src2, src3); - uint16_t e2 = inl_qrdmlsh_s16(env, src1 >> 16, src2 >> 16, src3 >> 16); + uint32_t *sat = &env->vfp.qc[0]; + uint16_t e1 = inl_qrdmlsh_s16(src1, src2, src3, sat); + uint16_t e2 = inl_qrdmlsh_s16(src1 >> 16, src2 >> 16, src3 >> 16, sat); return deposit32(e1, 16, 16, e2); } void HELPER(gvec_qrdmlsh_s16)(void *vd, void *vn, void *vm, - void *ve, uint32_t desc) + void *vq, uint32_t desc) { uintptr_t opr_sz = simd_oprsz(desc); int16_t *d = vd; int16_t *n = vn; int16_t *m = vm; - CPUARMState *env = ve; uintptr_t i; for (i = 0; i < opr_sz / 2; ++i) { - d[i] = inl_qrdmlsh_s16(env, n[i], m[i], d[i]); + d[i] = inl_qrdmlsh_s16(n[i], m[i], d[i], vq); } clear_tail(d, opr_sz, simd_maxsz(desc)); } /* Signed saturating rounding doubling multiply-accumulate high half, 32-bit */ -uint32_t HELPER(neon_qrdmlah_s32)(CPUARMState *env, int32_t src1, - int32_t src2, int32_t src3) +static int32_t inl_qrdmlah_s32(int32_t src1, int32_t src2, + int32_t src3, uint32_t *sat) { /* Simplify similarly to int_qrdmlah_s16 above. */ int64_t ret = (int64_t)src1 * src2; ret = ((int64_t)src3 << 31) + ret + (1 << 30); ret >>= 31; if (ret != (int32_t)ret) { - SET_QC(); + *sat = 1; ret = (ret < 0 ? INT32_MIN : INT32_MAX); } return ret; } +uint32_t HELPER(neon_qrdmlah_s32)(CPUARMState *env, int32_t src1, + int32_t src2, int32_t src3) +{ + uint32_t *sat = &env->vfp.qc[0]; + return inl_qrdmlah_s32(src1, src2, src3, sat); +} + void HELPER(gvec_qrdmlah_s32)(void *vd, void *vn, void *vm, - void *ve, uint32_t desc) + void *vq, uint32_t desc) { uintptr_t opr_sz = simd_oprsz(desc); int32_t *d = vd; int32_t *n = vn; int32_t *m = vm; - CPUARMState *env = ve; uintptr_t i; for (i = 0; i < opr_sz / 4; ++i) { - d[i] = helper_neon_qrdmlah_s32(env, n[i], m[i], d[i]); + d[i] = inl_qrdmlah_s32(n[i], m[i], d[i], vq); } clear_tail(d, opr_sz, simd_maxsz(desc)); } /* Signed saturating rounding doubling multiply-subtract high half, 32-bit */ -uint32_t HELPER(neon_qrdmlsh_s32)(CPUARMState *env, int32_t src1, - int32_t src2, int32_t src3) +static int32_t inl_qrdmlsh_s32(int32_t src1, int32_t src2, + int32_t src3, uint32_t *sat) { /* Simplify similarly to int_qrdmlsh_s16 above. */ int64_t ret = (int64_t)src1 * src2; ret = ((int64_t)src3 << 31) - ret + (1 << 30); ret >>= 31; if (ret != (int32_t)ret) { - SET_QC(); + *sat = 1; ret = (ret < 0 ? INT32_MIN : INT32_MAX); } return ret; } +uint32_t HELPER(neon_qrdmlsh_s32)(CPUARMState *env, int32_t src1, + int32_t src2, int32_t src3) +{ + uint32_t *sat = &env->vfp.qc[0]; + return inl_qrdmlsh_s32(src1, src2, src3, sat); +} + void HELPER(gvec_qrdmlsh_s32)(void *vd, void *vn, void *vm, - void *ve, uint32_t desc) + void *vq, uint32_t desc) { uintptr_t opr_sz = simd_oprsz(desc); int32_t *d = vd; int32_t *n = vn; int32_t *m = vm; - CPUARMState *env = ve; uintptr_t i; for (i = 0; i < opr_sz / 4; ++i) { - d[i] = helper_neon_qrdmlsh_s32(env, n[i], m[i], d[i]); + d[i] = inl_qrdmlsh_s32(n[i], m[i], d[i], vq); } clear_tail(d, opr_sz, simd_maxsz(desc)); } From 525d9b6d42844e187211d25b69be8b378785bc24 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:43 -0700 Subject: [PATCH 0434/2595] target/arm: Clear tail in gvec_fmul_idx_*, gvec_fmla_idx_* Must clear the tail for AdvSIMD when SVE is enabled. Fixes: ca40a6e6e39 Cc: qemu-stable@nongnu.org Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-15-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/vec_helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index 6aa2ca0827..a483841add 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -747,6 +747,7 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, void *stat, uint32_t desc) \ d[i + j] = TYPE##_mul(n[i + j], mm, stat); \ } \ } \ + clear_tail(d, oprsz, simd_maxsz(desc)); \ } DO_MUL_IDX(gvec_fmul_idx_h, float16, H2) @@ -771,6 +772,7 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, \ mm, a[i + j], 0, stat); \ } \ } \ + clear_tail(d, oprsz, simd_maxsz(desc)); \ } DO_FMLA_IDX(gvec_fmla_idx_h, float16, H2) From 50c160d44eb059c7fc7f348ae2c3b0cb41437044 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:44 -0700 Subject: [PATCH 0435/2595] target/arm: Vectorize SABD/UABD Include 64-bit element size in preparation for SVE2. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.h | 10 +++ target/arm/translate-a64.c | 8 ++- target/arm/translate.c | 133 ++++++++++++++++++++++++++++++++++++- target/arm/translate.h | 5 ++ target/arm/vec_helper.c | 24 +++++++ 5 files changed, 176 insertions(+), 4 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index aed3050965..4678d3a6f4 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -731,6 +731,16 @@ DEF_HELPER_FLAGS_3(gvec_sli_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(gvec_sli_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(gvec_sli_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_sabd_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_sabd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_sabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_sabd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_uabd_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uabd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uabd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + #ifdef TARGET_AARCH64 #include "helper-a64.h" #include "helper-sve.h" diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 4577df3cf4..54b06553a6 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -11190,6 +11190,13 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_smin, size); } return; + case 0xe: /* SABD, UABD */ + if (u) { + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_uabd, size); + } else { + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sabd, size); + } + return; case 0x10: /* ADD, SUB */ if (u) { gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_sub, size); @@ -11322,7 +11329,6 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) genenvfn = fns[size][u]; break; } - case 0xe: /* SABD, UABD */ case 0xf: /* SABA, UABA */ { static NeonGenTwoOpFn * const fns[3][2] = { diff --git a/target/arm/translate.c b/target/arm/translate.c index 21529a9b8f..d288721c23 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5102,6 +5102,126 @@ void gen_gvec_sqsub_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); } +static void gen_sabd_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i32 t = tcg_temp_new_i32(); + + tcg_gen_sub_i32(t, a, b); + tcg_gen_sub_i32(d, b, a); + tcg_gen_movcond_i32(TCG_COND_LT, d, a, b, d, t); + tcg_temp_free_i32(t); +} + +static void gen_sabd_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_sub_i64(t, a, b); + tcg_gen_sub_i64(d, b, a); + tcg_gen_movcond_i64(TCG_COND_LT, d, a, b, d, t); + tcg_temp_free_i64(t); +} + +static void gen_sabd_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + + tcg_gen_smin_vec(vece, t, a, b); + tcg_gen_smax_vec(vece, d, a, b); + tcg_gen_sub_vec(vece, d, d, t); + tcg_temp_free_vec(t); +} + +void gen_gvec_sabd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_sub_vec, INDEX_op_smin_vec, INDEX_op_smax_vec, 0 + }; + static const GVecGen3 ops[4] = { + { .fniv = gen_sabd_vec, + .fno = gen_helper_gvec_sabd_b, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fniv = gen_sabd_vec, + .fno = gen_helper_gvec_sabd_h, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_sabd_i32, + .fniv = gen_sabd_vec, + .fno = gen_helper_gvec_sabd_s, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_sabd_i64, + .fniv = gen_sabd_vec, + .fno = gen_helper_gvec_sabd_d, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} + +static void gen_uabd_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i32 t = tcg_temp_new_i32(); + + tcg_gen_sub_i32(t, a, b); + tcg_gen_sub_i32(d, b, a); + tcg_gen_movcond_i32(TCG_COND_LTU, d, a, b, d, t); + tcg_temp_free_i32(t); +} + +static void gen_uabd_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_sub_i64(t, a, b); + tcg_gen_sub_i64(d, b, a); + tcg_gen_movcond_i64(TCG_COND_LTU, d, a, b, d, t); + tcg_temp_free_i64(t); +} + +static void gen_uabd_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + + tcg_gen_umin_vec(vece, t, a, b); + tcg_gen_umax_vec(vece, d, a, b); + tcg_gen_sub_vec(vece, d, d, t); + tcg_temp_free_vec(t); +} + +void gen_gvec_uabd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_sub_vec, INDEX_op_umin_vec, INDEX_op_umax_vec, 0 + }; + static const GVecGen3 ops[4] = { + { .fniv = gen_uabd_vec, + .fno = gen_helper_gvec_uabd_b, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fniv = gen_uabd_vec, + .fno = gen_helper_gvec_uabd_h, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = gen_uabd_i32, + .fniv = gen_uabd_vec, + .fno = gen_helper_gvec_uabd_s, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = gen_uabd_i64, + .fniv = gen_uabd_vec, + .fno = gen_helper_gvec_uabd_d, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .opt_opc = vecop_list, + .vece = MO_64 }, + }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} + /* Translate a NEON data processing instruction. Return nonzero if the instruction is invalid. We process data in a mixture of 32-bit and 64-bit chunks. @@ -5236,6 +5356,16 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } return 1; + case NEON_3R_VABD: + if (u) { + gen_gvec_uabd(size, rd_ofs, rn_ofs, rm_ofs, + vec_size, vec_size); + } else { + gen_gvec_sabd(size, rd_ofs, rn_ofs, rm_ofs, + vec_size, vec_size); + } + return 0; + case NEON_3R_VADD_VSUB: case NEON_3R_LOGIC: case NEON_3R_VMAX: @@ -5380,9 +5510,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VQRSHL: GEN_NEON_INTEGER_OP_ENV(qrshl); break; - case NEON_3R_VABD: - GEN_NEON_INTEGER_OP(abd); - break; case NEON_3R_VABA: GEN_NEON_INTEGER_OP(abd); tcg_temp_free_i32(tmp2); diff --git a/target/arm/translate.h b/target/arm/translate.h index aea8a9759d..bbfe3d1393 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -337,6 +337,11 @@ void gen_gvec_sqrdmlah_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, void gen_gvec_sqrdmlsh_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_sabd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_uabd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); + /* * Forward to the isar_feature_* tests given a DisasContext pointer. */ diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index a483841add..a4972d02fc 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -1407,3 +1407,27 @@ DO_CMP0(gvec_cgt0_h, int16_t, >) DO_CMP0(gvec_cge0_h, int16_t, >=) #undef DO_CMP0 + +#define DO_ABD(NAME, TYPE) \ +void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \ +{ \ + intptr_t i, opr_sz = simd_oprsz(desc); \ + TYPE *d = vd, *n = vn, *m = vm; \ + \ + for (i = 0; i < opr_sz / sizeof(TYPE); ++i) { \ + d[i] = n[i] < m[i] ? m[i] - n[i] : n[i] - m[i]; \ + } \ + clear_tail(d, opr_sz, simd_maxsz(desc)); \ +} + +DO_ABD(gvec_sabd_b, int8_t) +DO_ABD(gvec_sabd_h, int16_t) +DO_ABD(gvec_sabd_s, int32_t) +DO_ABD(gvec_sabd_d, int64_t) + +DO_ABD(gvec_uabd_b, uint8_t) +DO_ABD(gvec_uabd_h, uint16_t) +DO_ABD(gvec_uabd_s, uint32_t) +DO_ABD(gvec_uabd_d, uint64_t) + +#undef DO_ABD From cfdb2c0c95ae9205b0dd7f0f5e970cdec50fef20 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 09:32:45 -0700 Subject: [PATCH 0436/2595] target/arm: Vectorize SABA/UABA Include 64-bit element size in preparation for SVE2. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200513163245.17915-17-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.h | 17 +++-- target/arm/neon_helper.c | 10 --- target/arm/translate-a64.c | 17 ++--- target/arm/translate.c | 134 +++++++++++++++++++++++++++++++++++-- target/arm/translate.h | 5 ++ target/arm/vec_helper.c | 24 +++++++ 6 files changed, 174 insertions(+), 33 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 4678d3a6f4..1857f4ee46 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -284,13 +284,6 @@ DEF_HELPER_2(neon_pmax_s8, i32, i32, i32) DEF_HELPER_2(neon_pmax_u16, i32, i32, i32) DEF_HELPER_2(neon_pmax_s16, i32, i32, i32) -DEF_HELPER_2(neon_abd_u8, i32, i32, i32) -DEF_HELPER_2(neon_abd_s8, i32, i32, i32) -DEF_HELPER_2(neon_abd_u16, i32, i32, i32) -DEF_HELPER_2(neon_abd_s16, i32, i32, i32) -DEF_HELPER_2(neon_abd_u32, i32, i32, i32) -DEF_HELPER_2(neon_abd_s32, i32, i32, i32) - DEF_HELPER_2(neon_shl_u16, i32, i32, i32) DEF_HELPER_2(neon_shl_s16, i32, i32, i32) DEF_HELPER_2(neon_rshl_u8, i32, i32, i32) @@ -741,6 +734,16 @@ DEF_HELPER_FLAGS_4(gvec_uabd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_uabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_uabd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_saba_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_saba_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_saba_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_saba_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_uaba_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uaba_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uaba_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uaba_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + #ifdef TARGET_AARCH64 #include "helper-a64.h" #include "helper-sve.h" diff --git a/target/arm/neon_helper.c b/target/arm/neon_helper.c index 448be93fa1..2ef75e04c8 100644 --- a/target/arm/neon_helper.c +++ b/target/arm/neon_helper.c @@ -576,16 +576,6 @@ NEON_POP(pmax_s16, neon_s16, 2) NEON_POP(pmax_u16, neon_u16, 2) #undef NEON_FN -#define NEON_FN(dest, src1, src2) \ - dest = (src1 > src2) ? (src1 - src2) : (src2 - src1) -NEON_VOP(abd_s8, neon_s8, 4) -NEON_VOP(abd_u8, neon_u8, 4) -NEON_VOP(abd_s16, neon_s16, 2) -NEON_VOP(abd_u16, neon_u16, 2) -NEON_VOP(abd_s32, neon_s32, 1) -NEON_VOP(abd_u32, neon_u32, 1) -#undef NEON_FN - #define NEON_FN(dest, src1, src2) do { \ int8_t tmp; \ tmp = (int8_t)src2; \ diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 54b06553a6..991e451644 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -11197,6 +11197,13 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sabd, size); } return; + case 0xf: /* SABA, UABA */ + if (u) { + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_uaba, size); + } else { + gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_saba, size); + } + return; case 0x10: /* ADD, SUB */ if (u) { gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_sub, size); @@ -11329,16 +11336,6 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) genenvfn = fns[size][u]; break; } - case 0xf: /* SABA, UABA */ - { - static NeonGenTwoOpFn * const fns[3][2] = { - { gen_helper_neon_abd_s8, gen_helper_neon_abd_u8 }, - { gen_helper_neon_abd_s16, gen_helper_neon_abd_u16 }, - { gen_helper_neon_abd_s32, gen_helper_neon_abd_u32 }, - }; - genfn = fns[size][u]; - break; - } case 0x16: /* SQDMULH, SQRDMULH */ { static NeonGenTwoOpEnvFn * const fns[2][2] = { diff --git a/target/arm/translate.c b/target/arm/translate.c index d288721c23..e3d37ef2e9 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5222,6 +5222,124 @@ void gen_gvec_uabd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); } +static void gen_saba_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i32 t = tcg_temp_new_i32(); + gen_sabd_i32(t, a, b); + tcg_gen_add_i32(d, d, t); + tcg_temp_free_i32(t); +} + +static void gen_saba_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + TCGv_i64 t = tcg_temp_new_i64(); + gen_sabd_i64(t, a, b); + tcg_gen_add_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_saba_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + gen_sabd_vec(vece, t, a, b); + tcg_gen_add_vec(vece, d, d, t); + tcg_temp_free_vec(t); +} + +void gen_gvec_saba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_sub_vec, INDEX_op_add_vec, + INDEX_op_smin_vec, INDEX_op_smax_vec, 0 + }; + static const GVecGen3 ops[4] = { + { .fniv = gen_saba_vec, + .fno = gen_helper_gvec_saba_b, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_8 }, + { .fniv = gen_saba_vec, + .fno = gen_helper_gvec_saba_h, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_16 }, + { .fni4 = gen_saba_i32, + .fniv = gen_saba_vec, + .fno = gen_helper_gvec_saba_s, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_32 }, + { .fni8 = gen_saba_i64, + .fniv = gen_saba_vec, + .fno = gen_helper_gvec_saba_d, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_64 }, + }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} + +static void gen_uaba_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i32 t = tcg_temp_new_i32(); + gen_uabd_i32(t, a, b); + tcg_gen_add_i32(d, d, t); + tcg_temp_free_i32(t); +} + +static void gen_uaba_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + TCGv_i64 t = tcg_temp_new_i64(); + gen_uabd_i64(t, a, b); + tcg_gen_add_i64(d, d, t); + tcg_temp_free_i64(t); +} + +static void gen_uaba_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + gen_uabd_vec(vece, t, a, b); + tcg_gen_add_vec(vece, d, d, t); + tcg_temp_free_vec(t); +} + +void gen_gvec_uaba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_sub_vec, INDEX_op_add_vec, + INDEX_op_umin_vec, INDEX_op_umax_vec, 0 + }; + static const GVecGen3 ops[4] = { + { .fniv = gen_uaba_vec, + .fno = gen_helper_gvec_uaba_b, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_8 }, + { .fniv = gen_uaba_vec, + .fno = gen_helper_gvec_uaba_h, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_16 }, + { .fni4 = gen_uaba_i32, + .fniv = gen_uaba_vec, + .fno = gen_helper_gvec_uaba_s, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_32 }, + { .fni8 = gen_uaba_i64, + .fniv = gen_uaba_vec, + .fno = gen_helper_gvec_uaba_d, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_64 }, + }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); +} + /* Translate a NEON data processing instruction. Return nonzero if the instruction is invalid. We process data in a mixture of 32-bit and 64-bit chunks. @@ -5366,6 +5484,16 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } return 0; + case NEON_3R_VABA: + if (u) { + gen_gvec_uaba(size, rd_ofs, rn_ofs, rm_ofs, + vec_size, vec_size); + } else { + gen_gvec_saba(size, rd_ofs, rn_ofs, rm_ofs, + vec_size, vec_size); + } + return 0; + case NEON_3R_VADD_VSUB: case NEON_3R_LOGIC: case NEON_3R_VMAX: @@ -5510,12 +5638,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VQRSHL: GEN_NEON_INTEGER_OP_ENV(qrshl); break; - case NEON_3R_VABA: - GEN_NEON_INTEGER_OP(abd); - tcg_temp_free_i32(tmp2); - tmp2 = neon_load_reg(rd, pass); - gen_neon_add(size, tmp, tmp2); - break; case NEON_3R_VPMAX: GEN_NEON_INTEGER_OP(pmax); break; diff --git a/target/arm/translate.h b/target/arm/translate.h index bbfe3d1393..c937dfe9bf 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -342,6 +342,11 @@ void gen_gvec_sabd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, void gen_gvec_uabd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_saba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_uaba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); + /* * Forward to the isar_feature_* tests given a DisasContext pointer. */ diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index a4972d02fc..fa33df859e 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -1431,3 +1431,27 @@ DO_ABD(gvec_uabd_s, uint32_t) DO_ABD(gvec_uabd_d, uint64_t) #undef DO_ABD + +#define DO_ABA(NAME, TYPE) \ +void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \ +{ \ + intptr_t i, opr_sz = simd_oprsz(desc); \ + TYPE *d = vd, *n = vn, *m = vm; \ + \ + for (i = 0; i < opr_sz / sizeof(TYPE); ++i) { \ + d[i] += n[i] < m[i] ? m[i] - n[i] : n[i] - m[i]; \ + } \ + clear_tail(d, opr_sz, simd_maxsz(desc)); \ +} + +DO_ABA(gvec_saba_b, int8_t) +DO_ABA(gvec_saba_h, int16_t) +DO_ABA(gvec_saba_s, int32_t) +DO_ABA(gvec_saba_d, int64_t) + +DO_ABA(gvec_uaba_b, uint8_t) +DO_ABA(gvec_uaba_h, uint16_t) +DO_ABA(gvec_uaba_s, uint32_t) +DO_ABA(gvec_uaba_d, uint64_t) + +#undef DO_ABA From 143b040f4abfafcbb562252df9fb350192ae6160 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Wed, 6 May 2020 13:32:19 -0500 Subject: [PATCH 0437/2595] aspeed: Add support for the sonorapass-bmc board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sonora Pass is a 2 socket x86 motherboard designed by Facebook and supported by OpenBMC. Strapping configuration was obtained from hardware and i2c configuration is based on dts found at: https://github.com/facebook/openbmc-linux/blob/1633c87b8ba7c162095787c988979b748ba65dc8/arch/arm/boot/dts/aspeed-bmc-facebook-sonorapass.dts Booted a test image of http://github.com/facebook/openbmc to login prompt. Signed-off-by: Patrick Williams Reviewed-by: Amithash Prasad Reviewed-by: Cédric Le Goater [PMM: fixed block comment style nit] Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 1eacb2fc17..4d57d1e436 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -73,6 +73,21 @@ struct AspeedBoardState { SCU_AST2500_HW_STRAP_ACPI_ENABLE | \ SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER)) +/* Sonorapass hardware value: 0xF100D216 */ +#define SONORAPASS_BMC_HW_STRAP1 ( \ + SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \ + SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \ + SCU_AST2500_HW_STRAP_UART_DEBUG | \ + SCU_AST2500_HW_STRAP_RESERVED28 | \ + SCU_AST2500_HW_STRAP_DDR4_ENABLE | \ + SCU_HW_STRAP_VGA_CLASS_CODE | \ + SCU_HW_STRAP_LPC_RESET_PIN | \ + SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER) | \ + SCU_AST2500_HW_STRAP_SET_AXI_AHB_RATIO(AXI_AHB_RATIO_2_1) | \ + SCU_HW_STRAP_VGA_BIOS_ROM | \ + SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \ + SCU_AST2500_HW_STRAP_RESERVED1) + /* Swift hardware value: 0xF11AD206 */ #define SWIFT_BMC_HW_STRAP1 ( \ AST2500_HW_STRAP1_DEFAULTS | \ @@ -437,6 +452,50 @@ static void swift_bmc_i2c_init(AspeedBoardState *bmc) i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 12), "tmp105", 0x4a); } +static void sonorapass_bmc_i2c_init(AspeedBoardState *bmc) +{ + AspeedSoCState *soc = &bmc->soc; + + /* bus 2 : */ + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2), "tmp105", 0x48); + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2), "tmp105", 0x49); + /* bus 2 : pca9546 @ 0x73 */ + + /* bus 3 : pca9548 @ 0x70 */ + + /* bus 4 : */ + uint8_t *eeprom4_54 = g_malloc0(8 * 1024); + smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), 0x54, + eeprom4_54); + /* PCA9539 @ 0x76, but PCA9552 is compatible */ + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), "pca9552", 0x76); + /* PCA9539 @ 0x77, but PCA9552 is compatible */ + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), "pca9552", 0x77); + + /* bus 6 : */ + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 6), "tmp105", 0x48); + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 6), "tmp105", 0x49); + /* bus 6 : pca9546 @ 0x73 */ + + /* bus 8 : */ + uint8_t *eeprom8_56 = g_malloc0(8 * 1024); + smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), 0x56, + eeprom8_56); + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "pca9552", 0x60); + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "pca9552", 0x61); + /* bus 8 : adc128d818 @ 0x1d */ + /* bus 8 : adc128d818 @ 0x1f */ + + /* + * bus 13 : pca9548 @ 0x71 + * - channel 3: + * - tmm421 @ 0x4c + * - tmp421 @ 0x4e + * - tmp421 @ 0x4f + */ + +} + static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc) { AspeedSoCState *soc = &bmc->soc; @@ -549,6 +608,21 @@ static void aspeed_machine_romulus_class_init(ObjectClass *oc, void *data) mc->default_ram_size = 512 * MiB; }; +static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "OCP SonoraPass BMC (ARM1176)"; + amc->soc_name = "ast2500-a1"; + amc->hw_strap1 = SONORAPASS_BMC_HW_STRAP1; + amc->fmc_model = "mx66l1g45g"; + amc->spi_model = "mx66l1g45g"; + amc->num_cs = 2; + amc->i2c_init = sonorapass_bmc_i2c_init; + mc->default_ram_size = 512 * MiB; +}; + static void aspeed_machine_swift_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -628,6 +702,10 @@ static const TypeInfo aspeed_machine_types[] = { .name = MACHINE_TYPE_NAME("swift-bmc"), .parent = TYPE_ASPEED_MACHINE, .class_init = aspeed_machine_swift_class_init, + }, { + .name = MACHINE_TYPE_NAME("sonorapass-bmc"), + .parent = TYPE_ASPEED_MACHINE, + .class_init = aspeed_machine_sonorapass_class_init, }, { .name = MACHINE_TYPE_NAME("witherspoon-bmc"), .parent = TYPE_ASPEED_MACHINE, From 1439f213074a8ebc30e6713ce1bf766407ddce46 Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Tue, 12 May 2020 11:06:00 +0800 Subject: [PATCH 0438/2595] acpi: nvdimm: change NVDIMM_UUID_LE to a common macro The little end UUID is used in many places, so make NVDIMM_UUID_LE to a common macro to convert the UUID to a little end array. Reviewed-by: Xiang Zheng Signed-off-by: Dongjiu Geng Message-id: 20200512030609.19593-2-gengdongjiu@huawei.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/acpi/nvdimm.c | 10 +++------- include/qemu/uuid.h | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index fa7bf8b507..9316d12b70 100644 --- a/hw/acpi/nvdimm.c +++ b/hw/acpi/nvdimm.c @@ -27,6 +27,7 @@ */ #include "qemu/osdep.h" +#include "qemu/uuid.h" #include "hw/acpi/acpi.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/bios-linker-loader.h" @@ -34,18 +35,13 @@ #include "hw/mem/nvdimm.h" #include "qemu/nvdimm-utils.h" -#define NVDIMM_UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ - { (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ - (b) & 0xff, ((b) >> 8) & 0xff, (c) & 0xff, ((c) >> 8) & 0xff, \ - (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } - /* * define Byte Addressable Persistent Memory (PM) Region according to * ACPI 6.0: 5.2.25.1 System Physical Address Range Structure. */ static const uint8_t nvdimm_nfit_spa_uuid[] = - NVDIMM_UUID_LE(0x66f0d379, 0xb4f3, 0x4074, 0xac, 0x43, 0x0d, 0x33, - 0x18, 0xb7, 0x8c, 0xdb); + UUID_LE(0x66f0d379, 0xb4f3, 0x4074, 0xac, 0x43, 0x0d, 0x33, + 0x18, 0xb7, 0x8c, 0xdb); /* * NVDIMM Firmware Interface Table diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h index 129c45f2c5..9925febfa5 100644 --- a/include/qemu/uuid.h +++ b/include/qemu/uuid.h @@ -34,6 +34,33 @@ typedef struct { }; } QemuUUID; +/** + * UUID_LE - converts the fields of UUID to little-endian array, + * each of parameters is the filed of UUID. + * + * @time_low: The low field of the timestamp + * @time_mid: The middle field of the timestamp + * @time_hi_and_version: The high field of the timestamp + * multiplexed with the version number + * @clock_seq_hi_and_reserved: The high field of the clock + * sequence multiplexed with the variant + * @clock_seq_low: The low field of the clock sequence + * @node0: The spatially unique node0 identifier + * @node1: The spatially unique node1 identifier + * @node2: The spatially unique node2 identifier + * @node3: The spatially unique node3 identifier + * @node4: The spatially unique node4 identifier + * @node5: The spatially unique node5 identifier + */ +#define UUID_LE(time_low, time_mid, time_hi_and_version, \ + clock_seq_hi_and_reserved, clock_seq_low, node0, node1, node2, \ + node3, node4, node5) \ + { (time_low) & 0xff, ((time_low) >> 8) & 0xff, ((time_low) >> 16) & 0xff, \ + ((time_low) >> 24) & 0xff, (time_mid) & 0xff, ((time_mid) >> 8) & 0xff, \ + (time_hi_and_version) & 0xff, ((time_hi_and_version) >> 8) & 0xff, \ + (clock_seq_hi_and_reserved), (clock_seq_low), (node0), (node1), (node2),\ + (node3), (node4), (node5) } + #define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-" \ "%02hhx%02hhx-%02hhx%02hhx-" \ "%02hhx%02hhx-" \ From 2afa8c85192595e2b6a61e2045df7bea66bdea08 Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Tue, 12 May 2020 11:06:01 +0800 Subject: [PATCH 0439/2595] hw/arm/virt: Introduce a RAS machine option RAS Virtualization feature is not supported now, so add a RAS machine option and disable it by default. Reviewed-by: Peter Maydell Signed-off-by: Dongjiu Geng Signed-off-by: Xiang Zheng Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Message-id: 20200512030609.19593-3-gengdongjiu@huawei.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 23 +++++++++++++++++++++++ include/hw/arm/virt.h | 1 + 2 files changed, 24 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 634db0cfe9..9e76fa7b01 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1995,6 +1995,20 @@ static void virt_set_acpi(Object *obj, Visitor *v, const char *name, visit_type_OnOffAuto(v, name, &vms->acpi, errp); } +static bool virt_get_ras(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->ras; +} + +static void virt_set_ras(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->ras = value; +} + static char *virt_get_gic_version(Object *obj, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -2327,6 +2341,15 @@ static void virt_instance_init(Object *obj) "Valid values are none and smmuv3", NULL); + /* Default disallows RAS instantiation */ + vms->ras = false; + object_property_add_bool(obj, "ras", virt_get_ras, + virt_set_ras, NULL); + object_property_set_description(obj, "ras", + "Set on/off to enable/disable reporting host memory errors " + "to a KVM guest using ACPI and guest external abort exceptions", + NULL); + vms->irqmap = a15irqmap; virt_flash_create(vms); diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 6d67ace76e..31878ddc72 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -132,6 +132,7 @@ typedef struct { bool highmem_ecam; bool its; bool virt; + bool ras; OnOffAuto acpi; VirtGICType gic_version; VirtIOMMUType iommu; From 5fb004a2650dde16ac41b7ee801fc30961524821 Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Tue, 12 May 2020 11:06:02 +0800 Subject: [PATCH 0440/2595] docs: APEI GHES generation and CPER record description Add APEI/GHES detailed design document Signed-off-by: Dongjiu Geng Signed-off-by: Xiang Zheng Reviewed-by: Michael S. Tsirkin Reviewed-by: Igor Mammedov Message-id: 20200512030609.19593-4-gengdongjiu@huawei.com Signed-off-by: Peter Maydell --- docs/specs/acpi_hest_ghes.rst | 110 ++++++++++++++++++++++++++++++++++ docs/specs/index.rst | 1 + 2 files changed, 111 insertions(+) create mode 100644 docs/specs/acpi_hest_ghes.rst diff --git a/docs/specs/acpi_hest_ghes.rst b/docs/specs/acpi_hest_ghes.rst new file mode 100644 index 0000000000..68f1fbe0a4 --- /dev/null +++ b/docs/specs/acpi_hest_ghes.rst @@ -0,0 +1,110 @@ +APEI tables generating and CPER record +====================================== + +.. + Copyright (c) 2020 HUAWEI TECHNOLOGIES CO., LTD. + + This work is licensed under the terms of the GNU GPL, version 2 or later. + See the COPYING file in the top-level directory. + +Design Details +-------------- + +:: + + etc/acpi/tables etc/hardware_errors + ==================== =============================== + + +--------------------------+ +----------------------------+ + | | HEST | +--------->| error_block_address1 |------+ + | +--------------------------+ | +----------------------------+ | + | | GHES1 | | +------->| error_block_address2 |------+-+ + | +--------------------------+ | | +----------------------------+ | | + | | ................. | | | | .............. | | | + | | error_status_address-----+-+ | -----------------------------+ | | + | | ................. | | +--->| error_block_addressN |------+-+---+ + | | read_ack_register--------+-+ | | +----------------------------+ | | | + | | read_ack_preserve | +-+---+--->| read_ack_register1 | | | | + | | read_ack_write | | | +----------------------------+ | | | + + +--------------------------+ | +-+--->| read_ack_register2 | | | | + | | GHES2 | | | | +----------------------------+ | | | + + +--------------------------+ | | | | ............. | | | | + | | ................. | | | | +----------------------------+ | | | + | | error_status_address-----+---+ | | +->| read_ack_registerN | | | | + | | ................. | | | | +----------------------------+ | | | + | | read_ack_register--------+-----+ | | |Generic Error Status Block 1|<-----+ | | + | | read_ack_preserve | | | |-+------------------------+-+ | | + | | read_ack_write | | | | | CPER | | | | + + +--------------------------| | | | | CPER | | | | + | | ............... | | | | | .... | | | | + + +--------------------------+ | | | | CPER | | | | + | | GHESN | | | |-+------------------------+-| | | + + +--------------------------+ | | |Generic Error Status Block 2|<-------+ | + | | ................. | | | |-+------------------------+-+ | + | | error_status_address-----+-------+ | | | CPER | | | + | | ................. | | | | CPER | | | + | | read_ack_register--------+---------+ | | .... | | | + | | read_ack_preserve | | | CPER | | | + | | read_ack_write | +-+------------------------+-+ | + + +--------------------------+ | .......... | | + |----------------------------+ | + |Generic Error Status Block N |<----------+ + |-+-------------------------+-+ + | | CPER | | + | | CPER | | + | | .... | | + | | CPER | | + +-+-------------------------+-+ + + +(1) QEMU generates the ACPI HEST table. This table goes in the current + "etc/acpi/tables" fw_cfg blob. Each error source has different + notification types. + +(2) A new fw_cfg blob called "etc/hardware_errors" is introduced. QEMU + also needs to populate this blob. The "etc/hardware_errors" fw_cfg blob + contains an address registers table and an Error Status Data Block table. + +(3) The address registers table contains N Error Block Address entries + and N Read Ack Register entries. The size for each entry is 8-byte. + The Error Status Data Block table contains N Error Status Data Block + entries. The size for each entry is 4096(0x1000) bytes. The total size + for the "etc/hardware_errors" fw_cfg blob is (N * 8 * 2 + N * 4096) bytes. + N is the number of the kinds of hardware error sources. + +(4) QEMU generates the ACPI linker/loader script for the firmware. The + firmware pre-allocates memory for "etc/acpi/tables", "etc/hardware_errors" + and copies blob contents there. + +(5) QEMU generates N ADD_POINTER commands, which patch addresses in the + "error_status_address" fields of the HEST table with a pointer to the + corresponding "address registers" in the "etc/hardware_errors" blob. + +(6) QEMU generates N ADD_POINTER commands, which patch addresses in the + "read_ack_register" fields of the HEST table with a pointer to the + corresponding "read_ack_register" within the "etc/hardware_errors" blob. + +(7) QEMU generates N ADD_POINTER commands for the firmware, which patch + addresses in the "error_block_address" fields with a pointer to the + respective "Error Status Data Block" in the "etc/hardware_errors" blob. + +(8) QEMU defines a third and write-only fw_cfg blob which is called + "etc/hardware_errors_addr". Through that blob, the firmware can send back + the guest-side allocation addresses to QEMU. The "etc/hardware_errors_addr" + blob contains a 8-byte entry. QEMU generates a single WRITE_POINTER command + for the firmware. The firmware will write back the start address of + "etc/hardware_errors" blob to the fw_cfg file "etc/hardware_errors_addr". + +(9) When QEMU gets a SIGBUS from the kernel, QEMU writes CPER into corresponding + "Error Status Data Block", guest memory, and then injects platform specific + interrupt (in case of arm/virt machine it's Synchronous External Abort) as a + notification which is necessary for notifying the guest. + +(10) This notification (in virtual hardware) will be handled by the guest + kernel, on receiving notification, guest APEI driver could read the CPER error + and take appropriate action. + +(11) kvm_arch_on_sigbus_vcpu() uses source_id as index in "etc/hardware_errors" to + find out "Error Status Data Block" entry corresponding to error source. So supported + source_id values should be assigned here and not be changed afterwards to make sure + that guest will write error into expected "Error Status Data Block" even if guest was + migrated to a newer QEMU. diff --git a/docs/specs/index.rst b/docs/specs/index.rst index de46a8b5e7..426632a475 100644 --- a/docs/specs/index.rst +++ b/docs/specs/index.rst @@ -14,3 +14,4 @@ Contents: ppc-spapr-xive acpi_hw_reduced_hotplug tpm + acpi_hest_ghes From aa16508f1d1bce2411fdbe82aa20e559bbd90e48 Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Tue, 12 May 2020 11:06:03 +0800 Subject: [PATCH 0441/2595] ACPI: Build related register address fields via hardware error fw_cfg blob This patch builds error_block_address and read_ack_register fields in hardware errors table , the error_block_address points to Generic Error Status Block(GESB) via bios_linker. The max size for one GESB is 1kb, For more detailed information, please refer to document: docs/specs/acpi_hest_ghes.rst Now we only support one Error source, if necessary, we can extend to support more. Suggested-by: Laszlo Ersek Signed-off-by: Xiang Zheng Reviewed-by: Jonathan Cameron Reviewed-by: Igor Mammedov Signed-off-by: Dongjiu Geng Reviewed-by: Michael S. Tsirkin Message-id: 20200512030609.19593-5-gengdongjiu@huawei.com Signed-off-by: Peter Maydell --- default-configs/arm-softmmu.mak | 1 + hw/acpi/Kconfig | 4 ++ hw/acpi/Makefile.objs | 1 + hw/acpi/aml-build.c | 2 + hw/acpi/ghes.c | 89 +++++++++++++++++++++++++++++++++ hw/arm/virt-acpi-build.c | 5 ++ include/hw/acpi/aml-build.h | 1 + include/hw/acpi/ghes.h | 28 +++++++++++ 8 files changed, 131 insertions(+) create mode 100644 hw/acpi/ghes.c create mode 100644 include/hw/acpi/ghes.h diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 36a0e89daa..8fc09a4a51 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -42,3 +42,4 @@ CONFIG_FSL_IMX7=y CONFIG_FSL_IMX6UL=y CONFIG_SEMIHOSTING=y CONFIG_ALLWINNER_H3=y +CONFIG_ACPI_APEI=y diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 54209c6f2f..1932f66af8 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -28,6 +28,10 @@ config ACPI_HMAT bool depends on ACPI +config ACPI_APEI + bool + depends on ACPI + config ACPI_PCI bool depends on ACPI && PCI diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs index cab9bcd457..72886c7965 100644 --- a/hw/acpi/Makefile.objs +++ b/hw/acpi/Makefile.objs @@ -8,6 +8,7 @@ common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o common-obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device.o common-obj-$(CONFIG_ACPI_HMAT) += hmat.o +common-obj-$(CONFIG_ACPI_APEI) += ghes.o common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o common-obj-$(call lnot,$(CONFIG_PC)) += acpi-x86-stub.o diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 2c3702b882..3681ec6e3d 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1578,6 +1578,7 @@ void acpi_build_tables_init(AcpiBuildTables *tables) tables->table_data = g_array_new(false, true /* clear */, 1); tables->tcpalog = g_array_new(false, true /* clear */, 1); tables->vmgenid = g_array_new(false, true /* clear */, 1); + tables->hardware_errors = g_array_new(false, true /* clear */, 1); tables->linker = bios_linker_loader_init(); } @@ -1588,6 +1589,7 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre) g_array_free(tables->table_data, true); g_array_free(tables->tcpalog, mfre); g_array_free(tables->vmgenid, mfre); + g_array_free(tables->hardware_errors, mfre); } /* diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c new file mode 100644 index 0000000000..e1b3f8fcaa --- /dev/null +++ b/hw/acpi/ghes.c @@ -0,0 +1,89 @@ +/* + * Support for generating APEI tables and recording CPER for Guests + * + * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO., LTD. + * + * Author: Dongjiu Geng + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "hw/acpi/ghes.h" +#include "hw/acpi/aml-build.h" + +#define ACPI_GHES_ERRORS_FW_CFG_FILE "etc/hardware_errors" +#define ACPI_GHES_DATA_ADDR_FW_CFG_FILE "etc/hardware_errors_addr" + +/* The max size in bytes for one error block */ +#define ACPI_GHES_MAX_RAW_DATA_LENGTH (1 * KiB) + +/* Now only support ARMv8 SEA notification type error source */ +#define ACPI_GHES_ERROR_SOURCE_COUNT 1 + +/* + * Build table for the hardware error fw_cfg blob. + * Initialize "etc/hardware_errors" and "etc/hardware_errors_addr" fw_cfg blobs. + * See docs/specs/acpi_hest_ghes.rst for blobs format. + */ +void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker) +{ + int i, error_status_block_offset; + + /* Build error_block_address */ + for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { + build_append_int_noprefix(hardware_errors, 0, sizeof(uint64_t)); + } + + /* Build read_ack_register */ + for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { + /* + * Initialize the value of read_ack_register to 1, so GHES can be + * writeable after (re)boot. + * ACPI 6.2: 18.3.2.8 Generic Hardware Error Source version 2 + * (GHESv2 - Type 10) + */ + build_append_int_noprefix(hardware_errors, 1, sizeof(uint64_t)); + } + + /* Generic Error Status Block offset in the hardware error fw_cfg blob */ + error_status_block_offset = hardware_errors->len; + + /* Reserve space for Error Status Data Block */ + acpi_data_push(hardware_errors, + ACPI_GHES_MAX_RAW_DATA_LENGTH * ACPI_GHES_ERROR_SOURCE_COUNT); + + /* Tell guest firmware to place hardware_errors blob into RAM */ + bios_linker_loader_alloc(linker, ACPI_GHES_ERRORS_FW_CFG_FILE, + hardware_errors, sizeof(uint64_t), false); + + for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { + /* + * Tell firmware to patch error_block_address entries to point to + * corresponding "Generic Error Status Block" + */ + bios_linker_loader_add_pointer(linker, + ACPI_GHES_ERRORS_FW_CFG_FILE, sizeof(uint64_t) * i, + sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, + error_status_block_offset + i * ACPI_GHES_MAX_RAW_DATA_LENGTH); + } + + /* + * tell firmware to write hardware_errors GPA into + * hardware_errors_addr fw_cfg, once the former has been initialized. + */ + bios_linker_loader_write_pointer(linker, ACPI_GHES_DATA_ADDR_FW_CFG_FILE, + 0, sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, 0); +} diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index f22b1e6097..8397bda424 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -49,6 +49,7 @@ #include "sysemu/reset.h" #include "kvm_arm.h" #include "migration/vmstate.h" +#include "hw/acpi/ghes.h" #define ARM_SPI_BASE 32 @@ -818,6 +819,10 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_spcr(tables_blob, tables->linker, vms); + if (vms->ras) { + build_ghes_error_table(tables->hardware_errors, tables->linker); + } + if (ms->numa_state->num_nodes > 0) { acpi_add_table(table_offsets, tables_blob); build_srat(tables_blob, tables->linker, vms); diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index 1539fe0667..ed7c89309e 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -220,6 +220,7 @@ struct AcpiBuildTables { GArray *rsdp; GArray *tcpalog; GArray *vmgenid; + GArray *hardware_errors; BIOSLinker *linker; } AcpiBuildTables; diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h new file mode 100644 index 0000000000..50379b0d0a --- /dev/null +++ b/include/hw/acpi/ghes.h @@ -0,0 +1,28 @@ +/* + * Support for generating APEI tables and recording CPER for Guests + * + * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO., LTD. + * + * Author: Dongjiu Geng + * + * 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 . + */ + +#ifndef ACPI_GHES_H +#define ACPI_GHES_H + +#include "hw/acpi/bios-linker-loader.h" + +void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker); +#endif From 205cc75deec196bb3266a0dac407a195a646b5fc Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Tue, 12 May 2020 11:06:04 +0800 Subject: [PATCH 0442/2595] ACPI: Build Hardware Error Source Table This patch builds Hardware Error Source Table(HEST) via fw_cfg blobs. Now it only supports ARMv8 SEA, a type of Generic Hardware Error Source version 2(GHESv2) error source. Afterwards, we can extend the supported types if needed. For the CPER section, currently it is memory section because kernel mainly wants userspace to handle the memory errors. This patch follows the spec ACPI 6.2 to build the Hardware Error Source table. For more detailed information, please refer to document: docs/specs/acpi_hest_ghes.rst build_ghes_hw_error_notification() helper will help to add Hardware Error Notification to ACPI tables without using packed C structures and avoid endianness issues as API doesn't need explicit conversion. Signed-off-by: Xiang Zheng Signed-off-by: Dongjiu Geng Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Message-id: 20200512030609.19593-6-gengdongjiu@huawei.com Signed-off-by: Peter Maydell --- hw/acpi/ghes.c | 126 +++++++++++++++++++++++++++++++++++++++ hw/arm/virt-acpi-build.c | 2 + include/hw/acpi/ghes.h | 39 ++++++++++++ 3 files changed, 167 insertions(+) diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index e1b3f8fcaa..091fd87094 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -23,6 +23,7 @@ #include "qemu/units.h" #include "hw/acpi/ghes.h" #include "hw/acpi/aml-build.h" +#include "qemu/error-report.h" #define ACPI_GHES_ERRORS_FW_CFG_FILE "etc/hardware_errors" #define ACPI_GHES_DATA_ADDR_FW_CFG_FILE "etc/hardware_errors_addr" @@ -33,6 +34,42 @@ /* Now only support ARMv8 SEA notification type error source */ #define ACPI_GHES_ERROR_SOURCE_COUNT 1 +/* Generic Hardware Error Source version 2 */ +#define ACPI_GHES_SOURCE_GENERIC_ERROR_V2 10 + +/* Address offset in Generic Address Structure(GAS) */ +#define GAS_ADDR_OFFSET 4 + +/* + * Hardware Error Notification + * ACPI 4.0: 17.3.2.7 Hardware Error Notification + * Composes dummy Hardware Error Notification descriptor of specified type + */ +static void build_ghes_hw_error_notification(GArray *table, const uint8_t type) +{ + /* Type */ + build_append_int_noprefix(table, type, 1); + /* + * Length: + * Total length of the structure in bytes + */ + build_append_int_noprefix(table, 28, 1); + /* Configuration Write Enable */ + build_append_int_noprefix(table, 0, 2); + /* Poll Interval */ + build_append_int_noprefix(table, 0, 4); + /* Vector */ + build_append_int_noprefix(table, 0, 4); + /* Switch To Polling Threshold Value */ + build_append_int_noprefix(table, 0, 4); + /* Switch To Polling Threshold Window */ + build_append_int_noprefix(table, 0, 4); + /* Error Threshold Value */ + build_append_int_noprefix(table, 0, 4); + /* Error Threshold Window */ + build_append_int_noprefix(table, 0, 4); +} + /* * Build table for the hardware error fw_cfg blob. * Initialize "etc/hardware_errors" and "etc/hardware_errors_addr" fw_cfg blobs. @@ -87,3 +124,92 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker) bios_linker_loader_write_pointer(linker, ACPI_GHES_DATA_ADDR_FW_CFG_FILE, 0, sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, 0); } + +/* Build Generic Hardware Error Source version 2 (GHESv2) */ +static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker) +{ + uint64_t address_offset; + /* + * Type: + * Generic Hardware Error Source version 2(GHESv2 - Type 10) + */ + build_append_int_noprefix(table_data, ACPI_GHES_SOURCE_GENERIC_ERROR_V2, 2); + /* Source Id */ + build_append_int_noprefix(table_data, source_id, 2); + /* Related Source Id */ + build_append_int_noprefix(table_data, 0xffff, 2); + /* Flags */ + build_append_int_noprefix(table_data, 0, 1); + /* Enabled */ + build_append_int_noprefix(table_data, 1, 1); + + /* Number of Records To Pre-allocate */ + build_append_int_noprefix(table_data, 1, 4); + /* Max Sections Per Record */ + build_append_int_noprefix(table_data, 1, 4); + /* Max Raw Data Length */ + build_append_int_noprefix(table_data, ACPI_GHES_MAX_RAW_DATA_LENGTH, 4); + + address_offset = table_data->len; + /* Error Status Address */ + build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 0x40, 0, + 4 /* QWord access */, 0); + bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, + address_offset + GAS_ADDR_OFFSET, sizeof(uint64_t), + ACPI_GHES_ERRORS_FW_CFG_FILE, source_id * sizeof(uint64_t)); + + switch (source_id) { + case ACPI_HEST_SRC_ID_SEA: + /* + * Notification Structure + * Now only enable ARMv8 SEA notification type + */ + build_ghes_hw_error_notification(table_data, ACPI_GHES_NOTIFY_SEA); + break; + default: + error_report("Not support this error source"); + abort(); + } + + /* Error Status Block Length */ + build_append_int_noprefix(table_data, ACPI_GHES_MAX_RAW_DATA_LENGTH, 4); + + /* + * Read Ack Register + * ACPI 6.1: 18.3.2.8 Generic Hardware Error Source + * version 2 (GHESv2 - Type 10) + */ + address_offset = table_data->len; + build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 0x40, 0, + 4 /* QWord access */, 0); + bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, + address_offset + GAS_ADDR_OFFSET, + sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, + (ACPI_GHES_ERROR_SOURCE_COUNT + source_id) * sizeof(uint64_t)); + + /* + * Read Ack Preserve field + * We only provide the first bit in Read Ack Register to OSPM to write + * while the other bits are preserved. + */ + build_append_int_noprefix(table_data, ~0x1ULL, 8); + /* Read Ack Write */ + build_append_int_noprefix(table_data, 0x1, 8); +} + +/* Build Hardware Error Source Table */ +void acpi_build_hest(GArray *table_data, BIOSLinker *linker) +{ + uint64_t hest_start = table_data->len; + + /* Hardware Error Source Table header*/ + acpi_data_push(table_data, sizeof(AcpiTableHeader)); + + /* Error Source Count */ + build_append_int_noprefix(table_data, ACPI_GHES_ERROR_SOURCE_COUNT, 4); + + build_ghes_v2(table_data, ACPI_HEST_SRC_ID_SEA, linker); + + build_header(linker, table_data, (void *)(table_data->data + hest_start), + "HEST", table_data->len - hest_start, 1, NULL, NULL); +} diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 8397bda424..ef94e034f6 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -821,6 +821,8 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) if (vms->ras) { build_ghes_error_table(tables->hardware_errors, tables->linker); + acpi_add_table(table_offsets, tables_blob); + acpi_build_hest(tables_blob, tables->linker); } if (ms->numa_state->num_nodes > 0) { diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h index 50379b0d0a..18debd8cf7 100644 --- a/include/hw/acpi/ghes.h +++ b/include/hw/acpi/ghes.h @@ -24,5 +24,44 @@ #include "hw/acpi/bios-linker-loader.h" +/* + * Values for Hardware Error Notification Type field + */ +enum AcpiGhesNotifyType { + /* Polled */ + ACPI_GHES_NOTIFY_POLLED = 0, + /* External Interrupt */ + ACPI_GHES_NOTIFY_EXTERNAL = 1, + /* Local Interrupt */ + ACPI_GHES_NOTIFY_LOCAL = 2, + /* SCI */ + ACPI_GHES_NOTIFY_SCI = 3, + /* NMI */ + ACPI_GHES_NOTIFY_NMI = 4, + /* CMCI, ACPI 5.0: 18.3.2.7, Table 18-290 */ + ACPI_GHES_NOTIFY_CMCI = 5, + /* MCE, ACPI 5.0: 18.3.2.7, Table 18-290 */ + ACPI_GHES_NOTIFY_MCE = 6, + /* GPIO-Signal, ACPI 6.0: 18.3.2.7, Table 18-332 */ + ACPI_GHES_NOTIFY_GPIO = 7, + /* ARMv8 SEA, ACPI 6.1: 18.3.2.9, Table 18-345 */ + ACPI_GHES_NOTIFY_SEA = 8, + /* ARMv8 SEI, ACPI 6.1: 18.3.2.9, Table 18-345 */ + ACPI_GHES_NOTIFY_SEI = 9, + /* External Interrupt - GSIV, ACPI 6.1: 18.3.2.9, Table 18-345 */ + ACPI_GHES_NOTIFY_GSIV = 10, + /* Software Delegated Exception, ACPI 6.2: 18.3.2.9, Table 18-383 */ + ACPI_GHES_NOTIFY_SDEI = 11, + /* 12 and greater are reserved */ + ACPI_GHES_NOTIFY_RESERVED = 12 +}; + +enum { + ACPI_HEST_SRC_ID_SEA = 0, + /* future ids go here */ + ACPI_HEST_SRC_ID_RESERVED, +}; + void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker); +void acpi_build_hest(GArray *table_data, BIOSLinker *linker); #endif From a08a64627b6b5874f3dbf202fb08563e7a74b1ea Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Tue, 12 May 2020 11:06:05 +0800 Subject: [PATCH 0443/2595] ACPI: Record the Generic Error Status Block address Record the GHEB address via fw_cfg file, when recording a error to CPER, it will use this address to find out Generic Error Data Entries and write the error. In order to avoid migration failure, make hardware error table address to a part of GED device instead of global variable, then this address will be migrated to target QEMU. Acked-by: Xiang Zheng Signed-off-by: Dongjiu Geng Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Message-id: 20200512030609.19593-7-gengdongjiu@huawei.com Signed-off-by: Peter Maydell --- hw/acpi/generic_event_device.c | 19 +++++++++++++++++++ hw/acpi/ghes.c | 14 ++++++++++++++ hw/arm/virt-acpi-build.c | 8 ++++++++ include/hw/acpi/generic_event_device.h | 2 ++ include/hw/acpi/ghes.h | 6 ++++++ 5 files changed, 49 insertions(+) diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index 5d17f78a1e..b1cbdd86b6 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -247,6 +247,24 @@ static const VMStateDescription vmstate_ged_state = { } }; +static bool ghes_needed(void *opaque) +{ + AcpiGedState *s = opaque; + return s->ghes_state.ghes_addr_le; +} + +static const VMStateDescription vmstate_ghes_state = { + .name = "acpi-ged/ghes", + .version_id = 1, + .minimum_version_id = 1, + .needed = ghes_needed, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(ghes_state, AcpiGedState, 1, + vmstate_ghes_state, AcpiGhesState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_acpi_ged = { .name = "acpi-ged", .version_id = 1, @@ -257,6 +275,7 @@ static const VMStateDescription vmstate_acpi_ged = { }, .subsections = (const VMStateDescription * []) { &vmstate_memhp_state, + &vmstate_ghes_state, NULL } }; diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index 091fd87094..e74af23c36 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -24,6 +24,8 @@ #include "hw/acpi/ghes.h" #include "hw/acpi/aml-build.h" #include "qemu/error-report.h" +#include "hw/acpi/generic_event_device.h" +#include "hw/nvram/fw_cfg.h" #define ACPI_GHES_ERRORS_FW_CFG_FILE "etc/hardware_errors" #define ACPI_GHES_DATA_ADDR_FW_CFG_FILE "etc/hardware_errors_addr" @@ -213,3 +215,15 @@ void acpi_build_hest(GArray *table_data, BIOSLinker *linker) build_header(linker, table_data, (void *)(table_data->data + hest_start), "HEST", table_data->len - hest_start, 1, NULL, NULL); } + +void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s, + GArray *hardware_error) +{ + /* Create a read-only fw_cfg file for GHES */ + fw_cfg_add_file(s, ACPI_GHES_ERRORS_FW_CFG_FILE, hardware_error->data, + hardware_error->len); + + /* Create a read-write fw_cfg file for Address */ + fw_cfg_add_file_callback(s, ACPI_GHES_DATA_ADDR_FW_CFG_FILE, NULL, NULL, + NULL, &(ags->ghes_addr_le), sizeof(ags->ghes_addr_le), false); +} diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index ef94e034f6..1b0a584c7b 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -917,6 +917,7 @@ void virt_acpi_setup(VirtMachineState *vms) { AcpiBuildTables tables; AcpiBuildState *build_state; + AcpiGedState *acpi_ged_state; if (!vms->fw_cfg) { trace_virt_acpi_setup(); @@ -947,6 +948,13 @@ void virt_acpi_setup(VirtMachineState *vms) fw_cfg_add_file(vms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, acpi_data_len(tables.tcpalog)); + if (vms->ras) { + assert(vms->acpi_dev); + acpi_ged_state = ACPI_GED(vms->acpi_dev); + acpi_ghes_add_fw_cfg(&acpi_ged_state->ghes_state, + vms->fw_cfg, tables.hardware_errors); + } + build_state->rsdp_mr = acpi_add_rom_blob(virt_acpi_build_update, build_state, tables.rsdp, ACPI_BUILD_RSDP_FILE, 0); diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h index 9eb86ca4fd..83917de024 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h @@ -61,6 +61,7 @@ #include "hw/sysbus.h" #include "hw/acpi/memory_hotplug.h" +#include "hw/acpi/ghes.h" #define ACPI_POWER_BUTTON_DEVICE "PWRB" @@ -96,6 +97,7 @@ typedef struct AcpiGedState { GEDState ged_state; uint32_t ged_event_bitmap; qemu_irq irq; + AcpiGhesState ghes_state; } AcpiGedState; void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev, diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h index 18debd8cf7..a3420fc9be 100644 --- a/include/hw/acpi/ghes.h +++ b/include/hw/acpi/ghes.h @@ -62,6 +62,12 @@ enum { ACPI_HEST_SRC_ID_RESERVED, }; +typedef struct AcpiGhesState { + uint64_t ghes_addr_le; +} AcpiGhesState; + void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker); void acpi_build_hest(GArray *table_data, BIOSLinker *linker); +void acpi_ghes_add_fw_cfg(AcpiGhesState *vms, FWCfgState *s, + GArray *hardware_errors); #endif From 6b552b9bc8421c48e91c9a40ce5dccf78020c339 Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Tue, 12 May 2020 11:06:06 +0800 Subject: [PATCH 0444/2595] KVM: Move hwpoison page related functions into kvm-all.c kvm_hwpoison_page_add() and kvm_unpoison_all() will both be used by X86 and ARM platforms, so moving them into "accel/kvm/kvm-all.c" to avoid duplicate code. For architectures that don't use the poison-list functionality the reset handler will harmlessly do nothing, so let's register the kvm_unpoison_all() function in the generic kvm_init() function. Reviewed-by: Peter Maydell Signed-off-by: Dongjiu Geng Signed-off-by: Xiang Zheng Acked-by: Xiang Zheng Message-id: 20200512030609.19593-8-gengdongjiu@huawei.com Signed-off-by: Peter Maydell --- accel/kvm/kvm-all.c | 36 ++++++++++++++++++++++++++++++++++++ include/sysemu/kvm_int.h | 12 ++++++++++++ target/i386/kvm.c | 36 ------------------------------------ 3 files changed, 48 insertions(+), 36 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 439a4efe52..36be11795d 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -44,6 +44,7 @@ #include "qapi/visitor.h" #include "qapi/qapi-types-common.h" #include "qapi/qapi-visit-common.h" +#include "sysemu/reset.h" #include "hw/boards.h" @@ -883,6 +884,39 @@ int kvm_vm_check_extension(KVMState *s, unsigned int extension) return ret; } +typedef struct HWPoisonPage { + ram_addr_t ram_addr; + QLIST_ENTRY(HWPoisonPage) list; +} HWPoisonPage; + +static QLIST_HEAD(, HWPoisonPage) hwpoison_page_list = + QLIST_HEAD_INITIALIZER(hwpoison_page_list); + +static void kvm_unpoison_all(void *param) +{ + HWPoisonPage *page, *next_page; + + QLIST_FOREACH_SAFE(page, &hwpoison_page_list, list, next_page) { + QLIST_REMOVE(page, list); + qemu_ram_remap(page->ram_addr, TARGET_PAGE_SIZE); + g_free(page); + } +} + +void kvm_hwpoison_page_add(ram_addr_t ram_addr) +{ + HWPoisonPage *page; + + QLIST_FOREACH(page, &hwpoison_page_list, list) { + if (page->ram_addr == ram_addr) { + return; + } + } + page = g_new(HWPoisonPage, 1); + page->ram_addr = ram_addr; + QLIST_INSERT_HEAD(&hwpoison_page_list, page, list); +} + static uint32_t adjust_ioeventfd_endianness(uint32_t val, uint32_t size) { #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) @@ -2085,6 +2119,8 @@ static int kvm_init(MachineState *ms) s->kernel_irqchip_split = mc->default_kernel_irqchip_split ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; } + qemu_register_reset(kvm_unpoison_all, NULL); + if (s->kernel_irqchip_allowed) { kvm_irqchip_create(s); } diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index ac2d1f8b56..c660a70c51 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -42,4 +42,16 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, AddressSpace *as, int as_id); void kvm_set_max_memslot_size(hwaddr max_slot_size); + +/** + * kvm_hwpoison_page_add: + * + * Parameters: + * @ram_addr: the address in the RAM for the poisoned page + * + * Add a poisoned page to the list + * + * Return: None. + */ +void kvm_hwpoison_page_add(ram_addr_t ram_addr); #endif diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 4901c6dd74..34f838728d 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -24,7 +24,6 @@ #include "sysemu/sysemu.h" #include "sysemu/hw_accel.h" #include "sysemu/kvm_int.h" -#include "sysemu/reset.h" #include "sysemu/runstate.h" #include "kvm_i386.h" #include "hyperv.h" @@ -533,40 +532,6 @@ uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index) } } - -typedef struct HWPoisonPage { - ram_addr_t ram_addr; - QLIST_ENTRY(HWPoisonPage) list; -} HWPoisonPage; - -static QLIST_HEAD(, HWPoisonPage) hwpoison_page_list = - QLIST_HEAD_INITIALIZER(hwpoison_page_list); - -static void kvm_unpoison_all(void *param) -{ - HWPoisonPage *page, *next_page; - - QLIST_FOREACH_SAFE(page, &hwpoison_page_list, list, next_page) { - QLIST_REMOVE(page, list); - qemu_ram_remap(page->ram_addr, TARGET_PAGE_SIZE); - g_free(page); - } -} - -static void kvm_hwpoison_page_add(ram_addr_t ram_addr) -{ - HWPoisonPage *page; - - QLIST_FOREACH(page, &hwpoison_page_list, list) { - if (page->ram_addr == ram_addr) { - return; - } - } - page = g_new(HWPoisonPage, 1); - page->ram_addr = ram_addr; - QLIST_INSERT_HEAD(&hwpoison_page_list, page, list); -} - static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap, int *max_banks) { @@ -2180,7 +2145,6 @@ int kvm_arch_init(MachineState *ms, KVMState *s) fprintf(stderr, "e820_add_entry() table is full\n"); return ret; } - qemu_register_reset(kvm_unpoison_all, NULL); shadow_mem = object_property_get_int(OBJECT(s), "kvm-shadow-mem", &error_abort); if (shadow_mem != -1) { From 558b9d86407d56e13d8a2cd61cdecf0359e7804a Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Tue, 12 May 2020 11:06:07 +0800 Subject: [PATCH 0445/2595] ACPI: Record Generic Error Status Block(GESB) table kvm_arch_on_sigbus_vcpu() error injection uses source_id as index in etc/hardware_errors to find out Error Status Data Block entry corresponding to error source. So supported source_id values should be assigned here and not be changed afterwards to make sure that guest will write error into expected Error Status Data Block. Before QEMU writes a new error to ACPI table, it will check whether previous error has been acknowledged. If not acknowledged, the new errors will be ignored and not be recorded. For the errors section type, QEMU simulate it to memory section error. Signed-off-by: Dongjiu Geng Signed-off-by: Xiang Zheng Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Message-id: 20200512030609.19593-9-gengdongjiu@huawei.com Signed-off-by: Peter Maydell --- hw/acpi/ghes.c | 219 +++++++++++++++++++++++++++++++++++++++++ include/hw/acpi/ghes.h | 1 + 2 files changed, 220 insertions(+) diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index e74af23c36..b363bc331d 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -26,6 +26,7 @@ #include "qemu/error-report.h" #include "hw/acpi/generic_event_device.h" #include "hw/nvram/fw_cfg.h" +#include "qemu/uuid.h" #define ACPI_GHES_ERRORS_FW_CFG_FILE "etc/hardware_errors" #define ACPI_GHES_DATA_ADDR_FW_CFG_FILE "etc/hardware_errors_addr" @@ -42,6 +43,36 @@ /* Address offset in Generic Address Structure(GAS) */ #define GAS_ADDR_OFFSET 4 +/* + * The total size of Generic Error Data Entry + * ACPI 6.1/6.2: 18.3.2.7.1 Generic Error Data, + * Table 18-343 Generic Error Data Entry + */ +#define ACPI_GHES_DATA_LENGTH 72 + +/* The memory section CPER size, UEFI 2.6: N.2.5 Memory Error Section */ +#define ACPI_GHES_MEM_CPER_LENGTH 80 + +/* Masks for block_status flags */ +#define ACPI_GEBS_UNCORRECTABLE 1 + +/* + * Total size for Generic Error Status Block except Generic Error Data Entries + * ACPI 6.2: 18.3.2.7.1 Generic Error Data, + * Table 18-380 Generic Error Status Block + */ +#define ACPI_GHES_GESB_SIZE 20 + +/* + * Values for error_severity field + */ +enum AcpiGenericErrorSeverity { + ACPI_CPER_SEV_RECOVERABLE = 0, + ACPI_CPER_SEV_FATAL = 1, + ACPI_CPER_SEV_CORRECTED = 2, + ACPI_CPER_SEV_NONE = 3, +}; + /* * Hardware Error Notification * ACPI 4.0: 17.3.2.7 Hardware Error Notification @@ -72,6 +103,138 @@ static void build_ghes_hw_error_notification(GArray *table, const uint8_t type) build_append_int_noprefix(table, 0, 4); } +/* + * Generic Error Data Entry + * ACPI 6.1: 18.3.2.7.1 Generic Error Data + */ +static void acpi_ghes_generic_error_data(GArray *table, + const uint8_t *section_type, uint32_t error_severity, + uint8_t validation_bits, uint8_t flags, + uint32_t error_data_length, QemuUUID fru_id, + uint64_t time_stamp) +{ + const uint8_t fru_text[20] = {0}; + + /* Section Type */ + g_array_append_vals(table, section_type, 16); + + /* Error Severity */ + build_append_int_noprefix(table, error_severity, 4); + /* Revision */ + build_append_int_noprefix(table, 0x300, 2); + /* Validation Bits */ + build_append_int_noprefix(table, validation_bits, 1); + /* Flags */ + build_append_int_noprefix(table, flags, 1); + /* Error Data Length */ + build_append_int_noprefix(table, error_data_length, 4); + + /* FRU Id */ + g_array_append_vals(table, fru_id.data, ARRAY_SIZE(fru_id.data)); + + /* FRU Text */ + g_array_append_vals(table, fru_text, sizeof(fru_text)); + + /* Timestamp */ + build_append_int_noprefix(table, time_stamp, 8); +} + +/* + * Generic Error Status Block + * ACPI 6.1: 18.3.2.7.1 Generic Error Data + */ +static void acpi_ghes_generic_error_status(GArray *table, uint32_t block_status, + uint32_t raw_data_offset, uint32_t raw_data_length, + uint32_t data_length, uint32_t error_severity) +{ + /* Block Status */ + build_append_int_noprefix(table, block_status, 4); + /* Raw Data Offset */ + build_append_int_noprefix(table, raw_data_offset, 4); + /* Raw Data Length */ + build_append_int_noprefix(table, raw_data_length, 4); + /* Data Length */ + build_append_int_noprefix(table, data_length, 4); + /* Error Severity */ + build_append_int_noprefix(table, error_severity, 4); +} + +/* UEFI 2.6: N.2.5 Memory Error Section */ +static void acpi_ghes_build_append_mem_cper(GArray *table, + uint64_t error_physical_addr) +{ + /* + * Memory Error Record + */ + + /* Validation Bits */ + build_append_int_noprefix(table, + (1ULL << 14) | /* Type Valid */ + (1ULL << 1) /* Physical Address Valid */, + 8); + /* Error Status */ + build_append_int_noprefix(table, 0, 8); + /* Physical Address */ + build_append_int_noprefix(table, error_physical_addr, 8); + /* Skip all the detailed information normally found in such a record */ + build_append_int_noprefix(table, 0, 48); + /* Memory Error Type */ + build_append_int_noprefix(table, 0 /* Unknown error */, 1); + /* Skip all the detailed information normally found in such a record */ + build_append_int_noprefix(table, 0, 7); +} + +static int acpi_ghes_record_mem_error(uint64_t error_block_address, + uint64_t error_physical_addr) +{ + GArray *block; + + /* Memory Error Section Type */ + const uint8_t uefi_cper_mem_sec[] = + UUID_LE(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83, \ + 0xED, 0x7C, 0x83, 0xB1); + + /* invalid fru id: ACPI 4.0: 17.3.2.6.1 Generic Error Data, + * Table 17-13 Generic Error Data Entry + */ + QemuUUID fru_id = {}; + uint32_t data_length; + + block = g_array_new(false, true /* clear */, 1); + + /* This is the length if adding a new generic error data entry*/ + data_length = ACPI_GHES_DATA_LENGTH + ACPI_GHES_MEM_CPER_LENGTH; + + /* + * Check whether it will run out of the preallocated memory if adding a new + * generic error data entry + */ + if ((data_length + ACPI_GHES_GESB_SIZE) > ACPI_GHES_MAX_RAW_DATA_LENGTH) { + error_report("Not enough memory to record new CPER!!!"); + g_array_free(block, true); + return -1; + } + + /* Build the new generic error status block header */ + acpi_ghes_generic_error_status(block, ACPI_GEBS_UNCORRECTABLE, + 0, 0, data_length, ACPI_CPER_SEV_RECOVERABLE); + + /* Build this new generic error data entry header */ + acpi_ghes_generic_error_data(block, uefi_cper_mem_sec, + ACPI_CPER_SEV_RECOVERABLE, 0, 0, + ACPI_GHES_MEM_CPER_LENGTH, fru_id, 0); + + /* Build the memory section CPER for above new generic error data entry */ + acpi_ghes_build_append_mem_cper(block, error_physical_addr); + + /* Write the generic error data entry into guest memory */ + cpu_physical_memory_write(error_block_address, block->data, block->len); + + g_array_free(block, true); + + return 0; +} + /* * Build table for the hardware error fw_cfg blob. * Initialize "etc/hardware_errors" and "etc/hardware_errors_addr" fw_cfg blobs. @@ -227,3 +390,59 @@ void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s, fw_cfg_add_file_callback(s, ACPI_GHES_DATA_ADDR_FW_CFG_FILE, NULL, NULL, NULL, &(ags->ghes_addr_le), sizeof(ags->ghes_addr_le), false); } + +int acpi_ghes_record_errors(uint8_t source_id, uint64_t physical_address) +{ + uint64_t error_block_addr, read_ack_register_addr, read_ack_register = 0; + uint64_t start_addr; + bool ret = -1; + AcpiGedState *acpi_ged_state; + AcpiGhesState *ags; + + assert(source_id < ACPI_HEST_SRC_ID_RESERVED); + + acpi_ged_state = ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED, + NULL)); + g_assert(acpi_ged_state); + ags = &acpi_ged_state->ghes_state; + + start_addr = le64_to_cpu(ags->ghes_addr_le); + + if (physical_address) { + + if (source_id < ACPI_HEST_SRC_ID_RESERVED) { + start_addr += source_id * sizeof(uint64_t); + } + + cpu_physical_memory_read(start_addr, &error_block_addr, + sizeof(error_block_addr)); + + error_block_addr = le64_to_cpu(error_block_addr); + + read_ack_register_addr = start_addr + + ACPI_GHES_ERROR_SOURCE_COUNT * sizeof(uint64_t); + + cpu_physical_memory_read(read_ack_register_addr, + &read_ack_register, sizeof(read_ack_register)); + + /* zero means OSPM does not acknowledge the error */ + if (!read_ack_register) { + error_report("OSPM does not acknowledge previous error," + " so can not record CPER for current error anymore"); + } else if (error_block_addr) { + read_ack_register = cpu_to_le64(0); + /* + * Clear the Read Ack Register, OSPM will write it to 1 when + * it acknowledges this error. + */ + cpu_physical_memory_write(read_ack_register_addr, + &read_ack_register, sizeof(uint64_t)); + + ret = acpi_ghes_record_mem_error(error_block_addr, + physical_address); + } else + error_report("can not find Generic Error Status Block"); + } + + return ret; +} diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h index a3420fc9be..4ad025e09a 100644 --- a/include/hw/acpi/ghes.h +++ b/include/hw/acpi/ghes.h @@ -70,4 +70,5 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker); void acpi_build_hest(GArray *table_data, BIOSLinker *linker); void acpi_ghes_add_fw_cfg(AcpiGhesState *vms, FWCfgState *s, GArray *hardware_errors); +int acpi_ghes_record_errors(uint8_t notify, uint64_t error_physical_addr); #endif From e24fd076a59604c4ba3c05fe9d19ea6fc5320a12 Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Tue, 12 May 2020 11:06:08 +0800 Subject: [PATCH 0446/2595] target-arm: kvm64: handle SIGBUS signal from kernel or KVM Add a SIGBUS signal handler. In this handler, it checks the SIGBUS type, translates the host VA delivered by host to guest PA, then fills this PA to guest APEI GHES memory, then notifies guest according to the SIGBUS type. When guest accesses the poisoned memory, it will generate a Synchronous External Abort(SEA). Then host kernel gets an APEI notification and calls memory_failure() to unmapped the affected page in stage 2, finally returns to guest. Guest continues to access the PG_hwpoison page, it will trap to KVM as stage2 fault, then a SIGBUS_MCEERR_AR synchronous signal is delivered to Qemu, Qemu records this error address into guest APEI GHES memory and notifes guest using Synchronous-External-Abort(SEA). In order to inject a vSEA, we introduce the kvm_inject_arm_sea() function in which we can setup the type of exception and the syndrome information. When switching to guest, the target vcpu will jump to the synchronous external abort vector table entry. The ESR_ELx.DFSC is set to synchronous external abort(0x10), and the ESR_ELx.FnV is set to not valid(0x1), which will tell guest that FAR is not valid and hold an UNKNOWN value. These values will be set to KVM register structures through KVM_SET_ONE_REG IOCTL. Signed-off-by: Dongjiu Geng Signed-off-by: Xiang Zheng Reviewed-by: Michael S. Tsirkin Acked-by: Xiang Zheng Reviewed-by: Peter Maydell Reviewed-by: Igor Mammedov Message-id: 20200512030609.19593-10-gengdongjiu@huawei.com Signed-off-by: Peter Maydell --- include/sysemu/kvm.h | 3 +- target/arm/cpu.h | 4 +++ target/arm/helper.c | 2 +- target/arm/internals.h | 5 +-- target/arm/kvm64.c | 77 +++++++++++++++++++++++++++++++++++++++++ target/arm/tlb_helper.c | 2 +- target/i386/cpu.h | 2 ++ 7 files changed, 89 insertions(+), 6 deletions(-) diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 141342de98..3b2250471c 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -379,8 +379,7 @@ bool kvm_vcpu_id_is_valid(int vcpu_id); /* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */ unsigned long kvm_arch_vcpu_id(CPUState *cpu); -#ifdef TARGET_I386 -#define KVM_HAVE_MCE_INJECTION 1 +#ifdef KVM_HAVE_MCE_INJECTION void kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); #endif diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 676f216b67..5d995368d4 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -28,6 +28,10 @@ /* ARM processors have a weak memory model */ #define TCG_GUEST_DEFAULT_MO (0) +#ifdef TARGET_AARCH64 +#define KVM_HAVE_MCE_INJECTION 1 +#endif + #define EXCP_UDEF 1 /* undefined instruction */ #define EXCP_SWI 2 /* software interrupt */ #define EXCP_PREFETCH_ABORT 3 diff --git a/target/arm/helper.c b/target/arm/helper.c index b88d27819d..a92ae55672 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -3465,7 +3465,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, * Report exception with ESR indicating a fault due to a * translation table walk for a cache maintenance instruction. */ - syn = syn_data_abort_no_iss(current_el == target_el, + syn = syn_data_abort_no_iss(current_el == target_el, 0, fi.ea, 1, fi.s1ptw, 1, fsc); env->exception.vaddress = value; env->exception.fsr = fsr; diff --git a/target/arm/internals.h b/target/arm/internals.h index a833e3941d..4bdbc3a8ac 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -451,13 +451,14 @@ static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc) | ARM_EL_IL | (ea << 9) | (s1ptw << 7) | fsc; } -static inline uint32_t syn_data_abort_no_iss(int same_el, +static inline uint32_t syn_data_abort_no_iss(int same_el, int fnv, int ea, int cm, int s1ptw, int wnr, int fsc) { return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) | ARM_EL_IL - | (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc; + | (fnv << 10) | (ea << 9) | (cm << 8) | (s1ptw << 7) + | (wnr << 6) | fsc; } static inline uint32_t syn_data_abort_with_iss(int same_el, diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index cd8ab6b8ae..f09ed9f4df 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -28,6 +28,9 @@ #include "sysemu/kvm_int.h" #include "kvm_arm.h" #include "internals.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/ghes.h" +#include "hw/arm/virt.h" static bool have_guest_debug; @@ -883,6 +886,30 @@ int kvm_arm_cpreg_level(uint64_t regidx) return KVM_PUT_RUNTIME_STATE; } +/* Callers must hold the iothread mutex lock */ +static void kvm_inject_arm_sea(CPUState *c) +{ + ARMCPU *cpu = ARM_CPU(c); + CPUARMState *env = &cpu->env; + CPUClass *cc = CPU_GET_CLASS(c); + uint32_t esr; + bool same_el; + + c->exception_index = EXCP_DATA_ABORT; + env->exception.target_el = 1; + + /* + * Set the DFSC to synchronous external abort and set FnV to not valid, + * this will tell guest the FAR_ELx is UNKNOWN for this abort. + */ + same_el = arm_current_el(env) == env->exception.target_el; + esr = syn_data_abort_no_iss(same_el, 1, 0, 0, 0, 0, 0x10); + + env->exception.syndrome = esr; + + cc->do_interrupt(c); +} + #define AARCH64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x)) @@ -1316,6 +1343,56 @@ int kvm_arch_get_registers(CPUState *cs) return ret; } +void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr) +{ + ram_addr_t ram_addr; + hwaddr paddr; + Object *obj = qdev_get_machine(); + VirtMachineState *vms = VIRT_MACHINE(obj); + bool acpi_enabled = virt_is_acpi_enabled(vms); + + assert(code == BUS_MCEERR_AR || code == BUS_MCEERR_AO); + + if (acpi_enabled && addr && + object_property_get_bool(obj, "ras", NULL)) { + ram_addr = qemu_ram_addr_from_host(addr); + if (ram_addr != RAM_ADDR_INVALID && + kvm_physical_memory_addr_from_host(c->kvm_state, addr, &paddr)) { + kvm_hwpoison_page_add(ram_addr); + /* + * If this is a BUS_MCEERR_AR, we know we have been called + * synchronously from the vCPU thread, so we can easily + * synchronize the state and inject an error. + * + * TODO: we currently don't tell the guest at all about + * BUS_MCEERR_AO. In that case we might either be being + * called synchronously from the vCPU thread, or a bit + * later from the main thread, so doing the injection of + * the error would be more complicated. + */ + if (code == BUS_MCEERR_AR) { + kvm_cpu_synchronize_state(c); + if (!acpi_ghes_record_errors(ACPI_HEST_SRC_ID_SEA, paddr)) { + kvm_inject_arm_sea(c); + } else { + error_report("failed to record the error"); + abort(); + } + } + return; + } + if (code == BUS_MCEERR_AO) { + error_report("Hardware memory error at addr %p for memory used by " + "QEMU itself instead of guest system!", addr); + } + } + + if (code == BUS_MCEERR_AR) { + error_report("Hardware memory error!"); + exit(1); + } +} + /* C6.6.29 BRK instruction */ static const uint32_t brk_insn = 0xd4200000; diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c index e63f8bda29..7388494a55 100644 --- a/target/arm/tlb_helper.c +++ b/target/arm/tlb_helper.c @@ -33,7 +33,7 @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn, * ISV field. */ if (!(template_syn & ARM_EL_ISV) || target_el != 2 || s1ptw) { - syn = syn_data_abort_no_iss(same_el, + syn = syn_data_abort_no_iss(same_el, 0, ea, 0, s1ptw, is_write, fsc); } else { /* diff --git a/target/i386/cpu.h b/target/i386/cpu.h index e818fc712a..408392dbf6 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -29,6 +29,8 @@ /* The x86 has a strong memory model with some store-after-load re-ordering */ #define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD) +#define KVM_HAVE_MCE_INJECTION 1 + /* Maximum instruction code size */ #define TARGET_MAX_INSN_SIZE 16 From f7e462f82b06d39acefff7b8f153bf5e6b3d28e5 Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Tue, 12 May 2020 11:06:09 +0800 Subject: [PATCH 0447/2595] MAINTAINERS: Add ACPI/HEST/GHES entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I and Xiang are willing to review the APEI-related patches and volunteer as the reviewers for the HEST/GHES part. Signed-off-by: Dongjiu Geng Signed-off-by: Xiang Zheng Reviewed-by: Philippe Mathieu-Daudé Acked-by: Michael S. Tsirkin Message-id: 20200512030609.19593-11-gengdongjiu@huawei.com Signed-off-by: Peter Maydell --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 005ee98a59..f972e12bfd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1516,6 +1516,15 @@ F: tests/qtest/bios-tables-test.c F: tests/qtest/acpi-utils.[hc] F: tests/data/acpi/ +ACPI/HEST/GHES +R: Dongjiu Geng +R: Xiang Zheng +L: qemu-arm@nongnu.org +S: Maintained +F: hw/acpi/ghes.c +F: include/hw/acpi/ghes.h +F: docs/specs/acpi_hest_ghes.rst + ppc4xx M: David Gibson L: qemu-ppc@nongnu.org From a063569508af8295cf6271e06700e5b956bb402d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:48 +0100 Subject: [PATCH 0448/2595] target/arm: Convert Neon 3-reg-same VQRDMLAH/VQRDMLSH to decodetree Convert the Neon VQRDMLAH and VQRDMLSH insns in the 3-reg-same group to decodetree. These don't use do_3same() because they want to operate on VFP double registers, whose offsets are different from the neon_reg_offset() calculations do_3same does. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-2-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 3 +++ target/arm/translate-neon.inc.c | 15 +++++++++++++++ target/arm/translate.c | 14 ++------------ 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 593f7fff03..82503c582e 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -97,3 +97,6 @@ VMLS_3s 1111 001 1 0 . .. .... .... 1001 . . . 0 .... @3same VMUL_3s 1111 001 0 0 . .. .... .... 1001 . . . 1 .... @3same VMUL_p_3s 1111 001 1 0 . .. .... .... 1001 . . . 1 .... @3same + +VQRDMLAH_3s 1111 001 1 0 . .. .... .... 1011 ... 1 .... @3same +VQRDMLSH_3s 1111 001 1 0 . .. .... .... 1100 ... 1 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 099491b16f..661b5fc4cf 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -671,3 +671,18 @@ static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) } return do_3same(s, a, gen_VMUL_p_3s); } + +#define DO_VQRDMLAH(INSN, FUNC) \ + static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ + { \ + if (!dc_isar_feature(aa32_rdm, s)) { \ + return false; \ + } \ + if (a->size != 1 && a->size != 2) { \ + return false; \ + } \ + return do_3same(s, a, FUNC); \ + } + +DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc) +DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc) diff --git a/target/arm/translate.c b/target/arm/translate.c index e3d37ef2e9..1f06cb5a87 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5450,12 +5450,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if (!u) { break; /* VPADD */ } - /* VQRDMLAH */ - if (dc_isar_feature(aa32_rdm, s) && (size == 1 || size == 2)) { - gen_gvec_sqrdmlah_qc(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - return 0; - } + /* VQRDMLAH : handled by decodetree */ return 1; case NEON_3R_VFM_VQRDMLSH: @@ -5466,12 +5461,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } break; } - /* VQRDMLSH */ - if (dc_isar_feature(aa32_rdm, s) && (size == 1 || size == 2)) { - gen_gvec_sqrdmlsh_qc(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - return 0; - } + /* VQRDMLSH : handled by decodetree */ return 1; case NEON_3R_VABD: From 21290edfc29d8929741c0ed043733c23c69bc3b9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:49 +0100 Subject: [PATCH 0449/2595] target/arm: Convert Neon 3-reg-same SHA to decodetree Convert the Neon SHA instructions in the 3-reg-same group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-3-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 10 +++ target/arm/translate-neon.inc.c | 139 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 46 +---------- 3 files changed, 151 insertions(+), 44 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 82503c582e..72eae12b26 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -99,4 +99,14 @@ VMUL_3s 1111 001 0 0 . .. .... .... 1001 . . . 1 .... @3same VMUL_p_3s 1111 001 1 0 . .. .... .... 1001 . . . 1 .... @3same VQRDMLAH_3s 1111 001 1 0 . .. .... .... 1011 ... 1 .... @3same + +SHA1_3s 1111 001 0 0 . optype:2 .... .... 1100 . 1 . 0 .... \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp +SHA256H_3s 1111 001 1 0 . 00 .... .... 1100 . 1 . 0 .... \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp +SHA256H2_3s 1111 001 1 0 . 01 .... .... 1100 . 1 . 0 .... \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp +SHA256SU1_3s 1111 001 1 0 . 10 .... .... 1100 . 1 . 0 .... \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp + VQRDMLSH_3s 1111 001 1 0 . .. .... .... 1100 ... 1 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 661b5fc4cf..03b3337e46 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -686,3 +686,142 @@ static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc) DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc) + +static bool trans_SHA1_3s(DisasContext *s, arg_SHA1_3s *a) +{ + TCGv_ptr ptr1, ptr2, ptr3; + TCGv_i32 tmp; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !dc_isar_feature(aa32_sha1, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if ((a->vn | a->vm | a->vd) & 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + ptr1 = vfp_reg_ptr(true, a->vd); + ptr2 = vfp_reg_ptr(true, a->vn); + ptr3 = vfp_reg_ptr(true, a->vm); + tmp = tcg_const_i32(a->optype); + gen_helper_crypto_sha1_3reg(ptr1, ptr2, ptr3, tmp); + tcg_temp_free_i32(tmp); + tcg_temp_free_ptr(ptr1); + tcg_temp_free_ptr(ptr2); + tcg_temp_free_ptr(ptr3); + + return true; +} + +static bool trans_SHA256H_3s(DisasContext *s, arg_SHA256H_3s *a) +{ + TCGv_ptr ptr1, ptr2, ptr3; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !dc_isar_feature(aa32_sha2, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if ((a->vn | a->vm | a->vd) & 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + ptr1 = vfp_reg_ptr(true, a->vd); + ptr2 = vfp_reg_ptr(true, a->vn); + ptr3 = vfp_reg_ptr(true, a->vm); + gen_helper_crypto_sha256h(ptr1, ptr2, ptr3); + tcg_temp_free_ptr(ptr1); + tcg_temp_free_ptr(ptr2); + tcg_temp_free_ptr(ptr3); + + return true; +} + +static bool trans_SHA256H2_3s(DisasContext *s, arg_SHA256H2_3s *a) +{ + TCGv_ptr ptr1, ptr2, ptr3; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !dc_isar_feature(aa32_sha2, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if ((a->vn | a->vm | a->vd) & 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + ptr1 = vfp_reg_ptr(true, a->vd); + ptr2 = vfp_reg_ptr(true, a->vn); + ptr3 = vfp_reg_ptr(true, a->vm); + gen_helper_crypto_sha256h2(ptr1, ptr2, ptr3); + tcg_temp_free_ptr(ptr1); + tcg_temp_free_ptr(ptr2); + tcg_temp_free_ptr(ptr3); + + return true; +} + +static bool trans_SHA256SU1_3s(DisasContext *s, arg_SHA256SU1_3s *a) +{ + TCGv_ptr ptr1, ptr2, ptr3; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !dc_isar_feature(aa32_sha2, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if ((a->vn | a->vm | a->vd) & 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + ptr1 = vfp_reg_ptr(true, a->vd); + ptr2 = vfp_reg_ptr(true, a->vn); + ptr3 = vfp_reg_ptr(true, a->vm); + gen_helper_crypto_sha256su1(ptr1, ptr2, ptr3); + tcg_temp_free_ptr(ptr1); + tcg_temp_free_ptr(ptr2); + tcg_temp_free_ptr(ptr3); + + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 1f06cb5a87..ee2b8d6f6e 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5359,7 +5359,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int vec_size; uint32_t imm; TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5; - TCGv_ptr ptr1, ptr2, ptr3; + TCGv_ptr ptr1, ptr2; TCGv_i64 tmp64; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { @@ -5403,49 +5403,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 1; } switch (op) { - case NEON_3R_SHA: - /* The SHA-1/SHA-256 3-register instructions require special - * treatment here, as their size field is overloaded as an - * op type selector, and they all consume their input in a - * single pass. - */ - if (!q) { - return 1; - } - if (!u) { /* SHA-1 */ - if (!dc_isar_feature(aa32_sha1, s)) { - return 1; - } - ptr1 = vfp_reg_ptr(true, rd); - ptr2 = vfp_reg_ptr(true, rn); - ptr3 = vfp_reg_ptr(true, rm); - tmp4 = tcg_const_i32(size); - gen_helper_crypto_sha1_3reg(ptr1, ptr2, ptr3, tmp4); - tcg_temp_free_i32(tmp4); - } else { /* SHA-256 */ - if (!dc_isar_feature(aa32_sha2, s) || size == 3) { - return 1; - } - ptr1 = vfp_reg_ptr(true, rd); - ptr2 = vfp_reg_ptr(true, rn); - ptr3 = vfp_reg_ptr(true, rm); - switch (size) { - case 0: - gen_helper_crypto_sha256h(ptr1, ptr2, ptr3); - break; - case 1: - gen_helper_crypto_sha256h2(ptr1, ptr2, ptr3); - break; - case 2: - gen_helper_crypto_sha256su1(ptr1, ptr2, ptr3); - break; - } - } - tcg_temp_free_ptr(ptr1); - tcg_temp_free_ptr(ptr2); - tcg_temp_free_ptr(ptr3); - return 0; - case NEON_3R_VPADD_VQRDMLAH: if (!u) { break; /* VPADD */ @@ -5496,6 +5453,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VMUL: case NEON_3R_VML: case NEON_3R_VSHL: + case NEON_3R_SHA: /* Already handled by decodetree */ return 1; } From 35d4352fa9e94b35bf17f58181cb16c184b98d56 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:50 +0100 Subject: [PATCH 0450/2595] target/arm: Convert Neon 64-bit element 3-reg-same insns Convert the 64-bit element insns in the 3-reg-same group to decodetree. This covers VQSHL, VRSHL and VQRSHL where size==0b11. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-4-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 13 +++++++++++ target/arm/translate-neon.inc.c | 24 +++++++++++++++++++++ target/arm/translate.c | 38 ++------------------------------- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 72eae12b26..fa52b998e8 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -81,6 +81,19 @@ VCGE_U_3s 1111 001 1 0 . .. .... .... 0011 . . . 1 .... @3same VSHL_S_3s 1111 001 0 0 . .. .... .... 0100 . . . 0 .... @3same_rev VSHL_U_3s 1111 001 1 0 . .. .... .... 0100 . . . 0 .... @3same_rev +# Insns operating on 64-bit elements (size!=0b11 handled elsewhere) +# The _rev suffix indicates that Vn and Vm are reversed (as explained +# by the comment for the @3same_rev format). +@3same_64_rev .... ... . . . 11 .... .... .... . q:1 . . .... \ + &3same vm=%vn_dp vn=%vm_dp vd=%vd_dp size=3 + +VQSHL_S64_3s 1111 001 0 0 . .. .... .... 0100 . . . 1 .... @3same_64_rev +VQSHL_U64_3s 1111 001 1 0 . .. .... .... 0100 . . . 1 .... @3same_64_rev +VRSHL_S64_3s 1111 001 0 0 . .. .... .... 0101 . . . 0 .... @3same_64_rev +VRSHL_U64_3s 1111 001 1 0 . .. .... .... 0101 . . . 0 .... @3same_64_rev +VQRSHL_S64_3s 1111 001 0 0 . .. .... .... 0101 . . . 1 .... @3same_64_rev +VQRSHL_U64_3s 1111 001 1 0 . .. .... .... 0101 . . . 1 .... @3same_64_rev + VMAX_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 0 .... @3same VMAX_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 0 .... @3same VMIN_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 1 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 03b3337e46..05c6dcdc9b 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -825,3 +825,27 @@ static bool trans_SHA256SU1_3s(DisasContext *s, arg_SHA256SU1_3s *a) return true; } + +#define DO_3SAME_64(INSN, FUNC) \ + static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ + uint32_t rn_ofs, uint32_t rm_ofs, \ + uint32_t oprsz, uint32_t maxsz) \ + { \ + static const GVecGen3 op = { .fni8 = FUNC }; \ + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &op); \ + } \ + DO_3SAME(INSN, gen_##INSN##_3s) + +#define DO_3SAME_64_ENV(INSN, FUNC) \ + static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m) \ + { \ + FUNC(d, cpu_env, n, m); \ + } \ + DO_3SAME_64(INSN, gen_##INSN##_elt) + +DO_3SAME_64(VRSHL_S64, gen_helper_neon_rshl_s64) +DO_3SAME_64(VRSHL_U64, gen_helper_neon_rshl_u64) +DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64) +DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64) +DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64) +DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) diff --git a/target/arm/translate.c b/target/arm/translate.c index ee2b8d6f6e..1ce3e18286 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5459,42 +5459,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } if (size == 3) { - /* 64-bit element instructions. */ - for (pass = 0; pass < (q ? 2 : 1); pass++) { - neon_load_reg64(cpu_V0, rn + pass); - neon_load_reg64(cpu_V1, rm + pass); - switch (op) { - case NEON_3R_VQSHL: - if (u) { - gen_helper_neon_qshl_u64(cpu_V0, cpu_env, - cpu_V1, cpu_V0); - } else { - gen_helper_neon_qshl_s64(cpu_V0, cpu_env, - cpu_V1, cpu_V0); - } - break; - case NEON_3R_VRSHL: - if (u) { - gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0); - } else { - gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0); - } - break; - case NEON_3R_VQRSHL: - if (u) { - gen_helper_neon_qrshl_u64(cpu_V0, cpu_env, - cpu_V1, cpu_V0); - } else { - gen_helper_neon_qrshl_s64(cpu_V0, cpu_env, - cpu_V1, cpu_V0); - } - break; - default: - abort(); - } - neon_store_reg64(cpu_V0, rd + pass); - } - return 0; + /* 64-bit element instructions: handled by decodetree */ + return 1; } pairwise = 0; switch (op) { From cb294bca866f1cd776e44e03e5e432942bc676e8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:51 +0100 Subject: [PATCH 0451/2595] target/arm: Convert Neon VHADD 3-reg-same insns Convert the Neon VHADD insns in the 3-reg-same group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-5-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 2 ++ target/arm/translate-neon.inc.c | 24 ++++++++++++++++++++++++ target/arm/translate.c | 4 +--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index fa52b998e8..8120d8d5f2 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -42,6 +42,8 @@ @3same .... ... . . . size:2 .... .... .... . q:1 . . .... \ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp +VHADD_S_3s 1111 001 0 0 . .. .... .... 0000 . . . 0 .... @3same +VHADD_U_3s 1111 001 1 0 . .. .... .... 0000 . . . 0 .... @3same VQADD_S_3s 1111 001 0 0 . .. .... .... 0000 . . . 1 .... @3same VQADD_U_3s 1111 001 1 0 . .. .... .... 0000 . . . 1 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 05c6dcdc9b..0418a84a7d 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -849,3 +849,27 @@ DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64) DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64) DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64) DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) + +#define DO_3SAME_32(INSN, FUNC) \ + static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ + uint32_t rn_ofs, uint32_t rm_ofs, \ + uint32_t oprsz, uint32_t maxsz) \ + { \ + static const GVecGen3 ops[4] = { \ + { .fni4 = gen_helper_neon_##FUNC##8 }, \ + { .fni4 = gen_helper_neon_##FUNC##16 }, \ + { .fni4 = gen_helper_neon_##FUNC##32 }, \ + { 0 }, \ + }; \ + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ + } \ + static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ + { \ + if (a->size > 2) { \ + return false; \ + } \ + return do_3same(s, a, gen_##INSN##_3s); \ + } + +DO_3SAME_32(VHADD_S, hadd_s) +DO_3SAME_32(VHADD_U, hadd_u) diff --git a/target/arm/translate.c b/target/arm/translate.c index 1ce3e18286..8d856ccfe9 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5454,6 +5454,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VML: case NEON_3R_VSHL: case NEON_3R_SHA: + case NEON_3R_VHADD: /* Already handled by decodetree */ return 1; } @@ -5534,9 +5535,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp2 = neon_load_reg(rm, pass); } switch (op) { - case NEON_3R_VHADD: - GEN_NEON_INTEGER_OP(hadd); - break; case NEON_3R_VRHADD: GEN_NEON_INTEGER_OP(rhadd); break; From 7715098f93ff5205334edf161e5fe156346122b0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:52 +0100 Subject: [PATCH 0452/2595] target/arm: Convert Neon VABA/VABD 3-reg-same to decodetree Convert the Neon VABA and VABD insns in the 3-reg-same group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-6-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 6 ++++++ target/arm/translate-neon.inc.c | 4 ++++ target/arm/translate.c | 22 ++-------------------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 8120d8d5f2..00a909a888 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -101,6 +101,12 @@ VMAX_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 0 .... @3same VMIN_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 1 .... @3same VMIN_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 1 .... @3same +VABD_S_3s 1111 001 0 0 . .. .... .... 0111 . . . 0 .... @3same +VABD_U_3s 1111 001 1 0 . .. .... .... 0111 . . . 0 .... @3same + +VABA_S_3s 1111 001 0 0 . .. .... .... 0111 . . . 1 .... @3same +VABA_U_3s 1111 001 1 0 . .. .... .... 0111 . . . 1 .... @3same + VADD_3s 1111 001 0 0 . .. .... .... 1000 . . . 0 .... @3same VSUB_3s 1111 001 1 0 . .. .... .... 1000 . . . 0 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 0418a84a7d..20f0f2c8d8 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -641,6 +641,10 @@ DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla) DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls) DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst) +DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd) +DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba) +DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd) +DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba) #define DO_3SAME_CMP(INSN, COND) \ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ diff --git a/target/arm/translate.c b/target/arm/translate.c index 8d856ccfe9..2c842df445 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5421,26 +5421,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) /* VQRDMLSH : handled by decodetree */ return 1; - case NEON_3R_VABD: - if (u) { - gen_gvec_uabd(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } else { - gen_gvec_sabd(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } - return 0; - - case NEON_3R_VABA: - if (u) { - gen_gvec_uaba(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } else { - gen_gvec_saba(size, rd_ofs, rn_ofs, rm_ofs, - vec_size, vec_size); - } - return 0; - case NEON_3R_VADD_VSUB: case NEON_3R_LOGIC: case NEON_3R_VMAX: @@ -5455,6 +5435,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VSHL: case NEON_3R_SHA: case NEON_3R_VHADD: + case NEON_3R_VABD: + case NEON_3R_VABA: /* Already handled by decodetree */ return 1; } From 8e44d03f4b5590e19a4f7910ca1c327609933dd7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:53 +0100 Subject: [PATCH 0453/2595] target/arm: Convert Neon VRHADD, VHSUB 3-reg-same insns to decodetree Convert the Neon VRHADD and VHSUB 3-reg-same insns to decodetree. (These are all the other insns in 3-reg-same which were using GEN_NEON_INTEGER_OP() and which are not pairwise or reversed-operands.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-7-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 6 ++++++ target/arm/translate-neon.inc.c | 4 ++++ target/arm/translate.c | 8 ++------ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 00a909a888..4984a5d4e1 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -47,6 +47,9 @@ VHADD_U_3s 1111 001 1 0 . .. .... .... 0000 . . . 0 .... @3same VQADD_S_3s 1111 001 0 0 . .. .... .... 0000 . . . 1 .... @3same VQADD_U_3s 1111 001 1 0 . .. .... .... 0000 . . . 1 .... @3same +VRHADD_S_3s 1111 001 0 0 . .. .... .... 0001 . . . 0 .... @3same +VRHADD_U_3s 1111 001 1 0 . .. .... .... 0001 . . . 0 .... @3same + @3same_logic .... ... . . . .. .... .... .... . q:1 .. .... \ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp size=0 @@ -59,6 +62,9 @@ VBSL_3s 1111 001 1 0 . 01 .... .... 0001 ... 1 .... @3same_logic VBIT_3s 1111 001 1 0 . 10 .... .... 0001 ... 1 .... @3same_logic VBIF_3s 1111 001 1 0 . 11 .... .... 0001 ... 1 .... @3same_logic +VHSUB_S_3s 1111 001 0 0 . .. .... .... 0010 . . . 0 .... @3same +VHSUB_U_3s 1111 001 1 0 . .. .... .... 0010 . . . 0 .... @3same + VQSUB_S_3s 1111 001 0 0 . .. .... .... 0010 . . . 1 .... @3same VQSUB_U_3s 1111 001 1 0 . .. .... .... 0010 . . . 1 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 20f0f2c8d8..e9da47171c 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -877,3 +877,7 @@ DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) DO_3SAME_32(VHADD_S, hadd_s) DO_3SAME_32(VHADD_U, hadd_u) +DO_3SAME_32(VHSUB_S, hsub_s) +DO_3SAME_32(VHSUB_U, hsub_u) +DO_3SAME_32(VRHADD_S, rhadd_s) +DO_3SAME_32(VRHADD_U, rhadd_u) diff --git a/target/arm/translate.c b/target/arm/translate.c index 2c842df445..ebb899d846 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5435,6 +5435,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VSHL: case NEON_3R_SHA: case NEON_3R_VHADD: + case NEON_3R_VRHADD: + case NEON_3R_VHSUB: case NEON_3R_VABD: case NEON_3R_VABA: /* Already handled by decodetree */ @@ -5517,12 +5519,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp2 = neon_load_reg(rm, pass); } switch (op) { - case NEON_3R_VRHADD: - GEN_NEON_INTEGER_OP(rhadd); - break; - case NEON_3R_VHSUB: - GEN_NEON_INTEGER_OP(hsub); - break; case NEON_3R_VQSHL: GEN_NEON_INTEGER_OP_ENV(qshl); break; From 6812dfdc6b0286730d6f903ebfbdc4f81b80c29b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:54 +0100 Subject: [PATCH 0454/2595] target/arm: Convert Neon VQSHL, VRSHL, VQRSHL 3-reg-same insns to decodetree Convert the VQSHL, VRSHL and VQRSHL insns in the 3-reg-same group to decodetree. We have already implemented the size==0b11 case of these insns; this commit handles the remaining sizes. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-8-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 30 ++++++++++++++++++----- target/arm/translate-neon.inc.c | 43 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 22 +++-------------- 3 files changed, 70 insertions(+), 25 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 4984a5d4e1..34bce81c43 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -95,12 +95,30 @@ VSHL_U_3s 1111 001 1 0 . .. .... .... 0100 . . . 0 .... @3same_rev @3same_64_rev .... ... . . . 11 .... .... .... . q:1 . . .... \ &3same vm=%vn_dp vn=%vm_dp vd=%vd_dp size=3 -VQSHL_S64_3s 1111 001 0 0 . .. .... .... 0100 . . . 1 .... @3same_64_rev -VQSHL_U64_3s 1111 001 1 0 . .. .... .... 0100 . . . 1 .... @3same_64_rev -VRSHL_S64_3s 1111 001 0 0 . .. .... .... 0101 . . . 0 .... @3same_64_rev -VRSHL_U64_3s 1111 001 1 0 . .. .... .... 0101 . . . 0 .... @3same_64_rev -VQRSHL_S64_3s 1111 001 0 0 . .. .... .... 0101 . . . 1 .... @3same_64_rev -VQRSHL_U64_3s 1111 001 1 0 . .. .... .... 0101 . . . 1 .... @3same_64_rev +{ + VQSHL_S64_3s 1111 001 0 0 . .. .... .... 0100 . . . 1 .... @3same_64_rev + VQSHL_S_3s 1111 001 0 0 . .. .... .... 0100 . . . 1 .... @3same_rev +} +{ + VQSHL_U64_3s 1111 001 1 0 . .. .... .... 0100 . . . 1 .... @3same_64_rev + VQSHL_U_3s 1111 001 1 0 . .. .... .... 0100 . . . 1 .... @3same_rev +} +{ + VRSHL_S64_3s 1111 001 0 0 . .. .... .... 0101 . . . 0 .... @3same_64_rev + VRSHL_S_3s 1111 001 0 0 . .. .... .... 0101 . . . 0 .... @3same_rev +} +{ + VRSHL_U64_3s 1111 001 1 0 . .. .... .... 0101 . . . 0 .... @3same_64_rev + VRSHL_U_3s 1111 001 1 0 . .. .... .... 0101 . . . 0 .... @3same_rev +} +{ + VQRSHL_S64_3s 1111 001 0 0 . .. .... .... 0101 . . . 1 .... @3same_64_rev + VQRSHL_S_3s 1111 001 0 0 . .. .... .... 0101 . . . 1 .... @3same_rev +} +{ + VQRSHL_U64_3s 1111 001 1 0 . .. .... .... 0101 . . . 1 .... @3same_64_rev + VQRSHL_U_3s 1111 001 1 0 . .. .... .... 0101 . . . 1 .... @3same_rev +} VMAX_S_3s 1111 001 0 0 . .. .... .... 0110 . . . 0 .... @3same VMAX_U_3s 1111 001 1 0 . .. .... .... 0110 . . . 0 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index e9da47171c..7097c18f33 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -875,9 +875,52 @@ DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) return do_3same(s, a, gen_##INSN##_3s); \ } +/* + * Some helper functions need to be passed the cpu_env. In order + * to use those with the gvec APIs like tcg_gen_gvec_3() we need + * to create wrapper functions whose prototype is a NeonGenTwoOpFn() + * and which call a NeonGenTwoOpEnvFn(). + */ +#define WRAP_ENV_FN(WRAPNAME, FUNC) \ + static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m) \ + { \ + FUNC(d, cpu_env, n, m); \ + } + +#define DO_3SAME_32_ENV(INSN, FUNC) \ + WRAP_ENV_FN(gen_##INSN##_tramp8, gen_helper_neon_##FUNC##8); \ + WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##16); \ + WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##32); \ + static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ + uint32_t rn_ofs, uint32_t rm_ofs, \ + uint32_t oprsz, uint32_t maxsz) \ + { \ + static const GVecGen3 ops[4] = { \ + { .fni4 = gen_##INSN##_tramp8 }, \ + { .fni4 = gen_##INSN##_tramp16 }, \ + { .fni4 = gen_##INSN##_tramp32 }, \ + { 0 }, \ + }; \ + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ + } \ + static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ + { \ + if (a->size > 2) { \ + return false; \ + } \ + return do_3same(s, a, gen_##INSN##_3s); \ + } + DO_3SAME_32(VHADD_S, hadd_s) DO_3SAME_32(VHADD_U, hadd_u) DO_3SAME_32(VHSUB_S, hsub_s) DO_3SAME_32(VHSUB_U, hsub_u) DO_3SAME_32(VRHADD_S, rhadd_s) DO_3SAME_32(VRHADD_U, rhadd_u) +DO_3SAME_32(VRSHL_S, rshl_s) +DO_3SAME_32(VRSHL_U, rshl_u) + +DO_3SAME_32_ENV(VQSHL_S, qshl_s) +DO_3SAME_32_ENV(VQSHL_U, qshl_u) +DO_3SAME_32_ENV(VQRSHL_S, qrshl_s) +DO_3SAME_32_ENV(VQRSHL_U, qrshl_u) diff --git a/target/arm/translate.c b/target/arm/translate.c index ebb899d846..3aabb18720 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5439,6 +5439,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VHSUB: case NEON_3R_VABD: case NEON_3R_VABA: + case NEON_3R_VQSHL: + case NEON_3R_VRSHL: + case NEON_3R_VQRSHL: /* Already handled by decodetree */ return 1; } @@ -5449,17 +5452,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } pairwise = 0; switch (op) { - case NEON_3R_VQSHL: - case NEON_3R_VRSHL: - case NEON_3R_VQRSHL: - { - int rtmp; - /* Shift instruction operands are reversed. */ - rtmp = rn; - rn = rm; - rm = rtmp; - } - break; case NEON_3R_VPADD_VQRDMLAH: case NEON_3R_VPMAX: case NEON_3R_VPMIN: @@ -5519,14 +5511,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp2 = neon_load_reg(rm, pass); } switch (op) { - case NEON_3R_VQSHL: - GEN_NEON_INTEGER_OP_ENV(qshl); - break; - case NEON_3R_VRSHL: - GEN_NEON_INTEGER_OP(rshl); - break; - case NEON_3R_VQRSHL: - GEN_NEON_INTEGER_OP_ENV(qrshl); break; case NEON_3R_VPMAX: GEN_NEON_INTEGER_OP(pmax); From 059c2398a2b1ae86c6722c45e79fb0d0f4d95b1d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:55 +0100 Subject: [PATCH 0455/2595] target/arm: Convert Neon VPMAX/VPMIN 3-reg-same insns to decodetree Convert the Neon integer VPMAX and VPMIN 3-reg-same insns to decodetree. These are 'pairwise' operations. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-9-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 9 +++++ target/arm/translate-neon.inc.c | 71 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 17 +------- 3 files changed, 82 insertions(+), 15 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 34bce81c43..2edcaba9f8 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -42,6 +42,9 @@ @3same .... ... . . . size:2 .... .... .... . q:1 . . .... \ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp +@3same_q0 .... ... . . . size:2 .... .... .... . 0 . . .... \ + &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp q=0 + VHADD_S_3s 1111 001 0 0 . .. .... .... 0000 . . . 0 .... @3same VHADD_U_3s 1111 001 1 0 . .. .... .... 0000 . . . 0 .... @3same VQADD_S_3s 1111 001 0 0 . .. .... .... 0000 . . . 1 .... @3same @@ -143,6 +146,12 @@ VMLS_3s 1111 001 1 0 . .. .... .... 1001 . . . 0 .... @3same VMUL_3s 1111 001 0 0 . .. .... .... 1001 . . . 1 .... @3same VMUL_p_3s 1111 001 1 0 . .. .... .... 1001 . . . 1 .... @3same +VPMAX_S_3s 1111 001 0 0 . .. .... .... 1010 . . . 0 .... @3same_q0 +VPMAX_U_3s 1111 001 1 0 . .. .... .... 1010 . . . 0 .... @3same_q0 + +VPMIN_S_3s 1111 001 0 0 . .. .... .... 1010 . . . 1 .... @3same_q0 +VPMIN_U_3s 1111 001 1 0 . .. .... .... 1010 . . . 1 .... @3same_q0 + VQRDMLAH_3s 1111 001 1 0 . .. .... .... 1011 ... 1 .... @3same SHA1_3s 1111 001 0 0 . optype:2 .... .... 1100 . 1 . 0 .... \ diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 7097c18f33..7db6b85659 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -924,3 +924,74 @@ DO_3SAME_32_ENV(VQSHL_S, qshl_s) DO_3SAME_32_ENV(VQSHL_U, qshl_u) DO_3SAME_32_ENV(VQRSHL_S, qrshl_s) DO_3SAME_32_ENV(VQRSHL_U, qrshl_u) + +static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn) +{ + /* Operations handled pairwise 32 bits at a time */ + TCGv_i32 tmp, tmp2, tmp3; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if (a->size == 3) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + assert(a->q == 0); /* enforced by decode patterns */ + + /* + * Note that we have to be careful not to clobber the source operands + * in the "vm == vd" case by storing the result of the first pass too + * early. Since Q is 0 there are always just two passes, so instead + * of a complicated loop over each pass we just unroll. + */ + tmp = neon_load_reg(a->vn, 0); + tmp2 = neon_load_reg(a->vn, 1); + fn(tmp, tmp, tmp2); + tcg_temp_free_i32(tmp2); + + tmp3 = neon_load_reg(a->vm, 0); + tmp2 = neon_load_reg(a->vm, 1); + fn(tmp3, tmp3, tmp2); + tcg_temp_free_i32(tmp2); + + neon_store_reg(a->vd, 0, tmp); + neon_store_reg(a->vd, 1, tmp3); + return true; +} + +#define DO_3SAME_PAIR(INSN, func) \ + static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ + { \ + static NeonGenTwoOpFn * const fns[] = { \ + gen_helper_neon_##func##8, \ + gen_helper_neon_##func##16, \ + gen_helper_neon_##func##32, \ + }; \ + if (a->size > 2) { \ + return false; \ + } \ + return do_3same_pair(s, a, fns[a->size]); \ + } + +/* 32-bit pairwise ops end up the same as the elementwise versions. */ +#define gen_helper_neon_pmax_s32 tcg_gen_smax_i32 +#define gen_helper_neon_pmax_u32 tcg_gen_umax_i32 +#define gen_helper_neon_pmin_s32 tcg_gen_smin_i32 +#define gen_helper_neon_pmin_u32 tcg_gen_umin_i32 + +DO_3SAME_PAIR(VPMAX_S, pmax_s) +DO_3SAME_PAIR(VPMIN_S, pmin_s) +DO_3SAME_PAIR(VPMAX_U, pmax_u) +DO_3SAME_PAIR(VPMIN_U, pmin_u) diff --git a/target/arm/translate.c b/target/arm/translate.c index 3aabb18720..82be4d4028 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3011,12 +3011,6 @@ static inline void gen_neon_rsb(int size, TCGv_i32 t0, TCGv_i32 t1) } } -/* 32-bit pairwise ops end up the same as the elementwise versions. */ -#define gen_helper_neon_pmax_s32 tcg_gen_smax_i32 -#define gen_helper_neon_pmax_u32 tcg_gen_umax_i32 -#define gen_helper_neon_pmin_s32 tcg_gen_smin_i32 -#define gen_helper_neon_pmin_u32 tcg_gen_umin_i32 - #define GEN_NEON_INTEGER_OP_ENV(name) do { \ switch ((size << 1) | u) { \ case 0: \ @@ -5442,6 +5436,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VQSHL: case NEON_3R_VRSHL: case NEON_3R_VQRSHL: + case NEON_3R_VPMAX: + case NEON_3R_VPMIN: /* Already handled by decodetree */ return 1; } @@ -5453,8 +5449,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) pairwise = 0; switch (op) { case NEON_3R_VPADD_VQRDMLAH: - case NEON_3R_VPMAX: - case NEON_3R_VPMIN: pairwise = 1; break; case NEON_3R_FLOAT_ARITH: @@ -5511,13 +5505,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp2 = neon_load_reg(rm, pass); } switch (op) { - break; - case NEON_3R_VPMAX: - GEN_NEON_INTEGER_OP(pmax); - break; - case NEON_3R_VPMIN: - GEN_NEON_INTEGER_OP(pmin); - break; case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high. */ if (!u) { /* VQDMULH */ switch (size) { From fa22827d4eb078b6c58cd3d19af0b50ed951e832 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:56 +0100 Subject: [PATCH 0456/2595] target/arm: Convert Neon VPADD 3-reg-same insns to decodetree Convert the Neon integer VPADD 3-reg-same insns to decodetree. These are 'pairwise' operations. (Note that VQRDMLAH, which shares the same primary opcode but has U=1, has already been converted.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-10-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 2 ++ target/arm/translate-neon.inc.c | 2 ++ target/arm/translate.c | 19 +------------------ 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 2edcaba9f8..3659fb036c 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -152,6 +152,8 @@ VPMAX_U_3s 1111 001 1 0 . .. .... .... 1010 . . . 0 .... @3same_q0 VPMIN_S_3s 1111 001 0 0 . .. .... .... 1010 . . . 1 .... @3same_q0 VPMIN_U_3s 1111 001 1 0 . .. .... .... 1010 . . . 1 .... @3same_q0 +VPADD_3s 1111 001 0 0 . .. .... .... 1011 . . . 1 .... @3same_q0 + VQRDMLAH_3s 1111 001 1 0 . .. .... .... 1011 ... 1 .... @3same SHA1_3s 1111 001 0 0 . optype:2 .... .... 1100 . 1 . 0 .... \ diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 7db6b85659..e013736407 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -990,8 +990,10 @@ static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn) #define gen_helper_neon_pmax_u32 tcg_gen_umax_i32 #define gen_helper_neon_pmin_s32 tcg_gen_smin_i32 #define gen_helper_neon_pmin_u32 tcg_gen_umin_i32 +#define gen_helper_neon_padd_u32 tcg_gen_add_i32 DO_3SAME_PAIR(VPMAX_S, pmax_s) DO_3SAME_PAIR(VPMIN_S, pmin_s) DO_3SAME_PAIR(VPMAX_U, pmax_u) DO_3SAME_PAIR(VPMIN_U, pmin_u) +DO_3SAME_PAIR(VPADD, padd_u) diff --git a/target/arm/translate.c b/target/arm/translate.c index 82be4d4028..ce30417014 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5397,13 +5397,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 1; } switch (op) { - case NEON_3R_VPADD_VQRDMLAH: - if (!u) { - break; /* VPADD */ - } - /* VQRDMLAH : handled by decodetree */ - return 1; - case NEON_3R_VFM_VQRDMLSH: if (!u) { /* VFM, VFMS */ @@ -5438,6 +5431,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VQRSHL: case NEON_3R_VPMAX: case NEON_3R_VPMIN: + case NEON_3R_VPADD_VQRDMLAH: /* Already handled by decodetree */ return 1; } @@ -5448,9 +5442,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } pairwise = 0; switch (op) { - case NEON_3R_VPADD_VQRDMLAH: - pairwise = 1; - break; case NEON_3R_FLOAT_ARITH: pairwise = (u && size < 2); /* if VPADD (float) */ break; @@ -5528,14 +5519,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } } break; - case NEON_3R_VPADD_VQRDMLAH: - switch (size) { - case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break; - case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break; - case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break; - default: abort(); - } - break; case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */ { TCGv_ptr fpstatus = get_fpstatus_ptr(1); From 7ecc28bc72b8033cf4e0c6332135ec20d4125dfb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:57 +0100 Subject: [PATCH 0457/2595] target/arm: Convert Neon VQDMULH/VQRDMULH 3-reg-same to decodetree Convert the Neon VQDMULH and VQRDMULH 3-reg-same insns to decodetree. These are the last integer operations in the 3-reg-same group. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-11-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 3 +++ target/arm/translate-neon.inc.c | 24 ++++++++++++++++++++++++ target/arm/translate.c | 24 +----------------------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 3659fb036c..fd32837fb1 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -152,6 +152,9 @@ VPMAX_U_3s 1111 001 1 0 . .. .... .... 1010 . . . 0 .... @3same_q0 VPMIN_S_3s 1111 001 0 0 . .. .... .... 1010 . . . 1 .... @3same_q0 VPMIN_U_3s 1111 001 1 0 . .. .... .... 1010 . . . 1 .... @3same_q0 +VQDMULH_3s 1111 001 0 0 . .. .... .... 1011 . . . 0 .... @3same +VQRDMULH_3s 1111 001 1 0 . .. .... .... 1011 . . . 0 .... @3same + VPADD_3s 1111 001 0 0 . .. .... .... 1011 . . . 1 .... @3same_q0 VQRDMLAH_3s 1111 001 1 0 . .. .... .... 1011 ... 1 .... @3same diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index e013736407..f52302f42b 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -997,3 +997,27 @@ DO_3SAME_PAIR(VPMIN_S, pmin_s) DO_3SAME_PAIR(VPMAX_U, pmax_u) DO_3SAME_PAIR(VPMIN_U, pmin_u) DO_3SAME_PAIR(VPADD, padd_u) + +#define DO_3SAME_VQDMULH(INSN, FUNC) \ + WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##_s16); \ + WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##_s32); \ + static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ + uint32_t rn_ofs, uint32_t rm_ofs, \ + uint32_t oprsz, uint32_t maxsz) \ + { \ + static const GVecGen3 ops[2] = { \ + { .fni4 = gen_##INSN##_tramp16 }, \ + { .fni4 = gen_##INSN##_tramp32 }, \ + }; \ + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece - 1]); \ + } \ + static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ + { \ + if (a->size != 1 && a->size != 2) { \ + return false; \ + } \ + return do_3same(s, a, gen_##INSN##_3s); \ + } + +DO_3SAME_VQDMULH(VQDMULH, qdmulh) +DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) diff --git a/target/arm/translate.c b/target/arm/translate.c index ce30417014..561cb67286 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5432,6 +5432,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VPMAX: case NEON_3R_VPMIN: case NEON_3R_VPADD_VQRDMLAH: + case NEON_3R_VQDMULH_VQRDMULH: /* Already handled by decodetree */ return 1; } @@ -5496,29 +5497,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp2 = neon_load_reg(rm, pass); } switch (op) { - case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high. */ - if (!u) { /* VQDMULH */ - switch (size) { - case 1: - gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2); - break; - case 2: - gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); - break; - default: abort(); - } - } else { /* VQRDMULH */ - switch (size) { - case 1: - gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); - break; - case 2: - gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); - break; - default: abort(); - } - } - break; case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */ { TCGv_ptr fpstatus = get_fpstatus_ptr(1); From a26a352bb498662cd0c205cb433a352f86fac7d2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:58 +0100 Subject: [PATCH 0458/2595] target/arm: Convert Neon VADD, VSUB, VABD 3-reg-same insns to decodetree Convert the Neon VADD, VSUB, VABD 3-reg-same insns to decodetree. We already have gvec helpers for addition and subtraction, but must add one for fabd. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-12-peter.maydell@linaro.org --- target/arm/helper.h | 3 ++- target/arm/neon-dp.decode | 8 ++++++++ target/arm/neon_helper.c | 7 ------- target/arm/translate-neon.inc.c | 28 ++++++++++++++++++++++++++++ target/arm/translate.c | 10 +++------- target/arm/vec_helper.c | 7 +++++++ 6 files changed, 48 insertions(+), 15 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 1857f4ee46..6e9629c87b 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -396,7 +396,6 @@ DEF_HELPER_FLAGS_2(neon_qneg_s16, TCG_CALL_NO_RWG, i32, env, i32) DEF_HELPER_FLAGS_2(neon_qneg_s32, TCG_CALL_NO_RWG, i32, env, i32) DEF_HELPER_FLAGS_2(neon_qneg_s64, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_3(neon_abd_f32, i32, i32, i32, ptr) DEF_HELPER_3(neon_ceq_f32, i32, i32, i32, ptr) DEF_HELPER_3(neon_cge_f32, i32, i32, i32, ptr) DEF_HELPER_3(neon_cgt_f32, i32, i32, i32, ptr) @@ -595,6 +594,8 @@ DEF_HELPER_FLAGS_5(gvec_fmul_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(gvec_fmul_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(gvec_fmul_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_fabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) + DEF_HELPER_FLAGS_5(gvec_ftsmul_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(gvec_ftsmul_s, TCG_CALL_NO_RWG, diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index fd32837fb1..0dd02f3b72 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -45,6 +45,10 @@ @3same_q0 .... ... . . . size:2 .... .... .... . 0 . . .... \ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp q=0 +# For FP insns the high bit of 'size' is used as part of opcode decode +@3same_fp .... ... . . . . size:1 .... .... .... . q:1 . . .... \ + &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp + VHADD_S_3s 1111 001 0 0 . .. .... .... 0000 . . . 0 .... @3same VHADD_U_3s 1111 001 1 0 . .. .... .... 0000 . . . 0 .... @3same VQADD_S_3s 1111 001 0 0 . .. .... .... 0000 . . . 1 .... @3same @@ -169,3 +173,7 @@ SHA256SU1_3s 1111 001 1 0 . 10 .... .... 1100 . 1 . 0 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp VQRDMLSH_3s 1111 001 1 0 . .. .... .... 1100 ... 1 .... @3same + +VADD_fp_3s 1111 001 0 0 . 0 . .... .... 1101 ... 0 .... @3same_fp +VSUB_fp_3s 1111 001 0 0 . 1 . .... .... 1101 ... 0 .... @3same_fp +VABD_fp_3s 1111 001 1 0 . 1 . .... .... 1101 ... 0 .... @3same_fp diff --git a/target/arm/neon_helper.c b/target/arm/neon_helper.c index 2ef75e04c8..b637265691 100644 --- a/target/arm/neon_helper.c +++ b/target/arm/neon_helper.c @@ -1825,13 +1825,6 @@ uint64_t HELPER(neon_qneg_s64)(CPUARMState *env, uint64_t x) } /* NEON Float helpers. */ -uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b, void *fpstp) -{ - float_status *fpst = fpstp; - float32 f0 = make_float32(a); - float32 f1 = make_float32(b); - return float32_val(float32_abs(float32_sub(f0, f1, fpst))); -} /* Floating point comparisons produce an integer result. * Note that EQ doesn't signal InvalidOp for QNaNs but GE and GT do. diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index f52302f42b..540720f5e0 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1021,3 +1021,31 @@ DO_3SAME_PAIR(VPADD, padd_u) DO_3SAME_VQDMULH(VQDMULH, qdmulh) DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) + +/* + * For all the functions using this macro, size == 1 means fp16, + * which is an architecture extension we don't implement yet. + */ +#define DO_3S_FP_GVEC(INSN,FUNC) \ + static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ + uint32_t rn_ofs, uint32_t rm_ofs, \ + uint32_t oprsz, uint32_t maxsz) \ + { \ + TCGv_ptr fpst = get_fpstatus_ptr(1); \ + tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst, \ + oprsz, maxsz, 0, FUNC); \ + tcg_temp_free_ptr(fpst); \ + } \ + static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ + { \ + if (a->size != 0) { \ + /* TODO fp16 support */ \ + return false; \ + } \ + return do_3same(s, a, gen_##INSN##_3s); \ + } + + +DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s) +DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s) +DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s) diff --git a/target/arm/translate.c b/target/arm/translate.c index 561cb67286..8a94856cd2 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5445,6 +5445,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) switch (op) { case NEON_3R_FLOAT_ARITH: pairwise = (u && size < 2); /* if VPADD (float) */ + if (!pairwise) { + return 1; /* handled by decodetree */ + } break; case NEON_3R_FLOAT_MINMAX: pairwise = u; /* if VPMIN/VPMAX (float) */ @@ -5501,16 +5504,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) { TCGv_ptr fpstatus = get_fpstatus_ptr(1); switch ((u << 2) | size) { - case 0: /* VADD */ case 4: /* VPADD */ gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus); break; - case 2: /* VSUB */ - gen_helper_vfp_subs(tmp, tmp, tmp2, fpstatus); - break; - case 6: /* VABD */ - gen_helper_neon_abd_f32(tmp, tmp, tmp2, fpstatus); - break; default: abort(); } diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index fa33df859e..50a499299f 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -691,6 +691,11 @@ static float64 float64_ftsmul(float64 op1, uint64_t op2, float_status *stat) return result; } +static float32 float32_abd(float32 op1, float32 op2, float_status *stat) +{ + return float32_abs(float32_sub(op1, op2, stat)); +} + #define DO_3OP(NAME, FUNC, TYPE) \ void HELPER(NAME)(void *vd, void *vn, void *vm, void *stat, uint32_t desc) \ { \ @@ -718,6 +723,8 @@ DO_3OP(gvec_ftsmul_h, float16_ftsmul, float16) DO_3OP(gvec_ftsmul_s, float32_ftsmul, float32) DO_3OP(gvec_ftsmul_d, float64_ftsmul, float64) +DO_3OP(gvec_fabd_s, float32_abd, float32) + #ifdef TARGET_AARCH64 DO_3OP(gvec_recps_h, helper_recpsf_f16, float16) From ab978335a56e3618212868fdce3a54217c6e71e6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:38:59 +0100 Subject: [PATCH 0459/2595] target/arm: Convert Neon VPMIN/VPMAX/VPADD float 3-reg-same insns to decodetree Convert the Neon float VPMIN, VPMAX and VPADD 3-reg-same insns to decodetree. These are the only remaining 'pairwise' operations, so we can delete the pairwise-specific bits of the old decoder's for-each-element loop now. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-13-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 5 +++ target/arm/translate-neon.inc.c | 63 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 63 +++++---------------------------- 3 files changed, 76 insertions(+), 55 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 0dd02f3b72..d66c67ca58 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -48,6 +48,8 @@ # For FP insns the high bit of 'size' is used as part of opcode decode @3same_fp .... ... . . . . size:1 .... .... .... . q:1 . . .... \ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp +@3same_fp_q0 .... ... . . . . size:1 .... .... .... . 0 . . .... \ + &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp q=0 VHADD_S_3s 1111 001 0 0 . .. .... .... 0000 . . . 0 .... @3same VHADD_U_3s 1111 001 1 0 . .. .... .... 0000 . . . 0 .... @3same @@ -176,4 +178,7 @@ VQRDMLSH_3s 1111 001 1 0 . .. .... .... 1100 ... 1 .... @3same VADD_fp_3s 1111 001 0 0 . 0 . .... .... 1101 ... 0 .... @3same_fp VSUB_fp_3s 1111 001 0 0 . 1 . .... .... 1101 ... 0 .... @3same_fp +VPADD_fp_3s 1111 001 1 0 . 0 . .... .... 1101 ... 0 .... @3same_fp_q0 VABD_fp_3s 1111 001 1 0 . 1 . .... .... 1101 ... 0 .... @3same_fp +VPMAX_fp_3s 1111 001 1 0 . 0 . .... .... 1111 ... 0 .... @3same_fp_q0 +VPMIN_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 0 .... @3same_fp_q0 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 540720f5e0..7bdf1e3fee 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1049,3 +1049,66 @@ DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s) DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s) DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s) + +static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn) +{ + /* FP operations handled pairwise 32 bits at a time */ + TCGv_i32 tmp, tmp2, tmp3; + TCGv_ptr fpstatus; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + assert(a->q == 0); /* enforced by decode patterns */ + + /* + * Note that we have to be careful not to clobber the source operands + * in the "vm == vd" case by storing the result of the first pass too + * early. Since Q is 0 there are always just two passes, so instead + * of a complicated loop over each pass we just unroll. + */ + fpstatus = get_fpstatus_ptr(1); + tmp = neon_load_reg(a->vn, 0); + tmp2 = neon_load_reg(a->vn, 1); + fn(tmp, tmp, tmp2, fpstatus); + tcg_temp_free_i32(tmp2); + + tmp3 = neon_load_reg(a->vm, 0); + tmp2 = neon_load_reg(a->vm, 1); + fn(tmp3, tmp3, tmp2, fpstatus); + tcg_temp_free_i32(tmp2); + tcg_temp_free_ptr(fpstatus); + + neon_store_reg(a->vd, 0, tmp); + neon_store_reg(a->vd, 1, tmp3); + return true; +} + +/* + * For all the functions using this macro, size == 1 means fp16, + * which is an architecture extension we don't implement yet. + */ +#define DO_3S_FP_PAIR(INSN,FUNC) \ + static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ + { \ + if (a->size != 0) { \ + /* TODO fp16 support */ \ + return false; \ + } \ + return do_3same_fp_pair(s, a, FUNC); \ + } + +DO_3S_FP_PAIR(VPADD, gen_helper_vfp_adds) +DO_3S_FP_PAIR(VPMAX, gen_helper_vfp_maxs) +DO_3S_FP_PAIR(VPMIN, gen_helper_vfp_mins) diff --git a/target/arm/translate.c b/target/arm/translate.c index 8a94856cd2..ca6ed09ec3 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5348,7 +5348,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int shift; int pass; int count; - int pairwise; int u; int vec_size; uint32_t imm; @@ -5433,6 +5432,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VPMIN: case NEON_3R_VPADD_VQRDMLAH: case NEON_3R_VQDMULH_VQRDMULH: + case NEON_3R_FLOAT_ARITH: /* Already handled by decodetree */ return 1; } @@ -5441,16 +5441,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) /* 64-bit element instructions: handled by decodetree */ return 1; } - pairwise = 0; switch (op) { - case NEON_3R_FLOAT_ARITH: - pairwise = (u && size < 2); /* if VPADD (float) */ - if (!pairwise) { - return 1; /* handled by decodetree */ - } - break; case NEON_3R_FLOAT_MINMAX: - pairwise = u; /* if VPMIN/VPMAX (float) */ + if (u) { + return 1; /* VPMIN/VPMAX handled by decodetree */ + } break; case NEON_3R_FLOAT_CMP: if (!u && size) { @@ -5478,41 +5473,12 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) break; } - if (pairwise && q) { - /* All the pairwise insns UNDEF if Q is set */ - return 1; - } - for (pass = 0; pass < (q ? 4 : 2); pass++) { - if (pairwise) { - /* Pairwise. */ - if (pass < 1) { - tmp = neon_load_reg(rn, 0); - tmp2 = neon_load_reg(rn, 1); - } else { - tmp = neon_load_reg(rm, 0); - tmp2 = neon_load_reg(rm, 1); - } - } else { - /* Elementwise. */ - tmp = neon_load_reg(rn, pass); - tmp2 = neon_load_reg(rm, pass); - } + /* Elementwise. */ + tmp = neon_load_reg(rn, pass); + tmp2 = neon_load_reg(rm, pass); switch (op) { - case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */ - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - switch ((u << 2) | size) { - case 4: /* VPADD */ - gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus); - break; - default: - abort(); - } - tcg_temp_free_ptr(fpstatus); - break; - } case NEON_3R_FLOAT_MULTIPLY: { TCGv_ptr fpstatus = get_fpstatus_ptr(1); @@ -5603,22 +5569,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } tcg_temp_free_i32(tmp2); - /* Save the result. For elementwise operations we can put it - straight into the destination register. For pairwise operations - we have to be careful to avoid clobbering the source operands. */ - if (pairwise && rd == rm) { - neon_store_scratch(pass, tmp); - } else { - neon_store_reg(rd, pass, tmp); - } + neon_store_reg(rd, pass, tmp); } /* for pass */ - if (pairwise && rd == rm) { - for (pass = 0; pass < (q ? 4 : 2); pass++) { - tmp = neon_load_scratch(pass); - neon_store_reg(rd, pass, tmp); - } - } /* End of 3 register same size operations. */ } else if (insn & (1 << 4)) { if ((insn & 0x00380080) != 0) { From 8aa71ead912ca0a9c0d29b74e0976f91952f950a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:39:00 +0100 Subject: [PATCH 0460/2595] target/arm: Convert Neon fp VMUL, VMLA, VMLS 3-reg-same insns to decodetree Convert the Neon integer VMUL, VMLA, and VMLS 3-reg-same inssn to decodetree. We don't have a gvec helper for multiply-accumulate, so VMLA and VMLS need a loop function do_3same_fp(). This takes a reads_vd parameter to do_3same_fp() which tells it to load the old value into vd before calling the callback function, in the same way that the do_vfp_3op_sp() and do_vfp_3op_dp() functions in translate-vfp.inc.c work. (The only uses in this patch pass reads_vd == true, but later commits will use reads_vd == false.) This conversion fixes in passing an underdecoding for VMUL (originally reported by Fredrik Strupe ): bit 1 of the 'size' field must be 0. The old decoder didn't enforce this, but the decodetree pattern does. The gen_VMLA_fp_reg() function performs the addition operation with the operands in the opposite order to the old decoder: since Neon sets 'default NaN mode' float32_add operations are commutative so there is no behaviour difference, but putting them this way around matches the Arm ARM pseudocode and the required operation order for the subtraction in gen_VMLS_fp_reg(). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-14-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 3 ++ target/arm/translate-neon.inc.c | 81 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 17 +------ 3 files changed, 85 insertions(+), 16 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index d66c67ca58..4c2f8c770d 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -180,5 +180,8 @@ VADD_fp_3s 1111 001 0 0 . 0 . .... .... 1101 ... 0 .... @3same_fp VSUB_fp_3s 1111 001 0 0 . 1 . .... .... 1101 ... 0 .... @3same_fp VPADD_fp_3s 1111 001 1 0 . 0 . .... .... 1101 ... 0 .... @3same_fp_q0 VABD_fp_3s 1111 001 1 0 . 1 . .... .... 1101 ... 0 .... @3same_fp +VMLA_fp_3s 1111 001 0 0 . 0 . .... .... 1101 ... 1 .... @3same_fp +VMLS_fp_3s 1111 001 0 0 . 1 . .... .... 1101 ... 1 .... @3same_fp +VMUL_fp_3s 1111 001 1 0 . 0 . .... .... 1101 ... 1 .... @3same_fp VPMAX_fp_3s 1111 001 1 0 . 0 . .... .... 1111 ... 0 .... @3same_fp_q0 VPMIN_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 0 .... @3same_fp_q0 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 7bdf1e3fee..18896598bb 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1022,6 +1022,55 @@ DO_3SAME_PAIR(VPADD, padd_u) DO_3SAME_VQDMULH(VQDMULH, qdmulh) DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) +static bool do_3same_fp(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn, + bool reads_vd) +{ + /* + * FP operations handled elementwise 32 bits at a time. + * If reads_vd is true then the old value of Vd will be + * loaded before calling the callback function. This is + * used for multiply-accumulate type operations. + */ + TCGv_i32 tmp, tmp2; + int pass; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if ((a->vn | a->vm | a->vd) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + TCGv_ptr fpstatus = get_fpstatus_ptr(1); + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + tmp = neon_load_reg(a->vn, pass); + tmp2 = neon_load_reg(a->vm, pass); + if (reads_vd) { + TCGv_i32 tmp_rd = neon_load_reg(a->vd, pass); + fn(tmp_rd, tmp, tmp2, fpstatus); + neon_store_reg(a->vd, pass, tmp_rd); + tcg_temp_free_i32(tmp); + } else { + fn(tmp, tmp, tmp2, fpstatus); + neon_store_reg(a->vd, pass, tmp); + } + tcg_temp_free_i32(tmp2); + } + tcg_temp_free_ptr(fpstatus); + return true; +} + /* * For all the functions using this macro, size == 1 means fp16, * which is an architecture extension we don't implement yet. @@ -1049,6 +1098,38 @@ DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s) DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s) DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s) +DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s) + +/* + * For all the functions using this macro, size == 1 means fp16, + * which is an architecture extension we don't implement yet. + */ +#define DO_3S_FP(INSN,FUNC,READS_VD) \ + static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ + { \ + if (a->size != 0) { \ + /* TODO fp16 support */ \ + return false; \ + } \ + return do_3same_fp(s, a, FUNC, READS_VD); \ + } + +static void gen_VMLA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, + TCGv_ptr fpstatus) +{ + gen_helper_vfp_muls(vn, vn, vm, fpstatus); + gen_helper_vfp_adds(vd, vd, vn, fpstatus); +} + +static void gen_VMLS_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, + TCGv_ptr fpstatus) +{ + gen_helper_vfp_muls(vn, vn, vm, fpstatus); + gen_helper_vfp_subs(vd, vd, vn, fpstatus); +} + +DO_3S_FP(VMLA, gen_VMLA_fp_3s, true) +DO_3S_FP(VMLS, gen_VMLS_fp_3s, true) static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn) { diff --git a/target/arm/translate.c b/target/arm/translate.c index ca6ed09ec3..06b6925d31 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5433,6 +5433,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VPADD_VQRDMLAH: case NEON_3R_VQDMULH_VQRDMULH: case NEON_3R_FLOAT_ARITH: + case NEON_3R_FLOAT_MULTIPLY: /* Already handled by decodetree */ return 1; } @@ -5479,22 +5480,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp = neon_load_reg(rn, pass); tmp2 = neon_load_reg(rm, pass); switch (op) { - case NEON_3R_FLOAT_MULTIPLY: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus); - if (!u) { - tcg_temp_free_i32(tmp2); - tmp2 = neon_load_reg(rd, pass); - if (size == 0) { - gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus); - } else { - gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus); - } - } - tcg_temp_free_ptr(fpstatus); - break; - } case NEON_3R_FLOAT_CMP: { TCGv_ptr fpstatus = get_fpstatus_ptr(1); From 727ff1d63213e6666e511956903b9e97a339ec7e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:39:01 +0100 Subject: [PATCH 0461/2595] target/arm: Convert Neon 3-reg-same compare insns to decodetree Convert the Neon integer 3-reg-same compare insns VCGE, VCGT, VCEQ, VACGE and VACGT to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-15-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 5 +++++ target/arm/translate-neon.inc.c | 6 +++++ target/arm/translate.c | 39 ++------------------------------- 3 files changed, 13 insertions(+), 37 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 4c2f8c770d..29cf54c217 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -183,5 +183,10 @@ VABD_fp_3s 1111 001 1 0 . 1 . .... .... 1101 ... 0 .... @3same_fp VMLA_fp_3s 1111 001 0 0 . 0 . .... .... 1101 ... 1 .... @3same_fp VMLS_fp_3s 1111 001 0 0 . 1 . .... .... 1101 ... 1 .... @3same_fp VMUL_fp_3s 1111 001 1 0 . 0 . .... .... 1101 ... 1 .... @3same_fp +VCEQ_fp_3s 1111 001 0 0 . 0 . .... .... 1110 ... 0 .... @3same_fp +VCGE_fp_3s 1111 001 1 0 . 0 . .... .... 1110 ... 0 .... @3same_fp +VACGE_fp_3s 1111 001 1 0 . 0 . .... .... 1110 ... 1 .... @3same_fp +VCGT_fp_3s 1111 001 1 0 . 1 . .... .... 1110 ... 0 .... @3same_fp +VACGT_fp_3s 1111 001 1 0 . 1 . .... .... 1110 ... 1 .... @3same_fp VPMAX_fp_3s 1111 001 1 0 . 0 . .... .... 1111 ... 0 .... @3same_fp_q0 VPMIN_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 0 .... @3same_fp_q0 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 18896598bb..eeea71e3be 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1114,6 +1114,12 @@ DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s) return do_3same_fp(s, a, FUNC, READS_VD); \ } +DO_3S_FP(VCEQ, gen_helper_neon_ceq_f32, false) +DO_3S_FP(VCGE, gen_helper_neon_cge_f32, false) +DO_3S_FP(VCGT, gen_helper_neon_cgt_f32, false) +DO_3S_FP(VACGE, gen_helper_neon_acge_f32, false) +DO_3S_FP(VACGT, gen_helper_neon_acgt_f32, false) + static void gen_VMLA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpstatus) { diff --git a/target/arm/translate.c b/target/arm/translate.c index 06b6925d31..b9fcbbcbcb 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5434,6 +5434,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_VQDMULH_VQRDMULH: case NEON_3R_FLOAT_ARITH: case NEON_3R_FLOAT_MULTIPLY: + case NEON_3R_FLOAT_CMP: + case NEON_3R_FLOAT_ACMP: /* Already handled by decodetree */ return 1; } @@ -5448,17 +5450,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 1; /* VPMIN/VPMAX handled by decodetree */ } break; - case NEON_3R_FLOAT_CMP: - if (!u && size) { - /* no encoding for U=0 C=1x */ - return 1; - } - break; - case NEON_3R_FLOAT_ACMP: - if (!u) { - return 1; - } - break; case NEON_3R_FLOAT_MISC: /* VMAXNM/VMINNM in ARMv8 */ if (u && !arm_dc_feature(s, ARM_FEATURE_V8)) { @@ -5480,32 +5471,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp = neon_load_reg(rn, pass); tmp2 = neon_load_reg(rm, pass); switch (op) { - case NEON_3R_FLOAT_CMP: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - if (!u) { - gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus); - } else { - if (size == 0) { - gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus); - } else { - gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus); - } - } - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_3R_FLOAT_ACMP: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - if (size == 0) { - gen_helper_neon_acge_f32(tmp, tmp, tmp2, fpstatus); - } else { - gen_helper_neon_acgt_f32(tmp, tmp, tmp2, fpstatus); - } - tcg_temp_free_ptr(fpstatus); - break; - } case NEON_3R_FLOAT_MINMAX: { TCGv_ptr fpstatus = get_fpstatus_ptr(1); From 26c6f695cfd2a3ccddb4d015a25b56f56aa62928 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:39:02 +0100 Subject: [PATCH 0462/2595] target/arm: Move 'env' argument of recps_f32 and rsqrts_f32 helpers to usual place The usual location for the env argument in the argument list of a TCG helper is immediately after the return-value argument. recps_f32 and rsqrts_f32 differ in that they put it at the end. Move the env argument to its usual place; this will allow us to more easily use these helper functions with the gvec APIs. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-16-peter.maydell@linaro.org --- target/arm/helper.h | 4 ++-- target/arm/translate.c | 4 ++-- target/arm/vfp_helper.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 6e9629c87b..49336dc432 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -203,8 +203,8 @@ DEF_HELPER_FLAGS_3(vfp_fcvt_f64_to_f16, TCG_CALL_NO_RWG, f16, f64, ptr, i32) DEF_HELPER_4(vfp_muladdd, f64, f64, f64, f64, ptr) DEF_HELPER_4(vfp_muladds, f32, f32, f32, f32, ptr) -DEF_HELPER_3(recps_f32, f32, f32, f32, env) -DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env) +DEF_HELPER_3(recps_f32, f32, env, f32, f32) +DEF_HELPER_3(rsqrts_f32, f32, env, f32, f32) DEF_HELPER_FLAGS_2(recpe_f16, TCG_CALL_NO_RWG, f16, f16, ptr) DEF_HELPER_FLAGS_2(recpe_f32, TCG_CALL_NO_RWG, f32, f32, ptr) DEF_HELPER_FLAGS_2(recpe_f64, TCG_CALL_NO_RWG, f64, f64, ptr) diff --git a/target/arm/translate.c b/target/arm/translate.c index b9fcbbcbcb..23e3705172 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5494,9 +5494,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(fpstatus); } else { if (size == 0) { - gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env); + gen_helper_recps_f32(tmp, cpu_env, tmp, tmp2); } else { - gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env); + gen_helper_rsqrts_f32(tmp, cpu_env, tmp, tmp2); } } break; diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index ec007fce25..88483d4066 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -581,7 +581,7 @@ uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, void *fpstp, uint32_t ahp_mode) #define float32_three make_float32(0x40400000) #define float32_one_point_five make_float32(0x3fc00000) -float32 HELPER(recps_f32)(float32 a, float32 b, CPUARMState *env) +float32 HELPER(recps_f32)(CPUARMState *env, float32 a, float32 b) { float_status *s = &env->vfp.standard_fp_status; if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) || @@ -594,7 +594,7 @@ float32 HELPER(recps_f32)(float32 a, float32 b, CPUARMState *env) return float32_sub(float32_two, float32_mul(a, b, s), s); } -float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUARMState *env) +float32 HELPER(rsqrts_f32)(CPUARMState *env, float32 a, float32 b) { float_status *s = &env->vfp.standard_fp_status; float32 product; From d5fdf9e9e1c6f2bbb0a4bcaafd85d344cce9c298 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:39:03 +0100 Subject: [PATCH 0463/2595] target/arm: Convert Neon fp VMAX/VMIN/VMAXNM/VMINNM/VRECPS/VRSQRTS to decodetree Convert the Neon fp VMAX/VMIN/VMAXNM/VMINNM/VRECPS/VRSQRTS 3-reg-same insns to decodetree. (These are all the remaining non-accumulation instructions in this group.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-17-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 6 +++ target/arm/translate-neon.inc.c | 70 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 42 +------------------- 3 files changed, 78 insertions(+), 40 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 29cf54c217..9c28886507 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -188,5 +188,11 @@ VCGE_fp_3s 1111 001 1 0 . 0 . .... .... 1110 ... 0 .... @3same_fp VACGE_fp_3s 1111 001 1 0 . 0 . .... .... 1110 ... 1 .... @3same_fp VCGT_fp_3s 1111 001 1 0 . 1 . .... .... 1110 ... 0 .... @3same_fp VACGT_fp_3s 1111 001 1 0 . 1 . .... .... 1110 ... 1 .... @3same_fp +VMAX_fp_3s 1111 001 0 0 . 0 . .... .... 1111 ... 0 .... @3same_fp +VMIN_fp_3s 1111 001 0 0 . 1 . .... .... 1111 ... 0 .... @3same_fp VPMAX_fp_3s 1111 001 1 0 . 0 . .... .... 1111 ... 0 .... @3same_fp_q0 VPMIN_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 0 .... @3same_fp_q0 +VRECPS_fp_3s 1111 001 0 0 . 0 . .... .... 1111 ... 1 .... @3same_fp +VRSQRTS_fp_3s 1111 001 0 0 . 1 . .... .... 1111 ... 1 .... @3same_fp +VMAXNM_fp_3s 1111 001 1 0 . 0 . .... .... 1111 ... 1 .... @3same_fp +VMINNM_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 1 .... @3same_fp diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index eeea71e3be..5e9e53c5c3 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1119,6 +1119,8 @@ DO_3S_FP(VCGE, gen_helper_neon_cge_f32, false) DO_3S_FP(VCGT, gen_helper_neon_cgt_f32, false) DO_3S_FP(VACGE, gen_helper_neon_acge_f32, false) DO_3S_FP(VACGT, gen_helper_neon_acgt_f32, false) +DO_3S_FP(VMAX, gen_helper_vfp_maxs, false) +DO_3S_FP(VMIN, gen_helper_vfp_mins, false) static void gen_VMLA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpstatus) @@ -1137,6 +1139,74 @@ static void gen_VMLS_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, DO_3S_FP(VMLA, gen_VMLA_fp_3s, true) DO_3S_FP(VMLS, gen_VMLS_fp_3s, true) +static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a) +{ + if (!arm_dc_feature(s, ARM_FEATURE_V8)) { + return false; + } + + if (a->size != 0) { + /* TODO fp16 support */ + return false; + } + + return do_3same_fp(s, a, gen_helper_vfp_maxnums, false); +} + +static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a) +{ + if (!arm_dc_feature(s, ARM_FEATURE_V8)) { + return false; + } + + if (a->size != 0) { + /* TODO fp16 support */ + return false; + } + + return do_3same_fp(s, a, gen_helper_vfp_minnums, false); +} + +WRAP_ENV_FN(gen_VRECPS_tramp, gen_helper_recps_f32) + +static void gen_VRECPS_fp_3s(unsigned vece, uint32_t rd_ofs, + uint32_t rn_ofs, uint32_t rm_ofs, + uint32_t oprsz, uint32_t maxsz) +{ + static const GVecGen3 ops = { .fni4 = gen_VRECPS_tramp }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops); +} + +static bool trans_VRECPS_fp_3s(DisasContext *s, arg_3same *a) +{ + if (a->size != 0) { + /* TODO fp16 support */ + return false; + } + + return do_3same(s, a, gen_VRECPS_fp_3s); +} + +WRAP_ENV_FN(gen_VRSQRTS_tramp, gen_helper_rsqrts_f32) + +static void gen_VRSQRTS_fp_3s(unsigned vece, uint32_t rd_ofs, + uint32_t rn_ofs, uint32_t rm_ofs, + uint32_t oprsz, uint32_t maxsz) +{ + static const GVecGen3 ops = { .fni4 = gen_VRSQRTS_tramp }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops); +} + +static bool trans_VRSQRTS_fp_3s(DisasContext *s, arg_3same *a) +{ + if (a->size != 0) { + /* TODO fp16 support */ + return false; + } + + return do_3same(s, a, gen_VRSQRTS_fp_3s); +} + static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn) { /* FP operations handled pairwise 32 bits at a time */ diff --git a/target/arm/translate.c b/target/arm/translate.c index 23e3705172..c1d4fab8e8 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5436,6 +5436,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_3R_FLOAT_MULTIPLY: case NEON_3R_FLOAT_CMP: case NEON_3R_FLOAT_ACMP: + case NEON_3R_FLOAT_MINMAX: + case NEON_3R_FLOAT_MISC: /* Already handled by decodetree */ return 1; } @@ -5445,17 +5447,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 1; } switch (op) { - case NEON_3R_FLOAT_MINMAX: - if (u) { - return 1; /* VPMIN/VPMAX handled by decodetree */ - } - break; - case NEON_3R_FLOAT_MISC: - /* VMAXNM/VMINNM in ARMv8 */ - if (u && !arm_dc_feature(s, ARM_FEATURE_V8)) { - return 1; - } - break; case NEON_3R_VFM_VQRDMLSH: if (!dc_isar_feature(aa32_simdfmac, s)) { return 1; @@ -5471,35 +5462,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp = neon_load_reg(rn, pass); tmp2 = neon_load_reg(rm, pass); switch (op) { - case NEON_3R_FLOAT_MINMAX: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - if (size == 0) { - gen_helper_vfp_maxs(tmp, tmp, tmp2, fpstatus); - } else { - gen_helper_vfp_mins(tmp, tmp, tmp2, fpstatus); - } - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_3R_FLOAT_MISC: - if (u) { - /* VMAXNM/VMINNM */ - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - if (size == 0) { - gen_helper_vfp_maxnums(tmp, tmp, tmp2, fpstatus); - } else { - gen_helper_vfp_minnums(tmp, tmp, tmp2, fpstatus); - } - tcg_temp_free_ptr(fpstatus); - } else { - if (size == 0) { - gen_helper_recps_f32(tmp, cpu_env, tmp, tmp2); - } else { - gen_helper_rsqrts_f32(tmp, cpu_env, tmp, tmp2); - } - } - break; case NEON_3R_VFM_VQRDMLSH: { /* VFMA, VFMS: fused multiply-add */ From e95485f85657be21135c17a9226e297c21e73360 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 May 2020 17:39:04 +0100 Subject: [PATCH 0464/2595] target/arm: Convert NEON VFMA, VFMS 3-reg-same insns to decodetree Convert the Neon floating point VFMA and VFMS insn to decodetree. These are the last insns in the 3-reg-same group so we can remove all the support/loop code from the old decoder. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200512163904.10918-18-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 3 + target/arm/translate-neon.inc.c | 41 ++++++++ target/arm/translate.c | 176 +------------------------------- 3 files changed, 46 insertions(+), 174 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 9c28886507..8beb1db768 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -174,6 +174,9 @@ SHA256H2_3s 1111 001 1 0 . 01 .... .... 1100 . 1 . 0 .... \ SHA256SU1_3s 1111 001 1 0 . 10 .... .... 1100 . 1 . 0 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp +VFMA_fp_3s 1111 001 0 0 . 0 . .... .... 1100 ... 1 .... @3same_fp +VFMS_fp_3s 1111 001 0 0 . 1 . .... .... 1100 ... 1 .... @3same_fp + VQRDMLSH_3s 1111 001 1 0 . .. .... .... 1100 ... 1 .... @3same VADD_fp_3s 1111 001 0 0 . 0 . .... .... 1101 ... 0 .... @3same_fp diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 5e9e53c5c3..3fe65a0b08 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1207,6 +1207,47 @@ static bool trans_VRSQRTS_fp_3s(DisasContext *s, arg_3same *a) return do_3same(s, a, gen_VRSQRTS_fp_3s); } +static void gen_VFMA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, + TCGv_ptr fpstatus) +{ + gen_helper_vfp_muladds(vd, vn, vm, vd, fpstatus); +} + +static bool trans_VFMA_fp_3s(DisasContext *s, arg_3same *a) +{ + if (!dc_isar_feature(aa32_simdfmac, s)) { + return false; + } + + if (a->size != 0) { + /* TODO fp16 support */ + return false; + } + + return do_3same_fp(s, a, gen_VFMA_fp_3s, true); +} + +static void gen_VFMS_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, + TCGv_ptr fpstatus) +{ + gen_helper_vfp_negs(vn, vn); + gen_helper_vfp_muladds(vd, vn, vm, vd, fpstatus); +} + +static bool trans_VFMS_fp_3s(DisasContext *s, arg_3same *a) +{ + if (!dc_isar_feature(aa32_simdfmac, s)) { + return false; + } + + if (a->size != 0) { + /* TODO fp16 support */ + return false; + } + + return do_3same_fp(s, a, gen_VFMS_fp_3s, true); +} + static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn) { /* FP operations handled pairwise 32 bits at a time */ diff --git a/target/arm/translate.c b/target/arm/translate.c index c1d4fab8e8..4c9bb8b5ac 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3391,78 +3391,6 @@ static void gen_neon_narrow_op(int op, int u, int size, } } -/* Symbolic constants for op fields for Neon 3-register same-length. - * The values correspond to bits [11:8,4]; see the ARM ARM DDI0406B - * table A7-9. - */ -#define NEON_3R_VHADD 0 -#define NEON_3R_VQADD 1 -#define NEON_3R_VRHADD 2 -#define NEON_3R_LOGIC 3 /* VAND,VBIC,VORR,VMOV,VORN,VEOR,VBIF,VBIT,VBSL */ -#define NEON_3R_VHSUB 4 -#define NEON_3R_VQSUB 5 -#define NEON_3R_VCGT 6 -#define NEON_3R_VCGE 7 -#define NEON_3R_VSHL 8 -#define NEON_3R_VQSHL 9 -#define NEON_3R_VRSHL 10 -#define NEON_3R_VQRSHL 11 -#define NEON_3R_VMAX 12 -#define NEON_3R_VMIN 13 -#define NEON_3R_VABD 14 -#define NEON_3R_VABA 15 -#define NEON_3R_VADD_VSUB 16 -#define NEON_3R_VTST_VCEQ 17 -#define NEON_3R_VML 18 /* VMLA, VMLS */ -#define NEON_3R_VMUL 19 -#define NEON_3R_VPMAX 20 -#define NEON_3R_VPMIN 21 -#define NEON_3R_VQDMULH_VQRDMULH 22 -#define NEON_3R_VPADD_VQRDMLAH 23 -#define NEON_3R_SHA 24 /* SHA1C,SHA1P,SHA1M,SHA1SU0,SHA256H{2},SHA256SU1 */ -#define NEON_3R_VFM_VQRDMLSH 25 /* VFMA, VFMS, VQRDMLSH */ -#define NEON_3R_FLOAT_ARITH 26 /* float VADD, VSUB, VPADD, VABD */ -#define NEON_3R_FLOAT_MULTIPLY 27 /* float VMLA, VMLS, VMUL */ -#define NEON_3R_FLOAT_CMP 28 /* float VCEQ, VCGE, VCGT */ -#define NEON_3R_FLOAT_ACMP 29 /* float VACGE, VACGT, VACLE, VACLT */ -#define NEON_3R_FLOAT_MINMAX 30 /* float VMIN, VMAX */ -#define NEON_3R_FLOAT_MISC 31 /* float VRECPS, VRSQRTS, VMAXNM/MINNM */ - -static const uint8_t neon_3r_sizes[] = { - [NEON_3R_VHADD] = 0x7, - [NEON_3R_VQADD] = 0xf, - [NEON_3R_VRHADD] = 0x7, - [NEON_3R_LOGIC] = 0xf, /* size field encodes op type */ - [NEON_3R_VHSUB] = 0x7, - [NEON_3R_VQSUB] = 0xf, - [NEON_3R_VCGT] = 0x7, - [NEON_3R_VCGE] = 0x7, - [NEON_3R_VSHL] = 0xf, - [NEON_3R_VQSHL] = 0xf, - [NEON_3R_VRSHL] = 0xf, - [NEON_3R_VQRSHL] = 0xf, - [NEON_3R_VMAX] = 0x7, - [NEON_3R_VMIN] = 0x7, - [NEON_3R_VABD] = 0x7, - [NEON_3R_VABA] = 0x7, - [NEON_3R_VADD_VSUB] = 0xf, - [NEON_3R_VTST_VCEQ] = 0x7, - [NEON_3R_VML] = 0x7, - [NEON_3R_VMUL] = 0x7, - [NEON_3R_VPMAX] = 0x7, - [NEON_3R_VPMIN] = 0x7, - [NEON_3R_VQDMULH_VQRDMULH] = 0x6, - [NEON_3R_VPADD_VQRDMLAH] = 0x7, - [NEON_3R_SHA] = 0xf, /* size field encodes op type */ - [NEON_3R_VFM_VQRDMLSH] = 0x7, /* For VFM, size bit 1 encodes op */ - [NEON_3R_FLOAT_ARITH] = 0x5, /* size bit 1 encodes op */ - [NEON_3R_FLOAT_MULTIPLY] = 0x5, /* size bit 1 encodes op */ - [NEON_3R_FLOAT_CMP] = 0x5, /* size bit 1 encodes op */ - [NEON_3R_FLOAT_ACMP] = 0x5, /* size bit 1 encodes op */ - [NEON_3R_FLOAT_MINMAX] = 0x5, /* size bit 1 encodes op */ - [NEON_3R_FLOAT_MISC] = 0x5, /* size bit 1 encodes op */ -}; - /* Symbolic constants for op fields for Neon 2-register miscellaneous. * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B * table A7-13. @@ -5383,108 +5311,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) rm_ofs = neon_reg_offset(rm, 0); if ((insn & (1 << 23)) == 0) { - /* Three register same length. */ - op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1); - /* Catch invalid op and bad size combinations: UNDEF */ - if ((neon_3r_sizes[op] & (1 << size)) == 0) { - return 1; - } - /* All insns of this form UNDEF for either this condition or the - * superset of cases "Q==1"; we catch the latter later. - */ - if (q && ((rd | rn | rm) & 1)) { - return 1; - } - switch (op) { - case NEON_3R_VFM_VQRDMLSH: - if (!u) { - /* VFM, VFMS */ - if (size == 1) { - return 1; - } - break; - } - /* VQRDMLSH : handled by decodetree */ - return 1; - - case NEON_3R_VADD_VSUB: - case NEON_3R_LOGIC: - case NEON_3R_VMAX: - case NEON_3R_VMIN: - case NEON_3R_VTST_VCEQ: - case NEON_3R_VCGT: - case NEON_3R_VCGE: - case NEON_3R_VQADD: - case NEON_3R_VQSUB: - case NEON_3R_VMUL: - case NEON_3R_VML: - case NEON_3R_VSHL: - case NEON_3R_SHA: - case NEON_3R_VHADD: - case NEON_3R_VRHADD: - case NEON_3R_VHSUB: - case NEON_3R_VABD: - case NEON_3R_VABA: - case NEON_3R_VQSHL: - case NEON_3R_VRSHL: - case NEON_3R_VQRSHL: - case NEON_3R_VPMAX: - case NEON_3R_VPMIN: - case NEON_3R_VPADD_VQRDMLAH: - case NEON_3R_VQDMULH_VQRDMULH: - case NEON_3R_FLOAT_ARITH: - case NEON_3R_FLOAT_MULTIPLY: - case NEON_3R_FLOAT_CMP: - case NEON_3R_FLOAT_ACMP: - case NEON_3R_FLOAT_MINMAX: - case NEON_3R_FLOAT_MISC: - /* Already handled by decodetree */ - return 1; - } - - if (size == 3) { - /* 64-bit element instructions: handled by decodetree */ - return 1; - } - switch (op) { - case NEON_3R_VFM_VQRDMLSH: - if (!dc_isar_feature(aa32_simdfmac, s)) { - return 1; - } - break; - default: - break; - } - - for (pass = 0; pass < (q ? 4 : 2); pass++) { - - /* Elementwise. */ - tmp = neon_load_reg(rn, pass); - tmp2 = neon_load_reg(rm, pass); - switch (op) { - case NEON_3R_VFM_VQRDMLSH: - { - /* VFMA, VFMS: fused multiply-add */ - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - TCGv_i32 tmp3 = neon_load_reg(rd, pass); - if (size) { - /* VFMS */ - gen_helper_vfp_negs(tmp, tmp); - } - gen_helper_vfp_muladds(tmp, tmp, tmp2, tmp3, fpstatus); - tcg_temp_free_i32(tmp3); - tcg_temp_free_ptr(fpstatus); - break; - } - default: - abort(); - } - tcg_temp_free_i32(tmp2); - - neon_store_reg(rd, pass, tmp); - - } /* for pass */ - /* End of 3 register same size operations. */ + /* Three register same length: handled by decodetree */ + return 1; } else if (insn & (1 << 4)) { if ((insn & 0x00380080) != 0) { /* Two registers and shift. */ From 975ac4559c4c00010e05f7a3e782eeb9497837ea Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:09 +0200 Subject: [PATCH 0465/2595] qom: Clearer reference counting in object_initialize_childv() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-2-armbru@redhat.com> --- qom/object.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/qom/object.c b/qom/object.c index be700e831f..5511649502 100644 --- a/qom/object.c +++ b/qom/object.c @@ -571,18 +571,18 @@ void object_initialize_childv(Object *parentobj, const char *propname, } } +out: /* - * Since object_property_add_child added a reference to the child object, - * we can drop the reference added by object_initialize(), so the child - * property will own the only reference to the object. + * We want @obj's reference to be 1 on success, 0 on failure. + * On success, it's 2: one taken by object_initialize(), and one + * by object_property_add_child(). + * On failure in object_initialize() or earlier, it's 1. + * On failure afterwards, it's also 1: object_unparent() releases + * the reference taken by object_property_add_child(). */ object_unref(obj); -out: - if (local_err) { - error_propagate(errp, local_err); - object_unref(obj); - } + error_propagate(errp, local_err); } static inline bool object_property_is_child(ObjectProperty *prop) From ddfb0baaf26e9e1b9869506c6e389dc8eb016de0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:10 +0200 Subject: [PATCH 0466/2595] qom: Clean up inconsistent use of gchar * vs. char * Uses of gchar * in qom/object.h: * ObjectProperty member @name Functions that take a property name argument all use char *. Change the member to match. * ObjectProperty member @type Functions that take a property type argument or return it all use char *. Change the member to match. * ObjectProperty member @description Functions that take a property description argument all use char *. Change the member to match. * object_resolve_path_component() parameter @part Path components are property names. Most callers pass char * arguments. Change the parameter to match. Adjust the few callers that pass gchar * to pass char *. * Return value of object_get_canonical_path_component(), object_get_canonical_path() Most callers convert their return values right back to char *. Change the return value to match. Adjust the few callers where that would add a conversion to gchar * to use char * instead. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-3-armbru@redhat.com> --- hw/dma/xlnx-zdma.c | 4 ++-- hw/net/virtio-net.c | 2 +- hw/ppc/spapr_drc.c | 2 +- include/qom/object.h | 12 +++++----- memory.c | 4 ++-- monitor/monitor-internal.h | 2 +- qom/container.c | 2 +- qom/object.c | 46 ++++++++++++++++++++------------------ 8 files changed, 38 insertions(+), 36 deletions(-) diff --git a/hw/dma/xlnx-zdma.c b/hw/dma/xlnx-zdma.c index 4121a1b489..2dec4a2643 100644 --- a/hw/dma/xlnx-zdma.c +++ b/hw/dma/xlnx-zdma.c @@ -719,7 +719,7 @@ static uint64_t zdma_read(void *opaque, hwaddr addr, unsigned size) RegisterInfo *r = &s->regs_info[addr / 4]; if (!r->data) { - gchar *path = object_get_canonical_path(OBJECT(s)); + char *path = object_get_canonical_path(OBJECT(s)); qemu_log("%s: Decode error: read from %" HWADDR_PRIx "\n", path, addr); @@ -738,7 +738,7 @@ static void zdma_write(void *opaque, hwaddr addr, uint64_t value, RegisterInfo *r = &s->regs_info[addr / 4]; if (!r->data) { - gchar *path = object_get_canonical_path(OBJECT(s)); + char *path = object_get_canonical_path(OBJECT(s)); qemu_log("%s: Decode error: write to %" HWADDR_PRIx "=%" PRIx64 "\n", path, addr, value); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 3301869d4f..e51231e795 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -399,7 +399,7 @@ static void rxfilter_notify(NetClientState *nc) VirtIONet *n = qemu_get_nic_opaque(nc); if (nc->rxfilter_notify_enabled) { - gchar *path = object_get_canonical_path(OBJECT(n->qdev)); + char *path = object_get_canonical_path(OBJECT(n->qdev)); qapi_event_send_nic_rx_filter_changed(!!n->netclient_name, n->netclient_name, path); g_free(path); diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 47e6bb12f9..0b66d59867 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -518,7 +518,7 @@ static void realize(DeviceState *d, Error **errp) SpaprDrc *drc = SPAPR_DR_CONNECTOR(d); Object *root_container; gchar *link_name; - gchar *child_name; + char *child_name; Error *err = NULL; trace_spapr_drc_realize(spapr_drc_index(drc)); diff --git a/include/qom/object.h b/include/qom/object.h index 784c97c0e1..ccfa82e33d 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -369,9 +369,9 @@ typedef void (ObjectPropertyInit)(Object *obj, ObjectProperty *prop); struct ObjectProperty { - gchar *name; - gchar *type; - gchar *description; + char *name; + char *type; + char *description; ObjectPropertyAccessor *get; ObjectPropertyAccessor *set; ObjectPropertyResolve *resolve; @@ -1421,7 +1421,7 @@ Object *object_get_internal_root(void); * path is the path within the composition tree starting from the root. * %NULL if the object doesn't have a parent (and thus a canonical path). */ -gchar *object_get_canonical_path_component(Object *obj); +char *object_get_canonical_path_component(Object *obj); /** * object_get_canonical_path: @@ -1429,7 +1429,7 @@ gchar *object_get_canonical_path_component(Object *obj); * Returns: The canonical path for a object. This is the path within the * composition tree starting from the root. */ -gchar *object_get_canonical_path(Object *obj); +char *object_get_canonical_path(Object *obj); /** * object_resolve_path: @@ -1487,7 +1487,7 @@ Object *object_resolve_path_type(const char *path, const char *typename, * * Returns: The resolved object or NULL on path lookup failure. */ -Object *object_resolve_path_component(Object *parent, const gchar *part); +Object *object_resolve_path_component(Object *parent, const char *part); /** * object_property_add_child: diff --git a/memory.c b/memory.c index 601b749906..936c1b23d4 100644 --- a/memory.c +++ b/memory.c @@ -1175,7 +1175,7 @@ static void memory_region_get_container(Object *obj, Visitor *v, Error **errp) { MemoryRegion *mr = MEMORY_REGION(obj); - gchar *path = (gchar *)""; + char *path = (char *)""; if (mr->container) { path = object_get_canonical_path(OBJECT(mr->container)); @@ -2845,7 +2845,7 @@ static void mtree_expand_owner(const char *label, Object *obj) if (dev && dev->id) { qemu_printf(" id=%s", dev->id); } else { - gchar *canonical_path = object_get_canonical_path(obj); + char *canonical_path = object_get_canonical_path(obj); if (canonical_path) { qemu_printf(" path=%s", canonical_path); g_free(canonical_path); diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index 8f60ccc70a..b39e03b744 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -91,7 +91,7 @@ struct Monitor { bool skip_flush; bool use_io_thread; - gchar *mon_cpu_path; + char *mon_cpu_path; QTAILQ_ENTRY(Monitor) entry; /* diff --git a/qom/container.c b/qom/container.c index f6ccaf7ea7..e635e8ee76 100644 --- a/qom/container.c +++ b/qom/container.c @@ -28,7 +28,7 @@ static void container_register_types(void) Object *container_get(Object *root, const char *path) { Object *obj, *child; - gchar **parts; + char **parts; int i; parts = g_strsplit(path, "/", 0); diff --git a/qom/object.c b/qom/object.c index 5511649502..07762cc331 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1357,7 +1357,7 @@ void object_property_set_link(Object *obj, Object *value, const char *name, Error **errp) { if (value) { - gchar *path = object_get_canonical_path(value); + char *path = object_get_canonical_path(value); object_property_set_str(obj, path, name, errp); g_free(path); } else { @@ -1651,14 +1651,15 @@ static void object_get_child_property(Object *obj, Visitor *v, Error **errp) { Object *child = opaque; - gchar *path; + char *path; path = object_get_canonical_path(child); visit_type_str(v, name, &path, errp); g_free(path); } -static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part) +static Object *object_resolve_child_property(Object *parent, void *opaque, + const char *part) { return opaque; } @@ -1679,7 +1680,7 @@ void object_property_add_child(Object *obj, const char *name, Object *child, Error **errp) { Error *local_err = NULL; - gchar *type; + char *type; ObjectProperty *op; if (child->parent != NULL) { @@ -1738,14 +1739,14 @@ static void object_get_link_property(Object *obj, Visitor *v, { LinkProperty *lprop = opaque; Object **targetp = object_link_get_targetp(obj, lprop); - gchar *path; + char *path; if (*targetp) { path = object_get_canonical_path(*targetp); visit_type_str(v, name, &path, errp); g_free(path); } else { - path = (gchar *)""; + path = (char *)""; visit_type_str(v, name, &path, errp); } } @@ -1763,7 +1764,7 @@ static Object *object_resolve_link(Object *obj, const char *name, const char *path, Error **errp) { const char *type; - gchar *target_type; + char *target_type; bool ambiguous = false; Object *target; @@ -1826,7 +1827,8 @@ static void object_set_link_property(Object *obj, Visitor *v, } } -static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part) +static Object *object_resolve_link_property(Object *parent, void *opaque, + const char *part) { LinkProperty *lprop = opaque; @@ -1856,7 +1858,7 @@ static void object_add_link_prop(Object *obj, const char *name, { Error *local_err = NULL; LinkProperty *prop = g_malloc(sizeof(*prop)); - gchar *full_type; + char *full_type; ObjectProperty *op; if (flags & OBJ_PROP_LINK_DIRECT) { @@ -1908,7 +1910,7 @@ object_class_property_add_link(ObjectClass *oc, { Error *local_err = NULL; LinkProperty *prop = g_new0(LinkProperty, 1); - gchar *full_type; + char *full_type; ObjectProperty *op; prop->offset = offset; @@ -1943,7 +1945,7 @@ void object_property_add_const_link(Object *obj, const char *name, NULL, OBJ_PROP_LINK_DIRECT, errp); } -gchar *object_get_canonical_path_component(Object *obj) +char *object_get_canonical_path_component(Object *obj) { ObjectProperty *prop = NULL; GHashTableIter iter; @@ -1968,7 +1970,7 @@ gchar *object_get_canonical_path_component(Object *obj) return NULL; } -gchar *object_get_canonical_path(Object *obj) +char *object_get_canonical_path(Object *obj) { Object *root = object_get_root(); char *newpath, *path = NULL; @@ -1998,7 +2000,7 @@ gchar *object_get_canonical_path(Object *obj) return path; } -Object *object_resolve_path_component(Object *parent, const gchar *part) +Object *object_resolve_path_component(Object *parent, const char *part) { ObjectProperty *prop = object_property_find(parent, part, NULL); if (prop == NULL) { @@ -2013,9 +2015,9 @@ Object *object_resolve_path_component(Object *parent, const gchar *part) } static Object *object_resolve_abs_path(Object *parent, - gchar **parts, - const char *typename, - int index) + char **parts, + const char *typename, + int index) { Object *child; @@ -2036,9 +2038,9 @@ static Object *object_resolve_abs_path(Object *parent, } static Object *object_resolve_partial_path(Object *parent, - gchar **parts, - const char *typename, - bool *ambiguous) + char **parts, + const char *typename, + bool *ambiguous) { Object *obj; GHashTableIter iter; @@ -2076,7 +2078,7 @@ Object *object_resolve_path_type(const char *path, const char *typename, bool *ambiguousp) { Object *obj; - gchar **parts; + char **parts; parts = g_strsplit(path, "/", 0); assert(parts); @@ -2767,7 +2769,7 @@ static void property_set_alias(Object *obj, Visitor *v, const char *name, } static Object *property_resolve_alias(Object *obj, void *opaque, - const gchar *part) + const char *part) { AliasProperty *prop = opaque; @@ -2789,7 +2791,7 @@ void object_property_add_alias(Object *obj, const char *name, AliasProperty *prop; ObjectProperty *op; ObjectProperty *target_prop; - gchar *prop_type; + char *prop_type; Error *local_err = NULL; target_prop = object_property_find(target_obj, target_name, errp); From f73a32a5147ef7ff90f682d6ba3a6ef11ff97d9e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:11 +0200 Subject: [PATCH 0467/2595] qom: Drop object_property_del_child()'s unused parameter @errp Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-4-armbru@redhat.com> --- qom/object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qom/object.c b/qom/object.c index 07762cc331..3d65658059 100644 --- a/qom/object.c +++ b/qom/object.c @@ -614,7 +614,7 @@ static void object_property_del_all(Object *obj) g_hash_table_unref(obj->properties); } -static void object_property_del_child(Object *obj, Object *child, Error **errp) +static void object_property_del_child(Object *obj, Object *child) { ObjectProperty *prop; GHashTableIter iter; @@ -644,7 +644,7 @@ static void object_property_del_child(Object *obj, Object *child, Error **errp) void object_unparent(Object *obj) { if (obj->parent) { - object_property_del_child(obj->parent, obj, NULL); + object_property_del_child(obj->parent, obj); } } From b555f89fcbdc797423f6d6a41b76ef5fa5272235 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:12 +0200 Subject: [PATCH 0468/2595] qom: Simplify object_property_get_enum() Reuse object_property_get_str(). Switches from the string to the qobject visitor under the hood. Signed-off-by: Markus Armbruster Message-Id: <20200505152926.18877-5-armbru@redhat.com> Reviewed-by: Paolo Bonzini --- qom/object.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/qom/object.c b/qom/object.c index 3d65658059..b374af302c 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1521,8 +1521,6 @@ typedef struct EnumProperty { int object_property_get_enum(Object *obj, const char *name, const char *typename, Error **errp) { - Error *err = NULL; - Visitor *v; char *str; int ret; ObjectProperty *prop = object_property_find(obj, name, errp); @@ -1541,15 +1539,10 @@ int object_property_get_enum(Object *obj, const char *name, enumprop = prop->opaque; - v = string_output_visitor_new(false, &str); - object_property_get(obj, v, name, &err); - if (err) { - error_propagate(errp, err); - visit_free(v); + str = object_property_get_str(obj, name, errp); + if (!str) { return 0; } - visit_complete(v, &str); - visit_free(v); ret = qapi_enum_parse(enumprop->lookup, str, -1, errp); g_free(str); From 44a17fe05a363d0f94cd0706fbe64cb4524adf54 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:13 +0200 Subject: [PATCH 0469/2595] qom: Drop convenience method object_property_get_uint16List() qom/object.c provides object_property_get_TYPE() and object_property_set_TYPE() for a number of common types. These are all convenience wrappers around object_property_get_qobject() and object_property_set_qobject(). Except for object_property_get_uint16List(), which is unusual in two ways: * It bypasses object_property_get_qobject(). Fixable; the previous commit did it for object_property_get_enum()) * It stores the value through a parameter. Its contract claims it returns the value, like the other functions do. Also fixable. Fixing is not worthwhile, though: object_property_get_uint16List() has seen exactly one user in six years. Convert the lone user to do its job with the generic object_property_get_qobject(), and drop object_property_get_uint16List(). Signed-off-by: Markus Armbruster Message-Id: <20200505152926.18877-6-armbru@redhat.com> Reviewed-by: Paolo Bonzini [Commit message typo fixed] --- hw/core/machine-qmp-cmds.c | 16 +++++++++++++--- include/qom/object.h | 14 -------------- qom/object.c | 23 ----------------------- 3 files changed, 13 insertions(+), 40 deletions(-) diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index eed5aeb2f7..2c5da8413d 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -11,9 +11,13 @@ #include "cpu.h" #include "hw/boards.h" #include "qapi/error.h" +#include "qapi/qapi-builtin-visit.h" #include "qapi/qapi-commands-machine.h" #include "qapi/qmp/qerror.h" +#include "qapi/qmp/qobject.h" +#include "qapi/qobject-input-visitor.h" #include "qemu/main-loop.h" +#include "qom/qom-qobject.h" #include "sysemu/hostmem.h" #include "sysemu/hw_accel.h" #include "sysemu/numa.h" @@ -303,6 +307,8 @@ static int query_memdev(Object *obj, void *opaque) { MemdevList **list = opaque; MemdevList *m = NULL; + QObject *host_nodes; + Visitor *v; if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) { m = g_malloc0(sizeof(*m)); @@ -325,9 +331,13 @@ static int query_memdev(Object *obj, void *opaque) "policy", "HostMemPolicy", &error_abort); - object_property_get_uint16List(obj, "host-nodes", - &m->value->host_nodes, - &error_abort); + host_nodes = object_property_get_qobject(obj, + "host-nodes", + &error_abort); + v = qobject_input_visitor_new(host_nodes); + visit_type_uint16List(v, NULL, &m->value->host_nodes, &error_abort); + visit_free(v); + qobject_unref(host_nodes); m->next = *list; *list = m; diff --git a/include/qom/object.h b/include/qom/object.h index ccfa82e33d..4df9ecebad 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1320,20 +1320,6 @@ uint64_t object_property_get_uint(Object *obj, const char *name, int object_property_get_enum(Object *obj, const char *name, const char *typename, Error **errp); -/** - * object_property_get_uint16List: - * @obj: the object - * @name: the name of the property - * @list: the returned int list - * @errp: returns an error if this function fails - * - * Returns: the value of the property, converted to integers, or - * undefined if an error occurs (including when the property value is not - * an list of integers). - */ -void object_property_get_uint16List(Object *obj, const char *name, - uint16List **list, Error **errp); - /** * object_property_set: * @obj: the object diff --git a/qom/object.c b/qom/object.c index b374af302c..54a26ed16a 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1550,29 +1550,6 @@ int object_property_get_enum(Object *obj, const char *name, return ret; } -void object_property_get_uint16List(Object *obj, const char *name, - uint16List **list, Error **errp) -{ - Error *err = NULL; - Visitor *v; - char *str; - - v = string_output_visitor_new(false, &str); - object_property_get(obj, v, name, &err); - if (err) { - error_propagate(errp, err); - goto out; - } - visit_complete(v, &str); - visit_free(v); - v = string_input_visitor_new(str); - visit_type_uint16List(v, NULL, list, errp); - - g_free(str); -out: - visit_free(v); -} - void object_property_parse(Object *obj, const char *string, const char *name, Error **errp) { From 702518877220187a858da1a6ba08d53995dc6e2f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:14 +0200 Subject: [PATCH 0470/2595] qom: Make all the object_property_add_FOO() return the property Some object_property_add_FOO() return the newly added property, some don't. Clean that up. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-7-armbru@redhat.com> --- include/qom/object.h | 50 ++++++--- qom/object.c | 250 ++++++++++++++++++++++--------------------- 2 files changed, 164 insertions(+), 136 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 4df9ecebad..0ea5808432 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1491,9 +1491,11 @@ Object *object_resolve_path_component(Object *parent, const char *part); * The value of a child property as a C string will be the child object's * canonical path. It can be retrieved using object_property_get_str(). * The child object itself can be retrieved using object_property_get_link(). + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_child(Object *obj, const char *name, - Object *child, Error **errp); +ObjectProperty *object_property_add_child(Object *obj, const char *name, + Object *child, Error **errp); typedef enum { /* Unref the link pointer when the property is deleted */ @@ -1542,8 +1544,10 @@ void object_property_allow_set_link(const Object *, const char *, * @flags OBJ_PROP_LINK_STRONG bit is set, * the reference count is decremented when the property is deleted or * modified. + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_link(Object *obj, const char *name, +ObjectProperty *object_property_add_link(Object *obj, const char *name, const char *type, Object **targetp, void (*check)(const Object *obj, const char *name, Object *val, Error **errp), @@ -1569,8 +1573,10 @@ ObjectProperty *object_class_property_add_link(ObjectClass *oc, * * Add a string property using getters/setters. This function will add a * property of type 'string'. + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_str(Object *obj, const char *name, +ObjectProperty *object_property_add_str(Object *obj, const char *name, char *(*get)(Object *, Error **), void (*set)(Object *, const char *, Error **), Error **errp); @@ -1592,8 +1598,10 @@ ObjectProperty *object_class_property_add_str(ObjectClass *klass, * * Add a bool property using getters/setters. This function will add a * property of type 'bool'. + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_bool(Object *obj, const char *name, +ObjectProperty *object_property_add_bool(Object *obj, const char *name, bool (*get)(Object *, Error **), void (*set)(Object *, bool, Error **), Error **errp); @@ -1615,8 +1623,10 @@ ObjectProperty *object_class_property_add_bool(ObjectClass *klass, * * Add an enum property using getters/setters. This function will add a * property of type '@typename'. + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_enum(Object *obj, const char *name, +ObjectProperty *object_property_add_enum(Object *obj, const char *name, const char *typename, const QEnumLookup *lookup, int (*get)(Object *, Error **), @@ -1640,8 +1650,10 @@ ObjectProperty *object_class_property_add_enum(ObjectClass *klass, * * Add a read-only struct tm valued property using a getter function. * This function will add a property of type 'struct tm'. + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_tm(Object *obj, const char *name, +ObjectProperty *object_property_add_tm(Object *obj, const char *name, void (*get)(Object *, struct tm *, Error **), Error **errp); @@ -1669,8 +1681,10 @@ typedef enum { * * Add an integer property in memory. This function will add a * property of type 'uint8'. + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_uint8_ptr(Object *obj, const char *name, +ObjectProperty *object_property_add_uint8_ptr(Object *obj, const char *name, const uint8_t *v, ObjectPropertyFlags flags, Error **errp); @@ -1690,8 +1704,10 @@ ObjectProperty *object_class_property_add_uint8_ptr(ObjectClass *klass, * * Add an integer property in memory. This function will add a * property of type 'uint16'. + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_uint16_ptr(Object *obj, const char *name, +ObjectProperty *object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, ObjectPropertyFlags flags, Error **errp); @@ -1712,8 +1728,10 @@ ObjectProperty *object_class_property_add_uint16_ptr(ObjectClass *klass, * * Add an integer property in memory. This function will add a * property of type 'uint32'. + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_uint32_ptr(Object *obj, const char *name, +ObjectProperty *object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, ObjectPropertyFlags flags, Error **errp); @@ -1734,8 +1752,10 @@ ObjectProperty *object_class_property_add_uint32_ptr(ObjectClass *klass, * * Add an integer property in memory. This function will add a * property of type 'uint64'. + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_uint64_ptr(Object *obj, const char *name, +ObjectProperty *object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, ObjectPropertyFlags flags, Error **Errp); @@ -1761,8 +1781,10 @@ ObjectProperty *object_class_property_add_uint64_ptr(ObjectClass *klass, * this property exists. In the case of a child object or an alias on the same * object this will be the case. For aliases to other objects the caller is * responsible for taking a reference. + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_alias(Object *obj, const char *name, +ObjectProperty *object_property_add_alias(Object *obj, const char *name, Object *target_obj, const char *target_name, Error **errp); @@ -1780,8 +1802,10 @@ void object_property_add_alias(Object *obj, const char *name, * this property exists. In the case @target is a child of @obj, * this will be the case. Otherwise, the caller is responsible for * taking a reference. + * + * Returns: The newly added property on success, or %NULL on failure. */ -void object_property_add_const_link(Object *obj, const char *name, +ObjectProperty *object_property_add_const_link(Object *obj, const char *name, Object *target, Error **errp); /** diff --git a/qom/object.c b/qom/object.c index 54a26ed16a..4e5b2ecacd 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1646,33 +1646,30 @@ static void object_finalize_child_property(Object *obj, const char *name, object_unref(child); } -void object_property_add_child(Object *obj, const char *name, - Object *child, Error **errp) +ObjectProperty * +object_property_add_child(Object *obj, const char *name, + Object *child, Error **errp) { - Error *local_err = NULL; - char *type; + g_autofree char *type = NULL; ObjectProperty *op; if (child->parent != NULL) { error_setg(errp, "child object is already parented"); - return; + return NULL; } type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); op = object_property_add(obj, name, type, object_get_child_property, NULL, - object_finalize_child_property, child, &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto out; + object_finalize_child_property, child, errp); + if (!op) { + return NULL; } op->resolve = object_resolve_child_property; object_ref(child); child->parent = obj; - -out: - g_free(type); + return op; } void object_property_allow_set_link(const Object *obj, const char *name, @@ -1819,16 +1816,16 @@ static void object_release_link_property(Object *obj, const char *name, } } -static void object_add_link_prop(Object *obj, const char *name, - const char *type, void *ptr, - void (*check)(const Object *, const char *, - Object *, Error **), - ObjectPropertyLinkFlags flags, - Error **errp) +static ObjectProperty * +object_add_link_prop(Object *obj, const char *name, + const char *type, void *ptr, + void (*check)(const Object *, const char *, + Object *, Error **), + ObjectPropertyLinkFlags flags, + Error **errp) { - Error *local_err = NULL; LinkProperty *prop = g_malloc(sizeof(*prop)); - char *full_type; + g_autofree char *full_type = NULL; ObjectProperty *op; if (flags & OBJ_PROP_LINK_DIRECT) { @@ -1846,27 +1843,26 @@ static void object_add_link_prop(Object *obj, const char *name, check ? object_set_link_property : NULL, object_release_link_property, prop, - &local_err); - if (local_err) { - error_propagate(errp, local_err); + errp); + if (!op) { g_free(prop); - goto out; + return NULL; } op->resolve = object_resolve_link_property; - -out: - g_free(full_type); + return op; } -void object_property_add_link(Object *obj, const char *name, - const char *type, Object **targetp, - void (*check)(const Object *, const char *, - Object *, Error **), - ObjectPropertyLinkFlags flags, - Error **errp) +ObjectProperty * +object_property_add_link(Object *obj, const char *name, + const char *type, Object **targetp, + void (*check)(const Object *, const char *, + Object *, Error **), + ObjectPropertyLinkFlags flags, + Error **errp) { - object_add_link_prop(obj, name, type, targetp, check, flags, errp); + return object_add_link_prop(obj, name, type, targetp, check, flags, + errp); } ObjectProperty * @@ -1908,11 +1904,13 @@ out: return op; } -void object_property_add_const_link(Object *obj, const char *name, - Object *target, Error **errp) +ObjectProperty * +object_property_add_const_link(Object *obj, const char *name, + Object *target, Error **errp) { - object_add_link_prop(obj, name, object_get_typename(target), target, - NULL, OBJ_PROP_LINK_DIRECT, errp); + return object_add_link_prop(obj, name, + object_get_typename(target), target, + NULL, OBJ_PROP_LINK_DIRECT, errp); } char *object_get_canonical_path_component(Object *obj) @@ -2121,26 +2119,27 @@ static void property_release_str(Object *obj, const char *name, g_free(prop); } -void object_property_add_str(Object *obj, const char *name, - char *(*get)(Object *, Error **), - void (*set)(Object *, const char *, Error **), - Error **errp) +ObjectProperty * +object_property_add_str(Object *obj, const char *name, + char *(*get)(Object *, Error **), + void (*set)(Object *, const char *, Error **), + Error **errp) { - Error *local_err = NULL; StringProperty *prop = g_malloc0(sizeof(*prop)); + ObjectProperty *op; prop->get = get; prop->set = set; - object_property_add(obj, name, "string", - get ? property_get_str : NULL, - set ? property_set_str : NULL, - property_release_str, - prop, &local_err); - if (local_err) { - error_propagate(errp, local_err); + op = object_property_add(obj, name, "string", + get ? property_get_str : NULL, + set ? property_set_str : NULL, + property_release_str, + prop, errp); + if (!op) { g_free(prop); } + return op; } ObjectProperty * @@ -2215,26 +2214,27 @@ static void property_release_bool(Object *obj, const char *name, g_free(prop); } -void object_property_add_bool(Object *obj, const char *name, - bool (*get)(Object *, Error **), - void (*set)(Object *, bool, Error **), - Error **errp) +ObjectProperty * +object_property_add_bool(Object *obj, const char *name, + bool (*get)(Object *, Error **), + void (*set)(Object *, bool, Error **), + Error **errp) { - Error *local_err = NULL; BoolProperty *prop = g_malloc0(sizeof(*prop)); + ObjectProperty *op; prop->get = get; prop->set = set; - object_property_add(obj, name, "bool", - get ? property_get_bool : NULL, - set ? property_set_bool : NULL, - property_release_bool, - prop, &local_err); - if (local_err) { - error_propagate(errp, local_err); + op = object_property_add(obj, name, "bool", + get ? property_get_bool : NULL, + set ? property_set_bool : NULL, + property_release_bool, + prop, errp); + if (!op) { g_free(prop); } + return op; } ObjectProperty * @@ -2301,29 +2301,30 @@ static void property_release_enum(Object *obj, const char *name, g_free(prop); } -void object_property_add_enum(Object *obj, const char *name, - const char *typename, - const QEnumLookup *lookup, - int (*get)(Object *, Error **), - void (*set)(Object *, int, Error **), - Error **errp) +ObjectProperty * +object_property_add_enum(Object *obj, const char *name, + const char *typename, + const QEnumLookup *lookup, + int (*get)(Object *, Error **), + void (*set)(Object *, int, Error **), + Error **errp) { - Error *local_err = NULL; EnumProperty *prop = g_malloc(sizeof(*prop)); + ObjectProperty *op; prop->lookup = lookup; prop->get = get; prop->set = set; - object_property_add(obj, name, typename, - get ? property_get_enum : NULL, - set ? property_set_enum : NULL, - property_release_enum, - prop, &local_err); - if (local_err) { - error_propagate(errp, local_err); + op = object_property_add(obj, name, typename, + get ? property_get_enum : NULL, + set ? property_set_enum : NULL, + property_release_enum, + prop, errp); + if (!op) { g_free(prop); } + return op; } ObjectProperty * @@ -2414,23 +2415,24 @@ static void property_release_tm(Object *obj, const char *name, g_free(prop); } -void object_property_add_tm(Object *obj, const char *name, - void (*get)(Object *, struct tm *, Error **), - Error **errp) +ObjectProperty * +object_property_add_tm(Object *obj, const char *name, + void (*get)(Object *, struct tm *, Error **), + Error **errp) { - Error *local_err = NULL; TMProperty *prop = g_malloc0(sizeof(*prop)); + ObjectProperty *op; prop->get = get; - object_property_add(obj, name, "struct tm", - get ? property_get_tm : NULL, NULL, - property_release_tm, - prop, &local_err); - if (local_err) { - error_propagate(errp, local_err); + op = object_property_add(obj, name, "struct tm", + get ? property_get_tm : NULL, NULL, + property_release_tm, + prop, errp); + if (!op) { g_free(prop); } + return op; } ObjectProperty * @@ -2553,10 +2555,11 @@ static void property_set_uint64_ptr(Object *obj, Visitor *v, const char *name, *field = value; } -void object_property_add_uint8_ptr(Object *obj, const char *name, - const uint8_t *v, - ObjectPropertyFlags flags, - Error **errp) +ObjectProperty * +object_property_add_uint8_ptr(Object *obj, const char *name, + const uint8_t *v, + ObjectPropertyFlags flags, + Error **errp) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2569,8 +2572,8 @@ void object_property_add_uint8_ptr(Object *obj, const char *name, setter = property_set_uint8_ptr; } - object_property_add(obj, name, "uint8", - getter, setter, NULL, (void *)v, errp); + return object_property_add(obj, name, "uint8", + getter, setter, NULL, (void *)v, errp); } ObjectProperty * @@ -2594,10 +2597,11 @@ object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, getter, setter, NULL, (void *)v, errp); } -void object_property_add_uint16_ptr(Object *obj, const char *name, - const uint16_t *v, - ObjectPropertyFlags flags, - Error **errp) +ObjectProperty * +object_property_add_uint16_ptr(Object *obj, const char *name, + const uint16_t *v, + ObjectPropertyFlags flags, + Error **errp) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2610,8 +2614,8 @@ void object_property_add_uint16_ptr(Object *obj, const char *name, setter = property_set_uint16_ptr; } - object_property_add(obj, name, "uint16", - getter, setter, NULL, (void *)v, errp); + return object_property_add(obj, name, "uint16", + getter, setter, NULL, (void *)v, errp); } ObjectProperty * @@ -2635,10 +2639,11 @@ object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, getter, setter, NULL, (void *)v, errp); } -void object_property_add_uint32_ptr(Object *obj, const char *name, - const uint32_t *v, - ObjectPropertyFlags flags, - Error **errp) +ObjectProperty * +object_property_add_uint32_ptr(Object *obj, const char *name, + const uint32_t *v, + ObjectPropertyFlags flags, + Error **errp) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2651,8 +2656,8 @@ void object_property_add_uint32_ptr(Object *obj, const char *name, setter = property_set_uint32_ptr; } - object_property_add(obj, name, "uint32", - getter, setter, NULL, (void *)v, errp); + return object_property_add(obj, name, "uint32", + getter, setter, NULL, (void *)v, errp); } ObjectProperty * @@ -2676,10 +2681,11 @@ object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, getter, setter, NULL, (void *)v, errp); } -void object_property_add_uint64_ptr(Object *obj, const char *name, - const uint64_t *v, - ObjectPropertyFlags flags, - Error **errp) +ObjectProperty * +object_property_add_uint64_ptr(Object *obj, const char *name, + const uint64_t *v, + ObjectPropertyFlags flags, + Error **errp) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2692,8 +2698,8 @@ void object_property_add_uint64_ptr(Object *obj, const char *name, setter = property_set_uint64_ptr; } - object_property_add(obj, name, "uint64", - getter, setter, NULL, (void *)v, errp); + return object_property_add(obj, name, "uint64", + getter, setter, NULL, (void *)v, errp); } ObjectProperty * @@ -2754,19 +2760,19 @@ static void property_release_alias(Object *obj, const char *name, void *opaque) g_free(prop); } -void object_property_add_alias(Object *obj, const char *name, - Object *target_obj, const char *target_name, - Error **errp) +ObjectProperty * +object_property_add_alias(Object *obj, const char *name, + Object *target_obj, const char *target_name, + Error **errp) { AliasProperty *prop; ObjectProperty *op; ObjectProperty *target_prop; - char *prop_type; - Error *local_err = NULL; + g_autofree char *prop_type = NULL; target_prop = object_property_find(target_obj, target_name, errp); if (!target_prop) { - return; + return NULL; } if (object_property_is_child(target_prop)) { @@ -2784,12 +2790,12 @@ void object_property_add_alias(Object *obj, const char *name, property_get_alias, property_set_alias, property_release_alias, - prop, &local_err); - if (local_err) { - error_propagate(errp, local_err); + prop, errp); + if (!op) { g_free(prop); - goto out; + return NULL; } + op->resolve = property_resolve_alias; if (target_prop->defval) { op->defval = qobject_ref(target_prop->defval); @@ -2798,9 +2804,7 @@ void object_property_add_alias(Object *obj, const char *name, object_property_set_description(obj, op->name, target_prop->description, &error_abort); - -out: - g_free(prop_type); + return op; } void object_property_set_description(Object *obj, const char *name, From 7eecec7d1224890b0d04479dd4736e1eefaa72dc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:15 +0200 Subject: [PATCH 0471/2595] qom: Drop object_property_set_description() parameter @errp object_property_set_description() and object_class_property_set_description() fail only when property @name is not found. There are 85 calls of object_property_set_description() and object_class_property_set_description(). None of them can fail: * 84 immediately follow the creation of the property. * The one in spapr_rng_instance_init() refers to a property created in spapr_rng_class_init(), from spapr_rng_properties[]. Every one of them still gets to decide what to pass for @errp. 51 calls pass &error_abort, 32 calls pass NULL, one receives the error and propagates it to &error_abort, and one propagates it to &error_fatal. I'm actually surprised none of them violates the Error API. What are we gaining by letting callers handle the "property not found" error? Use when the property is not known to exist is simpler: you don't have to guard the call with a check. We haven't found such a use in 5+ years. Until we do, let's make life a bit simpler and drop the @errp parameter. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-8-armbru@redhat.com> [One semantic rebase conflict resolved] --- accel/kvm/kvm-all.c | 4 ++-- accel/tcg/tcg-all.c | 2 +- backends/hostmem-memfd.c | 9 +++------ backends/hostmem.c | 16 +++++++-------- hw/arm/aspeed.c | 2 +- hw/arm/vexpress.c | 6 ++---- hw/arm/virt.c | 23 ++++++++------------- hw/arm/xlnx-zcu102.c | 6 ++---- hw/core/machine.c | 41 ++++++++++++++++++-------------------- hw/core/qdev.c | 6 ++---- hw/i386/microvm.c | 14 ++++++------- hw/i386/pc.c | 2 +- hw/i386/x86.c | 6 +++--- hw/ppc/mac_newworld.c | 3 +-- hw/ppc/pnv.c | 3 +-- hw/ppc/spapr.c | 21 ++++++++----------- hw/ppc/spapr_caps.c | 6 +----- hw/ppc/spapr_rng.c | 3 +-- hw/riscv/sifive_u.c | 5 ++--- hw/s390x/css-bridge.c | 3 +-- hw/s390x/s390-virtio-ccw.c | 9 +++------ hw/sparc/sun4m.c | 3 +-- hw/xen/xen-common.c | 2 +- include/qom/object.h | 6 ++---- qom/object.c | 19 ++++-------------- target/arm/cpu64.c | 3 +-- target/arm/kvm.c | 2 +- target/i386/sev.c | 6 +++--- target/ppc/compat.c | 2 +- target/s390x/cpu_models.c | 4 ++-- 30 files changed, 92 insertions(+), 145 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 36be11795d..9b712aac77 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3113,13 +3113,13 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data) NULL, kvm_set_kernel_irqchip, NULL, NULL, &error_abort); object_class_property_set_description(oc, "kernel-irqchip", - "Configure KVM in-kernel irqchip", &error_abort); + "Configure KVM in-kernel irqchip"); object_class_property_add(oc, "kvm-shadow-mem", "int", kvm_get_kvm_shadow_mem, kvm_set_kvm_shadow_mem, NULL, NULL, &error_abort); object_class_property_set_description(oc, "kvm-shadow-mem", - "KVM shadow MMU size", &error_abort); + "KVM shadow MMU size"); } static const TypeInfo kvm_accel_type = { diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index acfdcfdf59..3398a56ef9 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -210,7 +210,7 @@ static void tcg_accel_class_init(ObjectClass *oc, void *data) tcg_get_tb_size, tcg_set_tb_size, NULL, NULL, &error_abort); object_class_property_set_description(oc, "tb-size", - "TCG translation block cache size", &error_abort); + "TCG translation block cache size"); } diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c index 74ba9879c4..5991f31459 100644 --- a/backends/hostmem-memfd.c +++ b/backends/hostmem-memfd.c @@ -144,23 +144,20 @@ memfd_backend_class_init(ObjectClass *oc, void *data) memfd_backend_set_hugetlb, &error_abort); object_class_property_set_description(oc, "hugetlb", - "Use huge pages", - &error_abort); + "Use huge pages"); object_class_property_add(oc, "hugetlbsize", "int", memfd_backend_get_hugetlbsize, memfd_backend_set_hugetlbsize, NULL, NULL, &error_abort); object_class_property_set_description(oc, "hugetlbsize", - "Huge pages size (ex: 2M, 1G)", - &error_abort); + "Huge pages size (ex: 2M, 1G)"); } object_class_property_add_bool(oc, "seal", memfd_backend_get_seal, memfd_backend_set_seal, &error_abort); object_class_property_set_description(oc, "seal", - "Seal growing & shrinking", - &error_abort); + "Seal growing & shrinking"); } static const TypeInfo memfd_backend_info = { diff --git a/backends/hostmem.c b/backends/hostmem.c index 327f9eebc3..946d176435 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -465,46 +465,46 @@ host_memory_backend_class_init(ObjectClass *oc, void *data) host_memory_backend_get_merge, host_memory_backend_set_merge, &error_abort); object_class_property_set_description(oc, "merge", - "Mark memory as mergeable", &error_abort); + "Mark memory as mergeable"); object_class_property_add_bool(oc, "dump", host_memory_backend_get_dump, host_memory_backend_set_dump, &error_abort); object_class_property_set_description(oc, "dump", - "Set to 'off' to exclude from core dump", &error_abort); + "Set to 'off' to exclude from core dump"); object_class_property_add_bool(oc, "prealloc", host_memory_backend_get_prealloc, host_memory_backend_set_prealloc, &error_abort); object_class_property_set_description(oc, "prealloc", - "Preallocate memory", &error_abort); + "Preallocate memory"); object_class_property_add(oc, "prealloc-threads", "int", host_memory_backend_get_prealloc_threads, host_memory_backend_set_prealloc_threads, NULL, NULL, &error_abort); object_class_property_set_description(oc, "prealloc-threads", - "Number of CPU threads to use for prealloc", &error_abort); + "Number of CPU threads to use for prealloc"); object_class_property_add(oc, "size", "int", host_memory_backend_get_size, host_memory_backend_set_size, NULL, NULL, &error_abort); object_class_property_set_description(oc, "size", - "Size of the memory region (ex: 500M)", &error_abort); + "Size of the memory region (ex: 500M)"); object_class_property_add(oc, "host-nodes", "int", host_memory_backend_get_host_nodes, host_memory_backend_set_host_nodes, NULL, NULL, &error_abort); object_class_property_set_description(oc, "host-nodes", - "Binds memory to the list of NUMA host nodes", &error_abort); + "Binds memory to the list of NUMA host nodes"); object_class_property_add_enum(oc, "policy", "HostMemPolicy", &HostMemPolicy_lookup, host_memory_backend_get_policy, host_memory_backend_set_policy, &error_abort); object_class_property_set_description(oc, "policy", - "Set the NUMA policy", &error_abort); + "Set the NUMA policy"); object_class_property_add_bool(oc, "share", host_memory_backend_get_share, host_memory_backend_set_share, &error_abort); object_class_property_set_description(oc, "share", - "Mark the memory as private to QEMU or shared", &error_abort); + "Mark the memory as private to QEMU or shared"); object_class_property_add_bool(oc, "x-use-canonical-path-for-ramblock-id", host_memory_backend_get_use_canonical_path, host_memory_backend_set_use_canonical_path, &error_abort); diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 4d57d1e436..231527c6c8 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -546,7 +546,7 @@ static void aspeed_machine_class_props_init(ObjectClass *oc) aspeed_get_mmio_exec, aspeed_set_mmio_exec, &error_abort); object_class_property_set_description(oc, "execute-in-place", - "boot directly from CE0 flash device", &error_abort); + "boot directly from CE0 flash device"); } static void aspeed_machine_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index ed683eeea5..5372ab6c9b 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -752,8 +752,7 @@ static void vexpress_instance_init(Object *obj) vexpress_set_secure, NULL); object_property_set_description(obj, "secure", "Set on/off to enable/disable the ARM " - "Security Extensions (TrustZone)", - NULL); + "Security Extensions (TrustZone)"); } static void vexpress_a15_instance_init(Object *obj) @@ -770,8 +769,7 @@ static void vexpress_a15_instance_init(Object *obj) object_property_set_description(obj, "virtualization", "Set on/off to enable/disable the ARM " "Virtualization Extensions " - "(defaults to same as 'secure')", - NULL); + "(defaults to same as 'secure')"); } static void vexpress_a9_instance_init(Object *obj) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 9e76fa7b01..de66def51e 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2272,7 +2272,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) virt_get_acpi, virt_set_acpi, NULL, NULL, &error_abort); object_class_property_set_description(oc, "acpi", - "Enable ACPI", &error_abort); + "Enable ACPI"); } static void virt_instance_init(Object *obj) @@ -2289,8 +2289,7 @@ static void virt_instance_init(Object *obj) virt_set_secure, NULL); object_property_set_description(obj, "secure", "Set on/off to enable/disable the ARM " - "Security Extensions (TrustZone)", - NULL); + "Security Extensions (TrustZone)"); /* EL2 is also disabled by default, for similar reasons */ vms->virt = false; @@ -2299,8 +2298,7 @@ static void virt_instance_init(Object *obj) object_property_set_description(obj, "virtualization", "Set on/off to enable/disable emulating a " "guest CPU which implements the ARM " - "Virtualization Extensions", - NULL); + "Virtualization Extensions"); /* High memory is enabled by default */ vms->highmem = true; @@ -2308,15 +2306,13 @@ static void virt_instance_init(Object *obj) virt_set_highmem, NULL); object_property_set_description(obj, "highmem", "Set on/off to enable/disable using " - "physical address space above 32 bits", - NULL); + "physical address space above 32 bits"); vms->gic_version = VIRT_GIC_VERSION_NOSEL; object_property_add_str(obj, "gic-version", virt_get_gic_version, virt_set_gic_version, NULL); object_property_set_description(obj, "gic-version", "Set GIC version. " - "Valid values are 2, 3, host and max", - NULL); + "Valid values are 2, 3, host and max"); vms->highmem_ecam = !vmc->no_highmem_ecam; @@ -2329,8 +2325,7 @@ static void virt_instance_init(Object *obj) virt_set_its, NULL); object_property_set_description(obj, "its", "Set on/off to enable/disable " - "ITS instantiation", - NULL); + "ITS instantiation"); } /* Default disallows iommu instantiation */ @@ -2338,8 +2333,7 @@ static void virt_instance_init(Object *obj) object_property_add_str(obj, "iommu", virt_get_iommu, virt_set_iommu, NULL); object_property_set_description(obj, "iommu", "Set the IOMMU type. " - "Valid values are none and smmuv3", - NULL); + "Valid values are none and smmuv3"); /* Default disallows RAS instantiation */ vms->ras = false; @@ -2347,8 +2341,7 @@ static void virt_instance_init(Object *obj) virt_set_ras, NULL); object_property_set_description(obj, "ras", "Set on/off to enable/disable reporting host memory errors " - "to a KVM guest using ACPI and guest external abort exceptions", - NULL); + "to a KVM guest using ACPI and guest external abort exceptions"); vms->irqmap = a15irqmap; diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index a798e228b7..808fdae804 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -212,8 +212,7 @@ static void xlnx_zcu102_machine_instance_init(Object *obj) zcu102_set_secure, NULL); object_property_set_description(obj, "secure", "Set on/off to enable/disable the ARM " - "Security Extensions (TrustZone)", - NULL); + "Security Extensions (TrustZone)"); /* Default to virt (EL2) being disabled */ s->virt = false; @@ -222,8 +221,7 @@ static void xlnx_zcu102_machine_instance_init(Object *obj) object_property_set_description(obj, "virtualization", "Set on/off to enable/disable emulating a " "guest CPU which implements the ARM " - "Virtualization Extensions", - NULL); + "Virtualization Extensions"); } static void xlnx_zcu102_machine_class_init(ObjectClass *oc, void *data) diff --git a/hw/core/machine.c b/hw/core/machine.c index 7a50dd518f..0cd2033b1f 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -789,83 +789,82 @@ static void machine_class_init(ObjectClass *oc, void *data) object_class_property_add_str(oc, "kernel", machine_get_kernel, machine_set_kernel, &error_abort); object_class_property_set_description(oc, "kernel", - "Linux kernel image file", &error_abort); + "Linux kernel image file"); object_class_property_add_str(oc, "initrd", machine_get_initrd, machine_set_initrd, &error_abort); object_class_property_set_description(oc, "initrd", - "Linux initial ramdisk file", &error_abort); + "Linux initial ramdisk file"); object_class_property_add_str(oc, "append", machine_get_append, machine_set_append, &error_abort); object_class_property_set_description(oc, "append", - "Linux kernel command line", &error_abort); + "Linux kernel command line"); object_class_property_add_str(oc, "dtb", machine_get_dtb, machine_set_dtb, &error_abort); object_class_property_set_description(oc, "dtb", - "Linux kernel device tree file", &error_abort); + "Linux kernel device tree file"); object_class_property_add_str(oc, "dumpdtb", machine_get_dumpdtb, machine_set_dumpdtb, &error_abort); object_class_property_set_description(oc, "dumpdtb", - "Dump current dtb to a file and quit", &error_abort); + "Dump current dtb to a file and quit"); object_class_property_add(oc, "phandle-start", "int", machine_get_phandle_start, machine_set_phandle_start, NULL, NULL, &error_abort); object_class_property_set_description(oc, "phandle-start", - "The first phandle ID we may generate dynamically", &error_abort); + "The first phandle ID we may generate dynamically"); object_class_property_add_str(oc, "dt-compatible", machine_get_dt_compatible, machine_set_dt_compatible, &error_abort); object_class_property_set_description(oc, "dt-compatible", - "Overrides the \"compatible\" property of the dt root node", - &error_abort); + "Overrides the \"compatible\" property of the dt root node"); object_class_property_add_bool(oc, "dump-guest-core", machine_get_dump_guest_core, machine_set_dump_guest_core, &error_abort); object_class_property_set_description(oc, "dump-guest-core", - "Include guest memory in a core dump", &error_abort); + "Include guest memory in a core dump"); object_class_property_add_bool(oc, "mem-merge", machine_get_mem_merge, machine_set_mem_merge, &error_abort); object_class_property_set_description(oc, "mem-merge", - "Enable/disable memory merge support", &error_abort); + "Enable/disable memory merge support"); object_class_property_add_bool(oc, "usb", machine_get_usb, machine_set_usb, &error_abort); object_class_property_set_description(oc, "usb", - "Set on/off to enable/disable usb", &error_abort); + "Set on/off to enable/disable usb"); object_class_property_add_bool(oc, "graphics", machine_get_graphics, machine_set_graphics, &error_abort); object_class_property_set_description(oc, "graphics", - "Set on/off to enable/disable graphics emulation", &error_abort); + "Set on/off to enable/disable graphics emulation"); object_class_property_add_str(oc, "firmware", machine_get_firmware, machine_set_firmware, &error_abort); object_class_property_set_description(oc, "firmware", - "Firmware image", &error_abort); + "Firmware image"); object_class_property_add_bool(oc, "suppress-vmdesc", machine_get_suppress_vmdesc, machine_set_suppress_vmdesc, &error_abort); object_class_property_set_description(oc, "suppress-vmdesc", - "Set on to disable self-describing migration", &error_abort); + "Set on to disable self-describing migration"); object_class_property_add_bool(oc, "enforce-config-section", machine_get_enforce_config_section, machine_set_enforce_config_section, &error_abort); object_class_property_set_description(oc, "enforce-config-section", - "Set on to enforce configuration section migration", &error_abort); + "Set on to enforce configuration section migration"); object_class_property_add_str(oc, "memory-encryption", machine_get_memory_encryption, machine_set_memory_encryption, &error_abort); object_class_property_set_description(oc, "memory-encryption", - "Set memory encryption object to use", &error_abort); + "Set memory encryption object to use"); } static void machine_class_base_init(ObjectClass *oc, void *data) @@ -898,7 +897,7 @@ static void machine_initfn(Object *obj) &error_abort); object_property_set_description(obj, "nvdimm", "Set on/off to enable/disable " - "NVDIMM instantiation", NULL); + "NVDIMM instantiation"); object_property_add_str(obj, "nvdimm-persistence", machine_get_nvdimm_persistence, @@ -906,8 +905,7 @@ static void machine_initfn(Object *obj) &error_abort); object_property_set_description(obj, "nvdimm-persistence", "Set NVDIMM persistence" - "Valid values are cpu, mem-ctrl", - NULL); + "Valid values are cpu, mem-ctrl"); } if (mc->cpu_index_to_instance_props && mc->get_default_cpu_node_id) { @@ -918,7 +916,7 @@ static void machine_initfn(Object *obj) object_property_set_description(obj, "hmat", "Set on/off to enable/disable " "ACPI Heterogeneous Memory Attribute " - "Table (HMAT)", NULL); + "Table (HMAT)"); } object_property_add_str(obj, "memory-backend", @@ -926,8 +924,7 @@ static void machine_initfn(Object *obj) &error_abort); object_property_set_description(obj, "memory-backend", "Set RAM backend" - "Valid value is ID of hostmem based backend", - &error_abort); + "Valid value is ID of hostmem based backend"); /* Register notifier when init is done for sysbus sanity checks */ ms->sysbus_notifier.notify = machine_init_notify; diff --git a/hw/core/qdev.c b/hw/core/qdev.c index dd77a56067..ea7118ab0e 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -775,8 +775,7 @@ void qdev_property_add_static(DeviceState *dev, Property *prop) prop, &error_abort); object_property_set_description(obj, prop->name, - prop->info->description, - &error_abort); + prop->info->description); if (prop->set_default) { prop->info->set_default_value(op, prop); @@ -805,8 +804,7 @@ static void qdev_class_add_property(DeviceClass *klass, Property *prop) } } object_class_property_set_description(oc, prop->name, - prop->info->description, - &error_abort); + prop->info->description); } /* @qdev_alias_all_properties - Add alias properties to the source object for diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 38d8e51703..76aaa7a8d8 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -512,36 +512,35 @@ static void microvm_class_init(ObjectClass *oc, void *data) microvm_machine_set_pic, NULL, NULL, &error_abort); object_class_property_set_description(oc, MICROVM_MACHINE_PIC, - "Enable i8259 PIC", &error_abort); + "Enable i8259 PIC"); object_class_property_add(oc, MICROVM_MACHINE_PIT, "OnOffAuto", microvm_machine_get_pit, microvm_machine_set_pit, NULL, NULL, &error_abort); object_class_property_set_description(oc, MICROVM_MACHINE_PIT, - "Enable i8254 PIT", &error_abort); + "Enable i8254 PIT"); object_class_property_add(oc, MICROVM_MACHINE_RTC, "OnOffAuto", microvm_machine_get_rtc, microvm_machine_set_rtc, NULL, NULL, &error_abort); object_class_property_set_description(oc, MICROVM_MACHINE_RTC, - "Enable MC146818 RTC", &error_abort); + "Enable MC146818 RTC"); object_class_property_add_bool(oc, MICROVM_MACHINE_ISA_SERIAL, microvm_machine_get_isa_serial, microvm_machine_set_isa_serial, &error_abort); object_class_property_set_description(oc, MICROVM_MACHINE_ISA_SERIAL, - "Set off to disable the instantiation an ISA serial port", - &error_abort); + "Set off to disable the instantiation an ISA serial port"); object_class_property_add_bool(oc, MICROVM_MACHINE_OPTION_ROMS, microvm_machine_get_option_roms, microvm_machine_set_option_roms, &error_abort); object_class_property_set_description(oc, MICROVM_MACHINE_OPTION_ROMS, - "Set off to disable loading option ROMs", &error_abort); + "Set off to disable loading option ROMs"); object_class_property_add_bool(oc, MICROVM_MACHINE_AUTO_KERNEL_CMDLINE, microvm_machine_get_auto_kernel_cmdline, @@ -549,8 +548,7 @@ static void microvm_class_init(ObjectClass *oc, void *data) &error_abort); object_class_property_set_description(oc, MICROVM_MACHINE_AUTO_KERNEL_CMDLINE, - "Set off to disable adding virtio-mmio devices to the kernel cmdline", - &error_abort); + "Set off to disable adding virtio-mmio devices to the kernel cmdline"); } static const TypeInfo microvm_machine_info = { diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 97e345faea..21d4a8ec3a 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1971,7 +1971,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) pc_machine_get_vmport, pc_machine_set_vmport, NULL, NULL, &error_abort); object_class_property_set_description(oc, PC_MACHINE_VMPORT, - "Enable vmport (pc & q35)", &error_abort); + "Enable vmport (pc & q35)"); object_class_property_add_bool(oc, PC_MACHINE_SMBUS, pc_machine_get_smbus, pc_machine_set_smbus, &error_abort); diff --git a/hw/i386/x86.c b/hw/i386/x86.c index b82770024c..e2bf601273 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -984,19 +984,19 @@ static void x86_machine_class_init(ObjectClass *oc, void *data) x86_machine_get_max_ram_below_4g, x86_machine_set_max_ram_below_4g, NULL, NULL, &error_abort); object_class_property_set_description(oc, X86_MACHINE_MAX_RAM_BELOW_4G, - "Maximum ram below the 4G boundary (32bit boundary)", &error_abort); + "Maximum ram below the 4G boundary (32bit boundary)"); object_class_property_add(oc, X86_MACHINE_SMM, "OnOffAuto", x86_machine_get_smm, x86_machine_set_smm, NULL, NULL, &error_abort); object_class_property_set_description(oc, X86_MACHINE_SMM, - "Enable SMM", &error_abort); + "Enable SMM"); object_class_property_add(oc, X86_MACHINE_ACPI, "OnOffAuto", x86_machine_get_acpi, x86_machine_set_acpi, NULL, NULL, &error_abort); object_class_property_set_description(oc, X86_MACHINE_ACPI, - "Enable ACPI", &error_abort); + "Enable ACPI"); } static const TypeInfo x86_machine_info = { diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 428cf63578..55d1419442 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -631,8 +631,7 @@ static void core99_instance_init(Object *obj) core99_set_via_config, NULL); object_property_set_description(obj, "via", "Set VIA configuration. " - "Valid values are cuda, pmu and pmu-adb", - NULL); + "Valid values are cuda, pmu and pmu-adb"); return; } diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index a3b7a8d0ff..4666dbbe7a 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -2030,8 +2030,7 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data) pnv_machine_get_hb, pnv_machine_set_hb, &error_abort); object_class_property_set_description(oc, "hb-mode", - "Use a hostboot like boot loader", - NULL); + "Use a hostboot like boot loader"); } #define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \ diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c18eab0a23..aa281e727a 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3307,8 +3307,7 @@ static void spapr_instance_init(Object *obj) object_property_add_str(obj, "kvm-type", spapr_get_kvm_type, spapr_set_kvm_type, NULL); object_property_set_description(obj, "kvm-type", - "Specifies the KVM virtualization mode (HV, PR)", - NULL); + "Specifies the KVM virtualization mode (HV, PR)"); object_property_add_bool(obj, "modern-hotplug-events", spapr_get_modern_hotplug_events, spapr_set_modern_hotplug_events, @@ -3316,8 +3315,7 @@ static void spapr_instance_init(Object *obj) object_property_set_description(obj, "modern-hotplug-events", "Use dedicated hotplug event mechanism in" " place of standard EPOW events when possible" - " (required for memory hot-unplug support)", - NULL); + " (required for memory hot-unplug support)"); ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr, "Maximum permitted CPU compatibility mode", &error_fatal); @@ -3325,14 +3323,13 @@ static void spapr_instance_init(Object *obj) object_property_add_str(obj, "resize-hpt", spapr_get_resize_hpt, spapr_set_resize_hpt, NULL); object_property_set_description(obj, "resize-hpt", - "Resizing of the Hash Page Table (enabled, disabled, required)", - NULL); + "Resizing of the Hash Page Table (enabled, disabled, required)"); object_property_add_uint32_ptr(obj, "vsmt", &spapr->vsmt, OBJ_PROP_FLAG_READWRITE, &error_abort); object_property_set_description(obj, "vsmt", "Virtual SMT: KVM behaves as if this were" - " the host's SMT mode", &error_abort); + " the host's SMT mode"); object_property_add_bool(obj, "vfio-no-msix-emulation", spapr_get_msix_emulation, NULL, NULL); @@ -3342,27 +3339,25 @@ static void spapr_instance_init(Object *obj) &error_abort); object_property_set_description(obj, "kernel-addr", stringify(KERNEL_LOAD_ADDR) - " for -kernel is the default", - NULL); + " for -kernel is the default"); spapr->kernel_addr = KERNEL_LOAD_ADDR; /* The machine class defines the default interrupt controller mode */ spapr->irq = smc->irq; object_property_add_str(obj, "ic-mode", spapr_get_ic_mode, spapr_set_ic_mode, NULL); object_property_set_description(obj, "ic-mode", - "Specifies the interrupt controller mode (xics, xive, dual)", - NULL); + "Specifies the interrupt controller mode (xics, xive, dual)"); object_property_add_str(obj, "host-model", spapr_get_host_model, spapr_set_host_model, &error_abort); object_property_set_description(obj, "host-model", - "Host model to advertise in guest device tree", &error_abort); + "Host model to advertise in guest device tree"); object_property_add_str(obj, "host-serial", spapr_get_host_serial, spapr_set_host_serial, &error_abort); object_property_set_description(obj, "host-serial", - "Host serial number to advertise in guest device tree", &error_abort); + "Host serial number to advertise in guest device tree"); } static void spapr_machine_finalizefn(Object *obj) diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index eb54f94227..0870961fc9 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -845,12 +845,8 @@ void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp) } desc = g_strdup_printf("%s", cap->description); - object_class_property_set_description(klass, name, desc, &local_err); + object_class_property_set_description(klass, name, desc); g_free(name); g_free(desc); - if (local_err) { - error_propagate(errp, local_err); - return; - } } } diff --git a/hw/ppc/spapr_rng.c b/hw/ppc/spapr_rng.c index e8e8d65ec0..85bf64d68e 100644 --- a/hw/ppc/spapr_rng.c +++ b/hw/ppc/spapr_rng.c @@ -103,8 +103,7 @@ static void spapr_rng_instance_init(Object *obj) } object_property_set_description(obj, "rng", - "ID of the random number generator backend", - NULL); + "ID of the random number generator backend"); } static void spapr_rng_realize(DeviceState *dev, Error **errp) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index bed10fcfa8..da48c958e2 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -445,13 +445,12 @@ static void sifive_u_machine_instance_init(Object *obj) sifive_u_machine_set_start_in_flash, NULL); object_property_set_description(obj, "start-in-flash", "Set on to tell QEMU's ROM to jump to " - "flash. Otherwise QEMU will jump to DRAM", - NULL); + "flash. Otherwise QEMU will jump to DRAM"); s->serial = OTP_SERIAL; object_property_add(obj, "serial", "uint32", sifive_u_machine_get_serial, sifive_u_machine_set_serial, NULL, &s->serial, NULL); - object_property_set_description(obj, "serial", "Board serial number", NULL); + object_property_set_description(obj, "serial", "Board serial number"); } static void sifive_u_machine_class_init(ObjectClass *oc, void *data) diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index a306a78e6c..c9ce06b043 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -144,8 +144,7 @@ static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) prop_get_true, NULL, NULL); object_class_property_set_description(klass, "cssid-unrestricted", "A css device can use any cssid, regardless whether virtual" - " or not (read only, always true)", - NULL); + " or not (read only, always true)"); } static const TypeInfo virtual_css_bridge_info = { diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index f660070d22..2f94061ff6 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -731,24 +731,21 @@ static inline void s390_machine_initfn(Object *obj) machine_get_aes_key_wrap, machine_set_aes_key_wrap, NULL); object_property_set_description(obj, "aes-key-wrap", - "enable/disable AES key wrapping using the CPACF wrapping key", - NULL); + "enable/disable AES key wrapping using the CPACF wrapping key"); object_property_set_bool(obj, true, "aes-key-wrap", NULL); object_property_add_bool(obj, "dea-key-wrap", machine_get_dea_key_wrap, machine_set_dea_key_wrap, NULL); object_property_set_description(obj, "dea-key-wrap", - "enable/disable DEA key wrapping using the CPACF wrapping key", - NULL); + "enable/disable DEA key wrapping using the CPACF wrapping key"); object_property_set_bool(obj, true, "dea-key-wrap", NULL); object_property_add_str(obj, "loadparm", machine_get_loadparm, machine_set_loadparm, NULL); object_property_set_description(obj, "loadparm", "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted" " to upper case) to pass to machine loader, boot manager," - " and guest kernel", - NULL); + " and guest kernel"); } static const TypeInfo ccw_machine_info = { diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 36ee1a0a3d..7472d24e2c 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -797,8 +797,7 @@ static void ram_initfn(Object *obj) object_property_allow_set_link, OBJ_PROP_LINK_STRONG, &error_abort); object_property_set_description(obj, "memdev", "Set RAM backend" - "Valid value is ID of a hostmem backend", - &error_abort); + "Valid value is ID of a hostmem backend"); } static void ram_class_init(ObjectClass *klass, void *data) diff --git a/hw/xen/xen-common.c b/hw/xen/xen-common.c index a15070f7f6..adaab81ce0 100644 --- a/hw/xen/xen-common.c +++ b/hw/xen/xen-common.c @@ -201,7 +201,7 @@ static void xen_accel_class_init(ObjectClass *oc, void *data) xen_get_igd_gfx_passthru, xen_set_igd_gfx_passthru, &error_abort); object_class_property_set_description(oc, "igd-passthru", - "Set on/off to enable/disable igd passthrou", &error_abort); + "Set on/off to enable/disable igd passthrou"); } #define TYPE_XEN_ACCEL ACCEL_CLASS_NAME("xen") diff --git a/include/qom/object.h b/include/qom/object.h index 0ea5808432..1f0386a231 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1813,16 +1813,14 @@ ObjectProperty *object_property_add_const_link(Object *obj, const char *name, * @obj: the object owning the property * @name: the name of the property * @description: the description of the property on the object - * @errp: if an error occurs, a pointer to an area to store the error * * Set an object property's description. * */ void object_property_set_description(Object *obj, const char *name, - const char *description, Error **errp); + const char *description); void object_class_property_set_description(ObjectClass *klass, const char *name, - const char *description, - Error **errp); + const char *description); /** * object_child_foreach: diff --git a/qom/object.c b/qom/object.c index 4e5b2ecacd..58a6ec9b1b 100644 --- a/qom/object.c +++ b/qom/object.c @@ -2802,38 +2802,27 @@ object_property_add_alias(Object *obj, const char *name, } object_property_set_description(obj, op->name, - target_prop->description, - &error_abort); + target_prop->description); return op; } void object_property_set_description(Object *obj, const char *name, - const char *description, Error **errp) + const char *description) { ObjectProperty *op; - op = object_property_find(obj, name, errp); - if (!op) { - return; - } - + op = object_property_find(obj, name, &error_abort); g_free(op->description); op->description = g_strdup(description); } void object_class_property_set_description(ObjectClass *klass, const char *name, - const char *description, - Error **errp) + const char *description) { ObjectProperty *op; op = g_hash_table_lookup(klass->properties, name); - if (!op) { - error_setg(errp, "Property '.%s' not found", name); - return; - } - g_free(op->description); op->description = g_strdup(description); } diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index f5c49ee32d..18a0af88e2 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -770,8 +770,7 @@ static void aarch64_cpu_initfn(Object *obj) aarch64_cpu_set_aarch64, NULL); object_property_set_description(obj, "aarch64", "Set on/off to enable/disable aarch64 " - "execution state ", - NULL); + "execution state "); } static void aarch64_cpu_finalizefn(Object *obj) diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 390077c518..1ea2d047e3 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -204,7 +204,7 @@ void kvm_arm_add_vcpu_properties(Object *obj) object_property_set_description(obj, "kvm-no-adjvtime", "Set on to disable the adjustment of " "the virtual counter. VM stopped time " - "will be counted.", &error_abort); + "will be counted."); } bool kvm_arm_pmu_supported(CPUState *cpu) diff --git a/target/i386/sev.c b/target/i386/sev.c index 846018a12d..6842cfc26d 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -251,19 +251,19 @@ qsev_guest_class_init(ObjectClass *oc, void *data) qsev_guest_set_sev_device, NULL); object_class_property_set_description(oc, "sev-device", - "SEV device to use", NULL); + "SEV device to use"); object_class_property_add_str(oc, "dh-cert-file", qsev_guest_get_dh_cert_file, qsev_guest_set_dh_cert_file, NULL); object_class_property_set_description(oc, "dh-cert-file", - "guest owners DH certificate (encoded with base64)", NULL); + "guest owners DH certificate (encoded with base64)"); object_class_property_add_str(oc, "session-file", qsev_guest_get_session_file, qsev_guest_set_session_file, NULL); object_class_property_set_description(oc, "session-file", - "guest owners session parameters (encoded with base64)", NULL); + "guest owners session parameters (encoded with base64)"); } static void diff --git a/target/ppc/compat.c b/target/ppc/compat.c index f48df25944..46ffb6da6d 100644 --- a/target/ppc/compat.c +++ b/target/ppc/compat.c @@ -324,7 +324,7 @@ void ppc_compat_add_property(Object *obj, const char *name, names = g_strjoinv(", ", namesv); desc = g_strdup_printf("%s. Valid values are %s.", basedesc, names); - object_property_set_description(obj, name, desc, &local_err); + object_property_set_description(obj, name, desc); g_free(names); g_free(desc); diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 7c32180269..aa7fc713ca 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -1107,13 +1107,13 @@ void s390_cpu_model_register_props(Object *obj) const S390FeatDef *def = s390_feat_def(feat); object_property_add(obj, def->name, "bool", get_feature, set_feature, NULL, (void *) feat, NULL); - object_property_set_description(obj, def->name, def->desc , NULL); + object_property_set_description(obj, def->name, def->desc); } for (group = 0; group < S390_FEAT_GROUP_MAX; group++) { const S390FeatGroupDef *def = s390_feat_group_def(group); object_property_add(obj, def->name, "bool", get_feature_group, set_feature_group, NULL, (void *) group, NULL); - object_property_set_description(obj, def->name, def->desc , NULL); + object_property_set_description(obj, def->name, def->desc); } } From 48942138177a89c920d0a01397ccbc4040090e5e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:16 +0200 Subject: [PATCH 0472/2595] tests/check-qom-proplist: Improve iterator coverage The tests' "qemu-dummy" device has only class properties. Turn one of them into an instance property. test_dummy_class_iterator() expects one fewer property than test_dummy_iterator(). Rewrite test_dummy_prop_iterator() to take expected properties as argument. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-9-armbru@redhat.com> --- tests/check-qom-proplist.c | 51 +++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c index a8b2958e6e..140d56439a 100644 --- a/tests/check-qom-proplist.c +++ b/tests/check-qom-proplist.c @@ -130,17 +130,18 @@ static void dummy_init(Object *obj) object_property_add_bool(obj, "bv", dummy_get_bv, dummy_set_bv, - &err); + NULL); + /* duplicate: */ + object_property_add_str(obj, "sv", + dummy_get_sv, + dummy_set_sv, + &err); error_free_or_abort(&err); } static void dummy_class_init(ObjectClass *cls, void *data) { - object_class_property_add_bool(cls, "bv", - dummy_get_bv, - dummy_set_bv, - NULL); object_class_property_add_str(cls, "sv", dummy_get_sv, dummy_set_sv, @@ -520,34 +521,33 @@ static void test_dummy_getenum(void) } -static void test_dummy_prop_iterator(ObjectPropertyIterator *iter) +static void test_dummy_prop_iterator(ObjectPropertyIterator *iter, + const char *expected[], int n) { - bool seenbv = false, seensv = false, seenav = false, seentype = false; ObjectProperty *prop; + int i; while ((prop = object_property_iter_next(iter))) { - if (!seenbv && g_str_equal(prop->name, "bv")) { - seenbv = true; - } else if (!seensv && g_str_equal(prop->name, "sv")) { - seensv = true; - } else if (!seenav && g_str_equal(prop->name, "av")) { - seenav = true; - } else if (!seentype && g_str_equal(prop->name, "type")) { - /* This prop comes from the base Object class */ - seentype = true; - } else { - g_printerr("Found prop '%s'\n", prop->name); - g_assert_not_reached(); + for (i = 0; i < n; i++) { + if (!g_strcmp0(prop->name, expected[i])) { + break; + } } + g_assert(i < n); + expected[i] = NULL; + } + + for (i = 0; i < n; i++) { + g_assert(!expected[i]); } - g_assert(seenbv); - g_assert(seenav); - g_assert(seensv); - g_assert(seentype); } static void test_dummy_iterator(void) { + const char *expected[] = { + "type", /* inherited from TYPE_OBJECT */ + "sv", "av", /* class properties */ + "bv"}; /* instance property */ Object *parent = object_get_objects_root(); DummyObject *dobj = DUMMY_OBJECT( object_new_with_props(TYPE_DUMMY, @@ -561,17 +561,18 @@ static void test_dummy_iterator(void) ObjectPropertyIterator iter; object_property_iter_init(&iter, OBJECT(dobj)); - test_dummy_prop_iterator(&iter); + test_dummy_prop_iterator(&iter, expected, ARRAY_SIZE(expected)); object_unparent(OBJECT(dobj)); } static void test_dummy_class_iterator(void) { + const char *expected[] = { "type", "av", "sv" }; ObjectPropertyIterator iter; ObjectClass *klass = object_class_by_name(TYPE_DUMMY); object_class_property_iter_init(&iter, klass); - test_dummy_prop_iterator(&iter); + test_dummy_prop_iterator(&iter, expected, ARRAY_SIZE(expected)); } static void test_dummy_delchild(void) From e274408cdc07b431ef6dfdbb5011c5ef434702e8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:17 +0200 Subject: [PATCH 0473/2595] s390x/cpumodel: Fix UI to CPU features pcc-cmac-{aes,eaes}-256 Both s390_features[S390_FEAT_PCC_CMAC_AES_256].name and s390_features[S390_FEAT_PCC_CMAC_EAES_256].name is "pcc-cmac-eaes-256". The former is obviously a pasto. Impact: * s390_feat_bitmap_to_ascii() misidentifies S390_FEAT_PCC_CMAC_AES_256 as "pcc-cmac-eaes-256". Affects QMP commands query-cpu-definitions, query-cpu-model-expansion, query-cpu-model-baseline, query-cpu-model-comparison, and the error message when s390_realize_cpu_model() fails in check_compatibility(). * s390_cpu_list() also misidentifies it. Affects -cpu help. * s390_cpu_model_register_props() creates CPU property "pcc-cmac-eaes-256" twice. The second one fails, but the error is ignored (a later commit will change that). Results in a single property "pcc-cmac-eaes-256" with the description for S390_FEAT_PCC_CMAC_AES_256, and no property for S390_FEAT_PCC_CMAC_EAES_256. CPU properties are visible in CLI -cpu and -device, QMP & HMP device_add, QMP device-list-properties, and QOM introspection. The two features are almost always used via their group msa4. Such use is not affected by this bug. Fix by deleting the wayward 'e'. Fixes: 782417446279 ("s390x/cpumodel: introduce CPU features") Cc: Halil Pasic Cc: Cornelia Huck Cc: Christian Borntraeger Cc: Richard Henderson Cc: David Hildenbrand Cc: qemu-s390x@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: David Hildenbrand Tested-by: Christian Borntraeger Message-Id: <20200505152926.18877-10-armbru@redhat.com> Reviewed-by: Cornelia Huck [Lost paragraph in commit message restored, Fixes: tweaked] --- target/s390x/cpu_features_def.inc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/s390x/cpu_features_def.inc.h b/target/s390x/cpu_features_def.inc.h index 60db28351d..5942f81f16 100644 --- a/target/s390x/cpu_features_def.inc.h +++ b/target/s390x/cpu_features_def.inc.h @@ -311,7 +311,7 @@ DEF_FEAT(PCC_CMAC_ETDEA_192, "pcc-cmac-etdea-128", PCC, 10, "PCC Compute-Last-Bl DEF_FEAT(PCC_CMAC_TDEA, "pcc-cmac-etdea-192", PCC, 11, "PCC Compute-Last-Block-CMAC-Using-EncryptedTDEA-192") DEF_FEAT(PCC_CMAC_AES_128, "pcc-cmac-aes-128", PCC, 18, "PCC Compute-Last-Block-CMAC-Using-AES-128") DEF_FEAT(PCC_CMAC_AES_192, "pcc-cmac-aes-192", PCC, 19, "PCC Compute-Last-Block-CMAC-Using-AES-192") -DEF_FEAT(PCC_CMAC_AES_256, "pcc-cmac-eaes-256", PCC, 20, "PCC Compute-Last-Block-CMAC-Using-AES-256") +DEF_FEAT(PCC_CMAC_AES_256, "pcc-cmac-aes-256", PCC, 20, "PCC Compute-Last-Block-CMAC-Using-AES-256") DEF_FEAT(PCC_CMAC_EAES_128, "pcc-cmac-eaes-128", PCC, 26, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-128") DEF_FEAT(PCC_CMAC_EAES_192, "pcc-cmac-eaes-192", PCC, 27, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-192") DEF_FEAT(PCC_CMAC_EAES_256, "pcc-cmac-eaes-256", PCC, 28, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-256") From e508430619b3b26112117b6e06ebc5f8f1d54aed Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:18 +0200 Subject: [PATCH 0474/2595] hw/isa/superio: Make the components QOM children MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit isa_superio_realize() attempts to make isa-parallel and isa-serial QOM children, but this does not work, because it calls object_property_add_child() after realizing with qdev_init_nofail(). Realizing a device without a parent gives it one: it gets put into the "/machine/unattached/" orphanage. The extra object_property_add_child() fails, and isa_superio_realize() ignores the error. Move the object_property_add_child() before qdev_init_nofail(), and pass &error_abort. For the other components, isa_superio_realize() doesn't even try. Add object_property_add_child() there. This affects machines 40p, clipper and fulong2e. For instance, fulong2e has its vt82c686b-superio (which is an isa-superio) at /machine/unattached/device[9]. Before the patch, its components are at /machine/unattached/device[10] .. [14]. Afterwards, they are at /machine/unattached/device[9]/{parallel0,serial0,serial1,isa-fdc,i8042}. Cc: Michael S. Tsirkin Cc: Paolo Bonzini Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-11-armbru@redhat.com> --- hw/isa/isa-superio.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index 180a8b9625..0d9d848280 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -62,6 +62,8 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(d, "irq", k->parallel.get_irq(sio, i)); } qdev_prop_set_chr(d, "chardev", chr); + object_property_add_child(OBJECT(sio), name, OBJECT(isa), + &error_abort); qdev_init_nofail(d); sio->parallel[i] = isa; trace_superio_create_parallel(i, @@ -69,8 +71,6 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) k->parallel.get_iobase(sio, i) : -1, k->parallel.get_irq ? k->parallel.get_irq(sio, i) : -1); - object_property_add_child(OBJECT(dev), name, - OBJECT(sio->parallel[i]), NULL); g_free(name); } } @@ -102,6 +102,8 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(d, "irq", k->serial.get_irq(sio, i)); } qdev_prop_set_chr(d, "chardev", chr); + object_property_add_child(OBJECT(sio), name, OBJECT(isa), + &error_abort); qdev_init_nofail(d); sio->serial[i] = isa; trace_superio_create_serial(i, @@ -109,8 +111,6 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) k->serial.get_iobase(sio, i) : -1, k->serial.get_irq ? k->serial.get_irq(sio, i) : -1); - object_property_add_child(OBJECT(dev), name, - OBJECT(sio->serial[0]), NULL); g_free(name); } } @@ -137,6 +137,8 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) qdev_prop_set_drive(d, "driveB", blk_by_legacy_dinfo(drive), &error_fatal); } + object_property_add_child(OBJECT(sio), "isa-fdc", OBJECT(isa), + &error_abort); qdev_init_nofail(d); sio->floppy = isa; trace_superio_create_floppy(0, @@ -147,7 +149,11 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) } /* Keyboard, mouse */ - sio->kbc = isa_create_simple(bus, TYPE_I8042); + isa = isa_create(bus, TYPE_I8042); + object_property_add_child(OBJECT(sio), TYPE_I8042, OBJECT(isa), + &error_abort); + qdev_init_nofail(DEVICE(isa)); + sio->kbc = isa; /* IDE */ if (k->ide.count && (!k->ide.is_enabled || k->ide.is_enabled(sio, 0))) { @@ -163,6 +169,8 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(d, "irq", k->ide.get_irq(sio, 0)); } qdev_init_nofail(d); + object_property_add_child(OBJECT(sio), "isa-ide", OBJECT(isa), + &error_abort); sio->ide = isa; trace_superio_create_ide(0, k->ide.get_iobase ? From a13f20422dc657719c3fa335788300c7ccf464ee Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:19 +0200 Subject: [PATCH 0475/2595] e1000: Don't run e1000_instance_init() twice QOM object initialization runs .instance_init() for the type and all its supertypes; see object_init_with_type(). Both TYPE_E1000_BASE and its concrete subtypes set .instance_init() to e1000_instance_init(). For the concrete subtypes, it duly gets run twice. The second run fails, but the error gets ignored (a later commit will change that). Remove it from the subtypes. Cc: Jason Wang Signed-off-by: Markus Armbruster Acked-by: Jason Wang Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-12-armbru@redhat.com> --- hw/net/e1000.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 2a69eee63f..0d2c2759e3 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -1824,7 +1824,6 @@ static void e1000_register_types(void) type_info.parent = TYPE_E1000_BASE; type_info.class_data = (void *)info; type_info.class_init = e1000_class_init; - type_info.instance_init = e1000_instance_init; type_register(&type_info); } From 5462cc8110845f88ae80b82799121d15c9c3a8fc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:20 +0200 Subject: [PATCH 0476/2595] hw/arm/bcm2835: Drop futile attempts at QOM-adopting memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "bcm2835-peripherals" device's .instance_init() method bcm2835_peripherals_init() attempts to make two memory regions QOM children of the device. This is futile, because memory_region_init() already did. The errors are ignored (a later commit will change that). Drop the useless calls. Cc: Peter Maydell Cc: Andrew Baumann Cc: "Philippe Mathieu-Daudé" Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Eric Blake Message-Id: <20200505152926.18877-13-armbru@redhat.com> --- hw/arm/bcm2835_peripherals.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index edcaa4916d..8b399d67ff 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -43,12 +43,10 @@ static void bcm2835_peripherals_init(Object *obj) /* Memory region for peripheral devices, which we export to our parent */ memory_region_init(&s->peri_mr, obj,"bcm2835-peripherals", 0x1000000); - object_property_add_child(obj, "peripheral-io", OBJECT(&s->peri_mr), NULL); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->peri_mr); /* Internal memory region for peripheral bus addresses (not exported) */ memory_region_init(&s->gpu_bus_mr, obj, "bcm2835-gpu", (uint64_t)1 << 32); - object_property_add_child(obj, "gpu-bus", OBJECT(&s->gpu_bus_mr), NULL); /* Internal memory region for request/response communication with * mailbox-addressable peripherals (not exported) From 9f742c28f52d55ff83dc441a0cea365239a4906d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:21 +0200 Subject: [PATCH 0477/2595] qdev: Clean up qdev_connect_gpio_out_named() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both qdev_connect_gpio_out_named() and device_set_realized() put objects without a parent into the "/machine/unattached/" orphanage. qdev_connect_gpio_out_named() needs a lengthy comment to explain how it works. It exploits that object_property_add_child() can fail only when we got a parent already, and ignoring that error does what we want. True. If it failed due to "duplicate property", we'd be in trouble, but that would be a programming error. device_set_realized() is cleaner: it checks whether we need a parent, then calls object_property_add_child(), aborting on failure. No need for a comment, and programming errors get caught. Change qdev_connect_gpio_out_named() to match. Cc: Peter Crosthwaite Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200505152926.18877-14-armbru@redhat.com> --- hw/core/qdev.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index ea7118ab0e..2e6c29ba78 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -542,15 +542,12 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, { char *propname = g_strdup_printf("%s[%d]", name ? name : "unnamed-gpio-out", n); - if (pin) { - /* We need a name for object_property_set_link to work. If the - * object has a parent, object_property_add_child will come back - * with an error without doing anything. If it has none, it will - * never fail. So we can just call it with a NULL Error pointer. - */ + if (pin && !OBJECT(pin)->parent) { + /* We need a name for object_property_set_link to work */ object_property_add_child(container_get(qdev_get_machine(), "/unattached"), - "non-qdev-gpio[*]", OBJECT(pin), NULL); + "non-qdev-gpio[*]", OBJECT(pin), + &error_abort); } object_property_set_link(OBJECT(dev), OBJECT(pin), propname, &error_abort); g_free(propname); From d2623129a7dec1d3041ad1221dda1ca49c667532 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:22 +0200 Subject: [PATCH 0478/2595] qom: Drop parameter @errp of object_property_add() & friends The only way object_property_add() can fail is when a property with the same name already exists. Since our property names are all hardcoded, failure is a programming error, and the appropriate way to handle it is passing &error_abort. Same for its variants, except for object_property_add_child(), which additionally fails when the child already has a parent. Parentage is also under program control, so this is a programming error, too. We have a bit over 500 callers. Almost half of them pass &error_abort, slightly fewer ignore errors, one test case handles errors, and the remaining few callers pass them to their own callers. The previous few commits demonstrated once again that ignoring programming errors is a bad idea. Of the few ones that pass on errors, several violate the Error API. The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. ich9_pm_add_properties(), sparc32_ledma_realize(), sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize() are wrong that way. When the one appropriate choice of argument is &error_abort, letting users pick the argument is a bad idea. Drop parameter @errp and assert the preconditions instead. There's one exception to "duplicate property name is a programming error": the way object_property_add() implements the magic (and undocumented) "automatic arrayification". Don't drop @errp there. Instead, rename object_property_add() to object_property_try_add(), and add the obvious wrapper object_property_add(). Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-15-armbru@redhat.com> [Two semantic rebase conflicts resolved] --- accel/kvm/kvm-all.c | 4 +- accel/tcg/tcg-all.c | 5 +- authz/list.c | 5 +- authz/listfile.c | 6 +- authz/pamacct.c | 3 +- authz/simple.c | 3 +- backends/cryptodev-vhost-user.c | 3 +- backends/cryptodev.c | 2 +- backends/dbus-vmstate.c | 6 +- backends/hostmem-file.c | 11 +- backends/hostmem-memfd.c | 8 +- backends/hostmem.c | 19 +- backends/rng-egd.c | 3 +- backends/rng-random.c | 3 +- backends/rng.c | 3 +- backends/vhost-user.c | 2 +- block/throttle-groups.c | 6 +- bootdevice.c | 8 +- chardev/char-socket.c | 4 +- chardev/char.c | 7 +- crypto/secret.c | 18 +- crypto/tlscreds.c | 12 +- crypto/tlscredsanon.c | 3 +- crypto/tlscredspsk.c | 6 +- crypto/tlscredsx509.c | 9 +- hw/acpi/ich9.c | 23 +-- hw/acpi/pcihp.c | 7 +- hw/acpi/piix4.c | 15 +- hw/arm/allwinner-a10.c | 2 +- hw/arm/allwinner-h3.c | 12 +- hw/arm/armv7m.c | 2 +- hw/arm/aspeed.c | 2 +- hw/arm/aspeed_ast2600.c | 13 +- hw/arm/aspeed_soc.c | 13 +- hw/arm/bcm2835_peripherals.c | 26 +-- hw/arm/bcm2836.c | 16 +- hw/arm/cubieboard.c | 3 +- hw/arm/mcimx6ul-evk.c | 2 +- hw/arm/mcimx7d-sabre.c | 2 +- hw/arm/msf2-soc.c | 3 +- hw/arm/nrf51_soc.c | 3 +- hw/arm/orangepi.c | 3 +- hw/arm/raspi.c | 3 +- hw/arm/sabrelite.c | 2 +- hw/arm/sbsa-ref.c | 5 +- hw/arm/vexpress.c | 4 +- hw/arm/virt.c | 21 +- hw/arm/xilinx_zynq.c | 2 +- hw/arm/xlnx-versal-virt.c | 6 +- hw/arm/xlnx-versal.c | 2 +- hw/arm/xlnx-zcu102.c | 4 +- hw/arm/xlnx-zynqmp.c | 9 +- hw/audio/marvell_88w8618.c | 2 +- hw/audio/pcspk.c | 2 +- hw/core/bus.c | 7 +- hw/core/machine.c | 46 ++--- hw/core/qdev-clock.c | 4 +- hw/core/qdev-properties.c | 9 +- hw/core/qdev.c | 40 ++-- hw/cpu/core.c | 4 +- hw/display/bochs-display.c | 3 +- hw/display/sm501.c | 2 +- hw/display/vga-pci.c | 4 +- hw/display/vhost-user-gpu-pci.c | 3 +- hw/display/vhost-user-gpu.c | 2 +- hw/display/vhost-user-vga.c | 3 +- hw/display/xlnx_dp.c | 7 +- hw/dma/sparc32_dma.c | 10 +- hw/dma/xilinx_axidma.c | 12 +- hw/dma/xlnx-zdma.c | 3 +- hw/gpio/aspeed_gpio.c | 2 +- hw/hyperv/hyperv.c | 2 +- hw/i386/microvm.c | 15 +- hw/i386/pc.c | 12 +- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 4 +- hw/i386/pc_sysfw.c | 5 +- hw/i386/x86.c | 8 +- hw/ide/macio.c | 2 +- hw/ide/qdev.c | 2 +- hw/input/vhost-user-input.c | 2 +- hw/intc/apic_common.c | 2 +- hw/intc/s390_flic.c | 4 +- hw/intc/xics.c | 2 +- hw/intc/xive.c | 2 +- hw/ipmi/ipmi.c | 3 +- hw/isa/isa-superio.c | 15 +- hw/isa/lpc_ich9.c | 6 +- hw/mem/nvdimm.c | 4 +- hw/mem/pc-dimm.c | 2 +- hw/microblaze/petalogix_ml605_mmu.c | 6 +- hw/misc/aspeed_sdmc.c | 2 +- hw/misc/edu.c | 3 +- hw/misc/mac_via.c | 4 +- hw/misc/macio/gpio.c | 2 +- hw/misc/macio/macio.c | 4 +- hw/misc/macio/pmu.c | 2 +- hw/misc/pca9552.c | 2 +- hw/misc/tmp105.c | 2 +- hw/misc/tmp421.c | 8 +- hw/net/cadence_gem.c | 3 +- hw/net/can/can_kvaser_pci.c | 2 +- hw/net/can/can_mioe3680_pci.c | 4 +- hw/net/can/can_pcm3680_pci.c | 4 +- hw/net/ne2000-isa.c | 2 +- hw/net/xilinx_axienet.c | 9 +- hw/nios2/10m50_devboard.c | 3 +- hw/nvram/fw_cfg.c | 4 +- hw/pci-host/grackle.c | 2 +- hw/pci-host/i440fx.c | 12 +- hw/pci-host/pnv_phb3_msi.c | 3 +- hw/pci-host/pnv_phb3_pbcq.c | 3 +- hw/pci-host/q35.c | 20 +- hw/pci-host/sabre.c | 2 +- hw/pci-host/uninorth.c | 8 +- hw/pcmcia/pxa2xx.c | 2 +- hw/ppc/e500.c | 8 +- hw/ppc/mac_newworld.c | 4 +- hw/ppc/mac_oldworld.c | 2 +- hw/ppc/pnv.c | 13 +- hw/ppc/pnv_bmc.c | 5 +- hw/ppc/pnv_core.c | 2 +- hw/ppc/pnv_psi.c | 2 +- hw/ppc/prep.c | 6 +- hw/ppc/spapr.c | 25 +-- hw/ppc/spapr_caps.c | 8 +- hw/ppc/spapr_cpu_core.c | 5 +- hw/ppc/spapr_drc.c | 18 +- hw/ppc/spapr_iommu.c | 2 +- hw/ppc/spapr_irq.c | 2 +- hw/ppc/spapr_rtc.c | 2 +- hw/riscv/sifive_u.c | 10 +- hw/riscv/virt.c | 5 +- hw/rtc/mc146818rtc.c | 4 +- hw/s390x/ap-bridge.c | 2 +- hw/s390x/css-bridge.c | 4 +- hw/s390x/event-facility.c | 6 +- hw/s390x/s390-skeys.c | 4 +- hw/s390x/s390-stattrib.c | 4 +- hw/s390x/s390-virtio-ccw.c | 10 +- hw/s390x/sclp.c | 5 +- hw/s390x/tod.c | 2 +- hw/s390x/virtio-ccw-balloon.c | 4 +- hw/s390x/virtio-ccw-blk.c | 2 +- hw/s390x/virtio-ccw-net.c | 2 +- hw/scsi/scsi-bus.c | 2 +- hw/sparc/sun4m.c | 4 +- hw/sparc64/sun4u.c | 2 +- hw/ssi/xilinx_spips.c | 3 +- hw/usb/bus.c | 6 +- hw/usb/dev-storage.c | 2 +- hw/vfio/pci-quirks.c | 6 +- hw/virtio/vhost-scsi-pci.c | 2 +- hw/virtio/vhost-user-blk-pci.c | 2 +- hw/virtio/vhost-user-input-pci.c | 3 +- hw/virtio/vhost-user-scsi-pci.c | 2 +- hw/virtio/virtio-balloon-pci.c | 4 +- hw/virtio/virtio-balloon.c | 4 +- hw/virtio/virtio-blk-pci.c | 2 +- hw/virtio/virtio-net-pci.c | 2 +- hw/virtio/virtio-rng.c | 2 +- hw/xen/xen-common.c | 3 +- include/qom/object.h | 81 +++----- iothread.c | 6 +- memory.c | 10 +- net/can/can_host.c | 3 +- net/can/can_socketcan.c | 3 +- net/colo-compare.c | 20 +- net/dump.c | 4 +- net/filter-buffer.c | 2 +- net/filter-mirror.c | 10 +- net/filter-rewriter.c | 2 +- net/filter.c | 15 +- qdev-monitor.c | 4 +- qom/container.c | 2 +- qom/object.c | 302 +++++++++------------------- qom/object_interfaces.c | 5 +- scsi/pr-manager-helper.c | 3 +- softmmu/vl.c | 7 +- target/arm/cpu.c | 11 +- target/arm/cpu64.c | 8 +- target/arm/kvm.c | 2 +- target/i386/cpu.c | 83 ++++---- target/i386/sev.c | 17 +- target/ppc/compat.c | 9 +- target/s390x/cpu.c | 2 +- target/s390x/cpu_models.c | 11 +- tests/check-qom-proplist.c | 29 +-- tests/test-qdev-global-props.c | 4 +- ui/console.c | 7 +- ui/input-barrier.c | 14 +- ui/input-linux.c | 8 +- 192 files changed, 650 insertions(+), 994 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 9b712aac77..d06cc04079 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3111,13 +3111,13 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data) object_class_property_add(oc, "kernel-irqchip", "on|off|split", NULL, kvm_set_kernel_irqchip, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, "kernel-irqchip", "Configure KVM in-kernel irqchip"); object_class_property_add(oc, "kvm-shadow-mem", "int", kvm_get_kvm_shadow_mem, kvm_set_kvm_shadow_mem, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, "kvm-shadow-mem", "KVM shadow MMU size"); } diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 3398a56ef9..3b4fda5640 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -203,12 +203,11 @@ static void tcg_accel_class_init(ObjectClass *oc, void *data) object_class_property_add_str(oc, "thread", tcg_get_thread, - tcg_set_thread, - NULL); + tcg_set_thread); object_class_property_add(oc, "tb-size", "int", tcg_get_tb_size, tcg_set_tb_size, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, "tb-size", "TCG translation block cache size"); diff --git a/authz/list.c b/authz/list.c index 5a48074d0a..8e904bfc93 100644 --- a/authz/list.c +++ b/authz/list.c @@ -124,13 +124,12 @@ qauthz_list_class_init(ObjectClass *oc, void *data) "QAuthZListPolicy", &QAuthZListPolicy_lookup, qauthz_list_prop_get_policy, - qauthz_list_prop_set_policy, - NULL); + qauthz_list_prop_set_policy); object_class_property_add(oc, "rules", "QAuthZListRule", qauthz_list_prop_get_rules, qauthz_list_prop_set_rules, - NULL, NULL, NULL); + NULL, NULL); authz->is_allowed = qauthz_list_is_allowed; } diff --git a/authz/listfile.c b/authz/listfile.c index b71f57d30a..666df872ad 100644 --- a/authz/listfile.c +++ b/authz/listfile.c @@ -221,12 +221,10 @@ qauthz_list_file_class_init(ObjectClass *oc, void *data) object_class_property_add_str(oc, "filename", qauthz_list_file_prop_get_filename, - qauthz_list_file_prop_set_filename, - NULL); + qauthz_list_file_prop_set_filename); object_class_property_add_bool(oc, "refresh", qauthz_list_file_prop_get_refresh, - qauthz_list_file_prop_set_refresh, - NULL); + qauthz_list_file_prop_set_refresh); authz->is_allowed = qauthz_list_file_is_allowed; } diff --git a/authz/pamacct.c b/authz/pamacct.c index a8ad25b6c7..3c6be43916 100644 --- a/authz/pamacct.c +++ b/authz/pamacct.c @@ -107,8 +107,7 @@ qauthz_pam_class_init(ObjectClass *oc, void *data) object_class_property_add_str(oc, "service", qauthz_pam_prop_get_service, - qauthz_pam_prop_set_service, - NULL); + qauthz_pam_prop_set_service); } diff --git a/authz/simple.c b/authz/simple.c index 008912d247..84954b80a5 100644 --- a/authz/simple.c +++ b/authz/simple.c @@ -74,8 +74,7 @@ qauthz_simple_class_init(ObjectClass *oc, void *data) object_class_property_add_str(oc, "identity", qauthz_simple_prop_get_identity, - qauthz_simple_prop_set_identity, - NULL); + qauthz_simple_prop_set_identity); } diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c index 6edada8e9e..8b8cbc4223 100644 --- a/backends/cryptodev-vhost-user.c +++ b/backends/cryptodev-vhost-user.c @@ -340,8 +340,7 @@ static void cryptodev_vhost_user_instance_int(Object *obj) { object_property_add_str(obj, "chardev", cryptodev_vhost_user_get_chardev, - cryptodev_vhost_user_set_chardev, - NULL); + cryptodev_vhost_user_set_chardev); } static void cryptodev_vhost_user_finalize(Object *obj) diff --git a/backends/cryptodev.c b/backends/cryptodev.c index 5a9735684e..a3841c4e41 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -213,7 +213,7 @@ static void cryptodev_backend_instance_init(Object *obj) object_property_add(obj, "queues", "uint32", cryptodev_backend_get_queues, cryptodev_backend_set_queues, - NULL, NULL, NULL); + NULL, NULL); /* Initialize devices' queues property to 1 */ object_property_set_int(obj, 1, "queues", NULL); } diff --git a/backends/dbus-vmstate.c b/backends/dbus-vmstate.c index cc594a722e..56361a6272 100644 --- a/backends/dbus-vmstate.c +++ b/backends/dbus-vmstate.c @@ -481,11 +481,9 @@ dbus_vmstate_class_init(ObjectClass *oc, void *data) vc->get_id = dbus_vmstate_get_id; object_class_property_add_str(oc, "addr", - get_dbus_addr, set_dbus_addr, - &error_abort); + get_dbus_addr, set_dbus_addr); object_class_property_add_str(oc, "id-list", - get_id_list, set_id_list, - &error_abort); + get_id_list, set_id_list); } static const TypeInfo dbus_vmstate_info = { diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index c8c355f5aa..cdabb412e6 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -184,18 +184,15 @@ file_backend_class_init(ObjectClass *oc, void *data) oc->unparent = file_backend_unparent; object_class_property_add_bool(oc, "discard-data", - file_memory_backend_get_discard_data, file_memory_backend_set_discard_data, - &error_abort); + file_memory_backend_get_discard_data, file_memory_backend_set_discard_data); object_class_property_add_str(oc, "mem-path", - get_mem_path, set_mem_path, - &error_abort); + get_mem_path, set_mem_path); object_class_property_add(oc, "align", "int", file_memory_backend_get_align, file_memory_backend_set_align, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_add_bool(oc, "pmem", - file_memory_backend_get_pmem, file_memory_backend_set_pmem, - &error_abort); + file_memory_backend_get_pmem, file_memory_backend_set_pmem); } static void file_backend_instance_finalize(Object *o) diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c index 5991f31459..1b5e4bfe0d 100644 --- a/backends/hostmem-memfd.c +++ b/backends/hostmem-memfd.c @@ -141,21 +141,19 @@ memfd_backend_class_init(ObjectClass *oc, void *data) if (qemu_memfd_check(MFD_HUGETLB)) { object_class_property_add_bool(oc, "hugetlb", memfd_backend_get_hugetlb, - memfd_backend_set_hugetlb, - &error_abort); + memfd_backend_set_hugetlb); object_class_property_set_description(oc, "hugetlb", "Use huge pages"); object_class_property_add(oc, "hugetlbsize", "int", memfd_backend_get_hugetlbsize, memfd_backend_set_hugetlbsize, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, "hugetlbsize", "Huge pages size (ex: 2M, 1G)"); } object_class_property_add_bool(oc, "seal", memfd_backend_get_seal, - memfd_backend_set_seal, - &error_abort); + memfd_backend_set_seal); object_class_property_set_description(oc, "seal", "Seal growing & shrinking"); } diff --git a/backends/hostmem.c b/backends/hostmem.c index 946d176435..4ee4354898 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -463,51 +463,50 @@ host_memory_backend_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "merge", host_memory_backend_get_merge, - host_memory_backend_set_merge, &error_abort); + host_memory_backend_set_merge); object_class_property_set_description(oc, "merge", "Mark memory as mergeable"); object_class_property_add_bool(oc, "dump", host_memory_backend_get_dump, - host_memory_backend_set_dump, &error_abort); + host_memory_backend_set_dump); object_class_property_set_description(oc, "dump", "Set to 'off' to exclude from core dump"); object_class_property_add_bool(oc, "prealloc", host_memory_backend_get_prealloc, - host_memory_backend_set_prealloc, &error_abort); + host_memory_backend_set_prealloc); object_class_property_set_description(oc, "prealloc", "Preallocate memory"); object_class_property_add(oc, "prealloc-threads", "int", host_memory_backend_get_prealloc_threads, host_memory_backend_set_prealloc_threads, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, "prealloc-threads", "Number of CPU threads to use for prealloc"); object_class_property_add(oc, "size", "int", host_memory_backend_get_size, host_memory_backend_set_size, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, "size", "Size of the memory region (ex: 500M)"); object_class_property_add(oc, "host-nodes", "int", host_memory_backend_get_host_nodes, host_memory_backend_set_host_nodes, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, "host-nodes", "Binds memory to the list of NUMA host nodes"); object_class_property_add_enum(oc, "policy", "HostMemPolicy", &HostMemPolicy_lookup, host_memory_backend_get_policy, - host_memory_backend_set_policy, &error_abort); + host_memory_backend_set_policy); object_class_property_set_description(oc, "policy", "Set the NUMA policy"); object_class_property_add_bool(oc, "share", - host_memory_backend_get_share, host_memory_backend_set_share, - &error_abort); + host_memory_backend_get_share, host_memory_backend_set_share); object_class_property_set_description(oc, "share", "Mark the memory as private to QEMU or shared"); object_class_property_add_bool(oc, "x-use-canonical-path-for-ramblock-id", host_memory_backend_get_use_canonical_path, - host_memory_backend_set_use_canonical_path, &error_abort); + host_memory_backend_set_use_canonical_path); } static const TypeInfo host_memory_backend_info = { diff --git a/backends/rng-egd.c b/backends/rng-egd.c index e380519408..7aaa6ee239 100644 --- a/backends/rng-egd.c +++ b/backends/rng-egd.c @@ -138,8 +138,7 @@ static char *rng_egd_get_chardev(Object *obj, Error **errp) static void rng_egd_init(Object *obj) { object_property_add_str(obj, "chardev", - rng_egd_get_chardev, rng_egd_set_chardev, - NULL); + rng_egd_get_chardev, rng_egd_set_chardev); } static void rng_egd_finalize(Object *obj) diff --git a/backends/rng-random.c b/backends/rng-random.c index a810581393..32998d8ee7 100644 --- a/backends/rng-random.c +++ b/backends/rng-random.c @@ -110,8 +110,7 @@ static void rng_random_init(Object *obj) object_property_add_str(obj, "filename", rng_random_get_filename, - rng_random_set_filename, - NULL); + rng_random_set_filename); s->filename = g_strdup("/dev/urandom"); s->fd = -1; diff --git a/backends/rng.c b/backends/rng.c index 391888b8b3..597f0ec268 100644 --- a/backends/rng.c +++ b/backends/rng.c @@ -108,8 +108,7 @@ static void rng_backend_init(Object *obj) object_property_add_bool(obj, "opened", rng_backend_prop_get_opened, - rng_backend_prop_set_opened, - NULL); + rng_backend_prop_set_opened); } static void rng_backend_finalize(Object *obj) diff --git a/backends/vhost-user.c b/backends/vhost-user.c index 2bf3406525..9e6e198546 100644 --- a/backends/vhost-user.c +++ b/backends/vhost-user.c @@ -177,7 +177,7 @@ static char *get_chardev(Object *obj, Error **errp) static void vhost_user_backend_init(Object *obj) { - object_property_add_str(obj, "chardev", get_chardev, set_chardev, NULL); + object_property_add_str(obj, "chardev", get_chardev, set_chardev); } static void vhost_user_backend_finalize(Object *obj) diff --git a/block/throttle-groups.c b/block/throttle-groups.c index 37695b0cd7..784fa4a16c 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -954,8 +954,7 @@ static void throttle_group_obj_class_init(ObjectClass *klass, void *class_data) "int", throttle_group_get, throttle_group_set, - NULL, &properties[i], - &error_abort); + NULL, &properties[i]); } /* ThrottleLimits */ @@ -963,8 +962,7 @@ static void throttle_group_obj_class_init(ObjectClass *klass, void *class_data) "limits", "ThrottleLimits", throttle_group_get_limits, throttle_group_set_limits, - NULL, NULL, - &error_abort); + NULL, NULL); } static const TypeInfo throttle_group_info = { diff --git a/bootdevice.c b/bootdevice.c index 03aaffcc8d..d11576d575 100644 --- a/bootdevice.c +++ b/bootdevice.c @@ -329,7 +329,6 @@ void device_add_bootindex_property(Object *obj, int32_t *bootindex, const char *name, const char *suffix, DeviceState *dev, Error **errp) { - Error *local_err = NULL; BootIndexProperty *prop = g_malloc0(sizeof(*prop)); prop->bootindex = bootindex; @@ -340,13 +339,8 @@ void device_add_bootindex_property(Object *obj, int32_t *bootindex, device_get_bootindex, device_set_bootindex, property_release_bootindex, - prop, &local_err); + prop); - if (local_err) { - error_propagate(errp, local_err); - g_free(prop); - return; - } /* initialize devices' bootindex property to -1 */ object_property_set_int(obj, -1, name, NULL); } diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 185fe38dda..232e0a8604 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1489,10 +1489,10 @@ static void char_socket_class_init(ObjectClass *oc, void *data) object_class_property_add(oc, "addr", "SocketAddress", char_socket_get_addr, NULL, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_add_bool(oc, "connected", char_socket_get_connected, - NULL, &error_abort); + NULL); } static const TypeInfo char_socket_type_info = { diff --git a/chardev/char.c b/chardev/char.c index e77564060d..0196e2887b 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -986,10 +986,7 @@ static Chardev *chardev_new(const char *id, const char *typename, } if (id) { - object_property_add_child(get_chardevs_root(), id, obj, &local_err); - if (local_err) { - goto end; - } + object_property_add_child(get_chardevs_root(), id, obj); object_unref(obj); } @@ -1116,7 +1113,7 @@ ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend, object_unparent(OBJECT(chr)); object_property_add_child(get_chardevs_root(), chr_new->label, - OBJECT(chr_new), &error_abort); + OBJECT(chr_new)); object_unref(OBJECT(chr_new)); ret = g_new0(ChardevReturn, 1); diff --git a/crypto/secret.c b/crypto/secret.c index a846a3c87c..3107aecb47 100644 --- a/crypto/secret.c +++ b/crypto/secret.c @@ -369,30 +369,24 @@ qcrypto_secret_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_secret_prop_get_loaded, - qcrypto_secret_prop_set_loaded, - NULL); + qcrypto_secret_prop_set_loaded); object_class_property_add_enum(oc, "format", "QCryptoSecretFormat", &QCryptoSecretFormat_lookup, qcrypto_secret_prop_get_format, - qcrypto_secret_prop_set_format, - NULL); + qcrypto_secret_prop_set_format); object_class_property_add_str(oc, "data", qcrypto_secret_prop_get_data, - qcrypto_secret_prop_set_data, - NULL); + qcrypto_secret_prop_set_data); object_class_property_add_str(oc, "file", qcrypto_secret_prop_get_file, - qcrypto_secret_prop_set_file, - NULL); + qcrypto_secret_prop_set_file); object_class_property_add_str(oc, "keyid", qcrypto_secret_prop_get_keyid, - qcrypto_secret_prop_set_keyid, - NULL); + qcrypto_secret_prop_set_keyid); object_class_property_add_str(oc, "iv", qcrypto_secret_prop_get_iv, - qcrypto_secret_prop_set_iv, - NULL); + qcrypto_secret_prop_set_iv); } diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c index 4e657b850c..b68735f06f 100644 --- a/crypto/tlscreds.c +++ b/crypto/tlscreds.c @@ -226,22 +226,18 @@ qcrypto_tls_creds_class_init(ObjectClass *oc, void *data) { object_class_property_add_bool(oc, "verify-peer", qcrypto_tls_creds_prop_get_verify, - qcrypto_tls_creds_prop_set_verify, - NULL); + qcrypto_tls_creds_prop_set_verify); object_class_property_add_str(oc, "dir", qcrypto_tls_creds_prop_get_dir, - qcrypto_tls_creds_prop_set_dir, - NULL); + qcrypto_tls_creds_prop_set_dir); object_class_property_add_enum(oc, "endpoint", "QCryptoTLSCredsEndpoint", &QCryptoTLSCredsEndpoint_lookup, qcrypto_tls_creds_prop_get_endpoint, - qcrypto_tls_creds_prop_set_endpoint, - NULL); + qcrypto_tls_creds_prop_set_endpoint); object_class_property_add_str(oc, "priority", qcrypto_tls_creds_prop_get_priority, - qcrypto_tls_creds_prop_set_priority, - NULL); + qcrypto_tls_creds_prop_set_priority); } diff --git a/crypto/tlscredsanon.c b/crypto/tlscredsanon.c index a235f60146..fc078d5b97 100644 --- a/crypto/tlscredsanon.c +++ b/crypto/tlscredsanon.c @@ -187,8 +187,7 @@ qcrypto_tls_creds_anon_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_anon_prop_get_loaded, - qcrypto_tls_creds_anon_prop_set_loaded, - NULL); + qcrypto_tls_creds_anon_prop_set_loaded); } diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c index 15d12e2448..f01b64d8bc 100644 --- a/crypto/tlscredspsk.c +++ b/crypto/tlscredspsk.c @@ -275,12 +275,10 @@ qcrypto_tls_creds_psk_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_psk_prop_get_loaded, - qcrypto_tls_creds_psk_prop_set_loaded, - NULL); + qcrypto_tls_creds_psk_prop_set_loaded); object_class_property_add_str(oc, "username", qcrypto_tls_creds_psk_prop_get_username, - qcrypto_tls_creds_psk_prop_set_username, - NULL); + qcrypto_tls_creds_psk_prop_set_username); } diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c index 53a4368f49..e337d68c4f 100644 --- a/crypto/tlscredsx509.c +++ b/crypto/tlscredsx509.c @@ -806,16 +806,13 @@ qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_x509_prop_get_loaded, - qcrypto_tls_creds_x509_prop_set_loaded, - NULL); + qcrypto_tls_creds_x509_prop_set_loaded); object_class_property_add_bool(oc, "sanity-check", qcrypto_tls_creds_x509_prop_get_sanity, - qcrypto_tls_creds_x509_prop_set_sanity, - NULL); + qcrypto_tls_creds_x509_prop_set_sanity); object_class_property_add_str(oc, "passwordid", qcrypto_tls_creds_x509_prop_get_passwordid, - qcrypto_tls_creds_x509_prop_set_passwordid, - NULL); + qcrypto_tls_creds_x509_prop_set_passwordid); } diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 336cacea41..9e4c03bef8 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -379,32 +379,27 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) pm->s4_val = 2; object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, - &pm->pm_io_base, OBJ_PROP_FLAG_READ, errp); + &pm->pm_io_base, OBJ_PROP_FLAG_READ); object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32", ich9_pm_get_gpe0_blk, - NULL, NULL, pm, NULL); + NULL, NULL, pm); object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN, - &gpe0_len, OBJ_PROP_FLAG_READ, errp); + &gpe0_len, OBJ_PROP_FLAG_READ); object_property_add_bool(obj, "memory-hotplug-support", ich9_pm_get_memory_hotplug_support, - ich9_pm_set_memory_hotplug_support, - NULL); + ich9_pm_set_memory_hotplug_support); object_property_add_bool(obj, "cpu-hotplug-legacy", ich9_pm_get_cpu_hotplug_legacy, - ich9_pm_set_cpu_hotplug_legacy, - NULL); + ich9_pm_set_cpu_hotplug_legacy); object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S3_DISABLED, - &pm->disable_s3, OBJ_PROP_FLAG_READWRITE, - NULL); + &pm->disable_s3, OBJ_PROP_FLAG_READWRITE); object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_DISABLED, - &pm->disable_s4, OBJ_PROP_FLAG_READWRITE, - NULL); + &pm->disable_s4, OBJ_PROP_FLAG_READWRITE); object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_VAL, - &pm->s4_val, OBJ_PROP_FLAG_READWRITE, NULL); + &pm->s4_val, OBJ_PROP_FLAG_READWRITE); object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED, ich9_pm_get_enable_tco, - ich9_pm_set_enable_tco, - NULL); + ich9_pm_set_enable_tco); } void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 0dc963e983..fbc86af102 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -80,8 +80,7 @@ static void *acpi_set_bsel(PCIBus *bus, void *opaque) *bus_bsel = (*bsel_alloc)++; object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, - bus_bsel, OBJ_PROP_FLAG_READ, - &error_abort); + bus_bsel, OBJ_PROP_FLAG_READ); } return bsel_alloc; @@ -374,9 +373,9 @@ void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, memory_region_add_subregion(address_space_io, s->io_base, &s->io); object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_BASE_PROP, &s->io_base, - OBJ_PROP_FLAG_READ, &error_abort); + OBJ_PROP_FLAG_READ); object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_LEN_PROP, &s->io_len, - OBJ_PROP_FLAG_READ, &error_abort); + OBJ_PROP_FLAG_READ); } const VMStateDescription vmstate_acpi_pcihp_pci_status = { diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 964d6f5990..85c199b30d 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -444,17 +444,17 @@ static void piix4_pm_add_propeties(PIIX4PMState *s) static const uint16_t sci_int = 9; object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_ENABLE_CMD, - &acpi_enable_cmd, OBJ_PROP_FLAG_READ, NULL); + &acpi_enable_cmd, OBJ_PROP_FLAG_READ); object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_DISABLE_CMD, - &acpi_disable_cmd, OBJ_PROP_FLAG_READ, NULL); + &acpi_disable_cmd, OBJ_PROP_FLAG_READ); object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK, - &gpe0_blk, OBJ_PROP_FLAG_READ, NULL); + &gpe0_blk, OBJ_PROP_FLAG_READ); object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK_LEN, - &gpe0_blk_len, OBJ_PROP_FLAG_READ, NULL); + &gpe0_blk_len, OBJ_PROP_FLAG_READ); object_property_add_uint16_ptr(OBJECT(s), ACPI_PM_PROP_SCI_INT, - &sci_int, OBJ_PROP_FLAG_READ, NULL); + &sci_int, OBJ_PROP_FLAG_READ); object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_PM_IO_BASE, - &s->io_base, OBJ_PROP_FLAG_READ, NULL); + &s->io_base, OBJ_PROP_FLAG_READ); } static void piix4_pm_realize(PCIDevice *dev, Error **errp) @@ -598,8 +598,7 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, s->cpu_hotplug_legacy = true; object_property_add_bool(OBJECT(s), "cpu-hotplug-legacy", piix4_get_cpu_hotplug_legacy, - piix4_set_cpu_hotplug_legacy, - NULL); + piix4_set_cpu_hotplug_legacy); legacy_acpi_cpu_hotplug_init(parent, OBJECT(s), &s->gpe_cpu, PIIX4_CPU_HOTPLUG_IO_BASE); diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 62a67a3e1a..6e1329a4a2 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -178,7 +178,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc0), 0, AW_A10_MMC0_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc0), 0, qdev_get_gpio_in(dev, 32)); object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->mmc0), - "sd-bus", &error_abort); + "sd-bus"); /* RTC */ qdev_init_nofail(DEVICE(&s->rtc)); diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c index 9e4ce36093..f10674da5a 100644 --- a/hw/arm/allwinner-h3.c +++ b/hw/arm/allwinner-h3.c @@ -205,9 +205,9 @@ static void allwinner_h3_init(Object *obj) sysbus_init_child_obj(obj, "timer", &s->timer, sizeof(s->timer), TYPE_AW_A10_PIT); object_property_add_alias(obj, "clk0-freq", OBJECT(&s->timer), - "clk0-freq", &error_abort); + "clk0-freq"); object_property_add_alias(obj, "clk1-freq", OBJECT(&s->timer), - "clk1-freq", &error_abort); + "clk1-freq"); sysbus_init_child_obj(obj, "ccu", &s->ccu, sizeof(s->ccu), TYPE_AW_H3_CCU); @@ -221,7 +221,7 @@ static void allwinner_h3_init(Object *obj) sysbus_init_child_obj(obj, "sid", &s->sid, sizeof(s->sid), TYPE_AW_SID); object_property_add_alias(obj, "identifier", OBJECT(&s->sid), - "identifier", &error_abort); + "identifier"); sysbus_init_child_obj(obj, "mmc0", &s->mmc0, sizeof(s->mmc0), TYPE_AW_SDHOST_SUN5I); @@ -232,9 +232,9 @@ static void allwinner_h3_init(Object *obj) sysbus_init_child_obj(obj, "dramc", &s->dramc, sizeof(s->dramc), TYPE_AW_H3_DRAMC); object_property_add_alias(obj, "ram-addr", OBJECT(&s->dramc), - "ram-addr", &error_abort); + "ram-addr"); object_property_add_alias(obj, "ram-size", OBJECT(&s->dramc), - "ram-size", &error_abort); + "ram-size"); sysbus_init_child_obj(obj, "rtc", &s->rtc, sizeof(s->rtc), TYPE_AW_RTC_SUN6I); @@ -366,7 +366,7 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_MMC0)); object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->mmc0), - "sd-bus", &error_abort); + "sd-bus"); /* EMAC */ if (nd_table[0].used) { diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 7531b97ccd..7da57f56d3 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -138,7 +138,7 @@ static void armv7m_instance_init(Object *obj) sysbus_init_child_obj(obj, "nvnic", &s->nvic, sizeof(s->nvic), TYPE_NVIC); object_property_add_alias(obj, "num-irq", - OBJECT(&s->nvic), "num-irq", &error_abort); + OBJECT(&s->nvic), "num-irq"); for (i = 0; i < ARRAY_SIZE(s->bitband); i++) { sysbus_init_child_obj(obj, "bitband[*]", &s->bitband[i], diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 231527c6c8..2c23297edf 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -544,7 +544,7 @@ static void aspeed_machine_class_props_init(ObjectClass *oc) { object_class_property_add_bool(oc, "execute-in-place", aspeed_get_mmio_exec, - aspeed_set_mmio_exec, &error_abort); + aspeed_set_mmio_exec); object_class_property_set_description(oc, "execute-in-place", "boot directly from CE0 flash device"); } diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index c6e0ab84ac..71a0acfe26 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -138,11 +138,11 @@ static void aspeed_soc_ast2600_init(Object *obj) qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev); object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), - "hw-strap1", &error_abort); + "hw-strap1"); object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), - "hw-strap2", &error_abort); + "hw-strap2"); object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu), - "hw-prot-key", &error_abort); + "hw-prot-key"); sysbus_init_child_obj(obj, "a7mpcore", &s->a7mpcore, sizeof(s->a7mpcore), TYPE_A15MPCORE_PRIV); @@ -161,8 +161,7 @@ static void aspeed_soc_ast2600_init(Object *obj) snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname); sysbus_init_child_obj(obj, "fmc", OBJECT(&s->fmc), sizeof(s->fmc), typename); - object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs", - &error_abort); + object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs"); for (i = 0; i < sc->spis_num; i++) { snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i + 1, socname); @@ -179,9 +178,9 @@ static void aspeed_soc_ast2600_init(Object *obj) sysbus_init_child_obj(obj, "sdmc", OBJECT(&s->sdmc), sizeof(s->sdmc), typename); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), - "ram-size", &error_abort); + "ram-size"); object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc), - "max-ram-size", &error_abort); + "max-ram-size"); for (i = 0; i < sc->wdts_num; i++) { snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname); diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 696c7fda14..cf6b6dd116 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -153,11 +153,11 @@ static void aspeed_soc_init(Object *obj) qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev); object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), - "hw-strap1", &error_abort); + "hw-strap1"); object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), - "hw-strap2", &error_abort); + "hw-strap2"); object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu), - "hw-prot-key", &error_abort); + "hw-prot-key"); sysbus_init_child_obj(obj, "vic", OBJECT(&s->vic), sizeof(s->vic), TYPE_ASPEED_VIC); @@ -176,8 +176,7 @@ static void aspeed_soc_init(Object *obj) snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname); sysbus_init_child_obj(obj, "fmc", OBJECT(&s->fmc), sizeof(s->fmc), typename); - object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs", - &error_abort); + object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs"); for (i = 0; i < sc->spis_num; i++) { snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i + 1, socname); @@ -194,9 +193,9 @@ static void aspeed_soc_init(Object *obj) sysbus_init_child_obj(obj, "sdmc", OBJECT(&s->sdmc), sizeof(s->sdmc), typename); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), - "ram-size", &error_abort); + "ram-size"); object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc), - "max-ram-size", &error_abort); + "max-ram-size"); for (i = 0; i < sc->wdts_num; i++) { snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname); diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 8b399d67ff..f1bcc14f55 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -74,26 +74,25 @@ static void bcm2835_peripherals_init(Object *obj) TYPE_BCM2835_MBOX); object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr", - OBJECT(&s->mbox_mr), &error_abort); + OBJECT(&s->mbox_mr)); /* Framebuffer */ sysbus_init_child_obj(obj, "fb", &s->fb, sizeof(s->fb), TYPE_BCM2835_FB); - object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size", - &error_abort); + object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size"); object_property_add_const_link(OBJECT(&s->fb), "dma-mr", - OBJECT(&s->gpu_bus_mr), &error_abort); + OBJECT(&s->gpu_bus_mr)); /* Property channel */ sysbus_init_child_obj(obj, "property", &s->property, sizeof(s->property), TYPE_BCM2835_PROPERTY); object_property_add_alias(obj, "board-rev", OBJECT(&s->property), - "board-rev", &error_abort); + "board-rev"); object_property_add_const_link(OBJECT(&s->property), "fb", - OBJECT(&s->fb), &error_abort); + OBJECT(&s->fb)); object_property_add_const_link(OBJECT(&s->property), "dma-mr", - OBJECT(&s->gpu_bus_mr), &error_abort); + OBJECT(&s->gpu_bus_mr)); /* Random Number Generator */ sysbus_init_child_obj(obj, "rng", &s->rng, sizeof(s->rng), @@ -112,7 +111,7 @@ static void bcm2835_peripherals_init(Object *obj) TYPE_BCM2835_DMA); object_property_add_const_link(OBJECT(&s->dma), "dma-mr", - OBJECT(&s->gpu_bus_mr), &error_abort); + OBJECT(&s->gpu_bus_mr)); /* Thermal */ sysbus_init_child_obj(obj, "thermal", &s->thermal, sizeof(s->thermal), @@ -123,9 +122,9 @@ static void bcm2835_peripherals_init(Object *obj) TYPE_BCM2835_GPIO); object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhci", - OBJECT(&s->sdhci.sdbus), &error_abort); + OBJECT(&s->sdhci.sdbus)); object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhost", - OBJECT(&s->sdhost.sdbus), &error_abort); + OBJECT(&s->sdhost.sdbus)); } static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) @@ -359,12 +358,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(&s->peri_mr, GPIO_OFFSET, sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gpio), 0)); - object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus", - &err); - if (err) { - error_propagate(errp, err); - return; - } + object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus"); create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40); create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000); diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index 43022b83f5..e51b4e0c43 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -63,9 +63,9 @@ static void bcm2836_init(Object *obj) sysbus_init_child_obj(obj, "peripherals", &s->peripherals, sizeof(s->peripherals), TYPE_BCM2835_PERIPHERALS); object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals), - "board-rev", &error_abort); + "board-rev"); object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals), - "vcram-size", &error_abort); + "vcram-size"); } static void bcm2836_realize(DeviceState *dev, Error **errp) @@ -86,11 +86,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) return; } - object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err); - if (err) { - error_propagate(errp, err); - return; - } + object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj); object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err); if (err) { @@ -99,11 +95,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) } object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals), - "sd-bus", &err); - if (err) { - error_propagate(errp, err); - return; - } + "sd-bus"); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0, info->peri_base, 1); diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 0b8ba44976..cd1b6d3e19 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -59,8 +59,7 @@ static void cubieboard_init(MachineState *machine) } a10 = AW_A10(object_new(TYPE_AW_A10)); - object_property_add_child(OBJECT(machine), "soc", OBJECT(a10), - &error_abort); + object_property_add_child(OBJECT(machine), "soc", OBJECT(a10)); object_unref(OBJECT(a10)); object_property_set_int(OBJECT(&a10->emac), 1, "phy-addr", &err); diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c index 23a71ed378..5b5f23a6d4 100644 --- a/hw/arm/mcimx6ul-evk.c +++ b/hw/arm/mcimx6ul-evk.c @@ -39,7 +39,7 @@ static void mcimx6ul_evk_init(MachineState *machine) }; s = FSL_IMX6UL(object_new(TYPE_FSL_IMX6UL)); - object_property_add_child(OBJECT(machine), "soc", OBJECT(s), &error_fatal); + object_property_add_child(OBJECT(machine), "soc", OBJECT(s)); object_property_set_bool(OBJECT(s), true, "realized", &error_fatal); memory_region_add_subregion(get_system_memory(), FSL_IMX6UL_MMDC_ADDR, diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c index de1e264217..3851cd9e3e 100644 --- a/hw/arm/mcimx7d-sabre.c +++ b/hw/arm/mcimx7d-sabre.c @@ -41,7 +41,7 @@ static void mcimx7d_sabre_init(MachineState *machine) }; s = FSL_IMX7(object_new(TYPE_FSL_IMX7)); - object_property_add_child(OBJECT(machine), "soc", OBJECT(s), &error_fatal); + object_property_add_child(OBJECT(machine), "soc", OBJECT(s)); object_property_set_bool(OBJECT(s), true, "realized", &error_fatal); memory_region_add_subregion(get_system_memory(), FSL_IMX7_MMDC_ADDR, diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index a455b8831f..f4579e5a08 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -197,8 +197,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) /* Alias controller SPI bus to the SoC itself */ bus_name = g_strdup_printf("spi%d", i); object_property_add_alias(OBJECT(s), bus_name, - OBJECT(&s->spi[i]), "spi", - &error_abort); + OBJECT(&s->spi[i]), "spi"); g_free(bus_name); } diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index 71309e53cc..fe126581e4 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -197,8 +197,7 @@ static void nrf51_soc_init(Object *obj) sysbus_init_child_obj(obj, "uart", &s->uart, sizeof(s->uart), TYPE_NRF51_UART); - object_property_add_alias(obj, "serial0", OBJECT(&s->uart), "chardev", - &error_abort); + object_property_add_alias(obj, "serial0", OBJECT(&s->uart), "chardev"); sysbus_init_child_obj(obj, "rng", &s->rng, sizeof(s->rng), TYPE_NRF51_RNG); diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c index a9f64c5680..b291715f27 100644 --- a/hw/arm/orangepi.c +++ b/hw/arm/orangepi.c @@ -59,8 +59,7 @@ static void orangepi_init(MachineState *machine) } h3 = AW_H3(object_new(TYPE_AW_H3)); - object_property_add_child(OBJECT(machine), "soc", OBJECT(h3), - &error_abort); + object_property_add_child(OBJECT(machine), "soc", OBJECT(h3)); object_unref(OBJECT(h3)); /* Setup timer properties */ diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index fe3b9bc78b..a2efe0b94d 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -284,8 +284,7 @@ static void raspi_machine_init(MachineState *machine) /* Setup the SOC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), board_soc_type(board_rev), &error_abort, NULL); - object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(machine->ram), - &error_abort); + object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(machine->ram)); object_property_set_int(OBJECT(&s->soc), board_rev, "board-rev", &error_abort); object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort); diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index e31694bb92..6f0e233d77 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -51,7 +51,7 @@ static void sabrelite_init(MachineState *machine) } s = FSL_IMX6(object_new(TYPE_FSL_IMX6)); - object_property_add_child(OBJECT(machine), "soc", OBJECT(s), &error_fatal); + object_property_add_child(OBJECT(machine), "soc", OBJECT(s)); object_property_set_bool(OBJECT(s), true, "realized", &err); if (err != NULL) { error_report("%s", error_get_pretty(err)); diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 8409ba853d..a6cdb4fb7b 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -222,10 +222,9 @@ static PFlashCFI01 *sbsa_flash_create1(SBSAMachineState *sms, qdev_prop_set_uint16(dev, "id2", 0x00); qdev_prop_set_uint16(dev, "id3", 0x00); qdev_prop_set_string(dev, "name", name); - object_property_add_child(OBJECT(sms), name, OBJECT(dev), - &error_abort); + object_property_add_child(OBJECT(sms), name, OBJECT(dev)); object_property_add_alias(OBJECT(sms), alias_prop_name, - OBJECT(dev), "drive", &error_abort); + OBJECT(dev), "drive"); return PFLASH_CFI01(dev); } diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 5372ab6c9b..69ee4988f9 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -749,7 +749,7 @@ static void vexpress_instance_init(Object *obj) /* EL3 is enabled by default on vexpress */ vms->secure = true; object_property_add_bool(obj, "secure", vexpress_get_secure, - vexpress_set_secure, NULL); + vexpress_set_secure); object_property_set_description(obj, "secure", "Set on/off to enable/disable the ARM " "Security Extensions (TrustZone)"); @@ -765,7 +765,7 @@ static void vexpress_a15_instance_init(Object *obj) */ vms->virt = true; object_property_add_bool(obj, "virtualization", vexpress_get_virt, - vexpress_set_virt, NULL); + vexpress_set_virt); object_property_set_description(obj, "virtualization", "Set on/off to enable/disable the ARM " "Virtualization Extensions " diff --git a/hw/arm/virt.c b/hw/arm/virt.c index de66def51e..c41d5f9778 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -959,10 +959,9 @@ static PFlashCFI01 *virt_flash_create1(VirtMachineState *vms, qdev_prop_set_uint16(dev, "id2", 0x00); qdev_prop_set_uint16(dev, "id3", 0x00); qdev_prop_set_string(dev, "name", name); - object_property_add_child(OBJECT(vms), name, OBJECT(dev), - &error_abort); + object_property_add_child(OBJECT(vms), name, OBJECT(dev)); object_property_add_alias(OBJECT(vms), alias_prop_name, - OBJECT(dev), "drive", &error_abort); + OBJECT(dev), "drive"); return PFLASH_CFI01(dev); } @@ -2270,7 +2269,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) object_class_property_add(oc, "acpi", "OnOffAuto", virt_get_acpi, virt_set_acpi, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, "acpi", "Enable ACPI"); } @@ -2286,7 +2285,7 @@ static void virt_instance_init(Object *obj) */ vms->secure = false; object_property_add_bool(obj, "secure", virt_get_secure, - virt_set_secure, NULL); + virt_set_secure); object_property_set_description(obj, "secure", "Set on/off to enable/disable the ARM " "Security Extensions (TrustZone)"); @@ -2294,7 +2293,7 @@ static void virt_instance_init(Object *obj) /* EL2 is also disabled by default, for similar reasons */ vms->virt = false; object_property_add_bool(obj, "virtualization", virt_get_virt, - virt_set_virt, NULL); + virt_set_virt); object_property_set_description(obj, "virtualization", "Set on/off to enable/disable emulating a " "guest CPU which implements the ARM " @@ -2303,13 +2302,13 @@ static void virt_instance_init(Object *obj) /* High memory is enabled by default */ vms->highmem = true; object_property_add_bool(obj, "highmem", virt_get_highmem, - virt_set_highmem, NULL); + virt_set_highmem); object_property_set_description(obj, "highmem", "Set on/off to enable/disable using " "physical address space above 32 bits"); vms->gic_version = VIRT_GIC_VERSION_NOSEL; object_property_add_str(obj, "gic-version", virt_get_gic_version, - virt_set_gic_version, NULL); + virt_set_gic_version); object_property_set_description(obj, "gic-version", "Set GIC version. " "Valid values are 2, 3, host and max"); @@ -2322,7 +2321,7 @@ static void virt_instance_init(Object *obj) /* Default allows ITS instantiation */ vms->its = true; object_property_add_bool(obj, "its", virt_get_its, - virt_set_its, NULL); + virt_set_its); object_property_set_description(obj, "its", "Set on/off to enable/disable " "ITS instantiation"); @@ -2330,7 +2329,7 @@ static void virt_instance_init(Object *obj) /* Default disallows iommu instantiation */ vms->iommu = VIRT_IOMMU_NONE; - object_property_add_str(obj, "iommu", virt_get_iommu, virt_set_iommu, NULL); + object_property_add_str(obj, "iommu", virt_get_iommu, virt_set_iommu); object_property_set_description(obj, "iommu", "Set the IOMMU type. " "Valid values are none and smmuv3"); @@ -2338,7 +2337,7 @@ static void virt_instance_init(Object *obj) /* Default disallows RAS instantiation */ vms->ras = false; object_property_add_bool(obj, "ras", virt_get_ras, - virt_set_ras, NULL); + virt_set_ras); object_property_set_description(obj, "ras", "Set on/off to enable/disable reporting host memory errors " "to a KVM guest using ACPI and guest external abort exceptions"); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 91b498dd5d..cb933efb49 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -229,7 +229,7 @@ static void zynq_init(MachineState *machine) /* Create the main clock source, and feed slcr with it */ zynq_machine->ps_clk = CLOCK(object_new(TYPE_CLOCK)); object_property_add_child(OBJECT(zynq_machine), "ps_clk", - OBJECT(zynq_machine->ps_clk), &error_abort); + OBJECT(zynq_machine->ps_clk)); object_unref(OBJECT(zynq_machine->ps_clk)); clock_set_hz(zynq_machine->ps_clk, PS_CLK_FREQUENCY); qdev_connect_clock_in(slcr, "ps_clk", zynq_machine->ps_clk); diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 7e749e1926..43a71e2eea 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -433,8 +433,7 @@ static void create_virtio_regions(VersalVirt *s) pic_irq = qdev_get_gpio_in(DEVICE(&s->soc.fpd.apu.gic), irq); dev = qdev_create(NULL, "virtio-mmio"); - object_property_add_child(OBJECT(&s->soc), name, OBJECT(dev), - &error_fatal); + object_property_add_child(OBJECT(&s->soc), name, OBJECT(dev)); qdev_init_nofail(dev); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic_irq); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); @@ -465,8 +464,7 @@ static void sd_plugin_card(SDHCIState *sd, DriveInfo *di) DeviceState *card; card = qdev_create(qdev_get_child_bus(DEVICE(sd), "sd-bus"), TYPE_SD_CARD); - object_property_add_child(OBJECT(sd), "card[*]", OBJECT(card), - &error_fatal); + object_property_add_child(OBJECT(sd), "card[*]", OBJECT(card)); qdev_prop_set_drive(card, "drive", blk, &error_fatal); object_property_set_bool(OBJECT(card), true, "realized", &error_fatal); } diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 321171bcce..809a31390f 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -309,7 +309,7 @@ static void versal_unimp_area(Versal *s, const char *name, qdev_prop_set_string(dev, "name", name); qdev_prop_set_uint64(dev, "size", size); - object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal); + object_property_add_child(OBJECT(s), name, OBJECT(dev)); qdev_init_nofail(dev); mr_dev = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 808fdae804..b01e575b58 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -209,7 +209,7 @@ static void xlnx_zcu102_machine_instance_init(Object *obj) /* Default to secure mode being disabled */ s->secure = false; object_property_add_bool(obj, "secure", zcu102_get_secure, - zcu102_set_secure, NULL); + zcu102_set_secure); object_property_set_description(obj, "secure", "Set on/off to enable/disable the ARM " "Security Extensions (TrustZone)"); @@ -217,7 +217,7 @@ static void xlnx_zcu102_machine_instance_init(Object *obj) /* Default to virt (EL2) being disabled */ s->virt = false; object_property_add_bool(obj, "virtualization", zcu102_get_virt, - zcu102_set_virt, NULL); + zcu102_set_virt); object_property_set_description(obj, "virtualization", "Set on/off to enable/disable emulating a " "guest CPU which implements the ARM " diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index b84d153d56..f08abf60d7 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -554,8 +554,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) /* Alias controller SD bus to the SoC itself */ bus_name = g_strdup_printf("sd-bus%d", i); - object_property_add_alias(OBJECT(s), bus_name, sdhci, "sd-bus", - &error_abort); + object_property_add_alias(OBJECT(s), bus_name, sdhci, "sd-bus"); g_free(bus_name); } @@ -575,8 +574,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) /* Alias controller SPI bus to the SoC itself */ bus_name = g_strdup_printf("spi%d", i); object_property_add_alias(OBJECT(s), bus_name, - OBJECT(&s->spi[i]), "spi0", - &error_abort); + OBJECT(&s->spi[i]), "spi0"); g_free(bus_name); } @@ -597,8 +595,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) bus_name = g_strdup_printf("qspi%d", i); target_bus = g_strdup_printf("spi%d", i); object_property_add_alias(OBJECT(s), bus_name, - OBJECT(&s->qspi), target_bus, - &error_abort); + OBJECT(&s->qspi), target_bus); g_free(bus_name); g_free(target_bus); } diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c index 883ef74c8b..8dfacec693 100644 --- a/hw/audio/marvell_88w8618.c +++ b/hw/audio/marvell_88w8618.c @@ -259,7 +259,7 @@ static void mv88w8618_audio_init(Object *obj) object_property_add_link(OBJECT(dev), "wm8750", TYPE_WM8750, (Object **) &s->wm, qdev_prop_allow_set_link_before_realize, - 0, &error_abort); + 0); } static void mv88w8618_audio_realize(DeviceState *dev, Error **errp) diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index 29dc00bf8d..c37a387861 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -175,7 +175,7 @@ static void pcspk_initfn(Object *obj) object_property_add_link(obj, "pit", TYPE_PIT_COMMON, (Object **)&s->pit, qdev_prop_allow_set_link_before_realize, - 0, &error_abort); + 0); } static void pcspk_realizefn(DeviceState *dev, Error **errp) diff --git a/hw/core/bus.c b/hw/core/bus.c index 3dc0a825f0..4a57ae107e 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -122,7 +122,7 @@ static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) if (bus->parent) { QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); bus->parent->num_child_bus++; - object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); + object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus)); object_unref(OBJECT(bus)); } else { /* The only bus without a parent is the main system bus */ @@ -215,10 +215,9 @@ static void qbus_initfn(Object *obj) TYPE_HOTPLUG_HANDLER, (Object **)&bus->hotplug_handler, object_property_allow_set_link, - 0, - NULL); + 0); object_property_add_bool(obj, "realized", - bus_get_realized, bus_set_realized, NULL); + bus_get_realized, bus_set_realized); } static char *default_bus_get_fw_dev_path(DeviceState *dev) diff --git a/hw/core/machine.c b/hw/core/machine.c index 0cd2033b1f..bb3a7b18b1 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -787,82 +787,78 @@ static void machine_class_init(ObjectClass *oc, void *data) mc->numa_auto_assign_ram = numa_default_auto_assign_ram; object_class_property_add_str(oc, "kernel", - machine_get_kernel, machine_set_kernel, &error_abort); + machine_get_kernel, machine_set_kernel); object_class_property_set_description(oc, "kernel", "Linux kernel image file"); object_class_property_add_str(oc, "initrd", - machine_get_initrd, machine_set_initrd, &error_abort); + machine_get_initrd, machine_set_initrd); object_class_property_set_description(oc, "initrd", "Linux initial ramdisk file"); object_class_property_add_str(oc, "append", - machine_get_append, machine_set_append, &error_abort); + machine_get_append, machine_set_append); object_class_property_set_description(oc, "append", "Linux kernel command line"); object_class_property_add_str(oc, "dtb", - machine_get_dtb, machine_set_dtb, &error_abort); + machine_get_dtb, machine_set_dtb); object_class_property_set_description(oc, "dtb", "Linux kernel device tree file"); object_class_property_add_str(oc, "dumpdtb", - machine_get_dumpdtb, machine_set_dumpdtb, &error_abort); + machine_get_dumpdtb, machine_set_dumpdtb); object_class_property_set_description(oc, "dumpdtb", "Dump current dtb to a file and quit"); object_class_property_add(oc, "phandle-start", "int", machine_get_phandle_start, machine_set_phandle_start, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, "phandle-start", "The first phandle ID we may generate dynamically"); object_class_property_add_str(oc, "dt-compatible", - machine_get_dt_compatible, machine_set_dt_compatible, &error_abort); + machine_get_dt_compatible, machine_set_dt_compatible); object_class_property_set_description(oc, "dt-compatible", "Overrides the \"compatible\" property of the dt root node"); object_class_property_add_bool(oc, "dump-guest-core", - machine_get_dump_guest_core, machine_set_dump_guest_core, &error_abort); + machine_get_dump_guest_core, machine_set_dump_guest_core); object_class_property_set_description(oc, "dump-guest-core", "Include guest memory in a core dump"); object_class_property_add_bool(oc, "mem-merge", - machine_get_mem_merge, machine_set_mem_merge, &error_abort); + machine_get_mem_merge, machine_set_mem_merge); object_class_property_set_description(oc, "mem-merge", "Enable/disable memory merge support"); object_class_property_add_bool(oc, "usb", - machine_get_usb, machine_set_usb, &error_abort); + machine_get_usb, machine_set_usb); object_class_property_set_description(oc, "usb", "Set on/off to enable/disable usb"); object_class_property_add_bool(oc, "graphics", - machine_get_graphics, machine_set_graphics, &error_abort); + machine_get_graphics, machine_set_graphics); object_class_property_set_description(oc, "graphics", "Set on/off to enable/disable graphics emulation"); object_class_property_add_str(oc, "firmware", - machine_get_firmware, machine_set_firmware, - &error_abort); + machine_get_firmware, machine_set_firmware); object_class_property_set_description(oc, "firmware", "Firmware image"); object_class_property_add_bool(oc, "suppress-vmdesc", - machine_get_suppress_vmdesc, machine_set_suppress_vmdesc, - &error_abort); + machine_get_suppress_vmdesc, machine_set_suppress_vmdesc); object_class_property_set_description(oc, "suppress-vmdesc", "Set on to disable self-describing migration"); object_class_property_add_bool(oc, "enforce-config-section", - machine_get_enforce_config_section, machine_set_enforce_config_section, - &error_abort); + machine_get_enforce_config_section, machine_set_enforce_config_section); object_class_property_set_description(oc, "enforce-config-section", "Set on to enforce configuration section migration"); object_class_property_add_str(oc, "memory-encryption", - machine_get_memory_encryption, machine_set_memory_encryption, - &error_abort); + machine_get_memory_encryption, machine_set_memory_encryption); object_class_property_set_description(oc, "memory-encryption", "Set memory encryption object to use"); } @@ -893,16 +889,14 @@ static void machine_initfn(Object *obj) ms->nvdimms_state = g_new0(NVDIMMState, 1); object_property_add_bool(obj, "nvdimm", - machine_get_nvdimm, machine_set_nvdimm, - &error_abort); + machine_get_nvdimm, machine_set_nvdimm); object_property_set_description(obj, "nvdimm", "Set on/off to enable/disable " "NVDIMM instantiation"); object_property_add_str(obj, "nvdimm-persistence", machine_get_nvdimm_persistence, - machine_set_nvdimm_persistence, - &error_abort); + machine_set_nvdimm_persistence); object_property_set_description(obj, "nvdimm-persistence", "Set NVDIMM persistence" "Valid values are cpu, mem-ctrl"); @@ -911,8 +905,7 @@ static void machine_initfn(Object *obj) if (mc->cpu_index_to_instance_props && mc->get_default_cpu_node_id) { ms->numa_state = g_new0(NumaState, 1); object_property_add_bool(obj, "hmat", - machine_get_hmat, machine_set_hmat, - &error_abort); + machine_get_hmat, machine_set_hmat); object_property_set_description(obj, "hmat", "Set on/off to enable/disable " "ACPI Heterogeneous Memory Attribute " @@ -920,8 +913,7 @@ static void machine_initfn(Object *obj) } object_property_add_str(obj, "memory-backend", - machine_get_memdev, machine_set_memdev, - &error_abort); + machine_get_memdev, machine_set_memdev); object_property_set_description(obj, "memory-backend", "Set RAM backend" "Valid value is ID of hostmem based backend"); diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c index a94cc44437..5cc1e82e51 100644 --- a/hw/core/qdev-clock.c +++ b/hw/core/qdev-clock.c @@ -46,7 +46,7 @@ static NamedClockList *qdev_init_clocklist(DeviceState *dev, const char *name, */ if (clk == NULL) { clk = CLOCK(object_new(TYPE_CLOCK)); - object_property_add_child(OBJECT(dev), name, OBJECT(clk), &error_abort); + object_property_add_child(OBJECT(dev), name, OBJECT(clk)); if (output) { /* * Remove object_new()'s initial reference. @@ -59,7 +59,7 @@ static NamedClockList *qdev_init_clocklist(DeviceState *dev, const char *name, object_property_add_link(OBJECT(dev), name, object_get_typename(OBJECT(clk)), (Object **) &ncl->clock, - NULL, OBJ_PROP_LINK_STRONG, &error_abort); + NULL, OBJ_PROP_LINK_STRONG); } ncl->clock = clk; diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 2047114fca..2f294ec4a4 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -1043,11 +1043,7 @@ static void set_prop_arraylen(Object *obj, Visitor *v, const char *name, arrayprop->prop.info->get, arrayprop->prop.info->set, array_element_release, - arrayprop, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + arrayprop); } } @@ -1259,8 +1255,7 @@ static void create_link_property(ObjectClass *oc, Property *prop, Error **errp) object_class_property_add_link(oc, prop->name, prop->link_type, prop->offset, qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG, - errp); + OBJ_PROP_LINK_STRONG); } const PropertyInfo qdev_prop_link = { diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 2e6c29ba78..3f91bff712 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -91,8 +91,7 @@ static void bus_add_child(BusState *bus, DeviceState *child) object_get_typename(OBJECT(child)), (Object **)&kid->child, NULL, /* read-only property */ - 0, /* return ownership on prop deletion */ - NULL); + 0); } void qdev_set_parent_bus(DeviceState *dev, BusState *bus) @@ -481,7 +480,7 @@ void qdev_init_gpio_in_named_with_opaque(DeviceState *dev, gchar *propname = g_strdup_printf("%s[%u]", name, i); object_property_add_child(OBJECT(dev), propname, - OBJECT(gpio_list->in[i]), &error_abort); + OBJECT(gpio_list->in[i])); g_free(propname); } @@ -512,8 +511,7 @@ void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins, object_property_add_link(OBJECT(dev), propname, TYPE_IRQ, (Object **)&pins[i], object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); g_free(propname); } gpio_list->num_out += n; @@ -546,8 +544,7 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, /* We need a name for object_property_set_link to work */ object_property_add_child(container_get(qdev_get_machine(), "/unattached"), - "non-qdev-gpio[*]", OBJECT(pin), - &error_abort); + "non-qdev-gpio[*]", OBJECT(pin)); } object_property_set_link(OBJECT(dev), OBJECT(pin), propname, &error_abort); g_free(propname); @@ -605,8 +602,7 @@ void qdev_pass_gpios(DeviceState *dev, DeviceState *container, char *propname = g_strdup_printf("%s[%d]", nm, i); object_property_add_alias(OBJECT(container), propname, - OBJECT(dev), propname, - &error_abort); + OBJECT(dev), propname); g_free(propname); } for (i = 0; i < ngl->num_out; i++) { @@ -614,8 +610,7 @@ void qdev_pass_gpios(DeviceState *dev, DeviceState *container, char *propname = g_strdup_printf("%s[%d]", nm, i); object_property_add_alias(OBJECT(container), propname, - OBJECT(dev), propname, - &error_abort); + OBJECT(dev), propname); g_free(propname); } QLIST_REMOVE(ngl, node); @@ -756,7 +751,7 @@ static void qdev_class_add_legacy_property(DeviceClass *dc, Property *prop) name = g_strdup_printf("legacy-%s", prop->name); object_class_property_add(OBJECT_CLASS(dc), name, "str", prop->info->print ? qdev_get_legacy_property : prop->info->get, - NULL, NULL, prop, &error_abort); + NULL, NULL, prop); } void qdev_property_add_static(DeviceState *dev, Property *prop) @@ -769,7 +764,7 @@ void qdev_property_add_static(DeviceState *dev, Property *prop) op = object_property_add(obj, prop->name, prop->info->name, prop->info->get, prop->info->set, prop->info->release, - prop, &error_abort); + prop); object_property_set_description(obj, prop->name, prop->info->description); @@ -795,7 +790,7 @@ static void qdev_class_add_property(DeviceClass *klass, Property *prop) prop->name, prop->info->name, prop->info->get, prop->info->set, prop->info->release, - prop, &error_abort); + prop); if (prop->set_default) { prop->info->set_default_value(op, prop); } @@ -818,8 +813,7 @@ void qdev_alias_all_properties(DeviceState *target, Object *source) for (prop = dc->props_; prop && prop->name; prop++) { object_property_add_alias(source, prop->name, - OBJECT(target), prop->name, - &error_abort); + OBJECT(target), prop->name); } class = object_class_get_parent(class); } while (class != object_class_by_name(TYPE_DEVICE)); @@ -871,7 +865,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) object_property_add_child(container_get(qdev_get_machine(), "/unattached"), - name, obj, &error_abort); + name, obj); unattached_parent = true; g_free(name); } @@ -1198,17 +1192,13 @@ static void device_class_init(ObjectClass *class, void *data) rc->get_transitional_function = device_get_transitional_reset; object_class_property_add_bool(class, "realized", - device_get_realized, device_set_realized, - &error_abort); + device_get_realized, device_set_realized); object_class_property_add_bool(class, "hotpluggable", - device_get_hotpluggable, NULL, - &error_abort); + device_get_hotpluggable, NULL); object_class_property_add_bool(class, "hotplugged", - device_get_hotplugged, NULL, - &error_abort); + device_get_hotplugged, NULL); object_class_property_add_link(class, "parent_bus", TYPE_BUS, - offsetof(DeviceState, parent_bus), NULL, 0, - &error_abort); + offsetof(DeviceState, parent_bus), NULL, 0); } void device_class_set_props(DeviceClass *dc, Property *props) diff --git a/hw/cpu/core.c b/hw/cpu/core.c index 9874c5c870..a92ac597ca 100644 --- a/hw/cpu/core.c +++ b/hw/cpu/core.c @@ -76,9 +76,9 @@ static void cpu_core_instance_init(Object *obj) CPUCore *core = CPU_CORE(obj); object_property_add(obj, "core-id", "int", core_prop_get_core_id, - core_prop_set_core_id, NULL, NULL, NULL); + core_prop_set_core_id, NULL, NULL); object_property_add(obj, "nr-threads", "int", core_prop_get_nr_threads, - core_prop_set_nr_threads, NULL, NULL, NULL); + core_prop_set_nr_threads, NULL, NULL); core->nr_threads = ms->smp.threads; } diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c index e763a0a72d..a8e8ab8325 100644 --- a/hw/display/bochs-display.c +++ b/hw/display/bochs-display.c @@ -333,8 +333,7 @@ static void bochs_display_init(Object *obj) /* Expose framebuffer byteorder via QOM */ object_property_add_bool(obj, "big-endian-framebuffer", bochs_display_get_big_endian_fb, - bochs_display_set_big_endian_fb, - NULL); + bochs_display_set_big_endian_fb); dev->cap_present |= QEMU_PCI_CAP_EXPRESS; } diff --git a/hw/display/sm501.c b/hw/display/sm501.c index de0ab9d977..296cd56c4a 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -2011,7 +2011,7 @@ static void sm501_sysbus_init(Object *o) qdev_prop_set_uint8(DEVICE(smm), "endianness", DEVICE_LITTLE_ENDIAN); object_property_add_alias(o, "chardev", - OBJECT(smm), "chardev", &error_abort); + OBJECT(smm), "chardev"); } static const TypeInfo sm501_sysbus_info = { diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index 6b9db86e36..a640fd866d 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -270,7 +270,7 @@ static void pci_std_vga_init(Object *obj) { /* Expose framebuffer byteorder via QOM */ object_property_add_bool(obj, "big-endian-framebuffer", - vga_get_big_endian_fb, vga_set_big_endian_fb, NULL); + vga_get_big_endian_fb, vga_set_big_endian_fb); } static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp) @@ -321,7 +321,7 @@ static void pci_secondary_vga_init(Object *obj) { /* Expose framebuffer byteorder via QOM */ object_property_add_bool(obj, "big-endian-framebuffer", - vga_get_big_endian_fb, vga_set_big_endian_fb, NULL); + vga_get_big_endian_fb, vga_set_big_endian_fb); } static void pci_secondary_vga_reset(DeviceState *dev) diff --git a/hw/display/vhost-user-gpu-pci.c b/hw/display/vhost-user-gpu-pci.c index 7d9b1f5a8c..23ce655e0f 100644 --- a/hw/display/vhost-user-gpu-pci.c +++ b/hw/display/vhost-user-gpu-pci.c @@ -32,8 +32,7 @@ static void vhost_user_gpu_pci_initfn(Object *obj) VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); object_property_add_alias(obj, "chardev", - OBJECT(&dev->vdev), "chardev", - &error_abort); + OBJECT(&dev->vdev), "chardev"); } static const VirtioPCIDeviceTypeInfo vhost_user_gpu_pci_info = { diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index f0c7c6fb9a..4cdaee1bde 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -512,7 +512,7 @@ vhost_user_gpu_instance_init(Object *obj) g->vhost = VHOST_USER_BACKEND(object_new(TYPE_VHOST_USER_BACKEND)); object_property_add_alias(obj, "chardev", - OBJECT(g->vhost), "chardev", &error_abort); + OBJECT(g->vhost), "chardev"); } static void diff --git a/hw/display/vhost-user-vga.c b/hw/display/vhost-user-vga.c index a7195276d9..1690f6b610 100644 --- a/hw/display/vhost-user-vga.c +++ b/hw/display/vhost-user-vga.c @@ -33,8 +33,7 @@ static void vhost_user_vga_inst_initfn(Object *obj) VIRTIO_VGA_BASE(dev)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); object_property_add_alias(obj, "chardev", - OBJECT(&dev->vdev), "chardev", - &error_abort); + OBJECT(&dev->vdev), "chardev"); } static const VirtioPCIDeviceTypeInfo vhost_user_vga_info = { diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 7058443797..3e5fb44e06 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1237,8 +1237,7 @@ static void xlnx_dp_init(Object *obj) object_property_add_link(obj, "dpdma", TYPE_XLNX_DPDMA, (Object **) &s->dpdma, xlnx_dp_set_dpdma, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); /* * Initialize AUX Bus. @@ -1249,11 +1248,11 @@ static void xlnx_dp_init(Object *obj) * Initialize DPCD and EDID.. */ s->dpcd = DPCD(aux_create_slave(s->aux_bus, "dpcd")); - object_property_add_child(OBJECT(s), "dpcd", OBJECT(s->dpcd), NULL); + object_property_add_child(OBJECT(s), "dpcd", OBJECT(s->dpcd)); s->edid = I2CDDC(qdev_create(BUS(aux_get_i2c_bus(s->aux_bus)), "i2c-ddc")); i2c_set_slave_address(I2C_SLAVE(s->edid), 0x50); - object_property_add_child(OBJECT(s), "edid", OBJECT(s->edid), NULL); + object_property_add_child(OBJECT(s), "edid", OBJECT(s->edid)); fifo8_create(&s->rx_fifo, 16); fifo8_create(&s->tx_fifo, 16); diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index 3e4da0c47f..84b9c5dc77 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -264,7 +264,7 @@ static void sparc32_dma_device_init(Object *obj) object_property_add_link(OBJECT(dev), "iommu", TYPE_SUN4M_IOMMU, (Object **) &s->iommu, qdev_prop_allow_set_link_before_realize, - 0, NULL); + 0); qdev_init_gpio_in(dev, dma_set_irq, 1); qdev_init_gpio_out(dev, s->gpio, 2); @@ -302,7 +302,7 @@ static void sparc32_espdma_device_realize(DeviceState *dev, Error **errp) ESPState *esp; d = qdev_create(NULL, TYPE_ESP); - object_property_add_child(OBJECT(dev), "esp", OBJECT(d), errp); + object_property_add_child(OBJECT(dev), "esp", OBJECT(d)); sysbus = ESP_STATE(d); esp = &sysbus->esp; esp->dma_memory_read = espdma_memory_read; @@ -344,7 +344,7 @@ static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp) qemu_check_nic_model(nd, TYPE_LANCE); d = qdev_create(NULL, TYPE_LANCE); - object_property_add_child(OBJECT(dev), "lance", OBJECT(d), errp); + object_property_add_child(OBJECT(dev), "lance", OBJECT(d)); qdev_set_nic_properties(d, nd); object_property_set_link(OBJECT(d), OBJECT(dev), "dma", errp); qdev_init_nofail(d); @@ -380,7 +380,7 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) espdma = qdev_create(NULL, TYPE_SPARC32_ESPDMA_DEVICE); object_property_set_link(OBJECT(espdma), iommu, "iommu", errp); - object_property_add_child(OBJECT(s), "espdma", OBJECT(espdma), errp); + object_property_add_child(OBJECT(s), "espdma", OBJECT(espdma)); qdev_init_nofail(espdma); esp = DEVICE(object_resolve_path_component(OBJECT(espdma), "esp")); @@ -395,7 +395,7 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) ledma = qdev_create(NULL, TYPE_SPARC32_LEDMA_DEVICE); object_property_set_link(OBJECT(ledma), iommu, "iommu", errp); - object_property_add_child(OBJECT(s), "ledma", OBJECT(ledma), errp); + object_property_add_child(OBJECT(s), "ledma", OBJECT(ledma)); qdev_init_nofail(ledma); lance = DEVICE(object_resolve_path_component(OBJECT(ledma), "lance")); diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 87be9cade7..460102b142 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -543,16 +543,11 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA, (Object **)&ds->dma, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, - &local_err); + OBJ_PROP_LINK_STRONG); object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA, (Object **)&cs->dma, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, - &local_err); - if (local_err) { - goto xilinx_axidma_realize_fail; - } + OBJ_PROP_LINK_STRONG); object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_err); object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_err); if (local_err) { @@ -594,8 +589,7 @@ static void xilinx_axidma_init(Object *obj) object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, (Object **)&s->dma_mr, qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); sysbus_init_irq(sbd, &s->streams[0].irq); sysbus_init_irq(sbd, &s->streams[1].irq); diff --git a/hw/dma/xlnx-zdma.c b/hw/dma/xlnx-zdma.c index 2dec4a2643..fa38a55634 100644 --- a/hw/dma/xlnx-zdma.c +++ b/hw/dma/xlnx-zdma.c @@ -799,8 +799,7 @@ static void zdma_init(Object *obj) object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, (Object **)&s->dma_mr, qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); } static const VMStateDescription vmstate_zdma = { diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index 4c75b5c80c..dfa9db3d33 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -873,7 +873,7 @@ static void aspeed_gpio_init(Object *obj) name = g_strdup_printf("gpio%s%d", props->group_label[group_idx], pin_idx % GPIOS_PER_GROUP); object_property_add(obj, name, "bool", aspeed_gpio_get_pin, - aspeed_gpio_set_pin, NULL, NULL, NULL); + aspeed_gpio_set_pin, NULL, NULL); g_free(name); } } diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index 4ddafe1de1..4b11f7a76b 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -131,7 +131,7 @@ void hyperv_synic_add(CPUState *cs) obj = object_new(TYPE_SYNIC); synic = SYNIC(obj); synic->cs = cs; - object_property_add_child(OBJECT(cs), "synic", obj, &error_abort); + object_property_add_child(OBJECT(cs), "synic", obj); object_unref(obj); object_property_set_bool(obj, true, "realized", &error_abort); } diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 76aaa7a8d8..937db10ae6 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -510,42 +510,39 @@ static void microvm_class_init(ObjectClass *oc, void *data) object_class_property_add(oc, MICROVM_MACHINE_PIC, "OnOffAuto", microvm_machine_get_pic, microvm_machine_set_pic, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, MICROVM_MACHINE_PIC, "Enable i8259 PIC"); object_class_property_add(oc, MICROVM_MACHINE_PIT, "OnOffAuto", microvm_machine_get_pit, microvm_machine_set_pit, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, MICROVM_MACHINE_PIT, "Enable i8254 PIT"); object_class_property_add(oc, MICROVM_MACHINE_RTC, "OnOffAuto", microvm_machine_get_rtc, microvm_machine_set_rtc, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, MICROVM_MACHINE_RTC, "Enable MC146818 RTC"); object_class_property_add_bool(oc, MICROVM_MACHINE_ISA_SERIAL, microvm_machine_get_isa_serial, - microvm_machine_set_isa_serial, - &error_abort); + microvm_machine_set_isa_serial); object_class_property_set_description(oc, MICROVM_MACHINE_ISA_SERIAL, "Set off to disable the instantiation an ISA serial port"); object_class_property_add_bool(oc, MICROVM_MACHINE_OPTION_ROMS, microvm_machine_get_option_roms, - microvm_machine_set_option_roms, - &error_abort); + microvm_machine_set_option_roms); object_class_property_set_description(oc, MICROVM_MACHINE_OPTION_ROMS, "Set off to disable loading option ROMs"); object_class_property_add_bool(oc, MICROVM_MACHINE_AUTO_KERNEL_CMDLINE, microvm_machine_get_auto_kernel_cmdline, - microvm_machine_set_auto_kernel_cmdline, - &error_abort); + microvm_machine_set_auto_kernel_cmdline); object_class_property_set_description(oc, MICROVM_MACHINE_AUTO_KERNEL_CMDLINE, "Set off to disable adding virtio-mmio devices to the kernel cmdline"); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 21d4a8ec3a..33cf14363a 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -662,7 +662,7 @@ void pc_cmos_init(PCMachineState *pcms, TYPE_ISA_DEVICE, (Object **)&x86ms->rtc, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, &error_abort); + OBJ_PROP_LINK_STRONG); object_property_set_link(OBJECT(pcms), OBJECT(s), "rtc_state", &error_abort); @@ -1965,22 +1965,22 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) object_class_property_add(oc, PC_MACHINE_DEVMEM_REGION_SIZE, "int", pc_machine_get_device_memory_region_size, NULL, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_add(oc, PC_MACHINE_VMPORT, "OnOffAuto", pc_machine_get_vmport, pc_machine_set_vmport, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, PC_MACHINE_VMPORT, "Enable vmport (pc & q35)"); object_class_property_add_bool(oc, PC_MACHINE_SMBUS, - pc_machine_get_smbus, pc_machine_set_smbus, &error_abort); + pc_machine_get_smbus, pc_machine_set_smbus); object_class_property_add_bool(oc, PC_MACHINE_SATA, - pc_machine_get_sata, pc_machine_set_sata, &error_abort); + pc_machine_get_sata, pc_machine_set_sata); object_class_property_add_bool(oc, PC_MACHINE_PIT, - pc_machine_get_pit, pc_machine_set_pit, &error_abort); + pc_machine_get_pit, pc_machine_set_pit); } static const TypeInfo pc_machine_info = { diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 3862e5120e..f66e1d73ce 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -291,7 +291,7 @@ static void pc_init1(MachineState *machine, TYPE_HOTPLUG_HANDLER, (Object **)&pcms->acpi_dev, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, &error_abort); + OBJ_PROP_LINK_STRONG); object_property_set_link(OBJECT(machine), OBJECT(piix4_pm), PC_MACHINE_ACPI_DEVICE_PROP, &error_abort); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 3349e38a4c..4ba8ac8774 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -214,7 +214,7 @@ static void pc_q35_init(MachineState *machine) /* create pci host bus */ q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE)); - object_property_add_child(qdev_get_machine(), "q35", OBJECT(q35_host), NULL); + object_property_add_child(qdev_get_machine(), "q35", OBJECT(q35_host)); object_property_set_link(OBJECT(q35_host), OBJECT(ram_memory), MCH_HOST_PROP_RAM_MEM, NULL); object_property_set_link(OBJECT(q35_host), OBJECT(pci_memory), @@ -240,7 +240,7 @@ static void pc_q35_init(MachineState *machine) TYPE_HOTPLUG_HANDLER, (Object **)&pcms->acpi_dev, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, &error_abort); + OBJ_PROP_LINK_STRONG); object_property_set_link(OBJECT(machine), OBJECT(lpc), PC_MACHINE_ACPI_DEVICE_PROP, &error_abort); diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index f5f3f466b0..002133a2d8 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -90,10 +90,9 @@ static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms, qdev_prop_set_uint64(dev, "sector-length", FLASH_SECTOR_SIZE); qdev_prop_set_uint8(dev, "width", 1); qdev_prop_set_string(dev, "name", name); - object_property_add_child(OBJECT(pcms), name, OBJECT(dev), - &error_abort); + object_property_add_child(OBJECT(pcms), name, OBJECT(dev)); object_property_add_alias(OBJECT(pcms), alias_prop_name, - OBJECT(dev), "drive", &error_abort); + OBJECT(dev), "drive"); return PFLASH_CFI01(dev); } diff --git a/hw/i386/x86.c b/hw/i386/x86.c index e2bf601273..7a3bc7ab66 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -350,7 +350,7 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name) dev = qdev_create(NULL, TYPE_IOAPIC); } object_property_add_child(object_resolve_path(parent_name, NULL), - "ioapic", OBJECT(dev), NULL); + "ioapic", OBJECT(dev)); qdev_init_nofail(dev); d = SYS_BUS_DEVICE(dev); sysbus_mmio_map(d, 0, IO_APIC_DEFAULT_ADDRESS); @@ -982,19 +982,19 @@ static void x86_machine_class_init(ObjectClass *oc, void *data) object_class_property_add(oc, X86_MACHINE_MAX_RAM_BELOW_4G, "size", x86_machine_get_max_ram_below_4g, x86_machine_set_max_ram_below_4g, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, X86_MACHINE_MAX_RAM_BELOW_4G, "Maximum ram below the 4G boundary (32bit boundary)"); object_class_property_add(oc, X86_MACHINE_SMM, "OnOffAuto", x86_machine_get_smm, x86_machine_set_smm, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, X86_MACHINE_SMM, "Enable SMM"); object_class_property_add(oc, X86_MACHINE_ACPI, "OnOffAuto", x86_machine_get_acpi, x86_machine_set_acpi, - NULL, NULL, &error_abort); + NULL, NULL); object_class_property_set_description(oc, X86_MACHINE_ACPI, "Enable ACPI"); } diff --git a/hw/ide/macio.c b/hw/ide/macio.c index a9f25e5d02..30af0e93e6 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -459,7 +459,7 @@ static void macio_ide_initfn(Object *obj) object_property_add_link(obj, "dbdma", TYPE_MAC_DBDMA, (Object **) &s->dbdma, - qdev_prop_allow_set_link_before_realize, 0, NULL); + qdev_prop_allow_set_link_before_realize, 0); } static Property macio_ide_properties[] = { diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index c22afdb8ee..4909b14b91 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -266,7 +266,7 @@ static void ide_dev_instance_init(Object *obj) { object_property_add(obj, "bootindex", "int32", ide_dev_get_bootindex, - ide_dev_set_bootindex, NULL, NULL, NULL); + ide_dev_set_bootindex, NULL, NULL); object_property_set_int(obj, -1, "bootindex", NULL); } diff --git a/hw/input/vhost-user-input.c b/hw/input/vhost-user-input.c index 544452a234..63984a8ba7 100644 --- a/hw/input/vhost-user-input.c +++ b/hw/input/vhost-user-input.c @@ -101,7 +101,7 @@ static void vhost_input_init(Object *obj) vhi->vhost = VHOST_USER_BACKEND(object_new(TYPE_VHOST_USER_BACKEND)); object_property_add_alias(obj, "chardev", - OBJECT(vhi->vhost), "chardev", &error_abort); + OBJECT(vhi->vhost), "chardev"); } static void vhost_input_finalize(Object *obj) diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 9ec0f2deb2..243bb69430 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -445,7 +445,7 @@ static void apic_common_initfn(Object *obj) s->id = s->initial_apic_id = -1; object_property_add(obj, "id", "uint32", apic_common_get_id, - apic_common_set_id, NULL, NULL, NULL); + apic_common_set_id, NULL, NULL); } static void apic_common_class_init(ObjectClass *klass, void *data) diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c index 5f290f5410..baca4d8a2d 100644 --- a/hw/intc/s390_flic.c +++ b/hw/intc/s390_flic.c @@ -65,11 +65,11 @@ void s390_flic_init(void) if (kvm_enabled()) { dev = qdev_create(NULL, TYPE_KVM_S390_FLIC); object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC, - OBJECT(dev), NULL); + OBJECT(dev)); } else { dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC); object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC, - OBJECT(dev), NULL); + OBJECT(dev)); } qdev_init_nofail(dev); } diff --git a/hw/intc/xics.c b/hw/intc/xics.c index c5d507e707..e56d578841 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -380,7 +380,7 @@ Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp) Object *obj; obj = object_new(type); - object_property_add_child(cpu, type, obj, &error_abort); + object_property_add_child(cpu, type, obj); object_unref(obj); object_property_set_link(obj, OBJECT(xi), ICP_PROP_XICS, &error_abort); object_property_set_link(obj, cpu, ICP_PROP_CPU, &error_abort); diff --git a/hw/intc/xive.c b/hw/intc/xive.c index d6183f8ae4..8f2b4050cb 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -761,7 +761,7 @@ Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp) Object *obj; obj = object_new(TYPE_XIVE_TCTX); - object_property_add_child(cpu, TYPE_XIVE_TCTX, obj, &error_abort); + object_property_add_child(cpu, TYPE_XIVE_TCTX, obj); object_unref(obj); object_property_set_link(obj, cpu, "cpu", &error_abort); object_property_set_link(obj, OBJECT(xptr), "presenter", &error_abort); diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c index 46c6a79527..8d35c9fdd6 100644 --- a/hw/ipmi/ipmi.c +++ b/hw/ipmi/ipmi.c @@ -105,8 +105,7 @@ void ipmi_bmc_find_and_link(Object *obj, Object **bmc) { object_property_add_link(obj, "bmc", TYPE_IPMI_BMC, bmc, isa_ipmi_bmc_check, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); } static Property ipmi_bmc_properties[] = { diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index 0d9d848280..3dcdc234a4 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -62,8 +62,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(d, "irq", k->parallel.get_irq(sio, i)); } qdev_prop_set_chr(d, "chardev", chr); - object_property_add_child(OBJECT(sio), name, OBJECT(isa), - &error_abort); + object_property_add_child(OBJECT(dev), name, OBJECT(isa)); qdev_init_nofail(d); sio->parallel[i] = isa; trace_superio_create_parallel(i, @@ -102,8 +101,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(d, "irq", k->serial.get_irq(sio, i)); } qdev_prop_set_chr(d, "chardev", chr); - object_property_add_child(OBJECT(sio), name, OBJECT(isa), - &error_abort); + object_property_add_child(OBJECT(dev), name, OBJECT(isa)); qdev_init_nofail(d); sio->serial[i] = isa; trace_superio_create_serial(i, @@ -137,8 +135,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) qdev_prop_set_drive(d, "driveB", blk_by_legacy_dinfo(drive), &error_fatal); } - object_property_add_child(OBJECT(sio), "isa-fdc", OBJECT(isa), - &error_abort); + object_property_add_child(OBJECT(sio), "isa-fdc", OBJECT(isa)); qdev_init_nofail(d); sio->floppy = isa; trace_superio_create_floppy(0, @@ -150,8 +147,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) /* Keyboard, mouse */ isa = isa_create(bus, TYPE_I8042); - object_property_add_child(OBJECT(sio), TYPE_I8042, OBJECT(isa), - &error_abort); + object_property_add_child(OBJECT(sio), TYPE_I8042, OBJECT(isa)); qdev_init_nofail(DEVICE(isa)); sio->kbc = isa; @@ -169,8 +165,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(d, "irq", k->ide.get_irq(sio, 0)); } qdev_init_nofail(d); - object_property_add_child(OBJECT(sio), "isa-ide", OBJECT(isa), - &error_abort); + object_property_add_child(OBJECT(sio), "isa-ide", OBJECT(isa)); sio->ide = isa; trace_superio_create_ide(0, k->ide.get_iobase ? diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index fbc3165d03..c975d46675 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -633,11 +633,11 @@ static void ich9_lpc_initfn(Object *obj) static const uint8_t acpi_disable_cmd = ICH9_APM_ACPI_DISABLE; object_property_add_uint8_ptr(obj, ACPI_PM_PROP_SCI_INT, - &lpc->sci_gsi, OBJ_PROP_FLAG_READ, NULL); + &lpc->sci_gsi, OBJ_PROP_FLAG_READ); object_property_add_uint8_ptr(OBJECT(lpc), ACPI_PM_PROP_ACPI_ENABLE_CMD, - &acpi_enable_cmd, OBJ_PROP_FLAG_READ, NULL); + &acpi_enable_cmd, OBJ_PROP_FLAG_READ); object_property_add_uint8_ptr(OBJECT(lpc), ACPI_PM_PROP_ACPI_DISABLE_CMD, - &acpi_disable_cmd, OBJ_PROP_FLAG_READ, NULL); + &acpi_disable_cmd, OBJ_PROP_FLAG_READ); ich9_pm_add_properties(obj, &lpc->pm, NULL); } diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index 8e426d24bb..c5adedcc69 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -110,10 +110,10 @@ static void nvdimm_init(Object *obj) { object_property_add(obj, NVDIMM_LABEL_SIZE_PROP, "int", nvdimm_get_label_size, nvdimm_set_label_size, NULL, - NULL, NULL); + NULL); object_property_add(obj, NVDIMM_UUID_PROP, "QemuUUID", nvdimm_get_uuid, - nvdimm_set_uuid, NULL, NULL, NULL); + nvdimm_set_uuid, NULL, NULL); } static void nvdimm_finalize(Object *obj) diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 6d62588fea..b81c82f57b 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -165,7 +165,7 @@ static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name, static void pc_dimm_init(Object *obj) { object_property_add(obj, PC_DIMM_SIZE_PROP, "uint64", pc_dimm_get_size, - NULL, NULL, NULL, &error_abort); + NULL, NULL, NULL); } static void pc_dimm_realize(DeviceState *dev, Error **errp) diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index 0a2640c40b..536571db7f 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -138,10 +138,8 @@ petalogix_ml605_init(MachineState *machine) dma = qdev_create(NULL, "xlnx.axi-dma"); /* FIXME: attach to the sysbus instead */ - object_property_add_child(qdev_get_machine(), "xilinx-eth", OBJECT(eth0), - NULL); - object_property_add_child(qdev_get_machine(), "xilinx-dma", OBJECT(dma), - NULL); + object_property_add_child(qdev_get_machine(), "xilinx-eth", OBJECT(eth0)); + object_property_add_child(qdev_get_machine(), "xilinx-dma", OBJECT(dma)); ds = object_property_get_link(OBJECT(dma), "axistream-connected-target", NULL); diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index 14db9cfc1f..25e1e58356 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -250,7 +250,7 @@ static void aspeed_sdmc_initfn(Object *obj) { object_property_add(obj, "ram-size", "int", aspeed_sdmc_get_ram_size, aspeed_sdmc_set_ram_size, - NULL, NULL, NULL); + NULL, NULL); } static void aspeed_sdmc_realize(DeviceState *dev, Error **errp) diff --git a/hw/misc/edu.c b/hw/misc/edu.c index ff10f5b794..ec617e63f3 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -402,8 +402,7 @@ static void edu_instance_init(Object *obj) edu->dma_mask = (1UL << 28) - 1; object_property_add_uint64_ptr(obj, "dma_mask", - &edu->dma_mask, OBJ_PROP_FLAG_READWRITE, - NULL); + &edu->dma_mask, OBJ_PROP_FLAG_READWRITE); } static void edu_class_init(ObjectClass *class, void *data) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 81343301b1..e05623d730 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -885,10 +885,10 @@ static void mac_via_realize(DeviceState *dev, Error **errp) /* Pass through mos6522 output IRQs */ ms = MOS6522(&m->mos6522_via1); object_property_add_alias(OBJECT(dev), "irq[0]", OBJECT(ms), - SYSBUS_DEVICE_GPIO_IRQ "[0]", &error_abort); + SYSBUS_DEVICE_GPIO_IRQ "[0]"); ms = MOS6522(&m->mos6522_via2); object_property_add_alias(OBJECT(dev), "irq[1]", OBJECT(ms), - SYSBUS_DEVICE_GPIO_IRQ "[0]", &error_abort); + SYSBUS_DEVICE_GPIO_IRQ "[0]"); /* Pass through mos6522 input IRQs */ qdev_pass_gpios(DEVICE(&m->mos6522_via1), dev, "via1-irq"); diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c index 6cca6b27d6..0fef8fb335 100644 --- a/hw/misc/macio/gpio.c +++ b/hw/misc/macio/gpio.c @@ -170,7 +170,7 @@ static void macio_gpio_init(Object *obj) object_property_add_link(obj, "pic", TYPE_OPENPIC, (Object **) &s->pic, qdev_prop_allow_set_link_before_realize, - 0, NULL); + 0); memory_region_init_io(&s->gpiomem, OBJECT(s), &macio_gpio_ops, obj, "gpio", 0x30); diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 79222192e8..3779865ab2 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -241,7 +241,7 @@ static void macio_oldworld_init(Object *obj) object_property_add_link(obj, "pic", TYPE_HEATHROW, (Object **) &os->pic, qdev_prop_allow_set_link_before_realize, - 0, NULL); + 0); macio_init_child_obj(s, "cuda", &s->cuda, sizeof(s->cuda), TYPE_CUDA); @@ -397,7 +397,7 @@ static void macio_newworld_init(Object *obj) object_property_add_link(obj, "pic", TYPE_OPENPIC, (Object **) &ns->pic, qdev_prop_allow_set_link_before_realize, - 0, NULL); + 0); macio_init_child_obj(s, "gpio", &ns->gpio, sizeof(ns->gpio), TYPE_MACIO_GPIO); diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index b8466a4a3f..5fa792846c 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -773,7 +773,7 @@ static void pmu_init(Object *obj) object_property_add_link(obj, "gpio", TYPE_MACIO_GPIO, (Object **) &s->gpio, qdev_prop_allow_set_link_before_realize, - 0, NULL); + 0); sysbus_init_child_obj(obj, "mos6522-pmu", &s->mos6522_pmu, sizeof(s->mos6522_pmu), TYPE_MOS6522_PMU); diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index efd961e041..cac729e35a 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -298,7 +298,7 @@ static void pca9552_initfn(Object *obj) name = g_strdup_printf("led%d", led); object_property_add(obj, name, "bool", pca9552_get_led, pca9552_set_led, - NULL, NULL, NULL); + NULL, NULL); g_free(name); } } diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c index 75ddad3a12..58dbebca90 100644 --- a/hw/misc/tmp105.c +++ b/hw/misc/tmp105.c @@ -245,7 +245,7 @@ static void tmp105_initfn(Object *obj) { object_property_add(obj, "temperature", "int", tmp105_get_temperature, - tmp105_set_temperature, NULL, NULL, NULL); + tmp105_set_temperature, NULL, NULL); } static void tmp105_class_init(ObjectClass *klass, void *data) diff --git a/hw/misc/tmp421.c b/hw/misc/tmp421.c index c0bc150bca..74864cd93d 100644 --- a/hw/misc/tmp421.c +++ b/hw/misc/tmp421.c @@ -347,16 +347,16 @@ static void tmp421_initfn(Object *obj) { object_property_add(obj, "temperature0", "int", tmp421_get_temperature, - tmp421_set_temperature, NULL, NULL, NULL); + tmp421_set_temperature, NULL, NULL); object_property_add(obj, "temperature1", "int", tmp421_get_temperature, - tmp421_set_temperature, NULL, NULL, NULL); + tmp421_set_temperature, NULL, NULL); object_property_add(obj, "temperature2", "int", tmp421_get_temperature, - tmp421_set_temperature, NULL, NULL, NULL); + tmp421_set_temperature, NULL, NULL); object_property_add(obj, "temperature3", "int", tmp421_get_temperature, - tmp421_set_temperature, NULL, NULL, NULL); + tmp421_set_temperature, NULL, NULL); } static void tmp421_class_init(ObjectClass *klass, void *data) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 22a0b1b1f9..e8f9cc7f1e 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1600,8 +1600,7 @@ static void gem_init(Object *obj) object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, (Object **)&s->dma_mr, qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); } static const VMStateDescription vmstate_cadence_gem = { diff --git a/hw/net/can/can_kvaser_pci.c b/hw/net/can/can_kvaser_pci.c index 16861b8f9f..4b941370d0 100644 --- a/hw/net/can/can_kvaser_pci.c +++ b/hw/net/can/can_kvaser_pci.c @@ -282,7 +282,7 @@ static void kvaser_pci_instance_init(Object *obj) object_property_add_link(obj, "canbus", TYPE_CAN_BUS, (Object **)&d->canbus, qdev_prop_allow_set_link_before_realize, - 0, &error_abort); + 0); } static void kvaser_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/net/can/can_mioe3680_pci.c b/hw/net/can/can_mioe3680_pci.c index 965e252d9d..695e762a8d 100644 --- a/hw/net/can/can_mioe3680_pci.c +++ b/hw/net/can/can_mioe3680_pci.c @@ -219,11 +219,11 @@ static void mioe3680_pci_instance_init(Object *obj) object_property_add_link(obj, "canbus0", TYPE_CAN_BUS, (Object **)&d->canbus[0], qdev_prop_allow_set_link_before_realize, - 0, &error_abort); + 0); object_property_add_link(obj, "canbus1", TYPE_CAN_BUS, (Object **)&d->canbus[1], qdev_prop_allow_set_link_before_realize, - 0, &error_abort); + 0); } static void mioe3680_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/net/can/can_pcm3680_pci.c b/hw/net/can/can_pcm3680_pci.c index 51b6540072..4218e63eb2 100644 --- a/hw/net/can/can_pcm3680_pci.c +++ b/hw/net/can/can_pcm3680_pci.c @@ -220,11 +220,11 @@ static void pcm3680i_pci_instance_init(Object *obj) object_property_add_link(obj, "canbus0", TYPE_CAN_BUS, (Object **)&d->canbus[0], qdev_prop_allow_set_link_before_realize, - 0, &error_abort); + 0); object_property_add_link(obj, "canbus1", TYPE_CAN_BUS, (Object **)&d->canbus[1], qdev_prop_allow_set_link_before_realize, - 0, &error_abort); + 0); } static void pcm3680i_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index e744eff153..fdf8faa0d9 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -133,7 +133,7 @@ static void isa_ne2000_instance_init(Object *obj) { object_property_add(obj, "bootindex", "int32", isa_ne2000_get_bootindex, - isa_ne2000_set_bootindex, NULL, NULL, NULL); + isa_ne2000_set_bootindex, NULL, NULL); object_property_set_int(obj, -1, "bootindex", NULL); } static const TypeInfo ne2000_isa_info = { diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 498afe2f54..44fe04d889 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -985,16 +985,11 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet", (Object **) &ds->enet, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, - &local_err); + OBJ_PROP_LINK_STRONG); object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet", (Object **) &cs->enet, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, - &local_err); - if (local_err) { - goto xilinx_enet_realize_fail; - } + OBJ_PROP_LINK_STRONG); object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_err); object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_err); if (local_err) { diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c index 33dc2bf511..4c60a27fb7 100644 --- a/hw/nios2/10m50_devboard.c +++ b/hw/nios2/10m50_devboard.c @@ -81,8 +81,7 @@ static void nios2_10m50_ghrd_init(MachineState *machine) /* Register: Internal Interrupt Controller (IIC) */ dev = qdev_create(NULL, "altera,iic"); - object_property_add_const_link(OBJECT(dev), "cpu", OBJECT(cpu), - &error_abort); + object_property_add_const_link(OBJECT(dev), "cpu", OBJECT(cpu)); qdev_init_nofail(dev); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]); for (i = 0; i < 32; i++) { diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 4be6c9d9fd..8dd50c2c72 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -1105,7 +1105,7 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, } object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, - OBJECT(dev), NULL); + OBJECT(dev)); qdev_init_nofail(dev); sbd = SYS_BUS_DEVICE(dev); @@ -1145,7 +1145,7 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, } object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, - OBJECT(dev), NULL); + OBJECT(dev)); qdev_init_nofail(dev); sbd = SYS_BUS_DEVICE(dev); diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c index 24ccdf6ceb..4b3af0c704 100644 --- a/hw/pci-host/grackle.c +++ b/hw/pci-host/grackle.c @@ -109,7 +109,7 @@ static void grackle_init(Object *obj) object_property_add_link(obj, "pic", TYPE_HEATHROW, (Object **) &s->pic, qdev_prop_allow_set_link_before_realize, - 0, NULL); + 0); sysbus_init_mmio(sbd, &phb->conf_mem); sysbus_init_mmio(sbd, &phb->data_mem); diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c index d980c97049..0adbd77553 100644 --- a/hw/pci-host/i440fx.c +++ b/hw/pci-host/i440fx.c @@ -212,19 +212,19 @@ static void i440fx_pcihost_initfn(Object *obj) object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "uint32", i440fx_pcihost_get_pci_hole_start, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL); object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "uint32", i440fx_pcihost_get_pci_hole_end, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL); object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "uint64", i440fx_pcihost_get_pci_hole64_start, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL); object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "uint64", i440fx_pcihost_get_pci_hole64_end, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL); } static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) @@ -275,7 +275,7 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, b = pci_root_bus_new(dev, NULL, pci_address_space, address_space_io, 0, TYPE_PCI_BUS); s->bus = b; - object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL); + object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev)); qdev_init_nofail(dev); d = pci_create_simple(b, 0, pci_type); @@ -308,7 +308,7 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, memory_region_set_enabled(&f->low_smram, true); memory_region_add_subregion(&f->smram, 0xa0000, &f->low_smram); object_property_add_const_link(qdev_get_machine(), "smram", - OBJECT(&f->smram), &error_abort); + OBJECT(&f->smram)); init_pam(dev, f->ram_memory, f->system_memory, f->pci_address_space, &f->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE); diff --git a/hw/pci-host/pnv_phb3_msi.c b/hw/pci-host/pnv_phb3_msi.c index d645468f4a..099d2092a2 100644 --- a/hw/pci-host/pnv_phb3_msi.c +++ b/hw/pci-host/pnv_phb3_msi.c @@ -282,8 +282,7 @@ static void phb3_msi_instance_init(Object *obj) object_property_add_link(obj, "phb", TYPE_PNV_PHB3, (Object **)&msi->phb, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); /* Will be overriden later */ ics->offset = 0; diff --git a/hw/pci-host/pnv_phb3_pbcq.c b/hw/pci-host/pnv_phb3_pbcq.c index 7b9a121246..a0526aa1ec 100644 --- a/hw/pci-host/pnv_phb3_pbcq.c +++ b/hw/pci-host/pnv_phb3_pbcq.c @@ -324,8 +324,7 @@ static void phb3_pbcq_instance_init(Object *obj) object_property_add_link(obj, "phb", TYPE_PNV_PHB3, (Object **)&pbcq->phb, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); } static void pnv_pbcq_class_init(ObjectClass *klass, void *data) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 2bbc90b28f..352aeecfa7 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -222,38 +222,38 @@ static void q35_host_initfn(Object *obj) Q35_PCI_HOST_HOLE64_SIZE_DEFAULT); object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "uint32", q35_host_get_pci_hole_start, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL); object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "uint32", q35_host_get_pci_hole_end, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL); object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "uint64", q35_host_get_pci_hole64_start, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL); object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "uint64", q35_host_get_pci_hole64_end, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL); object_property_add_uint64_ptr(obj, PCIE_HOST_MCFG_SIZE, - &pehb->size, OBJ_PROP_FLAG_READ, NULL); + &pehb->size, OBJ_PROP_FLAG_READ); object_property_add_link(obj, MCH_HOST_PROP_RAM_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.ram_memory, - qdev_prop_allow_set_link_before_realize, 0, NULL); + qdev_prop_allow_set_link_before_realize, 0); object_property_add_link(obj, MCH_HOST_PROP_PCI_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.pci_address_space, - qdev_prop_allow_set_link_before_realize, 0, NULL); + qdev_prop_allow_set_link_before_realize, 0); object_property_add_link(obj, MCH_HOST_PROP_SYSTEM_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.system_memory, - qdev_prop_allow_set_link_before_realize, 0, NULL); + qdev_prop_allow_set_link_before_realize, 0); object_property_add_link(obj, MCH_HOST_PROP_IO_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.address_space_io, - qdev_prop_allow_set_link_before_realize, 0, NULL); + qdev_prop_allow_set_link_before_realize, 0); } static const TypeInfo q35_host_info = { @@ -638,7 +638,7 @@ static void mch_realize(PCIDevice *d, Error **errp) &mch->smbase_window); object_property_add_const_link(qdev_get_machine(), "smram", - OBJECT(&mch->smram), &error_abort); + OBJECT(&mch->smram)); init_pam(DEVICE(mch), mch->ram_memory, mch->system_memory, mch->pci_address_space, &mch->pam_regions[0], diff --git a/hw/pci-host/sabre.c b/hw/pci-host/sabre.c index 2b8503b709..475bcb01d7 100644 --- a/hw/pci-host/sabre.c +++ b/hw/pci-host/sabre.c @@ -442,7 +442,7 @@ static void sabre_init(Object *obj) object_property_add_link(obj, "iommu", TYPE_SUN4U_IOMMU, (Object **) &s->iommu, qdev_prop_allow_set_link_before_realize, - 0, NULL); + 0); /* sabre_config */ memory_region_init_io(&s->sabre_config, OBJECT(s), &sabre_config_ops, s, diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c index cf70b76fe2..1ed1072eeb 100644 --- a/hw/pci-host/uninorth.c +++ b/hw/pci-host/uninorth.c @@ -175,7 +175,7 @@ static void pci_unin_main_init(Object *obj) object_property_add_link(obj, "pic", TYPE_OPENPIC, (Object **) &s->pic, qdev_prop_allow_set_link_before_realize, - 0, NULL); + 0); sysbus_init_mmio(sbd, &h->conf_mem); sysbus_init_mmio(sbd, &h->data_mem); @@ -223,7 +223,7 @@ static void pci_u3_agp_init(Object *obj) object_property_add_link(obj, "pic", TYPE_OPENPIC, (Object **) &s->pic, qdev_prop_allow_set_link_before_realize, - 0, NULL); + 0); sysbus_init_mmio(sbd, &h->conf_mem); sysbus_init_mmio(sbd, &h->data_mem); @@ -262,7 +262,7 @@ static void pci_unin_agp_init(Object *obj) object_property_add_link(obj, "pic", TYPE_OPENPIC, (Object **) &s->pic, qdev_prop_allow_set_link_before_realize, - 0, NULL); + 0); sysbus_init_mmio(sbd, &h->conf_mem); sysbus_init_mmio(sbd, &h->data_mem); @@ -299,7 +299,7 @@ static void pci_unin_internal_init(Object *obj) object_property_add_link(obj, "pic", TYPE_OPENPIC, (Object **) &s->pic, qdev_prop_allow_set_link_before_realize, - 0, NULL); + 0); sysbus_init_mmio(sbd, &h->conf_mem); sysbus_init_mmio(sbd, &h->data_mem); diff --git a/hw/pcmcia/pxa2xx.c b/hw/pcmcia/pxa2xx.c index 14e4dfe8b1..8667244df4 100644 --- a/hw/pcmcia/pxa2xx.c +++ b/hw/pcmcia/pxa2xx.c @@ -189,7 +189,7 @@ static void pxa2xx_pcmcia_initfn(Object *obj) object_property_add_link(obj, "card", TYPE_PCMCIA_CARD, (Object **)&s->card, NULL, /* read-only property */ - 0, NULL); + 0); } /* Insert a new card into a slot */ diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 0d1f41197c..2a0b66a152 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -744,8 +744,7 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms, const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); dev = qdev_create(NULL, TYPE_OPENPIC); - object_property_add_child(OBJECT(machine), "pic", OBJECT(dev), - &error_fatal); + object_property_add_child(OBJECT(machine), "pic", OBJECT(dev)); qdev_prop_set_uint32(dev, "model", pmc->mpic_version); qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); @@ -916,7 +915,7 @@ void ppce500_init(MachineState *machine) dev = qdev_create(NULL, "e500-ccsr"); object_property_add_child(qdev_get_machine(), "e500-ccsr", - OBJECT(dev), NULL); + OBJECT(dev)); qdev_init_nofail(dev); ccsr = CCSR(dev); ccsr_addr_space = &ccsr->ccsr_space; @@ -957,8 +956,7 @@ void ppce500_init(MachineState *machine) /* PCI */ dev = qdev_create(NULL, "e500-pcihost"); - object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev), - &error_abort); + object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev)); qdev_prop_set_uint32(dev, "first_slot", pmc->pci_first_slot); qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]); qdev_init_nofail(dev); diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 55d1419442..3507f26f6e 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -455,7 +455,7 @@ static void ppc_core99_init(MachineState *machine) qdev_prop_set_uint32(dev, "data_width", 1); qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, - OBJECT(fw_cfg), NULL); + OBJECT(fw_cfg)); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, CFG_ADDR); @@ -628,7 +628,7 @@ static void core99_instance_init(Object *obj) /* Default via_config is CORE99_VIA_CONFIG_CUDA */ cms->via_config = CORE99_VIA_CONFIG_CUDA; object_property_add_str(obj, "via", core99_get_via_config, - core99_set_via_config, NULL); + core99_set_via_config); object_property_set_description(obj, "via", "Set VIA configuration. " "Valid values are cuda, pmu and pmu-adb"); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 101bdc5c4d..0b4c1c6373 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -314,7 +314,7 @@ static void ppc_heathrow_init(MachineState *machine) qdev_prop_set_uint32(dev, "data_width", 1); qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, - OBJECT(fw_cfg), NULL); + OBJECT(fw_cfg)); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, CFG_ADDR); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 4666dbbe7a..da637822f9 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -832,7 +832,7 @@ static void pnv_init(MachineState *machine) } snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i)); - object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal); + object_property_add_child(OBJECT(pnv), chip_name, chip); object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id", &error_fatal); object_property_set_int(chip, machine->smp.cores, @@ -1060,8 +1060,7 @@ static void pnv_chip_power8_instance_init(Object *obj) object_property_add_link(obj, "xics", TYPE_XICS_FABRIC, (Object **)&chip8->xics, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); object_initialize_child(obj, "psi", &chip8->psi, sizeof(chip8->psi), TYPE_PNV8_PSI, &error_abort, NULL); @@ -1321,7 +1320,7 @@ static void pnv_chip_power9_instance_init(Object *obj) object_initialize_child(obj, "xive", &chip9->xive, sizeof(chip9->xive), TYPE_PNV_XIVE, &error_abort, NULL); object_property_add_alias(obj, "xive-fabric", OBJECT(&chip9->xive), - "xive-fabric", &error_abort); + "xive-fabric"); object_initialize_child(obj, "psi", &chip9->psi, sizeof(chip9->psi), TYPE_PNV9_PSI, &error_abort, NULL); @@ -1739,8 +1738,7 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp) pnv_core = PNV_CORE(object_new(typename)); snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid); - object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core), - &error_abort); + object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core)); chip->cores[i] = pnv_core; object_property_set_int(OBJECT(pnv_core), chip->nr_threads, "nr-threads", &error_fatal); @@ -2027,8 +2025,7 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data) nc->nmi_monitor_handler = pnv_nmi; object_class_property_add_bool(oc, "hb-mode", - pnv_machine_get_hb, pnv_machine_set_hb, - &error_abort); + pnv_machine_get_hb, pnv_machine_set_hb); object_class_property_set_description(oc, "hb-mode", "Use a hostboot like boot loader"); } diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c index 4e018b8b70..5f86453b6a 100644 --- a/hw/ppc/pnv_bmc.c +++ b/hw/ppc/pnv_bmc.c @@ -217,8 +217,7 @@ static const IPMINetfn hiomap_netfn = { void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor) { object_ref(OBJECT(pnor)); - object_property_add_const_link(OBJECT(bmc), "pnor", OBJECT(pnor), - &error_abort); + object_property_add_const_link(OBJECT(bmc), "pnor", OBJECT(pnor)); /* Install the HIOMAP protocol handlers to access the PNOR */ ipmi_sim_register_netfn(IPMI_BMC_SIMULATOR(bmc), IPMI_NETFN_OEM, @@ -235,7 +234,7 @@ IPMIBmc *pnv_bmc_create(PnvPnor *pnor) obj = object_new(TYPE_IPMI_BMC_SIMULATOR); object_ref(OBJECT(pnor)); - object_property_add_const_link(obj, "pnor", OBJECT(pnor), &error_abort); + object_property_add_const_link(obj, "pnor", OBJECT(pnor)); object_property_set_bool(obj, true, "realized", &error_fatal); /* Install the HIOMAP protocol handlers to access the PNOR */ diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 234562040d..7033104676 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -232,7 +232,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp) pc->threads[i] = POWERPC_CPU(obj); snprintf(name, sizeof(name), "thread[%d]", i); - object_property_add_child(OBJECT(pc), name, obj, &error_abort); + object_property_add_child(OBJECT(pc), name, obj); cpu->machine_data = g_new0(PnvCPUState, 1); diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index c34a49b000..cfd5b7bc25 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -486,7 +486,7 @@ static void pnv_psi_power8_instance_init(Object *obj) object_initialize_child(obj, "ics-psi", &psi8->ics, sizeof(psi8->ics), TYPE_ICS, &error_abort, NULL); object_property_add_alias(obj, ICS_PROP_XICS, OBJECT(&psi8->ics), - ICS_PROP_XICS, &error_abort); + ICS_PROP_XICS); } static const uint8_t irq_to_xivr[] = { diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 44be9d25a2..9266453dd9 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -229,7 +229,7 @@ static int prep_set_cmos_checksum(DeviceState *dev, void *opaque) rtc_set_memory(rtc, 0x3f, checksum >> 8); object_property_add_alias(qdev_get_machine(), "rtc-time", OBJECT(rtc), - "date", NULL); + "date"); } return 0; } @@ -275,7 +275,7 @@ static void ibm_40p_init(MachineState *machine) qdev_prop_set_string(dev, "bios-name", bios_name); qdev_prop_set_uint32(dev, "elf-machine", PPC_ELF_MACHINE); pcihost = SYS_BUS_DEVICE(dev); - object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev), NULL); + object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev)); qdev_init_nofail(dev); pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0")); if (!pci_bus) { @@ -343,7 +343,7 @@ static void ibm_40p_init(MachineState *machine) qdev_prop_set_uint32(dev, "data_width", 1); qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, - OBJECT(fw_cfg), NULL); + OBJECT(fw_cfg)); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, CFG_ADDR); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index aa281e727a..976d40f60f 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1732,7 +1732,7 @@ static void spapr_rtc_create(SpaprMachineState *spapr) object_property_set_bool(OBJECT(&spapr->rtc), true, "realized", &error_fatal); object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc), - "date", &error_fatal); + "date"); } /* Returns whether we want to use VGA or not */ @@ -3305,13 +3305,12 @@ static void spapr_instance_init(Object *obj) spapr->htab_fd = -1; spapr->use_hotplug_event_source = true; object_property_add_str(obj, "kvm-type", - spapr_get_kvm_type, spapr_set_kvm_type, NULL); + spapr_get_kvm_type, spapr_set_kvm_type); object_property_set_description(obj, "kvm-type", "Specifies the KVM virtualization mode (HV, PR)"); object_property_add_bool(obj, "modern-hotplug-events", spapr_get_modern_hotplug_events, - spapr_set_modern_hotplug_events, - NULL); + spapr_set_modern_hotplug_events); object_property_set_description(obj, "modern-hotplug-events", "Use dedicated hotplug event mechanism in" " place of standard EPOW events when possible" @@ -3321,22 +3320,20 @@ static void spapr_instance_init(Object *obj) &error_fatal); object_property_add_str(obj, "resize-hpt", - spapr_get_resize_hpt, spapr_set_resize_hpt, NULL); + spapr_get_resize_hpt, spapr_set_resize_hpt); object_property_set_description(obj, "resize-hpt", "Resizing of the Hash Page Table (enabled, disabled, required)"); object_property_add_uint32_ptr(obj, "vsmt", - &spapr->vsmt, OBJ_PROP_FLAG_READWRITE, - &error_abort); + &spapr->vsmt, OBJ_PROP_FLAG_READWRITE); object_property_set_description(obj, "vsmt", "Virtual SMT: KVM behaves as if this were" " the host's SMT mode"); object_property_add_bool(obj, "vfio-no-msix-emulation", - spapr_get_msix_emulation, NULL, NULL); + spapr_get_msix_emulation, NULL); object_property_add_uint64_ptr(obj, "kernel-addr", - &spapr->kernel_addr, OBJ_PROP_FLAG_READWRITE, - &error_abort); + &spapr->kernel_addr, OBJ_PROP_FLAG_READWRITE); object_property_set_description(obj, "kernel-addr", stringify(KERNEL_LOAD_ADDR) " for -kernel is the default"); @@ -3344,18 +3341,16 @@ static void spapr_instance_init(Object *obj) /* The machine class defines the default interrupt controller mode */ spapr->irq = smc->irq; object_property_add_str(obj, "ic-mode", spapr_get_ic_mode, - spapr_set_ic_mode, NULL); + spapr_set_ic_mode); object_property_set_description(obj, "ic-mode", "Specifies the interrupt controller mode (xics, xive, dual)"); object_property_add_str(obj, "host-model", - spapr_get_host_model, spapr_set_host_model, - &error_abort); + spapr_get_host_model, spapr_set_host_model); object_property_set_description(obj, "host-model", "Host model to advertise in guest device tree"); object_property_add_str(obj, "host-serial", - spapr_get_host_serial, spapr_set_host_serial, - &error_abort); + spapr_get_host_serial, spapr_set_host_serial); object_property_set_description(obj, "host-serial", "Host serial number to advertise in guest device tree"); } diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 0870961fc9..184563e608 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -826,7 +826,6 @@ void spapr_caps_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu) void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp) { - Error *local_err = NULL; ObjectClass *klass = OBJECT_CLASS(smc); int i; @@ -837,12 +836,7 @@ void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp) object_class_property_add(klass, name, cap->type, cap->get, cap->set, - NULL, cap, &local_err); - if (local_err) { - error_propagate(errp, local_err); - g_free(name); - return; - } + NULL, cap); desc = g_strdup_printf("%s", cap->description); object_class_property_set_description(klass, name, desc); diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index ac1c109427..df5c7742ca 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -290,11 +290,8 @@ static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp) cpu->node_id = sc->node_id; id = g_strdup_printf("thread[%d]", i); - object_property_add_child(OBJECT(sc), id, obj, &local_err); + object_property_add_child(OBJECT(sc), id, obj); g_free(id); - if (local_err) { - goto err; - } cpu->machine_data = g_new0(SpaprCpuState, 1); diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 0b66d59867..728307a992 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -392,7 +392,7 @@ void spapr_drc_attach(SpaprDrc *drc, DeviceState *d, Error **errp) object_property_add_link(OBJECT(drc), "device", object_get_typename(OBJECT(drc->dev)), (Object **)(&drc->dev), - NULL, 0, NULL); + NULL, 0); } static void spapr_drc_release(SpaprDrc *drc) @@ -519,7 +519,6 @@ static void realize(DeviceState *d, Error **errp) Object *root_container; gchar *link_name; char *child_name; - Error *err = NULL; trace_spapr_drc_realize(spapr_drc_index(drc)); /* NOTE: we do this as part of realize/unrealize due to the fact @@ -534,13 +533,9 @@ static void realize(DeviceState *d, Error **errp) child_name = object_get_canonical_path_component(OBJECT(drc)); trace_spapr_drc_realize_child(spapr_drc_index(drc), child_name); object_property_add_alias(root_container, link_name, - drc->owner, child_name, &err); + drc->owner, child_name); g_free(child_name); g_free(link_name); - if (err) { - error_propagate(errp, err); - return; - } vmstate_register(VMSTATE_IF(drc), spapr_drc_index(drc), &vmstate_spapr_drc, drc); trace_spapr_drc_realize_complete(spapr_drc_index(drc)); @@ -570,7 +565,7 @@ SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type, drc->owner = owner; prop_name = g_strdup_printf("dr-connector[%"PRIu32"]", spapr_drc_index(drc)); - object_property_add_child(owner, prop_name, OBJECT(drc), &error_abort); + object_property_add_child(owner, prop_name, OBJECT(drc)); object_unref(OBJECT(drc)); object_property_set_bool(OBJECT(drc), true, "realized", NULL); g_free(prop_name); @@ -583,12 +578,11 @@ static void spapr_dr_connector_instance_init(Object *obj) SpaprDrc *drc = SPAPR_DR_CONNECTOR(obj); SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - object_property_add_uint32_ptr(obj, "id", &drc->id, OBJ_PROP_FLAG_READ, - NULL); + object_property_add_uint32_ptr(obj, "id", &drc->id, OBJ_PROP_FLAG_READ); object_property_add(obj, "index", "uint32", prop_get_index, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL); object_property_add(obj, "fdt", "struct", prop_get_fdt, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL); drc->state = drck->empty_state; } diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 5704fe6051..601b896214 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -365,7 +365,7 @@ SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn) tcet->liobn = liobn; tmp = g_strdup_printf("tce-table-%x", liobn); - object_property_add_child(OBJECT(owner), tmp, OBJECT(tcet), NULL); + object_property_add_child(OBJECT(owner), tmp, OBJECT(tcet)); g_free(tmp); object_unref(OBJECT(tcet)); diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 1f630f296b..0c594aa72e 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -307,7 +307,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) obj = object_new(TYPE_ICS_SPAPR); - object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); + object_property_add_child(OBJECT(spapr), "ics", obj); object_property_set_link(obj, OBJECT(spapr), ICS_PROP_XICS, &error_abort); object_property_set_int(obj, smc->nr_xirqs, "nr-irqs", &error_abort); diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c index 42ff72c269..68cfc578a3 100644 --- a/hw/ppc/spapr_rtc.c +++ b/hw/ppc/spapr_rtc.c @@ -149,7 +149,7 @@ static void spapr_rtc_realize(DeviceState *dev, Error **errp) rtc_ns = qemu_clock_get_ns(rtc_clock); rtc->ns_offset = host_s * NANOSECONDS_PER_SECOND - rtc_ns; - object_property_add_tm(OBJECT(rtc), "date", spapr_rtc_qom_date, NULL); + object_property_add_tm(OBJECT(rtc), "date", spapr_rtc_qom_date); } static const VMStateDescription vmstate_spapr_rtc = { diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index da48c958e2..4299bdf480 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -441,15 +441,17 @@ static void sifive_u_machine_instance_init(Object *obj) SiFiveUState *s = RISCV_U_MACHINE(obj); s->start_in_flash = false; - object_property_add_bool(obj, "start-in-flash", sifive_u_machine_get_start_in_flash, - sifive_u_machine_set_start_in_flash, NULL); + object_property_add_bool(obj, "start-in-flash", + sifive_u_machine_get_start_in_flash, + sifive_u_machine_set_start_in_flash); object_property_set_description(obj, "start-in-flash", "Set on to tell QEMU's ROM to jump to " "flash. Otherwise QEMU will jump to DRAM"); s->serial = OTP_SERIAL; - object_property_add(obj, "serial", "uint32", sifive_u_machine_get_serial, - sifive_u_machine_set_serial, NULL, &s->serial, NULL); + object_property_add(obj, "serial", "uint32", + sifive_u_machine_get_serial, + sifive_u_machine_set_serial, NULL, &s->serial); object_property_set_description(obj, "serial", "Board serial number"); } diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index daae3ebdbb..c695a44979 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -92,10 +92,9 @@ static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s, qdev_prop_set_uint16(dev, "id3", 0x00); qdev_prop_set_string(dev, "name", name); - object_property_add_child(OBJECT(s), name, OBJECT(dev), - &error_abort); + object_property_add_child(OBJECT(s), name, OBJECT(dev)); object_property_add_alias(OBJECT(s), alias_prop_name, - OBJECT(dev), "drive", &error_abort); + OBJECT(dev), "drive"); return PFLASH_CFI01(dev); } diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index d18c09911b..9c30cbdcd7 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -962,7 +962,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) qdev_set_legacy_instance_id(dev, RTC_ISA_BASE, 3); qemu_register_reset(rtc_reset, s); - object_property_add_tm(OBJECT(s), "date", rtc_get_date, NULL); + object_property_add_tm(OBJECT(s), "date", rtc_get_date); qdev_init_gpio_out(dev, &s->irq, 1); QLIST_INSERT_HEAD(&rtc_devices, s, link); @@ -984,7 +984,7 @@ ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) } object_property_add_alias(qdev_get_machine(), "rtc-time", OBJECT(isadev), - "date", NULL); + "date"); return isadev; } diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c index 9284de4eec..d0dbd0f1b6 100644 --- a/hw/s390x/ap-bridge.c +++ b/hw/s390x/ap-bridge.c @@ -51,7 +51,7 @@ void s390_init_ap(void) /* Create bridge device */ dev = qdev_create(NULL, TYPE_AP_BRIDGE); object_property_add_child(qdev_get_machine(), TYPE_AP_BRIDGE, - OBJECT(dev), NULL); + OBJECT(dev)); qdev_init_nofail(dev); /* Create bus on bridge device */ diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index c9ce06b043..5d5286bc6e 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -103,7 +103,7 @@ VirtualCssBus *virtual_css_bus_init(void) /* Create bridge device */ dev = qdev_create(NULL, TYPE_VIRTUAL_CSS_BRIDGE); object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE, - OBJECT(dev), NULL); + OBJECT(dev)); qdev_init_nofail(dev); /* Create bus on bridge device */ @@ -141,7 +141,7 @@ static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); device_class_set_props(dc, virtual_css_bridge_properties); object_class_property_add_bool(klass, "cssid-unrestricted", - prop_get_true, NULL, NULL); + prop_get_true, NULL); object_class_property_set_description(klass, "cssid-unrestricted", "A css device can use any cssid, regardless whether virtual" " or not (read only, always true)"); diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 9d6972afa8..97a4f0b1f5 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -449,18 +449,18 @@ static void init_event_facility(Object *obj) event_facility->allow_all_mask_sizes = true; object_property_add_bool(obj, "allow_all_mask_sizes", sclp_event_get_allow_all_mask_sizes, - sclp_event_set_allow_all_mask_sizes, NULL); + sclp_event_set_allow_all_mask_sizes); /* Spawn a new bus for SCLP events */ qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus), TYPE_SCLP_EVENTS_BUS, sdev, NULL); new = object_new(TYPE_SCLP_QUIESCE); - object_property_add_child(obj, TYPE_SCLP_QUIESCE, new, NULL); + object_property_add_child(obj, TYPE_SCLP_QUIESCE, new); object_unref(new); qdev_set_parent_bus(DEVICE(new), BUS(&event_facility->sbus)); new = object_new(TYPE_SCLP_CPU_HOTPLUG); - object_property_add_child(obj, TYPE_SCLP_CPU_HOTPLUG, new, NULL); + object_property_add_child(obj, TYPE_SCLP_CPU_HOTPLUG, new); object_unref(new); qdev_set_parent_bus(DEVICE(new), BUS(&event_facility->sbus)); /* the facility will automatically realize the devices via the bus */ diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index a9a4ae7b39..d304b85640 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -45,7 +45,7 @@ void s390_skeys_init(void) obj = object_new(TYPE_QEMU_S390_SKEYS); } object_property_add_child(qdev_get_machine(), TYPE_S390_SKEYS, - obj, NULL); + obj); object_unref(obj); qdev_init_nofail(DEVICE(obj)); @@ -400,7 +400,7 @@ static void s390_skeys_instance_init(Object *obj) { object_property_add_bool(obj, "migration-enabled", s390_skeys_get_migration_enabled, - s390_skeys_set_migration_enabled, NULL); + s390_skeys_set_migration_enabled); object_property_set_bool(obj, true, "migration-enabled", NULL); } diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index 58121b9f68..6d1e587527 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -47,7 +47,7 @@ void s390_stattrib_init(void) } object_property_add_child(qdev_get_machine(), TYPE_S390_STATTRIB, - obj, NULL); + obj); object_unref(obj); qdev_init_nofail(DEVICE(obj)); @@ -387,7 +387,7 @@ static void s390_stattrib_instance_init(Object *obj) object_property_add_bool(obj, "migration-enabled", s390_stattrib_get_migration_enabled, - s390_stattrib_set_migration_enabled, NULL); + s390_stattrib_set_migration_enabled); object_property_set_bool(obj, true, "migration-enabled", NULL); sas->migration_cur_gfn = 0; } diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 2f94061ff6..67ae2e02ff 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -208,7 +208,7 @@ static void s390_init_ipl_dev(const char *kernel_filename, } g_free(netboot_fw_prop); object_property_add_child(qdev_get_machine(), TYPE_S390_IPL, - new, NULL); + new); object_unref(new); qdev_init_nofail(dev); } @@ -271,7 +271,7 @@ static void ccw_init(MachineState *machine) dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE, - OBJECT(dev), NULL); + OBJECT(dev)); qdev_init_nofail(dev); /* register hypercalls */ @@ -729,19 +729,19 @@ static inline void s390_machine_initfn(Object *obj) { object_property_add_bool(obj, "aes-key-wrap", machine_get_aes_key_wrap, - machine_set_aes_key_wrap, NULL); + machine_set_aes_key_wrap); object_property_set_description(obj, "aes-key-wrap", "enable/disable AES key wrapping using the CPACF wrapping key"); object_property_set_bool(obj, true, "aes-key-wrap", NULL); object_property_add_bool(obj, "dea-key-wrap", machine_get_dea_key_wrap, - machine_set_dea_key_wrap, NULL); + machine_set_dea_key_wrap); object_property_set_description(obj, "dea-key-wrap", "enable/disable DEA key wrapping using the CPACF wrapping key"); object_property_set_bool(obj, true, "dea-key-wrap", NULL); object_property_add_str(obj, "loadparm", - machine_get_loadparm, machine_set_loadparm, NULL); + machine_get_loadparm, machine_set_loadparm); object_property_set_description(obj, "loadparm", "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted" " to upper case) to pass to machine loader, boot manager," diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index ede056b3ef..43cc1e0a41 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -320,8 +320,7 @@ void s390_sclp_init(void) { Object *new = object_new(TYPE_SCLP); - object_property_add_child(qdev_get_machine(), TYPE_SCLP, new, - NULL); + object_property_add_child(qdev_get_machine(), TYPE_SCLP, new); object_unref(OBJECT(new)); qdev_init_nofail(DEVICE(new)); } @@ -383,7 +382,7 @@ static void sclp_init(Object *obj) Object *new; new = object_new(TYPE_SCLP_EVENT_FACILITY); - object_property_add_child(obj, TYPE_SCLP_EVENT_FACILITY, new, NULL); + object_property_add_child(obj, TYPE_SCLP_EVENT_FACILITY, new); object_unref(new); sclp->event_facility = EVENT_FACILITY(new); diff --git a/hw/s390x/tod.c b/hw/s390x/tod.c index 2499d6f656..7324e37b5e 100644 --- a/hw/s390x/tod.c +++ b/hw/s390x/tod.c @@ -26,7 +26,7 @@ void s390_init_tod(void) } else { obj = object_new(TYPE_QEMU_S390_TOD); } - object_property_add_child(qdev_get_machine(), TYPE_S390_TOD, obj, NULL); + object_property_add_child(qdev_get_machine(), TYPE_S390_TOD, obj); object_unref(obj); qdev_init_nofail(DEVICE(obj)); diff --git a/hw/s390x/virtio-ccw-balloon.c b/hw/s390x/virtio-ccw-balloon.c index 5d28e72345..ef3308ecab 100644 --- a/hw/s390x/virtio-ccw-balloon.c +++ b/hw/s390x/virtio-ccw-balloon.c @@ -32,10 +32,10 @@ static void virtio_ccw_balloon_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON); object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev), - "guest-stats", &error_abort); + "guest-stats"); object_property_add_alias(obj, "guest-stats-polling-interval", OBJECT(&dev->vdev), - "guest-stats-polling-interval", &error_abort); + "guest-stats-polling-interval"); } static Property virtio_ccw_balloon_properties[] = { diff --git a/hw/s390x/virtio-ccw-blk.c b/hw/s390x/virtio-ccw-blk.c index bf8520e60a..7287932b7e 100644 --- a/hw/s390x/virtio-ccw-blk.c +++ b/hw/s390x/virtio-ccw-blk.c @@ -32,7 +32,7 @@ static void virtio_ccw_blk_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK); object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); + "bootindex"); } static Property virtio_ccw_blk_properties[] = { diff --git a/hw/s390x/virtio-ccw-net.c b/hw/s390x/virtio-ccw-net.c index cd02699934..26c4d873bf 100644 --- a/hw/s390x/virtio-ccw-net.c +++ b/hw/s390x/virtio-ccw-net.c @@ -35,7 +35,7 @@ static void virtio_ccw_net_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); + "bootindex"); } static Property virtio_ccw_net_properties[] = { diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 1c980cab38..ab5459a589 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -268,7 +268,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, } dev = qdev_create(&bus->qbus, driver); name = g_strdup_printf("legacy[%d]", unit); - object_property_add_child(OBJECT(bus), name, OBJECT(dev), NULL); + object_property_add_child(OBJECT(bus), name, OBJECT(dev)); g_free(name); qdev_prop_set_uint32(dev, "scsi-id", unit); diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 7472d24e2c..8dda3f7292 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -795,7 +795,7 @@ static void ram_initfn(Object *obj) object_property_add_link(obj, "memdev", TYPE_MEMORY_BACKEND, (Object **)&d->memdev, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, &error_abort); + OBJ_PROP_LINK_STRONG); object_property_set_description(obj, "memdev", "Set RAM backend" "Valid value is ID of a hostmem backend"); } @@ -1060,7 +1060,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, qdev_prop_set_uint32(dev, "data_width", 1); qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, - OBJECT(fw_cfg), NULL); + OBJECT(fw_cfg)); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, CFG_ADDR); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 6abfcb30f8..3a757ec42e 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -691,7 +691,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, dev = qdev_create(NULL, TYPE_FW_CFG_IO); qdev_prop_set_bit(dev, "dma_enabled", false); - object_property_add_child(OBJECT(ebus), TYPE_FW_CFG, OBJECT(dev), NULL); + object_property_add_child(OBJECT(ebus), TYPE_FW_CFG, OBJECT(dev)); qdev_init_nofail(dev); memory_region_add_subregion(pci_address_space_io(ebus), BIOS_CFG_IOPORT, &FW_CFG_IO(dev)->comb_iomem); diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 4cfce882ab..e76cf290c8 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -1360,8 +1360,7 @@ static void xlnx_zynqmp_qspips_init(Object *obj) object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SLAVE, (Object **)&rq->dma, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, - NULL); + OBJ_PROP_LINK_STRONG); } static int xilinx_spips_post_load(void *opaque, int version_id) diff --git a/hw/usb/bus.c b/hw/usb/bus.c index c9a390063f..686f492112 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -753,12 +753,10 @@ static void usb_device_instance_init(Object *obj) if (klass->attached_settable) { object_property_add_bool(obj, "attached", - usb_get_attached, usb_set_attached, - NULL); + usb_get_attached, usb_set_attached); } else { object_property_add_bool(obj, "attached", - usb_get_attached, NULL, - NULL); + usb_get_attached, NULL); } } diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 5c4b57b06b..4eba47538d 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -753,7 +753,7 @@ static void usb_msd_instance_init(Object *obj) { object_property_add(obj, "bootindex", "int32", usb_msd_get_bootindex, - usb_msd_set_bootindex, NULL, NULL, NULL); + usb_msd_set_bootindex, NULL, NULL); object_property_set_int(obj, -1, "bootindex", NULL); } diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index 2d348f8237..3bd05fed12 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1634,7 +1634,7 @@ int vfio_pci_nvidia_v100_ram_init(VFIOPCIDevice *vdev, Error **errp) object_property_add(OBJECT(vdev), "nvlink2-tgt", "uint64", vfio_pci_nvlink2_get_tgt, NULL, NULL, - (void *) (uintptr_t) cap->tgt, NULL); + (void *) (uintptr_t) cap->tgt); trace_vfio_pci_nvidia_gpu_setup_quirk(vdev->vbasedev.name, cap->tgt, nv2reg->size); free_exit: @@ -1695,13 +1695,13 @@ int vfio_pci_nvlink2_init(VFIOPCIDevice *vdev, Error **errp) object_property_add(OBJECT(vdev), "nvlink2-tgt", "uint64", vfio_pci_nvlink2_get_tgt, NULL, NULL, - (void *) (uintptr_t) captgt->tgt, NULL); + (void *) (uintptr_t) captgt->tgt); trace_vfio_pci_nvlink2_setup_quirk_ssatgt(vdev->vbasedev.name, captgt->tgt, atsdreg->size); object_property_add(OBJECT(vdev), "nvlink2-link-speed", "uint32", vfio_pci_nvlink2_get_link_speed, NULL, NULL, - (void *) (uintptr_t) capspeed->link_speed, NULL); + (void *) (uintptr_t) capspeed->link_speed); trace_vfio_pci_nvlink2_setup_quirk_lnkspd(vdev->vbasedev.name, capspeed->link_speed); free_exit: diff --git a/hw/virtio/vhost-scsi-pci.c b/hw/virtio/vhost-scsi-pci.c index 5dce640eaf..5da6bb6449 100644 --- a/hw/virtio/vhost-scsi-pci.c +++ b/hw/virtio/vhost-scsi-pci.c @@ -78,7 +78,7 @@ static void vhost_scsi_pci_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); + "bootindex"); } static const VirtioPCIDeviceTypeInfo vhost_scsi_pci_info = { diff --git a/hw/virtio/vhost-user-blk-pci.c b/hw/virtio/vhost-user-blk-pci.c index 8d3d766427..58d7c31735 100644 --- a/hw/virtio/vhost-user-blk-pci.c +++ b/hw/virtio/vhost-user-blk-pci.c @@ -84,7 +84,7 @@ static void vhost_user_blk_pci_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VHOST_USER_BLK); object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); + "bootindex"); } static const VirtioPCIDeviceTypeInfo vhost_user_blk_pci_info = { diff --git a/hw/virtio/vhost-user-input-pci.c b/hw/virtio/vhost-user-input-pci.c index ae9cff9aed..0a50015599 100644 --- a/hw/virtio/vhost-user-input-pci.c +++ b/hw/virtio/vhost-user-input-pci.c @@ -31,8 +31,7 @@ static void vhost_user_input_pci_instance_init(Object *obj) TYPE_VHOST_USER_INPUT); object_property_add_alias(obj, "chardev", - OBJECT(&dev->vhi), "chardev", - &error_abort); + OBJECT(&dev->vhi), "chardev"); } static const VirtioPCIDeviceTypeInfo vhost_user_input_pci_info = { diff --git a/hw/virtio/vhost-user-scsi-pci.c b/hw/virtio/vhost-user-scsi-pci.c index 32febb2daa..6f3375fe55 100644 --- a/hw/virtio/vhost-user-scsi-pci.c +++ b/hw/virtio/vhost-user-scsi-pci.c @@ -84,7 +84,7 @@ static void vhost_user_scsi_pci_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VHOST_USER_SCSI); object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); + "bootindex"); } static const VirtioPCIDeviceTypeInfo vhost_user_scsi_pci_info = { diff --git a/hw/virtio/virtio-balloon-pci.c b/hw/virtio/virtio-balloon-pci.c index 56962aeb43..cc25df0a3d 100644 --- a/hw/virtio/virtio-balloon-pci.c +++ b/hw/virtio/virtio-balloon-pci.c @@ -73,10 +73,10 @@ static void virtio_balloon_pci_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON); object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev), - "guest-stats", &error_abort); + "guest-stats"); object_property_add_alias(obj, "guest-stats-polling-interval", OBJECT(&dev->vdev), - "guest-stats-polling-interval", &error_abort); + "guest-stats-polling-interval"); } static const VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = { diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index a4729f7fc9..6d3ddf6449 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -893,12 +893,12 @@ static void virtio_balloon_instance_init(Object *obj) VirtIOBalloon *s = VIRTIO_BALLOON(obj); object_property_add(obj, "guest-stats", "guest statistics", - balloon_stats_get_all, NULL, NULL, s, NULL); + balloon_stats_get_all, NULL, NULL, s); object_property_add(obj, "guest-stats-polling-interval", "int", balloon_stats_get_poll_interval, balloon_stats_set_poll_interval, - NULL, s, NULL); + NULL, s); } static const VMStateDescription vmstate_virtio_balloon = { diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c index efb2c22a1d..28838fa958 100644 --- a/hw/virtio/virtio-blk-pci.c +++ b/hw/virtio/virtio-blk-pci.c @@ -81,7 +81,7 @@ static void virtio_blk_pci_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK); object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); + "bootindex"); } static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = { diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c index 5ca71d4c34..ea43040f7b 100644 --- a/hw/virtio/virtio-net-pci.c +++ b/hw/virtio/virtio-net-pci.c @@ -79,7 +79,7 @@ static void virtio_net_pci_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); + "bootindex"); } static const VirtioPCIDeviceTypeInfo virtio_net_pci_info = { diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index 1e363ad07b..672619c780 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -203,7 +203,7 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp) } object_property_add_child(OBJECT(dev), "default-backend", - default_backend, &error_abort); + default_backend); /* The child property took a reference, we can safely drop ours now */ object_unref(default_backend); diff --git a/hw/xen/xen-common.c b/hw/xen/xen-common.c index adaab81ce0..70564cc952 100644 --- a/hw/xen/xen-common.c +++ b/hw/xen/xen-common.c @@ -198,8 +198,7 @@ static void xen_accel_class_init(ObjectClass *oc, void *data) compat_props_add(ac->compat_props, compat, G_N_ELEMENTS(compat)); object_class_property_add_bool(oc, "igd-passthru", - xen_get_igd_gfx_passthru, xen_set_igd_gfx_passthru, - &error_abort); + xen_get_igd_gfx_passthru, xen_set_igd_gfx_passthru); object_class_property_set_description(oc, "igd-passthru", "Set on/off to enable/disable igd passthrou"); } diff --git a/include/qom/object.h b/include/qom/object.h index 1f0386a231..990e28e408 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1036,7 +1036,6 @@ void object_unref(Object *obj); * meant to allow a property to free its opaque upon object * destruction. This may be NULL. * @opaque: an opaque pointer to pass to the callbacks for the property - * @errp: returns an error if this function fails * * Returns: The #ObjectProperty; this can be used to set the @resolve * callback for child and link properties. @@ -1046,7 +1045,7 @@ ObjectProperty *object_property_add(Object *obj, const char *name, ObjectPropertyAccessor *get, ObjectPropertyAccessor *set, ObjectPropertyRelease *release, - void *opaque, Error **errp); + void *opaque); void object_property_del(Object *obj, const char *name, Error **errp); @@ -1055,7 +1054,7 @@ ObjectProperty *object_class_property_add(ObjectClass *klass, const char *name, ObjectPropertyAccessor *get, ObjectPropertyAccessor *set, ObjectPropertyRelease *release, - void *opaque, Error **errp); + void *opaque); /** * object_property_set_default_bool: @@ -1480,7 +1479,6 @@ Object *object_resolve_path_component(Object *parent, const char *part); * @obj: the object to add a property to * @name: the name of the property * @child: the child object - * @errp: if an error occurs, a pointer to an area to store the error * * Child properties form the composition tree. All objects need to be a child * of another object. Objects can only be a child of one object. @@ -1495,7 +1493,7 @@ Object *object_resolve_path_component(Object *parent, const char *part); * Returns: The newly added property on success, or %NULL on failure. */ ObjectProperty *object_property_add_child(Object *obj, const char *name, - Object *child, Error **errp); + Object *child); typedef enum { /* Unref the link pointer when the property is deleted */ @@ -1524,7 +1522,6 @@ void object_property_allow_set_link(const Object *, const char *, * @targetp: a pointer to where the link object reference is stored * @check: callback to veto setting or NULL if the property is read-only * @flags: additional options for the link - * @errp: if an error occurs, a pointer to an area to store the error * * Links establish relationships between objects. Links are unidirectional * although two links can be combined to form a bidirectional relationship @@ -1551,16 +1548,14 @@ ObjectProperty *object_property_add_link(Object *obj, const char *name, const char *type, Object **targetp, void (*check)(const Object *obj, const char *name, Object *val, Error **errp), - ObjectPropertyLinkFlags flags, - Error **errp); + ObjectPropertyLinkFlags flags); ObjectProperty *object_class_property_add_link(ObjectClass *oc, const char *name, const char *type, ptrdiff_t offset, void (*check)(const Object *obj, const char *name, Object *val, Error **errp), - ObjectPropertyLinkFlags flags, - Error **errp); + ObjectPropertyLinkFlags flags); /** * object_property_add_str: @@ -1569,7 +1564,6 @@ ObjectProperty *object_class_property_add_link(ObjectClass *oc, * @get: the getter or NULL if the property is write-only. This function must * return a string to be freed by g_free(). * @set: the setter or NULL if the property is read-only - * @errp: if an error occurs, a pointer to an area to store the error * * Add a string property using getters/setters. This function will add a * property of type 'string'. @@ -1578,15 +1572,13 @@ ObjectProperty *object_class_property_add_link(ObjectClass *oc, */ ObjectProperty *object_property_add_str(Object *obj, const char *name, char *(*get)(Object *, Error **), - void (*set)(Object *, const char *, Error **), - Error **errp); + void (*set)(Object *, const char *, Error **)); ObjectProperty *object_class_property_add_str(ObjectClass *klass, const char *name, char *(*get)(Object *, Error **), void (*set)(Object *, const char *, - Error **), - Error **errp); + Error **)); /** * object_property_add_bool: @@ -1594,7 +1586,6 @@ ObjectProperty *object_class_property_add_str(ObjectClass *klass, * @name: the name of the property * @get: the getter or NULL if the property is write-only. * @set: the setter or NULL if the property is read-only - * @errp: if an error occurs, a pointer to an area to store the error * * Add a bool property using getters/setters. This function will add a * property of type 'bool'. @@ -1603,14 +1594,12 @@ ObjectProperty *object_class_property_add_str(ObjectClass *klass, */ ObjectProperty *object_property_add_bool(Object *obj, const char *name, bool (*get)(Object *, Error **), - void (*set)(Object *, bool, Error **), - Error **errp); + void (*set)(Object *, bool, Error **)); ObjectProperty *object_class_property_add_bool(ObjectClass *klass, const char *name, bool (*get)(Object *, Error **), - void (*set)(Object *, bool, Error **), - Error **errp); + void (*set)(Object *, bool, Error **)); /** * object_property_add_enum: @@ -1619,7 +1608,6 @@ ObjectProperty *object_class_property_add_bool(ObjectClass *klass, * @typename: the name of the enum data type * @get: the getter or %NULL if the property is write-only. * @set: the setter or %NULL if the property is read-only - * @errp: if an error occurs, a pointer to an area to store the error * * Add an enum property using getters/setters. This function will add a * property of type '@typename'. @@ -1630,23 +1618,20 @@ ObjectProperty *object_property_add_enum(Object *obj, const char *name, const char *typename, const QEnumLookup *lookup, int (*get)(Object *, Error **), - void (*set)(Object *, int, Error **), - Error **errp); + void (*set)(Object *, int, Error **)); ObjectProperty *object_class_property_add_enum(ObjectClass *klass, const char *name, const char *typename, const QEnumLookup *lookup, int (*get)(Object *, Error **), - void (*set)(Object *, int, Error **), - Error **errp); + void (*set)(Object *, int, Error **)); /** * object_property_add_tm: * @obj: the object to add a property to * @name: the name of the property * @get: the getter or NULL if the property is write-only. - * @errp: if an error occurs, a pointer to an area to store the error * * Add a read-only struct tm valued property using a getter function. * This function will add a property of type 'struct tm'. @@ -1654,13 +1639,11 @@ ObjectProperty *object_class_property_add_enum(ObjectClass *klass, * Returns: The newly added property on success, or %NULL on failure. */ ObjectProperty *object_property_add_tm(Object *obj, const char *name, - void (*get)(Object *, struct tm *, Error **), - Error **errp); + void (*get)(Object *, struct tm *, Error **)); ObjectProperty *object_class_property_add_tm(ObjectClass *klass, - const char *name, - void (*get)(Object *, struct tm *, Error **), - Error **errp); + const char *name, + void (*get)(Object *, struct tm *, Error **)); typedef enum { /* Automatically add a getter to the property */ @@ -1677,7 +1660,6 @@ typedef enum { * @name: the name of the property * @v: pointer to value * @flags: bitwise-or'd ObjectPropertyFlags - * @errp: if an error occurs, a pointer to an area to store the error * * Add an integer property in memory. This function will add a * property of type 'uint8'. @@ -1685,14 +1667,13 @@ typedef enum { * Returns: The newly added property on success, or %NULL on failure. */ ObjectProperty *object_property_add_uint8_ptr(Object *obj, const char *name, - const uint8_t *v, ObjectPropertyFlags flags, - Error **errp); + const uint8_t *v, + ObjectPropertyFlags flags); ObjectProperty *object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, const uint8_t *v, - ObjectPropertyFlags flags, - Error **errp); + ObjectPropertyFlags flags); /** * object_property_add_uint16_ptr: @@ -1700,7 +1681,6 @@ ObjectProperty *object_class_property_add_uint8_ptr(ObjectClass *klass, * @name: the name of the property * @v: pointer to value * @flags: bitwise-or'd ObjectPropertyFlags - * @errp: if an error occurs, a pointer to an area to store the error * * Add an integer property in memory. This function will add a * property of type 'uint16'. @@ -1709,14 +1689,12 @@ ObjectProperty *object_class_property_add_uint8_ptr(ObjectClass *klass, */ ObjectProperty *object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, - ObjectPropertyFlags flags, - Error **errp); + ObjectPropertyFlags flags); ObjectProperty *object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, const uint16_t *v, - ObjectPropertyFlags flags, - Error **errp); + ObjectPropertyFlags flags); /** * object_property_add_uint32_ptr: @@ -1724,7 +1702,6 @@ ObjectProperty *object_class_property_add_uint16_ptr(ObjectClass *klass, * @name: the name of the property * @v: pointer to value * @flags: bitwise-or'd ObjectPropertyFlags - * @errp: if an error occurs, a pointer to an area to store the error * * Add an integer property in memory. This function will add a * property of type 'uint32'. @@ -1733,14 +1710,12 @@ ObjectProperty *object_class_property_add_uint16_ptr(ObjectClass *klass, */ ObjectProperty *object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, - ObjectPropertyFlags flags, - Error **errp); + ObjectPropertyFlags flags); ObjectProperty *object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, const uint32_t *v, - ObjectPropertyFlags flags, - Error **errp); + ObjectPropertyFlags flags); /** * object_property_add_uint64_ptr: @@ -1748,7 +1723,6 @@ ObjectProperty *object_class_property_add_uint32_ptr(ObjectClass *klass, * @name: the name of the property * @v: pointer to value * @flags: bitwise-or'd ObjectPropertyFlags - * @errp: if an error occurs, a pointer to an area to store the error * * Add an integer property in memory. This function will add a * property of type 'uint64'. @@ -1757,14 +1731,12 @@ ObjectProperty *object_class_property_add_uint32_ptr(ObjectClass *klass, */ ObjectProperty *object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, - ObjectPropertyFlags flags, - Error **Errp); + ObjectPropertyFlags flags); ObjectProperty *object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, const uint64_t *v, - ObjectPropertyFlags flags, - Error **Errp); + ObjectPropertyFlags flags); /** * object_property_add_alias: @@ -1772,7 +1744,6 @@ ObjectProperty *object_class_property_add_uint64_ptr(ObjectClass *klass, * @name: the name of the property * @target_obj: the object to forward property access to * @target_name: the name of the property on the forwarded object - * @errp: if an error occurs, a pointer to an area to store the error * * Add an alias for a property on an object. This function will add a property * of the same type as the forwarded property. @@ -1785,15 +1756,13 @@ ObjectProperty *object_class_property_add_uint64_ptr(ObjectClass *klass, * Returns: The newly added property on success, or %NULL on failure. */ ObjectProperty *object_property_add_alias(Object *obj, const char *name, - Object *target_obj, const char *target_name, - Error **errp); + Object *target_obj, const char *target_name); /** * object_property_add_const_link: * @obj: the object to add a property to * @name: the name of the property * @target: the object to be referred by the link - * @errp: if an error occurs, a pointer to an area to store the error * * Add an unmodifiable link for a property on an object. This function will * add a property of type link where TYPE is the type of @target. @@ -1806,7 +1775,7 @@ ObjectProperty *object_property_add_alias(Object *obj, const char *name, * Returns: The newly added property on success, or %NULL on failure. */ ObjectProperty *object_property_add_const_link(Object *obj, const char *name, - Object *target, Error **errp); + Object *target); /** * object_property_set_description: diff --git a/iothread.c b/iothread.c index 7130be58e3..cb082b9b26 100644 --- a/iothread.c +++ b/iothread.c @@ -276,15 +276,15 @@ static void iothread_class_init(ObjectClass *klass, void *class_data) object_class_property_add(klass, "poll-max-ns", "int", iothread_get_poll_param, iothread_set_poll_param, - NULL, &poll_max_ns_info, &error_abort); + NULL, &poll_max_ns_info); object_class_property_add(klass, "poll-grow", "int", iothread_get_poll_param, iothread_set_poll_param, - NULL, &poll_grow_info, &error_abort); + NULL, &poll_grow_info); object_class_property_add(klass, "poll-shrink", "int", iothread_get_poll_param, iothread_set_poll_param, - NULL, &poll_shrink_info, &error_abort); + NULL, &poll_shrink_info); } static const TypeInfo iothread_info = { diff --git a/memory.c b/memory.c index 936c1b23d4..fd6f3d6aca 100644 --- a/memory.c +++ b/memory.c @@ -1154,7 +1154,7 @@ static void memory_region_do_init(MemoryRegion *mr, owner = container_get(qdev_get_machine(), "/unattached"); } - object_property_add_child(owner, name_array, OBJECT(mr), &error_abort); + object_property_add_child(owner, name_array, OBJECT(mr)); object_unref(OBJECT(mr)); g_free(name_array); g_free(escaped_name); @@ -1230,19 +1230,19 @@ static void memory_region_initfn(Object *obj) "link<" TYPE_MEMORY_REGION ">", memory_region_get_container, NULL, /* memory_region_set_container */ - NULL, NULL, &error_abort); + NULL, NULL); op->resolve = memory_region_resolve_container; object_property_add_uint64_ptr(OBJECT(mr), "addr", - &mr->addr, OBJ_PROP_FLAG_READ, &error_abort); + &mr->addr, OBJ_PROP_FLAG_READ); object_property_add(OBJECT(mr), "priority", "uint32", memory_region_get_priority, NULL, /* memory_region_set_priority */ - NULL, NULL, &error_abort); + NULL, NULL); object_property_add(OBJECT(mr), "size", "uint64", memory_region_get_size, NULL, /* memory_region_set_size, */ - NULL, NULL, &error_abort); + NULL, NULL); } static void iommu_memory_region_initfn(Object *obj) diff --git a/net/can/can_host.c b/net/can/can_host.c index 1dfaf0ced0..be4547d913 100644 --- a/net/can/can_host.c +++ b/net/can/can_host.c @@ -79,8 +79,7 @@ static void can_host_instance_init(Object *obj) object_property_add_link(obj, "canbus", TYPE_CAN_BUS, (Object **)&ch->bus, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); } static void can_host_class_init(ObjectClass *klass, diff --git a/net/can/can_socketcan.c b/net/can/can_socketcan.c index 807f31fcde..b7ef63ec0e 100644 --- a/net/can/can_socketcan.c +++ b/net/can/can_socketcan.c @@ -266,8 +266,7 @@ static void can_host_socketcan_class_init(ObjectClass *klass, object_class_property_add_str(klass, "if", can_host_socketcan_get_if, - can_host_socketcan_set_if, - &error_abort); + can_host_socketcan_set_if); chc->connect = can_host_socketcan_connect; chc->disconnect = can_host_socketcan_disconnect; } diff --git a/net/colo-compare.c b/net/colo-compare.c index 10c0239f9d..c07e7c1c09 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -1245,34 +1245,30 @@ static void colo_compare_init(Object *obj) CompareState *s = COLO_COMPARE(obj); object_property_add_str(obj, "primary_in", - compare_get_pri_indev, compare_set_pri_indev, - NULL); + compare_get_pri_indev, compare_set_pri_indev); object_property_add_str(obj, "secondary_in", - compare_get_sec_indev, compare_set_sec_indev, - NULL); + compare_get_sec_indev, compare_set_sec_indev); object_property_add_str(obj, "outdev", - compare_get_outdev, compare_set_outdev, - NULL); + compare_get_outdev, compare_set_outdev); object_property_add_link(obj, "iothread", TYPE_IOTHREAD, (Object **)&s->iothread, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, NULL); + OBJ_PROP_LINK_STRONG); /* This parameter just for Xen COLO */ object_property_add_str(obj, "notify_dev", - compare_get_notify_dev, compare_set_notify_dev, - NULL); + compare_get_notify_dev, compare_set_notify_dev); object_property_add(obj, "compare_timeout", "uint32", compare_get_timeout, - compare_set_timeout, NULL, NULL, NULL); + compare_set_timeout, NULL, NULL); object_property_add(obj, "expired_scan_cycle", "uint32", compare_get_expired_scan_cycle, - compare_set_expired_scan_cycle, NULL, NULL, NULL); + compare_set_expired_scan_cycle, NULL, NULL); s->vnet_hdr = false; object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr, - compare_set_vnet_hdr, NULL); + compare_set_vnet_hdr); } static void colo_compare_finalize(Object *obj) diff --git a/net/dump.c b/net/dump.c index 23b3628dde..61389e7dad 100644 --- a/net/dump.c +++ b/net/dump.c @@ -232,9 +232,9 @@ static void filter_dump_instance_init(Object *obj) nfds->maxlen = 65536; object_property_add(obj, "maxlen", "uint32", filter_dump_get_maxlen, - filter_dump_set_maxlen, NULL, NULL, NULL); + filter_dump_set_maxlen, NULL, NULL); object_property_add_str(obj, "file", file_dump_get_filename, - file_dump_set_filename, NULL); + file_dump_set_filename); } static void filter_dump_instance_finalize(Object *obj) diff --git a/net/filter-buffer.c b/net/filter-buffer.c index 12e0254287..93050f86cf 100644 --- a/net/filter-buffer.c +++ b/net/filter-buffer.c @@ -192,7 +192,7 @@ static void filter_buffer_init(Object *obj) { object_property_add(obj, "interval", "uint32", filter_buffer_get_interval, - filter_buffer_set_interval, NULL, NULL, NULL); + filter_buffer_set_interval, NULL, NULL); } static const TypeInfo filter_buffer_info = { diff --git a/net/filter-mirror.c b/net/filter-mirror.c index d83e815545..e9379ce248 100644 --- a/net/filter-mirror.c +++ b/net/filter-mirror.c @@ -392,12 +392,12 @@ static void filter_mirror_init(Object *obj) MirrorState *s = FILTER_MIRROR(obj); object_property_add_str(obj, "outdev", filter_mirror_get_outdev, - filter_mirror_set_outdev, NULL); + filter_mirror_set_outdev); s->vnet_hdr = false; object_property_add_bool(obj, "vnet_hdr_support", filter_mirror_get_vnet_hdr, - filter_mirror_set_vnet_hdr, NULL); + filter_mirror_set_vnet_hdr); } static void filter_redirector_init(Object *obj) @@ -405,14 +405,14 @@ static void filter_redirector_init(Object *obj) MirrorState *s = FILTER_REDIRECTOR(obj); object_property_add_str(obj, "indev", filter_redirector_get_indev, - filter_redirector_set_indev, NULL); + filter_redirector_set_indev); object_property_add_str(obj, "outdev", filter_redirector_get_outdev, - filter_redirector_set_outdev, NULL); + filter_redirector_set_outdev); s->vnet_hdr = false; object_property_add_bool(obj, "vnet_hdr_support", filter_redirector_get_vnet_hdr, - filter_redirector_set_vnet_hdr, NULL); + filter_redirector_set_vnet_hdr); } static void filter_mirror_fini(Object *obj) diff --git a/net/filter-rewriter.c b/net/filter-rewriter.c index 31da08a2f4..1aaad101b6 100644 --- a/net/filter-rewriter.c +++ b/net/filter-rewriter.c @@ -413,7 +413,7 @@ static void filter_rewriter_init(Object *obj) s->failover_mode = FAILOVER_MODE_OFF; object_property_add_bool(obj, "vnet_hdr_support", filter_rewriter_get_vnet_hdr, - filter_rewriter_set_vnet_hdr, NULL); + filter_rewriter_set_vnet_hdr); } static void colo_rewriter_class_init(ObjectClass *oc, void *data) diff --git a/net/filter.c b/net/filter.c index 8221666263..caf6443655 100644 --- a/net/filter.c +++ b/net/filter.c @@ -214,21 +214,16 @@ static void netfilter_init(Object *obj) nf->position = g_strdup("tail"); object_property_add_str(obj, "netdev", - netfilter_get_netdev_id, netfilter_set_netdev_id, - NULL); + netfilter_get_netdev_id, netfilter_set_netdev_id); object_property_add_enum(obj, "queue", "NetFilterDirection", &NetFilterDirection_lookup, - netfilter_get_direction, netfilter_set_direction, - NULL); + netfilter_get_direction, netfilter_set_direction); object_property_add_str(obj, "status", - netfilter_get_status, netfilter_set_status, - NULL); + netfilter_get_status, netfilter_set_status); object_property_add_str(obj, "position", - netfilter_get_position, netfilter_set_position, - NULL); + netfilter_get_position, netfilter_set_position); object_property_add_str(obj, "insert", - netfilter_get_insert, netfilter_set_insert, - NULL); + netfilter_get_insert, netfilter_set_insert); } static void netfilter_complete(UserCreatable *uc, Error **errp) diff --git a/qdev-monitor.c b/qdev-monitor.c index 56cee1483f..a4735d3bb1 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -562,12 +562,12 @@ void qdev_set_id(DeviceState *dev, const char *id) if (dev->id) { object_property_add_child(qdev_get_peripheral(), dev->id, - OBJECT(dev), NULL); + OBJECT(dev)); } else { static int anon_count; gchar *name = g_strdup_printf("device[%d]", anon_count++); object_property_add_child(qdev_get_peripheral_anon(), name, - OBJECT(dev), NULL); + OBJECT(dev)); g_free(name); } } diff --git a/qom/container.c b/qom/container.c index e635e8ee76..14e7ae485b 100644 --- a/qom/container.c +++ b/qom/container.c @@ -39,7 +39,7 @@ Object *container_get(Object *root, const char *path) child = object_resolve_path_component(obj, parts[i]); if (!child) { child = object_new("container"); - object_property_add_child(obj, parts[i], child, NULL); + object_property_add_child(obj, parts[i], child); object_unref(child); } } diff --git a/qom/object.c b/qom/object.c index 58a6ec9b1b..23f481ca46 100644 --- a/qom/object.c +++ b/qom/object.c @@ -557,10 +557,7 @@ void object_initialize_childv(Object *parentobj, const char *propname, goto out; } - object_property_add_child(parentobj, propname, obj, &local_err); - if (local_err) { - goto out; - } + object_property_add_child(parentobj, propname, obj); uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE); if (uc) { @@ -745,10 +742,7 @@ Object *object_new_with_propv(const char *typename, } if (id != NULL) { - object_property_add_child(parent, id, obj, &local_err); - if (local_err) { - goto error; - } + object_property_add_child(parent, id, obj); } uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE); @@ -1129,12 +1123,12 @@ void object_unref(Object *obj) } } -ObjectProperty * -object_property_add(Object *obj, const char *name, const char *type, - ObjectPropertyAccessor *get, - ObjectPropertyAccessor *set, - ObjectPropertyRelease *release, - void *opaque, Error **errp) +static ObjectProperty * +object_property_try_add(Object *obj, const char *name, const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp) { ObjectProperty *prop; size_t name_len = strlen(name); @@ -1148,8 +1142,8 @@ object_property_add(Object *obj, const char *name, const char *type, for (i = 0; ; ++i) { char *full_name = g_strdup_printf("%s[%d]", name_no_array, i); - ret = object_property_add(obj, full_name, type, get, set, - release, opaque, NULL); + ret = object_property_try_add(obj, full_name, type, get, set, + release, opaque, NULL); g_free(full_name); if (ret) { break; @@ -1179,6 +1173,17 @@ object_property_add(Object *obj, const char *name, const char *type, return prop; } +ObjectProperty * +object_property_add(Object *obj, const char *name, const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque) +{ + return object_property_try_add(obj, name, type, get, set, release, + opaque, &error_abort); +} + ObjectProperty * object_class_property_add(ObjectClass *klass, const char *name, @@ -1186,16 +1191,11 @@ object_class_property_add(ObjectClass *klass, ObjectPropertyAccessor *get, ObjectPropertyAccessor *set, ObjectPropertyRelease *release, - void *opaque, - Error **errp) + void *opaque) { ObjectProperty *prop; - if (object_class_property_find(klass, name, NULL) != NULL) { - error_setg(errp, "attempt to add duplicate property '%s' to class (type '%s')", - name, object_class_get_name(klass)); - return NULL; - } + assert(!object_class_property_find(klass, name, NULL)); prop = g_malloc0(sizeof(*prop)); @@ -1648,24 +1648,17 @@ static void object_finalize_child_property(Object *obj, const char *name, ObjectProperty * object_property_add_child(Object *obj, const char *name, - Object *child, Error **errp) + Object *child) { g_autofree char *type = NULL; ObjectProperty *op; - if (child->parent != NULL) { - error_setg(errp, "child object is already parented"); - return NULL; - } + assert(!child->parent); type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); op = object_property_add(obj, name, type, object_get_child_property, NULL, - object_finalize_child_property, child, errp); - if (!op) { - return NULL; - } - + object_finalize_child_property, child); op->resolve = object_resolve_child_property; object_ref(child); child->parent = obj; @@ -1821,8 +1814,7 @@ object_add_link_prop(Object *obj, const char *name, const char *type, void *ptr, void (*check)(const Object *, const char *, Object *, Error **), - ObjectPropertyLinkFlags flags, - Error **errp) + ObjectPropertyLinkFlags flags) { LinkProperty *prop = g_malloc(sizeof(*prop)); g_autofree char *full_type = NULL; @@ -1842,13 +1834,7 @@ object_add_link_prop(Object *obj, const char *name, object_get_link_property, check ? object_set_link_property : NULL, object_release_link_property, - prop, - errp); - if (!op) { - g_free(prop); - return NULL; - } - + prop); op->resolve = object_resolve_link_property; return op; } @@ -1858,11 +1844,9 @@ object_property_add_link(Object *obj, const char *name, const char *type, Object **targetp, void (*check)(const Object *, const char *, Object *, Error **), - ObjectPropertyLinkFlags flags, - Error **errp) + ObjectPropertyLinkFlags flags) { - return object_add_link_prop(obj, name, type, targetp, check, flags, - errp); + return object_add_link_prop(obj, name, type, targetp, check, flags); } ObjectProperty * @@ -1871,10 +1855,8 @@ object_class_property_add_link(ObjectClass *oc, const char *type, ptrdiff_t offset, void (*check)(const Object *obj, const char *name, Object *val, Error **errp), - ObjectPropertyLinkFlags flags, - Error **errp) + ObjectPropertyLinkFlags flags) { - Error *local_err = NULL; LinkProperty *prop = g_new0(LinkProperty, 1); char *full_type; ObjectProperty *op; @@ -1889,28 +1871,21 @@ object_class_property_add_link(ObjectClass *oc, object_get_link_property, check ? object_set_link_property : NULL, object_release_link_property, - prop, - &local_err); - if (local_err) { - error_propagate(errp, local_err); - g_free(prop); - goto out; - } + prop); op->resolve = object_resolve_link_property; -out: g_free(full_type); return op; } ObjectProperty * object_property_add_const_link(Object *obj, const char *name, - Object *target, Error **errp) + Object *target) { return object_add_link_prop(obj, name, object_get_typename(target), target, - NULL, OBJ_PROP_LINK_DIRECT, errp); + NULL, OBJ_PROP_LINK_DIRECT); } char *object_get_canonical_path_component(Object *obj) @@ -2122,51 +2097,36 @@ static void property_release_str(Object *obj, const char *name, ObjectProperty * object_property_add_str(Object *obj, const char *name, char *(*get)(Object *, Error **), - void (*set)(Object *, const char *, Error **), - Error **errp) + void (*set)(Object *, const char *, Error **)) { StringProperty *prop = g_malloc0(sizeof(*prop)); - ObjectProperty *op; prop->get = get; prop->set = set; - op = object_property_add(obj, name, "string", - get ? property_get_str : NULL, - set ? property_set_str : NULL, - property_release_str, - prop, errp); - if (!op) { - g_free(prop); - } - return op; + return object_property_add(obj, name, "string", + get ? property_get_str : NULL, + set ? property_set_str : NULL, + property_release_str, + prop); } ObjectProperty * object_class_property_add_str(ObjectClass *klass, const char *name, char *(*get)(Object *, Error **), void (*set)(Object *, const char *, - Error **), - Error **errp) + Error **)) { - Error *local_err = NULL; StringProperty *prop = g_malloc0(sizeof(*prop)); - ObjectProperty *rv; prop->get = get; prop->set = set; - rv = object_class_property_add(klass, name, "string", - get ? property_get_str : NULL, - set ? property_set_str : NULL, - NULL, - prop, &local_err); - if (local_err) { - error_propagate(errp, local_err); - g_free(prop); - } - - return rv; + return object_class_property_add(klass, name, "string", + get ? property_get_str : NULL, + set ? property_set_str : NULL, + NULL, + prop); } typedef struct BoolProperty @@ -2217,50 +2177,35 @@ static void property_release_bool(Object *obj, const char *name, ObjectProperty * object_property_add_bool(Object *obj, const char *name, bool (*get)(Object *, Error **), - void (*set)(Object *, bool, Error **), - Error **errp) + void (*set)(Object *, bool, Error **)) { BoolProperty *prop = g_malloc0(sizeof(*prop)); - ObjectProperty *op; prop->get = get; prop->set = set; - op = object_property_add(obj, name, "bool", - get ? property_get_bool : NULL, - set ? property_set_bool : NULL, - property_release_bool, - prop, errp); - if (!op) { - g_free(prop); - } - return op; + return object_property_add(obj, name, "bool", + get ? property_get_bool : NULL, + set ? property_set_bool : NULL, + property_release_bool, + prop); } ObjectProperty * object_class_property_add_bool(ObjectClass *klass, const char *name, bool (*get)(Object *, Error **), - void (*set)(Object *, bool, Error **), - Error **errp) + void (*set)(Object *, bool, Error **)) { - Error *local_err = NULL; BoolProperty *prop = g_malloc0(sizeof(*prop)); - ObjectProperty *rv; prop->get = get; prop->set = set; - rv = object_class_property_add(klass, name, "bool", - get ? property_get_bool : NULL, - set ? property_set_bool : NULL, - NULL, - prop, &local_err); - if (local_err) { - error_propagate(errp, local_err); - g_free(prop); - } - - return rv; + return object_class_property_add(klass, name, "bool", + get ? property_get_bool : NULL, + set ? property_set_bool : NULL, + NULL, + prop); } static void property_get_enum(Object *obj, Visitor *v, const char *name, @@ -2306,25 +2251,19 @@ object_property_add_enum(Object *obj, const char *name, const char *typename, const QEnumLookup *lookup, int (*get)(Object *, Error **), - void (*set)(Object *, int, Error **), - Error **errp) + void (*set)(Object *, int, Error **)) { EnumProperty *prop = g_malloc(sizeof(*prop)); - ObjectProperty *op; prop->lookup = lookup; prop->get = get; prop->set = set; - op = object_property_add(obj, name, typename, - get ? property_get_enum : NULL, - set ? property_set_enum : NULL, - property_release_enum, - prop, errp); - if (!op) { - g_free(prop); - } - return op; + return object_property_add(obj, name, typename, + get ? property_get_enum : NULL, + set ? property_set_enum : NULL, + property_release_enum, + prop); } ObjectProperty * @@ -2332,28 +2271,19 @@ object_class_property_add_enum(ObjectClass *klass, const char *name, const char *typename, const QEnumLookup *lookup, int (*get)(Object *, Error **), - void (*set)(Object *, int, Error **), - Error **errp) + void (*set)(Object *, int, Error **)) { - Error *local_err = NULL; EnumProperty *prop = g_malloc(sizeof(*prop)); - ObjectProperty *rv; prop->lookup = lookup; prop->get = get; prop->set = set; - rv = object_class_property_add(klass, name, typename, - get ? property_get_enum : NULL, - set ? property_set_enum : NULL, - NULL, - prop, &local_err); - if (local_err) { - error_propagate(errp, local_err); - g_free(prop); - } - - return rv; + return object_class_property_add(klass, name, typename, + get ? property_get_enum : NULL, + set ? property_set_enum : NULL, + NULL, + prop); } typedef struct TMProperty { @@ -2417,45 +2347,29 @@ static void property_release_tm(Object *obj, const char *name, ObjectProperty * object_property_add_tm(Object *obj, const char *name, - void (*get)(Object *, struct tm *, Error **), - Error **errp) + void (*get)(Object *, struct tm *, Error **)) { TMProperty *prop = g_malloc0(sizeof(*prop)); - ObjectProperty *op; prop->get = get; - op = object_property_add(obj, name, "struct tm", - get ? property_get_tm : NULL, NULL, - property_release_tm, - prop, errp); - if (!op) { - g_free(prop); - } - return op; + return object_property_add(obj, name, "struct tm", + get ? property_get_tm : NULL, NULL, + property_release_tm, + prop); } ObjectProperty * object_class_property_add_tm(ObjectClass *klass, const char *name, - void (*get)(Object *, struct tm *, Error **), - Error **errp) + void (*get)(Object *, struct tm *, Error **)) { - Error *local_err = NULL; TMProperty *prop = g_malloc0(sizeof(*prop)); - ObjectProperty *rv; prop->get = get; - rv = object_class_property_add(klass, name, "struct tm", - get ? property_get_tm : NULL, NULL, - NULL, - prop, &local_err); - if (local_err) { - error_propagate(errp, local_err); - g_free(prop); - } - - return rv; + return object_class_property_add(klass, name, "struct tm", + get ? property_get_tm : NULL, + NULL, NULL, prop); } static char *qdev_get_type(Object *obj, Error **errp) @@ -2558,8 +2472,7 @@ static void property_set_uint64_ptr(Object *obj, Visitor *v, const char *name, ObjectProperty * object_property_add_uint8_ptr(Object *obj, const char *name, const uint8_t *v, - ObjectPropertyFlags flags, - Error **errp) + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2573,14 +2486,13 @@ object_property_add_uint8_ptr(Object *obj, const char *name, } return object_property_add(obj, name, "uint8", - getter, setter, NULL, (void *)v, errp); + getter, setter, NULL, (void *)v); } ObjectProperty * object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, const uint8_t *v, - ObjectPropertyFlags flags, - Error **errp) + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2594,14 +2506,13 @@ object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, } return object_class_property_add(klass, name, "uint8", - getter, setter, NULL, (void *)v, errp); + getter, setter, NULL, (void *)v); } ObjectProperty * object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, - ObjectPropertyFlags flags, - Error **errp) + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2615,14 +2526,13 @@ object_property_add_uint16_ptr(Object *obj, const char *name, } return object_property_add(obj, name, "uint16", - getter, setter, NULL, (void *)v, errp); + getter, setter, NULL, (void *)v); } ObjectProperty * object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, const uint16_t *v, - ObjectPropertyFlags flags, - Error **errp) + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2636,14 +2546,13 @@ object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, } return object_class_property_add(klass, name, "uint16", - getter, setter, NULL, (void *)v, errp); + getter, setter, NULL, (void *)v); } ObjectProperty * object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, - ObjectPropertyFlags flags, - Error **errp) + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2657,14 +2566,13 @@ object_property_add_uint32_ptr(Object *obj, const char *name, } return object_property_add(obj, name, "uint32", - getter, setter, NULL, (void *)v, errp); + getter, setter, NULL, (void *)v); } ObjectProperty * object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, const uint32_t *v, - ObjectPropertyFlags flags, - Error **errp) + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2678,14 +2586,13 @@ object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, } return object_class_property_add(klass, name, "uint32", - getter, setter, NULL, (void *)v, errp); + getter, setter, NULL, (void *)v); } ObjectProperty * object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, - ObjectPropertyFlags flags, - Error **errp) + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2699,14 +2606,13 @@ object_property_add_uint64_ptr(Object *obj, const char *name, } return object_property_add(obj, name, "uint64", - getter, setter, NULL, (void *)v, errp); + getter, setter, NULL, (void *)v); } ObjectProperty * object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, const uint64_t *v, - ObjectPropertyFlags flags, - Error **errp) + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2720,7 +2626,7 @@ object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, } return object_class_property_add(klass, name, "uint64", - getter, setter, NULL, (void *)v, errp); + getter, setter, NULL, (void *)v); } typedef struct { @@ -2762,18 +2668,15 @@ static void property_release_alias(Object *obj, const char *name, void *opaque) ObjectProperty * object_property_add_alias(Object *obj, const char *name, - Object *target_obj, const char *target_name, - Error **errp) + Object *target_obj, const char *target_name) { AliasProperty *prop; ObjectProperty *op; ObjectProperty *target_prop; g_autofree char *prop_type = NULL; - target_prop = object_property_find(target_obj, target_name, errp); - if (!target_prop) { - return NULL; - } + target_prop = object_property_find(target_obj, target_name, + &error_abort); if (object_property_is_child(target_prop)) { prop_type = g_strdup_printf("link%s", @@ -2790,12 +2693,7 @@ object_property_add_alias(Object *obj, const char *name, property_get_alias, property_set_alias, property_release_alias, - prop, errp); - if (!op) { - g_free(prop); - return NULL; - } - + prop); op->resolve = property_resolve_alias; if (target_prop->defval) { op->defval = qobject_ref(target_prop->defval); @@ -2830,7 +2728,7 @@ void object_class_property_set_description(ObjectClass *klass, static void object_class_init(ObjectClass *klass, void *data) { object_class_property_add_str(klass, "type", qdev_get_type, - NULL, &error_abort); + NULL); } static void register_types(void) diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index bc36f96e47..054e75043d 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -83,10 +83,7 @@ Object *user_creatable_add_type(const char *type, const char *id, if (id != NULL) { object_property_add_child(object_get_objects_root(), - id, obj, &local_err); - if (local_err) { - goto out; - } + id, obj); } user_creatable_complete(USER_CREATABLE(obj), &local_err); diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c index ca27c93283..bf62cbec11 100644 --- a/scsi/pr-manager-helper.c +++ b/scsi/pr-manager-helper.c @@ -307,8 +307,7 @@ static void pr_manager_helper_class_init(ObjectClass *klass, PRManagerClass *prmgr_klass = PR_MANAGER_CLASS(klass); UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass); - object_class_property_add_str(klass, "path", get_path, set_path, - &error_abort); + object_class_property_add_str(klass, "path", get_path, set_path); uc_klass->complete = pr_manager_helper_complete; prmgr_klass->run = pr_manager_helper_run; prmgr_klass->is_connected = pr_manager_helper_is_connected; diff --git a/softmmu/vl.c b/softmmu/vl.c index afd2615fb3..f84151acd3 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2802,7 +2802,7 @@ static void create_default_memdev(MachineState *ms, const char *path) } object_property_set_int(obj, ms->ram_size, "size", &error_fatal); object_property_add_child(object_get_objects_root(), mc->default_ram_id, - obj, &error_fatal); + obj); /* Ensure backend's memory region name is equal to mc->default_ram_id */ object_property_set_bool(obj, false, "x-use-canonical-path-for-ramblock-id", &error_fatal); @@ -3878,11 +3878,10 @@ void qemu_init(int argc, char **argv, char **envp) exit(0); } object_property_add_child(object_get_root(), "machine", - OBJECT(current_machine), &error_abort); + OBJECT(current_machine)); object_property_add_child(container_get(OBJECT(current_machine), "/unattached"), - "sysbus", OBJECT(sysbus_get_default()), - NULL); + "sysbus", OBJECT(sysbus_get_default())); if (machine_class->minimum_page_bits) { if (!set_preferred_target_page_bits(machine_class->minimum_page_bits)) { diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 3794f0dbc4..32bec156f2 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1179,8 +1179,7 @@ void arm_cpu_post_init(Object *obj) TYPE_MEMORY_REGION, (Object **)&cpu->secure_memory, qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); } if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) { @@ -1190,8 +1189,7 @@ void arm_cpu_post_init(Object *obj) if (arm_feature(&cpu->env, ARM_FEATURE_PMU)) { cpu->has_pmu = true; - object_property_add_bool(obj, "pmu", arm_get_pmu, arm_set_pmu, - &error_abort); + object_property_add_bool(obj, "pmu", arm_get_pmu, arm_set_pmu); } /* @@ -1231,8 +1229,7 @@ void arm_cpu_post_init(Object *obj) if (arm_feature(&cpu->env, ARM_FEATURE_M_SECURITY)) { object_property_add_link(obj, "idau", TYPE_IDAU_INTERFACE, &cpu->idau, qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); /* * M profile: initial value of the Secure VTOR. We can't just use * a simple DEFINE_PROP_UINT32 for this because we want to permit @@ -1240,7 +1237,7 @@ void arm_cpu_post_init(Object *obj) */ object_property_add_uint32_ptr(obj, "init-svtor", &cpu->init_svtor, - OBJ_PROP_FLAG_READWRITE, &error_abort); + OBJ_PROP_FLAG_READWRITE); } qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property); diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 18a0af88e2..cbc5c3868f 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -571,13 +571,13 @@ void aarch64_add_sve_properties(Object *obj) uint32_t vq; object_property_add(obj, "sve", "bool", cpu_arm_get_sve, - cpu_arm_set_sve, NULL, NULL, &error_fatal); + cpu_arm_set_sve, NULL, NULL); for (vq = 1; vq <= ARM_MAX_VQ; ++vq) { char name[8]; sprintf(name, "sve%d", vq * 128); object_property_add(obj, name, "bool", cpu_arm_get_sve_vq, - cpu_arm_set_sve_vq, NULL, NULL, &error_fatal); + cpu_arm_set_sve_vq, NULL, NULL); } } @@ -726,7 +726,7 @@ static void aarch64_max_initfn(Object *obj) aarch64_add_sve_properties(obj); object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq, - cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal); + cpu_max_set_sve_max_vq, NULL, NULL); } static const ARMCPUInfo aarch64_cpus[] = { @@ -767,7 +767,7 @@ static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp) static void aarch64_cpu_initfn(Object *obj) { object_property_add_bool(obj, "aarch64", aarch64_cpu_get_aarch64, - aarch64_cpu_set_aarch64, NULL); + aarch64_cpu_set_aarch64); object_property_set_description(obj, "aarch64", "Set on/off to enable/disable aarch64 " "execution state "); diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 1ea2d047e3..4bdbe6dcac 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -200,7 +200,7 @@ void kvm_arm_add_vcpu_properties(Object *obj) ARM_CPU(obj)->kvm_adjvtime = true; object_property_add_bool(obj, "kvm-no-adjvtime", kvm_no_adjvtime_get, - kvm_no_adjvtime_set, &error_abort); + kvm_no_adjvtime_set); object_property_set_description(obj, "kvm-no-adjvtime", "Set on to disable the adjustment of " "the virtual counter. VM stopped time " diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 9c256ab159..6a64d2a5cd 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6110,7 +6110,7 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) cpu->apic_state = DEVICE(object_new_with_class(apic_class)); object_property_add_child(OBJECT(cpu), "lapic", - OBJECT(cpu->apic_state), &error_abort); + OBJECT(cpu->apic_state)); object_unref(OBJECT(cpu->apic_state)); qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id); @@ -6822,7 +6822,7 @@ static void x86_cpu_register_bit_prop(X86CPU *cpu, object_property_add(OBJECT(cpu), prop_name, "bool", x86_cpu_get_bit_prop, x86_cpu_set_bit_prop, - x86_cpu_release_bit_prop, fp, &error_abort); + x86_cpu_release_bit_prop, fp); } } @@ -6905,28 +6905,28 @@ static void x86_cpu_initfn(Object *obj) object_property_add(obj, "family", "int", x86_cpuid_version_get_family, - x86_cpuid_version_set_family, NULL, NULL, NULL); + x86_cpuid_version_set_family, NULL, NULL); object_property_add(obj, "model", "int", x86_cpuid_version_get_model, - x86_cpuid_version_set_model, NULL, NULL, NULL); + x86_cpuid_version_set_model, NULL, NULL); object_property_add(obj, "stepping", "int", x86_cpuid_version_get_stepping, - x86_cpuid_version_set_stepping, NULL, NULL, NULL); + x86_cpuid_version_set_stepping, NULL, NULL); object_property_add_str(obj, "vendor", x86_cpuid_get_vendor, - x86_cpuid_set_vendor, NULL); + x86_cpuid_set_vendor); object_property_add_str(obj, "model-id", x86_cpuid_get_model_id, - x86_cpuid_set_model_id, NULL); + x86_cpuid_set_model_id); object_property_add(obj, "tsc-frequency", "int", x86_cpuid_get_tsc_freq, - x86_cpuid_set_tsc_freq, NULL, NULL, NULL); + x86_cpuid_set_tsc_freq, NULL, NULL); object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo", x86_cpu_get_feature_words, - NULL, NULL, (void *)env->features, NULL); + NULL, NULL, (void *)env->features); object_property_add(obj, "filtered-features", "X86CPUFeatureWordInfo", x86_cpu_get_feature_words, - NULL, NULL, (void *)cpu->filtered_features, NULL); + NULL, NULL, (void *)cpu->filtered_features); /* * The "unavailable-features" property has the same semantics as * CpuDefinitionInfo.unavailable-features on the "query-cpu-definitions" @@ -6935,10 +6935,10 @@ static void x86_cpu_initfn(Object *obj) */ object_property_add(obj, "unavailable-features", "strList", x86_cpu_get_unavailable_features, - NULL, NULL, NULL, &error_abort); + NULL, NULL, NULL); object_property_add(obj, "crash-information", "GuestPanicInformation", - x86_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL); + x86_cpu_get_crash_info_qom, NULL, NULL, NULL); for (w = 0; w < FEATURE_WORDS; w++) { int bitnr; @@ -6948,37 +6948,36 @@ static void x86_cpu_initfn(Object *obj) } } - object_property_add_alias(obj, "sse3", obj, "pni", &error_abort); - object_property_add_alias(obj, "pclmuldq", obj, "pclmulqdq", &error_abort); - object_property_add_alias(obj, "sse4-1", obj, "sse4.1", &error_abort); - object_property_add_alias(obj, "sse4-2", obj, "sse4.2", &error_abort); - object_property_add_alias(obj, "xd", obj, "nx", &error_abort); - object_property_add_alias(obj, "ffxsr", obj, "fxsr-opt", &error_abort); - object_property_add_alias(obj, "i64", obj, "lm", &error_abort); + object_property_add_alias(obj, "sse3", obj, "pni"); + object_property_add_alias(obj, "pclmuldq", obj, "pclmulqdq"); + object_property_add_alias(obj, "sse4-1", obj, "sse4.1"); + object_property_add_alias(obj, "sse4-2", obj, "sse4.2"); + object_property_add_alias(obj, "xd", obj, "nx"); + object_property_add_alias(obj, "ffxsr", obj, "fxsr-opt"); + object_property_add_alias(obj, "i64", obj, "lm"); - object_property_add_alias(obj, "ds_cpl", obj, "ds-cpl", &error_abort); - object_property_add_alias(obj, "tsc_adjust", obj, "tsc-adjust", &error_abort); - object_property_add_alias(obj, "fxsr_opt", obj, "fxsr-opt", &error_abort); - object_property_add_alias(obj, "lahf_lm", obj, "lahf-lm", &error_abort); - object_property_add_alias(obj, "cmp_legacy", obj, "cmp-legacy", &error_abort); - object_property_add_alias(obj, "nodeid_msr", obj, "nodeid-msr", &error_abort); - object_property_add_alias(obj, "perfctr_core", obj, "perfctr-core", &error_abort); - object_property_add_alias(obj, "perfctr_nb", obj, "perfctr-nb", &error_abort); - object_property_add_alias(obj, "kvm_nopiodelay", obj, "kvm-nopiodelay", &error_abort); - object_property_add_alias(obj, "kvm_mmu", obj, "kvm-mmu", &error_abort); - object_property_add_alias(obj, "kvm_asyncpf", obj, "kvm-asyncpf", &error_abort); - object_property_add_alias(obj, "kvm_steal_time", obj, "kvm-steal-time", &error_abort); - object_property_add_alias(obj, "kvm_pv_eoi", obj, "kvm-pv-eoi", &error_abort); - object_property_add_alias(obj, "kvm_pv_unhalt", obj, "kvm-pv-unhalt", &error_abort); - object_property_add_alias(obj, "kvm_poll_control", obj, "kvm-poll-control", - &error_abort); - object_property_add_alias(obj, "svm_lock", obj, "svm-lock", &error_abort); - object_property_add_alias(obj, "nrip_save", obj, "nrip-save", &error_abort); - object_property_add_alias(obj, "tsc_scale", obj, "tsc-scale", &error_abort); - object_property_add_alias(obj, "vmcb_clean", obj, "vmcb-clean", &error_abort); - object_property_add_alias(obj, "pause_filter", obj, "pause-filter", &error_abort); - object_property_add_alias(obj, "sse4_1", obj, "sse4.1", &error_abort); - object_property_add_alias(obj, "sse4_2", obj, "sse4.2", &error_abort); + object_property_add_alias(obj, "ds_cpl", obj, "ds-cpl"); + object_property_add_alias(obj, "tsc_adjust", obj, "tsc-adjust"); + object_property_add_alias(obj, "fxsr_opt", obj, "fxsr-opt"); + object_property_add_alias(obj, "lahf_lm", obj, "lahf-lm"); + object_property_add_alias(obj, "cmp_legacy", obj, "cmp-legacy"); + object_property_add_alias(obj, "nodeid_msr", obj, "nodeid-msr"); + object_property_add_alias(obj, "perfctr_core", obj, "perfctr-core"); + object_property_add_alias(obj, "perfctr_nb", obj, "perfctr-nb"); + object_property_add_alias(obj, "kvm_nopiodelay", obj, "kvm-nopiodelay"); + object_property_add_alias(obj, "kvm_mmu", obj, "kvm-mmu"); + object_property_add_alias(obj, "kvm_asyncpf", obj, "kvm-asyncpf"); + object_property_add_alias(obj, "kvm_steal_time", obj, "kvm-steal-time"); + object_property_add_alias(obj, "kvm_pv_eoi", obj, "kvm-pv-eoi"); + object_property_add_alias(obj, "kvm_pv_unhalt", obj, "kvm-pv-unhalt"); + object_property_add_alias(obj, "kvm_poll_control", obj, "kvm-poll-control"); + object_property_add_alias(obj, "svm_lock", obj, "svm-lock"); + object_property_add_alias(obj, "nrip_save", obj, "nrip-save"); + object_property_add_alias(obj, "tsc_scale", obj, "tsc-scale"); + object_property_add_alias(obj, "vmcb_clean", obj, "vmcb-clean"); + object_property_add_alias(obj, "pause_filter", obj, "pause-filter"); + object_property_add_alias(obj, "sse4_1", obj, "sse4.1"); + object_property_add_alias(obj, "sse4_2", obj, "sse4.2"); if (xcc->model) { x86_cpu_load_model(cpu, xcc->model, &error_abort); diff --git a/target/i386/sev.c b/target/i386/sev.c index 6842cfc26d..51cdbe5496 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -248,20 +248,17 @@ qsev_guest_class_init(ObjectClass *oc, void *data) { object_class_property_add_str(oc, "sev-device", qsev_guest_get_sev_device, - qsev_guest_set_sev_device, - NULL); + qsev_guest_set_sev_device); object_class_property_set_description(oc, "sev-device", "SEV device to use"); object_class_property_add_str(oc, "dh-cert-file", qsev_guest_get_dh_cert_file, - qsev_guest_set_dh_cert_file, - NULL); + qsev_guest_set_dh_cert_file); object_class_property_set_description(oc, "dh-cert-file", "guest owners DH certificate (encoded with base64)"); object_class_property_add_str(oc, "session-file", qsev_guest_get_session_file, - qsev_guest_set_session_file, - NULL); + qsev_guest_set_session_file); object_class_property_set_description(oc, "session-file", "guest owners session parameters (encoded with base64)"); } @@ -274,14 +271,14 @@ qsev_guest_init(Object *obj) sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE); sev->policy = DEFAULT_GUEST_POLICY; object_property_add_uint32_ptr(obj, "policy", &sev->policy, - OBJ_PROP_FLAG_READWRITE, NULL); + OBJ_PROP_FLAG_READWRITE); object_property_add_uint32_ptr(obj, "handle", &sev->handle, - OBJ_PROP_FLAG_READWRITE, NULL); + OBJ_PROP_FLAG_READWRITE); object_property_add_uint32_ptr(obj, "cbitpos", &sev->cbitpos, - OBJ_PROP_FLAG_READWRITE, NULL); + OBJ_PROP_FLAG_READWRITE); object_property_add_uint32_ptr(obj, "reduced-phys-bits", &sev->reduced_phys_bits, - OBJ_PROP_FLAG_READWRITE, NULL); + OBJ_PROP_FLAG_READWRITE); } /* sev guest info */ diff --git a/target/ppc/compat.c b/target/ppc/compat.c index 46ffb6da6d..7f144392f8 100644 --- a/target/ppc/compat.c +++ b/target/ppc/compat.c @@ -301,17 +301,13 @@ void ppc_compat_add_property(Object *obj, const char *name, uint32_t *compat_pvr, const char *basedesc, Error **errp) { - Error *local_err = NULL; gchar *namesv[ARRAY_SIZE(compat_table) + 1]; gchar *names, *desc; int i; object_property_add(obj, name, "string", ppc_compat_prop_get, ppc_compat_prop_set, NULL, - compat_pvr, &local_err); - if (local_err) { - goto out; - } + compat_pvr); for (i = 0; i < ARRAY_SIZE(compat_table); i++) { /* @@ -328,7 +324,4 @@ void ppc_compat_add_property(Object *obj, const char *name, g_free(names); g_free(desc); - -out: - error_propagate(errp, local_err); } diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index f2ccf0a06a..ca50b70451 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -296,7 +296,7 @@ static void s390_cpu_initfn(Object *obj) cs->halted = 1; cs->exception_index = EXCP_HLT; object_property_add(obj, "crash-information", "GuestPanicInformation", - s390_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL); + s390_cpu_get_crash_info_qom, NULL, NULL, NULL); s390_cpu_model_register_props(obj); #if !defined(CONFIG_USER_ONLY) cpu->env.tod_timer = diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index aa7fc713ca..8efe6ed514 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -1106,13 +1106,13 @@ void s390_cpu_model_register_props(Object *obj) for (feat = 0; feat < S390_FEAT_MAX; feat++) { const S390FeatDef *def = s390_feat_def(feat); object_property_add(obj, def->name, "bool", get_feature, - set_feature, NULL, (void *) feat, NULL); + set_feature, NULL, (void *) feat); object_property_set_description(obj, def->name, def->desc); } for (group = 0; group < S390_FEAT_GROUP_MAX; group++) { const S390FeatGroupDef *def = s390_feat_group_def(group); object_property_add(obj, def->name, "bool", get_feature_group, - set_feature_group, NULL, (void *) group, NULL); + set_feature_group, NULL, (void *) group); object_property_set_description(obj, def->name, def->desc); } } @@ -1225,11 +1225,10 @@ static char *get_description(Object *obj, Error **errp) void s390_cpu_model_class_register_props(ObjectClass *oc) { object_class_property_add_bool(oc, "migration-safe", get_is_migration_safe, - NULL, NULL); + NULL); object_class_property_add_bool(oc, "static", get_is_static, - NULL, NULL); - object_class_property_add_str(oc, "description", get_description, NULL, - NULL); + NULL); + object_class_property_add_str(oc, "description", get_description, NULL); } #ifdef CONFIG_KVM diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c index 140d56439a..84f48fe592 100644 --- a/tests/check-qom-proplist.c +++ b/tests/check-qom-proplist.c @@ -125,18 +125,9 @@ static char *dummy_get_sv(Object *obj, static void dummy_init(Object *obj) { - Error *err = NULL; - object_property_add_bool(obj, "bv", dummy_get_bv, - dummy_set_bv, - NULL); - /* duplicate: */ - object_property_add_str(obj, "sv", - dummy_get_sv, - dummy_set_sv, - &err); - error_free_or_abort(&err); + dummy_set_bv); } @@ -144,14 +135,12 @@ static void dummy_class_init(ObjectClass *cls, void *data) { object_class_property_add_str(cls, "sv", dummy_get_sv, - dummy_set_sv, - NULL); + dummy_set_sv); object_class_property_add_enum(cls, "av", "DummyAnimal", &dummy_animal_map, dummy_get_av, - dummy_set_av, - NULL); + dummy_set_av); } @@ -256,13 +245,13 @@ static void dummy_dev_init(Object *obj) DummyBus *bus = DUMMY_BUS(object_new(TYPE_DUMMY_BUS)); DummyBackend *backend = DUMMY_BACKEND(object_new(TYPE_DUMMY_BACKEND)); - object_property_add_child(obj, "bus", OBJECT(bus), NULL); + object_property_add_child(obj, "bus", OBJECT(bus)); dev->bus = bus; - object_property_add_child(OBJECT(bus), "backend", OBJECT(backend), NULL); + object_property_add_child(OBJECT(bus), "backend", OBJECT(backend)); bus->backend = backend; object_property_add_link(obj, "backend", TYPE_DUMMY_BACKEND, - (Object **)&bus->backend, NULL, 0, NULL); + (Object **)&bus->backend, NULL, 0); } static void dummy_dev_unparent(Object *obj) @@ -603,11 +592,11 @@ static void test_qom_partial_path(void) * /cont1/obj2 (obj2a) * /obj2 (obj2b) */ - object_property_add_child(cont1, "obj1", obj1, &error_abort); + object_property_add_child(cont1, "obj1", obj1); object_unref(obj1); - object_property_add_child(cont1, "obj2", obj2a, &error_abort); + object_property_add_child(cont1, "obj2", obj2a); object_unref(obj2a); - object_property_add_child(root, "obj2", obj2b, &error_abort); + object_property_add_child(root, "obj2", obj2b); object_unref(obj2b); ambiguous = false; diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c index 270c690479..42d3dd7030 100644 --- a/tests/test-qdev-global-props.c +++ b/tests/test-qdev-global-props.c @@ -151,9 +151,9 @@ static void prop2_accessor(Object *obj, Visitor *v, const char *name, static void dynamic_instance_init(Object *obj) { object_property_add(obj, "prop1", "uint32", prop1_accessor, prop1_accessor, - NULL, NULL, NULL); + NULL, NULL); object_property_add(obj, "prop2", "uint32", prop2_accessor, prop2_accessor, - NULL, NULL, NULL); + NULL, NULL); } static void dynamic_class_init(ObjectClass *oc, void *data) diff --git a/ui/console.c b/ui/console.c index 184e173687..865fa32635 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1297,10 +1297,9 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type, object_property_add_link(obj, "device", TYPE_DEVICE, (Object **)&s->device, object_property_allow_set_link, - OBJ_PROP_LINK_STRONG, - &error_abort); + OBJ_PROP_LINK_STRONG); object_property_add_uint32_ptr(obj, "head", &s->head, - OBJ_PROP_FLAG_READ, &error_abort); + OBJ_PROP_FLAG_READ); if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) && (console_type == GRAPHIC_CONSOLE))) { @@ -1868,7 +1867,7 @@ DisplayState *init_displaystate(void) * doesn't change any more */ name = g_strdup_printf("console[%d]", con->index); object_property_add_child(container_get(object_get_root(), "/backend"), - name, OBJECT(con), &error_abort); + name, OBJECT(con)); g_free(name); } diff --git a/ui/input-barrier.c b/ui/input-barrier.c index 527c75e130..1cdf0c5f82 100644 --- a/ui/input-barrier.c +++ b/ui/input-barrier.c @@ -700,25 +700,25 @@ static void input_barrier_instance_init(Object *obj) object_property_add_str(obj, "name", input_barrier_get_name, - input_barrier_set_name, NULL); + input_barrier_set_name); object_property_add_str(obj, "server", input_barrier_get_server, - input_barrier_set_server, NULL); + input_barrier_set_server); object_property_add_str(obj, "port", input_barrier_get_port, - input_barrier_set_port, NULL); + input_barrier_set_port); object_property_add_str(obj, "x-origin", input_barrier_get_x_origin, - input_barrier_set_x_origin, NULL); + input_barrier_set_x_origin); object_property_add_str(obj, "y-origin", input_barrier_get_y_origin, - input_barrier_set_y_origin, NULL); + input_barrier_set_y_origin); object_property_add_str(obj, "width", input_barrier_get_width, - input_barrier_set_width, NULL); + input_barrier_set_width); object_property_add_str(obj, "height", input_barrier_get_height, - input_barrier_set_height, NULL); + input_barrier_set_height); } static void input_barrier_class_init(ObjectClass *oc, void *data) diff --git a/ui/input-linux.c b/ui/input-linux.c index ef37b14d6f..4925ce1af1 100644 --- a/ui/input-linux.c +++ b/ui/input-linux.c @@ -499,17 +499,17 @@ static void input_linux_instance_init(Object *obj) { object_property_add_str(obj, "evdev", input_linux_get_evdev, - input_linux_set_evdev, NULL); + input_linux_set_evdev); object_property_add_bool(obj, "grab_all", input_linux_get_grab_all, - input_linux_set_grab_all, NULL); + input_linux_set_grab_all); object_property_add_bool(obj, "repeat", input_linux_get_repeat, - input_linux_set_repeat, NULL); + input_linux_set_repeat); object_property_add_enum(obj, "grab-toggle", "GrabToggleKeys", &GrabToggleKeys_lookup, input_linux_get_grab_toggle, - input_linux_set_grab_toggle, NULL); + input_linux_set_grab_toggle); } static void input_linux_class_init(ObjectClass *oc, void *data) From 40c2281cc3342573bd72895997b5cfaddee36ef2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:23 +0200 Subject: [PATCH 0479/2595] Drop more @errp parameters after previous commit Several functions can't fail anymore: ich9_pm_add_properties(), device_add_bootindex_property(), ppc_compat_add_property(), spapr_caps_add_properties(), PropertyInfo.create(). Drop their @errp parameter. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-16-armbru@redhat.com> --- bootdevice.c | 2 +- hw/acpi/ich9.c | 2 +- hw/block/fdc.c | 4 ++-- hw/block/nvme.c | 2 +- hw/block/vhost-user-blk.c | 2 +- hw/block/virtio-blk.c | 2 +- hw/core/qdev-properties.c | 2 +- hw/core/qdev.c | 2 +- hw/isa/lpc_ich9.c | 2 +- hw/net/e1000.c | 2 +- hw/net/e1000e.c | 2 +- hw/net/eepro100.c | 2 +- hw/net/lance.c | 2 +- hw/net/lasi_i82596.c | 2 +- hw/net/ne2000-pci.c | 2 +- hw/net/pcnet-pci.c | 2 +- hw/net/rtl8139.c | 2 +- hw/net/spapr_llan.c | 2 +- hw/net/sungem.c | 2 +- hw/net/sunhme.c | 2 +- hw/net/tulip.c | 2 +- hw/net/virtio-net.c | 2 +- hw/net/vmxnet3.c | 2 +- hw/ppc/spapr.c | 5 ++--- hw/ppc/spapr_caps.c | 2 +- hw/s390x/s390-ccw.c | 2 +- hw/scsi/scsi-bus.c | 2 +- hw/scsi/vhost-scsi.c | 2 +- hw/scsi/vhost-user-scsi.c | 2 +- hw/usb/dev-network.c | 2 +- hw/usb/host-libusb.c | 2 +- hw/usb/redirect.c | 2 +- hw/vfio/pci.c | 2 +- include/hw/acpi/ich9.h | 2 +- include/hw/ppc/spapr.h | 2 +- include/hw/qdev-core.h | 2 +- include/sysemu/sysemu.h | 2 +- target/ppc/compat.c | 3 +-- target/ppc/cpu.h | 3 +-- 39 files changed, 41 insertions(+), 44 deletions(-) diff --git a/bootdevice.c b/bootdevice.c index d11576d575..0ff55e2b79 100644 --- a/bootdevice.c +++ b/bootdevice.c @@ -327,7 +327,7 @@ static void property_release_bootindex(Object *obj, const char *name, void device_add_bootindex_property(Object *obj, int32_t *bootindex, const char *name, const char *suffix, - DeviceState *dev, Error **errp) + DeviceState *dev) { BootIndexProperty *prop = g_malloc0(sizeof(*prop)); diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 9e4c03bef8..2d204babc6 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -369,7 +369,7 @@ static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp) s->pm.enable_tco = value; } -void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) +void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm) { static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN; pm->acpi_memory_hotplug.is_enabled = true; diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 9628cc171e..c5fb9d6ece 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2813,10 +2813,10 @@ static void isabus_fdc_instance_init(Object *obj) device_add_bootindex_property(obj, &isa->bootindexA, "bootindexA", "/floppy@0", - DEVICE(obj), NULL); + DEVICE(obj)); device_add_bootindex_property(obj, &isa->bootindexB, "bootindexB", "/floppy@1", - DEVICE(obj), NULL); + DEVICE(obj)); } static const TypeInfo isa_fdc_info = { diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 9b453423cf..2f3100e56c 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1594,7 +1594,7 @@ static void nvme_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/namespace@1,0", - DEVICE(obj), &error_abort); + DEVICE(obj)); } static const TypeInfo nvme_info = { diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 6c485d1c9e..5263e0c9ad 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -481,7 +481,7 @@ static void vhost_user_blk_instance_init(Object *obj) VHostUserBlk *s = VHOST_USER_BLK(obj); device_add_bootindex_property(obj, &s->bootindex, "bootindex", - "/disk@0,0", DEVICE(obj), NULL); + "/disk@0,0", DEVICE(obj)); } static const VMStateDescription vmstate_vhost_user_blk = { diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 97ba8a2187..fb32717a12 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1248,7 +1248,7 @@ static void virtio_blk_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.conf.bootindex, "bootindex", "/disk@0,0", - DEVICE(obj), NULL); + DEVICE(obj)); } static const VMStateDescription vmstate_virtio_blk = { diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 2f294ec4a4..cc924815da 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -1250,7 +1250,7 @@ const PropertyInfo qdev_prop_size = { /* --- object link property --- */ -static void create_link_property(ObjectClass *oc, Property *prop, Error **errp) +static void create_link_property(ObjectClass *oc, Property *prop) { object_class_property_add_link(oc, prop->name, prop->link_type, prop->offset, diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 3f91bff712..2afa2562b8 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -782,7 +782,7 @@ static void qdev_class_add_property(DeviceClass *klass, Property *prop) ObjectClass *oc = OBJECT_CLASS(klass); if (prop->info->create) { - prop->info->create(oc, prop, &error_abort); + prop->info->create(oc, prop); } else { ObjectProperty *op; diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index c975d46675..cd6e169d47 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -639,7 +639,7 @@ static void ich9_lpc_initfn(Object *obj) object_property_add_uint8_ptr(OBJECT(lpc), ACPI_PM_PROP_ACPI_DISABLE_CMD, &acpi_disable_cmd, OBJ_PROP_FLAG_READ); - ich9_pm_add_properties(obj, &lpc->pm, NULL); + ich9_pm_add_properties(obj, &lpc->pm); } static void ich9_lpc_realize(PCIDevice *d, Error **errp) diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 0d2c2759e3..a18f80e369 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -1774,7 +1774,7 @@ static void e1000_instance_init(Object *obj) E1000State *n = E1000(obj); device_add_bootindex_property(obj, &n->conf.bootindex, "bootindex", "/ethernet-phy@0", - DEVICE(n), NULL); + DEVICE(n)); } static const TypeInfo e1000_base_info = { diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index 79ba158d41..fda34518c9 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -705,7 +705,7 @@ static void e1000e_instance_init(Object *obj) E1000EState *s = E1000E(obj); device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", - DEVICE(obj), NULL); + DEVICE(obj)); } static const TypeInfo e1000e_info = { diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index f6474f0e68..16e95ef9cc 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -1883,7 +1883,7 @@ static void eepro100_instance_init(Object *obj) EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, PCI_DEVICE(obj)); device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", - DEVICE(s), NULL); + DEVICE(s)); } static E100PCIDeviceInfo e100_devices[] = { diff --git a/hw/net/lance.c b/hw/net/lance.c index 688724db0b..4c5f01baad 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -134,7 +134,7 @@ static void lance_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", - DEVICE(obj), NULL); + DEVICE(obj)); } static Property lance_properties[] = { diff --git a/hw/net/lasi_i82596.c b/hw/net/lasi_i82596.c index 52637a562d..5e0fd69763 100644 --- a/hw/net/lasi_i82596.c +++ b/hw/net/lasi_i82596.c @@ -152,7 +152,7 @@ static void lasi_82596_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", - DEVICE(obj), NULL); + DEVICE(obj)); } static Property lasi_82596_properties[] = { diff --git a/hw/net/ne2000-pci.c b/hw/net/ne2000-pci.c index e11d67bf75..9e5d10859a 100644 --- a/hw/net/ne2000-pci.c +++ b/hw/net/ne2000-pci.c @@ -92,7 +92,7 @@ static void ne2000_instance_init(Object *obj) device_add_bootindex_property(obj, &s->c.bootindex, "bootindex", "/ethernet-phy@0", - &pci_dev->qdev, NULL); + &pci_dev->qdev); } static Property ne2000_properties[] = { diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index d1f31e0272..49d3e42e83 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -250,7 +250,7 @@ static void pcnet_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", - DEVICE(obj), NULL); + DEVICE(obj)); } static Property pcnet_properties[] = { diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 70aca7ec26..ab93d78ab3 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -3415,7 +3415,7 @@ static void rtl8139_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", - DEVICE(obj), NULL); + DEVICE(obj)); } static Property rtl8139_properties[] = { diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index a2377025a7..968a1ce78e 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -340,7 +340,7 @@ static void spapr_vlan_instance_init(Object *obj) device_add_bootindex_property(obj, &dev->nicconf.bootindex, "bootindex", "", - DEVICE(dev), NULL); + DEVICE(dev)); if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) { for (i = 0; i < RX_MAX_POOLS; i++) { diff --git a/hw/net/sungem.c b/hw/net/sungem.c index b01197d952..e4b7b57704 100644 --- a/hw/net/sungem.c +++ b/hw/net/sungem.c @@ -1378,7 +1378,7 @@ static void sungem_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", - DEVICE(obj), NULL); + DEVICE(obj)); } static Property sungem_properties[] = { diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c index 9c38583180..bc48d46b9f 100644 --- a/hw/net/sunhme.c +++ b/hw/net/sunhme.c @@ -901,7 +901,7 @@ static void sunhme_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", - DEVICE(obj), NULL); + DEVICE(obj)); } static void sunhme_reset(DeviceState *ds) diff --git a/hw/net/tulip.c b/hw/net/tulip.c index 1295f51d07..6cefc0add2 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -1001,7 +1001,7 @@ static void tulip_instance_init(Object *obj) device_add_bootindex_property(obj, &d->c.bootindex, "bootindex", "/ethernet-phy@0", - &pci_dev->qdev, NULL); + &pci_dev->qdev); } static Property tulip_properties[] = { diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index e51231e795..b43fd7d608 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3125,7 +3125,7 @@ static void virtio_net_instance_init(Object *obj) n->config_size = sizeof(struct virtio_net_config); device_add_bootindex_property(obj, &n->nic_conf.bootindex, "bootindex", "/ethernet-phy@0", - DEVICE(n), NULL); + DEVICE(n)); } static int virtio_net_pre_save(void *opaque) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 6d91cd8309..7a6ca4ec35 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2237,7 +2237,7 @@ static void vmxnet3_instance_init(Object *obj) VMXNET3State *s = VMXNET3(obj); device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", - DEVICE(obj), NULL); + DEVICE(obj)); } static void vmxnet3_pci_uninit(PCIDevice *pci_dev) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 976d40f60f..b73f4d94d3 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3316,8 +3316,7 @@ static void spapr_instance_init(Object *obj) " place of standard EPOW events when possible" " (required for memory hot-unplug support)"); ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr, - "Maximum permitted CPU compatibility mode", - &error_fatal); + "Maximum permitted CPU compatibility mode"); object_property_add_str(obj, "resize-hpt", spapr_get_resize_hpt, spapr_set_resize_hpt); @@ -4525,7 +4524,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON; smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_ON; smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_ON; - spapr_caps_add_properties(smc, &error_abort); + spapr_caps_add_properties(smc); smc->irq = &spapr_irq_dual; smc->dr_phb_enabled = true; smc->linux_pci_probe = true; diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 184563e608..efdc0dbbcf 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -824,7 +824,7 @@ void spapr_caps_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu) } } -void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp) +void spapr_caps_add_properties(SpaprMachineClass *smc) { ObjectClass *klass = OBJECT_CLASS(smc); int i; diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index 0c5a5b60bd..569020dae4 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -151,7 +151,7 @@ static void s390_ccw_instance_init(Object *obj) S390CCWDevice *dev = S390_CCW_DEVICE(obj); device_add_bootindex_property(obj, &dev->bootindex, "bootindex", - "/disk@0,0", DEVICE(obj), NULL); + "/disk@0,0", DEVICE(obj)); } static void s390_ccw_class_init(ObjectClass *klass, void *data) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index ab5459a589..1733307407 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1738,7 +1738,7 @@ static void scsi_dev_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", NULL, - &s->qdev, NULL); + &s->qdev); } static const TypeInfo scsi_device_type_info = { diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index f052377b7e..ffa667171d 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -311,7 +311,7 @@ static void vhost_scsi_instance_init(Object *obj) vsc->feature_bits = kernel_feature_bits; device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL, - DEVICE(vsc), NULL); + DEVICE(vsc)); } static const TypeInfo vhost_scsi_info = { diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index a01bf63a08..ae380b63b4 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -217,7 +217,7 @@ static void vhost_user_scsi_instance_init(Object *obj) /* Add the bootindex property for this object */ device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL, - DEVICE(vsc), NULL); + DEVICE(vsc)); } static const TypeInfo vhost_user_scsi_info = { diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 6210427544..720744488b 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1381,7 +1381,7 @@ static void usb_net_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", - &dev->qdev, NULL); + &dev->qdev); } static const VMStateDescription vmstate_usb_net = { diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 2ac7a936fb..78a5c2ba55 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -1101,7 +1101,7 @@ static void usb_host_instance_init(Object *obj) device_add_bootindex_property(obj, &s->bootindex, "bootindex", NULL, - &udev->qdev, NULL); + &udev->qdev); } static void usb_host_unrealize(USBDevice *udev, Error **errp) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 45d8b76218..e9a97feaed 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -2595,7 +2595,7 @@ static void usbredir_instance_init(Object *obj) device_add_bootindex_property(obj, &dev->bootindex, "bootindex", NULL, - &udev->qdev, NULL); + &udev->qdev); } static const TypeInfo usbredir_dev_info = { diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 5e75a95129..342dd6b912 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -3133,7 +3133,7 @@ static void vfio_instance_init(Object *obj) device_add_bootindex_property(obj, &vdev->bootindex, "bootindex", NULL, - &pci_dev->qdev, NULL); + &pci_dev->qdev); vdev->host.domain = ~0U; vdev->host.bus = ~0U; vdev->host.slot = ~0U; diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h index 41568d1837..28a53181cb 100644 --- a/include/hw/acpi/ich9.h +++ b/include/hw/acpi/ich9.h @@ -72,7 +72,7 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base); extern const VMStateDescription vmstate_ich9_pm; -void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp); +void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm); void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index e579eaf28c..d2533e7264 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -921,7 +921,7 @@ static inline uint8_t spapr_get_cap(SpaprMachineState *spapr, int cap) void spapr_caps_init(SpaprMachineState *spapr); void spapr_caps_apply(SpaprMachineState *spapr); void spapr_caps_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu); -void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp); +void spapr_caps_add_properties(SpaprMachineClass *smc); int spapr_caps_post_migration(SpaprMachineState *spapr); void spapr_check_pagesize(SpaprMachineState *spapr, hwaddr pagesize, diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index d87d989e72..6f537f687f 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -286,7 +286,7 @@ struct PropertyInfo { const QEnumLookup *enum_table; int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); void (*set_default_value)(ObjectProperty *op, const Property *prop); - void (*create)(ObjectClass *oc, Property *prop, Error **errp); + void (*create)(ObjectClass *oc, Property *prop); ObjectPropertyAccessor *get; ObjectPropertyAccessor *set; ObjectPropertyRelease *release; diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index ef81302e1a..26c0c802d1 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -92,7 +92,7 @@ void check_boot_index(int32_t bootindex, Error **errp); void del_boot_device_path(DeviceState *dev, const char *suffix); void device_add_bootindex_property(Object *obj, int32_t *bootindex, const char *name, const char *suffix, - DeviceState *dev, Error **errp); + DeviceState *dev); void restore_boot_order(void *opaque); void validate_bootdevices(const char *devices, Error **errp); void add_boot_device_lchs(DeviceState *dev, const char *suffix, diff --git a/target/ppc/compat.c b/target/ppc/compat.c index 7f144392f8..fda0dfe8f8 100644 --- a/target/ppc/compat.c +++ b/target/ppc/compat.c @@ -298,8 +298,7 @@ out: } void ppc_compat_add_property(Object *obj, const char *name, - uint32_t *compat_pvr, const char *basedesc, - Error **errp) + uint32_t *compat_pvr, const char *basedesc) { gchar *namesv[ARRAY_SIZE(compat_table) + 1]; gchar *names, *desc; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 6b6dd7e483..7db7882f52 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1338,8 +1338,7 @@ void ppc_set_compat_all(uint32_t compat_pvr, Error **errp); #endif int ppc_compat_max_vthreads(PowerPCCPU *cpu); void ppc_compat_add_property(Object *obj, const char *name, - uint32_t *compat_pvr, const char *basedesc, - Error **errp); + uint32_t *compat_pvr, const char *basedesc); #endif /* defined(TARGET_PPC64) */ typedef CPUPPCState CPUArchState; From b69c3c21a5d11075d42100d5cfe0a736593fae6b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:24 +0200 Subject: [PATCH 0480/2595] qdev: Unrealize must not fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Devices may have component devices and buses. Device realization may fail. Realization is recursive: a device's realize() method realizes its components, and device_set_realized() realizes its buses (which should in turn realize the devices on that bus, except bus_set_realized() doesn't implement that, yet). When realization of a component or bus fails, we need to roll back: unrealize everything we realized so far. If any of these unrealizes failed, the device would be left in an inconsistent state. Must not happen. device_set_realized() lets it happen: it ignores errors in the roll back code starting at label child_realize_fail. Since realization is recursive, unrealization must be recursive, too. But how could a partly failed unrealize be rolled back? We'd have to re-realize, which can fail. This design is fundamentally broken. device_set_realized() does not roll back at all. Instead, it keeps unrealizing, ignoring further errors. It can screw up even for a device with no buses: if the lone dc->unrealize() fails, it still unregisters vmstate, and calls listeners' unrealize() callback. bus_set_realized() does not roll back either. Instead, it stops unrealizing. Fortunately, no unrealize method can fail, as we'll see below. To fix the design error, drop parameter @errp from all the unrealize methods. Any unrealize method that uses @errp now needs an update. This leads us to unrealize() methods that can fail. Merely passing it to another unrealize method cannot cause failure, though. Here are the ones that do other things with @errp: * virtio_serial_device_unrealize() Fails when qbus_set_hotplug_handler() fails, but still does all the other work. On failure, the device would stay realized with its resources completely gone. Oops. Can't happen, because qbus_set_hotplug_handler() can't actually fail here. Pass &error_abort to qbus_set_hotplug_handler() instead. * hw/ppc/spapr_drc.c's unrealize() Fails when object_property_del() fails, but all the other work is already done. On failure, the device would stay realized with its vmstate registration gone. Oops. Can't happen, because object_property_del() can't actually fail here. Pass &error_abort to object_property_del() instead. * spapr_phb_unrealize() Fails and bails out when remove_drcs() fails, but other work is already done. On failure, the device would stay realized with some of its resources gone. Oops. remove_drcs() fails only when chassis_from_bus()'s object_property_get_uint() fails, and it can't here. Pass &error_abort to remove_drcs() instead. Therefore, no unrealize method can fail before this patch. device_set_realized()'s recursive unrealization via bus uses object_property_set_bool(). Can't drop @errp there, so pass &error_abort. We similarly unrealize with object_property_set_bool() elsewhere, always ignoring errors. Pass &error_abort instead. Several unrealize methods no longer handle errors from other unrealize methods: virtio_9p_device_unrealize(), virtio_input_device_unrealize(), scsi_qdev_unrealize(), ... Much of the deleted error handling looks wrong anyway. One unrealize methods no longer ignore such errors: usb_ehci_pci_exit(). Several realize methods no longer ignore errors when rolling back: v9fs_device_realize_common(), pci_qdev_unrealize(), spapr_phb_realize(), usb_qdev_realize(), vfio_ccw_realize(), virtio_device_realize(). Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-17-armbru@redhat.com> --- hw/9pfs/9p.c | 4 ++-- hw/9pfs/9p.h | 2 +- hw/9pfs/virtio-9p-device.c | 4 ++-- hw/acpi/pcihp.c | 2 +- hw/audio/intel-hda.c | 2 +- hw/block/pflash_cfi02.c | 2 +- hw/block/vhost-user-blk.c | 2 +- hw/block/virtio-blk.c | 2 +- hw/block/xen-block.c | 8 ++++---- hw/char/serial-pci-multi.c | 2 +- hw/char/serial-pci.c | 2 +- hw/char/serial.c | 2 +- hw/char/virtio-console.c | 2 +- hw/char/virtio-serial-bus.c | 8 ++++---- hw/core/bus.c | 17 ++++------------- hw/core/cpu.c | 2 +- hw/core/generic-loader.c | 2 +- hw/core/qdev.c | 17 ++++++----------- hw/display/virtio-gpu-base.c | 2 +- hw/dma/rc4030.c | 2 +- hw/i386/kvm/apic.c | 2 +- hw/i386/pc.c | 4 ++-- hw/ide/qdev.c | 4 ++-- hw/input/virtio-input-hid.c | 2 +- hw/input/virtio-input-host.c | 2 +- hw/input/virtio-input.c | 9 ++------- hw/intc/apic.c | 2 +- hw/intc/apic_common.c | 4 ++-- hw/intc/ioapic.c | 2 +- hw/intc/xics.c | 2 +- hw/ipack/ipack.c | 6 ++---- hw/mem/pc-dimm.c | 2 +- hw/net/virtio-net.c | 2 +- hw/nvram/mac_nvram.c | 2 +- hw/pci/pci.c | 14 +++++++------- hw/pci/pcie.c | 2 +- hw/pci/shpc.c | 2 +- hw/ppc/pnv_core.c | 2 +- hw/ppc/spapr.c | 8 ++++---- hw/ppc/spapr_cpu_core.c | 2 +- hw/ppc/spapr_drc.c | 14 ++++---------- hw/ppc/spapr_iommu.c | 2 +- hw/ppc/spapr_pci.c | 14 +++++--------- hw/ppc/spapr_tpm_proxy.c | 2 +- hw/s390x/css-bridge.c | 2 +- hw/s390x/s390-ccw.c | 2 +- hw/s390x/s390-pci-bus.c | 4 ++-- hw/s390x/virtio-ccw.c | 8 ++++---- hw/s390x/virtio-ccw.h | 2 +- hw/scsi/lsi53c895a.c | 2 +- hw/scsi/scsi-bus.c | 13 ++++--------- hw/scsi/scsi-disk.c | 2 +- hw/scsi/vhost-scsi.c | 2 +- hw/scsi/vhost-user-scsi.c | 2 +- hw/scsi/virtio-scsi.c | 2 +- hw/sd/sdhci-internal.h | 2 +- hw/sd/sdhci-pci.c | 2 +- hw/sd/sdhci.c | 6 +++--- hw/usb/bus.c | 12 ++++++------ hw/usb/ccid-card-emulated.c | 2 +- hw/usb/ccid.h | 2 +- hw/usb/dev-audio.c | 2 +- hw/usb/dev-hid.c | 2 +- hw/usb/dev-hub.c | 2 +- hw/usb/dev-network.c | 2 +- hw/usb/dev-smartcard-reader.c | 11 +++-------- hw/usb/dev-uas.c | 2 +- hw/usb/dev-wacom.c | 2 +- hw/usb/hcd-ehci-pci.c | 2 +- hw/usb/hcd-ehci.c | 2 +- hw/usb/hcd-ehci.h | 2 +- hw/usb/host-libusb.c | 2 +- hw/usb/redirect.c | 2 +- hw/vfio/ap.c | 2 +- hw/vfio/ccw.c | 6 +++--- hw/virtio/vhost-user-fs.c | 2 +- hw/virtio/vhost-vsock.c | 2 +- hw/virtio/virtio-balloon.c | 2 +- hw/virtio/virtio-crypto.c | 2 +- hw/virtio/virtio-iommu.c | 2 +- hw/virtio/virtio-pmem.c | 2 +- hw/virtio/virtio-rng.c | 2 +- hw/virtio/virtio.c | 11 +++-------- hw/watchdog/wdt_diag288.c | 2 +- hw/xen/xen-bus.c | 12 ++++++------ include/hw/qdev-core.h | 4 ++-- include/hw/s390x/s390-ccw.h | 2 +- include/hw/scsi/scsi.h | 2 +- include/hw/usb.h | 2 +- include/hw/xen/xen-block.h | 2 +- include/hw/xen/xen-bus.h | 2 +- target/i386/cpu.c | 9 ++------- target/ppc/translate_init.inc.c | 9 ++------- 93 files changed, 158 insertions(+), 214 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 9e046f7acb..a2a14b5979 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -4124,13 +4124,13 @@ int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t, rc = 0; out: if (rc) { - v9fs_device_unrealize_common(s, NULL); + v9fs_device_unrealize_common(s); } v9fs_path_free(&path); return rc; } -void v9fs_device_unrealize_common(V9fsState *s, Error **errp) +void v9fs_device_unrealize_common(V9fsState *s) { if (s->ops && s->ops->cleanup) { s->ops->cleanup(&s->ctx); diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index b8f72a3bd9..dd1c6cb8d2 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -423,7 +423,7 @@ int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, const char *name, V9fsPath *path); int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t, Error **errp); -void v9fs_device_unrealize_common(V9fsState *s, Error **errp); +void v9fs_device_unrealize_common(V9fsState *s); V9fsPDU *pdu_alloc(V9fsState *s); void pdu_free(V9fsPDU *pdu); diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 536447a355..e5b44977c7 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -212,7 +212,7 @@ static void virtio_9p_device_realize(DeviceState *dev, Error **errp) v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); } -static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp) +static void virtio_9p_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); V9fsVirtioState *v = VIRTIO_9P(dev); @@ -220,7 +220,7 @@ static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp) virtio_delete_queue(v->vq); virtio_cleanup(vdev); - v9fs_device_unrealize_common(s, errp); + v9fs_device_unrealize_common(s); } /* virtio-9p device */ diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index fbc86af102..d42906ea19 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -266,7 +266,7 @@ void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, { trace_acpi_pci_unplug(PCI_SLOT(PCI_DEVICE(dev)->devfn), acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev)))); - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); } void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev, diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index e8d18b7c58..4696ae0d9a 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -74,7 +74,7 @@ static void hda_codec_dev_realize(DeviceState *qdev, Error **errp) } } -static void hda_codec_dev_unrealize(DeviceState *qdev, Error **errp) +static void hda_codec_dev_unrealize(DeviceState *qdev) { HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev); HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev); diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 12f18d401a..f0579ecb17 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -949,7 +949,7 @@ static Property pflash_cfi02_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void pflash_cfi02_unrealize(DeviceState *dev, Error **errp) +static void pflash_cfi02_unrealize(DeviceState *dev) { PFlashCFI02 *pfl = PFLASH_CFI02(dev); timer_del(&pfl->timer); diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 5263e0c9ad..9d8c0b3909 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -452,7 +452,7 @@ virtio_err: vhost_user_cleanup(&s->vhost_user); } -static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) +static void vhost_user_blk_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserBlk *s = VHOST_USER_BLK(dev); diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index fb32717a12..f5f6fc925e 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1223,7 +1223,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) conf->conf.lsecs); } -static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp) +static void virtio_blk_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBlock *s = VIRTIO_BLK(dev); diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 99cb4c67cb..570489d6d9 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -136,7 +136,7 @@ static void xen_block_connect(XenDevice *xendev, Error **errp) g_free(ring_ref); } -static void xen_block_unrealize(XenDevice *xendev, Error **errp) +static void xen_block_unrealize(XenDevice *xendev) { XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); XenBlockDeviceClass *blockdev_class = @@ -157,7 +157,7 @@ static void xen_block_unrealize(XenDevice *xendev, Error **errp) blockdev->dataplane = NULL; if (blockdev_class->unrealize) { - blockdev_class->unrealize(blockdev, errp); + blockdev_class->unrealize(blockdev); } } @@ -567,7 +567,7 @@ static const TypeInfo xen_block_type_info = { .class_init = xen_block_class_init, }; -static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp) +static void xen_disk_unrealize(XenBlockDevice *blockdev) { trace_xen_disk_unrealize(); } @@ -606,7 +606,7 @@ static const TypeInfo xen_disk_type_info = { .class_init = xen_disk_class_init, }; -static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp) +static void xen_cdrom_unrealize(XenBlockDevice *blockdev) { trace_xen_cdrom_unrealize(); } diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c index 1742cb77ec..5f9ccfcc93 100644 --- a/hw/char/serial-pci-multi.c +++ b/hw/char/serial-pci-multi.c @@ -56,7 +56,7 @@ static void multi_serial_pci_exit(PCIDevice *dev) for (i = 0; i < pci->ports; i++) { s = pci->state + i; - object_property_set_bool(OBJECT(s), false, "realized", NULL); + object_property_set_bool(OBJECT(s), false, "realized", &error_abort); memory_region_del_subregion(&pci->iobar, &s->io); g_free(pci->name[i]); } diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index 743552c56b..37818db156 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -68,7 +68,7 @@ static void serial_pci_exit(PCIDevice *dev) PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); SerialState *s = &pci->state; - object_property_set_bool(OBJECT(s), false, "realized", NULL); + object_property_set_bool(OBJECT(s), false, "realized", &error_abort); qemu_free_irq(s->irq); } diff --git a/hw/char/serial.c b/hw/char/serial.c index c822a9ae6c..7d74694587 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -950,7 +950,7 @@ static void serial_realize(DeviceState *dev, Error **errp) serial_reset(s); } -static void serial_unrealize(DeviceState *dev, Error **errp) +static void serial_unrealize(DeviceState *dev) { SerialState *s = SERIAL(dev); diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index b010c21de4..4f46753ea3 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -249,7 +249,7 @@ static void virtconsole_realize(DeviceState *dev, Error **errp) } } -static void virtconsole_unrealize(DeviceState *dev, Error **errp) +static void virtconsole_unrealize(DeviceState *dev) { VirtConsole *vcon = VIRTIO_CONSOLE(dev); diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 99a65bab7f..262089c0c9 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -1010,7 +1010,7 @@ static void virtser_port_device_plug(HotplugHandler *hotplug_dev, virtio_notify_config(VIRTIO_DEVICE(hotplug_dev)); } -static void virtser_port_device_unrealize(DeviceState *dev, Error **errp) +static void virtser_port_device_unrealize(DeviceState *dev) { VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(dev); @@ -1022,7 +1022,7 @@ static void virtser_port_device_unrealize(DeviceState *dev, Error **errp) QTAILQ_REMOVE(&vser->ports, port, next); if (vsc->unrealize) { - vsc->unrealize(dev, errp); + vsc->unrealize(dev); } } @@ -1122,7 +1122,7 @@ static const TypeInfo virtio_serial_port_type_info = { .class_init = virtio_serial_port_class_init, }; -static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp) +static void virtio_serial_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOSerial *vser = VIRTIO_SERIAL(dev); @@ -1147,7 +1147,7 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp) g_free(vser->post_load); } - qbus_set_hotplug_handler(BUS(&vser->bus), NULL, errp); + qbus_set_hotplug_handler(BUS(&vser->bus), NULL, &error_abort); virtio_cleanup(vdev); } diff --git a/hw/core/bus.c b/hw/core/bus.c index 4a57ae107e..a9e4118d3c 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -176,11 +176,10 @@ static void bus_set_realized(Object *obj, bool value, Error **errp) BusState *bus = BUS(obj); BusClass *bc = BUS_GET_CLASS(bus); BusChild *kid; - Error *local_err = NULL; if (value && !bus->realized) { if (bc->realize) { - bc->realize(bus, &local_err); + bc->realize(bus, errp); } /* TODO: recursive realization */ @@ -188,21 +187,13 @@ static void bus_set_realized(Object *obj, bool value, Error **errp) QTAILQ_FOREACH(kid, &bus->children, sibling) { DeviceState *dev = kid->child; object_property_set_bool(OBJECT(dev), false, "realized", - &local_err); - if (local_err != NULL) { - break; - } + &error_abort); } - if (bc->unrealize && local_err == NULL) { - bc->unrealize(bus, &local_err); + if (bc->unrealize) { + bc->unrealize(bus); } } - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - bus->realized = value; } diff --git a/hw/core/cpu.c b/hw/core/cpu.c index 786a1bec8a..5284d384fb 100644 --- a/hw/core/cpu.c +++ b/hw/core/cpu.c @@ -345,7 +345,7 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) trace_init_vcpu(cpu); } -static void cpu_common_unrealizefn(DeviceState *dev, Error **errp) +static void cpu_common_unrealizefn(DeviceState *dev) { CPUState *cpu = CPU(dev); /* NOTE: latest generic point before the cpu is fully unrealized */ diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c index b9aaa52706..a242c076f6 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -173,7 +173,7 @@ static void generic_loader_realize(DeviceState *dev, Error **errp) } } -static void generic_loader_unrealize(DeviceState *dev, Error **errp) +static void generic_loader_unrealize(DeviceState *dev) { qemu_unregister_reset(generic_loader_reset, dev); } diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 2afa2562b8..b9c7a2f904 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -392,7 +392,7 @@ static void device_reset_child_foreach(Object *obj, ResettableChildCallback cb, void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); } /* @@ -945,23 +945,18 @@ static void device_set_realized(Object *obj, bool value, Error **errp) } } else if (!value && dev->realized) { - /* We want local_err to track only the first error */ QLIST_FOREACH(bus, &dev->child_bus, sibling) { object_property_set_bool(OBJECT(bus), false, "realized", - local_err ? NULL : &local_err); + &error_abort); } if (qdev_get_vmsd(dev)) { vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev); } if (dc->unrealize) { - dc->unrealize(dev, local_err ? NULL : &local_err); + dc->unrealize(dev); } dev->pending_deleted_event = true; DEVICE_LISTENER_CALL(unrealize, Reverse, dev); - - if (local_err != NULL) { - goto fail; - } } assert(local_err == NULL); @@ -971,7 +966,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) child_realize_fail: QLIST_FOREACH(bus, &dev->child_bus, sibling) { object_property_set_bool(OBJECT(bus), false, "realized", - NULL); + &error_abort); } if (qdev_get_vmsd(dev)) { @@ -982,7 +977,7 @@ post_realize_fail: g_free(dev->canonical_path); dev->canonical_path = NULL; if (dc->unrealize) { - dc->unrealize(dev, NULL); + dc->unrealize(dev); } fail: @@ -1083,7 +1078,7 @@ static void device_unparent(Object *obj) BusState *bus; if (dev->realized) { - object_property_set_bool(obj, false, "realized", NULL); + object_property_set_bool(obj, false, "realized", &error_abort); } while (dev->num_child_bus) { bus = QLIST_FIRST(&dev->child_bus); diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index 55e07995fe..c159351be3 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -203,7 +203,7 @@ virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features) } static void -virtio_gpu_base_device_unrealize(DeviceState *qdev, Error **errp) +virtio_gpu_base_device_unrealize(DeviceState *qdev) { VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev); diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index 7434d274aa..eefbabd758 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -690,7 +690,7 @@ static void rc4030_realize(DeviceState *dev, Error **errp) address_space_init(&s->dma_as, MEMORY_REGION(&s->dma_mr), "rc4030-dma"); } -static void rc4030_unrealize(DeviceState *dev, Error **errp) +static void rc4030_unrealize(DeviceState *dev) { rc4030State *s = RC4030(dev); diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index 91fb622d63..4eb2d77b87 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -230,7 +230,7 @@ static void kvm_apic_realize(DeviceState *dev, Error **errp) } } -static void kvm_apic_unrealize(DeviceState *dev, Error **errp) +static void kvm_apic_unrealize(DeviceState *dev) { } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 33cf14363a..2128f3d6fe 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1385,7 +1385,7 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev, } pc_dimm_unplug(PC_DIMM(dev), MACHINE(pcms)); - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); out: error_propagate(errp, local_err); } @@ -1493,7 +1493,7 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev, found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL); found_cpu->cpu = NULL; - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); /* decrement the number of CPUs */ x86ms->boot_cpus--; diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 4909b14b91..06b11583f5 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -36,7 +36,7 @@ /* --------------------------------- */ static char *idebus_get_fw_dev_path(DeviceState *dev); -static void idebus_unrealize(BusState *qdev, Error **errp); +static void idebus_unrealize(BusState *qdev); static Property ide_props[] = { DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1), @@ -51,7 +51,7 @@ static void ide_bus_class_init(ObjectClass *klass, void *data) k->unrealize = idebus_unrealize; } -static void idebus_unrealize(BusState *bus, Error **errp) +static void idebus_unrealize(BusState *bus) { IDEBus *ibus = IDE_BUS(bus); diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c index e8ae6c148a..09cf260985 100644 --- a/hw/input/virtio-input-hid.c +++ b/hw/input/virtio-input-hid.c @@ -165,7 +165,7 @@ static void virtio_input_hid_realize(DeviceState *dev, Error **errp) } } -static void virtio_input_hid_unrealize(DeviceState *dev, Error **errp) +static void virtio_input_hid_unrealize(DeviceState *dev) { VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev); qemu_input_handler_unregister(vhid->hs); diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c index f2ab6df676..85daf73f1a 100644 --- a/hw/input/virtio-input-host.c +++ b/hw/input/virtio-input-host.c @@ -178,7 +178,7 @@ err_close: return; } -static void virtio_input_host_unrealize(DeviceState *dev, Error **errp) +static void virtio_input_host_unrealize(DeviceState *dev) { VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev); diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index 4d49790f50..54bcb46c74 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -276,19 +276,14 @@ static void virtio_input_finalize(Object *obj) g_free(vinput->queue); } -static void virtio_input_device_unrealize(DeviceState *dev, Error **errp) +static void virtio_input_device_unrealize(DeviceState *dev) { VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOInput *vinput = VIRTIO_INPUT(dev); - Error *local_err = NULL; if (vic->unrealize) { - vic->unrealize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + vic->unrealize(dev); } virtio_delete_queue(vinput->evt); virtio_delete_queue(vinput->sts); diff --git a/hw/intc/apic.c b/hw/intc/apic.c index bd40467965..6b46839ef4 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -900,7 +900,7 @@ static void apic_realize(DeviceState *dev, Error **errp) msi_nonbroken = true; } -static void apic_unrealize(DeviceState *dev, Error **errp) +static void apic_unrealize(DeviceState *dev) { APICCommonState *s = APIC(dev); diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 243bb69430..7da2862b3d 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -293,13 +293,13 @@ static void apic_common_realize(DeviceState *dev, Error **errp) s, -1, 0, NULL); } -static void apic_common_unrealize(DeviceState *dev, Error **errp) +static void apic_common_unrealize(DeviceState *dev) { APICCommonState *s = APIC_COMMON(dev); APICCommonClass *info = APIC_COMMON_GET_CLASS(s); vmstate_unregister(NULL, &vmstate_apic_common, s); - info->unrealize(dev, errp); + info->unrealize(dev); if (apic_report_tpr_access && info->enable_tpr_reporting) { info->enable_tpr_reporting(s, false); diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 15747fe2c2..ffe30dc457 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -451,7 +451,7 @@ static void ioapic_realize(DeviceState *dev, Error **errp) qemu_add_machine_init_done_notifier(&s->machine_done); } -static void ioapic_unrealize(DeviceState *dev, Error **errp) +static void ioapic_unrealize(DeviceState *dev) { IOAPICCommonState *s = IOAPIC_COMMON(dev); diff --git a/hw/intc/xics.c b/hw/intc/xics.c index e56d578841..d5032c8f8a 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -338,7 +338,7 @@ static void icp_realize(DeviceState *dev, Error **errp) vmstate_register(NULL, icp->cs->cpu_index, &vmstate_icp_server, icp); } -static void icp_unrealize(DeviceState *dev, Error **errp) +static void icp_unrealize(DeviceState *dev) { ICPState *icp = ICP(dev); diff --git a/hw/ipack/ipack.c b/hw/ipack/ipack.c index 49787a13bc..f19ecaeb1c 100644 --- a/hw/ipack/ipack.c +++ b/hw/ipack/ipack.c @@ -60,15 +60,13 @@ static void ipack_device_realize(DeviceState *dev, Error **errp) k->realize(dev, errp); } -static void ipack_device_unrealize(DeviceState *dev, Error **errp) +static void ipack_device_unrealize(DeviceState *dev) { IPackDevice *idev = IPACK_DEVICE(dev); IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev); - Error *err = NULL; if (k->unrealize) { - k->unrealize(dev, &err); - error_propagate(errp, err); + k->unrealize(dev); return; } diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index b81c82f57b..f2a86ec4ee 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -199,7 +199,7 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp) host_memory_backend_set_mapped(dimm->hostmem, true); } -static void pc_dimm_unrealize(DeviceState *dev, Error **errp) +static void pc_dimm_unrealize(DeviceState *dev) { PCDIMMDevice *dimm = PC_DIMM(dev); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index b43fd7d608..b7f3d1b2eb 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3077,7 +3077,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) n->qdev = dev; } -static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) +static void virtio_net_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIONet *n = VIRTIO_NET(dev); diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c index 2e8a1e3812..ff5db03e6b 100644 --- a/hw/nvram/mac_nvram.c +++ b/hw/nvram/mac_nvram.c @@ -107,7 +107,7 @@ static void macio_nvram_realizefn(DeviceState *dev, Error **errp) sysbus_init_mmio(d, &s->mem); } -static void macio_nvram_unrealizefn(DeviceState *dev, Error **errp) +static void macio_nvram_unrealizefn(DeviceState *dev) { MacIONVRAMState *s = MACIO_NVRAM(dev); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index b5bc842fac..70c66965f5 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -146,7 +146,7 @@ static void pcie_bus_realize(BusState *qbus, Error **errp) } } -static void pci_bus_unrealize(BusState *qbus, Error **errp) +static void pci_bus_unrealize(BusState *qbus) { PCIBus *bus = PCI_BUS(qbus); @@ -456,7 +456,7 @@ void pci_root_bus_cleanup(PCIBus *bus) { pci_bus_uninit(bus); /* the caller of the unplug hotplug handler will delete this device */ - object_property_set_bool(OBJECT(bus), false, "realized", NULL); + object_property_set_bool(OBJECT(bus), false, "realized", &error_abort); } void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, @@ -1118,7 +1118,7 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev) pci_unregister_vga(pci_dev); } -static void pci_qdev_unrealize(DeviceState *dev, Error **errp) +static void pci_qdev_unrealize(DeviceState *dev) { PCIDevice *pci_dev = PCI_DEVICE(dev); PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); @@ -2108,7 +2108,7 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) error_setg(errp, "failover primary device must be on " "PCIExpress bus"); error_propagate(errp, local_err); - pci_qdev_unrealize(DEVICE(pci_dev), NULL); + pci_qdev_unrealize(DEVICE(pci_dev)); return; } class_id = pci_get_word(pci_dev->config + PCI_CLASS_DEVICE); @@ -2116,7 +2116,7 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) error_setg(errp, "failover primary device is not an " "Ethernet device"); error_propagate(errp, local_err); - pci_qdev_unrealize(DEVICE(pci_dev), NULL); + pci_qdev_unrealize(DEVICE(pci_dev)); return; } if (!(pci_dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) @@ -2126,7 +2126,7 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) error_setg(errp, "failover: primary device must be in its own " "PCI slot"); error_propagate(errp, local_err); - pci_qdev_unrealize(DEVICE(pci_dev), NULL); + pci_qdev_unrealize(DEVICE(pci_dev)); return; } qdev->allow_unplug_during_migration = true; @@ -2142,7 +2142,7 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) pci_add_option_rom(pci_dev, is_default_rom, &local_err); if (local_err) { error_propagate(errp, local_err); - pci_qdev_unrealize(DEVICE(pci_dev), NULL); + pci_qdev_unrealize(DEVICE(pci_dev)); return; } } diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index abc99b6eff..f50e10b8fb 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -457,7 +457,7 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); } static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque) diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index 7f0aa28e44..b76d3d2c9a 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -547,7 +547,7 @@ void shpc_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); } void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev, diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 7033104676..96a446f001 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -275,7 +275,7 @@ static void pnv_core_cpu_unrealize(PnvCore *pc, PowerPCCPU *cpu) object_unparent(OBJECT(cpu)); } -static void pnv_core_unrealize(DeviceState *dev, Error **errp) +static void pnv_core_unrealize(DeviceState *dev) { PnvCore *pc = PNV_CORE(dev); CPUCore *cc = CPU_CORE(dev); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b73f4d94d3..c0bf8c8d4f 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3670,7 +3670,7 @@ static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev)); pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev)); - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); spapr_pending_dimm_unplugs_remove(spapr, ds); } @@ -3763,7 +3763,7 @@ static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) assert(core_slot); core_slot->cpu = NULL; - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); } static @@ -4036,7 +4036,7 @@ void spapr_phb_release(DeviceState *dev) static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) { - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); } static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev, @@ -4072,7 +4072,7 @@ static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev { SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); object_unparent(OBJECT(dev)); spapr->tpm_proxy = NULL; } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index df5c7742ca..e1f76c74f3 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -218,7 +218,7 @@ static void spapr_cpu_core_reset_handler(void *opaque) spapr_cpu_core_reset(opaque); } -static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp) +static void spapr_cpu_core_unrealize(DeviceState *dev) { SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); CPUCore *cc = CPU_CORE(dev); diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 728307a992..8b2171f698 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -541,7 +541,7 @@ static void realize(DeviceState *d, Error **errp) trace_spapr_drc_realize_complete(spapr_drc_index(drc)); } -static void unrealize(DeviceState *d, Error **errp) +static void unrealize(DeviceState *d) { SpaprDrc *drc = SPAPR_DR_CONNECTOR(d); Object *root_container; @@ -551,7 +551,7 @@ static void unrealize(DeviceState *d, Error **errp) vmstate_unregister(VMSTATE_IF(drc), &vmstate_spapr_drc, drc); root_container = container_get(object_get_root(), DRC_CONTAINER_PATH); name = g_strdup_printf("%x", spapr_drc_index(drc)); - object_property_del(root_container, name, errp); + object_property_del(root_container, name, &error_abort); g_free(name); } @@ -650,17 +650,11 @@ static void realize_physical(DeviceState *d, Error **errp) qemu_register_reset(drc_physical_reset, drcp); } -static void unrealize_physical(DeviceState *d, Error **errp) +static void unrealize_physical(DeviceState *d) { SpaprDrcPhysical *drcp = SPAPR_DRC_PHYSICAL(d); - Error *local_err = NULL; - - unrealize(d, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + unrealize(d); vmstate_unregister(VMSTATE_IF(drcp), &vmstate_spapr_drc_physical, drcp); qemu_unregister_reset(drc_physical_reset, drcp); } diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 601b896214..7e1d6d59ac 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -416,7 +416,7 @@ void spapr_tce_table_disable(SpaprTceTable *tcet) tcet->nb_table = 0; } -static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp) +static void spapr_tce_table_unrealize(DeviceState *dev) { SpaprTceTable *tcet = SPAPR_TCE_TABLE(dev); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 61b84a392d..616034222d 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1627,7 +1627,8 @@ static void spapr_pci_unplug(HotplugHandler *plug_handler, return; } - object_property_set_bool(OBJECT(plugged_dev), false, "realized", NULL); + object_property_set_bool(OBJECT(plugged_dev), false, "realized", + &error_abort); } static void spapr_pci_unplug_request(HotplugHandler *plug_handler, @@ -1715,7 +1716,7 @@ static void spapr_phb_finalizefn(Object *obj) sphb->dtbusname = NULL; } -static void spapr_phb_unrealize(DeviceState *dev, Error **errp) +static void spapr_phb_unrealize(DeviceState *dev) { SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); SysBusDevice *s = SYS_BUS_DEVICE(dev); @@ -1724,7 +1725,6 @@ static void spapr_phb_unrealize(DeviceState *dev, Error **errp) SpaprTceTable *tcet; int i; const unsigned windows_supported = spapr_phb_windows_supported(sphb); - Error *local_err = NULL; spapr_phb_nvgpu_free(sphb); @@ -1745,11 +1745,7 @@ static void spapr_phb_unrealize(DeviceState *dev, Error **errp) } } - remove_drcs(sphb, phb->bus, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + remove_drcs(sphb, phb->bus, &error_abort); for (i = PCI_NUM_PINS - 1; i >= 0; i--) { if (sphb->lsi_table[i].irq) { @@ -2011,7 +2007,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) return; unrealize: - spapr_phb_unrealize(dev, NULL); + spapr_phb_unrealize(dev); } static int spapr_phb_children_reset(Object *child, void *opaque) diff --git a/hw/ppc/spapr_tpm_proxy.c b/hw/ppc/spapr_tpm_proxy.c index 991615d77a..a01f81f9e0 100644 --- a/hw/ppc/spapr_tpm_proxy.c +++ b/hw/ppc/spapr_tpm_proxy.c @@ -140,7 +140,7 @@ static void spapr_tpm_proxy_realize(DeviceState *d, Error **errp) qemu_register_reset(spapr_tpm_proxy_reset, tpm_proxy); } -static void spapr_tpm_proxy_unrealize(DeviceState *d, Error **errp) +static void spapr_tpm_proxy_unrealize(DeviceState *d) { SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(d); diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index 5d5286bc6e..3f6aec6b6a 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -54,7 +54,7 @@ static void ccw_device_unplug(HotplugHandler *hotplug_dev, css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); } static void virtual_css_bus_reset(BusState *qbus) diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index 569020dae4..c48510f9e5 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -132,7 +132,7 @@ out_err_propagate: error_propagate(errp, err); } -static void s390_ccw_unrealize(S390CCWDevice *cdev, Error **errp) +static void s390_ccw_unrealize(S390CCWDevice *cdev) { CcwDevice *ccw_dev = CCW_DEVICE(cdev); SubchDev *sch = ccw_dev->sch; diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index ed8be124da..c4a4259f0c 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -1003,7 +1003,7 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, pbdev->fh, pbdev->fid); bus = pci_get_bus(pci_dev); devfn = pci_dev->devfn; - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); s390_pci_msix_free(pbdev); s390_pci_iommu_free(s, bus, devfn); @@ -1014,7 +1014,7 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, pbdev->fid = 0; QTAILQ_REMOVE(&s->zpci_devs, pbdev, link); g_hash_table_remove(s->zpci_table, &pbdev->idx); - object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); } } diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 64f928fc7d..c1f4bb1d33 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -752,14 +752,14 @@ out_err: g_free(sch); } -static void virtio_ccw_device_unrealize(VirtioCcwDevice *dev, Error **errp) +static void virtio_ccw_device_unrealize(VirtioCcwDevice *dev) { VirtIOCCWDeviceClass *dc = VIRTIO_CCW_DEVICE_GET_CLASS(dev); CcwDevice *ccw_dev = CCW_DEVICE(dev); SubchDev *sch = ccw_dev->sch; if (dc->unrealize) { - dc->unrealize(dev, errp); + dc->unrealize(dev); } if (sch) { @@ -1155,11 +1155,11 @@ static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp) virtio_ccw_device_realize(_dev, errp); } -static void virtio_ccw_busdev_unrealize(DeviceState *dev, Error **errp) +static void virtio_ccw_busdev_unrealize(DeviceState *dev) { VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; - virtio_ccw_device_unrealize(_dev, errp); + virtio_ccw_device_unrealize(_dev); } static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev, diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 3453aa1f98..c0e3355248 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -76,7 +76,7 @@ typedef struct VirtioCcwDevice VirtioCcwDevice; typedef struct VirtIOCCWDeviceClass { CCWDeviceClass parent_class; void (*realize)(VirtioCcwDevice *dev, Error **errp); - void (*unrealize)(VirtioCcwDevice *dev, Error **errp); + void (*unrealize)(VirtioCcwDevice *dev); void (*parent_reset)(DeviceState *dev); } VirtIOCCWDeviceClass; diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index ec53b14f7f..63ff4181de 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -2312,7 +2312,7 @@ static void lsi_scsi_realize(PCIDevice *dev, Error **errp) scsi_bus_new(&s->bus, sizeof(s->bus), d, &lsi_scsi_info, NULL); } -static void lsi_scsi_unrealize(DeviceState *dev, Error **errp) +static void lsi_scsi_unrealize(DeviceState *dev) { LSIState *s = LSI53C895A(dev); diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 1733307407..2836f807a0 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -59,11 +59,11 @@ static void scsi_device_realize(SCSIDevice *s, Error **errp) } } -static void scsi_device_unrealize(SCSIDevice *s, Error **errp) +static void scsi_device_unrealize(SCSIDevice *s) { SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s); if (sc->unrealize) { - sc->unrealize(s, errp); + sc->unrealize(s); } } @@ -222,10 +222,9 @@ static void scsi_qdev_realize(DeviceState *qdev, Error **errp) scsi_dma_restart_cb, dev); } -static void scsi_qdev_unrealize(DeviceState *qdev, Error **errp) +static void scsi_qdev_unrealize(DeviceState *qdev) { SCSIDevice *dev = SCSI_DEVICE(qdev); - Error *local_err = NULL; if (dev->vmsentry) { qemu_del_vm_change_state_handler(dev->vmsentry); @@ -233,11 +232,7 @@ static void scsi_qdev_unrealize(DeviceState *qdev, Error **errp) scsi_device_purge_requests(dev, SENSE_CODE(NO_SENSE)); - scsi_device_unrealize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + scsi_device_unrealize(dev); blockdev_mark_auto_del(dev->conf.blk); } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index e5bcd0baf8..387503e11b 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2421,7 +2421,7 @@ static void scsi_realize(SCSIDevice *dev, Error **errp) dev->conf.lsecs); } -static void scsi_unrealize(SCSIDevice *dev, Error **errp) +static void scsi_unrealize(SCSIDevice *dev) { del_boot_device_lchs(&dev->qdev, NULL); } diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index ffa667171d..c1b012aea4 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -248,7 +248,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) return; } -static void vhost_scsi_unrealize(DeviceState *dev, Error **errp) +static void vhost_scsi_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev); diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index ae380b63b4..cbb5d97599 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -143,7 +143,7 @@ free_virtio: virtio_scsi_common_unrealize(dev); } -static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp) +static void vhost_user_scsi_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserSCSI *s = VHOST_USER_SCSI(dev); diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 472bbd233b..9b72094a61 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -954,7 +954,7 @@ void virtio_scsi_common_unrealize(DeviceState *dev) virtio_cleanup(vdev); } -static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp) +static void virtio_scsi_device_unrealize(DeviceState *dev) { VirtIOSCSI *s = VIRTIO_SCSI(dev); diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index 34141400f8..e7c8a523b5 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -335,7 +335,7 @@ extern const VMStateDescription sdhci_vmstate; void sdhci_initfn(SDHCIState *s); void sdhci_uninitfn(SDHCIState *s); void sdhci_common_realize(SDHCIState *s, Error **errp); -void sdhci_common_unrealize(SDHCIState *s, Error **errp); +void sdhci_common_unrealize(SDHCIState *s); void sdhci_common_class_init(ObjectClass *klass, void *data); #endif diff --git a/hw/sd/sdhci-pci.c b/hw/sd/sdhci-pci.c index 19fa8bd8ed..4f5977d487 100644 --- a/hw/sd/sdhci-pci.c +++ b/hw/sd/sdhci-pci.c @@ -50,7 +50,7 @@ static void sdhci_pci_exit(PCIDevice *dev) { SDHCIState *s = PCI_SDHCI(dev); - sdhci_common_unrealize(s, &error_abort); + sdhci_common_unrealize(s); sdhci_uninitfn(s); } diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 70531ad360..1b75d7bab9 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1346,7 +1346,7 @@ void sdhci_common_realize(SDHCIState *s, Error **errp) SDHC_REGISTERS_MAP_SIZE); } -void sdhci_common_unrealize(SDHCIState *s, Error **errp) +void sdhci_common_unrealize(SDHCIState *s) { /* This function is expected to be called only once for each class: * - SysBus: via DeviceClass->unrealize(), @@ -1479,11 +1479,11 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); } -static void sdhci_sysbus_unrealize(DeviceState *dev, Error **errp) +static void sdhci_sysbus_unrealize(DeviceState *dev) { SDHCIState *s = SYSBUS_SDHCI(dev); - sdhci_common_unrealize(s, &error_abort); + sdhci_common_unrealize(s); if (s->dma_mr) { address_space_destroy(s->dma_as); diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 686f492112..fa07df98a2 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -14,7 +14,7 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); static char *usb_get_dev_path(DeviceState *dev); static char *usb_get_fw_dev_path(DeviceState *qdev); -static void usb_qdev_unrealize(DeviceState *qdev, Error **errp); +static void usb_qdev_unrealize(DeviceState *qdev); static Property usb_props[] = { DEFINE_PROP_STRING("port", USBDevice, port_path), @@ -130,12 +130,12 @@ USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr) return NULL; } -static void usb_device_unrealize(USBDevice *dev, Error **errp) +static void usb_device_unrealize(USBDevice *dev) { USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); if (klass->unrealize) { - klass->unrealize(dev, errp); + klass->unrealize(dev); } } @@ -265,14 +265,14 @@ static void usb_qdev_realize(DeviceState *qdev, Error **errp) if (dev->auto_attach) { usb_device_attach(dev, &local_err); if (local_err) { - usb_qdev_unrealize(qdev, NULL); + usb_qdev_unrealize(qdev); error_propagate(errp, local_err); return; } } } -static void usb_qdev_unrealize(DeviceState *qdev, Error **errp) +static void usb_qdev_unrealize(DeviceState *qdev) { USBDevice *dev = USB_DEVICE(qdev); USBDescString *s, *next; @@ -286,7 +286,7 @@ static void usb_qdev_unrealize(DeviceState *qdev, Error **errp) if (dev->attached) { usb_device_detach(dev); } - usb_device_unrealize(dev, errp); + usb_device_unrealize(dev); if (dev->port) { usb_release_port(dev); } diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index 3083124556..7d6105ef34 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -562,7 +562,7 @@ out1: qemu_mutex_destroy(&card->event_list_mutex); } -static void emulated_unrealize(CCIDCardState *base, Error **errp) +static void emulated_unrealize(CCIDCardState *base) { EmulatedState *card = EMULATED_CCID_CARD(base); VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL); diff --git a/hw/usb/ccid.h b/hw/usb/ccid.h index bb2fdbfff3..531bf28fb0 100644 --- a/hw/usb/ccid.h +++ b/hw/usb/ccid.h @@ -36,7 +36,7 @@ typedef struct CCIDCardClass { const uint8_t *apdu, uint32_t len); void (*realize)(CCIDCardState *card, Error **errp); - void (*unrealize)(CCIDCardState *card, Error **errp); + void (*unrealize)(CCIDCardState *card); } CCIDCardClass; /* diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index 6fa213fad5..1371c44f48 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -923,7 +923,7 @@ static void usb_audio_handle_data(USBDevice *dev, USBPacket *p) } } -static void usb_audio_unrealize(USBDevice *dev, Error **errp) +static void usb_audio_unrealize(USBDevice *dev) { USBAudioState *s = USB_AUDIO(dev); diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 67ec8b69ec..89f63b698b 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -699,7 +699,7 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p) } } -static void usb_hid_unrealize(USBDevice *dev, Error **errp) +static void usb_hid_unrealize(USBDevice *dev) { USBHIDState *us = USB_HID(dev); diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 49a573b346..5f19dd9fb5 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -565,7 +565,7 @@ static void usb_hub_handle_data(USBDevice *dev, USBPacket *p) } } -static void usb_hub_unrealize(USBDevice *dev, Error **errp) +static void usb_hub_unrealize(USBDevice *dev) { USBHubState *s = (USBHubState *)dev; int i; diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 720744488b..c69756709b 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1326,7 +1326,7 @@ static void usbnet_cleanup(NetClientState *nc) s->nic = NULL; } -static void usb_net_unrealize(USBDevice *dev, Error **errp) +static void usb_net_unrealize(USBDevice *dev) { USBNetState *s = (USBNetState *) dev; diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index ef72738ced..ada18c1983 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1146,7 +1146,7 @@ static void ccid_handle_data(USBDevice *dev, USBPacket *p) } } -static void ccid_unrealize(USBDevice *dev, Error **errp) +static void ccid_unrealize(USBDevice *dev) { USBCCIDState *s = USB_CCID_DEV(dev); @@ -1269,23 +1269,18 @@ void ccid_card_card_inserted(CCIDCardState *card) ccid_on_slot_change(s, true); } -static void ccid_card_unrealize(DeviceState *qdev, Error **errp) +static void ccid_card_unrealize(DeviceState *qdev) { CCIDCardState *card = CCID_CARD(qdev); CCIDCardClass *cc = CCID_CARD_GET_CLASS(card); USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent); USBCCIDState *s = USB_CCID_DEV(dev); - Error *local_err = NULL; if (ccid_card_inserted(s)) { ccid_card_card_removed(card); } if (cc->unrealize) { - cc->unrealize(card, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } + cc->unrealize(card); } s->card = NULL; } diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 11a8684cc2..a3a4d41c07 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -894,7 +894,7 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) } } -static void usb_uas_unrealize(USBDevice *dev, Error **errp) +static void usb_uas_unrealize(USBDevice *dev) { UASDevice *uas = USB_UAS(dev); diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index 8ed57b3b44..8aba44b8bc 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -331,7 +331,7 @@ static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p) } } -static void usb_wacom_unrealize(USBDevice *dev, Error **errp) +static void usb_wacom_unrealize(USBDevice *dev) { USBWacomState *s = (USBWacomState *) dev; diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index fc73a054c6..4c37c8e227 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -105,7 +105,7 @@ static void usb_ehci_pci_exit(PCIDevice *dev) EHCIPCIState *i = PCI_EHCI(dev); EHCIState *s = &i->ehci; - usb_ehci_unrealize(s, DEVICE(dev), NULL); + usb_ehci_unrealize(s, DEVICE(dev)); g_free(s->irq); s->irq = NULL; diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 29d49c2d7e..1495e8f7fa 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -2522,7 +2522,7 @@ void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp) s->vmstate = qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s); } -void usb_ehci_unrealize(EHCIState *s, DeviceState *dev, Error **errp) +void usb_ehci_unrealize(EHCIState *s, DeviceState *dev) { trace_usb_ehci_unrealize(); diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index edb59311c4..57b38cfc05 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -324,7 +324,7 @@ extern const VMStateDescription vmstate_ehci; void usb_ehci_init(EHCIState *s, DeviceState *dev); void usb_ehci_finalize(EHCIState *s); void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp); -void usb_ehci_unrealize(EHCIState *s, DeviceState *dev, Error **errp); +void usb_ehci_unrealize(EHCIState *s, DeviceState *dev); void ehci_reset(void *opaque); #define TYPE_PCI_EHCI "pci-ehci-usb" diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 78a5c2ba55..e28441379d 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -1104,7 +1104,7 @@ static void usb_host_instance_init(Object *obj) &udev->qdev); } -static void usb_host_unrealize(USBDevice *udev, Error **errp) +static void usb_host_unrealize(USBDevice *udev) { USBHostDevice *s = USB_HOST_DEVICE(udev); diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index e9a97feaed..417a60a2e6 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -1468,7 +1468,7 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev) } } -static void usbredir_unrealize(USBDevice *udev, Error **errp) +static void usbredir_unrealize(USBDevice *udev) { USBRedirDevice *dev = USB_REDIRECT(udev); diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index 8649ac15f9..95564c17ed 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -124,7 +124,7 @@ out_get_dev_err: vfio_put_group(vfio_group); } -static void vfio_ap_unrealize(DeviceState *dev, Error **errp) +static void vfio_ap_unrealize(DeviceState *dev) { APDevice *apdev = AP_DEVICE(dev); VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index 50cc2ec75c..c8624943c1 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -521,13 +521,13 @@ out_device_err: vfio_put_group(group); out_group_err: if (cdc->unrealize) { - cdc->unrealize(cdev, NULL); + cdc->unrealize(cdev); } out_err_propagate: error_propagate(errp, err); } -static void vfio_ccw_unrealize(DeviceState *dev, Error **errp) +static void vfio_ccw_unrealize(DeviceState *dev) { CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev); S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev); @@ -541,7 +541,7 @@ static void vfio_ccw_unrealize(DeviceState *dev, Error **errp) vfio_put_group(group); if (cdc->unrealize) { - cdc->unrealize(cdev, errp); + cdc->unrealize(cdev); } } diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c index 6136768875..1bc5d03a00 100644 --- a/hw/virtio/vhost-user-fs.c +++ b/hw/virtio/vhost-user-fs.c @@ -241,7 +241,7 @@ err_virtio: return; } -static void vuf_device_unrealize(DeviceState *dev, Error **errp) +static void vuf_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserFS *fs = VHOST_USER_FS(dev); diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index 09b6b07f94..4a228f5168 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -377,7 +377,7 @@ err_virtio: return; } -static void vhost_vsock_device_unrealize(DeviceState *dev, Error **errp) +static void vhost_vsock_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostVSock *vsock = VHOST_VSOCK(dev); diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 6d3ddf6449..065cd450f1 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -819,7 +819,7 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) reset_stats(s); } -static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp) +static void virtio_balloon_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBalloon *s = VIRTIO_BALLOON(dev); diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index 4c65114de5..bd9165c565 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -822,7 +822,7 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp) cryptodev_backend_set_used(vcrypto->cryptodev, true); } -static void virtio_crypto_device_unrealize(DeviceState *dev, Error **errp) +static void virtio_crypto_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev); diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 22ba8848c2..483883ec1d 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -688,7 +688,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) } } -static void virtio_iommu_device_unrealize(DeviceState *dev, Error **errp) +static void virtio_iommu_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOIOMMU *s = VIRTIO_IOMMU(dev); diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c index 43399522f5..c3374b2f3f 100644 --- a/hw/virtio/virtio-pmem.c +++ b/hw/virtio/virtio-pmem.c @@ -124,7 +124,7 @@ static void virtio_pmem_realize(DeviceState *dev, Error **errp) pmem->rq_vq = virtio_add_queue(vdev, 128, virtio_pmem_flush); } -static void virtio_pmem_unrealize(DeviceState *dev, Error **errp) +static void virtio_pmem_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOPMEM *pmem = VIRTIO_PMEM(dev); diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index 672619c780..a8df41b11b 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -230,7 +230,7 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp) vrng); } -static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp) +static void virtio_rng_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIORNG *vrng = VIRTIO_RNG(dev); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index b6c8ef5bc0..850fcce5e7 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3622,7 +3622,7 @@ static void virtio_device_realize(DeviceState *dev, Error **errp) virtio_bus_device_plugged(vdev, &err); if (err != NULL) { error_propagate(errp, err); - vdc->unrealize(dev, NULL); + vdc->unrealize(dev); return; } @@ -3630,20 +3630,15 @@ static void virtio_device_realize(DeviceState *dev, Error **errp) memory_listener_register(&vdev->listener, vdev->dma_as); } -static void virtio_device_unrealize(DeviceState *dev, Error **errp) +static void virtio_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev); - Error *err = NULL; virtio_bus_device_unplugged(vdev); if (vdc->unrealize != NULL) { - vdc->unrealize(dev, &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } + vdc->unrealize(dev); } g_free(vdev->bus_name); diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c index 5b6eb2b09f..71a945f0bd 100644 --- a/hw/watchdog/wdt_diag288.c +++ b/hw/watchdog/wdt_diag288.c @@ -108,7 +108,7 @@ static void wdt_diag288_realize(DeviceState *dev, Error **errp) dev); } -static void wdt_diag288_unrealize(DeviceState *dev, Error **errp) +static void wdt_diag288_unrealize(DeviceState *dev) { DIAG288State *diag288 = DIAG288(dev); diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index 18237b34ea..32dd4461be 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -428,7 +428,7 @@ static void xen_bus_backend_changed(void *opaque) xen_bus_cleanup(xenbus); } -static void xen_bus_unrealize(BusState *bus, Error **errp) +static void xen_bus_unrealize(BusState *bus) { XenBus *xenbus = XEN_BUS(bus); @@ -486,7 +486,7 @@ static void xen_bus_realize(BusState *bus, Error **errp) return; fail: - xen_bus_unrealize(bus, &error_abort); + xen_bus_unrealize(bus); } static void xen_bus_unplug_request(HotplugHandler *hotplug, @@ -1189,7 +1189,7 @@ void xen_device_unbind_event_channel(XenDevice *xendev, g_free(channel); } -static void xen_device_unrealize(DeviceState *dev, Error **errp) +static void xen_device_unrealize(DeviceState *dev) { XenDevice *xendev = XEN_DEVICE(dev); XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); @@ -1208,7 +1208,7 @@ static void xen_device_unrealize(DeviceState *dev, Error **errp) } if (xendev_class->unrealize) { - xendev_class->unrealize(xendev, errp); + xendev_class->unrealize(xendev); } /* Make sure all event channels are cleaned up */ @@ -1242,7 +1242,7 @@ static void xen_device_exit(Notifier *n, void *data) { XenDevice *xendev = container_of(n, XenDevice, exit); - xen_device_unrealize(DEVICE(xendev), &error_abort); + xen_device_unrealize(DEVICE(xendev)); } static void xen_device_realize(DeviceState *dev, Error **errp) @@ -1336,7 +1336,7 @@ static void xen_device_realize(DeviceState *dev, Error **errp) return; unrealize: - xen_device_unrealize(dev, &error_abort); + xen_device_unrealize(dev); } static Property xen_device_props[] = { diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 6f537f687f..b870b27966 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -30,10 +30,10 @@ typedef enum DeviceCategory { } DeviceCategory; typedef void (*DeviceRealize)(DeviceState *dev, Error **errp); -typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp); +typedef void (*DeviceUnrealize)(DeviceState *dev); typedef void (*DeviceReset)(DeviceState *dev); typedef void (*BusRealize)(BusState *bus, Error **errp); -typedef void (*BusUnrealize)(BusState *bus, Error **errp); +typedef void (*BusUnrealize)(BusState *bus); /** * DeviceClass: diff --git a/include/hw/s390x/s390-ccw.h b/include/hw/s390x/s390-ccw.h index fffb54562f..7f27bc2f53 100644 --- a/include/hw/s390x/s390-ccw.h +++ b/include/hw/s390x/s390-ccw.h @@ -33,7 +33,7 @@ typedef struct S390CCWDevice { typedef struct S390CCWDeviceClass { CCWDeviceClass parent_class; void (*realize)(S390CCWDevice *dev, char *sysfsdev, Error **errp); - void (*unrealize)(S390CCWDevice *dev, Error **errp); + void (*unrealize)(S390CCWDevice *dev); IOInstEnding (*handle_request) (SubchDev *sch); int (*handle_halt) (SubchDev *sch); int (*handle_clear) (SubchDev *sch); diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 332ef602f4..2fc23e44ba 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -59,7 +59,7 @@ struct SCSIRequest { typedef struct SCSIDeviceClass { DeviceClass parent_class; void (*realize)(SCSIDevice *dev, Error **errp); - void (*unrealize)(SCSIDevice *dev, Error **errp); + void (*unrealize)(SCSIDevice *dev); int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf, void *hba_private); SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun, diff --git a/include/hw/usb.h b/include/hw/usb.h index c24d968a19..1cf1cd9584 100644 --- a/include/hw/usb.h +++ b/include/hw/usb.h @@ -272,7 +272,7 @@ struct USBDevice { OBJECT_GET_CLASS(USBDeviceClass, (obj), TYPE_USB_DEVICE) typedef void (*USBDeviceRealize)(USBDevice *dev, Error **errp); -typedef void (*USBDeviceUnrealize)(USBDevice *dev, Error **errp); +typedef void (*USBDeviceUnrealize)(USBDevice *dev); typedef struct USBDeviceClass { DeviceClass parent_class; diff --git a/include/hw/xen/xen-block.h b/include/hw/xen/xen-block.h index 11d351b4b3..2cd2fc2701 100644 --- a/include/hw/xen/xen-block.h +++ b/include/hw/xen/xen-block.h @@ -57,7 +57,7 @@ typedef struct XenBlockDevice { } XenBlockDevice; typedef void (*XenBlockDeviceRealize)(XenBlockDevice *blockdev, Error **errp); -typedef void (*XenBlockDeviceUnrealize)(XenBlockDevice *blockdev, Error **errp); +typedef void (*XenBlockDeviceUnrealize)(XenBlockDevice *blockdev); typedef struct XenBlockDeviceClass { /*< private >*/ diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index c18c1372af..4ec0bb072f 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -42,7 +42,7 @@ typedef void (*XenDeviceRealize)(XenDevice *xendev, Error **errp); typedef void (*XenDeviceFrontendChanged)(XenDevice *xendev, enum xenbus_state frontend_state, Error **errp); -typedef void (*XenDeviceUnrealize)(XenDevice *xendev, Error **errp); +typedef void (*XenDeviceUnrealize)(XenDevice *xendev); typedef struct XenDeviceClass { /*< private >*/ diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 6a64d2a5cd..7a4a8e3847 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6722,11 +6722,10 @@ out: } } -static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp) +static void x86_cpu_unrealizefn(DeviceState *dev) { X86CPU *cpu = X86_CPU(dev); X86CPUClass *xcc = X86_CPU_GET_CLASS(dev); - Error *local_err = NULL; #ifndef CONFIG_USER_ONLY cpu_remove_sync(CPU(dev)); @@ -6738,11 +6737,7 @@ static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp) cpu->apic_state = NULL; } - xcc->parent_unrealize(dev, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } + xcc->parent_unrealize(dev); } typedef struct BitProperty { diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index 2b6e832c4c..d8adc1bd49 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -10293,19 +10293,14 @@ unrealize: cpu_exec_unrealizefn(cs); } -static void ppc_cpu_unrealize(DeviceState *dev, Error **errp) +static void ppc_cpu_unrealize(DeviceState *dev) { PowerPCCPU *cpu = POWERPC_CPU(dev); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - Error *local_err = NULL; opc_handler_t **table, **table_2; int i, j, k; - pcc->parent_unrealize(dev, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } + pcc->parent_unrealize(dev); for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) { if (cpu->opcodes[i] == &invalid_handler) { From 7ef1553dac8ef8dbe547b58d7420461a16be0eeb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:25 +0200 Subject: [PATCH 0481/2595] spapr_pci: Drop some dead error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit chassis_from_bus() uses object_property_get_uint() to get property "chassis_nr" of the bridge device. Failure would be a programming error. Pass &error_abort, and simplify its callers. Cc: David Gibson Cc: qemu-ppc@nongnu.org Signed-off-by: Markus Armbruster Acked-by: David Gibson Reviewed-by: Greg Kurz Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-18-armbru@redhat.com> --- hw/ppc/spapr_pci.c | 86 ++++++++++------------------------------------ 1 file changed, 18 insertions(+), 68 deletions(-) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 616034222d..83f1453096 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1203,46 +1203,36 @@ static SpaprDrc *drc_from_devfn(SpaprPhbState *phb, drc_id_from_devfn(phb, chassis, devfn)); } -static uint8_t chassis_from_bus(PCIBus *bus, Error **errp) +static uint8_t chassis_from_bus(PCIBus *bus) { if (pci_bus_is_root(bus)) { return 0; } else { PCIDevice *bridge = pci_bridge_get_device(bus); - return object_property_get_uint(OBJECT(bridge), "chassis_nr", errp); + return object_property_get_uint(OBJECT(bridge), "chassis_nr", + &error_abort); } } static SpaprDrc *drc_from_dev(SpaprPhbState *phb, PCIDevice *dev) { - Error *local_err = NULL; - uint8_t chassis = chassis_from_bus(pci_get_bus(dev), &local_err); - - if (local_err) { - error_report_err(local_err); - return NULL; - } + uint8_t chassis = chassis_from_bus(pci_get_bus(dev)); return drc_from_devfn(phb, chassis, dev->devfn); } -static void add_drcs(SpaprPhbState *phb, PCIBus *bus, Error **errp) +static void add_drcs(SpaprPhbState *phb, PCIBus *bus) { Object *owner; int i; uint8_t chassis; - Error *local_err = NULL; if (!phb->dr_enabled) { return; } - chassis = chassis_from_bus(bus, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + chassis = chassis_from_bus(bus); if (pci_bus_is_root(bus)) { owner = OBJECT(phb); @@ -1256,21 +1246,16 @@ static void add_drcs(SpaprPhbState *phb, PCIBus *bus, Error **errp) } } -static void remove_drcs(SpaprPhbState *phb, PCIBus *bus, Error **errp) +static void remove_drcs(SpaprPhbState *phb, PCIBus *bus) { int i; uint8_t chassis; - Error *local_err = NULL; if (!phb->dr_enabled) { return; } - chassis = chassis_from_bus(bus, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + chassis = chassis_from_bus(bus); for (i = PCI_SLOT_MAX * PCI_FUNC_MAX - 1; i >= 0; i--) { SpaprDrc *drc = drc_from_devfn(phb, chassis, i); @@ -1488,17 +1473,11 @@ int spapr_pci_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, } static void spapr_pci_bridge_plug(SpaprPhbState *phb, - PCIBridge *bridge, - Error **errp) + PCIBridge *bridge) { - Error *local_err = NULL; PCIBus *bus = pci_bridge_get_sec_bus(bridge); - add_drcs(phb, bus, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + add_drcs(phb, bus); } static void spapr_pci_plug(HotplugHandler *plug_handler, @@ -1529,11 +1508,7 @@ static void spapr_pci_plug(HotplugHandler *plug_handler, g_assert(drc); if (pc->is_bridge) { - spapr_pci_bridge_plug(phb, PCI_BRIDGE(plugged_dev), &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + spapr_pci_bridge_plug(phb, PCI_BRIDGE(plugged_dev)); } /* Following the QEMU convention used for PCIe multifunction @@ -1560,12 +1535,7 @@ static void spapr_pci_plug(HotplugHandler *plug_handler, spapr_drc_reset(drc); } else if (PCI_FUNC(pdev->devfn) == 0) { int i; - uint8_t chassis = chassis_from_bus(pci_get_bus(pdev), &local_err); - - if (local_err) { - error_propagate(errp, local_err); - return; - } + uint8_t chassis = chassis_from_bus(pci_get_bus(pdev)); for (i = 0; i < 8; i++) { SpaprDrc *func_drc; @@ -1587,17 +1557,11 @@ out: } static void spapr_pci_bridge_unplug(SpaprPhbState *phb, - PCIBridge *bridge, - Error **errp) + PCIBridge *bridge) { - Error *local_err = NULL; PCIBus *bus = pci_bridge_get_sec_bus(bridge); - remove_drcs(phb, bus, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + remove_drcs(phb, bus); } static void spapr_pci_unplug(HotplugHandler *plug_handler, @@ -1619,11 +1583,7 @@ static void spapr_pci_unplug(HotplugHandler *plug_handler, pci_device_reset(PCI_DEVICE(plugged_dev)); if (pc->is_bridge) { - Error *local_err = NULL; - spapr_pci_bridge_unplug(phb, PCI_BRIDGE(plugged_dev), &local_err); - if (local_err) { - error_propagate(errp, local_err); - } + spapr_pci_bridge_unplug(phb, PCI_BRIDGE(plugged_dev)); return; } @@ -1654,13 +1614,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, SpaprDrcClass *func_drck; SpaprDREntitySense state; int i; - Error *local_err = NULL; - uint8_t chassis = chassis_from_bus(pci_get_bus(pdev), &local_err); - - if (local_err) { - error_propagate(errp, local_err); - return; - } + uint8_t chassis = chassis_from_bus(pci_get_bus(pdev)); if (pc->is_bridge) { error_setg(errp, "PCI: Hot unplug of PCI bridges not supported"); @@ -1745,7 +1699,7 @@ static void spapr_phb_unrealize(DeviceState *dev) } } - remove_drcs(sphb, phb->bus, &error_abort); + remove_drcs(sphb, phb->bus); for (i = PCI_NUM_PINS - 1; i >= 0; i--) { if (sphb->lsi_table[i].irq) { @@ -1984,11 +1938,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) } /* allocate connectors for child PCI devices */ - add_drcs(sphb, phb->bus, &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto unrealize; - } + add_drcs(sphb, phb->bus); /* DMA setup */ for (i = 0; i < windows_supported; ++i) { From df4fe0b291b2baf1694517a4a67be7525102656b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 17:29:26 +0200 Subject: [PATCH 0482/2595] qom: Drop @errp parameter of object_property_del() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same story as for object_property_add(): the only way object_property_del() can fail is when the property with this name does not exist. Since our property names are all hardcoded, failure is a programming error, and the appropriate way to handle it is passing &error_abort. Most callers do that, the commit before previous fixed one that didn't (and got the error handling wrong), and the two remaining exceptions ignore errors. Drop the @errp parameter. Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200505152926.18877-19-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/core/qdev.c | 2 +- hw/i386/pc_sysfw.c | 2 +- hw/ppc/spapr_drc.c | 4 ++-- include/qom/object.h | 2 +- qom/object.c | 7 +------ qom/object_interfaces.c | 3 +-- tests/check-qom-proplist.c | 2 +- 7 files changed, 8 insertions(+), 14 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index b9c7a2f904..9e5538aeae 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -65,7 +65,7 @@ static void bus_remove_child(BusState *bus, DeviceState *child) bus->num_children--; /* This gives back ownership of kid->child back to us. */ - object_property_del(OBJECT(bus), name, NULL); + object_property_del(OBJECT(bus), name); object_unref(OBJECT(kid->child)); g_free(kid); return; diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index 002133a2d8..2abab3a27c 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -120,7 +120,7 @@ static void pc_system_flash_cleanup_unused(PCMachineState *pcms) dev_obj = OBJECT(pcms->flash[i]); if (!object_property_get_bool(dev_obj, "realized", &error_abort)) { prop_name = g_strdup_printf("pflash%d", i); - object_property_del(OBJECT(pcms), prop_name, &error_abort); + object_property_del(OBJECT(pcms), prop_name); g_free(prop_name); object_unparent(dev_obj); pcms->flash[i] = NULL; diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 8b2171f698..b958f8acb5 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -405,7 +405,7 @@ static void spapr_drc_release(SpaprDrc *drc) g_free(drc->fdt); drc->fdt = NULL; drc->fdt_start_offset = 0; - object_property_del(OBJECT(drc), "device", &error_abort); + object_property_del(OBJECT(drc), "device"); drc->dev = NULL; } @@ -551,7 +551,7 @@ static void unrealize(DeviceState *d) vmstate_unregister(VMSTATE_IF(drc), &vmstate_spapr_drc, drc); root_container = container_get(object_get_root(), DRC_CONTAINER_PATH); name = g_strdup_printf("%x", spapr_drc_index(drc)); - object_property_del(root_container, name, &error_abort); + object_property_del(root_container, name); g_free(name); } diff --git a/include/qom/object.h b/include/qom/object.h index 990e28e408..fd453dc8d6 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1047,7 +1047,7 @@ ObjectProperty *object_property_add(Object *obj, const char *name, ObjectPropertyRelease *release, void *opaque); -void object_property_del(Object *obj, const char *name, Error **errp); +void object_property_del(Object *obj, const char *name); ObjectProperty *object_class_property_add(ObjectClass *klass, const char *name, const char *type, diff --git a/qom/object.c b/qom/object.c index 23f481ca46..e89ffbe3d1 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1280,15 +1280,10 @@ ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, return prop; } -void object_property_del(Object *obj, const char *name, Error **errp) +void object_property_del(Object *obj, const char *name) { ObjectProperty *prop = g_hash_table_lookup(obj->properties, name); - if (!prop) { - error_setg(errp, "Property '.%s' not found", name); - return; - } - if (prop->release) { prop->release(obj, name, prop->opaque); } diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 054e75043d..7e26f86fa6 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -89,8 +89,7 @@ Object *user_creatable_add_type(const char *type, const char *id, user_creatable_complete(USER_CREATABLE(obj), &local_err); if (local_err) { if (id != NULL) { - object_property_del(object_get_objects_root(), - id, &error_abort); + object_property_del(object_get_objects_root(), id); } goto out; } diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c index 84f48fe592..13a824cfae 100644 --- a/tests/check-qom-proplist.c +++ b/tests/check-qom-proplist.c @@ -280,7 +280,7 @@ static void dummy_bus_init(Object *obj) static void dummy_bus_unparent(Object *obj) { DummyBus *bus = DUMMY_BUS(obj); - object_property_del(obj->parent, "backend", NULL); + object_property_del(obj->parent, "backend"); object_unparent(OBJECT(bus->backend)); } From 96449e4a30a56e3303d6d0407aca130c71671754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 12 May 2020 09:00:18 +0200 Subject: [PATCH 0483/2595] target: Remove unnecessary CPU() cast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CPU() macro is defined as: #define CPU(obj) ((CPUState *)(obj)) which expands to: ((CPUState *)object_dynamic_cast_assert((Object *)(obj), (name), __FILE__, __LINE__, __func__)) This assertion can only fail when @obj points to something other than its stated type, i.e. when we're in undefined behavior country. Remove the unnecessary CPU() casts when we already know the pointer is of CPUState type. Patch created mechanically using spatch with this script: @@ typedef CPUState; CPUState *s; @@ - CPU(s) + s Acked-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Richard Henderson Reviewed-by: Markus Armbruster Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200512070020.22782-2-f4bug@amsat.org> --- target/ppc/mmu_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 86c667b094..8972714775 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -1820,7 +1820,7 @@ static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu, if (((end - base) >> TARGET_PAGE_BITS) > 1024) { /* Flushing 1024 4K pages is slower than a complete flush */ LOG_BATS("Flush all BATs\n"); - tlb_flush(CPU(cs)); + tlb_flush(cs); LOG_BATS("Flush done\n"); return; } From 688ffbb4f72bf9a75c7ff3a899a9617de61d5fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 12 May 2020 09:00:19 +0200 Subject: [PATCH 0484/2595] various: Remove unnecessary OBJECT() cast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OBJECT() macro is defined as: #define OBJECT(obj) ((Object *)(obj)) Remove the unnecessary OBJECT() casts when we already know the pointer is of Object type. Patch created mechanically using spatch with this script: @@ typedef Object; Object *o; @@ - OBJECT(o) + o Acked-by: Cornelia Huck Acked-by: Corey Minyard Acked-by: John Snow Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200512070020.22782-3-f4bug@amsat.org> [Trivial rebase conflict in hw/s390x/sclp.c resolved] --- hw/core/bus.c | 2 +- hw/ide/ahci-allwinner.c | 2 +- hw/ipmi/smbus_ipmi.c | 2 +- hw/microblaze/petalogix_ml605_mmu.c | 8 ++++---- hw/s390x/sclp.c | 2 +- monitor/misc.c | 3 +-- qom/object.c | 4 ++-- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/hw/core/bus.c b/hw/core/bus.c index a9e4118d3c..50924793ac 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -25,7 +25,7 @@ void qbus_set_hotplug_handler(BusState *bus, Object *handler, Error **errp) { - object_property_set_link(OBJECT(bus), OBJECT(handler), + object_property_set_link(OBJECT(bus), handler, QDEV_HOTPLUG_HANDLER_PROPERTY, errp); } diff --git a/hw/ide/ahci-allwinner.c b/hw/ide/ahci-allwinner.c index bb8393d2b6..8536b9eb5a 100644 --- a/hw/ide/ahci-allwinner.c +++ b/hw/ide/ahci-allwinner.c @@ -90,7 +90,7 @@ static void allwinner_ahci_init(Object *obj) SysbusAHCIState *s = SYSBUS_AHCI(obj); AllwinnerAHCIState *a = ALLWINNER_AHCI(obj); - memory_region_init_io(&a->mmio, OBJECT(obj), &allwinner_ahci_mem_ops, a, + memory_region_init_io(&a->mmio, obj, &allwinner_ahci_mem_ops, a, "allwinner-ahci", ALLWINNER_AHCI_MMIO_SIZE); memory_region_add_subregion(&s->ahci.mem, ALLWINNER_AHCI_MMIO_OFF, &a->mmio); diff --git a/hw/ipmi/smbus_ipmi.c b/hw/ipmi/smbus_ipmi.c index 2a9470d9df..f1a0148755 100644 --- a/hw/ipmi/smbus_ipmi.c +++ b/hw/ipmi/smbus_ipmi.c @@ -329,7 +329,7 @@ static void smbus_ipmi_init(Object *obj) { SMBusIPMIDevice *sid = SMBUS_IPMI(obj); - ipmi_bmc_find_and_link(OBJECT(obj), (Object **) &sid->bmc); + ipmi_bmc_find_and_link(obj, (Object **) &sid->bmc); } static void smbus_ipmi_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info) diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index 536571db7f..05a5614a04 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -148,9 +148,9 @@ petalogix_ml605_init(MachineState *machine) qdev_set_nic_properties(eth0, &nd_table[0]); qdev_prop_set_uint32(eth0, "rxmem", 0x1000); qdev_prop_set_uint32(eth0, "txmem", 0x1000); - object_property_set_link(OBJECT(eth0), OBJECT(ds), + object_property_set_link(OBJECT(eth0), ds, "axistream-connected", &error_abort); - object_property_set_link(OBJECT(eth0), OBJECT(cs), + object_property_set_link(OBJECT(eth0), cs, "axistream-control-connected", &error_abort); qdev_init_nofail(eth0); sysbus_mmio_map(SYS_BUS_DEVICE(eth0), 0, AXIENET_BASEADDR); @@ -161,9 +161,9 @@ petalogix_ml605_init(MachineState *machine) cs = object_property_get_link(OBJECT(eth0), "axistream-control-connected-target", NULL); qdev_prop_set_uint32(dma, "freqhz", 100 * 1000000); - object_property_set_link(OBJECT(dma), OBJECT(ds), + object_property_set_link(OBJECT(dma), ds, "axistream-connected", &error_abort); - object_property_set_link(OBJECT(dma), OBJECT(cs), + object_property_set_link(OBJECT(dma), cs, "axistream-control-connected", &error_abort); qdev_init_nofail(dma); sysbus_mmio_map(SYS_BUS_DEVICE(dma), 0, AXIDMA_BASEADDR); diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 43cc1e0a41..20aca30ac4 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -321,7 +321,7 @@ void s390_sclp_init(void) Object *new = object_new(TYPE_SCLP); object_property_add_child(qdev_get_machine(), TYPE_SCLP, new); - object_unref(OBJECT(new)); + object_unref(new); qdev_init_nofail(DEVICE(new)); } diff --git a/monitor/misc.c b/monitor/misc.c index 9723b466cd..f5207cd242 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -1837,8 +1837,7 @@ void object_add_completion(ReadLineState *rs, int nb_args, const char *str) static int qdev_add_hotpluggable_device(Object *obj, void *opaque) { GSList **list = opaque; - DeviceState *dev = (DeviceState *)object_dynamic_cast(OBJECT(obj), - TYPE_DEVICE); + DeviceState *dev = (DeviceState *)object_dynamic_cast(obj, TYPE_DEVICE); if (dev == NULL) { return 0; diff --git a/qom/object.c b/qom/object.c index e89ffbe3d1..d0be42c8d6 100644 --- a/qom/object.c +++ b/qom/object.c @@ -756,7 +756,7 @@ Object *object_new_with_propv(const char *typename, } } - object_unref(OBJECT(obj)); + object_unref(obj); return obj; error: @@ -1650,7 +1650,7 @@ object_property_add_child(Object *obj, const char *name, assert(!child->parent); - type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); + type = g_strdup_printf("child<%s>", object_get_typename(child)); op = object_property_add(obj, name, type, object_get_child_property, NULL, object_finalize_child_property, child); From 8e5c952b370b57beb642826882c80e1b66a9cf12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 12 May 2020 09:00:20 +0200 Subject: [PATCH 0485/2595] hw: Remove unnecessary DEVICE() cast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DEVICE() macro is defined as: #define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE) which expands to: ((DeviceState *)object_dynamic_cast_assert((Object *)(obj), (name), __FILE__, __LINE__, __func__)) This assertion can only fail when @obj points to something other than its stated type, i.e. when we're in undefined behavior country. Remove the unnecessary DEVICE() casts when we already know the pointer is of DeviceState type. Patch created mechanically using spatch with this script: @@ typedef DeviceState; DeviceState *s; @@ - DEVICE(s) + s Acked-by: David Gibson Acked-by: Paul Durrant Reviewed-by: Markus Armbruster Reviewed-by: Cédric Le Goater Acked-by: John Snow Reviewed-by: Richard Henderson Reviewed-by: Markus Armbruster Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200512070020.22782-4-f4bug@amsat.org> --- hw/display/artist.c | 2 +- hw/display/cg3.c | 2 +- hw/display/sm501.c | 2 +- hw/display/tcx.c | 4 ++-- hw/display/vga-isa.c | 2 +- hw/i2c/imx_i2c.c | 2 +- hw/i2c/mpc_i2c.c | 2 +- hw/ide/piix.c | 2 +- hw/misc/macio/pmu.c | 2 +- hw/net/ftgmac100.c | 3 +-- hw/net/imx_fec.c | 2 +- hw/nubus/nubus-device.c | 2 +- hw/pci-host/bonito.c | 2 +- hw/ppc/spapr.c | 2 +- hw/sh4/sh_pci.c | 2 +- hw/xen/xen-legacy-backend.c | 2 +- 16 files changed, 17 insertions(+), 18 deletions(-) diff --git a/hw/display/artist.c b/hw/display/artist.c index 753dbb9a77..7e2a4556bd 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -1353,7 +1353,7 @@ static void artist_realizefn(DeviceState *dev, Error **errp) s->cursor_height = 32; s->cursor_width = 32; - s->con = graphic_console_init(DEVICE(dev), 0, &artist_ops, s); + s->con = graphic_console_init(dev, 0, &artist_ops, s); qemu_console_resize(s->con, s->width, s->height); } diff --git a/hw/display/cg3.c b/hw/display/cg3.c index a1ede10394..f7f1c199ce 100644 --- a/hw/display/cg3.c +++ b/hw/display/cg3.c @@ -321,7 +321,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp) sysbus_init_irq(sbd, &s->irq); - s->con = graphic_console_init(DEVICE(dev), 0, &cg3_ops, s); + s->con = graphic_console_init(dev, 0, &cg3_ops, s); qemu_console_resize(s->con, s->width, s->height); } diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 296cd56c4a..acc692531a 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1839,7 +1839,7 @@ static void sm501_init(SM501State *s, DeviceState *dev, &s->twoD_engine_region); /* create qemu graphic console */ - s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s); + s->con = graphic_console_init(dev, 0, &sm501_ops, s); } static const VMStateDescription vmstate_sm501_state = { diff --git a/hw/display/tcx.c b/hw/display/tcx.c index 76de16e8ea..1fb45b1aab 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -868,9 +868,9 @@ static void tcx_realizefn(DeviceState *dev, Error **errp) sysbus_init_irq(sbd, &s->irq); if (s->depth == 8) { - s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s); + s->con = graphic_console_init(dev, 0, &tcx_ops, s); } else { - s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); + s->con = graphic_console_init(dev, 0, &tcx24_ops, s); } s->thcmisc = 0; diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c index 0633ed382c..3aaeeeca1e 100644 --- a/hw/display/vga-isa.c +++ b/hw/display/vga-isa.c @@ -74,7 +74,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp) 0x000a0000, vga_io_memory, 1); memory_region_set_coalescing(vga_io_memory); - s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s); + s->con = graphic_console_init(dev, 0, s->hw_ops, s); memory_region_add_subregion(isa_address_space(isadev), VBE_DISPI_LFB_PHYSICAL_ADDRESS, diff --git a/hw/i2c/imx_i2c.c b/hw/i2c/imx_i2c.c index 30b9aea247..2e02e1c4fa 100644 --- a/hw/i2c/imx_i2c.c +++ b/hw/i2c/imx_i2c.c @@ -305,7 +305,7 @@ static void imx_i2c_realize(DeviceState *dev, Error **errp) IMX_I2C_MEM_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); - s->bus = i2c_init_bus(DEVICE(dev), NULL); + s->bus = i2c_init_bus(dev, NULL); } static void imx_i2c_class_init(ObjectClass *klass, void *data) diff --git a/hw/i2c/mpc_i2c.c b/hw/i2c/mpc_i2c.c index 0aa1be3ce7..9a724f3a3e 100644 --- a/hw/i2c/mpc_i2c.c +++ b/hw/i2c/mpc_i2c.c @@ -332,7 +332,7 @@ static void mpc_i2c_realize(DeviceState *dev, Error **errp) memory_region_init_io(&i2c->iomem, OBJECT(i2c), &i2c_ops, i2c, "mpc-i2c", 0x14); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &i2c->iomem); - i2c->bus = i2c_init_bus(DEVICE(dev), "i2c"); + i2c->bus = i2c_init_bus(dev, "i2c"); } static void mpc_i2c_class_init(ObjectClass *klass, void *data) diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 3b2de4c312..b402a93636 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -193,7 +193,7 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux) blk_unref(blk); } } - qdev_reset_all(DEVICE(dev)); + qdev_reset_all(dev); return 0; } diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index 5fa792846c..9a9cd427e1 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -758,7 +758,7 @@ static void pmu_realize(DeviceState *dev, Error **errp) if (s->has_adb) { qbus_create_inplace(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS, - DEVICE(dev), "adb.0"); + dev, "adb.0"); s->adb_poll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, pmu_adb_poll, s); s->adb_poll_mask = 0xffff; s->autopoll_rate_ms = 20; diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 041ed21017..25ebee7ec2 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -1035,8 +1035,7 @@ static void ftgmac100_realize(DeviceState *dev, Error **errp) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_ftgmac100_info, &s->conf, - object_get_typename(OBJECT(dev)), DEVICE(dev)->id, - s); + object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); } diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index a35c33683e..7adcc9df65 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1323,7 +1323,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf, object_get_typename(OBJECT(dev)), - DEVICE(dev)->id, s); + dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); } diff --git a/hw/nubus/nubus-device.c b/hw/nubus/nubus-device.c index 01ccad9e8e..ffe78a8823 100644 --- a/hw/nubus/nubus-device.c +++ b/hw/nubus/nubus-device.c @@ -156,7 +156,7 @@ void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size, static void nubus_device_realize(DeviceState *dev, Error **errp) { - NubusBus *nubus = NUBUS_BUS(qdev_get_parent_bus(DEVICE(dev))); + NubusBus *nubus = NUBUS_BUS(qdev_get_parent_bus(dev)); NubusDevice *nd = NUBUS_DEVICE(dev); char *name; hwaddr slot_offset; diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index cc6545c8a8..f212796044 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -606,7 +606,7 @@ static void bonito_pcihost_realize(DeviceState *dev, Error **errp) BonitoState *bs = BONITO_PCI_HOST_BRIDGE(dev); memory_region_init(&bs->pci_mem, OBJECT(dev), "pci.mem", BONITO_PCILO_SIZE); - phb->bus = pci_register_root_bus(DEVICE(dev), "pci", + phb->bus = pci_register_root_bus(dev, "pci", pci_bonito_set_irq, pci_bonito_map_irq, dev, &bs->pci_mem, get_system_io(), 0x28, 32, TYPE_PCI_BUS); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c0bf8c8d4f..9b358fcc60 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4013,7 +4013,7 @@ static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev, /* hotplug hooks should check it's enabled before getting this far */ assert(drc); - spapr_drc_attach(drc, DEVICE(dev), &local_err); + spapr_drc_attach(drc, dev, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/sh4/sh_pci.c b/hw/sh4/sh_pci.c index 08f2fc1dde..0a3e86f949 100644 --- a/hw/sh4/sh_pci.c +++ b/hw/sh4/sh_pci.c @@ -129,7 +129,7 @@ static void sh_pci_device_realize(DeviceState *dev, Error **errp) for (i = 0; i < 4; i++) { sysbus_init_irq(sbd, &s->irq[i]); } - phb->bus = pci_register_root_bus(DEVICE(dev), "pci", + phb->bus = pci_register_root_bus(dev, "pci", sh_pci_set_irq, sh_pci_map_irq, s->irq, get_system_memory(), diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index 4a373b2373..f9d013811a 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -705,7 +705,7 @@ int xen_be_init(void) xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV); qdev_init_nofail(xen_sysdev); - xen_sysbus = qbus_create(TYPE_XENSYSBUS, DEVICE(xen_sysdev), "xen-sysbus"); + xen_sysbus = qbus_create(TYPE_XENSYSBUS, xen_sysdev, "xen-sysbus"); qbus_set_bus_hotplug_handler(xen_sysbus, &error_abort); return 0; From a1dcdda8275e15ab919bcec012e9e662283b6a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 May 2020 16:34:28 +0200 Subject: [PATCH 0486/2595] tests/fuzz/Makefile: Do not link code using unavailable devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some devices availability depends on CONFIG options. Use these options to only link tests when requested device is available. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200514143433.18569-2-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/qtest/fuzz/Makefile.include | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/qtest/fuzz/Makefile.include b/tests/qtest/fuzz/Makefile.include index cde3e9636c..f259d866c9 100644 --- a/tests/qtest/fuzz/Makefile.include +++ b/tests/qtest/fuzz/Makefile.include @@ -7,9 +7,9 @@ fuzz-obj-y += tests/qtest/fuzz/fork_fuzz.o fuzz-obj-y += tests/qtest/fuzz/qos_fuzz.o # Targets -fuzz-obj-y += tests/qtest/fuzz/i440fx_fuzz.o -fuzz-obj-y += tests/qtest/fuzz/virtio_net_fuzz.o -fuzz-obj-y += tests/qtest/fuzz/virtio_scsi_fuzz.o +fuzz-obj-$(CONFIG_PCI_I440FX) += tests/qtest/fuzz/i440fx_fuzz.o +fuzz-obj-$(CONFIG_VIRTIO_NET) += tests/qtest/fuzz/virtio_net_fuzz.o +fuzz-obj-$(CONFIG_SCSI) += tests/qtest/fuzz/virtio_scsi_fuzz.o FUZZ_CFLAGS += -I$(SRC_PATH)/tests -I$(SRC_PATH)/tests/qtest From 763815a83744fe7b9c5d88bd54370f25742fd10c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 May 2020 16:34:29 +0200 Subject: [PATCH 0487/2595] Makefile: List fuzz targets in 'make help' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit List softmmu fuzz targets in 'make help' output: $ make help ... Architecture specific targets: aarch64-softmmu/all - Build for aarch64-softmmu aarch64-softmmu/fuzz - Build fuzzer for aarch64-softmmu alpha-softmmu/all - Build for alpha-softmmu alpha-softmmu/fuzz - Build fuzzer for alpha-softmmu arm-softmmu/all - Build for arm-softmmu arm-softmmu/fuzz - Build fuzzer for arm-softmmu ... Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200514143433.18569-3-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 34275f57c9..40e4f7677b 100644 --- a/Makefile +++ b/Makefile @@ -1252,7 +1252,11 @@ endif @$(if $(TARGET_DIRS), \ echo 'Architecture specific targets:'; \ $(foreach t, $(TARGET_DIRS), \ - $(call print-help-run,$(t)/all,Build for $(t));) \ + $(call print-help-run,$(t)/all,Build for $(t)); \ + $(if $(CONFIG_FUZZ), \ + $(if $(findstring softmmu,$(t)), \ + $(call print-help-run,$(t)/fuzz,Build fuzzer for $(t)); \ + ))) \ echo '') @$(if $(TOOLS), \ echo 'Tools targets:'; \ From 73ee6da45d22c82275042f7e84426e647246a56d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 May 2020 16:34:30 +0200 Subject: [PATCH 0488/2595] tests/fuzz: Add missing space in test description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200514143433.18569-4-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/qtest/fuzz/i440fx_fuzz.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/qtest/fuzz/i440fx_fuzz.c b/tests/qtest/fuzz/i440fx_fuzz.c index ab5f112584..96fed9ff12 100644 --- a/tests/qtest/fuzz/i440fx_fuzz.c +++ b/tests/qtest/fuzz/i440fx_fuzz.c @@ -159,7 +159,7 @@ static void register_pci_fuzz_targets(void) /* Uses simple qtest commands and reboots to reset state */ fuzz_add_target(&(FuzzTarget){ .name = "i440fx-qtest-reboot-fuzz", - .description = "Fuzz the i440fx using raw qtest commands and" + .description = "Fuzz the i440fx using raw qtest commands and " "rebooting after each run", .get_init_cmdline = i440fx_argv, .fuzz = i440fx_fuzz_qtest}); @@ -167,7 +167,7 @@ static void register_pci_fuzz_targets(void) /* Uses libqos and forks to prevent state leakage */ fuzz_add_qos_target(&(FuzzTarget){ .name = "i440fx-qos-fork-fuzz", - .description = "Fuzz the i440fx using raw qtest commands and" + .description = "Fuzz the i440fx using raw qtest commands and " "rebooting after each run", .pre_vm_init = &fork_init, .fuzz = i440fx_fuzz_qos_fork,}, @@ -182,7 +182,7 @@ static void register_pci_fuzz_targets(void) */ fuzz_add_qos_target(&(FuzzTarget){ .name = "i440fx-qos-noreset-fuzz", - .description = "Fuzz the i440fx using raw qtest commands and" + .description = "Fuzz the i440fx using raw qtest commands and " "rebooting after each run", .fuzz = i440fx_fuzz_qos,}, "i440FX-pcihost", From 79e18a60ab456764eaa974b67b9c54281a5156db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 May 2020 16:34:31 +0200 Subject: [PATCH 0489/2595] tests/fuzz: Remove unuseful/unused typedefs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These typedefs are not used. Use a simple structure, remote the typedefs. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200514143433.18569-5-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/qtest/fuzz/i440fx_fuzz.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/qtest/fuzz/i440fx_fuzz.c b/tests/qtest/fuzz/i440fx_fuzz.c index 96fed9ff12..c197b026db 100644 --- a/tests/qtest/fuzz/i440fx_fuzz.c +++ b/tests/qtest/fuzz/i440fx_fuzz.c @@ -45,12 +45,11 @@ static void i440fx_fuzz_qtest(QTestState *s, * loop over the Data, breaking it up into actions. each action has an * opcode, address offset and value */ - typedef struct QTestFuzzAction { + struct { uint8_t opcode; uint8_t addr; uint32_t value; - } QTestFuzzAction; - QTestFuzzAction a; + } a; while (Size >= sizeof(a)) { /* make a copy of the action so we can normalize the values in-place */ @@ -91,19 +90,18 @@ static void i440fx_fuzz_qos(QTestState *s, * Same as i440fx_fuzz_qtest, but using QOS. devfn is incorporated into the * value written over Port IO */ - typedef struct QOSFuzzAction { + struct { uint8_t opcode; uint8_t offset; int devfn; uint32_t value; - } QOSFuzzAction; + } a; static QPCIBus *bus; if (!bus) { bus = qpci_new_pc(s, fuzz_qos_alloc); } - QOSFuzzAction a; while (Size >= sizeof(a)) { memcpy(&a, Data, sizeof(a)); switch (a.opcode % ACTION_MAX) { From 84cb0a6d20c94abab6bc868e0e92044fcebdb1d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 May 2020 16:34:32 +0200 Subject: [PATCH 0490/2595] tests/fuzz: Extract pciconfig_fuzz_qos() method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the generic pciconfig_fuzz_qos() method from i440fx_fuzz_qos(). This will help to write tests not specific to the i440FX controller. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200514143433.18569-6-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/qtest/fuzz/i440fx_fuzz.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/qtest/fuzz/i440fx_fuzz.c b/tests/qtest/fuzz/i440fx_fuzz.c index c197b026db..558fa17c93 100644 --- a/tests/qtest/fuzz/i440fx_fuzz.c +++ b/tests/qtest/fuzz/i440fx_fuzz.c @@ -84,7 +84,7 @@ static void i440fx_fuzz_qtest(QTestState *s, flush_events(s); } -static void i440fx_fuzz_qos(QTestState *s, +static void pciconfig_fuzz_qos(QTestState *s, QPCIBus *bus, const unsigned char *Data, size_t Size) { /* * Same as i440fx_fuzz_qtest, but using QOS. devfn is incorporated into the @@ -97,11 +97,6 @@ static void i440fx_fuzz_qos(QTestState *s, uint32_t value; } a; - static QPCIBus *bus; - if (!bus) { - bus = qpci_new_pc(s, fuzz_qos_alloc); - } - while (Size >= sizeof(a)) { memcpy(&a, Data, sizeof(a)); switch (a.opcode % ACTION_MAX) { @@ -130,6 +125,19 @@ static void i440fx_fuzz_qos(QTestState *s, flush_events(s); } +static void i440fx_fuzz_qos(QTestState *s, + const unsigned char *Data, + size_t Size) +{ + static QPCIBus *bus; + + if (!bus) { + bus = qpci_new_pc(s, fuzz_qos_alloc); + } + + pciconfig_fuzz_qos(s, bus, Data, Size); +} + static void i440fx_fuzz_qos_fork(QTestState *s, const unsigned char *Data, size_t Size) { if (fork() == 0) { From 6fb5f0842aab0f744eebfabefb447b3a3a1af7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 May 2020 16:34:33 +0200 Subject: [PATCH 0491/2595] tests/fuzz: Extract ioport_fuzz_qtest() method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract generic ioport_fuzz_qtest() method from i440fx_fuzz_qtest(). This will help to write tests not specific to the i440FX controller. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200514143433.18569-7-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/qtest/fuzz/i440fx_fuzz.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/qtest/fuzz/i440fx_fuzz.c b/tests/qtest/fuzz/i440fx_fuzz.c index 558fa17c93..bcd6769b4c 100644 --- a/tests/qtest/fuzz/i440fx_fuzz.c +++ b/tests/qtest/fuzz/i440fx_fuzz.c @@ -39,7 +39,7 @@ enum action_id { ACTION_MAX }; -static void i440fx_fuzz_qtest(QTestState *s, +static void ioport_fuzz_qtest(QTestState *s, const unsigned char *Data, size_t Size) { /* * loop over the Data, breaking it up into actions. each action has an @@ -84,10 +84,17 @@ static void i440fx_fuzz_qtest(QTestState *s, flush_events(s); } +static void i440fx_fuzz_qtest(QTestState *s, + const unsigned char *Data, + size_t Size) +{ + ioport_fuzz_qtest(s, Data, Size); +} + static void pciconfig_fuzz_qos(QTestState *s, QPCIBus *bus, const unsigned char *Data, size_t Size) { /* - * Same as i440fx_fuzz_qtest, but using QOS. devfn is incorporated into the + * Same as ioport_fuzz_qtest, but using QOS. devfn is incorporated into the * value written over Port IO */ struct { From b03e4ffffb1e4a34cb0985f5f5c4a2cfb272e697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 13 May 2020 18:51:25 +0100 Subject: [PATCH 0492/2595] tests/guest-debug: catch hanging guests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If gdb never actually connected with the guest we need to catch that and clean-up after ourselves. Signed-off-by: Alex Bennée Message-Id: <20200513175134.19619-2-alex.bennee@linaro.org> --- tests/guest-debug/run-test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py index d9af9573b9..71c5569054 100755 --- a/tests/guest-debug/run-test.py +++ b/tests/guest-debug/run-test.py @@ -80,4 +80,10 @@ if __name__ == '__main__': print("GDB crashed? SKIPPING") exit(0) + try: + inferior.wait(2) + except subprocess.TimeoutExpired: + print("GDB never connected? Killed guest") + inferior.kill() + exit(result) From aae8b87e9c1658261f6c58ded9928d9ed24bdbef Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 13 May 2020 18:51:26 +0100 Subject: [PATCH 0493/2595] travis.yml: Improve the --disable-tcg test on s390x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the s390x containers do not allow KVM, we only compile-test the --disable-tcg build on s390x and do not run the qtests. Thus, it does not make sense to install genisoimage here, and it also does not make sense to build the s390-ccw.img here again - it is simply not used without the qtests. On the other hand, if we do not build the s390-ccw.img anymore, we can also compile with Clang - so let's use that compiler here to get some additional test coverage. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cornelia Huck Signed-off-by: Alex Bennée Message-Id: <20200512133849.10624-1-thuth@redhat.com> Message-Id: <20200513175134.19619-3-alex.bennee@linaro.org> --- .travis.yml | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index fe708792ca..1ec8a7b465 100644 --- a/.travis.yml +++ b/.travis.yml @@ -502,9 +502,10 @@ jobs: $(exit $BUILD_RC); fi - - name: "[s390x] GCC check (KVM)" + - name: "[s390x] Clang (disable-tcg)" arch: s390x dist: bionic + compiler: clang addons: apt_packages: - libaio-dev @@ -528,21 +529,10 @@ jobs: - libusb-1.0-0-dev - libvdeplug-dev - libvte-2.91-dev - # Tests dependencies - - genisoimage env: - TEST_CMD="make check-unit" - - CONFIG="--disable-containers --disable-tcg --enable-kvm --disable-tools" - script: - - ( cd ${SRC_DIR} ; git submodule update --init roms/SLOF ) - - BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$? - - | - if [ "$BUILD_RC" -eq 0 ] ; then - mv pc-bios/s390-ccw/*.img pc-bios/ ; - ${TEST_CMD} ; - else - $(exit $BUILD_RC); - fi + - CONFIG="--disable-containers --disable-tcg --enable-kvm + --disable-tools --host-cc=clang --cxx=clang++" # Release builds # The make-release script expect a QEMU version, so our tag must start with a 'v'. From ee94743034bfb443cf246eda4971bdc15d8ee066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 13 May 2020 18:51:28 +0100 Subject: [PATCH 0494/2595] linux-user: completely re-write init_guest_space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First we ensure all guest space initialisation logic comes through probe_guest_base once we understand the nature of the binary we are loading. The convoluted init_guest_space routine is removed and replaced with a number of pgb_* helpers which are called depending on what requirements we have when loading the binary. We first try to do what is requested by the host. Failing that we try and satisfy the guest requested base address. If all those options fail we fall back to finding a space in the memory map using our recently written read_self_maps() helper. There are some additional complications we try and take into account when looking for holes in the address space. We try not to go directly after the system brk() space so there is space for a little growth. We also don't want to have to use negative offsets which would result in slightly less efficient code on x86 when it's unable to use the segment offset register. Less mind-binding gotos and hopefully clearer logic throughout. Signed-off-by: Alex Bennée Acked-by: Laurent Vivier Message-Id: <20200513175134.19619-5-alex.bennee@linaro.org> --- linux-user/elfload.c | 555 +++++++++++++++++++++--------------------- linux-user/flatload.c | 6 + linux-user/main.c | 23 +- linux-user/qemu.h | 31 ++- 4 files changed, 303 insertions(+), 312 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 619c054cc4..01a9323a63 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -11,6 +11,7 @@ #include "qemu/queue.h" #include "qemu/guest-random.h" #include "qemu/units.h" +#include "qemu/selfmap.h" #ifdef _ARCH_PPC64 #undef ARCH_DLINFO @@ -382,68 +383,30 @@ enum { /* The commpage only exists for 32 bit kernels */ -/* Return 1 if the proposed guest space is suitable for the guest. - * Return 0 if the proposed guest space isn't suitable, but another - * address space should be tried. - * Return -1 if there is no way the proposed guest space can be - * valid regardless of the base. - * The guest code may leave a page mapped and populate it if the - * address is suitable. - */ -static int init_guest_commpage(unsigned long guest_base, - unsigned long guest_size) +#define ARM_COMMPAGE (intptr_t)0xffff0f00u + +static bool init_guest_commpage(void) { - unsigned long real_start, test_page_addr; + void *want = g2h(ARM_COMMPAGE & -qemu_host_page_size); + void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - /* We need to check that we can force a fault on access to the - * commpage at 0xffff0fxx - */ - test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask); - - /* If the commpage lies within the already allocated guest space, - * then there is no way we can allocate it. - * - * You may be thinking that that this check is redundant because - * we already validated the guest size against MAX_RESERVED_VA; - * but if qemu_host_page_mask is unusually large, then - * test_page_addr may be lower. - */ - if (test_page_addr >= guest_base - && test_page_addr < (guest_base + guest_size)) { - return -1; + if (addr == MAP_FAILED) { + perror("Allocating guest commpage"); + exit(EXIT_FAILURE); + } + if (addr != want) { + return false; } - /* Note it needs to be writeable to let us initialise it */ - real_start = (unsigned long) - mmap((void *)test_page_addr, qemu_host_page_size, - PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + /* Set kernel helper versions; rest of page is 0. */ + __put_user(5, (uint32_t *)g2h(0xffff0ffcu)); - /* If we can't map it then try another address */ - if (real_start == -1ul) { - return 0; - } - - if (real_start != test_page_addr) { - /* OS didn't put the page where we asked - unmap and reject */ - munmap((void *)real_start, qemu_host_page_size); - return 0; - } - - /* Leave the page mapped - * Populate it (mmap should have left it all 0'd) - */ - - /* Kernel helper versions */ - __put_user(5, (uint32_t *)g2h(0xffff0ffcul)); - - /* Now it's populated make it RO */ - if (mprotect((void *)test_page_addr, qemu_host_page_size, PROT_READ)) { + if (mprotect(addr, qemu_host_page_size, PROT_READ)) { perror("Protecting guest commpage"); - exit(-1); + exit(EXIT_FAILURE); } - - return 1; /* All good */ + return true; } #define ELF_HWCAP get_elf_hwcap() @@ -2075,240 +2038,268 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, return sp; } -unsigned long init_guest_space(unsigned long host_start, - unsigned long host_size, - unsigned long guest_start, - bool fixed) +#ifndef ARM_COMMPAGE +#define ARM_COMMPAGE 0 +#define init_guest_commpage() true +#endif + +static void pgb_fail_in_use(const char *image_name) +{ + error_report("%s: requires virtual address space that is in use " + "(omit the -B option or choose a different value)", + image_name); + exit(EXIT_FAILURE); +} + +static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr, + abi_ulong guest_hiaddr, long align) +{ + const int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE; + void *addr, *test; + + if (!QEMU_IS_ALIGNED(guest_base, align)) { + fprintf(stderr, "Requested guest base 0x%lx does not satisfy " + "host minimum alignment (0x%lx)\n", + guest_base, align); + exit(EXIT_FAILURE); + } + + /* Sanity check the guest binary. */ + if (reserved_va) { + if (guest_hiaddr > reserved_va) { + error_report("%s: requires more than reserved virtual " + "address space (0x%" PRIx64 " > 0x%lx)", + image_name, (uint64_t)guest_hiaddr, reserved_va); + exit(EXIT_FAILURE); + } + } else { + if ((guest_hiaddr - guest_base) > ~(uintptr_t)0) { + error_report("%s: requires more virtual address space " + "than the host can provide (0x%" PRIx64 ")", + image_name, (uint64_t)guest_hiaddr - guest_base); + exit(EXIT_FAILURE); + } + } + + /* + * Expand the allocation to the entire reserved_va. + * Exclude the mmap_min_addr hole. + */ + if (reserved_va) { + guest_loaddr = (guest_base >= mmap_min_addr ? 0 + : mmap_min_addr - guest_base); + guest_hiaddr = reserved_va; + } + + /* Reserve the address space for the binary, or reserved_va. */ + test = g2h(guest_loaddr); + addr = mmap(test, guest_hiaddr - guest_loaddr, PROT_NONE, flags, -1, 0); + if (test != addr) { + pgb_fail_in_use(image_name); + } +} + +/* Return value for guest_base, or -1 if no hole found. */ +static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size, + long align) +{ + GSList *maps, *iter; + uintptr_t this_start, this_end, next_start, brk; + intptr_t ret = -1; + + assert(QEMU_IS_ALIGNED(guest_loaddr, align)); + + maps = read_self_maps(); + + /* Read brk after we've read the maps, which will malloc. */ + brk = (uintptr_t)sbrk(0); + + /* The first hole is before the first map entry. */ + this_start = mmap_min_addr; + + for (iter = maps; iter; + this_start = next_start, iter = g_slist_next(iter)) { + uintptr_t align_start, hole_size; + + this_end = ((MapInfo *)iter->data)->start; + next_start = ((MapInfo *)iter->data)->end; + align_start = ROUND_UP(this_start, align); + + /* Skip holes that are too small. */ + if (align_start >= this_end) { + continue; + } + hole_size = this_end - align_start; + if (hole_size < guest_size) { + continue; + } + + /* If this hole contains brk, give ourselves some room to grow. */ + if (this_start <= brk && brk < this_end) { + hole_size -= guest_size; + if (sizeof(uintptr_t) == 8 && hole_size >= 1 * GiB) { + align_start += 1 * GiB; + } else if (hole_size >= 16 * MiB) { + align_start += 16 * MiB; + } else { + align_start = (this_end - guest_size) & -align; + if (align_start < this_start) { + continue; + } + } + } + + /* Record the lowest successful match. */ + if (ret < 0) { + ret = align_start - guest_loaddr; + } + /* If this hole contains the identity map, select it. */ + if (align_start <= guest_loaddr && + guest_loaddr + guest_size <= this_end) { + ret = 0; + } + /* If this hole ends above the identity map, stop looking. */ + if (this_end >= guest_loaddr) { + break; + } + } + free_self_maps(maps); + + return ret; +} + +static void pgb_static(const char *image_name, abi_ulong orig_loaddr, + abi_ulong orig_hiaddr, long align) +{ + uintptr_t loaddr = orig_loaddr; + uintptr_t hiaddr = orig_hiaddr; + uintptr_t addr; + + if (hiaddr != orig_hiaddr) { + error_report("%s: requires virtual address space that the " + "host cannot provide (0x%" PRIx64 ")", + image_name, (uint64_t)orig_hiaddr); + exit(EXIT_FAILURE); + } + + loaddr &= -align; + if (ARM_COMMPAGE) { + /* + * Extend the allocation to include the commpage. + * For a 64-bit host, this is just 4GiB; for a 32-bit host, + * the address arithmetic will wrap around, but the difference + * will produce the correct allocation size. + */ + if (sizeof(uintptr_t) == 8 || loaddr >= 0x80000000u) { + hiaddr = (uintptr_t)4 << 30; + } else { + loaddr = ARM_COMMPAGE & -align; + } + } + + addr = pgb_find_hole(loaddr, hiaddr - loaddr, align); + if (addr == -1) { + /* + * If ARM_COMMPAGE, there *might* be a non-consecutive allocation + * that can satisfy both. But as the normal arm32 link base address + * is ~32k, and we extend down to include the commpage, making the + * overhead only ~96k, this is unlikely. + */ + error_report("%s: Unable to allocate %#zx bytes of " + "virtual address space", image_name, + (size_t)(hiaddr - loaddr)); + exit(EXIT_FAILURE); + } + + guest_base = addr; +} + +static void pgb_dynamic(const char *image_name, long align) +{ + /* + * The executable is dynamic and does not require a fixed address. + * All we need is a commpage that satisfies align. + * If we do not need a commpage, leave guest_base == 0. + */ + if (ARM_COMMPAGE) { + uintptr_t addr, commpage; + + /* 64-bit hosts should have used reserved_va. */ + assert(sizeof(uintptr_t) == 4); + + /* + * By putting the commpage at the first hole, that puts guest_base + * just above that, and maximises the positive guest addresses. + */ + commpage = ARM_COMMPAGE & -align; + addr = pgb_find_hole(commpage, -commpage, align); + assert(addr != -1); + guest_base = addr; + } +} + +static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr, + abi_ulong guest_hiaddr, long align) +{ + const int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE; + void *addr, *test; + + if (guest_hiaddr > reserved_va) { + error_report("%s: requires more than reserved virtual " + "address space (0x%" PRIx64 " > 0x%lx)", + image_name, (uint64_t)guest_hiaddr, reserved_va); + exit(EXIT_FAILURE); + } + + /* Widen the "image" to the entire reserved address space. */ + pgb_static(image_name, 0, reserved_va, align); + + /* Reserve the memory on the host. */ + assert(guest_base != 0); + test = g2h(0); + addr = mmap(test, reserved_va, PROT_NONE, flags, -1, 0); + if (addr == MAP_FAILED) { + error_report("Unable to reserve 0x%lx bytes of virtual address " + "space for use as guest address space (check your " + "virtual memory ulimit setting or reserve less " + "using -R option)", reserved_va); + exit(EXIT_FAILURE); + } + assert(addr == test); +} + +void probe_guest_base(const char *image_name, abi_ulong guest_loaddr, + abi_ulong guest_hiaddr) { /* In order to use host shmat, we must be able to honor SHMLBA. */ - unsigned long align = MAX(SHMLBA, qemu_host_page_size); - unsigned long current_start, aligned_start; - int flags; + uintptr_t align = MAX(SHMLBA, qemu_host_page_size); - assert(host_start || host_size); - - /* If just a starting address is given, then just verify that - * address. */ - if (host_start && !host_size) { -#if defined(TARGET_ARM) && !defined(TARGET_AARCH64) - if (init_guest_commpage(host_start, host_size) != 1) { - return (unsigned long)-1; - } -#endif - return host_start; + if (have_guest_base) { + pgb_have_guest_base(image_name, guest_loaddr, guest_hiaddr, align); + } else if (reserved_va) { + pgb_reserved_va(image_name, guest_loaddr, guest_hiaddr, align); + } else if (guest_loaddr) { + pgb_static(image_name, guest_loaddr, guest_hiaddr, align); + } else { + pgb_dynamic(image_name, align); } - /* Setup the initial flags and start address. */ - current_start = host_start & -align; - flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE; - if (fixed) { - flags |= MAP_FIXED; - } - - /* Otherwise, a non-zero size region of memory needs to be mapped - * and validated. */ - -#if defined(TARGET_ARM) && !defined(TARGET_AARCH64) - /* On 32-bit ARM, we need to map not just the usable memory, but - * also the commpage. Try to find a suitable place by allocating - * a big chunk for all of it. If host_start, then the naive - * strategy probably does good enough. - */ - if (!host_start) { - unsigned long guest_full_size, host_full_size, real_start; - - guest_full_size = - (0xffff0f00 & qemu_host_page_mask) + qemu_host_page_size; - host_full_size = guest_full_size - guest_start; - real_start = (unsigned long) - mmap(NULL, host_full_size, PROT_NONE, flags, -1, 0); - if (real_start == (unsigned long)-1) { - if (host_size < host_full_size - qemu_host_page_size) { - /* We failed to map a continous segment, but we're - * allowed to have a gap between the usable memory and - * the commpage where other things can be mapped. - * This sparseness gives us more flexibility to find - * an address range. - */ - goto naive; - } - return (unsigned long)-1; - } - munmap((void *)real_start, host_full_size); - if (real_start & (align - 1)) { - /* The same thing again, but with extra - * so that we can shift around alignment. - */ - unsigned long real_size = host_full_size + qemu_host_page_size; - real_start = (unsigned long) - mmap(NULL, real_size, PROT_NONE, flags, -1, 0); - if (real_start == (unsigned long)-1) { - if (host_size < host_full_size - qemu_host_page_size) { - goto naive; - } - return (unsigned long)-1; - } - munmap((void *)real_start, real_size); - real_start = ROUND_UP(real_start, align); - } - current_start = real_start; - } - naive: -#endif - - while (1) { - unsigned long real_start, real_size, aligned_size; - aligned_size = real_size = host_size; - - /* Do not use mmap_find_vma here because that is limited to the - * guest address space. We are going to make the - * guest address space fit whatever we're given. + /* Reserve and initialize the commpage. */ + if (!init_guest_commpage()) { + /* + * With have_guest_base, the user has selected the address and + * we are trying to work with that. Otherwise, we have selected + * free space and init_guest_commpage must succeeded. */ - real_start = (unsigned long) - mmap((void *)current_start, host_size, PROT_NONE, flags, -1, 0); - if (real_start == (unsigned long)-1) { - return (unsigned long)-1; - } - - /* Check to see if the address is valid. */ - if (host_start && real_start != current_start) { - qemu_log_mask(CPU_LOG_PAGE, "invalid %lx && %lx != %lx\n", - host_start, real_start, current_start); - goto try_again; - } - - /* Ensure the address is properly aligned. */ - if (real_start & (align - 1)) { - /* Ideally, we adjust like - * - * pages: [ ][ ][ ][ ][ ] - * old: [ real ] - * [ aligned ] - * new: [ real ] - * [ aligned ] - * - * But if there is something else mapped right after it, - * then obviously it won't have room to grow, and the - * kernel will put the new larger real someplace else with - * unknown alignment (if we made it to here, then - * fixed=false). Which is why we grow real by a full page - * size, instead of by part of one; so that even if we get - * moved, we can still guarantee alignment. But this does - * mean that there is a padding of < 1 page both before - * and after the aligned range; the "after" could could - * cause problems for ARM emulation where it could butt in - * to where we need to put the commpage. - */ - munmap((void *)real_start, host_size); - real_size = aligned_size + align; - real_start = (unsigned long) - mmap((void *)real_start, real_size, PROT_NONE, flags, -1, 0); - if (real_start == (unsigned long)-1) { - return (unsigned long)-1; - } - aligned_start = ROUND_UP(real_start, align); - } else { - aligned_start = real_start; - } - -#if defined(TARGET_ARM) && !defined(TARGET_AARCH64) - /* On 32-bit ARM, we need to also be able to map the commpage. */ - int valid = init_guest_commpage(aligned_start - guest_start, - aligned_size + guest_start); - if (valid == -1) { - munmap((void *)real_start, real_size); - return (unsigned long)-1; - } else if (valid == 0) { - goto try_again; - } -#endif - - /* If nothing has said `return -1` or `goto try_again` yet, - * then the address we have is good. - */ - break; - - try_again: - /* That address didn't work. Unmap and try a different one. - * The address the host picked because is typically right at - * the top of the host address space and leaves the guest with - * no usable address space. Resort to a linear search. We - * already compensated for mmap_min_addr, so this should not - * happen often. Probably means we got unlucky and host - * address space randomization put a shared library somewhere - * inconvenient. - * - * This is probably a good strategy if host_start, but is - * probably a bad strategy if not, which means we got here - * because of trouble with ARM commpage setup. - */ - if (munmap((void *)real_start, real_size) != 0) { - error_report("%s: failed to unmap %lx:%lx (%s)", __func__, - real_start, real_size, strerror(errno)); - abort(); - } - current_start += align; - if (host_start == current_start) { - /* Theoretically possible if host doesn't have any suitably - * aligned areas. Normally the first mmap will fail. - */ - return (unsigned long)-1; - } + assert(have_guest_base); + pgb_fail_in_use(image_name); } - qemu_log_mask(CPU_LOG_PAGE, "Reserved 0x%lx bytes of guest address space\n", host_size); - - return aligned_start; + assert(QEMU_IS_ALIGNED(guest_base, align)); + qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space " + "@ 0x%" PRIx64 "\n", (uint64_t)guest_base); } -static void probe_guest_base(const char *image_name, - abi_ulong loaddr, abi_ulong hiaddr) -{ - /* Probe for a suitable guest base address, if the user has not set - * it explicitly, and set guest_base appropriately. - * In case of error we will print a suitable message and exit. - */ - const char *errmsg; - if (!have_guest_base && !reserved_va) { - unsigned long host_start, real_start, host_size; - - /* Round addresses to page boundaries. */ - loaddr &= qemu_host_page_mask; - hiaddr = HOST_PAGE_ALIGN(hiaddr); - - if (loaddr < mmap_min_addr) { - host_start = HOST_PAGE_ALIGN(mmap_min_addr); - } else { - host_start = loaddr; - if (host_start != loaddr) { - errmsg = "Address overflow loading ELF binary"; - goto exit_errmsg; - } - } - host_size = hiaddr - loaddr; - - /* Setup the initial guest memory space with ranges gleaned from - * the ELF image that is being loaded. - */ - real_start = init_guest_space(host_start, host_size, loaddr, false); - if (real_start == (unsigned long)-1) { - errmsg = "Unable to find space for application"; - goto exit_errmsg; - } - guest_base = real_start - loaddr; - - qemu_log_mask(CPU_LOG_PAGE, "Relocating guest address space from 0x" - TARGET_ABI_FMT_lx " to 0x%lx\n", - loaddr, real_start); - } - return; - -exit_errmsg: - fprintf(stderr, "%s: %s\n", image_name, errmsg); - exit(-1); -} - - /* Load an ELF image into the address space. IMAGE_NAME is the filename of the image, to use in error messages. @@ -2399,6 +2390,12 @@ static void load_elf_image(const char *image_name, int image_fd, * MMAP_MIN_ADDR or the QEMU application itself. */ probe_guest_base(image_name, loaddr, hiaddr); + } else { + /* + * The binary is dynamic, but we still need to + * select guest_base. In this case we pass a size. + */ + probe_guest_base(image_name, 0, hiaddr - loaddr); } } diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 66901f39cc..8fb448f0bf 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -441,6 +441,12 @@ static int load_flat_file(struct linux_binprm * bprm, indx_len = MAX_SHARED_LIBS * sizeof(abi_ulong); indx_len = (indx_len + 15) & ~(abi_ulong)15; + /* + * Alloate the address space. + */ + probe_guest_base(bprm->filename, 0, + text_len + data_len + extra + indx_len); + /* * there are a couple of cases here, the separate code/data * case, and then the fully copied to RAM case which lumps diff --git a/linux-user/main.c b/linux-user/main.c index 2cd443237d..e18c1fb952 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -24,6 +24,7 @@ #include "qemu-version.h" #include #include +#include #include "qapi/error.h" #include "qemu.h" @@ -747,28 +748,6 @@ int main(int argc, char **argv, char **envp) target_environ = envlist_to_environ(envlist, NULL); envlist_free(envlist); - /* - * Now that page sizes are configured in tcg_exec_init() we can do - * proper page alignment for guest_base. - */ - guest_base = HOST_PAGE_ALIGN(guest_base); - - if (reserved_va || have_guest_base) { - guest_base = init_guest_space(guest_base, reserved_va, 0, - have_guest_base); - if (guest_base == (unsigned long)-1) { - fprintf(stderr, "Unable to reserve 0x%lx bytes of virtual address " - "space for use as guest address space (check your virtual " - "memory ulimit setting or reserve less using -R option)\n", - reserved_va); - exit(EXIT_FAILURE); - } - - if (reserved_va) { - mmap_next_start = reserved_va; - } - } - /* * Read in mmap_min_addr kernel parameter. This value is used * When loading the ELF image to determine whether guest_base diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 792c74290f..ce902f5132 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -219,18 +219,27 @@ void init_qemu_uname_release(void); void fork_start(void); void fork_end(int child); -/* Creates the initial guest address space in the host memory space using - * the given host start address hint and size. The guest_start parameter - * specifies the start address of the guest space. guest_base will be the - * difference between the host start address computed by this function and - * guest_start. If fixed is specified, then the mapped address space must - * start at host_start. The real start address of the mapped memory space is - * returned or -1 if there was an error. +/** + * probe_guest_base: + * @image_name: the executable being loaded + * @loaddr: the lowest fixed address in the executable + * @hiaddr: the highest fixed address in the executable + * + * Creates the initial guest address space in the host memory space. + * + * If @loaddr == 0, then no address in the executable is fixed, + * i.e. it is fully relocatable. In that case @hiaddr is the size + * of the executable. + * + * This function will not return if a valid value for guest_base + * cannot be chosen. On return, the executable loader can expect + * + * target_mmap(loaddr, hiaddr - loaddr, ...) + * + * to succeed. */ -unsigned long init_guest_space(unsigned long host_start, - unsigned long host_size, - unsigned long guest_start, - bool fixed); +void probe_guest_base(const char *image_name, + abi_ulong loaddr, abi_ulong hiaddr); #include "qemu/log.h" From e307c192ff95c7c30d1c2fa02409686d450c1ccd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 18:51:29 +0100 Subject: [PATCH 0495/2595] exec/cpu-all: Use bool for have_guest_base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20200513175134.19619-6-alex.bennee@linaro.org> --- bsd-user/main.c | 4 ++-- include/exec/cpu-all.h | 2 +- linux-user/main.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 28f122b80e..0bfe46cff9 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -42,7 +42,7 @@ int singlestep; unsigned long mmap_min_addr; unsigned long guest_base; -int have_guest_base; +bool have_guest_base; unsigned long reserved_va; static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; @@ -828,7 +828,7 @@ int main(int argc, char **argv) } } else if (!strcmp(r, "B")) { guest_base = strtol(argv[optind++], NULL, 0); - have_guest_base = 1; + have_guest_base = true; } else if (!strcmp(r, "drop-ld-preload")) { (void) envlist_unsetenv(envlist, "LD_PRELOAD"); } else if (!strcmp(r, "bsd")) { diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 43ddcf024c..0895a57881 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -159,7 +159,7 @@ static inline void tswap64s(uint64_t *s) * This allows the guest address space to be offset to a convenient location. */ extern unsigned long guest_base; -extern int have_guest_base; +extern bool have_guest_base; extern unsigned long reserved_va; #if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS diff --git a/linux-user/main.c b/linux-user/main.c index e18c1fb952..3597e99bb1 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -59,7 +59,7 @@ static const char *cpu_type; static const char *seed_optarg; unsigned long mmap_min_addr; unsigned long guest_base; -int have_guest_base; +bool have_guest_base; /* * Used to implement backwards-compatibility for the `-strace`, and @@ -334,7 +334,7 @@ static void handle_arg_cpu(const char *arg) static void handle_arg_guest_base(const char *arg) { guest_base = strtol(arg, NULL, 0); - have_guest_base = 1; + have_guest_base = true; } static void handle_arg_reserved_va(const char *arg) From 7d8cbbabcb1234ffba9a946083073a5e01cdc020 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 May 2020 18:51:30 +0100 Subject: [PATCH 0496/2595] accel/tcg: Relax va restrictions on 64-bit guests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We cannot at present limit a 64-bit guest to a virtual address space smaller than the host. It will mostly work to ignore this limitation, except if the guest uses high bits of the address space for tags. But it will certainly work better, as presently we can wind up failing to allocate the guest stack. Widen our user-only page tree to the host or abi pointer width. Remove the workaround for this problem from target/alpha. Always validate guest addresses vs reserved_va, as there we control allocation ourselves. Signed-off-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20200513175134.19619-7-alex.bennee@linaro.org> --- accel/tcg/translate-all.c | 15 +++++++++------ include/exec/cpu-all.h | 23 +++++++++++++++++++---- target/alpha/cpu-param.h | 15 ++------------- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 9924e66d1f..e4f703a7e6 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -173,8 +173,13 @@ struct page_collection { #define TB_FOR_EACH_JMP(head_tb, tb, n) \ TB_FOR_EACH_TAGGED((head_tb)->jmp_list_head, tb, n, jmp_list_next) -/* In system mode we want L1_MAP to be based on ram offsets, - while in user mode we want it to be based on virtual addresses. */ +/* + * In system mode we want L1_MAP to be based on ram offsets, + * while in user mode we want it to be based on virtual addresses. + * + * TODO: For user mode, see the caveat re host vs guest virtual + * address spaces near GUEST_ADDR_MAX. + */ #if !defined(CONFIG_USER_ONLY) #if HOST_LONG_BITS < TARGET_PHYS_ADDR_SPACE_BITS # define L1_MAP_ADDR_SPACE_BITS HOST_LONG_BITS @@ -182,7 +187,7 @@ struct page_collection { # define L1_MAP_ADDR_SPACE_BITS TARGET_PHYS_ADDR_SPACE_BITS #endif #else -# define L1_MAP_ADDR_SPACE_BITS TARGET_VIRT_ADDR_SPACE_BITS +# define L1_MAP_ADDR_SPACE_BITS MIN(HOST_LONG_BITS, TARGET_ABI_BITS) #endif /* Size of the L2 (and L3, etc) page tables. */ @@ -2497,9 +2502,7 @@ void page_set_flags(target_ulong start, target_ulong end, int flags) /* This function should never be called with addresses outside the guest address space. If this assert fires, it probably indicates a missing call to h2g_valid. */ -#if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS - assert(end <= ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS)); -#endif + assert(end - 1 <= GUEST_ADDR_MAX); assert(start < end); assert_memory_lock(); diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 0895a57881..d14374bdd4 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -162,12 +162,27 @@ extern unsigned long guest_base; extern bool have_guest_base; extern unsigned long reserved_va; -#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS -#define GUEST_ADDR_MAX (~0ul) +/* + * Limit the guest addresses as best we can. + * + * When not using -R reserved_va, we cannot really limit the guest + * to less address space than the host. For 32-bit guests, this + * acts as a sanity check that we're not giving the guest an address + * that it cannot even represent. For 64-bit guests... the address + * might not be what the real kernel would give, but it is at least + * representable in the guest. + * + * TODO: Improve address allocation to avoid this problem, and to + * avoid setting bits at the top of guest addresses that might need + * to be used for tags. + */ +#if MIN(TARGET_VIRT_ADDR_SPACE_BITS, TARGET_ABI_BITS) <= 32 +# define GUEST_ADDR_MAX_ UINT32_MAX #else -#define GUEST_ADDR_MAX (reserved_va ? reserved_va - 1 : \ - (1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1) +# define GUEST_ADDR_MAX_ (~0ul) #endif +#define GUEST_ADDR_MAX (reserved_va ? reserved_va - 1 : GUEST_ADDR_MAX_) + #else #include "exec/hwaddr.h" diff --git a/target/alpha/cpu-param.h b/target/alpha/cpu-param.h index 692aee27ca..1153992e42 100644 --- a/target/alpha/cpu-param.h +++ b/target/alpha/cpu-param.h @@ -10,22 +10,11 @@ #define TARGET_LONG_BITS 64 #define TARGET_PAGE_BITS 13 -#ifdef CONFIG_USER_ONLY -/* - * ??? The kernel likes to give addresses in high memory. If the host has - * more virtual address space than the guest, this can lead to impossible - * allocations. Honor the long-standing assumption that only kernel addrs - * are negative, but otherwise allow allocations anywhere. This could lead - * to tricky emulation problems for programs doing tagged addressing, but - * that's far fewer than encounter the impossible allocation problem. - */ -#define TARGET_PHYS_ADDR_SPACE_BITS 63 -#define TARGET_VIRT_ADDR_SPACE_BITS 63 -#else + /* ??? EV4 has 34 phys addr bits, EV5 has 40, EV6 has 44. */ #define TARGET_PHYS_ADDR_SPACE_BITS 44 #define TARGET_VIRT_ADDR_SPACE_BITS (30 + TARGET_PAGE_BITS) -#endif + #define NB_MMU_MODES 3 #endif From 6a7aa856c59fba11c119fd2f62a2dbd03f8ca08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 13 May 2020 18:51:31 +0100 Subject: [PATCH 0497/2595] accel/tcg: don't disable exec_tb trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I doubt the well predicted trace event check is particularly special in the grand context of TCG code execution. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200513175134.19619-8-alex.bennee@linaro.org> --- accel/tcg/trace-events | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accel/tcg/trace-events b/accel/tcg/trace-events index 01852217a6..385b9f749b 100644 --- a/accel/tcg/trace-events +++ b/accel/tcg/trace-events @@ -1,10 +1,10 @@ # See docs/devel/tracing.txt for syntax documentation. -# TCG related tracing (mostly disabled by default) +# TCG related tracing # cpu-exec.c -disable exec_tb(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR -disable exec_tb_nocache(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR -disable exec_tb_exit(void *last_tb, unsigned int flags) "tb:%p flags=0x%x" +exec_tb(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR +exec_tb_nocache(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR +exec_tb_exit(void *last_tb, unsigned int flags) "tb:%p flags=0x%x" # translate-all.c translate_block(void *tb, uintptr_t pc, uint8_t *tb_code) "tb:%p, pc:0x%"PRIxPTR", tb_code:%p" From e5ef4ec28b801155e20fdb3a4cd21920ffc5f1af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 13 May 2020 18:51:32 +0100 Subject: [PATCH 0498/2595] disas: include an optional note for the start of disassembly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will become useful shortly for providing more information about output assembly inline. While there fix up the indenting and code formatting in disas(). Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200513175134.19619-9-alex.bennee@linaro.org> --- accel/tcg/translate-all.c | 4 ++-- disas.c | 14 ++++++++++---- include/disas/disas.h | 2 +- include/exec/log.h | 4 ++-- tcg/tcg.c | 4 ++-- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index e4f703a7e6..cdf58bb420 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1800,7 +1800,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, size_t data_size = gen_code_size - code_size; size_t i; - log_disas(tb->tc.ptr, code_size); + log_disas(tb->tc.ptr, code_size, NULL); for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { if (sizeof(tcg_target_ulong) == 8) { @@ -1814,7 +1814,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, } } } else { - log_disas(tb->tc.ptr, gen_code_size); + log_disas(tb->tc.ptr, gen_code_size, NULL); } qemu_log("\n"); qemu_log_flush(); diff --git a/disas.c b/disas.c index 3937da6157..7e8692de30 100644 --- a/disas.c +++ b/disas.c @@ -586,7 +586,7 @@ char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size) } /* Disassemble this for me please... (debugging). */ -void disas(FILE *out, void *code, unsigned long size) +void disas(FILE *out, void *code, unsigned long size, const char *note) { uintptr_t pc; int count; @@ -674,10 +674,16 @@ void disas(FILE *out, void *code, unsigned long size) for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) { fprintf(out, "0x%08" PRIxPTR ": ", pc); count = print_insn(pc, &s.info); - fprintf(out, "\n"); - if (count < 0) - break; + if (note) { + fprintf(out, "\t\t%s", note); + note = NULL; + } + fprintf(out, "\n"); + if (count < 0) { + break; + } } + } /* Look up symbol for debugging purpose. Returns "" if unknown. */ diff --git a/include/disas/disas.h b/include/disas/disas.h index 36c33f6f19..1b6e035e32 100644 --- a/include/disas/disas.h +++ b/include/disas/disas.h @@ -7,7 +7,7 @@ #include "cpu.h" /* Disassemble this for me please... (debugging). */ -void disas(FILE *out, void *code, unsigned long size); +void disas(FILE *out, void *code, unsigned long size, const char *note); void target_disas(FILE *out, CPUState *cpu, target_ulong code, target_ulong size); diff --git a/include/exec/log.h b/include/exec/log.h index fcc7b9e00b..3ed797c1c8 100644 --- a/include/exec/log.h +++ b/include/exec/log.h @@ -56,13 +56,13 @@ static inline void log_target_disas(CPUState *cpu, target_ulong start, rcu_read_unlock(); } -static inline void log_disas(void *code, unsigned long size) +static inline void log_disas(void *code, unsigned long size, const char *note) { QemuLogFile *logfile; rcu_read_lock(); logfile = atomic_rcu_read(&qemu_logfile); if (logfile) { - disas(logfile->fd, code, size); + disas(logfile->fd, code, size, note); } rcu_read_unlock(); } diff --git a/tcg/tcg.c b/tcg/tcg.c index dd4b3d7684..a2268d9db0 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1092,7 +1092,7 @@ void tcg_prologue_init(TCGContext *s) size_t data_size = prologue_size - code_size; size_t i; - log_disas(buf0, code_size); + log_disas(buf0, code_size, NULL); for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { if (sizeof(tcg_target_ulong) == 8) { @@ -1106,7 +1106,7 @@ void tcg_prologue_init(TCGContext *s) } } } else { - log_disas(buf0, prologue_size); + log_disas(buf0, prologue_size, NULL); } qemu_log("\n"); qemu_log_flush(); From 16b22e02b57e403568b471511e0b2a70789c94df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 13 May 2020 18:51:33 +0100 Subject: [PATCH 0499/2595] disas: add optional note support to cap_disas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include support for outputting a note at the top of a chunk of disassembly to capstone as well. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200513175134.19619-10-alex.bennee@linaro.org> --- disas.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/disas.c b/disas.c index 7e8692de30..45285d3f63 100644 --- a/disas.c +++ b/disas.c @@ -260,7 +260,8 @@ static void cap_dump_insn_units(disassemble_info *info, cs_insn *insn, } } -static void cap_dump_insn(disassemble_info *info, cs_insn *insn) +static void cap_dump_insn(disassemble_info *info, cs_insn *insn, + const char *note) { fprintf_function print = info->fprintf_func; int i, n, split; @@ -281,7 +282,11 @@ static void cap_dump_insn(disassemble_info *info, cs_insn *insn) } /* Print the actual instruction. */ - print(info->stream, " %-8s %s\n", insn->mnemonic, insn->op_str); + print(info->stream, " %-8s %s", insn->mnemonic, insn->op_str); + if (note) { + print(info->stream, "\t\t%s", note); + } + print(info->stream, "\n"); /* Dump any remaining part of the insn on subsequent lines. */ for (i = split; i < n; i += split) { @@ -313,7 +318,7 @@ static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size) size -= tsize; while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) { - cap_dump_insn(info, insn); + cap_dump_insn(info, insn, NULL); } /* If the target memory is not consumed, go back for more... */ @@ -342,7 +347,8 @@ static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size) } /* Disassemble SIZE bytes at CODE for the host. */ -static bool cap_disas_host(disassemble_info *info, void *code, size_t size) +static bool cap_disas_host(disassemble_info *info, void *code, size_t size, + const char *note) { csh handle; const uint8_t *cbuf; @@ -358,7 +364,8 @@ static bool cap_disas_host(disassemble_info *info, void *code, size_t size) pc = (uintptr_t)code; while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) { - cap_dump_insn(info, insn); + cap_dump_insn(info, insn, note); + note = NULL; } if (size != 0) { (*info->fprintf_func)(info->stream, @@ -402,7 +409,7 @@ static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count) csize += tsize; if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) { - cap_dump_insn(info, insn); + cap_dump_insn(info, insn, NULL); if (--count <= 0) { break; } @@ -416,7 +423,7 @@ static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count) #endif /* !CONFIG_USER_ONLY */ #else # define cap_disas_target(i, p, s) false -# define cap_disas_host(i, p, s) false +# define cap_disas_host(i, p, s, n) false # define cap_disas_monitor(i, p, c) false # define cap_disas_plugin(i, p, c) false #endif /* CONFIG_CAPSTONE */ @@ -664,7 +671,7 @@ void disas(FILE *out, void *code, unsigned long size, const char *note) print_insn = print_insn_hppa; #endif - if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) { + if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size, note)) { return; } From 5f0df0333b20be816ae54a3fa6476f79f9da160e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 13 May 2020 18:51:34 +0100 Subject: [PATCH 0500/2595] translate-all: include guest address in out_asm output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have information about where each guest instructions representation starts stored in the tcg_ctx->gen_insn_data so we can rectify the PC for faults. We can re-use this information to annotate the out_asm output with guest instruction address which makes it a bit easier to work out where you are especially with longer blocks. A minor wrinkle is that some instructions get optimised away so we have to scan forward until we find some actual generated code. Signed-off-by: Alex Bennée Message-Id: <20200513175134.19619-11-alex.bennee@linaro.org> --- accel/tcg/translate-all.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index cdf58bb420..42ce1dfcff 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1794,14 +1794,43 @@ TranslationBlock *tb_gen_code(CPUState *cpu, if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM) && qemu_log_in_addr_range(tb->pc)) { FILE *logfile = qemu_log_lock(); + int code_size, data_size = 0; + g_autoptr(GString) note = g_string_new("[tb header & initial instruction]"); + size_t chunk_start = 0; + int insn = 0; qemu_log("OUT: [size=%d]\n", gen_code_size); if (tcg_ctx->data_gen_ptr) { - size_t code_size = tcg_ctx->data_gen_ptr - tb->tc.ptr; - size_t data_size = gen_code_size - code_size; - size_t i; + code_size = tcg_ctx->data_gen_ptr - tb->tc.ptr; + data_size = gen_code_size - code_size; + } else { + code_size = gen_code_size; + } - log_disas(tb->tc.ptr, code_size, NULL); + /* Dump header and the first instruction */ + chunk_start = tcg_ctx->gen_insn_end_off[insn]; + log_disas(tb->tc.ptr, chunk_start, note->str); + /* + * Dump each instruction chunk, wrapping up empty chunks into + * the next instruction. The whole array is offset so the + * first entry is the beginning of the 2nd instruction. + */ + while (insn <= tb->icount && chunk_start < code_size) { + size_t chunk_end = tcg_ctx->gen_insn_end_off[insn]; + if (chunk_end > chunk_start) { + g_string_printf(note, "[guest addr: " TARGET_FMT_lx "]", + tcg_ctx->gen_insn_data[insn][0]); + log_disas(tb->tc.ptr + chunk_start, chunk_end - chunk_start, + note->str); + chunk_start = chunk_end; + } + insn++; + } + + /* Finally dump any data we may have after the block */ + if (data_size) { + int i; + qemu_log(" data: [size=%d]\n", data_size); for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) { if (sizeof(tcg_target_ulong) == 8) { qemu_log("0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n", @@ -1813,8 +1842,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, *(uint32_t *)(tcg_ctx->data_gen_ptr + i)); } } - } else { - log_disas(tb->tc.ptr, gen_code_size, NULL); } qemu_log("\n"); qemu_log_flush(); From d2f6dc0790b5a87adb91b150c6a1a88163a0e2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 13 May 2020 18:31:53 +0100 Subject: [PATCH 0501/2595] qemu/plugin: Trivial code movement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the qemu_plugin_event enum declaration earlier. This will make the next commit easier to review. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Emilio G. Cota Signed-off-by: Alex Bennée Message-Id: <20200510171119.20827-2-f4bug@amsat.org> Message-Id: <20200513173200.11830-2-alex.bennee@linaro.org> --- include/qemu/plugin.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index 11687e8cdc..e45f950fe3 100644 --- a/include/qemu/plugin.h +++ b/include/qemu/plugin.h @@ -13,6 +13,22 @@ #include "qemu/queue.h" #include "qemu/option.h" +/* + * Events that plugins can subscribe to. + */ +enum qemu_plugin_event { + QEMU_PLUGIN_EV_VCPU_INIT, + QEMU_PLUGIN_EV_VCPU_EXIT, + QEMU_PLUGIN_EV_VCPU_TB_TRANS, + QEMU_PLUGIN_EV_VCPU_IDLE, + QEMU_PLUGIN_EV_VCPU_RESUME, + QEMU_PLUGIN_EV_VCPU_SYSCALL, + QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, + QEMU_PLUGIN_EV_FLUSH, + QEMU_PLUGIN_EV_ATEXIT, + QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */ +}; + /* * Option parsing/processing. * Note that we can load an arbitrary number of plugins. @@ -47,22 +63,6 @@ static inline int qemu_plugin_load_list(QemuPluginList *head) } #endif /* !CONFIG_PLUGIN */ -/* - * Events that plugins can subscribe to. - */ -enum qemu_plugin_event { - QEMU_PLUGIN_EV_VCPU_INIT, - QEMU_PLUGIN_EV_VCPU_EXIT, - QEMU_PLUGIN_EV_VCPU_TB_TRANS, - QEMU_PLUGIN_EV_VCPU_IDLE, - QEMU_PLUGIN_EV_VCPU_RESUME, - QEMU_PLUGIN_EV_VCPU_SYSCALL, - QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, - QEMU_PLUGIN_EV_FLUSH, - QEMU_PLUGIN_EV_ATEXIT, - QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */ -}; - union qemu_plugin_cb_sig { qemu_plugin_simple_cb_t simple; qemu_plugin_udata_cb_t udata; From 1b9905ca0a7fdfdb691131646ee311e7e7dd1dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 13 May 2020 18:31:54 +0100 Subject: [PATCH 0502/2595] qemu/plugin: Move !CONFIG_PLUGIN stubs altogether MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the ifdef'ry by moving all stubs together. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Emilio G. Cota Signed-off-by: Alex Bennée Message-Id: <20200510171119.20827-3-f4bug@amsat.org> Message-Id: <20200513173200.11830-3-alex.bennee@linaro.org> --- include/qemu/plugin.h | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index e45f950fe3..ab790ad105 100644 --- a/include/qemu/plugin.h +++ b/include/qemu/plugin.h @@ -46,22 +46,6 @@ static inline void qemu_plugin_add_opts(void) void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head); int qemu_plugin_load_list(QemuPluginList *head); -#else /* !CONFIG_PLUGIN */ -static inline void qemu_plugin_add_opts(void) -{ } - -static inline void qemu_plugin_opt_parse(const char *optarg, - QemuPluginList *head) -{ - error_report("plugin interface not enabled in this build"); - exit(1); -} - -static inline int qemu_plugin_load_list(QemuPluginList *head) -{ - return 0; -} -#endif /* !CONFIG_PLUGIN */ union qemu_plugin_cb_sig { qemu_plugin_simple_cb_t simple; @@ -182,8 +166,6 @@ struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb) return insn; } -#ifdef CONFIG_PLUGIN - void qemu_plugin_vcpu_init_hook(CPUState *cpu); void qemu_plugin_vcpu_exit_hook(CPUState *cpu); void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb); @@ -207,6 +189,21 @@ void qemu_plugin_disable_mem_helpers(CPUState *cpu); #else /* !CONFIG_PLUGIN */ +static inline void qemu_plugin_add_opts(void) +{ } + +static inline void qemu_plugin_opt_parse(const char *optarg, + QemuPluginList *head) +{ + error_report("plugin interface not enabled in this build"); + exit(1); +} + +static inline int qemu_plugin_load_list(QemuPluginList *head) +{ + return 0; +} + static inline void qemu_plugin_vcpu_init_hook(CPUState *cpu) { } From 308e7549642eb74b9671b94dd56d1e20773c358a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 13 May 2020 18:31:55 +0100 Subject: [PATCH 0503/2595] qemu/qemu-plugin: Make qemu_plugin_hwaddr_is_io() hwaddr argument const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename qemu_plugin_hwaddr_is_io() address argument 'haddr' similarly to qemu_plugin_hwaddr_device_offset(), and make it const. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Emilio G. Cota Signed-off-by: Alex Bennée Message-Id: <20200510171119.20827-4-f4bug@amsat.org> Message-Id: <20200513173200.11830-4-alex.bennee@linaro.org> --- include/qemu/qemu-plugin.h | 2 +- plugins/api.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index 5502e112c8..89ed579f55 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -331,7 +331,7 @@ struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info, * to return information about it. For non-IO accesses the device * offset will be into the appropriate block of RAM. */ -bool qemu_plugin_hwaddr_is_io(struct qemu_plugin_hwaddr *hwaddr); +bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr); uint64_t qemu_plugin_hwaddr_device_offset(const struct qemu_plugin_hwaddr *haddr); typedef void diff --git a/plugins/api.c b/plugins/api.c index 53c8a73582..bbdc5a4eb4 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -275,10 +275,10 @@ struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info, } #endif -bool qemu_plugin_hwaddr_is_io(struct qemu_plugin_hwaddr *hwaddr) +bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr) { #ifdef CONFIG_SOFTMMU - return hwaddr->is_io; + return haddr->is_io; #else return false; #endif From adf1cfbdc29e6e3342ca07701be4d2cbfd7d3907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 13 May 2020 18:31:56 +0100 Subject: [PATCH 0504/2595] MAINTAINERS: update the orphaned cpus-common.c file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We forgot to update MAINTAINERS when this code was re-factored. Fixes: 267f685b8b Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200513173200.11830-5-alex.bennee@linaro.org> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index f02e290702..47ef3139e6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -115,6 +115,7 @@ M: Richard Henderson R: Paolo Bonzini S: Maintained F: cpus.c +F: cpus-common.c F: exec.c F: accel/tcg/ F: accel/stubs/tcg-stub.c From 7537c2b4a363237534c96d089a02b0712b49d890 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 4 May 2020 23:37:54 +0000 Subject: [PATCH 0505/2595] softfloat: silence sNaN for conversions to/from floatx80 Conversions between IEEE floating-point formats should convert signaling NaNs to quiet NaNs. Most of those in QEMU's softfloat code do so, but those for floatx80 fail to. Fix those conversions to silence signaling NaNs as well. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Richard Henderson --- fpu/softfloat.c | 24 +++++++--- tests/tcg/i386/test-i386-snan-convert.c | 63 +++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 tests/tcg/i386/test-i386-snan-convert.c diff --git a/fpu/softfloat.c b/fpu/softfloat.c index ae6ba71854..ac116c70b8 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -4498,7 +4498,9 @@ floatx80 float32_to_floatx80(float32 a, float_status *status) aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { if (aSig) { - return commonNaNToFloatx80(float32ToCommonNaN(a, status), status); + floatx80 res = commonNaNToFloatx80(float32ToCommonNaN(a, status), + status); + return floatx80_silence_nan(res, status); } return packFloatx80(aSign, floatx80_infinity_high, @@ -5016,7 +5018,9 @@ floatx80 float64_to_floatx80(float64 a, float_status *status) aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { if (aSig) { - return commonNaNToFloatx80(float64ToCommonNaN(a, status), status); + floatx80 res = commonNaNToFloatx80(float64ToCommonNaN(a, status), + status); + return floatx80_silence_nan(res, status); } return packFloatx80(aSign, floatx80_infinity_high, @@ -5618,7 +5622,9 @@ float32 floatx80_to_float32(floatx80 a, float_status *status) aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { if ( (uint64_t) ( aSig<<1 ) ) { - return commonNaNToFloat32(floatx80ToCommonNaN(a, status), status); + float32 res = commonNaNToFloat32(floatx80ToCommonNaN(a, status), + status); + return float32_silence_nan(res, status); } return packFloat32( aSign, 0xFF, 0 ); } @@ -5650,7 +5656,9 @@ float64 floatx80_to_float64(floatx80 a, float_status *status) aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { if ( (uint64_t) ( aSig<<1 ) ) { - return commonNaNToFloat64(floatx80ToCommonNaN(a, status), status); + float64 res = commonNaNToFloat64(floatx80ToCommonNaN(a, status), + status); + return float64_silence_nan(res, status); } return packFloat64( aSign, 0x7FF, 0 ); } @@ -5681,7 +5689,9 @@ float128 floatx80_to_float128(floatx80 a, float_status *status) aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) { - return commonNaNToFloat128(floatx80ToCommonNaN(a, status), status); + float128 res = commonNaNToFloat128(floatx80ToCommonNaN(a, status), + status); + return float128_silence_nan(res, status); } shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 ); return packFloat128( aSign, aExp, zSig0, zSig1 ); @@ -6959,7 +6969,9 @@ floatx80 float128_to_floatx80(float128 a, float_status *status) aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) { - return commonNaNToFloatx80(float128ToCommonNaN(a, status), status); + floatx80 res = commonNaNToFloatx80(float128ToCommonNaN(a, status), + status); + return floatx80_silence_nan(res, status); } return packFloatx80(aSign, floatx80_infinity_high, floatx80_infinity_low); diff --git a/tests/tcg/i386/test-i386-snan-convert.c b/tests/tcg/i386/test-i386-snan-convert.c new file mode 100644 index 0000000000..ed6d535ce2 --- /dev/null +++ b/tests/tcg/i386/test-i386-snan-convert.c @@ -0,0 +1,63 @@ +/* Test conversions of signaling NaNs to and from long double. */ + +#include +#include + +volatile float f_res; +volatile double d_res; +volatile long double ld_res; + +volatile float f_snan = __builtin_nansf(""); +volatile double d_snan = __builtin_nans(""); +volatile long double ld_snan = __builtin_nansl(""); + +int issignaling_f(float x) +{ + union { float f; uint32_t u; } u = { .f = x }; + return (u.u & 0x7fffffff) > 0x7f800000 && (u.u & 0x400000) == 0; +} + +int issignaling_d(double x) +{ + union { double d; uint64_t u; } u = { .d = x }; + return (((u.u & UINT64_C(0x7fffffffffffffff)) > + UINT64_C(0x7ff0000000000000)) && + (u.u & UINT64_C(0x8000000000000)) == 0); +} + +int issignaling_ld(long double x) +{ + union { + long double ld; + struct { uint64_t sig; uint16_t sign_exp; } s; + } u = { .ld = x }; + return ((u.s.sign_exp & 0x7fff) == 0x7fff && + (u.s.sig >> 63) != 0 && + (u.s.sig & UINT64_C(0x4000000000000000)) == 0); +} + +int main(void) +{ + int ret = 0; + ld_res = f_snan; + if (issignaling_ld(ld_res)) { + printf("FAIL: float -> long double\n"); + ret = 1; + } + ld_res = d_snan; + if (issignaling_ld(ld_res)) { + printf("FAIL: double -> long double\n"); + ret = 1; + } + f_res = ld_snan; + if (issignaling_d(f_res)) { + printf("FAIL: long double -> float\n"); + ret = 1; + } + d_res = ld_snan; + if (issignaling_d(d_res)) { + printf("FAIL: long double -> double\n"); + ret = 1; + } + return ret; +} From 41602807766e253ccb6fb761f3ff12767f786e2c Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 4 May 2020 23:38:44 +0000 Subject: [PATCH 0506/2595] softfloat: fix floatx80 pseudo-denormal addition / subtraction The softfloat function addFloatx80Sigs, used for addition of values with the same sign and subtraction of values with opposite sign, fails to handle the case where the two values both have biased exponent zero and there is a carry resulting from adding the significands, which can occur if one or both values are pseudo-denormals (biased exponent zero, explicit integer bit 1). Add a check for that case, so making the results match those seen on x86 hardware for pseudo-denormals. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Richard Henderson --- fpu/softfloat.c | 6 ++++++ tests/tcg/i386/test-i386-pseudo-denormal.c | 24 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/tcg/i386/test-i386-pseudo-denormal.c diff --git a/fpu/softfloat.c b/fpu/softfloat.c index ac116c70b8..6094d267b5 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5866,6 +5866,12 @@ static floatx80 addFloatx80Sigs(floatx80 a, floatx80 b, flag zSign, zSig1 = 0; zSig0 = aSig + bSig; if ( aExp == 0 ) { + if ((aSig | bSig) & UINT64_C(0x8000000000000000) && zSig0 < aSig) { + /* At least one of the values is a pseudo-denormal, + * and there is a carry out of the result. */ + zExp = 1; + goto shiftRight1; + } if (zSig0 == 0) { return packFloatx80(zSign, 0, 0); } diff --git a/tests/tcg/i386/test-i386-pseudo-denormal.c b/tests/tcg/i386/test-i386-pseudo-denormal.c new file mode 100644 index 0000000000..cfa2a500b0 --- /dev/null +++ b/tests/tcg/i386/test-i386-pseudo-denormal.c @@ -0,0 +1,24 @@ +/* Test pseudo-denormal operations. */ + +#include +#include + +union u { + struct { uint64_t sig; uint16_t sign_exp; } s; + long double ld; +}; + +volatile union u ld_pseudo_m16382 = { .s = { UINT64_C(1) << 63, 0 } }; + +volatile long double ld_res; + +int main(void) +{ + int ret = 0; + ld_res = ld_pseudo_m16382.ld + ld_pseudo_m16382.ld; + if (ld_res != 0x1p-16381L) { + printf("FAIL: pseudo-denormal add\n"); + ret = 1; + } + return ret; +} From be53fa785ab766d2722628403edee75b3e6ab599 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 4 May 2020 23:39:39 +0000 Subject: [PATCH 0507/2595] softfloat: fix floatx80 pseudo-denormal comparisons The softfloat floatx80 comparisons fail to allow for pseudo-denormals, which should compare equal to corresponding values with biased exponent 1 rather than 0. Add an adjustment for that case when comparing numbers with the same sign. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Richard Henderson --- fpu/softfloat.c | 7 +++++++ tests/tcg/i386/test-i386-pseudo-denormal.c | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 6094d267b5..c57f72e3a6 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -7966,6 +7966,13 @@ static inline int floatx80_compare_internal(floatx80 a, floatx80 b, return 1 - (2 * aSign); } } else { + /* Normalize pseudo-denormals before comparison. */ + if ((a.high & 0x7fff) == 0 && a.low & UINT64_C(0x8000000000000000)) { + ++a.high; + } + if ((b.high & 0x7fff) == 0 && b.low & UINT64_C(0x8000000000000000)) { + ++b.high; + } if (a.low == b.low && a.high == b.high) { return float_relation_equal; } else { diff --git a/tests/tcg/i386/test-i386-pseudo-denormal.c b/tests/tcg/i386/test-i386-pseudo-denormal.c index cfa2a500b0..acf2b9cf03 100644 --- a/tests/tcg/i386/test-i386-pseudo-denormal.c +++ b/tests/tcg/i386/test-i386-pseudo-denormal.c @@ -20,5 +20,9 @@ int main(void) printf("FAIL: pseudo-denormal add\n"); ret = 1; } + if (ld_pseudo_m16382.ld != 0x1p-16382L) { + printf("FAIL: pseudo-denormal compare\n"); + ret = 1; + } return ret; } From 9ecaf5ccec13ff2e8fe1e72f6e0f3367d2169c1c Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 4 May 2020 23:40:20 +0000 Subject: [PATCH 0508/2595] softfloat: fix floatx80 pseudo-denormal round to integer The softfloat function floatx80_round_to_int incorrectly handles the case of a pseudo-denormal where only the high bit of the significand is set, ignoring that bit (treating the number as an exact zero) rather than treating the number as an alternative representation of +/- 2^-16382 (which may round to +/- 1 depending on the rounding mode) as hardware does. Fix this check (simplifying the code in the process). Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Richard Henderson --- fpu/softfloat.c | 2 +- tests/tcg/i386/test-i386-pseudo-denormal.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index c57f72e3a6..a362bf89ca 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5741,7 +5741,7 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status) } if ( aExp < 0x3FFF ) { if ( ( aExp == 0 ) - && ( (uint64_t) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) { + && ( (uint64_t) ( extractFloatx80Frac( a ) ) == 0 ) ) { return a; } status->float_exception_flags |= float_flag_inexact; diff --git a/tests/tcg/i386/test-i386-pseudo-denormal.c b/tests/tcg/i386/test-i386-pseudo-denormal.c index acf2b9cf03..00d510cf4a 100644 --- a/tests/tcg/i386/test-i386-pseudo-denormal.c +++ b/tests/tcg/i386/test-i386-pseudo-denormal.c @@ -14,6 +14,7 @@ volatile long double ld_res; int main(void) { + short cw; int ret = 0; ld_res = ld_pseudo_m16382.ld + ld_pseudo_m16382.ld; if (ld_res != 0x1p-16381L) { @@ -24,5 +25,14 @@ int main(void) printf("FAIL: pseudo-denormal compare\n"); ret = 1; } + /* Set round-upward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x800; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ ("frndint" : "=t" (ld_res) : "0" (ld_pseudo_m16382.ld)); + if (ld_res != 1.0L) { + printf("FAIL: pseudo-denormal round-to-integer\n"); + ret = 1; + } return ret; } From 2cc2278edf0403720397a33b0747e0aba9e6d420 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 4 May 2020 04:30:45 -0700 Subject: [PATCH 0509/2595] target/xtensa: fetch HW version from configuration overlay Xtensa architecture has features which behavior depends on hardware version. Provide hardware version information to translators: add XtensaConfig::hw_version and use XCHAL_HW_VERSION from configuration overlay to initialize it. Signed-off-by: Max Filippov --- target/xtensa/cpu.h | 1 + target/xtensa/overlay_tool.h | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 7a46dccbe1..32749378bf 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -464,6 +464,7 @@ struct XtensaConfig { XtensaMemory sysrom; XtensaMemory sysram; + unsigned hw_version; uint32_t configid[2]; void *isa_internal; diff --git a/target/xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h index cab532095c..a994e69b6e 100644 --- a/target/xtensa/overlay_tool.h +++ b/target/xtensa/overlay_tool.h @@ -60,8 +60,9 @@ #define XCHAL_RESET_VECTOR1_VADDR XCHAL_RESET_VECTOR_VADDR #endif -#ifndef XCHAL_HW_MIN_VERSION -#define XCHAL_HW_MIN_VERSION 0 +#ifndef XCHAL_HW_VERSION +#define XCHAL_HW_VERSION (XCHAL_HW_VERSION_MAJOR * 100 \ + + XCHAL_HW_VERSION_MINOR) #endif #ifndef XCHAL_LOOP_BUFFER_SIZE @@ -100,7 +101,7 @@ XCHAL_OPTION(XCHAL_HAVE_FP, XTENSA_OPTION_FP_COPROCESSOR) | \ XCHAL_OPTION(XCHAL_HAVE_RELEASE_SYNC, XTENSA_OPTION_MP_SYNCHRO) | \ XCHAL_OPTION(XCHAL_HAVE_S32C1I, XTENSA_OPTION_CONDITIONAL_STORE) | \ - XCHAL_OPTION(((XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION >= 230000) || \ + XCHAL_OPTION(((XCHAL_HAVE_S32C1I && XCHAL_HW_VERSION >= 230000) || \ XCHAL_HAVE_EXCLUSIVE), XTENSA_OPTION_ATOMCTL) | \ XCHAL_OPTION(XCHAL_HAVE_DEPBITS, XTENSA_OPTION_DEPBITS) | \ /* Interrupts and exceptions */ \ @@ -498,6 +499,7 @@ } #define CONFIG_SECTION \ + .hw_version = XCHAL_HW_VERSION, \ .configid = { \ XCHAL_HW_CONFIGID0, \ XCHAL_HW_CONFIGID1, \ From 62ed68e33db89584355ca4c63cd5b21dd98df636 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 4 May 2020 05:15:14 -0700 Subject: [PATCH 0510/2595] target/xtensa: fix simcall for newer hardware After Xtensa release RE.2 simcall opcode has become nop for the hardware instead of illegal instruction. Signed-off-by: Max Filippov --- target/xtensa/translate.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 546d2fa2fa..4bc15252c8 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -2367,9 +2367,10 @@ static bool test_ill_simcall(DisasContext *dc, const OpcodeArg arg[], #ifdef CONFIG_USER_ONLY bool ill = true; #else - bool ill = !semihosting_enabled(); + /* Between RE.2 and RE.3 simcall opcode's become nop for the hardware. */ + bool ill = dc->config->hw_version <= 250002 && !semihosting_enabled(); #endif - if (ill) { + if (ill || !semihosting_enabled()) { qemu_log_mask(LOG_GUEST_ERROR, "SIMCALL but semihosting is disabled\n"); } return ill; @@ -2379,7 +2380,9 @@ static void translate_simcall(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_helper_simcall(cpu_env); + if (semihosting_enabled()) { + gen_helper_simcall(cpu_env); + } #endif } From b0588cb51da6986715294bfec4b52f55612a666e Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 16 May 2020 15:13:03 +0200 Subject: [PATCH 0511/2595] ati-vga: Do not allow unaligned access via index register According to docs bits 1 and 0 of MM_INDEX are hard coded to 0 so unaligned access via this register should not be possible. This also fixes problems reported in bug #1878134. Buglink: https://bugs.launchpad.net/qemu/+bug/1878134 Signed-off-by: BALATON Zoltan Tested-by: Alexander Bulekov Acked-by: Alexander Bulekov Message-id: 20200516132352.39E9374594E@zero.eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/ati.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/display/ati.c b/hw/display/ati.c index 58ec8291d4..065f197678 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -511,7 +511,7 @@ static void ati_mm_write(void *opaque, hwaddr addr, } switch (addr) { case MM_INDEX: - s->regs.mm_index = data; + s->regs.mm_index = data & ~3; break; case MM_DATA ... MM_DATA + 3: /* indexed access to regs or memory */ From 63dc3465d6e2c1c31769b0d099991ee978e6e311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 10:20:02 +0200 Subject: [PATCH 0512/2595] hw/display: Include local 'framebuffer.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "framebuffer.h" header is not an exported include. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Message-id: 20200504082003.16298-2-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/artist.c | 2 +- hw/display/next-fb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/display/artist.c b/hw/display/artist.c index 7e2a4556bd..6261bfe65b 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -21,7 +21,7 @@ #include "migration/vmstate.h" #include "ui/console.h" #include "trace.h" -#include "hw/display/framebuffer.h" +#include "framebuffer.h" #define TYPE_ARTIST "artist" #define ARTIST(obj) OBJECT_CHECK(ARTISTState, (obj), TYPE_ARTIST) diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c index 2b726a10f8..b0513a8fba 100644 --- a/hw/display/next-fb.c +++ b/hw/display/next-fb.c @@ -27,7 +27,7 @@ #include "hw/hw.h" #include "hw/boards.h" #include "hw/loader.h" -#include "hw/display/framebuffer.h" +#include "framebuffer.h" #include "ui/pixel_ops.h" #include "hw/m68k/next-cube.h" From 2fc979cb9d717161c1dfde69fa5fe495c1ab03e9 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 13:52:31 +0200 Subject: [PATCH 0513/2595] Revert "hw/display/ramfb: initialize fw-config space with xres/ yres" This reverts commit f79081b4b71b72640bedd40a7cd76f864c8287f1. Patch has broken byteorder handling: RAMFBCfg fields are in bigendian byteorder, the reset function doesn't care so native byteorder is used instead. Given this went unnoticed so far the feature is obviously unused, so just revert the patch. Cc: Hou Qiming Signed-off-by: Gerd Hoffmann Acked-by: Laszlo Ersek Message-id: 20200429115236.28709-2-kraxel@redhat.com --- hw/display/ramfb-standalone.c | 12 +----------- hw/display/ramfb.c | 16 +--------------- hw/vfio/display.c | 4 ++-- include/hw/display/ramfb.h | 2 +- stubs/ramfb.c | 2 +- 5 files changed, 6 insertions(+), 30 deletions(-) diff --git a/hw/display/ramfb-standalone.c b/hw/display/ramfb-standalone.c index d76a9d0fe2..b18db97eeb 100644 --- a/hw/display/ramfb-standalone.c +++ b/hw/display/ramfb-standalone.c @@ -3,7 +3,6 @@ #include "qemu/module.h" #include "hw/loader.h" #include "hw/qdev-properties.h" -#include "hw/isa/isa.h" #include "hw/display/ramfb.h" #include "ui/console.h" @@ -13,8 +12,6 @@ typedef struct RAMFBStandaloneState { SysBusDevice parent_obj; QemuConsole *con; RAMFBState *state; - uint32_t xres; - uint32_t yres; } RAMFBStandaloneState; static void display_update_wrapper(void *dev) @@ -37,22 +34,15 @@ static void ramfb_realizefn(DeviceState *dev, Error **errp) RAMFBStandaloneState *ramfb = RAMFB(dev); ramfb->con = graphic_console_init(dev, 0, &wrapper_ops, dev); - ramfb->state = ramfb_setup(dev, errp); + ramfb->state = ramfb_setup(errp); } -static Property ramfb_properties[] = { - DEFINE_PROP_UINT32("xres", RAMFBStandaloneState, xres, 0), - DEFINE_PROP_UINT32("yres", RAMFBStandaloneState, yres, 0), - DEFINE_PROP_END_OF_LIST(), -}; - static void ramfb_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->realize = ramfb_realizefn; - device_class_set_props(dc, ramfb_properties); dc->desc = "ram framebuffer standalone device"; dc->user_creatable = true; } diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c index 7ba07c80f6..bd4746dc17 100644 --- a/hw/display/ramfb.c +++ b/hw/display/ramfb.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu/option.h" #include "hw/loader.h" #include "hw/display/ramfb.h" #include "ui/console.h" @@ -31,7 +30,6 @@ struct QEMU_PACKED RAMFBCfg { struct RAMFBState { DisplaySurface *ds; uint32_t width, height; - uint32_t starting_width, starting_height; struct RAMFBCfg cfg; bool locked; }; @@ -117,11 +115,9 @@ static void ramfb_reset(void *opaque) RAMFBState *s = (RAMFBState *)opaque; s->locked = false; memset(&s->cfg, 0, sizeof(s->cfg)); - s->cfg.width = s->starting_width; - s->cfg.height = s->starting_height; } -RAMFBState *ramfb_setup(DeviceState* dev, Error **errp) +RAMFBState *ramfb_setup(Error **errp) { FWCfgState *fw_cfg = fw_cfg_find(); RAMFBState *s; @@ -133,16 +129,6 @@ RAMFBState *ramfb_setup(DeviceState* dev, Error **errp) s = g_new0(RAMFBState, 1); - const char *s_fb_width = qemu_opt_get(dev->opts, "xres"); - const char *s_fb_height = qemu_opt_get(dev->opts, "yres"); - if (s_fb_width) { - s->cfg.width = atoi(s_fb_width); - s->starting_width = s->cfg.width; - } - if (s_fb_height) { - s->cfg.height = atoi(s_fb_height); - s->starting_height = s->cfg.height; - } s->locked = false; rom_add_vga("vgabios-ramfb.bin"); diff --git a/hw/vfio/display.c b/hw/vfio/display.c index f4977c66e1..a57a22674d 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -353,7 +353,7 @@ static int vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp) &vfio_display_dmabuf_ops, vdev); if (vdev->enable_ramfb) { - vdev->dpy->ramfb = ramfb_setup(DEVICE(vdev), errp); + vdev->dpy->ramfb = ramfb_setup(errp); } vfio_display_edid_init(vdev); return 0; @@ -479,7 +479,7 @@ static int vfio_display_region_init(VFIOPCIDevice *vdev, Error **errp) &vfio_display_region_ops, vdev); if (vdev->enable_ramfb) { - vdev->dpy->ramfb = ramfb_setup(DEVICE(vdev), errp); + vdev->dpy->ramfb = ramfb_setup(errp); } return 0; } diff --git a/include/hw/display/ramfb.h b/include/hw/display/ramfb.h index f6c2de93b2..b33a2c467b 100644 --- a/include/hw/display/ramfb.h +++ b/include/hw/display/ramfb.h @@ -4,7 +4,7 @@ /* ramfb.c */ typedef struct RAMFBState RAMFBState; void ramfb_display_update(QemuConsole *con, RAMFBState *s); -RAMFBState *ramfb_setup(DeviceState *dev, Error **errp); +RAMFBState *ramfb_setup(Error **errp); /* ramfb-standalone.c */ #define TYPE_RAMFB_DEVICE "ramfb" diff --git a/stubs/ramfb.c b/stubs/ramfb.c index 0799093a5d..48143f3354 100644 --- a/stubs/ramfb.c +++ b/stubs/ramfb.c @@ -6,7 +6,7 @@ void ramfb_display_update(QemuConsole *con, RAMFBState *s) { } -RAMFBState *ramfb_setup(DeviceState* dev, Error **errp) +RAMFBState *ramfb_setup(Error **errp) { error_setg(errp, "ramfb support not available"); return NULL; From c326eedc7584b94f6f9f3b8ba61a6e9ff04ad681 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 13:52:32 +0200 Subject: [PATCH 0514/2595] Revert "hw/display/ramfb: lock guest resolution after it's set" This reverts commit a9e0cb67b7f4c485755659f9b764c38b5f970de4. This breaks OVMF. Reproducer: Just hit 'ESC' at early boot to enter firmware setup. OVMF wants switch from (default) 800x600 to 640x480 for that, and this patch blocks it. Cc: Hou Qiming Signed-off-by: Gerd Hoffmann Reviewed-by: Laszlo Ersek Message-id: 20200429115236.28709-3-kraxel@redhat.com --- hw/display/ramfb.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c index bd4746dc17..9d41c2ad28 100644 --- a/hw/display/ramfb.c +++ b/hw/display/ramfb.c @@ -31,7 +31,6 @@ struct RAMFBState { DisplaySurface *ds; uint32_t width, height; struct RAMFBCfg cfg; - bool locked; }; static void ramfb_unmap_display_surface(pixman_image_t *image, void *unused) @@ -72,25 +71,18 @@ static DisplaySurface *ramfb_create_display_surface(int width, int height, static void ramfb_fw_cfg_write(void *dev, off_t offset, size_t len) { RAMFBState *s = dev; - uint32_t fourcc, format, width, height; + uint32_t fourcc, format; hwaddr stride, addr; - width = be32_to_cpu(s->cfg.width); - height = be32_to_cpu(s->cfg.height); + s->width = be32_to_cpu(s->cfg.width); + s->height = be32_to_cpu(s->cfg.height); stride = be32_to_cpu(s->cfg.stride); fourcc = be32_to_cpu(s->cfg.fourcc); addr = be64_to_cpu(s->cfg.addr); format = qemu_drm_format_to_pixman(fourcc); fprintf(stderr, "%s: %dx%d @ 0x%" PRIx64 "\n", __func__, - width, height, addr); - if (s->locked) { - fprintf(stderr, "%s: resolution locked, change rejected\n", __func__); - return; - } - s->locked = true; - s->width = width; - s->height = height; + s->width, s->height, addr); s->ds = ramfb_create_display_surface(s->width, s->height, format, stride, addr); } @@ -110,13 +102,6 @@ void ramfb_display_update(QemuConsole *con, RAMFBState *s) dpy_gfx_update_full(con); } -static void ramfb_reset(void *opaque) -{ - RAMFBState *s = (RAMFBState *)opaque; - s->locked = false; - memset(&s->cfg, 0, sizeof(s->cfg)); -} - RAMFBState *ramfb_setup(Error **errp) { FWCfgState *fw_cfg = fw_cfg_find(); @@ -129,12 +114,9 @@ RAMFBState *ramfb_setup(Error **errp) s = g_new0(RAMFBState, 1); - s->locked = false; - rom_add_vga("vgabios-ramfb.bin"); fw_cfg_add_file_callback(fw_cfg, "etc/ramfb", NULL, ramfb_fw_cfg_write, s, &s->cfg, sizeof(s->cfg), false); - qemu_register_reset(ramfb_reset, s); return s; } From 46a298d60271f03d4f85031827426fca67af2a20 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 13:52:33 +0200 Subject: [PATCH 0515/2595] ramfb: drop leftover debug message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laszlo Ersek Message-id: 20200429115236.28709-4-kraxel@redhat.com --- hw/display/ramfb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c index 9d41c2ad28..228defee56 100644 --- a/hw/display/ramfb.c +++ b/hw/display/ramfb.c @@ -81,8 +81,6 @@ static void ramfb_fw_cfg_write(void *dev, off_t offset, size_t len) addr = be64_to_cpu(s->cfg.addr); format = qemu_drm_format_to_pixman(fourcc); - fprintf(stderr, "%s: %dx%d @ 0x%" PRIx64 "\n", __func__, - s->width, s->height, addr); s->ds = ramfb_create_display_surface(s->width, s->height, format, stride, addr); } From 19aaee2a65a26693fe0a30b5a0746f967774e278 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 13:52:34 +0200 Subject: [PATCH 0516/2595] ramfb: don't update RAMFBState on errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store width & height & surface in local variables. Update RAMFBState with the new values only in case the ramfb_create_display_surface() call succeeds. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laszlo Ersek Message-id: 20200429115236.28709-5-kraxel@redhat.com --- hw/display/ramfb.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c index 228defee56..1a20bdec41 100644 --- a/hw/display/ramfb.c +++ b/hw/display/ramfb.c @@ -71,18 +71,26 @@ static DisplaySurface *ramfb_create_display_surface(int width, int height, static void ramfb_fw_cfg_write(void *dev, off_t offset, size_t len) { RAMFBState *s = dev; - uint32_t fourcc, format; + DisplaySurface *surface; + uint32_t fourcc, format, width, height; hwaddr stride, addr; - s->width = be32_to_cpu(s->cfg.width); - s->height = be32_to_cpu(s->cfg.height); - stride = be32_to_cpu(s->cfg.stride); - fourcc = be32_to_cpu(s->cfg.fourcc); - addr = be64_to_cpu(s->cfg.addr); - format = qemu_drm_format_to_pixman(fourcc); + width = be32_to_cpu(s->cfg.width); + height = be32_to_cpu(s->cfg.height); + stride = be32_to_cpu(s->cfg.stride); + fourcc = be32_to_cpu(s->cfg.fourcc); + addr = be64_to_cpu(s->cfg.addr); + format = qemu_drm_format_to_pixman(fourcc); - s->ds = ramfb_create_display_surface(s->width, s->height, - format, stride, addr); + surface = ramfb_create_display_surface(width, height, + format, stride, addr); + if (!surface) { + return; + } + + s->width = width; + s->height = height; + s->ds = surface; } void ramfb_display_update(QemuConsole *con, RAMFBState *s) From 819c83e27895472befbfee67d3d7d089c61d7fbd Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 13:52:35 +0200 Subject: [PATCH 0517/2595] ramfb: add sanity checks to ramfb_create_display_surface Signed-off-by: Gerd Hoffmann Reviewed-by: Laszlo Ersek Message-id: 20200429115236.28709-6-kraxel@redhat.com --- hw/display/ramfb.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c index 1a20bdec41..52dae78db4 100644 --- a/hw/display/ramfb.c +++ b/hw/display/ramfb.c @@ -15,6 +15,7 @@ #include "qapi/error.h" #include "hw/loader.h" #include "hw/display/ramfb.h" +#include "hw/display/bochs-vbe.h" /* for limits */ #include "ui/console.h" #include "sysemu/reset.h" @@ -49,6 +50,11 @@ static DisplaySurface *ramfb_create_display_surface(int width, int height, hwaddr size; void *data; + if (width < 16 || width > VBE_DISPI_MAX_XRES || + height < 16 || height > VBE_DISPI_MAX_YRES || + format == 0 /* unknown format */) + return NULL; + if (linesize == 0) { linesize = width * PIXMAN_FORMAT_BPP(format) / 8; } From 3fcf15df0073a76d37e2816597771d4c9763e413 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 29 Apr 2020 13:52:36 +0200 Subject: [PATCH 0518/2595] ramfb: fix size calculation size calculation isn't correct with guest-supplied stride, the last display line isn't accounted for correctly. For the typical case of stride > linesize (add padding) we error on the safe side (calculated size is larger than actual size). With stride < linesize (scanlines overlap) the calculated size is smaller than the actual size though so our guest memory mapping might end up being too small. While being at it also fix ramfb_create_display_surface to use hwaddr for the parameters. That way all calculation are done with hwaddr type and we can't get funny effects from type castings. Signed-off-by: Gerd Hoffmann Acked-by: Laszlo Ersek Message-id: 20200429115236.28709-7-kraxel@redhat.com --- hw/display/ramfb.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c index 52dae78db4..79b9754a58 100644 --- a/hw/display/ramfb.c +++ b/hw/display/ramfb.c @@ -44,10 +44,10 @@ static void ramfb_unmap_display_surface(pixman_image_t *image, void *unused) static DisplaySurface *ramfb_create_display_surface(int width, int height, pixman_format_code_t format, - int linesize, uint64_t addr) + hwaddr stride, hwaddr addr) { DisplaySurface *surface; - hwaddr size; + hwaddr size, mapsize, linesize; void *data; if (width < 16 || width > VBE_DISPI_MAX_XRES || @@ -55,19 +55,20 @@ static DisplaySurface *ramfb_create_display_surface(int width, int height, format == 0 /* unknown format */) return NULL; - if (linesize == 0) { - linesize = width * PIXMAN_FORMAT_BPP(format) / 8; + linesize = width * PIXMAN_FORMAT_BPP(format) / 8; + if (stride == 0) { + stride = linesize; } - size = (hwaddr)linesize * height; - data = cpu_physical_memory_map(addr, &size, false); - if (size != (hwaddr)linesize * height) { - cpu_physical_memory_unmap(data, size, 0, 0); + mapsize = size = stride * (height - 1) + linesize; + data = cpu_physical_memory_map(addr, &mapsize, false); + if (size != mapsize) { + cpu_physical_memory_unmap(data, mapsize, 0, 0); return NULL; } surface = qemu_create_displaysurface_from(width, height, - format, linesize, data); + format, stride, data); pixman_image_set_destroy_function(surface->image, ramfb_unmap_display_surface, NULL); From 0eaf453ebf6788885fbb5d40426b154ef8805407 Mon Sep 17 00:00:00 2001 From: Raphael Pour Date: Fri, 15 May 2020 08:36:07 +0200 Subject: [PATCH 0519/2595] qemu-nbd: Close inherited stderr Close inherited stderr of the parent if fork_process is false. Otherwise no one will close it. (introduced by e6df58a5) This only affected 'qemu-nbd -c /dev/nbd0'. Signed-off-by: Raphael Pour Message-Id: Reviewed-by: Eric Blake [eblake: Enhance commit message] Signed-off-by: Eric Blake --- qemu-nbd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qemu-nbd.c b/qemu-nbd.c index 4aa005004e..306e44fb0a 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -916,7 +916,11 @@ int main(int argc, char **argv) } else if (pid == 0) { close(stderr_fd[0]); - old_stderr = dup(STDERR_FILENO); + /* Remember parent's stderr if we will be restoring it. */ + if (fork_process) { + old_stderr = dup(STDERR_FILENO); + } + ret = qemu_daemon(1, 0); /* Temporarily redirect stderr to the parent's pipe... */ From 43d589b074370ebc9b340340b5f641b385da9df8 Mon Sep 17 00:00:00 2001 From: Eyal Moscovici Date: Wed, 13 May 2020 16:36:26 +0300 Subject: [PATCH 0520/2595] qemu_img: add cvtnum_full to print error reports All calls to cvtnum check the return value and print the same error message more or less. And so error reporting moved to cvtnum_full to reduce code duplication and provide a single error message. Additionally, cvtnum now wraps cvtnum_full with the existing default range of 0 to MAX_INT64. Acked-by: Mark Kanda Signed-off-by: Eyal Moscovici Message-Id: <20200513133629.18508-2-eyal.moscovici@oracle.com> Reviewed-by: Eric Blake [eblake: fix printf formatting, avoid trailing space, change error wording, reformat commit message] Signed-off-by: Eric Blake --- qemu-img.c | 74 +++++++++++++++++--------------------- tests/qemu-iotests/049.out | 8 ++--- 2 files changed, 37 insertions(+), 45 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 6a4327aaba..5d824fc15f 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -470,19 +470,31 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts, return 0; } -static int64_t cvtnum(const char *s) +static int64_t cvtnum_full(const char *name, const char *value, int64_t min, + int64_t max) { int err; - uint64_t value; + uint64_t res; - err = qemu_strtosz(s, NULL, &value); - if (err < 0) { + err = qemu_strtosz(value, NULL, &res); + if (err < 0 && err != -ERANGE) { + error_report("Invalid %s specified. You may use " + "k, M, G, T, P or E suffixes for", name); + error_report("kilobytes, megabytes, gigabytes, terabytes, " + "petabytes and exabytes."); return err; } - if (value > INT64_MAX) { + if (err == -ERANGE || res > max || res < min) { + error_report("Invalid %s specified. Must be between %" PRId64 + " and %" PRId64 ".", name, min, max); return -ERANGE; } - return value; + return res; +} + +static int64_t cvtnum(const char *name, const char *value) +{ + return cvtnum_full(name, value, 0, INT64_MAX); } static int img_create(int argc, char **argv) @@ -572,16 +584,8 @@ static int img_create(int argc, char **argv) if (optind < argc) { int64_t sval; - sval = cvtnum(argv[optind++]); + sval = cvtnum("image size", argv[optind++]); if (sval < 0) { - if (sval == -ERANGE) { - error_report("Image size must be less than 8 EiB!"); - } else { - error_report("Invalid image size specified! You may use k, M, " - "G, T, P or E suffixes for "); - error_report("kilobytes, megabytes, gigabytes, terabytes, " - "petabytes and exabytes."); - } goto fail; } img_size = (uint64_t)sval; @@ -2187,8 +2191,10 @@ static int img_convert(int argc, char **argv) { int64_t sval; - sval = cvtnum(optarg); - if (sval < 0 || !QEMU_IS_ALIGNED(sval, BDRV_SECTOR_SIZE) || + sval = cvtnum("buffer size for sparse output", optarg); + if (sval < 0) { + goto fail_getopt; + } else if (!QEMU_IS_ALIGNED(sval, BDRV_SECTOR_SIZE) || sval / BDRV_SECTOR_SIZE > MAX_BUF_SECTORS) { error_report("Invalid buffer size for sparse output specified. " "Valid sizes are multiples of %llu up to %llu. Select " @@ -4291,9 +4297,8 @@ static int img_bench(int argc, char **argv) break; case 'o': { - offset = cvtnum(optarg); + offset = cvtnum("offset", optarg); if (offset < 0) { - error_report("Invalid offset specified"); return 1; } break; @@ -4306,9 +4311,8 @@ static int img_bench(int argc, char **argv) { int64_t sval; - sval = cvtnum(optarg); - if (sval < 0 || sval > INT_MAX) { - error_report("Invalid buffer size specified"); + sval = cvtnum_full("buffer size", optarg, 0, INT_MAX); + if (sval < 0) { return 1; } @@ -4319,9 +4323,8 @@ static int img_bench(int argc, char **argv) { int64_t sval; - sval = cvtnum(optarg); - if (sval < 0 || sval > INT_MAX) { - error_report("Invalid step size specified"); + sval = cvtnum_full("step_size", optarg, 0, INT_MAX); + if (sval < 0) { return 1; } @@ -4491,10 +4494,9 @@ static int img_dd_bs(const char *arg, { int64_t res; - res = cvtnum(arg); + res = cvtnum_full("bs", arg, 1, INT_MAX); - if (res <= 0 || res > INT_MAX) { - error_report("invalid number: '%s'", arg); + if (res < 0) { return 1; } in->bsz = out->bsz = res; @@ -4506,10 +4508,9 @@ static int img_dd_count(const char *arg, struct DdIo *in, struct DdIo *out, struct DdInfo *dd) { - dd->count = cvtnum(arg); + dd->count = cvtnum("count", arg); if (dd->count < 0) { - error_report("invalid number: '%s'", arg); return 1; } @@ -4538,10 +4539,9 @@ static int img_dd_skip(const char *arg, struct DdIo *in, struct DdIo *out, struct DdInfo *dd) { - in->offset = cvtnum(arg); + in->offset = cvtnum("skip", arg); if (in->offset < 0) { - error_report("invalid number: '%s'", arg); return 1; } @@ -4923,16 +4923,8 @@ static int img_measure(int argc, char **argv) { int64_t sval; - sval = cvtnum(optarg); + sval = cvtnum("image size", optarg); if (sval < 0) { - if (sval == -ERANGE) { - error_report("Image size must be less than 8 EiB!"); - } else { - error_report("Invalid image size specified! You may use " - "k, M, G, T, P or E suffixes for "); - error_report("kilobytes, megabytes, gigabytes, terabytes, " - "petabytes and exabytes."); - } goto out; } img_size = (uint64_t)sval; diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out index a5cfba1756..c54ae21b86 100644 --- a/tests/qemu-iotests/049.out +++ b/tests/qemu-iotests/049.out @@ -92,19 +92,19 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 l == 3. Invalid sizes == qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1024 -qemu-img: Image size must be less than 8 EiB! +qemu-img: Invalid image size specified. Must be between 0 and 9223372036854775807. qemu-img create -f qcow2 -o size=-1024 TEST_DIR/t.qcow2 qemu-img: TEST_DIR/t.qcow2: Value '-1024' is out of range for parameter 'size' qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1k -qemu-img: Image size must be less than 8 EiB! +qemu-img: Invalid image size specified. Must be between 0 and 9223372036854775807. qemu-img create -f qcow2 -o size=-1k TEST_DIR/t.qcow2 qemu-img: TEST_DIR/t.qcow2: Value '-1k' is out of range for parameter 'size' qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte -qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for +qemu-img: Invalid image size specified. You may use k, M, G, T, P or E suffixes for qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes. qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2 @@ -113,7 +113,7 @@ Optional suffix k, M, G, T, P or E means kilo-, mega-, giga-, tera-, peta- and exabytes, respectively. qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar -qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for +qemu-img: Invalid image size specified. You may use k, M, G, T, P or E suffixes for qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes. qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2 From 8f282e83edd3d1b4ea6e9258f5a4081b490c33cc Mon Sep 17 00:00:00 2001 From: Eyal Moscovici Date: Wed, 13 May 2020 16:36:27 +0300 Subject: [PATCH 0521/2595] qemu-img: validate image length in img_map The code handles this case correctly: we merely skip the loop. However it is probably best to return an explicit error. Reviewed-by: Eric Blake Acked-by: Mark Kanda Signed-off-by: Eyal Moscovici Message-Id: <20200513133629.18508-3-eyal.moscovici@oracle.com> [eblake: commit message tweak] Signed-off-by: Eric Blake --- qemu-img.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qemu-img.c b/qemu-img.c index 5d824fc15f..c88f412333 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -3092,6 +3092,11 @@ static int img_map(int argc, char **argv) } length = blk_getlength(blk); + if (length < 0) { + error_report("Failed to get size for '%s'", filename); + return 1; + } + while (curr.start + curr.length < length) { int64_t offset = curr.start + curr.length; int64_t n; From e46c0b18cfd02195a0d527ca73f3ed9f3ce5eacb Mon Sep 17 00:00:00 2001 From: Eyal Moscovici Date: Wed, 13 May 2020 16:36:28 +0300 Subject: [PATCH 0522/2595] qemu-img: refactor dump_map_entry JSON format output Previously dump_map_entry identified whether we need to start a new JSON array based on whether start address == 0. In this refactor we remove this assumption as in following patches we will allow map to start from an arbitrary position. Reviewed-by: Eric Blake Acked-by: Mark Kanda Signed-off-by: Eyal Moscovici Message-Id: <20200513133629.18508-4-eyal.moscovici@oracle.com> Signed-off-by: Eric Blake --- qemu-img.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index c88f412333..4aa9414aba 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2902,9 +2902,8 @@ static int dump_map_entry(OutputFormat output_format, MapEntry *e, } break; case OFORMAT_JSON: - printf("%s{ \"start\": %"PRId64", \"length\": %"PRId64"," + printf("{ \"start\": %"PRId64", \"length\": %"PRId64"," " \"depth\": %"PRId64", \"zero\": %s, \"data\": %s", - (e->start == 0 ? "[" : ",\n"), e->start, e->length, e->depth, e->zero ? "true" : "false", e->data ? "true" : "false"); @@ -2913,8 +2912,8 @@ static int dump_map_entry(OutputFormat output_format, MapEntry *e, } putchar('}'); - if (!next) { - printf("]\n"); + if (next) { + puts(","); } break; } @@ -3089,6 +3088,8 @@ static int img_map(int argc, char **argv) if (output_format == OFORMAT_HUMAN) { printf("%-16s%-16s%-16s%s\n", "Offset", "Length", "Mapped to", "File"); + } else if (output_format == OFORMAT_JSON) { + putchar('['); } length = blk_getlength(blk); @@ -3125,6 +3126,9 @@ static int img_map(int argc, char **argv) } ret = dump_map_entry(output_format, &curr, NULL); + if (output_format == OFORMAT_JSON) { + puts("]"); + } out: blk_unref(blk); From c0469496b32910a6a092d5b614efbf4088b13a29 Mon Sep 17 00:00:00 2001 From: Eyal Moscovici Date: Wed, 13 May 2020 16:36:29 +0300 Subject: [PATCH 0523/2595] qemu-img: Add --start-offset and --max-length to map The mapping operation of large disks especially ones stored over a long chain of QCOW2 files can take a long time to finish. Additionally when mapping fails there was no way recover by restarting the mapping from the failed location. The new options, --start-offset and --max-length allows the user to divide these type of map operations into shorter independent tasks. Reviewed-by: Eric Blake Acked-by: Mark Kanda Co-developed-by: Yoav Elnekave Signed-off-by: Yoav Elnekave Signed-off-by: Eyal Moscovici Message-Id: <20200513133629.18508-5-eyal.moscovici@oracle.com> Signed-off-by: Eric Blake --- docs/tools/qemu-img.rst | 2 +- qemu-img-cmds.hx | 4 ++-- qemu-img.c | 22 +++++++++++++++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index 0080f83a76..f4ffe528ea 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -519,7 +519,7 @@ Command description: ``ImageInfoSpecific*`` QAPI object (e.g. ``ImageInfoSpecificQCow2`` for qcow2 images). -.. option:: map [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [-U] FILENAME +.. option:: map [--object OBJECTDEF] [--image-opts] [-f FMT] [--start-offset=OFFSET] [--max-length=LEN] [--output=OFMT] [-U] FILENAME Dump the metadata of image *FILENAME* and its backing file chain. In particular, this commands dumps the allocation state of every sector diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index c9c54de1df..35f832816f 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -63,9 +63,9 @@ SRST ERST DEF("map", img_map, - "map [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [-U] filename") + "map [--object objectdef] [--image-opts] [-f fmt] [--start-offset=offset] [--max-length=len] [--output=ofmt] [-U] filename") SRST -.. option:: map [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [-U] FILENAME +.. option:: map [--object OBJECTDEF] [--image-opts] [-f FMT] [--start-offset=OFFSET] [--max-length=LEN] [--output=OFMT] [-U] FILENAME ERST DEF("measure", img_measure, diff --git a/qemu-img.c b/qemu-img.c index 4aa9414aba..947bf8b34b 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -3009,6 +3009,8 @@ static int img_map(int argc, char **argv) int ret = 0; bool image_opts = false; bool force_share = false; + int64_t start_offset = 0; + int64_t max_length = -1; fmt = NULL; output = NULL; @@ -3021,9 +3023,11 @@ static int img_map(int argc, char **argv) {"object", required_argument, 0, OPTION_OBJECT}, {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {"force-share", no_argument, 0, 'U'}, + {"start-offset", required_argument, 0, 's'}, + {"max-length", required_argument, 0, 'l'}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, ":f:hU", + c = getopt_long(argc, argv, ":f:s:l:hU", long_options, &option_index); if (c == -1) { break; @@ -3047,6 +3051,18 @@ static int img_map(int argc, char **argv) case OPTION_OUTPUT: output = optarg; break; + case 's': + start_offset = cvtnum("start offset", optarg); + if (start_offset < 0) { + return 1; + } + break; + case 'l': + max_length = cvtnum("max length", optarg); + if (max_length < 0) { + return 1; + } + break; case OPTION_OBJECT: { QemuOpts *opts; opts = qemu_opts_parse_noisily(&qemu_object_opts, @@ -3097,7 +3113,11 @@ static int img_map(int argc, char **argv) error_report("Failed to get size for '%s'", filename); return 1; } + if (max_length != -1) { + length = MIN(start_offset + max_length, length); + } + curr.start = start_offset; while (curr.start + curr.length < length) { int64_t offset = curr.start + curr.length; int64_t n; From d8154b0945f795177511ea0e2212bd5c749fe84c Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 13 May 2020 12:58:34 -0500 Subject: [PATCH 0524/2595] iotests: Enhance 223 to cover qemu-img map improvements Since qemu-img map + x-dirty-bitmap remains the easiest way to read persistent bitmaps at the moment, it makes a reasonable place to add coverage to ensure we do not regress on the just-added parameters to qemu-img map. Signed-off-by: Eric Blake Message-Id: <20200513181455.295267-1-eblake@redhat.com> --- tests/qemu-iotests/223 | 6 ++++-- tests/qemu-iotests/223.out | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 index 56fbc5fb09..d68bc3cb6f 100755 --- a/tests/qemu-iotests/223 +++ b/tests/qemu-iotests/223 @@ -2,7 +2,7 @@ # # Test reading dirty bitmap over NBD # -# Copyright (C) 2018-2019 Red Hat, Inc. +# Copyright (C) 2018-2020 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 @@ -206,7 +206,9 @@ $QEMU_IMG map --output=json --image-opts \ nbd_server_start_unix_socket -f $IMGFMT -B b2 "$TEST_IMG" IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket" -$QEMU_IMG map --output=json --image-opts \ +$QEMU_IMG map --output=json --image-opts --max-length=12345 \ + "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map +$QEMU_IMG map --output=json --image-opts --start-offset=12345 \ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map # success, all done diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index 80c0cf6509..e1eaaedb55 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -201,6 +201,7 @@ read 2097152/2097152 bytes at offset 2097152 { "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] [{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, { "start": 512, "length": 512, "depth": 0, "zero": false, "data": false}, -{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 1024, "length": 11321, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 12345, "length": 2084807, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, { "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] *** done From ffa41a62d0b0e6d91f2071328befa046d56993e1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 11 May 2020 15:58:22 +0200 Subject: [PATCH 0525/2595] iotests/109: Don't mirror with mismatched size This patch makes the raw image the same size as the file in a different format that is mirrored as raw to it to avoid errors when mirror starts to enforce that source and target are the same size. We check only that the first 512 bytes are zeroed (instead of 64k) because some image formats create image files that are smaller than 64k, so trying to read 64k would result in I/O errors. Apart from this, 512 is more appropriate anyway because the raw format driver protects specifically the first 512 bytes. Signed-off-by: Kevin Wolf Message-Id: <20200511135825.219437-2-kwolf@redhat.com> Reviewed-by: Max Reitz Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- tests/qemu-iotests/109 | 10 ++--- tests/qemu-iotests/109.out | 74 +++++++++++++------------------- tests/qemu-iotests/common.filter | 5 +++ 3 files changed, 41 insertions(+), 48 deletions(-) diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109 index 5bc2e9b001..3ffeaf3c55 100755 --- a/tests/qemu-iotests/109 +++ b/tests/qemu-iotests/109 @@ -77,14 +77,14 @@ for fmt in qcow qcow2 qed vdi vmdk vpc; do echo "=== Writing a $fmt header into raw ===" echo - _make_test_img 64M TEST_IMG="$TEST_IMG.src" IMGFMT=$fmt _make_test_img 64M + _make_test_img $(du -b "$TEST_IMG.src" | cut -f1) | _filter_img_create_size # This first test should fail: The image format was probed, we may not # write an image header at the start of the image run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" | _filter_block_job_len - $QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io + $QEMU_IO -c 'read -P 0 0 512' "$TEST_IMG" | _filter_qemu_io # When raw was explicitly specified, the same must succeed @@ -103,12 +103,12 @@ for sample_img in empty.bochs iotest-dirtylog-10G-4M.vhdx parallels-v1 \ # Can't use _use_sample_img because that isn't designed to be used multiple # times and it overwrites $TEST_IMG (both breaks cleanup) - _make_test_img 64M bzcat "$SAMPLE_IMG_DIR/$sample_img.bz2" > "$TEST_IMG.src" + _make_test_img $(du -b "$TEST_IMG.src" | cut -f1) | _filter_img_create_size run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" | _filter_block_job_offset | _filter_block_job_len - $QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io + $QEMU_IO -c 'read -P 0 0 512' "$TEST_IMG" | _filter_qemu_io run_qemu "$TEST_IMG" "$TEST_IMG.src" "'format': 'raw'," "BLOCK_JOB_READY" $QEMU_IMG compare -f raw -F raw "$TEST_IMG" "$TEST_IMG.src" @@ -119,8 +119,8 @@ echo "=== Write legitimate MBR into raw ===" echo for sample_img in grub_mbr.raw; do - _make_test_img 64M bzcat "$SAMPLE_IMG_DIR/$sample_img.bz2" > "$TEST_IMG.src" + _make_test_img $(du -b "$TEST_IMG.src" | cut -f1) | _filter_img_create_size run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_READY" $QEMU_IMG compare -f raw -F raw "$TEST_IMG" "$TEST_IMG.src" diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out index 884f65f18d..ad739df46c 100644 --- a/tests/qemu-iotests/109.out +++ b/tests/qemu-iotests/109.out @@ -2,8 +2,8 @@ QA output created by 109 === Writing a qcow header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -23,8 +23,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed {"execute":"quit"} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} -read 65536/65536 bytes at offset 0 -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -43,13 +43,12 @@ read 65536/65536 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. === Writing a qcow2 header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -69,8 +68,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed {"execute":"quit"} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} -read 65536/65536 bytes at offset 0 -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -89,13 +88,12 @@ read 65536/65536 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. === Writing a qed header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -115,8 +113,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed {"execute":"quit"} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} -read 65536/65536 bytes at offset 0 -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -135,13 +133,12 @@ read 65536/65536 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. === Writing a vdi header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -161,8 +158,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed {"execute":"quit"} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} -read 65536/65536 bytes at offset 0 -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -181,13 +178,12 @@ read 65536/65536 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. === Writing a vmdk header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -207,8 +203,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed {"execute":"quit"} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} -read 65536/65536 bytes at offset 0 -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -227,13 +223,12 @@ read 65536/65536 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. === Writing a vpc header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -253,8 +248,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed {"execute":"quit"} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} -read 65536/65536 bytes at offset 0 -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -273,12 +268,11 @@ read 65536/65536 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. === Copying sample image empty.bochs into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -298,8 +292,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed {"execute":"quit"} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} -read 65536/65536 bytes at offset 0 -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -318,12 +312,11 @@ read 65536/65536 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. === Copying sample image iotest-dirtylog-10G-4M.vhdx into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -343,8 +336,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed {"execute":"quit"} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} -read 65536/65536 bytes at offset 0 -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -363,12 +356,11 @@ read 65536/65536 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. === Copying sample image parallels-v1 into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -388,8 +380,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed {"execute":"quit"} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} -read 65536/65536 bytes at offset 0 -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -408,12 +400,11 @@ read 65536/65536 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. === Copying sample image simple-pattern.cloop into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -433,8 +424,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed {"execute":"quit"} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} -read 65536/65536 bytes at offset 0 -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -453,12 +444,11 @@ read 65536/65536 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. === Write legitimate MBR into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE { 'execute': 'qmp_capabilities' } {"return": {}} {'execute':'drive-mirror', 'arguments':{ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', 'mode': 'existing', 'sync': 'full'}} @@ -480,7 +470,6 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. { 'execute': 'qmp_capabilities' } {"return": {}} @@ -500,6 +489,5 @@ Images are identical. {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} -Warning: Image size mismatch! Images are identical. *** done diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 279e0bbb0d..03e4f71808 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -156,6 +156,11 @@ _filter_img_create() -e "s# compression_type=[a-zA-Z0-9]\\+##g" } +_filter_img_create_size() +{ + $SED -e "s# size=[0-9]\\+# size=SIZE#g" +} + _filter_img_info() { if [[ "$1" == "--format-specific" ]]; then From d89ac3cf305b28c024a76805a84d75c0ee1e786f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 11 May 2020 15:58:23 +0200 Subject: [PATCH 0526/2595] iotests/229: Use blkdebug to inject an error 229 relies on the mirror running into an I/O error when the target is smaller than the source. After changing mirror to catch this condition while starting the job, this test case won't get a job that is paused for an I/O error any more. Use blkdebug instead to inject an error. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Message-Id: <20200511135825.219437-3-kwolf@redhat.com> Reviewed-by: Max Reitz Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- tests/qemu-iotests/229 | 18 +++++++++++++----- tests/qemu-iotests/229.out | 6 +++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229 index 866168b236..99acb55ebb 100755 --- a/tests/qemu-iotests/229 +++ b/tests/qemu-iotests/229 @@ -33,6 +33,7 @@ _cleanup() _cleanup_test_img _rm_test_img "$TEST_IMG" _rm_test_img "$DEST_IMG" + rm -f "$TEST_DIR/blkdebug.conf" } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -49,11 +50,10 @@ _supported_os Linux DEST_IMG="$TEST_DIR/d.$IMGFMT" TEST_IMG="$TEST_DIR/b.$IMGFMT" +BLKDEBUG_CONF="$TEST_DIR/blkdebug.conf" _make_test_img 2M - -# destination for mirror will be too small, causing error -TEST_IMG=$DEST_IMG _make_test_img 1M +TEST_IMG=$DEST_IMG _make_test_img 2M $QEMU_IO -c 'write 0 2M' "$TEST_IMG" | _filter_qemu_io @@ -67,11 +67,18 @@ echo echo '=== Starting drive-mirror, causing error & stop ===' echo +cat > "$BLKDEBUG_CONF" < Date: Mon, 11 May 2020 15:58:24 +0200 Subject: [PATCH 0527/2595] mirror: Make sure that source and target size match If the target is shorter than the source, mirror would copy data until it reaches the end of the target and then fail with an I/O error when trying to write past the end. If the target is longer than the source, the mirror job would complete successfully, but the target wouldn't actually be an accurate copy of the source image (it would contain some additional garbage at the end). Fix this by checking that both images have the same size when the job starts. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Message-Id: <20200511135825.219437-4-kwolf@redhat.com> Reviewed-by: Max Reitz Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- block/mirror.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index aca95c9bc9..201ffa26f9 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -872,6 +872,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) BlockDriverState *target_bs = blk_bs(s->target); bool need_drain = true; int64_t length; + int64_t target_length; BlockDriverInfo bdi; char backing_filename[2]; /* we only need 2 characters because we are only checking for a NULL string */ @@ -887,24 +888,26 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) goto immediate_exit; } + target_length = blk_getlength(s->target); + if (target_length < 0) { + ret = target_length; + goto immediate_exit; + } + /* Active commit must resize the base image if its size differs from the * active layer. */ if (s->base == blk_bs(s->target)) { - int64_t base_length; - - base_length = blk_getlength(s->target); - if (base_length < 0) { - ret = base_length; - goto immediate_exit; - } - - if (s->bdev_length > base_length) { + if (s->bdev_length > target_length) { ret = blk_truncate(s->target, s->bdev_length, false, PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) { goto immediate_exit; } } + } else if (s->bdev_length != target_length) { + error_setg(errp, "Source and target image have different sizes"); + ret = -EINVAL; + goto immediate_exit; } if (s->bdev_length == 0) { From 16cea4ee1c8e5a69a058e76f426b2e17974d8d7d Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 11 May 2020 15:58:25 +0200 Subject: [PATCH 0528/2595] iotests: Mirror with different source/target size This tests that the mirror job catches situations where the target node has a different size than the source node. It must also forbid resize operations when the job is already running. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Message-Id: <20200511135825.219437-5-kwolf@redhat.com> Reviewed-by: Max Reitz Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- tests/qemu-iotests/041 | 45 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/041.out | 4 ++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 1812dd8479..601c756117 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -240,6 +240,49 @@ class TestSingleBlockdev(TestSingleDrive): target=self.qmp_target) self.assert_qmp(result, 'error/class', 'GenericError') + def do_test_resize(self, device, node): + def pre_finalize(): + if device: + result = self.vm.qmp('block_resize', device=device, size=65536) + self.assert_qmp(result, 'error/class', 'GenericError') + + result = self.vm.qmp('block_resize', node_name=node, size=65536) + self.assert_qmp(result, 'error/class', 'GenericError') + + result = self.vm.qmp(self.qmp_cmd, job_id='job0', device='drive0', + sync='full', target=self.qmp_target, + auto_finalize=False, auto_dismiss=False) + self.assert_qmp(result, 'return', {}) + + result = self.vm.run_job('job0', auto_finalize=False, + pre_finalize=pre_finalize) + self.assertEqual(result, None) + + def test_source_resize(self): + self.do_test_resize('drive0', 'top') + + def test_target_resize(self): + self.do_test_resize(None, self.qmp_target) + + def do_test_target_size(self, size): + result = self.vm.qmp('block_resize', node_name=self.qmp_target, + size=size) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp(self.qmp_cmd, job_id='job0', + device='drive0', sync='full', auto_dismiss=False, + target=self.qmp_target) + self.assert_qmp(result, 'return', {}) + + result = self.vm.run_job('job0') + self.assertEqual(result, 'Source and target image have different sizes') + + def test_small_target(self): + self.do_test_target_size(self.image_len // 2) + + def test_large_target(self): + self.do_test_target_size(self.image_len * 2) + test_large_cluster = None test_image_not_found = None test_small_buffer2 = None @@ -251,6 +294,8 @@ class TestSingleDriveZeroLength(TestSingleDrive): class TestSingleBlockdevZeroLength(TestSingleBlockdev): image_len = 0 + test_small_target = None + test_large_target = None class TestSingleDriveUnalignedLength(TestSingleDrive): image_len = 1025 * 1024 diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out index 877b76fd31..53abe11d73 100644 --- a/tests/qemu-iotests/041.out +++ b/tests/qemu-iotests/041.out @@ -1,5 +1,5 @@ -.............................................................................................. +........................................................................................................ ---------------------------------------------------------------------- -Ran 94 tests +Ran 104 tests OK From e140f4b7b8c0fdda866ba3d8b4aa184b6ba6d6b8 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Mon, 11 May 2020 09:08:01 +0200 Subject: [PATCH 0529/2595] block/replication.c: Avoid cancelling the job twice If qemu in colo secondary mode is stopped, it crashes because s->backup_job is canceled twice: First with job_cancel_sync_all() in qemu_cleanup() and then in replication_stop(). Fix this by assigning NULL to s->backup_job when the job completes so replication_stop() and replication_do_checkpoint() won't touch the job. Signed-off-by: Lukas Straub Message-Id: <20200511090801.7ed5d8f3@luklap> Signed-off-by: Kevin Wolf --- block/replication.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/block/replication.c b/block/replication.c index 971f0fe266..c03980a192 100644 --- a/block/replication.c +++ b/block/replication.c @@ -398,6 +398,8 @@ static void backup_job_cleanup(BlockDriverState *bs) BDRVReplicationState *s = bs->opaque; BlockDriverState *top_bs; + s->backup_job = NULL; + top_bs = bdrv_lookup_bs(s->top_id, s->top_id, NULL); if (!top_bs) { return; From cd8f5b75927afdd8ac2378f4360208e0aa8f58e2 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 11 May 2020 18:35:28 +0200 Subject: [PATCH 0530/2595] iotests: Fix incomplete type declarations We need to fix only a few places so that iotests.py can pass mypy --disallow-incomplete-defs, which seems to be a desirable option to have enabled in the long run. Signed-off-by: Kevin Wolf Message-Id: <20200511163529.349329-2-kwolf@redhat.com> Reviewed-by: Max Reitz Reviewed-by: John Snow Signed-off-by: Kevin Wolf --- tests/qemu-iotests/iotests.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 6c0e781af7..1d7f6fd7cf 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -1040,7 +1040,7 @@ def _verify_cache_mode(supported_cache_modes: Sequence[str] = ()) -> None: if supported_cache_modes and (cachemode not in supported_cache_modes): notrun('not suitable for this cache mode: %s' % cachemode) -def _verify_aio_mode(supported_aio_modes: Sequence[str] = ()): +def _verify_aio_mode(supported_aio_modes: Sequence[str] = ()) -> None: if supported_aio_modes and (aiomode not in supported_aio_modes): notrun('not suitable for this aio mode: %s' % aiomode) @@ -1087,7 +1087,8 @@ def skip_if_unsupported(required_formats=(), read_only=False): '''Skip Test Decorator Runs the test if all the required formats are whitelisted''' def skip_test_decorator(func): - def func_wrapper(test_case: QMPTestCase, *args, **kwargs): + def func_wrapper(test_case: QMPTestCase, *args: List[Any], + **kwargs: Dict[str, Any]) -> None: if callable(required_formats): fmts = required_formats(test_case) else: @@ -1097,9 +1098,8 @@ def skip_if_unsupported(required_formats=(), read_only=False): if usf_list: msg = f'{test_case}: formats {usf_list} are not whitelisted' test_case.case_skip(msg) - return None else: - return func(test_case, *args, **kwargs) + func(test_case, *args, **kwargs) return func_wrapper return skip_test_decorator From 19b7868eff865c01985a5d37f1c9c0c8691b0001 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 11 May 2020 18:35:29 +0200 Subject: [PATCH 0531/2595] iotests: Run pylint and mypy in a testcase We made sure that iotests.py passes pylint. It would be a shame if we allowed new patches in that break this again, so let's just add a meta-test case that runs pylint on it. While we don't pass mypy --strict yet, we can already run it with a few options that would be part of --strict to make sure that we won't regress on these aspects at least until we can enable the full thing. Signed-off-by: Kevin Wolf Message-Id: <20200511163529.349329-3-kwolf@redhat.com> Reviewed-by: Max Reitz Reviewed-by: John Snow Signed-off-by: Kevin Wolf --- tests/qemu-iotests/297 | 44 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/297.out | 3 +++ tests/qemu-iotests/group | 1 + 3 files changed, 48 insertions(+) create mode 100755 tests/qemu-iotests/297 create mode 100644 tests/qemu-iotests/297.out diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297 new file mode 100755 index 0000000000..5c5420712b --- /dev/null +++ b/tests/qemu-iotests/297 @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2020 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 . + +seq=$(basename $0) +echo "QA output created by $seq" + +status=1 # failure is the default! + +# get standard environment +. ./common.rc + +if ! type -p "pylint-3" > /dev/null; then + _notrun "pylint-3 not found" +fi +if ! type -p "mypy" > /dev/null; then + _notrun "mypy not found" +fi + +pylint-3 --score=n iotests.py + +MYPYPATH=../../python/ mypy --warn-unused-configs --disallow-subclassing-any \ + --disallow-any-generics --disallow-incomplete-defs \ + --disallow-untyped-decorators --no-implicit-optional \ + --warn-redundant-casts --warn-unused-ignores \ + --no-implicit-reexport iotests.py + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/297.out b/tests/qemu-iotests/297.out new file mode 100644 index 0000000000..6acc843649 --- /dev/null +++ b/tests/qemu-iotests/297.out @@ -0,0 +1,3 @@ +QA output created by 297 +Success: no issues found in 1 source file +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 34175fd437..445c26f8d2 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -300,3 +300,4 @@ 289 rw quick 290 rw auto quick 292 rw auto quick +297 meta From 6f7a3b535f0d48d138e43cadf13323f083bfb547 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 29 Apr 2020 16:11:23 +0200 Subject: [PATCH 0532/2595] block: Add bdrv_make_empty() Right now, all users of bdrv_make_empty() call the BlockDriver method directly. That is not only bad style, it is also wrong, unless the caller has a BdrvChild with a WRITE or WRITE_UNCHANGED permission. (WRITE_UNCHANGED suffices, because callers generally use this function to clear a node with a backing file after a commit operation.) Introduce bdrv_make_empty() that verifies that it does. Signed-off-by: Max Reitz Message-Id: <20200429141126.85159-2-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 23 +++++++++++++++++++++++ include/block/block.h | 1 + 2 files changed, 24 insertions(+) diff --git a/block.c b/block.c index 0653ccb913..c6a5c144b7 100644 --- a/block.c +++ b/block.c @@ -6764,3 +6764,26 @@ void bdrv_del_child(BlockDriverState *parent_bs, BdrvChild *child, Error **errp) parent_bs->drv->bdrv_del_child(parent_bs, child, errp); } + +int bdrv_make_empty(BdrvChild *c, Error **errp) +{ + BlockDriver *drv = c->bs->drv; + int ret; + + assert(c->perm & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)); + + if (!drv->bdrv_make_empty) { + error_setg(errp, "%s does not support emptying nodes", + drv->format_name); + return -ENOTSUP; + } + + ret = drv->bdrv_make_empty(c->bs); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to empty %s", + c->bs->filename); + return ret; + } + + return 0; +} diff --git a/include/block/block.h b/include/block/block.h index 4de8d8f8a6..8f3eb70df4 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -352,6 +352,7 @@ BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); void bdrv_refresh_limits(BlockDriverState *bs, Error **errp); int bdrv_commit(BlockDriverState *bs); +int bdrv_make_empty(BdrvChild *c, Error **errp); int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, const char *backing_fmt); void bdrv_register(BlockDriver *bdrv); From 2b7bbdbdefe203cf8468c61b4217e578981d6fce Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 29 Apr 2020 16:11:25 +0200 Subject: [PATCH 0533/2595] block: Add blk_make_empty() Two callers of BlockDriver.bdrv_make_empty() remain that should not call this method directly. Both do not have access to a BdrvChild, but they can use a BlockBackend, so we add this function that lets them use it. Signed-off-by: Max Reitz Message-Id: <20200429141126.85159-4-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/block-backend.c | 10 ++++++++++ include/sysemu/block-backend.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/block/block-backend.c b/block/block-backend.c index f4944861fa..47bd56244d 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2402,3 +2402,13 @@ const BdrvChild *blk_root(BlockBackend *blk) { return blk->root; } + +int blk_make_empty(BlockBackend *blk, Error **errp) +{ + if (!blk_is_available(blk)) { + error_setg(errp, "No medium inserted"); + return -ENOMEDIUM; + } + + return bdrv_make_empty(blk->root, errp); +} diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 0917663d89..8203d7f6f9 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -266,4 +266,6 @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, const BdrvChild *blk_root(BlockBackend *blk); +int blk_make_empty(BlockBackend *blk, Error **errp); + #endif From 2d97fde43991829f74e1e258bb82031605bf9bca Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 29 Apr 2020 16:11:26 +0200 Subject: [PATCH 0534/2595] block: Use blk_make_empty() after commits bdrv_commit() already has a BlockBackend pointing to the BDS that we want to empty, it just has the wrong permissions. qemu-img commit has no BlockBackend pointing to the old backing file yet, but introducing one is simple. After this commit, bdrv_make_empty() is the only remaining caller of BlockDriver.bdrv_make_empty(). Signed-off-by: Max Reitz Message-Id: <20200429141126.85159-5-mreitz@redhat.com> Reviewed-by: Eric Blake [kwolf: Fixed up reference output for 098] Signed-off-by: Kevin Wolf --- block/commit.c | 16 +++++++++------- qemu-img.c | 19 ++++++++++++++----- tests/qemu-iotests/098.out | 8 ++++---- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/block/commit.c b/block/commit.c index 87f6096d90..ba60fb7955 100644 --- a/block/commit.c +++ b/block/commit.c @@ -414,7 +414,9 @@ int bdrv_commit(BlockDriverState *bs) } ctx = bdrv_get_aio_context(bs); - src = blk_new(ctx, BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL); + /* WRITE_UNCHANGED is required for bdrv_make_empty() */ + src = blk_new(ctx, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED, + BLK_PERM_ALL); backing = blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); ret = blk_insert_bs(src, bs, &local_err); @@ -492,14 +494,14 @@ int bdrv_commit(BlockDriverState *bs) } } - if (drv->bdrv_make_empty) { - ret = drv->bdrv_make_empty(bs); - if (ret < 0) { - goto ro_cleanup; - } - blk_flush(src); + ret = blk_make_empty(src, NULL); + /* Ignore -ENOTSUP */ + if (ret < 0 && ret != -ENOTSUP) { + goto ro_cleanup; } + blk_flush(src); + /* * Make sure all data we wrote to the backing device is actually * stable on disk. diff --git a/qemu-img.c b/qemu-img.c index 6a4327aaba..f1795c788c 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1104,11 +1104,20 @@ static int img_commit(int argc, char **argv) goto unref_backing; } - if (!drop && bs->drv->bdrv_make_empty) { - ret = bs->drv->bdrv_make_empty(bs); - if (ret) { - error_setg_errno(&local_err, -ret, "Could not empty %s", - filename); + if (!drop) { + BlockBackend *old_backing_blk; + + old_backing_blk = blk_new_with_bs(bs, BLK_PERM_WRITE, BLK_PERM_ALL, + &local_err); + if (!old_backing_blk) { + goto unref_backing; + } + ret = blk_make_empty(old_backing_blk, &local_err); + blk_unref(old_backing_blk); + if (ret == -ENOTSUP) { + error_free(local_err); + local_err = NULL; + } else if (ret < 0) { goto unref_backing; } } diff --git a/tests/qemu-iotests/098.out b/tests/qemu-iotests/098.out index 7634d0e8b0..23cf371f53 100644 --- a/tests/qemu-iotests/098.out +++ b/tests/qemu-iotests/098.out @@ -6,7 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error +qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error No errors were found on the image. === empty_image_prepare === @@ -15,7 +15,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error +qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error Leaked cluster 4 refcount=1 reference=0 Leaked cluster 5 refcount=1 reference=0 Repairing cluster 4 refcount=1 reference=0 @@ -28,7 +28,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error +qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error ERROR cluster 0 refcount=0 reference=1 ERROR cluster 1 refcount=0 reference=1 ERROR cluster 3 refcount=0 reference=1 @@ -42,7 +42,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error +qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error ERROR cluster 0 refcount=0 reference=1 ERROR cluster 1 refcount=0 reference=1 ERROR cluster 3 refcount=0 reference=1 From 6ecbc6c52672db5c13805735ca02784879ce8285 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 15 May 2020 13:25:44 +0200 Subject: [PATCH 0535/2595] replication: Avoid blk_make_empty() on read-only child This is just a bandaid to keep tests/test-replication working after bdrv_make_empty() starts to assert that we're not trying to call it on a read-only child. For the real solution in the future, replication should not steal the BdrvChild from its backing file (this is never correct to do!), but instead have its own child node references, with the appropriate permissions. Signed-off-by: Kevin Wolf --- block/replication.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/block/replication.c b/block/replication.c index c03980a192..eb480a8e08 100644 --- a/block/replication.c +++ b/block/replication.c @@ -343,9 +343,18 @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp) return; } - ret = s->hidden_disk->bs->drv->bdrv_make_empty(s->hidden_disk->bs); + BlockBackend *blk = blk_new(qemu_get_current_aio_context(), + BLK_PERM_WRITE, BLK_PERM_ALL); + blk_insert_bs(blk, s->hidden_disk->bs, &local_err); + if (local_err) { + error_propagate(errp, local_err); + blk_unref(blk); + return; + } + + ret = blk_make_empty(blk, errp); + blk_unref(blk); if (ret < 0) { - error_setg(errp, "Cannot make hidden disk empty"); return; } } From f844ec01b36797e0e5f31f56bfbe49f8c24cc7d4 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 29 Apr 2020 16:11:24 +0200 Subject: [PATCH 0536/2595] block: Use bdrv_make_empty() where possible Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Kevin Wolf Message-Id: <20200429141126.85159-3-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block/replication.c | 3 +-- block/vvfat.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/block/replication.c b/block/replication.c index eb480a8e08..9a9f36e524 100644 --- a/block/replication.c +++ b/block/replication.c @@ -331,9 +331,8 @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp) return; } - ret = s->active_disk->bs->drv->bdrv_make_empty(s->active_disk->bs); + ret = bdrv_make_empty(s->active_disk, errp); if (ret < 0) { - error_setg(errp, "Cannot make active disk empty"); return; } diff --git a/block/vvfat.c b/block/vvfat.c index 6d5c090dec..34c121c07a 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2960,9 +2960,7 @@ static int do_commit(BDRVVVFATState* s) return ret; } - if (s->qcow->bs->drv && s->qcow->bs->drv->bdrv_make_empty) { - s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs); - } + bdrv_make_empty(s->qcow, NULL); memset(s->used_clusters, 0, sector2cluster(s, s->sector_count)); From 6540fd153ca9d4cff31b1cc3f5ced271eca9296c Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:11 +0200 Subject: [PATCH 0537/2595] block: Mark commit, mirror, blkreplay as filters The commit, mirror, and blkreplay block nodes are filters, so they should be marked as such. Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-2-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block/blkreplay.c | 1 + block/commit.c | 2 ++ block/mirror.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/block/blkreplay.c b/block/blkreplay.c index c96ac8f4bc..131c9e8477 100644 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -135,6 +135,7 @@ static int blkreplay_snapshot_goto(BlockDriverState *bs, static BlockDriver bdrv_blkreplay = { .format_name = "blkreplay", .instance_size = 0, + .is_filter = true, .bdrv_open = blkreplay_open, .bdrv_child_perm = bdrv_filter_default_perms, diff --git a/block/commit.c b/block/commit.c index ba60fb7955..b0a8a793cd 100644 --- a/block/commit.c +++ b/block/commit.c @@ -240,6 +240,8 @@ static BlockDriver bdrv_commit_top = { .bdrv_co_block_status = bdrv_co_block_status_from_backing, .bdrv_refresh_filename = bdrv_commit_top_refresh_filename, .bdrv_child_perm = bdrv_commit_top_child_perm, + + .is_filter = true, }; void commit_start(const char *job_id, BlockDriverState *bs, diff --git a/block/mirror.c b/block/mirror.c index 201ffa26f9..55e992670a 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1530,6 +1530,8 @@ static BlockDriver bdrv_mirror_top = { .bdrv_co_block_status = bdrv_co_block_status_from_backing, .bdrv_refresh_filename = bdrv_mirror_top_refresh_filename, .bdrv_child_perm = bdrv_mirror_top_child_perm, + + .is_filter = true, }; static BlockJob *mirror_start_job( From d67066d8bc01a14f7c9d9b9aeeffb30a10f0e900 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:12 +0200 Subject: [PATCH 0538/2595] block: Add BlockDriver.is_format We want to unify child_format and child_file at some point. One of the important things that set format drivers apart from other drivers is that they do not expect other format nodes under them (except in the backing chain), i.e. we must not probe formats inside of formats. That means we need something on which to distinguish format drivers from others, and hence this flag. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Alberto Garcia Message-Id: <20200513110544.176672-3-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block/bochs.c | 1 + block/cloop.c | 1 + block/crypto.c | 2 ++ block/dmg.c | 1 + block/parallels.c | 1 + block/qcow.c | 1 + block/qcow2.c | 1 + block/qed.c | 1 + block/raw-format.c | 1 + block/vdi.c | 1 + block/vhdx.c | 1 + block/vmdk.c | 1 + block/vpc.c | 1 + include/block/block_int.h | 7 +++++++ 14 files changed, 21 insertions(+) diff --git a/block/bochs.c b/block/bochs.c index 32bb83b268..e7bbeaa1c4 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -301,6 +301,7 @@ static BlockDriver bdrv_bochs = { .bdrv_refresh_limits = bochs_refresh_limits, .bdrv_co_preadv = bochs_co_preadv, .bdrv_close = bochs_close, + .is_format = true, }; static void bdrv_bochs_init(void) diff --git a/block/cloop.c b/block/cloop.c index 4de94876d4..f90f1a4b4c 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -297,6 +297,7 @@ static BlockDriver bdrv_cloop = { .bdrv_refresh_limits = cloop_refresh_limits, .bdrv_co_preadv = cloop_co_preadv, .bdrv_close = cloop_close, + .is_format = true, }; static void bdrv_cloop_init(void) diff --git a/block/crypto.c b/block/crypto.c index 6b21d6bf6c..bdb2b27475 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -771,6 +771,8 @@ static BlockDriver bdrv_crypto_luks = { .bdrv_get_info = block_crypto_get_info_luks, .bdrv_get_specific_info = block_crypto_get_specific_info_luks, + .is_format = true, + .strong_runtime_opts = block_crypto_strong_runtime_opts, }; diff --git a/block/dmg.c b/block/dmg.c index 4a045f2b3e..ef3c6e771d 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -753,6 +753,7 @@ static BlockDriver bdrv_dmg = { .bdrv_child_perm = bdrv_format_default_perms, .bdrv_co_preadv = dmg_co_preadv, .bdrv_close = dmg_close, + .is_format = true, }; static void bdrv_dmg_init(void) diff --git a/block/parallels.c b/block/parallels.c index e7717c508e..bd5f6ffa09 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -918,6 +918,7 @@ static BlockDriver bdrv_parallels = { .bdrv_co_flush_to_os = parallels_co_flush_to_os, .bdrv_co_readv = parallels_co_readv, .bdrv_co_writev = parallels_co_writev, + .is_format = true, .supports_backing = true, .bdrv_co_create = parallels_co_create, .bdrv_co_create_opts = parallels_co_create_opts, diff --git a/block/qcow.c b/block/qcow.c index b0475b73a5..6a72dea049 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -1185,6 +1185,7 @@ static BlockDriver bdrv_qcow = { .bdrv_co_create = qcow_co_create, .bdrv_co_create_opts = qcow_co_create_opts, .bdrv_has_zero_init = bdrv_has_zero_init_1, + .is_format = true, .supports_backing = true, .bdrv_refresh_limits = qcow_refresh_limits, diff --git a/block/qcow2.c b/block/qcow2.c index ad9ab4fafa..76bec61ee9 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5767,6 +5767,7 @@ BlockDriver bdrv_qcow2 = { .bdrv_save_vmstate = qcow2_save_vmstate, .bdrv_load_vmstate = qcow2_load_vmstate, + .is_format = true, .supports_backing = true, .bdrv_change_backing_file = qcow2_change_backing_file, diff --git a/block/qed.c b/block/qed.c index 5da9726518..337eb6dbb6 100644 --- a/block/qed.c +++ b/block/qed.c @@ -1665,6 +1665,7 @@ static BlockDriver bdrv_qed = { .format_name = "qed", .instance_size = sizeof(BDRVQEDState), .create_opts = &qed_create_opts, + .is_format = true, .supports_backing = true, .bdrv_probe = bdrv_qed_probe, diff --git a/block/raw-format.c b/block/raw-format.c index 9108e43696..00e13bb41e 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -566,6 +566,7 @@ BlockDriver bdrv_raw = { .bdrv_co_copy_range_to = &raw_co_copy_range_to, .bdrv_co_truncate = &raw_co_truncate, .bdrv_getlength = &raw_getlength, + .is_format = true, .has_variable_length = true, .bdrv_measure = &raw_measure, .bdrv_get_info = &raw_get_info, diff --git a/block/vdi.c b/block/vdi.c index 2d28046615..0ef733ae19 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -1053,6 +1053,7 @@ static BlockDriver bdrv_vdi = { .bdrv_get_info = vdi_get_info, + .is_format = true, .create_opts = &vdi_create_opts, .bdrv_co_check = vdi_co_check, }; diff --git a/block/vhdx.c b/block/vhdx.c index 53e756438a..e692cf80cc 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -2254,6 +2254,7 @@ static BlockDriver bdrv_vhdx = { .bdrv_co_check = vhdx_co_check, .bdrv_has_zero_init = vhdx_has_zero_init, + .is_format = true, .create_opts = &vhdx_create_opts, }; diff --git a/block/vmdk.c b/block/vmdk.c index b18f128816..56e85689f3 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -3070,6 +3070,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_get_info = vmdk_get_info, .bdrv_gather_child_options = vmdk_gather_child_options, + .is_format = true, .supports_backing = true, .create_opts = &vmdk_create_opts, }; diff --git a/block/vpc.c b/block/vpc.c index 5e31dd1e47..46a2d48659 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -1250,6 +1250,7 @@ static BlockDriver bdrv_vpc = { .bdrv_get_info = vpc_get_info, + .is_format = true, .create_opts = &vpc_create_opts, .bdrv_has_zero_init = vpc_has_zero_init, .strong_runtime_opts = vpc_strong_runtime_opts, diff --git a/include/block/block_int.h b/include/block/block_int.h index 7ba8c89036..1c24df53fd 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -95,6 +95,13 @@ struct BlockDriver { * must implement them and return -ENOTSUP. */ bool is_filter; + /* + * Set to true if the BlockDriver is a format driver. Format nodes + * generally do not expect their children to be other format nodes + * (except for backing files), and so format probing is disabled + * on those children. + */ + bool is_format; /* * Return true if @to_replace can be replaced by a BDS with the * same data as @bs without it affecting @bs's behavior (that is, From bd86fb990cfedc50d9705b8ed31d183f01942035 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:13 +0200 Subject: [PATCH 0539/2595] block: Rename BdrvChildRole to BdrvChildClass This structure nearly only contains parent callbacks for child state changes. It cannot really reflect a child's role, because different roles may overlap (as we will see when real roles are introduced), and because parents can have custom callbacks even when the child fulfills a standard role. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Alberto Garcia Message-Id: <20200513110544.176672-4-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 142 ++++++++++++++++++------------------ block/backup-top.c | 8 +- block/blkdebug.c | 4 +- block/blklogwrites.c | 8 +- block/block-backend.c | 6 +- block/commit.c | 2 +- block/copy-on-read.c | 2 +- block/io.c | 22 +++--- block/mirror.c | 2 +- block/quorum.c | 2 +- block/replication.c | 2 +- block/vvfat.c | 6 +- blockjob.c | 2 +- include/block/block.h | 6 +- include/block/block_int.h | 22 +++--- tests/test-bdrv-drain.c | 36 ++++----- tests/test-bdrv-graph-mod.c | 2 +- 17 files changed, 141 insertions(+), 133 deletions(-) diff --git a/block.c b/block.c index c6a5c144b7..0ce9b61c97 100644 --- a/block.c +++ b/block.c @@ -76,7 +76,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, const char *reference, QDict *options, int flags, BlockDriverState *parent, - const BdrvChildRole *child_role, + const BdrvChildClass *child_class, Error **errp); /* If non-zero, use only whitelisted block drivers */ @@ -1183,7 +1183,7 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options, *child_flags = flags; } -const BdrvChildRole child_file = { +const BdrvChildClass child_file = { .parent_is_bds = true, .get_parent_desc = bdrv_child_get_parent_desc, .inherit_options = bdrv_inherited_options, @@ -1211,7 +1211,7 @@ static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options, *child_flags &= ~(BDRV_O_PROTOCOL | BDRV_O_NO_IO); } -const BdrvChildRole child_format = { +const BdrvChildClass child_format = { .parent_is_bds = true, .get_parent_desc = bdrv_child_get_parent_desc, .inherit_options = bdrv_inherited_fmt_options, @@ -1335,7 +1335,7 @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, return ret; } -const BdrvChildRole child_backing = { +const BdrvChildClass child_backing = { .parent_is_bds = true, .get_parent_desc = bdrv_child_get_parent_desc, .attach = bdrv_backing_attach, @@ -1953,13 +1953,13 @@ bool bdrv_is_writable(BlockDriverState *bs) } static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, - BdrvChild *c, const BdrvChildRole *role, + BdrvChild *c, const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t parent_perm, uint64_t parent_shared, uint64_t *nperm, uint64_t *nshared) { assert(bs->drv && bs->drv->bdrv_child_perm); - bs->drv->bdrv_child_perm(bs, c, role, reopen_queue, + bs->drv->bdrv_child_perm(bs, c, child_class, reopen_queue, parent_perm, parent_shared, nperm, nshared); /* TODO Take force_share from reopen_queue */ @@ -2053,7 +2053,7 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, uint64_t cur_perm, cur_shared; bool child_tighten_restr; - bdrv_child_perm(bs, c->bs, c, c->role, q, + bdrv_child_perm(bs, c->bs, c, c->klass, q, cumulative_perms, cumulative_shared_perms, &cur_perm, &cur_shared); ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, ignore_children, @@ -2120,7 +2120,7 @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms, /* Update all children */ QLIST_FOREACH(c, &bs->children, next) { uint64_t cur_perm, cur_shared; - bdrv_child_perm(bs, c->bs, c, c->role, NULL, + bdrv_child_perm(bs, c->bs, c, c->klass, NULL, cumulative_perms, cumulative_shared_perms, &cur_perm, &cur_shared); bdrv_child_set_perm(c, cur_perm, cur_shared); @@ -2145,8 +2145,8 @@ void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, static char *bdrv_child_user_desc(BdrvChild *c) { - if (c->role->get_parent_desc) { - return c->role->get_parent_desc(c); + if (c->klass->get_parent_desc) { + return c->klass->get_parent_desc(c); } return g_strdup("another user"); @@ -2348,14 +2348,14 @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) uint64_t perms, shared; bdrv_get_cumulative_perm(bs, &parent_perms, &parent_shared); - bdrv_child_perm(bs, c->bs, c, c->role, NULL, parent_perms, parent_shared, + bdrv_child_perm(bs, c->bs, c, c->klass, NULL, parent_perms, parent_shared, &perms, &shared); return bdrv_child_try_set_perm(c, perms, shared, errp); } void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) @@ -2365,21 +2365,21 @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, } void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { - bool backing = (role == &child_backing); - assert(role == &child_backing || role == &child_file); + bool backing = (child_class == &child_backing); + assert(child_class == &child_backing || child_class == &child_file); if (!backing) { int flags = bdrv_reopen_get_flags(reopen_queue, bs); /* Apart from the modifications below, the same permissions are * forwarded and left alone as for filters */ - bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, - &perm, &shared); + bdrv_filter_default_perms(bs, c, child_class, reopen_queue, + perm, shared, &perm, &shared); /* Format drivers may touch metadata even if the guest doesn't write */ if (bdrv_is_writable_after_reopen(bs, reopen_queue)) { @@ -2456,7 +2456,7 @@ static void bdrv_replace_child_noperm(BdrvChild *child, * If the new child node is drained but the old one was not, flush * all outstanding requests to the old child node. */ - while (drain_saldo > 0 && child->role->drained_begin) { + while (drain_saldo > 0 && child->klass->drained_begin) { bdrv_parent_drained_begin_single(child, true); drain_saldo--; } @@ -2465,8 +2465,8 @@ static void bdrv_replace_child_noperm(BdrvChild *child, /* Detach first so that the recursive drain sections coming from @child * are already gone and we only end the drain sections that came from * elsewhere. */ - if (child->role->detach) { - child->role->detach(child); + if (child->klass->detach) { + child->klass->detach(child); } QLIST_REMOVE(child, next_parent); } @@ -2488,8 +2488,8 @@ static void bdrv_replace_child_noperm(BdrvChild *child, /* Attach only after starting new drained sections, so that recursive * drain sections coming from @child don't get an extra .drained_begin * callback. */ - if (child->role->attach) { - child->role->attach(child); + if (child->klass->attach) { + child->klass->attach(child); } } @@ -2497,7 +2497,7 @@ static void bdrv_replace_child_noperm(BdrvChild *child, * If the old child node was drained but the new one is not, allow * requests to come in only after the new node has been attached. */ - while (drain_saldo < 0 && child->role->drained_end) { + while (drain_saldo < 0 && child->klass->drained_end) { bdrv_parent_drained_end_single(child); drain_saldo++; } @@ -2570,7 +2570,7 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) */ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, const char *child_name, - const BdrvChildRole *child_role, + const BdrvChildClass *child_class, AioContext *ctx, uint64_t perm, uint64_t shared_perm, void *opaque, Error **errp) @@ -2591,7 +2591,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, *child = (BdrvChild) { .bs = NULL, .name = g_strdup(child_name), - .role = child_role, + .klass = child_class, .perm = perm, .shared_perm = shared_perm, .opaque = opaque, @@ -2602,15 +2602,15 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, * try moving the parent into the AioContext of child_bs instead. */ if (bdrv_get_aio_context(child_bs) != ctx) { ret = bdrv_try_set_aio_context(child_bs, ctx, &local_err); - if (ret < 0 && child_role->can_set_aio_ctx) { + if (ret < 0 && child_class->can_set_aio_ctx) { GSList *ignore = g_slist_prepend(NULL, child); ctx = bdrv_get_aio_context(child_bs); - if (child_role->can_set_aio_ctx(child, ctx, &ignore, NULL)) { + if (child_class->can_set_aio_ctx(child, ctx, &ignore, NULL)) { error_free(local_err); ret = 0; g_slist_free(ignore); ignore = g_slist_prepend(NULL, child); - child_role->set_aio_ctx(child, ctx, &ignore); + child_class->set_aio_ctx(child, ctx, &ignore); } g_slist_free(ignore); } @@ -2643,7 +2643,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, const char *child_name, - const BdrvChildRole *child_role, + const BdrvChildClass *child_class, Error **errp) { BdrvChild *child; @@ -2652,10 +2652,10 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm); assert(parent_bs->drv); - bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL, + bdrv_child_perm(parent_bs, child_bs, NULL, child_class, NULL, perm, shared_perm, &perm, &shared_perm); - child = bdrv_root_attach_child(child_bs, child_name, child_role, + child = bdrv_root_attach_child(child_bs, child_name, child_class, bdrv_get_aio_context(parent_bs), perm, shared_perm, parent_bs, errp); if (child == NULL) { @@ -2728,8 +2728,8 @@ static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load) { BdrvChild *c; QLIST_FOREACH(c, &bs->parents, next_parent) { - if (c->role->change_media) { - c->role->change_media(c, load); + if (c->klass->change_media) { + c->klass->change_media(c, load); } } } @@ -2905,7 +2905,7 @@ free_exit: static BlockDriverState * bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key, - BlockDriverState *parent, const BdrvChildRole *child_role, + BlockDriverState *parent, const BdrvChildClass *child_class, bool allow_none, Error **errp) { BlockDriverState *bs = NULL; @@ -2913,7 +2913,7 @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key, char *bdref_key_dot; const char *reference; - assert(child_role != NULL); + assert(child_class != NULL); bdref_key_dot = g_strdup_printf("%s.", bdref_key); qdict_extract_subqdict(options, &image_options, bdref_key_dot); @@ -2937,7 +2937,7 @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key, } bs = bdrv_open_inherit(filename, reference, image_options, 0, - parent, child_role, errp); + parent, child_class, errp); if (!bs) { goto done; } @@ -2964,22 +2964,24 @@ done: BdrvChild *bdrv_open_child(const char *filename, QDict *options, const char *bdref_key, BlockDriverState *parent, - const BdrvChildRole *child_role, + const BdrvChildClass *child_class, bool allow_none, Error **errp) { BlockDriverState *bs; - bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_role, + bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class, allow_none, errp); if (bs == NULL) { return NULL; } - return bdrv_attach_child(parent, bs, bdref_key, child_role, errp); + return bdrv_attach_child(parent, bs, bdref_key, child_class, errp); } -/* TODO Future callers may need to specify parent/child_role in order for - * option inheritance to work. Existing callers use it for the root node. */ +/* + * TODO Future callers may need to specify parent/child_class in order for + * option inheritance to work. Existing callers use it for the root node. + */ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) { BlockDriverState *bs = NULL; @@ -3107,7 +3109,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, const char *reference, QDict *options, int flags, BlockDriverState *parent, - const BdrvChildRole *child_role, + const BdrvChildClass *child_class, Error **errp) { int ret; @@ -3121,8 +3123,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, QDict *snapshot_options = NULL; int snapshot_flags = 0; - assert(!child_role || !flags); - assert(!child_role == !parent); + assert(!child_class || !flags); + assert(!child_class == !parent); if (reference) { bool options_non_empty = options ? qdict_size(options) : false; @@ -3158,10 +3160,10 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, bs->explicit_options = qdict_clone_shallow(options); - if (child_role) { + if (child_class) { bs->inherits_from = parent; - child_role->inherit_options(&flags, options, - parent->open_flags, parent->options); + child_class->inherit_options(&flags, options, + parent->open_flags, parent->options); } ret = bdrv_fill_options(&options, filename, &flags, &local_err); @@ -3472,7 +3474,7 @@ static bool bdrv_recurse_has_child(BlockDriverState *bs, static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, BlockDriverState *bs, QDict *options, - const BdrvChildRole *role, + const BdrvChildClass *klass, QDict *parent_options, int parent_flags, bool keep_old_opts) @@ -3528,7 +3530,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, /* Inherit from parent node */ if (parent_options) { flags = 0; - role->inherit_options(&flags, options, parent_flags, parent_options); + klass->inherit_options(&flags, options, parent_flags, parent_options); } else { flags = bdrv_get_flags(bs); } @@ -3619,7 +3621,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, } bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options, - child->role, options, flags, child_keep_old); + child->klass, options, flags, child_keep_old); } return bs_queue; @@ -3799,7 +3801,7 @@ static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs, } else { uint64_t nperm, nshared; - bdrv_child_perm(parent->state.bs, bs, c, c->role, q, + bdrv_child_perm(parent->state.bs, bs, c, c->klass, q, parent->state.perm, parent->state.shared_perm, &nperm, &nshared); @@ -4305,7 +4307,7 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to) GHashTable *found; bool ret; - if (c->role->stay_at_node) { + if (c->klass->stay_at_node) { return false; } @@ -4776,9 +4778,9 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, } /* If so, update the backing file path in the image file */ - if (c->role->update_filename) { - ret = c->role->update_filename(c, base, backing_file_str, - &local_err); + if (c->klass->update_filename) { + ret = c->klass->update_filename(c, base, backing_file_str, + &local_err); if (ret < 0) { bdrv_abort_perm_update(base); error_report_err(local_err); @@ -5226,8 +5228,8 @@ const char *bdrv_get_parent_name(const BlockDriverState *bs) /* If multiple parents have a name, just pick the first one. */ QLIST_FOREACH(c, &bs->parents, next_parent) { - if (c->role->get_name) { - name = c->role->get_name(c); + if (c->klass->get_name) { + name = c->klass->get_name(c); if (name && *name) { return name; } @@ -5586,8 +5588,8 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, } QLIST_FOREACH(parent, &bs->parents, next_parent) { - if (parent->role->activate) { - parent->role->activate(parent, &local_err); + if (parent->klass->activate) { + parent->klass->activate(parent, &local_err); if (local_err) { bs->open_flags |= BDRV_O_INACTIVE; error_propagate(errp, local_err); @@ -5655,7 +5657,7 @@ static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active) BdrvChild *parent; QLIST_FOREACH(parent, &bs->parents, next_parent) { - if (parent->role->parent_is_bds) { + if (parent->klass->parent_is_bds) { BlockDriverState *parent_bs = parent->opaque; if (!only_active || !(parent_bs->open_flags & BDRV_O_INACTIVE)) { return true; @@ -5694,8 +5696,8 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs) } QLIST_FOREACH(parent, &bs->parents, next_parent) { - if (parent->role->inactivate) { - ret = parent->role->inactivate(parent); + if (parent->klass->inactivate) { + ret = parent->klass->inactivate(parent); if (ret < 0) { return ret; } @@ -6195,9 +6197,9 @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs, if (g_slist_find(*ignore, child)) { continue; } - assert(child->role->set_aio_ctx); + assert(child->klass->set_aio_ctx); *ignore = g_slist_prepend(*ignore, child); - child->role->set_aio_ctx(child, new_context, ignore); + child->klass->set_aio_ctx(child, new_context, ignore); } bdrv_detach_aio_context(bs); @@ -6237,15 +6239,17 @@ static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx, } *ignore = g_slist_prepend(*ignore, c); - /* A BdrvChildRole that doesn't handle AioContext changes cannot - * tolerate any AioContext changes */ - if (!c->role->can_set_aio_ctx) { + /* + * A BdrvChildClass that doesn't handle AioContext changes cannot + * tolerate any AioContext changes + */ + if (!c->klass->can_set_aio_ctx) { char *user = bdrv_child_user_desc(c); error_setg(errp, "Changing iothreads is not supported by %s", user); g_free(user); return false; } - if (!c->role->can_set_aio_ctx(c, ctx, ignore, errp)) { + if (!c->klass->can_set_aio_ctx(c, ctx, ignore, errp)) { assert(!errp || *errp); return false; } @@ -6631,7 +6635,7 @@ void bdrv_refresh_filename(BlockDriverState *bs) drv->bdrv_gather_child_options(bs, opts, backing_overridden); } else { QLIST_FOREACH(child, &bs->children, next) { - if (child->role == &child_backing && !backing_overridden) { + if (child->klass == &child_backing && !backing_overridden) { /* We can skip the backing BDS if it has not been overridden */ continue; } diff --git a/block/backup-top.c b/block/backup-top.c index 79b268e6dc..282845a410 100644 --- a/block/backup-top.c +++ b/block/backup-top.c @@ -122,7 +122,7 @@ static void backup_top_refresh_filename(BlockDriverState *bs) } static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) @@ -142,7 +142,7 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, return; } - if (role == &child_file) { + if (child_class == &child_file) { /* * Target child * @@ -155,8 +155,8 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, *nperm = BLK_PERM_WRITE; } else { /* Source child */ - bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, - nperm, nshared); + bdrv_filter_default_perms(bs, c, child_class, reopen_queue, + perm, shared, nperm, nshared); if (perm & BLK_PERM_WRITE) { *nperm = *nperm | BLK_PERM_CONSISTENT_READ; diff --git a/block/blkdebug.c b/block/blkdebug.c index af44aa973f..f369d54ee4 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -993,14 +993,14 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, } static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { BDRVBlkdebugState *s = bs->opaque; - bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, + bdrv_filter_default_perms(bs, c, child_class, reopen_queue, perm, shared, nperm, nshared); *nperm |= s->take_child_perms; diff --git a/block/blklogwrites.c b/block/blklogwrites.c index 04d8b33607..f3b3259d8d 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -282,7 +282,7 @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs) } static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *ro_q, uint64_t perm, uint64_t shrd, uint64_t *nperm, uint64_t *nshrd) @@ -294,9 +294,11 @@ static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, } if (!strcmp(c->name, "log")) { - bdrv_format_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd); + bdrv_format_default_perms(bs, c, child_class, ro_q, perm, shrd, nperm, + nshrd); } else { - bdrv_filter_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd); + bdrv_filter_default_perms(bs, c, child_class, ro_q, perm, shrd, nperm, + nshrd); } } diff --git a/block/block-backend.c b/block/block-backend.c index 47bd56244d..c0af79147a 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -297,7 +297,7 @@ static void blk_root_detach(BdrvChild *child) } } -static const BdrvChildRole child_root = { +static const BdrvChildClass child_root = { .inherit_options = blk_root_inherit_options, .change_media = blk_root_change_media, @@ -716,7 +716,7 @@ static BlockBackend *bdrv_first_blk(BlockDriverState *bs) { BdrvChild *child; QLIST_FOREACH(child, &bs->parents, next_parent) { - if (child->role == &child_root) { + if (child->klass == &child_root) { return child->opaque; } } @@ -740,7 +740,7 @@ bool bdrv_is_root_node(BlockDriverState *bs) BdrvChild *c; QLIST_FOREACH(c, &bs->parents, next_parent) { - if (c->role != &child_root) { + if (c->klass != &child_root) { return false; } } diff --git a/block/commit.c b/block/commit.c index b0a8a793cd..834eeae412 100644 --- a/block/commit.c +++ b/block/commit.c @@ -223,7 +223,7 @@ static void bdrv_commit_top_refresh_filename(BlockDriverState *bs) } static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) diff --git a/block/copy-on-read.c b/block/copy-on-read.c index 242d3ff055..7504ca6ffc 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -51,7 +51,7 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, #define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH) static void cor_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) diff --git a/block/io.c b/block/io.c index 7d30e61edc..121ce17a49 100644 --- a/block/io.c +++ b/block/io.c @@ -50,7 +50,7 @@ static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore, BdrvChild *c, *next; QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { - if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) { + if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) { continue; } bdrv_parent_drained_begin_single(c, false); @@ -62,8 +62,8 @@ static void bdrv_parent_drained_end_single_no_poll(BdrvChild *c, { assert(c->parent_quiesce_counter > 0); c->parent_quiesce_counter--; - if (c->role->drained_end) { - c->role->drained_end(c, drained_end_counter); + if (c->klass->drained_end) { + c->klass->drained_end(c, drained_end_counter); } } @@ -81,7 +81,7 @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore, BdrvChild *c; QLIST_FOREACH(c, &bs->parents, next_parent) { - if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) { + if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) { continue; } bdrv_parent_drained_end_single_no_poll(c, drained_end_counter); @@ -90,8 +90,8 @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore, static bool bdrv_parent_drained_poll_single(BdrvChild *c) { - if (c->role->drained_poll) { - return c->role->drained_poll(c); + if (c->klass->drained_poll) { + return c->klass->drained_poll(c); } return false; } @@ -103,7 +103,7 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, bool busy = false; QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { - if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) { + if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) { continue; } busy |= bdrv_parent_drained_poll_single(c); @@ -115,8 +115,8 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll) { c->parent_quiesce_counter++; - if (c->role->drained_begin) { - c->role->drained_begin(c); + if (c->klass->drained_begin) { + c->klass->drained_begin(c); } if (poll) { BDRV_POLL_WHILE(c->bs, bdrv_parent_drained_poll_single(c)); @@ -3326,8 +3326,8 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs) { BdrvChild *c; QLIST_FOREACH(c, &bs->parents, next_parent) { - if (c->role->resize) { - c->role->resize(c); + if (c->klass->resize) { + c->klass->resize(c); } } } diff --git a/block/mirror.c b/block/mirror.c index 55e992670a..d6598463d5 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1492,7 +1492,7 @@ static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs) } static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) diff --git a/block/quorum.c b/block/quorum.c index 6d7a56bd93..a0824c300d 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -1151,7 +1151,7 @@ static char *quorum_dirname(BlockDriverState *bs, Error **errp) } static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) diff --git a/block/replication.c b/block/replication.c index 9a9f36e524..af428c5b66 100644 --- a/block/replication.c +++ b/block/replication.c @@ -163,7 +163,7 @@ static void replication_close(BlockDriverState *bs) } static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) diff --git a/block/vvfat.c b/block/vvfat.c index 34c121c07a..f845d9b485 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3136,7 +3136,7 @@ static void vvfat_qcow_options(int *child_flags, QDict *child_options, qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on"); } -static const BdrvChildRole child_vvfat_qcow = { +static const BdrvChildClass child_vvfat_qcow = { .parent_is_bds = true, .inherit_options = vvfat_qcow_options, }; @@ -3210,14 +3210,14 @@ err: } static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { BDRVVVFATState *s = bs->opaque; - assert(c == s->qcow || role == &child_backing); + assert(c == s->qcow || child_class == &child_backing); if (c == s->qcow) { /* This is a private node, nobody should try to attach to it */ diff --git a/blockjob.c b/blockjob.c index 2affa1844d..be38c8c550 100644 --- a/blockjob.c +++ b/blockjob.c @@ -163,7 +163,7 @@ static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx, job->job.aio_context = ctx; } -static const BdrvChildRole child_job = { +static const BdrvChildClass child_job = { .get_parent_desc = child_job_get_parent_desc, .drained_begin = child_job_drained_begin, .drained_poll = child_job_drained_poll, diff --git a/include/block/block.h b/include/block/block.h index 8f3eb70df4..bc42e507bb 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -13,7 +13,7 @@ /* block.c */ typedef struct BlockDriver BlockDriver; typedef struct BdrvChild BdrvChild; -typedef struct BdrvChildRole BdrvChildRole; +typedef struct BdrvChildClass BdrvChildClass; typedef struct BlockDriverInfo { /* in bytes, 0 if irrelevant */ @@ -296,7 +296,7 @@ int bdrv_parse_discard_flags(const char *mode, int *flags); BdrvChild *bdrv_open_child(const char *filename, QDict *options, const char *bdref_key, BlockDriverState* parent, - const BdrvChildRole *child_role, + const BdrvChildClass *child_class, bool allow_none, Error **errp); BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, @@ -541,7 +541,7 @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, const char *child_name, - const BdrvChildRole *child_role, + const BdrvChildClass *child_class, Error **errp); bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); diff --git a/include/block/block_int.h b/include/block/block_int.h index 1c24df53fd..9a78b981e4 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -556,14 +556,14 @@ struct BlockDriver { * the parents in @parent_perm and @parent_shared. * * If @c is NULL, return the permissions for attaching a new child for the - * given @role. + * given @child_class. * * If @reopen_queue is non-NULL, don't return the currently needed * permissions, but those that will be needed after applying the * @reopen_queue. */ void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t parent_perm, uint64_t parent_shared, uint64_t *nperm, uint64_t *nshared); @@ -665,7 +665,7 @@ typedef struct BdrvAioNotifier { QLIST_ENTRY(BdrvAioNotifier) list; } BdrvAioNotifier; -struct BdrvChildRole { +struct BdrvChildClass { /* If true, bdrv_replace_node() doesn't change the node this BdrvChild * points to. */ bool stay_at_node; @@ -738,14 +738,14 @@ struct BdrvChildRole { void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore); }; -extern const BdrvChildRole child_file; -extern const BdrvChildRole child_format; -extern const BdrvChildRole child_backing; +extern const BdrvChildClass child_file; +extern const BdrvChildClass child_format; +extern const BdrvChildClass child_backing; struct BdrvChild { BlockDriverState *bs; char *name; - const BdrvChildRole *role; + const BdrvChildClass *klass; void *opaque; /** @@ -772,7 +772,7 @@ struct BdrvChild { /* * How many times the parent of this child has been drained - * (through role->drained_*). + * (through klass->drained_*). * Usually, this is equal to bs->quiesce_counter (potentially * reduced by bdrv_drain_all_count). It may differ while the * child is entering or leaving a drained section. @@ -1232,7 +1232,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, const char *child_name, - const BdrvChildRole *child_role, + const BdrvChildClass *child_class, AioContext *ctx, uint64_t perm, uint64_t shared_perm, void *opaque, Error **errp); @@ -1263,7 +1263,7 @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); * block filters: Forward CONSISTENT_READ, WRITE, WRITE_UNCHANGED and RESIZE to * all children */ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared); @@ -1273,7 +1273,7 @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, * requires WRITE | RESIZE for read-write images, always requires * CONSISTENT_READ and doesn't share WRITE. */ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared); diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index fa0e6a648b..9d683a6c11 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -86,18 +86,20 @@ static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, } static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { - /* bdrv_format_default_perms() accepts only these two, so disguise - * detach_by_driver_cb_role as one of them. */ - if (role != &child_file && role != &child_backing) { - role = &child_file; + /* + * bdrv_format_default_perms() accepts only these two, so disguise + * detach_by_driver_cb_parent as one of them. + */ + if (child_class != &child_file && child_class != &child_backing) { + child_class = &child_file; } - bdrv_format_default_perms(bs, c, role, reopen_queue, perm, shared, + bdrv_format_default_perms(bs, c, child_class, reopen_queue, perm, shared, nperm, nshared); } @@ -1332,7 +1334,7 @@ static void detach_by_driver_cb_drained_begin(BdrvChild *child) child_file.drained_begin(child); } -static BdrvChildRole detach_by_driver_cb_role; +static BdrvChildClass detach_by_driver_cb_class; /* * Initial graph: @@ -1349,7 +1351,7 @@ static BdrvChildRole detach_by_driver_cb_role; * * by_parent_cb == false: Test that bdrv_drain_invoke() doesn't poll * - * PA's BdrvChildRole has a .drained_begin callback that schedules a BH + * PA's BdrvChildClass has a .drained_begin callback that schedules a BH * that does the same graph change. If bdrv_drain_invoke() calls it, the * state is messed up, but if it is only polled in the single * BDRV_POLL_WHILE() at the end of the drain, this should work fine. @@ -1364,8 +1366,8 @@ static void test_detach_indirect(bool by_parent_cb) QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0); if (!by_parent_cb) { - detach_by_driver_cb_role = child_file; - detach_by_driver_cb_role.drained_begin = + detach_by_driver_cb_class = child_file; + detach_by_driver_cb_class.drained_begin = detach_by_driver_cb_drained_begin; } @@ -1399,7 +1401,7 @@ static void test_detach_indirect(bool by_parent_cb) bdrv_ref(a); bdrv_attach_child(parent_a, a, "PA-A", - by_parent_cb ? &child_file : &detach_by_driver_cb_role, + by_parent_cb ? &child_file : &detach_by_driver_cb_class, &error_abort); g_assert_cmpint(parent_a->refcnt, ==, 1); @@ -1735,7 +1737,7 @@ static int drop_intermediate_poll_update_filename(BdrvChild *child, /** * Test a poll in the midst of bdrv_drop_intermediate(). * - * bdrv_drop_intermediate() calls BdrvChildRole.update_filename(), + * bdrv_drop_intermediate() calls BdrvChildClass.update_filename(), * which can yield or poll. This may lead to graph changes, unless * the whole subtree in question is drained. * @@ -1772,7 +1774,7 @@ static int drop_intermediate_poll_update_filename(BdrvChild *child, * * The solution is for bdrv_drop_intermediate() to drain top's * subtree. This prevents graph changes from happening just because - * BdrvChildRole.update_filename() yields or polls. Thus, the block + * BdrvChildClass.update_filename() yields or polls. Thus, the block * job is paused during that drained section and must finish before or * after. * @@ -1780,7 +1782,7 @@ static int drop_intermediate_poll_update_filename(BdrvChild *child, */ static void test_drop_intermediate_poll(void) { - static BdrvChildRole chain_child_role; + static BdrvChildClass chain_child_class; BlockDriverState *chain[3]; TestSimpleBlockJob *job; BlockDriverState *job_node; @@ -1788,8 +1790,8 @@ static void test_drop_intermediate_poll(void) int i; int ret; - chain_child_role = child_backing; - chain_child_role.update_filename = drop_intermediate_poll_update_filename; + chain_child_class = child_backing; + chain_child_class.update_filename = drop_intermediate_poll_update_filename; for (i = 0; i < 3; i++) { char name[32]; @@ -1810,7 +1812,7 @@ static void test_drop_intermediate_poll(void) if (i) { /* Takes the reference to chain[i - 1] */ chain[i]->backing = bdrv_attach_child(chain[i], chain[i - 1], - "chain", &chain_child_role, + "chain", &chain_child_class, &error_abort); } } diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c index a007754d9e..fef42cb294 100644 --- a/tests/test-bdrv-graph-mod.c +++ b/tests/test-bdrv-graph-mod.c @@ -30,7 +30,7 @@ static BlockDriver bdrv_pass_through = { }; static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, + const BdrvChildClass *child_class, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) From 3284bcf430a1d42885c184de73df52fcfd86d589 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:14 +0200 Subject: [PATCH 0540/2595] block: Add BdrvChildRole and BdrvChildRoleBits This mask will supplement BdrvChildClass when it comes to what role (or combination of roles) a child takes for its parent. It consists of BdrvChildRoleBits values (which is an enum). Because empty enums are not allowed, let us just start with it filled. Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-5-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- include/block/block.h | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/include/block/block.h b/include/block/block.h index bc42e507bb..35f1a1cecf 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -268,6 +268,62 @@ enum { DEFAULT_PERM_UNCHANGED = BLK_PERM_ALL & ~DEFAULT_PERM_PASSTHROUGH, }; +/* + * Flags that parent nodes assign to child nodes to specify what kind of + * role(s) they take. + * + * At least one of DATA, METADATA, FILTERED, or COW must be set for + * every child. + */ +enum BdrvChildRoleBits { + /* + * This child stores data. + * Any node may have an arbitrary number of such children. + */ + BDRV_CHILD_DATA = (1 << 0), + + /* + * This child stores metadata. + * Any node may have an arbitrary number of metadata-storing + * children. + */ + BDRV_CHILD_METADATA = (1 << 1), + + /* + * A child that always presents exactly the same visible data as + * the parent, e.g. by virtue of the parent forwarding all reads + * and writes. + * This flag is mutually exclusive with DATA, METADATA, and COW. + * Any node may have at most one filtered child at a time. + */ + BDRV_CHILD_FILTERED = (1 << 2), + + /* + * Child from which to read all data that isn’t allocated in the + * parent (i.e., the backing child); such data is copied to the + * parent through COW (and optionally COR). + * This field is mutually exclusive with DATA, METADATA, and + * FILTERED. + * Any node may have at most one such backing child at a time. + */ + BDRV_CHILD_COW = (1 << 3), + + /* + * The primary child. For most drivers, this is the child whose + * filename applies best to the parent node. + * Any node may have at most one primary child at a time. + */ + BDRV_CHILD_PRIMARY = (1 << 4), + + /* Useful combination of flags */ + BDRV_CHILD_IMAGE = BDRV_CHILD_DATA + | BDRV_CHILD_METADATA + | BDRV_CHILD_PRIMARY, +}; + +/* Mask of BdrvChildRoleBits values */ +typedef unsigned int BdrvChildRole; + char *bdrv_perm_names(uint64_t perm); uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm); From 258b776515cc812a26783ffab98b31aa8eb008d4 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:15 +0200 Subject: [PATCH 0541/2595] block: Add BdrvChildRole to BdrvChild For now, it is always set to 0. Later patches in this series will ensure that all callers pass an appropriate combination of flags. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-6-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 11 ++++++++--- block/backup-top.c | 3 ++- block/blkdebug.c | 2 +- block/blklogwrites.c | 6 +++--- block/blkreplay.c | 2 +- block/blkverify.c | 4 ++-- block/block-backend.c | 4 ++-- block/bochs.c | 2 +- block/cloop.c | 2 +- block/copy-on-read.c | 2 +- block/crypto.c | 2 +- block/dmg.c | 2 +- block/filter-compress.c | 2 +- block/parallels.c | 2 +- block/qcow.c | 2 +- block/qcow2.c | 6 +++--- block/qed.c | 2 +- block/quorum.c | 4 ++-- block/raw-format.c | 2 +- block/replication.c | 2 +- block/throttle.c | 2 +- block/vdi.c | 2 +- block/vhdx.c | 2 +- block/vmdk.c | 4 ++-- block/vpc.c | 2 +- block/vvfat.c | 2 +- blockjob.c | 5 +++-- include/block/block.h | 2 ++ include/block/block_int.h | 2 ++ tests/test-bdrv-drain.c | 20 +++++++++++--------- tests/test-bdrv-graph-mod.c | 4 ++-- 31 files changed, 62 insertions(+), 49 deletions(-) diff --git a/block.c b/block.c index 0ce9b61c97..14810e0426 100644 --- a/block.c +++ b/block.c @@ -2571,6 +2571,7 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, const char *child_name, const BdrvChildClass *child_class, + BdrvChildRole child_role, AioContext *ctx, uint64_t perm, uint64_t shared_perm, void *opaque, Error **errp) @@ -2592,6 +2593,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, .bs = NULL, .name = g_strdup(child_name), .klass = child_class, + .role = child_role, .perm = perm, .shared_perm = shared_perm, .opaque = opaque, @@ -2644,6 +2646,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, const char *child_name, const BdrvChildClass *child_class, + BdrvChildRole child_role, Error **errp) { BdrvChild *child; @@ -2656,7 +2659,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, perm, shared_perm, &perm, &shared_perm); child = bdrv_root_attach_child(child_bs, child_name, child_class, - bdrv_get_aio_context(parent_bs), + child_role, bdrv_get_aio_context(parent_bs), perm, shared_perm, parent_bs, errp); if (child == NULL) { return NULL; @@ -2774,7 +2777,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, } bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing, - errp); + 0, errp); /* If backing_hd was already part of bs's backing chain, and * inherits_from pointed recursively to bs then let's update it to * point directly to bs (else it will become NULL). */ @@ -2965,6 +2968,7 @@ BdrvChild *bdrv_open_child(const char *filename, QDict *options, const char *bdref_key, BlockDriverState *parent, const BdrvChildClass *child_class, + BdrvChildRole child_role, bool allow_none, Error **errp) { BlockDriverState *bs; @@ -2975,7 +2979,8 @@ BdrvChild *bdrv_open_child(const char *filename, return NULL; } - return bdrv_attach_child(parent, bs, bdref_key, child_class, errp); + return bdrv_attach_child(parent, bs, bdref_key, child_class, child_role, + errp); } /* diff --git a/block/backup-top.c b/block/backup-top.c index 282845a410..f891dd7838 100644 --- a/block/backup-top.c +++ b/block/backup-top.c @@ -214,7 +214,8 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, source->supported_zero_flags); bdrv_ref(target); - state->target = bdrv_attach_child(top, target, "target", &child_file, errp); + state->target = bdrv_attach_child(top, target, "target", &child_file, 0, + errp); if (!state->target) { bdrv_unref(target); bdrv_unref(top); diff --git a/block/blkdebug.c b/block/blkdebug.c index f369d54ee4..c91e78d5c8 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -497,7 +497,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, /* Open the image file */ bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image", - bs, &child_file, false, &local_err); + bs, &child_file, 0, false, &local_err); if (local_err) { ret = -EINVAL; error_propagate(errp, local_err); diff --git a/block/blklogwrites.c b/block/blklogwrites.c index f3b3259d8d..739db6dcf6 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -157,7 +157,7 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, } /* Open the file */ - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, &local_err); if (local_err) { ret = -EINVAL; @@ -166,8 +166,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, } /* Open the log file */ - s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, false, - &local_err); + s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, 0, + false, &local_err); if (local_err) { ret = -EINVAL; error_propagate(errp, local_err); diff --git a/block/blkreplay.c b/block/blkreplay.c index 131c9e8477..9b2814fc58 100644 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -28,7 +28,7 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags, /* Open the image file */ bs->file = bdrv_open_child(NULL, options, "image", - bs, &child_file, false, &local_err); + bs, &child_file, 0, false, &local_err); if (local_err) { ret = -EINVAL; error_propagate(errp, local_err); diff --git a/block/blkverify.c b/block/blkverify.c index ba6b1853ae..ba4f6d7b7c 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -125,7 +125,7 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, /* Open the raw file */ bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw", - bs, &child_file, false, &local_err); + bs, &child_file, 0, false, &local_err); if (local_err) { ret = -EINVAL; error_propagate(errp, local_err); @@ -134,7 +134,7 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, /* Open the test file */ s->test_file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, - "test", bs, &child_format, false, + "test", bs, &child_format, 0, false, &local_err); if (local_err) { ret = -EINVAL; diff --git a/block/block-backend.c b/block/block-backend.c index c0af79147a..efc7acb3d8 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -423,7 +423,7 @@ BlockBackend *blk_new_open(const char *filename, const char *reference, return NULL; } - blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx, + blk->root = bdrv_root_attach_child(bs, "root", &child_root, 0, blk->ctx, perm, BLK_PERM_ALL, blk, errp); if (!blk->root) { blk_unref(blk); @@ -834,7 +834,7 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) { ThrottleGroupMember *tgm = &blk->public.throttle_group_member; bdrv_ref(bs); - blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx, + blk->root = bdrv_root_attach_child(bs, "root", &child_root, 0, blk->ctx, blk->perm, blk->shared_perm, blk, errp); if (blk->root == NULL) { return -EPERM; diff --git a/block/bochs.c b/block/bochs.c index e7bbeaa1c4..b013e73063 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -110,7 +110,7 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, return ret; } - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/cloop.c b/block/cloop.c index f90f1a4b4c..3ed9fa63cc 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -71,7 +71,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, return ret; } - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/copy-on-read.c b/block/copy-on-read.c index 7504ca6ffc..a2c4e6dc58 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -28,7 +28,7 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/crypto.c b/block/crypto.c index bdb2b27475..8b516bfee2 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -218,7 +218,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, unsigned int cflags = 0; QDict *cryptoopts = NULL; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/dmg.c b/block/dmg.c index ef3c6e771d..af8188638c 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -439,7 +439,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags, return ret; } - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/filter-compress.c b/block/filter-compress.c index 82c315b298..4dc5f9fb8c 100644 --- a/block/filter-compress.c +++ b/block/filter-compress.c @@ -30,7 +30,7 @@ static int compress_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/parallels.c b/block/parallels.c index bd5f6ffa09..9855ac1162 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -739,7 +739,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, Error *local_err = NULL; char *buf; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/qcow.c b/block/qcow.c index 6a72dea049..13583f0339 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -130,7 +130,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, qdict_extract_subqdict(options, &encryptopts, "encrypt."); encryptfmt = qdict_get_try_str(encryptopts, "format"); - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { ret = -EINVAL; diff --git a/block/qcow2.c b/block/qcow2.c index 76bec61ee9..86335d9403 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1591,7 +1591,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, /* Open external data file */ s->data_file = bdrv_open_child(NULL, options, "data-file", bs, &child_file, - true, &local_err); + 0, true, &local_err); if (local_err) { error_propagate(errp, local_err); ret = -EINVAL; @@ -1601,7 +1601,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { if (!s->data_file && s->image_data_file) { s->data_file = bdrv_open_child(s->image_data_file, options, - "data-file", bs, &child_file, + "data-file", bs, &child_file, 0, false, errp); if (!s->data_file) { ret = -EINVAL; @@ -1863,7 +1863,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, .ret = -EINPROGRESS }; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/qed.c b/block/qed.c index 337eb6dbb6..1ad2aba810 100644 --- a/block/qed.c +++ b/block/qed.c @@ -547,7 +547,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, .ret = -EINPROGRESS }; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/quorum.c b/block/quorum.c index a0824c300d..024de76e6f 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -977,7 +977,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, assert(ret < 32); s->children[i] = bdrv_open_child(NULL, options, indexstr, bs, - &child_format, false, &local_err); + &child_format, 0, false, &local_err); if (local_err) { ret = -EINVAL; goto close_exit; @@ -1053,7 +1053,7 @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs, /* We can safely add the child now */ bdrv_ref(child_bs); - child = bdrv_attach_child(bs, child_bs, indexstr, &child_format, errp); + child = bdrv_attach_child(bs, child_bs, indexstr, &child_format, 0, errp); if (child == NULL) { s->next_child_index--; goto out; diff --git a/block/raw-format.c b/block/raw-format.c index 00e13bb41e..4b8d4ce8be 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -428,7 +428,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, BDRVRawState *s = bs->opaque; int ret; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/replication.c b/block/replication.c index af428c5b66..052c7ef601 100644 --- a/block/replication.c +++ b/block/replication.c @@ -90,7 +90,7 @@ static int replication_open(BlockDriverState *bs, QDict *options, const char *mode; const char *top_id; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/throttle.c b/block/throttle.c index 71f4bb0ad1..2dea913be7 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -82,7 +82,7 @@ static int throttle_open(BlockDriverState *bs, QDict *options, int ret; bs->file = bdrv_open_child(NULL, options, "file", bs, - &child_file, false, errp); + &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/vdi.c b/block/vdi.c index 0ef733ae19..653acb5fc1 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -378,7 +378,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, Error *local_err = NULL; QemuUUID uuid_link, uuid_parent; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/vhdx.c b/block/vhdx.c index e692cf80cc..dde156c97b 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -996,7 +996,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, uint64_t signature; Error *local_err = NULL; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/vmdk.c b/block/vmdk.c index 56e85689f3..c2cb741e2d 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1152,7 +1152,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, assert(ret < 32); extent_file = bdrv_open_child(extent_path, options, extent_opt_prefix, - bs, &child_file, false, &local_err); + bs, &child_file, 0, false, &local_err); g_free(extent_path); if (local_err) { error_propagate(errp, local_err); @@ -1257,7 +1257,7 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, uint32_t magic; Error *local_err = NULL; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/vpc.c b/block/vpc.c index 46a2d48659..b2a86074a5 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -228,7 +228,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, int ret; int64_t bs_size; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/vvfat.c b/block/vvfat.c index f845d9b485..cd8ae50a2c 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3183,7 +3183,7 @@ static int enable_write_target(BlockDriverState *bs, Error **errp) options = qdict_new(); qdict_put_str(options, "write-target.driver", "qcow"); s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs, - &child_vvfat_qcow, false, errp); + &child_vvfat_qcow, 0, false, errp); qobject_unref(options); if (!s->qcow) { ret = -EINVAL; diff --git a/blockjob.c b/blockjob.c index be38c8c550..470facfd47 100644 --- a/blockjob.c +++ b/blockjob.c @@ -217,8 +217,9 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, if (job->job.aio_context != qemu_get_aio_context()) { aio_context_release(job->job.aio_context); } - c = bdrv_root_attach_child(bs, name, &child_job, job->job.aio_context, - perm, shared_perm, job, errp); + c = bdrv_root_attach_child(bs, name, &child_job, 0, + job->job.aio_context, perm, shared_perm, job, + errp); if (job->job.aio_context != qemu_get_aio_context()) { aio_context_acquire(job->job.aio_context); } diff --git a/include/block/block.h b/include/block/block.h index 35f1a1cecf..25e299605e 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -353,6 +353,7 @@ BdrvChild *bdrv_open_child(const char *filename, QDict *options, const char *bdref_key, BlockDriverState* parent, const BdrvChildClass *child_class, + BdrvChildRole child_role, bool allow_none, Error **errp); BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, @@ -598,6 +599,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, const char *child_name, const BdrvChildClass *child_class, + BdrvChildRole child_role, Error **errp); bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); diff --git a/include/block/block_int.h b/include/block/block_int.h index 9a78b981e4..1c6641c17a 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -746,6 +746,7 @@ struct BdrvChild { BlockDriverState *bs; char *name; const BdrvChildClass *klass; + BdrvChildRole role; void *opaque; /** @@ -1233,6 +1234,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, const char *child_name, const BdrvChildClass *child_class, + BdrvChildRole child_role, AioContext *ctx, uint64_t perm, uint64_t shared_perm, void *opaque, Error **errp); diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 9d683a6c11..c03705ea37 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -1202,7 +1202,7 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, &error_abort); - bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort); + bdrv_attach_child(bs, null_bs, "null-child", &child_file, 0, &error_abort); /* This child will be the one to pass to requests through to, and * it will stall until a drain occurs */ @@ -1211,13 +1211,13 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS; /* Takes our reference to child_bs */ tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child", &child_file, - &error_abort); + 0, &error_abort); /* This child is just there to be deleted * (for detach_instead_of_delete == true) */ null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, &error_abort); - bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort); + bdrv_attach_child(bs, null_bs, "null-child", &child_file, 0, &error_abort); blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); blk_insert_bs(blk, bs, &error_abort); @@ -1314,7 +1314,7 @@ static void detach_indirect_bh(void *opaque) bdrv_ref(data->c); data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C", - &child_file, &error_abort); + &child_file, 0, &error_abort); } static void detach_by_parent_aio_cb(void *opaque, int ret) @@ -1396,13 +1396,15 @@ static void test_detach_indirect(bool by_parent_cb) /* Set child relationships */ bdrv_ref(b); bdrv_ref(a); - child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, &error_abort); - child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_backing, &error_abort); + child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, 0, + &error_abort); + child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_backing, 0, + &error_abort); bdrv_ref(a); bdrv_attach_child(parent_a, a, "PA-A", by_parent_cb ? &child_file : &detach_by_driver_cb_class, - &error_abort); + 0, &error_abort); g_assert_cmpint(parent_a->refcnt, ==, 1); g_assert_cmpint(parent_b->refcnt, ==, 1); @@ -1813,7 +1815,7 @@ static void test_drop_intermediate_poll(void) /* Takes the reference to chain[i - 1] */ chain[i]->backing = bdrv_attach_child(chain[i], chain[i - 1], "chain", &chain_child_class, - &error_abort); + 0, &error_abort); } } @@ -2031,7 +2033,7 @@ static void do_test_replace_child_mid_drain(int old_drain_count, bdrv_ref(old_child_bs); parent_bs->backing = bdrv_attach_child(parent_bs, old_child_bs, "child", - &child_backing, &error_abort); + &child_backing, 0, &error_abort); for (i = 0; i < old_drain_count; i++) { bdrv_drained_begin(old_child_bs); diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c index fef42cb294..8b8c186c9f 100644 --- a/tests/test-bdrv-graph-mod.c +++ b/tests/test-bdrv-graph-mod.c @@ -111,7 +111,7 @@ static void test_update_perm_tree(void) blk_insert_bs(root, bs, &error_abort); - bdrv_attach_child(filter, bs, "child", &child_file, &error_abort); + bdrv_attach_child(filter, bs, "child", &child_file, 0, &error_abort); bdrv_append(filter, bs, &local_err); @@ -177,7 +177,7 @@ static void test_should_update_child(void) bdrv_set_backing_hd(target, bs, &error_abort); g_assert(target->backing->bs == bs); - bdrv_attach_child(filter, target, "target", &child_file, &error_abort); + bdrv_attach_child(filter, target, "target", &child_file, 0, &error_abort); bdrv_append(filter, bs, &error_abort); g_assert(target->backing->bs == bs); From bf8e925eb569f31466eb5c9d935959a58772eec6 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:16 +0200 Subject: [PATCH 0542/2595] block: Pass BdrvChildRole to bdrv_child_perm() For now, all callers pass 0 and no callee evaluates this value. Later patches will change both. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-7-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 22 ++++++++++++---------- block/backup-top.c | 3 ++- block/blkdebug.c | 5 +++-- block/blklogwrites.c | 9 +++++---- block/commit.c | 1 + block/copy-on-read.c | 1 + block/mirror.c | 1 + block/quorum.c | 1 + block/replication.c | 1 + block/vvfat.c | 1 + include/block/block_int.h | 5 ++++- tests/test-bdrv-drain.c | 5 +++-- tests/test-bdrv-graph-mod.c | 1 + 13 files changed, 36 insertions(+), 20 deletions(-) diff --git a/block.c b/block.c index 14810e0426..5d9a331f5b 100644 --- a/block.c +++ b/block.c @@ -1954,12 +1954,12 @@ bool bdrv_is_writable(BlockDriverState *bs) static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, BdrvChild *c, const BdrvChildClass *child_class, - BlockReopenQueue *reopen_queue, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t parent_perm, uint64_t parent_shared, uint64_t *nperm, uint64_t *nshared) { assert(bs->drv && bs->drv->bdrv_child_perm); - bs->drv->bdrv_child_perm(bs, c, child_class, reopen_queue, + bs->drv->bdrv_child_perm(bs, c, child_class, role, reopen_queue, parent_perm, parent_shared, nperm, nshared); /* TODO Take force_share from reopen_queue */ @@ -2053,7 +2053,7 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, uint64_t cur_perm, cur_shared; bool child_tighten_restr; - bdrv_child_perm(bs, c->bs, c, c->klass, q, + bdrv_child_perm(bs, c->bs, c, c->klass, c->role, q, cumulative_perms, cumulative_shared_perms, &cur_perm, &cur_shared); ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, ignore_children, @@ -2120,7 +2120,7 @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms, /* Update all children */ QLIST_FOREACH(c, &bs->children, next) { uint64_t cur_perm, cur_shared; - bdrv_child_perm(bs, c->bs, c, c->klass, NULL, + bdrv_child_perm(bs, c->bs, c, c->klass, c->role, NULL, cumulative_perms, cumulative_shared_perms, &cur_perm, &cur_shared); bdrv_child_set_perm(c, cur_perm, cur_shared); @@ -2348,14 +2348,15 @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) uint64_t perms, shared; bdrv_get_cumulative_perm(bs, &parent_perms, &parent_shared); - bdrv_child_perm(bs, c->bs, c, c->klass, NULL, parent_perms, parent_shared, - &perms, &shared); + bdrv_child_perm(bs, c->bs, c, c->klass, c->role, NULL, + parent_perms, parent_shared, &perms, &shared); return bdrv_child_try_set_perm(c, perms, shared, errp); } void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) @@ -2366,6 +2367,7 @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) @@ -2378,7 +2380,7 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, /* Apart from the modifications below, the same permissions are * forwarded and left alone as for filters */ - bdrv_filter_default_perms(bs, c, child_class, reopen_queue, + bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, perm, shared, &perm, &shared); /* Format drivers may touch metadata even if the guest doesn't write */ @@ -2655,7 +2657,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm); assert(parent_bs->drv); - bdrv_child_perm(parent_bs, child_bs, NULL, child_class, NULL, + bdrv_child_perm(parent_bs, child_bs, NULL, child_class, child_role, NULL, perm, shared_perm, &perm, &shared_perm); child = bdrv_root_attach_child(child_bs, child_name, child_class, @@ -3683,7 +3685,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) if (state->replace_backing_bs && state->new_backing_bs) { uint64_t nperm, nshared; bdrv_child_perm(state->bs, state->new_backing_bs, - NULL, &child_backing, bs_queue, + NULL, &child_backing, 0, bs_queue, state->perm, state->shared_perm, &nperm, &nshared); ret = bdrv_check_update_perm(state->new_backing_bs, NULL, @@ -3806,7 +3808,7 @@ static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs, } else { uint64_t nperm, nshared; - bdrv_child_perm(parent->state.bs, bs, c, c->klass, q, + bdrv_child_perm(parent->state.bs, bs, c, c->klass, c->role, q, parent->state.perm, parent->state.shared_perm, &nperm, &nshared); diff --git a/block/backup-top.c b/block/backup-top.c index f891dd7838..e2b4d2acd3 100644 --- a/block/backup-top.c +++ b/block/backup-top.c @@ -123,6 +123,7 @@ static void backup_top_refresh_filename(BlockDriverState *bs) static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) @@ -155,7 +156,7 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, *nperm = BLK_PERM_WRITE; } else { /* Source child */ - bdrv_filter_default_perms(bs, c, child_class, reopen_queue, + bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, perm, shared, nperm, nshared); if (perm & BLK_PERM_WRITE) { diff --git a/block/blkdebug.c b/block/blkdebug.c index c91e78d5c8..8dd8ed6055 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -994,14 +994,15 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { BDRVBlkdebugState *s = bs->opaque; - bdrv_filter_default_perms(bs, c, child_class, reopen_queue, perm, shared, - nperm, nshared); + bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, + perm, shared, nperm, nshared); *nperm |= s->take_child_perms; *nshared &= ~s->unshare_child_perms; diff --git a/block/blklogwrites.c b/block/blklogwrites.c index 739db6dcf6..4faf912ef1 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -283,6 +283,7 @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs) static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *ro_q, uint64_t perm, uint64_t shrd, uint64_t *nperm, uint64_t *nshrd) @@ -294,11 +295,11 @@ static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, } if (!strcmp(c->name, "log")) { - bdrv_format_default_perms(bs, c, child_class, ro_q, perm, shrd, nperm, - nshrd); + bdrv_format_default_perms(bs, c, child_class, role, ro_q, perm, shrd, + nperm, nshrd); } else { - bdrv_filter_default_perms(bs, c, child_class, ro_q, perm, shrd, nperm, - nshrd); + bdrv_filter_default_perms(bs, c, child_class, role, ro_q, perm, shrd, + nperm, nshrd); } } diff --git a/block/commit.c b/block/commit.c index 834eeae412..6af1c808bc 100644 --- a/block/commit.c +++ b/block/commit.c @@ -224,6 +224,7 @@ static void bdrv_commit_top_refresh_filename(BlockDriverState *bs) static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) diff --git a/block/copy-on-read.c b/block/copy-on-read.c index a2c4e6dc58..a2d92ac394 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -52,6 +52,7 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, static void cor_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) diff --git a/block/mirror.c b/block/mirror.c index d6598463d5..cb4bdad32a 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1493,6 +1493,7 @@ static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs) static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) diff --git a/block/quorum.c b/block/quorum.c index 024de76e6f..d37b77a522 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -1152,6 +1152,7 @@ static char *quorum_dirname(BlockDriverState *bs, Error **errp) static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) diff --git a/block/replication.c b/block/replication.c index 052c7ef601..ea87b1a4f0 100644 --- a/block/replication.c +++ b/block/replication.c @@ -164,6 +164,7 @@ static void replication_close(BlockDriverState *bs) static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) diff --git a/block/vvfat.c b/block/vvfat.c index cd8ae50a2c..6cf3c74fe3 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3211,6 +3211,7 @@ err: static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) diff --git a/include/block/block_int.h b/include/block/block_int.h index 1c6641c17a..dc4bc486d6 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -556,7 +556,7 @@ struct BlockDriver { * the parents in @parent_perm and @parent_shared. * * If @c is NULL, return the permissions for attaching a new child for the - * given @child_class. + * given @child_class and @role. * * If @reopen_queue is non-NULL, don't return the currently needed * permissions, but those that will be needed after applying the @@ -564,6 +564,7 @@ struct BlockDriver { */ void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t parent_perm, uint64_t parent_shared, uint64_t *nperm, uint64_t *nshared); @@ -1266,6 +1267,7 @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); * all children */ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole child_role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared); @@ -1276,6 +1278,7 @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, * CONSISTENT_READ and doesn't share WRITE. */ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole child_role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared); diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index c03705ea37..b3d7960bd0 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -87,6 +87,7 @@ static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) @@ -99,8 +100,8 @@ static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, child_class = &child_file; } - bdrv_format_default_perms(bs, c, child_class, reopen_queue, perm, shared, - nperm, nshared); + bdrv_format_default_perms(bs, c, child_class, role, reopen_queue, + perm, shared, nperm, nshared); } static int bdrv_test_change_backing_file(BlockDriverState *bs, diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c index 8b8c186c9f..3707e2533c 100644 --- a/tests/test-bdrv-graph-mod.c +++ b/tests/test-bdrv-graph-mod.c @@ -31,6 +31,7 @@ static BlockDriver bdrv_pass_through = { static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) From 272c02eaef0388225c1dcdbec99b2e838bb64d23 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:17 +0200 Subject: [PATCH 0543/2595] block: Pass BdrvChildRole to .inherit_options() For now, all callers (effectively) pass 0 and no callee evaluates thie value. Later patches will change both. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-8-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 40 +++++++++++++++++++++++---------------- block/block-backend.c | 3 ++- block/vvfat.c | 3 ++- include/block/block_int.h | 3 ++- 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/block.c b/block.c index 5d9a331f5b..40db0b78b9 100644 --- a/block.c +++ b/block.c @@ -77,6 +77,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, QDict *options, int flags, BlockDriverState *parent, const BdrvChildClass *child_class, + BdrvChildRole child_role, Error **errp); /* If non-zero, use only whitelisted block drivers */ @@ -1153,7 +1154,8 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options, * Returns the options and flags that bs->file should get if a protocol driver * is expected, based on the given options and flags for the parent BDS */ -static void bdrv_inherited_options(int *child_flags, QDict *child_options, +static void bdrv_inherited_options(BdrvChildRole role, + int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { int flags = parent_flags; @@ -1202,10 +1204,11 @@ const BdrvChildClass child_file = { * (and not only protocols) is permitted for it, based on the given options and * flags for the parent BDS */ -static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options, +static void bdrv_inherited_fmt_options(BdrvChildRole role, + int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { - child_file.inherit_options(child_flags, child_options, + child_file.inherit_options(role, child_flags, child_options, parent_flags, parent_options); *child_flags &= ~(BDRV_O_PROTOCOL | BDRV_O_NO_IO); @@ -1286,7 +1289,8 @@ static void bdrv_backing_detach(BdrvChild *c) * Returns the options and flags that bs->backing should get, based on the * given options and flags for the parent BDS */ -static void bdrv_backing_options(int *child_flags, QDict *child_options, +static void bdrv_backing_options(BdrvChildRole role, + int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { int flags = parent_flags; @@ -2876,7 +2880,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, } backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs, - &child_backing, errp); + &child_backing, 0, errp); if (!backing_hd) { bs->open_flags |= BDRV_O_NO_BACKING; error_prepend(errp, "Could not open backing file: "); @@ -2911,7 +2915,7 @@ free_exit: static BlockDriverState * bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key, BlockDriverState *parent, const BdrvChildClass *child_class, - bool allow_none, Error **errp) + BdrvChildRole child_role, bool allow_none, Error **errp) { BlockDriverState *bs = NULL; QDict *image_options; @@ -2942,7 +2946,7 @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key, } bs = bdrv_open_inherit(filename, reference, image_options, 0, - parent, child_class, errp); + parent, child_class, child_role, errp); if (!bs) { goto done; } @@ -2976,7 +2980,7 @@ BdrvChild *bdrv_open_child(const char *filename, BlockDriverState *bs; bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class, - allow_none, errp); + child_role, allow_none, errp); if (bs == NULL) { return NULL; } @@ -3020,7 +3024,7 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) } - bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp); + bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, errp); obj = NULL; qobject_unref(obj); visit_free(v); @@ -3117,6 +3121,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, QDict *options, int flags, BlockDriverState *parent, const BdrvChildClass *child_class, + BdrvChildRole child_role, Error **errp) { int ret; @@ -3169,7 +3174,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, if (child_class) { bs->inherits_from = parent; - child_class->inherit_options(&flags, options, + child_class->inherit_options(child_role, &flags, options, parent->open_flags, parent->options); } @@ -3198,7 +3203,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, flags, options); /* Let bdrv_backing_options() override "read-only" */ qdict_del(options, BDRV_OPT_READ_ONLY); - bdrv_backing_options(&flags, options, flags, options); + bdrv_backing_options(0, &flags, options, flags, options); } bs->open_flags = flags; @@ -3240,7 +3245,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, BlockDriverState *file_bs; file_bs = bdrv_open_child_bs(filename, options, "file", bs, - &child_file, true, &local_err); + &child_file, 0, true, &local_err); if (local_err) { goto fail; } @@ -3385,7 +3390,7 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference, QDict *options, int flags, Error **errp) { return bdrv_open_inherit(filename, reference, options, flags, NULL, - NULL, errp); + NULL, 0, errp); } /* Return true if the NULL-terminated @list contains @str */ @@ -3482,6 +3487,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, BlockDriverState *bs, QDict *options, const BdrvChildClass *klass, + BdrvChildRole role, QDict *parent_options, int parent_flags, bool keep_old_opts) @@ -3537,7 +3543,8 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, /* Inherit from parent node */ if (parent_options) { flags = 0; - klass->inherit_options(&flags, options, parent_flags, parent_options); + klass->inherit_options(role, &flags, options, + parent_flags, parent_options); } else { flags = bdrv_get_flags(bs); } @@ -3628,7 +3635,8 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, } bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options, - child->klass, options, flags, child_keep_old); + child->klass, child->role, options, flags, + child_keep_old); } return bs_queue; @@ -3638,7 +3646,7 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, BlockDriverState *bs, QDict *options, bool keep_old_opts) { - return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, NULL, 0, + return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, NULL, 0, keep_old_opts); } diff --git a/block/block-backend.c b/block/block-backend.c index efc7acb3d8..5539ca8816 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -120,7 +120,8 @@ static QTAILQ_HEAD(, BlockBackend) block_backends = static QTAILQ_HEAD(, BlockBackend) monitor_block_backends = QTAILQ_HEAD_INITIALIZER(monitor_block_backends); -static void blk_root_inherit_options(int *child_flags, QDict *child_options, +static void blk_root_inherit_options(BdrvChildRole role, + int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { /* We're not supposed to call this function for root nodes */ diff --git a/block/vvfat.c b/block/vvfat.c index 6cf3c74fe3..4033e4f369 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3128,7 +3128,8 @@ static BlockDriver vvfat_write_target = { .bdrv_co_pwritev = write_target_commit, }; -static void vvfat_qcow_options(int *child_flags, QDict *child_options, +static void vvfat_qcow_options(BdrvChildRole role, + int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off"); diff --git a/include/block/block_int.h b/include/block/block_int.h index dc4bc486d6..8c1160a577 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -677,7 +677,8 @@ struct BdrvChildClass { * non-BDS parents. */ bool parent_is_bds; - void (*inherit_options)(int *child_flags, QDict *child_options, + void (*inherit_options)(BdrvChildRole role, + int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options); void (*change_media)(BdrvChild *child, bool load); From 3cdc69d31b49bed603adc973cf06ac898a9b2914 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:18 +0200 Subject: [PATCH 0544/2595] block: Pass parent_is_format to .inherit_options() We plan to unify the generic .inherit_options() functions. The resulting common function will need to decide whether to force-enable format probing, force-disable it, or leave it as-is. To make this decision, it will need to know whether the parent node is a format node or not (because we never want format probing if the parent is a format node already (except for the backing chain)). Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-9-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 37 +++++++++++++++++++++++++++---------- block/block-backend.c | 2 +- block/vvfat.c | 2 +- include/block/block_int.h | 2 +- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/block.c b/block.c index 40db0b78b9..b78e2dc141 100644 --- a/block.c +++ b/block.c @@ -1154,7 +1154,7 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options, * Returns the options and flags that bs->file should get if a protocol driver * is expected, based on the given options and flags for the parent BDS */ -static void bdrv_inherited_options(BdrvChildRole role, +static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { @@ -1205,10 +1205,12 @@ const BdrvChildClass child_file = { * flags for the parent BDS */ static void bdrv_inherited_fmt_options(BdrvChildRole role, + bool parent_is_format, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { - child_file.inherit_options(role, child_flags, child_options, + child_file.inherit_options(role, parent_is_format, + child_flags, child_options, parent_flags, parent_options); *child_flags &= ~(BDRV_O_PROTOCOL | BDRV_O_NO_IO); @@ -1289,7 +1291,7 @@ static void bdrv_backing_detach(BdrvChild *c) * Returns the options and flags that bs->backing should get, based on the * given options and flags for the parent BDS */ -static void bdrv_backing_options(BdrvChildRole role, +static void bdrv_backing_options(BdrvChildRole role, bool parent_is_format, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { @@ -3173,8 +3175,22 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, bs->explicit_options = qdict_clone_shallow(options); if (child_class) { + bool parent_is_format; + + if (parent->drv) { + parent_is_format = parent->drv->is_format; + } else { + /* + * parent->drv is not set yet because this node is opened for + * (potential) format probing. That means that @parent is going + * to be a format node. + */ + parent_is_format = true; + } + bs->inherits_from = parent; - child_class->inherit_options(child_role, &flags, options, + child_class->inherit_options(child_role, parent_is_format, + &flags, options, parent->open_flags, parent->options); } @@ -3203,7 +3219,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, flags, options); /* Let bdrv_backing_options() override "read-only" */ qdict_del(options, BDRV_OPT_READ_ONLY); - bdrv_backing_options(0, &flags, options, flags, options); + bdrv_backing_options(0, true, &flags, options, flags, options); } bs->open_flags = flags; @@ -3488,6 +3504,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, QDict *options, const BdrvChildClass *klass, BdrvChildRole role, + bool parent_is_format, QDict *parent_options, int parent_flags, bool keep_old_opts) @@ -3543,7 +3560,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, /* Inherit from parent node */ if (parent_options) { flags = 0; - klass->inherit_options(role, &flags, options, + klass->inherit_options(role, parent_is_format, &flags, options, parent_flags, parent_options); } else { flags = bdrv_get_flags(bs); @@ -3635,8 +3652,8 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, } bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options, - child->klass, child->role, options, flags, - child_keep_old); + child->klass, child->role, bs->drv->is_format, + options, flags, child_keep_old); } return bs_queue; @@ -3646,8 +3663,8 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, BlockDriverState *bs, QDict *options, bool keep_old_opts) { - return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, NULL, 0, - keep_old_opts); + return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, false, + NULL, 0, keep_old_opts); } /* diff --git a/block/block-backend.c b/block/block-backend.c index 5539ca8816..f2e81af27d 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -120,7 +120,7 @@ static QTAILQ_HEAD(, BlockBackend) block_backends = static QTAILQ_HEAD(, BlockBackend) monitor_block_backends = QTAILQ_HEAD_INITIALIZER(monitor_block_backends); -static void blk_root_inherit_options(BdrvChildRole role, +static void blk_root_inherit_options(BdrvChildRole role, bool parent_is_format, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { diff --git a/block/vvfat.c b/block/vvfat.c index 4033e4f369..b4c8417dbd 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3128,7 +3128,7 @@ static BlockDriver vvfat_write_target = { .bdrv_co_pwritev = write_target_commit, }; -static void vvfat_qcow_options(BdrvChildRole role, +static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { diff --git a/include/block/block_int.h b/include/block/block_int.h index 8c1160a577..6245d8a18d 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -677,7 +677,7 @@ struct BdrvChildClass { * non-BDS parents. */ bool parent_is_bds; - void (*inherit_options)(BdrvChildRole role, + void (*inherit_options)(BdrvChildRole role, bool parent_is_format, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options); From b054ff73547b6e032bde1e98c9a4f8240ce9dd30 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:19 +0200 Subject: [PATCH 0545/2595] block: Rename bdrv_inherited_options() The other two .inherit_options implementations specify exactly for what case they are used in their name, so do it for this one as well. (The actual intention behind this patch is to follow it up with a generic bdrv_inherited_options() that works for all three cases.) Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-10-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/block.c b/block.c index b78e2dc141..a17c29f54b 100644 --- a/block.c +++ b/block.c @@ -1154,9 +1154,9 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options, * Returns the options and flags that bs->file should get if a protocol driver * is expected, based on the given options and flags for the parent BDS */ -static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, - int *child_flags, QDict *child_options, - int parent_flags, QDict *parent_options) +static void bdrv_protocol_options(BdrvChildRole role, bool parent_is_format, + int *child_flags, QDict *child_options, + int parent_flags, QDict *parent_options) { int flags = parent_flags; @@ -1188,7 +1188,7 @@ static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, const BdrvChildClass child_file = { .parent_is_bds = true, .get_parent_desc = bdrv_child_get_parent_desc, - .inherit_options = bdrv_inherited_options, + .inherit_options = bdrv_protocol_options, .drained_begin = bdrv_child_cb_drained_begin, .drained_poll = bdrv_child_cb_drained_poll, .drained_end = bdrv_child_cb_drained_end, From fae8bd3904642dd7ff582f4ad4e5e63b0cacbe6f Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:20 +0200 Subject: [PATCH 0546/2595] block: Add generic bdrv_inherited_options() After the series this patch belongs to, we want to have a common BdrvChildClass that encompasses all of child_file, child_format, and child_backing. Such a single class needs a single .inherit_options() implementation, and this patch introduces it. The next patch will show how the existing implementations can fall back to it just by passing appropriate BdrvChildRole and parent_is_format values. Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-11-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/block.c b/block.c index a17c29f54b..9b0e13d537 100644 --- a/block.c +++ b/block.c @@ -1356,6 +1356,87 @@ const BdrvChildClass child_backing = { .set_aio_ctx = bdrv_child_cb_set_aio_ctx, }; +/* + * Returns the options and flags that a generic child of a BDS should + * get, based on the given options and flags for the parent BDS. + */ +static void __attribute__((unused)) + bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, + int *child_flags, QDict *child_options, + int parent_flags, QDict *parent_options) +{ + int flags = parent_flags; + + /* + * First, decide whether to set, clear, or leave BDRV_O_PROTOCOL. + * Generally, the question to answer is: Should this child be + * format-probed by default? + */ + + /* + * Pure and non-filtered data children of non-format nodes should + * be probed by default (even when the node itself has BDRV_O_PROTOCOL + * set). This only affects a very limited set of drivers (namely + * quorum and blkverify when this comment was written). + * Force-clear BDRV_O_PROTOCOL then. + */ + if (!parent_is_format && + (role & BDRV_CHILD_DATA) && + !(role & (BDRV_CHILD_METADATA | BDRV_CHILD_FILTERED))) + { + flags &= ~BDRV_O_PROTOCOL; + } + + /* + * All children of format nodes (except for COW children) and all + * metadata children in general should never be format-probed. + * Force-set BDRV_O_PROTOCOL then. + */ + if ((parent_is_format && !(role & BDRV_CHILD_COW)) || + (role & BDRV_CHILD_METADATA)) + { + flags |= BDRV_O_PROTOCOL; + } + + /* + * If the cache mode isn't explicitly set, inherit direct and no-flush from + * the parent. + */ + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT); + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH); + qdict_copy_default(child_options, parent_options, BDRV_OPT_FORCE_SHARE); + + if (role & BDRV_CHILD_COW) { + /* backing files are opened read-only by default */ + qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on"); + qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off"); + } else { + /* Inherit the read-only option from the parent if it's not set */ + qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY); + qdict_copy_default(child_options, parent_options, + BDRV_OPT_AUTO_READ_ONLY); + } + + /* + * bdrv_co_pdiscard() respects unmap policy for the parent, so we + * can default to enable it on lower layers regardless of the + * parent option. + */ + qdict_set_default_str(child_options, BDRV_OPT_DISCARD, "unmap"); + + /* Clear flags that only apply to the top layer */ + flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ); + + if (role & BDRV_CHILD_METADATA) { + flags &= ~BDRV_O_NO_IO; + } + if (role & BDRV_CHILD_COW) { + flags &= ~BDRV_O_TEMPORARY; + } + + *child_flags = flags; +} + static int bdrv_open_flags(BlockDriverState *bs, int flags) { int open_flags = flags; From 00ff7ffd67c50fe45a1e313765d416d082541128 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:21 +0200 Subject: [PATCH 0547/2595] block: Use bdrv_inherited_options() Let child_file's, child_format's, and child_backing's .inherit_options() implementations fall back to bdrv_inherited_options() to show that it would really work for all of these cases, if only the parents passed the appropriate BdrvChildRole and parent_is_format values. (Also, make bdrv_open_inherit(), the only place to explicitly call bdrv_backing_options(), call bdrv_inherited_options() instead.) This patch should incur only two visible changes, both for child_format children, both of which are effectively bug fixes: First, they no longer have discard=unmap set by default. This reason it was set is because bdrv_inherited_fmt_options() fell through to bdrv_protocol_options(), and that set it because "format drivers take care to send flushes and respect unmap policy". None of the drivers that use child_format for their children (quorum and blkverify) are format drivers, though, so this reasoning does not apply here. Second, they no longer have BDRV_O_NO_IO force-cleared. child_format was used solely for children that do not store any metadata and as such will not be accessed by their parents as long as those parents do not receive I/O themselves. Thus, such children should inherit BDRV_O_NO_IO. Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-12-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 71 +++++++++++++++------------------------------------------ 1 file changed, 19 insertions(+), 52 deletions(-) diff --git a/block.c b/block.c index 9b0e13d537..b3b978a092 100644 --- a/block.c +++ b/block.c @@ -80,6 +80,11 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, BdrvChildRole child_role, Error **errp); +/* TODO: Remove when no longer needed */ +static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, + int *child_flags, QDict *child_options, + int parent_flags, QDict *parent_options); + /* If non-zero, use only whitelisted block drivers */ static int use_bdrv_whitelist; @@ -1158,31 +1163,9 @@ static void bdrv_protocol_options(BdrvChildRole role, bool parent_is_format, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { - int flags = parent_flags; - - /* Enable protocol handling, disable format probing for bs->file */ - flags |= BDRV_O_PROTOCOL; - - /* If the cache mode isn't explicitly set, inherit direct and no-flush from - * the parent. */ - qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT); - qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH); - qdict_copy_default(child_options, parent_options, BDRV_OPT_FORCE_SHARE); - - /* Inherit the read-only option from the parent if it's not set */ - qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY); - qdict_copy_default(child_options, parent_options, BDRV_OPT_AUTO_READ_ONLY); - - /* Our block drivers take care to send flushes and respect unmap policy, - * so we can default to enable both on lower layers regardless of the - * corresponding parent options. */ - qdict_set_default_str(child_options, BDRV_OPT_DISCARD, "unmap"); - - /* Clear flags that only apply to the top layer */ - flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ | - BDRV_O_NO_IO); - - *child_flags = flags; + bdrv_inherited_options(BDRV_CHILD_IMAGE, true, + child_flags, child_options, + parent_flags, parent_options); } const BdrvChildClass child_file = { @@ -1209,11 +1192,9 @@ static void bdrv_inherited_fmt_options(BdrvChildRole role, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { - child_file.inherit_options(role, parent_is_format, - child_flags, child_options, - parent_flags, parent_options); - - *child_flags &= ~(BDRV_O_PROTOCOL | BDRV_O_NO_IO); + bdrv_inherited_options(BDRV_CHILD_DATA, false, + child_flags, child_options, + parent_flags, parent_options); } const BdrvChildClass child_format = { @@ -1295,23 +1276,9 @@ static void bdrv_backing_options(BdrvChildRole role, bool parent_is_format, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { - int flags = parent_flags; - - /* The cache mode is inherited unmodified for backing files; except WCE, - * which is only applied on the top level (BlockBackend) */ - qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT); - qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH); - qdict_copy_default(child_options, parent_options, BDRV_OPT_FORCE_SHARE); - - /* backing files always opened read-only */ - qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on"); - qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off"); - flags &= ~BDRV_O_COPY_ON_READ; - - /* snapshot=on is handled on the top layer */ - flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY); - - *child_flags = flags; + bdrv_inherited_options(BDRV_CHILD_COW, true, + child_flags, child_options, + parent_flags, parent_options); } static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, @@ -1360,10 +1327,9 @@ const BdrvChildClass child_backing = { * Returns the options and flags that a generic child of a BDS should * get, based on the given options and flags for the parent BDS. */ -static void __attribute__((unused)) - bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, - int *child_flags, QDict *child_options, - int parent_flags, QDict *parent_options) +static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, + int *child_flags, QDict *child_options, + int parent_flags, QDict *parent_options) { int flags = parent_flags; @@ -3300,7 +3266,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, flags, options); /* Let bdrv_backing_options() override "read-only" */ qdict_del(options, BDRV_OPT_READ_ONLY); - bdrv_backing_options(0, true, &flags, options, flags, options); + bdrv_inherited_options(BDRV_CHILD_COW, true, + &flags, options, flags, options); } bs->open_flags = flags; From ca2f1234c3c051f416fb0a1d09eecde328a6dd51 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:22 +0200 Subject: [PATCH 0548/2595] block: Unify bdrv_child_cb_attach() Make bdrv_child_cb_attach() call bdrv_backing_attach() for children with a COW role (and drop the reverse call from bdrv_backing_attach()), so it can be used for any child (with a proper role set). Because so far no child has a proper role set, we need a temporary new callback for child_backing.attach that ensures bdrv_backing_attach() is called for all COW children that do not have their role set yet. (Also, move bdrv_child_cb_attach() down to group it with bdrv_inherited_options().) Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-13-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/block.c b/block.c index b3b978a092..755704a54c 100644 --- a/block.c +++ b/block.c @@ -84,6 +84,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options); +static void bdrv_child_cb_attach(BdrvChild *child); /* If non-zero, use only whitelisted block drivers */ static int use_bdrv_whitelist; @@ -1099,12 +1100,6 @@ static void bdrv_child_cb_drained_end(BdrvChild *child, bdrv_drained_end_no_poll(bs, drained_end_counter); } -static void bdrv_child_cb_attach(BdrvChild *child) -{ - BlockDriverState *bs = child->opaque; - bdrv_apply_subtree_drain(child, bs); -} - static void bdrv_child_cb_detach(BdrvChild *child) { BlockDriverState *bs = child->opaque; @@ -1252,7 +1247,14 @@ static void bdrv_backing_attach(BdrvChild *c) parent->backing_blocker); bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET, parent->backing_blocker); +} +/* XXX: Will be removed along with child_backing */ +static void bdrv_child_cb_attach_backing(BdrvChild *c) +{ + if (!(c->role & BDRV_CHILD_COW)) { + bdrv_backing_attach(c); + } bdrv_child_cb_attach(c); } @@ -1311,7 +1313,7 @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, const BdrvChildClass child_backing = { .parent_is_bds = true, .get_parent_desc = bdrv_child_get_parent_desc, - .attach = bdrv_backing_attach, + .attach = bdrv_child_cb_attach_backing, .detach = bdrv_backing_detach, .inherit_options = bdrv_backing_options, .drained_begin = bdrv_child_cb_drained_begin, @@ -1403,6 +1405,17 @@ static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, *child_flags = flags; } +static void bdrv_child_cb_attach(BdrvChild *child) +{ + BlockDriverState *bs = child->opaque; + + if (child->role & BDRV_CHILD_COW) { + bdrv_backing_attach(child); + } + + bdrv_apply_subtree_drain(child, bs); +} + static int bdrv_open_flags(BlockDriverState *bs, int flags) { int open_flags = flags; From 48e082886132f49e883d96ce39fb926f53868e26 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:23 +0200 Subject: [PATCH 0549/2595] block: Unify bdrv_child_cb_detach() Make bdrv_child_cb_detach() call bdrv_backing_detach() for children with a COW role (and drop the reverse call from bdrv_backing_detach()), so it can be used for any child (with a proper role set). Because so far no child has a proper role set, we need a temporary new callback for child_backing.detach that ensures bdrv_backing_detach() is called for all COW children that do not have their role set yet. (Also, move bdrv_child_cb_detach() down to group it with bdrv_inherited_options() and bdrv_child_cb_attach().) Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-14-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/block.c b/block.c index 755704a54c..f63417c06d 100644 --- a/block.c +++ b/block.c @@ -85,6 +85,7 @@ static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options); static void bdrv_child_cb_attach(BdrvChild *child); +static void bdrv_child_cb_detach(BdrvChild *child); /* If non-zero, use only whitelisted block drivers */ static int use_bdrv_whitelist; @@ -1100,12 +1101,6 @@ static void bdrv_child_cb_drained_end(BdrvChild *child, bdrv_drained_end_no_poll(bs, drained_end_counter); } -static void bdrv_child_cb_detach(BdrvChild *child) -{ - BlockDriverState *bs = child->opaque; - bdrv_unapply_subtree_drain(child, bs); -} - static int bdrv_child_cb_inactivate(BdrvChild *child) { BlockDriverState *bs = child->opaque; @@ -1266,7 +1261,14 @@ static void bdrv_backing_detach(BdrvChild *c) bdrv_op_unblock_all(c->bs, parent->backing_blocker); error_free(parent->backing_blocker); parent->backing_blocker = NULL; +} +/* XXX: Will be removed along with child_backing */ +static void bdrv_child_cb_detach_backing(BdrvChild *c) +{ + if (!(c->role & BDRV_CHILD_COW)) { + bdrv_backing_detach(c); + } bdrv_child_cb_detach(c); } @@ -1314,7 +1316,7 @@ const BdrvChildClass child_backing = { .parent_is_bds = true, .get_parent_desc = bdrv_child_get_parent_desc, .attach = bdrv_child_cb_attach_backing, - .detach = bdrv_backing_detach, + .detach = bdrv_child_cb_detach_backing, .inherit_options = bdrv_backing_options, .drained_begin = bdrv_child_cb_drained_begin, .drained_poll = bdrv_child_cb_drained_poll, @@ -1416,6 +1418,17 @@ static void bdrv_child_cb_attach(BdrvChild *child) bdrv_apply_subtree_drain(child, bs); } +static void bdrv_child_cb_detach(BdrvChild *child) +{ + BlockDriverState *bs = child->opaque; + + if (child->role & BDRV_CHILD_COW) { + bdrv_backing_detach(child); + } + + bdrv_unapply_subtree_drain(child, bs); +} + static int bdrv_open_flags(BlockDriverState *bs, int flags) { int open_flags = flags; From 4348355032c027d0029994fc62da395e68afb60d Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:24 +0200 Subject: [PATCH 0550/2595] block: Add child_of_bds Any current user of child_file, child_format, and child_backing can and should use this generic BdrvChildClass instead, as it can handle all of these cases. However, to be able to do so, the users must pass the appropriate BdrvChildRole when the child is created/attached. (The following commits will take care of that.) Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-15-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 24 ++++++++++++++++++++++++ include/block/block_int.h | 1 + 2 files changed, 25 insertions(+) diff --git a/block.c b/block.c index f63417c06d..be9bfa9d46 100644 --- a/block.c +++ b/block.c @@ -1429,6 +1429,30 @@ static void bdrv_child_cb_detach(BdrvChild *child) bdrv_unapply_subtree_drain(child, bs); } +static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base, + const char *filename, Error **errp) +{ + if (c->role & BDRV_CHILD_COW) { + return bdrv_backing_update_filename(c, base, filename, errp); + } + return 0; +} + +const BdrvChildClass child_of_bds = { + .parent_is_bds = true, + .get_parent_desc = bdrv_child_get_parent_desc, + .inherit_options = bdrv_inherited_options, + .drained_begin = bdrv_child_cb_drained_begin, + .drained_poll = bdrv_child_cb_drained_poll, + .drained_end = bdrv_child_cb_drained_end, + .attach = bdrv_child_cb_attach, + .detach = bdrv_child_cb_detach, + .inactivate = bdrv_child_cb_inactivate, + .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx, + .set_aio_ctx = bdrv_child_cb_set_aio_ctx, + .update_filename = bdrv_child_cb_update_filename, +}; + static int bdrv_open_flags(BlockDriverState *bs, int flags) { int open_flags = flags; diff --git a/include/block/block_int.h b/include/block/block_int.h index 6245d8a18d..54df821d61 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -740,6 +740,7 @@ struct BdrvChildClass { void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore); }; +extern const BdrvChildClass child_of_bds; extern const BdrvChildClass child_file; extern const BdrvChildClass child_format; extern const BdrvChildClass child_backing; From 33f2663bd58696ab836731830f9fb6a878a5b944 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:25 +0200 Subject: [PATCH 0551/2595] block: Distinguish paths in *_format_default_perms bdrv_format_default_perms() has one code path for backing files, and one for storage files. We want to pull them out into their own functions, so make sure they are completely distinct before so the next patches will be a bit cleaner. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-16-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/block.c b/block.c index be9bfa9d46..b3e7ae70c7 100644 --- a/block.c +++ b/block.c @@ -2497,6 +2497,13 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, perm |= BLK_PERM_CONSISTENT_READ; } shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); + + if (bs->open_flags & BDRV_O_INACTIVE) { + shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; + } + + *nperm = perm; + *nshared = shared; } else { /* We want consistent read from backing files if the parent needs it. * No other operations are performed on backing files. */ @@ -2513,14 +2520,14 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD | BLK_PERM_WRITE_UNCHANGED; - } - if (bs->open_flags & BDRV_O_INACTIVE) { - shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; - } + if (bs->open_flags & BDRV_O_INACTIVE) { + shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; + } - *nperm = perm; - *nshared = shared; + *nperm = perm; + *nshared = shared; + } } uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm) From 70082db4efab1bc91467a9207c6e3f554a8e6bac Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:26 +0200 Subject: [PATCH 0552/2595] block: Pull out bdrv_default_perms_for_cow() Right now, bdrv_format_default_perms() is used by format parents (generally). We want to switch to a model where most parents use a single BdrvChildClass, which then decides the permissions based on the child role. To do so, we have to split bdrv_format_default_perms() into separate functions for each such role. Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-17-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 62 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/block.c b/block.c index b3e7ae70c7..b12222a471 100644 --- a/block.c +++ b/block.c @@ -2468,6 +2468,44 @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, *nshared = (shared & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED; } +static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, + const BdrvChildClass *child_class, + BdrvChildRole role, + BlockReopenQueue *reopen_queue, + uint64_t perm, uint64_t shared, + uint64_t *nperm, uint64_t *nshared) +{ + assert(child_class == &child_backing || + (child_class == &child_of_bds && (role & BDRV_CHILD_COW))); + + /* + * We want consistent read from backing files if the parent needs it. + * No other operations are performed on backing files. + */ + perm &= BLK_PERM_CONSISTENT_READ; + + /* + * If the parent can deal with changing data, we're okay with a + * writable and resizable backing file. + * TODO Require !(perm & BLK_PERM_CONSISTENT_READ), too? + */ + if (shared & BLK_PERM_WRITE) { + shared = BLK_PERM_WRITE | BLK_PERM_RESIZE; + } else { + shared = 0; + } + + shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD | + BLK_PERM_WRITE_UNCHANGED; + + if (bs->open_flags & BDRV_O_INACTIVE) { + shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; + } + + *nperm = perm; + *nshared = shared; +} + void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, BdrvChildRole role, @@ -2505,28 +2543,8 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, *nperm = perm; *nshared = shared; } else { - /* We want consistent read from backing files if the parent needs it. - * No other operations are performed on backing files. */ - perm &= BLK_PERM_CONSISTENT_READ; - - /* If the parent can deal with changing data, we're okay with a - * writable and resizable backing file. */ - /* TODO Require !(perm & BLK_PERM_CONSISTENT_READ), too? */ - if (shared & BLK_PERM_WRITE) { - shared = BLK_PERM_WRITE | BLK_PERM_RESIZE; - } else { - shared = 0; - } - - shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD | - BLK_PERM_WRITE_UNCHANGED; - - if (bs->open_flags & BDRV_O_INACTIVE) { - shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; - } - - *nperm = perm; - *nshared = shared; + bdrv_default_perms_for_cow(bs, c, child_class, role, reopen_queue, + perm, shared, nperm, nshared); } } From 6f838a4b73d9c85e498f94c28109dde0efc1cb9d Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:27 +0200 Subject: [PATCH 0553/2595] block: Pull out bdrv_default_perms_for_storage() Right now, bdrv_format_default_perms() is used by format parents (generally). We want to switch to a model where most parents use a single BdrvChildClass, which then decides the permissions based on the child role. To do so, we have to split bdrv_format_default_perms() into separate functions for each such role. Note that bdrv_default_perms_for_storage() currently handles all DATA | METADATA children. A follow-up patch is going to split it further into one function for each case. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-18-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 71 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/block.c b/block.c index b12222a471..5d17aa1cc3 100644 --- a/block.c +++ b/block.c @@ -2506,6 +2506,50 @@ static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, *nshared = shared; } +static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, + const BdrvChildClass *child_class, + BdrvChildRole role, + BlockReopenQueue *reopen_queue, + uint64_t perm, uint64_t shared, + uint64_t *nperm, uint64_t *nshared) +{ + int flags; + + assert(child_class == &child_file || + (child_class == &child_of_bds && + (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)))); + + flags = bdrv_reopen_get_flags(reopen_queue, bs); + + /* + * Apart from the modifications below, the same permissions are + * forwarded and left alone as for filters + */ + bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, + perm, shared, &perm, &shared); + + /* Format drivers may touch metadata even if the guest doesn't write */ + if (bdrv_is_writable_after_reopen(bs, reopen_queue)) { + perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; + } + + /* + * bs->file always needs to be consistent because of the metadata. We + * can never allow other users to resize or write to it. + */ + if (!(flags & BDRV_O_NO_IO)) { + perm |= BLK_PERM_CONSISTENT_READ; + } + shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); + + if (bs->open_flags & BDRV_O_INACTIVE) { + shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; + } + + *nperm = perm; + *nshared = shared; +} + void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, BdrvChildRole role, @@ -2517,31 +2561,8 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, assert(child_class == &child_backing || child_class == &child_file); if (!backing) { - int flags = bdrv_reopen_get_flags(reopen_queue, bs); - - /* Apart from the modifications below, the same permissions are - * forwarded and left alone as for filters */ - bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, - perm, shared, &perm, &shared); - - /* Format drivers may touch metadata even if the guest doesn't write */ - if (bdrv_is_writable_after_reopen(bs, reopen_queue)) { - perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; - } - - /* bs->file always needs to be consistent because of the metadata. We - * can never allow other users to resize or write to it. */ - if (!(flags & BDRV_O_NO_IO)) { - perm |= BLK_PERM_CONSISTENT_READ; - } - shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); - - if (bs->open_flags & BDRV_O_INACTIVE) { - shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; - } - - *nperm = perm; - *nshared = shared; + bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, + perm, shared, nperm, nshared); } else { bdrv_default_perms_for_cow(bs, c, child_class, role, reopen_queue, perm, shared, nperm, nshared); From f889054f031f2f01ae97bdc7579fbdf3a30e4e0e Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:28 +0200 Subject: [PATCH 0554/2595] block: Relax *perms_for_storage for data children We can be less restrictive about pure data children than those with metadata on them, so let bdrv_default_perms_for_storage() handle metadata children differently from pure data children. As explained in the code, the restrictions on metadata children are strictly stricter than those for pure data children, so in theory we just have to distinguish between pure-data and all other storage children (pure metadata or data+metadata). In practice, that is not obvious, though, so we have two independent code paths for metadata and for data children, and data+metadata children will go through both (without the path for data children doing anything meaningful). Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-19-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/block.c b/block.c index 5d17aa1cc3..5ff6cbd796 100644 --- a/block.c +++ b/block.c @@ -2528,19 +2528,57 @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, perm, shared, &perm, &shared); - /* Format drivers may touch metadata even if the guest doesn't write */ - if (bdrv_is_writable_after_reopen(bs, reopen_queue)) { - perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; + if (role & BDRV_CHILD_METADATA) { + /* Format drivers may touch metadata even if the guest doesn't write */ + if (bdrv_is_writable_after_reopen(bs, reopen_queue)) { + perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; + } + + /* + * bs->file always needs to be consistent because of the + * metadata. We can never allow other users to resize or write + * to it. + */ + if (!(flags & BDRV_O_NO_IO)) { + perm |= BLK_PERM_CONSISTENT_READ; + } + shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); } - /* - * bs->file always needs to be consistent because of the metadata. We - * can never allow other users to resize or write to it. - */ - if (!(flags & BDRV_O_NO_IO)) { - perm |= BLK_PERM_CONSISTENT_READ; + if (role & BDRV_CHILD_DATA) { + /* + * Technically, everything in this block is a subset of the + * BDRV_CHILD_METADATA path taken above, and so this could + * be an "else if" branch. However, that is not obvious, and + * this function is not performance critical, therefore we let + * this be an independent "if". + */ + + /* + * We cannot allow other users to resize the file because the + * format driver might have some assumptions about the size + * (e.g. because it is stored in metadata, or because the file + * is split into fixed-size data files). + */ + shared &= ~BLK_PERM_RESIZE; + + /* + * WRITE_UNCHANGED often cannot be performed as such on the + * data file. For example, the qcow2 driver may still need to + * write copied clusters on copy-on-read. + */ + if (perm & BLK_PERM_WRITE_UNCHANGED) { + perm |= BLK_PERM_WRITE; + } + + /* + * If the data file is written to, the format driver may + * expect to be able to resize it by writing beyond the EOF. + */ + if (perm & BLK_PERM_WRITE) { + perm |= BLK_PERM_RESIZE; + } } - shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); if (bs->open_flags & BDRV_O_INACTIVE) { shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE; From 2519f54919a9c3e0696e2fac7d564e15722618c4 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:29 +0200 Subject: [PATCH 0555/2595] block: Add bdrv_default_perms() This callback can be used by BDSs that use child_of_bds with the appropriate BdrvChildRole for their children. Also, make bdrv_format_default_perms() use it for child_of_bds children (just a temporary solution until we can drop bdrv_format_default_perms() altogether). Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-20-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 32 ++++++++++++++++++++++++++++++++ include/block/block_int.h | 11 +++++++++++ 2 files changed, 43 insertions(+) diff --git a/block.c b/block.c index 5ff6cbd796..088727fdbe 100644 --- a/block.c +++ b/block.c @@ -2596,6 +2596,13 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, uint64_t *nperm, uint64_t *nshared) { bool backing = (child_class == &child_backing); + + if (child_class == &child_of_bds) { + bdrv_default_perms(bs, c, child_class, role, reopen_queue, + perm, shared, nperm, nshared); + return; + } + assert(child_class == &child_backing || child_class == &child_file); if (!backing) { @@ -2607,6 +2614,31 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, } } +void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, + const BdrvChildClass *child_class, BdrvChildRole role, + BlockReopenQueue *reopen_queue, + uint64_t perm, uint64_t shared, + uint64_t *nperm, uint64_t *nshared) +{ + assert(child_class == &child_of_bds); + + if (role & BDRV_CHILD_FILTERED) { + assert(!(role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | + BDRV_CHILD_COW))); + bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, + perm, shared, nperm, nshared); + } else if (role & BDRV_CHILD_COW) { + assert(!(role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA))); + bdrv_default_perms_for_cow(bs, c, child_class, role, reopen_queue, + perm, shared, nperm, nshared); + } else if (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)) { + bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, + perm, shared, nperm, nshared); + } else { + g_assert_not_reached(); + } +} + uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm) { static const uint64_t permissions[] = { diff --git a/include/block/block_int.h b/include/block/block_int.h index 54df821d61..3a9dda9be7 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -1288,6 +1288,17 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, bool bdrv_recurse_can_replace(BlockDriverState *bs, BlockDriverState *to_replace); +/* + * Default implementation for BlockDriver.bdrv_child_perm() that can + * be used by block filters and image formats, as long as they use the + * child_of_bds child class and set an appropriate BdrvChildRole. + */ +void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, + const BdrvChildClass *child_class, BdrvChildRole role, + BlockReopenQueue *reopen_queue, + uint64_t perm, uint64_t shared, + uint64_t *nperm, uint64_t *nshared); + /* * Default implementation for drivers to pass bdrv_co_block_status() to * their file. From 500e2434207dd3cff4f88e6d6c7b0b7b9c1a2caf Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:30 +0200 Subject: [PATCH 0556/2595] raw-format: Split raw_read_options() Split raw_read_options() into one function that actually just reads the options, and another that applies them. This will allow us to detect whether the user has specified any options before attaching the file child (so we can decide on its role based on the options). Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-21-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block/raw-format.c | 110 ++++++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/block/raw-format.c b/block/raw-format.c index 4b8d4ce8be..824fe70686 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -71,20 +71,13 @@ static QemuOptsList raw_create_opts = { } }; -static int raw_read_options(QDict *options, BlockDriverState *bs, - BDRVRawState *s, Error **errp) +static int raw_read_options(QDict *options, uint64_t *offset, bool *has_size, + uint64_t *size, Error **errp) { Error *local_err = NULL; QemuOpts *opts = NULL; - int64_t real_size = 0; int ret; - real_size = bdrv_getlength(bs->file->bs); - if (real_size < 0) { - error_setg_errno(errp, -real_size, "Could not get image size"); - return real_size; - } - opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); qemu_opts_absorb_qdict(opts, options, &local_err); if (local_err) { @@ -93,64 +86,84 @@ static int raw_read_options(QDict *options, BlockDriverState *bs, goto end; } - s->offset = qemu_opt_get_size(opts, "offset", 0); - if (s->offset > real_size) { - error_setg(errp, "Offset (%" PRIu64 ") cannot be greater than " - "size of the containing file (%" PRId64 ")", - s->offset, real_size); - ret = -EINVAL; - goto end; - } + *offset = qemu_opt_get_size(opts, "offset", 0); + *has_size = qemu_opt_find(opts, "size"); + *size = qemu_opt_get_size(opts, "size", 0); - if (qemu_opt_find(opts, "size") != NULL) { - s->size = qemu_opt_get_size(opts, "size", 0); - s->has_size = true; - } else { - s->has_size = false; - s->size = real_size - s->offset; + ret = 0; +end: + qemu_opts_del(opts); + return ret; +} + +static int raw_apply_options(BlockDriverState *bs, BDRVRawState *s, + uint64_t offset, bool has_size, uint64_t size, + Error **errp) +{ + int64_t real_size = 0; + + real_size = bdrv_getlength(bs->file->bs); + if (real_size < 0) { + error_setg_errno(errp, -real_size, "Could not get image size"); + return real_size; } /* Check size and offset */ - if ((real_size - s->offset) < s->size) { + if (offset > real_size) { + error_setg(errp, "Offset (%" PRIu64 ") cannot be greater than " + "size of the containing file (%" PRId64 ")", + s->offset, real_size); + return -EINVAL; + } + + if (has_size && (real_size - offset) < size) { error_setg(errp, "The sum of offset (%" PRIu64 ") and size " - "(%" PRIu64 ") has to be smaller or equal to the " - " actual size of the containing file (%" PRId64 ")", - s->offset, s->size, real_size); - ret = -EINVAL; - goto end; + "(%" PRIu64 ") has to be smaller or equal to the " + " actual size of the containing file (%" PRId64 ")", + s->offset, s->size, real_size); + return -EINVAL; } /* Make sure size is multiple of BDRV_SECTOR_SIZE to prevent rounding * up and leaking out of the specified area. */ - if (s->has_size && !QEMU_IS_ALIGNED(s->size, BDRV_SECTOR_SIZE)) { + if (has_size && !QEMU_IS_ALIGNED(size, BDRV_SECTOR_SIZE)) { error_setg(errp, "Specified size is not multiple of %llu", - BDRV_SECTOR_SIZE); - ret = -EINVAL; - goto end; + BDRV_SECTOR_SIZE); + return -EINVAL; } - ret = 0; + s->offset = offset; + s->has_size = has_size; + s->size = has_size ? size : real_size - offset; -end: - - qemu_opts_del(opts); - - return ret; + return 0; } static int raw_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, Error **errp) { + bool has_size; + uint64_t offset, size; + int ret; + assert(reopen_state != NULL); assert(reopen_state->bs != NULL); reopen_state->opaque = g_new0(BDRVRawState, 1); - return raw_read_options( - reopen_state->options, - reopen_state->bs, - reopen_state->opaque, - errp); + ret = raw_read_options(reopen_state->options, &offset, &has_size, &size, + errp); + if (ret < 0) { + return ret; + } + + ret = raw_apply_options(reopen_state->bs, reopen_state->opaque, + offset, has_size, size, errp); + if (ret < 0) { + return ret; + } + + return 0; } static void raw_reopen_commit(BDRVReopenState *state) @@ -426,8 +439,15 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVRawState *s = bs->opaque; + bool has_size; + uint64_t offset, size; int ret; + ret = raw_read_options(options, &offset, &has_size, &size, errp); + if (ret < 0) { + return ret; + } + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, errp); if (!bs->file) { @@ -455,7 +475,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, bs->file->bs->filename); } - ret = raw_read_options(options, bs, s, errp); + ret = raw_apply_options(bs, s, offset, has_size, size, errp); if (ret < 0) { return ret; } From 36ee58d13bbcb75c72385bee6e262afed3acce47 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:31 +0200 Subject: [PATCH 0557/2595] block: Switch child_format users to child_of_bds Both users (quorum and blkverify) use child_format for not-really-filtered children, so the appropriate BdrvChildRole in both cases is DATA. (Note that this will cause bdrv_inherited_options() to force-allow format probing.) Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-22-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block/blkverify.c | 4 ++-- block/quorum.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/block/blkverify.c b/block/blkverify.c index ba4f6d7b7c..1684b7aa2e 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -134,8 +134,8 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, /* Open the test file */ s->test_file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, - "test", bs, &child_format, 0, false, - &local_err); + "test", bs, &child_of_bds, BDRV_CHILD_DATA, + false, &local_err); if (local_err) { ret = -EINVAL; error_propagate(errp, local_err); diff --git a/block/quorum.c b/block/quorum.c index d37b77a522..616ac3a927 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -977,7 +977,8 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, assert(ret < 32); s->children[i] = bdrv_open_child(NULL, options, indexstr, bs, - &child_format, 0, false, &local_err); + &child_of_bds, BDRV_CHILD_DATA, false, + &local_err); if (local_err) { ret = -EINVAL; goto close_exit; @@ -1053,7 +1054,8 @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs, /* We can safely add the child now */ bdrv_ref(child_bs); - child = bdrv_attach_child(bs, child_bs, indexstr, &child_format, 0, errp); + child = bdrv_attach_child(bs, child_bs, indexstr, &child_of_bds, + BDRV_CHILD_DATA, errp); if (child == NULL) { s->next_child_index--; goto out; From f34ade114818c5a011a743ebd899c91b9ebbe040 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:32 +0200 Subject: [PATCH 0558/2595] block: Drop child_format Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-23-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 29 ----------------------------- include/block/block_int.h | 1 - 2 files changed, 30 deletions(-) diff --git a/block.c b/block.c index 088727fdbe..85b4f947ba 100644 --- a/block.c +++ b/block.c @@ -1172,35 +1172,6 @@ const BdrvChildClass child_file = { .set_aio_ctx = bdrv_child_cb_set_aio_ctx, }; -/* - * Returns the options and flags that bs->file should get if the use of formats - * (and not only protocols) is permitted for it, based on the given options and - * flags for the parent BDS - */ -static void bdrv_inherited_fmt_options(BdrvChildRole role, - bool parent_is_format, - int *child_flags, QDict *child_options, - int parent_flags, QDict *parent_options) -{ - bdrv_inherited_options(BDRV_CHILD_DATA, false, - child_flags, child_options, - parent_flags, parent_options); -} - -const BdrvChildClass child_format = { - .parent_is_bds = true, - .get_parent_desc = bdrv_child_get_parent_desc, - .inherit_options = bdrv_inherited_fmt_options, - .drained_begin = bdrv_child_cb_drained_begin, - .drained_poll = bdrv_child_cb_drained_poll, - .drained_end = bdrv_child_cb_drained_end, - .attach = bdrv_child_cb_attach, - .detach = bdrv_child_cb_detach, - .inactivate = bdrv_child_cb_inactivate, - .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx, - .set_aio_ctx = bdrv_child_cb_set_aio_ctx, -}; - static void bdrv_backing_attach(BdrvChild *c) { BlockDriverState *parent = c->opaque; diff --git a/include/block/block_int.h b/include/block/block_int.h index 3a9dda9be7..4b09fa1124 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -742,7 +742,6 @@ struct BdrvChildClass { extern const BdrvChildClass child_of_bds; extern const BdrvChildClass child_file; -extern const BdrvChildClass child_format; extern const BdrvChildClass child_backing; struct BdrvChild { From 25191e5ff0804bbd3b9e9dd86fb538c06710cee2 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:33 +0200 Subject: [PATCH 0559/2595] block: Make backing files child_of_bds children Make all parents of backing files pass the appropriate BdrvChildRole. By doing so, we can switch their BdrvChildClass over to the generic child_of_bds, which will do the right thing when given a correct BdrvChildRole. Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-24-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 26 ++++++++++++++++++++------ block/backup-top.c | 2 +- block/vvfat.c | 3 ++- tests/test-bdrv-drain.c | 13 +++++++------ 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/block.c b/block.c index 85b4f947ba..131ae20ffc 100644 --- a/block.c +++ b/block.c @@ -2941,6 +2941,20 @@ static bool bdrv_inherits_from_recursive(BlockDriverState *child, return child != NULL; } +/* + * Return the BdrvChildRole for @bs's backing child. bs->backing is + * mostly used for COW backing children (role = COW), but also for + * filtered children (role = FILTERED | PRIMARY). + */ +static BdrvChildRole bdrv_backing_role(BlockDriverState *bs) +{ + if (bs->drv && bs->drv->is_filter) { + return BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY; + } else { + return BDRV_CHILD_COW; + } +} + /* * Sets the backing file link of a BDS. A new reference is created; callers * which don't need their own reference any more must call bdrv_unref(). @@ -2968,8 +2982,8 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, goto out; } - bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing, - 0, errp); + bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_of_bds, + bdrv_backing_role(bs), errp); /* If backing_hd was already part of bs's backing chain, and * inherits_from pointed recursively to bs then let's update it to * point directly to bs (else it will become NULL). */ @@ -3066,7 +3080,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, } backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs, - &child_backing, 0, errp); + &child_of_bds, bdrv_backing_role(bs), errp); if (!backing_hd) { bs->open_flags |= BDRV_O_NO_BACKING; error_prepend(errp, "Could not open backing file: "); @@ -3895,8 +3909,8 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) if (state->replace_backing_bs && state->new_backing_bs) { uint64_t nperm, nshared; bdrv_child_perm(state->bs, state->new_backing_bs, - NULL, &child_backing, 0, bs_queue, - state->perm, state->shared_perm, + NULL, &child_of_bds, bdrv_backing_role(state->bs), + bs_queue, state->perm, state->shared_perm, &nperm, &nshared); ret = bdrv_check_update_perm(state->new_backing_bs, NULL, nperm, nshared, NULL, NULL, errp); @@ -6852,7 +6866,7 @@ void bdrv_refresh_filename(BlockDriverState *bs) drv->bdrv_gather_child_options(bs, opts, backing_overridden); } else { QLIST_FOREACH(child, &bs->children, next) { - if (child->klass == &child_backing && !backing_overridden) { + if (child == bs->backing && !backing_overridden) { /* We can skip the backing BDS if it has not been overridden */ continue; } diff --git a/block/backup-top.c b/block/backup-top.c index e2b4d2acd3..f059617095 100644 --- a/block/backup-top.c +++ b/block/backup-top.c @@ -143,7 +143,7 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, return; } - if (child_class == &child_file) { + if (!(role & BDRV_CHILD_FILTERED)) { /* * Target child * diff --git a/block/vvfat.c b/block/vvfat.c index b4c8417dbd..e8848a0497 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3219,7 +3219,8 @@ static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, { BDRVVVFATState *s = bs->opaque; - assert(c == s->qcow || child_class == &child_backing); + assert(c == s->qcow || + (child_class == &child_of_bds && (role & BDRV_CHILD_COW))); if (c == s->qcow) { /* This is a private node, nobody should try to attach to it */ diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index b3d7960bd0..15393a0140 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -96,7 +96,7 @@ static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, * bdrv_format_default_perms() accepts only these two, so disguise * detach_by_driver_cb_parent as one of them. */ - if (child_class != &child_file && child_class != &child_backing) { + if (child_class != &child_file && child_class != &child_of_bds) { child_class = &child_file; } @@ -1399,8 +1399,8 @@ static void test_detach_indirect(bool by_parent_cb) bdrv_ref(a); child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, 0, &error_abort); - child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_backing, 0, - &error_abort); + child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_of_bds, + BDRV_CHILD_COW, &error_abort); bdrv_ref(a); bdrv_attach_child(parent_a, a, "PA-A", @@ -1793,7 +1793,7 @@ static void test_drop_intermediate_poll(void) int i; int ret; - chain_child_class = child_backing; + chain_child_class = child_of_bds; chain_child_class.update_filename = drop_intermediate_poll_update_filename; for (i = 0; i < 3; i++) { @@ -1816,7 +1816,7 @@ static void test_drop_intermediate_poll(void) /* Takes the reference to chain[i - 1] */ chain[i]->backing = bdrv_attach_child(chain[i], chain[i - 1], "chain", &chain_child_class, - 0, &error_abort); + BDRV_CHILD_COW, &error_abort); } } @@ -2034,7 +2034,8 @@ static void do_test_replace_child_mid_drain(int old_drain_count, bdrv_ref(old_child_bs); parent_bs->backing = bdrv_attach_child(parent_bs, old_child_bs, "child", - &child_backing, 0, &error_abort); + &child_of_bds, BDRV_CHILD_COW, + &error_abort); for (i = 0; i < old_drain_count; i++) { bdrv_drained_begin(old_child_bs); From ff3541c4e27030fe681d0613ef69bdffb0e29f3a Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:34 +0200 Subject: [PATCH 0560/2595] block: Drop child_backing Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-25-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 60 ++------------------------------------- include/block/block_int.h | 1 - 2 files changed, 3 insertions(+), 58 deletions(-) diff --git a/block.c b/block.c index 131ae20ffc..d138a3c261 100644 --- a/block.c +++ b/block.c @@ -1215,15 +1215,6 @@ static void bdrv_backing_attach(BdrvChild *c) parent->backing_blocker); } -/* XXX: Will be removed along with child_backing */ -static void bdrv_child_cb_attach_backing(BdrvChild *c) -{ - if (!(c->role & BDRV_CHILD_COW)) { - bdrv_backing_attach(c); - } - bdrv_child_cb_attach(c); -} - static void bdrv_backing_detach(BdrvChild *c) { BlockDriverState *parent = c->opaque; @@ -1234,28 +1225,6 @@ static void bdrv_backing_detach(BdrvChild *c) parent->backing_blocker = NULL; } -/* XXX: Will be removed along with child_backing */ -static void bdrv_child_cb_detach_backing(BdrvChild *c) -{ - if (!(c->role & BDRV_CHILD_COW)) { - bdrv_backing_detach(c); - } - bdrv_child_cb_detach(c); -} - -/* - * Returns the options and flags that bs->backing should get, based on the - * given options and flags for the parent BDS - */ -static void bdrv_backing_options(BdrvChildRole role, bool parent_is_format, - int *child_flags, QDict *child_options, - int parent_flags, QDict *parent_options) -{ - bdrv_inherited_options(BDRV_CHILD_COW, true, - child_flags, child_options, - parent_flags, parent_options); -} - static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, const char *filename, Error **errp) { @@ -1283,21 +1252,6 @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, return ret; } -const BdrvChildClass child_backing = { - .parent_is_bds = true, - .get_parent_desc = bdrv_child_get_parent_desc, - .attach = bdrv_child_cb_attach_backing, - .detach = bdrv_child_cb_detach_backing, - .inherit_options = bdrv_backing_options, - .drained_begin = bdrv_child_cb_drained_begin, - .drained_poll = bdrv_child_cb_drained_poll, - .drained_end = bdrv_child_cb_drained_end, - .inactivate = bdrv_child_cb_inactivate, - .update_filename = bdrv_backing_update_filename, - .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx, - .set_aio_ctx = bdrv_child_cb_set_aio_ctx, -}; - /* * Returns the options and flags that a generic child of a BDS should * get, based on the given options and flags for the parent BDS. @@ -2446,8 +2400,7 @@ static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { - assert(child_class == &child_backing || - (child_class == &child_of_bds && (role & BDRV_CHILD_COW))); + assert(child_class == &child_of_bds && (role & BDRV_CHILD_COW)); /* * We want consistent read from backing files if the parent needs it. @@ -2566,23 +2519,16 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { - bool backing = (child_class == &child_backing); - if (child_class == &child_of_bds) { bdrv_default_perms(bs, c, child_class, role, reopen_queue, perm, shared, nperm, nshared); return; } - assert(child_class == &child_backing || child_class == &child_file); + assert(child_class == &child_file); - if (!backing) { - bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, - perm, shared, nperm, nshared); - } else { - bdrv_default_perms_for_cow(bs, c, child_class, role, reopen_queue, + bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, perm, shared, nperm, nshared); - } } void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, diff --git a/include/block/block_int.h b/include/block/block_int.h index 4b09fa1124..0781d43af5 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -742,7 +742,6 @@ struct BdrvChildClass { extern const BdrvChildClass child_of_bds; extern const BdrvChildClass child_file; -extern const BdrvChildClass child_backing; struct BdrvChild { BlockDriverState *bs; From 8b1869daad17f313bf9a68fd3275448df0ecb7fb Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:35 +0200 Subject: [PATCH 0561/2595] block: Make format drivers use child_of_bds Commonly, they need to pass the BDRV_CHILD_IMAGE set as the BdrvChildRole; but there are exceptions for drivers with external data files (qcow2 and vmdk). Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-26-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block/bochs.c | 4 ++-- block/cloop.c | 4 ++-- block/crypto.c | 4 ++-- block/dmg.c | 4 ++-- block/parallels.c | 4 ++-- block/qcow.c | 4 ++-- block/qcow2.c | 19 +++++++++++++------ block/qed.c | 4 ++-- block/vdi.c | 4 ++-- block/vhdx.c | 4 ++-- block/vmdk.c | 20 +++++++++++++++++--- block/vpc.c | 4 ++-- 12 files changed, 50 insertions(+), 29 deletions(-) diff --git a/block/bochs.c b/block/bochs.c index b013e73063..62c3f42548 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -110,8 +110,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, return ret; } - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/cloop.c b/block/cloop.c index 3ed9fa63cc..d374a8427d 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -71,8 +71,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, return ret; } - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/crypto.c b/block/crypto.c index 8b516bfee2..457f3a06a5 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -218,8 +218,8 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, unsigned int cflags = 0; QDict *cryptoopts = NULL; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/dmg.c b/block/dmg.c index af8188638c..bc64194577 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -439,8 +439,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags, return ret; } - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/parallels.c b/block/parallels.c index 9855ac1162..168d6c531a 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -739,8 +739,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, Error *local_err = NULL; char *buf; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/qcow.c b/block/qcow.c index 13583f0339..5347037720 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -130,8 +130,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, qdict_extract_subqdict(options, &encryptopts, "encrypt."); encryptfmt = qdict_get_try_str(encryptopts, "format"); - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { ret = -EINVAL; goto fail; diff --git a/block/qcow2.c b/block/qcow2.c index 86335d9403..8d7230dca8 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1590,8 +1590,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, } /* Open external data file */ - s->data_file = bdrv_open_child(NULL, options, "data-file", bs, &child_file, - 0, true, &local_err); + s->data_file = bdrv_open_child(NULL, options, "data-file", bs, + &child_of_bds, BDRV_CHILD_DATA, + true, &local_err); if (local_err) { error_propagate(errp, local_err); ret = -EINVAL; @@ -1601,8 +1602,8 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { if (!s->data_file && s->image_data_file) { s->data_file = bdrv_open_child(s->image_data_file, options, - "data-file", bs, &child_file, 0, - false, errp); + "data-file", bs, &child_of_bds, + BDRV_CHILD_DATA, false, errp); if (!s->data_file) { ret = -EINVAL; goto fail; @@ -1613,6 +1614,12 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, ret = -EINVAL; goto fail; } + + /* No data here */ + bs->file->role &= ~BDRV_CHILD_DATA; + + /* Must succeed because we have given up permissions if anything */ + bdrv_child_refresh_perms(bs, bs->file, &error_abort); } else { if (s->data_file) { error_setg(errp, "'data-file' can only be set for images with an " @@ -1863,8 +1870,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, .ret = -EINPROGRESS }; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/qed.c b/block/qed.c index 1ad2aba810..ef6463b48d 100644 --- a/block/qed.c +++ b/block/qed.c @@ -547,8 +547,8 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, .ret = -EINPROGRESS }; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/vdi.c b/block/vdi.c index 653acb5fc1..d20698b3cc 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -378,8 +378,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, Error *local_err = NULL; QemuUUID uuid_link, uuid_parent; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/vhdx.c b/block/vhdx.c index dde156c97b..62c6bd69ff 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -996,8 +996,8 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, uint64_t signature; Error *local_err = NULL; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/vmdk.c b/block/vmdk.c index c2cb741e2d..fadc98a262 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1089,6 +1089,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, char *desc_file_dir = NULL; char *extent_path; BdrvChild *extent_file; + BdrvChildRole extent_role; BDRVVmdkState *s = bs->opaque; VmdkExtent *extent; char extent_opt_prefix[32]; @@ -1151,8 +1152,15 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents); assert(ret < 32); + extent_role = BDRV_CHILD_DATA; + if (strcmp(type, "FLAT") != 0 && strcmp(type, "VMFS") != 0) { + /* non-flat extents have metadata */ + extent_role |= BDRV_CHILD_METADATA; + } + extent_file = bdrv_open_child(extent_path, options, extent_opt_prefix, - bs, &child_file, 0, false, &local_err); + bs, &child_of_bds, extent_role, false, + &local_err); g_free(extent_path); if (local_err) { error_propagate(errp, local_err); @@ -1257,8 +1265,8 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, uint32_t magic; Error *local_err = NULL; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } @@ -1277,6 +1285,12 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, s->desc_offset = 0x200; break; default: + /* No data in the descriptor file */ + bs->file->role &= ~BDRV_CHILD_DATA; + + /* Must succeed because we have given up permissions if anything */ + bdrv_child_refresh_perms(bs, bs->file, &error_abort); + ret = vmdk_open_desc_file(bs, flags, buf, options, errp); break; } diff --git a/block/vpc.c b/block/vpc.c index b2a86074a5..651a6737b6 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -228,8 +228,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, int ret; int64_t bs_size; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } From b3af2af43b2bf85191cf40fa84b33df1268a08fd Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:36 +0200 Subject: [PATCH 0562/2595] block: Make filter drivers use child_of_bds Note that some filters have secondary children, namely blkverify (the image to be verified) and blklogwrites (the log). This patch does not touch those children. Note that for blkverify, the filtered child should not be format-probed. While there is nothing enforcing this here, in practice, it will not be: blkverify implements .bdrv_file_open. The block layer ensures (and in fact, asserts) that BDRV_O_PROTOCOL is set for every BDS whose driver implements .bdrv_file_open. This flag will then be bequeathed to blkverify's children, and they will thus (by default) not be probed either. ("By default" refers to the fact that blkverify's other child (the non-filtered one) will have BDRV_O_PROTOCOL force-unset, because that is what happens for all non-filtered children of non-format drivers.) Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-27-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/blkdebug.c | 4 +++- block/blklogwrites.c | 3 ++- block/blkreplay.c | 5 +++-- block/blkverify.c | 4 +++- block/copy-on-read.c | 5 +++-- block/filter-compress.c | 5 +++-- block/replication.c | 3 ++- block/throttle.c | 5 +++-- 8 files changed, 22 insertions(+), 12 deletions(-) diff --git a/block/blkdebug.c b/block/blkdebug.c index 8dd8ed6055..b31fa40b0e 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -497,7 +497,9 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, /* Open the image file */ bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image", - bs, &child_file, 0, false, &local_err); + bs, &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, + false, &local_err); if (local_err) { ret = -EINVAL; error_propagate(errp, local_err); diff --git a/block/blklogwrites.c b/block/blklogwrites.c index 4faf912ef1..78b0c49460 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -157,7 +157,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, } /* Open the file */ - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, false, &local_err); if (local_err) { ret = -EINVAL; diff --git a/block/blkreplay.c b/block/blkreplay.c index 9b2814fc58..20d6139baa 100644 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -27,8 +27,9 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags, int ret; /* Open the image file */ - bs->file = bdrv_open_child(NULL, options, "image", - bs, &child_file, 0, false, &local_err); + bs->file = bdrv_open_child(NULL, options, "image", bs, &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, + false, &local_err); if (local_err) { ret = -EINVAL; error_propagate(errp, local_err); diff --git a/block/blkverify.c b/block/blkverify.c index 1684b7aa2e..5c3b29244a 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -125,7 +125,9 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, /* Open the raw file */ bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw", - bs, &child_file, 0, false, &local_err); + bs, &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, + false, &local_err); if (local_err) { ret = -EINVAL; error_propagate(errp, local_err); diff --git a/block/copy-on-read.c b/block/copy-on-read.c index a2d92ac394..c857ea0da7 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -28,8 +28,9 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, - errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, + false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/filter-compress.c b/block/filter-compress.c index 4dc5f9fb8c..9edd937645 100644 --- a/block/filter-compress.c +++ b/block/filter-compress.c @@ -30,8 +30,9 @@ static int compress_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false, - errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, + false, errp); if (!bs->file) { return -EINVAL; } diff --git a/block/replication.c b/block/replication.c index ea87b1a4f0..cc9c473ad1 100644 --- a/block/replication.c +++ b/block/replication.c @@ -90,7 +90,8 @@ static int replication_open(BlockDriverState *bs, QDict *options, const char *mode; const char *top_id; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, false, errp); if (!bs->file) { return -EINVAL; diff --git a/block/throttle.c b/block/throttle.c index 2dea913be7..47b0a3522d 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -81,8 +81,9 @@ static int throttle_open(BlockDriverState *bs, QDict *options, char *group; int ret; - bs->file = bdrv_open_child(NULL, options, "file", bs, - &child_file, 0, false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, + false, errp); if (!bs->file) { return -EINVAL; } From 58944401d661f22fef15af5a0270ef808a1f4791 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:37 +0200 Subject: [PATCH 0563/2595] block: Use child_of_bds in remaining places Replace child_file by child_of_bds in all remaining places (excluding tests). Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-28-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 3 ++- block/backup-top.c | 4 ++-- block/blklogwrites.c | 4 ++-- block/raw-format.c | 15 +++++++++++++-- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/block.c b/block.c index d138a3c261..fb94adcca4 100644 --- a/block.c +++ b/block.c @@ -3406,7 +3406,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, BlockDriverState *file_bs; file_bs = bdrv_open_child_bs(filename, options, "file", bs, - &child_file, 0, true, &local_err); + &child_of_bds, BDRV_CHILD_IMAGE, + true, &local_err); if (local_err) { goto fail; } diff --git a/block/backup-top.c b/block/backup-top.c index f059617095..8af2c5fe9b 100644 --- a/block/backup-top.c +++ b/block/backup-top.c @@ -215,8 +215,8 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, source->supported_zero_flags); bdrv_ref(target); - state->target = bdrv_attach_child(top, target, "target", &child_file, 0, - errp); + state->target = bdrv_attach_child(top, target, "target", &child_of_bds, + BDRV_CHILD_DATA, errp); if (!state->target) { bdrv_unref(target); bdrv_unref(top); diff --git a/block/blklogwrites.c b/block/blklogwrites.c index 78b0c49460..3a57b273fc 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -167,8 +167,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, } /* Open the log file */ - s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, 0, - false, &local_err); + s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_of_bds, + BDRV_CHILD_METADATA, false, &local_err); if (local_err) { ret = -EINVAL; error_propagate(errp, local_err); diff --git a/block/raw-format.c b/block/raw-format.c index 824fe70686..bfb4d7ddb7 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -441,6 +441,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, BDRVRawState *s = bs->opaque; bool has_size; uint64_t offset, size; + BdrvChildRole file_role; int ret; ret = raw_read_options(options, &offset, &has_size, &size, errp); @@ -448,8 +449,18 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, return ret; } - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, - false, errp); + /* + * Without offset and a size limit, this driver behaves very much + * like a filter. With any such limit, it does not. + */ + if (offset || has_size) { + file_role = BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY; + } else { + file_role = BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY; + } + + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + file_role, false, errp); if (!bs->file) { return -EINVAL; } From a16be3cdfce2379b5fb0a17a3017a6c59d73388d Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:38 +0200 Subject: [PATCH 0564/2595] tests: Use child_of_bds instead of child_file Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-29-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- tests/test-bdrv-drain.c | 29 +++++++++++++++++------------ tests/test-bdrv-graph-mod.c | 6 ++++-- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 15393a0140..91567ca97d 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -97,7 +97,7 @@ static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, * detach_by_driver_cb_parent as one of them. */ if (child_class != &child_file && child_class != &child_of_bds) { - child_class = &child_file; + child_class = &child_of_bds; } bdrv_format_default_perms(bs, c, child_class, role, reopen_queue, @@ -1203,7 +1203,8 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, &error_abort); - bdrv_attach_child(bs, null_bs, "null-child", &child_file, 0, &error_abort); + bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, + BDRV_CHILD_DATA, &error_abort); /* This child will be the one to pass to requests through to, and * it will stall until a drain occurs */ @@ -1211,14 +1212,17 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, &error_abort); child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS; /* Takes our reference to child_bs */ - tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child", &child_file, - 0, &error_abort); + tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child", + &child_of_bds, + BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY, + &error_abort); /* This child is just there to be deleted * (for detach_instead_of_delete == true) */ null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, &error_abort); - bdrv_attach_child(bs, null_bs, "null-child", &child_file, 0, &error_abort); + bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, BDRV_CHILD_DATA, + &error_abort); blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); blk_insert_bs(blk, bs, &error_abort); @@ -1315,7 +1319,8 @@ static void detach_indirect_bh(void *opaque) bdrv_ref(data->c); data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C", - &child_file, 0, &error_abort); + &child_of_bds, BDRV_CHILD_DATA, + &error_abort); } static void detach_by_parent_aio_cb(void *opaque, int ret) @@ -1332,7 +1337,7 @@ static void detach_by_driver_cb_drained_begin(BdrvChild *child) { aio_bh_schedule_oneshot(qemu_get_current_aio_context(), detach_indirect_bh, &detach_by_parent_data); - child_file.drained_begin(child); + child_of_bds.drained_begin(child); } static BdrvChildClass detach_by_driver_cb_class; @@ -1367,7 +1372,7 @@ static void test_detach_indirect(bool by_parent_cb) QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0); if (!by_parent_cb) { - detach_by_driver_cb_class = child_file; + detach_by_driver_cb_class = child_of_bds; detach_by_driver_cb_class.drained_begin = detach_by_driver_cb_drained_begin; } @@ -1397,15 +1402,15 @@ static void test_detach_indirect(bool by_parent_cb) /* Set child relationships */ bdrv_ref(b); bdrv_ref(a); - child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, 0, - &error_abort); + child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_of_bds, + BDRV_CHILD_DATA, &error_abort); child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_of_bds, BDRV_CHILD_COW, &error_abort); bdrv_ref(a); bdrv_attach_child(parent_a, a, "PA-A", - by_parent_cb ? &child_file : &detach_by_driver_cb_class, - 0, &error_abort); + by_parent_cb ? &child_of_bds : &detach_by_driver_cb_class, + BDRV_CHILD_DATA, &error_abort); g_assert_cmpint(parent_a->refcnt, ==, 1); g_assert_cmpint(parent_b->refcnt, ==, 1); diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c index 3707e2533c..6ae91ff171 100644 --- a/tests/test-bdrv-graph-mod.c +++ b/tests/test-bdrv-graph-mod.c @@ -112,7 +112,8 @@ static void test_update_perm_tree(void) blk_insert_bs(root, bs, &error_abort); - bdrv_attach_child(filter, bs, "child", &child_file, 0, &error_abort); + bdrv_attach_child(filter, bs, "child", &child_of_bds, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort); bdrv_append(filter, bs, &local_err); @@ -178,7 +179,8 @@ static void test_should_update_child(void) bdrv_set_backing_hd(target, bs, &error_abort); g_assert(target->backing->bs == bs); - bdrv_attach_child(filter, target, "target", &child_file, 0, &error_abort); + bdrv_attach_child(filter, target, "target", &child_of_bds, + BDRV_CHILD_DATA, &error_abort); bdrv_append(filter, bs, &error_abort); g_assert(target->backing->bs == bs); From 69dca43d6b6819b3d0895364692e2d0445674916 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:39 +0200 Subject: [PATCH 0565/2595] block: Use bdrv_default_perms() bdrv_default_perms() can decide which permission profile to use based on the BdrvChildRole, so block drivers do not need to select it explicitly. The blkverify driver now no longer shares the WRITE permission for the image to verify. We thus have to adjust two places in test-block-iothread not to take it. (Note that in theory, blkverify should behave like quorum in this regard and share neither WRITE nor RESIZE for both of its children. In practice, it does not really matter, because blkverify is used only for debugging, so we might as well keep its permissions rather liberal.) Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-30-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block/backup-top.c | 4 ++-- block/blkdebug.c | 4 ++-- block/blklogwrites.c | 9 ++------- block/blkreplay.c | 2 +- block/blkverify.c | 2 +- block/bochs.c | 2 +- block/cloop.c | 2 +- block/crypto.c | 2 +- block/dmg.c | 2 +- block/filter-compress.c | 2 +- block/parallels.c | 2 +- block/qcow.c | 2 +- block/qcow2.c | 2 +- block/qed.c | 2 +- block/raw-format.c | 2 +- block/throttle.c | 2 +- block/vdi.c | 2 +- block/vhdx.c | 2 +- block/vmdk.c | 2 +- block/vpc.c | 2 +- tests/test-bdrv-drain.c | 10 +++++----- tests/test-bdrv-graph-mod.c | 2 +- tests/test-block-iothread.c | 17 ++++++++++++++--- 23 files changed, 43 insertions(+), 37 deletions(-) diff --git a/block/backup-top.c b/block/backup-top.c index 8af2c5fe9b..f0efec18b5 100644 --- a/block/backup-top.c +++ b/block/backup-top.c @@ -156,8 +156,8 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, *nperm = BLK_PERM_WRITE; } else { /* Source child */ - bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, - perm, shared, nperm, nshared); + bdrv_default_perms(bs, c, child_class, role, reopen_queue, + perm, shared, nperm, nshared); if (perm & BLK_PERM_WRITE) { *nperm = *nperm | BLK_PERM_CONSISTENT_READ; diff --git a/block/blkdebug.c b/block/blkdebug.c index b31fa40b0e..a925d8295e 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -1003,8 +1003,8 @@ static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c, { BDRVBlkdebugState *s = bs->opaque; - bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, - perm, shared, nperm, nshared); + bdrv_default_perms(bs, c, child_class, role, reopen_queue, + perm, shared, nperm, nshared); *nperm |= s->take_child_perms; *nshared &= ~s->unshare_child_perms; diff --git a/block/blklogwrites.c b/block/blklogwrites.c index 3a57b273fc..8684fb1c74 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -295,13 +295,8 @@ static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, return; } - if (!strcmp(c->name, "log")) { - bdrv_format_default_perms(bs, c, child_class, role, ro_q, perm, shrd, - nperm, nshrd); - } else { - bdrv_filter_default_perms(bs, c, child_class, role, ro_q, perm, shrd, - nperm, nshrd); - } + bdrv_default_perms(bs, c, child_class, role, ro_q, perm, shrd, + nperm, nshrd); } static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp) diff --git a/block/blkreplay.c b/block/blkreplay.c index 20d6139baa..30a0f5d57a 100644 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -139,7 +139,7 @@ static BlockDriver bdrv_blkreplay = { .is_filter = true, .bdrv_open = blkreplay_open, - .bdrv_child_perm = bdrv_filter_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_getlength = blkreplay_getlength, .bdrv_co_preadv = blkreplay_co_preadv, diff --git a/block/blkverify.c b/block/blkverify.c index 5c3b29244a..2f261de24b 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -319,7 +319,7 @@ static BlockDriver bdrv_blkverify = { .bdrv_parse_filename = blkverify_parse_filename, .bdrv_file_open = blkverify_open, .bdrv_close = blkverify_close, - .bdrv_child_perm = bdrv_filter_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_getlength = blkverify_getlength, .bdrv_refresh_filename = blkverify_refresh_filename, .bdrv_dirname = blkverify_dirname, diff --git a/block/bochs.c b/block/bochs.c index 62c3f42548..2f010ab40a 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -297,7 +297,7 @@ static BlockDriver bdrv_bochs = { .instance_size = sizeof(BDRVBochsState), .bdrv_probe = bochs_probe, .bdrv_open = bochs_open, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_refresh_limits = bochs_refresh_limits, .bdrv_co_preadv = bochs_co_preadv, .bdrv_close = bochs_close, diff --git a/block/cloop.c b/block/cloop.c index d374a8427d..c99192a57f 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -293,7 +293,7 @@ static BlockDriver bdrv_cloop = { .instance_size = sizeof(BDRVCloopState), .bdrv_probe = cloop_probe, .bdrv_open = cloop_open, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_refresh_limits = cloop_refresh_limits, .bdrv_co_preadv = cloop_co_preadv, .bdrv_close = cloop_close, diff --git a/block/crypto.c b/block/crypto.c index 457f3a06a5..b216e12c31 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -756,7 +756,7 @@ static BlockDriver bdrv_crypto_luks = { .bdrv_close = block_crypto_close, /* This driver doesn't modify LUKS metadata except when creating image. * Allow share-rw=on as a special case. */ - .bdrv_child_perm = bdrv_filter_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_co_create = block_crypto_co_create_luks, .bdrv_co_create_opts = block_crypto_co_create_opts_luks, .bdrv_co_truncate = block_crypto_co_truncate, diff --git a/block/dmg.c b/block/dmg.c index bc64194577..0d6c317296 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -750,7 +750,7 @@ static BlockDriver bdrv_dmg = { .bdrv_probe = dmg_probe, .bdrv_open = dmg_open, .bdrv_refresh_limits = dmg_refresh_limits, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_co_preadv = dmg_co_preadv, .bdrv_close = dmg_close, .is_format = true, diff --git a/block/filter-compress.c b/block/filter-compress.c index 9edd937645..8ec1991c1f 100644 --- a/block/filter-compress.c +++ b/block/filter-compress.c @@ -133,7 +133,7 @@ static BlockDriver bdrv_compress = { .format_name = "compress", .bdrv_open = compress_open, - .bdrv_child_perm = bdrv_filter_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_getlength = compress_getlength, diff --git a/block/parallels.c b/block/parallels.c index 168d6c531a..63a1cde8af 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -912,7 +912,7 @@ static BlockDriver bdrv_parallels = { .bdrv_probe = parallels_probe, .bdrv_open = parallels_open, .bdrv_close = parallels_close, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_co_block_status = parallels_co_block_status, .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_co_flush_to_os = parallels_co_flush_to_os, diff --git a/block/qcow.c b/block/qcow.c index 5347037720..ee5d35fe20 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -1180,7 +1180,7 @@ static BlockDriver bdrv_qcow = { .bdrv_probe = qcow_probe, .bdrv_open = qcow_open, .bdrv_close = qcow_close, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_reopen_prepare = qcow_reopen_prepare, .bdrv_co_create = qcow_co_create, .bdrv_co_create_opts = qcow_co_create_opts, diff --git a/block/qcow2.c b/block/qcow2.c index 8d7230dca8..fe0ce39799 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5744,7 +5744,7 @@ BlockDriver bdrv_qcow2 = { .bdrv_reopen_commit_post = qcow2_reopen_commit_post, .bdrv_reopen_abort = qcow2_reopen_abort, .bdrv_join_options = qcow2_join_options, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_co_create_opts = qcow2_co_create_opts, .bdrv_co_create = qcow2_co_create, .bdrv_has_zero_init = qcow2_has_zero_init, diff --git a/block/qed.c b/block/qed.c index ef6463b48d..c0c65015c7 100644 --- a/block/qed.c +++ b/block/qed.c @@ -1672,7 +1672,7 @@ static BlockDriver bdrv_qed = { .bdrv_open = bdrv_qed_open, .bdrv_close = bdrv_qed_close, .bdrv_reopen_prepare = bdrv_qed_reopen_prepare, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_co_create = bdrv_qed_co_create, .bdrv_co_create_opts = bdrv_qed_co_create_opts, .bdrv_has_zero_init = bdrv_has_zero_init_1, diff --git a/block/raw-format.c b/block/raw-format.c index bfb4d7ddb7..018441bddf 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -586,7 +586,7 @@ BlockDriver bdrv_raw = { .bdrv_reopen_commit = &raw_reopen_commit, .bdrv_reopen_abort = &raw_reopen_abort, .bdrv_open = &raw_open, - .bdrv_child_perm = bdrv_filter_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_co_create_opts = &raw_co_create_opts, .bdrv_co_preadv = &raw_co_preadv, .bdrv_co_pwritev = &raw_co_pwritev, diff --git a/block/throttle.c b/block/throttle.c index 47b0a3522d..0ebbad0743 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -237,7 +237,7 @@ static BlockDriver bdrv_throttle = { .bdrv_close = throttle_close, .bdrv_co_flush = throttle_co_flush, - .bdrv_child_perm = bdrv_filter_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_getlength = throttle_getlength, diff --git a/block/vdi.c b/block/vdi.c index d20698b3cc..2f506a01ba 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -1039,7 +1039,7 @@ static BlockDriver bdrv_vdi = { .bdrv_open = vdi_open, .bdrv_close = vdi_close, .bdrv_reopen_prepare = vdi_reopen_prepare, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_co_create = vdi_co_create, .bdrv_co_create_opts = vdi_co_create_opts, .bdrv_has_zero_init = vdi_has_zero_init, diff --git a/block/vhdx.c b/block/vhdx.c index 62c6bd69ff..fa9e544a5e 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -2245,7 +2245,7 @@ static BlockDriver bdrv_vhdx = { .bdrv_open = vhdx_open, .bdrv_close = vhdx_close, .bdrv_reopen_prepare = vhdx_reopen_prepare, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_co_readv = vhdx_co_readv, .bdrv_co_writev = vhdx_co_writev, .bdrv_co_create = vhdx_co_create, diff --git a/block/vmdk.c b/block/vmdk.c index fadc98a262..62da465126 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -3067,7 +3067,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_open = vmdk_open, .bdrv_co_check = vmdk_co_check, .bdrv_reopen_prepare = vmdk_reopen_prepare, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_co_preadv = vmdk_co_preadv, .bdrv_co_pwritev = vmdk_co_pwritev, .bdrv_co_pwritev_compressed = vmdk_co_pwritev_compressed, diff --git a/block/vpc.c b/block/vpc.c index 651a6737b6..c055591641 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -1240,7 +1240,7 @@ static BlockDriver bdrv_vpc = { .bdrv_open = vpc_open, .bdrv_close = vpc_close, .bdrv_reopen_prepare = vpc_reopen_prepare, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_co_create = vpc_co_create, .bdrv_co_create_opts = vpc_co_create_opts, diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 91567ca97d..0da5a3a6a1 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -93,15 +93,15 @@ static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, uint64_t *nperm, uint64_t *nshared) { /* - * bdrv_format_default_perms() accepts only these two, so disguise + * bdrv_default_perms() accepts only these two, so disguise * detach_by_driver_cb_parent as one of them. */ if (child_class != &child_file && child_class != &child_of_bds) { child_class = &child_of_bds; } - bdrv_format_default_perms(bs, c, child_class, role, reopen_queue, - perm, shared, nperm, nshared); + bdrv_default_perms(bs, c, child_class, role, reopen_queue, + perm, shared, nperm, nshared); } static int bdrv_test_change_backing_file(BlockDriverState *bs, @@ -1137,7 +1137,7 @@ static BlockDriver bdrv_test_top_driver = { .bdrv_close = bdrv_test_top_close, .bdrv_co_preadv = bdrv_test_top_co_preadv, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, }; typedef struct TestCoDeleteByDrainData { @@ -1966,7 +1966,7 @@ static BlockDriver bdrv_replace_test = { .bdrv_co_drain_begin = bdrv_replace_test_co_drain_begin, .bdrv_co_drain_end = bdrv_replace_test_co_drain_end, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, }; static void coroutine_fn test_replace_child_mid_drain_read_co(void *opaque) diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c index 6ae91ff171..a2d0318b16 100644 --- a/tests/test-bdrv-graph-mod.c +++ b/tests/test-bdrv-graph-mod.c @@ -26,7 +26,7 @@ static BlockDriver bdrv_pass_through = { .format_name = "pass-through", - .bdrv_child_perm = bdrv_filter_default_perms, + .bdrv_child_perm = bdrv_default_perms, }; static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c, diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c index 71e9bce3b1..a953794be2 100644 --- a/tests/test-block-iothread.c +++ b/tests/test-block-iothread.c @@ -482,8 +482,13 @@ static void test_propagate_basic(void) BlockDriverState *bs_a, *bs_b, *bs_verify; QDict *options; - /* Create bs_a and its BlockBackend */ - blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); + /* + * Create bs_a and its BlockBackend. We cannot take the RESIZE + * permission because blkverify will not share it on the test + * image. + */ + blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL & ~BLK_PERM_RESIZE, + BLK_PERM_ALL); bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort); blk_insert_bs(blk, bs_a, &error_abort); @@ -566,7 +571,13 @@ static void test_propagate_diamond(void) qdict_put_str(options, "raw", "bs_c"); bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort); - blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); + /* + * Do not take the RESIZE permission: This would require the same + * from bs_c and thus from bs_a; however, blkverify will not share + * it on bs_b, and thus it will not be available for bs_a. + */ + blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL & ~BLK_PERM_RESIZE, + BLK_PERM_ALL); blk_insert_bs(blk, bs_verify, &error_abort); /* Switch the AioContext */ From 87278af1d9bac404e1c64ee2b652193a4c2628a6 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:40 +0200 Subject: [PATCH 0566/2595] block: Make bdrv_filter_default_perms() static Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-31-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 17 +++++++++++------ include/block/block_int.h | 10 ---------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/block.c b/block.c index fb94adcca4..54bc1c3b2d 100644 --- a/block.c +++ b/block.c @@ -2382,12 +2382,17 @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) return bdrv_child_try_set_perm(c, perms, shared, errp); } -void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, - BdrvChildRole role, - BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared) +/* + * Default implementation for .bdrv_child_perm() for block filters: + * Forward CONSISTENT_READ, WRITE, WRITE_UNCHANGED, and RESIZE to the + * filtered child. + */ +static void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, + const BdrvChildClass *child_class, + BdrvChildRole role, + BlockReopenQueue *reopen_queue, + uint64_t perm, uint64_t shared, + uint64_t *nperm, uint64_t *nshared) { *nperm = perm & DEFAULT_PERM_PASSTHROUGH; *nshared = (shared & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED; diff --git a/include/block/block_int.h b/include/block/block_int.h index 0781d43af5..6fc5f0d333 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -1262,16 +1262,6 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, */ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); -/* Default implementation for BlockDriver.bdrv_child_perm() that can be used by - * block filters: Forward CONSISTENT_READ, WRITE, WRITE_UNCHANGED and RESIZE to - * all children */ -void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, - BdrvChildRole child_role, - BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared); - /* Default implementation for BlockDriver.bdrv_child_perm() that can be used by * (non-raw) image formats: Like above for bs->backing, but for bs->file it * requires WRITE | RESIZE for read-write images, always requires From 9aab945e9cad484d668dbd26b023261223a4b02f Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:41 +0200 Subject: [PATCH 0567/2595] block: Drop bdrv_format_default_perms() Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-Id: <20200513110544.176672-32-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 19 ------------------- include/block/block_int.h | 11 ----------- 2 files changed, 30 deletions(-) diff --git a/block.c b/block.c index 54bc1c3b2d..e79fe6e07e 100644 --- a/block.c +++ b/block.c @@ -2517,25 +2517,6 @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, *nshared = shared; } -void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, - BdrvChildRole role, - BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared) -{ - if (child_class == &child_of_bds) { - bdrv_default_perms(bs, c, child_class, role, reopen_queue, - perm, shared, nperm, nshared); - return; - } - - assert(child_class == &child_file); - - bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, - perm, shared, nperm, nshared); -} - void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, diff --git a/include/block/block_int.h b/include/block/block_int.h index 6fc5f0d333..e791c40496 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -1262,17 +1262,6 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, */ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); -/* Default implementation for BlockDriver.bdrv_child_perm() that can be used by - * (non-raw) image formats: Like above for bs->backing, but for bs->file it - * requires WRITE | RESIZE for read-write images, always requires - * CONSISTENT_READ and doesn't share WRITE. */ -void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, - BdrvChildRole child_role, - BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared); - bool bdrv_recurse_can_replace(BlockDriverState *bs, BlockDriverState *to_replace); From f6de853fa3d76b4b92032dc6cdc06bedacbf9466 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:42 +0200 Subject: [PATCH 0568/2595] block: Drop child_file Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-33-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 39 ++------------------------------------- include/block/block_int.h | 1 - tests/test-bdrv-drain.c | 8 +++----- 3 files changed, 5 insertions(+), 43 deletions(-) diff --git a/block.c b/block.c index e79fe6e07e..6a24b23d51 100644 --- a/block.c +++ b/block.c @@ -80,13 +80,6 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, BdrvChildRole child_role, Error **errp); -/* TODO: Remove when no longer needed */ -static void bdrv_inherited_options(BdrvChildRole role, bool parent_is_format, - int *child_flags, QDict *child_options, - int parent_flags, QDict *parent_options); -static void bdrv_child_cb_attach(BdrvChild *child); -static void bdrv_child_cb_detach(BdrvChild *child); - /* If non-zero, use only whitelisted block drivers */ static int use_bdrv_whitelist; @@ -1145,33 +1138,6 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options, *child_flags &= ~BDRV_O_NATIVE_AIO; } -/* - * Returns the options and flags that bs->file should get if a protocol driver - * is expected, based on the given options and flags for the parent BDS - */ -static void bdrv_protocol_options(BdrvChildRole role, bool parent_is_format, - int *child_flags, QDict *child_options, - int parent_flags, QDict *parent_options) -{ - bdrv_inherited_options(BDRV_CHILD_IMAGE, true, - child_flags, child_options, - parent_flags, parent_options); -} - -const BdrvChildClass child_file = { - .parent_is_bds = true, - .get_parent_desc = bdrv_child_get_parent_desc, - .inherit_options = bdrv_protocol_options, - .drained_begin = bdrv_child_cb_drained_begin, - .drained_poll = bdrv_child_cb_drained_poll, - .drained_end = bdrv_child_cb_drained_end, - .attach = bdrv_child_cb_attach, - .detach = bdrv_child_cb_detach, - .inactivate = bdrv_child_cb_inactivate, - .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx, - .set_aio_ctx = bdrv_child_cb_set_aio_ctx, -}; - static void bdrv_backing_attach(BdrvChild *c) { BlockDriverState *parent = c->opaque; @@ -2444,9 +2410,8 @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, { int flags; - assert(child_class == &child_file || - (child_class == &child_of_bds && - (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)))); + assert(child_class == &child_of_bds && + (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA))); flags = bdrv_reopen_get_flags(reopen_queue, bs); diff --git a/include/block/block_int.h b/include/block/block_int.h index e791c40496..7fbe3206b4 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -741,7 +741,6 @@ struct BdrvChildClass { }; extern const BdrvChildClass child_of_bds; -extern const BdrvChildClass child_file; struct BdrvChild { BlockDriverState *bs; diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 0da5a3a6a1..655fd0d085 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -93,12 +93,10 @@ static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, uint64_t *nperm, uint64_t *nshared) { /* - * bdrv_default_perms() accepts only these two, so disguise - * detach_by_driver_cb_parent as one of them. + * bdrv_default_perms() accepts nothing else, so disguise + * detach_by_driver_cb_parent. */ - if (child_class != &child_file && child_class != &child_of_bds) { - child_class = &child_of_bds; - } + child_class = &child_of_bds; bdrv_default_perms(bs, c, child_class, role, reopen_queue, perm, shared, nperm, nshared); From 1f38f04eacd4c3b9409dcb411525f203cce168a1 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:43 +0200 Subject: [PATCH 0569/2595] block: Pass BdrvChildRole in remaining cases These calls have no real use for the child role yet, but it will not harm to give one. Notably, the bdrv_root_attach_child() call in blockjob.c is left unmodified because there is not much the generic BlockJob object wants from its children. Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-34-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/block-backend.c | 11 +++++++---- block/vvfat.c | 4 +++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index f2e81af27d..6936b25c83 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -424,8 +424,9 @@ BlockBackend *blk_new_open(const char *filename, const char *reference, return NULL; } - blk->root = bdrv_root_attach_child(bs, "root", &child_root, 0, blk->ctx, - perm, BLK_PERM_ALL, blk, errp); + blk->root = bdrv_root_attach_child(bs, "root", &child_root, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, + blk->ctx, perm, BLK_PERM_ALL, blk, errp); if (!blk->root) { blk_unref(blk); return NULL; @@ -835,8 +836,10 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) { ThrottleGroupMember *tgm = &blk->public.throttle_group_member; bdrv_ref(bs); - blk->root = bdrv_root_attach_child(bs, "root", &child_root, 0, blk->ctx, - blk->perm, blk->shared_perm, blk, errp); + blk->root = bdrv_root_attach_child(bs, "root", &child_root, + BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, + blk->ctx, blk->perm, blk->shared_perm, + blk, errp); if (blk->root == NULL) { return -EPERM; } diff --git a/block/vvfat.c b/block/vvfat.c index e8848a0497..089abe1e29 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3184,7 +3184,9 @@ static int enable_write_target(BlockDriverState *bs, Error **errp) options = qdict_new(); qdict_put_str(options, "write-target.driver", "qcow"); s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs, - &child_vvfat_qcow, 0, false, errp); + &child_vvfat_qcow, + BDRV_CHILD_DATA | BDRV_CHILD_METADATA, + false, errp); qobject_unref(options); if (!s->qcow) { ret = -EINVAL; From e5d8a4068526d3fb692e3402485edd03bc11c084 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 13 May 2020 13:05:44 +0200 Subject: [PATCH 0570/2595] block: Drop @child_class from bdrv_child_perm() Implementations should decide the necessary permissions based on @role. Signed-off-by: Max Reitz Message-Id: <20200513110544.176672-35-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 39 +++++++++++++++---------------------- block/backup-top.c | 3 +-- block/blkdebug.c | 3 +-- block/blklogwrites.c | 3 +-- block/commit.c | 1 - block/copy-on-read.c | 1 - block/mirror.c | 1 - block/quorum.c | 1 - block/replication.c | 1 - block/vvfat.c | 4 +--- include/block/block_int.h | 4 +--- tests/test-bdrv-drain.c | 19 +----------------- tests/test-bdrv-graph-mod.c | 1 - 13 files changed, 22 insertions(+), 59 deletions(-) diff --git a/block.c b/block.c index 6a24b23d51..8416376c9b 100644 --- a/block.c +++ b/block.c @@ -1947,13 +1947,13 @@ bool bdrv_is_writable(BlockDriverState *bs) } static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, - BdrvChild *c, const BdrvChildClass *child_class, - BdrvChildRole role, BlockReopenQueue *reopen_queue, + BdrvChild *c, BdrvChildRole role, + BlockReopenQueue *reopen_queue, uint64_t parent_perm, uint64_t parent_shared, uint64_t *nperm, uint64_t *nshared) { assert(bs->drv && bs->drv->bdrv_child_perm); - bs->drv->bdrv_child_perm(bs, c, child_class, role, reopen_queue, + bs->drv->bdrv_child_perm(bs, c, role, reopen_queue, parent_perm, parent_shared, nperm, nshared); /* TODO Take force_share from reopen_queue */ @@ -2047,7 +2047,7 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, uint64_t cur_perm, cur_shared; bool child_tighten_restr; - bdrv_child_perm(bs, c->bs, c, c->klass, c->role, q, + bdrv_child_perm(bs, c->bs, c, c->role, q, cumulative_perms, cumulative_shared_perms, &cur_perm, &cur_shared); ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, ignore_children, @@ -2114,7 +2114,7 @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms, /* Update all children */ QLIST_FOREACH(c, &bs->children, next) { uint64_t cur_perm, cur_shared; - bdrv_child_perm(bs, c->bs, c, c->klass, c->role, NULL, + bdrv_child_perm(bs, c->bs, c, c->role, NULL, cumulative_perms, cumulative_shared_perms, &cur_perm, &cur_shared); bdrv_child_set_perm(c, cur_perm, cur_shared); @@ -2342,7 +2342,7 @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) uint64_t perms, shared; bdrv_get_cumulative_perm(bs, &parent_perms, &parent_shared); - bdrv_child_perm(bs, c->bs, c, c->klass, c->role, NULL, + bdrv_child_perm(bs, c->bs, c, c->role, NULL, parent_perms, parent_shared, &perms, &shared); return bdrv_child_try_set_perm(c, perms, shared, errp); @@ -2354,7 +2354,6 @@ int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) * filtered child. */ static void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, @@ -2365,13 +2364,12 @@ static void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, } static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { - assert(child_class == &child_of_bds && (role & BDRV_CHILD_COW)); + assert(role & BDRV_CHILD_COW); /* * We want consistent read from backing files if the parent needs it. @@ -2402,7 +2400,6 @@ static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c, } static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, @@ -2410,8 +2407,7 @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, { int flags; - assert(child_class == &child_of_bds && - (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA))); + assert(role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)); flags = bdrv_reopen_get_flags(reopen_queue, bs); @@ -2419,7 +2415,7 @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, * Apart from the modifications below, the same permissions are * forwarded and left alone as for filters */ - bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, + bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, &perm, &shared); if (role & BDRV_CHILD_METADATA) { @@ -2483,24 +2479,21 @@ static void bdrv_default_perms_for_storage(BlockDriverState *bs, BdrvChild *c, } void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, - BlockReopenQueue *reopen_queue, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { - assert(child_class == &child_of_bds); - if (role & BDRV_CHILD_FILTERED) { assert(!(role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | BDRV_CHILD_COW))); - bdrv_filter_default_perms(bs, c, child_class, role, reopen_queue, + bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared); } else if (role & BDRV_CHILD_COW) { assert(!(role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA))); - bdrv_default_perms_for_cow(bs, c, child_class, role, reopen_queue, + bdrv_default_perms_for_cow(bs, c, role, reopen_queue, perm, shared, nperm, nshared); } else if (role & (BDRV_CHILD_METADATA | BDRV_CHILD_DATA)) { - bdrv_default_perms_for_storage(bs, c, child_class, role, reopen_queue, + bdrv_default_perms_for_storage(bs, c, role, reopen_queue, perm, shared, nperm, nshared); } else { g_assert_not_reached(); @@ -2744,7 +2737,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm); assert(parent_bs->drv); - bdrv_child_perm(parent_bs, child_bs, NULL, child_class, child_role, NULL, + bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL, perm, shared_perm, &perm, &shared_perm); child = bdrv_root_attach_child(child_bs, child_name, child_class, @@ -3807,7 +3800,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) if (state->replace_backing_bs && state->new_backing_bs) { uint64_t nperm, nshared; bdrv_child_perm(state->bs, state->new_backing_bs, - NULL, &child_of_bds, bdrv_backing_role(state->bs), + NULL, bdrv_backing_role(state->bs), bs_queue, state->perm, state->shared_perm, &nperm, &nshared); ret = bdrv_check_update_perm(state->new_backing_bs, NULL, @@ -3930,7 +3923,7 @@ static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs, } else { uint64_t nperm, nshared; - bdrv_child_perm(parent->state.bs, bs, c, c->klass, c->role, q, + bdrv_child_perm(parent->state.bs, bs, c, c->role, q, parent->state.perm, parent->state.shared_perm, &nperm, &nshared); diff --git a/block/backup-top.c b/block/backup-top.c index f0efec18b5..af2f20f346 100644 --- a/block/backup-top.c +++ b/block/backup-top.c @@ -122,7 +122,6 @@ static void backup_top_refresh_filename(BlockDriverState *bs) } static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, @@ -156,7 +155,7 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, *nperm = BLK_PERM_WRITE; } else { /* Source child */ - bdrv_default_perms(bs, c, child_class, role, reopen_queue, + bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared); if (perm & BLK_PERM_WRITE) { diff --git a/block/blkdebug.c b/block/blkdebug.c index a925d8295e..7194bc7f06 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -995,7 +995,6 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, } static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, @@ -1003,7 +1002,7 @@ static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c, { BDRVBlkdebugState *s = bs->opaque; - bdrv_default_perms(bs, c, child_class, role, reopen_queue, + bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared); *nperm |= s->take_child_perms; diff --git a/block/blklogwrites.c b/block/blklogwrites.c index 8684fb1c74..6753bd9a3e 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -283,7 +283,6 @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs) } static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *ro_q, uint64_t perm, uint64_t shrd, @@ -295,7 +294,7 @@ static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, return; } - bdrv_default_perms(bs, c, child_class, role, ro_q, perm, shrd, + bdrv_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd); } diff --git a/block/commit.c b/block/commit.c index 6af1c808bc..7732d02dfe 100644 --- a/block/commit.c +++ b/block/commit.c @@ -223,7 +223,6 @@ static void bdrv_commit_top_refresh_filename(BlockDriverState *bs) } static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, diff --git a/block/copy-on-read.c b/block/copy-on-read.c index c857ea0da7..a6e3c74a68 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -52,7 +52,6 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, #define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH) static void cor_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, diff --git a/block/mirror.c b/block/mirror.c index cb4bdad32a..e8e8844afc 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1492,7 +1492,6 @@ static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs) } static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, diff --git a/block/quorum.c b/block/quorum.c index 616ac3a927..7cf7ab1546 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -1153,7 +1153,6 @@ static char *quorum_dirname(BlockDriverState *bs, Error **errp) } static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, diff --git a/block/replication.c b/block/replication.c index cc9c473ad1..ccf7b78160 100644 --- a/block/replication.c +++ b/block/replication.c @@ -164,7 +164,6 @@ static void replication_close(BlockDriverState *bs) } static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, diff --git a/block/vvfat.c b/block/vvfat.c index 089abe1e29..c65a98e3ee 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3213,7 +3213,6 @@ err: } static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, @@ -3221,8 +3220,7 @@ static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, { BDRVVVFATState *s = bs->opaque; - assert(c == s->qcow || - (child_class == &child_of_bds && (role & BDRV_CHILD_COW))); + assert(c == s->qcow || (role & BDRV_CHILD_COW)); if (c == s->qcow) { /* This is a private node, nobody should try to attach to it */ diff --git a/include/block/block_int.h b/include/block/block_int.h index 7fbe3206b4..5e4f4c348c 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -563,7 +563,6 @@ struct BlockDriver { * @reopen_queue. */ void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t parent_perm, uint64_t parent_shared, @@ -1270,8 +1269,7 @@ bool bdrv_recurse_can_replace(BlockDriverState *bs, * child_of_bds child class and set an appropriate BdrvChildRole. */ void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, - BlockReopenQueue *reopen_queue, + BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared); diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 655fd0d085..1107271840 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -85,23 +85,6 @@ static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, return 0; } -static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, - BdrvChildRole role, - BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared) -{ - /* - * bdrv_default_perms() accepts nothing else, so disguise - * detach_by_driver_cb_parent. - */ - child_class = &child_of_bds; - - bdrv_default_perms(bs, c, child_class, role, reopen_queue, - perm, shared, nperm, nshared); -} - static int bdrv_test_change_backing_file(BlockDriverState *bs, const char *backing_file, const char *backing_fmt) @@ -119,7 +102,7 @@ static BlockDriver bdrv_test = { .bdrv_co_drain_begin = bdrv_test_co_drain_begin, .bdrv_co_drain_end = bdrv_test_co_drain_end, - .bdrv_child_perm = bdrv_test_child_perm, + .bdrv_child_perm = bdrv_default_perms, .bdrv_change_backing_file = bdrv_test_change_backing_file, }; diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c index a2d0318b16..f93f3168b0 100644 --- a/tests/test-bdrv-graph-mod.c +++ b/tests/test-bdrv-graph-mod.c @@ -30,7 +30,6 @@ static BlockDriver bdrv_pass_through = { }; static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildClass *child_class, BdrvChildRole role, BlockReopenQueue *reopen_queue, uint64_t perm, uint64_t shared, From c78dd00e3529f923280e2ab51e60dfcdad2c6094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 7 May 2020 14:11:28 +0200 Subject: [PATCH 0571/2595] block/block-copy: Fix uninitialized variable in block_copy_task_entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix when building with -Os: CC block/block-copy.o block/block-copy.c: In function ‘block_copy_task_entry’: block/block-copy.c:428:38: error: ‘error_is_read’ may be used uninitialized in this function [-Werror=maybe-uninitialized] 428 | t->call_state->error_is_read = error_is_read; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~ Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200507121129.29760-2-philmd@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/block-copy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/block-copy.c b/block/block-copy.c index 4713c8f2a3..7c7f7acbae 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -418,7 +418,7 @@ out: static coroutine_fn int block_copy_task_entry(AioTask *task) { BlockCopyTask *t = container_of(task, BlockCopyTask, task); - bool error_is_read; + bool error_is_read = false; int ret; ret = block_copy_do_copy(t->s, t->offset, t->bytes, t->zeroes, From d7eca542228bf3ca03c615c46ea2253590d57cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 7 May 2020 14:11:29 +0200 Subject: [PATCH 0572/2595] block/block-copy: Simplify block_copy_do_copy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit block_copy_do_copy() is static, only used in block_copy_task_entry with the error_is_read argument set. No need to check for it, simplify. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200507121129.29760-3-philmd@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/block-copy.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/block/block-copy.c b/block/block-copy.c index 7c7f7acbae..bb8d0569f2 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -343,9 +343,7 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s, ~BDRV_REQ_WRITE_COMPRESSED); if (ret < 0) { trace_block_copy_write_zeroes_fail(s, offset, ret); - if (error_is_read) { - *error_is_read = false; - } + *error_is_read = false; } return ret; } @@ -393,9 +391,7 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s, ret = bdrv_co_pread(s->source, offset, nbytes, bounce_buffer, 0); if (ret < 0) { trace_block_copy_read_fail(s, offset, ret); - if (error_is_read) { - *error_is_read = true; - } + *error_is_read = true; goto out; } @@ -403,9 +399,7 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s, s->write_flags); if (ret < 0) { trace_block_copy_write_fail(s, offset, ret); - if (error_is_read) { - *error_is_read = false; - } + *error_is_read = false; goto out; } From 44a46a9cd9f088e1a9655f2af8cb72ec36dfc731 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 14 May 2020 16:16:12 -0400 Subject: [PATCH 0573/2595] iotests: log messages from notrun() Shift the logging initialization up to occur prior to validation checks, so that notrun() messages still get printed to console. (Also, remove the "debugging messages active" message, because we don't need to see that hundreds of times per iotest suite run.) Signed-off-by: John Snow Message-Id: <20200514201614.19941-2-jsnow@redhat.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/iotests.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 1d7f6fd7cf..f20d90f969 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -1168,18 +1168,17 @@ def execute_setup_common(supported_fmts: Sequence[str] = (), sys.stderr.write('Please run this test via the "check" script\n') sys.exit(os.EX_USAGE) + debug = '-d' in sys.argv + if debug: + sys.argv.remove('-d') + logging.basicConfig(level=(logging.DEBUG if debug else logging.WARN)) + _verify_image_format(supported_fmts, unsupported_fmts) _verify_protocol(supported_protocols, unsupported_protocols) _verify_platform(supported=supported_platforms) _verify_cache_mode(supported_cache_modes) _verify_aio_mode(supported_aio_modes) - debug = '-d' in sys.argv - if debug: - sys.argv.remove('-d') - logging.basicConfig(level=(logging.DEBUG if debug else logging.WARN)) - logger.debug("iotests debugging messages active") - return debug def execute_test(*args, test_function=None, **kwargs): From c5f12a80c6472bc158e5092c731bbc7affaca2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 11:48:58 +0200 Subject: [PATCH 0574/2595] hw/ide/ahci: Log lost IRQs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One might find interesting to look at AHCI IRQs. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200504094858.5975-1-f4bug@amsat.org> Reviewed-by: John Snow Acked-by: John Snow Signed-off-by: Kevin Wolf --- hw/ide/ahci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 13d91e109a..fc82cbd5f1 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1509,6 +1509,7 @@ static void ahci_cmd_done(IDEDMA *dma) static void ahci_irq_set(void *opaque, int n, int level) { + qemu_log_mask(LOG_UNIMP, "ahci: IRQ#%d level:%d\n", n, level); } static const IDEDMAOps ahci_dma_ops = { From b1b30ff4df942ef75abb3799889ab2f4c52155e9 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 13 May 2020 12:00:25 +0200 Subject: [PATCH 0575/2595] iotests/030: Reduce run time by unthrottling job earlier test_overlapping_3() throttles its active commit job so it can be sure the job is still busy when it checks that you can't start a conflicting streaming job. However, it only sets the commit job back to full speed when it is ready, which takes a few seconds while it's throttled. We can already reset the limit after having checked that block-stream returns an error and save these seconds. Signed-off-by: Kevin Wolf Message-Id: <20200513100025.33543-1-kwolf@redhat.com> Reviewed-by: Alberto Garcia Signed-off-by: Kevin Wolf --- tests/qemu-iotests/030 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index 104e3cee1b..1cdd7e2999 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -354,14 +354,14 @@ class TestParallelOps(iotests.QMPTestCase): self.assert_qmp(result, 'error/desc', "Node 'node5' is busy: block device is in use by block job: commit") + result = self.vm.qmp('block-job-set-speed', device='commit-drive0', speed=0) + self.assert_qmp(result, 'return', {}) + event = self.vm.event_wait(name='BLOCK_JOB_READY') self.assert_qmp(event, 'data/device', 'commit-drive0') self.assert_qmp(event, 'data/type', 'commit') self.assert_qmp_absent(event, 'data/error') - result = self.vm.qmp('block-job-set-speed', device='commit-drive0', speed=0) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('block-job-complete', device='commit-drive0') self.assert_qmp(result, 'return', {}) From 4cdd0a774dc35b2ffe6ddb634e0c431f17dfe07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 11 May 2020 22:52:46 +0200 Subject: [PATCH 0576/2595] hw: Use QEMU_IS_ALIGNED() on parallel flash block size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the QEMU_IS_ALIGNED() macro to verify the flash block size is properly aligned. It is quicker to process when reviewing. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200511205246.24621-1-philmd@redhat.com> Reviewed-by: Alistair Francis Reviewed-by: Peter Maydell Acked-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- hw/arm/sbsa-ref.c | 2 +- hw/arm/virt.c | 2 +- hw/block/pflash_cfi01.c | 2 +- hw/block/pflash_cfi02.c | 2 +- hw/i386/pc_sysfw.c | 2 +- hw/riscv/virt.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index a6cdb4fb7b..6a0221a681 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -240,7 +240,7 @@ static void sbsa_flash_map1(PFlashCFI01 *flash, { DeviceState *dev = DEVICE(flash); - assert(size % SBSA_FLASH_SECTOR_SIZE == 0); + assert(QEMU_IS_ALIGNED(size, SBSA_FLASH_SECTOR_SIZE)); assert(size / SBSA_FLASH_SECTOR_SIZE <= UINT32_MAX); qdev_prop_set_uint32(dev, "num-blocks", size / SBSA_FLASH_SECTOR_SIZE); qdev_init_nofail(dev); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index c41d5f9778..37462a6f78 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -977,7 +977,7 @@ static void virt_flash_map1(PFlashCFI01 *flash, { DeviceState *dev = DEVICE(flash); - assert(size % VIRT_FLASH_SECTOR_SIZE == 0); + assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE)); assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE); qdev_init_nofail(dev); diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 24f3bce7ef..8e8887253d 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -965,7 +965,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, if (blk) { qdev_prop_set_drive(dev, "drive", blk, &error_abort); } - assert(size % sector_len == 0); + assert(QEMU_IS_ALIGNED(size, sector_len)); qdev_prop_set_uint32(dev, "num-blocks", size / sector_len); qdev_prop_set_uint64(dev, "sector-length", sector_len); qdev_prop_set_uint8(dev, "width", bank_width); diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index f0579ecb17..c277b0309d 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -997,7 +997,7 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base, if (blk) { qdev_prop_set_drive(dev, "drive", blk, &error_abort); } - assert(size % sector_len == 0); + assert(QEMU_IS_ALIGNED(size, sector_len)); qdev_prop_set_uint32(dev, "num-blocks", size / sector_len); qdev_prop_set_uint32(dev, "sector-length", sector_len); qdev_prop_set_uint8(dev, "width", width); diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index 2abab3a27c..b8d8ef59eb 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -167,7 +167,7 @@ static void pc_system_flash_map(PCMachineState *pcms, blk_name(blk), strerror(-size)); exit(1); } - if (size == 0 || size % FLASH_SECTOR_SIZE != 0) { + if (size == 0 || !QEMU_IS_ALIGNED(size, FLASH_SECTOR_SIZE)) { error_report("system firmware block device %s has invalid size " "%" PRId64, blk_name(blk), size); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index c695a44979..7ce28895bc 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -111,7 +111,7 @@ static void virt_flash_map1(PFlashCFI01 *flash, { DeviceState *dev = DEVICE(flash); - assert(size % VIRT_FLASH_SECTOR_SIZE == 0); + assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE)); assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE); qdev_init_nofail(dev); From de137e44f75d9868f5b548638081850f6ac771f2 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 11 May 2020 19:36:29 +0100 Subject: [PATCH 0577/2595] aio-posix: don't duplicate fd handler deletion in fdmon_io_uring_destroy() The io_uring file descriptor monitoring implementation has an internal list of fd handlers that are pending submission to io_uring. fdmon_io_uring_destroy() deletes all fd handlers on the list. Don't delete fd handlers directly in fdmon_io_uring_destroy() for two reasons: 1. This duplicates the aio-posix.c AioHandler deletion code and could become outdated if the struct changes. 2. Only handlers with the FDMON_IO_URING_REMOVE flag set are safe to remove. If the flag is not set then something still has a pointer to the fd handler. Let aio-posix.c and its user worry about that. In practice this isn't an issue because fdmon_io_uring_destroy() is only called when shutting down so all users have removed their fd handlers, but the next patch will need this! Signed-off-by: Stefan Hajnoczi Tested-by: Oleksandr Natalenko Message-id: 20200511183630.279750-2-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- util/aio-posix.c | 1 + util/fdmon-io_uring.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/util/aio-posix.c b/util/aio-posix.c index c3613d299e..8af334ab19 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -679,6 +679,7 @@ void aio_context_destroy(AioContext *ctx) { fdmon_io_uring_destroy(ctx); fdmon_epoll_disable(ctx); + aio_free_deleted_handlers(ctx); } void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, diff --git a/util/fdmon-io_uring.c b/util/fdmon-io_uring.c index d5a80ed6fb..1d14177df0 100644 --- a/util/fdmon-io_uring.c +++ b/util/fdmon-io_uring.c @@ -342,11 +342,18 @@ void fdmon_io_uring_destroy(AioContext *ctx) io_uring_queue_exit(&ctx->fdmon_io_uring); - /* No need to submit these anymore, just free them. */ + /* Move handlers due to be removed onto the deleted list */ while ((node = QSLIST_FIRST_RCU(&ctx->submit_list))) { + unsigned flags = atomic_fetch_and(&node->flags, + ~(FDMON_IO_URING_PENDING | + FDMON_IO_URING_ADD | + FDMON_IO_URING_REMOVE)); + + if (flags & FDMON_IO_URING_REMOVE) { + QLIST_INSERT_HEAD_RCU(&ctx->deleted_aio_handlers, node, node_deleted); + } + QSLIST_REMOVE_HEAD_RCU(&ctx->submit_list, node_submitted); - QLIST_REMOVE(node, node); - g_free(node); } ctx->fdmon_ops = &fdmon_poll_ops; From ba607ca8bff4d2c2062902f8355657c865ac7c29 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 11 May 2020 19:36:30 +0100 Subject: [PATCH 0578/2595] aio-posix: disable fdmon-io_uring when GSource is used The glib event loop does not call fdmon_io_uring_wait() so fd handlers waiting to be submitted build up in the list. There is no benefit is using io_uring when the glib GSource is being used, so disable it instead of implementing a more complex fix. This fixes a memory leak where AioHandlers would build up and increasing amounts of CPU time were spent iterating them in aio_pending(). The symptom is that guests become slow when QEMU is built with io_uring support. Buglink: https://bugs.launchpad.net/qemu/+bug/1877716 Fixes: 73fd282e7b6dd4e4ea1c3bbb3d302c8db51e4ccf ("aio-posix: add io_uring fd monitoring implementation") Signed-off-by: Stefan Hajnoczi Tested-by: Oleksandr Natalenko Message-id: 20200511183630.279750-3-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- include/block/aio.h | 3 +++ util/aio-posix.c | 12 ++++++++++++ util/aio-win32.c | 4 ++++ util/async.c | 1 + 4 files changed, 20 insertions(+) diff --git a/include/block/aio.h b/include/block/aio.h index 62ed954344..b2f703fa3f 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -701,6 +701,9 @@ void aio_context_setup(AioContext *ctx); */ void aio_context_destroy(AioContext *ctx); +/* Used internally, do not call outside AioContext code */ +void aio_context_use_g_source(AioContext *ctx); + /** * aio_context_set_poll_params: * @ctx: the aio context diff --git a/util/aio-posix.c b/util/aio-posix.c index 8af334ab19..1b2a3af65b 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -682,6 +682,18 @@ void aio_context_destroy(AioContext *ctx) aio_free_deleted_handlers(ctx); } +void aio_context_use_g_source(AioContext *ctx) +{ + /* + * Disable io_uring when the glib main loop is used because it doesn't + * support mixed glib/aio_poll() usage. It relies on aio_poll() being + * called regularly so that changes to the monitored file descriptors are + * submitted, otherwise a list of pending fd handlers builds up. + */ + fdmon_io_uring_destroy(ctx); + aio_free_deleted_handlers(ctx); +} + void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, int64_t grow, int64_t shrink, Error **errp) { diff --git a/util/aio-win32.c b/util/aio-win32.c index 729d533faf..953c56ab48 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -414,6 +414,10 @@ void aio_context_destroy(AioContext *ctx) { } +void aio_context_use_g_source(AioContext *ctx) +{ +} + void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, int64_t grow, int64_t shrink, Error **errp) { diff --git a/util/async.c b/util/async.c index 3165a28f2f..1319eee3bc 100644 --- a/util/async.c +++ b/util/async.c @@ -362,6 +362,7 @@ static GSourceFuncs aio_source_funcs = { GSource *aio_get_g_source(AioContext *ctx) { + aio_context_use_g_source(ctx); g_source_ref(&ctx->source); return &ctx->source; } From 2df9f5718df7722924699a3754f99165e2f4ae35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:04 +0200 Subject: [PATCH 0579/2595] ui/win32-kbd-hook: handle AltGr in a hook procedure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Import win32 keyboard hooking code from project spice-gtk. This patch removes the extra left control key up/down input events inserted by Windows for the right alt key up/down input events with international keyboard layouts. Additionally there's some code to grab the keyboard. The next patches will use this code. Only Windows needs this. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-1-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- include/ui/win32-kbd-hook.h | 14 +++++ stubs/Makefile.objs | 1 + stubs/win32-kbd-hook.c | 18 +++++++ ui/Makefile.objs | 3 ++ ui/win32-kbd-hook.c | 102 ++++++++++++++++++++++++++++++++++++ 5 files changed, 138 insertions(+) create mode 100644 include/ui/win32-kbd-hook.h create mode 100644 stubs/win32-kbd-hook.c create mode 100644 ui/win32-kbd-hook.c diff --git a/include/ui/win32-kbd-hook.h b/include/ui/win32-kbd-hook.h new file mode 100644 index 0000000000..4bd9f00f97 --- /dev/null +++ b/include/ui/win32-kbd-hook.h @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef UI_WIN32_KBD_HOOK_H +#define UI_WIN32_KBD_HOOK_H + +void win32_kbd_set_window(void *hwnd); +void win32_kbd_set_grab(bool grab); + +#endif diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 45be5dc0ed..6a9e3135e8 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -32,6 +32,7 @@ stub-obj-y += trace-control.o stub-obj-y += uuid.o stub-obj-y += vm-stop.o stub-obj-y += vmstate.o +stub-obj-y += win32-kbd-hook.o stub-obj-y += fd-register.o stub-obj-y += qmp_memory_device.o stub-obj-y += target-monitor-defs.o diff --git a/stubs/win32-kbd-hook.c b/stubs/win32-kbd-hook.c new file mode 100644 index 0000000000..1a084b081a --- /dev/null +++ b/stubs/win32-kbd-hook.c @@ -0,0 +1,18 @@ +/* + * Win32 keyboard hook stubs + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" +#include "ui/win32-kbd-hook.h" + +void win32_kbd_set_window(void *hwnd) +{ +} + +void win32_kbd_set_grab(bool grab) +{ +} diff --git a/ui/Makefile.objs b/ui/Makefile.objs index e6da6ff047..504b196479 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -15,6 +15,9 @@ common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o common-obj-$(CONFIG_COCOA) += cocoa.o common-obj-$(CONFIG_VNC) += $(vnc-obj-y) common-obj-$(call lnot,$(CONFIG_VNC)) += vnc-stubs.o +ifneq (,$(findstring m,$(CONFIG_SDL)$(CONFIG_GTK))) +common-obj-$(CONFIG_WIN32) += win32-kbd-hook.o +endif # ui-sdl module common-obj-$(CONFIG_SDL) += sdl.mo diff --git a/ui/win32-kbd-hook.c b/ui/win32-kbd-hook.c new file mode 100644 index 0000000000..1ac237db9e --- /dev/null +++ b/ui/win32-kbd-hook.c @@ -0,0 +1,102 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + * + * The win32 keyboard hooking code was imported from project spice-gtk. + */ + +#include "qemu/osdep.h" +#include "sysemu/sysemu.h" +#include "ui/win32-kbd-hook.h" + +static Notifier win32_unhook_notifier; +static HHOOK win32_keyboard_hook; +static HWND win32_window; +static DWORD win32_grab; + +static LRESULT CALLBACK keyboard_hook_cb(int code, WPARAM wparam, LPARAM lparam) +{ + if (win32_window && code == HC_ACTION && win32_window == GetFocus()) { + KBDLLHOOKSTRUCT *hooked = (KBDLLHOOKSTRUCT *)lparam; + + if (wparam != WM_KEYUP) { + DWORD dwmsg = (hooked->flags << 24) | + ((hooked->scanCode & 0xff) << 16) | 1; + + switch (hooked->vkCode) { + case VK_CAPITAL: + /* fall through */ + case VK_SCROLL: + /* fall through */ + case VK_NUMLOCK: + /* fall through */ + case VK_LSHIFT: + /* fall through */ + case VK_RSHIFT: + /* fall through */ + case VK_RCONTROL: + /* fall through */ + case VK_LMENU: + /* fall through */ + case VK_RMENU: + break; + + case VK_LCONTROL: + /* + * When pressing AltGr, an extra VK_LCONTROL with a special + * scancode with bit 9 set is sent. Let's ignore the extra + * VK_LCONTROL, as that will make AltGr misbehave. + */ + if (hooked->scanCode & 0x200) { + return 1; + } + break; + + default: + if (win32_grab) { + SendMessage(win32_window, wparam, hooked->vkCode, dwmsg); + return 1; + } + break; + } + + } else { + switch (hooked->vkCode) { + case VK_LCONTROL: + if (hooked->scanCode & 0x200) { + return 1; + } + break; + } + } + } + + return CallNextHookEx(NULL, code, wparam, lparam); +} + +static void keyboard_hook_unhook(Notifier *n, void *data) +{ + UnhookWindowsHookEx(win32_keyboard_hook); + win32_keyboard_hook = NULL; +} + +void win32_kbd_set_window(void *hwnd) +{ + if (hwnd && !win32_keyboard_hook) { + /* note: the installing thread must have a message loop */ + win32_keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_cb, + GetModuleHandle(NULL), 0); + if (win32_keyboard_hook) { + win32_unhook_notifier.notify = keyboard_hook_unhook; + qemu_add_exit_notifier(&win32_unhook_notifier); + } + } + + win32_window = hwnd; +} + +void win32_kbd_set_grab(bool grab) +{ + win32_grab = grab; +} From bd593d2cd9932ea20593c4e6960d84fd59854130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:05 +0200 Subject: [PATCH 0580/2595] ui/gtk: fix handling of AltGr key on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire up the keyboard hooking code on Windows to fix the AltGr key and improve keyboard grabbing. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-2-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/ui/gtk.c b/ui/gtk.c index 83f2f5d49b..a0b10a1403 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -38,6 +38,10 @@ #include "ui/console.h" #include "ui/gtk.h" +#ifdef G_OS_WIN32 +#include +#endif +#include "ui/win32-kbd-hook.h" #include #include @@ -428,6 +432,16 @@ static void gd_widget_reparent(GtkWidget *from, GtkWidget *to, g_object_unref(G_OBJECT(widget)); } +static void *gd_win32_get_hwnd(VirtualConsole *vc) +{ +#ifdef G_OS_WIN32 + return gdk_win32_window_get_impl_hwnd( + gtk_widget_get_window(vc->window ? vc->window : vc->s->window)); +#else + return NULL; +#endif +} + /** DisplayState Callbacks **/ static void gd_update(DisplayChangeListener *dcl, @@ -1451,6 +1465,7 @@ static void gd_grab_keyboard(VirtualConsole *vc, const char *reason) } } + win32_kbd_set_grab(true); #if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, true, vc->s->ptr_owner == vc); #else @@ -1472,6 +1487,7 @@ static void gd_ungrab_keyboard(GtkDisplayState *s) } s->kbd_owner = NULL; + win32_kbd_set_grab(false); #if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, false, vc->s->ptr_owner == vc); #else @@ -1614,12 +1630,22 @@ static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing, return TRUE; } +static gboolean gd_focus_in_event(GtkWidget *widget, + GdkEventFocus *event, gpointer opaque) +{ + VirtualConsole *vc = opaque; + + win32_kbd_set_window(gd_win32_get_hwnd(vc)); + return TRUE; +} + static gboolean gd_focus_out_event(GtkWidget *widget, - GdkEventCrossing *crossing, gpointer opaque) + GdkEventFocus *event, gpointer opaque) { VirtualConsole *vc = opaque; GtkDisplayState *s = vc->s; + win32_kbd_set_window(NULL); gtk_release_modifiers(s); return TRUE; } @@ -1878,6 +1904,8 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc) G_CALLBACK(gd_enter_event), vc); g_signal_connect(vc->gfx.drawing_area, "leave-notify-event", G_CALLBACK(gd_leave_event), vc); + g_signal_connect(vc->gfx.drawing_area, "focus-in-event", + G_CALLBACK(gd_focus_in_event), vc); g_signal_connect(vc->gfx.drawing_area, "focus-out-event", G_CALLBACK(gd_focus_out_event), vc); g_signal_connect(vc->gfx.drawing_area, "configure-event", From 0c4b1a7dc597499814d6222da4c95cbf9de68ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:06 +0200 Subject: [PATCH 0581/2595] ui/gkt: release all keys on grab-broken-event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no way to grab the Ctrl-Alt-Del key combination on Windows. This key combination will leave all three keys in a stuck condition. This patch uses the grab-broken-event to release the keys. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-3-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index a0b10a1403..655b26de38 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1142,6 +1142,25 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) return TRUE; } +static gboolean gd_grab_broken_event(GtkWidget *widget, + GdkEventGrabBroken *event, void *opaque) +{ +#ifdef CONFIG_WIN32 + /* + * On Windows the Ctrl-Alt-Del key combination can't be grabbed. This + * key combination leaves all three keys in a stuck condition. We use + * the grab-broken-event to release all keys. + */ + if (event->keyboard) { + VirtualConsole *vc = opaque; + GtkDisplayState *s = vc->s; + + gtk_release_modifiers(s); + } +#endif + return TRUE; +} + static gboolean gd_event(GtkWidget *widget, GdkEvent *event, void *opaque) { if (event->type == GDK_MOTION_NOTIFY) { @@ -1910,6 +1929,8 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc) G_CALLBACK(gd_focus_out_event), vc); g_signal_connect(vc->gfx.drawing_area, "configure-event", G_CALLBACK(gd_configure), vc); + g_signal_connect(vc->gfx.drawing_area, "grab-broken-event", + G_CALLBACK(gd_grab_broken_event), vc); } else { g_signal_connect(vc->gfx.drawing_area, "key-press-event", G_CALLBACK(gd_text_key_down), vc); From 9ef99eccb10002d785279d1fd1dc5b0f4c295bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:07 +0200 Subject: [PATCH 0582/2595] ui/gtk: remove unused code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code was last used before commit 2ec78706d1 "ui: convert GTK and SDL1 frontends to keycodemapdb". Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-4-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 655b26de38..0e9503a0d1 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -112,15 +112,6 @@ # define VTE_CHECK_VERSION(a, b, c) 0 #endif -/* Some older mingw versions lack this constant or have - * it conditionally defined */ -#ifdef _WIN32 -# ifndef MAPVK_VK_TO_VSC -# define MAPVK_VK_TO_VSC 0 -# endif -#endif - - #define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK) static const guint16 *keycode_map; From fd7c1bea17e4aaea45c00b37b7a2af5dd72b17f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:08 +0200 Subject: [PATCH 0583/2595] ui/gtk: remove unused variable ignore_keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the removal of GTK2 code in commit 89d85cde75 the code around ignore_keys is unused. See commit 1a01716a30 "gtk: Avoid accel key leakage into guest on console switch" why it was only needed for GTK2. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-5-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 0e9503a0d1..354dd90e18 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -168,8 +168,6 @@ struct GtkDisplayState { bool external_pause_update; - bool ignore_keys; - DisplayOptions *opts; }; @@ -1095,14 +1093,8 @@ static gboolean gd_text_key_down(GtkWidget *widget, static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) { VirtualConsole *vc = opaque; - GtkDisplayState *s = vc->s; int qcode; - if (s->ignore_keys) { - s->ignore_keys = (key->type == GDK_KEY_PRESS); - return TRUE; - } - #ifdef WIN32 /* on windows, we ought to ignore the reserved key event? */ if (key->hardware_keycode == 0xff) @@ -1204,7 +1196,6 @@ static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque) gtk_notebook_set_current_page(nb, page); gtk_widget_grab_focus(vc->focus); } - s->ignore_keys = false; } static void gd_accel_switch_vc(void *opaque) From 830473455fb94e7362c464a9b7667dca1004a5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:09 +0200 Subject: [PATCH 0584/2595] ui/sdl2: fix handling of AltGr key on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire up the keyboard hooking code on Windows to fix the AltGr key and improve keyboard grabbing. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-6-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/sdl2.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ui/sdl2.c b/ui/sdl2.c index 61c7956da3..79c1ea29d2 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -30,6 +30,7 @@ #include "ui/sdl2.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" +#include "ui/win32-kbd-hook.h" static int sdl2_num_outputs; static struct sdl2_console *sdl2_console; @@ -220,6 +221,7 @@ static void sdl_grab_start(struct sdl2_console *scon) } SDL_SetWindowGrab(scon->real_window, SDL_TRUE); gui_grab = 1; + win32_kbd_set_grab(true); sdl_update_caption(scon); } @@ -227,6 +229,7 @@ static void sdl_grab_end(struct sdl2_console *scon) { SDL_SetWindowGrab(scon->real_window, SDL_FALSE); gui_grab = 0; + win32_kbd_set_grab(false); sdl_show_cursor(scon); sdl_update_caption(scon); } @@ -325,6 +328,19 @@ static int get_mod_state(void) } } +static void *sdl2_win32_get_hwnd(struct sdl2_console *scon) +{ +#ifdef CONFIG_WIN32 + SDL_SysWMinfo info; + + SDL_VERSION(&info.version); + if (SDL_GetWindowWMInfo(scon->real_window, &info)) { + return info.info.win.window; + } +#endif + return NULL; +} + static void handle_keydown(SDL_Event *ev) { int win; @@ -544,6 +560,11 @@ static void handle_windowevent(SDL_Event *ev) sdl2_redraw(scon); break; case SDL_WINDOWEVENT_FOCUS_GAINED: + win32_kbd_set_grab(gui_grab); + if (qemu_console_is_graphic(scon->dcl.con)) { + win32_kbd_set_window(sdl2_win32_get_hwnd(scon)); + } + /* fall through */ case SDL_WINDOWEVENT_ENTER: if (!gui_grab && (qemu_input_is_absolute() || absolute_enabled)) { absolute_mouse_grab(scon); @@ -558,6 +579,9 @@ static void handle_windowevent(SDL_Event *ev) scon->ignore_hotkeys = get_mod_state(); break; case SDL_WINDOWEVENT_FOCUS_LOST: + if (qemu_console_is_graphic(scon->dcl.con)) { + win32_kbd_set_window(NULL); + } if (gui_grab && !gui_fullscreen) { sdl_grab_end(scon); } From 7dafc6793a5b1806bec4b1f233561b809c5cc649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:10 +0200 Subject: [PATCH 0585/2595] ui/sdl2: start in full screen with grab enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU with SDL 1.2 display used to enable keyboard and mouse grab- bing when started in full screen. The SDL 2.0 code tries to do the same but fails to enable grabbing because sdl_grab_start(0) returns early. To do it's work the sdl_grab_start() function needs a pointer to a sdl2_console structure. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-7-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/sdl2.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ui/sdl2.c b/ui/sdl2.c index 79c1ea29d2..b23a8f0a8e 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -881,17 +881,16 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) SDL_SetWindowIcon(sdl2_console[0].real_window, icon); } - gui_grab = 0; - if (gui_fullscreen) { - sdl_grab_start(0); - } - mouse_mode_notifier.notify = sdl_mouse_mode_change; qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier); sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0); sdl_cursor_normal = SDL_GetCursor(); + if (gui_fullscreen) { + sdl_grab_start(&sdl2_console[0]); + } + atexit(sdl_cleanup); } From 20a37f2fa3873ad62c31b40f55f2218ec9ff470b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:11 +0200 Subject: [PATCH 0586/2595] ui/sdl2-input: use trace-events to debug key events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-8-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/sdl2-input.c | 3 +++ ui/trace-events | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ui/sdl2-input.c b/ui/sdl2-input.c index 1f9fe831b3..f068382209 100644 --- a/ui/sdl2-input.c +++ b/ui/sdl2-input.c @@ -27,6 +27,7 @@ #include "ui/console.h" #include "ui/input.h" #include "ui/sdl2.h" +#include "trace.h" void sdl2_process_key(struct sdl2_console *scon, SDL_KeyboardEvent *ev) @@ -38,6 +39,8 @@ void sdl2_process_key(struct sdl2_console *scon, return; } qcode = qemu_input_map_usb_to_qcode[ev->keysym.scancode]; + trace_sdl2_process_key(ev->keysym.scancode, qcode, + ev->type == SDL_KEYDOWN ? "down" : "up"); qkbd_state_key_event(scon->kbd, qcode, ev->type == SDL_KEYDOWN); if (!qemu_console_is_graphic(con)) { diff --git a/ui/trace-events b/ui/trace-events index 0dcda393c1..5367fd3f16 100644 --- a/ui/trace-events +++ b/ui/trace-events @@ -75,6 +75,9 @@ input_event_abs(int conidx, const char *axis, int value) "con %d, axis %s, value input_event_sync(void) "" input_mouse_mode(int absolute) "absolute %d" +# sdl2-input.c +sdl2_process_key(int sdl_scancode, int qcode, const char *action) "translated SDL scancode %d to QKeyCode %d (%s)" + # spice-display.c qemu_spice_add_memslot(int qid, uint32_t slot_id, unsigned long virt_start, unsigned long virt_end, int async) "%d %u: host virt 0x%lx - 0x%lx async=%d" qemu_spice_del_memslot(int qid, uint32_t gid, uint32_t slot_id) "%d gid=%u sid=%u" From d3953bf7978521b6373cb8101f594cc44b0efa9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:12 +0200 Subject: [PATCH 0587/2595] ui/gtk: don't pass on win keys without keyboard grab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without keyboard grab Windows currently handles the two win keys and the key events are also sent to the guest. This is undesir- able. Only one program should handle key events. This patch ap- plies commit c68f74b02e "win32: do not handle win keys when the keyboard is not grabbed" from project spice-gtk to ui/gtk.c to fix this problem. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-9-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ui/gtk.c b/ui/gtk.c index 354dd90e18..1d51e14bb5 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1095,10 +1095,17 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) VirtualConsole *vc = opaque; int qcode; -#ifdef WIN32 +#ifdef G_OS_WIN32 /* on windows, we ought to ignore the reserved key event? */ if (key->hardware_keycode == 0xff) return false; + + if (!vc->s->kbd_owner) { + if (key->hardware_keycode == VK_LWIN || + key->hardware_keycode == VK_RWIN) { + return FALSE; + } + } #endif if (key->keyval == GDK_KEY_Pause From 145419274621f846385d35e609c051d4cbdd39a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:13 +0200 Subject: [PATCH 0588/2595] ui/gtk: use native keyboard scancodes on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since GTK 3.22 the function gdk_event_get_scancode() is available. On Windows this function returns keyboard scancodes and some extended flags. These raw keyboard scancodes are much better suited for this use case than the half-cooked win32 virtual-key codes because scancodes report the key position on the keyboard and the positions are independent of national language settings. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-10-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 1d51e14bb5..68a5b901c7 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1026,8 +1026,13 @@ static const guint16 *gd_get_keymap(size_t *maplen) #ifdef GDK_WINDOWING_WIN32 if (GDK_IS_WIN32_DISPLAY(dpy)) { trace_gd_keymap_windowing("win32"); +#if GTK_CHECK_VERSION(3, 22, 0) + *maplen = qemu_input_map_atset1_to_qcode_len; + return qemu_input_map_atset1_to_qcode; +#else *maplen = qemu_input_map_win32_to_qcode_len; return qemu_input_map_win32_to_qcode; +#endif } #endif @@ -1073,6 +1078,25 @@ static int gd_map_keycode(int scancode) return keycode_map[scancode]; } +static int gd_get_keycode(GdkEventKey *key) +{ +#if defined G_OS_WIN32 && GTK_CHECK_VERSION(3, 22, 0) + int scancode = gdk_event_get_scancode((GdkEvent *)key); + + /* translate Windows native scancodes to atset1 keycodes */ + switch (scancode & (KF_EXTENDED | 0xff)) { + case 0x145: /* NUMLOCK */ + return scancode & 0xff; + } + + return scancode & KF_EXTENDED ? + 0xe000 | (scancode & 0xff) : scancode & 0xff; + +#else + return key->hardware_keycode; +#endif +} + static gboolean gd_text_key_down(GtkWidget *widget, GdkEventKey *key, void *opaque) { @@ -1084,7 +1108,7 @@ static gboolean gd_text_key_down(GtkWidget *widget, } else if (key->length) { kbd_put_string_console(con, key->string, key->length); } else { - int qcode = gd_map_keycode(key->hardware_keycode); + int qcode = gd_map_keycode(gd_get_keycode(key)); kbd_put_qcode_console(con, qcode, false); } return TRUE; @@ -1093,7 +1117,7 @@ static gboolean gd_text_key_down(GtkWidget *widget, static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) { VirtualConsole *vc = opaque; - int qcode; + int keycode, qcode; #ifdef G_OS_WIN32 /* on windows, we ought to ignore the reserved key event? */ @@ -1121,9 +1145,10 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) return TRUE; } - qcode = gd_map_keycode(key->hardware_keycode); + keycode = gd_get_keycode(key); + qcode = gd_map_keycode(keycode); - trace_gd_key_event(vc->label, key->hardware_keycode, qcode, + trace_gd_key_event(vc->label, keycode, qcode, (key->type == GDK_KEY_PRESS) ? "down" : "up"); qkbd_state_key_event(vc->gfx.kbd, qcode, From 7b23d121f913709306e678a3289edc813f3a7463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 16 May 2020 09:20:14 +0200 Subject: [PATCH 0589/2595] ui: increase min required GTK version to 3.22.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on a mail on the qemu-devel mailing list at https://lists.nongnu.org/archive/html/qemu-devel/2020-05/msg02909.html and some internet research the GTK3 versions on supported platforms are: RHEL-7.4: 3.22.10 RHEL-7.5: 3.22.26 Debian (Stretch): 3.22.11 Debian (Buster): 3.24.5 OpenBSD (Ports): 3.22.30 FreeBSD (Ports): 3.22.29 OpenSUSE Leap 15: 3.22.30 SLE12-SP2: Unknown SLE15: 3.22.30 Ubuntu (Bionic): 3.22.30 Ubuntu (Focal): 3.24.18 macOS (Homebrew): 3.22.30 This justifies increasing the minimum required GTK version in QEMU to 3.22.0. Signed-off-by: Volker Rümelin Message-id: 20200516072014.7766-11-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- configure | 2 +- ui/gtk.c | 91 +++++-------------------------------------------------- 2 files changed, 9 insertions(+), 84 deletions(-) diff --git a/configure b/configure index 26084fc53a..2fc05c4465 100755 --- a/configure +++ b/configure @@ -2897,7 +2897,7 @@ fi if test "$gtk" != "no"; then gtkpackage="gtk+-3.0" gtkx11package="gtk+-x11-3.0" - gtkversion="3.14.0" + gtkversion="3.22.0" if $pkg_config --exists "$gtkpackage >= $gtkversion"; then gtk_cflags=$($pkg_config --cflags $gtkpackage) gtk_libs=$($pkg_config --libs $gtkpackage) diff --git a/ui/gtk.c b/ui/gtk.c index 68a5b901c7..d4b49bd7da 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -490,12 +490,7 @@ static void gd_refresh(DisplayChangeListener *dcl) static GdkDevice *gd_get_pointer(GdkDisplay *dpy) { -#if GTK_CHECK_VERSION(3, 20, 0) return gdk_seat_get_pointer(gdk_display_get_default_seat(dpy)); -#else - return gdk_device_manager_get_client_pointer( - gdk_display_get_device_manager(dpy)); -#endif } static void gd_mouse_set(DisplayChangeListener *dcl, @@ -877,27 +872,18 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, if (!qemu_input_is_absolute() && s->ptr_owner == vc) { GdkScreen *screen = gtk_widget_get_screen(vc->gfx.drawing_area); + GdkDisplay *dpy = gtk_widget_get_display(widget); + GdkWindow *win = gtk_widget_get_window(widget); + GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win); + GdkRectangle geometry; int screen_width, screen_height; int x = (int)motion->x_root; int y = (int)motion->y_root; -#if GTK_CHECK_VERSION(3, 22, 0) - { - GdkDisplay *dpy = gtk_widget_get_display(widget); - GdkWindow *win = gtk_widget_get_window(widget); - GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win); - GdkRectangle geometry; - gdk_monitor_get_geometry(monitor, &geometry); - screen_width = geometry.width; - screen_height = geometry.height; - } -#else - { - screen_width = gdk_screen_get_width(screen); - screen_height = gdk_screen_get_height(screen); - } -#endif + gdk_monitor_get_geometry(monitor, &geometry); + screen_width = geometry.width; + screen_height = geometry.height; /* In relative mode check to see if client pointer hit * one of the screen edges, and if so move it back by @@ -1026,13 +1012,8 @@ static const guint16 *gd_get_keymap(size_t *maplen) #ifdef GDK_WINDOWING_WIN32 if (GDK_IS_WIN32_DISPLAY(dpy)) { trace_gd_keymap_windowing("win32"); -#if GTK_CHECK_VERSION(3, 22, 0) *maplen = qemu_input_map_atset1_to_qcode_len; return qemu_input_map_atset1_to_qcode; -#else - *maplen = qemu_input_map_win32_to_qcode_len; - return qemu_input_map_win32_to_qcode; -#endif } #endif @@ -1080,7 +1061,7 @@ static int gd_map_keycode(int scancode) static int gd_get_keycode(GdkEventKey *key) { -#if defined G_OS_WIN32 && GTK_CHECK_VERSION(3, 22, 0) +#ifdef G_OS_WIN32 int scancode = gdk_event_get_scancode((GdkEvent *)key); /* translate Windows native scancodes to atset1 keycodes */ @@ -1437,7 +1418,6 @@ static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque) gd_update_full_redraw(vc); } -#if GTK_CHECK_VERSION(3, 20, 0) static void gd_grab_update(VirtualConsole *vc, bool kbd, bool ptr) { GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area); @@ -1461,32 +1441,6 @@ static void gd_grab_update(VirtualConsole *vc, bool kbd, bool ptr) gdk_seat_ungrab(seat); } } -#else -static void gd_grab_devices(VirtualConsole *vc, bool grab, - GdkInputSource source, GdkEventMask mask, - GdkCursor *cursor) -{ - GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area); - GdkDeviceManager *mgr = gdk_display_get_device_manager(display); - GList *devs = gdk_device_manager_list_devices(mgr, GDK_DEVICE_TYPE_MASTER); - GList *tmp = devs; - - for (tmp = devs; tmp; tmp = tmp->next) { - GdkDevice *dev = tmp->data; - if (gdk_device_get_source(dev) != source) { - continue; - } - if (grab) { - GdkWindow *win = gtk_widget_get_window(vc->gfx.drawing_area); - gdk_device_grab(dev, win, GDK_OWNERSHIP_NONE, FALSE, - mask, cursor, GDK_CURRENT_TIME); - } else { - gdk_device_ungrab(dev, GDK_CURRENT_TIME); - } - } - g_list_free(devs); -} -#endif static void gd_grab_keyboard(VirtualConsole *vc, const char *reason) { @@ -1499,13 +1453,7 @@ static void gd_grab_keyboard(VirtualConsole *vc, const char *reason) } win32_kbd_set_grab(true); -#if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, true, vc->s->ptr_owner == vc); -#else - gd_grab_devices(vc, true, GDK_SOURCE_KEYBOARD, - GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, - NULL); -#endif vc->s->kbd_owner = vc; gd_update_caption(vc->s); trace_gd_grab(vc->label, "kbd", reason); @@ -1521,11 +1469,7 @@ static void gd_ungrab_keyboard(GtkDisplayState *s) s->kbd_owner = NULL; win32_kbd_set_grab(false); -#if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, false, vc->s->ptr_owner == vc); -#else - gd_grab_devices(vc, false, GDK_SOURCE_KEYBOARD, 0, NULL); -#endif gd_update_caption(s); trace_gd_ungrab(vc->label, "kbd"); } @@ -1542,21 +1486,9 @@ static void gd_grab_pointer(VirtualConsole *vc, const char *reason) } } -#if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, vc->s->kbd_owner == vc, true); gdk_device_get_position(gd_get_pointer(display), NULL, &vc->s->grab_x_root, &vc->s->grab_y_root); -#else - gd_grab_devices(vc, true, GDK_SOURCE_MOUSE, - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_SCROLL_MASK, - vc->s->null_cursor); - gdk_device_get_position(gd_get_pointer(display), - NULL, &vc->s->grab_x_root, &vc->s->grab_y_root); -#endif vc->s->ptr_owner = vc; gd_update_caption(vc->s); trace_gd_grab(vc->label, "ptr", reason); @@ -1573,17 +1505,10 @@ static void gd_ungrab_pointer(GtkDisplayState *s) s->ptr_owner = NULL; display = gtk_widget_get_display(vc->gfx.drawing_area); -#if GTK_CHECK_VERSION(3, 20, 0) gd_grab_update(vc, vc->s->kbd_owner == vc, false); gdk_device_warp(gd_get_pointer(display), gtk_widget_get_screen(vc->gfx.drawing_area), vc->s->grab_x_root, vc->s->grab_y_root); -#else - gd_grab_devices(vc, false, GDK_SOURCE_MOUSE, 0, NULL); - gdk_device_warp(gd_get_pointer(display), - gtk_widget_get_screen(vc->gfx.drawing_area), - vc->s->grab_x_root, vc->s->grab_y_root); -#endif gd_update_caption(s); trace_gd_ungrab(vc->label, "ptr"); } From edb059040371784d12c05c0f3a19a9ddcd3a868d Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 14 May 2020 13:00:03 -0500 Subject: [PATCH 0590/2595] bitmaps: Update maintainer Dirty bitmaps are important to incremental backups, including exposure over NBD where I'm already maintainer. Also, I'm aware that lately I have been doing as much code/review on bitmaps as John Snow who is trying to scale back in order to focus elsewhere; and many of the recent patches have come from Vladimir, who is also interested in taking on maintainer duties, but would like to start with co-maintainership. Therefore, it's time to revamp the ownership of this category, as agreed between the three of us. Signed-off-by: Eric Blake Message-Id: <20200514180003.325406-1-eblake@redhat.com> Acked-by: John Snow Reviewed-by: John Snow --- MAINTAINERS | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 47ef3139e6..4e99bb05da 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2011,8 +2011,9 @@ F: qapi/transaction.json T: git https://repo.or.cz/qemu/armbru.git block-next Dirty Bitmaps -M: John Snow -R: Vladimir Sementsov-Ogievskiy +M: Eric Blake +M: Vladimir Sementsov-Ogievskiy +R: John Snow L: qemu-block@nongnu.org S: Supported F: include/qemu/hbitmap.h @@ -2023,7 +2024,7 @@ F: migration/block-dirty-bitmap.c F: util/hbitmap.c F: tests/test-hbitmap.c F: docs/interop/bitmaps.rst -T: git https://github.com/jnsnow/qemu.git bitmaps +T: git https://repo.or.cz/qemu/ericb.git bitmaps Character device backends M: Marc-André Lureau From 6edb788f292a83ad5f77b25bf90ed0eb14800639 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 12 May 2020 20:16:40 -0500 Subject: [PATCH 0591/2595] docs: Sort sections on qemu-img subcommand parameters We already list the subcommand summaries alphabetically, we should do the same for the documentation related to subcommand-specific parameters. Signed-off-by: Eric Blake Reviewed-by: Max Reitz Message-Id: <20200513011648.166876-2-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- docs/tools/qemu-img.rst | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index f4ffe528ea..3b6223b5d6 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -142,30 +142,6 @@ by the used format or see the format descriptions below for details. the documentation of the emulator's ``-drive cache=...`` option for allowed values. -Parameters to snapshot subcommand: - -.. program:: qemu-img-snapshot - -.. option:: snapshot - - Is the name of the snapshot to create, apply or delete - -.. option:: -a - - Applies a snapshot (revert disk to saved state) - -.. option:: -c - - Creates a snapshot - -.. option:: -d - - Deletes a snapshot - -.. option:: -l - - Lists all snapshots in the given image - Parameters to compare subcommand: .. program:: qemu-img-compare @@ -245,6 +221,30 @@ Parameters to dd subcommand: Sets the number of input blocks to skip +Parameters to snapshot subcommand: + +.. program:: qemu-img-snapshot + +.. option:: snapshot + + Is the name of the snapshot to create, apply or delete + +.. option:: -a + + Applies a snapshot (revert disk to saved state) + +.. option:: -c + + Creates a snapshot + +.. option:: -d + + Deletes a snapshot + +.. option:: -l + + Lists all snapshots in the given image + Command description: .. program:: qemu-img-commands From 0562adf51712c3c0354d68e745afb7e6705668f1 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 12 May 2020 20:16:41 -0500 Subject: [PATCH 0592/2595] qemu-img: Fix stale comments on doc location Missed in commit e13c59fa. Signed-off-by: Eric Blake Reviewed-by: Max Reitz Message-Id: <20200513011648.166876-3-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- qemu-img-cmds.hx | 2 +- qemu-img.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 35f832816f..cfe8f37587 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -7,7 +7,7 @@ HXCOMM command structures and help message. HXCOMM HXCOMM can be used for comments, discarded from both rST and C HXCOMM When amending the rST sections, please remember to copy the usage -HXCOMM over to the per-command sections in qemu-img.texi. +HXCOMM over to the per-command sections in docs/tools/qemu-img.rst. DEF("amend", img_amend, "amend [--object objectdef] [--image-opts] [-p] [-q] [-f fmt] [-t cache] -o options filename") diff --git a/qemu-img.c b/qemu-img.c index 2a9186139d..4740de082f 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -108,7 +108,7 @@ static void QEMU_NORETURN unrecognized_option(const char *option) error_exit("unrecognized option '%s'", option); } -/* Please keep in synch with qemu-img.texi */ +/* Please keep in synch with docs/tools/qemu-img.rst */ static void QEMU_NORETURN help(void) { const char *help_msg = From ef893b5c84f3199d777e33966dc28839f71b1a5c Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 12 May 2020 20:16:42 -0500 Subject: [PATCH 0593/2595] block: Make it easier to learn which BDS support bitmaps Upcoming patches will enhance bitmap support in qemu-img, but in doing so, it turns out to be nice to suppress output when persistent bitmaps make no sense (such as on a qcow2 v2 image). Add a hook to make this easier to query. This patch adds a new callback .bdrv_supports_persistent_dirty_bitmap, rather than trying to shoehorn the answer in via existing callbacks. In particular, while it might have been possible to overload .bdrv_co_can_store_new_dirty_bitmap to special-case a NULL input to answer whether any persistent bitmaps are supported, that is at odds with whether a particular bitmap can be stored (for example, even on an image that supports persistent bitmaps but has currently filled up the maximum number of bitmaps, attempts to store another one should fail); and the new functionality doesn't require coroutine safety. Similarly, we could have added one more piece of information to .bdrv_get_info, but then again, most callers to that function tend to already discard extraneous information, and making it a catch-all rather than a series of dedicated scalar queries hasn't really simplified life. In the future, when we improve the ability to look up bitmaps through a filter, we will probably also want to teach the block layer to automatically let filters pass this request on through. Signed-off-by: Eric Blake Message-Id: <20200513011648.166876-4-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- block/dirty-bitmap.c | 9 +++++++++ block/qcow2-bitmap.c | 7 +++++++ block/qcow2.c | 2 ++ block/qcow2.h | 1 + include/block/block_int.h | 1 + include/block/dirty-bitmap.h | 1 + 6 files changed, 21 insertions(+) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index 063793e316..f9bfc77985 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -478,6 +478,15 @@ int bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, } } +bool +bdrv_supports_persistent_dirty_bitmap(BlockDriverState *bs) +{ + if (bs->drv && bs->drv->bdrv_supports_persistent_dirty_bitmap) { + return bs->drv->bdrv_supports_persistent_dirty_bitmap(bs); + } + return false; +} + static bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, uint32_t granularity, Error **errp) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index cb06954b4a..1cf6d2ab77 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -1748,3 +1748,10 @@ fail: name, bdrv_get_device_or_node_name(bs)); return false; } + +bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs) +{ + BDRVQcow2State *s = bs->opaque; + + return s->qcow_version >= 3; +} diff --git a/block/qcow2.c b/block/qcow2.c index fe0ce39799..dfab8d2f6c 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5791,6 +5791,8 @@ BlockDriver bdrv_qcow2 = { .bdrv_detach_aio_context = qcow2_detach_aio_context, .bdrv_attach_aio_context = qcow2_attach_aio_context, + .bdrv_supports_persistent_dirty_bitmap = + qcow2_supports_persistent_dirty_bitmap, .bdrv_co_can_store_new_dirty_bitmap = qcow2_co_can_store_new_dirty_bitmap, .bdrv_co_remove_persistent_dirty_bitmap = qcow2_co_remove_persistent_dirty_bitmap, diff --git a/block/qcow2.h b/block/qcow2.h index 6a8b82e6cc..402e8acb1c 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -782,6 +782,7 @@ bool qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, int qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, Error **errp); +bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs); ssize_t coroutine_fn qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size, diff --git a/include/block/block_int.h b/include/block/block_int.h index 5e4f4c348c..33a12916f4 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -568,6 +568,7 @@ struct BlockDriver { uint64_t parent_perm, uint64_t parent_shared, uint64_t *nperm, uint64_t *nshared); + bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs); bool (*bdrv_co_can_store_new_dirty_bitmap)(BlockDriverState *bs, const char *name, uint32_t granularity, diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index 8a10029418..5a8d52e4de 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -16,6 +16,7 @@ typedef enum BitmapCheckFlags { #define BDRV_BITMAP_MAX_NAME_SIZE 1023 +bool bdrv_supports_persistent_dirty_bitmap(BlockDriverState *bs); BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, uint32_t granularity, const char *name, From c6996cf9a6c759c29919642be9a73ac64b38301b Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 12 May 2020 20:16:43 -0500 Subject: [PATCH 0594/2595] blockdev: Promote several bitmap functions to non-static The next patch will split blockdev.c, which will require accessing some previously-static functions from more than one .c file. But part of promoting a function to public is picking a naming scheme that does not reek of exposing too many internals (two of the three functions were named starting with 'do_'). To make future code motion easier, perform the function rename and non-static promotion into its own patch. Signed-off-by: Eric Blake Reviewed-by: Max Reitz Message-Id: <20200513011648.166876-5-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- blockdev.c | 47 ++++++++++++++++----------------------- include/block/block_int.h | 12 ++++++++++ 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/blockdev.c b/blockdev.c index b3c840ec03..69a30613a3 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1197,10 +1197,10 @@ out_aio_context: * * @return: A bitmap object on success, or NULL on failure. */ -static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node, - const char *name, - BlockDriverState **pbs, - Error **errp) +BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node, + const char *name, + BlockDriverState **pbs, + Error **errp) { BlockDriverState *bs; BdrvDirtyBitmap *bitmap; @@ -2171,11 +2171,6 @@ static void block_dirty_bitmap_disable_abort(BlkActionState *common) } } -static BdrvDirtyBitmap *do_block_dirty_bitmap_merge( - const char *node, const char *target, - BlockDirtyBitmapMergeSourceList *bitmaps, - HBitmap **backup, Error **errp); - static void block_dirty_bitmap_merge_prepare(BlkActionState *common, Error **errp) { @@ -2189,15 +2184,11 @@ static void block_dirty_bitmap_merge_prepare(BlkActionState *common, action = common->action->u.block_dirty_bitmap_merge.data; - state->bitmap = do_block_dirty_bitmap_merge(action->node, action->target, - action->bitmaps, &state->backup, - errp); + state->bitmap = block_dirty_bitmap_merge(action->node, action->target, + action->bitmaps, &state->backup, + errp); } -static BdrvDirtyBitmap *do_block_dirty_bitmap_remove( - const char *node, const char *name, bool release, - BlockDriverState **bitmap_bs, Error **errp); - static void block_dirty_bitmap_remove_prepare(BlkActionState *common, Error **errp) { @@ -2211,8 +2202,8 @@ static void block_dirty_bitmap_remove_prepare(BlkActionState *common, action = common->action->u.block_dirty_bitmap_remove.data; - state->bitmap = do_block_dirty_bitmap_remove(action->node, action->name, - false, &state->bs, errp); + state->bitmap = block_dirty_bitmap_remove(action->node, action->name, + false, &state->bs, errp); if (state->bitmap) { bdrv_dirty_bitmap_skip_store(state->bitmap, true); bdrv_dirty_bitmap_set_busy(state->bitmap, true); @@ -2504,9 +2495,10 @@ out: aio_context_release(aio_context); } -static BdrvDirtyBitmap *do_block_dirty_bitmap_remove( - const char *node, const char *name, bool release, - BlockDriverState **bitmap_bs, Error **errp) +BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name, + bool release, + BlockDriverState **bitmap_bs, + Error **errp) { BlockDriverState *bs; BdrvDirtyBitmap *bitmap; @@ -2548,7 +2540,7 @@ static BdrvDirtyBitmap *do_block_dirty_bitmap_remove( void qmp_block_dirty_bitmap_remove(const char *node, const char *name, Error **errp) { - do_block_dirty_bitmap_remove(node, name, true, NULL, errp); + block_dirty_bitmap_remove(node, name, true, NULL, errp); } /** @@ -2609,10 +2601,9 @@ void qmp_block_dirty_bitmap_disable(const char *node, const char *name, bdrv_disable_dirty_bitmap(bitmap); } -static BdrvDirtyBitmap *do_block_dirty_bitmap_merge( - const char *node, const char *target, - BlockDirtyBitmapMergeSourceList *bitmaps, - HBitmap **backup, Error **errp) +BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, + BlockDirtyBitmapMergeSourceList *bms, + HBitmap **backup, Error **errp) { BlockDriverState *bs; BdrvDirtyBitmap *dst, *src, *anon; @@ -2630,7 +2621,7 @@ static BdrvDirtyBitmap *do_block_dirty_bitmap_merge( return NULL; } - for (lst = bitmaps; lst; lst = lst->next) { + for (lst = bms; lst; lst = lst->next) { switch (lst->value->type) { const char *name, *node; case QTYPE_QSTRING: @@ -2675,7 +2666,7 @@ void qmp_block_dirty_bitmap_merge(const char *node, const char *target, BlockDirtyBitmapMergeSourceList *bitmaps, Error **errp) { - do_block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp); + block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp); } BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, diff --git a/include/block/block_int.h b/include/block/block_int.h index 33a12916f4..791de6a59c 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -1344,4 +1344,16 @@ int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv, Error **errp); extern QemuOptsList bdrv_create_opts_simple; +BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node, + const char *name, + BlockDriverState **pbs, + Error **errp); +BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, + BlockDirtyBitmapMergeSourceList *bms, + HBitmap **backup, Error **errp); +BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name, + bool release, + BlockDriverState **bitmap_bs, + Error **errp); + #endif /* BLOCK_INT_H */ From bb4e58c6137e80129b955789dd4b66c1504f20dc Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 18 May 2020 13:53:07 -0500 Subject: [PATCH 0595/2595] blockdev: Split off basic bitmap operations for qemu-img Upcoming patches want to add some basic bitmap manipulation abilities to qemu-img. But blockdev.o is too heavyweight to link into qemu-img (among other things, it would drag in block jobs and transaction support - qemu-img does offline manipulation, where atomicity is less important because there are no concurrent modifications to compete with), so it's time to split off the bare bones of what we will need into a new file block/monitor/bitmap-qmp-cmds.o. This is sufficient to expose 6 QMP commands for use by qemu-img (add, remove, clear, enable, disable, merge), as well as move the three helper functions touched in the previous patch. Regarding MAINTAINERS, the new file is automatically part of block core, but also makes sense as related to other dirty bitmap files. Signed-off-by: Eric Blake Reviewed-by: Max Reitz Message-Id: <20200513011648.166876-6-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- MAINTAINERS | 1 + Makefile.objs | 3 +- block/monitor/Makefile.objs | 1 + block/monitor/bitmap-qmp-cmds.c | 321 ++++++++++++++++++++++++++++++++ blockdev.c | 284 ---------------------------- 5 files changed, 324 insertions(+), 286 deletions(-) create mode 100644 block/monitor/bitmap-qmp-cmds.c diff --git a/MAINTAINERS b/MAINTAINERS index 4e99bb05da..87a412c229 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2018,6 +2018,7 @@ L: qemu-block@nongnu.org S: Supported F: include/qemu/hbitmap.h F: include/block/dirty-bitmap.h +F: block/monitor/bitmap-qmp-cmds.c F: block/dirty-bitmap.c F: block/qcow2-bitmap.c F: migration/block-dirty-bitmap.c diff --git a/Makefile.objs b/Makefile.objs index a7c967633a..99774cfd25 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -13,9 +13,8 @@ chardev-obj-y = chardev/ authz-obj-y = authz/ -block-obj-y = nbd/ +block-obj-y = block/ block/monitor/ nbd/ scsi/ block-obj-y += block.o blockjob.o job.o -block-obj-y += block/ scsi/ block-obj-y += qemu-io-cmds.o block-obj-$(CONFIG_REPLICATION) += replication.o diff --git a/block/monitor/Makefile.objs b/block/monitor/Makefile.objs index 0a74f9a8b5..39acf85022 100644 --- a/block/monitor/Makefile.objs +++ b/block/monitor/Makefile.objs @@ -1 +1,2 @@ common-obj-y += block-hmp-cmds.o +block-obj-y += bitmap-qmp-cmds.o diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c new file mode 100644 index 0000000000..9f11deec64 --- /dev/null +++ b/block/monitor/bitmap-qmp-cmds.c @@ -0,0 +1,321 @@ +/* + * QEMU block dirty bitmap QMP commands + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" + +#include "block/block_int.h" +#include "qapi/qapi-commands-block.h" +#include "qapi/error.h" + +/** + * block_dirty_bitmap_lookup: + * Return a dirty bitmap (if present), after validating + * the node reference and bitmap names. + * + * @node: The name of the BDS node to search for bitmaps + * @name: The name of the bitmap to search for + * @pbs: Output pointer for BDS lookup, if desired. Can be NULL. + * @errp: Output pointer for error information. Can be NULL. + * + * @return: A bitmap object on success, or NULL on failure. + */ +BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node, + const char *name, + BlockDriverState **pbs, + Error **errp) +{ + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; + + if (!node) { + error_setg(errp, "Node cannot be NULL"); + return NULL; + } + if (!name) { + error_setg(errp, "Bitmap name cannot be NULL"); + return NULL; + } + bs = bdrv_lookup_bs(node, node, NULL); + if (!bs) { + error_setg(errp, "Node '%s' not found", node); + return NULL; + } + + bitmap = bdrv_find_dirty_bitmap(bs, name); + if (!bitmap) { + error_setg(errp, "Dirty bitmap '%s' not found", name); + return NULL; + } + + if (pbs) { + *pbs = bs; + } + + return bitmap; +} + +void qmp_block_dirty_bitmap_add(const char *node, const char *name, + bool has_granularity, uint32_t granularity, + bool has_persistent, bool persistent, + bool has_disabled, bool disabled, + Error **errp) +{ + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; + AioContext *aio_context; + + if (!name || name[0] == '\0') { + error_setg(errp, "Bitmap name cannot be empty"); + return; + } + + bs = bdrv_lookup_bs(node, node, errp); + if (!bs) { + return; + } + + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + + if (has_granularity) { + if (granularity < 512 || !is_power_of_2(granularity)) { + error_setg(errp, "Granularity must be power of 2 " + "and at least 512"); + goto out; + } + } else { + /* Default to cluster size, if available: */ + granularity = bdrv_get_default_bitmap_granularity(bs); + } + + if (!has_persistent) { + persistent = false; + } + + if (!has_disabled) { + disabled = false; + } + + if (persistent && + !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) + { + goto out; + } + + bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp); + if (bitmap == NULL) { + goto out; + } + + if (disabled) { + bdrv_disable_dirty_bitmap(bitmap); + } + + bdrv_dirty_bitmap_set_persistence(bitmap, persistent); + +out: + aio_context_release(aio_context); +} + +BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name, + bool release, + BlockDriverState **bitmap_bs, + Error **errp) +{ + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; + AioContext *aio_context; + + bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); + if (!bitmap || !bs) { + return NULL; + } + + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + + if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO, + errp)) { + aio_context_release(aio_context); + return NULL; + } + + if (bdrv_dirty_bitmap_get_persistence(bitmap) && + bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0) + { + aio_context_release(aio_context); + return NULL; + } + + if (release) { + bdrv_release_dirty_bitmap(bitmap); + } + + if (bitmap_bs) { + *bitmap_bs = bs; + } + + aio_context_release(aio_context); + return release ? NULL : bitmap; +} + +void qmp_block_dirty_bitmap_remove(const char *node, const char *name, + Error **errp) +{ + block_dirty_bitmap_remove(node, name, true, NULL, errp); +} + +/** + * Completely clear a bitmap, for the purposes of synchronizing a bitmap + * immediately after a full backup operation. + */ +void qmp_block_dirty_bitmap_clear(const char *node, const char *name, + Error **errp) +{ + BdrvDirtyBitmap *bitmap; + BlockDriverState *bs; + + bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); + if (!bitmap || !bs) { + return; + } + + if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) { + return; + } + + bdrv_clear_dirty_bitmap(bitmap, NULL); +} + +void qmp_block_dirty_bitmap_enable(const char *node, const char *name, + Error **errp) +{ + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; + + bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); + if (!bitmap) { + return; + } + + if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { + return; + } + + bdrv_enable_dirty_bitmap(bitmap); +} + +void qmp_block_dirty_bitmap_disable(const char *node, const char *name, + Error **errp) +{ + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; + + bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); + if (!bitmap) { + return; + } + + if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { + return; + } + + bdrv_disable_dirty_bitmap(bitmap); +} + +BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, + BlockDirtyBitmapMergeSourceList *bms, + HBitmap **backup, Error **errp) +{ + BlockDriverState *bs; + BdrvDirtyBitmap *dst, *src, *anon; + BlockDirtyBitmapMergeSourceList *lst; + Error *local_err = NULL; + + dst = block_dirty_bitmap_lookup(node, target, &bs, errp); + if (!dst) { + return NULL; + } + + anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst), + NULL, errp); + if (!anon) { + return NULL; + } + + for (lst = bms; lst; lst = lst->next) { + switch (lst->value->type) { + const char *name, *node; + case QTYPE_QSTRING: + name = lst->value->u.local; + src = bdrv_find_dirty_bitmap(bs, name); + if (!src) { + error_setg(errp, "Dirty bitmap '%s' not found", name); + dst = NULL; + goto out; + } + break; + case QTYPE_QDICT: + node = lst->value->u.external.node; + name = lst->value->u.external.name; + src = block_dirty_bitmap_lookup(node, name, NULL, errp); + if (!src) { + dst = NULL; + goto out; + } + break; + default: + abort(); + } + + bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err); + if (local_err) { + error_propagate(errp, local_err); + dst = NULL; + goto out; + } + } + + /* Merge into dst; dst is unchanged on failure. */ + bdrv_merge_dirty_bitmap(dst, anon, backup, errp); + + out: + bdrv_release_dirty_bitmap(anon); + return dst; +} + +void qmp_block_dirty_bitmap_merge(const char *node, const char *target, + BlockDirtyBitmapMergeSourceList *bitmaps, + Error **errp) +{ + block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp); +} diff --git a/blockdev.c b/blockdev.c index 69a30613a3..72df193ca7 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1185,53 +1185,6 @@ out_aio_context: return NULL; } -/** - * block_dirty_bitmap_lookup: - * Return a dirty bitmap (if present), after validating - * the node reference and bitmap names. - * - * @node: The name of the BDS node to search for bitmaps - * @name: The name of the bitmap to search for - * @pbs: Output pointer for BDS lookup, if desired. Can be NULL. - * @errp: Output pointer for error information. Can be NULL. - * - * @return: A bitmap object on success, or NULL on failure. - */ -BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node, - const char *name, - BlockDriverState **pbs, - Error **errp) -{ - BlockDriverState *bs; - BdrvDirtyBitmap *bitmap; - - if (!node) { - error_setg(errp, "Node cannot be NULL"); - return NULL; - } - if (!name) { - error_setg(errp, "Bitmap name cannot be NULL"); - return NULL; - } - bs = bdrv_lookup_bs(node, node, NULL); - if (!bs) { - error_setg(errp, "Node '%s' not found", node); - return NULL; - } - - bitmap = bdrv_find_dirty_bitmap(bs, name); - if (!bitmap) { - error_setg(errp, "Dirty bitmap '%s' not found", name); - return NULL; - } - - if (pbs) { - *pbs = bs; - } - - return bitmap; -} - /* New and old BlockDriverState structs for atomic group operations */ typedef struct BlkActionState BlkActionState; @@ -2432,243 +2385,6 @@ void qmp_block_passwd(bool has_device, const char *device, "Setting block passwords directly is no longer supported"); } -void qmp_block_dirty_bitmap_add(const char *node, const char *name, - bool has_granularity, uint32_t granularity, - bool has_persistent, bool persistent, - bool has_disabled, bool disabled, - Error **errp) -{ - BlockDriverState *bs; - BdrvDirtyBitmap *bitmap; - AioContext *aio_context; - - if (!name || name[0] == '\0') { - error_setg(errp, "Bitmap name cannot be empty"); - return; - } - - bs = bdrv_lookup_bs(node, node, errp); - if (!bs) { - return; - } - - aio_context = bdrv_get_aio_context(bs); - aio_context_acquire(aio_context); - - if (has_granularity) { - if (granularity < 512 || !is_power_of_2(granularity)) { - error_setg(errp, "Granularity must be power of 2 " - "and at least 512"); - goto out; - } - } else { - /* Default to cluster size, if available: */ - granularity = bdrv_get_default_bitmap_granularity(bs); - } - - if (!has_persistent) { - persistent = false; - } - - if (!has_disabled) { - disabled = false; - } - - if (persistent && - !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) - { - goto out; - } - - bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp); - if (bitmap == NULL) { - goto out; - } - - if (disabled) { - bdrv_disable_dirty_bitmap(bitmap); - } - - bdrv_dirty_bitmap_set_persistence(bitmap, persistent); - -out: - aio_context_release(aio_context); -} - -BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name, - bool release, - BlockDriverState **bitmap_bs, - Error **errp) -{ - BlockDriverState *bs; - BdrvDirtyBitmap *bitmap; - AioContext *aio_context; - - bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); - if (!bitmap || !bs) { - return NULL; - } - - aio_context = bdrv_get_aio_context(bs); - aio_context_acquire(aio_context); - - if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO, - errp)) { - aio_context_release(aio_context); - return NULL; - } - - if (bdrv_dirty_bitmap_get_persistence(bitmap) && - bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0) - { - aio_context_release(aio_context); - return NULL; - } - - if (release) { - bdrv_release_dirty_bitmap(bitmap); - } - - if (bitmap_bs) { - *bitmap_bs = bs; - } - - aio_context_release(aio_context); - return release ? NULL : bitmap; -} - -void qmp_block_dirty_bitmap_remove(const char *node, const char *name, - Error **errp) -{ - block_dirty_bitmap_remove(node, name, true, NULL, errp); -} - -/** - * Completely clear a bitmap, for the purposes of synchronizing a bitmap - * immediately after a full backup operation. - */ -void qmp_block_dirty_bitmap_clear(const char *node, const char *name, - Error **errp) -{ - BdrvDirtyBitmap *bitmap; - BlockDriverState *bs; - - bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); - if (!bitmap || !bs) { - return; - } - - if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) { - return; - } - - bdrv_clear_dirty_bitmap(bitmap, NULL); -} - -void qmp_block_dirty_bitmap_enable(const char *node, const char *name, - Error **errp) -{ - BlockDriverState *bs; - BdrvDirtyBitmap *bitmap; - - bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); - if (!bitmap) { - return; - } - - if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { - return; - } - - bdrv_enable_dirty_bitmap(bitmap); -} - -void qmp_block_dirty_bitmap_disable(const char *node, const char *name, - Error **errp) -{ - BlockDriverState *bs; - BdrvDirtyBitmap *bitmap; - - bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); - if (!bitmap) { - return; - } - - if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { - return; - } - - bdrv_disable_dirty_bitmap(bitmap); -} - -BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, - BlockDirtyBitmapMergeSourceList *bms, - HBitmap **backup, Error **errp) -{ - BlockDriverState *bs; - BdrvDirtyBitmap *dst, *src, *anon; - BlockDirtyBitmapMergeSourceList *lst; - Error *local_err = NULL; - - dst = block_dirty_bitmap_lookup(node, target, &bs, errp); - if (!dst) { - return NULL; - } - - anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst), - NULL, errp); - if (!anon) { - return NULL; - } - - for (lst = bms; lst; lst = lst->next) { - switch (lst->value->type) { - const char *name, *node; - case QTYPE_QSTRING: - name = lst->value->u.local; - src = bdrv_find_dirty_bitmap(bs, name); - if (!src) { - error_setg(errp, "Dirty bitmap '%s' not found", name); - dst = NULL; - goto out; - } - break; - case QTYPE_QDICT: - node = lst->value->u.external.node; - name = lst->value->u.external.name; - src = block_dirty_bitmap_lookup(node, name, NULL, errp); - if (!src) { - dst = NULL; - goto out; - } - break; - default: - abort(); - } - - bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err); - if (local_err) { - error_propagate(errp, local_err); - dst = NULL; - goto out; - } - } - - /* Merge into dst; dst is unchanged on failure. */ - bdrv_merge_dirty_bitmap(dst, anon, backup, errp); - - out: - bdrv_release_dirty_bitmap(anon); - return dst; -} - -void qmp_block_dirty_bitmap_merge(const char *node, const char *target, - BlockDirtyBitmapMergeSourceList *bitmaps, - Error **errp) -{ - block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp); -} - BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, const char *name, Error **errp) From b240c9c497b9880ac0ba29465907d5ebecd48083 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 4 May 2020 16:57:21 -0700 Subject: [PATCH 0596/2595] softfloat: Use post test for floatN_mul MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing f{32,64}_addsub_post test, which checks for zero inputs, is identical to f{32,64}_mul_fast_test. Which means we can eliminate the fast_test/fast_op hooks in favor of reusing the same post hook. This means we have one fewer test along the fast path for multiply. Tested-by: Alex Bennée Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 65 +++++++++++-------------------------------------- 1 file changed, 14 insertions(+), 51 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index a362bf89ca..5fb4ef75bb 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -339,12 +339,10 @@ static inline bool f64_is_inf(union_float64 a) return float64_is_infinity(a.s); } -/* Note: @fast_test and @post can be NULL */ static inline float32 float32_gen2(float32 xa, float32 xb, float_status *s, hard_f32_op2_fn hard, soft_f32_op2_fn soft, - f32_check_fn pre, f32_check_fn post, - f32_check_fn fast_test, soft_f32_op2_fn fast_op) + f32_check_fn pre, f32_check_fn post) { union_float32 ua, ub, ur; @@ -359,17 +357,12 @@ float32_gen2(float32 xa, float32 xb, float_status *s, if (unlikely(!pre(ua, ub))) { goto soft; } - if (fast_test && fast_test(ua, ub)) { - return fast_op(ua.s, ub.s, s); - } ur.h = hard(ua.h, ub.h); if (unlikely(f32_is_inf(ur))) { s->float_exception_flags |= float_flag_overflow; - } else if (unlikely(fabsf(ur.h) <= FLT_MIN)) { - if (post == NULL || post(ua, ub)) { - goto soft; - } + } else if (unlikely(fabsf(ur.h) <= FLT_MIN) && post(ua, ub)) { + goto soft; } return ur.s; @@ -380,8 +373,7 @@ float32_gen2(float32 xa, float32 xb, float_status *s, static inline float64 float64_gen2(float64 xa, float64 xb, float_status *s, hard_f64_op2_fn hard, soft_f64_op2_fn soft, - f64_check_fn pre, f64_check_fn post, - f64_check_fn fast_test, soft_f64_op2_fn fast_op) + f64_check_fn pre, f64_check_fn post) { union_float64 ua, ub, ur; @@ -396,17 +388,12 @@ float64_gen2(float64 xa, float64 xb, float_status *s, if (unlikely(!pre(ua, ub))) { goto soft; } - if (fast_test && fast_test(ua, ub)) { - return fast_op(ua.s, ub.s, s); - } ur.h = hard(ua.h, ub.h); if (unlikely(f64_is_inf(ur))) { s->float_exception_flags |= float_flag_overflow; - } else if (unlikely(fabs(ur.h) <= DBL_MIN)) { - if (post == NULL || post(ua, ub)) { - goto soft; - } + } else if (unlikely(fabs(ur.h) <= DBL_MIN) && post(ua, ub)) { + goto soft; } return ur.s; @@ -1115,7 +1102,7 @@ static double hard_f64_sub(double a, double b) return a - b; } -static bool f32_addsub_post(union_float32 a, union_float32 b) +static bool f32_addsubmul_post(union_float32 a, union_float32 b) { if (QEMU_HARDFLOAT_2F32_USE_FP) { return !(fpclassify(a.h) == FP_ZERO && fpclassify(b.h) == FP_ZERO); @@ -1123,7 +1110,7 @@ static bool f32_addsub_post(union_float32 a, union_float32 b) return !(float32_is_zero(a.s) && float32_is_zero(b.s)); } -static bool f64_addsub_post(union_float64 a, union_float64 b) +static bool f64_addsubmul_post(union_float64 a, union_float64 b) { if (QEMU_HARDFLOAT_2F64_USE_FP) { return !(fpclassify(a.h) == FP_ZERO && fpclassify(b.h) == FP_ZERO); @@ -1136,14 +1123,14 @@ static float32 float32_addsub(float32 a, float32 b, float_status *s, hard_f32_op2_fn hard, soft_f32_op2_fn soft) { return float32_gen2(a, b, s, hard, soft, - f32_is_zon2, f32_addsub_post, NULL, NULL); + f32_is_zon2, f32_addsubmul_post); } static float64 float64_addsub(float64 a, float64 b, float_status *s, hard_f64_op2_fn hard, soft_f64_op2_fn soft) { return float64_gen2(a, b, s, hard, soft, - f64_is_zon2, f64_addsub_post, NULL, NULL); + f64_is_zon2, f64_addsubmul_post); } float32 QEMU_FLATTEN @@ -1258,42 +1245,18 @@ static double hard_f64_mul(double a, double b) return a * b; } -static bool f32_mul_fast_test(union_float32 a, union_float32 b) -{ - return float32_is_zero(a.s) || float32_is_zero(b.s); -} - -static bool f64_mul_fast_test(union_float64 a, union_float64 b) -{ - return float64_is_zero(a.s) || float64_is_zero(b.s); -} - -static float32 f32_mul_fast_op(float32 a, float32 b, float_status *s) -{ - bool signbit = float32_is_neg(a) ^ float32_is_neg(b); - - return float32_set_sign(float32_zero, signbit); -} - -static float64 f64_mul_fast_op(float64 a, float64 b, float_status *s) -{ - bool signbit = float64_is_neg(a) ^ float64_is_neg(b); - - return float64_set_sign(float64_zero, signbit); -} - float32 QEMU_FLATTEN float32_mul(float32 a, float32 b, float_status *s) { return float32_gen2(a, b, s, hard_f32_mul, soft_f32_mul, - f32_is_zon2, NULL, f32_mul_fast_test, f32_mul_fast_op); + f32_is_zon2, f32_addsubmul_post); } float64 QEMU_FLATTEN float64_mul(float64 a, float64 b, float_status *s) { return float64_gen2(a, b, s, hard_f64_mul, soft_f64_mul, - f64_is_zon2, NULL, f64_mul_fast_test, f64_mul_fast_op); + f64_is_zon2, f64_addsubmul_post); } /* @@ -1834,14 +1797,14 @@ float32 QEMU_FLATTEN float32_div(float32 a, float32 b, float_status *s) { return float32_gen2(a, b, s, hard_f32_div, soft_f32_div, - f32_div_pre, f32_div_post, NULL, NULL); + f32_div_pre, f32_div_post); } float64 QEMU_FLATTEN float64_div(float64 a, float64 b, float_status *s) { return float64_gen2(a, b, s, hard_f64_div, soft_f64_div, - f64_div_pre, f64_div_post, NULL, NULL); + f64_div_pre, f64_div_post); } /* From c120391c0090d9c40425c92cdb00f38ea8588ff6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 4 May 2020 19:54:57 -0700 Subject: [PATCH 0597/2595] softfloat: Replace flag with bool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have had this on the to-do list for quite some time. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- fpu/softfloat-specialize.inc.c | 16 +-- fpu/softfloat.c | 190 ++++++++++++++++---------------- include/fpu/softfloat-helpers.h | 14 +-- include/fpu/softfloat-macros.h | 24 ++-- include/fpu/softfloat-types.h | 14 +-- include/fpu/softfloat.h | 10 +- target/arm/sve_helper.c | 8 +- target/arm/vfp_helper.c | 8 +- target/m68k/softfloat.c | 70 ++++++------ target/mips/msa_helper.c | 10 +- 10 files changed, 174 insertions(+), 190 deletions(-) diff --git a/fpu/softfloat-specialize.inc.c b/fpu/softfloat-specialize.inc.c index 5ab2fa1941..025ee4f991 100644 --- a/fpu/softfloat-specialize.inc.c +++ b/fpu/softfloat-specialize.inc.c @@ -93,7 +93,7 @@ this code that are retained. * 2008 revision and backward compatibility with their original choice. * Thus for MIPS we must make the choice at runtime. */ -static inline flag snan_bit_is_one(float_status *status) +static inline bool snan_bit_is_one(float_status *status) { #if defined(TARGET_MIPS) return status->snan_bit_is_one; @@ -114,7 +114,7 @@ static bool parts_is_snan_frac(uint64_t frac, float_status *status) #ifdef NO_SIGNALING_NANS return false; #else - flag msb = extract64(frac, DECOMPOSED_BINARY_POINT - 1, 1); + bool msb = extract64(frac, DECOMPOSED_BINARY_POINT - 1, 1); return msb == snan_bit_is_one(status); #endif } @@ -236,7 +236,7 @@ void float_raise(uint8_t flags, float_status *status) | Internal canonical NaN format. *----------------------------------------------------------------------------*/ typedef struct { - flag sign; + bool sign; uint64_t high, low; } commonNaNT; @@ -374,7 +374,7 @@ static float32 commonNaNToFloat32(commonNaNT a, float_status *status) *----------------------------------------------------------------------------*/ static int pickNaN(FloatClass a_cls, FloatClass b_cls, - flag aIsLargerSignificand) + bool aIsLargerSignificand) { #if defined(TARGET_ARM) || defined(TARGET_MIPS) || defined(TARGET_HPPA) /* ARM mandated NaN propagation rules (see FPProcessNaNs()), take @@ -584,7 +584,7 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, static float32 propagateFloat32NaN(float32 a, float32 b, float_status *status) { - flag aIsLargerSignificand; + bool aIsLargerSignificand; uint32_t av, bv; FloatClass a_cls, b_cls; @@ -722,7 +722,7 @@ static float64 commonNaNToFloat64(commonNaNT a, float_status *status) static float64 propagateFloat64NaN(float64 a, float64 b, float_status *status) { - flag aIsLargerSignificand; + bool aIsLargerSignificand; uint64_t av, bv; FloatClass a_cls, b_cls; @@ -890,7 +890,7 @@ static floatx80 commonNaNToFloatx80(commonNaNT a, float_status *status) floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status) { - flag aIsLargerSignificand; + bool aIsLargerSignificand; FloatClass a_cls, b_cls; /* This is not complete, but is good enough for pickNaN. */ @@ -1038,7 +1038,7 @@ static float128 commonNaNToFloat128(commonNaNT a, float_status *status) static float128 propagateFloat128NaN(float128 a, float128 b, float_status *status) { - flag aIsLargerSignificand; + bool aIsLargerSignificand; FloatClass a_cls, b_cls; /* This is not complete, but is good enough for pickNaN. */ diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 5fb4ef75bb..b741cf5bc3 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -423,7 +423,7 @@ static inline int extractFloat32Exp(float32 a) | Returns the sign bit of the single-precision floating-point value `a'. *----------------------------------------------------------------------------*/ -static inline flag extractFloat32Sign(float32 a) +static inline bool extractFloat32Sign(float32 a) { return float32_val(a) >> 31; } @@ -450,7 +450,7 @@ static inline int extractFloat64Exp(float64 a) | Returns the sign bit of the double-precision floating-point value `a'. *----------------------------------------------------------------------------*/ -static inline flag extractFloat64Sign(float64 a) +static inline bool extractFloat64Sign(float64 a) { return float64_val(a) >> 63; } @@ -3328,10 +3328,11 @@ float64 float64_squash_input_denormal(float64 a, float_status *status) | positive or negative integer is returned. *----------------------------------------------------------------------------*/ -static int32_t roundAndPackInt32(flag zSign, uint64_t absZ, float_status *status) +static int32_t roundAndPackInt32(bool zSign, uint64_t absZ, + float_status *status) { int8_t roundingMode; - flag roundNearestEven; + bool roundNearestEven; int8_t roundIncrement, roundBits; int32_t z; @@ -3385,11 +3386,11 @@ static int32_t roundAndPackInt32(flag zSign, uint64_t absZ, float_status *status | returned. *----------------------------------------------------------------------------*/ -static int64_t roundAndPackInt64(flag zSign, uint64_t absZ0, uint64_t absZ1, +static int64_t roundAndPackInt64(bool zSign, uint64_t absZ0, uint64_t absZ1, float_status *status) { int8_t roundingMode; - flag roundNearestEven, increment; + bool roundNearestEven, increment; int64_t z; roundingMode = status->float_rounding_mode; @@ -3443,11 +3444,11 @@ static int64_t roundAndPackInt64(flag zSign, uint64_t absZ0, uint64_t absZ1, | exception is raised and the largest unsigned integer is returned. *----------------------------------------------------------------------------*/ -static int64_t roundAndPackUint64(flag zSign, uint64_t absZ0, +static int64_t roundAndPackUint64(bool zSign, uint64_t absZ0, uint64_t absZ1, float_status *status) { int8_t roundingMode; - flag roundNearestEven, increment; + bool roundNearestEven, increment; roundingMode = status->float_rounding_mode; roundNearestEven = (roundingMode == float_round_nearest_even); @@ -3531,13 +3532,13 @@ static void | Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig, +static float32 roundAndPackFloat32(bool zSign, int zExp, uint32_t zSig, float_status *status) { int8_t roundingMode; - flag roundNearestEven; + bool roundNearestEven; int8_t roundIncrement, roundBits; - flag isTiny; + bool isTiny; roundingMode = status->float_rounding_mode; roundNearestEven = ( roundingMode == float_round_nearest_even ); @@ -3618,7 +3619,7 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig, *----------------------------------------------------------------------------*/ static float32 - normalizeRoundAndPackFloat32(flag zSign, int zExp, uint32_t zSig, + normalizeRoundAndPackFloat32(bool zSign, int zExp, uint32_t zSig, float_status *status) { int8_t shiftCount; @@ -3658,7 +3659,7 @@ static void | significand. *----------------------------------------------------------------------------*/ -static inline float64 packFloat64(flag zSign, int zExp, uint64_t zSig) +static inline float64 packFloat64(bool zSign, int zExp, uint64_t zSig) { return make_float64( @@ -3688,13 +3689,13 @@ static inline float64 packFloat64(flag zSign, int zExp, uint64_t zSig) | Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static float64 roundAndPackFloat64(flag zSign, int zExp, uint64_t zSig, +static float64 roundAndPackFloat64(bool zSign, int zExp, uint64_t zSig, float_status *status) { int8_t roundingMode; - flag roundNearestEven; + bool roundNearestEven; int roundIncrement, roundBits; - flag isTiny; + bool isTiny; roundingMode = status->float_rounding_mode; roundNearestEven = ( roundingMode == float_round_nearest_even ); @@ -3774,7 +3775,7 @@ static float64 roundAndPackFloat64(flag zSign, int zExp, uint64_t zSig, *----------------------------------------------------------------------------*/ static float64 - normalizeRoundAndPackFloat64(flag zSign, int zExp, uint64_t zSig, + normalizeRoundAndPackFloat64(bool zSign, int zExp, uint64_t zSig, float_status *status) { int8_t shiftCount; @@ -3826,12 +3827,12 @@ void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr, | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -floatx80 roundAndPackFloatx80(int8_t roundingPrecision, flag zSign, +floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status) { int8_t roundingMode; - flag roundNearestEven, increment, isTiny; + bool roundNearestEven, increment, isTiny; int64_t roundIncrement, roundMask, roundBits; roundingMode = status->float_rounding_mode; @@ -4025,7 +4026,7 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, flag zSign, *----------------------------------------------------------------------------*/ floatx80 normalizeRoundAndPackFloatx80(int8_t roundingPrecision, - flag zSign, int32_t zExp, + bool zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status) { @@ -4084,11 +4085,9 @@ static inline int32_t extractFloat128Exp( float128 a ) | Returns the sign bit of the quadruple-precision floating-point value `a'. *----------------------------------------------------------------------------*/ -static inline flag extractFloat128Sign( float128 a ) +static inline bool extractFloat128Sign(float128 a) { - - return a.high>>63; - + return a.high >> 63; } /*---------------------------------------------------------------------------- @@ -4146,14 +4145,13 @@ static void *----------------------------------------------------------------------------*/ static inline float128 - packFloat128( flag zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1 ) +packFloat128(bool zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1) { float128 z; z.low = zSig1; - z.high = ( ( (uint64_t) zSign )<<63 ) + ( ( (uint64_t) zExp )<<48 ) + zSig0; + z.high = ((uint64_t)zSign << 63) + ((uint64_t)zExp << 48) + zSig0; return z; - } /*---------------------------------------------------------------------------- @@ -4177,12 +4175,12 @@ static inline float128 | overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static float128 roundAndPackFloat128(flag zSign, int32_t zExp, +static float128 roundAndPackFloat128(bool zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, uint64_t zSig2, float_status *status) { int8_t roundingMode; - flag roundNearestEven, increment, isTiny; + bool roundNearestEven, increment, isTiny; roundingMode = status->float_rounding_mode; roundNearestEven = ( roundingMode == float_round_nearest_even ); @@ -4302,7 +4300,7 @@ static float128 roundAndPackFloat128(flag zSign, int32_t zExp, | point exponent. *----------------------------------------------------------------------------*/ -static float128 normalizeRoundAndPackFloat128(flag zSign, int32_t zExp, +static float128 normalizeRoundAndPackFloat128(bool zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status) { @@ -4338,7 +4336,7 @@ static float128 normalizeRoundAndPackFloat128(flag zSign, int32_t zExp, floatx80 int32_to_floatx80(int32_t a, float_status *status) { - flag zSign; + bool zSign; uint32_t absA; int8_t shiftCount; uint64_t zSig; @@ -4360,7 +4358,7 @@ floatx80 int32_to_floatx80(int32_t a, float_status *status) float128 int32_to_float128(int32_t a, float_status *status) { - flag zSign; + bool zSign; uint32_t absA; int8_t shiftCount; uint64_t zSig0; @@ -4383,7 +4381,7 @@ float128 int32_to_float128(int32_t a, float_status *status) floatx80 int64_to_floatx80(int64_t a, float_status *status) { - flag zSign; + bool zSign; uint64_t absA; int8_t shiftCount; @@ -4403,7 +4401,7 @@ floatx80 int64_to_floatx80(int64_t a, float_status *status) float128 int64_to_float128(int64_t a, float_status *status) { - flag zSign; + bool zSign; uint64_t absA; int8_t shiftCount; int32_t zExp; @@ -4451,7 +4449,7 @@ float128 uint64_to_float128(uint64_t a, float_status *status) floatx80 float32_to_floatx80(float32 a, float_status *status) { - flag aSign; + bool aSign; int aExp; uint32_t aSig; @@ -4487,7 +4485,7 @@ floatx80 float32_to_floatx80(float32 a, float_status *status) float128 float32_to_float128(float32 a, float_status *status) { - flag aSign; + bool aSign; int aExp; uint32_t aSig; @@ -4518,7 +4516,7 @@ float128 float32_to_float128(float32 a, float_status *status) float32 float32_rem(float32 a, float32 b, float_status *status) { - flag aSign, zSign; + bool aSign, zSign; int aExp, bExp, expDiff; uint32_t aSig, bSig; uint32_t q; @@ -4653,7 +4651,7 @@ static const float64 float32_exp2_coefficients[15] = float32 float32_exp2(float32 a, float_status *status) { - flag aSign; + bool aSign; int aExp; uint32_t aSig; float64 r, x, xn; @@ -4703,7 +4701,7 @@ float32 float32_exp2(float32 a, float_status *status) *----------------------------------------------------------------------------*/ float32 float32_log2(float32 a, float_status *status) { - flag aSign, zSign; + bool aSign, zSign; int aExp; uint32_t aSig, zSig, i; @@ -4779,7 +4777,7 @@ int float32_eq(float32 a, float32 b, float_status *status) int float32_le(float32 a, float32 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; uint32_t av, bv; a = float32_squash_input_denormal(a, status); b = float32_squash_input_denormal(b, status); @@ -4808,7 +4806,7 @@ int float32_le(float32 a, float32 b, float_status *status) int float32_lt(float32 a, float32 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; uint32_t av, bv; a = float32_squash_input_denormal(a, status); b = float32_squash_input_denormal(b, status); @@ -4883,7 +4881,7 @@ int float32_eq_quiet(float32 a, float32 b, float_status *status) int float32_le_quiet(float32 a, float32 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; uint32_t av, bv; a = float32_squash_input_denormal(a, status); b = float32_squash_input_denormal(b, status); @@ -4915,7 +4913,7 @@ int float32_le_quiet(float32 a, float32 b, float_status *status) int float32_lt_quiet(float32 a, float32 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; uint32_t av, bv; a = float32_squash_input_denormal(a, status); b = float32_squash_input_denormal(b, status); @@ -4971,7 +4969,7 @@ int float32_unordered_quiet(float32 a, float32 b, float_status *status) floatx80 float64_to_floatx80(float64 a, float_status *status) { - flag aSign; + bool aSign; int aExp; uint64_t aSig; @@ -5008,7 +5006,7 @@ floatx80 float64_to_floatx80(float64 a, float_status *status) float128 float64_to_float128(float64 a, float_status *status) { - flag aSign; + bool aSign; int aExp; uint64_t aSig, zSig0, zSig1; @@ -5041,7 +5039,7 @@ float128 float64_to_float128(float64 a, float_status *status) float64 float64_rem(float64 a, float64 b, float_status *status) { - flag aSign, zSign; + bool aSign, zSign; int aExp, bExp, expDiff; uint64_t aSig, bSig; uint64_t q, alternateASig; @@ -5128,7 +5126,7 @@ float64 float64_rem(float64 a, float64 b, float_status *status) *----------------------------------------------------------------------------*/ float64 float64_log2(float64 a, float_status *status) { - flag aSign, zSign; + bool aSign, zSign; int aExp; uint64_t aSig, aSig0, aSig1, zSig, i; a = float64_squash_input_denormal(a, status); @@ -5204,7 +5202,7 @@ int float64_eq(float64 a, float64 b, float_status *status) int float64_le(float64 a, float64 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; uint64_t av, bv; a = float64_squash_input_denormal(a, status); b = float64_squash_input_denormal(b, status); @@ -5233,7 +5231,7 @@ int float64_le(float64 a, float64 b, float_status *status) int float64_lt(float64 a, float64 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; uint64_t av, bv; a = float64_squash_input_denormal(a, status); @@ -5311,7 +5309,7 @@ int float64_eq_quiet(float64 a, float64 b, float_status *status) int float64_le_quiet(float64 a, float64 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; uint64_t av, bv; a = float64_squash_input_denormal(a, status); b = float64_squash_input_denormal(b, status); @@ -5343,7 +5341,7 @@ int float64_le_quiet(float64 a, float64 b, float_status *status) int float64_lt_quiet(float64 a, float64 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; uint64_t av, bv; a = float64_squash_input_denormal(a, status); b = float64_squash_input_denormal(b, status); @@ -5402,7 +5400,7 @@ int float64_unordered_quiet(float64 a, float64 b, float_status *status) int32_t floatx80_to_int32(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp, shiftCount; uint64_t aSig; @@ -5433,7 +5431,7 @@ int32_t floatx80_to_int32(floatx80 a, float_status *status) int32_t floatx80_to_int32_round_to_zero(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp, shiftCount; uint64_t aSig, savedASig; int32_t z; @@ -5484,7 +5482,7 @@ int32_t floatx80_to_int32_round_to_zero(floatx80 a, float_status *status) int64_t floatx80_to_int64(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp, shiftCount; uint64_t aSig, aSigExtra; @@ -5525,7 +5523,7 @@ int64_t floatx80_to_int64(floatx80 a, float_status *status) int64_t floatx80_to_int64_round_to_zero(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp, shiftCount; uint64_t aSig; int64_t z; @@ -5572,7 +5570,7 @@ int64_t floatx80_to_int64_round_to_zero(floatx80 a, float_status *status) float32 floatx80_to_float32(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -5606,7 +5604,7 @@ float32 floatx80_to_float32(floatx80 a, float_status *status) float64 floatx80_to_float64(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig, zSig; @@ -5640,7 +5638,7 @@ float64 floatx80_to_float64(floatx80 a, float_status *status) float128 floatx80_to_float128(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int aExp; uint64_t aSig, zSig0, zSig1; @@ -5686,7 +5684,7 @@ floatx80 floatx80_round(floatx80 a, float_status *status) floatx80 floatx80_round_to_int(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t lastBitMask, roundBitsMask; floatx80 z; @@ -5783,7 +5781,7 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status) | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static floatx80 addFloatx80Sigs(floatx80 a, floatx80 b, flag zSign, +static floatx80 addFloatx80Sigs(floatx80 a, floatx80 b, bool zSign, float_status *status) { int32_t aExp, bExp, zExp; @@ -5863,7 +5861,7 @@ static floatx80 addFloatx80Sigs(floatx80 a, floatx80 b, flag zSign, | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static floatx80 subFloatx80Sigs(floatx80 a, floatx80 b, flag zSign, +static floatx80 subFloatx80Sigs(floatx80 a, floatx80 b, bool zSign, float_status *status) { int32_t aExp, bExp, zExp; @@ -5932,7 +5930,7 @@ static floatx80 subFloatx80Sigs(floatx80 a, floatx80 b, flag zSign, floatx80 floatx80_add(floatx80 a, floatx80 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { float_raise(float_flag_invalid, status); @@ -5957,7 +5955,7 @@ floatx80 floatx80_add(floatx80 a, floatx80 b, float_status *status) floatx80 floatx80_sub(floatx80 a, floatx80 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { float_raise(float_flag_invalid, status); @@ -5982,7 +5980,7 @@ floatx80 floatx80_sub(floatx80 a, floatx80 b, float_status *status) floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status) { - flag aSign, bSign, zSign; + bool aSign, bSign, zSign; int32_t aExp, bExp, zExp; uint64_t aSig, bSig, zSig0, zSig1; @@ -6044,7 +6042,7 @@ floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status) floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status) { - flag aSign, bSign, zSign; + bool aSign, bSign, zSign; int32_t aExp, bExp, zExp; uint64_t aSig, bSig, zSig0, zSig1; uint64_t rem0, rem1, rem2, term0, term1, term2; @@ -6131,7 +6129,7 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status) floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status) { - flag aSign, zSign; + bool aSign, zSign; int32_t aExp, bExp, expDiff; uint64_t aSig0, aSig1, bSig; uint64_t q, term0, term1, alternateASig0, alternateASig1; @@ -6230,7 +6228,7 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status) floatx80 floatx80_sqrt(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp, zExp; uint64_t aSig0, aSig1, zSig0, zSig1, doubleZSig0; uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3; @@ -6331,7 +6329,7 @@ int floatx80_eq(floatx80 a, floatx80 b, float_status *status) int floatx80_le(floatx80 a, floatx80 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) || (extractFloatx80Exp(a) == 0x7FFF @@ -6365,7 +6363,7 @@ int floatx80_le(floatx80 a, floatx80 b, float_status *status) int floatx80_lt(floatx80 a, floatx80 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) || (extractFloatx80Exp(a) == 0x7FFF @@ -6453,7 +6451,7 @@ int floatx80_eq_quiet(floatx80 a, floatx80 b, float_status *status) int floatx80_le_quiet(floatx80 a, floatx80 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { float_raise(float_flag_invalid, status); @@ -6493,7 +6491,7 @@ int floatx80_le_quiet(floatx80 a, floatx80 b, float_status *status) int floatx80_lt_quiet(floatx80 a, floatx80 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { float_raise(float_flag_invalid, status); @@ -6562,7 +6560,7 @@ int floatx80_unordered_quiet(floatx80 a, floatx80 b, float_status *status) int32_t float128_to_int32(float128 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp, shiftCount; uint64_t aSig0, aSig1; @@ -6591,7 +6589,7 @@ int32_t float128_to_int32(float128 a, float_status *status) int32_t float128_to_int32_round_to_zero(float128 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp, shiftCount; uint64_t aSig0, aSig1, savedASig; int32_t z; @@ -6641,7 +6639,7 @@ int32_t float128_to_int32_round_to_zero(float128 a, float_status *status) int64_t float128_to_int64(float128 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp, shiftCount; uint64_t aSig0, aSig1; @@ -6684,7 +6682,7 @@ int64_t float128_to_int64(float128 a, float_status *status) int64_t float128_to_int64_round_to_zero(float128 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp, shiftCount; uint64_t aSig0, aSig1; int64_t z; @@ -6749,7 +6747,7 @@ int64_t float128_to_int64_round_to_zero(float128 a, float_status *status) uint64_t float128_to_uint64(float128 a, float_status *status) { - flag aSign; + bool aSign; int aExp; int shiftCount; uint64_t aSig0, aSig1; @@ -6860,7 +6858,7 @@ uint32_t float128_to_uint32(float128 a, float_status *status) float32 float128_to_float32(float128 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig0, aSig1; uint32_t zSig; @@ -6895,7 +6893,7 @@ float32 float128_to_float32(float128 a, float_status *status) float64 float128_to_float64(float128 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig0, aSig1; @@ -6928,7 +6926,7 @@ float64 float128_to_float64(float128 a, float_status *status) floatx80 float128_to_floatx80(float128 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig0, aSig1; @@ -6966,7 +6964,7 @@ floatx80 float128_to_floatx80(float128 a, float_status *status) float128 float128_round_to_int(float128 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t lastBitMask, roundBitsMask; float128 z; @@ -7121,7 +7119,7 @@ float128 float128_round_to_int(float128 a, float_status *status) | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static float128 addFloat128Sigs(float128 a, float128 b, flag zSign, +static float128 addFloat128Sigs(float128 a, float128 b, bool zSign, float_status *status) { int32_t aExp, bExp, zExp; @@ -7212,7 +7210,7 @@ static float128 addFloat128Sigs(float128 a, float128 b, flag zSign, | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static float128 subFloat128Sigs(float128 a, float128 b, flag zSign, +static float128 subFloat128Sigs(float128 a, float128 b, bool zSign, float_status *status) { int32_t aExp, bExp, zExp; @@ -7300,7 +7298,7 @@ static float128 subFloat128Sigs(float128 a, float128 b, flag zSign, float128 float128_add(float128 a, float128 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; aSign = extractFloat128Sign( a ); bSign = extractFloat128Sign( b ); @@ -7321,7 +7319,7 @@ float128 float128_add(float128 a, float128 b, float_status *status) float128 float128_sub(float128 a, float128 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; aSign = extractFloat128Sign( a ); bSign = extractFloat128Sign( b ); @@ -7342,7 +7340,7 @@ float128 float128_sub(float128 a, float128 b, float_status *status) float128 float128_mul(float128 a, float128 b, float_status *status) { - flag aSign, bSign, zSign; + bool aSign, bSign, zSign; int32_t aExp, bExp, zExp; uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; @@ -7405,7 +7403,7 @@ float128 float128_mul(float128 a, float128 b, float_status *status) float128 float128_div(float128 a, float128 b, float_status *status) { - flag aSign, bSign, zSign; + bool aSign, bSign, zSign; int32_t aExp, bExp, zExp; uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3; @@ -7492,7 +7490,7 @@ float128 float128_div(float128 a, float128 b, float_status *status) float128 float128_rem(float128 a, float128 b, float_status *status) { - flag aSign, zSign; + bool aSign, zSign; int32_t aExp, bExp, expDiff; uint64_t aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2; uint64_t allZero, alternateASig0, alternateASig1, sigMean1; @@ -7599,7 +7597,7 @@ float128 float128_rem(float128 a, float128 b, float_status *status) float128 float128_sqrt(float128 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp, zExp; uint64_t aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0; uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3; @@ -7695,7 +7693,7 @@ int float128_eq(float128 a, float128 b, float_status *status) int float128_le(float128 a, float128 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) @@ -7728,7 +7726,7 @@ int float128_le(float128 a, float128 b, float_status *status) int float128_lt(float128 a, float128 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) @@ -7811,7 +7809,7 @@ int float128_eq_quiet(float128 a, float128 b, float_status *status) int float128_le_quiet(float128 a, float128 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) @@ -7847,7 +7845,7 @@ int float128_le_quiet(float128 a, float128 b, float_status *status) int float128_lt_quiet(float128 a, float128 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) @@ -7900,7 +7898,7 @@ int float128_unordered_quiet(float128 a, float128 b, float_status *status) static inline int floatx80_compare_internal(floatx80 a, floatx80 b, int is_quiet, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { float_raise(float_flag_invalid, status); @@ -7957,7 +7955,7 @@ int floatx80_compare_quiet(floatx80 a, floatx80 b, float_status *status) static inline int float128_compare_internal(float128 a, float128 b, int is_quiet, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; if (( ( extractFloat128Exp( a ) == 0x7fff ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || @@ -8000,7 +7998,7 @@ int float128_compare_quiet(float128 a, float128 b, float_status *status) floatx80 floatx80_scalbn(floatx80 a, int n, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -8039,7 +8037,7 @@ floatx80 floatx80_scalbn(floatx80 a, int n, float_status *status) float128 float128_scalbn(float128 a, int n, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig0, aSig1; diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index e0baf24c8f..528d7ebd9f 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -74,22 +74,22 @@ static inline void set_floatx80_rounding_precision(int val, status->floatx80_rounding_precision = val; } -static inline void set_flush_to_zero(flag val, float_status *status) +static inline void set_flush_to_zero(bool val, float_status *status) { status->flush_to_zero = val; } -static inline void set_flush_inputs_to_zero(flag val, float_status *status) +static inline void set_flush_inputs_to_zero(bool val, float_status *status) { status->flush_inputs_to_zero = val; } -static inline void set_default_nan_mode(flag val, float_status *status) +static inline void set_default_nan_mode(bool val, float_status *status) { status->default_nan_mode = val; } -static inline void set_snan_bit_is_one(flag val, float_status *status) +static inline void set_snan_bit_is_one(bool val, float_status *status) { status->snan_bit_is_one = val; } @@ -114,17 +114,17 @@ static inline int get_floatx80_rounding_precision(float_status *status) return status->floatx80_rounding_precision; } -static inline flag get_flush_to_zero(float_status *status) +static inline bool get_flush_to_zero(float_status *status) { return status->flush_to_zero; } -static inline flag get_flush_inputs_to_zero(float_status *status) +static inline bool get_flush_inputs_to_zero(float_status *status) { return status->flush_inputs_to_zero; } -static inline flag get_default_nan_mode(float_status *status) +static inline bool get_default_nan_mode(float_status *status) { return status->default_nan_mode; } diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h index 605c4f4bc6..a35ec2893a 100644 --- a/include/fpu/softfloat-macros.h +++ b/include/fpu/softfloat-macros.h @@ -756,11 +756,9 @@ static inline uint32_t estimateSqrt32(int aExp, uint32_t a) | Otherwise, returns 0. *----------------------------------------------------------------------------*/ -static inline flag eq128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 ) +static inline bool eq128(uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1) { - - return ( a0 == b0 ) && ( a1 == b1 ); - + return a0 == b0 && a1 == b1; } /*---------------------------------------------------------------------------- @@ -769,11 +767,9 @@ static inline flag eq128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 ) | Otherwise, returns 0. *----------------------------------------------------------------------------*/ -static inline flag le128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 ) +static inline bool le128(uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1) { - - return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); - + return a0 < b0 || (a0 == b0 && a1 <= b1); } /*---------------------------------------------------------------------------- @@ -782,11 +778,9 @@ static inline flag le128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 ) | returns 0. *----------------------------------------------------------------------------*/ -static inline flag lt128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 ) +static inline bool lt128(uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1) { - - return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); - + return a0 < b0 || (a0 == b0 && a1 < b1); } /*---------------------------------------------------------------------------- @@ -795,11 +789,9 @@ static inline flag lt128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 ) | Otherwise, returns 0. *----------------------------------------------------------------------------*/ -static inline flag ne128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 ) +static inline bool ne128(uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1) { - - return ( a0 != b0 ) || ( a1 != b1 ); - + return a0 != b0 || a1 != b1; } #endif diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index 2aae6a89b1..619b875df6 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -80,12 +80,6 @@ this code that are retained. #ifndef SOFTFLOAT_TYPES_H #define SOFTFLOAT_TYPES_H -/* This 'flag' type must be able to hold at least 0 and 1. It should - * probably be replaced with 'bool' but the uses would need to be audited - * to check that they weren't accidentally relying on it being a larger type. - */ -typedef uint8_t flag; - /* * Software IEC/IEEE floating-point types. */ @@ -169,12 +163,12 @@ typedef struct float_status { uint8_t float_exception_flags; signed char floatx80_rounding_precision; /* should denormalised results go to zero and set the inexact flag? */ - flag flush_to_zero; + bool flush_to_zero; /* should denormalised inputs go to zero and set the input_denormal flag? */ - flag flush_inputs_to_zero; - flag default_nan_mode; + bool flush_inputs_to_zero; + bool default_nan_mode; /* not always used -- see snan_bit_is_one() in softfloat-specialize.h */ - flag snan_bit_is_one; + bool snan_bit_is_one; } float_status; #endif /* SOFTFLOAT_TYPES_H */ diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index ecb8ba0114..3f588da7c7 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -440,7 +440,7 @@ static inline float32 float32_set_sign(float32 a, int sign) | significand. *----------------------------------------------------------------------------*/ -static inline float32 packFloat32(flag zSign, int zExp, uint32_t zSig) +static inline float32 packFloat32(bool zSign, int zExp, uint32_t zSig) { return make_float32( (((uint32_t)zSign) << 31) + (((uint32_t)zExp) << 23) + zSig); @@ -722,7 +722,7 @@ static inline int32_t extractFloatx80Exp(floatx80 a) | `a'. *----------------------------------------------------------------------------*/ -static inline flag extractFloatx80Sign(floatx80 a) +static inline bool extractFloatx80Sign(floatx80 a) { return a.high >> 15; } @@ -732,7 +732,7 @@ static inline flag extractFloatx80Sign(floatx80 a) | extended double-precision floating-point value, returning the result. *----------------------------------------------------------------------------*/ -static inline floatx80 packFloatx80(flag zSign, int32_t zExp, uint64_t zSig) +static inline floatx80 packFloatx80(bool zSign, int32_t zExp, uint64_t zSig) { floatx80 z; @@ -783,7 +783,7 @@ floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status); | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -floatx80 roundAndPackFloatx80(int8_t roundingPrecision, flag zSign, +floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status); @@ -797,7 +797,7 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, flag zSign, *----------------------------------------------------------------------------*/ floatx80 normalizeRoundAndPackFloatx80(int8_t roundingPrecision, - flag zSign, int32_t zExp, + bool zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status); diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 0da254d402..e590db6637 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -3201,7 +3201,7 @@ void HELPER(NAME)(void *vd, void *vn, void *vg, void *status, uint32_t desc) \ */ static inline float32 sve_f16_to_f32(float16 f, float_status *fpst) { - flag save = get_flush_inputs_to_zero(fpst); + bool save = get_flush_inputs_to_zero(fpst); float32 ret; set_flush_inputs_to_zero(false, fpst); @@ -3212,7 +3212,7 @@ static inline float32 sve_f16_to_f32(float16 f, float_status *fpst) static inline float64 sve_f16_to_f64(float16 f, float_status *fpst) { - flag save = get_flush_inputs_to_zero(fpst); + bool save = get_flush_inputs_to_zero(fpst); float64 ret; set_flush_inputs_to_zero(false, fpst); @@ -3223,7 +3223,7 @@ static inline float64 sve_f16_to_f64(float16 f, float_status *fpst) static inline float16 sve_f32_to_f16(float32 f, float_status *fpst) { - flag save = get_flush_to_zero(fpst); + bool save = get_flush_to_zero(fpst); float16 ret; set_flush_to_zero(false, fpst); @@ -3234,7 +3234,7 @@ static inline float16 sve_f32_to_f16(float32 f, float_status *fpst) static inline float16 sve_f64_to_f16(float64 f, float_status *fpst) { - flag save = get_flush_to_zero(fpst); + bool save = get_flush_to_zero(fpst); float16 ret; set_flush_to_zero(false, fpst); diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index 88483d4066..42625747d1 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -531,7 +531,7 @@ float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, void *fpstp, uint32_t ahp_mode) * it would affect flushing input denormals. */ float_status *fpst = fpstp; - flag save = get_flush_inputs_to_zero(fpst); + bool save = get_flush_inputs_to_zero(fpst); set_flush_inputs_to_zero(false, fpst); float32 r = float16_to_float32(a, !ahp_mode, fpst); set_flush_inputs_to_zero(save, fpst); @@ -544,7 +544,7 @@ uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, void *fpstp, uint32_t ahp_mode) * it would affect flushing output denormals. */ float_status *fpst = fpstp; - flag save = get_flush_to_zero(fpst); + bool save = get_flush_to_zero(fpst); set_flush_to_zero(false, fpst); float16 r = float32_to_float16(a, !ahp_mode, fpst); set_flush_to_zero(save, fpst); @@ -557,7 +557,7 @@ float64 HELPER(vfp_fcvt_f16_to_f64)(uint32_t a, void *fpstp, uint32_t ahp_mode) * it would affect flushing input denormals. */ float_status *fpst = fpstp; - flag save = get_flush_inputs_to_zero(fpst); + bool save = get_flush_inputs_to_zero(fpst); set_flush_inputs_to_zero(false, fpst); float64 r = float16_to_float64(a, !ahp_mode, fpst); set_flush_inputs_to_zero(save, fpst); @@ -570,7 +570,7 @@ uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, void *fpstp, uint32_t ahp_mode) * it would affect flushing output denormals. */ float_status *fpst = fpstp; - flag save = get_flush_to_zero(fpst); + bool save = get_flush_to_zero(fpst); set_flush_to_zero(false, fpst); float16 r = float64_to_float16(a, !ahp_mode, fpst); set_flush_to_zero(save, fpst); diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c index 24c313ed69..9f120cf15e 100644 --- a/target/m68k/softfloat.c +++ b/target/m68k/softfloat.c @@ -49,7 +49,7 @@ static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status) floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status) { - flag aSign, zSign; + bool aSign, zSign; int32_t aExp, bExp, expDiff; uint64_t aSig0, aSig1, bSig; uint64_t qTemp, term0, term1; @@ -132,7 +132,7 @@ floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status) floatx80 floatx80_getman(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -166,7 +166,7 @@ floatx80 floatx80_getman(floatx80 a, float_status *status) floatx80 floatx80_getexp(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -202,7 +202,7 @@ floatx80 floatx80_getexp(floatx80 a, float_status *status) floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status) { - flag aSign, bSign; + bool aSign, bSign; int32_t aExp, bExp, shiftCount; uint64_t aSig, bSig; @@ -258,7 +258,7 @@ floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status) floatx80 floatx80_move(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -306,7 +306,7 @@ static int32_t floatx80_make_compact(int32_t aExp, uint64_t aSig) floatx80 floatx80_lognp1(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig, fSig; @@ -505,7 +505,7 @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status) floatx80 floatx80_logn(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig, fSig; @@ -673,7 +673,7 @@ floatx80 floatx80_logn(floatx80 a, float_status *status) floatx80 floatx80_log10(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -730,7 +730,7 @@ floatx80 floatx80_log10(floatx80 a, float_status *status) floatx80 floatx80_log2(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -797,7 +797,7 @@ floatx80 floatx80_log2(floatx80 a, float_status *status) floatx80 floatx80_etox(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -805,7 +805,7 @@ floatx80 floatx80_etox(floatx80 a, float_status *status) int32_t compact, n, j, k, m, m1; floatx80 fp0, fp1, fp2, fp3, l2, scale, adjscale; - flag adjflag; + bool adjflag; aSig = extractFloatx80Frac(a); aExp = extractFloatx80Exp(a); @@ -981,7 +981,7 @@ floatx80 floatx80_etox(floatx80 a, float_status *status) floatx80 floatx80_twotox(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -1131,7 +1131,7 @@ floatx80 floatx80_twotox(floatx80 a, float_status *status) floatx80 floatx80_tentox(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -1286,7 +1286,7 @@ floatx80 floatx80_tentox(floatx80 a, float_status *status) floatx80 floatx80_tan(floatx80 a, float_status *status) { - flag aSign, xSign; + bool aSign, xSign; int32_t aExp, xExp; uint64_t aSig, xSig; @@ -1295,7 +1295,7 @@ floatx80 floatx80_tan(floatx80 a, float_status *status) int32_t compact, l, n, j; floatx80 fp0, fp1, fp2, fp3, fp4, fp5, invtwopi, twopi1, twopi2; float32 twoto63; - flag endflag; + bool endflag; aSig = extractFloatx80Frac(a); aExp = extractFloatx80Exp(a); @@ -1344,10 +1344,10 @@ floatx80 floatx80_tan(floatx80 a, float_status *status) xExp -= 0x3FFF; if (xExp <= 28) { l = 0; - endflag = 1; + endflag = true; } else { l = xExp - 27; - endflag = 0; + endflag = false; } invtwopi = packFloatx80(0, 0x3FFE - l, UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */ @@ -1372,7 +1372,7 @@ floatx80 floatx80_tan(floatx80 a, float_status *status) fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */ fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */ - if (endflag > 0) { + if (endflag) { n = floatx80_to_int32(fp2, status); goto tancont; } @@ -1496,7 +1496,7 @@ floatx80 floatx80_tan(floatx80 a, float_status *status) floatx80 floatx80_sin(floatx80 a, float_status *status) { - flag aSign, xSign; + bool aSign, xSign; int32_t aExp, xExp; uint64_t aSig, xSig; @@ -1505,7 +1505,7 @@ floatx80 floatx80_sin(floatx80 a, float_status *status) int32_t compact, l, n, j; floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2; float32 posneg1, twoto63; - flag endflag; + bool endflag; aSig = extractFloatx80Frac(a); aExp = extractFloatx80Exp(a); @@ -1554,10 +1554,10 @@ floatx80 floatx80_sin(floatx80 a, float_status *status) xExp -= 0x3FFF; if (xExp <= 28) { l = 0; - endflag = 1; + endflag = true; } else { l = xExp - 27; - endflag = 0; + endflag = false; } invtwopi = packFloatx80(0, 0x3FFE - l, UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */ @@ -1582,7 +1582,7 @@ floatx80 floatx80_sin(floatx80 a, float_status *status) fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */ fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */ - if (endflag > 0) { + if (endflag) { n = floatx80_to_int32(fp2, status); goto sincont; } @@ -1735,7 +1735,7 @@ floatx80 floatx80_sin(floatx80 a, float_status *status) floatx80 floatx80_cos(floatx80 a, float_status *status) { - flag aSign, xSign; + bool aSign, xSign; int32_t aExp, xExp; uint64_t aSig, xSig; @@ -1744,7 +1744,7 @@ floatx80 floatx80_cos(floatx80 a, float_status *status) int32_t compact, l, n, j; floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2; float32 posneg1, twoto63; - flag endflag; + bool endflag; aSig = extractFloatx80Frac(a); aExp = extractFloatx80Exp(a); @@ -1793,10 +1793,10 @@ floatx80 floatx80_cos(floatx80 a, float_status *status) xExp -= 0x3FFF; if (xExp <= 28) { l = 0; - endflag = 1; + endflag = true; } else { l = xExp - 27; - endflag = 0; + endflag = false; } invtwopi = packFloatx80(0, 0x3FFE - l, UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */ @@ -1821,7 +1821,7 @@ floatx80 floatx80_cos(floatx80 a, float_status *status) fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */ fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */ - if (endflag > 0) { + if (endflag) { n = floatx80_to_int32(fp2, status); goto sincont; } @@ -1972,7 +1972,7 @@ floatx80 floatx80_cos(floatx80 a, float_status *status) floatx80 floatx80_atan(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -2169,7 +2169,7 @@ floatx80 floatx80_atan(floatx80 a, float_status *status) floatx80 floatx80_asin(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -2234,7 +2234,7 @@ floatx80 floatx80_asin(floatx80 a, float_status *status) floatx80 floatx80_acos(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -2303,7 +2303,7 @@ floatx80 floatx80_acos(floatx80 a, float_status *status) floatx80 floatx80_atanh(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -2368,7 +2368,7 @@ floatx80 floatx80_atanh(floatx80 a, float_status *status) floatx80 floatx80_etoxm1(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; @@ -2620,7 +2620,7 @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status) floatx80 floatx80_tanh(floatx80 a, float_status *status) { - flag aSign, vSign; + bool aSign, vSign; int32_t aExp, vExp; uint64_t aSig, vSig; @@ -2735,7 +2735,7 @@ floatx80 floatx80_tanh(floatx80 a, float_status *status) floatx80 floatx80_sinh(floatx80 a, float_status *status) { - flag aSign; + bool aSign; int32_t aExp; uint64_t aSig; diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 4065cfe4f7..3c7012c0b8 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -5508,7 +5508,7 @@ static inline int get_enabled_exceptions(const CPUMIPSState *env, int c) return c & enable; } -static inline float16 float16_from_float32(int32_t a, flag ieee, +static inline float16 float16_from_float32(int32_t a, bool ieee, float_status *status) { float16 f_val; @@ -5527,7 +5527,7 @@ static inline float32 float32_from_float64(int64_t a, float_status *status) return a < 0 ? (f_val | (1 << 31)) : f_val; } -static inline float32 float32_from_float16(int16_t a, flag ieee, +static inline float32 float32_from_float16(int16_t a, bool ieee, float_status *status) { float32 f_val; @@ -6564,7 +6564,7 @@ void helper_msa_fexdo_df(CPUMIPSState *env, uint32_t df, uint32_t wd, * IEEE and "ARM" format. The latter gains extra exponent * range by omitting the NaN/Inf encodings. */ - flag ieee = 1; + bool ieee = true; MSA_FLOAT_BINOP(Lh(pwx, i), from_float32, pws->w[i], ieee, 16); MSA_FLOAT_BINOP(Rh(pwx, i), from_float32, pwt->w[i], ieee, 16); @@ -7178,7 +7178,7 @@ void helper_msa_fexupl_df(CPUMIPSState *env, uint32_t df, uint32_t wd, * IEEE and "ARM" format. The latter gains extra exponent * range by omitting the NaN/Inf encodings. */ - flag ieee = 1; + bool ieee = true; MSA_FLOAT_BINOP(pwx->w[i], from_float16, Lh(pws, i), ieee, 32); } @@ -7214,7 +7214,7 @@ void helper_msa_fexupr_df(CPUMIPSState *env, uint32_t df, uint32_t wd, * IEEE and "ARM" format. The latter gains extra exponent * range by omitting the NaN/Inf encodings. */ - flag ieee = 1; + bool ieee = true; MSA_FLOAT_BINOP(pwx->w[i], from_float16, Rh(pws, i), ieee, 32); } From a828b373bdabc7e53d1e218e3fc76f85b6674688 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 4 May 2020 21:19:39 -0700 Subject: [PATCH 0598/2595] softfloat: Change tininess_before_rounding to bool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Slightly tidies the usage within softfloat.c and the representation in float_status. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 54 ++++++++++++--------------------- include/fpu/softfloat-helpers.h | 8 ++--- include/fpu/softfloat-types.h | 8 ++--- tests/fp/fp-test.c | 2 +- 4 files changed, 28 insertions(+), 44 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index b741cf5bc3..65d457a548 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -744,8 +744,7 @@ static FloatParts round_canonical(FloatParts p, float_status *s, p.cls = float_class_zero; goto do_zero; } else { - bool is_tiny = (s->float_detect_tininess - == float_tininess_before_rounding) + bool is_tiny = s->tininess_before_rounding || (exp < 0) || !((frac + inc) & DECOMPOSED_OVERFLOW_BIT); @@ -3579,11 +3578,9 @@ static float32 roundAndPackFloat32(bool zSign, int zExp, uint32_t zSig, float_raise(float_flag_output_denormal, status); return packFloat32(zSign, 0, 0); } - isTiny = - (status->float_detect_tininess - == float_tininess_before_rounding) - || ( zExp < -1 ) - || ( zSig + roundIncrement < 0x80000000 ); + isTiny = status->tininess_before_rounding + || (zExp < -1) + || (zSig + roundIncrement < 0x80000000); shift32RightJamming( zSig, - zExp, &zSig ); zExp = 0; roundBits = zSig & 0x7F; @@ -3735,11 +3732,9 @@ static float64 roundAndPackFloat64(bool zSign, int zExp, uint64_t zSig, float_raise(float_flag_output_denormal, status); return packFloat64(zSign, 0, 0); } - isTiny = - (status->float_detect_tininess - == float_tininess_before_rounding) - || ( zExp < -1 ) - || ( zSig + roundIncrement < UINT64_C(0x8000000000000000) ); + isTiny = status->tininess_before_rounding + || (zExp < -1) + || (zSig + roundIncrement < UINT64_C(0x8000000000000000)); shift64RightJamming( zSig, - zExp, &zSig ); zExp = 0; roundBits = zSig & 0x3FF; @@ -3878,11 +3873,9 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign, float_raise(float_flag_output_denormal, status); return packFloatx80(zSign, 0, 0); } - isTiny = - (status->float_detect_tininess - == float_tininess_before_rounding) - || ( zExp < 0 ) - || ( zSig0 <= zSig0 + roundIncrement ); + isTiny = status->tininess_before_rounding + || (zExp < 0 ) + || (zSig0 <= zSig0 + roundIncrement); shift64RightJamming( zSig0, 1 - zExp, &zSig0 ); zExp = 0; roundBits = zSig0 & roundMask; @@ -3956,12 +3949,10 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign, floatx80_infinity_low); } if ( zExp <= 0 ) { - isTiny = - (status->float_detect_tininess - == float_tininess_before_rounding) - || ( zExp < 0 ) - || ! increment - || ( zSig0 < UINT64_C(0xFFFFFFFFFFFFFFFF) ); + isTiny = status->tininess_before_rounding + || (zExp < 0) + || !increment + || (zSig0 < UINT64_C(0xFFFFFFFFFFFFFFFF)); shift64ExtraRightJamming( zSig0, zSig1, 1 - zExp, &zSig0, &zSig1 ); zExp = 0; if (isTiny && zSig1) { @@ -4237,17 +4228,12 @@ static float128 roundAndPackFloat128(bool zSign, int32_t zExp, float_raise(float_flag_output_denormal, status); return packFloat128(zSign, 0, 0, 0); } - isTiny = - (status->float_detect_tininess - == float_tininess_before_rounding) - || ( zExp < -1 ) - || ! increment - || lt128( - zSig0, - zSig1, - UINT64_C(0x0001FFFFFFFFFFFF), - UINT64_C(0xFFFFFFFFFFFFFFFF) - ); + isTiny = status->tininess_before_rounding + || (zExp < -1) + || !increment + || lt128(zSig0, zSig1, + UINT64_C(0x0001FFFFFFFFFFFF), + UINT64_C(0xFFFFFFFFFFFFFFFF)); shift128ExtraRightJamming( zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 ); zExp = 0; diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index 528d7ebd9f..40d32a6d5d 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -53,9 +53,9 @@ this code that are retained. #include "fpu/softfloat-types.h" -static inline void set_float_detect_tininess(int val, float_status *status) +static inline void set_float_detect_tininess(bool val, float_status *status) { - status->float_detect_tininess = val; + status->tininess_before_rounding = val; } static inline void set_float_rounding_mode(int val, float_status *status) @@ -94,9 +94,9 @@ static inline void set_snan_bit_is_one(bool val, float_status *status) status->snan_bit_is_one = val; } -static inline int get_float_detect_tininess(float_status *status) +static inline bool get_float_detect_tininess(float_status *status) { - return status->float_detect_tininess; + return status->tininess_before_rounding; } static inline int get_float_rounding_mode(float_status *status) diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index 619b875df6..874ddd9f93 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -116,10 +116,8 @@ typedef struct { * Software IEC/IEEE floating-point underflow tininess-detection mode. */ -enum { - float_tininess_after_rounding = 0, - float_tininess_before_rounding = 1 -}; +#define float_tininess_after_rounding false +#define float_tininess_before_rounding true /* *Software IEC/IEEE floating-point rounding mode. @@ -158,10 +156,10 @@ enum { */ typedef struct float_status { - signed char float_detect_tininess; signed char float_rounding_mode; uint8_t float_exception_flags; signed char floatx80_rounding_precision; + bool tininess_before_rounding; /* should denormalised results go to zero and set the inexact flag? */ bool flush_to_zero; /* should denormalised inputs go to zero and set the input_denormal flag? */ diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c index 7d0faf2b47..43ef9628c4 100644 --- a/tests/fp/fp-test.c +++ b/tests/fp/fp-test.c @@ -989,7 +989,7 @@ static void QEMU_NORETURN run_test(void) verCases_tininessCode = 0; slowfloat_detectTininess = tmode; - qsf.float_detect_tininess = sf_tininess_to_qemu(tmode); + qsf.tininess_before_rounding = sf_tininess_to_qemu(tmode); if (attrs & FUNC_EFF_TININESSMODE || ((attrs & FUNC_EFF_TININESSMODE_REDUCEDPREC) && From 3dede407cc61b64997f0c30f6dbf4df09949abc9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 May 2020 09:01:49 -0700 Subject: [PATCH 0599/2595] softfloat: Name rounding mode enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Give the previously unnamed enum a typedef name. Use the packed attribute so that we do not affect the layout of the float_status struct. Use it in the prototypes of relevant functions. Adjust switch statements as necessary to avoid compiler warnings. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- fpu/softfloat.c | 57 ++++++++++++++++++++------------- include/fpu/softfloat-helpers.h | 5 +-- include/fpu/softfloat-types.h | 6 ++-- include/fpu/softfloat.h | 39 +++++++++++----------- target/arm/vfp_helper.c | 4 +-- target/m68k/fpu_helper.c | 6 ++-- 6 files changed, 66 insertions(+), 51 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 65d457a548..93d8a03de6 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -759,6 +759,8 @@ static FloatParts round_canonical(FloatParts p, float_status *s, case float_round_to_odd: inc = frac & frac_lsb ? 0 : round_mask; break; + default: + break; } flags |= float_flag_inexact; frac += inc; @@ -1928,7 +1930,7 @@ float32 float64_to_float32(float64 a, float_status *s) * Arithmetic. */ -static FloatParts round_to_int(FloatParts a, int rmode, +static FloatParts round_to_int(FloatParts a, FloatRoundMode rmode, int scale, float_status *s) { switch (a.cls) { @@ -2061,8 +2063,8 @@ float64 float64_round_to_int(float64 a, float_status *s) * is returned. */ -static int64_t round_to_int_and_pack(FloatParts in, int rmode, int scale, - int64_t min, int64_t max, +static int64_t round_to_int_and_pack(FloatParts in, FloatRoundMode rmode, + int scale, int64_t min, int64_t max, float_status *s) { uint64_t r; @@ -2107,63 +2109,63 @@ static int64_t round_to_int_and_pack(FloatParts in, int rmode, int scale, } } -int16_t float16_to_int16_scalbn(float16 a, int rmode, int scale, +int16_t float16_to_int16_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_int_and_pack(float16_unpack_canonical(a, s), rmode, scale, INT16_MIN, INT16_MAX, s); } -int32_t float16_to_int32_scalbn(float16 a, int rmode, int scale, +int32_t float16_to_int32_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_int_and_pack(float16_unpack_canonical(a, s), rmode, scale, INT32_MIN, INT32_MAX, s); } -int64_t float16_to_int64_scalbn(float16 a, int rmode, int scale, +int64_t float16_to_int64_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_int_and_pack(float16_unpack_canonical(a, s), rmode, scale, INT64_MIN, INT64_MAX, s); } -int16_t float32_to_int16_scalbn(float32 a, int rmode, int scale, +int16_t float32_to_int16_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_int_and_pack(float32_unpack_canonical(a, s), rmode, scale, INT16_MIN, INT16_MAX, s); } -int32_t float32_to_int32_scalbn(float32 a, int rmode, int scale, +int32_t float32_to_int32_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_int_and_pack(float32_unpack_canonical(a, s), rmode, scale, INT32_MIN, INT32_MAX, s); } -int64_t float32_to_int64_scalbn(float32 a, int rmode, int scale, +int64_t float32_to_int64_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_int_and_pack(float32_unpack_canonical(a, s), rmode, scale, INT64_MIN, INT64_MAX, s); } -int16_t float64_to_int16_scalbn(float64 a, int rmode, int scale, +int16_t float64_to_int16_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_int_and_pack(float64_unpack_canonical(a, s), rmode, scale, INT16_MIN, INT16_MAX, s); } -int32_t float64_to_int32_scalbn(float64 a, int rmode, int scale, +int32_t float64_to_int32_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_int_and_pack(float64_unpack_canonical(a, s), rmode, scale, INT32_MIN, INT32_MAX, s); } -int64_t float64_to_int64_scalbn(float64 a, int rmode, int scale, +int64_t float64_to_int64_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_int_and_pack(float64_unpack_canonical(a, s), @@ -2273,8 +2275,9 @@ int64_t float64_to_int64_round_to_zero(float64 a, float_status *s) * flag. */ -static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, int scale, - uint64_t max, float_status *s) +static uint64_t round_to_uint_and_pack(FloatParts in, FloatRoundMode rmode, + int scale, uint64_t max, + float_status *s) { int orig_flags = get_float_exception_flags(s); FloatParts p = round_to_int(in, rmode, scale, s); @@ -2319,63 +2322,63 @@ static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, int scale, } } -uint16_t float16_to_uint16_scalbn(float16 a, int rmode, int scale, +uint16_t float16_to_uint16_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_uint_and_pack(float16_unpack_canonical(a, s), rmode, scale, UINT16_MAX, s); } -uint32_t float16_to_uint32_scalbn(float16 a, int rmode, int scale, +uint32_t float16_to_uint32_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_uint_and_pack(float16_unpack_canonical(a, s), rmode, scale, UINT32_MAX, s); } -uint64_t float16_to_uint64_scalbn(float16 a, int rmode, int scale, +uint64_t float16_to_uint64_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_uint_and_pack(float16_unpack_canonical(a, s), rmode, scale, UINT64_MAX, s); } -uint16_t float32_to_uint16_scalbn(float32 a, int rmode, int scale, +uint16_t float32_to_uint16_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_uint_and_pack(float32_unpack_canonical(a, s), rmode, scale, UINT16_MAX, s); } -uint32_t float32_to_uint32_scalbn(float32 a, int rmode, int scale, +uint32_t float32_to_uint32_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_uint_and_pack(float32_unpack_canonical(a, s), rmode, scale, UINT32_MAX, s); } -uint64_t float32_to_uint64_scalbn(float32 a, int rmode, int scale, +uint64_t float32_to_uint64_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_uint_and_pack(float32_unpack_canonical(a, s), rmode, scale, UINT64_MAX, s); } -uint16_t float64_to_uint16_scalbn(float64 a, int rmode, int scale, +uint16_t float64_to_uint16_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_uint_and_pack(float64_unpack_canonical(a, s), rmode, scale, UINT16_MAX, s); } -uint32_t float64_to_uint32_scalbn(float64 a, int rmode, int scale, +uint32_t float64_to_uint32_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_uint_and_pack(float64_unpack_canonical(a, s), rmode, scale, UINT32_MAX, s); } -uint64_t float64_to_uint64_scalbn(float64 a, int rmode, int scale, +uint64_t float64_to_uint64_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { return round_to_uint_and_pack(float64_unpack_canonical(a, s), @@ -5715,6 +5718,11 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status) return aSign ? packFloatx80( 1, 0, 0 ) : packFloatx80( 0, 0x3FFF, UINT64_C(0x8000000000000000)); + + case float_round_to_zero: + break; + default: + g_assert_not_reached(); } return packFloatx80( aSign, 0, 0 ); } @@ -7047,6 +7055,9 @@ float128 float128_round_to_int(float128 a, float_status *status) case float_round_to_odd: return packFloat128(aSign, 0x3FFF, 0, 0); + + case float_round_to_zero: + break; } return packFloat128( aSign, 0, 0, 0 ); } diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index 40d32a6d5d..735ed6b653 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -58,7 +58,8 @@ static inline void set_float_detect_tininess(bool val, float_status *status) status->tininess_before_rounding = val; } -static inline void set_float_rounding_mode(int val, float_status *status) +static inline void set_float_rounding_mode(FloatRoundMode val, + float_status *status) { status->float_rounding_mode = val; } @@ -99,7 +100,7 @@ static inline bool get_float_detect_tininess(float_status *status) return status->tininess_before_rounding; } -static inline int get_float_rounding_mode(float_status *status) +static inline FloatRoundMode get_float_rounding_mode(float_status *status) { return status->float_rounding_mode; } diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index 874ddd9f93..7680193ebc 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -123,7 +123,7 @@ typedef struct { *Software IEC/IEEE floating-point rounding mode. */ -enum { +typedef enum __attribute__((__packed__)) { float_round_nearest_even = 0, float_round_down = 1, float_round_up = 2, @@ -131,7 +131,7 @@ enum { float_round_ties_away = 4, /* Not an IEEE rounding mode: round to the closest odd mantissa value */ float_round_to_odd = 5, -}; +} FloatRoundMode; /* * Software IEC/IEEE floating-point exception flags. @@ -156,7 +156,7 @@ enum { */ typedef struct float_status { - signed char float_rounding_mode; + FloatRoundMode float_rounding_mode; uint8_t float_exception_flags; signed char floatx80_rounding_precision; bool tininess_before_rounding; diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 3f588da7c7..ca75f764aa 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -186,9 +186,9 @@ float32 float16_to_float32(float16, bool ieee, float_status *status); float16 float64_to_float16(float64 a, bool ieee, float_status *status); float64 float16_to_float64(float16 a, bool ieee, float_status *status); -int16_t float16_to_int16_scalbn(float16, int, int, float_status *status); -int32_t float16_to_int32_scalbn(float16, int, int, float_status *status); -int64_t float16_to_int64_scalbn(float16, int, int, float_status *status); +int16_t float16_to_int16_scalbn(float16, FloatRoundMode, int, float_status *); +int32_t float16_to_int32_scalbn(float16, FloatRoundMode, int, float_status *); +int64_t float16_to_int64_scalbn(float16, FloatRoundMode, int, float_status *); int16_t float16_to_int16(float16, float_status *status); int32_t float16_to_int32(float16, float_status *status); @@ -198,9 +198,12 @@ int16_t float16_to_int16_round_to_zero(float16, float_status *status); int32_t float16_to_int32_round_to_zero(float16, float_status *status); int64_t float16_to_int64_round_to_zero(float16, float_status *status); -uint16_t float16_to_uint16_scalbn(float16 a, int, int, float_status *status); -uint32_t float16_to_uint32_scalbn(float16 a, int, int, float_status *status); -uint64_t float16_to_uint64_scalbn(float16 a, int, int, float_status *status); +uint16_t float16_to_uint16_scalbn(float16 a, FloatRoundMode, + int, float_status *status); +uint32_t float16_to_uint32_scalbn(float16 a, FloatRoundMode, + int, float_status *status); +uint64_t float16_to_uint64_scalbn(float16 a, FloatRoundMode, + int, float_status *status); uint16_t float16_to_uint16(float16 a, float_status *status); uint32_t float16_to_uint32(float16 a, float_status *status); @@ -298,9 +301,9 @@ float16 float16_default_nan(float_status *status); | Software IEC/IEEE single-precision conversion routines. *----------------------------------------------------------------------------*/ -int16_t float32_to_int16_scalbn(float32, int, int, float_status *status); -int32_t float32_to_int32_scalbn(float32, int, int, float_status *status); -int64_t float32_to_int64_scalbn(float32, int, int, float_status *status); +int16_t float32_to_int16_scalbn(float32, FloatRoundMode, int, float_status *); +int32_t float32_to_int32_scalbn(float32, FloatRoundMode, int, float_status *); +int64_t float32_to_int64_scalbn(float32, FloatRoundMode, int, float_status *); int16_t float32_to_int16(float32, float_status *status); int32_t float32_to_int32(float32, float_status *status); @@ -310,9 +313,9 @@ int16_t float32_to_int16_round_to_zero(float32, float_status *status); int32_t float32_to_int32_round_to_zero(float32, float_status *status); int64_t float32_to_int64_round_to_zero(float32, float_status *status); -uint16_t float32_to_uint16_scalbn(float32, int, int, float_status *status); -uint32_t float32_to_uint32_scalbn(float32, int, int, float_status *status); -uint64_t float32_to_uint64_scalbn(float32, int, int, float_status *status); +uint16_t float32_to_uint16_scalbn(float32, FloatRoundMode, int, float_status *); +uint32_t float32_to_uint32_scalbn(float32, FloatRoundMode, int, float_status *); +uint64_t float32_to_uint64_scalbn(float32, FloatRoundMode, int, float_status *); uint16_t float32_to_uint16(float32, float_status *status); uint32_t float32_to_uint32(float32, float_status *status); @@ -455,9 +458,9 @@ float32 float32_default_nan(float_status *status); | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ -int16_t float64_to_int16_scalbn(float64, int, int, float_status *status); -int32_t float64_to_int32_scalbn(float64, int, int, float_status *status); -int64_t float64_to_int64_scalbn(float64, int, int, float_status *status); +int16_t float64_to_int16_scalbn(float64, FloatRoundMode, int, float_status *); +int32_t float64_to_int32_scalbn(float64, FloatRoundMode, int, float_status *); +int64_t float64_to_int64_scalbn(float64, FloatRoundMode, int, float_status *); int16_t float64_to_int16(float64, float_status *status); int32_t float64_to_int32(float64, float_status *status); @@ -467,9 +470,9 @@ int16_t float64_to_int16_round_to_zero(float64, float_status *status); int32_t float64_to_int32_round_to_zero(float64, float_status *status); int64_t float64_to_int64_round_to_zero(float64, float_status *status); -uint16_t float64_to_uint16_scalbn(float64, int, int, float_status *status); -uint32_t float64_to_uint32_scalbn(float64, int, int, float_status *status); -uint64_t float64_to_uint64_scalbn(float64, int, int, float_status *status); +uint16_t float64_to_uint16_scalbn(float64, FloatRoundMode, int, float_status *); +uint32_t float64_to_uint32_scalbn(float64, FloatRoundMode, int, float_status *); +uint64_t float64_to_uint64_scalbn(float64, FloatRoundMode, int, float_status *); uint16_t float64_to_uint16(float64, float_status *status); uint32_t float64_to_uint32(float64, float_status *status); diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index 42625747d1..0920694764 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -697,9 +697,9 @@ static bool round_to_inf(float_status *fpst, bool sign_bit) return sign_bit; case float_round_to_zero: /* Round to Zero */ return false; + default: + g_assert_not_reached(); } - - g_assert_not_reached(); } uint32_t HELPER(recpe_f16)(uint32_t input, void *fpstp) diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index 4137542ec0..36e6c704d1 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -149,7 +149,7 @@ void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val) void HELPER(fitrunc)(CPUM68KState *env, FPReg *res, FPReg *val) { - int rounding_mode = get_float_rounding_mode(&env->fp_status); + FloatRoundMode rounding_mode = get_float_rounding_mode(&env->fp_status); set_float_rounding_mode(float_round_to_zero, &env->fp_status); res->d = floatx80_round_to_int(val->d, &env->fp_status); set_float_rounding_mode(rounding_mode, &env->fp_status); @@ -300,7 +300,7 @@ void HELPER(fdmul)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) void HELPER(fsglmul)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) { - int rounding_mode = get_float_rounding_mode(&env->fp_status); + FloatRoundMode rounding_mode = get_float_rounding_mode(&env->fp_status); floatx80 a, b; PREC_BEGIN(32); @@ -333,7 +333,7 @@ void HELPER(fddiv)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) void HELPER(fsgldiv)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) { - int rounding_mode = get_float_rounding_mode(&env->fp_status); + FloatRoundMode rounding_mode = get_float_rounding_mode(&env->fp_status); floatx80 a, b; PREC_BEGIN(32); From 71bfd65c5fcd72f8af2735905415c7ce4220f6dc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 May 2020 10:22:05 -0700 Subject: [PATCH 0600/2595] softfloat: Name compare relation enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Give the previously unnamed enum a typedef name. Use it in the prototypes of compare functions. Use it to hold the results of the compare functions. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- fpu/softfloat.c | 40 ++++++++++++++++++--------------- include/fpu/softfloat.h | 25 +++++++++++---------- target/arm/vfp_helper.c | 2 +- target/hppa/op_helper.c | 7 +++--- target/i386/fpu_helper.c | 8 +++---- target/i386/ops_sse.h | 8 +++---- target/openrisc/fpu_helper.c | 4 ++-- target/ppc/int_helper.c | 13 ++++++----- target/s390x/fpu_helper.c | 22 +++++++++--------- target/sparc/fop_helper.c | 4 ++-- target/unicore32/ucf64_helper.c | 6 ++--- target/xtensa/fpu_helper.c | 6 ++--- 12 files changed, 75 insertions(+), 70 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 93d8a03de6..60b9ae5f05 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2848,8 +2848,8 @@ MINMAX(64, maxnummag, false, true, true) #undef MINMAX /* Floating point compare */ -static int compare_floats(FloatParts a, FloatParts b, bool is_quiet, - float_status *s) +static FloatRelation compare_floats(FloatParts a, FloatParts b, bool is_quiet, + float_status *s) { if (is_nan(a.cls) || is_nan(b.cls)) { if (!is_quiet || @@ -2920,17 +2920,17 @@ COMPARE(soft_f64_compare, QEMU_SOFTFLOAT_ATTR, 64) #undef COMPARE -int float16_compare(float16 a, float16 b, float_status *s) +FloatRelation float16_compare(float16 a, float16 b, float_status *s) { return soft_f16_compare(a, b, false, s); } -int float16_compare_quiet(float16 a, float16 b, float_status *s) +FloatRelation float16_compare_quiet(float16 a, float16 b, float_status *s) { return soft_f16_compare(a, b, true, s); } -static int QEMU_FLATTEN +static FloatRelation QEMU_FLATTEN f32_compare(float32 xa, float32 xb, bool is_quiet, float_status *s) { union_float32 ua, ub; @@ -2959,17 +2959,17 @@ f32_compare(float32 xa, float32 xb, bool is_quiet, float_status *s) return soft_f32_compare(ua.s, ub.s, is_quiet, s); } -int float32_compare(float32 a, float32 b, float_status *s) +FloatRelation float32_compare(float32 a, float32 b, float_status *s) { return f32_compare(a, b, false, s); } -int float32_compare_quiet(float32 a, float32 b, float_status *s) +FloatRelation float32_compare_quiet(float32 a, float32 b, float_status *s) { return f32_compare(a, b, true, s); } -static int QEMU_FLATTEN +static FloatRelation QEMU_FLATTEN f64_compare(float64 xa, float64 xb, bool is_quiet, float_status *s) { union_float64 ua, ub; @@ -2998,12 +2998,12 @@ f64_compare(float64 xa, float64 xb, bool is_quiet, float_status *s) return soft_f64_compare(ua.s, ub.s, is_quiet, s); } -int float64_compare(float64 a, float64 b, float_status *s) +FloatRelation float64_compare(float64 a, float64 b, float_status *s) { return f64_compare(a, b, false, s); } -int float64_compare_quiet(float64 a, float64 b, float_status *s) +FloatRelation float64_compare_quiet(float64 a, float64 b, float_status *s) { return f64_compare(a, b, true, s); } @@ -7892,8 +7892,9 @@ int float128_unordered_quiet(float128 a, float128 b, float_status *status) return 0; } -static inline int floatx80_compare_internal(floatx80 a, floatx80 b, - int is_quiet, float_status *status) +static inline FloatRelation +floatx80_compare_internal(floatx80 a, floatx80 b, bool is_quiet, + float_status *status) { bool aSign, bSign; @@ -7939,18 +7940,20 @@ static inline int floatx80_compare_internal(floatx80 a, floatx80 b, } } -int floatx80_compare(floatx80 a, floatx80 b, float_status *status) +FloatRelation floatx80_compare(floatx80 a, floatx80 b, float_status *status) { return floatx80_compare_internal(a, b, 0, status); } -int floatx80_compare_quiet(floatx80 a, floatx80 b, float_status *status) +FloatRelation floatx80_compare_quiet(floatx80 a, floatx80 b, + float_status *status) { return floatx80_compare_internal(a, b, 1, status); } -static inline int float128_compare_internal(float128 a, float128 b, - int is_quiet, float_status *status) +static inline FloatRelation +float128_compare_internal(float128 a, float128 b, bool is_quiet, + float_status *status) { bool aSign, bSign; @@ -7983,12 +7986,13 @@ static inline int float128_compare_internal(float128 a, float128 b, } } -int float128_compare(float128 a, float128 b, float_status *status) +FloatRelation float128_compare(float128 a, float128 b, float_status *status) { return float128_compare_internal(a, b, 0, status); } -int float128_compare_quiet(float128 a, float128 b, float_status *status) +FloatRelation float128_compare_quiet(float128 a, float128 b, + float_status *status) { return float128_compare_internal(a, b, 1, status); } diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index ca75f764aa..7f84235122 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -85,12 +85,13 @@ this code that are retained. /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point ordering relations *----------------------------------------------------------------------------*/ -enum { + +typedef enum { float_relation_less = -1, float_relation_equal = 0, float_relation_greater = 1, float_relation_unordered = 2 -}; +} FloatRelation; #include "fpu/softfloat-types.h" #include "fpu/softfloat-helpers.h" @@ -231,8 +232,8 @@ float16 float16_maxnum(float16, float16, float_status *status); float16 float16_minnummag(float16, float16, float_status *status); float16 float16_maxnummag(float16, float16, float_status *status); float16 float16_sqrt(float16, float_status *status); -int float16_compare(float16, float16, float_status *status); -int float16_compare_quiet(float16, float16, float_status *status); +FloatRelation float16_compare(float16, float16, float_status *status); +FloatRelation float16_compare_quiet(float16, float16, float_status *status); int float16_is_quiet_nan(float16, float_status *status); int float16_is_signaling_nan(float16, float_status *status); @@ -350,8 +351,8 @@ int float32_eq_quiet(float32, float32, float_status *status); int float32_le_quiet(float32, float32, float_status *status); int float32_lt_quiet(float32, float32, float_status *status); int float32_unordered_quiet(float32, float32, float_status *status); -int float32_compare(float32, float32, float_status *status); -int float32_compare_quiet(float32, float32, float_status *status); +FloatRelation float32_compare(float32, float32, float_status *status); +FloatRelation float32_compare_quiet(float32, float32, float_status *status); float32 float32_min(float32, float32, float_status *status); float32 float32_max(float32, float32, float_status *status); float32 float32_minnum(float32, float32, float_status *status); @@ -506,8 +507,8 @@ int float64_eq_quiet(float64, float64, float_status *status); int float64_le_quiet(float64, float64, float_status *status); int float64_lt_quiet(float64, float64, float_status *status); int float64_unordered_quiet(float64, float64, float_status *status); -int float64_compare(float64, float64, float_status *status); -int float64_compare_quiet(float64, float64, float_status *status); +FloatRelation float64_compare(float64, float64, float_status *status); +FloatRelation float64_compare_quiet(float64, float64, float_status *status); float64 float64_min(float64, float64, float_status *status); float64 float64_max(float64, float64, float_status *status); float64 float64_minnum(float64, float64, float_status *status); @@ -630,8 +631,8 @@ int floatx80_eq_quiet(floatx80, floatx80, float_status *status); int floatx80_le_quiet(floatx80, floatx80, float_status *status); int floatx80_lt_quiet(floatx80, floatx80, float_status *status); int floatx80_unordered_quiet(floatx80, floatx80, float_status *status); -int floatx80_compare(floatx80, floatx80, float_status *status); -int floatx80_compare_quiet(floatx80, floatx80, float_status *status); +FloatRelation floatx80_compare(floatx80, floatx80, float_status *status); +FloatRelation floatx80_compare_quiet(floatx80, floatx80, float_status *status); int floatx80_is_quiet_nan(floatx80, float_status *status); int floatx80_is_signaling_nan(floatx80, float_status *status); floatx80 floatx80_silence_nan(floatx80, float_status *status); @@ -842,8 +843,8 @@ int float128_eq_quiet(float128, float128, float_status *status); int float128_le_quiet(float128, float128, float_status *status); int float128_lt_quiet(float128, float128, float_status *status); int float128_unordered_quiet(float128, float128, float_status *status); -int float128_compare(float128, float128, float_status *status); -int float128_compare_quiet(float128, float128, float_status *status); +FloatRelation float128_compare(float128, float128, float_status *status); +FloatRelation float128_compare_quiet(float128, float128, float_status *status); int float128_is_quiet_nan(float128, float_status *status); int float128_is_signaling_nan(float128, float_status *status); float128 float128_silence_nan(float128, float_status *status); diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index 0920694764..60dcd4bf14 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -281,7 +281,7 @@ float64 VFP_HELPER(sqrt, d)(float64 a, CPUARMState *env) return float64_sqrt(a, &env->vfp.fp_status); } -static void softfloat_to_vfp_compare(CPUARMState *env, int cmp) +static void softfloat_to_vfp_compare(CPUARMState *env, FloatRelation cmp) { uint32_t flags; switch (cmp) { diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index 7823706e9c..5685e303ab 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -523,7 +523,8 @@ uint64_t HELPER(fcnv_t_d_udw)(CPUHPPAState *env, float64 arg) return ret; } -static void update_fr0_cmp(CPUHPPAState *env, uint32_t y, uint32_t c, int r) +static void update_fr0_cmp(CPUHPPAState *env, uint32_t y, + uint32_t c, FloatRelation r) { uint32_t shadow = env->fr0_shadow; @@ -565,7 +566,7 @@ static void update_fr0_cmp(CPUHPPAState *env, uint32_t y, uint32_t c, int r) void HELPER(fcmp_s)(CPUHPPAState *env, float32 a, float32 b, uint32_t y, uint32_t c) { - int r; + FloatRelation r; if (c & 1) { r = float32_compare(a, b, &env->fp_status); } else { @@ -578,7 +579,7 @@ void HELPER(fcmp_s)(CPUHPPAState *env, float32 a, float32 b, void HELPER(fcmp_d)(CPUHPPAState *env, float64 a, float64 b, uint32_t y, uint32_t c) { - int r; + FloatRelation r; if (c & 1) { r = float64_compare(a, b, &env->fp_status); } else { diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 792a128a6d..b34fa784eb 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -420,7 +420,7 @@ static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500}; void helper_fcom_ST0_FT0(CPUX86State *env) { - int ret; + FloatRelation ret; ret = floatx80_compare(ST0, FT0, &env->fp_status); env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1]; @@ -428,7 +428,7 @@ void helper_fcom_ST0_FT0(CPUX86State *env) void helper_fucom_ST0_FT0(CPUX86State *env) { - int ret; + FloatRelation ret; ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status); env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1]; @@ -439,7 +439,7 @@ static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; void helper_fcomi_ST0_FT0(CPUX86State *env) { int eflags; - int ret; + FloatRelation ret; ret = floatx80_compare(ST0, FT0, &env->fp_status); eflags = cpu_cc_compute_all(env, CC_OP); @@ -450,7 +450,7 @@ void helper_fcomi_ST0_FT0(CPUX86State *env) void helper_fucomi_ST0_FT0(CPUX86State *env) { int eflags; - int ret; + FloatRelation ret; ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status); eflags = cpu_cc_compute_all(env, CC_OP); diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h index ec1ec745d0..4658768de2 100644 --- a/target/i386/ops_sse.h +++ b/target/i386/ops_sse.h @@ -1031,7 +1031,7 @@ static const int comis_eflags[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; void helper_ucomiss(CPUX86State *env, Reg *d, Reg *s) { - int ret; + FloatRelation ret; float32 s0, s1; s0 = d->ZMM_S(0); @@ -1042,7 +1042,7 @@ void helper_ucomiss(CPUX86State *env, Reg *d, Reg *s) void helper_comiss(CPUX86State *env, Reg *d, Reg *s) { - int ret; + FloatRelation ret; float32 s0, s1; s0 = d->ZMM_S(0); @@ -1053,7 +1053,7 @@ void helper_comiss(CPUX86State *env, Reg *d, Reg *s) void helper_ucomisd(CPUX86State *env, Reg *d, Reg *s) { - int ret; + FloatRelation ret; float64 d0, d1; d0 = d->ZMM_D(0); @@ -1064,7 +1064,7 @@ void helper_ucomisd(CPUX86State *env, Reg *d, Reg *s) void helper_comisd(CPUX86State *env, Reg *d, Reg *s) { - int ret; + FloatRelation ret; float64 d0, d1; d0 = d->ZMM_D(0); diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index 6f75ea0505..f9e34fa2cc 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -155,13 +155,13 @@ FLOAT_CMP(un, unordered_quiet) target_ulong helper_float_ ## name ## _d(CPUOpenRISCState *env, \ uint64_t fdt0, uint64_t fdt1) \ { \ - int r = float64_compare_quiet(fdt0, fdt1, &env->fp_status); \ + FloatRelation r = float64_compare_quiet(fdt0, fdt1, &env->fp_status); \ return expr; \ } \ target_ulong helper_float_ ## name ## _s(CPUOpenRISCState *env, \ uint32_t fdt0, uint32_t fdt1) \ { \ - int r = float32_compare_quiet(fdt0, fdt1, &env->fp_status); \ + FloatRelation r = float32_compare_quiet(fdt0, fdt1, &env->fp_status); \ return expr; \ } diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 6d238b989d..be53cd6f68 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -770,8 +770,9 @@ VCMPNE(w, u32, uint32_t, 0) \ for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \ uint32_t result; \ - int rel = float32_compare_quiet(a->f32[i], b->f32[i], \ - &env->vec_status); \ + FloatRelation rel = \ + float32_compare_quiet(a->f32[i], b->f32[i], \ + &env->vec_status); \ if (rel == float_relation_unordered) { \ result = 0; \ } else if (rel compare order) { \ @@ -803,15 +804,15 @@ static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r, int all_in = 0; for (i = 0; i < ARRAY_SIZE(r->f32); i++) { - int le_rel = float32_compare_quiet(a->f32[i], b->f32[i], - &env->vec_status); + FloatRelation le_rel = float32_compare_quiet(a->f32[i], b->f32[i], + &env->vec_status); if (le_rel == float_relation_unordered) { r->u32[i] = 0xc0000000; all_in = 1; } else { float32 bneg = float32_chs(b->f32[i]); - int ge_rel = float32_compare_quiet(a->f32[i], bneg, - &env->vec_status); + FloatRelation ge_rel = float32_compare_quiet(a->f32[i], bneg, + &env->vec_status); int le = le_rel != float_relation_greater; int ge = ge_rel != float_relation_less; diff --git a/target/s390x/fpu_helper.c b/target/s390x/fpu_helper.c index 8bb9f54fd0..f155bc048c 100644 --- a/target/s390x/fpu_helper.c +++ b/target/s390x/fpu_helper.c @@ -112,7 +112,7 @@ static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr) } } -int float_comp_to_cc(CPUS390XState *env, int float_compare) +int float_comp_to_cc(CPUS390XState *env, FloatRelation float_compare) { switch (float_compare) { case float_relation_equal: @@ -368,7 +368,7 @@ uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al, /* 32-bit FP compare */ uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - int cmp = float32_compare_quiet(f1, f2, &env->fpu_status); + FloatRelation cmp = float32_compare_quiet(f1, f2, &env->fpu_status); handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } @@ -376,7 +376,7 @@ uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) /* 64-bit FP compare */ uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - int cmp = float64_compare_quiet(f1, f2, &env->fpu_status); + FloatRelation cmp = float64_compare_quiet(f1, f2, &env->fpu_status); handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } @@ -385,9 +385,9 @@ uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t bh, uint64_t bl) { - int cmp = float128_compare_quiet(make_float128(ah, al), - make_float128(bh, bl), - &env->fpu_status); + FloatRelation cmp = float128_compare_quiet(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } @@ -675,7 +675,7 @@ uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, /* 32-bit FP compare and signal */ uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - int cmp = float32_compare(f1, f2, &env->fpu_status); + FloatRelation cmp = float32_compare(f1, f2, &env->fpu_status); handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } @@ -683,7 +683,7 @@ uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2) /* 64-bit FP compare and signal */ uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - int cmp = float64_compare(f1, f2, &env->fpu_status); + FloatRelation cmp = float64_compare(f1, f2, &env->fpu_status); handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } @@ -692,9 +692,9 @@ uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t bh, uint64_t bl) { - int cmp = float128_compare(make_float128(ah, al), - make_float128(bh, bl), - &env->fpu_status); + FloatRelation cmp = float128_compare(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } diff --git a/target/sparc/fop_helper.c b/target/sparc/fop_helper.c index 9eb9b75718..e6dd3fc313 100644 --- a/target/sparc/fop_helper.c +++ b/target/sparc/fop_helper.c @@ -264,7 +264,7 @@ void helper_fsqrtq(CPUSPARCState *env) #define GEN_FCMP(name, size, reg1, reg2, FS, E) \ target_ulong glue(helper_, name) (CPUSPARCState *env) \ { \ - int ret; \ + FloatRelation ret; \ target_ulong fsr; \ if (E) { \ ret = glue(size, _compare)(reg1, reg2, &env->fp_status); \ @@ -295,7 +295,7 @@ void helper_fsqrtq(CPUSPARCState *env) #define GEN_FCMP_T(name, size, FS, E) \ target_ulong glue(helper_, name)(CPUSPARCState *env, size src1, size src2)\ { \ - int ret; \ + FloatRelation ret; \ target_ulong fsr; \ if (E) { \ ret = glue(size, _compare)(src1, src2, &env->fp_status); \ diff --git a/target/unicore32/ucf64_helper.c b/target/unicore32/ucf64_helper.c index e078e84437..12a91900f6 100644 --- a/target/unicore32/ucf64_helper.c +++ b/target/unicore32/ucf64_helper.c @@ -174,8 +174,7 @@ float64 HELPER(ucf64_absd)(float64 a) void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, CPUUniCore32State *env) { - int flag; - flag = float32_compare_quiet(a, b, &env->ucf64.fp_status); + FloatRelation flag = float32_compare_quiet(a, b, &env->ucf64.fp_status); env->CF = 0; switch (c & 0x7) { case 0: /* F */ @@ -223,8 +222,7 @@ void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c, CPUUniCore32State *env) { - int flag; - flag = float64_compare_quiet(a, b, &env->ucf64.fp_status); + FloatRelation flag = float64_compare_quiet(a, b, &env->ucf64.fp_status); env->CF = 0; switch (c & 0x7) { case 0: /* F */ diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c index f8bbb6cdd8..87487293f9 100644 --- a/target/xtensa/fpu_helper.c +++ b/target/xtensa/fpu_helper.c @@ -139,7 +139,7 @@ void HELPER(oeq_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) void HELPER(ueq_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) { - int v = float32_compare_quiet(a, b, &env->fp_status); + FloatRelation v = float32_compare_quiet(a, b, &env->fp_status); set_br(env, v == float_relation_equal || v == float_relation_unordered, br); } @@ -150,7 +150,7 @@ void HELPER(olt_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) void HELPER(ult_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) { - int v = float32_compare_quiet(a, b, &env->fp_status); + FloatRelation v = float32_compare_quiet(a, b, &env->fp_status); set_br(env, v == float_relation_less || v == float_relation_unordered, br); } @@ -161,6 +161,6 @@ void HELPER(ole_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) void HELPER(ule_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) { - int v = float32_compare_quiet(a, b, &env->fp_status); + FloatRelation v = float32_compare_quiet(a, b, &env->fp_status); set_br(env, v != float_relation_greater, br); } From 5da2d2d8e53d80e92a61720ea995c86b33cbf25d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 May 2020 10:33:18 -0700 Subject: [PATCH 0601/2595] softfloat: Inline float32 compare specializations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the float32 compare specializations with inline functions that call the standard float32_compare{,_quiet} functions. Use bool as the return type. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 216 ---------------------------------------- include/fpu/softfloat.h | 49 +++++++-- 2 files changed, 41 insertions(+), 224 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 60b9ae5f05..f6bfc40c97 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -4733,222 +4733,6 @@ float32 float32_log2(float32 a, float_status *status) return normalizeRoundAndPackFloat32(zSign, 0x85, zSig, status); } -/*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float32_eq(float32 a, float32 b, float_status *status) -{ - uint32_t av, bv; - a = float32_squash_input_denormal(a, status); - b = float32_squash_input_denormal(b, status); - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - av = float32_val(a); - bv = float32_val(b); - return ( av == bv ) || ( (uint32_t) ( ( av | bv )<<1 ) == 0 ); -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point value `a' is less than -| or equal to the corresponding value `b', and 0 otherwise. The invalid -| exception is raised if either operand is a NaN. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float32_le(float32 a, float32 b, float_status *status) -{ - bool aSign, bSign; - uint32_t av, bv; - a = float32_squash_input_denormal(a, status); - b = float32_squash_input_denormal(b, status); - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - aSign = extractFloat32Sign( a ); - bSign = extractFloat32Sign( b ); - av = float32_val(a); - bv = float32_val(b); - if ( aSign != bSign ) return aSign || ( (uint32_t) ( ( av | bv )<<1 ) == 0 ); - return ( av == bv ) || ( aSign ^ ( av < bv ) ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. The comparison is performed according -| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float32_lt(float32 a, float32 b, float_status *status) -{ - bool aSign, bSign; - uint32_t av, bv; - a = float32_squash_input_denormal(a, status); - b = float32_squash_input_denormal(b, status); - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - aSign = extractFloat32Sign( a ); - bSign = extractFloat32Sign( b ); - av = float32_val(a); - bv = float32_val(b); - if ( aSign != bSign ) return aSign && ( (uint32_t) ( ( av | bv )<<1 ) != 0 ); - return ( av != bv ) && ( aSign ^ ( av < bv ) ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point values `a' and `b' cannot -| be compared, and 0 otherwise. The invalid exception is raised if either -| operand is a NaN. The comparison is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float32_unordered(float32 a, float32 b, float_status *status) -{ - a = float32_squash_input_denormal(a, status); - b = float32_squash_input_denormal(b, status); - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - float_raise(float_flag_invalid, status); - return 1; - } - return 0; -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an -| exception. The comparison is performed according to the IEC/IEEE Standard -| for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float32_eq_quiet(float32 a, float32 b, float_status *status) -{ - a = float32_squash_input_denormal(a, status); - b = float32_squash_input_denormal(b, status); - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - if (float32_is_signaling_nan(a, status) - || float32_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - return ( float32_val(a) == float32_val(b) ) || - ( (uint32_t) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point value `a' is less than or -| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not -| cause an exception. Otherwise, the comparison is performed according to the -| IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float32_le_quiet(float32 a, float32 b, float_status *status) -{ - bool aSign, bSign; - uint32_t av, bv; - a = float32_squash_input_denormal(a, status); - b = float32_squash_input_denormal(b, status); - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - if (float32_is_signaling_nan(a, status) - || float32_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - aSign = extractFloat32Sign( a ); - bSign = extractFloat32Sign( b ); - av = float32_val(a); - bv = float32_val(b); - if ( aSign != bSign ) return aSign || ( (uint32_t) ( ( av | bv )<<1 ) == 0 ); - return ( av == bv ) || ( aSign ^ ( av < bv ) ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an -| exception. Otherwise, the comparison is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float32_lt_quiet(float32 a, float32 b, float_status *status) -{ - bool aSign, bSign; - uint32_t av, bv; - a = float32_squash_input_denormal(a, status); - b = float32_squash_input_denormal(b, status); - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - if (float32_is_signaling_nan(a, status) - || float32_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - aSign = extractFloat32Sign( a ); - bSign = extractFloat32Sign( b ); - av = float32_val(a); - bv = float32_val(b); - if ( aSign != bSign ) return aSign && ( (uint32_t) ( ( av | bv )<<1 ) != 0 ); - return ( av != bv ) && ( aSign ^ ( av < bv ) ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point values `a' and `b' cannot -| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The -| comparison is performed according to the IEC/IEEE Standard for Binary -| Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float32_unordered_quiet(float32 a, float32 b, float_status *status) -{ - a = float32_squash_input_denormal(a, status); - b = float32_squash_input_denormal(b, status); - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - if (float32_is_signaling_nan(a, status) - || float32_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 1; - } - return 0; -} - /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the extended double-precision floating-point format. The conversion diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 7f84235122..4d1af6ab45 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -343,14 +343,6 @@ float32 float32_muladd(float32, float32, float32, int, float_status *status); float32 float32_sqrt(float32, float_status *status); float32 float32_exp2(float32, float_status *status); float32 float32_log2(float32, float_status *status); -int float32_eq(float32, float32, float_status *status); -int float32_le(float32, float32, float_status *status); -int float32_lt(float32, float32, float_status *status); -int float32_unordered(float32, float32, float_status *status); -int float32_eq_quiet(float32, float32, float_status *status); -int float32_le_quiet(float32, float32, float_status *status); -int float32_lt_quiet(float32, float32, float_status *status); -int float32_unordered_quiet(float32, float32, float_status *status); FloatRelation float32_compare(float32, float32, float_status *status); FloatRelation float32_compare_quiet(float32, float32, float_status *status); float32 float32_min(float32, float32, float_status *status); @@ -425,6 +417,47 @@ static inline float32 float32_set_sign(float32 a, int sign) return make_float32((float32_val(a) & 0x7fffffff) | (sign << 31)); } +static inline bool float32_eq(float32 a, float32 b, float_status *s) +{ + return float32_compare(a, b, s) == float_relation_equal; +} + +static inline bool float32_le(float32 a, float32 b, float_status *s) +{ + return float32_compare(a, b, s) <= float_relation_equal; +} + +static inline bool float32_lt(float32 a, float32 b, float_status *s) +{ + return float32_compare(a, b, s) < float_relation_equal; +} + +static inline bool float32_unordered(float32 a, float32 b, float_status *s) +{ + return float32_compare(a, b, s) == float_relation_unordered; +} + +static inline bool float32_eq_quiet(float32 a, float32 b, float_status *s) +{ + return float32_compare_quiet(a, b, s) == float_relation_equal; +} + +static inline bool float32_le_quiet(float32 a, float32 b, float_status *s) +{ + return float32_compare_quiet(a, b, s) <= float_relation_equal; +} + +static inline bool float32_lt_quiet(float32 a, float32 b, float_status *s) +{ + return float32_compare_quiet(a, b, s) < float_relation_equal; +} + +static inline bool float32_unordered_quiet(float32 a, float32 b, + float_status *s) +{ + return float32_compare_quiet(a, b, s) == float_relation_unordered; +} + #define float32_zero make_float32(0) #define float32_half make_float32(0x3f000000) #define float32_one make_float32(0x3f800000) From 0673ecdf6cb2b1445a85283db8cbacb251c46516 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 May 2020 10:40:23 -0700 Subject: [PATCH 0602/2595] softfloat: Inline float64 compare specializations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the float64 compare specializations with inline functions that call the standard float64_compare{,_quiet} functions. Use bool as the return type. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 220 ---------------------------------- include/fpu/softfloat.h | 49 ++++++-- target/s390x/vec_fpu_helper.c | 2 +- 3 files changed, 42 insertions(+), 229 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index f6bfc40c97..5d7fc2c17a 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -4941,226 +4941,6 @@ float64 float64_log2(float64 a, float_status *status) return normalizeRoundAndPackFloat64(zSign, 0x408, zSig, status); } -/*---------------------------------------------------------------------------- -| Returns 1 if the double-precision floating-point value `a' is equal to the -| corresponding value `b', and 0 otherwise. The invalid exception is raised -| if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float64_eq(float64 a, float64 b, float_status *status) -{ - uint64_t av, bv; - a = float64_squash_input_denormal(a, status); - b = float64_squash_input_denormal(b, status); - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - av = float64_val(a); - bv = float64_val(b); - return ( av == bv ) || ( (uint64_t) ( ( av | bv )<<1 ) == 0 ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the double-precision floating-point value `a' is less than or -| equal to the corresponding value `b', and 0 otherwise. The invalid -| exception is raised if either operand is a NaN. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float64_le(float64 a, float64 b, float_status *status) -{ - bool aSign, bSign; - uint64_t av, bv; - a = float64_squash_input_denormal(a, status); - b = float64_squash_input_denormal(b, status); - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - aSign = extractFloat64Sign( a ); - bSign = extractFloat64Sign( b ); - av = float64_val(a); - bv = float64_val(b); - if ( aSign != bSign ) return aSign || ( (uint64_t) ( ( av | bv )<<1 ) == 0 ); - return ( av == bv ) || ( aSign ^ ( av < bv ) ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the double-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. The comparison is performed according -| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float64_lt(float64 a, float64 b, float_status *status) -{ - bool aSign, bSign; - uint64_t av, bv; - - a = float64_squash_input_denormal(a, status); - b = float64_squash_input_denormal(b, status); - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - aSign = extractFloat64Sign( a ); - bSign = extractFloat64Sign( b ); - av = float64_val(a); - bv = float64_val(b); - if ( aSign != bSign ) return aSign && ( (uint64_t) ( ( av | bv )<<1 ) != 0 ); - return ( av != bv ) && ( aSign ^ ( av < bv ) ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the double-precision floating-point values `a' and `b' cannot -| be compared, and 0 otherwise. The invalid exception is raised if either -| operand is a NaN. The comparison is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float64_unordered(float64 a, float64 b, float_status *status) -{ - a = float64_squash_input_denormal(a, status); - b = float64_squash_input_denormal(b, status); - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - float_raise(float_flag_invalid, status); - return 1; - } - return 0; -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the double-precision floating-point value `a' is equal to the -| corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an -| exception.The comparison is performed according to the IEC/IEEE Standard -| for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float64_eq_quiet(float64 a, float64 b, float_status *status) -{ - uint64_t av, bv; - a = float64_squash_input_denormal(a, status); - b = float64_squash_input_denormal(b, status); - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - if (float64_is_signaling_nan(a, status) - || float64_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - av = float64_val(a); - bv = float64_val(b); - return ( av == bv ) || ( (uint64_t) ( ( av | bv )<<1 ) == 0 ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the double-precision floating-point value `a' is less than or -| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not -| cause an exception. Otherwise, the comparison is performed according to the -| IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float64_le_quiet(float64 a, float64 b, float_status *status) -{ - bool aSign, bSign; - uint64_t av, bv; - a = float64_squash_input_denormal(a, status); - b = float64_squash_input_denormal(b, status); - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - if (float64_is_signaling_nan(a, status) - || float64_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - aSign = extractFloat64Sign( a ); - bSign = extractFloat64Sign( b ); - av = float64_val(a); - bv = float64_val(b); - if ( aSign != bSign ) return aSign || ( (uint64_t) ( ( av | bv )<<1 ) == 0 ); - return ( av == bv ) || ( aSign ^ ( av < bv ) ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the double-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an -| exception. Otherwise, the comparison is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float64_lt_quiet(float64 a, float64 b, float_status *status) -{ - bool aSign, bSign; - uint64_t av, bv; - a = float64_squash_input_denormal(a, status); - b = float64_squash_input_denormal(b, status); - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - if (float64_is_signaling_nan(a, status) - || float64_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - aSign = extractFloat64Sign( a ); - bSign = extractFloat64Sign( b ); - av = float64_val(a); - bv = float64_val(b); - if ( aSign != bSign ) return aSign && ( (uint64_t) ( ( av | bv )<<1 ) != 0 ); - return ( av != bv ) && ( aSign ^ ( av < bv ) ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the double-precision floating-point values `a' and `b' cannot -| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The -| comparison is performed according to the IEC/IEEE Standard for Binary -| Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float64_unordered_quiet(float64 a, float64 b, float_status *status) -{ - a = float64_squash_input_denormal(a, status); - b = float64_squash_input_denormal(b, status); - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - if (float64_is_signaling_nan(a, status) - || float64_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 1; - } - return 0; -} - /*---------------------------------------------------------------------------- | Returns the result of converting the extended double-precision floating- | point value `a' to the 32-bit two's complement integer format. The diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 4d1af6ab45..281f0fd971 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -532,14 +532,6 @@ float64 float64_rem(float64, float64, float_status *status); float64 float64_muladd(float64, float64, float64, int, float_status *status); float64 float64_sqrt(float64, float_status *status); float64 float64_log2(float64, float_status *status); -int float64_eq(float64, float64, float_status *status); -int float64_le(float64, float64, float_status *status); -int float64_lt(float64, float64, float_status *status); -int float64_unordered(float64, float64, float_status *status); -int float64_eq_quiet(float64, float64, float_status *status); -int float64_le_quiet(float64, float64, float_status *status); -int float64_lt_quiet(float64, float64, float_status *status); -int float64_unordered_quiet(float64, float64, float_status *status); FloatRelation float64_compare(float64, float64, float_status *status); FloatRelation float64_compare_quiet(float64, float64, float_status *status); float64 float64_min(float64, float64, float_status *status); @@ -615,6 +607,47 @@ static inline float64 float64_set_sign(float64 a, int sign) | ((int64_t)sign << 63)); } +static inline bool float64_eq(float64 a, float64 b, float_status *s) +{ + return float64_compare(a, b, s) == float_relation_equal; +} + +static inline bool float64_le(float64 a, float64 b, float_status *s) +{ + return float64_compare(a, b, s) <= float_relation_equal; +} + +static inline bool float64_lt(float64 a, float64 b, float_status *s) +{ + return float64_compare(a, b, s) < float_relation_equal; +} + +static inline bool float64_unordered(float64 a, float64 b, float_status *s) +{ + return float64_compare(a, b, s) == float_relation_unordered; +} + +static inline bool float64_eq_quiet(float64 a, float64 b, float_status *s) +{ + return float64_compare_quiet(a, b, s) == float_relation_equal; +} + +static inline bool float64_le_quiet(float64 a, float64 b, float_status *s) +{ + return float64_compare_quiet(a, b, s) <= float_relation_equal; +} + +static inline bool float64_lt_quiet(float64 a, float64 b, float_status *s) +{ + return float64_compare_quiet(a, b, s) < float_relation_equal; +} + +static inline bool float64_unordered_quiet(float64 a, float64 b, + float_status *s) +{ + return float64_compare_quiet(a, b, s) == float_relation_unordered; +} + #define float64_zero make_float64(0) #define float64_half make_float64(0x3fe0000000000000LL) #define float64_one make_float64(0x3ff0000000000000LL) diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c index a48bd704bc..c1564e819b 100644 --- a/target/s390x/vec_fpu_helper.c +++ b/target/s390x/vec_fpu_helper.c @@ -174,7 +174,7 @@ void HELPER(gvec_wfk64)(const void *v1, const void *v2, CPUS390XState *env, env->cc_op = wfc64(v1, v2, env, true, GETPC()); } -typedef int (*vfc64_fn)(float64 a, float64 b, float_status *status); +typedef bool (*vfc64_fn)(float64 a, float64 b, float_status *status); static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, CPUS390XState *env, bool s, vfc64_fn fn, uintptr_t retaddr) { From b7b1ac684fea49c6bfe1ad8b706aed7b09116d15 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 May 2020 10:50:32 -0700 Subject: [PATCH 0603/2595] softfloat: Inline float128 compare specializations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the float128 compare specializations with inline functions that call the standard float128_compare{,_quiet} functions. Use bool as the return type. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 238 ---------------------------------------- include/fpu/softfloat.h | 49 +++++++-- 2 files changed, 41 insertions(+), 246 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 5d7fc2c17a..4567dda112 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -7218,244 +7218,6 @@ float128 float128_sqrt(float128 a, float_status *status) } -/*---------------------------------------------------------------------------- -| Returns 1 if the quadruple-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float128_eq(float128 a, float128 b, float_status *status) -{ - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - return - ( a.low == b.low ) - && ( ( a.high == b.high ) - || ( ( a.low == 0 ) - && ( (uint64_t) ( ( a.high | b.high )<<1 ) == 0 ) ) - ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the quadruple-precision floating-point value `a' is less than -| or equal to the corresponding value `b', and 0 otherwise. The invalid -| exception is raised if either operand is a NaN. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float128_le(float128 a, float128 b, float_status *status) -{ - bool aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - || ( ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - == 0 ); - } - return - aSign ? le128( b.high, b.low, a.high, a.low ) - : le128( a.high, a.low, b.high, b.low ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the quadruple-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. The comparison is performed according -| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float128_lt(float128 a, float128 b, float_status *status) -{ - bool aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - && ( ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - != 0 ); - } - return - aSign ? lt128( b.high, b.low, a.high, a.low ) - : lt128( a.high, a.low, b.high, b.low ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot -| be compared, and 0 otherwise. The invalid exception is raised if either -| operand is a NaN. The comparison is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float128_unordered(float128 a, float128 b, float_status *status) -{ - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - float_raise(float_flag_invalid, status); - return 1; - } - return 0; -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the quadruple-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an -| exception. The comparison is performed according to the IEC/IEEE Standard -| for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float128_eq_quiet(float128 a, float128 b, float_status *status) -{ - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - if (float128_is_signaling_nan(a, status) - || float128_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - return - ( a.low == b.low ) - && ( ( a.high == b.high ) - || ( ( a.low == 0 ) - && ( (uint64_t) ( ( a.high | b.high )<<1 ) == 0 ) ) - ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the quadruple-precision floating-point value `a' is less than -| or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not -| cause an exception. Otherwise, the comparison is performed according to the -| IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float128_le_quiet(float128 a, float128 b, float_status *status) -{ - bool aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - if (float128_is_signaling_nan(a, status) - || float128_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - || ( ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - == 0 ); - } - return - aSign ? le128( b.high, b.low, a.high, a.low ) - : le128( a.high, a.low, b.high, b.low ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the quadruple-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an -| exception. Otherwise, the comparison is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float128_lt_quiet(float128 a, float128 b, float_status *status) -{ - bool aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - if (float128_is_signaling_nan(a, status) - || float128_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - && ( ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - != 0 ); - } - return - aSign ? lt128( b.high, b.low, a.high, a.low ) - : lt128( a.high, a.low, b.high, b.low ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot -| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The -| comparison is performed according to the IEC/IEEE Standard for Binary -| Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int float128_unordered_quiet(float128 a, float128 b, float_status *status) -{ - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - if (float128_is_signaling_nan(a, status) - || float128_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 1; - } - return 0; -} - static inline FloatRelation floatx80_compare_internal(floatx80 a, floatx80 b, bool is_quiet, float_status *status) diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 281f0fd971..cfb3cda46b 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -901,14 +901,6 @@ float128 float128_mul(float128, float128, float_status *status); float128 float128_div(float128, float128, float_status *status); float128 float128_rem(float128, float128, float_status *status); float128 float128_sqrt(float128, float_status *status); -int float128_eq(float128, float128, float_status *status); -int float128_le(float128, float128, float_status *status); -int float128_lt(float128, float128, float_status *status); -int float128_unordered(float128, float128, float_status *status); -int float128_eq_quiet(float128, float128, float_status *status); -int float128_le_quiet(float128, float128, float_status *status); -int float128_lt_quiet(float128, float128, float_status *status); -int float128_unordered_quiet(float128, float128, float_status *status); FloatRelation float128_compare(float128, float128, float_status *status); FloatRelation float128_compare_quiet(float128, float128, float_status *status); int float128_is_quiet_nan(float128, float_status *status); @@ -964,6 +956,47 @@ static inline int float128_is_any_nan(float128 a) ((a.low != 0) || ((a.high & 0xffffffffffffLL) != 0)); } +static inline bool float128_eq(float128 a, float128 b, float_status *s) +{ + return float128_compare(a, b, s) == float_relation_equal; +} + +static inline bool float128_le(float128 a, float128 b, float_status *s) +{ + return float128_compare(a, b, s) <= float_relation_equal; +} + +static inline bool float128_lt(float128 a, float128 b, float_status *s) +{ + return float128_compare(a, b, s) < float_relation_equal; +} + +static inline bool float128_unordered(float128 a, float128 b, float_status *s) +{ + return float128_compare(a, b, s) == float_relation_unordered; +} + +static inline bool float128_eq_quiet(float128 a, float128 b, float_status *s) +{ + return float128_compare_quiet(a, b, s) == float_relation_equal; +} + +static inline bool float128_le_quiet(float128 a, float128 b, float_status *s) +{ + return float128_compare_quiet(a, b, s) <= float_relation_equal; +} + +static inline bool float128_lt_quiet(float128 a, float128 b, float_status *s) +{ + return float128_compare_quiet(a, b, s) < float_relation_equal; +} + +static inline bool float128_unordered_quiet(float128 a, float128 b, + float_status *s) +{ + return float128_compare_quiet(a, b, s) == float_relation_unordered; +} + #define float128_zero make_float128(0, 0) /*---------------------------------------------------------------------------- From c6baf65000f826a713e8d9b5b35e617b0ca9ab5d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 May 2020 10:53:15 -0700 Subject: [PATCH 0604/2595] softfloat: Inline floatx80 compare specializations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the floatx80 compare specializations with inline functions that call the standard floatx80_compare{,_quiet} functions. Use bool as the return type. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 257 ---------------------------------------- include/fpu/softfloat.h | 49 ++++++-- 2 files changed, 41 insertions(+), 265 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 4567dda112..6c8f2d597a 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5849,263 +5849,6 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status) 0, zExp, zSig0, zSig1, status); } -/*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point value `a' is equal -| to the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int floatx80_eq(floatx80 a, floatx80 b, float_status *status) -{ - - if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) - || (extractFloatx80Exp(a) == 0x7FFF - && (uint64_t) (extractFloatx80Frac(a) << 1)) - || (extractFloatx80Exp(b) == 0x7FFF - && (uint64_t) (extractFloatx80Frac(b) << 1)) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - return - ( a.low == b.low ) - && ( ( a.high == b.high ) - || ( ( a.low == 0 ) - && ( (uint16_t) ( ( a.high | b.high )<<1 ) == 0 ) ) - ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point value `a' is -| less than or equal to the corresponding value `b', and 0 otherwise. The -| invalid exception is raised if either operand is a NaN. The comparison is -| performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. -*----------------------------------------------------------------------------*/ - -int floatx80_le(floatx80 a, floatx80 b, float_status *status) -{ - bool aSign, bSign; - - if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) - || (extractFloatx80Exp(a) == 0x7FFF - && (uint64_t) (extractFloatx80Frac(a) << 1)) - || (extractFloatx80Exp(b) == 0x7FFF - && (uint64_t) (extractFloatx80Frac(b) << 1)) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - aSign = extractFloatx80Sign( a ); - bSign = extractFloatx80Sign( b ); - if ( aSign != bSign ) { - return - aSign - || ( ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - == 0 ); - } - return - aSign ? le128( b.high, b.low, a.high, a.low ) - : le128( a.high, a.low, b.high, b.low ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point value `a' is -| less than the corresponding value `b', and 0 otherwise. The invalid -| exception is raised if either operand is a NaN. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int floatx80_lt(floatx80 a, floatx80 b, float_status *status) -{ - bool aSign, bSign; - - if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) - || (extractFloatx80Exp(a) == 0x7FFF - && (uint64_t) (extractFloatx80Frac(a) << 1)) - || (extractFloatx80Exp(b) == 0x7FFF - && (uint64_t) (extractFloatx80Frac(b) << 1)) - ) { - float_raise(float_flag_invalid, status); - return 0; - } - aSign = extractFloatx80Sign( a ); - bSign = extractFloatx80Sign( b ); - if ( aSign != bSign ) { - return - aSign - && ( ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - != 0 ); - } - return - aSign ? lt128( b.high, b.low, a.high, a.low ) - : lt128( a.high, a.low, b.high, b.low ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point values `a' and `b' -| cannot be compared, and 0 otherwise. The invalid exception is raised if -| either operand is a NaN. The comparison is performed according to the -| IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ -int floatx80_unordered(floatx80 a, floatx80 b, float_status *status) -{ - if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) - || (extractFloatx80Exp(a) == 0x7FFF - && (uint64_t) (extractFloatx80Frac(a) << 1)) - || (extractFloatx80Exp(b) == 0x7FFF - && (uint64_t) (extractFloatx80Frac(b) << 1)) - ) { - float_raise(float_flag_invalid, status); - return 1; - } - return 0; -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point value `a' is -| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not -| cause an exception. The comparison is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int floatx80_eq_quiet(floatx80 a, floatx80 b, float_status *status) -{ - - if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { - float_raise(float_flag_invalid, status); - return 0; - } - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) - ) { - if (floatx80_is_signaling_nan(a, status) - || floatx80_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - return - ( a.low == b.low ) - && ( ( a.high == b.high ) - || ( ( a.low == 0 ) - && ( (uint16_t) ( ( a.high | b.high )<<1 ) == 0 ) ) - ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point value `a' is less -| than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs -| do not cause an exception. Otherwise, the comparison is performed according -| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int floatx80_le_quiet(floatx80 a, floatx80 b, float_status *status) -{ - bool aSign, bSign; - - if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { - float_raise(float_flag_invalid, status); - return 0; - } - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) - ) { - if (floatx80_is_signaling_nan(a, status) - || floatx80_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - aSign = extractFloatx80Sign( a ); - bSign = extractFloatx80Sign( b ); - if ( aSign != bSign ) { - return - aSign - || ( ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - == 0 ); - } - return - aSign ? le128( b.high, b.low, a.high, a.low ) - : le128( a.high, a.low, b.high, b.low ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point value `a' is less -| than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause -| an exception. Otherwise, the comparison is performed according to the -| IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -int floatx80_lt_quiet(floatx80 a, floatx80 b, float_status *status) -{ - bool aSign, bSign; - - if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { - float_raise(float_flag_invalid, status); - return 0; - } - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) - ) { - if (floatx80_is_signaling_nan(a, status) - || floatx80_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 0; - } - aSign = extractFloatx80Sign( a ); - bSign = extractFloatx80Sign( b ); - if ( aSign != bSign ) { - return - aSign - && ( ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - != 0 ); - } - return - aSign ? lt128( b.high, b.low, a.high, a.low ) - : lt128( a.high, a.low, b.high, b.low ); - -} - -/*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point values `a' and `b' -| cannot be compared, and 0 otherwise. Quiet NaNs do not cause an exception. -| The comparison is performed according to the IEC/IEEE Standard for Binary -| Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ -int floatx80_unordered_quiet(floatx80 a, floatx80 b, float_status *status) -{ - if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { - float_raise(float_flag_invalid, status); - return 1; - } - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) - ) { - if (floatx80_is_signaling_nan(a, status) - || floatx80_is_signaling_nan(b, status)) { - float_raise(float_flag_invalid, status); - } - return 1; - } - return 0; -} - /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the 32-bit two's complement integer format. The conversion diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index cfb3cda46b..37217d9b9b 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -689,14 +689,6 @@ floatx80 floatx80_mul(floatx80, floatx80, float_status *status); floatx80 floatx80_div(floatx80, floatx80, float_status *status); floatx80 floatx80_rem(floatx80, floatx80, float_status *status); floatx80 floatx80_sqrt(floatx80, float_status *status); -int floatx80_eq(floatx80, floatx80, float_status *status); -int floatx80_le(floatx80, floatx80, float_status *status); -int floatx80_lt(floatx80, floatx80, float_status *status); -int floatx80_unordered(floatx80, floatx80, float_status *status); -int floatx80_eq_quiet(floatx80, floatx80, float_status *status); -int floatx80_le_quiet(floatx80, floatx80, float_status *status); -int floatx80_lt_quiet(floatx80, floatx80, float_status *status); -int floatx80_unordered_quiet(floatx80, floatx80, float_status *status); FloatRelation floatx80_compare(floatx80, floatx80, float_status *status); FloatRelation floatx80_compare_quiet(floatx80, floatx80, float_status *status); int floatx80_is_quiet_nan(floatx80, float_status *status); @@ -746,6 +738,47 @@ static inline int floatx80_is_any_nan(floatx80 a) return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1); } +static inline bool floatx80_eq(floatx80 a, floatx80 b, float_status *s) +{ + return floatx80_compare(a, b, s) == float_relation_equal; +} + +static inline bool floatx80_le(floatx80 a, floatx80 b, float_status *s) +{ + return floatx80_compare(a, b, s) <= float_relation_equal; +} + +static inline bool floatx80_lt(floatx80 a, floatx80 b, float_status *s) +{ + return floatx80_compare(a, b, s) < float_relation_equal; +} + +static inline bool floatx80_unordered(floatx80 a, floatx80 b, float_status *s) +{ + return floatx80_compare(a, b, s) == float_relation_unordered; +} + +static inline bool floatx80_eq_quiet(floatx80 a, floatx80 b, float_status *s) +{ + return floatx80_compare_quiet(a, b, s) == float_relation_equal; +} + +static inline bool floatx80_le_quiet(floatx80 a, floatx80 b, float_status *s) +{ + return floatx80_compare_quiet(a, b, s) <= float_relation_equal; +} + +static inline bool floatx80_lt_quiet(floatx80 a, floatx80 b, float_status *s) +{ + return floatx80_compare_quiet(a, b, s) < float_relation_equal; +} + +static inline bool floatx80_unordered_quiet(floatx80 a, floatx80 b, + float_status *s) +{ + return floatx80_compare_quiet(a, b, s) == float_relation_unordered; +} + /*---------------------------------------------------------------------------- | Return whether the given value is an invalid floatx80 encoding. | Invalid floatx80 encodings arise when the integer bit is not set, but From 150c7a91ce7862bcaf7422f6038dcf0ba4a7eee3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 May 2020 12:16:24 -0700 Subject: [PATCH 0605/2595] softfloat: Return bool from all classification predicates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This includes *_is_any_nan, *_is_neg, *_is_inf, etc. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- fpu/softfloat-specialize.inc.c | 16 ++++----- include/fpu/softfloat.h | 66 +++++++++++++++++----------------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/fpu/softfloat-specialize.inc.c b/fpu/softfloat-specialize.inc.c index 025ee4f991..44f5b661f8 100644 --- a/fpu/softfloat-specialize.inc.c +++ b/fpu/softfloat-specialize.inc.c @@ -245,7 +245,7 @@ typedef struct { | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float16_is_quiet_nan(float16 a_, float_status *status) +bool float16_is_quiet_nan(float16 a_, float_status *status) { #ifdef NO_SIGNALING_NANS return float16_is_any_nan(a_); @@ -264,7 +264,7 @@ int float16_is_quiet_nan(float16 a_, float_status *status) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float16_is_signaling_nan(float16 a_, float_status *status) +bool float16_is_signaling_nan(float16 a_, float_status *status) { #ifdef NO_SIGNALING_NANS return 0; @@ -283,7 +283,7 @@ int float16_is_signaling_nan(float16 a_, float_status *status) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float32_is_quiet_nan(float32 a_, float_status *status) +bool float32_is_quiet_nan(float32 a_, float_status *status) { #ifdef NO_SIGNALING_NANS return float32_is_any_nan(a_); @@ -302,7 +302,7 @@ int float32_is_quiet_nan(float32 a_, float_status *status) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float32_is_signaling_nan(float32 a_, float_status *status) +bool float32_is_signaling_nan(float32 a_, float_status *status) { #ifdef NO_SIGNALING_NANS return 0; @@ -637,7 +637,7 @@ static float32 propagateFloat32NaN(float32 a, float32 b, float_status *status) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float64_is_quiet_nan(float64 a_, float_status *status) +bool float64_is_quiet_nan(float64 a_, float_status *status) { #ifdef NO_SIGNALING_NANS return float64_is_any_nan(a_); @@ -657,7 +657,7 @@ int float64_is_quiet_nan(float64 a_, float_status *status) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float64_is_signaling_nan(float64 a_, float_status *status) +bool float64_is_signaling_nan(float64 a_, float_status *status) { #ifdef NO_SIGNALING_NANS return 0; @@ -939,7 +939,7 @@ floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float128_is_quiet_nan(float128 a, float_status *status) +bool float128_is_quiet_nan(float128 a, float_status *status) { #ifdef NO_SIGNALING_NANS return float128_is_any_nan(a); @@ -959,7 +959,7 @@ int float128_is_quiet_nan(float128 a, float_status *status) | signaling NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float128_is_signaling_nan(float128 a, float_status *status) +bool float128_is_signaling_nan(float128 a, float_status *status) { #ifdef NO_SIGNALING_NANS return 0; diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 37217d9b9b..16ca697a73 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -235,31 +235,31 @@ float16 float16_sqrt(float16, float_status *status); FloatRelation float16_compare(float16, float16, float_status *status); FloatRelation float16_compare_quiet(float16, float16, float_status *status); -int float16_is_quiet_nan(float16, float_status *status); -int float16_is_signaling_nan(float16, float_status *status); +bool float16_is_quiet_nan(float16, float_status *status); +bool float16_is_signaling_nan(float16, float_status *status); float16 float16_silence_nan(float16, float_status *status); -static inline int float16_is_any_nan(float16 a) +static inline bool float16_is_any_nan(float16 a) { return ((float16_val(a) & ~0x8000) > 0x7c00); } -static inline int float16_is_neg(float16 a) +static inline bool float16_is_neg(float16 a) { return float16_val(a) >> 15; } -static inline int float16_is_infinity(float16 a) +static inline bool float16_is_infinity(float16 a) { return (float16_val(a) & 0x7fff) == 0x7c00; } -static inline int float16_is_zero(float16 a) +static inline bool float16_is_zero(float16 a) { return (float16_val(a) & 0x7fff) == 0; } -static inline int float16_is_zero_or_denormal(float16 a) +static inline bool float16_is_zero_or_denormal(float16 a) { return (float16_val(a) & 0x7c00) == 0; } @@ -351,8 +351,8 @@ float32 float32_minnum(float32, float32, float_status *status); float32 float32_maxnum(float32, float32, float_status *status); float32 float32_minnummag(float32, float32, float_status *status); float32 float32_maxnummag(float32, float32, float_status *status); -int float32_is_quiet_nan(float32, float_status *status); -int float32_is_signaling_nan(float32, float_status *status); +bool float32_is_quiet_nan(float32, float_status *status); +bool float32_is_signaling_nan(float32, float_status *status); float32 float32_silence_nan(float32, float_status *status); float32 float32_scalbn(float32, int, float_status *status); @@ -372,27 +372,27 @@ static inline float32 float32_chs(float32 a) return make_float32(float32_val(a) ^ 0x80000000); } -static inline int float32_is_infinity(float32 a) +static inline bool float32_is_infinity(float32 a) { return (float32_val(a) & 0x7fffffff) == 0x7f800000; } -static inline int float32_is_neg(float32 a) +static inline bool float32_is_neg(float32 a) { return float32_val(a) >> 31; } -static inline int float32_is_zero(float32 a) +static inline bool float32_is_zero(float32 a) { return (float32_val(a) & 0x7fffffff) == 0; } -static inline int float32_is_any_nan(float32 a) +static inline bool float32_is_any_nan(float32 a) { return ((float32_val(a) & ~(1 << 31)) > 0x7f800000UL); } -static inline int float32_is_zero_or_denormal(float32 a) +static inline bool float32_is_zero_or_denormal(float32 a) { return (float32_val(a) & 0x7f800000) == 0; } @@ -540,8 +540,8 @@ float64 float64_minnum(float64, float64, float_status *status); float64 float64_maxnum(float64, float64, float_status *status); float64 float64_minnummag(float64, float64, float_status *status); float64 float64_maxnummag(float64, float64, float_status *status); -int float64_is_quiet_nan(float64 a, float_status *status); -int float64_is_signaling_nan(float64, float_status *status); +bool float64_is_quiet_nan(float64 a, float_status *status); +bool float64_is_signaling_nan(float64, float_status *status); float64 float64_silence_nan(float64, float_status *status); float64 float64_scalbn(float64, int, float_status *status); @@ -561,27 +561,27 @@ static inline float64 float64_chs(float64 a) return make_float64(float64_val(a) ^ 0x8000000000000000LL); } -static inline int float64_is_infinity(float64 a) +static inline bool float64_is_infinity(float64 a) { return (float64_val(a) & 0x7fffffffffffffffLL ) == 0x7ff0000000000000LL; } -static inline int float64_is_neg(float64 a) +static inline bool float64_is_neg(float64 a) { return float64_val(a) >> 63; } -static inline int float64_is_zero(float64 a) +static inline bool float64_is_zero(float64 a) { return (float64_val(a) & 0x7fffffffffffffffLL) == 0; } -static inline int float64_is_any_nan(float64 a) +static inline bool float64_is_any_nan(float64 a) { return ((float64_val(a) & ~(1ULL << 63)) > 0x7ff0000000000000ULL); } -static inline int float64_is_zero_or_denormal(float64 a) +static inline bool float64_is_zero_or_denormal(float64 a) { return (float64_val(a) & 0x7ff0000000000000LL) == 0; } @@ -708,7 +708,7 @@ static inline floatx80 floatx80_chs(floatx80 a) return a; } -static inline int floatx80_is_infinity(floatx80 a) +static inline bool floatx80_is_infinity(floatx80 a) { #if defined(TARGET_M68K) return (a.high & 0x7fff) == floatx80_infinity.high && !(a.low << 1); @@ -718,22 +718,22 @@ static inline int floatx80_is_infinity(floatx80 a) #endif } -static inline int floatx80_is_neg(floatx80 a) +static inline bool floatx80_is_neg(floatx80 a) { return a.high >> 15; } -static inline int floatx80_is_zero(floatx80 a) +static inline bool floatx80_is_zero(floatx80 a) { return (a.high & 0x7fff) == 0 && a.low == 0; } -static inline int floatx80_is_zero_or_denormal(floatx80 a) +static inline bool floatx80_is_zero_or_denormal(floatx80 a) { return (a.high & 0x7fff) == 0; } -static inline int floatx80_is_any_nan(floatx80 a) +static inline bool floatx80_is_any_nan(floatx80 a) { return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1); } @@ -936,8 +936,8 @@ float128 float128_rem(float128, float128, float_status *status); float128 float128_sqrt(float128, float_status *status); FloatRelation float128_compare(float128, float128, float_status *status); FloatRelation float128_compare_quiet(float128, float128, float_status *status); -int float128_is_quiet_nan(float128, float_status *status); -int float128_is_signaling_nan(float128, float_status *status); +bool float128_is_quiet_nan(float128, float_status *status); +bool float128_is_signaling_nan(float128, float_status *status); float128 float128_silence_nan(float128, float_status *status); float128 float128_scalbn(float128, int, float_status *status); @@ -953,22 +953,22 @@ static inline float128 float128_chs(float128 a) return a; } -static inline int float128_is_infinity(float128 a) +static inline bool float128_is_infinity(float128 a) { return (a.high & 0x7fffffffffffffffLL) == 0x7fff000000000000LL && a.low == 0; } -static inline int float128_is_neg(float128 a) +static inline bool float128_is_neg(float128 a) { return a.high >> 63; } -static inline int float128_is_zero(float128 a) +static inline bool float128_is_zero(float128 a) { return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0; } -static inline int float128_is_zero_or_denormal(float128 a) +static inline bool float128_is_zero_or_denormal(float128 a) { return (a.high & 0x7fff000000000000LL) == 0; } @@ -983,7 +983,7 @@ static inline bool float128_is_denormal(float128 a) return float128_is_zero_or_denormal(a) && !float128_is_zero(a); } -static inline int float128_is_any_nan(float128 a) +static inline bool float128_is_any_nan(float128 a) { return ((a.high >> 48) & 0x7fff) == 0x7fff && ((a.low != 0) || ((a.high & 0xffffffffffffLL) != 0)); From 3b51ab4bf0f49a01cc2db7b954e0669e081719b5 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 12 May 2020 20:16:45 -0500 Subject: [PATCH 0606/2595] qemu-img: Add bitmap sub-command Include actions for --add, --remove, --clear, --enable, --disable, and --merge (note that --clear is a bit of fluff, because the same can be accomplished by removing a bitmap and then adding a new one in its place, but it matches what QMP commands exist). Listing is omitted, because it does not require a bitmap name and because it was already possible with 'qemu-img info'. A single command line can play one or more bitmap commands in sequence on the same bitmap name (although all added bitmaps share the same granularity, and and all merged bitmaps come from the same source file). Merge defaults to other bitmaps in the primary image, but can also be told to merge bitmaps from a distinct image. While this supports --image-opts for the file being modified, I did not think it worth the extra complexity to support that for the source file in a cross-file merges. Likewise, I chose to have --merge only take a single source rather than following the QMP support for multiple merges in one go (although you can still use more than one --merge in the command line); in part because qemu-img is offline and therefore atomicity is not an issue. Upcoming patches will add iotest coverage of these commands while also testing other features. Signed-off-by: Eric Blake Reviewed-by: Max Reitz Message-Id: <20200513011648.166876-7-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- docs/tools/qemu-img.rst | 24 ++++ qemu-img-cmds.hx | 7 ++ qemu-img.c | 248 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 279 insertions(+) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index 3b6223b5d6..38d464ea3f 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -281,6 +281,30 @@ Command description: For write tests, by default a buffer filled with zeros is written. This can be overridden with a pattern byte specified by *PATTERN*. +.. option:: bitmap (--merge SOURCE | --add | --remove | --clear | --enable | --disable)... [-b SOURCE_FILE [-F SOURCE_FMT]] [-g GRANULARITY] [--object OBJECTDEF] [--image-opts | -f FMT] FILENAME BITMAP + + Perform one or more modifications of the persistent bitmap *BITMAP* + in the disk image *FILENAME*. The various modifications are: + + ``--add`` to create *BITMAP*, enabled to record future edits. + + ``--remove`` to remove *BITMAP*. + + ``--clear`` to clear *BITMAP*. + + ``--enable`` to change *BITMAP* to start recording future edits. + + ``--disable`` to change *BITMAP* to stop recording future edits. + + ``--merge`` to merge the contents of *SOURCE_BITMAP* into *BITMAP*. + + Additional options include ``-g`` which sets a non-default + *GRANULARITY* for ``--add``, and ``-b`` and ``-F`` which select an + alternative source file for all *SOURCE* bitmaps used by + ``--merge``. + + To see what bitmaps are present in an image, use ``qemu-img info``. + .. option:: check [--object OBJECTDEF] [--image-opts] [-q] [-f FMT] [--output=OFMT] [-r [leaks | all]] [-T SRC_CACHE] [-U] FILENAME Perform a consistency check on the disk image *FILENAME*. The command can diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index cfe8f37587..a87d3cb264 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -20,6 +20,13 @@ DEF("bench", img_bench, SRST .. option:: bench [-c COUNT] [-d DEPTH] [-f FMT] [--flush-interval=FLUSH_INTERVAL] [-i AIO] [-n] [--no-drain] [-o OFFSET] [--pattern=PATTERN] [-q] [-s BUFFER_SIZE] [-S STEP_SIZE] [-t CACHE] [-w] [-U] FILENAME ERST + +DEF("bitmap", img_bitmap, + "bitmap (--merge SOURCE | --add | --remove | --clear | --enable | --disable)... [-b source_file [-F source_fmt]] [-g granularity] [--object objectdef] [--image-opts | -f fmt] filename bitmap") +SRST +.. option:: bitmap (--merge SOURCE | --add | --remove | --clear | --enable | --disable)... [-b SOURCE_FILE [-F SOURCE_FMT]] [-g GRANULARITY] [--object OBJECTDEF] [--image-opts | -f FMT] FILENAME BITMAP +ERST + DEF("check", img_check, "check [--object objectdef] [--image-opts] [-q] [-f fmt] [--output=ofmt] [-r [leaks | all]] [-T src_cache] [-U] filename") SRST diff --git a/qemu-img.c b/qemu-img.c index 4740de082f..2d30682f12 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -28,6 +28,7 @@ #include "qemu-common.h" #include "qemu-version.h" #include "qapi/error.h" +#include "qapi/qapi-commands-block-core.h" #include "qapi/qapi-visit-block-core.h" #include "qapi/qobject-output-visitor.h" #include "qapi/qmp/qjson.h" @@ -71,6 +72,12 @@ enum { OPTION_SHRINK = 266, OPTION_SALVAGE = 267, OPTION_TARGET_IS_ZERO = 268, + OPTION_ADD = 269, + OPTION_REMOVE = 270, + OPTION_CLEAR = 271, + OPTION_ENABLE = 272, + OPTION_DISABLE = 273, + OPTION_MERGE = 274, }; typedef enum OutputFormat { @@ -169,6 +176,14 @@ static void QEMU_NORETURN help(void) " '-n' skips the target volume creation (useful if the volume is created\n" " prior to running qemu-img)\n" "\n" + "Parameters to bitmap subcommand:\n" + " 'bitmap' is the name of the bitmap to manipulate, through one or more\n" + " actions from '--add', '--remove', '--clear', '--enable', '--disable',\n" + " or '--merge source'\n" + " '-g granularity' sets the granularity for '--add' actions\n" + " '-b source' and '-F src_fmt' tell '--merge' actions to find the source\n" + " bitmaps from an alternative file\n" + "\n" "Parameters to check subcommand:\n" " '-r' tries to repair any inconsistencies that are found during the check.\n" " '-r leaks' repairs only cluster leaks, whereas '-r all' fixes all\n" @@ -4502,6 +4517,239 @@ out: return 0; } +enum ImgBitmapAct { + BITMAP_ADD, + BITMAP_REMOVE, + BITMAP_CLEAR, + BITMAP_ENABLE, + BITMAP_DISABLE, + BITMAP_MERGE, +}; +typedef struct ImgBitmapAction { + enum ImgBitmapAct act; + const char *src; /* only used for merge */ + QSIMPLEQ_ENTRY(ImgBitmapAction) next; +} ImgBitmapAction; + +static int img_bitmap(int argc, char **argv) +{ + Error *err = NULL; + int c, ret = 1; + QemuOpts *opts = NULL; + const char *fmt = NULL, *src_fmt = NULL, *src_filename = NULL; + const char *filename, *bitmap; + BlockBackend *blk = NULL, *src = NULL; + BlockDriverState *bs = NULL, *src_bs = NULL; + bool image_opts = false; + int64_t granularity = 0; + bool add = false, merge = false; + QSIMPLEQ_HEAD(, ImgBitmapAction) actions; + ImgBitmapAction *act, *act_next; + const char *op; + + QSIMPLEQ_INIT(&actions); + + for (;;) { + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {"add", no_argument, 0, OPTION_ADD}, + {"remove", no_argument, 0, OPTION_REMOVE}, + {"clear", no_argument, 0, OPTION_CLEAR}, + {"enable", no_argument, 0, OPTION_ENABLE}, + {"disable", no_argument, 0, OPTION_DISABLE}, + {"merge", required_argument, 0, OPTION_MERGE}, + {"granularity", required_argument, 0, 'g'}, + {"source-file", required_argument, 0, 'b'}, + {"source-format", required_argument, 0, 'F'}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, ":b:f:F:g:h", long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case ':': + missing_argument(argv[optind - 1]); + break; + case '?': + unrecognized_option(argv[optind - 1]); + break; + case 'h': + help(); + break; + case 'b': + src_filename = optarg; + break; + case 'f': + fmt = optarg; + break; + case 'F': + src_fmt = optarg; + break; + case 'g': + granularity = cvtnum("granularity", optarg); + if (granularity < 0) { + return 1; + } + break; + case OPTION_ADD: + act = g_new0(ImgBitmapAction, 1); + act->act = BITMAP_ADD; + QSIMPLEQ_INSERT_TAIL(&actions, act, next); + add = true; + break; + case OPTION_REMOVE: + act = g_new0(ImgBitmapAction, 1); + act->act = BITMAP_REMOVE; + QSIMPLEQ_INSERT_TAIL(&actions, act, next); + break; + case OPTION_CLEAR: + act = g_new0(ImgBitmapAction, 1); + act->act = BITMAP_CLEAR; + QSIMPLEQ_INSERT_TAIL(&actions, act, next); + break; + case OPTION_ENABLE: + act = g_new0(ImgBitmapAction, 1); + act->act = BITMAP_ENABLE; + QSIMPLEQ_INSERT_TAIL(&actions, act, next); + break; + case OPTION_DISABLE: + act = g_new0(ImgBitmapAction, 1); + act->act = BITMAP_DISABLE; + QSIMPLEQ_INSERT_TAIL(&actions, act, next); + break; + case OPTION_MERGE: + act = g_new0(ImgBitmapAction, 1); + act->act = BITMAP_MERGE; + act->src = optarg; + QSIMPLEQ_INSERT_TAIL(&actions, act, next); + merge = true; + break; + case OPTION_OBJECT: + opts = qemu_opts_parse_noisily(&qemu_object_opts, optarg, true); + if (!opts) { + goto out; + } + break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; + } + } + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + qemu_img_object_print_help, &error_fatal)) { + goto out; + } + + if (QSIMPLEQ_EMPTY(&actions)) { + error_report("Need at least one of --add, --remove, --clear, " + "--enable, --disable, or --merge"); + goto out; + } + + if (granularity && !add) { + error_report("granularity only supported with --add"); + goto out; + } + if (src_fmt && !src_filename) { + error_report("-F only supported with -b"); + goto out; + } + if (src_filename && !merge) { + error_report("Merge bitmap source file only supported with " + "--merge"); + goto out; + } + + if (optind != argc - 2) { + error_report("Expecting filename and bitmap name"); + goto out; + } + + filename = argv[optind]; + bitmap = argv[optind + 1]; + + blk = img_open(image_opts, filename, fmt, BDRV_O_RDWR, false, false, + false); + if (!blk) { + goto out; + } + bs = blk_bs(blk); + if (src_filename) { + src = img_open(false, src_filename, src_fmt, 0, false, false, false); + if (!src) { + goto out; + } + src_bs = blk_bs(src); + } else { + src_bs = bs; + } + + QSIMPLEQ_FOREACH_SAFE(act, &actions, next, act_next) { + switch (act->act) { + case BITMAP_ADD: + qmp_block_dirty_bitmap_add(bs->node_name, bitmap, + !!granularity, granularity, true, true, + false, false, &err); + op = "add"; + break; + case BITMAP_REMOVE: + qmp_block_dirty_bitmap_remove(bs->node_name, bitmap, &err); + op = "remove"; + break; + case BITMAP_CLEAR: + qmp_block_dirty_bitmap_clear(bs->node_name, bitmap, &err); + op = "clear"; + break; + case BITMAP_ENABLE: + qmp_block_dirty_bitmap_enable(bs->node_name, bitmap, &err); + op = "enable"; + break; + case BITMAP_DISABLE: + qmp_block_dirty_bitmap_disable(bs->node_name, bitmap, &err); + op = "disable"; + break; + case BITMAP_MERGE: { + BlockDirtyBitmapMergeSource *merge_src; + BlockDirtyBitmapMergeSourceList *list; + + merge_src = g_new0(BlockDirtyBitmapMergeSource, 1); + merge_src->type = QTYPE_QDICT; + merge_src->u.external.node = g_strdup(src_bs->node_name); + merge_src->u.external.name = g_strdup(act->src); + list = g_new0(BlockDirtyBitmapMergeSourceList, 1); + list->value = merge_src; + qmp_block_dirty_bitmap_merge(bs->node_name, bitmap, list, &err); + qapi_free_BlockDirtyBitmapMergeSourceList(list); + op = "merge"; + break; + } + default: + g_assert_not_reached(); + } + + if (err) { + error_reportf_err(err, "Operation %s on bitmap %s failed: ", + op, bitmap); + goto out; + } + g_free(act); + } + + ret = 0; + + out: + blk_unref(src); + blk_unref(blk); + qemu_opts_del(opts); + return ret; +} + #define C_BS 01 #define C_COUNT 02 #define C_IF 04 From 776b97d3605ed0fc94443048fdf988c7725e38a9 Mon Sep 17 00:00:00 2001 From: xiaoqiang zhao Date: Sat, 16 May 2020 11:13:25 +0800 Subject: [PATCH 0607/2595] qemu-sockets: add abstract UNIX domain socket support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit unix_listen/connect_saddr now support abstract address types two aditional BOOL switches are introduced: tight: whether to set @addrlen to the minimal string length, or the maximum sun_path length. default is TRUE abstract: whether we use abstract address. default is FALSE cli example: -monitor unix:/tmp/unix.socket,abstract,tight=off OR -chardev socket,path=/tmp/unix.socket,id=unix1,abstract,tight=on Signed-off-by: xiaoqiang zhao Signed-off-by: Daniel P. Berrangé --- chardev/char-socket.c | 4 ++++ chardev/char.c | 7 +++++++ qapi/sockets.json | 8 +++++++- util/qemu-sockets.c | 39 ++++++++++++++++++++++++++++++++------- 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 232e0a8604..e77699db48 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1380,6 +1380,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, const char *host = qemu_opt_get(opts, "host"); const char *port = qemu_opt_get(opts, "port"); const char *fd = qemu_opt_get(opts, "fd"); + bool tight = qemu_opt_get_bool(opts, "tight", true); + bool abstract = qemu_opt_get_bool(opts, "abstract", false); SocketAddressLegacy *addr; ChardevSocket *sock; @@ -1431,6 +1433,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX; q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1); q_unix->path = g_strdup(path); + q_unix->tight = tight; + q_unix->abstract = abstract; } else if (host) { addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET; addr->u.inet.data = g_new(InetSocketAddress, 1); diff --git a/chardev/char.c b/chardev/char.c index 0196e2887b..ea06c5ff4d 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -939,6 +939,13 @@ QemuOptsList qemu_chardev_opts = { },{ .name = "logappend", .type = QEMU_OPT_BOOL, + },{ + .name = "tight", + .type = QEMU_OPT_BOOL, + .def_value_str = "on", + },{ + .name = "abstract", + .type = QEMU_OPT_BOOL, }, { /* end of list */ } }, diff --git a/qapi/sockets.json b/qapi/sockets.json index ea933ed4b2..cbd6ef35d0 100644 --- a/qapi/sockets.json +++ b/qapi/sockets.json @@ -73,12 +73,18 @@ # Captures a socket address in the local ("Unix socket") namespace. # # @path: filesystem path to use +# @tight: pass a socket address length confined to the minimum length of the +# abstract string, rather than the full sockaddr_un record length +# (only matters for abstract sockets, default true). (Since 5.1) +# @abstract: whether this is an abstract address, default false. (Since 5.1) # # Since: 1.3 ## { 'struct': 'UnixSocketAddress', 'data': { - 'path': 'str' } } + 'path': 'str', + '*tight': 'bool', + '*abstract': 'bool' } } ## # @VsockSocketAddress: diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 86c48b9fa5..b37d288866 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -863,6 +863,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, char *pathbuf = NULL; const char *path; size_t pathlen; + size_t addrlen; sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { @@ -879,9 +880,11 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, } pathlen = strlen(path); - if (pathlen > sizeof(un.sun_path)) { + if (pathlen > sizeof(un.sun_path) || + (saddr->abstract && pathlen > (sizeof(un.sun_path) - 1))) { error_setg(errp, "UNIX socket path '%s' is too long", path); error_append_hint(errp, "Path must be less than %zu bytes\n", + saddr->abstract ? sizeof(un.sun_path) - 1 : sizeof(un.sun_path)); goto err; } @@ -903,7 +906,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, close(fd); } - if (unlink(path) < 0 && errno != ENOENT) { + if (!saddr->abstract && unlink(path) < 0 && errno != ENOENT) { error_setg_errno(errp, errno, "Failed to unlink socket %s", path); goto err; @@ -911,9 +914,19 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; - memcpy(un.sun_path, path, pathlen); + addrlen = sizeof(un); - if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { + if (saddr->abstract) { + un.sun_path[0] = '\0'; + memcpy(&un.sun_path[1], path, pathlen); + if (saddr->tight) { + addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + pathlen; + } + } else { + memcpy(un.sun_path, path, pathlen); + } + + if (bind(sock, (struct sockaddr *) &un, addrlen) < 0) { error_setg_errno(errp, errno, "Failed to bind socket to %s", path); goto err; } @@ -936,6 +949,7 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) struct sockaddr_un un; int sock, rc; size_t pathlen; + size_t addrlen; if (saddr->path == NULL) { error_setg(errp, "unix connect: no path specified"); @@ -949,21 +963,32 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) } pathlen = strlen(saddr->path); - if (pathlen > sizeof(un.sun_path)) { + if (pathlen > sizeof(un.sun_path) || + (saddr->abstract && pathlen > (sizeof(un.sun_path) - 1))) { error_setg(errp, "UNIX socket path '%s' is too long", saddr->path); error_append_hint(errp, "Path must be less than %zu bytes\n", + saddr->abstract ? sizeof(un.sun_path) - 1 : sizeof(un.sun_path)); goto err; } memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; - memcpy(un.sun_path, saddr->path, pathlen); + addrlen = sizeof(un); + if (saddr->abstract) { + un.sun_path[0] = '\0'; + memcpy(&un.sun_path[1], saddr->path, pathlen); + if (saddr->tight) { + addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + pathlen; + } + } else { + memcpy(un.sun_path, saddr->path, pathlen); + } /* connect to peer */ do { rc = 0; - if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) { + if (connect(sock, (struct sockaddr *) &un, addrlen) < 0) { rc = -errno; } } while (rc == -EINTR); From 4d3a329af59ef8acd076f99f05e82531d8129b34 Mon Sep 17 00:00:00 2001 From: xiaoqiang zhao Date: Sat, 16 May 2020 11:13:26 +0800 Subject: [PATCH 0608/2595] tests/util-sockets: add abstract unix socket cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add cases to test tight and non-tight for abstract address type Signed-off-by: xiaoqiang zhao Signed-off-by: Daniel P. Berrangé --- tests/test-util-sockets.c | 92 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c index 5fd947c7bf..2ca1e99f17 100644 --- a/tests/test-util-sockets.c +++ b/tests/test-util-sockets.c @@ -227,6 +227,93 @@ static void test_socket_fd_pass_num_nocli(void) g_free(addr.u.fd.str); } +#ifdef __linux__ +static gchar *abstract_sock_name; + +static gpointer unix_server_thread_func(gpointer user_data) +{ + SocketAddress addr; + Error *err = NULL; + int fd = -1; + int connfd = -1; + struct sockaddr_un un; + socklen_t len = sizeof(un); + + addr.type = SOCKET_ADDRESS_TYPE_UNIX; + addr.u.q_unix.path = abstract_sock_name; + addr.u.q_unix.tight = user_data != NULL; + addr.u.q_unix.abstract = true; + + fd = socket_listen(&addr, 1, &err); + g_assert_cmpint(fd, >=, 0); + g_assert(fd_is_socket(fd)); + + connfd = accept(fd, (struct sockaddr *)&un, &len); + g_assert_cmpint(connfd, !=, -1); + + close(fd); + + return NULL; +} + +static gpointer unix_client_thread_func(gpointer user_data) +{ + SocketAddress addr; + Error *err = NULL; + int fd = -1; + + addr.type = SOCKET_ADDRESS_TYPE_UNIX; + addr.u.q_unix.path = abstract_sock_name; + addr.u.q_unix.tight = user_data != NULL; + addr.u.q_unix.abstract = true; + + fd = socket_connect(&addr, &err); + + g_assert_cmpint(fd, >=, 0); + + close(fd); + + return NULL; +} + +static void test_socket_unix_abstract_good(void) +{ + GRand *r = g_rand_new(); + + abstract_sock_name = g_strdup_printf("unix-%d-%d", getpid(), + g_rand_int_range(r, 100, 1000)); + + /* non tight socklen serv and cli */ + GThread *serv = g_thread_new("abstract_unix_server", + unix_server_thread_func, + NULL); + + sleep(1); + + GThread *cli = g_thread_new("abstract_unix_client", + unix_client_thread_func, + NULL); + + g_thread_join(cli); + g_thread_join(serv); + + /* tight socklen serv and cli */ + serv = g_thread_new("abstract_unix_server", + unix_server_thread_func, + (gpointer)1); + + sleep(1); + + cli = g_thread_new("abstract_unix_client", + unix_client_thread_func, + (gpointer)1); + + g_thread_join(cli); + g_thread_join(serv); + + g_free(abstract_sock_name); +} +#endif int main(int argc, char **argv) { @@ -265,6 +352,11 @@ int main(int argc, char **argv) test_socket_fd_pass_num_nocli); } +#ifdef __linux__ + g_test_add_func("/util/socket/unix-abstract/good", + test_socket_unix_abstract_good); +#endif + end: return g_test_run(); } From e339273bfc514824410a49837e4f16dd4e51ae8e Mon Sep 17 00:00:00 2001 From: xiaoqiang zhao Date: Sat, 16 May 2020 11:13:27 +0800 Subject: [PATCH 0609/2595] qemu-options: updates for abstract unix sockets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add options documents changes for -chardev Signed-off-by: xiaoqiang zhao Signed-off-by: Daniel P. Berrangé --- qemu-options.hx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index e2dca8a4e9..93bde2bbc8 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2938,7 +2938,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, " [,server][,nowait][,telnet][,websocket][,reconnect=seconds][,mux=on|off]\n" " [,logfile=PATH][,logappend=on|off][,tls-creds=ID][,tls-authz=ID] (tcp)\n" "-chardev socket,id=id,path=path[,server][,nowait][,telnet][,websocket][,reconnect=seconds]\n" - " [,mux=on|off][,logfile=PATH][,logappend=on|off] (unix)\n" + " [,mux=on|off][,logfile=PATH][,logappend=on|off][,abstract=on|off][,tight=on|off] (unix)\n" "-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr]\n" " [,localport=localport][,ipv4][,ipv6][,mux=on|off]\n" " [,logfile=PATH][,logappend=on|off]\n" @@ -3105,9 +3105,13 @@ The available backends are: ``nodelay`` disables the Nagle algorithm. - ``unix options: path=path`` + ``unix options: path=path[,abstract=on|off][,tight=on|off]`` ``path`` specifies the local path of the unix socket. ``path`` is required. + ``abstract`` specifies the use of the abstract socket namespace, + rather than the filesystem. Optional, defaults to false. + ``tight`` sets the socket length of abstract sockets to their minimum, + rather than the full sun_path length. Optional, defaults to true. ``-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr][,localport=localport][,ipv4][,ipv6]`` Sends all traffic from the guest to a remote host over UDP. From 56c2c59252deb5676f63faf69a1b5fb97372b551 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 14 May 2020 21:04:22 +0200 Subject: [PATCH 0610/2595] tests/acceptance: Add a test for the canon-a1100 machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The canon-a1100 machine can be used with the Barebox firmware. The QEMU Advent Calendar 2018 features a pre-compiled image which we can use for testing. Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Reviewed-by: Wainer dos Santos Moschetta Tested-by: Wainer dos Santos Moschetta Signed-off-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200514190422.23645-1-f4bug@amsat.org Message-Id: <20200129090420.13954-1-thuth@redhat.com> [PMD: Rebased MAINTAINERS] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- MAINTAINERS | 1 + tests/acceptance/machine_arm_canona1100.py | 35 ++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/acceptance/machine_arm_canona1100.py diff --git a/MAINTAINERS b/MAINTAINERS index 87a412c229..1e006c98fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -608,6 +608,7 @@ S: Odd Fixes F: include/hw/arm/digic.h F: hw/*/digic* F: include/hw/*/digic* +F: tests/acceptance/machine_arm_canona1100.py Goldfish RTC M: Anup Patel diff --git a/tests/acceptance/machine_arm_canona1100.py b/tests/acceptance/machine_arm_canona1100.py new file mode 100644 index 0000000000..0e5c43dbcf --- /dev/null +++ b/tests/acceptance/machine_arm_canona1100.py @@ -0,0 +1,35 @@ +# Functional test that boots the canon-a1100 machine with firmware +# +# Copyright (c) 2020 Red Hat, Inc. +# +# Author: +# Thomas Huth +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +from avocado_qemu import Test +from avocado_qemu import wait_for_console_pattern +from avocado.utils import archive + +class CanonA1100Machine(Test): + """Boots the barebox firmware and checks that the console is operational""" + + timeout = 90 + + def test_arm_canona1100(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:canon-a1100 + :avocado: tags=device:pflash_cfi02 + """ + tar_url = ('https://www.qemu-advent-calendar.org' + '/2018/download/day18.tar.xz') + tar_hash = '068b5fc4242b29381acee94713509f8a876e9db6' + file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + archive.extract(file_path, self.workdir) + self.vm.set_console() + self.vm.add_args('-bios', + self.workdir + '/day18/barebox.canon-a1100.bin') + self.vm.launch() + wait_for_console_pattern(self, 'running /env/bin/init') From fc68b1c6755c467e256202a2eed7c145c7b4581e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 7 May 2020 16:18:15 +0100 Subject: [PATCH 0611/2595] docs/system: Add 'Arm' to the Integrator/CP document title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 'Arm' to the Integrator/CP document title, for consistency with the titling of the other documentation of Arm devboard models (versatile, realview). Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Reviewed-by: Alex Bennée Message-id: 20200507151819.28444-2-peter.maydell@linaro.org --- docs/system/arm/integratorcp.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/system/arm/integratorcp.rst b/docs/system/arm/integratorcp.rst index e6f050f602..594438008e 100644 --- a/docs/system/arm/integratorcp.rst +++ b/docs/system/arm/integratorcp.rst @@ -1,5 +1,5 @@ -Integrator/CP (``integratorcp``) -================================ +Arm Integrator/CP (``integratorcp``) +==================================== The Arm Integrator/CP board is emulated with the following devices: From b6e50ad0dbda699a2511861d84e313c756baded8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 7 May 2020 16:18:16 +0100 Subject: [PATCH 0612/2595] docs/system: Sort Arm board index into alphabetical order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sort the board index into alphabetical order. (Note that we need to sort alphabetically by the title text of each file, which isn't the same ordering as sorting by the filename.) Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Reviewed-by: Alex Bennée Message-id: 20200507151819.28444-3-peter.maydell@linaro.org --- docs/system/target-arm.rst | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index 324e2af1cb..d459efb3d2 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -67,19 +67,24 @@ Unfortunately many of the Arm boards QEMU supports are currently undocumented; you can get a complete list by running ``qemu-system-aarch64 --machine help``. +.. + This table of contents should be kept sorted alphabetically + by the title text of each file, which isn't the same ordering + as an alphabetical sort by filename. + .. toctree:: :maxdepth: 1 arm/integratorcp - arm/versatile arm/realview - arm/xscale - arm/palm - arm/nseries - arm/stellaris + arm/versatile arm/musicpal - arm/sx1 + arm/nseries arm/orangepi + arm/palm + arm/xscale + arm/sx1 + arm/stellaris Arm CPU features ================ From 5a1d424487992613582e8ed3d3070833f155cf75 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 7 May 2020 16:18:17 +0100 Subject: [PATCH 0613/2595] docs/system: Document Arm Versatile Express boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide a minimal documentation of the Versatile Express boards (vexpress-a9, vexpress-a15). Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Reviewed-by: Alex Bennée Message-id: 20200507151819.28444-4-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/vexpress.rst | 60 ++++++++++++++++++++++++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 62 insertions(+) create mode 100644 docs/system/arm/vexpress.rst diff --git a/MAINTAINERS b/MAINTAINERS index 1e006c98fa..6a9280c1b0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -828,6 +828,7 @@ M: Peter Maydell L: qemu-arm@nongnu.org S: Maintained F: hw/arm/vexpress.c +F: docs/system/arm/vexpress.rst Versatile PB M: Peter Maydell diff --git a/docs/system/arm/vexpress.rst b/docs/system/arm/vexpress.rst new file mode 100644 index 0000000000..7f1bcbef07 --- /dev/null +++ b/docs/system/arm/vexpress.rst @@ -0,0 +1,60 @@ +Arm Versatile Express boards (``vexpress-a9``, ``vexpress-a15``) +================================================================ + +QEMU models two variants of the Arm Versatile Express development +board family: + +- ``vexpress-a9`` models the combination of the Versatile Express + motherboard and the CoreTile Express A9x4 daughterboard +- ``vexpress-a15`` models the combination of the Versatile Express + motherboard and the CoreTile Express A15x2 daughterboard + +Note that as this hardware does not have PCI, IDE or SCSI, +the only available storage option is emulated SD card. + +Implemented devices: + +- PL041 audio +- PL181 SD controller +- PL050 keyboard and mouse +- PL011 UARTs +- SP804 timers +- I2C controller +- PL031 RTC +- PL111 LCD display controller +- Flash memory +- LAN9118 ethernet + +Unimplemented devices: + +- SP810 system control block +- PCI-express +- USB controller (Philips ISP1761) +- Local DAP ROM +- CoreSight interfaces +- PL301 AXI interconnect +- SCC +- System counter +- HDLCD controller (``vexpress-a15``) +- SP805 watchdog +- PL341 dynamic memory controller +- DMA330 DMA controller +- PL354 static memory controller +- BP147 TrustZone Protection Controller +- TrustZone Address Space Controller + +Other differences between the hardware and the QEMU model: + +- QEMU will default to creating one CPU unless you pass a different + ``-smp`` argument +- QEMU allows the amount of RAM provided to be specified with the + ``-m`` argument +- QEMU defaults to providing a CPU which does not provide either + TrustZone or the Virtualization Extensions: if you want these you + must enable them with ``-machine secure=on`` and ``-machine + virtualization=on`` +- QEMU provides 4 virtio-mmio virtio transports; these start at + address ``0x10013000`` for ``vexpress-a9`` and at ``0x1c130000`` for + ``vexpress-a15``, and have IRQs from 40 upwards. If a dtb is + provided on the command line then QEMU will edit it to include + suitable entries describing these transports for the guest. diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index d459efb3d2..1c759aa1a0 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -78,6 +78,7 @@ undocumented; you can get a complete list by running arm/integratorcp arm/realview arm/versatile + arm/vexpress arm/musicpal arm/nseries arm/orangepi From ba7912a55ae836019a97f0f192222616388fb154 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 7 May 2020 16:18:18 +0100 Subject: [PATCH 0614/2595] docs/system: Document the various MPS2 models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add basic documentation of the MPS2 board models. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Reviewed-by: Alex Bennée Message-id: 20200507151819.28444-5-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/mps2.rst | 29 +++++++++++++++++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 31 insertions(+) create mode 100644 docs/system/arm/mps2.rst diff --git a/MAINTAINERS b/MAINTAINERS index 6a9280c1b0..520a7b74f2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -701,6 +701,7 @@ F: hw/misc/armsse-cpuid.c F: include/hw/misc/armsse-cpuid.h F: hw/misc/armsse-mhu.c F: include/hw/misc/armsse-mhu.h +F: docs/system/arm/mps2.rst Musca M: Peter Maydell diff --git a/docs/system/arm/mps2.rst b/docs/system/arm/mps2.rst new file mode 100644 index 0000000000..3a98cb59b0 --- /dev/null +++ b/docs/system/arm/mps2.rst @@ -0,0 +1,29 @@ +Arm MPS2 boards (``mps2-an385``, ``mps2-an505``, ``mps2-an511``, ``mps2-an521``) +================================================================================ + +These board models all use Arm M-profile CPUs. + +The Arm MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger +FPGA but is otherwise the same as the 2). Since the CPU itself +and most of the devices are in the FPGA, the details of the board +as seen by the guest depend significantly on the FPGA image. + +QEMU models the following FPGA images: + +``mps2-an385`` + Cortex-M3 as documented in ARM Application Note AN385 +``mps2-an511`` + Cortex-M3 'DesignStart' as documented in AN511 +``mps2-an505`` + Cortex-M33 as documented in ARM Application Note AN505 +``mps2-an521`` + Dual Cortex-M33 as documented in Application Note AN521 + +Differences between QEMU and real hardware: + +- AN385 remapping of low 16K of memory to either ZBT SSRAM1 or to + block RAM is unimplemented (QEMU always maps this to ZBT SSRAM1, as + if zbt_boot_ctrl is always zero) +- QEMU provides a LAN9118 ethernet rather than LAN9220; the only guest + visible difference is that the LAN9118 doesn't support checksum + offloading diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index 1c759aa1a0..f2d9366e9b 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -76,6 +76,7 @@ undocumented; you can get a complete list by running :maxdepth: 1 arm/integratorcp + arm/mps2 arm/realview arm/versatile arm/vexpress From 9f8f640eae8a875fa302d64748985bf21dc7f907 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 7 May 2020 16:18:19 +0100 Subject: [PATCH 0615/2595] docs/system: Document Musca boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide a minimal documentation of the Musca boards. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Reviewed-by: Alex Bennée Message-id: 20200507151819.28444-6-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/musca.rst | 31 +++++++++++++++++++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 33 insertions(+) create mode 100644 docs/system/arm/musca.rst diff --git a/MAINTAINERS b/MAINTAINERS index 520a7b74f2..023f48d3ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -708,6 +708,7 @@ M: Peter Maydell L: qemu-arm@nongnu.org S: Maintained F: hw/arm/musca.c +F: docs/system/arm/musca.rst Musicpal M: Jan Kiszka diff --git a/docs/system/arm/musca.rst b/docs/system/arm/musca.rst new file mode 100644 index 0000000000..81e3dc9219 --- /dev/null +++ b/docs/system/arm/musca.rst @@ -0,0 +1,31 @@ +Arm Musca boards (``musca-a``, ``musca-b1``) +============================================ + +The Arm Musca development boards are a reference implementation +of a system using the SSE-200 Subsystem for Embedded. They are +dual Cortex-M33 systems. + +QEMU provides models of the A and B1 variants of this board. + +Unimplemented devices: + +- SPI +- |I2C| +- |I2S| +- PWM +- QSPI +- Timer +- SCC +- GPIO +- eFlash +- MHU +- PVT +- SDIO +- CryptoCell + +Note that (like the real hardware) the Musca-A machine is +asymmetric: CPU 0 does not have the FPU or DSP extensions, +but CPU 1 does. Also like the real hardware, the memory maps +for the A and B1 variants differ significantly, so guest +software must be built for the right variant. + diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index f2d9366e9b..dce384cb0e 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -77,6 +77,7 @@ undocumented; you can get a complete list by running arm/integratorcp arm/mps2 + arm/musca arm/realview arm/versatile arm/vexpress From 13a0c21e64bddf1a3659d30b2b6e95529f9047ed Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 20 Apr 2020 22:22:03 +0100 Subject: [PATCH 0616/2595] linux-user/arm: BKPT should cause SIGTRAP, not be a syscall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In linux-user/arm/cpu-loop.c we incorrectly treat EXCP_BKPT similarly to EXCP_SWI, which means that if the guest executes a BKPT insn then QEMU will perform a syscall for it (which syscall depends on what value happens to be in r7...). The correct behaviour is that the guest process should take a SIGTRAP. This code has been like this (more or less) since commit 06c949e62a098f in 2006 which added BKPT in the first place. This is probably because at the time the same code path was used to handle both Linux syscalls and semihosting calls, and (on M profile) BKPT with a suitable magic number is used for semihosting calls. But these days we've moved handling of semihosting out to an entirely different codepath, so we can fix this bug by simply removing this handling of EXCP_BKPT and instead making it deliver a SIGTRAP like EXCP_DEBUG (as we do already on aarch64). Reported-by: Reviewed-by: Edgar E. Iglesias Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell Message-id: 20200420212206.12776-2-peter.maydell@linaro.org Fixes: https://bugs.launchpad.net/qemu/+bug/1873898 Signed-off-by: Peter Maydell --- linux-user/arm/cpu_loop.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index cf618daa1c..82d0dd3c31 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -295,32 +295,17 @@ void cpu_loop(CPUARMState *env) } break; case EXCP_SWI: - case EXCP_BKPT: { env->eabi = 1; /* system call */ - if (trapnr == EXCP_BKPT) { - if (env->thumb) { - /* FIXME - what to do if get_user() fails? */ - get_user_code_u16(insn, env->regs[15], env); - n = insn & 0xff; - env->regs[15] += 2; - } else { - /* FIXME - what to do if get_user() fails? */ - get_user_code_u32(insn, env->regs[15], env); - n = (insn & 0xf) | ((insn >> 4) & 0xff0); - env->regs[15] += 4; - } + if (env->thumb) { + /* FIXME - what to do if get_user() fails? */ + get_user_code_u16(insn, env->regs[15] - 2, env); + n = insn & 0xff; } else { - if (env->thumb) { - /* FIXME - what to do if get_user() fails? */ - get_user_code_u16(insn, env->regs[15] - 2, env); - n = insn & 0xff; - } else { - /* FIXME - what to do if get_user() fails? */ - get_user_code_u32(insn, env->regs[15] - 4, env); - n = insn & 0xffffff; - } + /* FIXME - what to do if get_user() fails? */ + get_user_code_u32(insn, env->regs[15] - 4, env); + n = insn & 0xffffff; } if (n == ARM_NR_cacheflush) { @@ -396,6 +381,7 @@ void cpu_loop(CPUARMState *env) } break; case EXCP_DEBUG: + case EXCP_BKPT: excp_debug: info.si_signo = TARGET_SIGTRAP; info.si_errno = 0; From 62f141a426d27c15555714a2c2967045b43d9a4a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 20 Apr 2020 22:22:04 +0100 Subject: [PATCH 0617/2595] linux-user/arm: Remove bogus SVC 0xf0002 handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We incorrectly treat SVC 0xf0002 as a cacheflush request (which is a NOP for QEMU). This is the wrong syscall number, because in the svc-immediate OABI syscall numbers are all offset by the ARM_SYSCALL_BASE value and so the correct insn is SVC 0x9f0002. (This is handled further down in the code with the other Arm-specific syscalls like NR_breakpoint.) When this code was initially added in commit 6f1f31c069b20611 in 2004, ARM_NR_cacheflush was defined as (ARM_SYSCALL_BASE + 0xf0000 + 2) so the value in the comparison took account of the extra 0x900000 offset. In commit fbb4a2e371f2fa7 in 2008, the ARM_SYSCALL_BASE was removed from the definition of ARM_NR_cacheflush and handling for this group of syscalls was added below the point where we subtract ARM_SYSCALL_BASE from the SVC immediate value. However that commit forgot to remove the now-obsolete earlier handling code. Remove the spurious ARM_NR_cacheflush condition. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Message-id: 20200420212206.12776-3-peter.maydell@linaro.org --- linux-user/arm/cpu_loop.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 82d0dd3c31..025887d6b8 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -308,9 +308,7 @@ void cpu_loop(CPUARMState *env) n = insn & 0xffffff; } - if (n == ARM_NR_cacheflush) { - /* nop */ - } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) { + if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) { /* linux syscall */ if (env->thumb || n == 0) { n = env->regs[7]; From ab546bd23856866411ff1b2ffaedabdc360e69df Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 20 Apr 2020 22:22:05 +0100 Subject: [PATCH 0618/2595] linux-user/arm: Handle invalid arm-specific syscalls correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kernel has different handling for syscalls with invalid numbers that are in the "arm-specific" range 0x9f0000 and up: * 0x9f0000..0x9f07ff return -ENOSYS if not implemented * other out of range syscalls cause a SIGILL (see the kernel's arch/arm/kernel/traps.c:arm_syscall()) Implement this distinction. (Note that our code doesn't look quite like the kernel's, because we have removed the 0x900000 prefix by this point, whereas the kernel retains it in arm_syscall().) Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200420212206.12776-4-peter.maydell@linaro.org --- linux-user/arm/cpu_loop.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 025887d6b8..df8b7b3fa9 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -332,10 +332,32 @@ void cpu_loop(CPUARMState *env) env->regs[0] = cpu_get_tls(env); break; default: - qemu_log_mask(LOG_UNIMP, - "qemu: Unsupported ARM syscall: 0x%x\n", - n); - env->regs[0] = -TARGET_ENOSYS; + if (n < 0xf0800) { + /* + * Syscalls 0xf0000..0xf07ff (or 0x9f0000.. + * 0x9f07ff in OABI numbering) are defined + * to return -ENOSYS rather than raising + * SIGILL. Note that we have already + * removed the 0x900000 prefix. + */ + qemu_log_mask(LOG_UNIMP, + "qemu: Unsupported ARM syscall: 0x%x\n", + n); + env->regs[0] = -TARGET_ENOSYS; + } else { + /* Otherwise SIGILL */ + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLTRP; + info._sifields._sigfault._addr = env->regs[15]; + if (env->thumb) { + info._sifields._sigfault._addr -= 2; + } else { + info._sifields._sigfault._addr -= 4; + } + queue_signal(env, info.si_signo, + QEMU_SI_FAULT, &info); + } break; } } else { From 3986a1721e10aebe0dc2c17f262ebf067e7414df Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 20 Apr 2020 22:22:06 +0100 Subject: [PATCH 0619/2595] linux-user/arm: Fix identification of syscall numbers Our code to identify syscall numbers has some issues: * for Thumb mode, we never need the immediate value from the insn, but we always read it anyway * bad immediate values in the svc insn should cause a SIGILL, but we were abort()ing instead (via "goto error") We can fix both these things by refactoring the code that identifies the syscall number to more closely follow the kernel COMPAT_OABI code: * for Thumb it is always r7 * for Arm, if the immediate value is 0, then this is an EABI call with the syscall number in r7 * otherwise, we XOR the immediate value with 0x900000 (ARM_SYSCALL_BASE for QEMU; __NR_OABI_SYSCALL_BASE in the kernel), which converts valid syscall immediates into the desired value, and puts all invalid immediates in the range 0x100000 or above * then we can just let the existing "value too large, deliver SIGILL" case handle invalid numbers, and drop the 'goto error' Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Message-id: 20200420212206.12776-5-peter.maydell@linaro.org --- linux-user/arm/cpu_loop.c | 143 ++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 66 deletions(-) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index df8b7b3fa9..13629ee1f6 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -299,85 +299,96 @@ void cpu_loop(CPUARMState *env) env->eabi = 1; /* system call */ if (env->thumb) { - /* FIXME - what to do if get_user() fails? */ - get_user_code_u16(insn, env->regs[15] - 2, env); - n = insn & 0xff; + /* Thumb is always EABI style with syscall number in r7 */ + n = env->regs[7]; } else { + /* + * Equivalent of kernel CONFIG_OABI_COMPAT: read the + * Arm SVC insn to extract the immediate, which is the + * syscall number in OABI. + */ /* FIXME - what to do if get_user() fails? */ get_user_code_u32(insn, env->regs[15] - 4, env); n = insn & 0xffffff; - } - - if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) { - /* linux syscall */ - if (env->thumb || n == 0) { + if (n == 0) { + /* zero immediate: EABI, syscall number in r7 */ n = env->regs[7]; } else { - n -= ARM_SYSCALL_BASE; + /* + * This XOR matches the kernel code: an immediate + * in the valid range (0x900000 .. 0x9fffff) is + * converted into the correct EABI-style syscall + * number; invalid immediates end up as values + * > 0xfffff and are handled below as out-of-range. + */ + n ^= ARM_SYSCALL_BASE; env->eabi = 0; } - if ( n > ARM_NR_BASE) { - switch (n) { - case ARM_NR_cacheflush: - /* nop */ - break; - case ARM_NR_set_tls: - cpu_set_tls(env, env->regs[0]); - env->regs[0] = 0; - break; - case ARM_NR_breakpoint: - env->regs[15] -= env->thumb ? 2 : 4; - goto excp_debug; - case ARM_NR_get_tls: - env->regs[0] = cpu_get_tls(env); - break; - default: - if (n < 0xf0800) { - /* - * Syscalls 0xf0000..0xf07ff (or 0x9f0000.. - * 0x9f07ff in OABI numbering) are defined - * to return -ENOSYS rather than raising - * SIGILL. Note that we have already - * removed the 0x900000 prefix. - */ - qemu_log_mask(LOG_UNIMP, - "qemu: Unsupported ARM syscall: 0x%x\n", - n); - env->regs[0] = -TARGET_ENOSYS; + } + + if (n > ARM_NR_BASE) { + switch (n) { + case ARM_NR_cacheflush: + /* nop */ + break; + case ARM_NR_set_tls: + cpu_set_tls(env, env->regs[0]); + env->regs[0] = 0; + break; + case ARM_NR_breakpoint: + env->regs[15] -= env->thumb ? 2 : 4; + goto excp_debug; + case ARM_NR_get_tls: + env->regs[0] = cpu_get_tls(env); + break; + default: + if (n < 0xf0800) { + /* + * Syscalls 0xf0000..0xf07ff (or 0x9f0000.. + * 0x9f07ff in OABI numbering) are defined + * to return -ENOSYS rather than raising + * SIGILL. Note that we have already + * removed the 0x900000 prefix. + */ + qemu_log_mask(LOG_UNIMP, + "qemu: Unsupported ARM syscall: 0x%x\n", + n); + env->regs[0] = -TARGET_ENOSYS; + } else { + /* + * Otherwise SIGILL. This includes any SWI with + * immediate not originally 0x9fxxxx, because + * of the earlier XOR. + */ + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLTRP; + info._sifields._sigfault._addr = env->regs[15]; + if (env->thumb) { + info._sifields._sigfault._addr -= 2; } else { - /* Otherwise SIGILL */ - info.si_signo = TARGET_SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLTRP; - info._sifields._sigfault._addr = env->regs[15]; - if (env->thumb) { - info._sifields._sigfault._addr -= 2; - } else { - info._sifields._sigfault._addr -= 4; - } - queue_signal(env, info.si_signo, - QEMU_SI_FAULT, &info); + info._sifields._sigfault._addr -= 4; } - break; - } - } else { - ret = do_syscall(env, - n, - env->regs[0], - env->regs[1], - env->regs[2], - env->regs[3], - env->regs[4], - env->regs[5], - 0, 0); - if (ret == -TARGET_ERESTARTSYS) { - env->regs[15] -= env->thumb ? 2 : 4; - } else if (ret != -TARGET_QEMU_ESIGRETURN) { - env->regs[0] = ret; + queue_signal(env, info.si_signo, + QEMU_SI_FAULT, &info); } + break; } } else { - goto error; + ret = do_syscall(env, + n, + env->regs[0], + env->regs[1], + env->regs[2], + env->regs[3], + env->regs[4], + env->regs[5], + 0, 0); + if (ret == -TARGET_ERESTARTSYS) { + env->regs[15] -= env->thumb ? 2 : 4; + } else if (ret != -TARGET_QEMU_ESIGRETURN) { + env->regs[0] = ret; + } } } break; From ef81aa68a708ba5162e1d5fa8d98171ac1059e2d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 May 2020 15:20:47 +0100 Subject: [PATCH 0620/2595] target/arm: Remove unused GEN_NEON_INTEGER_OP macro The GEN_NEON_INTEGER_OP macro is no longer used; remove it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/translate.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 4c9bb8b5ac..c8296116d4 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3034,29 +3034,6 @@ static inline void gen_neon_rsb(int size, TCGv_i32 t0, TCGv_i32 t1) default: return 1; \ }} while (0) -#define GEN_NEON_INTEGER_OP(name) do { \ - switch ((size << 1) | u) { \ - case 0: \ - gen_helper_neon_##name##_s8(tmp, tmp, tmp2); \ - break; \ - case 1: \ - gen_helper_neon_##name##_u8(tmp, tmp, tmp2); \ - break; \ - case 2: \ - gen_helper_neon_##name##_s16(tmp, tmp, tmp2); \ - break; \ - case 3: \ - gen_helper_neon_##name##_u16(tmp, tmp, tmp2); \ - break; \ - case 4: \ - gen_helper_neon_##name##_s32(tmp, tmp, tmp2); \ - break; \ - case 5: \ - gen_helper_neon_##name##_u32(tmp, tmp, tmp2); \ - break; \ - default: return 1; \ - }} while (0) - static TCGv_i32 neon_load_scratch(int scratch) { TCGv_i32 tmp = tcg_temp_new_i32(); From 37f95959c730ff29f58c85b7a98f0b825933bee1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 17 May 2020 09:21:28 -0700 Subject: [PATCH 0621/2595] hw: Move i.MX watchdog driver to hw/watchdog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for a full implementation, move i.MX watchdog driver from hw/misc to hw/watchdog. While at it, add the watchdog files to MAINTAINERS. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Guenter Roeck Message-id: 20200517162135.110364-2-linux@roeck-us.net Signed-off-by: Peter Maydell --- MAINTAINERS | 2 ++ hw/arm/Kconfig | 3 +++ hw/misc/Makefile.objs | 1 - hw/watchdog/Kconfig | 3 +++ hw/watchdog/Makefile.objs | 1 + hw/{misc/imx2_wdt.c => watchdog/wdt_imx2.c} | 2 +- include/hw/arm/fsl-imx6.h | 2 +- include/hw/arm/fsl-imx6ul.h | 2 +- include/hw/arm/fsl-imx7.h | 2 +- include/hw/{misc/imx2_wdt.h => watchdog/wdt_imx2.h} | 0 10 files changed, 13 insertions(+), 5 deletions(-) rename hw/{misc/imx2_wdt.c => watchdog/wdt_imx2.c} (98%) rename include/hw/{misc/imx2_wdt.h => watchdog/wdt_imx2.h} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 023f48d3ea..3690f313c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -633,8 +633,10 @@ S: Odd Fixes F: hw/arm/fsl-imx25.c F: hw/arm/imx25_pdk.c F: hw/misc/imx25_ccm.c +F: hw/watchdog/wdt_imx2.c F: include/hw/arm/fsl-imx25.h F: include/hw/misc/imx25_ccm.h +F: include/hw/watchdog/wdt_imx2.h i.MX31 (kzm) M: Peter Chubb diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 5364172537..3d05dc8538 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -375,6 +375,7 @@ config FSL_IMX6 select IMX_FEC select IMX_I2C select IMX_USBPHY + select WDT_IMX2 select SDHCI config ASPEED_SOC @@ -412,6 +413,7 @@ config FSL_IMX7 select IMX select IMX_FEC select IMX_I2C + select WDT_IMX2 select PCI_EXPRESS_DESIGNWARE select SDHCI select UNIMP @@ -425,6 +427,7 @@ config FSL_IMX6UL select IMX select IMX_FEC select IMX_I2C + select WDT_IMX2 select SDHCI select UNIMP diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 68aae2eabb..b25181b711 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -44,7 +44,6 @@ common-obj-$(CONFIG_IMX) += imx6_ccm.o common-obj-$(CONFIG_IMX) += imx6ul_ccm.o obj-$(CONFIG_IMX) += imx6_src.o common-obj-$(CONFIG_IMX) += imx7_ccm.o -common-obj-$(CONFIG_IMX) += imx2_wdt.o common-obj-$(CONFIG_IMX) += imx7_snvs.o common-obj-$(CONFIG_IMX) += imx7_gpr.o common-obj-$(CONFIG_IMX) += imx_rngc.o diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig index 2118d897c9..293209b291 100644 --- a/hw/watchdog/Kconfig +++ b/hw/watchdog/Kconfig @@ -14,3 +14,6 @@ config WDT_IB700 config WDT_DIAG288 bool + +config WDT_IMX2 + bool diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs index 3f536d1cad..631b711d86 100644 --- a/hw/watchdog/Makefile.objs +++ b/hw/watchdog/Makefile.objs @@ -4,3 +4,4 @@ common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o common-obj-$(CONFIG_ASPEED_SOC) += wdt_aspeed.o +common-obj-$(CONFIG_WDT_IMX2) += wdt_imx2.o diff --git a/hw/misc/imx2_wdt.c b/hw/watchdog/wdt_imx2.c similarity index 98% rename from hw/misc/imx2_wdt.c rename to hw/watchdog/wdt_imx2.c index 2aedfe803a..ad1ef02e9e 100644 --- a/hw/misc/imx2_wdt.c +++ b/hw/watchdog/wdt_imx2.c @@ -14,7 +14,7 @@ #include "qemu/module.h" #include "sysemu/watchdog.h" -#include "hw/misc/imx2_wdt.h" +#include "hw/watchdog/wdt_imx2.h" #define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */ #define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */ diff --git a/include/hw/arm/fsl-imx6.h b/include/hw/arm/fsl-imx6.h index 973bcb72f7..1ebd751324 100644 --- a/include/hw/arm/fsl-imx6.h +++ b/include/hw/arm/fsl-imx6.h @@ -21,7 +21,7 @@ #include "hw/cpu/a9mpcore.h" #include "hw/misc/imx6_ccm.h" #include "hw/misc/imx6_src.h" -#include "hw/misc/imx2_wdt.h" +#include "hw/watchdog/wdt_imx2.h" #include "hw/char/imx_serial.h" #include "hw/timer/imx_gpt.h" #include "hw/timer/imx_epit.h" diff --git a/include/hw/arm/fsl-imx6ul.h b/include/hw/arm/fsl-imx6ul.h index 1a0bab8daa..37c89cc5f9 100644 --- a/include/hw/arm/fsl-imx6ul.h +++ b/include/hw/arm/fsl-imx6ul.h @@ -24,7 +24,7 @@ #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx7_gpr.h" #include "hw/intc/imx_gpcv2.h" -#include "hw/misc/imx2_wdt.h" +#include "hw/watchdog/wdt_imx2.h" #include "hw/gpio/imx_gpio.h" #include "hw/char/imx_serial.h" #include "hw/timer/imx_gpt.h" diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index 706aef2e7e..3a0041c4c2 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -26,7 +26,7 @@ #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx7_gpr.h" #include "hw/misc/imx6_src.h" -#include "hw/misc/imx2_wdt.h" +#include "hw/watchdog/wdt_imx2.h" #include "hw/gpio/imx_gpio.h" #include "hw/char/imx_serial.h" #include "hw/timer/imx_gpt.h" diff --git a/include/hw/misc/imx2_wdt.h b/include/hw/watchdog/wdt_imx2.h similarity index 100% rename from include/hw/misc/imx2_wdt.h rename to include/hw/watchdog/wdt_imx2.h From daca13d495a11945c22d2aa68ad28dc5c8180911 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 17 May 2020 09:21:29 -0700 Subject: [PATCH 0622/2595] hw/watchdog: Implement full i.MX watchdog support Implement full support for the watchdog in i.MX systems. Pretimeout support is optional because the watchdog hardware on i.MX31 does not support pretimeouts. Signed-off-by: Guenter Roeck Message-id: 20200517162135.110364-3-linux@roeck-us.net Signed-off-by: Peter Maydell [PMM: added Property array terminator entry] Reviewed-by: Peter Maydell --- hw/watchdog/wdt_imx2.c | 240 +++++++++++++++++++++++++++++++-- include/hw/watchdog/wdt_imx2.h | 61 ++++++++- 2 files changed, 286 insertions(+), 15 deletions(-) diff --git a/hw/watchdog/wdt_imx2.c b/hw/watchdog/wdt_imx2.c index ad1ef02e9e..a5fb76308f 100644 --- a/hw/watchdog/wdt_imx2.c +++ b/hw/watchdog/wdt_imx2.c @@ -13,24 +13,189 @@ #include "qemu/bitops.h" #include "qemu/module.h" #include "sysemu/watchdog.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" #include "hw/watchdog/wdt_imx2.h" -#define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */ -#define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */ - -static uint64_t imx2_wdt_read(void *opaque, hwaddr addr, - unsigned int size) +static void imx2_wdt_interrupt(void *opaque) { + IMX2WdtState *s = IMX2_WDT(opaque); + + s->wicr |= IMX2_WDT_WICR_WTIS; + qemu_set_irq(s->irq, 1); +} + +static void imx2_wdt_expired(void *opaque) +{ + IMX2WdtState *s = IMX2_WDT(opaque); + + s->wrsr = IMX2_WDT_WRSR_TOUT; + + /* Perform watchdog action if watchdog is enabled */ + if (s->wcr & IMX2_WDT_WCR_WDE) { + s->wrsr = IMX2_WDT_WRSR_TOUT; + watchdog_perform_action(); + } +} + +static void imx2_wdt_reset(DeviceState *dev) +{ + IMX2WdtState *s = IMX2_WDT(dev); + + ptimer_transaction_begin(s->timer); + ptimer_stop(s->timer); + ptimer_transaction_commit(s->timer); + + if (s->pretimeout_support) { + ptimer_transaction_begin(s->itimer); + ptimer_stop(s->itimer); + ptimer_transaction_commit(s->itimer); + } + + s->wicr_locked = false; + s->wcr_locked = false; + s->wcr_wde_locked = false; + + s->wcr = IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS; + s->wsr = 0; + s->wrsr &= ~(IMX2_WDT_WRSR_TOUT | IMX2_WDT_WRSR_SFTW); + s->wicr = IMX2_WDT_WICR_WICT_DEF; + s->wmcr = IMX2_WDT_WMCR_PDE; +} + +static uint64_t imx2_wdt_read(void *opaque, hwaddr addr, unsigned int size) +{ + IMX2WdtState *s = IMX2_WDT(opaque); + + switch (addr) { + case IMX2_WDT_WCR: + return s->wcr; + case IMX2_WDT_WSR: + return s->wsr; + case IMX2_WDT_WRSR: + return s->wrsr; + case IMX2_WDT_WICR: + return s->wicr; + case IMX2_WDT_WMCR: + return s->wmcr; + } return 0; } +static void imx_wdt2_update_itimer(IMX2WdtState *s, bool start) +{ + bool running = (s->wcr & IMX2_WDT_WCR_WDE) && (s->wcr & IMX2_WDT_WCR_WT); + bool enabled = s->wicr & IMX2_WDT_WICR_WIE; + + ptimer_transaction_begin(s->itimer); + if (start || !enabled) { + ptimer_stop(s->itimer); + } + if (running && enabled) { + int count = ptimer_get_count(s->timer); + int pretimeout = s->wicr & IMX2_WDT_WICR_WICT; + + /* + * Only (re-)start pretimeout timer if its counter value is larger + * than 0. Otherwise it will fire right away and we'll get an + * interrupt loop. + */ + if (count > pretimeout) { + ptimer_set_count(s->itimer, count - pretimeout); + if (start) { + ptimer_run(s->itimer, 1); + } + } + } + ptimer_transaction_commit(s->itimer); +} + +static void imx_wdt2_update_timer(IMX2WdtState *s, bool start) +{ + ptimer_transaction_begin(s->timer); + if (start) { + ptimer_stop(s->timer); + } + if ((s->wcr & IMX2_WDT_WCR_WDE) && (s->wcr & IMX2_WDT_WCR_WT)) { + int count = (s->wcr & IMX2_WDT_WCR_WT) >> 8; + + /* A value of 0 reflects one period (0.5s). */ + ptimer_set_count(s->timer, count + 1); + if (start) { + ptimer_run(s->timer, 1); + } + } + ptimer_transaction_commit(s->timer); + if (s->pretimeout_support) { + imx_wdt2_update_itimer(s, start); + } +} + static void imx2_wdt_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size) { - if (addr == IMX2_WDT_WCR && - (~value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS))) { - watchdog_perform_action(); + IMX2WdtState *s = IMX2_WDT(opaque); + + switch (addr) { + case IMX2_WDT_WCR: + if (s->wcr_locked) { + value &= ~IMX2_WDT_WCR_LOCK_MASK; + value |= (s->wicr & IMX2_WDT_WCR_LOCK_MASK); + } + s->wcr_locked = true; + if (s->wcr_wde_locked) { + value &= ~IMX2_WDT_WCR_WDE; + value |= (s->wicr & ~IMX2_WDT_WCR_WDE); + } else if (value & IMX2_WDT_WCR_WDE) { + s->wcr_wde_locked = true; + } + if (s->wcr_wdt_locked) { + value &= ~IMX2_WDT_WCR_WDT; + value |= (s->wicr & ~IMX2_WDT_WCR_WDT); + } else if (value & IMX2_WDT_WCR_WDT) { + s->wcr_wdt_locked = true; + } + + s->wcr = value; + if (!(value & IMX2_WDT_WCR_SRS)) { + s->wrsr = IMX2_WDT_WRSR_SFTW; + } + if (!(value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS)) || + (!(value & IMX2_WDT_WCR_WT) && (value & IMX2_WDT_WCR_WDE))) { + watchdog_perform_action(); + } + s->wcr |= IMX2_WDT_WCR_SRS; + imx_wdt2_update_timer(s, true); + break; + case IMX2_WDT_WSR: + if (s->wsr == IMX2_WDT_SEQ1 && value == IMX2_WDT_SEQ2) { + imx_wdt2_update_timer(s, false); + } + s->wsr = value; + break; + case IMX2_WDT_WRSR: + break; + case IMX2_WDT_WICR: + if (!s->pretimeout_support) { + return; + } + value &= IMX2_WDT_WICR_LOCK_MASK | IMX2_WDT_WICR_WTIS; + if (s->wicr_locked) { + value &= IMX2_WDT_WICR_WTIS; + value |= (s->wicr & IMX2_WDT_WICR_LOCK_MASK); + } + s->wicr = value | (s->wicr & IMX2_WDT_WICR_WTIS); + if (value & IMX2_WDT_WICR_WTIS) { + s->wicr &= ~IMX2_WDT_WICR_WTIS; + qemu_set_irq(s->irq, 0); + } + imx_wdt2_update_itimer(s, true); + s->wicr_locked = true; + break; + case IMX2_WDT_WMCR: + s->wmcr = value & IMX2_WDT_WMCR_PDE; + break; } } @@ -45,28 +210,77 @@ static const MemoryRegionOps imx2_wdt_ops = { * real device but in practice there is no reason for a guest * to access this device unaligned. */ - .min_access_size = 4, - .max_access_size = 4, + .min_access_size = 2, + .max_access_size = 2, .unaligned = false, }, }; +static const VMStateDescription vmstate_imx2_wdt = { + .name = "imx2.wdt", + .fields = (VMStateField[]) { + VMSTATE_PTIMER(timer, IMX2WdtState), + VMSTATE_PTIMER(itimer, IMX2WdtState), + VMSTATE_BOOL(wicr_locked, IMX2WdtState), + VMSTATE_BOOL(wcr_locked, IMX2WdtState), + VMSTATE_BOOL(wcr_wde_locked, IMX2WdtState), + VMSTATE_BOOL(wcr_wdt_locked, IMX2WdtState), + VMSTATE_UINT16(wcr, IMX2WdtState), + VMSTATE_UINT16(wsr, IMX2WdtState), + VMSTATE_UINT16(wrsr, IMX2WdtState), + VMSTATE_UINT16(wmcr, IMX2WdtState), + VMSTATE_UINT16(wicr, IMX2WdtState), + VMSTATE_END_OF_LIST() + } +}; + static void imx2_wdt_realize(DeviceState *dev, Error **errp) { IMX2WdtState *s = IMX2_WDT(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); memory_region_init_io(&s->mmio, OBJECT(dev), &imx2_wdt_ops, s, - TYPE_IMX2_WDT".mmio", - IMX2_WDT_REG_NUM * sizeof(uint16_t)); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); + TYPE_IMX2_WDT, + IMX2_WDT_MMIO_SIZE); + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_irq(sbd, &s->irq); + + s->timer = ptimer_init(imx2_wdt_expired, s, + PTIMER_POLICY_NO_IMMEDIATE_TRIGGER | + PTIMER_POLICY_NO_IMMEDIATE_RELOAD | + PTIMER_POLICY_NO_COUNTER_ROUND_DOWN); + ptimer_transaction_begin(s->timer); + ptimer_set_freq(s->timer, 2); + ptimer_set_limit(s->timer, 0xff, 1); + ptimer_transaction_commit(s->timer); + if (s->pretimeout_support) { + s->itimer = ptimer_init(imx2_wdt_interrupt, s, + PTIMER_POLICY_NO_IMMEDIATE_TRIGGER | + PTIMER_POLICY_NO_IMMEDIATE_RELOAD | + PTIMER_POLICY_NO_COUNTER_ROUND_DOWN); + ptimer_transaction_begin(s->itimer); + ptimer_set_freq(s->itimer, 2); + ptimer_set_limit(s->itimer, 0xff, 1); + ptimer_transaction_commit(s->itimer); + } } +static Property imx2_wdt_properties[] = { + DEFINE_PROP_BOOL("pretimeout-support", IMX2WdtState, pretimeout_support, + false), + DEFINE_PROP_END_OF_LIST() +}; + static void imx2_wdt_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + device_class_set_props(dc, imx2_wdt_properties); dc->realize = imx2_wdt_realize; + dc->reset = imx2_wdt_reset; + dc->vmsd = &vmstate_imx2_wdt; + dc->desc = "i.MX watchdog timer"; set_bit(DEVICE_CATEGORY_MISC, dc->categories); } diff --git a/include/hw/watchdog/wdt_imx2.h b/include/hw/watchdog/wdt_imx2.h index b91b002528..f9af6be4b6 100644 --- a/include/hw/watchdog/wdt_imx2.h +++ b/include/hw/watchdog/wdt_imx2.h @@ -12,22 +12,79 @@ #ifndef IMX2_WDT_H #define IMX2_WDT_H +#include "qemu/bitops.h" #include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/ptimer.h" #define TYPE_IMX2_WDT "imx2.wdt" #define IMX2_WDT(obj) OBJECT_CHECK(IMX2WdtState, (obj), TYPE_IMX2_WDT) enum IMX2WdtRegisters { - IMX2_WDT_WCR = 0x0000, - IMX2_WDT_REG_NUM = 0x0008 / sizeof(uint16_t) + 1, + IMX2_WDT_WCR = 0x0000, /* Control Register */ + IMX2_WDT_WSR = 0x0002, /* Service Register */ + IMX2_WDT_WRSR = 0x0004, /* Reset Status Register */ + IMX2_WDT_WICR = 0x0006, /* Interrupt Control Register */ + IMX2_WDT_WMCR = 0x0008, /* Misc Register */ }; +#define IMX2_WDT_MMIO_SIZE 0x000a + +/* Control Register definitions */ +#define IMX2_WDT_WCR_WT (0xFF << 8) /* Watchdog Timeout Field */ +#define IMX2_WDT_WCR_WDW BIT(7) /* WDOG Disable for Wait */ +#define IMX2_WDT_WCR_WDA BIT(5) /* WDOG Assertion */ +#define IMX2_WDT_WCR_SRS BIT(4) /* Software Reset Signal */ +#define IMX2_WDT_WCR_WDT BIT(3) /* WDOG Timeout Assertion */ +#define IMX2_WDT_WCR_WDE BIT(2) /* Watchdog Enable */ +#define IMX2_WDT_WCR_WDBG BIT(1) /* Watchdog Debug Enable */ +#define IMX2_WDT_WCR_WDZST BIT(0) /* Watchdog Timer Suspend */ + +#define IMX2_WDT_WCR_LOCK_MASK (IMX2_WDT_WCR_WDZST | IMX2_WDT_WCR_WDBG \ + | IMX2_WDT_WCR_WDW) + +/* Service Register definitions */ +#define IMX2_WDT_SEQ1 0x5555 /* service sequence 1 */ +#define IMX2_WDT_SEQ2 0xAAAA /* service sequence 2 */ + +/* Reset Status Register definitions */ +#define IMX2_WDT_WRSR_TOUT BIT(1) /* Reset due to Timeout */ +#define IMX2_WDT_WRSR_SFTW BIT(0) /* Reset due to software reset */ + +/* Interrupt Control Register definitions */ +#define IMX2_WDT_WICR_WIE BIT(15) /* Interrupt Enable */ +#define IMX2_WDT_WICR_WTIS BIT(14) /* Interrupt Status */ +#define IMX2_WDT_WICR_WICT 0xff /* Interrupt Timeout */ +#define IMX2_WDT_WICR_WICT_DEF 0x04 /* Default interrupt timeout (2s) */ + +#define IMX2_WDT_WICR_LOCK_MASK (IMX2_WDT_WICR_WIE | IMX2_WDT_WICR_WICT) + +/* Misc Control Register definitions */ +#define IMX2_WDT_WMCR_PDE BIT(0) /* Power-Down Enable */ typedef struct IMX2WdtState { /* */ SysBusDevice parent_obj; + /*< public >*/ MemoryRegion mmio; + qemu_irq irq; + + struct ptimer_state *timer; + struct ptimer_state *itimer; + + bool pretimeout_support; + bool wicr_locked; + + uint16_t wcr; + uint16_t wsr; + uint16_t wrsr; + uint16_t wicr; + uint16_t wmcr; + + bool wcr_locked; /* affects WDZST, WDBG, and WDW */ + bool wcr_wde_locked; /* affects WDE */ + bool wcr_wdt_locked; /* affects WDT (never cleared) */ } IMX2WdtState; #endif /* IMX2_WDT_H */ From e70626551ac64446b15350574d9422af2e0cff9d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 May 2020 20:17:20 +0100 Subject: [PATCH 0623/2595] Update OpenBIOS images to 4704d9eb built from submodule. Signed-off-by: Mark Cave-Ayland --- pc-bios/openbios-ppc | Bin 696912 -> 696912 bytes pc-bios/openbios-sparc32 | Bin 382048 -> 382048 bytes pc-bios/openbios-sparc64 | Bin 1593408 -> 1593408 bytes roms/openbios | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc index 1c9ab09af72daa1e382a95334e90a1d255d2a9bd..5da9363bff64e21ab61ecf70d571855a3714843f 100644 GIT binary patch delta 30420 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%0AHRNBfD{F;zwar+rBC$+R< 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 U_TNsbrOMO(@i=Z9Py09iADXC!7ytkO delta 15017 zcma)@0a#l_w#V;;P*MstP)I@x?M*^UTBxL@ZqpV^T+mYOYTQ<36<-5Xi!IuyXwjlc zDOyz4Mg|*vqNbEp)@3zMSjk$}MwV4pQ7K$3s^bBhl&N^ zIh!D$ox@DV@hglWFNS{HjK13COe=ywH6!3E47{KgXQM(s%HwCs!4~iwj#q&bI5vY5 zInDvk<=6zi;2b+$X_*kH&k0;Q@|-4tHG%pCxA5^tH9bBc49rOwe0;uV(CIKQN#k0t=_$0j!VHm<+ub~$nh3%5yv+0r5tYpU&e7UcmqNIGX@kvP|PV~ z)!=J5P5@uau?l=$c>S3W1}GsY;S>b$FV3^}EckkkL*N@Yo&uM0JPE#$;|cJ8a6Arn zZsi1H5ZE~mg3CA_1($O?0FsTOx}f_5l4IQD{X=eQMo2gfboJ2`F!S99zJ-^Fnw z_->9HoDl5h1ohw=j$Pn;IIacX%W(~O569KuT8p8Z8AK-Ws_`&n+)D}aq|GYq31a9Ei3Vw*=eDK2@TfmQSyb9dN zu^IeJj&s0|o@1v=Yl7gwIe|-?33hWVf*<2J9o)pR4oo>t0XK8320zYm0{Gwz3GmZVX6L_V9D-*!g)y*~;~@AD z$D`mjjz_?UIUWYLb1Z>>#ql8c*$9Wvf6V{{&v6R<;0}%h;9qmx3x1wsKlnEscY`}Q z_JM!PaVPkNFh|aRO$P)oatiHWAIDzse{tLjeu?82a2LnT;BJoH;NNlF2!5Gyc|n{MS@MaFkQn1`cp+2fxN~ zDY%d067U~6-U9CD*arR+$D6>fbLYRN7=kxAg(C0($5!y4InD>a$*~3e7RRf=gB+W| zZ*!ajeuq2%H6{q&rP1@1N(?v)~gPhrl0jJOv)*coO^}#}i=ZN1R|Bf|DGNfrA_e!5?!x3O>d02>3L| z!{9NFCGaO453=+BQ%*1dg}-s!4<6?@0RB72z2MI{_Jcp?xEnmdu@C$O$DQo_|B@4Q zK;a)8w}U4+_JY6SxE1_0$1UJ*IBo_{aqI^FljBBq{-5Cl4d8D%t_O!Wc7gxJaV_{e zj%&c*b6gER%drFe1II~K5KMD|O1eo+$ub&LXD$73MZwg~Nl1AG|EzH*>j$jD!nT(* z_P{*G8vRI9vYp9}Q*)Bm`8KGZX+zQs?QuK@_Kpj}Q>Tx5*Az@utwWhxYj8o{$XX7! zqAd%dUN2;SV7;*V=)nr!=T0`LW_kku4tjn(?_+Ju)CIo?d3REQGu-jrsHEd6b)e7( zCC85{wL#t)HTD+N5xF`~qO2ooXgLh$4Q)qTlno?W_j=Sdh3n3V%!d~Wk5F5(*7*RM zX-!&RAUkFG0e7nk7fPI>xkjLsP8oEe?*IqKy^ z>%D}|iy`}zj-?pM5voefc0TvmxS(SD3U$LF-zr#kuw4v(CsOumrBx^jpFhp;siwH2 z0(dR@5m>v7(Qb`ZP$~ksN0lh6KpA;OEvS&MMt)Y4TF7{OnW$#^&~32_G2cGE(yMko z=d=@pOPGZj6eC8)d<6x+*(I<}Zd#3Li77bK@CrJ!3X9iEW;;4s5k4CFW_{d^P7h0h z-4V%K_Deb|mTW3EY*?~Ah`~OO_9i23XFQ6{qvFbYt*eEMHVDm8g$I$x(w%F-jRyV` zGDo!he&icqST?QHWILyab#@CIU!?mYb5Lhj#S~20>(q7uV^;aq0_j&<1y`F@vC>8E zekIOMewAxitiU|9D_t3AJH&8f{cZS=W@J?XXAu04KB$#M_73YYt$;_C~2!UYx#*` zq1+4SzJp0IFR_t%DSYRYV6S2G;YEsc5py%0)Mk^P&~)8~i#MW7>uML0VWx@A2mFjQ z#l0$9g~Geg4#qsS9Z&SM@FAEIiY+*^FET8}MbxXycD}5KMx^ERE-ZK?UZfZ>_vxQt z2V~;;TMQsQs>7Tj65Jy?qtFrIX#38H6|L-P6%tBAV)+!yuR)T;a!hJr4Xg-HsKO
  • Tools Guide
  • System Emulation Management and Interoperability Guide
  • System Emulation Guest Hardware Specifications
  • -
  • QMP Reference Manual
  • -
  • Guest Agent Protocol Reference
  • +
  • QMP Reference Manual
  • +
  • Guest Agent Protocol Reference
  • From b00de3a51fc8e86d1678c57e65d57aa9ed052422 Mon Sep 17 00:00:00 2001 From: Anthony PERARD Date: Fri, 19 Jun 2020 11:31:15 +0100 Subject: [PATCH 1696/2595] xen: Actually fix build without passthrough Fix typo. Fixes: acd0c9416d48 ("xen: fix build without pci passthrough") Signed-off-by: Anthony PERARD Message-Id: <20200619103115.254127-1-anthony.perard@citrix.com> Signed-off-by: Paolo Bonzini --- hw/xen/Makefile.objs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index 3fc715e595..502b32d877 100644 --- a/hw/xen/Makefile.objs +++ b/hw/xen/Makefile.objs @@ -4,4 +4,4 @@ common-obj-y += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-bus.o xen-b obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt_load_rom.o -obj-$(call $(lnot, $(CONFIG_XEN_PCI_PASSTHROUGH))) += xen_pt_stub.o +obj-$(call lnot,$(CONFIG_XEN_PCI_PASSTHROUGH)) += xen_pt_stub.o From eca30647fc078f4d9ed1b455bd67960f99dbeb7a Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 11 Jun 2020 23:45:48 +0000 Subject: [PATCH 1697/2595] target/i386: reimplement f2xm1 using floatx80 operations The x87 f2xm1 emulation is currently based around conversion to double. This is inherently unsuitable for a good emulation of any floatx80 operation, even before considering that it is a particularly naive implementation using double (computing with pow and then subtracting 1 rather than attempting a better emulation using expm1). Reimplement using the soft-float operations, including additions and multiplications with higher precision where appropriate to limit accumulation of errors. I considered reusing some of the m68k code for transcendental operations, but the instructions don't generally correspond exactly to x87 operations (for example, m68k has 2^x and e^x - 1, but not 2^x - 1); to avoid possible accumulation of errors from applying multiple such operations each rounding to floatx80 precision, I wrote a direct implementation of 2^x - 1 instead. It would be possible in principle to make the implementation more efficient by doing the intermediate operations directly with significands, signs and exponents and not packing / unpacking floatx80 format for each operation, but that would make it significantly more complicated and it's not clear that's worthwhile; the m68k emulation doesn't try to do that. A test is included with many randomly generated inputs. The assumption of the test is that the result in round-to-nearest mode should always be one of the two closest floating-point numbers to the mathematical value of 2^x - 1; the implementation aims to do somewhat better than that (about 70 correct bits before rounding). I haven't investigated how accurate hardware is. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 385 +++++++++- tests/tcg/i386/test-i386-f2xm1.c | 1140 ++++++++++++++++++++++++++++++ 2 files changed, 1522 insertions(+), 3 deletions(-) create mode 100644 tests/tcg/i386/test-i386-f2xm1.c diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 8ef5b463ea..e32a2aa74b 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -25,6 +25,7 @@ #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "fpu/softfloat.h" +#include "fpu/softfloat-macros.h" #ifdef CONFIG_SOFTMMU #include "hw/irq.h" @@ -836,12 +837,390 @@ void helper_fbst_ST0(CPUX86State *env, target_ulong ptr) merge_exception_flags(env, old_flags); } +/* 128-bit significand of log(2). */ +#define ln2_sig_high 0xb17217f7d1cf79abULL +#define ln2_sig_low 0xc9e3b39803f2f6afULL + +/* + * Polynomial coefficients for an approximation to (2^x - 1) / x, on + * the interval [-1/64, 1/64]. + */ +#define f2xm1_coeff_0 make_floatx80(0x3ffe, 0xb17217f7d1cf79acULL) +#define f2xm1_coeff_0_low make_floatx80(0xbfbc, 0xd87edabf495b3762ULL) +#define f2xm1_coeff_1 make_floatx80(0x3ffc, 0xf5fdeffc162c7543ULL) +#define f2xm1_coeff_2 make_floatx80(0x3ffa, 0xe35846b82505fcc7ULL) +#define f2xm1_coeff_3 make_floatx80(0x3ff8, 0x9d955b7dd273b899ULL) +#define f2xm1_coeff_4 make_floatx80(0x3ff5, 0xaec3ff3c4ef4ac0cULL) +#define f2xm1_coeff_5 make_floatx80(0x3ff2, 0xa184897c3a7f0de9ULL) +#define f2xm1_coeff_6 make_floatx80(0x3fee, 0xffe634d0ec30d504ULL) +#define f2xm1_coeff_7 make_floatx80(0x3feb, 0xb160111d2db515e4ULL) + +struct f2xm1_data { + /* + * A value very close to a multiple of 1/32, such that 2^t and 2^t - 1 + * are very close to exact floatx80 values. + */ + floatx80 t; + /* The value of 2^t. */ + floatx80 exp2; + /* The value of 2^t - 1. */ + floatx80 exp2m1; +}; + +static const struct f2xm1_data f2xm1_table[65] = { + { make_floatx80(0xbfff, 0x8000000000000000ULL), + make_floatx80(0x3ffe, 0x8000000000000000ULL), + make_floatx80(0xbffe, 0x8000000000000000ULL) }, + { make_floatx80(0xbffe, 0xf800000000002e7eULL), + make_floatx80(0x3ffe, 0x82cd8698ac2b9160ULL), + make_floatx80(0xbffd, 0xfa64f2cea7a8dd40ULL) }, + { make_floatx80(0xbffe, 0xefffffffffffe960ULL), + make_floatx80(0x3ffe, 0x85aac367cc488345ULL), + make_floatx80(0xbffd, 0xf4aa7930676ef976ULL) }, + { make_floatx80(0xbffe, 0xe800000000006f10ULL), + make_floatx80(0x3ffe, 0x88980e8092da5c14ULL), + make_floatx80(0xbffd, 0xeecfe2feda4b47d8ULL) }, + { make_floatx80(0xbffe, 0xe000000000008a45ULL), + make_floatx80(0x3ffe, 0x8b95c1e3ea8ba2a5ULL), + make_floatx80(0xbffd, 0xe8d47c382ae8bab6ULL) }, + { make_floatx80(0xbffe, 0xd7ffffffffff8a9eULL), + make_floatx80(0x3ffe, 0x8ea4398b45cd8116ULL), + make_floatx80(0xbffd, 0xe2b78ce97464fdd4ULL) }, + { make_floatx80(0xbffe, 0xd0000000000019a0ULL), + make_floatx80(0x3ffe, 0x91c3d373ab11b919ULL), + make_floatx80(0xbffd, 0xdc785918a9dc8dceULL) }, + { make_floatx80(0xbffe, 0xc7ffffffffff14dfULL), + make_floatx80(0x3ffe, 0x94f4efa8fef76836ULL), + make_floatx80(0xbffd, 0xd61620ae02112f94ULL) }, + { make_floatx80(0xbffe, 0xc000000000006530ULL), + make_floatx80(0x3ffe, 0x9837f0518db87fbbULL), + make_floatx80(0xbffd, 0xcf901f5ce48f008aULL) }, + { make_floatx80(0xbffe, 0xb7ffffffffff1723ULL), + make_floatx80(0x3ffe, 0x9b8d39b9d54eb74cULL), + make_floatx80(0xbffd, 0xc8e58c8c55629168ULL) }, + { make_floatx80(0xbffe, 0xb00000000000b5e1ULL), + make_floatx80(0x3ffe, 0x9ef5326091a0c366ULL), + make_floatx80(0xbffd, 0xc2159b3edcbe7934ULL) }, + { make_floatx80(0xbffe, 0xa800000000006f8aULL), + make_floatx80(0x3ffe, 0xa27043030c49370aULL), + make_floatx80(0xbffd, 0xbb1f79f9e76d91ecULL) }, + { make_floatx80(0xbffe, 0x9fffffffffff816aULL), + make_floatx80(0x3ffe, 0xa5fed6a9b15171cfULL), + make_floatx80(0xbffd, 0xb40252ac9d5d1c62ULL) }, + { make_floatx80(0xbffe, 0x97ffffffffffb621ULL), + make_floatx80(0x3ffe, 0xa9a15ab4ea7c30e6ULL), + make_floatx80(0xbffd, 0xacbd4a962b079e34ULL) }, + { make_floatx80(0xbffe, 0x8fffffffffff162bULL), + make_floatx80(0x3ffe, 0xad583eea42a1b886ULL), + make_floatx80(0xbffd, 0xa54f822b7abc8ef4ULL) }, + { make_floatx80(0xbffe, 0x87ffffffffff4d34ULL), + make_floatx80(0x3ffe, 0xb123f581d2ac7b51ULL), + make_floatx80(0xbffd, 0x9db814fc5aa7095eULL) }, + { make_floatx80(0xbffe, 0x800000000000227dULL), + make_floatx80(0x3ffe, 0xb504f333f9de539dULL), + make_floatx80(0xbffd, 0x95f619980c4358c6ULL) }, + { make_floatx80(0xbffd, 0xefffffffffff3978ULL), + make_floatx80(0x3ffe, 0xb8fbaf4762fbd0a1ULL), + make_floatx80(0xbffd, 0x8e08a1713a085ebeULL) }, + { make_floatx80(0xbffd, 0xe00000000000df81ULL), + make_floatx80(0x3ffe, 0xbd08a39f580bfd8cULL), + make_floatx80(0xbffd, 0x85eeb8c14fe804e8ULL) }, + { make_floatx80(0xbffd, 0xd00000000000bccfULL), + make_floatx80(0x3ffe, 0xc12c4cca667062f6ULL), + make_floatx80(0xbffc, 0xfb4eccd6663e7428ULL) }, + { make_floatx80(0xbffd, 0xc00000000000eff0ULL), + make_floatx80(0x3ffe, 0xc5672a1155069abeULL), + make_floatx80(0xbffc, 0xea6357baabe59508ULL) }, + { make_floatx80(0xbffd, 0xb000000000000fe6ULL), + make_floatx80(0x3ffe, 0xc9b9bd866e2f234bULL), + make_floatx80(0xbffc, 0xd91909e6474372d4ULL) }, + { make_floatx80(0xbffd, 0x9fffffffffff2172ULL), + make_floatx80(0x3ffe, 0xce248c151f84bf00ULL), + make_floatx80(0xbffc, 0xc76dcfab81ed0400ULL) }, + { make_floatx80(0xbffd, 0x8fffffffffffafffULL), + make_floatx80(0x3ffe, 0xd2a81d91f12afb2bULL), + make_floatx80(0xbffc, 0xb55f89b83b541354ULL) }, + { make_floatx80(0xbffc, 0xffffffffffff81a3ULL), + make_floatx80(0x3ffe, 0xd744fccad69d7d5eULL), + make_floatx80(0xbffc, 0xa2ec0cd4a58a0a88ULL) }, + { make_floatx80(0xbffc, 0xdfffffffffff1568ULL), + make_floatx80(0x3ffe, 0xdbfbb797daf25a44ULL), + make_floatx80(0xbffc, 0x901121a0943696f0ULL) }, + { make_floatx80(0xbffc, 0xbfffffffffff68daULL), + make_floatx80(0x3ffe, 0xe0ccdeec2a94f811ULL), + make_floatx80(0xbffb, 0xf999089eab583f78ULL) }, + { make_floatx80(0xbffc, 0x9fffffffffff4690ULL), + make_floatx80(0x3ffe, 0xe5b906e77c83657eULL), + make_floatx80(0xbffb, 0xd237c8c41be4d410ULL) }, + { make_floatx80(0xbffb, 0xffffffffffff8aeeULL), + make_floatx80(0x3ffe, 0xeac0c6e7dd24427cULL), + make_floatx80(0xbffb, 0xa9f9c8c116ddec20ULL) }, + { make_floatx80(0xbffb, 0xbfffffffffff2d18ULL), + make_floatx80(0x3ffe, 0xefe4b99bdcdb06ebULL), + make_floatx80(0xbffb, 0x80da33211927c8a8ULL) }, + { make_floatx80(0xbffa, 0xffffffffffff8ccbULL), + make_floatx80(0x3ffe, 0xf5257d152486d0f4ULL), + make_floatx80(0xbffa, 0xada82eadb792f0c0ULL) }, + { make_floatx80(0xbff9, 0xffffffffffff11feULL), + make_floatx80(0x3ffe, 0xfa83b2db722a0846ULL), + make_floatx80(0xbff9, 0xaf89a491babef740ULL) }, + { floatx80_zero, + make_floatx80(0x3fff, 0x8000000000000000ULL), + floatx80_zero }, + { make_floatx80(0x3ff9, 0xffffffffffff2680ULL), + make_floatx80(0x3fff, 0x82cd8698ac2b9f6fULL), + make_floatx80(0x3ff9, 0xb361a62b0ae7dbc0ULL) }, + { make_floatx80(0x3ffb, 0x800000000000b500ULL), + make_floatx80(0x3fff, 0x85aac367cc488345ULL), + make_floatx80(0x3ffa, 0xb5586cf9891068a0ULL) }, + { make_floatx80(0x3ffb, 0xbfffffffffff4b67ULL), + make_floatx80(0x3fff, 0x88980e8092da7cceULL), + make_floatx80(0x3ffb, 0x8980e8092da7cce0ULL) }, + { make_floatx80(0x3ffb, 0xffffffffffffff57ULL), + make_floatx80(0x3fff, 0x8b95c1e3ea8bd6dfULL), + make_floatx80(0x3ffb, 0xb95c1e3ea8bd6df0ULL) }, + { make_floatx80(0x3ffc, 0x9fffffffffff811fULL), + make_floatx80(0x3fff, 0x8ea4398b45cd4780ULL), + make_floatx80(0x3ffb, 0xea4398b45cd47800ULL) }, + { make_floatx80(0x3ffc, 0xbfffffffffff9980ULL), + make_floatx80(0x3fff, 0x91c3d373ab11b919ULL), + make_floatx80(0x3ffc, 0x8e1e9b9d588dc8c8ULL) }, + { make_floatx80(0x3ffc, 0xdffffffffffff631ULL), + make_floatx80(0x3fff, 0x94f4efa8fef70864ULL), + make_floatx80(0x3ffc, 0xa7a77d47f7b84320ULL) }, + { make_floatx80(0x3ffc, 0xffffffffffff2499ULL), + make_floatx80(0x3fff, 0x9837f0518db892d4ULL), + make_floatx80(0x3ffc, 0xc1bf828c6dc496a0ULL) }, + { make_floatx80(0x3ffd, 0x8fffffffffff80fbULL), + make_floatx80(0x3fff, 0x9b8d39b9d54e3a79ULL), + make_floatx80(0x3ffc, 0xdc69cdceaa71d3c8ULL) }, + { make_floatx80(0x3ffd, 0x9fffffffffffbc23ULL), + make_floatx80(0x3fff, 0x9ef5326091a10313ULL), + make_floatx80(0x3ffc, 0xf7a993048d081898ULL) }, + { make_floatx80(0x3ffd, 0xafffffffffff20ecULL), + make_floatx80(0x3fff, 0xa27043030c49370aULL), + make_floatx80(0x3ffd, 0x89c10c0c3124dc28ULL) }, + { make_floatx80(0x3ffd, 0xc00000000000fd2cULL), + make_floatx80(0x3fff, 0xa5fed6a9b15171cfULL), + make_floatx80(0x3ffd, 0x97fb5aa6c545c73cULL) }, + { make_floatx80(0x3ffd, 0xd0000000000093beULL), + make_floatx80(0x3fff, 0xa9a15ab4ea7c30e6ULL), + make_floatx80(0x3ffd, 0xa6856ad3a9f0c398ULL) }, + { make_floatx80(0x3ffd, 0xe00000000000c2aeULL), + make_floatx80(0x3fff, 0xad583eea42a17876ULL), + make_floatx80(0x3ffd, 0xb560fba90a85e1d8ULL) }, + { make_floatx80(0x3ffd, 0xefffffffffff1e3fULL), + make_floatx80(0x3fff, 0xb123f581d2abef6cULL), + make_floatx80(0x3ffd, 0xc48fd6074aafbdb0ULL) }, + { make_floatx80(0x3ffd, 0xffffffffffff1c23ULL), + make_floatx80(0x3fff, 0xb504f333f9de2cadULL), + make_floatx80(0x3ffd, 0xd413cccfe778b2b4ULL) }, + { make_floatx80(0x3ffe, 0x8800000000006344ULL), + make_floatx80(0x3fff, 0xb8fbaf4762fbd0a1ULL), + make_floatx80(0x3ffd, 0xe3eebd1d8bef4284ULL) }, + { make_floatx80(0x3ffe, 0x9000000000005d67ULL), + make_floatx80(0x3fff, 0xbd08a39f580c668dULL), + make_floatx80(0x3ffd, 0xf4228e7d60319a34ULL) }, + { make_floatx80(0x3ffe, 0x9800000000009127ULL), + make_floatx80(0x3fff, 0xc12c4cca6670e042ULL), + make_floatx80(0x3ffe, 0x82589994cce1c084ULL) }, + { make_floatx80(0x3ffe, 0x9fffffffffff06f9ULL), + make_floatx80(0x3fff, 0xc5672a11550655c3ULL), + make_floatx80(0x3ffe, 0x8ace5422aa0cab86ULL) }, + { make_floatx80(0x3ffe, 0xa7fffffffffff80dULL), + make_floatx80(0x3fff, 0xc9b9bd866e2f234bULL), + make_floatx80(0x3ffe, 0x93737b0cdc5e4696ULL) }, + { make_floatx80(0x3ffe, 0xafffffffffff1470ULL), + make_floatx80(0x3fff, 0xce248c151f83fd69ULL), + make_floatx80(0x3ffe, 0x9c49182a3f07fad2ULL) }, + { make_floatx80(0x3ffe, 0xb800000000000e0aULL), + make_floatx80(0x3fff, 0xd2a81d91f12aec5cULL), + make_floatx80(0x3ffe, 0xa5503b23e255d8b8ULL) }, + { make_floatx80(0x3ffe, 0xc00000000000b7faULL), + make_floatx80(0x3fff, 0xd744fccad69dd630ULL), + make_floatx80(0x3ffe, 0xae89f995ad3bac60ULL) }, + { make_floatx80(0x3ffe, 0xc800000000003aa6ULL), + make_floatx80(0x3fff, 0xdbfbb797daf25a44ULL), + make_floatx80(0x3ffe, 0xb7f76f2fb5e4b488ULL) }, + { make_floatx80(0x3ffe, 0xd00000000000a6aeULL), + make_floatx80(0x3fff, 0xe0ccdeec2a954685ULL), + make_floatx80(0x3ffe, 0xc199bdd8552a8d0aULL) }, + { make_floatx80(0x3ffe, 0xd800000000004165ULL), + make_floatx80(0x3fff, 0xe5b906e77c837155ULL), + make_floatx80(0x3ffe, 0xcb720dcef906e2aaULL) }, + { make_floatx80(0x3ffe, 0xe00000000000582cULL), + make_floatx80(0x3fff, 0xeac0c6e7dd24713aULL), + make_floatx80(0x3ffe, 0xd5818dcfba48e274ULL) }, + { make_floatx80(0x3ffe, 0xe800000000001a5dULL), + make_floatx80(0x3fff, 0xefe4b99bdcdb06ebULL), + make_floatx80(0x3ffe, 0xdfc97337b9b60dd6ULL) }, + { make_floatx80(0x3ffe, 0xefffffffffffc1efULL), + make_floatx80(0x3fff, 0xf5257d152486a2faULL), + make_floatx80(0x3ffe, 0xea4afa2a490d45f4ULL) }, + { make_floatx80(0x3ffe, 0xf800000000001069ULL), + make_floatx80(0x3fff, 0xfa83b2db722a0e5cULL), + make_floatx80(0x3ffe, 0xf50765b6e4541cb8ULL) }, + { make_floatx80(0x3fff, 0x8000000000000000ULL), + make_floatx80(0x4000, 0x8000000000000000ULL), + make_floatx80(0x3fff, 0x8000000000000000ULL) }, +}; + void helper_f2xm1(CPUX86State *env) { - double val = floatx80_to_double(env, ST0); + uint8_t old_flags = save_exception_flags(env); + uint64_t sig = extractFloatx80Frac(ST0); + int32_t exp = extractFloatx80Exp(ST0); + bool sign = extractFloatx80Sign(ST0); - val = pow(2.0, val) - 1.0; - ST0 = double_to_floatx80(env, val); + if (floatx80_invalid_encoding(ST0)) { + float_raise(float_flag_invalid, &env->fp_status); + ST0 = floatx80_default_nan(&env->fp_status); + } else if (floatx80_is_any_nan(ST0)) { + if (floatx80_is_signaling_nan(ST0, &env->fp_status)) { + float_raise(float_flag_invalid, &env->fp_status); + ST0 = floatx80_silence_nan(ST0, &env->fp_status); + } + } else if (exp > 0x3fff || + (exp == 0x3fff && sig != (0x8000000000000000ULL))) { + /* Out of range for the instruction, treat as invalid. */ + float_raise(float_flag_invalid, &env->fp_status); + ST0 = floatx80_default_nan(&env->fp_status); + } else if (exp == 0x3fff) { + /* Argument 1 or -1, exact result 1 or -0.5. */ + if (sign) { + ST0 = make_floatx80(0xbffe, 0x8000000000000000ULL); + } + } else if (exp < 0x3fb0) { + if (!floatx80_is_zero(ST0)) { + /* + * Multiplying the argument by an extra-precision version + * of log(2) is sufficiently precise. Zero arguments are + * returned unchanged. + */ + uint64_t sig0, sig1, sig2; + if (exp == 0) { + normalizeFloatx80Subnormal(sig, &exp, &sig); + } + mul128By64To192(ln2_sig_high, ln2_sig_low, sig, &sig0, &sig1, + &sig2); + /* This result is inexact. */ + sig1 |= 1; + ST0 = normalizeRoundAndPackFloatx80(80, sign, exp, sig0, sig1, + &env->fp_status); + } + } else { + floatx80 tmp, y, accum; + bool asign, bsign; + int32_t n, aexp, bexp; + uint64_t asig0, asig1, asig2, bsig0, bsig1; + FloatRoundMode save_mode = env->fp_status.float_rounding_mode; + signed char save_prec = env->fp_status.floatx80_rounding_precision; + env->fp_status.float_rounding_mode = float_round_nearest_even; + env->fp_status.floatx80_rounding_precision = 80; + + /* Find the nearest multiple of 1/32 to the argument. */ + tmp = floatx80_scalbn(ST0, 5, &env->fp_status); + n = 32 + floatx80_to_int32(tmp, &env->fp_status); + y = floatx80_sub(ST0, f2xm1_table[n].t, &env->fp_status); + + if (floatx80_is_zero(y)) { + /* + * Use the value of 2^t - 1 from the table, to avoid + * needing to special-case zero as a result of + * multiplication below. + */ + ST0 = f2xm1_table[n].t; + set_float_exception_flags(float_flag_inexact, &env->fp_status); + env->fp_status.float_rounding_mode = save_mode; + } else { + /* + * Compute the lower parts of a polynomial expansion for + * (2^y - 1) / y. + */ + accum = floatx80_mul(f2xm1_coeff_7, y, &env->fp_status); + accum = floatx80_add(f2xm1_coeff_6, accum, &env->fp_status); + accum = floatx80_mul(accum, y, &env->fp_status); + accum = floatx80_add(f2xm1_coeff_5, accum, &env->fp_status); + accum = floatx80_mul(accum, y, &env->fp_status); + accum = floatx80_add(f2xm1_coeff_4, accum, &env->fp_status); + accum = floatx80_mul(accum, y, &env->fp_status); + accum = floatx80_add(f2xm1_coeff_3, accum, &env->fp_status); + accum = floatx80_mul(accum, y, &env->fp_status); + accum = floatx80_add(f2xm1_coeff_2, accum, &env->fp_status); + accum = floatx80_mul(accum, y, &env->fp_status); + accum = floatx80_add(f2xm1_coeff_1, accum, &env->fp_status); + accum = floatx80_mul(accum, y, &env->fp_status); + accum = floatx80_add(f2xm1_coeff_0_low, accum, &env->fp_status); + + /* + * The full polynomial expansion is f2xm1_coeff_0 + accum + * (where accum has much lower magnitude, and so, in + * particular, carry out of the addition is not possible). + * (This expansion is only accurate to about 70 bits, not + * 128 bits.) + */ + aexp = extractFloatx80Exp(f2xm1_coeff_0); + asign = extractFloatx80Sign(f2xm1_coeff_0); + shift128RightJamming(extractFloatx80Frac(accum), 0, + aexp - extractFloatx80Exp(accum), + &asig0, &asig1); + bsig0 = extractFloatx80Frac(f2xm1_coeff_0); + bsig1 = 0; + if (asign == extractFloatx80Sign(accum)) { + add128(bsig0, bsig1, asig0, asig1, &asig0, &asig1); + } else { + sub128(bsig0, bsig1, asig0, asig1, &asig0, &asig1); + } + /* And thus compute an approximation to 2^y - 1. */ + mul128By64To192(asig0, asig1, extractFloatx80Frac(y), + &asig0, &asig1, &asig2); + aexp += extractFloatx80Exp(y) - 0x3ffe; + asign ^= extractFloatx80Sign(y); + if (n != 32) { + /* + * Multiply this by the precomputed value of 2^t and + * add that of 2^t - 1. + */ + mul128By64To192(asig0, asig1, + extractFloatx80Frac(f2xm1_table[n].exp2), + &asig0, &asig1, &asig2); + aexp += extractFloatx80Exp(f2xm1_table[n].exp2) - 0x3ffe; + bexp = extractFloatx80Exp(f2xm1_table[n].exp2m1); + bsig0 = extractFloatx80Frac(f2xm1_table[n].exp2m1); + bsig1 = 0; + if (bexp < aexp) { + shift128RightJamming(bsig0, bsig1, aexp - bexp, + &bsig0, &bsig1); + } else if (aexp < bexp) { + shift128RightJamming(asig0, asig1, bexp - aexp, + &asig0, &asig1); + aexp = bexp; + } + /* The sign of 2^t - 1 is always that of the result. */ + bsign = extractFloatx80Sign(f2xm1_table[n].exp2m1); + if (asign == bsign) { + /* Avoid possible carry out of the addition. */ + shift128RightJamming(asig0, asig1, 1, + &asig0, &asig1); + shift128RightJamming(bsig0, bsig1, 1, + &bsig0, &bsig1); + ++aexp; + add128(asig0, asig1, bsig0, bsig1, &asig0, &asig1); + } else { + sub128(bsig0, bsig1, asig0, asig1, &asig0, &asig1); + asign = bsign; + } + } + env->fp_status.float_rounding_mode = save_mode; + /* This result is inexact. */ + asig1 |= 1; + ST0 = normalizeRoundAndPackFloatx80(80, asign, aexp, asig0, asig1, + &env->fp_status); + } + + env->fp_status.floatx80_rounding_precision = save_prec; + } + merge_exception_flags(env, old_flags); } void helper_fyl2x(CPUX86State *env) diff --git a/tests/tcg/i386/test-i386-f2xm1.c b/tests/tcg/i386/test-i386-f2xm1.c new file mode 100644 index 0000000000..4513ed8cc1 --- /dev/null +++ b/tests/tcg/i386/test-i386-f2xm1.c @@ -0,0 +1,1140 @@ +/* Test f2xm1 instruction. */ + +#include + +struct test { + long double arg, down, up; +}; + +const struct test tests[] = { + { -1.0L, -0.5L, -0.5L }, + { -0.0L, -0.0L, -0.0L }, + { 0.0L, 0.0L, 0.0L }, + /* Randomly generated tests. */ + { 0x4.1481697ac693aa6p-4L, 0x3.17ec9f8454896518p-4L, 0x3.17ec9f845489651cp-4L }, + { -0xd.84a873b14b9c0e2p-4L, -0x7.1788c46ac260d948p-4L, -0x7.1788c46ac260d94p-4L }, + { 0xa.a3dc18b1eff7e8ap-188L, 0x7.6009241b9e21523p-188L, 0x7.6009241b9e215238p-188L }, + { -0xe.846aeb6f58174d5p-92L, -0xa.1006405817acc33p-92L, -0xa.1006405817acc32p-92L }, + { 0x5.4459f2ac77bb0978p-4L, 0x4.19d3ce7fd5b90ac8p-4L, 0x4.19d3ce7fd5b90adp-4L }, + { -0xb.79bece734a62216p-4L, -0x6.4489a7fc150c0fp-4L, -0x6.4489a7fc150c0ef8p-4L }, + { 0xa.ab48f9ef732f5c4p-4L, 0x9.66acd7d4b7cf015p-4L, 0x9.66acd7d4b7cf016p-4L }, + { -0xb.8204e63359a46e6p-4L, -0x6.48060f0a504e3488p-4L, -0x6.48060f0a504e348p-4L }, + { 0xd.c732865701ae935p-4L, 0xd.103bc1a15cd9f71p-4L, 0xd.103bc1a15cd9f72p-4L }, + { -0x1.6296e8ff499827a2p-4L, -0xe.e8dc973f0bce9d1p-8L, -0xe.e8dc973f0bce9dp-8L }, + { 0x8.3e49377820195c8p-4L, 0x6.ddff7e8caa601a08p-4L, 0x6.ddff7e8caa601a1p-4L }, + { -0x7.ece8699d62a9f76p-4L, -0x4.a6516088a15ab01p-4L, -0x4.a6516088a15ab008p-4L }, + { 0x4.b875c0342c9f86b8p-4L, 0x3.a1709cfaecf11ce8p-4L, 0x3.a1709cfaecf11cecp-4L }, + { -0xe.a37e0fa859e499cp-4L, -0x7.83956f7028853738p-4L, -0x7.83956f702885373p-4L }, + { 0x7.23210d9474f0715p-4L, 0x5.cc1ac556913b5258p-4L, 0x5.cc1ac556913b526p-4L }, + { -0xb.755e74862e61e2bp-4L, -0x6.42b11ec6fd4c00dp-4L, -0x6.42b11ec6fd4c00c8p-4L }, + { 0x3.48cc248e266ab90cp-4L, 0x2.724bd1b7f02d354cp-4L, 0x2.724bd1b7f02d355p-4L }, + { -0xa.9a331b76f8ece94p-4L, -0x5.e47b32e80b1f837p-4L, -0x5.e47b32e80b1f8368p-4L }, + { 0x5.8312ebb25c93d22p-4L, 0x4.50bcc3442a6e832p-4L, 0x4.50bcc3442a6e8328p-4L }, + { -0xa.d41581f0036d233p-4L, -0x5.fdb41cec4e2c108p-4L, -0x5.fdb41cec4e2c1078p-4L }, + { 0x4.84a87d8107c5f408p-4L, 0x3.759419ac694e8798p-4L, 0x3.759419ac694e879cp-4L }, + { -0x1.1a592590e007fap-4L, -0xb.f1b5fdf338edbc1p-8L, -0xb.f1b5fdf338edbcp-8L }, + { 0x2.72f96b27827d2054p-4L, 0x1.ca7a491c0c9ae094p-4L, 0x1.ca7a491c0c9ae096p-4L }, + { -0x8.34634eae18e60c5p-4L, -0x4.c941052638a95e6p-4L, -0x4.c941052638a95e58p-4L }, + { 0x2.f6cff94cffe53048p-180L, 0x2.0df7fb06812da41p-180L, 0x2.0df7fb06812da414p-180L }, + { -0x3.e0779bd58963da5p-120L, -0x2.afed04ed88e2c16cp-120L, -0x2.afed04ed88e2c168p-120L }, + { 0xc.1c72a98f7733051p-4L, 0xb.09ddaf3c3330ff9p-4L, 0xb.09ddaf3c3330ffap-4L }, + { -0x9.6eacf3012c77e7p-4L, -0x5.5df25bc91430e81p-4L, -0x5.5df25bc91430e808p-4L }, + { 0x4.962ce97c4afbc1f8p-4L, 0x3.845e1e9659d35364p-4L, 0x3.845e1e9659d35368p-4L }, + { -0xa.a7735b993f17f55p-4L, -0x5.ea46e99ae5f6dce8p-4L, -0x5.ea46e99ae5f6dcep-4L }, + { 0x5.155f76560f08fccp-4L, 0x3.f1149b22956dff34p-4L, 0x3.f1149b22956dff38p-4L }, + { -0xd.32a453289bd47b3p-4L, -0x6.f7a99ad68a5d961p-4L, -0x6.f7a99ad68a5d9608p-4L }, + { 0xa.9942e7418052b4bp-4L, 0x9.52df2bbafc3218bp-4L, 0x9.52df2bbafc3218cp-4L }, + { -0x5.4f4efad2aff4f76p-4L, -0x3.49afb77e7a12385p-4L, -0x3.49afb77e7a12384cp-4L }, + { 0x3.c9e289d962998608p-4L, 0x2.da96d228ab6c8fd8p-4L, 0x2.da96d228ab6c8fdcp-4L }, + { -0x7.cc295689678770bp-4L, -0x4.962bd983de0367b8p-4L, -0x4.962bd983de0367bp-4L }, + { 0xa.8fc7c1f2a46626cp-4L, 0x9.487a90c858224c9p-4L, 0x9.487a90c858224cap-4L }, + { -0x8.a1d9201d5f09ad6p-4L, -0x4.fdf0ccee86f8d98p-4L, -0x4.fdf0ccee86f8d978p-4L }, + { 0x7.5b8ee6778ad1d64p-4L, 0x6.01a5419abf1cb4f8p-4L, 0x6.01a5419abf1cb5p-4L }, + { -0x9.d20d0f7fc98548p-4L, -0x5.8b571e52bd288448p-4L, -0x5.8b571e52bd28844p-4L }, + { 0x5.f135e81ee2608d4p-4L, 0x4.b293c42ca99fd6e8p-4L, 0x4.b293c42ca99fd6fp-4L }, + { -0x5.d981a42b6b7a36fp-4L, -0x3.94e920725edbe7d4p-4L, -0x3.94e920725edbe7dp-4L }, + { 0xa.edffe301db8be0bp-4L, 0x9.b08144d0a85602p-4L, 0x9.b08144d0a856021p-4L }, + { -0x4.5a026d37f55f1d18p-4L, -0x2.bfc10df32554a28cp-4L, -0x2.bfc10df32554a288p-4L }, + { 0x7.82c193b48128193p-4L, 0x6.2723ac59ee5faf68p-4L, 0x6.2723ac59ee5faf7p-4L }, + { -0xd.2d0fe1cd05a87f4p-4L, -0x6.f57a61e00a5f24bp-4L, -0x6.f57a61e00a5f24a8p-4L }, + { 0x5.e1494f95151c64fp-196L, 0x4.13628f9a498f05d8p-196L, 0x4.13628f9a498f05ep-196L }, + { -0x4.51babb72810e518p-140L, -0x2.fe6ee847d0741a5cp-140L, -0x2.fe6ee847d0741a58p-140L }, + { 0xb.638d8454a685474p-4L, 0xa.34a429815e10dc1p-4L, 0xa.34a429815e10dc2p-4L }, + { -0xb.9ec4e9f266dce49p-4L, -0x6.54194f84395ed2b8p-4L, -0x6.54194f84395ed2bp-4L }, + { 0xe.4b7a4c83290855cp-4L, 0xd.b8a9a282646fa0cp-4L, 0xd.b8a9a282646fa0dp-4L }, + { -0xf.13ec97b6c4f17a7p-4L, -0x7.ac86ac65cc0a8878p-4L, -0x7.ac86ac65cc0a887p-4L }, + { 0x3.8ded178a72c15bcp-4L, 0x2.a9dd11713298de98p-4L, 0x2.a9dd11713298de9cp-4L }, + { -0xd.36a9965916287d1p-4L, -0x6.f93c3981d5369078p-4L, -0x6.f93c3981d536907p-4L }, + { 0x6.b3a10f94dcd70e1p-4L, 0x5.63cd831188f697c8p-4L, 0x5.63cd831188f697dp-4L }, + { -0xc.8517674f15bbcbfp-4L, -0x6.b2be7a8ee34bfc8p-4L, -0x6.b2be7a8ee34bfc78p-4L }, + { 0xb.204e5335e697f73p-4L, 0x9.e8bb034ff53dc6p-4L, 0x9.e8bb034ff53dc61p-4L }, + { -0x8.913a951884085ddp-4L, -0x4.f60101f7884f4f6p-4L, -0x4.f60101f7884f4f58p-4L }, + { 0x4.5861903e9a2c5178p-4L, 0x3.50645bac48af734cp-4L, 0x3.50645bac48af735p-4L }, + { -0x5.24585590086993p-4L, -0x3.31f08d8ca7e0c6e4p-4L, -0x3.31f08d8ca7e0c6ep-4L }, + { 0xf.2ba8f23d35f13f9p-4L, 0xe.dedc34179a9e3acp-4L, 0xe.dedc34179a9e3adp-4L }, + { -0xa.3ecdb386b33fbe5p-4L, -0x5.bc2672b634fa598p-4L, -0x5.bc2672b634fa5978p-4L }, + { 0x9.9b8e544f05c6de4p-8L, 0x6.bf33cd9ab91f6d28p-8L, 0x6.bf33cd9ab91f6d3p-8L }, + { -0x7.abd5585035c4696p-4L, -0x4.862497557f052a6p-4L, -0x4.862497557f052a58p-4L }, + { 0xa.e654e5ca1c1d1fbp-4L, 0x9.a7fa0d5fa5d62cbp-4L, 0x9.a7fa0d5fa5d62ccp-4L }, + { -0x7.8b963b5c9698ae88p-8L, -0x5.2d4a519ba339886p-8L, -0x5.2d4a519ba3398858p-8L }, + { 0xb.ea47beace8589dep-4L, 0xa.cf59bd897bb1319p-4L, 0xa.cf59bd897bb131ap-4L }, + { -0x3.8f66d5a2d60e1fc8p-4L, -0x2.496dee34a71055ap-4L, -0x2.496dee34a710559cp-4L }, + { 0x3.1a53eaa26d0157p-188L, 0x2.269608f745c0b83p-188L, 0x2.269608f745c0b834p-188L }, + { -0x8.6659e1a891ccbd3p-96L, -0x5.d282825fc03c7ca8p-96L, -0x5.d282825fc03c7cap-96L }, + { 0x9.4ae3410622cd598p-4L, 0x7.ee3a22f81622643p-4L, 0x7.ee3a22f816226438p-4L }, + { -0x9.b8fe7ab721fb04cp-4L, -0x5.7ff768a6654000e8p-4L, -0x5.7ff768a6654000ep-4L }, + { 0x4.ee554b54200eeb18p-4L, 0x3.cf77028b579146a8p-4L, 0x3.cf77028b579146acp-4L }, + { -0x1.e1d0727b5f12c23cp-8L, -0x1.4d1e625247cef1dap-8L, -0x1.4d1e625247cef1d8p-8L }, + { 0x8.f3637cea7b9b0b8p-4L, 0x7.942f15c8b77d89c8p-4L, 0x7.942f15c8b77d89dp-4L }, + { -0x2.f3202c602060bd7cp-4L, -0x1.eb59cec0fd5e5b22p-4L, -0x1.eb59cec0fd5e5b2p-4L }, + { 0xc.cdb9d9e3a3a5b61p-4L, 0xb.dcaaf5c009c0684p-4L, 0xb.dcaaf5c009c0685p-4L }, + { -0x5.7ddc79efb147e828p-4L, -0x3.63390bf8b99265d4p-4L, -0x3.63390bf8b99265dp-4L }, + { 0x6.7236b6f8976437ap-4L, 0x5.27852c069a4fd5ep-4L, 0x5.27852c069a4fd5e8p-4L }, + { -0x5.e1ad137b44bc3ad8p-4L, -0x3.994d814216774764p-4L, -0x3.994d81421677476p-4L }, + { 0xb.f5ec1a26fcc9d7ep-4L, 0xa.dce2b2a69a74106p-4L, 0xa.dce2b2a69a74107p-4L }, + { -0xd.dcb826624975b1ep-4L, -0x7.394429db03b0d5e8p-4L, -0x7.394429db03b0d5ep-4L }, + { 0x1.a983e64980e6104p-4L, 0x1.31d2cb35db04030ep-4L, 0x1.31d2cb35db04031p-4L }, + { -0xa.14ebef82079ff92p-4L, -0x5.a9758de717320278p-4L, -0x5.a9758de71732027p-4L }, + { 0x1.e4fcc97f32b404d8p-4L, 0x1.5e5913e4b0dadd5ep-4L, 0x1.5e5913e4b0dadd6p-4L }, + { -0xe.9391126d81ddf25p-4L, -0x7.7db899379b97afep-4L, -0x7.7db899379b97afd8p-4L }, + { 0xb.83be497f42b1776p-8L, 0x8.1b67845064d833ap-8L, 0x8.1b67845064d833bp-8L }, + { -0xb.6c13349b9671c7bp-4L, -0x6.3ec4737bebffb8f8p-4L, -0x6.3ec4737bebffb8fp-4L }, + { 0xd.00d476fab7a907dp-4L, 0xc.1a9e868d759da06p-4L, 0xc.1a9e868d759da07p-4L }, + { -0x3.bf394566ed3e5a44p-4L, -0x2.65b989f46e7a2458p-4L, -0x2.65b989f46e7a2454p-4L }, + { 0x7.4a72aacaec9cd52p-52L, 0x5.0db91de577a1e5c8p-52L, 0x5.0db91de577a1e5dp-52L }, + { -0x4.3354d8429f36037p-24L, -0x2.e95ce5bede67faap-24L, -0x2.e95ce5bede67fa9cp-24L }, + { 0x5.431e650334b97d18p-4L, 0x4.18c10ccaa716c258p-4L, 0x4.18c10ccaa716c26p-4L }, + { -0xf.1eb2c535e06fba3p-4L, -0x7.b068a3edafc6822p-4L, -0x7.b068a3edafc68218p-4L }, + { 0x8.54a857fb1034b62p-4L, 0x6.f433cc318f296fep-4L, 0x6.f433cc318f296fe8p-4L }, + { -0xa.d3c15d582c446d9p-4L, -0x5.fd8fa08a9be23ac8p-4L, -0x5.fd8fa08a9be23acp-4L }, + { 0xc.cb73edcbfcb307fp-4L, 0xb.d9ecb2c64e8df6bp-4L, 0xb.d9ecb2c64e8df6cp-4L }, + { -0x3.fb61f1b2cf35f60cp-4L, -0x2.88fef3c7864d396cp-4L, -0x2.88fef3c7864d3968p-4L }, + { 0x9.d7eb5c50bc8c632p-4L, 0x8.8231f68c5c65f6cp-4L, 0x8.8231f68c5c65f6dp-4L }, + { -0x4.d312891f5f4e786p-4L, -0x3.048b329391356fc8p-4L, -0x3.048b329391356fc4p-4L }, + { 0xe.ae0633b99b178edp-4L, 0xe.389ce9e10301401p-4L, 0xe.389ce9e10301402p-4L }, + { -0x1.39568b7ef55672cp-4L, -0xd.38818f18029f0edp-8L, -0xd.38818f18029f0ecp-8L }, + { 0x4.cf293b1353f539bp-4L, 0x3.b4c86315977b5c7cp-4L, 0x3.b4c86315977b5c8p-4L }, + { -0xd.2b8a9e00126538ap-4L, -0x6.f4e1e5a5bc2731ap-4L, -0x6.f4e1e5a5bc273198p-4L }, + { 0x5.b5eb2a3dcc35826p-8L, 0x3.fd3309c0a1b58598p-8L, 0x3.fd3309c0a1b5859cp-8L }, + { -0xa.db19f19a7ea88bep-4L, -0x6.00be987018657798p-4L, -0x6.00be98701865779p-4L }, + { 0x1.09017c7c80c2c48ap-4L, 0xb.bde7d981fb53b8ep-8L, 0xb.bde7d981fb53b8fp-8L }, + { -0x2.5ae089add9bdff18p-4L, -0x1.8d45d20a5f7c4556p-4L, -0x1.8d45d20a5f7c4554p-4L }, + { 0x6.d211b21df46dcc18p-4L, 0x5.801525b9519ab1cp-4L, 0x5.801525b9519ab1c8p-4L }, + { -0xd.1a64a16c7c8f6d7p-4L, -0x6.ee27813a5adc48a8p-4L, -0x6.ee27813a5adc48ap-4L }, + { 0xc.1ef9ffac1d2c793p-4L, 0xb.0cd41b95ab8f726p-4L, 0xb.0cd41b95ab8f727p-4L }, + { -0x1.67c59b4c06bd7496p-4L, -0xf.1ef71ffc4b3edp-8L, -0xf.1ef71ffc4b3ecffp-8L }, + { 0x8.ba4b4feae22142bp-168L, 0x6.0cb1d8faa6f42ce8p-168L, 0x6.0cb1d8faa6f42cfp-168L }, + { -0x4.d89f7b5a88882dbp-32L, -0x3.5bef2f703124413p-32L, -0x3.5bef2f703124412cp-32L }, + { 0xb.03fa4c349a339d2p-4L, 0x9.c902a02a0215ad1p-4L, 0x9.c902a02a0215ad2p-4L }, + { -0x1.e57ddc8153f3ba8p-8L, -0x1.4fa797d98bce1f74p-8L, -0x1.4fa797d98bce1f72p-8L }, + { 0xc.9c281b57f7d11c8p-4L, 0xb.a11623dd20659ecp-4L, 0xb.a11623dd20659edp-4L }, + { -0x6.8fac6e3f60b61e1p-4L, -0x3.f56b115363b7d2d8p-4L, -0x3.f56b115363b7d2d4p-4L }, + { 0x3.65bed5b32d99326p-4L, 0x2.897c78eee4adc054p-4L, 0x2.897c78eee4adc058p-4L }, + { -0x2.3ef31cc65b2354cp-4L, -0x1.7bc0457bdf14a022p-4L, -0x1.7bc0457bdf14a02p-4L }, + { 0x2.bceec8bc1d31b0ccp-4L, 0x2.03d68f4acad10114p-4L, 0x2.03d68f4acad10118p-4L }, + { -0xd.146217a63673958p-4L, -0x6.ebcaaea4b926a99p-4L, -0x6.ebcaaea4b926a988p-4L }, + { 0x2.17b7fc97b1f46e7cp-4L, 0x1.84af2ad78df6619cp-4L, 0x1.84af2ad78df6619ep-4L }, + { -0x4.49abbcdefc0c959p-4L, -0x2.b65ca46b981930ecp-4L, -0x2.b65ca46b981930e8p-4L }, + { 0x3.efc6f5f489c6c7bcp-4L, 0x2.f9a3671c9c3698fcp-4L, 0x2.f9a3671c9c3699p-4L }, + { -0x8.f7ff40b96f9bd91p-4L, -0x5.26b9d6a96a7c7d4p-4L, -0x5.26b9d6a96a7c7d38p-4L }, + { 0x6.003126d0e9a9acc8p-4L, 0x4.c0070418e60c3eap-4L, 0x4.c0070418e60c3ea8p-4L }, + { -0x5.7be9edcc9dc2a02p-4L, -0x3.6228999b34cd56c8p-4L, -0x3.6228999b34cd56c4p-4L }, + { 0x7.8952a49ff2c2f168p-4L, 0x6.2d71e3ee870f2fp-4L, 0x6.2d71e3ee870f2f08p-4L }, + { -0x3.8a644fc56f9d1fbp-4L, -0x2.4673b0704862205cp-4L, -0x2.4673b07048622058p-4L }, + { 0xf.c1271b0a53a3319p-4L, 0xf.a9563e019f9388ep-4L, 0xf.a9563e019f9388fp-4L }, + { -0x8.a07f742f2a61d18p-4L, -0x4.fd4bef713b1bf35p-4L, -0x4.fd4bef713b1bf348p-4L }, + { 0xf.ce2fc60abd9a47cp-4L, 0xf.bb3bf685a5fb078p-4L, 0xf.bb3bf685a5fb079p-4L }, + { -0x9.e8a3a1c0f885e07p-4L, -0x5.958d6298d2833328p-4L, -0x5.958d6298d283332p-4L }, + { 0xd.11c135742977841p-96L, 0x9.0f19b73e51b46a5p-96L, 0x9.0f19b73e51b46a6p-96L }, + { -0x1.0028929dbde83802p-60L, -0xb.18e376bf8ce7ca1p-64L, -0xb.18e376bf8ce7cap-64L }, + { 0x5.244b484bc9bb7828p-4L, 0x3.fdfcc0ee0ab5b92p-4L, 0x3.fdfcc0ee0ab5b924p-4L }, + { -0x7.02ec4c8b2cc95998p-4L, -0x4.30f4ae1282b41938p-4L, -0x4.30f4ae1282b4193p-4L }, + { 0xa.4d34be63f5bedffp-4L, 0x8.fff7fb1648dba28p-4L, 0x8.fff7fb1648dba29p-4L }, + { -0xf.be786c39b309e8p-4L, -0x7.e929ac0fe4454fbp-4L, -0x7.e929ac0fe4454fa8p-4L }, + { 0x6.16481538d3215558p-4L, 0x4.d3ebea6da53ed4bp-4L, 0x4.d3ebea6da53ed4b8p-4L }, + { -0x8.5ea05eecb9ac14dp-4L, -0x4.ddb34f8925005bf8p-4L, -0x4.ddb34f8925005bfp-4L }, + { 0xd.4be5b4aaf95a52bp-4L, 0xc.7698fe58f5fbc96p-4L, 0xc.7698fe58f5fbc97p-4L }, + { -0x5.505294ddb8af9558p-4L, -0x3.4a3eaba09a1a5584p-4L, -0x3.4a3eaba09a1a558p-4L }, + { 0xf.a2f9540a64c79ap-8L, 0xb.1239629d9548b9ap-8L, 0xb.1239629d9548b9bp-8L }, + { -0x2.b68cfa7df5a80aep-4L, -0x1.c635cc5a0e342052p-4L, -0x1.c635cc5a0e34205p-4L }, + { 0xb.8ac8e4b25441b53p-4L, 0xa.6154102e9f6deb3p-4L, 0xa.6154102e9f6deb4p-4L }, + { -0x2.047a032c2a353b58p-4L, -0x1.56cbb83364a118fcp-4L, -0x1.56cbb83364a118fap-4L }, + { 0x8.eb2ab17c06312d9p-4L, 0x7.8bca95748b755068p-4L, 0x7.8bca95748b75507p-4L }, + { -0xb.932fffb0dfd7537p-4L, -0x6.4f3dd628a0e5cf6p-4L, -0x6.4f3dd628a0e5cf58p-4L }, + { 0x4.e0e6c013f25279bp-4L, 0x3.c3f354fd7de31834p-4L, 0x3.c3f354fd7de31838p-4L }, + { -0xa.7fafcf461e92982p-4L, -0x5.d8d88aa29bb4cebp-4L, -0x5.d8d88aa29bb4cea8p-4L }, + { 0x6.41b8cd66b9392ef8p-4L, 0x4.fb4312effd41adb8p-4L, 0x4.fb4312effd41adcp-4L }, + { -0xf.d372339bf2bef0fp-4L, -0x7.f0801caf476622cp-4L, -0x7.f0801caf476622b8p-4L }, + { 0xf.843d63b0a71eb93p-4L, 0xf.56375011490bccp-4L, 0xf.56375011490bcc1p-4L }, + { -0xe.679784396815117p-4L, -0x7.6d735bc4f5da77p-4L, -0x7.6d735bc4f5da76f8p-4L }, + { 0x2.d7c4bef6577f86p-168L, 0x1.f87361c88ca3f5dcp-168L, 0x1.f87361c88ca3f5dep-168L }, + { -0x3.f871c581e5f5dc24p-128L, -0x2.c08bab62f3684a08p-128L, -0x2.c08bab62f3684a04p-128L }, + { 0x9.f6c4eb5c911111ap-4L, 0x8.a309258b14973d6p-4L, 0x8.a309258b14973d7p-4L }, + { -0xa.08c53e65e98b067p-4L, -0x5.a402f5ec7cf294fp-4L, -0x5.a402f5ec7cf294e8p-4L }, + { 0x4.1a4c613ba5fe16ap-4L, 0x3.1cb7e0a2f57d95e4p-4L, 0x3.1cb7e0a2f57d95e8p-4L }, + { -0xd.36e91d3e54f0432p-4L, -0x6.f95510d133d9ba9p-4L, -0x6.f95510d133d9ba88p-4L }, + { 0xd.1de964de30857a7p-4L, 0xc.3e1d28af4fff2d7p-4L, 0xc.3e1d28af4fff2d8p-4L }, + { -0x8.604a0e63d4f5df1p-4L, -0x4.de809bb2d3dfaec8p-4L, -0x4.de809bb2d3dfaecp-4L }, + { 0xc.6b9d18c70882d52p-4L, 0xb.67389c48f17db3ap-4L, 0xb.67389c48f17db3bp-4L }, + { -0x2.711b4139fbed3dc8p-4L, -0x1.9b290dfa49d31a48p-4L, -0x1.9b290dfa49d31a46p-4L }, + { 0x9.4021cab7a0d78bbp-4L, 0x7.e3162eb6a1bdbe8p-4L, 0x7.e3162eb6a1bdbe88p-4L }, + { -0x8.305eb92b4243ea2p-4L, -0x4.c74d292fe63f0918p-4L, -0x4.c74d292fe63f091p-4L }, + { 0x4.f0330cdb93893948p-4L, 0x3.d111183eddd7d2p-4L, 0x3.d111183eddd7d204p-4L }, + { -0xe.be93c7764505ff9p-8L, -0xa.04ccfff3805ed0dp-8L, -0xa.04ccfff3805ed0cp-8L }, + { 0xd.ea533ffe043e52bp-4L, 0xd.3c980125a65c5dfp-4L, 0xd.3c980125a65c5ep-4L }, + { -0x1.1dd2693fe11489c2p-4L, -0xc.166d57fe9c4abe2p-8L, -0xc.166d57fe9c4abe1p-8L }, + { 0x2.0397d0e9676f1b2p-4L, 0x1.756fb86ebc62a682p-4L, 0x1.756fb86ebc62a684p-4L }, + { -0xa.9002b4ad763bb7cp-4L, -0x5.e0041011e34ae53p-4L, -0x5.e0041011e34ae528p-4L }, + { 0x3.34a5a4894a28659cp-4L, 0x2.623883e4934c92d8p-4L, 0x2.623883e4934c92dcp-4L }, + { -0xd.c27cd78e0864371p-4L, -0x7.2f454c780b622d58p-4L, -0x7.2f454c780b622d5p-4L }, + { 0x9.c7f27c2034ec1cfp-4L, 0x8.714272ce09a4f87p-4L, 0x8.714272ce09a4f88p-4L }, + { -0xa.a9e0aa658eda7dcp-4L, -0x5.eb564d46b128566p-4L, -0x5.eb564d46b1285658p-4L }, + { 0xa.0183ad6b5f24f24p-148L, 0x6.ef81a75cf4925d9p-148L, 0x6.ef81a75cf4925d98p-148L }, + { -0x2.0bdfa7925a4bf4ap-28L, -0x1.6b1f1d70f143adc4p-28L, -0x1.6b1f1d70f143adc2p-28L }, + { 0xa.93e861896961066p-4L, 0x9.4d004c2eac2676fp-4L, 0x9.4d004c2eac2677p-4L }, + { -0xd.4c10bf60bb97196p-4L, -0x7.0196eb9b79274b88p-4L, -0x7.0196eb9b79274b8p-4L }, + { 0x4.ff124c9911f2538p-4L, 0x3.ddd9b3e49fd11e9p-4L, 0x3.ddd9b3e49fd11e94p-4L }, + { -0x8.776b58ba7268d9ep-4L, -0x4.e9a2512b1cd9282p-4L, -0x4.e9a2512b1cd92818p-4L }, + { 0x9.b6f6d16f1d76615p-4L, 0x8.5f4d5e77db1195p-4L, 0x8.5f4d5e77db11951p-4L }, + { -0x9.b667363949a8b6dp-4L, -0x5.7ec9a21714bc48c8p-4L, -0x5.7ec9a21714bc48cp-4L }, + { 0x9.799737c602ebc35p-12L, 0x6.92a3d4df8ac3168p-12L, 0x6.92a3d4df8ac31688p-12L }, + { -0x9.dc0d38d251990e4p-4L, -0x5.8fddc90938b5c8a8p-4L, -0x5.8fddc90938b5c8ap-4L }, + { 0x1.51d68e213ec66d4ep-4L, 0xf.0feacd9b26e94efp-8L, 0xf.0feacd9b26e94fp-8L }, + { -0xd.c78a8c73db2538p-4L, -0x7.313326148c62dbd8p-4L, -0x7.313326148c62dbdp-4L }, + { 0x7.c5f3d0d9d9db89cp-4L, 0x6.67fee55e98a6cf7p-4L, 0x6.67fee55e98a6cf78p-4L }, + { -0x1.6b364994830303c2p-4L, -0xf.42da9bf688d1dbp-8L, -0xf.42da9bf688d1dafp-8L }, + { 0x4.2513fed56a721cp-4L, 0x3.25a6d8fff7773d4cp-4L, 0x3.25a6d8fff7773d5p-4L }, + { -0x3.e183251bd312b9f8p-4L, -0x2.79df44b0dabf9e1p-4L, -0x2.79df44b0dabf9e0cp-4L }, + { 0x5.372c1f6cb3bb4cep-8L, 0x3.a4094f9b223ac4d8p-8L, 0x3.a4094f9b223ac4dcp-8L }, + { -0xc.30d4cc265a07403p-4L, -0x6.908bed536532ac7p-4L, -0x6.908bed536532ac68p-4L }, + { 0xf.7e3aa552d45b234p-4L, 0xf.4e0f6f1aac5a5e6p-4L, 0xf.4e0f6f1aac5a5e7p-4L }, + { -0x3.9a644e95053aaf1cp-4L, -0x2.4ff3cc5ef967d1bcp-4L, -0x2.4ff3cc5ef967d1b8p-4L }, + { 0xe.85839cd58ef2c75p-4L, 0xe.03c1d8a304b280dp-4L, 0xe.03c1d8a304b280ep-4L }, + { -0x7.8809e818c58ede8p-4L, -0x4.744b120d61aa22b8p-4L, -0x4.744b120d61aa22bp-4L }, + { 0xd.d9ee24413681697p-176L, 0x9.99d9ff1a3fe5cecp-176L, 0x9.99d9ff1a3fe5cedp-176L }, + { -0x3.40d11dc412df0dd4p-140L, -0x2.4143c0acd05aa3fcp-140L, -0x2.4143c0acd05aa3f8p-140L }, + { 0x5.0487ddb4070bf26p-4L, 0x3.e28d14d38a11cea8p-4L, 0x3.e28d14d38a11ceacp-4L }, + { -0x5.a0e26438dfac03cp-4L, -0x3.764d74346acb839p-4L, -0x3.764d74346acb838cp-4L }, + { 0x4.cfd480a28c2b6b48p-4L, 0x3.b55a9c63e74d1b2cp-4L, 0x3.b55a9c63e74d1b3p-4L }, + { -0x1.8657dd64795c35ap-4L, -0x1.05d2980556ab36f8p-4L, -0x1.05d2980556ab36f6p-4L }, + { 0x1.262cb60430e5eb9ep-4L, 0xd.11128880978613p-8L, 0xd.111288809786131p-8L }, + { -0x8.0e85fe0bcf8a253p-4L, -0x4.b6ccdbc2803a24p-4L, -0x4.b6ccdbc2803a23f8p-4L }, + { 0x3.cefbd3ecacf92c44p-4L, 0x2.dec16ac730be9dbp-4L, 0x2.dec16ac730be9db4p-4L }, + { -0x5.f20def7196dea63p-4L, -0x3.a216f486f08b5aecp-4L, -0x3.a216f486f08b5ae8p-4L }, + { 0x1.3a394f91198290bcp-4L, 0xd.fb2be9402707d47p-8L, 0xd.fb2be9402707d48p-8L }, + { -0x5.fa0cb4bdfd2d7318p-4L, -0x3.a65ec6a869e7e184p-4L, -0x3.a65ec6a869e7e18p-4L }, + { 0x4.08cc4ee18d971c48p-4L, 0x3.0e3ffd7c5370e6b8p-4L, 0x3.0e3ffd7c5370e6bcp-4L }, + { -0xc.08ff29dce9d081fp-4L, -0x6.8035806826b593e8p-4L, -0x6.8035806826b593ep-4L }, + { 0x8.84e7a8e11ece222p-4L, 0x7.2460415572a2c778p-4L, 0x7.2460415572a2c78p-4L }, + { -0x3.6ac116d0aa98b8bp-4L, -0x2.3397207a04b6d448p-4L, -0x2.3397207a04b6d444p-4L }, + { 0x5.b4cccaf7aee9cd6p-4L, 0x4.7caf8d9a7c39bdf8p-4L, 0x4.7caf8d9a7c39bep-4L }, + { -0xd.08cda37bcd9c8cp-4L, -0x6.e73b932483f4027p-4L, -0x6.e73b932483f40268p-4L }, + { 0xb.d7f74d7d0014f61p-4L, 0xa.ba1cc39b8135ef5p-4L, 0xa.ba1cc39b8135ef6p-4L }, + { -0xa.7263655e0a0ea62p-4L, -0x5.d2fd72c3fb172f98p-4L, -0x5.d2fd72c3fb172f9p-4L }, + { 0x2.47b34fa6f1ad5d68p-4L, 0x1.a93f34ee2980e0cap-4L, 0x1.a93f34ee2980e0ccp-4L }, + { -0x8.fcbb11c22f14e77p-4L, -0x5.28f3257a6e3ab71p-4L, -0x5.28f3257a6e3ab708p-4L }, + { 0xf.9268d3496434d05p-16L, 0xa.cb65631de896653p-16L, 0xa.cb65631de896654p-16L }, + { -0x6.90a7904ae1f6ca48p-172L, -0x4.8cf0e2bc08a21768p-172L, -0x4.8cf0e2bc08a2176p-172L }, + { 0xf.e7cc8c0c8fca8d6p-4L, 0xf.de84d77e096dc2cp-4L, 0xf.de84d77e096dc2dp-4L }, + { -0xb.5766572c78c1636p-4L, -0x6.3603cb668acec5ep-4L, -0x6.3603cb668acec5d8p-4L }, + { 0x7.08271953e92da93p-4L, 0x5.b2b05f792a83ec2p-4L, 0x5.b2b05f792a83ec28p-4L }, + { -0xe.0f6704c35bc87d8p-4L, -0x7.4c742ba7517a322p-4L, -0x7.4c742ba7517a3218p-4L }, + { 0x3.622e5c923b06d66cp-8L, 0x2.5b264a119b7052e8p-8L, 0x2.5b264a119b7052ecp-8L }, + { -0x8.911302b7a344f8ap-4L, -0x4.f5ee153ff9a408ap-4L, -0x4.f5ee153ff9a40898p-4L }, + { 0x5.5234861ad0d016d8p-4L, 0x4.25e7cdeba20def88p-4L, 0x4.25e7cdeba20def9p-4L }, + { -0x8.87063dd41e8a8bbp-4L, -0x4.f11ea0bcf9eb3e7p-4L, -0x4.f11ea0bcf9eb3e68p-4L }, + { 0x4.e1420e7e82cd22dp-4L, 0x3.c44184744892d3ecp-4L, 0x3.c44184744892d3fp-4L }, + { -0xb.db1fc14ef9e7aa3p-4L, -0x6.6d4209f7697a729p-4L, -0x6.6d4209f7697a7288p-4L }, + { 0xc.8346ca25bd9f342p-4L, 0xb.835e70838f32309p-4L, 0xb.835e70838f3230ap-4L }, + { -0x1.51646879b012b5b8p-4L, -0xe.34fbed59aa6c7acp-8L, -0xe.34fbed59aa6c7abp-8L }, + { 0x2.b32d8027c5516654p-4L, 0x1.fc3b2ff7be6c91e6p-4L, 0x1.fc3b2ff7be6c91e8p-4L }, + { -0x6.fd1366df02fe9c5p-4L, -0x4.2df6864ab991689p-4L, -0x4.2df6864ab9916888p-4L }, + { 0x6.c090b4e367d6c7ep-8L, 0x4.b92b6f86425d3ccp-8L, 0x4.b92b6f86425d3cc8p-8L }, + { -0x5.081c001c09df9f3p-4L, -0x3.223d2d4760b053ap-4L, -0x3.223d2d4760b0539cp-4L }, + { 0x7.f9714aab4e09b278p-4L, 0x6.9a31bedda6cc2ab8p-4L, 0x6.9a31bedda6cc2acp-4L }, + { -0x6.4804670d1e062cd8p-4L, -0x3.cfcfa1c45c5a88e8p-4L, -0x3.cfcfa1c45c5a88e4p-4L }, + { 0x9.ef4abcd7f8e696ap-4L, 0x8.9b0f698e7955a9p-4L, 0x8.9b0f698e7955a91p-4L }, + { -0x4.8c4513525f5a0ap-4L, -0x2.dc7be2a249c73a38p-4L, -0x2.dc7be2a249c73a34p-4L }, + { 0x1.7fe67833e1976e6p-168L, 0x1.0a1971aebce11604p-168L, 0x1.0a1971aebce11606p-168L }, + { -0xe.a86b5a2c843f668p-36L, -0xa.28fa9875dd806c6p-36L, -0xa.28fa9875dd806c5p-36L }, + { 0x6.0dd96d442bc44b28p-4L, 0x4.cc518e951f69bd48p-4L, 0x4.cc518e951f69bd5p-4L }, + { -0x3.e88917f9e6c0bb2p-4L, -0x2.7dfc064ecfe2635cp-4L, -0x2.7dfc064ecfe26358p-4L }, + { 0xf.e9c0adcf6e6ebaap-4L, 0xf.e13773c6da26f73p-4L, 0xf.e13773c6da26f74p-4L }, + { -0xe.6049cc9d4ea9c32p-8L, -0x9.c5f8986aafe8b3p-8L, -0x9.c5f8986aafe8b2fp-8L }, + { 0xd.e0ca0ae677c56c7p-4L, 0xd.30868169c79fdeap-4L, 0xd.30868169c79fdebp-4L }, + { -0x3.b604528c1bde4ca8p-4L, -0x2.604b88132e3dceb4p-4L, -0x2.604b88132e3dcebp-4L }, + { 0x9.3e94ea277274ab3p-4L, 0x7.e17b8968152545ep-4L, 0x7.e17b8968152545e8p-4L }, + { -0xf.ec080621a8d9456p-4L, -0x7.f91153ca519955fp-4L, -0x7.f91153ca519955e8p-4L }, + { 0x1.96ef7e6b80e63adep-4L, 0x1.24014f5d43fc1232p-4L, 0x1.24014f5d43fc1234p-4L }, + { -0x2.fd0a9d9f59d83bc8p-4L, -0x1.f164f450f8e2c15p-4L, -0x1.f164f450f8e2c14ep-4L }, + { 0x5.82923d4fd6f683p-4L, 0x4.504b840326d2f688p-4L, 0x4.504b840326d2f69p-4L }, + { -0x2.5fa1d9a3a5a2b664p-4L, -0x1.903f73ce566d8522p-4L, -0x1.903f73ce566d852p-4L }, + { 0xf.b8a161f6eba3189p-4L, 0xf.9da7e29775ea166p-4L, 0xf.9da7e29775ea167p-4L }, + { -0xb.79a14c17c57922dp-4L, -0x6.447d36e53f9fbf98p-4L, -0x6.447d36e53f9fbf9p-4L }, + { 0x9.9b19d045170086ap-4L, 0x8.41f3b9e1fe6130dp-4L, 0x8.41f3b9e1fe6130ep-4L }, + { -0xd.65fbae6f453f5a2p-4L, -0x7.0baa677949607eb8p-4L, -0x7.0baa677949607ebp-4L }, + { 0xc.7a9e15e82248878p-4L, 0xb.790e3f5b2936dc4p-4L, 0xb.790e3f5b2936dc5p-4L }, + { -0x3.f5ec8986cfd785dp-4L, -0x2.85cf707de281dc78p-4L, -0x2.85cf707de281dc74p-4L }, + { 0xa.530c1b060238f06p-4L, 0x9.064c5060f10810bp-4L, 0x9.064c5060f10810cp-4L }, + { -0x3.aa0cc319c013919p-4L, -0x2.59398f9b92fe953p-4L, -0x2.59398f9b92fe952cp-4L }, + { 0x3.c0a4bd100746357p-184L, 0x2.99de0a05056aaf74p-184L, 0x2.99de0a05056aaf78p-184L }, + { -0x6.fd442271482ca6dp-136L, -0x4.d8398bacdf9d28ap-136L, -0x4.d8398bacdf9d2898p-136L }, + { 0x6.67012d8b67014328p-4L, 0x5.1d41e56dafaf995p-4L, 0x5.1d41e56dafaf9958p-4L }, + { -0xa.6b6836f2ff72662p-4L, -0x5.cfe921fda171774p-4L, -0x5.cfe921fda1717738p-4L }, + { 0x9.620bcddbdd20a79p-4L, 0x8.064866d2e843838p-4L, 0x8.064866d2e843839p-4L }, + { -0x4.17376606afdde85p-4L, -0x2.99319a6951355f74p-4L, -0x2.99319a6951355f7p-4L }, + { 0xd.1dc39e358b023ap-4L, 0xc.3deef0997e22f56p-4L, 0xc.3deef0997e22f57p-4L }, + { -0xb.13430c035931444p-4L, -0x6.18f3b1ddbf4bbd98p-4L, -0x6.18f3b1ddbf4bbd9p-4L }, + { 0x3.606617a1673d0184p-4L, 0x2.8531caa9e41d88d8p-4L, 0x2.8531caa9e41d88dcp-4L }, + { -0x8.f017932d188a998p-4L, -0x5.23021a6f15e3204p-4L, -0x5.23021a6f15e32038p-4L }, + { 0x3.cf39982caefbf098p-4L, 0x2.def3e957a9d7b4e8p-4L, 0x2.def3e957a9d7b4ecp-4L }, + { -0x1.8dad3bd8dae62b26p-4L, -0x1.0a93f35dbc547e06p-4L, -0x1.0a93f35dbc547e04p-4L }, + { 0xf.d53ec036950502fp-4L, 0xf.c4f16bfb42b91ebp-4L, 0xf.c4f16bfb42b91ecp-4L }, + { -0xa.9cb0f8ebab4d7f8p-4L, -0x5.e59271c5142a2828p-4L, -0x5.e59271c5142a282p-4L }, + { 0x4.9ff6d398cf5c723p-4L, 0x3.8ca6a81f115945c8p-4L, 0x3.8ca6a81f115945ccp-4L }, + { -0x3.c7ea3c3c2b39e2c8p-4L, -0x2.6ad7b91001b1a278p-4L, -0x2.6ad7b91001b1a274p-4L }, + { 0xf.7206b4c8d50f316p-4L, 0xf.3d872c603dec047p-4L, 0xf.3d872c603dec048p-4L }, + { -0x7.5f74c3dd6c9936dp-4L, -0x4.5fecbd230b7b225p-4L, -0x4.5fecbd230b7b2248p-4L }, + { 0x1.d1a5048e1cfadea8p-4L, 0x1.4fd148e51db81464p-4L, 0x1.4fd148e51db81466p-4L }, + { -0xe.8f9244700df6721p-4L, -0x7.7c3f71d67ca51a2p-4L, -0x7.7c3f71d67ca51a18p-4L }, + { 0x3.99c86ae38d72f47cp-4L, 0x2.b375b38730124248p-4L, 0x2.b375b3873012424cp-4L }, + { -0x5.e2a8926a1f2a69f8p-4L, -0x3.99d49b6de5eb2bfp-4L, -0x3.99d49b6de5eb2becp-4L }, + { 0x2.58e048821c0475f4p-64L, 0x1.a07ede4412af4bbap-64L, 0x1.a07ede4412af4bbcp-64L }, + { -0x1.8989c2560de848e8p-124L, -0x1.10c7a38e60d87138p-124L, -0x1.10c7a38e60d87136p-124L }, + { 0x7.bc19ff559d9831b8p-4L, 0x6.5e7110fac4089518p-4L, 0x6.5e7110fac408952p-4L }, + { -0x6.c87c79c7f39458b8p-4L, -0x4.12e9a15e9bfdadb8p-4L, -0x4.12e9a15e9bfdadbp-4L }, + { 0x2.f5c34056d7c105dp-4L, 0x2.30678a0e37a17cep-4L, 0x2.30678a0e37a17ce4p-4L }, + { -0xd.4a8d8fca0cbe02bp-4L, -0x7.01000b10ed4e999p-4L, -0x7.01000b10ed4e9988p-4L }, + { 0x6.f866735c25236f98p-4L, 0x5.a3e6c10f6f1511fp-4L, 0x5.a3e6c10f6f1511f8p-4L }, + { -0xc.91587f5ff35915fp-4L, -0x6.b7ad5204ea051758p-4L, -0x6.b7ad5204ea05175p-4L }, + { 0x5.8acab0d65d615ap-4L, 0x4.5788c486bedea82p-4L, 0x4.5788c486bedea828p-4L }, + { -0xa.a22cceb5d16a7b9p-4L, -0x5.e7f89a5c228804ap-4L, -0x5.e7f89a5c22880498p-4L }, + { 0x7.9bb3d37308387268p-4L, 0x6.3f21841dccbd4848p-4L, 0x6.3f21841dccbd485p-4L }, + { -0xc.186ea423cfbc56dp-4L, -0x6.868d7eab6a729728p-4L, -0x6.868d7eab6a72972p-4L }, + { 0x2.797cf0eb89b43758p-4L, 0x1.cf80358fed6434cap-4L, 0x1.cf80358fed6434ccp-4L }, + { -0x1.5803a5d39e417564p-4L, -0xe.7a4f6be0f29e7b7p-8L, -0xe.7a4f6be0f29e7b6p-8L }, + { 0xc.a52f12f15058ap-8L, 0x8.eab3287521cf0c3p-8L, 0x8.eab3287521cf0c4p-8L }, + { -0x7.c0b1a87701c336f8p-4L, -0x4.907ee683856ce948p-4L, -0x4.907ee683856ce94p-4L }, + { 0x7.810b603203760db8p-4L, 0x6.257f312ef0f8e4cp-4L, 0x6.257f312ef0f8e4c8p-4L }, + { -0x3.74e32a2c3287777cp-4L, -0x2.39a477aba5f3e36cp-4L, -0x2.39a477aba5f3e368p-4L }, + { 0x7.ce4d4cf62f3cae4p-4L, 0x6.701b2af84891b008p-4L, 0x6.701b2af84891b01p-4L }, + { -0xc.d26229e318f0c64p-4L, -0x6.d1b0028af7ad99e8p-4L, -0x6.d1b0028af7ad99ep-4L }, + { 0x8.457740622adf15fp-4L, 0x6.e51d70eb7475fd68p-4L, 0x6.e51d70eb7475fd7p-4L }, + { -0x7.492c117c47e7f31p-4L, -0x4.54ae45d535c0da2p-4L, -0x4.54ae45d535c0da18p-4L }, + { 0x1.7627671657573188p-68L, 0x1.0357feda17430d52p-68L, 0x1.0357feda17430d54p-68L }, + { -0x1.80b4a26e54c41986p-136L, -0x1.0aa858c341e9388ep-136L, -0x1.0aa858c341e9388cp-136L }, + { 0xf.52d7c0f49c1b5a4p-4L, 0xf.136f9f9fa392aa3p-4L, 0xf.136f9f9fa392aa4p-4L }, + { -0xd.90fb86e4d60004ep-4L, -0x7.1c4914f985d3d1c8p-4L, -0x7.1c4914f985d3d1cp-4L }, + { 0x1.5c0865fc4e06a84ep-4L, 0xf.87bc506c0360beap-8L, 0xf.87bc506c0360bebp-8L }, + { -0xa.2dfc5d1f96be4bcp-4L, -0x5.b4a92468e23a59ep-4L, -0x5.b4a92468e23a59d8p-4L }, + { 0xf.d25ff3331838e0ap-4L, 0xf.c0fe5c5501df211p-4L, 0xf.c0fe5c5501df212p-4L }, + { -0xe.e893761d9d926b2p-4L, -0x7.9cd539ff83893758p-4L, -0x7.9cd539ff8389375p-4L }, + { 0x5.03f2d9b66abed898p-4L, 0x3.e20cb7d716acf19cp-4L, 0x3.e20cb7d716acf1ap-4L }, + { -0xd.e1d2b8730f8408fp-4L, -0x7.3b34b6801908a2d8p-4L, -0x7.3b34b6801908a2dp-4L }, + { 0x3.8052f809aaac9b64p-4L, 0x2.9ee0e2805679d1e8p-4L, 0x2.9ee0e2805679d1ecp-4L }, + { -0xf.ad374726f5b37c2p-4L, -0x7.e31b793e91a5aa08p-4L, -0x7.e31b793e91a5aap-4L }, + { 0x3.48836233e960d588p-4L, 0x2.7211ad27a4176778p-4L, 0x2.7211ad27a417677cp-4L }, + { -0x8.af10e3af7480717p-4L, -0x5.043cabb9514315b8p-4L, -0x5.043cabb9514315bp-4L }, + { 0x2.684f23a780f8d16cp-4L, 0x1.c243ddcaf1137a7ap-4L, 0x1.c243ddcaf1137a7cp-4L }, + { -0x2.956954f33db8ba84p-4L, -0x1.b1bac7e767d6e47p-4L, -0x1.b1bac7e767d6e46ep-4L }, + { 0xe.05c36356f1cc00bp-4L, 0xd.5f6d58c69cd39e4p-4L, 0xd.5f6d58c69cd39e5p-4L }, + { -0x9.851c7f17e3779ebp-4L, -0x5.68430d8fcaf782c8p-4L, -0x5.68430d8fcaf782cp-4L }, + { 0x8.98fecd06210c28ep-8L, 0x6.07827af96e4199d8p-8L, 0x6.07827af96e4199ep-8L }, + { -0xa.944a9ff08e89db6p-4L, -0x5.e1e49752fc61a1f8p-4L, -0x5.e1e49752fc61a1fp-4L }, + { 0xf.069ae41b6f97acbp-4L, 0xe.ad7594fe8b4b59ap-4L, 0xe.ad7594fe8b4b59bp-4L }, + { -0x2.849c2bec428d3088p-4L, -0x1.a74d58f4fabdbfecp-4L, -0x1.a74d58f4fabdbfeap-4L }, + { 0x7.77014ff302ca7f18p-132L, 0x5.2c9b99c7adcd1158p-132L, 0x5.2c9b99c7adcd116p-132L }, + { -0xe.aa11ca5025d7161p-8L, -0x9.f724056ca1ff3ffp-8L, -0x9.f724056ca1ff3fep-8L }, + { 0xe.30a7bdb7d22b3c9p-4L, 0xd.96346f655e1888ep-4L, 0xd.96346f655e1888fp-4L }, + { -0xd.1710819efb6a90bp-4L, -0x6.ecd8990f76e583d8p-4L, -0x6.ecd8990f76e583dp-4L }, + { 0xc.289ab032c02ec2bp-8L, 0x8.91661f345b3b24ap-8L, 0x8.91661f345b3b24bp-8L }, + { -0x9.3c743e33f50fbe3p-8L, -0x6.52977132d3793028p-8L, -0x6.52977132d379302p-8L }, + { 0xc.b983cae10f7203p-4L, 0xb.c45064517003de9p-4L, 0xb.c45064517003deap-4L }, + { -0xb.7422dd3d2b45dc5p-4L, -0x6.422bf2df07d21bc8p-4L, -0x6.422bf2df07d21bcp-4L }, + { 0xa.fbaa8d616ab8d1dp-4L, 0x9.bfbb7af27216907p-4L, 0x9.bfbb7af27216908p-4L }, + { -0xe.926ef7c0fa60c33p-4L, -0x7.7d4da667730b916p-4L, -0x7.7d4da667730b9158p-4L }, + { 0xf.80c7c99d2c6404cp-4L, 0xf.518567961cfcee4p-4L, 0xf.518567961cfcee5p-4L }, + { -0x3.9556369534624858p-8L, -0x2.78c655fc919c92b8p-8L, -0x2.78c655fc919c92b4p-8L }, + { 0xe.80d9a3a08faf173p-4L, 0xd.fdb1f369b283091p-4L, 0xd.fdb1f369b283092p-4L }, + { -0x8.400e8efd60a398p-4L, -0x4.ceeacdda92f4d4f8p-4L, -0x4.ceeacdda92f4d4fp-4L }, + { 0x1.e30b1be4461dcf88p-4L, 0x1.5ce2ab3afe2480fcp-4L, 0x1.5ce2ab3afe2480fep-4L }, + { -0xc.2454aa891f5dba1p-4L, -0x6.8b6e7833d8a9115p-4L, -0x6.8b6e7833d8a91148p-4L }, + { 0x2.c925c1f452e23ebp-4L, 0x2.0d617fc9f8513ef4p-4L, 0x2.0d617fc9f8513ef8p-4L }, + { -0x3.a0caae204aa84214p-4L, -0x2.53bec8ebfa7cc494p-4L, -0x2.53bec8ebfa7cc49p-4L }, + { 0x6.db2d4dd8afa84408p-4L, 0x5.88928d8e125932e8p-4L, 0x5.88928d8e125932fp-4L }, + { -0x8.7fd39596a804d49p-4L, -0x4.edab5a4106ecd58p-4L, -0x4.edab5a4106ecd578p-4L }, + { 0xf.c5af0e065f2eb13p-4L, 0xf.af8ddf3950b244p-4L, 0xf.af8ddf3950b2441p-4L }, + { -0x5.9541e8c20a3e7eep-4L, -0x3.6ffb2642f78d6758p-4L, -0x3.6ffb2642f78d6754p-4L }, + { 0x2.b8baba6727f5d1ep-24L, 0x1.e2efa10b181a1d0cp-24L, 0x1.e2efa10b181a1d0ep-24L }, + { -0x8.db8aa5ad53966d6p-64L, -0x6.23bd7497280c936p-64L, -0x6.23bd7497280c9358p-64L }, + { 0xc.2a19196663e14b4p-4L, 0xb.19dfa4b37a6fc82p-4L, 0xb.19dfa4b37a6fc83p-4L }, + { -0x5.0fb02f7662c3e03p-4L, -0x3.2675eb61e2d86868p-4L, -0x3.2675eb61e2d86864p-4L }, + { 0x6.883e7a1d34914268p-4L, 0x5.3bbf577ebbb3a6e8p-4L, 0x5.3bbf577ebbb3a6fp-4L }, + { -0xb.88a85700deb5549p-4L, -0x6.4ad12b9dbb86aa58p-4L, -0x6.4ad12b9dbb86aa5p-4L }, + { 0xf.2b2a3a311948993p-4L, 0xe.de32bdbd5328a8bp-4L, 0xe.de32bdbd5328a8cp-4L }, + { -0x3.06fe2a10fe55267cp-4L, -0x1.f7730b164f7095cap-4L, -0x1.f7730b164f7095c8p-4L }, + { 0xd.de264368cd7459ap-4L, 0xd.2d302551f4723e2p-4L, 0xd.2d302551f4723e3p-4L }, + { -0x5.567777c9aa2124c8p-4L, -0x3.4da047a5e9ef6524p-4L, -0x3.4da047a5e9ef652p-4L }, + { 0x1.935a9217a5a3024p-4L, 0x1.2158a4e7876f331ep-4L, 0x1.2158a4e7876f332p-4L }, + { -0x7.3ccc7fe1d42ad228p-4L, -0x4.4e6b4b167987ff4p-4L, -0x4.4e6b4b167987ff38p-4L }, + { 0x4.bbff6d1fef17b4c8p-4L, 0x3.a4730f28cbe2fbf4p-4L, 0x3.a4730f28cbe2fbf8p-4L }, + { -0x2.826940b5855fb4cp-4L, -0x1.a5ef6bae7291935p-4L, -0x1.a5ef6bae7291934ep-4L }, + { 0x5.265fe49d84076a68p-4L, 0x3.ffca2018e001a9f4p-4L, 0x3.ffca2018e001a9f8p-4L }, + { -0xc.103986b2d38539dp-4L, -0x6.832e7fadd55aecp-4L, -0x6.832e7fadd55aebf8p-4L }, + { 0x1.70101c108d2f0d0ep-4L, 0x1.073c0b1e50c5d204p-4L, 0x1.073c0b1e50c5d206p-4L }, + { -0x2.66bb0943c921a184p-4L, -0x1.94af43fe62d2cf1ap-4L, -0x1.94af43fe62d2cf18p-4L }, + { 0x7.5a723c24f0c64ebp-4L, 0x6.0095e4fad124e338p-4L, 0x6.0095e4fad124e34p-4L }, + { -0x3.c761bdd9cf2def2cp-4L, -0x2.6a876738e18b6208p-4L, -0x2.6a876738e18b6204p-4L }, + { 0x3.e7acf294cc0ca23cp-8L, 0x2.b89933565f7ae4f4p-8L, 0x2.b89933565f7ae4f8p-8L }, + { -0x7.3c061c9452915b98p-4L, -0x4.4e06c9112a70ca8p-4L, -0x4.4e06c9112a70ca78p-4L }, + { 0x3.0efe779ab69c208p-72L, 0x2.1ebae7521123e438p-72L, 0x2.1ebae7521123e43cp-72L }, + { -0x6.90517ba54103e7cp-172L, -0x4.8cb53818436922b8p-172L, -0x4.8cb53818436922bp-172L }, + { 0xb.dde4e379662aeeap-4L, 0xa.c0facbdff63e577p-4L, 0xa.c0facbdff63e578p-4L }, + { -0xb.0226291c9bc5964p-4L, -0x6.1199984540184bp-4L, -0x6.1199984540184af8p-4L }, + { 0xd.bf9a0da9faa3504p-4L, 0xd.06ad1755cc71cafp-4L, 0xd.06ad1755cc71cbp-4L }, + { -0x5.c1892b0fafe1dc68p-4L, -0x3.87fd1b244474f46p-4L, -0x3.87fd1b244474f45cp-4L }, + { 0x1.44812a3159648466p-4L, 0xe.7384fa316de3657p-8L, 0xe.7384fa316de3658p-8L }, + { -0x3.675c755eb8dbe27cp-4L, -0x2.318fbbc51015422p-4L, -0x2.318fbbc51015421cp-4L }, + { 0x1.e8e8f49835eaacb8p-4L, 0x1.614ce65fa1a17274p-4L, 0x1.614ce65fa1a17276p-4L }, + { -0x9.eac5efdf2c187bdp-4L, -0x5.9683d9aacedb09d8p-4L, -0x5.9683d9aacedb09dp-4L }, + { 0xf.8a9cd502481f327p-4L, 0xf.5edf4b01d85e97fp-4L, 0xf.5edf4b01d85e98p-4L }, + { -0x2.9371a4cdcbd8ac4p-4L, -0x1.b0829193db9b2a82p-4L, -0x1.b0829193db9b2a8p-4L }, + { 0xf.ec9e23f6d0a3bd2p-4L, 0xf.e52cabad2944b2dp-4L, 0xf.e52cabad2944b2ep-4L }, + { -0x4.bfabe9c4786421c8p-4L, -0x2.f99d50346680f5e4p-4L, -0x2.f99d50346680f5ep-4L }, + { 0x6.028525d3aafe4428p-4L, 0x4.c21ee15b144d29a8p-4L, 0x4.c21ee15b144d29bp-4L }, + { -0x4.c2d0568402546a5p-8L, -0x3.47653cfe61fb05p-8L, -0x3.47653cfe61fb04fcp-8L }, + { 0xc.976222dd345048p-4L, 0xb.9b60191b6b95aecp-4L, 0xb.9b60191b6b95aedp-4L }, + { -0xd.6563e961e96fd5dp-4L, -0x7.0b6f86cbdfafbe78p-4L, -0x7.0b6f86cbdfafbe7p-4L }, + { 0x9.e03ff635ae5b0afp-4L, 0x8.8b0bdb10fd8a85fp-4L, 0x8.8b0bdb10fd8a86p-4L }, + { -0xa.42b9f1752ebee14p-4L, -0x5.bde4e29a894df518p-4L, -0x5.bde4e29a894df51p-4L }, + { 0x6.4ef2060125bf954p-4L, 0x5.074b877b025a5c38p-4L, 0x5.074b877b025a5c4p-4L }, + { -0xc.a4d9e356caf3a4ap-4L, -0x6.bf8205df1ee0d508p-4L, -0x6.bf8205df1ee0d5p-4L }, + { 0x7.e842fb7dd3d50cap-196L, 0x5.7b1c7b3b95bed698p-196L, 0x5.7b1c7b3b95bed6ap-196L }, + { -0x1.31f41258f7c01eccp-60L, -0xd.4121c04c9ce13acp-64L, -0xd.4121c04c9ce13abp-64L }, + { 0x2.29f54bce824a24cp-8L, 0x1.811a02ec67bf37aep-8L, 0x1.811a02ec67bf37bp-8L }, + { -0xa.b8f81b679b49916p-4L, -0x5.f1eb5dee53695e5p-4L, -0x5.f1eb5dee53695e48p-4L }, + { 0x2.dfa40c215498cf14p-4L, 0x2.1f01613fffbe7cfcp-4L, 0x2.1f01613fffbe7dp-4L }, + { -0x2.ec02031137509e54p-4L, -0x1.e7019f7577e0055ap-4L, -0x1.e7019f7577e00558p-4L }, + { 0xc.95b28af67c0d0fdp-4L, 0xb.995bfeb5a18fb19p-4L, 0xb.995bfeb5a18fb1ap-4L }, + { -0x3.8b937ee4a5ad9044p-4L, -0x2.4727f0551eb47668p-4L, -0x2.4727f0551eb47664p-4L }, + { 0xc.b61f96c1b9a40fep-8L, 0x8.f6d9fa1cd76287dp-8L, 0x8.f6d9fa1cd76287ep-8L }, + { -0x5.32ac5f2f72c534e8p-4L, -0x3.39e0dcc0490bcf08p-4L, -0x3.39e0dcc0490bcf04p-4L }, + { 0x3.71a836d1385ea83cp-4L, 0x2.930fc44d7c9f0878p-4L, 0x2.930fc44d7c9f087cp-4L }, + { -0x2.98de885b63ec9fap-4L, -0x1.b3df390ab96ff674p-4L, -0x1.b3df390ab96ff672p-4L }, + { 0x2.ec64d50f08792a24p-4L, 0x2.290720411b492388p-4L, 0x2.290720411b49238cp-4L }, + { -0x7.4a3ef749c24694d8p-4L, -0x4.55393aafd5f18ddp-4L, -0x4.55393aafd5f18dc8p-4L }, + { 0x1.c73a886f525db7c4p-4L, 0x1.48033f1818ec4274p-4L, 0x1.48033f1818ec4276p-4L }, + { -0x7.e597e9edb98f8dd8p-4L, -0x4.a2b8122945a3a86p-4L, -0x4.a2b8122945a3a858p-4L }, + { 0x5.b2db0149e01e772p-4L, 0x4.7af5d27da276247p-4L, 0x4.7af5d27da2762478p-4L }, + { -0xa.4e00c5865119715p-4L, -0x5.c2e6944e696561dp-4L, -0x5.c2e6944e696561c8p-4L }, + { 0x3.2d5ce470bbbfc05p-4L, 0x2.5c6c520e75d5dcfp-4L, 0x2.5c6c520e75d5dcf4p-4L }, + { -0x6.fef503b2cde63e88p-4L, -0x4.2eed1c50abe4d0fp-4L, -0x4.2eed1c50abe4d0e8p-4L }, + { 0x9.d7135271cf1adc5p-8L, 0x6.e98f0ad0c8f784bp-8L, 0x6.e98f0ad0c8f784b8p-8L }, + { -0x1.37a6e3f9da2ebc3ap-4L, -0xd.26c4f046ca71bc4p-8L, -0xd.26c4f046ca71bc3p-8L }, + { 0xe.f91909cb851832p-16L, 0xa.611c7fdf8ec95cap-16L, 0xa.611c7fdf8ec95cbp-16L }, + { -0x1.8aec185a037005eap-44L, -0x1.11bd3ef298133bf6p-44L, -0x1.11bd3ef298133bf4p-44L }, + { 0x4.58042455b6631c78p-4L, 0x3.5016317376e61d88p-4L, 0x3.5016317376e61d8cp-4L }, + { -0xf.a5425993c2d22edp-4L, -0x7.e04f162edd1444c8p-4L, -0x7.e04f162edd1444cp-4L }, + { 0xc.cc707747b5d9891p-4L, 0xb.db1d6d0a67ba46dp-4L, 0xb.db1d6d0a67ba46ep-4L }, + { -0x5.6352b9b11a14c48p-4L, -0x3.54b0a77bead101c4p-4L, -0x3.54b0a77bead101cp-4L }, + { 0xb.ddfe2e36f24ba09p-4L, 0xa.c1181c4c96d3b16p-4L, 0xa.c1181c4c96d3b17p-4L }, + { -0xf.ff0d58e82429fafp-4L, -0x7.ffabe56fa53e346p-4L, -0x7.ffabe56fa53e3458p-4L }, + { 0x9.bd53e4167e85b42p-4L, 0x8.6606596f18f0c25p-4L, 0x8.6606596f18f0c26p-4L }, + { -0x5.4c28c9b0b345941p-4L, -0x3.47f39e55e7145a5p-4L, -0x3.47f39e55e7145a4cp-4L }, + { 0x8.fef78aad41a1338p-4L, 0x7.a005c2fb7b575668p-4L, 0x7.a005c2fb7b57567p-4L }, + { -0xf.25b2822b10d9f65p-4L, -0x7.b2ed5c3922a4e83p-4L, -0x7.b2ed5c3922a4e828p-4L }, + { 0x5.cd10c03bcaf10088p-8L, 0x4.0d7eda5d78333cc8p-8L, 0x4.0d7eda5d78333cdp-8L }, + { -0xa.a821812c5f53b52p-4L, -0x5.ea92fddd766193d8p-4L, -0x5.ea92fddd766193dp-4L }, + { 0x5.94e05ec04235ac68p-4L, 0x4.606dcea9678b422p-4L, 0x4.606dcea9678b4228p-4L }, + { -0x5.04ba966a5474e0e8p-4L, -0x3.205aab0b1a291c5cp-4L, -0x3.205aab0b1a291c58p-4L }, + { 0xd.167af1356c9c025p-4L, 0xc.3506efb6e7f748dp-4L, 0xc.3506efb6e7f748ep-4L }, + { -0xf.d0cd204dbb8b533p-4L, -0x7.ef93a0736368116p-4L, -0x7.ef93a07363681158p-4L }, + { 0xa.c0e5742f317f8a3p-4L, 0x9.7e80068401fa255p-4L, 0x9.7e80068401fa256p-4L }, + { -0xe.2242314d427e9c1p-4L, -0x7.538ce8c2b95acc28p-4L, -0x7.538ce8c2b95acc2p-4L }, + { 0x2.37749e13337ef694p-4L, 0x1.9cd5b81ee0f49f52p-4L, 0x1.9cd5b81ee0f49f54p-4L }, + { -0x4.8513915f54085e2p-4L, -0x2.d86313394f7dfa98p-4L, -0x2.d86313394f7dfa94p-4L }, + { 0x7.11d091eb6c5e7f8p-32L, 0x4.e677cd427aff876p-32L, 0x4.e677cd427aff8768p-32L }, + { -0x2.92d0f5e17e14f8ep-176L, -0x1.c8a818bcf03dad22p-176L, -0x1.c8a818bcf03dad2p-176L }, + { 0x9.19d2bf8e626ce94p-4L, 0x7.bb9267aaaf8d16f8p-4L, 0x7.bb9267aaaf8d17p-4L }, + { -0x5.78fee31b1243e6ep-4L, -0x3.6090300d6de230a8p-4L, -0x3.6090300d6de230a4p-4L }, + { 0xe.920450e2df4f23ep-4L, 0xe.14081596bb730e3p-4L, 0xe.14081596bb730e4p-4L }, + { -0x7.8a913f4c29492cdp-4L, -0x4.758ec9da15257a08p-4L, -0x4.758ec9da15257ap-4L }, + { 0xd.f18c68c5e57c1fep-4L, 0xd.45bf8cfdf37d1c1p-4L, 0xd.45bf8cfdf37d1c2p-4L }, + { -0xc.97ed4020a652183p-4L, -0x6.ba5270a397bd198p-4L, -0x6.ba5270a397bd1978p-4L }, + { 0x6.b2da8740f690432p-4L, 0x5.63158e0eca286c4p-4L, 0x5.63158e0eca286c48p-4L }, + { -0x8.d86e55e3f0a94b1p-4L, -0x5.17d9c3b44828322p-4L, -0x5.17d9c3b448283218p-4L }, + { 0x5.0308adabc4a020fp-4L, 0x3.e14306a78e1170ccp-4L, 0x3.e14306a78e1170dp-4L }, + { -0x2.a7d9b961e2c3089p-4L, -0x1.bd23ae2c81af213p-4L, -0x1.bd23ae2c81af212ep-4L }, + { 0xd.227d8e4d09d7251p-4L, 0xc.43b7e073dd24255p-4L, 0xc.43b7e073dd24256p-4L }, + { -0x7.d5608278690935ap-4L, -0x4.9ab96d634d10f6a8p-4L, -0x4.9ab96d634d10f6ap-4L }, + { 0xe.81b27c03c76f499p-4L, 0xd.fecbb5a87bddaadp-4L, 0xd.fecbb5a87bddaaep-4L }, + { -0x2.b154c8162bc04cb4p-4L, -0x1.c2fdf56982dfaa86p-4L, -0x1.c2fdf56982dfaa84p-4L }, + { 0x4.35ecdac82f2a93c8p-4L, 0x3.33a5663cd3ec757cp-4L, 0x3.33a5663cd3ec758p-4L }, + { -0x5.771325ed71c201dp-4L, -0x3.5f833dab5799d678p-4L, -0x3.5f833dab5799d674p-4L }, + { 0xb.d5c2b3ad8490192p-4L, 0xa.b78f2869f7f0d2fp-4L, 0xa.b78f2869f7f0d3p-4L }, + { -0x5.121392f3a25f68p-4L, -0x3.27ca31d087184188p-4L, -0x3.27ca31d087184184p-4L }, + { 0x7.b9734cb7e88bd598p-4L, 0x6.5bdf83f80e502428p-4L, 0x6.5bdf83f80e50243p-4L }, + { -0x1.778ccedfa82f4736p-4L, -0xf.c36523958ccb66dp-8L, -0xf.c36523958ccb66cp-8L }, + { 0x5.9e61f2660d92e2bp-24L, 0x3.e502ce773052c2ep-24L, 0x3.e502ce773052c2e4p-24L }, + { -0xc.ed5cdd95e040dd5p-124L, -0x8.f5e01e66418fdc9p-124L, -0x8.f5e01e66418fdc8p-124L }, + { 0xe.22ec92ad54501adp-4L, 0xd.84a01b636eef0b3p-4L, 0xd.84a01b636eef0b4p-4L }, + { -0x7.ec2bfe55bde275dp-4L, -0x4.a5f4b909907e0218p-4L, -0x4.a5f4b909907e021p-4L }, + { 0xf.d304d6628c01f2ap-4L, 0xf.c1e1328eafdd3bfp-4L, 0xf.c1e1328eafdd3cp-4L }, + { -0x9.352c83f42a1922fp-4L, -0x5.43546e87e016ee88p-4L, -0x5.43546e87e016ee8p-4L }, + { 0x7.4cdb36f2473c8acp-4L, 0x5.f3a5959c53f3ceb8p-4L, 0x5.f3a5959c53f3cecp-4L }, + { -0x1.70792a73178fa0fap-4L, -0xf.79b33e5d77df4c1p-8L, -0xf.79b33e5d77df4cp-8L }, + { 0x5.1ce62b8e10774afp-4L, 0x3.f7962ac86af2f5ecp-4L, 0x3.f7962ac86af2f5fp-4L }, + { -0x7.fa8931ceaf326ac8p-4L, -0x4.ad02e3351c74545p-4L, -0x4.ad02e3351c745448p-4L }, + { 0xb.369caaaa169ce0fp-4L, 0xa.01d090312957af1p-4L, 0xa.01d090312957af2p-4L }, + { -0xa.954d79680ea5909p-4L, -0x5.e25609c7a753185p-4L, -0x5.e25609c7a7531848p-4L }, + { 0xb.432563e5c37e78fp-4L, 0xa.0ff3939e94e53c8p-4L, 0xa.0ff3939e94e53c9p-4L }, + { -0xa.950b0bb7d84c5b3p-4L, -0x5.e238ed18b7fab0bp-4L, -0x5.e238ed18b7fab0a8p-4L }, + { 0x4.3e136fbe7e156658p-4L, 0x3.3a6e53129453d0d4p-4L, 0x3.3a6e53129453d0d8p-4L }, + { -0xb.9930789b19cf8a8p-4L, -0x6.51c2880aa5aa9ff8p-4L, -0x6.51c2880aa5aa9ffp-4L }, + { 0x8.1697784edf6fe07p-8L, 0x5.ab0e426210147018p-8L, 0x5.ab0e42621014702p-8L }, + { -0x2.e9849ddc62c0d374p-4L, -0x1.e57c4324b108422ep-4L, -0x1.e57c4324b108422cp-4L }, + { 0xc.d570e244c0e60bep-4L, 0xb.e5fc70032574c78p-4L, 0xb.e5fc70032574c79p-4L }, + { -0xf.15d04c531718d34p-4L, -0x7.ad351e2ce95c1f88p-4L, -0x7.ad351e2ce95c1f8p-4L }, + { 0x1.e1200b8406eda8fep-4L, 0x1.5b715b4dfb18883p-4L, 0x1.5b715b4dfb188832p-4L }, + { -0x7.995991a529314d5p-4L, -0x4.7cf0755dd5eca728p-4L, -0x4.7cf0755dd5eca72p-4L }, + { 0x9.2cb86254ecdfd09p-192L, 0x6.5c0241febd46c9cp-192L, 0x6.5c0241febd46c9c8p-192L }, + { -0x2.4cc15f58d07c3b1cp-140L, -0x1.981818282e5dbca4p-140L, -0x1.981818282e5dbca2p-140L }, + { 0x3.9173123187f70484p-4L, 0x2.acb691682f6030d4p-4L, 0x2.acb691682f6030d8p-4L }, + { -0x4.e07d3709dbe3fep-4L, -0x3.0c14b7174878c9ecp-4L, -0x3.0c14b7174878c9e8p-4L }, + { 0x5.653d42dac0a5219p-4L, 0x4.368bd2c07053e5ep-4L, 0x4.368bd2c07053e5e8p-4L }, + { -0x9.5f1aff673a041bcp-4L, -0x5.56c3d8c108a0611p-4L, -0x5.56c3d8c108a06108p-4L }, + { 0x8.bcd403a004e1a23p-4L, 0x7.5cb550c524697b8p-4L, 0x7.5cb550c524697b88p-4L }, + { -0x8.1c9d05645c7987cp-4L, -0x4.bdae53d810a91ac8p-4L, -0x4.bdae53d810a91acp-4L }, + { 0xd.13a5ae9285d253dp-4L, 0xc.3190e4f8d4d5582p-4L, 0xc.3190e4f8d4d5583p-4L }, + { -0x9.4cf62e7e77f656p-4L, -0x5.4e5f50857e68f51p-4L, -0x5.4e5f50857e68f508p-4L }, + { 0x2.84d9c1bc69548254p-4L, 0x1.d846c310aa00c054p-4L, 0x1.d846c310aa00c056p-4L }, + { -0x4.21ac0c75a3a7dbe8p-4L, -0x2.9f423cc607a168dcp-4L, -0x2.9f423cc607a168d8p-4L }, + { 0xd.b9bd68e165f831p-4L, 0xc.ff4f076046a69dp-4L, 0xc.ff4f076046a69d1p-4L }, + { -0x8.3fd61ad578cd929p-4L, -0x4.cecf6eabd87b7c9p-4L, -0x4.cecf6eabd87b7c88p-4L }, + { 0xf.30d46d764112444p-4L, 0xe.e5c6f47afffabf2p-4L, 0xe.e5c6f47afffabf3p-4L }, + { -0xb.cd4a73dc359d737p-4L, -0x6.6783a45e4e8dae2p-4L, -0x6.6783a45e4e8dae18p-4L }, + { 0x5.457d60a9148a985p-4L, 0x4.1ad19bfee71e48dp-4L, 0x4.1ad19bfee71e48d8p-4L }, + { -0x5.9e1738c1ccd8a9a8p-4L, -0x3.74c8e8a92c7f7b74p-4L, -0x3.74c8e8a92c7f7b7p-4L }, + { 0x1.497ab915f40b4518p-4L, 0xe.add4c95fb682b23p-8L, 0xe.add4c95fb682b24p-8L }, + { -0x4.8e012f7d7878b01p-4L, -0x2.dd78a1d7e408573cp-4L, -0x2.dd78a1d7e4085738p-4L }, + { 0x5.9d5fb6a6e532323p-4L, 0x4.67ef7a4d5b079348p-4L, 0x4.67ef7a4d5b07935p-4L }, + { -0x7.bc4dc1a54a48fdbp-4L, -0x4.8e51e755a24d00f8p-4L, -0x4.8e51e755a24d00fp-4L }, + { 0x3.fc5a846dfbec9adp-200L, 0x2.c3415566e5a54668p-200L, 0x2.c3415566e5a5466cp-200L }, + { -0x7.6980774d9eb5024p-128L, -0x5.233f7f59341a9e7p-128L, -0x5.233f7f59341a9e68p-128L }, + { 0xc.52f873b5b0d54efp-8L, 0x8.afc12e42adf7bacp-8L, 0x8.afc12e42adf7badp-8L }, + { -0x2.b8137644250c4bbcp-4L, -0x1.c7266a67c6352a0ap-4L, -0x1.c7266a67c6352a08p-4L }, + { 0x8.b13bd917a919d6p-4L, 0x7.50fc3760355aaba8p-4L, 0x7.50fc3760355aabbp-4L }, + { -0xd.a7e60f2da06694ep-4L, -0x7.2517f5997441288p-4L, -0x7.2517f59974412878p-4L }, + { 0x9.6d66afe84b35074p-4L, 0x8.121cbf603f1eb03p-4L, 0x8.121cbf603f1eb04p-4L }, + { -0x8.d45410dc1895ef4p-4L, -0x5.15e9564a5d57b1d8p-4L, -0x5.15e9564a5d57b1dp-4L }, + { 0x8.7112de739485f11p-4L, 0x7.108706705b67e1bp-4L, 0x7.108706705b67e1b8p-4L }, + { -0x5.28bf133fa6f14d3p-4L, -0x3.34615bbf1f08718cp-4L, -0x3.34615bbf1f087188p-4L }, + { 0x5.9ce42450cfaf8ee8p-4L, 0x4.67823dfabf51ea3p-4L, 0x4.67823dfabf51ea38p-4L }, + { -0x6.efb719daf136a1cp-4L, -0x4.271d11505413f6b8p-4L, -0x4.271d11505413f6bp-4L }, + { 0x9.ba0bd38df957e82p-8L, 0x6.d4e5a59f2ab3464p-8L, 0x6.d4e5a59f2ab34648p-8L }, + { -0x7.f37ea4723b67675p-4L, -0x4.a98e0f5848567a48p-4L, -0x4.a98e0f5848567a4p-4L }, + { 0x2.bf5897672b745798p-4L, 0x2.05b8d1dd696925cp-4L, 0x2.05b8d1dd696925c4p-4L }, + { -0x1.2b46b769cd53c99cp-4L, -0xc.a46ee1aa5cf6e29p-8L, -0xc.a46ee1aa5cf6e28p-8L }, + { 0x8.0d256afefef3c89p-4L, 0x6.ad850d0f71e9f0fp-4L, 0x6.ad850d0f71e9f0f8p-4L }, + { -0xa.e23fca6db43882fp-4L, -0x6.03d69b4a9fcb498p-4L, -0x6.03d69b4a9fcb4978p-4L }, + { 0x3.5d7f19c9107b35a4p-4L, 0x2.82ddd03061b78d4p-4L, 0x2.82ddd03061b78d44p-4L }, + { -0x4.0740585229be331p-4L, -0x2.8fe9890e66210b8p-4L, -0x2.8fe9890e66210b7cp-4L }, + { 0xb.2f2372351c33164p-8L, 0x7.deee40d7b054f0a8p-8L, 0x7.deee40d7b054f0bp-8L }, + { -0x1.e98b74b783fe8242p-4L, -0x1.45a6bc169044944ep-4L, -0x1.45a6bc169044944cp-4L }, + { 0x1.ef271536f1acac7cp-116L, 0x1.5736b36e46fd9e2p-116L, 0x1.5736b36e46fd9e22p-116L }, + { -0x2.f2b30898a501e344p-172L, -0x2.0b1e2354091a9a9p-172L, -0x2.0b1e2354091a9a8cp-172L }, + { 0xc.de09271a73942cap-4L, 0xb.f061a10e47f19afp-4L, 0xb.f061a10e47f19bp-4L }, + { -0xd.1fe6e25acc0107ap-4L, -0x6.f0515b52d3bc8b1p-4L, -0x6.f0515b52d3bc8b08p-4L }, + { 0x5.379d21e155802d5p-8L, 0x3.a458c1e822fc87b8p-8L, 0x3.a458c1e822fc87bcp-8L }, + { -0x7.f34a81711f9595fp-4L, -0x4.a974739e5e3c1ecp-4L, -0x4.a974739e5e3c1eb8p-4L }, + { 0x9.8f02fd2b4d10383p-4L, 0x8.3542c1ae328d562p-4L, 0x8.3542c1ae328d563p-4L }, + { -0x3.10d386b4ddaa9bccp-4L, -0x1.fd6c33e550a573ep-4L, -0x1.fd6c33e550a573dep-4L }, + { 0x8.a7f4a483fcced92p-4L, 0x7.479ee5100ad2768p-4L, 0x7.479ee5100ad27688p-4L }, + { -0x8.6ddd524df76f7bdp-4L, -0x4.e50a7bb2dd656468p-4L, -0x4.e50a7bb2dd65646p-4L }, + { 0xc.779757b60637763p-4L, 0xb.757468127d65f88p-4L, 0xb.757468127d65f89p-4L }, + { -0xe.777fe73bf0e9a48p-4L, -0x7.7359b3768a34b5c8p-4L, -0x7.7359b3768a34b5cp-4L }, + { 0x2.31b8036de80e551p-4L, 0x1.9875b4516816bbbep-4L, 0x1.9875b4516816bbcp-4L }, + { -0x9.0b16723fd236994p-4L, -0x5.2faf0a9074dea98p-4L, -0x5.2faf0a9074dea978p-4L }, + { 0x8.9a19522584fca8fp-4L, 0x7.39a98b528df1ef3p-4L, 0x7.39a98b528df1ef38p-4L }, + { -0xf.5402328fd9d6fdfp-4L, -0x7.c38432212a78edbp-4L, -0x7.c38432212a78eda8p-4L }, + { 0x3.39b72eedc5fb39acp-4L, 0x2.664255df780701c4p-4L, 0x2.664255df780701c8p-4L }, + { -0xc.d7d4b25d5ee54a4p-4L, -0x6.d3da67d23282e35p-4L, -0x6.d3da67d23282e348p-4L }, + { 0xf.002b8779c597ceep-4L, 0xe.a4e96c0af56d93ap-4L, 0xe.a4e96c0af56d93bp-4L }, + { -0x7.903eb3c7555e4358p-4L, -0x4.78651e55fe9e325p-4L, -0x4.78651e55fe9e3248p-4L }, + { 0x2.90b7822bc63776fcp-4L, 0x1.e17582d5a09ed40ap-4L, 0x1.e17582d5a09ed40cp-4L }, + { -0xb.887e64736056822p-4L, -0x6.4abf8763ec5ac7ep-4L, -0x6.4abf8763ec5ac7d8p-4L }, + { 0x1.4b3a350eb68541aep-20L, 0xe.596e40ce64dcf5ap-24L, 0xe.596e40ce64dcf5bp-24L }, + { -0x1.aef913a565a8bc1ap-128L, -0x1.2aba49d9af3d613p-128L, -0x1.2aba49d9af3d612ep-128L }, + { 0xc.8b02c285d275bd6p-4L, 0xb.8c97f1c3166348p-4L, 0xb.8c97f1c31663481p-4L }, + { -0x7.2ea947c351044f48p-4L, -0x4.473fa3759df5825p-4L, -0x4.473fa3759df58248p-4L }, + { 0xc.4830d91b64528bdp-4L, 0xb.3d4b68c0a1c1452p-4L, 0xb.3d4b68c0a1c1453p-4L }, + { -0xa.faff5d48675db64p-4L, -0x6.0e8570512dea4ae8p-4L, -0x6.0e8570512dea4aep-4L }, + { 0x1.456f46c72593c416p-4L, 0xe.7e6b02981c8b075p-8L, 0xe.7e6b02981c8b076p-8L }, + { -0x2.cdc53dd42a6cdf4cp-4L, -0x1.d47df5d7bd63c49ep-4L, -0x1.d47df5d7bd63c49cp-4L }, + { 0xd.de830895fc14d25p-4L, 0xd.2da568a29ea15dp-4L, 0xd.2da568a29ea15d1p-4L }, + { -0x1.d696938384c107e8p-4L, -0x1.39897019921dfe5ap-4L, -0x1.39897019921dfe58p-4L }, + { 0x3.5cde202fff810fdp-4L, 0x2.825cba775f96e8d4p-4L, 0x2.825cba775f96e8d8p-4L }, + { -0xb.0173bf64b3af081p-4L, -0x6.114cd4839031f808p-4L, -0x6.114cd4839031f8p-4L }, + { 0x9.ae157e1a5d07d3dp-4L, 0x8.55eee27b4bf2689p-4L, 0x8.55eee27b4bf268ap-4L }, + { -0x4.bded6e2f0ae69668p-4L, -0x2.f8a157b29a4320f8p-4L, -0x2.f8a157b29a4320f4p-4L }, + { 0xb.7b9077a770021aep-4L, 0xa.4ff4d2970ce8214p-4L, 0xa.4ff4d2970ce8215p-4L }, + { -0xe.794bdddad00436cp-4L, -0x7.740408ba771c01d8p-4L, -0x7.740408ba771c01dp-4L }, + { 0x8.bcfd1861de45b01p-4L, 0x7.5cdee4cb7bee481p-4L, 0x7.5cdee4cb7bee4818p-4L }, + { -0xa.ab4ea1951712b09p-4L, -0x5.ebf61acd701b7f68p-4L, -0x5.ebf61acd701b7f6p-4L }, + { 0x6.f81960839d640cdp-4L, 0x5.a39e8005baae39bp-4L, 0x5.a39e8005baae39b8p-4L }, + { -0x7.693a270061cf9de8p-4L, -0x4.64d777196e594488p-4L, -0x4.64d777196e59448p-4L }, + { 0xe.7b0648fc94495aap-4L, 0xd.f6213f610dcf21ep-4L, 0xd.f6213f610dcf21fp-4L }, + { -0xa.916b419fbe9fc1p-4L, -0x5.e0a2312a38c0e318p-4L, -0x5.e0a2312a38c0e31p-4L }, + { 0x1.89bd813bf1f6a1c2p-92L, 0x1.10eb819b2e242b1ep-92L, 0x1.10eb819b2e242b2p-92L }, + { -0x5.9293af393bd5fbfp-184L, -0x3.dcd3e77adc468a94p-184L, -0x3.dcd3e77adc468a9p-184L }, + { 0xd.3ea27eab88fb691p-4L, 0xc.6643216e56bbfb4p-4L, 0xc.6643216e56bbfb5p-4L }, + { -0xe.5d425700b9dfb9p-4L, -0x7.699c2694c5a2105p-4L, -0x7.699c2694c5a21048p-4L }, + { 0x7.ef30d4f5d43c309p-4L, 0x6.902a2db66b7bda78p-4L, 0x6.902a2db66b7bda8p-4L }, + { -0xc.2cc3adaa5f76bd8p-4L, -0x6.8ee23784f80cfdc8p-4L, -0x6.8ee23784f80cfdcp-4L }, + { 0x2.8b29e4e9b1677aap-4L, 0x1.dd28d0729a15749cp-4L, 0x1.dd28d0729a15749ep-4L }, + { -0xb.c9870bb9c74469p-4L, -0x6.65f306cc38bba318p-4L, -0x6.65f306cc38bba31p-4L }, + { 0x3.9b5a02bfcb72b468p-4L, 0x2.b4bb195f6468ceep-4L, 0x2.b4bb195f6468cee4p-4L }, + { -0x3.fcdc007ba74601ap-4L, -0x2.89db741e09207918p-4L, -0x2.89db741e09207914p-4L }, + { 0xf.8ea939c39a2414cp-8L, 0xb.038978e1848fbcep-8L, 0xb.038978e1848fbcfp-8L }, + { -0xd.38eafd3878fe2f4p-12L, -0x9.279f93a09aef86p-12L, -0x9.279f93a09aef85fp-12L }, + { 0x1.c55b237b57929914p-8L, 0x1.3aff3dbaa1f54462p-8L, 0x1.3aff3dbaa1f54464p-8L }, + { -0xe.5512393a7c3aa68p-4L, -0x7.668fce4e8d41ec3p-4L, -0x7.668fce4e8d41ec28p-4L }, + { 0x6.c72dbae38baf489p-4L, 0x5.75f2be10b3da51p-4L, 0x5.75f2be10b3da5108p-4L }, + { -0xa.9efab67bae298c4p-4L, -0x5.e692c461328f2a38p-4L, -0x5.e692c461328f2a3p-4L }, + { 0x6.d6fe2acf94b44bp-4L, 0x5.84abad9d09e7a7dp-4L, 0x5.84abad9d09e7a7d8p-4L }, + { -0x2.1052fcc75fe78e44p-4L, -0x1.5e50254d52c2cb86p-4L, -0x1.5e50254d52c2cb84p-4L }, + { 0xf.5f7e274f7549127p-4L, 0xf.247c06ed64581d2p-4L, 0xf.247c06ed64581d3p-4L }, + { -0xc.e3f378c5ed3afabp-4L, -0x6.d8aa145971328588p-4L, -0x6.d8aa14597132858p-4L }, + { 0x5.ed5d3988224f9748p-4L, 0x4.af2122809de98b08p-4L, 0x4.af2122809de98b1p-4L }, + { -0x3.ceeb00215e0d28fp-4L, -0x2.6ef600bcd292a928p-4L, -0x2.6ef600bcd292a924p-4L }, + { 0x1.81a67feedc219a8cp-160L, 0x1.0b4ffeb467c6a36cp-160L, 0x1.0b4ffeb467c6a36ep-160L }, + { -0x4.1c590bda30ba606p-76L, -0x2.d96e935fdb4f2c6p-76L, -0x2.d96e935fdb4f2c5cp-76L }, + { 0xc.afcea80015980b8p-4L, 0xb.b8a5752c99ff1d2p-4L, 0xb.b8a5752c99ff1d3p-4L }, + { -0xb.d8b227ae135fe8fp-4L, -0x6.6c4030ee2cb63a3p-4L, -0x6.6c4030ee2cb63a28p-4L }, + { 0x8.dc01d8b49232a17p-4L, 0x7.7c58fa948c1ea33p-4L, 0x7.7c58fa948c1ea338p-4L }, + { -0x1.933e5a044e710e98p-4L, -0x1.0e2f0aea0ed3f88ep-4L, -0x1.0e2f0aea0ed3f88cp-4L }, + { 0x1.a467d39df9435c82p-4L, 0x1.2e04d4c090c9af46p-4L, 0x1.2e04d4c090c9af48p-4L }, + { -0xd.177492196d07a44p-4L, -0x6.ecffef80c3115ef8p-4L, -0x6.ecffef80c3115efp-4L }, + { 0xa.8eb53214a5d4d15p-4L, 0x9.474ddcecd909225p-4L, 0x9.474ddcecd909226p-4L }, + { -0x1.8712ead1e57a5c3cp-4L, -0x1.064bf416745202b8p-4L, -0x1.064bf416745202b6p-4L }, + { 0x8.4de1b5d10a110dbp-4L, 0x6.ed77dcb741f173c8p-4L, 0x6.ed77dcb741f173dp-4L }, + { -0x2.5fb6ddfc66521d98p-4L, -0x1.904c98bb8b81f248p-4L, -0x1.904c98bb8b81f246p-4L }, + { 0x9.4d57927720bce2ap-4L, 0x7.f0c5a855860ee5c8p-4L, 0x7.f0c5a855860ee5dp-4L }, + { -0xd.c24a0c2da437c45p-8L, -0x9.5c8c25cb60521fp-8L, -0x9.5c8c25cb60521efp-8L }, + { 0xe.f5d12aeb5942b6bp-8L, 0xa.951ffb20b4a544dp-8L, 0xa.951ffb20b4a544ep-8L }, + { -0x1.6c160eed113f724cp-8L, -0xf.be148f1adb1e1fp-12L, -0xf.be148f1adb1e1efp-12L }, + { 0xe.5e4d4cc7965edb5p-4L, 0xd.d0f05f423ac4ecp-4L, 0xd.d0f05f423ac4ec1p-4L }, + { -0x9.fc2ec0983ea77b3p-4L, -0x5.9e5b37a59c48991p-4L, -0x5.9e5b37a59c489908p-4L }, + { 0xe.add7dabec19d155p-4L, 0xe.38603c1d1ea2234p-4L, 0xe.38603c1d1ea2235p-4L }, + { -0xe.ca8e0a5bcb1909bp-4L, -0x7.91e59560df20b59p-4L, -0x7.91e59560df20b588p-4L }, + { 0xf.3c4d21f42ce9eep-4L, 0xe.f525a7db23c77d2p-4L, 0xe.f525a7db23c77d3p-4L }, + { -0x6.a2b3b3cd69bd69p-4L, -0x3.ff5415c01005cd3p-4L, -0x3.ff5415c01005cd2cp-4L }, + { 0x1.5878b28462452782p-68L, 0xe.ec4f96d55b56cbap-72L, 0xe.ec4f96d55b56cbbp-72L }, + { -0xd.226b6159f1b8274p-176L, -0x9.1aa6ccef2946b71p-176L, -0x9.1aa6ccef2946b7p-176L }, + { 0xd.a2d0231770a0b2fp-4L, 0xc.e29042d0f0148dep-4L, 0xc.e29042d0f0148dfp-4L }, + { -0x5.88f950204ac58c2p-4L, -0x3.6949fabdeff8c62cp-4L, -0x3.6949fabdeff8c628p-4L }, + { 0xd.566e196c5299a76p-4L, 0xc.8398d1f51b7d57bp-4L, 0xc.8398d1f51b7d57cp-4L }, + { -0xd.827bfd05ebedd0fp-4L, -0x7.16b1fb3d30143fdp-4L, -0x7.16b1fb3d30143fc8p-4L }, + { 0xe.690353be92b1ef7p-4L, 0xd.dec96ccbdc54711p-4L, 0xd.dec96ccbdc54712p-4L }, + { -0xc.b40a6525370a3c1p-4L, -0x6.c59691f570ea335p-4L, -0x6.c59691f570ea3348p-4L }, + { 0x4.a16f62e1fb463d7p-4L, 0x3.8de59c3015480afp-4L, 0x3.8de59c3015480af4p-4L }, + { -0xb.6a308232b3be302p-4L, -0x6.3df86ee55414e478p-4L, -0x6.3df86ee55414e47p-4L }, + { 0xa.589c3c563d348fcp-4L, 0x9.0c54f3c1e94b5d5p-4L, 0x9.0c54f3c1e94b5d6p-4L }, + { -0xe.aaf84b1b375592p-4L, -0x7.8654b73051a16d2p-4L, -0x7.8654b73051a16d18p-4L }, + { 0x2.4225b8cb6a3450acp-4L, 0x1.a5000bbb5b20203p-4L, 0x1.a5000bbb5b202032p-4L }, + { -0x5.e1f5a13fb1e038ap-16L, -0x4.13d1b0bbfe40d278p-16L, -0x4.13d1b0bbfe40d27p-16L }, + { 0x6.501f9ed256bec01p-4L, 0x5.085e4ef770a5bbd8p-4L, 0x5.085e4ef770a5bbep-4L }, + { -0xa.0150779e90ebc75p-4L, -0x5.a0a9cac5cfa9e798p-4L, -0x5.a0a9cac5cfa9e79p-4L }, + { 0xd.5de12ee5f0afea5p-4L, 0xc.8cce152f519601bp-4L, 0xc.8cce152f519601cp-4L }, + { -0x8.16fa985eea51244p-4L, -0x4.baee6e9ee24b5858p-4L, -0x4.baee6e9ee24b585p-4L }, + { 0x2.32885a9f2271ac78p-4L, 0x1.991486e0e24975d2p-4L, 0x1.991486e0e24975d4p-4L }, + { -0x9.2c631a27ad6ae34p-4L, -0x5.3f3d59c428297e48p-4L, -0x5.3f3d59c428297e4p-4L }, + { 0xd.5153d9f62ecffddp-4L, 0xc.7d4bf03f0e6d411p-4L, 0xc.7d4bf03f0e6d412p-4L }, + { -0x2.e68bda95c5b3e06cp-4L, -0x1.e3ab538ce3f7ecdap-4L, -0x1.e3ab538ce3f7ecd8p-4L }, + { 0x7.a68b5532b0e7f568p-200L, 0x5.4d8f37527724f7d8p-200L, 0x5.4d8f37527724f7ep-200L }, + { -0x3.cd1483e1b10e99dp-84L, -0x2.a27cdd6c9a12d844p-84L, -0x2.a27cdd6c9a12d84p-84L }, + { 0xc.e8479ca0a43ef6p-8L, 0x9.1ad81877660b242p-8L, 0x9.1ad81877660b243p-8L }, + { -0x9.182ad6a367d08aep-4L, -0x5.35cdecfe5b731ce8p-4L, -0x5.35cdecfe5b731cep-4L }, + { 0x9.3029b8a7e85f35dp-4L, 0x7.d29571a8ad519618p-4L, 0x7.d29571a8ad51962p-4L }, + { -0xa.52ae9411f58887cp-4L, -0x5.c4f9aa019dcb689p-4L, -0x5.c4f9aa019dcb6888p-4L }, + { 0x7.5113a83ec9894cep-4L, 0x5.f7a9702b44563248p-4L, 0x5.f7a9702b4456325p-4L }, + { -0xd.13cf8aa40b87d27p-4L, -0x6.eb9109ecc7f4ddb8p-4L, -0x6.eb9109ecc7f4ddbp-4L }, + { 0xf.2395a1a0df7935bp-4L, 0xe.d411568c149c22fp-4L, 0xe.d411568c149c23p-4L }, + { -0x1.7af3bd8ca1f57c42p-4L, -0xf.e6caba0e492e4c1p-8L, -0xf.e6caba0e492e4cp-8L }, + { 0xd.f33b2053ffa6ae5p-4L, 0xd.47e1d5b0dd7bc76p-4L, 0xd.47e1d5b0dd7bc77p-4L }, + { -0xa.8e75c696dc40c78p-4L, -0x5.df55ef48a4e347e8p-4L, -0x5.df55ef48a4e347ep-4L }, + { 0x9.85d3f0dd48eaf72p-4L, 0x8.2ba30c3f7be89e3p-4L, 0x8.2ba30c3f7be89e4p-4L }, + { -0xd.506b8a6e4aa92acp-4L, -0x7.03491cf2bf49246p-4L, -0x7.03491cf2bf492458p-4L }, + { 0xa.d1883d4b01ef45ap-4L, 0x9.90e6441f511c6d1p-4L, 0x9.90e6441f511c6d2p-4L }, + { -0x3.08af0a00602595fp-4L, -0x1.f87a2c14dd7b7f16p-4L, -0x1.f87a2c14dd7b7f14p-4L }, + { 0xf.cac159b69035579p-4L, 0xf.b684c855d131bb2p-4L, 0xf.b684c855d131bb3p-4L }, + { -0x6.46e719cea85447d8p-4L, -0x3.cf38f95b6009617cp-4L, -0x3.cf38f95b60096178p-4L }, + { 0x5.987b05c45ed8a2ep-4L, 0x4.639c8775c1682ffp-4L, 0x4.639c8775c1682ff8p-4L }, + { -0x6.c4e52aa8d26db038p-4L, -0x4.110e8410a7512478p-4L, -0x4.110e8410a751247p-4L }, + { 0x8.23b5b38feb155f2p-4L, 0x6.c3bac23408a8825p-4L, 0x6.c3bac23408a88258p-4L }, + { -0x8.ad2a11b7f1b5ea6p-4L, -0x5.0354fe71cc130f2p-4L, -0x5.0354fe71cc130f18p-4L }, + { 0xf.af53dc003c2e966p-112L, 0xa.df368663af3dfc2p-112L, 0xa.df368663af3dfc3p-112L }, + { -0x3.f7b5578e89e3d3e8p-128L, -0x2.c0090f63161770cp-128L, -0x2.c0090f63161770bcp-128L }, + { 0x3.73e18f430b288f48p-4L, 0x2.94d9fe08f28f346cp-4L, 0x2.94d9fe08f28f347p-4L }, + { -0xc.f70837877517a74p-4L, -0x6.e03802a500a2e72p-4L, -0x6.e03802a500a2e718p-4L }, + { 0x7.3487f80314c54488p-4L, 0x5.dc8fba31d9f318ep-4L, 0x5.dc8fba31d9f318e8p-4L }, + { -0x5.4eccb9e96eb8967p-4L, -0x3.4967fb3eb0a4d81cp-4L, -0x3.4967fb3eb0a4d818p-4L }, + { 0x9.44460917d619271p-4L, 0x7.e75fbc9c380ed29p-4L, 0x7.e75fbc9c380ed298p-4L }, + { -0xd.5620dcdef8d6adep-4L, -0x7.0581c9d72c7b4df8p-4L, -0x7.0581c9d72c7b4dfp-4L }, + { 0xd.105984ee31d1a19p-4L, 0xc.2d8a202b2771e41p-4L, 0xc.2d8a202b2771e42p-4L }, + { -0xe.cb19e0196a54de2p-4L, -0x7.9218a6517e6df27p-4L, -0x7.9218a6517e6df268p-4L }, + { 0x5.b49471d499a4cf1p-4L, 0x4.7c7d8b0af0f48c28p-4L, 0x4.7c7d8b0af0f48c3p-4L }, + { -0x9.94f5bdecfacab51p-8L, -0x6.8e6561102f3ee5e8p-8L, -0x6.8e6561102f3ee5ep-8L }, + { 0xf.641993c9a620462p-4L, 0xf.2ab3dcfcad4c33ap-4L, 0xf.2ab3dcfcad4c33bp-4L }, + { -0xd.a2dd238869b2787p-4L, -0x7.23294ba101bfcb28p-4L, -0x7.23294ba101bfcb2p-4L }, + { 0xd.4c3f10c6378bac1p-4L, 0xc.77072f3026675d1p-4L, 0xc.77072f3026675d2p-4L }, + { -0xd.a0da38c144c364ap-4L, -0x7.22638fd7197afdbp-4L, -0x7.22638fd7197afda8p-4L }, + { 0x5.9e57359c4cf1067p-4L, 0x4.68ca49a0fa5b5d78p-4L, 0x4.68ca49a0fa5b5d8p-4L }, + { -0xf.5afa51a915c3c2cp-4L, -0x7.c600693d7adedab8p-4L, -0x7.c600693d7adedabp-4L }, + { 0xa.7324ede2d5b774ep-4L, 0x9.29307a00e1a50c1p-4L, 0x9.29307a00e1a50c2p-4L }, + { -0x4.deb94e5dff32647p-4L, -0x3.0b17181ece0d3c68p-4L, -0x3.0b17181ece0d3c64p-4L }, + { 0x6.67af9a1b48f5476p-4L, 0x5.1de173c8b6ffd77p-4L, 0x5.1de173c8b6ffd778p-4L }, + { -0xb.916f204d9b607e2p-4L, -0x6.4e815e5c604ec948p-4L, -0x6.4e815e5c604ec94p-4L }, + { 0x9.a94b7284791aef1p-88L, 0x6.b25b7556a0da05f8p-88L, 0x6.b25b7556a0da06p-88L }, + { -0x7.986b2cd7ddf22268p-132L, -0x5.43c4afc7229c434p-132L, -0x5.43c4afc7229c4338p-132L }, + { 0x1.15035f9ba3aac31ep-4L, 0xc.49523582a5e80c3p-8L, 0xc.49523582a5e80c4p-8L }, + { -0xc.6f90a760827aa89p-4L, -0x6.aa0dc49e51cdac1p-4L, -0x6.aa0dc49e51cdac08p-4L }, + { 0xf.fef4a753b10a076p-4L, 0xf.fe8d6976d07d14bp-4L, 0xf.fe8d6976d07d14cp-4L }, + { -0x6.4c2eb46758106918p-4L, -0x3.d202750df16f62a4p-4L, -0x3.d202750df16f62ap-4L }, + { 0x1.3ef509e0c382df66p-4L, 0xe.328e01d44f681dp-8L, 0xe.328e01d44f681d1p-8L }, + { -0xc.49b63ac9b2b9eaap-4L, -0x6.9ab1ff6082b3beap-4L, -0x6.9ab1ff6082b3be98p-4L }, + { 0x6.d057f880739cc278p-4L, 0x5.7e79c56f2d15b708p-4L, 0x5.7e79c56f2d15b71p-4L }, + { -0xb.1981c21be406601p-4L, -0x6.1ba12bbd58b2c01p-4L, -0x6.1ba12bbd58b2c008p-4L }, + { 0x8.0a6f57c957a28d4p-4L, 0x6.aadb51c6015dbep-4L, 0x6.aadb51c6015dbe08p-4L }, + { -0x5.f3f181c210c8a89p-4L, -0x3.a319fd0750dac56p-4L, -0x3.a319fd0750dac55cp-4L }, + { 0xe.2859c8a2c48c40ap-4L, 0xd.8b91686f98b11bdp-4L, 0xd.8b91686f98b11bep-4L }, + { -0xa.dd44c44ce7a5755p-4L, -0x6.01aed71b7ef78488p-4L, -0x6.01aed71b7ef7848p-4L }, + { 0xb.51ba4b350a61c32p-4L, 0xa.206f7762d17482bp-4L, 0xa.206f7762d17482cp-4L }, + { -0xc.0dfbf7e5e3212ffp-12L, -0x8.58dc6a67dabce9bp-12L, -0x8.58dc6a67dabce9ap-12L }, + { 0x7.6c639e488208ccc8p-4L, 0x6.11b6da6b26aebcd8p-4L, 0x6.11b6da6b26aebcep-4L }, + { -0x3.a1d6c7b434bf3d98p-4L, -0x2.545d932e669d3904p-4L, -0x2.545d932e669d39p-4L }, + { 0x5.c358113ef832c348p-4L, 0x4.899c27db749b1de8p-4L, 0x4.899c27db749b1dfp-4L }, + { -0xb.d7d98c530f97875p-4L, -0x6.6be6509d664dfbbp-4L, -0x6.6be6509d664dfba8p-4L }, + { 0x4.fa42d3ac3bebd7e8p-4L, 0x3.d9b642da220bca6p-4L, 0x3.d9b642da220bca64p-4L }, + { -0xa.5b3f67eed42f35ep-4L, -0x5.c8c4d54ed02eeb08p-4L, -0x5.c8c4d54ed02eebp-4L }, + { 0x8.df34d29839f6cbap-140L, 0x6.2647bfc5682b23d8p-140L, 0x6.2647bfc5682b23ep-140L }, + { -0x4.37cad4bbf2a5aa78p-108L, -0x2.ec747a81313e72acp-108L, -0x2.ec747a81313e72a8p-108L }, + { 0x1.d6566fbbd43703bcp-4L, 0x1.5356ad8698dd1454p-4L, 0x1.5356ad8698dd1456p-4L }, + { -0x5.7c58e6c483f58898p-4L, -0x3.6265408f3b9628d4p-4L, -0x3.6265408f3b9628dp-4L }, + { 0x4.6a4204ea8eeaab98p-4L, 0x3.5f5f5a4b33974f1p-4L, 0x3.5f5f5a4b33974f14p-4L }, + { -0x8.3dccba3b25f76c1p-4L, -0x4.cdd2979cf80fe2a8p-4L, -0x4.cdd2979cf80fe2ap-4L }, + { 0xd.5f0d592ded19983p-4L, 0xc.8e415fdd3807e8fp-4L, 0xc.8e415fdd3807e9p-4L }, + { -0xa.c3b832d5003b707p-8L, -0x7.5a8d2a98b9c25298p-8L, -0x7.5a8d2a98b9c2529p-8L }, + { 0xa.1061f8f22c56a2p-4L, 0x8.be6ebf67d3a8ca6p-4L, 0x8.be6ebf67d3a8ca7p-4L }, + { -0x7.a0e695df486975a8p-4L, -0x4.80b3df37bd2da46p-4L, -0x4.80b3df37bd2da458p-4L }, + { 0x2.0f49c0d924c5ef48p-4L, 0x1.7e4a674b14e39638p-4L, 0x1.7e4a674b14e3963ap-4L }, + { -0x2.98c242e38ab361a4p-4L, -0x1.b3cdb6359889897cp-4L, -0x1.b3cdb6359889897ap-4L }, + { 0xe.a88d8d085eb83b1p-4L, 0xe.3173fc65ba950ccp-4L, 0xe.3173fc65ba950cdp-4L }, + { -0x7.18f85d323644c07p-4L, -0x4.3c36aae8265e794p-4L, -0x4.3c36aae8265e7938p-4L }, + { 0xb.e3d76e1e4bf5645p-8L, 0x8.6028af6e8498d12p-8L, 0x8.6028af6e8498d13p-8L }, + { -0xa.e3f91773dee5cbdp-4L, -0x6.0495789dfe04b06p-4L, -0x6.0495789dfe04b058p-4L }, + { 0x6.64a485a65ba2bb8p-4L, 0x5.1b18ec86f4768a78p-4L, 0x5.1b18ec86f4768a8p-4L }, + { -0xb.ab5d793764e46aap-4L, -0x6.595eea36719ee3p-4L, -0x6.595eea36719ee2f8p-4L }, + { 0x4.180ed04588b6b84p-4L, 0x3.1add121478e2fe34p-4L, 0x3.1add121478e2fe38p-4L }, + { -0x3.1b46b393f7f02654p-4L, -0x2.03c27049f1c5241p-4L, -0x2.03c27049f1c5240cp-4L }, + { 0xb.12b6b696713dd3p-4L, 0x9.d97de4a57a62c6ep-4L, 0x9.d97de4a57a62c6fp-4L }, + { -0x4.65ce2cb3797b29a8p-12L, -0x3.0c0efb555fa20864p-12L, -0x3.0c0efb555fa2086p-12L }, + { 0x2.8d217b257289e3ccp-48L, 0x1.c4b73c33ff87c0a6p-48L, 0x1.c4b73c33ff87c0a8p-48L }, + { -0x6.2775ae1abb4f1b8p-132L, -0x4.44068348b3cc65f8p-132L, -0x4.44068348b3cc65fp-132L }, + { 0x7.9916813ff5ff3cc8p-4L, 0x6.3c9c97e7b3dc5dcp-4L, 0x6.3c9c97e7b3dc5dc8p-4L }, + { -0xe.8cc5489d5bd410dp-4L, -0x7.7b36e89d757a4abp-4L, -0x7.7b36e89d757a4aa8p-4L }, + { 0x4.332914d9e18063ap-4L, 0x3.3158c643f12f4994p-4L, 0x3.3158c643f12f4998p-4L }, + { -0xb.0de0f587f5c107fp-4L, -0x6.16a43bbcf353ca98p-4L, -0x6.16a43bbcf353ca9p-4L }, + { 0x7.8ea9558f03ae0e7p-4L, 0x6.32938e784969b998p-4L, 0x6.32938e784969b9ap-4L }, + { -0xf.dee9088b413455fp-4L, -0x7.f47ff39c1d7b3888p-4L, -0x7.f47ff39c1d7b388p-4L }, + { 0x8.2df8e53739c9b8bp-4L, 0x6.cddbf2a3d58ac5cp-4L, 0x6.cddbf2a3d58ac5c8p-4L }, + { -0xb.237c6168dab68dbp-4L, -0x6.1fe702218f1a48a8p-4L, -0x6.1fe702218f1a48ap-4L }, + { 0xc.ff8006e798ca57dp-4L, 0xc.190015c68329532p-4L, 0xc.190015c68329533p-4L }, + { -0x5.a01080821eed49f8p-4L, -0x3.75db7123ab84cf58p-4L, -0x3.75db7123ab84cf54p-4L }, + { 0x7.837abefd5e55df78p-4L, 0x6.27d5641a6c02fc68p-4L, 0x6.27d5641a6c02fc7p-4L }, + { -0x3.5060ef99941b0558p-4L, -0x2.23c9d923cd4adb98p-4L, -0x2.23c9d923cd4adb94p-4L }, + { 0xe.81ed35e6e8294cep-4L, 0xd.ff1805c791d6424p-4L, 0xd.ff1805c791d6425p-4L }, + { -0x4.bb21255de4a41a5p-4L, -0x2.f70cf4785702e974p-4L, -0x2.f70cf4785702e97p-4L }, + { 0x2.a7771004562ceed4p-4L, 0x1.f31d427f09d18b7cp-4L, 0x1.f31d427f09d18b7ep-4L }, + { -0x1.6959757c92243a3ap-4L, -0xf.2f6ce0c9b166b49p-8L, -0xf.2f6ce0c9b166b48p-8L }, + { 0x6.bbde2a7543c30b38p-4L, 0x5.6b71442a60dd2568p-4L, 0x5.6b71442a60dd257p-4L }, + { -0xb.8edecd5dd38da0cp-4L, -0x6.4d6db28b17aa8588p-4L, -0x6.4d6db28b17aa858p-4L }, + { 0x6.c15f52803f443968p-4L, 0x5.708d7c1ba353e398p-4L, 0x5.708d7c1ba353e3ap-4L }, + { -0x3.918ec1969b0edd88p-4L, -0x2.4ab5c149bf41c4c4p-4L, -0x2.4ab5c149bf41c4cp-4L }, + { 0x7.7b238d3b9d8115e8p-120L, 0x5.2f791dc93f08299p-120L, 0x5.2f791dc93f082998p-120L }, + { -0x1.9f3582a69a86e648p-60L, -0x1.1fcd0c091eb14d28p-60L, -0x1.1fcd0c091eb14d26p-60L }, + { 0x6.81487cec2e861c7p-8L, 0x4.8c82f180777d68f8p-8L, 0x4.8c82f180777d69p-8L }, + { -0x4.87a7a304beeda28p-4L, -0x2.d9db282588789b7cp-4L, -0x2.d9db282588789b78p-4L }, + { 0xd.c7238c1ad3cafc9p-4L, 0xd.1028e60f36ff2b1p-4L, 0xd.1028e60f36ff2b2p-4L }, + { -0xe.ac1774f7032d1ffp-4L, -0x7.86be2433cc1d9da8p-4L, -0x7.86be2433cc1d9dap-4L }, + { 0x8.fc6153c653d77c7p-4L, 0x7.9d6025bd14094ad8p-4L, 0x7.9d6025bd14094aep-4L }, + { -0x1.014e18840001d972p-4L, -0xa.e85ead1a4e78382p-8L, -0xa.e85ead1a4e78381p-8L }, + { 0x5.040eb8c257682f18p-4L, 0x3.e224b9c7d7c0f06cp-4L, 0x3.e224b9c7d7c0f07p-4L }, + { -0xf.7346ad82e18af85p-4L, -0x7.cea4b926fe7c2368p-4L, -0x7.cea4b926fe7c236p-4L }, + { 0x3.c7346df124e8ef98p-4L, 0x2.d8668c024b6308e8p-4L, 0x2.d8668c024b6308ecp-4L }, + { -0xc.f461f50edbbb96fp-4L, -0x6.df2bda27bd06182p-4L, -0x6.df2bda27bd061818p-4L }, + { 0xd.c278b0558bd0b11p-4L, 0xd.0a4916e65159357p-4L, 0xd.0a4916e65159358p-4L }, + { -0x4.b2842fc0d4e29f8p-4L, -0x2.f22eea0353ff92dp-4L, -0x2.f22eea0353ff92ccp-4L }, + { 0xf.a09a22b402060edp-4L, 0xf.7ccfec40ad06d7ep-4L, 0xf.7ccfec40ad06d7fp-4L }, + { -0x8.e32395dc002f9bfp-8L, -0x6.162efd7ddd7ad93p-8L, -0x6.162efd7ddd7ad928p-8L }, + { 0xf.8c0db00bdf53596p-4L, 0xf.60d4a396fb9dadcp-4L, 0xf.60d4a396fb9daddp-4L }, + { -0x5.36e056abcab2faa8p-4L, -0x3.3c3413c718ca2bf4p-4L, -0x3.3c3413c718ca2bfp-4L }, + { 0x7.6c92e56712d5affp-4L, 0x6.11e40e1716fd4fb8p-4L, 0x6.11e40e1716fd4fcp-4L }, + { -0xd.6cb0532deaf2679p-4L, -0x7.0e43f2e8f0654b5p-4L, -0x7.0e43f2e8f0654b48p-4L }, + { 0x1.864d5d5420279f0cp-4L, 0x1.17abd4dea55c6812p-4L, 0x1.17abd4dea55c6814p-4L }, + { -0xa.e4299f2f9dca735p-4L, -0x6.04aa7510ef638d5p-4L, -0x6.04aa7510ef638d48p-4L }, + { 0xe.d132e5394f60034p-128L, 0xa.453ebc4a42e6cb8p-128L, 0xa.453ebc4a42e6cb9p-128L }, + { -0x2.35600cb5057b0fe8p-100L, -0x1.87e3627dc194acb4p-100L, -0x1.87e3627dc194acb2p-100L }, + { 0x9.ea2a7bd17c460dep-4L, 0x8.95993518360a117p-4L, 0x8.95993518360a118p-4L }, + { -0xe.c5d9227ffaac8cfp-4L, -0x7.902d5e9f35d6cfa8p-4L, -0x7.902d5e9f35d6cfap-4L }, + { 0x7.e3d1eea20b324e7p-4L, 0x6.850f961c58bba1cp-4L, 0x6.850f961c58bba1c8p-4L }, + { -0x9.86088a50194e78ap-4L, -0x5.68af5d2483728da8p-4L, -0x5.68af5d2483728dap-4L }, + { 0xf.7fa93e24f531607p-4L, 0xf.5000aaa67e5abb3p-4L, 0xf.5000aaa67e5abb4p-4L }, + { -0x6.3df2b4ad8ed98938p-4L, -0x3.ca7d689c3a04ee1cp-4L, -0x3.ca7d689c3a04ee18p-4L }, + { 0xe.e19314560029718p-4L, 0xe.7c6642b7e0cbddap-4L, 0xe.7c6642b7e0cbddbp-4L }, + { -0xa.e3c3bdecf1dec26p-8L, -0x7.701f272b4e954b3p-8L, -0x7.701f272b4e954b28p-8L }, + { 0x7.13c978b522f9333p-4L, 0x5.bda2c8c3fcf67318p-4L, 0x5.bda2c8c3fcf6732p-4L }, + { -0xd.81aab9ad9044dbbp-4L, -0x7.16613057101cc2e8p-4L, -0x7.16613057101cc2ep-4L }, + { 0x1.1d1ed153b343c44ep-4L, 0xc.a79cde97e744a1p-8L, 0xc.a79cde97e744a11p-8L }, + { -0x7.6fdb8f997549cde8p-8L, -0x5.1a74b0bff8212ac8p-8L, -0x5.1a74b0bff8212acp-8L }, + { 0x9.e81deac115960bcp-4L, 0x8.936a9f1de1dc2c9p-4L, 0x8.936a9f1de1dc2cap-4L }, + { -0xf.6e420d340620fd3p-4L, -0x7.ccdc951843f633f8p-4L, -0x7.ccdc951843f633fp-4L }, + { 0xe.6c4b7e894887c7fp-4L, 0xd.e308edc7c69afe9p-4L, 0xd.e308edc7c69afeap-4L }, + { -0xa.a620eccc4c7480bp-4L, -0x5.e9b3097aa5fb3aep-4L, -0x5.e9b3097aa5fb3ad8p-4L }, + { 0x1.c456c45ad9be2a9p-4L, 0x1.45d98d5ceaac11ecp-4L, 0x1.45d98d5ceaac11eep-4L }, + { -0x3.af9571884b9dea6cp-4L, -0x2.5c7f00327abdcc8cp-4L, -0x2.5c7f00327abdcc88p-4L }, + { 0xb.a0a2f3e13b85a66p-4L, 0xa.7a58fb959132f5p-4L, 0xa.7a58fb959132f51p-4L }, + { -0x1.574d5a4e81cea558p-4L, -0xe.72dbed0cf3f04efp-8L, -0xe.72dbed0cf3f04eep-8L }, + { 0x2.4592a2ef43290dcp-184L, 0x1.931d946725be0bacp-184L, 0x1.931d946725be0baep-184L }, + { -0x2.1340349dc88fe5ap-148L, -0x1.703c28b59101b778p-148L, -0x1.703c28b59101b776p-148L }, + { 0xc.52069130f81cabfp-8L, 0x8.af13d4a97a211afp-8L, 0x8.af13d4a97a211bp-8L }, + { -0x4.20c946d47a37871p-4L, -0x2.9ebecd164da3800cp-4L, -0x2.9ebecd164da38008p-4L }, + { 0xc.ad96dfac7b95172p-4L, 0xb.b5fbb7908197649p-4L, 0xb.b5fbb790819764ap-4L }, + { -0x1.1fc7d37c0ec92196p-4L, -0xc.2b1ec45e46b2f21p-8L, -0xc.2b1ec45e46b2f2p-8L }, + { 0xd.0d8c22a9e6d3c5p-4L, 0xc.2a1e9cdc9f50a83p-4L, 0xc.2a1e9cdc9f50a84p-4L }, + { -0x8.c7054bd7b8a06d5p-4L, -0x5.0f9cb256bb7dc48p-4L, -0x5.0f9cb256bb7dc478p-4L }, + { 0x5.13c1489191b10628p-4L, 0x3.efaed7947e426ea4p-4L, 0x3.efaed7947e426ea8p-4L }, + { -0x9.40268306f3eaf37p-4L, -0x5.486e4611a98deb68p-4L, -0x5.486e4611a98deb6p-4L }, + { 0x4.8b3a84ec2d62ab1p-4L, 0x3.7b1edaf9b2695bacp-4L, 0x3.7b1edaf9b2695bbp-4L }, + { -0x2.971ee88e20aca63cp-4L, -0x1.b2c9edea76d921ap-4L, -0x1.b2c9edea76d9219ep-4L }, + { 0x3.f7343ff72e27615cp-4L, 0x2.ffbf501a1f86d97cp-4L, 0x2.ffbf501a1f86d98p-4L }, + { -0xc.f38290b95d0f886p-4L, -0x6.ded38151017c9f78p-4L, -0x6.ded38151017c9f7p-4L }, + { 0x6.19ec462854667938p-4L, 0x4.d73549a9496846e8p-4L, 0x4.d73549a9496846fp-4L }, + { -0xe.a753d50ad228a17p-4L, -0x7.84fe3ea5ac9675c8p-4L, -0x7.84fe3ea5ac9675cp-4L }, + { 0xb.2326e5c709d8338p-4L, 0x9.ebecfa9a7ed2102p-4L, 0x9.ebecfa9a7ed2103p-4L }, + { -0xe.4cbeeba038e2a66p-4L, -0x7.63754094094d3058p-4L, -0x7.63754094094d305p-4L }, + { 0x9.90137db5d8438f6p-4L, 0x8.36609082c07d8ebp-4L, 0x8.36609082c07d8ecp-4L }, + { -0x8.f6fc2825e1cf803p-4L, -0x5.26400e89ac84512p-4L, -0x5.26400e89ac845118p-4L }, + { 0xb.a6e18f1dc982de2p-4L, 0xa.8183a9b9420a005p-4L, 0xa.8183a9b9420a006p-4L }, + { -0x7.093038cd340d2eap-4L, -0x4.3428c5f7bc4908e8p-4L, -0x4.3428c5f7bc4908ep-4L }, + { 0x1.7d48f31379a2fd94p-16L, 0x1.0849e6ab4023994ep-16L, 0x1.0849e6ab4023995p-16L }, + { -0xe.811989909a6ff03p-172L, -0xa.0db9811ffb53051p-172L, -0xa.0db9811ffb5305p-172L }, + { 0xf.a038fe23264b69fp-4L, 0xf.7c4b6a476a8be7cp-4L, 0xf.7c4b6a476a8be7dp-4L }, + { -0x5.d983ceba22bba45p-4L, -0x3.94ea4ac9f11d384cp-4L, -0x3.94ea4ac9f11d3848p-4L }, + { 0x3.aaf0ce3e734d6f2p-4L, 0x2.c161688c554ee7fcp-4L, 0x2.c161688c554ee8p-4L }, + { -0xf.72f358999238d68p-4L, -0x7.ce872556e868c9d8p-4L, -0x7.ce872556e868c9dp-4L }, + { 0x6.4d100f244be8113p-4L, 0x5.059488ceb9e3a5p-4L, 0x5.059488ceb9e3a508p-4L }, + { -0x8.8a2584d61c785a5p-4L, -0x4.f29d6d10179eb218p-4L, -0x4.f29d6d10179eb21p-4L }, + { 0xd.c98d7189a0303bfp-4L, 0xd.133307457e07c72p-4L, 0xd.133307457e07c73p-4L }, + { -0x1.4471ec132a54d16ap-4L, -0xd.ad37019fa9d9a9p-8L, -0xd.ad37019fa9d9a8fp-8L }, + { 0xb.bac11f4e1e14036p-4L, 0xa.985f73784b37eb5p-4L, 0xa.985f73784b37eb6p-4L }, + { -0x5.f466fe6cbdda3498p-4L, -0x3.a358e8e63a5fba64p-4L, -0x3.a358e8e63a5fba6p-4L }, + { 0xb.650503cc7e3186cp-4L, 0xa.364e81e99eb81f3p-4L, 0xa.364e81e99eb81f4p-4L }, + { -0x1.5d03274c615fac7ep-4L, -0xe.ae956d0835aaf87p-8L, -0xe.ae956d0835aaf86p-8L }, + { 0xf.e3a0ddc922c2768p-4L, 0xf.d8c34a986f967d3p-4L, 0xf.d8c34a986f967d4p-4L }, + { -0xa.669f21ff1f04159p-4L, -0x5.cdcc37c6f732fe1p-4L, -0x5.cdcc37c6f732fe08p-4L }, + { 0x8.ab617e168652f41p-4L, 0x7.4b137892a0c69d88p-4L, 0x7.4b137892a0c69d9p-4L }, + { -0xa.9ceb33ff19c471bp-4L, -0x5.e5abee4fb863c6ep-4L, -0x5.e5abee4fb863c6d8p-4L }, + { 0x7.e712d33d338b3f4p-4L, 0x6.883c6044c3c2bcb8p-4L, 0x6.883c6044c3c2bccp-4L }, + { -0x6.ed724b0ecd1acf48p-4L, -0x4.25f2ea71fb90ba5p-4L, -0x4.25f2ea71fb90ba48p-4L }, + { 0xb.0f353c55a1bc86bp-4L, 0x9.d59127340917f95p-4L, 0x9.d59127340917f96p-4L }, + { -0xa.9ea90fbdcd33289p-4L, -0x5.e66f0ac4d504378p-4L, -0x5.e66f0ac4d5043778p-4L }, + { 0x1.8d57c92ab74b5dbp-36L, 0x1.136ac861af6fd0cep-36L, 0x1.136ac861af6fd0dp-36L }, + { -0x5.db625c7f505b3848p-168L, -0x4.0f4b402286520448p-168L, -0x4.0f4b40228652044p-168L }, + { 0x2.b76e057b32691f28p-4L, 0x1.ff8b9dda8f045aep-4L, 0x1.ff8b9dda8f045ae2p-4L }, + { -0x6.dee852c47ad7ae6p-4L, -0x4.1e798f7b43706028p-4L, -0x4.1e798f7b4370602p-4L }, + { 0x6.bb1bf54be9664e8p-4L, 0x5.6abd10b33410d838p-4L, 0x5.6abd10b33410d84p-4L }, + { -0x6.aee79d84df01a37p-4L, -0x4.05aac336cc0ddf4p-4L, -0x4.05aac336cc0ddf38p-4L }, + { 0xf.db239caa0c58725p-4L, 0xf.cd0f1aa065d9edcp-4L, 0xf.cd0f1aa065d9eddp-4L }, + { -0x6.a15fc994e42a5f98p-4L, -0x3.fea35173a1f28d58p-4L, -0x3.fea35173a1f28d54p-4L }, + { 0xe.d6bf659b8abbf88p-4L, 0xe.6e1d0b3dcc929a2p-4L, 0xe.6e1d0b3dcc929a3p-4L }, + { -0x6.3520edf48c502b48p-4L, -0x3.c5d25806006121bcp-4L, -0x3.c5d25806006121b8p-4L }, + { 0x2.845d2338bd21f05cp-4L, 0x1.d7e66d41d318c988p-4L, 0x1.d7e66d41d318c98ap-4L }, + { -0x1.d3130e0c084f14c8p-4L, -0x1.37497e3ebaa67dcap-4L, -0x1.37497e3ebaa67dc8p-4L }, + { 0x7.e34ef80c4f7e3eep-4L, 0x6.848fd32b674801d8p-4L, 0x6.848fd32b674801ep-4L }, + { -0x5.a8b3cf39973ba25p-4L, -0x3.7a8bd473e711806cp-4L, -0x3.7a8bd473e7118068p-4L }, + { 0xa.b5fcccca163aaedp-4L, 0x9.727686834a4ee16p-4L, 0x9.727686834a4ee17p-4L }, + { -0x9.80fe0cfc3618055p-4L, -0x5.665f01272fca1dfp-4L, -0x5.665f01272fca1de8p-4L }, + { 0x1.deff9f28444c6c38p-4L, 0x1.59d80e0bc88e7a36p-4L, 0x1.59d80e0bc88e7a38p-4L }, + { -0x9.1da1f7cda29486bp-4L, -0x5.385b9fa450441c1p-4L, -0x5.385b9fa450441c08p-4L }, + { 0x9.24964216848ef53p-4L, 0x7.c6a60a15ee989f5p-4L, 0x7.c6a60a15ee989f58p-4L }, + { -0x7.c3b5a7c39208799p-4L, -0x4.91fd41abd0551208p-4L, -0x4.91fd41abd05512p-4L }, + { 0xc.7f839e0758c0fc4p-4L, 0xb.7ee2c8991a66c5bp-4L, 0xb.7ee2c8991a66c5cp-4L }, + { -0xa.04266867c71fecep-4L, -0x5.a1efea5e48c556e8p-4L, -0x5.a1efea5e48c556ep-4L }, + { 0x3.1aa2b36a1fb87f7cp-48L, 0x2.26cca4e6218f7cc8p-48L, 0x2.26cca4e6218f7cccp-48L }, + { -0x1.ba95b94050477ba6p-152L, -0x1.32c6c531dafa9e4p-152L, -0x1.32c6c531dafa9e3ep-152L }, + { 0x6.108af52b9d9b2bp-4L, 0x4.cebef902a16e9c8p-4L, 0x4.cebef902a16e9c88p-4L }, + { -0x3.072eed70b90d2ae8p-4L, -0x1.f790b03dd687e68cp-4L, -0x1.f790b03dd687e68ap-4L }, + { 0xb.ad44f9f8ad944a6p-4L, 0xa.88da98fd452a1b5p-4L, 0xa.88da98fd452a1b6p-4L }, + { -0xb.3fef5d7e57e0805p-4L, -0x6.2c0b5071c8e72768p-4L, -0x6.2c0b5071c8e7276p-4L }, + { 0xe.b53f2b3083d023ep-4L, 0xe.42131e5b55a520bp-4L, 0xe.42131e5b55a520cp-4L }, + { -0xb.f408f69524f06c2p-4L, -0x6.779147008107f7cp-4L, -0x6.779147008107f7b8p-4L }, + { 0x8.03baca4a7357516p-4L, 0x6.a446a2fcb76d806p-4L, 0x6.a446a2fcb76d8068p-4L }, + { -0xa.c1abbb69e26abf7p-4L, -0x5.f5b5017c8517f208p-4L, -0x5.f5b5017c8517f2p-4L }, + { 0x1.d872e7eedaaa637ep-4L, 0x1.54ec695ac1dbc924p-4L, 0x1.54ec695ac1dbc926p-4L }, + { -0x4.495ee30da4659e98p-4L, -0x2.b6306706e0bbaac4p-4L, -0x2.b6306706e0bbaacp-4L }, + { 0xc.150a73ee88aac4bp-4L, 0xb.0131f0d15ff1b5p-4L, 0xb.0131f0d15ff1b51p-4L }, + { -0xa.3e82e32d6766963p-4L, -0x5.bc052d79040a9f88p-4L, -0x5.bc052d79040a9f8p-4L }, + { 0x6.08720c311ad69e78p-4L, 0x4.c773b03aa96a3fc8p-4L, 0x4.c773b03aa96a3fdp-4L }, + { -0x7.3b6b4ffd7b8decp-8L, -0x4.f6d2acdaf77fd21p-8L, -0x4.f6d2acdaf77fd208p-8L }, + { 0x5.80db9fe644d1e708p-4L, 0x4.4ec994b6102856dp-4L, 0x4.4ec994b6102856d8p-4L }, + { -0x1.f640e13ffc2a24cap-4L, -0x1.4dc050898710d058p-4L, -0x1.4dc050898710d056p-4L }, + { 0xb.656227303abf84fp-4L, 0xa.36b8463547f4c73p-4L, 0xa.36b8463547f4c74p-4L }, + { -0x7.b40be4642e982ab8p-4L, -0x4.8a392adbf99bf968p-4L, -0x4.8a392adbf99bf96p-4L }, + { 0x2.8126daf9591a4a78p-4L, 0x1.d56af8b597dab07ep-4L, 0x1.d56af8b597dab08p-4L }, + { -0xf.8481196507714a9p-4L, -0x7.d4bfd1129eebe82p-4L, -0x7.d4bfd1129eebe818p-4L }, + { 0x2.1a154d27c4610f5cp-92L, 0x1.74f88a35a7f80dcep-92L, 0x1.74f88a35a7f80ddp-92L }, + { -0x5.585153da63583088p-12L, -0x3.b40448ded8eb7678p-12L, -0x3.b40448ded8eb7674p-12L }, + { 0x8.4b1f02dac6cd4b9p-4L, 0x6.eaba168a48b0171p-4L, 0x6.eaba168a48b01718p-4L }, + { -0xc.759d3a3d2bb277bp-4L, -0x6.ac7fc087257bf838p-4L, -0x6.ac7fc087257bf83p-4L }, + { 0x9.5efce40ef5c193p-4L, 0x8.0319c4d499a7ca3p-4L, 0x8.0319c4d499a7ca4p-4L }, + { -0x1.3acdec63c75ba85ap-4L, -0xd.47ed2768ca5ede8p-8L, -0xd.47ed2768ca5ede7p-8L }, + { 0x3.a8862397aa33d5bcp-4L, 0x2.bf6ad5c108758048p-4L, 0x2.bf6ad5c10875804cp-4L }, + { -0x8.40b99f3260074bbp-4L, -0x4.cf3dbd131e8a17ap-4L, -0x4.cf3dbd131e8a1798p-4L }, + { 0x1.13ba9d07bc3a2952p-4L, 0xc.3a6591e048e18fep-8L, 0xc.3a6591e048e18ffp-8L }, + { -0x2.71006a8cb34d554cp-4L, -0x1.9b18519a46103f02p-4L, -0x1.9b18519a46103fp-4L }, + { 0x9.1553f4826cd4c82p-4L, 0x7.b6f3ad6001421a68p-4L, 0x7.b6f3ad6001421a7p-4L }, + { -0x5.67cce3baa54af0cp-4L, -0x3.57257d17a151238cp-4L, -0x3.57257d17a1512388p-4L }, + { 0x3.8114a9e190ab791p-4L, 0x2.9f7d24d05db91814p-4L, 0x2.9f7d24d05db91818p-4L }, + { -0x4.9c18fd283d9a589p-4L, -0x2.e57b1e06ca7a4c84p-4L, -0x2.e57b1e06ca7a4c8p-4L }, + { 0xc.05b3f7d8b6f7624p-4L, 0xa.ef465963b3e1fc3p-4L, 0xa.ef465963b3e1fc4p-4L }, + { -0xc.aa597d6d2ed91e3p-4L, -0x6.c1b5f0a62eb977fp-4L, -0x6.c1b5f0a62eb977e8p-4L }, + { 0x5.7aa677b8b3a14efp-4L, 0x4.49543a3a46f57d38p-4L, 0x4.49543a3a46f57d4p-4L }, + { -0x6.8d1b5b54f8172e1p-4L, -0x3.f4143adbee4eb904p-4L, -0x3.f4143adbee4eb9p-4L }, + { 0x4.a8455a7e3a68ed78p-4L, 0x3.93b0e898b77bf4c8p-4L, 0x3.93b0e898b77bf4ccp-4L }, + { -0x8.f684ab518e13e14p-4L, -0x5.2607e33540e678cp-4L, -0x5.2607e33540e678b8p-4L }, + { 0xf.331d018a51a3937p-4L, 0xe.e8d595bf6b18a9ap-4L, 0xe.e8d595bf6b18a9bp-4L }, + { -0x3.eca2bd0c8570369p-4L, -0x2.80620c0582a7ae94p-4L, -0x2.80620c0582a7ae9p-4L }, + { 0xc.a5327c102d01348p-80L, 0x8.c3daa757b84ad52p-80L, 0x8.c3daa757b84ad53p-80L }, + { -0x2.a3c7cec074186df4p-180L, -0x1.d46a5432452e2c9p-180L, -0x1.d46a5432452e2c8ep-180L }, + { 0x2.293460674db2c4p-4L, 0x1.91f96e67e72e8cc2p-4L, 0x1.91f96e67e72e8cc4p-4L }, + { -0xd.ea0bd2fdf3193cep-4L, -0x7.3e53d5de8fa95728p-4L, -0x7.3e53d5de8fa9572p-4L }, + { 0x7.7cc8ad228793eeep-4L, 0x6.2169209a50da8dfp-4L, 0x6.2169209a50da8df8p-4L }, + { -0x3.3eb74cb49c028ad4p-4L, -0x2.192ac814bd5f0c5cp-4L, -0x2.192ac814bd5f0c58p-4L }, + { 0xe.bc5331958998244p-4L, 0xe.4b5bcd8b0908ccfp-4L, 0xe.4b5bcd8b0908cdp-4L }, + { -0x1.2903edbad4d00bdep-4L, -0xc.8c97befaf20c969p-8L, -0xc.8c97befaf20c968p-8L }, + { 0x5.3ee964d9303fef2p-4L, 0x4.1517b8de179c1dap-4L, 0x4.1517b8de179c1da8p-4L }, + { -0x9.0a14cf75dc8c935p-8L, -0x6.30877227885a5f9p-8L, -0x6.30877227885a5f88p-8L }, + { 0x6.e59cd2b304be20bp-8L, 0x4.d353ed698d0eff18p-8L, 0x4.d353ed698d0eff2p-8L }, + { -0xd.25ced593ff0ac61p-4L, -0x6.f2a2932d1abac2d8p-4L, -0x6.f2a2932d1abac2dp-4L }, + { 0x3.1617c019abd659bp-4L, 0x2.49f324ab933e42d8p-4L, 0x2.49f324ab933e42dcp-4L }, + { -0x6.690f39e52d0c90c8p-4L, -0x3.e1358e26e4c35228p-4L, -0x3.e1358e26e4c35224p-4L }, + { 0x9.1050fe64665d025p-4L, 0x7.b1ce2c811fa492bp-4L, 0x7.b1ce2c811fa492b8p-4L }, + { -0x7.f6184dd3447fc3fp-4L, -0x4.aad4f07652aeae78p-4L, -0x4.aad4f07652aeae7p-4L }, + { 0xd.953628a90529c68p-4L, 0xc.d1901b07c97032cp-4L, 0xc.d1901b07c97032dp-4L }, + { -0x7.43be3e30b7e5c7a8p-4L, -0x4.51ef59e61758d838p-4L, -0x4.51ef59e61758d83p-4L }, + { 0x7.a4dabfc6c9e825b8p-4L, 0x6.47f5486a01b237ap-4L, 0x6.47f5486a01b237a8p-4L }, + { -0xb.f01119533e278e8p-4L, -0x6.75ed9a05142d0eap-4L, -0x6.75ed9a05142d0e98p-4L }, + { 0x1.6396f574b56c6172p-4L, 0xf.e0af65687e4b67ep-8L, 0xf.e0af65687e4b67fp-8L }, + { -0xf.b5e4a3223e61c14p-4L, -0x7.e627a04f577a3258p-4L, -0x7.e627a04f577a325p-4L }, + { 0xd.0f395b84573f61dp-192L, 0x9.0d58a8d3ccd5356p-192L, 0x9.0d58a8d3ccd5357p-192L }, + { -0x1.cad34f8832df94b6p-188L, -0x1.3e08970bbbe4953cp-188L, -0x1.3e08970bbbe4953ap-188L }, + { 0xd.a82c5b229e8fe54p-4L, 0xc.e94629ca486873dp-4L, 0xc.e94629ca486873ep-4L }, + { -0xc.337e6ec5ca09cbfp-4L, -0x6.91a27c9fb5331f48p-4L, -0x6.91a27c9fb5331f4p-4L }, + { 0x5.999aa2e2c49c8778p-4L, 0x4.649a9990259a6b08p-4L, 0x4.649a9990259a6b1p-4L }, + { -0x7.b2a783da083648ep-8L, -0x5.47d116a619b453bp-8L, -0x5.47d116a619b453a8p-8L }, + { 0xe.68481349ea07669p-4L, 0xd.ddd72166e76368fp-4L, 0xd.ddd72166e76369p-4L }, + { -0x7.c2d56e73e1215768p-4L, -0x4.918e390065e28458p-4L, -0x4.918e390065e2845p-4L }, + { 0x7.cfb667a4a3914a3p-4L, 0x6.717a3878ea0e60d8p-4L, 0x6.717a3878ea0e60ep-4L }, + { -0x8.d974808af557b0ep-4L, -0x5.1855a0cd14dbe46p-4L, -0x5.1855a0cd14dbe458p-4L }, + { 0xb.439e5356c702ad8p-4L, 0xa.107c2031a79089ep-4L, 0xa.107c2031a79089fp-4L }, + { -0xe.188d98ec6dc463bp-4L, -0x7.4fe68a1b12545d8p-4L, -0x7.4fe68a1b12545d78p-4L }, + { 0xe.d87c88ea04cfc54p-4L, 0xe.7067f2e9706541cp-4L, 0xe.7067f2e9706541dp-4L }, + { -0x7.5df293fec0fa7908p-4L, -0x4.5f2a3838248134f8p-4L, -0x4.5f2a3838248134fp-4L }, + { 0xb.f31341da10838b7p-4L, 0xa.d992b6a99f3586cp-4L, 0xa.d992b6a99f3586dp-4L }, + { -0x4.94201f2127bae1d8p-4L, -0x2.e0f3cbf83592b45cp-4L, -0x2.e0f3cbf83592b458p-4L }, + { 0xf.466813a0cb58997p-4L, 0xf.02b6115e1e0a079p-4L, 0xf.02b6115e1e0a07ap-4L }, + { -0x1.b40206802faf31f8p-4L, -0x1.2356684fa89060dp-4L, -0x1.2356684fa89060cep-4L }, + { 0x5.cfe8b47a3d2bb528p-4L, 0x4.94cd1c5dccf7537p-4L, 0x4.94cd1c5dccf75378p-4L }, + { -0xd.f8e6092df0a67cdp-4L, -0x7.43f462a4ef5a1918p-4L, -0x7.43f462a4ef5a191p-4L }, + { 0xe.c5c2bbb0872eb38p-4L, 0xe.57c07f71f4fb432p-4L, 0xe.57c07f71f4fb433p-4L }, + { -0xe.4ffa3f0dccc1904p-4L, -0x7.64a9d0532f3787bp-4L, -0x7.64a9d0532f3787a8p-4L }, + { 0xd.f51b450c06fa53fp-8L, 0x9.dc151be4407a68ap-8L, 0x9.dc151be4407a68bp-8L }, + { -0x1.eb1cef301d81df08p-52L, -0x1.5469e23dccbca00ep-52L, -0x1.5469e23dccbca00cp-52L }, + { 0x8.5ae9b271c862bd1p-4L, 0x6.fa6d07dce385fccp-4L, 0x6.fa6d07dce385fcc8p-4L }, + { -0xa.8fdf30d83ecd512p-4L, -0x5.dff47c13aa88bb28p-4L, -0x5.dff47c13aa88bb2p-4L }, + { 0x1.e689240cdaba32p-4L, 0x1.5f8358e071a53472p-4L, 0x1.5f8358e071a53474p-4L }, + { -0x7.62f10575934711p-4L, -0x4.61adf89887b9a24p-4L, -0x4.61adf89887b9a238p-4L }, + { 0xf.65a3e9387da5a2fp-4L, 0xf.2cc85c945028fcap-4L, 0xf.2cc85c945028fcbp-4L }, + { -0xb.d4af71c255e18d6p-4L, -0x6.6a9610ee9e87a8cp-4L, -0x6.6a9610ee9e87a8b8p-4L }, + { 0x5.9a9d1446632f3aep-4L, 0x4.657ef16969a055cp-4L, 0x4.657ef16969a055c8p-4L }, + { -0x9.b4e978d15970db2p-4L, -0x5.7e1be34eafa75f3p-4L, -0x5.7e1be34eafa75f28p-4L }, + { 0x8.7aea261756d25f3p-4L, 0x7.1a5e60645036bcb8p-4L, 0x7.1a5e60645036bccp-4L }, + { -0xf.b5a3f9c32315f89p-4L, -0x7.e610eed3517ac508p-4L, -0x7.e610eed3517ac5p-4L }, + { 0xe.7abe135a43a13e6p-4L, 0xd.f5c385f4adc9adbp-4L, 0xd.f5c385f4adc9adcp-4L }, + { -0x7.31920eb4fe1bd628p-4L, -0x4.48b9bee7bd62fefp-4L, -0x4.48b9bee7bd62fee8p-4L }, + { 0x3.2bf2a0a669999b48p-4L, 0x2.5b4c32cabb20c8acp-4L, 0x2.5b4c32cabb20c8bp-4L }, + { -0xa.6bff2a4ca65e178p-4L, -0x5.d02bc0929aebb8c8p-4L, -0x5.d02bc0929aebb8cp-4L }, + { 0x9.8e13ef308c3a17bp-4L, 0x8.3448125bdeacbe9p-4L, 0x8.3448125bdeacbeap-4L }, + { -0x8.4ef4a64c01509a8p-4L, -0x4.d621b783f39f31a8p-4L, -0x4.d621b783f39f31ap-4L }, + { 0x3.765e093b8a1ce118p-4L, 0x2.96da7371ca2fa4f8p-4L, 0x2.96da7371ca2fa4fcp-4L }, + { -0x7.aadaa9cd4105412p-4L, -0x4.85a7f3b0c1e06018p-4L, -0x4.85a7f3b0c1e0601p-4L }, + { 0x1.a2bf59174aca4d52p-4L, 0x1.2cc8f455ff2cea6ap-4L, 0x1.2cc8f455ff2cea6cp-4L }, + { -0x5.8f5a8c1e06358d9p-4L, -0x3.6cc434f58f798508p-4L, -0x3.6cc434f58f798504p-4L }, + { 0x2.8d03b0fea7261144p-156L, 0x1.c4a296285d9fa774p-156L, 0x1.c4a296285d9fa776p-156L }, + { -0xb.4261fc576312e18p-204L, -0x7.cdea5cf7def284b8p-204L, -0x7.cdea5cf7def284bp-204L }, + { 0x4.6d7ef04080b676d8p-4L, 0x3.6217371c0fa676ep-4L, 0x3.6217371c0fa676e4p-4L }, + { -0xb.c0ae25e2a801fc9p-4L, -0x6.62443424ce0cc21p-4L, -0x6.62443424ce0cc208p-4L }, + { 0x9.33aadc610c07076p-4L, 0x7.d6339920da9a3778p-4L, 0x7.d6339920da9a378p-4L }, + { -0xb.62d8d178f4ea271p-4L, -0x6.3add5679a51923bp-4L, -0x6.3add5679a51923a8p-4L }, + { 0xb.de8017b99009994p-4L, 0xa.c1aeb0c257defb4p-4L, 0xa.c1aeb0c257defb5p-4L }, + { -0xc.d14f3f856910093p-4L, -0x6.d142a83bc366c57p-4L, -0x6.d142a83bc366c568p-4L }, + { 0x1.36027b0d8b10a26cp-4L, 0xd.c9e65e03a5bcddcp-8L, 0xd.c9e65e03a5bcdddp-8L }, + { -0xc.5d2d16de94144fcp-4L, -0x6.a29ae09167802018p-4L, -0x6.a29ae0916780201p-4L }, + { 0xd.79e031e02305347p-4L, 0xc.af83870de952b8fp-4L, 0xc.af83870de952b9p-4L }, + { -0xa.c010f18d71bc8c5p-4L, -0x5.f5024e3266fc5898p-4L, -0x5.f5024e3266fc589p-4L }, + { 0x1.9cd7b4a183ae1dcp-4L, 0x1.2864c8400d7852d2p-4L, 0x1.2864c8400d7852d4p-4L }, + { -0x1.720bafd1b399ec82p-4L, -0xf.8a14ed8ba218a08p-8L, -0xf.8a14ed8ba218a07p-8L }, + { 0x4.fac18c7be7e011e8p-4L, 0x3.da233da5c7f9843cp-4L, 0x3.da233da5c7f9844p-4L }, + { -0xe.e7cda687036f7d6p-8L, -0xa.20408f833c406efp-8L, -0xa.20408f833c406eep-8L }, + { 0x9.9c2d0517aeee533p-4L, 0x8.4314f6301d33356p-4L, 0x8.4314f6301d33357p-4L }, + { -0xe.573ec2d151cf156p-4L, -0x7.675f198c15befecp-4L, -0x7.675f198c15befeb8p-4L }, + { 0xe.947a2689d86b12ap-4L, 0xe.173cf492cdc5f07p-4L, 0xe.173cf492cdc5f08p-4L }, + { -0x5.fee8120e5e04be2p-4L, -0x3.a8f7bcd02665b4bcp-4L, -0x3.a8f7bcd02665b4b8p-4L }, + { 0x3.f3364f18a79b3b3cp-4L, 0x2.fc7677f28287f59cp-4L, 0x2.fc7677f28287f5ap-4L }, + { -0xd.acb73d1f464055dp-4L, -0x7.26f0d62a8825fadp-4L, -0x7.26f0d62a8825fac8p-4L }, + { 0x3.72e8ef378d42c014p-136L, 0x2.63fc8bc98f409418p-136L, 0x2.63fc8bc98f40941cp-136L }, + { -0xf.f7a6695a9469f6bp-64L, -0xb.1157d5a78619d6ap-64L, -0xb.1157d5a78619d69p-64L }, + { 0xa.ed0ce5b49afa192p-4L, 0x9.af72dd5f9d309c8p-4L, 0x9.af72dd5f9d309c9p-4L }, + { -0x8.92179a4e3bb69e3p-4L, -0x4.f66ab2d67cb085b8p-4L, -0x4.f66ab2d67cb085bp-4L }, + { 0xb.ed688726df9befap-4L, 0xa.d2fc0f03bbaa3eap-4L, 0xa.d2fc0f03bbaa3ebp-4L }, + { -0x9.3f55bdfddb49b2bp-4L, -0x5.480d56cfe248124p-4L, -0x5.480d56cfe2481238p-4L }, + { 0x7.2ec3f10b51218bfp-4L, 0x5.d71a7e29e3375c08p-4L, 0x5.d71a7e29e3375c1p-4L }, + { -0x7.f78628cdda70a8d8p-8L, -0x5.768d49335e93bc48p-8L, -0x5.768d49335e93bc4p-8L }, + { 0x6.5dbff56825b7dbb8p-4L, 0x5.14cc73903ffab37p-4L, 0x5.14cc73903ffab378p-4L }, + { -0xa.e7a98283fc10855p-4L, -0x6.062dbfc6c13a0cp-4L, -0x6.062dbfc6c13a0bf8p-4L }, + { 0xc.2509016f44e196ap-4L, 0xb.13ee99066e4da51p-4L, 0xb.13ee99066e4da52p-4L }, + { -0x7.861514480ac9199p-4L, -0x4.7350865eeea1ec4p-4L, -0x4.7350865eeea1ec38p-4L }, + { 0xf.17da41cf884346bp-4L, 0xe.c46a3230752f01ep-4L, 0xe.c46a3230752f01fp-4L }, + { -0xc.62d7c253621dcf7p-4L, -0x6.a4e721c955ab92bp-4L, -0x6.a4e721c955ab92a8p-4L }, + { 0x9.845c3e40ed6ad83p-8L, 0x6.aeb3e091a9ca62a8p-8L, 0x6.aeb3e091a9ca62bp-8L }, + { -0xd.68fda9eec5a66c2p-4L, -0x7.0cd5054a8559068p-4L, -0x7.0cd5054a85590678p-4L }, + { 0x8.18f925371b61292p-4L, 0x6.b926981ecb341cc8p-4L, 0x6.b926981ecb341cdp-4L }, + { -0x1.57f7c0849ebb346p-4L, -0xe.79d2f43931febcep-8L, -0xe.79d2f43931febcdp-8L }, + { 0xa.e4ab5281b09d79fp-4L, 0x9.a6211af13affacbp-4L, 0x9.a6211af13affaccp-4L }, + { -0x7.1174b12c13aaf4e8p-4L, -0x4.38619acc6b16c48p-4L, -0x4.38619acc6b16c478p-4L }, + { 0xe.880fef5908d95bdp-4L, 0xe.07123c37decbd2bp-4L, 0xe.07123c37decbd2cp-4L }, + { -0x7.609718a06f5f08ap-4L, -0x4.607ef189a568c048p-4L, -0x4.607ef189a568c04p-4L }, + { 0x6.e2bdbcf507ec4778p-80L, 0x4.c5d6cd2d0554bd38p-80L, 0x4.c5d6cd2d0554bd4p-80L }, + { -0xa.20544abb2f768b5p-172L, -0x7.04dd9fe9c3d0ca4p-172L, -0x7.04dd9fe9c3d0ca38p-172L }, + { 0x6.14aea1523dfe3aa8p-4L, 0x4.d27a84995c90398p-4L, 0x4.d27a84995c903988p-4L }, + { -0xc.97a55c9c85f26f9p-4L, -0x6.ba359004a30e41c8p-4L, -0x6.ba359004a30e41cp-4L }, + { 0x8.680ab975830d106p-4L, 0x7.078281205f71db5p-4L, 0x7.078281205f71db58p-4L }, + { -0x3.7b5dd7324be888fcp-4L, -0x2.3d81bd11bf2f6c4cp-4L, -0x2.3d81bd11bf2f6c48p-4L }, + { 0xd.ff0ee4cab1a5c92p-4L, 0xd.56e662606151cc8p-4L, 0xd.56e662606151cc9p-4L }, + { -0xe.008f2e366ac05f5p-4L, -0x7.46d9fe3c6c7508bp-4L, -0x7.46d9fe3c6c7508a8p-4L }, + { 0xa.b9de710cc3240eap-4L, 0x9.76be49caa91f1f7p-4L, 0x9.76be49caa91f1f8p-4L }, + { -0xd.b8496a7f5a40118p-4L, -0x7.2b5f2502bf92f008p-4L, -0x7.2b5f2502bf92fp-4L }, + { 0xb.c810c87ed94addfp-4L, 0xa.a7ba02e0d048d4bp-4L, 0xa.a7ba02e0d048d4cp-4L }, + { -0x6.0a47a8ab4ac89cd8p-4L, -0x3.af0abdfd7366387cp-4L, -0x3.af0abdfd73663878p-4L }, + { 0xd.694a760f35e0c5cp-4L, 0xc.9aeeb6a65c8040ap-4L, 0xc.9aeeb6a65c8040bp-4L }, + { -0x1.02b5df71e26e7eeep-4L, -0xa.f74a44b0786e5d7p-8L, -0xa.f74a44b0786e5d6p-8L }, + { 0x8.2d4ad8d9b79c26ep-4L, 0x6.cd300350fa1084ep-4L, 0x6.cd300350fa1084e8p-4L }, + { -0x5.d8b77fd6db5f46fp-4L, -0x3.947c5ee25dae93cp-4L, -0x3.947c5ee25dae93bcp-4L }, + { 0x3.b2d5aa2bd4f226c8p-4L, 0x2.c7cc7c21062df578p-4L, 0x2.c7cc7c21062df57cp-4L }, + { -0x1.3d87d39ca205f226p-4L, -0xd.6495ea183c77a34p-8L, -0xd.6495ea183c77a33p-8L }, + { 0x7.58b591427632828p-4L, 0x5.feee1c31635efc6p-4L, 0x5.feee1c31635efc68p-4L }, + { -0xd.51cbb799b3f3a26p-4L, -0x7.03d23697240275b8p-4L, -0x7.03d23697240275bp-4L }, + { 0x9.0e54bb10a5b7912p-4L, 0x7.afc489158099261p-4L, 0x7.afc4891580992618p-4L }, + { -0xa.7e81ca95f58d507p-4L, -0x5.d853b00c0424b748p-4L, -0x5.d853b00c0424b74p-4L }, + { 0xa.38c6b26a97ad959p-144L, 0x7.15cf9ed628b7443p-144L, 0x7.15cf9ed628b74438p-144L }, + { -0xd.8dbb3097e168af8p-16L, -0x9.64dcae1a44ce08fp-16L, -0x9.64dcae1a44ce08ep-16L }, + { 0xf.05da5fd59fc565bp-4L, 0xe.ac75be21fa0a721p-4L, 0xe.ac75be21fa0a722p-4L }, + { -0xd.dd9a1c0c442c4c6p-4L, -0x7.399a1163598e674p-4L, -0x7.399a1163598e6738p-4L }, + { 0x4.61b51c01df55d6d8p-4L, 0x3.5833a282f0757d38p-4L, 0x3.5833a282f0757d3cp-4L }, + { -0xb.dce6fd9bad9f495p-4L, -0x6.6dfecf316daaa2b8p-4L, -0x6.6dfecf316daaa2bp-4L }, + { 0xa.b6f22a1b9f2939fp-4L, 0x9.73850a513137669p-4L, 0x9.73850a51313766ap-4L }, + { -0x3.4bb35afb05788e3p-4L, -0x2.20fa7ab319293c2cp-4L, -0x2.20fa7ab319293c28p-4L }, + { 0xd.0db3afda3c5f8cp-4L, 0xc.2a4edf1f8e608e3p-4L, 0xc.2a4edf1f8e608e4p-4L }, + { -0x2.1ce57b45214ebd74p-4L, -0x1.6646119faf2579e4p-4L, -0x1.6646119faf2579e2p-4L }, + { 0x5.067f9f48fc5b234p-8L, 0x3.81d3c5994dfa29ep-8L, 0x3.81d3c5994dfa29e4p-8L }, + { -0xb.a04244a598be88fp-4L, -0x6.54b9128406b6e57p-4L, -0x6.54b9128406b6e568p-4L }, + { 0xf.d97f1711de15f9cp-4L, 0xf.cacbd7b24bfa344p-4L, 0xf.cacbd7b24bfa345p-4L }, + { -0xf.493b2b477feaaf9p-4L, -0x7.bfaad9fbab559b1p-4L, -0x7.bfaad9fbab559b08p-4L }, + { 0xc.deaf7691740cdefp-8L, 0x9.13f529a0032aecap-8L, 0x9.13f529a0032aecbp-8L }, + { -0xa.59b5d478c821a2ep-4L, -0x5.c816a0d158b46128p-4L, -0x5.c816a0d158b4612p-4L }, + { 0xd.1b186c2e3417901p-4L, 0xc.3aab3f3a165b5b1p-4L, 0xc.3aab3f3a165b5b2p-4L }, + { -0xf.14939428966efa8p-4L, -0x7.acc2e6e3a1c40bfp-4L, -0x7.acc2e6e3a1c40be8p-4L }, + { 0xa.548931dd5b08516p-4L, 0x9.07e9820c45dc918p-4L, 0x9.07e9820c45dc919p-4L }, + { -0x1.86c3057b9088fe1cp-4L, -0x1.06181e6e8d7c4ee6p-4L, -0x1.06181e6e8d7c4ee4p-4L }, + { 0x8.de5082bfa47b272p-8L, 0x6.38b52f74fd4fac9p-8L, 0x6.38b52f74fd4fac98p-8L }, + { -0x6.381df51cf6ba1e58p-4L, -0x3.c7677b23d838f2c4p-4L, -0x3.c7677b23d838f2cp-4L }, + { 0x2.f43f9bb64395d398p-28L, 0x2.0c3105ebb2d3ec1p-28L, 0x2.0c3105ebb2d3ec14p-28L }, + { -0x1.7d1826b58589517p-188L, -0x1.08278b32d446a3dap-188L, -0x1.08278b32d446a3d8p-188L }, + { 0x3.24bd5453a5d96c38p-4L, 0x2.5591a327002dbbfp-4L, 0x2.5591a327002dbbf4p-4L }, + { -0xd.ac66274a591f9a9p-4L, -0x7.26d1c15c81b1be3p-4L, -0x7.26d1c15c81b1be28p-4L }, + { 0x7.4bbb894be77050dp-4L, 0x5.f29408389bbe66ep-4L, 0x5.f29408389bbe66e8p-4L }, + { -0xa.eacc82e14c1610fp-4L, -0x6.0788b0f7dc794f7p-4L, -0x6.0788b0f7dc794f68p-4L }, + { 0x2.a982ac56625aefc4p-4L, 0x1.f4b47ebd7795a254p-4L, 0x1.f4b47ebd7795a256p-4L }, + { -0x8.056940c538fa279p-4L, -0x4.b257711af2be1e78p-4L, -0x4.b257711af2be1e7p-4L }, + { 0x1.66b64b9c9f79a1dep-4L, 0x1.00578a1c0c673a1p-4L, 0x1.00578a1c0c673a12p-4L }, + { -0x3.26b75fa52c7ce30cp-4L, -0x2.0aaf1c1238c99944p-4L, -0x2.0aaf1c1238c9994p-4L }, + { 0x9.da5604fb75e8d87p-4L, 0x8.84c2f5daaacf75ep-4L, 0x8.84c2f5daaacf75fp-4L }, + { -0x8.f39b1339c38973dp-4L, -0x5.24a94b90f03e7ed8p-4L, -0x5.24a94b90f03e7edp-4L }, + { 0x7.677b36d2e1d48358p-4L, 0x6.0d06229c56a97f4p-4L, 0x6.0d06229c56a97f48p-4L }, + { -0xa.996804efaa5460cp-4L, -0x5.e4224415b8782278p-4L, -0x5.e4224415b878227p-4L }, + { 0x6.b6c06e4a29c88afp-4L, 0x5.66b27094b245b1ep-4L, 0x5.66b27094b245b1e8p-4L }, + { -0x5.a5149fe9b18171c8p-4L, -0x3.7894bad1006fb798p-4L, -0x3.7894bad1006fb794p-4L }, + { 0x5.375a31264862647p-4L, 0x4.0e852a933247c008p-4L, 0x4.0e852a933247c01p-4L }, + { -0xc.55651fd1cbee3d4p-4L, -0x6.9f72345b02eab28p-4L, -0x6.9f72345b02eab278p-4L }, + { 0xe.006deb92f93d672p-4L, 0xd.58a49a5d8de28c4p-4L, 0xd.58a49a5d8de28c5p-4L }, + { -0xa.6871090121d471bp-4L, -0x5.ce99fb28aafa5bb8p-4L, -0x5.ce99fb28aafa5bbp-4L }, + { 0xc.8ed445e1ea26da6p-4L, 0xb.9126f62f86bcb47p-4L, 0xb.9126f62f86bcb48p-4L }, + { -0x3.70640030d409ab74p-4L, -0x2.36f53ff3b132cba8p-4L, -0x2.36f53ff3b132cba4p-4L }, + { 0x2.219473696b04364cp-96L, 0x1.7a2acafbc3adc14ep-96L, 0x1.7a2acafbc3adc15p-96L }, + { -0xd.bdc3902e400dcddp-144L, -0x9.865401201b95f7ap-144L, -0x9.865401201b95f79p-144L }, + { 0xb.b53f28201a854efp-4L, 0xa.9207b77bb750cf7p-4L, 0xa.9207b77bb750cf8p-4L }, + { -0x4.28b1a78cc7055bd8p-4L, -0x2.a3536d42907d291p-4L, -0x2.a3536d42907d290cp-4L }, + { 0xd.e2cee7a54e7c7dfp-4L, 0xd.331435f3041bf4fp-4L, 0xd.331435f3041bf5p-4L }, + { -0x9.3f6896a8070ab3ep-4L, -0x5.4816171c316ed77p-4L, -0x5.4816171c316ed768p-4L }, + { 0x1.a1524a334652c37cp-4L, 0x1.2bb95dd5b9658e26p-4L, 0x1.2bb95dd5b9658e28p-4L }, + { -0x1.9b7f6344a4875e14p-4L, -0x1.13861edcadba3e08p-4L, -0x1.13861edcadba3e06p-4L }, + { 0xb.4660bc20f1141f9p-4L, 0xa.1399f4f27c33975p-4L, 0xa.1399f4f27c33976p-4L }, + { -0xd.9888197bcafba2ap-4L, -0x7.1f30db722ee63d78p-4L, -0x7.1f30db722ee63d7p-4L }, + { 0xf.3adad3101e81209p-4L, 0xe.f33515340a557e4p-4L, 0xe.f33515340a557e5p-4L }, + { -0xa.79ea74b25ad8a16p-4L, -0x5.d64e6bad7c9fffc8p-4L, -0x5.d64e6bad7c9fffcp-4L }, + { 0xd.4d87683a39ac568p-4L, 0xc.789c1f6e5dcac31p-4L, 0xc.789c1f6e5dcac32p-4L }, + { -0xd.0f2848388d6bd4fp-4L, -0x6.e9bc44c0f7734168p-4L, -0x6.e9bc44c0f773416p-4L }, + { 0x5.d9fb99a27648b5d8p-4L, 0x4.9dca7407214af058p-4L, 0x4.9dca7407214af06p-4L }, + { -0x1.705dc2d9924977d6p-4L, -0xf.7895af9cd8410b4p-8L, -0xf.7895af9cd8410b3p-8L }, + { 0xe.de1ad3b0df8a929p-4L, 0xe.77d17cd52544381p-4L, 0xe.77d17cd52544382p-4L }, + { -0xe.4bc9f399afa1199p-4L, -0x7.6319db0e3314bc98p-4L, -0x7.6319db0e3314bc9p-4L }, + { 0x9.4bc88b56990e957p-4L, 0x7.ef27dce522664078p-4L, 0x7.ef27dce52266408p-4L }, + { -0xe.2a8337406c02664p-4L, -0x7.56a65648e9cbee38p-4L, -0x7.56a65648e9cbee3p-4L }, +}; + +int check_equal(long double res, long double expected) +{ + if (res != expected) { + return 0; + } + return (__builtin_copysignl(1.0L, res) == + __builtin_copysignl(1.0L, expected)); +} + +int main(void) +{ + int ret = 0; + int i; + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + long double ld_res; + __asm__ volatile ("f2xm1" : "=t" (ld_res) : "0" (tests[i].arg)); + if (!check_equal(ld_res, tests[i].down) && + !check_equal(ld_res, tests[i].up)) { + printf("FAIL: f2xm1 %La, expected %La or %La, got %La\n", + tests[i].arg, tests[i].down, tests[i].up, ld_res); + ret = 1; + } + } + return ret; +} From 6b8b0136ab3018e4b552b485f808bf66bcf19ead Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 8 Jun 2020 16:55:11 +0000 Subject: [PATCH 1698/2595] softfloat: merge floatx80_mod and floatx80_rem The m68k-specific softfloat code includes a function floatx80_mod that is extremely similar to floatx80_rem, but computing the remainder based on truncating the quotient toward zero rather than rounding it to nearest integer. This is also useful for emulating the x87 fprem and fprem1 instructions. Change the floatx80_rem implementation into floatx80_modrem that can perform either operation, with both floatx80_rem and floatx80_mod as thin wrappers available for all targets. There does not appear to be any use for the _mod operation for other floating-point formats in QEMU (the only other architectures using _rem at all are linux-user/arm/nwfpe, for FPA emulation, and openrisc, for instructions that have been removed in the latest version of the architecture), so no change is made to the code for other formats. Signed-off-by: Joseph Myers Reviewed-by: Richard Henderson Message-Id: Signed-off-by: Paolo Bonzini --- fpu/softfloat.c | 49 ++++++++++++++++++------ include/fpu/softfloat.h | 2 + target/m68k/softfloat.c | 83 ----------------------------------------- target/m68k/softfloat.h | 1 - 4 files changed, 40 insertions(+), 95 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 5e9746c287..b7dcf4d6c3 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5697,10 +5697,13 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status) /*---------------------------------------------------------------------------- | Returns the remainder of the extended double-precision floating-point value | `a' with respect to the corresponding value `b'. The operation is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic, +| if 'mod' is false; if 'mod' is true, return the remainder based on truncating +| the quotient toward zero instead. *----------------------------------------------------------------------------*/ -floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status) +floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, + float_status *status) { bool aSign, zSign; int32_t aExp, bExp, expDiff; @@ -5746,7 +5749,7 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status) expDiff = aExp - bExp; aSig1 = 0; if ( expDiff < 0 ) { - if ( expDiff < -1 ) return a; + if ( mod || expDiff < -1 ) return a; shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); expDiff = 0; } @@ -5778,14 +5781,16 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status) term1 = 0; term0 = bSig; } - sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 ); - if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 ) - || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 ) - && ( q & 1 ) ) - ) { - aSig0 = alternateASig0; - aSig1 = alternateASig1; - zSign = ! zSign; + if (!mod) { + sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 ); + if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 ) + || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 ) + && ( q & 1 ) ) + ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + zSign = ! zSign; + } } return normalizeRoundAndPackFloatx80( @@ -5793,6 +5798,28 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status) } +/*---------------------------------------------------------------------------- +| Returns the remainder of the extended double-precision floating-point value +| `a' with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status) +{ + return floatx80_modrem(a, b, false, status); +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the extended double-precision floating-point value +| `a' with respect to the corresponding value `b', with the quotient truncated +| toward zero. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status) +{ + return floatx80_modrem(a, b, true, status); +} + /*---------------------------------------------------------------------------- | Returns the square root of the extended double-precision floating-point | value `a'. The operation is performed according to the IEC/IEEE Standard diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 16ca697a73..bff6934d09 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -687,6 +687,8 @@ floatx80 floatx80_add(floatx80, floatx80, float_status *status); floatx80 floatx80_sub(floatx80, floatx80, float_status *status); floatx80 floatx80_mul(floatx80, floatx80, float_status *status); floatx80 floatx80_div(floatx80, floatx80, float_status *status); +floatx80 floatx80_modrem(floatx80, floatx80, bool, float_status *status); +floatx80 floatx80_mod(floatx80, floatx80, float_status *status); floatx80 floatx80_rem(floatx80, floatx80, float_status *status); floatx80 floatx80_sqrt(floatx80, float_status *status); FloatRelation floatx80_compare(floatx80, floatx80, float_status *status); diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c index 9f120cf15e..b6d0ed7acf 100644 --- a/target/m68k/softfloat.c +++ b/target/m68k/softfloat.c @@ -42,89 +42,6 @@ static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status) return a; } -/* - * Returns the modulo remainder of the extended double-precision floating-point - * value `a' with respect to the corresponding value `b'. - */ - -floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status) -{ - bool aSign, zSign; - int32_t aExp, bExp, expDiff; - uint64_t aSig0, aSig1, bSig; - uint64_t qTemp, term0, term1; - - aSig0 = extractFloatx80Frac(a); - aExp = extractFloatx80Exp(a); - aSign = extractFloatx80Sign(a); - bSig = extractFloatx80Frac(b); - bExp = extractFloatx80Exp(b); - - if (aExp == 0x7FFF) { - if ((uint64_t) (aSig0 << 1) - || ((bExp == 0x7FFF) && (uint64_t) (bSig << 1))) { - return propagateFloatx80NaN(a, b, status); - } - goto invalid; - } - if (bExp == 0x7FFF) { - if ((uint64_t) (bSig << 1)) { - return propagateFloatx80NaN(a, b, status); - } - return a; - } - if (bExp == 0) { - if (bSig == 0) { - invalid: - float_raise(float_flag_invalid, status); - return floatx80_default_nan(status); - } - normalizeFloatx80Subnormal(bSig, &bExp, &bSig); - } - if (aExp == 0) { - if ((uint64_t) (aSig0 << 1) == 0) { - return a; - } - normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0); - } - bSig |= UINT64_C(0x8000000000000000); - zSign = aSign; - expDiff = aExp - bExp; - aSig1 = 0; - if (expDiff < 0) { - return a; - } - qTemp = (bSig <= aSig0); - if (qTemp) { - aSig0 -= bSig; - } - expDiff -= 64; - while (0 < expDiff) { - qTemp = estimateDiv128To64(aSig0, aSig1, bSig); - qTemp = (2 < qTemp) ? qTemp - 2 : 0; - mul64To128(bSig, qTemp, &term0, &term1); - sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1); - shortShift128Left(aSig0, aSig1, 62, &aSig0, &aSig1); - expDiff -= 62; - } - expDiff += 64; - if (0 < expDiff) { - qTemp = estimateDiv128To64(aSig0, aSig1, bSig); - qTemp = (2 < qTemp) ? qTemp - 2 : 0; - qTemp >>= 64 - expDiff; - mul64To128(bSig, qTemp << (64 - expDiff), &term0, &term1); - sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1); - shortShift128Left(0, bSig, 64 - expDiff, &term0, &term1); - while (le128(term0, term1, aSig0, aSig1)) { - ++qTemp; - sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1); - } - } - return - normalizeRoundAndPackFloatx80( - 80, zSign, bExp + expDiff, aSig0, aSig1, status); -} - /* * Returns the mantissa of the extended double-precision floating-point * value `a'. diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h index 365ef6ac7a..4bb9567134 100644 --- a/target/m68k/softfloat.h +++ b/target/m68k/softfloat.h @@ -23,7 +23,6 @@ #define TARGET_M68K_SOFTFLOAT_H #include "fpu/softfloat.h" -floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status); floatx80 floatx80_getman(floatx80 a, float_status *status); floatx80 floatx80_getexp(floatx80 a, float_status *status); floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status); From 499a2f7b554a295cfc10f8cd026d9b20a38fe664 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 8 Jun 2020 16:55:49 +0000 Subject: [PATCH 1699/2595] softfloat: fix floatx80 remainder pseudo-denormal check for zero The floatx80 remainder implementation ignores the high bit of the significand when checking whether an operand (numerator) with zero exponent is zero. This means it mishandles a pseudo-denormal representation of 0x1p-16382L by treating it as zero. Fix this by checking the whole significand instead. Signed-off-by: Joseph Myers Reviewed-by: Richard Henderson Message-Id: Signed-off-by: Paolo Bonzini --- fpu/softfloat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index b7dcf4d6c3..f164b5c0ad 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5741,7 +5741,7 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); } if ( aExp == 0 ) { - if ( (uint64_t) ( aSig0<<1 ) == 0 ) return a; + if ( aSig0 == 0 ) return a; normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); } bSig |= UINT64_C(0x8000000000000000); From b662495dca0a2a36008cf8def91e2566519ed3f2 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 8 Jun 2020 16:56:20 +0000 Subject: [PATCH 1700/2595] softfloat: do not return pseudo-denormal from floatx80 remainder The floatx80 remainder implementation sometimes returns the numerator unchanged when the denominator is sufficiently larger than the numerator. But if the value to be returned unchanged is a pseudo-denormal, that is incorrect. Fix it to normalize the numerator in that case. Signed-off-by: Joseph Myers Reviewed-by: Richard Henderson Message-Id: Signed-off-by: Paolo Bonzini --- fpu/softfloat.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index f164b5c0ad..ab50088c35 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5706,7 +5706,7 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, float_status *status) { bool aSign, zSign; - int32_t aExp, bExp, expDiff; + int32_t aExp, bExp, expDiff, aExpOrig; uint64_t aSig0, aSig1, bSig; uint64_t q, term0, term1, alternateASig0, alternateASig1; @@ -5715,7 +5715,7 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, return floatx80_default_nan(status); } aSig0 = extractFloatx80Frac( a ); - aExp = extractFloatx80Exp( a ); + aExpOrig = aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); bSig = extractFloatx80Frac( b ); bExp = extractFloatx80Exp( b ); @@ -5730,6 +5730,13 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, if ((uint64_t)(bSig << 1)) { return propagateFloatx80NaN(a, b, status); } + if (aExp == 0 && aSig0 >> 63) { + /* + * Pseudo-denormal argument must be returned in normalized + * form. + */ + return packFloatx80(aSign, 1, aSig0); + } return a; } if ( bExp == 0 ) { @@ -5749,7 +5756,16 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, expDiff = aExp - bExp; aSig1 = 0; if ( expDiff < 0 ) { - if ( mod || expDiff < -1 ) return a; + if ( mod || expDiff < -1 ) { + if (aExp == 1 && aExpOrig == 0) { + /* + * Pseudo-denormal argument must be returned in + * normalized form. + */ + return packFloatx80(aSign, aExp, aSig0); + } + return a; + } shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); expDiff = 0; } From 566601f1f9d972e44214696d3cb320e6c18880aa Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 8 Jun 2020 16:56:47 +0000 Subject: [PATCH 1701/2595] softfloat: do not set denominator high bit for floatx80 remainder The floatx80 remainder implementation unnecessarily sets the high bit of bSig explicitly. By that point in the function, arguments that are invalid, zero, infinity or NaN have already been handled and subnormals have been through normalizeFloatx80Subnormal, so the high bit will already be set. Remove the unnecessary code. Signed-off-by: Joseph Myers Reviewed-by: Richard Henderson Message-Id: Signed-off-by: Paolo Bonzini --- fpu/softfloat.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index ab50088c35..1ee3342715 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5751,7 +5751,6 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, if ( aSig0 == 0 ) return a; normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); } - bSig |= UINT64_C(0x8000000000000000); zSign = aSign; expDiff = aExp - bExp; aSig1 = 0; From 445810ec915687d37b8ae0ef8d7340ab4a153efa Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 8 Jun 2020 16:57:16 +0000 Subject: [PATCH 1702/2595] softfloat: return low bits of quotient from floatx80_modrem Both x87 and m68k need the low parts of the quotient for their remainder operations. Arrange for floatx80_modrem to track those bits and return them via a pointer. The architectures using float32_rem and float64_rem do not appear to need this information, so the *_rem interface is left unchanged and the information returned only from floatx80_modrem. The logic used to determine the low 7 bits of the quotient for m68k (target/m68k/fpu_helper.c:make_quotient) appears completely bogus (it looks at the result of converting the remainder to integer, the quotient having been discarded by that point); this patch does not change that, but the m68k maintainers may wish to do so. Signed-off-by: Joseph Myers Reviewed-by: Richard Henderson Message-Id: Signed-off-by: Paolo Bonzini --- fpu/softfloat.c | 23 ++++++++++++++++++----- include/fpu/softfloat.h | 3 ++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 1ee3342715..79be4f5840 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5699,10 +5699,11 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status) | `a' with respect to the corresponding value `b'. The operation is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic, | if 'mod' is false; if 'mod' is true, return the remainder based on truncating -| the quotient toward zero instead. +| the quotient toward zero instead. '*quotient' is set to the low 64 bits of +| the absolute value of the integer quotient. *----------------------------------------------------------------------------*/ -floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, +floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, uint64_t *quotient, float_status *status) { bool aSign, zSign; @@ -5710,6 +5711,7 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, uint64_t aSig0, aSig1, bSig; uint64_t q, term0, term1, alternateASig0, alternateASig1; + *quotient = 0; if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { float_raise(float_flag_invalid, status); return floatx80_default_nan(status); @@ -5768,7 +5770,7 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); expDiff = 0; } - q = ( bSig <= aSig0 ); + *quotient = q = ( bSig <= aSig0 ); if ( q ) aSig0 -= bSig; expDiff -= 64; while ( 0 < expDiff ) { @@ -5778,6 +5780,8 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 ); expDiff -= 62; + *quotient <<= 62; + *quotient += q; } expDiff += 64; if ( 0 < expDiff ) { @@ -5791,6 +5795,12 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, ++q; sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); } + if (expDiff < 64) { + *quotient <<= expDiff; + } else { + *quotient = 0; + } + *quotient += q; } else { term1 = 0; @@ -5805,6 +5815,7 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, aSig0 = alternateASig0; aSig1 = alternateASig1; zSign = ! zSign; + ++*quotient; } } return @@ -5821,7 +5832,8 @@ floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod, floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status) { - return floatx80_modrem(a, b, false, status); + uint64_t quotient; + return floatx80_modrem(a, b, false, "ient, status); } /*---------------------------------------------------------------------------- @@ -5832,7 +5844,8 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status) floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status) { - return floatx80_modrem(a, b, true, status); + uint64_t quotient; + return floatx80_modrem(a, b, true, "ient, status); } /*---------------------------------------------------------------------------- diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index bff6934d09..ff4e2605b1 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -687,7 +687,8 @@ floatx80 floatx80_add(floatx80, floatx80, float_status *status); floatx80 floatx80_sub(floatx80, floatx80, float_status *status); floatx80 floatx80_mul(floatx80, floatx80, float_status *status); floatx80 floatx80_div(floatx80, floatx80, float_status *status); -floatx80 floatx80_modrem(floatx80, floatx80, bool, float_status *status); +floatx80 floatx80_modrem(floatx80, floatx80, bool, uint64_t *, + float_status *status); floatx80 floatx80_mod(floatx80, floatx80, float_status *status); floatx80 floatx80_rem(floatx80, floatx80, float_status *status); floatx80 floatx80_sqrt(floatx80, float_status *status); From 5ef396e2ba865f34a4766dbd60c739fb4bcb4fcc Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 8 Jun 2020 16:58:23 +0000 Subject: [PATCH 1703/2595] target/i386: reimplement fprem, fprem1 using floatx80 operations The x87 fprem and fprem1 emulation is currently based around conversion to double, which is inherently unsuitable for a good emulation of any floatx80 operation. Reimplement using the soft-float floatx80 remainder operations. Signed-off-by: Joseph Myers Reviewed-by: Richard Henderson Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 164 +++++++++++++-------------------------- 1 file changed, 52 insertions(+), 112 deletions(-) diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index e32a2aa74b..8f34ea9776 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -1313,124 +1313,64 @@ void helper_fxtract(CPUX86State *env) merge_exception_flags(env, old_flags); } +static void helper_fprem_common(CPUX86State *env, bool mod) +{ + uint8_t old_flags = save_exception_flags(env); + uint64_t quotient; + CPU_LDoubleU temp0, temp1; + int exp0, exp1, expdiff; + + temp0.d = ST0; + temp1.d = ST1; + exp0 = EXPD(temp0); + exp1 = EXPD(temp1); + + env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */ + if (floatx80_is_zero(ST0) || floatx80_is_zero(ST1) || + exp0 == 0x7fff || exp1 == 0x7fff || + floatx80_invalid_encoding(ST0) || floatx80_invalid_encoding(ST1)) { + ST0 = floatx80_modrem(ST0, ST1, mod, "ient, &env->fp_status); + } else { + if (exp0 == 0) { + exp0 = 1 - clz64(temp0.l.lower); + } + if (exp1 == 0) { + exp1 = 1 - clz64(temp1.l.lower); + } + expdiff = exp0 - exp1; + if (expdiff < 64) { + ST0 = floatx80_modrem(ST0, ST1, mod, "ient, &env->fp_status); + env->fpus |= (quotient & 0x4) << (8 - 2); /* (C0) <-- q2 */ + env->fpus |= (quotient & 0x2) << (14 - 1); /* (C3) <-- q1 */ + env->fpus |= (quotient & 0x1) << (9 - 0); /* (C1) <-- q0 */ + } else { + /* + * Partial remainder. This choice of how many bits to + * process at once is specified in AMD instruction set + * manuals, and empirically is followed by Intel + * processors as well; it ensures that the final remainder + * operation in a loop does produce the correct low three + * bits of the quotient. AMD manuals specify that the + * flags other than C2 are cleared, and empirically Intel + * processors clear them as well. + */ + int n = 32 + (expdiff % 32); + temp1.d = floatx80_scalbn(temp1.d, expdiff - n, &env->fp_status); + ST0 = floatx80_mod(ST0, temp1.d, &env->fp_status); + env->fpus |= 0x400; /* C2 <-- 1 */ + } + } + merge_exception_flags(env, old_flags); +} + void helper_fprem1(CPUX86State *env) { - double st0, st1, dblq, fpsrcop, fptemp; - CPU_LDoubleU fpsrcop1, fptemp1; - int expdif; - signed long long int q; - - st0 = floatx80_to_double(env, ST0); - st1 = floatx80_to_double(env, ST1); - - if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) { - ST0 = double_to_floatx80(env, 0.0 / 0.0); /* NaN */ - env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */ - return; - } - - fpsrcop = st0; - fptemp = st1; - fpsrcop1.d = ST0; - fptemp1.d = ST1; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - - if (expdif < 0) { - /* optimisation? taken from the AMD docs */ - env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */ - /* ST0 is unchanged */ - return; - } - - if (expdif < 53) { - dblq = fpsrcop / fptemp; - /* round dblq towards nearest integer */ - dblq = rint(dblq); - st0 = fpsrcop - fptemp * dblq; - - /* convert dblq to q by truncating towards zero */ - if (dblq < 0.0) { - q = (signed long long int)(-dblq); - } else { - q = (signed long long int)dblq; - } - - env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C3,C1) <-- (q2,q1,q0) */ - env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ - env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ - env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ - } else { - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif - 50); - fpsrcop = (st0 / st1) / fptemp; - /* fpsrcop = integer obtained by chopping */ - fpsrcop = (fpsrcop < 0.0) ? - -(floor(fabs(fpsrcop))) : floor(fpsrcop); - st0 -= (st1 * fpsrcop * fptemp); - } - ST0 = double_to_floatx80(env, st0); + helper_fprem_common(env, false); } void helper_fprem(CPUX86State *env) { - double st0, st1, dblq, fpsrcop, fptemp; - CPU_LDoubleU fpsrcop1, fptemp1; - int expdif; - signed long long int q; - - st0 = floatx80_to_double(env, ST0); - st1 = floatx80_to_double(env, ST1); - - if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) { - ST0 = double_to_floatx80(env, 0.0 / 0.0); /* NaN */ - env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */ - return; - } - - fpsrcop = st0; - fptemp = st1; - fpsrcop1.d = ST0; - fptemp1.d = ST1; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - - if (expdif < 0) { - /* optimisation? taken from the AMD docs */ - env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */ - /* ST0 is unchanged */ - return; - } - - if (expdif < 53) { - dblq = fpsrcop / fptemp; /* ST0 / ST1 */ - /* round dblq towards zero */ - dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq); - st0 = fpsrcop - fptemp * dblq; /* fpsrcop is ST0 */ - - /* convert dblq to q by truncating towards zero */ - if (dblq < 0.0) { - q = (signed long long int)(-dblq); - } else { - q = (signed long long int)dblq; - } - - env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C3,C1) <-- (q2,q1,q0) */ - env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ - env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ - env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ - } else { - int N = 32 + (expdif % 32); /* as per AMD docs */ - - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, (double)(expdif - N)); - fpsrcop = (st0 / st1) / fptemp; - /* fpsrcop = integer obtained by chopping */ - fpsrcop = (fpsrcop < 0.0) ? - -(floor(fabs(fpsrcop))) : floor(fpsrcop); - st0 -= (st1 * fpsrcop * fptemp); - } - ST0 = double_to_floatx80(env, st0); + helper_fprem_common(env, true); } void helper_fyl2xp1(CPUX86State *env) From 5eebc49d2d0aa5fc7e90eeac97533051bb7b72fa Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Wed, 17 Jun 2020 23:20:50 +0000 Subject: [PATCH 1704/2595] target/i386: reimplement fyl2xp1 using floatx80 operations The x87 fyl2xp1 emulation is currently based around conversion to double. This is inherently unsuitable for a good emulation of any floatx80 operation, even before considering that it is a particularly naive implementation using double (adding 1 then using log rather than attempting a better emulation using log1p). Reimplement using the soft-float operations, as was done for f2xm1; as in that case, m68k has related operations but not exactly this one and it seemed safest to implement directly rather than reusing the m68k code to avoid accumulation of errors. A test is included with many randomly generated inputs. The assumption of the test is that the result in round-to-nearest mode should always be one of the two closest floating-point numbers to the mathematical value of y * log2(x + 1); the implementation aims to do somewhat better than that (about 70 correct bits before rounding). I haven't investigated how accurate hardware is. Intel manuals describe a narrower range of valid arguments to this instruction than AMD manuals. The implementation accepts the wider range (it's needed anyway for the core code to be reusable in a subsequent patch reimplementing fyl2x), but the test only has inputs in the narrower range so that it's valid on hardware that may reject or produce poor results for inputs outside that range. Code in the previous implementation that sets C2 for some out-of-range arguments is not carried forward to the new implementation; C2 is undefined for this instruction and I suspect that code was just cut-and-pasted from the trigonometric instructions (fcos, fptan, fsin, fsincos) where C2 *is* defined to be set for out-of-range arguments. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 209 ++++- tests/tcg/i386/test-i386-fyl2xp1.c | 1156 ++++++++++++++++++++++++++++ 2 files changed, 1357 insertions(+), 8 deletions(-) create mode 100644 tests/tcg/i386/test-i386-fyl2xp1.c diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 8f34ea9776..884e84c804 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -1373,19 +1373,212 @@ void helper_fprem(CPUX86State *env) helper_fprem_common(env, true); } +/* 128-bit significand of log2(e). */ +#define log2_e_sig_high 0xb8aa3b295c17f0bbULL +#define log2_e_sig_low 0xbe87fed0691d3e89ULL + +/* + * Polynomial coefficients for an approximation to log2((1+x)/(1-x)), + * with only odd powers of x used, for x in the interval [2*sqrt(2)-3, + * 3-2*sqrt(2)], which corresponds to logarithms of numbers in the + * interval [sqrt(2)/2, sqrt(2)]. + */ +#define fyl2x_coeff_0 make_floatx80(0x4000, 0xb8aa3b295c17f0bcULL) +#define fyl2x_coeff_0_low make_floatx80(0xbfbf, 0x834972fe2d7bab1bULL) +#define fyl2x_coeff_1 make_floatx80(0x3ffe, 0xf6384ee1d01febb8ULL) +#define fyl2x_coeff_2 make_floatx80(0x3ffe, 0x93bb62877cdfa2e3ULL) +#define fyl2x_coeff_3 make_floatx80(0x3ffd, 0xd30bb153d808f269ULL) +#define fyl2x_coeff_4 make_floatx80(0x3ffd, 0xa42589eaf451499eULL) +#define fyl2x_coeff_5 make_floatx80(0x3ffd, 0x864d42c0f8f17517ULL) +#define fyl2x_coeff_6 make_floatx80(0x3ffc, 0xe3476578adf26272ULL) +#define fyl2x_coeff_7 make_floatx80(0x3ffc, 0xc506c5f874e6d80fULL) +#define fyl2x_coeff_8 make_floatx80(0x3ffc, 0xac5cf50cc57d6372ULL) +#define fyl2x_coeff_9 make_floatx80(0x3ffc, 0xb1ed0066d971a103ULL) + void helper_fyl2xp1(CPUX86State *env) { - double fptemp = floatx80_to_double(env, ST0); + uint8_t old_flags = save_exception_flags(env); + uint64_t arg0_sig = extractFloatx80Frac(ST0); + int32_t arg0_exp = extractFloatx80Exp(ST0); + bool arg0_sign = extractFloatx80Sign(ST0); + uint64_t arg1_sig = extractFloatx80Frac(ST1); + int32_t arg1_exp = extractFloatx80Exp(ST1); + bool arg1_sign = extractFloatx80Sign(ST1); - if ((fptemp + 1.0) > 0.0) { - fptemp = log(fptemp + 1.0) / log(2.0); /* log2(ST + 1.0) */ - fptemp *= floatx80_to_double(env, ST1); - ST1 = double_to_floatx80(env, fptemp); - fpop(env); + if (floatx80_is_signaling_nan(ST0, &env->fp_status)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_silence_nan(ST0, &env->fp_status); + } else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_silence_nan(ST1, &env->fp_status); + } else if (floatx80_invalid_encoding(ST0) || + floatx80_invalid_encoding(ST1)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_default_nan(&env->fp_status); + } else if (floatx80_is_any_nan(ST0)) { + ST1 = ST0; + } else if (floatx80_is_any_nan(ST1)) { + /* Pass this NaN through. */ + } else if (arg0_exp > 0x3ffd || + (arg0_exp == 0x3ffd && arg0_sig > (arg0_sign ? + 0x95f619980c4336f7ULL : + 0xd413cccfe7799211ULL))) { + /* + * Out of range for the instruction (ST0 must have absolute + * value less than 1 - sqrt(2)/2 = 0.292..., according to + * Intel manuals; AMD manuals allow a range from sqrt(2)/2 - 1 + * to sqrt(2) - 1, which we allow here), treat as invalid. + */ + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_default_nan(&env->fp_status); + } else if (floatx80_is_zero(ST0) || floatx80_is_zero(ST1) || + arg1_exp == 0x7fff) { + /* + * One argument is zero, or multiplying by infinity; correct + * result is exact and can be obtained by multiplying the + * arguments. + */ + ST1 = floatx80_mul(ST0, ST1, &env->fp_status); + } else if (arg0_exp < 0x3fb0) { + /* + * Multiplying both arguments and an extra-precision version + * of log2(e) is sufficiently precise. + */ + uint64_t sig0, sig1, sig2; + int32_t exp; + if (arg0_exp == 0) { + normalizeFloatx80Subnormal(arg0_sig, &arg0_exp, &arg0_sig); + } + if (arg1_exp == 0) { + normalizeFloatx80Subnormal(arg1_sig, &arg1_exp, &arg1_sig); + } + mul128By64To192(log2_e_sig_high, log2_e_sig_low, arg0_sig, + &sig0, &sig1, &sig2); + exp = arg0_exp + 1; + mul128By64To192(sig0, sig1, arg1_sig, &sig0, &sig1, &sig2); + exp += arg1_exp - 0x3ffe; + /* This result is inexact. */ + sig1 |= 1; + ST1 = normalizeRoundAndPackFloatx80(80, arg0_sign ^ arg1_sign, exp, + sig0, sig1, &env->fp_status); } else { - env->fpus &= ~0x4700; - env->fpus |= 0x400; + bool asign; + uint32_t dexp, texp, aexp; + uint64_t dsig0, dsig1, tsig0, tsig1, rsig0, rsig1, rsig2; + uint64_t msig0, msig1, msig2, t2sig0, t2sig1, t2sig2, t2sig3; + uint64_t asig0, asig1, asig2, asig3, bsig0, bsig1; + floatx80 t2, accum; + FloatRoundMode save_mode = env->fp_status.float_rounding_mode; + signed char save_prec = env->fp_status.floatx80_rounding_precision; + env->fp_status.float_rounding_mode = float_round_nearest_even; + env->fp_status.floatx80_rounding_precision = 80; + + /* + * Compute an approximation of ST0/(2+ST0), with extra + * precision, as the argument to a polynomial approximation. + * The extra precision is only needed for the first term of + * the approximation, with subsequent terms being + * significantly smaller; the approximation only uses odd + * exponents, and the square of ST0/(2+ST0) is at most + * 17-12*sqrt(2) = 0.029.... + */ + if (arg0_sign) { + dexp = 0x3fff; + shift128RightJamming(arg0_sig, 0, dexp - arg0_exp, &dsig0, &dsig1); + sub128(0, 0, dsig0, dsig1, &dsig0, &dsig1); + } else { + dexp = 0x4000; + shift128RightJamming(arg0_sig, 0, dexp - arg0_exp, &dsig0, &dsig1); + dsig0 |= 0x8000000000000000ULL; + } + texp = arg0_exp - dexp + 0x3ffe; + rsig0 = arg0_sig; + rsig1 = 0; + rsig2 = 0; + if (dsig0 <= rsig0) { + shift128Right(rsig0, rsig1, 1, &rsig0, &rsig1); + ++texp; + } + tsig0 = estimateDiv128To64(rsig0, rsig1, dsig0); + mul128By64To192(dsig0, dsig1, tsig0, &msig0, &msig1, &msig2); + sub192(rsig0, rsig1, rsig2, msig0, msig1, msig2, + &rsig0, &rsig1, &rsig2); + while ((int64_t) rsig0 < 0) { + --tsig0; + add192(rsig0, rsig1, rsig2, 0, dsig0, dsig1, + &rsig0, &rsig1, &rsig2); + } + tsig1 = estimateDiv128To64(rsig1, rsig2, dsig0); + /* + * No need to correct any estimation error in tsig1; even with + * such error, it is accurate enough. Now compute the square + * of that approximation. + */ + mul128To256(tsig0, tsig1, tsig0, tsig1, + &t2sig0, &t2sig1, &t2sig2, &t2sig3); + t2 = normalizeRoundAndPackFloatx80(80, false, texp + texp - 0x3ffe, + t2sig0, t2sig1, &env->fp_status); + + /* Compute the lower parts of the polynomial expansion. */ + accum = floatx80_mul(fyl2x_coeff_9, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_8, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_7, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_6, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_5, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_4, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_3, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_2, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_1, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_0_low, accum, &env->fp_status); + + /* + * The full polynomial expansion is fyl2x_coeff_0 + accum + * (where accum has much lower magnitude, and so, in + * particular, carry out of the addition is not possible), + * multiplied by t. (This expansion is only accurate to about + * 70 bits, not 128 bits.) + */ + aexp = extractFloatx80Exp(fyl2x_coeff_0); + asign = extractFloatx80Sign(fyl2x_coeff_0); + shift128RightJamming(extractFloatx80Frac(accum), 0, + aexp - extractFloatx80Exp(accum), + &asig0, &asig1); + bsig0 = extractFloatx80Frac(fyl2x_coeff_0); + bsig1 = 0; + if (asign == extractFloatx80Sign(accum)) { + add128(bsig0, bsig1, asig0, asig1, &asig0, &asig1); + } else { + sub128(bsig0, bsig1, asig0, asig1, &asig0, &asig1); + } + /* + * Multiply by t and by the second argument to compute the + * required result. + */ + mul128To256(asig0, asig1, tsig0, tsig1, + &asig0, &asig1, &asig2, &asig3); + aexp += texp - 0x3ffe; + if (arg1_exp == 0) { + normalizeFloatx80Subnormal(arg1_sig, &arg1_exp, &arg1_sig); + } + mul128By64To192(asig0, asig1, arg1_sig, &asig0, &asig1, &asig2); + aexp += arg1_exp - 0x3ffe; + /* This result is inexact. */ + asig1 |= 1; + env->fp_status.float_rounding_mode = save_mode; + ST1 = normalizeRoundAndPackFloatx80(80, arg0_sign ^ arg1_sign, aexp, + asig0, asig1, &env->fp_status); + env->fp_status.floatx80_rounding_precision = save_prec; } + fpop(env); + merge_exception_flags(env, old_flags); } void helper_fsqrt(CPUX86State *env) diff --git a/tests/tcg/i386/test-i386-fyl2xp1.c b/tests/tcg/i386/test-i386-fyl2xp1.c new file mode 100644 index 0000000000..99b08c188a --- /dev/null +++ b/tests/tcg/i386/test-i386-fyl2xp1.c @@ -0,0 +1,1156 @@ +/* Test fyl2xp1 instruction. */ + +#include + +struct test { + long double arg0, arg1, down, up; +}; + +const struct test tests[] = { + { 0.0L, 12345.0L, 0.0L, 0.0L }, + { 0.0L, -12345.0L, -0.0L, -0.0L }, + { -0.0L, 12345.0L, -0.0L, -0.0L }, + { -0.0L, -12345.0L, 0.0L, 0.0L }, + { 0.0L, 0.0L, 0.0L, 0.0L }, + { 0.0L, -0.0L, -0.0L, -0.0L }, + { -0.0L, 0.0L, -0.0L, -0.0L }, + { -0.0L, -0.0L, 0.0L, 0.0L }, + { 0.1L, 0.0L, 0.0L, 0.0L }, + { 0.1L, -0.0L, -0.0L, -0.0L }, + { -0.1L, 0.0L, -0.0L, -0.0L }, + { -0.1L, -0.0L, 0.0L, 0.0L }, + { 0.1L, __builtin_infl(), __builtin_infl(), __builtin_infl() }, + { 0.1L, -__builtin_infl(), -__builtin_infl(), -__builtin_infl() }, + { -0.1L, __builtin_infl(), -__builtin_infl(), -__builtin_infl() }, + { -0.1L, -__builtin_infl(), __builtin_infl(), __builtin_infl() }, + { 0x4p-4L, 0x1p-16400L, 0x5.269e12f3468p-16404L, 0x5.269e12f347p-16404L }, + /* Randomly generated tests. */ + { 0x1.31edb79669dd58b4p-4L, 0x6.c25439d8a5ce071p+14380L, 0xb.3d0da52c1f58af3p+14376L, 0xb.3d0da52c1f58af4p+14376L }, + { -0x1.8ee6680c65ce5a5p-4L, -0x7.423575b7ac0ba6a8p-2228L, 0x1.12aefa96f5501268p-2228L, 0x1.12aefa96f550126ap-2228L }, + { 0x2.a22cf9563bdd84bcp-140L, -0x2.de6fb39cd2988858p-9616L, -0xa.e65ebedd6a09e4cp-9756L, -0xa.e65ebedd6a09e4bp-9756L }, + { -0x7.d1095c8p-16416L, 0x1.faa600d255691f3cp+6420L, -0x1.6516c14a553da39ap-9992L, -0x1.6516c14a553da398p-9992L }, + { 0x4.109249df7871ecb8p-4L, 0x1.48d8eebeb8e650ccp-4976L, 0x6.b65f4ea303a8bc3p-4980L, 0x6.b65f4ea303a8bc38p-4980L }, + { -0x4.69bcd5ccca0e4b7p-4L, -0x5.8808ae941f249bb8p+5056L, 0x2.93432047c7d8a37p+5056L, 0x2.93432047c7d8a374p+5056L }, + { 0x3.311f29ec8b38ef74p-4L, -0x3.9865a5505c3ae018p+8924L, -0xf.188d6a2bba06e17p+8920L, -0xf.188d6a2bba06e16p+8920L }, + { -0x2.d60110be2e4f812p-4L, 0x9.d61827e646421b3p-11580L, -0x2.c4c3e84b6c7366c8p-11580L, -0x2.c4c3e84b6c7366c4p-11580L }, + { 0xe.e4d7ebcee10774ap-8L, 0x6.5cde5b7691984918p+732L, 0x8.4e3d353f31e18a3p+728L, 0x8.4e3d353f31e18a4p+728L }, + { -0x2.a675c1a9bd30047cp-4L, 0x7.6eae536d8312ebb8p+364L, -0x1.f116f2eaf6acba9ep+364L, -0x1.f116f2eaf6acba9cp+364L }, + { 0xb.b88ac679a0d52c7p-8L, 0x1.9e45eb57212a1f62p-8572L, 0x1.ac193570d9ac8e8p-8576L, 0x1.ac193570d9ac8e82p-8576L }, + { -0x4.64109ab4700cf108p-4L, 0x6.b8d96cb8e5f2d648p+6524L, -0x3.1c6e7c0e4e7a72cp+6524L, -0x3.1c6e7c0e4e7a72bcp+6524L }, + { 0x3.e104f8db9c02bf08p-4L, -0x9.7b905723db3fe54p+10116L, -0x2.f83eb6c0529e814p+10116L, -0x2.f83eb6c0529e813cp+10116L }, + { -0x3.906c6b45a9367874p-4L, -0x3.b4f349ff071caa64p-1868L, 0x1.5901debf0c548972p-1868L, 0x1.5901debf0c548974p-1868L }, + { 0x1.a960a3b0bddab872p-4L, -0xa.80f80d092c59d2fp+14796L, -0x1.7f4db50bf3cd7588p+14796L, -0x1.7f4db50bf3cd7586p+14796L }, + { -0x1.422d05691d16c3c2p-4L, -0x3.b7afc1088aafbb28p+8056L, 0x7.07a7a145b32d0108p+8052L, 0x7.07a7a145b32d011p+8052L }, + { 0x3.005497260bfe3efcp-4L, 0x2.70b5fc4ea650b9d4p+13164L, 0x9.af1b9b78be96p+13160L, 0x9.af1b9b78be96001p+13160L }, + { -0x3.06e1d8ce558315f4p-4L, 0xd.35a31147278a276p+13452L, -0x3.ff1a81342b225bf4p+13452L, -0x3.ff1a81342b225bfp+13452L }, + { 0x5.0312793de5c8af88p-8L, -0x1.4d64bd7151f8f83ep+13040L, -0x9.53672f561e11e6dp+13032L, -0x9.53672f561e11e6cp+13032L }, + { -0x4.6fd8156d1cd1594p-4L, 0x1.2bbce9cdd6e3b99ep+2372L, -0x8.c70a26daa3a50c9p+2368L, -0x8.c70a26daa3a50c8p+2368L }, + { 0x1.eab2d269541adaap-4L, 0x6.ac21c841f135e818p-10084L, 0x1.16d60a1c1c53feb2p-10084L, 0x1.16d60a1c1c53feb4p-10084L }, + { -0x3.f7c63bee23b61aep-4L, -0x1.a4746c335dbffc62p+13532L, 0xa.ce1e8b95a3cf783p+13528L, 0xa.ce1e8b95a3cf784p+13528L }, + { 0x2.6770b5d4fbdb93ap-4L, 0x2.d0747a0fc160c9d8p-680L, 0x9.17f6580ba6d8d8fp-684L, 0x9.17f6580ba6d8d9p-684L }, + { -0x4.0c0f16fccf171958p-4L, -0x3.809f02e6f0a4a7ccp-632L, 0x1.793819991e50c69p-632L, 0x1.793819991e50c692p-632L }, + { 0x2.810e5178p-16416L, -0x2.449b1281f31c58ccp-8912L, -0x8p-16448L, -0x0p+0L }, + { -0x9.d14aa8cda67cd5p-80L, 0x2.3ff156f07699390cp+1860L, -0x1.fdd7e7674c238f56p+1784L, -0x1.fdd7e7674c238f54p+1784L }, + { 0x4.336973fa388adee8p-4L, 0x6.68a249106b0173e8p+1992L, 0x2.27d09f940daa748cp+1992L, 0x2.27d09f940daa749p+1992L }, + { -0x2.975eb02ec54042c4p-4L, -0xe.5f17872c08b122dp+7300L, 0x3.a9ce29cce0f873bp+7300L, 0x3.a9ce29cce0f873b4p+7300L }, + { 0x3.18142b116ed172acp-4L, -0x4.c54f6758e57de6ap+2080L, -0x1.377f5497b5e407dcp+2080L, -0x1.377f5497b5e407dap+2080L }, + { -0x1.1bbc90a005c56912p-4L, -0x4.a9cd0b7c6a571cd8p+5332L, 0x7.ba3b3fc9d3dba0f8p+5328L, 0x7.ba3b3fc9d3dba1p+5328L }, + { 0x1.7e8efe16b98d3692p-8L, -0x3.dde86e3bf4d91464p-4156L, -0x8.4ff4f144076f27ep-4164L, -0x8.4ff4f144076f27dp-4164L }, + { -0xa.7e96579f3a805bp-8L, -0x7.ab5c584ae971a368p+6308L, 0x7.6906aa4947cba078p+6304L, 0x7.6906aa4947cba08p+6304L }, + { 0x1.9eca084b5e88755ep-4L, 0xf.227ce981b624ea7p+11116L, 0x2.1b30979fa829e6dcp+11116L, 0x2.1b30979fa829e6ep+11116L }, + { -0x2.1874c2d880381c8p-4L, -0x1.137b3104db6109dap-5420L, 0x3.7ca97456f9d67034p-5424L, 0x3.7ca97456f9d67038p-5424L }, + { 0x3.198e690cee01623p-4L, -0x1.adc155088273f77ep+13812L, -0x6.dcc1714e4ba0c37p+13808L, -0x6.dcc1714e4ba0c368p+13808L }, + { -0x4.6551f788f1588b28p-4L, -0x7.69f3a55b24a9777p+428L, 0x3.6f8dc0f3c3d2cf44p+428L, 0x3.6f8dc0f3c3d2cf48p+428L }, + { 0x7.88f397834128293p-8L, 0x6.bf38fb4299638c08p-960L, 0x4.849080f3ab11f818p-964L, 0x4.849080f3ab11f82p-964L }, + { -0x1.b55f0bbc95324732p-4L, 0x1.b42e17120776fe52p-13916L, -0x4.70f2c0a6bc44465p-13920L, -0x4.70f2c0a6bc444648p-13920L }, + { 0x3.32c5f1314a8c6dap-4L, -0x1.bdb2f33681f41db6p+12272L, -0x7.52da7e0b1bed5968p+12268L, -0x7.52da7e0b1bed596p+12268L }, + { -0x3.36905b81e589d9e8p-4L, 0x3.d8dded4726d3fb34p+784L, -0x1.3e840521ab659a96p+784L, -0x1.3e840521ab659a94p+784L }, + { 0x2.f78a13ae770dc39cp-4L, -0x3.cf1123d327fd9024p-9600L, -0xe.f4c0070f6303241p-9604L, -0xe.f4c0070f630324p-9604L }, + { -0x3.5c99081287a8051p-4L, -0x1.70700e3356c86b3cp+7752L, 0x7.d5e5870a6e18d73p+7748L, 0x7.d5e5870a6e18d738p+7748L }, + { 0xa.dd6d280bcc33172p-8L, -0xf.1ff631d3dfa8c85p+4928L, -0xe.82fa32a3cab9bcep+4924L, -0xe.82fa32a3cab9bcdp+4924L }, + { -0x2.ecbb3c2ebebf283p-4L, -0x3.212b343a660ecbb4p+4672L, 0xe.953534ceecbfcf2p+4668L, 0xe.953534ceecbfcf3p+4668L }, + { 0x3.75380852cb5eb234p-4L, -0x2.df562212c19c9528p+12736L, -0xc.f92b33893bdc2ap+12732L, -0xc.f92b33893bdc29fp+12732L }, + { -0x1.ad74e73c3fab3c44p-4L, -0x1.a457ed324f1b85bp-8776L, 0x4.32b38b6b976e91b8p-8780L, 0x4.32b38b6b976e91cp-8780L }, + { 0x2.18c8d7808e9812b8p-144L, 0x5.0f40c3a5a98fe708p-14212L, 0xf.4e3924951dac17fp-14356L, 0xf.4e3924951dac18p-14356L }, + { -0x9.5d0b284b6a68ac4p-184L, -0x3.68104ae46b7bcf6p+12464L, 0x2.e045d02aa9b47858p+12284L, 0x2.e045d02aa9b4785cp+12284L }, + { 0x2.2261e8b5a73122bcp-4L, 0x1.39e07d457c893d2p-4904L, 0x3.8b3a68313dff915p-4908L, 0x3.8b3a68313dff9154p-4908L }, + { -0x3.e7f8b8fdf0027474p-4L, 0xb.8b615ebfce42d08p-1688L, -0x4.a95fab921aa3a9c8p-1688L, -0x4.a95fab921aa3a9cp-1688L }, + { 0x2.90731457099d1b3p-4L, 0x3.41f7f39a30b3898cp-8352L, 0xb.2d9667a84b2a4dbp-8356L, 0xb.2d9667a84b2a4dcp-8356L }, + { -0x1.090c8ddde72dd1a2p-4L, 0x1.6a8b36c84fd8d976p+12300L, -0x2.2fd80d7e66d3f60cp+12296L, -0x2.2fd80d7e66d3f608p+12296L }, + { 0x2.40b0eeedb834a1d4p-4L, 0x3.56b6f4120c52d84cp-10716L, 0xa.26da0df382c1052p-10720L, 0xa.26da0df382c1053p-10720L }, + { -0x1.a336b1480b20b424p-4L, 0x2.2ac2bc77bdfef9ccp+8860L, -0x5.66a4f7795a77dca8p+8856L, -0x5.66a4f7795a77dcap+8856L }, + { 0xe.db656802d11a281p-8L, -0x4.2e126b3484e7514p+13440L, -0x5.717346005231cffp+13436L, -0x5.717346005231cfe8p+13436L }, + { -0x1.c4b925adab67ae7ep-4L, 0x1.a15ba1a3fbe9dd4p-6564L, -0x4.68657bab4041a828p-6568L, -0x4.68657bab4041a82p-6568L }, + { 0x3.7586cb9442c45784p-4L, -0x7.713929beef89c638p-6972L, -0x2.19fb69e21ac718acp-6972L, -0x2.19fb69e21ac718a8p-6972L }, + { -0x2.fa71ba62a32a8b7p-4L, -0xa.936c0eb50eb5e37p-6908L, 0x3.24855b9f7f8ce32p-6908L, 0x3.24855b9f7f8ce324p-6908L }, + { 0x3.67490f5787dde48p-4L, 0xf.67432f04da27bbp-524L, 0x4.492e50d2f71cf588p-524L, 0x4.492e50d2f71cf59p-524L }, + { -0x2.97b9427d1d5c7c24p-4L, 0x1.57a9f87e42d057eep+5708L, -0x5.7a6c8388322303c8p+5704L, -0x5.7a6c8388322303cp+5704L }, + { 0x1.33ef1ab5c6634e46p-4L, 0x1.d8999e72af335708p+9564L, 0x3.16c5444800c64aa8p+9560L, 0x3.16c5444800c64aacp+9560L }, + { -0xa.9a5ba7d8b6734cdp-8L, 0xa.671a839c0039ab8p-5508L, -0xa.284bae12c6dde0dp-5512L, -0xa.284bae12c6dde0cp-5512L }, + { 0xe.181100f05f0394cp-8L, -0x3.f3e2c4d22523780cp-416L, -0x4.e3ca00e35b39c898p-420L, -0x4.e3ca00e35b39c89p-420L }, + { -0x1.66f888b96b8e00e8p-4L, -0x3.8ded010cb7762338p+10300L, 0x7.867a91379ede7e08p+10296L, 0x7.867a91379ede7e1p+10296L }, + { 0x4.a6c0029c00b96fep-4L, -0x4.e87d73d329cb332p+11216L, -0x1.ce989e2a560b54b2p+11216L, -0x1.ce989e2a560b54bp+11216L }, + { -0x3.5843155f8dc36dfp-4L, -0xa.15334aafc6d22b9p-13476L, 0x3.6951d7122f8daafp-13476L, 0x3.6951d7122f8daaf4p-13476L }, + { 0x4.22701b25d6c80c3p-4L, -0x5.126eff0187a3803p-9272L, -0x1.ae8f4e7823ebfeeep-9272L, -0x1.ae8f4e7823ebfeecp-9272L }, + { -0x1.a7a0556e6f951196p-4L, 0x8.0be412ff866338fp+4496L, -0x1.44704cea9eeb28f4p+4496L, -0x1.44704cea9eeb28f2p+4496L }, + { 0x1.36be53940221672p-172L, -0x7.194c9b043451bfep+4704L, -0xc.6e75e23d8e56928p+4532L, -0xc.6e75e23d8e56927p+4532L }, + { -0x1.f30afcd111913c04p-156L, 0x9.b3ff5c8d9b3d3acp+2792L, -0x1.b49eb9a0eb4c908cp+2640L, -0x1.b49eb9a0eb4c908ap+2640L }, + { 0x3.140ad6b1e9922ec4p-4L, 0x3.bff4c5061256d8ccp-12384L, 0xf.3b1c7d17ba2c0edp-12388L, 0xf.3b1c7d17ba2c0eep-12388L }, + { -0x3.9ede658d4493b08p-4L, 0x2.f71c7b1bb45c5604p-12156L, -0x1.18f7f35b0c252984p-12156L, -0x1.18f7f35b0c252982p-12156L }, + { 0x2.4ddf39d02ae29214p-4L, -0x1.d106f81605905eeap+7920L, -0x5.a433bd60909bf0bp+7916L, -0x5.a433bd60909bf0a8p+7916L }, + { -0x1.c546cdac360a9cp-4L, -0x7.bad48611f3e40dap+7376L, 0x1.4ed08a35cb87ed0ep+7376L, 0x1.4ed08a35cb87ed1p+7376L }, + { 0x1.a15d4c117c202388p-4L, 0xd.0e541be4b24c664p+12760L, 0x1.d3e2699c368b4f18p+12760L, 0x1.d3e2699c368b4f1ap+12760L }, + { -0x7.16658416ee8125e8p-8L, 0x1.62dc2caf9f8fdad6p-5160L, -0xe.5fa5d852e85667p-5168L, -0xe.5fa5d852e85666fp-5168L }, + { 0xd.0bad0960312abe4p-12L, 0x1.f48ad8b59f54a95cp+192L, 0x2.4bda7bbd2000768p+184L, 0x2.4bda7bbd20007684p+184L }, + { -0x3.f1bddc60ebe5c3ap-4L, 0x8.063bbdb884d4c9fp-7972L, -0x3.46dc3e1d744ccba8p-7972L, -0x3.46dc3e1d744ccba4p-7972L }, + { 0xe.8a2046b2bb94931p-8L, 0x7.322c00fd114c6b78p+5120L, 0x9.2d030614c8ad44fp+5116L, 0x9.2d030614c8ad45p+5116L }, + { -0x3.7454ee5b08c8cb7cp-4L, -0x3.642f824f3db6287cp+11984L, 0x1.30a3de1a3b5cc8aap+11984L, 0x1.30a3de1a3b5cc8acp+11984L }, + { 0x3.b7e07d72b90e939p-4L, 0x4.8d8e9330b67dc858p-1260L, 0x1.5f5eb6ed8b9c0ed4p-1260L, 0x1.5f5eb6ed8b9c0ed6p-1260L }, + { -0xc.f22d7bfd55c6c94p-8L, 0x4.64873d3f77ee2338p-2776L, -0x5.430a59c679c81728p-2780L, -0x5.430a59c679c8172p-2780L }, + { 0x2.50df0103c304075cp-4L, -0x7.b4b24f138f39278p+14856L, -0x1.80b99699a7f61822p+14856L, -0x1.80b99699a7f6182p+14856L }, + { -0x3.1f0b53ee6296bd78p-4L, -0x7.0f43afd6ab41b8c8p-13572L, 0x2.35d20bba726b6ae8p-13572L, 0x2.35d20bba726b6aecp-13572L }, + { 0x2.6725591bb528453cp-4L, 0x1.ce864eaac5f98256p-8564L, 0x5.d5dc4cda5a5180a8p-8568L, 0x5.d5dc4cda5a5180bp-8568L }, + { -0x3.2290e7cdb1817facp-4L, 0x3.4d8a9f94b9a431bcp-11728L, -0x1.0a06e1a9cc7457eap-11728L, -0x1.0a06e1a9cc7457e8p-11728L }, + { 0x3.8b99e9b78a041538p-4L, -0x3.b23e0cc201793b9p+6472L, -0x1.113a80c6eb278128p+6472L, -0x1.113a80c6eb278126p+6472L }, + { -0x1.1f197acd86bd6b08p-4L, -0x1.f1665c655caaaf4ap-6144L, 0x3.425e0b5214f9cd34p-6148L, 0x3.425e0b5214f9cd38p-6148L }, + { 0xf.ed161e95b0ae352p-8L, -0x8.be9a4b8e5552e1cp-8976L, -0xc.2eacd7db48ff243p-8980L, -0xc.2eacd7db48ff242p-8980L }, + { -0x3.6a4be64691ce57a4p-4L, -0x5.839b606e3a436a78p-6768L, 0x1.e8f825b15269b6cap-6768L, 0x1.e8f825b15269b6ccp-6768L }, + { 0x5.00c1d6bp-16416L, -0x4.b497e93cf288163p+9424L, -0x2.1f671dd90f010a24p-6988L, -0x2.1f671dd90f010a2p-6988L }, + { -0x2.5a584197e5510fc4p-132L, -0x1.1772e32ccdc2478p+14528L, 0x3.b498edc574c550ccp+14396L, 0x3.b498edc574c550dp+14396L }, + { 0x2.f851cb35a14097acp-4L, -0xa.7268d9e3b2e61bap-12600L, -0x2.90f65da0448e38f8p-12600L, -0x2.90f65da0448e38f4p-12600L }, + { -0x4.6d56dca19ebe3708p-4L, -0x2.526a2db40e4a133p+760L, 0x1.15c884d416e79d9cp+760L, 0x1.15c884d416e79d9ep+760L }, + { 0x2.fe2658a2c8078de8p-4L, 0x1.0d699d587ebc0e5p-10464L, 0x4.2a59bbf556de3138p-10468L, 0x4.2a59bbf556de314p-10468L }, + { -0x3.0fe4a68e65c41494p-4L, -0x1.7173155e4bd10df2p+1836L, 0x7.13952436db99bf8p+1832L, 0x7.13952436db99bf88p+1832L }, + { 0x4.033ea3caa0b5f698p-4L, -0x6.03ab20e0280437cp-188L, -0x1.f111dcaf19286f9p-188L, -0x1.f111dcaf19286f8ep-188L }, + { -0x4.5b0056b6b6068878p-4L, -0xc.6497d33070a9a97p+5684L, 0x5.ae614b07dc079ecp+5684L, 0x5.ae614b07dc079ec8p+5684L }, + { 0x1.82adf1f869ababbcp-4L, -0x1.123ccd14ea237d04p-7084L, -0x2.3b0d91c0089d65e4p-7088L, -0x2.3b0d91c0089d65ep-7088L }, + { -0x2.5b451d0b82180d44p-4L, 0x6.8a58d91ee307a548p-8008L, -0x1.80ddcbdeb9c0f3bap-8008L, -0x1.80ddcbdeb9c0f3b8p-8008L }, + { 0x2.e352f84376e4f1d8p-4L, 0x5.8248426003120498p-7260L, 0x1.519dfeeb985eb048p-7260L, 0x1.519dfeeb985eb04ap-7260L }, + { -0xa.7b393feb80e94efp-12L, 0x2.ef48748849de0554p-12820L, -0x2.c6eff255a859ad08p-12828L, -0x2.c6eff255a859ad04p-12828L }, + { 0x1.5fbb3b2cb9a73a0ap-4L, -0x4.a27aba12e1fe1ef8p+10496L, -0x8.d048b795b632ed1p+10492L, -0x8.d048b795b632edp+10492L }, + { -0x3.809836ef223bfdacp-4L, 0x2.0d96044152595614p-8280L, -0xb.b533a267a420e5fp-8284L, -0xb.b533a267a420e5ep-8284L }, + { 0x2.71939b3f2db2b26p-4L, -0xd.d36dfd2744533a6p+10580L, -0x2.d5c54067b4f1a7ep+10580L, -0x2.d5c54067b4f1a7dcp+10580L }, + { -0x3.6b9ad80ebf1deb08p-4L, 0x6.7a681b6bb071e288p+13136L, -0x2.3f6e3d82be3f2ad4p+13136L, -0x2.3f6e3d82be3f2adp+13136L }, + { 0x2.9afe8631c4e5ce7p-4L, -0x3.83b2bda6ed10fea8p+4784L, -0xc.3d274a1edea87ebp+4780L, -0xc.3d274a1edea87eap+4780L }, + { -0x2.c4c0d66a1b99c3c8p-4L, 0x2.5b1e1eead3bb2cacp+13080L, -0xa.550eea778396ce3p+13076L, -0xa.550eea778396ce2p+13076L }, + { 0x4.08187131d98288b8p-4L, 0xc.30a692d385849d1p+3460L, 0x3.f3bcf1eaed28f854p+3460L, 0x3.f3bcf1eaed28f858p+3460L }, + { -0x2.ef6cdbc058cd31ep-4L, 0x2.75c1df05fa79e34p-5496L, -0xb.822f6abf9319caap-5500L, -0xb.822f6abf9319ca9p-5500L }, + { 0xc.80ee642b1a4020bp-8L, -0xc.f511a8dcdc0ce5ep+13800L, -0xe.43506254711d49bp+13796L, -0xe.43506254711d49ap+13796L }, + { -0x2.0992fd9466d2b79p-4L, -0x5.3b81e7664b8716fp+3608L, 0x1.0738060d1d9ad53ap+3608L, 0x1.0738060d1d9ad53cp+3608L }, + { 0x4.7e5d88ep-16416L, 0x4.b21a682b16590228p-5704L, 0x0p+0L, 0x8p-16448L }, + { -0x3.70fb6523fc99c194p-176L, 0xc.8fca8d5dd6ce8cep+9336L, -0x3.e5dc145add1549cp+9164L, -0x3.e5dc145add1549bcp+9164L }, + { 0x3.a722ebee85536cdp-4L, -0x7.e92da929dfeccb3p-11692L, -0x2.58ce8b42e26f75cp-11692L, -0x2.58ce8b42e26f75bcp-11692L }, + { -0x3.53ab833486c08db8p-4L, -0x8.ec1b59a9caa6303p-7400L, 0x3.00224e3c6217e70cp-7400L, 0x3.00224e3c6217e71p-7400L }, + { 0x4.9487cc987ce18b6p-4L, 0x1.b43405b727b9b4ecp+660L, 0x9.e6c239cbd68f84cp+656L, 0x9.e6c239cbd68f84dp+656L }, + { -0xe.32da65364dfac0fp-8L, -0x1.a0b348b4888fa2fcp-124L, 0x2.24daad6dfa91c368p-128L, 0x2.24daad6dfa91c36cp-128L }, + { 0x2.31765e800ee61554p-4L, 0xd.bd9f34293d3d29bp+4316L, 0x2.8bea4d125ba3dd28p+4316L, 0x2.8bea4d125ba3dd2cp+4316L }, + { -0x7.e8d207888e10bb28p-8L, 0xf.1545995a9604c33p+4440L, -0xa.ed3b79e2b24ae3cp+4436L, -0xa.ed3b79e2b24ae3bp+4436L }, + { 0x2.0dbde28b26dc5474p-4L, -0x1.d9f5b1f814163e0ep+3520L, -0x5.292de7ec7fde3dbp+3516L, -0x5.292de7ec7fde3da8p+3516L }, + { -0x2.5da10be7bc76adbcp-4L, 0xe.9c1364eb8db9e71p+11700L, -0x3.5f577bc6db6ff75cp+11700L, -0x3.5f577bc6db6ff758p+11700L }, + { 0x1.7fb27a800f7431d8p-4L, 0x3.fe39a5a5f5c97a9p+3280L, 0x8.40e81d2da1bfc96p+3276L, 0x8.40e81d2da1bfc97p+3276L }, + { -0x3.bb9fab7278c86f2p-4L, -0xf.0cbb72ff70654d3p-12084L, 0x5.c4ab2766bb87bf6p-12084L, 0x5.c4ab2766bb87bf68p-12084L }, + { 0x3.aa809df3dbec6abp-4L, 0x2.15e22591ab1c856p+7060L, 0x9.ee6cd49285b6905p+7056L, 0x9.ee6cd49285b6906p+7056L }, + { -0x1.248726fb26304a8ep-4L, 0xf.6e6ebaa083c4cd3p-2404L, -0x1.a64bcf5800dc981p-2404L, -0x1.a64bcf5800dc980ep-2404L }, + { 0x3.e5c9dd1ff3793c6cp-4L, -0xe.77c56c623d0f0eep-11552L, -0x4.8cec2abe53411658p-11552L, -0x4.8cec2abe5341165p-11552L }, + { -0x9.e1fb01951741bb8p-12L, 0x3.dc9d2acf270903a8p+14376L, -0x3.7207777a5f25e4bcp+14368L, -0x3.7207777a5f25e4b8p+14368L }, + { 0x2.d447d6b5e5ce3cc8p-4L, 0xc.0731d6f892df414p+2464L, 0x2.d34ea5652b7493e8p+2464L, 0x2.d34ea5652b7493ecp+2464L }, + { -0x3.ed070cb292baae74p-4L, 0x1.f5bda0c135772ea8p+5972L, -0xc.bc8d2aeea6f8d93p+5968L, -0xc.bc8d2aeea6f8d92p+5968L }, + { 0x4.45d277b639fcf9c8p-4L, 0x7.75d18c49b089dc88p-1124L, 0x2.8c2501bc216e5db4p-1124L, 0x2.8c2501bc216e5db8p-1124L }, + { -0x4.9e8c6ba757e6aa9p-4L, 0xd.170086ac1893a93p+13928L, -0x6.6ef8d754645a469p+13928L, -0x6.6ef8d754645a4688p+13928L }, + { 0x2.3c7efc4a74a8b844p-4L, 0x2.089221e2807b8ae8p+13656L, 0x6.240ef782a887ef18p+13652L, 0x6.240ef782a887ef2p+13652L }, + { -0x3.4b58e3e6f3f4be84p-4L, -0x7.011c78290d122728p+12196L, 0x2.546305cf20c52e78p+12196L, 0x2.546305cf20c52e7cp+12196L }, + { 0x3.c013919270a9d0a8p-200L, -0x4.0e8c6ae1a53296c8p+7956L, -0x1.5f31af56e9407d08p+7760L, -0x1.5f31af56e9407d06p+7760L }, + { -0x1.f7dc69dp-16416L, -0x1.bf51089c520b29b4p+4664L, 0x4.f62a54dd5dd4a83p-11752L, 0x4.f62a54dd5dd4a838p-11752L }, + { 0x1.e00da7403dc86138p-4L, -0x5.35b41b797fb9331p-3908L, -0xd.53e4f12ca294a6p-3912L, -0xd.53e4f12ca294a5fp-3912L }, + { -0x2.bf8b03274d13363cp-4L, -0x1.05cdd981abf77a14p+1464L, 0x4.72e3f9ff62128ed8p+1460L, 0x4.72e3f9ff62128eep+1460L }, + { 0x3.d7776260cc65e86p-4L, 0xb.13430c035931444p-3664L, 0x3.703d2634906f9538p-3664L, 0x3.703d2634906f953cp-3664L }, + { -0xf.d2d322382421f69p-8L, -0x8.f017932d188a998p+2680L, 0xd.29ddb607a558484p+2676L, 0xd.29ddb607a558485p+2676L }, + { 0x1.1da304350ac720aap-4L, 0x6.36b4ef636b98ac98p+10536L, 0x9.ab3f04c20130e66p+10532L, 0x9.ab3f04c20130e67p+10532L }, + { -0x4.a32b02b37caedc88p-4L, 0x5.4e587c75d5a6bfcp+14104L, -0x2.9eb7d7a4081dba88p+14104L, -0x2.9eb7d7a4081dba84p+14104L }, + { 0x1.5ac66b5ac9bb06fcp-4L, -0x3.c7ea3c3c2b39e2c8p-5248L, -0x7.17bcb1e2b4044dp-5252L, -0x7.17bcb1e2b4044cf8p-5252L }, + { -0x4.861b827cdb0400cp-4L, 0x1.d7dd30f75b264db4p-6584L, -0xe.23a4a8fbc48fd9fp-6588L, -0xe.23a4a8fbc48fd9ep-6588L }, + { 0x8.86257636294381fp-8L, 0xe.8f9244700df6721p+4408L, 0xb.02557c2fc89289bp+4404L, 0xb.02557c2fc89289cp+4404L }, + { -0x1.0dfbe47a9aca7786p-4L, 0x5.e2a8926a1f2a69f8p-2832L, -0x9.436d5defb285aa4p-2836L, -0x9.436d5defb285aa3p-2836L }, + { 0x2.bff85b9860bb1c0cp-4L, -0x1.8989c2560de848e8p-2992L, -0x5.a0b9bd60c6e9415p-2996L, -0x5.a0b9bd60c6e94148p-2996L }, + { -0x2.43f55447649b8c24p-4L, -0x1.b21f1e71fce5162ep-9792L, 0x5.f9f03cfb02f136b8p-9796L, 0x5.f9f03cfb02f136cp-9796L }, + { 0xd.df18cea4044bb26p-8L, -0x6.a546c7e5065f0158p+12584L, -0x8.184130740ad26bep+12580L, -0x8.184130740ad26bdp+12580L }, + { -0x2.0aa382fea7dd8ed4p-4L, 0x1.922b0febfe6b22bep+14300L, -0x4.f33585b409b249b8p+14296L, -0x4.f33585b409b249bp+14296L }, + { 0x1.9f8df2c594f5aba2p-4L, 0xa.a22cceb5d16a7b9p+12368L, 0x1.7b7ed32a30c1340ep+12368L, 0x1.7b7ed32a30c1341p+12368L }, + { -0x2.3a7805cc42052c88p-4L, 0x6.0c375211e7de2b68p-13748L, -0x1.4efed1a1d060daf8p-13748L, -0x1.4efed1a1d060daf6p-13748L }, + { 0xb.98b5acf06c53957p-8L, 0xa.c01d2e9cf20bab2p-408L, 0xa.fe7242406c2e29dp-412L, 0xa.fe7242406c2e29ep-412L }, + { -0x3.b426327377c1e0ccp-8L, -0x7.c0b1a87701c336f8p+4900L, 0x2.9ba51806e9e0d1c4p+4896L, 0x2.9ba51806e9e0d1c8p+4896L }, + { 0x2.32a92ffd519efa3p-4L, -0x1.ba7195161943bbbep-5192L, -0x5.2295fa8174e88c5p-5196L, -0x5.2295fa8174e88c48p-5196L }, + { -0x2.494a01edd418deacp-4L, 0x6.693114f18c78632p+10664L, -0x1.6d165465955afcb4p+10664L, -0x1.6d165465955afcb2p+10664L }, + { 0x3.36cc1fd8p-16416L, -0x3.731a5226115dd018p-13876L, -0x8p-16448L, -0x0p+0L }, + { -0x5.a44d891b492c118p-64L, 0xb.69fb96dbb13b38cp-1084L, -0x5.ce7362af963c8f38p-1144L, -0x5.ce7362af963c8f3p-1144L }, + { 0x3.474c4807a8ad6228p-4L, -0x2.f3562babd4b5f03cp-12580L, -0xc.b2050e940966a45p-12584L, -0xc.b2050e940966a44p-12584L }, + { -0x1.72da05f3ba83570cp-4L, 0x2.bd74f98cb810cbf8p-3608L, -0x6.00abe3e58945abf8p-3612L, -0x6.00abe3e58945abfp-3612L }, + { 0x3.03355b3ad678a4e4p-4L, 0x2.fcacda0bf497fcdp+624L, 0xb.e4fbcf489c92111p+620L, 0xb.e4fbcf489c92112p+620L }, + { -0x4.87b616543e6d68f8p-4L, -0x1.5aa2807140fcb66ep-5712L, 0xa.6762b975babc4a7p-5716L, 0xa.6762b975babc4a8p-5716L }, + { 0x3.3eef25ea1d0cb1a4p-4L, 0x8.77ef4346014be03p+2668L, 0x2.41b30237313d1594p+2668L, 0x2.41b30237313d1598p+2668L }, + { -0x4.abe5ee4fb3e5bap-4L, -0x9.ad41850d220d88cp+12620L, 0x4.d1f38825ce2a945p+12620L, 0x4.d1f38825ce2a9458p+12620L }, + { 0x5.a5eb695ee8c9932p-8L, 0x1.d13834b0342791d4p-3780L, 0xe.a5a311a3e533135p-3788L, 0xe.a5a311a3e533136p-3788L }, + { -0x3.57d686c40d552838p-4L, -0xf.0b6de12e05c3635p-8368L, 0x5.165c21cb97c896d8p-8368L, 0x5.165c21cb97c896ep-8368L }, + { 0x3.02fa76adc4b3f734p-4L, 0x2.c8a8a9ca263fb34p-1104L, 0xb.1512e047c64d14bp-1108L, 0xb.1512e047c64d14cp-1108L }, + { -0x2.e4dfe9c3785c81f4p-4L, 0x2.47670d17c1a6b908p+7296L, -0xa.7ee8efc4c4a9f53p+7292L, -0xa.7ee8efc4c4a9f52p+7292L }, + { 0x9.aaf264c27c54e8ap-8L, 0xb.54e2e10eee029ffp-4480L, 0x9.b23353124c7f80ap-4484L, 0x9.b23353124c7f80bp-4484L }, + { -0x1.47d8c6c7e55c7a26p-4L, 0x1.2ae861e0c614f7b8p+3208L, -0x2.3f9d8ce1381508fp+3204L, -0x2.3f9d8ce1381508ecp+3204L }, + { 0x3.cb86413e9654e6cp-8L, -0x1.8722bfac85135608p+3816L, -0x8.4dc558bd3004cd6p+3808L, -0x8.4dc558bd3004cd5p+3808L }, + { -0x2.b06c6bf6c50a6bfcp-4L, 0x3.666a36ff2e60f2bcp+12728L, -0xe.7119a8d1ccc016p+12724L, -0xe.7119a8d1ccc015fp+12724L }, + { 0x3.47ce25adf55a2814p-4L, 0x7.ddb836a97dd546bp+10988L, 0x2.1dd4bf63fa5a9bccp+10988L, 0x2.1dd4bf63fa5a9bdp+10988L }, + { -0x9.d038f0be8c9445p-8L, 0x2.cb89c09be031f264p-4624L, -0x2.859a5e7613fdf99cp-4628L, -0x2.859a5e7613fdf998p-4628L }, + { 0x5.f4040498e9510358p-8L, -0xe.8e6b01ce80d9a3bp+268L, -0x7.b965fce804203578p+264L, -0x7.b965fce80420357p+264L }, + { -0x3.9bec29ae6836c004p-4L, 0x3.349abf15c61637ccp-6152L, -0x1.2ea0fb97798d6ffcp-6152L, -0x1.2ea0fb97798d6ffap-6152L }, + { 0x3.1cb0194881148be8p-4L, -0xd.f8498b43249707dp-3144L, -0x3.950056a5b35f5a1cp-3144L, -0x3.950056a5b35f5a18p-3144L }, + { -0x2.bb9b8d7aa3c0d0a4p-4L, 0x5.7723b746db2d4dep-9424L, -0x1.7a10aa106c1d1108p-9424L, -0x1.7a10aa106c1d1106p-9424L }, + { 0xe.4d878fb87fd395ap-12L, 0x3.4f9956a9f16bc38p+2616L, 0x4.4337165130e7f47p+2608L, 0x4.4337165130e7f478p+2608L }, + { -0x1.1630a82965507a32p-16L, 0xa.2e28946ae2eae99p+6956L, -0xf.f5d543fa5f7a7cbp+6940L, -0xf.f5d543fa5f7a7cap+6940L }, + { 0x3.59c0a36418e9a6dp-4L, -0x2.1ad5b8410a86465cp-13676L, -0x9.3ce405e344231efp-13680L, -0x9.3ce405e344231eep-13680L }, + { -0x2.3acdbdd2877849ep-8L, 0x4.84f0a846883e7a18p-6060L, -0xe.99ec6628631da5bp-6068L, -0xe.99ec6628631da5ap-6068L }, + { 0x2.4706917d5d92e68p-4L, 0x3.1e5765ddcaca8e8cp-11800L, 0x9.946873401fa60ap-11804L, 0x9.946873401fa60a1p-11804L }, + { -0x3.c87f60de0535481cp-4L, -0xf.51c1e48dde26436p+1780L, 0x5.f65dcfd39a0ece18p+1780L, 0x5.f65dcfd39a0ece2p+1780L }, + { 0x3.7dc1ea97cf0b5704p-4L, 0xc.90a3dd049ad490bp+7836L, 0x3.93f379f1866fdb2p+7836L, 0x3.93f379f1866fdb24p+7836L }, + { -0x1.f798a53251ee9fbp-4L, -0xe.75c48de977feda3p-5476L, 0x2.bc9e9decff0f5cb4p-5476L, 0x2.bc9e9decff0f5cb8p-5476L }, + { 0xb.aa65757ee31da3p-8L, -0x5.4d142559265fe498p-6132L, -0x5.73e6d4277632f548p-6136L, -0x5.73e6d4277632f54p-6136L }, + { -0x4.6c8e0d8c9dc60d18p-4L, 0x3.c991984ee0203824p+14956L, -0x1.c4bb15413b7086ecp+14956L, -0x1.c4bb15413b7086eap+14956L }, + { 0x1.f5fd4ee6b1f86f46p-4L, -0xd.fee89bfeb4e4785p+3032L, -0x2.55958e192187d838p+3032L, -0x2.55958e192187d834p+3032L }, + { -0x2.5fc6fbe9f0d78b54p-4L, 0x1.afcc807af3d6794ap-7248L, -0x6.40ed6a17958f5abp-7252L, -0x6.40ed6a17958f5aa8p-7252L }, + { 0x2.451ffb9b70940624p-4L, -0x1.37f52061877f3bccp-11700L, -0x3.bb5eb351baf17c7cp-11704L, -0x3.bb5eb351baf17c78p-11704L }, + { -0x4.95757561d2aaa5p-4L, -0x1.3d9fcaab7bbc9c6ep-2868L, 0x9.aae38ba996d3919p-2872L, 0x9.aae38ba996d391ap-2872L }, + { 0x1.7d04bff149a7d55cp-4L, -0xf.61c71955bf9a0dap+7880L, -0x1.f94e4939cb229d26p+7880L, -0x1.f94e4939cb229d24p+7880L }, + { -0x4.47b25b1314f91ddp-4L, 0x1.f3a3c57544812a32p-7436L, -0xe.0645285005f95b2p-7440L, -0xe.0645285005f95b1p-7440L }, + { 0x4.5b48f6c753552e7p-4L, 0x7.f9951c9fa3a3d26p-14636L, 0x2.c54b2a5dc4af4df4p-14636L, 0x2.c54b2a5dc4af4df8p-14636L }, + { -0x2.755a177a9bcd19ecp-4L, 0x2.8f368cebe2a73544p+9496L, -0x9.db16676f3eeb8b6p+9492L, -0x9.db16676f3eeb8b5p+9492L }, + { 0x4.74f58fd716847278p-8L, 0xb.5105baafec9e23fp-1216L, 0x4.8234ae72b3afbcap-1220L, 0x4.8234ae72b3afbca8p-1220L }, + { -0xf.3a54ecf20e1f38dp-8L, -0x1.cb2ddc2e80a14976p+11248L, 0x2.8a0435ff27f289fp+11244L, 0x2.8a0435ff27f289f4p+11244L }, + { 0x1.6e76573c811c0cc8p-4L, -0x6.890bc5e24bb11168p-1700L, -0xc.ed43d94a59956a1p-1704L, -0xc.ed43d94a59956ap-1704L }, + { -0x1.cc0d76d858214824p-4L, 0x4.9d780438f01ffb18p+360L, -0xc.b13775b6b72f16cp+356L, -0xc.b13775b6b72f16bp+356L }, + { 0x2.975f7098p-16416L, -0x1.7c27bae5b714e156p+9888L, -0x5.8d31808ab8fc3f1p-6528L, -0x5.8d31808ab8fc3f08p-6528L }, + { -0x2.84c6bb3c78ad39p-156L, 0x2.187b034003e64b7cp-1008L, -0x7.9d6286f490256558p-1164L, -0x7.9d6286f49025655p-1164L }, + { 0x1.3294feaed50f486cp-4L, 0x2.ed77680ef406a86cp-5816L, 0x4.e0b890b56bc98c3p-5820L, 0x4.e0b890b56bc98c38p-5820L }, + { -0x4.1adda118b2b67118p-4L, -0x1.1da0ee568b65fe28p-11272L, 0x7.a2a8b5ea7803f64p-11276L, 0x7.a2a8b5ea7803f648p-11276L }, + { 0x2.77501a3949fd1c3cp-8L, 0xa.f6abbcf12cd419p-12544L, 0x2.6d1bb5bd9453001cp-12548L, 0x2.6d1bb5bd9453002p-12548L }, + { -0x3.7d7a59482ce42cb8p-4L, 0x1.751b58122d75b98ap-11080L, -0x8.474a285e08f1966p-11084L, -0x8.474a285e08f1965p-11084L }, + { 0x1.f807f393d863f41ep-4L, 0xa.fc78b24fd33203p+1300L, 0x1.d6e2db24a50f8948p+1300L, 0x1.d6e2db24a50f894ap+1300L }, + { -0x3.40dcfa4088fed5fp-4L, -0xe.e3fdb321f26f9c4p+13020L, 0x4.e22a8f2ea6bab6a8p+13020L, 0x4.e22a8f2ea6bab6bp+13020L }, + { 0x2.2c85d17e3ac7521p-4L, -0xf.8890f12fb883eafp+1744L, -0x2.dae202adf96b494p+1744L, -0x2.dae202adf96b493cp+1744L }, + { -0xe.60ec2578a9c34f3p-8L, 0xb.6de7e775308bfap+3896L, -0xf.401f5a2820d2433p+3892L, -0xf.401f5a2820d2432p+3892L }, + { 0xa.ceb454639d49191p-8L, 0xb.214592ce214ecfep+2692L, 0xa.9f939fed0fd998cp+2688L, 0xa.9f939fed0fd998dp+2688L }, + { -0x6.d08f79b55a47424p-8L, 0x3.405b3c3e3f6864cp+6040L, -0x2.066381858f2491acp+6036L, -0x2.066381858f2491a8p+6036L }, + { 0xb.58fe4c3ae76ed36p-8L, -0x3.71ed0565cf0a82f8p-3000L, -0x3.72f5022d0c286c9cp-3004L, -0x3.72f5022d0c286c98p-3004L }, + { -0x3.7ef417dcb2ad04fp-4L, -0x1.989fd2c40d16b72ep+11400L, 0x9.15614e994d5f1eep+11396L, 0x9.15614e994d5f1efp+11396L }, + { 0x2.773887c3a113544p-4L, -0x1.317ad55b9bdb3828p+5680L, -0x3.f2a82f605122f56cp+5676L, -0x3.f2a82f605122f568p+5676L }, + { -0x2.4141773c8bf242b8p-4L, -0xc.e4018849b76a23ap-6468L, 0x2.d33684b6ec2dc264p-6468L, 0x2.d33684b6ec2dc268p-6468L }, + { 0x3.adfdb601b76362f4p-4L, -0x7.03e0d7aa253797dp+10148L, -0x2.184ee92bef09f62cp+10148L, -0x2.184ee92bef09f628p+10148L }, + { -0x1.82b638b5edf2eadp-4L, -0xd.8e0fec8304331dep-2872L, 0x1.f07932a2326e2cb6p-2872L, 0x1.f07932a2326e2cb8p-2872L }, + { 0x3.114503e53e4715p-4L, -0x3.7c55d418348e7ec8p+6688L, -0xe.1cc12794f6aa77cp+6684L, -0xe.1cc12794f6aa77bp+6684L }, + { -0x2.2c7255ce8e0f4f9p-8L, 0x9.0de4b7a3cab1a87p+11120L, -0x1.c83a5890fd2868f2p+11116L, -0x1.c83a5890fd2868fp+11116L }, + { 0x4.ab95d9c4f778dd8p-4L, -0x1.27dd0ddd53988dd4p+628L, -0x6.d512169b928744b8p+624L, -0x6.d512169b928744bp+624L }, + { -0x5.593dab1fc941b63p-8L, 0x7.cba30673cf34e1ep+5956L, -0x3.cca43ab5aa4168d8p+5952L, -0x3.cca43ab5aa4168d4p+5952L }, + { 0x5.6072ba1p-16416L, -0x6.a13f4e0f825a5edp+10340L, -0x3.36d910a4c3e979d8p-6072L, -0x3.36d910a4c3e979d4p-6072L }, + { -0x3.2fe0a04p-16416L, -0x2.37749e13337ef694p+7896L, 0xa.311a8b6de7cbd63p-8520L, 0xa.311a8b6de7cbd64p-8520L }, + { 0x1.52e65c0c28e07afcp-4L, 0x7.11d091eb6c5e7f8p+12968L, 0xc.f8f6054ce2e09fep+12964L, 0xc.f8f6054ce2e09ffp+12964L }, + { -0x1.81ecf5c638b525dcp-4L, 0x1.233a57f1cc4d9d28p+5288L, -0x2.993f1f95e2f6901cp+5284L, -0x2.993f1f95e2f69018p+5284L }, + { 0x1.9a579596fe22accep-4L, -0xe.920450e2df4f23ep+12984L, -0x2.01c6d90f6cf53254p+12984L, -0x2.01c6d90f6cf5325p+12984L }, + { -0x2.357339367c8e7d0cp-4L, 0x6.f8c63462f2be0ffp-9208L, -0x1.7e848fd237f1492ep-9208L, -0x1.7e848fd237f1492cp-9208L }, + { 0x3.b0442b4fcd5e3a68p-4L, -0x6.b2da8740f690432p-11860L, -0x2.013a89ca88d8b8b8p-11860L, -0x2.013a89ca88d8b8b4p-11860L }, + { -0x2.973c8a33f43ce22p-4L, -0x1.40c22b6af128083cp+13388L, 0x5.1be67cad86a0b2b8p+13384L, 0x5.1be67cad86a0b2cp+13384L }, + { 0xc.71fa40b14fe60a5p-8L, -0xd.227d8e4d09d7251p+10336L, -0xe.646cd1236a17ed5p+10332L, -0xe.646cd1236a17ed4p+10332L }, + { -0x2.4b5c7f957978c8dcp-4L, 0x1.d0364f8078ede932p-4432L, -0x6.7a91bf8da9e1b3a8p-4436L, -0x6.7a91bf8da9e1b3ap-4436L }, + { 0xc.9e6826befd572b6p-8L, -0x4.35ecdac82f2a93c8p-10772L, -0x4.ad35c4fc10f2895p-10776L, -0x4.ad35c4fc10f28948p-10776L }, + { -0x1.99c78eacbd3c165cp-4L, -0x2.f570aceb61240648p-8960L, 0x7.32fbbe18c44de7f8p-8964L, 0x7.32fbbe18c44de8p-8964L }, + { 0x1.7c32a28ef3632bb6p-4L, 0xf.72e6996fd117ab3p-5888L, 0x1.fa74fbd79d515e86p-5888L, 0x1.fa74fbd79d515e88p-5888L }, + { -0x6.dfefda162cd8123p-8L, -0x1.67987c998364b8acp-8240L, 0xe.1f4baaf83c19e7bp-8248L, 0xe.1f4baaf83c19e7cp-8248L }, + { 0x1.e4a51bc43235ecccp-4L, -0x1.c45d9255aa8a035ap-8692L, -0x4.8fb7ec77333b0dep-8696L, -0x4.8fb7ec77333b0dd8p-8696L }, + { -0x2.5209ac099a829dcp-4L, 0x1.fa609acc51803e54p+10424L, -0x7.277bc27d907174bp+10420L, -0x7.277bc27d907174a8p+10420L }, + { 0x2.b266769ea2ada0bcp-4L, -0x3.a66d9b79239e456p+11364L, -0xd.1fd5b30e293c2c8p+11360L, -0xd.1fd5b30e293c2c7p+11360L }, + { -0x6.bec5f7d3b060d94p-8L, 0x1.47398ae3841dd2bcp+9232L, -0xc.9b04a2f88f16892p+9224L, -0xc.9b04a2f88f16891p+9224L }, + { 0x2.563eb303d8df1594p-4L, -0x2.cda72aaa85a7383cp-3376L, -0x8.d25687622b560eap-3380L, -0x8.d25687622b560e9p-3380L }, + { -0x3.19894f7cf9935508p-4L, -0x1.6864ac7cb86fcf1ep+11056L, 0x6.ff6e7770c8294bdp+11052L, 0x6.ff6e7770c8294bd8p+11052L }, + { 0x3.1975daa32c02ffep-4L, -0x4.3e136fbe7e156658p+8164L, -0x1.1572cd89e15a791ep+8164L, -0x1.1572cd89e15a791cp+8164L }, + { -0x3.65a7c9cfb4ec9ab8p-4L, -0x2.05a5de13b7dbf81cp-4648L, 0xb.23bea1415cf66bep-4652L, 0xb.23bea1415cf66bfp-4652L }, + { 0x5.0967e18p-16416L, -0xd.64b77ebba612778p+96L, -0x6.152b53b092754e88p-16316L, -0x6.152b53b092754e8p-16316L }, + { -0xc.6c68c8a4d570e25p-200L, -0x3.c05c0d3fc5741314p+9912L, 0x4.33ccc2e9096608dp+9716L, 0x4.33ccc2e9096608d8p+9716L }, + { 0x1.d63714ff39a598ecp-4L, -0x2.ca0aeb11ccacc8dp+10576L, -0x6.ff328ab531d34ad8p+10572L, -0x6.ff328ab531d34adp+10572L }, + { -0x3.e95c9e94baaf75ap-8L, 0x2.b37daf0e4cc15f5cp-6056L, -0xf.5c57a917b87be75p-6064L, -0xf.5c57a917b87be74p-6064L }, + { 0xd.21b0e96ae054bf4p-8L, -0x4.5ad7ee78e07d371p-2356L, -0x5.074bf1af42266298p-2360L, -0x5.074bf1af4226629p-2360L }, + { -0xc.9b1515d090b1ce3p-8L, -0x4.ada9d304af8d7fbp-5952L, 0x5.73fa016de999be4p-5956L, 0x5.73fa016de999be48p-5956L }, + { 0xe.b9d75b04d351c82p-8L, -0x3.85edaba407274158p+4628L, -0x4.8c6a7d6bd001b9c8p+4624L, -0x4.8c6a7d6bd001b9cp+4624L }, + { -0xd.34f3239dcc380fcp-8L, -0xc.06ad79f94cf62e7p+5852L, 0xe.b429eec27adfe9p+5848L, 0xe.b429eec27adfe91p+5848L }, + { 0x4.0c1e5626f9899408p-4L, 0x4.405bbb3021ac0c78p-3692L, 0x1.6215cccd7becd3a4p-3692L, 0x1.6215cccd7becd3a6p-3692L }, + { -0x7.9f4ff67b7c63b818p-8L, 0xa.5aabb9f03fd61adp+14208L, -0x7.39751aa043595f8p+14204L, -0x7.39751aa043595f78p+14204L }, + { 0x1.67e82d241b189066p-4L, -0x2.e37d4d68f3529cf4p-11492L, -0x5.9d9b8b0eb10abbb8p-11496L, -0x5.9d9b8b0eb10abbbp-11496L }, + { -0x4.38ba5d3e626fd8fp-8L, -0x3.172227f2cf0b9c64p-592L, 0x1.2fa8c214228a6956p-596L, 0x1.2fa8c214228a6958p-596L }, + { 0x3.02d0858fe476bc54p-4L, 0xa.26efe8211c025fp+4600L, 0x2.86845b1a66c4dc94p+4600L, 0x2.86845b1a66c4dc98p+4600L }, + { -0x1.7ec8305cbdb5012ap-4L, 0x1.737b8c40ef13706ap-8812L, -0x3.494ee73f4ccbe1cp-8816L, -0x3.494ee73f4ccbe1bcp-8816L }, + { 0x2.685b430bceda8654p-4L, 0x2.2f04308bb4c03ba8p+1352L, 0x7.10d31a9faf05516p+1348L, 0x7.10d31a9faf055168p+1348L }, + { -0x3.e7d21df6c6451cfp-4L, 0xf.38cac992e04dd92p-8384L, -0x6.253d3816519df5p-8384L, -0x6.253d3816519df4f8p-8384L }, + { 0x1.fbff5cc9a151f10ep-4L, 0x2.9be74a9169f983ccp+3984L, 0x7.0a7fb003231082d8p+3980L, 0x7.0a7fb003231082ep+3980L }, + { -0x2.508346b6f97e4b3cp-4L, 0x2.6d5aa9ca35150438p-6664L, -0x8.c1175295f78a7e1p-6668L, -0x8.c1175295f78a7ep-6668L }, + { 0x5.549003e0bc3a306p-8L, -0x2.70cf96f2945f89ap+2768L, -0x1.29379ea6735a5004p+2764L, -0x1.29379ea6735a5002p+2764L }, + { -0x3.fa89daadb8874124p-4L, -0x2.ab88ffd377db8cfp+1852L, 0x1.19f0ebb714ef0082p+1852L, 0x1.19f0ebb714ef0084p+1852L }, + { 0x4.86128b9686d1bdcp-4L, 0x2.078508a7f9bf523cp-14396L, 0xb.a9f3e9f70793d79p-14400L, 0xb.a9f3e9f70793d7ap-14400L }, + { -0x3.e6a1389c4ee6330cp-4L, -0x1.2345feb52b46b768p+10848L, 0x7.56ee97ddf48f583p+10844L, 0x7.56ee97ddf48f5838p+10844L }, + { 0x7.7f79e448p-16416L, -0x5.89900df823ee83c8p+8056L, -0x3.be6252f3b85d24f4p-8356L, -0x3.be6252f3b85d24fp-8356L }, + { -0x1.751bf47b749ae18ep-148L, -0x3.4c815158eac0515cp-14220L, 0x6.efb696954a1d8d3p-14368L, 0x6.efb696954a1d8d38p-14368L }, + { 0x3.d69c812f0a906bd4p-8L, -0xd.06f121a87cad8ccp+3452L, -0x4.79a468a3717e3028p+3448L, -0x4.79a468a3717e302p+3448L }, + { -0x1.4bfbe1c3d5f8ce94p-4L, 0x1.9747531df7189f0cp-7364L, -0x3.1aa2ca71ed8f5fc4p-7368L, -0x3.1aa2ca71ed8f5fcp-7368L }, + { 0xa.44e50bb5c56359cp-8L, -0x2.e250f2584c59c4cp-4520L, -0x2.9e49db540232a5f8p-4524L, -0x2.9e49db540232a5f4p-4524L }, + { -0xd.01531ce3c620f03p-8L, -0x9.056ee6b1e29e3e8p+5472L, 0xa.db6218bc99e8e2bp+5468L, 0xa.db6218bc99e8e2cp+5468L }, + { 0x1.0d530c43cda37932p-4L, 0x2.8bcc9cd9155cb68cp+14312L, 0x3.be202d0192c1a7fp+14308L, 0x3.be202d0192c1a7f4p+14308L }, + { -0x3.39a32a058fcbd9bp-4L, 0xd.4669ea4a5bdd882p+724L, -0x4.4fafa80c4d44f55p+724L, -0x4.4fafa80c4d44f548p+724L }, + { 0xc.1c22b996eb6fc7dp-8L, -0x3.eaca0e062a95276p-1544L, -0x4.2dddffac0b5068ep-1548L, -0x4.2dddffac0b5068d8p-1548L }, + { -0x1.9325d2dfab3eb5d2p-4L, -0x2.710afbcd65e7036cp+4436L, 0x5.d6e783266eb95218p+4432L, 0x5.d6e783266eb9522p+4432L }, + { 0xb.c4d70eca941742ap-8L, 0x3.bac06319b31be118p-3616L, 0x3.de917500e1ea70ep-3620L, 0x3.de917500e1ea70e4p-3620L }, + { -0x9.6a871f761f0c392p-8L, -0x1.592f777d4a7269b4p+6232L, 0x1.2a99e215b4f530d2p+6228L, 0x1.2a99e215b4f530d4p+6228L }, + { 0xe.df857e03ba44519p-8L, -0xc.c83486dca7f8a6cp-1324L, -0x1.0a99133f1e6df45cp-1324L, -0x1.0a99133f1e6df45ap-1324L }, + { -0x1.ae8e54132f4d75fep-4L, -0x2.7ecb7748d3228784p+5356L, 0x6.65a46eeaf16f3928p+5352L, 0x6.65a46eeaf16f393p+5352L }, + { 0x1.82ea01a6ac3c059p-4L, 0x7.98283bcc23ee3c7p-4304L, 0xf.d2b9c546b9e8162p-4308L, 0xf.d2b9c546b9e8163p-4308L }, + { -0x4.332911eac4b16d08p-4L, -0x1.9da5f0f88e76c41cp-3164L, 0xb.5b39fa5929f2c5fp-3168L, 0xb.5b39fa5929f2c6p-3168L }, + { 0x2.a5f0f5ce82c6a948p-4L, -0x5.8738762c85c9f63p+13360L, -0x1.38b6df6f8ec4846p+13360L, -0x1.38b6df6f8ec4845ep+13360L }, + { -0x2.a250e04abfe2cep-4L, 0x1.7f89064b4d7281dcp-6208L, -0x6.387e99c0eb366d48p-6212L, -0x6.387e99c0eb366d4p-6212L }, + { 0x1.533e34fc681e0d64p-4L, -0x6.976ed0ef48c07898p-5156L, -0xc.1b684b6e1d7a6cep-5160L, -0xc.1b684b6e1d7a6cdp-5160L }, + { -0x2.976fa0885b74a0dp-4L, 0x2.6fa1664ea3a1be14p-7544L, -0x9.efb47ad4a474badp-7548L, -0x9.efb47ad4a474bacp-7548L }, + { 0x3.401f19e03339b7d8p-4L, -0x2.e1cf29eba91248ep+14388L, -0xc.4dd22e8eb32e339p+14384L, -0xc.4dd22e8eb32e338p+14384L }, + { -0x2.8bbc0949a8a731bp-4L, 0x3.5cec679bb3f69d98p-9212L, -0xd.73f5e8ad1296da5p-9216L, -0xd.73f5e8ad1296da4p-9216L }, + { 0x7.3ca5eee8p-16416L, -0x1.3bc8b60293078f84p+6520L, -0xc.e0fd8c95f925282p-9896L, -0xc.e0fd8c95f925281p-9896L }, + { -0x3.45c4ac22f9b9fe7p-96L, -0x7.9d640cca80c83b9p-3056L, 0x2.3f397b79fe0ed3dcp-3148L, 0x2.3f397b79fe0ed3ep-3148L }, + { 0x1.48922246e164c31cp-8L, 0x3.251256a4a4974324p-5772L, 0x5.cf00a20473ec53bp-5780L, 0x5.cf00a20473ec53b8p-5780L }, + { -0x2.4e456ef4b9adcafp-4L, 0xf.8fb50e1402f38bp+5532L, -0x3.7e58facfd2d1d0c8p+5532L, -0x3.7e58facfd2d1d0c4p+5532L }, + { 0x1.886dc89c16b624d6p-4L, -0x3.4fa89faae23eda44p+44L, -0x6.fe2f4a64ea4a6c78p+40L, -0x6.fe2f4a64ea4a6c7p+40L }, + { -0x4.350b55034874941p-4L, -0x1.fbcc353d750f0c24p+9096L, 0xd.f83ecea28158477p+9092L, 0xd.f83ecea28158478p+9092L }, + { 0x3.90e10fdba85c0cacp-4L, -0x5.1653c9d362cef54p-13924L, -0x1.7a077ddbf4922fa4p-13924L, -0x1.7a077ddbf4922fa2p-13924L }, + { -0x3.73d037a3672f812cp-4L, 0x3.9b5a02bfcb72b468p-1488L, -0x1.43c84f88af1422acp-1488L, -0x1.43c84f88af1422aap-1488L }, + { 0x1.2b00b6e01f6098dep-4L, -0x7.c7549ce1cd120a6p-2776L, -0xc.a6a5dc751c89f3bp-2780L, -0xc.a6a5dc751c89f3ap-2780L }, + { -0x3.df6b64cd498a6994p-12L, -0x1.c55b237b57929914p-13212L, 0x9.e62d19737b44741p-13224L, 0x9.e62d19737b44742p-13224L }, + { 0x4.32a564d20155332p-4L, 0x1.b1cb6eb8e2ebd224p-2664L, 0x9.1cf96d8b1129d15p-2668L, 0x9.1cf96d8b1129d16p-2668L }, + { -0x3.1c5ee07b5d11cdf4p-4L, 0x1.b5bf8ab3e52d12cp+4216L, -0x8.889eebe2fc21ca4p+4212L, -0x8.889eebe2fc21ca3p+4212L }, + { 0x9.abe18d86bd60c06p-8L, -0x3.d7df89d3dd52449cp+8968L, -0x3.4a2eb51714a7023p+8964L, -0x3.4a2eb51714a7022cp+8964L }, + { -0x3.c6888595ff59158cp-4L, 0x5.ed5d3988224f9748p-192L, -0x2.4d30d9000b4ddc6p-192L, -0x2.4d30d9000b4ddc5cp-192L }, + { 0x1.1d8bff2ec4862e24p-4L, 0x3.034cffddb8433518p-10028L, 0x4.afd48a2d96496ecp-10032L, 0x4.afd48a2d96496ec8p-10032L }, + { -0x2.68737aad1b771f48p-4L, -0xc.afcea80015980b8p+6532L, 0x2.fc425811997eff4cp+6532L, 0x2.fc425811997eff5p+6532L }, + { 0x3.78418dbe89bccdc8p-4L, -0x8.dc01d8b49232a17p-10828L, -0x2.8236ebb32d22f0bp-10828L, -0x2.8236ebb32d22f0acp-10828L }, + { -0x7.61b784fcc75ec3bp-8L, 0xd.233e9cefca1ae41p+14200L, -0x8.df794bc06987c0ap+14196L, -0x8.df794bc06987c09p+14196L }, + { 0x3.d59e590f10746e48p-4L, 0x1.51d6a64294ba9a2ap-10144L, 0x6.8b55a306cdce8dc8p-10148L, 0x6.8b55a306cdce8ddp-10148L }, + { -0x7.28afaf977941c1b8p-8L, 0x4.26f0dae8850886d8p+8496L, -0x2.b7ea3e87e2b0473p+8492L, -0x2.b7ea3e87e2b0472cp+8492L }, + { 0xb.1fed2d782bad9dcp-8L, 0x4.a6abc93b905e715p-4876L, 0x4.91230a64c6e7b4bp-4880L, 0x4.91230a64c6e7b4b8p-4880L }, + { -0x4.07a79631c2281c9p-8L, 0xe.f5d12aeb5942b6bp+228L, -0x5.7ab5bf59532e948p+224L, -0x5.7ab5bf59532e9478p+224L }, + { 0x1.6ee95808p-16416L, 0x5.a07bbf49b0583bbp-9900L, 0x0p+0L, 0x8p-16448L }, + { -0x3.863ad23f9793533p-48L, -0x7.1c785eecfe17605p+3708L, 0x2.428413a21a98386cp+3664L, 0x2.428413a21a98387p+3664L }, + { 0x1.e7dd2eadf3394a16p-4L, 0x3.c1009cb5b2a38294p+4932L, 0x9.c046f0b4f3b69c4p+4928L, 0x9.c046f0b4f3b69c5p+4928L }, + { -0x3.d60f5fcdb37d8eap-4L, 0x1.dc3545b0a8acecf4p+12372L, -0xb.c54051f027930e7p+12368L, -0xb.c54051f027930e6p+12368L }, + { 0x2.5d3d714a0d0272bp-4L, 0x1.e6cbc995a44d6c2cp-1388L, 0x6.0c99b457b89474e8p-1392L, 0x6.0c99b457b89474fp-1392L }, + { -0x1.278a728bb66b64dep-4L, -0xc.9cb7f96b11f2a04p-1236L, 0x1.5cd64e58107b75aep-1236L, 0x1.5cd64e58107b75bp-1236L }, + { 0x2.1df7b3b08b64e3dp-4L, 0x3.dacf3b11609eff4p-88L, 0xb.0e98a5a6b729862p-92L, 0xb.0e98a5a6b729863p-92L }, + { -0x2.c12eb8612105f50cp-4L, -0x3.d5d13ddf2d02994cp+1880L, 0x1.0ba055798a93cce6p+1880L, 0x1.0ba055798a93cce8p+1880L }, + { 0x4.42ffed1cfdb04edp-4L, 0xb.83e125a36a30824p-8028L, 0x3.ec4c0c7e99dcab2cp-8028L, 0x3.ec4c0c7e99dcab3p-8028L }, + { -0x2.bd3a518dddcd87d8p-4L, 0xa.f782f5eeaaf84b2p-976L, -0x2.f88ebb9a09ff9754p-976L, -0x2.f88ebb9a09ff975p-976L }, + { 0xa.a48014f31d21f5p-8L, 0x1.787d684fec780e28p-13432L, 0x1.61fb236d58d214e6p-13436L, 0x1.61fb236d58d214e8p-13436L }, + { -0x1.d95a03b300a7839p-4L, -0x1.402a0ef3d21d78eap+11592L, 0x3.8b94b58f3dd5ddd8p+11588L, 0x3.8b94b58f3dd5dddcp+11588L }, + { 0x3.ea3ece65229e7c1cp-4L, -0x1.02df530bdd4a2488p+5252L, -0x5.1bf7eec74ce67c5p+5248L, -0x5.1bf7eec74ce67c48p+5248L }, + { -0xa.4c31201905c5915p-8L, 0x2.4b18c689eb5ab8dp-1928L, -0x2.2c6611b3ab947174p-1932L, -0x2.2c6611b3ab94717p-1932L }, + { 0x3.e691a4a4ec98c938p-4L, -0x5.cd17b52b8b67c0d8p-10292L, -0x1.d36cada1fee74204p-10292L, -0x1.d36cada1fee74202p-10292L }, + { -0x2.3da4f3249dc52684p-4L, -0xf.34520f86c43a674p+3372L, 0x3.4f42e88d8003846p+3372L, 0x3.4f42e88d80038464p+3372L }, + { 0x3.c7cd16a9c4870a48p-8L, -0x4.8c156b51b3e8457p+10772L, -0x1.89e922297cbf68aap+10768L, -0x1.89e922297cbf68a8p+10768L }, + { -0x2.b0eebddd240923ep-4L, -0x5.29574a08fac443ep-12084L, 0x1.5f0f8e898258fbacp-12084L, 0x1.5f0f8e898258fbaep-12084L }, + { 0x2.249c8a89d03aa864p-4L, -0xd.13cf8aa40b87d27p+11728L, -0x2.5f197166ecfbca14p+11728L, -0x2.5f197166ecfbca1p+11728L }, + { -0x4.6f21e629b4f6c5e8p-4L, -0x2.f5e77b1943eaf884p+6012L, 0x1.62d8f7d63feb95f8p+6012L, 0x1.62d8f7d63feb95fap+6012L }, + { 0x4.15fd44d5e86bc01p-4L, 0x5.473ae34b6e2063cp-4768L, 0x1.bb5a721b7a439e0ap-4768L, 0x1.bb5a721b7a439e0cp-4768L }, + { -0x2.ca05f449ee9bba2p-4L, 0x6.a835c5372554956p-9312L, -0x1.d6f4ea6ae1e36da8p-9312L, -0x1.d6f4ea6ae1e36da6p-9312L }, + { 0x3.38e23638p-16416L, 0xd.b64a7582d1883d4p+7568L, 0x3.fbe211139f2c5e74p-8844L, 0x3.fbe211139f2c5e78p-8844L }, + { -0x2.c0eede3d08af0a04p-96L, -0x1.9cc6ff87f9582b36p-8292L, 0x6.67d3fa6766d44f5p-8388L, 0x6.67d3fa6766d44f58p-8388L }, + { 0x3.657fca1541630014p-4L, 0xa.5555080b30f60b8p+12212L, 0x2.deab71182cd05b2cp+12212L, 0x2.deab71182cd05b3p+12212L }, + { -0x2.15a5a3d39fca9d74p-8L, 0x4.ba3ed0a011dad9c8p+11960L, -0xe.4691fded533e7dp+11952L, -0xe.4691fded533e7cfp+11952L }, + { 0x2.820600a7b4b8b6c8p-4L, 0x1.434edd70f5ea7b82p-7912L, 0x4.3eacdda95f716048p-7916L, 0x4.3eacdda95f71605p-7916L }, + { -0x4.76729a8ab5f9d168p-4L, -0x3.f2ca785573e18f44p-6872L, 0x1.dcdaf54fb1102d4cp-6872L, 0x1.dcdaf54fb1102d4ep-6872L }, + { 0x1.b28350368d79329p-4L, -0x5.bd5227673487f808p+13568L, -0xd.5b9b9a020b995c7p+13564L, -0xd.5b9b9a020b995c6p+13564L }, + { -0x4.422aeed297423dfp-4L, 0xd.6dbe42d94446092p-5372L, -0x5.fec8d99f836824e8p-5372L, -0x5.fec8d99f836824ep-5372L }, + { 0x2.b4c82511d6b8adbp-4L, -0x2.58c6fae544166138p-10216L, -0x8.770e6e77fa12c41p-10220L, -0x8.770e6e77fa12c4p-10220L }, + { -0x3.603dab982401c2fp-4L, 0xd.c28e13e36928e3ap-12400L, -0x4.b458ff98a77bea88p-12400L, -0x4.b458ff98a77bea8p-12400L }, + { 0x2.52993b67468165dp-4L, 0xe.abf2bcc7641993cp+4800L, 0x2.de7fd921b9b3f348p+4800L, 0x2.de7fd921b9b3f34cp+4800L }, + { -0x2.ffc62e45c4920ca8p-4L, -0x9.e0554ee54c3f10cp+2864L, 0x2.f5240374ef1e8fa4p+2864L, 0x2.f5240374ef1e8fa8p+2864L }, + { 0x1.d76afc41248078d8p-4L, 0x1.96be670b6795cd66p+4484L, 0x3.fecd39da987d611p+4480L, 0x3.fecd39da987d6114p+4480L }, + { -0x1.1fe55dbba061231cp-4L, -0x2.3f0e956a9cc93b7cp-2808L, 0x3.c768e818370d0554p-2812L, 0x3.c768e818370d0558p-2812L }, + { 0x4.7ffbbb9da4656abp-4L, 0x1.883501d399ebe686p-2052L, 0x8.c3b8d2ed744ac29p-2056L, 0x8.c3b8d2ed744ac2ap-2056L }, + { -0x2.e7771c3617428004p-4L, 0x4.aa305910d4a5b948p-14036L, -0x1.5913b10b6f6bb312p-14036L, -0x1.5913b10b6f6bb31p-14036L }, + { 0x1.f51f691570542864p-4L, -0x7.ff805590540d7e68p-8240L, -0x1.54f0cc2a744adbep-8240L, -0x1.54f0cc2a744adbdep-8240L }, + { -0x2.bc9523828d7c744p-4L, -0x5.f8c2890bff7a53a8p-4408L, 0x1.9db92d87363ce3a4p-4408L, 0x1.9db92d87363ce3a6p-4408L }, + { 0xb.cface8db66432b4p-8L, -0x1.52f8d17d3ef509ep-14136L, -0x1.60ecc5e5445bc5fap-14140L, -0x1.60ecc5e5445bc5f8p-14140L }, + { -0x3.c4fcb83a4348059p-4L, -0x6.92589a2ad057f888p+14032L, 0x2.8c0de6f4f4ad5a8p+14032L, 0x2.8c0de6f4f4ad5a84p+14032L }, + { 0xd.3e73c6c392e1b2cp-16L, -0x1.9d39baf7c3757386p-7232L, -0x1.ed6b25bf930609f2p-7244L, -0x1.ed6b25bf930609fp-7244L }, + { -0x1.2be18a59c6c0cb46p-4L, -0x5.2f34ad391bf16bep+14208L, 0x9.194f55dcdc049ddp+14204L, 0x9.194f55dcdc049dep+14204L }, + { 0x1.6ea2622p-16416L, 0xd.0a61c31aa71a8b4p+192L, 0x1.af1b0b9011702c9cp-16220L, 0x1.af1b0b9011702c9ep-16220L }, + { -0xe.24746d350747p-76L, -0x6.2cd68ac90fd809cp-20L, 0x7.dfe1c92e972b245p-92L, 0x7.dfe1c92e972b2458p-92L }, + { 0x3.172ad4e89020bdc4p-4L, -0x7.5d68336e21e50738p-10576L, -0x1.e05e86f2c4aaa87p-10576L, -0x1.e05e86f2c4aaa86ep-10576L }, + { -0x1.1cc46bd3cc5d5eep-4L, 0x8.dfe337c5f8f4ed8p-2964L, -0xe.c2e4fcc9056e939p-2968L, -0xe.c2e4fcc9056e938p-2968L }, + { 0x1.6aec81e28b750398p-4L, 0x6.d60397f1aab8875p+5068L, 0xd.65769829a5eb6bbp+5064L, 0xd.65769829a5eb6bcp+5064L }, + { -0xa.dd9db54ce301e4fp-8L, 0x2.994e7862cafbb18p-9172L, -0x2.9a10f7c79bc8a514p-9176L, -0x2.9a10f7c79bc8a51p-9176L }, + { 0x3.4c1067ae36f3df8p-4L, 0x5.e39292b71e3bd29p-14656L, 0x1.97849d850815a968p-14656L, 0x1.97849d850815a96ap-14656L }, + { -0x3.2716db715997395cp-4L, -0x3.7b95a736d2a03acp-2972L, 0x1.1a47ea03f6df2b3p-2972L, 0x1.1a47ea03f6df2b32p-2972L }, + { 0x3.511564feccb7ade4p-4L, 0xa.3be5fc2351c749fp+8708L, 0x2.c808aa921e98c90cp+8708L, 0x2.c808aa921e98c91p+8708L }, + { -0x3.69c632e288b42e7cp-4L, 0x2.6cfab89ec92c9a94p+12520L, -0xd.6f501c63d843bbp+12516L, -0xd.6f501c63d843bafp+12516L }, + { 0xd.50c03549bb8a308p-8L, -0xd.bb307fe5c0a193dp+11920L, -0x1.0125a0d31814385ap+11920L, -0x1.0125a0d318143858p+11920L }, + { -0x4.62f76781cd43fa1p-4L, 0x6.add388611cf3e0dp-5568L, -0x3.166b1e48e4d0d538p-5568L, -0x3.166b1e48e4d0d534p-5568L }, + { 0x2.af134161b98b158cp-4L, -0x6.b78672290432052p+4200L, -0x1.80b269a8acd58f28p+4200L, -0x1.80b269a8acd58f26p+4200L }, + { -0x4.07400317e3bbdf6p-4L, 0x4.6f0a1bd0504232fp-4560L, -0x1.daf3ffdcfaf5a3fcp-4560L, -0x1.daf3ffdcfaf5a3fap-4560L }, + { 0x3.e2c42f99082b0694p-8L, -0x2.23235efc5d063d1cp+484L, -0xb.e43a884083a14cdp+476L, -0xb.e43a884083a14ccp+476L }, + { -0x2.510f0edafa423e34p-4L, 0x8.ea166668cb9c597p-728L, -0x2.02f35e07c5b586ep-728L, -0x2.02f35e07c5b586dcp-728L }, + { 0x2.87d8f5995c149e84p-4L, -0x1.fd41fdd489dd6b86p-4740L, -0x6.be1d42ef4ae7d568p-4744L, -0x6.be1d42ef4ae7d56p-4744L }, + { -0x4.91cd3914269e7f4p-4L, -0x7.5908781b4662a448p+4676L, 0x3.90a7abc41bfff254p+4676L, 0x3.90a7abc41bfff258p+4676L }, + { 0x1.a5cddc11ef6ac702p-4L, -0x5.101df29586f07ac8p+14844L, -0xb.7475b0a9b9616e6p+14840L, -0xb.7475b0a9b9616e5p+14840L }, + { -0x2.59a788d1463d5708p-4L, 0x5.93f40353ef748448p-6680L, -0x1.4747090652a60d3p-6680L, -0x1.4747090652a60d2ep-6680L }, + { 0x2.70458f50e301850cp-4L, -0x2.bbcb14f8c8df1858p+4120L, -0x8.f3733a06672424fp+4116L, -0x8.f3733a06672424ep+4116L }, + { -0x1.edb5a0fdb59e0032p-4L, 0x1.8d559c866804202p-7668L, -0x4.9a064be7a218d8bp-7672L, -0x4.9a064be7a218d8a8p-7672L }, + { 0x5.5e55df7p-16416L, 0x1.d91cda789c52cbdp+4364L, 0xe.504ec49dde8ab29p-12052L, 0xe.504ec49dde8ab2ap-12052L }, + { -0x2.3345c79170f14c5p-180L, -0xb.f1c6659cf21c7f9p-4736L, 0x2.5ea6960e05da9f88p-4912L, 0x2.5ea6960e05da9f8cp-4912L }, + { 0x3.0afb26c30345b6c8p-4L, 0x2.302e0468775a2cfp+3692L, 0x8.cb4da2d9809cb86p+3688L, 0x8.cb4da2d9809cb87p+3688L }, + { -0x3.1a5317d464e8bcd8p-4L, -0xf.5f00a957d87468bp-352L, 0x4.c7dab607b60b8738p-352L, 0x4.c7dab607b60b874p-352L }, + { 0x2.f8e069607dea9234p-4L, -0x3.684738cd5ffb438p-4096L, -0xd.66adc86b056b9e4p-4100L, -0xd.66adc86b056b9e3p-4100L }, + { -0x1.68f2cde5ae072e6ep-4L, 0xb.6bb5e3b9506b364p+1724L, -0x1.851c08718da5d4e4p+1724L, -0x1.851c08718da5d4e2p+1724L }, + { 0x2.23ce11d6341a8aacp-4L, 0x1.455660f0dbaacbacp-9204L, 0x3.aea780e4a73a96e4p-9208L, 0x3.aea780e4a73a96e8p-9208L }, + { -0x2.135127bb12ede30cp-4L, 0xa.d8293b85a4bffcfp+12080L, -0x2.2c758719e47f09d8p+12080L, -0x2.2c758719e47f09d4p+12080L }, + { 0x1.33cb1ea0c84f5a1ap-4L, 0xa.2e25e1b057a53d2p-9672L, 0x1.106c68c29be5ecd4p-9672L, 0x1.106c68c29be5ecd6p-9672L }, + { -0x1.fa3c2eb2e9308f1cp-4L, -0xd.079788536be471ap+5984L, 0x2.7ad9dd04bd787d68p+5984L, 0x2.7ad9dd04bd787d6cp+5984L }, + { 0x3.5875e63760a4466p-4L, -0x1.e565eb8bd950bb6cp-6104L, -0x8.4f709e7bba8e058p-6108L, -0x8.4f709e7bba8e057p-6108L }, + { -0x1.3f197fa4514cf7c2p-4L, 0x7.dc189a6904687248p-3956L, -0xe.b70fcbf84500736p-3960L, -0xe.b70fcbf84500735p-3960L }, + { 0x2.98ff74bb0396e2a8p-4L, -0x6.cc6bb049840d2788p+3184L, -0x1.79c15ad6f10263bcp+3184L, -0x1.79c15ad6f10263bap+3184L }, + { -0x1.e92034fc00fd7a98p-4L, -0x3.e5597d53f64ac974p-2504L, 0xb.6faf807e0f4e0a3p-2508L, 0xb.6faf807e0f4e0a4p-2508L }, + { 0x4.24c32dc8985a08d8p-4L, 0xd.eaf2679d518cbcap-5988L, 0x4.9fc9e3020022b7cp-5988L, 0x4.9fc9e3020022b7c8p-5988L }, + { -0x2.a33049d338912ac4p-4L, -0x1.f3b94e68042c5dc8p-11892L, 0x8.1dde7a4bbda2816p-11896L, 0x8.1dde7a4bbda2817p-11896L }, + { 0x2.ba130b3c4d1f4e8p-4L, 0x6.0af61fcd08d308f8p-15004L, 0x1.5f378240ba9a69fep-15004L, 0x1.5f378240ba9a6ap-15004L }, + { -0xb.1ce64865e029d5fp-8L, 0x1.ff55919d9667cf4cp+13108L, -0x2.0bd3af3af36c6e6cp+13104L, -0x2.0bd3af3af36c6e68p+13104L }, + { 0xe.294e92a7a26e0f2p-12L, 0x1.0329cf12c0f4735cp-9924L, 0x1.4a5b55d460c69b9ep-9932L, 0x1.4a5b55d460c69bap-9932L }, + { -0xf.2e554c655733393p-8L, -0x1.63b6624e7048c69p-13664L, 0x1.f5f341a9df85c5ep-13668L, 0x1.f5f341a9df85c5e2p-13668L }, + { 0x4.19c6d69c8374d198p-8L, 0x3.3c77b09aeb197434p-5576L, 0x1.2fe6936fb94fa2a6p-5580L, 0x1.2fe6936fb94fa2a8p-5580L }, + { -0x6.0496537484fa208p-8L, -0x6.c8226dd9ecd375ap-9856L, 0x3.b95264ba207a26p-9860L, 0x3.b95264ba207a2604p-9860L }, + { 0x3.6687889ff8995454p-36L, -0xa.ea939bccf0c7a07p+1528L, -0x3.58de478a3f4ba21p+1496L, -0x3.58de478a3f4ba20cp+1496L }, + { -0x2.7f156648p-16416L, -0x4.f40ef5608acb05ep-1128L, 0x0p+0L, 0x8p-16448L }, + { 0x4.8500f80b4fa4a34p-4L, -0x7.3625bf44a443e3f8p+5176L, -0x2.96a1ca8ead93767p+5176L, -0x2.96a1ca8ead93766cp+5176L }, + { -0x3.1e76ef016909914cp-4L, 0x7.115b116b66f8aa4p-12752L, -0x2.36042efa2987b7a8p-12752L, -0x2.36042efa2987b7a4p-12752L }, + { 0x1.145e8982b98005cp-4L, -0x5.d05179f09dc2d33p-13872L, -0x8.c32eaca7f2e537ap-13876L, -0x8.c32eaca7f2e5379p-13876L }, + { -0x6.48d061b769787a38p-8L, -0x1.22c95177a19486ep-7144L, 0xa.6d51af264791aebp-7152L, 0xa.6d51af264791aecp-7152L }, + { 0x1.3733136f320f9f84p-4L, -0x1.8a40d2261f03957ep+4176L, -0x2.9a6c6aca7935b768p+4172L, -0x2.9a6c6aca7935b764p+4172L }, + { -0x1.358688a586adbbf8p-4L, -0x6.56cb6fd63dca8b9p+9600L, 0xb.7f5f931dd5eb2eep+9596L, 0xb.7f5f931dd5eb2efp+9596L }, + { 0x5.449fa70eef370f58p-8L, -0x1.a1b184553cda78ap+7432L, -0xc.465569d2c326a9ep+7424L, -0xc.465569d2c326a9dp+7424L }, + { -0x2.92231a70c5780dap-4L, 0xa.2782912323620c5p-4824L, -0x2.90e7e4c7728e0584p-4824L, -0x2.90e7e4c7728e058p-4824L }, + { 0x2.b59d7e039fdf9904p-4L, -0x2.459d427616b15588p+4412L, -0x8.344523d1b10cf33p+4408L, -0x8.344523d1b10cf32p+4408L }, + { -0xc.2393bad0835b34cp-8L, -0x7.ee687fee5c4ec2b8p+3820L, 0x8.e4ce378035800c9p+3816L, 0x8.e4ce378035800cap+3816L }, + { 0x3.cb172495f4e11098p-4L, -0x1.867b118a15199e4ep-6280L, -0x7.7dad976d917e1cd8p-6284L, -0x7.7dad976d917e1cdp-6284L }, + { -0x4.4abd064ca0fe822p-4L, -0x5.919372e384ec19cp-4452L, 0x2.8252a05d4039be14p-4452L, 0x2.8252a05d4039be18p-4452L }, + { 0x4.3035264bc9659e2p-4L, -0x9.90137db5d8438f6p+5028L, -0x3.3533f8369942f288p+5028L, -0x3.3533f8369942f284p+5028L }, + { -0x2.a02f7f8f2a33579p-4L, -0x1.74dc31e3b9305bc4p+8180L, 0x6.06d01869bfc02898p+8176L, 0x6.06d01869bfc028ap+8176L }, + { 0x2.0f8e4cbcc27850d8p-4L, -0x2.fa91e626f345fb28p-14588L, -0x8.549922eac21ecdp-14592L, -0x8.549922eac21eccfp-14592L }, + { -0x2.1fc557b50c931d24p-4L, -0xf.a038fe23264b69fp+14704L, 0x3.360291be1344afe4p+14704L, 0x3.360291be1344afe8p+14704L }, + { 0x1.b69ca8d925216fc6p-4L, 0x1.d578671f39a6b79p+4996L, 0x4.4e6ab61dbdffe2b8p+4992L, 0x4.4e6ab61dbdffe2cp+4992L }, + { -0x4.8660d1e7a3a18068p-4L, 0xc.9a201e4897d0226p+7292L, -0x6.0b24b9cb8f96233p+7292L, -0x6.0b24b9cb8f962328p+7292L }, + { 0x2.804eb8772ea477cp-4L, -0xd.c98d7189a0303bfp-9228L, -0x2.e39b75a1ab637314p-9228L, -0x2.e39b75a1ab63731p-9228L }, + { -0x5.f071a27eaa54e38p-8L, 0x1.775823e9c3c2806cp+3976L, -0xc.b60896a0bc1c55ep+3968L, -0xc.b60896a0bc1c55dp+3968L }, + { 0x1.7d19bf9b2f768d26p-136L, -0x2.d94140f31f8c61bp-1620L, -0x6.1e39086add179f3p-1756L, -0x6.1e39086add179f28p-1756L }, + { -0x7.e376b0bp-16416L, 0x1.3247488c5d03274ep+8560L, -0xd.9dad2138f46abb9p-7856L, -0xd.9dad2138f46abb8p-7856L }, + { 0x1.6343494b7816dd6p-4L, 0x1.24f1b7414cd3e44p+8680L, 0x2.3272b4a13c6b0828p+8676L, 0x2.3272b4a13c6b082cp+8676L }, + { -0x1.c03717a7400b18dep-4L, -0x2.32aa0ac2a73accfcp+12680L, 0x5.e131f8511a6780ap+12676L, 0x5.e131f8511a6780a8p+12676L }, + { 0x3.9639abe76c1e22b4p-4L, -0x1.aad25e3bbb5c92c2p-716L, -0x7.c8d239822cb8acep-720L, -0x7.c8d239822cb8acd8p-720L }, + { -0x1.6f8de0a23eb23f08p-4L, -0x2.a959c77ea7aa43ecp+988L, 0x5.c6b591b2a7e072ep+984L, 0x5.c6b591b2a7e072e8p+984L }, + { 0x3.0493f6bd3e7a9d08p-4L, 0x2.3b45ef80edb12e4p-7692L, 0x8.e68e11e3908f565p-7696L, 0x8.e68e11e3908f566p-7696L }, + { -0x3.4ebaefe2e6c2ffd4p-4L, -0xe.87ffc2cdbdd0a59p-888L, 0x4.dada35190941404p-888L, 0x4.dada351909414048p-888L }, + { 0x3.c04aa41676d3a1dcp-4L, 0x5.c671189eaee79d8p-3112L, 0x1.c13ec20855e228fap-3112L, 0x1.c13ec20855e228fcp-3112L }, + { -0xd.84c80ecec0dfc24p-8L, -0xa.41831a7d42bf933p+524L, 0xc.d7fd375ea441b22p+520L, 0xc.d7fd375ea441b23p+520L }, + { 0x3.9b18f252e9cc6204p-4L, -0xc.541234ac6a41dbfp+2520L, -0x3.9d66104d07c6c03cp+2520L, -0x3.9d66104d07c6c038p+2520L }, + { -0x9.01dc33c60cb85cfp-8L, 0x7.ff05934f4c4c383p-13868L, -0x6.9c7c08044a14d7b8p-13872L, -0x6.9c7c08044a14d7bp-13872L }, + { 0x2.c31e22698d11a4ecp-4L, -0x1.8a1311226a2cf3dp+14616L, -0x5.a8a6f3b45150fea8p+14612L, -0x5.a8a6f3b45150feap+14612L }, + { -0x3.c76e6f9502a10174p-4L, -0xd.cd06a7b980fe0dp-4668L, 0x5.5d5541ea4ee0ea48p-4668L, 0x5.5d5541ea4ee0ea5p-4668L }, + { 0x8.77c988605043e5bp-8L, 0x1.6982403523b43efap-8420L, 0x1.0f8f240be8bbfaa6p-8424L, 0x1.0f8f240be8bbfaa8p-8424L }, + { -0x2.574faa96bdd3213p-4L, 0xc.503b4e17876b4f8p-696L, -0x2.cf6c154995d02d98p-696L, -0x2.cf6c154995d02d94p-696L }, + { 0x4.0e6b69653c7259cp-4L, 0xf.ea4c84120426686p-4116L, 0x5.30298b34abe7e7cp-4116L, 0x5.30298b34abe7e7c8p-4116L }, + { -0x2.6a84e1dc3ed5b358p-4L, 0x6.681d1a92ea56e508p-8188L, -0x1.8359cb0bb17a3c26p-8188L, -0x1.8359cb0bb17a3c24p-8188L }, + { 0x2.43c341781144525p-4L, 0x1.2c0b226e839776bap-1564L, 0x3.94dda02c158a4d1p-1568L, 0x3.94dda02c158a4d14p-1568L }, + { -0x3.5ce4a1fe88889f1cp-4L, -0x5.d49892159ff7aeb8p-5000L, 0x1.fc1549257f8001eap-5000L, 0x1.fc1549257f8001ecp-5000L }, + { 0x9.d9c0516a61c2fd1p-8L, 0x5.d5a66b8dfa047b5p+6780L, 0x5.15ca590d0fb17b28p+6776L, 0x5.15ca590d0fb17b3p+6776L }, + { -0x7.ce5459cf45b18448p-8L, -0x1.37c211415835776cp+3656L, 0xd.ed8c6d47ece27fcp+3648L, 0xd.ed8c6d47ece27fdp+3648L }, + { 0x3.6aa98df8p-16416L, 0x3.3644cdf8f7e5e378p-5876L, 0x0p+0L, 0x8p-16448L }, + { -0x4.95ee308p-16420L, 0x7.44556257ec455fb8p-8352L, -0x8p-16448L, -0x0p+0L }, + { 0x1.f6845a417bd06bd4p-4L, 0x2.8d6b4f3f8a5ae1d8p-4092L, 0x6.d171ba168e7c00c8p-4096L, 0x6.d171ba168e7c00dp-4096L }, + { -0x3.362ee1134557b0c8p-4L, -0x6.44d1e706f42b9218p-14364L, 0x2.06becf0cbf15a76cp-14364L, 0x2.06becf0cbf15a77p-14364L }, + { 0x1.29ad0ab6b39c71e8p-4L, 0x8.3abf84f84659fbfp+6884L, 0xd.53ad29e0460e74bp+6880L, 0xd.53ad29e0460e74cp+6880L }, + { -0x2.7323c21f31ee0c94p-4L, 0x1.ac8d253b449af046p-12608L, -0x6.6bf33ea54480fb38p-12612L, -0x6.6bf33ea54480fb3p-12612L }, + { 0x3.d0edb25b17c3c3c8p-4L, -0x1.e23087ac1fc0803ep-1112L, -0x9.4ce21b7a005ec4p-1116L, -0x9.4ce21b7a005ec3fp-1116L }, + { -0x1.defb373d645dd7fcp-4L, 0x2.b1b352e26c101b48p+196L, -0x7.bbe0c9d1fb10f57p+192L, -0x7.bbe0c9d1fb10f568p+192L }, + { 0x3.db8c171e647ac154p-4L, 0x3.bd7064bc96439e88p-8072L, 0x1.2a5b636788b866a6p-8072L, 0x1.2a5b636788b866a8p-8072L }, + { -0x2.157c312f0a7331dcp-4L, 0x1.d519eadd05d80046p+3776L, -0x5.e7076a49325e2b2p+3772L, -0x5.e7076a49325e2b18p+3772L }, + { 0x6.13dd8fa1bb5a0888p-8L, 0xd.e1d14a94f3f3513p-14348L, 0x7.84c2d6dc58e0033p-14352L, 0x7.84c2d6dc58e00338p-14352L }, + { -0xc.a7a4a0836807865p-8L, 0xa.6cd4c82b6c3ad8fp-14052L, -0xc.332a5ac869f5485p-14056L, -0xc.332a5ac869f5484p-14056L }, + { 0x3.e4981e366529f448p-4L, -0x1.c855bc869ec45c56p-2360L, -0x8.f5fa49da4d36b7cp-2364L, -0x8.f5fa49da4d36b7bp-2364L }, + { -0x1.3df73a344e1df3cep-4L, -0x8.b6f7624f6d4b8fap+4364L, 0x1.0415fd3b8843c92ap+4364L, 0x1.0415fd3b8843c92cp+4364L }, + { 0xf.71e1693aabd6949p-8L, -0x9.67429de92a0cc45p+13180L, -0xc.b7344f5f174184ap+13176L, -0xc.b7344f5f1741849p+13176L }, + { -0x2.e92c6340870d1904p-4L, 0x6.3a68ed7dc2ab1b18p+1772L, -0x1.cde5ffd73bb78894p+1772L, -0x1.cde5ffd73bb78892p+1772L }, + { 0x1.6638437083b5e5cep-4L, -0xa.51a3936a6af3cc4p-9740L, -0x1.3f86597d7dfbb25ap-9740L, -0x1.3f86597d7dfbb258p-9740L }, + { -0x5.e85b2872af8b8768p-8L, -0x1.05a0268fc1493582p-6052L, 0x8.cff240ac67268dbp-6060L, 0x8.cff240ac67268dcp-6060L }, + { 0x2.dfdc0c89ab932644p-4L, -0x1.a6d9620079c35e76p-14696L, -0x6.4caa08299af24148p-14700L, -0x6.4caa08299af2414p-14700L }, + { -0x4.15f357d7796b39f8p-4L, -0xd.0f27ddc214b3d5fp+2272L, 0x5.8e1f34fcf9c6555p+2272L, 0x5.8e1f34fcf9c65558p+2272L }, + { 0x3.0e9f50108a3ff43cp-4L, -0x6.c4cc122615b61d18p+7552L, -0x1.b51cb1eca74aff38p+7552L, -0x1.b51cb1eca74aff36p+7552L }, + { -0x4.4a7f16c7046c96c8p-4L, -0x2.981ff7909e578104p-14228L, 0x1.2b286a2c567ea818p-14228L, 0x1.2b286a2c567ea81ap-14228L }, + { 0x5.ef34f4p-16420L, -0x1.214299eebb91926ap+7320L, -0x9.ac829743b8c0f05p-9100L, -0x9.ac829743b8c0f04p-9100L }, + { -0x1.691f3828p-16416L, 0x1.efebf2a3b96734aep+3408L, -0x3.f141a8e9339c907cp-13008L, -0x3.f141a8e9339c9078p-13008L }, + { 0x1.4e8c937c8e553dcp-4L, -0x1.3035f2318b0be00ep-6620L, -0x2.27538394a1b35e5cp-6624L, -0x2.27538394a1b35e58p-6624L }, + { -0x7.5976854fcf9031fp-8L, -0x6.11bab7a888287f3p-312L, 0x4.14b5a5ddbd843bdp-316L, 0x4.14b5a5ddbd843bd8p-316L }, + { 0x1.705c9e77f96a731cp-4L, 0x3.d432ed3f654d8a28p-2564L, 0x7.9c73705bb807b3p-2568L, 0x7.9c73705bb807b308p-2568L }, + { -0x4.9a5360d861aaa4e8p-4L, 0x1.1531b287e936aff2p-6580L, -0x8.7a86ebb8c48bafp-6584L, -0x8.7a86ebb8c48baefp-6584L }, + { 0x3.aed6e32454d1f618p-4L, 0x1.296010316396f574p-10016L, 0x5.8e0d53264bbb5658p-10020L, 0x5.8e0d53264bbb566p-10020L }, + { -0x6.40fd50816f8157b8p-8L, 0x6.4b02ec16879cadc8p-3652L, -0x3.97bb59c7052cc938p-3656L, -0x3.97bb59c7052cc934p-3656L }, + { 0x2.2873a4ee7791f16cp-4L, -0x1.5e183567b5058b64p-6240L, -0x3.fe783fc7ec0a3e54p-6244L, -0x3.fe783fc7ec0a3e5p-6244L }, + { -0x4.91ca4444446e025p-4L, 0x1.8871ecc06666a8b8p+6540L, -0xb.e684deb0c4ea1a1p+6536L, -0xb.e684deb0c4ea1ap+6536L }, + { 0x5.f63f2f14fa25c78p-8L, 0x7.f61f9817342409ap+6848L, 0x4.3b14e17bad193658p+6844L, 0x4.3b14e17bad19366p+6844L }, + { -0x3.73b374e9d6f1b14cp-4L, 0x1.a766304af3ed99eap-11340L, -0x9.472a21f120494b4p-11344L, -0x9.472a21f120494b3p-11344L }, + { 0x3.8a6aa9bc55f2078p-8L, -0x6.2c58a861a1cf29a8p+5396L, -0x1.f514ecea291b833ep+5392L, -0x1.f514ecea291b833cp+5392L }, + { -0xd.f5a19cfa9847764p-8L, -0x1.9ead8227db0f911cp-9848L, 0x2.18ba56217d205048p-9852L, 0x2.18ba56217d20504cp-9852L }, + { 0x1.03b2429f433bd84p-4L, 0x7.6174df81f989a0fp-5988L, 0xa.7924c7723ddc533p-5992L, 0xa.7924c7723ddc534p-5992L }, + { -0x1.1908bf815764d01ep-4L, 0x6.b0ac0d83a33409dp+4848L, -0xa.fa080088ed7f3f8p+4844L, -0xa.fa080088ed7f3f7p+4844L }, + { 0x4.187fb9c09c55f5ep-4L, -0x2.670dd27ee7f45a3cp-10212L, -0xc.a3d27b26df9ae5ep-10216L, -0xc.a3d27b26df9ae5dp-10216L }, + { -0x4.aded544e99e15d3p-4L, -0x1.fb63b223d8b85776p-12512L, 0xf.d3fc75e67e5697dp-12516L, 0xf.d3fc75e67e5697ep-12516L }, + { 0x9.f5a904e0a16b75p-12L, 0x6.b6db5486fa8da28p-4968L, 0x6.05bb9a21b9c5695p-4976L, 0x6.05bb9a21b9c56958p-4976L }, + { -0x3.7ea985070d82c5dcp-4L, 0x7.8ed5f1582d74d94p+13856L, -0x2.afe9bbfb32eedff4p+13856L, -0x2.afe9bbfb32eedffp+13856L }, + { 0x8.ceca186af1571abp-8L, -0x4.aa7a2e0b9a249038p+5868L, -0x3.a4aded1bd7f30504p+5864L, -0x3.a4aded1bd7f305p+5864L }, + { -0x8.fd7657912a84383p-8L, -0x1.1c18c670ecb47d26p-8016L, 0xe.a6fa205a23754cep-8024L, 0xe.a6fa205a23754cfp-8024L }, + { 0x1.2af0c6bp-16416L, 0x2.e55845c69ebf1658p+3336L, 0x4.e0ef355e6d13fa58p-13080L, 0x4.e0ef355e6d13fa6p-13080L }, + { -0x1.9a9d144p-16416L, -0x1.2b2e1b630ba1b3b6p+2664L, 0x2.b44f5c0dc1564e68p-13752L, 0x2.b44f5c0dc1564e6cp-13752L }, + { 0x2.3f11da078aa8a478p-4L, -0xb.2315f89420146ccp+8064L, -0x2.1c631386d9d9fc94p+8064L, -0x2.1c631386d9d9fc9p+8064L }, + { -0x3.019d6e7999c6dddcp-4L, 0x1.3f86f58ae2fdd6dcp-7640L, -0x5.ff0fffae46c8157p-7644L, -0x5.ff0fffae46c81568p-7644L }, + { 0xb.4e40f5e1d904b61p-8L, 0x6.532f0bc4c2ab27fp-13652L, 0x6.4f362dc573683e08p-13656L, 0x6.4f362dc573683e1p-13656L }, + { -0x2.80eab5330cc1f32cp-4L, -0x3.005426a19639d6bp+14296L, 0xb.c9efe6146589be6p+14292L, 0xb.c9efe6146589be7p+14292L }, + { 0x2.12c9e15ad0b4a958p-4L, 0x1.504150487ac4b4e4p-13364L, 0x3.b1cb463da2f231cp-13368L, 0x3.b1cb463da2f231c4p-13368L }, + { -0xc.1c5be79cff6476p-8L, 0xc.0c6b1b1a302ca68p+14360L, -0xd.7a7df9fc3108fap+14356L, -0xd.7a7df9fc3108f9fp+14356L }, + { 0x3.1bac1512e32d6aa8p-4L, -0xf.6312e170067d25bp-3972L, -0x3.f0d8177d9054014cp-3972L, -0x3.f0d8177d90540148p-3972L }, + { -0x1.519f2ae231695ea2p-4L, 0x5.5400fe4d2a5ab7f8p-8900L, -0xa.947c24f62e74fcdp-8904L, -0xa.947c24f62e74fccp-8904L }, + { 0x2.a65946c7f23f31acp-4L, 0x4.7a751384d759865p+8672L, 0xf.d77ddbba6b11fd9p+8668L, 0xf.d77ddbba6b11fdap+8668L }, + { -0x2.cd037a11f9213844p-4L, -0xd.6910092b63029a8p-1592L, 0x3.b91ac58ce049a54p-1592L, 0x3.b91ac58ce049a544p-1592L }, + { 0x3.9db1e0144ed66a8cp-8L, 0x1.d28289f977ace56p-32L, 0x9.70a6bb89b1c4544p-40L, 0x9.70a6bb89b1c4545p-40L }, + { -0x2.621a3f5edf1bfa3cp-4L, -0x3.5c6f2312eb314f6p-8832L, 0xc.835eabfeaf37f45p-8836L, 0xc.835eabfeaf37f46p-8836L }, + { 0x3.8c641d8c7144c56cp-4L, -0xd.9ccf64003bcfe19p-2164L, -0x3.ef094c1261084a5cp-2164L, -0x3.ef094c1261084a58p-2164L }, + { -0x4.a18f061049fc9cbp-4L, 0x1.e06defabb32ffe1ep+1648L, -0xe.cd74e842dc9ff13p+1644L, -0xe.cd74e842dc9ff12p+1644L }, + { 0x4.97f2306d8c28e9dp-4L, -0x1.2a39e2ab6ffe536p-536L, -0x6.c970e37e84181a4p-540L, -0x6.c970e37e84181a38p-540L }, + { -0x2.e236a258e6dd6b5cp-4L, 0x3.2f025f0ea7bb3938p+7324L, -0xe.9aad918f2225785p+7320L, -0xe.9aad918f2225784p+7320L }, + { 0x3.1c35592c972c292cp-4L, -0x3.d19015724427ff7p+5180L, -0xf.a85299ffafa135ep+5176L, -0xf.a85299ffafa135dp+5176L }, + { -0x4.2943e5b07a55b8cp-4L, -0xa.9469f6ae3a4e6f4p+1964L, 0x4.98efa780ae2c64e8p+1964L, 0x4.98efa780ae2c64fp+1964L }, + { 0xe.c4a37f159ae949ep-8L, 0x1.c776d3c51e49998ap-4852L, 0x2.4da7c80b031f717cp-4856L, 0x2.4da7c80b031f718p-4856L }, + { -0x8.b6721f00e89d647p-8L, -0x3.76d26cae7f3a370cp-10612L, 0x2.c4d3a29814e11f84p-10616L, 0x2.c4d3a29814e11f88p-10616L }, + { 0x1.d44862fbc3ffe4e8p-112L, 0xb.b4e151abbff7d07p-5376L, 0x1.ee4d3e9b98db0a2ap-5484L, 0x1.ee4d3e9b98db0a2cp-5484L }, + { -0x2.12dbeddf1c572d24p-140L, 0x2.ff042155d43837b8p-456L, -0x8.f6a8f33c480a7f2p-596L, -0x8.f6a8f33c480a7f1p-596L }, + { 0x2.3c7141110977a1c8p-4L, 0x2.05648cc457e12568p-13128L, 0x6.1a52ec074b18dfc8p-13132L, 0x6.1a52ec074b18dfdp-13132L }, + { -0x2.464f6995d5846fc4p-4L, 0x5.b10ee7beb80f44c8p-8176L, -0x1.4257e6f5e91cfddep-8176L, -0x1.4257e6f5e91cfddcp-8176L }, + { 0x2.9d621c7f336f1a48p-4L, -0x1.d8b4cd85d3888762p-52L, -0x6.73a5b1d70e5b209p-56L, -0x6.73a5b1d70e5b2088p-56L }, + { -0x4.6cbaaf7a0ff40348p-4L, -0x1.9ebb345e0fe9f626p+152L, 0xc.1b0a270a799060ap+148L, 0xc.1b0a270a799060bp+148L }, + { 0x2.d68e2ba3eefebbfcp-4L, 0x8.2755e9d53631d79p+13464L, 0x1.ebbd2662baaccf46p+13464L, 0x1.ebbd2662baaccf48p+13464L }, + { -0x2.a56af544d1743bfp-4L, -0x8.debe114eff2fb6p-4048L, 0x2.503fe5daad061f4cp-4048L, 0x2.503fe5daad061f5p-4048L }, + { 0x2.f272a3677efcea3p-4L, -0x1.65eed16b0fbcd18p+3820L, -0x5.74cf60355c5bfdd8p+3816L, -0x5.74cf60355c5bfddp+3816L }, + { -0x3.a8152a324eb599fcp-4L, 0x6.42f937c40f3caep-11832L, -0x2.580a107ac781e86cp-11832L, -0x2.580a107ac781e868p-11832L }, + { 0x1.fa90f8ba8eb45d18p-4L, 0x4.97d111ff563d917p+672L, 0xc.5cc95af0b67a1aap+668L, 0xc.5cc95af0b67a1abp+668L }, + { -0x3.21d6a286a61d7cc4p-4L, -0xe.6ac05f4362737a7p-1760L, 0x4.8804f700b3804178p-1760L, 0x4.8804f700b380418p-1760L }, + { 0x3.bcec63e4fa22720cp-4L, 0x1.eb48022e5de68778p-2240L, 0x9.4cf74bdc0e3abdap-2244L, 0x9.4cf74bdc0e3abdbp-2244L }, + { -0x2.2cafb74c417a862cp-4L, -0x7.4ac89cd8c8343a4p+5320L, 0x1.896adaaf74423c38p+5320L, 0x1.896adaaf74423c3ap+5320L }, + { 0x4.747d8f2cd1e0b778p-4L, -0x7.89b9fbbca8b068b8p-10904L, -0x2.abdd7d16fc67e358p-10904L, -0x2.abdd7d16fc67e354p-10904L }, + { -0x1.6c4d52d87e228112p-4L, -0x6.db5f46e906978aa8p+6068L, 0xe.be49f013bde4911p+6064L, 0xe.be49f013bde4912p+6064L }, + { 0x4.7d3fe6ab59f609d8p-4L, -0x3.440be44d83299c4p+7040L, -0x1.2a4c3c114199e58ep+7040L, -0x1.2a4c3c114199e58cp+7040L }, + { -0x1.e480cff01c28fb9cp-4L, -0x4.d9f9d12975bd7c4p-12344L, 0xe.190f113ed0925d4p-12348L, 0xe.190f113ed0925d5p-12348L }, + { 0x2.8861f994981bf17cp-4L, -0xd.f58d50699b9fcecp+1284L, -0x2.f59c17dbe51eda7p+1284L, -0x2.f59c17dbe51eda6cp+1284L }, + { -0x3.1a3b6bf5fdf6fd38p-4L, -0x1.fc2d15ef2a625dacp+8468L, 0x9.e07f594916cb5fcp+8464L, 0x9.e07f594916cb5fdp+8464L }, + { 0x3.fd8b6443df9dc76p-4L, 0x6.2216263345a9de58p-3452L, 0x1.f85e4c88ba163cd4p-3452L, 0x1.f85e4c88ba163cd6p-3452L }, + { -0x3.70a228d1d553bf4cp-4L, -0x2.eb67d254460cc304p-9620L, 0x1.0504afba5f5c67a6p-9620L, 0x1.0504afba5f5c67a8p-9620L }, + { 0x5.cf949cfc0d27367p-152L, -0x3.05788e2f35ec3cd4p+14300L, -0x1.9543d4ed5bd3f968p+14152L, -0x1.9543d4ed5bd3f966p+14152L }, + { -0x4.019728c8p-16416L, 0x6.86d9d7ed1e2fc6p-12528L, -0x8p-16448L, -0x0p+0L }, + { 0x9.e6cc5abae024698p-8L, 0x2.833fcfa47e2d91ap+3004L, 0x2.33784faf5903c048p+3000L, 0x2.33784faf5903c04cp+3000L }, + { -0x3.67b9dd9843d29348p-4L, -0xf.d97f1711de15f9cp+1908L, 0x5.78d0d081f721bp+1908L, 0x5.78d0d081f721b008p+1908L }, + { 0x4.7a28ab2398fb352p-4L, 0x1.9bd5eed22e819bdep-3276L, 0x9.2974b9b5c14f70bp-3280L, 0x9.2974b9b5c14f70cp-3280L }, + { -0x3.081509267e970864p-4L, -0xd.1b186c2e3417901p+1864L, 0x3.f8d299ebb41104fp+1864L, 0x3.f8d299ebb41104f4p+1864L }, + { 0x4.6abc9681ac49cfdp-4L, -0x2.95224c7756c21458p+0L, -0xe.8847182bcf70294p-4L, -0xe.8847182bcf70293p-4L }, + { -0x7.2739454a8f4579bp-8L, 0x4.6f28415fd23d939p+14200L, -0x2.e698128be4a28434p+14196L, -0x2.e698128be4a2843p+14196L }, + { 0x1.d251fdcff8361a78p-4L, -0xb.d0fe6ed90e574e6p+212L, -0x1.d68b3c44dd6d6312p+212L, -0x1.d68b3c44dd6d631p+212L }, + { -0x1.be7ad3ad1b0e4a4p-4L, -0x6.497aa8a74bb2d87p-2628L, 0x1.0bfe1bb4299021acp-2628L, 0x1.0bfe1bb4299021aep-2628L }, + { 0x4.013e3e7e82bd3c2p-4L, 0x7.4bbb894be77050dp+12468L, 0x2.59ee0420ec379c6p+12468L, 0x2.59ee0420ec379c64p+12468L }, + { -0x3.3293e00e66ee8678p-4L, -0x5.530558acc4b5df88p-6048L, 0x1.b66bd84ef8a7f7aep-6048L, 0x1.b66bd84ef8a7f7bp-6048L }, + { 0x2.596e2190f3ee11cp-4L, -0x2.cd6c97393ef343bcp+1120L, -0x8.dcd9e903e4f5e01p+1116L, -0x8.dcd9e903e4f5ep+1116L }, + { -0xe.c481fc40bbce19fp-8L, 0x1.3b4ac09f6ebd1b0ep+1796L, -0x1.b06e1e656074da7p+1792L, -0x1.b06e1e656074da6ep+1792L }, + { 0x2.9f321f282784f3acp-4L, -0x1.d9decdb4b87520d6p+8416L, -0x6.7bdfcc4fcaf35388p+8412L, -0x6.7bdfcc4fcaf3538p+8412L }, + { -0x3.1abd020d7e543628p-4L, 0xd.6d80dc94539115ep-6852L, -0x4.2dbeb1b3e077f1ep-6852L, -0x4.2dbeb1b3e077f1d8p-6852L }, + { 0x1.a74119aefdfb086ap-4L, 0x1.4dd68c499218991cp-9528L, 0x2.f5c7d01357aeb918p-9532L, 0x2.f5c7d01357aeb91cp-9532L }, + { -0x3.9cc7932ded57df7p-4L, 0x1.c00dbd725f27ace4p+392L, -0xa.5694f0b8c0a7444p+388L, -0xa.5694f0b8c0a7443p+388L }, + { 0x3.0c65989eee333da8p-4L, -0xc.8ed445e1ea26da6p+944L, -0x3.28d9b866e998f3p+944L, -0x3.28d9b866e998f2fcp+944L }, + { -0x1.01dc461ca1f30d7cp-4L, 0x2.219473696b04364cp+5028L, -0x3.32e1826689d1e408p+5024L, -0x3.32e1826689d1e404p+5024L }, + { 0x2.032a2322395b1f7cp-4L, -0x5.da9f94100d42a778p+4556L, -0x1.00234c58a1593fa4p+4556L, -0x1.00234c58a1593fa2p+4556L }, + { -0x1.37d775d6d37abbc6p-4L, -0xd.e2cee7a54e7c7dfp-2844L, 0x1.961ce3d5d092c2bcp-2844L, 0x1.961ce3d5d092c2bep-2844L }, + { 0x5.e788f67p-16416L, -0x1.b20009ea27ed12d4p+2716L, -0xe.70f136a6f3fd9c9p-13700L, -0xe.70f136a6f3fd9c8p-13700L }, + { -0xe.54631f1d0a92519p-108L, 0x2.3b61b0ed36fec68cp-11996L, -0x2.e245772cd7482448p-12100L, -0x2.e245772cd7482444p-12100L }, + { 0x4.78666b09054db02p-4L, 0xd.9866ac659888197p-12280L, 0x4.d525ce8fca3be678p-12280L, 0x4.d525ce8fca3be68p-12280L }, + { -0x2.b6ea5b47429cf1ccp-8L, 0x2.6614f05e9e7a9d2cp+13784L, -0x9.71b7a8a09362cc3p+13776L, -0x9.71b7a8a09362cc2p+13776L }, + { 0x1.9fc564d5cd252834p-4L, -0x7.78b432f287942418p+8704L, -0x1.0ac7c8898679cf7cp+8704L, -0x1.0ac7c8898679cf7ap+8704L }, + { -0x3.627629b0fc2138f4p-4L, 0x2.4adc5340e0bb85bp-14064L, -0xc.93a314133e66097p-14068L, -0xc.93a314133e66096p-14068L }, + { 0xd.e2670359c5e7cep-8L, 0x1.776c2223c9793e74p+7492L, 0x1.c9b37d76bc51a286p+7488L, 0x1.c9b37d76bc51a288p+7488L }, + { -0x1.ea4c7df916a93fa4p-4L, 0x1.77873596c55066eap-4292L, -0x4.512b68b4a46ce678p-4296L, -0x4.512b68b4a46ce67p-4296L }, + { 0x7.782d2513f5714bdp-8L, -0xd.cf27b2fef93cd6fp+900L, -0x9.2ae14b6070abef1p+896L, -0x9.2ae14b6070abefp+896L }, + { -0x4.40fc24e1abcef118p-4L, -0x1.acf23a9f7fc1bac6p+4612L, 0xb.f42951fd6c23841p+4608L, 0xb.f42951fd6c23842p+4608L }, + { 0x1.a8824a9a4cd5dc64p-4L, -0x1.c0f84566366a7b42p-1364L, -0x3.fdfecdec46081674p-1368L, -0x3.fdfecdec4608167p-1368L }, + { -0x2.656451181fd48ae8p-4L, -0x8.112f7800783ce43p+14416L, 0x1.e35a03c5b235c0bp+14416L, 0x1.e35a03c5b235c0b2p+14416L }, + { 0x8.870c70596055849p-8L, 0x1.07c83cf4f6c4df66p+2828L, 0xc.7855e9bc9829172p+2820L, 0xc.7855e9bc9829173p+2820L }, + { -0x2.b8afdde3454b599p-4L, 0x2.8eebc607cfde77d8p-8824L, -0xb.027de4727525e58p-8828L, -0xb.027de4727525e57p-8828L }, + { 0x2.31f1d5227156b604p-4L, -0x1.2b06750af8061c3p+4092L, -0x3.77668bc7db26768p+4088L, -0x3.77668bc7db26767cp+4088L }, + { -0x2.032456443411d81p-4L, -0xb.f31c2fef2a2645fp-1980L, 0x2.5131763f6e042228p-1980L, 0x2.5131763f6e04222cp-1980L }, + { 0x1.3042297b1a544afep-4L, 0x3.f1be09c7487defap+14152L, 0x6.8612fdbf3a6c6758p+14148L, 0x6.8612fdbf3a6c676p+14148L }, + { -0x4.20c8cc889aaca378p-4L, 0x1.6010a2abc0602b0ep-14432L, -0x9.791e17dde1c914ep-14436L, -0x9.791e17dde1c914dp-14436L }, + { 0x2.776cad4e7559584cp-8L, 0xb.e51e58c1c7b3dbfp+14964L, 0x2.a1fe9ebfdf8a86ap+14960L, 0x2.a1fe9ebfdf8a86a4p+14960L }, + { -0xf.b02a1730396127ep-8L, -0xc.11b48ff5e5ec64ep+7368L, 0x1.19e46bdcea15f47cp+7368L, 0x1.19e46bdcea15f47ep+7368L }, + { 0x4.1edb9c5a8639aaap-4L, 0x1.bbf840a1aee939e4p+13432L, 0x9.2c66ade98f2991ep+13428L, 0x9.2c66ade98f2991fp+13428L }, + { -0x2.e5ef99ea8924db7p-4L, 0x3.5a17dd1b1d7f10fcp-12416L, -0xf.76499bc4522f185p-12420L, -0xf.76499bc4522f184p-12420L }, + { 0x5.2ceb4e8ad3a63198p-56L, 0x1.10226b66be92f5ep-13504L, 0x7.efec9208539fa86p-13560L, 0x7.efec9208539fa868p-13560L }, + { -0x1.609defa4c28c41aap-68L, -0x1.9abae50c07573824p-3260L, 0x3.3032106521e2a38p-3328L, 0x3.3032106521e2a384p-3328L }, + { 0x1.17954e967e739b96p-4L, 0xf.d9c4d8361d42b6cp-12924L, 0x1.828a9fe2da6d8d6ap-12924L, 0x1.828a9fe2da6d8d6cp-12924L }, + { -0x2.9a3fed5ce81a8d6cp-4L, -0xc.5a8bd8936a03dp-13656L, 0x3.29f77393bb45b71cp-13656L, 0x3.29f77393bb45b72p-13656L }, + { 0x2.c752af068bb180e4p-4L, 0x3.de670419142bc428p-14816L, 0xe.4cd016833918784p-14820L, 0xe.4cd016833918785p-14820L }, + { -0x3.2082fc347aa2e55p-4L, 0x4.e64b83b064446a3p+10008L, -0x1.89807286643a3178p+10008L, -0x1.89807286643a3176p+10008L }, + { 0x2.79eaa550e420d934p-4L, 0x1.f2ae9ee8ba0d3204p-868L, 0x6.786a2bba8c07b1dp-872L, 0x6.786a2bba8c07b1d8p-872L }, + { -0xa.fc3eb30d9c09d39p-8L, -0x2.5ab3fc8e3cf96824p-2280L, 0x2.622ee8401eb2be9p-2284L, 0x2.622ee8401eb2be94p-2284L }, + { 0x3.d81a8d8a8d16a8e8p-4L, -0x3.ce388047558bafc8p-8232L, -0x1.2ea2546e51c6e8f4p-8232L, -0x1.2ea2546e51c6e8f2p-8232L }, + { -0x3.056f019da2d3178cp-4L, -0x1.323a89ec36541c0cp+6516L, 0x5.c74b2bd614a49e08p+6512L, 0x5.c74b2bd614a49e1p+6512L }, + { 0x2.bc32f485a0d1cda4p-4L, -0x2.80bd89a1c7a42c04p+10352L, -0x9.1e18f19057194f5p+10348L, -0x9.1e18f19057194f4p+10348L }, + { -0x1.680e5f4f178505bp-4L, -0xf.1a49a93ff5772ep-1880L, 0x2.0138ef578553b23p-1880L, 0x2.0138ef578553b234p-1880L }, + { 0x2.fc8ccc84ce54f5d4p-8L, 0x3.e472948a7445df58p+11256L, 0x1.0ac7c7a20eca1108p+11252L, 0x1.0ac7c7a20eca110ap+11252L }, + { -0x4.6e1a1a157ff363bp-4L, -0x9.7fc1e541c82e26dp+12412L, 0x4.7151555968fe228p+12412L, 0x4.7151555968fe2288p+12412L }, + { 0x2.58ccc597cdeae488p-4L, 0xf.172c9598837df0ep-3292L, 0x2.fad4e99f0ed6a2ap-3292L, 0x2.fad4e99f0ed6a2a4p-3292L }, + { -0x3.2be4288461f1d2ccp-4L, 0xf.f5f8e2e97cc43a7p-6300L, -0x5.16417a8368ea715p-6300L, -0x5.16417a8368ea7148p-6300L }, + { 0x1.fdf693f75f71c5f8p-4L, 0xf.1536891b917c5b4p-12272L, 0x2.8da7609b1e39234p-12272L, 0x2.8da7609b1e392344p-12272L }, + { -0x3.2561fe08d06ed66p-4L, -0xa.bc73aa7d823faf6p-2276L, 0x3.641e7eed6d3d515cp-2276L, 0x3.641e7eed6d3d516p-2276L }, + { 0x1.1bc04a8e9588d6d2p-8L, -0x1.c52369a0cacff0aep-688L, -0x2.d30b2a4ee51c61dcp-696L, -0x2.d30b2a4ee51c61d8p-696L }, + { -0x1.d61ba0502067409ep-4L, 0x3.73d3d6eaa64d0e48p-13916L, -0x9.b7284d8b255d1e5p-13920L, -0x9.b7284d8b255d1e4p-13920L }, + { 0x1.c4a0b08d7654ecb4p-4L, 0x1.b5b6c832a020e5ecp-4332L, 0x4.2306f7cb22efbd4p-4336L, 0x4.2306f7cb22efbd48p-4336L }, + { -0x3.a5b84c3a8b5a86d8p-4L, 0x3.33e3dabe68c35688p+1484L, -0x1.3206409c6c6fc45p+1484L, -0x1.3206409c6c6fc44ep+1484L }, + { 0x9.dcdfcf8p-16420L, -0x5.4a43e598fc3723cp-9444L, -0x8p-16448L, -0x0p+0L }, + { -0x7.c97e52a8p-16416L, -0x4.c1408d8a28bcc7ep+10200L, 0x3.56b150006e157e34p-6212L, 0x3.56b150006e157e38p-6212L }, + { 0x5.83b36a0816afd008p-8L, 0x6.728edc7190e888ap-8300L, 0x3.2bfe0fbf8883065p-8304L, 0x3.2bfe0fbf88830654p-8304L }, + { -0x1.a6bb6ebf8bf709p-4L, -0x1.32eaa51c63cff0c2p-12444L, 0x3.03b810bfb07b3e04p-12448L, 0x3.03b810bfb07b3e08p-12448L }, + { 0x3.adb8baaf789553dp-4L, 0x7.b3f922ab6d1fc2d8p-11600L, 0x2.4cbe69773df6c864p-11600L, 0x2.4cbe69773df6c868p-11600L }, + { -0x1.201e22e464402deap-4L, -0x3.bcdf6b0e23c23b8p-3112L, 0x6.4b04dff5faf1ab6p-3116L, 0x6.4b04dff5faf1ab68p-3116L }, + { 0xa.db12b542cfd4967p-8L, -0x2.cc4f4ec335a9b73p-3480L, -0x2.aeb2bfd2569213f8p-3484L, -0x2.aeb2bfd2569213f4p-3484L }, + { -0x1.4bacae5b8139ebf4p-4L, 0x3.018ab0d86a85aa18p-2564L, -0x5.dbfb9574a7700e9p-2568L, -0x5.dbfb9574a7700e88p-2568L }, + { 0xc.37926f622957e79p-8L, 0x6.d9a09257a9de7178p-9644L, 0x7.5f1b82a670566b2p-9648L, 0x7.5f1b82a670566b28p-9648L }, + { -0x2.ab328a75d78456d4p-4L, 0x3.984ce041f93d20dcp+8376L, -0xf.246f0c6123fd2c2p+8372L, -0xf.246f0c6123fd2c1p+8372L }, + { 0x5.0ac37ce140a5e408p-8L, 0xc.85f521d6b73e5cp-12304L, 0x5.a35e190d7bbadde8p-12308L, 0x5.a35e190d7bbaddfp-12308L }, + { -0x2.84eaed8e54bf7608p-4L, -0x3.b386e93fc25a36ep-120L, 0xe.a327ea760c0cc07p-124L, 0xe.a327ea760c0cc08p-124L }, + { 0x3.20e1ecc2bf932e94p-4L, -0x4.f0d6473e6cf14dbp-10104L, -0x1.45e1efc080d53264p-10104L, -0x1.45e1efc080d53262p-10104L }, + { -0x3.af399facb8e06b6cp-4L, -0x1.a6fe04423bc64194p-2412L, 0x9.fb819c61aa22e65p-2416L, 0x9.fb819c61aa22e66p-2416L }, + { 0xd.f2607f2eff81943p-8L, 0x1.db63aa1cc3714696p+5352L, 0x2.461d3054010ba93cp+5348L, 0x2.461d3054010ba94p+5348L }, + { -0x2.1ca9e269366503acp-4L, 0x8.85ca099da14eecfp+11944L, -0x1.bd9606e084b91422p+11944L, -0x1.bd9606e084b9142p+11944L }, + { 0x3.8f814c8a783b37e4p-4L, 0xc.dc92cfd134c1f43p+8032L, 0x3.ba705b78dbdfdb08p+8032L, 0x3.ba705b78dbdfdb0cp+8032L }, + { -0xa.363a7e007bb490cp-8L, 0x3.4fc1153a0181986p+2104L, -0x3.1c9855bfaf3c0b24p+2100L, -0x3.1c9855bfaf3c0b2p+2100L }, + { 0x4.8f405305d971325p-4L, 0x1.68828b76a000f3cap+10416L, 0x8.2690c5f0b9e8f9ep+10412L, 0x8.2690c5f0b9e8f9fp+10412L }, + { -0x3.338c408bb3a0c4a8p-4L, -0xe.159d1696dfd0e91p+10916L, 0x4.894cf2237970296p+10916L, 0x4.894cf22379702968p+10916L }, + { 0x4.8f4674e0d5a0d808p-4L, 0xa.c362f68453e1677p+3476L, 0x3.e4bf65fe96e2af2p+3476L, 0x3.e4bf65fe96e2af24p+3476L }, + { -0xd.54b8a67fe103072p-8L, 0x2.cdcd722c20086f78p-9008L, -0x3.7618e9e91de0ea8cp-9012L, -0x3.7618e9e91de0ea88p-9012L }, + { 0x1.7902a678p-16416L, 0x1.19427dcda0480416p+3436L, 0x2.559440aae40e6a3p-12980L, 0x2.559440aae40e6a34p-12980L }, + { -0x1.c36218d9ea12b06p-120L, -0xc.ce2bca2cbcab86p+11308L, 0x2.092f42c661962da4p+11192L, 0x2.092f42c661962da8p+11192L }, + { 0x4.3848af1238619848p-4L, 0x1.06b2c98753a26482p+4016L, 0x5.8b6a91a3e86c1628p+4012L, 0x5.8b6a91a3e86c163p+4012L }, + { -0x2.1a3e861da87eb79cp-4L, 0x1.4ec5569f83ab5736p-9836L, -0x4.40aa56c3c5c637e8p-9840L, -0x4.40aa56c3c5c637ep-9840L }, + { 0x1.0ae262cde6391e24p-4L, 0x5.73257b4e6064d01p+6604L, 0x7.f0d1589033cf2398p+6600L, 0x7.f0d1589033cf23ap+6600L }, + { -0x4.27fce65cac88f6e8p-4L, -0x1.f57725c0787861ecp-3256L, 0xd.99b231a6d0c4c1dp-3260L, 0xd.99b231a6d0c4c1ep-3260L }, + { 0x3.a27dda9eab4a71cp-4L, -0x1.c7f592e6977ce3bep+12420L, -0x8.6a945925111c26ep+12416L, -0x8.6a945925111c26dp+12416L }, + { -0x2.a793421cbf6f9968p-4L, 0x5.48fc6bc3d7c0194p+1292L, -0x1.621d63e8f5d14274p+1292L, -0x1.621d63e8f5d14272p+1292L }, + { 0x4.0c3cdf0761d114bp-4L, -0x1.a94536dcae3efe9ap-4444L, -0x8.a5f06bea2cc4c7bp-4448L, -0x8.a5f06bea2cc4c7ap-4448L }, + { -0xa.f93df896ce6a1p-8L, -0x5.c36184a826a997c8p+10672L, 0x5.d40fc05d1c8d8c78p+10668L, 0x5.d40fc05d1c8d8c8p+10668L }, + { 0x4.166c1433f1fd7bbp-4L, -0x3.fd85a4b30da5905cp+1568L, -0x1.4f4bec3a523108b4p+1568L, -0x1.4f4bec3a523108b2p+1568L }, + { -0x4.269ac20097d48278p-4L, 0x3.1537ec91418ea6d4p+3920L, -0x1.55f44918ad45177p+3920L, -0x1.55f44918ad45176ep+3920L }, + { 0x4.69a871365aa2e12p-4L, -0xa.36231bab07402b6p-4836L, -0x3.9699940c44fff68p-4836L, -0x3.9699940c44fff67cp-4836L }, + { -0x2.e0e69529aa3c2148p-4L, -0xc.898efcf06fac3c9p-10916L, 0x3.96631e40f648290cp-10916L, 0x3.96631e40f648291p-10916L }, + { 0x8.0d6f02cf24f9c97p-8L, 0x2.6ae43fbbb8290e98p+8564L, 0x1.ba711272f9e989e8p+8560L, 0x1.ba711272f9e989eap+8560L }, + { -0x3.5f039ab81ea9c368p-4L, -0xd.8fb34ea26dcd466p+10808L, 0x4.a10f4862e4c525c8p+10808L, 0x4.a10f4862e4c525dp+10808L }, + { 0x1.3d60e214e24fd8e2p-4L, -0x1.570c61df14ef3c2cp+188L, -0x2.4ef6c43084fc9dep+184L, -0x2.4ef6c43084fc9ddcp+184L }, + { -0x6.40ba95b8e8b92fc8p-8L, 0x1.be3c2fefa23edde8p-11668L, -0xf.eb712b3687d7e23p-11676L, -0xf.eb712b3687d7e22p-11676L }, + { 0x2.732d3b1aa6d2beep-4L, -0x3.cdaf1e5edd4c86p+184L, -0xc.821fcc2bcca0a5dp+180L, -0xc.821fcc2bcca0a5cp+180L }, + { -0x2.152e0397420f72fcp-4L, 0x2.8364ae6977782604p-11632L, -0x8.172bae23dd68d33p-11636L, -0x8.172bae23dd68d32p-11636L }, + { 0x3.e5df21cab65c997cp-4L, -0xf.2ffda7297446dd8p+564L, -0x4.c6f49497a19568p+564L, -0x4.c6f49497a19567f8p+564L }, + { -0x1.04b57b83b68184dep-4L, -0x4.ea4ab92cea09eec8p+11136L, 0x7.762e3332d594d7fp+11132L, 0x7.762e3332d594d7f8p+11132L }, + { 0x5.5594498p-16420L, 0x1.eabcf8252879b3c6p-2564L, 0x0p+0L, 0x8p-16448L }, + { -0x4.c0ce2b247d038ac8p-196L, 0x6.aab669b77225bdf8p+14936L, -0x2.db7821b4f7e6fe48p+14744L, -0x2.db7821b4f7e6fe44p+14744L }, + { 0x3.baced53f1471e364p-4L, 0x1.f4152fd9e1338794p+11508L, 0x9.72c9bd6a87c42aap+11504L, 0x9.72c9bd6a87c42abp+11504L }, + { -0x2.317130a7a75d4aa4p-4L, 0x4.3a585af61da3746p+10124L, -0xe.63319f6181f397cp+10120L, -0xe.63319f6181f397bp+10120L }, + { 0x4.1c54e5eb63fd28fp-4L, -0xc.0148aba29b8d557p-13200L, -0x3.f5d7e7e9f34a935cp-13200L, -0x3.f5d7e7e9f34a9358p-13200L }, + { -0x3.a93752f48b02534p-8L, 0x2.d86805c835243508p+7344L, -0xf.2300d704ac6742ep+7336L, -0xf.2300d704ac6742dp+7336L }, + { 0xc.f022cc79b221c33p-8L, -0x1.7bce210b7a3b4ce4p+13136L, -0x1.b03f9fb7b732302cp+13132L, -0x1.b03f9fb7b732302ap+13132L }, + { -0x3.2a0c0f7441062828p-4L, -0x3.b3492f1fb9e61c04p+5492L, 0x1.2d25592e5dfb1a5p+5492L, 0x1.2d25592e5dfb1a52p+5492L }, + { 0x1.5e4534702331dd36p-4L, 0xe.23089b23489992ap-8584L, 0x1.ac6bc81aca47148ep-8584L, 0x1.ac6bc81aca47149p-8584L }, + { -0xb.335bf0873459e2ap-8L, -0x2.d5f5698f339a3b6cp+12224L, 0x2.edb30cd4b7211294p+12220L, 0x2.edb30cd4b7211298p+12220L }, + { 0x2.a703a7cbf8389048p-4L, -0x3.c02be3f7a5fcc11p-10844L, -0xd.479c75b64677e6ep-10848L, -0xd.479c75b64677e6dp-10848L }, + { -0x4.6a8b51e9bd44a3d8p-4L, -0x9.16e2136af0bd999p+5352L, 0x4.3c3d2021a09b0ccp+5352L, 0x4.3c3d2021a09b0cc8p+5352L }, + { 0x2.2dedef8b8456de34p-4L, -0x1.612ac453131ff6ccp+12644L, -0x4.110b3f69085532bp+12640L, -0x4.110b3f69085532a8p+12640L }, + { -0xc.1dba691316d74bdp-8L, 0x2.ec398343a2ca763p-1556L, -0x3.456805b257b0ee1p-1560L, -0x3.456805b257b0ee0cp-1560L }, + { 0xe.ec733d0bbf8686ep-8L, -0x3.cf1395284a6357fp-6892L, -0x4.fb48374fa922b608p-6896L, -0x4.fb48374fa922b6p-6896L }, + { -0x1.edcef2a6b293fd46p-4L, -0x5.f75c87391b381cb8p+12600L, 0x1.1b1516b3d9f8b04cp+12600L, 0x1.1b1516b3d9f8b04ep+12600L }, + { 0x1.1ee70cc7cae8441ap-4L, 0xd.5bd215637191857p-9180L, 0x1.4e0453af199cc7d6p-9180L, 0x1.4e0453af199cc7d8p-9180L }, + { -0x1.3b763982b3071dd4p-4L, 0x9.e9da1b99800a76dp-4788L, -0x1.256fd3aa961492bap-4788L, -0x1.256fd3aa961492b8p-4788L }, + { 0x1.dcdb59c7c235dbc2p-4L, -0x2.d021db0eb4e66bc4p+4172L, -0x7.26a25cdf864b2e2p+4168L, -0x7.26a25cdf864b2e18p+4168L }, + { -0x7.39e6166b4e7ff328p-8L, 0xd.d257bb858d37bdep+5592L, -0x9.22a66ce89f4a1d8p+5588L, -0x9.22a66ce89f4a1d7p+5588L }, + { 0x2.cbc98bdd8b82901p-4L, 0x3.6f0885306061a098p+1264L, 0xc.c3fea6c91774964p+1260L, 0xc.c3fea6c91774965p+1260L }, + { -0x2.7c3e61d780a4f324p-4L, -0x1.da01a42e71e30548p+7012L, 0x7.37128b7293c62da8p+7008L, 0x7.37128b7293c62dbp+7008L }, + { 0x1.637d8202e9a84f9p-64L, -0x3.95f019facb81ca2p-352L, -0x7.2ef9571efed13f38p-416L, -0x7.2ef9571efed13f3p-416L }, + { -0x6.82a90c9p-16416L, 0x8.4b9ea0f6dd41af6p-3128L, -0x8p-16448L, -0x0p+0L }, + { 0xb.15e9277124ef54ap-8L, 0x3.181d10559801b24p-3016L, 0x3.071c007555f37dp-3020L, 0x3.071c007555f37d04p-3020L }, + { -0x2.34958a751bd7e2b4p-4L, -0x7.1e0c4f162e18cb3p-14368L, 0x1.85dc9e96b295d1f4p-14368L, 0x1.85dc9e96b295d1f6p-14368L }, + { 0x1.baa38808f4d9ef8p-4L, -0x1.94cc68b2b3c4a3cap+6596L, -0x3.bed8f66fe0b67d94p+6592L, -0x3.bed8f66fe0b67d9p+6592L }, + { -0x2.9c8a581b1fc5d614p-4L, -0x2.8c01857641e55648p-2264L, 0xa.79d78516d7f224p-2268L, 0xa.79d78516d7f2241p-2268L }, + { 0xf.b589bcceb220068p-8L, -0x1.4789d33b87e903d2p+5568L, -0x1.c2450650774c5p+5564L, -0x1.c2450650774c4ffep+5564L }, + { -0x2.8d5e2c4a97b5ca14p-4L, 0xa.6c4e4d3fd85b1d1p-2464L, -0x2.9cf440e73f0f258p-2464L, -0x2.9cf440e73f0f257cp-2464L }, + { 0x1.fac5b9a230ace1ccp-4L, -0xc.183e2d13feeccbp+5796L, -0x2.090f003628c73a5p+5796L, -0x2.090f003628c73a4cp+5796L }, + { -0x2.3a1aa1ebf9d944d8p-4L, 0xb.56f3fb671e6d7bp-10204L, -0x2.73b180956d044ca8p-10204L, -0x2.73b180956d044ca4p-10204L }, + { 0x3.f1ed5917ebae5ee8p-4L, 0x1.5d25d26ea685965ap-9392L, 0x6.f0398d9603c092cp-9396L, 0x6.f0398d9603c092c8p-9396L }, + { -0x4.2ed20be58e7ce458p-4L, -0x1.bb72045b4fb64006p+11436L, 0xc.1df41156acd8b46p+11432L, 0xc.1df41156acd8b47p+11432L }, + { 0x1.533ed177d8f43096p-4L, -0x6.6c5aad8f16c7612p-12240L, -0xb.cc4d7e98c47615cp-12244L, -0xb.cc4d7e98c47615bp-12244L }, + { -0x2.b3759933edcfbb8cp-4L, -0x5.be3632756b1f6c08p-13700L, 0x1.882fe94f6b50223p-13700L, 0x1.882fe94f6b502232p-13700L }, + { 0x4.71542952f2eb2118p-4L, -0xf.bc3571405a814dbp-12400L, -0x5.90065e0286f0d738p-12400L, -0x5.90065e0286f0d73p-12400L }, + { -0x2.17fa44980470472p-4L, 0xb.d365be5d38977b2p-484L, -0x2.648810e10755e434p-484L, -0x2.648810e10755e43p-484L }, + { 0x3.a3076d42e4a727a4p-4L, 0x1.16e61b22825583d6p-10652L, 0x5.269729e108bbd29p-10656L, 0x5.269729e108bbd298p-10656L }, + { -0x3.54041d65782d11a8p-4L, -0x3.82c837279f08c5c8p-2472L, 0x1.2e64f5ccd94f2862p-2472L, 0x1.2e64f5ccd94f2864p-2472L }, + { 0x4.6fa9ede403127e4p-4L, -0x1.71f2e5247996097cp+11700L, -0x8.29ca8ac57dfca06p+11696L, -0x8.29ca8ac57dfca05p+11696L }, + { -0x2.e31e7f5102321e84p-4L, -0x1.06117dc5bf40339ep+6984L, 0x4.b3d0402392c36ffp+6980L, 0x4.b3d0402392c36ff8p+6980L }, + { 0x3.b9638838b09138f4p-4L, -0x3.7b942a0763ad15e4p+10616L, -0x1.0d2953cf22d7307ap+10616L, -0x1.0d2953cf22d73078p+10616L }, + { -0x4.91ac63ed12ffa698p-4L, 0xf.ca607d23e02b6a5p-5416L, -0x7.a90ecaa3a7c85628p-5416L, -0x7.a90ecaa3a7c8562p-5416L }, + { 0x3.bd32cd8p-16420L, 0xc.64d8265a9554331p+13480L, 0x4.2db54f6499fee318p-2936L, 0x4.2db54f6499fee32p-2936L }, + { -0x7.30ab6348p-16416L, 0x2.d01e62e5954e5ecp-84L, -0x8p-16448L, -0x0p+0L }, + { 0x4.67c806cb2037368p-4L, -0x1.eee94944aabe7324p+14052L, -0xa.da76434365cbe5p+14048L, -0xa.da76434365cbe4fp+14048L }, + { -0x9.63a7f9a9b4e3772p-8L, -0x6.9750c01b7eab2c18p-6576L, 0x5.af5d76a3b96d562p-6580L, 0x5.af5d76a3b96d5628p-6580L }, + { 0x3.a890e71f965c423p-4L, 0x2.65754ef7508e6b2cp+14816L, 0xb.63ec8116f9623b9p+14812L, 0xb.63ec8116f9623bap+14812L }, + { -0x4.49c1355a26341ebp-4L, -0xa.2df5b84e07b2b1dp+2576L, 0x4.94ef7cdabf583378p+2576L, 0x4.94ef7cdabf58338p+2576L }, + { 0x3.592044d31e941f3cp-4L, -0xd.a2a1544a13a75a8p+8764L, -0x3.bcdd3b58fc6b4dccp+8764L, -0x3.bcdd3b58fc6b4dc8p+8764L }, + { -0x2.1c5be0eceea3074cp-4L, 0x9.8705b776af68ab6p+12632L, -0x1.f1d1b127094cc7d8p+12632L, -0x1.f1d1b127094cc7d6p+12632L }, + { 0x1.918ff257bb0d693cp-4L, 0xe.4262f654fe7fbd6p+7432L, 0x1.ec89a740290f2b92p+7432L, 0x1.ec89a740290f2b94p+7432L }, + { -0x4.4c3ff5e8f02ea658p-4L, 0x2.44e6f663c6e96414p+2392L, -0x1.062905420850e93p+2392L, -0x1.062905420850e92ep+2392L }, + { 0x4.25a93aaf3e8e66d8p-4L, -0xa.1d09747650d55b9p+9676L, -0x3.5cdba7179be56514p+9676L, -0x3.5cdba7179be5651p+9676L }, + { -0x7.4029c8dbfe579468p-8L, 0x1.c03a669c155fa5f8p+9484L, -0x1.29459dde5831c58ap+9480L, -0x1.29459dde5831c588p+9480L }, + { 0x4.99a9a4d5bf45f348p-8L, 0xa.41177495779f599p-6252L, 0x4.37364b1fa5c8e98p-6256L, 0x4.37364b1fa5c8e988p-6256L }, + { -0x2.24107ead42d5b40cp-8L, 0x1.c65fcf3a7b070d68p-10904L, -0x5.814bc88b1eff00f8p-10912L, -0x5.814bc88b1eff00fp-10912L }, + { 0xd.7bd18c92836d9b7p-8L, -0x2.fe022bf9a8eac0f8p+4008L, -0x3.8b9dbb6814dca604p+4004L, -0x3.8b9dbb6814dca6p+4004L }, + { -0x2.bd9ef84dc1262334p-4L, -0x1.926d2e72dc294662p+8176L, 0x6.d15c01dce8da9378p+8172L, 0x6.d15c01dce8da938p+8172L }, + { 0x1.79677266716881dep-4L, -0x3.9250255d51f10438p-8936L, -0x7.442fb2c4a2d081ap-8940L, -0x7.442fb2c4a2d08198p-8940L }, + { -0xd.23ebb0103a3412p-8L, 0x1.0c7d8c40c9f7f63cp-10576L, -0x1.4692db88dd7f76dep-10580L, -0x1.4692db88dd7f76dcp-10580L }, + { 0x3.c37ee7fcc3f66618p-4L, -0x1.0b426c0abe2f515p-10024L, -0x5.1746c07ac5fd95a8p-10028L, -0x5.1746c07ac5fd95ap-10028L }, + { -0x2.64319ac6eea8ea44p-4L, 0x2.14977aea96547074p-8036L, -0x7.c633388965b5c9p-8040L, -0x7.c633388965b5c8f8p-8040L }, + { 0x4.36557dfc7b7a0858p-4L, -0xb.5f490bd4a0d58a3p-8256L, -0x3.d58fc1d6c174b18p-8256L, -0x3.d58fc1d6c174b17cp-8256L }, + { -0x2.118c4c79edf47354p-4L, 0x5.7bbb5596a817d228p-2732L, -0x1.185caaa41d1fcbf8p-2732L, -0x1.185caaa41d1fcbf6p-2732L }, + { 0x2.2dfb2465030d9704p-120L, -0x3.2070b9ab6c091d04p+156L, -0x9.d4ffa1b506ada6fp+36L, -0x9.d4ffa1b506ada6ep+36L }, + { -0x1.b8ca4718dfb949b4p-156L, 0x2.b703c4e83381ac98p-13808L, -0x6.be79c4120e72058p-13964L, -0x6.be79c4120e720578p-13964L }, + { 0x3.aa7e6497bf65cec8p-4L, 0x2.207f40048a485988p+8000L, 0xa.20f27e1acc74886p+7996L, 0xa.20f27e1acc74887p+7996L }, + { -0x4.a61b8649abf09bdp-4L, -0x6.463247ab1fb7f22p-9052L, 0x3.1b719641a4a7976cp-9052L, 0x3.1b719641a4a7977p-9052L }, + { 0x3.7f3e92fee7a6f28p-4L, -0x2.0b71289ec2fa384cp+13492L, -0x9.546f7189f8f4635p+13488L, -0x9.546f7189f8f4634p+13488L }, + { -0x2.48a19098f3bb9008p-4L, 0xb.8b1a411e3e76627p-5852L, -0x2.90922f5ecf5c1fd4p-5852L, -0x2.90922f5ecf5c1fdp-5852L }, + { 0x3.b47754510462f6c4p-4L, -0x2.0bfc7264e887cdc8p+7904L, -0x9.d734f5619b3ab5bp+7900L, -0x9.d734f5619b3ab5ap+7900L }, + { -0x1.9703efc23286a644p-4L, 0x5.4bd8b1a807b11328p-15000L, -0xc.cb8cd9e7e25290cp-15004L, -0xc.cb8cd9e7e25290bp-15004L }, + { 0x3.765f83baff0c21fcp-4L, -0xf.dcbdd271ed9656bp+1780L, -0x4.7ba2cfd8cf705ba8p+1780L, -0x4.7ba2cfd8cf705bap+1780L }, + { -0x2.d47396eb2be5851p-4L, -0xa.33e2e879179697fp+1788L, 0x2.dd6dda56ba24386p+1788L, 0x2.dd6dda56ba243864p+1788L }, + { 0x2.a803fd68ec7649e8p-4L, 0xb.02935a9215a3cacp+8628L, 0x2.7092c54d30c5f24p+8628L, 0x2.7092c54d30c5f244p+8628L }, + { -0x3.0abba9ed50933008p-4L, -0xa.646a2e2861abb61p+11556L, 0x3.295a5daefccd137cp+11556L, 0x3.295a5daefccd138p+11556L }, + { 0x1.4fddcbc604cd0d02p-4L, 0x2.bb83c03d681805d8p-13988L, 0x4.f88acdec70c270ep-13992L, 0x4.f88acdec70c270e8p-13992L }, + { -0x3.13fe026e5c2ebb5cp-4L, -0x2.e6c29d1a543973dp-14108L, 0xe.4f547fb973cd189p-14112L, 0xe.4f547fb973cd18ap-14112L }, + { 0x6.fd3591d417b2bea8p-8L, 0x7.3b0323418d7119bp+10092L, 0x4.7edc810794e8dc88p+10088L, 0x4.7edc810794e8dc9p+10088L }, + { -0x3.d7d6efab7eaa891p-4L, -0x1.e2d85877948f2bfep+3328L, 0xb.f59e66f55ab1a34p+3324L, 0xb.f59e66f55ab1a35p+3324L }, + { 0x3.866120802df86e44p-4L, 0xb.ede747cdb5bd40ap-13692L, 0x3.6d37b2c1b0fc0a44p-13692L, 0x3.6d37b2c1b0fc0a48p-13692L }, + { -0x1.837e3a3951b222fep-4L, -0x9.33ad5ce66f0989cp-12372L, 0x1.51c022680d7198fcp-12372L, 0x1.51c022680d7198fep-12372L }, + { 0x1.fdcd9cf05688d39ap-4L, 0x7.a430ee8b67706cd8p+12908L, 0x1.4b0f5cb18c3a0502p+12908L, 0x1.4b0f5cb18c3a0504p+12908L }, + { -0x4.6d76b6c10b4f68dp-4L, 0x3.86937071555cdafp-6228L, -0x1.a5d93ae065b24362p-6228L, -0x1.a5d93ae065b2436p-6228L }, + { 0xc.e11cc48bc0890a6p-8L, -0xe.d33d2fb05570f5p+9980L, -0x1.0cc2a4739972082ep+9980L, -0x1.0cc2a4739972082cp+9980L }, + { -0x3.15cc58d05242c5c4p-4L, -0x2.b3bc30083b4d4404p+11624L, 0xd.5c643b37b5143f8p+11620L, 0xd.5c643b37b5143f9p+11620L }, + { 0x1.ba0d3017b025eae6p-32L, 0x1.198638bd324fcb54p+14568L, 0x2.bd54dd9644f2be48p+14536L, 0x2.bd54dd9644f2be4cp+14536L }, + { -0x5.fd20bf720e8711ep-172L, 0x6.73a42eb2b2605db8p-3488L, -0x3.7be27d9b5a793af4p-3656L, -0x3.7be27d9b5a793afp-3656L }, + { 0x3.ccf8a019857ed894p-4L, -0x1.d70139a2e6defee6p+7832L, -0x9.0d2c0e9df766c0fp+7828L, -0x9.0d2c0e9df766c0ep+7828L }, + { -0x3.76614c7863ec1a34p-4L, 0x9.5e5abe936c610a9p-7228L, -0x3.4bc5db18912ee0b4p-7228L, -0x3.4bc5db18912ee0bp-7228L }, + { 0x3.41a0d3833286b12p-4L, -0x2.80acf5ba59112edp+14608L, -0xa.b3a9e16bc318f8cp+14604L, -0xa.b3a9e16bc318f8bp+14604L }, + { -0x3.3e705853c67d7d8cp-4L, -0x5.f6741be9484aa37p+7296L, 0x1.f2f9757c7add715cp+7296L, 0x1.f2f9757c7add715ep+7296L }, + { 0x3.48681763319dda58p-4L, -0x3.67fd89d48c38dc8cp-1216L, -0xe.ac78d74c01e27a5p-1220L, -0xe.ac78d74c01e27a4p-1220L }, + { -0x4.7f84659f13b7e02p-4L, 0x7.bf798fb07a11662p+5760L, -0x3.b0889ae3587bbd1cp+5760L, -0x3.b0889ae3587bbd18p+5760L }, + { 0xa.4a3324d14b02089p-8L, 0xe.377d20895e5873fp-8496L, 0xc.eeb025e6099e398p-8500L, 0xc.eeb025e6099e399p-8500L }, + { -0x1.4888cb0fc88855d4p-4L, 0xe.db1b91e2caa0ba9p-5588L, -0x1.cabc6b23578f7164p-5588L, -0x1.cabc6b23578f7162p-5588L }, + { 0x2.7d6c843a1e34bb04p-4L, -0x9.a100a7ee5db1c0dp-13024L, -0x2.025e40217cfd859p-13024L, -0x2.025e40217cfd858cp-13024L }, + { -0x3.5fa0f418a95b1664p-4L, 0xf.bcd9d43d60027c9p-1464L, -0x5.6058e9841e63ffc8p-1464L, -0x5.6058e9841e63ffcp-1464L }, + { 0x4.8fa3ee4eaa7f608p-4L, 0x2.36d491e5ba55fc0cp+3820L, 0xc.d1ad707323f03c3p+3816L, 0xc.d1ad707323f03c4p+3816L }, + { -0x1.4b4df2cc6ad25ea8p-4L, 0x1.868500451829747cp+12564L, -0x2.f84f7bac1d20f1ep+12560L, -0x2.f84f7bac1d20f1dcp+12560L }, + { 0x1.f632e7d78adaa7bap-4L, 0x4.feb116d8a3c818ep+4492L, 0xd.55a8e7b75c1d99p+4488L, 0xd.55a8e7b75c1d991p+4488L }, + { -0x1.1908e7c45b2a3cdp-4L, -0x1.7103d1307c4d3a48p-3456L, 0x2.5d74775e3b76a7ap-3460L, 0x2.5d74775e3b76a7a4p-3460L }, + { 0x3.d1361d5e6ee7fc4cp-4L, -0x4.71adf08ff0311758p+4848L, -0x1.5f2ed550fa6c8e9ap+4848L, -0x1.5f2ed550fa6c8e98p+4848L }, + { -0x1.0feb13e1b3fa32cep-4L, 0x5.beb340c633bfc9b8p-10700L, -0x9.1bff6c6cb9b3392p-10704L, -0x9.1bff6c6cb9b3391p-10704L }, + { 0x2.9f4ded3ecc16efe8p-4L, -0xb.866e84a68035155p-1164L, -0x2.86054df08503d23p-1164L, -0x2.86054df08503d22cp-1164L }, + { -0x1.0e6005400df64018p-4L, 0x3.8d17e470f6e09b88p-8468L, -0x5.9906aeea3ec75f8p-8472L, -0x5.9906aeea3ec75f78p-8472L }, + { 0x2.06b035aa76cdd098p-4L, 0x1.e00da34298889842p-5192L, 0x5.293db0d00f0e8c4p-5196L, 0x5.293db0d00f0e8c48p-5196L }, + { -0x2.d44b97592a7f2cacp-4L, -0xf.c8025dd6fb1fa7dp+5864L, 0x4.6e2ea290515d3d28p+5864L, 0x4.6e2ea290515d3d3p+5864L }, + { 0xb.bf2398p-16424L, -0x9.79c050222c1c028p+2980L, -0xa.094c1b19085e6eap-13440L, -0xa.094c1b19085e6e9p-13440L }, + { -0xe.69fc312b6c20148p-188L, 0x1.4f5d050e1ce71f9ap+9460L, -0x1.b3de2a1f249a3644p+9276L, -0x1.b3de2a1f249a3642p+9276L }, + { 0x7.8ae95a742e52adf8p-8L, 0x8.966bd426c329fd3p+4712L, 0x5.c18ec9b9358e0c1p+4708L, 0x5.c18ec9b9358e0c18p+4708L }, + { -0x2.c7dfd0fb6c73cb18p-4L, -0x2.cf1cfb2de02b7d78p+14340L, 0xc.611330d26020636p+14336L, 0xc.611330d26020637p+14336L }, + { 0xe.5af0f71551e3f5cp-8L, 0x3.a98a7ec294cc83c8p-816L, 0x4.9cbd3cb9c9116e38p-820L, 0x4.9cbd3cb9c9116e4p-820L }, + { -0x1.8276da55153cfdbp-4L, -0x1.a307e03dd9845d44p+5600L, 0x3.be96b5f832a200acp+5596L, 0x3.be96b5f832a200bp+5596L }, + { 0x2.81a24543987fd82p-4L, 0xd.8bd22d5fd653c0cp-9644L, 0x2.d8128d3bec32cd3cp-9644L, 0x2.d8128d3bec32cd4p-9644L }, + { -0x1.379a979d3d9108c8p-4L, 0x7.730ab999d45ba668p+8876L, -0xd.9b19d340489c12ap+8872L, -0xd.9b19d340489c129p+8872L }, + { 0x4.7b84cbeaf9218068p-4L, 0x1.94a35a444837f348p-1060L, 0x9.02e333ae71b31c6p-1064L, 0x9.02e333ae71b31c7p-1064L }, + { -0x4.0c6068743ed7f7ap-4L, 0x8.653a7b58a965687p-2084L, -0x3.88871c668e454124p-2084L, -0x3.88871c668e45412p-2084L }, + { 0x1.c2424e1940d7455p-4L, -0x5.5deec579d8a42c3p-7868L, -0xc.eba462f43ab86e2p-7872L, -0xc.eba462f43ab86e1p-7872L }, + { -0x2.d7b31c0c9af1a328p-4L, -0x1.b015dec33f70594ep-11840L, 0x7.9eeac3e3d95935ep-11844L, 0x7.9eeac3e3d95935e8p-11844L }, + { 0x2.494fadc55b33b084p-4L, -0x3.dc339a3898bc7a18p+8868L, -0xb.e6c675431839112p+8864L, -0xb.e6c675431839111p+8864L }, + { -0x2.ee153b661645587cp-4L, -0x6.c3feb8fbd6d16edp+9160L, 0x1.f96ba24721b9912ep+9160L, 0x1.f96ba24721b9913p+9160L }, + { 0x4.8e20e07126ab5fbp-4L, 0x3.c7f4fe11df2d42d8p+2808L, 0x1.5dd9737f23ac2e7ap+2808L, 0x1.5dd9737f23ac2e7cp+2808L }, + { -0x2.2d194219b0dffcacp-4L, -0x6.07756407b2f410bp-12488L, 0x1.45898bc66612542p-12488L, 0x1.45898bc666125422p-12488L }, + { 0x4.99aacb94db2a32ep-4L, 0x2.185cd30ea16fd298p-8768L, 0xc.38d8901d530a557p-8772L, 0xc.38d8901d530a558p-8772L }, + { -0x2.96ffad178b37fbfcp-4L, -0x3.e5143e6ad3e345cp-12712L, 0xf.e0050f04899e61ap-12716L, 0xf.e0050f04899e61bp-12716L }, + { 0x2.07cf3823d73ab374p-8L, 0x4.fa7fc381b3d6c2f8p+13688L, 0xe.86ca1ccd04ba732p+13680L, 0xe.86ca1ccd04ba733p+13680L }, + { -0x2.28ed2ce3d1807394p-8L, -0x5.a384207efdf44f98p+10336L, 0x1.1a5201007023cabap+10332L, 0x1.1a5201007023cabcp+10332L }, + { 0x2.469a2200238d7444p-4L, 0x5.9ad70266bfb8e91p+2488L, 0x1.134a7e067761fe5ap+2488L, 0x1.134a7e067761fe5cp+2488L }, + { -0x2.37b70d8d4113f934p-4L, -0x1.af092832a5fc99d8p+10212L, 0x5.cc7a4fd5be1823d8p+10208L, 0x5.cc7a4fd5be1823ep+10208L }, + { 0x2.1e0b843dc844a878p-48L, -0x1.b9ae023d8acd6e66p-13528L, -0x5.453405a12d6a7e78p-13576L, -0x5.453405a12d6a7e7p-13576L }, + { -0x4.4c7b47cp-16416L, -0x3.547713310a06b54p+5744L, 0x1.4a6d0327cbe06654p-10668L, 0x1.4a6d0327cbe06656p-10668L }, + { 0x4.083830ddfa7690ep-4L, 0x1.613dfb10e1a54184p+10872L, 0x7.2893986d292e673p+10868L, 0x7.2893986d292e6738p+10868L }, + { -0x3.433014eef8a70788p-4L, -0x1.a8639abcd8b6e402p-8536L, 0x8.b9e0c375b70f81ap-8540L, 0x8.b9e0c375b70f81bp-8540L }, + { 0x2.d29ec953e7aa219p-4L, 0x1.4fa6beb2f76975acp+13676L, 0x4.ead9b52fbb5f5fc8p+13672L, 0x4.ead9b52fbb5f5fdp+13672L }, + { -0x3.5e2ea6dbdbaa02p-4L, 0x5.ee655300abbc5d6p+14676L, -0x2.05bd11a5d53281cp+14676L, -0x2.05bd11a5d53281bcp+14676L }, + { 0x8.304de71d9e9114cp-8L, 0x2.7910d5b01fbe64e4p-6028L, 0x1.cc1c6eb2df659e2ep-6032L, 0x1.cc1c6eb2df659e3p-6032L }, + { -0x2.b4d0633cb32e7d3p-4L, -0x1.f35e33822898ee8p+10012L, 0x8.57ef3448b90b49dp+10008L, 0x8.57ef3448b90b49ep+10008L }, + { 0x4.349e9799eee38c3p-4L, -0x3.85166ab0880d15d8p-14236L, -0x1.2f60a91c12616b9p-14236L, -0x1.2f60a91c12616b8ep-14236L }, + { -0x1.82c3ae4bbb10637cp-4L, 0x4.d7001bc86349c478p-10896L, -0xb.14b1458f431b427p-10900L, -0xb.14b1458f431b426p-10900L }, + { 0x1.2e5ba50de7eddadap-4L, -0x7.d3c6bad19081ebap-11612L, -0xc.de2fb1024afe26ap-11616L, -0xc.de2fb1024afe269p-11616L }, + { -0x3.83f8c7b7cb57825cp-4L, 0x5.1e6faf1b430e137p+13408L, -0x1.d50d40244e687828p+13408L, -0x1.d50d40244e687826p+13408L }, + { 0xb.41592caa2c324c4p-8L, 0x4.168f2c495ff127f8p+14584L, 0x4.0f6f7aae5e342928p+14580L, 0x4.0f6f7aae5e34293p+14580L }, + { -0x2.a3c26e78708216b4p-4L, 0x8.cbb456a056bda98p+2832L, -0x2.49b56eddf19b1a38p+2832L, -0x2.49b56eddf19b1a34p+2832L }, + { 0x2.559fafbe5db9e92p-4L, -0x1.020dcff6a035d17ep-1564L, -0x3.2b440ece5ae09ac4p-1568L, -0x3.2b440ece5ae09acp-1568L }, + { -0x1.c97f2c8d93653d48p-4L, -0x2.e37117c16676a0ecp-8384L, 0x7.e595007c6cac50dp-8388L, 0x7.e595007c6cac50d8p-8388L }, + { 0x1.9549043c3fae6d76p-4L, -0x5.6ca968825df497b8p-6632L, -0xb.d06c203591750cbp-6636L, -0xb.d06c203591750cap-6636L }, + { -0x2.938e403b0b6781e4p-4L, 0x1.cc1921f91d82e518p+8416L, -0x7.48adf070f40903dp+8412L, -0x7.48adf070f40903c8p+8412L }, + { 0x1.d3d61644611f7f54p-4L, -0x2.3bbe429554a65cfcp-6468L, -0x5.935b89809acb83fp-6472L, -0x5.935b89809acb83e8p-6472L }, + { -0x1.0e5ea40906fee1a8p-4L, 0x2.b30ab79d07e2deap-5244L, -0x4.4148a4a719f6c5a8p-5248L, -0x4.4148a4a719f6c5ap-5248L }, + { 0x1.b7e8585df0a1e78ap-4L, -0x1.1c71d650867d7786p-304L, -0x2.9dd0113be448c594p-308L, -0x2.9dd0113be448c59p-308L }, + { -0x3.c216a3f300f2fa4p-4L, -0x5.1494a94b36616a18p-8936L, 0x1.f659d5fe58f69792p-8936L, 0x1.f659d5fe58f69794p-8936L }, + { 0x1.c0f2c38245dc8a1ep-36L, 0x5.38cf2d6c438c4fdp+10484L, 0xd.363555200aa28b1p+10448L, 0xd.363555200aa28b2p+10448L }, + { -0x5.338a3398p-16416L, 0xb.9bac1859a410106p-9056L, -0x8p-16448L, -0x0p+0L }, + { 0x4.10c4032a61d96d4p-4L, -0x7.0d9040683a3fcp+520L, -0x2.4dc7081478ce8b44p+520L, -0x2.4dc7081478ce8b4p+520L }, + { -0x3.1a6581525a6ef994p-4L, -0x6.d2ef9a6ba6f44528p+10288L, 0x2.1f61e588277a8a1p+10288L, 0x2.1f61e588277a8a14p+10288L }, + { 0xb.44e6f1ad62eb1d3p-12L, 0x1.2f26e54a1a2d2bcep+2628L, 0x1.339dc2b5be6f05ccp+2620L, 0x1.339dc2b5be6f05cep+2620L }, + { -0x3.dc341dbfa33afaf8p-4L, 0x2.87da9cc0fd94cab4p-12668L, -0x1.020e3b564a370bbp-12668L, -0x1.020e3b564a370baep-12668L }, + { 0x2.2f1d94a92b73ba54p-8L, 0xc.fd7aedfbcc36e21p-2864L, 0x2.8c1d8f7d4aeaeb8p-2868L, 0x2.8c1d8f7d4aeaeb84p-2868L }, + { -0x3.1f6b10cfe59f209p-4L, -0x1.d7e7a366c9f4fafp+8040L, 0x9.3d25ebcfc0e8757p+8036L, 0x9.3d25ebcfc0e8758p+8036L }, + { 0x3.7328f5190b649058p-4L, -0x1.cb288c3a6ffb891ap-14664L, -0x8.156bb127252ce95p-14668L, -0x8.156bb127252ce94p-14668L }, + { -0x4.05760d773cce4b18p-4L, -0x3.619f8ab766bdc80cp-12980L, 0x1.697cf65320577f2ep-12980L, 0x1.697cf65320577f3p-12980L }, + { 0x3.06e0564e8648504p-4L, 0x1.9129d4b6a8c0a64cp-3348L, 0x6.446edb2686c4b438p-3352L, 0x6.446edb2686c4b44p-3352L }, + { -0x3.b4c9c714bc24a95p-4L, 0x8.0c9d9e18f2f4e02p+12048L, -0x3.0f534e9f9071cd6cp+12048L, -0x3.0f534e9f9071cd68p+12048L }, + { 0x1.8456626db4b3e754p-4L, 0xa.75791f1b98fa7c2p+7952L, 0x1.5de3cd5f95a39698p+7952L, 0x1.5de3cd5f95a3969ap+7952L }, + { -0x1.cf4a46c4585b047ap-4L, -0x2.588015b168bce7acp-13720L, 0x6.7fd06d3587654c08p-13724L, 0x6.7fd06d3587654c1p-13724L }, + { 0x1.332103e3ea9e239cp-4L, -0xc.30c9869073f6cbfp+14536L, -0x1.458a3582f79dec28p+14536L, -0x1.458a3582f79dec26p+14536L }, + { -0x2.8f2194cfbb3ca8dp-4L, -0x2.5bd03241d4e64288p+9824L, 0x9.7d31337f76bc8p+9820L, 0x9.7d31337f76bc801p+9820L }, + { 0x1.75adff2c459d542ep-4L, 0x8.cc5bcdf810d087bp+12200L, 0x1.1bb28d31bd29f1a2p+12200L, 0x1.1bb28d31bd29f1a4p+12200L }, + { -0x2.7210b844df60db2cp-4L, -0x1.622e351acabb98cep-1124L, 0x5.4c208ba7477d9a4p-1128L, 0x5.4c208ba7477d9a48p-1128L }, + { 0xe.6e7603454ee5fdap-8L, 0x2.cccf4c722416cda8p+10164L, 0x3.8b6a8a886aa48544p+10160L, 0x3.8b6a8a886aa48548p+10160L }, + { -0x4.51b2bbef5b4e2008p-4L, 0x3.6cdc3fba23bef70cp+12224L, -0x1.8e074b185d5c9a1p+12224L, -0x1.8e074b185d5c9a0ep+12224L }, + { 0x4.086bd3b7798df198p-4L, -0x5.3ede769cd9e10ad8p-13484L, -0x1.b37dba8860e6a8e8p-13484L, -0x1.b37dba8860e6a8e6p-13484L }, + { -0x3.444dbd716806ed7p-4L, -0x1.a1223f3c67d88328p+14220L, 0x8.96fbc10a6b2910cp+14216L, 0x8.96fbc10a6b2910dp+14216L }, + { 0x7.845f8708p-16416L, -0x9.2a78d116f539cddp+13612L, -0x6.3672794bc955e378p-2800L, -0x6.3672794bc955e37p-2800L }, + { -0x9.a00bf03936bb962p-188L, 0xb.006265771517025p+9288L, -0x9.8c4e23ea8f3d0ccp+9104L, -0x9.8c4e23ea8f3d0cbp+9104L }, + { 0x4.1484721ea2376538p-4L, -0x1.a41add8aeb9b4806p-7968L, -0x8.9aae06ea9963ce4p-7972L, -0x8.9aae06ea9963ce3p-7972L }, + { -0x2.ceb5ec6d975953c8p-4L, 0x1.3990fbbe138579bp-2444L, -0x5.747fa8d3ebe39c2p-2448L, -0x5.747fa8d3ebe39c18p-2448L }, + { 0x2.0eb33e95ad6976d4p-4L, -0x1.1151218de56ba42cp-13140L, -0x2.fb304a838c96f87cp-13144L, -0x2.fb304a838c96f878p-13144L }, + { -0x2.eb00c9bd97ca2dp-4L, -0x5.2422819f09d6c978p-5108L, 0x1.7e51d1ba67214bdcp-5108L, 0x1.7e51d1ba67214bdep-5108L }, + { 0x1.16afed5122a1c164p-4L, -0x6.328d311aeae95f4p-7344L, -0x9.6aa5fcce16eb342p-7348L, -0x9.6aa5fcce16eb341p-7348L }, + { -0x4.57c457a4cf259718p-8L, -0x3.96ccc33bb2e63e44p-12628L, 0x1.6ae07bf02b257026p-12632L, 0x1.6ae07bf02b257028p-12632L }, + { 0x1.aeeefbd8d00e0efep-4L, -0xf.b5614be31d80bd7p+7168L, -0x2.445bf283f4c48574p+7168L, -0x2.445bf283f4c4857p+7168L }, + { -0x2.5dce95be94cb3c98p-4L, -0x2.2e554820ae22992cp-120L, 0x8.0ec90a8240db617p-124L, 0x8.0ec90a8240db618p-124L }, + { 0x2.3818b947f150da88p-4L, -0x7.24ffac24722f38fp-10332L, -0x1.56b8a9c932ce8192p-10332L, -0x1.56b8a9c932ce819p-10332L }, + { -0x4.a1dc33e9391f4958p-4L, 0xc.da35ced9d50c067p-6524L, -0x6.567e050c8546b6c8p-6524L, -0x6.567e050c8546b6cp-6524L }, + { 0x4.8ad503c066b5bb88p-4L, -0x1.3c6056edfdb7ef2ep-13072L, -0x7.20fe70074b4f73d8p-13076L, -0x7.20fe70074b4f73dp-13076L }, + { -0x2.c614d5e5bb68713cp-4L, 0xa.dfd4d1fff016deap+8040L, -0x2.fca16bfa05891708p+8040L, -0x2.fca16bfa05891704p+8040L }, + { 0x2.9652c0875ceb61c8p-4L, 0x3.d368fc20214ae89p-2724L, 0xd.3c90696ace7402fp-2728L, 0xd.3c90696ace7403p-2728L }, + { -0x3.c49bb1a332166398p-4L, 0x1.e4beaa8e0eaf876p-792L, -0xb.bcbb8fd43fa70eap-796L, -0xb.bcbb8fd43fa70e9p-796L }, + { 0x9.bf4a383f6ca4c78p-8L, 0x2.f082dcbeb993682cp+14744L, 0x2.891890b8ea5a86dcp+14740L, 0x2.891890b8ea5a86ep+14740L }, + { -0x9.7cae2a328b898f8p-8L, 0x3.89ef3c26f0876fc8p-12636L, -0x3.15b05d09ca38963cp-12640L, -0x3.15b05d09ca389638p-12640L }, + { 0x3.50d23d5945a1409p-4L, -0x2.33c93e2e43fe6d7p+8756L, -0x9.92ea36d589899d7p+8752L, -0x9.92ea36d589899d6p+8752L }, + { -0x3.4717abe0a3cf3558p-4L, 0x3.8534b1e86f26faa4p+6740L, -0x1.2a0a5aa6bbe09072p+6740L, -0x1.2a0a5aa6bbe0907p+6740L }, + { 0x3.4daf40c873d20d78p-4L, -0x7.736b651db7cbd5a8p+14396L, -0x2.04813b9537b6064p+14396L, -0x2.04813b9537b6063cp+14396L }, + { -0x2.5c070e6f3535825p-4L, 0xf.3a0b99c5b4aab25p-11840L, -0x3.813a1682912fbe2cp-11840L, -0x3.813a1682912fbe28p-11840L }, + { 0x1.57462eab133f0c7ep-104L, -0xb.c22c24524226f33p-584L, -0x1.6bf458868d45cbaap-684L, -0x1.6bf458868d45cba8p-684L }, + { -0x7.d1036a7p-16416L, 0x1.9c8928976825f972p-9340L, -0x8p-16448L, -0x0p+0L }, + { 0x4.139c9d206a49b8e8p-4L, 0x7.f8137ffd163b3ba8p-6224L, 0x2.9c02918d1a124d84p-6224L, 0x2.9c02918d1a124d88p-6224L }, + { -0x7.bf1a44aeb781fdcp-8L, 0x5.c592f47919e4e23p-11080L, -0x4.1801d2a31591ef48p-11084L, -0x4.1801d2a31591ef4p-11084L }, + { 0x1.89ac0b1dee90fcbcp-4L, -0x5.2ce714d9965b9eb8p-7004L, -0xa.f68dd40a901fabdp-7008L, -0xa.f68dd40a901fabcp-7008L }, + { -0x8.f6b1a263d7a28bbp-8L, -0x6.a8e6be614c1b8df8p-13004L, 0x5.7aab3c44fdedc898p-13008L, 0x5.7aab3c44fdedc8ap-13008L }, + { 0x2.a9b18d178ac3225p-4L, 0x5.3e11ed5dcfa44448p-8052L, 0x1.2a1266fb395796a8p-8052L, 0x1.2a1266fb395796aap-8052L }, + { -0x3.526959569dd12bf4p-4L, -0x5.9adce70a60a095a8p+5500L, 0x1.e1bc0e901384afd6p+5500L, 0x1.e1bc0e901384afd8p+5500L }, + { 0x3.6ef9b4fb7ad8d1c4p-4L, -0x3.3c5645dc55c04f94p+14756L, -0xe.853a48486c560e4p+14752L, -0xe.853a48486c560e3p+14752L }, + { -0x4.ad357dc0f71b3c18p-4L, 0x1.f1a437afbf657566p-12476L, -0xf.834b1b792328df6p-12480L, -0xf.834b1b792328df5p-12480L }, + { 0x2.dd74eb48ec7ac348p-4L, 0x1.571b76b38f6ad39p+14116L, 0x5.189ace0fd7dbc34p+14112L, 0x5.189ace0fd7dbc348p+14112L }, + { -0x7.e37552b2966c9e38p-8L, -0x3.145c1bfaf5874b28p-10368L, 0x2.3993d2134acb4a2cp-10372L, 0x2.3993d2134acb4a3p-10372L }, + { 0x3.7800dc9da42fa068p-4L, -0xe.ddd4485dc420705p+14556L, -0x4.3563bf3edbcb7518p+14556L, -0x4.3563bf3edbcb751p+14556L }, + { -0x9.fdb9cb46bb40cb6p-8L, -0x7.ec4ed7347f198e18p-4392L, 0x7.47e1bfbdff5ed83p-4396L, 0x7.47e1bfbdff5ed838p-4396L }, + { 0x1.b3312385e89ecbd4p-4L, 0x1.9a43d194ce98771ep+6932L, 0x3.bc3ea85906d8a39p+6928L, 0x3.bc3ea85906d8a394p+6928L }, + { -0x3.832741f767b3e59p-4L, -0x9.4618839acbce14p-11256L, 0x3.50e5766c6f4962ecp-11256L, 0x3.50e5766c6f4962fp-11256L }, + { 0x1.5125eee5de5358fcp-4L, -0xe.ff418d777e5efbep+11616L, -0x1.b61ebb3ae9848ea4p+11616L, -0x1.b61ebb3ae9848ea2p+11616L }, + { -0x3.13efbef15009e7c8p-4L, -0x3.fc05faf9a81f3d04p+3860L, 0x1.3a668b8af93bf2ap+3860L, 0x1.3a668b8af93bf2a2p+3860L }, + { 0x1.9510ceed893154cep-4L, 0x5.8bca7ba191d1075p+6828L, 0xc.129f0a66d0014c7p+6824L, 0xc.129f0a66d0014c8p+6824L }, + { -0x1.254279726e925594p-8L, -0x7.926da2dc2eb3e0c8p-7000L, 0xc.8ac6eb52210a585p-7008L, 0xc.8ac6eb52210a586p-7008L }, + { 0x4.5ecc0b5462ae235p-4L, 0x2.6721d566c52f5a78p+2456L, 0xd.64f286714c83778p+2452L, 0xd.64f286714c83779p+2452L }, + { -0xe.a208f1fa6e8cbdp-8L, -0x7.e11743909b3a78f8p-8876L, 0xa.b4809b9e927b678p-8880L, 0xa.b4809b9e927b679p-8880L }, + { 0x6.3dc45d2p-16416L, 0x1.9db3f0479ed959aep+11628L, 0xe.8d16a10d0f22682p-4788L, 0xe.8d16a10d0f22683p-4788L }, + { -0x1.5127dea136e65c68p-144L, 0x1.0c629491d3eb9e36p-11556L, -0x1.fdf1f80bf0ed63d8p-11700L, -0x1.fdf1f80bf0ed63d6p-11700L }, + { 0x2.5e09e9760f0d8768p-4L, 0x1.7442b66581565f6ap-7544L, 0x4.a1b2e861f70853dp-7548L, 0x4.a1b2e861f70853d8p-7548L }, + { -0x1.14d28b05df6107a4p-4L, -0xf.768d54acb3f2db4p-4996L, 0x1.8fa16bbf1e49e9e6p-4996L, 0x1.8fa16bbf1e49e9e8p-4996L }, + { 0x4.a354a165b37aa58p-4L, 0x1.e8ded63613d24c3ep-11836L, 0xb.387636549b96063p-11840L, 0xb.387636549b96064p-11840L }, + { -0x3.7f1e516e412a78dcp-4L, 0x5.d4ed544e69ab835p-13136L, -0x2.131a7bf1093fe2b8p-13136L, -0x2.131a7bf1093fe2b4p-13136L }, + { 0x3.ba0b69e7e4e2cdc8p-4L, -0x1.d273ed425e50a33p+5924L, -0x8.ce800f5bbd5a8dep+5920L, -0x8.ce800f5bbd5a8ddp+5920L }, + { -0x1.ff549a9c9f82ec1ap-4L, 0x2.fdb3fd975c2fcc24p+11236L, -0x9.34d767e53428793p+11232L, -0x9.34d767e53428792p+11232L }, + { 0x2.029bf74b014ff484p-4L, -0x2.a30dbd97704f33ap-11300L, -0x7.3428258b7189c5f8p-11304L, -0x7.3428258b7189c5fp-11304L }, + { -0x2.e1b6a811746baae4p-4L, 0xf.f88c4f246cd86a5p-5444L, -0x4.93546cd11bc8d19p-5444L, -0x4.93546cd11bc8d188p-5444L }, + { 0x4.5a3aed0d1ae13a2p-4L, -0xe.7792c29f1ca2519p-11176L, -0x5.05a0661deb318c68p-11176L, -0x5.05a0661deb318c6p-11176L }, + { -0x2.63162683080b9cbcp-4L, -0x8.bd152439e522049p+8456L, 0x2.0972b167c0230b94p+8456L, 0x2.0972b167c0230b98p+8456L }, + { 0x1.b1c8e39b79681704p-4L, 0x4.33534d4293ac9658p+4804L, 0x9.c2a816a4d7c0fe6p+4800L, 0x9.c2a816a4d7c0fe7p+4800L }, + { -0x1.7e5bc5004f62d1d6p-4L, 0x9.6fd0b86f1bc0b1p+7492L, -0x1.558cfea5c44dab0ap+7492L, -0x1.558cfea5c44dab08p+7492L }, + { 0x4.0935c6e8ba8176cp-4L, -0x2.45ae50f119d75d4cp-12464L, -0xb.cc484240eada775p-12468L, -0xb.cc484240eada774p-12468L }, + { -0x5.5a423aabc9b990ap-8L, 0x1.ffe076f2fd67cd5p+136L, -0xf.9ab02a9a0165a16p+128L, -0xf.9ab02a9a0165a15p+128L }, + { 0x1.a0a0dfe1f0a99b6p-4L, -0x2.64149f518ed134b8p+12468L, -0x5.58a2666218ac564p+12464L, -0x5.58a2666218ac5638p+12464L }, + { -0x4.65e52871cff18e08p-4L, 0x4.1bf7b256271f8f28p-14612L, -0x1.e7cc9f85102b525cp-14612L, -0x1.e7cc9f85102b525ap-14612L }, + { 0x5.b61843dfb71d1fb8p-8L, 0x3.49a93629ad7fc314p+13540L, 0x1.acac91b8860aecfap+13536L, 0x1.acac91b8860aecfcp+13536L }, + { -0x3.f52785993c70ec3p-8L, -0x3.9bc242c0137acf5cp-12472L, 0x1.4c38af5e25f74042p-12476L, 0x1.4c38af5e25f74044p-12476L }, + { 0xe.d492edc66d3e62ep-8L, -0x6.03a80cdae8d71a98p+740L, -0x7.d1728cf552ba731p+736L, -0x7.d1728cf552ba7308p+736L }, + { -0x4.670e905322dbb63p-4L, 0x1.6a9a4d57bc0ab21ap-14452L, -0xa.8581ee4fafd174fp-14456L, -0xa.8581ee4fafd174ep-14456L }, + { 0x5.74d1d9f8p-16416L, -0x5.d7c80be9da872b28p+11784L, -0x2.dfe8427ef946d498p-4628L, -0x2.dfe8427ef946d494p-4628L }, + { -0x1.ea990a7a7c9093b4p-144L, -0x1.54c1c54d508c174p+4632L, 0x3.ae1df71c96cb2fc4p+4488L, 0x3.ae1df71c96cb2fc8p+4488L }, + { 0x4.93dbf2db2ba9b988p-4L, -0xf.46327c7f85e2d9bp+10320L, -0x5.8b67deefd704f668p+10320L, -0x5.8b67deefd704f66p+10320L }, + { -0x3.8cfabd226c133e6p-4L, 0x2.ea14d6304eb12438p-14544L, -0x1.0e1644540f887aa8p-14544L, -0x1.0e1644540f887aa6p-14544L }, + { 0x1.9329c67c6c57433p-4L, -0x2.91d7f1505ba6b1p+3140L, -0x5.919562e974081818p+3136L, -0x5.919562e97408181p+3136L }, + { -0x4.a986cc606ebb7c4p-4L, 0xf.bbc8e9388c45f3ap-10816L, -0x7.d189e02359a7d8f8p-10816L, -0x7.d189e02359a7d8fp-10816L }, + { 0x1.0068bafe2db46dc8p-4L, -0xd.0ec84ab52b6bccfp+10516L, -0x1.24d293c044903b7ap+10516L, -0x1.24d293c044903b78p+10516L }, + { -0xe.b86d33c9dc908e3p-8L, 0x3.9bf2d583cd0d0d8cp-8448L, -0x4.ef0b6998a234653p-8452L, -0x4.ef0b6998a2346528p-8452L }, + { 0x2.bf26bd5a8657f64p-4L, 0x1.619579cddffcb6aep+12140L, 0x5.0d0ffca3706c2acp+12136L, 0x5.0d0ffca3706c2ac8p+12136L }, + { -0x2.26a816730ea9fa2p-4L, -0x2.1cd826493af5d3a4p+5928L, 0x7.0a714112caed041p+5924L, 0x7.0a714112caed0418p+5924L }, + { 0x1.f4ebd7a17a5e1fd4p-4L, -0x8.ca91adedeaa1e77p-14972L, -0x1.769cbd033d773138p-14972L, -0x1.769cbd033d773136p-14972L }, + { -0x4.9755a649fce3a72p-4L, 0x1.9ffbbc6c991dce28p+2304L, -0xc.af74ccc1edf3feep+2300L, -0xc.af74ccc1edf3fedp+2300L }, + { 0x2.03c9c35825e8cce8p-4L, -0x4.c58df0c00390e39p+14776L, -0xd.1055487d9d10608p+14772L, -0xd.1055487d9d10607p+14772L }, + { -0x1.4a829868b2d07d8ap-4L, 0x6.ec9b9c24e5dad6d8p-6360L, -0xd.727e7114ad2833ep-6364L, -0xd.727e7114ad2833dp-6364L }, + { 0x2.e638feebcca21c28p-4L, 0x1.5555753a1fdc2362p-5456L, 0x5.202652e78b04ba6p-5460L, 0x5.202652e78b04ba68p-5460L }, + { -0x9.979149647a1982ap-8L, 0x1.1f233b6d8f73e8ccp+1520L, -0xf.d1e2d416d88a874p+1512L, -0xf.d1e2d416d88a873p+1512L }, + { 0x7.c696d728e20f0848p-8L, -0x1.5ef60b9d2b73390ap+11924L, -0xf.267aeee72356083p+11916L, -0xf.267aeee72356082p+11916L }, + { -0x4.05c95bb140d74508p-8L, -0x1.ed7fe53fd80fb15ap-13268L, 0xb.46b5e70ab7dc4a7p-13276L, 0xb.46b5e70ab7dc4a8p-13276L }, + { 0x1.2102593d8b22e7bep-4L, -0xd.0f4dc08b32e489ap-10512L, -0x1.48dc788829e9e252p-10512L, -0x1.48dc788829e9e25p-10512L }, + { -0x9.453822cef91e918p-8L, 0x4.86ba6e2b530b797p-4708L, -0x3.da8c9cccd9d956bp-4712L, -0x3.da8c9cccd9d956acp-4712L }, + { 0x1.12f7b7ecee83bc12p-4L, 0x3.6d9e8e1a109a2ec8p-13472L, 0x5.243f0c6c55752578p-13476L, 0x5.243f0c6c5575258p-13476L }, + { -0x2.777e0c0a02694fd4p-4L, 0x3.08ae8e74c266a098p-956L, -0xb.b9e9452b01c070cp-960L, -0xb.b9e9452b01c070bp-960L }, + { 0x6.ed708598p-16416L, -0xf.89d9753e770635ep+11952L, -0x9.b4bb0cc1c6d23bep-4460L, -0x9.b4bb0cc1c6d23bdp-4460L }, + { -0x1.3ab2fe378fa08002p-52L, -0x3.faaa35d0c21a25p-132L, 0x7.0e99197749af91cp-184L, 0x7.0e99197749af91c8p-184L }, + { 0x2.075c4fded02a10dp-4L, -0x1.5c155893f7056016p+13476L, -0x3.bf317f30aab92a88p+13472L, -0x3.bf317f30aab92a84p+13472L }, + { -0x3.5dd7c365c8f83704p-4L, 0xa.1cb34dbd6cd395fp+11084L, -0x3.724bd3f3733cf154p+11084L, -0x3.724bd3f3733cf15p+11084L }, + { 0x4.47f11be2f8a972c8p-4L, -0x1.736a1fc6a5a78362p+7336L, -0x7.f0ba632851590e18p+7332L, -0x7.f0ba632851590e1p+7332L }, + { -0x2.9823a4b955403824p-4L, -0x1.b699f56c55fc52a4p+216L, 0x6.ff120dac9ded8abp+212L, 0x6.ff120dac9ded8ab8p+212L }, + { 0x4.1a23ac74ce37c868p-4L, -0x1.857b2ba5a176f0aap-11308L, -0x8.03f0f38f6e53751p-11312L, -0x8.03f0f38f6e5375p-11312L }, + { -0xa.1f42d577650c9adp-8L, 0x2.c4758147ef57417cp+13012L, -0x2.93bcd7ecd68feaa8p+13008L, -0x2.93bcd7ecd68feaa4p+13008L }, + { 0x1.84b9cdd00271f558p-4L, 0x1.3a2fc03e0387d0bcp-14720L, 0x2.918ccc5362c1ca84p-14724L, 0x2.918ccc5362c1ca88p-14724L }, + { -0x2.73a88be3087e5338p-4L, 0xe.bc8d2b7772f396p-2136L, -0x3.894c4ef8b23ccf6p-2136L, -0x3.894c4ef8b23ccf5cp-2136L }, + { 0x1.17e8c62b745eff6ap-4L, -0x4.017bb7f9858a1c18p+12L, -0x6.1cc20f6aafe3d05p+8L, -0x6.1cc20f6aafe3d048p+8L }, + { -0x1.08a6904e103c8a42p-4L, 0x4.245b3e4558ce84e8p+6880L, -0x6.62de455bb063efc8p+6876L, -0x6.62de455bb063efcp+6876L }, + { 0x9.3c659a1e94df67fp-8L, -0x3.2b939ab516941194p+14296L, -0x2.97f72ef04ae09db8p+14292L, -0x2.97f72ef04ae09db4p+14292L }, + { -0x2.b761508254c49454p-4L, 0xc.e0c6bc3b7739bb7p-4252L, -0x3.74e9fc4c3e6a1f4cp-4252L, -0x3.74e9fc4c3e6a1f48p-4252L }, + { 0x1.55e43d50aa1de912p-4L, 0x5.13ab96c153d35eb8p-11768L, 0x9.65173e148f5a0ap-11772L, 0x9.65173e148f5a0a1p-11772L }, + { -0xf.543ac800941658ep-8L, -0x6.20199bbcb0f17f4p+5288L, 0x8.bb05c1a6d35f348p+5284L, 0x8.bb05c1a6d35f349p+5284L }, + { 0x3.56f9ca36fbdfa67p-4L, 0x1.d50869ea25276784p-8844L, 0x8.04776fbae54cc54p-8848L, 0x8.04776fbae54cc55p-8848L }, + { -0x2.d2b77bbab795dc74p-4L, -0x2.7faeedff97b59518p-8980L, 0xb.326b17219f8d2c7p-8984L, 0xb.326b17219f8d2c8p-8984L }, + { 0x3.3b96a64d429b4d74p-4L, -0x2.9d9c43b7825d326p+12716L, -0xb.1c721c34cbaf487p+12712L, -0xb.1c721c34cbaf486p+12712L }, + { -0xc.8d12f03af1ad8dp-8L, 0x1.1f16f03ddddac2b2p+2568L, -0x1.4d231dfe98d4ceacp+2564L, -0x1.4d231dfe98d4ceaap+2564L }, + { 0x3.8f9ba551c055efep-4L, -0x4.bdce2365684786f8p+11256L, -0x1.5fe3aa07b1e38e1p+11256L, -0x1.5fe3aa07b1e38e0ep+11256L }, + { -0x2.fd0968609dfabf38p-4L, -0x3.9f3872fe7a19d514p-7100L, 0x1.149160a36b1937d4p-7100L, 0x1.149160a36b1937d6p-7100L }, + { 0x3.a1bc97534cf86254p-120L, 0xe.078e9669dcc8821p-3916L, 0x4.9822a91bbcaa6d3p-4032L, 0x4.9822a91bbcaa6d38p-4032L }, + { -0x9.0e702a7e143108fp-164L, -0x4.f196f6e23fedaebp+3012L, 0x4.097b774bec74e7bp+2852L, 0x4.097b774bec74e7b8p+2852L }, + { 0x2.a7f9d0e587d0031cp-4L, -0x1.7df0e27c0ccf76bcp+372L, -0x5.4a1628b2dfeb3de8p+368L, -0x5.4a1628b2dfeb3dep+368L }, + { -0x1.98c8703e63e3b9f4p-4L, -0x7.c403891453f18a28p-10492L, 0x1.2d8c742191748b96p-10492L, 0x1.2d8c742191748b98p-10492L }, + { 0x2.7f9a121a213dffe8p-4L, 0x1.60a510438baeb314p+13976L, 0x4.9d1e27c49a25cffp+13972L, 0x4.9d1e27c49a25cff8p+13972L }, + { -0x3.883ffac36198bb74p-4L, 0x1.ba64610e5fc1c95p+2376L, -0x9.f33e8f6c9f253b3p+2372L, -0x9.f33e8f6c9f253b2p+2372L }, + { 0x1.b65b0807a6b7ed1ap-4L, -0xd.a336acdf6754e5bp+7972L, -0x2.0018f97311be95d4p+7972L, -0x2.0018f97311be95dp+7972L }, + { -0x1.e1d113619cb17674p-4L, -0xc.c9f8ff221cab8ddp-2844L, 0x2.4f1a50a2821f20b4p-2844L, 0x2.4f1a50a2821f20b8p-2844L }, + { 0x2.914e861be45c55e8p-8L, 0x1.55c48d407375e2cap-2168L, 0x4.ebb18aef8402f5c8p-2176L, 0x4.ebb18aef8402f5dp-2176L }, + { -0x2.f5709c93a8a0a9dp-4L, 0x7.b9cef07eaf4eed7p-4876L, -0x2.476edf2184857d34p-4876L, -0x2.476edf2184857d3p-4876L }, + { 0x3.648cf748ec9e27f8p-4L, 0x3.1423bae5f0affdccp-12004L, 0xd.aaad3e8f8eb0b16p-12008L, 0xd.aaad3e8f8eb0b17p-12008L }, + { -0x3.61791f35cba8863p-4L, -0x8.74595f3c5c6cb4dp-1688L, 0x2.e52c5807e549f5dcp-1688L, 0x2.e52c5807e549f5ep-1688L }, + { 0x1.b82710349d66924cp-4L, 0x7.e61a34168ab5f008p-8164L, 0x1.29c2f5adf7458efp-8164L, 0x1.29c2f5adf7458ef2p-8164L }, + { -0x3.4d11e5ccd6ac7cap-4L, -0x3.9a82f3943aa5a188p-9436L, 0x1.3388089c3b0d5588p-9436L, 0x1.3388089c3b0d558ap-9436L }, + { 0x4.9428b7da62c702b8p-4L, 0xd.1467d75f56bcf5ep-11520L, 0x4.bfbff268e075cc18p-11520L, 0x4.bfbff268e075cc2p-11520L }, + { -0x2.6b566d5498306d08p-4L, -0x3.ccde3d308a22eb5cp+10760L, 0xe.6187fe1b7bad52ap+10756L, 0xe.6187fe1b7bad52bp+10756L }, + { 0xf.c0bf63c433c05f9p-8L, 0x2.492819446118a574p+1964L, 0x3.26989997ddb6f92cp+1960L, 0x3.26989997ddb6f93p+1960L }, + { -0x3.6892bbb36e176cecp-4L, 0xf.d741a00abd03d2p-4572L, -0x5.799464669eee8fp-4572L, -0x5.799464669eee8ef8p-4572L }, + { 0x2.3ccc852342a3e2ep-4L, -0x1.092e784e29e30784p-14964L, -0x3.21364368eb287a8p-14968L, -0x3.21364368eb287a7cp-14968L }, + { -0x3.dabe1d3a5400a66cp-4L, 0x3.819f5f8d05fa313p+14716L, -0x1.64ef8bbed09c8112p+14716L, -0x1.64ef8bbed09c811p+14716L }, + { 0x2.6c673a145214ba98p-4L, -0xf.03aefac3e377757p-14792L, -0x3.0e1458d47bc4cb5cp-14792L, -0x3.0e1458d47bc4cb58p-14792L }, + { -0x4.0e4a540e71cc0288p-8L, 0x2.2419fb7ebbf4a7d8p-1068L, -0xc.a0ca66c14def27p-1076L, -0xc.a0ca66c14def26fp-1076L }, + { 0x4.dd8f85c8p-16416L, -0xf.980d0cd19d231dp+11088L, -0x6.d75c47eef8bbfbap-5324L, -0x6.d75c47eef8bbfb98p-5324L }, + { -0x7.f51abd665f9bee8p-36L, 0x1.dcd6e7960fd2d35cp-6200L, -0x1.562314b0db6f2412p-6232L, -0x1.562314b0db6f241p-6232L }, + { 0x2.3cac744f1052e66p-4L, 0x2.62280853a9ba5768p+8628L, 0x7.3321a245f69bf7ap+8624L, 0x7.3321a245f69bf7a8p+8624L }, + { -0x3.3f453518bf958f1p-4L, -0x1.8abf11344317fd2ep+5524L, 0x8.12e7dcb9203daf8p+5520L, 0x8.12e7dcb9203daf9p+5520L }, + { 0x4.a37a0a2e94817af8p-4L, 0x3.31608177e97de46p+4688L, 0x1.2c3317257700dc6cp+4688L, 0x1.2c3317257700dc6ep+4688L }, + { -0x2.759bed88d3ee0a9cp-4L, -0x1.23025455b6bb4b3cp-3840L, 0x4.611cf16d993dc978p-3844L, 0x4.611cf16d993dc98p-3844L }, + { 0x2.b2f4298813acd09p-4L, -0x1.5260cf8ab304676ep+12932L, -0x4.c193d858e5159aa8p+12928L, -0x4.c193d858e5159aap+12928L }, + { -0x3.02ab01e994f9301p-4L, -0x2.05a8427f1a2184bp-10208L, 0x9.bab237364385aefp-10212L, 0x9.bab237364385afp-10212L }, + { 0x3.9dd2497df6505db8p-4L, -0x5.ef9d56c6ff28bfdp+6132L, -0x1.bec25594dc09e1c2p+6132L, -0x1.bec25594dc09e1cp+6132L }, + { -0x3.1f36e2acdac799cp-4L, 0x1.fe0c5686cbb69ae8p+2348L, -0x9.fb9770501834541p+2344L, -0x9.fb977050183454p+2344L }, + { 0x3.f9f38bcacc608ea4p-4L, -0xc.a975585bddf812bp-13688L, -0x4.0dfd1663aa583348p-13688L, -0x4.0dfd1663aa58334p-13688L }, + { -0x1.e46e7b9f1fb532bep-4L, -0x2.bcb39ddfe1c68248p-9104L, 0x7.f3d951935813894p-9108L, 0x7.f3d9519358138948p-9108L }, + { 0x9.4556c7b62d8c8cfp-8L, -0x1.0eeffe20e57f824ap-6140L, -0xd.e7b819b422e8faep-6148L, -0xd.e7b819b422e8fadp-6148L }, + { -0x3.8ca02be25fde5288p-4L, -0x2.815db6eb9885e86p+11972L, 0xe.81398e978d87862p+11968L, 0xe.81398e978d87863p+11968L }, + { 0x2.98b2b17e1c13daccp-4L, -0x5.d0c98aabaedb1fbp+9108L, -0x1.4300e03ac130142cp+9108L, -0x1.4300e03ac130142ap+9108L }, + { -0x1.b53661215c292a9ap-4L, 0xc.ea5c116014da9b3p-1576L, -0x2.1a70dbc7c639fd2cp-1576L, -0x2.1a70dbc7c639fd28p-1576L }, + { 0x3.a9585cd202a6d0c4p-4L, 0xc.13d12aa5f2fb35ap+5048L, 0x3.9733ed35d1e948b4p+5048L, 0x3.9733ed35d1e948b8p+5048L }, + { -0x2.7e3ce1ae5b5d40fp-12L, -0x1.6ac3d1cdbddd70c6p+6624L, 0x5.19314cff3a227e4p+6612L, 0x5.19314cff3a227e48p+6612L }, + { 0x3.7200d9155209c2acp-4L, -0x1.a45b5a228d4622ep-3568L, -0x7.6449cd5931a2d96p-3572L, -0x7.6449cd5931a2d958p-3572L }, + { -0x1.a1a30e0fbfd17eb4p-4L, 0x8.8af95da1e0b1a78p+4272L, -0x1.535022cb1f7efafcp+4272L, -0x1.535022cb1f7efafap+4272L }, + { 0x2.33bf12728763519cp-4L, 0x2.6686b8dba75ea304p-2056L, 0x7.252e6bd693f1342p-2060L, 0x7.252e6bd693f13428p-2060L }, + { -0xc.90d32e60a9fdbc3p-8L, 0x3.62ff10781a5bdf74p-4852L, -0x3.ef43238141c37684p-4856L, -0x3.ef43238141c3768p-4856L }, + { 0x7.5625c9523f78c92p-152L, 0x6.33a7de5685f56b88p+2796L, 0x4.1a44ed3d49f37aep+2648L, 0x4.1a44ed3d49f37ae8p+2648L }, + { -0x1.0ac1f2f8p-16416L, 0x1.02a1bda3565bc8fap-3500L, -0x8p-16448L, -0x0p+0L }, + { 0x2.f11c7fc4f146158cp-4L, -0x1.77606bad7e693d04p+2548L, -0x5.b67ed1c0247fe558p+2544L, -0x5.b67ed1c0247fe55p+2544L }, + { -0x1.e932f553a0ce9d4p-4L, -0x1.c28b03b6522311d4p+5524L, 0x5.2ac3ccf307a22a88p+5520L, 0x5.2ac3ccf307a22a9p+5520L }, + { 0x2.28ebcd228b766488p-4L, 0x9.8ddc34fd380f7cdp+14008L, 0x1.becf6f24b98f4aap+14008L, 0x1.becf6f24b98f4aa2p+14008L }, + { -0x2.05aa67d0e7893ffp-8L, 0xa.a847a961d00df0ap+12556L, -0x1.f36dd414d6b2b91ep+12552L, -0x1.f36dd414d6b2b91cp+12552L }, + { 0x8.61b6b3ddab95935p-8L, 0x3.4f402dd17b106c64p-1012L, 0x2.761010bf33f5993cp-1016L, 0x2.761010bf33f5994p-1016L }, + { -0x1.9b432de297579e68p-4L, 0x3.5fa4d9a9fc21151cp+12192L, -0x8.3d6ac109bb4c2a7p+12188L, -0x8.3d6ac109bb4c2a6p+12188L }, + { 0x1.f2c45be62dde2318p-4L, -0xa.5a267aef528216ep+2032L, -0x1.b754d0e25e0a58dap+2032L, -0x1.b754d0e25e0a58d8p+2032L }, + { -0xe.c7886d486b1423bp-8L, -0x5.f0ff7cfd1f4b93d8p+11376L, 0x8.27cda2dd6d26dp+11372L, 0x8.27cda2dd6d26d01p+11372L }, + { 0x2.f148d81ff59e6c9cp-4L, 0x1.c09e468785b5c354p-7792L, 0x6.d43859f4941b858p-7796L, 0x6.d43859f4941b8588p-7796L }, + { -0x4.a7fa8456a5738f48p-4L, 0xb.8cf756c51b10491p-12304L, -0x5.bb23984d4ca08e1p-12304L, -0x5.bb23984d4ca08e08p-12304L }, + { 0x2.b29a39d96a13c414p-4L, 0x5.04f17d6142a2ec78p-4464L, 0x1.20d66e21c7406f52p-4464L, 0x1.20d66e21c7406f54p-4464L }, + { -0x3.77d74e76e2309764p-4L, -0x1.c3e2606dd5d09a4ep+9832L, 0x9.f4693dade8d5703p+9828L, 0x9.f4693dade8d5704p+9828L }, + { 0x4.09e8d44c0a9dec4p-8L, -0x3.f98c983119717b98p+5448L, -0x1.6fa98b37837c778ep+5444L, -0x1.6fa98b37837c778cp+5444L }, + { -0x4.863fe515ba68863p-4L, 0x2.44a0fe29d471fe0cp+6924L, -0x1.1669eef8591793ep+6924L, -0x1.1669eef8591793dep+6924L }, + { 0x2.4d7dfb360ed7fc04p-4L, -0x4.f0d30f06332ddp-12644L, -0xf.55b574e4f66676dp-12648L, -0xf.55b574e4f66676cp-12648L }, + { -0x2.321867445cc97e58p-4L, 0x2.9f2b2d00894a5d88p+4876L, -0x8.eed56b3be3be27p+4872L, -0x8.eed56b3be3be26fp+4872L }, + { 0x1.0f1653c21d88f58p-4L, 0x7.1d5b99213d03b6e8p+8576L, 0xa.8651050e953498ap+8572L, 0xa.8651050e953498bp+8572L }, + { -0x2.8cc781990c3e3904p-8L, 0x1.a7d261806a6e3d7ap+11852L, -0x6.1ef42f9c5224235p+11844L, -0x6.1ef42f9c52242348p+11844L }, + { 0x2.048284a37fa5629cp-4L, -0x3.94e24b6aa1db9f44p-8368L, -0x9.d187169aa9e30fdp-8372L, -0x9.d187169aa9e30fcp-8372L }, + { -0x2.7270920cc658bdfcp-4L, 0x2.2e30b685d8bcaea4p-2292L, -0x8.5aa759a252e70d6p-2296L, -0x8.5aa759a252e70d5p-2296L }, + { 0x5.dfbf765p-16416L, 0x1.75ea58cb0a2a111cp+1256L, 0xc.60b6aa985c7126p-15160L, 0xc.60b6aa985c71261p-15160L }, + { -0xe.1d7e71fee6192bap-40L, 0x9.4f89ff3200affa3p-10532L, -0xb.d9a41b81a0ded4cp-10568L, -0xb.d9a41b81a0ded4bp-10568L }, + { 0x4.56aa4f6cc88118d8p-4L, -0x3.f63ba994a2b78004p+10588L, -0x1.5f1214fe4a6577a8p+10588L, -0x1.5f1214fe4a6577a6p+10588L }, + { -0x6.4b399c5d6f79c53p-8L, 0x5.20a0673897bdb3p-7740L, -0x2.f23beac70fa873bp-7744L, -0x2.f23beac70fa873acp-7744L }, + { 0x3.1e0ea75bc7ed36ccp-4L, 0x8.e27b579a17f1c4dp-8756L, 0x2.481f238e55239f44p-8756L, 0x2.481f238e55239f48p-8756L }, + { -0x3.f633c649d5060228p-4L, 0x5.d72f16fe681c1abp-3536L, -0x2.65b046536bfbeb0cp-3536L, -0x2.65b046536bfbeb08p-3536L }, + { 0x2.d5c982b9a0bb948p-4L, 0x2.a22fd9997a52536cp-1444L, 0x9.eabe16ba330ce96p-1448L, 0x9.eabe16ba330ce97p-1448L }, + { -0x3.2a5af82e25817eecp-4L, 0x2.7171b5c5ce8e77acp-12700L, -0xc.6ea7205da7d336ep-12704L, -0xc.6ea7205da7d336dp-12704L }, + { 0x1.0fb5e02c9615884p-4L, -0x4.3cbd69afe18488ap+14960L, -0x6.4837d3bd5446182p+14956L, -0x6.4837d3bd54461818p+14956L }, + { -0x2.ebb14b0f25d3d54cp-4L, -0x3.f0fb7afa6ec2cfb8p+32L, 0x1.256547ff3538326ap+32L, 0x1.256547ff3538326cp+32L }, + { 0xa.4b37ca400e3e139p-8L, -0x2.2bd7a614add96564p-2988L, -0x1.f9d15a8fce18accp-2992L, -0x1.f9d15a8fce18acbep-2992L }, + { -0x1.9dfb38f66e6ce44ap-4L, 0x1.410266a44f4ade2cp+14432L, -0x3.1585cfd6c0bc80c4p+14428L, -0x3.1585cfd6c0bc80cp+14428L }, + { 0xc.89886ba4ab470fap-8L, 0x2.4d20ce827eba1d5cp-6572L, 0x2.8a31828e7806188cp-6576L, 0x2.8a31828e7806189p-6576L }, + { -0x2.cf1bd2db6eece3bp-4L, -0x9.81d66bb4eea5f5dp+8664L, 0x2.a5df5372cf8ee82p+8664L, 0x2.a5df5372cf8ee824p+8664L }, + { 0x3.d52f7205e2265278p-4L, -0x5.8137ad906185b418p-4344L, -0x1.b4981d0839394732p-4344L, -0x1.b4981d083939473p-4344L }, + { -0x4.068ea746952344c8p-4L, -0x3.bc6a67b96be7c0ecp-1508L, 0x1.8fe5914831f7a6f8p-1508L, 0x1.8fe5914831f7a6fap-1508L }, + { 0x2.4a7156c47e3c5cfp-4L, 0x7.a3b09d22470dbdbp+13304L, 0x1.798992cc1888896ep+13304L, 0x1.798992cc1888897p+13304L }, + { -0x2.27f0bcaf31f43d84p-4L, -0x2.52eaea727fb51b3cp-2292L, 0x7.c39f824994a1ee3p-2296L, 0x7.c39f824994a1ee38p-2296L }, + { 0x7.714aee9717d46d38p-8L, 0x1.1e6c22f27b1bf57ap+5028L, 0xb.d78e0ad132d5ff6p+5020L, 0xb.d78e0ad132d5ff7p+5020L }, + { -0x3.87ec179e6586821p-4L, 0x9.4b4c59fac13b018p+1888L, -0x3.57e18719fdcf879cp+1888L, -0x3.57e18719fdcf8798p+1888L }, + { 0x3.3d30b32379a65114p-4L, 0x4.c5d29adfdda9ea18p+4440L, 0x1.44f5e4b2409b9124p+4440L, 0x1.44f5e4b2409b9126p+4440L }, + { -0x2.e2bda144c2f2277p-4L, 0x5.64267b2495b7c128p-1996L, -0x1.8c024b9431e50014p-1996L, -0x1.8c024b9431e50012p-1996L }, + { 0x4.9de5e3de07d9f6c8p-68L, 0x9.e7a6b488ba25371p-10492L, 0x4.1f9017df12388bb8p-10556L, 0x4.1f9017df12388bcp-10556L }, + { -0x7.eeb8e528p-16416L, -0x7.bd9dbdb1739d2078p+4548L, 0x5.895fe80806e16bf8p-11864L, 0x5.895fe80806e16cp-11864L }, + { 0x2.8c83c5564b76a9ap-4L, 0x1.952d401223808022p+7108L, 0x5.66882b0ad5c27dep+7104L, 0x5.66882b0ad5c27de8p+7104L }, + { -0x2.4d42d236c3d3fd98p-4L, -0x1.ab5e5d1fb46d837cp-4360L, 0x5.fc465dcd2d8a37ep-4364L, 0x5.fc465dcd2d8a37e8p-4364L }, + { 0x4.6ae6b426dff3a728p-4L, -0x1.18b02e8036eaf6fp-2520L, -0x6.2bab4a04d616aaf8p-2524L, -0x6.2bab4a04d616aafp-2524L }, + { -0x2.3a083ce38aa2c904p-8L, -0x3.4db11e32b03da7ep-11912L, 0xa.a89c94dda8a851ap-11920L, 0xa.a89c94dda8a851bp-11920L }, + { 0x2.9ec8fd0020cc084p-4L, 0x1.3dcad9832e8f1d88p+12852L, 0x4.58883200d1e122cp+12848L, 0x4.58883200d1e122c8p+12848L }, + { -0x8.afe56fd65488476p-12L, -0x6.be0fd3b8186a0038p-7268L, 0x5.49768b31e35bebp-7276L, 0x5.49768b31e35beb08p-7276L }, + { 0x2.c9937a12a36f69e4p-4L, 0x2.84f3d72672642d5cp+2680L, 0x9.56e8000300c7c24p+2676L, 0x9.56e8000300c7c25p+2676L }, + { -0x3.6f1d5c73cafd067cp-4L, 0x4.59cae1c34a6ae298p+3720L, -0x1.8436b71ec7d37d58p+3720L, -0x1.8436b71ec7d37d56p+3720L }, + { 0x3.4d8e31567ec04358p-4L, 0xb.15e67692e908166p+728L, 0x3.005c2fd462395254p+728L, 0x3.005c2fd462395258p+728L }, + { -0x2.6fd4b22406dd3548p-4L, -0x5.32ae39061f42ebfp-3816L, 0x1.3d34a2d69fb46afap-3816L, 0x1.3d34a2d69fb46afcp-3816L }, + { 0x3.a481c0c1bd38eeccp-4L, 0x1.31f75b812f26c6fp-4144L, 0x5.a8a308f4e33ea0bp-4148L, 0x5.a8a308f4e33ea0b8p-4148L }, + { -0x2.74946e84015b7904p-4L, -0xe.ef2009edfa62e1p-7280L, 0x3.96e65616243fb15p-7280L, 0x3.96e65616243fb154p-7280L }, + { 0x4.6bc95d66b99cb698p-4L, 0x6.ec530160d23ac0ap+9560L, 0x2.6fd4a9c6a61334b8p+9560L, 0x2.6fd4a9c6a61334bcp+9560L }, + { -0x2.af79152508966b7p-4L, -0x3.033c0f9587a37dacp+9720L, 0xc.c6dd7b7b703686cp+9716L, 0xc.c6dd7b7b703686dp+9716L }, + { 0x4.12d04be0b70108dp-4L, 0x1.026134c613738e1p+832L, 0x5.48c0269f3bdf4c58p+828L, 0x5.48c0269f3bdf4c6p+828L }, + { -0x1.c5ad26059c8173c6p-4L, -0x1.902f5e5d3170116ep-600L, 0x4.3c6233f83fc19d08p-604L, 0x4.3c6233f83fc19d1p-604L }, + { 0x2.dccc064c67226e14p-4L, 0x6.2cbe80578c0dfd4p+3320L, 0x1.77583ce754d1405ep+3320L, 0x1.77583ce754d1406p+3320L }, + { -0x3.3fa98ff5a2971bfcp-4L, -0x8.b7bd8b1ef0ee6b8p+2360L, 0x2.daba824595904f3p+2360L, 0x2.daba824595904f34p+2360L }, + { 0x1.d8602eb4d94e28ecp-4L, -0x2.bae59a7e7af9a67cp+3584L, -0x6.e0d5db7658c5c028p+3580L, -0x6.e0d5db7658c5c02p+3580L }, + { -0x3.6c3a213e7b4881bp-4L, 0x5.494bb22b56f01408p+10044L, -0x1.d5f0eafdebb7153ep+10044L, -0x1.d5f0eafdebb7153cp+10044L }, + { 0x1.93f52cf9da54bfd2p-188L, 0x6.7a10e84122b54878p+13800L, 0xe.be9ca7b0c77d0b6p+13612L, 0xe.be9ca7b0c77d0b7p+13612L }, + { -0x4.58f5e4ap-16416L, -0x1.fe7de6b1cc44106ep+8880L, 0xc.81dd9ac770a9c4dp-7536L, 0xc.81dd9ac770a9c4ep-7536L }, + { 0x5.27c48a1ec2d6863p-8L, 0x2.977a191025cba5c4p+5568L, 0x1.315a3386fa9d6726p+5564L, 0x1.315a3386fa9d6728p+5564L }, + { -0x2.eb002870df40a93p-4L, -0x5.08c29ee62ab9a4c8p+692L, 0x1.765dc5a976721a6ap+692L, 0x1.765dc5a976721a6cp+692L }, + { 0x2.35b97b8a544150a4p-4L, -0x1.876176fc24a19868p-12496L, -0x4.90cea080288cc9c8p-12500L, -0x4.90cea080288cc9cp-12500L }, + { -0x4.20fe502368675c3p-4L, 0x2.89b504f1eeca05ep+14364L, -0x1.17c6332d638442ecp+14364L, -0x1.17c6332d638442eap+14364L }, + { 0x1.3507193d9fcdf874p-8L, -0x4.44ed38babbc1a31p-6140L, -0x7.6ae54c90c135363p-6148L, -0x7.6ae54c90c1353628p-6148L }, + { -0x4.9c77377231cc5c68p-4L, 0x3.0df98b1b24a9fd5p+8788L, -0x1.7f86156db3450b48p+8788L, -0x1.7f86156db3450b46p+8788L }, + { 0x4.6bfb936cb1cc028p-4L, 0x1.a2b46ba8847fdacap+12288L, 0x9.36677b413811f5ap+12284L, 0x9.36677b413811f5bp+12284L }, + { -0x7.fe3a8eade3847d6p-8L, -0x1.2e4dc4b59c87951ep-5840L, 0xd.d59f3e0866526ffp-5848L, 0xd.d59f3e0866527p-5848L }, + { 0x3.bd32a8458d6aa984p-4L, 0xf.95ff672171f9ce3p-5912L, 0x4.b8e4b10ffb79ebfp-5912L, 0x4.b8e4b10ffb79ebf8p-5912L }, + { -0xf.68a5c2a7fb327c8p-8L, -0xd.06212bca315272ap+7596L, 0x1.2a9aa0cc67647bc4p+7596L, 0x1.2a9aa0cc67647bc6p+7596L }, + { 0x2.d63c10403cb6b6ep-4L, 0x8.9e2a941dc61ad8fp+14140L, 0x2.078585b0204e1778p+14140L, 0x2.078585b0204e177cp+14140L }, + { -0x2.6b6b837e7eb6ae64p-4L, 0x4.23ab68b527c43a3p+2648L, -0xf.aa95c9793bf78dfp+2644L, -0xf.aa95c9793bf78dep+2644L }, + { 0x3.91cf23ec265a44bcp-4L, -0x4.bc960cdc39b32268p-9416L, -0x1.604dfff2b63b8282p-9416L, -0x1.604dfff2b63b828p-9416L }, + { -0x2.bc4062eed81cc3acp-4L, -0x1.fa0727fe515c697ap-11556L, 0x8.8df9fc101ed9003p-11560L, 0x8.8df9fc101ed9004p-11560L }, + { 0x2.b0fa1e0dd7f558a4p-4L, 0x5.8280a606a48f5318p+10272L, 0x1.3c5ed74d77afe5a6p+10272L, 0x1.3c5ed74d77afe5a8p+10272L }, + { -0x3.d2579cb3ff0ee9f8p-4L, -0x8.0b945d741ecd16ap-1048L, 0x3.2af74742433897ap-1048L, 0x3.2af74742433897a4p-1048L }, + { 0x3.c535c7bd86beae28p-4L, -0xf.2f9fb8404b10c06p+10324L, -0x4.a2c30bd72da67518p+10324L, -0x4.a2c30bd72da6751p+10324L }, + { -0x2.dff8fb970f266844p-4L, -0x3.74fd4274bff9725cp-1160L, 0xf.ce11601a35fdcdbp-1164L, 0xf.ce11601a35fdcdcp-1164L }, + { 0x1.4b5ff1e4dc2e3c8ap-4L, 0xd.153b5302441b7e9p-1056L, 0x1.77e756dd04bced5ep-1056L, 0x1.77e756dd04bced6p-1056L }, + { -0x2.2377af118d3b64d8p-4L, 0x1.4bd65cdbcd0ba822p+11900L, -0x4.4b025c7b23622dc8p+11896L, -0x4.4b025c7b23622dcp+11896L }, + { 0x6.95a6923d8b1019fp-48L, -0xe.509d14cf004cbe5p+2568L, -0x8.7fc1c0221d2a71cp+2524L, -0x8.7fc1c0221d2a71bp+2524L }, + { -0x6.35b4505c73bc73f8p-148L, -0x2.beb5ae276a22e078p-11460L, 0x1.897739142f742bcap-11604L, 0x1.897739142f742bccp-11604L }, + { 0x1.c09464de3920faa2p-4L, -0xe.76812b4dfc9816p-1364L, -0x2.2b1eea208c44b79p-1364L, -0x2.2b1eea208c44b78cp-1364L }, + { -0x4.62afbcd5d3fdceap-4L, 0x4.7c65d956f633426p+10856L, -0x2.12b9ade27f17cfep+10856L, -0x2.12b9ade27f17cfdcp+10856L }, + { 0x1.1eb7165174c4df74p-4L, 0x5.dd67d7554c7a8508p+13252L, 0x9.28d0f9cf98b2726p+13248L, 0x9.28d0f9cf98b2727p+13248L }, + { -0x6.1647cb705094df4p-8L, 0x5.ec80442e2871996p+2424L, -0x3.4a663d160a45da88p+2420L, -0x3.4a663d160a45da84p+2420L }, + { 0x4.8cdb06d2fa8dce68p-4L, -0x1.0734bf21712e7332p-4704L, -0x5.f09f4db0c1add98p-4708L, -0x5.f09f4db0c1add978p-4708L }, + { -0xe.c1625ff5573e525p-8L, 0x3.486cd98536b2738cp-1708L, -0x4.7fae5c446047168p-1712L, -0x4.7fae5c4460471678p-1712L }, + { 0x1.87006f5c5d2ec9eap-4L, -0x8.9ee3d43da2c297ep+9552L, -0x1.22491738b797491ap+9552L, -0x1.22491738b7974918p+9552L }, + { -0x3.3dfd025c24acda3p-4L, -0x8.400dba5a97204e1p-10880L, 0x2.b1fa547bf7acaf78p-10880L, 0x2.b1fa547bf7acaf7cp-10880L }, + { 0x2.5d1332c90ae9c9a4p-4L, -0x1.d15f57eac86808e4p-11748L, -0x5.c81202070960b9d8p-11752L, -0x5.c81202070960b9dp-11752L }, + { -0x2.28cec5c3aa2d0f18p-4L, -0x4.b7f858c41748a67p+9068L, 0xf.caa8d0ecd255b6ep+9064L, 0xf.caa8d0ecd255b6fp+9064L }, + { 0x2.67ce16bc94144a94p-4L, 0x9.ad9bf6e1a2ade89p-1124L, 0x1.f4a2cdc76f7d181p-1124L, 0x1.f4a2cdc76f7d1812p-1124L }, + { -0xe.f6744817cecdd4ep-8L, 0x5.ce4c9a5a4bd4f098p+7716L, -0x8.124097d64be7bd8p+7712L, -0x8.124097d64be7bd7p+7712L }, + { 0x3.22f0bacfe12728f8p-4L, -0x4.d9d086aa5d561098p+9364L, -0x1.40b41e628d5e3048p+9364L, -0x1.40b41e628d5e3046p+9364L }, + { -0x3.a65ad31a6788a01cp-4L, 0x2.2153a3d97331573cp-1800L, -0xc.bb3936c148ee21ap-1804L, -0xc.bb3936c148ee219p-1804L }, + { 0x4.9bdd0004d248afc8p-4L, -0x1.6ebf29fc22091bcp+4728L, -0x8.5eeca757bc17a6ep+4724L, -0x8.5eeca757bc17a6dp+4724L }, + { -0x3.6d1bb2ded9b5e544p-4L, -0x1.363933431c365c5p+6784L, 0x6.bd984ed7081d1dcp+6780L, 0x6.bd984ed7081d1dc8p+6780L }, + { 0x4.5c381c7800220bb8p-4L, -0x1.7a9820b7b4be9b5cp+10592L, -0x8.3a163379e86ae8dp+10588L, -0x8.3a163379e86ae8cp+10588L }, + { -0x6.12772be7f5f9adp-8L, 0x2.5ff922bcfdd1ccf4p+13856L, -0x1.50e2b035b7e3a3c6p+13852L, -0x1.50e2b035b7e3a3c4p+13852L }, + { 0x4.6f048c603adeb688p-4L, -0x7.dcd7d704615cb8ep-7496L, -0x2.c648b04027667808p-7496L, -0x2.c648b04027667804p-7496L }, + { -0x1.426147d80b509dfap-4L, -0x3.b6cb63cc4e57698cp+12696L, 0x7.0727b8bc7de37648p+12692L, 0x7.0727b8bc7de3765p+12692L }, + { 0x7.43a24958p-16416L, -0x1.20c104316e13e7eap+2340L, -0xb.d225983bb5815cp-14076L, -0xb.d225983bb5815bfp-14076L }, + { -0x4.aca95d18p-16416L, -0x4.b253ac25282630fp+5944L, 0x1.fac465fc7e12004p-10468L, 0x1.fac465fc7e120042p-10468L }, + { 0xd.346171700066942p-8L, -0x3.5c5b7a0cde7c0b9p-4344L, -0x3.e6d4bdea75d4f7c8p-4348L, -0x3.e6d4bdea75d4f7c4p-4348L }, + { -0xc.f7fe649ca9f78f1p-8L, -0xe.3a382cc6e7f5879p-4128L, 0x1.112c520281402072p-4128L, 0x1.112c520281402074p-4128L }, + { 0x2.891205a511e09d4p-4L, -0xa.3b1708de40827f3p+9100L, -0x2.2bce95e0f3eadc8p+9100L, -0x2.2bce95e0f3eadc7cp+9100L }, + { -0x2.745b23499b0ba8b8p-4L, 0x1.a50af797227d1b2p-12948L, -0x6.528e377bfd748168p-12952L, -0x6.528e377bfd74816p-12952L }, + { 0x2.e200bf44c048b27p-4L, 0x1.502214b180236b8ep+1004L, 0x5.056320e0e40dcac8p+1000L, 0x5.056320e0e40dcadp+1000L }, + { -0x1.003d0ef8adbf3c9ep-4L, -0x6.b73ddbc1c250fa2p+1172L, 0xa.03b4bfa836d3073p+1168L, 0xa.03b4bfa836d3074p+1168L }, + { 0x4.a8e3b6eba0e5cc5p-4L, -0xa.6207a616c7e6709p+6296L, -0x3.d4256c2208b55f5p+6296L, -0x3.d4256c2208b55f4cp+6296L }, + { -0x2.a92e6e1474be8348p-4L, 0x3.bb46a57c610a305p+7304L, -0xf.aabbe15fe37ce8bp+7300L, -0xf.aabbe15fe37ce8ap+7300L }, + { 0x4.96fd5f79440dfd3p-4L, -0x2.86ed35b8573a3bfcp+624L, -0xe.b63b818d676319ap+620L, -0xe.b63b818d6763199p+620L }, + { -0x3.eca5c520475dad78p-4L, -0x1.112bec17e2eb9514p-7920L, 0x6.ee6ca95de9ffe858p-7924L, 0x6.ee6ca95de9ffe86p-7924L }, + { 0x4.8f4fa442deb571ep-4L, 0x4.bd8cc4d14c3c0818p+3100L, 0x1.b701f77c99e885p+3100L, 0x1.b701f77c99e88502p+3100L }, + { -0x1.cc63ab2f4422f75ep-4L, -0x4.1bd4c5adafb9c458p-7880L, 0xb.4ef13944ce6d745p-7884L, 0xb.4ef13944ce6d746p-7884L }, + { 0x4.5a1c9f3d22df0e3p-4L, -0x4.64d5303735c2074p-6252L, -0x1.866d8aad2725025p-6252L, -0x1.866d8aad2725024ep-6252L }, + { -0x1.55b34aaaa8d19ee2p-4L, 0xf.75a8872ceab3815p-5504L, -0x1.f15dd2d15d4dc058p-5504L, -0x1.f15dd2d15d4dc056p-5504L }, + { 0x2.b3311b1a7010d558p-4L, 0x1.1ecd98b620696b2ep-3596L, 0x4.085356c3e0bf9dfp-3600L, 0x4.085356c3e0bf9df8p-3600L }, + { -0x1.68820b6e4592bfc4p-4L, -0x6.67e7a1d8fd4df47p-13612L, 0xd.9f8d17ac5abfbefp-13616L, 0xd.9f8d17ac5abfbfp-13616L }, + { 0x3.b6a73d8796b983bcp-4L, 0xa.68bc997e0f48d23p-14004L, 0x3.2261d9832d9eb434p-14004L, 0x3.2261d9832d9eb438p-14004L }, + { -0x1.aaa0ed7ab388530cp-4L, 0x5.c31f424ba4ed1fd8p-11856L, -0xe.a1394c8e746bdp-11860L, -0xe.a1394c8e746bcffp-11860L }, +}; + +int check_equal(long double res, long double expected) +{ + if (res != expected) { + return 0; + } + return (__builtin_copysignl(1.0L, res) == + __builtin_copysignl(1.0L, expected)); +} + +int main(void) +{ + int ret = 0; + int i; + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + long double ld_res; + __asm__ volatile ("fyl2xp1" : "=t" (ld_res) : + "0" (tests[i].arg0), "u" (tests[i].arg1) : "st(1)"); + if (!check_equal(ld_res, tests[i].down) && + !check_equal(ld_res, tests[i].up)) { + printf("FAIL: fyl2xp1 %La %La, expected %La or %La, got %La\n", + tests[i].arg0, tests[i].arg1, tests[i].down, tests[i].up, + ld_res); + ret = 1; + } + } + return ret; +} From 1f18a1e6ab8368a4eab2d22894d3b2ae75250cd3 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Wed, 17 Jun 2020 23:24:29 +0000 Subject: [PATCH 1705/2595] target/i386: reimplement fyl2x using floatx80 operations The x87 fyl2x emulation is currently based around conversion to double. This is inherently unsuitable for a good emulation of any floatx80 operation. Reimplement using the soft-float operations, building on top of the reimplementation of fyl2xp1 and factoring out code to be shared between the two instructions. The included test assumes that the result in round-to-nearest mode should always be one of the two closest floating-point numbers to the mathematically exact result (including that it should be exact, in the exact cases which cover more cases than for fyl2xp1). Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 373 +++++++--- tests/tcg/i386/test-i386-fyl2x.c | 1161 ++++++++++++++++++++++++++++++ 2 files changed, 1423 insertions(+), 111 deletions(-) create mode 100644 tests/tcg/i386/test-i386-fyl2x.c diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 884e84c804..62820bc735 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -1223,21 +1223,6 @@ void helper_f2xm1(CPUX86State *env) merge_exception_flags(env, old_flags); } -void helper_fyl2x(CPUX86State *env) -{ - double fptemp = floatx80_to_double(env, ST0); - - if (fptemp > 0.0) { - fptemp = log(fptemp) / log(2.0); /* log2(ST) */ - fptemp *= floatx80_to_double(env, ST1); - ST1 = double_to_floatx80(env, fptemp); - fpop(env); - } else { - env->fpus &= ~0x4700; - env->fpus |= 0x400; - } -} - void helper_fptan(CPUX86State *env) { double fptemp = floatx80_to_double(env, ST0); @@ -1395,6 +1380,118 @@ void helper_fprem(CPUX86State *env) #define fyl2x_coeff_8 make_floatx80(0x3ffc, 0xac5cf50cc57d6372ULL) #define fyl2x_coeff_9 make_floatx80(0x3ffc, 0xb1ed0066d971a103ULL) +/* + * Compute an approximation of log2(1+arg), where 1+arg is in the + * interval [sqrt(2)/2, sqrt(2)]. It is assumed that when this + * function is called, rounding precision is set to 80 and the + * round-to-nearest mode is in effect. arg must not be exactly zero, + * and must not be so close to zero that underflow might occur. + */ +static void helper_fyl2x_common(CPUX86State *env, floatx80 arg, int32_t *exp, + uint64_t *sig0, uint64_t *sig1) +{ + uint64_t arg0_sig = extractFloatx80Frac(arg); + int32_t arg0_exp = extractFloatx80Exp(arg); + bool arg0_sign = extractFloatx80Sign(arg); + bool asign; + int32_t dexp, texp, aexp; + uint64_t dsig0, dsig1, tsig0, tsig1, rsig0, rsig1, rsig2; + uint64_t msig0, msig1, msig2, t2sig0, t2sig1, t2sig2, t2sig3; + uint64_t asig0, asig1, asig2, asig3, bsig0, bsig1; + floatx80 t2, accum; + + /* + * Compute an approximation of arg/(2+arg), with extra precision, + * as the argument to a polynomial approximation. The extra + * precision is only needed for the first term of the + * approximation, with subsequent terms being significantly + * smaller; the approximation only uses odd exponents, and the + * square of arg/(2+arg) is at most 17-12*sqrt(2) = 0.029.... + */ + if (arg0_sign) { + dexp = 0x3fff; + shift128RightJamming(arg0_sig, 0, dexp - arg0_exp, &dsig0, &dsig1); + sub128(0, 0, dsig0, dsig1, &dsig0, &dsig1); + } else { + dexp = 0x4000; + shift128RightJamming(arg0_sig, 0, dexp - arg0_exp, &dsig0, &dsig1); + dsig0 |= 0x8000000000000000ULL; + } + texp = arg0_exp - dexp + 0x3ffe; + rsig0 = arg0_sig; + rsig1 = 0; + rsig2 = 0; + if (dsig0 <= rsig0) { + shift128Right(rsig0, rsig1, 1, &rsig0, &rsig1); + ++texp; + } + tsig0 = estimateDiv128To64(rsig0, rsig1, dsig0); + mul128By64To192(dsig0, dsig1, tsig0, &msig0, &msig1, &msig2); + sub192(rsig0, rsig1, rsig2, msig0, msig1, msig2, + &rsig0, &rsig1, &rsig2); + while ((int64_t) rsig0 < 0) { + --tsig0; + add192(rsig0, rsig1, rsig2, 0, dsig0, dsig1, + &rsig0, &rsig1, &rsig2); + } + tsig1 = estimateDiv128To64(rsig1, rsig2, dsig0); + /* + * No need to correct any estimation error in tsig1; even with + * such error, it is accurate enough. Now compute the square of + * that approximation. + */ + mul128To256(tsig0, tsig1, tsig0, tsig1, + &t2sig0, &t2sig1, &t2sig2, &t2sig3); + t2 = normalizeRoundAndPackFloatx80(80, false, texp + texp - 0x3ffe, + t2sig0, t2sig1, &env->fp_status); + + /* Compute the lower parts of the polynomial expansion. */ + accum = floatx80_mul(fyl2x_coeff_9, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_8, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_7, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_6, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_5, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_4, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_3, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_2, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_1, accum, &env->fp_status); + accum = floatx80_mul(accum, t2, &env->fp_status); + accum = floatx80_add(fyl2x_coeff_0_low, accum, &env->fp_status); + + /* + * The full polynomial expansion is fyl2x_coeff_0 + accum (where + * accum has much lower magnitude, and so, in particular, carry + * out of the addition is not possible), multiplied by t. (This + * expansion is only accurate to about 70 bits, not 128 bits.) + */ + aexp = extractFloatx80Exp(fyl2x_coeff_0); + asign = extractFloatx80Sign(fyl2x_coeff_0); + shift128RightJamming(extractFloatx80Frac(accum), 0, + aexp - extractFloatx80Exp(accum), + &asig0, &asig1); + bsig0 = extractFloatx80Frac(fyl2x_coeff_0); + bsig1 = 0; + if (asign == extractFloatx80Sign(accum)) { + add128(bsig0, bsig1, asig0, asig1, &asig0, &asig1); + } else { + sub128(bsig0, bsig1, asig0, asig1, &asig0, &asig1); + } + /* Multiply by t to compute the required result. */ + mul128To256(asig0, asig1, tsig0, tsig1, + &asig0, &asig1, &asig2, &asig3); + aexp += texp - 0x3ffe; + *exp = aexp; + *sig0 = asig0; + *sig1 = asig1; +} + void helper_fyl2xp1(CPUX86State *env) { uint8_t old_flags = save_exception_flags(env); @@ -1462,109 +1559,18 @@ void helper_fyl2xp1(CPUX86State *env) ST1 = normalizeRoundAndPackFloatx80(80, arg0_sign ^ arg1_sign, exp, sig0, sig1, &env->fp_status); } else { - bool asign; - uint32_t dexp, texp, aexp; - uint64_t dsig0, dsig1, tsig0, tsig1, rsig0, rsig1, rsig2; - uint64_t msig0, msig1, msig2, t2sig0, t2sig1, t2sig2, t2sig3; - uint64_t asig0, asig1, asig2, asig3, bsig0, bsig1; - floatx80 t2, accum; + int32_t aexp; + uint64_t asig0, asig1, asig2; FloatRoundMode save_mode = env->fp_status.float_rounding_mode; signed char save_prec = env->fp_status.floatx80_rounding_precision; env->fp_status.float_rounding_mode = float_round_nearest_even; env->fp_status.floatx80_rounding_precision = 80; + helper_fyl2x_common(env, ST0, &aexp, &asig0, &asig1); /* - * Compute an approximation of ST0/(2+ST0), with extra - * precision, as the argument to a polynomial approximation. - * The extra precision is only needed for the first term of - * the approximation, with subsequent terms being - * significantly smaller; the approximation only uses odd - * exponents, and the square of ST0/(2+ST0) is at most - * 17-12*sqrt(2) = 0.029.... + * Multiply by the second argument to compute the required + * result. */ - if (arg0_sign) { - dexp = 0x3fff; - shift128RightJamming(arg0_sig, 0, dexp - arg0_exp, &dsig0, &dsig1); - sub128(0, 0, dsig0, dsig1, &dsig0, &dsig1); - } else { - dexp = 0x4000; - shift128RightJamming(arg0_sig, 0, dexp - arg0_exp, &dsig0, &dsig1); - dsig0 |= 0x8000000000000000ULL; - } - texp = arg0_exp - dexp + 0x3ffe; - rsig0 = arg0_sig; - rsig1 = 0; - rsig2 = 0; - if (dsig0 <= rsig0) { - shift128Right(rsig0, rsig1, 1, &rsig0, &rsig1); - ++texp; - } - tsig0 = estimateDiv128To64(rsig0, rsig1, dsig0); - mul128By64To192(dsig0, dsig1, tsig0, &msig0, &msig1, &msig2); - sub192(rsig0, rsig1, rsig2, msig0, msig1, msig2, - &rsig0, &rsig1, &rsig2); - while ((int64_t) rsig0 < 0) { - --tsig0; - add192(rsig0, rsig1, rsig2, 0, dsig0, dsig1, - &rsig0, &rsig1, &rsig2); - } - tsig1 = estimateDiv128To64(rsig1, rsig2, dsig0); - /* - * No need to correct any estimation error in tsig1; even with - * such error, it is accurate enough. Now compute the square - * of that approximation. - */ - mul128To256(tsig0, tsig1, tsig0, tsig1, - &t2sig0, &t2sig1, &t2sig2, &t2sig3); - t2 = normalizeRoundAndPackFloatx80(80, false, texp + texp - 0x3ffe, - t2sig0, t2sig1, &env->fp_status); - - /* Compute the lower parts of the polynomial expansion. */ - accum = floatx80_mul(fyl2x_coeff_9, t2, &env->fp_status); - accum = floatx80_add(fyl2x_coeff_8, accum, &env->fp_status); - accum = floatx80_mul(accum, t2, &env->fp_status); - accum = floatx80_add(fyl2x_coeff_7, accum, &env->fp_status); - accum = floatx80_mul(accum, t2, &env->fp_status); - accum = floatx80_add(fyl2x_coeff_6, accum, &env->fp_status); - accum = floatx80_mul(accum, t2, &env->fp_status); - accum = floatx80_add(fyl2x_coeff_5, accum, &env->fp_status); - accum = floatx80_mul(accum, t2, &env->fp_status); - accum = floatx80_add(fyl2x_coeff_4, accum, &env->fp_status); - accum = floatx80_mul(accum, t2, &env->fp_status); - accum = floatx80_add(fyl2x_coeff_3, accum, &env->fp_status); - accum = floatx80_mul(accum, t2, &env->fp_status); - accum = floatx80_add(fyl2x_coeff_2, accum, &env->fp_status); - accum = floatx80_mul(accum, t2, &env->fp_status); - accum = floatx80_add(fyl2x_coeff_1, accum, &env->fp_status); - accum = floatx80_mul(accum, t2, &env->fp_status); - accum = floatx80_add(fyl2x_coeff_0_low, accum, &env->fp_status); - - /* - * The full polynomial expansion is fyl2x_coeff_0 + accum - * (where accum has much lower magnitude, and so, in - * particular, carry out of the addition is not possible), - * multiplied by t. (This expansion is only accurate to about - * 70 bits, not 128 bits.) - */ - aexp = extractFloatx80Exp(fyl2x_coeff_0); - asign = extractFloatx80Sign(fyl2x_coeff_0); - shift128RightJamming(extractFloatx80Frac(accum), 0, - aexp - extractFloatx80Exp(accum), - &asig0, &asig1); - bsig0 = extractFloatx80Frac(fyl2x_coeff_0); - bsig1 = 0; - if (asign == extractFloatx80Sign(accum)) { - add128(bsig0, bsig1, asig0, asig1, &asig0, &asig1); - } else { - sub128(bsig0, bsig1, asig0, asig1, &asig0, &asig1); - } - /* - * Multiply by t and by the second argument to compute the - * required result. - */ - mul128To256(asig0, asig1, tsig0, tsig1, - &asig0, &asig1, &asig2, &asig3); - aexp += texp - 0x3ffe; if (arg1_exp == 0) { normalizeFloatx80Subnormal(arg1_sig, &arg1_exp, &arg1_sig); } @@ -1581,6 +1587,151 @@ void helper_fyl2xp1(CPUX86State *env) merge_exception_flags(env, old_flags); } +void helper_fyl2x(CPUX86State *env) +{ + uint8_t old_flags = save_exception_flags(env); + uint64_t arg0_sig = extractFloatx80Frac(ST0); + int32_t arg0_exp = extractFloatx80Exp(ST0); + bool arg0_sign = extractFloatx80Sign(ST0); + uint64_t arg1_sig = extractFloatx80Frac(ST1); + int32_t arg1_exp = extractFloatx80Exp(ST1); + bool arg1_sign = extractFloatx80Sign(ST1); + + if (floatx80_is_signaling_nan(ST0, &env->fp_status)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_silence_nan(ST0, &env->fp_status); + } else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_silence_nan(ST1, &env->fp_status); + } else if (floatx80_invalid_encoding(ST0) || + floatx80_invalid_encoding(ST1)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_default_nan(&env->fp_status); + } else if (floatx80_is_any_nan(ST0)) { + ST1 = ST0; + } else if (floatx80_is_any_nan(ST1)) { + /* Pass this NaN through. */ + } else if (arg0_sign && !floatx80_is_zero(ST0)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_default_nan(&env->fp_status); + } else if (floatx80_is_infinity(ST1)) { + FloatRelation cmp = floatx80_compare(ST0, floatx80_one, + &env->fp_status); + switch (cmp) { + case float_relation_less: + ST1 = floatx80_chs(ST1); + break; + case float_relation_greater: + /* Result is infinity of the same sign as ST1. */ + break; + default: + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_default_nan(&env->fp_status); + break; + } + } else if (floatx80_is_infinity(ST0)) { + if (floatx80_is_zero(ST1)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_default_nan(&env->fp_status); + } else if (arg1_sign) { + ST1 = floatx80_chs(ST0); + } else { + ST1 = ST0; + } + } else if (floatx80_is_zero(ST0)) { + if (floatx80_is_zero(ST1)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_default_nan(&env->fp_status); + } else { + /* Result is infinity with opposite sign to ST1. */ + float_raise(float_flag_divbyzero, &env->fp_status); + ST1 = make_floatx80(arg1_sign ? 0x7fff : 0xffff, + 0x8000000000000000ULL); + } + } else if (floatx80_is_zero(ST1)) { + if (floatx80_lt(ST0, floatx80_one, &env->fp_status)) { + ST1 = floatx80_chs(ST1); + } + /* Otherwise, ST1 is already the correct result. */ + } else if (floatx80_eq(ST0, floatx80_one, &env->fp_status)) { + if (arg1_sign) { + ST1 = floatx80_chs(floatx80_zero); + } else { + ST1 = floatx80_zero; + } + } else { + int32_t int_exp; + floatx80 arg0_m1; + FloatRoundMode save_mode = env->fp_status.float_rounding_mode; + signed char save_prec = env->fp_status.floatx80_rounding_precision; + env->fp_status.float_rounding_mode = float_round_nearest_even; + env->fp_status.floatx80_rounding_precision = 80; + + if (arg0_exp == 0) { + normalizeFloatx80Subnormal(arg0_sig, &arg0_exp, &arg0_sig); + } + if (arg1_exp == 0) { + normalizeFloatx80Subnormal(arg1_sig, &arg1_exp, &arg1_sig); + } + int_exp = arg0_exp - 0x3fff; + if (arg0_sig > 0xb504f333f9de6484ULL) { + ++int_exp; + } + arg0_m1 = floatx80_sub(floatx80_scalbn(ST0, -int_exp, + &env->fp_status), + floatx80_one, &env->fp_status); + if (floatx80_is_zero(arg0_m1)) { + /* Exact power of 2; multiply by ST1. */ + env->fp_status.float_rounding_mode = save_mode; + ST1 = floatx80_mul(int32_to_floatx80(int_exp, &env->fp_status), + ST1, &env->fp_status); + } else { + bool asign = extractFloatx80Sign(arg0_m1); + int32_t aexp; + uint64_t asig0, asig1, asig2; + helper_fyl2x_common(env, arg0_m1, &aexp, &asig0, &asig1); + if (int_exp != 0) { + bool isign = (int_exp < 0); + int32_t iexp; + uint64_t isig; + int shift; + int_exp = isign ? -int_exp : int_exp; + shift = clz32(int_exp) + 32; + isig = int_exp; + isig <<= shift; + iexp = 0x403e - shift; + shift128RightJamming(asig0, asig1, iexp - aexp, + &asig0, &asig1); + if (asign == isign) { + add128(isig, 0, asig0, asig1, &asig0, &asig1); + } else { + sub128(isig, 0, asig0, asig1, &asig0, &asig1); + } + aexp = iexp; + asign = isign; + } + /* + * Multiply by the second argument to compute the required + * result. + */ + if (arg1_exp == 0) { + normalizeFloatx80Subnormal(arg1_sig, &arg1_exp, &arg1_sig); + } + mul128By64To192(asig0, asig1, arg1_sig, &asig0, &asig1, &asig2); + aexp += arg1_exp - 0x3ffe; + /* This result is inexact. */ + asig1 |= 1; + env->fp_status.float_rounding_mode = save_mode; + ST1 = normalizeRoundAndPackFloatx80(80, asign ^ arg1_sign, aexp, + asig0, asig1, &env->fp_status); + } + + env->fp_status.floatx80_rounding_precision = save_prec; + } + fpop(env); + merge_exception_flags(env, old_flags); +} + void helper_fsqrt(CPUX86State *env) { uint8_t old_flags = save_exception_flags(env); diff --git a/tests/tcg/i386/test-i386-fyl2x.c b/tests/tcg/i386/test-i386-fyl2x.c new file mode 100644 index 0000000000..71d7a8fc99 --- /dev/null +++ b/tests/tcg/i386/test-i386-fyl2x.c @@ -0,0 +1,1161 @@ +/* Test fyl2x instruction. */ + +#include + +struct test { + long double arg0, arg1, down, up; +}; + +const struct test tests[] = { + { 1.0L, 12345.0L, 0.0L, 0.0L }, + { 1.0L, -12345.0L, -0.0L, -0.0L }, + { 1.0L, 0.0L, 0.0L, 0.0L }, + { 1.0L, -0.0L, -0.0L, -0.0L }, + { 0.1L, 0.0L, -0.0L, -0.0L }, + { 0.1L, -0.0L, 0.0L, 0.0L }, + { 1.1L, 0.0L, 0.0L, 0.0L }, + { 1.1L, -0.0L, -0.0L, -0.0L }, + { 0.0L, __builtin_infl(), -__builtin_infl(), -__builtin_infl() }, + { 0.0L, -__builtin_infl(), __builtin_infl(), __builtin_infl() }, + { -0.0L, __builtin_infl(), -__builtin_infl(), -__builtin_infl() }, + { -0.0L, -__builtin_infl(), __builtin_infl(), __builtin_infl() }, + { 0.0L, 12345.0L, -__builtin_infl(), -__builtin_infl() }, + { 0.0L, -12345.0L, __builtin_infl(), __builtin_infl() }, + { -0.0L, 12345.0L, -__builtin_infl(), -__builtin_infl() }, + { -0.0L, -12345.0L, __builtin_infl(), __builtin_infl() }, + { 0.1L, __builtin_infl(), -__builtin_infl(), -__builtin_infl() }, + { 0.1L, -__builtin_infl(), __builtin_infl(), __builtin_infl() }, + { 1.1L, __builtin_infl(), __builtin_infl(), __builtin_infl() }, + { 1.1L, -__builtin_infl(), -__builtin_infl(), -__builtin_infl() }, + { 4.0L, 1.5L, 3.0L, 3.0L }, + { 0x1p-16400L, 1.5L, -24600.0L, -24600.0L }, + /* Randomly generated tests. */ + { 0x2.0a40b4bd6349d53p+14380L, -0x3.612a1cec52e70388p-14116L, -0xb.dd9637a24570d1ap-14104L, -0xb.dd9637a24570d19p-14104L }, + { 0xa.a3dc18b1eff7e8ap-4L, 0x7.423575b7ac0ba6a8p-7212L, -0x4.45ac6ae2f9cc1a7p-7212L, -0x4.45ac6ae2f9cc1a68p-7212L }, + { 0x1.51167cab1deec25ep-9616L, 0xb.79bece734a62216p-14512L, -0x1.af0880f05109d5c8p-14496L, -0x1.af0880f05109d5c6p-14496L }, + { 0x1.55691f3dee65eb88p+6420L, -0x2.e081398cd6691b98p-2640L, -0x4.8275aa22ebb6ebe8p-2628L, -0x4.8275aa22ebb6ebep-2628L }, + { 0x3.71cca195c06ba4d4p-6312L, -0xb.14b747fa4cc13d1p+5052L, 0x1.112301748a1cc83p+5068L, 0x1.112301748a1cc832p+5068L }, + { 0x2.0f924dde0806572p+8924L, -0x7.ece8699d62a9f76p-14464L, -0x1.144eba5c079d0fa2p-14448L, -0x1.144eba5c079d0fap-14448L }, + { 0x4.b875c0342c9f86b8p-5832L, 0xe.a37e0fa859e499cp+732L, -0x1.4d5bc95e2af0bb08p+748L, -0x1.4d5bc95e2af0bb06p+748L }, + { 0x7.23210d9474f0715p+364L, -0x5.baaf3a431730f158p-2436L, -0x8.35afbc04cd37fafp-2428L, -0x8.35afbc04cd37faep-2428L }, + { 0xd.2330923899aae43p+776L, 0x2.a68cc6ddbe3b3a5p+6528L, 0x8.12b3f5a7b346e37p+6536L, 0x8.12b3f5a7b346e38p+6536L }, + { 0x2.c18975d92e49e91p+10120L, 0x5.6a0ac0f801b69198p+9064L, 0xd.60fe44e0b41da9dp+9076L, 0xd.60fe44e0b41da9ep+9076L }, + { 0x9.0950fb020f8be81p-11076L, -0x4.69649643801fe8p+14796L, 0xb.ed1e14ac1ee3159p+14808L, 0xb.ed1e14ac1ee315ap+14808L }, + { 0x9.cbe5ac9e09f4815p+8052L, -0x1.068c69d5c31cc18ap+8068L, -0x2.04558d1bf9a219b4p+8080L, -0x2.04558d1bf9a219bp+8080L }, + { 0x2.8158a2ep-16416L, 0x1.2f720ae47b67fca8p+13452L, -0x4.c00deece9e0fbdd8p+13464L, -0x4.c00deece9e0fbddp+13464L }, + { 0x3.0acd5bcfe0779bd4p+13040L, -0xe.d3cd27fc1c72a99p+11224L, -0x2.f35c6ed58511949p+11240L, -0x2.f35c6ed58511948cp+11240L }, + { 0xb.58a8c4316eacf31p-584L, 0x1.501f01a1258b3a5ep-10084L, -0x2.fa2ce9d2db22ad5cp-10076L, -0x2.fa2ce9d2db22ad58p-10076L }, + { 0x8.97f4540aa7735bap+13532L, -0x3.b7afc1088aafbb28p-9804L, -0xc.48d1793ca776382p-9792L, -0xc.48d1793ca776381p-9792L }, + { 0x5.1f9f41429952299p-6688L, -0x1.385afe2753285ceap-632L, 0x1.fdd68ec1544cca1ap-620L, 0x1.fdd68ec1544cca1cp-620L }, + { 0x2.95674162a7a77d6cp-11476L, -0x6.9ad188a393c513bp-8912L, 0x1.280b2d9ef35a1b0ep-8896L, 0x1.280b2d9ef35a1b1p-8896L }, + { 0x1.11caeb05f30a55a2p-5048L, 0xa.6b25eb8a8fc7c1fp+6868L, -0xc.d6fd12efe012db1p+6880L, -0xc.d6fd12efe012dbp+6880L }, + { 0x3.c980e98228764804p-5832L, 0x9.5de74e6eb71dccfp+1992L, -0xd.5513ed4865b07fep+2004L, -0xd.5513ed4865b07fdp+2004L }, + { 0xd.16b2f891d20d0f8p+7300L, -0x1.ab0872107c4d7a06p+5924L, -0x2.f974d3a68daf1cacp+5936L, -0x2.f974d3a68daf1ca8p+5936L }, + { 0x6.c6090865d981a428p-8676L, -0xd.23a3619aedffe31p+5328L, 0x1.bd2789bab1d1088cp+5344L, 0x1.bd2789bab1d1088ep+5344L }, + { 0x2.0d4fa66a2d01369cp-4156L, -0x5.a0e8f41f82c193bp+6724L, 0x5.b5a6f9779b0a4488p+6736L, 0x5.b5a6f9779b0a449p+6736L }, + { 0x1.ba2a72afa5a1fc38p+0L, 0xe.027c0b9bc2929f3p+11120L, 0xb.0bbdb58c72375d9p+11120L, 0xb.0bbdb58c72375dap+11120L }, + { 0xf.cc716330a37576ep-5424L, -0xd.a67cd50b638d845p-4460L, 0x1.21011acae853070ap-4444L, 0x1.21011acae853070cp-4444L }, + { 0x2.7699390ee7b13a7cp+8364L, -0x1.d8cb9730c96f499p+432L, -0x3.c598297e793d4e98p+444L, -0x3.c598297e793d4e94p+444L }, + { 0x4.6b0173e789f64bd8p-960L, -0x2.140353c78ded1788p+8748L, 0x7.c6982a68b41c327p+8756L, 0x7.c6982a68b41c3278p+8756L }, + { 0xc.08b122dd36a9965p+11804L, -0xa.c8e6364d67421f2p+12272L, -0x1.f16e0be947126474p+12288L, -0x1.f16e0be947126472p+12288L }, + { 0x9.cafbcd348517675p+784L, 0x4.148eb9b190272998p-1420L, 0xc.8c638141b3c6b91p-1412L, 0xc.8c638141b3c6b92p-1412L }, + { 0x4.6a571cdc489d4a9p-12352L, -0x8.a8aa4198b0c3207p+7748L, 0x1.a1b789910f110f64p+7764L, 0x1.a1b789910f110f66p+7764L }, + { 0x7.e9b228c12458559p+4928L, -0xb.2c5bdfaf2ba8f24p+56L, -0xd.73740755eb037a7p+68L, -0xd.73740755eb037a6p+68L }, + { 0xd.d2e346da3ecdb39p-1636L, -0x5.8d0ce8c4cdc72a28p+12736L, 0x2.3645e062564a6de4p+12748L, 0x2.3645e062564a6de8p+12748L }, + { 0x9.b624ea7f57aab0ap-8780L, -0x2.5e13b5ceb995397p-6416L, 0x5.12ac8402317cf408p-6404L, 0x5.12ac8402317cf41p-6404L }, + { 0x7.6d8427638b963b58p+12536L, 0x4.021f2d6df523df5p-14208L, 0xc.4537f396f309b57p-14196L, 0xc.4537f396f309b58p-14196L }, + { 0x1.8273f77fc7b36adp+0L, 0x2.f4e4c4891a53eaap-4624L, 0x1.c1b52b72090b9f64p-4624L, 0x1.c1b52b72090b9f66p-4624L }, + { 0x1.c92a5ddc0ccb3c36p+11600L, 0x1.090c0001295c6822p-4904L, 0x2.eeacd7b5643f39ecp-4892L, 0x2.eeacd7b5643f39fp-4892L }, + { 0xd.32c71819b8fe7abp-1688L, -0x6.3d33ce38ee554b58p-14512L, 0x2.90c54596d3bf22ecp-14500L, 0x2.90c54596d3bf22fp-14500L }, + { 0x1.0776fe51e1d0727cp+5752L, 0x1.4264622f1e6c6f9ep+12300L, 0x1.c4bccdc673bd74bap+12312L, 0x1.c4bccdc673bd74bcp+12312L }, + { 0x1.81f41db779901632p-10716L, -0x8.66aed834cdb9d9fp+4436L, 0x1.5fa54511d99a6f4ap+4452L, 0x1.5fa54511d99a6f4cp+4452L }, + { 0xc.9b4feccafbb8f3ep-5320L, -0xe.ccfc061ce46d6dfp+13440L, 0x1.335db86628278a4cp+13456L, 0x1.335db86628278a4ep+13456L }, + { 0x6.4ffb2045e1ad1378p-6564L, 0xf.7dfd3273f5ec1a3p+9724L, -0x1.8d1141c2de30f8eap+9740L, -0x1.8d1141c2de30f8e8p+9740L }, + { 0x2.ad90d677772e099cp+13112L, -0x2.830a812d5307cc94p-6908L, -0x8.0ab53e41596b795p-6896L, -0x8.0ab53e41596b794p-6896L }, + { 0x1.7bf51909429d7df2p-520L, -0x3.3d489a77c9f992fcp+5672L, 0x6.92a309adfd41fffp+5680L, 0x6.92a309adfd41fff8p+5680L }, + { 0x1.330765dbd272224cp+13924L, 0x2.b0444ac2e0ef926p+9564L, 0x9.23bf6ee60967adp+9576L, 0x9.23bf6ee60967ad1p+9576L }, + { 0xb.067254ab6c13349p-5508L, 0xa.7a515bb500d476fp+7348L, -0xe.14b76544da68e7fp+7360L, -0xe.14b76544da68e7ep+7360L }, + { 0x1.4f1b85b1df9ca2b4p+0L, -0x2.8e9812b9a5395564p+10304L, -0xf.e4bfca8c781c9d5p+10300L, -0xf.e4bfca8c781c9d4p+10300L }, + { 0x2.d4c7f38019aa6c2p+11216L, 0xb.6a68ac4a863ccap-6380L, 0x1.f4372db1fc362048p-6364L, 0x1.f4372db1fc36204ap-6364L }, + { 0x4.d6f79ebf8f5962ap-12132L, -0x7.2fde53882a542cp-9272L, 0x1.54882a9fcea32926p-9256L, 0x1.54882a9fcea32928p-9256L }, + { 0x5.f224f48169e0aea8p+4500L, -0x2.3e6bba4532dcfb74p-4984L, -0x2.77702ff129d7eb24p-4972L, -0x2.77702ff129d7eb2p-4972L }, + { 0xf.ce42d087ed87c6dp-1636L, -0x3.b45d9ada75fad714p+4704L, 0x1.79de5728a407b37ap+4716L, 0x1.79de5728a407b37cp+4716L }, + { 0x8.c2ce2631a625123p-8668L, 0x1.bdf6302fd5c0c678p+13148L, -0x3.af6876f1ee35ebf4p+13160L, -0x3.af6876f1ee35ebfp+13160L }, + { 0x2.9fb1b2e872ad16fcp+5720L, 0xa.405432519e52763p-12388L, 0xe.51b9d7128949a09p-12376L, 0xe.51b9d7128949a0ap-12376L }, + { 0x2.0c52d8494ae2a78p-12156L, 0x2.c778146cdaf5952p+8448L, -0x8.3f4ca0808d4657fp+8460L, -0x8.3f4ca0808d4657ep+8460L }, + { 0x7.7bfdf3916d8cf8dp+8552L, -0x2.fcc721321202f8fcp+7376L, -0x6.3d508fed61bad698p+7388L, -0x6.3d508fed61bad69p+7388L }, + { 0x9.09cea2796b8226bp+12760L, -0xe.d759972da423644p-6776L, -0x2.e3ecfc770c2adf48p-6760L, -0x2.e3ecfc770c2adf44p-6760L }, + { 0x3.f7d3ba7d4699285cp-2652L, 0x1.806cf84083df3ff4p+192L, -0xf.8b6c7389e003b59p+200L, -0xf.8b6c7389e003b58p+200L }, + { 0xd.df138c6b3e2cda7p-4L, -0x3.056a73ca2e92d3f8p+2760L, 0x9.f4ace14ab975a41p+2756L, 0x9.f4ace14ab975a42p+2756L }, + { 0x3.43ad78da6c4fbdbp-88L, -0x7.e7d5025d81fd262p+11984L, 0x2.aa32f09cb4608f7p+11992L, 0x2.aa32f09cb4608f74p+11992L }, + { 0x1.9b44f75fe57ddc8p-1260L, 0x4.38ec201a4e140da8p+1488L, -0x1.4c546e4cce840414p+1500L, -0x1.4c546e4cce840412p+1500L }, + { 0x1.42d057efa3eb1b9p-6636L, -0x6.64151de2cb7dab68p+14856L, 0xa.5a83005207a7a31p+14868L, 0xa.5a83005207a7a32p+14868L }, + { 0x3.5e66ae0c3ef31cc8p-13572L, -0x1.fa8c3fd05e77645ep-2452L, 0x6.8e37bd270fc92fb8p-2440L, 0x6.8e37bd270fc92fcp-2440L }, + { 0x6.001cd5c28a310bd8p+4224L, 0x4.c1b839282f6ff928p-11728L, 0x4.e88ab9284208a73p-11716L, 0x4.e88ab9284208a738p-11716L }, + { 0x2.2523780824d5de6cp+6472L, 0x1.b994f4a4f7e37afcp-8880L, 0x2.b9da3fa65283fa3p-8868L, 0x2.b9da3fa65283fa34p-8868L }, + { 0x5.6eec466c7bffa06p-608L, -0x1.97289654800c49b6p-8972L, 0x3.c31e2f1c37735488p-8964L, 0x3.c31e2f1c3773548cp-8964L }, + { 0x1.ca72ccc65efa7b72p-6772L, 0x5.f8e4e1978952a4ap-11212L, -0x9.df7016942b5d202p-11200L, -0x9.df7016942b5d201p-11200L }, + { 0xf.c6d22b8e29913f1p+9424L, -0xe.a6d7654fc1271b1p+1136L, -0x2.1b98288c7d75e8e8p+1152L, -0x2.1b98288c7d75e8e4p+1152L }, + { 0x1.61e8e00c140fee84p-9076L, -0x8.36dc1307ce2fc6p+14524L, 0x1.23351bc9d473a88p+14540L, 0x1.23351bc9d473a882p+14540L }, + { 0xf.866338e1e8a3a1dp-8L, -0x2.0442ce4344704d5cp-560L, 0x8.277e13b5af2161dp-560L, 0x8.277e13b5af2161ep-560L }, + { 0xe.3299360868a37fcp-10400L, 0x3.e615f9a223227808p-10468L, -0x9.e54507c6991311ep-10456L, -0x9.e54507c6991311dp-10456L }, + { 0x9.b3ff5c8d9b3d3acp+1836L, 0xa.828b7a9eaf39effp-2100L, 0x4.b82b5232056d9bbp-2088L, 0x4.b82b5232056d9bb8p-2088L }, + { 0xe.ffd31418495b633p+10124L, -0xc.5c871eba0b4806fp+5684L, -0x1.e90b7ad4822936e8p+5700L, -0x1.e90b7ad4822936e6p+5700L }, + { 0x1.7b8e3d8dda2e2b02p-7084L, 0xf.bbe5d63f9e346a3p-5088L, -0x1.b35a8b7f594154ecp-5072L, -0x1.b35a8b7f594154eap-5072L }, + { 0xe.8837c0b02c82f75p+8320L, 0x3.05caa0d06bb20888p-7260L, 0x6.247e5285220e72ap-7248L, 0x6.247e5285220e72a8p-7248L }, + { 0x7.bad48611f3e40dap-12820L, -0x1.643e2a67aaa8efa2p+13488L, 0x4.5abde1190f1b7cp+13500L, 0x4.5abde1190f1b7c08p+13500L }, + { 0xd.0e541be4b24c664p-5232L, 0x3.065797f0fcc28dbp-8280L, -0x3.dc667fc93532e9c4p-8268L, -0x3.dc667fc93532e9cp-8268L }, + { 0x2.c5b8595f3f1fb5acp+10588L, 0x5.914bbd1c2a1f9d8p-7504L, 0xe.64d8944801b7e74p-7492L, 0xe.64d8944801b7e75p-7492L }, + { 0x3.e915b16b3ea952b8p-12048L, -0x3.5dde4fb68f625424p+4784L, 0x9.e6b0eef12e35a51p+4796L, 0x9.e6b0eef12e35a52p+4796L }, + { 0x8.063bbdb884d4c9fp+13076L, -0xc.690888a046c216cp+13536L, -0x2.7a0a30ea19f24dcp+13552L, -0x2.7a0a30ea19f24dbcp+13552L }, + { 0x3.33cbc218p-16416L, 0x2.577f86039916008p-5496L, -0x9.626e2d063f7c1e6p-5484L, -0x9.626e2d063f7c1e5p-5484L }, + { 0xf.97d7708bcb4c28ap+13800L, 0x1.92222235b217c128p+11344L, 0x5.4b3b99b0bd7e58cp+11356L, 0x5.4b3b99b0bd7e58c8p+11356L }, + { 0x3.7a62c19d2c7a4ef8p-1380L, 0xf.4bfc2d311b1d267p+12820L, -0x5.25a19533e5ec3898p+12832L, -0x5.25a19533e5ec389p+12832L }, + { 0x3.953c10cac334f73cp+2340L, 0x1.c610af4e1921cf5p-9256L, 0x1.039b482967f45ea8p-9244L, 0x1.039b482967f45eaap-9244L }, + { 0x2.f53d77c7f418237p+9336L, 0x3.c220b549da592788p-9580L, 0x8.9157a2d708af2c2p-9568L, 0x8.9157a2d708af2c3p-9568L }, + { 0x3.fbed3dcaaa06e4c4p-1192L, -0x3.e835e2ef87a1d7ecp-7400L, 0x1.229703d42721d65p-7388L, 0x1.229703d42721d652p-7388L }, + { 0x1.68487d450687a984p+660L, -0xf.2712729e7432756p+8724L, -0x2.71833e4eea72386cp+8736L, -0x2.71833e4eea723868p+8736L }, + { 0x3.91417fe2ad087038p+6300L, 0x7.021f29569b153f3p+4316L, 0xa.c8512daa73d6e1p+4328L, 0xa.c8512daa73d6e11p+4328L }, + { 0x3.c229138106afa45p+4436L, -0x3.676f1b1db23e0ccp+13624L, -0x3.b02d1d0112ccfa2cp+13636L, -0x3.b02d1d0112ccfa28p+13636L }, + { 0x1.aec776f7ea1c0bc6p+8464L, 0xd.28a1966f8b32e32p+11704L, 0x1.b3193facdf56a46ap+11720L, 0x1.b3193facdf56a46cp+11720L }, + { 0x1.c10c86e3b300597cp+3280L, 0x4.1a760e745f4d25cp+8252L, 0x3.4965c3cd3ca8ad3cp+8264L, 0x3.4965c3cd3ca8ad4p+8264L }, + { 0x1.b1db4fb675211df6p+0L, 0x1.6be49e4860e6d81ap+7060L, 0x1.14f3265dd400057ep+7060L, 0x1.14f3265dd400058p+7060L }, + { 0x4.b497e93cf288163p-2404L, -0x9.6961065f95443f1p-2968L, 0x5.84c8bc67a7686f48p-2956L, 0x5.84c8bc67a7686f5p-2956L }, + { 0x4.5dcb8cb337091ep+6896L, 0x5.11f25379bb653bd8p+14376L, 0x8.89e37aa0f515b74p+14388L, 0x8.89e37aa0f515b75p+14388L }, + { 0xa.7268d9e3b2e61bap+2464L, 0x7.8ebb30aae46e97dp-14932L, 0x4.8d75ec76fb62c77p-14920L, 0x4.8d75ec76fb62c778p-14920L }, + { 0x2.526a2db40e4a133p+12128L, 0x1.46f991704d64c4p-1120L, 0x3.c83fcabb8bd20458p-1108L, 0x3.c83fcabb8bd2045cp-1108L }, + { 0x8.6b4ceac3f5e0728p+13928L, 0x2.9d183c4c6fdb04a4p-9108L, 0x8.e3af724b181616bp-9096L, 0x8.e3af724b181616cp-9096L }, + { 0xb.8b98aaf25e886f9p+5156L, -0x6.d99dca78791969cp+12196L, -0x8.a0f1aedd7cc7487p+12208L, -0x8.a0f1aedd7cc7486p+12208L }, + { 0xc.075641c050086f8p+3892L, 0xe.deda4695e681519p+7992L, 0xe.2496aff9a14be97p+8004L, 0xe.2496aff9a14be98p+8004L }, + { 0x1.8c92fa660e15352ep-1228L, -0xa.5069a079cc133acp+7808L, 0x3.1733766197485eacp+7820L, 0x3.1733766197485ebp+7820L }, + { 0x2.24799a29d446fa08p-7812L, -0x4.05d8a4c62f6a18e8p-3908L, 0x7.abdfaecc0aeb94ep-3896L, 0x7.abdfaecc0aeb94e8p-3896L }, + { 0x1.a2963647b8c1e952p+1464L, -0x9.dc35dae9cfa046fp-9920L, -0x3.86a529d9cab1a628p-9908L, -0x3.86a529d9cab1a624p-9908L }, + { 0x7.42c1ce68p-16416L, -0x9.8b1dbd0b049084dp+2680L, 0x2.63dd875dd5ab9c6cp+2696L, 0x2.63dd875dd5ab9c7p+2696L }, + { 0x2.4da05a583c91938p+10540L, -0x4.25be1ba5de90e918p+932L, -0xa.ac6ed13b63a1d92p+944L, -0xa.ac6ed13b63a1d91p+944L }, + { 0x8.0e17e4b161c5a45p+2440L, -0x9.bf58078144f5743p-5248L, -0x5.d0515bfeef3843f8p-5236L, -0x5.d0515bfeef3843fp-5236L }, + { 0xd.1856d68bf52a57dp-6588L, -0x5.e570d6841b2c088p-8116L, 0x9.7a6a259ef770338p-8104L, 0x9.7a6a259ef770339p-8104L }, + { 0x9.872f5ce857da213p-1656L, 0xb.cf8a253dd36dfd2p-2832L, -0x4.c401c85ddd5c1c38p-2820L, -0x4.c401c85ddd5c1c3p-2820L }, + { 0x1.567c962075b01046p-2992L, 0x5.96dea6367a681b68p-12668L, -0x4.150f162a937d4c98p-12656L, -0x4.150f162a937d4c9p-12656L }, + { 0x2.330521783950b058p-8660L, -0x5.fd2d731707657b5p+12584L, 0xc.a91b62f8e76612cp+12596L, 0xc.a91b62f8e76612dp+12596L }, + { 0x1.6365c7132e7ab896p+14300L, 0x6.74e840f8b63c3dd8p+2708L, 0x1.68ad6bdb36c77d3ep+2724L, 0x1.68ad6bdb36c77d4p+2724L }, + { 0x1.23d9c444b8796b86p+10316L, 0x5.5531715a18534968p-13748L, 0xd.6e6068774baf9a8p-13736L, 0xd.6e6068774baf9a9p-13736L }, + { 0x7.aee9cd5902c35aa8p-404L, -0x1.79b3917e3ae0ef84p+2720L, 0x2.4fb84a5052ed5f7p+2728L, 0x2.4fb84a5052ed5f74p+2728L }, + { 0x6.800a7b095615357p+10936L, -0x3.8283a98b3d446a38p-5192L, -0x9.5f8e2dd199e2736p-5180L, -0x9.5f8e2dd199e2735p-5180L }, + { 0x1.78d6aeb5bd310056p+0L, 0x1.45e29cec4ee079d8p-3296L, 0xb.5c79c6a6c49a62bp-3300L, 0xb.5c79c6a6c49a62cp-3300L }, + { 0x4.b21a682b16590228p-13876L, -0x3.70fb6523fc99c194p+14144L, 0xb.a804c9fc9c673dfp+14156L, 0xb.a804c9fc9c673ep+14156L }, + { 0x3.23f2a35775b3a338p-8344L, 0xc.78c1635bb7ee7c4p-1084L, -0x1.966b48238708618ap-1068L, -0x1.966b482387086188p-1068L }, + { 0x3.f496d494eff66598p-12580L, 0x1.6b790fafdbb51f08p+12268L, -0x4.5c277f50b347c3f8p+12280L, -0x4.5c277f50b347c3fp+12280L }, + { 0x8.ec1b59a9caa6303p-10924L, 0x3.e8d13e253b2213ccp+628L, -0xa.6c668c91aec61d6p+640L, -0xa.6c668c91aec61d5p+640L }, + { 0xd.a1a02db93dcda76p-5712L, -0x3.07a2a2ead26ae24cp+6968L, 0x4.38ef190fdff3c19p+6980L, 0x4.38ef190fdff3c198p+6980L }, + { 0x1.a0b348b4888fa2fcp-1152L, -0xe.f9e7aa3db6ed0afp+12620L, 0x4.35a0bc4fb075f8d8p+12632L, 0x4.35a0bc4fb075f8ep+12632L }, + { 0x3.6f67cd0a4f4f4a6cp-3780L, -0xd.8095adbeaff6317p+14292L, 0xc.746980c872b61e4p+14304L, 0xc.746980c872b61e5p+14304L }, + { 0x3.c5516656a58130ccp+11040L, 0x1.c0bfa71287c3acdap-1104L, 0x4.b9ba44f7f286c4a8p-1092L, 0x4.b9ba44f7f286c4bp-1092L }, + { 0x1.d9f5b1f814163e0ep+7296L, -0x2.04efcf98cc6bd1c8p+1188L, -0x3.98e7df8daf1d5404p+1200L, -0x3.98e7df8daf1d54p+1200L }, + { 0x3.a704d93ae36e79c4p-2416L, 0xa.3c0c59ab56e5e6cp+3204L, -0x6.0839412e892258p+3216L, -0x6.0839412e892257f8p+3216L }, + { 0x1.ff1cd2d2fae4bd48p+0L, -0xc.beb414075682a59p+4332L, -0xc.b689b68cb462e06p+4332L, -0xc.b689b68cb462e05p+4332L }, + { 0x7.865db97fb832a698p-3852L, 0x3.210fd99d2fe72c7p+10992L, -0x2.f0c5e11a2cdeea2cp+11004L, -0x2.f0c5e11a2cdeea28p+11004L }, + { 0x4.2bc44b2356390acp-4624L, -0x7.cd81763c0a3f1938p-10236L, 0x8.cdfdec8404d7021p-10224L, 0x8.cdfdec8404d7022p-10224L }, + { 0xf.6e6ebaa083c4cd3p+6772L, 0x3.53aa70c4188f244p-6152L, 0x5.80e5ae2af4891598p-6140L, 0x5.80e5ae2af48915ap-6140L }, + { 0xe.77c56c623d0f0eep-3144L, 0x8.6f79329139f632dp+3132L, -0x6.7788429ecc43227p+3144L, -0x6.7788429ecc432268p+3144L }, + { 0x7.b93a559e4e12075p-9120L, -0x1.351b28adc68b89bcp-13008L, 0x2.b0057e68ca71b908p-12996L, 0x2.b0057e68ca71b90cp-12996L }, + { 0x1.80e63adf125be828p+2620L, -0x6.b3b07792c5acf1b8p+4564L, -0x4.49af36f38515eb78p+4576L, -0x4.49af36f38515eb7p+4576L }, + { 0x1.f5bda0c135772ea8p-14388L, 0x1.d2d15b323301604cp+6960L, -0x6.67ad949e9dd71688p+6972L, -0x6.67ad949e9dd7168p+6972L }, + { 0xe.eba318936113b91p-13680L, -0x7.e2bc9165ba0d4e7p-744L, 0x1.a5457d1a3b4bf81cp-728L, 0x1.a5457d1a3b4bf81ep-728L }, + { 0x1.a2e010d583127526p+3200L, 0x1.e8a7eb43e7eecf8ep-11800L, 0x1.7dd8e1e0fb4c040cp-11788L, 0x1.7dd8e1e0fb4c040ep-11788L }, + { 0x2.089221e2807b8ae8p+1780L, -0x1.67ebc2e75a0f1464p+7020L, -0x9.c803d1c26ea95eap+7028L, -0x9.c803d1c26ea95e9p+7028L }, + { 0x4.0ac05ec8p-16416L, -0xa.530c1b060238f06p-5476L, 0x2.95f89a58fc3e6abp-5460L, 0x2.95f89a58fc3e6ab4p-5460L }, + { 0x3.aa0cc319c013919p-6132L, -0xf.0292f4401d18d5cp+4904L, 0x1.676d88de1fc94da8p+4920L, 0x1.676d88de1fc94daap+4920L }, + { 0x6.fd442271482ca6dp-14508L, -0x6.67012d8b67014328p+3032L, 0x1.6ac38118c5f3b35cp+3048L, 0x1.6ac38118c5f3b35ep+3048L }, + { 0x1.4d6d06de5fee4cc4p-7248L, -0x9.620bcddbdd20a79p-8756L, 0x1.09a45a7db576a522p-8740L, 0x1.09a45a7db576a524p-8740L }, + { 0x8.2e6ecc0d5fbbd0ap-1672L, -0x1.a3b873c6b160474p-2868L, 0xa.b053f78195d37f2p-2860L, 0xa.b053f78195d37f3p-2860L }, + { 0x2.c4d0c300d64c511p+7888L, 0xd.81985e859cf4061p+14748L, 0x1.a03cff013e09efbap+14764L, 0x1.a03cff013e09efbcp+14764L }, + { 0x2.3c05e4cb4622a66p-13256L, 0x3.cf39982caefbf098p-14636L, -0xc.53df31e9a942054p-14624L, -0xc.53df31e9a942053p-14624L }, + { 0x1.8dad3bd8dae62b26p+9496L, -0x3.f54fb00da54140bcp-6956L, -0x9.2d607d3aa28d78fp-6944L, -0x9.2d607d3aa28d78ep-6944L }, + { 0x1.53961f1d7569affp-5204L, -0x9.3feda7319eb8e46p+11244L, 0xb.c03c5caa9f7303ap+11256L, 0xb.c03c5caa9f7303bp+11256L }, + { 0x1.e3f51e1e159cf164p-1700L, -0x1.ee40d6991aa1e62cp-1968L, 0xc.d0607a66892a6d7p-1960L, 0xc.d0607a66892a6d8p-1960L }, + { 0xe.bee987bad9326dap-2508L, -0x3.a34a091c39f5bd5p-4752L, 0x2.39599d7487d87de4p-4740L, 0x2.39599d7487d87de8p-4740L }, + { 0x1.d1f2488e01bece42p+0L, 0x7.3390d5c71ae5e8f8p+4120L, 0x6.38e0cf11409a5648p+4120L, 0x6.38e0cf11409a565p+4120L }, + { 0x5.e2a8926a1f2a69f8p-1008L, -0x4.b1c091043808ebe8p+10972L, 0x1.26fe52f8e473663p+10984L, 0x1.26fe52f8e4736632p+10984L }, + { 0x1.8989c2560de848e8p+14156L, -0xf.7833feab3b30637p-11276L, -0x3.577473e6616fea3p-11260L, -0x3.577473e6616fea2cp-11260L }, + { 0x6.c87c79c7f39458b8p-12544L, 0xb.d70d015b5f04174p+8408L, -0x2.4408c9a20dd4504p+8424L, -0x2.4408c9a20dd4503cp+8424L }, + { 0xd.4a8d8fca0cbe02bp+5456L, 0x6.f866735c25236f98p+1300L, 0x9.4a80b93e0752cc4p+1312L, 0x9.4a80b93e0752cc5p+1312L }, + { 0x6.48ac3faff9ac8af8p+13024L, 0x1.62b2ac359758568p+3048L, 0x4.680ee828882103ep+3060L, 0x4.680ee828882103e8p+3060L }, + { 0xa.a22cceb5d16a7b9p+12552L, 0x1.e6ecf4dcc20e1c9ap+3900L, 0x5.d490ef450521d888p+3912L, 0x5.d490ef450521d89p+3912L }, + { 0x1.830dd48479f78adap+2696L, -0x1.3cbe7875c4da1bacp+13696L, -0xd.0872cbd8e0bf46bp+13704L, -0xd.0872cbd8e0bf46ap+13704L }, + { 0xa.c01d2e9cf20bab2p-3968L, -0x3.294bc4bc541628p-3004L, 0x3.0f54180488efda18p-2992L, 0x3.0f54180488efda1cp-2992L }, + { 0x3.e058d43b80e19b7cp+11400L, -0x7.810b603203760db8p+9496L, -0x1.4e392da4e7b28d82p+9512L, -0x1.4e392da4e7b28d8p+9512L }, + { 0x1.ba7195161943bbbep+12644L, -0x1.f393533d8bcf2b9p-6464L, -0x6.063e2d250c93d678p-6452L, -0x6.063e2d250c93d67p-6452L }, + { 0x1.1f75457p-16416L, -0x3.f70754c334988a7cp+7532L, 0xf.e400c62e39970d1p+7544L, 0xf.e400c62e39970d2p+7544L }, + { 0x3.731a5226115dd018p-10664L, -0x5.a44d891b492c118p+6688L, 0xe.afa29af29c307fp+6700L, 0xe.afa29af29c307f1p+6700L }, + { 0x5.b4fdcb6dd89d9c6p+11124L, -0xb.318ae2fc05a5137p-14500L, -0x1.e680e7664b81aa66p-14484L, -0x1.e680e7664b81aa64p-14484L }, + { 0x1.79ab15d5ea5af81ep-14952L, 0x4.f22aafc2c87dc378p+5960L, -0x1.20dd46df8b6d5d0ep+5976L, -0x1.20dd46df8b6d5d0cp+5976L }, + { 0x5.7ae9f319702197fp+1424L, -0x5.2488fe3916fe2e88p+10340L, -0x1.ca7d914199218ff6p+10352L, -0x1.ca7d914199218ff4p+10352L }, + { 0x1.7e566d05fa4bfe68p-11828L, -0xf.77808166e893761p+7896L, 0x2.ca9469fa524cdc5p+7912L, 0x2.ca9469fa524cdc54p+7912L }, + { 0xa.d514038a07e5b37p+12964L, 0x1.629f9336bc3a571p+1948L, 0x4.62b1beae45dbf53p+1960L, 0x4.62b1beae45dbf538p+1960L }, + { 0x4.3bf7a1a300a5f018p+10364L, -0xf.f30d3f07ad37473p+12984L, -0x2.85d5019bf4601528p+13000L, -0x2.85d5019bf4601524p+13000L }, + { 0x2.6b5061434883623p-9208L, 0x9.a456d030af10e3ap-14264L, -0x1.5ac2c899349909fp-14248L, -0x1.5ac2c899349909eep-14248L }, + { 0xe.89c1a581a13c8eap-12176L, -0x2.da80e03a956954f4p+13388L, 0x8.7ad8ca0015fc69dp+13400L, 0x8.7ad8ca0015fc69ep+13400L }, + { 0xf.0b6de12e05c3635p+10332L, 0x1.49091d3c30a38fe2p+8540L, 0x3.3e4b2c2a174d602p+8552L, 0x3.3e4b2c2a174d6024p+8552L }, + { 0x3.1086147p-16416L, -0xa.9787fe8322a2a72p-10772L, 0x2.a723d3adbf2fd25p-10756L, 0x2.a723d3adbf2fd254p-10756L }, + { 0x2.ce0956e8786046bp-8960L, 0x7.2bd571ac8ece1a28p-14644L, -0xf.af382fad626ef52p-14632L, -0xf.af382fad626ef51p-14632L }, + { 0x5.0c6e2ff0203fe848p+13020L, -0x1.07ec467a6a9c5c22p-8240L, -0x3.4715d4de6a6a238p-8228L, -0x3.4715d4de6a6a237cp-8228L }, + { 0x1.33b9813117d5b116p-8692L, -0x3.d4488a6e55d0c3cp+8188L, 0x8.202aab93e9336b5p+8200L, 0x8.202aab93e9336b6p+8200L }, + { 0x1.45a904169e9fbd9cp-6008L, -0x1.94df821b8722bfaep+11360L, 0x2.51d50e0975a72d2cp+11372L, 0x2.51d50e0975a72d3p+11372L }, + { 0x3.f58aff984b9b3204p+9232L, -0x3.a6650315666a36fcp-14312L, -0x8.3a7d9b2f7306025p-14300L, -0x8.3a7d9b2f7306024p-14300L }, + { 0x9.39fedfcb334646bp-480L, -0x1.f25409b8f76e0daap+11056L, 0x3.a02008fe8682753p+11064L, 0x3.a02008fe86827534p+11064L }, + { 0x6.0516ed4c30287198p+8164L, -0x1.7089f60565c4e04ep-6796L, -0x2.decaa14cd6f9a774p-6784L, -0x2.decaa14cd6f9a77p-6784L }, + { 0x8.d065ef1229a853cp+11308L, -0xd.57b3e95e8e6b01cp+2380L, -0x2.4d87e3ad36e3efc8p+2396L, -0x2.4d87e3ad36e3efc4p+2396L }, + { 0x2.fa1ba053149e004cp-656L, -0x2.7fd142bf349abf18p-2276L, 0x6.639940c58c55f74p-2268L, 0x6.639940c58c55f748p-2268L }, + { 0xf.c238b2baa010058p+9912L, 0x4.59241972fc24c5a8p+11548L, 0xa.86cb9e1cc4f0be8p+11560L, 0xa.86cb9e1cc4f0be9p+11560L }, + { 0x1.d646aaa62a9383e6p+0L, 0x3.00f84a86bb91dbap-6056L, 0x2.a2aaa0b9b93a6c6p-6056L, 0x2.a2aaa0b9b93a6c64p-6056L }, + { 0x2.77f437759361e3fp-2356L, -0x3.0610c5014f9956a8p-8032L, 0x1.bcfe133b031e1e7p-8020L, 0x1.bcfe133b031e1e72p-8020L }, + { 0x1.bc5bfdb21630a828p+4076L, -0x6.3a84a13517144a38p+4628L, -0x6.330ac4906176e618p+4640L, -0x6.330ac4906176e61p+4640L }, + { 0xd.6d13288b708cd99p+5852L, -0x4.2028a34835ab7088p+13624L, -0x5.e5e9658792a973fp+13636L, -0x5.e5e9658792a973e8p+13636L }, + { 0x2.fa0781a5ce6c3e88p+6884L, 0x1.c6c301a4213c2a1p+14212L, 0x2.fc79f81093748b58p+14224L, 0x2.fc79f81093748b5cp+14224L }, + { 0x5.9f857743c692f8a8p-11492L, -0x2.8b763c9b1e5765dcp+5088L, 0x7.23630afba9bef2cp+5100L, 0x7.23630afba9bef2c8p+5100L }, + { 0x7.a2e7744675542a68p+4476L, 0x9.93f484e751c1e49p+4604L, 0xa.792fe8f5fdd5e07p+4616L, 0xa.792fe8f5fdd5e08p+4616L }, + { 0x1.11daae277d6f5364p-8812L, -0x3.d9d851412428f74p+7268L, 0x8.48e4229b98372p+7280L, 0x8.48e4229b9837201p+7280L }, + { 0x1.599e76b4add8a768p+12640L, 0xc.0312220675c48dep-8384L, 0x2.511cd2efecb3462cp-8368L, 0x2.511cd2efecb3463p-8368L }, + { 0x1.d76fce983ea18f04p+3984L, 0xd.3b162e429a284abp-7116L, 0xc.df330f0e1231f7bp-7104L, 0xc.df330f0e1231f7cp-7104L }, + { 0x1.8b74ca29e35918d2p-436L, -0x2.54fefc87c991985p+2764L, 0x3.f74bbbe1e37fc588p+2772L, 0x3.f74bbbe1e37fc58cp+2772L }, + { 0xc.fb85e61563cc723p-4L, -0x1.5cd1de7bbfdd138p-14584L, 0x6.92b84a87a4b81f6p-14588L, 0x6.92b84a87a4b81f68p-14588L }, + { 0x4.06dfa8140d8a6c8p-12744L, -0x1.44ff72f9afcc807cp+10848L, 0x3.f303f71b131fd3d4p+10860L, 0x3.f303f71b131fd3d8p+10860L }, + { 0x1.5eaf968af0056a88p+2204L, -0x7.35ddb1c4dfd4818p+8056L, -0x3.e1706bd38b2ad348p+8068L, -0x3.e1706bd38b2ad344p+8068L }, + { 0x1.f79b47daf4ce0c82p+13516L, 0x4.7522f5f4f67f2aa8p-60L, 0xe.b5ccbbe59c33412p-48L, 0xe.b5ccbbe59c33413p-48L }, + { 0x1.45e7258945383cdap+1872L, -0x3.206a35c1d871c654p+3456L, -0x1.6de1f719d8e923e2p+3468L, -0x1.6de1f719d8e923ep+3468L }, + { 0x8.c482717e9cf14a6p-7368L, -0x2.9b72ec9fe7478ae8p-716L, 0x4.b01d9179e2b0c0c8p-704L, 0x4.b01d9179e2b0c0dp-704L }, + { 0x3.5aa11443b7f48ef8p-8396L, -0x1.5837711dfe654728p+5476L, 0x2.c16e15ae8bd79e5cp+5488L, 0x2.c16e15ae8bd79e6p+5488L }, + { 0x2.53bd4242192f7ab4p+14312L, -0x2.a60390f68f368cecp+9468L, -0x9.414718fc5f5020bp+9480L, -0x9.414718fc5f5020ap+9480L }, + { 0x3.7ce54eadcdde9f24p-3904L, -0x1.501e18a96a20b756p-1544L, 0x1.4036d2b1739a047cp-1532L, 0x1.4036d2b1739a047ep-1532L }, + { 0xd.5b4db41cff6f2cap+4432L, -0x1.570fa20acb2ddc2ep+13024L, -0x1.7384184ab61b5b9p+13036L, -0x1.7384184ab61b5b8ep+13036L }, + { 0x2.88f36222719718e8p-1928L, -0x4.fbec2f96890bc5e8p+6228L, 0x2.5829a880863725e8p+6240L, 0x2.5829a880863725ecp+6240L }, + { 0x1.efcbb15e88adf09p+0L, 0xc.97d62d013af0088p+8488L, 0xc.0241b42358d14d1p+8488L, 0xc.0241b42358d14d2p+8488L }, + { 0x5.f09eeb96dc538558p-4736L, 0x5.098d7678f15a72p-4304L, -0x5.d23c6567e92e3838p-4292L, -0x5.d23c6567e92e383p-4292L }, + { 0x1.0c3d81a001f325bep-3164L, -0x8.2d7911586469751p+564L, 0x6.51177426b609ff5p+576L, 0x6.51177426b609ff58p+576L }, + { 0xb.b5dda03bd01aa1bp-2384L, 0x3.80f852e5b49c1f08p-6208L, -0x2.0949885ea1918fccp-6196L, -0x2.0949885ea1918fc8p-6196L }, + { 0x4.7683b95a2d97f8ap-5156L, -0x4.35b7f1c56a3d2cbp+1424L, 0x5.4c0d70ada064bc7p+1436L, 0x5.4c0d70ada064bc78p+1436L }, + { 0x2.bdaaef3c4b35064p+11680L, -0x2.faa1909111fad7dcp+14388L, -0x8.7ef60bf38a0dd3ep+14400L, -0x8.7ef60bf38a0dd3dp+14400L }, + { 0x5.d46d6048b5d6e628p-9212L, 0xd.71bd470441c9db9p-9948L, -0x1.e3a6a527a3ea5d7ap-9932L, -0x1.e3a6a527a3ea5d78p-9932L }, + { 0x1.5f8f1649fa66406p+6520L, -0x1.63725477bb562e8cp+1156L, -0x2.35d6a805caba07c8p+1168L, -0x2.35d6a805caba07c4p+1168L }, + { 0xe.e3fdb321f26f9c4p+6484L, -0x3.b60b3167c404578p-3056L, -0x5.e0d492e2b6ee28b8p-3044L, -0x5.e0d492e2b6ee28bp-3044L }, + { 0x7.c4487897dc41f578p-5772L, 0x6.22ee9224c3c35c1p+10016L, -0x8.a49754c89a1f8f7p+10028L, -0x8.a49754c89a1f8f6p+10028L }, + { 0x2.db79f9dd4c22fe8p-11264L, -0x9.3987a9a321c2401p+48L, 0x1.95d5583932101174p+64L, 0x1.95d5583932101176p+64L }, + { 0xb.214592ce214ecfep-4L, -0x2.e889a996b77521fcp+10320L, 0x1.85db50a2a5f1944cp+10320L, 0x1.85db50a2a5f1944ep+10320L }, + { 0x6.80b6787c7ed0c98p-7488L, 0x2.6be4487c1dcd7bfp-1488L, -0x4.6cd4aeb3074b39c8p-1476L, -0x4.6cd4aeb3074b39cp-1476L }, + { 0x6.e3da0acb9e1505fp-2772L, -0x5.f7c7fac38340451p+11136L, 0x4.08e6346af3f436b8p+11148L, 0x4.08e6346af3f436cp+11148L }, + { 0x3.313fa5881a2d6e5cp-9600L, 0x2.1ac7da26f1204bfcp-2664L, -0x4.ee8c0326a97c7bf8p-2652L, -0x4.ee8c0326a97c7bfp-2652L }, + { 0x2.62f5aab737b6705p+4216L, -0xf.65bfa7da3df8702p-5984L, -0xf.da6fef5fb57dd6p-5972L, -0xf.da6fef5fb57dd5fp-5972L }, + { 0xc.e4018849b76a23ap+14856L, 0xc.90289d1db5a105cp-192L, 0x2.d93c0adf50cdc9bp-176L, 0x2.d93c0adf50cdc9b4p-176L }, + { 0x1.c0f835ea894de5f4p-10024L, -0xa.50a22423b6723b2p-2320L, 0x1.93dcf0ad050407e8p-2304L, 0x1.93dcf0ad050407eap-2304L }, + { 0x3.6383fb20c10cc778p+14900L, -0xa.7913fd7ca999ff9p-10828L, -0x2.61a190302a99bc9p-10812L, -0x2.61a190302a99bc8cp-10812L }, + { 0x1.be2aea0c1a473f64p+14204L, 0x3.b5e9eee471131f3p+4752L, 0xc.de458efd065f26ep+4764L, 0xc.de458efd065f26fp+4764L }, + { 0x1.21bc96f47956350ep+4740L, 0x7.f8fdeae69d08eb7p+8496L, 0x9.39fa9f5f9ddd9a5p+8508L, 0x9.39fa9f5f9ddd9a6p+8508L }, + { 0x4.9f7437754e62375p-4876L, -0x4.90b85f6fbc1b8688p+8944L, 0x5.6ea6245478d9c558p+8956L, 0x5.6ea6245478d9c56p+8956L }, + { 0x7.e866902p-16416L, 0xf.317f8a3f97460cep-7188L, -0x3.ce18bf0bbbe749e4p-7172L, -0x3.ce18bf0bbbe749ep-7172L }, + { 0x6.a13f4e0f825a5edp-4440L, -0x1.99bf7b4b74e4b654p+5044L, 0x1.bbe32d09c4b547a2p+5056L, 0x1.bbe32d09c4b547a4p+5056L }, + { 0x7.54085e25bafd5bd8p+3704L, 0x1.db179fdf5aef456ap-13196L, 0x1.adf52fae66292f0ep-13184L, 0x1.adf52fae66292f1p-13184L }, + { 0x6.fc29f1b82c7f8a7p-1712L, 0x7.3136749a8e732cbp+12372L, -0x3.004f0ed0aea3e038p+12384L, -0x3.004f0ed0aea3e034p+12384L }, + { 0xe.2487cdb8e096076p-1392L, -0x2.b7d3c8f4fa93f2dcp-11416L, 0xe.bd2c23a004fef05p-11408L, 0xe.bd2c23a004fef06p-11408L }, + { 0x1.0a524b330b6d1cf8p+3992L, 0x6.f2be0ff2b50477ap-88L, 0x6.c59a9376d2d243f8p-76L, 0x6.c59a9376d2d244p-76L }, + { 0x4.53290c103cf68ddp+1876L, -0x2.7b48218ca4945d54p-184L, -0x1.234aab65fdcc0972p-172L, -0x1.234aab65fdcc097p-172L }, + { 0x5.f854a5860d3485fp+11712L, 0x3.e2501079eb01d518p-972L, 0xb.1bbd2067493cbf4p-960L, 0xb.1bbd2067493cbf5p-960L }, + { 0x7.c586111d11b319f8p-13432L, -0x1.a13ae4a3354b1b9cp-4876L, 0x5.57eb7cb8deede698p-4864L, 0x5.57eb7cb8deede6ap-4864L }, + { 0x8.d2126b4d376bf71p+6480L, -0xb.c76f499facfc4cbp+5248L, -0x1.2a4d3012ac4367c2p+5264L, -0x1.2a4d3012ac4367cp+5264L }, + { 0x8.af0132d6f3c8239p-1932L, 0x2.179549e27c305d7p-7188L, -0xf.c3748e5a2f3e907p-7180L, -0xf.c3748e5a2f3e906p-7180L }, + { 0xa.e384039aa141762p-4L, -0xd.84901915b6223efp+3372L, 0x7.816daa88ba083fbp+3372L, 0x7.816daa88ba083fb8p+3372L }, + { 0x7.a25f680376b80218p+10772L, 0x1.fa22f565869b428ep-7916L, 0x5.337133b5a9625a98p-7904L, 0x5.337133b5a9625aap-7904L }, + { 0x1.a82f4735f426182cp+708L, -0x3.06c97154863b8668p+11728L, -0x8.60f995bea7d1f3ep+11736L, -0x8.60f995bea7d1f3dp+11736L }, + { 0x6.f0206ea828b61b08p+6012L, 0x3.551406b5d024e324p-4656L, 0x4.e4b523f064ac9a2p-4644L, 0x4.e4b523f064ac9a28p-4644L }, + { 0x1.6f789d7564f928e8p-3864L, 0x5.4600f951d5eba66p-9312L, -0x4.f95deb0b036b9c7p-9300L, -0x4.f95deb0b036b9c68p-9300L }, + { 0x3.0a8648ba053122fp-1060L, 0x1.91cf22af1ab650a4p+7572L, -0x6.7d38ed8edc9459e8p+7580L, -0x6.7d38ed8edc9459ep+7580L }, + { 0x8.bc7d07ddb2c022p+5920L, 0x6.10774af59183db48p+4288L, 0x8.c4fbd3cdc063727p+4300L, 0x8.c4fbd3cdc063728p+4300L }, + { 0x3.5799356238e9851p+9016L, 0xa.169ce0f7fec2be6p+12212L, 0x1.635df4dc89456662p+12228L, 0x1.635df4dc89456664p+12228L }, + { 0x1.01d4b210da78dd4cp+11956L, -0x6.e1bf3c78ece6063p+10052L, -0x1.41672971127f38a4p+10068L, -0x1.41672971127f38a2p+10068L }, + { 0xf.d84c5b3d6730ba3p+8852L, -0x1.9f855997d2792acep-6872L, -0x3.826673c9aa64c2c4p-6860L, -0x3.826673c9aa64c2cp-6860L }, + { 0x5.8ce7c53b96255d4p+13568L, -0xe.df6fe073a22e50cp-12344L, -0x3.1466efb79f69482p-12328L, -0x3.1466efb79f69481cp-12328L }, + { 0x6.75dca56p-16416L, -0x5.d3093bb8c581a6e8p-10216L, 0x1.756d02c70d3f1626p-10200L, 0x1.756d02c70d3f1628p-10200L }, + { 0xc.d570e244c0e60bep-12400L, -0x7.8ae826298b8c69ap+11848L, 0x1.6d3c875ec58ba32ap+11864L, 0x1.6d3c875ec58ba32cp+11864L }, + { 0x7.84802e101bb6a3f8p-5756L, -0x7.995991a529314d5p+2864L, 0xa.ac5dc693017439dp+2876L, 0xa.ac5dc693017439ep+2876L }, + { 0x1.25970c4a9d9bfa12p+4480L, -0x1.2660afac683e1d8ep+14004L, -0x1.41fd632043cb071ep+14016L, -0x1.41fd632043cb071cp+14016L }, + { 0x1.c8b98918c3fb8242p-364L, 0x9.c0fa6e13b7c7fcp-2056L, -0xd.d63ea6a5acb5b84p-2048L, -0xd.d63ea6a5acb5b83p-2048L }, + { 0x2.b29ea16d605290c8p-14036L, 0x2.57c6bfd9ce8106fp-4776L, -0x8.07142545c68a338p-4764L, -0x8.07142545c68a337p-4764L }, + { 0x1.179a8074009c3446p-7324L, -0x8.1c9d05645c7987cp-4408L, 0xe.811940c7fc9af73p-4396L, 0xe.811940c7fc9af74p-4396L }, + { 0x1.a274b5d250ba4a7ap-14136L, -0x9.4cf62e7e77f656p-7444L, 0x2.018b21e6dce1dfacp-7428L, 0x2.018b21e6dce1dfbp-7428L }, + { 0x1.426ce0de34aa412ap-7048L, -0x1.086b031d68e9f6fap-7232L, 0x1.c6f6a2cc131aca9p-7220L, 0x1.c6f6a2cc131aca92p-7220L }, + { 0x6.dcdeb470b2fc188p+14208L, 0x2.0ff586b55e3364a4p-8660L, 0x7.27b75caeddd08bdp-8648L, 0x7.27b75caeddd08bd8p-8648L }, + { 0xf.30d46d764112444p+192L, -0x5.e6a539ee1aceb9b8p-2624L, -0x4.84256283872b606p-2616L, -0x4.84256283872b6058p-2616L }, + { 0xa.8afac152291530ap-4L, -0x5.9e1738c1ccd8a9a8p-20L, 0x3.617206ff8982409cp-20L, 0x3.617206ff898240ap-20L }, + { 0xa.4bd5c8afa05a28cp-10580L, -0x1.23804bdf5e1e2c04p+9232L, 0x2.f0b5da03924596b4p+9244L, 0x2.f0b5da03924596b8p+9244L }, + { 0x2.ceafdb5372991918p+2280L, 0x7.bc4dc1a54a48fdbp+5068L, 0x4.4f099a01d4cd5418p+5080L, 0x4.4f099a01d4cd542p+5080L }, + { 0x3.fc5a846dfbec9adp-9172L, 0x3.b4c03ba6cf5a812p-3940L, -0x8.4c092babb4e1d41p-3928L, -0x8.4c092babb4e1d4p-3928L }, + { 0x3.14be1ced6c3553bcp+1944L, -0xa.e04dd91094312efp-2976L, -0x5.2a8f73a173accdb8p-2964L, -0x5.2a8f73a173accdbp-2964L }, + { 0x2.2c4ef645ea46758p+8712L, 0x6.d3f30796d0334a7p+11056L, 0xe.8648bda7e0f6294p+11068L, 0xe.8648bda7e0f6295p+11068L }, + { 0x4.b6b357f4259a83ap-10956L, -0x8.d45410dc1895ef4p+11920L, 0x1.79cb3dbc67eac20cp+11936L, 0x1.79cb3dbc67eac20ep+11936L }, + { 0x4.38896f39ca42f888p-5568L, 0x5.28bf133fa6f14d3p-3772L, -0x7.02b83fde3a8b00dp-3760L, -0x7.02b83fde3a8b00c8p-3760L }, + { 0x1.6739091433ebe3bap+7952L, 0x3.77db8ced789b50ep-4560L, 0x6.bbcc5b6ebb15a848p-4548L, 0x6.bbcc5b6ebb15a85p-4548L }, + { 0x2.6e82f4e37e55fa08p+480L, 0x7.f37ea4723b67675p+10636L, 0xe.f2bedee5c61d497p+10644L, 0xe.f2bedee5c61d498p+10644L }, + { 0x1.5fac4bb395ba2bccp+4156L, -0x4.ad1adda7354f267p-4744L, -0x4.bec64886a213215p-4732L, -0x4.bec64886a2132148p-4732L }, + { 0x2.a62a7e9p-16416L, -0x1.08fba0f001a4ad6p+6040L, 0x4.25e934181bdf777p+6052L, 0x4.25e934181bdf7778p+6052L }, + { 0x1.749ae18d5c47f94ep-13280L, 0x5.d580a2b2bafe339p-6680L, -0x1.2ea0483b70c44786p-6664L, -0x1.2ea0483b70c44784p-6664L }, + { 0x1.58297b3f01d01614p+4120L, 0x1.0f95b19865e46e46p-848L, 0x1.1134515c360fd09ep-836L, 0x1.1134515c360fd0ap-836L }, + { 0x4.a3a8a81ba62dd2ep+10816L, -0x7.dc627c37bc9c54d8p-7548L, -0x1.4c30a83a929ac21ep-7532L, -0x1.4c30a83a929ac21cp-7532L }, + { 0x7.289dc72de566113p-2256L, 0x4.98b3897e6f049388p-13832L, -0x2.874a0b468128b94cp-13820L, -0x2.874a0b468128b948p-13820L }, + { 0x9.8f2b30dd1fe6e25p-4736L, -0x2.78a78fa09bce90f4p-9784L, 0x2.db00f635c2145e2cp-9772L, 0x2.db00f635c2145e3p-9772L }, + { 0x5.c89b4377f34a817p+6700L, -0x1.8aae5b4631e05fa4p-348L, -0x2.85d728f29858853cp-336L, -0x2.85d728f298588538p-336L }, + { 0x5.a8ced3fe21a70d68p-4096L, 0x5.2deec40853fa524p-1044L, -0x5.2d1f88ec24116c38p-1032L, -0x5.2d1f88ec24116c3p-1032L }, + { 0x2.7d2734d21b77549p-2196L, 0x8.aa549d7c779757cp-9208L, -0x4.a49b7a241fea8f4p-9196L, -0x4.a49b7a241fea8f38p-9196L }, + { 0x7.b8041d5b3bbff3ap+12080L, 0x6.cbce06dc637006ep-13696L, 0x1.40c5137e55d4c17ep-13680L, 0x1.40c5137e55d4c18p-13680L }, + { 0x2.fc10d82242c59c8cp-12304L, -0x7.6637c2344d0ca91p+5988L, 0x1.63952bab4a1661f6p+6004L, 0x1.63952bab4a1661f8p+6004L }, + { 0x7.eceb7efp-16416L, -0x1.0130744d8cd6c3f2p+7712L, 0x4.0694309a8adc05bp+7724L, 0x4.0694309a8adc05b8p+7724L }, + { 0x5.64bdddf529c9a6dp-9832L, -0x6.58f61fd8c5e3ec6p+3184L, 0xf.3b93e106624f0dp+3196L, 0xf.3b93e106624f0d1p+3196L }, + { 0x1.990690db94ff14d8p-2496L, -0x1.6f80a4634a39b2d2p-992L, 0xd.fe2dcfcc7595336p-984L, 0xd.fe2dcfcc7595337p-984L }, + { 0x9.fb2ddd234c8a1e1p-6780L, -0xa.5203c030e1c9aa7p-11896L, 0x1.1131d9f0246b6b0cp-11880L, 0x1.1131d9f0246b6b0ep-11880L }, + { 0xf.3050779847dc78ep-15004L, 0x3.95b4f2d22803a954p-1624L, -0xd.20c275868938d06p-1612L, -0xd.20c275868938d05p-1612L }, + { 0x6.7697c3e239db107p+10048L, 0x1.21545bdaae9fde28p-9920L, 0x2.c5f3a0898c76a22p-9908L, 0x2.c5f3a0898c76a224p-9908L }, + { 0x2.c39c3b1642e4fb18p-13664L, 0x1.1fc8462fb1f9d056p+988L, -0x3.bfebb82e0cc421ap+1000L, -0x3.bfebb82e0cc4219cp+1000L }, + { 0x2.ff120c969ae503b8p+3064L, -0x2.431fbfb49e7b4928p-9856L, -0x1.b16f8df41d25490ap-9844L, -0x1.b16f8df41d254908p-9844L }, + { 0x6.976ed0ef48c07898p-8216L, -0x4.6c8e610cee69d8dp-12772L, 0x8.deff03b117f428dp-12760L, 0x8.deff03b117f428ep-12760L }, + { 0x2.6fa1664ea3a1be14p-2884L, 0x1.63214b8ba5b95b7cp-3720L, -0xf.9efae89cadca879p-3712L, -0xf.9efae89cadca878p-3712L }, + { 0x2.e1cf29eba91248ep-152L, -0x4.589495f2b172e14p+5176L, 0x2.8df5325dc46aa2a4p+5184L, 0x2.8df5325dc46aa2a8p+5184L }, + { 0x5.bdc83bdp-16416L, -0x1.5a0086d9ae7633cep+10348L, 0x5.6a7f95f9b29fe038p+10360L, 0x5.6a7f95f9b29fe04p+10360L }, + { 0x1.3bc8b60293078f84p-11188L, -0xd.1712b08be6e7f9cp-7148L, 0x2.3c10661bfd903a2cp-7132L, 0x2.3c10661bfd903a3p-7132L }, + { 0x1.e7590332a0320ee4p+4180L, -0x8.c39f3bc3d0d8d73p+1072L, -0x8.f2247e086109516p+1084L, -0x8.f2247e086109515p+1084L }, + { 0x6.4a24ad49492e8648p-9284L, -0xf.be9fc104f449286p+7428L, 0x2.3ad3547099aaf9e8p+7444L, 0x2.3ad3547099aaf9ecp+7444L }, + { 0xf.8fb50e1402f38bp-4824L, 0x2.9deafdf9778819d4p+2484L, -0x3.1456753ac5fc7a9cp+2496L, -0x3.1456753ac5fc7a98p+2496L }, + { 0xd.3ea27eab88fb691p+14284L, -0x1.cba84ae0173bf72p+3824L, -0x6.436237e69f433458p+3836L, -0x6.436237e69f43345p+3836L }, + { 0x1.fbcc353d750f0c24p-6280L, -0xc.2cc3adaa5f76bd8p-8112L, 0x1.2a9e188779743a3ap-8096L, 0x1.2a9e188779743a3cp-8096L }, + { 0x5.1653c9d362cef54p-14708L, -0xb.c9870bb9c74469p+5028L, 0x2.a51ab90a18a8738cp+5044L, 0x2.a51ab90a18a8739p+5044L }, + { 0x7.36b4057f96e568dp+8176L, -0xf.f37001ee9d18068p-6500L, -0x1.fd9c420b6f4867fcp-6484L, -0x1.fd9c420b6f4867fap-6484L }, + { 0x1.f1d5273873448298p-7948L, -0xd.38eafd3878fe2f4p+14696L, 0x1.9a766fcad504a18cp+14712L, 0x1.9a766fcad504a18ep+14712L }, + { 0xe.2ad91bdabc94c8ap+4988L, 0x3.95448e4e9f0ea9ap-13040L, 0x4.5de17dc1f4a7fab8p-13028L, 0x4.5de17dc1f4a7facp-13028L }, + { 0x6.99d9f3e8p-16416L, -0x1.ad91e546b1cb6ebap-9228L, 0x6.b9599f96d124ec8p-9216L, 0x6.b9599f96d124ec88p-9216L }, + { 0x1.f5e39c6453df56cep+3976L, -0xd.82073d1dadfc559p-13696L, -0xd.1d89ef310c16451p-13684L, -0xd.1d89ef310c1645p-13684L }, + { 0xb.edb1abf0414bf32p+4928L, -0xd.e8fd8b2f5f7e274p-1624L, -0x1.0bf6d0071c8443aap-1608L, -0x1.0bf6d0071c8443a8p-1608L }, + { 0x2.4441537d38fcde3p-10736L, 0x6.d2a95499ed5d399p+8560L, -0x1.1e1a8f495e7a1a52p+8576L, -0x1.1e1a8f495e7a1a5p+8576L }, + { 0x8.350f634f3bac009p+8676L, -0x2.d48a8e03034cffdcp+14208L, -0x5.ff3c0112847868d8p+14220L, -0x5.ff3c0112847868dp+14220L }, + { 0x3.216932500e2c85ecp+14080L, -0x1.476cc48b95f9d5p-716L, -0x4.65a794c5d3743b58p-704L, -0x4.65a794c5d3743b5p-704L }, + { 0x2.db319188f62c89e8p+988L, 0xe.a63c4600dc01d8cp-424L, 0x3.89fbee2ba66bc188p-412L, 0x3.89fbee2ba66bc18cp-412L }, + { 0x6.6aaa7a664cf96818p-3528L, -0x7.5c73f3fe919f4e7p-888L, 0x6.55e60356eb25c59p-876L, 0x6.55e60356eb25c598p-876L }, + { 0x5.916df5368bba491p-3112L, -0x2.9cfe9de6a3ad4c88p+12520L, 0x1.fbdfdf6fbd783f8cp+12532L, 0x1.fbdfdf6fbd783f8ep+12532L }, + { 0x8.e258363c3897569p-6168L, -0x1.72e257e109bc36bap+2524L, 0x2.2e36cb7155364494p+2536L, 0x2.2e36cb7155364498p+2536L }, + { 0x4.488a31c8bf6dbcp-13868L, -0x2.d5e7d27c5355e4ap+6356L, 0x9.995b6c142be9f9fp+6368L, 0x9.995b6c142be9fap+6368L }, + { 0xc.5cffd705c24a0c2p-4L, -0x9.01d522cef5d12afp-4668L, 0x3.59cb3ebcfd0a1f08p-4668L, 0x3.59cb3ebcfd0a1f0cp-4668L }, + { 0xb.40f77e9360b0776p-8424L, -0x1.c31d691fcbc9a998p-8380L, 0x3.9f658593c3b5b0ap-8368L, 0x3.9f658593c3b5b0a4p-8368L }, + { 0x7.1c785eecfe17605p+12952L, 0x6.81abff3b56ebed6p-4116L, 0x1.4942fffbc4b683b8p-4100L, 0x1.4942fffbc4b683bap-4100L }, + { 0x7.8201396b65470528p-8188L, -0x3.463d9ddfcf13487cp-10432L, 0x6.8b114d5e19d248fp-10420L, 0x6.8b114d5e19d248f8p-10420L }, + { 0x7.70d516c2a2b3b3dp-4152L, -0x8.126b2caac3c5943p-4996L, 0x8.2d35b07156a52abp-4984L, 0x8.2d35b07156a52acp-4984L }, + { 0x3.cd97932b489ad858p+6780L, -0xf.c42863b5a2d0232p-12656L, -0x1.a1ad801137893564p-12640L, -0x1.a1ad801137893562p-12640L }, + { 0x1.9396ff2d623e5408p+14096L, 0x3.9d32507b559b865cp-1176L, 0xc.702020e071d0773p-1164L, 0xc.702020e071d0774p-1164L }, + { 0x1.ed679d88b04f7fap+6264L, -0x4.b3d263673481a9ep-12932L, -0x7.31477827f160e46p-12920L, -0x7.31477827f160e458p-12920L }, + { 0x1.eae89eef96814ca6p-1852L, 0x3.a339fc1c50b7b174p-4092L, -0x1.a4d6cc5ce493c0cep-4080L, -0x1.a4d6cc5ce493c0ccp-4080L }, + { 0x1.707c24b46d461048p-14368L, 0x2.56890e2696270f18p+3396L, -0x8.33791b84ac10fa8p+3408L, -0x8.33791b84ac10fa7p+3408L }, + { 0xa.f782f5eeaaf84b2p-8396L, 0x4.8ac0d484844b719p-12612L, -0x9.4e6fad33abacc8cp-12600L, -0x9.4e6fad33abacc8bp-12600L }, + { 0x6.75f9102p-16416L, 0x1.c215aac2787d684ep-6028L, -0x7.0b8f1e582b0f2ac8p-6016L, -0x7.0b8f1e582b0f2acp-6016L }, + { 0x1.8e028ccf9407e7b6p-10456L, 0x2.6587235c80541de4p-8072L, -0x6.1e140f05b8db7f18p-8060L, -0x6.1e140f05b8db7f1p-8060L }, + { 0x1.da364cbdabbc25dcp+3776L, -0x3.e477a90405bea618p+5096L, -0x3.96d5b3c2d4f9d27p+5108L, -0x3.96d5b3c2d4f9d26cp+5108L }, + { 0x4.8ccd46cc6510b538p-6440L, 0x3.68c9ba824b18c688p-14052L, -0x5.5bc9eef09da496f8p-14040L, -0x5.5bc9eef09da496fp-14040L }, + { 0x1.5523bc7caa2a7b4p-2360L, 0xf.e04552139a2f6a5p+7728L, -0x9.254eb8dbb10de6p+7740L, -0x9.254eb8dbb10de5fp+7740L }, + { 0x3.5e00cae7d345aa9cp-13704L, -0x5.e5c76fe79a2907cp+13180L, 0x1.3baa07aa98aaf93ep+13196L, 0x1.3baa07aa98aaf94p+13196L }, + { 0x6.d8686db27423ce58p+1772L, -0x1.dd67447223055ad4p+10804L, -0xc.edb3a82a0914dc7p+10812L, -0xc.edb3a82a0914dc6p+10812L }, + { 0x5.81ac23cc9814dc5p+8424L, -0x1.82aa76204a55d282p-6048L, -0x3.1b770e30bffad924p-6036L, -0x3.1b770e30bffad92p-6036L }, + { 0xc.6ab94dcea227508p-14696L, -0x7.9584757e89e7c55p-5412L, 0x1.b343ac0c30e5ed04p-5396L, 0x1.b343ac0c30e5ed06p-5396L }, + { 0x8.f16bb6cf2395a1bp+7192L, -0x1.1a54811d7af3bd8cp+7552L, -0x1.eff326c8340b378ap+7564L, -0x1.eff326c8340b3788p+7564L }, + { 0x3.ce0c67c37ccec814p-14228L, 0xa.955a451a8e75c69p-8560L, -0x2.4c2055cf200b6e7p-8544L, -0x2.4c2055cf200b6e6cp-8544L }, + { 0x6.a4757b88p-16416L, 0x1.e49fe1c472843028p-4008L, -0x7.95f6092fae66987p-3996L, -0x7.95f6092fae669868p-3996L }, + { 0xe.71c46c73262a925p+3408L, 0x6.65257962db253ac8p-8876L, 0x5.53b25e184835333p-8864L, 0x5.53b25e1848353338p-8864L }, + { 0x1.3780298260776f1ep+10420L, -0x1.11661cd09cc6ff86p-308L, -0x2.b787db272797c17cp-296L, -0x2.b787db272797c178p-296L }, + { 0x1.fa3248ab7314fcfep-2564L, -0x2.384d1920955542p+12332L, 0x1.639b53b49c911ccap+12344L, 0x1.639b53b49c911cccp+12344L }, + { 0x2.72eeaa978efe1234p-6844L, 0x5.9b815458ba3ed0ap-10020L, -0x9.5e216a1ccb17dd4p-10008L, -0x9.5e216a1ccb17dd3p-10008L }, + { 0x4.6b38b0944800a92p-3652L, 0x1.06c7deaa434edd72p+6760L, -0xe.a287f40f40e33c8p+6768L, -0xe.a287f40f40e33c7p+6768L }, + { 0xc.e16733773c8f71ep+7968L, 0x1.d1a8610ef9653c2cp+6540L, 0x3.8a44dbbe5691ada4p+6552L, 0x3.8a44dbbe5691ada8p+6552L }, + { 0x5.fb96128dcb851d9p+6848L, 0x2.b75c4b387bdde9e8p+6840L, 0x4.8afe7743710b6da8p+6852L, 0x4.8afe7743710b6dbp+6852L }, + { 0x3.f58649c18725aaa8p+480L, -0x1.df1ad5bab9cc8704p+5396L, -0x3.86096aedbe0ccf84p+5404L, -0x3.86096aedbe0ccf8p+5404L }, + { 0x3.8c7468635255c36cp-9848L, -0x1.2d4a9bc2537a65c2p+6172L, 0x2.d44278d5964e9308p+6184L, 0x2.d44278d5964e930cp+6184L }, + { 0x1.266933c47623dcf2p+1504L, 0x1.9f5956a11f8d8a1cp+4848L, 0x9.8880a23f0954318p+4856L, 0x9.8880a23f0954319p+4856L }, + { 0x7.ee162358p-16416L, -0x7.b20cc9e4d310231p-6740L, 0x1.ed6276e44234215ep-6724L, 0x1.ed6276e44234216p-6724L }, + { 0xd.a2dd238869b2787p-1832L, 0x1.a987e218c6f17582p-4964L, -0xb.def06e8887e84fcp-4956L, -0xb.def06e8887e84fbp-4956L }, + { 0x6.d06d1c60a261b25p+13856L, -0x5.9e57359c4cf1067p+13824L, -0x1.3029be4f0d001bb4p+13840L, -0x1.3029be4f0d001bb2p+13840L }, + { 0xf.5afa51a915c3c2cp-7724L, -0x5.399276f16adbba7p-8016L, 0x9.d90782db4be7b57p-8004L, 0x9.d90782db4be7b58p-8004L }, + { 0x1.37ae53977fcc991cp+11588L, 0xc.cf5f343691ea8ecp+3336L, 0x2.43de7490fbe55f28p+3352L, 0x2.43de7490fbe55f2cp+3352L }, + { 0xb.916f204d9b607e2p-9652L, -0x1.35296e508f235de2p+2664L, 0x2.d841a1731ad9bf24p+2676L, 0x2.d841a1731ad9bf28p+2676L }, + { 0x7.986b2cd7ddf22268p+8064L, -0x2.2a06bf374755863cp-5488L, -0x4.432291fb48046c6p-5476L, -0x4.432291fb48046c58p-5476L }, + { 0x6.37c853b0413d5448p-11920L, 0x7.ff7a53a9d88503bp-13652L, -0x1.745299d0aed002f4p-13636L, -0x1.745299d0aed002f2p-13636L }, + { 0x6.4c2eb46758106918p+14296L, 0x4.fbd427830e0b7d98p-8500L, 0x1.165c4a9036705c38p-8484L, 0x1.165c4a9036705c3ap-8484L }, + { 0x6.24db1d64d95cf55p-336L, 0x6.d057f880739cc278p+14360L, -0x8.df9aba4673d5941p+14368L, -0x8.df9aba4673d594p+14368L }, + { 0xb.1981c21be406601p-3972L, 0x2.029bd5f255e8a35p-10848L, -0x1.f297ef0c6b6837e8p-10836L, -0x1.f297ef0c6b6837e6p-10836L }, + { 0x6.74e6ebd8p-16416L, 0xb.151703cbe7e3038p+8672L, -0x2.c68a91d35a06273p+8688L, -0x2.c68a91d35a06272cp+8688L }, + { 0xa.37e2d7be2859c8bp-1596L, -0x1.c4a435d45ba8988ap+7536L, 0xb.000200ece72bb1cp+7544L, 0xb.000200ece72bb1dp+7544L }, + { 0x2.916b7b8ed46e92ccp-4368L, -0x3.037efdf978c84bfcp-8832L, 0x3.3678d0ccdadaeffp-8820L, 0x3.3678d0ccdadaeff4p-8820L }, + { 0x7.6c639e488208ccc8p-2160L, 0x3.a1d6c7b434bf3d98p-12244L, -0x1.e9b030a027bc75dp-12232L, -0x1.e9b030a027bc75cep-12232L }, + { 0x1.70d6044fbe0cb0d2p-8188L, -0x1.7afb318a61f2f0eap-536L, 0x2.f58b29b59e1cd59p-524L, 0x2.f58b29b59e1cd594p-524L }, + { 0x1.3e90b4eb0efaf5fap+7324L, -0x2.96cfd9fbb50bcd78p-1116L, -0x4.a1373950c6aeb928p-1104L, -0x4.a1373950c6aeb92p-1104L }, + { 0x4.6f9a694c1cfb65dp-8964L, -0x1.0df2b52efca96a9ep+1968L, 0x2.4ea226124824d4f4p+1980L, 0x2.4ea226124824d4f8p+1980L }, + { 0x1.d6566fbbd43703bcp-4852L, -0xa.f8b1cd8907eb113p+7616L, 0xc.fe7e9244b013f7bp+7628L, 0xc.fe7e9244b013f7cp+7628L }, + { 0x1.1a90813aa3baaae6p-3212L, 0x1.07b9974764beed82p-7712L, -0xc.ecc705b170e316ap-7704L, -0xc.ecc705b170e3169p-7704L }, + { 0x6.af86ac96f68ccc18p-5372L, -0x1.5877065aa0076e0ep+9668L, 0x1.c38b175b4ec73c6ep+9680L, 0x1.c38b175b4ec73c7p+9680L }, + { 0x5.0830fc79162b51p+732L, 0x7.a0e695df486975a8p-456L, 0x1.5e1dbcc4c6615ef2p-444L, 0x1.5e1dbcc4c6615ef4p-444L }, + { 0x4.1e9381b2498bde9p-4L, -0x5.318485c71566c348p-10692L, 0xa.2a99b81fbb45d58p-10692L, 0xa.2a99b81fbb45d59p-10692L }, + { 0x3.aa23634217ae0ec4p+8196L, -0xe.31f0ba646c8980ep-56L, -0x1.c69177d12e2f164p-40L, -0x1.c69177d12e2f163ep-40L }, + { 0x5.f1ebb70f25fab228p+148L, -0x1.5c7f22ee7bdcb97ap+12792L, -0xc.cf9b8c1bbde569fp+12796L, -0xc.cf9b8c1bbde569ep+12796L }, + { 0x6.64a485a65ba2bb8p-6848L, -0xb.ab5d793764e46aap-4044L, 0x1.3808c8a9a9457a22p-4028L, 0x1.3808c8a9a9457a24p-4028L }, + { 0x2.0c076822c45b5c2p+3820L, 0xc.6d1ace4fdfc0995p-11720L, 0xb.978e3acafba5dep-11708L, 0xb.978e3acafba5de1p-11708L }, + { 0x2.c4adada59c4f74cp+356L, 0x8.cb9c5966f2f6535p+664L, 0xc.481102c34516cep+672L, 0xc.481102c34516ce1p+672L }, + { 0x1.4690bd92b944f1e6p-1756L, 0x1.89dd6b86aed3c6ep-12820L, -0xa.8d20776fa7c107fp-12812L, -0xa.8d20776fa7c107ep-12812L }, + { 0x1.e645a04ffd7fcf32p+8988L, -0x7.4662a44eadea0868p+5320L, -0xf.f71eb1d0013d055p+5332L, -0xf.f71eb1d0013d054p+5332L }, + { 0x4.332914d9e18063ap-10904L, 0x2.c3783d61fd7041fcp+14952L, -0x7.5b010c3479470088p+14964L, -0x7.5b010c347947008p+14964L }, + { 0x7.8ea9558f03ae0e7p+3360L, -0x3.f7ba4222d04d157cp+7040L, -0x3.41f0065a9b4f0258p+7052L, -0x3.41f0065a9b4f0254p+7052L }, + { 0x4.16fc729b9ce4dc58p-12344L, 0x5.91be30b46d5b46d8p+8916L, -0x1.0c803996b4e5dd76p+8932L, -0x1.0c803996b4e5dd74p+8932L }, + { 0x1.9ff000dcf3194afap+0L, -0xb.402101043dda93fp+8464L, -0x7.e0bb855f276d611p+8464L, -0x7.e0bb855f276d6108p+8464L }, + { 0x3.c1bd5f7eaf2aefbcp-3452L, 0x3.5060ef99941b0558p-28L, -0x2.ca98723a104a705cp-16L, -0x2.ca98723a104a7058p-16L }, + { 0x7.40f69af37414a67p-4984L, 0x9.76424abbc94834ap+8128L, -0xb.81b4e09a2241edap+8140L, -0xb.81b4e09a2241ed9p+8140L }, + { 0x2.a7771004562ceed4p+14300L, 0x1.6959757c92243a3ap-3048L, 0x4.edabdfe0f6ebfd28p-3036L, 0x4.edabdfe0f6ebfd3p-3036L }, + { 0x3.5def153aa1e1859cp-12528L, 0x2.e3b7b35774e3683p-11336L, -0x8.d62de479ad0aa6p-11324L, -0x8.d62de479ad0aa5fp-11324L }, + { 0x3.60afa9401fa21cb4p+13964L, -0x3.918ec1969b0edd88p+1908L, -0xc.2adfb245bfe4ad7p+1920L, -0xc.2adfb245bfe4ad6p+1920L }, + { 0x1.dec8e34ee760457ap-3276L, -0xc.f9ac1534d437324p-4104L, 0xa.5ff4de0ac7cf5eap-4092L, 0xa.5ff4de0ac7cf5ebp-4092L }, + { 0x3.40a43e7617430e38p-6876L, -0x1.21e9e8c12fbb68ap+0L, 0x1.e68f95a0715b74ecp+12L, 0x1.e68f95a0715b74eep+12L }, + { 0x6.e391c60d69e57e48p+14204L, -0x3.ab05dd3dc0cb47fcp-5284L, -0xc.b8f4fe0c2d1d37dp-5272L, -0xc.b8f4fe0c2d1d37cp-5272L }, + { 0x4.7e30a9e329ebbe38p-3820L, -0x2.029c31080003b2e4p-2628L, 0x1.dfa972c247b7e80ep-2616L, 0x1.dfa972c247b7e81p-2616L }, + { 0x5.040eb8c257682f18p+12468L, -0x1.ee68d5b05c315f0ap-10428L, -0x5.e13c804f6f999478p-10416L, -0x5.e13c804f6f99947p-10416L }, + { 0x7.8e68dbe249d1df3p-4L, -0x1.9e8c3ea1db7772dep+1124L, 0x1.c0aca5bb6957525ep+1124L, 0x1.c0aca5bb6957526p+1124L }, + { 0x1.b84f160ab17a1622p+1796L, 0x4.b2842fc0d4e29f8p-12508L, 0x2.0f8142fc8078e574p-12496L, 0x2.0f8142fc8078e578p-12496L }, + { 0x1.f41344568040c1dap-11860L, 0x1.1c6472bb8005f37ep-6852L, -0x3.3764ada231d16af8p-6840L, -0x3.3764ada231d16af4p-6840L }, + { 0x3.e3036c02f7d4d658p-9528L, 0x5.36e056abcab2faa8p+1976L, -0xc.208372633388ae4p+1988L, -0xc.208372633388ae3p+1988L }, + { 0xe.d925cace25ab5fep+8480L, -0xd.6cb0532deaf2679p+944L, -0x1.bce4911c050e131p+960L, -0x1.bce4911c050e130ep+960L }, + { 0x6.19357550809e7c3p+5024L, 0x1.5c8533e5f3b94e6ap-10972L, 0x1.abb43335a7f7f332p-10960L, 0x1.abb43335a7f7f334p-10960L }, + { 0x3.b44cb94e53d800dp-8104L, -0x1.1ab0065a82bd87f4p-2844L, 0x2.2f2be3b82899a4e8p-2832L, 0x2.2f2be3b82899a4ecp-2832L }, + { 0x9.ea2a7bd17c460dep-8580L, -0x7.62ec913ffd564678p+2716L, 0xf.7770e8e86e4eb82p+2728L, 0xf.7770e8e86e4eb83p+2728L }, + { 0xf.c7a3dd4416649cep+6636L, 0x2.6182229406539e28p+13900L, 0x3.dc11331e9f68bf5cp+13912L, 0x3.dc11331e9f68bf6p+13912L }, + { 0xf.7fa93e24f531607p-1524L, 0x1.8f7cad2b63b6624ep-12276L, -0x9.44069d140a4f7c3p-12268L, -0x9.44069d140a4f7c2p-12268L }, + { 0x1.dc32628ac0052e3p+13788L, -0xa.e3c3bdecf1dec26p-868L, -0x2.4a8d02bd7a23b6acp-852L, -0x2.4a8d02bd7a23b6a8p-852L }, + { 0xe.2792f16a45f2666p-4L, 0x3.606aae6b641136ecp-14064L, -0x9.8d4b6f35e1bb5f7p-14068L, -0x9.8d4b6f35e1bb5f6p-14068L }, + { 0x2.3a3da2a76687889cp+7488L, 0x3.b7edc7ccbaa4e6f4p-4576L, 0x6.cc836f69a9a8fbfp-4564L, 0x6.cc836f69a9a8fbf8p-4564L }, + { 0x9.e81deac115960bcp-10784L, -0x1.edc841a680c41fa6p+904L, 0x5.13a322bc0411e47p+916L, 0x5.13a322bc0411e478p+916L }, + { 0x1.cd896fd12910f8fep+4612L, -0x5.53107666263a4058p-5612L, -0x5.ff0fb993b0e4c34p-5600L, -0x5.ff0fb993b0e4c338p-5600L }, + { 0x7.115b116b66f8aa4p+13264L, -0x7.5f2ae310973bd4d8p+14416L, -0x1.7e07aa45adacd32cp+14432L, -0x1.7e07aa45adacd32ap+14432L }, + { 0x1.74145e7c2770b4ccp+2828L, -0xa.ba6ad2740e752acp-2336L, -0x7.6891da714ff943c8p-2324L, -0x7.6891da714ff943cp-2324L }, + { 0x4.8b2545de86521b8p+13740L, -0x2.1340349dc88fe5ap+4092L, -0x6.f65c22f70b2c646p+4104L, -0x6.f65c22f70b2c6458p+4104L }, + { 0xc.52069130f81cabfp-1984L, -0x4.20c946d47a37871p+2084L, 0x1.fef232e25ad65e4p+2096L, 0x1.fef232e25ad65e42p+2096L }, + { 0x3.2b65b7eb1ee545c8p+7384L, 0x2.3f8fa6f81d92432cp-14436L, 0x4.0dd155add9d84d1p-14424L, 0x4.0dd155add9d84d18p-14424L }, + { 0x1.a1b184553cda78ap+14968L, -0x2.31c152f5ee281b54p-9292L, -0x8.04eac2f38cfa541p-9280L, -0x8.04eac2f38cfa54p-9280L }, + { 0x1.44f05224646c418ap-14972L, 0x1.2804d060de7d5e6ep+13432L, -0x4.3a013b476092fe2p+13444L, -0x4.3a013b476092fe18p+13444L }, + { 0x9.167509d85ac5562p-4L, -0x1.4b8f74471056531ep+12276L, 0x1.0e948448a0348196p+12276L, 0x1.0e948448a0348198p+12276L }, + { 0x7.ee687fee5c4ec2b8p+4644L, 0x6.79c1485cae87c43p-13504L, 0x7.58c0ee6ada14d12p-13492L, 0x7.58c0ee6ada14d128p-13492L }, + { 0x3.0cf623142a333c9cp+2336L, -0xe.a753d50ad228a17p+12460L, -0x8.5ce71421a143a5bp+12472L, -0x8.5ce71421a143a5ap+12472L }, + { 0x2.c8c9b971c2760cep-7672L, 0x3.932fbae80e38a998p-12916L, -0x6.b1db6613ef55474p-12904L, -0x6.b1db6613ef554738p-12904L }, + { 0x1.32026fb6bb0871ecp-13652L, -0x4.7b7e1412f0e7c018p+4912L, 0xe.f08781f91bd2a4dp+4924L, 0xe.f08781f91bd2a4ep+4924L }, + { 0x1.74dc31e3b9305bc4p-1120L, 0x3.84981c669a06975p+10008L, -0xf.6230ebdd8fed1ebp+10016L, -0xf.6230ebdd8fed1eap+10016L }, + { 0xb.ea47989bcd17ecap-872L, -0x3.a0466264269bfc0cp-616L, 0xc.4cf96b143aaed5p-608L, 0xc.4cf96b143aaed51p-608L }, + { 0x7.d01c7f119325b4f8p-1716L, -0xb.b3079d74457748ap-8232L, 0x4.e495c312907e048p-8220L, 0x4.e495c312907e0488p-8220L }, + { 0x1.d578671f39a6b79p+6516L, -0x3.dcbcd626648e35ap-8260L, -0x6.251d78436ccc76e8p-8248L, -0x6.251d78436ccc76ep-8248L }, + { 0x6.4d100f244be8113p+5240L, -0x8.8a2584d61c785a5p-1880L, -0xa.ee25d77822d6b9ap-1868L, -0xa.ee25d77822d6b99p-1868L }, + { 0x6.e4c6b8c4d0181df8p+11256L, -0xa.238f609952a68b5p+7056L, -0x1.bde7c574f5a56112p+7072L, -0x1.bde7c574f5a5611p+7072L }, + { 0x1.775823e9c3c2806cp+0L, 0x5.f466fe6cbdda3498p-3292L, 0x3.4993f3fbee8e12ap-3292L, 0x3.4993f3fbee8e12a4p-3292L }, + { 0x1.6ca0a0798fc630d8p-6296L, -0x1.5d03274c615fac7ep-9600L, 0x2.186d3767c5e0b77cp-9588L, 0x2.186d3767c5e0b78p-9588L }, + { 0x7.f1d06ee491613b4p+11796L, -0x2.99a7c87fc7c10564p-2268L, -0x7.7d7ed6d273782118p-2256L, -0x7.7d7ed6d27378211p-2256L }, + { 0x4.55b0bf0b43297a08p-688L, -0x5.4e7599ff8ce238d8p+5432L, 0xe.37a1a230f9d393cp+5440L, 0xe.37a1a230f9d393dp+5440L }, + { 0xf.ce25a67a67167e8p+5848L, 0xd.dae4961d9a359e9p-4336L, 0x1.3cb782addfad199ep-4320L, 0x1.3cb782addfad19ap-4320L }, + { 0x5.879a9e2ad0de4358p+1484L, 0x2.a7aa43ef734cca24p+9800L, 0xf.6a7be0d01960894p+9808L, 0xf.6a7be0d01960895p+9808L }, + { 0x1.8d57c92ab74b5dbp-9440L, 0xb.b6c4b8fea0b6709p-6916L, -0x1.afec2834b3ae434p-6900L, -0x1.afec2834b3ae433ep-6900L }, + { 0x5.6edc0af664d23e5p+10200L, 0x6.dee852c47ad7ae6p-9044L, 0x1.11d23f76b577fcfep-9028L, 0x1.11d23f76b577fdp-9028L }, + { 0x3.5d8dfaa5f4b3274p+11908L, -0xd.5dcf3b09be0346ep-12448L, -0x2.6dd7025c41524ea4p-12432L, -0x2.6dd7025c41524eap-12432L }, + { 0x7.ed91ce55062c3928p-11600L, -0x6.a15fc994e42a5f98p+13812L, 0x1.2c5c7661e2e3939cp+13828L, 0x1.2c5c7661e2e3939ep+13828L }, + { 0x1.dad7ecb371577f1p-14180L, -0x1.8d483b7d23140ad2p-3480L, 0x5.5f452e54f7efca4p-3468L, 0x5.5f452e54f7efca48p-3468L }, + { 0x7.2dc2a178p-16416L, 0xf.60597a6a11748cfp+11572L, -0x3.d9d6afdc9faabf58p+11588L, -0x3.d9d6afdc9faabf54p+11588L }, + { 0x7.ff05934f4c4c383p+6524L, 0x2.5b900e7df1a77c04p+8376L, 0x3.c1c7d76fd3351f88p+8388L, 0x3.c1c7d76fd3351f8cp+8388L }, + { 0x6.284c4489a8b3cf4p-12304L, -0x1.9ce08e5156bf999ap-956L, 0x4.d7fae0579e379fp-944L, 0x4.d7fae0579e379f08p-944L }, + { 0x3.7341a9ee603f834p-11216L, -0xe.74a4f05ef7fcf94p-10108L, 0x2.793ca67d11dad138p-10092L, 0x2.793ca67d11dad13cp-10092L }, + { 0xb.4c1201a91da1f7dp-2416L, -0x1.ff8b4a662492c844p+6384L, 0x1.2d4b53b5778f5e24p+6396L, 0x1.2d4b53b5778f5e26p+6396L }, + { 0xc.503b4e17876b4f8p+14420L, 0xd.d962de347f839ep+11944L, 0x3.0c4b1eff3371d3dcp+11960L, 0x3.0c4b1eff3371d3ep+11960L }, + { 0xf.ea4c84120426686p+8032L, 0x2.0ff0659d1aa2b36cp+13504L, 0x4.0bc5229ec619288p+13516L, 0x4.0bc5229ec6192888p+13516L }, + { 0xc.d03a3525d4adca1p-8912L, 0xf.76de125c2115ea5p+10412L, -0x2.1a212be6d70d0b54p+10428L, -0x2.1a212be6d70d0b5p+10428L }, + { 0x1.2c0b226e839776bap+10920L, -0xb.7b45dbebad44f9fp+13816L, -0x1.e9c4fd19de7db7ap+13832L, -0x1.e9c4fd19de7db79ep+13832L }, + { 0x1.7526248567fdebaep-840L, 0x8.687306d6b53f2b3p-9012L, -0x1.b922757bed236fdcp-9000L, -0x1.b922757bed236fdap-9000L }, + { 0x5.d5a66b8dfa047b5p-880L, 0x3.54d7284400eeb294p+3432L, -0xb.6b29715876e4f48p+3440L, -0xb.6b29715876e4f47p+3440L }, + { 0x1.37c211415835776cp+0L, -0x1.7bf2f1bdd872e7eep+1316L, -0x6.c0359c02dd59851p+1312L, -0x6.c0359c02dd598508p+1312L }, + { 0x5.9bf965c8495ee31p-1072L, 0xe.d2641494150a73fp+4012L, -0x3.dec2358e511f578cp+4024L, -0x3.dec2358e511f5788p+4024L }, + { 0xe.89eb0db23e82e32p-9840L, 0x8.530d8f2410e4187p+14152L, -0x1.3fd83369fbaaebfep+14168L, -0x1.3fd83369fbaaebfcp+14168L }, + { 0x1.a52fd5b0cedad4p-7932L, -0x1.44fe526e6036e7f8p-3256L, 0x2.754ce8f57959c7e8p-3244L, 0x2.754ce8f57959c7ecp-3244L }, + { 0x1.549a7733f640e13ep+12420L, 0x3.1188e7c0d95889dp-3832L, 0x9.4dff9a550c1eeb8p-3820L, 0x9.4dff9a550c1eeb9p-3820L }, + { 0x9.2e4d38476817c8dp-6436L, -0x4.abcedf3d024db5f8p-4444L, 0x7.5606bf1b0956cffp-4432L, 0x7.5606bf1b0956cff8p-4432L }, + { 0xb.f856641f8481196p+10672L, -0x8.d47787d0685534ap+1648L, -0x1.7038d6792aa77424p+1664L, -0x1.7038d6792aa77422p+1664L }, + { 0x1.69824482561454f8p+336L, 0x1.e0a9fb820963e05ap+3924L, 0x2.77ce6b1d230c7e5cp+3932L, 0x2.77ce6b1d230c7e6p+3932L }, + { 0x4.7b875bee3ace9d18p-4832L, 0x1.32f4fca22bdf9c8p-11912L, -0x1.69f37c67b419941cp-11900L, -0x1.69f37c67b419941ap-11900L }, + { 0x1.f1b6d7dd3acdec62p+1524L, 0x1.b0ec522ad44311ccp+8564L, 0xa.12de18c6f5ad5a6p+8572L, 0xa.12de18c6f5ad5a7p+8572L }, + { 0xa.077356a040b99f3p+10808L, 0x3.8f22e0e027753a1p-1952L, 0x9.64edf128ed9b026p-1940L, 0x9.64edf128ed9b027p-1940L }, + { 0xb.b5048a19c401aa4p-4L, 0x1.49cb7d1d22aa7e92p-11668L, -0x9.4a276cfbcb4689p-11672L, -0x9.4a276cfbcb4688fp-11672L }, + { 0x5.ac937fd967cce3cp+180L, 0x2.044831378114a9e4p-6504L, 0x1.700fbc6017636d7ep-6496L, 0x1.700fbc6017636d8p-6496L }, + { 0x6.5a8d06709c18fd3p-8212L, -0x3.bfed54c9016cfdf8p+564L, 0x7.83ea8701dcdca1c8p+576L, 0x7.83ea8701dcdca1dp+576L }, + { 0x1.22fb3728954b2facp+11140L, 0x2.a9bbdeb2bd533bdcp+4340L, 0x7.3e2913fd71866cap+4352L, 0x7.3e2913fd71866ca8p+4352L }, + { 0x1.a3d958faa346d6d4p-2564L, -0x7.2d5882b0a8455a8p-10740L, 0x4.7dd0b200bb918158p-10728L, 0x4.7dd0b200bb91816p-10728L }, + { 0x5.aae8c1b07b4255a8p-11416L, 0x1.a5322e33e663a032p+14936L, -0x4.95a97974b2d6be5p+14948L, -0x4.95a97974b2d6be48p+14948L }, + { 0x1.32b51a0ef6515e86p+11512L, -0x2.e5e11f37294c9f08p+6628L, -0x8.25224dfd2ae08ebp+6640L, -0x8.25224dfd2ae08eap+6640L }, + { 0x9.9f9641c28f1f3bp+3252L, -0x1.a299130160a73736p-13208L, -0x1.4cad7e3dd198472ep-13196L, -0x1.4cad7e3dd198472cp-13196L }, + { 0xa.14b3d5f6dc54435p+7340L, -0x5.9aded1ca64712fc8p+9680L, -0xa.0c71bdcb75c7ab2p+9692L, -0xa.0c71bdcb75c7ab1p+9692L }, + { 0x6.15b61d120f49268p+6220L, -0xf.7f9391555365de2p+5488L, -0x1.78b815d015e81898p+5504L, -0x1.78b815d015e81896p+5504L }, + { 0x1.4f2bc08178d6eb22p-8580L, 0xa.04e870f0bde69e8p+3968L, -0x1.4fc8994b94f2a114p+3984L, -0x1.4fc8994b94f2a112p+3984L }, + { 0x1.5a47ce0ae772d35p+0L, -0x1.2cdf2167efebf2a4p-10844L, -0x8.31e78a3e624db2bp-10848L, -0x8.31e78a3e624db2ap-10848L }, + { 0x6.f4cbf9587638df9p+5352L, 0x6.68a1cb4cc0d7c8cp-4056L, 0x8.60d658044a4bc4bp-4044L, 0x8.60d658044a4bc4cp-4044L }, + { 0x3.84a9333922f6ecb4p-9532L, 0x2.fc9ff16108dd5bd8p-1556L, -0x6.f30e7b39aef8555p-1544L, -0x6.f30e7b39aef85548p-1544L }, + { 0x4.73121c1ce9aa73dp-6892L, 0x5.84c4b307a865da78p+10880L, -0x9.4867ceb0d8c1681p+10892L, -0x9.4867ceb0d8c168p+10892L }, + { 0x1.904286dff6e1c742p+12660L, 0x1.a23ce96a1531b288p-9176L, 0x5.0cc39f45fb54f2a8p-9164L, 0x5.0cc39f45fb54f2bp-9164L }, + { 0xd.fc03b164930e19ap-4788L, -0x4.484bbdd4a58040c8p-12664L, 0x5.007dc60263b9e04p-12652L, 0x5.007dc60263b9e048p-12652L }, + { 0x3.cf945718ab43d7d8p-9660L, 0x9.75ee615c9605d82p+5592L, -0x1.64ebcc8679ceb56p+5608L, -0x1.64ebcc8679ceb55ep+5608L }, + { 0x6.133ee5675e302e6p+1264L, -0x2.ebb2e212bc306adp+4292L, -0xe.735d70c085412d7p+4300L, -0xe.735d70c085412d6p+4300L }, + { 0x1.6faa14baf33d3942p+5756L, 0x2.98fb801310e3d98p-4484L, 0x3.a69121c6a4586a9cp-4472L, 0x3.a69121c6a4586aap-4472L }, + { 0x1.8bf4374345aeebcap-352L, 0x3.433b152bfb0fcc0cp+8288L, -0x4.7a63b884113c79c8p+8296L, -0x4.7a63b884113c79cp+8296L }, + { 0xf.348c75a3c924d9dp-3128L, -0x6.d27f0cba9d98c128p-4724L, 0x5.34136c5b13a1832p-4712L, 0x5.34136c5b13a18328p-4712L }, + { 0x4.6cba404p-16416L, -0x3.b1c0ab60b7afe674p-14368L, 0xe.cde75bc3f6da7cdp-14356L, 0xe.cde75bc3f6da7cep-14356L }, + { 0x3.1b7118eb85377698p+6592L, -0x5.0267e29e12c8f49p-8896L, -0x8.106249044735cbfp-8884L, -0x8.106249044735cbep-8884L }, + { 0x3.607d3c87fbf0054cp-68L, -0x2.8420e2df1534abep+5568L, 0xa.6add61dff55ffbdp+5572L, 0xa.6add61dff55ffbep+5572L }, + { 0xa.4f75c3ab1754f75p-2464L, -0x2.32d6265dd6c5c31cp+9576L, 0x1.521e6ab64b73a75p+9588L, 0x1.521e6ab64b73a752p+9588L }, + { 0x4.bebcc7d8d84470bp-4920L, 0xc.7a576a4e9617a7ap-10204L, -0xe.fb33826c58f70a1p-10192L, -0xe.fb33826c58f70ap-10192L }, + { 0x1.be14cf99336dd968p-9392L, 0x4.439759bba9387e28p+1492L, -0x9.c6c56213fcb7fdcp+1504L, -0x9.c6c56213fcb7fdbp+1504L }, + { 0xd.ccc1903e13b59f8p-12068L, -0x6.037d29fedf54928p-12240L, 0x1.1b65b2ea6fa5deeap-12224L, 0x1.1b65b2ea6fa5deecp-12224L }, + { 0x8.ec0ef83d152f4acp-13700L, -0x1.390c57a14d17b9fp+14872L, 0x4.16d1c17c1224422p+14884L, 0x4.16d1c17c12244228p+14884L }, + { 0x2.0fb3544804b262fp+5160L, 0x3.b57463fce853545p-480L, 0x4.ac550d3435adb7d8p-468L, 0x4.ac550d3435adb7ep-468L }, + { 0x1.64d1c43e23cf40aep-10652L, 0x1.0fb4b45ff8885f8ep-12252L, -0x2.c2900d82132cfb08p-12240L, -0x2.c2900d82132cfb04p-12240L }, + { 0x1.4abc31acbc7bc518p+1336L, -0xc.c65e75c39561171p+11700L, -0x4.2aff57887c738d9p+11712L, -0x4.2aff57887c738d88p+11712L }, + { 0x1.2b2e1b630ba1b3b6p+0L, 0x1.eada4be47dcfc9f2p+3300L, 0x6.e60d5e6d365afda8p+3296L, 0x6.e60d5e6d365afdbp+3296L }, + { 0x2.c8c57e2508051b3p-3924L, 0x5.21d09f2ffed0044p-5412L, -0x4.ea2bce361f26c5ap-5400L, -0x4.ea2bce361f26c598p-5400L }, + { 0x4.fe1bd62b8bf75b7p-12596L, 0x2.69999b4a350849p+13480L, -0x7.6ae41382c2fb955p+13492L, -0x7.6ae41382c2fb9548p+13492L }, + { 0x1.94cbc2f130aac9fcp+14560L, 0x4.461d0bdbe3e5e6e8p-84L, 0xf.316874645a5d084p-72L, 0xf.316874645a5d085p-72L }, + { 0x6.00a84d432c73ad6p+14048L, -0x7.1439c231e1c871ap+5524L, -0x1.84882f27e22d69e8p+5540L, -0x1.84882f27e22d69e6p+5540L }, + { 0x1.504150487ac4b4e4p+10492L, 0x1.4aca4d52f53ae634p+14816L, 0x3.4f5bd5c26e4d5f5p+14828L, 0x3.4f5bd5c26e4d5f54p+14828L }, + { 0x1.818d6363460594dp+2580L, 0x5.4e4c228f75fecc6p-13880L, 0x3.57c39c1ba0acfc6cp-13868L, 0x3.57c39c1ba0acfc7p-13868L }, + { 0x7.b18970b8033e92d8p+5184L, 0x2.405b3b6f6bd5017cp+12636L, 0x2.d9dd8099a79debfp+12648L, 0x2.d9dd8099a79debf4p+12648L }, + { 0x1.55003f934a96adfep+7436L, 0x9.0c070751c7715e7p-13016L, 0x1.06cd1a244ad7ce72p-13000L, 0x1.06cd1a244ad7ce74p-13000L }, + { 0x8.f4ea2709aeb30cap-3688L, -0x9.90099934edea7dfp+9676L, 0x8.9a4cb3758de9216p+9688L, 0x8.9a4cb3758de9217p+9688L }, + { 0x3.5a44024ad8c0a6ap+9484L, -0x3.162144dafa472c6cp+8012L, -0x7.25d3b827636c377p+8024L, -0x7.25d3b827636c3768p+8024L }, + { 0x4.5f98d1p-16420L, 0x3.174b45b7a50513fp-10904L, -0xc.63b8389565e5a89p-10892L, -0xc.63b8389565e5a88p-10892L }, + { 0x3.5e780c7808c14d1cp+4008L, -0x1.58021e31ae37918ap-8496L, -0x1.50c3bf982d8bc07ep-8484L, -0x1.50c3bf982d8bc07cp-8484L }, + { 0x6.735ed2860eb877p-8864L, -0x5.c82ebf46ce67b208p-8940L, 0xc.823c5bf27f289adp-8928L, 0xc.823c5bf27f289aep-8928L }, + { 0x9.f58318f7cfc023dp-10580L, 0xe.e7cda687036f7d6p-3536L, -0x2.67d291ecbebf4044p-3520L, -0x2.67d291ecbebf404p-3520L }, + { 0x1.3385a0a2f5ddca66p-2148L, 0x3.95cfb0b45473c558p-8036L, -0x1.e140fd913d3cdd4ep-8024L, -0x1.e140fd913d3cdd4cp-8024L }, + { 0xe.947a2689d86b12ap-8256L, 0x2.ff7409072f025f1p+9544L, -0x6.0a2c739e5b996318p+9556L, -0x6.0a2c739e5b99631p+9556L }, + { 0x3.f3364f18a79b3b3cp-14488L, -0x3.6b2dcf47d1901574p+6084L, 0xc.172e20d1e6aa072p+6096L, 0xc.172e20d1e6aa073p+6096L }, + { 0x1.b974779bc6a1600ap+156L, -0x1.fef4cd2b528d3ed6p+4876L, -0x1.38eed99c599a6616p+4884L, -0x1.38eed99c599a6614p+4884L }, + { 0x1.5da19cb6935f4324p-12448L, 0x1.1242f349c776d3c6p-13804L, -0x3.4177c20b08c8a534p-13792L, -0x3.4177c20b08c8a53p-13792L }, + { 0x5.f6b443936fcdf7dp+8000L, 0x4.9faadefeeda4d958p-12968L, 0x9.08985174ac99b73p-12956L, 0x9.08985174ac99b74p-12956L }, + { 0x3.9761f885a890c5f8p-6896L, -0x1.fde18a33769c2a36p+13492L, 0x3.5a33efe387a603p+13504L, 0x3.5a33efe387a60304p+13504L }, + { 0x6.38ae5a4p-16416L, -0xa.2bd753c4bb7feadp+8856L, 0x2.8c207ce6520e07dcp+8872L, 0x2.8c207ce6520e07ep+8872L }, + { 0x1.ce5c78f45cf53052p-12668L, 0x2.d403d4610942405cp-15000L, -0x8.bf104029e978686p-14988L, -0x8.bf104029e978685p-14988L }, + { 0x3.83b4fdb7c30a8a24p+1780L, -0x7.47e990178bed20ep-10576L, -0x3.2ad37d867fd49f4p-10564L, -0x3.2ad37d867fd49f3cp-10564L }, + { 0x4.f47fb482316be128p+6760L, 0x1.e4ba4361308b87cap+8632L, 0x3.20435b40eefebe3cp+8644L, 0x3.20435b40eefebe4p+8644L }, + { 0x9.ecba992568fda9fp+11556L, 0x1.57a41871031f24a8p-14620L, 0x3.c9c9d2d431974ee8p-14608L, 0x3.c9c9d2d431974eecp-14608L }, + { 0x5.0527cf795fdf0218p+180L, -0x1.0ed493bb5c956a5p-14104L, -0xc.0e3e3338d3a0555p-14100L, -0xc.0e3e3338d3a0554p-14100L }, + { 0x1.9e25e3c9c45d2c4cp+10096L, 0xf.d72920ce880fef5p+7404L, 0x2.70c064489db2a254p+7420L, 0x2.70c064489db2a258p+7420L }, + { 0x3.14721fc3b04b8c5p-1656L, 0x1.9d71a05ab8af6f3ep-13688L, -0xa.6fd80e54131d7c3p-13680L, -0xa.6fd80e54131d7c2p-13680L }, + { 0x2.5ad78a50881512acp-12368L, -0x6.200f74ea14aea158p+9312L, 0x1.27e55933256dda96p+9328L, 0x1.27e55933256dda98p+9328L }, + { 0x1.bed98ef392f4ab94p-6416L, 0x3.2511f8a81a02ae5cp-6232L, -0x4.ece8b6a1658e5688p-6220L, -0x4.ece8b6a1658e568p-6220L }, + { 0x9.ca98394ded775ccp+9980L, 0x3.3e1f319d7fc3b93p+2928L, 0x7.e74746d926c576d8p+2940L, 0x7.e74746d926c576ep+2940L }, + { 0x1.b05b032ac011e5c8p+0L, -0x9.89c1d87ab9de711p+11612L, -0x7.36265c43bbe44028p+11612L, -0x7.36265c43bbe4402p+11612L }, + { 0x2.56b6d5ed6e125aap+14564L, -0xd.309c19e3c810c88p+4748L, -0x2.ee719b7b44bb0cb8p+4764L, -0x2.ee719b7b44bb0cb4p+4764L }, + { 0x3.5c49fed90523d454p+1364L, 0x3.2ccd51955a529d84p-3488L, 0x1.0f0434ad8333b286p-3476L, 0x1.0f0434ad8333b288p-3476L }, + { 0xa.8ae9762015aefb8p+7828L, -0x5.a7c6805416a56c7p-576L, -0xa.d0179929a88ed25p-564L, -0xa.d0179929a88ed24p-564L }, + { 0x4.7e2047add8b77fd8p+8844L, -0x1.9d9b7dbed96ad514p+14612L, -0x3.7d45842a9b0a778p+14624L, -0x3.7d45842a9b0a777cp+14624L }, + { 0x1.48bc20b93d87d39cp+7296L, 0x1.f1f4a3bcd62d6452p-13940L, 0x3.7706fe1a27bb84ecp-13928L, 0x3.7706fe1a27bb84fp-13928L }, + { 0x5.e20fed3aa8e5dbdp-4376L, 0x8.e74b97d10e54bb2p+5756L, -0x9.81af1001916f875p+5768L, -0x9.81af1001916f874p+5768L }, + { 0x7.fea63fbd3f40e548p-8500L, -0x8.7ccedf1a38c6b27p+8392L, 0x1.19b6906c783876a8p+8408L, 0x1.19b6906c783876aap+8408L }, + { 0x4.3aa8266ac6dd9848p-4228L, -0x1.d6194fbfe0bb4bfcp-13020L, 0x1.e50280f80b74003ep-13008L, 0x1.e50280f80b74004p-13008L }, + { 0x8.532cbb25dd9a1cp-1464L, 0xe.6973c478c36a38p-11684L, -0x5.23efdcaa87ca0d1p-11672L, -0x5.23efdcaa87ca0d08p-11672L }, + { 0x3.3872f03af739bf68p+1516L, 0x1.c137424956de4544p+12564L, 0xa.67293139ecd81bap+12572L, 0xa.67293139ecd81bbp+12572L }, + { 0x6.0af11c58p-16416L, 0x2.d7786a2a00cb9468p+12132L, -0xb.631a9a8ce1d6547p+12144L, -0xb.631a9a8ce1d6546p+12144L }, + { 0xb.0c8e827b71ff9ddp+11904L, -0x1.991e9c0fb5a8a95cp+4852L, -0x4.a55994b56a2c982p+4864L, -0x4.a55994b56a2c9818p+4864L }, + { 0x5.b2a2fc8e42885c78p-10700L, -0x1.081daf3c372a6146p-2316L, 0x2.b1ca1ae901cbbed4p-2304L, 0x2.b1ca1ae901cbbed8p-2304L }, + { 0x7.f81afe7f042b169p+3428L, 0x3.7991903d8fee1378p-8468L, 0x2.e9248ef40b9703a4p-8456L, 0x2.e9248ef40b9703a8p-8456L }, + { 0x1.053217463c55943ap-5192L, -0x1.80cc47c7e5f02abap+13832L, 0x1.e7c23e8549413a6ap+13844L, 0x1.e7c23e8549413a6cp+13844L }, + { 0xc.a34c4ecf5b0aaabp+8592L, 0x2.e10d47fb5277498p+812L, 0x6.0abd7203021fbcep+824L, 0x6.0abd7203021fbce8p+824L }, + { 0x1.9f351837670e8d28p-6308L, -0x8.befb20c310d5188p+7320L, 0xd.77bc9d6e05309cdp+7332L, 0xd.77bc9d6e05309cep+7332L }, + { 0x4.862a5be8bc9616c8p+9460L, -0x5.2e01d76fb0f858a8p-5552L, -0xb.f7363992738cdf4p-5540L, -0xb.f7363992738cdf3p-5540L }, + { 0x1.1fbaf0e92a32036cp+10360L, -0x3.532ad895dea863e4p+14340L, -0x8.68e3d68cfc8efbp+14352L, -0x8.68e3d68cfc8efafp+14352L }, + { 0x8.b1ffeda31e21d18p-820L, -0x8.d4c31482f8ed374p+856L, 0x1.c2df2c0489d2c7a6p+868L, 0x1.c2df2c0489d2c7a8p+868L }, + { 0x6.bf0de63f8aba85p-9024L, 0x2.245b98a003e208ep-9644L, -0x4.b7bb688e83688eep-9632L, -0x4.b7bb688e83688ed8p-9632L }, + { 0x5.530558a8p-16416L, 0x3.4e3e89e41c249f1cp-6384L, -0xd.3f170a5de7dc7fap-6372L, -0xd.3f170a5de7dc7f9p-6372L }, + { 0xc.fbcd0eea9797117p+8288L, 0x6.58f9c61c99d53948p-2080L, 0xc.d9810980cf5822dp-2068L, 0xc.d9810980cf5822ep-2068L }, + { 0x2.dd7a3619e921daa8p-7868L, 0x4.e1c4b9ed98971fdp-7296L, -0x9.60370599ec12297p-7284L, -0x9.60370599ec12296p-7284L }, + { 0x3.70ea41aa5607c17cp+11940L, -0x1.f54a8c18553ed762p+8868L, -0x5.b5806a96815e76d8p+8880L, -0x5.b5806a96815e76dp+8880L }, + { 0x6.29c88af64c1d2208p+9156L, -0x2.d8c0b8e7335ac6p+2464L, -0x6.5d7c4d973388c83p+2476L, -0x6.5d7c4d973388c828p+2476L }, + { 0x1.9218991c4bceca82p+3496L, -0x4.e5f71ea1e451644p-12488L, -0x4.2e7a78e719b0a1ep-12476L, -0x4.2e7a78e719b0a1d8p-12476L }, + { 0x2.be4f59cbceea3f8p-8768L, 0x9.21d471a6f899699p-11672L, -0x1.38b96068ba6bd08cp-11656L, -0x1.38b96068ba6bd08ap-11656L }, + { 0x9.ea26da61e1e9ee4p+10944L, 0x5.a81356ece0725948p+13688L, 0xf.1e3f343362aac9bp+13700L, 0xf.1e3f343362aac9cp+13700L }, + { 0x6.d6086c949b90754p+10336L, -0xe.400dcdc7097b86ap-2124L, -0x2.3f81b1fd4ef356ep-2108L, -0x2.3f81b1fd4ef356dcp-2108L }, + { 0x1.0350a9dede8123fap+7292L, -0x1.31c156f68fa864e2p+10212L, -0x2.20544d6074c3297p+10224L, -0x2.20544d6074c3296cp+10224L }, + { 0x3.539f1f79bb8d2b58p+1380L, -0x4.038559ede788f67p+10440L, -0x1.5a9f0a37b78786a2p+10452L, -0x1.5a9f0a37b78786ap+10452L }, + { 0x1.4652c37bddc46c36p+0L, -0x3.490ebc26b0621858p+3736L, -0x1.2680d02b02da8dfap+3736L, -0x1.2680d02b02da8df8p+3736L }, + { 0x1.1e2283f3e0d553d2p+11948L, 0x1.795f7455f6f5970ap+10872L, 0x4.4ccefa00fb8ddc7p+10884L, 0x4.4ccefa00fb8ddc78p+10884L }, + { 0x1.03d02412ea0fcd1ep-8536L, -0xa.5ad8a157b120ca8p+14164L, 0x1.5944eeb8cff41832p+14180L, 0x1.5944eeb8cff41834p+14180L }, + { 0x2.8e6b15a22d662794p-192L, 0x4.46b5ea7e4593773p+14680L, -0x3.2f3e1f7c0534dae8p+14688L, -0x3.2f3e1f7c0534dae4p+14688L }, + { 0xc.ec916ba1d9f3d7cp-6028L, -0x6.4925df5d8dba609p+9532L, 0x9.3eb32d1c6521b32p+9544L, 0x9.3eb32d1c6521b33p+9544L }, + { 0x8.df8a92908e3e2d5p+10460L, -0x1.35f423319cb099ecp-14232L, -0x3.17c537d732e96b68p-14220L, -0x3.17c537d732e96b64p-14220L }, + { 0xe.990e956e9d5098cp-10900L, 0x8.6c02663c1fa029ap-11932L, -0x1.667643641596bc48p-11916L, -0x1.667643641596bc46p-11916L }, + { 0xf.0b38b18a81a2e75p-9264L, 0x5.807d83c8ec8ff568p+13408L, -0xc.7043951c1e543f3p+13420L, -0xc.7043951c1e543f2p+13420L }, + { 0x1.e65c8504b82ec6a2p+14584L, -0x6.9bd91d1f5f5a1338p+12052L, -0x1.78849727fbcb985cp+12068L, -0x1.78849727fbcb985ap+12068L }, + { 0xf.1b596643482a518p+13788L, -0x5.d188e3656b87e14p-1564L, -0x1.3978336aa69399ap-1548L, -0x1.3978336aa693999ep-1548L }, + { 0xc.57817a1978c4d96p-8384L, 0x1.7bc496e53462329ep+5112L, -0x3.090057635b92403p+5124L, -0x3.090057635b92402cp+5124L }, + { 0x1.acfc662b3c39eebcp+0L, 0x4.11c79de36b71e45p+8412L, 0x3.07e74dd05087436p+8412L, 0x3.07e74dd050874364p+8412L }, + { 0x1.e9ead1df706b14a2p-6468L, -0x5.98f7597ee100d5d8p+14880L, 0x8.d678b9ee0d151bap+14892L, 0x8.d678b9ee0d151bbp+14892L }, + { 0x6.433a12950afdf158p-1436L, -0x1.98718075dc660c0ap-304L, 0x8.eee39f155669ff3p-296L, 0x8.eee39f155669ff4p-296L }, + { 0x4.449bca5d7a1edddp-8936L, -0x1.0bea9b7e8ad6b81ap+8672L, 0x2.485c45d7b9b8dd2cp+8684L, 0x2.485c45d7b9b8dd3p+8684L }, + { 0x1.f2325cb37958cfa4p-7568L, 0x3.71de7698fe1de088p+10488L, -0x6.5d2f178d80f3e77p+10500L, -0x6.5d2f178d80f3e768p+10500L }, + { 0x4.3b8744dd0317419p-2872L, 0x1.9f85eb8234b6ee9cp-9052L, -0x1.232457e89b7f36ap-9040L, -0x1.232457e89b7f369ep-9040L }, + { 0x2.82d91c368563b43p+520L, 0xf.74f8978fb20a3c3p-3316L, 0x1.f7a2121c656ba95ep-3304L, 0x1.f7a2121c656ba96p-3304L }, + { 0x5.e796e1cfc9288b08p-6856L, 0x1.e7549a99b10b7a6cp+2624L, -0x3.2f671549d02c643cp+2636L, -0x3.2f671549d02c6438p+2636L }, + { 0x6.e056753a5860b3b8p-12668L, 0x3.f7ba2b85ca9670e4p+1420L, -0xc.44b971f65cd0ba4p+1432L, -0xc.44b971f65cd0ba3p+1432L }, + { 0x7.dab816b779cd0b28p+6964L, -0x2.6b4a99eb6919b3e4p+8040L, -0x4.1d5dad8f69d2d4fp+8052L, -0x4.1d5dad8f69d2d4e8p+8052L }, + { 0x2.768c2ccae5a41844p-14664L, 0x2.2bd7f0960ffa1d4cp+11764L, -0x7.c5c9672b404b585p+11776L, -0x7.c5c9672b404b5848p+11776L }, + { 0x1.4214ceb4f8b26f84p+0L, 0x1.aeee948823e94fdp-3348L, 0x8.ec272fe563e96d8p-3352L, 0x8.ec272fe563e96d9p-3352L }, + { 0xf.22fae2a1fe73d63p+12048L, -0xc.6919a02e29e222ap+10216L, -0x2.4842ec282586fd2p+10232L, -0x2.4842ec282586fd1cp+10232L }, + { 0xf.2d33cefe0c45e86p+4200L, -0x2.b6a0e50f22f86cf8p-13716L, -0x2.c8ee53eb4bc41c2p-13704L, -0x2.c8ee53eb4bc41c1cp-13704L }, + { 0xa.77239ea21ede3cap+14536L, -0x1.b2d35d2a6452f9c2p-6280L, -0x6.077b280d797de588p-6268L, -0x6.077b280d797de58p-6268L }, + { 0xb.0b452f4738e9ba3p+1988L, 0xb.054b19e6e2203d5p+12200L, 0x5.5bb4b8962241e958p+12212L, 0x5.5bb4b8962241e96p+12212L }, + { 0x1.2b4c1f63d0b618bcp-1124L, 0xa.0d829b5cf72e0d7p-2276L, -0x2.c210d48e5f1921p-2264L, -0x2.c210d48e5f1920fcp-2264L }, + { 0x1.277fb450f434ba56p-5832L, 0x3.12f29b90db4ce928p+12224L, -0x4.60704004db7e2cb8p+12236L, -0x4.60704004db7e2cbp+12236L }, + { 0x3.70f6435c48a390ep-13484L, -0x2.ed8098445a35e71cp+14560L, 0x9.a307903a581ace3p+14572L, 0x9.a307903a581ace4p+14572L }, + { 0x1.c3c2896f8e2c3c2cp-1344L, 0x2.e80154ad5d5bfe34p+12880L, -0xf.3fa556e4f615bd4p+12888L, -0xf.3fa556e4f615bd3p+12888L }, + { 0x7.55b2ffccf81fa4b8p+7264L, -0x7.898636ae4e2f4d18p+13220L, -0xd.5f3eb3613345c3bp+13232L, -0xd.5f3eb3613345c3ap+13232L }, + { 0x4.12a3f2a71216bef8p+9288L, -0x4.fc64f774546e7168p+508L, -0xb.4ef49340f384ccfp+520L, -0xb.4ef49340f384ccep+520L }, + { 0x1.78262e13ab821e2p+0L, 0x1.80928281b3ac1d92p-2440L, 0xd.57fe1c2ddca1d6bp-2444L, 0xd.57fe1c2ddca1d6cp-2444L }, + { 0xf.215dcf89bd7792ap-13144L, -0xb.2d7f53d1195baf3p-13236L, 0x2.3dbc323174b49ab8p-13220L, 0x2.3dbc323174b49abcp-13220L }, + { 0x1.daac07c45ff52192p-13804L, -0x6.e2ed9d399f6c20a8p-7344L, 0x1.734e42351476817ap-7328L, 0x1.734e42351476817cp-7328L }, + { 0x6.775c2f8ce5a4a958p-12628L, -0x1.faa26ace0fb72f9ap-13992L, 0x6.199ff67cf30c524p-13980L, 0x6.199ff67cf30c5248p-13980L }, + { 0x1.4b67a4bdb9c98152p-5500L, -0x6.aab152bd7aff0f4p-116L, 0x8.f38be04d7e34735p-104L, 0x8.f38be04d7e34736p-104L }, + { 0x1.b93aed734b7a822ap-10328L, -0x6.f21ba81d936c2638p+9052L, 0x1.183217455957ceaep+9068L, 0x1.183217455957cebp+9068L }, + { 0x6.7701481d120c1b6p+8820L, -0x1.a8ad4a5048b28454p-13072L, -0x3.92be9e2abf346cbcp-13060L, -0x3.92be9e2abf346cb8p-13060L }, + { 0xd.606d27e348943bep+8040L, -0x3.c4aee51dff57549cp+6940L, -0x7.6672e4ca1236dbf8p+6952L, -0x7.6672e4ca1236dbfp+6952L }, + { 0x8.9aaf44bff92900ap+13008L, 0xe.c1faf84f1f451c8p-796L, 0x2.ee0e7337eb6ae698p-780L, 0x2.ee0e7337eb6ae69cp-780L }, + { 0xe.4770dc927d5eba1p+14740L, -0x4.73f832df7f78bec8p-156L, -0x1.0076638bc9f51726p-140L, -0x1.0076638bc9f51724p-140L }, + { 0x2.4ee6fe7f8bfa4f84p-1868L, -0x3.c61bfddaa521f2dp+8756L, 0x1.b85065fb85524aa2p+8768L, 0x1.b85065fb85524aa4p+8768L }, + { 0x2.d971898p-16416L, 0x1.5638b03330502364p-13028L, -0x5.5b6ee288b3cddcb8p-13016L, -0x5.5b6ee288b3cddcbp-13016L }, + { 0x3.185dd7d25a7b23f8p-13364L, 0xb.908cd56ce51db8fp-11836L, -0x2.5ba31e30c31c3dbcp-11820L, -0x2.5ba31e30c31c3db8p-11820L }, + { 0x3.a9a51c7cd1a62094p-12044L, -0x2.00963f0465d54a3cp-3104L, 0x5.e2fdc96e2c6a383p-3092L, 0x5.e2fdc96e2c6a3838p-3092L }, + { 0x9.7bae07b48f3d186p-13524L, 0x3.7eab03f7d9fc9158p+12752L, -0xb.8944ae7feb4dfc1p+12764L, -0xb.8944ae7feb4dfcp+12764L }, + { 0x2.974394b3d7b2078p+4088L, 0xb.3d5a0ceef37dac4p-6224L, 0xb.38b25dccc5a2166p-6212L, 0xb.38b25dccc5a2167p-6212L }, + { 0x5.3df9deaca20b2af8p-11080L, -0x5.4e765875989e9d8p-12400L, 0xe.59f433942d6ed78p-12388L, 0xe.59f433942d6ed79p-12388L }, + { 0x9.a7432a90d8d0bdbp+3312L, -0xd.a5c8e96c062ac37p-13004L, -0xb.0bd7b947d5a7d5bp-12992L, -0xb.0bd7b947d5a7d5ap-12992L }, + { 0xa.5245ba426d8cb8dp-8052L, 0x3.d8775bbd6cd0492cp-14992L, -0x7.8e796f0d9e08e8f8p-14980L, -0x7.8e796f0d9e08e8fp-14980L }, + { 0x2.71263b8c47253e1cp+8804L, -0x1.1047e1aacc267022p+14756L, -0x2.49546c369bf44644p+14768L, -0x2.49546c369bf4464p+14768L }, + { 0xb.7bbc2a109b78a97p-12480L, -0x3.10f36db5217d4878p-2108L, 0x9.56f8ef5d208aaa8p-2096L, 0x9.56f8ef5d208aaa9p-2096L }, + { 0x3.43e23acc2678bfecp-14844L, -0x9.ba704ceece1ba4fp-10368L, 0x2.3405ec1a1d6af318p-10352L, 0x2.3405ec1a1d6af31cp-10352L }, + { 0x5.447d50515731259p-4L, -0x3.8b954314786b23ap-2376L, 0x5.aebd2b28bf0b051p-2376L, 0x5.aebd2b28bf0b0518p-2376L }, + { 0x1.53ad8155928be6a4p-2032L, 0x1.a4ce39e0a6fe0442p+6936L, -0xd.0b7938a1f47f704p+6944L, -0xd.0b7938a1f47f703p+6944L }, + { 0x4.d16dd659f3c0f0ap-11256L, -0xd.fd723f0edb1d50fp+8416L, 0x2.66fffae75fb38a2cp+8432L, 0x2.66fffae75fb38a3p+8432L }, + { 0x1.103dfac7cd7c39e4p-5592L, -0x7.de07d07c42e504c8p+3860L, 0xa.bd947f52d4fff55p+3872L, 0xa.bd947f52d4fff56p+3872L }, + { 0x5.7c08324a140957ap+6828L, -0x1.3b6c02589b9259fcp+7784L, -0x2.0dfeb4804581daep+7796L, -0x2.0dfeb4804581dadcp+7796L }, + { 0x6.6f91a8945bb1196p+14828L, 0x6.57abdcaa9f822a78p+2452L, 0x1.6f6f1ff2fef76764p+2468L, 0x1.6f6f1ff2fef76766p+2468L }, + { 0x4.0dbdac43c89f5fa8p-8876L, 0x2.d4d64652d10516ecp+9408L, -0x6.225bdb14e1f214b8p+9420L, -0x6.225bdb14e1f214bp+9420L }, + { 0x6.04e85f85770e42f8p+11628L, -0x1.68a03c17c2b3a2d4p+9568L, -0x3.ffff406c0bdc55f4p+9580L, -0x3.ffff406c0bdc55fp+9580L }, + { 0x1.fac44e7ef22a75e2p-6660L, 0x1.53007eaa586c5ed2p-11556L, -0x2.2720ae514ec9e31p-11544L, -0x2.2720ae514ec9e30cp-11544L }, + { 0x1.c1af05b36c1e1314p-7544L, -0x1.db24c1b166e6b918p-11396L, 0x3.6b060fd951632d28p-11384L, 0x3.6b060fd951632d2cp-11384L }, + { 0x1.19427dcda0480416p-100L, 0x1.c36218d9ea12b06p-11836L, -0xb.0150a2cc8ed4846p-11832L, -0xb.0150a2cc8ed4845p-11832L }, + { 0x1.99c57945979570cp+0L, -0x3.9a147b2294cce81cp+7488L, -0x2.71cb044a663ad638p+7488L, -0x2.71cb044a663ad634p+7488L }, + { 0x8.35964c3a9d13241p-14272L, 0x1.cb6b91a0ad1a1b26p+11236L, -0x6.4073995695e99f88p+11248L, -0x6.4073995695e99f8p+11248L }, + { 0x1.4ec5569f83ab5736p-11296L, -0x3.8f33377c31308a44p-3004L, 0x9.d0d5346d7f8775ap-2992L, 0x9.d0d5346d7f8775bp-2992L }, + { 0xa.e64af69cc0c9a02p+452L, -0xe.30ae8ff9c10b4e2p-11172L, -0x1.93edb29bc02715cap-11160L, -0x1.93edb29bc02715c8p-11160L }, + { 0x1.f57725c0787861ecp+8460L, -0x1.8d1cb508a9ab2afp-4984L, -0x3.344d1e223db10d48p-4972L, -0x3.344d1e223db10d44p-4972L }, + { 0xe.3fac9734bbe71dfp+1164L, 0x1.2206e0f0b72822fcp+7496L, 0x5.2b0ee153f0bcf8a8p+7504L, 0x5.2b0ee153f0bcf8bp+7504L }, + { 0x2.a47e35e1ebe00cap-12464L, -0xd.d1efe43682ae912p+4124L, 0x2.a0c9efc557e73a04p+4140L, 0x2.a0c9efc557e73a08p+4140L }, + { 0xd.4a29b6e571f7f4dp+10012L, -0x9.5dd68d90c07dd66p+12464L, -0x1.6e74e8550fd34c12p+12480L, -0x1.6e74e8550fd34c1p+12480L }, + { 0x5.c36184a826a997c8p-14612L, 0xd.f4b5749411edfbp-3724L, -0x3.1c70415b25d650c8p-3708L, -0x3.1c70415b25d650c4p-3708L }, + { 0x1.fec2d25986d2c82ep+1752L, -0x1.c57eae44abd4be9ep-12468L, -0xc.215ee188c77742cp-12460L, -0xc.215ee188c77742bp-12460L }, + { 0xc.54dfb245063a9b5p+736L, 0xf.10e4c2279861992p-10604L, 0x2.b872c2568d3b19d4p-10592L, 0x2.b872c2568d3b19d8p-10592L }, + { 0x7.2511d87p-16416L, -0x1.8e6f895a46c46376p-3516L, 0x6.3c945f5d473002ep-3504L, 0x6.3c945f5d473002e8p-3504L }, + { 0x5.ab74bda0e9f7dc48p-11284L, -0x3.85da52552263bf3cp+188L, 0x9.b3f299cce4fce6ap+200L, 0x9.b3f299cce4fce6bp+200L }, + { 0x6.f8e5e146df8b2df8p+4628L, -0x6.801cd00cd5c87f7p-14356L, -0x7.5963f19aebc7d238p-14344L, -0x7.5963f19aebc7d23p-14344L }, + { 0x6.af69ebfdc141d71p+6980L, 0xc.78d6cd9d8fb34ebp-14544L, 0x1.5430f03a79108192p-14528L, 0x1.5430f03a79108194p-14528L }, + { 0x2.d62679fc1dcc84f8p+3140L, 0x5.fdcf1e255c31878p+1624L, 0x4.9862377e4c9b3cp+1636L, 0x4.9862377e4c9b3c08p+1636L }, + { 0x7.f8395e79564ebaap+60L, -0xf.6848263df1e17f7p+10516L, -0x3.ca941be39f8c20acp+10524L, -0x3.ca941be39f8c20a8p+10524L }, + { 0x1.8c3ff1590baa159ap-8448L, -0x2.d6a2d6b9cdaf1e5cp+5536L, 0x5.da933b48b3f2c5b8p+5548L, 0x5.da933b48b3f2c5cp+5548L }, + { 0xf.7679533e38c76d9p-13512L, -0x2.9e835f5c8364ae6cp+5928L, 0x8.a342cfd4ceeb772p+5940L, 0x8.a342cfd4ceeb773p+5940L }, + { 0xb.faf082b54ef2606p-14972L, 0x1.f3c6efc2e5ffb4e6p-7316L, -0x7.226282ff9956c7c8p-7304L, -0x7.226282ff9956c7cp-7304L }, + { 0x5.bfaf79aef43b597p-6912L, -0xf.1209a1e9d495726p+14776L, 0x1.96c0fd44f325c3fp+14792L, 0x1.96c0fd44f325c3f2p+14792L }, + { 0xf.55e7c12943cd9e3p-6360L, 0x1.30338ac91f40e2b2p-2200L, -0x1.d80d24f04b5e17bep-2188L, -0x1.d80d24f04b5e17bcp-2188L }, + { 0x2.0170ec08p-16416L, 0x3.f9d950af555b34d8p+1520L, -0xf.ef1915c00213218p+1532L, -0xf.ef1915c00213217p+1532L }, + { 0x9.438df09cbbeb10bp+11920L, -0x1.f49d11dbf4152fd8p-8844L, -0x5.b1419570741079ep-8832L, -0x5.b1419570741079d8p-8832L }, + { 0x1.39b9c285df388998p+13596L, -0xc.9214ffa074b0b5fp-10512L, -0x2.9ba203464a83d634p-10496L, -0x2.9ba203464a83d63p-10496L }, + { 0xa.5f724f2608e28b2p-4708L, 0x1.dd92386080291574p+13984L, -0x2.248896740c8620e8p+13996L, -0x2.248896740c8620e4p+13996L }, + { 0x1.2fcd33518ffb63f6p+5836L, 0xf.6172d7a361a0172p-956L, 0x1.5ea55289ffeab622p-940L, 0x1.5ea55289ffeab624p-940L }, + { 0xc.a8dc2de30b15b92p+5508L, -0x4.bbe0b101ef388428p+11952L, -0x6.5eba477cb699702p+11964L, -0x6.5eba477cb6997018p+11964L }, + { 0x2.5589af74b36b200cp+2652L, 0x1.2df972a1d9a4979p+13440L, 0xc.39b5674995e5924p+13448L, 0xc.39b5674995e5925p+13448L }, + { 0x2.6e39319255f2e85cp-12576L, -0x8.6765d8ee23089b3p+13476L, 0x1.9ccca6b0cc048174p+13492L, 0x1.9ccca6b0cc048176p+13492L }, + { 0xf.d8fad8e98f71b18p+11084L, -0xd.1751bb0b57d5a64p-8428L, -0x2.3701d5ad9aede528p-8412L, -0x2.3701d5ad9aede524p-8412L }, + { 0x1.f20b5ada21c997a6p+2796L, -0x7.4f3d7f0f8057c7fp+216L, -0x4.fdc784a368328628p+228L, -0x4.fdc784a36832862p+228L }, + { 0x2.ec355c67c4fad788p-11308L, -0x1.8877194d22dc426ep+12004L, 0x4.3b58d8f089f7b7d8p+12016L, 0x4.3b58d8f089f7b7ep+12016L }, + { 0x6.10df3f08p-16416L, 0x3.817942a0a769381cp-14720L, -0xe.0c561bbd87a62c2p-14708L, -0xe.0c561bbd87a62c1p-14708L }, + { 0x6.bd0fe1dc836eadfp-2136L, -0x6.f44c3fc5e9f0dcdp-9768L, 0x3.9f3380dc7a30e2d4p-9756L, 0x3.9f3380dc7a30e2d8p-9756L }, + { 0x1.dc7ec24162fe6b86p+6416L, 0xa.d904450a87c914dp+6880L, 0x1.0fe8b419324e5f7cp+6896L, 0x1.0fe8b419324e5f7ep+6896L }, + { 0x2.1154e9b7d8bc947cp+14296L, 0x2.8005335ce62297e4p-2280L, 0x8.b9fc12eb0b97e15p-2268L, 0x8.b9fc12eb0b97e16p-2268L }, + { 0x2.74ac5ca14051d8c8p+11348L, 0x7.0dbe8b515344edd8p-11768L, 0x1.38b667035b5453eap-11752L, 0x1.38b667035b5453ecp-11752L }, + { 0x7.1de5eb4d52288bd8p+5288L, 0x1.574c4b79e115507cp+12240L, 0x1.bb70beb675fd9e3ep+12252L, 0x1.bb70beb675fd9e4p+12252L }, + { 0xe.94dc072f915b9d6p-9840L, -0x1.33686966e730be5cp-8980L, 0x2.e2358dde81d0fe6cp-8968L, 0x2.e2358dde81d0fe7p-8968L }, + { 0x1.7c62423d8dcc70ap+12720L, 0x6.caa1f4e928c8b418p-12892L, 0x1.51783086464f7fbcp-12876L, 0x1.51783086464f7fbep-12876L }, + { 0x2.fd1e13da6acdd0bcp+11408L, -0x5.a5a7ab4fcb0ebe2p+11256L, -0xf.baeeb396d2b0e9p+11268L, -0xf.baeeb396d2b0e8fp+11268L }, + { 0x1.0405975065fa257ep-7100L, -0x3.fdf6965a0a7ce894p+14952L, 0x6.eb76bf6483135628p+14964L, 0x6.eb76bf648313563p+14964L }, + { 0x1.7989128da5ed012p-9088L, 0x2.fc6d5635215dc184p-3920L, -0x6.9ff7d0476617d7fp-3908L, -0x6.9ff7d0476617d7e8p-3908L }, + { 0xd.055219222b15826p-4L, 0x2.edc4531e12e7a84p+8956L, -0xd.edf55a814a9b1a7p+8952L, -0xd.edf55a814a9b1a6p+8952L }, + { 0x7.5b088224bb277808p-7200L, -0x5.6b6879b6303a20bp+372L, 0x9.85d403deb866612p+384L, 0x9.85d403deb866613p+384L }, + { 0x7.03716987879c6018p-10492L, 0x1.adc33e4dc78313c6p-328L, -0x4.4c8d63dc02372a48p-316L, -0x4.4c8d63dc02372a4p-316L }, + { 0x1.da61b2ff79d0db24p+264L, 0x1.2e8b11af94cc68b2p+2376L, 0x1.390ca6484829684cp+2384L, 0x1.390ca6484829684ep+2384L }, + { 0xa.f1f3b5f8ea8a2b6p+7968L, 0x1.904871e14600c2bcp-7332L, 0x3.0b034b594dda06ap-7320L, 0x3.0b034b594dda06a4p-7320L }, + { 0x3.6ae487af5a263c4p+14132L, 0x1.ae943bae4789d33ap-2168L, 0x5.cdc4a551070f1538p-2156L, 0x5.cdc4a551070f154p-2156L }, + { 0x2.91609a622daf31e4p-4876L, 0x2.dc7407749b13934cp+1904L, -0x3.67b0d6eb6b3bdf74p+1916L, -0x3.67b0d6eb6b3bdf7p+1916L }, + { 0x1.d99d97dab08ea934p+12696L, -0xd.6727a80c183e2d2p-1688L, -0x2.98bfbc1c6bf749a8p-1672L, -0x2.98bfbc1c6bf749a4p-1672L }, + { 0x1.a88e6202e69d3e36p-8164L, -0x3.3b8ff738d5bcfedcp+12568L, 0x6.7151f311b8f003b8p+12580L, 0x6.7151f311b8f003cp+12580L }, + { 0x3.9da48fd55e06d82p-2016L, 0x9.75441492e92e938p-11520L, -0x4.a69ee59d49e6ac78p-11508L, -0x4.a69ee59d49e6ac7p-11508L }, + { 0x6.e4b00b3b240142e8p+10764L, 0x6.e51718f6edc8117p+11268L, 0x1.21fbbb4d7e6a6ebep+11284L, 0x1.21fbbb4d7e6a6ecp+11284L }, + { 0x4.b95f1008p-16416L, 0x7.908b2d72dd961268p-4568L, -0x1.e503ead22ff73dbcp-4552L, -0x1.e503ead22ff73dbap-4552L }, + { 0x1.66c1bb97ab0ddaf2p-14964L, 0x2.5463a5ef35f229f8p-56L, -0x8.82bae6360805bacp-44L, -0x8.82bae6360805babp-44L }, + { 0x2.3637d76bb2135d3p-9636L, -0xb.7a932240c1b4016p-14796L, 0x1.b004a4e92f670be6p-14780L, 0x1.b004a4e92f670be8p-14780L }, + { 0x4.cf778309532b4ebp-1072L, 0xd.a187d193099d32p+14532L, -0x3.8f584e61aa9fd4f8p+14544L, -0x3.8f584e61aa9fd4f4p+14544L }, + { 0x6.6073bd067abac2c8p+11092L, -0x2.20b8ef4823854164p+13672L, -0x5.c377cd23914a472p+13684L, -0x5.c377cd23914a4718p+13684L }, + { 0x6.6c2bf697eaadaa5p+5628L, 0x2.3ba43ace18fc3068p-6200L, 0x3.11d2c48e39fe1bdcp-6188L, 0x3.11d2c48e39fe1bep-6188L }, + { 0x2.87c33a262964fd9cp+8628L, -0xf.26e2f1c7fdd8f81p-2156L, -0x1.febee3d02376b5f8p-2140L, -0x1.febee3d02376b5f6p-2140L }, + { 0x2.5af103b8c04393dcp+14240L, 0xf.eeaf2649294683ep+4684L, 0x3.76507f6f2843ac0cp+4700L, 0x3.76507f6f2843ac1p+4700L }, + { 0x1.c5517be1322d88acp-3840L, -0xd.ad84401801a45f6p-12328L, 0xc.d1f792c56fea84dp-12316L, 0xc.d1f792c56fea84ep-12316L }, + { 0x1.f481e7f5a608c8c2p-10832L, -0x7.caae88ce01de0b28p-10208L, 0x1.49a86fa297491138p-10192L, 0x1.49a86fa29749113ap-10192L }, + { 0x4.3bd32cddd2adb53p+6132L, 0x1.7ef0a1fc8c9b04ccp+9928L, 0x2.3d7b927c9e933c78p+9940L, 0x2.3d7b927c9e933c7cp+9940L }, + { 0x5.7001db08p-16416L, -0xc.41d507fb40798b9p-13684L, 0x3.11df8b0dd5773becp-13668L, 0x3.11df8b0dd5773bfp-13668L }, + { 0x6.044acf83853e4228p-9104L, -0xd.b86c5707774a4a2p-8316L, 0x1.e7cb073787416962p-8300L, 0x1.e7cb073787416964p-8300L }, + { 0x7.eedd2b5801d30ddp+7992L, -0x3.7b7080994ba8601p+11972L, -0x6.cc007b1d43a7a56p+11984L, -0x6.cc007b1d43a7a558p+11984L }, + { 0x1.f5be5d508fb45da4p+9112L, 0x1.df36989632baa77cp+8068L, 0x4.2a2d08050cc7844p+8080L, 0x4.2a2d08050cc78448p+8080L }, + { 0xb.cb682f76a3f814p-588L, 0x1.8221ab8a45beb70ap+5048L, -0x3.7186b04965becde4p+5056L, -0x3.7186b04965becdep+5056L }, + { 0x1.da34232a6dcd2a12p+6624L, 0x2.4b62cb0f68a8551p-1320L, 0x3.b60a6ac66abd2584p-1308L, 0x3.b60a6ac66abd2588p-1308L }, + { 0x1.493dc3decd39a4dep+3500L, 0x1.0d22af0930e0b6fp+4276L, 0xe.5ff7e362d36c1fcp+4284L, 0xe.5ff7e362d36c1fdp+4284L }, + { 0x1.677dc1ce56c13e36p-2052L, 0x3.369a880d9098bd94p-8212L, -0x1.9c01bbe923a7cd8ep-8200L, -0x1.9c01bbe923a7cd8cp-8200L }, + { 0x1.243bd932d58f9d4p+2232L, -0x4.405714e489cdecc8p-4048L, -0x2.511c717d4ef5a6ap-4036L, -0x2.511c717d4ef5a69cp-4036L }, + { 0x6.0af8d49f145e687p+2796L, 0x5.839c88a10e84ba4p-6556L, 0x3.c47c119946aaf368p-6544L, 0x3.c47c119946aaf36cp-6544L }, + { 0x6.d702937630559bfp-3504L, -0xe.d559a68601d334ep-376L, 0xc.adf155961d544e9p-364L, 0xc.adf155961d544eap-364L }, + { 0x5.a1a1b43fda655bd8p-4L, -0xc.eb3db51a4117749p+5524L, 0x1.37666ead2720f402p+5528L, 0x1.37666ead2720f404p+5528L }, + { 0x1.d4fff2bbd3cd6096p+14012L, -0x9.b242f08632fe79dp+4872L, -0x2.12c180026a9a0d44p+4888L, -0x2.12c180026a9a0d4p+4888L }, + { 0x3.dce49626e093ee74p-1236L, 0xe.19b5bca3f808afep-1016L, -0x4.3f8a3b4158ea32dp-1004L, -0x4.3f8a3b4158ea32c8p-1004L }, + { 0x3.da483e0a56def77p+12192L, -0x1.a6e3721b926d2e74p-10244L, -0x4.eaf46fbbec4f8428p-10232L, -0x4.eaf46fbbec4f842p-10232L }, + { 0x4.07f8e4310889c4e8p+10772L, -0xc.8841513e4940958p+11376L, -0x2.0f6e90d6698fa354p+11392L, -0x2.0f6e90d6698fa35p+11392L }, + { 0x1.fb59ad3e66e925fp-7792L, 0x4.36d6c1b431f631p+6232L, -0x8.04100041d8b6f53p+6244L, -0x8.04100041d8b6f52p+6244L }, + { 0x4.dd76d9666cca4358p-320L, 0x4.25e1b5ec2d09b028p-4464L, -0x5.25e26d6cad8dc608p-4456L, -0x5.25e26d6cad8dc6p-4456L }, + { 0x7.511fbab815148398p+9832L, -0x9.136d9190525debbp+12768L, -0x1.5cac3737912c4d42p+12784L, -0x1.5cac3737912c4d4p+12784L }, + { 0x1.d2c419eacc353274p-5220L, 0x3.a7736bf4d7d242f8p+6924L, -0x4.a7f42e68003a106p+6936L, -0x4.a7f42e68003a1058p+6936L }, + { 0x3.d1ca473f87febbdp-12640L, -0x6.e69234d17bbb5598p-11576L, 0x1.54ab1b7b62ece05ep-11560L, 0x1.54ab1b7b62ece06p-11560L }, + { 0x8.aa229058b7ec91ap+11260L, 0x2.56be1f012070b9acp+8576L, 0x6.6e69b8535265253p+8588L, 0x6.6e69b85352652538p+8588L }, + { 0x1.c7748fedb8ca471ap+0L, 0x3.392a62c6b703c4ecp+13940L, 0x2.add96e5e07d757e4p+13940L, 0x2.add96e5e07d757e8p+13940L }, + { 0x1.40b8689b9086f9d2p-14232L, 0x2.67e16890207f4008p-2292L, -0x8.5be5308a970cf1cp-2280L, -0x8.5be5308a970cf1bp-2280L }, + { 0x1.4020453efbe8ffdp-10896L, 0xc.8616627c8c648f6p+1252L, -0x2.15070ecc4a673a9cp+1268L, -0x2.15070ecc4a673a98p+1268L }, + { 0x2.38adc006fc23903p+6140L, 0x6.1777a16c16e2514p-2972L, 0x9.221dcf1a3d6e125p-2960L, 0x9.221dcf1a3d6e126p-2960L }, + { 0x5.eccfd047cc0e3388p-10440L, -0x1.b6e7836a71634822p+10592L, 0x4.5e6aacff0d156058p+10604L, 0x4.5e6aacff0d15606p+10604L }, + { 0x6.42d0a34a532209ep-7740L, -0x6.f6bb9a4c17f8e4c8p+1628L, 0xd.279623da9a5e4b7p+1640L, 0xd.279623da9a5e4b8p+1640L }, + { 0x7.eb89e9bd6da32ep+8104L, 0x2.06274f7ea5ec58d4p-3536L, 0x4.018d760dfe123718p-3524L, 0x4.018d760dfe12372p-3524L }, + { 0x1.52e498e37a488bdap-1444L, -0xa.0f4bc2cfdcbdd27p+12596L, 0x3.8ba35274a6f86ec4p+12608L, 0x3.8ba35274a6f86ec8p+12608L }, + { 0xa.fe50b439a96ea55p+10156L, -0x3.a6a05daa8cf8ba1cp+14960L, -0x9.0e3027c0c5b948dp+14972L, -0x9.0e3027c0c5b948cp+14972L }, + { 0x1.95f38ef02236fd6cp+36L, 0x5.9a25ab758149ad5p+11224L, 0xc.d673d3e22020888p+11228L, 0xc.d673d3e22020889p+11228L }, + { 0x2.aa06a7b698b0b3e4p-13208L, 0xf.a22449fa646a2e3p+14428L, -0x3.267f668663bace68p+14444L, -0x3.267f668663bace64p+14444L }, + { 0x1.bf2d10d91eae0db2p+0L, -0x1.f41156a05dc1e02p-8448L, -0x1.92676f0461939be2p-8448L, -0x1.92676f0461939bep-8448L }, + { 0x3.678e1f2aa097eb6p-9600L, -0x6.48717c11cd853a38p-4344L, 0xe.b9184d58694da4ap-4332L, 0xe.b9184d58694da4bp-4332L }, + { 0x6.fa2cdb8df72f8548p-1508L, -0x5.5c8be3b33b03234p-13204L, 0x1.f86214217fa1db1p-13192L, 0x1.f86214217fa1db12p-13192L }, + { 0x5.b43694428f84ed2p+2964L, -0x2.9ea35367c5b0b0fp-2284L, -0x1.e5b4f9fe4ab5c4fcp-2272L, -0x1.e5b4f9fe4ab5c4fap-2272L }, + { 0x1.01687357811d4fd2p+5028L, -0x7.3e1390b9f6f3a3e8p+11328L, -0x8.e3f46f26fefd7d4p+11340L, -0x8.e3f46f26fefd7d3p+11340L }, + { 0x1.1181efb54abefbbep-12372L, 0x6.83c34bd099d6ae7p+4440L, -0x1.3ad73b21743243aep+4456L, -0x1.3ad73b21743243acp+4456L }, + { 0x7.6dfb1adacc93b0d8p-1996L, -0x1.c3d8c6cee90c3ba2p-5648L, 0xd.bde2db8a05260cep-5640L, 0xd.bde2db8a05260cfp-5640L }, + { 0x1.a43f7998e3bc6428p+6660L, 0x1.25125ef5c349b838p-10488L, 0x1.dc943819311290cp-10476L, 0x1.dc943819311290c2p-10476L }, + { 0x9.59de5e82fe42ee3p-4912L, -0x2.82f638bfb4cf4becp+4548L, 0x3.028babe7dbd4e47cp+4560L, 0x3.028babe7dbd4e48p+4560L }, + { 0x1.c7a1126551114648p+7108L, 0xd.27237ee2cef0c03p+12688L, 0x1.6d3da6102aee785p+12704L, 0x1.6d3da6102aee7852p+12704L }, + { 0xb.dd30144dd06980cp-11936L, -0x1.791cebbb198638bep-2520L, 0x4.4a9a2b2b484838b8p-2508L, 0x4.4a9a2b2b484838cp-2508L }, + { 0x2.0e8711d8p-16416L, -0x1.7bb6dd104adc4d0cp+2888L, 0x5.f1ba3150ca7f0828p+2900L, 0x5.f1ba3150ca7f083p+2900L }, + { 0x1.1d43bf5824a1e06cp+4368L, -0x3.6aff33a9a6024948p-7268L, -0x3.a522b04900fbdfp-7256L, -0x3.a522b04900fbdefcp-7256L }, + { 0x2.ea4f2a6ac862728cp+2680L, -0x6.3f1754e29b634308p+10700L, -0x4.16e20a83ab3a847p+10712L, -0x4.16e20a83ab3a8468p+10712L }, + { 0x6.dc2337c4dcfc9ba8p+9292L, 0x1.db67943b70f0e37ap+732L, 0x4.36cdc5c0cbf5c598p+744L, 0x4.36cdc5c0cbf5c5ap+744L }, + { 0x2.11d8eb885c371facp-3816L, 0x9.420077450c7ba7ep+3360L, -0x8.9f61fc96a86315ep+3372L, -0x8.9f61fc96a86315dp+3372L }, + { 0x2.80989ac0b86b7144p+7248L, -0x9.6b6d7f66e9adc62p-7280L, -0x1.0abe032023d3bc7ap-7264L, -0x1.0abe032023d3bc78p-7264L }, + { 0x4.9affaf38db31985p+9560L, -0x3.9fb0ce552022caep-9264L, -0x8.75b6e9f5bba47f3p-9252L, -0x8.75b6e9f5bba47f2p-9252L }, + { 0x1.79f10252e5d32328p-11808L, 0x3.5d72f3d2e9a1c1bp+832L, -0x9.b347207cf9028e7p+844L, -0x9.b347207cf9028e6p+844L }, + { 0x1.551248fac9273744p-604L, -0x4.acf1bc3134803b78p-7060L, 0xb.061ae47f2cbbf69p-7052L, 0xb.061ae47f2cbbf6ap-7052L }, + { 0x7.7cc2f48a5f0b8c2p-13612L, -0x7.4e46d17991c7841p+2360L, 0x1.8460e567b6746cbp+2376L, 0x1.8460e567b6746cb2p+2376L }, + { 0xa.371f3fbdd75e962p+3584L, -0x5.44ff275c91095f78p+5452L, -0x4.9d79ee220fd58108p+5464L, -0x4.9d79ee220fd581p+5464L }, + { 0x3.de6cea18p-16416L, -0x2.d768065c9b0efec8p-5176L, 0xb.62f62c4094f50b5p-5164L, 0xb.62f62c4094f50b6p-5164L }, + { 0x1.dd2afe046d25b216p+13800L, 0xb.fba33f67d3e9c4ep-11144L, 0x2.85ff9be480399d14p-11128L, 0x2.85ff9be480399d18p-11128L }, + { 0x1.1829747c59eaadeep+8880L, -0x2.d7c6fd57d4a80568p+13152L, -0x6.29d2526173e85b88p+13164L, -0x6.29d2526173e85b8p+13164L }, + { 0x9.479031be3e93809p+6644L, -0x5.470f8a96fe098158p+692L, -0x8.90935ba9e5537d9p+704L, -0x8.90935ba9e5537d8p+704L }, + { 0xb.e269d2411d00a65p-12500L, 0xe.dc859359b9e1993p-7060L, -0x2.d572984be4518698p-7044L, -0x2.d572984be4518694p-7044L }, + { 0x1.fc0c45d7d5b6944ep+14064L, -0x7.c373eda7898c0138p-6140L, -0x1.aa895e0c3e0a8064p-6124L, -0x1.aa895e0c3e0a8062p-6124L }, + { 0x3.19dfe4d95f04bf3cp+8788L, 0xe.56a26033db6ec8ep+3404L, 0x1.ec4d67591c6e716cp+3420L, 0x1.ec4d67591c6e716ep+3420L }, + { 0xe.80351557405b528p+5764L, -0xb.b6c59696ddc332cp-5844L, -0x1.07ec6a44e392920ap-5828L, -0x1.07ec6a44e3929208p-5828L }, + { 0x5.edc1370a9352152p-5912L, -0x6.cb8d5970de366248p-4448L, 0x9.cdb559965ad814fp-4436L, 0x9.cdb559965ad815p-4436L }, + { 0x3.311130840d33e9b8p+1248L, 0x4.619b478aa823bf98p+14140L, 0x1.5632ae7c6fddcc8ap+14152L, 0x1.5632ae7c6fddcc8cp+14152L }, + { 0xe.fb1fa7cc5c99a7bp+2644L, 0x6.215a6f280bbf23ap+13288L, 0x3.f686a6e27cbd46ccp+13300L, 0x3.f686a6e27cbd46dp+13300L }, + { 0x6.3a39de95ec46d4bp-8L, -0xe.1e6dc0d48239149p-11560L, 0x4.bb2407581006d8c8p-11556L, 0x4.bb2407581006d8dp-11556L }, + { 0x4.24ff70bcd18c18fp+10272L, 0x1.21f37f880ee736bap-11320L, 0x2.d749d1d167a36bd4p-11308L, 0x2.d749d1d167a36bd8p-11308L }, + { 0x7.390a0da36cdc0aap+7196L, -0xc.b4b337e7f289e73p+10324L, -0x1.654b9c3d455f6008p+10340L, -0x1.654b9c3d455f6006p+10340L }, + { 0x2.10284ca11e4b7564p-1160L, -0xf.507826a098b359bp+12828L, 0x4.554a03b8742e5ebp+12840L, 0x4.554a03b8742e5eb8p+12840L }, + { 0xe.136ea4a2bb31728p+4556L, 0x1.85282eebef8dacc8p+11900L, 0x1.b1393d4db800a8a2p+11912L, 0x1.b1393d4db800a8a4p+11912L }, + { 0x1.20284f808bcc88fap+9660L, -0x6.b85cbded358fc63p+12036L, -0xf.d95f13f31f24b66p+12048L, -0xf.d95f13f31f24b65p+12048L }, + { 0x7.f78dd33fc42fe6c8p+6952L, -0x6.6f2c0f935ec5eb78p+2808L, -0xa.ece48391f9f0029p+2820L, -0xa.ece48391f9f0028p+2820L }, + { 0xc.f8724b65692d26dp-11464L, 0xc.d8d86a52dace604p-11752L, -0x2.3f1f1bf4cf514d88p-11736L, -0x2.3f1f1bf4cf514d84p-11736L }, + { 0x2.d7b18b7d7e32001p-12508L, 0x6.2e48d04a8fa4117p+10856L, -0x1.2df41cd47c378c7p+10872L, -0x1.2df41cd47c378c6ep+10872L }, + { 0x3.ffb401ff0c4f759p+13256L, -0x1.4180a10c714422fap-1496L, -0x4.10a4f72213d46648p-1484L, -0x4.10a4f72213d4664p-1484L }, + { 0x2.b76b974e31a16b8p-11156L, -0x7.5d2f72fd85a96188p-4708L, 0x1.40de39cbf5a8e2bep-4692L, 0x1.40de39cbf5a8e2cp-4692L }, + { 0xa.a6e924d5c873e25p-4L, -0x2.8d7c8afc118c282p-3080L, 0x1.7f9010b25b95f5dp-3080L, 0x1.7f9010b25b95f5d2p-3080L }, + { 0x2.d9a4ff4e3c08fb64p+12248L, -0x1.52b21398d2eb239p-10876L, -0x3.f4e77a2ce1ec901p-10864L, -0x3.f4e77a2ce1ec900cp-10864L }, + { 0x3.aee0b2eba4ea93f4p-11752L, -0x3.a608c14af6727124p+9316L, 0xa.777250fbd0a127fp+9328L, 0xa.777250fbd0a128p+9328L }, + { 0x7.f6a14a5fad86d0ap+8552L, 0xb.3506e923aabefd2p-1124L, 0x1.7684faf5fb9185c8p-1108L, 0x1.7684faf5fb9185cap-1108L }, + { 0x5.3f76be96f999fc38p+7716L, 0x6.58c19d7142062018p-108L, 0xb.f5a59acc9015199p-96L, 0xb.f5a59acc901519ap-96L }, + { 0xf.aca3cd9099be9bep+1640L, 0x6.fc8dd636b71e3f1p-1800L, 0x2.cdda9cd629895304p-1788L, 0x2.cdda9cd629895308p-1788L }, + { 0x1.91d42e0b36883b3ep+4728L, -0x3.88c36c923b28995cp+1744L, -0x4.14825bb13e4b1f18p+1756L, -0x4.14825bb13e4b1f1p+1756L }, + { 0x1.bab5220de2d5268cp-11632L, -0x2.47c45a33bea715d4p+10592L, 0x6.79b1c761cb108088p+10604L, 0x6.79b1c761cb10809p+10604L }, + { 0x2.6e042d7870e54f5p+13852L, 0x8.62d7e11cf21a5ccp+8848L, 0x1.c5cf16cabe81f1a8p+8864L, 0x1.c5cf16cabe81f1aap+8864L }, + { 0x1.c98310f63362d2a6p+1284L, -0x5.78ce0504a9a6ecbp+12692L, -0x1.b767eb9220e28388p+12704L, -0x1.b767eb9220e28386p+12704L }, + { 0x3.608d17ea6d8d0a38p-1492L, -0xa.2155d2a64e7f091p+2336L, 0x3.af87ec9ef906c52p+2348L, 0x3.af87ec9ef906c524p+2348L }, + { 0x2.e6b808fp-16416L, -0x7.f3d928344c7b47c8p+5944L, 0x1.fde88cc384e52e2ep+5960L, 0x1.fde88cc384e52e3p+5960L }, + { 0x3.72e5835930c81eap-4344L, 0x1.b87e6990fe084aaap+9196L, -0x1.d2f8e4b2d0532fccp+9208L, -0x1.d2f8e4b2d0532fcap+9208L }, + { 0x1.0a1e398ca5cf0d14p-10272L, -0x1.e7e7659b06787af2p+9104L, 0x4.c790983fed5fc48p+9116L, 0x4.c790983fed5fc488p+9116L }, + { 0x9.7f447b066f4437ep-12952L, 0x5.3edda06af98605b8p+8176L, -0x1.095393f9b90e26f4p+8192L, -0x1.095393f9b90e26f2p+8192L }, + { 0x5.0884ee2ef216ceb8p-12232L, -0x4.b62cb06b0fc0e708p+1172L, 0xe.1158b1bcde399cap+1184L, 0xe.1158b1bcde399cbp+1184L }, + { 0x1.8778ce2f2d89ba82p+6300L, -0x5.a232f0b2fd82fd1p-9100L, -0x8.aa7115611ef092dp-9088L, -0x8.aa7115611ef092cp-9088L }, + { 0x5.24577f8a1d1b998p+4436L, -0x3.5a69e9684f3f2374p+624L, -0x3.a229f193a2b1b89p+636L, -0x3.a229f193a2b1b88cp+636L }, + { 0x3.e93bb773f849539cp-7916L, 0xe.fde691265bdaf28p-520L, -0x1.cf7596412dbee2fap-504L, -0x1.cf7596412dbee2f8p-504L }, + { 0x3.665e1565d0b924cp+5944L, -0x4.16982d7fcb64e9dp-7880L, -0x5.ef3d51e83c4fcfdp-7868L, -0x5.ef3d51e83c4fcfc8p-7868L }, + { 0x3.fafa5900bf81a534p-6252L, 0xb.17cc0862a59adb9p+5632L, -0x1.0ed30f6930eee0ecp+5648L, -0x1.0ed30f6930eee0eap+5648L }, + { 0x8.78bf4985ee30992p-172L, 0x1.0199abbdde89b38cp-3592L, -0xa.9f92837c78e2a71p-3588L, -0xa.9f92837c78e2a7p-3588L }, + { 0x5.1e6faf18p-16416L, 0x4.f5a6b38aa882c1d8p+7064L, -0x1.3dfcb2a38d27ad42p+7080L, -0x1.3dfcb2a38d27ad4p+7080L }, + { 0x5.5ff127fa305d256p-2732L, 0x1.0506d4431b0e8b1ep-11852L, -0xa.df2b936c1b35f1p-11844L, -0xa.df2b936c1b35f0fp-11844L }, + { 0x1.0ad7b52e9d45bd8ep-1620L, -0xa.7ba4137b5209863p-3448L, 0x4.255c9b0e196d188p-3436L, 0x4.255c9b0e196d1888p-3436L }, + { 0x6.80d745f6314c29dp+14384L, -0xb.e3f21267bbdc57fp-676L, -0x2.9c37cf9ff975118p-660L, -0x2.9c37cf9ff975117cp-660L }, + { 0x3.6676a0eb13ce909cp-10052L, 0xe.072b868a1df7877p-3024L, -0x2.26b8c4584e8e6188p-3008L, -0x2.26b8c4584e8e6184p-3008L }, + { 0x6.5df497b7697155a8p+12256L, -0x1.eedd42b14d9a1374p-13580L, -0x5.c90ca70b1a73cdap-13568L, -0x5.c90ca70b1a73cd98p-13568L }, + { 0x1.1d82e518260f0294p+6512L, -0x9.191d1ec32fdf37bp-144L, -0xe.770435b3120105cp-132L, -0xe.770435b3120105bp-132L }, + { 0xd.529973ed01b4e92p+968L, 0x6.ce2581b071a031dp-9196L, 0x1.9d4ea26451941dap-9184L, 0x1.9d4ea26451941da2p-9184L }, + { 0x1.83f16f4f0984ca08p-6872L, -0x5.338c1e2e6f3d2b3p+5908L, 0x8.b9c9ac256e9a086p+5920L, 0x8.b9c9ac256e9a087p+5920L }, + { 0x1.867d77867b5c95eap+2628L, 0x7.3398eb375f75dfb8p-9260L, 0x4.9f210d1f21e1aa2p-9248L, 0x4.9f210d1f21e1aa28p-9248L }, + { 0x1.cd985a87e976e13cp+3076L, -0x1.45dc8a1f648e67c6p-7864L, -0xf.4c830f7af568de8p-7856L, -0xf.4c830f7af568de7p-7856L }, + { 0x1.4a4d37ap-16416L, 0x1.4e33cb5b10e313f4p+10756L, -0x5.3b63e726e0a641f8p+10768L, -0x5.3b63e726e0a641fp+10768L }, + { 0x1.3482020ad3c0a882p-816L, -0x9.872caa0b23c65a8p-5864L, 0x1.e5c4dd4b25b6778cp-5852L, 0x1.e5c4dd4b25b6778ep-5852L }, + { 0x1.0e8ff00081bc371cp-6176L, 0x1.cf4067f2e44a798ep-120L, -0x2.ba7ccd219acfff4p-108L, -0x2.ba7ccd219acfff3cp-108L }, + { 0x7.a6f445256a7fda78p+4636L, -0x6.6c725b49451ea01p+4828L, -0x7.466c2cdfef5e2efp+4840L, -0x7.466c2cdfef5e2ee8p+4840L }, + { 0x1.1a2d2bcf0843d15ep-8644L, 0x6.b3ca3aa6fe517d3p+8440L, -0xe.24dc76733d14932p+8452L, -0xe.24dc76733d14931p+8452L }, + { 0x1.7eca655a01c636c2p+52L, -0x1.dd3c2732d945f4d4p+6296L, -0x6.2053619ae4b322p+6300L, -0x6.2053619ae4b321f8p+6300L }, + { 0x1.9faf5dbf7986dc42p-412L, 0x5.54b138d415c78598p-7720L, -0x8.9092d2bfa96a01p-7712L, -0x8.9092d2bfa96a00fp-7712L }, + { 0xe.bf3d1b364fa7d78p+6240L, 0xb.c74bfc158951011p+408L, 0x1.1f4796923b917cb8p+424L, 0x1.1f4796923b917cbap+424L }, + { 0x7.2ca230e9bfee2468p+9888L, -0x3.6eb3366a69620d54p-11960L, -0x8.49d8c188f6ff293p-11948L, -0x8.49d8c188f6ff292p-11948L }, + { 0x6.c33f156ecd7b9018p-5056L, -0xa.5597ddf352c5401p+6116L, 0xc.bfdf7e5c155895dp+6128L, 0xc.bfdf7e5c155895ep+6128L }, + { 0xc.894ea5b54605326p+8424L, -0x3.29d764acd5dcadc4p+1548L, -0x6.824621f901eaa6bp+1560L, -0x6.824621f901eaa6a8p+1560L }, + { 0x4.dc0e408p-16420L, 0x2.f294ae2e03276788p-14272L, -0xb.d088f60ec237848p-14260L, -0xb.d088f60ec237847p-14260L }, + { 0x1.8d8d6c474b777c26p-6764L, 0x2.82a240469d5e47c8p+912L, -0x4.251fee784a74545p+924L, -0x4.251fee784a745448p+924L }, + { 0x3.320003e916e2c018p-11548L, 0x2.0fc01824588015bp-9448L, -0x5.cfb08c45bb157868p-9436L, -0x5.cfb08c45bb15786p-9436L }, + { 0x2.766f084c0c4d4becp-4344L, -0xf.918a628430c9869p+3260L, 0x1.08196636d42693dp+3276L, 0x1.08196636d42693d2p+3276L }, + { 0x1.a7ea62a617983f7cp+4280L, 0x4.31f5016cb7a06488p-11684L, 0x4.62645a22f39bbd8p-11672L, 0x4.62645a22f39bbd88p-11672L }, + { 0x3.e2845c867de93e5p+4116L, -0x4.d4440dbc662de6f8p+9256L, -0x4.dae4a99df679d47p+9268L, -0x4.dae4a99df679d468p+9268L }, + { 0x6.eab30da02cc2a598p+9760L, 0x1.2c806e5e622e351cp+504L, 0x2.cc3e6de19ba004fcp+516L, 0x2.cc3e6de19ba005p+516L }, + { 0xa.b66e1024516b719p+6312L, -0x2.77acf612cccf4c7p-4604L, -0x3.cdf31b042afc3218p-4592L, -0x3.cdf31b042afc3214p-4592L }, + { 0x1.114b9705d7e2df02p+14968L, -0x1.5d185f94b66e1fdep+11700L, -0x4.fbb4a016d14170f8p+11712L, -0x4.fbb4a016d14170fp+11712L }, + { 0x6.05221386e27406ep+7108L, -0xa.ea5ec6727dbced3p+5124L, -0x1.2f2fb448d3bf0a6ap+5140L, -0x1.2f2fb448d3bf0a68p+5140L }, + { 0xe.ede20bdb2751c04p-4992L, -0x2.63ffa25342447e7cp-14816L, 0x2.e94a60754ec70b58p-14804L, 0x2.e94a60754ec70b5cp-14804L }, + { 0xb.1a3a6ap-16420L, 0x7.4ddb04c8953c689p-224L, -0x1.d46456593d727256p-208L, -0x1.d46456593d727254p-208L }, + { 0x3.6fa725b26802fc1p+3976L, -0x6.a2e23061803132b8p+9584L, -0x6.71d9a5a82683f7f8p+9596L, -0x6.71d9a5a82683f7fp+9596L }, + { 0x3.1bc6c41d7b8d2494p+12084L, 0x1.7b90e0d7a41add8ap-9760L, 0x4.5ff1fc2dc73c17a8p-9748L, 0x4.5ff1fc2dc73c17bp-9748L }, + { 0xf.4bf5dfe195d4e46p-10012L, 0xe.ef03e3c1cc87ddfp-14124L, -0x2.47d0f7fb93db53b8p-14108L, -0x2.47d0f7fb93db53b4p-14108L }, + { 0x5.ddca9397064452p-10792L, 0xf.f4db22808a890c7p+4992L, -0x2.a0817b6ef96e117cp+5008L, -0x2.a0817b6ef96e1178p+5008L }, + { 0x2.3bf4fe007d9b6508p-4292L, 0xf.5b06933a4845034p+6108L, -0x1.01604b2d99b21d0cp+6124L, -0x1.01604b2d99b21d0ap+6124L }, + { 0x1.13b11c9cdbbfb39cp+324L, -0x8.3f36b704651a623p+3780L, -0xa.70e2f6da63903a9p+3788L, -0xa.70e2f6da63903a8p+3788L }, + { 0x3.debb4f1fb4f3d46cp+1624L, 0x4.46c390ab2d99867p+10104L, 0x1.b2941faa9cc9d50ep+10116L, 0x1.b2941faa9cc9d51p+10116L }, + { 0x6.c1201301bf4c9218p+6756L, -0x2.4d6a37f3ed5852fcp+2216L, -0x3.cc95f7fec27acff4p+2228L, -0x3.cc95f7fec27acffp+2228L }, + { 0x1.7499fce7028b5718p-1560L, -0x3.4a630b8e2e554824p+12228L, 0x1.40b836996da41882p+12240L, 0x1.40b836996da41884p+12240L }, + { 0x2.5cdec5c3c9cd305cp-2792L, -0x4.df8c690724ffac2p-10720L, 0x3.52007c9cd5f5bcecp-10708L, 0x3.52007c9cd5f5bcfp-10708L }, + { 0xd.563eae6fd0c7a55p-4L, 0xf.407ea5dcda35ceep+14612L, -0x4.01832b7b29c949a8p+14612L, -0x4.01832b7b29c949ap+14612L }, + { 0x2.88537585e08a0db8p+8480L, -0x2.d1b1e77a78c0add8p-11944L, -0x5.d65ec904e91d1dap-11932L, -0x5.d65ec904e91d1d98p-11932L }, + { 0x1.903cbb912f0bd304p-6664L, 0x1.f043925d5bfa9a4p-6948L, -0x3.2751f0797c3c2104p-6936L, -0x3.2751f0797c3c21p-6936L }, + { 0x1.2d980aa61aaa044ap-5788L, -0x7.5c4c52f7a6d1f848p+3612L, 0xa.6691012806f86e1p+3624L, 0xa.6691012806f86e2p+3624L }, + { 0x3.df18660f37583684p+12996L, 0xa.9226fd0725f5548p-9324L, 0x2.18b8280f88377528p-9308L, 0x2.18b8280f8837752cp-9308L }, + { 0xa.bb09710051dcf8dp-6364L, -0x3.a3b7749ef082dccp+6000L, 0x5.a6d6eb577c61432p+6012L, 0x5.a6d6eb577c614328p+6012L }, + { 0x9.f86536a0190222p-8972L, 0x2.834c95d589ef3c24p-7364L, -0x5.80949d7b13ce07bp-7352L, -0x5.80949d7b13ce07a8p-7352L }, + { 0xf.095b5efb520e98cp-14876L, -0x4.925b19d467927c58p-9252L, 0x1.0996c5412e3615b4p-9236L, 0x1.0996c5412e3615b6p-9236L }, + { 0x1.dad1ee8a661ae87ap+5708L, 0x1.fe352d18c29a58f6p+10544L, 0x2.c71d060d0cef0e34p+10556L, 0x2.c71d060d0cef0e38p+10556L }, + { 0xf.c50d2b0b4759078p+2820L, 0xf.297abc86e6d6ca4p-7248L, 0xa.74140c28fb060b3p-7236L, 0xa.74140c28fb060b4p-7236L }, + { 0x7.0453d1280723b998p-8932L, -0x8.aaf24f9f3a0b99cp-4004L, 0x1.2e54114a95896f2ep-3988L, 0x1.2e54114a95896f3p-3988L }, + { 0x4.4cfc31fp-16416L, 0xb.0d9092f80bfd229p-10520L, -0x2.c4ae93c54ad8e124p-10504L, -0x2.c4ae93c54ad8e12p-10504L }, + { 0xf.a206d4e1105d091p-8016L, -0x2.d55598a73912513p+4172L, 0x5.8accb2f3cc70fd8p+4184L, 0x5.8accb2f3cc70fd88p+4184L }, + { 0x8.2ee1b7d5eb1d0c3p-6348L, -0x7.c8f8d0eff8137ff8p+13384L, 0xc.0f3dddeec691ed5p+13396L, 0xc.0f3dddeec691ed6p+13396L }, + { 0x3.b1a407914e578be8p+8968L, -0x1.7e3c9a467164bd2p-12264L, -0x3.4510b8f20a060848p-12252L, -0x3.4510b8f20a060844p-12252L }, + { 0x3.a757d9b6a00a4ba8p-1900L, -0x7.177fa6a92ce714d8p-3624L, 0x3.495259a9dfb60448p-3612L, 0x3.495259a9dfb6044cp-3612L }, + { 0x3.be5e8801d352664p+6012L, -0x3.a12c079f54735f34p+8764L, -0x5.543ef8fe17f7f85p+8776L, -0x5.543ef8fe17f7f848p+8776L }, + { 0x2.2d8852e645dca22p+9040L, 0x2.ffff06be9f08f6acp-14752L, 0x6.9f33c0295b347e1p-14740L, 0x6.9f33c0295b347e18p-14740L }, + { 0x1.03322ae66aef91c2p-720L, -0x6.ff7e97b99adce708p+5956L, 0x1.3ae73f9a1237c138p+5968L, 0x1.3ae73f9a1237c13ap+5968L }, + { 0xd.9ec53ffbb90281cp-544L, 0x4.4c329e6a78ac8bcp+132L, -0x9.11ba60714038acbp+140L, -0x9.11ba60714038acap+140L }, + { 0x7.536fe5affbc375ep+3920L, 0x3.1222fe8be3486f6p+6204L, 0x2.f0e8a6e185c7e7bcp+6216L, 0x2.f0e8a6e185c7e7cp+6216L }, + { 0x8.15c1c9e9c82d888p+14352L, 0x1.d25ed81d571b76b2p-4888L, 0x6.627636ca6db9ff78p-4876L, 0x6.627636ca6db9ff8p-4876L }, + { 0x1.06142a4caeedca5p+0L, 0x3.0b886441145c1bf8p+8452L, 0x1.a6473f7721100534p+8448L, 0x1.a6473f7721100536p+8448L }, + { 0xa.022610dbd7d5487p-4260L, 0x1.f8669248dbba890cp-12896L, -0x2.0c2fea8c9a403c08p-12884L, -0x2.0c2fea8c9a403c04p-12884L }, + { 0x1.427e698110e4f9cep+12256L, -0xa.ceffd4a7d89dae6p-12572L, -0x2.0579b1a86fbaa90cp-12556L, -0x2.0579b1a86fbaa908p-12556L }, + { 0x6.98bfa5fdcdd697bp+4448L, -0x2.ae37715f3487a328p+6884L, -0x2.e9a4f05a20a95cc4p+6896L, -0x2.e9a4f05a20a95ccp+6896L }, + { 0x5.471706d1fef36668p+11296L, 0x2.60481b44518620e4p-2100L, 0x6.8de218514d390dbp-2088L, 0x6.8de218514d390db8p-2088L }, + { 0x1.c9dc47831fc622dap+8488L, 0x2.277891fbbfd0636p-8056L, 0x4.76e84361d1c36df8p-8044L, 0x4.76e84361d1c36ep-8044L }, + { 0x2.7aa75062a08bbeap-12220L, 0x1.855b35dcfe02fd7cp+12580L, -0x4.897afe1ff40bdd3p+12592L, -0x4.897afe1ff40bdd28p+12592L }, + { 0x4.b2b1830d66fb0c98p-13732L, 0x5.23b229f58bca7ba8p-2960L, -0x1.13a3481ea7e7e5f4p-2944L, -0x1.13a3481ea7e7e5f2p-2944L }, + { 0x8.d08fe057a50127ap-1140L, -0xb.6ba4e2f724db45bp-7688L, 0x3.2b77e4777e7a7954p-7676L, 0x3.2b77e4777e7a7958p-7676L }, + { 0x1.662b22f1dd79fc5ap-1184L, -0x9.5692b3519c8755ap-8328L, 0x2.b2be0450fbef222p-8316L, 0x2.b2be0450fbef2224p-8316L }, + { 0x1.82d56f808fae1b4p+3252L, 0xa.fe2e145fc22e872p+10868L, 0x8.bab6d6535a848adp+10880L, 0x8.bab6d6535a848aep+10880L }, + { 0x6.76cfc11e7b6566b8p-4L, 0x5.449f7a84db9971ap-8384L, -0x6.e363ec6143f817cp-8384L, -0x6.e363ec6143f817b8p-8384L }, + { 0x8.6314a48e9f5cf1bp+14264L, 0x1.02a4a8db28694176p-11124L, 0x3.84e602f86fc958e4p-11112L, 0x3.84e602f86fc958e8p-11112L }, + { 0xb.a215b32c0ab2fb5p-8296L, 0x3.b121832e8103529p+14676L, -0x7.7971416c1af6341p+14688L, -0x7.7971416c1af63408p+14688L }, + { 0x3.dda3552b2cfcb6dp-6772L, 0x7.eae66ccf86eba1b8p-12672L, -0xd.1626578ff235625p-12660L, -0xd.1626578ff235624p-12660L }, + { 0x3.d1bdac6c27a4987cp-11480L, -0xb.f0201fb3fdf4fdap+10816L, 0x2.17410c1ecf9c6a04p+10832L, 0x2.17410c1ecf9c6a08p+10832L }, + { 0x1.753b55139a6ae0d4p-9588L, -0xc.b94fdca214abb5bp-10048L, 0x1.dc8597552b0e5e98p-10032L, 0x1.dc8597552b0e5e9ap-10032L }, + { 0x7.49cfb50979428ccp+13260L, 0x6.d1ca9e09ccdfe48p-8776L, 0x1.614e15a9b7619142p-8760L, 0x1.614e15a9b7619144p-8760L }, + { 0x2.fdb3fd975c2fcc24p-8752L, -0x6.dcfc60eadb01717p+11444L, 0xe.a981b074aac6ebep+11456L, 0xe.a981b074aac6ebfp+11456L }, + { 0x5.461b7b2ee09e674p-3212L, 0x2.75ad884b4a7c987cp+1616L, -0x1.ed696c80266e3dc4p+1628L, -0x1.ed696c80266e3dc2p+1628L }, + { 0x3.fe2313c91b361a94p-11200L, -0xe.dc38443676c5a64p-10132L, 0x2.8a04ef36438bec6p-10116L, 0x2.8a04ef36438bec64p-10116L }, + { 0x7.3bc9614f8e5128c8p+4260L, 0x4.1330a0a05f33682p+14436L, 0x4.3daf7300edde6ddp+14448L, 0x4.3daf7300edde6dd8p+14448L }, + { 0x8.bd152439e522049p-4L, 0xb.92113f16dc8ef45p+13704L, -0xa.18b112a71a99ff9p+13704L, -0xa.18b112a71a99ff8p+13704L }, + { 0x2.19a9a6a149d64b2cp+7252L, 0x1.465d05fbac7ff242p-3232L, 0x2.41ea09187aa26998p-3220L, 0x2.41ea09187aa2699cp-3220L }, + { 0x1.2dfa170de378162p+1848L, 0x6.e3ccc6f233fe54p+11352L, 0x3.1be1289e5ccdfe38p+11364L, 0x3.1be1289e5ccdfe3cp+11364L }, + { 0x2.45ae50f119d75d4cp+9348L, 0x2.48cb633ccf171d88p-8776L, 0x5.36cd745dea71ace8p-8764L, 0x5.36cd745dea71acfp-8764L }, + { 0x3.ffc0ede5facf9aap+144L, -0x1.639d563ebd47e19cp-3360L, -0xc.acf9b954dff786p-3356L, -0xc.acf9b954dff785fp-3356L }, + { 0x1.320a4fa8c7689a5cp+12176L, -0x3.c102f99e035bd4c4p-5096L, -0xb.28d15096dbe0335p-5084L, -0xb.28d15096dbe0334p-5084L }, + { 0x1.06fdec9589c7e3cap-11048L, 0x1.37fe7627faad46a8p+7504L, -0x3.498717a4095b29a8p+7516L, -0x3.498717a4095b29a4p+7516L }, + { 0x3.49a93629ad7fc314p-3304L, -0x6.c1900e2ee2255dfp-10704L, 0x5.72691640c0fb8b8p-10692L, 0x5.72691640c0fb8b88p-10692L }, + { 0x7.3784858026f59eb8p-12536L, 0x1.9512838f9ba32ffap-6896L, -0x4.d775f974a9b756dp-6884L, -0x4.d775f974a9b756c8p-6884L }, + { 0x1.80ea0336ba35c6a6p+10468L, 0x3.c200d3a7e961c3dcp-11276L, 0x9.9ab1fd7e38b6ddp-11264L, 0x9.9ab1fd7e38b6dd1p-11264L }, + { 0x5.aa69355ef02ac868p-13564L, 0x1.76a1cac98f2db2cep+8268L, -0x4.d85fb08ac5441228p+8280L, -0x4.d85fb08ac544122p+8280L }, + { 0x1.b089a658p-16416L, 0x1.ea990a7a7c9093b4p+524L, -0x7.ae22285ee60e2328p+536L, -0x7.ae22285ee60e232p+536L }, + { 0x5.5307153542305dp+5812L, -0xf.a0fa3c8f422f914p-12628L, -0x1.62f865e81f9e158p-12612L, -0x1.62f865e81f9e157ep-12612L }, + { 0x3.d18c9f1fe178b66cp-5976L, 0x3.07dccc28a2dbb64cp-11924L, -0x4.6b9ae7abba0f89dp-11912L, -0x4.6b9ae7abba0f89c8p-11912L }, + { 0xb.a85358c13ac490ep+8052L, -0x1.581f0dbe008f95a6p+3224L, -0x2.a4c7405adef4cb88p+3236L, -0x2.a4c7405adef4cb84p+3236L }, + { 0x5.23afe2a0b74d62p+3396L, 0xf.eaf45db22aa5f58p+400L, 0xd.34e691543edfc8fp+412L, 0xd.34e691543edfc9p+412L }, + { 0xf.bbc8e9388c45f3ap+4960L, 0xd.adbde37244f6cd2p+4352L, 0x1.093ca1363e18977cp+4368L, 0x1.093ca1363e18977ep+4368L }, + { 0xd.0ec84ab52b6bccfp-14316L, 0x3.242368e52518021p-7596L, -0xa.f9d475f53e8f64cp-7584L, -0xa.f9d475f53e8f64bp-7584L }, + { 0xe.6fcb560f3434363p+6672L, -0x2.582d5ceb82c13698p+1228L, -0x3.d2325f4c49e3efp+1240L, -0x3.d2325f4c49e3eefcp+1240L }, + { 0x2.c32af39bbff96d5cp-14764L, 0x3.ac0794141c17ee54p+3048L, -0xd.3bfe31094bba577p+3060L, -0xd.3bfe31094bba576p+3060L }, + { 0x2.1cd826493af5d3a4p-6760L, -0x6.ae408d4f2bfec03p+4488L, 0xb.062231847cd3d58p+4500L, 0xb.062231847cd3d59p+4500L }, + { 0x8.ca91adedeaa1e77p+6300L, 0xf.acd7dd8fa7e0887p-14224L, 0x1.81f2b8e35ed12114p-14208L, 0x1.81f2b8e35ed12116p-14208L }, + { 0x3.3ff778d9323b9c5p-4L, -0xd.c2058e770c939ap+12944L, 0x1.fa34dff1e1c4bc78p+12948L, 0x1.fa34dff1e1c4bc7ap+12948L }, + { 0x1.31637c3000e438e4p+11384L, -0x4.686ea46458512aep-1676L, -0xc.405174ea19fdec5p-1664L, -0xc.405174ea19fdec4p-1664L }, + { 0xd.d9373849cbb5adbp-8496L, -0x4.f30da52b4bc6c1bp-8616L, 0xa.42f909e0e6d629dp-8604L, 0xa.42f909e0e6d629ep-8604L }, + { 0x2.aaaaea743fb846c4p-10376L, -0x8.2ff53eaf90ae7cp-13868L, 0x1.4bcc3637b01b0c72p-13852L, 0x1.4bcc3637b01b0c74p-13852L }, + { 0x8.f919db6c7b9f466p-2356L, -0x6.a312fd5cbddcec78p+12452L, 0x3.cffc82d80b2c68e4p+12464L, 0x3.cffc82d80b2c68e8p+12464L }, + { 0x1.5ef60b9d2b73390ap-1820L, 0x3.6efa517d1c5d3a28p+13140L, -0x1.8676b8655aad1cd6p+13152L, -0x1.8676b8655aad1cd4p+13152L }, + { 0x3.daffca7fb01f62b4p-14284L, -0xf.6af4c77adde2767p+11168L, 0x3.5c25cd91022ff884p+11184L, 0x3.5c25cd91022ff888p+11184L }, + { 0x3.43d37022ccb92268p+5012L, 0x7.e9ab5b70fd0bde88p+11408L, 0x9.af850ca0012c747p+11420L, 0x9.af850ca0012c748p+11420L }, + { 0x2.435d3715a985bcb8p+10736L, 0x3.aacc5c1e9457eadp-10348L, 0x9.9cf2c8d41a4e1ddp-10336L, 0x9.9cf2c8d41a4e1dep-10336L }, + { 0x6.db3d1c3421345d9p+9732L, -0x4.36066072222de638p-12688L, -0xa.0217c93e79fcf29p-12676L, -0xa.0217c93e79fcf28p-12676L }, + { 0x3.08ae8e74c266a098p-5748L, 0xe.770635edbd5eaf3p-13844L, -0x1.44b14e3d8e36c586p-13828L, -0x1.44b14e3d8e36c584p-13828L }, + { 0x1.76212ep-16420L, 0x1.3ab2fe378fa08002p+12544L, -0x4.ed85475e9e6609c8p+12556L, -0x4.ed85475e9e6609cp+12556L }, + { 0x1.fd551ae8610d128p+7480L, 0x3.769a9f2eaaf3700cp-10948L, 0x6.534e5c73be7354ap-10936L, 0x6.534e5c73be7354a8p-10936L }, + { 0xa.e0aac49fb82b00bp-7972L, 0x1.6fd07eaba5d3fd5ep+32L, -0x2.cb9062aca3ea933cp+44L, -0x2.cb9062aca3ea9338p+44L }, + { 0xa.1cb34dbd6cd395fp-1656L, 0x7.4ee3c5874237b978p+12680L, -0x2.f2dec58363c34d3cp+12692L, -0x2.f2dec58363c34d38p+12692L }, + { 0xb.9b50fe352d3c1b1p+364L, -0x8.db835f5f3c3aa14p+2212L, -0xc.b772bb6b1a9a731p+2220L, -0xc.b772bb6b1a9a73p+2220L }, + { 0x3.6d33ead8abf8a548p-13856L, -0x1.c02ccce5ca28e9c4p+2936L, 0x5.ebe5c84acb3e408p+2948L, 0x5.ebe5c84acb3e4088p+2948L }, + { 0x3.0af6574b42ede154p-11844L, 0x1.1478f312ab1800b6p-700L, -0x3.1f56ff3ec7659148p-688L, -0x3.1f56ff3ec7659144p-688L }, + { 0x1.623ac0a3f7aba0bep+8220L, -0x1.4bcc58434b1bb7aap-4960L, -0x2.99e70d80ff093388p-4948L, -0x2.99e70d80ff093384p-4948L }, + { 0x2.745f807c070fa178p-12228L, 0x1.0bdeb66d4a421602p-10224L, -0x3.1f99efcbce646dfcp-10212L, -0x3.1f99efcbce646df8p-10212L }, + { 0x1.d791a56eee5e72cp+4460L, 0xe.eeae1eb0781a412p+5380L, 0x1.04336a8490f4dae4p+5396L, 0x1.04336a8490f4dae6p+5396L }, + { 0x1.005eedfe61628706p-10904L, -0x7.0f25c96d65a172ap+7888L, 0x1.2cad2db5759ce0b4p+7904L, 0x1.2cad2db5759ce0b6p+7904L }, + { 0x8.48b67c8ab19d09dp-4L, -0x1.f888e4fc233d27dcp+6724L, 0x1.df23c41e1919f418p+6724L, 0x1.df23c41e1919f41ap+6724L }, + { 0xc.ae4e6ad45a50465p+4112L, -0x2.518b484925a2b1cp+13764L, -0x2.5464c5094de3f82p+13776L, -0x2.5464c5094de3f81cp+13776L }, + { 0x1.9c18d7876ee7376ep-14044L, 0x1.23d29c845c03c0dap+3464L, -0x3.e886d92ea80a7d1p+3476L, -0x3.e886d92ea80a7d0cp+3476L }, + { 0x2.89d5cb60a9e9af5cp-4744L, -0xd.158a1c32534c8bbp-4820L, 0xf.26591cea3a34904p-4808L, 0xf.26591cea3a34905p-4808L }, + { 0xc.4033377961e2fe8p+9052L, -0x5.b388ee53b605e2b8p-3668L, -0xc.9acd9b90883283fp-3656L, -0xc.9acd9b90883283ep-3656L }, + { 0x1.d50869ea25276784p-10972L, 0x4.d1c12faa90b5e068p-508L, -0xc.e89be19644230e7p-496L, -0xc.e89be19644230e6p-496L }, + { 0x9.febbb7fe5ed6546p-4588L, 0xb.099054e905162d5p-7288L, -0xc.5aabe646430f123p-7276L, -0xc.5aabe646430f122p-7276L }, + { 0x2.9d9c43b7825d326p+12808L, -0x2.ada1ee9ab68cb0fp-4512L, -0x8.602c4c1dc8b3b28p-4500L, -0x8.602c4c1dc8b3b27p-4500L }, + { 0x4.7c5bc0f7776b0ac8p+2520L, -0x3.0a1b28d67b2747b8p-8696L, -0x1.df2103aaf6513a14p-8684L, -0x1.df2103aaf6513a12p-8684L }, + { 0x1.2f7388d95a11e1bep-6608L, 0x5.19ffda1dd0d9c2a8p-4600L, -0x8.3addbca737209aap-4588L, -0x8.3addbca737209a9p-4588L }, + { 0x7.3e70e5fcf433aa28p-11840L, 0x1.d0de4ba9a67c312ap+3816L, -0x5.3f6f925f1b5ac89p+3828L, -0x5.3f6f925f1b5ac888p+3828L }, + { 0x7.d5521358p-16416L, 0xa.6edd69b6078e966p-7072L, -0x2.9ce63aa876c852a4p-7056L, -0x2.9ce63aa876c852ap-7056L }, + { 0x1.a06b478721ce054ep+13548L, -0x1.393c0e863c65bdb8p-6108L, -0x4.0c1d22c0912dc55p-6096L, -0x4.0c1d22c0912dc548p-6096L }, + { 0x3.b69179fa44654bbcp+1440L, -0x6.e4159565f7c389f8p+10500L, -0x2.6d004320fc3ff95cp+10512L, -0x2.6d004320fc3ff958p+10512L }, + { 0x2.5ad010f8b9d60f14p+12900L, 0xb.828c126f8807123p+10908L, 0x2.440c92f86267255p+10924L, 0x2.440c92f862672554p+10924L }, + { 0x9.98a3919087bcbddp+12296L, -0xb.6ce393db0528821p+14940L, -0x2.24eb593295e856b8p+14956L, -0x2.24eb593295e856b4p+14956L }, + { 0xb.5517b51c0f4d664p-4000L, 0x1.d4234882ba64610ep-4640L, -0x1.c8c3fb42f463b05p-4628L, -0x1.c8c3fb42f463b04ep-4628L }, + { 0x8.5bd2dd7bb1477a4p-3904L, -0x1.12e3d6e3b466d59ap-476L, 0x1.05cc87caeb220ccep-464L, 0x1.05cc87caeb220cdp-464L }, + { 0x5.ed808c966d066e28p+7324L, -0x2.00368397327e3fccp-12952L, -0x3.9433ab5ccc8a19ccp-12940L, -0x3.9433ab5ccc8a19c8p-12940L }, + { 0x4.b40d71fc6217c0ap+8936L, -0x5.e9dcc5f1571235p+1792L, -0xc.e7877da64a564eep+1804L, -0xc.e7877da64a564edp+1804L }, + { 0x1.34407e864341f828p+3440L, -0x5.1b8cadf3b9cef08p+11308L, -0x4.4a390c27f8641c38p+11320L, -0x4.4a390c27f8641c3p+11320L }, + { 0x8.179975b3956adafp-10324L, 0x1.dd7c8a838a11dd72p-4000L, -0x4.b328227e31522ce8p-3988L, -0x4.b328227e31522cep-3988L }, + { 0x1.01fdcep-16416L, 0xb.a372ba15d4c940dp-5452L, -0x2.ea50fb8dd4efd0cp-5436L, -0x2.ea50fb8dd4efd0bcp-5436L }, + { 0x5.3b665bec0d2e2dcp-2800L, -0x1.f45e190fe1072f02p-12656L, 0x1.55c1aa1fbb13f3f6p-12644L, 0x1.55c1aa1fbb13f3f8p-12644L }, + { 0x8.992f6f29de9baa1p-6444L, 0x2.6df885a56ac520b8p-14752L, -0x3.d20a120e0c03b828p-14740L, -0x3.d20a120e0c03b824p-14740L }, + { 0xc.c702ea51f29dd29p+1248L, 0x1.8a572c70170d4e5cp+12552L, 0x7.881260ccbcf27268p+12560L, 0x7.881260ccbcf2727p+12560L }, + { 0x7.7da787b409a377c8p-6564L, 0x9.7e0cf04e7e0519bp-6448L, -0xf.348702698a255aep-6436L, -0xf.348702698a255adp-6436L }, + { 0x7.e356b90a1e983p+6044L, -0x1.595f87983b91e67ap+11008L, -0x1.fde107e29925392cp+11020L, -0x1.fde107e29925392ap+11020L }, + { 0x6.68cb8626a1a7bd2p-856L, -0x5.2867609201d772p+3332L, 0x1.13146bfa618ef4acp+3344L, 0x1.13146bfa618ef4aep+3344L }, + { 0x1.d9c129761350a49ep-1456L, -0x1.29e3078444080f32p-2724L, 0x6.9d32b50a997a3358p-2716L, 0x6.9d32b50a997a336p-2716L }, + { 0x7.d308bb4487d45ed8p+8360L, 0x3.05fa312cc9b12db8p-7928L, 0x6.2c42b7a54e1f43p-7916L, 0x6.2c42b7a54e1f4308p-7916L }, + { 0xb.1557c6f908f40bfp+13336L, 0x1.7c6eeead727f952ep-3248L, 0x4.d6f5b1bc630d822p-3236L, 0x4.d6f5b1bc630d8228p-3236L }, + { 0x2.aa3fe22d8b80d434p-3748L, -0x2.bbf4a7d991feb2d4p-864L, 0x2.803ec10c3efa22f4p-852L, 0x2.803ec10c3efa22f8p-852L }, + { 0x5.4ec5032p-16416L, -0x2.6748c73e3720dc58p+11340L, 0x9.a195140488f7b6fp+11352L, 0x9.a195140488f7b7p+11352L }, + { 0x1.97e6fba1fa77cd84p+776L, 0x1.0fd2d35c90316ae6p-10104L, 0x3.38adc0961147ee3cp-10096L, 0x3.38adc0961147ee4p-10096L }, + { 0xa.ff44e18825e4262p-3300L, -0x3.a9ba576b1d83aeep+6148L, 0x2.f2b3a675e3dd0e28p+6160L, 0x2.f2b3a675e3dd0e2cp+6160L }, + { 0x7.8af9d275e91fced8p-7428L, 0x1.4317fd2efba13bf6p-9056L, -0x2.49b16335dd4b114cp-9044L, -0x2.49b16335dd4b1148p-9044L }, + { 0x7.9c3ee1462407ec68p+5156L, -0x3.e97de45eb74e97b4p+11988L, -0x4.ed61fdf674171e78p+12000L, -0x4.ed61fdf674171e7p+12000L }, + { 0x1.47be5e7291ef5b5ep+8620L, 0x1.b6bb4b3df23a952p-3860L, 0x3.9b586e9657351918p-3848L, 0x3.9b586e965735191cp-3848L }, + { 0xf.f85cf60592328d2p-9520L, 0x6.cc119db119c5da9p+9692L, -0xf.ca9a38109b4c719p+9704L, -0xf.ca9a38109b4c718p+9704L }, + { 0x2.4705d056fcb476bp-10860L, 0x3.1a2184afa03ed9b8p+9408L, -0x8.394d6f3a2c6421fp+9420L, -0x8.394d6f3a2c6421ep+9420L }, + { 0x1.efef03e24f29831p-3176L, -0x1.bfca2ff565e7c7bp+7752L, 0x1.5b1b931975e428fcp+7764L, 0x1.5b1b931975e428fep+7764L }, + { 0x7.f9560ea0eafc2cc8p+9148L, -0xe.5db4d730684872fp-4644L, -0x2.0187920d54cfb648p-4628L, -0x2.0187920d54cfb644p-4628L }, + { 0x2.1c6a49285ec69a54p+7380L, -0xb.ddf812b2df6f309p+11120L, -0x1.5627be2e7b4b330ep+11136L, -0x1.5627be2e7b4b330cp+11136L }, + { 0x2.50ff3a6p-16416L, 0x1.9d7cfb7be4e5e346p-3100L, -0x6.790f9653202121ap-3088L, -0x6.790f965320212198p-3088L }, + { 0xa.f2ce777f871a092p+8780L, -0x7.e9c5837c2b7a4378p+8600L, -0x1.0f80f46491d8b8b6p+8616L, -0x1.0f80f46491d8b8b4p+8616L }, + { 0x4.3bbff88395fe0928p+7164L, 0x3.078f7e4f50cee1fp-7468L, 0x5.4cde225bf7236df8p-7456L, 0x5.4cde225bf7236ep-7456L }, + { 0x1.40aedb75cc42f43p-3192L, -0x2.375af19fcf60d21cp-10956L, 0x1.ba17d902e7ac91cp-10944L, 0x1.ba17d902e7ac91c2p-10944L }, + { 0x2.e864c555d76d8fd8p+6104L, 0xb.a979200b6675bf5p+12664L, 0x1.1622d579502026b8p+12680L, 0x1.1622d579502026bap+12680L }, + { 0x6.752e08b00a6d4d98p-13552L, 0x1.90097d94485a7816p-11844L, -0x5.2b4c1e50cbcc733p-11832L, -0x5.2b4c1e50cbcc7328p-11832L }, + { 0x3.04f44aa97cbecd68p+9068L, 0x2.20c52243c3fe5f5cp-1352L, 0x4.b642b5821f0aeabp-1340L, 0x4.b642b5821f0aeab8p-1340L }, + { 0xb.561e8e6deeeb863p+8760L, -0x5.e1ac807eaa7b77d8p+10480L, -0xc.956e10315ea540ep+10492L, -0xc.956e10315ea540dp+10492L }, + { 0xd.22dad1146a3117p-3440L, 0x1.6479b527d613626ep+10984L, -0x1.2b0f6f8ef5196098p+10996L, -0x1.2b0f6f8ef5196096p+10996L }, + { 0x2.22be5768782c69ep-1500L, -0x7.84c022153d71427p+3364L, 0x2.c059ab76744f422p+3376L, 0x2.c059ab76744f4224p+3376L }, + { 0x1.33435c6dd3af5182p-9572L, 0x1.57376b17d4e90b76p-3676L, -0x3.220b9bf2119f92fp-3664L, -0x3.220b9bf2119f92ecp-3664L }, + { 0x6.36fe5bdp-16416L, -0x3.80b314c162ff107cp-3536L, 0xe.093a021c9f60a3ap-3524L, 0xe.093a021c9f60a3bp-3524L }, + { 0x3.5eddbf43ab12e4a8p-5700L, -0xa.5a9dd55c674fbcbp-11372L, 0xe.6777bbf7206e289p-11360L, 0xe.6777bbf7206e28ap-11360L }, + { 0x4.0a86f68d596f23e8p+7288L, -0x2.82d21b0211fc61fp+6792L, -0x4.7815c915a64ae22p+6804L, -0x4.7815c915a64ae218p+6804L }, + { 0x5.dd81aeb5f9a4f41p-12728L, -0x3.431d7252485001e4p+4252L, 0xa.2288cab8ba1862ep+4264L, 0xa.2288cab8ba1862fp+4264L }, + { 0x1.c28b03b6522311d4p+8396L, -0x3.afe5362342fa9fe4p+5704L, -0x7.8efd32fc985cb208p+5716L, -0x7.8efd32fc985cb2p+5716L }, + { 0x9.8ddc34fd380f7cdp+568L, 0xd.ced796ac550d5bp-232L, 0x1.ecfe43ab490e4fp-220L, 0x1.ecfe43ab490e4f02p-220L }, + { 0xa.a847a961d00df0ap-12848L, 0x3.93bd979611f43f78p-112L, -0xb.37a8505a07b2fcfp-100L, -0xb.37a8505a07b2fcep-100L }, + { 0x3.4f402dd17b106c64p+2848L, 0xa.f846845320f317ep+11452L, 0x7.a1d0165417058f2p+11464L, 0x7.a1d0165417058f28p+11464L }, + { 0x3.5fa4d9a9fc21151cp-1100L, -0x6.a6e5ab8e0621faap-5044L, 0x1.c89777bcbd33655ap-5032L, 0x1.c89777bcbd33655cp-5032L }, + { 0x5.2d133d77a9410b7p-2572L, -0x3.275ca162a017e318p+6740L, 0x1.fa7fbb2b9abf17f6p+6752L, 0x1.fa7fbb2b9abf17f8p+6752L }, + { 0xb.e1fef9fa3e9727bp+7852L, -0x5.05efe9b304aee998p-8292L, -0x9.a240a67e18be2fap-8280L, -0x9.a240a67e18be2f9p-8280L }, + { 0x1.c09e468785b5c354p+0L, -0xf.e5ab606d8f7b3f9p+7364L, -0xc.ddc3c7616dc446ap+7364L, -0xc.ddc3c7616dc4469p+7364L }, + { 0x1.719eead8a3620922p-180L, -0x9.35dd3e7b4a587e8p-344L, 0x6.74fe200dd9b9ac08p-336L, 0x6.74fe200dd9b9ac1p-336L }, + { 0x2.8278beb0a151763cp-8212L, 0x5.eba3b3c3cbebaa48p+8284L, -0xb.de30343dea0b754p+8296L, -0xb.de30343dea0b753p+8296L }, + { 0x3.87c4c0dbaba1349cp-12224L, 0x6.e4fe70430b5bdc7p+1680L, -0x1.4929e97c9702dfbap+1696L, -0x1.4929e97c9702dfb8p+1696L }, + { 0x7.f319306232e2f73p-6724L, -0x1.ee505dd9decefc84p-6388L, 0x3.2b1b071aed29ccap-6376L, 0x3.2b1b071aed29cca4p-6376L }, + { 0x9.1283f8a751c7f83p+12432L, 0x7.dca6e7a2f237d91p+2120L, 0x1.7de46c83437e1e1ep+2136L, 0x1.7de46c83437e1e2p+2136L }, + { 0x1.3c34c3c18ccb74p+3424L, 0x1.dfc743544c7cf47p-10028L, 0x1.9119b57694c572a8p-10016L, 0x1.9119b57694c572aap-10016L }, + { 0x5.3e565a011294bb1p-3244L, -0x7.3b196b739bfda8ep+10224L, 0x5.b8f9d0123290a33p+10236L, 0x5.b8f9d0123290a338p+10236L }, + { 0x3.8eadcc909e81db74p+8456L, -0x8.b4ba5efc626545bp-7348L, -0x1.1fa19c6bacf2da3ep-7332L, -0x1.1fa19c6bacf2da3cp-7332L }, + { 0xd.3e930c035371ebdp+1480L, 0xd.c6f32497b5fa56dp-8132L, 0x4.fd987b827f63e48p-8120L, 0x4.fd987b827f63e488p-8120L }, + { 0x1.ca7125b550edcfa2p+12328L, -0x8.5acc8c64428f007p-4880L, -0x1.925b90260d25c798p-4864L, -0x1.925b90260d25c796p-4864L }, + { 0x1.0759db8p-16416L, -0x1.3d7f601417185b42p+9944L, 0x4.f877af95374dab3p+9956L, 0x4.f877af95374dab38p+9956L }, + { 0x2.ebd4b19614542238p-14220L, -0xe.1d7e71fee6192bap-6916L, 0x3.0ff877205d61bf4p-6900L, 0x3.0ff877205d61bf44p-6900L }, + { 0x1.29f13fe64015ff46p-12340L, -0xe.d00c66c632b4331p-4136L, 0x2.ca0157bfdbd30f1cp-4120L, 0x2.ca0157bfdbd30f2p-4120L }, + { 0x3.f63ba994a2b78004p+10240L, -0x1.57d10ff018294618p+10496L, -0x3.5bb555eab8c5fb3cp+10508L, -0x3.5bb555eab8c5fb38p+10508L }, + { 0xa.4140ce712f7b66p-6044L, 0xa.a4bce42874e01e7p+7932L, -0xf.b259d473b5ba7p+7944L, -0xf.b259d473b5ba6ffp+7944L }, + { 0x2.389ed5e685fc7134p-7432L, 0x1.b0d67f730c4f25bp+2716L, -0x3.113e0ce097de504p+2728L, -0x3.113e0ce097de503cp+2728L }, + { 0x2.eb978b7f340e0d58p-12364L, -0x9.adfe099d19d2efdp+14472L, 0x1.d37051fa5ea8b54cp+14488L, 0x1.d37051fa5ea8b54ep+14488L }, + { 0x1.5117ecccbd2929b6p-984L, -0x2.b3ae7a75c3b22b8p+7932L, 0xa.61940cdf8cae1a3p+7940L, 0xa.61940cdf8cae1a4p+7940L }, + { 0x9.c5c6d7173a39debp+2136L, -0xe.7eb5c52358f835ep+764L, -0x7.920e831d2af5f778p+776L, -0x7.920e831d2af5f77p+776L }, + { 0x4.3cbd69afe18488ap-11676L, -0x4.fc641a37202982b8p+4448L, 0xe.35d02b71acd487fp+4460L, 0xe.35d02b71acd488p+4460L }, + { 0x3.f0fb7afa6ec2cfb8p-3124L, 0x8.c94c984dbf4168dp-7396L, -0x6.b27180ae20d41818p-7384L, -0x6.b27180ae20d4181p-7384L }, + { 0x1.15ebd30a56ecb2b2p+0L, -0x5.856bb2e62511b85p-6612L, -0xa.7891ddb0a39e893p-6616L, -0xa.7891ddb0a39e892p-6616L }, + { 0x1.410266a44f4ade2cp+12952L, -0x5.59c0fbbe79fde728p-3952L, -0x1.0eb6baf03c343682p-3936L, -0x1.0eb6baf03c34368p-3936L }, + { 0x4.9a419d04fd743ab8p-1156L, 0x9.9730cd1292b85ap-2352L, -0x2.b3998f683c0b5874p-2340L, -0x2.b3998f683c0b587p-2340L }, + { 0x2.60759aed3ba97d74p-6648L, -0x3.457e7b428940e34cp+6612L, 0x5.4f0968584e19d46p+6624L, 0x5.4f0968584e19d468p+6624L }, + { 0x2.c09bd6c830c2da0cp+4984L, 0x3.6fa2b8685f61706p-9464L, 0x4.2ea6cd39acdfcd5p-9452L, 0x4.2ea6cd39acdfcd58p-9452L }, + { 0x7.78d4cf72d7cf81d8p-2060L, 0x7.d23da006d9cb052p-476L, -0x3.ed916667567ea0d4p-464L, -0x3.ed916667567ea0dp-464L }, + { 0x1.e8ec274891c36f6cp-7524L, -0xe.b8e278ce572ceccp+13540L, 0x1.b0a4220a5507d7cap+13556L, 0x1.b0a4220a5507d7ccp+13556L }, + { 0x2.52eaea727fb51b3cp+1024L, 0x3.2d22702027067fbp+7032L, 0xc.b866f7b6cca84f4p+7040L, 0xc.b866f7b6cca84f5p+7040L }, + { 0x4.79b08bc9ec6fd5e8p+10104L, 0x1.81c5dfaf98a0897p+10364L, 0x3.b7d3bdf2e8856dccp+10376L, 0x3.b7d3bdf2e8856ddp+10376L }, + { 0x4.a5a62cfd609d80cp+5652L, -0x5.87842a4bef49dfa8p-7756L, -0x7.a203332a806e1458p-7744L, -0x7.a203332a806e145p-7744L }, + { 0x1.3174a6b7f76a7a86p-3852L, 0x1.3b46ff4438b080d2p+3696L, -0x1.2879ff24035ac472p+3708L, -0x1.2879ff24035ac47p+3708L }, + { 0x1.59099ec9256df04ap+0L, -0x1.277978f781f67db2p+8000L, -0x7.f3bf3708724aa25p+7996L, -0x7.f3bf3708724aa248p+7996L }, + { 0x1.3cf4d6911744a6e2p-6764L, -0x2.b9ce903eca743bf8p-8152L, 0x4.80486c57075689p-8140L, 0x4.80486c5707568908p-8140L }, + { 0x9.e73df967ed71cb5p+10888L, -0x9.1c04010e8eff95cp+200L, -0x1.838dac64b03492fp+216L, -0x1.838dac64b03492eep+216L }, + { 0x5.ac4763ac26327b68p-2172L, 0x6.d1b60df617649598p-9812L, -0x3.9ca312dc58e6275p-9800L, -0x3.9ca312dc58e6274cp-9800L }, + { 0x7.c5ae0be7d6818d3p+2488L, -0x4.dbabdbbb9c48c46p+9484L, -0x2.f454d6d39c21f13cp+9496L, -0x2.f454d6d39c21f138p+9496L }, + { 0x5.da0ebfb61ec3d02p+12980L, -0x1.581ed3ef522cbf1ap-6680L, -0x4.42b6830ac9def328p-6668L, -0x4.42b6830ac9def32p-6668L }, + { 0xc.49cd167ff1e78d8p-7248L, 0x2.5d1e3b11ab1bc11p+9356L, -0x4.2e3d9db76c4da9bp+9368L, -0x4.2e3d9db76c4da9a8p+9368L }, + { 0x2.3b097280a7388008p-11704L, -0x1.061a800d969622bap+4464L, 0x2.ecddc2fed514cc58p+4476L, 0x2.ecddc2fed514cc5cp+4476L }, + { 0x3.cb828c1d80e286fcp+9648L, 0x4.e4c85ab7c7a946f8p-4884L, 0xb.877a950bfab740bp-4872L, 0xb.877a950bfab740cp-4872L }, + { 0xc.edf760d6631b3bep+8604L, -0x1.d29ab8a4c77d5026p+12620L, -0x3.d49031197037c1fcp+12632L, -0x3.d49031197037c1f8p+12632L }, + { 0xe.225defb5c321ae6p-14048L, -0x5.74840b374f4bf2b8p+5052L, 0x1.2b44f5a5454a26a4p+5068L, 0x1.2b44f5a5454a26a6p+5068L }, + { 0x1.f568cdf552161702p+0L, -0x3.0fa175f6b0d25a68p+13292L, -0x2.f8001ffc544eaf7p+13292L, -0x2.f8001ffc544eaf6cp+13292L }, + { 0xc.720d79d29899fb8p+11764L, 0x9.7936377be97bc8ep-14464L, 0x1.b3788544a5202dp-14448L, 0x1.b3788544a5202d02p-14448L }, + { 0x1.65183aeb23c7f346p-12864L, 0x3.7e98b83d4e4ca3d4p-1628L, -0xa.f97cc9cbef6f274p-1616L, -0xa.f97cc9cbef6f273p-1616L }, + { 0x1.ef79e62dda211fbp-1948L, -0x4.d23ac0a4bc617a2p-7780L, 0x2.4ab1f4112fd17bd8p-7768L, 0x2.4ab1f4112fd17bdcp-7768L }, + { 0x2.07b821eeab20cb9p-160L, -0x3.87a37dafaa376984p-3444L, 0x2.312b08e897671c68p-3436L, 0x2.312b08e897671c6cp-3436L }, + { 0xe.72871f0890145a5p+6524L, -0x8.9b9c7083ec7bb41p+4312L, -0xd.b7ed0b19656759ep+4324L, -0xd.b7ed0b19656759dp+4324L }, + { 0x7.4749b7447d5e7338p+5256L, -0x2.62e022dcd7674688p+13968L, -0x3.104df1ed95530a84p+13980L, -0x3.104df1ed95530a8p+13980L }, + { 0x3.7b8f1a318d818b88p-652L, -0xf.181bfa7fcc16529p+14968L, 0x2.6563b23fcf087a7cp+14980L, 0x2.6563b23fcf087a8p+14980L }, + { 0x7.5c8ebd177e7ae458p+7036L, 0xe.f0ee6b7c83a4f2ap+8576L, 0x1.9ad0e0a9821d3b5ep+8592L, 0x1.9ad0e0a9821d3b6p+8592L }, + { 0xa.9952cee8bf7946cp+9776L, -0x9.ebe699f73877e14p+9532L, -0x1.7b024099ee813daep+9548L, -0x1.7b024099ee813dacp+9548L }, + { 0x5.41cd5dd4d2e6f57p-832L, 0x7.56f01406b724bdfp-1104L, -0x1.7c8f99b2a519ef76p-1092L, -0x1.7c8f99b2a519ef74p-1092L }, + { 0x7.6952ff4171fab3e8p-4L, -0x1.48ad521dcbf4fffap+2016L, 0x1.6ce9dbd767f12b1p+2016L, 0x1.6ce9dbd767f12b12p+2016L }, + { 0x1.8ea82281163d7928p-10440L, 0x7.f9f050a81e69354p+10508L, -0x1.4543b78b02164af6p+10524L, -0x1.4543b78b02164af4p+10524L }, + { 0x1.6ad2d6305e908336p-4748L, -0xb.4b631a00023d4e5p-88L, 0xd.174834bfe56bdf3p-76L, 0xd.174834bfe56bdf4p-76L }, + { 0x7.eb9bc51887342998p-10920L, -0x2.99dd95695c7be558p+14760L, 0x6.eeb8ff1797c83d48p+14772L, 0x6.eeb8ff1797c83d5p+14772L }, + { 0x4.b577a5ced64ab34p-2420L, 0x2.19c1abad13c7ff4p+6292L, -0x1.3d6c8b4378990c28p+6304L, -0x1.3d6c8b4378990c26p+6304L }, + { 0x3.5a9733b22bf6430cp+448L, -0x9.845cc05884f6906p-3452L, -0x1.0b83fc7f2a9cbfe2p-3440L, -0x1.0b83fc7f2a9cbfep-3440L }, + { 0x1.8d9e8b60d5f8a05cp-872L, -0x1.50baf7988b16437p-12748L, 0x4.7a26f37415047d8p-12740L, 0x4.7a26f37415047d88p-12740L }, + { 0x1.768be5f438d658c6p+7928L, -0xe.79a06c92bcdce18p+9292L, -0x1.c04e9286dd4bbf2ap+9308L, -0x1.c04e9286dd4bbf28p+9308L }, + { 0x5.cc20a3adbc707e28p-2948L, 0x1.418168344c0a6e5cp+10428L, -0xe.73270ee786c9bb4p+10436L, -0xe.73270ee786c9bb3p+10436L }, + { 0x2.01c7e3e1c94921a8p-116L, -0x7.49980d9c71c299dp-5404L, 0x3.4605f5bf68747d74p-5396L, 0x3.4605f5bf68747d78p-5396L }, + { 0x1.2d18c093a14af7c2p+13716L, -0x3.2206b08cd203d208p-12288L, -0xa.7dbca28d7e9a709p-12276L, -0xa.7dbca28d7e9a708p-12276L }, + { 0x1.9b11ae9e8789a284p+0L, -0xc.b66cf8836b8e5dbp-1376L, -0x8.af8b48e59260aa5p-1376L, -0x8.af8b48e59260aa4p-1376L }, + { 0x3.b06bfa9d957936c4p-4168L, -0x1.188ea5802ac70448p+8880L, 0x1.1d5c217dd118b722p+8892L, 0x1.1d5c217dd118b724p+8892L }, + { 0x7.baa53749caf9a77p+800L, -0x3.ea31eb4e2589909cp-10688L, -0xc.4768c5478ebac23p-10680L, -0xc.4768c5478ebac22p-10680L }, + { 0xc.41014580a7e7c5bp-6320L, 0x1.a46de5ad785de1bcp+8256L, -0x2.885692990a3b54ccp+8268L, -0x2.885692990a3b54c8p+8268L }, + { 0xe.6403838c15ab5c3p+5876L, -0x7.15c7d5d8dcdd2f4p-6296L, -0xa.2bb3092c3f77652p-6284L, -0xa.2bb3092c3f77651p-6284L }, + { 0x4.65c5ae737a956a58p-6604L, -0xe.3fc8bb8cbd6b77fp+7832L, 0x1.6f76fc0e8ab70b94p+7848L, 0x1.6f76fc0e8ab70b96p+7848L }, + { 0x6.8944175f279787cp+10884L, -0x3.c6fc4b6f87ef254p+7116L, -0xa.0a2397fa3e675fbp+7128L, -0xa.0a2397fa3e675fap+7128L }, + { 0x7.97bc7363ddb9f9dp-14396L, -0x1.705e3b449ab47172p-10828L, 0x5.0e6bdb7051618038p-10816L, 0x5.0e6bdb705161804p-10816L }, + { 0xf.4b3b8c6e5f4077ep-8792L, -0xe.ed14847db8e58eap+10408L, 0x2.00637d26121590cp+10424L, 0x2.00637d26121590c4p+10424L }, + { 0x2.41544dd69bee4b34p-12932L, -0x9.56c015923cb5347p+9124L, 0x1.d7b74a4ea2338eb6p+9140L, 0x1.d7b74a4ea2338eb8p+9140L }, + { 0xd.e8a92b7b9d69849p+6300L, 0x3.378443d08ca9b84p-7784L, 0x4.f36729d56447749p-7772L, 0x4.f36729d564477498p-7772L }, + { 0x2.95a69238p-16416L, -0x7.80265f26200c7ebp+3052L, 0x1.e0ef561ee038353cp+3068L, 0x1.e0ef561ee038353ep+3068L }, + { 0x3.d22d04b09cd96cp-9300L, 0xf.766def43d7f6db7p-4796L, -0x2.319c6a506e36063p-4780L, -0x2.319c6a506e36062cp-4780L }, + { 0xe.05ec56e0474d77fp-9876L, 0x6.3465a4ac0b6eea4p+3892L, -0xe.f45bdd4a240a8e9p+3904L, -0xe.f45bdd4a240a8e8p+3904L }, + { 0x1.5625d5075933e438p-12804L, -0x1.6a8b27da36acfbfcp+1128L, 0x4.6d4403e057a6ebcp+1140L, 0x4.6d4403e057a6ebc8p+1140L }, + { 0x3.ff1468eb7c6639d8p+2168L, 0x5.89011895dd2bfa1p+9524L, 0x2.eeb5173dba868ba4p+9536L, 0x2.eeb5173dba868ba8p+9536L }, + { 0x5.5e6fb8e79a725d4p-10600L, 0x3.4479f5178f043be4p+5416L, -0x8.7436da836e63732p+5428L, -0x8.7436da836e63731p+5428L }, + { 0x4.bac9e5fddf2f185p+7280L, 0x2.f6cd56a85259e42p+12372L, 0x5.45114581f9e1dacp+12384L, 0x5.45114581f9e1dac8p+12384L }, + { 0x4.483dd9562600d12p-9412L, -0xa.91077e9f213cfefp-5060L, 0x1.8465eb7223d017dep-5044L, 0x1.8465eb7223d017ep-5044L }, + { 0x6.89490ba0c6021cbp-10152L, -0x1.93dd39b70d0c7806p+3368L, 0x3.e8b771e60bf65d74p+3380L, 0x3.e8b771e60bf65d78p+3380L }, + { 0x6.a491ee61660c85b8p-8176L, -0x8.c58567eeb3bfc0fp+1020L, 0x1.180c5e553f4e3ccap+1036L, 0x1.180c5e553f4e3cccp+1036L }, + { 0xd.f08f28601b06388p+13780L, 0x1.f2be9ba2b44f15dep+7068L, 0x6.8e5e3dc0bd5a4308p+7080L, 0x6.8e5e3dc0bd5a431p+7080L }, + { 0x7.457d5fa8p-16416L, 0x5.36121d8b16e4023p+12776L, -0x1.4e1c5f378a2e9af4p+12792L, -0x1.4e1c5f378a2e9af2p+12792L }, + { 0x4.1748a66d103e0fa8p+2480L, -0xb.d4d5cce3f37beb6p-5748L, -0x7.2b5e31b51058241p-5736L, -0x7.2b5e31b510582408p-5736L }, + { 0x9.a2ade899ef170ddp-7756L, 0x1.bd8b440f03c52848p+2808L, -0x3.4b4e71fdaa1b4c3cp+2820L, -0x3.4b4e71fdaa1b4c38p+2820L }, + { 0x1.92f53c269af15d42p-2928L, -0xa.9b2b2aefde35ef1p-10024L, 0x7.947ccb13fbbf40fp-10012L, 0x7.947ccb13fbbf40f8p-10012L }, + { 0x6.5d56109347b4ece8p-5268L, -0xa.9333fe0a2e921e5p+732L, 0xd.980ed7ca91c85f8p+744L, 0xd.980ed7ca91c85f9p+744L }, + { 0x3.7331573dbbfe41p-9136L, 0xd.1d5fbf9a047f6e6p-6984L, -0x1.d3f0daca4b8e608cp-6968L, -0x1.d3f0daca4b8e608ap-6968L }, + { 0x1.22091bc1d5e9fd24p+3872L, -0x4.9486f9b8459c0e5p-1392L, -0x4.5474ca8e81c1c0c8p-1380L, -0x4.5474ca8e81c1c0cp-1380L }, + { 0x2.386cb89f395c99d8p+5940L, -0x2.96e4faa003243a54p+9812L, -0x3.c1833e77be9321d8p+9824L, -0x3.c1833e77be9321d4p+9824L }, + { 0xd.a5f4daee140e571p+14840L, -0x1.4c05492fe894fe3cp-13360L, -0x4.b33b6593c762fa18p-13348L, -0x4.b33b6593c762fa1p-13348L }, + { 0x2.fdd1ccf5dd08fa6cp+7320L, 0xc.71f7b0b27cb30f2p-8224L, 0x1.63ee6ef689e23e96p-8208L, 0x1.63ee6ef689e23e98p-8208L }, + { 0x1.18572e37370fa8eap-5800L, -0x5.6bd9b71f1fad727p-10896L, 0x7.ad2c6c0e239a106p-10884L, 0x7.ad2c6c0e239a1068p-10884L }, + { 0x4.338ea3e8p-16416L, 0x7.6d96c7989caed318p+6588L, -0x1.dc4402ce4443924cp+6604L, -0x1.dc4402ce4443924ap+6604L }, + { 0x5.b84f9fac30c5708p+7284L, 0x2.75e933325654ae8cp-9812L, 0x4.6092020d634cd7e8p-9800L, 0x4.6092020d634cd7fp-9800L }, + { 0x3.3e8858dcbe489fccp-14240L, 0x7.1714d40b275a0028p+2264L, -0x1.8a57dcc28e880ca2p+2280L, -0x1.8a57dcc28e880cap+2280L }, + { 0x9.afa19306462ec46p-4888L, -0x3.32b794a45c3dca3p-11648L, 0x3.d05e73304663623cp-11636L, 0x3.d05e73304663624p-11636L }, + { 0xd.6eaf9e68e259a17p+1236L, 0x1.cae4c43fd3dd00fcp+568L, 0x8.ae504857a6a66dap+576L, 0x8.ae504857a6a66dbp+576L }, + { 0x1.5385af8dce743fa2p+4740L, 0xc.6bc92b4c49f5ed6p-10560L, 0xe.600c818b9dbc8e6p-10548L, 0xe.600c818b9dbc8e7p-10548L }, + { 0x2.6955eff09a469d1p-5464L, 0x1.bf618641435e7edep-13260L, -0x2.54a916727d0b84p-13248L, -0x2.54a916727d0b83fcp-13248L }, + { 0xb.b90392d51073b9p+2700L, -0xb.85d9396b5e43565p-13416L, -0x7.9b09aa40c40f5878p-13404L, -0x7.9b09aa40c40f587p-13404L }, + { 0x1.4e74d9c2a57143e4p+3248L, 0x1.3eb38c672955f3f6p-14744L, 0xf.cc00ef9a86640aap-14736L, 0xf.cc00ef9a86640abp-14736L }, + { 0x2.ffdfeb1e2d7afdcp-4136L, -0x4.d00269c32889b9bp-5536L, 0x4.db90696a8a4897cp-5524L, 0x4.db90696a8a4897c8p-5524L }, + { 0x4.31404d22df9d95fp-7388L, 0x1.0fe8d9c29ebdb07ep+764L, -0x1.ea4f1ad3071fc356p+776L, -0x1.ea4f1ad3071fc354p+776L }, + { 0x5.0dda6b7p-16416L, 0x2.4106f760ba40ae1p-596L, -0x9.08499f030f1555dp-584L, -0x9.08499f030f1555cp-584L }, + { 0x7.8bae544d63ec3028p-7564L, -0xc.a0b5e26f909cb8bp+6516L, 0x1.74f7acb203909964p+6532L, 0x1.74f7acb203909966p+6532L }, + { 0x5.4c3c08113f951888p-2412L, -0x9.c30a7694e19585ep-7016L, 0x5.be22b69ad1450abp-7004L, 0x5.be22b69ad1450ab8p-7004L }, + { 0x5.afb9c4521af8ad88p-5172L, -0x5.37c3c13b646fb49p+9220L, 0x6.95d89660c2da22f8p+9232L, 0x6.95d89660c2da23p+9232L }, + { 0x1.cd7081ce9dc8e7b6p+88L, -0x1.867a488422075acp-1032L, -0x8.785f0a1c2ad14f6p-1028L, -0x8.785f0a1c2ad14f5p-1028L }, + { 0xc.eab3815fae9cc61p-4692L, 0x8.ffb864f70ff47bcp+14852L, -0xa.4cda82a0bacc544p+14864L, -0xa.4cda82a0bacc543p+14864L }, + { 0x9.034b59783532405p-14652L, 0x1.068f1b119399b4fep+8912L, -0x3.ab025bbdc4919f7p+8924L, -0x3.ab025bbdc4919f6cp+8924L }, + { 0x2.7ea6fa3a41a2ed88p+13384L, -0x1.cb41210310ca777cp-2836L, -0x5.dccc2ba4750423a8p-2824L, -0x5.dccc2ba4750423ap-2824L }, + { 0x7.07a46917c6845538p-11804L, 0xe.2919c752d6e306p+14380L, -0x2.8cc7496f5889be98p+14396L, -0x2.8cc7496f5889be94p+14396L }, + { 0x1.e93b47f4fe49cc4p+3472L, -0xc.48da1160ad2d58bp-8004L, -0xa.6a788032e89083ap-7992L, -0xa.6a788032e890839p-7992L }, +}; + +int check_equal(long double res, long double expected) +{ + if (res != expected) { + return 0; + } + return (__builtin_copysignl(1.0L, res) == + __builtin_copysignl(1.0L, expected)); +} + +int main(void) +{ + int ret = 0; + int i; + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + long double ld_res; + __asm__ volatile ("fyl2x" : "=t" (ld_res) : + "0" (tests[i].arg0), "u" (tests[i].arg1) : "st(1)"); + if (!check_equal(ld_res, tests[i].down) && + !check_equal(ld_res, tests[i].up)) { + printf("FAIL: fyl2x %La %La, expected %La or %La, got %La\n", + tests[i].arg0, tests[i].arg1, tests[i].down, tests[i].up, + ld_res); + ret = 1; + } + } + return ret; +} From ff57bb7b63267dabd60f88354c8c29ea5e1eb3ec Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Tue, 23 Jun 2020 00:01:38 +0000 Subject: [PATCH 1706/2595] target/i386: reimplement fpatan using floatx80 operations The x87 fpatan emulation is currently based around conversion to double. This is inherently unsuitable for a good emulation of any floatx80 operation. Reimplement using the soft-float operations, as for other such instructions. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 487 ++++++++++++- tests/tcg/i386/test-i386-fpatan.c | 1071 +++++++++++++++++++++++++++++ 2 files changed, 1554 insertions(+), 4 deletions(-) create mode 100644 tests/tcg/i386/test-i386-fpatan.c diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 62820bc735..71cec3962f 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -1239,14 +1239,493 @@ void helper_fptan(CPUX86State *env) } } +/* Values of pi/4, pi/2, 3pi/4 and pi, with 128-bit precision. */ +#define pi_4_exp 0x3ffe +#define pi_4_sig_high 0xc90fdaa22168c234ULL +#define pi_4_sig_low 0xc4c6628b80dc1cd1ULL +#define pi_2_exp 0x3fff +#define pi_2_sig_high 0xc90fdaa22168c234ULL +#define pi_2_sig_low 0xc4c6628b80dc1cd1ULL +#define pi_34_exp 0x4000 +#define pi_34_sig_high 0x96cbe3f9990e91a7ULL +#define pi_34_sig_low 0x9394c9e8a0a5159dULL +#define pi_exp 0x4000 +#define pi_sig_high 0xc90fdaa22168c234ULL +#define pi_sig_low 0xc4c6628b80dc1cd1ULL + +/* + * Polynomial coefficients for an approximation to atan(x), with only + * odd powers of x used, for x in the interval [-1/16, 1/16]. (Unlike + * for some other approximations, no low part is needed for the first + * coefficient here to achieve a sufficiently accurate result, because + * the coefficient in this minimax approximation is very close to + * exactly 1.) + */ +#define fpatan_coeff_0 make_floatx80(0x3fff, 0x8000000000000000ULL) +#define fpatan_coeff_1 make_floatx80(0xbffd, 0xaaaaaaaaaaaaaa43ULL) +#define fpatan_coeff_2 make_floatx80(0x3ffc, 0xccccccccccbfe4f8ULL) +#define fpatan_coeff_3 make_floatx80(0xbffc, 0x92492491fbab2e66ULL) +#define fpatan_coeff_4 make_floatx80(0x3ffb, 0xe38e372881ea1e0bULL) +#define fpatan_coeff_5 make_floatx80(0xbffb, 0xba2c0104bbdd0615ULL) +#define fpatan_coeff_6 make_floatx80(0x3ffb, 0x9baf7ebf898b42efULL) + +struct fpatan_data { + /* High and low parts of atan(x). */ + floatx80 atan_high, atan_low; +}; + +static const struct fpatan_data fpatan_table[9] = { + { floatx80_zero, + floatx80_zero }, + { make_floatx80(0x3ffb, 0xfeadd4d5617b6e33ULL), + make_floatx80(0xbfb9, 0xdda19d8305ddc420ULL) }, + { make_floatx80(0x3ffc, 0xfadbafc96406eb15ULL), + make_floatx80(0x3fbb, 0xdb8f3debef442fccULL) }, + { make_floatx80(0x3ffd, 0xb7b0ca0f26f78474ULL), + make_floatx80(0xbfbc, 0xeab9bdba460376faULL) }, + { make_floatx80(0x3ffd, 0xed63382b0dda7b45ULL), + make_floatx80(0x3fbc, 0xdfc88bd978751a06ULL) }, + { make_floatx80(0x3ffe, 0x8f005d5ef7f59f9bULL), + make_floatx80(0x3fbd, 0xb906bc2ccb886e90ULL) }, + { make_floatx80(0x3ffe, 0xa4bc7d1934f70924ULL), + make_floatx80(0x3fbb, 0xcd43f9522bed64f8ULL) }, + { make_floatx80(0x3ffe, 0xb8053e2bc2319e74ULL), + make_floatx80(0xbfbc, 0xd3496ab7bd6eef0cULL) }, + { make_floatx80(0x3ffe, 0xc90fdaa22168c235ULL), + make_floatx80(0xbfbc, 0xece675d1fc8f8cbcULL) }, +}; + void helper_fpatan(CPUX86State *env) { - double fptemp, fpsrcop; + uint8_t old_flags = save_exception_flags(env); + uint64_t arg0_sig = extractFloatx80Frac(ST0); + int32_t arg0_exp = extractFloatx80Exp(ST0); + bool arg0_sign = extractFloatx80Sign(ST0); + uint64_t arg1_sig = extractFloatx80Frac(ST1); + int32_t arg1_exp = extractFloatx80Exp(ST1); + bool arg1_sign = extractFloatx80Sign(ST1); + + if (floatx80_is_signaling_nan(ST0, &env->fp_status)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_silence_nan(ST0, &env->fp_status); + } else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_silence_nan(ST1, &env->fp_status); + } else if (floatx80_invalid_encoding(ST0) || + floatx80_invalid_encoding(ST1)) { + float_raise(float_flag_invalid, &env->fp_status); + ST1 = floatx80_default_nan(&env->fp_status); + } else if (floatx80_is_any_nan(ST0)) { + ST1 = ST0; + } else if (floatx80_is_any_nan(ST1)) { + /* Pass this NaN through. */ + } else if (floatx80_is_zero(ST1) && !arg0_sign) { + /* Pass this zero through. */ + } else if (((floatx80_is_infinity(ST0) && !floatx80_is_infinity(ST1)) || + arg0_exp - arg1_exp >= 80) && + !arg0_sign) { + /* + * Dividing ST1 by ST0 gives the correct result up to + * rounding, and avoids spurious underflow exceptions that + * might result from passing some small values through the + * polynomial approximation, but if a finite nonzero result of + * division is exact, the result of fpatan is still inexact + * (and underflowing where appropriate). + */ + signed char save_prec = env->fp_status.floatx80_rounding_precision; + env->fp_status.floatx80_rounding_precision = 80; + ST1 = floatx80_div(ST1, ST0, &env->fp_status); + env->fp_status.floatx80_rounding_precision = save_prec; + if (!floatx80_is_zero(ST1) && + !(get_float_exception_flags(&env->fp_status) & + float_flag_inexact)) { + /* + * The mathematical result is very slightly closer to zero + * than this exact result. Round a value with the + * significand adjusted accordingly to get the correct + * exceptions, and possibly an adjusted result depending + * on the rounding mode. + */ + uint64_t sig = extractFloatx80Frac(ST1); + int32_t exp = extractFloatx80Exp(ST1); + bool sign = extractFloatx80Sign(ST1); + if (exp == 0) { + normalizeFloatx80Subnormal(sig, &exp, &sig); + } + ST1 = normalizeRoundAndPackFloatx80(80, sign, exp, sig - 1, + -1, &env->fp_status); + } + } else { + /* The result is inexact. */ + bool rsign = arg1_sign; + int32_t rexp; + uint64_t rsig0, rsig1; + if (floatx80_is_zero(ST1)) { + /* + * ST0 is negative. The result is pi with the sign of + * ST1. + */ + rexp = pi_exp; + rsig0 = pi_sig_high; + rsig1 = pi_sig_low; + } else if (floatx80_is_infinity(ST1)) { + if (floatx80_is_infinity(ST0)) { + if (arg0_sign) { + rexp = pi_34_exp; + rsig0 = pi_34_sig_high; + rsig1 = pi_34_sig_low; + } else { + rexp = pi_4_exp; + rsig0 = pi_4_sig_high; + rsig1 = pi_4_sig_low; + } + } else { + rexp = pi_2_exp; + rsig0 = pi_2_sig_high; + rsig1 = pi_2_sig_low; + } + } else if (floatx80_is_zero(ST0) || arg1_exp - arg0_exp >= 80) { + rexp = pi_2_exp; + rsig0 = pi_2_sig_high; + rsig1 = pi_2_sig_low; + } else if (floatx80_is_infinity(ST0) || arg0_exp - arg1_exp >= 80) { + /* ST0 is negative. */ + rexp = pi_exp; + rsig0 = pi_sig_high; + rsig1 = pi_sig_low; + } else { + /* + * ST0 and ST1 are finite, nonzero and with exponents not + * too far apart. + */ + int32_t adj_exp, num_exp, den_exp, xexp, yexp, n, texp, zexp, aexp; + int32_t azexp, axexp; + bool adj_sub, ysign, zsign; + uint64_t adj_sig0, adj_sig1, num_sig, den_sig, xsig0, xsig1; + uint64_t msig0, msig1, msig2, remsig0, remsig1, remsig2; + uint64_t ysig0, ysig1, tsig, zsig0, zsig1, asig0, asig1; + uint64_t azsig0, azsig1; + uint64_t azsig2, azsig3, axsig0, axsig1; + floatx80 x8; + FloatRoundMode save_mode = env->fp_status.float_rounding_mode; + signed char save_prec = env->fp_status.floatx80_rounding_precision; + env->fp_status.float_rounding_mode = float_round_nearest_even; + env->fp_status.floatx80_rounding_precision = 80; + + if (arg0_exp == 0) { + normalizeFloatx80Subnormal(arg0_sig, &arg0_exp, &arg0_sig); + } + if (arg1_exp == 0) { + normalizeFloatx80Subnormal(arg1_sig, &arg1_exp, &arg1_sig); + } + if (arg0_exp > arg1_exp || + (arg0_exp == arg1_exp && arg0_sig >= arg1_sig)) { + /* Work with abs(ST1) / abs(ST0). */ + num_exp = arg1_exp; + num_sig = arg1_sig; + den_exp = arg0_exp; + den_sig = arg0_sig; + if (arg0_sign) { + /* The result is subtracted from pi. */ + adj_exp = pi_exp; + adj_sig0 = pi_sig_high; + adj_sig1 = pi_sig_low; + adj_sub = true; + } else { + /* The result is used as-is. */ + adj_exp = 0; + adj_sig0 = 0; + adj_sig1 = 0; + adj_sub = false; + } + } else { + /* Work with abs(ST0) / abs(ST1). */ + num_exp = arg0_exp; + num_sig = arg0_sig; + den_exp = arg1_exp; + den_sig = arg1_sig; + /* The result is added to or subtracted from pi/2. */ + adj_exp = pi_2_exp; + adj_sig0 = pi_2_sig_high; + adj_sig1 = pi_2_sig_low; + adj_sub = !arg0_sign; + } + + /* + * Compute x = num/den, where 0 < x <= 1 and x is not too + * small. + */ + xexp = num_exp - den_exp + 0x3ffe; + remsig0 = num_sig; + remsig1 = 0; + if (den_sig <= remsig0) { + shift128Right(remsig0, remsig1, 1, &remsig0, &remsig1); + ++xexp; + } + xsig0 = estimateDiv128To64(remsig0, remsig1, den_sig); + mul64To128(den_sig, xsig0, &msig0, &msig1); + sub128(remsig0, remsig1, msig0, msig1, &remsig0, &remsig1); + while ((int64_t) remsig0 < 0) { + --xsig0; + add128(remsig0, remsig1, 0, den_sig, &remsig0, &remsig1); + } + xsig1 = estimateDiv128To64(remsig1, 0, den_sig); + /* + * No need to correct any estimation error in xsig1; even + * with such error, it is accurate enough. + */ + + /* + * Split x as x = t + y, where t = n/8 is the nearest + * multiple of 1/8 to x. + */ + x8 = normalizeRoundAndPackFloatx80(80, false, xexp + 3, xsig0, + xsig1, &env->fp_status); + n = floatx80_to_int32(x8, &env->fp_status); + if (n == 0) { + ysign = false; + yexp = xexp; + ysig0 = xsig0; + ysig1 = xsig1; + texp = 0; + tsig = 0; + } else { + int shift = clz32(n) + 32; + texp = 0x403b - shift; + tsig = n; + tsig <<= shift; + if (texp == xexp) { + sub128(xsig0, xsig1, tsig, 0, &ysig0, &ysig1); + if ((int64_t) ysig0 >= 0) { + ysign = false; + if (ysig0 == 0) { + if (ysig1 == 0) { + yexp = 0; + } else { + shift = clz64(ysig1) + 64; + yexp = xexp - shift; + shift128Left(ysig0, ysig1, shift, + &ysig0, &ysig1); + } + } else { + shift = clz64(ysig0); + yexp = xexp - shift; + shift128Left(ysig0, ysig1, shift, &ysig0, &ysig1); + } + } else { + ysign = true; + sub128(0, 0, ysig0, ysig1, &ysig0, &ysig1); + if (ysig0 == 0) { + shift = clz64(ysig1) + 64; + } else { + shift = clz64(ysig0); + } + yexp = xexp - shift; + shift128Left(ysig0, ysig1, shift, &ysig0, &ysig1); + } + } else { + /* + * t's exponent must be greater than x's because t + * is positive and the nearest multiple of 1/8 to + * x, and if x has a greater exponent, the power + * of 2 with that exponent is also a multiple of + * 1/8. + */ + uint64_t usig0, usig1; + shift128RightJamming(xsig0, xsig1, texp - xexp, + &usig0, &usig1); + ysign = true; + sub128(tsig, 0, usig0, usig1, &ysig0, &ysig1); + if (ysig0 == 0) { + shift = clz64(ysig1) + 64; + } else { + shift = clz64(ysig0); + } + yexp = texp - shift; + shift128Left(ysig0, ysig1, shift, &ysig0, &ysig1); + } + } + + /* + * Compute z = y/(1+tx), so arctan(x) = arctan(t) + + * arctan(z). + */ + zsign = ysign; + if (texp == 0 || yexp == 0) { + zexp = yexp; + zsig0 = ysig0; + zsig1 = ysig1; + } else { + /* + * t <= 1, x <= 1 and if both are 1 then y is 0, so tx < 1. + */ + int32_t dexp = texp + xexp - 0x3ffe; + uint64_t dsig0, dsig1, dsig2; + mul128By64To192(xsig0, xsig1, tsig, &dsig0, &dsig1, &dsig2); + /* + * dexp <= 0x3fff (and if equal, dsig0 has a leading 0 + * bit). Add 1 to produce the denominator 1+tx. + */ + shift128RightJamming(dsig0, dsig1, 0x3fff - dexp, + &dsig0, &dsig1); + dsig0 |= 0x8000000000000000ULL; + zexp = yexp - 1; + remsig0 = ysig0; + remsig1 = ysig1; + remsig2 = 0; + if (dsig0 <= remsig0) { + shift128Right(remsig0, remsig1, 1, &remsig0, &remsig1); + ++zexp; + } + zsig0 = estimateDiv128To64(remsig0, remsig1, dsig0); + mul128By64To192(dsig0, dsig1, zsig0, &msig0, &msig1, &msig2); + sub192(remsig0, remsig1, remsig2, msig0, msig1, msig2, + &remsig0, &remsig1, &remsig2); + while ((int64_t) remsig0 < 0) { + --zsig0; + add192(remsig0, remsig1, remsig2, 0, dsig0, dsig1, + &remsig0, &remsig1, &remsig2); + } + zsig1 = estimateDiv128To64(remsig1, remsig2, dsig0); + /* No need to correct any estimation error in zsig1. */ + } + + if (zexp == 0) { + azexp = 0; + azsig0 = 0; + azsig1 = 0; + } else { + floatx80 z2, accum; + uint64_t z2sig0, z2sig1, z2sig2, z2sig3; + /* Compute z^2. */ + mul128To256(zsig0, zsig1, zsig0, zsig1, + &z2sig0, &z2sig1, &z2sig2, &z2sig3); + z2 = normalizeRoundAndPackFloatx80(80, false, + zexp + zexp - 0x3ffe, + z2sig0, z2sig1, + &env->fp_status); + + /* Compute the lower parts of the polynomial expansion. */ + accum = floatx80_mul(fpatan_coeff_6, z2, &env->fp_status); + accum = floatx80_add(fpatan_coeff_5, accum, &env->fp_status); + accum = floatx80_mul(accum, z2, &env->fp_status); + accum = floatx80_add(fpatan_coeff_4, accum, &env->fp_status); + accum = floatx80_mul(accum, z2, &env->fp_status); + accum = floatx80_add(fpatan_coeff_3, accum, &env->fp_status); + accum = floatx80_mul(accum, z2, &env->fp_status); + accum = floatx80_add(fpatan_coeff_2, accum, &env->fp_status); + accum = floatx80_mul(accum, z2, &env->fp_status); + accum = floatx80_add(fpatan_coeff_1, accum, &env->fp_status); + accum = floatx80_mul(accum, z2, &env->fp_status); + + /* + * The full polynomial expansion is z*(fpatan_coeff_0 + accum). + * fpatan_coeff_0 is 1, and accum is negative and much smaller. + */ + aexp = extractFloatx80Exp(fpatan_coeff_0); + shift128RightJamming(extractFloatx80Frac(accum), 0, + aexp - extractFloatx80Exp(accum), + &asig0, &asig1); + sub128(extractFloatx80Frac(fpatan_coeff_0), 0, asig0, asig1, + &asig0, &asig1); + /* Multiply by z to compute arctan(z). */ + azexp = aexp + zexp - 0x3ffe; + mul128To256(asig0, asig1, zsig0, zsig1, &azsig0, &azsig1, + &azsig2, &azsig3); + } + + /* Add arctan(t) (positive or zero) and arctan(z) (sign zsign). */ + if (texp == 0) { + /* z is positive. */ + axexp = azexp; + axsig0 = azsig0; + axsig1 = azsig1; + } else { + bool low_sign = extractFloatx80Sign(fpatan_table[n].atan_low); + int32_t low_exp = extractFloatx80Exp(fpatan_table[n].atan_low); + uint64_t low_sig0 = + extractFloatx80Frac(fpatan_table[n].atan_low); + uint64_t low_sig1 = 0; + axexp = extractFloatx80Exp(fpatan_table[n].atan_high); + axsig0 = extractFloatx80Frac(fpatan_table[n].atan_high); + axsig1 = 0; + shift128RightJamming(low_sig0, low_sig1, axexp - low_exp, + &low_sig0, &low_sig1); + if (low_sign) { + sub128(axsig0, axsig1, low_sig0, low_sig1, + &axsig0, &axsig1); + } else { + add128(axsig0, axsig1, low_sig0, low_sig1, + &axsig0, &axsig1); + } + if (azexp >= axexp) { + shift128RightJamming(axsig0, axsig1, azexp - axexp + 1, + &axsig0, &axsig1); + axexp = azexp + 1; + shift128RightJamming(azsig0, azsig1, 1, + &azsig0, &azsig1); + } else { + shift128RightJamming(axsig0, axsig1, 1, + &axsig0, &axsig1); + shift128RightJamming(azsig0, azsig1, axexp - azexp + 1, + &azsig0, &azsig1); + ++axexp; + } + if (zsign) { + sub128(axsig0, axsig1, azsig0, azsig1, + &axsig0, &axsig1); + } else { + add128(axsig0, axsig1, azsig0, azsig1, + &axsig0, &axsig1); + } + } + + if (adj_exp == 0) { + rexp = axexp; + rsig0 = axsig0; + rsig1 = axsig1; + } else { + /* + * Add or subtract arctan(x) (exponent axexp, + * significand axsig0 and axsig1, positive, not + * necessarily normalized) to the number given by + * adj_exp, adj_sig0 and adj_sig1, according to + * adj_sub. + */ + if (adj_exp >= axexp) { + shift128RightJamming(axsig0, axsig1, adj_exp - axexp + 1, + &axsig0, &axsig1); + rexp = adj_exp + 1; + shift128RightJamming(adj_sig0, adj_sig1, 1, + &adj_sig0, &adj_sig1); + } else { + shift128RightJamming(axsig0, axsig1, 1, + &axsig0, &axsig1); + shift128RightJamming(adj_sig0, adj_sig1, + axexp - adj_exp + 1, + &adj_sig0, &adj_sig1); + rexp = axexp + 1; + } + if (adj_sub) { + sub128(adj_sig0, adj_sig1, axsig0, axsig1, + &rsig0, &rsig1); + } else { + add128(adj_sig0, adj_sig1, axsig0, axsig1, + &rsig0, &rsig1); + } + } + + env->fp_status.float_rounding_mode = save_mode; + env->fp_status.floatx80_rounding_precision = save_prec; + } + /* This result is inexact. */ + rsig1 |= 1; + ST1 = normalizeRoundAndPackFloatx80(80, rsign, rexp, + rsig0, rsig1, &env->fp_status); + } - fpsrcop = floatx80_to_double(env, ST1); - fptemp = floatx80_to_double(env, ST0); - ST1 = double_to_floatx80(env, atan2(fpsrcop, fptemp)); fpop(env); + merge_exception_flags(env, old_flags); } void helper_fxtract(CPUX86State *env) diff --git a/tests/tcg/i386/test-i386-fpatan.c b/tests/tcg/i386/test-i386-fpatan.c new file mode 100644 index 0000000000..7f1f9853de --- /dev/null +++ b/tests/tcg/i386/test-i386-fpatan.c @@ -0,0 +1,1071 @@ +/* Test fpatan instruction. */ + +#include + +struct test { + long double arg0, arg1, down, up; +}; + +const struct test tests[] = { + { -__builtin_infl(), -__builtin_infl(), -0x2.5b2f8fe6643a46ap+0L, -0x2.5b2f8fe6643a469cp+0L }, + { -__builtin_infl(), -1.0L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -__builtin_infl(), -0.0L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -__builtin_infl(), 0.0L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -__builtin_infl(), 1.0L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -__builtin_infl(), __builtin_infl(), 0x2.5b2f8fe6643a469cp+0L, 0x2.5b2f8fe6643a46ap+0L }, + { -1.0L, -__builtin_infl(), -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -1.0L, -0.0L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -1.0L, 0.0L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -1.0L, __builtin_infl(), 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0.0L, -__builtin_infl(), -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0.0L, -1.0L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0.0L, -0.0L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0.0L, 0.0L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0.0L, 1.0L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0.0L, __builtin_infl(), 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0.0L, -__builtin_infl(), -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0.0L, -1.0L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0.0L, -0.0L, -0.0L, -0.0L }, + { 0.0L, 0.0L, 0.0L, 0.0L }, + { 0.0L, 1.0L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0.0L, __builtin_infl(), 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 1.0L, -__builtin_infl(), -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 1.0L, -0.0L, -0.0L, -0.0L }, + { 1.0L, 0.0L, 0.0L, 0.0L }, + { 1.0L, __builtin_infl(), 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { __builtin_infl(), -__builtin_infl(), -0xc.90fdaa22168c235p-4L, -0xc.90fdaa22168c234p-4L }, + { __builtin_infl(), -1.0L, -0.0L, -0.0L }, + { __builtin_infl(), -0.0L, -0.0L, -0.0L }, + { __builtin_infl(), 0.0L, 0.0L, 0.0L }, + { __builtin_infl(), 1.0L, 0.0L, 0.0L }, + { __builtin_infl(), __builtin_infl(), 0xc.90fdaa22168c234p-4L, 0xc.90fdaa22168c235p-4L }, + /* Randomly generated tests. */ + { -0x4.1481697ac693aa6p-4L, 0xd.84a873b14b9c0e2p-4L, 0x1.dd2a294db671468ep+0L, 0x1.dd2a294db671469p+0L }, + { 0x5.51ee0c58f7fbf45p-4L, -0x3.a11abadbd605d354p-4L, -0x9.942ec5a1e6d706ap-4L, -0x9.942ec5a1e6d7069p-4L }, + { -0x5.4459f2ac77bb0978p-4L, -0xb.79bece734a62216p-4L, -0x2.004758bce8469e14p+0L, -0x2.004758bce8469e1p+0L }, + { 0x2.aad23e7bdccbd71p+352L, 0xb.8204e63359a46e6p-4L, 0x4.5081cdc076384b38p-356L, 0x4.5081cdc076384b4p-356L }, + { 0x1.b8e650cae035d26ap+72L, -0x1.6296e8ff499827a2p-4L, -0xc.de2b934dfff2be5p-80L, -0xc.de2b934dfff2be4p-80L }, + { -0x8.3e49377820195c8p-4L, 0x7.ece8699d62a9f76p-4L, 0x2.6037dbebdbb2fd48p+0L, 0x2.6037dbebdbb2fd4cp+0L }, + { -0x4.b875c0342c9f86b8p-4L, 0xe.a37e0fa859e499cp-4L, 0x1.e1fb3a96e1e2071p+0L, 0x1.e1fb3a96e1e20712p+0L }, + { -0x7.23210d9474f0715p-4L, 0xb.755e74862e61e2bp+116L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xd.2330923899aae43p-76L, 0xa.9a331b76f8ece94p+16L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x2.c18975d92e49e91p+72L, 0xa.d41581f0036d233p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x4.84a87d8107c5f408p-4L, -0x4.69649643801fe8p-5424L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x2.72f96b27827d2054p-4L, 0x8.34634eae18e60c5p-4L, 0x1.47dcc6c860bbdaf8p+0L, 0x1.47dcc6c860bbdafap+0L }, + { 0x5.ed9ff299ffca609p-4L, 0x1.f03bcdeac4b1ed28p-4L, 0x5.0e6d2d3ad020af98p-4L, 0x5.0e6d2d3ad020afap-4L }, + { -0x1.838e5531eee660a2p+100L, -0x9.6eacf3012c77e7p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x4.962ce97c4afbc1f8p-4L, -0xa.a7735b993f17f55p-4L, -0x1.fa318fa84cd3d3c6p+0L, -0x1.fa318fa84cd3d3c4p+0L }, + { 0x5.155f76560f08fccp-4L, 0xd.32a453289bd47b3p-4L, 0x1.340095b1ff56c6e8p+0L, 0x1.340095b1ff56c6eap+0L }, + { 0xa.9942e7418052b4bp-4L, -0x5.4f4efad2aff4f76p-4L, -0x7.6e5556d70c57ac08p-4L, -0x7.6e5556d70c57acp-4L }, + { 0x3.c9e289d962998608p-4L, 0x3.e614ab44b3c3b858p+88L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x1.51f8f83e548cc4d8p-32L, -0x8.a1d9201d5f09ad6p-4L, -0x1.921fb541d06114b2p+0L, -0x1.921fb541d06114bp+0L }, + { 0x7.5b8ee6778ad1d64p-4L, 0x9.d20d0f7fc98548p-4L, 0xe.d84441fe9061ea4p-4L, 0xe.d84441fe9061ea5p-4L }, + { 0x2.f89af40f713046ap+44L, -0x5.d981a42b6b7a36fp-4L, -0x1.f805944fa81791f6p-48L, -0x1.f805944fa81791f4p-48L }, + { 0x1.5dbffc603b717c16p-12056L, 0x4.5a026d37f55f1d18p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x7.82c193b48128193p-4L, -0xd.2d0fe1cd05a87f4p-4L, -0x2.16c178d148863734p+0L, -0x2.16c178d14886373p+0L }, + { 0x1.785253e54547193cp-128L, -0x4.51babb72810e518p-104L, -0x1.921fb4ed226f9e3ep+0L, -0x1.921fb4ed226f9e3cp+0L }, + { 0xb.638d8454a685474p-4L, -0x5.cf6274f9336e7248p+88L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xe.4b7a4c83290855cp+5104L, 0x3.c4fb25edb13c5e9cp-96L, 0x4.3816d5c0af96b0f8p-5204L, 0x4.3816d5c0af96b1p-5204L }, + { -0x1.c6f68bc53960adep+112L, -0xd.36a9965916287d1p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x6.b3a10f94dcd70e1p-4L, 0xc.8517674f15bbcbfp-4L, 0x1.144e7f18ba67b4fep+0L, 0x1.144e7f18ba67b5p+0L }, + { -0xb.204e5335e697f73p-4L, 0x8.913a951884085ddp-4L, 0x2.7c439b7e5e590704p+0L, 0x2.7c439b7e5e590708p+0L }, + { -0x4.5861903e9a2c5178p-4L, -0x5.24585590086993p-4L, -0x2.45bcbee2a405a1d4p+0L, -0x2.45bcbee2a405a1dp+0L }, + { -0xf.2ba8f23d35f13f9p-4L, 0xa.3ecdb386b33fbe5p-4L, 0x2.8c2ffc8ed89a67b4p+0L, 0x2.8c2ffc8ed89a67b8p+0L }, + { 0x9.9b8e544f05c6de4p-8L, -0x7.abd5585035c4696p-4L, -0x1.7e2035d4e6006922p+0L, -0x1.7e2035d4e600692p+0L }, + { 0x5.732a72e50e0e8fd8p-136L, 0x7.8b963b5c9698ae88p+112L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xb.ea47beace8589dep-4L, -0x3.8f66d5a2d60e1fc8p-4L, -0x2.d9eb1ca9b45b3eacp+0L, -0x2.d9eb1ca9b45b3ea8p+0L }, + { -0xc.694faa89b4055cp+100L, -0x8.6659e1a891ccbd3p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x4.a571a0831166accp+14352L, -0x9.b8fe7ab721fb04cp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x4.ee554b54200eeb18p-4L, -0x1.e1d0727b5f12c23cp-8L, -0x6.1b1657327a7313d8p-8L, -0x6.1b1657327a7313dp-8L }, + { -0x1.1e6c6f9d4f73617p-140L, 0x2.f3202c602060bd7cp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xc.cdb9d9e3a3a5b61p-4L, 0x5.7ddc79efb147e828p-4L, 0x2.bc857c5ac09c3d04p+0L, 0x2.bc857c5ac09c3d08p+0L }, + { -0x6.7236b6f8976437ap-4L, 0x5.e1ad137b44bc3ad8p-4L, 0x2.66e6f8a4616f47f8p+0L, 0x2.66e6f8a4616f47fcp+0L }, + { -0xb.f5ec1a26fcc9d7ep-4L, -0x3.772e0998925d6c78p-152L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x1.a983e64980e6104p-4L, 0xa.14ebef82079ff92p-4L, 0x1.684b277673a26358p+0L, 0x1.684b277673a2635ap+0L }, + { 0x1.e4fcc97f32b404d8p+13860L, -0x1.d272224db03bbe4ap-88L, -0xf.6367c3b63ab282p-13952L, -0xf.6367c3b63ab281fp-13952L }, + { 0xb.83be497f42b1776p-8L, -0xb.6c13349b9671c7bp-4L, -0x1.8204013b36ec0acp+0L, -0x1.8204013b36ec0abep+0L }, + { -0xd.00d476fab7a907dp-4L, 0xe.fce5159bb4f9691p+128L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xe.94e55595d939aa4p-4L, 0x8.66a9b0853e6c06ep-4L, 0x2.9e7077a5a9177248p+0L, 0x2.9e7077a5a917724cp+0L }, + { 0x5.431e650334b97d18p-4L, 0xf.1eb2c535e06fba3p-4L, 0x1.3c627af215641846p+0L, 0x1.3c627af215641848p+0L }, + { -0x8.54a857fb1034b62p-4L, -0xa.d3c15d582c446d9p-4L, -0x2.3a035e85ad032918p+0L, -0x2.3a035e85ad032914p+0L }, + { -0xc.cb73edcbfcb307fp-4L, 0xf.ed87c6cb3cd7d83p-84L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x1.3afd6b8a17918c64p+48L, -0x4.d312891f5f4e786p-4L, -0x3.243f6a8885a2ca18p+0L, -0x3.243f6a8885a2ca14p+0L }, + { 0xe.ae0633b99b178edp-4L, -0x1.39568b7ef55672cp-4L, -0x1.54bad5d8d44c04e4p-4L, -0x1.54bad5d8d44c04e2p-4L }, + { 0x4.cf293b1353f539bp-4L, 0x6.95c54f0009329c5p+116L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x5.b5eb2a3dcc35826p-5716L, -0xa.db19f19a7ea88bep-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x1.09017c7c80c2c48ap-4L, -0x2.5ae089add9bdff18p-4L, -0x1.281a477bf785850cp+0L, -0x1.281a477bf785850ap+0L }, + { -0x6.d211b21df46dcc18p-56L, 0xd.1a64a16c7c8f6d7p-4L, 0x1.921fb54442d18cbcp+0L, 0x1.921fb54442d18cbep+0L }, + { -0xc.1ef9ffac1d2c793p-4L, 0x1.67c59b4c06bd7496p-4L, 0x3.06b2add391c9eb78p+0L, 0x3.06b2add391c9eb7cp+0L }, + { -0x4.5d25a7f57110a158p+268L, -0x2.6c4fbdad444416d8p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0xb.03fa4c349a339d2p-9120L, 0x1.e57ddc8153f3ba8p-8L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x1.9385036afefa239p+6960L, -0x6.8fac6e3f60b61e1p-4L, -0x4.299d61fcfb4de92p-6964L, -0x4.299d61fcfb4de918p-6964L }, + { -0x3.65bed5b32d99326p+1832L, 0x2.3ef31cc65b2354cp-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x2.bceec8bc1d31b0ccp-4L, 0xd.146217a63673958p-4L, 0x1.c6f361fb1067b388p+0L, 0x1.c6f361fb1067b38ap+0L }, + { 0x2.17b7fc97b1f46e7cp-4L, -0x4.49abbcdefc0c959p-4L, -0x1.1de39755c8eb62aep+0L, -0x1.1de39755c8eb62acp+0L }, + { -0x3.efc6f5f489c6c7bcp-4L, 0x8.f7ff40b96f9bd91p+92L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x6.003126d0e9a9acc8p-4L, -0x5.7be9edcc9dc2a02p-4L, -0x2.66b21a740cac5bf4p+0L, -0x2.66b21a740cac5bfp+0L }, + { -0x7.8952a49ff2c2f168p-4L, -0x1.c53227e2b7ce8fd8p-100L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0xf.c1271b0a53a3319p-4L, -0x2.281fdd0bca98746p+36L, -0x1.921fb5443b837dc2p+0L, -0x1.921fb5443b837dcp+0L }, + { 0xf.ce2fc60abd9a47cp-4L, 0x9.e8a3a1c0f885e07p-4L, 0x8.f5ad0c8c16696eap-4L, 0x8.f5ad0c8c16696ebp-4L }, + { 0x6.88e09aba14bbc208p-28L, 0x2.0051253b7bd07004p+9792L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x5.244b484bc9bb7828p-4L, -0x7.02ec4c8b2cc95998p-4L, -0xf.02379007abbea58p-4L, -0xf.02379007abbea57p-4L }, + { -0xa.4d34be63f5bedffp-4L, 0xf.be786c39b309e8p-4L, 0x2.26738a0739adbffcp+0L, 0x2.26738a0739adcp+0L }, + { -0x6.16481538d3215558p-4L, 0x8.5ea05eecb9ac14dp-4L, 0x2.3318a84b9fd18a38p+0L, 0x2.3318a84b9fd18a3cp+0L }, + { -0xd.4be5b4aaf95a52bp-4L, 0x5.505294ddb8af9558p-4L, 0x2.c2eb12ab368a9a94p+0L, 0x2.c2eb12ab368a9a98p+0L }, + { -0x1.f45f2a814c98f34p+80L, 0x2.b68cfa7df5a80aep-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x1.71591c964a8836a6p+16L, 0x2.047a032c2a353b58p-4L, 0x3.243f5428e50fb82cp+0L, 0x3.243f5428e50fb83p+0L }, + { -0x8.eb2ab17c06312d9p-4L, 0xb.932fffb0dfd7537p-4L, 0x2.3a3007c5cc9e7d3cp+0L, 0x2.3a3007c5cc9e7d4p+0L }, + { -0x1.3839b004fc949e6cp-120L, 0xa.7fafcf461e92982p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x6.41b8cd66b9392ef8p-4L, 0xf.d372339bf2bef0fp-4L, 0x1.f28133bb63853c52p+0L, 0x1.f28133bb63853c54p+0L }, + { -0xf.843d63b0a71eb93p-4L, -0xe.679784396815117p-4L, -0x2.64b1d552e74bdb24p+0L, -0x2.64b1d552e74bdb2p+0L }, + { -0x1.6be25f7b2bbfc3p-4L, -0xf.e1c7160797d7709p-4L, -0x1.a8f98c5e679f44fep+0L, -0x1.a8f98c5e679f44fcp+0L }, + { -0x9.f6c4eb5c911111ap-4L, -0xa.08c53e65e98b067p-4L, -0x2.5a492049a9cbbe7p+0L, -0x2.5a492049a9cbbe6cp+0L }, + { -0x4.1a4c613ba5fe16ap-4L, -0xd.36e91d3e54f0432p-4L, -0x1.df30682153ea13e8p+0L, -0x1.df30682153ea13e6p+0L }, + { -0xd.1de964de30857a7p-4L, -0x8.604a0e63d4f5df1p-4L, -0x2.92c30d3b7d0de73cp+0L, -0x2.92c30d3b7d0de738p+0L }, + { 0xc.6b9d18c70882d52p-4L, -0x2.711b4139fbed3dc8p-11492L, -0x3.254433723f77f3bcp-11492L, -0x3.254433723f77f3b8p-11492L }, + { 0x9.4021cab7a0d78bbp-4L, 0x8.305eb92b4243ea2p-4L, 0xb.97f7af5268b8f8fp-4L, 0xb.97f7af5268b8f9p-4L }, + { -0x4.f0330cdb93893948p-4L, 0xe.be93c7764505ff9p-8L, 0x2.f504ddece3874ccp+0L, 0x2.f504ddece3874cc4p+0L }, + { -0xd.ea533ffe043e52bp+2296L, 0x1.1dd2693fe11489c2p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x2.0397d0e9676f1b2p-4L, 0x5.48015a56bb1ddbep-136L, 0x2.9f4ab0b2d7a99144p-132L, 0x2.9f4ab0b2d7a99148p-132L }, + { -0x1.9a52d244a51432cep-80L, -0xd.c27cd78e0864371p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x9.c7f27c2034ec1cfp-4L, -0xa.a9e0aa658eda7dcp-4L, -0x2.50244d2439996p+0L, -0x2.50244d2439995ffcp+0L }, + { 0x1.403075ad6be49e48p+104L, 0x8.2f7e9e49692fd28p-4L, 0x6.8b6793c6b839addp-108L, 0x6.8b6793c6b839add8p-108L }, + { -0xa.93e861896961066p-4L, -0xd.4c10bf60bb97196p-4L, -0x2.3e2700333180df34p+0L, -0x2.3e2700333180df3p+0L }, + { 0x4.ff124c9911f2538p-4L, -0x8.776b58ba7268d9ep-4L, -0x1.09a4306282277e7p+0L, -0x1.09a4306282277e6ep+0L }, + { -0x4.db7b68b78ebb30a8p-80L, -0x9.b667363949a8b6dp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x9.799737c602ebc35p-12L, -0x4.ee069c6928cc872p+68L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xa.8eb47109f6336a7p+7944L, 0x6.e3c54639ed929cp-16L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x7.c5f3d0d9d9db89cp-4L, 0x1.6b364994830303c2p-4L, 0x2.f607d4a28c7c5d2p+0L, 0x2.f607d4a28c7c5d24p+0L }, + { -0x4.2513fed56a721cp-4L, 0x3.e183251bd312b9f8p-4L, 0x2.6399f4ee48a52b1p+0L, 0x2.6399f4ee48a52b14p+0L }, + { 0x5.372c1f6cb3bb4cep-8L, 0xc.30d4cc265a07403p-4L, 0x1.8b47c0312064586p+0L, 0x1.8b47c03120645862p+0L }, + { 0xf.7e3aa552d45b234p-4L, -0x3.9a644e95053aaf1cp-4L, -0x3.a7ef5825b5df9e1p-4L, -0x3.a7ef5825b5df9e0cp-4L }, + { 0xe.85839cd58ef2c75p-4L, 0x1.e2027a063163b7ap+92L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xd.d9ee24413681697p+96L, -0x1.a0688ee2096f86eap-148L, -0x1.e10130aa540fdb18p-248L, -0x1.e10130aa540fdb16p-248L }, + { -0x5.0487ddb4070bf26p-4L, 0xb.41c4c871bf58078p-64L, 0x3.243f6a8885a308acp+0L, 0x3.243f6a8885a308bp+0L }, + { -0x4.cfd480a28c2b6b48p-4L, 0x1.8657dd64795c35ap-4L, 0x2.d5b053c0ec2d5304p+0L, 0x2.d5b053c0ec2d5308p+0L }, + { -0x1.262cb60430e5eb9ep-4L, 0x8.0e85fe0bcf8a253p-4L, 0x1.b66463ab64833336p+0L, 0x1.b66463ab64833338p+0L }, + { -0x3.cefbd3ecacf92c44p-4L, -0x5.f20def7196dea63p-4L, -0x2.23f8c03324b67e44p+0L, -0x2.23f8c03324b67e4p+0L }, + { 0x1.3a394f91198290bcp-4L, -0x5.fa0cb4bdfd2d7318p-4L, -0x1.5e454070508e5eap+0L, -0x1.5e454070508e5e9ep+0L }, + { 0x4.08cc4ee18d971c48p-4L, -0xc.08ff29dce9d081fp-4L, -0x1.3f5281f2c773c0bap+0L, -0x1.3f5281f2c773c0b8p+0L }, + { 0x1.109cf51c23d9c444p-3868L, 0x6.d5822da15531716p-12L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x5.b4cccaf7aee9cd6p-4L, 0xd.08cda37bcd9c8cp-4L, 0x1.287c57a28064102cp+0L, 0x1.287c57a28064102ep+0L }, + { -0xb.d7f74d7d0014f61p-4L, -0xa.7263655e0a0ea62p-4L, -0x2.6b34e32fa133c618p+0L, -0x2.6b34e32fa133c614p+0L }, + { -0x2.47b34fa6f1ad5d68p-4L, -0x4.7e5d88e1178a73b8p+136L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x3.e49a34d2590d3414p-148L, 0x6.90a7904ae1f6ca48p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xf.e7cc8c0c8fca8d6p-4L, 0xb.5766572c78c1636p-4L, 0x9.e930d3e45526457p-4L, 0x9.e930d3e45526458p-4L }, + { -0x3.84138ca9f496d498p+24L, -0x3.83d9c130d6f21f6p-92L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x3.622e5c923b06d66cp-8L, 0x8.911302b7a344f8ap-4L, 0x1.987124e672754176p+0L, 0x1.987124e672754178p+0L }, + { -0x2.a91a430d68680b6cp-132L, -0x8.87063dd41e8a8bbp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x4.e1420e7e82cd22dp-4L, 0x5.ed8fe0a77cf3d518p-14676L, 0x1.36fb35f69a850f64p-14672L, 0x1.36fb35f69a850f66p-14672L }, + { -0xc.8346ca25bd9f342p-4L, 0xa.8b2343cd8095adcp-10960L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x2.b32d8027c5516654p-3772L, 0x6.fd1366df02fe9c5p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x6.c090b4e367d6c7ep-8L, -0x5.081c001c09df9f3p-4L, -0x1.7cb3f4f28e98b0c6p+0L, -0x1.7cb3f4f28e98b0c4p+0L }, + { -0x3.fcb8a555a704d93cp-112L, -0x1.920119c347818b36p+4120L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x4.f7a55e6bfc734b5p-132L, 0x9.188a26a4beb414p+116L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xb.ff33c19f0cbb73p-4L, 0x1.d50d6b459087ecdp-4L, 0x2.6cc4d1a540b1449cp-4L, 0x2.6cc4d1a540b144ap-4L }, + { 0x6.0dd96d442bc44b28p-4L, -0x3.e88917f9e6c0bb2p-4L, -0x9.2c0cc2bcd1b42bcp-4L, -0x9.2c0cc2bcd1b42bbp-4L }, + { 0xf.e9c0adcf6e6ebaap+80L, -0xe.6049cc9d4ea9c32p-8L, -0xe.746309506e28c41p-92L, -0xe.746309506e28c4p-92L }, + { -0xd.e0ca0ae677c56c7p-4L, -0x3.b604528c1bde4ca8p-4L, -0x2.e15bb2ef66714438p+0L, -0x2.e15bb2ef66714434p+0L }, + { 0x9.3e94ea277274ab3p-4L, 0xf.ec080621a8d9456p-4L, 0x1.0b752d4e563c12fp+0L, 0x1.0b752d4e563c12f2p+0L }, + { 0x1.96ef7e6b80e63adep-4L, 0x5.fa153b3eb3b0779p+984L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x2.c1491ea7eb7b418p+220L, -0x2.5fa1d9a3a5a2b664p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x1.f7142c3edd746312p-76L, 0xb.79a14c17c57922dp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x9.9b19d045170086ap-4L, -0xd.65fbae6f453f5a2p-4L, -0x2.315b8727ceee88f4p+0L, -0x2.315b8727ceee88fp+0L }, + { 0xc.7a9e15e82248878p-4L, 0x3.f5ec8986cfd785dp-4L, 0x4.ead1f3dda3a04a3p-4L, 0x4.ead1f3dda3a04a38p-4L }, + { -0x2.94c306c1808e3c18p+44L, -0x3.aa0cc319c013919p-4L, -0x3.243f6a8885a19d68p+0L, -0x3.243f6a8885a19d64p+0L }, + { -0xf.0292f4401d18d5cp-4L, -0x1.bf51089c520b29b4p-4L, -0x3.0694831553eb506p+0L, -0x3.0694831553eb505cp+0L }, + { -0x3.338096c5b380a194p+5592L, -0x5.35b41b797fb9331p-56L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x9.620bcddbdd20a79p-4L, 0x4.17376606afdde85p-4L, 0x6.93f7056b927052fp-4L, 0x6.93f7056b927052f8p-4L }, + { 0xd.1dc39e358b023ap-4L, 0xb.13430c035931444p-4L, 0xb.383ae5cd743ce8ap-4L, 0xb.383ae5cd743ce8bp-4L }, + { 0x3.606617a1673d0184p-4L, -0x8.f017932d188a998p-4L, -0x1.35a7a5999089613cp+0L, -0x1.35a7a5999089613ap+0L }, + { -0xf.3ce660b2bbefc26p-80L, -0x1.8dad3bd8dae62b26p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xf.d53ec036950502fp-4L, -0x2.a72c3e3aead35fep+14616L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x4.9ff6d398cf5c723p-4L, 0x3.c7ea3c3c2b39e2c8p+56L, 0x1.921fb54442d18454p+0L, 0x1.921fb54442d18456p+0L }, + { 0xf.7206b4c8d50f316p-4L, 0x7.5f74c3dd6c9936dp-4L, 0x7.203659231b6ebf78p-4L, 0x7.203659231b6ebf8p-4L }, + { 0x1.d1a5048e1cfadea8p-4L, 0xe.8f9244700df6721p-4L, 0x1.724f343754e1f6c2p+0L, 0x1.724f343754e1f6c4p+0L }, + { 0x3.99c86ae38d72f47cp-4L, 0x1.78aa249a87ca9a7ep-4092L, 0x6.89bb9c00e2992908p-4092L, 0x6.89bb9c00e299291p-4092L }, + { 0x9.638122087011d7dp-4L, 0xc.4c4e12b06f42474p-4L, 0xe.b33a0191f01596ap-4L, 0xe.b33a0191f01596bp-4L }, + { 0x1.ef067fd567660c6ep+124L, 0x6.c87c79c7f39458b8p-4L, 0x3.8203f86101129a1p-128L, 0x3.8203f86101129a14p-128L }, + { 0x1.7ae1a02b6be082e8p-96L, 0x6.a546c7e5065f0158p-112L, 0x4.7d81cd7fc2b19b08p-16L, 0x4.7d81cd7fc2b19b1p-16L }, + { -0x6.f866735c25236f98p-4L, -0x6.48ac3faff9ac8af8p-148L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x1.62b2ac359758568p-124L, 0xa.a22cceb5d16a7b9p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x7.9bb3d37308387268p-4L, -0xc.186ea423cfbc56dp-4L, -0x2.21dcf2dcca126d7p+0L, -0x2.21dcf2dcca126d6cp+0L }, + { 0x9.e5f3c3ae26d0dd6p-44L, -0x1.5803a5d39e417564p-4L, -0x1.921fb5443b73dd0ep+0L, -0x1.921fb5443b73dd0cp+0L }, + { -0xc.a52f12f15058ap-8L, -0x3.e058d43b80e19b7cp+32L, -0x1.921fb5444614a0ap+0L, -0x1.921fb5444614a09ep+0L }, + { -0x7.810b603203760db8p-4L, 0xd.d38ca8b0ca1dddfp-140L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x3.e726a67b179e572p+5396L, -0xc.d26229e318f0c64p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x8.457740622adf15fp-4L, -0x7.492c117c47e7f31p-4L, -0xb.8ddcb5e4e618633p-4L, -0xb.8ddcb5e4e618632p-4L }, + { 0xb.b13b38b2bab98c4p-4L, -0xc.05a51372a620cc3p-4L, -0xc.c9f0d2797fe328dp-4L, -0xc.c9f0d2797fe328cp-4L }, + { -0xf.52d7c0f49c1b5a4p-4L, 0x6.c87dc3726b00027p-112L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x1.5c0865fc4e06a84ep-4L, 0xa.2dfc5d1f96be4bcp-4L, 0x1.b41ca3f2a679e626p+0L, 0x1.b41ca3f2a679e628p+0L }, + { -0x3.f497fcccc60e3828p+60L, 0x1.dd126ec3b3b24d64p+116L, 0x1.921fb54442d18688p+0L, 0x1.921fb54442d1868ap+0L }, + { 0x5.03f2d9b66abed898p-4L, 0xd.e1d2b8730f8408fp-4L, 0x1.395ec39fa3cbe086p+0L, 0x1.395ec39fa3cbe088p+0L }, + { -0x3.8052f809aaac9b64p-4L, 0xf.ad374726f5b37c2p+16L, 0x1.921fb8d713091e94p+0L, 0x1.921fb8d713091e96p+0L }, + { 0x3.48836233e960d588p-4L, -0x8.af10e3af7480717p-4L, -0x1.35961a95496c7024p+0L, -0x1.35961a95496c7022p+0L }, + { 0x4.d09e474f01f1a2d8p-72L, 0x2.956954f33db8ba84p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xe.05c36356f1cc00bp-4L, -0x1.30a38fe2fc6ef3d6p-120L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x8.98fecd06210c28ep-8L, -0xa.944a9ff08e89db6p-4L, -0x1.8521cc1c24d70946p+0L, -0x1.8521cc1c24d70944p+0L }, + { -0xf.069ae41b6f97acbp-4L, -0x2.849c2bec428d3088p-4L, -0x2.f9be11bfeff191ep+0L, -0x2.f9be11bfeff191dcp+0L }, + { 0x1.ddc053fcc0b29fc6p-2068L, -0xe.aa11ca5025d7161p+352L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xe.30a7bdb7d22b3c9p-4L, -0x6.8b8840cf7db54858p+5320L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xc.289ab032c02ec2bp+96L, -0x2.4f1d0f8cfd43ef8cp+68L, -0x3.243f6a857bc45af8p+0L, -0x3.243f6a857bc45af4p+0L }, + { 0xc.b983cae10f7203p-4L, 0xb.7422dd3d2b45dc5p-4L, 0xb.b9dea242a2b569ap-4L, 0xb.b9dea242a2b569bp-4L }, + { -0xa.fbaa8d616ab8d1dp-4L, -0xe.926ef7c0fa60c33p-4L, -0x2.37778ac56a06051p+0L, -0x2.37778ac56a06050cp+0L }, + { 0xf.80c7c99d2c6404cp-4L, -0x7.2aac6d2a68c490bp+8L, -0x1.91fd18c483c4059ap+0L, -0x1.91fd18c483c40598p+0L }, + { -0xe.80d9a3a08faf173p-4L, -0x8.400e8efd60a398p-4L, -0x2.9fd8298eb95656f4p+0L, -0x2.9fd8298eb95656fp+0L }, + { -0x1.e30b1be4461dcf88p+212L, -0xc.2454aa891f5dba1p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x1.6492e0fa29711f58p+104L, 0x3.a0caae204aa84214p-4L, 0x2.9ad20bbc8b5aa404p-108L, 0x2.9ad20bbc8b5aa408p-108L }, + { 0x6.db2d4dd8afa84408p-4L, 0x8.7fd39596a804d49p-80L, 0x1.3d5a80194777316p-76L, 0x1.3d5a801947773162p-76L }, + { 0x3.f16bc38197cbac4cp-104L, -0xb.2a83d184147cfdcp-96L, -0x1.91c54eb36a10602cp+0L, -0x1.91c54eb36a10602ap+0L }, + { 0xa.e2eae99c9fd7478p-4L, -0x2.36e2a96b54e59b58p-4L, -0x3.35f38d6e0b59fa84p-4L, -0x3.35f38d6e0b59fa8p-4L }, + { 0x3.0a86465998f852dp+128L, -0x1.43ec0bdd98b0f80cp-112L, -0x6.a83ada10badb8dep-244L, -0x6.a83ada10badb8dd8p-244L }, + { 0x6.883e7a1d34914268p-4L, 0xb.88a85700deb5549p-4L, 0x1.0e344a89b3d1ea2ep+0L, 0x1.0e344a89b3d1ea3p+0L }, + { -0xf.2b2a3a311948993p-4L, -0x3.06fe2a10fe55267cp-4L, -0x2.f1d184e7e8b146b8p+0L, -0x2.f1d184e7e8b146b4p+0L }, + { -0xd.de264368cd7459ap-4L, 0x5.567777c9aa2124c8p-4L, 0x2.c62fd64a3dffbda4p+0L, 0x2.c62fd64a3dffbda8p+0L }, + { -0x1.935a9217a5a3024p-4L, 0x7.3ccc7fe1d42ad228p-4L, 0x1.c8ffb02ef3152e56p+0L, 0x1.c8ffb02ef3152e58p+0L }, + { -0x4.bbff6d1fef17b4c8p-4L, -0x1.4134a05ac2afda6p+20L, -0x1.921fb90a3855426ep+0L, -0x1.921fb90a3855426cp+0L }, + { 0x5.265fe49d84076a68p-4L, -0xc.103986b2d38539dp-4L, -0x1.2ad51c99871cfe42p+0L, -0x1.2ad51c99871cfe4p+0L }, + { -0x2.e02038211a5e1a1cp+84L, 0x2.66bb0943c921a184p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x7.5a723c24f0c64ebp-4L, 0x3.c761bdd9cf2def2cp-4L, 0x2.aab94e7e66bac71cp+0L, 0x2.aab94e7e66bac72p+0L }, + { -0x7.cf59e52998194478p+128L, -0xe.780c3928a522b73p-12L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x6.1dfcef356d3841p-4L, 0x3.4828bdd2a081f3ep-4L, 0x7.e0f6aac2c77ae808p-4L, 0x7.e0f6aac2c77ae81p-4L }, + { 0xb.dde4e379662aeeap-4L, 0xb.0226291c9bc5964p-4L, 0xb.f75cd67c86afa4cp-4L, 0xb.f75cd67c86afa4dp-4L }, + { -0xd.bf9a0da9faa3504p-4L, -0x5.c1892b0fafe1dc68p-4L, -0x2.bebed8f131223be4p+0L, -0x2.bebed8f131223bep+0L }, + { 0x1.44812a3159648466p-4L, 0xd.9d71d57ae36f89fp+1968L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x1.e8e8f49835eaacb8p-4L, 0x9.eac5efdf2c187bdp-4L, 0x1.c2d3d0e12540c0eep+0L, 0x1.c2d3d0e12540c0fp+0L }, + { 0xf.8a9cd502481f327p-4L, -0x2.9371a4cdcbd8ac4p-4L, -0x2.a0c8bb47d0fe5554p-4L, -0x2.a0c8bb47d0fe555p-4L }, + { 0xf.ec9e23f6d0a3bd2p-4L, -0x2.5fd5f4e23c3210e4p+108L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x1.80a14974eabf910ap-152L, -0x4.c2d0568402546a5p-8L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xc.976222dd345048p-68L, -0xd.6563e961e96fd5dp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x9.e03ff635ae5b0afp-8912L, -0xa.42b9f1752ebee14p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x6.4ef2060125bf954p-4L, 0x1.949b3c6ad95e7494p-128L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0xf.d085f6fba7aa194p+11308L, 0x9.8fa092c7be00f66p+52L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x2.29f54bce824a24cp-8L, -0xa.b8f81b679b49916p-4L, -0x1.8ee524e86c1ee1e4p+0L, -0x1.8ee524e86c1ee1e2p+0L }, + { -0x2.dfa40c215498cf14p-4L, -0x2.ec02031137509e54p-4L, -0x2.590d4b9283e4bb88p+0L, -0x2.590d4b9283e4bb84p+0L }, + { 0xc.95b28af67c0d0fdp-4L, -0x3.8b937ee4a5ad9044p-4L, -0x4.64b9dc9fe48f2ca8p-4L, -0x4.64b9dc9fe48f2cap-4L }, + { 0x1.96c3f2d8373481fcp-128L, 0x5.32ac5f2f72c534e8p+7120L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x3.71a836d1385ea83cp+32L, -0x2.98de885b63ec9fap-4L, -0xc.10d9073a34cf0d8p-40L, -0xc.10d9073a34cf0d7p-40L }, + { -0x2.ec64d50f08792a24p-12L, 0x7.4a3ef749c24694d8p+144L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xe.39d4437a92edbe2p+6624L, -0x7.e597e9edb98f8dd8p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x5.b2db0149e01e772p-4L, -0xa.4e00c5865119715p-4L, -0x2.13718dc24c8ca814p+0L, -0x2.13718dc24c8ca81p+0L }, + { 0x3.2d5ce470bbbfc05p-4L, -0x6.fef503b2cde63e88p-4L, -0x1.24fdbd6081eb3d04p+0L, -0x1.24fdbd6081eb3d02p+0L }, + { -0x2.75c4d49c73c6b714p-4L, -0x2.6f4dc7f3b45d7874p+84L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x3.be464272e1460c8p-92L, -0xc.5760c2d01b802f5p+84L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x4.58042455b6631c78p-4L, -0xf.a5425993c2d22edp-4L, -0x1.d774099a530614d4p+0L, -0x1.d774099a530614d2p+0L }, + { -0x3.331c1dd1ed766244p-352L, 0x5.6352b9b11a14c48p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x5.eeff171b7925d048p-14368L, -0xf.ff0d58e82429fafp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x9.bd53e4167e85b42p-4L, -0x5.4c28c9b0b345941p-4L, -0x2.a4b8051a75508798p+0L, -0x2.a4b8051a75508794p+0L }, + { 0x8.fef78aad41a1338p-4L, 0xf.25b2822b10d9f65p-4L, 0x1.08ed7bc61d7d73f2p+0L, 0x1.08ed7bc61d7d73f4p+0L }, + { -0x5.cd10c03bcaf10088p-8L, -0xa.a821812c5f53b52p-4L, -0x1.9ad4845fb36d2352p+0L, -0x1.9ad4845fb36d235p+0L }, + { 0x5.94e05ec04235ac68p-4L, -0xa.09752cd4a8e9c1dp-104L, -0x1.cc59396f222b7724p-100L, -0x1.cc59396f222b7722p-100L }, + { -0xd.167af1356c9c025p-4L, -0xf.d0cd204dbb8b533p-4L, -0x2.4318bedab39b9894p+0L, -0x2.4318bedab39b989p+0L }, + { 0xa.c0e5742f317f8a3p-4L, 0xe.2242314d427e9c1p-204L, 0x1.5078fcaf7a061e0cp-200L, 0x1.5078fcaf7a061e0ep-200L }, + { -0x2.37749e13337ef694p-4L, 0x4.8513915f54085e2p-4L, 0x2.06d9395eb203ac84p+0L, 0x2.06d9395eb203ac88p+0L }, + { 0xe.23a123d6d8bcffp+5256L, 0x5.25a1ebc2fc29f1cp+84L, 0x5.d30afa61156b2b38p-5176L, 0x5.d30afa61156b2b4p-5176L }, + { -0x2.4674afe3989b3a5p-72L, -0x1.5e3fb8c6c490f9b8p-100L, -0x3.243f6a7ee695750cp+0L, -0x3.243f6a7ee6957508p+0L }, + { -0xe.920450e2df4f23ep-4L, -0x7.8a913f4c29492cdp-4L, -0x2.a9facee71eddd834p+0L, -0x2.a9facee71eddd83p+0L }, + { 0xd.f18c68c5e57c1fep-4L, 0x6.4bf6a01053290c18p+100L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xd.65b50e81ed20864p+92L, 0x8.d86e55e3f0a94b1p-4L, 0xa.905826200246659p-100L, 0xa.90582620024665ap-100L }, + { -0x5.0308adabc4a020fp-4L, -0x2.a7d9b961e2c3089p-4L, -0x2.a7822a212eff89d4p+0L, -0x2.a7822a212eff89dp+0L }, + { -0xd.227d8e4d09d7251p-4L, 0x7.d5608278690935ap-4L, 0x2.9a9469fdb763be6cp+0L, 0x2.9a9469fdb763be7p+0L }, + { -0xe.81b27c03c76f499p-48L, -0x2.b154c8162bc04cb4p-4L, -0x1.921fb5444327b72cp+0L, -0x1.921fb5444327b72ap+0L }, + { 0x4.35ecdac82f2a93c8p-4L, -0x5.771325ed71c201dp-4L, -0xe.a11a21eaf4329d6p-4L, -0xe.a11a21eaf4329d5p-4L }, + { -0x5.eae159d6c2480c9p+32L, 0x5.121392f3a25f68p-4L, 0x3.243f6a8877ed3cf8p+0L, 0x3.243f6a8877ed3cfcp+0L }, + { 0x3.dcb9a65bf445eaccp+10876L, 0x1.778ccedfa82f4736p-4L, 0x6.13cb511c0ab34e3p-10884L, 0x6.13cb511c0ab34e38p-10884L }, + { 0xb.3cc3e4cc1b25c56p-4L, -0x6.76ae6ecaf0206ea8p-4L, -0x8.5a0330d0113839fp-4L, -0x8.5a0330d0113839ep-4L }, + { 0xe.22ec92ad54501adp-4L, -0x3.f615ff2adef13ae8p+56L, -0x1.921fb54442d18432p+0L, -0x1.921fb54442d1843p+0L }, + { -0x7.e9826b314600f95p-120L, 0x4.9a9641fa150c9178p+60L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xe.99b66de48e79158p-4376L, -0x5.c1e4a9cc5e3e83e8p+52L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x5.1ce62b8e10774afp-4L, 0x7.fa8931ceaf326ac8p-4L, 0x2.24045af1101a7c0cp+0L, 0x2.24045af1101a7c1p+0L }, + { 0x5.9b4e55550b4e7078p+112L, -0xa.954d79680ea5909p-4L, -0x1.e33a9f922fb03e88p-116L, -0x1.e33a9f922fb03e86p-116L }, + { 0xb.432563e5c37e78fp+108L, 0xa.950b0bb7d84c5b3p-4L, 0xf.08a83c251380dd2p-116L, 0xf.08a83c251380dd3p-116L }, + { 0x4.3e136fbe7e156658p-4L, 0xb.9930789b19cf8a8p-4L, 0x1.385a8b82e95fe408p+0L, 0x1.385a8b82e95fe40ap+0L }, + { -0x8.1697784edf6fe07p-8L, 0x2.e9849ddc62c0d374p-4L, 0x1.be1fa44b4ee5c01ep+0L, 0x1.be1fa44b4ee5c02p+0L }, + { 0xc.d570e244c0e60bep-4L, 0xf.15d04c531718d34p-4L, 0xd.da96e59bf70d9cfp-4L, 0xd.da96e59bf70d9dp-4L }, + { 0x1.e1200b8406eda8fep-4L, 0x1.e65664694a4c5354p-1032L, 0x1.02c5fcd18c965c48p-1028L, 0x1.02c5fcd18c965c4ap-1028L }, + { -0x9.2cb86254ecdfd09p-8L, -0x4.9982beb1a0f87638p-4L, -0x1.b1dfdabe0ce0405cp+0L, -0x1.b1dfdabe0ce0405ap+0L }, + { -0xe.45cc48c61fdc121p+40L, 0x4.e07d3709dbe3fep-4L, 0x3.243f6a88859d913cp+0L, 0x3.243f6a88859d914p+0L }, + { 0x5.653d42dac0a5219p-4L, 0x9.5f1aff673a041bcp-4L, 0x1.0c64c95c41e196a2p+0L, 0x1.0c64c95c41e196a4p+0L }, + { -0x8.bcd403a004e1a23p-4L, -0x8.1c9d05645c7987cp-4L, -0x2.64b0a8416a0a6878p+0L, -0x2.64b0a8416a0a6874p+0L }, + { 0xd.13a5ae9285d253dp-4L, 0x9.4cf62e7e77f656p-4L, 0x9.e4410391f565abdp-4L, 0x9.e4410391f565abep-4L }, + { -0x2.84d9c1bc69548254p-4L, -0x4.21ac0c75a3a7dbe8p-4L, -0x2.1e4985c908e36c6cp+0L, -0x2.1e4985c908e36c68p+0L }, + { -0xd.b9bd68e165f831p-4L, 0x8.3fd61ad578cd929p-4L, 0x2.99b53d1ee1512a74p+0L, 0x2.99b53d1ee1512a78p+0L }, + { 0xf.30d46d764112444p-4L, 0xb.cd4a73dc359d737p-4L, 0xa.916e2e87f1b749dp-4L, 0xa.916e2e87f1b749ep-4L }, + { 0x1.515f582a4522a614p-112L, -0x5.9e1738c1ccd8a9a8p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x2.92f5722be8168a3p+84L, -0x4.8e012f7d7878b01p-4L, -0x1.c4fbac335198d82cp-88L, -0x1.c4fbac335198d82ap-88L }, + { -0x1.6757eda9b94c8c8cp-6468L, -0xf.789b834a9491fb6p-308L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xf.f16a11b7efb26b4p-4L, 0x7.6980774d9eb5024p-4L, 0x2.b4d71146599f1ebcp+0L, 0x2.b4d71146599f1ecp+0L }, + { 0xc.52f873b5b0d54efp-8L, 0x2.b8137644250c4bbcp-4L, 0x1.4b748a8aaca4742cp+0L, 0x1.4b748a8aaca4742ep+0L }, + { 0x8.b13bd917a919d6p-4L, 0xd.a7e60f2da06694ep-4L, 0x1.0102ec7f8667321ap+0L, 0x1.0102ec7f8667321cp+0L }, + { -0x9.6d66afe84b35074p-4L, 0x8.d45410dc1895ef4p-4L, 0x2.6391367299a3faccp+0L, 0x2.6391367299a3fadp+0L }, + { 0x8.7112de739485f11p-6744L, -0x1.4a2fc4cfe9bc534cp-13708L, -0x2.71d20e8084e1e9cp-6968L, -0x2.71d20e8084e1e9bcp-6968L }, + { -0x5.9ce42450cfaf8ee8p-4L, 0x6.efb719daf136a1cp-4L, 0x2.404921fc654263p+0L, 0x2.404921fc65426304p+0L }, + { 0x9.ba0bd38df957e82p-5860L, -0x7.f37ea4723b67675p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x2.bf5897672b745798p-4L, -0x1.2b46b769cd53c99cp-4L, -0x6.6fcf0d804412fb1p-4L, -0x6.6fcf0d804412fb08p-4L }, + { 0x8.0d256afefef3c89p-4L, -0xa.e23fca6db43882fp-4L, -0xe.f12f9edadf77c82p-4L, -0xe.f12f9edadf77c81p-4L }, + { -0x3.5d7f19c9107b35a4p-92L, -0x4.0740585229be331p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xb.2f2372351c33164p-8L, -0x1.e98b74b783fe8242p-4L, -0x1.ebd6a4be06afe44ep+0L, -0x1.ebd6a4be06afe44cp+0L }, + { -0xf.7938a9b78d6563ep-4L, -0x5.e56611314a03c688p-24L, -0x3.243f646fc449c69p+0L, -0x3.243f646fc449c68cp+0L }, + { -0x3.378249c69ce50b28p+128L, 0xd.1fe6e25acc0107ap-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x2.9bce90f0aac016a8p+8752L, -0x3.f9a540b88fcacaf8p+20L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x9.8f02fd2b4d10383p-4L, -0x3.10d386b4ddaa9bccp-4L, -0x2.d4cb6d7692b4340cp+0L, -0x2.d4cb6d7692b43408p+0L }, + { 0x8.a7f4a483fcced92p-4L, 0x1.0dbbaa49beedef7ap-80L, 0x1.f293f545ba902d6p-80L, 0x1.f293f545ba902d62p-80L }, + { 0xc.779757b60637763p-4L, 0xe.777fe73bf0e9a48p-4L, 0xd.c087f481f381bc4p-4L, 0xd.c087f481f381bc5p-4L }, + { -0x4.637006dbd01caa2p-48L, -0x9.0b16723fd236994p-4L, -0x1.921fb54442d94812p+0L, -0x1.921fb54442d9481p+0L }, + { -0x2.26865489613f2a3cp-16L, -0xf.5402328fd9d6fdfp-4L, -0x1.9221f3ebd1a9f3a6p+0L, -0x1.9221f3ebd1a9f3a4p+0L }, + { -0x1.9cdb9776e2fd9cd6p-88L, 0xc.d7d4b25d5ee54a4p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xf.002b8779c597ceep-4L, 0x7.903eb3c7555e4358p-4L, 0x7.78ddd72dbbbd4ep-4L, 0x7.78ddd72dbbbd4e08p-4L }, + { 0x5.216f04578c6eedf8p-28L, -0xb.887e64736056822p-4L, -0x1.921fb4d260c15a72p+0L, -0x1.921fb4d260c15a7p+0L }, + { -0x2.96746a1d6d0a835cp-12L, -0x6.bbe44e9596a2f068p-44L, -0x3.243f6a85eb741a2cp+0L, -0x3.243f6a85eb741a28p+0L }, + { 0xc.8b02c285d275bd6p-4L, -0x7.2ea947c351044f48p-4L, -0x8.5212a1fc5bb54a1p-4L, -0x8.5212a1fc5bb54ap-4L }, + { -0xc.4830d91b64528bdp-4L, -0xa.faff5d48675db64p-11172L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x1.456f46c72593c416p-4L, 0x1.66e29eea15366fa6p+144L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xd.de830895fc14d25p-4L, 0x1.d696938384c107e8p-4L, 0x2.1bbde70f3e78278p-4L, 0x2.1bbde70f3e782784p-4L }, + { 0xd.737880bffe043f4p+1748L, -0xb.0173bf64b3af081p-4L, -0xd.175a392434528acp-1756L, -0xd.175a392434528abp-1756L }, + { -0x4.d70abf0d2e83e9e8p-32L, -0x4.bded6e2f0ae69668p-4L, -0x1.921fb554978f2276p+0L, -0x1.921fb554978f2274p+0L }, + { -0x1.6f720ef4ee00435cp-104L, -0xe.794bdddad00436cp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x8.bcfd1861de45b01p-4L, 0x2.aad3a86545c4ac24p+68L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x6.f81960839d640cdp-4L, -0x7.693a270061cf9de8p-4L, -0xd.0ed284135386fbep-4L, -0xd.0ed284135386fbdp-4L }, + { 0xe.7b0648fc94495aap+6848L, -0x5.48b5a0cfdf4fe08p+92L, -0x5.d6a5f8e290a54e2p-6760L, -0x5.d6a5f8e290a54e18p-6760L }, + { -0x6.26f604efc7da8708p+72L, -0x5.9293af393bd5fbfp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0xd.3ea27eab88fb691p-4L, 0xe.5d425700b9dfb9p-4L, 0xd.37014b312bf4ee6p-4L, 0xd.37014b312bf4ee7p-4L }, + { -0xf.de61a9eba878612p+2584L, 0x3.0b30eb6a97ddaf6p+20L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x2.8b29e4e9b1677aap-8428L, -0xb.c9870bb9c74469p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x1.cdad015fe5b95a34p-148L, 0x3.fcdc007ba74601ap-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x1.f1d5273873448298p-140L, 0xd.38eafd3878fe2f4p-2288L, 0x6.cc9f855116729cd8p-2148L, 0x6.cc9f855116729cep-2148L }, + { 0x1.c55b237b57929914p-8L, 0xe.5512393a7c3aa68p+88L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x6.c72dbae38baf489p-4L, 0xa.9efab67bae298c4p-4L, 0x2.238931ee6f4619p+0L, 0x2.238931ee6f461904p+0L }, + { 0x6.d6fe2acf94b44bp-4L, -0x2.1052fcc75fe78e44p-4L, -0x4.b04c77d29e1352ap-4L, -0x4.b04c77d29e135298p-4L }, + { 0x7.afbf13a7baa48938p+28L, -0xc.e3f378c5ed3afabp-4L, -0x1.ad5137573db23a6ap-32L, -0x1.ad5137573db23a68p-32L }, + { -0x5.ed5d3988224f9748p-4L, 0x1.e7758010af069478p+112L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xc.0d33ff76e10cd46p+12L, 0x4.1c590bda30ba606p-4876L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x6.57e754000acc05cp-56L, -0xb.d8b227ae135fe8fp+116L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x4.6e00ec5a491950b8p+10764L, -0x1.933e5a044e710e98p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0xd.233e9cefca1ae41p-120L, 0x3.45dd24865b41e91p+60L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x5.475a990a52ea68a8p+64L, -0x1.8712ead1e57a5c3cp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x1.09bc36ba214221b6p+5604L, -0x4.bf6dbbf8cca43b3p-8L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x9.4d57927720bce2ap-4L, -0xd.c24a0c2da437c45p-8L, -0x3.0ca61d2678ef9458p+0L, -0x3.0ca61d2678ef9454p+0L }, + { -0x3.bd744abad650adacp+24L, -0x5.b0583bb444fdc93p-72L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x7.2f26a663cb2f6da8p-152L, 0x9.fc2ec0983ea77b3p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x7.56ebed5f60ce8aa8p-128L, 0xe.ca8e0a5bcb1909bp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x7.9e2690fa1674f7p-4852L, -0x6.a2b3b3cd69bd69p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x5.61e2ca1189149e08p-8L, -0x3.489ad8567c6e09dp-4L, -0x1.77fd0cf88ee2c678p+0L, -0x1.77fd0cf88ee2c676p+0L }, + { -0xd.a2d0231770a0b2fp-4L, -0xb.11f2a040958b184p+108L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xd.566e196c5299a76p-4L, -0xd.827bfd05ebedd0fp-4L, -0xc.ab3ec5d1508e531p-4L, -0xc.ab3ec5d1508e53p-4L }, + { 0xe.690353be92b1ef7p-4L, 0xc.b40a6525370a3c1p-4L, 0xb.8f77d01ae6a411cp-4L, 0xb.8f77d01ae6a411dp-4L }, + { -0x4.a16f62e1fb463d7p-4L, -0xb.6a308232b3be302p-4L, -0x1.f4c81947d7e0267p+0L, -0x1.f4c81947d7e0266ep+0L }, + { -0xa.589c3c563d348fcp+108L, 0x3.aabe12c6cdd5648p+11880L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x1.2112dc65b51a2856p+16L, -0x2.f0fad09fd8f01c5p-108L, -0x2.9ad45124fc8c3a5p-124L, -0x2.9ad45124fc8c3a4cp-124L }, + { 0x6.501f9ed256bec01p-4L, -0xa.0150779e90ebc75p-4L, -0x1.02068c4d16492b4ap+0L, -0x1.02068c4d16492b48p+0L }, + { 0x3.57784bb97c2bfa94p-3436L, -0x8.16fa985eea51244p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x4.6510b53e44e358fp+108L, -0x9.2c631a27ad6ae34p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0xd.5153d9f62ecffddp-4L, 0x1.7345ed4ae2d9f036p+116L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x7.a68b5532b0e7f568p-4L, 0x7.9a2907c3621d33ap-4L, 0x2.5bff699f72c04828p+0L, 0x2.5bff699f72c0482cp+0L }, + { 0xc.e8479ca0a43ef6p-8L, 0x9.182ad6a367d08aep-4L, 0x1.7b7995fca66e81cep+0L, 0x1.7b7995fca66e81dp+0L }, + { -0x1.26053714fd0be6bap-44L, 0xa.52ae9411f58887cp-4L, 0x1.921fb54442edffd6p+0L, 0x1.921fb54442edffd8p+0L }, + { 0xe.a227507d931299cp-104L, -0xd.13cf8aa40b87d27p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x1.e472b4341bef26b6p-56L, -0x1.7af3bd8ca1f57c42p-7268L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0xd.f33b2053ffa6ae5p-4L, 0xa.8e75c696dc40c78p-4L, 0x2.7e69886741fe3d78p+0L, 0x2.7e69886741fe3d7cp+0L }, + { 0x9.85d3f0dd48eaf72p-4L, -0x3.541ae29b92aa4abp+72L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x1.5a3107a9603de8b4p-28L, -0x3.08af0a00602595fp-4L, -0x1.921fb4d2276f0c64p+0L, -0x1.921fb4d2276f0c62p+0L }, + { 0xf.cac159b69035579p-4L, -0x6.46e719cea85447d8p-4L, -0x6.0da354e1ed3337d8p-4L, -0x6.0da354e1ed3337dp-4L }, + { -0x5.987b05c45ed8a2ep-4L, 0x6.c4e52aa8d26db038p-4L, 0x2.42f6589620f3dab4p+0L, 0x2.42f6589620f3dab8p+0L }, + { -0x8.23b5b38feb155f2p+28L, 0x1.15a54236fe36bd4cp-56L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x1.f5ea7b800785d2ccp-4L, -0x7.ef6aaf1d13c7a7dp-4L, -0x1.541d373bdb2328c8p+0L, -0x1.541d373bdb2328c6p+0L }, + { 0x3.73e18f430b288f48p+5764L, 0xc.f70837877517a74p-4L, 0x3.c14c064e7addf6f4p-5768L, 0x3.c14c064e7addf6f8p-5768L }, + { -0x7.3487f80314c54488p-4L, 0x5.4eccb9e96eb8967p-4L, 0x2.81b5de701e1c753cp+0L, 0x2.81b5de701e1c754p+0L }, + { -0x1.2888c122fac324e2p-116L, -0xd.5620dcdef8d6adep-1048L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x1.a20b309dc63a3432p+100L, 0x1.d9633c032d4a9bc4p+11900L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x5.b49471d499a4cf1p-4L, -0x9.94f5bdecfacab51p-8L, -0x3.09798474778972c8p+0L, -0x3.09798474778972c4p+0L }, + { 0xf.641993c9a620462p-4L, 0xd.a2dd238869b2787p-4L, 0xb.99ab7575d6c73c4p-4L, 0xb.99ab7575d6c73c5p-4L }, + { 0xd.4c3f10c6378bac1p-144L, -0xd.a0da38c144c364ap-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x1.6795cd67133c419cp+104L, -0xf.5afa51a915c3c2cp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0xa.7324ede2d5b774ep-4L, 0x9.bd729cbbfe64c8ep+64L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x6.67af9a1b48f5476p-4L, -0xb.916f204d9b607e2p-4L, -0x1.10ac84512c1151bep+0L, -0x1.10ac84512c1151bcp+0L }, + { -0x9.a94b7284791aef1p-4L, -0xf.30d659afbbe444dp-4L, -0x2.2323d6dc698c7f1cp+0L, -0x2.2323d6dc698c7f18p+0L }, + { 0x1.15035f9ba3aac31ep-4L, 0xc.6f90a760827aa89p-124L, 0xb.7e126079e1ac136p-120L, 0xb.7e126079e1ac137p-120L }, + { -0xf.fef4a753b10a076p-4L, 0x6.4c2eb46758106918p-4L, 0x2.c43b45ae1e73a0e8p+0L, 0x2.c43b45ae1e73a0ecp+0L }, + { 0x1.3ef509e0c382df66p-4L, 0xc.49b63ac9b2b9eaap-4L, 0x1.78415d75aa039046p+0L, 0x1.78415d75aa039048p+0L }, + { -0x6.d057f880739cc278p-4L, -0x2.c6607086f9019804p+624L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x8.0a6f57c957a28d4p-4L, -0xb.e7e303842191512p+68L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x1.c50b391458918814p-168L, 0x2.b751311339e95d54p+40L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xb.51ba4b350a61c32p-4L, -0xc.0dfbf7e5e3212ffp-12L, -0x1.10a1458b2219c224p-8L, -0x1.10a1458b2219c222p-8L }, + { -0x7.6c639e488208ccc8p-4L, 0x3.a1d6c7b434bf3d98p-4L, 0x2.afc1c9bc173fb84cp+0L, 0x2.afc1c9bc173fb85p+0L }, + { -0x5.c358113ef832c348p-4L, -0xb.d7d98c530f97875p-4L, -0x2.060fd0c52c8ea69p+0L, -0x2.060fd0c52c8ea68cp+0L }, + { 0x1.3e90b4eb0efaf5fap-6916L, -0xa.5b3f67eed42f35ep-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x8.df34d29839f6cbap-76L, 0x8.6f95a977e54b54fp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x1.d6566fbbd43703bcp-4L, 0x5.7c58e6c483f58898p-4L, 0x1.e4db3a1a27a3fd2ep+0L, 0x1.e4db3a1a27a3fd3p+0L }, + { -0x2.35210275477555ccp-120L, -0x8.3dccba3b25f76c1p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xd.5f0d592ded19983p-4L, 0xa.c3b832d5003b707p-8L, 0xc.deb2302702560a9p-8L, 0xc.deb2302702560aap-8L }, + { 0xa.1061f8f22c56a2p-4L, 0x7.a0e695df486975a8p-4L, 0xa.60aca0123922aa8p-4L, 0xa.60aca0123922aa9p-4L }, + { 0x2.0f49c0d924c5ef48p-4L, -0x1.4c612171c559b0d2p-4L, -0x8.ffc2ff83f8bbf35p-4L, -0x8.ffc2ff83f8bbf34p-4L }, + { 0x7.5446c6842f5c1d88p-12L, 0x7.18f85d323644c07p-4L, 0x1.91175a864f920822p+0L, 0x1.91175a864f920824p+0L }, + { -0xb.e3d76e1e4bf5645p-8L, 0xa.e3f91773dee5cbdp-4L, 0x1.a390b3558878456ap+0L, 0x1.a390b3558878456cp+0L }, + { -0x6.64a485a65ba2bb8p-4L, 0xb.ab5d793764e46aap-4L, 0x2.126e03037b78e2a4p+0L, 0x2.126e03037b78e2a8p+0L }, + { -0x4.180ed04588b6b84p-4L, -0x3.1b46b393f7f02654p-4L, -0x2.7e12fe53471d28ep+0L, -0x2.7e12fe53471d28dcp+0L }, + { -0xb.12b6b696713dd3p-4L, 0x4.65ce2cb3797b29a8p+24L, 0x1.921fb56c8c50179p+0L, 0x1.921fb56c8c501792p+0L }, + { -0xa.3485ec95ca278f3p-4L, -0xc.4eeb5c35769e37p-4L, -0x2.43572f0e1543b008p+0L, -0x2.43572f0e1543b004p+0L }, + { 0x7.9916813ff5ff3cc8p-4L, 0xe.8cc5489d5bd410dp-4L, 0x1.16ec5e1241b086b4p+0L, 0x1.16ec5e1241b086b6p+0L }, + { -0x4.332914d9e18063ap-4L, 0x2.c3783d61fd7041fcp+324L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x7.8ea9558f03ae0e7p-4L, -0xf.dee9088b413455fp-4L, -0x1.205b027c87f0ec66p+0L, -0x1.205b027c87f0ec64p+0L }, + { -0x8.2df8e53739c9b8bp-4L, -0xb.237c6168dab68dbp-4L, -0x2.344698f98d5f286p+0L, -0x2.344698f98d5f285cp+0L }, + { -0xc.ff8006e798ca57dp-4L, -0xb.402101043dda93fp-72L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x7.837abefd5e55df78p-4L, 0x1.a83077ccca0d82acp-136L, 0x3.874cdd05c1765a8p-136L, 0x3.874cdd05c1765a84p-136L }, + { 0x3.a07b4d79ba0a5338p+28L, -0x4.bb21255de4a41a5p-4L, -0x1.4dee6dffdfcabca8p-32L, -0x1.4dee6dffdfcabca6p-32L }, + { -0x5.4eee2008ac59dda8p-24L, 0x2.d2b2eaf924487474p+8820L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x6.bbde2a7543c30b38p-4L, 0xb.8edecd5dd38da0cp-4L, 0x1.0b1331d46f6de5d4p+0L, 0x1.0b1331d46f6de5d6p+0L }, + { -0x6.c15f52803f443968p-4L, 0x3.918ec1969b0edd88p-4L, 0x2.a7d4fdd140e4ebecp+0L, 0x2.a7d4fdd140e4ebfp+0L }, + { -0xe.f6471a773b022bdp-8L, 0x3.3e6b054d350dcc9p-4L, 0x1.d9f9aa2df774d312p+0L, 0x1.d9f9aa2df774d314p+0L }, + { 0x6.81487cec2e861c7p-8L, 0x4.87a7a304beeda28p-4L, 0x1.7b3580ce6e5967ep+0L, 0x1.7b3580ce6e5967e2p+0L }, + { -0xd.c7238c1ad3cafc9p+88L, 0xe.ac1774f7032d1ffp-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x2.3f1854f194f5df1cp-128L, 0x1.014e18840001d972p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x5.040eb8c257682f18p-4L, 0xf.7346ad82e18af85p-4L, 0x1.41c34c3094d5a47cp+0L, 0x1.41c34c3094d5a47ep+0L }, + { 0xf.1cd1b7c493a3be6p-124L, 0x1.9e8c3ea1db7772dep+120L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x6.e13c582ac5e85888p-64L, 0x4.b2842fc0d4e29f8p-4L, 0x1.921fb54442d18452p+0L, 0x1.921fb54442d18454p+0L }, + { 0xf.a09a22b402060edp-4L, -0x8.e32395dc002f9bfp-8L, -0x9.1869589c28478e3p-8L, -0x9.1869589c28478e2p-8L }, + { -0xf.8c0db00bdf53596p-4L, 0x5.36e056abcab2faa8p-4L, 0x2.d167d9163e9e6a94p+0L, 0x2.d167d9163e9e6a98p+0L }, + { 0x7.6c92e56712d5affp-4L, -0x6.b6582996f57933c8p+124L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x3.0c9abaa8404f3e18p+140L, -0xa.e4299f2f9dca735p-4L, -0x3.926176c315d2215p-144L, -0x3.926176c315d2214cp-144L }, + { -0xe.d132e5394f60034p-10048L, -0x4.6ac0196a0af61fdp+72L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x9.ea2a7bd17c460dep-4L, -0x3.b176489ffeab233cp-80L, -0x5.f5c096bd8a9e69d8p-80L, -0x5.f5c096bd8a9e69dp-80L }, + { -0x7.e3d1eea20b324e7p-4L, -0x9.86088a50194e78ap-4L, -0x2.433d3f80c2defd8cp+0L, -0x2.433d3f80c2defd88p+0L }, + { 0x3.dfea4f893d4c581cp-3232L, 0xc.7be5695b1db3127p+100L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xe.e19314560029718p-4L, -0xa.e3c3bdecf1dec26p-8L, -0xb.b346fb302824719p-8L, -0xb.b346fb302824718p-8L }, + { 0x7.13c978b522f9333p-4L, -0x6.c0d55cd6c8226dd8p+16L, -0x1.921fa47fb9a46872p+0L, -0x1.921fa47fb9a4687p+0L }, + { -0x1.1d1ed153b343c44ep-4L, 0x7.6fdb8f997549cde8p-8L, 0x2.bf08ff529f82588p+0L, 0x2.bf08ff529f825884p+0L }, + { 0x2.7a077ab0456582fp+88L, 0xf.6e420d340620fd3p-4L, 0x6.3afbbdbf3e3239e8p-92L, 0x6.3afbbdbf3e3239fp-92L }, + { -0xe.6c4b7e894887c7fp-4L, -0x2.a9883b33131d202cp-4880L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0xe.22b622d6cdf1548p+8L, -0x3.af9571884b9dea6cp-4L, -0x3.243b3e7ef45eb194p+0L, -0x3.243b3e7ef45eb19p+0L }, + { -0xb.a0a2f3e13b85a66p-4L, -0x5.5d35693a073a956p-80L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x1.22c95177a19486ep-100L, -0x1.09a01a4ee447f2dp-8L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x6.290348987c0e55f8p+136L, -0x4.20c946d47a37871p+4972L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xc.ad96dfac7b95172p-4L, 0x1.1fc7d37c0ec92196p+104L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xd.0d8c22a9e6d3c5p-4L, -0x2.31c152f5ee281b54p+11172L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x5.13c1489191b10628p-4L, 0x9.40268306f3eaf37p-4L, 0x1.119f5be56987a0b4p+0L, 0x1.119f5be56987a0b6p+0L }, + { 0x9.167509d85ac5562p+60L, 0x1.4b8f74471056531ep+12628L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x3.f7343ff72e27615cp-4L, -0x3.3ce0a42e5743e218p-3160L, -0xd.103c74c735aacefp-3160L, -0xd.103c74c735aaceep-3160L }, + { -0x6.19ec462854667938p-4L, 0xe.a753d50ad228a17p-4L, 0x1.f71fe9e91d7e6d3ep+0L, 0x1.f71fe9e91d7e6d4p+0L }, + { 0xb.2326e5c709d8338p-4L, 0xe.4cbeeba038e2a66p-4L, 0xe.8ba0b620906082cp-4L, 0xe.8ba0b620906082dp-4L }, + { 0x9.90137db5d8438f6p-4L, 0x8.f6fc2825e1cf803p-4L, 0xc.0cd4a9c04892b88p-4L, 0xc.0cd4a9c04892b89p-4L }, + { 0xb.a6e18f1dc982de2p+16L, 0x7.093038cd340d2eap-4L, 0x9.a9560c2566d537p-24L, 0x9.a9560c2566d5371p-24L }, + { -0x1.7d48f31379a2fd94p+13764L, 0x7.408cc4c84d37f818p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0xf.a038fe23264b69fp-4L, -0x5.d983ceba22bba45p-4L, -0x2.c88bec446ef69d7cp+0L, -0x2.c88bec446ef69d78p+0L }, + { 0x3.aaf0ce3e734d6f2p-4L, 0xf.72f358999238d68p-4L, 0x1.5673af7a281b339p+0L, 0x1.5673af7a281b3392p+0L }, + { -0x6.4d100f244be8113p-4L, -0x8.8a2584d61c785a5p+10256L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x6.e4c6b8c4d0181df8p-11840L, 0x2.88e3d82654a9a2d4p+84L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xb.bac11f4e1e14036p-4L, -0x5.f466fe6cbdda3498p-4L, -0x2.abfd043f83efad38p+0L, -0x2.abfd043f83efad34p+0L }, + { 0x5.b28281e63f18c36p-40L, 0x1.5d03274c615fac7ep-4L, 0x1.921fb543fff47b6ap+0L, 0x1.921fb543fff47b6cp+0L }, + { 0xf.e3a0ddc922c2768p-4L, 0xa.669f21ff1f04159p-4L, 0x9.460446a2490498ep-4L, 0x9.460446a2490498fp-4L }, + { 0x8.ab617e168652f41p-4L, 0xa.9ceb33ff19c471bp-4L, 0xe.2c71acd10589374p-4L, 0xe.2c71acd10589375p-4L }, + { 0x7.e712d33d338b3f4p-4L, 0x1.bb5c92c3b346b3d2p-140L, 0x3.81a60c2164f42748p-140L, 0x3.81a60c2164f4274cp-140L }, + { 0xb.0f353c55a1bc86bp-4L, 0x2.a7aa43ef734cca24p-14752L, 0x3.d74b1fcceaff8cc4p-14752L, 0x3.d74b1fcceaff8cc8p-14752L }, + { 0x6.355f24aadd2d76cp-4L, 0x5.db625c7f505b3848p-4L, 0xc.19b1387d741a37p-4L, 0xc.19b1387d741a371p-4L }, + { 0x2.b76e057b32691f28p+56L, 0x6.dee852c47ad7ae6p-4L, 0x2.877c26e1b4786b5p-60L, 0x2.877c26e1b4786b54p-60L }, + { -0x6.bb1bf54be9664e8p-4L, -0x1.abb9e76137c068dcp-28L, -0x3.243f6a48f9ae83e8p+0L, -0x3.243f6a48f9ae83e4p+0L }, + { 0xf.db239caa0c58725p-4L, -0x1.a857f265390a97e6p+11340L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xe.d6bf659b8abbf88p-52L, -0x6.3520edf48c502b48p-4L, -0x1.921fb54442cf2076p+0L, -0x1.921fb54442cf2074p+0L }, + { -0x2.845d2338bd21f05cp-4L, -0x1.d3130e0c084f14c8p-4L, -0x2.83ae1a3982d00d2p+0L, -0x2.83ae1a3982d00d1cp+0L }, + { 0x7.e34ef80c4f7e3eep-4L, -0x5.a8b3cf39973ba25p-4L, -0x9.f50b2ea47c1075ap-4L, -0x9.f50b2ea47c10759p-4L }, + { -0x1.56bf999942c755dap+7896L, -0x9.80fe0cfc3618055p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x1.deff9f28444c6c38p-4L, 0x9.1da1f7cda29486bp+48L, 0x1.921fb54442d187b2p+0L, 0x1.921fb54442d187b4p+0L }, + { -0x9.24964216848ef53p-4L, 0x1.f0ed69f0e4821e64p-116L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0xc.7f839e0758c0fc4p-4L, -0xa.04266867c71fecep-4L, -0x2.774af214e503f1a4p+0L, -0x2.774af214e503f1ap+0L }, + { 0x1.8d5159b50fdc3fbep-84L, -0x6.ea56e501411dee98p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x6.108af52b9d9b2bp-4L, -0xc.1cbbb5c2e434abap-88L, -0x1.ff48471de69df2e4p-84L, -0x1.ff48471de69df2e2p-84L }, + { 0x5.d6a27cfc56ca253p-36L, -0xb.3fef5d7e57e0805p-4L, -0x1.921fb543bdf581a8p+0L, -0x1.921fb543bdf581a6p+0L }, + { 0xe.b53f2b3083d023ep-4L, 0xb.f408f69524f06c2p-4L, 0xa.eb4641b720503dbp-4L, 0xa.eb4641b720503dcp-4L }, + { 0x8.03baca4a7357516p-4L, -0xa.c1abbb69e26abf7p-4L, -0xe.e31b0d044e273ap-4L, -0xe.e31b0d044e2739fp-4L }, + { 0x1.d872e7eedaaa637ep-4L, 0x4.495ee30da4659e98p-4L, 0x1.2a0c770aea65c4c6p+0L, 0x1.2a0c770aea65c4c8p+0L }, + { -0xc.150a73ee88aac4bp-4L, 0x2.8fa0b8cb59d9a58cp-8L, 0x3.20db3e407d76332p+0L, 0x3.20db3e407d763324p+0L }, + { -0x6.08720c311ad69e78p-4L, -0x7.3b6b4ffd7b8decp-8L, -0x3.111a73de1561f32p+0L, -0x3.111a73de1561f31cp+0L }, + { -0x5.80db9fe644d1e708p-4L, -0x3.ec81c27ff8544994p-76L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0xb.656227303abf84fp-4L, 0x7.b40be4642e982ab8p-4L, 0x9.82b5d74d3bcff98p-4L, 0x9.82b5d74d3bcff99p-4L }, + { 0xa.049b6be5646929ep-28L, 0x7.c2408cb283b8a548p-124L, 0xc.644b5de744c024bp-100L, 0xc.644b5de744c024cp-100L }, + { -0x1.0d0aa693e23087aep-4L, 0xa.b0a2a7b4c6b0611p+80L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x8.4b1f02dac6cd4b9p-4L, -0xc.759d3a3d2bb277bp-4L, -0x2.28783fdcb3986748p+0L, -0x2.28783fdcb3986744p+0L }, + { -0x9.5efce40ef5c193p-4L, 0x1.3acdec63c75ba85ap-4L, 0x3.02d863b62e9ce0ep+0L, 0x3.02d863b62e9ce0e4p+0L }, + { -0x3.a8862397aa33d5bcp-4L, -0x8.40b99f3260074bbp-4L, -0x1.fcf094a049d0f47p+0L, -0x1.fcf094a049d0f46ep+0L }, + { -0x1.13ba9d07bc3a2952p+84L, -0x2.71006a8cb34d554cp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x9.1553f4826cd4c82p-4L, 0xa.cf99c7754a95e18p+96L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x3.8114a9e190ab791p-60L, -0x4.9c18fd283d9a589p-4L, -0x1.921fb54442d183a8p+0L, -0x1.921fb54442d183a6p+0L }, + { 0xc.05b3f7d8b6f7624p-4L, -0x1.954b2fada5db23c6p+104L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x5.7aa677b8b3a14efp-4L, 0x6.8d1b5b54f8172e1p-4L, 0xd.fd0cb0efb607319p-4L, 0xd.fd0cb0efb60731ap-4L }, + { -0x4.a8455a7e3a68ed78p-4L, -0x4.7b4255a8c709f0ap-16L, -0x3.2430052b6ba121b8p+0L, -0x3.2430052b6ba121b4p+0L }, + { 0xf.331d018a51a3937p-4L, -0x3.eca2bd0c8570369p-4L, -0x4.0aeef8cb409b3868p-4L, -0x4.0aeef8cb409b386p-4L }, + { 0x6.52993e0816809a4p+1080L, 0xa.8f1f3b01d061b7dp-4L, 0x1.ab87a4c2ecb907f2p-1084L, 0x1.ab87a4c2ecb907f4p-1084L }, + { 0x2.293460674db2c4p-4L, -0xd.ea0bd2fdf3193cep-4L, -0x1.6aae49a397df62c6p+0L, -0x1.6aae49a397df62c4p+0L }, + { -0x7.7cc8ad228793eeep-4L, 0x3.3eb74cb49c028ad4p-4L, 0x2.bb8e137b5adb0bc8p+0L, 0x2.bb8e137b5adb0bccp+0L }, + { 0xe.bc5331958998244p-4L, -0x1.2903edbad4d00bdep-152L, -0x1.428000ee39f15116p-152L, -0x1.428000ee39f15114p-152L }, + { 0x5.3ee964d9303fef2p-4L, 0x9.0a14cf75dc8c935p-136L, 0x1.b92274ff2c1cfc2ap-132L, 0x1.b92274ff2c1cfc2cp-132L }, + { -0x6.e59cd2b304be20bp-8L, -0xd.25ced593ff0ac61p-4L, -0x1.9a83972861c5912p+0L, -0x1.9a83972861c5911ep+0L }, + { -0x3.1617c019abd659bp-4L, -0x6.690f39e52d0c90c8p-4L, -0x2.04fdb7e0f6ca2148p+0L, -0x2.04fdb7e0f6ca2144p+0L }, + { 0x9.1050fe64665d025p-4L, -0x1.fd861374d11ff0fcp+4216L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xd.953628a90529c68p+16L, 0x1.d0ef8f8c2df971eap-52L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x7.a4dabfc6c9e825b8p-4L, -0xb.f01119533e278e8p-4L, -0x1.00526ae79cfdf7bp+0L, -0x1.00526ae79cfdf7aep+0L }, + { -0x1.6396f574b56c6172p-4L, 0xf.b5e4a3223e61c14p-4L, 0x1.a8b2f2c93a739358p+0L, 0x1.a8b2f2c93a73935ap+0L }, + { -0x1.a1e72b708ae7ec3ap-84L, -0x1.cad34f8832df94b6p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xd.a82c5b229e8fe54p-4L, -0xc.337e6ec5ca09cbfp-4L, -0xb.aaa255a332a6dc7p-4L, -0xb.aaa255a332a6dc6p-4L }, + { -0x1.6666a8b8b12721dep+4L, 0x7.b2a783da083648ep-8L, 0x3.23e770d8aa1a524cp+0L, 0x3.23e770d8aa1a525p+0L }, + { -0x3.9a1204d27a81d9a4p+56L, -0x7.c2d56e73e1215768p-4L, -0x3.243f6a8885a308b4p+0L, -0x3.243f6a8885a308bp+0L }, + { -0x7.cfb667a4a3914a3p-4L, -0x2.365d2022bd55ec38p+8880L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xb.439e5356c702ad8p-4L, -0x1.c311b31d8db88c76p+12068L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xe.d87c88ea04cfc54p-4L, 0x7.5df293fec0fa7908p-4L, 0x7.5ec19b27ea9d83ap-4L, 0x7.5ec19b27ea9d83a8p-4L }, + { -0xb.f31341da10838b7p-4L, -0x4.94201f2127bae1d8p-4L, -0x2.c69340156b018bb8p+0L, -0x2.c69340156b018bb4p+0L }, + { -0xf.466813a0cb58997p-4L, 0x1.b40206802faf31f8p-4L, 0x3.07d2400cd8e729fp+0L, 0x3.07d2400cd8e729f4p+0L }, + { -0x1.73fa2d1e8f4aed4ap-8956L, -0xd.f8e6092df0a67cdp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x3.b170aeec21cbacep-124L, -0xe.4ffa3f0dccc1904p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x6.fa8da286037d29f8p-4L, 0xf.58e77980ec0ef84p-4L, 0x1.24debdfdda0fa8c4p+0L, 0x1.24debdfdda0fa8c6p+0L }, + { 0x8.5ae9b271c862bd1p-4L, -0xa.8fdf30d83ecd512p-4L, -0xe.6cae0678d6b6b55p-4L, -0xe.6cae0678d6b6b54p-4L }, + { -0x1.e689240cdaba32p-84L, 0xe.c5e20aeb268e22p+68L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xf.65a3e9387da5a2fp-4L, -0x2.f52bdc7095786358p-68L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x5.9a9d1446632f3aep-4L, -0x4.da74bc68acb86d9p+28L, -0x1.921fb5431b39c106p+0L, -0x1.921fb5431b39c104p+0L }, + { -0x8.7aea261756d25f3p-4L, 0xf.b5a3f9c32315f89p-4L, 0x2.10d707be6bdebe98p+0L, 0x2.10d707be6bdebe9cp+0L }, + { -0xe.7abe135a43a13e6p-4L, -0xe.63241d69fc37ac5p-88L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x3.2bf2a0a669999b48p-4L, 0x2.9affca93299785ep+5448L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x1.31c27de6118742f6p+7288L, 0x8.4ef4a64c01509a8p-4L, 0x6.f4cfe94bc3c887e8p-7292L, 0x6.f4cfe94bc3c887fp-7292L }, + { -0xd.d97824ee2873846p+60L, -0x3.d56d54e6a082a09p-9744L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x3.457eb22e95949aa4p-132L, -0x2.c7ad460f031ac6c8p-148L, -0xd.98a6edfdd4c7bcep-20L, -0xd.98a6edfdd4c7bcdp-20L }, + { 0xa.340ec3fa9c98451p-4L, -0x5.a130fe2bb18970cp-4L, -0x8.11219835b80db8cp-4L, -0x8.11219835b80db8bp-4L }, + { 0x2.36bf7820405b3b6cp-1364L, 0xb.c0ae25e2a801fc9p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x9.33aadc610c07076p-4L, 0xb.62d8d178f4ea271p-4L, 0xe.41f0912d1fc9e9ap-4L, 0xe.41f0912d1fc9e9bp-4L }, + { -0xb.de8017b99009994p-4L, 0xc.d14f3f856910093p-4L, 0x2.515ae28f032a6f08p+0L, 0x2.515ae28f032a6f0cp+0L }, + { 0x4.d809ec362c4289bp-104L, -0xc.5d2d16de94144fcp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xd.79e031e02305347p-4L, -0xa.c010f18d71bc8c5p-4L, -0xa.c60f92816aef05p-4L, -0xa.c60f92816aef04fp-4L }, + { -0x3.39af6943075c3b8p-13668L, 0x1.720bafd1b399ec82p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x4.fac18c7be7e011e8p-4L, 0xe.e7cda687036f7d6p-8L, 0x2.f58afa694e9eab6p-4L, 0x2.f58afa694e9eab64p-4L }, + { -0x9.9c2d0517aeee533p-8L, 0x1.cae7d85a2a39e2acp-3348L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x1.d28f44d13b0d6254p-12L, -0x5.fee8120e5e04be2p-4L, -0x1.926d85fbcd378c66p+0L, -0x1.926d85fbcd378c64p+0L }, + { 0x3.f3364f18a79b3b3cp-4L, -0x3.6b2dcf47d1901574p-144L, -0xd.d8fc6e63635a2c2p-144L, -0xd.d8fc6e63635a2c1p-144L }, + { 0x6.e5d1de6f1a858028p-8428L, -0xf.f7a6695a9469f6bp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x5.768672da4d7d0c9p-64L, 0x8.92179a4e3bb69e3p-4L, 0x1.921fb54442d1845ep+0L, 0x1.921fb54442d1846p+0L }, + { 0xb.ed688726df9befap-4L, 0x9.3f55bdfddb49b2bp-4L, 0xa.8d531b9fae50f96p-4L, 0xa.8d531b9fae50f97p-4L }, + { -0x3.9761f885a890c5f8p-148L, 0x3.fbc31466ed38546cp+112L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x6.5dbff56825b7dbb8p-4L, 0xa.e7a98283fc10855p-4L, 0x1.0ad966b89af0b16p+0L, 0x1.0ad966b89af0b162p+0L }, + { -0xc.2509016f44e196ap-4L, 0x7.861514480ac9199p-4L, 0x2.96425b66aa6752cp+0L, 0x2.96425b66aa6752c4p+0L }, + { -0xf.17da41cf884346bp-4L, -0xc.62d7c253621dcf7p+92L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x9.845c3e40ed6ad83p-8L, 0xd.68fda9eec5a66c2p-4L, 0x1.9d78b2079eeed2acp+0L, 0x1.9d78b2079eeed2aep+0L }, + { 0x8.18f925371b61292p-4L, -0x1.57f7c0849ebb346p-4L, -0x2.a182f2c02a69e4b4p-4L, -0x2.a182f2c02a69e4bp-4L }, + { -0x5.7255a940d84ebcf8p-104L, 0x7.1174b12c13aaf4e8p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xe.880fef5908d95bdp-4L, 0x7.609718a06f5f08ap-4L, 0x2.abfc8b95e8a16a24p+0L, 0x2.abfc8b95e8a16a28p+0L }, + { -0x6.e2bdbcf507ec4778p-4L, 0xa.20544abb2f768b5p-4L, 0x2.2aff89eb7f75b724p+0L, 0x2.2aff89eb7f75b728p+0L }, + { 0x6.14aea1523dfe3aa8p-4L, 0xc.97a55c9c85f26f9p-4L, 0x1.1ef5051994890448p+0L, 0x1.1ef505199489044ap+0L }, + { -0x8.680ab975830d106p-28L, -0x3.7b5dd7324be888fcp-4L, -0x1.921fb7ae5387a11ep+0L, -0x1.921fb7ae5387a11cp+0L }, + { 0xd.ff0ee4cab1a5c92p-36L, -0xe.008f2e366ac05f5p-4L, -0x1.921fb54342ecf648p+0L, -0x1.921fb54342ecf646p+0L }, + { -0xa.b9de710cc3240eap-4L, 0xd.b8496a7f5a40118p-4L, 0x2.3bfd545148e14c4p+0L, 0x2.3bfd545148e14c44p+0L }, + { 0xb.c810c87ed94addfp-4L, -0x3.0523d455a5644e6cp-11020L, -0x4.19f89145d6fd82p-11020L, -0x4.19f89145d6fd81f8p-11020L }, + { 0x6.b4a53b079af062ep-52L, 0x1.02b5df71e26e7eeep-4L, 0x1.921fb54442cae1cp+0L, 0x1.921fb54442cae1c2p+0L }, + { -0x1.05a95b1b36f384dcp-100L, 0x5.d8b77fd6db5f46fp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x3.b2d5aa2bd4f226c8p-4L, 0x1.3d87d39ca205f226p-4L, 0x5.2d5b7585602e1918p-4L, 0x5.2d5b7585602e192p-4L }, + { 0x7.58b591427632828p-4L, 0xd.51cbb799b3f3a26p-4L, 0x1.1116e6ac8ad3c638p+0L, 0x1.1116e6ac8ad3c63ap+0L }, + { 0x9.0e54bb10a5b7912p-4L, 0xa.7e81ca95f58d507p-76L, 0x1.28a7d33e5f568438p-72L, 0x1.28a7d33e5f56843ap-72L }, + { -0x5.1c6359354bd6cac8p-4L, -0x6.c6dd984bf0b457cp+11148L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x3.c17697f567f1596cp-7888L, -0xd.dd9a1c0c442c4c6p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x4.61b51c01df55d6d8p-4L, -0xb.dce6fd9bad9f495p-4L, -0x1.ecb365c6c3aa5084p+0L, -0x1.ecb365c6c3aa5082p+0L }, + { -0xa.b6f22a1b9f2939fp-4L, -0x3.4bb35afb05788e3p-4L, -0x2.d7db2978909722ap+0L, -0x2.d7db29789097229cp+0L }, + { -0x1.a1b675fb478bf18p+0L, -0x2.1ce57b45214ebd74p-4L, -0x3.0f9309e0cdbb0d7cp+0L, -0x3.0f9309e0cdbb0d78p+0L }, + { -0x5.067f9f48fc5b234p-8L, 0xb.a04244a598be88fp-4L, 0x1.9909c9c477bcd66cp+0L, 0x1.9909c9c477bcd66ep+0L }, + { 0xf.d97f1711de15f9cp-4L, -0x3.d24ecad1dffaabe4p-36L, -0x3.db97674bec9f4df8p-36L, -0x3.db97674bec9f4df4p-36L }, + { -0xc.deaf7691740cdefp-8L, 0xa.59b5d478c821a2ep-4L, 0x1.a5fa83821cba7646p+0L, 0x1.a5fa83821cba7648p+0L }, + { -0xd.1b186c2e3417901p-4L, 0xf.14939428966efa8p-4L, 0x2.49480ac2f173d45p+0L, 0x2.49480ac2f173d454p+0L }, + { 0xa.548931dd5b08516p-1308L, 0x3.0d860af72111fc38p-84L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x2.379420afe91ec9c8p+40L, 0x6.381df51cf6ba1e58p-4L, 0x3.243f6a888576271cp+0L, 0x3.243f6a888576272p+0L }, + { 0xb.d0fe6ed90e574e6p-4L, 0x5.f4609ad6162545cp-4608L, 0x8.101632edfcc5ab9p-4608L, 0x8.101632edfcc5abap-4608L }, + { 0x1.925eaa29d2ecb61cp+44L, -0xd.ac66274a591f9a9p-4L, -0x8.b30fadfb09888a8p-48L, -0x8.b30fadfb09888a7p-48L }, + { 0x3.a5ddc4a5f3b82868p+64L, -0x2.bab320b85305843cp+11384L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x2.a982ac56625aefc4p-4L, 0x8.056940c538fa279p-4L, 0x1.e428e4e0f8cafb9p+0L, 0x1.e428e4e0f8cafb92p+0L }, + { 0x1.66b64b9c9f79a1dep-4L, -0x3.26b75fa52c7ce30cp-4L, -0x1.2703530602efb014p+0L, -0x1.2703530602efb012p+0L }, + { -0x9.da5604fb75e8d87p-116L, 0x8.f39b1339c38973dp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x7.677b36d2e1d48358p-4L, 0xa.996804efaa5460cp-4L, 0x2.2e38eedff366f594p+0L, 0x2.2e38eedff366f598p+0L }, + { -0x6.b6c06e4a29c88afp-4L, 0x5.a5149fe9b18171c8p-4L, 0x2.714657cddd0fa80cp+0L, 0x2.714657cddd0fa81p+0L }, + { -0x5.375a31264862647p+3840L, -0xc.55651fd1cbee3d4p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0xe.006deb92f93d672p+1080L, 0xa.6871090121d471bp-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0xc.8ed445e1ea26da6p-4L, -0x3.70640030d409ab74p-4L, -0x4.46dbe31ace4e4798p-4L, -0x4.46dbe31ace4e479p-4L }, + { 0x8.8651cda5ac10d93p-4L, -0x6.dee1c8172006e6e8p-4L, -0xa.da9a82f5b8d481bp-4L, -0xa.da9a82f5b8d481ap-4L }, + { -0xb.b53f28201a854efp-4L, -0x1.0a2c69e331c156f6p+3472L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xd.e2cee7a54e7c7dfp-4L, -0x9.3f6896a8070ab3ep-4L, -0x9.667e289dbdd94abp-4L, -0x9.667e289dbdd94aap-4L }, + { 0x1.a1524a334652c37cp-4L, 0x1.9b7f6344a4875e14p-4L, 0xc.7435ca5edddaf34p-4L, 0xc.7435ca5edddaf35p-4L }, + { -0xb.4660bc20f1141f9p-4L, 0x6.cc440cbde57dd15p+3488L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xf.3adad3101e81209p-4L, 0xa.79ea74b25ad8a16p-4L, 0x2.89ff542b1f7b17e8p+0L, 0x2.89ff542b1f7b17ecp+0L }, + { -0xd.4d87683a39ac568p-4L, -0xd.0f2848388d6bd4fp-4L, -0x2.5d8d3b12422814a4p+0L, -0x2.5d8d3b12422814ap+0L }, + { 0x1.767ee6689d922d76p-20L, -0x1.705dc2d9924977d6p-4L, -0x1.921eb101c57d5742p+0L, -0x1.921eb101c57d574p+0L }, + { -0xe.de1ad3b0df8a929p-4L, -0xe.4bc9f399afa1199p-4L, -0x2.6033c43349c8a4bp+0L, -0x2.6033c43349c8a4acp+0L }, + { 0x9.4bc88b56990e957p-4L, 0x3.8aa0cdd01b00999p+7580L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x7.5dedd023859c58c8p-4L, -0xe.f93cd6eb00fb07ap-4L, -0x1.1d13330bde9cdc64p+0L, -0x1.1d13330bde9cdc62p+0L }, + { -0x6.3df3c6079972141p-4L, 0xb.fe0dd62537b23a4p-2520L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x4.d95e34fb8dacb328p-124L, -0x9.b353da0ba311c6dp-60L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xc.6abf9e7c57817a2p-4L, -0x4.3c1e721def125b9p-4L, -0x2.d01af5496f51c508p+0L, -0x2.d01af5496f51c504p+0L }, + { 0x7.2ddd2222b3f198a8p-4L, 0x7.db137d9811c79dep-112L, 0x1.18208ad22454d6c4p-108L, 0x1.18208ad22454d6c6p-108L }, + { -0x4.cf7eed0ba7ab4778p-4L, -0x3.cfde77dacc7baccp-96L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x3.c4fc5635219d094cp-116L, 0x3.f00c386330e300ecp-28L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xf.6b843b68893794cp-4L, 0xf.2a2645e05f54dbfp-8L, 0xf.b71cea10e6fa9dfp-8L, 0xf.b71cea10e6fa9ep-8L }, + { -0x4.baca2c1fc8c972dp+24L, 0x6.90fbdf3ee3bced38p-776L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x2.c5e571ee1dc3a27p-4L, -0x7.0180ac3e7e17ae1p-4L, -0x1.f29bd3e4a7c4ec62p+0L, -0x1.f29bd3e4a7c4ec6p+0L }, + { -0xb.fe012bea0b6470dp-8L, 0x4.e3d9edfbba7c4bcp+136L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x5.42c4c079e796e1dp-4L, 0x3.797b1939cea93534p-4L, 0x2.8ed2b02d7596067cp+0L, 0x2.8ed2b02d7596068p+0L }, + { 0x5.994c986ae0567538p-4L, -0x1.aee939e2fbdd15c2p-9024L, -0x4.cf6eca9b5e92e72p-9024L, -0x4.cf6eca9b5e92e718p-9024L }, + { -0x2.6ae2f779ed5c0b58p-10132L, 0xc.75fc43f9ad2a67ap-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x1.b4e98c673b461666p-4L, 0x6.fa4bd77c57afe13p+3972L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xe.14620d5210a675ap+72L, 0x8.3ab9c1257774a44p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x6.75bfbc7f917d7158p-4L, 0x3.8750adb31a46680cp-4L, 0x7.ffbf86632db338ap-4L, 0x7.ffbf86632db338a8p-4L }, + { -0x2.a07fb251cb4cf3bcp+6416L, -0x5.b501e8056d41ca2p-88L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x9.a0eb440277239eap-4L, 0xc.50af1095969ae95p-4L, 0x2.3bffb3aafd0b1948p+0L, 0x2.3bffb3aafd0b194cp+0L }, + { -0x8.c5fdbc4b0b452f4p-60L, -0x8.c888d45b054b19ep-4L, -0x1.921fb54442d1856ap+0L, -0x1.921fb54442d18568p+0L }, + { -0x4.1a164828ad307d9p-4L, 0xd.d06990220d829b5p-6340L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x3.709d5b044eff68ap-4L, 0x4.79f2d04625e53728p-4L, 0xe.a63d1a773c7886ep-4L, 0xe.a63d1a773c7886fp-4L }, + { 0x2.5d97ab2d70f6435cp-4L, 0xd.562ebf23b602612p-4L, 0x1.652ee26e7a2cbd9p+0L, 0x1.652ee26e7a2cbd92p+0L }, + { 0x1.e0fded40c3c2896ep-4L, 0x9.b2a0e063a00552bp-4L, 0x1.6121f3177cf3867ep+0L, 0x1.6121f3177cf3868p+0L }, + { -0xc.ea981936ab65ff9p-4L, -0xf.1e90b017130c6d5p-4L, -0x2.471c6550f0ab8d14p+0L, -0x2.471c6550f0ab8d1p+0L }, + { -0x8.fc9915b02547e54p-4L, 0x3.fd5dcb827e327bbcp-4L, 0x2.b9495a0e3741ecc4p+0L, 0x2.b9495a0e3741ecc8p+0L }, + { -0x1.b1ad8c2578262e12p-4L, 0x9.d1177d54049414p-4L, 0x1.bddecac7f2edd0d6p+0L, 0x1.bddecac7f2edd0d8p+0L }, + { 0x2.1253578fc85773e4p-4L, -0x9.c82e26cb2d7f53dp-4L, -0x1.5cb2d32b7dd67718p+0L, -0x1.5cb2d32b7dd67716p+0L }, + { 0xf.27497e66d5603e2p-52L, -0x1.106fbe1bb8bb675p-4L, -0x1.921fb54442c3472cp+0L, -0x1.921fb54442c3472ap+0L }, + { -0x2.834fa5093bae17c8p-4L, -0x4.be621d3bea89ab38p+64L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x8.b87762725b3d25ep-4L, -0xb.917c5b4d5562a58p-96L, -0x1.53990086a1a7d33ep-92L, -0x1.53990086a1a7d33cp-92L }, + { 0x1.232c19a7b93aed74p-4L, 0x6.c11fd7b2f21ba82p+84L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x6.ca169f967701482p-4L, 0x3.959fe15d515a94ap-20L, 0x8.727c2adf96323fcp-20L, 0x8.727c2adf96323fdp-20L }, + { 0xb.d05c1485606d27ep-4L, 0x5.4c9a1c93895dca38p-6076L, 0x7.2d4b9799a5cc26c8p-6076L, 0x7.2d4b9799a5cc26dp-6076L }, + { -0xa.aa5f16e89aaf44cp-8L, 0x1.a020e5ecd83f5f0ap+92L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x9.4873bc564770dcap-4L, 0x9.a30d5a20e7f065cp-4L, 0x2.5665d2a4b1ec940cp+0L, 0x2.5665d2a4b1ec941p+0L }, + { 0x8.fb1811913b9bf9fp-4L, -0xf.92fca557186ff76p-4L, -0x1.0c3797d9ba60eabap+0L, -0x1.0c3797d9ba60eab8p+0L }, + { 0x1.5638b03330502364p+5720L, 0xc.61775f4969ec8fep-4L, 0x9.42ee4d5147e88c7p-5724L, 0x9.42ee4d5147e88c8p-5724L }, + { 0x1.72119aad9ca3b71ep-4L, 0xe.a69471f34698825p-4L, 0x1.78f2269fea0fe2bcp+0L, 0x1.78f2269fea0fe2bep+0L }, + { 0x4.012c7e08cbaa9478p-4L, 0x9.7bae07b48f3d186p-8L, 0x2.59db176e78ca1928p-4L, 0x2.59db176e78ca192cp-4L }, + { 0x6.fd5607efb3f922bp-4L, 0xa.5d0e52cf5ec81ep-4L, 0xf.a38cbd712f445c9p-4L, 0xf.a38cbd712f445cap-4L }, + { -0xb.3d5a0ceef37dac4p-4L, 0xa.7bf3bd59441655fp-4L, 0x2.6415b8938c9c69f8p+0L, 0x2.6415b8938c9c69fcp+0L }, + { 0xa.9cecb0eb313d3bp-4L, 0x1.34e865521b1a17b6p+92L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x6.d2e474b6031561b8p+92L, -0xa.5245ba426d8cb8dp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x3.d8775bbd6cd0492cp-4L, -0x4.e24c77188e4a7c38p-4L, -0x2.3ce04e2b601eabdcp+0L, -0x2.3ce04e2b601eabd8p+0L }, + { -0x2.208fc355984ce044p-4L, -0x5.bdde15084dbc54b8p-4L, -0x1.ecf436be968f6d2ap+0L, -0x1.ecf436be968f6d28p+0L }, + { 0xc.43cdb6d485f521ep-4L, 0x6.87c475984cf17fd8p+4L, 0x1.903eea125ad80b1ap+0L, 0x1.903eea125ad80b1cp+0L }, + { -0x4.dd382677670dd278p+0L, 0x2.a23ea828ab9892c8p-4L, 0x3.1b966a3063100448p+0L, 0x3.1b966a306310044cp+0L }, + { -0x3.8b954314786b23ap-136L, -0xa.9d6c0aac945f352p-8L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xd.2671cf0537f0221p+8056L, -0x4.d16dd659f3c0f0ap-4L, -0x5.dcbaf59e460c343p-8064L, -0x5.dcbaf59e460c3428p-8064L }, + { -0x6.feb91f876d8ea878p-4L, -0x8.81efd63e6be1cf2p-4L, -0x2.4249875056a07d8p+0L, -0x2.4249875056a07d7cp+0L }, + { 0xf.bc0fa0f885ca099p-4L, 0x5.7c08324a140957ap-4L, 0x5.5dc5ee9b879c424p-4L, 0x5.5dc5ee9b879c4248p-4L }, + { 0x4.edb009626e4967fp-4L, 0x3.37c8d44a2dd88cbp-4L, 0x9.413cc440ef46a35p-4L, 0x9.413cc440ef46a36p-4L }, + { 0x1.95eaf72aa7e08a9ep-4L, -0x8.1b7b5887913ebf5p-4L, -0x1.60ae1adef48fda1p+0L, -0x1.60ae1adef48fda0ep+0L }, + { -0xb.5359194b44145bbp-4L, -0x6.04e85f85770e42f8p+16L, -0x1.921fd35f3b27f2f2p+0L, -0x1.921fd35f3b27f2fp+0L }, + { -0xb.4501e0be159d16ap-4L, -0x1.fac44e7ef22a75e2p-8244L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x5.4c01faa961b17b48p-4L, -0x7.06bc16cdb0784c5p-4L, -0x2.377e1cc99262c594p+0L, -0x2.377e1cc99262c59p+0L }, + { -0xe.d9260d8b3735c8cp-4L, -0x8.ca13ee6d024020bp-4L, -0x2.9b6bee6c5172a15cp+0L, -0x2.9b6bee6c5172a158p+0L }, + { 0xe.1b10c6cf509583p-4L, 0xc.ce2bca2cbcab86p-4L, 0xb.cb38da4c1afe696p-4L, 0xb.cb38da4c1afe697p-4L }, + { -0x3.9a147b2294cce81cp+9392L, 0x8.35964c3a9d13241p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x7.2dae4682b4686c98p-4L, 0xa.762ab4fc1d5ab9bp-4L, 0xf.82b60dca04dac5ap-4L, 0xf.82b60dca04dac5bp-4L }, + { 0x1.c7999bbe18984522p+7836L, -0x5.73257b4e6064d01p-4L, -0x3.0fed7d28e284ea74p-7840L, -0x3.0fed7d28e284ea7p-7840L }, + { 0x3.8c2ba3fe7042d388p-116L, 0x7.d5dc9701e1e187bp+124L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xc.68e5a8454d59578p-4L, 0x7.1fd64b9a5df38ef8p-4L, 0x8.56a48c286152098p-4L, 0x8.56a48c286152099p-4L }, + { -0x4.881b83c2dca08bfp-116L, 0xa.91f8d787af80328p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xd.d1efe43682ae912p-4L, -0x3.528a6db95c7dfd34p-4L, -0x3.c65d2785eeb5cedp-4L, -0x3.c65d2785eeb5ceccp-4L }, + { -0x2.5775a364301f7598p+4216L, -0x5.c36184a826a997c8p-2260L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x3.7d2d5d25047b7ecp-128L, -0x7.fb0b49661b4b20b8p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x7.15fab912af52fa78p-84L, 0x1.8a9bf648a0c7536ap+136L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x1.e21c9844f30c3324p-44L, -0xa.36231bab07402b6p-8L, -0x1.921fb54445c4ebd4p+0L, -0x1.921fb54445c4ebd2p+0L }, + { -0x9.d3efb895e20c043p-4L, 0x6.44c77e7837d61e48p-4L, 0x2.92e529b4f918d0dp+0L, 0x2.92e529b4f918d0d4p+0L }, + { 0x1.b7e2cb7d51c65e38p-4L, -0x9.ab90feeee0a43a6p-4L, -0x1.651ad72533e8b13p+0L, -0x1.651ad72533e8b12ep+0L }, + { -0x1.705075c296c945a2p+8148L, -0xd.8fb34ea26dcd466p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x4.3b9909e92aa74c08p-4L, -0x5.5c31877c53bcf0bp-160L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x2.ab275d4d45f58b1p+40L, -0xd.f1e17f7d11f6ef4p-4L, -0x3.243f6a88854f6cdp+0L, -0x3.243f6a88854f6cccp+0L }, + { 0x8.5d50acd960ea87ap-4L, -0x3.cdaf1e5edd4c86p+48L, -0x1.921fb54442d1613ap+0L, -0x1.921fb54442d16138p+0L }, + { 0x7.1c63b6c0603b465p-4L, -0x5.06c95cd2eef04c08p+7836L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xd.4ef26051ededf26p-4L, -0x1.e5ffb4e52e88dbbp-60L, -0x3.243f6a8885a308bp+0L, -0x3.243f6a8885a308acp+0L }, + { -0x3.7a1dacb5eeed287p-4L, -0x2.75255c967504f764p-4L, -0x2.86bc274ba5844bep+0L, -0x2.86bc274ba5844bdcp+0L }, + { 0x9.43cd9e2120286b3p-4L, 0x1.1f40e2b07af92cdap-144L, 0x1.f012f92279311758p-144L, 0x1.f012f9227931175ap-144L }, + { 0xe.e44b7be402e1d81p-4L, 0x2.19395d52c4ffbbep-140L, 0x2.413416ce00a833e4p-140L, 0x2.413416ce00a833e8p-140L }, + { -0xf.099c3c9b804cd09p-8L, 0x6.c417103ca3c8b37p+384L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x1.8768dd184e3fbefcp+264L, 0x9.4f4b6e56944c6fep-4L, 0x6.16c8f28c7cc0ba38p-268L, 0x6.16c8f28c7cc0ba4p-268L }, + { -0xa.9b8d5570d3354bfp-4L, -0x3.44d2e445d54ef838p-4L, -0x2.d7b9029e74d35b4p+0L, -0x2.d7b9029e74d35b3cp+0L }, + { 0x8.d490d42bb07e2c7p-4L, 0x6.1bb3f5bd906ea9d8p-4L, 0x9.aeb69331ab83233p-4L, 0x9.aeb69331ab83234p-4L }, + { -0xb.d1da672fb0a4a6cp-4L, -0x3.cd44320f7cb17634p-4L, -0x2.d494aaaf940ef35cp+0L, -0x2.d494aaaf940ef358p+0L }, + { -0xe.e798701cb00ba65p-4L, 0x6.188c517655d962b8p-4L, 0x2.c0dc1cb781eb0c04p+0L, 0x2.c0dc1cb781eb0c08p+0L }, + { -0x5.a44cc952f2f84af8p-4L, -0x7.3f72b7eca34409f8p-2908L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x1.99cd1db7dfc4219ep-8264L, 0x8.4553ceee4227da5p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x3.a5fcc10d81eb5f18p+120L, -0x1.43edbd1c91c01de4p+112L, -0x5.8c967b142642a9f8p-12L, -0x5.8c967b142642a9fp-12L }, + { 0x1.5e17b3337849e126p-4L, 0xc.21be7e1f393f14fp-4L, 0x1.75634482719a6aa6p+0L, 0x1.75634482719a6aa8p+0L }, + { 0x4.4c7fdb3702f28548p-8L, 0xa.75cd63ad7a1fc3cp-4L, 0x1.8b8cbd8921671fd6p+0L, 0x1.8b8cbd8921671fd8p+0L }, + { 0xe.8b29d8cde8987f8p-4L, 0xd.887cf89ee3f6121p-4L, 0xb.fda4e7230ad4398p-4L, 0xb.fda4e7230ad4399p-4L }, + { -0x4.94c6afdd6c82228p-4L, -0x1.05fda0e408aa74dap-4L, -0x2.ebfb96a3f9a42878p+0L, -0x2.ebfb96a3f9a42874p+0L }, + { 0xa.3670397a0014cd8p-4L, 0x3.a35da38274ac5cap-4L, 0x5.79be30299d3f009p-4L, 0x5.79be30299d3f0098p-4L }, + { -0x1.6e3230adc36fa2d4p+72L, 0x2.46b281598ef2f5a8p+68L, 0x3.0adf2743dfff3e94p+0L, 0x3.0adf2743dfff3e98p+0L }, + { 0x2.60029db4ae9896f4p-4L, 0x9.b40053c694dc073p-4L, 0x1.54abbdf7c77fd402p+0L, 0x1.54abbdf7c77fd404p+0L }, + { 0x2.b4e66bc066d0d2dp-4L, -0x5.4231e76df18908fp-4L, -0x1.186f69ed098e7cbcp+0L, -0x1.186f69ed098e7cbap+0L }, + { 0x1.b1a6f7bbb2a87d3ap+4L, 0x2.811588b8fd1e13dcp-4L, 0x1.7a73376fe2e0dffcp-8L, 0x1.7a73376fe2e0dffep-8L }, + { 0x9.818682634b4f569p+48L, -0xd.948c0f98202cba9p-4L, -0x1.6db912400d2d0042p-52L, -0x1.6db912400d2d004p-52L }, + { 0x5.c78c1527fbed2cb8p-132L, 0xf.4d427c83cc48947p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x5.9703943df8daac68p-4L, 0xb.e333189d0552193p+108L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xd.9f9ad2fbb7114c8p-8L, 0x7.30036483bed4a05p-12L, 0x3.1bcf3458f84318fcp+0L, 0x3.1bcf3458f84319p+0L }, + { 0x2.a5a39f32557c8ep-4L, -0x3.170c659960195678p-4L, -0xd.cca65d3fe500765p-4L, -0xd.cca65d3fe500764p-4L }, + { 0x2.82da0a654e4b095cp-4L, 0x6.cf128f250e94a368p-4L, 0x1.37ac0c52f9b10dd8p+0L, 0x1.37ac0c52f9b10ddap+0L }, + { 0xd.76c3b09c76ff3e9p-4L, 0x9.07955929333661ap+116L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x5.81cb354b63bfe2p-60L, -0x1.87e903d0c3db82e4p+4L, -0x1.921fb54442d18466p+0L, -0x1.921fb54442d18464p+0L }, + { -0xa.2353060706c5cabp-4L, 0x1.fb0b63a1a1d40916p-11204L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0xd.5b6d7ec2493a866p-4L, 0xb.feeccb085d9a77fp-4L, 0x2.68eb2ca1b4fe66ccp+0L, 0x2.68eb2ca1b4fe66dp+0L }, + { 0xd.8290d23d319cf46p-4L, 0x7.8f36bd86059e0dp+60L, 0x1.921fb54442d18466p+0L, 0x1.921fb54442d18468p+0L }, + { 0x9.228ffe9d2dbc7a8p-4L, 0x3.4d0b2cb006ec1248p-76L, 0x5.c818c6860b871adp-76L, 0x5.c818c6860b871ad8p-76L }, + { 0x5.d6213cf1fe6c0418p-4L, 0x1.4fb6400683507e4p-108L, 0x3.9851a6b04169056cp-108L, 0x3.9851a6b04169057p-108L }, + { 0x1.2e57c4035227f4a4p-4L, 0x3.8b63b08dc84596bcp-44L, 0x3.004e3b1435fcb234p-40L, 0x3.004e3b1435fcb238p-40L }, + { -0x1.4360cd0166c1bb96p-96L, 0x5.6b1f6c08a8c74bd8p-48L, 0x1.921fb54442d1c016p+0L, 0x1.921fb54442d1c018p+0L }, + { 0xa.16180a40d8df5dap+5656L, -0x1.0b5029b46f526448p-4L, -0x1.a80a966ff0d212dcp-5664L, -0x1.a80a966ff0d212dap-5664L }, + { 0xf.cc3eef919eef062p-84L, 0x1.a712ef62b430fa34p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x5.f94934066073bd08p-4L, 0x6.09560f5c4171de98p-4L, 0xc.a65f6b1a7f95643p-4L, 0xc.a65f6b1a7f95644p-4L }, + { 0x7.901026e26c2bf698p-4L, -0xe.7c231718ee90eb4p-4660L, -0x1.ea50f230ad14fcbap-4656L, -0x1.ea50f230ad14fcb8p-4656L }, + { -0x3.6877a67287c33a24p-148L, -0xb.ccb04bd726e2f1cp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xe.92b733496bc40efp+104L, 0x3.7e80673dfbabc99p+104L, 0x2.e80131ce1300ed4cp+0L, 0x2.e80131ce1300ed5p+0L }, + { 0x2.f8fd52cb8aa2f7cp-24L, 0xd.8eb4579dad84402p-4L, 0x1.921fb1c22b2c5adap+0L, 0x1.921fb1c22b2c5adcp+0L }, + { -0x5.5efd70abd2079fd8p-4L, 0x5.f015b527caae88c8p-4L, 0x2.4e5dc999616481bcp+0L, 0x2.4e5dc999616481cp+0L }, + { 0xc.5b36895077a659cp-4L, -0xe.6156c69bf7850ffp+68L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xc.41d507fb40798b9p-4L, 0x6.044acf83853e4228p-4L, 0x2.af6dd05f6ba7bd54p+0L, 0x2.af6dd05f6ba7bd58p+0L }, + { 0xd.b86c5707774a4a2p-4L, 0x7.eedd2b5801d30ddp-4L, 0x8.6340d5849f75649p-4L, 0x8.6340d5849f7564ap-4L }, + { -0x6.f6e101329750c02p+0L, -0x7.d6f975423ed1769p-4L, -0x3.124429a16a9c980cp+0L, -0x3.124429a16a9c9808p+0L }, + { -0x3.be6d312c65754ef8p-80L, 0xb.cb682f76a3f814p-60L, 0x1.921fba586c06424p+0L, 0x1.921fba586c064242p+0L }, + { 0x1.8221ab8a45beb70ap-4L, -0x3.b4684654db9a5424p+140L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x9.2d8b2c3da2a1544p-4L, 0x5.24f70f7b34e69378p-4L, 0x2.a17623dc05226ce8p+0L, 0x2.a17623dc05226cecp+0L }, + { 0x8.691578498705b78p+80L, 0xb.3bee0e72b609f1bp-4L, 0x1.55f2221d830f232ap-84L, 0x1.55f2221d830f232cp-84L }, + { -0xc.da6a20364262f65p-4L, 0x2.4877b265ab1f3a8p-13304L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x4.405714e489cdecc8p-8L, -0xc.15f1a93e28bcd0ep-4L, -0x1.97c04dd68088ca78p+0L, -0x1.97c04dd68088ca76p+0L }, + { -0xb.073911421d09748p-4L, -0x1.b5c0a4dd8c1566fcp-4L, -0x2.fcde10ab4dd76134p+0L, -0x2.fcde10ab4dd7613p+0L }, + { 0xe.d559a68601d334ep-4L, 0x2.d0d0da1fed32adecp-4L, 0x3.005d3f535fcec9ecp-4L, 0x3.005d3f535fcec9fp-4L }, + { 0xc.eb3db51a4117749p-4L, -0xe.a7ff95de9e6b04bp+32L, -0x1.921fb54434b70d58p+0L, -0x1.921fb54434b70d56p+0L }, + { -0x9.b242f08632fe79dp-4L, 0xf.7392589b824fb9dp-4L, 0x2.21976ce06de5b27cp+0L, 0x2.21976ce06de5b28p+0L }, + { -0x3.866d6f28fe022bf8p-4L, -0xf.6920f8295b7bddcp-4L, -0x1.cbb12c5cf3020402p+0L, -0x1.cbb12c5cf30204p+0L }, + { -0xd.371b90dc936973ap+1584L, -0x2.03fc72188444e274p+1388L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0xc.8841513e4940958p-8L, 0xf.dacd69f337492f8p-4L, 0x1.9ec2bc5751b6109ep+0L, 0x1.9ec2bc5751b610ap+0L }, + { -0x2.1b6b60da18fb188p+56L, -0x1.375db6599b3290d6p-144L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x8.4bc36bd85a13605p-4L, 0x7.511fbab815148398p-4L, 0x2.6b37dcb798ecddc8p+0L, 0x2.6b37dcb798ecddccp+0L }, + { -0x1.226db2320a4bbd76p-4L, 0xe.9620cf5661a993ap-4L, 0x1.a5fea59ad16975acp+0L, 0x1.a5fea59ad16975aep+0L }, + { -0xe.9dcdafd35f490bep-4L, 0xf.47291cfe1ffaef4p-4L, 0x2.558583302f17d3ccp+0L, 0x2.558583302f17d3dp+0L }, + { 0x3.73491a68bdddaaccp+144L, 0x8.aa229058b7ec91ap-4L, 0x2.82e01ab54a6a64ep-148L, 0x2.82e01ab54a6a64e4p-148L }, + { 0x4.ad7c3e0240e17358p-4L, 0xe.3ba47f6dc65238dp-4L, 0x1.40d60ca76f3b16bcp+0L, 0x1.40d60ca76f3b16bep+0L }, + { 0x3.392a62c6b703c4ecp-4L, -0xa.05c344dc8437ce9p-4L, -0x1.427790ebd5ffa4dap+0L, -0x1.427790ebd5ffa4d8p+0L }, + { -0x4.cfc2d12040fe801p-4L, 0x5.008114fbefa3ff4p+6792L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x6.430b313e463247bp-4L, 0x8.e2b7001bf08e40cp-140L, 0x1.6b43699da53b302ap-136L, 0x1.6b43699da53b302cp-136L }, + { 0x1.85dde85b05b8945p-4L, -0x2.f667e823e60719c4p-4L, -0x1.18910e0e7794c9bep+0L, -0x1.18910e0e7794c9bcp+0L }, + { 0x3.6dcf06d4e2c69044p-4L, -0x3.216851a5299104fp-4L, -0xb.d6c24b0a25b1c6dp-4L, -0xb.d6c24b0a25b1c6cp-4L }, + { 0x6.f6bb9a4c17f8e4c8p-4L, -0xf.d713d37adb465cp-4L, -0x1.2816ea59da6ddadep+0L, -0x1.2816ea59da6ddadcp+0L }, + { 0x1.0313a7bf52f62c6ap+12220L, -0x5.4b92638de9222f68p-4L, -0x5.3b792079fc7b5658p-12224L, -0x5.3b792079fc7b565p-12224L }, + { -0x5.07a5e167ee5ee938p-4L, 0xa.fe50b439a96ea55p-32L, 0x3.243f6a658d516568p+0L, 0x3.243f6a658d51656cp+0L }, + { 0x7.4d40bb5519f17438p-4L, 0x6.57ce3bc088dbf5bp-4L, 0xb.71a620269adc806p-4L, 0xb.71a620269adc807p-4L }, + { -0xb.344b56eb02935aap-4L, -0x2.aa06a7b698b0b3e4p-4L, -0x2.e87c4fa4fad0ed48p+0L, -0x2.e87c4fa4fad0ed44p+0L }, + { -0x7.d11224fd32351718p-4L, 0x3.7e5a21b23d5c1b64p-20L, 0x3.243ef81e138f1854p+0L, 0x3.243ef81e138f1858p+0L }, + { -0xf.a08ab502ee0f01p+144L, 0x6.cf1c3e55412fd6cp-128L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x6.48717c11cd853a38p+12L, -0xd.f459b71bee5f0a9p-4L, -0x3.243d31f5270113d8p+0L, -0x3.243d31f5270113d4p+0L }, + { -0x2.ae45f1d99d8191ap-4L, -0x1.6d0da510a3e13b48p+72L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x1.4f51a9b3e2d85878p-36L, -0x8.0b439abc08ea7e9p-4L, -0x1.921fb544192200cep+0L, -0x1.921fb544192200ccp+0L }, + { 0xe.7c272173ede747dp-8L, 0x2.2303df6a957df77cp+128L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xd.078697a133ad5cep-4L, 0xe.dbf635b5992761bp-4L, 0xd.9d5a5adb9750ca4p-4L, 0xd.9d5a5adb9750ca5p-4L }, + { 0xe.1ec636774861dd1p-4L, 0x6.90fde6638ef190ap-4L, 0x6.f6edca5da7e976ep-4L, 0x6.f6edca5da7e976e8p-4L }, + { 0x9.2892f7ae1a4dc1cp-4L, 0x9.59de5e82fe42ee3p-8L, 0x1.05074845332e8fbp-4L, 0x1.05074845332e8fb2p-4L }, + { 0xa.0bd8e2fed33d2fbp+48L, 0x7.1e8449954445192p-4L, 0xb.56981838fbcdfb4p-56L, 0xb.56981838fbcdfb5p-56L }, + { 0x6.9391bf7167786018p-88L, -0x5.ee980a26e834c06p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xb.c8e75dd8cc31c5fp+4172L, -0xa.56e2685bfa417eep+140L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x1.24a1e06c9ce90bacp+12L, 0x3.a60249453e7b9ccp-96L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x2.c8627289ae027344p-88L, -0x6.9b634305e9253b2p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x1.373f26e92bcb57d2p-144L, -0x2.e1e1c6f6c78bd3c4p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x9.70dc7ea202b3d6ep-4L, 0x1.a18f74fd6269755cp-4L, 0x2.f87376c50bbbb78p+0L, 0x2.f87376c50bbbb784p+0L }, + { -0x5.70d6e285f6741be8p-4L, 0x3.ba6b718acd54f7f8p-8L, 0x3.194a6a535ac8d614p+0L, 0x3.194a6a535ac8d618p+0L }, + { 0x2.6d98cc2767fd89d8p-4L, 0xc.808b2b8f5b868bp-4L, 0x1.610412f8c9e8121ap+0L, 0x1.610412f8c9e8121cp+0L }, + { 0xf.2e99194f7ef31f7p-4L, -0x2.e9a1c1b2321b87a4p-4L, -0x3.085f31e10671090cp-4L, -0x3.085f31e106710908p-4L }, + { -0x3.924e6e858ddf4824p-4L, 0x2.9a401dba30d7dcep+10456L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x6.5f0b8c236d8dc8f8p-2672L, -0x2.c8e3c20a2013488p+2656L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xd.d75e9619a100a7fp-8L, -0x4.91095f75c24e73a8p+12L, -0x1.921fe5c34e2b3f08p+0L, -0x1.921fe5c34e2b3f06p+0L }, + { 0xa.b860bc07bcd9d43p-4L, -0x1.5cffc658f2525a68p+32L, -0x1.921fb543c5005914p+0L, -0x1.921fb543c5005912p+0L }, + { 0x2.39efe79c36d491e8p-8L, -0xc.844c97b8d649ddcp-4L, -0x1.8f4732858a9cdac8p+0L, -0x1.8f4732858a9cdac6p+0L }, + { -0x3.bc36c1490d0a008cp-4L, 0x3.7373aa65594e9ba4p+28L, 0x1.921fb54557e72276p+0L, 0x1.921fb54557e72278p+0L }, + { 0x1.e030a1263fac45b6p-4L, 0x4.6a742a7f7f068b1p-4L, 0x1.2b4b21e62728d41cp+0L, 0x1.2b4b21e62728d41ep+0L }, + { 0x1.abcbe4707103d132p-36L, 0x2.63828893421a22a8p-4L, 0x1.921fb5438fba3b7ap+0L, 0x1.921fb5438fba3b7cp+0L }, + { 0xe.fa45bfa0e35be11p-4L, -0x2.6aa2a2cda06315ep-68L, -0x2.94dd051d34d86718p-68L, -0x2.94dd051d34d86714p-68L }, + { -0x5.033b46cdbeb340cp+16L, 0x3.8a8a6bba3cfe8078p-8L, 0x3.243f69d3aba38a3cp+0L, 0x3.243f69d3aba38a4p+0L }, + { -0x6.c85e2b71c3374258p-4L, -0x5.27a1297f363c8d48p-4L, -0x2.7de1bf0aef3c59b8p+0L, -0x2.7de1bf0aef3c59b4p+0L }, + { -0xd.3df3c95e345f91cp-4L, -0x2.d4dacdbb7574d32p-4L, -0x2.ee521baede0beaa8p+0L, -0x2.ee521baede0beaa4p+0L }, + { 0x3.e0f12593c01b4688p-4L, 0xf.2f0dd139a8e6154p-68L, 0x3.ea28b93c20ccdc1p-64L, 0x3.ea28b93c20ccdc14p-64L }, + { -0x7.0a9be4dfe4012efp-4L, -0x9.79c050222c1c028p-4L, -0x2.35ba688648eae5b8p+0L, -0x2.35ba688648eae5b4p+0L }, + { 0xe.69fc312b6c20148p-4L, -0xa.7ae82870e738fcdp-8L, -0xb.a0105da162b779dp-8L, -0xb.a0105da162b779cp-8L }, + { 0x1.9c08b5ae28dcf1ep-4L, 0x8.966bd426c329fd3p-4L, 0x1.62b1a3a4abfa30dap+0L, 0x1.62b1a3a4abfa30dcp+0L }, + { -0x9.7e7da70cdfaf86fp-4L, 0x5.9e39f65bc056fafp-4L, 0x2.9b75d071d8859284p+0L, 0x2.9b75d071d8859288p+0L }, + { -0x3.10308c990392d81p-4L, 0x7.5314fd852999079p-8236L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x5.2778b767dd6e12ap-4L, 0x6.8c1f80f76611751p-4L, 0x2.3cd97d6e9dd74d8cp+0L, 0x2.3cd97d6e9dd74d9p+0L }, + { -0x1.11d59a15316df40ep-88L, 0x1.b17a45abfaca7818p+84L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x8.4fc3ad0329a03fbp-24L, -0x7.730ab999d45ba668p+36L, -0x1.921fb54442d1847cp+0L, -0x1.921fb54442d1847ap+0L }, + { 0xf.4ddfc0a6a7ff926p-4L, 0xc.a51ad22241bf9a4p-3400L, 0xd.3847934faa3ce58p-3400L, 0xd.3847934faa3ce59p-3400L }, + { -0x3.749a4e30ff80721p+132L, 0x8.653a7b58a965687p-8L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x6.0147c8355dcb5118p-4L, 0xa.bbdd8af3b148586p-4L, 0x2.14b363e8be093404p+0L, 0x2.14b363e8be093408p+0L }, + { 0x9.b485a2016e89ac8p-4L, -0x6.c0577b0cfdc16538p-4L, -0x9.b9887f0bf97893p-4L, -0x9.b9887f0bf97892fp-4L }, + { 0x1.f3982a7709f0cbp+40L, 0xf.70ce68e262f1e86p-4L, 0x7.e97ada86bdfd66a8p-44L, 0x7.e97ada86bdfd66bp-44L }, + { 0xa.00f17ea146af72cp-4L, 0xd.87fd71f7ada2ddap-4L, 0xe.f2621401a87f5aap-4L, 0xe.f2621401a87f5abp-4L }, + { 0xf.8d6956f54124902p-4L, -0x3.c7f4fe11df2d42d8p+104L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xe.dc1b8debe374cf4p+116L, -0xc.0eeac80f65e8216p-4L, -0xc.fbc762d00c60c7ap-124L, -0xc.fbc762d00c60c79p-124L }, + { -0xf.b4cea5f9045b01ap-4L, 0x1.0c2e698750b7e94cp-96L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0x8.d79e88a664c070ap-4L, -0xf.9450f9ab4f8d17p-4L, -0x2.1647280289f2978cp+0L, -0x2.1647280289f29788p+0L }, + { -0x6.eebd8fca95c9ca4p-8L, -0x2.7d3fe1c0d9eb617cp-4L, -0x1.be3dea5c2a040718p+0L, -0x1.be3dea5c2a040716p+0L }, + { -0x3.afe78e9efcbac40cp+140L, -0x1.68e1081fbf7d13e6p+1008L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x7.c520bfdab8a3eep-4L, -0x1.66b5c099afee3a44p-4L, -0x2.dacc8235e43513fp-4L, -0x2.dacc8235e43513ecp-4L }, + { 0x1.e4933a2a2ddf904p+136L, 0xd.784941952fe4cecp-4L, 0x7.1db8e5d213caf838p-140L, 0x7.1db8e5d213caf84p-140L }, + { 0x4.3c17087b908950fp+7148L, -0x3.735c047b159adcccp-4L, -0xd.099540663e33b06p-7156L, -0xd.099540663e33b05p-7156L }, + { 0xc.281ad4f7e7b2506p-4L, 0xd.32303b9dcb960d7p-4L, 0xd.38d23e57b79989p-4L, 0xd.38d23e57b799891p-4L }, + { 0x7.8695060ae1f9a64p-4L, -0x2.3be9aa14143c731cp+104L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x7.62db900b9f9d9668p-4L, -0x6.cfd1fde0bfa23d8p-4L, -0xb.eb61a702cf9e3e1p-4L, -0xb.eb61a702cf9e3ep-4L }, + { -0xf.bb4bad527dbb40ep-4L, -0x5.3e9ef2b10884ee28p-10036L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x9.5778bac96c5960dp-4L, -0x1.178465778778ce2ep+14336L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x8.7ef9939b4465e16p-4L, -0x3.51600c72922bbfc4p-4L, -0x5.f4fa36d23aa5506p-4L, -0x5.f4fa36d23aa55058p-4L }, + { 0x2.5131dd015a69e96cp-2408L, 0xa.870e0a37a4eeddcp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x2.880d15d9bf79a448p-4L, 0x2.446fd3d9665e1568p-4L, 0xb.afc7a6c62bd905fp-4L, 0xb.afc7a6c62bd906p-4L }, + { -0x2.31a4e2380b4c16cp-4L, -0x7.645911f7f5f4b208p-4L, -0x1.dbfbe65a7e307902p+0L, -0x1.dbfbe65a7e3079p+0L }, + { 0xb.2103d74317cc086p-4L, 0xf.771337e878bf499p-4L, 0xf.2704bf58b4bb6a8p-4L, 0xf.2704bf58b4bb6a9p-4L }, + { 0xe.861c26d80ccd5dfp-4L, -0x1.3d69ace2aa20b076p-36L, -0x1.5dac4c2bc3e57078p-36L, -0x1.5dac4c2bc3e57076p-36L }, + { -0x2.aff893fd182e92bp-152L, 0x4.141b510c6c3a2c78p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x8.56bda974ea2dec7p-4L, 0xa.7ba4137b5209863p-4L, 0x2.3e25e1fea85cbe24p+0L, 0x2.3e25e1fea85cbe28p+0L }, + { -0x6.80d745f6314c29dp-4L, 0x1.7c7e424cf77b8afep-76L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x6.cced41d6279d2138p-4L, 0x1.c0e570d143bef0eep-4L, 0x4.09a27a95df0f54cp-4L, 0x4.09a27a95df0f54c8p-4L }, + { 0x6.5df497b7697155a8p+1564L, -0x3.ddba85629b3426e8p-4L, -0x9.b723fdc7b00661cp-1572L, -0x9.b723fdc7b00661bp-1572L }, + { -0x4.760b9460983c0a5p-4L, 0x4.8c8e8f6197ef9bd8p-4L, 0x2.58aff93ef60ec054p+0L, 0x2.58aff93ef60ec058p+0L }, + { -0xd.529973ed01b4e92p-132L, -0x3.6712c0d838d018e8p-68L, -0x1.921fb54442d1846ep+0L, -0x1.921fb54442d1846cp+0L }, + { 0xc.1f8b7a784c26504p-4L, -0xa.67183c5cde7a566p-4L, -0xb.58bfac992b804b5p-4L, -0xb.58bfac992b804b4p-4L }, + { -0x6.19f5de19ed7257a8p-4L, -0x7.3398eb375f75dfb8p-4L, -0x2.46101795deb7d9d8p+0L, -0x2.46101795deb7d9d4p+0L }, + { -0x7.36616a1fa5db84fp-4L, 0xa.2ee450fb24733e3p-4L, 0x2.2fe288a6338d798p+0L, 0x2.2fe288a6338d7984p+0L }, + { -0x4.438c4fc90d39b8ep+96L, -0x7.4f02a205338a33ap-64L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x2.c8f196a2f3e8ed9cp-9224L, -0x3.03786e351e5ebe78p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xf.2253cc715933c65p-8L, 0x5.6a7fda73f84b1c18p-4L, 0x1.65dc717427bbf3f2p+0L, 0x1.65dc717427bbf3f4p+0L }, + { -0x2.a28f500b8a00b09p+14092L, -0x1.0843d15dc3b8cafp-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0xd.fca2fa696c2274ap-4L, -0x4.0718db0d5c58c15p-4L, -0x2.dc787f077ff8e63p+0L, -0x2.dc787f077ff8e62cp+0L }, + { 0x3.9a1be41771a60404p-4L, 0x1.80953538294166f8p-12L, 0x6.ac4fe9d96a3bf4f8p-12L, 0x6.ac4fe9d96a3bf5p-12L }, + { -0xb.7124296f93e8defp-4L, -0x1.98246e4efb47458ap-4L, -0x3.00ce24c21911792p+0L, -0x3.00ce24c21911791cp+0L }, + { 0xb.839f5cfd4cd5f2cp+8436L, 0xa.61c8331ffa99071p-4L, 0xe.6d3d4051b118d3p-8444L, 0xe.6d3d4051b118d31p-8444L }, + { -0x1.6b1b156ea818eb8p-4L, 0xf.d7c5e11a00df0a5p-4L, 0x1.a8fb6c440c3be30cp+0L, 0x1.a8fb6c440c3be30ep+0L }, + { 0x8.598d995551324f1p-4L, 0xd.e18c0d942a69d5bp-4L, 0x1.077d42bee50504fcp+0L, 0x1.077d42bee50504fep+0L }, + { 0x6.93e866ab2447886p-4L, -0x2.26e07207dc8de1ep-4L, -0x5.0f06179f8f3a16fp-4L, -0x5.0f06179f8f3a16e8p-4L }, + { -0xf.1ce9f7b3ca52b8bp-4L, -0x1.399c88aa8d8d6c48p-4L, -0x3.0f8ab40146b6b5f8p+0L, -0x3.0f8ab40146b6b5f4p+0L }, + { -0xe.ff04c61a0a89012p-4L, -0x6.cb47f83a640007dp-9320L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x4.593edb241f803048p-4L, -0x9.cafddfe1d9bc214p-4L, -0x1.fd1b36f82d14fef4p+0L, -0x1.fd1b36f82d14fef2p+0L }, + { -0x3.0d234ad1e46298a4p+1408L, -0xd.cb179b353f53154p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0xe.9bb1c73063ea02dp-4L, 0xd.8a2175b78a11721p-4L, 0x2.64e664936b63d554p+0L, 0x2.64e664936b63d558p+0L }, + { 0xc.25bdb8a9a8881b7p-4L, -0xc.89a9a53dd5661b4p-4L, -0xc.d1c03a780665391p-4L, -0xc.d1c03a78066539p-4L }, + { 0x2.977deccc5900dccp-84L, -0x2.a3636c60ad9b8408p-112L, -0x1.04971135aba73bc2p-28L, -0x1.04971135aba73bcp-28L }, + { -0x1.4529afc43bd67b0ap-4L, 0xa.bf1476588a5cb83p+80L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x8.ebeb881ae8c2fcap-6420L, 0xa.e0e4170c0a4427p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x8.e91c2aa2ea5ec68p-4L, 0x2.91145ecdbb7882f4p+28L, 0x1.921fb540ca177aacp+0L, 0x1.921fb540ca177aaep+0L }, + { -0xf.08bf0e198ffe894p-4L, 0xe.9bb609912a78d12p-4L, 0x2.5edd27ca99c98c7cp+0L, 0x2.5edd27ca99c98c8p+0L }, + { 0x6.df4e4b64d005f82p-4L, -0x3.51711830c018995cp-4L, -0x7.3271f7b631f74408p-4L, -0x7.3271f7b631f744p-4L }, + { 0x3.1bc6c41d7b8d2494p-4L, 0x2.f721c1af4835bb14p-8L, 0xf.3ec38f9992dee5cp-8L, 0xf.3ec38f9992dee5dp-8L }, + { 0xf.4bf5dfe195d4e46p+7524L, 0x3.bbc0f8f07321f77cp+128L, 0x3.e7b20446a0be4ef8p-7400L, 0x3.e7b20446a0be4efcp-7400L }, + { -0xb.bb95272e0c88a4p-4L, 0x1.fe9b64501151218ep-4L, 0x2.f923d79c3f550efp+0L, 0x2.f923d79c3f550ef4p+0L }, + { 0x4.77e9fc00fb36ca1p-4L, 0xf.5b06933a4845034p-16L, 0x3.6fbc6b1f82dbb2ecp-12L, 0x3.6fbc6b1f82dbb2fp-12L }, + { 0x4.4ec472736efece7p-4L, -0x8.3f36b704651a623p-4L, -0x1.16e56e8ac8595702p+0L, -0x1.16e56e8ac85957p+0L }, + { -0x3.debb4f1fb4f3d46cp-8L, 0x8.8d8721565b330cep+120L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x3.60900980dfa6490cp-4L, 0x4.9ad46fe7dab0a5f8p+28L, 0x1.921fb544fe921c84p+0L, 0x1.921fb544fe921c86p+0L }, + { -0x5.d267f39c0a2d5c6p+120L, -0x6.94c6171c5caa9048p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x9.737b170f2734c17p-4L, 0x2.6fc63483927fd61p+7936L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x1.aac7d5cdfa18f4aap+12364L, 0xf.407ea5dcda35ceep+7392L, 0x9.261246ae706ee0fp-4972L, 0x9.261246ae706ee1p-4972L }, + { 0x5.10a6eb0bc1141b7p-4L, 0x1.68d8f3bd3c6056ecp-108L, 0x4.73e1f9d1f9e61ff8p-108L, 0x4.73e1f9d1f9e62p-108L }, + { -0xc.81e5dc89785e982p-4L, 0xf.821c92eadfd4d2p-4L, 0x2.3fde7bb67cf34c8cp+0L, 0x2.3fde7bb67cf34c9p+0L }, + { -0x9.6cc05530d550225p-4L, -0x3.ae26297bd368fc24p-4L, -0x2.c4f1bbd66d554dd4p+0L, -0x2.c4f1bbd66d554ddp+0L }, + { -0xf.7c61983cdd60da1p-4L, -0xa.9226fd0725f5548p+11124L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xa.bb09710051dcf8dp-92L, 0x1.d1dbba4f78416e6p-8L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x1.3f0ca6d40320444p-4L, -0xa.0d32575627bcf09p-12L, -0x3.1c2f68820068be54p+0L, -0x3.1c2f68820068be5p+0L }, + { 0x1.e12b6bdf6a41d318p-4L, -0x4.925b19d467927c58p-4L, -0x1.2e446699a3dada42p+0L, -0x1.2e446699a3dada4p+0L }, + { -0x3.b5a3dd14cc35d0f4p-80L, 0xf.f1a968c614d2c7bp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xf.c50d2b0b4759078p-4L, 0xf.297abc86e6d6ca4p-4L, 0xc.4087639b48a9f52p-4L, 0xc.4087639b48a9f53p-4L }, + { -0xe.08a7a2500e47733p+14336L, -0x2.2abc93e7ce82e67p-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x2.02ff48a6ae8c5d58p-4L, 0x2.44174246f08b0914p-4L, 0x2.4bfc95703b29449p+0L, 0x2.4bfc95703b294494p+0L }, + { 0xc.e44944bb412fcb9p-4L, -0xd.eb1d0c38abd1094p-4L, -0xd.2dc44265a1645cp-4L, -0xd.2dc44265a1645bfp-4L }, + { -0xf.f026fffa2c76775p+40L, -0x1.a72bc5f3fc609372p-4L, -0x3.243f6a8885a16004p+0L, -0x3.243f6a8885a16p+0L }, + { 0xb.8b25e8f233c9c46p-4L, -0x5.40149751018e5d7p-4L, -0x6.d46bc98b7c992a28p-4L, -0x6.d46bc98b7c992a2p-4L }, + { -0x5.2ce714d9965b9eb8p-4L, -0x3.d352663ddebb0c3p+2848L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x6.a8e6be614c1b8df8p-4L, 0x9.1772887aa9cf3dep-4L, 0xf.0469050950c1959p-4L, 0xf.0469050950c195ap-4L }, + { 0x2.9f08f6aee7d22224p+92L, 0xb.577c8e19d32b913p-4L, 0x4.53ae4466cb3e5e78p-96L, 0x4.53ae4466cb3e5e8p-96L }, + { -0x1.66b739c29828256ap+140L, -0xb.b90281c3323087ep-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x6.78ac8bb8ab809f28p-4L, -0x7.fbc375dd3564a3e8p+12L, -0x1.921ee5c0cd46c342p+0L, -0x1.921ee5c0cd46c34p+0L }, + { -0xf.8d21bd7dfb2bab3p-4L, -0x2.720b6221072b1ec8p+48L, -0x1.921fb54442d1ea2ap+0L, -0x1.921fb54442d1ea28p+0L }, + { -0xa.b8dbb59c7b569c8p-4L, 0x1.aeedca5050d1070cp-4L, 0x2.fc61e5dba0d3a35cp+0L, 0x2.fc61e5dba0d3a36p+0L }, + { 0x6.28b837f5eb0e965p-72L, -0x5.ebeaa439a80db7ep-76L, -0xf.5d50fec9b391b43p-8L, -0xf.5d50fec9b391b42p-8L }, + { -0xe.ddd4485dc420705p-4L, -0x1.10e4f9cc5932fd56p-10872L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x1.fb13b5cd1fc66386p-4568L, 0x5.cdd697b048eb7df8p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xc.d21e8ca674c3b8fp-8L, 0x1.7fbcd99b4b7c7f6ep-44L, 0x3.243f6a8883c423c4p+0L, 0x3.243f6a8883c423c8p+0L }, + { 0x9.4618839acbce14p-20L, 0x4.7f188b632b02a568p-4L, 0x1.921da546825dcbbap+0L, 0x1.921da546825dcbbcp+0L }, + { -0x3.bfd0635ddf97bef8p+11616L, -0xa.822efa7aeaf1e3ep-4L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x7.f80bf5f3503e7a08p-4L, -0x5.66fb0c9fd21294p-4L, -0x2.8bbc526a1520f534p+0L, -0x2.8bbc526a1520f53p+0L }, + { 0x5.8bca7ba191d1075p-4L, -0x3.e94049e7c0978424p+11256L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x7.926da2dc2eb3e0c8p-4L, 0xe.ebcfe2cc1e5917ap-4L, 0x2.0a57a10f93327888p+0L, 0x2.0a57a10f9332788cp+0L }, + { 0x9.9c87559b14bd69ep-4L, -0x3.1f5c367f6a8d3b5cp-4L, -0x5.069feaa26d81f0f8p-4L, -0x5.069feaa26d81f0fp-4L }, + { -0x1.f845d0e426ce9e3ep-92L, 0xc.f6cacd60d500638p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x1.36e65c677d6c8f6cp-8L, 0x1.d3eb9e3493db468p+72L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x9.434a0bafd4669fdp-116L, -0xc.0ab2fb511db1a65p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xa.040d4a425532027p-4L, 0xc.b3f2db4a1555938p-4L, 0x2.3d0c0848c1390774p+0L, 0x2.3d0c0848c1390778p+0L }, + { 0xf.0dd7437193656e6p-4L, -0x8.9e9261e5f0cbb96p-4L, -0x8.51ed7de5596cff5p-4L, -0x8.51ed7de5596cff4p-4L }, + { -0x5.fefa7ed009a1ad1p-4L, -0xc.d35706a15ac1dabp-4L, -0x2.02139e1fc30da4f8p+0L, -0x2.02139e1fc30da4f4p+0L }, + { -0x1.429576b6a439e36cp+8536L, -0xa.f28519810a83c71p-8L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x2.e66ff240855b11a8p-4L, 0x3.5c2fcc256af1f36cp+128L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x6.db01716e57cabb6p-4L, 0xd.c13cce87d39e616p-4L, 0x2.087db05ce82d89dp+0L, 0x2.087db05ce82d89d4p+0L }, + { -0x6.94f930f4029ebd6p-4292L, 0xc.6cd86a5a2553727p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x3.9db1698fccb05bb8p-4L, 0xf.1ca25184529230bp-4L, 0x1.55ff8e23c2cfab8p+0L, 0x1.55ff8e23c2cfab82p+0L }, + { -0x8.be66d03d7655fd6p-4L, -0x9.e5220481205cb59p+24L, -0x1.921fb552663f2e1p+0L, -0x1.921fb552663f2e0ep+0L }, + { 0x3.b723bd1111fd51acp-4L, -0x1.a4eb25964fa28b04p-8L, -0x7.142fe4a6d289e84p-8L, -0x7.142fe4a6d289e838p-8L }, + { -0xd.63ff921e325126cp-12464L, 0xf.1bc0b107e859569p+0L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x6.33fe53feb223e4f8p-4L, 0x1.8cebaea5077b3788p+24L, 0x1.921fb5844606fp+0L, 0x1.921fb5844606f002p+0L }, + { -0x5.9e2e3b14b66b70c8p-4L, 0x7.f59f3541b0d99908p-40L, 0x3.243f6a886ef7ccc4p+0L, 0x3.243f6a886ef7ccc8p+0L }, + { 0x6.f51f8676115f0248p+136L, -0x7.1da2696d46c614d8p-4L, -0x1.05d29a4a665da448p-140L, -0x1.05d29a4a665da446p-140L }, + { 0x8.0d6f53062b6d5dap-4L, -0x6.271f8f2a56b072ep-4L, -0xa.70782c23ee3d0bap-4L, -0xa.70782c23ee3d0b9p-4L }, + { -0xf.d56a354a71cc019p-7972L, 0x7.5aff86281b39de38p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xd.c44abbdbb28d90ap-4L, 0x8.4deb3d7fdbcc113p-4L, 0x8.af3d12fc8626167p-4L, 0x8.af3d12fc8626168p-4L }, + { -0xc.dd197fcdeb2df37p-1016L, 0xd.d1ae353afc701eep-24L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x7.d2c387b3911c47dp-4L, -0x1.bc0ab21990f1029p-144L, -0x3.8c2481f80c0e7ca8p-144L, -0x3.8c2481f80c0e7ca4p-144L }, + { -0x6.3cb6cb3574d1d9f8p-4L, -0x6.96d3daf1b089a66p-4L, -0x2.5429717f7e7c73bcp+0L, -0x2.5429717f7e7c73b8p+0L }, + { -0x4.39d33a8bd7344ee8p-32L, -0x3.60b3af53040b6134p+132L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x9.a8b4f46185e5f1ep-4L, 0xe.2d87496db29944bp-4L, 0xf.9060956959d726ap-4L, 0xf.9060956959d726bp-4L }, + { -0xd.667041c980fb86ap-8L, 0x8.86bc2686850d445p+44L, 0x1.921fb54442d19d8ep+0L, 0x1.921fb54442d19d9p+0L }, + { -0x4.50e215fa10553d48p+8L, -0xf.b3f92be44496d7dp+120L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xd.f212d18f02b8957p-4L, 0x1.bdfe0c435f3ecb6p-72L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x2.43e5d27672761aep-4L, 0x3.5eaa54a49a4ae46p-856L, 0x1.7cd46c8fb5f07dccp-852L, 0x1.7cd46c8fb5f07dcep-852L }, + { 0x3.abc16e9612cf3498p-4L, 0x7.181a2f454b0cdc38p-4L, 0x1.17e13b779b179daep+0L, 0x1.17e13b779b179dbp+0L }, + { -0x3.effb9151b19d3bc4p-4L, -0xd.6d8e757bfced33fp-4L, -0x1.db249c4f5ddbb53p+0L, -0x1.db249c4f5ddbb52ep+0L }, + { -0x4.1c7675db4a13c528p-8L, -0x5.916912756e511cc8p-44L, -0x3.243f6a886ff7966cp+0L, -0x3.243f6a886ff79668p+0L }, + { -0x9.ae36136241e082p-4L, -0xa.e229ff39b139c49p+36L, -0x1.921fb54443b538c4p+0L, -0x1.921fb54443b538c2p+0L }, + { -0x8.ea7441c1fcae2c9p-4L, -0x3.1ec5e57752e627dp-4L, -0x2.ce114af4e63febacp+0L, -0x2.ce114af4e63feba8p+0L }, + { 0xd.2ba2276ff04dde1p-4L, -0x1.036ccaf8131b87e4p-4L, -0x1.3a8a5ba2fe62b7f6p-4L, -0x1.3a8a5ba2fe62b7f4p-4L }, + { 0xe.8b06f66a6205032p-4L, -0xd.ae112e1be26b88dp-4L, -0xc.13c3c7343dcb262p-4L, -0xc.13c3c7343dcb261p-4L }, + { -0xd.95c2feeb327b501p-4L, -0xe.f8f263f130a717ap-4L, -0x2.4ec20c3ac11aba8p+0L, -0x2.4ec20c3ac11aba7cp+0L }, + { 0x3.f769c52f22e30058p-140L, 0x8.46e4f1b98e2ba04p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x1.e4581b83724c3aeep-7320L, -0x8.53fa90b742c3c73p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x4.9d47118131cc5d58p-4L, -0xa.e9fb23a5f0ee204p-4L, -0x1.2bb947cf278427fap+0L, -0x1.2bb947cf278427f8p+0L }, + { -0x7.cbd5551ff762f788p-4L, -0x8.c9f6a15fcc211ap-8L, -0x3.123d7d5448f77928p+0L, -0x3.123d7d5448f77924p+0L }, + { -0xe.83b3579c4b7fd68p-112L, -0xd.200e63e91fae96p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x6.957c45c90a7c23ap+96L, 0xd.ce8bdb00853c926p-4L, 0x2.18d83b8b49fb8b3cp-100L, 0x2.18d83b8b49fb8b4p-100L }, + { 0xf.0b8ed1b50e825c8p-8L, 0x6.ed7085987456212p-12700L, 0x7.5dfe047fcd4cf058p-12696L, 0x7.5dfe047fcd4cf06p-12696L }, + { -0x4.176212e7c4ecbaap-4L, -0x6.93d4b9e5fd90fb28p-124L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x6.5877ca61dc57f7b8p-4L, -0x4.d2f3a82b21bdc158p-80L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x7.95f214f6efdcd0fp-4L, -0x6.68bbadffe256848p-4L, -0xb.396dd5127435ff2p-4L, -0xb.396dd5127435ff1p-4L }, + { -0xf.e9e97c18e559f59p-4L, 0x9.f5b28b8c5abdfbdp-4L, 0x2.95168d1a7a401db4p+0L, 0x2.95168d1a7a401db8p+0L }, + { 0x2.055b1777b282e33cp-1508L, 0xa.ddd851824e9cc4dp-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xb.5eaa19741f96466p-4L, 0x6.947f8b39e9330e3p-4L, 0x8.64e80eb23f4e797p-4L, 0x8.64e80eb23f4e798p-4L }, + { 0x8.0caee3998490c06p-4L, 0xb.fdd5aaea1f21087p-4L, 0xf.ac80644d42f8741p-4L, 0xf.ac80644d42f8742p-4L }, + { 0x7.2dab42195d9c94bp-4L, -0x1.1432f4dd5422d976p-40L, -0x2.679f7d784fd215a8p-40L, -0x2.679f7d784fd215a4p-40L }, + { 0x1.4606e76e580b8a0cp-4L, 0x3.0f05b15d1a1c90ccp-4L, 0x1.2d1f3eca25e48488p+0L, 0x1.2d1f3eca25e4848ap+0L }, + { -0x8.5ed70349b636516p-4L, -0x7.b69c3fd741b5e678p-12912L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x4.681599c48280feb8p-24L, 0x3.c6a8b9f4986a9634p-4L, 0x1.921fc7f043a898ep+0L, 0x1.921fc7f043a898e2p+0L }, + { 0x4.04dc8898d9c85308p+9536L, -0x2.5df4adcca608ba98p-12L, -0x9.6c5ece3961e7b91p-9552L, -0x9.6c5ece3961e7b9p-9552L }, + { 0xa.83e14bca0dac3fdp-4L, -0x1.5c01106a0de1ffeap-4L, -0x2.0e9b5df42dab89bcp-4L, -0x2.0e9b5df42dab89b8p-4L }, + { 0x8.2cdf755e03ecc16p-4L, 0x6.a1b1ca60f56fa998p-4L, 0xa.e781da0ed69665ap-4L, 0xa.e781da0ed69665bp-4L }, + { -0x3.039964d84c1627d4p+116L, 0xb.e6ab265f4ede4b9p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x3.3fb4865ddd19c4a4p+44L, 0xc.d231d5c4e611168p-4L, 0x3.f243987c6bb87648p-48L, 0x3.f243987c6bb8764cp-48L }, + { -0x8.72d7be8c1ce0c13p-4L, 0xc.16abe5e217ed38fp-4L, 0x2.2e4782208e9be82p+0L, 0x2.2e4782208e9be824p+0L }, + { 0x1.6310b10d9de5d426p+88L, 0x5.4a1938838acdc4fp-4L, 0x3.d04c201d8bb1fa2p-92L, 0x3.d04c201d8bb1fa24p-92L }, + { 0x8.5b4b0396d43ee47p-4L, -0x9.4834e879d5b0849p-4L, -0xd.67b2a76f016882ap-4L, -0xd.67b2a76f0168829p-4L }, + { 0x7.753bb7b8c25f952p+2888L, 0x3.e7a2599013f5192p-4L, 0x8.609439e6466766ep-2896L, 0x8.609439e6466766fp-2896L }, + { -0x1.fa942bc5b553041cp+12L, -0x6.6c53ede2a18a2428p-4L, -0x3.243c2b9225dff5d8p+0L, -0x3.243c2b9225dff5d4p+0L }, + { 0xa.47ea2dd67ff54e3p-4L, -0x7.d552135c630eca7p+140L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x5.b62f47f1376eb4d8p-4L, 0xa.1da7e265035a3c4p-4L, 0x1.0e8a0d4a9838070ep+0L, 0x1.0e8a0d4a9838071p+0L }, + { 0xd.5462bb61c9e0743p-4L, -0x3.e94008a1b69179f8p+2368L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x3.c6b50185720acab4p-4L, 0xc.e8153da96b4043fp-4L, 0x1.dafd8f82584b3aep+0L, 0x1.dafd8f82584b3ae2p+0L }, + { -0x6.6e228eb9c146093p-144L, 0xa.b6c4172198a391ap-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x2.a1bcbf92db38e4f8p-4L, 0x1.578aa97b6aa2f6a4p-120L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x4.03871323508d2208p-92L, 0x1.b7b42b180b7a5baep-4908L, 0x6.d8c6e23c0a17926p-4820L, 0x6.d8c6e23c0a179268p-4820L }, + { 0x1.e866d68d12e3d6e2p+64L, 0xc.ace2470bdb01192p-4L, 0x6.a4d586910831b16p-68L, 0x6.a4d586910831b168p-68L }, + { -0x2.a5ce182e00368394p+10688L, 0x1.c403d9c62d035c8p-4L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0x8.cac1a823d3b98bep-4L, 0x2.4dd80bb46880fd0cp+3768L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0xa.74b0b9f237195bfp-8L, -0xd.4880b498179975bp-4L, -0x1.858a2858781939d8p+0L, -0x1.858a2858781939d6p+0L }, + { -0xd.9c03b986ebe4541p-4L, 0xb.a372ba15d4c940dp-136L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { -0xa.76ccb7d81a5c5b8p-4L, -0x7.d178643f841cbc08p-4L, -0x2.7ffa8c7878fe5444p+0L, -0x2.7ffa8c7878fe544p+0L }, + { 0x8.992f6f29de9baa1p-4L, -0x2.6df885a56ac520b8p+84L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xc.c702ea51f29dd29p-4L, 0xc.52b96380b86a72ep-4L, 0x2.5fd171ce65416f68p+0L, 0x2.5fd171ce65416f6cp+0L }, + { 0x7.7da787b409a377c8p-4L, 0x4.bf0678273f028cd8p-4L, 0x9.09413df2baa84dfp-4L, 0x9.09413df2baa84ep-4L }, + { 0x7.e356b90a1e983p-4L, 0x5.657e1e60ee4799e8p-4L, 0x9.99959836d098709p-4L, 0x9.99959836d09870ap-4L }, + { -0x6.68cb8626a1a7bd2p-4L, 0x2.9433b04900ebb9p-4L, 0x2.c250ed62efbc5ed4p+0L, 0x2.c250ed62efbc5ed8p+0L }, + { -0x7.6704a5d84d429278p-12L, -0x2.53c60f0888101e64p+48L, -0x1.921fb54442d1849ep+0L, -0x1.921fb54442d1849cp+0L }, + { 0xf.a61176890fa8bdbp-4L, -0xc.17e8c4b326c4b6ep-4L, -0xa.86e92eeee828f27p-4L, -0xa.86e92eeee828f26p-4L }, + { -0x2.c555f1be423d02fcp-464L, 0x1.7c6eeead727f952ep-8L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x1.551ff116c5c06a1ap-116L, -0x2.bbf4a7d991feb2d4p-120L, -0x3.0398704f0e5afc7cp+0L, -0x3.0398704f0e5afc78p+0L }, + { 0x4.6e41b8acdd8f85dp-4L, -0x3.f4ef9b082435ce7cp-148L, -0xe.49e3b21a45821f7p-148L, -0xe.49e3b21a45821f6p-148L }, + { -0x6.40c5ab955d01a03p+5648L, -0x2.0979098b1bd5dbp+9916L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0x6.3b075dc7d59d685p-4L, -0x2.f48fe76be3d44e1p-152L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { -0x3.f74277ed265e015cp+60L, 0xc.480fd8d360f7142p-4L, 0x3.243f6a8885a308ccp+0L, 0x3.243f6a8885a308dp+0L }, + { -0x2.b74e97b30cacec2cp-4L, 0x6.47bd6d76772ae9ep-4L, 0x1.fa9e81a87803b58ep+0L, 0x1.fa9e81a87803b59p+0L }, + { -0x3.e4752a427feefdap-4L, -0x3.648ca3460f50fc28p-4L, -0x2.6cb7357e013e0c08p+0L, -0x2.6cb7357e013e0c04p+0L }, + { -0xa.338bb51e509e044p-152L, 0xb.f2d1dac2e74ad02p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x3.a03ed9b66660c09p-4L, 0xa.794c188e703dab8p-4L, 0x1.3ccdefaeb1710678p+0L, 0x1.3ccdefaeb171067ap+0L }, + { 0xb.2f3e3d838ebed4bp-4L, -0x4.eafc2cc3463c771p-6788L, -0x7.09091cfdd29e7dfp-6788L, -0x7.09091cfdd29e7de8p-6788L }, + { -0x8.684872e3380a1fdp+6060L, -0x4.bd8d34ac79591d58p+52L, -0x3.243f6a8885a308d4p+0L, -0x3.243f6a8885a308dp+0L }, + { 0x5.6fb79843c82e2c1p+5652L, -0xa.dec92754a1fe74dp-5540L, -0x1.ffe1755d00a766b8p-11192L, -0x1.ffe1755d00a766b6p-11192L }, + { 0x5.c1b1d1b6b056b648p-108L, -0x6.4e37b8f49a0b21f8p-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0x1.1c741352a9784764p+12044L, 0x1.7ffaf524a6c9d0e4p+7808L, 0x1.59924535f3025922p-4236L, 0x1.59924535f3025924p-4236L }, + { 0xa.36099fe806b84fcp+56L, 0x2.dfb4d2b6b161659cp-6848L, 0x4.80cbe1da75a10368p-6908L, 0x4.80cbe1da75a1037p-6908L }, + { -0x4.5190f0b1846ea89p-4L, 0x1.c37f5ed30d4ba53p+48L, 0x1.921fb54442d1ab96p+0L, 0x1.921fb54442d1ab98p+0L }, + { -0x4.0a6d4d991fcb0778p+8L, 0x2.90b4f02d88546e28p-4L, 0x3.2435422f3623d1fp+0L, 0x3.2435422f3623d1f4p+0L }, + { -0x6.f97d9ace617c1f1p-4L, -0x9.e638c81b7bb9dp-4L, -0x2.2f40065b511baef4p+0L, -0x2.2f40065b511baefp+0L }, + { -0x9.99f82f11bf88bbcp-4L, 0xa.7ea03cd6316368dp-4L, 0x2.4fd0aaeea4bea7acp+0L, 0x2.4fd0aaeea4bea7bp+0L }, + { 0x8.02f1895758feb2dp-8L, -0x1.b831b2fcec2b3d52p-4L, -0x1.49953e75cd87d946p+0L, -0x1.49953e75cd87d944p+0L }, + { -0x5.07e7aa225447584p-10264L, 0x4.4629c3e0a37fba8p+68L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x5.052f08bb6e5732c8p-4L, -0x5.0d5e419c51e0f3ep+116L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { -0xc.6dfcb7adf3a11cdp-4L, 0x1.121df88ac0598a6p-4L, 0x3.0e3f9f78b370d72p+0L, 0x3.0e3f9f78b370d724p+0L }, + { 0x5.d3cac7f6bdbb7e8p-13848L, 0xa.1583e5fa5a9dd55p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x5.d272fc700a86f688p-40L, 0x5.76e058e105a436p-4L, 0x1.921fb54453dda5f6p+0L, 0x1.921fb54453dda5f8p+0L }, + { 0xb.68c49383bb035d6p-4L, 0x4.ae54afae863ae4a8p-4L, 0x6.3ab8c728eac35168p-4L, 0x6.3ab8c728eac3517p-4L }, + { -0x8.81cb17de14581dbp-4L, -0x1.c2dcac66d7f29b12p+11656L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xb.0ae3fdc98ddc34fp-4L, -0xc.0b6e288dced796bp-8L, -0x1.16ccf2c7fd07e9aap-4L, -0x1.16ccf2c7fd07e9a8p-4L }, + { 0xe.c573d472a847a96p-8L, -0xb.8ff6fcd64ef65e6p-4L, -0x1.7dba02db709d9a0ap+0L, -0x1.7dba02db709d9a08p+0L }, + { 0x1.c2eb0a9ea7a016e8p-4L, 0x2.837abafcbe11a118p+20L, 0x1.921fb490de793956p+0L, 0x1.921fb490de793958p+0L }, + { -0x6.0003437ebf49b358p-4L, -0x6.8366f772a6e5ab88p-4L, -0x2.50b11488d2e618p+0L, -0x2.50b11488d2e617fcp+0L }, + { -0x5.5180b0012d133d7p-4L, 0x1.265b051593ae50bp+36L, 0x1.921fb54447719c84p+0L, 0x1.921fb54447719c86p+0L }, + { 0x7.fb6040f1f0ff7dp-4L, -0x3.7a55504e82f7f4dcp-4L, -0x6.93193e94ff08f66p-4L, -0x6.93193e94ff08f658p-4L }, + { 0x7.0db37c7302791a18p+140L, -0x9.17638d6fe5ab606p-4L, -0x1.49f61a170196d194p-144L, -0x1.49f61a170196d192p-144L }, + { -0x9.ce06d03b8cf756cp+12212L, 0x1.dedfea0526bba7dp+4572L, 0x3.243f6a8885a308dp+0L, 0x3.243f6a8885a308d4p+0L }, + { 0xb.7859f7b209e2fadp-4L, 0x4.7d451cc9eba3b3c8p+12080L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x3.800a4ceb87c4c0dcp-4L, -0xc.6125c4bdc9fce09p-4L, -0x1.4b95805a73babb12p+0L, -0x1.4b95805a73babb1p+0L }, + { 0xe.2f27e0dfe63260cp-4L, -0x5.15611dfbb941776p-4L, -0x5.81906be9aff7f478p-4L, -0x5.81906be9aff7f47p-4L }, + { -0xe.839068311283f8ap-4L, -0x3.ec9f15b5ee5373d4p-4L, -0x2.e0a57836248d1de8p+0L, -0x2.e0a57836248d1de4p+0L }, + { 0xf.e2ae6bf1e1a61e1p-4L, 0xf.c01b51aefe3a1aap+80L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x7.b53f66013e565ap-4L, 0x1.fca730dbcec65adcp-4L, 0x2.e3a9d5c63f015c2cp+0L, 0x2.e3a9d5c63f015c3p+0L }, + { 0xd.0cf58dc63ab7324p-4L, 0x7.449c0b585a5d2f78p-4L, 0x8.214f01a14103e4p-4L, 0x8.214f01a14103e41p-4L }, + { -0x5.6bd9880a9f4986p+44L, -0x6.2ffa8922e379925p-4L, -0x3.243f6a8885a1e4a8p+0L, -0x3.243f6a8885a1e4a4p+0L }, + { 0xf.704f945653892dbp-4L, -0xb.c78f60e05acc8c6p-92L, -0xc.353165a139735efp-92L, -0xc.353165a139735eep-92L }, + { 0x9.ebfb00a0b8c2da1p-4L, -0xb.af52c658515088ep-4L, -0xd.de7a23a873b3f3ep-4L, -0xd.de7a23a873b3f3dp-4L }, + { 0x3.875f9c7fb9864ae8p+468L, -0x9.4f89ff3200affa3p-4L, -0x2.a373dfc24c5488ap-472L, -0x2.a373dfc24c54889cp-472L }, + { -0xe.d00c66c632b4331p-4L, 0x7.ec775329456f0008p-8L, 0x3.1bb12c979946dfacp+0L, 0x3.1bb12c979946dfbp+0L }, + { -0x5.5f443fc060a5186p+4L, -0x5.20a0673897bdb3p+11012L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xa.a4bce42874e01e7p-4L, -0x4.713dabcd0bf8e268p-4L, -0x6.538a5466fb3e0bp-4L, -0x6.538a5466fb3e0af8p-4L }, + { 0xd.86b3fb9862792d8p-4L, 0xb.ae5e2dfcd038356p-4L, 0xb.65b757a77df534p-4L, 0xb.65b757a77df5341p-4L }, + { -0x9.adfe099d19d2efdp-4L, 0xa.88bf6665e9494dbp-4L, 0x2.505ec334ccbb79e4p+0L, 0x2.505ec334ccbb79e8p+0L }, + { 0x2.b3ae7a75c3b22b8p-6084L, 0x9.c5c6d7173a39debp+24L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0xe.7eb5c52358f835ep-3196L, 0x8.797ad35fc309114p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { -0x9.f8c8346e4053057p-4L, 0xf.c3edebe9bb0b3eep-8L, 0x3.0b089fc3ca8e624cp+0L, 0x3.0b089fc3ca8e625p+0L }, + { 0x8.c94c984dbf4168dp-140L, 0x8.af5e9852b765959p-4L, 0x1.921fb54442d18468p+0L, 0x1.921fb54442d1846ap+0L }, + { 0x2.c2b5d9731288dc28p+11664L, 0x5.04099a913d2b78bp+84L, 0x1.d121cb458be8286ap-11580L, 0x1.d121cb458be8286cp-11580L }, + { -0x2.ace07ddf3cfef394p-4L, -0x9.34833a09fae8757p-4L, -0x1.da87e7197755b95p+0L, -0x1.da87e7197755b94ep+0L }, + { -0x9.9730cd1292b85ap-4L, 0x4.c0eb35da7752fae8p-4L, 0x2.ae7231301fba2fc8p+0L, 0x2.ae7231301fba2fccp+0L }, + { 0xd.15f9ed0a25038d3p-4L, -0xb.026f5b20c30b683p-9908L, -0xd.761645d4aa3d8eap-9908L, -0xd.761645d4aa3d8e9p-9908L }, + { 0xd.be8ae1a17d85c18p-4L, 0x7.78d4cf72d7cf81d8p-4L, 0x7.f799f5d2cfdc8abp-4L, 0x7.f799f5d2cfdc8ab8p-4L }, + { 0x7.d23da006d9cb052p+100L, -0x7.a3b09d22470dbdbp+8L, -0xf.a0c5461aa543069p-96L, -0xf.a0c5461aa543068p-96L }, + { -0x7.5c713c672b96766p-4L, 0x2.52eaea727fb51b3cp-20L, 0x3.243f19b6d5b1f9b4p+0L, 0x3.243f19b6d5b1f9b8p+0L }, + { -0x3.2d22702027067fbp-11224L, -0x8.f3611793d8dfabdp-4L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xc.0e2efd7cc5044b8p-4L, 0x9.4b4c59fac13b018p-4L, 0xa.822768942e46d48p-4L, 0xa.822768942e46d49p-4L }, + { -0xb.0f085497de93bf5p-4L, 0x9.8ba535bfbb53d43p-4L, 0x2.6df415a19533453p+0L, 0x2.6df415a195334534p+0L }, + { -0x9.da37fa21c584069p-4L, 0xa.c84cf6492b6f825p-4L, 0x2.4fa7dddb330669c4p+0L, 0x2.4fa7dddb330669c8p+0L }, + { -0x9.3bcbc7bc0fb3ed9p+88L, -0x2.79e9ad222e894dc4p+6552L, -0x1.921fb54442d1846ap+0L, -0x1.921fb54442d18468p+0L }, + { 0xa.e73a40fb29d0efep-4L, -0x2.79cf7e59fb5c72d4p-7232L, -0x3.a21696480c751084p-7232L, -0x3.a21696480c75108p-7232L }, + { 0x4.8e020087477fcaep-4L, -0xb.588ec7584c64f6dp-8L, -0x2.789fd1176ef175bp-4L, -0x2.789fd1176ef175acp-4L }, +}; + +int check_equal(long double res, long double expected) +{ + if (res != expected) { + return 0; + } + return (__builtin_copysignl(1.0L, res) == + __builtin_copysignl(1.0L, expected)); +} + +int main(void) +{ + int ret = 0; + int i; + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + long double ld_res; + __asm__ volatile ("fpatan" : "=t" (ld_res) : + "0" (tests[i].arg0), "u" (tests[i].arg1) : "st(1)"); + if (!check_equal(ld_res, tests[i].down) && + !check_equal(ld_res, tests[i].up)) { + printf("FAIL: fpatan %La %La, expected %La or %La, got %La\n", + tests[i].arg0, tests[i].arg1, tests[i].down, tests[i].up, + ld_res); + ret = 1; + } + } + return ret; +} From 47f0d11d215695bd3434099a7c823f26c910d3ec Mon Sep 17 00:00:00 2001 From: Tao Xu Date: Tue, 24 Mar 2020 13:10:34 +0800 Subject: [PATCH 1707/2595] target/i386: Add notes for versioned CPU models Add which features are added or removed in this version. Signed-off-by: Tao Xu Message-Id: <20200324051034.30541-1-tao3.xu@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index b1b311baa2..06dc013d88 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3135,6 +3135,7 @@ static X86CPUDefinition builtin_x86_defs[] = { .versions = (X86CPUVersionDefinition[]) { { .version = 1 }, { .version = 2, + .note = "ARCH_CAPABILITIES", .props = (PropValue[]) { { "arch-capabilities", "on" }, { "rdctl-no", "on" }, @@ -3146,6 +3147,7 @@ static X86CPUDefinition builtin_x86_defs[] = { }, { .version = 3, .alias = "Cascadelake-Server-noTSX", + .note = "ARCH_CAPABILITIES, no TSX", .props = (PropValue[]) { { "hle", "off" }, { "rtm", "off" }, @@ -3367,6 +3369,7 @@ static X86CPUDefinition builtin_x86_defs[] = { { .version = 1 }, { .version = 2, + .note = "no TSX", .alias = "Icelake-Client-noTSX", .props = (PropValue[]) { { "hle", "off" }, @@ -3484,6 +3487,7 @@ static X86CPUDefinition builtin_x86_defs[] = { { .version = 1 }, { .version = 2, + .note = "no TSX", .alias = "Icelake-Server-noTSX", .props = (PropValue[]) { { "hle", "off" }, @@ -3604,6 +3608,7 @@ static X86CPUDefinition builtin_x86_defs[] = { { .version = 1 }, { .version = 2, + .note = "no MPX, no MONITOR", .props = (PropValue[]) { { "monitor", "off" }, { "mpx", "off" }, From f9919116b8c226428df28bc69ab33480eaa1ee6d Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 25 Jun 2020 11:26:02 -0500 Subject: [PATCH 1708/2595] osdep: Make MIN/MAX evaluate arguments only once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm not aware of any immediate bugs in qemu where a second runtime evaluation of the arguments to MIN() or MAX() causes a problem, but proactively preventing such abuse is easier than falling prey to an unintended case down the road. At any rate, here's the conversation that sparked the current patch: https://lists.gnu.org/archive/html/qemu-devel/2018-12/msg05718.html Update the MIN/MAX macros to only evaluate their argument once at runtime; this uses typeof(1 ? (a) : (b)) to ensure that we are promoting the temporaries to the same type as the final comparison (we have to trigger type promotion, as typeof(bitfield) won't compile; and we can't use typeof((a) + (b)) or even typeof((a) + 0), as some of our uses of MAX are on void* pointers where such addition is undefined). However, we are unable to work around gcc refusing to compile ({}) in a constant context (such as the array length of a static variable), even when only used in the dead branch of a __builtin_choose_expr(), so we have to provide a second macro pair MIN_CONST and MAX_CONST for use when both arguments are known to be compile-time constants and where the result must also be usable as a constant; this second form evaluates arguments multiple times but that doesn't matter for constants. By using a void expression as the expansion if a non-constant is presented to this second form, we can enlist the compiler to ensure the double evaluation is not attempted on non-constants. Alas, as both macros now rely on compiler intrinsics, they are no longer usable in preprocessor #if conditions; those will just have to be open-coded or the logic rewritten into #define or runtime 'if' conditions (but where the compiler dead-code-elimination will probably still apply). I tested that both gcc 10.1.1 and clang 10.0.0 produce errors for all forms of macro mis-use. As the errors can sometimes be cryptic, I'm demonstrating the gcc output: Use of MIN when MIN_CONST is needed: In file included from /home/eblake/qemu/qemu-img.c:25: /home/eblake/qemu/include/qemu/osdep.h:249:5: error: braced-group within expression allowed only inside a function 249 | ({ \ | ^ /home/eblake/qemu/qemu-img.c:92:12: note: in expansion of macro ‘MIN’ 92 | char array[MIN(1, 2)] = ""; | ^~~ Use of MIN_CONST when MIN is needed: /home/eblake/qemu/qemu-img.c: In function ‘is_allocated_sectors’: /home/eblake/qemu/qemu-img.c:1225:15: error: void value not ignored as it ought to be 1225 | i = MIN_CONST(i, n); | ^ Use of MIN in the preprocessor: In file included from /home/eblake/qemu/accel/tcg/translate-all.c:20: /home/eblake/qemu/accel/tcg/translate-all.c: In function ‘page_check_range’: /home/eblake/qemu/include/qemu/osdep.h:249:6: error: token "{" is not valid in preprocessor expressions 249 | ({ \ | ^ Fix the resulting callsites that used #if or computed a compile-time constant min or max to use the new macros. cpu-defs.h is interesting, as CPU_TLB_DYN_MAX_BITS is sometimes used as a constant and sometimes dynamic. It may be worth improving glib's MIN/MAX definitions to be saner, but that is a task for another day. Signed-off-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20200625162602.700741-1-eblake@redhat.com> Signed-off-by: Paolo Bonzini --- accel/tcg/translate-all.c | 6 ++--- hw/usb/hcd-xhci.h | 2 +- include/block/block.h | 4 +-- include/exec/cpu-all.h | 8 +++--- include/exec/cpu-defs.h | 7 ++++- include/qemu/osdep.h | 57 ++++++++++++++++++++++++++++++++------- migration/qemu-file.c | 2 +- 7 files changed, 63 insertions(+), 23 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index c3d37058a1..2afa46bd2b 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -2582,9 +2582,9 @@ int page_check_range(target_ulong start, target_ulong len, int flags) /* This function should never be called with addresses outside the guest address space. If this assert fires, it probably indicates a missing call to h2g_valid. */ -#if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS - assert(start < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS)); -#endif + if (TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS) { + assert(start < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS)); + } if (len == 0) { return 0; diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h index 2fad4df2a7..946af51fc2 100644 --- a/hw/usb/hcd-xhci.h +++ b/hw/usb/hcd-xhci.h @@ -214,7 +214,7 @@ struct XHCIState { uint32_t dcbaap_high; uint32_t config; - USBPort uports[MAX(MAXPORTS_2, MAXPORTS_3)]; + USBPort uports[MAX_CONST(MAXPORTS_2, MAXPORTS_3)]; XHCIPort ports[MAXPORTS]; XHCISlot slots[MAXSLOTS]; uint32_t numports; diff --git a/include/block/block.h b/include/block/block.h index 25e299605e..e8fc814996 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -133,8 +133,8 @@ typedef struct HDGeometry { #define BDRV_SECTOR_BITS 9 #define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS) -#define BDRV_REQUEST_MAX_SECTORS MIN(SIZE_MAX >> BDRV_SECTOR_BITS, \ - INT_MAX >> BDRV_SECTOR_BITS) +#define BDRV_REQUEST_MAX_SECTORS MIN_CONST(SIZE_MAX >> BDRV_SECTOR_BITS, \ + INT_MAX >> BDRV_SECTOR_BITS) #define BDRV_REQUEST_MAX_BYTES (BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) /* diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index fb4e8a8e29..fc403d456b 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -176,11 +176,9 @@ extern unsigned long reserved_va; * avoid setting bits at the top of guest addresses that might need * to be used for tags. */ -#if MIN(TARGET_VIRT_ADDR_SPACE_BITS, TARGET_ABI_BITS) <= 32 -# define GUEST_ADDR_MAX_ UINT32_MAX -#else -# define GUEST_ADDR_MAX_ (~0ul) -#endif +#define GUEST_ADDR_MAX_ \ + ((MIN_CONST(TARGET_VIRT_ADDR_SPACE_BITS, TARGET_ABI_BITS) <= 32) ? \ + UINT32_MAX : ~0ul) #define GUEST_ADDR_MAX (reserved_va ? reserved_va - 1 : GUEST_ADDR_MAX_) #else diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index 8c44abefa2..9185632337 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -102,8 +102,13 @@ typedef uint64_t target_ulong; * Skylake's Level-2 STLB has 16 1G entries. * Also, make sure we do not size the TLB past the guest's address space. */ -# define CPU_TLB_DYN_MAX_BITS \ +# ifdef TARGET_PAGE_BITS_VARY +# define CPU_TLB_DYN_MAX_BITS \ MIN(22, TARGET_VIRT_ADDR_SPACE_BITS - TARGET_PAGE_BITS) +# else +# define CPU_TLB_DYN_MAX_BITS \ + MIN_CONST(22, TARGET_VIRT_ADDR_SPACE_BITS - TARGET_PAGE_BITS) +# endif # endif typedef struct CPUTLBEntry { diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index ff7c17b857..0d26a1b9bd 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -236,18 +236,55 @@ extern int daemon(int, int); #define SIZE_MAX ((size_t)-1) #endif -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif +/* + * Two variations of MIN/MAX macros. The first is for runtime use, and + * evaluates arguments only once (so it is safe even with side + * effects), but will not work in constant contexts (such as array + * size declarations) because of the '{}'. The second is for constant + * expression use, where evaluating arguments twice is safe because + * the result is going to be constant anyway, but will not work in a + * runtime context because of a void expression where a value is + * expected. Thus, both gcc and clang will fail to compile if you use + * the wrong macro (even if the error may seem a bit cryptic). + * + * Note that neither form is usable as an #if condition; if you truly + * need to write conditional code that depends on a minimum or maximum + * determined by the pre-processor instead of the compiler, you'll + * have to open-code it. + */ +#undef MIN +#define MIN(a, b) \ + ({ \ + typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ + _a < _b ? _a : _b; \ + }) +#define MIN_CONST(a, b) \ + __builtin_choose_expr( \ + __builtin_constant_p(a) && __builtin_constant_p(b), \ + (a) < (b) ? (a) : (b), \ + ((void)0)) +#undef MAX +#define MAX(a, b) \ + ({ \ + typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ + _a > _b ? _a : _b; \ + }) +#define MAX_CONST(a, b) \ + __builtin_choose_expr( \ + __builtin_constant_p(a) && __builtin_constant_p(b), \ + (a) > (b) ? (a) : (b), \ + ((void)0)) -/* Minimum function that returns zero only iff both values are zero. - * Intended for use with unsigned values only. */ +/* + * Minimum function that returns zero only if both values are zero. + * Intended for use with unsigned values only. + */ #ifndef MIN_NON_ZERO -#define MIN_NON_ZERO(a, b) ((a) == 0 ? (b) : \ - ((b) == 0 ? (a) : (MIN(a, b)))) +#define MIN_NON_ZERO(a, b) \ + ({ \ + typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ + _a == 0 ? _b : (_b == 0 || _b > _a) ? _a : _b; \ + }) #endif /* Round number down to multiple */ diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 1c3a358a14..be21518c57 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -31,7 +31,7 @@ #include "qapi/error.h" #define IO_BUF_SIZE 32768 -#define MAX_IOV_SIZE MIN(IOV_MAX, 64) +#define MAX_IOV_SIZE MIN_CONST(IOV_MAX, 64) struct QEMUFile { const QEMUFileOps *ops; From 32a354dc6c07d766e70b51f42a62d8cd479e3f82 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 9 Jun 2020 09:56:35 -0400 Subject: [PATCH 1709/2595] numa: forbid '-numa node, mem' for 5.1 and newer machine types Deprecation period is run out and it's a time to flip the switch introduced by cd5ff8333a. Disable legacy option for new machine types (since 5.1) and amend documentation. '-numa node,memdev' shall be used instead of disabled option with new machine types. Signed-off-by: Igor Mammedov Reviewed-by: Michal Privoznik Reviewed-by: Michael S. Tsirkin Reviewed-by: Greg Kurz Message-Id: <20200609135635.761587-1-imammedo@redhat.com> Signed-off-by: Paolo Bonzini --- docs/system/deprecated.rst | 37 ++++++++++++++++++++----------------- hw/arm/virt.c | 2 +- hw/core/numa.c | 7 +++++++ hw/i386/pc.c | 1 - hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 1 + hw/ppc/spapr.c | 2 +- qemu-options.hx | 9 +++++---- 8 files changed, 36 insertions(+), 24 deletions(-) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 728233a8ff..843ae71fc6 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -95,23 +95,6 @@ error in the future. The ``-realtime mlock=on|off`` argument has been replaced by the ``-overcommit mem-lock=on|off`` argument. -``-numa node,mem=``\ *size* (since 4.1) -''''''''''''''''''''''''''''''''''''''' - -The parameter ``mem`` of ``-numa node`` is used to assign a part of -guest RAM to a NUMA node. But when using it, it's impossible to manage specified -RAM chunk on the host side (like bind it to a host node, setting bind policy, ...), -so guest end-ups with the fake NUMA configuration with suboptiomal performance. -However since 2014 there is an alternative way to assign RAM to a NUMA node -using parameter ``memdev``, which does the same as ``mem`` and adds -means to actualy manage node RAM on the host side. Use parameter ``memdev`` -with *memory-backend-ram* backend as an replacement for parameter ``mem`` -to achieve the same fake NUMA effect or a properly configured -*memory-backend-file* backend to actually benefit from NUMA configuration. -In future new machine versions will not accept the option but it will still -work with old machine types. User can check QAPI schema to see if the legacy -option is supported by looking at MachineInfo::numa-mem-supported property. - ``-numa`` node (without memory specified) (since 4.1) ''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -553,3 +536,23 @@ long starting at 1MiB, the old command:: can be rewritten as:: qemu-nbd -t --image-opts driver=raw,offset=1M,size=100M,file.driver=qcow2,file.file.driver=file,file.file.filename=file.qcow2 + +Command line options +-------------------- + +``-numa node,mem=``\ *size* (removed in 5.1) +'''''''''''''''''''''''''''''''''''''''''''' + +The parameter ``mem`` of ``-numa node`` was used to assign a part of +guest RAM to a NUMA node. But when using it, it's impossible to manage a specified +RAM chunk on the host side (like bind it to a host node, setting bind policy, ...), +so the guest ends up with the fake NUMA configuration with suboptiomal performance. +However since 2014 there is an alternative way to assign RAM to a NUMA node +using parameter ``memdev``, which does the same as ``mem`` and adds +means to actually manage node RAM on the host side. Use parameter ``memdev`` +with *memory-backend-ram* backend as replacement for parameter ``mem`` +to achieve the same fake NUMA effect or a properly configured +*memory-backend-file* backend to actually benefit from NUMA configuration. +New machine versions (since 5.1) will not accept the option but it will still +work with old machine types. User can check the QAPI schema to see if the legacy +option is supported by looking at MachineInfo::numa-mem-supported property. diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 402c362c14..5aa8b87465 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2320,7 +2320,6 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) hc->plug = virt_machine_device_plug_cb; hc->unplug_request = virt_machine_device_unplug_request_cb; hc->unplug = virt_machine_device_unplug_cb; - mc->numa_mem_supported = true; mc->nvdimm_supported = true; mc->auto_enable_numa_with_memhp = true; mc->default_ram_id = "mach-virt.ram"; @@ -2434,6 +2433,7 @@ static void virt_machine_5_0_options(MachineClass *mc) { virt_machine_5_1_options(mc); compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len); + mc->numa_mem_supported = true; } DEFINE_VIRT_MACHINE(5, 0) diff --git a/hw/core/numa.c b/hw/core/numa.c index 5f81900f88..2725886d06 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -117,6 +117,13 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node, } if (node->has_mem) { + if (!mc->numa_mem_supported) { + error_setg(errp, "Parameter -numa node,mem is not supported by this" + " machine type"); + error_append_hint(errp, "Use -numa node,memdev instead\n"); + return; + } + numa_info[nodenr].node_mem = node->mem; if (!qtest_enabled()) { warn_report("Parameter -numa node,mem is deprecated," diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 803bd52ca4..4af9679d03 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1980,7 +1980,6 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) hc->unplug = pc_machine_device_unplug_cb; mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE; mc->nvdimm_supported = true; - mc->numa_mem_supported = true; mc->default_ram_id = "pc.ram"; object_class_property_add(oc, PC_MACHINE_MAX_RAM_BELOW_4G, "size", diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 1497d0e4ae..1d832b2878 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -441,6 +441,7 @@ static void pc_i440fx_5_0_machine_options(MachineClass *m) pc_i440fx_5_1_machine_options(m); m->alias = NULL; m->is_default = false; + m->numa_mem_supported = true; compat_props_add(m->compat_props, hw_compat_5_0, hw_compat_5_0_len); compat_props_add(m->compat_props, pc_compat_5_0, pc_compat_5_0_len); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 46cd06524c..047ea8db28 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -369,6 +369,7 @@ static void pc_q35_5_0_machine_options(MachineClass *m) { pc_q35_5_1_machine_options(m); m->alias = NULL; + m->numa_mem_supported = true; compat_props_add(m->compat_props, hw_compat_5_0, hw_compat_5_0_len); compat_props_add(m->compat_props, pc_compat_5_0, pc_compat_5_0_len); } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index bd9345cdac..4c185bcc13 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4510,7 +4510,6 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) * in which LMBs are represented and hot-added */ mc->numa_mem_align_shift = 28; - mc->numa_mem_supported = true; mc->auto_enable_numa = true; smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; @@ -4598,6 +4597,7 @@ static void spapr_machine_5_0_class_options(MachineClass *mc) { spapr_machine_5_1_class_options(mc); compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len); + mc->numa_mem_supported = true; } DEFINE_SPAPR_MACHINE(5_0, "5.0", false); diff --git a/qemu-options.hx b/qemu-options.hx index 93bde2bbc8..196f468786 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -239,10 +239,11 @@ SRST -numa node,nodeid=0 -numa node,nodeid=1 \ -numa cpu,node-id=0,socket-id=0 -numa cpu,node-id=1,socket-id=1 - '\ ``mem``\ ' assigns a given RAM amount to a node. '\ ``memdev``\ ' - assigns RAM from a given memory backend device to a node. If - '\ ``mem``\ ' and '\ ``memdev``\ ' are omitted in all nodes, RAM is - split equally between them. + Legacy '\ ``mem``\ ' assigns a given RAM amount to a node (not supported + for 5.1 and newer machine types). '\ ``memdev``\ ' assigns RAM from + a given memory backend device to a node. If '\ ``mem``\ ' and + '\ ``memdev``\ ' are omitted in all nodes, RAM is split equally between them. + '\ ``mem``\ ' and '\ ``memdev``\ ' are mutually exclusive. Furthermore, if one node uses '\ ``memdev``\ ', all of them have to From 74aaddc6283ff789923127f3b95f781796fe3f39 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Tue, 16 Jun 2020 13:58:05 -0300 Subject: [PATCH 1710/2595] kvm: i386: allow TSC to differ by NTP correction bounds without TSC scaling The Linux TSC calibration procedure is subject to small variations (its common to see +-1 kHz difference between reboots on a given CPU, for example). So migrating a guest between two hosts with identical processor can fail, in case of a small variation in calibrated TSC between them. Allow a conservative 250ppm error between host TSC and VM TSC frequencies, rather than requiring an exact match. NTP daemon in the guest can correct this difference. Also change migration to accept this bound. KVM_SET_TSC_KHZ depends on a kernel interface change. Without this change, the behaviour remains the same: in case of a different frequency between host and VM, KVM_SET_TSC_KHZ will fail and QEMU will exit. Signed-off-by: Marcelo Tosatti Message-Id: <20200616165805.GA324612@fuller.cnet> Signed-off-by: Paolo Bonzini --- target/i386/kvm.c | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/target/i386/kvm.c b/target/i386/kvm.c index b3c13cb898..6adbff3d74 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -740,26 +740,62 @@ static bool hyperv_enabled(X86CPU *cpu) cpu->hyperv_features || cpu->hyperv_passthrough); } +/* + * Check whether target_freq is within conservative + * ntp correctable bounds (250ppm) of freq + */ +static inline bool freq_within_bounds(int freq, int target_freq) +{ + int max_freq = freq + (freq * 250 / 1000000); + int min_freq = freq - (freq * 250 / 1000000); + + if (target_freq >= min_freq && target_freq <= max_freq) { + return true; + } + + return false; +} + static int kvm_arch_set_tsc_khz(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; - int r; + int r, cur_freq; + bool set_ioctl = false; if (!env->tsc_khz) { return 0; } - r = kvm_check_extension(cs->kvm_state, KVM_CAP_TSC_CONTROL) ? + cur_freq = kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ? + kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) : -ENOTSUP; + + /* + * If TSC scaling is supported, attempt to set TSC frequency. + */ + if (kvm_check_extension(cs->kvm_state, KVM_CAP_TSC_CONTROL)) { + set_ioctl = true; + } + + /* + * If desired TSC frequency is within bounds of NTP correction, + * attempt to set TSC frequency. + */ + if (cur_freq != -ENOTSUP && freq_within_bounds(cur_freq, env->tsc_khz)) { + set_ioctl = true; + } + + r = set_ioctl ? kvm_vcpu_ioctl(cs, KVM_SET_TSC_KHZ, env->tsc_khz) : -ENOTSUP; + if (r < 0) { /* When KVM_SET_TSC_KHZ fails, it's an error only if the current * TSC frequency doesn't match the one we want. */ - int cur_freq = kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ? - kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) : - -ENOTSUP; + cur_freq = kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ? + kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) : + -ENOTSUP; if (cur_freq <= 0 || cur_freq != env->tsc_khz) { warn_report("TSC frequency mismatch between " "VM (%" PRId64 " kHz) and host (%d kHz), " From 8f06f22f38246ea7a6b0b20013fd9a7a87e23569 Mon Sep 17 00:00:00 2001 From: Jon Doron Date: Wed, 17 Jun 2020 19:09:02 +0300 Subject: [PATCH 1711/2595] hyperv: vmbus: Remove the 2nd IRQ It seems like Windows does not really require 2 IRQs to have a functioning VMBus. Signed-off-by: Jon Doron Message-Id: <20200617160904.681845-2-arilou@gmail.com> Signed-off-by: Paolo Bonzini --- hw/hyperv/vmbus.c | 3 +-- hw/i386/acpi-build.c | 4 +--- include/hw/hyperv/vmbus-bridge.h | 3 +-- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index f371240176..a8bcb41026 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -2741,8 +2741,7 @@ static const VMStateDescription vmstate_vmbus_bridge = { }; static Property vmbus_bridge_props[] = { - DEFINE_PROP_UINT8("irq0", VMBusBridge, irq0, 7), - DEFINE_PROP_UINT8("irq1", VMBusBridge, irq1, 13), + DEFINE_PROP_UINT8("irq", VMBusBridge, irq, 7), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 378515df66..b7bcbbbb2a 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -967,9 +967,7 @@ static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge) aml_append(dev, aml_name_decl("_PS3", aml_int(0x0))); crs = aml_resource_template(); - aml_append(crs, aml_irq_no_flags(vmbus_bridge->irq0)); - /* FIXME: newer HyperV gets by with only one IRQ */ - aml_append(crs, aml_irq_no_flags(vmbus_bridge->irq1)); + aml_append(crs, aml_irq_no_flags(vmbus_bridge->irq)); aml_append(dev, aml_name_decl("_CRS", crs)); return dev; diff --git a/include/hw/hyperv/vmbus-bridge.h b/include/hw/hyperv/vmbus-bridge.h index c0a06d832c..33f93de64d 100644 --- a/include/hw/hyperv/vmbus-bridge.h +++ b/include/hw/hyperv/vmbus-bridge.h @@ -19,8 +19,7 @@ typedef struct VMBus VMBus; typedef struct VMBusBridge { SysBusDevice parent_obj; - uint8_t irq0; - uint8_t irq1; + uint8_t irq; VMBus *bus; } VMBusBridge; From f983ff95f4c9886eaa4c59beff609d59fa2a90ff Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 23 Jun 2020 06:28:08 -0400 Subject: [PATCH 1712/2595] vmport: move compat properties to hw_compat_5_0 The patches that introduced the properties were submitted when QEMU 5.0 had not been released yet, so they got merged under the wrong heading. Move them to hw_compat_5_0 so that 5.0 machine types get the pre-patch behavior. Fixes: b889212973da ("hw/i386/vmport: Propagate IOPort read to vCPU EAX register") Fixes: 0342ee761ef2 ("hw/i386/vmport: Set EAX to -1 on failed and unsupported commands") Fixes: f8bdc550370f ("hw/i386/vmport: Report vmware-vmx-type in CMD_GETVERSION") Fixes: aaacf1c15a22 ("hw/i386/vmport: Add support for CMD_GETBIOSUUID") Reported-by: Laurent Vivier Cc: Liran Alon Reviewed-by: Laurent Vivier Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 1d80ab0e1d..211b4e077a 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -30,6 +30,10 @@ GlobalProperty hw_compat_5_0[] = { { "virtio-balloon-device", "page-poison", "false" }, + { "vmport", "x-read-set-eax", "off" }, + { "vmport", "x-signal-unsupported-cmd", "off" }, + { "vmport", "x-report-vmx-type", "off" }, + { "vmport", "x-cmds-v2", "off" }, }; const size_t hw_compat_5_0_len = G_N_ELEMENTS(hw_compat_5_0); @@ -45,10 +49,6 @@ GlobalProperty hw_compat_4_2[] = { { "qxl", "revision", "4" }, { "qxl-vga", "revision", "4" }, { "fw_cfg", "acpi-mr-restore", "false" }, - { "vmport", "x-read-set-eax", "off" }, - { "vmport", "x-signal-unsupported-cmd", "off" }, - { "vmport", "x-report-vmx-type", "off" }, - { "vmport", "x-cmds-v2", "off" }, }; const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2); From c8d7fd059d73a7d3035e379c319034c30ba3dbbf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 23 Jun 2020 15:54:25 -0400 Subject: [PATCH 1713/2595] ibex_uart: fix XOR-as-pow The xor-as-pow warning in clang actually detected a genuine bug. Fix it. Signed-off-by: Paolo Bonzini --- hw/char/ibex_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c index 3e0dd9968e..45cd724998 100644 --- a/hw/char/ibex_uart.c +++ b/hw/char/ibex_uart.c @@ -331,7 +331,7 @@ static void ibex_uart_write(void *opaque, hwaddr addr, if (value & UART_CTRL_NCO) { uint64_t baud = ((value & UART_CTRL_NCO) >> 16); baud *= 1000; - baud /= 2 ^ 20; + baud >>= 20; s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; } From 730319aef0fcb94f11a4a2d32656437fdde7efdd Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 23 Jun 2020 19:01:16 -0400 Subject: [PATCH 1714/2595] i386: Mask SVM features if nested SVM is disabled QEMU incorrectly validates FEAT_SVM feature flags against GET_SUPPORTED_CPUID even if SVM features are being masked out by cpu_x86_cpuid(). This can make QEMU print warnings on most AMD CPU models, even when SVM nesting is disabled (which is the default). This bug was never detected before because of a Linux KVM bug: until Linux v5.6, KVM was not filtering out SVM features in GET_SUPPORTED_CPUID when nested was disabled. This KVM bug was fixed in Linux v5.7-rc1, on Linux commit a50718cc3f43 ("KVM: nSVM: Expose SVM features to L1 iff nested is enabled"). Fix the problem by adding a CPUID_EXT3_SVM dependency to all FEAT_SVM feature flags in the feature_dependencies table. Reported-by: Yanan Fu Signed-off-by: Eduardo Habkost Message-Id: <20200623230116.277409-1-ehabkost@redhat.com> [Fix testcase. - Paolo] Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 4 ++++ tests/qtest/test-x86-cpuid-compat.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 06dc013d88..36cbd3d027 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1404,6 +1404,10 @@ static FeatureDep feature_dependencies[] = { .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_VMFUNC }, .to = { FEAT_VMX_VMFUNC, ~0ull }, }, + { + .from = { FEAT_8000_0001_ECX, CPUID_EXT3_SVM }, + .to = { FEAT_SVM, ~0ull }, + }, }; typedef struct X86RegisterInfo32 { diff --git a/tests/qtest/test-x86-cpuid-compat.c b/tests/qtest/test-x86-cpuid-compat.c index 772287bdb4..7ca1883a29 100644 --- a/tests/qtest/test-x86-cpuid-compat.c +++ b/tests/qtest/test-x86-cpuid-compat.c @@ -256,7 +256,7 @@ int main(int argc, char **argv) "-cpu 486,+invtsc", "xlevel", 0x80000007); /* CPUID[8000_000A].EDX: */ add_cpuid_test("x86/cpuid/auto-xlevel/486/npt", - "-cpu 486,+npt", "xlevel", 0x8000000A); + "-cpu 486,+svm,+npt", "xlevel", 0x8000000A); /* CPUID[C000_0001].EDX: */ add_cpuid_test("x86/cpuid/auto-xlevel2/phenom/xstore", "-cpu phenom,+xstore", "xlevel2", 0xC0000001); @@ -348,7 +348,7 @@ int main(int argc, char **argv) "-machine pc-i440fx-2.4 -cpu SandyBridge,", "xlevel", 0x80000008); add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-on", - "-machine pc-i440fx-2.4 -cpu SandyBridge,+npt", + "-machine pc-i440fx-2.4 -cpu SandyBridge,+svm,+npt", "xlevel", 0x80000008); /* Test feature parsing */ From 719d109b7fe153b0ec4dfeba2f303f864555d819 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 24 Jun 2020 18:45:28 +0800 Subject: [PATCH 1715/2595] hw/mips: Implement the kvm_type() hook in MachineClass MIPS has two types of KVM: TE & VZ, and TE is the default type. Now we can't create a VZ guest in QEMU because it lacks the kvm_type() hook in MachineClass. This patch add the the kvm_type() hook to support both of the two types. [AM: Added "if defined" guards.] Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Signed-off-by: Huacai Chen Co-developed-by: Jiaxun Yang Message-Id: <1592995531-32600-2-git-send-email-chenhc@lemote.com> --- target/mips/kvm.c | 26 ++++++++++++++++++++++++++ target/mips/kvm_mips.h | 11 +++++++++++ 2 files changed, 37 insertions(+) diff --git a/target/mips/kvm.c b/target/mips/kvm.c index 96cfa10cf2..72637a1e02 100644 --- a/target/mips/kvm.c +++ b/target/mips/kvm.c @@ -21,10 +21,12 @@ #include "qemu/main-loop.h" #include "qemu/timer.h" #include "sysemu/kvm.h" +#include "sysemu/kvm_int.h" #include "sysemu/runstate.h" #include "sysemu/cpus.h" #include "kvm_mips.h" #include "exec/memattrs.h" +#include "hw/boards.h" #define DEBUG_KVM 0 @@ -1270,3 +1272,27 @@ int kvm_arch_msi_data_to_gsi(uint32_t data) { abort(); } + +int mips_kvm_type(MachineState *machine, const char *vm_type) +{ +#if defined(KVM_CAP_MIPS_VZ) || defined(KVM_CAP_MIPS_TE) + int r; + KVMState *s = KVM_STATE(machine->accelerator); +#endif + +#if defined(KVM_CAP_MIPS_VZ) + r = kvm_check_extension(s, KVM_CAP_MIPS_VZ); + if (r > 0) { + return KVM_VM_MIPS_VZ; + } +#endif + +#if defined(KVM_CAP_MIPS_TE) + r = kvm_check_extension(s, KVM_CAP_MIPS_TE); + if (r > 0) { + return KVM_VM_MIPS_TE; + } +#endif + + return -1; +} diff --git a/target/mips/kvm_mips.h b/target/mips/kvm_mips.h index 1e4014792d..171d53dbe1 100644 --- a/target/mips/kvm_mips.h +++ b/target/mips/kvm_mips.h @@ -12,6 +12,8 @@ #ifndef KVM_MIPS_H #define KVM_MIPS_H +#include "cpu.h" + /** * kvm_mips_reset_vcpu: * @cpu: MIPSCPU @@ -23,4 +25,13 @@ void kvm_mips_reset_vcpu(MIPSCPU *cpu); int kvm_mips_set_interrupt(MIPSCPU *cpu, int irq, int level); int kvm_mips_set_ipi_interrupt(MIPSCPU *cpu, int irq, int level); +#ifdef CONFIG_KVM +int mips_kvm_type(MachineState *machine, const char *vm_type); +#else +static inline int mips_kvm_type(MachineState *machine, const char *vm_type) +{ + return 0; +} +#endif + #endif /* KVM_MIPS_H */ From c012e0b1f9121f3d8d2315af4dfd63084ea23faa Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 24 Jun 2020 18:45:29 +0800 Subject: [PATCH 1716/2595] hw/intc: Add Loongson LIOINTC support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Loongson-3 has an integrated liointc (Local I/O Interrupt Controller). It is similar to Goldfish interrupt controller, but more powerful (e.g., it can route external interrupt to multi-cores). Documents about Loongson-3's liointc: 1, https://wiki.godson.ac.cn/ip_block:liointc; 2, The "I/O中断" section of Loongson-3's user mannual, part 1. Signed-off-by: Huacai Chen Signed-off-by: Jiaxun Yang Signed-off-by: Aleksandar Markovic Reviewed-by: Aleksandar Markovic Message-Id: <1592995531-32600-3-git-send-email-chenhc@lemote.com> --- hw/intc/Kconfig | 3 + hw/intc/Makefile.objs | 1 + hw/intc/loongson_liointc.c | 242 +++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 hw/intc/loongson_liointc.c diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index f562342bab..2ae1e89497 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -64,3 +64,6 @@ config OMPIC config RX_ICU bool + +config LOONGSON_LIOINTC + bool diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index a4202636d4..3ac2b40fbb 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -51,3 +51,4 @@ obj-$(CONFIG_MIPS_CPS) += mips_gic.o obj-$(CONFIG_NIOS2) += nios2_iic.o obj-$(CONFIG_OMPIC) += ompic.o obj-$(CONFIG_IBEX) += ibex_plic.o +obj-$(CONFIG_LOONGSON_LIOINTC) += loongson_liointc.o diff --git a/hw/intc/loongson_liointc.c b/hw/intc/loongson_liointc.c new file mode 100644 index 0000000000..23ca51cc2e --- /dev/null +++ b/hw/intc/loongson_liointc.c @@ -0,0 +1,242 @@ +/* + * QEMU Loongson Local I/O interrupt controler. + * + * Copyright (c) 2020 Jiaxun Yang + * + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "qemu/module.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" + +#define D(x) + +#define NUM_IRQS 32 + +#define NUM_CORES 4 +#define NUM_IPS 4 +#define NUM_PARENTS (NUM_CORES * NUM_IPS) +#define PARENT_COREx_IPy(x, y) (NUM_IPS * x + y) + +#define R_MAPPER_START 0x0 +#define R_MAPPER_END 0x20 +#define R_ISR R_MAPPER_END +#define R_IEN 0x24 +#define R_IEN_SET 0x28 +#define R_IEN_CLR 0x2c +#define R_PERCORE_ISR(x) (0x40 + 0x8 * x) +#define R_END 0x64 + +#define TYPE_LOONGSON_LIOINTC "loongson.liointc" +#define LOONGSON_LIOINTC(obj) \ + OBJECT_CHECK(struct loongson_liointc, (obj), TYPE_LOONGSON_LIOINTC) + +struct loongson_liointc { + SysBusDevice parent_obj; + + MemoryRegion mmio; + qemu_irq parent_irq[NUM_PARENTS]; + + uint8_t mapper[NUM_IRQS]; /* 0:3 for core, 4:7 for IP */ + uint32_t isr; + uint32_t ien; + uint32_t per_core_isr[NUM_CORES]; + + /* state of the interrupt input pins */ + uint32_t pin_state; + bool parent_state[NUM_PARENTS]; +}; + +static void update_irq(struct loongson_liointc *p) +{ + uint32_t irq, core, ip; + uint32_t per_ip_isr[NUM_IPS] = {0}; + + /* level triggered interrupt */ + p->isr = p->pin_state; + + /* Clear disabled IRQs */ + p->isr &= p->ien; + + /* Clear per_core_isr */ + for (core = 0; core < NUM_CORES; core++) { + p->per_core_isr[core] = 0; + } + + /* Update per_core_isr and per_ip_isr */ + for (irq = 0; irq < NUM_IRQS; irq++) { + if (!(p->isr & (1 << irq))) { + continue; + } + + for (core = 0; core < NUM_CORES; core++) { + if ((p->mapper[irq] & (1 << core))) { + p->per_core_isr[core] |= (1 << irq); + } + } + + for (ip = 0; ip < NUM_IPS; ip++) { + if ((p->mapper[irq] & (1 << (ip + 4)))) { + per_ip_isr[ip] |= (1 << irq); + } + } + } + + /* Emit IRQ to parent! */ + for (core = 0; core < NUM_CORES; core++) { + for (ip = 0; ip < NUM_IPS; ip++) { + int parent = PARENT_COREx_IPy(core, ip); + if (p->parent_state[parent] != + (!!p->per_core_isr[core] && !!per_ip_isr[ip])) { + p->parent_state[parent] = !p->parent_state[parent]; + qemu_set_irq(p->parent_irq[parent], p->parent_state[parent]); + } + } + } +} + +static uint64_t +liointc_read(void *opaque, hwaddr addr, unsigned int size) +{ + struct loongson_liointc *p = opaque; + uint32_t r = 0; + + /* Mapper is 1 byte */ + if (size == 1 && addr < R_MAPPER_END) { + r = p->mapper[addr]; + goto out; + } + + /* Rest is 4 byte */ + if (size != 4 || (addr % 4)) { + goto out; + } + + if (addr >= R_PERCORE_ISR(0) && + addr < R_PERCORE_ISR(NUM_CORES)) { + int core = (addr - R_PERCORE_ISR(0)) / 4; + r = p->per_core_isr[core]; + goto out; + } + + switch (addr) { + case R_ISR: + r = p->isr; + break; + case R_IEN: + r = p->ien; + break; + default: + break; + } + +out: + D(qemu_log("%s: size=%d addr=%lx val=%x\n", __func__, size, addr, r)); + return r; +} + +static void +liointc_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + struct loongson_liointc *p = opaque; + uint32_t value = val64; + + D(qemu_log("%s: size=%d, addr=%lx val=%x\n", __func__, size, addr, value)); + + /* Mapper is 1 byte */ + if (size == 1 && addr < R_MAPPER_END) { + p->mapper[addr] = value; + goto out; + } + + /* Rest is 4 byte */ + if (size != 4 || (addr % 4)) { + goto out; + } + + if (addr >= R_PERCORE_ISR(0) && + addr < R_PERCORE_ISR(NUM_CORES)) { + int core = (addr - R_PERCORE_ISR(0)) / 4; + p->per_core_isr[core] = value; + goto out; + } + + switch (addr) { + case R_IEN_SET: + p->ien |= value; + break; + case R_IEN_CLR: + p->ien &= ~value; + break; + default: + break; + } + +out: + update_irq(p); +} + +static const MemoryRegionOps pic_ops = { + .read = liointc_read, + .write = liointc_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4 + } +}; + +static void irq_handler(void *opaque, int irq, int level) +{ + struct loongson_liointc *p = opaque; + + p->pin_state &= ~(1 << irq); + p->pin_state |= level << irq; + update_irq(p); +} + +static void loongson_liointc_init(Object *obj) +{ + struct loongson_liointc *p = LOONGSON_LIOINTC(obj); + int i; + + qdev_init_gpio_in(DEVICE(obj), irq_handler, 32); + + for (i = 0; i < NUM_PARENTS; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq[i]); + } + + memory_region_init_io(&p->mmio, obj, &pic_ops, p, + "loongson.liointc", R_END); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio); +} + +static const TypeInfo loongson_liointc_info = { + .name = TYPE_LOONGSON_LIOINTC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct loongson_liointc), + .instance_init = loongson_liointc_init, +}; + +static void loongson_liointc_register_types(void) +{ + type_register_static(&loongson_liointc_info); +} + +type_init(loongson_liointc_register_types) From 2c5b1a7dbb6f3f692bf42835a284d17c749bc14f Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 24 Jun 2020 18:45:31 +0800 Subject: [PATCH 1717/2595] MAINTAINERS: Add Loongson-3 maintainer and reviewer Add myself as the maintainer for Loongson-3 virtual platforms, and also add Jiaxun Yang as the reviewer. Signed-off-by: Huacai Chen Co-developed-by: Jiaxun Yang Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: <1592995531-32600-5-git-send-email-chenhc@lemote.com> --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1b40446c73..fe925ea661 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1096,6 +1096,13 @@ F: hw/isa/vt82c686.c F: hw/pci-host/bonito.c F: include/hw/isa/vt82c686.h +Loongson-3 Virtual Platform +M: Huacai Chen +R: Jiaxun Yang +S: Maintained +F: hw/mips/loongson3_virt.c +F: hw/intc/loongson_liointc.c + Boston M: Paul Burton R: Aleksandar Rikalo From c5a5839856119a3644dcc0775a046ed0ee3081c3 Mon Sep 17 00:00:00 2001 From: Ahmed Karaman Date: Fri, 26 Jun 2020 18:45:44 +0200 Subject: [PATCH 1718/2595] scripts/performance: Add topN_perf.py script Syntax: topN_perf.py [-h] [-n] -- \ [] \ [] [-h] - Print the script arguments help message. [-n] - Specify the number of top functions to print. - If this flag is not specified, the tool defaults to 25. Example of usage: topN_perf.py -n 20 -- qemu-arm coulomb_double-arm Example Output: No. Percentage Name Invoked by ---- ---------- ------------------------- ------------------------- 1 16.25% float64_mul qemu-x86_64 2 12.01% float64_sub qemu-x86_64 3 11.99% float64_add qemu-x86_64 4 5.69% helper_mulsd qemu-x86_64 5 4.68% helper_addsd qemu-x86_64 6 4.43% helper_lookup_tb_ptr qemu-x86_64 7 4.28% helper_subsd qemu-x86_64 8 2.71% f64_compare qemu-x86_64 9 2.71% helper_ucomisd qemu-x86_64 10 1.04% helper_pand_xmm qemu-x86_64 11 0.71% float64_div qemu-x86_64 12 0.63% helper_pxor_xmm qemu-x86_64 13 0.50% 0x00007f7b7004ef95 [JIT] tid 491 14 0.50% 0x00007f7b70044e83 [JIT] tid 491 15 0.36% helper_por_xmm qemu-x86_64 16 0.32% helper_cc_compute_all qemu-x86_64 17 0.30% 0x00007f7b700433f0 [JIT] tid 491 18 0.30% float64_compare_quiet qemu-x86_64 19 0.27% soft_f64_addsub qemu-x86_64 20 0.26% round_to_int qemu-x86_64 Signed-off-by: Ahmed Karaman Signed-off-by: Aleksandar Markovic Reviewed-by: Aleksandar Markovic Message-Id: <20200626164546.22102-2-ahmedkhaledkaraman@gmail.com> --- scripts/performance/topN_perf.py | 149 +++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100755 scripts/performance/topN_perf.py diff --git a/scripts/performance/topN_perf.py b/scripts/performance/topN_perf.py new file mode 100755 index 0000000000..07be195fc8 --- /dev/null +++ b/scripts/performance/topN_perf.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 + +# Print the top N most executed functions in QEMU using perf. +# Syntax: +# topN_perf.py [-h] [-n] -- \ +# [] \ +# [] +# +# [-h] - Print the script arguments help message. +# [-n] - Specify the number of top functions to print. +# - If this flag is not specified, the tool defaults to 25. +# +# Example of usage: +# topN_perf.py -n 20 -- qemu-arm coulomb_double-arm +# +# This file is a part of the project "TCG Continuous Benchmarking". +# +# Copyright (C) 2020 Ahmed Karaman +# Copyright (C) 2020 Aleksandar Markovic +# +# 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 . + +import argparse +import os +import subprocess +import sys + + +# Parse the command line arguments +parser = argparse.ArgumentParser( + usage='topN_perf.py [-h] [-n] -- ' + ' [] ' + ' []') + +parser.add_argument('-n', dest='top', type=int, default=25, + help='Specify the number of top functions to print.') + +parser.add_argument('command', type=str, nargs='+', help=argparse.SUPPRESS) + +args = parser.parse_args() + +# Extract the needed variables from the args +command = args.command +top = args.top + +# Insure that perf is installed +check_perf_presence = subprocess.run(["which", "perf"], + stdout=subprocess.DEVNULL) +if check_perf_presence.returncode: + sys.exit("Please install perf before running the script!") + +# Insure user has previllage to run perf +check_perf_executability = subprocess.run(["perf", "stat", "ls", "/"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) +if check_perf_executability.returncode: + sys.exit( +""" +Error: +You may not have permission to collect stats. + +Consider tweaking /proc/sys/kernel/perf_event_paranoid, +which controls use of the performance events system by +unprivileged users (without CAP_SYS_ADMIN). + + -1: Allow use of (almost) all events by all users + Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK + 0: Disallow ftrace function tracepoint by users without CAP_SYS_ADMIN + Disallow raw tracepoint access by users without CAP_SYS_ADMIN + 1: Disallow CPU event access by users without CAP_SYS_ADMIN + 2: Disallow kernel profiling by users without CAP_SYS_ADMIN + +To make this setting permanent, edit /etc/sysctl.conf too, e.g.: + kernel.perf_event_paranoid = -1 + +* Alternatively, you can run this script under sudo privileges. +""" +) + +# Run perf record +perf_record = subprocess.run((["perf", "record", "--output=/tmp/perf.data"] + + command), + stdout=subprocess.DEVNULL, + stderr=subprocess.PIPE) +if perf_record.returncode: + os.unlink('/tmp/perf.data') + sys.exit(perf_record.stderr.decode("utf-8")) + +# Save perf report output to /tmp/perf_report.out +with open("/tmp/perf_report.out", "w") as output: + perf_report = subprocess.run( + ["perf", "report", "--input=/tmp/perf.data", "--stdio"], + stdout=output, + stderr=subprocess.PIPE) + if perf_report.returncode: + os.unlink('/tmp/perf.data') + output.close() + os.unlink('/tmp/perf_report.out') + sys.exit(perf_report.stderr.decode("utf-8")) + +# Read the reported data to functions[] +functions = [] +with open("/tmp/perf_report.out", "r") as data: + # Only read lines that are not comments (comments start with #) + # Only read lines that are not empty + functions = [line for line in data.readlines() if line and line[0] + != '#' and line[0] != "\n"] + +# Limit the number of top functions to "top" +number_of_top_functions = top if len(functions) > top else len(functions) + +# Store the data of the top functions in top_functions[] +top_functions = functions[:number_of_top_functions] + +# Print table header +print('{:>4} {:>10} {:<30} {}\n{} {} {} {}'.format('No.', + 'Percentage', + 'Name', + 'Invoked by', + '-' * 4, + '-' * 10, + '-' * 30, + '-' * 25)) + +# Print top N functions +for (index, function) in enumerate(top_functions, start=1): + function_data = function.split() + function_percentage = function_data[0] + function_name = function_data[-1] + function_invoker = ' '.join(function_data[2:-2]) + print('{:>4} {:>10} {:<30} {}'.format(index, + function_percentage, + function_name, + function_invoker)) + +# Remove intermediate files +os.unlink('/tmp/perf.data') +os.unlink('/tmp/perf_report.out') From 5c362ccfdec5fa8e6e43d0d5e82a600b34b8e6d2 Mon Sep 17 00:00:00 2001 From: Ahmed Karaman Date: Fri, 26 Jun 2020 18:45:45 +0200 Subject: [PATCH 1719/2595] scripts/performance: Add topN_callgrind.py script Python script that prints the top N most executed functions in QEMU using callgrind. Syntax: topN_callgrind.py [-h] [-n] -- \ [] \ [] [-h] - Print the script arguments help message. [-n] - Specify the number of top functions to print. - If this flag is not specified, the tool defaults to 25. Example of usage: topN_callgrind.py -n 20 -- qemu-arm coulomb_double-arm Example Output: No. Percentage Function Name Source File ---- --------- ------------------ ------------------------------ 1 24.577% 0x00000000082db000 ??? 2 20.467% float64_mul /fpu/softfloat.c 3 14.720% float64_sub /fpu/softfloat.c 4 13.864% float64_add /fpu/softfloat.c 5 4.876% helper_mulsd /target/i386/ops_sse.h 6 3.767% helper_subsd /target/i386/ops_sse.h 7 3.549% helper_addsd /target/i386/ops_sse.h 8 2.185% helper_ucomisd /target/i386/ops_sse.h 9 1.667% helper_lookup_tb_ptr /include/exec/tb-lookup.h 10 1.662% f64_compare /fpu/softfloat.c 11 1.509% helper_lookup_tb_ptr /accel/tcg/tcg-runtime.c 12 0.635% helper_lookup_tb_ptr /include/exec/exec-all.h 13 0.616% float64_div /fpu/softfloat.c 14 0.502% helper_pand_xmm /target/i386/ops_sse.h 15 0.502% float64_mul /include/fpu/softfloat.h 16 0.476% helper_lookup_tb_ptr /target/i386/cpu.h 17 0.437% float64_compare_quiet /fpu/softfloat.c 18 0.414% helper_pxor_xmm /target/i386/ops_sse.h 19 0.353% round_to_int /fpu/softfloat.c 20 0.347% helper_cc_compute_all /target/i386/cc_helper.c Signed-off-by: Ahmed Karaman Signed-off-by: Aleksandar Markovic Reviewed-by: Aleksandar Markovic Message-Id: <20200626164546.22102-3-ahmedkhaledkaraman@gmail.com> --- scripts/performance/topN_callgrind.py | 140 ++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100755 scripts/performance/topN_callgrind.py diff --git a/scripts/performance/topN_callgrind.py b/scripts/performance/topN_callgrind.py new file mode 100755 index 0000000000..67c59197af --- /dev/null +++ b/scripts/performance/topN_callgrind.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 + +# Print the top N most executed functions in QEMU using callgrind. +# Syntax: +# topN_callgrind.py [-h] [-n] -- \ +# [] \ +# [] +# +# [-h] - Print the script arguments help message. +# [-n] - Specify the number of top functions to print. +# - If this flag is not specified, the tool defaults to 25. +# +# Example of usage: +# topN_callgrind.py -n 20 -- qemu-arm coulomb_double-arm +# +# This file is a part of the project "TCG Continuous Benchmarking". +# +# Copyright (C) 2020 Ahmed Karaman +# Copyright (C) 2020 Aleksandar Markovic +# +# 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 . + +import argparse +import os +import subprocess +import sys + + +# Parse the command line arguments +parser = argparse.ArgumentParser( + usage='topN_callgrind.py [-h] [-n] -- ' + ' [] ' + ' []') + +parser.add_argument('-n', dest='top', type=int, default=25, + help='Specify the number of top functions to print.') + +parser.add_argument('command', type=str, nargs='+', help=argparse.SUPPRESS) + +args = parser.parse_args() + +# Extract the needed variables from the args +command = args.command +top = args.top + +# Insure that valgrind is installed +check_valgrind_presence = subprocess.run(["which", "valgrind"], + stdout=subprocess.DEVNULL) +if check_valgrind_presence.returncode: + sys.exit("Please install valgrind before running the script!") + +# Run callgrind +callgrind = subprocess.run(( + ["valgrind", "--tool=callgrind", "--callgrind-out-file=/tmp/callgrind.data"] + + command), + stdout=subprocess.DEVNULL, + stderr=subprocess.PIPE) +if callgrind.returncode: + sys.exit(callgrind.stderr.decode("utf-8")) + +# Save callgrind_annotate output to /tmp/callgrind_annotate.out +with open("/tmp/callgrind_annotate.out", "w") as output: + callgrind_annotate = subprocess.run(["callgrind_annotate", + "/tmp/callgrind.data"], + stdout=output, + stderr=subprocess.PIPE) + if callgrind_annotate.returncode: + os.unlink('/tmp/callgrind.data') + output.close() + os.unlink('/tmp/callgrind_annotate.out') + sys.exit(callgrind_annotate.stderr.decode("utf-8")) + +# Read the callgrind_annotate output to callgrind_data[] +callgrind_data = [] +with open('/tmp/callgrind_annotate.out', 'r') as data: + callgrind_data = data.readlines() + +# Line number with the total number of instructions +total_instructions_line_number = 20 + +# Get the total number of instructions +total_instructions_line_data = callgrind_data[total_instructions_line_number] +total_number_of_instructions = total_instructions_line_data.split(' ')[0] +total_number_of_instructions = int( + total_number_of_instructions.replace(',', '')) + +# Line number with the top function +first_func_line = 25 + +# Number of functions recorded by callgrind, last two lines are always empty +number_of_functions = len(callgrind_data) - first_func_line - 2 + +# Limit the number of top functions to "top" +number_of_top_functions = (top if number_of_functions > + top else number_of_functions) + +# Store the data of the top functions in top_functions[] +top_functions = callgrind_data[first_func_line: + first_func_line + number_of_top_functions] + +# Print table header +print('{:>4} {:>10} {:<30} {}\n{} {} {} {}'.format('No.', + 'Percentage', + 'Function Name', + 'Source File', + '-' * 4, + '-' * 10, + '-' * 30, + '-' * 30, + )) + +# Print top N functions +for (index, function) in enumerate(top_functions, start=1): + function_data = function.split() + # Calculate function percentage + function_instructions = float(function_data[0].replace(',', '')) + function_percentage = (function_instructions / + total_number_of_instructions)*100 + # Get function name and source files path + function_source_file, function_name = function_data[1].split(':') + # Print extracted data + print('{:>4} {:>9.3f}% {:<30} {}'.format(index, + round(function_percentage, 3), + function_name, + function_source_file)) + +# Remove intermediate files +os.unlink('/tmp/callgrind.data') +os.unlink('/tmp/callgrind_annotate.out') From 53fb8bfb93487c0fd88b0babb9a52ec8d67cff7b Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 27 Jun 2020 20:13:17 +0200 Subject: [PATCH 1720/2595] MAINTAINERS: Add 'Performance Tools and Tests' subsection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit creates a new 'Miscellaneous' section which hosts a new 'Performance Tools and Tests' subsection. This subsection will contain the the performance scripts and benchmarks written as a part of the 'TCG Continuous Benchmarking' project. Also, it will be a placeholder for follow-ups to this project, if any. Signed-off-by: Ahmed Karaman Reviewed-by: Alex Bennée Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: <20200626164546.22102-4-ahmedkhaledkaraman@gmail.com> --- MAINTAINERS | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index fe925ea661..dec252f38b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1096,11 +1096,10 @@ F: hw/isa/vt82c686.c F: hw/pci-host/bonito.c F: include/hw/isa/vt82c686.h -Loongson-3 Virtual Platform +Loongson-3 virtual platforms M: Huacai Chen R: Jiaxun Yang S: Maintained -F: hw/mips/loongson3_virt.c F: hw/intc/loongson_liointc.c Boston @@ -3026,3 +3025,10 @@ M: Peter Maydell S: Maintained F: docs/conf.py F: docs/*/conf.py + +Miscellaneous +------------- +Performance Tools and Tests +M: Ahmed Karaman +S: Maintained +F: scripts/performance/ From aa04c9d9ef962d516af5ca89667de4282d1c22ef Mon Sep 17 00:00:00 2001 From: Giuseppe Musacchio Date: Thu, 25 Jun 2020 11:12:03 +0200 Subject: [PATCH 1721/2595] target/sparc: Translate flushw opcode The ifdef logic should unconditionally compile in the `xop == 0x2b` case when targeting sparc64. Signed-off-by: Giuseppe Musacchio Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20200625091204.3186186-2-laurent@vivier.eu> --- target/sparc/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 9416a551cf..1a4efd4ed6 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -3663,6 +3663,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #endif gen_store_gpr(dc, rd, cpu_tmp0); break; +#endif +#if defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY) } else if (xop == 0x2b) { /* rdtbr / V9 flushw */ #ifdef TARGET_SPARC64 gen_helper_flushw(cpu_env); From d43624c400597aec18dff917c1424b807bbb473d Mon Sep 17 00:00:00 2001 From: Giuseppe Musacchio Date: Thu, 25 Jun 2020 11:12:04 +0200 Subject: [PATCH 1722/2595] linux-user/sparc64: Fix the handling of window spill trap Fix the handling of window spill traps by keeping cansave into account when calculating the new CWP. Signed-off-by: Giuseppe Musacchio Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20200625091204.3186186-3-laurent@vivier.eu> --- bsd-user/main.c | 6 +++++- linux-user/sparc/cpu_loop.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 0bfe46cff9..ac40d79bfa 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -413,7 +413,11 @@ static void save_window(CPUSPARCState *env) save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); env->wim = new_wim; #else - save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); + /* + * cansave is zero if the spill trap handler is triggered by `save` and + * nonzero if triggered by a `flushw` + */ + save_window_offset(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2)); env->cansave++; env->canrestore--; #endif diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index 7645cc04ca..02532f198d 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -69,7 +69,11 @@ static void save_window(CPUSPARCState *env) save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); env->wim = new_wim; #else - save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); + /* + * cansave is zero if the spill trap handler is triggered by `save` and + * nonzero if triggered by a `flushw` + */ + save_window_offset(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2)); env->cansave++; env->canrestore--; #endif From e865b97ff4d924a81c28b9d9f3d6fe3e198bcdb9 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Fri, 5 Jun 2020 09:32:21 +0800 Subject: [PATCH 1723/2595] linux-user: syscall: ioctls: support DRM_IOCTL_VERSION Another DRM_IOCTL_* commands will be done later. Signed-off-by: Chen Gang Reviewed-by: Laurent Vivier Message-Id: <20200605013221.22828-1-chengang@emindsoft.com.cn> Signed-off-by: Laurent Vivier --- configure | 10 ++++ linux-user/ioctls.h | 5 ++ linux-user/syscall.c | 98 ++++++++++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 15 ++++++ linux-user/syscall_types.h | 11 +++++ 5 files changed, 139 insertions(+) diff --git a/configure b/configure index 4a22dcd563..2014c72b67 100755 --- a/configure +++ b/configure @@ -3194,6 +3194,13 @@ if ! check_include "ifaddrs.h" ; then have_ifaddrs_h=no fi +######################################### +# libdrm check +have_drm_h=no +if check_include "libdrm/drm.h" ; then + have_drm_h=yes +fi + ########################################## # VTE probe @@ -7377,6 +7384,9 @@ fi if test "$have_ifaddrs_h" = "yes" ; then echo "HAVE_IFADDRS_H=y" >> $config_host_mak fi +if test "$have_drm_h" = "yes" ; then + echo "HAVE_DRM_H=y" >> $config_host_mak +fi if test "$have_broken_size_max" = "yes" ; then echo "HAVE_BROKEN_SIZE_MAX=y" >> $config_host_mak fi diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 0defa1d8c1..f2e2fa9c87 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -574,6 +574,11 @@ IOCTL_SPECIAL(SIOCDELRT, IOC_W, do_ioctl_rt, MK_PTR(MK_STRUCT(STRUCT_rtentry))) +#ifdef HAVE_DRM_H + IOCTL_SPECIAL(DRM_IOCTL_VERSION, IOC_RW, do_ioctl_drm, + MK_PTR(MK_STRUCT(STRUCT_drm_version))) +#endif + #ifdef TARGET_TIOCSTART IOCTL_IGNORE(TIOCSTART) IOCTL_IGNORE(TIOCSTOP) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 97de9fb5c9..17ed7f8d6b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -112,6 +112,9 @@ #include #include #include +#ifdef HAVE_DRM_H +#include +#endif #include "linux_loop.h" #include "uname.h" @@ -5276,6 +5279,101 @@ static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp, } #endif +#ifdef HAVE_DRM_H + +static void unlock_drm_version(struct drm_version *host_ver, + struct target_drm_version *target_ver, + bool copy) +{ + unlock_user(host_ver->name, target_ver->name, + copy ? host_ver->name_len : 0); + unlock_user(host_ver->date, target_ver->date, + copy ? host_ver->date_len : 0); + unlock_user(host_ver->desc, target_ver->desc, + copy ? host_ver->desc_len : 0); +} + +static inline abi_long target_to_host_drmversion(struct drm_version *host_ver, + struct target_drm_version *target_ver) +{ + memset(host_ver, 0, sizeof(*host_ver)); + + __get_user(host_ver->name_len, &target_ver->name_len); + if (host_ver->name_len) { + host_ver->name = lock_user(VERIFY_WRITE, target_ver->name, + target_ver->name_len, 0); + if (!host_ver->name) { + return -EFAULT; + } + } + + __get_user(host_ver->date_len, &target_ver->date_len); + if (host_ver->date_len) { + host_ver->date = lock_user(VERIFY_WRITE, target_ver->date, + target_ver->date_len, 0); + if (!host_ver->date) { + goto err; + } + } + + __get_user(host_ver->desc_len, &target_ver->desc_len); + if (host_ver->desc_len) { + host_ver->desc = lock_user(VERIFY_WRITE, target_ver->desc, + target_ver->desc_len, 0); + if (!host_ver->desc) { + goto err; + } + } + + return 0; +err: + unlock_drm_version(host_ver, target_ver, false); + return -EFAULT; +} + +static inline void host_to_target_drmversion( + struct target_drm_version *target_ver, + struct drm_version *host_ver) +{ + __put_user(host_ver->version_major, &target_ver->version_major); + __put_user(host_ver->version_minor, &target_ver->version_minor); + __put_user(host_ver->version_patchlevel, &target_ver->version_patchlevel); + __put_user(host_ver->name_len, &target_ver->name_len); + __put_user(host_ver->date_len, &target_ver->date_len); + __put_user(host_ver->desc_len, &target_ver->desc_len); + unlock_drm_version(host_ver, target_ver, true); +} + +static abi_long do_ioctl_drm(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, int cmd, abi_long arg) +{ + struct drm_version *ver; + struct target_drm_version *target_ver; + abi_long ret; + + switch (ie->host_cmd) { + case DRM_IOCTL_VERSION: + if (!lock_user_struct(VERIFY_WRITE, target_ver, arg, 0)) { + return -TARGET_EFAULT; + } + ver = (struct drm_version *)buf_temp; + ret = target_to_host_drmversion(ver, target_ver); + if (!is_error(ret)) { + ret = get_errno(safe_ioctl(fd, ie->host_cmd, ver)); + if (is_error(ret)) { + unlock_drm_version(ver, target_ver, false); + } else { + host_to_target_drmversion(target_ver, ver); + } + } + unlock_user_struct(target_ver, arg, 0); + return ret; + } + return -TARGET_ENOSYS; +} + +#endif + static IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 152ec637cb..3c261cff0e 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1167,6 +1167,9 @@ struct target_rtc_pll_info { #define TARGET_DM_TARGET_MSG TARGET_IOWRU(0xfd, 0x0e) #define TARGET_DM_DEV_SET_GEOMETRY TARGET_IOWRU(0xfd, 0x0f) +/* drm ioctls */ +#define TARGET_DRM_IOCTL_VERSION TARGET_IOWRU('d', 0x00) + /* from asm/termbits.h */ #define TARGET_NCC 8 @@ -2598,6 +2601,18 @@ struct target_mq_attr { abi_long mq_curmsgs; }; +struct target_drm_version { + int version_major; + int version_minor; + int version_patchlevel; + abi_ulong name_len; + abi_ulong name; + abi_ulong date_len; + abi_ulong date; + abi_ulong desc_len; + abi_ulong desc; +}; + #include "socket.h" #include "errno_defs.h" diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 4e12c1661e..e2b0484f50 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -292,6 +292,17 @@ STRUCT(dm_target_versions, STRUCT(dm_target_msg, TYPE_ULONGLONG) /* sector */ +STRUCT(drm_version, + TYPE_INT, /* version_major */ + TYPE_INT, /* version_minor */ + TYPE_INT, /* version_patchlevel */ + TYPE_ULONG, /* name_len */ + TYPE_PTRVOID, /* name */ + TYPE_ULONG, /* date_len */ + TYPE_PTRVOID, /* date */ + TYPE_ULONG, /* desc_len */ + TYPE_PTRVOID) /* desc */ + STRUCT(file_clone_range, TYPE_LONGLONG, /* src_fd */ TYPE_ULONGLONG, /* src_offset */ From c84be71f685436fd7216a159528421c3d7af8d05 Mon Sep 17 00:00:00 2001 From: Filip Bozuta Date: Fri, 19 Jun 2020 14:33:26 +0200 Subject: [PATCH 1724/2595] linux-user: Extend strace support to enable argument printing after syscall execution Structure "struct syscallname" in file "strace.c" is used for "-strace" to print arguments and return values of syscalls. The last field of this structure "result" represents the calling function that prints the return values. This field was extended in this patch so that this function takes all syscalls arguments beside the return value. In this way, it enables "-strace" to print arguments of syscalls that have changed after the syscall execution. This extension will be useful as there are many syscalls that return values inside their arguments (i.e. listxattr() that returns the list of extended attributes inside the "list" argument). Implementation notes: Since there are already three existing "print_syscall_ret*" functions inside "strace.c" ("print_syscall_ret_addr()", "print_syscall_ret_adjtimex()", "print_syscall_ret_newselect()"), they were changed to have all syscall arguments beside the return value. This was done so that these functions don't cause build errors (even though syscall arguments are not used in these functions). There is code repetition in these functions for checking the return value and printing the approppriate error message (this code is also located in print_syscall_ret() at the end of "strace.c"). That is the reason why a function "syscall_print_err()" was added for this code and put inside these functions. Functions "print_newselect()" and "print_syscall_ret_newselect()" were changed to use this new implemented functionality and not store the syscall argument values in separate static variables. Signed-off-by: Filip Bozuta Reviewed-by: Laurent Vivier Message-Id: <20200619123331.17387-2-filip.bozuta@syrmia.com> Signed-off-by: Laurent Vivier --- linux-user/qemu.h | 4 +- linux-user/strace.c | 108 ++++++++++++++++++++++--------------------- linux-user/syscall.c | 2 +- 3 files changed, 60 insertions(+), 54 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index ce902f5132..8f938b8105 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -383,7 +383,9 @@ int host_to_target_waitstatus(int status); void print_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6); -void print_syscall_ret(int num, abi_long arg1); +void print_syscall_ret(int num, abi_long ret, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6); /** * print_taken_signal: * @target_signum: target signal being taken diff --git a/linux-user/strace.c b/linux-user/strace.c index 0d9095c674..62117e8555 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -19,7 +19,9 @@ struct syscallname { void (*call)(const struct syscallname *, abi_long, abi_long, abi_long, abi_long, abi_long, abi_long); - void (*result)(const struct syscallname *, abi_long); + void (*result)(const struct syscallname *, abi_long, + abi_long, abi_long, abi_long, + abi_long, abi_long, abi_long); }; #ifdef __GNUC__ @@ -631,18 +633,12 @@ print_clockid(int clockid, int last) /* select */ #ifdef TARGET_NR__newselect -static long newselect_arg1 = 0; -static long newselect_arg2 = 0; -static long newselect_arg3 = 0; -static long newselect_arg4 = 0; -static long newselect_arg5 = 0; - static void print_newselect(const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { - qemu_log("%s(" TARGET_ABI_FMT_ld ",", name->name, arg1); + print_syscall_prologue(name); print_fdset(arg1, arg2); qemu_log(","); print_fdset(arg1, arg3); @@ -650,14 +646,7 @@ print_newselect(const struct syscallname *name, print_fdset(arg1, arg4); qemu_log(","); print_timeval(arg5, 1); - qemu_log(")"); - - /* save for use in the return output function below */ - newselect_arg1=arg1; - newselect_arg2=arg2; - newselect_arg3=arg3; - newselect_arg4=arg4; - newselect_arg5=arg5; + print_syscall_epilogue(name); } #endif @@ -736,17 +725,29 @@ print_ipc(const struct syscallname *name, */ static void -print_syscall_ret_addr(const struct syscallname *name, abi_long ret) +print_syscall_err(abi_long ret) { const char *errstr = NULL; + qemu_log(" = "); if (ret < 0) { + qemu_log("-1 errno=%d", errno); errstr = target_strerror(-ret); + if (errstr) { + qemu_log(" (%s)", errstr); + } } - if (errstr) { - qemu_log(" = -1 errno=%d (%s)\n", (int)-ret, errstr); - } else { - qemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); +} + +static void +print_syscall_ret_addr(const struct syscallname *name, abi_long ret, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_err(ret); + + if (ret >= 0) { + qemu_log("0x" TARGET_ABI_FMT_lx "\n", ret); } } @@ -760,17 +761,25 @@ print_syscall_ret_raw(struct syscallname *name, abi_long ret) #ifdef TARGET_NR__newselect static void -print_syscall_ret_newselect(const struct syscallname *name, abi_long ret) +print_syscall_ret_newselect(const struct syscallname *name, abi_long ret, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) { - qemu_log(" = 0x" TARGET_ABI_FMT_lx " (", ret); - print_fdset(newselect_arg1,newselect_arg2); - qemu_log(","); - print_fdset(newselect_arg1,newselect_arg3); - qemu_log(","); - print_fdset(newselect_arg1,newselect_arg4); - qemu_log(","); - print_timeval(newselect_arg5, 1); - qemu_log(")\n"); + print_syscall_err(ret); + + if (ret >= 0) { + qemu_log(" = 0x" TARGET_ABI_FMT_lx " (", ret); + print_fdset(arg0, arg1); + qemu_log(","); + print_fdset(arg0, arg2); + qemu_log(","); + print_fdset(arg0, arg3); + qemu_log(","); + print_timeval(arg4, 1); + qemu_log(")"); + } + + qemu_log("\n"); } #endif @@ -783,18 +792,13 @@ print_syscall_ret_newselect(const struct syscallname *name, abi_long ret) #define TARGET_TIME_ERROR 5 /* clock not synchronized */ #ifdef TARGET_NR_adjtimex static void -print_syscall_ret_adjtimex(const struct syscallname *name, abi_long ret) +print_syscall_ret_adjtimex(const struct syscallname *name, abi_long ret, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) { - const char *errstr = NULL; + print_syscall_err(ret); - qemu_log(" = "); - if (ret < 0) { - qemu_log("-1 errno=%d", errno); - errstr = target_strerror(-ret); - if (errstr) { - qemu_log(" (%s)", errstr); - } - } else { + if (ret >= 0) { qemu_log(TARGET_ABI_FMT_ld, ret); switch (ret) { case TARGET_TIME_OK: @@ -2847,25 +2851,25 @@ print_syscall(int num, void -print_syscall_ret(int num, abi_long ret) +print_syscall_ret(int num, abi_long ret, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) { int i; - const char *errstr = NULL; for(i=0;i= 0) { + qemu_log(TARGET_ABI_FMT_ld, ret); } + qemu_log("\n"); } break; } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 17ed7f8d6b..1b971c06b2 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -12565,7 +12565,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, arg5, arg6, arg7, arg8); if (unlikely(qemu_loglevel_mask(LOG_STRACE))) { - print_syscall_ret(num, ret); + print_syscall_ret(num, ret, arg1, arg2, arg3, arg4, arg5, arg6); } record_syscall_return(cpu, num, ret); From c42569f65c1c5302fb110488ad27423a948e5a7f Mon Sep 17 00:00:00 2001 From: Filip Bozuta Date: Fri, 19 Jun 2020 14:33:27 +0200 Subject: [PATCH 1725/2595] linux-user: Add strace support for a group of syscalls This patch implements strace argument printing functionality for following syscalls: *acct - switch process accounting on or off int acct(const char *filename) man page: https://www.man7.org/linux/man-pages/man2/acct.2.html *fsync, fdatasync - synchronize a file's in-core state with storage device int fsync(int fd) int fdatasync(int fd) man page: https://www.man7.org/linux/man-pages/man2/fsync.2.html *listen - listen for connections on a socket int listen(int sockfd, int backlog) man page: https://www.man7.org/linux/man-pages/man2/listen.2.html Implementation notes: Syscall acct() takes string as its only argument and thus a separate print function "print_acct" is stated in file "strace.list". This function is defined and implemented in "strace.c" by using an existing function used to print string arguments: "print_string()". All the other syscalls have only primitive argument types, so the rest of the implementation was handled by stating an appropriate printing format in file "strace.list". Signed-off-by: Filip Bozuta Reviewed-by: Laurent Vivier Message-Id: <20200619123331.17387-3-filip.bozuta@syrmia.com> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 13 ++++++++++++- linux-user/strace.list | 8 ++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 62117e8555..123e022c35 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1357,6 +1357,18 @@ print_access(const struct syscallname *name, } #endif +#ifdef TARGET_NR_acct +static void +print_acct(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 1); + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_brk static void print_brk(const struct syscallname *name, @@ -1621,7 +1633,6 @@ print_fcntl(const struct syscallname *name, #define print_fcntl64 print_fcntl #endif - #ifdef TARGET_NR_futimesat static void print_futimesat(const struct syscallname *name, diff --git a/linux-user/strace.list b/linux-user/strace.list index 9281c0a758..8a887fc16d 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -13,7 +13,7 @@ { TARGET_NR_access, "access" , NULL, print_access, NULL }, #endif #ifdef TARGET_NR_acct -{ TARGET_NR_acct, "acct" , NULL, NULL, NULL }, +{ TARGET_NR_acct, "acct" , NULL, print_acct, NULL }, #endif #ifdef TARGET_NR_add_key { TARGET_NR_add_key, "add_key" , NULL, NULL, NULL }, @@ -215,7 +215,7 @@ { TARGET_NR_fcntl64, "fcntl64" , NULL, print_fcntl64, NULL }, #endif #ifdef TARGET_NR_fdatasync -{ TARGET_NR_fdatasync, "fdatasync" , NULL, NULL, NULL }, +{ TARGET_NR_fdatasync, "fdatasync" , "%s(%d)", NULL, NULL }, #endif #ifdef TARGET_NR_fgetxattr { TARGET_NR_fgetxattr, "fgetxattr" , NULL, NULL, NULL }, @@ -251,7 +251,7 @@ { TARGET_NR_fstatfs64, "fstatfs64" , "%s(%d,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_fsync -{ TARGET_NR_fsync, "fsync" , NULL, NULL, NULL }, +{ TARGET_NR_fsync, "fsync" , "%s(%d)", NULL, NULL }, #endif #ifdef TARGET_NR_ftime { TARGET_NR_ftime, "ftime" , NULL, NULL, NULL }, @@ -492,7 +492,7 @@ { TARGET_NR_Linux, "Linux" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_listen -{ TARGET_NR_listen, "listen" , NULL, NULL, NULL }, +{ TARGET_NR_listen, "listen" , "%s(%d,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_listxattr { TARGET_NR_listxattr, "listxattr" , NULL, NULL, NULL }, From 4fc3cdde40f977ee8deecf988eea7acfa373117a Mon Sep 17 00:00:00 2001 From: Filip Bozuta Date: Fri, 19 Jun 2020 14:33:28 +0200 Subject: [PATCH 1726/2595] linux-user: Add strace support for printing argument of syscalls used for extended attributes This patch implements strace argument printing functionality for following syscalls: *getxattr, lgetxattr, fgetxattr - retrieve an extended attribute value ssize_t getxattr(const char *path, const char *name, void *value, size_t size) ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size) ssize_t fgetxattr(int fd, const char *name, void *value, size_t size) man page: https://www.man7.org/linux/man-pages/man2/getxattr.2.html *listxattr, llistxattr, flistxattr - list extended attribute names ssize_t listxattr(const char *path, char *list, size_t size) ssize_t llistxattr(const char *path, char *list, size_t size) ssize_t flistxattr(int fd, char *list, size_t size) man page: https://www.man7.org/linux/man-pages/man2/listxattr.2.html *removexattr, lremovexattr, fremovexattr - remove an extended attribute int removexattr(const char *path, const char *name) int lremovexattr(const char *path, const char *name) int fremovexattr(int fd, const char *name) man page: https://www.man7.org/linux/man-pages/man2/removexattr.2.html Implementation notes: All of the syscalls have strings as argument types and thus a separate printing function was stated in file "strace.list" for every one of them. All of these printing functions were defined in "strace.c" using existing printing functions for appropriate argument types: "print_string()" - for (const char*) type "print_pointer()" - for (char*) and (void *) type "print_raw_param()" for (int) and (size_t) type Syscalls "getxattr()" and "lgetxattr()" have the same number and type of arguments and thus their print functions ("print_getxattr", "print_lgetxattr") share a same definition. The same statement applies to syscalls "listxattr()" and "llistxattr()". Function "print_syscall_ret_listxattr()" was added to print the returned list of extended attributes for syscalls "print_listxattr(), print_llistxattr() and print_flistxattr()". Signed-off-by: Filip Bozuta Reviewed-by: Laurent Vivier Message-Id: <20200619123331.17387-4-filip.bozuta@syrmia.com> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 121 +++++++++++++++++++++++++++++++++++++++++ linux-user/strace.list | 21 ++++--- 2 files changed, 133 insertions(+), 9 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 123e022c35..760020132b 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -826,6 +826,40 @@ print_syscall_ret_adjtimex(const struct syscallname *name, abi_long ret, } #endif +#if defined(TARGET_NR_listxattr) || defined(TARGET_NR_llistxattr) \ + || defined(TARGGET_NR_flistxattr) +static void +print_syscall_ret_listxattr(const struct syscallname *name, abi_long ret, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_err(ret); + + if (ret >= 0) { + qemu_log(TARGET_ABI_FMT_ld, ret); + qemu_log(" (list = "); + if (arg1 != 0) { + abi_long attr = arg1; + while (ret) { + if (attr != arg1) { + qemu_log(","); + } + print_string(attr, 1); + ret -= target_strlen(attr) + 1; + attr += target_strlen(attr) + 1; + } + } else { + qemu_log("NULL"); + } + qemu_log(")"); + } + + qemu_log("\n"); +} +#define print_syscall_ret_llistxattr print_syscall_ret_listxattr +#define print_syscall_ret_flistxattr print_syscall_ret_listxattr +#endif + UNUSED static struct flags access_flags[] = { FLAG_GENERIC(F_OK), FLAG_GENERIC(R_OK), @@ -1633,6 +1667,93 @@ print_fcntl(const struct syscallname *name, #define print_fcntl64 print_fcntl #endif +#ifdef TARGET_NR_fgetxattr +static void +print_fgetxattr(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_raw_param("%d", arg0, 0); + print_string(arg1, 0); + print_pointer(arg2, 0); + print_raw_param(TARGET_FMT_lu, arg3, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_flistxattr +static void +print_flistxattr(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_raw_param("%d", arg0, 0); + print_pointer(arg1, 0); + print_raw_param(TARGET_FMT_lu, arg2, 1); + print_syscall_epilogue(name); +} +#endif + +#if defined(TARGET_NR_getxattr) || defined(TARGET_NR_lgetxattr) +static void +print_getxattr(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_string(arg1, 0); + print_pointer(arg2, 0); + print_raw_param(TARGET_FMT_lu, arg3, 1); + print_syscall_epilogue(name); +} +#define print_lgetxattr print_getxattr +#endif + +#if defined(TARGET_NR_listxattr) || defined(TARGET_NR_llistxattr) +static void +print_listxattr(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_pointer(arg1, 0); + print_raw_param(TARGET_FMT_lu, arg2, 1); + print_syscall_epilogue(name); +} +#define print_llistxattr print_listxattr +#endif + +#if defined(TARGET_NR_fremovexattr) +static void +print_fremovexattr(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_raw_param("%d", arg0, 0); + print_string(arg1, 1); + print_syscall_epilogue(name); +} +#endif + +#if defined(TARGET_NR_removexattr) || defined(TARGET_NR_lremovexattr) +static void +print_removexattr(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_string(arg1, 1); + print_syscall_epilogue(name); +} +#define print_lremovexattr print_removexattr +#endif + #ifdef TARGET_NR_futimesat static void print_futimesat(const struct syscallname *name, diff --git a/linux-user/strace.list b/linux-user/strace.list index 8a887fc16d..d04ad507b0 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -218,13 +218,14 @@ { TARGET_NR_fdatasync, "fdatasync" , "%s(%d)", NULL, NULL }, #endif #ifdef TARGET_NR_fgetxattr -{ TARGET_NR_fgetxattr, "fgetxattr" , NULL, NULL, NULL }, +{ TARGET_NR_fgetxattr, "fgetxattr" , NULL, print_fgetxattr, NULL }, #endif #ifdef TARGET_NR_finit_module { TARGET_NR_finit_module, "finit_module" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_flistxattr -{ TARGET_NR_flistxattr, "flistxattr" , NULL, NULL, NULL }, +{ TARGET_NR_flistxattr, "flistxattr" , NULL, print_flistxattr, + print_syscall_ret_flistxattr}, #endif #ifdef TARGET_NR_flock { TARGET_NR_flock, "flock" , NULL, NULL, NULL }, @@ -233,7 +234,7 @@ { TARGET_NR_fork, "fork" , "%s()", NULL, NULL }, #endif #ifdef TARGET_NR_fremovexattr -{ TARGET_NR_fremovexattr, "fremovexattr" , NULL, NULL, NULL }, +{ TARGET_NR_fremovexattr, "fremovexattr" , NULL, print_fremovexattr, NULL }, #endif #ifdef TARGET_NR_fsetxattr { TARGET_NR_fsetxattr, "fsetxattr" , NULL, NULL, NULL }, @@ -396,7 +397,7 @@ { TARGET_NR_getuid32, "getuid32" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_getxattr -{ TARGET_NR_getxattr, "getxattr" , NULL, NULL, NULL }, +{ TARGET_NR_getxattr, "getxattr" , NULL, print_getxattr, NULL }, #endif #ifdef TARGET_NR_getxgid { TARGET_NR_getxgid, "getxgid" , NULL, NULL, NULL }, @@ -480,7 +481,7 @@ { TARGET_NR_lchown32, "lchown32" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_lgetxattr -{ TARGET_NR_lgetxattr, "lgetxattr" , NULL, NULL, NULL }, +{ TARGET_NR_lgetxattr, "lgetxattr" , NULL, print_lgetxattr, NULL }, #endif #ifdef TARGET_NR_link { TARGET_NR_link, "link" , NULL, print_link, NULL }, @@ -495,10 +496,12 @@ { TARGET_NR_listen, "listen" , "%s(%d,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_listxattr -{ TARGET_NR_listxattr, "listxattr" , NULL, NULL, NULL }, +{ TARGET_NR_listxattr, "listxattr" , NULL, print_listxattr, + print_syscall_ret_listxattr}, #endif #ifdef TARGET_NR_llistxattr -{ TARGET_NR_llistxattr, "llistxattr" , NULL, NULL, NULL }, +{ TARGET_NR_llistxattr, "llistxattr" , NULL, print_llistxattr, + print_syscall_ret_llistxattr}, #endif #ifdef TARGET_NR__llseek { TARGET_NR__llseek, "_llseek" , NULL, print__llseek, NULL }, @@ -510,7 +513,7 @@ { TARGET_NR_lookup_dcookie, "lookup_dcookie" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_lremovexattr -{ TARGET_NR_lremovexattr, "lremovexattr" , NULL, NULL, NULL }, +{ TARGET_NR_lremovexattr, "lremovexattr" , NULL, print_lremovexattr, NULL }, #endif #ifdef TARGET_NR_lseek { TARGET_NR_lseek, "lseek" , NULL, NULL, NULL }, @@ -1116,7 +1119,7 @@ { TARGET_NR_remap_file_pages, "remap_file_pages" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_removexattr -{ TARGET_NR_removexattr, "removexattr" , NULL, NULL, NULL }, +{ TARGET_NR_removexattr, "removexattr" , NULL, print_removexattr, NULL }, #endif #ifdef TARGET_NR_rename { TARGET_NR_rename, "rename" , NULL, print_rename, NULL }, From af861deaed5aa979522ec72425913295dc050f10 Mon Sep 17 00:00:00 2001 From: Filip Bozuta Date: Fri, 19 Jun 2020 14:33:29 +0200 Subject: [PATCH 1727/2595] linux-user: Add strace support for printing arguments of lseek() This patch implements strace argument printing functionality for syscall: *lseek - reposition read/write file offset off_t lseek(int fd, off_t offset, int whence) man page: https://www.man7.org/linux/man-pages/man2/lseek.2.html Implementation notes: The syscall's third argument "whence" has predefined values: "SEEK_SET","SEEK_CUR","SEEK_END","SEEK_DATA","SEEK_HOLE" and thus a separate printing function "print_lseek" was stated in file "strace.list". This function is defined in "strace.c" by using an existing function "print_raw_param()" to print the first and second argument and a switch(case) statement for the predefined values of the third argument. Values "SEEK_DATA" and "SEEK_HOLE" are defined in kernel version 3.1. That is the reason why case statements for these values are enwrapped in #ifdef directive. Signed-off-by: Filip Bozuta Reviewed-by: Laurent Vivier Message-Id: <20200619123331.17387-5-filip.bozuta@syrmia.com> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 31 +++++++++++++++++++++++++++++++ linux-user/strace.list | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 760020132b..a26736516b 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1833,6 +1833,37 @@ print__llseek(const struct syscallname *name, } #endif +#ifdef TARGET_NR_lseek +static void +print_lseek(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_raw_param("%d", arg0, 0); + print_raw_param(TARGET_ABI_FMT_ld, arg1, 0); + switch (arg2) { + case SEEK_SET: + qemu_log("SEEK_SET"); break; + case SEEK_CUR: + qemu_log("SEEK_CUR"); break; + case SEEK_END: + qemu_log("SEEK_END"); break; +#ifdef SEEK_DATA + case SEEK_DATA: + qemu_log("SEEK_DATA"); break; +#endif +#ifdef SEEK_HOLE + case SEEK_HOLE: + qemu_log("SEEK_HOLE"); break; +#endif + default: + print_raw_param("%#x", arg2, 1); + } + print_syscall_epilogue(name); +} +#endif + #if defined(TARGET_NR_socket) static void print_socket(const struct syscallname *name, diff --git a/linux-user/strace.list b/linux-user/strace.list index d04ad507b0..a4a8c61969 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -516,7 +516,7 @@ { TARGET_NR_lremovexattr, "lremovexattr" , NULL, print_lremovexattr, NULL }, #endif #ifdef TARGET_NR_lseek -{ TARGET_NR_lseek, "lseek" , NULL, NULL, NULL }, +{ TARGET_NR_lseek, "lseek" , NULL, print_lseek, NULL }, #endif #ifdef TARGET_NR_lsetxattr { TARGET_NR_lsetxattr, "lsetxattr" , NULL, NULL, NULL }, From 5844f4bc4111248b9de0c2efa422cafcdaa69cf1 Mon Sep 17 00:00:00 2001 From: Filip Bozuta Date: Fri, 19 Jun 2020 14:33:30 +0200 Subject: [PATCH 1728/2595] linux-user: Add strace support for printing arguments of chown()/lchown() This patch implements strace argument printing functionality for syscalls: *chown, lchown - change ownership of a file int chown(const char *pathname, uid_t owner, gid_t group) int lchown(const char *pathname, uid_t owner, gid_t group) man page: https://www.man7.org/linux/man-pages/man2/lchown.2.html Implementation notes: Both syscalls use strings as arguments and thus a separate printing function was stated in "strace.list" for them. Both syscalls share the same number and types of arguments and thus share a same definition in file "syscall.c". This defintion uses existing functions "print_string()" to print the string argument and "print_raw_param()" to print other two arguments that are of basic types. Signed-off-by: Filip Bozuta Reviewed-by: Laurent Vivier Message-Id: <20200619123331.17387-6-filip.bozuta@syrmia.com> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 15 +++++++++++++++ linux-user/strace.list | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index a26736516b..957f08f1ad 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1452,6 +1452,21 @@ print_chmod(const struct syscallname *name, } #endif +#if defined(TARGET_NR_chown) || defined(TARGET_NR_lchown) +static void +print_chown(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_raw_param("%d", arg1, 0); + print_raw_param("%d", arg2, 1); + print_syscall_epilogue(name); +} +#define print_lchown print_chown +#endif + #ifdef TARGET_NR_clock_adjtime static void print_clock_adjtime(const struct syscallname *name, diff --git a/linux-user/strace.list b/linux-user/strace.list index a4a8c61969..e99030c9ef 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -71,7 +71,7 @@ { TARGET_NR_chmod, "chmod" , NULL, print_chmod, NULL }, #endif #ifdef TARGET_NR_chown -{ TARGET_NR_chown, "chown" , NULL, NULL, NULL }, +{ TARGET_NR_chown, "chown" , NULL, print_chown, NULL }, #endif #ifdef TARGET_NR_chown32 { TARGET_NR_chown32, "chown32" , NULL, NULL, NULL }, @@ -475,7 +475,7 @@ { TARGET_NR_kill, "kill", NULL, print_kill, NULL }, #endif #ifdef TARGET_NR_lchown -{ TARGET_NR_lchown, "lchown" , NULL, NULL, NULL }, +{ TARGET_NR_lchown, "lchown" , NULL, print_lchown, NULL }, #endif #ifdef TARGET_NR_lchown32 { TARGET_NR_lchown32, "lchown32" , NULL, NULL, NULL }, From f4d92c5e9f24efdc83f24a2fd99c37a8609787ee Mon Sep 17 00:00:00 2001 From: Filip Bozuta Date: Fri, 19 Jun 2020 14:33:31 +0200 Subject: [PATCH 1729/2595] linux-user: Add strace support for printing arguments of fallocate() This patch implements strace argument printing functionality for following syscall: *fallocate - manipulate file space int fallocate(int fd, int mode, off_t offset, off_t len) man page: https://www.man7.org/linux/man-pages/man2/fallocate.2.html Implementation notes: This syscall's second argument "mode" is composed of predefined values which represent flags that determine the type of operation that is to be performed on the file space. For that reason, a printing function "print_fallocate" was stated in file "strace.list". This printing function uses an already existing function "print_flags()" to print flags of the "mode" argument. These flags are stated inside an array "falloc_flags" that contains values of type "struct flags". These values are instantiated using an existing macro "FLAG_GENERIC()". Most of these flags are defined after kernel version 3.0 which is why they are enwrapped in an #ifdef directive. The syscall's third ant fourth argument are of type "off_t" which can cause variations between 32/64-bit architectures. To handle this variation, function "target_offset64()" was copied from file "strace.c" and used in "print_fallocate" to print "off_t" arguments for 32-bit architectures. Signed-off-by: Filip Bozuta Reviewed-by: Laurent Vivier Message-Id: <20200619123331.17387-7-filip.bozuta@syrmia.com> Signed-off-by: Laurent Vivier --- linux-user/qemu.h | 16 ++++++++++++++++ linux-user/strace.c | 40 ++++++++++++++++++++++++++++++++++++++++ linux-user/strace.list | 2 +- linux-user/syscall.c | 16 ---------------- 4 files changed, 57 insertions(+), 17 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 8f938b8105..be67391ba4 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -670,6 +670,22 @@ static inline int is_error(abi_long ret) return (abi_ulong)ret >= (abi_ulong)(-4096); } +#if TARGET_ABI_BITS == 32 +static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) +{ +#ifdef TARGET_WORDS_BIGENDIAN + return ((uint64_t)word0 << 32) | word1; +#else + return ((uint64_t)word1 << 32) | word0; +#endif +} +#else /* TARGET_ABI_BITS == 32 */ +static inline uint64_t target_offset64(uint64_t word0, uint64_t word1) +{ + return word0; +} +#endif /* TARGET_ABI_BITS != 32 */ + /** * preexit_cleanup: housekeeping before the guest exits * diff --git a/linux-user/strace.c b/linux-user/strace.c index 957f08f1ad..32e5e987ac 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1135,6 +1135,26 @@ UNUSED static struct flags statx_mask[] = { FLAG_END, }; +UNUSED static struct flags falloc_flags[] = { + FLAG_GENERIC(FALLOC_FL_KEEP_SIZE), + FLAG_GENERIC(FALLOC_FL_PUNCH_HOLE), +#ifdef FALLOC_FL_NO_HIDE_STALE + FLAG_GENERIC(FALLOC_FL_NO_HIDE_STALE), +#endif +#ifdef FALLOC_FL_COLLAPSE_RANGE + FLAG_GENERIC(FALLOC_FL_COLLAPSE_RANGE), +#endif +#ifdef FALLOC_FL_ZERO_RANGE + FLAG_GENERIC(FALLOC_FL_ZERO_RANGE), +#endif +#ifdef FALLOC_FL_INSERT_RANGE + FLAG_GENERIC(FALLOC_FL_INSERT_RANGE), +#endif +#ifdef FALLOC_FL_UNSHARE_RANGE + FLAG_GENERIC(FALLOC_FL_UNSHARE_RANGE), +#endif +}; + /* * print_xxx utility functions. These are used to print syscall * parameters in certain format. All of these have parameter @@ -1552,6 +1572,26 @@ print_faccessat(const struct syscallname *name, } #endif +#ifdef TARGET_NR_fallocate +static void +print_fallocate(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_raw_param("%d", arg0, 0); + print_flags(falloc_flags, arg1, 0); +#if TARGET_ABI_BITS == 32 + print_raw_param("%" PRIu64, target_offset64(arg2, arg3), 0); + print_raw_param("%" PRIu64, target_offset64(arg4, arg5), 1); +#else + print_raw_param(TARGET_ABI_FMT_ld, arg2, 0); + print_raw_param(TARGET_ABI_FMT_ld, arg3, 1); +#endif + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_fchmodat static void print_fchmodat(const struct syscallname *name, diff --git a/linux-user/strace.list b/linux-user/strace.list index e99030c9ef..ebb713252c 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -182,7 +182,7 @@ { TARGET_NR_fadvise64_64, "fadvise64_64" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_fallocate -{ TARGET_NR_fallocate, "fallocate" , NULL, NULL, NULL }, +{ TARGET_NR_fallocate, "fallocate" , NULL, print_fallocate, NULL }, #endif #ifdef TARGET_NR_fanotify_init { TARGET_NR_fanotify_init, "fanotify_init" , NULL, NULL, NULL }, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1b971c06b2..506b94a12c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6712,22 +6712,6 @@ void syscall_init(void) } } -#if TARGET_ABI_BITS == 32 -static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) -{ -#ifdef TARGET_WORDS_BIGENDIAN - return ((uint64_t)word0 << 32) | word1; -#else - return ((uint64_t)word1 << 32) | word0; -#endif -} -#else /* TARGET_ABI_BITS == 32 */ -static inline uint64_t target_offset64(uint64_t word0, uint64_t word1) -{ - return word0; -} -#endif /* TARGET_ABI_BITS != 32 */ - #ifdef TARGET_NR_truncate64 static inline abi_long target_truncate64(void *cpu_env, const char *arg1, abi_long arg2, From a20a7c26406b14aed56815e2bb9f150facca2cc0 Mon Sep 17 00:00:00 2001 From: Filip Bozuta Date: Fri, 19 Jun 2020 14:47:26 +0200 Subject: [PATCH 1730/2595] linux-user: Add thunk argument types for SIOCGSTAMP and SIOCGSTAMPNS Socket ioctls SIOCGSTAMP and SIOCGSTAMPNS, used for timestamping the socket connection, are defined in file "ioctls.h" differently from other ioctls. The reason for this difference is explained in the comments above their definition. These ioctls didn't have defined thunk argument types before changes from this patch. They have special handling functions ("do_ioctl_SIOCGSTAMP" and "do_ioctl_SIOCGSTAMPNS") that take care of setting values for approppriate argument types (struct timeval and struct timespec) and thus no thunk argument types were needed for their implementation. But this patch adds those argument type definitions in file "syscall_types.h" and "ioctls.h" as it is needed for printing arguments of these ioctls with strace. Implementation notes: There are two variants of these ioctls: SIOCGSTAMP_OLD/SIOCGSTAM_NEW and SIOCGSTAMPNS_OLD/SIOCGSTAMPNS_NEW. One is the old existing definition and the other is the 2038 safe variant used for 32-bit architectures. Corresponding structure definitions STRUCT_timespec/STRUCT__kernel_timespec and STRUCT_timeval/STRUCT__kernel_sock_timeval were added for these variants. STRUCT_timeval definition was already inside the file as it is used by another implemented ioctl. Two cases were added for definitions STRUCT_timeval/STRUCT__kernel_sock_timeval to manage the case when the "u_sec" field of the timeval structure is of type int. Signed-off-by: Filip Bozuta Reviewed-by: Laurent Vivier Message-Id: <20200619124727.18080-2-filip.bozuta@syrmia.com> Signed-off-by: Laurent Vivier --- linux-user/ioctls.h | 12 ++++++++---- linux-user/syscall_types.h | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index f2e2fa9c87..0713ae1311 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -279,13 +279,17 @@ * FIXME: create a macro to define this kind of entry */ { TARGET_SIOCGSTAMP_OLD, TARGET_SIOCGSTAMP_OLD, - "SIOCGSTAMP_OLD", IOC_R, do_ioctl_SIOCGSTAMP }, + "SIOCGSTAMP_OLD", IOC_R, do_ioctl_SIOCGSTAMP, + { MK_PTR(MK_STRUCT(STRUCT_timeval)) } }, { TARGET_SIOCGSTAMPNS_OLD, TARGET_SIOCGSTAMPNS_OLD, - "SIOCGSTAMPNS_OLD", IOC_R, do_ioctl_SIOCGSTAMPNS }, + "SIOCGSTAMPNS_OLD", IOC_R, do_ioctl_SIOCGSTAMPNS, + { MK_PTR(MK_STRUCT(STRUCT_timespec)) } }, { TARGET_SIOCGSTAMP_NEW, TARGET_SIOCGSTAMP_NEW, - "SIOCGSTAMP_NEW", IOC_R, do_ioctl_SIOCGSTAMP }, + "SIOCGSTAMP_NEW", IOC_R, do_ioctl_SIOCGSTAMP, + { MK_PTR(MK_STRUCT(STRUCT__kernel_sock_timeval)) } }, { TARGET_SIOCGSTAMPNS_NEW, TARGET_SIOCGSTAMPNS_NEW, - "SIOCGSTAMPNS_NEW", IOC_R, do_ioctl_SIOCGSTAMPNS }, + "SIOCGSTAMPNS_NEW", IOC_R, do_ioctl_SIOCGSTAMPNS, + { MK_PTR(MK_STRUCT(STRUCT__kernel_timespec)) } }, IOCTL(RNDGETENTCNT, IOC_R, MK_PTR(TYPE_INT)) IOCTL(RNDADDTOENTCNT, IOC_W, MK_PTR(TYPE_INT)) diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index e2b0484f50..3f1f033464 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -137,10 +137,32 @@ STRUCT(snd_timer_params, TYPE_INT, /* filter */ MK_ARRAY(TYPE_CHAR, 60)) /* reserved */ +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) +STRUCT(timeval, + TYPE_LONG, /* tv_sec */ + TYPE_INT) /* tv_usec */ + +STRUCT(_kernel_sock_timeval, + TYPE_LONG, /* tv_sec */ + TYPE_INT) /* tv_usec */ +#else +STRUCT(timeval, + TYPE_LONG, /* tv_sec */ + TYPE_LONG) /* tv_usec */ + +STRUCT(_kernel_sock_timeval, + TYPE_LONGLONG, /* tv_sec */ + TYPE_LONGLONG) /* tv_usec */ +#endif + STRUCT(timespec, TYPE_LONG, /* tv_sec */ TYPE_LONG) /* tv_nsec */ +STRUCT(_kernel_timespec, + TYPE_LONGLONG, /* tv_sec */ + TYPE_LONGLONG) /* tv_nsec */ + STRUCT(snd_timer_status, MK_STRUCT(STRUCT_timespec), /* tstamp */ TYPE_INT, /* resolution */ From fc1bff958998910ec8d25db86cd2f53ff125f7ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 29 Jun 2020 09:47:04 +0200 Subject: [PATCH 1731/2595] hw/misc/pca9552: Add missing TypeInfo::class_size field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When adding the generic PCA955xClass in commit 736132e455, we forgot to set the class_size field. Fill it now to avoid: (gdb) run -machine mcimx6ul-evk -m 128M -display none -serial stdio -kernel ./OS.elf Starting program: ../../qemu/qemu/arm-softmmu/qemu-system-arm -machine mcimx6ul-evk -m 128M -display none -serial stdio -kernel ./OS.elf double free or corruption (!prev) Thread 1 "qemu-system-arm" received signal SIGABRT, Aborted. __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50 (gdb) where #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50 #1 0x00007ffff75d8859 in __GI_abort () at abort.c:79 #2 0x00007ffff76433ee in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff776d285 "%s\n") at ../sysdeps/posix/libc_fatal.c:155 #3 0x00007ffff764b47c in malloc_printerr (str=str@entry=0x7ffff776f690 "double free or corruption (!prev)") at malloc.c:5347 #4 0x00007ffff764d12c in _int_free (av=0x7ffff779eb80 , p=0x5555567a3990, have_lock=) at malloc.c:4317 #5 0x0000555555c906c3 in type_initialize_interface (ti=ti@entry=0x5555565b8f40, interface_type=0x555556597ad0, parent_type=0x55555662ca10) at qom/object.c:259 #6 0x0000555555c902da in type_initialize (ti=ti@entry=0x5555565b8f40) at qom/object.c:323 #7 0x0000555555c90d20 in type_initialize (ti=0x5555565b8f40) at qom/object.c:1028 $ valgrind --track-origins=yes qemu-system-arm -M mcimx6ul-evk -m 128M -display none -serial stdio -kernel ./OS.elf ==77479== Memcheck, a memory error detector ==77479== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==77479== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==77479== Command: qemu-system-arm -M mcimx6ul-evk -m 128M -display none -serial stdio -kernel ./OS.elf ==77479== ==77479== Invalid write of size 2 ==77479== at 0x6D8322: pca9552_class_init (pca9552.c:424) ==77479== by 0x844D1F: type_initialize (object.c:1029) ==77479== by 0x844D1F: object_class_foreach_tramp (object.c:1016) ==77479== by 0x4AE1057: g_hash_table_foreach (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.2) ==77479== by 0x8453A4: object_class_foreach (object.c:1038) ==77479== by 0x8453A4: object_class_get_list (object.c:1095) ==77479== by 0x556194: select_machine (vl.c:2416) ==77479== by 0x556194: qemu_init (vl.c:3828) ==77479== by 0x40AF9C: main (main.c:48) ==77479== Address 0x583f108 is 0 bytes after a block of size 200 alloc'd ==77479== at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==77479== by 0x4AF8D30: g_malloc0 (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.2) ==77479== by 0x844258: type_initialize.part.0 (object.c:306) ==77479== by 0x844D1F: type_initialize (object.c:1029) ==77479== by 0x844D1F: object_class_foreach_tramp (object.c:1016) ==77479== by 0x4AE1057: g_hash_table_foreach (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.2) ==77479== by 0x8453A4: object_class_foreach (object.c:1038) ==77479== by 0x8453A4: object_class_get_list (object.c:1095) ==77479== by 0x556194: select_machine (vl.c:2416) ==77479== by 0x556194: qemu_init (vl.c:3828) ==77479== by 0x40AF9C: main (main.c:48) Fixes: 736132e455 ("hw/misc/pca9552: Add generic PCA955xClass") Reported-by: Jean-Christophe DUBOIS Signed-off-by: Philippe Mathieu-Daudé Tested-by: Jean-Christophe DUBOIS Message-id: 20200629074704.23028-1-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/misc/pca9552.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index 80caa9ec8f..68b574d084 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -410,6 +410,7 @@ static const TypeInfo pca955x_info = { .instance_init = pca955x_initfn, .instance_size = sizeof(PCA955xState), .class_init = pca955x_class_init, + .class_size = sizeof(PCA955xClass), .abstract = true, }; From 84ec3f940289dfba9b6de531c9aac7f089fc6c8f Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 20 Jun 2020 22:56:28 +0200 Subject: [PATCH 1732/2595] sm501: Fix bounds checks We don't need to add width to pitch when calculating last point, that would reject valid ops within the card's local_mem. Fixes: b15a22bbcbe6a78dc3d88fe3134985e4cdd87de4 Signed-off-by: BALATON Zoltan Reviewed-by: Peter Maydell Message-id: ddb5781d12913bb9d6dbfd9e5b1e2b893e2b3e2d.1592686588.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index a7fc08c52b..5ceee4166f 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -723,8 +723,8 @@ static void sm501_2d_operation(SM501State *s) dst_y -= height - 1; } - if (dst_base >= get_local_mem_size(s) || dst_base + - (dst_x + width + (dst_y + height) * (dst_pitch + width)) * + if (dst_base >= get_local_mem_size(s) || + dst_base + (dst_x + width + (dst_y + height) * dst_pitch) * (1 << format) >= get_local_mem_size(s)) { qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op dest is outside vram.\n"); return; @@ -749,8 +749,8 @@ static void sm501_2d_operation(SM501State *s) src_y -= height - 1; } - if (src_base >= get_local_mem_size(s) || src_base + - (src_x + width + (src_y + height) * (src_pitch + width)) * + if (src_base >= get_local_mem_size(s) || + src_base + (src_x + width + (src_y + height) * src_pitch) * (1 << format) >= get_local_mem_size(s)) { qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op src is outside vram.\n"); From 4decaad9d295c8598bbcba09c40d3fd4a115f1e8 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 20 Jun 2020 22:56:28 +0200 Subject: [PATCH 1733/2595] sm501: Drop unneded variable We don't need a separate variable to keep track if we allocated memory that needs to be freed as we can test the pointer itself. Signed-off-by: BALATON Zoltan Reviewed-by: Peter Maydell Message-id: ff9136c3151a15cdfa1d9b7a68acf11cffb8efa4.1592686588.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 5ceee4166f..5d2e019575 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -796,13 +796,12 @@ static void sm501_2d_operation(SM501State *s) de = db + width + height * (width + dst_pitch); if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) { /* regions may overlap: copy via temporary */ - int free_buf = 0, llb = width * (1 << format); + int llb = width * (1 << format); int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t)); uint32_t *tmp = tmp_buf; if (tmp_stride * sizeof(uint32_t) * height > sizeof(tmp_buf)) { tmp = g_malloc(tmp_stride * sizeof(uint32_t) * height); - free_buf = 1; } pixman_blt((uint32_t *)&s->local_mem[src_base], tmp, src_pitch * (1 << format) / sizeof(uint32_t), @@ -813,7 +812,7 @@ static void sm501_2d_operation(SM501State *s) dst_pitch * (1 << format) / sizeof(uint32_t), 8 * (1 << format), 8 * (1 << format), 0, 0, dst_x, dst_y, width, height); - if (free_buf) { + if (tmp != tmp_buf) { g_free(tmp); } } else { From 1cb62e3666b48ac4c6a22340165e21439919908f Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 20 Jun 2020 22:56:28 +0200 Subject: [PATCH 1734/2595] sm501: Ignore no-op blits Some guests seem to try source copy blits with same source and dest which are no-op so avoid calling pixman for these. Signed-off-by: BALATON Zoltan Reviewed-by: Peter Maydell Message-id: a2a8214dd37344dfb65f1c343ace4cff2e94f3bb.1592686588.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 5d2e019575..ad5a62bfab 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -788,6 +788,11 @@ static void sm501_2d_operation(SM501State *s) (rop2_source_is_pattern ? " with pattern source" : "")); } + /* Ignore no-op blits, some guests seem to do this */ + if (src_base == dst_base && src_pitch == dst_pitch && + src_x == dst_x && src_y == dst_y) { + break; + } /* Check for overlaps, this could be made more exact */ uint32_t sb, se, db, de; sb = src_base + src_x + src_y * (width + src_pitch); From 299778d5af207b298224d2c610324941b8561006 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 20 Jun 2020 22:56:28 +0200 Subject: [PATCH 1735/2595] sm501: Introduce variable for commonly used value for better readability The bytes per pixel value can be calculated from format but it's used freqently enough (and will be used more in subseqent patches) so store it in a variable for better readabilty. Also drop some unneded 0x prefix around where new variable is defined. Signed-off-by: BALATON Zoltan Reviewed-by: Peter Maydell Message-id: b9ea5ef2d68583db9f3fb73a2b859abbd7c044a8.1592686588.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index ad5a62bfab..3ced2c42db 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -684,10 +684,11 @@ static void sm501_2d_operation(SM501State *s) { int cmd = (s->twoD_control >> 16) & 0x1F; int rtl = s->twoD_control & BIT(27); - int format = (s->twoD_stretch >> 20) & 0x3; - int rop_mode = (s->twoD_control >> 15) & 0x1; /* 1 for rop2, else rop3 */ + int format = (s->twoD_stretch >> 20) & 3; + int bypp = 1 << format; /* bytes per pixel */ + int rop_mode = (s->twoD_control >> 15) & 1; /* 1 for rop2, else rop3 */ /* 1 if rop2 source is the pattern, otherwise the source is the bitmap */ - int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1; + int rop2_source_is_pattern = (s->twoD_control >> 14) & 1; int rop = s->twoD_control & 0xFF; unsigned int dst_x = (s->twoD_destination >> 16) & 0x01FFF; unsigned int dst_y = s->twoD_destination & 0xFFFF; @@ -724,8 +725,8 @@ static void sm501_2d_operation(SM501State *s) } if (dst_base >= get_local_mem_size(s) || - dst_base + (dst_x + width + (dst_y + height) * dst_pitch) * - (1 << format) >= get_local_mem_size(s)) { + dst_base + (dst_x + width + (dst_y + height) * dst_pitch) * bypp >= + get_local_mem_size(s)) { qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op dest is outside vram.\n"); return; } @@ -750,8 +751,8 @@ static void sm501_2d_operation(SM501State *s) } if (src_base >= get_local_mem_size(s) || - src_base + (src_x + width + (src_y + height) * src_pitch) * - (1 << format) >= get_local_mem_size(s)) { + src_base + (src_x + width + (src_y + height) * src_pitch) * bypp >= + get_local_mem_size(s)) { qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op src is outside vram.\n"); return; @@ -763,8 +764,8 @@ static void sm501_2d_operation(SM501State *s) uint8_t *d = s->local_mem + dst_base; for (y = 0; y < height; y++) { - i = (dst_x + (dst_y + y) * dst_pitch) * (1 << format); - for (x = 0; x < width; x++, i += (1 << format)) { + i = (dst_x + (dst_y + y) * dst_pitch) * bypp; + for (x = 0; x < width; x++, i += bypp) { switch (format) { case 0: d[i] = ~d[i]; @@ -801,7 +802,7 @@ static void sm501_2d_operation(SM501State *s) de = db + width + height * (width + dst_pitch); if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) { /* regions may overlap: copy via temporary */ - int llb = width * (1 << format); + int llb = width * bypp; int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t)); uint32_t *tmp = tmp_buf; @@ -809,13 +810,13 @@ static void sm501_2d_operation(SM501State *s) tmp = g_malloc(tmp_stride * sizeof(uint32_t) * height); } pixman_blt((uint32_t *)&s->local_mem[src_base], tmp, - src_pitch * (1 << format) / sizeof(uint32_t), - tmp_stride, 8 * (1 << format), 8 * (1 << format), + src_pitch * bypp / sizeof(uint32_t), + tmp_stride, 8 * bypp, 8 * bypp, src_x, src_y, 0, 0, width, height); pixman_blt(tmp, (uint32_t *)&s->local_mem[dst_base], tmp_stride, - dst_pitch * (1 << format) / sizeof(uint32_t), - 8 * (1 << format), 8 * (1 << format), + dst_pitch * bypp / sizeof(uint32_t), + 8 * bypp, 8 * bypp, 0, 0, dst_x, dst_y, width, height); if (tmp != tmp_buf) { g_free(tmp); @@ -823,9 +824,9 @@ static void sm501_2d_operation(SM501State *s) } else { pixman_blt((uint32_t *)&s->local_mem[src_base], (uint32_t *)&s->local_mem[dst_base], - src_pitch * (1 << format) / sizeof(uint32_t), - dst_pitch * (1 << format) / sizeof(uint32_t), - 8 * (1 << format), 8 * (1 << format), + src_pitch * bypp / sizeof(uint32_t), + dst_pitch * bypp / sizeof(uint32_t), + 8 * bypp, 8 * bypp, src_x, src_y, dst_x, dst_y, width, height); } } @@ -842,8 +843,8 @@ static void sm501_2d_operation(SM501State *s) } pixman_fill((uint32_t *)&s->local_mem[dst_base], - dst_pitch * (1 << format) / sizeof(uint32_t), - 8 * (1 << format), dst_x, dst_y, width, height, color); + dst_pitch * bypp / sizeof(uint32_t), + 8 * bypp, dst_x, dst_y, width, height, color); break; } default: @@ -855,7 +856,7 @@ static void sm501_2d_operation(SM501State *s) if (dst_base >= get_fb_addr(s, crt) && dst_base <= get_fb_addr(s, crt) + fb_len) { int dst_len = MIN(fb_len, ((dst_y + height - 1) * dst_pitch + - dst_x + width) * (1 << format)); + dst_x + width) * bypp); if (dst_len) { memory_region_set_dirty(&s->local_mem_region, dst_base, dst_len); } From c208085a3e979e1da23a59c397ad6ab56a29d7bf Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 20 Jun 2020 22:56:28 +0200 Subject: [PATCH 1736/2595] sm501: Optimise 1 pixel 2d ops Some guests do 1x1 blits which is faster to do directly than calling a function for it so avoid overhead in this case. Signed-off-by: BALATON Zoltan Reviewed-by: Peter Maydell Message-id: 7cccc302d7b4c5c313bad7681ac4686417143c3e.1592686588.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 3ced2c42db..2098e69810 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -794,6 +794,14 @@ static void sm501_2d_operation(SM501State *s) src_x == dst_x && src_y == dst_y) { break; } + /* Some clients also do 1 pixel blits, avoid overhead for these */ + if (width == 1 && height == 1) { + unsigned int si = (src_x + src_y * src_pitch) * bypp; + unsigned int di = (dst_x + dst_y * dst_pitch) * bypp; + stn_he_p(&s->local_mem[dst_base + di], bypp, + ldn_he_p(&s->local_mem[src_base + si], bypp)); + break; + } /* Check for overlaps, this could be made more exact */ uint32_t sb, se, db, de; sb = src_base + src_x + src_y * (width + src_pitch); @@ -842,9 +850,14 @@ static void sm501_2d_operation(SM501State *s) color = cpu_to_le16(color); } - pixman_fill((uint32_t *)&s->local_mem[dst_base], - dst_pitch * bypp / sizeof(uint32_t), - 8 * bypp, dst_x, dst_y, width, height, color); + if (width == 1 && height == 1) { + unsigned int i = (dst_x + dst_y * dst_pitch) * bypp; + stn_he_p(&s->local_mem[dst_base + i], bypp, color); + } else { + pixman_fill((uint32_t *)&s->local_mem[dst_base], + dst_pitch * bypp / sizeof(uint32_t), + 8 * bypp, dst_x, dst_y, width, height, color); + } break; } default: From ba27110fab0b7ba26ff6a36a7311481181dd83f8 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 20 Jun 2020 22:56:28 +0200 Subject: [PATCH 1737/2595] sm501: Use stn_he_p/ldn_he_p instead of switch/case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of open coding op with different sizes using a switch and type casting it can be written more compactly using stn_he_p/ldn_he_p. Suggested-by: Peter Maydell Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-id: e2f649cb286f0735a10ec87c1b36a7ae081acb61.1592686588.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 2098e69810..6349f31e64 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -766,17 +766,7 @@ static void sm501_2d_operation(SM501State *s) for (y = 0; y < height; y++) { i = (dst_x + (dst_y + y) * dst_pitch) * bypp; for (x = 0; x < width; x++, i += bypp) { - switch (format) { - case 0: - d[i] = ~d[i]; - break; - case 1: - *(uint16_t *)&d[i] = ~*(uint16_t *)&d[i]; - break; - case 2: - *(uint32_t *)&d[i] = ~*(uint32_t *)&d[i]; - break; - } + stn_he_p(&d[i], bypp, ~ldn_he_p(&d[i], bypp)); } } } else { From f018edc358669d42553f4a636b7611d05ab2198f Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 20 Jun 2020 22:56:28 +0200 Subject: [PATCH 1738/2595] sm501: Do not allow guest to set invalid format Prevent guest setting invalid format value that might trip checks in sm501_2d_operation(). Signed-off-by: BALATON Zoltan Reviewed-by: Peter Maydell Message-id: 26d4fa9b8ce81e2723e98d592ccba7550042752c.1592686588.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 6349f31e64..7e4c042d52 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1503,6 +1503,9 @@ static void sm501_2d_engine_write(void *opaque, hwaddr addr, s->twoD_background = value; break; case SM501_2D_STRETCH: + if (((value >> 20) & 3) == 3) { + value &= ~BIT(20); + } s->twoD_stretch = value; break; case SM501_2D_COLOR_COMPARE: From d8327a68694e49d7d125b5dbe4eeaaf9695cbb73 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 20 Jun 2020 22:56:28 +0200 Subject: [PATCH 1739/2595] sm501: Convert debug printfs to traces Signed-off-by: BALATON Zoltan Reviewed-by: Peter Maydell Message-id: caf97bf0c84a440896ddf020e84c312fa5c15076.1592686588.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 50 +++++++++++------------------------------ hw/display/trace-events | 12 ++++++++++ 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 7e4c042d52..2db347dcbc 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -39,15 +39,7 @@ #include "qemu/range.h" #include "ui/pixel_ops.h" #include "qemu/bswap.h" - -/*#define DEBUG_SM501*/ -/*#define DEBUG_BITBLT*/ - -#ifdef DEBUG_SM501 -#define SM501_DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else -#define SM501_DPRINTF(fmt, ...) do {} while (0) -#endif +#include "trace.h" #define MMIO_BASE_OFFSET 0x3e00000 #define MMIO_SIZE 0x200000 @@ -871,7 +863,6 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr, { SM501State *s = (SM501State *)opaque; uint32_t ret = 0; - SM501_DPRINTF("sm501 system config regs : read addr=%x\n", (int)addr); switch (addr) { case SM501_SYSTEM_CONTROL: @@ -923,7 +914,7 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr, qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config" "register read. addr=%" HWADDR_PRIx "\n", addr); } - + trace_sm501_system_config_read(addr, ret); return ret; } @@ -931,9 +922,8 @@ static void sm501_system_config_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { SM501State *s = (SM501State *)opaque; - SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n", - (uint32_t)addr, (uint32_t)value); + trace_sm501_system_config_write((uint32_t)addr, (uint32_t)value); switch (addr) { case SM501_SYSTEM_CONTROL: s->system_control &= 0x10DB0000; @@ -1019,9 +1009,7 @@ static uint64_t sm501_i2c_read(void *opaque, hwaddr addr, unsigned size) qemu_log_mask(LOG_UNIMP, "sm501 i2c : not implemented register read." " addr=0x%" HWADDR_PRIx "\n", addr); } - - SM501_DPRINTF("sm501 i2c regs : read addr=%" HWADDR_PRIx " val=%x\n", - addr, ret); + trace_sm501_i2c_read((uint32_t)addr, ret); return ret; } @@ -1029,9 +1017,8 @@ static void sm501_i2c_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { SM501State *s = (SM501State *)opaque; - SM501_DPRINTF("sm501 i2c regs : write addr=%" HWADDR_PRIx - " val=%" PRIx64 "\n", addr, value); + trace_sm501_i2c_write((uint32_t)addr, (uint32_t)value); switch (addr) { case SM501_I2C_BYTE_COUNT: s->i2c_byte_count = value & 0xf; @@ -1045,25 +1032,19 @@ static void sm501_i2c_write(void *opaque, hwaddr addr, uint64_t value, s->i2c_status |= (res ? SM501_I2C_STATUS_ERROR : 0); if (!res) { int i; - SM501_DPRINTF("sm501 i2c : transferring %d bytes to 0x%x\n", - s->i2c_byte_count + 1, s->i2c_addr >> 1); for (i = 0; i <= s->i2c_byte_count; i++) { res = i2c_send_recv(s->i2c_bus, &s->i2c_data[i], !(s->i2c_addr & 1)); if (res) { - SM501_DPRINTF("sm501 i2c : transfer failed" - " i=%d, res=%d\n", i, res); s->i2c_status |= SM501_I2C_STATUS_ERROR; return; } } if (i) { - SM501_DPRINTF("sm501 i2c : transferred %d bytes\n", i); s->i2c_status = SM501_I2C_STATUS_COMPLETE; } } } else { - SM501_DPRINTF("sm501 i2c : end transfer\n"); i2c_end_transfer(s->i2c_bus); s->i2c_status &= ~SM501_I2C_STATUS_ERROR; } @@ -1103,7 +1084,8 @@ static const MemoryRegionOps sm501_i2c_ops = { static uint32_t sm501_palette_read(void *opaque, hwaddr addr) { SM501State *s = (SM501State *)opaque; - SM501_DPRINTF("sm501 palette read addr=%x\n", (int)addr); + + trace_sm501_palette_read((uint32_t)addr); /* TODO : consider BYTE/WORD access */ /* TODO : consider endian */ @@ -1116,8 +1098,8 @@ static void sm501_palette_write(void *opaque, hwaddr addr, uint32_t value) { SM501State *s = (SM501State *)opaque; - SM501_DPRINTF("sm501 palette write addr=%x, val=%x\n", - (int)addr, value); + + trace_sm501_palette_write((uint32_t)addr, value); /* TODO : consider BYTE/WORD access */ /* TODO : consider endian */ @@ -1132,7 +1114,6 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr, { SM501State *s = (SM501State *)opaque; uint32_t ret = 0; - SM501_DPRINTF("sm501 disp ctrl regs : read addr=%x\n", (int)addr); switch (addr) { @@ -1237,7 +1218,7 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr, qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register " "read. addr=%" HWADDR_PRIx "\n", addr); } - + trace_sm501_disp_ctrl_read((uint32_t)addr, ret); return ret; } @@ -1245,9 +1226,8 @@ static void sm501_disp_ctrl_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { SM501State *s = (SM501State *)opaque; - SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n", - (unsigned)addr, (unsigned)value); + trace_sm501_disp_ctrl_write((uint32_t)addr, (uint32_t)value); switch (addr) { case SM501_DC_PANEL_CONTROL: s->dc_panel_control = value & 0x0FFF73FF; @@ -1392,7 +1372,6 @@ static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr, { SM501State *s = (SM501State *)opaque; uint32_t ret = 0; - SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr); switch (addr) { case SM501_2D_SOURCE: @@ -1462,7 +1441,7 @@ static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr, qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register " "read. addr=%" HWADDR_PRIx "\n", addr); } - + trace_sm501_2d_engine_read((uint32_t)addr, ret); return ret; } @@ -1470,9 +1449,8 @@ static void sm501_2d_engine_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { SM501State *s = (SM501State *)opaque; - SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n", - (unsigned)addr, (unsigned)value); + trace_sm501_2d_engine_write((uint32_t)addr, (uint32_t)value); switch (addr) { case SM501_2D_SOURCE: s->twoD_source = value; @@ -1830,8 +1808,6 @@ static void sm501_init(SM501State *s, DeviceState *dev, uint32_t local_mem_bytes) { s->local_mem_size_index = get_local_mem_size_index(local_mem_bytes); - SM501_DPRINTF("sm501 local mem size=%x. index=%d\n", get_local_mem_size(s), - s->local_mem_size_index); /* local memory */ memory_region_init_ram(&s->local_mem_region, OBJECT(dev), "sm501.local", diff --git a/hw/display/trace-events b/hw/display/trace-events index 72d4c9812c..970d6bac5d 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -161,3 +161,15 @@ cg3_write(uint32_t addr, uint32_t val, unsigned size) "write addr:0x%06"PRIx32" # dpcd.c dpcd_read(uint32_t addr, uint8_t val) "read addr:0x%"PRIx32" val:0x%02x" dpcd_write(uint32_t addr, uint8_t val) "write addr:0x%"PRIx32" val:0x%02x" + +# sm501.c +sm501_system_config_read(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x" +sm501_system_config_write(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x" +sm501_i2c_read(uint32_t addr, uint8_t val) "addr=0x%x, val=0x%x" +sm501_i2c_write(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x" +sm501_palette_read(uint32_t addr) "addr=0x%x" +sm501_palette_write(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x" +sm501_disp_ctrl_read(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x" +sm501_disp_ctrl_write(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x" +sm501_2d_engine_read(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x" +sm501_2d_engine_write(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x" From 9982c605a71bffd4c52c111b5c79e2060953a762 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 24 Jun 2020 18:42:18 +0200 Subject: [PATCH 1740/2595] sm501: Fix and optimize overlap check When doing reverse blit we need to check if source and dest overlap but it is not trivial due to possible different base and pitch of source and dest. Do rectangle overlap if base and pitch match, otherwise just check if memory area containing the rects overlaps so rects could possibly overlap. Signed-off-by: BALATON Zoltan Message-Id: <20200624164737.A941374633D@zero.eik.bme.hu> Reviewed-by: Peter Maydell Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 2db347dcbc..9cccc68c35 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -690,6 +690,7 @@ static void sm501_2d_operation(SM501State *s) unsigned int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); + bool overlap = false; if ((s->twoD_stretch >> 16) & 0xF) { qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n"); @@ -784,16 +785,21 @@ static void sm501_2d_operation(SM501State *s) ldn_he_p(&s->local_mem[src_base + si], bypp)); break; } - /* Check for overlaps, this could be made more exact */ - uint32_t sb, se, db, de; - sb = src_base + src_x + src_y * (width + src_pitch); - se = sb + width + height * (width + src_pitch); - db = dst_base + dst_x + dst_y * (width + dst_pitch); - de = db + width + height * (width + dst_pitch); - if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) { - /* regions may overlap: copy via temporary */ - int llb = width * bypp; - int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t)); + /* If reverse blit do simple check for overlaps */ + if (rtl && src_base == dst_base && src_pitch == dst_pitch) { + overlap = (src_x < dst_x + width && src_x + width > dst_x && + src_y < dst_y + height && src_y + height > dst_y); + } else if (rtl) { + unsigned int sb, se, db, de; + sb = src_base + (src_x + src_y * src_pitch) * bypp; + se = sb + (width + (height - 1) * src_pitch) * bypp; + db = dst_base + (dst_x + dst_y * dst_pitch) * bypp; + de = db + (width + (height - 1) * dst_pitch) * bypp; + overlap = (db < se && sb < de); + } + if (overlap) { + /* pixman can't do reverse blit: copy via temporary */ + int tmp_stride = DIV_ROUND_UP(width * bypp, sizeof(uint32_t)); uint32_t *tmp = tmp_buf; if (tmp_stride * sizeof(uint32_t) * height > sizeof(tmp_buf)) { From d634c883ca07c28da2cb84c019659694f05d8b3a Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sun, 21 Jun 2020 13:12:38 +0200 Subject: [PATCH 1741/2595] ati-vga: Support unaligned access to hardware cursor registers This fixes horizontal mouse movement and pointer color with MacOS that writes these registers with access size less than 4 so previously only the last portion of access was effective overwriting previous partial writes. Signed-off-by: BALATON Zoltan Message-id: ba1d5ba97f246e8807f86f1243c2bdc6497dc8f2.1592737958.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/ati.c | 85 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/hw/display/ati.c b/hw/display/ati.c index 7216f7e08f..245130d52f 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -389,22 +389,28 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) case 0xf00 ... 0xfff: val = pci_default_read_config(&s->dev, addr - 0xf00, size); break; - case CUR_OFFSET: - val = s->regs.cur_offset; + case CUR_OFFSET ... CUR_OFFSET + 3: + val = ati_reg_read_offs(s->regs.cur_offset, addr - CUR_OFFSET, size); break; - case CUR_HORZ_VERT_POSN: - val = s->regs.cur_hv_pos; - val |= s->regs.cur_offset & BIT(31); + case CUR_HORZ_VERT_POSN ... CUR_HORZ_VERT_POSN + 3: + val = ati_reg_read_offs(s->regs.cur_hv_pos, + addr - CUR_HORZ_VERT_POSN, size); + if (addr + size > CUR_HORZ_VERT_POSN + 3) { + val |= (s->regs.cur_offset & BIT(31)) >> (4 - size); + } break; - case CUR_HORZ_VERT_OFF: - val = s->regs.cur_hv_offs; - val |= s->regs.cur_offset & BIT(31); + case CUR_HORZ_VERT_OFF ... CUR_HORZ_VERT_OFF + 3: + val = ati_reg_read_offs(s->regs.cur_hv_offs, + addr - CUR_HORZ_VERT_OFF, size); + if (addr + size > CUR_HORZ_VERT_OFF + 3) { + val |= (s->regs.cur_offset & BIT(31)) >> (4 - size); + } break; - case CUR_CLR0: - val = s->regs.cur_color0; + case CUR_CLR0 ... CUR_CLR0 + 3: + val = ati_reg_read_offs(s->regs.cur_color0, addr - CUR_CLR0, size); break; - case CUR_CLR1: - val = s->regs.cur_color1; + case CUR_CLR1 ... CUR_CLR1 + 3: + val = ati_reg_read_offs(s->regs.cur_color1, addr - CUR_CLR1, size); break; case DST_OFFSET: val = s->regs.dst_offset; @@ -679,48 +685,71 @@ static void ati_mm_write(void *opaque, hwaddr addr, case 0xf00 ... 0xfff: /* read-only copy of PCI config space so ignore writes */ break; - case CUR_OFFSET: - if (s->regs.cur_offset != (data & 0x87fffff0)) { - s->regs.cur_offset = data & 0x87fffff0; + case CUR_OFFSET ... CUR_OFFSET + 3: + { + uint32_t t = s->regs.cur_offset; + + ati_reg_write_offs(&t, addr - CUR_OFFSET, data, size); + t &= 0x87fffff0; + if (s->regs.cur_offset != t) { + s->regs.cur_offset = t; ati_cursor_define(s); } break; - case CUR_HORZ_VERT_POSN: - s->regs.cur_hv_pos = data & 0x3fff0fff; - if (data & BIT(31)) { - s->regs.cur_offset |= data & BIT(31); + } + case CUR_HORZ_VERT_POSN ... CUR_HORZ_VERT_POSN + 3: + { + uint32_t t = s->regs.cur_hv_pos | (s->regs.cur_offset & BIT(31)); + + ati_reg_write_offs(&t, addr - CUR_HORZ_VERT_POSN, data, size); + s->regs.cur_hv_pos = t & 0x3fff0fff; + if (t & BIT(31)) { + s->regs.cur_offset |= t & BIT(31); } else if (s->regs.cur_offset & BIT(31)) { s->regs.cur_offset &= ~BIT(31); ati_cursor_define(s); } if (!s->cursor_guest_mode && - (s->regs.crtc_gen_cntl & CRTC2_CUR_EN) && !(data & BIT(31))) { + (s->regs.crtc_gen_cntl & CRTC2_CUR_EN) && !(t & BIT(31))) { dpy_mouse_set(s->vga.con, s->regs.cur_hv_pos >> 16, s->regs.cur_hv_pos & 0xffff, 1); } break; + } case CUR_HORZ_VERT_OFF: - s->regs.cur_hv_offs = data & 0x3f003f; - if (data & BIT(31)) { - s->regs.cur_offset |= data & BIT(31); + { + uint32_t t = s->regs.cur_hv_offs | (s->regs.cur_offset & BIT(31)); + + ati_reg_write_offs(&t, addr - CUR_HORZ_VERT_OFF, data, size); + s->regs.cur_hv_offs = t & 0x3f003f; + if (t & BIT(31)) { + s->regs.cur_offset |= t & BIT(31); } else if (s->regs.cur_offset & BIT(31)) { s->regs.cur_offset &= ~BIT(31); ati_cursor_define(s); } break; - case CUR_CLR0: - if (s->regs.cur_color0 != (data & 0xffffff)) { - s->regs.cur_color0 = data & 0xffffff; + } + case CUR_CLR0 ... CUR_CLR0 + 3: + { + uint32_t t = s->regs.cur_color0; + + ati_reg_write_offs(&t, addr - CUR_CLR0, data, size); + t &= 0xffffff; + if (s->regs.cur_color0 != t) { + s->regs.cur_color0 = t; ati_cursor_define(s); } break; - case CUR_CLR1: + } + case CUR_CLR1 ... CUR_CLR1 + 3: /* * Update cursor unconditionally here because some clients set up * other registers before actually writing cursor data to memory at * offset so we would miss cursor change unless always updating here */ - s->regs.cur_color1 = data & 0xffffff; + ati_reg_write_offs(&s->regs.cur_color1, addr - CUR_CLR1, data, size); + s->regs.cur_color1 &= 0xffffff; ati_cursor_define(s); break; case DST_OFFSET: From 41977c65c04a85f177603778cb60e06847efd3af Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sun, 21 Jun 2020 13:12:38 +0200 Subject: [PATCH 1742/2595] ati-vga: Do not assert on error Do not abort on unsupported value just print log and continue. While display will likely be broken this prevents malicious guest to crash QEMU causing denial of service. Signed-off-by: BALATON Zoltan Message-id: 0c13dab5d8e3b7e7479c3edbf53aeac8c09de6de.1592737958.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/ati.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/display/ati.c b/hw/display/ati.c index 245130d52f..95fc443cac 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -86,8 +86,8 @@ static void ati_vga_switch_mode(ATIVGAState *s) break; default: qemu_log_mask(LOG_UNIMP, "Unsupported bpp value\n"); + return; } - assert(bpp != 0); DPRINTF("Switching to %dx%d %d %d @ %x\n", h, v, stride, bpp, offs); vbe_ioport_write_index(&s->vga, 0, VBE_DISPI_INDEX_ENABLE); vbe_ioport_write_data(&s->vga, 0, VBE_DISPI_DISABLED); From 2bbcaa7cd67c30fc90d643f2fb490787b9d9627c Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sun, 21 Jun 2020 13:12:38 +0200 Subject: [PATCH 1743/2595] ati-vga: Add dummy MEM_SDRAM_MODE_REG Radeon chips have an SDRAM mode reg that is accessed by some drivers. We don't emulate the memory controller but provide some default value to prevent drivers getting unexpected 0. Signed-off-by: BALATON Zoltan Message-id: cc1324b9ef06beb8ae233ddc77dedd8bab9b8624.1592737958.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/ati.c | 5 +++++ hw/display/ati_dbg.c | 1 + hw/display/ati_regs.h | 1 + 3 files changed, 7 insertions(+) diff --git a/hw/display/ati.c b/hw/display/ati.c index 95fc443cac..4c3ad8f47b 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -361,6 +361,11 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) case MC_STATUS: val = 5; break; + case MEM_SDRAM_MODE_REG: + if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) { + val = BIT(28) | BIT(20); + } + break; case RBBM_STATUS: case GUI_STAT: val = 64; /* free CMDFIFO entries */ diff --git a/hw/display/ati_dbg.c b/hw/display/ati_dbg.c index 0ebbd36f14..bd0ecd48c7 100644 --- a/hw/display/ati_dbg.c +++ b/hw/display/ati_dbg.c @@ -42,6 +42,7 @@ static struct ati_regdesc ati_reg_names[] = { {"MC_FB_LOCATION", 0x0148}, {"MC_AGP_LOCATION", 0x014C}, {"MC_STATUS", 0x0150}, + {"MEM_SDRAM_MODE_REG", 0x0158}, {"MEM_POWER_MISC", 0x015c}, {"AGP_BASE", 0x0170}, {"AGP_CNTL", 0x0174}, diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h index ebd37ee30d..d6282b2ef2 100644 --- a/hw/display/ati_regs.h +++ b/hw/display/ati_regs.h @@ -60,6 +60,7 @@ #define MC_FB_LOCATION 0x0148 #define MC_AGP_LOCATION 0x014C #define MC_STATUS 0x0150 +#define MEM_SDRAM_MODE_REG 0x0158 #define MEM_POWER_MISC 0x015c #define AGP_BASE 0x0170 #define AGP_CNTL 0x0174 From 8db2a4fd8abf6550479f7a8caa8f655c34238d6a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 22 Jun 2020 15:12:40 +0200 Subject: [PATCH 1744/2595] configure: vgabios cleanups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 91b8eba9ec3f ("vgabios: remove submodule and build rules.") removed the vgabios submodule, but left some traces in the configure script. Remove them. Reported-by: BALATON Zoltan Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200622131240.9624-1-kraxel@redhat.com --- configure | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 4a22dcd563..8a65240d4a 100755 --- a/configure +++ b/configure @@ -8486,14 +8486,14 @@ DIRS="tests tests/tcg tests/tcg/lm32 tests/qapi-schema tests/qtest/libqos" DIRS="$DIRS tests/qtest tests/qemu-iotests tests/vm tests/fp tests/qgraph" DIRS="$DIRS docs docs/interop fsdev scsi" DIRS="$DIRS pc-bios/optionrom pc-bios/s390-ccw" -DIRS="$DIRS roms/seabios roms/vgabios" +DIRS="$DIRS roms/seabios" LINKS="Makefile" LINKS="$LINKS tests/tcg/lm32/Makefile po/Makefile" LINKS="$LINKS tests/tcg/Makefile.target tests/fp/Makefile" LINKS="$LINKS tests/plugin/Makefile" LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps" LINKS="$LINKS pc-bios/s390-ccw/Makefile" -LINKS="$LINKS roms/seabios/Makefile roms/vgabios/Makefile" +LINKS="$LINKS roms/seabios/Makefile" LINKS="$LINKS pc-bios/qemu-icon.bmp" LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit LINKS="$LINKS tests/acceptance tests/data" @@ -8526,7 +8526,7 @@ export target_list source_path use_containers $source_path/tests/tcg/configure.sh) # temporary config to build submodules -for rom in seabios vgabios ; do +for rom in seabios; do config_mak=roms/$rom/config.mak echo "# Automatically generated by configure - do not modify" > $config_mak echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak From e6e68e32d2fac52e2f88efc0bd16dd92c2e9e88a Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 11 Jun 2020 12:44:42 -0400 Subject: [PATCH 1745/2595] tests: disassemble-aml.sh: generate AML in readable format On systems where the IASL tool exists, we can convert extected ACPI tables to ASL format, which is useful for debugging and documentation purposes. This script does this for all ACPI tables under tests/data/acpi/. Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/disassemle-aml.sh | 52 +++++++++++++++++++++++++ tests/data/acpi/rebuild-expected-aml.sh | 1 + 2 files changed, 53 insertions(+) create mode 100755 tests/data/acpi/disassemle-aml.sh diff --git a/tests/data/acpi/disassemle-aml.sh b/tests/data/acpi/disassemle-aml.sh new file mode 100755 index 0000000000..1d8a4d0301 --- /dev/null +++ b/tests/data/acpi/disassemle-aml.sh @@ -0,0 +1,52 @@ +#!/usr/bin/bash + +outdir= +while getopts "o:" arg; do + case ${arg} in + o ) + outdir=$OPTARG + ;; + \? ) + echo "Usage: ./tests/data/acpi/disassemle-aml.sh [-o ]" + exit 1 + ;; + + esac +done + +for machine in tests/data/acpi/* +do + if [[ ! -d "$machine" ]]; + then + continue + fi + + if [[ "${outdir}" ]]; + then + mkdir -p "${outdir}"/${machine} || exit $? + fi + for aml in $machine/* + do + if [[ "$aml" == $machine/*.dsl ]]; + then + continue + fi + if [[ "$aml" == $machine/SSDT*.* ]]; + then + dsdt=${aml/SSDT*./DSDT.} + extra="-e ${dsdt}" + elif [[ "$aml" == $machine/SSDT* ]]; + then + dsdt=${aml/SSDT*/DSDT}; + extra="-e ${dsdt}" + else + extra="" + fi + asl=${aml}.dsl + if [[ "${outdir}" ]]; + then + asl="${outdir}"/${machine}/${asl} + fi + iasl -d -p ${asl} ${extra} ${aml} + done +done diff --git a/tests/data/acpi/rebuild-expected-aml.sh b/tests/data/acpi/rebuild-expected-aml.sh index 9cbaab1a4d..76cd797d1e 100755 --- a/tests/data/acpi/rebuild-expected-aml.sh +++ b/tests/data/acpi/rebuild-expected-aml.sh @@ -36,6 +36,7 @@ old_allowed_dif=`grep -v -e 'List of comma-separated changed AML files to ignore echo '/* List of comma-separated changed AML files to ignore */' > ${SRC_PATH}/tests/qtest/bios-tables-test-allowed-diff.h echo "The files were rebuilt and can be added to git." +echo "You can use ${SRC_PATH}/tests/data/acpi/disassemle-aml.sh to disassemble them to ASL." if [ -z "$old_allowed_dif" ]; then echo "Note! Please do not commit expected files with source changes" From ed4e0d2ef140aef255d67eec30767e5fcd949f58 Mon Sep 17 00:00:00 2001 From: lichun Date: Mon, 22 Jun 2020 05:30:17 +0800 Subject: [PATCH 1746/2595] chardev/tcp: Fix error message double free error Errors are already freed by error_report_err, so we only need to call error_free when that function is not called. Cc: qemu-stable@nongnu.org Signed-off-by: lichun Message-Id: <20200621213017.17978-1-lichun@ruijie.com.cn> Reviewed-by: Markus Armbruster [Commit message improved, cc: qemu-stable] Signed-off-by: Markus Armbruster --- chardev/char-socket.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index afebeec5c3..569d54c144 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -142,6 +142,8 @@ static void check_report_connect_error(Chardev *chr, "Unable to connect character device %s: ", chr->label); s->connect_err_reported = true; + } else { + error_free(err); } qemu_chr_socket_restart_timer(chr); } @@ -1086,7 +1088,6 @@ static void qemu_chr_socket_connected(QIOTask *task, void *opaque) if (qio_task_propagate_error(task, &err)) { tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); check_report_connect_error(chr, err); - error_free(err); goto cleanup; } From 590090b4e6aa8df53c20792ce20c8684b83c51a9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 25 Jun 2020 11:08:11 +0100 Subject: [PATCH 1747/2595] hw/virtio/virtio-iommu-pci.c: Fix typo in error message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a typo in an error message in virtio_iommu_pci_realize(): "Check you machine" should be "Check your machine". Reported-by: Markus Armbruster Signed-off-by: Peter Maydell Message-Id: <20200625100811.12690-1-peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Eric Auger Signed-off-by: Markus Armbruster --- hw/virtio/virtio-iommu-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c index 632533abaf..32e3215d1d 100644 --- a/hw/virtio/virtio-iommu-pci.c +++ b/hw/virtio/virtio-iommu-pci.c @@ -48,7 +48,7 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) "%s machine fails to create iommu-map device tree bindings", mc->name); error_append_hint(errp, - "Check you machine implements a hotplug handler " + "Check your machine implements a hotplug handler " "for the virtio-iommu-pci device\n"); error_append_hint(errp, "Check the guest is booted without FW or with " "-no-acpi\n"); From ca72efccbe33373810341a0d8a10f5698b8fbc87 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:26 +0200 Subject: [PATCH 1748/2595] net/virtio: Fix failover_replug_primary() return value regression Commit 150ab54aa6 "net/virtio: fix re-plugging of primary device" fixed failover_replug_primary() to return false on failure. Commit 5a0948d36c "net/virtio: Fix failover error handling crash bugs" broke it again for hotplug_handler_plug() failure. Unbreak it. Commit 5a0948d36c4cbc1c5534afac6fee99de55245d12 Fixes: 5a0948d36c4cbc1c5534afac6fee99de55245d12 Cc: Jens Freimann Cc: Michael S. Tsirkin Cc: qemu-stable@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Jens Freimann Reviewed-by: Michael S. Tsirkin Message-Id: <20200630090351.1247703-2-armbru@redhat.com> --- hw/net/virtio-net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index aff67a92df..9bb5578e5d 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3129,7 +3129,7 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp) if (err) { goto out; } - hotplug_handler_plug(hotplug_ctrl, n->primary_dev, errp); + hotplug_handler_plug(hotplug_ctrl, n->primary_dev, &err); } out: From 5a79d10c953c9eebc69e4ad7c18cd8476782cf6f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:27 +0200 Subject: [PATCH 1749/2595] pci: Delete useless error_propagate() Cc: Jens Freimann Cc: Michael S. Tsirkin Cc: Marcel Apfelbaum Signed-off-by: Markus Armbruster Reviewed-by: Jens Freimann Reviewed-by: Michael S. Tsirkin Message-Id: <20200630090351.1247703-3-armbru@redhat.com> --- hw/pci/pci.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index b22dedc88c..de0fae10ab 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2123,7 +2123,6 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) if (!pci_bus_is_express(pci_get_bus(pci_dev))) { error_setg(errp, "failover primary device must be on " "PCIExpress bus"); - error_propagate(errp, local_err); pci_qdev_unrealize(DEVICE(pci_dev)); return; } @@ -2131,7 +2130,6 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) if (class_id != PCI_CLASS_NETWORK_ETHERNET) { error_setg(errp, "failover primary device is not an " "Ethernet device"); - error_propagate(errp, local_err); pci_qdev_unrealize(DEVICE(pci_dev)); return; } @@ -2141,7 +2139,6 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) } else { error_setg(errp, "failover: primary device must be in its own " "PCI slot"); - error_propagate(errp, local_err); pci_qdev_unrealize(DEVICE(pci_dev)); return; } From 9261ef5e32b0559642ccb70565836e1bc023937e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:28 +0200 Subject: [PATCH 1750/2595] Clean up some calls to ignore Error objects the right way MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Receiving the error in a local variable only to free it is less clear (and also less efficient) than passing NULL. Clean up. Cc: Daniel P. Berrange Cc: Jerome Forissier CC: Greg Kurz Signed-off-by: Markus Armbruster Reviewed-by: Greg Kurz Message-Id: <20200630090351.1247703-4-armbru@redhat.com> Reviewed-by: Daniel P. Berrangé --- chardev/char-socket.c | 6 ++---- hw/9pfs/9p.c | 6 ++---- hw/arm/virt.c | 4 +--- hw/ppc/spapr_drc.c | 4 +--- ui/vnc.c | 3 +-- 5 files changed, 7 insertions(+), 16 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 569d54c144..5758d9900f 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -817,22 +817,20 @@ static void tcp_chr_tls_init(Chardev *chr) { SocketChardev *s = SOCKET_CHARDEV(chr); QIOChannelTLS *tioc; - Error *err = NULL; gchar *name; if (s->is_listen) { tioc = qio_channel_tls_new_server( s->ioc, s->tls_creds, s->tls_authz, - &err); + NULL); } else { tioc = qio_channel_tls_new_client( s->ioc, s->tls_creds, s->addr->u.inet.host, - &err); + NULL); } if (tioc == NULL) { - error_free(err); tcp_chr_disconnect(chr); return; } diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 45a788f6e6..9755fba9a9 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1399,7 +1399,6 @@ static void coroutine_fn v9fs_attach(void *opaque) size_t offset = 7; V9fsQID qid; ssize_t err; - Error *local_err = NULL; v9fs_string_init(&uname); v9fs_string_init(&aname); @@ -1437,9 +1436,8 @@ static void coroutine_fn v9fs_attach(void *opaque) error_setg(&s->migration_blocker, "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'", s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag); - err = migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_free(local_err); + err = migrate_add_blocker(s->migration_blocker, NULL); + if (err < 0) { error_free(s->migration_blocker); s->migration_blocker = NULL; clunk_fid(s, fid); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index cd0834ce7f..af3050bc4b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -217,11 +217,9 @@ static bool cpu_type_valid(const char *cpu) static void create_kaslr_seed(VirtMachineState *vms, const char *node) { - Error *err = NULL; uint64_t seed; - if (qemu_guest_getrandom(&seed, sizeof(seed), &err)) { - error_free(err); + if (qemu_guest_getrandom(&seed, sizeof(seed), NULL)) { return; } qemu_fdt_setprop_u64(vms->fdt, node, "kaslr-seed", seed); diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 2689104295..951bcdf2c0 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -1163,16 +1163,14 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu, drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); if (!drc->fdt) { - Error *local_err = NULL; void *fdt; int fdt_size; fdt = create_device_tree(&fdt_size); if (drck->dt_populate(drc, spapr, fdt, &drc->fdt_start_offset, - &local_err)) { + NULL)) { g_free(fdt); - error_free(local_err); rc = SPAPR_DR_CC_RESPONSE_ERROR; goto out; } diff --git a/ui/vnc.c b/ui/vnc.c index 12a12714e1..0702a76cce 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -458,9 +458,8 @@ static VncServerInfo2List *qmp_query_server_entry(QIOChannelSocket *ioc, Error *err = NULL; SocketAddress *addr; - addr = qio_channel_socket_get_local_address(ioc, &err); + addr = qio_channel_socket_get_local_address(ioc, NULL); if (!addr) { - error_free(err); return prev; } From d8da9e71b6c79c2899c08bb168cd0ae88da70596 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:29 +0200 Subject: [PATCH 1751/2595] tests: Use &error_abort where appropriate Receiving the error in a local variable only to assert there is none is less clear than passing &error_abort. Clean up. Signed-off-by: Markus Armbruster Reviewed-by: Thomas Huth Message-Id: <20200630090351.1247703-5-armbru@redhat.com> --- tests/check-qobject.c | 5 +- tests/check-qom-proplist.c | 7 +- tests/test-logging.c | 12 +--- tests/test-qemu-opts.c | 22 ++---- tests/test-replication.c | 109 +++++++++-------------------- tests/test-string-input-visitor.c | 33 +++------ tests/test-string-output-visitor.c | 16 ++--- 7 files changed, 59 insertions(+), 145 deletions(-) diff --git a/tests/check-qobject.c b/tests/check-qobject.c index 593c3a0618..6b6deaeb8b 100644 --- a/tests/check-qobject.c +++ b/tests/check-qobject.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "block/qdict.h" +#include "qapi/error.h" #include "qapi/qmp/qbool.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" @@ -213,7 +214,6 @@ static void qobject_is_equal_list_test(void) static void qobject_is_equal_dict_test(void) { - Error *local_err = NULL; QDict *dict_0, *dict_1, *dict_cloned; QDict *dict_different_key, *dict_different_value, *dict_different_null_key; QDict *dict_longer, *dict_shorter, *dict_nested; @@ -276,8 +276,7 @@ static void qobject_is_equal_dict_test(void) dict_different_null_key, dict_longer, dict_shorter, dict_nested); - dict_crumpled = qobject_to(QDict, qdict_crumple(dict_1, &local_err)); - g_assert(!local_err); + dict_crumpled = qobject_to(QDict, qdict_crumple(dict_1, &error_abort)); check_equal(dict_crumpled, dict_nested); qdict_flatten(dict_nested); diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c index 13a824cfae..8c71734e1a 100644 --- a/tests/check-qom-proplist.c +++ b/tests/check-qom-proplist.c @@ -419,9 +419,7 @@ static void test_dummy_createcmdl(void) g_assert(dobj->bv == true); g_assert(dobj->av == DUMMY_PLATYPUS); - user_creatable_del("dev0", &err); - g_assert(err == NULL); - error_free(err); + user_creatable_del("dev0", &error_abort); object_unref(OBJECT(dobj)); @@ -485,8 +483,7 @@ static void test_dummy_getenum(void) val = object_property_get_enum(OBJECT(dobj), "av", "DummyAnimal", - &err); - g_assert(err == NULL); + &error_abort); g_assert(val == DUMMY_PLATYPUS); /* A bad enum type name */ diff --git a/tests/test-logging.c b/tests/test-logging.c index 8580b82420..8a1161de1d 100644 --- a/tests/test-logging.c +++ b/tests/test-logging.c @@ -113,7 +113,6 @@ static void test_logfile_write(gconstpointer data) QemuLogFile *logfile; QemuLogFile *logfile2; gchar const *dir = data; - Error *err = NULL; g_autofree gchar *file_path = NULL; g_autofree gchar *file_path1 = NULL; FILE *orig_fd; @@ -132,8 +131,7 @@ static void test_logfile_write(gconstpointer data) * Test that even if an open file handle is changed, * our handle remains valid due to RCU. */ - qemu_set_log_filename(file_path, &err); - g_assert(!err); + qemu_set_log_filename(file_path, &error_abort); rcu_read_lock(); logfile = atomic_rcu_read(&qemu_logfile); orig_fd = logfile->fd; @@ -142,8 +140,7 @@ static void test_logfile_write(gconstpointer data) fflush(logfile->fd); /* Change the logfile and ensure that the handle is still valid. */ - qemu_set_log_filename(file_path1, &err); - g_assert(!err); + qemu_set_log_filename(file_path1, &error_abort); logfile2 = atomic_rcu_read(&qemu_logfile); g_assert(logfile->fd == orig_fd); g_assert(logfile2->fd != logfile->fd); @@ -156,7 +153,6 @@ static void test_logfile_lock(gconstpointer data) { FILE *logfile; gchar const *dir = data; - Error *err = NULL; g_autofree gchar *file_path = NULL; file_path = g_build_filename(dir, "qemu_test_logfile_lock0.log", NULL); @@ -166,7 +162,7 @@ static void test_logfile_lock(gconstpointer data) * that even if an open file handle is closed, * our handle remains valid for use due to RCU. */ - qemu_set_log_filename(file_path, &err); + qemu_set_log_filename(file_path, &error_abort); logfile = qemu_log_lock(); g_assert(logfile); fprintf(logfile, "%s 1st write to file\n", __func__); @@ -180,8 +176,6 @@ static void test_logfile_lock(gconstpointer data) fprintf(logfile, "%s 2nd write to file\n", __func__); fflush(logfile); qemu_log_unlock(logfile); - - g_assert(!err); } /* Remove a directory and all its entries (non-recursive). */ diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index 2a0f42a09b..297ffe79dd 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -187,7 +187,6 @@ static void test_qemu_opt_get(void) static void test_qemu_opt_get_bool(void) { - Error *err = NULL; QemuOptsList *list; QemuOpts *opts; bool opt; @@ -210,16 +209,14 @@ static void test_qemu_opt_get_bool(void) opt = qemu_opt_get_bool(opts, "bool1", false); g_assert(opt == false); - qemu_opt_set_bool(opts, "bool1", true, &err); - g_assert(!err); + qemu_opt_set_bool(opts, "bool1", true, &error_abort); /* now we have set bool1, should know about it */ opt = qemu_opt_get_bool(opts, "bool1", false); g_assert(opt == true); /* having reset the value, opt should be the reset one not defval */ - qemu_opt_set_bool(opts, "bool1", false, &err); - g_assert(!err); + qemu_opt_set_bool(opts, "bool1", false, &error_abort); opt = qemu_opt_get_bool(opts, "bool1", true); g_assert(opt == false); @@ -233,7 +230,6 @@ static void test_qemu_opt_get_bool(void) static void test_qemu_opt_get_number(void) { - Error *err = NULL; QemuOptsList *list; QemuOpts *opts; uint64_t opt; @@ -256,16 +252,14 @@ static void test_qemu_opt_get_number(void) opt = qemu_opt_get_number(opts, "number1", 5); g_assert(opt == 5); - qemu_opt_set_number(opts, "number1", 10, &err); - g_assert(!err); + qemu_opt_set_number(opts, "number1", 10, &error_abort); /* now we have set number1, should know about it */ opt = qemu_opt_get_number(opts, "number1", 5); g_assert(opt == 10); /* having reset it, the returned should be the reset one not defval */ - qemu_opt_set_number(opts, "number1", 15, &err); - g_assert(!err); + qemu_opt_set_number(opts, "number1", 15, &error_abort); opt = qemu_opt_get_number(opts, "number1", 5); g_assert(opt == 15); @@ -367,7 +361,6 @@ static void test_qemu_opt_unset(void) static void test_qemu_opts_reset(void) { - Error *err = NULL; QemuOptsList *list; QemuOpts *opts; uint64_t opt; @@ -390,8 +383,7 @@ static void test_qemu_opts_reset(void) opt = qemu_opt_get_number(opts, "number1", 5); g_assert(opt == 5); - qemu_opt_set_number(opts, "number1", 10, &err); - g_assert(!err); + qemu_opt_set_number(opts, "number1", 10, &error_abort); /* now we have set number1, should know about it */ opt = qemu_opt_get_number(opts, "number1", 5); @@ -406,7 +398,6 @@ static void test_qemu_opts_reset(void) static void test_qemu_opts_set(void) { - Error *err = NULL; QemuOptsList *list; QemuOpts *opts; const char *opt; @@ -421,8 +412,7 @@ static void test_qemu_opts_set(void) g_assert(opts == NULL); /* implicitly create opts and set str3 value */ - qemu_opts_set(list, NULL, "str3", "value", &err); - g_assert(!err); + qemu_opts_set(list, NULL, "str3", "value", &error_abort); g_assert(!QTAILQ_EMPTY(&list->head)); /* get the just created opts */ diff --git a/tests/test-replication.c b/tests/test-replication.c index cbc37db2df..e0b03dafc2 100644 --- a/tests/test-replication.c +++ b/tests/test-replication.c @@ -139,8 +139,6 @@ static void make_temp(char *template) static void prepare_imgs(void) { - Error *local_err = NULL; - make_temp(p_local_disk); make_temp(s_local_disk); make_temp(s_active_disk); @@ -148,19 +146,15 @@ static void prepare_imgs(void) /* Primary */ bdrv_img_create(p_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, - BDRV_O_RDWR, true, &local_err); - g_assert(!local_err); + BDRV_O_RDWR, true, &error_abort); /* Secondary */ bdrv_img_create(s_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, - BDRV_O_RDWR, true, &local_err); - g_assert(!local_err); + BDRV_O_RDWR, true, &error_abort); bdrv_img_create(s_active_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, - BDRV_O_RDWR, true, &local_err); - g_assert(!local_err); + BDRV_O_RDWR, true, &error_abort); bdrv_img_create(s_hidden_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, - BDRV_O_RDWR, true, &local_err); - g_assert(!local_err); + BDRV_O_RDWR, true, &error_abort); } static void cleanup_imgs(void) @@ -179,7 +173,6 @@ static BlockBackend *start_primary(void) BlockBackend *blk; QemuOpts *opts; QDict *qdict; - Error *local_err = NULL; char *cmdline; cmdline = g_strdup_printf("driver=replication,mode=primary,node-name=xxx," @@ -193,12 +186,10 @@ static BlockBackend *start_primary(void) qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off"); qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off"); - blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err); + blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &error_abort); g_assert(blk); - g_assert(!local_err); - monitor_add_blk(blk, P_ID, &local_err); - g_assert(!local_err); + monitor_add_blk(blk, P_ID, &error_abort); qemu_opts_del(opts); @@ -248,12 +239,10 @@ static void test_primary_write(void) static void test_primary_start(void) { BlockBackend *blk = NULL; - Error *local_err = NULL; blk = start_primary(); - replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); - g_assert(!local_err); + replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort); /* read from 0 to IMG_SIZE */ test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true); @@ -266,46 +255,35 @@ static void test_primary_start(void) static void test_primary_stop(void) { - Error *local_err = NULL; bool failover = true; start_primary(); - replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); - g_assert(!local_err); + replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort); - replication_stop_all(failover, &local_err); - g_assert(!local_err); + replication_stop_all(failover, &error_abort); teardown_primary(); } static void test_primary_do_checkpoint(void) { - Error *local_err = NULL; - start_primary(); - replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); - g_assert(!local_err); + replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort); - replication_do_checkpoint_all(&local_err); - g_assert(!local_err); + replication_do_checkpoint_all(&error_abort); teardown_primary(); } static void test_primary_get_error_all(void) { - Error *local_err = NULL; - start_primary(); - replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); - g_assert(!local_err); + replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort); - replication_get_error_all(&local_err); - g_assert(!local_err); + replication_get_error_all(&error_abort); teardown_primary(); } @@ -316,7 +294,6 @@ static BlockBackend *start_secondary(void) QDict *qdict; BlockBackend *blk; char *cmdline; - Error *local_err = NULL; /* add s_local_disk and forge S_LOCAL_DISK_ID */ cmdline = g_strdup_printf("file.filename=%s,driver=qcow2," @@ -329,10 +306,9 @@ static BlockBackend *start_secondary(void) qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off"); qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off"); - blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err); + blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &error_abort); assert(blk); - monitor_add_blk(blk, S_LOCAL_DISK_ID, &local_err); - g_assert(!local_err); + monitor_add_blk(blk, S_LOCAL_DISK_ID, &error_abort); /* format s_local_disk with pattern "0x11" */ test_blk_write(blk, 0x11, 0, IMG_SIZE, false); @@ -356,10 +332,9 @@ static BlockBackend *start_secondary(void) qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off"); qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off"); - blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err); + blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &error_abort); assert(blk); - monitor_add_blk(blk, S_ID, &local_err); - g_assert(!local_err); + monitor_add_blk(blk, S_ID, &error_abort); qemu_opts_del(opts); @@ -420,12 +395,10 @@ static void test_secondary_write(void) static void test_secondary_start(void) { BlockBackend *top_blk, *local_blk; - Error *local_err = NULL; bool failover = true; top_blk = start_secondary(); - replication_start_all(REPLICATION_MODE_SECONDARY, &local_err); - g_assert(!local_err); + replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort); /* read from s_local_disk (0, IMG_SIZE) */ test_blk_read(top_blk, 0x11, 0, IMG_SIZE, 0, IMG_SIZE, false); @@ -446,8 +419,7 @@ static void test_secondary_start(void) 0, IMG_SIZE / 2, false); /* unblock top_bs */ - replication_stop_all(failover, &local_err); - g_assert(!local_err); + replication_stop_all(failover, &error_abort); teardown_secondary(); } @@ -456,12 +428,10 @@ static void test_secondary_start(void) static void test_secondary_stop(void) { BlockBackend *top_blk, *local_blk; - Error *local_err = NULL; bool failover = true; top_blk = start_secondary(); - replication_start_all(REPLICATION_MODE_SECONDARY, &local_err); - g_assert(!local_err); + replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort); /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ local_blk = blk_by_name(S_LOCAL_DISK_ID); @@ -475,8 +445,7 @@ static void test_secondary_stop(void) test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false); /* do active commit */ - replication_stop_all(failover, &local_err); - g_assert(!local_err); + replication_stop_all(failover, &error_abort); /* read from s_local_disk (0, IMG_SIZE / 2) */ test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2, @@ -493,11 +462,9 @@ static void test_secondary_stop(void) static void test_secondary_continuous_replication(void) { BlockBackend *top_blk, *local_blk; - Error *local_err = NULL; top_blk = start_secondary(); - replication_start_all(REPLICATION_MODE_SECONDARY, &local_err); - g_assert(!local_err); + replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort); /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ local_blk = blk_by_name(S_LOCAL_DISK_ID); @@ -511,22 +478,18 @@ static void test_secondary_continuous_replication(void) test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false); /* do failover (active commit) */ - replication_stop_all(true, &local_err); - g_assert(!local_err); + replication_stop_all(true, &error_abort); /* it should ignore all requests from now on */ /* start after failover */ - replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); - g_assert(!local_err); + replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort); /* checkpoint */ - replication_do_checkpoint_all(&local_err); - g_assert(!local_err); + replication_do_checkpoint_all(&error_abort); /* stop */ - replication_stop_all(true, &local_err); - g_assert(!local_err); + replication_stop_all(true, &error_abort); /* read from s_local_disk (0, IMG_SIZE / 2) */ test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2, @@ -543,12 +506,10 @@ static void test_secondary_continuous_replication(void) static void test_secondary_do_checkpoint(void) { BlockBackend *top_blk, *local_blk; - Error *local_err = NULL; bool failover = true; top_blk = start_secondary(); - replication_start_all(REPLICATION_MODE_SECONDARY, &local_err); - g_assert(!local_err); + replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort); /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ local_blk = blk_by_name(S_LOCAL_DISK_ID); @@ -559,35 +520,29 @@ static void test_secondary_do_checkpoint(void) test_blk_read(top_blk, 0x11, IMG_SIZE / 2, IMG_SIZE / 2, 0, IMG_SIZE, false); - replication_do_checkpoint_all(&local_err); - g_assert(!local_err); + replication_do_checkpoint_all(&error_abort); /* after checkpoint, read pattern 0x22 from s_local_disk */ test_blk_read(top_blk, 0x22, IMG_SIZE / 2, IMG_SIZE / 2, 0, IMG_SIZE, false); /* unblock top_bs */ - replication_stop_all(failover, &local_err); - g_assert(!local_err); + replication_stop_all(failover, &error_abort); teardown_secondary(); } static void test_secondary_get_error_all(void) { - Error *local_err = NULL; bool failover = true; start_secondary(); - replication_start_all(REPLICATION_MODE_SECONDARY, &local_err); - g_assert(!local_err); + replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort); - replication_get_error_all(&local_err); - g_assert(!local_err); + replication_get_error_all(&error_abort); /* unblock top_bs */ - replication_stop_all(failover, &local_err); - g_assert(!local_err); + replication_stop_all(failover, &error_abort); teardown_secondary(); } diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c index 5418e085a4..249faafc9d 100644 --- a/tests/test-string-input-visitor.c +++ b/tests/test-string-input-visitor.c @@ -53,8 +53,7 @@ static void test_visitor_in_int(TestInputVisitorData *data, v = visitor_input_test_init(data, "-42"); - visit_type_int(v, NULL, &res, &err); - g_assert(!err); + visit_type_int(v, NULL, &res, &error_abort); g_assert_cmpint(res, ==, value); v = visitor_input_test_init(data, "not an int"); @@ -327,44 +326,37 @@ static void test_visitor_in_uintList(TestInputVisitorData *data, static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { - Error *err = NULL; bool res = false; Visitor *v; v = visitor_input_test_init(data, "true"); - visit_type_bool(v, NULL, &res, &err); - g_assert(!err); + visit_type_bool(v, NULL, &res, &error_abort); g_assert_cmpint(res, ==, true); v = visitor_input_test_init(data, "yes"); - visit_type_bool(v, NULL, &res, &err); - g_assert(!err); + visit_type_bool(v, NULL, &res, &error_abort); g_assert_cmpint(res, ==, true); v = visitor_input_test_init(data, "on"); - visit_type_bool(v, NULL, &res, &err); - g_assert(!err); + visit_type_bool(v, NULL, &res, &error_abort); g_assert_cmpint(res, ==, true); v = visitor_input_test_init(data, "false"); - visit_type_bool(v, NULL, &res, &err); - g_assert(!err); + visit_type_bool(v, NULL, &res, &error_abort); g_assert_cmpint(res, ==, false); v = visitor_input_test_init(data, "no"); - visit_type_bool(v, NULL, &res, &err); - g_assert(!err); + visit_type_bool(v, NULL, &res, &error_abort); g_assert_cmpint(res, ==, false); v = visitor_input_test_init(data, "off"); - visit_type_bool(v, NULL, &res, &err); - g_assert(!err); + visit_type_bool(v, NULL, &res, &error_abort); g_assert_cmpint(res, ==, false); } @@ -377,8 +369,7 @@ static void test_visitor_in_number(TestInputVisitorData *data, v = visitor_input_test_init(data, "3.14"); - visit_type_number(v, NULL, &res, &err); - g_assert(!err); + visit_type_number(v, NULL, &res, &error_abort); g_assert_cmpfloat(res, ==, value); /* NaN and infinity has to be rejected */ @@ -399,13 +390,11 @@ static void test_visitor_in_string(TestInputVisitorData *data, const void *unused) { char *res = NULL, *value = (char *) "Q E M U"; - Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, value); - visit_type_str(v, NULL, &res, &err); - g_assert(!err); + visit_type_str(v, NULL, &res, &error_abort); g_assert_cmpstr(res, ==, value); g_free(res); @@ -414,7 +403,6 @@ static void test_visitor_in_string(TestInputVisitorData *data, static void test_visitor_in_enum(TestInputVisitorData *data, const void *unused) { - Error *err = NULL; Visitor *v; EnumOne i; @@ -423,8 +411,7 @@ static void test_visitor_in_enum(TestInputVisitorData *data, v = visitor_input_test_init(data, EnumOne_str(i)); - visit_type_EnumOne(v, NULL, &res, &err); - g_assert(!err); + visit_type_EnumOne(v, NULL, &res, &error_abort); g_assert_cmpint(i, ==, res); } } diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c index 3bd732222c..9f6581439a 100644 --- a/tests/test-string-output-visitor.c +++ b/tests/test-string-output-visitor.c @@ -71,11 +71,9 @@ static void test_visitor_out_int(TestOutputVisitorData *data, const void *unused) { int64_t value = 42; - Error *err = NULL; char *str; - visit_type_int(data->ov, NULL, &value, &err); - g_assert(!err); + visit_type_int(data->ov, NULL, &value, &error_abort); str = visitor_get(data); if (data->human) { @@ -120,12 +118,10 @@ static void test_visitor_out_intList(TestOutputVisitorData *data, static void test_visitor_out_bool(TestOutputVisitorData *data, const void *unused) { - Error *err = NULL; bool value = true; char *str; - visit_type_bool(data->ov, NULL, &value, &err); - g_assert(!err); + visit_type_bool(data->ov, NULL, &value, &error_abort); str = visitor_get(data); g_assert_cmpstr(str, ==, "true"); @@ -135,11 +131,9 @@ static void test_visitor_out_number(TestOutputVisitorData *data, const void *unused) { double value = 3.14; - Error *err = NULL; char *str; - visit_type_number(data->ov, NULL, &value, &err); - g_assert(!err); + visit_type_number(data->ov, NULL, &value, &error_abort); str = visitor_get(data); g_assert_cmpstr(str, ==, "3.140000"); @@ -150,11 +144,9 @@ static void test_visitor_out_string(TestOutputVisitorData *data, { char *string = (char *) "Q E M U"; const char *string_human = "\"Q E M U\""; - Error *err = NULL; char *str; - visit_type_str(data->ov, NULL, &string, &err); - g_assert(!err); + visit_type_str(data->ov, NULL, &string, &error_abort); str = visitor_get(data); if (data->human) { From 7b8eb7f848fdd808dbd01f6aa7ae42fd8c64e4b4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:30 +0200 Subject: [PATCH 1752/2595] tests: Use error_free_or_abort() where appropriate Replace g_assert(err != NULL); error_free(err); err = NULL; and variations thereof by error_free_or_abort(&err); Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200630090351.1247703-6-armbru@redhat.com> --- tests/check-block-qdict.c | 24 ++++++------------------ tests/check-qom-proplist.c | 7 ++----- tests/test-base64.c | 3 +-- tests/test-bdrv-graph-mod.c | 4 +--- tests/test-block-iothread.c | 3 +-- tests/test-crypto-cipher.c | 8 ++------ tests/test-io-task.c | 4 +--- 7 files changed, 14 insertions(+), 39 deletions(-) diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c index 73d3e9f574..5a25825093 100644 --- a/tests/check-block-qdict.c +++ b/tests/check-block-qdict.c @@ -610,9 +610,7 @@ static void qdict_rename_keys_test(void) copy = qdict_clone_shallow(dict); qdict_rename_keys(copy, renames, &local_err); - g_assert(local_err != NULL); - error_free(local_err); - local_err = NULL; + error_free_or_abort(&local_err); g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo"); g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar"); @@ -649,9 +647,7 @@ static void qdict_crumple_test_bad_inputs(void) qdict_put_str(src, "rule.0.policy", "allow"); g_assert(qdict_crumple(src, &error) == NULL); - g_assert(error != NULL); - error_free(error); - error = NULL; + error_free_or_abort(&error); qobject_unref(src); src = qdict_new(); @@ -660,9 +656,7 @@ static void qdict_crumple_test_bad_inputs(void) qdict_put_str(src, "rule.a", "allow"); g_assert(qdict_crumple(src, &error) == NULL); - g_assert(error != NULL); - error_free(error); - error = NULL; + error_free_or_abort(&error); qobject_unref(src); src = qdict_new(); @@ -673,9 +667,7 @@ static void qdict_crumple_test_bad_inputs(void) qdict_put_str(src, "rule.b", "allow"); g_assert(qdict_crumple(src, &error) == NULL); - g_assert(error != NULL); - error_free(error); - error = NULL; + error_free_or_abort(&error); qobject_unref(src); src = qdict_new(); @@ -684,9 +676,7 @@ static void qdict_crumple_test_bad_inputs(void) qdict_put_str(src, "rule.3", "allow"); g_assert(qdict_crumple(src, &error) == NULL); - g_assert(error != NULL); - error_free(error); - error = NULL; + error_free_or_abort(&error); qobject_unref(src); src = qdict_new(); @@ -695,9 +685,7 @@ static void qdict_crumple_test_bad_inputs(void) qdict_put_str(src, "rule.+1", "allow"); g_assert(qdict_crumple(src, &error) == NULL); - g_assert(error != NULL); - error_free(error); - error = NULL; + error_free_or_abort(&error); qobject_unref(src); } diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c index 8c71734e1a..e1e0a96661 100644 --- a/tests/check-qom-proplist.c +++ b/tests/check-qom-proplist.c @@ -491,17 +491,14 @@ static void test_dummy_getenum(void) "av", "BadAnimal", &err); - g_assert(err != NULL); - error_free(err); - err = NULL; + error_free_or_abort(&err); /* A non-enum property name */ val = object_property_get_enum(OBJECT(dobj), "iv", "DummyAnimal", &err); - g_assert(err != NULL); - error_free(err); + error_free_or_abort(&err); object_unparent(OBJECT(dobj)); } diff --git a/tests/test-base64.c b/tests/test-base64.c index ec122ceba5..a7f722c459 100644 --- a/tests/test-base64.c +++ b/tests/test-base64.c @@ -54,10 +54,9 @@ static void test_base64_bad(const char *input, &len, &err); - g_assert(err != NULL); + error_free_or_abort(&err); g_assert(actual == NULL); g_assert_cmpint(len, ==, 0); - error_free(err); } diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c index f93f3168b0..8cff13830e 100644 --- a/tests/test-bdrv-graph-mod.c +++ b/tests/test-bdrv-graph-mod.c @@ -115,9 +115,7 @@ static void test_update_perm_tree(void) BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort); bdrv_append(filter, bs, &local_err); - - g_assert_nonnull(local_err); - error_free(local_err); + error_free_or_abort(&local_err); blk_unref(root); } diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c index a953794be2..3f866a35c6 100644 --- a/tests/test-block-iothread.c +++ b/tests/test-block-iothread.c @@ -650,8 +650,7 @@ static void test_propagate_mirror(void) blk_insert_bs(blk, src, &error_abort); bdrv_try_set_aio_context(target, ctx, &local_err); - g_assert(local_err); - error_free(local_err); + error_free_or_abort(&local_err); g_assert(blk_get_aio_context(blk) == main_ctx); g_assert(bdrv_get_aio_context(src) == main_ctx); diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c index 07fa2fa616..bebba1a4f4 100644 --- a/tests/test-crypto-cipher.c +++ b/tests/test-crypto-cipher.c @@ -761,10 +761,7 @@ static void test_cipher_short_plaintext(void) sizeof(plaintext1), &err); g_assert(ret == -1); - g_assert(err != NULL); - - error_free(err); - err = NULL; + error_free_or_abort(&err); /* Should report an error as plaintext is larger than * block size, but not a multiple of block size @@ -775,9 +772,8 @@ static void test_cipher_short_plaintext(void) sizeof(plaintext2), &err); g_assert(ret == -1); - g_assert(err != NULL); + error_free_or_abort(&err); - error_free(err); qcrypto_cipher_free(cipher); } diff --git a/tests/test-io-task.c b/tests/test-io-task.c index c8a3813d49..85e7a98da5 100644 --- a/tests/test-io-task.c +++ b/tests/test-io-task.c @@ -240,9 +240,7 @@ static void test_task_thread_failure(void) object_unref(obj); g_assert(data.source == obj); - g_assert(data.err != NULL); - - error_free(data.err); + error_free_or_abort(&data.err); self = g_thread_self(); From 562a558647be6fe43e60f8bf3601e5b6122c0599 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:31 +0200 Subject: [PATCH 1753/2595] usb/dev-mtp: Fix Error double free after inotify failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit error_report_err() frees its first argument. Freeing it again is wrong. Don't. Fixes: 47287c27d0c367a89f7b2851e23a7f8b2d499dd6 Cc: Gerd Hoffmann Cc: Daniel P. Berrangé Cc: qemu-stable@nongnu.org Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-7-armbru@redhat.com> Reviewed-by: Daniel P. Berrangé --- hw/usb/dev-mtp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 168428156b..15a2243101 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -634,7 +634,6 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o) error_reportf_err(err, "usb-mtp: failed to add watch for %s: ", o->path); - error_free(err); } else { trace_usb_mtp_file_monitor_event(s->dev.addr, o->path, "Watch Added"); @@ -1279,7 +1278,6 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) if (err) { error_reportf_err(err, "usb-mtp: file monitoring init failed: "); - error_free(err); } else { QTAILQ_INIT(&s->events); } From 14963c34b9901abee6cc91d1831841b2c20511c3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:32 +0200 Subject: [PATCH 1754/2595] spapr: Plug minor memory leak in spapr_machine_init() spapr_machine_init() leaks an Error object when kvmppc_check_papr_resize_hpt() fails and spapr->resize_hpt is SPAPR_RESIZE_HPT_DISABLED, i.e. when the host doesn't support hash page table resizing, and the user didn't ask for it. As harmless as memory leaks can possibly be. Plug it. Fixes: 30f4b05bd090564181554d0890605eb2c143e4ea Cc: David Gibson Cc: qemu-ppc@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Greg Kurz Acked-by: David Gibson Message-Id: <20200630090351.1247703-8-armbru@redhat.com> --- hw/ppc/spapr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 4c185bcc13..44fd578ea9 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2731,6 +2731,7 @@ static void spapr_machine_init(MachineState *machine) error_report_err(resize_hpt_err); exit(1); } + error_free(resize_hpt_err); spapr->rma_size = spapr_rma_size(spapr, &error_fatal); From b368123dd9979e8840b6c98ff69722e7bf1da54d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:33 +0200 Subject: [PATCH 1755/2595] qga: Plug unlikely memory leak in guest-set-memory-blocks transfer_memory_block() leaks an Error object when reading file /sys/devices/system/memory/memory/state fails with errno other than ENOENT, and @sys2memblk is false, i.e. when the state file exists but cannot be read (seems quite unlikely), and this is guest-set-memory-blocks, not guest-get-memory-blocks. Plug the leak. Fixes: bd240fca42d5f072fb758a71720d9de9990ac553 Cc: Michael Roth Cc: Hailiang Zhang Signed-off-by: Markus Armbruster Reviewed-by: zhanghailiang Message-Id: <20200630090351.1247703-9-armbru@redhat.com> --- qga/commands-posix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index ae1348dc8f..cdbeb59dcc 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -2421,6 +2421,7 @@ static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk, if (sys2memblk) { error_propagate(errp, local_err); } else { + error_free(local_err); result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED; } From b98e8d1230ff7023bb34ddeb7194424dfcbaf789 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:34 +0200 Subject: [PATCH 1756/2595] sd/milkymist-memcard: Plug minor memory leak in realize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit milkymist_memcard_realize() leaks an Error object when realization of its "sd-card" device fails. Quite harmless, since we only ever realize this once, in milkymist_init() via milkymist_memcard_create(). Plug the leak. Fixes: 3d0369ba499866cc6a839f71212d97876500762d Cc: Philippe Mathieu-Daudé Cc: Michael Walle Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-10-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/sd/milkymist-memcard.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index 482e97191e..afdb8aa0c0 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -280,9 +280,8 @@ static void milkymist_memcard_realize(DeviceState *dev, Error **errp) blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk); - qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err); - if (err) { - error_setg(errp, "failed to init SD card: %s", error_get_pretty(err)); + if (!qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err)) { + error_propagate_prepend(errp, err, "failed to init SD card: %s"); return; } s->enabled = blk && blk_is_inserted(blk); From 05584d12ae0c818665637b7ec580b600920d3027 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:35 +0200 Subject: [PATCH 1757/2595] test-util-filemonitor: Plug unlikely memory leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test_file_monitor_events() leaks an Error object when qemu_file_monitor_add_watch() fails, which seems unlikely. Plug it. Cc: Daniel P. Berrangé Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-11-armbru@redhat.com> Reviewed-by: Daniel P. Berrangé --- tests/test-util-filemonitor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test-util-filemonitor.c b/tests/test-util-filemonitor.c index 45009c69f4..8f0eff3d03 100644 --- a/tests/test-util-filemonitor.c +++ b/tests/test-util-filemonitor.c @@ -495,6 +495,7 @@ test_file_monitor_events(void) if (*op->watchid < 0) { g_printerr("Unable to add watch %s", error_get_pretty(local_err)); + error_free(local_err); goto cleanup; } if (debug) { From b94b3c02df87dc9cca1b395e836f6d83f3a3001f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:36 +0200 Subject: [PATCH 1758/2595] vnc: Plug minor memory leak in vnc_display_open() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vnc_display_print_local_addr() leaks the Error object when qio_channel_socket_get_local_address() fails. Seems unlikely. Called when we create a VNC display with vnc_display_open(). Plug the leak by passing NULL to ignore the error. Cc: Daniel P. Berrange Cc: Gerd Hoffmann Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-12-armbru@redhat.com> Reviewed-by: Daniel P. Berrangé --- ui/vnc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 0702a76cce..527ad25124 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3274,13 +3274,12 @@ int vnc_display_pw_expire(const char *id, time_t expires) static void vnc_display_print_local_addr(VncDisplay *vd) { SocketAddress *addr; - Error *err = NULL; if (!vd->listener || !vd->listener->nsioc) { return; } - addr = qio_channel_socket_get_local_address(vd->listener->sioc[0], &err); + addr = qio_channel_socket_get_local_address(vd->listener->sioc[0], NULL); if (!addr) { return; } From 123327d14e8ccca3e94986a9ea48fc61e8c2357d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:37 +0200 Subject: [PATCH 1759/2595] aspeed: Clean up roundabout error propagation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &local_err); error_propagate(&err, local_err); if (err) { error_propagate(errp, err); return; } by sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); if (err) { error_propagate(errp, err); return; } Cc: Cédric Le Goater Signed-off-by: Markus Armbruster Reviewed-by: Cédric Le Goater Message-Id: <20200630090351.1247703-13-armbru@redhat.com> --- hw/arm/aspeed_ast2600.c | 10 ++++------ hw/arm/aspeed_soc.c | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 6da687299f..08b3592e36 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -228,7 +228,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) int i; AspeedSoCState *s = ASPEED_SOC(dev); AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); - Error *err = NULL, *local_err = NULL; + Error *err = NULL; qemu_irq irq; /* IO space */ @@ -394,8 +394,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) return; } object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err); - sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &local_err); - error_propagate(&err, local_err); + sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); if (err) { error_propagate(errp, err); return; @@ -446,11 +445,10 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", &err); - sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &local_err); - error_propagate(&err, local_err); + sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err); if (err) { error_propagate(errp, err); - return; + return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, sc->memmap[ASPEED_ETH1 + i]); diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 810cf9b6cc..ec21de50ce 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -218,7 +218,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) int i; AspeedSoCState *s = ASPEED_SOC(dev); AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); - Error *err = NULL, *local_err = NULL; + Error *err = NULL; /* IO space */ create_unimplemented_device("aspeed_soc.io", sc->memmap[ASPEED_IOMEM], @@ -340,8 +340,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* SPI */ for (i = 0; i < sc->spis_num; i++) { object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err); - sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &local_err); - error_propagate(&err, local_err); + sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); if (err) { error_propagate(errp, err); return; @@ -392,11 +391,10 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", &err); - sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &local_err); - error_propagate(&err, local_err); + sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err); if (err) { error_propagate(errp, err); - return; + return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, sc->memmap[ASPEED_ETH1 + i]); From cd7c866074ed413bb0ccb708f7660436beb4ce37 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:38 +0200 Subject: [PATCH 1760/2595] qdev: Drop qbus_set_bus_hotplug_handler() parameter @errp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All callers pass &error_abort. Drop the parameter. Cc: Paolo Bonzini Cc: "Daniel P. Berrangé" Cc: Eduardo Habkost Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-14-armbru@redhat.com> --- hw/core/bus.c | 4 ++-- hw/scsi/scsi-bus.c | 2 +- hw/usb/bus.c | 2 +- hw/xen/xen-bus.c | 2 +- hw/xen/xen-legacy-backend.c | 2 +- include/hw/qdev-core.h | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/core/bus.c b/hw/core/bus.c index 6cc28b334e..8d4e810d7f 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -29,9 +29,9 @@ void qbus_set_hotplug_handler(BusState *bus, Object *handler, Error **errp) QDEV_HOTPLUG_HANDLER_PROPERTY, errp); } -void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp) +void qbus_set_bus_hotplug_handler(BusState *bus) { - qbus_set_hotplug_handler(bus, OBJECT(bus), errp); + qbus_set_hotplug_handler(bus, OBJECT(bus), &error_abort); } int qbus_walk_children(BusState *bus, diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 27843bb04b..b878a08080 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -107,7 +107,7 @@ void scsi_bus_new(SCSIBus *bus, size_t bus_size, DeviceState *host, qbus_create_inplace(bus, bus_size, TYPE_SCSI_BUS, host, bus_name); bus->busnr = next_scsi_bus++; bus->info = info; - qbus_set_bus_hotplug_handler(BUS(bus), &error_abort); + qbus_set_bus_hotplug_handler(BUS(bus)); } static void scsi_dma_restart_bh(void *opaque) diff --git a/hw/usb/bus.c b/hw/usb/bus.c index a81aee2051..957559b18d 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -84,7 +84,7 @@ void usb_bus_new(USBBus *bus, size_t bus_size, USBBusOps *ops, DeviceState *host) { qbus_create_inplace(bus, bus_size, TYPE_USB_BUS, host, NULL); - qbus_set_bus_hotplug_handler(BUS(bus), &error_abort); + qbus_set_bus_hotplug_handler(BUS(bus)); bus->ops = ops; bus->busnr = next_usb_bus++; QTAILQ_INIT(&bus->free); diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index 4b00320f1c..c4e2162ae9 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -1391,5 +1391,5 @@ void xen_bus_init(void) BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - qbus_set_bus_hotplug_handler(bus, &error_abort); + qbus_set_bus_hotplug_handler(bus); } diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index 2335ee2e65..7d4b13351e 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -705,7 +705,7 @@ int xen_be_init(void) xen_sysdev = qdev_new(TYPE_XENSYSDEV); sysbus_realize_and_unref(SYS_BUS_DEVICE(xen_sysdev), &error_fatal); xen_sysbus = qbus_create(TYPE_XENSYSBUS, xen_sysdev, "xen-sysbus"); - qbus_set_bus_hotplug_handler(xen_sysbus, &error_abort); + qbus_set_bus_hotplug_handler(xen_sysbus); return 0; diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 7dc10be46f..78acdeaed6 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -537,7 +537,7 @@ char *qdev_get_dev_path(DeviceState *dev); void qbus_set_hotplug_handler(BusState *bus, Object *handler, Error **errp); -void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp); +void qbus_set_bus_hotplug_handler(BusState *bus); static inline bool qbus_is_hotpluggable(BusState *bus) { From 9bc6bfdf67287fcf5435f22f68e902bb19831243 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:39 +0200 Subject: [PATCH 1761/2595] qdev: Drop qbus_set_hotplug_handler() parameter @errp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qbus_set_hotplug_handler() is a simple wrapper around object_property_set_link(). object_property_set_link() fails when the property doesn't exist, is not settable, or its .check() method fails. These are all programming errors here, so passing &error_abort to qbus_set_hotplug_handler() is appropriate. Most of its callers do. Exceptions: * pcie_cap_slot_init(), shpc_init(), spapr_phb_realize() pass NULL, i.e. they ignore errors. * spapr_machine_init() passes &error_fatal. * s390_pcihost_realize(), virtio_serial_device_realize(), s390_pcihost_plug() pass the error to their callers. The latter two keep going after the error, which looks wrong. Drop the @errp parameter, and instead pass &error_abort to object_property_set_link(). Cc: Paolo Bonzini Cc: "Daniel P. Berrangé" Cc: Eduardo Habkost Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-15-armbru@redhat.com> --- hw/acpi/pcihp.c | 3 +-- hw/acpi/piix4.c | 2 +- hw/char/virtio-serial-bus.c | 4 ++-- hw/core/bus.c | 6 +++--- hw/pci/pcie.c | 2 +- hw/pci/shpc.c | 2 +- hw/ppc/spapr.c | 3 +-- hw/ppc/spapr_pci.c | 4 ++-- hw/s390x/ap-bridge.c | 2 +- hw/s390x/css-bridge.c | 2 +- hw/s390x/s390-pci-bus.c | 14 +++----------- hw/scsi/virtio-scsi.c | 4 ++-- hw/scsi/vmw_pvscsi.c | 2 +- hw/usb/dev-smartcard-reader.c | 2 +- include/hw/qdev-core.h | 3 +-- 15 files changed, 22 insertions(+), 33 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 33ea2b76ae..9e31ab2da4 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -246,8 +246,7 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) { PCIBus *sec = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev)); - qbus_set_hotplug_handler(BUS(sec), OBJECT(hotplug_dev), - &error_abort); + qbus_set_hotplug_handler(BUS(sec), OBJECT(hotplug_dev)); /* We don't have to overwrite any other hotplug handler yet */ assert(QLIST_EMPTY(&sec->child)); } diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 630ca6ec87..283422e0d3 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -506,7 +506,7 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp) piix4_acpi_system_hot_add_init(pci_address_space_io(dev), pci_get_bus(dev), s); - qbus_set_hotplug_handler(BUS(pci_get_bus(dev)), OBJECT(s), &error_abort); + qbus_set_hotplug_handler(BUS(pci_get_bus(dev)), OBJECT(s)); piix4_pm_add_propeties(s); } diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 262089c0c9..f9a4428bd6 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -1056,7 +1056,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp) /* Spawn a new virtio-serial bus on which the ports will ride as devices */ qbus_create_inplace(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS, dev, vdev->bus_name); - qbus_set_hotplug_handler(BUS(&vser->bus), OBJECT(vser), errp); + qbus_set_hotplug_handler(BUS(&vser->bus), OBJECT(vser)); vser->bus.vser = vser; QTAILQ_INIT(&vser->ports); @@ -1147,7 +1147,7 @@ static void virtio_serial_device_unrealize(DeviceState *dev) g_free(vser->post_load); } - qbus_set_hotplug_handler(BUS(&vser->bus), NULL, &error_abort); + qbus_set_hotplug_handler(BUS(&vser->bus), NULL); virtio_cleanup(vdev); } diff --git a/hw/core/bus.c b/hw/core/bus.c index 8d4e810d7f..544dd8a6fa 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -23,15 +23,15 @@ #include "qemu/module.h" #include "qapi/error.h" -void qbus_set_hotplug_handler(BusState *bus, Object *handler, Error **errp) +void qbus_set_hotplug_handler(BusState *bus, Object *handler) { object_property_set_link(OBJECT(bus), handler, - QDEV_HOTPLUG_HANDLER_PROPERTY, errp); + QDEV_HOTPLUG_HANDLER_PROPERTY, &error_abort); } void qbus_set_bus_hotplug_handler(BusState *bus) { - qbus_set_hotplug_handler(bus, OBJECT(bus), &error_abort); + qbus_set_hotplug_handler(bus, OBJECT(bus)); } int qbus_walk_children(BusState *bus, diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 086d0dfceb..5b48bae0f6 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -574,7 +574,7 @@ void pcie_cap_slot_init(PCIDevice *dev, PCIESlot *s) dev->exp.hpev_notified = false; qbus_set_hotplug_handler(BUS(pci_bridge_get_sec_bus(PCI_BRIDGE(dev))), - OBJECT(dev), NULL); + OBJECT(dev)); } void pcie_cap_slot_reset(PCIDevice *dev) diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index 99d65d5c4c..b00dce629c 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -649,7 +649,7 @@ int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, shpc_cap_update_dword(d); memory_region_add_subregion(bar, offset, &shpc->mmio); - qbus_set_hotplug_handler(BUS(sec_bus), OBJECT(d), NULL); + qbus_set_hotplug_handler(BUS(sec_bus), OBJECT(d)); d->cap_present |= QEMU_PCI_CAP_SHPC; return 0; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 44fd578ea9..f6f034d039 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3033,8 +3033,7 @@ static void spapr_machine_init(MachineState *machine) register_savevm_live("spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1, &savevm_htab_handlers, spapr); - qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine), - &error_fatal); + qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine)); qemu_register_boot_set(spapr_boot_set, spapr); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 329002ac04..0f00e2421f 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1719,7 +1719,7 @@ static void spapr_phb_unrealize(DeviceState *dev) address_space_remove_listeners(&sphb->iommu_as); address_space_destroy(&sphb->iommu_as); - qbus_set_hotplug_handler(BUS(phb->bus), NULL, &error_abort); + qbus_set_hotplug_handler(BUS(phb->bus), NULL); pci_unregister_root_bus(phb->bus); memory_region_del_subregion(get_system_memory(), &sphb->iowindow); @@ -1868,7 +1868,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE; } phb->bus = bus; - qbus_set_hotplug_handler(BUS(phb->bus), OBJECT(sphb), NULL); + qbus_set_hotplug_handler(BUS(phb->bus), OBJECT(sphb)); /* * Initialize PHB address space. diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c index c4e3188ad6..8bcf8ece9d 100644 --- a/hw/s390x/ap-bridge.c +++ b/hw/s390x/ap-bridge.c @@ -58,7 +58,7 @@ void s390_init_ap(void) bus = qbus_create(TYPE_AP_BUS, dev, TYPE_AP_BUS); /* Enable hotplugging */ - qbus_set_hotplug_handler(bus, OBJECT(dev), &error_abort); + qbus_set_hotplug_handler(bus, OBJECT(dev)); } static void ap_bridge_class_init(ObjectClass *oc, void *data) diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index e37a54d3f2..9d793d671e 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -111,7 +111,7 @@ VirtualCssBus *virtual_css_bus_init(void) cbus = VIRTUAL_CSS_BUS(bus); /* Enable hotplugging */ - qbus_set_hotplug_handler(bus, OBJECT(dev), &error_abort); + qbus_set_hotplug_handler(bus, OBJECT(dev)); css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false, 0, &error_abort); diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index a13978bb37..142e52a8ff 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -751,19 +751,11 @@ static void s390_pcihost_realize(DeviceState *dev, Error **errp) pci_setup_iommu(b, s390_pci_dma_iommu, s); bus = BUS(b); - qbus_set_hotplug_handler(bus, OBJECT(dev), &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + qbus_set_hotplug_handler(bus, OBJECT(dev)); phb->bus = b; s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, dev, NULL)); - qbus_set_hotplug_handler(BUS(s->bus), OBJECT(dev), &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + qbus_set_hotplug_handler(BUS(s->bus), OBJECT(dev)); s->iommu_table = g_hash_table_new_full(g_int64_hash, g_int64_equal, NULL, g_free); @@ -921,7 +913,7 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq); pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s); - qbus_set_hotplug_handler(BUS(&pb->sec_bus), OBJECT(s), errp); + qbus_set_hotplug_handler(BUS(&pb->sec_bus), OBJECT(s)); if (dev->hotplugged) { pci_default_write_config(pdev, PCI_PRIMARY_BUS, diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 9b72094a61..b49775269e 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -934,7 +934,7 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) scsi_bus_new(&s->bus, sizeof(s->bus), dev, &virtio_scsi_scsi_info, vdev->bus_name); /* override default SCSI bus hotplug-handler, with virtio-scsi's one */ - qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev), &error_abort); + qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev)); virtio_scsi_dataplane_setup(s, errp); } @@ -958,7 +958,7 @@ static void virtio_scsi_device_unrealize(DeviceState *dev) { VirtIOSCSI *s = VIRTIO_SCSI(dev); - qbus_set_hotplug_handler(BUS(&s->bus), NULL, &error_abort); + qbus_set_hotplug_handler(BUS(&s->bus), NULL); virtio_scsi_common_unrealize(dev); } diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index ec5bf9ea34..df07ab6bfb 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1147,7 +1147,7 @@ pvscsi_realizefn(PCIDevice *pci_dev, Error **errp) scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(pci_dev), &pvscsi_scsi_info, NULL); /* override default SCSI bus hotplug-handler, with pvscsi's one */ - qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(s), &error_abort); + qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(s)); pvscsi_reset_state(s); } diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index ada18c1983..fcfe216594 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1320,7 +1320,7 @@ static void ccid_realize(USBDevice *dev, Error **errp) usb_desc_init(dev); qbus_create_inplace(&s->bus, sizeof(s->bus), TYPE_CCID_BUS, DEVICE(dev), NULL); - qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev), &error_abort); + qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev)); s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP); s->bulk = usb_ep_get(dev, USB_TOKEN_IN, CCID_BULK_IN_EP); s->card = NULL; diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 78acdeaed6..fe78073c70 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -535,8 +535,7 @@ extern bool qdev_hot_removed; char *qdev_get_dev_path(DeviceState *dev); -void qbus_set_hotplug_handler(BusState *bus, Object *handler, Error **errp); - +void qbus_set_hotplug_handler(BusState *bus, Object *handler); void qbus_set_bus_hotplug_handler(BusState *bus); static inline bool qbus_is_hotpluggable(BusState *bus) From 2726dc51e0c8c4267ba7c10b5c89d6f842144b48 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:40 +0200 Subject: [PATCH 1762/2595] hw: Fix error API violation around object_property_set_link() The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. virtio_gpu_pci_base_realize(), virtio_vga_base_realize(), sparc32_ledma_device_realize(), sparc32_dma_realize(), sparc32_dma_realize() xilinx_axidma_realize(), mips_cps_realize(), macio_realize_ide(), xilinx_enet_realize(), and virtio_iommu_pci_realize() are wrong that way: they reuse the argument they pass to object_property_set_link() for another call. Harmless, because object_property_set_link() can't actually fail for them: it fails when the property doesn't exist, is not settable, or its .check() method fails. Fix by passing &error_abort instead. Cc: Gerd Hoffmann Cc: Mark Cave-Ayland Cc: "Edgar E. Iglesias" Cc: Alistair Francis Cc: Peter Maydell Cc: qemu-arm@nongnu.org Cc: Aleksandar Markovic Cc: Aurelien Jarno Cc: Aleksandar Rikalo Cc: Eric Auger Signed-off-by: Markus Armbruster Reviewed-by: Eric Auger Reviewed-by: Alistair Francis Message-Id: <20200630090351.1247703-16-armbru@redhat.com> Reviewed-by: Mark Cave-Ayland --- hw/display/virtio-gpu-pci.c | 2 +- hw/display/virtio-vga.c | 2 +- hw/dma/sparc32_dma.c | 6 +++--- hw/dma/xilinx_axidma.c | 12 ++---------- hw/mips/cps.c | 6 ++++-- hw/misc/macio/macio.c | 3 ++- hw/net/xilinx_axienet.c | 12 ++---------- hw/virtio/virtio-iommu-pci.c | 2 +- 8 files changed, 16 insertions(+), 29 deletions(-) diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index b532fe8b5f..41b88b878d 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -44,7 +44,7 @@ static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) for (i = 0; i < g->conf.max_outputs; i++) { object_property_set_link(OBJECT(g->scanout[i].con), OBJECT(vpci_dev), - "device", errp); + "device", &error_abort); } } diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 68a062ece6..67f409e106 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -154,7 +154,7 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) for (i = 0; i < g->conf.max_outputs; i++) { object_property_set_link(OBJECT(g->scanout[i].con), OBJECT(vpci_dev), - "device", errp); + "device", &error_abort); } } diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index f02aca6f40..2d7dbbb92d 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -346,7 +346,7 @@ static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp) d = qdev_new(TYPE_LANCE); object_property_add_child(OBJECT(dev), "lance", OBJECT(d)); qdev_set_nic_properties(d, nd); - object_property_set_link(OBJECT(d), OBJECT(dev), "dma", errp); + object_property_set_link(OBJECT(d), OBJECT(dev), "dma", &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(d), &error_fatal); } @@ -379,7 +379,7 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) } espdma = qdev_new(TYPE_SPARC32_ESPDMA_DEVICE); - object_property_set_link(OBJECT(espdma), iommu, "iommu", errp); + object_property_set_link(OBJECT(espdma), iommu, "iommu", &error_abort); object_property_add_child(OBJECT(s), "espdma", OBJECT(espdma)); sysbus_realize_and_unref(SYS_BUS_DEVICE(espdma), &error_fatal); @@ -394,7 +394,7 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(sbd, 0)); ledma = qdev_new(TYPE_SPARC32_LEDMA_DEVICE); - object_property_set_link(OBJECT(ledma), iommu, "iommu", errp); + object_property_set_link(OBJECT(ledma), iommu, "iommu", &error_abort); object_property_add_child(OBJECT(s), "ledma", OBJECT(ledma)); sysbus_realize_and_unref(SYS_BUS_DEVICE(ledma), &error_fatal); diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 6a9df2c4db..a069637bf2 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -537,7 +537,6 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(&s->rx_data_dev); XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM( &s->rx_control_dev); - Error *local_err = NULL; int i; object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA, @@ -548,11 +547,8 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) (Object **)&cs->dma, object_property_allow_set_link, OBJ_PROP_LINK_STRONG); - object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_err); - object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_err); - if (local_err) { - goto xilinx_axidma_realize_fail; - } + object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &error_abort); + object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &error_abort); for (i = 0; i < 2; i++) { struct Stream *st = &s->streams[i]; @@ -567,10 +563,6 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) address_space_init(&s->as, s->dma_mr ? s->dma_mr : get_system_memory(), "dma"); - return; - -xilinx_axidma_realize_fail: - error_propagate(errp, local_err); } static void xilinx_axidma_init(Object *obj) diff --git a/hw/mips/cps.c b/hw/mips/cps.c index cdfab19826..5382bc86f7 100644 --- a/hw/mips/cps.c +++ b/hw/mips/cps.c @@ -150,8 +150,10 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp", &err); object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev", &err); object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base", &err); - object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->gic.mr), "gic", &err); - object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc", &err); + object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->gic.mr), "gic", + &error_abort); + object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc", + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->gcr), &err); if (err != NULL) { error_propagate(errp, err); diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 8ba7af073c..3251c79f46 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -136,7 +136,8 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide, sysbus_connect_irq(sysbus_dev, 0, irq0); sysbus_connect_irq(sysbus_dev, 1, irq1); qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid); - object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma", errp); + object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma", + &error_abort); macio_ide_register_dma(ide); qdev_realize(DEVICE(ide), BUS(&s->macio_bus), errp); diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index c2f40b8ea9..679a359f9a 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -980,7 +980,6 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev); XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM( &s->rx_control_dev); - Error *local_err = NULL; object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet", (Object **) &ds->enet, @@ -990,11 +989,8 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) (Object **) &cs->enet, object_property_allow_set_link, OBJ_PROP_LINK_STRONG); - object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_err); - object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_err); - if (local_err) { - goto xilinx_enet_realize_fail; - } + object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &error_abort); + object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &error_abort); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf, @@ -1008,10 +1004,6 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) s->rxmem = g_malloc(s->c_rxmem); s->txmem = g_malloc(s->c_txmem); - return; - -xilinx_enet_realize_fail: - error_propagate(errp, local_err); } static void xilinx_enet_init(Object *obj) diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c index 32e3215d1d..4588361d6b 100644 --- a/hw/virtio/virtio-iommu-pci.c +++ b/hw/virtio/virtio-iommu-pci.c @@ -56,7 +56,7 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) } object_property_set_link(OBJECT(dev), OBJECT(pci_get_bus(&vpci_dev->pci_dev)), - "primary-bus", errp); + "primary-bus", &error_abort); qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } From c24d97168a3ec92d4d624bb463214e449be0a42d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:41 +0200 Subject: [PATCH 1763/2595] hw/arm: Drop useless object_property_set_link() error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit object_property_set_link() fails when the property doesn't exist, is not settable, or its .check() method fails. These are all programming errors here, so passing it &error_abort is appropriate. Cc: Peter Maydell Cc: "Cédric Le Goater" Cc: Andrew Jeffery Cc: Joel Stanley Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Cédric Le Goater Message-Id: <20200630090351.1247703-17-armbru@redhat.com> --- hw/arm/armsse.c | 53 ++++++++++------------------------------- hw/arm/armv7m.c | 7 ++---- hw/arm/aspeed_ast2600.c | 20 ++++------------ hw/arm/aspeed_soc.c | 14 ++++------- hw/arm/nrf51_soc.c | 6 +---- 5 files changed, 24 insertions(+), 76 deletions(-) diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 9ddde339ec..a851652b39 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -563,16 +563,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) &s->container, -1); } object_property_set_link(cpuobj, OBJECT(&s->cpu_container[i]), - "memory", &err); - if (err) { - error_propagate(errp, err); - return; - } - object_property_set_link(cpuobj, OBJECT(s), "idau", &err); - if (err) { - error_propagate(errp, err); - return; - } + "memory", &error_abort); + object_property_set_link(cpuobj, OBJECT(s), "idau", &error_abort); sysbus_realize(SYS_BUS_DEVICE(cpuobj), &err); if (err) { error_propagate(errp, err); @@ -699,11 +691,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) return; } object_property_set_link(OBJECT(&s->mpc[i]), OBJECT(&s->sram[i]), - "downstream", &err); - if (err) { - error_propagate(errp, err); - return; - } + "downstream", &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->mpc[i]), &err); if (err) { error_propagate(errp, err); @@ -754,11 +742,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer0), 0, armsse_get_common_irq_in(s, 3)); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer0), 0); - object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[0]", &err); - if (err) { - error_propagate(errp, err); - return; - } + object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[0]", + &error_abort); qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq); sysbus_realize(SYS_BUS_DEVICE(&s->timer1), &err); @@ -769,12 +754,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer1), 0, armsse_get_common_irq_in(s, 4)); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer1), 0); - object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[1]", &err); - if (err) { - error_propagate(errp, err); - return; - } - + object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[1]", + &error_abort); qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq); sysbus_realize(SYS_BUS_DEVICE(&s->dualtimer), &err); @@ -785,11 +766,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0, armsse_get_common_irq_in(s, 5)); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0); - object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", &err); - if (err) { - error_propagate(errp, err); - return; - } + object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", + &error_abort); if (info->has_mhus) { /* @@ -814,12 +792,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) port = g_strdup_printf("port[%d]", i + 3); mr = sysbus_mmio_get_region(mhu_sbd, 0); object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), - port, &err); + port, &error_abort); g_free(port); - if (err) { - error_propagate(errp, err); - return; - } /* * Each MHU has an irq line for each CPU: @@ -966,11 +940,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0, armsse_get_common_irq_in(s, 2)); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0); - object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err); - if (err) { - error_propagate(errp, err); - return; - } + object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc1), &err); if (err) { diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index ce83586e03..3308211e9c 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -170,11 +170,8 @@ static void armv7m_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(s->cpu), OBJECT(&s->container), "memory", &error_abort); if (object_property_find(OBJECT(s->cpu), "idau", NULL)) { - object_property_set_link(OBJECT(s->cpu), s->idau, "idau", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } + object_property_set_link(OBJECT(s->cpu), s->idau, "idau", + &error_abort); } if (object_property_find(OBJECT(s->cpu), "init-svtor", NULL)) { object_property_set_uint(OBJECT(s->cpu), s->init_svtor, diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 08b3592e36..4efac02e2b 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -341,11 +341,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* I2C */ - object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", &err); - if (err) { - error_propagate(errp, err); - return; - } + object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err); if (err) { error_propagate(errp, err); @@ -363,11 +360,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* FMC, The number of CS is set at the board level */ - object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram", &err); - if (err) { - error_propagate(errp, err); - return; - } + object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram", + &error_abort); object_property_set_int(OBJECT(&s->fmc), sc->memmap[ASPEED_SDRAM], "sdram-base", &err); if (err) { @@ -388,11 +382,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* SPI */ for (i = 0; i < sc->spis_num; i++) { object_property_set_link(OBJECT(&s->spi[i]), OBJECT(s->dram_mr), - "dram", &err); - if (err) { - error_propagate(errp, err); - return; - } + "dram", &error_abort); object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err); sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); if (err) { diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index ec21de50ce..03b91bade6 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -300,11 +300,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } /* I2C */ - object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", &err); - if (err) { - error_propagate(errp, err); - return; - } + object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err); if (err) { error_propagate(errp, err); @@ -315,11 +312,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_I2C)); /* FMC, The number of CS is set at the board level */ - object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram", &err); - if (err) { - error_propagate(errp, err); - return; - } + object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram", + &error_abort); object_property_set_int(OBJECT(&s->fmc), sc->memmap[ASPEED_SDRAM], "sdram-base", &err); if (err) { diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index 5a8961ddbb..20dd8b5897 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -66,11 +66,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) } object_property_set_link(OBJECT(&s->cpu), OBJECT(&s->container), "memory", - &err); - if (err) { - error_propagate(errp, err); - return; - } + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->cpu), &err); if (err) { error_propagate(errp, err); From cbe3a8c582f964a222b64bce02a0a3ae22dc0efd Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:42 +0200 Subject: [PATCH 1764/2595] riscv/sifive_u: Fix sifive_u_soc_realize() error API violations The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. sifive_u_soc_realize() is wrong that way: it passes &err to sysbus_realize() four times before checking it. Harmless, because the first three can't actually fail (I think). Fix by checking for failure right away. Cc: Palmer Dabbelt Cc: Alistair Francis Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: Bin Meng Cc: qemu-riscv@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Alistair Francis Message-Id: <20200630090351.1247703-18-armbru@redhat.com> --- hw/riscv/sifive_u.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 7d051e7c92..a1d2edfe13 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -677,11 +677,15 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) memmap[SIFIVE_U_CLINT].size, ms->smp.cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false); - sysbus_realize(SYS_BUS_DEVICE(&s->prci), &err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) { + return; + } sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base); qdev_prop_set_uint32(DEVICE(&s->gpio), "ngpio", 16); - sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { + return; + } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_U_GPIO].base); /* Pass all GPIOs to the SOC layer so they are available to the board */ @@ -695,7 +699,9 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) } qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial); - sysbus_realize(SYS_BUS_DEVICE(&s->otp), &err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->otp), errp)) { + return; + } sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base); if (nd->used) { From 3e9a88c3721cd0171ab4e51f0b3617befd124e2a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:43 +0200 Subject: [PATCH 1765/2595] riscv_hart: Fix riscv_harts_realize() error API violations The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. riscv_harts_realize() is wrong that way: it passes @errp to riscv_hart_realize() in a loop. I can't tell offhand whether this can fail. Fix by checking for failure in each iteration. Cc: Palmer Dabbelt Cc: Alistair Francis Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: Bin Meng Cc: qemu-riscv@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Alistair Francis Message-Id: <20200630090351.1247703-19-armbru@redhat.com> --- hw/riscv/riscv_hart.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c index e26c382259..f59fe52f0f 100644 --- a/hw/riscv/riscv_hart.c +++ b/hw/riscv/riscv_hart.c @@ -40,19 +40,13 @@ static void riscv_harts_cpu_reset(void *opaque) cpu_reset(CPU(cpu)); } -static void riscv_hart_realize(RISCVHartArrayState *s, int idx, +static bool riscv_hart_realize(RISCVHartArrayState *s, int idx, char *cpu_type, Error **errp) { - Error *err = NULL; - object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], cpu_type); s->harts[idx].env.mhartid = s->hartid_base + idx; qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]); - qdev_realize(DEVICE(&s->harts[idx]), NULL, &err); - if (err) { - error_propagate(errp, err); - return; - } + return qdev_realize(DEVICE(&s->harts[idx]), NULL, errp); } static void riscv_harts_realize(DeviceState *dev, Error **errp) @@ -63,7 +57,9 @@ static void riscv_harts_realize(DeviceState *dev, Error **errp) s->harts = g_new0(RISCVCPU, s->num_harts); for (n = 0; n < s->num_harts; n++) { - riscv_hart_realize(s, n, s->cpu_type, errp); + if (!riscv_hart_realize(s, n, s->cpu_type, errp)) { + return; + } } } From 81f66cfd24ccd2645b19366d768a72f20ea3838b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:44 +0200 Subject: [PATCH 1766/2595] mips/cps: Fix mips_cps_realize() error API violations The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. mips_cps_realize() is wrong that way: it passes &err to multiple object_property_set_FOO() without checking for failure, and then to sysbus_realize(). Harmless, because the object_property_set_FOO() can't actually fail here. Fix by passing &error_abort instead. Cc: Aleksandar Markovic Cc: Aurelien Jarno Cc: Aleksandar Rikalo Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-20-armbru@redhat.com> --- hw/mips/cps.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/hw/mips/cps.c b/hw/mips/cps.c index 5382bc86f7..0d7f3cf673 100644 --- a/hw/mips/cps.c +++ b/hw/mips/cps.c @@ -100,10 +100,12 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) /* Inter-Thread Communication Unit */ if (itu_present) { object_initialize_child(OBJECT(dev), "itu", &s->itu, TYPE_MIPS_ITU); - object_property_set_int(OBJECT(&s->itu), 16, "num-fifo", &err); - object_property_set_int(OBJECT(&s->itu), 16, "num-semaphores", &err); + object_property_set_int(OBJECT(&s->itu), 16, "num-fifo", + &error_abort); + object_property_set_int(OBJECT(&s->itu), 16, "num-semaphores", + &error_abort); object_property_set_bool(OBJECT(&s->itu), saar_present, "saar-present", - &err); + &error_abort); if (saar_present) { s->itu.saar = &env->CP0_SAAR; } @@ -119,8 +121,10 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) /* Cluster Power Controller */ object_initialize_child(OBJECT(dev), "cpc", &s->cpc, TYPE_MIPS_CPC); - object_property_set_int(OBJECT(&s->cpc), s->num_vp, "num-vp", &err); - object_property_set_int(OBJECT(&s->cpc), 1, "vp-start-running", &err); + object_property_set_int(OBJECT(&s->cpc), s->num_vp, "num-vp", + &error_abort); + object_property_set_int(OBJECT(&s->cpc), 1, "vp-start-running", + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->cpc), &err); if (err != NULL) { error_propagate(errp, err); @@ -132,8 +136,10 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) /* Global Interrupt Controller */ object_initialize_child(OBJECT(dev), "gic", &s->gic, TYPE_MIPS_GIC); - object_property_set_int(OBJECT(&s->gic), s->num_vp, "num-vp", &err); - object_property_set_int(OBJECT(&s->gic), 128, "num-irq", &err); + object_property_set_int(OBJECT(&s->gic), s->num_vp, "num-vp", + &error_abort); + object_property_set_int(OBJECT(&s->gic), 128, "num-irq", + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); if (err != NULL) { error_propagate(errp, err); @@ -147,9 +153,12 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) gcr_base = env->CP0_CMGCRBase << 4; object_initialize_child(OBJECT(dev), "gcr", &s->gcr, TYPE_MIPS_GCR); - object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp", &err); - object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev", &err); - object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base", &err); + object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp", + &error_abort); + object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev", + &error_abort); + object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base", + &error_abort); object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->gic.mr), "gic", &error_abort); object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc", From 8c6cc7b9df36e0ca6f562a46f2afd883b6dc6867 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Wed, 24 Jun 2020 03:52:15 -0400 Subject: [PATCH 1767/2595] pc-bios: s390x: cio.c cleanup and compile fix Let's initialize the structs at the beginning to ease reading and also zeroing all other fields. This also makes the compiler stop complaining about sense_id_ccw.flags being ored into when it's not initialized. Signed-off-by: Janosch Frank Reviewed-by: Pierre Morel Reviewed-by: Thomas Huth Reviewed-by: David Hildenbrand Reviewed-by: Christian Borntraeger Reviewed-by: Cornelia Huck Message-Id: <20200624075226.92728-2-frankja@linux.ibm.com> Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/cio.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c index 339ec5fbe7..83ca27ab41 100644 --- a/pc-bios/s390-ccw/cio.c +++ b/pc-bios/s390-ccw/cio.c @@ -49,13 +49,13 @@ void enable_subchannel(SubChannelId schid) uint16_t cu_type(SubChannelId schid) { - Ccw1 sense_id_ccw; SenseId sense_data; - - sense_id_ccw.cmd_code = CCW_CMD_SENSE_ID; - sense_id_ccw.cda = ptr2u32(&sense_data); - sense_id_ccw.count = sizeof(sense_data); - sense_id_ccw.flags |= CCW_FLAG_SLI; + Ccw1 sense_id_ccw = { + .cmd_code = CCW_CMD_SENSE_ID, + .flags = CCW_FLAG_SLI, + .count = sizeof(sense_data), + .cda = ptr2u32(&sense_data), + }; if (do_cio(schid, CU_TYPE_UNKNOWN, ptr2u32(&sense_id_ccw), CCW_FMT1)) { panic("Failed to run SenseID CCw\n"); @@ -67,13 +67,13 @@ uint16_t cu_type(SubChannelId schid) int basic_sense(SubChannelId schid, uint16_t cutype, void *sense_data, uint16_t data_size) { - Ccw1 senseCcw; + Ccw1 senseCcw = { + .cmd_code = CCW_CMD_BASIC_SENSE, + .count = data_size, + .cda = ptr2u32(sense_data), + }; Irb irb; - senseCcw.cmd_code = CCW_CMD_BASIC_SENSE; - senseCcw.cda = ptr2u32(sense_data); - senseCcw.count = data_size; - return __do_cio(schid, ptr2u32(&senseCcw), CCW_FMT1, &irb); } @@ -314,7 +314,17 @@ static void print_irb_err(Irb *irb) */ static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb) { - CmdOrb orb = {}; + /* + * QEMU's CIO implementation requires prefetch and 64-bit idaws. We + * allow all paths. + */ + CmdOrb orb = { + .fmt = fmt, + .pfch = 1, + .c64 = 1, + .lpm = 0xFF, + .cpa = ccw_addr, + }; int rc; IPL_assert(fmt == 0 || fmt == 1, "Invalid ccw format"); @@ -324,12 +334,6 @@ static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb) IPL_assert(ccw_addr <= 0xFFFFFF - 8, "Invalid ccw address"); } - orb.fmt = fmt; - orb.pfch = 1; /* QEMU's cio implementation requires prefetch */ - orb.c64 = 1; /* QEMU's cio implementation requires 64-bit idaws */ - orb.lpm = 0xFF; /* All paths allowed */ - orb.cpa = ccw_addr; - rc = ssch(schid, &orb); if (rc == 1 || rc == 2) { /* Subchannel status pending or busy. Eat status and ask for retry. */ From e70bc57ba0c982944cf5b71f293122dbb2b462f4 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Wed, 24 Jun 2020 03:52:16 -0400 Subject: [PATCH 1768/2595] pc-bios: s390x: Consolidate timing functions into time.h Let's consolidate timing related functions into one header. Signed-off-by: Janosch Frank Acked-by: Thomas Huth Reviewed-by: David Hildenbrand Message-Id: <20200624075226.92728-3-frankja@linux.ibm.com> Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/menu.c | 1 + pc-bios/s390-ccw/netmain.c | 15 +++------------ pc-bios/s390-ccw/s390-ccw.h | 8 ++++---- pc-bios/s390-ccw/s390-time.h | 23 +++++++++++++++++++++++ pc-bios/s390-ccw/virtio-net.c | 1 + pc-bios/s390-ccw/virtio-scsi.c | 1 + pc-bios/s390-ccw/virtio.c | 18 +++--------------- 7 files changed, 36 insertions(+), 31 deletions(-) create mode 100644 pc-bios/s390-ccw/s390-time.h diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c index ce3815b201..de8260a5d6 100644 --- a/pc-bios/s390-ccw/menu.c +++ b/pc-bios/s390-ccw/menu.c @@ -12,6 +12,7 @@ #include "libc.h" #include "s390-ccw.h" #include "sclp.h" +#include "s390-time.h" #define KEYCODE_NO_INP '\0' #define KEYCODE_ESCAPE '\033' diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c index 309ffa30d9..f1ee63577a 100644 --- a/pc-bios/s390-ccw/netmain.c +++ b/pc-bios/s390-ccw/netmain.c @@ -35,6 +35,7 @@ #include "s390-ccw.h" #include "cio.h" #include "virtio.h" +#include "s390-time.h" #define DEFAULT_BOOT_RETRIES 10 #define DEFAULT_TFTP_RETRIES 20 @@ -57,24 +58,14 @@ static SubChannelId net_schid = { .one = 1 }; static uint8_t mac[6]; static uint64_t dest_timer; -static uint64_t get_timer_ms(void) -{ - uint64_t clk; - - asm volatile(" stck %0 " : : "Q"(clk) : "memory"); - - /* Bit 51 is incremented each microsecond */ - return (clk >> (63 - 51)) / 1000; -} - void set_timer(int val) { - dest_timer = get_timer_ms() + val; + dest_timer = get_time_ms() + val; } int get_timer(void) { - return dest_timer - get_timer_ms(); + return dest_timer - get_time_ms(); } int get_sec_ticks(void) diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index 21f27e7990..fae1de363f 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -74,8 +74,6 @@ unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2, bool virtio_is_supported(SubChannelId schid); void virtio_blk_setup_device(SubChannelId schid); int virtio_read(ulong sector, void *load_addr); -u64 get_clock(void); -ulong get_second(void); /* bootmap.c */ void zipl_load(void); @@ -153,11 +151,13 @@ static inline void yield(void) #define MAX_SECTOR_SIZE 4096 +#include "s390-time.h" + static inline void sleep(unsigned int seconds) { - ulong target = get_second() + seconds; + ulong target = get_time_seconds() + seconds; - while (get_second() < target) { + while (get_time_seconds() < target) { yield(); } } diff --git a/pc-bios/s390-ccw/s390-time.h b/pc-bios/s390-ccw/s390-time.h new file mode 100644 index 0000000000..ed6d982371 --- /dev/null +++ b/pc-bios/s390-ccw/s390-time.h @@ -0,0 +1,23 @@ +#ifndef TIME_H +#define TIME_H + +static inline u64 get_clock(void) +{ + u64 r; + + asm volatile("stck %0" : "=Q" (r) : : "cc"); + return r; +} + +static inline u64 get_time_ms(void) +{ + /* Bit 51 is incremented each microsecond */ + return (get_clock() >> 12) / 1000; +} + +static inline u64 get_time_seconds(void) +{ + return get_time_ms() / 1000; +} + +#endif diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c index ff7f4dad25..a13f3b6fb9 100644 --- a/pc-bios/s390-ccw/virtio-net.c +++ b/pc-bios/s390-ccw/virtio-net.c @@ -19,6 +19,7 @@ #include #include "s390-ccw.h" #include "virtio.h" +#include "s390-time.h" #ifndef DEBUG_VIRTIO_NET #define DEBUG_VIRTIO_NET 0 diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c index 4fe4b9d261..7bf0be4ffa 100644 --- a/pc-bios/s390-ccw/virtio-scsi.c +++ b/pc-bios/s390-ccw/virtio-scsi.c @@ -14,6 +14,7 @@ #include "virtio.h" #include "scsi.h" #include "virtio-scsi.h" +#include "s390-time.h" static ScsiDevice default_scsi_device; static VirtioScsiCmdReq req; diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index fb40ca9828..ab49840db8 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -15,6 +15,7 @@ #include "virtio-scsi.h" #include "bswap.h" #include "helper.h" +#include "s390-time.h" #define VRING_WAIT_REPLY_TIMEOUT 30 @@ -157,19 +158,6 @@ void vring_send_buf(VRing *vr, void *p, int len, int flags) } } -u64 get_clock(void) -{ - u64 r; - - asm volatile("stck %0" : "=Q" (r) : : "cc"); - return r; -} - -ulong get_second(void) -{ - return (get_clock() >> 12) / 1000000; -} - int vr_poll(VRing *vr) { if (vr->used->idx == vr->used_idx) { @@ -194,7 +182,7 @@ int vr_poll(VRing *vr) */ int vring_wait_reply(void) { - ulong target_second = get_second() + vdev.wait_reply_timeout; + ulong target_second = get_time_seconds() + vdev.wait_reply_timeout; /* Wait for any queue to be updated by the host */ do { @@ -207,7 +195,7 @@ int vring_wait_reply(void) if (r) { return 0; } - } while (!vdev.wait_reply_timeout || (get_second() < target_second)); + } while (!vdev.wait_reply_timeout || (get_time_seconds() < target_second)); return 1; } From 12ea90dbd8fc38ca937acb53c730818077bf86fe Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Wed, 24 Jun 2020 03:52:17 -0400 Subject: [PATCH 1769/2595] pc-bios: s390x: Move sleep and yield to helper.h They are definitely helper functions. Signed-off-by: Janosch Frank Reviewed-by: Christian Borntraeger Reviewed-by: Thomas Huth Reviewed-by: David Hildenbrand Message-Id: <20200624075226.92728-4-frankja@linux.ibm.com> Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/helper.h | 17 +++++++++++++++++ pc-bios/s390-ccw/s390-ccw.h | 18 ------------------ pc-bios/s390-ccw/virtio-net.c | 1 + pc-bios/s390-ccw/virtio-scsi.c | 1 + 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/pc-bios/s390-ccw/helper.h b/pc-bios/s390-ccw/helper.h index 78d5bc7442..32a453b634 100644 --- a/pc-bios/s390-ccw/helper.h +++ b/pc-bios/s390-ccw/helper.h @@ -14,6 +14,7 @@ #define S390_CCW_HELPER_H #include "s390-ccw.h" +#include "s390-time.h" /* Avoids compiler warnings when casting a pointer to a u32 */ static inline uint32_t ptr2u32(void *ptr) @@ -28,4 +29,20 @@ static inline void *u32toptr(uint32_t n) return (void *)(uint64_t)n; } +static inline void yield(void) +{ + asm volatile ("diag 0,0,0x44" + : : + : "memory", "cc"); +} + +static inline void sleep(unsigned int seconds) +{ + ulong target = get_time_seconds() + seconds; + + while (get_time_seconds() < target) { + yield(); + } +} + #endif diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index fae1de363f..c5820e43ae 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -142,26 +142,8 @@ static inline void debug_print_addr(const char *desc, void *p) #define KVM_S390_VIRTIO_SET_STATUS 2 #define KVM_S390_VIRTIO_CCW_NOTIFY 3 -static inline void yield(void) -{ - asm volatile ("diag 0,0,0x44" - : : - : "memory", "cc"); -} - #define MAX_SECTOR_SIZE 4096 -#include "s390-time.h" - -static inline void sleep(unsigned int seconds) -{ - ulong target = get_time_seconds() + seconds; - - while (get_time_seconds() < target) { - yield(); - } -} - static inline void IPL_assert(bool term, const char *message) { if (!term) { diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c index a13f3b6fb9..2fcb0a58c5 100644 --- a/pc-bios/s390-ccw/virtio-net.c +++ b/pc-bios/s390-ccw/virtio-net.c @@ -20,6 +20,7 @@ #include "s390-ccw.h" #include "virtio.h" #include "s390-time.h" +#include "helper.h" #ifndef DEBUG_VIRTIO_NET #define DEBUG_VIRTIO_NET 0 diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c index 7bf0be4ffa..eddfb8a7ad 100644 --- a/pc-bios/s390-ccw/virtio-scsi.c +++ b/pc-bios/s390-ccw/virtio-scsi.c @@ -15,6 +15,7 @@ #include "scsi.h" #include "virtio-scsi.h" #include "s390-time.h" +#include "helper.h" static ScsiDevice default_scsi_device; static VirtioScsiCmdReq req; From e6d393d097ac09c9146772a829fff1bfaf61eb9d Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Wed, 24 Jun 2020 03:52:18 -0400 Subject: [PATCH 1770/2595] pc-bios: s390x: Get rid of magic offsets into the lowcore If we have a lowcore struct that has members for offsets that we want to touch, why not use it? Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Thomas Huth Reviewed-by: Cornelia Huck Message-Id: <20200624075226.92728-5-frankja@linux.ibm.com> Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/cio.h | 17 +++++++++++------ pc-bios/s390-ccw/main.c | 8 +++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h index aaa432dedd..1e5d4e92e1 100644 --- a/pc-bios/s390-ccw/cio.h +++ b/pc-bios/s390-ccw/cio.h @@ -122,12 +122,17 @@ typedef struct schib { } __attribute__ ((packed, aligned(4))) Schib; typedef struct subchannel_id { - __u32 cssid:8; - __u32:4; - __u32 m:1; - __u32 ssid:2; - __u32 one:1; - __u32 sch_no:16; + union { + struct { + __u16 cssid:8; + __u16 reserved:4; + __u16 m:1; + __u16 ssid:2; + __u16 one:1; + }; + __u16 sch_id; + }; + __u16 sch_no; } __attribute__ ((packed, aligned(4))) SubChannelId; struct chsc_header { diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index 4e65b411e1..8b912454c9 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -36,11 +36,9 @@ LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */ */ void write_subsystem_identification(void) { - SubChannelId *schid = (SubChannelId *) 184; - uint32_t *zeroes = (uint32_t *) 188; - - *schid = blk_schid; - *zeroes = 0; + lowcore->subchannel_id = blk_schid.sch_id; + lowcore->subchannel_nr = blk_schid.sch_no; + lowcore->io_int_parm = 0; } void write_iplb_location(void) From b88faa1c899db2fae8b5b168aeb6c47bef090f27 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Wed, 24 Jun 2020 03:52:20 -0400 Subject: [PATCH 1771/2595] pc-bios: s390x: Rename PSW_MASK_ZMODE to PSW_MASK_64 This constant enables 64 bit addressing, not the ESAME architecture, so it shouldn't be named ZMODE. Signed-off-by: Janosch Frank Reviewed-by: Thomas Huth Message-Id: <20200624075226.92728-7-frankja@linux.ibm.com> Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/s390-arch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/s390-ccw/s390-arch.h b/pc-bios/s390-ccw/s390-arch.h index 5f36361c02..73852029d4 100644 --- a/pc-bios/s390-ccw/s390-arch.h +++ b/pc-bios/s390-ccw/s390-arch.h @@ -29,7 +29,7 @@ _Static_assert(sizeof(struct PSWLegacy) == 8, "PSWLegacy size incorrect"); #define PSW_MASK_WAIT 0x0002000000000000ULL #define PSW_MASK_EAMODE 0x0000000100000000ULL #define PSW_MASK_BAMODE 0x0000000080000000ULL -#define PSW_MASK_ZMODE (PSW_MASK_EAMODE | PSW_MASK_BAMODE) +#define PSW_MASK_64 (PSW_MASK_EAMODE | PSW_MASK_BAMODE) /* Low core mapping */ typedef struct LowCore { From fe75c657b8ee962da79f5d3518b139e26dc69c24 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Wed, 24 Jun 2020 03:52:21 -0400 Subject: [PATCH 1772/2595] pc-bios: s390x: Use PSW masks where possible and introduce PSW_MASK_SHORT_ADDR Let's move some of the PSW mask defines into s390-arch.h and use them in jump2ipl.c. Also let's introduce a new constant for the address mask of 8 byte (short) PSWs. Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Thomas Huth Message-Id: <20200624075226.92728-8-frankja@linux.ibm.com> Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/jump2ipl.c | 10 ++++------ pc-bios/s390-ccw/s390-arch.h | 2 ++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c index 4eba2510b0..767012bf0c 100644 --- a/pc-bios/s390-ccw/jump2ipl.c +++ b/pc-bios/s390-ccw/jump2ipl.c @@ -8,12 +8,10 @@ #include "libc.h" #include "s390-ccw.h" +#include "s390-arch.h" #define KERN_IMAGE_START 0x010000UL -#define PSW_MASK_64 0x0000000100000000ULL -#define PSW_MASK_32 0x0000000080000000ULL -#define PSW_MASK_SHORTPSW 0x0008000000000000ULL -#define RESET_PSW_MASK (PSW_MASK_SHORTPSW | PSW_MASK_32 | PSW_MASK_64) +#define RESET_PSW_MASK (PSW_MASK_SHORTPSW | PSW_MASK_64) typedef struct ResetInfo { uint64_t ipl_psw; @@ -54,7 +52,7 @@ void jump_to_IPL_code(uint64_t address) current->ipl_psw = (uint64_t) &jump_to_IPL_2; current->ipl_psw |= RESET_PSW_MASK; - current->ipl_continue = address & 0x7fffffff; + current->ipl_continue = address & PSW_MASK_SHORT_ADDR; debug_print_int("set IPL addr to", current->ipl_continue); @@ -86,7 +84,7 @@ void jump_to_low_kernel(void) /* Trying to get PSW at zero address */ if (*((uint64_t *)0) & RESET_PSW_MASK) { - jump_to_IPL_code((*((uint64_t *)0)) & 0x7fffffff); + jump_to_IPL_code((*((uint64_t *)0)) & PSW_MASK_SHORT_ADDR); } /* No other option left, so use the Linux kernel start address */ diff --git a/pc-bios/s390-ccw/s390-arch.h b/pc-bios/s390-ccw/s390-arch.h index 73852029d4..6da44d4436 100644 --- a/pc-bios/s390-ccw/s390-arch.h +++ b/pc-bios/s390-ccw/s390-arch.h @@ -26,9 +26,11 @@ _Static_assert(sizeof(struct PSWLegacy) == 8, "PSWLegacy size incorrect"); /* s390 psw bit masks */ #define PSW_MASK_IOINT 0x0200000000000000ULL +#define PSW_MASK_SHORTPSW 0x0008000000000000ULL #define PSW_MASK_WAIT 0x0002000000000000ULL #define PSW_MASK_EAMODE 0x0000000100000000ULL #define PSW_MASK_BAMODE 0x0000000080000000ULL +#define PSW_MASK_SHORT_ADDR 0x000000007fffffffULL #define PSW_MASK_64 (PSW_MASK_EAMODE | PSW_MASK_BAMODE) /* Low core mapping */ From add923b72e76080ca5339a27d58ed13566156935 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Wed, 24 Jun 2020 03:52:22 -0400 Subject: [PATCH 1773/2595] pc-bios: s390x: Move panic() into header and add infinite loop panic() was defined for the ccw and net bios, i.e. twice, so it's cleaner to rather put it into the header. Also let's add an infinite loop into the assembly of disabled_wait() so the caller doesn't need to take care of it. Signed-off-by: Janosch Frank Reviewed-by: Pierre Morel Reviewed-by: David Hildenbrand Reviewed-by: Thomas Huth Message-Id: <20200624075226.92728-9-frankja@linux.ibm.com> Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/main.c | 7 ------- pc-bios/s390-ccw/netmain.c | 8 -------- pc-bios/s390-ccw/s390-ccw.h | 9 +++++++-- pc-bios/s390-ccw/start.S | 5 +++-- 4 files changed, 10 insertions(+), 19 deletions(-) diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index 8b912454c9..146a50760b 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -46,13 +46,6 @@ void write_iplb_location(void) lowcore->ptr_iplb = ptr2u32(&iplb); } -void panic(const char *string) -{ - sclp_print(string); - disabled_wait(); - while (1) { } -} - unsigned int get_loadparm_index(void) { return atoui(loadparm_str); diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c index f1ee63577a..056e93a818 100644 --- a/pc-bios/s390-ccw/netmain.c +++ b/pc-bios/s390-ccw/netmain.c @@ -439,14 +439,6 @@ static int net_try_direct_tftp_load(filename_ip_t *fn_ip) return rc; } -void panic(const char *string) -{ - sclp_print(string); - for (;;) { - disabled_wait(); - } -} - void write_subsystem_identification(void) { SubChannelId *schid = (SubChannelId *) 184; diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index c5820e43ae..36b884cced 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -50,12 +50,11 @@ typedef unsigned long long __u64; #include "iplb.h" /* start.s */ -void disabled_wait(void); +void disabled_wait(void) __attribute__ ((__noreturn__)); void consume_sclp_int(void); void consume_io_int(void); /* main.c */ -void panic(const char *string); void write_subsystem_identification(void); void write_iplb_location(void); extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); @@ -91,6 +90,12 @@ bool menu_is_enabled_enum(void); #define MAX_BOOT_ENTRIES 31 +static inline void panic(const char *string) +{ + sclp_print(string); + disabled_wait(); +} + static inline void fill_hex(char *out, unsigned char val) { const char hex[] = "0123456789abcdef"; diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S index aa8fceb19d..ce519300a1 100644 --- a/pc-bios/s390-ccw/start.S +++ b/pc-bios/s390-ccw/start.S @@ -47,8 +47,9 @@ memsetxc: */ .globl disabled_wait disabled_wait: - larl %r1,disabled_wait_psw - lpswe 0(%r1) + larl %r1,disabled_wait_psw + lpswe 0(%r1) +1: j 1b /* From 78182aea78257edc6b03a167cf7159479aa2ae06 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Wed, 24 Jun 2020 03:52:23 -0400 Subject: [PATCH 1774/2595] pc-bios: s390x: Use ebcdic2ascii table Why should we do conversion of a ebcdic value if we have a handy table where we could look up the ascii value instead? Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Thomas Huth Message-Id: <20200624075226.92728-10-frankja@linux.ibm.com> Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/bootmap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c index d13b7cbd15..97205674e5 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -328,9 +328,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode) msg[0] = '2'; break; default: - msg[0] = vlbl->LDL_version; - msg[0] &= 0x0f; /* convert EBCDIC */ - msg[0] |= 0x30; /* to ASCII (digit) */ + msg[0] = ebc2asc[vlbl->LDL_version]; msg[1] = '?'; break; } From 9598c227aaff9f0c2ee7aee5b8013600b71bca15 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Wed, 24 Jun 2020 03:52:24 -0400 Subject: [PATCH 1775/2595] pc-bios: s390x: Make u32 ptr check explicit Let's make it a bit more clear that we check the full 64 bits to fit into the 32 we return. Signed-off-by: Janosch Frank Suggested-by: David Hildenbrand Reviewed-by: David Hildenbrand Reviewed-by: Thomas Huth Message-Id: <20200624075226.92728-11-frankja@linux.ibm.com> Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/s390-ccw/helper.h b/pc-bios/s390-ccw/helper.h index 32a453b634..dfcfea0ff0 100644 --- a/pc-bios/s390-ccw/helper.h +++ b/pc-bios/s390-ccw/helper.h @@ -19,7 +19,7 @@ /* Avoids compiler warnings when casting a pointer to a u32 */ static inline uint32_t ptr2u32(void *ptr) { - IPL_assert((uint64_t)ptr <= 0xffffffff, "ptr2u32: ptr too large"); + IPL_assert((uint64_t)ptr <= 0xffffffffull, "ptr2u32: ptr too large"); return (uint32_t)(uint64_t)ptr; } From 1c9f655066d1defbe083ef06723be919cdfc13dc Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 30 Jun 2020 16:17:30 +0200 Subject: [PATCH 1776/2595] pc-bios/s390-ccw: Generate and include dependency files in the Makefile The Makefile of the s390-ccw bios does not handle dependencies of the *.c files from the headers yet, so that you often have to run a "make clean" to get the build right when one of the headers has been changed. Let's make sure that we generate and include dependency files for all *.c files now to avoid this problem in the future. Acked-by: Cornelia Huck Message-Id: <20200630142955.7662-1-thuth@redhat.com> Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/Makefile | 3 +++ pc-bios/s390-ccw/netboot.mak | 13 +++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index a048b6b077..50bc880272 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -38,5 +38,8 @@ s390-netboot.img: @echo "s390-netboot.img not built since roms/SLOF/ is not available." endif +ALL_OBJS = $(sort $(OBJECTS) $(NETOBJS) $(LIBCOBJS) $(LIBNETOBJS)) +-include $(ALL_OBJS:%.o=%.d) + clean: rm -f *.o *.d *.img *.elf *~ *.a diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak index 5eefb7c289..577c023afe 100644 --- a/pc-bios/s390-ccw/netboot.mak +++ b/pc-bios/s390-ccw/netboot.mak @@ -1,8 +1,7 @@ SLOF_DIR := $(SRC_PATH)/roms/SLOF -NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o \ - libnet.a libc.a +NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include LIBNET_INC := -I$(SLOF_DIR)/lib/libnet @@ -11,15 +10,16 @@ NETLDFLAGS := $(LDFLAGS) -Ttext=0x7800000 $(NETOBJS): QEMU_CFLAGS += $(LIBC_INC) $(LIBNET_INC) -s390-netboot.elf: $(NETOBJS) - $(call quiet-command,$(CC) $(NETLDFLAGS) -o $@ $(NETOBJS),"BUILD","$(TARGET_DIR)$@") +s390-netboot.elf: $(NETOBJS) libnet.a libc.a + $(call quiet-command,$(CC) $(NETLDFLAGS) -o $@ $^,"BUILD","$(TARGET_DIR)$@") s390-netboot.img: s390-netboot.elf $(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@") # libc files: -LIBC_CFLAGS := $(QEMU_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) +LIBC_CFLAGS = $(QEMU_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \ + -MMD -MP -MT $@ -MF $(@:%.o=%.d) CTYPE_OBJS = isdigit.o isxdigit.o toupper.o %.o : $(SLOF_DIR)/lib/libc/ctype/%.c @@ -52,7 +52,8 @@ libc.a: $(LIBCOBJS) LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \ dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o -LIBNETCFLAGS := $(QEMU_CFLAGS) $(CFLAGS) -DDHCPARCH=0x1F $(LIBC_INC) $(LIBNET_INC) +LIBNETCFLAGS = $(QEMU_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \ + -DDHCPARCH=0x1F -MMD -MP -MT $@ -MF $(@:%.o=%.d) %.o : $(SLOF_DIR)/lib/libnet/%.c $(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@") From b71db6b9abb5af302c9669c133d78115c6437c45 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 2 Jul 2020 11:51:31 +0200 Subject: [PATCH 1777/2595] pc-bios/s390: Update s390-ccw bios binaries with the latest changes ... to make sure that the binaries match the current state of the sources. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw.img | Bin 42608 -> 42608 bytes pc-bios/s390-netboot.img | Bin 67232 -> 67232 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index b9da9d8ecb10faa484a9a524a202f1f69cb59ad6..3074686a8c7448d943aa62f810d88d3e92865ef3 100644 GIT binary patch literal 42608 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 M*2pCE*Bnp$A1vB}761SM literal 42608 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 From 18d588fe1e178b43203532a2debdffd4f36535c5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:45 +0200 Subject: [PATCH 1778/2595] x86: Fix x86_cpu_new() error handling The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. x86_cpu_new() is wrong that way: it passes &local_err to object_property_set_uint() without checking it, and then to qdev_realize(). If both fail, we'll trip error_setv()'s assertion. To assess the bug's impact, we'd need to figure out how to make both calls fail. Too much work for ignorant me, sorry. Fix by checking for failure right away. Cc: Igor Mammedov Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-21-armbru@redhat.com> Reviewed-by: Paolo Bonzini --- hw/i386/x86.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 34229b45c7..93f7371a56 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -118,14 +118,16 @@ uint32_t x86_cpu_apic_id_from_index(X86MachineState *x86ms, void x86_cpu_new(X86MachineState *x86ms, int64_t apic_id, Error **errp) { - Object *cpu = NULL; Error *local_err = NULL; - - cpu = object_new(MACHINE(x86ms)->cpu_type); + Object *cpu = object_new(MACHINE(x86ms)->cpu_type); object_property_set_uint(cpu, apic_id, "apic-id", &local_err); + if (local_err) { + goto out; + } qdev_realize(DEVICE(cpu), NULL, &local_err); +out: object_unref(cpu); error_propagate(errp, local_err); } From 475fc97d091c2cbcce0cd48c9fd70e966e5d1159 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:46 +0200 Subject: [PATCH 1779/2595] amd_iommu: Fix amdvi_realize() error API violation The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. amdvi_realize() is wrong that way: it passes @errp to qdev_realize(), object_property_get_int(), and msi_init() without checking it. I can't tell offhand whether qdev_realize() can fail here. Fix by checking it for failure. object_property_get_int() can't. Fix by passing &error_abort instead. Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-22-armbru@redhat.com> --- hw/i386/amd_iommu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index b26d30da57..087f601666 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1549,7 +1549,9 @@ static void amdvi_realize(DeviceState *dev, Error **errp) /* This device should take care of IOMMU PCI properties */ x86_iommu->type = TYPE_AMD; - qdev_realize(DEVICE(&s->pci), &bus->qbus, errp); + if (!qdev_realize(DEVICE(&s->pci), &bus->qbus, errp)) { + return; + } ret = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0, AMDVI_CAPAB_SIZE, errp); if (ret < 0) { @@ -1578,7 +1580,7 @@ static void amdvi_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, AMDVI_BASE_ADDR); pci_setup_iommu(bus, amdvi_host_dma_iommu, s); - s->devid = object_property_get_int(OBJECT(&s->pci), "addr", errp); + s->devid = object_property_get_int(OBJECT(&s->pci), "addr", &error_abort); msi_init(&s->pci.dev, 0, 1, true, false, errp); amdvi_init(s); } From b40181942e037f74cd12ae7afa140d6508a30639 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:47 +0200 Subject: [PATCH 1780/2595] arm/stm32f205 arm/stm32f405: Fix realize error API violation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. stm32f205_soc_realize() and stm32f405_soc_realize() are wrong that way: they pass &err to object_property_set_int() without checking it, and then to qdev_realize(). Harmless, because the former can't actually fail here. Fix by passing &error_abort instead. Cc: Alistair Francis Cc: Peter Maydell Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Alistair Francis Message-Id: <20200630090351.1247703-23-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/arm/stm32f205_soc.c | 2 +- hw/arm/stm32f405_soc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index 19487544f0..56aef686c9 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -154,7 +154,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) /* ADC 1 to 3 */ object_property_set_int(OBJECT(s->adc_irqs), STM_NUM_ADCS, - "num-lines", &err); + "num-lines", &error_abort); qdev_realize(DEVICE(s->adc_irqs), NULL, &err); if (err != NULL) { error_propagate(errp, err); diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index c12d9f999d..cf9228d8e7 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -172,7 +172,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) return; } object_property_set_int(OBJECT(&s->adc_irqs), STM_NUM_ADCS, - "num-lines", &err); + "num-lines", &error_abort); qdev_realize(DEVICE(&s->adc_irqs), NULL, &err); if (err != NULL) { error_propagate(errp, err); From 2255f6b7966d981054397765a700e8a34c6a15c4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:48 +0200 Subject: [PATCH 1781/2595] aspeed: Fix realize error API violation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. aspeed_soc_ast2600_realize() and aspeed_soc_realize() are wrong that way: they pass &err to object_property_set_int() and object_property_set_bool() without checking it, and then to sysbus_realize(). Harmless, because the former can't actually fail here. Fix by passing &error_abort instead. Cc: "Cédric Le Goater" Cc: Peter Maydell Cc: Andrew Jeffery Cc: Joel Stanley Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-24-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/arm/aspeed_ast2600.c | 5 +++-- hw/arm/aspeed_soc.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 4efac02e2b..59a7a1370b 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -383,7 +383,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->spis_num; i++) { object_property_set_link(OBJECT(&s->spi[i]), OBJECT(s->dram_mr), "dram", &error_abort); - object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err); + object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); if (err) { error_propagate(errp, err); @@ -434,7 +435,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* Net */ for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", - &err); + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err); if (err) { error_propagate(errp, err); diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 03b91bade6..311458aa76 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -333,7 +333,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* SPI */ for (i = 0; i < sc->spis_num; i++) { - object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err); + object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); if (err) { error_propagate(errp, err); @@ -384,7 +385,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* Net */ for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", - &err); + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err); if (err) { error_propagate(errp, err); From 17d5d49a4e877b08ebf82aa33b349176281e68a3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:49 +0200 Subject: [PATCH 1782/2595] hw/arm/armsse: Fix armsse_realize() error API violation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. armsse_realize() is wrong that way: it passes &err to object_property_set_int() multiple times without checking it, and then to sysbus_realize(). Harmless, because the former can't actually fail here. Fix by passing &error_abort instead. Cc: Peter Maydell Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-25-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/arm/armsse.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index a851652b39..2fbd970b4f 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -990,13 +990,13 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000); /* System control registers */ object_property_set_int(OBJECT(&s->sysctl), info->sys_version, - "SYS_VERSION", &err); + "SYS_VERSION", &error_abort); object_property_set_int(OBJECT(&s->sysctl), info->cpuwait_rst, - "CPUWAIT_RST", &err); + "CPUWAIT_RST", &error_abort); object_property_set_int(OBJECT(&s->sysctl), s->init_svtor, - "INITSVTOR0_RST", &err); + "INITSVTOR0_RST", &error_abort); object_property_set_int(OBJECT(&s->sysctl), s->init_svtor, - "INITSVTOR1_RST", &err); + "INITSVTOR1_RST", &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->sysctl), &err); if (err) { error_propagate(errp, err); From 7cd1c981eb497de3efd6707d7ccf3fb756c2350f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:50 +0200 Subject: [PATCH 1783/2595] arm/{bcm2835,fsl-imx25,fsl-imx6}: Fix realize error API violations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. bcm2835_peripherals_realize(), fsl_imx25_realize() and fsl_imx6_realize() are wrong that way: they pass &err to object_property_set_uint() and object_property_set_bool() without checking it, and then to sysbus_realize(). Harmless, because the former can't actually fail here. Fix by passing &error_abort instead. Cc: Peter Maydell Cc: Andrew Baumann Cc: "Philippe Mathieu-Daudé" Cc: Jean-Christophe Dubois Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-26-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/arm/bcm2835_peripherals.c | 12 ++++-------- hw/arm/fsl-imx25.c | 12 +++++------- hw/arm/fsl-imx6.c | 12 +++++------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 1e975d7eec..7ffdf62067 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -283,16 +283,12 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) * For the exact details please refer to the Arasan documentation: * SD3.0_Host_AHB_eMMC4.4_Usersguide_ver5.9_jan11_10.pdf */ - object_property_set_uint(OBJECT(&s->sdhci), 3, "sd-spec-version", &err); + object_property_set_uint(OBJECT(&s->sdhci), 3, "sd-spec-version", + &error_abort); object_property_set_uint(OBJECT(&s->sdhci), BCM2835_SDHC_CAPAREG, "capareg", - &err); + &error_abort); object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk", - &err); - if (err) { - error_propagate(errp, err); - return; - } - + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err); if (err) { error_propagate(errp, err); diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index f32f9bce0f..7ab5c98fbe 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -260,15 +260,13 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) }; object_property_set_uint(OBJECT(&s->esdhc[i]), 2, "sd-spec-version", - &err); + &error_abort); object_property_set_uint(OBJECT(&s->esdhc[i]), IMX25_ESDHC_CAPABILITIES, - "capareg", &err); + "capareg", + &error_abort); object_property_set_uint(OBJECT(&s->esdhc[i]), SDHCI_VENDOR_IMX, - "vendor", &err); - if (err) { - error_propagate(errp, err); - return; - } + "vendor", + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err); if (err) { error_propagate(errp, err); diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index d4bc4fae93..4ae3c3efc2 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -336,15 +336,13 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) /* UHS-I SDIO3.0 SDR104 1.8V ADMA */ object_property_set_uint(OBJECT(&s->esdhc[i]), 3, "sd-spec-version", - &err); + &error_abort); object_property_set_uint(OBJECT(&s->esdhc[i]), IMX6_ESDHC_CAPABILITIES, - "capareg", &err); + "capareg", + &error_abort); object_property_set_uint(OBJECT(&s->esdhc[i]), SDHCI_VENDOR_IMX, - "vendor", &err); - if (err) { - error_propagate(errp, err); - return; - } + "vendor", + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err); if (err) { error_propagate(errp, err); From 9cde9caa04beac25cef32a8a9d0bd26d6b91a41a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 30 Jun 2020 11:03:51 +0200 Subject: [PATCH 1784/2595] migration/rdma: Plug memory leaks in qemu_rdma_registration_stop() qemu_rdma_registration_stop() uses the ERROR() macro to create, report to stderr, and store an Error object. The stored Error object is never used, and its memory is leaked. Even where ERROR() doesn't leak, it is ill-advised. The whole point of passing an Error to the caller is letting the caller handle the error. Error handling may report to stderr, to somewhere else, or not at all. Also reporting in the callee mixes up concerns that should be kept separate. Since I don't know what reporting to stderr is supposed to accomplish, I'm not touching it. Commit 2a1bc8bde7 "migration/rdma: rdma_accept_incoming_migration fix error handling" plugged the same leak in rdma_accept_incoming_migration(). Plug the memory leak the same way: keep the report part, delete the store part. The report part uses fprintf(). If it's truly an error, it should use error_report() instead. But I don't know, so I leave it alone, just like commit 2a1bc8bde7 did. Fixes: 2da776db4846eadcb808598a5d3484d149773c05 Cc: Dr. David Alan Gilbert Cc: Juan Quintela Signed-off-by: Markus Armbruster Message-Id: <20200630090351.1247703-27-armbru@redhat.com> Reviewed-by: Dr. David Alan Gilbert --- migration/rdma.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index ec45d33ba3..3b18823268 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3787,7 +3787,6 @@ static int qemu_rdma_registration_start(QEMUFile *f, void *opaque, static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque, uint64_t flags, void *data) { - Error *local_err = NULL, **errp = &local_err; QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque); RDMAContext *rdma; RDMAControlHeader head = { .len = 0, .repeat = 1 }; @@ -3832,7 +3831,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque, ®_result_idx, rdma->pin_all ? qemu_rdma_reg_whole_ram_blocks : NULL); if (ret < 0) { - ERROR(errp, "receiving remote info!"); + fprintf(stderr, "receiving remote info!"); return ret; } @@ -3851,10 +3850,10 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque, */ if (local->nb_blocks != nb_dest_blocks) { - ERROR(errp, "ram blocks mismatch (Number of blocks %d vs %d) " - "Your QEMU command line parameters are probably " - "not identical on both the source and destination.", - local->nb_blocks, nb_dest_blocks); + fprintf(stderr, "ram blocks mismatch (Number of blocks %d vs %d) " + "Your QEMU command line parameters are probably " + "not identical on both the source and destination.", + local->nb_blocks, nb_dest_blocks); rdma->error_state = -EINVAL; return -EINVAL; } @@ -3867,10 +3866,10 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque, /* We require that the blocks are in the same order */ if (rdma->dest_blocks[i].length != local->block[i].length) { - ERROR(errp, "Block %s/%d has a different length %" PRIu64 - "vs %" PRIu64, local->block[i].block_name, i, - local->block[i].length, - rdma->dest_blocks[i].length); + fprintf(stderr, "Block %s/%d has a different length %" PRIu64 + "vs %" PRIu64, local->block[i].block_name, i, + local->block[i].length, + rdma->dest_blocks[i].length); rdma->error_state = -EINVAL; return -EINVAL; } From 0d935ffd66154a2aa3af3e49bcffd832a8bb53e5 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 9 Jun 2020 12:26:55 -0400 Subject: [PATCH 1785/2595] Revert "tests/migration: Reduce autoconverge initial bandwidth" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6d1da867e65f ("tests/migration: Reduce autoconverge initial bandwidth") since that change makes unit tests much slower for all developers, while it's not a robust way to fix migration tests. Migration tests need to find a more robust way to discover a reasonable bandwidth without slowing things down for everyone. Fixes: 6d1da867e65f ("tests/migration: Reduce autoconverge initial bandwidth") Signed-off-by: Michael S. Tsirkin Acked-by: Dr. David Alan Gilbert Acked-by: Philippe Mathieu-Daudé Acked-by: Thomas Huth --- tests/qtest/migration-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index dc3490c9fa..21ea5ba1d2 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -1211,7 +1211,7 @@ static void test_migrate_auto_converge(void) * without throttling. */ migrate_set_parameter_int(from, "downtime-limit", 1); - migrate_set_parameter_int(from, "max-bandwidth", 1000000); /* ~1Mb/s */ + migrate_set_parameter_int(from, "max-bandwidth", 100000000); /* ~100Mb/s */ /* To check remaining size after precopy */ migrate_set_capability(from, "pause-before-switchover", true); From dd8eeb9671fc881e613008bd20035b85fe45383d Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 29 Jun 2020 10:06:15 +0200 Subject: [PATCH 1786/2595] virtio-balloon: always indicate S_DONE when migration fails If something goes wrong during precopy, before stopping the VM, we will never send a S_DONE indication to the VM, resulting in the hinted pages not getting released to be used by the guest OS (e.g., Linux). Easy to reproduce: 1. Start migration (e.g., HMP "migrate -d 'exec:gzip -c > STATEFILE.gz'") 2. Cancel migration (e.g., HMP "migrate_cancel") 3. Oberve in the guest (e.g., cat /proc/meminfo) that there is basically no free memory left. While at it, add similar locking to virtio_balloon_free_page_done() as done in virtio_balloon_free_page_stop. Locking is still weird, but that has to be sorted out separately. There is nothing to do in the PRECOPY_NOTIFY_COMPLETE case. Add some comments regarding S_DONE handling. Fixes: c13c4153f76d ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT") Reviewed-by: Alexander Duyck Cc: Wei Wang Cc: Alexander Duyck Signed-off-by: David Hildenbrand Message-Id: <20200629080615.26022-1-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 10507b2a43..8a84718490 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -628,8 +628,13 @@ static void virtio_balloon_free_page_done(VirtIOBalloon *s) { VirtIODevice *vdev = VIRTIO_DEVICE(s); - s->free_page_report_status = FREE_PAGE_REPORT_S_DONE; - virtio_notify_config(vdev); + if (s->free_page_report_status != FREE_PAGE_REPORT_S_DONE) { + /* See virtio_balloon_free_page_stop() */ + qemu_mutex_lock(&s->free_page_lock); + s->free_page_report_status = FREE_PAGE_REPORT_S_DONE; + qemu_mutex_unlock(&s->free_page_lock); + virtio_notify_config(vdev); + } } static int @@ -653,17 +658,26 @@ virtio_balloon_free_page_report_notify(NotifierWithReturn *n, void *data) case PRECOPY_NOTIFY_SETUP: precopy_enable_free_page_optimization(); break; - case PRECOPY_NOTIFY_COMPLETE: - case PRECOPY_NOTIFY_CLEANUP: case PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC: virtio_balloon_free_page_stop(dev); break; case PRECOPY_NOTIFY_AFTER_BITMAP_SYNC: if (vdev->vm_running) { virtio_balloon_free_page_start(dev); - } else { - virtio_balloon_free_page_done(dev); + break; } + /* + * Set S_DONE before migrating the vmstate, so the guest will reuse + * all hinted pages once running on the destination. Fall through. + */ + case PRECOPY_NOTIFY_CLEANUP: + /* + * Especially, if something goes wrong during precopy or if migration + * is canceled, we have to properly communicate S_DONE to the VM. + */ + virtio_balloon_free_page_done(dev); + break; + case PRECOPY_NOTIFY_COMPLETE: break; default: virtio_error(vdev, "%s: %d reason unknown", __func__, pnd->reason); From af1d039f6dd46276e5f4ffafd535f486936012db Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:28 +0200 Subject: [PATCH 1787/2595] pc: Support coldplugging of virtio-pmem-pci devices on all buses E.g., with "pc-q35-4.2", trying to coldplug a virtio-pmem-pci devices results in "virtio-pmem-pci not supported on this bus" Reasons is, that the bus does not support hotplug and, therefore, does not have a hotplug handler. Let's allow coldplugging virtio-pmem devices on such buses. The hotplug order is only relevant for virtio-pmem-pci when the guest is already alive and the device is visible before memory_device_plug() wired up the memory device bits. Hotplug attempts will still fail with: "Error: Bus 'pcie.0' does not support hotplugging" Hotunplug attempts will still fail with: "Error: Bus 'pcie.0' does not support hotplugging" Reported-by: Vivek Goyal Reviewed-by: Pankaj Gupta Cc: Pankaj Gupta Cc: Igor Mammedov Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Cc: "Michael S. Tsirkin" Cc: Marcel Apfelbaum Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-2-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 4af9679d03..58b1425c17 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1643,13 +1643,13 @@ static void pc_virtio_pmem_pci_pre_plug(HotplugHandler *hotplug_dev, HotplugHandler *hotplug_dev2 = qdev_get_bus_hotplug_handler(dev); Error *local_err = NULL; - if (!hotplug_dev2) { + if (!hotplug_dev2 && dev->hotplugged) { /* * Without a bus hotplug handler, we cannot control the plug/unplug - * order. This should never be the case on x86, however better add - * a safety net. + * order. We should never reach this point when hotplugging on x86, + * however, better add a safety net. */ - error_setg(errp, "virtio-pmem-pci not supported on this bus."); + error_setg(errp, "virtio-pmem-pci hotplug not supported on this bus."); return; } /* @@ -1658,7 +1658,7 @@ static void pc_virtio_pmem_pci_pre_plug(HotplugHandler *hotplug_dev, */ memory_device_pre_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev), NULL, &local_err); - if (!local_err) { + if (!local_err && hotplug_dev2) { hotplug_handler_pre_plug(hotplug_dev2, dev, &local_err); } error_propagate(errp, local_err); @@ -1676,9 +1676,11 @@ static void pc_virtio_pmem_pci_plug(HotplugHandler *hotplug_dev, * device bits. */ memory_device_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev)); - hotplug_handler_plug(hotplug_dev2, dev, &local_err); - if (local_err) { - memory_device_unplug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev)); + if (hotplug_dev2) { + hotplug_handler_plug(hotplug_dev2, dev, &local_err); + if (local_err) { + memory_device_unplug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev)); + } } error_propagate(errp, local_err); } From d24f31db3bcb46b09d8717850112d6a1bbee78f2 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:29 +0200 Subject: [PATCH 1788/2595] exec: Introduce ram_block_discard_(disable|require)() We want to replace qemu_balloon_inhibit() by something more generic. Especially, we want to make sure that technologies that really rely on RAM block discards to work reliably to run mutual exclusive with technologies that effectively break it. E.g., vfio will usually pin all guest memory, turning the virtio-balloon basically useless and make the VM consume more memory than reported via the balloon. While the balloon is special already (=> no guarantees, same behavior possible afer reboots and with huge pages), this will be different, especially, with virtio-mem. Let's implement a way such that we can make both types of technology run mutually exclusive. We'll convert existing balloon inhibitors in successive patches and add some new ones. Add the check to qemu_balloon_is_inhibited() for now. We might want to make virtio-balloon an acutal inhibitor in the future - however, that requires more thought to not break existing setups. Reviewed-by: Dr. David Alan Gilbert Cc: "Michael S. Tsirkin" Cc: Richard Henderson Cc: Paolo Bonzini Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-3-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- balloon.c | 3 ++- exec.c | 52 +++++++++++++++++++++++++++++++++++++++++++ include/exec/memory.h | 41 ++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/balloon.c b/balloon.c index f104b42961..5fff79523a 100644 --- a/balloon.c +++ b/balloon.c @@ -40,7 +40,8 @@ static int balloon_inhibit_count; bool qemu_balloon_is_inhibited(void) { - return atomic_read(&balloon_inhibit_count) > 0; + return atomic_read(&balloon_inhibit_count) > 0 || + ram_block_discard_is_disabled(); } void qemu_balloon_inhibit(bool state) diff --git a/exec.c b/exec.c index 21926dc9c7..893636176e 100644 --- a/exec.c +++ b/exec.c @@ -4115,4 +4115,56 @@ void mtree_print_dispatch(AddressSpaceDispatch *d, MemoryRegion *root) } } +/* + * If positive, discarding RAM is disabled. If negative, discarding RAM is + * required to work and cannot be disabled. + */ +static int ram_block_discard_disabled; + +int ram_block_discard_disable(bool state) +{ + int old; + + if (!state) { + atomic_dec(&ram_block_discard_disabled); + return 0; + } + + do { + old = atomic_read(&ram_block_discard_disabled); + if (old < 0) { + return -EBUSY; + } + } while (atomic_cmpxchg(&ram_block_discard_disabled, old, old + 1) != old); + return 0; +} + +int ram_block_discard_require(bool state) +{ + int old; + + if (!state) { + atomic_inc(&ram_block_discard_disabled); + return 0; + } + + do { + old = atomic_read(&ram_block_discard_disabled); + if (old > 0) { + return -EBUSY; + } + } while (atomic_cmpxchg(&ram_block_discard_disabled, old, old - 1) != old); + return 0; +} + +bool ram_block_discard_is_disabled(void) +{ + return atomic_read(&ram_block_discard_disabled) > 0; +} + +bool ram_block_discard_is_required(void) +{ + return atomic_read(&ram_block_discard_disabled) < 0; +} + #endif diff --git a/include/exec/memory.h b/include/exec/memory.h index 7207025bd4..38ec38b9a8 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -2472,6 +2472,47 @@ static inline MemOp devend_memop(enum device_endian end) } #endif +/* + * Inhibit technologies that require discarding of pages in RAM blocks, e.g., + * to manage the actual amount of memory consumed by the VM (then, the memory + * provided by RAM blocks might be bigger than the desired memory consumption). + * This *must* be set if: + * - Discarding parts of a RAM blocks does not result in the change being + * reflected in the VM and the pages getting freed. + * - All memory in RAM blocks is pinned or duplicated, invaldiating any previous + * discards blindly. + * - Discarding parts of a RAM blocks will result in integrity issues (e.g., + * encrypted VMs). + * Technologies that only temporarily pin the current working set of a + * driver are fine, because we don't expect such pages to be discarded + * (esp. based on guest action like balloon inflation). + * + * This is *not* to be used to protect from concurrent discards (esp., + * postcopy). + * + * Returns 0 if successful. Returns -EBUSY if a technology that relies on + * discards to work reliably is active. + */ +int ram_block_discard_disable(bool state); + +/* + * Inhibit technologies that disable discarding of pages in RAM blocks. + * + * Returns 0 if successful. Returns -EBUSY if discards are already set to + * broken. + */ +int ram_block_discard_require(bool state); + +/* + * Test if discarding of memory in ram blocks is disabled. + */ +bool ram_block_discard_is_disabled(void); + +/* + * Test if discarding of memory in ram blocks is required to work reliably. + */ +bool ram_block_discard_is_required(void); + #endif #endif From aff92b828647839b956dfa647a18b3ce10058e6a Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:30 +0200 Subject: [PATCH 1789/2595] vfio: Convert to ram_block_discard_disable() VFIO is (except devices without a physical IOMMU or some mediated devices) incompatible with discarding of RAM. The kernel will pin basically all VM memory. Let's convert to ram_block_discard_disable(), which can now fail, in contrast to qemu_balloon_inhibit(). Leave "x-balloon-allowed" named as it is for now. Reviewed-by: Tony Krowiak Acked-by: Cornelia Huck Cc: Cornelia Huck Cc: Alex Williamson Cc: Christian Borntraeger Cc: Tony Krowiak Cc: Halil Pasic Cc: Pierre Morel Cc: Eric Farman Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-4-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/vfio/ap.c | 8 +++--- hw/vfio/ccw.c | 11 ++++---- hw/vfio/common.c | 53 +++++++++++++++++++---------------- hw/vfio/pci.c | 6 ++-- include/hw/vfio/vfio-common.h | 4 +-- 5 files changed, 44 insertions(+), 38 deletions(-) diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index 95564c17ed..b9330a8e6f 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -105,12 +105,12 @@ static void vfio_ap_realize(DeviceState *dev, Error **errp) vapdev->vdev.dev = dev; /* - * vfio-ap devices operate in a way compatible with - * memory ballooning, as no pages are pinned in the host. + * vfio-ap devices operate in a way compatible with discarding of + * memory in RAM blocks, as no pages are pinned in the host. * This needs to be set before vfio_get_device() for vfio common to - * handle the balloon inhibitor. + * handle ram_block_discard_disable(). */ - vapdev->vdev.balloon_allowed = true; + vapdev->vdev.ram_block_discard_allowed = true; ret = vfio_get_device(vfio_group, mdevid, &vapdev->vdev, errp); if (ret) { diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index 06e69d7066..ff7f369779 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -574,12 +574,13 @@ static void vfio_ccw_get_device(VFIOGroup *group, VFIOCCWDevice *vcdev, /* * All vfio-ccw devices are believed to operate in a way compatible with - * memory ballooning, ie. pages pinned in the host are in the current - * working set of the guest driver and therefore never overlap with pages - * available to the guest balloon driver. This needs to be set before - * vfio_get_device() for vfio common to handle the balloon inhibitor. + * discarding of memory in RAM blocks, ie. pages pinned in the host are + * in the current working set of the guest driver and therefore never + * overlap e.g., with pages available to the guest balloon driver. This + * needs to be set before vfio_get_device() for vfio common to handle + * ram_block_discard_disable(). */ - vcdev->vdev.balloon_allowed = true; + vcdev->vdev.ram_block_discard_allowed = true; if (vfio_get_device(group, vcdev->cdev.mdevid, &vcdev->vdev, errp)) { goto out_err; diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 0b3593b3c0..33357140b8 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -33,7 +33,6 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/range.h" -#include "sysemu/balloon.h" #include "sysemu/kvm.h" #include "sysemu/reset.h" #include "trace.h" @@ -1215,31 +1214,36 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, space = vfio_get_address_space(as); /* - * VFIO is currently incompatible with memory ballooning insofar as the + * VFIO is currently incompatible with discarding of RAM insofar as the * madvise to purge (zap) the page from QEMU's address space does not * interact with the memory API and therefore leaves stale virtual to * physical mappings in the IOMMU if the page was previously pinned. We - * therefore add a balloon inhibit for each group added to a container, + * therefore set discarding broken for each group added to a container, * whether the container is used individually or shared. This provides * us with options to allow devices within a group to opt-in and allow - * ballooning, so long as it is done consistently for a group (for instance + * discarding, so long as it is done consistently for a group (for instance * if the device is an mdev device where it is known that the host vendor * driver will never pin pages outside of the working set of the guest - * driver, which would thus not be ballooning candidates). + * driver, which would thus not be discarding candidates). * * The first opportunity to induce pinning occurs here where we attempt to * attach the group to existing containers within the AddressSpace. If any - * pages are already zapped from the virtual address space, such as from a - * previous ballooning opt-in, new pinning will cause valid mappings to be + * pages are already zapped from the virtual address space, such as from + * previous discards, new pinning will cause valid mappings to be * re-established. Likewise, when the overall MemoryListener for a new * container is registered, a replay of mappings within the AddressSpace * will occur, re-establishing any previously zapped pages as well. * - * NB. Balloon inhibiting does not currently block operation of the - * balloon driver or revoke previously pinned pages, it only prevents - * calling madvise to modify the virtual mapping of ballooned pages. + * Especially virtio-balloon is currently only prevented from discarding + * new memory, it will not yet set ram_block_discard_set_required() and + * therefore, neither stops us here or deals with the sudden memory + * consumption of inflated memory. */ - qemu_balloon_inhibit(true); + ret = ram_block_discard_disable(true); + if (ret) { + error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken"); + return ret; + } QLIST_FOREACH(container, &space->containers, next) { if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) { @@ -1405,7 +1409,7 @@ close_fd_exit: close(fd); put_space_exit: - qemu_balloon_inhibit(false); + ram_block_discard_disable(false); vfio_put_address_space(space); return ret; @@ -1526,8 +1530,8 @@ void vfio_put_group(VFIOGroup *group) return; } - if (!group->balloon_allowed) { - qemu_balloon_inhibit(false); + if (!group->ram_block_discard_allowed) { + ram_block_discard_disable(false); } vfio_kvm_device_del_group(group); vfio_disconnect_container(group); @@ -1565,22 +1569,23 @@ int vfio_get_device(VFIOGroup *group, const char *name, } /* - * Clear the balloon inhibitor for this group if the driver knows the - * device operates compatibly with ballooning. Setting must be consistent - * per group, but since compatibility is really only possible with mdev - * currently, we expect singleton groups. + * Set discarding of RAM as not broken for this group if the driver knows + * the device operates compatibly with discarding. Setting must be + * consistent per group, but since compatibility is really only possible + * with mdev currently, we expect singleton groups. */ - if (vbasedev->balloon_allowed != group->balloon_allowed) { + if (vbasedev->ram_block_discard_allowed != + group->ram_block_discard_allowed) { if (!QLIST_EMPTY(&group->device_list)) { - error_setg(errp, - "Inconsistent device balloon setting within group"); + error_setg(errp, "Inconsistent setting of support for discarding " + "RAM (e.g., balloon) within group"); close(fd); return -1; } - if (!group->balloon_allowed) { - group->balloon_allowed = true; - qemu_balloon_inhibit(false); + if (!group->ram_block_discard_allowed) { + group->ram_block_discard_allowed = true; + ram_block_discard_disable(false); } } diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 6838bcc4b3..d020ea9f82 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2789,7 +2789,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } /* - * Mediated devices *might* operate compatibly with memory ballooning, but + * Mediated devices *might* operate compatibly with discarding of RAM, but * we cannot know for certain, it depends on whether the mdev vendor driver * stays in sync with the active working set of the guest driver. Prevent * the x-balloon-allowed option unless this is minimally an mdev device. @@ -2802,7 +2802,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) trace_vfio_mdev(vdev->vbasedev.name, is_mdev); - if (vdev->vbasedev.balloon_allowed && !is_mdev) { + if (vdev->vbasedev.ram_block_discard_allowed && !is_mdev) { error_setg(errp, "x-balloon-allowed only potentially compatible " "with mdev devices"); vfio_put_group(group); @@ -3156,7 +3156,7 @@ static Property vfio_pci_dev_properties[] = { VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT, false), DEFINE_PROP_BOOL("x-no-mmap", VFIOPCIDevice, vbasedev.no_mmap, false), DEFINE_PROP_BOOL("x-balloon-allowed", VFIOPCIDevice, - vbasedev.balloon_allowed, false), + vbasedev.ram_block_discard_allowed, false), DEFINE_PROP_BOOL("x-no-kvm-intx", VFIOPCIDevice, no_kvm_intx, false), DEFINE_PROP_BOOL("x-no-kvm-msi", VFIOPCIDevice, no_kvm_msi, false), DEFINE_PROP_BOOL("x-no-kvm-msix", VFIOPCIDevice, no_kvm_msix, false), diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index fd564209ac..c78f3ff559 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -108,7 +108,7 @@ typedef struct VFIODevice { bool reset_works; bool needs_reset; bool no_mmap; - bool balloon_allowed; + bool ram_block_discard_allowed; VFIODeviceOps *ops; unsigned int num_irqs; unsigned int num_regions; @@ -128,7 +128,7 @@ typedef struct VFIOGroup { QLIST_HEAD(, VFIODevice) device_list; QLIST_ENTRY(VFIOGroup) next; QLIST_ENTRY(VFIOGroup) container_next; - bool balloon_allowed; + bool ram_block_discard_allowed; } VFIOGroup; typedef struct VFIODMABuf { From 956b109fe305228fb2bca32e71356823257318c9 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:31 +0200 Subject: [PATCH 1790/2595] accel/kvm: Convert to ram_block_discard_disable() Discarding memory does not work as expected. At the time this is called, we cannot have anyone active that relies on discards to work properly. Reviewed-by: Dr. David Alan Gilbert Cc: Paolo Bonzini Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-5-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- accel/kvm/kvm-all.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index d54a8701d8..ab36fbfa0c 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -40,7 +40,6 @@ #include "trace.h" #include "hw/irq.h" #include "sysemu/sev.h" -#include "sysemu/balloon.h" #include "qapi/visitor.h" #include "qapi/qapi-types-common.h" #include "qapi/qapi-visit-common.h" @@ -2229,7 +2228,8 @@ static int kvm_init(MachineState *ms) s->sync_mmu = !!kvm_vm_check_extension(kvm_state, KVM_CAP_SYNC_MMU); if (!s->sync_mmu) { - qemu_balloon_inhibit(true); + ret = ram_block_discard_disable(true); + assert(!ret); } return 0; From b030958c2b5c133e70d083ff8a612cb62254eabc Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:32 +0200 Subject: [PATCH 1791/2595] s390x/pv: Convert to ram_block_discard_disable() Discarding RAM does not work as expected with protected VMs. Let's switch to ram_block_discard_disable() for now, as we want to get rid of qemu_balloon_inhibit(). Note that it will currently never fail, but might fail in the future with new technologies (e.g., virtio-mem). Acked-by: Cornelia Huck Cc: Richard Henderson Cc: Cornelia Huck Cc: Halil Pasic Cc: Christian Borntraeger Cc: Janosch Frank Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-6-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/s390x/s390-virtio-ccw.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index b111406d56..023fd25f2b 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -43,7 +43,6 @@ #include "hw/qdev-properties.h" #include "hw/s390x/tod.h" #include "sysemu/sysemu.h" -#include "sysemu/balloon.h" #include "hw/s390x/pv.h" #include "migration/blocker.h" @@ -329,7 +328,7 @@ static void s390_machine_unprotect(S390CcwMachineState *ms) ms->pv = false; migrate_del_blocker(pv_mig_blocker); error_free_or_abort(&pv_mig_blocker); - qemu_balloon_inhibit(false); + ram_block_discard_disable(false); } static int s390_machine_protect(S390CcwMachineState *ms) @@ -338,17 +337,22 @@ static int s390_machine_protect(S390CcwMachineState *ms) int rc; /* - * Ballooning on protected VMs needs support in the guest for - * sharing and unsharing balloon pages. Block ballooning for - * now, until we have a solution to make at least Linux guests - * either support it or fail gracefully. + * Discarding of memory in RAM blocks does not work as expected with + * protected VMs. Sharing and unsharing pages would be required. Disable + * it for now, until until we have a solution to make at least Linux + * guests either support it (e.g., virtio-balloon) or fail gracefully. */ - qemu_balloon_inhibit(true); + rc = ram_block_discard_disable(true); + if (rc) { + error_report("protected VMs: cannot disable RAM discard"); + return rc; + } + error_setg(&pv_mig_blocker, "protected VMs are currently not migrateable."); rc = migrate_add_blocker(pv_mig_blocker, &local_err); if (rc) { - qemu_balloon_inhibit(false); + ram_block_discard_disable(false); error_report_err(local_err); error_free_or_abort(&pv_mig_blocker); return rc; @@ -357,7 +361,7 @@ static int s390_machine_protect(S390CcwMachineState *ms) /* Create SE VM */ rc = s390_pv_vm_enable(); if (rc) { - qemu_balloon_inhibit(false); + ram_block_discard_disable(false); migrate_del_blocker(pv_mig_blocker); error_free_or_abort(&pv_mig_blocker); return rc; From 06df2e692a95509ee5f6e7d1663502adb74cb2a5 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:33 +0200 Subject: [PATCH 1792/2595] virtio-balloon: Rip out qemu_balloon_inhibit() The only remaining special case is postcopy. It cannot handle concurrent discards yet, which would result in requesting already sent pages from the source. Special-case it in virtio-balloon instead. Introduce migration_in_incoming_postcopy(), to find out if incoming postcopy is active. Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Michael S. Tsirkin Cc: "Michael S. Tsirkin" Cc: Juan Quintela Cc: "Dr. David Alan Gilbert" Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-7-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- balloon.c | 18 ------------------ hw/virtio/virtio-balloon.c | 10 ++++++++-- include/migration/misc.h | 2 ++ include/sysemu/balloon.h | 2 -- migration/migration.c | 7 +++++++ migration/postcopy-ram.c | 23 ----------------------- 6 files changed, 17 insertions(+), 45 deletions(-) diff --git a/balloon.c b/balloon.c index 5fff79523a..354408c6ea 100644 --- a/balloon.c +++ b/balloon.c @@ -36,24 +36,6 @@ static QEMUBalloonEvent *balloon_event_fn; static QEMUBalloonStatus *balloon_stat_fn; static void *balloon_opaque; -static int balloon_inhibit_count; - -bool qemu_balloon_is_inhibited(void) -{ - return atomic_read(&balloon_inhibit_count) > 0 || - ram_block_discard_is_disabled(); -} - -void qemu_balloon_inhibit(bool state) -{ - if (state) { - atomic_inc(&balloon_inhibit_count); - } else { - atomic_dec(&balloon_inhibit_count); - } - - assert(atomic_read(&balloon_inhibit_count) >= 0); -} static bool have_balloon(Error **errp) { diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 8a84718490..ae31f0817a 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -63,6 +63,12 @@ static bool virtio_balloon_pbp_matches(PartiallyBalloonedPage *pbp, return pbp->base_gpa == base_gpa; } +static bool virtio_balloon_inhibited(void) +{ + /* Postcopy cannot deal with concurrent discards, so it's special. */ + return ram_block_discard_is_disabled() || migration_in_incoming_postcopy(); +} + static void balloon_inflate_page(VirtIOBalloon *balloon, MemoryRegion *mr, hwaddr mr_offset, PartiallyBalloonedPage *pbp) @@ -336,7 +342,7 @@ static void virtio_balloon_handle_report(VirtIODevice *vdev, VirtQueue *vq) * accessible by another device or process, or if the guest is * expecting it to retain a non-zero value. */ - if (qemu_balloon_is_inhibited() || dev->poison_val) { + if (virtio_balloon_inhibited() || dev->poison_val) { goto skip_element; } @@ -421,7 +427,7 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) trace_virtio_balloon_handle_output(memory_region_name(section.mr), pa); - if (!qemu_balloon_is_inhibited()) { + if (!virtio_balloon_inhibited()) { if (vq == s->ivq) { balloon_inflate_page(s, section.mr, section.offset_within_region, &pbp); diff --git a/include/migration/misc.h b/include/migration/misc.h index d2762257aa..34e7d75713 100644 --- a/include/migration/misc.h +++ b/include/migration/misc.h @@ -69,6 +69,8 @@ bool migration_has_failed(MigrationState *); /* ...and after the device transmission */ bool migration_in_postcopy_after_devices(MigrationState *); void migration_global_dump(Monitor *mon); +/* True if incomming migration entered POSTCOPY_INCOMING_DISCARD */ +bool migration_in_incoming_postcopy(void); /* migration/block-dirty-bitmap.c */ void dirty_bitmap_mig_init(void); diff --git a/include/sysemu/balloon.h b/include/sysemu/balloon.h index aea0c44985..20a2defe3a 100644 --- a/include/sysemu/balloon.h +++ b/include/sysemu/balloon.h @@ -23,7 +23,5 @@ typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info); int qemu_add_balloon_handler(QEMUBalloonEvent *event_func, QEMUBalloonStatus *stat_func, void *opaque); void qemu_remove_balloon_handler(void *opaque); -bool qemu_balloon_is_inhibited(void); -void qemu_balloon_inhibit(bool state); #endif diff --git a/migration/migration.c b/migration/migration.c index 481a590f72..d365d82209 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1772,6 +1772,13 @@ bool migration_in_postcopy_after_devices(MigrationState *s) return migration_in_postcopy() && s->postcopy_after_devices; } +bool migration_in_incoming_postcopy(void) +{ + PostcopyState ps = postcopy_state_get(); + + return ps >= POSTCOPY_INCOMING_DISCARD && ps < POSTCOPY_INCOMING_END; +} + bool migration_is_idle(void) { MigrationState *s = current_migration; diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index a36402722b..b41a9fe2fd 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -27,7 +27,6 @@ #include "qemu/notify.h" #include "qemu/rcu.h" #include "sysemu/sysemu.h" -#include "sysemu/balloon.h" #include "qemu/error-report.h" #include "trace.h" #include "hw/boards.h" @@ -520,20 +519,6 @@ int postcopy_ram_incoming_init(MigrationIncomingState *mis) return 0; } -/* - * Manage a single vote to the QEMU balloon inhibitor for all postcopy usage, - * last caller wins. - */ -static void postcopy_balloon_inhibit(bool state) -{ - static bool cur_state = false; - - if (state != cur_state) { - qemu_balloon_inhibit(state); - cur_state = state; - } -} - /* * At the end of a migration where postcopy_ram_incoming_init was called. */ @@ -565,8 +550,6 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis) mis->have_fault_thread = false; } - postcopy_balloon_inhibit(false); - if (enable_mlock) { if (os_mlock() < 0) { error_report("mlock: %s", strerror(errno)); @@ -1160,12 +1143,6 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis) } memset(mis->postcopy_tmp_zero_page, '\0', mis->largest_page_size); - /* - * Ballooning can mark pages as absent while we're postcopying - * that would cause false userfaults. - */ - postcopy_balloon_inhibit(true); - trace_postcopy_ram_enable_notify(); return 0; From fee3f3baff12e78f544db51cc16ef028b8fe03a9 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:34 +0200 Subject: [PATCH 1793/2595] target/i386: sev: Use ram_block_discard_disable() AMD SEV will pin all guest memory, mark discarding of RAM broken. At the time this is called, we cannot have anyone active that relies on discards to work properly - let's still implement error handling. Reviewed-by: Dr. David Alan Gilbert Cc: "Michael S. Tsirkin" Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-8-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- target/i386/sev.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/target/i386/sev.c b/target/i386/sev.c index d273174ad3..f100a53231 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -680,6 +680,12 @@ sev_guest_init(const char *id) uint32_t host_cbitpos; struct sev_user_data_status status = {}; + ret = ram_block_discard_disable(true); + if (ret) { + error_report("%s: cannot disable RAM discard", __func__); + return NULL; + } + sev = lookup_sev_guest_info(id); if (!sev) { error_report("%s: '%s' is not a valid '%s' object", @@ -751,6 +757,7 @@ sev_guest_init(const char *id) return sev; err: sev_guest = NULL; + ram_block_discard_disable(false); return NULL; } From 5f1f1902f8e4020f27b4e35631a38c4e68d9be54 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:35 +0200 Subject: [PATCH 1794/2595] migration/rdma: Use ram_block_discard_disable() RDMA will pin all guest memory (as documented in docs/rdma.txt). We want to disable RAM block discards - however, to keep it simple use ram_block_discard_is_required() instead of inhibiting. Note: It is not sufficient to limit disabling to pin_all. Even when only conditionally pinning 1 MB chunks, as soon as one page within such a chunk was discarded and one page not, the discarded pages will be pinned as well. Reviewed-by: Dr. David Alan Gilbert Cc: "Michael S. Tsirkin" Cc: Juan Quintela Cc: "Dr. David Alan Gilbert" Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-9-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- migration/rdma.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index ec45d33ba3..bbe6f36627 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -29,6 +29,7 @@ #include "qemu/sockets.h" #include "qemu/bitmap.h" #include "qemu/coroutine.h" +#include "exec/memory.h" #include #include #include @@ -4017,8 +4018,14 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) Error *local_err = NULL; trace_rdma_start_incoming_migration(); - rdma = qemu_rdma_data_init(host_port, &local_err); + /* Avoid ram_block_discard_disable(), cannot change during migration. */ + if (ram_block_discard_is_required()) { + error_setg(errp, "RDMA: cannot disable RAM discard"); + return; + } + + rdma = qemu_rdma_data_init(host_port, &local_err); if (rdma == NULL) { goto err; } @@ -4067,10 +4074,17 @@ void rdma_start_outgoing_migration(void *opaque, const char *host_port, Error **errp) { MigrationState *s = opaque; - RDMAContext *rdma = qemu_rdma_data_init(host_port, errp); RDMAContext *rdma_return_path = NULL; + RDMAContext *rdma; int ret = 0; + /* Avoid ram_block_discard_disable(), cannot change during migration. */ + if (ram_block_discard_is_required()) { + error_setg(errp, "RDMA: cannot disable RAM discard"); + return; + } + + rdma = qemu_rdma_data_init(host_port, errp); if (rdma == NULL) { goto err; } From 18b1d3c952d00ef1881852ee46cf41783dacf530 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:36 +0200 Subject: [PATCH 1795/2595] migration/colo: Use ram_block_discard_disable() COLO will copy all memory in a RAM block, disable discarding of RAM. Reviewed-by: Dr. David Alan Gilbert Tested-by: Lukas Straub Cc: "Michael S. Tsirkin" Cc: Hailiang Zhang Cc: Juan Quintela Cc: "Dr. David Alan Gilbert" Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-10-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/migration/colo.h | 2 +- migration/migration.c | 8 +++++++- migration/savevm.c | 11 +++++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/include/migration/colo.h b/include/migration/colo.h index 1636e6f907..768e1f04c3 100644 --- a/include/migration/colo.h +++ b/include/migration/colo.h @@ -25,7 +25,7 @@ void migrate_start_colo_process(MigrationState *s); bool migration_in_colo_state(void); /* loadvm */ -void migration_incoming_enable_colo(void); +int migration_incoming_enable_colo(void); void migration_incoming_disable_colo(void); bool migration_incoming_colo_enabled(void); void *colo_process_incoming_thread(void *opaque); diff --git a/migration/migration.c b/migration/migration.c index d365d82209..92e44e021e 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -338,12 +338,18 @@ bool migration_incoming_colo_enabled(void) void migration_incoming_disable_colo(void) { + ram_block_discard_disable(false); migration_colo_enabled = false; } -void migration_incoming_enable_colo(void) +int migration_incoming_enable_colo(void) { + if (ram_block_discard_disable(true)) { + error_report("COLO: cannot disable RAM discard"); + return -EBUSY; + } migration_colo_enabled = true; + return 0; } void migrate_add_address(SocketAddress *address) diff --git a/migration/savevm.c b/migration/savevm.c index b979ea6e7f..6e01724605 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -2111,8 +2111,15 @@ static int loadvm_handle_recv_bitmap(MigrationIncomingState *mis, static int loadvm_process_enable_colo(MigrationIncomingState *mis) { - migration_incoming_enable_colo(); - return colo_init_ram_cache(); + int ret = migration_incoming_enable_colo(); + + if (!ret) { + ret = colo_init_ram_cache(); + if (ret) { + migration_incoming_disable_colo(); + } + } + return ret; } /* From de15df5ead400b7c3d0cf21c8164a7686dc81933 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:28:54 +0200 Subject: [PATCH 1796/2595] seabios: update submodule to pre-1.14 master snapshot seabios 1.14 release is planned for end of july, early enough to make it into qemu 5.1-rc2 if everything goes as planned. Update seabios to a master snapshot now, so it'll get test coverage during the freeze and the update to the final version is much smaller (and should have bugfixes only). seabios git shortlog -------------------- Alexey Kirillov (2): boot: Detect strict boot order (HALT record) in function virtio: Do not init non-bootable devices Christian Ehrhardt (1): build: use -fcf-protection=none when available Gerd Hoffmann (25): boot: cache HALT priority virtio-scsi: skip initializing non-bootable devices nvme: skip initializing non-bootable devices timer: add tsctimer_setfreq() kvm: detect unconditionally kvm: add support for reading tsc frequency via cpuid. kvm: add support for reading tsc frequency from kvmclock sercon: vbe modeset is int 10h function 4f02 not 4f00 pci: factor out ioconfig_cmd() pci: add mmconfig support qemu: factor out qemu_cfg_detect() qemu: rework e820 detection qemu: check rtc presence before reading cpu count from cmos virtio-mmio: device probing and initialization. virtio-mmio: add support to vp_*() functions virtio-mmio: add support for scsi devices. virtio-mmio: add support for block devices. virtio-mmio: print device type acpi: add xsdt support acpi: add dsdt parser acpi: skip kbd init if not present acpi: find and register virtio-mmio devices rewrap Makefile lines. pci: fix mmconfig support vga: fix cirrus bios Jason Andryuk (1): serialio: Preserve Xen DebugOutputPort Kevin O'Connor (3): usb-hid: Improve max packet size checking Revert "ps2port: adjust init routine to fix PS/2 keyboard issues" boot: Fixup check for only one item in boot list Matt DeVillier (4): hw/usb-hid: Don't abort if setting key repeat rate fails Skip boot menu and timeout with only one boot device ps2port: adjust init routine to fix PS/2 keyboard issues boot: Fix logic for boot menu display Paul Menzel (4): std/tcg: Replace zero-length array with flexible-array member boot: Extend `etc/show-boot-menu` to configure skipping boot menu with only one device boot: Log, if boot menu is skipped cdrom: Demote `scsi_is_ready` return print to debug level Roman Bolshakov (1): timer: Handle decrements of PIT counter Stefan Berger (3): tcgbios: Only write logs for PCRs that are in active PCR banks tcgbios: Fix the vendorInfoSize to be of type u8 tcgbios: Add support for SHA3 type of algorithms Signed-off-by: Gerd Hoffmann --- roms/seabios | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roms/seabios b/roms/seabios index f21b5a4aeb..88ab0c1552 160000 --- a/roms/seabios +++ b/roms/seabios @@ -1 +1 @@ -Subproject commit f21b5a4aeb020f2a5e2c6503f906a9349dd2f069 +Subproject commit 88ab0c15525ced2eefe39220742efe4769089ad8 From 4879d1bbc6d27975a8aab572483d4b78d0013057 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:43:11 +0200 Subject: [PATCH 1797/2595] seabios: update 128k config Turn off some options to keep size below 128k. Signed-off-by: Gerd Hoffmann --- roms/config.seabios-128k | 3 +++ 1 file changed, 3 insertions(+) diff --git a/roms/config.seabios-128k b/roms/config.seabios-128k index c43912bf9d..d18c802c46 100644 --- a/roms/config.seabios-128k +++ b/roms/config.seabios-128k @@ -11,8 +11,11 @@ CONFIG_USB_UAS=n CONFIG_SDCARD=n CONFIG_TCGBIOS=n CONFIG_MPT_SCSI=n +CONFIG_ESP_SCSI=n +CONFIG_MEGASAS=n CONFIG_PVSCSI=n CONFIG_NVME=n CONFIG_USE_SMM=n CONFIG_VGAHOOKS=n CONFIG_HOST_BIOS_GEOMETRY=n +CONFIG_ACPI_PARSE=n From 563b9d0d8d944d358921a774f82a0e60527e7823 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:45:13 +0200 Subject: [PATCH 1798/2595] seabios: update binaries Signed-off-by: Gerd Hoffmann --- pc-bios/bios-256k.bin | Bin 262144 -> 262144 bytes pc-bios/bios.bin | Bin 131072 -> 131072 bytes pc-bios/vgabios-ati.bin | Bin 39424 -> 39424 bytes pc-bios/vgabios-bochs-display.bin | Bin 28672 -> 28672 bytes pc-bios/vgabios-cirrus.bin | Bin 38912 -> 38912 bytes pc-bios/vgabios-qxl.bin | Bin 39424 -> 39424 bytes pc-bios/vgabios-ramfb.bin | Bin 28672 -> 28672 bytes pc-bios/vgabios-stdvga.bin | Bin 39424 -> 39424 bytes pc-bios/vgabios-virtio.bin | Bin 39424 -> 39424 bytes pc-bios/vgabios-vmware.bin | Bin 39424 -> 39424 bytes pc-bios/vgabios.bin | Bin 38912 -> 38912 bytes 11 files changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin index 4af7f7d5a91bcc19905e1742b0706e034e2a655c..25b69cafba592be74bcb122570ac3cae5fd3dff3 100644 GIT binary patch delta 73483 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℘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 delta 46256 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 diff --git a/pc-bios/vgabios-ati.bin b/pc-bios/vgabios-ati.bin index 6202cf73e254ccac67b3289230a23f3f45f6b41f..d034f6d254722ea47a706ffa08bcc9a73fa0847f 100644 GIT binary patch delta 86 zcmZqJ!ql*Zi9K|c@5|qzb2qY^&9pbxOG+$G)l1DWkGIe>WGG6_(KXaFG}bfFH8Igm qx3EY|GDtQwH8nC#)-5PXO)AaIDbXuT%`Mf-FG^=%VwoJs*a83qWgEx< delta 86 zcmZqJ!ql*Zi9K|c@5|qzEgRX*X4)I-B_$T8>ZRtG$D8XJG8Coe=o;!78tWP88tA5{ q85t&-CYmIsCK(v%78Io>m1gFY=oO~smg?mfr86)vu}ltRYykiX92>|0 diff --git a/pc-bios/vgabios-bochs-display.bin b/pc-bios/vgabios-bochs-display.bin index b675f86bc622b77afd8b24a50948663aeae2c2ce..1ced8400f4dd3667063b2b0cb7aee7a00c188fc8 100644 GIT binary patch delta 86 zcmZp8z}WDBkv(*k#mnzDu^ZVh<=GqSB_$T8>ZRtG$6M$bG8Coe=o;!78tWP8nwaRO qTUaC}86+E;ni`oV>lPHHCY5I9l;{ZRtG$D8XJG8Coe=o;!78tWP88tA5{ q85t&-CYmIsCK(v%78Io>m1gFY=oO~smg?mfr86)vu}lthe*pj_H5|tP diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index 63fde14fea4a2d4873b6efc02b0437c1802625ea..b3af3771bd8feae2c2de6ca593bd56b21057d742 100644 GIT binary patch delta 5093 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 diff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin index 80168826e2e5cdba8fb6a7805adf061f3cf38685..3fac6dc13765b26029c9ae9bbb50c62e30e8257d 100644 GIT binary patch delta 87 zcmZqJ!ql*Zi9K|c@5^tYTQ;&c&9FDtOG+$G)l1DWkGIe>WGG6_(KXaFG}bfFH8Igm rx3EY|GDtQwH8nC#)-5PXO)AaIDbXuT%`Mf-FG^=%V%eM+Z@~xvJBS=; delta 87 zcmZqJ!ql*Zi9K|c@5^tYvp2Fg&9FDrOG+$G)l1DWk2lvdWGG6_(KXaFG}bfFHPB5@ rGcrsvO*BbNO)@ajEhtJ&D$UF((JM^NE!E2}N@rkTV%eM+Z@~xvKtCL4 diff --git a/pc-bios/vgabios-ramfb.bin b/pc-bios/vgabios-ramfb.bin index 1dc413dcd2ab1720a46d0e7ee7abca46469200b5..1ca4f68a6e5e38e4c61cc216bb70b1047e835054 100644 GIT binary patch delta 86 zcmZp8z}WDBkv(*k#mhsshLagx#5c+<&bK$#OG+$G)l1DWkGIe>WGG6_(KXaFG}bfF qH8Igmx3EY|GDtQwH8nC#)-5PXO)AaIDbXuT%`Mf-FG^=%VgUf^n;R?u delta 86 zcmZp8z}WDBkv(*k#mhss5|bHS#5c+<&bK$zOG+$G)l1DWk2lvdWGG6_(KXaFG}bfF qHPB5@GcrsvO*BbNO)@ajEhtJ&D$UF((JM^NE!E2}N@rkTVgUf|?i(xs diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin index f92b9a664dfbdbf953efddbba2250d7556c6b53a..a146eead00e87d25ebeab1300623c7155e806283 100644 GIT binary patch delta 87 zcmZqJ!ql*Zi9K|c@5^tY^ER?K&9FDtOG+$G)l1DWkGIe>WGG6_(KXaFG}bfFH8Igm rx3EY|GDtQwH8nC#)-5PXO)AaIDbXuT%`Mf-FG^=%V%eM+Z@~xvH7p!b delta 87 zcmZqJ!ql*Zi9K|c@5^tYtsB{!X4o6*B_$T8>ZRtG$D8XJG8Coe=o;!78tWP88tA5{ r85t&-CYmIsCK(v%78Io>m1gFY=oO~smg?mfr86)vv20F^w_pSSIpZ8s diff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin index b0d2f70670303c9d0daafea45e9bbf7473ec127e..49981a4334cdd3d1a101b24c469dd47da1940bfd 100644 GIT binary patch delta 87 zcmZqJ!ql*Zi9K|c@5^tYGd8j}&9FDtOG+$G)l1DWkGIe>WGG6_(KXaFG}bfFH8Igm rx3EY|GDtQwH8nC#)-5PXO)AaIDbXuT%`Mf-FG^=%V%eM+Z@~xvGjJSC delta 87 zcmZqJ!ql*Zi9K|c@5^tY^&8onX4o6*B_$T8>ZRtG$D8XJG8Coe=o;!78tWP88tA5{ r85t&-CYmIsCK(v%78Io>m1gFY=oO~smg?mfr86)vv20F^w_pSSI42xT diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin index 1c2776e8cf6b02f4e01a4c4f1616cdc190417a34..2f8935bf1f4a9977b69ab99a886b9a5f1e6eee03 100644 GIT binary patch delta 87 zcmZqJ!ql*Zi9K|c@5^tY)*IQIX4o6+B_$T8>ZRtG$6M$bG8Coe=o;!78tWP8nwaRO rTUaC}86+E;ni`oV>lPHHCY5I9l;{*n7 delta 87 zcmZqJ!ql*Zi9K|c@5^tYN*mdmX4o6*B_$T8>ZRtG$D8XJG8Coe=o;!78tWP88tA5{ r85t&-CYmIsCK(v%78Io>m1gFY=oO~smg?mfr86)vv20F^w_pSS9Yq`O diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index c5aad8f3a99f9be693b008fd921f50a601c41be8..d371983ab9f8dcaad1e0441bf547d0e32dda5cd7 100644 GIT binary patch delta 87 zcmZqJz|^pTi9K|c&&z`$6DKpqiEotqKF!8hFDbD&RWCKiJl;ajkfA6wN7qo#&{)qv r*Th6O-NGU<$spO#)YQl{S+}4lHK{Z+r$nzXHMdkRzbJij;PmwXI-wp8 delta 87 zcmZqJz|^pTi9K|c&&z`$6_Xj`#5c-)pJrpImy}qXs+XE$9&fH^$WWA;qid*VXsl Date: Thu, 18 Jun 2020 21:23:43 +0100 Subject: [PATCH 1799/2595] riscv: plic: Honour source priorities The source priorities can be used to order sources with respect to other sources, not just as a way to enable/disable them based off a threshold. We must therefore always claim the highest-priority source, rather than the first source we find. Signed-off-by: Jessica Clarke Reviewed-by: Alistair Francis Message-Id: <20200618202343.20455-1-jrtc27@jrtc27.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_plic.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c index 4f216c5585..d91e82b8ab 100644 --- a/hw/riscv/sifive_plic.c +++ b/hw/riscv/sifive_plic.c @@ -166,6 +166,9 @@ static void sifive_plic_update(SiFivePLICState *plic) static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid) { int i, j; + uint32_t max_irq = 0; + uint32_t max_prio = plic->target_priority[addrid]; + for (i = 0; i < plic->bitfield_words; i++) { uint32_t pending_enabled_not_claimed = (plic->pending[i] & ~plic->claimed[i]) & @@ -177,14 +180,18 @@ static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid) int irq = (i << 5) + j; uint32_t prio = plic->source_priority[irq]; int enabled = pending_enabled_not_claimed & (1 << j); - if (enabled && prio > plic->target_priority[addrid]) { - sifive_plic_set_pending(plic, irq, false); - sifive_plic_set_claimed(plic, irq, true); - return irq; + if (enabled && prio > max_prio) { + max_irq = irq; + max_prio = prio; } } } - return 0; + + if (max_irq) { + sifive_plic_set_pending(plic, max_irq, false); + sifive_plic_set_claimed(plic, max_irq, true); + } + return max_irq; } static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size) From 55765822804f5a58594e0931e0fb8f80337b5425 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Thu, 18 Jun 2020 22:06:49 +0100 Subject: [PATCH 1800/2595] riscv: plic: Add a couple of mising sifive_plic_update calls Claiming an interrupt and changing the source priority both potentially affect whether an interrupt is pending, thus we must re-compute xEIP. Note that we don't put the sifive_plic_update inside sifive_plic_claim so that the logging of a claim (and the resulting IRQ) happens before the state update, making the causal effect clear, and that we drop the explicit call to sifive_plic_print_state when claiming since sifive_plic_update already does that automatically at the end for us. This can result in both spurious interrupt storms if you fail to complete an IRQ before enabling interrupts (and no other actions occur that result in a call to sifive_plic_update), but also more importantly lost interrupts if a disabled interrupt is pending and then becomes enabled. Signed-off-by: Jessica Clarke Reviewed-by: Alistair Francis Message-Id: <20200618210649.22451-1-jrtc27@jrtc27.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_plic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c index d91e82b8ab..c20c192034 100644 --- a/hw/riscv/sifive_plic.c +++ b/hw/riscv/sifive_plic.c @@ -255,8 +255,8 @@ static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size) plic->addr_config[addrid].hartid, mode_to_char(plic->addr_config[addrid].mode), value); - sifive_plic_print_state(plic); } + sifive_plic_update(plic); return value; } } @@ -287,6 +287,7 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value, qemu_log("plic: write priority: irq=%d priority=%d\n", irq, plic->source_priority[irq]); } + sifive_plic_update(plic); return; } else if (addr >= plic->pending_base && /* 1 bit per source */ addr < plic->pending_base + (plic->num_sources >> 3)) From 70b78d4e71494c90d2ccb40381336bc9b9a22f79 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 30 Jun 2020 13:12:11 -0700 Subject: [PATCH 1801/2595] hw/riscv: Allow 64 bit access to SiFive CLINT Commit 5d971f9e672507210e77d020d89e0e89165c8fc9 "memory: Revert "memory: accept mismatching sizes in memory_region_access_valid"" broke most RISC-V boards as they do 64 bit accesses to the CLINT and QEMU would trigger a fault. Fix this failure by allowing 8 byte accesses. Signed-off-by: Alistair Francis Reviewed-by: LIU Zhiwei Message-Id: <122b78825b077e4dfd39b444d3a46fe894a7804c.1593547870.git.alistair.francis@wdc.com> --- hw/riscv/sifive_clint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c index b11ffa0edc..669c21adc2 100644 --- a/hw/riscv/sifive_clint.c +++ b/hw/riscv/sifive_clint.c @@ -181,7 +181,7 @@ static const MemoryRegionOps sifive_clint_ops = { .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 4, - .max_access_size = 4 + .max_access_size = 8 } }; From ad9e5aa2ae8032f19a8293b6b8f4661c06167bf0 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:24:49 +0800 Subject: [PATCH 1802/2595] target/riscv: add vector extension field in CPURISCVState The 32 vector registers will be viewed as a continuous memory block. It avoids the convension between element index and (regno, offset). Thus elements can be directly accessed by offset from the first vector base address. Signed-off-by: LIU Zhiwei Acked-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-2-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 12 ++++++++++++ target/riscv/translate.c | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 80569f0d44..0018a79fa3 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -59,6 +59,7 @@ #define RVA RV('A') #define RVF RV('F') #define RVD RV('D') +#define RVV RV('V') #define RVC RV('C') #define RVS RV('S') #define RVU RV('U') @@ -88,9 +89,20 @@ typedef struct CPURISCVState CPURISCVState; #include "pmp.h" +#define RV_VLEN_MAX 512 + struct CPURISCVState { target_ulong gpr[32]; uint64_t fpr[32]; /* assume both F and D extensions */ + + /* vector coprocessor state. */ + uint64_t vreg[32 * RV_VLEN_MAX / 64] QEMU_ALIGNED(16); + target_ulong vxrm; + target_ulong vxsat; + target_ulong vl; + target_ulong vstart; + target_ulong vtype; + target_ulong pc; target_ulong load_res; target_ulong load_val; diff --git a/target/riscv/translate.c b/target/riscv/translate.c index ce71ca7a92..b269f15920 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -32,7 +32,7 @@ #include "instmap.h" /* global register indices */ -static TCGv cpu_gpr[32], cpu_pc; +static TCGv cpu_gpr[32], cpu_pc, cpu_vl; static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */ static TCGv load_res; static TCGv load_val; @@ -887,6 +887,7 @@ void riscv_translate_init(void) } cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, pc), "pc"); + cpu_vl = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, vl), "vl"); load_res = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_res), "load_res"); load_val = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_val), From 32931383270e2ca8209267ca99f23f3c5f780982 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:24:50 +0800 Subject: [PATCH 1803/2595] target/riscv: implementation-defined constant parameters vlen is the vector register length in bits. elen is the max element size in bits. vext_spec is the vector specification version, default value is v0.7.1. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-3-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 7 +++++++ target/riscv/cpu.h | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 391a0b9eec..d525cfb687 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -106,6 +106,11 @@ static void set_priv_version(CPURISCVState *env, int priv_ver) env->priv_ver = priv_ver; } +static void set_vext_version(CPURISCVState *env, int vext_ver) +{ + env->vext_ver = vext_ver; +} + static void set_feature(CPURISCVState *env, int feature) { env->features |= (1ULL << feature); @@ -334,6 +339,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) CPURISCVState *env = &cpu->env; RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev); int priv_version = PRIV_VERSION_1_11_0; + int vext_version = VEXT_VERSION_0_07_1; target_ulong target_misa = 0; Error *local_err = NULL; @@ -357,6 +363,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } set_priv_version(env, priv_version); + set_vext_version(env, vext_version); if (cpu->cfg.mmu) { set_feature(env, RISCV_FEATURE_MMU); diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 0018a79fa3..302e0859a0 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -78,6 +78,8 @@ enum { #define PRIV_VERSION_1_10_0 0x00011000 #define PRIV_VERSION_1_11_0 0x00011100 +#define VEXT_VERSION_0_07_1 0x00000701 + #define TRANSLATE_PMP_FAIL 2 #define TRANSLATE_FAIL 1 #define TRANSLATE_SUCCESS 0 @@ -113,6 +115,7 @@ struct CPURISCVState { target_ulong guest_phys_fault_addr; target_ulong priv_ver; + target_ulong vext_ver; target_ulong misa; target_ulong misa_mask; @@ -275,6 +278,8 @@ typedef struct RISCVCPU { char *priv_spec; char *user_spec; + uint16_t vlen; + uint16_t elen; bool mmu; bool pmp; } cfg; From 8e3a1f18871e0ea251b95561fe1ec5a9bc896c4a Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:24:51 +0800 Subject: [PATCH 1804/2595] target/riscv: support vector extension csr The v0.7.1 specification does not define vector status within mstatus. A future revision will define the privileged portion of the vector status. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-4-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/cpu_bits.h | 15 +++++++++ target/riscv/csr.c | 75 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 7f64ee1174..8117e8b5a7 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -29,6 +29,14 @@ #define FSR_NXA (FPEXC_NX << FSR_AEXC_SHIFT) #define FSR_AEXC (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA) +/* Vector Fixed-Point round model */ +#define FSR_VXRM_SHIFT 9 +#define FSR_VXRM (0x3 << FSR_VXRM_SHIFT) + +/* Vector Fixed-Point saturation flag */ +#define FSR_VXSAT_SHIFT 8 +#define FSR_VXSAT (0x1 << FSR_VXSAT_SHIFT) + /* Control and Status Registers */ /* User Trap Setup */ @@ -48,6 +56,13 @@ #define CSR_FRM 0x002 #define CSR_FCSR 0x003 +/* User Vector CSRs */ +#define CSR_VSTART 0x008 +#define CSR_VXSAT 0x009 +#define CSR_VXRM 0x00a +#define CSR_VL 0xc20 +#define CSR_VTYPE 0xc21 + /* User Timers and Counters */ #define CSR_CYCLE 0xc00 #define CSR_TIME 0xc01 diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 383be0a955..ac01c835e1 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -46,6 +46,10 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops) static int fs(CPURISCVState *env, int csrno) { #if !defined(CONFIG_USER_ONLY) + /* loose check condition for fcsr in vector extension */ + if ((csrno == CSR_FCSR) && (env->misa & RVV)) { + return 0; + } if (!env->debugger && !riscv_cpu_fp_enabled(env)) { return -1; } @@ -53,6 +57,14 @@ static int fs(CPURISCVState *env, int csrno) return 0; } +static int vs(CPURISCVState *env, int csrno) +{ + if (env->misa & RVV) { + return 0; + } + return -1; +} + static int ctr(CPURISCVState *env, int csrno) { #if !defined(CONFIG_USER_ONLY) @@ -154,6 +166,10 @@ static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val) #endif *val = (riscv_cpu_get_fflags(env) << FSR_AEXC_SHIFT) | (env->frm << FSR_RD_SHIFT); + if (vs(env, csrno) >= 0) { + *val |= (env->vxrm << FSR_VXRM_SHIFT) + | (env->vxsat << FSR_VXSAT_SHIFT); + } return 0; } @@ -166,10 +182,62 @@ static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val) env->mstatus |= MSTATUS_FS; #endif env->frm = (val & FSR_RD) >> FSR_RD_SHIFT; + if (vs(env, csrno) >= 0) { + env->vxrm = (val & FSR_VXRM) >> FSR_VXRM_SHIFT; + env->vxsat = (val & FSR_VXSAT) >> FSR_VXSAT_SHIFT; + } riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT); return 0; } +static int read_vtype(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vtype; + return 0; +} + +static int read_vl(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vl; + return 0; +} + +static int read_vxrm(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vxrm; + return 0; +} + +static int write_vxrm(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vxrm = val; + return 0; +} + +static int read_vxsat(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vxsat; + return 0; +} + +static int write_vxsat(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vxsat = val; + return 0; +} + +static int read_vstart(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vstart; + return 0; +} + +static int write_vstart(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vstart = val; + return 0; +} + /* User Timers and Counters */ static int read_instret(CPURISCVState *env, int csrno, target_ulong *val) { @@ -1183,7 +1251,12 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_FFLAGS] = { fs, read_fflags, write_fflags }, [CSR_FRM] = { fs, read_frm, write_frm }, [CSR_FCSR] = { fs, read_fcsr, write_fcsr }, - + /* Vector CSRs */ + [CSR_VSTART] = { vs, read_vstart, write_vstart }, + [CSR_VXSAT] = { vs, read_vxsat, write_vxsat }, + [CSR_VXRM] = { vs, read_vxrm, write_vxrm }, + [CSR_VL] = { vs, read_vl }, + [CSR_VTYPE] = { vs, read_vtype }, /* User Timers and Counters */ [CSR_CYCLE] = { ctr, read_instret }, [CSR_INSTRET] = { ctr, read_instret }, From 2b7168fc43fb270fb89e1dddc17ef54714712f3a Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:24:52 +0800 Subject: [PATCH 1805/2595] target/riscv: add vector configure instruction vsetvl and vsetvli are two configure instructions for vl, vtype. TB flags should update after configure instructions. The (ill, lmul, sew ) of vtype and the bit of (VSTART == 0 && VL == VLMAX) will be placed within tb_flags. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-5-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/Makefile.objs | 2 +- target/riscv/cpu.h | 65 ++++++++++++++++---- target/riscv/helper.h | 3 + target/riscv/insn32.decode | 5 ++ target/riscv/insn_trans/trans_rvv.inc.c | 79 +++++++++++++++++++++++++ target/riscv/translate.c | 17 +++++- target/riscv/vector_helper.c | 53 +++++++++++++++++ 7 files changed, 211 insertions(+), 13 deletions(-) create mode 100644 target/riscv/insn_trans/trans_rvv.inc.c create mode 100644 target/riscv/vector_helper.c diff --git a/target/riscv/Makefile.objs b/target/riscv/Makefile.objs index ff651f69f6..ff38df6219 100644 --- a/target/riscv/Makefile.objs +++ b/target/riscv/Makefile.objs @@ -1,4 +1,4 @@ -obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o +obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o vector_helper.o gdbstub.o obj-$(CONFIG_SOFTMMU) += pmp.o ifeq ($(CONFIG_SOFTMMU),y) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 302e0859a0..0ad51c6580 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -21,6 +21,7 @@ #define RISCV_CPU_H #include "hw/core/cpu.h" +#include "hw/registerfields.h" #include "exec/cpu-defs.h" #include "fpu/softfloat-types.h" @@ -93,6 +94,12 @@ typedef struct CPURISCVState CPURISCVState; #define RV_VLEN_MAX 512 +FIELD(VTYPE, VLMUL, 0, 2) +FIELD(VTYPE, VSEW, 2, 3) +FIELD(VTYPE, VEDIV, 5, 2) +FIELD(VTYPE, RESERVED, 7, sizeof(target_ulong) * 8 - 9) +FIELD(VTYPE, VILL, sizeof(target_ulong) * 8 - 2, 1) + struct CPURISCVState { target_ulong gpr[32]; uint64_t fpr[32]; /* assume both F and D extensions */ @@ -352,19 +359,62 @@ void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong); #define TB_FLAGS_MMU_MASK 3 #define TB_FLAGS_MSTATUS_FS MSTATUS_FS -static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +typedef CPURISCVState CPUArchState; +typedef RISCVCPU ArchCPU; +#include "exec/cpu-all.h" + +FIELD(TB_FLAGS, VL_EQ_VLMAX, 2, 1) +FIELD(TB_FLAGS, LMUL, 3, 2) +FIELD(TB_FLAGS, SEW, 5, 3) +FIELD(TB_FLAGS, VILL, 8, 1) + +/* + * A simplification for VLMAX + * = (1 << LMUL) * VLEN / (8 * (1 << SEW)) + * = (VLEN << LMUL) / (8 << SEW) + * = (VLEN << LMUL) >> (SEW + 3) + * = VLEN >> (SEW + 3 - LMUL) + */ +static inline uint32_t vext_get_vlmax(RISCVCPU *cpu, target_ulong vtype) { + uint8_t sew, lmul; + + sew = FIELD_EX64(vtype, VTYPE, VSEW); + lmul = FIELD_EX64(vtype, VTYPE, VLMUL); + return cpu->cfg.vlen >> (sew + 3 - lmul); +} + +static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *pflags) +{ + uint32_t flags = 0; + *pc = env->pc; *cs_base = 0; + + if (riscv_has_ext(env, RVV)) { + uint32_t vlmax = vext_get_vlmax(env_archcpu(env), env->vtype); + bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl); + flags = FIELD_DP32(flags, TB_FLAGS, VILL, + FIELD_EX64(env->vtype, VTYPE, VILL)); + flags = FIELD_DP32(flags, TB_FLAGS, SEW, + FIELD_EX64(env->vtype, VTYPE, VSEW)); + flags = FIELD_DP32(flags, TB_FLAGS, LMUL, + FIELD_EX64(env->vtype, VTYPE, VLMUL)); + flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax); + } else { + flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1); + } + #ifdef CONFIG_USER_ONLY - *flags = TB_FLAGS_MSTATUS_FS; + flags |= TB_FLAGS_MSTATUS_FS; #else - *flags = cpu_mmu_index(env, 0); + flags |= cpu_mmu_index(env, 0); if (riscv_cpu_fp_enabled(env)) { - *flags |= env->mstatus & MSTATUS_FS; + flags |= env->mstatus & MSTATUS_FS; } #endif + *pflags = flags; } int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, @@ -405,9 +455,4 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops); void riscv_cpu_register_gdb_regs_for_features(CPUState *cs); -typedef CPURISCVState CPUArchState; -typedef RISCVCPU ArchCPU; - -#include "exec/cpu-all.h" - #endif /* RISCV_CPU_H */ diff --git a/target/riscv/helper.h b/target/riscv/helper.h index b36be978d5..8e81ff440b 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -81,3 +81,6 @@ DEF_HELPER_1(tlb_flush, void, env) #ifndef CONFIG_USER_ONLY DEF_HELPER_1(hyp_tlb_flush, void, env) #endif + +/* Vector functions */ +DEF_HELPER_3(vsetvl, tl, env, tl, tl) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 4c8d1215ce..1916cf331d 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -62,6 +62,7 @@ @r_rm ....... ..... ..... ... ..... ....... %rs2 %rs1 %rm %rd @r2_rm ....... ..... ..... ... ..... ....... %rs1 %rm %rd @r2 ....... ..... ..... ... ..... ....... %rs1 %rd +@r2_zimm . zimm:11 ..... ... ..... ....... %rs1 %rd @hfence_gvma ....... ..... ..... ... ..... ....... %rs2 %rs1 @hfence_vvma ....... ..... ..... ... ..... ....... %rs2 %rs1 @@ -209,3 +210,7 @@ fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm # *** RV32H Base Instruction Set *** hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma hfence_vvma 0010001 ..... ..... 000 00000 1110011 @hfence_vvma + +# *** RV32V Extension *** +vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm +vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c new file mode 100644 index 0000000000..c82fdf013e --- /dev/null +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -0,0 +1,79 @@ +/* + * RISC-V translation routines for the RVV Standard Extension. + * + * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +static bool trans_vsetvl(DisasContext *ctx, arg_vsetvl *a) +{ + TCGv s1, s2, dst; + + if (!has_ext(ctx, RVV)) { + return false; + } + + s2 = tcg_temp_new(); + dst = tcg_temp_new(); + + /* Using x0 as the rs1 register specifier, encodes an infinite AVL */ + if (a->rs1 == 0) { + /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */ + s1 = tcg_const_tl(RV_VLEN_MAX); + } else { + s1 = tcg_temp_new(); + gen_get_gpr(s1, a->rs1); + } + gen_get_gpr(s2, a->rs2); + gen_helper_vsetvl(dst, cpu_env, s1, s2); + gen_set_gpr(a->rd, dst); + tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); + lookup_and_goto_ptr(ctx); + ctx->base.is_jmp = DISAS_NORETURN; + + tcg_temp_free(s1); + tcg_temp_free(s2); + tcg_temp_free(dst); + return true; +} + +static bool trans_vsetvli(DisasContext *ctx, arg_vsetvli *a) +{ + TCGv s1, s2, dst; + + if (!has_ext(ctx, RVV)) { + return false; + } + + s2 = tcg_const_tl(a->zimm); + dst = tcg_temp_new(); + + /* Using x0 as the rs1 register specifier, encodes an infinite AVL */ + if (a->rs1 == 0) { + /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */ + s1 = tcg_const_tl(RV_VLEN_MAX); + } else { + s1 = tcg_temp_new(); + gen_get_gpr(s1, a->rs1); + } + gen_helper_vsetvl(dst, cpu_env, s1, s2); + gen_set_gpr(a->rd, dst); + gen_goto_tb(ctx, 0, ctx->pc_succ_insn); + ctx->base.is_jmp = DISAS_NORETURN; + + tcg_temp_free(s1); + tcg_temp_free(s2); + tcg_temp_free(dst); + return true; +} diff --git a/target/riscv/translate.c b/target/riscv/translate.c index b269f15920..cacb9b9cd3 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -56,6 +56,12 @@ typedef struct DisasContext { to reset this known value. */ int frm; bool ext_ifencei; + /* vector extension */ + bool vill; + uint8_t lmul; + uint8_t sew; + uint16_t vlen; + bool vl_eq_vlmax; } DisasContext; #ifdef TARGET_RISCV64 @@ -712,6 +718,7 @@ static bool gen_shift(DisasContext *ctx, arg_r *a, #include "insn_trans/trans_rvf.inc.c" #include "insn_trans/trans_rvd.inc.c" #include "insn_trans/trans_rvh.inc.c" +#include "insn_trans/trans_rvv.inc.c" #include "insn_trans/trans_privileged.inc.c" /* Include the auto-generated decoder for 16 bit insn */ @@ -746,10 +753,11 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) DisasContext *ctx = container_of(dcbase, DisasContext, base); CPURISCVState *env = cs->env_ptr; RISCVCPU *cpu = RISCV_CPU(cs); + uint32_t tb_flags = ctx->base.tb->flags; ctx->pc_succ_insn = ctx->base.pc_first; - ctx->mem_idx = ctx->base.tb->flags & TB_FLAGS_MMU_MASK; - ctx->mstatus_fs = ctx->base.tb->flags & TB_FLAGS_MSTATUS_FS; + ctx->mem_idx = tb_flags & TB_FLAGS_MMU_MASK; + ctx->mstatus_fs = tb_flags & TB_FLAGS_MSTATUS_FS; ctx->priv_ver = env->priv_ver; #if !defined(CONFIG_USER_ONLY) if (riscv_has_ext(env, RVH)) { @@ -773,6 +781,11 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->misa = env->misa; ctx->frm = -1; /* unknown rounding mode */ ctx->ext_ifencei = cpu->cfg.ext_ifencei; + ctx->vlen = cpu->cfg.vlen; + ctx->vill = FIELD_EX32(tb_flags, TB_FLAGS, VILL); + ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW); + ctx->lmul = FIELD_EX32(tb_flags, TB_FLAGS, LMUL); + ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX); } static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c new file mode 100644 index 0000000000..40ed0d55e7 --- /dev/null +++ b/target/riscv/vector_helper.c @@ -0,0 +1,53 @@ +/* + * RISC-V Vector Extension Helpers for QEMU. + * + * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" +#include + +target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, + target_ulong s2) +{ + int vlmax, vl; + RISCVCPU *cpu = env_archcpu(env); + uint16_t sew = 8 << FIELD_EX64(s2, VTYPE, VSEW); + uint8_t ediv = FIELD_EX64(s2, VTYPE, VEDIV); + bool vill = FIELD_EX64(s2, VTYPE, VILL); + target_ulong reserved = FIELD_EX64(s2, VTYPE, RESERVED); + + if ((sew > cpu->cfg.elen) || vill || (ediv != 0) || (reserved != 0)) { + /* only set vill bit. */ + env->vtype = FIELD_DP64(0, VTYPE, VILL, 1); + env->vl = 0; + env->vstart = 0; + return 0; + } + + vlmax = vext_get_vlmax(cpu, s2); + if (s1 <= vlmax) { + vl = s1; + } else { + vl = vlmax; + } + env->vl = vl; + env->vtype = s2; + env->vstart = 0; + return vl; +} From f476f17740ad42288d42dd8fedcdae8ca7007a16 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:24:53 +0800 Subject: [PATCH 1806/2595] target/riscv: add an internals.h header The internals.h keeps things that are not relevant to the actual architecture, only to the implementation, separate. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-6-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/internals.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 target/riscv/internals.h diff --git a/target/riscv/internals.h b/target/riscv/internals.h new file mode 100644 index 0000000000..22a49af413 --- /dev/null +++ b/target/riscv/internals.h @@ -0,0 +1,24 @@ +/* + * QEMU RISC-V CPU -- internal functions and types + * + * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#ifndef RISCV_CPU_INTERNALS_H +#define RISCV_CPU_INTERNALS_H + +#include "hw/registerfields.h" + +#endif From 751538d5da557e5c10e5045c2d27639580ea54a7 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:24:54 +0800 Subject: [PATCH 1807/2595] target/riscv: add vector stride load and store instructions Vector strided operations access the first memory element at the base address, and then access subsequent elements at address increments given by the byte offset contained in the x register specified by rs2. Vector unit-stride operations access elements stored contiguously in memory starting from the base effective address. It can been seen as a special case of strided operations. Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-7-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 105 ++++++ target/riscv/insn32.decode | 32 ++ target/riscv/insn_trans/trans_rvv.inc.c | 355 ++++++++++++++++++++ target/riscv/internals.h | 5 + target/riscv/translate.c | 7 + target/riscv/vector_helper.c | 410 ++++++++++++++++++++++++ 6 files changed, 914 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 8e81ff440b..f03b3d52f5 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -84,3 +84,108 @@ DEF_HELPER_1(hyp_tlb_flush, void, env) /* Vector functions */ DEF_HELPER_3(vsetvl, tl, env, tl, tl) +DEF_HELPER_5(vlb_v_b, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlb_v_b_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlb_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlb_v_h_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlb_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlb_v_w_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlb_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlb_v_d_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlh_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlh_v_h_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlh_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlh_v_w_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlh_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlh_v_d_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlw_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlw_v_w_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlw_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlw_v_d_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vle_v_b, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vle_v_b_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vle_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vle_v_h_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vle_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vle_v_w_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vle_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vle_v_d_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbu_v_b, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbu_v_b_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbu_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbu_v_h_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbu_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbu_v_w_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbu_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbu_v_d_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhu_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhu_v_h_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhu_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhu_v_w_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhu_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhu_v_d_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlwu_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlwu_v_w_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlwu_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlwu_v_d_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsb_v_b, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsb_v_b_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsb_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsb_v_h_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsb_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsb_v_w_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsb_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsb_v_d_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsh_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsh_v_h_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsh_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsh_v_w_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsh_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsh_v_d_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsw_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsw_v_w_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsw_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vsw_v_d_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vse_v_b, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vse_v_b_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vse_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vse_v_h_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vse_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vse_v_w_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vse_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vse_v_d_mask, void, ptr, ptr, tl, env, i32) +DEF_HELPER_6(vlsb_v_b, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsb_v_h, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsb_v_w, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsb_v_d, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsh_v_h, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsh_v_w, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsh_v_d, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsw_v_w, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsw_v_d, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlse_v_b, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlse_v_h, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlse_v_w, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlse_v_d, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsbu_v_b, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsbu_v_h, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsbu_v_w, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlsbu_v_d, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlshu_v_h, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlshu_v_w, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlshu_v_d, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlswu_v_w, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlswu_v_d, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vssb_v_b, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vssb_v_h, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vssb_v_w, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vssb_v_d, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vssh_v_h, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vssh_v_w, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vssh_v_d, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vssw_v_w, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vssw_v_d, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vsse_v_b, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vsse_v_h, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vsse_v_w, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vsse_v_d, void, ptr, ptr, tl, tl, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 1916cf331d..58b95792e6 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -25,6 +25,7 @@ %sh10 20:10 %csr 20:12 %rm 12:3 +%nf 29:3 !function=ex_plus_1 # immediates: %imm_i 20:s12 @@ -43,6 +44,8 @@ &u imm rd &shift shamt rs1 rd &atomic aq rl rs2 rs1 rd +&r2nfvm vm rd rs1 nf +&rnfvm vm rd rs1 rs2 nf # Formats 32: @r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd @@ -62,6 +65,8 @@ @r_rm ....... ..... ..... ... ..... ....... %rs2 %rs1 %rm %rd @r2_rm ....... ..... ..... ... ..... ....... %rs1 %rm %rd @r2 ....... ..... ..... ... ..... ....... %rs1 %rd +@r2_nfvm ... ... vm:1 ..... ..... ... ..... ....... &r2nfvm %nf %rs1 %rd +@r_nfvm ... ... vm:1 ..... ..... ... ..... ....... &rnfvm %nf %rs2 %rs1 %rd @r2_zimm . zimm:11 ..... ... ..... ....... %rs1 %rd @hfence_gvma ....... ..... ..... ... ..... ....... %rs2 %rs1 @@ -212,5 +217,32 @@ hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma hfence_vvma 0010001 ..... ..... 000 00000 1110011 @hfence_vvma # *** RV32V Extension *** + +# *** Vector loads and stores are encoded within LOADFP/STORE-FP *** +vlb_v ... 100 . 00000 ..... 000 ..... 0000111 @r2_nfvm +vlh_v ... 100 . 00000 ..... 101 ..... 0000111 @r2_nfvm +vlw_v ... 100 . 00000 ..... 110 ..... 0000111 @r2_nfvm +vle_v ... 000 . 00000 ..... 111 ..... 0000111 @r2_nfvm +vlbu_v ... 000 . 00000 ..... 000 ..... 0000111 @r2_nfvm +vlhu_v ... 000 . 00000 ..... 101 ..... 0000111 @r2_nfvm +vlwu_v ... 000 . 00000 ..... 110 ..... 0000111 @r2_nfvm +vsb_v ... 000 . 00000 ..... 000 ..... 0100111 @r2_nfvm +vsh_v ... 000 . 00000 ..... 101 ..... 0100111 @r2_nfvm +vsw_v ... 000 . 00000 ..... 110 ..... 0100111 @r2_nfvm +vse_v ... 000 . 00000 ..... 111 ..... 0100111 @r2_nfvm + +vlsb_v ... 110 . ..... ..... 000 ..... 0000111 @r_nfvm +vlsh_v ... 110 . ..... ..... 101 ..... 0000111 @r_nfvm +vlsw_v ... 110 . ..... ..... 110 ..... 0000111 @r_nfvm +vlse_v ... 010 . ..... ..... 111 ..... 0000111 @r_nfvm +vlsbu_v ... 010 . ..... ..... 000 ..... 0000111 @r_nfvm +vlshu_v ... 010 . ..... ..... 101 ..... 0000111 @r_nfvm +vlswu_v ... 010 . ..... ..... 110 ..... 0000111 @r_nfvm +vssb_v ... 010 . ..... ..... 000 ..... 0100111 @r_nfvm +vssh_v ... 010 . ..... ..... 101 ..... 0100111 @r_nfvm +vssw_v ... 010 . ..... ..... 110 ..... 0100111 @r_nfvm +vsse_v ... 010 . ..... ..... 111 ..... 0100111 @r_nfvm + +# *** new major opcode OP-V *** vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index c82fdf013e..451ab05f69 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -15,6 +15,9 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg-gvec-desc.h" +#include "internals.h" static bool trans_vsetvl(DisasContext *ctx, arg_vsetvl *a) { @@ -77,3 +80,355 @@ static bool trans_vsetvli(DisasContext *ctx, arg_vsetvli *a) tcg_temp_free(dst); return true; } + +/* vector register offset from env */ +static uint32_t vreg_ofs(DisasContext *s, int reg) +{ + return offsetof(CPURISCVState, vreg) + reg * s->vlen / 8; +} + +/* check functions */ + +/* + * In cpu_get_tb_cpu_state(), set VILL if RVV was not present. + * So RVV is also be checked in this function. + */ +static bool vext_check_isa_ill(DisasContext *s) +{ + return !s->vill; +} + +/* + * There are two rules check here. + * + * 1. Vector register numbers are multiples of LMUL. (Section 3.2) + * + * 2. For all widening instructions, the destination LMUL value must also be + * a supported LMUL value. (Section 11.2) + */ +static bool vext_check_reg(DisasContext *s, uint32_t reg, bool widen) +{ + /* + * The destination vector register group results are arranged as if both + * SEW and LMUL were at twice their current settings. (Section 11.2). + */ + int legal = widen ? 2 << s->lmul : 1 << s->lmul; + + return !((s->lmul == 0x3 && widen) || (reg % legal)); +} + +/* + * There are two rules check here. + * + * 1. The destination vector register group for a masked vector instruction can + * only overlap the source mask register (v0) when LMUL=1. (Section 5.3) + * + * 2. In widen instructions and some other insturctions, like vslideup.vx, + * there is no need to check whether LMUL=1. + */ +static bool vext_check_overlap_mask(DisasContext *s, uint32_t vd, bool vm, + bool force) +{ + return (vm != 0 || vd != 0) || (!force && (s->lmul == 0)); +} + +/* The LMUL setting must be such that LMUL * NFIELDS <= 8. (Section 7.8) */ +static bool vext_check_nf(DisasContext *s, uint32_t nf) +{ + return (1 << s->lmul) * nf <= 8; +} + +/* common translation macro */ +#define GEN_VEXT_TRANS(NAME, SEQ, ARGTYPE, OP, CHECK) \ +static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE *a)\ +{ \ + if (CHECK(s, a)) { \ + return OP(s, a, SEQ); \ + } \ + return false; \ +} + +/* + *** unit stride load and store + */ +typedef void gen_helper_ldst_us(TCGv_ptr, TCGv_ptr, TCGv, + TCGv_env, TCGv_i32); + +static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, + gen_helper_ldst_us *fn, DisasContext *s) +{ + TCGv_ptr dest, mask; + TCGv base; + TCGv_i32 desc; + + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + dest = tcg_temp_new_ptr(); + mask = tcg_temp_new_ptr(); + base = tcg_temp_new(); + + /* + * As simd_desc supports at most 256 bytes, and in this implementation, + * the max vector group length is 2048 bytes. So split it into two parts. + * + * The first part is vlen in bytes, encoded in maxsz of simd_desc. + * The second part is lmul, encoded in data of simd_desc. + */ + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + + gen_get_gpr(base, rs1); + tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + + fn(dest, mask, base, cpu_env, desc); + + tcg_temp_free_ptr(dest); + tcg_temp_free_ptr(mask); + tcg_temp_free(base); + tcg_temp_free_i32(desc); + gen_set_label(over); + return true; +} + +static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq) +{ + uint32_t data = 0; + gen_helper_ldst_us *fn; + static gen_helper_ldst_us * const fns[2][7][4] = { + /* masked unit stride load */ + { { gen_helper_vlb_v_b_mask, gen_helper_vlb_v_h_mask, + gen_helper_vlb_v_w_mask, gen_helper_vlb_v_d_mask }, + { NULL, gen_helper_vlh_v_h_mask, + gen_helper_vlh_v_w_mask, gen_helper_vlh_v_d_mask }, + { NULL, NULL, + gen_helper_vlw_v_w_mask, gen_helper_vlw_v_d_mask }, + { gen_helper_vle_v_b_mask, gen_helper_vle_v_h_mask, + gen_helper_vle_v_w_mask, gen_helper_vle_v_d_mask }, + { gen_helper_vlbu_v_b_mask, gen_helper_vlbu_v_h_mask, + gen_helper_vlbu_v_w_mask, gen_helper_vlbu_v_d_mask }, + { NULL, gen_helper_vlhu_v_h_mask, + gen_helper_vlhu_v_w_mask, gen_helper_vlhu_v_d_mask }, + { NULL, NULL, + gen_helper_vlwu_v_w_mask, gen_helper_vlwu_v_d_mask } }, + /* unmasked unit stride load */ + { { gen_helper_vlb_v_b, gen_helper_vlb_v_h, + gen_helper_vlb_v_w, gen_helper_vlb_v_d }, + { NULL, gen_helper_vlh_v_h, + gen_helper_vlh_v_w, gen_helper_vlh_v_d }, + { NULL, NULL, + gen_helper_vlw_v_w, gen_helper_vlw_v_d }, + { gen_helper_vle_v_b, gen_helper_vle_v_h, + gen_helper_vle_v_w, gen_helper_vle_v_d }, + { gen_helper_vlbu_v_b, gen_helper_vlbu_v_h, + gen_helper_vlbu_v_w, gen_helper_vlbu_v_d }, + { NULL, gen_helper_vlhu_v_h, + gen_helper_vlhu_v_w, gen_helper_vlhu_v_d }, + { NULL, NULL, + gen_helper_vlwu_v_w, gen_helper_vlwu_v_d } } + }; + + fn = fns[a->vm][seq][s->sew]; + if (fn == NULL) { + return false; + } + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, NF, a->nf); + return ldst_us_trans(a->rd, a->rs1, data, fn, s); +} + +static bool ld_us_check(DisasContext *s, arg_r2nfvm* a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, false) && + vext_check_reg(s, a->rd, false) && + vext_check_nf(s, a->nf)); +} + +GEN_VEXT_TRANS(vlb_v, 0, r2nfvm, ld_us_op, ld_us_check) +GEN_VEXT_TRANS(vlh_v, 1, r2nfvm, ld_us_op, ld_us_check) +GEN_VEXT_TRANS(vlw_v, 2, r2nfvm, ld_us_op, ld_us_check) +GEN_VEXT_TRANS(vle_v, 3, r2nfvm, ld_us_op, ld_us_check) +GEN_VEXT_TRANS(vlbu_v, 4, r2nfvm, ld_us_op, ld_us_check) +GEN_VEXT_TRANS(vlhu_v, 5, r2nfvm, ld_us_op, ld_us_check) +GEN_VEXT_TRANS(vlwu_v, 6, r2nfvm, ld_us_op, ld_us_check) + +static bool st_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq) +{ + uint32_t data = 0; + gen_helper_ldst_us *fn; + static gen_helper_ldst_us * const fns[2][4][4] = { + /* masked unit stride load and store */ + { { gen_helper_vsb_v_b_mask, gen_helper_vsb_v_h_mask, + gen_helper_vsb_v_w_mask, gen_helper_vsb_v_d_mask }, + { NULL, gen_helper_vsh_v_h_mask, + gen_helper_vsh_v_w_mask, gen_helper_vsh_v_d_mask }, + { NULL, NULL, + gen_helper_vsw_v_w_mask, gen_helper_vsw_v_d_mask }, + { gen_helper_vse_v_b_mask, gen_helper_vse_v_h_mask, + gen_helper_vse_v_w_mask, gen_helper_vse_v_d_mask } }, + /* unmasked unit stride store */ + { { gen_helper_vsb_v_b, gen_helper_vsb_v_h, + gen_helper_vsb_v_w, gen_helper_vsb_v_d }, + { NULL, gen_helper_vsh_v_h, + gen_helper_vsh_v_w, gen_helper_vsh_v_d }, + { NULL, NULL, + gen_helper_vsw_v_w, gen_helper_vsw_v_d }, + { gen_helper_vse_v_b, gen_helper_vse_v_h, + gen_helper_vse_v_w, gen_helper_vse_v_d } } + }; + + fn = fns[a->vm][seq][s->sew]; + if (fn == NULL) { + return false; + } + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, NF, a->nf); + return ldst_us_trans(a->rd, a->rs1, data, fn, s); +} + +static bool st_us_check(DisasContext *s, arg_r2nfvm* a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false) && + vext_check_nf(s, a->nf)); +} + +GEN_VEXT_TRANS(vsb_v, 0, r2nfvm, st_us_op, st_us_check) +GEN_VEXT_TRANS(vsh_v, 1, r2nfvm, st_us_op, st_us_check) +GEN_VEXT_TRANS(vsw_v, 2, r2nfvm, st_us_op, st_us_check) +GEN_VEXT_TRANS(vse_v, 3, r2nfvm, st_us_op, st_us_check) + +/* + *** stride load and store + */ +typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv, + TCGv, TCGv_env, TCGv_i32); + +static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, + uint32_t data, gen_helper_ldst_stride *fn, + DisasContext *s) +{ + TCGv_ptr dest, mask; + TCGv base, stride; + TCGv_i32 desc; + + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + dest = tcg_temp_new_ptr(); + mask = tcg_temp_new_ptr(); + base = tcg_temp_new(); + stride = tcg_temp_new(); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + + gen_get_gpr(base, rs1); + gen_get_gpr(stride, rs2); + tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + + fn(dest, mask, base, stride, cpu_env, desc); + + tcg_temp_free_ptr(dest); + tcg_temp_free_ptr(mask); + tcg_temp_free(base); + tcg_temp_free(stride); + tcg_temp_free_i32(desc); + gen_set_label(over); + return true; +} + +static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq) +{ + uint32_t data = 0; + gen_helper_ldst_stride *fn; + static gen_helper_ldst_stride * const fns[7][4] = { + { gen_helper_vlsb_v_b, gen_helper_vlsb_v_h, + gen_helper_vlsb_v_w, gen_helper_vlsb_v_d }, + { NULL, gen_helper_vlsh_v_h, + gen_helper_vlsh_v_w, gen_helper_vlsh_v_d }, + { NULL, NULL, + gen_helper_vlsw_v_w, gen_helper_vlsw_v_d }, + { gen_helper_vlse_v_b, gen_helper_vlse_v_h, + gen_helper_vlse_v_w, gen_helper_vlse_v_d }, + { gen_helper_vlsbu_v_b, gen_helper_vlsbu_v_h, + gen_helper_vlsbu_v_w, gen_helper_vlsbu_v_d }, + { NULL, gen_helper_vlshu_v_h, + gen_helper_vlshu_v_w, gen_helper_vlshu_v_d }, + { NULL, NULL, + gen_helper_vlswu_v_w, gen_helper_vlswu_v_d }, + }; + + fn = fns[seq][s->sew]; + if (fn == NULL) { + return false; + } + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, NF, a->nf); + return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s); +} + +static bool ld_stride_check(DisasContext *s, arg_rnfvm* a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, false) && + vext_check_reg(s, a->rd, false) && + vext_check_nf(s, a->nf)); +} + +GEN_VEXT_TRANS(vlsb_v, 0, rnfvm, ld_stride_op, ld_stride_check) +GEN_VEXT_TRANS(vlsh_v, 1, rnfvm, ld_stride_op, ld_stride_check) +GEN_VEXT_TRANS(vlsw_v, 2, rnfvm, ld_stride_op, ld_stride_check) +GEN_VEXT_TRANS(vlse_v, 3, rnfvm, ld_stride_op, ld_stride_check) +GEN_VEXT_TRANS(vlsbu_v, 4, rnfvm, ld_stride_op, ld_stride_check) +GEN_VEXT_TRANS(vlshu_v, 5, rnfvm, ld_stride_op, ld_stride_check) +GEN_VEXT_TRANS(vlswu_v, 6, rnfvm, ld_stride_op, ld_stride_check) + +static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq) +{ + uint32_t data = 0; + gen_helper_ldst_stride *fn; + static gen_helper_ldst_stride * const fns[4][4] = { + /* masked stride store */ + { gen_helper_vssb_v_b, gen_helper_vssb_v_h, + gen_helper_vssb_v_w, gen_helper_vssb_v_d }, + { NULL, gen_helper_vssh_v_h, + gen_helper_vssh_v_w, gen_helper_vssh_v_d }, + { NULL, NULL, + gen_helper_vssw_v_w, gen_helper_vssw_v_d }, + { gen_helper_vsse_v_b, gen_helper_vsse_v_h, + gen_helper_vsse_v_w, gen_helper_vsse_v_d } + }; + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, NF, a->nf); + fn = fns[seq][s->sew]; + if (fn == NULL) { + return false; + } + + return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s); +} + +static bool st_stride_check(DisasContext *s, arg_rnfvm* a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false) && + vext_check_nf(s, a->nf)); +} + +GEN_VEXT_TRANS(vssb_v, 0, rnfvm, st_stride_op, st_stride_check) +GEN_VEXT_TRANS(vssh_v, 1, rnfvm, st_stride_op, st_stride_check) +GEN_VEXT_TRANS(vssw_v, 2, rnfvm, st_stride_op, st_stride_check) +GEN_VEXT_TRANS(vsse_v, 3, rnfvm, st_stride_op, st_stride_check) diff --git a/target/riscv/internals.h b/target/riscv/internals.h index 22a49af413..3253e73474 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -21,4 +21,9 @@ #include "hw/registerfields.h" +/* share data between vector helpers and decode code */ +FIELD(VDATA, MLEN, 0, 8) +FIELD(VDATA, VM, 8, 1) +FIELD(VDATA, LMUL, 9, 2) +FIELD(VDATA, NF, 11, 4) #endif diff --git a/target/riscv/translate.c b/target/riscv/translate.c index cacb9b9cd3..9632e79cf3 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -61,6 +61,7 @@ typedef struct DisasContext { uint8_t lmul; uint8_t sew; uint16_t vlen; + uint16_t mlen; bool vl_eq_vlmax; } DisasContext; @@ -548,6 +549,11 @@ static void decode_RV32_64C(DisasContext *ctx, uint16_t opcode) } } +static int ex_plus_1(DisasContext *ctx, int nf) +{ + return nf + 1; +} + #define EX_SH(amount) \ static int ex_shift_##amount(DisasContext *ctx, int imm) \ { \ @@ -785,6 +791,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->vill = FIELD_EX32(tb_flags, TB_FLAGS, VILL); ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW); ctx->lmul = FIELD_EX32(tb_flags, TB_FLAGS, LMUL); + ctx->mlen = 1 << (ctx->sew + 3 - ctx->lmul); ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX); } diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 40ed0d55e7..5c98da8a4e 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -18,8 +18,11 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/memop.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" +#include "tcg/tcg-gvec-desc.h" +#include "internals.h" #include target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, @@ -51,3 +54,410 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, env->vstart = 0; return vl; } + +/* + * Note that vector data is stored in host-endian 64-bit chunks, + * so addressing units smaller than that needs a host-endian fixup. + */ +#ifdef HOST_WORDS_BIGENDIAN +#define H1(x) ((x) ^ 7) +#define H1_2(x) ((x) ^ 6) +#define H1_4(x) ((x) ^ 4) +#define H2(x) ((x) ^ 3) +#define H4(x) ((x) ^ 1) +#define H8(x) ((x)) +#else +#define H1(x) (x) +#define H1_2(x) (x) +#define H1_4(x) (x) +#define H2(x) (x) +#define H4(x) (x) +#define H8(x) (x) +#endif + +static inline uint32_t vext_nf(uint32_t desc) +{ + return FIELD_EX32(simd_data(desc), VDATA, NF); +} + +static inline uint32_t vext_mlen(uint32_t desc) +{ + return FIELD_EX32(simd_data(desc), VDATA, MLEN); +} + +static inline uint32_t vext_vm(uint32_t desc) +{ + return FIELD_EX32(simd_data(desc), VDATA, VM); +} + +static inline uint32_t vext_lmul(uint32_t desc) +{ + return FIELD_EX32(simd_data(desc), VDATA, LMUL); +} + +/* + * Get vector group length in bytes. Its range is [64, 2048]. + * + * As simd_desc support at most 256, the max vlen is 512 bits. + * So vlen in bytes is encoded as maxsz. + */ +static inline uint32_t vext_maxsz(uint32_t desc) +{ + return simd_maxsz(desc) << vext_lmul(desc); +} + +/* + * This function checks watchpoint before real load operation. + * + * In softmmu mode, the TLB API probe_access is enough for watchpoint check. + * In user mode, there is no watchpoint support now. + * + * It will trigger an exception if there is no mapping in TLB + * and page table walk can't fill the TLB entry. Then the guest + * software can return here after process the exception or never return. + */ +static void probe_pages(CPURISCVState *env, target_ulong addr, + target_ulong len, uintptr_t ra, + MMUAccessType access_type) +{ + target_ulong pagelen = -(addr | TARGET_PAGE_MASK); + target_ulong curlen = MIN(pagelen, len); + + probe_access(env, addr, curlen, access_type, + cpu_mmu_index(env, false), ra); + if (len > curlen) { + addr += curlen; + curlen = len - curlen; + probe_access(env, addr, curlen, access_type, + cpu_mmu_index(env, false), ra); + } +} + +#ifdef HOST_WORDS_BIGENDIAN +static void vext_clear(void *tail, uint32_t cnt, uint32_t tot) +{ + /* + * Split the remaining range to two parts. + * The first part is in the last uint64_t unit. + * The second part start from the next uint64_t unit. + */ + int part1 = 0, part2 = tot - cnt; + if (cnt % 8) { + part1 = 8 - (cnt % 8); + part2 = tot - cnt - part1; + memset((void *)((uintptr_t)tail & ~(7ULL)), 0, part1); + memset((void *)(((uintptr_t)tail + 8) & ~(7ULL)), 0, part2); + } else { + memset(tail, 0, part2); + } +} +#else +static void vext_clear(void *tail, uint32_t cnt, uint32_t tot) +{ + memset(tail, 0, tot - cnt); +} +#endif + +static void clearb(void *vd, uint32_t idx, uint32_t cnt, uint32_t tot) +{ + int8_t *cur = ((int8_t *)vd + H1(idx)); + vext_clear(cur, cnt, tot); +} + +static void clearh(void *vd, uint32_t idx, uint32_t cnt, uint32_t tot) +{ + int16_t *cur = ((int16_t *)vd + H2(idx)); + vext_clear(cur, cnt, tot); +} + +static void clearl(void *vd, uint32_t idx, uint32_t cnt, uint32_t tot) +{ + int32_t *cur = ((int32_t *)vd + H4(idx)); + vext_clear(cur, cnt, tot); +} + +static void clearq(void *vd, uint32_t idx, uint32_t cnt, uint32_t tot) +{ + int64_t *cur = (int64_t *)vd + idx; + vext_clear(cur, cnt, tot); +} + + +static inline int vext_elem_mask(void *v0, int mlen, int index) +{ + int idx = (index * mlen) / 64; + int pos = (index * mlen) % 64; + return (((uint64_t *)v0)[idx] >> pos) & 1; +} + +/* elements operations for load and store */ +typedef void vext_ldst_elem_fn(CPURISCVState *env, target_ulong addr, + uint32_t idx, void *vd, uintptr_t retaddr); +typedef void clear_fn(void *vd, uint32_t idx, uint32_t cnt, uint32_t tot); + +#define GEN_VEXT_LD_ELEM(NAME, MTYPE, ETYPE, H, LDSUF) \ +static void NAME(CPURISCVState *env, abi_ptr addr, \ + uint32_t idx, void *vd, uintptr_t retaddr)\ +{ \ + MTYPE data; \ + ETYPE *cur = ((ETYPE *)vd + H(idx)); \ + data = cpu_##LDSUF##_data_ra(env, addr, retaddr); \ + *cur = data; \ +} \ + +GEN_VEXT_LD_ELEM(ldb_b, int8_t, int8_t, H1, ldsb) +GEN_VEXT_LD_ELEM(ldb_h, int8_t, int16_t, H2, ldsb) +GEN_VEXT_LD_ELEM(ldb_w, int8_t, int32_t, H4, ldsb) +GEN_VEXT_LD_ELEM(ldb_d, int8_t, int64_t, H8, ldsb) +GEN_VEXT_LD_ELEM(ldh_h, int16_t, int16_t, H2, ldsw) +GEN_VEXT_LD_ELEM(ldh_w, int16_t, int32_t, H4, ldsw) +GEN_VEXT_LD_ELEM(ldh_d, int16_t, int64_t, H8, ldsw) +GEN_VEXT_LD_ELEM(ldw_w, int32_t, int32_t, H4, ldl) +GEN_VEXT_LD_ELEM(ldw_d, int32_t, int64_t, H8, ldl) +GEN_VEXT_LD_ELEM(lde_b, int8_t, int8_t, H1, ldsb) +GEN_VEXT_LD_ELEM(lde_h, int16_t, int16_t, H2, ldsw) +GEN_VEXT_LD_ELEM(lde_w, int32_t, int32_t, H4, ldl) +GEN_VEXT_LD_ELEM(lde_d, int64_t, int64_t, H8, ldq) +GEN_VEXT_LD_ELEM(ldbu_b, uint8_t, uint8_t, H1, ldub) +GEN_VEXT_LD_ELEM(ldbu_h, uint8_t, uint16_t, H2, ldub) +GEN_VEXT_LD_ELEM(ldbu_w, uint8_t, uint32_t, H4, ldub) +GEN_VEXT_LD_ELEM(ldbu_d, uint8_t, uint64_t, H8, ldub) +GEN_VEXT_LD_ELEM(ldhu_h, uint16_t, uint16_t, H2, lduw) +GEN_VEXT_LD_ELEM(ldhu_w, uint16_t, uint32_t, H4, lduw) +GEN_VEXT_LD_ELEM(ldhu_d, uint16_t, uint64_t, H8, lduw) +GEN_VEXT_LD_ELEM(ldwu_w, uint32_t, uint32_t, H4, ldl) +GEN_VEXT_LD_ELEM(ldwu_d, uint32_t, uint64_t, H8, ldl) + +#define GEN_VEXT_ST_ELEM(NAME, ETYPE, H, STSUF) \ +static void NAME(CPURISCVState *env, abi_ptr addr, \ + uint32_t idx, void *vd, uintptr_t retaddr)\ +{ \ + ETYPE data = *((ETYPE *)vd + H(idx)); \ + cpu_##STSUF##_data_ra(env, addr, data, retaddr); \ +} + +GEN_VEXT_ST_ELEM(stb_b, int8_t, H1, stb) +GEN_VEXT_ST_ELEM(stb_h, int16_t, H2, stb) +GEN_VEXT_ST_ELEM(stb_w, int32_t, H4, stb) +GEN_VEXT_ST_ELEM(stb_d, int64_t, H8, stb) +GEN_VEXT_ST_ELEM(sth_h, int16_t, H2, stw) +GEN_VEXT_ST_ELEM(sth_w, int32_t, H4, stw) +GEN_VEXT_ST_ELEM(sth_d, int64_t, H8, stw) +GEN_VEXT_ST_ELEM(stw_w, int32_t, H4, stl) +GEN_VEXT_ST_ELEM(stw_d, int64_t, H8, stl) +GEN_VEXT_ST_ELEM(ste_b, int8_t, H1, stb) +GEN_VEXT_ST_ELEM(ste_h, int16_t, H2, stw) +GEN_VEXT_ST_ELEM(ste_w, int32_t, H4, stl) +GEN_VEXT_ST_ELEM(ste_d, int64_t, H8, stq) + +/* + *** stride: access vector element from strided memory + */ +static void +vext_ldst_stride(void *vd, void *v0, target_ulong base, + target_ulong stride, CPURISCVState *env, + uint32_t desc, uint32_t vm, + vext_ldst_elem_fn *ldst_elem, clear_fn *clear_elem, + uint32_t esz, uint32_t msz, uintptr_t ra, + MMUAccessType access_type) +{ + uint32_t i, k; + uint32_t nf = vext_nf(desc); + uint32_t mlen = vext_mlen(desc); + uint32_t vlmax = vext_maxsz(desc) / esz; + + /* probe every access*/ + for (i = 0; i < env->vl; i++) { + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + probe_pages(env, base + stride * i, nf * msz, ra, access_type); + } + /* do real access */ + for (i = 0; i < env->vl; i++) { + k = 0; + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + while (k < nf) { + target_ulong addr = base + stride * i + k * msz; + ldst_elem(env, addr, i + k * vlmax, vd, ra); + k++; + } + } + /* clear tail elements */ + if (clear_elem) { + for (k = 0; k < nf; k++) { + clear_elem(vd, env->vl + k * vlmax, env->vl * esz, vlmax * esz); + } + } +} + +#define GEN_VEXT_LD_STRIDE(NAME, MTYPE, ETYPE, LOAD_FN, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void * v0, target_ulong base, \ + target_ulong stride, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + uint32_t vm = vext_vm(desc); \ + vext_ldst_stride(vd, v0, base, stride, env, desc, vm, LOAD_FN, \ + CLEAR_FN, sizeof(ETYPE), sizeof(MTYPE), \ + GETPC(), MMU_DATA_LOAD); \ +} + +GEN_VEXT_LD_STRIDE(vlsb_v_b, int8_t, int8_t, ldb_b, clearb) +GEN_VEXT_LD_STRIDE(vlsb_v_h, int8_t, int16_t, ldb_h, clearh) +GEN_VEXT_LD_STRIDE(vlsb_v_w, int8_t, int32_t, ldb_w, clearl) +GEN_VEXT_LD_STRIDE(vlsb_v_d, int8_t, int64_t, ldb_d, clearq) +GEN_VEXT_LD_STRIDE(vlsh_v_h, int16_t, int16_t, ldh_h, clearh) +GEN_VEXT_LD_STRIDE(vlsh_v_w, int16_t, int32_t, ldh_w, clearl) +GEN_VEXT_LD_STRIDE(vlsh_v_d, int16_t, int64_t, ldh_d, clearq) +GEN_VEXT_LD_STRIDE(vlsw_v_w, int32_t, int32_t, ldw_w, clearl) +GEN_VEXT_LD_STRIDE(vlsw_v_d, int32_t, int64_t, ldw_d, clearq) +GEN_VEXT_LD_STRIDE(vlse_v_b, int8_t, int8_t, lde_b, clearb) +GEN_VEXT_LD_STRIDE(vlse_v_h, int16_t, int16_t, lde_h, clearh) +GEN_VEXT_LD_STRIDE(vlse_v_w, int32_t, int32_t, lde_w, clearl) +GEN_VEXT_LD_STRIDE(vlse_v_d, int64_t, int64_t, lde_d, clearq) +GEN_VEXT_LD_STRIDE(vlsbu_v_b, uint8_t, uint8_t, ldbu_b, clearb) +GEN_VEXT_LD_STRIDE(vlsbu_v_h, uint8_t, uint16_t, ldbu_h, clearh) +GEN_VEXT_LD_STRIDE(vlsbu_v_w, uint8_t, uint32_t, ldbu_w, clearl) +GEN_VEXT_LD_STRIDE(vlsbu_v_d, uint8_t, uint64_t, ldbu_d, clearq) +GEN_VEXT_LD_STRIDE(vlshu_v_h, uint16_t, uint16_t, ldhu_h, clearh) +GEN_VEXT_LD_STRIDE(vlshu_v_w, uint16_t, uint32_t, ldhu_w, clearl) +GEN_VEXT_LD_STRIDE(vlshu_v_d, uint16_t, uint64_t, ldhu_d, clearq) +GEN_VEXT_LD_STRIDE(vlswu_v_w, uint32_t, uint32_t, ldwu_w, clearl) +GEN_VEXT_LD_STRIDE(vlswu_v_d, uint32_t, uint64_t, ldwu_d, clearq) + +#define GEN_VEXT_ST_STRIDE(NAME, MTYPE, ETYPE, STORE_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ + target_ulong stride, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + uint32_t vm = vext_vm(desc); \ + vext_ldst_stride(vd, v0, base, stride, env, desc, vm, STORE_FN, \ + NULL, sizeof(ETYPE), sizeof(MTYPE), \ + GETPC(), MMU_DATA_STORE); \ +} + +GEN_VEXT_ST_STRIDE(vssb_v_b, int8_t, int8_t, stb_b) +GEN_VEXT_ST_STRIDE(vssb_v_h, int8_t, int16_t, stb_h) +GEN_VEXT_ST_STRIDE(vssb_v_w, int8_t, int32_t, stb_w) +GEN_VEXT_ST_STRIDE(vssb_v_d, int8_t, int64_t, stb_d) +GEN_VEXT_ST_STRIDE(vssh_v_h, int16_t, int16_t, sth_h) +GEN_VEXT_ST_STRIDE(vssh_v_w, int16_t, int32_t, sth_w) +GEN_VEXT_ST_STRIDE(vssh_v_d, int16_t, int64_t, sth_d) +GEN_VEXT_ST_STRIDE(vssw_v_w, int32_t, int32_t, stw_w) +GEN_VEXT_ST_STRIDE(vssw_v_d, int32_t, int64_t, stw_d) +GEN_VEXT_ST_STRIDE(vsse_v_b, int8_t, int8_t, ste_b) +GEN_VEXT_ST_STRIDE(vsse_v_h, int16_t, int16_t, ste_h) +GEN_VEXT_ST_STRIDE(vsse_v_w, int32_t, int32_t, ste_w) +GEN_VEXT_ST_STRIDE(vsse_v_d, int64_t, int64_t, ste_d) + +/* + *** unit-stride: access elements stored contiguously in memory + */ + +/* unmasked unit-stride load and store operation*/ +static void +vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, + vext_ldst_elem_fn *ldst_elem, clear_fn *clear_elem, + uint32_t esz, uint32_t msz, uintptr_t ra, + MMUAccessType access_type) +{ + uint32_t i, k; + uint32_t nf = vext_nf(desc); + uint32_t vlmax = vext_maxsz(desc) / esz; + + /* probe every access */ + probe_pages(env, base, env->vl * nf * msz, ra, access_type); + /* load bytes from guest memory */ + for (i = 0; i < env->vl; i++) { + k = 0; + while (k < nf) { + target_ulong addr = base + (i * nf + k) * msz; + ldst_elem(env, addr, i + k * vlmax, vd, ra); + k++; + } + } + /* clear tail elements */ + if (clear_elem) { + for (k = 0; k < nf; k++) { + clear_elem(vd, env->vl + k * vlmax, env->vl * esz, vlmax * esz); + } + } +} + +/* + * masked unit-stride load and store operation will be a special case of stride, + * stride = NF * sizeof (MTYPE) + */ + +#define GEN_VEXT_LD_US(NAME, MTYPE, ETYPE, LOAD_FN, CLEAR_FN) \ +void HELPER(NAME##_mask)(void *vd, void *v0, target_ulong base, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t stride = vext_nf(desc) * sizeof(MTYPE); \ + vext_ldst_stride(vd, v0, base, stride, env, desc, false, LOAD_FN, \ + CLEAR_FN, sizeof(ETYPE), sizeof(MTYPE), \ + GETPC(), MMU_DATA_LOAD); \ +} \ + \ +void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + vext_ldst_us(vd, base, env, desc, LOAD_FN, CLEAR_FN, \ + sizeof(ETYPE), sizeof(MTYPE), GETPC(), MMU_DATA_LOAD); \ +} + +GEN_VEXT_LD_US(vlb_v_b, int8_t, int8_t, ldb_b, clearb) +GEN_VEXT_LD_US(vlb_v_h, int8_t, int16_t, ldb_h, clearh) +GEN_VEXT_LD_US(vlb_v_w, int8_t, int32_t, ldb_w, clearl) +GEN_VEXT_LD_US(vlb_v_d, int8_t, int64_t, ldb_d, clearq) +GEN_VEXT_LD_US(vlh_v_h, int16_t, int16_t, ldh_h, clearh) +GEN_VEXT_LD_US(vlh_v_w, int16_t, int32_t, ldh_w, clearl) +GEN_VEXT_LD_US(vlh_v_d, int16_t, int64_t, ldh_d, clearq) +GEN_VEXT_LD_US(vlw_v_w, int32_t, int32_t, ldw_w, clearl) +GEN_VEXT_LD_US(vlw_v_d, int32_t, int64_t, ldw_d, clearq) +GEN_VEXT_LD_US(vle_v_b, int8_t, int8_t, lde_b, clearb) +GEN_VEXT_LD_US(vle_v_h, int16_t, int16_t, lde_h, clearh) +GEN_VEXT_LD_US(vle_v_w, int32_t, int32_t, lde_w, clearl) +GEN_VEXT_LD_US(vle_v_d, int64_t, int64_t, lde_d, clearq) +GEN_VEXT_LD_US(vlbu_v_b, uint8_t, uint8_t, ldbu_b, clearb) +GEN_VEXT_LD_US(vlbu_v_h, uint8_t, uint16_t, ldbu_h, clearh) +GEN_VEXT_LD_US(vlbu_v_w, uint8_t, uint32_t, ldbu_w, clearl) +GEN_VEXT_LD_US(vlbu_v_d, uint8_t, uint64_t, ldbu_d, clearq) +GEN_VEXT_LD_US(vlhu_v_h, uint16_t, uint16_t, ldhu_h, clearh) +GEN_VEXT_LD_US(vlhu_v_w, uint16_t, uint32_t, ldhu_w, clearl) +GEN_VEXT_LD_US(vlhu_v_d, uint16_t, uint64_t, ldhu_d, clearq) +GEN_VEXT_LD_US(vlwu_v_w, uint32_t, uint32_t, ldwu_w, clearl) +GEN_VEXT_LD_US(vlwu_v_d, uint32_t, uint64_t, ldwu_d, clearq) + +#define GEN_VEXT_ST_US(NAME, MTYPE, ETYPE, STORE_FN) \ +void HELPER(NAME##_mask)(void *vd, void *v0, target_ulong base, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t stride = vext_nf(desc) * sizeof(MTYPE); \ + vext_ldst_stride(vd, v0, base, stride, env, desc, false, STORE_FN, \ + NULL, sizeof(ETYPE), sizeof(MTYPE), \ + GETPC(), MMU_DATA_STORE); \ +} \ + \ +void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + vext_ldst_us(vd, base, env, desc, STORE_FN, NULL, \ + sizeof(ETYPE), sizeof(MTYPE), GETPC(), MMU_DATA_STORE);\ +} + +GEN_VEXT_ST_US(vsb_v_b, int8_t, int8_t , stb_b) +GEN_VEXT_ST_US(vsb_v_h, int8_t, int16_t, stb_h) +GEN_VEXT_ST_US(vsb_v_w, int8_t, int32_t, stb_w) +GEN_VEXT_ST_US(vsb_v_d, int8_t, int64_t, stb_d) +GEN_VEXT_ST_US(vsh_v_h, int16_t, int16_t, sth_h) +GEN_VEXT_ST_US(vsh_v_w, int16_t, int32_t, sth_w) +GEN_VEXT_ST_US(vsh_v_d, int16_t, int64_t, sth_d) +GEN_VEXT_ST_US(vsw_v_w, int32_t, int32_t, stw_w) +GEN_VEXT_ST_US(vsw_v_d, int32_t, int64_t, stw_d) +GEN_VEXT_ST_US(vse_v_b, int8_t, int8_t , ste_b) +GEN_VEXT_ST_US(vse_v_h, int16_t, int16_t, ste_h) +GEN_VEXT_ST_US(vse_v_w, int32_t, int32_t, ste_w) +GEN_VEXT_ST_US(vse_v_d, int64_t, int64_t, ste_d) From f732560e3551c0823cee52efba993fbb8f689a36 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:24:55 +0800 Subject: [PATCH 1808/2595] target/riscv: add vector index load and store instructions Vector indexed operations add the contents of each element of the vector offset operand specified by vs2 to the base effective address to give the effective address of each element. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-8-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 35 +++++++ target/riscv/insn32.decode | 13 +++ target/riscv/insn_trans/trans_rvv.inc.c | 129 ++++++++++++++++++++++++ target/riscv/vector_helper.c | 116 +++++++++++++++++++++ 4 files changed, 293 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index f03b3d52f5..f3650f736e 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -189,3 +189,38 @@ DEF_HELPER_6(vsse_v_b, void, ptr, ptr, tl, tl, env, i32) DEF_HELPER_6(vsse_v_h, void, ptr, ptr, tl, tl, env, i32) DEF_HELPER_6(vsse_v_w, void, ptr, ptr, tl, tl, env, i32) DEF_HELPER_6(vsse_v_d, void, ptr, ptr, tl, tl, env, i32) +DEF_HELPER_6(vlxb_v_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxb_v_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxb_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxb_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxh_v_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxh_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxh_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxw_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxw_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxe_v_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxe_v_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxe_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxe_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxbu_v_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxbu_v_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxbu_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxbu_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxhu_v_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxhu_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxhu_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxwu_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vlxwu_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxb_v_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxb_v_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxb_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxb_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxh_v_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxh_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxh_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxw_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxw_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxe_v_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxe_v_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxe_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsxe_v_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 58b95792e6..287d52bcc9 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -243,6 +243,19 @@ vssh_v ... 010 . ..... ..... 101 ..... 0100111 @r_nfvm vssw_v ... 010 . ..... ..... 110 ..... 0100111 @r_nfvm vsse_v ... 010 . ..... ..... 111 ..... 0100111 @r_nfvm +vlxb_v ... 111 . ..... ..... 000 ..... 0000111 @r_nfvm +vlxh_v ... 111 . ..... ..... 101 ..... 0000111 @r_nfvm +vlxw_v ... 111 . ..... ..... 110 ..... 0000111 @r_nfvm +vlxe_v ... 011 . ..... ..... 111 ..... 0000111 @r_nfvm +vlxbu_v ... 011 . ..... ..... 000 ..... 0000111 @r_nfvm +vlxhu_v ... 011 . ..... ..... 101 ..... 0000111 @r_nfvm +vlxwu_v ... 011 . ..... ..... 110 ..... 0000111 @r_nfvm +# Vector ordered-indexed and unordered-indexed store insns. +vsxb_v ... -11 . ..... ..... 000 ..... 0100111 @r_nfvm +vsxh_v ... -11 . ..... ..... 101 ..... 0100111 @r_nfvm +vsxw_v ... -11 . ..... ..... 110 ..... 0100111 @r_nfvm +vsxe_v ... -11 . ..... ..... 111 ..... 0100111 @r_nfvm + # *** new major opcode OP-V *** vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 451ab05f69..11a3a89d54 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -432,3 +432,132 @@ GEN_VEXT_TRANS(vssb_v, 0, rnfvm, st_stride_op, st_stride_check) GEN_VEXT_TRANS(vssh_v, 1, rnfvm, st_stride_op, st_stride_check) GEN_VEXT_TRANS(vssw_v, 2, rnfvm, st_stride_op, st_stride_check) GEN_VEXT_TRANS(vsse_v, 3, rnfvm, st_stride_op, st_stride_check) + +/* + *** index load and store + */ +typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv, + TCGv_ptr, TCGv_env, TCGv_i32); + +static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, + uint32_t data, gen_helper_ldst_index *fn, + DisasContext *s) +{ + TCGv_ptr dest, mask, index; + TCGv base; + TCGv_i32 desc; + + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + dest = tcg_temp_new_ptr(); + mask = tcg_temp_new_ptr(); + index = tcg_temp_new_ptr(); + base = tcg_temp_new(); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + + gen_get_gpr(base, rs1); + tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2)); + tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + + fn(dest, mask, base, index, cpu_env, desc); + + tcg_temp_free_ptr(dest); + tcg_temp_free_ptr(mask); + tcg_temp_free_ptr(index); + tcg_temp_free(base); + tcg_temp_free_i32(desc); + gen_set_label(over); + return true; +} + +static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq) +{ + uint32_t data = 0; + gen_helper_ldst_index *fn; + static gen_helper_ldst_index * const fns[7][4] = { + { gen_helper_vlxb_v_b, gen_helper_vlxb_v_h, + gen_helper_vlxb_v_w, gen_helper_vlxb_v_d }, + { NULL, gen_helper_vlxh_v_h, + gen_helper_vlxh_v_w, gen_helper_vlxh_v_d }, + { NULL, NULL, + gen_helper_vlxw_v_w, gen_helper_vlxw_v_d }, + { gen_helper_vlxe_v_b, gen_helper_vlxe_v_h, + gen_helper_vlxe_v_w, gen_helper_vlxe_v_d }, + { gen_helper_vlxbu_v_b, gen_helper_vlxbu_v_h, + gen_helper_vlxbu_v_w, gen_helper_vlxbu_v_d }, + { NULL, gen_helper_vlxhu_v_h, + gen_helper_vlxhu_v_w, gen_helper_vlxhu_v_d }, + { NULL, NULL, + gen_helper_vlxwu_v_w, gen_helper_vlxwu_v_d }, + }; + + fn = fns[seq][s->sew]; + if (fn == NULL) { + return false; + } + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, NF, a->nf); + return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s); +} + +static bool ld_index_check(DisasContext *s, arg_rnfvm* a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, false) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + vext_check_nf(s, a->nf)); +} + +GEN_VEXT_TRANS(vlxb_v, 0, rnfvm, ld_index_op, ld_index_check) +GEN_VEXT_TRANS(vlxh_v, 1, rnfvm, ld_index_op, ld_index_check) +GEN_VEXT_TRANS(vlxw_v, 2, rnfvm, ld_index_op, ld_index_check) +GEN_VEXT_TRANS(vlxe_v, 3, rnfvm, ld_index_op, ld_index_check) +GEN_VEXT_TRANS(vlxbu_v, 4, rnfvm, ld_index_op, ld_index_check) +GEN_VEXT_TRANS(vlxhu_v, 5, rnfvm, ld_index_op, ld_index_check) +GEN_VEXT_TRANS(vlxwu_v, 6, rnfvm, ld_index_op, ld_index_check) + +static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq) +{ + uint32_t data = 0; + gen_helper_ldst_index *fn; + static gen_helper_ldst_index * const fns[4][4] = { + { gen_helper_vsxb_v_b, gen_helper_vsxb_v_h, + gen_helper_vsxb_v_w, gen_helper_vsxb_v_d }, + { NULL, gen_helper_vsxh_v_h, + gen_helper_vsxh_v_w, gen_helper_vsxh_v_d }, + { NULL, NULL, + gen_helper_vsxw_v_w, gen_helper_vsxw_v_d }, + { gen_helper_vsxe_v_b, gen_helper_vsxe_v_h, + gen_helper_vsxe_v_w, gen_helper_vsxe_v_d } + }; + + fn = fns[seq][s->sew]; + if (fn == NULL) { + return false; + } + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, NF, a->nf); + return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s); +} + +static bool st_index_check(DisasContext *s, arg_rnfvm* a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + vext_check_nf(s, a->nf)); +} + +GEN_VEXT_TRANS(vsxb_v, 0, rnfvm, st_index_op, st_index_check) +GEN_VEXT_TRANS(vsxh_v, 1, rnfvm, st_index_op, st_index_check) +GEN_VEXT_TRANS(vsxw_v, 2, rnfvm, st_index_op, st_index_check) +GEN_VEXT_TRANS(vsxe_v, 3, rnfvm, st_index_op, st_index_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 5c98da8a4e..bbf5991688 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -461,3 +461,119 @@ GEN_VEXT_ST_US(vse_v_b, int8_t, int8_t , ste_b) GEN_VEXT_ST_US(vse_v_h, int16_t, int16_t, ste_h) GEN_VEXT_ST_US(vse_v_w, int32_t, int32_t, ste_w) GEN_VEXT_ST_US(vse_v_d, int64_t, int64_t, ste_d) + +/* + *** index: access vector element from indexed memory + */ +typedef target_ulong vext_get_index_addr(target_ulong base, + uint32_t idx, void *vs2); + +#define GEN_VEXT_GET_INDEX_ADDR(NAME, ETYPE, H) \ +static target_ulong NAME(target_ulong base, \ + uint32_t idx, void *vs2) \ +{ \ + return (base + *((ETYPE *)vs2 + H(idx))); \ +} + +GEN_VEXT_GET_INDEX_ADDR(idx_b, int8_t, H1) +GEN_VEXT_GET_INDEX_ADDR(idx_h, int16_t, H2) +GEN_VEXT_GET_INDEX_ADDR(idx_w, int32_t, H4) +GEN_VEXT_GET_INDEX_ADDR(idx_d, int64_t, H8) + +static inline void +vext_ldst_index(void *vd, void *v0, target_ulong base, + void *vs2, CPURISCVState *env, uint32_t desc, + vext_get_index_addr get_index_addr, + vext_ldst_elem_fn *ldst_elem, + clear_fn *clear_elem, + uint32_t esz, uint32_t msz, uintptr_t ra, + MMUAccessType access_type) +{ + uint32_t i, k; + uint32_t nf = vext_nf(desc); + uint32_t vm = vext_vm(desc); + uint32_t mlen = vext_mlen(desc); + uint32_t vlmax = vext_maxsz(desc) / esz; + + /* probe every access*/ + for (i = 0; i < env->vl; i++) { + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + probe_pages(env, get_index_addr(base, i, vs2), nf * msz, ra, + access_type); + } + /* load bytes from guest memory */ + for (i = 0; i < env->vl; i++) { + k = 0; + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + while (k < nf) { + abi_ptr addr = get_index_addr(base, i, vs2) + k * msz; + ldst_elem(env, addr, i + k * vlmax, vd, ra); + k++; + } + } + /* clear tail elements */ + if (clear_elem) { + for (k = 0; k < nf; k++) { + clear_elem(vd, env->vl + k * vlmax, env->vl * esz, vlmax * esz); + } + } +} + +#define GEN_VEXT_LD_INDEX(NAME, MTYPE, ETYPE, INDEX_FN, LOAD_FN, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ +{ \ + vext_ldst_index(vd, v0, base, vs2, env, desc, INDEX_FN, \ + LOAD_FN, CLEAR_FN, sizeof(ETYPE), sizeof(MTYPE), \ + GETPC(), MMU_DATA_LOAD); \ +} + +GEN_VEXT_LD_INDEX(vlxb_v_b, int8_t, int8_t, idx_b, ldb_b, clearb) +GEN_VEXT_LD_INDEX(vlxb_v_h, int8_t, int16_t, idx_h, ldb_h, clearh) +GEN_VEXT_LD_INDEX(vlxb_v_w, int8_t, int32_t, idx_w, ldb_w, clearl) +GEN_VEXT_LD_INDEX(vlxb_v_d, int8_t, int64_t, idx_d, ldb_d, clearq) +GEN_VEXT_LD_INDEX(vlxh_v_h, int16_t, int16_t, idx_h, ldh_h, clearh) +GEN_VEXT_LD_INDEX(vlxh_v_w, int16_t, int32_t, idx_w, ldh_w, clearl) +GEN_VEXT_LD_INDEX(vlxh_v_d, int16_t, int64_t, idx_d, ldh_d, clearq) +GEN_VEXT_LD_INDEX(vlxw_v_w, int32_t, int32_t, idx_w, ldw_w, clearl) +GEN_VEXT_LD_INDEX(vlxw_v_d, int32_t, int64_t, idx_d, ldw_d, clearq) +GEN_VEXT_LD_INDEX(vlxe_v_b, int8_t, int8_t, idx_b, lde_b, clearb) +GEN_VEXT_LD_INDEX(vlxe_v_h, int16_t, int16_t, idx_h, lde_h, clearh) +GEN_VEXT_LD_INDEX(vlxe_v_w, int32_t, int32_t, idx_w, lde_w, clearl) +GEN_VEXT_LD_INDEX(vlxe_v_d, int64_t, int64_t, idx_d, lde_d, clearq) +GEN_VEXT_LD_INDEX(vlxbu_v_b, uint8_t, uint8_t, idx_b, ldbu_b, clearb) +GEN_VEXT_LD_INDEX(vlxbu_v_h, uint8_t, uint16_t, idx_h, ldbu_h, clearh) +GEN_VEXT_LD_INDEX(vlxbu_v_w, uint8_t, uint32_t, idx_w, ldbu_w, clearl) +GEN_VEXT_LD_INDEX(vlxbu_v_d, uint8_t, uint64_t, idx_d, ldbu_d, clearq) +GEN_VEXT_LD_INDEX(vlxhu_v_h, uint16_t, uint16_t, idx_h, ldhu_h, clearh) +GEN_VEXT_LD_INDEX(vlxhu_v_w, uint16_t, uint32_t, idx_w, ldhu_w, clearl) +GEN_VEXT_LD_INDEX(vlxhu_v_d, uint16_t, uint64_t, idx_d, ldhu_d, clearq) +GEN_VEXT_LD_INDEX(vlxwu_v_w, uint32_t, uint32_t, idx_w, ldwu_w, clearl) +GEN_VEXT_LD_INDEX(vlxwu_v_d, uint32_t, uint64_t, idx_d, ldwu_d, clearq) + +#define GEN_VEXT_ST_INDEX(NAME, MTYPE, ETYPE, INDEX_FN, STORE_FN)\ +void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ +{ \ + vext_ldst_index(vd, v0, base, vs2, env, desc, INDEX_FN, \ + STORE_FN, NULL, sizeof(ETYPE), sizeof(MTYPE),\ + GETPC(), MMU_DATA_STORE); \ +} + +GEN_VEXT_ST_INDEX(vsxb_v_b, int8_t, int8_t, idx_b, stb_b) +GEN_VEXT_ST_INDEX(vsxb_v_h, int8_t, int16_t, idx_h, stb_h) +GEN_VEXT_ST_INDEX(vsxb_v_w, int8_t, int32_t, idx_w, stb_w) +GEN_VEXT_ST_INDEX(vsxb_v_d, int8_t, int64_t, idx_d, stb_d) +GEN_VEXT_ST_INDEX(vsxh_v_h, int16_t, int16_t, idx_h, sth_h) +GEN_VEXT_ST_INDEX(vsxh_v_w, int16_t, int32_t, idx_w, sth_w) +GEN_VEXT_ST_INDEX(vsxh_v_d, int16_t, int64_t, idx_d, sth_d) +GEN_VEXT_ST_INDEX(vsxw_v_w, int32_t, int32_t, idx_w, stw_w) +GEN_VEXT_ST_INDEX(vsxw_v_d, int32_t, int64_t, idx_d, stw_d) +GEN_VEXT_ST_INDEX(vsxe_v_b, int8_t, int8_t, idx_b, ste_b) +GEN_VEXT_ST_INDEX(vsxe_v_h, int16_t, int16_t, idx_h, ste_h) +GEN_VEXT_ST_INDEX(vsxe_v_w, int32_t, int32_t, idx_w, ste_w) +GEN_VEXT_ST_INDEX(vsxe_v_d, int64_t, int64_t, idx_d, ste_d) From 022b4ecf775ffeff522eaea4f0d94edcfe00a0a9 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:24:56 +0800 Subject: [PATCH 1809/2595] target/riscv: add fault-only-first unit stride load The unit-stride fault-only-fault load instructions are used to vectorize loops with data-dependent exit conditions(while loops). These instructions execute as a regular load except that they will only take a trap on element 0. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-9-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 22 +++++ target/riscv/insn32.decode | 7 ++ target/riscv/insn_trans/trans_rvv.inc.c | 73 ++++++++++++++++ target/riscv/vector_helper.c | 110 ++++++++++++++++++++++++ 4 files changed, 212 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index f3650f736e..5c97bc446e 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -224,3 +224,25 @@ DEF_HELPER_6(vsxe_v_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vsxe_v_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vsxe_v_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vsxe_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_5(vlbff_v_b, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbff_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbff_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbff_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhff_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhff_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhff_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlwff_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlwff_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vleff_v_b, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vleff_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vleff_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vleff_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbuff_v_b, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbuff_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbuff_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlbuff_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhuff_v_h, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhuff_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlhuff_v_d, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlwuff_v_w, void, ptr, ptr, tl, env, i32) +DEF_HELPER_5(vlwuff_v_d, void, ptr, ptr, tl, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 287d52bcc9..7146aec22a 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -226,6 +226,13 @@ vle_v ... 000 . 00000 ..... 111 ..... 0000111 @r2_nfvm vlbu_v ... 000 . 00000 ..... 000 ..... 0000111 @r2_nfvm vlhu_v ... 000 . 00000 ..... 101 ..... 0000111 @r2_nfvm vlwu_v ... 000 . 00000 ..... 110 ..... 0000111 @r2_nfvm +vlbff_v ... 100 . 10000 ..... 000 ..... 0000111 @r2_nfvm +vlhff_v ... 100 . 10000 ..... 101 ..... 0000111 @r2_nfvm +vlwff_v ... 100 . 10000 ..... 110 ..... 0000111 @r2_nfvm +vleff_v ... 000 . 10000 ..... 111 ..... 0000111 @r2_nfvm +vlbuff_v ... 000 . 10000 ..... 000 ..... 0000111 @r2_nfvm +vlhuff_v ... 000 . 10000 ..... 101 ..... 0000111 @r2_nfvm +vlwuff_v ... 000 . 10000 ..... 110 ..... 0000111 @r2_nfvm vsb_v ... 000 . 00000 ..... 000 ..... 0100111 @r2_nfvm vsh_v ... 000 . 00000 ..... 101 ..... 0100111 @r2_nfvm vsw_v ... 000 . 00000 ..... 110 ..... 0100111 @r2_nfvm diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 11a3a89d54..5e2fbb7078 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -561,3 +561,76 @@ GEN_VEXT_TRANS(vsxb_v, 0, rnfvm, st_index_op, st_index_check) GEN_VEXT_TRANS(vsxh_v, 1, rnfvm, st_index_op, st_index_check) GEN_VEXT_TRANS(vsxw_v, 2, rnfvm, st_index_op, st_index_check) GEN_VEXT_TRANS(vsxe_v, 3, rnfvm, st_index_op, st_index_check) + +/* + *** unit stride fault-only-first load + */ +static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data, + gen_helper_ldst_us *fn, DisasContext *s) +{ + TCGv_ptr dest, mask; + TCGv base; + TCGv_i32 desc; + + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + dest = tcg_temp_new_ptr(); + mask = tcg_temp_new_ptr(); + base = tcg_temp_new(); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + + gen_get_gpr(base, rs1); + tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + + fn(dest, mask, base, cpu_env, desc); + + tcg_temp_free_ptr(dest); + tcg_temp_free_ptr(mask); + tcg_temp_free(base); + tcg_temp_free_i32(desc); + gen_set_label(over); + return true; +} + +static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq) +{ + uint32_t data = 0; + gen_helper_ldst_us *fn; + static gen_helper_ldst_us * const fns[7][4] = { + { gen_helper_vlbff_v_b, gen_helper_vlbff_v_h, + gen_helper_vlbff_v_w, gen_helper_vlbff_v_d }, + { NULL, gen_helper_vlhff_v_h, + gen_helper_vlhff_v_w, gen_helper_vlhff_v_d }, + { NULL, NULL, + gen_helper_vlwff_v_w, gen_helper_vlwff_v_d }, + { gen_helper_vleff_v_b, gen_helper_vleff_v_h, + gen_helper_vleff_v_w, gen_helper_vleff_v_d }, + { gen_helper_vlbuff_v_b, gen_helper_vlbuff_v_h, + gen_helper_vlbuff_v_w, gen_helper_vlbuff_v_d }, + { NULL, gen_helper_vlhuff_v_h, + gen_helper_vlhuff_v_w, gen_helper_vlhuff_v_d }, + { NULL, NULL, + gen_helper_vlwuff_v_w, gen_helper_vlwuff_v_d } + }; + + fn = fns[seq][s->sew]; + if (fn == NULL) { + return false; + } + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, NF, a->nf); + return ldff_trans(a->rd, a->rs1, data, fn, s); +} + +GEN_VEXT_TRANS(vlbff_v, 0, r2nfvm, ldff_op, ld_us_check) +GEN_VEXT_TRANS(vlhff_v, 1, r2nfvm, ldff_op, ld_us_check) +GEN_VEXT_TRANS(vlwff_v, 2, r2nfvm, ldff_op, ld_us_check) +GEN_VEXT_TRANS(vleff_v, 3, r2nfvm, ldff_op, ld_us_check) +GEN_VEXT_TRANS(vlbuff_v, 4, r2nfvm, ldff_op, ld_us_check) +GEN_VEXT_TRANS(vlhuff_v, 5, r2nfvm, ldff_op, ld_us_check) +GEN_VEXT_TRANS(vlwuff_v, 6, r2nfvm, ldff_op, ld_us_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index bbf5991688..cbe87265a1 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -577,3 +577,113 @@ GEN_VEXT_ST_INDEX(vsxe_v_b, int8_t, int8_t, idx_b, ste_b) GEN_VEXT_ST_INDEX(vsxe_v_h, int16_t, int16_t, idx_h, ste_h) GEN_VEXT_ST_INDEX(vsxe_v_w, int32_t, int32_t, idx_w, ste_w) GEN_VEXT_ST_INDEX(vsxe_v_d, int64_t, int64_t, idx_d, ste_d) + +/* + *** unit-stride fault-only-fisrt load instructions + */ +static inline void +vext_ldff(void *vd, void *v0, target_ulong base, + CPURISCVState *env, uint32_t desc, + vext_ldst_elem_fn *ldst_elem, + clear_fn *clear_elem, + uint32_t esz, uint32_t msz, uintptr_t ra) +{ + void *host; + uint32_t i, k, vl = 0; + uint32_t mlen = vext_mlen(desc); + uint32_t nf = vext_nf(desc); + uint32_t vm = vext_vm(desc); + uint32_t vlmax = vext_maxsz(desc) / esz; + target_ulong addr, offset, remain; + + /* probe every access*/ + for (i = 0; i < env->vl; i++) { + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + addr = base + nf * i * msz; + if (i == 0) { + probe_pages(env, addr, nf * msz, ra, MMU_DATA_LOAD); + } else { + /* if it triggers an exception, no need to check watchpoint */ + remain = nf * msz; + while (remain > 0) { + offset = -(addr | TARGET_PAGE_MASK); + host = tlb_vaddr_to_host(env, addr, MMU_DATA_LOAD, + cpu_mmu_index(env, false)); + if (host) { +#ifdef CONFIG_USER_ONLY + if (page_check_range(addr, nf * msz, PAGE_READ) < 0) { + vl = i; + goto ProbeSuccess; + } +#else + probe_pages(env, addr, nf * msz, ra, MMU_DATA_LOAD); +#endif + } else { + vl = i; + goto ProbeSuccess; + } + if (remain <= offset) { + break; + } + remain -= offset; + addr += offset; + } + } + } +ProbeSuccess: + /* load bytes from guest memory */ + if (vl != 0) { + env->vl = vl; + } + for (i = 0; i < env->vl; i++) { + k = 0; + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + while (k < nf) { + target_ulong addr = base + (i * nf + k) * msz; + ldst_elem(env, addr, i + k * vlmax, vd, ra); + k++; + } + } + /* clear tail elements */ + if (vl != 0) { + return; + } + for (k = 0; k < nf; k++) { + clear_elem(vd, env->vl + k * vlmax, env->vl * esz, vlmax * esz); + } +} + +#define GEN_VEXT_LDFF(NAME, MTYPE, ETYPE, LOAD_FN, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong base, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + vext_ldff(vd, v0, base, env, desc, LOAD_FN, CLEAR_FN, \ + sizeof(ETYPE), sizeof(MTYPE), GETPC()); \ +} + +GEN_VEXT_LDFF(vlbff_v_b, int8_t, int8_t, ldb_b, clearb) +GEN_VEXT_LDFF(vlbff_v_h, int8_t, int16_t, ldb_h, clearh) +GEN_VEXT_LDFF(vlbff_v_w, int8_t, int32_t, ldb_w, clearl) +GEN_VEXT_LDFF(vlbff_v_d, int8_t, int64_t, ldb_d, clearq) +GEN_VEXT_LDFF(vlhff_v_h, int16_t, int16_t, ldh_h, clearh) +GEN_VEXT_LDFF(vlhff_v_w, int16_t, int32_t, ldh_w, clearl) +GEN_VEXT_LDFF(vlhff_v_d, int16_t, int64_t, ldh_d, clearq) +GEN_VEXT_LDFF(vlwff_v_w, int32_t, int32_t, ldw_w, clearl) +GEN_VEXT_LDFF(vlwff_v_d, int32_t, int64_t, ldw_d, clearq) +GEN_VEXT_LDFF(vleff_v_b, int8_t, int8_t, lde_b, clearb) +GEN_VEXT_LDFF(vleff_v_h, int16_t, int16_t, lde_h, clearh) +GEN_VEXT_LDFF(vleff_v_w, int32_t, int32_t, lde_w, clearl) +GEN_VEXT_LDFF(vleff_v_d, int64_t, int64_t, lde_d, clearq) +GEN_VEXT_LDFF(vlbuff_v_b, uint8_t, uint8_t, ldbu_b, clearb) +GEN_VEXT_LDFF(vlbuff_v_h, uint8_t, uint16_t, ldbu_h, clearh) +GEN_VEXT_LDFF(vlbuff_v_w, uint8_t, uint32_t, ldbu_w, clearl) +GEN_VEXT_LDFF(vlbuff_v_d, uint8_t, uint64_t, ldbu_d, clearq) +GEN_VEXT_LDFF(vlhuff_v_h, uint16_t, uint16_t, ldhu_h, clearh) +GEN_VEXT_LDFF(vlhuff_v_w, uint16_t, uint32_t, ldhu_w, clearl) +GEN_VEXT_LDFF(vlhuff_v_d, uint16_t, uint64_t, ldhu_d, clearq) +GEN_VEXT_LDFF(vlwuff_v_w, uint32_t, uint32_t, ldwu_w, clearl) +GEN_VEXT_LDFF(vlwuff_v_d, uint32_t, uint64_t, ldwu_d, clearq) From 268fcca66bde62257960ec8d859de374315a5e3d Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:24:57 +0800 Subject: [PATCH 1810/2595] target/riscv: add vector amo operations Vector AMOs operate as if aq and rl bits were zero on each element with regard to ordering relative to other instructions in the same hart. Vector AMOs provide no ordering guarantee between element operations in the same vector AMO instruction Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-10-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 29 +++++ target/riscv/insn32-64.decode | 11 ++ target/riscv/insn32.decode | 13 +++ target/riscv/insn_trans/trans_rvv.inc.c | 138 ++++++++++++++++++++++ target/riscv/internals.h | 1 + target/riscv/vector_helper.c | 147 ++++++++++++++++++++++++ 6 files changed, 339 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 5c97bc446e..c5f43b5b64 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -246,3 +246,32 @@ DEF_HELPER_5(vlhuff_v_w, void, ptr, ptr, tl, env, i32) DEF_HELPER_5(vlhuff_v_d, void, ptr, ptr, tl, env, i32) DEF_HELPER_5(vlwuff_v_w, void, ptr, ptr, tl, env, i32) DEF_HELPER_5(vlwuff_v_d, void, ptr, ptr, tl, env, i32) +#ifdef TARGET_RISCV64 +DEF_HELPER_6(vamoswapw_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoswapd_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoaddw_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoaddd_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoxorw_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoxord_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoandw_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoandd_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoorw_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoord_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamominw_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamomind_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamomaxw_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamomaxd_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamominuw_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamominud_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamomaxuw_v_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamomaxud_v_d, void, ptr, ptr, tl, ptr, env, i32) +#endif +DEF_HELPER_6(vamoswapw_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoaddw_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoxorw_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoandw_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamoorw_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamominw_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamomaxw_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamominuw_v_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vamomaxuw_v_w, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32-64.decode b/target/riscv/insn32-64.decode index 380bf791bc..86153d93fa 100644 --- a/target/riscv/insn32-64.decode +++ b/target/riscv/insn32-64.decode @@ -57,6 +57,17 @@ amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st +#*** Vector AMO operations (in addition to Zvamo) *** +vamoswapd_v 00001 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoaddd_v 00000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoxord_v 00100 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoandd_v 01100 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoord_v 01000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamomind_v 10000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamomaxd_v 10100 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamominud_v 11000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamomaxud_v 11100 . . ..... ..... 111 ..... 0101111 @r_wdvm + # *** RV64F Standard Extension (in addition to RV32F) *** fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 7146aec22a..625914c85f 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -44,6 +44,7 @@ &u imm rd &shift shamt rs1 rd &atomic aq rl rs2 rs1 rd +&rwdvm vm wd rd rs1 rs2 &r2nfvm vm rd rs1 nf &rnfvm vm rd rs1 rs2 nf @@ -67,6 +68,7 @@ @r2 ....... ..... ..... ... ..... ....... %rs1 %rd @r2_nfvm ... ... vm:1 ..... ..... ... ..... ....... &r2nfvm %nf %rs1 %rd @r_nfvm ... ... vm:1 ..... ..... ... ..... ....... &rnfvm %nf %rs2 %rs1 %rd +@r_wdvm ..... wd:1 vm:1 ..... ..... ... ..... ....... &rwdvm %rs2 %rs1 %rd @r2_zimm . zimm:11 ..... ... ..... ....... %rs1 %rd @hfence_gvma ....... ..... ..... ... ..... ....... %rs2 %rs1 @@ -263,6 +265,17 @@ vsxh_v ... -11 . ..... ..... 101 ..... 0100111 @r_nfvm vsxw_v ... -11 . ..... ..... 110 ..... 0100111 @r_nfvm vsxe_v ... -11 . ..... ..... 111 ..... 0100111 @r_nfvm +#*** Vector AMO operations are encoded under the standard AMO major opcode *** +vamoswapw_v 00001 . . ..... ..... 110 ..... 0101111 @r_wdvm +vamoaddw_v 00000 . . ..... ..... 110 ..... 0101111 @r_wdvm +vamoxorw_v 00100 . . ..... ..... 110 ..... 0101111 @r_wdvm +vamoandw_v 01100 . . ..... ..... 110 ..... 0101111 @r_wdvm +vamoorw_v 01000 . . ..... ..... 110 ..... 0101111 @r_wdvm +vamominw_v 10000 . . ..... ..... 110 ..... 0101111 @r_wdvm +vamomaxw_v 10100 . . ..... ..... 110 ..... 0101111 @r_wdvm +vamominuw_v 11000 . . ..... ..... 110 ..... 0101111 @r_wdvm +vamomaxuw_v 11100 . . ..... ..... 110 ..... 0101111 @r_wdvm + # *** new major opcode OP-V *** vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 5e2fbb7078..768e95c8c4 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -634,3 +634,141 @@ GEN_VEXT_TRANS(vleff_v, 3, r2nfvm, ldff_op, ld_us_check) GEN_VEXT_TRANS(vlbuff_v, 4, r2nfvm, ldff_op, ld_us_check) GEN_VEXT_TRANS(vlhuff_v, 5, r2nfvm, ldff_op, ld_us_check) GEN_VEXT_TRANS(vlwuff_v, 6, r2nfvm, ldff_op, ld_us_check) + +/* + *** vector atomic operation + */ +typedef void gen_helper_amo(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr, + TCGv_env, TCGv_i32); + +static bool amo_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, + uint32_t data, gen_helper_amo *fn, DisasContext *s) +{ + TCGv_ptr dest, mask, index; + TCGv base; + TCGv_i32 desc; + + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + dest = tcg_temp_new_ptr(); + mask = tcg_temp_new_ptr(); + index = tcg_temp_new_ptr(); + base = tcg_temp_new(); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + + gen_get_gpr(base, rs1); + tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2)); + tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + + fn(dest, mask, base, index, cpu_env, desc); + + tcg_temp_free_ptr(dest); + tcg_temp_free_ptr(mask); + tcg_temp_free_ptr(index); + tcg_temp_free(base); + tcg_temp_free_i32(desc); + gen_set_label(over); + return true; +} + +static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq) +{ + uint32_t data = 0; + gen_helper_amo *fn; + static gen_helper_amo *const fnsw[9] = { + /* no atomic operation */ + gen_helper_vamoswapw_v_w, + gen_helper_vamoaddw_v_w, + gen_helper_vamoxorw_v_w, + gen_helper_vamoandw_v_w, + gen_helper_vamoorw_v_w, + gen_helper_vamominw_v_w, + gen_helper_vamomaxw_v_w, + gen_helper_vamominuw_v_w, + gen_helper_vamomaxuw_v_w + }; +#ifdef TARGET_RISCV64 + static gen_helper_amo *const fnsd[18] = { + gen_helper_vamoswapw_v_d, + gen_helper_vamoaddw_v_d, + gen_helper_vamoxorw_v_d, + gen_helper_vamoandw_v_d, + gen_helper_vamoorw_v_d, + gen_helper_vamominw_v_d, + gen_helper_vamomaxw_v_d, + gen_helper_vamominuw_v_d, + gen_helper_vamomaxuw_v_d, + gen_helper_vamoswapd_v_d, + gen_helper_vamoaddd_v_d, + gen_helper_vamoxord_v_d, + gen_helper_vamoandd_v_d, + gen_helper_vamoord_v_d, + gen_helper_vamomind_v_d, + gen_helper_vamomaxd_v_d, + gen_helper_vamominud_v_d, + gen_helper_vamomaxud_v_d + }; +#endif + + if (tb_cflags(s->base.tb) & CF_PARALLEL) { + gen_helper_exit_atomic(cpu_env); + s->base.is_jmp = DISAS_NORETURN; + return true; + } else { + if (s->sew == 3) { +#ifdef TARGET_RISCV64 + fn = fnsd[seq]; +#else + /* Check done in amo_check(). */ + g_assert_not_reached(); +#endif + } else { + fn = fnsw[seq]; + } + } + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + data = FIELD_DP32(data, VDATA, WD, a->wd); + return amo_trans(a->rd, a->rs1, a->rs2, data, fn, s); +} +/* + * There are two rules check here. + * + * 1. SEW must be at least as wide as the AMO memory element size. + * + * 2. If SEW is greater than XLEN, an illegal instruction exception is raised. + */ +static bool amo_check(DisasContext *s, arg_rwdvm* a) +{ + return (!s->vill && has_ext(s, RVA) && + (!a->wd || vext_check_overlap_mask(s, a->rd, a->vm, false)) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + ((1 << s->sew) <= sizeof(target_ulong)) && + ((1 << s->sew) >= 4)); +} + +GEN_VEXT_TRANS(vamoswapw_v, 0, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamoaddw_v, 1, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamoxorw_v, 2, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamoandw_v, 3, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamoorw_v, 4, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamominw_v, 5, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamomaxw_v, 6, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamominuw_v, 7, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamomaxuw_v, 8, rwdvm, amo_op, amo_check) +#ifdef TARGET_RISCV64 +GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check) +GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check) +#endif diff --git a/target/riscv/internals.h b/target/riscv/internals.h index 3253e73474..e59e8b30ad 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -26,4 +26,5 @@ FIELD(VDATA, MLEN, 0, 8) FIELD(VDATA, VM, 8, 1) FIELD(VDATA, LMUL, 9, 2) FIELD(VDATA, NF, 11, 4) +FIELD(VDATA, WD, 11, 1) #endif diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index cbe87265a1..7c3b2bfd12 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -95,6 +95,11 @@ static inline uint32_t vext_lmul(uint32_t desc) return FIELD_EX32(simd_data(desc), VDATA, LMUL); } +static uint32_t vext_wd(uint32_t desc) +{ + return (simd_data(desc) >> 11) & 0x1; +} + /* * Get vector group length in bytes. Its range is [64, 2048]. * @@ -687,3 +692,145 @@ GEN_VEXT_LDFF(vlhuff_v_w, uint16_t, uint32_t, ldhu_w, clearl) GEN_VEXT_LDFF(vlhuff_v_d, uint16_t, uint64_t, ldhu_d, clearq) GEN_VEXT_LDFF(vlwuff_v_w, uint32_t, uint32_t, ldwu_w, clearl) GEN_VEXT_LDFF(vlwuff_v_d, uint32_t, uint64_t, ldwu_d, clearq) + +/* + *** Vector AMO Operations (Zvamo) + */ +typedef void vext_amo_noatomic_fn(void *vs3, target_ulong addr, + uint32_t wd, uint32_t idx, CPURISCVState *env, + uintptr_t retaddr); + +/* no atomic opreation for vector atomic insructions */ +#define DO_SWAP(N, M) (M) +#define DO_AND(N, M) (N & M) +#define DO_XOR(N, M) (N ^ M) +#define DO_OR(N, M) (N | M) +#define DO_ADD(N, M) (N + M) + +#define GEN_VEXT_AMO_NOATOMIC_OP(NAME, ESZ, MSZ, H, DO_OP, SUF) \ +static void \ +vext_##NAME##_noatomic_op(void *vs3, target_ulong addr, \ + uint32_t wd, uint32_t idx, \ + CPURISCVState *env, uintptr_t retaddr)\ +{ \ + typedef int##ESZ##_t ETYPE; \ + typedef int##MSZ##_t MTYPE; \ + typedef uint##MSZ##_t UMTYPE __attribute__((unused)); \ + ETYPE *pe3 = (ETYPE *)vs3 + H(idx); \ + MTYPE a = cpu_ld##SUF##_data(env, addr), b = *pe3; \ + \ + cpu_st##SUF##_data(env, addr, DO_OP(a, b)); \ + if (wd) { \ + *pe3 = a; \ + } \ +} + +/* Signed min/max */ +#define DO_MAX(N, M) ((N) >= (M) ? (N) : (M)) +#define DO_MIN(N, M) ((N) >= (M) ? (M) : (N)) + +/* Unsigned min/max */ +#define DO_MAXU(N, M) DO_MAX((UMTYPE)N, (UMTYPE)M) +#define DO_MINU(N, M) DO_MIN((UMTYPE)N, (UMTYPE)M) + +GEN_VEXT_AMO_NOATOMIC_OP(vamoswapw_v_w, 32, 32, H4, DO_SWAP, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamoaddw_v_w, 32, 32, H4, DO_ADD, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamoxorw_v_w, 32, 32, H4, DO_XOR, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamoandw_v_w, 32, 32, H4, DO_AND, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamoorw_v_w, 32, 32, H4, DO_OR, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamominw_v_w, 32, 32, H4, DO_MIN, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamomaxw_v_w, 32, 32, H4, DO_MAX, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamominuw_v_w, 32, 32, H4, DO_MINU, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamomaxuw_v_w, 32, 32, H4, DO_MAXU, l) +#ifdef TARGET_RISCV64 +GEN_VEXT_AMO_NOATOMIC_OP(vamoswapw_v_d, 64, 32, H8, DO_SWAP, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamoswapd_v_d, 64, 64, H8, DO_SWAP, q) +GEN_VEXT_AMO_NOATOMIC_OP(vamoaddw_v_d, 64, 32, H8, DO_ADD, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamoaddd_v_d, 64, 64, H8, DO_ADD, q) +GEN_VEXT_AMO_NOATOMIC_OP(vamoxorw_v_d, 64, 32, H8, DO_XOR, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamoxord_v_d, 64, 64, H8, DO_XOR, q) +GEN_VEXT_AMO_NOATOMIC_OP(vamoandw_v_d, 64, 32, H8, DO_AND, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamoandd_v_d, 64, 64, H8, DO_AND, q) +GEN_VEXT_AMO_NOATOMIC_OP(vamoorw_v_d, 64, 32, H8, DO_OR, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamoord_v_d, 64, 64, H8, DO_OR, q) +GEN_VEXT_AMO_NOATOMIC_OP(vamominw_v_d, 64, 32, H8, DO_MIN, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamomind_v_d, 64, 64, H8, DO_MIN, q) +GEN_VEXT_AMO_NOATOMIC_OP(vamomaxw_v_d, 64, 32, H8, DO_MAX, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamomaxd_v_d, 64, 64, H8, DO_MAX, q) +GEN_VEXT_AMO_NOATOMIC_OP(vamominuw_v_d, 64, 32, H8, DO_MINU, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamominud_v_d, 64, 64, H8, DO_MINU, q) +GEN_VEXT_AMO_NOATOMIC_OP(vamomaxuw_v_d, 64, 32, H8, DO_MAXU, l) +GEN_VEXT_AMO_NOATOMIC_OP(vamomaxud_v_d, 64, 64, H8, DO_MAXU, q) +#endif + +static inline void +vext_amo_noatomic(void *vs3, void *v0, target_ulong base, + void *vs2, CPURISCVState *env, uint32_t desc, + vext_get_index_addr get_index_addr, + vext_amo_noatomic_fn *noatomic_op, + clear_fn *clear_elem, + uint32_t esz, uint32_t msz, uintptr_t ra) +{ + uint32_t i; + target_long addr; + uint32_t wd = vext_wd(desc); + uint32_t vm = vext_vm(desc); + uint32_t mlen = vext_mlen(desc); + uint32_t vlmax = vext_maxsz(desc) / esz; + + for (i = 0; i < env->vl; i++) { + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + probe_pages(env, get_index_addr(base, i, vs2), msz, ra, MMU_DATA_LOAD); + probe_pages(env, get_index_addr(base, i, vs2), msz, ra, MMU_DATA_STORE); + } + for (i = 0; i < env->vl; i++) { + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + addr = get_index_addr(base, i, vs2); + noatomic_op(vs3, addr, wd, i, env, ra); + } + clear_elem(vs3, env->vl, env->vl * esz, vlmax * esz); +} + +#define GEN_VEXT_AMO(NAME, MTYPE, ETYPE, INDEX_FN, CLEAR_FN) \ +void HELPER(NAME)(void *vs3, void *v0, target_ulong base, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ +{ \ + vext_amo_noatomic(vs3, v0, base, vs2, env, desc, \ + INDEX_FN, vext_##NAME##_noatomic_op, \ + CLEAR_FN, sizeof(ETYPE), sizeof(MTYPE), \ + GETPC()); \ +} + +#ifdef TARGET_RISCV64 +GEN_VEXT_AMO(vamoswapw_v_d, int32_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamoswapd_v_d, int64_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamoaddw_v_d, int32_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamoaddd_v_d, int64_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamoxorw_v_d, int32_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamoxord_v_d, int64_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamoandw_v_d, int32_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamoandd_v_d, int64_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamoorw_v_d, int32_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamoord_v_d, int64_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamominw_v_d, int32_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamomind_v_d, int64_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamomaxw_v_d, int32_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamomaxd_v_d, int64_t, int64_t, idx_d, clearq) +GEN_VEXT_AMO(vamominuw_v_d, uint32_t, uint64_t, idx_d, clearq) +GEN_VEXT_AMO(vamominud_v_d, uint64_t, uint64_t, idx_d, clearq) +GEN_VEXT_AMO(vamomaxuw_v_d, uint32_t, uint64_t, idx_d, clearq) +GEN_VEXT_AMO(vamomaxud_v_d, uint64_t, uint64_t, idx_d, clearq) +#endif +GEN_VEXT_AMO(vamoswapw_v_w, int32_t, int32_t, idx_w, clearl) +GEN_VEXT_AMO(vamoaddw_v_w, int32_t, int32_t, idx_w, clearl) +GEN_VEXT_AMO(vamoxorw_v_w, int32_t, int32_t, idx_w, clearl) +GEN_VEXT_AMO(vamoandw_v_w, int32_t, int32_t, idx_w, clearl) +GEN_VEXT_AMO(vamoorw_v_w, int32_t, int32_t, idx_w, clearl) +GEN_VEXT_AMO(vamominw_v_w, int32_t, int32_t, idx_w, clearl) +GEN_VEXT_AMO(vamomaxw_v_w, int32_t, int32_t, idx_w, clearl) +GEN_VEXT_AMO(vamominuw_v_w, uint32_t, uint32_t, idx_w, clearl) +GEN_VEXT_AMO(vamomaxuw_v_w, uint32_t, uint32_t, idx_w, clearl) From 43740e3a3b3bb66456103684e622ba4e9baae297 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:24:58 +0800 Subject: [PATCH 1811/2595] target/riscv: vector single-width integer add and subtract Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-11-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 25 ++ target/riscv/insn32.decode | 10 + target/riscv/insn_trans/trans_rvv.inc.c | 291 ++++++++++++++++++++++++ target/riscv/vector_helper.c | 183 +++++++++++++++ 4 files changed, 509 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index c5f43b5b64..7660bec01f 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -275,3 +275,28 @@ DEF_HELPER_6(vamominw_v_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamomaxw_v_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamominuw_v_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamomaxuw_v_w, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vadd_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsub_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsub_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vadd_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vadd_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vadd_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vadd_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsub_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsub_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsub_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsub_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vrsub_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vrsub_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vrsub_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vrsub_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_FLAGS_4(vec_rsubs8, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vec_rsubs16, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vec_rsubs32, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vec_rsubs64, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 625914c85f..bb1e47a2be 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -44,6 +44,7 @@ &u imm rd &shift shamt rs1 rd &atomic aq rl rs2 rs1 rd +&rmrr vm rd rs1 rs2 &rwdvm vm wd rd rs1 rs2 &r2nfvm vm rd rs1 nf &rnfvm vm rd rs1 rs2 nf @@ -68,6 +69,7 @@ @r2 ....... ..... ..... ... ..... ....... %rs1 %rd @r2_nfvm ... ... vm:1 ..... ..... ... ..... ....... &r2nfvm %nf %rs1 %rd @r_nfvm ... ... vm:1 ..... ..... ... ..... ....... &rnfvm %nf %rs2 %rs1 %rd +@r_vm ...... vm:1 ..... ..... ... ..... ....... &rmrr %rs2 %rs1 %rd @r_wdvm ..... wd:1 vm:1 ..... ..... ... ..... ....... &rwdvm %rs2 %rs1 %rd @r2_zimm . zimm:11 ..... ... ..... ....... %rs1 %rd @@ -277,5 +279,13 @@ vamominuw_v 11000 . . ..... ..... 110 ..... 0101111 @r_wdvm vamomaxuw_v 11100 . . ..... ..... 110 ..... 0101111 @r_wdvm # *** new major opcode OP-V *** +vadd_vv 000000 . ..... ..... 000 ..... 1010111 @r_vm +vadd_vx 000000 . ..... ..... 100 ..... 1010111 @r_vm +vadd_vi 000000 . ..... ..... 011 ..... 1010111 @r_vm +vsub_vv 000010 . ..... ..... 000 ..... 1010111 @r_vm +vsub_vx 000010 . ..... ..... 100 ..... 1010111 @r_vm +vrsub_vx 000011 . ..... ..... 100 ..... 1010111 @r_vm +vrsub_vi 000011 . ..... ..... 011 ..... 1010111 @r_vm + vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 768e95c8c4..c2b276809a 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -772,3 +772,294 @@ GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check) #endif + +/* + *** Vector Integer Arithmetic Instructions + */ +#define MAXSZ(s) (s->vlen >> (3 - s->lmul)) + +static bool opivv_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, false) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + vext_check_reg(s, a->rs1, false)); +} + +typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t); + +static inline bool +do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, + gen_helper_gvec_4_ptr *fn) +{ + TCGLabel *over = gen_new_label(); + if (!opivv_check(s, a)) { + return false; + } + + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + if (a->vm && s->vl_eq_vlmax) { + gvec_fn(s->sew, vreg_ofs(s, a->rd), + vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1), + MAXSZ(s), MAXSZ(s)); + } else { + uint32_t data = 0; + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), + vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), + cpu_env, 0, s->vlen / 8, data, fn); + } + gen_set_label(over); + return true; +} + +/* OPIVV with GVEC IR */ +#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + static gen_helper_gvec_4_ptr * const fns[4] = { \ + gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ + }; \ + return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ +} + +GEN_OPIVV_GVEC_TRANS(vadd_vv, add) +GEN_OPIVV_GVEC_TRANS(vsub_vv, sub) + +typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr, + TCGv_env, TCGv_i32); + +static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, + gen_helper_opivx *fn, DisasContext *s) +{ + TCGv_ptr dest, src2, mask; + TCGv src1; + TCGv_i32 desc; + uint32_t data = 0; + + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + dest = tcg_temp_new_ptr(); + mask = tcg_temp_new_ptr(); + src2 = tcg_temp_new_ptr(); + src1 = tcg_temp_new(); + gen_get_gpr(src1, rs1); + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + + tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); + tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + + fn(dest, mask, src1, src2, cpu_env, desc); + + tcg_temp_free_ptr(dest); + tcg_temp_free_ptr(mask); + tcg_temp_free_ptr(src2); + tcg_temp_free(src1); + tcg_temp_free_i32(desc); + gen_set_label(over); + return true; +} + +static bool opivx_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, false) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false)); +} + +typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64, + uint32_t, uint32_t); + +static inline bool +do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn, + gen_helper_opivx *fn) +{ + if (!opivx_check(s, a)) { + return false; + } + + if (a->vm && s->vl_eq_vlmax) { + TCGv_i64 src1 = tcg_temp_new_i64(); + TCGv tmp = tcg_temp_new(); + + gen_get_gpr(tmp, a->rs1); + tcg_gen_ext_tl_i64(src1, tmp); + gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), + src1, MAXSZ(s), MAXSZ(s)); + + tcg_temp_free_i64(src1); + tcg_temp_free(tmp); + return true; + } + return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); +} + +/* OPIVX with GVEC IR */ +#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + static gen_helper_opivx * const fns[4] = { \ + gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ + }; \ + return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ +} + +GEN_OPIVX_GVEC_TRANS(vadd_vx, adds) +GEN_OPIVX_GVEC_TRANS(vsub_vx, subs) + +static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + tcg_gen_vec_sub8_i64(d, b, a); +} + +static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + tcg_gen_vec_sub8_i64(d, b, a); +} + +static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_sub_i32(ret, arg2, arg1); +} + +static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_sub_i64(ret, arg2, arg1); +} + +static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) +{ + tcg_gen_sub_vec(vece, r, b, a); +} + +static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs, + TCGv_i64 c, uint32_t oprsz, uint32_t maxsz) +{ + static const GVecGen2s rsub_op[4] = { + { .fni8 = gen_vec_rsub8_i64, + .fniv = gen_rsub_vec, + .fno = gen_helper_vec_rsubs8, + .vece = MO_8 }, + { .fni8 = gen_vec_rsub16_i64, + .fniv = gen_rsub_vec, + .fno = gen_helper_vec_rsubs16, + .vece = MO_16 }, + { .fni4 = gen_rsub_i32, + .fniv = gen_rsub_vec, + .fno = gen_helper_vec_rsubs32, + .vece = MO_32 }, + { .fni8 = gen_rsub_i64, + .fniv = gen_rsub_vec, + .fno = gen_helper_vec_rsubs64, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .vece = MO_64 }, + }; + + tcg_debug_assert(vece <= MO_64); + tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]); +} + +GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs) + +static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, + gen_helper_opivx *fn, DisasContext *s, int zx) +{ + TCGv_ptr dest, src2, mask; + TCGv src1; + TCGv_i32 desc; + uint32_t data = 0; + + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + dest = tcg_temp_new_ptr(); + mask = tcg_temp_new_ptr(); + src2 = tcg_temp_new_ptr(); + if (zx) { + src1 = tcg_const_tl(imm); + } else { + src1 = tcg_const_tl(sextract64(imm, 0, 5)); + } + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + + tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); + tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + + fn(dest, mask, src1, src2, cpu_env, desc); + + tcg_temp_free_ptr(dest); + tcg_temp_free_ptr(mask); + tcg_temp_free_ptr(src2); + tcg_temp_free(src1); + tcg_temp_free_i32(desc); + gen_set_label(over); + return true; +} + +typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t, + uint32_t, uint32_t); + +static inline bool +do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn, + gen_helper_opivx *fn, int zx) +{ + if (!opivx_check(s, a)) { + return false; + } + + if (a->vm && s->vl_eq_vlmax) { + if (zx) { + gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), + extract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s)); + } else { + gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), + sextract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s)); + } + } else { + return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, zx); + } + return true; +} + +/* OPIVI with GVEC IR */ +#define GEN_OPIVI_GVEC_TRANS(NAME, ZX, OPIVX, SUF) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + static gen_helper_opivx * const fns[4] = { \ + gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ + gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ + }; \ + return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \ + fns[s->sew], ZX); \ +} + +GEN_OPIVI_GVEC_TRANS(vadd_vi, 0, vadd_vx, addi) + +static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs, + int64_t c, uint32_t oprsz, uint32_t maxsz) +{ + TCGv_i64 tmp = tcg_const_i64(c); + tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz); + tcg_temp_free_i64(tmp); +} + +GEN_OPIVI_GVEC_TRANS(vrsub_vi, 0, vrsub_vx, rsubi) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 7c3b2bfd12..26ddc2dc6f 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -834,3 +834,186 @@ GEN_VEXT_AMO(vamominw_v_w, int32_t, int32_t, idx_w, clearl) GEN_VEXT_AMO(vamomaxw_v_w, int32_t, int32_t, idx_w, clearl) GEN_VEXT_AMO(vamominuw_v_w, uint32_t, uint32_t, idx_w, clearl) GEN_VEXT_AMO(vamomaxuw_v_w, uint32_t, uint32_t, idx_w, clearl) + +/* + *** Vector Integer Arithmetic Instructions + */ + +/* expand macro args before macro */ +#define RVVCALL(macro, ...) macro(__VA_ARGS__) + +/* (TD, T1, T2, TX1, TX2) */ +#define OP_SSS_B int8_t, int8_t, int8_t, int8_t, int8_t +#define OP_SSS_H int16_t, int16_t, int16_t, int16_t, int16_t +#define OP_SSS_W int32_t, int32_t, int32_t, int32_t, int32_t +#define OP_SSS_D int64_t, int64_t, int64_t, int64_t, int64_t + +/* operation of two vector elements */ +typedef void opivv2_fn(void *vd, void *vs1, void *vs2, int i); + +#define OPIVV2(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ +static void do_##NAME(void *vd, void *vs1, void *vs2, int i) \ +{ \ + TX1 s1 = *((T1 *)vs1 + HS1(i)); \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + *((TD *)vd + HD(i)) = OP(s2, s1); \ +} +#define DO_SUB(N, M) (N - M) +#define DO_RSUB(N, M) (M - N) + +RVVCALL(OPIVV2, vadd_vv_b, OP_SSS_B, H1, H1, H1, DO_ADD) +RVVCALL(OPIVV2, vadd_vv_h, OP_SSS_H, H2, H2, H2, DO_ADD) +RVVCALL(OPIVV2, vadd_vv_w, OP_SSS_W, H4, H4, H4, DO_ADD) +RVVCALL(OPIVV2, vadd_vv_d, OP_SSS_D, H8, H8, H8, DO_ADD) +RVVCALL(OPIVV2, vsub_vv_b, OP_SSS_B, H1, H1, H1, DO_SUB) +RVVCALL(OPIVV2, vsub_vv_h, OP_SSS_H, H2, H2, H2, DO_SUB) +RVVCALL(OPIVV2, vsub_vv_w, OP_SSS_W, H4, H4, H4, DO_SUB) +RVVCALL(OPIVV2, vsub_vv_d, OP_SSS_D, H8, H8, H8, DO_SUB) + +static void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2, + CPURISCVState *env, uint32_t desc, + uint32_t esz, uint32_t dsz, + opivv2_fn *fn, clear_fn *clearfn) +{ + uint32_t vlmax = vext_maxsz(desc) / esz; + uint32_t mlen = vext_mlen(desc); + uint32_t vm = vext_vm(desc); + uint32_t vl = env->vl; + uint32_t i; + + for (i = 0; i < vl; i++) { + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + fn(vd, vs1, vs2, i); + } + clearfn(vd, vl, vl * dsz, vlmax * dsz); +} + +/* generate the helpers for OPIVV */ +#define GEN_VEXT_VV(NAME, ESZ, DSZ, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, \ + void *vs2, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + do_vext_vv(vd, v0, vs1, vs2, env, desc, ESZ, DSZ, \ + do_##NAME, CLEAR_FN); \ +} + +GEN_VEXT_VV(vadd_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vadd_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vadd_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vadd_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vsub_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vsub_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vsub_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vsub_vv_d, 8, 8, clearq) + +typedef void opivx2_fn(void *vd, target_long s1, void *vs2, int i); + +/* + * (T1)s1 gives the real operator type. + * (TX1)(T1)s1 expands the operator type of widen or narrow operations. + */ +#define OPIVX2(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ +static void do_##NAME(void *vd, target_long s1, void *vs2, int i) \ +{ \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1); \ +} + +RVVCALL(OPIVX2, vadd_vx_b, OP_SSS_B, H1, H1, DO_ADD) +RVVCALL(OPIVX2, vadd_vx_h, OP_SSS_H, H2, H2, DO_ADD) +RVVCALL(OPIVX2, vadd_vx_w, OP_SSS_W, H4, H4, DO_ADD) +RVVCALL(OPIVX2, vadd_vx_d, OP_SSS_D, H8, H8, DO_ADD) +RVVCALL(OPIVX2, vsub_vx_b, OP_SSS_B, H1, H1, DO_SUB) +RVVCALL(OPIVX2, vsub_vx_h, OP_SSS_H, H2, H2, DO_SUB) +RVVCALL(OPIVX2, vsub_vx_w, OP_SSS_W, H4, H4, DO_SUB) +RVVCALL(OPIVX2, vsub_vx_d, OP_SSS_D, H8, H8, DO_SUB) +RVVCALL(OPIVX2, vrsub_vx_b, OP_SSS_B, H1, H1, DO_RSUB) +RVVCALL(OPIVX2, vrsub_vx_h, OP_SSS_H, H2, H2, DO_RSUB) +RVVCALL(OPIVX2, vrsub_vx_w, OP_SSS_W, H4, H4, DO_RSUB) +RVVCALL(OPIVX2, vrsub_vx_d, OP_SSS_D, H8, H8, DO_RSUB) + +static void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2, + CPURISCVState *env, uint32_t desc, + uint32_t esz, uint32_t dsz, + opivx2_fn fn, clear_fn *clearfn) +{ + uint32_t vlmax = vext_maxsz(desc) / esz; + uint32_t mlen = vext_mlen(desc); + uint32_t vm = vext_vm(desc); + uint32_t vl = env->vl; + uint32_t i; + + for (i = 0; i < vl; i++) { + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + fn(vd, s1, vs2, i); + } + clearfn(vd, vl, vl * dsz, vlmax * dsz); +} + +/* generate the helpers for OPIVX */ +#define GEN_VEXT_VX(NAME, ESZ, DSZ, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ + void *vs2, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + do_vext_vx(vd, v0, s1, vs2, env, desc, ESZ, DSZ, \ + do_##NAME, CLEAR_FN); \ +} + +GEN_VEXT_VX(vadd_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vadd_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vadd_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vadd_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vsub_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vsub_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vsub_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vsub_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vrsub_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vrsub_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vrsub_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vrsub_vx_d, 8, 8, clearq) + +void HELPER(vec_rsubs8)(void *d, void *a, uint64_t b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint8_t)) { + *(uint8_t *)(d + i) = (uint8_t)b - *(uint8_t *)(a + i); + } +} + +void HELPER(vec_rsubs16)(void *d, void *a, uint64_t b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint16_t)) { + *(uint16_t *)(d + i) = (uint16_t)b - *(uint16_t *)(a + i); + } +} + +void HELPER(vec_rsubs32)(void *d, void *a, uint64_t b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint32_t)) { + *(uint32_t *)(d + i) = (uint32_t)b - *(uint32_t *)(a + i); + } +} + +void HELPER(vec_rsubs64)(void *d, void *a, uint64_t b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint64_t)) { + *(uint64_t *)(d + i) = b - *(uint64_t *)(a + i); + } +} From 8fcdf77630290591a6068c2d82ca2935338c3b0c Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:24:59 +0800 Subject: [PATCH 1812/2595] target/riscv: vector widening integer add and subtract Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-12-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 49 +++++++ target/riscv/insn32.decode | 16 ++ target/riscv/insn_trans/trans_rvv.inc.c | 186 ++++++++++++++++++++++++ target/riscv/vector_helper.c | 111 ++++++++++++++ 4 files changed, 362 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 7660bec01f..da6acc067b 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -300,3 +300,52 @@ DEF_HELPER_FLAGS_4(vec_rsubs8, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) DEF_HELPER_FLAGS_4(vec_rsubs16, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) DEF_HELPER_FLAGS_4(vec_rsubs32, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) DEF_HELPER_FLAGS_4(vec_rsubs64, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_6(vwaddu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwaddu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwaddu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsubu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsubu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsubu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwadd_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsub_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwaddu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwaddu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwaddu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsubu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsubu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsubu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwadd_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwadd_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwadd_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsub_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsub_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsub_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwaddu_wv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwaddu_wv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwaddu_wv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsubu_wv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsubu_wv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsubu_wv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwadd_wv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwadd_wv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwadd_wv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsub_wv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsub_wv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsub_wv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwaddu_wx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwaddu_wx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwaddu_wx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsubu_wx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsubu_wx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsubu_wx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwadd_wx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwadd_wx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwadd_wx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsub_wx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsub_wx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsub_wx_w, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index bb1e47a2be..6ec166d0ed 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -286,6 +286,22 @@ vsub_vv 000010 . ..... ..... 000 ..... 1010111 @r_vm vsub_vx 000010 . ..... ..... 100 ..... 1010111 @r_vm vrsub_vx 000011 . ..... ..... 100 ..... 1010111 @r_vm vrsub_vi 000011 . ..... ..... 011 ..... 1010111 @r_vm +vwaddu_vv 110000 . ..... ..... 010 ..... 1010111 @r_vm +vwaddu_vx 110000 . ..... ..... 110 ..... 1010111 @r_vm +vwadd_vv 110001 . ..... ..... 010 ..... 1010111 @r_vm +vwadd_vx 110001 . ..... ..... 110 ..... 1010111 @r_vm +vwsubu_vv 110010 . ..... ..... 010 ..... 1010111 @r_vm +vwsubu_vx 110010 . ..... ..... 110 ..... 1010111 @r_vm +vwsub_vv 110011 . ..... ..... 010 ..... 1010111 @r_vm +vwsub_vx 110011 . ..... ..... 110 ..... 1010111 @r_vm +vwaddu_wv 110100 . ..... ..... 010 ..... 1010111 @r_vm +vwaddu_wx 110100 . ..... ..... 110 ..... 1010111 @r_vm +vwadd_wv 110101 . ..... ..... 010 ..... 1010111 @r_vm +vwadd_wx 110101 . ..... ..... 110 ..... 1010111 @r_vm +vwsubu_wv 110110 . ..... ..... 010 ..... 1010111 @r_vm +vwsubu_wx 110110 . ..... ..... 110 ..... 1010111 @r_vm +vwsub_wv 110111 . ..... ..... 010 ..... 1010111 @r_vm +vwsub_wx 110111 . ..... ..... 110 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index c2b276809a..850df9df66 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -138,6 +138,14 @@ static bool vext_check_nf(DisasContext *s, uint32_t nf) return (1 << s->lmul) * nf <= 8; } +/* + * The destination vector register group cannot overlap a source vector register + * group of a different element width. (Section 11.2) + */ +static inline bool vext_check_overlap_group(int rd, int dlen, int rs, int slen) +{ + return ((rd >= rs + slen) || (rs >= rd + dlen)); +} /* common translation macro */ #define GEN_VEXT_TRANS(NAME, SEQ, ARGTYPE, OP, CHECK) \ static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE *a)\ @@ -1063,3 +1071,181 @@ static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs, } GEN_OPIVI_GVEC_TRANS(vrsub_vi, 0, vrsub_vx, rsubi) + +/* Vector Widening Integer Add/Subtract */ + +/* OPIVV with WIDEN */ +static bool opivv_widen_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, true) && + vext_check_reg(s, a->rs2, false) && + vext_check_reg(s, a->rs1, false) && + vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, + 1 << s->lmul) && + vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, + 1 << s->lmul) && + (s->lmul < 0x3) && (s->sew < 0x3)); +} + +static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, + gen_helper_gvec_4_ptr *fn, + bool (*checkfn)(DisasContext *, arg_rmrr *)) +{ + if (checkfn(s, a)) { + uint32_t data = 0; + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), + vreg_ofs(s, a->rs1), + vreg_ofs(s, a->rs2), + cpu_env, 0, s->vlen / 8, + data, fn); + gen_set_label(over); + return true; + } + return false; +} + +#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + static gen_helper_gvec_4_ptr * const fns[3] = { \ + gen_helper_##NAME##_b, \ + gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w \ + }; \ + return do_opivv_widen(s, a, fns[s->sew], CHECK); \ +} + +GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check) + +/* OPIVX with WIDEN */ +static bool opivx_widen_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, true) && + vext_check_reg(s, a->rs2, false) && + vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, + 1 << s->lmul) && + (s->lmul < 0x3) && (s->sew < 0x3)); +} + +static bool do_opivx_widen(DisasContext *s, arg_rmrr *a, + gen_helper_opivx *fn) +{ + if (opivx_widen_check(s, a)) { + return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); + } + return true; +} + +#define GEN_OPIVX_WIDEN_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + static gen_helper_opivx * const fns[3] = { \ + gen_helper_##NAME##_b, \ + gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w \ + }; \ + return do_opivx_widen(s, a, fns[s->sew]); \ +} + +GEN_OPIVX_WIDEN_TRANS(vwaddu_vx) +GEN_OPIVX_WIDEN_TRANS(vwadd_vx) +GEN_OPIVX_WIDEN_TRANS(vwsubu_vx) +GEN_OPIVX_WIDEN_TRANS(vwsub_vx) + +/* WIDEN OPIVV with WIDEN */ +static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, true) && + vext_check_reg(s, a->rs2, true) && + vext_check_reg(s, a->rs1, false) && + vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, + 1 << s->lmul) && + (s->lmul < 0x3) && (s->sew < 0x3)); +} + +static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, + gen_helper_gvec_4_ptr *fn) +{ + if (opiwv_widen_check(s, a)) { + uint32_t data = 0; + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), + vreg_ofs(s, a->rs1), + vreg_ofs(s, a->rs2), + cpu_env, 0, s->vlen / 8, data, fn); + gen_set_label(over); + return true; + } + return false; +} + +#define GEN_OPIWV_WIDEN_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + static gen_helper_gvec_4_ptr * const fns[3] = { \ + gen_helper_##NAME##_b, \ + gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w \ + }; \ + return do_opiwv_widen(s, a, fns[s->sew]); \ +} + +GEN_OPIWV_WIDEN_TRANS(vwaddu_wv) +GEN_OPIWV_WIDEN_TRANS(vwadd_wv) +GEN_OPIWV_WIDEN_TRANS(vwsubu_wv) +GEN_OPIWV_WIDEN_TRANS(vwsub_wv) + +/* WIDEN OPIVX with WIDEN */ +static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, true) && + vext_check_reg(s, a->rs2, true) && + (s->lmul < 0x3) && (s->sew < 0x3)); +} + +static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a, + gen_helper_opivx *fn) +{ + if (opiwx_widen_check(s, a)) { + return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); + } + return false; +} + +#define GEN_OPIWX_WIDEN_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + static gen_helper_opivx * const fns[3] = { \ + gen_helper_##NAME##_b, \ + gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w \ + }; \ + return do_opiwx_widen(s, a, fns[s->sew]); \ +} + +GEN_OPIWX_WIDEN_TRANS(vwaddu_wx) +GEN_OPIWX_WIDEN_TRANS(vwadd_wx) +GEN_OPIWX_WIDEN_TRANS(vwsubu_wx) +GEN_OPIWX_WIDEN_TRANS(vwsub_wx) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 26ddc2dc6f..06435ed82a 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -1017,3 +1017,114 @@ void HELPER(vec_rsubs64)(void *d, void *a, uint64_t b, uint32_t desc) *(uint64_t *)(d + i) = b - *(uint64_t *)(a + i); } } + +/* Vector Widening Integer Add/Subtract */ +#define WOP_UUU_B uint16_t, uint8_t, uint8_t, uint16_t, uint16_t +#define WOP_UUU_H uint32_t, uint16_t, uint16_t, uint32_t, uint32_t +#define WOP_UUU_W uint64_t, uint32_t, uint32_t, uint64_t, uint64_t +#define WOP_SSS_B int16_t, int8_t, int8_t, int16_t, int16_t +#define WOP_SSS_H int32_t, int16_t, int16_t, int32_t, int32_t +#define WOP_SSS_W int64_t, int32_t, int32_t, int64_t, int64_t +#define WOP_WUUU_B uint16_t, uint8_t, uint16_t, uint16_t, uint16_t +#define WOP_WUUU_H uint32_t, uint16_t, uint32_t, uint32_t, uint32_t +#define WOP_WUUU_W uint64_t, uint32_t, uint64_t, uint64_t, uint64_t +#define WOP_WSSS_B int16_t, int8_t, int16_t, int16_t, int16_t +#define WOP_WSSS_H int32_t, int16_t, int32_t, int32_t, int32_t +#define WOP_WSSS_W int64_t, int32_t, int64_t, int64_t, int64_t +RVVCALL(OPIVV2, vwaddu_vv_b, WOP_UUU_B, H2, H1, H1, DO_ADD) +RVVCALL(OPIVV2, vwaddu_vv_h, WOP_UUU_H, H4, H2, H2, DO_ADD) +RVVCALL(OPIVV2, vwaddu_vv_w, WOP_UUU_W, H8, H4, H4, DO_ADD) +RVVCALL(OPIVV2, vwsubu_vv_b, WOP_UUU_B, H2, H1, H1, DO_SUB) +RVVCALL(OPIVV2, vwsubu_vv_h, WOP_UUU_H, H4, H2, H2, DO_SUB) +RVVCALL(OPIVV2, vwsubu_vv_w, WOP_UUU_W, H8, H4, H4, DO_SUB) +RVVCALL(OPIVV2, vwadd_vv_b, WOP_SSS_B, H2, H1, H1, DO_ADD) +RVVCALL(OPIVV2, vwadd_vv_h, WOP_SSS_H, H4, H2, H2, DO_ADD) +RVVCALL(OPIVV2, vwadd_vv_w, WOP_SSS_W, H8, H4, H4, DO_ADD) +RVVCALL(OPIVV2, vwsub_vv_b, WOP_SSS_B, H2, H1, H1, DO_SUB) +RVVCALL(OPIVV2, vwsub_vv_h, WOP_SSS_H, H4, H2, H2, DO_SUB) +RVVCALL(OPIVV2, vwsub_vv_w, WOP_SSS_W, H8, H4, H4, DO_SUB) +RVVCALL(OPIVV2, vwaddu_wv_b, WOP_WUUU_B, H2, H1, H1, DO_ADD) +RVVCALL(OPIVV2, vwaddu_wv_h, WOP_WUUU_H, H4, H2, H2, DO_ADD) +RVVCALL(OPIVV2, vwaddu_wv_w, WOP_WUUU_W, H8, H4, H4, DO_ADD) +RVVCALL(OPIVV2, vwsubu_wv_b, WOP_WUUU_B, H2, H1, H1, DO_SUB) +RVVCALL(OPIVV2, vwsubu_wv_h, WOP_WUUU_H, H4, H2, H2, DO_SUB) +RVVCALL(OPIVV2, vwsubu_wv_w, WOP_WUUU_W, H8, H4, H4, DO_SUB) +RVVCALL(OPIVV2, vwadd_wv_b, WOP_WSSS_B, H2, H1, H1, DO_ADD) +RVVCALL(OPIVV2, vwadd_wv_h, WOP_WSSS_H, H4, H2, H2, DO_ADD) +RVVCALL(OPIVV2, vwadd_wv_w, WOP_WSSS_W, H8, H4, H4, DO_ADD) +RVVCALL(OPIVV2, vwsub_wv_b, WOP_WSSS_B, H2, H1, H1, DO_SUB) +RVVCALL(OPIVV2, vwsub_wv_h, WOP_WSSS_H, H4, H2, H2, DO_SUB) +RVVCALL(OPIVV2, vwsub_wv_w, WOP_WSSS_W, H8, H4, H4, DO_SUB) +GEN_VEXT_VV(vwaddu_vv_b, 1, 2, clearh) +GEN_VEXT_VV(vwaddu_vv_h, 2, 4, clearl) +GEN_VEXT_VV(vwaddu_vv_w, 4, 8, clearq) +GEN_VEXT_VV(vwsubu_vv_b, 1, 2, clearh) +GEN_VEXT_VV(vwsubu_vv_h, 2, 4, clearl) +GEN_VEXT_VV(vwsubu_vv_w, 4, 8, clearq) +GEN_VEXT_VV(vwadd_vv_b, 1, 2, clearh) +GEN_VEXT_VV(vwadd_vv_h, 2, 4, clearl) +GEN_VEXT_VV(vwadd_vv_w, 4, 8, clearq) +GEN_VEXT_VV(vwsub_vv_b, 1, 2, clearh) +GEN_VEXT_VV(vwsub_vv_h, 2, 4, clearl) +GEN_VEXT_VV(vwsub_vv_w, 4, 8, clearq) +GEN_VEXT_VV(vwaddu_wv_b, 1, 2, clearh) +GEN_VEXT_VV(vwaddu_wv_h, 2, 4, clearl) +GEN_VEXT_VV(vwaddu_wv_w, 4, 8, clearq) +GEN_VEXT_VV(vwsubu_wv_b, 1, 2, clearh) +GEN_VEXT_VV(vwsubu_wv_h, 2, 4, clearl) +GEN_VEXT_VV(vwsubu_wv_w, 4, 8, clearq) +GEN_VEXT_VV(vwadd_wv_b, 1, 2, clearh) +GEN_VEXT_VV(vwadd_wv_h, 2, 4, clearl) +GEN_VEXT_VV(vwadd_wv_w, 4, 8, clearq) +GEN_VEXT_VV(vwsub_wv_b, 1, 2, clearh) +GEN_VEXT_VV(vwsub_wv_h, 2, 4, clearl) +GEN_VEXT_VV(vwsub_wv_w, 4, 8, clearq) + +RVVCALL(OPIVX2, vwaddu_vx_b, WOP_UUU_B, H2, H1, DO_ADD) +RVVCALL(OPIVX2, vwaddu_vx_h, WOP_UUU_H, H4, H2, DO_ADD) +RVVCALL(OPIVX2, vwaddu_vx_w, WOP_UUU_W, H8, H4, DO_ADD) +RVVCALL(OPIVX2, vwsubu_vx_b, WOP_UUU_B, H2, H1, DO_SUB) +RVVCALL(OPIVX2, vwsubu_vx_h, WOP_UUU_H, H4, H2, DO_SUB) +RVVCALL(OPIVX2, vwsubu_vx_w, WOP_UUU_W, H8, H4, DO_SUB) +RVVCALL(OPIVX2, vwadd_vx_b, WOP_SSS_B, H2, H1, DO_ADD) +RVVCALL(OPIVX2, vwadd_vx_h, WOP_SSS_H, H4, H2, DO_ADD) +RVVCALL(OPIVX2, vwadd_vx_w, WOP_SSS_W, H8, H4, DO_ADD) +RVVCALL(OPIVX2, vwsub_vx_b, WOP_SSS_B, H2, H1, DO_SUB) +RVVCALL(OPIVX2, vwsub_vx_h, WOP_SSS_H, H4, H2, DO_SUB) +RVVCALL(OPIVX2, vwsub_vx_w, WOP_SSS_W, H8, H4, DO_SUB) +RVVCALL(OPIVX2, vwaddu_wx_b, WOP_WUUU_B, H2, H1, DO_ADD) +RVVCALL(OPIVX2, vwaddu_wx_h, WOP_WUUU_H, H4, H2, DO_ADD) +RVVCALL(OPIVX2, vwaddu_wx_w, WOP_WUUU_W, H8, H4, DO_ADD) +RVVCALL(OPIVX2, vwsubu_wx_b, WOP_WUUU_B, H2, H1, DO_SUB) +RVVCALL(OPIVX2, vwsubu_wx_h, WOP_WUUU_H, H4, H2, DO_SUB) +RVVCALL(OPIVX2, vwsubu_wx_w, WOP_WUUU_W, H8, H4, DO_SUB) +RVVCALL(OPIVX2, vwadd_wx_b, WOP_WSSS_B, H2, H1, DO_ADD) +RVVCALL(OPIVX2, vwadd_wx_h, WOP_WSSS_H, H4, H2, DO_ADD) +RVVCALL(OPIVX2, vwadd_wx_w, WOP_WSSS_W, H8, H4, DO_ADD) +RVVCALL(OPIVX2, vwsub_wx_b, WOP_WSSS_B, H2, H1, DO_SUB) +RVVCALL(OPIVX2, vwsub_wx_h, WOP_WSSS_H, H4, H2, DO_SUB) +RVVCALL(OPIVX2, vwsub_wx_w, WOP_WSSS_W, H8, H4, DO_SUB) +GEN_VEXT_VX(vwaddu_vx_b, 1, 2, clearh) +GEN_VEXT_VX(vwaddu_vx_h, 2, 4, clearl) +GEN_VEXT_VX(vwaddu_vx_w, 4, 8, clearq) +GEN_VEXT_VX(vwsubu_vx_b, 1, 2, clearh) +GEN_VEXT_VX(vwsubu_vx_h, 2, 4, clearl) +GEN_VEXT_VX(vwsubu_vx_w, 4, 8, clearq) +GEN_VEXT_VX(vwadd_vx_b, 1, 2, clearh) +GEN_VEXT_VX(vwadd_vx_h, 2, 4, clearl) +GEN_VEXT_VX(vwadd_vx_w, 4, 8, clearq) +GEN_VEXT_VX(vwsub_vx_b, 1, 2, clearh) +GEN_VEXT_VX(vwsub_vx_h, 2, 4, clearl) +GEN_VEXT_VX(vwsub_vx_w, 4, 8, clearq) +GEN_VEXT_VX(vwaddu_wx_b, 1, 2, clearh) +GEN_VEXT_VX(vwaddu_wx_h, 2, 4, clearl) +GEN_VEXT_VX(vwaddu_wx_w, 4, 8, clearq) +GEN_VEXT_VX(vwsubu_wx_b, 1, 2, clearh) +GEN_VEXT_VX(vwsubu_wx_h, 2, 4, clearl) +GEN_VEXT_VX(vwsubu_wx_w, 4, 8, clearq) +GEN_VEXT_VX(vwadd_wx_b, 1, 2, clearh) +GEN_VEXT_VX(vwadd_wx_h, 2, 4, clearl) +GEN_VEXT_VX(vwadd_wx_w, 4, 8, clearq) +GEN_VEXT_VX(vwsub_wx_b, 1, 2, clearh) +GEN_VEXT_VX(vwsub_wx_h, 2, 4, clearl) +GEN_VEXT_VX(vwsub_wx_w, 4, 8, clearq) From 3a6f8f68ad2f4a22d9ae8287f336b5dcc80b6448 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:00 +0800 Subject: [PATCH 1813/2595] target/riscv: vector integer add-with-carry / subtract-with-borrow instructions Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-13-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 33 ++++++ target/riscv/insn32.decode | 11 ++ target/riscv/insn_trans/trans_rvv.inc.c | 113 +++++++++++++++++++ target/riscv/vector_helper.c | 137 ++++++++++++++++++++++++ 4 files changed, 294 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index da6acc067b..67a2e64c4a 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -349,3 +349,36 @@ DEF_HELPER_6(vwadd_wx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwsub_wx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwsub_wx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwsub_wx_w, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vadc_vvm_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vadc_vvm_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vadc_vvm_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vadc_vvm_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsbc_vvm_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsbc_vvm_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsbc_vvm_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsbc_vvm_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmadc_vvm_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmadc_vvm_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmadc_vvm_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmadc_vvm_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsbc_vvm_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsbc_vvm_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsbc_vvm_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsbc_vvm_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vadc_vxm_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vadc_vxm_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vadc_vxm_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vadc_vxm_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsbc_vxm_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsbc_vxm_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsbc_vxm_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsbc_vxm_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmadc_vxm_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmadc_vxm_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmadc_vxm_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmadc_vxm_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsbc_vxm_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsbc_vxm_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsbc_vxm_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsbc_vxm_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 6ec166d0ed..be63e900c6 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -70,6 +70,7 @@ @r2_nfvm ... ... vm:1 ..... ..... ... ..... ....... &r2nfvm %nf %rs1 %rd @r_nfvm ... ... vm:1 ..... ..... ... ..... ....... &rnfvm %nf %rs2 %rs1 %rd @r_vm ...... vm:1 ..... ..... ... ..... ....... &rmrr %rs2 %rs1 %rd +@r_vm_1 ...... . ..... ..... ... ..... ....... &rmrr vm=1 %rs2 %rs1 %rd @r_wdvm ..... wd:1 vm:1 ..... ..... ... ..... ....... &rwdvm %rs2 %rs1 %rd @r2_zimm . zimm:11 ..... ... ..... ....... %rs1 %rd @@ -302,6 +303,16 @@ vwsubu_wv 110110 . ..... ..... 010 ..... 1010111 @r_vm vwsubu_wx 110110 . ..... ..... 110 ..... 1010111 @r_vm vwsub_wv 110111 . ..... ..... 010 ..... 1010111 @r_vm vwsub_wx 110111 . ..... ..... 110 ..... 1010111 @r_vm +vadc_vvm 010000 1 ..... ..... 000 ..... 1010111 @r_vm_1 +vadc_vxm 010000 1 ..... ..... 100 ..... 1010111 @r_vm_1 +vadc_vim 010000 1 ..... ..... 011 ..... 1010111 @r_vm_1 +vmadc_vvm 010001 1 ..... ..... 000 ..... 1010111 @r_vm_1 +vmadc_vxm 010001 1 ..... ..... 100 ..... 1010111 @r_vm_1 +vmadc_vim 010001 1 ..... ..... 011 ..... 1010111 @r_vm_1 +vsbc_vvm 010010 1 ..... ..... 000 ..... 1010111 @r_vm_1 +vsbc_vxm 010010 1 ..... ..... 100 ..... 1010111 @r_vm_1 +vmsbc_vvm 010011 1 ..... ..... 000 ..... 1010111 @r_vm_1 +vmsbc_vxm 010011 1 ..... ..... 100 ..... 1010111 @r_vm_1 vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 850df9df66..98bd5bcb79 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1249,3 +1249,116 @@ GEN_OPIWX_WIDEN_TRANS(vwaddu_wx) GEN_OPIWX_WIDEN_TRANS(vwadd_wx) GEN_OPIWX_WIDEN_TRANS(vwsubu_wx) GEN_OPIWX_WIDEN_TRANS(vwsub_wx) + +/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */ +/* OPIVV without GVEC IR */ +#define GEN_OPIVV_TRANS(NAME, CHECK) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (CHECK(s, a)) { \ + uint32_t data = 0; \ + static gen_helper_gvec_4_ptr * const fns[4] = { \ + gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ + }; \ + TCGLabel *over = gen_new_label(); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ + vreg_ofs(s, a->rs1), \ + vreg_ofs(s, a->rs2), cpu_env, 0, \ + s->vlen / 8, data, fns[s->sew]); \ + gen_set_label(over); \ + return true; \ + } \ + return false; \ +} + +/* + * For vadc and vsbc, an illegal instruction exception is raised if the + * destination vector register is v0 and LMUL > 1. (Section 12.3) + */ +static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + vext_check_reg(s, a->rs1, false) && + ((a->rd != 0) || (s->lmul == 0))); +} + +GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check) +GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check) + +/* + * For vmadc and vmsbc, an illegal instruction exception is raised if the + * destination vector register overlaps a source vector register group. + */ +static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rs2, false) && + vext_check_reg(s, a->rs1, false) && + vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && + vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)); +} + +GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check) +GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check) + +static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + ((a->rd != 0) || (s->lmul == 0))); +} + +/* OPIVX without GVEC IR */ +#define GEN_OPIVX_TRANS(NAME, CHECK) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (CHECK(s, a)) { \ + static gen_helper_opivx * const fns[4] = { \ + gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ + }; \ + \ + return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ + } \ + return false; \ +} + +GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check) +GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check) + +static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rs2, false) && + vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)); +} + +GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check) +GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check) + +/* OPIVI without GVEC IR */ +#define GEN_OPIVI_TRANS(NAME, ZX, OPIVX, CHECK) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (CHECK(s, a)) { \ + static gen_helper_opivx * const fns[4] = { \ + gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ + gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ + }; \ + return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ + fns[s->sew], s, ZX); \ + } \ + return false; \ +} + +GEN_OPIVI_TRANS(vadc_vim, 0, vadc_vxm, opivx_vadc_check) +GEN_OPIVI_TRANS(vmadc_vim, 0, vmadc_vxm, opivx_vmadc_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 06435ed82a..e152641b4f 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -187,6 +187,14 @@ static void clearq(void *vd, uint32_t idx, uint32_t cnt, uint32_t tot) vext_clear(cur, cnt, tot); } +static inline void vext_set_elem_mask(void *v0, int mlen, int index, + uint8_t value) +{ + int idx = (index * mlen) / 64; + int pos = (index * mlen) % 64; + uint64_t old = ((uint64_t *)v0)[idx]; + ((uint64_t *)v0)[idx] = deposit64(old, pos, mlen, value); +} static inline int vext_elem_mask(void *v0, int mlen, int index) { @@ -1128,3 +1136,132 @@ GEN_VEXT_VX(vwadd_wx_w, 4, 8, clearq) GEN_VEXT_VX(vwsub_wx_b, 1, 2, clearh) GEN_VEXT_VX(vwsub_wx_h, 2, 4, clearl) GEN_VEXT_VX(vwsub_wx_w, 4, 8, clearq) + +/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */ +#define DO_VADC(N, M, C) (N + M + C) +#define DO_VSBC(N, M, C) (N - M - C) + +#define GEN_VEXT_VADC_VVM(NAME, ETYPE, H, DO_OP, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t vlmax = vext_maxsz(desc) / esz; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ + ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ + uint8_t carry = vext_elem_mask(v0, mlen, i); \ + \ + *((ETYPE *)vd + H(i)) = DO_OP(s2, s1, carry); \ + } \ + CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \ +} + +GEN_VEXT_VADC_VVM(vadc_vvm_b, uint8_t, H1, DO_VADC, clearb) +GEN_VEXT_VADC_VVM(vadc_vvm_h, uint16_t, H2, DO_VADC, clearh) +GEN_VEXT_VADC_VVM(vadc_vvm_w, uint32_t, H4, DO_VADC, clearl) +GEN_VEXT_VADC_VVM(vadc_vvm_d, uint64_t, H8, DO_VADC, clearq) + +GEN_VEXT_VADC_VVM(vsbc_vvm_b, uint8_t, H1, DO_VSBC, clearb) +GEN_VEXT_VADC_VVM(vsbc_vvm_h, uint16_t, H2, DO_VSBC, clearh) +GEN_VEXT_VADC_VVM(vsbc_vvm_w, uint32_t, H4, DO_VSBC, clearl) +GEN_VEXT_VADC_VVM(vsbc_vvm_d, uint64_t, H8, DO_VSBC, clearq) + +#define GEN_VEXT_VADC_VXM(NAME, ETYPE, H, DO_OP, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t vlmax = vext_maxsz(desc) / esz; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ + uint8_t carry = vext_elem_mask(v0, mlen, i); \ + \ + *((ETYPE *)vd + H(i)) = DO_OP(s2, (ETYPE)(target_long)s1, carry);\ + } \ + CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \ +} + +GEN_VEXT_VADC_VXM(vadc_vxm_b, uint8_t, H1, DO_VADC, clearb) +GEN_VEXT_VADC_VXM(vadc_vxm_h, uint16_t, H2, DO_VADC, clearh) +GEN_VEXT_VADC_VXM(vadc_vxm_w, uint32_t, H4, DO_VADC, clearl) +GEN_VEXT_VADC_VXM(vadc_vxm_d, uint64_t, H8, DO_VADC, clearq) + +GEN_VEXT_VADC_VXM(vsbc_vxm_b, uint8_t, H1, DO_VSBC, clearb) +GEN_VEXT_VADC_VXM(vsbc_vxm_h, uint16_t, H2, DO_VSBC, clearh) +GEN_VEXT_VADC_VXM(vsbc_vxm_w, uint32_t, H4, DO_VSBC, clearl) +GEN_VEXT_VADC_VXM(vsbc_vxm_d, uint64_t, H8, DO_VSBC, clearq) + +#define DO_MADC(N, M, C) (C ? (__typeof(N))(N + M + 1) <= N : \ + (__typeof(N))(N + M) < N) +#define DO_MSBC(N, M, C) (C ? N <= M : N < M) + +#define GEN_VEXT_VMADC_VVM(NAME, ETYPE, H, DO_OP) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vl = env->vl; \ + uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ + ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ + uint8_t carry = vext_elem_mask(v0, mlen, i); \ + \ + vext_set_elem_mask(vd, mlen, i, DO_OP(s2, s1, carry));\ + } \ + for (; i < vlmax; i++) { \ + vext_set_elem_mask(vd, mlen, i, 0); \ + } \ +} + +GEN_VEXT_VMADC_VVM(vmadc_vvm_b, uint8_t, H1, DO_MADC) +GEN_VEXT_VMADC_VVM(vmadc_vvm_h, uint16_t, H2, DO_MADC) +GEN_VEXT_VMADC_VVM(vmadc_vvm_w, uint32_t, H4, DO_MADC) +GEN_VEXT_VMADC_VVM(vmadc_vvm_d, uint64_t, H8, DO_MADC) + +GEN_VEXT_VMADC_VVM(vmsbc_vvm_b, uint8_t, H1, DO_MSBC) +GEN_VEXT_VMADC_VVM(vmsbc_vvm_h, uint16_t, H2, DO_MSBC) +GEN_VEXT_VMADC_VVM(vmsbc_vvm_w, uint32_t, H4, DO_MSBC) +GEN_VEXT_VMADC_VVM(vmsbc_vvm_d, uint64_t, H8, DO_MSBC) + +#define GEN_VEXT_VMADC_VXM(NAME, ETYPE, H, DO_OP) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vl = env->vl; \ + uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ + uint8_t carry = vext_elem_mask(v0, mlen, i); \ + \ + vext_set_elem_mask(vd, mlen, i, \ + DO_OP(s2, (ETYPE)(target_long)s1, carry)); \ + } \ + for (; i < vlmax; i++) { \ + vext_set_elem_mask(vd, mlen, i, 0); \ + } \ +} + +GEN_VEXT_VMADC_VXM(vmadc_vxm_b, uint8_t, H1, DO_MADC) +GEN_VEXT_VMADC_VXM(vmadc_vxm_h, uint16_t, H2, DO_MADC) +GEN_VEXT_VMADC_VXM(vmadc_vxm_w, uint32_t, H4, DO_MADC) +GEN_VEXT_VMADC_VXM(vmadc_vxm_d, uint64_t, H8, DO_MADC) + +GEN_VEXT_VMADC_VXM(vmsbc_vxm_b, uint8_t, H1, DO_MSBC) +GEN_VEXT_VMADC_VXM(vmsbc_vxm_h, uint16_t, H2, DO_MSBC) +GEN_VEXT_VMADC_VXM(vmsbc_vxm_w, uint32_t, H4, DO_MSBC) +GEN_VEXT_VMADC_VXM(vmsbc_vxm_d, uint64_t, H8, DO_MSBC) From d3842924cf93d104f691c5ea9090d6700ccef281 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:01 +0800 Subject: [PATCH 1814/2595] target/riscv: vector bitwise logical instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-14-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 25 ++++++++++++ target/riscv/insn32.decode | 9 +++++ target/riscv/insn_trans/trans_rvv.inc.c | 11 ++++++ target/riscv/vector_helper.c | 51 +++++++++++++++++++++++++ 4 files changed, 96 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 67a2e64c4a..f8b1c8a800 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -382,3 +382,28 @@ DEF_HELPER_6(vmsbc_vxm_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmsbc_vxm_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmsbc_vxm_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmsbc_vxm_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vand_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vand_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vand_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vand_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vor_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vor_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vor_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vor_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vxor_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vxor_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vxor_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vxor_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vand_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vand_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vand_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vand_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vor_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vor_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vor_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vor_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vxor_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vxor_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vxor_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vxor_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index be63e900c6..34d05a5917 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -313,6 +313,15 @@ vsbc_vvm 010010 1 ..... ..... 000 ..... 1010111 @r_vm_1 vsbc_vxm 010010 1 ..... ..... 100 ..... 1010111 @r_vm_1 vmsbc_vvm 010011 1 ..... ..... 000 ..... 1010111 @r_vm_1 vmsbc_vxm 010011 1 ..... ..... 100 ..... 1010111 @r_vm_1 +vand_vv 001001 . ..... ..... 000 ..... 1010111 @r_vm +vand_vx 001001 . ..... ..... 100 ..... 1010111 @r_vm +vand_vi 001001 . ..... ..... 011 ..... 1010111 @r_vm +vor_vv 001010 . ..... ..... 000 ..... 1010111 @r_vm +vor_vx 001010 . ..... ..... 100 ..... 1010111 @r_vm +vor_vi 001010 . ..... ..... 011 ..... 1010111 @r_vm +vxor_vv 001011 . ..... ..... 000 ..... 1010111 @r_vm +vxor_vx 001011 . ..... ..... 100 ..... 1010111 @r_vm +vxor_vi 001011 . ..... ..... 011 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 98bd5bcb79..1552534796 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1362,3 +1362,14 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ GEN_OPIVI_TRANS(vadc_vim, 0, vadc_vxm, opivx_vadc_check) GEN_OPIVI_TRANS(vmadc_vim, 0, vmadc_vxm, opivx_vmadc_check) + +/* Vector Bitwise Logical Instructions */ +GEN_OPIVV_GVEC_TRANS(vand_vv, and) +GEN_OPIVV_GVEC_TRANS(vor_vv, or) +GEN_OPIVV_GVEC_TRANS(vxor_vv, xor) +GEN_OPIVX_GVEC_TRANS(vand_vx, ands) +GEN_OPIVX_GVEC_TRANS(vor_vx, ors) +GEN_OPIVX_GVEC_TRANS(vxor_vx, xors) +GEN_OPIVI_GVEC_TRANS(vand_vi, 0, vand_vx, andi) +GEN_OPIVI_GVEC_TRANS(vor_vi, 0, vor_vx, ori) +GEN_OPIVI_GVEC_TRANS(vxor_vi, 0, vxor_vx, xori) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index e152641b4f..bd77de110e 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -1265,3 +1265,54 @@ GEN_VEXT_VMADC_VXM(vmsbc_vxm_b, uint8_t, H1, DO_MSBC) GEN_VEXT_VMADC_VXM(vmsbc_vxm_h, uint16_t, H2, DO_MSBC) GEN_VEXT_VMADC_VXM(vmsbc_vxm_w, uint32_t, H4, DO_MSBC) GEN_VEXT_VMADC_VXM(vmsbc_vxm_d, uint64_t, H8, DO_MSBC) + +/* Vector Bitwise Logical Instructions */ +RVVCALL(OPIVV2, vand_vv_b, OP_SSS_B, H1, H1, H1, DO_AND) +RVVCALL(OPIVV2, vand_vv_h, OP_SSS_H, H2, H2, H2, DO_AND) +RVVCALL(OPIVV2, vand_vv_w, OP_SSS_W, H4, H4, H4, DO_AND) +RVVCALL(OPIVV2, vand_vv_d, OP_SSS_D, H8, H8, H8, DO_AND) +RVVCALL(OPIVV2, vor_vv_b, OP_SSS_B, H1, H1, H1, DO_OR) +RVVCALL(OPIVV2, vor_vv_h, OP_SSS_H, H2, H2, H2, DO_OR) +RVVCALL(OPIVV2, vor_vv_w, OP_SSS_W, H4, H4, H4, DO_OR) +RVVCALL(OPIVV2, vor_vv_d, OP_SSS_D, H8, H8, H8, DO_OR) +RVVCALL(OPIVV2, vxor_vv_b, OP_SSS_B, H1, H1, H1, DO_XOR) +RVVCALL(OPIVV2, vxor_vv_h, OP_SSS_H, H2, H2, H2, DO_XOR) +RVVCALL(OPIVV2, vxor_vv_w, OP_SSS_W, H4, H4, H4, DO_XOR) +RVVCALL(OPIVV2, vxor_vv_d, OP_SSS_D, H8, H8, H8, DO_XOR) +GEN_VEXT_VV(vand_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vand_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vand_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vand_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vor_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vor_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vor_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vor_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vxor_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vxor_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vxor_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vxor_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2, vand_vx_b, OP_SSS_B, H1, H1, DO_AND) +RVVCALL(OPIVX2, vand_vx_h, OP_SSS_H, H2, H2, DO_AND) +RVVCALL(OPIVX2, vand_vx_w, OP_SSS_W, H4, H4, DO_AND) +RVVCALL(OPIVX2, vand_vx_d, OP_SSS_D, H8, H8, DO_AND) +RVVCALL(OPIVX2, vor_vx_b, OP_SSS_B, H1, H1, DO_OR) +RVVCALL(OPIVX2, vor_vx_h, OP_SSS_H, H2, H2, DO_OR) +RVVCALL(OPIVX2, vor_vx_w, OP_SSS_W, H4, H4, DO_OR) +RVVCALL(OPIVX2, vor_vx_d, OP_SSS_D, H8, H8, DO_OR) +RVVCALL(OPIVX2, vxor_vx_b, OP_SSS_B, H1, H1, DO_XOR) +RVVCALL(OPIVX2, vxor_vx_h, OP_SSS_H, H2, H2, DO_XOR) +RVVCALL(OPIVX2, vxor_vx_w, OP_SSS_W, H4, H4, DO_XOR) +RVVCALL(OPIVX2, vxor_vx_d, OP_SSS_D, H8, H8, DO_XOR) +GEN_VEXT_VX(vand_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vand_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vand_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vand_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vor_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vor_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vor_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vor_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vxor_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vxor_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vxor_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vxor_vx_d, 8, 8, clearq) From 3277d955d21d8943d80062b4cfd8547f831dbd51 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:02 +0800 Subject: [PATCH 1815/2595] target/riscv: vector single-width bit shift instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-15-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 25 ++++++++ target/riscv/insn32.decode | 9 +++ target/riscv/insn_trans/trans_rvv.inc.c | 52 ++++++++++++++++ target/riscv/vector_helper.c | 79 +++++++++++++++++++++++++ 4 files changed, 165 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index f8b1c8a800..6805bf7dbd 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -407,3 +407,28 @@ DEF_HELPER_6(vxor_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vxor_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vxor_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vxor_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vsll_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsll_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsll_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsll_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsrl_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsrl_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsrl_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsrl_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsra_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsra_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsra_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsra_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsll_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsll_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsll_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsll_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsrl_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsrl_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsrl_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsrl_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsra_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsra_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsra_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsra_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 34d05a5917..e5334230df 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -322,6 +322,15 @@ vor_vi 001010 . ..... ..... 011 ..... 1010111 @r_vm vxor_vv 001011 . ..... ..... 000 ..... 1010111 @r_vm vxor_vx 001011 . ..... ..... 100 ..... 1010111 @r_vm vxor_vi 001011 . ..... ..... 011 ..... 1010111 @r_vm +vsll_vv 100101 . ..... ..... 000 ..... 1010111 @r_vm +vsll_vx 100101 . ..... ..... 100 ..... 1010111 @r_vm +vsll_vi 100101 . ..... ..... 011 ..... 1010111 @r_vm +vsrl_vv 101000 . ..... ..... 000 ..... 1010111 @r_vm +vsrl_vx 101000 . ..... ..... 100 ..... 1010111 @r_vm +vsrl_vi 101000 . ..... ..... 011 ..... 1010111 @r_vm +vsra_vv 101001 . ..... ..... 000 ..... 1010111 @r_vm +vsra_vx 101001 . ..... ..... 100 ..... 1010111 @r_vm +vsra_vi 101001 . ..... ..... 011 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 1552534796..d2dbf701c8 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1373,3 +1373,55 @@ GEN_OPIVX_GVEC_TRANS(vxor_vx, xors) GEN_OPIVI_GVEC_TRANS(vand_vi, 0, vand_vx, andi) GEN_OPIVI_GVEC_TRANS(vor_vi, 0, vor_vx, ori) GEN_OPIVI_GVEC_TRANS(vxor_vi, 0, vxor_vx, xori) + +/* Vector Single-Width Bit Shift Instructions */ +GEN_OPIVV_GVEC_TRANS(vsll_vv, shlv) +GEN_OPIVV_GVEC_TRANS(vsrl_vv, shrv) +GEN_OPIVV_GVEC_TRANS(vsra_vv, sarv) + +typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32, + uint32_t, uint32_t); + +static inline bool +do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn, + gen_helper_opivx *fn) +{ + if (!opivx_check(s, a)) { + return false; + } + + if (a->vm && s->vl_eq_vlmax) { + TCGv_i32 src1 = tcg_temp_new_i32(); + TCGv tmp = tcg_temp_new(); + + gen_get_gpr(tmp, a->rs1); + tcg_gen_trunc_tl_i32(src1, tmp); + tcg_gen_extract_i32(src1, src1, 0, s->sew + 3); + gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), + src1, MAXSZ(s), MAXSZ(s)); + + tcg_temp_free_i32(src1); + tcg_temp_free(tmp); + return true; + } + return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); +} + +#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + static gen_helper_opivx * const fns[4] = { \ + gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ + }; \ + \ + return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ +} + +GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx, shls) +GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx, shrs) +GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx, sars) + +GEN_OPIVI_GVEC_TRANS(vsll_vi, 1, vsll_vx, shli) +GEN_OPIVI_GVEC_TRANS(vsrl_vi, 1, vsrl_vx, shri) +GEN_OPIVI_GVEC_TRANS(vsra_vi, 1, vsra_vx, sari) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index bd77de110e..cd81f86faf 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -1316,3 +1316,82 @@ GEN_VEXT_VX(vxor_vx_b, 1, 1, clearb) GEN_VEXT_VX(vxor_vx_h, 2, 2, clearh) GEN_VEXT_VX(vxor_vx_w, 4, 4, clearl) GEN_VEXT_VX(vxor_vx_d, 8, 8, clearq) + +/* Vector Single-Width Bit Shift Instructions */ +#define DO_SLL(N, M) (N << (M)) +#define DO_SRL(N, M) (N >> (M)) + +/* generate the helpers for shift instructions with two vector operators */ +#define GEN_VEXT_SHIFT_VV(NAME, TS1, TS2, HS1, HS2, OP, MASK, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t esz = sizeof(TS1); \ + uint32_t vlmax = vext_maxsz(desc) / esz; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + TS1 s1 = *((TS1 *)vs1 + HS1(i)); \ + TS2 s2 = *((TS2 *)vs2 + HS2(i)); \ + *((TS1 *)vd + HS1(i)) = OP(s2, s1 & MASK); \ + } \ + CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \ +} + +GEN_VEXT_SHIFT_VV(vsll_vv_b, uint8_t, uint8_t, H1, H1, DO_SLL, 0x7, clearb) +GEN_VEXT_SHIFT_VV(vsll_vv_h, uint16_t, uint16_t, H2, H2, DO_SLL, 0xf, clearh) +GEN_VEXT_SHIFT_VV(vsll_vv_w, uint32_t, uint32_t, H4, H4, DO_SLL, 0x1f, clearl) +GEN_VEXT_SHIFT_VV(vsll_vv_d, uint64_t, uint64_t, H8, H8, DO_SLL, 0x3f, clearq) + +GEN_VEXT_SHIFT_VV(vsrl_vv_b, uint8_t, uint8_t, H1, H1, DO_SRL, 0x7, clearb) +GEN_VEXT_SHIFT_VV(vsrl_vv_h, uint16_t, uint16_t, H2, H2, DO_SRL, 0xf, clearh) +GEN_VEXT_SHIFT_VV(vsrl_vv_w, uint32_t, uint32_t, H4, H4, DO_SRL, 0x1f, clearl) +GEN_VEXT_SHIFT_VV(vsrl_vv_d, uint64_t, uint64_t, H8, H8, DO_SRL, 0x3f, clearq) + +GEN_VEXT_SHIFT_VV(vsra_vv_b, uint8_t, int8_t, H1, H1, DO_SRL, 0x7, clearb) +GEN_VEXT_SHIFT_VV(vsra_vv_h, uint16_t, int16_t, H2, H2, DO_SRL, 0xf, clearh) +GEN_VEXT_SHIFT_VV(vsra_vv_w, uint32_t, int32_t, H4, H4, DO_SRL, 0x1f, clearl) +GEN_VEXT_SHIFT_VV(vsra_vv_d, uint64_t, int64_t, H8, H8, DO_SRL, 0x3f, clearq) + +/* generate the helpers for shift instructions with one vector and one scalar */ +#define GEN_VEXT_SHIFT_VX(NAME, TD, TS2, HD, HS2, OP, MASK, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t esz = sizeof(TD); \ + uint32_t vlmax = vext_maxsz(desc) / esz; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + TS2 s2 = *((TS2 *)vs2 + HS2(i)); \ + *((TD *)vd + HD(i)) = OP(s2, s1 & MASK); \ + } \ + CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \ +} + +GEN_VEXT_SHIFT_VX(vsll_vx_b, uint8_t, int8_t, H1, H1, DO_SLL, 0x7, clearb) +GEN_VEXT_SHIFT_VX(vsll_vx_h, uint16_t, int16_t, H2, H2, DO_SLL, 0xf, clearh) +GEN_VEXT_SHIFT_VX(vsll_vx_w, uint32_t, int32_t, H4, H4, DO_SLL, 0x1f, clearl) +GEN_VEXT_SHIFT_VX(vsll_vx_d, uint64_t, int64_t, H8, H8, DO_SLL, 0x3f, clearq) + +GEN_VEXT_SHIFT_VX(vsrl_vx_b, uint8_t, uint8_t, H1, H1, DO_SRL, 0x7, clearb) +GEN_VEXT_SHIFT_VX(vsrl_vx_h, uint16_t, uint16_t, H2, H2, DO_SRL, 0xf, clearh) +GEN_VEXT_SHIFT_VX(vsrl_vx_w, uint32_t, uint32_t, H4, H4, DO_SRL, 0x1f, clearl) +GEN_VEXT_SHIFT_VX(vsrl_vx_d, uint64_t, uint64_t, H8, H8, DO_SRL, 0x3f, clearq) + +GEN_VEXT_SHIFT_VX(vsra_vx_b, int8_t, int8_t, H1, H1, DO_SRL, 0x7, clearb) +GEN_VEXT_SHIFT_VX(vsra_vx_h, int16_t, int16_t, H2, H2, DO_SRL, 0xf, clearh) +GEN_VEXT_SHIFT_VX(vsra_vx_w, int32_t, int32_t, H4, H4, DO_SRL, 0x1f, clearl) +GEN_VEXT_SHIFT_VX(vsra_vx_d, int64_t, int64_t, H8, H8, DO_SRL, 0x3f, clearq) From 7689b028ca56268fde3d492038413582b494c489 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:03 +0800 Subject: [PATCH 1816/2595] target/riscv: vector narrowing integer right shift instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-16-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 13 ++++ target/riscv/insn32.decode | 6 ++ target/riscv/insn_trans/trans_rvv.inc.c | 90 +++++++++++++++++++++++++ target/riscv/vector_helper.c | 14 ++++ 4 files changed, 123 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 6805bf7dbd..1ec2202814 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -432,3 +432,16 @@ DEF_HELPER_6(vsra_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vsra_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vsra_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vsra_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vnsrl_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnsrl_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnsrl_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnsra_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnsra_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnsra_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnsrl_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnsrl_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnsrl_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnsra_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnsra_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnsra_vx_w, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index e5334230df..435415f9f9 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -331,6 +331,12 @@ vsrl_vi 101000 . ..... ..... 011 ..... 1010111 @r_vm vsra_vv 101001 . ..... ..... 000 ..... 1010111 @r_vm vsra_vx 101001 . ..... ..... 100 ..... 1010111 @r_vm vsra_vi 101001 . ..... ..... 011 ..... 1010111 @r_vm +vnsrl_vv 101100 . ..... ..... 000 ..... 1010111 @r_vm +vnsrl_vx 101100 . ..... ..... 100 ..... 1010111 @r_vm +vnsrl_vi 101100 . ..... ..... 011 ..... 1010111 @r_vm +vnsra_vv 101101 . ..... ..... 000 ..... 1010111 @r_vm +vnsra_vx 101101 . ..... ..... 100 ..... 1010111 @r_vm +vnsra_vi 101101 . ..... ..... 011 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index d2dbf701c8..9d2c327366 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1425,3 +1425,93 @@ GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx, sars) GEN_OPIVI_GVEC_TRANS(vsll_vi, 1, vsll_vx, shli) GEN_OPIVI_GVEC_TRANS(vsrl_vi, 1, vsrl_vx, shri) GEN_OPIVI_GVEC_TRANS(vsra_vi, 1, vsra_vx, sari) + +/* Vector Narrowing Integer Right Shift Instructions */ +static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, false) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, true) && + vext_check_reg(s, a->rs1, false) && + vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, + 2 << s->lmul) && + (s->lmul < 0x3) && (s->sew < 0x3)); +} + +/* OPIVV with NARROW */ +#define GEN_OPIVV_NARROW_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (opivv_narrow_check(s, a)) { \ + uint32_t data = 0; \ + static gen_helper_gvec_4_ptr * const fns[3] = { \ + gen_helper_##NAME##_b, \ + gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, \ + }; \ + TCGLabel *over = gen_new_label(); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ + vreg_ofs(s, a->rs1), \ + vreg_ofs(s, a->rs2), cpu_env, 0, \ + s->vlen / 8, data, fns[s->sew]); \ + gen_set_label(over); \ + return true; \ + } \ + return false; \ +} +GEN_OPIVV_NARROW_TRANS(vnsra_vv) +GEN_OPIVV_NARROW_TRANS(vnsrl_vv) + +static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, false) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, true) && + vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, + 2 << s->lmul) && + (s->lmul < 0x3) && (s->sew < 0x3)); +} + +/* OPIVX with NARROW */ +#define GEN_OPIVX_NARROW_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (opivx_narrow_check(s, a)) { \ + static gen_helper_opivx * const fns[3] = { \ + gen_helper_##NAME##_b, \ + gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, \ + }; \ + return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ + } \ + return false; \ +} + +GEN_OPIVX_NARROW_TRANS(vnsra_vx) +GEN_OPIVX_NARROW_TRANS(vnsrl_vx) + +/* OPIVI with NARROW */ +#define GEN_OPIVI_NARROW_TRANS(NAME, ZX, OPIVX) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (opivx_narrow_check(s, a)) { \ + static gen_helper_opivx * const fns[3] = { \ + gen_helper_##OPIVX##_b, \ + gen_helper_##OPIVX##_h, \ + gen_helper_##OPIVX##_w, \ + }; \ + return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ + fns[s->sew], s, ZX); \ + } \ + return false; \ +} + +GEN_OPIVI_NARROW_TRANS(vnsra_vi, 1, vnsra_vx) +GEN_OPIVI_NARROW_TRANS(vnsrl_vi, 1, vnsrl_vx) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index cd81f86faf..96e3467353 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -1395,3 +1395,17 @@ GEN_VEXT_SHIFT_VX(vsra_vx_b, int8_t, int8_t, H1, H1, DO_SRL, 0x7, clearb) GEN_VEXT_SHIFT_VX(vsra_vx_h, int16_t, int16_t, H2, H2, DO_SRL, 0xf, clearh) GEN_VEXT_SHIFT_VX(vsra_vx_w, int32_t, int32_t, H4, H4, DO_SRL, 0x1f, clearl) GEN_VEXT_SHIFT_VX(vsra_vx_d, int64_t, int64_t, H8, H8, DO_SRL, 0x3f, clearq) + +/* Vector Narrowing Integer Right Shift Instructions */ +GEN_VEXT_SHIFT_VV(vnsrl_vv_b, uint8_t, uint16_t, H1, H2, DO_SRL, 0xf, clearb) +GEN_VEXT_SHIFT_VV(vnsrl_vv_h, uint16_t, uint32_t, H2, H4, DO_SRL, 0x1f, clearh) +GEN_VEXT_SHIFT_VV(vnsrl_vv_w, uint32_t, uint64_t, H4, H8, DO_SRL, 0x3f, clearl) +GEN_VEXT_SHIFT_VV(vnsra_vv_b, uint8_t, int16_t, H1, H2, DO_SRL, 0xf, clearb) +GEN_VEXT_SHIFT_VV(vnsra_vv_h, uint16_t, int32_t, H2, H4, DO_SRL, 0x1f, clearh) +GEN_VEXT_SHIFT_VV(vnsra_vv_w, uint32_t, int64_t, H4, H8, DO_SRL, 0x3f, clearl) +GEN_VEXT_SHIFT_VX(vnsrl_vx_b, uint8_t, uint16_t, H1, H2, DO_SRL, 0xf, clearb) +GEN_VEXT_SHIFT_VX(vnsrl_vx_h, uint16_t, uint32_t, H2, H4, DO_SRL, 0x1f, clearh) +GEN_VEXT_SHIFT_VX(vnsrl_vx_w, uint32_t, uint64_t, H4, H8, DO_SRL, 0x3f, clearl) +GEN_VEXT_SHIFT_VX(vnsra_vx_b, int8_t, int16_t, H1, H2, DO_SRL, 0xf, clearb) +GEN_VEXT_SHIFT_VX(vnsra_vx_h, int16_t, int32_t, H2, H4, DO_SRL, 0x1f, clearh) +GEN_VEXT_SHIFT_VX(vnsra_vx_w, int32_t, int64_t, H4, H8, DO_SRL, 0x3f, clearl) From 1366fc79be04fa56a0e3f078ba4f26c27ac67e89 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:04 +0800 Subject: [PATCH 1817/2595] target/riscv: vector integer comparison instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-17-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 57 +++++++++++ target/riscv/insn32.decode | 20 ++++ target/riscv/insn_trans/trans_rvv.inc.c | 46 +++++++++ target/riscv/vector_helper.c | 123 ++++++++++++++++++++++++ 4 files changed, 246 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 1ec2202814..2bcb6c7889 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -445,3 +445,60 @@ DEF_HELPER_6(vnsrl_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vnsra_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vnsra_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vnsra_vx_w, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vmseq_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmseq_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmseq_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmseq_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsne_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsne_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsne_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsne_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsltu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsltu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsltu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsltu_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmslt_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmslt_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmslt_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmslt_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsleu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsleu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsleu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsleu_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsle_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsle_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsle_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmsle_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmseq_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmseq_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmseq_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmseq_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsne_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsne_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsne_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsne_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsltu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsltu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsltu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsltu_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmslt_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmslt_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmslt_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmslt_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsleu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsleu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsleu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsleu_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsle_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsle_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsle_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsle_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsgtu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsgtu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsgtu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsgtu_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsgt_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsgt_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsgt_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmsgt_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 435415f9f9..5d022ff414 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -337,6 +337,26 @@ vnsrl_vi 101100 . ..... ..... 011 ..... 1010111 @r_vm vnsra_vv 101101 . ..... ..... 000 ..... 1010111 @r_vm vnsra_vx 101101 . ..... ..... 100 ..... 1010111 @r_vm vnsra_vi 101101 . ..... ..... 011 ..... 1010111 @r_vm +vmseq_vv 011000 . ..... ..... 000 ..... 1010111 @r_vm +vmseq_vx 011000 . ..... ..... 100 ..... 1010111 @r_vm +vmseq_vi 011000 . ..... ..... 011 ..... 1010111 @r_vm +vmsne_vv 011001 . ..... ..... 000 ..... 1010111 @r_vm +vmsne_vx 011001 . ..... ..... 100 ..... 1010111 @r_vm +vmsne_vi 011001 . ..... ..... 011 ..... 1010111 @r_vm +vmsltu_vv 011010 . ..... ..... 000 ..... 1010111 @r_vm +vmsltu_vx 011010 . ..... ..... 100 ..... 1010111 @r_vm +vmslt_vv 011011 . ..... ..... 000 ..... 1010111 @r_vm +vmslt_vx 011011 . ..... ..... 100 ..... 1010111 @r_vm +vmsleu_vv 011100 . ..... ..... 000 ..... 1010111 @r_vm +vmsleu_vx 011100 . ..... ..... 100 ..... 1010111 @r_vm +vmsleu_vi 011100 . ..... ..... 011 ..... 1010111 @r_vm +vmsle_vv 011101 . ..... ..... 000 ..... 1010111 @r_vm +vmsle_vx 011101 . ..... ..... 100 ..... 1010111 @r_vm +vmsle_vi 011101 . ..... ..... 011 ..... 1010111 @r_vm +vmsgtu_vx 011110 . ..... ..... 100 ..... 1010111 @r_vm +vmsgtu_vi 011110 . ..... ..... 011 ..... 1010111 @r_vm +vmsgt_vx 011111 . ..... ..... 100 ..... 1010111 @r_vm +vmsgt_vi 011111 . ..... ..... 011 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 9d2c327366..7d7e3d4cd8 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1515,3 +1515,49 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ GEN_OPIVI_NARROW_TRANS(vnsra_vi, 1, vnsra_vx) GEN_OPIVI_NARROW_TRANS(vnsrl_vi, 1, vnsrl_vx) + +/* Vector Integer Comparison Instructions */ +/* + * For all comparison instructions, an illegal instruction exception is raised + * if the destination vector register overlaps a source vector register group + * and LMUL > 1. + */ +static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rs2, false) && + vext_check_reg(s, a->rs1, false) && + ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && + vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) || + (s->lmul == 0))); +} +GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check) +GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check) +GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check) +GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check) +GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check) +GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check) + +static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rs2, false) && + (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) || + (s->lmul == 0))); +} + +GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check) +GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check) +GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check) +GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check) +GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check) +GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check) +GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check) +GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check) + +GEN_OPIVI_TRANS(vmseq_vi, 0, vmseq_vx, opivx_cmp_check) +GEN_OPIVI_TRANS(vmsne_vi, 0, vmsne_vx, opivx_cmp_check) +GEN_OPIVI_TRANS(vmsleu_vi, 1, vmsleu_vx, opivx_cmp_check) +GEN_OPIVI_TRANS(vmsle_vi, 0, vmsle_vx, opivx_cmp_check) +GEN_OPIVI_TRANS(vmsgtu_vi, 1, vmsgtu_vx, opivx_cmp_check) +GEN_OPIVI_TRANS(vmsgt_vi, 0, vmsgt_vx, opivx_cmp_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 96e3467353..71f27146b3 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -1409,3 +1409,126 @@ GEN_VEXT_SHIFT_VX(vnsrl_vx_w, uint32_t, uint64_t, H4, H8, DO_SRL, 0x3f, clearl) GEN_VEXT_SHIFT_VX(vnsra_vx_b, int8_t, int16_t, H1, H2, DO_SRL, 0xf, clearb) GEN_VEXT_SHIFT_VX(vnsra_vx_h, int16_t, int32_t, H2, H4, DO_SRL, 0x1f, clearh) GEN_VEXT_SHIFT_VX(vnsra_vx_w, int32_t, int64_t, H4, H8, DO_SRL, 0x3f, clearl) + +/* Vector Integer Comparison Instructions */ +#define DO_MSEQ(N, M) (N == M) +#define DO_MSNE(N, M) (N != M) +#define DO_MSLT(N, M) (N < M) +#define DO_MSLE(N, M) (N <= M) +#define DO_MSGT(N, M) (N > M) + +#define GEN_VEXT_CMP_VV(NAME, ETYPE, H, DO_OP) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ + ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + vext_set_elem_mask(vd, mlen, i, DO_OP(s2, s1)); \ + } \ + for (; i < vlmax; i++) { \ + vext_set_elem_mask(vd, mlen, i, 0); \ + } \ +} + +GEN_VEXT_CMP_VV(vmseq_vv_b, uint8_t, H1, DO_MSEQ) +GEN_VEXT_CMP_VV(vmseq_vv_h, uint16_t, H2, DO_MSEQ) +GEN_VEXT_CMP_VV(vmseq_vv_w, uint32_t, H4, DO_MSEQ) +GEN_VEXT_CMP_VV(vmseq_vv_d, uint64_t, H8, DO_MSEQ) + +GEN_VEXT_CMP_VV(vmsne_vv_b, uint8_t, H1, DO_MSNE) +GEN_VEXT_CMP_VV(vmsne_vv_h, uint16_t, H2, DO_MSNE) +GEN_VEXT_CMP_VV(vmsne_vv_w, uint32_t, H4, DO_MSNE) +GEN_VEXT_CMP_VV(vmsne_vv_d, uint64_t, H8, DO_MSNE) + +GEN_VEXT_CMP_VV(vmsltu_vv_b, uint8_t, H1, DO_MSLT) +GEN_VEXT_CMP_VV(vmsltu_vv_h, uint16_t, H2, DO_MSLT) +GEN_VEXT_CMP_VV(vmsltu_vv_w, uint32_t, H4, DO_MSLT) +GEN_VEXT_CMP_VV(vmsltu_vv_d, uint64_t, H8, DO_MSLT) + +GEN_VEXT_CMP_VV(vmslt_vv_b, int8_t, H1, DO_MSLT) +GEN_VEXT_CMP_VV(vmslt_vv_h, int16_t, H2, DO_MSLT) +GEN_VEXT_CMP_VV(vmslt_vv_w, int32_t, H4, DO_MSLT) +GEN_VEXT_CMP_VV(vmslt_vv_d, int64_t, H8, DO_MSLT) + +GEN_VEXT_CMP_VV(vmsleu_vv_b, uint8_t, H1, DO_MSLE) +GEN_VEXT_CMP_VV(vmsleu_vv_h, uint16_t, H2, DO_MSLE) +GEN_VEXT_CMP_VV(vmsleu_vv_w, uint32_t, H4, DO_MSLE) +GEN_VEXT_CMP_VV(vmsleu_vv_d, uint64_t, H8, DO_MSLE) + +GEN_VEXT_CMP_VV(vmsle_vv_b, int8_t, H1, DO_MSLE) +GEN_VEXT_CMP_VV(vmsle_vv_h, int16_t, H2, DO_MSLE) +GEN_VEXT_CMP_VV(vmsle_vv_w, int32_t, H4, DO_MSLE) +GEN_VEXT_CMP_VV(vmsle_vv_d, int64_t, H8, DO_MSLE) + +#define GEN_VEXT_CMP_VX(NAME, ETYPE, H, DO_OP) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + vext_set_elem_mask(vd, mlen, i, \ + DO_OP(s2, (ETYPE)(target_long)s1)); \ + } \ + for (; i < vlmax; i++) { \ + vext_set_elem_mask(vd, mlen, i, 0); \ + } \ +} + +GEN_VEXT_CMP_VX(vmseq_vx_b, uint8_t, H1, DO_MSEQ) +GEN_VEXT_CMP_VX(vmseq_vx_h, uint16_t, H2, DO_MSEQ) +GEN_VEXT_CMP_VX(vmseq_vx_w, uint32_t, H4, DO_MSEQ) +GEN_VEXT_CMP_VX(vmseq_vx_d, uint64_t, H8, DO_MSEQ) + +GEN_VEXT_CMP_VX(vmsne_vx_b, uint8_t, H1, DO_MSNE) +GEN_VEXT_CMP_VX(vmsne_vx_h, uint16_t, H2, DO_MSNE) +GEN_VEXT_CMP_VX(vmsne_vx_w, uint32_t, H4, DO_MSNE) +GEN_VEXT_CMP_VX(vmsne_vx_d, uint64_t, H8, DO_MSNE) + +GEN_VEXT_CMP_VX(vmsltu_vx_b, uint8_t, H1, DO_MSLT) +GEN_VEXT_CMP_VX(vmsltu_vx_h, uint16_t, H2, DO_MSLT) +GEN_VEXT_CMP_VX(vmsltu_vx_w, uint32_t, H4, DO_MSLT) +GEN_VEXT_CMP_VX(vmsltu_vx_d, uint64_t, H8, DO_MSLT) + +GEN_VEXT_CMP_VX(vmslt_vx_b, int8_t, H1, DO_MSLT) +GEN_VEXT_CMP_VX(vmslt_vx_h, int16_t, H2, DO_MSLT) +GEN_VEXT_CMP_VX(vmslt_vx_w, int32_t, H4, DO_MSLT) +GEN_VEXT_CMP_VX(vmslt_vx_d, int64_t, H8, DO_MSLT) + +GEN_VEXT_CMP_VX(vmsleu_vx_b, uint8_t, H1, DO_MSLE) +GEN_VEXT_CMP_VX(vmsleu_vx_h, uint16_t, H2, DO_MSLE) +GEN_VEXT_CMP_VX(vmsleu_vx_w, uint32_t, H4, DO_MSLE) +GEN_VEXT_CMP_VX(vmsleu_vx_d, uint64_t, H8, DO_MSLE) + +GEN_VEXT_CMP_VX(vmsle_vx_b, int8_t, H1, DO_MSLE) +GEN_VEXT_CMP_VX(vmsle_vx_h, int16_t, H2, DO_MSLE) +GEN_VEXT_CMP_VX(vmsle_vx_w, int32_t, H4, DO_MSLE) +GEN_VEXT_CMP_VX(vmsle_vx_d, int64_t, H8, DO_MSLE) + +GEN_VEXT_CMP_VX(vmsgtu_vx_b, uint8_t, H1, DO_MSGT) +GEN_VEXT_CMP_VX(vmsgtu_vx_h, uint16_t, H2, DO_MSGT) +GEN_VEXT_CMP_VX(vmsgtu_vx_w, uint32_t, H4, DO_MSGT) +GEN_VEXT_CMP_VX(vmsgtu_vx_d, uint64_t, H8, DO_MSGT) + +GEN_VEXT_CMP_VX(vmsgt_vx_b, int8_t, H1, DO_MSGT) +GEN_VEXT_CMP_VX(vmsgt_vx_h, int16_t, H2, DO_MSGT) +GEN_VEXT_CMP_VX(vmsgt_vx_w, int32_t, H4, DO_MSGT) +GEN_VEXT_CMP_VX(vmsgt_vx_d, int64_t, H8, DO_MSGT) From 558fa7797c919c4f21ac10980f3ed28160d6d3cb Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:05 +0800 Subject: [PATCH 1818/2595] target/riscv: vector integer min/max instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-18-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 33 ++++++++++++ target/riscv/insn32.decode | 8 +++ target/riscv/insn_trans/trans_rvv.inc.c | 10 ++++ target/riscv/vector_helper.c | 71 +++++++++++++++++++++++++ 4 files changed, 122 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 2bcb6c7889..9c576e1220 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -502,3 +502,36 @@ DEF_HELPER_6(vmsgt_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmsgt_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmsgt_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmsgt_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vminu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vminu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vminu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vminu_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmin_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmin_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmin_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmin_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmaxu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmaxu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmaxu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmaxu_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmax_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmax_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmax_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmax_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vminu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vminu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vminu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vminu_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmin_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmin_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmin_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmin_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmaxu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmaxu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmaxu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmaxu_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmax_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmax_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmax_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmax_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 5d022ff414..3d8986c74d 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -357,6 +357,14 @@ vmsgtu_vx 011110 . ..... ..... 100 ..... 1010111 @r_vm vmsgtu_vi 011110 . ..... ..... 011 ..... 1010111 @r_vm vmsgt_vx 011111 . ..... ..... 100 ..... 1010111 @r_vm vmsgt_vi 011111 . ..... ..... 011 ..... 1010111 @r_vm +vminu_vv 000100 . ..... ..... 000 ..... 1010111 @r_vm +vminu_vx 000100 . ..... ..... 100 ..... 1010111 @r_vm +vmin_vv 000101 . ..... ..... 000 ..... 1010111 @r_vm +vmin_vx 000101 . ..... ..... 100 ..... 1010111 @r_vm +vmaxu_vv 000110 . ..... ..... 000 ..... 1010111 @r_vm +vmaxu_vx 000110 . ..... ..... 100 ..... 1010111 @r_vm +vmax_vv 000111 . ..... ..... 000 ..... 1010111 @r_vm +vmax_vx 000111 . ..... ..... 100 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 7d7e3d4cd8..861fd3bf1a 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1561,3 +1561,13 @@ GEN_OPIVI_TRANS(vmsleu_vi, 1, vmsleu_vx, opivx_cmp_check) GEN_OPIVI_TRANS(vmsle_vi, 0, vmsle_vx, opivx_cmp_check) GEN_OPIVI_TRANS(vmsgtu_vi, 1, vmsgtu_vx, opivx_cmp_check) GEN_OPIVI_TRANS(vmsgt_vi, 0, vmsgt_vx, opivx_cmp_check) + +/* Vector Integer Min/Max Instructions */ +GEN_OPIVV_GVEC_TRANS(vminu_vv, umin) +GEN_OPIVV_GVEC_TRANS(vmin_vv, smin) +GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax) +GEN_OPIVV_GVEC_TRANS(vmax_vv, smax) +GEN_OPIVX_TRANS(vminu_vx, opivx_check) +GEN_OPIVX_TRANS(vmin_vx, opivx_check) +GEN_OPIVX_TRANS(vmaxu_vx, opivx_check) +GEN_OPIVX_TRANS(vmax_vx, opivx_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 71f27146b3..b1ff767209 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -855,6 +855,10 @@ GEN_VEXT_AMO(vamomaxuw_v_w, uint32_t, uint32_t, idx_w, clearl) #define OP_SSS_H int16_t, int16_t, int16_t, int16_t, int16_t #define OP_SSS_W int32_t, int32_t, int32_t, int32_t, int32_t #define OP_SSS_D int64_t, int64_t, int64_t, int64_t, int64_t +#define OP_UUU_B uint8_t, uint8_t, uint8_t, uint8_t, uint8_t +#define OP_UUU_H uint16_t, uint16_t, uint16_t, uint16_t, uint16_t +#define OP_UUU_W uint32_t, uint32_t, uint32_t, uint32_t, uint32_t +#define OP_UUU_D uint64_t, uint64_t, uint64_t, uint64_t, uint64_t /* operation of two vector elements */ typedef void opivv2_fn(void *vd, void *vs1, void *vs2, int i); @@ -1532,3 +1536,70 @@ GEN_VEXT_CMP_VX(vmsgt_vx_b, int8_t, H1, DO_MSGT) GEN_VEXT_CMP_VX(vmsgt_vx_h, int16_t, H2, DO_MSGT) GEN_VEXT_CMP_VX(vmsgt_vx_w, int32_t, H4, DO_MSGT) GEN_VEXT_CMP_VX(vmsgt_vx_d, int64_t, H8, DO_MSGT) + +/* Vector Integer Min/Max Instructions */ +RVVCALL(OPIVV2, vminu_vv_b, OP_UUU_B, H1, H1, H1, DO_MIN) +RVVCALL(OPIVV2, vminu_vv_h, OP_UUU_H, H2, H2, H2, DO_MIN) +RVVCALL(OPIVV2, vminu_vv_w, OP_UUU_W, H4, H4, H4, DO_MIN) +RVVCALL(OPIVV2, vminu_vv_d, OP_UUU_D, H8, H8, H8, DO_MIN) +RVVCALL(OPIVV2, vmin_vv_b, OP_SSS_B, H1, H1, H1, DO_MIN) +RVVCALL(OPIVV2, vmin_vv_h, OP_SSS_H, H2, H2, H2, DO_MIN) +RVVCALL(OPIVV2, vmin_vv_w, OP_SSS_W, H4, H4, H4, DO_MIN) +RVVCALL(OPIVV2, vmin_vv_d, OP_SSS_D, H8, H8, H8, DO_MIN) +RVVCALL(OPIVV2, vmaxu_vv_b, OP_UUU_B, H1, H1, H1, DO_MAX) +RVVCALL(OPIVV2, vmaxu_vv_h, OP_UUU_H, H2, H2, H2, DO_MAX) +RVVCALL(OPIVV2, vmaxu_vv_w, OP_UUU_W, H4, H4, H4, DO_MAX) +RVVCALL(OPIVV2, vmaxu_vv_d, OP_UUU_D, H8, H8, H8, DO_MAX) +RVVCALL(OPIVV2, vmax_vv_b, OP_SSS_B, H1, H1, H1, DO_MAX) +RVVCALL(OPIVV2, vmax_vv_h, OP_SSS_H, H2, H2, H2, DO_MAX) +RVVCALL(OPIVV2, vmax_vv_w, OP_SSS_W, H4, H4, H4, DO_MAX) +RVVCALL(OPIVV2, vmax_vv_d, OP_SSS_D, H8, H8, H8, DO_MAX) +GEN_VEXT_VV(vminu_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vminu_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vminu_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vminu_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vmin_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vmin_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vmin_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vmin_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vmaxu_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vmaxu_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vmaxu_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vmaxu_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vmax_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vmax_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vmax_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vmax_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2, vminu_vx_b, OP_UUU_B, H1, H1, DO_MIN) +RVVCALL(OPIVX2, vminu_vx_h, OP_UUU_H, H2, H2, DO_MIN) +RVVCALL(OPIVX2, vminu_vx_w, OP_UUU_W, H4, H4, DO_MIN) +RVVCALL(OPIVX2, vminu_vx_d, OP_UUU_D, H8, H8, DO_MIN) +RVVCALL(OPIVX2, vmin_vx_b, OP_SSS_B, H1, H1, DO_MIN) +RVVCALL(OPIVX2, vmin_vx_h, OP_SSS_H, H2, H2, DO_MIN) +RVVCALL(OPIVX2, vmin_vx_w, OP_SSS_W, H4, H4, DO_MIN) +RVVCALL(OPIVX2, vmin_vx_d, OP_SSS_D, H8, H8, DO_MIN) +RVVCALL(OPIVX2, vmaxu_vx_b, OP_UUU_B, H1, H1, DO_MAX) +RVVCALL(OPIVX2, vmaxu_vx_h, OP_UUU_H, H2, H2, DO_MAX) +RVVCALL(OPIVX2, vmaxu_vx_w, OP_UUU_W, H4, H4, DO_MAX) +RVVCALL(OPIVX2, vmaxu_vx_d, OP_UUU_D, H8, H8, DO_MAX) +RVVCALL(OPIVX2, vmax_vx_b, OP_SSS_B, H1, H1, DO_MAX) +RVVCALL(OPIVX2, vmax_vx_h, OP_SSS_H, H2, H2, DO_MAX) +RVVCALL(OPIVX2, vmax_vx_w, OP_SSS_W, H4, H4, DO_MAX) +RVVCALL(OPIVX2, vmax_vx_d, OP_SSS_D, H8, H8, DO_MAX) +GEN_VEXT_VX(vminu_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vminu_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vminu_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vminu_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vmin_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vmin_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vmin_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vmin_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vmaxu_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vmaxu_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vmaxu_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vmaxu_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vmax_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vmax_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vmax_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vmax_vx_d, 8, 8, clearq) From 958b85f3686631af93f695b2a5dd047e037074f2 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:06 +0800 Subject: [PATCH 1819/2595] target/riscv: vector single-width integer multiply instructions Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-19-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 33 +++++ target/riscv/insn32.decode | 8 ++ target/riscv/insn_trans/trans_rvv.inc.c | 10 ++ target/riscv/vector_helper.c | 163 ++++++++++++++++++++++++ 4 files changed, 214 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 9c576e1220..c2de0d29ba 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -535,3 +535,36 @@ DEF_HELPER_6(vmax_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmax_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmax_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmax_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vmul_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmul_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmul_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmul_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulh_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulh_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulh_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulh_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulhu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulhu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulhu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulhu_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulhsu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulhsu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulhsu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmulhsu_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmul_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmul_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmul_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmul_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulh_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulh_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulh_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulh_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulhu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulhu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulhu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulhu_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulhsu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulhsu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulhsu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmulhsu_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 3d8986c74d..6b29aad4d2 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -365,6 +365,14 @@ vmaxu_vv 000110 . ..... ..... 000 ..... 1010111 @r_vm vmaxu_vx 000110 . ..... ..... 100 ..... 1010111 @r_vm vmax_vv 000111 . ..... ..... 000 ..... 1010111 @r_vm vmax_vx 000111 . ..... ..... 100 ..... 1010111 @r_vm +vmul_vv 100101 . ..... ..... 010 ..... 1010111 @r_vm +vmul_vx 100101 . ..... ..... 110 ..... 1010111 @r_vm +vmulh_vv 100111 . ..... ..... 010 ..... 1010111 @r_vm +vmulh_vx 100111 . ..... ..... 110 ..... 1010111 @r_vm +vmulhu_vv 100100 . ..... ..... 010 ..... 1010111 @r_vm +vmulhu_vx 100100 . ..... ..... 110 ..... 1010111 @r_vm +vmulhsu_vv 100110 . ..... ..... 010 ..... 1010111 @r_vm +vmulhsu_vx 100110 . ..... ..... 110 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 861fd3bf1a..b5ea1c59a1 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1571,3 +1571,13 @@ GEN_OPIVX_TRANS(vminu_vx, opivx_check) GEN_OPIVX_TRANS(vmin_vx, opivx_check) GEN_OPIVX_TRANS(vmaxu_vx, opivx_check) GEN_OPIVX_TRANS(vmax_vx, opivx_check) + +/* Vector Single-Width Integer Multiply Instructions */ +GEN_OPIVV_GVEC_TRANS(vmul_vv, mul) +GEN_OPIVV_TRANS(vmulh_vv, opivv_check) +GEN_OPIVV_TRANS(vmulhu_vv, opivv_check) +GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check) +GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) +GEN_OPIVX_TRANS(vmulh_vx, opivx_check) +GEN_OPIVX_TRANS(vmulhu_vx, opivx_check) +GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index b1ff767209..77f0399ebe 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -859,6 +859,10 @@ GEN_VEXT_AMO(vamomaxuw_v_w, uint32_t, uint32_t, idx_w, clearl) #define OP_UUU_H uint16_t, uint16_t, uint16_t, uint16_t, uint16_t #define OP_UUU_W uint32_t, uint32_t, uint32_t, uint32_t, uint32_t #define OP_UUU_D uint64_t, uint64_t, uint64_t, uint64_t, uint64_t +#define OP_SUS_B int8_t, uint8_t, int8_t, uint8_t, int8_t +#define OP_SUS_H int16_t, uint16_t, int16_t, uint16_t, int16_t +#define OP_SUS_W int32_t, uint32_t, int32_t, uint32_t, int32_t +#define OP_SUS_D int64_t, uint64_t, int64_t, uint64_t, int64_t /* operation of two vector elements */ typedef void opivv2_fn(void *vd, void *vs1, void *vs2, int i); @@ -1603,3 +1607,162 @@ GEN_VEXT_VX(vmax_vx_b, 1, 1, clearb) GEN_VEXT_VX(vmax_vx_h, 2, 2, clearh) GEN_VEXT_VX(vmax_vx_w, 4, 4, clearl) GEN_VEXT_VX(vmax_vx_d, 8, 8, clearq) + +/* Vector Single-Width Integer Multiply Instructions */ +#define DO_MUL(N, M) (N * M) +RVVCALL(OPIVV2, vmul_vv_b, OP_SSS_B, H1, H1, H1, DO_MUL) +RVVCALL(OPIVV2, vmul_vv_h, OP_SSS_H, H2, H2, H2, DO_MUL) +RVVCALL(OPIVV2, vmul_vv_w, OP_SSS_W, H4, H4, H4, DO_MUL) +RVVCALL(OPIVV2, vmul_vv_d, OP_SSS_D, H8, H8, H8, DO_MUL) +GEN_VEXT_VV(vmul_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vmul_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vmul_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vmul_vv_d, 8, 8, clearq) + +static int8_t do_mulh_b(int8_t s2, int8_t s1) +{ + return (int16_t)s2 * (int16_t)s1 >> 8; +} + +static int16_t do_mulh_h(int16_t s2, int16_t s1) +{ + return (int32_t)s2 * (int32_t)s1 >> 16; +} + +static int32_t do_mulh_w(int32_t s2, int32_t s1) +{ + return (int64_t)s2 * (int64_t)s1 >> 32; +} + +static int64_t do_mulh_d(int64_t s2, int64_t s1) +{ + uint64_t hi_64, lo_64; + + muls64(&lo_64, &hi_64, s1, s2); + return hi_64; +} + +static uint8_t do_mulhu_b(uint8_t s2, uint8_t s1) +{ + return (uint16_t)s2 * (uint16_t)s1 >> 8; +} + +static uint16_t do_mulhu_h(uint16_t s2, uint16_t s1) +{ + return (uint32_t)s2 * (uint32_t)s1 >> 16; +} + +static uint32_t do_mulhu_w(uint32_t s2, uint32_t s1) +{ + return (uint64_t)s2 * (uint64_t)s1 >> 32; +} + +static uint64_t do_mulhu_d(uint64_t s2, uint64_t s1) +{ + uint64_t hi_64, lo_64; + + mulu64(&lo_64, &hi_64, s2, s1); + return hi_64; +} + +static int8_t do_mulhsu_b(int8_t s2, uint8_t s1) +{ + return (int16_t)s2 * (uint16_t)s1 >> 8; +} + +static int16_t do_mulhsu_h(int16_t s2, uint16_t s1) +{ + return (int32_t)s2 * (uint32_t)s1 >> 16; +} + +static int32_t do_mulhsu_w(int32_t s2, uint32_t s1) +{ + return (int64_t)s2 * (uint64_t)s1 >> 32; +} + +/* + * Let A = signed operand, + * B = unsigned operand + * P = mulu64(A, B), unsigned product + * + * LET X = 2 ** 64 - A, 2's complement of A + * SP = signed product + * THEN + * IF A < 0 + * SP = -X * B + * = -(2 ** 64 - A) * B + * = A * B - 2 ** 64 * B + * = P - 2 ** 64 * B + * ELSE + * SP = P + * THEN + * HI_P -= (A < 0 ? B : 0) + */ + +static int64_t do_mulhsu_d(int64_t s2, uint64_t s1) +{ + uint64_t hi_64, lo_64; + + mulu64(&lo_64, &hi_64, s2, s1); + + hi_64 -= s2 < 0 ? s1 : 0; + return hi_64; +} + +RVVCALL(OPIVV2, vmulh_vv_b, OP_SSS_B, H1, H1, H1, do_mulh_b) +RVVCALL(OPIVV2, vmulh_vv_h, OP_SSS_H, H2, H2, H2, do_mulh_h) +RVVCALL(OPIVV2, vmulh_vv_w, OP_SSS_W, H4, H4, H4, do_mulh_w) +RVVCALL(OPIVV2, vmulh_vv_d, OP_SSS_D, H8, H8, H8, do_mulh_d) +RVVCALL(OPIVV2, vmulhu_vv_b, OP_UUU_B, H1, H1, H1, do_mulhu_b) +RVVCALL(OPIVV2, vmulhu_vv_h, OP_UUU_H, H2, H2, H2, do_mulhu_h) +RVVCALL(OPIVV2, vmulhu_vv_w, OP_UUU_W, H4, H4, H4, do_mulhu_w) +RVVCALL(OPIVV2, vmulhu_vv_d, OP_UUU_D, H8, H8, H8, do_mulhu_d) +RVVCALL(OPIVV2, vmulhsu_vv_b, OP_SUS_B, H1, H1, H1, do_mulhsu_b) +RVVCALL(OPIVV2, vmulhsu_vv_h, OP_SUS_H, H2, H2, H2, do_mulhsu_h) +RVVCALL(OPIVV2, vmulhsu_vv_w, OP_SUS_W, H4, H4, H4, do_mulhsu_w) +RVVCALL(OPIVV2, vmulhsu_vv_d, OP_SUS_D, H8, H8, H8, do_mulhsu_d) +GEN_VEXT_VV(vmulh_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vmulh_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vmulh_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vmulh_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vmulhu_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vmulhu_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vmulhu_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vmulhu_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vmulhsu_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vmulhsu_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vmulhsu_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vmulhsu_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2, vmul_vx_b, OP_SSS_B, H1, H1, DO_MUL) +RVVCALL(OPIVX2, vmul_vx_h, OP_SSS_H, H2, H2, DO_MUL) +RVVCALL(OPIVX2, vmul_vx_w, OP_SSS_W, H4, H4, DO_MUL) +RVVCALL(OPIVX2, vmul_vx_d, OP_SSS_D, H8, H8, DO_MUL) +RVVCALL(OPIVX2, vmulh_vx_b, OP_SSS_B, H1, H1, do_mulh_b) +RVVCALL(OPIVX2, vmulh_vx_h, OP_SSS_H, H2, H2, do_mulh_h) +RVVCALL(OPIVX2, vmulh_vx_w, OP_SSS_W, H4, H4, do_mulh_w) +RVVCALL(OPIVX2, vmulh_vx_d, OP_SSS_D, H8, H8, do_mulh_d) +RVVCALL(OPIVX2, vmulhu_vx_b, OP_UUU_B, H1, H1, do_mulhu_b) +RVVCALL(OPIVX2, vmulhu_vx_h, OP_UUU_H, H2, H2, do_mulhu_h) +RVVCALL(OPIVX2, vmulhu_vx_w, OP_UUU_W, H4, H4, do_mulhu_w) +RVVCALL(OPIVX2, vmulhu_vx_d, OP_UUU_D, H8, H8, do_mulhu_d) +RVVCALL(OPIVX2, vmulhsu_vx_b, OP_SUS_B, H1, H1, do_mulhsu_b) +RVVCALL(OPIVX2, vmulhsu_vx_h, OP_SUS_H, H2, H2, do_mulhsu_h) +RVVCALL(OPIVX2, vmulhsu_vx_w, OP_SUS_W, H4, H4, do_mulhsu_w) +RVVCALL(OPIVX2, vmulhsu_vx_d, OP_SUS_D, H8, H8, do_mulhsu_d) +GEN_VEXT_VX(vmul_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vmul_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vmul_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vmul_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vmulh_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vmulh_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vmulh_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vmulh_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vmulhu_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vmulhu_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vmulhu_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vmulhu_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vmulhsu_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vmulhsu_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vmulhsu_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vmulhsu_vx_d, 8, 8, clearq) From 85e6658cfe9d71cc207a710ffdf0e6546f8612aa Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:07 +0800 Subject: [PATCH 1820/2595] target/riscv: vector integer divide instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-20-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 33 +++++++++++ target/riscv/insn32.decode | 8 +++ target/riscv/insn_trans/trans_rvv.inc.c | 10 ++++ target/riscv/vector_helper.c | 74 +++++++++++++++++++++++++ 4 files changed, 125 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index c2de0d29ba..e14979e452 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -568,3 +568,36 @@ DEF_HELPER_6(vmulhsu_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmulhsu_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmulhsu_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vmulhsu_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vdivu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vdivu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vdivu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vdivu_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vdiv_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vdiv_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vdiv_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vdiv_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vremu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vremu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vremu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vremu_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vrem_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vrem_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vrem_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vrem_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vdivu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vdivu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vdivu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vdivu_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vdiv_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vdiv_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vdiv_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vdiv_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vremu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vremu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vremu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vremu_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vrem_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vrem_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vrem_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vrem_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 6b29aad4d2..cf58764308 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -373,6 +373,14 @@ vmulhu_vv 100100 . ..... ..... 010 ..... 1010111 @r_vm vmulhu_vx 100100 . ..... ..... 110 ..... 1010111 @r_vm vmulhsu_vv 100110 . ..... ..... 010 ..... 1010111 @r_vm vmulhsu_vx 100110 . ..... ..... 110 ..... 1010111 @r_vm +vdivu_vv 100000 . ..... ..... 010 ..... 1010111 @r_vm +vdivu_vx 100000 . ..... ..... 110 ..... 1010111 @r_vm +vdiv_vv 100001 . ..... ..... 010 ..... 1010111 @r_vm +vdiv_vx 100001 . ..... ..... 110 ..... 1010111 @r_vm +vremu_vv 100010 . ..... ..... 010 ..... 1010111 @r_vm +vremu_vx 100010 . ..... ..... 110 ..... 1010111 @r_vm +vrem_vv 100011 . ..... ..... 010 ..... 1010111 @r_vm +vrem_vx 100011 . ..... ..... 110 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index b5ea1c59a1..f3a8baf581 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1581,3 +1581,13 @@ GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) GEN_OPIVX_TRANS(vmulh_vx, opivx_check) GEN_OPIVX_TRANS(vmulhu_vx, opivx_check) GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check) + +/* Vector Integer Divide Instructions */ +GEN_OPIVV_TRANS(vdivu_vv, opivv_check) +GEN_OPIVV_TRANS(vdiv_vv, opivv_check) +GEN_OPIVV_TRANS(vremu_vv, opivv_check) +GEN_OPIVV_TRANS(vrem_vv, opivv_check) +GEN_OPIVX_TRANS(vdivu_vx, opivx_check) +GEN_OPIVX_TRANS(vdiv_vx, opivx_check) +GEN_OPIVX_TRANS(vremu_vx, opivx_check) +GEN_OPIVX_TRANS(vrem_vx, opivx_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 77f0399ebe..1a90f6e967 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -1766,3 +1766,77 @@ GEN_VEXT_VX(vmulhsu_vx_b, 1, 1, clearb) GEN_VEXT_VX(vmulhsu_vx_h, 2, 2, clearh) GEN_VEXT_VX(vmulhsu_vx_w, 4, 4, clearl) GEN_VEXT_VX(vmulhsu_vx_d, 8, 8, clearq) + +/* Vector Integer Divide Instructions */ +#define DO_DIVU(N, M) (unlikely(M == 0) ? (__typeof(N))(-1) : N / M) +#define DO_REMU(N, M) (unlikely(M == 0) ? N : N % M) +#define DO_DIV(N, M) (unlikely(M == 0) ? (__typeof(N))(-1) :\ + unlikely((N == -N) && (M == (__typeof(N))(-1))) ? N : N / M) +#define DO_REM(N, M) (unlikely(M == 0) ? N :\ + unlikely((N == -N) && (M == (__typeof(N))(-1))) ? 0 : N % M) + +RVVCALL(OPIVV2, vdivu_vv_b, OP_UUU_B, H1, H1, H1, DO_DIVU) +RVVCALL(OPIVV2, vdivu_vv_h, OP_UUU_H, H2, H2, H2, DO_DIVU) +RVVCALL(OPIVV2, vdivu_vv_w, OP_UUU_W, H4, H4, H4, DO_DIVU) +RVVCALL(OPIVV2, vdivu_vv_d, OP_UUU_D, H8, H8, H8, DO_DIVU) +RVVCALL(OPIVV2, vdiv_vv_b, OP_SSS_B, H1, H1, H1, DO_DIV) +RVVCALL(OPIVV2, vdiv_vv_h, OP_SSS_H, H2, H2, H2, DO_DIV) +RVVCALL(OPIVV2, vdiv_vv_w, OP_SSS_W, H4, H4, H4, DO_DIV) +RVVCALL(OPIVV2, vdiv_vv_d, OP_SSS_D, H8, H8, H8, DO_DIV) +RVVCALL(OPIVV2, vremu_vv_b, OP_UUU_B, H1, H1, H1, DO_REMU) +RVVCALL(OPIVV2, vremu_vv_h, OP_UUU_H, H2, H2, H2, DO_REMU) +RVVCALL(OPIVV2, vremu_vv_w, OP_UUU_W, H4, H4, H4, DO_REMU) +RVVCALL(OPIVV2, vremu_vv_d, OP_UUU_D, H8, H8, H8, DO_REMU) +RVVCALL(OPIVV2, vrem_vv_b, OP_SSS_B, H1, H1, H1, DO_REM) +RVVCALL(OPIVV2, vrem_vv_h, OP_SSS_H, H2, H2, H2, DO_REM) +RVVCALL(OPIVV2, vrem_vv_w, OP_SSS_W, H4, H4, H4, DO_REM) +RVVCALL(OPIVV2, vrem_vv_d, OP_SSS_D, H8, H8, H8, DO_REM) +GEN_VEXT_VV(vdivu_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vdivu_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vdivu_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vdivu_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vdiv_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vdiv_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vdiv_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vdiv_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vremu_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vremu_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vremu_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vremu_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vrem_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vrem_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vrem_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vrem_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2, vdivu_vx_b, OP_UUU_B, H1, H1, DO_DIVU) +RVVCALL(OPIVX2, vdivu_vx_h, OP_UUU_H, H2, H2, DO_DIVU) +RVVCALL(OPIVX2, vdivu_vx_w, OP_UUU_W, H4, H4, DO_DIVU) +RVVCALL(OPIVX2, vdivu_vx_d, OP_UUU_D, H8, H8, DO_DIVU) +RVVCALL(OPIVX2, vdiv_vx_b, OP_SSS_B, H1, H1, DO_DIV) +RVVCALL(OPIVX2, vdiv_vx_h, OP_SSS_H, H2, H2, DO_DIV) +RVVCALL(OPIVX2, vdiv_vx_w, OP_SSS_W, H4, H4, DO_DIV) +RVVCALL(OPIVX2, vdiv_vx_d, OP_SSS_D, H8, H8, DO_DIV) +RVVCALL(OPIVX2, vremu_vx_b, OP_UUU_B, H1, H1, DO_REMU) +RVVCALL(OPIVX2, vremu_vx_h, OP_UUU_H, H2, H2, DO_REMU) +RVVCALL(OPIVX2, vremu_vx_w, OP_UUU_W, H4, H4, DO_REMU) +RVVCALL(OPIVX2, vremu_vx_d, OP_UUU_D, H8, H8, DO_REMU) +RVVCALL(OPIVX2, vrem_vx_b, OP_SSS_B, H1, H1, DO_REM) +RVVCALL(OPIVX2, vrem_vx_h, OP_SSS_H, H2, H2, DO_REM) +RVVCALL(OPIVX2, vrem_vx_w, OP_SSS_W, H4, H4, DO_REM) +RVVCALL(OPIVX2, vrem_vx_d, OP_SSS_D, H8, H8, DO_REM) +GEN_VEXT_VX(vdivu_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vdivu_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vdivu_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vdivu_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vdiv_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vdiv_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vdiv_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vdiv_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vremu_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vremu_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vremu_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vremu_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vrem_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vrem_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vrem_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vrem_vx_d, 8, 8, clearq) From 97b1cba39967251ab78b9d52fd9a4c62bb42d428 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:08 +0800 Subject: [PATCH 1821/2595] target/riscv: vector widening integer multiply instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-21-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 19 +++++++++ target/riscv/insn32.decode | 6 +++ target/riscv/insn_trans/trans_rvv.inc.c | 8 ++++ target/riscv/vector_helper.c | 51 +++++++++++++++++++++++++ 4 files changed, 84 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index e14979e452..60c436616a 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -601,3 +601,22 @@ DEF_HELPER_6(vrem_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vrem_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vrem_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vrem_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vwmul_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmul_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmul_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmulu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmulu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmulu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmulsu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmulsu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmulsu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmul_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmul_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmul_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmulu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmulu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmulu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmulsu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmulsu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmulsu_vx_w, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index cf58764308..877d999129 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -381,6 +381,12 @@ vremu_vv 100010 . ..... ..... 010 ..... 1010111 @r_vm vremu_vx 100010 . ..... ..... 110 ..... 1010111 @r_vm vrem_vv 100011 . ..... ..... 010 ..... 1010111 @r_vm vrem_vx 100011 . ..... ..... 110 ..... 1010111 @r_vm +vwmulu_vv 111000 . ..... ..... 010 ..... 1010111 @r_vm +vwmulu_vx 111000 . ..... ..... 110 ..... 1010111 @r_vm +vwmulsu_vv 111010 . ..... ..... 010 ..... 1010111 @r_vm +vwmulsu_vx 111010 . ..... ..... 110 ..... 1010111 @r_vm +vwmul_vv 111011 . ..... ..... 010 ..... 1010111 @r_vm +vwmul_vx 111011 . ..... ..... 110 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index f3a8baf581..9cd31ba1d8 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1591,3 +1591,11 @@ GEN_OPIVX_TRANS(vdivu_vx, opivx_check) GEN_OPIVX_TRANS(vdiv_vx, opivx_check) GEN_OPIVX_TRANS(vremu_vx, opivx_check) GEN_OPIVX_TRANS(vrem_vx, opivx_check) + +/* Vector Widening Integer Multiply Instructions */ +GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check) +GEN_OPIVX_WIDEN_TRANS(vwmul_vx) +GEN_OPIVX_WIDEN_TRANS(vwmulu_vx) +GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 1a90f6e967..f27543914f 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -863,6 +863,18 @@ GEN_VEXT_AMO(vamomaxuw_v_w, uint32_t, uint32_t, idx_w, clearl) #define OP_SUS_H int16_t, uint16_t, int16_t, uint16_t, int16_t #define OP_SUS_W int32_t, uint32_t, int32_t, uint32_t, int32_t #define OP_SUS_D int64_t, uint64_t, int64_t, uint64_t, int64_t +#define WOP_UUU_B uint16_t, uint8_t, uint8_t, uint16_t, uint16_t +#define WOP_UUU_H uint32_t, uint16_t, uint16_t, uint32_t, uint32_t +#define WOP_UUU_W uint64_t, uint32_t, uint32_t, uint64_t, uint64_t +#define WOP_SSS_B int16_t, int8_t, int8_t, int16_t, int16_t +#define WOP_SSS_H int32_t, int16_t, int16_t, int32_t, int32_t +#define WOP_SSS_W int64_t, int32_t, int32_t, int64_t, int64_t +#define WOP_SUS_B int16_t, uint8_t, int8_t, uint16_t, int16_t +#define WOP_SUS_H int32_t, uint16_t, int16_t, uint32_t, int32_t +#define WOP_SUS_W int64_t, uint32_t, int32_t, uint64_t, int64_t +#define WOP_SSU_B int16_t, int8_t, uint8_t, int16_t, uint16_t +#define WOP_SSU_H int32_t, int16_t, uint16_t, int32_t, uint32_t +#define WOP_SSU_W int64_t, int32_t, uint32_t, int64_t, uint64_t /* operation of two vector elements */ typedef void opivv2_fn(void *vd, void *vs1, void *vs2, int i); @@ -1840,3 +1852,42 @@ GEN_VEXT_VX(vrem_vx_b, 1, 1, clearb) GEN_VEXT_VX(vrem_vx_h, 2, 2, clearh) GEN_VEXT_VX(vrem_vx_w, 4, 4, clearl) GEN_VEXT_VX(vrem_vx_d, 8, 8, clearq) + +/* Vector Widening Integer Multiply Instructions */ +RVVCALL(OPIVV2, vwmul_vv_b, WOP_SSS_B, H2, H1, H1, DO_MUL) +RVVCALL(OPIVV2, vwmul_vv_h, WOP_SSS_H, H4, H2, H2, DO_MUL) +RVVCALL(OPIVV2, vwmul_vv_w, WOP_SSS_W, H8, H4, H4, DO_MUL) +RVVCALL(OPIVV2, vwmulu_vv_b, WOP_UUU_B, H2, H1, H1, DO_MUL) +RVVCALL(OPIVV2, vwmulu_vv_h, WOP_UUU_H, H4, H2, H2, DO_MUL) +RVVCALL(OPIVV2, vwmulu_vv_w, WOP_UUU_W, H8, H4, H4, DO_MUL) +RVVCALL(OPIVV2, vwmulsu_vv_b, WOP_SUS_B, H2, H1, H1, DO_MUL) +RVVCALL(OPIVV2, vwmulsu_vv_h, WOP_SUS_H, H4, H2, H2, DO_MUL) +RVVCALL(OPIVV2, vwmulsu_vv_w, WOP_SUS_W, H8, H4, H4, DO_MUL) +GEN_VEXT_VV(vwmul_vv_b, 1, 2, clearh) +GEN_VEXT_VV(vwmul_vv_h, 2, 4, clearl) +GEN_VEXT_VV(vwmul_vv_w, 4, 8, clearq) +GEN_VEXT_VV(vwmulu_vv_b, 1, 2, clearh) +GEN_VEXT_VV(vwmulu_vv_h, 2, 4, clearl) +GEN_VEXT_VV(vwmulu_vv_w, 4, 8, clearq) +GEN_VEXT_VV(vwmulsu_vv_b, 1, 2, clearh) +GEN_VEXT_VV(vwmulsu_vv_h, 2, 4, clearl) +GEN_VEXT_VV(vwmulsu_vv_w, 4, 8, clearq) + +RVVCALL(OPIVX2, vwmul_vx_b, WOP_SSS_B, H2, H1, DO_MUL) +RVVCALL(OPIVX2, vwmul_vx_h, WOP_SSS_H, H4, H2, DO_MUL) +RVVCALL(OPIVX2, vwmul_vx_w, WOP_SSS_W, H8, H4, DO_MUL) +RVVCALL(OPIVX2, vwmulu_vx_b, WOP_UUU_B, H2, H1, DO_MUL) +RVVCALL(OPIVX2, vwmulu_vx_h, WOP_UUU_H, H4, H2, DO_MUL) +RVVCALL(OPIVX2, vwmulu_vx_w, WOP_UUU_W, H8, H4, DO_MUL) +RVVCALL(OPIVX2, vwmulsu_vx_b, WOP_SUS_B, H2, H1, DO_MUL) +RVVCALL(OPIVX2, vwmulsu_vx_h, WOP_SUS_H, H4, H2, DO_MUL) +RVVCALL(OPIVX2, vwmulsu_vx_w, WOP_SUS_W, H8, H4, DO_MUL) +GEN_VEXT_VX(vwmul_vx_b, 1, 2, clearh) +GEN_VEXT_VX(vwmul_vx_h, 2, 4, clearl) +GEN_VEXT_VX(vwmul_vx_w, 4, 8, clearq) +GEN_VEXT_VX(vwmulu_vx_b, 1, 2, clearh) +GEN_VEXT_VX(vwmulu_vx_h, 2, 4, clearl) +GEN_VEXT_VX(vwmulu_vx_w, 4, 8, clearq) +GEN_VEXT_VX(vwmulsu_vx_b, 1, 2, clearh) +GEN_VEXT_VX(vwmulsu_vx_h, 2, 4, clearl) +GEN_VEXT_VX(vwmulsu_vx_w, 4, 8, clearq) From 54df813a331d3badfb83604c36bef7cb1de4315a Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:09 +0800 Subject: [PATCH 1822/2595] target/riscv: vector single-width integer multiply-add instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-22-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 33 ++++++++++ target/riscv/insn32.decode | 8 +++ target/riscv/insn_trans/trans_rvv.inc.c | 10 +++ target/riscv/vector_helper.c | 88 +++++++++++++++++++++++++ 4 files changed, 139 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 60c436616a..a65a38596b 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -620,3 +620,36 @@ DEF_HELPER_6(vwmulu_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwmulsu_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwmulsu_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwmulsu_vx_w, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vmacc_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmacc_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnmsac_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnmsac_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnmsac_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnmsac_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmadd_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnmsub_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnmsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnmsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnmsub_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmacc_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmacc_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmacc_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmacc_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnmsac_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnmsac_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnmsac_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnmsac_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmadd_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmadd_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmadd_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmadd_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnmsub_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnmsub_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnmsub_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnmsub_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 877d999129..f01cf14777 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -387,6 +387,14 @@ vwmulsu_vv 111010 . ..... ..... 010 ..... 1010111 @r_vm vwmulsu_vx 111010 . ..... ..... 110 ..... 1010111 @r_vm vwmul_vv 111011 . ..... ..... 010 ..... 1010111 @r_vm vwmul_vx 111011 . ..... ..... 110 ..... 1010111 @r_vm +vmacc_vv 101101 . ..... ..... 010 ..... 1010111 @r_vm +vmacc_vx 101101 . ..... ..... 110 ..... 1010111 @r_vm +vnmsac_vv 101111 . ..... ..... 010 ..... 1010111 @r_vm +vnmsac_vx 101111 . ..... ..... 110 ..... 1010111 @r_vm +vmadd_vv 101001 . ..... ..... 010 ..... 1010111 @r_vm +vmadd_vx 101001 . ..... ..... 110 ..... 1010111 @r_vm +vnmsub_vv 101011 . ..... ..... 010 ..... 1010111 @r_vm +vnmsub_vx 101011 . ..... ..... 110 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 9cd31ba1d8..0f549f7a19 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1599,3 +1599,13 @@ GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check) GEN_OPIVX_WIDEN_TRANS(vwmul_vx) GEN_OPIVX_WIDEN_TRANS(vwmulu_vx) GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx) + +/* Vector Single-Width Integer Multiply-Add Instructions */ +GEN_OPIVV_TRANS(vmacc_vv, opivv_check) +GEN_OPIVV_TRANS(vnmsac_vv, opivv_check) +GEN_OPIVV_TRANS(vmadd_vv, opivv_check) +GEN_OPIVV_TRANS(vnmsub_vv, opivv_check) +GEN_OPIVX_TRANS(vmacc_vx, opivx_check) +GEN_OPIVX_TRANS(vnmsac_vx, opivx_check) +GEN_OPIVX_TRANS(vmadd_vx, opivx_check) +GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index f27543914f..9c31e4d75a 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -1891,3 +1891,91 @@ GEN_VEXT_VX(vwmulu_vx_w, 4, 8, clearq) GEN_VEXT_VX(vwmulsu_vx_b, 1, 2, clearh) GEN_VEXT_VX(vwmulsu_vx_h, 2, 4, clearl) GEN_VEXT_VX(vwmulsu_vx_w, 4, 8, clearq) + +/* Vector Single-Width Integer Multiply-Add Instructions */ +#define OPIVV3(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ +static void do_##NAME(void *vd, void *vs1, void *vs2, int i) \ +{ \ + TX1 s1 = *((T1 *)vs1 + HS1(i)); \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + TD d = *((TD *)vd + HD(i)); \ + *((TD *)vd + HD(i)) = OP(s2, s1, d); \ +} + +#define DO_MACC(N, M, D) (M * N + D) +#define DO_NMSAC(N, M, D) (-(M * N) + D) +#define DO_MADD(N, M, D) (M * D + N) +#define DO_NMSUB(N, M, D) (-(M * D) + N) +RVVCALL(OPIVV3, vmacc_vv_b, OP_SSS_B, H1, H1, H1, DO_MACC) +RVVCALL(OPIVV3, vmacc_vv_h, OP_SSS_H, H2, H2, H2, DO_MACC) +RVVCALL(OPIVV3, vmacc_vv_w, OP_SSS_W, H4, H4, H4, DO_MACC) +RVVCALL(OPIVV3, vmacc_vv_d, OP_SSS_D, H8, H8, H8, DO_MACC) +RVVCALL(OPIVV3, vnmsac_vv_b, OP_SSS_B, H1, H1, H1, DO_NMSAC) +RVVCALL(OPIVV3, vnmsac_vv_h, OP_SSS_H, H2, H2, H2, DO_NMSAC) +RVVCALL(OPIVV3, vnmsac_vv_w, OP_SSS_W, H4, H4, H4, DO_NMSAC) +RVVCALL(OPIVV3, vnmsac_vv_d, OP_SSS_D, H8, H8, H8, DO_NMSAC) +RVVCALL(OPIVV3, vmadd_vv_b, OP_SSS_B, H1, H1, H1, DO_MADD) +RVVCALL(OPIVV3, vmadd_vv_h, OP_SSS_H, H2, H2, H2, DO_MADD) +RVVCALL(OPIVV3, vmadd_vv_w, OP_SSS_W, H4, H4, H4, DO_MADD) +RVVCALL(OPIVV3, vmadd_vv_d, OP_SSS_D, H8, H8, H8, DO_MADD) +RVVCALL(OPIVV3, vnmsub_vv_b, OP_SSS_B, H1, H1, H1, DO_NMSUB) +RVVCALL(OPIVV3, vnmsub_vv_h, OP_SSS_H, H2, H2, H2, DO_NMSUB) +RVVCALL(OPIVV3, vnmsub_vv_w, OP_SSS_W, H4, H4, H4, DO_NMSUB) +RVVCALL(OPIVV3, vnmsub_vv_d, OP_SSS_D, H8, H8, H8, DO_NMSUB) +GEN_VEXT_VV(vmacc_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vmacc_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vmacc_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vmacc_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vnmsac_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vnmsac_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vnmsac_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vnmsac_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vmadd_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vmadd_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vmadd_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vmadd_vv_d, 8, 8, clearq) +GEN_VEXT_VV(vnmsub_vv_b, 1, 1, clearb) +GEN_VEXT_VV(vnmsub_vv_h, 2, 2, clearh) +GEN_VEXT_VV(vnmsub_vv_w, 4, 4, clearl) +GEN_VEXT_VV(vnmsub_vv_d, 8, 8, clearq) + +#define OPIVX3(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ +static void do_##NAME(void *vd, target_long s1, void *vs2, int i) \ +{ \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + TD d = *((TD *)vd + HD(i)); \ + *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1, d); \ +} + +RVVCALL(OPIVX3, vmacc_vx_b, OP_SSS_B, H1, H1, DO_MACC) +RVVCALL(OPIVX3, vmacc_vx_h, OP_SSS_H, H2, H2, DO_MACC) +RVVCALL(OPIVX3, vmacc_vx_w, OP_SSS_W, H4, H4, DO_MACC) +RVVCALL(OPIVX3, vmacc_vx_d, OP_SSS_D, H8, H8, DO_MACC) +RVVCALL(OPIVX3, vnmsac_vx_b, OP_SSS_B, H1, H1, DO_NMSAC) +RVVCALL(OPIVX3, vnmsac_vx_h, OP_SSS_H, H2, H2, DO_NMSAC) +RVVCALL(OPIVX3, vnmsac_vx_w, OP_SSS_W, H4, H4, DO_NMSAC) +RVVCALL(OPIVX3, vnmsac_vx_d, OP_SSS_D, H8, H8, DO_NMSAC) +RVVCALL(OPIVX3, vmadd_vx_b, OP_SSS_B, H1, H1, DO_MADD) +RVVCALL(OPIVX3, vmadd_vx_h, OP_SSS_H, H2, H2, DO_MADD) +RVVCALL(OPIVX3, vmadd_vx_w, OP_SSS_W, H4, H4, DO_MADD) +RVVCALL(OPIVX3, vmadd_vx_d, OP_SSS_D, H8, H8, DO_MADD) +RVVCALL(OPIVX3, vnmsub_vx_b, OP_SSS_B, H1, H1, DO_NMSUB) +RVVCALL(OPIVX3, vnmsub_vx_h, OP_SSS_H, H2, H2, DO_NMSUB) +RVVCALL(OPIVX3, vnmsub_vx_w, OP_SSS_W, H4, H4, DO_NMSUB) +RVVCALL(OPIVX3, vnmsub_vx_d, OP_SSS_D, H8, H8, DO_NMSUB) +GEN_VEXT_VX(vmacc_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vmacc_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vmacc_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vmacc_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vnmsac_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vnmsac_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vnmsac_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vnmsac_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vmadd_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vmadd_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vmadd_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vmadd_vx_d, 8, 8, clearq) +GEN_VEXT_VX(vnmsub_vx_b, 1, 1, clearb) +GEN_VEXT_VX(vnmsub_vx_h, 2, 2, clearh) +GEN_VEXT_VX(vnmsub_vx_w, 4, 4, clearl) +GEN_VEXT_VX(vnmsub_vx_d, 8, 8, clearq) From 2b587b335050dbc0cb3823758341f145c0375312 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:10 +0800 Subject: [PATCH 1823/2595] target/riscv: vector widening integer multiply-add instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-23-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 22 ++++++++++++ target/riscv/insn32.decode | 7 ++++ target/riscv/insn_trans/trans_rvv.inc.c | 9 +++++ target/riscv/vector_helper.c | 45 +++++++++++++++++++++++++ 4 files changed, 83 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index a65a38596b..1249ee274d 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -653,3 +653,25 @@ DEF_HELPER_6(vnmsub_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vnmsub_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vnmsub_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vnmsub_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vwmaccu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmaccu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmaccu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmacc_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmaccsu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmaccsu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmaccsu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwmaccu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmaccu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmaccu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmacc_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmacc_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmacc_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmaccsu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmaccsu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmaccsu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmaccus_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmaccus_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwmaccus_vx_w, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index f01cf14777..843c15f8fa 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -395,6 +395,13 @@ vmadd_vv 101001 . ..... ..... 010 ..... 1010111 @r_vm vmadd_vx 101001 . ..... ..... 110 ..... 1010111 @r_vm vnmsub_vv 101011 . ..... ..... 010 ..... 1010111 @r_vm vnmsub_vx 101011 . ..... ..... 110 ..... 1010111 @r_vm +vwmaccu_vv 111100 . ..... ..... 010 ..... 1010111 @r_vm +vwmaccu_vx 111100 . ..... ..... 110 ..... 1010111 @r_vm +vwmacc_vv 111101 . ..... ..... 010 ..... 1010111 @r_vm +vwmacc_vx 111101 . ..... ..... 110 ..... 1010111 @r_vm +vwmaccsu_vv 111110 . ..... ..... 010 ..... 1010111 @r_vm +vwmaccsu_vx 111110 . ..... ..... 110 ..... 1010111 @r_vm +vwmaccus_vx 111111 . ..... ..... 110 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 0f549f7a19..24e43c615c 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1609,3 +1609,12 @@ GEN_OPIVX_TRANS(vmacc_vx, opivx_check) GEN_OPIVX_TRANS(vnmsac_vx, opivx_check) GEN_OPIVX_TRANS(vmadd_vx, opivx_check) GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) + +/* Vector Widening Integer Multiply-Add Instructions */ +GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) +GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx) +GEN_OPIVX_WIDEN_TRANS(vwmacc_vx) +GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx) +GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 9c31e4d75a..9dd2d5748e 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -1979,3 +1979,48 @@ GEN_VEXT_VX(vnmsub_vx_b, 1, 1, clearb) GEN_VEXT_VX(vnmsub_vx_h, 2, 2, clearh) GEN_VEXT_VX(vnmsub_vx_w, 4, 4, clearl) GEN_VEXT_VX(vnmsub_vx_d, 8, 8, clearq) + +/* Vector Widening Integer Multiply-Add Instructions */ +RVVCALL(OPIVV3, vwmaccu_vv_b, WOP_UUU_B, H2, H1, H1, DO_MACC) +RVVCALL(OPIVV3, vwmaccu_vv_h, WOP_UUU_H, H4, H2, H2, DO_MACC) +RVVCALL(OPIVV3, vwmaccu_vv_w, WOP_UUU_W, H8, H4, H4, DO_MACC) +RVVCALL(OPIVV3, vwmacc_vv_b, WOP_SSS_B, H2, H1, H1, DO_MACC) +RVVCALL(OPIVV3, vwmacc_vv_h, WOP_SSS_H, H4, H2, H2, DO_MACC) +RVVCALL(OPIVV3, vwmacc_vv_w, WOP_SSS_W, H8, H4, H4, DO_MACC) +RVVCALL(OPIVV3, vwmaccsu_vv_b, WOP_SSU_B, H2, H1, H1, DO_MACC) +RVVCALL(OPIVV3, vwmaccsu_vv_h, WOP_SSU_H, H4, H2, H2, DO_MACC) +RVVCALL(OPIVV3, vwmaccsu_vv_w, WOP_SSU_W, H8, H4, H4, DO_MACC) +GEN_VEXT_VV(vwmaccu_vv_b, 1, 2, clearh) +GEN_VEXT_VV(vwmaccu_vv_h, 2, 4, clearl) +GEN_VEXT_VV(vwmaccu_vv_w, 4, 8, clearq) +GEN_VEXT_VV(vwmacc_vv_b, 1, 2, clearh) +GEN_VEXT_VV(vwmacc_vv_h, 2, 4, clearl) +GEN_VEXT_VV(vwmacc_vv_w, 4, 8, clearq) +GEN_VEXT_VV(vwmaccsu_vv_b, 1, 2, clearh) +GEN_VEXT_VV(vwmaccsu_vv_h, 2, 4, clearl) +GEN_VEXT_VV(vwmaccsu_vv_w, 4, 8, clearq) + +RVVCALL(OPIVX3, vwmaccu_vx_b, WOP_UUU_B, H2, H1, DO_MACC) +RVVCALL(OPIVX3, vwmaccu_vx_h, WOP_UUU_H, H4, H2, DO_MACC) +RVVCALL(OPIVX3, vwmaccu_vx_w, WOP_UUU_W, H8, H4, DO_MACC) +RVVCALL(OPIVX3, vwmacc_vx_b, WOP_SSS_B, H2, H1, DO_MACC) +RVVCALL(OPIVX3, vwmacc_vx_h, WOP_SSS_H, H4, H2, DO_MACC) +RVVCALL(OPIVX3, vwmacc_vx_w, WOP_SSS_W, H8, H4, DO_MACC) +RVVCALL(OPIVX3, vwmaccsu_vx_b, WOP_SSU_B, H2, H1, DO_MACC) +RVVCALL(OPIVX3, vwmaccsu_vx_h, WOP_SSU_H, H4, H2, DO_MACC) +RVVCALL(OPIVX3, vwmaccsu_vx_w, WOP_SSU_W, H8, H4, DO_MACC) +RVVCALL(OPIVX3, vwmaccus_vx_b, WOP_SUS_B, H2, H1, DO_MACC) +RVVCALL(OPIVX3, vwmaccus_vx_h, WOP_SUS_H, H4, H2, DO_MACC) +RVVCALL(OPIVX3, vwmaccus_vx_w, WOP_SUS_W, H8, H4, DO_MACC) +GEN_VEXT_VX(vwmaccu_vx_b, 1, 2, clearh) +GEN_VEXT_VX(vwmaccu_vx_h, 2, 4, clearl) +GEN_VEXT_VX(vwmaccu_vx_w, 4, 8, clearq) +GEN_VEXT_VX(vwmacc_vx_b, 1, 2, clearh) +GEN_VEXT_VX(vwmacc_vx_h, 2, 4, clearl) +GEN_VEXT_VX(vwmacc_vx_w, 4, 8, clearq) +GEN_VEXT_VX(vwmaccsu_vx_b, 1, 2, clearh) +GEN_VEXT_VX(vwmaccsu_vx_h, 2, 4, clearl) +GEN_VEXT_VX(vwmaccsu_vx_w, 4, 8, clearq) +GEN_VEXT_VX(vwmaccus_vx_b, 1, 2, clearh) +GEN_VEXT_VX(vwmaccus_vx_h, 2, 4, clearl) +GEN_VEXT_VX(vwmaccus_vx_w, 4, 8, clearq) From f020a7a14505d6996497693e63331ab609847d93 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:11 +0800 Subject: [PATCH 1824/2595] target/riscv: vector integer merge and move instructions Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-24-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 17 ++++ target/riscv/insn32.decode | 7 ++ target/riscv/insn_trans/trans_rvv.inc.c | 113 ++++++++++++++++++++++++ target/riscv/vector_helper.c | 88 ++++++++++++++++++ 4 files changed, 225 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 1249ee274d..9851086730 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -675,3 +675,20 @@ DEF_HELPER_6(vwmaccsu_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwmaccus_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwmaccus_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwmaccus_vx_w, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vmerge_vvm_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmerge_vvm_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmerge_vvm_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmerge_vvm_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmerge_vxm_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmerge_vxm_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmerge_vxm_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vmerge_vxm_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_4(vmv_v_v_b, void, ptr, ptr, env, i32) +DEF_HELPER_4(vmv_v_v_h, void, ptr, ptr, env, i32) +DEF_HELPER_4(vmv_v_v_w, void, ptr, ptr, env, i32) +DEF_HELPER_4(vmv_v_v_d, void, ptr, ptr, env, i32) +DEF_HELPER_4(vmv_v_x_b, void, ptr, i64, env, i32) +DEF_HELPER_4(vmv_v_x_h, void, ptr, i64, env, i32) +DEF_HELPER_4(vmv_v_x_w, void, ptr, i64, env, i32) +DEF_HELPER_4(vmv_v_x_d, void, ptr, i64, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 843c15f8fa..238aa014d1 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -71,6 +71,7 @@ @r_nfvm ... ... vm:1 ..... ..... ... ..... ....... &rnfvm %nf %rs2 %rs1 %rd @r_vm ...... vm:1 ..... ..... ... ..... ....... &rmrr %rs2 %rs1 %rd @r_vm_1 ...... . ..... ..... ... ..... ....... &rmrr vm=1 %rs2 %rs1 %rd +@r_vm_0 ...... . ..... ..... ... ..... ....... &rmrr vm=0 %rs2 %rs1 %rd @r_wdvm ..... wd:1 vm:1 ..... ..... ... ..... ....... &rwdvm %rs2 %rs1 %rd @r2_zimm . zimm:11 ..... ... ..... ....... %rs1 %rd @@ -402,6 +403,12 @@ vwmacc_vx 111101 . ..... ..... 110 ..... 1010111 @r_vm vwmaccsu_vv 111110 . ..... ..... 010 ..... 1010111 @r_vm vwmaccsu_vx 111110 . ..... ..... 110 ..... 1010111 @r_vm vwmaccus_vx 111111 . ..... ..... 110 ..... 1010111 @r_vm +vmv_v_v 010111 1 00000 ..... 000 ..... 1010111 @r2 +vmv_v_x 010111 1 00000 ..... 100 ..... 1010111 @r2 +vmv_v_i 010111 1 00000 ..... 011 ..... 1010111 @r2 +vmerge_vvm 010111 0 ..... ..... 000 ..... 1010111 @r_vm_0 +vmerge_vxm 010111 0 ..... ..... 100 ..... 1010111 @r_vm_0 +vmerge_vim 010111 0 ..... ..... 011 ..... 1010111 @r_vm_0 vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 24e43c615c..f9532ebc71 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1618,3 +1618,116 @@ GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx) GEN_OPIVX_WIDEN_TRANS(vwmacc_vx) GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx) GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx) + +/* Vector Integer Merge and Move Instructions */ +static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) +{ + if (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs1, false)) { + + if (s->vl_eq_vlmax) { + tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), + vreg_ofs(s, a->rs1), + MAXSZ(s), MAXSZ(s)); + } else { + uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); + static gen_helper_gvec_2_ptr * const fns[4] = { + gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, + gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, + }; + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), + cpu_env, 0, s->vlen / 8, data, fns[s->sew]); + gen_set_label(over); + } + return true; + } + return false; +} + +typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32); +static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) +{ + if (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false)) { + + TCGv s1; + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + s1 = tcg_temp_new(); + gen_get_gpr(s1, a->rs1); + + if (s->vl_eq_vlmax) { + tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), + MAXSZ(s), MAXSZ(s), s1); + } else { + TCGv_i32 desc ; + TCGv_i64 s1_i64 = tcg_temp_new_i64(); + TCGv_ptr dest = tcg_temp_new_ptr(); + uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); + static gen_helper_vmv_vx * const fns[4] = { + gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, + gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, + }; + + tcg_gen_ext_tl_i64(s1_i64, s1); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); + fns[s->sew](dest, s1_i64, cpu_env, desc); + + tcg_temp_free_ptr(dest); + tcg_temp_free_i32(desc); + tcg_temp_free_i64(s1_i64); + } + + tcg_temp_free(s1); + gen_set_label(over); + return true; + } + return false; +} + +static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) +{ + if (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false)) { + + int64_t simm = sextract64(a->rs1, 0, 5); + if (s->vl_eq_vlmax) { + tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), + MAXSZ(s), MAXSZ(s), simm); + } else { + TCGv_i32 desc; + TCGv_i64 s1; + TCGv_ptr dest; + uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); + static gen_helper_vmv_vx * const fns[4] = { + gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, + gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, + }; + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + s1 = tcg_const_i64(simm); + dest = tcg_temp_new_ptr(); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); + fns[s->sew](dest, s1, cpu_env, desc); + + tcg_temp_free_ptr(dest); + tcg_temp_free_i32(desc); + tcg_temp_free_i64(s1); + gen_set_label(over); + } + return true; + } + return false; +} + +GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check) +GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check) +GEN_OPIVI_TRANS(vmerge_vim, 0, vmerge_vxm, opivx_vadc_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 9dd2d5748e..92d90d07d6 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -2024,3 +2024,91 @@ GEN_VEXT_VX(vwmaccsu_vx_w, 4, 8, clearq) GEN_VEXT_VX(vwmaccus_vx_b, 1, 2, clearh) GEN_VEXT_VX(vwmaccus_vx_h, 2, 4, clearl) GEN_VEXT_VX(vwmaccus_vx_w, 4, 8, clearq) + +/* Vector Integer Merge and Move Instructions */ +#define GEN_VEXT_VMV_VV(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *vs1, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t vlmax = vext_maxsz(desc) / esz; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ + *((ETYPE *)vd + H(i)) = s1; \ + } \ + CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \ +} + +GEN_VEXT_VMV_VV(vmv_v_v_b, int8_t, H1, clearb) +GEN_VEXT_VMV_VV(vmv_v_v_h, int16_t, H2, clearh) +GEN_VEXT_VMV_VV(vmv_v_v_w, int32_t, H4, clearl) +GEN_VEXT_VMV_VV(vmv_v_v_d, int64_t, H8, clearq) + +#define GEN_VEXT_VMV_VX(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, uint64_t s1, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t vlmax = vext_maxsz(desc) / esz; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + *((ETYPE *)vd + H(i)) = (ETYPE)s1; \ + } \ + CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \ +} + +GEN_VEXT_VMV_VX(vmv_v_x_b, int8_t, H1, clearb) +GEN_VEXT_VMV_VX(vmv_v_x_h, int16_t, H2, clearh) +GEN_VEXT_VMV_VX(vmv_v_x_w, int32_t, H4, clearl) +GEN_VEXT_VMV_VX(vmv_v_x_d, int64_t, H8, clearq) + +#define GEN_VEXT_VMERGE_VV(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t vlmax = vext_maxsz(desc) / esz; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE *vt = (!vext_elem_mask(v0, mlen, i) ? vs2 : vs1); \ + *((ETYPE *)vd + H(i)) = *(vt + H(i)); \ + } \ + CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \ +} + +GEN_VEXT_VMERGE_VV(vmerge_vvm_b, int8_t, H1, clearb) +GEN_VEXT_VMERGE_VV(vmerge_vvm_h, int16_t, H2, clearh) +GEN_VEXT_VMERGE_VV(vmerge_vvm_w, int32_t, H4, clearl) +GEN_VEXT_VMERGE_VV(vmerge_vvm_d, int64_t, H8, clearq) + +#define GEN_VEXT_VMERGE_VX(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t vlmax = vext_maxsz(desc) / esz; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ + ETYPE d = (!vext_elem_mask(v0, mlen, i) ? s2 : \ + (ETYPE)(target_long)s1); \ + *((ETYPE *)vd + H(i)) = d; \ + } \ + CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \ +} + +GEN_VEXT_VMERGE_VX(vmerge_vxm_b, int8_t, H1, clearb) +GEN_VEXT_VMERGE_VX(vmerge_vxm_h, int16_t, H2, clearh) +GEN_VEXT_VMERGE_VX(vmerge_vxm_w, int32_t, H4, clearl) +GEN_VEXT_VMERGE_VX(vmerge_vxm_d, int64_t, H8, clearq) From eb2650e35ec1ed60ff302ce3330bd6c770640833 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:12 +0800 Subject: [PATCH 1825/2595] target/riscv: vector single-width saturating add and subtract Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-25-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 33 ++ target/riscv/insn32.decode | 10 + target/riscv/insn_trans/trans_rvv.inc.c | 16 + target/riscv/vector_helper.c | 385 ++++++++++++++++++++++++ 4 files changed, 444 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 9851086730..85bd4b91bc 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -692,3 +692,36 @@ DEF_HELPER_4(vmv_v_x_b, void, ptr, i64, env, i32) DEF_HELPER_4(vmv_v_x_h, void, ptr, i64, env, i32) DEF_HELPER_4(vmv_v_x_w, void, ptr, i64, env, i32) DEF_HELPER_4(vmv_v_x_d, void, ptr, i64, env, i32) + +DEF_HELPER_6(vsaddu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsaddu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsaddu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsaddu_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsadd_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssubu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssubu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssubu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssubu_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssub_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssub_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssub_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssub_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsaddu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsaddu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsaddu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsaddu_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsadd_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsadd_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsadd_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsadd_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssubu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssubu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssubu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssubu_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssub_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssub_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssub_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssub_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 238aa014d1..70df42de9a 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -409,6 +409,16 @@ vmv_v_i 010111 1 00000 ..... 011 ..... 1010111 @r2 vmerge_vvm 010111 0 ..... ..... 000 ..... 1010111 @r_vm_0 vmerge_vxm 010111 0 ..... ..... 100 ..... 1010111 @r_vm_0 vmerge_vim 010111 0 ..... ..... 011 ..... 1010111 @r_vm_0 +vsaddu_vv 100000 . ..... ..... 000 ..... 1010111 @r_vm +vsaddu_vx 100000 . ..... ..... 100 ..... 1010111 @r_vm +vsaddu_vi 100000 . ..... ..... 011 ..... 1010111 @r_vm +vsadd_vv 100001 . ..... ..... 000 ..... 1010111 @r_vm +vsadd_vx 100001 . ..... ..... 100 ..... 1010111 @r_vm +vsadd_vi 100001 . ..... ..... 011 ..... 1010111 @r_vm +vssubu_vv 100010 . ..... ..... 000 ..... 1010111 @r_vm +vssubu_vx 100010 . ..... ..... 100 ..... 1010111 @r_vm +vssub_vv 100011 . ..... ..... 000 ..... 1010111 @r_vm +vssub_vx 100011 . ..... ..... 100 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index f9532ebc71..a2ab14ade0 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1731,3 +1731,19 @@ static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check) GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check) GEN_OPIVI_TRANS(vmerge_vim, 0, vmerge_vxm, opivx_vadc_check) + +/* + *** Vector Fixed-Point Arithmetic Instructions + */ + +/* Vector Single-Width Saturating Add and Subtract */ +GEN_OPIVV_TRANS(vsaddu_vv, opivv_check) +GEN_OPIVV_TRANS(vsadd_vv, opivv_check) +GEN_OPIVV_TRANS(vssubu_vv, opivv_check) +GEN_OPIVV_TRANS(vssub_vv, opivv_check) +GEN_OPIVX_TRANS(vsaddu_vx, opivx_check) +GEN_OPIVX_TRANS(vsadd_vx, opivx_check) +GEN_OPIVX_TRANS(vssubu_vx, opivx_check) +GEN_OPIVX_TRANS(vssub_vx, opivx_check) +GEN_OPIVI_TRANS(vsaddu_vi, 1, vsaddu_vx, opivx_check) +GEN_OPIVI_TRANS(vsadd_vi, 0, vsadd_vx, opivx_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 92d90d07d6..1277aa1c10 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -2112,3 +2112,388 @@ GEN_VEXT_VMERGE_VX(vmerge_vxm_b, int8_t, H1, clearb) GEN_VEXT_VMERGE_VX(vmerge_vxm_h, int16_t, H2, clearh) GEN_VEXT_VMERGE_VX(vmerge_vxm_w, int32_t, H4, clearl) GEN_VEXT_VMERGE_VX(vmerge_vxm_d, int64_t, H8, clearq) + +/* + *** Vector Fixed-Point Arithmetic Instructions + */ + +/* Vector Single-Width Saturating Add and Subtract */ + +/* + * As fixed point instructions probably have round mode and saturation, + * define common macros for fixed point here. + */ +typedef void opivv2_rm_fn(void *vd, void *vs1, void *vs2, int i, + CPURISCVState *env, int vxrm); + +#define OPIVV2_RM(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ +static inline void \ +do_##NAME(void *vd, void *vs1, void *vs2, int i, \ + CPURISCVState *env, int vxrm) \ +{ \ + TX1 s1 = *((T1 *)vs1 + HS1(i)); \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + *((TD *)vd + HD(i)) = OP(env, vxrm, s2, s1); \ +} + +static inline void +vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2, + CPURISCVState *env, + uint32_t vl, uint32_t vm, uint32_t mlen, int vxrm, + opivv2_rm_fn *fn) +{ + for (uint32_t i = 0; i < vl; i++) { + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + fn(vd, vs1, vs2, i, env, vxrm); + } +} + +static inline void +vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2, + CPURISCVState *env, + uint32_t desc, uint32_t esz, uint32_t dsz, + opivv2_rm_fn *fn, clear_fn *clearfn) +{ + uint32_t vlmax = vext_maxsz(desc) / esz; + uint32_t mlen = vext_mlen(desc); + uint32_t vm = vext_vm(desc); + uint32_t vl = env->vl; + + switch (env->vxrm) { + case 0: /* rnu */ + vext_vv_rm_1(vd, v0, vs1, vs2, + env, vl, vm, mlen, 0, fn); + break; + case 1: /* rne */ + vext_vv_rm_1(vd, v0, vs1, vs2, + env, vl, vm, mlen, 1, fn); + break; + case 2: /* rdn */ + vext_vv_rm_1(vd, v0, vs1, vs2, + env, vl, vm, mlen, 2, fn); + break; + default: /* rod */ + vext_vv_rm_1(vd, v0, vs1, vs2, + env, vl, vm, mlen, 3, fn); + break; + } + + clearfn(vd, vl, vl * dsz, vlmax * dsz); +} + +/* generate helpers for fixed point instructions with OPIVV format */ +#define GEN_VEXT_VV_RM(NAME, ESZ, DSZ, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + vext_vv_rm_2(vd, v0, vs1, vs2, env, desc, ESZ, DSZ, \ + do_##NAME, CLEAR_FN); \ +} + +static inline uint8_t saddu8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b) +{ + uint8_t res = a + b; + if (res < a) { + res = UINT8_MAX; + env->vxsat = 0x1; + } + return res; +} + +static inline uint16_t saddu16(CPURISCVState *env, int vxrm, uint16_t a, + uint16_t b) +{ + uint16_t res = a + b; + if (res < a) { + res = UINT16_MAX; + env->vxsat = 0x1; + } + return res; +} + +static inline uint32_t saddu32(CPURISCVState *env, int vxrm, uint32_t a, + uint32_t b) +{ + uint32_t res = a + b; + if (res < a) { + res = UINT32_MAX; + env->vxsat = 0x1; + } + return res; +} + +static inline uint64_t saddu64(CPURISCVState *env, int vxrm, uint64_t a, + uint64_t b) +{ + uint64_t res = a + b; + if (res < a) { + res = UINT64_MAX; + env->vxsat = 0x1; + } + return res; +} + +RVVCALL(OPIVV2_RM, vsaddu_vv_b, OP_UUU_B, H1, H1, H1, saddu8) +RVVCALL(OPIVV2_RM, vsaddu_vv_h, OP_UUU_H, H2, H2, H2, saddu16) +RVVCALL(OPIVV2_RM, vsaddu_vv_w, OP_UUU_W, H4, H4, H4, saddu32) +RVVCALL(OPIVV2_RM, vsaddu_vv_d, OP_UUU_D, H8, H8, H8, saddu64) +GEN_VEXT_VV_RM(vsaddu_vv_b, 1, 1, clearb) +GEN_VEXT_VV_RM(vsaddu_vv_h, 2, 2, clearh) +GEN_VEXT_VV_RM(vsaddu_vv_w, 4, 4, clearl) +GEN_VEXT_VV_RM(vsaddu_vv_d, 8, 8, clearq) + +typedef void opivx2_rm_fn(void *vd, target_long s1, void *vs2, int i, + CPURISCVState *env, int vxrm); + +#define OPIVX2_RM(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ +static inline void \ +do_##NAME(void *vd, target_long s1, void *vs2, int i, \ + CPURISCVState *env, int vxrm) \ +{ \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + *((TD *)vd + HD(i)) = OP(env, vxrm, s2, (TX1)(T1)s1); \ +} + +static inline void +vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2, + CPURISCVState *env, + uint32_t vl, uint32_t vm, uint32_t mlen, int vxrm, + opivx2_rm_fn *fn) +{ + for (uint32_t i = 0; i < vl; i++) { + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + fn(vd, s1, vs2, i, env, vxrm); + } +} + +static inline void +vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2, + CPURISCVState *env, + uint32_t desc, uint32_t esz, uint32_t dsz, + opivx2_rm_fn *fn, clear_fn *clearfn) +{ + uint32_t vlmax = vext_maxsz(desc) / esz; + uint32_t mlen = vext_mlen(desc); + uint32_t vm = vext_vm(desc); + uint32_t vl = env->vl; + + switch (env->vxrm) { + case 0: /* rnu */ + vext_vx_rm_1(vd, v0, s1, vs2, + env, vl, vm, mlen, 0, fn); + break; + case 1: /* rne */ + vext_vx_rm_1(vd, v0, s1, vs2, + env, vl, vm, mlen, 1, fn); + break; + case 2: /* rdn */ + vext_vx_rm_1(vd, v0, s1, vs2, + env, vl, vm, mlen, 2, fn); + break; + default: /* rod */ + vext_vx_rm_1(vd, v0, s1, vs2, + env, vl, vm, mlen, 3, fn); + break; + } + + clearfn(vd, vl, vl * dsz, vlmax * dsz); +} + +/* generate helpers for fixed point instructions with OPIVX format */ +#define GEN_VEXT_VX_RM(NAME, ESZ, DSZ, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ +{ \ + vext_vx_rm_2(vd, v0, s1, vs2, env, desc, ESZ, DSZ, \ + do_##NAME, CLEAR_FN); \ +} + +RVVCALL(OPIVX2_RM, vsaddu_vx_b, OP_UUU_B, H1, H1, saddu8) +RVVCALL(OPIVX2_RM, vsaddu_vx_h, OP_UUU_H, H2, H2, saddu16) +RVVCALL(OPIVX2_RM, vsaddu_vx_w, OP_UUU_W, H4, H4, saddu32) +RVVCALL(OPIVX2_RM, vsaddu_vx_d, OP_UUU_D, H8, H8, saddu64) +GEN_VEXT_VX_RM(vsaddu_vx_b, 1, 1, clearb) +GEN_VEXT_VX_RM(vsaddu_vx_h, 2, 2, clearh) +GEN_VEXT_VX_RM(vsaddu_vx_w, 4, 4, clearl) +GEN_VEXT_VX_RM(vsaddu_vx_d, 8, 8, clearq) + +static inline int8_t sadd8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) +{ + int8_t res = a + b; + if ((res ^ a) & (res ^ b) & INT8_MIN) { + res = a > 0 ? INT8_MAX : INT8_MIN; + env->vxsat = 0x1; + } + return res; +} + +static inline int16_t sadd16(CPURISCVState *env, int vxrm, int16_t a, int16_t b) +{ + int16_t res = a + b; + if ((res ^ a) & (res ^ b) & INT16_MIN) { + res = a > 0 ? INT16_MAX : INT16_MIN; + env->vxsat = 0x1; + } + return res; +} + +static inline int32_t sadd32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) +{ + int32_t res = a + b; + if ((res ^ a) & (res ^ b) & INT32_MIN) { + res = a > 0 ? INT32_MAX : INT32_MIN; + env->vxsat = 0x1; + } + return res; +} + +static inline int64_t sadd64(CPURISCVState *env, int vxrm, int64_t a, int64_t b) +{ + int64_t res = a + b; + if ((res ^ a) & (res ^ b) & INT64_MIN) { + res = a > 0 ? INT64_MAX : INT64_MIN; + env->vxsat = 0x1; + } + return res; +} + +RVVCALL(OPIVV2_RM, vsadd_vv_b, OP_SSS_B, H1, H1, H1, sadd8) +RVVCALL(OPIVV2_RM, vsadd_vv_h, OP_SSS_H, H2, H2, H2, sadd16) +RVVCALL(OPIVV2_RM, vsadd_vv_w, OP_SSS_W, H4, H4, H4, sadd32) +RVVCALL(OPIVV2_RM, vsadd_vv_d, OP_SSS_D, H8, H8, H8, sadd64) +GEN_VEXT_VV_RM(vsadd_vv_b, 1, 1, clearb) +GEN_VEXT_VV_RM(vsadd_vv_h, 2, 2, clearh) +GEN_VEXT_VV_RM(vsadd_vv_w, 4, 4, clearl) +GEN_VEXT_VV_RM(vsadd_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2_RM, vsadd_vx_b, OP_SSS_B, H1, H1, sadd8) +RVVCALL(OPIVX2_RM, vsadd_vx_h, OP_SSS_H, H2, H2, sadd16) +RVVCALL(OPIVX2_RM, vsadd_vx_w, OP_SSS_W, H4, H4, sadd32) +RVVCALL(OPIVX2_RM, vsadd_vx_d, OP_SSS_D, H8, H8, sadd64) +GEN_VEXT_VX_RM(vsadd_vx_b, 1, 1, clearb) +GEN_VEXT_VX_RM(vsadd_vx_h, 2, 2, clearh) +GEN_VEXT_VX_RM(vsadd_vx_w, 4, 4, clearl) +GEN_VEXT_VX_RM(vsadd_vx_d, 8, 8, clearq) + +static inline uint8_t ssubu8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b) +{ + uint8_t res = a - b; + if (res > a) { + res = 0; + env->vxsat = 0x1; + } + return res; +} + +static inline uint16_t ssubu16(CPURISCVState *env, int vxrm, uint16_t a, + uint16_t b) +{ + uint16_t res = a - b; + if (res > a) { + res = 0; + env->vxsat = 0x1; + } + return res; +} + +static inline uint32_t ssubu32(CPURISCVState *env, int vxrm, uint32_t a, + uint32_t b) +{ + uint32_t res = a - b; + if (res > a) { + res = 0; + env->vxsat = 0x1; + } + return res; +} + +static inline uint64_t ssubu64(CPURISCVState *env, int vxrm, uint64_t a, + uint64_t b) +{ + uint64_t res = a - b; + if (res > a) { + res = 0; + env->vxsat = 0x1; + } + return res; +} + +RVVCALL(OPIVV2_RM, vssubu_vv_b, OP_UUU_B, H1, H1, H1, ssubu8) +RVVCALL(OPIVV2_RM, vssubu_vv_h, OP_UUU_H, H2, H2, H2, ssubu16) +RVVCALL(OPIVV2_RM, vssubu_vv_w, OP_UUU_W, H4, H4, H4, ssubu32) +RVVCALL(OPIVV2_RM, vssubu_vv_d, OP_UUU_D, H8, H8, H8, ssubu64) +GEN_VEXT_VV_RM(vssubu_vv_b, 1, 1, clearb) +GEN_VEXT_VV_RM(vssubu_vv_h, 2, 2, clearh) +GEN_VEXT_VV_RM(vssubu_vv_w, 4, 4, clearl) +GEN_VEXT_VV_RM(vssubu_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2_RM, vssubu_vx_b, OP_UUU_B, H1, H1, ssubu8) +RVVCALL(OPIVX2_RM, vssubu_vx_h, OP_UUU_H, H2, H2, ssubu16) +RVVCALL(OPIVX2_RM, vssubu_vx_w, OP_UUU_W, H4, H4, ssubu32) +RVVCALL(OPIVX2_RM, vssubu_vx_d, OP_UUU_D, H8, H8, ssubu64) +GEN_VEXT_VX_RM(vssubu_vx_b, 1, 1, clearb) +GEN_VEXT_VX_RM(vssubu_vx_h, 2, 2, clearh) +GEN_VEXT_VX_RM(vssubu_vx_w, 4, 4, clearl) +GEN_VEXT_VX_RM(vssubu_vx_d, 8, 8, clearq) + +static inline int8_t ssub8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) +{ + int8_t res = a - b; + if ((res ^ a) & (a ^ b) & INT8_MIN) { + res = a > 0 ? INT8_MAX : INT8_MIN; + env->vxsat = 0x1; + } + return res; +} + +static inline int16_t ssub16(CPURISCVState *env, int vxrm, int16_t a, int16_t b) +{ + int16_t res = a - b; + if ((res ^ a) & (a ^ b) & INT16_MIN) { + res = a > 0 ? INT16_MAX : INT16_MIN; + env->vxsat = 0x1; + } + return res; +} + +static inline int32_t ssub32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) +{ + int32_t res = a - b; + if ((res ^ a) & (a ^ b) & INT32_MIN) { + res = a > 0 ? INT32_MAX : INT32_MIN; + env->vxsat = 0x1; + } + return res; +} + +static inline int64_t ssub64(CPURISCVState *env, int vxrm, int64_t a, int64_t b) +{ + int64_t res = a - b; + if ((res ^ a) & (a ^ b) & INT64_MIN) { + res = a > 0 ? INT64_MAX : INT64_MIN; + env->vxsat = 0x1; + } + return res; +} + +RVVCALL(OPIVV2_RM, vssub_vv_b, OP_SSS_B, H1, H1, H1, ssub8) +RVVCALL(OPIVV2_RM, vssub_vv_h, OP_SSS_H, H2, H2, H2, ssub16) +RVVCALL(OPIVV2_RM, vssub_vv_w, OP_SSS_W, H4, H4, H4, ssub32) +RVVCALL(OPIVV2_RM, vssub_vv_d, OP_SSS_D, H8, H8, H8, ssub64) +GEN_VEXT_VV_RM(vssub_vv_b, 1, 1, clearb) +GEN_VEXT_VV_RM(vssub_vv_h, 2, 2, clearh) +GEN_VEXT_VV_RM(vssub_vv_w, 4, 4, clearl) +GEN_VEXT_VV_RM(vssub_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2_RM, vssub_vx_b, OP_SSS_B, H1, H1, ssub8) +RVVCALL(OPIVX2_RM, vssub_vx_h, OP_SSS_H, H2, H2, ssub16) +RVVCALL(OPIVX2_RM, vssub_vx_w, OP_SSS_W, H4, H4, ssub32) +RVVCALL(OPIVX2_RM, vssub_vx_d, OP_SSS_D, H8, H8, ssub64) +GEN_VEXT_VX_RM(vssub_vx_b, 1, 1, clearb) +GEN_VEXT_VX_RM(vssub_vx_h, 2, 2, clearh) +GEN_VEXT_VX_RM(vssub_vx_w, 4, 4, clearl) +GEN_VEXT_VX_RM(vssub_vx_d, 8, 8, clearq) From b7aee4819206cbb7adfdb624d4f2fa9918c25d43 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:13 +0800 Subject: [PATCH 1826/2595] target/riscv: vector single-width averaging add and subtract Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-26-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 17 ++++ target/riscv/insn32.decode | 5 ++ target/riscv/insn_trans/trans_rvv.inc.c | 7 ++ target/riscv/vector_helper.c | 100 ++++++++++++++++++++++++ 4 files changed, 129 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 85bd4b91bc..db9e2024ae 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -725,3 +725,20 @@ DEF_HELPER_6(vssub_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vssub_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vssub_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vssub_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vaadd_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vaadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vaadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vaadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vasub_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vasub_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vasub_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vasub_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vaadd_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vaadd_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vaadd_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vaadd_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vasub_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vasub_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vasub_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vasub_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 70df42de9a..57228242aa 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -419,6 +419,11 @@ vssubu_vv 100010 . ..... ..... 000 ..... 1010111 @r_vm vssubu_vx 100010 . ..... ..... 100 ..... 1010111 @r_vm vssub_vv 100011 . ..... ..... 000 ..... 1010111 @r_vm vssub_vx 100011 . ..... ..... 100 ..... 1010111 @r_vm +vaadd_vv 100100 . ..... ..... 000 ..... 1010111 @r_vm +vaadd_vx 100100 . ..... ..... 100 ..... 1010111 @r_vm +vaadd_vi 100100 . ..... ..... 011 ..... 1010111 @r_vm +vasub_vv 100110 . ..... ..... 000 ..... 1010111 @r_vm +vasub_vx 100110 . ..... ..... 100 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index a2ab14ade0..354a802518 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1747,3 +1747,10 @@ GEN_OPIVX_TRANS(vssubu_vx, opivx_check) GEN_OPIVX_TRANS(vssub_vx, opivx_check) GEN_OPIVI_TRANS(vsaddu_vi, 1, vsaddu_vx, opivx_check) GEN_OPIVI_TRANS(vsadd_vi, 0, vsadd_vx, opivx_check) + +/* Vector Single-Width Averaging Add and Subtract */ +GEN_OPIVV_TRANS(vaadd_vv, opivv_check) +GEN_OPIVV_TRANS(vasub_vv, opivv_check) +GEN_OPIVX_TRANS(vaadd_vx, opivx_check) +GEN_OPIVX_TRANS(vasub_vx, opivx_check) +GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 1277aa1c10..0b2119b6cc 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -2497,3 +2497,103 @@ GEN_VEXT_VX_RM(vssub_vx_b, 1, 1, clearb) GEN_VEXT_VX_RM(vssub_vx_h, 2, 2, clearh) GEN_VEXT_VX_RM(vssub_vx_w, 4, 4, clearl) GEN_VEXT_VX_RM(vssub_vx_d, 8, 8, clearq) + +/* Vector Single-Width Averaging Add and Subtract */ +static inline uint8_t get_round(int vxrm, uint64_t v, uint8_t shift) +{ + uint8_t d = extract64(v, shift, 1); + uint8_t d1; + uint64_t D1, D2; + + if (shift == 0 || shift > 64) { + return 0; + } + + d1 = extract64(v, shift - 1, 1); + D1 = extract64(v, 0, shift); + if (vxrm == 0) { /* round-to-nearest-up (add +0.5 LSB) */ + return d1; + } else if (vxrm == 1) { /* round-to-nearest-even */ + if (shift > 1) { + D2 = extract64(v, 0, shift - 1); + return d1 & ((D2 != 0) | d); + } else { + return d1 & d; + } + } else if (vxrm == 3) { /* round-to-odd (OR bits into LSB, aka "jam") */ + return !d & (D1 != 0); + } + return 0; /* round-down (truncate) */ +} + +static inline int32_t aadd32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) +{ + int64_t res = (int64_t)a + b; + uint8_t round = get_round(vxrm, res, 1); + + return (res >> 1) + round; +} + +static inline int64_t aadd64(CPURISCVState *env, int vxrm, int64_t a, int64_t b) +{ + int64_t res = a + b; + uint8_t round = get_round(vxrm, res, 1); + int64_t over = (res ^ a) & (res ^ b) & INT64_MIN; + + /* With signed overflow, bit 64 is inverse of bit 63. */ + return ((res >> 1) ^ over) + round; +} + +RVVCALL(OPIVV2_RM, vaadd_vv_b, OP_SSS_B, H1, H1, H1, aadd32) +RVVCALL(OPIVV2_RM, vaadd_vv_h, OP_SSS_H, H2, H2, H2, aadd32) +RVVCALL(OPIVV2_RM, vaadd_vv_w, OP_SSS_W, H4, H4, H4, aadd32) +RVVCALL(OPIVV2_RM, vaadd_vv_d, OP_SSS_D, H8, H8, H8, aadd64) +GEN_VEXT_VV_RM(vaadd_vv_b, 1, 1, clearb) +GEN_VEXT_VV_RM(vaadd_vv_h, 2, 2, clearh) +GEN_VEXT_VV_RM(vaadd_vv_w, 4, 4, clearl) +GEN_VEXT_VV_RM(vaadd_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2_RM, vaadd_vx_b, OP_SSS_B, H1, H1, aadd32) +RVVCALL(OPIVX2_RM, vaadd_vx_h, OP_SSS_H, H2, H2, aadd32) +RVVCALL(OPIVX2_RM, vaadd_vx_w, OP_SSS_W, H4, H4, aadd32) +RVVCALL(OPIVX2_RM, vaadd_vx_d, OP_SSS_D, H8, H8, aadd64) +GEN_VEXT_VX_RM(vaadd_vx_b, 1, 1, clearb) +GEN_VEXT_VX_RM(vaadd_vx_h, 2, 2, clearh) +GEN_VEXT_VX_RM(vaadd_vx_w, 4, 4, clearl) +GEN_VEXT_VX_RM(vaadd_vx_d, 8, 8, clearq) + +static inline int32_t asub32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) +{ + int64_t res = (int64_t)a - b; + uint8_t round = get_round(vxrm, res, 1); + + return (res >> 1) + round; +} + +static inline int64_t asub64(CPURISCVState *env, int vxrm, int64_t a, int64_t b) +{ + int64_t res = (int64_t)a - b; + uint8_t round = get_round(vxrm, res, 1); + int64_t over = (res ^ a) & (a ^ b) & INT64_MIN; + + /* With signed overflow, bit 64 is inverse of bit 63. */ + return ((res >> 1) ^ over) + round; +} + +RVVCALL(OPIVV2_RM, vasub_vv_b, OP_SSS_B, H1, H1, H1, asub32) +RVVCALL(OPIVV2_RM, vasub_vv_h, OP_SSS_H, H2, H2, H2, asub32) +RVVCALL(OPIVV2_RM, vasub_vv_w, OP_SSS_W, H4, H4, H4, asub32) +RVVCALL(OPIVV2_RM, vasub_vv_d, OP_SSS_D, H8, H8, H8, asub64) +GEN_VEXT_VV_RM(vasub_vv_b, 1, 1, clearb) +GEN_VEXT_VV_RM(vasub_vv_h, 2, 2, clearh) +GEN_VEXT_VV_RM(vasub_vv_w, 4, 4, clearl) +GEN_VEXT_VV_RM(vasub_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2_RM, vasub_vx_b, OP_SSS_B, H1, H1, asub32) +RVVCALL(OPIVX2_RM, vasub_vx_h, OP_SSS_H, H2, H2, asub32) +RVVCALL(OPIVX2_RM, vasub_vx_w, OP_SSS_W, H4, H4, asub32) +RVVCALL(OPIVX2_RM, vasub_vx_d, OP_SSS_D, H8, H8, asub64) +GEN_VEXT_VX_RM(vasub_vx_b, 1, 1, clearb) +GEN_VEXT_VX_RM(vasub_vx_h, 2, 2, clearh) +GEN_VEXT_VX_RM(vasub_vx_w, 4, 4, clearl) +GEN_VEXT_VX_RM(vasub_vx_d, 8, 8, clearq) From 9f0ff9e51480f8f1d2d7a62b11aa156fcdb4ef95 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:14 +0800 Subject: [PATCH 1827/2595] target/riscv: vector single-width fractional multiply with rounding and saturation Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-27-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 9 ++ target/riscv/insn32.decode | 2 + target/riscv/insn_trans/trans_rvv.inc.c | 4 + target/riscv/vector_helper.c | 107 ++++++++++++++++++++++++ 4 files changed, 122 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index db9e2024ae..b2fc71c2ea 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -742,3 +742,12 @@ DEF_HELPER_6(vasub_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vasub_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vasub_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vasub_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vsmul_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsmul_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsmul_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsmul_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vsmul_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsmul_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsmul_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vsmul_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 57228242aa..1dfc5f7ca0 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -424,6 +424,8 @@ vaadd_vx 100100 . ..... ..... 100 ..... 1010111 @r_vm vaadd_vi 100100 . ..... ..... 011 ..... 1010111 @r_vm vasub_vv 100110 . ..... ..... 000 ..... 1010111 @r_vm vasub_vx 100110 . ..... ..... 100 ..... 1010111 @r_vm +vsmul_vv 100111 . ..... ..... 000 ..... 1010111 @r_vm +vsmul_vx 100111 . ..... ..... 100 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 354a802518..8e85a2aed3 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1754,3 +1754,7 @@ GEN_OPIVV_TRANS(vasub_vv, opivv_check) GEN_OPIVX_TRANS(vaadd_vx, opivx_check) GEN_OPIVX_TRANS(vasub_vx, opivx_check) GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check) + +/* Vector Single-Width Fractional Multiply with Rounding and Saturation */ +GEN_OPIVV_TRANS(vsmul_vv, opivv_check) +GEN_OPIVX_TRANS(vsmul_vx, opivx_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 0b2119b6cc..d062d904ca 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -2597,3 +2597,110 @@ GEN_VEXT_VX_RM(vasub_vx_b, 1, 1, clearb) GEN_VEXT_VX_RM(vasub_vx_h, 2, 2, clearh) GEN_VEXT_VX_RM(vasub_vx_w, 4, 4, clearl) GEN_VEXT_VX_RM(vasub_vx_d, 8, 8, clearq) + +/* Vector Single-Width Fractional Multiply with Rounding and Saturation */ +static inline int8_t vsmul8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) +{ + uint8_t round; + int16_t res; + + res = (int16_t)a * (int16_t)b; + round = get_round(vxrm, res, 7); + res = (res >> 7) + round; + + if (res > INT8_MAX) { + env->vxsat = 0x1; + return INT8_MAX; + } else if (res < INT8_MIN) { + env->vxsat = 0x1; + return INT8_MIN; + } else { + return res; + } +} + +static int16_t vsmul16(CPURISCVState *env, int vxrm, int16_t a, int16_t b) +{ + uint8_t round; + int32_t res; + + res = (int32_t)a * (int32_t)b; + round = get_round(vxrm, res, 15); + res = (res >> 15) + round; + + if (res > INT16_MAX) { + env->vxsat = 0x1; + return INT16_MAX; + } else if (res < INT16_MIN) { + env->vxsat = 0x1; + return INT16_MIN; + } else { + return res; + } +} + +static int32_t vsmul32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) +{ + uint8_t round; + int64_t res; + + res = (int64_t)a * (int64_t)b; + round = get_round(vxrm, res, 31); + res = (res >> 31) + round; + + if (res > INT32_MAX) { + env->vxsat = 0x1; + return INT32_MAX; + } else if (res < INT32_MIN) { + env->vxsat = 0x1; + return INT32_MIN; + } else { + return res; + } +} + +static int64_t vsmul64(CPURISCVState *env, int vxrm, int64_t a, int64_t b) +{ + uint8_t round; + uint64_t hi_64, lo_64; + int64_t res; + + if (a == INT64_MIN && b == INT64_MIN) { + env->vxsat = 1; + return INT64_MAX; + } + + muls64(&lo_64, &hi_64, a, b); + round = get_round(vxrm, lo_64, 63); + /* + * Cannot overflow, as there are always + * 2 sign bits after multiply. + */ + res = (hi_64 << 1) | (lo_64 >> 63); + if (round) { + if (res == INT64_MAX) { + env->vxsat = 1; + } else { + res += 1; + } + } + return res; +} + +RVVCALL(OPIVV2_RM, vsmul_vv_b, OP_SSS_B, H1, H1, H1, vsmul8) +RVVCALL(OPIVV2_RM, vsmul_vv_h, OP_SSS_H, H2, H2, H2, vsmul16) +RVVCALL(OPIVV2_RM, vsmul_vv_w, OP_SSS_W, H4, H4, H4, vsmul32) +RVVCALL(OPIVV2_RM, vsmul_vv_d, OP_SSS_D, H8, H8, H8, vsmul64) +GEN_VEXT_VV_RM(vsmul_vv_b, 1, 1, clearb) +GEN_VEXT_VV_RM(vsmul_vv_h, 2, 2, clearh) +GEN_VEXT_VV_RM(vsmul_vv_w, 4, 4, clearl) +GEN_VEXT_VV_RM(vsmul_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2_RM, vsmul_vx_b, OP_SSS_B, H1, H1, vsmul8) +RVVCALL(OPIVX2_RM, vsmul_vx_h, OP_SSS_H, H2, H2, vsmul16) +RVVCALL(OPIVX2_RM, vsmul_vx_w, OP_SSS_W, H4, H4, vsmul32) +RVVCALL(OPIVX2_RM, vsmul_vx_d, OP_SSS_D, H8, H8, vsmul64) +GEN_VEXT_VX_RM(vsmul_vx_b, 1, 1, clearb) +GEN_VEXT_VX_RM(vsmul_vx_h, 2, 2, clearh) +GEN_VEXT_VX_RM(vsmul_vx_w, 4, 4, clearl) +GEN_VEXT_VX_RM(vsmul_vx_d, 8, 8, clearq) From 0a1eaf0036442b2bfa69df7fad9a5f1d6a4984f2 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:15 +0800 Subject: [PATCH 1828/2595] target/riscv: vector widening saturating scaled multiply-add Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-28-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 22 +++ target/riscv/insn32.decode | 7 + target/riscv/insn_trans/trans_rvv.inc.c | 9 ++ target/riscv/vector_helper.c | 205 ++++++++++++++++++++++++ 4 files changed, 243 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index b2fc71c2ea..f123302b82 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -751,3 +751,25 @@ DEF_HELPER_6(vsmul_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vsmul_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vsmul_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vsmul_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vwsmaccu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsmaccu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsmaccu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsmacc_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsmaccsu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsmaccsu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsmaccsu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwsmaccu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsmaccu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsmaccu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsmacc_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsmacc_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsmacc_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsmaccsu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsmaccsu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsmaccsu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsmaccus_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsmaccus_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vwsmaccus_vx_w, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 1dfc5f7ca0..8cc2bf4864 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -426,6 +426,13 @@ vasub_vv 100110 . ..... ..... 000 ..... 1010111 @r_vm vasub_vx 100110 . ..... ..... 100 ..... 1010111 @r_vm vsmul_vv 100111 . ..... ..... 000 ..... 1010111 @r_vm vsmul_vx 100111 . ..... ..... 100 ..... 1010111 @r_vm +vwsmaccu_vv 111100 . ..... ..... 000 ..... 1010111 @r_vm +vwsmaccu_vx 111100 . ..... ..... 100 ..... 1010111 @r_vm +vwsmacc_vv 111101 . ..... ..... 000 ..... 1010111 @r_vm +vwsmacc_vx 111101 . ..... ..... 100 ..... 1010111 @r_vm +vwsmaccsu_vv 111110 . ..... ..... 000 ..... 1010111 @r_vm +vwsmaccsu_vx 111110 . ..... ..... 100 ..... 1010111 @r_vm +vwsmaccus_vx 111111 . ..... ..... 100 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 8e85a2aed3..5e36ee8de5 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1758,3 +1758,12 @@ GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check) /* Vector Single-Width Fractional Multiply with Rounding and Saturation */ GEN_OPIVV_TRANS(vsmul_vv, opivv_check) GEN_OPIVX_TRANS(vsmul_vx, opivx_check) + +/* Vector Widening Saturating Scaled Multiply-Add */ +GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check) +GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx) +GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx) +GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx) +GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index d062d904ca..d818c32d97 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -2704,3 +2704,208 @@ GEN_VEXT_VX_RM(vsmul_vx_b, 1, 1, clearb) GEN_VEXT_VX_RM(vsmul_vx_h, 2, 2, clearh) GEN_VEXT_VX_RM(vsmul_vx_w, 4, 4, clearl) GEN_VEXT_VX_RM(vsmul_vx_d, 8, 8, clearq) + +/* Vector Widening Saturating Scaled Multiply-Add */ +static inline uint16_t +vwsmaccu8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b, + uint16_t c) +{ + uint8_t round; + uint16_t res = (uint16_t)a * b; + + round = get_round(vxrm, res, 4); + res = (res >> 4) + round; + return saddu16(env, vxrm, c, res); +} + +static inline uint32_t +vwsmaccu16(CPURISCVState *env, int vxrm, uint16_t a, uint16_t b, + uint32_t c) +{ + uint8_t round; + uint32_t res = (uint32_t)a * b; + + round = get_round(vxrm, res, 8); + res = (res >> 8) + round; + return saddu32(env, vxrm, c, res); +} + +static inline uint64_t +vwsmaccu32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b, + uint64_t c) +{ + uint8_t round; + uint64_t res = (uint64_t)a * b; + + round = get_round(vxrm, res, 16); + res = (res >> 16) + round; + return saddu64(env, vxrm, c, res); +} + +#define OPIVV3_RM(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ +static inline void \ +do_##NAME(void *vd, void *vs1, void *vs2, int i, \ + CPURISCVState *env, int vxrm) \ +{ \ + TX1 s1 = *((T1 *)vs1 + HS1(i)); \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + TD d = *((TD *)vd + HD(i)); \ + *((TD *)vd + HD(i)) = OP(env, vxrm, s2, s1, d); \ +} + +RVVCALL(OPIVV3_RM, vwsmaccu_vv_b, WOP_UUU_B, H2, H1, H1, vwsmaccu8) +RVVCALL(OPIVV3_RM, vwsmaccu_vv_h, WOP_UUU_H, H4, H2, H2, vwsmaccu16) +RVVCALL(OPIVV3_RM, vwsmaccu_vv_w, WOP_UUU_W, H8, H4, H4, vwsmaccu32) +GEN_VEXT_VV_RM(vwsmaccu_vv_b, 1, 2, clearh) +GEN_VEXT_VV_RM(vwsmaccu_vv_h, 2, 4, clearl) +GEN_VEXT_VV_RM(vwsmaccu_vv_w, 4, 8, clearq) + +#define OPIVX3_RM(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ +static inline void \ +do_##NAME(void *vd, target_long s1, void *vs2, int i, \ + CPURISCVState *env, int vxrm) \ +{ \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + TD d = *((TD *)vd + HD(i)); \ + *((TD *)vd + HD(i)) = OP(env, vxrm, s2, (TX1)(T1)s1, d); \ +} + +RVVCALL(OPIVX3_RM, vwsmaccu_vx_b, WOP_UUU_B, H2, H1, vwsmaccu8) +RVVCALL(OPIVX3_RM, vwsmaccu_vx_h, WOP_UUU_H, H4, H2, vwsmaccu16) +RVVCALL(OPIVX3_RM, vwsmaccu_vx_w, WOP_UUU_W, H8, H4, vwsmaccu32) +GEN_VEXT_VX_RM(vwsmaccu_vx_b, 1, 2, clearh) +GEN_VEXT_VX_RM(vwsmaccu_vx_h, 2, 4, clearl) +GEN_VEXT_VX_RM(vwsmaccu_vx_w, 4, 8, clearq) + +static inline int16_t +vwsmacc8(CPURISCVState *env, int vxrm, int8_t a, int8_t b, int16_t c) +{ + uint8_t round; + int16_t res = (int16_t)a * b; + + round = get_round(vxrm, res, 4); + res = (res >> 4) + round; + return sadd16(env, vxrm, c, res); +} + +static inline int32_t +vwsmacc16(CPURISCVState *env, int vxrm, int16_t a, int16_t b, int32_t c) +{ + uint8_t round; + int32_t res = (int32_t)a * b; + + round = get_round(vxrm, res, 8); + res = (res >> 8) + round; + return sadd32(env, vxrm, c, res); + +} + +static inline int64_t +vwsmacc32(CPURISCVState *env, int vxrm, int32_t a, int32_t b, int64_t c) +{ + uint8_t round; + int64_t res = (int64_t)a * b; + + round = get_round(vxrm, res, 16); + res = (res >> 16) + round; + return sadd64(env, vxrm, c, res); +} + +RVVCALL(OPIVV3_RM, vwsmacc_vv_b, WOP_SSS_B, H2, H1, H1, vwsmacc8) +RVVCALL(OPIVV3_RM, vwsmacc_vv_h, WOP_SSS_H, H4, H2, H2, vwsmacc16) +RVVCALL(OPIVV3_RM, vwsmacc_vv_w, WOP_SSS_W, H8, H4, H4, vwsmacc32) +GEN_VEXT_VV_RM(vwsmacc_vv_b, 1, 2, clearh) +GEN_VEXT_VV_RM(vwsmacc_vv_h, 2, 4, clearl) +GEN_VEXT_VV_RM(vwsmacc_vv_w, 4, 8, clearq) +RVVCALL(OPIVX3_RM, vwsmacc_vx_b, WOP_SSS_B, H2, H1, vwsmacc8) +RVVCALL(OPIVX3_RM, vwsmacc_vx_h, WOP_SSS_H, H4, H2, vwsmacc16) +RVVCALL(OPIVX3_RM, vwsmacc_vx_w, WOP_SSS_W, H8, H4, vwsmacc32) +GEN_VEXT_VX_RM(vwsmacc_vx_b, 1, 2, clearh) +GEN_VEXT_VX_RM(vwsmacc_vx_h, 2, 4, clearl) +GEN_VEXT_VX_RM(vwsmacc_vx_w, 4, 8, clearq) + +static inline int16_t +vwsmaccsu8(CPURISCVState *env, int vxrm, uint8_t a, int8_t b, int16_t c) +{ + uint8_t round; + int16_t res = a * (int16_t)b; + + round = get_round(vxrm, res, 4); + res = (res >> 4) + round; + return ssub16(env, vxrm, c, res); +} + +static inline int32_t +vwsmaccsu16(CPURISCVState *env, int vxrm, uint16_t a, int16_t b, uint32_t c) +{ + uint8_t round; + int32_t res = a * (int32_t)b; + + round = get_round(vxrm, res, 8); + res = (res >> 8) + round; + return ssub32(env, vxrm, c, res); +} + +static inline int64_t +vwsmaccsu32(CPURISCVState *env, int vxrm, uint32_t a, int32_t b, int64_t c) +{ + uint8_t round; + int64_t res = a * (int64_t)b; + + round = get_round(vxrm, res, 16); + res = (res >> 16) + round; + return ssub64(env, vxrm, c, res); +} + +RVVCALL(OPIVV3_RM, vwsmaccsu_vv_b, WOP_SSU_B, H2, H1, H1, vwsmaccsu8) +RVVCALL(OPIVV3_RM, vwsmaccsu_vv_h, WOP_SSU_H, H4, H2, H2, vwsmaccsu16) +RVVCALL(OPIVV3_RM, vwsmaccsu_vv_w, WOP_SSU_W, H8, H4, H4, vwsmaccsu32) +GEN_VEXT_VV_RM(vwsmaccsu_vv_b, 1, 2, clearh) +GEN_VEXT_VV_RM(vwsmaccsu_vv_h, 2, 4, clearl) +GEN_VEXT_VV_RM(vwsmaccsu_vv_w, 4, 8, clearq) +RVVCALL(OPIVX3_RM, vwsmaccsu_vx_b, WOP_SSU_B, H2, H1, vwsmaccsu8) +RVVCALL(OPIVX3_RM, vwsmaccsu_vx_h, WOP_SSU_H, H4, H2, vwsmaccsu16) +RVVCALL(OPIVX3_RM, vwsmaccsu_vx_w, WOP_SSU_W, H8, H4, vwsmaccsu32) +GEN_VEXT_VX_RM(vwsmaccsu_vx_b, 1, 2, clearh) +GEN_VEXT_VX_RM(vwsmaccsu_vx_h, 2, 4, clearl) +GEN_VEXT_VX_RM(vwsmaccsu_vx_w, 4, 8, clearq) + +static inline int16_t +vwsmaccus8(CPURISCVState *env, int vxrm, int8_t a, uint8_t b, int16_t c) +{ + uint8_t round; + int16_t res = (int16_t)a * b; + + round = get_round(vxrm, res, 4); + res = (res >> 4) + round; + return ssub16(env, vxrm, c, res); +} + +static inline int32_t +vwsmaccus16(CPURISCVState *env, int vxrm, int16_t a, uint16_t b, int32_t c) +{ + uint8_t round; + int32_t res = (int32_t)a * b; + + round = get_round(vxrm, res, 8); + res = (res >> 8) + round; + return ssub32(env, vxrm, c, res); +} + +static inline int64_t +vwsmaccus32(CPURISCVState *env, int vxrm, int32_t a, uint32_t b, int64_t c) +{ + uint8_t round; + int64_t res = (int64_t)a * b; + + round = get_round(vxrm, res, 16); + res = (res >> 16) + round; + return ssub64(env, vxrm, c, res); +} + +RVVCALL(OPIVX3_RM, vwsmaccus_vx_b, WOP_SUS_B, H2, H1, vwsmaccus8) +RVVCALL(OPIVX3_RM, vwsmaccus_vx_h, WOP_SUS_H, H4, H2, vwsmaccus16) +RVVCALL(OPIVX3_RM, vwsmaccus_vx_w, WOP_SUS_W, H8, H4, vwsmaccus32) +GEN_VEXT_VX_RM(vwsmaccus_vx_b, 1, 2, clearh) +GEN_VEXT_VX_RM(vwsmaccus_vx_h, 2, 4, clearl) +GEN_VEXT_VX_RM(vwsmaccus_vx_w, 4, 8, clearq) From 04a614062dd5fb43f00bd955f44f7a2c3def016d Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:16 +0800 Subject: [PATCH 1829/2595] target/riscv: vector single-width scaling shift instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-29-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 17 ++++ target/riscv/insn32.decode | 6 ++ target/riscv/insn_trans/trans_rvv.inc.c | 8 ++ target/riscv/vector_helper.c | 117 ++++++++++++++++++++++++ 4 files changed, 148 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index f123302b82..78438f1ad6 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -773,3 +773,20 @@ DEF_HELPER_6(vwsmaccsu_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwsmaccus_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwsmaccus_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vwsmaccus_vx_w, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vssrl_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssrl_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssrl_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssrl_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssra_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssra_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssra_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssra_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vssrl_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssrl_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssrl_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssrl_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssra_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssra_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssra_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vssra_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 8cc2bf4864..7d5dfeb5c7 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -433,6 +433,12 @@ vwsmacc_vx 111101 . ..... ..... 100 ..... 1010111 @r_vm vwsmaccsu_vv 111110 . ..... ..... 000 ..... 1010111 @r_vm vwsmaccsu_vx 111110 . ..... ..... 100 ..... 1010111 @r_vm vwsmaccus_vx 111111 . ..... ..... 100 ..... 1010111 @r_vm +vssrl_vv 101010 . ..... ..... 000 ..... 1010111 @r_vm +vssrl_vx 101010 . ..... ..... 100 ..... 1010111 @r_vm +vssrl_vi 101010 . ..... ..... 011 ..... 1010111 @r_vm +vssra_vv 101011 . ..... ..... 000 ..... 1010111 @r_vm +vssra_vx 101011 . ..... ..... 100 ..... 1010111 @r_vm +vssra_vi 101011 . ..... ..... 011 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 5e36ee8de5..31be40f4ba 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1767,3 +1767,11 @@ GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx) GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx) GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx) GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx) + +/* Vector Single-Width Scaling Shift Instructions */ +GEN_OPIVV_TRANS(vssrl_vv, opivv_check) +GEN_OPIVV_TRANS(vssra_vv, opivv_check) +GEN_OPIVX_TRANS(vssrl_vx, opivx_check) +GEN_OPIVX_TRANS(vssra_vx, opivx_check) +GEN_OPIVI_TRANS(vssrl_vi, 1, vssrl_vx, opivx_check) +GEN_OPIVI_TRANS(vssra_vi, 0, vssra_vx, opivx_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index d818c32d97..acd44599ba 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -2909,3 +2909,120 @@ RVVCALL(OPIVX3_RM, vwsmaccus_vx_w, WOP_SUS_W, H8, H4, vwsmaccus32) GEN_VEXT_VX_RM(vwsmaccus_vx_b, 1, 2, clearh) GEN_VEXT_VX_RM(vwsmaccus_vx_h, 2, 4, clearl) GEN_VEXT_VX_RM(vwsmaccus_vx_w, 4, 8, clearq) + +/* Vector Single-Width Scaling Shift Instructions */ +static inline uint8_t +vssrl8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b) +{ + uint8_t round, shift = b & 0x7; + uint8_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + return res; +} +static inline uint16_t +vssrl16(CPURISCVState *env, int vxrm, uint16_t a, uint16_t b) +{ + uint8_t round, shift = b & 0xf; + uint16_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + return res; +} +static inline uint32_t +vssrl32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b) +{ + uint8_t round, shift = b & 0x1f; + uint32_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + return res; +} +static inline uint64_t +vssrl64(CPURISCVState *env, int vxrm, uint64_t a, uint64_t b) +{ + uint8_t round, shift = b & 0x3f; + uint64_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + return res; +} +RVVCALL(OPIVV2_RM, vssrl_vv_b, OP_UUU_B, H1, H1, H1, vssrl8) +RVVCALL(OPIVV2_RM, vssrl_vv_h, OP_UUU_H, H2, H2, H2, vssrl16) +RVVCALL(OPIVV2_RM, vssrl_vv_w, OP_UUU_W, H4, H4, H4, vssrl32) +RVVCALL(OPIVV2_RM, vssrl_vv_d, OP_UUU_D, H8, H8, H8, vssrl64) +GEN_VEXT_VV_RM(vssrl_vv_b, 1, 1, clearb) +GEN_VEXT_VV_RM(vssrl_vv_h, 2, 2, clearh) +GEN_VEXT_VV_RM(vssrl_vv_w, 4, 4, clearl) +GEN_VEXT_VV_RM(vssrl_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2_RM, vssrl_vx_b, OP_UUU_B, H1, H1, vssrl8) +RVVCALL(OPIVX2_RM, vssrl_vx_h, OP_UUU_H, H2, H2, vssrl16) +RVVCALL(OPIVX2_RM, vssrl_vx_w, OP_UUU_W, H4, H4, vssrl32) +RVVCALL(OPIVX2_RM, vssrl_vx_d, OP_UUU_D, H8, H8, vssrl64) +GEN_VEXT_VX_RM(vssrl_vx_b, 1, 1, clearb) +GEN_VEXT_VX_RM(vssrl_vx_h, 2, 2, clearh) +GEN_VEXT_VX_RM(vssrl_vx_w, 4, 4, clearl) +GEN_VEXT_VX_RM(vssrl_vx_d, 8, 8, clearq) + +static inline int8_t +vssra8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) +{ + uint8_t round, shift = b & 0x7; + int8_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + return res; +} +static inline int16_t +vssra16(CPURISCVState *env, int vxrm, int16_t a, int16_t b) +{ + uint8_t round, shift = b & 0xf; + int16_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + return res; +} +static inline int32_t +vssra32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) +{ + uint8_t round, shift = b & 0x1f; + int32_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + return res; +} +static inline int64_t +vssra64(CPURISCVState *env, int vxrm, int64_t a, int64_t b) +{ + uint8_t round, shift = b & 0x3f; + int64_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + return res; +} +RVVCALL(OPIVV2_RM, vssra_vv_b, OP_SSS_B, H1, H1, H1, vssra8) +RVVCALL(OPIVV2_RM, vssra_vv_h, OP_SSS_H, H2, H2, H2, vssra16) +RVVCALL(OPIVV2_RM, vssra_vv_w, OP_SSS_W, H4, H4, H4, vssra32) +RVVCALL(OPIVV2_RM, vssra_vv_d, OP_SSS_D, H8, H8, H8, vssra64) +GEN_VEXT_VV_RM(vssra_vv_b, 1, 1, clearb) +GEN_VEXT_VV_RM(vssra_vv_h, 2, 2, clearh) +GEN_VEXT_VV_RM(vssra_vv_w, 4, 4, clearl) +GEN_VEXT_VV_RM(vssra_vv_d, 8, 8, clearq) + +RVVCALL(OPIVX2_RM, vssra_vx_b, OP_SSS_B, H1, H1, vssra8) +RVVCALL(OPIVX2_RM, vssra_vx_h, OP_SSS_H, H2, H2, vssra16) +RVVCALL(OPIVX2_RM, vssra_vx_w, OP_SSS_W, H4, H4, vssra32) +RVVCALL(OPIVX2_RM, vssra_vx_d, OP_SSS_D, H8, H8, vssra64) +GEN_VEXT_VX_RM(vssra_vx_b, 1, 1, clearb) +GEN_VEXT_VX_RM(vssra_vx_h, 2, 2, clearh) +GEN_VEXT_VX_RM(vssra_vx_w, 4, 4, clearl) +GEN_VEXT_VX_RM(vssra_vx_d, 8, 8, clearq) From 9ff3d28739b760970f5e542c74a033470dca3f9b Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:17 +0800 Subject: [PATCH 1830/2595] target/riscv: vector narrowing fixed-point clip instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-30-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 13 +++ target/riscv/insn32.decode | 6 + target/riscv/insn_trans/trans_rvv.inc.c | 8 ++ target/riscv/vector_helper.c | 141 ++++++++++++++++++++++++ 4 files changed, 168 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 78438f1ad6..5fa4330200 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -790,3 +790,16 @@ DEF_HELPER_6(vssra_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vssra_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vssra_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vssra_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vnclip_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnclip_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnclip_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnclipu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnclipu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnclipu_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vnclipu_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnclipu_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnclipu_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnclip_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnclip_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vnclip_vx_w, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 7d5dfeb5c7..78e6da6205 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -439,6 +439,12 @@ vssrl_vi 101010 . ..... ..... 011 ..... 1010111 @r_vm vssra_vv 101011 . ..... ..... 000 ..... 1010111 @r_vm vssra_vx 101011 . ..... ..... 100 ..... 1010111 @r_vm vssra_vi 101011 . ..... ..... 011 ..... 1010111 @r_vm +vnclipu_vv 101110 . ..... ..... 000 ..... 1010111 @r_vm +vnclipu_vx 101110 . ..... ..... 100 ..... 1010111 @r_vm +vnclipu_vi 101110 . ..... ..... 011 ..... 1010111 @r_vm +vnclip_vv 101111 . ..... ..... 000 ..... 1010111 @r_vm +vnclip_vx 101111 . ..... ..... 100 ..... 1010111 @r_vm +vnclip_vi 101111 . ..... ..... 011 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 31be40f4ba..b9d29f4051 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1775,3 +1775,11 @@ GEN_OPIVX_TRANS(vssrl_vx, opivx_check) GEN_OPIVX_TRANS(vssra_vx, opivx_check) GEN_OPIVI_TRANS(vssrl_vi, 1, vssrl_vx, opivx_check) GEN_OPIVI_TRANS(vssra_vi, 0, vssra_vx, opivx_check) + +/* Vector Narrowing Fixed-Point Clip Instructions */ +GEN_OPIVV_NARROW_TRANS(vnclipu_vv) +GEN_OPIVV_NARROW_TRANS(vnclip_vv) +GEN_OPIVX_NARROW_TRANS(vnclipu_vx) +GEN_OPIVX_NARROW_TRANS(vnclip_vx) +GEN_OPIVI_NARROW_TRANS(vnclipu_vi, 1, vnclipu_vx) +GEN_OPIVI_NARROW_TRANS(vnclip_vi, 1, vnclip_vx) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index acd44599ba..d7c51daca7 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -875,6 +875,12 @@ GEN_VEXT_AMO(vamomaxuw_v_w, uint32_t, uint32_t, idx_w, clearl) #define WOP_SSU_B int16_t, int8_t, uint8_t, int16_t, uint16_t #define WOP_SSU_H int32_t, int16_t, uint16_t, int32_t, uint32_t #define WOP_SSU_W int64_t, int32_t, uint32_t, int64_t, uint64_t +#define NOP_SSS_B int8_t, int8_t, int16_t, int8_t, int16_t +#define NOP_SSS_H int16_t, int16_t, int32_t, int16_t, int32_t +#define NOP_SSS_W int32_t, int32_t, int64_t, int32_t, int64_t +#define NOP_UUU_B uint8_t, uint8_t, uint16_t, uint8_t, uint16_t +#define NOP_UUU_H uint16_t, uint16_t, uint32_t, uint16_t, uint32_t +#define NOP_UUU_W uint32_t, uint32_t, uint64_t, uint32_t, uint64_t /* operation of two vector elements */ typedef void opivv2_fn(void *vd, void *vs1, void *vs2, int i); @@ -3009,6 +3015,7 @@ vssra64(CPURISCVState *env, int vxrm, int64_t a, int64_t b) res = (a >> shift) + round; return res; } + RVVCALL(OPIVV2_RM, vssra_vv_b, OP_SSS_B, H1, H1, H1, vssra8) RVVCALL(OPIVV2_RM, vssra_vv_h, OP_SSS_H, H2, H2, H2, vssra16) RVVCALL(OPIVV2_RM, vssra_vv_w, OP_SSS_W, H4, H4, H4, vssra32) @@ -3026,3 +3033,137 @@ GEN_VEXT_VX_RM(vssra_vx_b, 1, 1, clearb) GEN_VEXT_VX_RM(vssra_vx_h, 2, 2, clearh) GEN_VEXT_VX_RM(vssra_vx_w, 4, 4, clearl) GEN_VEXT_VX_RM(vssra_vx_d, 8, 8, clearq) + +/* Vector Narrowing Fixed-Point Clip Instructions */ +static inline int8_t +vnclip8(CPURISCVState *env, int vxrm, int16_t a, int8_t b) +{ + uint8_t round, shift = b & 0xf; + int16_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + if (res > INT8_MAX) { + env->vxsat = 0x1; + return INT8_MAX; + } else if (res < INT8_MIN) { + env->vxsat = 0x1; + return INT8_MIN; + } else { + return res; + } +} + +static inline int16_t +vnclip16(CPURISCVState *env, int vxrm, int32_t a, int16_t b) +{ + uint8_t round, shift = b & 0x1f; + int32_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + if (res > INT16_MAX) { + env->vxsat = 0x1; + return INT16_MAX; + } else if (res < INT16_MIN) { + env->vxsat = 0x1; + return INT16_MIN; + } else { + return res; + } +} + +static inline int32_t +vnclip32(CPURISCVState *env, int vxrm, int64_t a, int32_t b) +{ + uint8_t round, shift = b & 0x3f; + int64_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + if (res > INT32_MAX) { + env->vxsat = 0x1; + return INT32_MAX; + } else if (res < INT32_MIN) { + env->vxsat = 0x1; + return INT32_MIN; + } else { + return res; + } +} + +RVVCALL(OPIVV2_RM, vnclip_vv_b, NOP_SSS_B, H1, H2, H1, vnclip8) +RVVCALL(OPIVV2_RM, vnclip_vv_h, NOP_SSS_H, H2, H4, H2, vnclip16) +RVVCALL(OPIVV2_RM, vnclip_vv_w, NOP_SSS_W, H4, H8, H4, vnclip32) +GEN_VEXT_VV_RM(vnclip_vv_b, 1, 1, clearb) +GEN_VEXT_VV_RM(vnclip_vv_h, 2, 2, clearh) +GEN_VEXT_VV_RM(vnclip_vv_w, 4, 4, clearl) + +RVVCALL(OPIVX2_RM, vnclip_vx_b, NOP_SSS_B, H1, H2, vnclip8) +RVVCALL(OPIVX2_RM, vnclip_vx_h, NOP_SSS_H, H2, H4, vnclip16) +RVVCALL(OPIVX2_RM, vnclip_vx_w, NOP_SSS_W, H4, H8, vnclip32) +GEN_VEXT_VX_RM(vnclip_vx_b, 1, 1, clearb) +GEN_VEXT_VX_RM(vnclip_vx_h, 2, 2, clearh) +GEN_VEXT_VX_RM(vnclip_vx_w, 4, 4, clearl) + +static inline uint8_t +vnclipu8(CPURISCVState *env, int vxrm, uint16_t a, uint8_t b) +{ + uint8_t round, shift = b & 0xf; + uint16_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + if (res > UINT8_MAX) { + env->vxsat = 0x1; + return UINT8_MAX; + } else { + return res; + } +} + +static inline uint16_t +vnclipu16(CPURISCVState *env, int vxrm, uint32_t a, uint16_t b) +{ + uint8_t round, shift = b & 0x1f; + uint32_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + if (res > UINT16_MAX) { + env->vxsat = 0x1; + return UINT16_MAX; + } else { + return res; + } +} + +static inline uint32_t +vnclipu32(CPURISCVState *env, int vxrm, uint64_t a, uint32_t b) +{ + uint8_t round, shift = b & 0x3f; + int64_t res; + + round = get_round(vxrm, a, shift); + res = (a >> shift) + round; + if (res > UINT32_MAX) { + env->vxsat = 0x1; + return UINT32_MAX; + } else { + return res; + } +} + +RVVCALL(OPIVV2_RM, vnclipu_vv_b, NOP_UUU_B, H1, H2, H1, vnclipu8) +RVVCALL(OPIVV2_RM, vnclipu_vv_h, NOP_UUU_H, H2, H4, H2, vnclipu16) +RVVCALL(OPIVV2_RM, vnclipu_vv_w, NOP_UUU_W, H4, H8, H4, vnclipu32) +GEN_VEXT_VV_RM(vnclipu_vv_b, 1, 1, clearb) +GEN_VEXT_VV_RM(vnclipu_vv_h, 2, 2, clearh) +GEN_VEXT_VV_RM(vnclipu_vv_w, 4, 4, clearl) + +RVVCALL(OPIVX2_RM, vnclipu_vx_b, NOP_UUU_B, H1, H2, vnclipu8) +RVVCALL(OPIVX2_RM, vnclipu_vx_h, NOP_UUU_H, H2, H4, vnclipu16) +RVVCALL(OPIVX2_RM, vnclipu_vx_w, NOP_UUU_W, H4, H8, vnclipu32) +GEN_VEXT_VX_RM(vnclipu_vx_b, 1, 1, clearb) +GEN_VEXT_VX_RM(vnclipu_vx_h, 2, 2, clearh) +GEN_VEXT_VX_RM(vnclipu_vx_w, 4, 4, clearl) From ce2a0343f441f0ee949690eabae5ab600397e2eb Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:18 +0800 Subject: [PATCH 1831/2595] target/riscv: vector single-width floating-point add/subtract instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-31-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 16 ++++ target/riscv/insn32.decode | 5 + target/riscv/insn_trans/trans_rvv.inc.c | 118 ++++++++++++++++++++++++ target/riscv/vector_helper.c | 111 ++++++++++++++++++++++ 4 files changed, 250 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 5fa4330200..ba8a3710e1 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -803,3 +803,19 @@ DEF_HELPER_6(vnclipu_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vnclip_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vnclip_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vnclip_vx_w, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vfadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsub_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfadd_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfadd_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfadd_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfsub_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfsub_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfsub_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfrsub_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfrsub_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfrsub_vf_d, void, ptr, ptr, i64, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 78e6da6205..9e26ed36e7 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -445,6 +445,11 @@ vnclipu_vi 101110 . ..... ..... 011 ..... 1010111 @r_vm vnclip_vv 101111 . ..... ..... 000 ..... 1010111 @r_vm vnclip_vx 101111 . ..... ..... 100 ..... 1010111 @r_vm vnclip_vi 101111 . ..... ..... 011 ..... 1010111 @r_vm +vfadd_vv 000000 . ..... ..... 001 ..... 1010111 @r_vm +vfadd_vf 000000 . ..... ..... 101 ..... 1010111 @r_vm +vfsub_vv 000010 . ..... ..... 001 ..... 1010111 @r_vm +vfsub_vf 000010 . ..... ..... 101 ..... 1010111 @r_vm +vfrsub_vf 100111 . ..... ..... 101 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index b9d29f4051..55a6e514a9 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1783,3 +1783,121 @@ GEN_OPIVX_NARROW_TRANS(vnclipu_vx) GEN_OPIVX_NARROW_TRANS(vnclip_vx) GEN_OPIVI_NARROW_TRANS(vnclipu_vi, 1, vnclipu_vx) GEN_OPIVI_NARROW_TRANS(vnclip_vi, 1, vnclip_vx) + +/* + *** Vector Float Point Arithmetic Instructions + */ +/* Vector Single-Width Floating-Point Add/Subtract Instructions */ + +/* + * If the current SEW does not correspond to a supported IEEE floating-point + * type, an illegal instruction exception is raised. + */ +static bool opfvv_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, false) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + vext_check_reg(s, a->rs1, false) && + (s->sew != 0)); +} + +/* OPFVV without GVEC IR */ +#define GEN_OPFVV_TRANS(NAME, CHECK) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (CHECK(s, a)) { \ + uint32_t data = 0; \ + static gen_helper_gvec_4_ptr * const fns[3] = { \ + gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, \ + gen_helper_##NAME##_d, \ + }; \ + TCGLabel *over = gen_new_label(); \ + gen_set_rm(s, 7); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ + vreg_ofs(s, a->rs1), \ + vreg_ofs(s, a->rs2), cpu_env, 0, \ + s->vlen / 8, data, fns[s->sew - 1]); \ + gen_set_label(over); \ + return true; \ + } \ + return false; \ +} +GEN_OPFVV_TRANS(vfadd_vv, opfvv_check) +GEN_OPFVV_TRANS(vfsub_vv, opfvv_check) + +typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, + TCGv_env, TCGv_i32); + +static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, + uint32_t data, gen_helper_opfvf *fn, DisasContext *s) +{ + TCGv_ptr dest, src2, mask; + TCGv_i32 desc; + + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + dest = tcg_temp_new_ptr(); + mask = tcg_temp_new_ptr(); + src2 = tcg_temp_new_ptr(); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + + tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); + tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + + fn(dest, mask, cpu_fpr[rs1], src2, cpu_env, desc); + + tcg_temp_free_ptr(dest); + tcg_temp_free_ptr(mask); + tcg_temp_free_ptr(src2); + tcg_temp_free_i32(desc); + gen_set_label(over); + return true; +} + +static bool opfvf_check(DisasContext *s, arg_rmrr *a) +{ +/* + * If the current SEW does not correspond to a supported IEEE floating-point + * type, an illegal instruction exception is raised + */ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, false) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + (s->sew != 0)); +} + +/* OPFVF without GVEC IR */ +#define GEN_OPFVF_TRANS(NAME, CHECK) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (CHECK(s, a)) { \ + uint32_t data = 0; \ + static gen_helper_opfvf *const fns[3] = { \ + gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, \ + gen_helper_##NAME##_d, \ + }; \ + gen_set_rm(s, 7); \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ + fns[s->sew - 1], s); \ + } \ + return false; \ +} + +GEN_OPFVF_TRANS(vfadd_vf, opfvf_check) +GEN_OPFVF_TRANS(vfsub_vf, opfvf_check) +GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index d7c51daca7..a2bbe8481f 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -21,6 +21,7 @@ #include "exec/memop.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" +#include "fpu/softfloat.h" #include "tcg/tcg-gvec-desc.h" #include "internals.h" #include @@ -3167,3 +3168,113 @@ RVVCALL(OPIVX2_RM, vnclipu_vx_w, NOP_UUU_W, H4, H8, vnclipu32) GEN_VEXT_VX_RM(vnclipu_vx_b, 1, 1, clearb) GEN_VEXT_VX_RM(vnclipu_vx_h, 2, 2, clearh) GEN_VEXT_VX_RM(vnclipu_vx_w, 4, 4, clearl) + +/* + *** Vector Float Point Arithmetic Instructions + */ +/* Vector Single-Width Floating-Point Add/Subtract Instructions */ +#define OPFVV2(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ +static void do_##NAME(void *vd, void *vs1, void *vs2, int i, \ + CPURISCVState *env) \ +{ \ + TX1 s1 = *((T1 *)vs1 + HS1(i)); \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + *((TD *)vd + HD(i)) = OP(s2, s1, &env->fp_status); \ +} + +#define GEN_VEXT_VV_ENV(NAME, ESZ, DSZ, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, \ + void *vs2, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + uint32_t vlmax = vext_maxsz(desc) / ESZ; \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + do_##NAME(vd, vs1, vs2, i, env); \ + } \ + CLEAR_FN(vd, vl, vl * DSZ, vlmax * DSZ); \ +} + +RVVCALL(OPFVV2, vfadd_vv_h, OP_UUU_H, H2, H2, H2, float16_add) +RVVCALL(OPFVV2, vfadd_vv_w, OP_UUU_W, H4, H4, H4, float32_add) +RVVCALL(OPFVV2, vfadd_vv_d, OP_UUU_D, H8, H8, H8, float64_add) +GEN_VEXT_VV_ENV(vfadd_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfadd_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfadd_vv_d, 8, 8, clearq) + +#define OPFVF2(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ +static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ + CPURISCVState *env) \ +{ \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1, &env->fp_status);\ +} + +#define GEN_VEXT_VF(NAME, ESZ, DSZ, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \ + void *vs2, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + uint32_t vlmax = vext_maxsz(desc) / ESZ; \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + do_##NAME(vd, s1, vs2, i, env); \ + } \ + CLEAR_FN(vd, vl, vl * DSZ, vlmax * DSZ); \ +} + +RVVCALL(OPFVF2, vfadd_vf_h, OP_UUU_H, H2, H2, float16_add) +RVVCALL(OPFVF2, vfadd_vf_w, OP_UUU_W, H4, H4, float32_add) +RVVCALL(OPFVF2, vfadd_vf_d, OP_UUU_D, H8, H8, float64_add) +GEN_VEXT_VF(vfadd_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfadd_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfadd_vf_d, 8, 8, clearq) + +RVVCALL(OPFVV2, vfsub_vv_h, OP_UUU_H, H2, H2, H2, float16_sub) +RVVCALL(OPFVV2, vfsub_vv_w, OP_UUU_W, H4, H4, H4, float32_sub) +RVVCALL(OPFVV2, vfsub_vv_d, OP_UUU_D, H8, H8, H8, float64_sub) +GEN_VEXT_VV_ENV(vfsub_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfsub_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfsub_vv_d, 8, 8, clearq) +RVVCALL(OPFVF2, vfsub_vf_h, OP_UUU_H, H2, H2, float16_sub) +RVVCALL(OPFVF2, vfsub_vf_w, OP_UUU_W, H4, H4, float32_sub) +RVVCALL(OPFVF2, vfsub_vf_d, OP_UUU_D, H8, H8, float64_sub) +GEN_VEXT_VF(vfsub_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfsub_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfsub_vf_d, 8, 8, clearq) + +static uint16_t float16_rsub(uint16_t a, uint16_t b, float_status *s) +{ + return float16_sub(b, a, s); +} + +static uint32_t float32_rsub(uint32_t a, uint32_t b, float_status *s) +{ + return float32_sub(b, a, s); +} + +static uint64_t float64_rsub(uint64_t a, uint64_t b, float_status *s) +{ + return float64_sub(b, a, s); +} + +RVVCALL(OPFVF2, vfrsub_vf_h, OP_UUU_H, H2, H2, float16_rsub) +RVVCALL(OPFVF2, vfrsub_vf_w, OP_UUU_W, H4, H4, float32_rsub) +RVVCALL(OPFVF2, vfrsub_vf_d, OP_UUU_D, H8, H8, float64_rsub) +GEN_VEXT_VF(vfrsub_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfrsub_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfrsub_vf_d, 8, 8, clearq) From eeffab2ec1b332a5eb2d2dcd2732cdb57179c6eb Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:19 +0800 Subject: [PATCH 1832/2595] target/riscv: vector widening floating-point add/subtract instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-32-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 17 +++ target/riscv/insn32.decode | 8 ++ target/riscv/insn_trans/trans_rvv.inc.c | 149 ++++++++++++++++++++++++ target/riscv/vector_helper.c | 83 +++++++++++++ 4 files changed, 257 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index ba8a3710e1..828b145150 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -819,3 +819,20 @@ DEF_HELPER_6(vfsub_vf_d, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfrsub_vf_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfrsub_vf_w, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfrsub_vf_d, void, ptr, ptr, i64, ptr, env, i32) + +DEF_HELPER_6(vfwadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwadd_wv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwadd_wv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwsub_wv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwsub_wv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwadd_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwadd_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwsub_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwsub_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwadd_wf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwadd_wf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwsub_wf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwsub_wf_w, void, ptr, ptr, i64, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 9e26ed36e7..42d8a967d0 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -450,6 +450,14 @@ vfadd_vf 000000 . ..... ..... 101 ..... 1010111 @r_vm vfsub_vv 000010 . ..... ..... 001 ..... 1010111 @r_vm vfsub_vf 000010 . ..... ..... 101 ..... 1010111 @r_vm vfrsub_vf 100111 . ..... ..... 101 ..... 1010111 @r_vm +vfwadd_vv 110000 . ..... ..... 001 ..... 1010111 @r_vm +vfwadd_vf 110000 . ..... ..... 101 ..... 1010111 @r_vm +vfwadd_wv 110100 . ..... ..... 001 ..... 1010111 @r_vm +vfwadd_wf 110100 . ..... ..... 101 ..... 1010111 @r_vm +vfwsub_vv 110010 . ..... ..... 001 ..... 1010111 @r_vm +vfwsub_vf 110010 . ..... ..... 101 ..... 1010111 @r_vm +vfwsub_wv 110110 . ..... ..... 001 ..... 1010111 @r_vm +vfwsub_wf 110110 . ..... ..... 101 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 55a6e514a9..0224b66962 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1901,3 +1901,152 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ GEN_OPFVF_TRANS(vfadd_vf, opfvf_check) GEN_OPFVF_TRANS(vfsub_vf, opfvf_check) GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) + +/* Vector Widening Floating-Point Add/Subtract Instructions */ +static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, true) && + vext_check_reg(s, a->rs2, false) && + vext_check_reg(s, a->rs1, false) && + vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, + 1 << s->lmul) && + vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, + 1 << s->lmul) && + (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); +} + +/* OPFVV with WIDEN */ +#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (CHECK(s, a)) { \ + uint32_t data = 0; \ + static gen_helper_gvec_4_ptr * const fns[2] = { \ + gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ + }; \ + TCGLabel *over = gen_new_label(); \ + gen_set_rm(s, 7); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ + vreg_ofs(s, a->rs1), \ + vreg_ofs(s, a->rs2), cpu_env, 0, \ + s->vlen / 8, data, fns[s->sew - 1]); \ + gen_set_label(over); \ + return true; \ + } \ + return false; \ +} + +GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) + +static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, true) && + vext_check_reg(s, a->rs2, false) && + vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, + 1 << s->lmul) && + (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); +} + +/* OPFVF with WIDEN */ +#define GEN_OPFVF_WIDEN_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (opfvf_widen_check(s, a)) { \ + uint32_t data = 0; \ + static gen_helper_opfvf *const fns[2] = { \ + gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ + }; \ + gen_set_rm(s, 7); \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ + fns[s->sew - 1], s); \ + } \ + return false; \ +} + +GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) +GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) + +static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, true) && + vext_check_reg(s, a->rs2, true) && + vext_check_reg(s, a->rs1, false) && + vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, + 1 << s->lmul) && + (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); +} + +/* WIDEN OPFVV with WIDEN */ +#define GEN_OPFWV_WIDEN_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (opfwv_widen_check(s, a)) { \ + uint32_t data = 0; \ + static gen_helper_gvec_4_ptr * const fns[2] = { \ + gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ + }; \ + TCGLabel *over = gen_new_label(); \ + gen_set_rm(s, 7); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ + vreg_ofs(s, a->rs1), \ + vreg_ofs(s, a->rs2), cpu_env, 0, \ + s->vlen / 8, data, fns[s->sew - 1]); \ + gen_set_label(over); \ + return true; \ + } \ + return false; \ +} + +GEN_OPFWV_WIDEN_TRANS(vfwadd_wv) +GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) + +static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, true) && + vext_check_reg(s, a->rs2, true) && + (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); +} + +/* WIDEN OPFVF with WIDEN */ +#define GEN_OPFWF_WIDEN_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ +{ \ + if (opfwf_widen_check(s, a)) { \ + uint32_t data = 0; \ + static gen_helper_opfvf *const fns[2] = { \ + gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ + }; \ + gen_set_rm(s, 7); \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ + fns[s->sew - 1], s); \ + } \ + return false; \ +} + +GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) +GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index a2bbe8481f..b31f52b11d 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -3278,3 +3278,86 @@ RVVCALL(OPFVF2, vfrsub_vf_d, OP_UUU_D, H8, H8, float64_rsub) GEN_VEXT_VF(vfrsub_vf_h, 2, 2, clearh) GEN_VEXT_VF(vfrsub_vf_w, 4, 4, clearl) GEN_VEXT_VF(vfrsub_vf_d, 8, 8, clearq) + +/* Vector Widening Floating-Point Add/Subtract Instructions */ +static uint32_t vfwadd16(uint16_t a, uint16_t b, float_status *s) +{ + return float32_add(float16_to_float32(a, true, s), + float16_to_float32(b, true, s), s); +} + +static uint64_t vfwadd32(uint32_t a, uint32_t b, float_status *s) +{ + return float64_add(float32_to_float64(a, s), + float32_to_float64(b, s), s); + +} + +RVVCALL(OPFVV2, vfwadd_vv_h, WOP_UUU_H, H4, H2, H2, vfwadd16) +RVVCALL(OPFVV2, vfwadd_vv_w, WOP_UUU_W, H8, H4, H4, vfwadd32) +GEN_VEXT_VV_ENV(vfwadd_vv_h, 2, 4, clearl) +GEN_VEXT_VV_ENV(vfwadd_vv_w, 4, 8, clearq) +RVVCALL(OPFVF2, vfwadd_vf_h, WOP_UUU_H, H4, H2, vfwadd16) +RVVCALL(OPFVF2, vfwadd_vf_w, WOP_UUU_W, H8, H4, vfwadd32) +GEN_VEXT_VF(vfwadd_vf_h, 2, 4, clearl) +GEN_VEXT_VF(vfwadd_vf_w, 4, 8, clearq) + +static uint32_t vfwsub16(uint16_t a, uint16_t b, float_status *s) +{ + return float32_sub(float16_to_float32(a, true, s), + float16_to_float32(b, true, s), s); +} + +static uint64_t vfwsub32(uint32_t a, uint32_t b, float_status *s) +{ + return float64_sub(float32_to_float64(a, s), + float32_to_float64(b, s), s); + +} + +RVVCALL(OPFVV2, vfwsub_vv_h, WOP_UUU_H, H4, H2, H2, vfwsub16) +RVVCALL(OPFVV2, vfwsub_vv_w, WOP_UUU_W, H8, H4, H4, vfwsub32) +GEN_VEXT_VV_ENV(vfwsub_vv_h, 2, 4, clearl) +GEN_VEXT_VV_ENV(vfwsub_vv_w, 4, 8, clearq) +RVVCALL(OPFVF2, vfwsub_vf_h, WOP_UUU_H, H4, H2, vfwsub16) +RVVCALL(OPFVF2, vfwsub_vf_w, WOP_UUU_W, H8, H4, vfwsub32) +GEN_VEXT_VF(vfwsub_vf_h, 2, 4, clearl) +GEN_VEXT_VF(vfwsub_vf_w, 4, 8, clearq) + +static uint32_t vfwaddw16(uint32_t a, uint16_t b, float_status *s) +{ + return float32_add(a, float16_to_float32(b, true, s), s); +} + +static uint64_t vfwaddw32(uint64_t a, uint32_t b, float_status *s) +{ + return float64_add(a, float32_to_float64(b, s), s); +} + +RVVCALL(OPFVV2, vfwadd_wv_h, WOP_WUUU_H, H4, H2, H2, vfwaddw16) +RVVCALL(OPFVV2, vfwadd_wv_w, WOP_WUUU_W, H8, H4, H4, vfwaddw32) +GEN_VEXT_VV_ENV(vfwadd_wv_h, 2, 4, clearl) +GEN_VEXT_VV_ENV(vfwadd_wv_w, 4, 8, clearq) +RVVCALL(OPFVF2, vfwadd_wf_h, WOP_WUUU_H, H4, H2, vfwaddw16) +RVVCALL(OPFVF2, vfwadd_wf_w, WOP_WUUU_W, H8, H4, vfwaddw32) +GEN_VEXT_VF(vfwadd_wf_h, 2, 4, clearl) +GEN_VEXT_VF(vfwadd_wf_w, 4, 8, clearq) + +static uint32_t vfwsubw16(uint32_t a, uint16_t b, float_status *s) +{ + return float32_sub(a, float16_to_float32(b, true, s), s); +} + +static uint64_t vfwsubw32(uint64_t a, uint32_t b, float_status *s) +{ + return float64_sub(a, float32_to_float64(b, s), s); +} + +RVVCALL(OPFVV2, vfwsub_wv_h, WOP_WUUU_H, H4, H2, H2, vfwsubw16) +RVVCALL(OPFVV2, vfwsub_wv_w, WOP_WUUU_W, H8, H4, H4, vfwsubw32) +GEN_VEXT_VV_ENV(vfwsub_wv_h, 2, 4, clearl) +GEN_VEXT_VV_ENV(vfwsub_wv_w, 4, 8, clearq) +RVVCALL(OPFVF2, vfwsub_wf_h, WOP_WUUU_H, H4, H2, vfwsubw16) +RVVCALL(OPFVF2, vfwsub_wf_w, WOP_WUUU_W, H8, H4, vfwsubw32) +GEN_VEXT_VF(vfwsub_wf_h, 2, 4, clearl) +GEN_VEXT_VF(vfwsub_wf_w, 4, 8, clearq) From 0e0057cbe2169195a08ae8247504e69f9b80542b Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:20 +0800 Subject: [PATCH 1833/2595] target/riscv: vector single-width floating-point multiply/divide instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-33-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 16 ++++++++ target/riscv/insn32.decode | 5 +++ target/riscv/insn_trans/trans_rvv.inc.c | 7 ++++ target/riscv/vector_helper.c | 49 +++++++++++++++++++++++++ 4 files changed, 77 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 828b145150..94305bd870 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -836,3 +836,19 @@ DEF_HELPER_6(vfwadd_wf_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfwadd_wf_w, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfwsub_wf_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfwsub_wf_w, void, ptr, ptr, i64, ptr, env, i32) + +DEF_HELPER_6(vfmul_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmul_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmul_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfdiv_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfdiv_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfdiv_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmul_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmul_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmul_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfdiv_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfdiv_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfdiv_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfrdiv_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfrdiv_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfrdiv_vf_d, void, ptr, ptr, i64, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 42d8a967d0..5db02f0c0a 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -458,6 +458,11 @@ vfwsub_vv 110010 . ..... ..... 001 ..... 1010111 @r_vm vfwsub_vf 110010 . ..... ..... 101 ..... 1010111 @r_vm vfwsub_wv 110110 . ..... ..... 001 ..... 1010111 @r_vm vfwsub_wf 110110 . ..... ..... 101 ..... 1010111 @r_vm +vfmul_vv 100100 . ..... ..... 001 ..... 1010111 @r_vm +vfmul_vf 100100 . ..... ..... 101 ..... 1010111 @r_vm +vfdiv_vv 100000 . ..... ..... 001 ..... 1010111 @r_vm +vfdiv_vf 100000 . ..... ..... 101 ..... 1010111 @r_vm +vfrdiv_vf 100001 . ..... ..... 101 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 0224b66962..be9a9a8295 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2050,3 +2050,10 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) + +/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ +GEN_OPFVV_TRANS(vfmul_vv, opfvv_check) +GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) +GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) +GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) +GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index b31f52b11d..e0da273849 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -3361,3 +3361,52 @@ RVVCALL(OPFVF2, vfwsub_wf_h, WOP_WUUU_H, H4, H2, vfwsubw16) RVVCALL(OPFVF2, vfwsub_wf_w, WOP_WUUU_W, H8, H4, vfwsubw32) GEN_VEXT_VF(vfwsub_wf_h, 2, 4, clearl) GEN_VEXT_VF(vfwsub_wf_w, 4, 8, clearq) + +/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ +RVVCALL(OPFVV2, vfmul_vv_h, OP_UUU_H, H2, H2, H2, float16_mul) +RVVCALL(OPFVV2, vfmul_vv_w, OP_UUU_W, H4, H4, H4, float32_mul) +RVVCALL(OPFVV2, vfmul_vv_d, OP_UUU_D, H8, H8, H8, float64_mul) +GEN_VEXT_VV_ENV(vfmul_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfmul_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfmul_vv_d, 8, 8, clearq) +RVVCALL(OPFVF2, vfmul_vf_h, OP_UUU_H, H2, H2, float16_mul) +RVVCALL(OPFVF2, vfmul_vf_w, OP_UUU_W, H4, H4, float32_mul) +RVVCALL(OPFVF2, vfmul_vf_d, OP_UUU_D, H8, H8, float64_mul) +GEN_VEXT_VF(vfmul_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfmul_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfmul_vf_d, 8, 8, clearq) + +RVVCALL(OPFVV2, vfdiv_vv_h, OP_UUU_H, H2, H2, H2, float16_div) +RVVCALL(OPFVV2, vfdiv_vv_w, OP_UUU_W, H4, H4, H4, float32_div) +RVVCALL(OPFVV2, vfdiv_vv_d, OP_UUU_D, H8, H8, H8, float64_div) +GEN_VEXT_VV_ENV(vfdiv_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfdiv_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfdiv_vv_d, 8, 8, clearq) +RVVCALL(OPFVF2, vfdiv_vf_h, OP_UUU_H, H2, H2, float16_div) +RVVCALL(OPFVF2, vfdiv_vf_w, OP_UUU_W, H4, H4, float32_div) +RVVCALL(OPFVF2, vfdiv_vf_d, OP_UUU_D, H8, H8, float64_div) +GEN_VEXT_VF(vfdiv_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfdiv_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfdiv_vf_d, 8, 8, clearq) + +static uint16_t float16_rdiv(uint16_t a, uint16_t b, float_status *s) +{ + return float16_div(b, a, s); +} + +static uint32_t float32_rdiv(uint32_t a, uint32_t b, float_status *s) +{ + return float32_div(b, a, s); +} + +static uint64_t float64_rdiv(uint64_t a, uint64_t b, float_status *s) +{ + return float64_div(b, a, s); +} + +RVVCALL(OPFVF2, vfrdiv_vf_h, OP_UUU_H, H2, H2, float16_rdiv) +RVVCALL(OPFVF2, vfrdiv_vf_w, OP_UUU_W, H4, H4, float32_rdiv) +RVVCALL(OPFVF2, vfrdiv_vf_d, OP_UUU_D, H8, H8, float64_rdiv) +GEN_VEXT_VF(vfrdiv_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfrdiv_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfrdiv_vf_d, 8, 8, clearq) From f7c7b7cd293ca6f14f23cc2c14d6d23fc47a604d Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:21 +0800 Subject: [PATCH 1834/2595] target/riscv: vector widening floating-point multiply Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-34-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 5 +++++ target/riscv/insn32.decode | 2 ++ target/riscv/insn_trans/trans_rvv.inc.c | 4 ++++ target/riscv/vector_helper.c | 22 ++++++++++++++++++++++ 4 files changed, 33 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 94305bd870..9d7dcfeef9 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -852,3 +852,8 @@ DEF_HELPER_6(vfdiv_vf_d, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfrdiv_vf_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfrdiv_vf_w, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfrdiv_vf_d, void, ptr, ptr, i64, ptr, env, i32) + +DEF_HELPER_6(vfwmul_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwmul_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwmul_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwmul_vf_w, void, ptr, ptr, i64, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 5db02f0c0a..dd9bca7eeb 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -463,6 +463,8 @@ vfmul_vf 100100 . ..... ..... 101 ..... 1010111 @r_vm vfdiv_vv 100000 . ..... ..... 001 ..... 1010111 @r_vm vfdiv_vf 100000 . ..... ..... 101 ..... 1010111 @r_vm vfrdiv_vf 100001 . ..... ..... 101 ..... 1010111 @r_vm +vfwmul_vv 111000 . ..... ..... 001 ..... 1010111 @r_vm +vfwmul_vf 111000 . ..... ..... 101 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index be9a9a8295..3ce7815f5d 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2057,3 +2057,7 @@ GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) + +/* Vector Widening Floating-Point Multiply */ +GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index e0da273849..dbdfeacf25 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -3410,3 +3410,25 @@ RVVCALL(OPFVF2, vfrdiv_vf_d, OP_UUU_D, H8, H8, float64_rdiv) GEN_VEXT_VF(vfrdiv_vf_h, 2, 2, clearh) GEN_VEXT_VF(vfrdiv_vf_w, 4, 4, clearl) GEN_VEXT_VF(vfrdiv_vf_d, 8, 8, clearq) + +/* Vector Widening Floating-Point Multiply */ +static uint32_t vfwmul16(uint16_t a, uint16_t b, float_status *s) +{ + return float32_mul(float16_to_float32(a, true, s), + float16_to_float32(b, true, s), s); +} + +static uint64_t vfwmul32(uint32_t a, uint32_t b, float_status *s) +{ + return float64_mul(float32_to_float64(a, s), + float32_to_float64(b, s), s); + +} +RVVCALL(OPFVV2, vfwmul_vv_h, WOP_UUU_H, H4, H2, H2, vfwmul16) +RVVCALL(OPFVV2, vfwmul_vv_w, WOP_UUU_W, H8, H4, H4, vfwmul32) +GEN_VEXT_VV_ENV(vfwmul_vv_h, 2, 4, clearl) +GEN_VEXT_VV_ENV(vfwmul_vv_w, 4, 8, clearq) +RVVCALL(OPFVF2, vfwmul_vf_h, WOP_UUU_H, H4, H2, vfwmul16) +RVVCALL(OPFVF2, vfwmul_vf_w, WOP_UUU_W, H8, H4, vfwmul32) +GEN_VEXT_VF(vfwmul_vf_h, 2, 4, clearl) +GEN_VEXT_VF(vfwmul_vf_w, 4, 8, clearq) From 4aa5a8fed4a21fe2e132a9a21b251aa95e19de80 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:22 +0800 Subject: [PATCH 1835/2595] target/riscv: vector single-width floating-point fused multiply-add instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-35-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 49 +++++ target/riscv/insn32.decode | 16 ++ target/riscv/insn_trans/trans_rvv.inc.c | 18 ++ target/riscv/vector_helper.c | 251 ++++++++++++++++++++++++ 4 files changed, 334 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 9d7dcfeef9..108a177f25 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -857,3 +857,52 @@ DEF_HELPER_6(vfwmul_vv_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfwmul_vv_w, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfwmul_vf_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfwmul_vf_w, void, ptr, ptr, i64, ptr, env, i32) + +DEF_HELPER_6(vfmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmacc_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmacc_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmsac_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmsac_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmsac_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmsac_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmsac_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmsac_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmsub_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfnmsub_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmacc_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmacc_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmacc_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmacc_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmacc_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmacc_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmsac_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmsac_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmsac_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmsac_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmsac_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmsac_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmadd_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmadd_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmadd_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmadd_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmadd_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmadd_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmsub_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmsub_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmsub_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmsub_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmsub_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfnmsub_vf_d, void, ptr, ptr, i64, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index dd9bca7eeb..9ca765d37f 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -465,6 +465,22 @@ vfdiv_vf 100000 . ..... ..... 101 ..... 1010111 @r_vm vfrdiv_vf 100001 . ..... ..... 101 ..... 1010111 @r_vm vfwmul_vv 111000 . ..... ..... 001 ..... 1010111 @r_vm vfwmul_vf 111000 . ..... ..... 101 ..... 1010111 @r_vm +vfmacc_vv 101100 . ..... ..... 001 ..... 1010111 @r_vm +vfnmacc_vv 101101 . ..... ..... 001 ..... 1010111 @r_vm +vfnmacc_vf 101101 . ..... ..... 101 ..... 1010111 @r_vm +vfmacc_vf 101100 . ..... ..... 101 ..... 1010111 @r_vm +vfmsac_vv 101110 . ..... ..... 001 ..... 1010111 @r_vm +vfmsac_vf 101110 . ..... ..... 101 ..... 1010111 @r_vm +vfnmsac_vv 101111 . ..... ..... 001 ..... 1010111 @r_vm +vfnmsac_vf 101111 . ..... ..... 101 ..... 1010111 @r_vm +vfmadd_vv 101000 . ..... ..... 001 ..... 1010111 @r_vm +vfmadd_vf 101000 . ..... ..... 101 ..... 1010111 @r_vm +vfnmadd_vv 101001 . ..... ..... 001 ..... 1010111 @r_vm +vfnmadd_vf 101001 . ..... ..... 101 ..... 1010111 @r_vm +vfmsub_vv 101010 . ..... ..... 001 ..... 1010111 @r_vm +vfmsub_vf 101010 . ..... ..... 101 ..... 1010111 @r_vm +vfnmsub_vv 101011 . ..... ..... 001 ..... 1010111 @r_vm +vfnmsub_vf 101011 . ..... ..... 101 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 3ce7815f5d..ee601fd790 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2061,3 +2061,21 @@ GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) /* Vector Widening Floating-Point Multiply */ GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) + +/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ +GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) +GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check) +GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check) +GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check) +GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check) +GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check) +GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check) +GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check) +GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check) +GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check) +GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check) +GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check) +GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) +GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) +GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) +GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index dbdfeacf25..29dc1d1d73 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -3432,3 +3432,254 @@ RVVCALL(OPFVF2, vfwmul_vf_h, WOP_UUU_H, H4, H2, vfwmul16) RVVCALL(OPFVF2, vfwmul_vf_w, WOP_UUU_W, H8, H4, vfwmul32) GEN_VEXT_VF(vfwmul_vf_h, 2, 4, clearl) GEN_VEXT_VF(vfwmul_vf_w, 4, 8, clearq) + +/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ +#define OPFVV3(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \ +static void do_##NAME(void *vd, void *vs1, void *vs2, int i, \ + CPURISCVState *env) \ +{ \ + TX1 s1 = *((T1 *)vs1 + HS1(i)); \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + TD d = *((TD *)vd + HD(i)); \ + *((TD *)vd + HD(i)) = OP(s2, s1, d, &env->fp_status); \ +} + +static uint16_t fmacc16(uint16_t a, uint16_t b, uint16_t d, float_status *s) +{ + return float16_muladd(a, b, d, 0, s); +} + +static uint32_t fmacc32(uint32_t a, uint32_t b, uint32_t d, float_status *s) +{ + return float32_muladd(a, b, d, 0, s); +} + +static uint64_t fmacc64(uint64_t a, uint64_t b, uint64_t d, float_status *s) +{ + return float64_muladd(a, b, d, 0, s); +} + +RVVCALL(OPFVV3, vfmacc_vv_h, OP_UUU_H, H2, H2, H2, fmacc16) +RVVCALL(OPFVV3, vfmacc_vv_w, OP_UUU_W, H4, H4, H4, fmacc32) +RVVCALL(OPFVV3, vfmacc_vv_d, OP_UUU_D, H8, H8, H8, fmacc64) +GEN_VEXT_VV_ENV(vfmacc_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfmacc_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfmacc_vv_d, 8, 8, clearq) + +#define OPFVF3(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \ +static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \ + CPURISCVState *env) \ +{ \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + TD d = *((TD *)vd + HD(i)); \ + *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1, d, &env->fp_status);\ +} + +RVVCALL(OPFVF3, vfmacc_vf_h, OP_UUU_H, H2, H2, fmacc16) +RVVCALL(OPFVF3, vfmacc_vf_w, OP_UUU_W, H4, H4, fmacc32) +RVVCALL(OPFVF3, vfmacc_vf_d, OP_UUU_D, H8, H8, fmacc64) +GEN_VEXT_VF(vfmacc_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfmacc_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfmacc_vf_d, 8, 8, clearq) + +static uint16_t fnmacc16(uint16_t a, uint16_t b, uint16_t d, float_status *s) +{ + return float16_muladd(a, b, d, + float_muladd_negate_c | float_muladd_negate_product, s); +} + +static uint32_t fnmacc32(uint32_t a, uint32_t b, uint32_t d, float_status *s) +{ + return float32_muladd(a, b, d, + float_muladd_negate_c | float_muladd_negate_product, s); +} + +static uint64_t fnmacc64(uint64_t a, uint64_t b, uint64_t d, float_status *s) +{ + return float64_muladd(a, b, d, + float_muladd_negate_c | float_muladd_negate_product, s); +} + +RVVCALL(OPFVV3, vfnmacc_vv_h, OP_UUU_H, H2, H2, H2, fnmacc16) +RVVCALL(OPFVV3, vfnmacc_vv_w, OP_UUU_W, H4, H4, H4, fnmacc32) +RVVCALL(OPFVV3, vfnmacc_vv_d, OP_UUU_D, H8, H8, H8, fnmacc64) +GEN_VEXT_VV_ENV(vfnmacc_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfnmacc_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfnmacc_vv_d, 8, 8, clearq) +RVVCALL(OPFVF3, vfnmacc_vf_h, OP_UUU_H, H2, H2, fnmacc16) +RVVCALL(OPFVF3, vfnmacc_vf_w, OP_UUU_W, H4, H4, fnmacc32) +RVVCALL(OPFVF3, vfnmacc_vf_d, OP_UUU_D, H8, H8, fnmacc64) +GEN_VEXT_VF(vfnmacc_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfnmacc_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfnmacc_vf_d, 8, 8, clearq) + +static uint16_t fmsac16(uint16_t a, uint16_t b, uint16_t d, float_status *s) +{ + return float16_muladd(a, b, d, float_muladd_negate_c, s); +} + +static uint32_t fmsac32(uint32_t a, uint32_t b, uint32_t d, float_status *s) +{ + return float32_muladd(a, b, d, float_muladd_negate_c, s); +} + +static uint64_t fmsac64(uint64_t a, uint64_t b, uint64_t d, float_status *s) +{ + return float64_muladd(a, b, d, float_muladd_negate_c, s); +} + +RVVCALL(OPFVV3, vfmsac_vv_h, OP_UUU_H, H2, H2, H2, fmsac16) +RVVCALL(OPFVV3, vfmsac_vv_w, OP_UUU_W, H4, H4, H4, fmsac32) +RVVCALL(OPFVV3, vfmsac_vv_d, OP_UUU_D, H8, H8, H8, fmsac64) +GEN_VEXT_VV_ENV(vfmsac_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfmsac_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfmsac_vv_d, 8, 8, clearq) +RVVCALL(OPFVF3, vfmsac_vf_h, OP_UUU_H, H2, H2, fmsac16) +RVVCALL(OPFVF3, vfmsac_vf_w, OP_UUU_W, H4, H4, fmsac32) +RVVCALL(OPFVF3, vfmsac_vf_d, OP_UUU_D, H8, H8, fmsac64) +GEN_VEXT_VF(vfmsac_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfmsac_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfmsac_vf_d, 8, 8, clearq) + +static uint16_t fnmsac16(uint16_t a, uint16_t b, uint16_t d, float_status *s) +{ + return float16_muladd(a, b, d, float_muladd_negate_product, s); +} + +static uint32_t fnmsac32(uint32_t a, uint32_t b, uint32_t d, float_status *s) +{ + return float32_muladd(a, b, d, float_muladd_negate_product, s); +} + +static uint64_t fnmsac64(uint64_t a, uint64_t b, uint64_t d, float_status *s) +{ + return float64_muladd(a, b, d, float_muladd_negate_product, s); +} + +RVVCALL(OPFVV3, vfnmsac_vv_h, OP_UUU_H, H2, H2, H2, fnmsac16) +RVVCALL(OPFVV3, vfnmsac_vv_w, OP_UUU_W, H4, H4, H4, fnmsac32) +RVVCALL(OPFVV3, vfnmsac_vv_d, OP_UUU_D, H8, H8, H8, fnmsac64) +GEN_VEXT_VV_ENV(vfnmsac_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfnmsac_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfnmsac_vv_d, 8, 8, clearq) +RVVCALL(OPFVF3, vfnmsac_vf_h, OP_UUU_H, H2, H2, fnmsac16) +RVVCALL(OPFVF3, vfnmsac_vf_w, OP_UUU_W, H4, H4, fnmsac32) +RVVCALL(OPFVF3, vfnmsac_vf_d, OP_UUU_D, H8, H8, fnmsac64) +GEN_VEXT_VF(vfnmsac_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfnmsac_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfnmsac_vf_d, 8, 8, clearq) + +static uint16_t fmadd16(uint16_t a, uint16_t b, uint16_t d, float_status *s) +{ + return float16_muladd(d, b, a, 0, s); +} + +static uint32_t fmadd32(uint32_t a, uint32_t b, uint32_t d, float_status *s) +{ + return float32_muladd(d, b, a, 0, s); +} + +static uint64_t fmadd64(uint64_t a, uint64_t b, uint64_t d, float_status *s) +{ + return float64_muladd(d, b, a, 0, s); +} + +RVVCALL(OPFVV3, vfmadd_vv_h, OP_UUU_H, H2, H2, H2, fmadd16) +RVVCALL(OPFVV3, vfmadd_vv_w, OP_UUU_W, H4, H4, H4, fmadd32) +RVVCALL(OPFVV3, vfmadd_vv_d, OP_UUU_D, H8, H8, H8, fmadd64) +GEN_VEXT_VV_ENV(vfmadd_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfmadd_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfmadd_vv_d, 8, 8, clearq) +RVVCALL(OPFVF3, vfmadd_vf_h, OP_UUU_H, H2, H2, fmadd16) +RVVCALL(OPFVF3, vfmadd_vf_w, OP_UUU_W, H4, H4, fmadd32) +RVVCALL(OPFVF3, vfmadd_vf_d, OP_UUU_D, H8, H8, fmadd64) +GEN_VEXT_VF(vfmadd_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfmadd_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfmadd_vf_d, 8, 8, clearq) + +static uint16_t fnmadd16(uint16_t a, uint16_t b, uint16_t d, float_status *s) +{ + return float16_muladd(d, b, a, + float_muladd_negate_c | float_muladd_negate_product, s); +} + +static uint32_t fnmadd32(uint32_t a, uint32_t b, uint32_t d, float_status *s) +{ + return float32_muladd(d, b, a, + float_muladd_negate_c | float_muladd_negate_product, s); +} + +static uint64_t fnmadd64(uint64_t a, uint64_t b, uint64_t d, float_status *s) +{ + return float64_muladd(d, b, a, + float_muladd_negate_c | float_muladd_negate_product, s); +} + +RVVCALL(OPFVV3, vfnmadd_vv_h, OP_UUU_H, H2, H2, H2, fnmadd16) +RVVCALL(OPFVV3, vfnmadd_vv_w, OP_UUU_W, H4, H4, H4, fnmadd32) +RVVCALL(OPFVV3, vfnmadd_vv_d, OP_UUU_D, H8, H8, H8, fnmadd64) +GEN_VEXT_VV_ENV(vfnmadd_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfnmadd_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfnmadd_vv_d, 8, 8, clearq) +RVVCALL(OPFVF3, vfnmadd_vf_h, OP_UUU_H, H2, H2, fnmadd16) +RVVCALL(OPFVF3, vfnmadd_vf_w, OP_UUU_W, H4, H4, fnmadd32) +RVVCALL(OPFVF3, vfnmadd_vf_d, OP_UUU_D, H8, H8, fnmadd64) +GEN_VEXT_VF(vfnmadd_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfnmadd_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfnmadd_vf_d, 8, 8, clearq) + +static uint16_t fmsub16(uint16_t a, uint16_t b, uint16_t d, float_status *s) +{ + return float16_muladd(d, b, a, float_muladd_negate_c, s); +} + +static uint32_t fmsub32(uint32_t a, uint32_t b, uint32_t d, float_status *s) +{ + return float32_muladd(d, b, a, float_muladd_negate_c, s); +} + +static uint64_t fmsub64(uint64_t a, uint64_t b, uint64_t d, float_status *s) +{ + return float64_muladd(d, b, a, float_muladd_negate_c, s); +} + +RVVCALL(OPFVV3, vfmsub_vv_h, OP_UUU_H, H2, H2, H2, fmsub16) +RVVCALL(OPFVV3, vfmsub_vv_w, OP_UUU_W, H4, H4, H4, fmsub32) +RVVCALL(OPFVV3, vfmsub_vv_d, OP_UUU_D, H8, H8, H8, fmsub64) +GEN_VEXT_VV_ENV(vfmsub_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfmsub_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfmsub_vv_d, 8, 8, clearq) +RVVCALL(OPFVF3, vfmsub_vf_h, OP_UUU_H, H2, H2, fmsub16) +RVVCALL(OPFVF3, vfmsub_vf_w, OP_UUU_W, H4, H4, fmsub32) +RVVCALL(OPFVF3, vfmsub_vf_d, OP_UUU_D, H8, H8, fmsub64) +GEN_VEXT_VF(vfmsub_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfmsub_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfmsub_vf_d, 8, 8, clearq) + +static uint16_t fnmsub16(uint16_t a, uint16_t b, uint16_t d, float_status *s) +{ + return float16_muladd(d, b, a, float_muladd_negate_product, s); +} + +static uint32_t fnmsub32(uint32_t a, uint32_t b, uint32_t d, float_status *s) +{ + return float32_muladd(d, b, a, float_muladd_negate_product, s); +} + +static uint64_t fnmsub64(uint64_t a, uint64_t b, uint64_t d, float_status *s) +{ + return float64_muladd(d, b, a, float_muladd_negate_product, s); +} + +RVVCALL(OPFVV3, vfnmsub_vv_h, OP_UUU_H, H2, H2, H2, fnmsub16) +RVVCALL(OPFVV3, vfnmsub_vv_w, OP_UUU_W, H4, H4, H4, fnmsub32) +RVVCALL(OPFVV3, vfnmsub_vv_d, OP_UUU_D, H8, H8, H8, fnmsub64) +GEN_VEXT_VV_ENV(vfnmsub_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfnmsub_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfnmsub_vv_d, 8, 8, clearq) +RVVCALL(OPFVF3, vfnmsub_vf_h, OP_UUU_H, H2, H2, fnmsub16) +RVVCALL(OPFVF3, vfnmsub_vf_w, OP_UUU_W, H4, H4, fnmsub32) +RVVCALL(OPFVF3, vfnmsub_vf_d, OP_UUU_D, H8, H8, fnmsub64) +GEN_VEXT_VF(vfnmsub_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfnmsub_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfnmsub_vf_d, 8, 8, clearq) From 0dd509594fbd53fc9c3edc79bd7a575f079c3c87 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:23 +0800 Subject: [PATCH 1836/2595] target/riscv: vector widening floating-point fused multiply-add instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-36-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 17 +++++ target/riscv/insn32.decode | 8 +++ target/riscv/insn_trans/trans_rvv.inc.c | 10 +++ target/riscv/vector_helper.c | 91 +++++++++++++++++++++++++ 4 files changed, 126 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 108a177f25..b537030a11 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -906,3 +906,20 @@ DEF_HELPER_6(vfmsub_vf_d, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfnmsub_vf_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfnmsub_vf_w, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfnmsub_vf_d, void, ptr, ptr, i64, ptr, env, i32) + +DEF_HELPER_6(vfwmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwnmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwnmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwmsac_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwmsac_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwnmsac_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwnmsac_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwmacc_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwmacc_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwnmacc_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwnmacc_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwmsac_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwmsac_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwnmsac_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfwnmsac_vf_w, void, ptr, ptr, i64, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 9ca765d37f..c9d5078385 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -481,6 +481,14 @@ vfmsub_vv 101010 . ..... ..... 001 ..... 1010111 @r_vm vfmsub_vf 101010 . ..... ..... 101 ..... 1010111 @r_vm vfnmsub_vv 101011 . ..... ..... 001 ..... 1010111 @r_vm vfnmsub_vf 101011 . ..... ..... 101 ..... 1010111 @r_vm +vfwmacc_vv 111100 . ..... ..... 001 ..... 1010111 @r_vm +vfwmacc_vf 111100 . ..... ..... 101 ..... 1010111 @r_vm +vfwnmacc_vv 111101 . ..... ..... 001 ..... 1010111 @r_vm +vfwnmacc_vf 111101 . ..... ..... 101 ..... 1010111 @r_vm +vfwmsac_vv 111110 . ..... ..... 001 ..... 1010111 @r_vm +vfwmsac_vf 111110 . ..... ..... 101 ..... 1010111 @r_vm +vfwnmsac_vv 111111 . ..... ..... 001 ..... 1010111 @r_vm +vfwnmsac_vf 111111 . ..... ..... 101 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index ee601fd790..3a5fd0cf89 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2079,3 +2079,13 @@ GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) + +/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ +GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) +GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) +GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) +GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 29dc1d1d73..607fcc8742 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -3683,3 +3683,94 @@ RVVCALL(OPFVF3, vfnmsub_vf_d, OP_UUU_D, H8, H8, fnmsub64) GEN_VEXT_VF(vfnmsub_vf_h, 2, 2, clearh) GEN_VEXT_VF(vfnmsub_vf_w, 4, 4, clearl) GEN_VEXT_VF(vfnmsub_vf_d, 8, 8, clearq) + +/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ +static uint32_t fwmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s) +{ + return float32_muladd(float16_to_float32(a, true, s), + float16_to_float32(b, true, s), d, 0, s); +} + +static uint64_t fwmacc32(uint32_t a, uint32_t b, uint64_t d, float_status *s) +{ + return float64_muladd(float32_to_float64(a, s), + float32_to_float64(b, s), d, 0, s); +} + +RVVCALL(OPFVV3, vfwmacc_vv_h, WOP_UUU_H, H4, H2, H2, fwmacc16) +RVVCALL(OPFVV3, vfwmacc_vv_w, WOP_UUU_W, H8, H4, H4, fwmacc32) +GEN_VEXT_VV_ENV(vfwmacc_vv_h, 2, 4, clearl) +GEN_VEXT_VV_ENV(vfwmacc_vv_w, 4, 8, clearq) +RVVCALL(OPFVF3, vfwmacc_vf_h, WOP_UUU_H, H4, H2, fwmacc16) +RVVCALL(OPFVF3, vfwmacc_vf_w, WOP_UUU_W, H8, H4, fwmacc32) +GEN_VEXT_VF(vfwmacc_vf_h, 2, 4, clearl) +GEN_VEXT_VF(vfwmacc_vf_w, 4, 8, clearq) + +static uint32_t fwnmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s) +{ + return float32_muladd(float16_to_float32(a, true, s), + float16_to_float32(b, true, s), d, + float_muladd_negate_c | float_muladd_negate_product, s); +} + +static uint64_t fwnmacc32(uint32_t a, uint32_t b, uint64_t d, float_status *s) +{ + return float64_muladd(float32_to_float64(a, s), + float32_to_float64(b, s), d, + float_muladd_negate_c | float_muladd_negate_product, s); +} + +RVVCALL(OPFVV3, vfwnmacc_vv_h, WOP_UUU_H, H4, H2, H2, fwnmacc16) +RVVCALL(OPFVV3, vfwnmacc_vv_w, WOP_UUU_W, H8, H4, H4, fwnmacc32) +GEN_VEXT_VV_ENV(vfwnmacc_vv_h, 2, 4, clearl) +GEN_VEXT_VV_ENV(vfwnmacc_vv_w, 4, 8, clearq) +RVVCALL(OPFVF3, vfwnmacc_vf_h, WOP_UUU_H, H4, H2, fwnmacc16) +RVVCALL(OPFVF3, vfwnmacc_vf_w, WOP_UUU_W, H8, H4, fwnmacc32) +GEN_VEXT_VF(vfwnmacc_vf_h, 2, 4, clearl) +GEN_VEXT_VF(vfwnmacc_vf_w, 4, 8, clearq) + +static uint32_t fwmsac16(uint16_t a, uint16_t b, uint32_t d, float_status *s) +{ + return float32_muladd(float16_to_float32(a, true, s), + float16_to_float32(b, true, s), d, + float_muladd_negate_c, s); +} + +static uint64_t fwmsac32(uint32_t a, uint32_t b, uint64_t d, float_status *s) +{ + return float64_muladd(float32_to_float64(a, s), + float32_to_float64(b, s), d, + float_muladd_negate_c, s); +} + +RVVCALL(OPFVV3, vfwmsac_vv_h, WOP_UUU_H, H4, H2, H2, fwmsac16) +RVVCALL(OPFVV3, vfwmsac_vv_w, WOP_UUU_W, H8, H4, H4, fwmsac32) +GEN_VEXT_VV_ENV(vfwmsac_vv_h, 2, 4, clearl) +GEN_VEXT_VV_ENV(vfwmsac_vv_w, 4, 8, clearq) +RVVCALL(OPFVF3, vfwmsac_vf_h, WOP_UUU_H, H4, H2, fwmsac16) +RVVCALL(OPFVF3, vfwmsac_vf_w, WOP_UUU_W, H8, H4, fwmsac32) +GEN_VEXT_VF(vfwmsac_vf_h, 2, 4, clearl) +GEN_VEXT_VF(vfwmsac_vf_w, 4, 8, clearq) + +static uint32_t fwnmsac16(uint16_t a, uint16_t b, uint32_t d, float_status *s) +{ + return float32_muladd(float16_to_float32(a, true, s), + float16_to_float32(b, true, s), d, + float_muladd_negate_product, s); +} + +static uint64_t fwnmsac32(uint32_t a, uint32_t b, uint64_t d, float_status *s) +{ + return float64_muladd(float32_to_float64(a, s), + float32_to_float64(b, s), d, + float_muladd_negate_product, s); +} + +RVVCALL(OPFVV3, vfwnmsac_vv_h, WOP_UUU_H, H4, H2, H2, fwnmsac16) +RVVCALL(OPFVV3, vfwnmsac_vv_w, WOP_UUU_W, H8, H4, H4, fwnmsac32) +GEN_VEXT_VV_ENV(vfwnmsac_vv_h, 2, 4, clearl) +GEN_VEXT_VV_ENV(vfwnmsac_vv_w, 4, 8, clearq) +RVVCALL(OPFVF3, vfwnmsac_vf_h, WOP_UUU_H, H4, H2, fwnmsac16) +RVVCALL(OPFVF3, vfwnmsac_vf_w, WOP_UUU_W, H8, H4, fwnmsac32) +GEN_VEXT_VF(vfwnmsac_vf_h, 2, 4, clearl) +GEN_VEXT_VF(vfwnmsac_vf_w, 4, 8, clearq) From d9e4ce72a5a0f7c404156d40d3252d4d6a9d6a36 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:24 +0800 Subject: [PATCH 1837/2595] target/riscv: vector floating-point square-root instruction Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-37-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 4 +++ target/riscv/insn32.decode | 3 ++ target/riscv/insn_trans/trans_rvv.inc.c | 43 +++++++++++++++++++++++++ target/riscv/vector_helper.c | 43 +++++++++++++++++++++++++ 4 files changed, 93 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index b537030a11..8d44154ad2 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -923,3 +923,7 @@ DEF_HELPER_6(vfwmsac_vf_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfwmsac_vf_w, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfwnmsac_vf_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfwnmsac_vf_w, void, ptr, ptr, i64, ptr, env, i32) + +DEF_HELPER_5(vfsqrt_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfsqrt_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfsqrt_v_d, void, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index c9d5078385..0d58c4c5e8 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -45,6 +45,7 @@ &shift shamt rs1 rd &atomic aq rl rs2 rs1 rd &rmrr vm rd rs1 rs2 +&rmr vm rd rs2 &rwdvm vm wd rd rs1 rs2 &r2nfvm vm rd rs1 nf &rnfvm vm rd rs1 rs2 nf @@ -68,6 +69,7 @@ @r2_rm ....... ..... ..... ... ..... ....... %rs1 %rm %rd @r2 ....... ..... ..... ... ..... ....... %rs1 %rd @r2_nfvm ... ... vm:1 ..... ..... ... ..... ....... &r2nfvm %nf %rs1 %rd +@r2_vm ...... vm:1 ..... ..... ... ..... ....... &rmr %rs2 %rd @r_nfvm ... ... vm:1 ..... ..... ... ..... ....... &rnfvm %nf %rs2 %rs1 %rd @r_vm ...... vm:1 ..... ..... ... ..... ....... &rmrr %rs2 %rs1 %rd @r_vm_1 ...... . ..... ..... ... ..... ....... &rmrr vm=1 %rs2 %rs1 %rd @@ -489,6 +491,7 @@ vfwmsac_vv 111110 . ..... ..... 001 ..... 1010111 @r_vm vfwmsac_vf 111110 . ..... ..... 101 ..... 1010111 @r_vm vfwnmsac_vv 111111 . ..... ..... 001 ..... 1010111 @r_vm vfwnmsac_vf 111111 . ..... ..... 101 ..... 1010111 @r_vm +vfsqrt_v 100011 . ..... 00000 001 ..... 1010111 @r2_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 3a5fd0cf89..e875c0e48a 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2089,3 +2089,46 @@ GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) + +/* Vector Floating-Point Square-Root Instruction */ + +/* + * If the current SEW does not correspond to a supported IEEE floating-point + * type, an illegal instruction exception is raised + */ +static bool opfv_check(DisasContext *s, arg_rmr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, false) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + (s->sew != 0)); +} + +#define GEN_OPFV_TRANS(NAME, CHECK) \ +static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ +{ \ + if (CHECK(s, a)) { \ + uint32_t data = 0; \ + static gen_helper_gvec_3_ptr * const fns[3] = { \ + gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, \ + gen_helper_##NAME##_d, \ + }; \ + TCGLabel *over = gen_new_label(); \ + gen_set_rm(s, 7); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ + vreg_ofs(s, a->rs2), cpu_env, 0, \ + s->vlen / 8, data, fns[s->sew - 1]); \ + gen_set_label(over); \ + return true; \ + } \ + return false; \ +} + +GEN_OPFV_TRANS(vfsqrt_v, opfv_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 607fcc8742..40ea67d116 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -3774,3 +3774,46 @@ RVVCALL(OPFVF3, vfwnmsac_vf_h, WOP_UUU_H, H4, H2, fwnmsac16) RVVCALL(OPFVF3, vfwnmsac_vf_w, WOP_UUU_W, H8, H4, fwnmsac32) GEN_VEXT_VF(vfwnmsac_vf_h, 2, 4, clearl) GEN_VEXT_VF(vfwnmsac_vf_w, 4, 8, clearq) + +/* Vector Floating-Point Square-Root Instruction */ +/* (TD, T2, TX2) */ +#define OP_UU_H uint16_t, uint16_t, uint16_t +#define OP_UU_W uint32_t, uint32_t, uint32_t +#define OP_UU_D uint64_t, uint64_t, uint64_t + +#define OPFVV1(NAME, TD, T2, TX2, HD, HS2, OP) \ +static void do_##NAME(void *vd, void *vs2, int i, \ + CPURISCVState *env) \ +{ \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + *((TD *)vd + HD(i)) = OP(s2, &env->fp_status); \ +} + +#define GEN_VEXT_V_ENV(NAME, ESZ, DSZ, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t vlmax = vext_maxsz(desc) / ESZ; \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t i; \ + \ + if (vl == 0) { \ + return; \ + } \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + do_##NAME(vd, vs2, i, env); \ + } \ + CLEAR_FN(vd, vl, vl * DSZ, vlmax * DSZ); \ +} + +RVVCALL(OPFVV1, vfsqrt_v_h, OP_UU_H, H2, H2, float16_sqrt) +RVVCALL(OPFVV1, vfsqrt_v_w, OP_UU_W, H4, H4, float32_sqrt) +RVVCALL(OPFVV1, vfsqrt_v_d, OP_UU_D, H8, H8, float64_sqrt) +GEN_VEXT_V_ENV(vfsqrt_v_h, 2, 2, clearh) +GEN_VEXT_V_ENV(vfsqrt_v_w, 4, 4, clearl) +GEN_VEXT_V_ENV(vfsqrt_v_d, 8, 8, clearq) From 230b53ddd706c8b18a6d9beed1a0153b276d7037 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:25 +0800 Subject: [PATCH 1838/2595] target/riscv: vector floating-point min/max instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-38-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 13 ++++++++++++ target/riscv/insn32.decode | 4 ++++ target/riscv/insn_trans/trans_rvv.inc.c | 6 ++++++ target/riscv/vector_helper.c | 27 +++++++++++++++++++++++++ 4 files changed, 50 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 8d44154ad2..a080f8358a 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -927,3 +927,16 @@ DEF_HELPER_6(vfwnmsac_vf_w, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_5(vfsqrt_v_h, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfsqrt_v_w, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfsqrt_v_d, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_6(vfmin_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmin_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmin_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmax_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmax_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmax_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfmin_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmin_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmin_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmax_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmax_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmax_vf_d, void, ptr, ptr, i64, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 0d58c4c5e8..854ff9a38f 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -492,6 +492,10 @@ vfwmsac_vf 111110 . ..... ..... 101 ..... 1010111 @r_vm vfwnmsac_vv 111111 . ..... ..... 001 ..... 1010111 @r_vm vfwnmsac_vf 111111 . ..... ..... 101 ..... 1010111 @r_vm vfsqrt_v 100011 . ..... 00000 001 ..... 1010111 @r2_vm +vfmin_vv 000100 . ..... ..... 001 ..... 1010111 @r_vm +vfmin_vf 000100 . ..... ..... 101 ..... 1010111 @r_vm +vfmax_vv 000110 . ..... ..... 001 ..... 1010111 @r_vm +vfmax_vf 000110 . ..... ..... 101 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index e875c0e48a..b40e8eec53 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2132,3 +2132,9 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ } GEN_OPFV_TRANS(vfsqrt_v, opfv_check) + +/* Vector Floating-Point MIN/MAX Instructions */ +GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) +GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) +GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) +GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 40ea67d116..6779e4b976 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -3817,3 +3817,30 @@ RVVCALL(OPFVV1, vfsqrt_v_d, OP_UU_D, H8, H8, float64_sqrt) GEN_VEXT_V_ENV(vfsqrt_v_h, 2, 2, clearh) GEN_VEXT_V_ENV(vfsqrt_v_w, 4, 4, clearl) GEN_VEXT_V_ENV(vfsqrt_v_d, 8, 8, clearq) + +/* Vector Floating-Point MIN/MAX Instructions */ +RVVCALL(OPFVV2, vfmin_vv_h, OP_UUU_H, H2, H2, H2, float16_minnum) +RVVCALL(OPFVV2, vfmin_vv_w, OP_UUU_W, H4, H4, H4, float32_minnum) +RVVCALL(OPFVV2, vfmin_vv_d, OP_UUU_D, H8, H8, H8, float64_minnum) +GEN_VEXT_VV_ENV(vfmin_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfmin_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfmin_vv_d, 8, 8, clearq) +RVVCALL(OPFVF2, vfmin_vf_h, OP_UUU_H, H2, H2, float16_minnum) +RVVCALL(OPFVF2, vfmin_vf_w, OP_UUU_W, H4, H4, float32_minnum) +RVVCALL(OPFVF2, vfmin_vf_d, OP_UUU_D, H8, H8, float64_minnum) +GEN_VEXT_VF(vfmin_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfmin_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfmin_vf_d, 8, 8, clearq) + +RVVCALL(OPFVV2, vfmax_vv_h, OP_UUU_H, H2, H2, H2, float16_maxnum) +RVVCALL(OPFVV2, vfmax_vv_w, OP_UUU_W, H4, H4, H4, float32_maxnum) +RVVCALL(OPFVV2, vfmax_vv_d, OP_UUU_D, H8, H8, H8, float64_maxnum) +GEN_VEXT_VV_ENV(vfmax_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfmax_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfmax_vv_d, 8, 8, clearq) +RVVCALL(OPFVF2, vfmax_vf_h, OP_UUU_H, H2, H2, float16_maxnum) +RVVCALL(OPFVF2, vfmax_vf_w, OP_UUU_W, H4, H4, float32_maxnum) +RVVCALL(OPFVF2, vfmax_vf_d, OP_UUU_D, H8, H8, float64_maxnum) +GEN_VEXT_VF(vfmax_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfmax_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfmax_vf_d, 8, 8, clearq) From 1d426b81f71eeeb1cbfec76c2f27ed0495719fb0 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:26 +0800 Subject: [PATCH 1839/2595] target/riscv: vector floating-point sign-injection instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-39-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 19 ++++++ target/riscv/insn32.decode | 6 ++ target/riscv/insn_trans/trans_rvv.inc.c | 8 +++ target/riscv/vector_helper.c | 85 +++++++++++++++++++++++++ 4 files changed, 118 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index a080f8358a..eea4c59820 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -940,3 +940,22 @@ DEF_HELPER_6(vfmin_vf_d, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfmax_vf_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfmax_vf_w, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfmax_vf_d, void, ptr, ptr, i64, ptr, env, i32) + +DEF_HELPER_6(vfsgnj_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsgnj_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsgnj_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsgnjn_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsgnjn_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsgnjn_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsgnjx_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsgnjx_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsgnjx_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfsgnj_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfsgnj_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfsgnj_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfsgnjn_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfsgnjn_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfsgnjn_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfsgnjx_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfsgnjx_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfsgnjx_vf_d, void, ptr, ptr, i64, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 854ff9a38f..0e173e9b71 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -496,6 +496,12 @@ vfmin_vv 000100 . ..... ..... 001 ..... 1010111 @r_vm vfmin_vf 000100 . ..... ..... 101 ..... 1010111 @r_vm vfmax_vv 000110 . ..... ..... 001 ..... 1010111 @r_vm vfmax_vf 000110 . ..... ..... 101 ..... 1010111 @r_vm +vfsgnj_vv 001000 . ..... ..... 001 ..... 1010111 @r_vm +vfsgnj_vf 001000 . ..... ..... 101 ..... 1010111 @r_vm +vfsgnjn_vv 001001 . ..... ..... 001 ..... 1010111 @r_vm +vfsgnjn_vf 001001 . ..... ..... 101 ..... 1010111 @r_vm +vfsgnjx_vv 001010 . ..... ..... 001 ..... 1010111 @r_vm +vfsgnjx_vf 001010 . ..... ..... 101 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index b40e8eec53..460d9bce8c 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2138,3 +2138,11 @@ GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) + +/* Vector Floating-Point Sign-Injection Instructions */ +GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check) +GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check) +GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) +GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) +GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) +GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 6779e4b976..7f1b7a8614 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -3844,3 +3844,88 @@ RVVCALL(OPFVF2, vfmax_vf_d, OP_UUU_D, H8, H8, float64_maxnum) GEN_VEXT_VF(vfmax_vf_h, 2, 2, clearh) GEN_VEXT_VF(vfmax_vf_w, 4, 4, clearl) GEN_VEXT_VF(vfmax_vf_d, 8, 8, clearq) + +/* Vector Floating-Point Sign-Injection Instructions */ +static uint16_t fsgnj16(uint16_t a, uint16_t b, float_status *s) +{ + return deposit64(b, 0, 15, a); +} + +static uint32_t fsgnj32(uint32_t a, uint32_t b, float_status *s) +{ + return deposit64(b, 0, 31, a); +} + +static uint64_t fsgnj64(uint64_t a, uint64_t b, float_status *s) +{ + return deposit64(b, 0, 63, a); +} + +RVVCALL(OPFVV2, vfsgnj_vv_h, OP_UUU_H, H2, H2, H2, fsgnj16) +RVVCALL(OPFVV2, vfsgnj_vv_w, OP_UUU_W, H4, H4, H4, fsgnj32) +RVVCALL(OPFVV2, vfsgnj_vv_d, OP_UUU_D, H8, H8, H8, fsgnj64) +GEN_VEXT_VV_ENV(vfsgnj_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfsgnj_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfsgnj_vv_d, 8, 8, clearq) +RVVCALL(OPFVF2, vfsgnj_vf_h, OP_UUU_H, H2, H2, fsgnj16) +RVVCALL(OPFVF2, vfsgnj_vf_w, OP_UUU_W, H4, H4, fsgnj32) +RVVCALL(OPFVF2, vfsgnj_vf_d, OP_UUU_D, H8, H8, fsgnj64) +GEN_VEXT_VF(vfsgnj_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfsgnj_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfsgnj_vf_d, 8, 8, clearq) + +static uint16_t fsgnjn16(uint16_t a, uint16_t b, float_status *s) +{ + return deposit64(~b, 0, 15, a); +} + +static uint32_t fsgnjn32(uint32_t a, uint32_t b, float_status *s) +{ + return deposit64(~b, 0, 31, a); +} + +static uint64_t fsgnjn64(uint64_t a, uint64_t b, float_status *s) +{ + return deposit64(~b, 0, 63, a); +} + +RVVCALL(OPFVV2, vfsgnjn_vv_h, OP_UUU_H, H2, H2, H2, fsgnjn16) +RVVCALL(OPFVV2, vfsgnjn_vv_w, OP_UUU_W, H4, H4, H4, fsgnjn32) +RVVCALL(OPFVV2, vfsgnjn_vv_d, OP_UUU_D, H8, H8, H8, fsgnjn64) +GEN_VEXT_VV_ENV(vfsgnjn_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfsgnjn_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfsgnjn_vv_d, 8, 8, clearq) +RVVCALL(OPFVF2, vfsgnjn_vf_h, OP_UUU_H, H2, H2, fsgnjn16) +RVVCALL(OPFVF2, vfsgnjn_vf_w, OP_UUU_W, H4, H4, fsgnjn32) +RVVCALL(OPFVF2, vfsgnjn_vf_d, OP_UUU_D, H8, H8, fsgnjn64) +GEN_VEXT_VF(vfsgnjn_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfsgnjn_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfsgnjn_vf_d, 8, 8, clearq) + +static uint16_t fsgnjx16(uint16_t a, uint16_t b, float_status *s) +{ + return deposit64(b ^ a, 0, 15, a); +} + +static uint32_t fsgnjx32(uint32_t a, uint32_t b, float_status *s) +{ + return deposit64(b ^ a, 0, 31, a); +} + +static uint64_t fsgnjx64(uint64_t a, uint64_t b, float_status *s) +{ + return deposit64(b ^ a, 0, 63, a); +} + +RVVCALL(OPFVV2, vfsgnjx_vv_h, OP_UUU_H, H2, H2, H2, fsgnjx16) +RVVCALL(OPFVV2, vfsgnjx_vv_w, OP_UUU_W, H4, H4, H4, fsgnjx32) +RVVCALL(OPFVV2, vfsgnjx_vv_d, OP_UUU_D, H8, H8, H8, fsgnjx64) +GEN_VEXT_VV_ENV(vfsgnjx_vv_h, 2, 2, clearh) +GEN_VEXT_VV_ENV(vfsgnjx_vv_w, 4, 4, clearl) +GEN_VEXT_VV_ENV(vfsgnjx_vv_d, 8, 8, clearq) +RVVCALL(OPFVF2, vfsgnjx_vf_h, OP_UUU_H, H2, H2, fsgnjx16) +RVVCALL(OPFVF2, vfsgnjx_vf_w, OP_UUU_W, H4, H4, fsgnjx32) +RVVCALL(OPFVF2, vfsgnjx_vf_d, OP_UUU_D, H8, H8, fsgnjx64) +GEN_VEXT_VF(vfsgnjx_vf_h, 2, 2, clearh) +GEN_VEXT_VF(vfsgnjx_vf_w, 4, 4, clearl) +GEN_VEXT_VF(vfsgnjx_vf_d, 8, 8, clearq) From 2a68e9e568faddf4d689a37fa6895bcb8404a677 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:27 +0800 Subject: [PATCH 1840/2595] target/riscv: vector floating-point compare instructions Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-40-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 37 +++++ target/riscv/insn32.decode | 12 ++ target/riscv/insn_trans/trans_rvv.inc.c | 35 +++++ target/riscv/vector_helper.c | 174 ++++++++++++++++++++++++ 4 files changed, 258 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index eea4c59820..0e8d241831 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -959,3 +959,40 @@ DEF_HELPER_6(vfsgnjn_vf_d, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfsgnjx_vf_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfsgnjx_vf_w, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfsgnjx_vf_d, void, ptr, ptr, i64, ptr, env, i32) + +DEF_HELPER_6(vmfeq_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmfeq_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmfeq_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmfne_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmfne_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmfne_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmflt_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmflt_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmflt_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmfle_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmfle_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmfle_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmfeq_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfeq_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfeq_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfne_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfne_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfne_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmflt_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmflt_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmflt_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfle_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfle_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfle_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfgt_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfgt_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfgt_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfge_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfge_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmfge_vf_d, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmford_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmford_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmford_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmford_vf_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmford_vf_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vmford_vf_d, void, ptr, ptr, i64, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 0e173e9b71..59fb1a2425 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -502,6 +502,18 @@ vfsgnjn_vv 001001 . ..... ..... 001 ..... 1010111 @r_vm vfsgnjn_vf 001001 . ..... ..... 101 ..... 1010111 @r_vm vfsgnjx_vv 001010 . ..... ..... 001 ..... 1010111 @r_vm vfsgnjx_vf 001010 . ..... ..... 101 ..... 1010111 @r_vm +vmfeq_vv 011000 . ..... ..... 001 ..... 1010111 @r_vm +vmfeq_vf 011000 . ..... ..... 101 ..... 1010111 @r_vm +vmfne_vv 011100 . ..... ..... 001 ..... 1010111 @r_vm +vmfne_vf 011100 . ..... ..... 101 ..... 1010111 @r_vm +vmflt_vv 011011 . ..... ..... 001 ..... 1010111 @r_vm +vmflt_vf 011011 . ..... ..... 101 ..... 1010111 @r_vm +vmfle_vv 011001 . ..... ..... 001 ..... 1010111 @r_vm +vmfle_vf 011001 . ..... ..... 101 ..... 1010111 @r_vm +vmfgt_vf 011101 . ..... ..... 101 ..... 1010111 @r_vm +vmfge_vf 011111 . ..... ..... 101 ..... 1010111 @r_vm +vmford_vv 011010 . ..... ..... 001 ..... 1010111 @r_vm +vmford_vf 011010 . ..... ..... 101 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 460d9bce8c..791d377e3c 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2146,3 +2146,38 @@ GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) + +/* Vector Floating-Point Compare Instructions */ +static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rs2, false) && + vext_check_reg(s, a->rs1, false) && + (s->sew != 0) && + ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && + vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) || + (s->lmul == 0))); +} + +GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) +GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check) +GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check) +GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check) +GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check) + +static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rs2, false) && + (s->sew != 0) && + (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) || + (s->lmul == 0))); +} + +GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) +GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check) +GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check) +GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) +GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) +GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) +GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 7f1b7a8614..0c12752f49 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -3929,3 +3929,177 @@ RVVCALL(OPFVF2, vfsgnjx_vf_d, OP_UUU_D, H8, H8, fsgnjx64) GEN_VEXT_VF(vfsgnjx_vf_h, 2, 2, clearh) GEN_VEXT_VF(vfsgnjx_vf_w, 4, 4, clearl) GEN_VEXT_VF(vfsgnjx_vf_d, 8, 8, clearq) + +/* Vector Floating-Point Compare Instructions */ +#define GEN_VEXT_CMP_VV_ENV(NAME, ETYPE, H, DO_OP) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ + ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + vext_set_elem_mask(vd, mlen, i, \ + DO_OP(s2, s1, &env->fp_status)); \ + } \ + for (; i < vlmax; i++) { \ + vext_set_elem_mask(vd, mlen, i, 0); \ + } \ +} + +static bool float16_eq_quiet(uint16_t a, uint16_t b, float_status *s) +{ + FloatRelation compare = float16_compare_quiet(a, b, s); + return compare == float_relation_equal; +} + +GEN_VEXT_CMP_VV_ENV(vmfeq_vv_h, uint16_t, H2, float16_eq_quiet) +GEN_VEXT_CMP_VV_ENV(vmfeq_vv_w, uint32_t, H4, float32_eq_quiet) +GEN_VEXT_CMP_VV_ENV(vmfeq_vv_d, uint64_t, H8, float64_eq_quiet) + +#define GEN_VEXT_CMP_VF(NAME, ETYPE, H, DO_OP) \ +void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + vext_set_elem_mask(vd, mlen, i, \ + DO_OP(s2, (ETYPE)s1, &env->fp_status)); \ + } \ + for (; i < vlmax; i++) { \ + vext_set_elem_mask(vd, mlen, i, 0); \ + } \ +} + +GEN_VEXT_CMP_VF(vmfeq_vf_h, uint16_t, H2, float16_eq_quiet) +GEN_VEXT_CMP_VF(vmfeq_vf_w, uint32_t, H4, float32_eq_quiet) +GEN_VEXT_CMP_VF(vmfeq_vf_d, uint64_t, H8, float64_eq_quiet) + +static bool vmfne16(uint16_t a, uint16_t b, float_status *s) +{ + FloatRelation compare = float16_compare_quiet(a, b, s); + return compare != float_relation_equal; +} + +static bool vmfne32(uint32_t a, uint32_t b, float_status *s) +{ + FloatRelation compare = float32_compare_quiet(a, b, s); + return compare != float_relation_equal; +} + +static bool vmfne64(uint64_t a, uint64_t b, float_status *s) +{ + FloatRelation compare = float64_compare_quiet(a, b, s); + return compare != float_relation_equal; +} + +GEN_VEXT_CMP_VV_ENV(vmfne_vv_h, uint16_t, H2, vmfne16) +GEN_VEXT_CMP_VV_ENV(vmfne_vv_w, uint32_t, H4, vmfne32) +GEN_VEXT_CMP_VV_ENV(vmfne_vv_d, uint64_t, H8, vmfne64) +GEN_VEXT_CMP_VF(vmfne_vf_h, uint16_t, H2, vmfne16) +GEN_VEXT_CMP_VF(vmfne_vf_w, uint32_t, H4, vmfne32) +GEN_VEXT_CMP_VF(vmfne_vf_d, uint64_t, H8, vmfne64) + +static bool float16_lt(uint16_t a, uint16_t b, float_status *s) +{ + FloatRelation compare = float16_compare(a, b, s); + return compare == float_relation_less; +} + +GEN_VEXT_CMP_VV_ENV(vmflt_vv_h, uint16_t, H2, float16_lt) +GEN_VEXT_CMP_VV_ENV(vmflt_vv_w, uint32_t, H4, float32_lt) +GEN_VEXT_CMP_VV_ENV(vmflt_vv_d, uint64_t, H8, float64_lt) +GEN_VEXT_CMP_VF(vmflt_vf_h, uint16_t, H2, float16_lt) +GEN_VEXT_CMP_VF(vmflt_vf_w, uint32_t, H4, float32_lt) +GEN_VEXT_CMP_VF(vmflt_vf_d, uint64_t, H8, float64_lt) + +static bool float16_le(uint16_t a, uint16_t b, float_status *s) +{ + FloatRelation compare = float16_compare(a, b, s); + return compare == float_relation_less || + compare == float_relation_equal; +} + +GEN_VEXT_CMP_VV_ENV(vmfle_vv_h, uint16_t, H2, float16_le) +GEN_VEXT_CMP_VV_ENV(vmfle_vv_w, uint32_t, H4, float32_le) +GEN_VEXT_CMP_VV_ENV(vmfle_vv_d, uint64_t, H8, float64_le) +GEN_VEXT_CMP_VF(vmfle_vf_h, uint16_t, H2, float16_le) +GEN_VEXT_CMP_VF(vmfle_vf_w, uint32_t, H4, float32_le) +GEN_VEXT_CMP_VF(vmfle_vf_d, uint64_t, H8, float64_le) + +static bool vmfgt16(uint16_t a, uint16_t b, float_status *s) +{ + FloatRelation compare = float16_compare(a, b, s); + return compare == float_relation_greater; +} + +static bool vmfgt32(uint32_t a, uint32_t b, float_status *s) +{ + FloatRelation compare = float32_compare(a, b, s); + return compare == float_relation_greater; +} + +static bool vmfgt64(uint64_t a, uint64_t b, float_status *s) +{ + FloatRelation compare = float64_compare(a, b, s); + return compare == float_relation_greater; +} + +GEN_VEXT_CMP_VF(vmfgt_vf_h, uint16_t, H2, vmfgt16) +GEN_VEXT_CMP_VF(vmfgt_vf_w, uint32_t, H4, vmfgt32) +GEN_VEXT_CMP_VF(vmfgt_vf_d, uint64_t, H8, vmfgt64) + +static bool vmfge16(uint16_t a, uint16_t b, float_status *s) +{ + FloatRelation compare = float16_compare(a, b, s); + return compare == float_relation_greater || + compare == float_relation_equal; +} + +static bool vmfge32(uint32_t a, uint32_t b, float_status *s) +{ + FloatRelation compare = float32_compare(a, b, s); + return compare == float_relation_greater || + compare == float_relation_equal; +} + +static bool vmfge64(uint64_t a, uint64_t b, float_status *s) +{ + FloatRelation compare = float64_compare(a, b, s); + return compare == float_relation_greater || + compare == float_relation_equal; +} + +GEN_VEXT_CMP_VF(vmfge_vf_h, uint16_t, H2, vmfge16) +GEN_VEXT_CMP_VF(vmfge_vf_w, uint32_t, H4, vmfge32) +GEN_VEXT_CMP_VF(vmfge_vf_d, uint64_t, H8, vmfge64) + +static bool float16_unordered_quiet(uint16_t a, uint16_t b, float_status *s) +{ + FloatRelation compare = float16_compare_quiet(a, b, s); + return compare == float_relation_unordered; +} + +GEN_VEXT_CMP_VV_ENV(vmford_vv_h, uint16_t, H2, !float16_unordered_quiet) +GEN_VEXT_CMP_VV_ENV(vmford_vv_w, uint32_t, H4, !float32_unordered_quiet) +GEN_VEXT_CMP_VV_ENV(vmford_vv_d, uint64_t, H8, !float64_unordered_quiet) +GEN_VEXT_CMP_VF(vmford_vf_h, uint16_t, H2, !float16_unordered_quiet) +GEN_VEXT_CMP_VF(vmford_vf_w, uint32_t, H4, !float32_unordered_quiet) +GEN_VEXT_CMP_VF(vmford_vf_d, uint64_t, H8, !float64_unordered_quiet) From 121ddbb36f17d24a7f39d6024d9b3145d154a98c Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:28 +0800 Subject: [PATCH 1841/2595] target/riscv: vector floating-point classify instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-41-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/fpu_helper.c | 33 +-------- target/riscv/helper.h | 4 ++ target/riscv/insn32.decode | 1 + target/riscv/insn_trans/trans_rvv.inc.c | 3 + target/riscv/internals.h | 5 ++ target/riscv/vector_helper.c | 91 +++++++++++++++++++++++++ 6 files changed, 107 insertions(+), 30 deletions(-) diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c index 0b79562a69..4379756dc4 100644 --- a/target/riscv/fpu_helper.c +++ b/target/riscv/fpu_helper.c @@ -22,6 +22,7 @@ #include "exec/exec-all.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" +#include "internals.h" target_ulong riscv_cpu_get_fflags(CPURISCVState *env) { @@ -230,21 +231,7 @@ uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1) target_ulong helper_fclass_s(uint64_t frs1) { - float32 f = frs1; - bool sign = float32_is_neg(f); - - if (float32_is_infinity(f)) { - return sign ? 1 << 0 : 1 << 7; - } else if (float32_is_zero(f)) { - return sign ? 1 << 3 : 1 << 4; - } else if (float32_is_zero_or_denormal(f)) { - return sign ? 1 << 2 : 1 << 5; - } else if (float32_is_any_nan(f)) { - float_status s = { }; /* for snan_bit_is_one */ - return float32_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8; - } else { - return sign ? 1 << 1 : 1 << 6; - } + return fclass_s(frs1); } uint64_t helper_fadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2) @@ -353,19 +340,5 @@ uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t rs1) target_ulong helper_fclass_d(uint64_t frs1) { - float64 f = frs1; - bool sign = float64_is_neg(f); - - if (float64_is_infinity(f)) { - return sign ? 1 << 0 : 1 << 7; - } else if (float64_is_zero(f)) { - return sign ? 1 << 3 : 1 << 4; - } else if (float64_is_zero_or_denormal(f)) { - return sign ? 1 << 2 : 1 << 5; - } else if (float64_is_any_nan(f)) { - float_status s = { }; /* for snan_bit_is_one */ - return float64_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8; - } else { - return sign ? 1 << 1 : 1 << 6; - } + return fclass_d(frs1); } diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 0e8d241831..fb744c5ec9 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -996,3 +996,7 @@ DEF_HELPER_6(vmford_vv_d, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vmford_vf_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vmford_vf_w, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vmford_vf_d, void, ptr, ptr, i64, ptr, env, i32) + +DEF_HELPER_5(vfclass_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfclass_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfclass_v_d, void, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 59fb1a2425..6912eda259 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -514,6 +514,7 @@ vmfgt_vf 011101 . ..... ..... 101 ..... 1010111 @r_vm vmfge_vf 011111 . ..... ..... 101 ..... 1010111 @r_vm vmford_vv 011010 . ..... ..... 001 ..... 1010111 @r_vm vmford_vf 011010 . ..... ..... 101 ..... 1010111 @r_vm +vfclass_v 100011 . ..... 10000 001 ..... 1010111 @r2_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 791d377e3c..361bdce654 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2181,3 +2181,6 @@ GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check) + +/* Vector Floating-Point Classify Instruction */ +GEN_OPFV_TRANS(vfclass_v, opfv_check) diff --git a/target/riscv/internals.h b/target/riscv/internals.h index e59e8b30ad..f3cea478f7 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -27,4 +27,9 @@ FIELD(VDATA, VM, 8, 1) FIELD(VDATA, LMUL, 9, 2) FIELD(VDATA, NF, 11, 4) FIELD(VDATA, WD, 11, 1) + +/* float point classify helpers */ +target_ulong fclass_h(uint64_t frs1); +target_ulong fclass_s(uint64_t frs1); +target_ulong fclass_d(uint64_t frs1); #endif diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 0c12752f49..63f08e4554 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4103,3 +4103,94 @@ GEN_VEXT_CMP_VV_ENV(vmford_vv_d, uint64_t, H8, !float64_unordered_quiet) GEN_VEXT_CMP_VF(vmford_vf_h, uint16_t, H2, !float16_unordered_quiet) GEN_VEXT_CMP_VF(vmford_vf_w, uint32_t, H4, !float32_unordered_quiet) GEN_VEXT_CMP_VF(vmford_vf_d, uint64_t, H8, !float64_unordered_quiet) + +/* Vector Floating-Point Classify Instruction */ +#define OPIVV1(NAME, TD, T2, TX2, HD, HS2, OP) \ +static void do_##NAME(void *vd, void *vs2, int i) \ +{ \ + TX2 s2 = *((T2 *)vs2 + HS2(i)); \ + *((TD *)vd + HD(i)) = OP(s2); \ +} + +#define GEN_VEXT_V(NAME, ESZ, DSZ, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t vlmax = vext_maxsz(desc) / ESZ; \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + do_##NAME(vd, vs2, i); \ + } \ + CLEAR_FN(vd, vl, vl * DSZ, vlmax * DSZ); \ +} + +target_ulong fclass_h(uint64_t frs1) +{ + float16 f = frs1; + bool sign = float16_is_neg(f); + + if (float16_is_infinity(f)) { + return sign ? 1 << 0 : 1 << 7; + } else if (float16_is_zero(f)) { + return sign ? 1 << 3 : 1 << 4; + } else if (float16_is_zero_or_denormal(f)) { + return sign ? 1 << 2 : 1 << 5; + } else if (float16_is_any_nan(f)) { + float_status s = { }; /* for snan_bit_is_one */ + return float16_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8; + } else { + return sign ? 1 << 1 : 1 << 6; + } +} + +target_ulong fclass_s(uint64_t frs1) +{ + float32 f = frs1; + bool sign = float32_is_neg(f); + + if (float32_is_infinity(f)) { + return sign ? 1 << 0 : 1 << 7; + } else if (float32_is_zero(f)) { + return sign ? 1 << 3 : 1 << 4; + } else if (float32_is_zero_or_denormal(f)) { + return sign ? 1 << 2 : 1 << 5; + } else if (float32_is_any_nan(f)) { + float_status s = { }; /* for snan_bit_is_one */ + return float32_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8; + } else { + return sign ? 1 << 1 : 1 << 6; + } +} + +target_ulong fclass_d(uint64_t frs1) +{ + float64 f = frs1; + bool sign = float64_is_neg(f); + + if (float64_is_infinity(f)) { + return sign ? 1 << 0 : 1 << 7; + } else if (float64_is_zero(f)) { + return sign ? 1 << 3 : 1 << 4; + } else if (float64_is_zero_or_denormal(f)) { + return sign ? 1 << 2 : 1 << 5; + } else if (float64_is_any_nan(f)) { + float_status s = { }; /* for snan_bit_is_one */ + return float64_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8; + } else { + return sign ? 1 << 1 : 1 << 6; + } +} + +RVVCALL(OPIVV1, vfclass_v_h, OP_UU_H, H2, H2, fclass_h) +RVVCALL(OPIVV1, vfclass_v_w, OP_UU_W, H4, H4, fclass_s) +RVVCALL(OPIVV1, vfclass_v_d, OP_UU_D, H8, H8, fclass_d) +GEN_VEXT_V(vfclass_v_h, 2, 2, clearh) +GEN_VEXT_V(vfclass_v_w, 4, 4, clearl) +GEN_VEXT_V(vfclass_v_d, 8, 8, clearq) From 64ab5846974140118c64e4d94ff2696932a0a58b Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:29 +0800 Subject: [PATCH 1842/2595] target/riscv: vector floating-point merge instructions Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-42-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 4 +++ target/riscv/insn32.decode | 2 ++ target/riscv/insn_trans/trans_rvv.inc.c | 38 +++++++++++++++++++++++++ target/riscv/vector_helper.c | 24 ++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index fb744c5ec9..2c3f0a4e0c 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1000,3 +1000,7 @@ DEF_HELPER_6(vmford_vf_d, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_5(vfclass_v_h, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfclass_v_w, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfclass_v_d, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_6(vfmerge_vfm_h, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmerge_vfm_w, void, ptr, ptr, i64, ptr, env, i32) +DEF_HELPER_6(vfmerge_vfm_d, void, ptr, ptr, i64, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 6912eda259..38e7445a16 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -515,6 +515,8 @@ vmfge_vf 011111 . ..... ..... 101 ..... 1010111 @r_vm vmford_vv 011010 . ..... ..... 001 ..... 1010111 @r_vm vmford_vf 011010 . ..... ..... 101 ..... 1010111 @r_vm vfclass_v 100011 . ..... 10000 001 ..... 1010111 @r2_vm +vfmerge_vfm 010111 0 ..... ..... 101 ..... 1010111 @r_vm_0 +vfmv_v_f 010111 1 00000 ..... 101 ..... 1010111 @r2 vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 361bdce654..b6872376ce 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2184,3 +2184,41 @@ GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check) /* Vector Floating-Point Classify Instruction */ GEN_OPFV_TRANS(vfclass_v, opfv_check) + +/* Vector Floating-Point Merge Instruction */ +GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check) + +static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) +{ + if (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false) && + (s->sew != 0)) { + + if (s->vl_eq_vlmax) { + tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), + MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]); + } else { + TCGv_ptr dest; + TCGv_i32 desc; + uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); + static gen_helper_vmv_vx * const fns[3] = { + gen_helper_vmv_v_x_h, + gen_helper_vmv_v_x_w, + gen_helper_vmv_v_x_d, + }; + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + dest = tcg_temp_new_ptr(); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); + fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc); + + tcg_temp_free_ptr(dest); + tcg_temp_free_i32(desc); + gen_set_label(over); + } + return true; + } + return false; +} diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 63f08e4554..1d5667f471 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4194,3 +4194,27 @@ RVVCALL(OPIVV1, vfclass_v_d, OP_UU_D, H8, H8, fclass_d) GEN_VEXT_V(vfclass_v_h, 2, 2, clearh) GEN_VEXT_V(vfclass_v_w, 4, 4, clearl) GEN_VEXT_V(vfclass_v_d, 8, 8, clearq) + +/* Vector Floating-Point Merge Instruction */ +#define GEN_VFMERGE_VF(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t vlmax = vext_maxsz(desc) / esz; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ + *((ETYPE *)vd + H(i)) \ + = (!vm && !vext_elem_mask(v0, mlen, i) ? s2 : s1); \ + } \ + CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \ +} + +GEN_VFMERGE_VF(vfmerge_vfm_h, int16_t, H2, clearh) +GEN_VFMERGE_VF(vfmerge_vfm_w, int32_t, H4, clearl) +GEN_VFMERGE_VF(vfmerge_vfm_d, int64_t, H8, clearq) From 921009732614fd620c75f05496597796719544cf Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:30 +0800 Subject: [PATCH 1843/2595] target/riscv: vector floating-point/integer type-convert instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-43-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 13 ++++++++++ target/riscv/insn32.decode | 4 +++ target/riscv/insn_trans/trans_rvv.inc.c | 6 +++++ target/riscv/vector_helper.c | 33 +++++++++++++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 2c3f0a4e0c..d01e739607 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1004,3 +1004,16 @@ DEF_HELPER_5(vfclass_v_d, void, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfmerge_vfm_h, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfmerge_vfm_w, void, ptr, ptr, i64, ptr, env, i32) DEF_HELPER_6(vfmerge_vfm_d, void, ptr, ptr, i64, ptr, env, i32) + +DEF_HELPER_5(vfcvt_xu_f_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfcvt_xu_f_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfcvt_xu_f_v_d, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfcvt_x_f_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfcvt_x_f_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfcvt_x_f_v_d, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfcvt_f_xu_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfcvt_f_xu_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfcvt_f_xu_v_d, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfcvt_f_x_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfcvt_f_x_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfcvt_f_x_v_d, void, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 38e7445a16..913c3b099b 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -517,6 +517,10 @@ vmford_vf 011010 . ..... ..... 101 ..... 1010111 @r_vm vfclass_v 100011 . ..... 10000 001 ..... 1010111 @r2_vm vfmerge_vfm 010111 0 ..... ..... 101 ..... 1010111 @r_vm_0 vfmv_v_f 010111 1 00000 ..... 101 ..... 1010111 @r2 +vfcvt_xu_f_v 100010 . ..... 00000 001 ..... 1010111 @r2_vm +vfcvt_x_f_v 100010 . ..... 00001 001 ..... 1010111 @r2_vm +vfcvt_f_xu_v 100010 . ..... 00010 001 ..... 1010111 @r2_vm +vfcvt_f_x_v 100010 . ..... 00011 001 ..... 1010111 @r2_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index b6872376ce..ed238edfa9 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2222,3 +2222,9 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) } return false; } + +/* Single-Width Floating-Point/Integer Type-Convert Instructions */ +GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check) +GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check) +GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check) +GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 1d5667f471..8da9ca18d3 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4218,3 +4218,36 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ GEN_VFMERGE_VF(vfmerge_vfm_h, int16_t, H2, clearh) GEN_VFMERGE_VF(vfmerge_vfm_w, int32_t, H4, clearl) GEN_VFMERGE_VF(vfmerge_vfm_d, int64_t, H8, clearq) + +/* Single-Width Floating-Point/Integer Type-Convert Instructions */ +/* vfcvt.xu.f.v vd, vs2, vm # Convert float to unsigned integer. */ +RVVCALL(OPFVV1, vfcvt_xu_f_v_h, OP_UU_H, H2, H2, float16_to_uint16) +RVVCALL(OPFVV1, vfcvt_xu_f_v_w, OP_UU_W, H4, H4, float32_to_uint32) +RVVCALL(OPFVV1, vfcvt_xu_f_v_d, OP_UU_D, H8, H8, float64_to_uint64) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_h, 2, 2, clearh) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_w, 4, 4, clearl) +GEN_VEXT_V_ENV(vfcvt_xu_f_v_d, 8, 8, clearq) + +/* vfcvt.x.f.v vd, vs2, vm # Convert float to signed integer. */ +RVVCALL(OPFVV1, vfcvt_x_f_v_h, OP_UU_H, H2, H2, float16_to_int16) +RVVCALL(OPFVV1, vfcvt_x_f_v_w, OP_UU_W, H4, H4, float32_to_int32) +RVVCALL(OPFVV1, vfcvt_x_f_v_d, OP_UU_D, H8, H8, float64_to_int64) +GEN_VEXT_V_ENV(vfcvt_x_f_v_h, 2, 2, clearh) +GEN_VEXT_V_ENV(vfcvt_x_f_v_w, 4, 4, clearl) +GEN_VEXT_V_ENV(vfcvt_x_f_v_d, 8, 8, clearq) + +/* vfcvt.f.xu.v vd, vs2, vm # Convert unsigned integer to float. */ +RVVCALL(OPFVV1, vfcvt_f_xu_v_h, OP_UU_H, H2, H2, uint16_to_float16) +RVVCALL(OPFVV1, vfcvt_f_xu_v_w, OP_UU_W, H4, H4, uint32_to_float32) +RVVCALL(OPFVV1, vfcvt_f_xu_v_d, OP_UU_D, H8, H8, uint64_to_float64) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_h, 2, 2, clearh) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_w, 4, 4, clearl) +GEN_VEXT_V_ENV(vfcvt_f_xu_v_d, 8, 8, clearq) + +/* vfcvt.f.x.v vd, vs2, vm # Convert integer to float. */ +RVVCALL(OPFVV1, vfcvt_f_x_v_h, OP_UU_H, H2, H2, int16_to_float16) +RVVCALL(OPFVV1, vfcvt_f_x_v_w, OP_UU_W, H4, H4, int32_to_float32) +RVVCALL(OPFVV1, vfcvt_f_x_v_d, OP_UU_D, H8, H8, int64_to_float64) +GEN_VEXT_V_ENV(vfcvt_f_x_v_h, 2, 2, clearh) +GEN_VEXT_V_ENV(vfcvt_f_x_v_w, 4, 4, clearl) +GEN_VEXT_V_ENV(vfcvt_f_x_v_d, 8, 8, clearq) From 4514b7b12390525e59e335e7ca58fd44f6e69272 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:31 +0800 Subject: [PATCH 1844/2595] target/riscv: widening floating-point/integer type-convert instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-44-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 11 ++++++ target/riscv/insn32.decode | 5 +++ target/riscv/insn_trans/trans_rvv.inc.c | 48 +++++++++++++++++++++++++ target/riscv/vector_helper.c | 42 ++++++++++++++++++++++ 4 files changed, 106 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index d01e739607..c5f1f298f2 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1017,3 +1017,14 @@ DEF_HELPER_5(vfcvt_f_xu_v_d, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfcvt_f_x_v_h, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfcvt_f_x_v_w, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfcvt_f_x_v_d, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_5(vfwcvt_xu_f_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfwcvt_xu_f_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfwcvt_x_f_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfwcvt_x_f_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfwcvt_f_xu_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfwcvt_f_xu_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfwcvt_f_x_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfwcvt_f_x_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfwcvt_f_f_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfwcvt_f_f_v_w, void, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 913c3b099b..eda09f0c15 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -521,6 +521,11 @@ vfcvt_xu_f_v 100010 . ..... 00000 001 ..... 1010111 @r2_vm vfcvt_x_f_v 100010 . ..... 00001 001 ..... 1010111 @r2_vm vfcvt_f_xu_v 100010 . ..... 00010 001 ..... 1010111 @r2_vm vfcvt_f_x_v 100010 . ..... 00011 001 ..... 1010111 @r2_vm +vfwcvt_xu_f_v 100010 . ..... 01000 001 ..... 1010111 @r2_vm +vfwcvt_x_f_v 100010 . ..... 01001 001 ..... 1010111 @r2_vm +vfwcvt_f_xu_v 100010 . ..... 01010 001 ..... 1010111 @r2_vm +vfwcvt_f_x_v 100010 . ..... 01011 001 ..... 1010111 @r2_vm +vfwcvt_f_f_v 100010 . ..... 01100 001 ..... 1010111 @r2_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index ed238edfa9..0fc8947389 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2228,3 +2228,51 @@ GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check) GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check) GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check) GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check) + +/* Widening Floating-Point/Integer Type-Convert Instructions */ + +/* + * If the current SEW does not correspond to a supported IEEE floating-point + * type, an illegal instruction exception is raised + */ +static bool opfv_widen_check(DisasContext *s, arg_rmr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, true) && + vext_check_reg(s, a->rs2, false) && + vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, + 1 << s->lmul) && + (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); +} + +#define GEN_OPFV_WIDEN_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ +{ \ + if (opfv_widen_check(s, a)) { \ + uint32_t data = 0; \ + static gen_helper_gvec_3_ptr * const fns[2] = { \ + gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, \ + }; \ + TCGLabel *over = gen_new_label(); \ + gen_set_rm(s, 7); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ + vreg_ofs(s, a->rs2), cpu_env, 0, \ + s->vlen / 8, data, fns[s->sew - 1]); \ + gen_set_label(over); \ + return true; \ + } \ + return false; \ +} + +GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v) +GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v) +GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v) +GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v) +GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 8da9ca18d3..742080dc7d 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4251,3 +4251,45 @@ RVVCALL(OPFVV1, vfcvt_f_x_v_d, OP_UU_D, H8, H8, int64_to_float64) GEN_VEXT_V_ENV(vfcvt_f_x_v_h, 2, 2, clearh) GEN_VEXT_V_ENV(vfcvt_f_x_v_w, 4, 4, clearl) GEN_VEXT_V_ENV(vfcvt_f_x_v_d, 8, 8, clearq) + +/* Widening Floating-Point/Integer Type-Convert Instructions */ +/* (TD, T2, TX2) */ +#define WOP_UU_H uint32_t, uint16_t, uint16_t +#define WOP_UU_W uint64_t, uint32_t, uint32_t +/* vfwcvt.xu.f.v vd, vs2, vm # Convert float to double-width unsigned integer.*/ +RVVCALL(OPFVV1, vfwcvt_xu_f_v_h, WOP_UU_H, H4, H2, float16_to_uint32) +RVVCALL(OPFVV1, vfwcvt_xu_f_v_w, WOP_UU_W, H8, H4, float32_to_uint64) +GEN_VEXT_V_ENV(vfwcvt_xu_f_v_h, 2, 4, clearl) +GEN_VEXT_V_ENV(vfwcvt_xu_f_v_w, 4, 8, clearq) + +/* vfwcvt.x.f.v vd, vs2, vm # Convert float to double-width signed integer. */ +RVVCALL(OPFVV1, vfwcvt_x_f_v_h, WOP_UU_H, H4, H2, float16_to_int32) +RVVCALL(OPFVV1, vfwcvt_x_f_v_w, WOP_UU_W, H8, H4, float32_to_int64) +GEN_VEXT_V_ENV(vfwcvt_x_f_v_h, 2, 4, clearl) +GEN_VEXT_V_ENV(vfwcvt_x_f_v_w, 4, 8, clearq) + +/* vfwcvt.f.xu.v vd, vs2, vm # Convert unsigned integer to double-width float */ +RVVCALL(OPFVV1, vfwcvt_f_xu_v_h, WOP_UU_H, H4, H2, uint16_to_float32) +RVVCALL(OPFVV1, vfwcvt_f_xu_v_w, WOP_UU_W, H8, H4, uint32_to_float64) +GEN_VEXT_V_ENV(vfwcvt_f_xu_v_h, 2, 4, clearl) +GEN_VEXT_V_ENV(vfwcvt_f_xu_v_w, 4, 8, clearq) + +/* vfwcvt.f.x.v vd, vs2, vm # Convert integer to double-width float. */ +RVVCALL(OPFVV1, vfwcvt_f_x_v_h, WOP_UU_H, H4, H2, int16_to_float32) +RVVCALL(OPFVV1, vfwcvt_f_x_v_w, WOP_UU_W, H8, H4, int32_to_float64) +GEN_VEXT_V_ENV(vfwcvt_f_x_v_h, 2, 4, clearl) +GEN_VEXT_V_ENV(vfwcvt_f_x_v_w, 4, 8, clearq) + +/* + * vfwcvt.f.f.v vd, vs2, vm # + * Convert single-width float to double-width float. + */ +static uint32_t vfwcvtffv16(uint16_t a, float_status *s) +{ + return float16_to_float32(a, true, s); +} + +RVVCALL(OPFVV1, vfwcvt_f_f_v_h, WOP_UU_H, H4, H2, vfwcvtffv16) +RVVCALL(OPFVV1, vfwcvt_f_f_v_w, WOP_UU_W, H8, H4, float32_to_float64) +GEN_VEXT_V_ENV(vfwcvt_f_f_v_h, 2, 4, clearl) +GEN_VEXT_V_ENV(vfwcvt_f_f_v_w, 4, 8, clearq) From 878d406ec28f945d262af4ffbea50b825d7a0825 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:32 +0800 Subject: [PATCH 1845/2595] target/riscv: narrowing floating-point/integer type-convert instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-45-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 11 ++++++ target/riscv/insn32.decode | 5 +++ target/riscv/insn_trans/trans_rvv.inc.c | 48 +++++++++++++++++++++++++ target/riscv/vector_helper.c | 39 ++++++++++++++++++++ 4 files changed, 103 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index c5f1f298f2..5870c4041e 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1028,3 +1028,14 @@ DEF_HELPER_5(vfwcvt_f_x_v_h, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfwcvt_f_x_v_w, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfwcvt_f_f_v_h, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfwcvt_f_f_v_w, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_5(vfncvt_xu_f_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfncvt_xu_f_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfncvt_x_f_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfncvt_x_f_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfncvt_f_xu_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfncvt_f_xu_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfncvt_f_x_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfncvt_f_x_v_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfncvt_f_f_v_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vfncvt_f_f_v_w, void, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index eda09f0c15..55fbe166d8 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -526,6 +526,11 @@ vfwcvt_x_f_v 100010 . ..... 01001 001 ..... 1010111 @r2_vm vfwcvt_f_xu_v 100010 . ..... 01010 001 ..... 1010111 @r2_vm vfwcvt_f_x_v 100010 . ..... 01011 001 ..... 1010111 @r2_vm vfwcvt_f_f_v 100010 . ..... 01100 001 ..... 1010111 @r2_vm +vfncvt_xu_f_v 100010 . ..... 10000 001 ..... 1010111 @r2_vm +vfncvt_x_f_v 100010 . ..... 10001 001 ..... 1010111 @r2_vm +vfncvt_f_xu_v 100010 . ..... 10010 001 ..... 1010111 @r2_vm +vfncvt_f_x_v 100010 . ..... 10011 001 ..... 1010111 @r2_vm +vfncvt_f_f_v 100010 . ..... 10100 001 ..... 1010111 @r2_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 0fc8947389..6c46d893b0 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2276,3 +2276,51 @@ GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v) GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v) GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v) GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v) + +/* Narrowing Floating-Point/Integer Type-Convert Instructions */ + +/* + * If the current SEW does not correspond to a supported IEEE floating-point + * type, an illegal instruction exception is raised + */ +static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, false) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, true) && + vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, + 2 << s->lmul) && + (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); +} + +#define GEN_OPFV_NARROW_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ +{ \ + if (opfv_narrow_check(s, a)) { \ + uint32_t data = 0; \ + static gen_helper_gvec_3_ptr * const fns[2] = { \ + gen_helper_##NAME##_h, \ + gen_helper_##NAME##_w, \ + }; \ + TCGLabel *over = gen_new_label(); \ + gen_set_rm(s, 7); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ + vreg_ofs(s, a->rs2), cpu_env, 0, \ + s->vlen / 8, data, fns[s->sew - 1]); \ + gen_set_label(over); \ + return true; \ + } \ + return false; \ +} + +GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v) +GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v) +GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v) +GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v) +GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 742080dc7d..05dcf7cd09 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4293,3 +4293,42 @@ RVVCALL(OPFVV1, vfwcvt_f_f_v_h, WOP_UU_H, H4, H2, vfwcvtffv16) RVVCALL(OPFVV1, vfwcvt_f_f_v_w, WOP_UU_W, H8, H4, float32_to_float64) GEN_VEXT_V_ENV(vfwcvt_f_f_v_h, 2, 4, clearl) GEN_VEXT_V_ENV(vfwcvt_f_f_v_w, 4, 8, clearq) + +/* Narrowing Floating-Point/Integer Type-Convert Instructions */ +/* (TD, T2, TX2) */ +#define NOP_UU_H uint16_t, uint32_t, uint32_t +#define NOP_UU_W uint32_t, uint64_t, uint64_t +/* vfncvt.xu.f.v vd, vs2, vm # Convert float to unsigned integer. */ +RVVCALL(OPFVV1, vfncvt_xu_f_v_h, NOP_UU_H, H2, H4, float32_to_uint16) +RVVCALL(OPFVV1, vfncvt_xu_f_v_w, NOP_UU_W, H4, H8, float64_to_uint32) +GEN_VEXT_V_ENV(vfncvt_xu_f_v_h, 2, 2, clearh) +GEN_VEXT_V_ENV(vfncvt_xu_f_v_w, 4, 4, clearl) + +/* vfncvt.x.f.v vd, vs2, vm # Convert double-width float to signed integer. */ +RVVCALL(OPFVV1, vfncvt_x_f_v_h, NOP_UU_H, H2, H4, float32_to_int16) +RVVCALL(OPFVV1, vfncvt_x_f_v_w, NOP_UU_W, H4, H8, float64_to_int32) +GEN_VEXT_V_ENV(vfncvt_x_f_v_h, 2, 2, clearh) +GEN_VEXT_V_ENV(vfncvt_x_f_v_w, 4, 4, clearl) + +/* vfncvt.f.xu.v vd, vs2, vm # Convert double-width unsigned integer to float */ +RVVCALL(OPFVV1, vfncvt_f_xu_v_h, NOP_UU_H, H2, H4, uint32_to_float16) +RVVCALL(OPFVV1, vfncvt_f_xu_v_w, NOP_UU_W, H4, H8, uint64_to_float32) +GEN_VEXT_V_ENV(vfncvt_f_xu_v_h, 2, 2, clearh) +GEN_VEXT_V_ENV(vfncvt_f_xu_v_w, 4, 4, clearl) + +/* vfncvt.f.x.v vd, vs2, vm # Convert double-width integer to float. */ +RVVCALL(OPFVV1, vfncvt_f_x_v_h, NOP_UU_H, H2, H4, int32_to_float16) +RVVCALL(OPFVV1, vfncvt_f_x_v_w, NOP_UU_W, H4, H8, int64_to_float32) +GEN_VEXT_V_ENV(vfncvt_f_x_v_h, 2, 2, clearh) +GEN_VEXT_V_ENV(vfncvt_f_x_v_w, 4, 4, clearl) + +/* vfncvt.f.f.v vd, vs2, vm # Convert double float to single-width float. */ +static uint16_t vfncvtffv16(uint32_t a, float_status *s) +{ + return float32_to_float16(a, true, s); +} + +RVVCALL(OPFVV1, vfncvt_f_f_v_h, NOP_UU_H, H2, H4, vfncvtffv16) +RVVCALL(OPFVV1, vfncvt_f_f_v_w, NOP_UU_W, H4, H8, float64_to_float32) +GEN_VEXT_V_ENV(vfncvt_f_f_v_h, 2, 2, clearh) +GEN_VEXT_V_ENV(vfncvt_f_f_v_w, 4, 4, clearl) From fe5c9ab1fc185e96bf7e034954127429ca74d386 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:33 +0800 Subject: [PATCH 1846/2595] target/riscv: vector single-width integer reduction instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-46-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 33 +++++++++++ target/riscv/insn32.decode | 8 +++ target/riscv/insn_trans/trans_rvv.inc.c | 18 ++++++ target/riscv/vector_helper.c | 74 +++++++++++++++++++++++++ 4 files changed, 133 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 5870c4041e..a7fe4443e4 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1039,3 +1039,36 @@ DEF_HELPER_5(vfncvt_f_x_v_h, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfncvt_f_x_v_w, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfncvt_f_f_v_h, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vfncvt_f_f_v_w, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_6(vredsum_vs_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredsum_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmaxu_vs_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmaxu_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmaxu_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmaxu_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmax_vs_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmax_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmax_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmax_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredminu_vs_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredminu_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredminu_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredminu_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmin_vs_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmin_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmin_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredmin_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredand_vs_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredand_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredand_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredand_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredor_vs_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredor_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredor_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredor_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredxor_vs_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredxor_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredxor_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vredxor_vs_d, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 55fbe166d8..878eeecb7e 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -531,6 +531,14 @@ vfncvt_x_f_v 100010 . ..... 10001 001 ..... 1010111 @r2_vm vfncvt_f_xu_v 100010 . ..... 10010 001 ..... 1010111 @r2_vm vfncvt_f_x_v 100010 . ..... 10011 001 ..... 1010111 @r2_vm vfncvt_f_f_v 100010 . ..... 10100 001 ..... 1010111 @r2_vm +vredsum_vs 000000 . ..... ..... 010 ..... 1010111 @r_vm +vredand_vs 000001 . ..... ..... 010 ..... 1010111 @r_vm +vredor_vs 000010 . ..... ..... 010 ..... 1010111 @r_vm +vredxor_vs 000011 . ..... ..... 010 ..... 1010111 @r_vm +vredminu_vs 000100 . ..... ..... 010 ..... 1010111 @r_vm +vredmin_vs 000101 . ..... ..... 010 ..... 1010111 @r_vm +vredmaxu_vs 000110 . ..... ..... 010 ..... 1010111 @r_vm +vredmax_vs 000111 . ..... ..... 010 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 6c46d893b0..b4e3f904d3 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2324,3 +2324,21 @@ GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v) GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v) GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v) GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v) + +/* + *** Vector Reduction Operations + */ +/* Vector Single-Width Integer Reduction Instructions */ +static bool reduction_check(DisasContext *s, arg_rmrr *a) +{ + return vext_check_isa_ill(s) && vext_check_reg(s, a->rs2, false); +} + +GEN_OPIVV_TRANS(vredsum_vs, reduction_check) +GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) +GEN_OPIVV_TRANS(vredmax_vs, reduction_check) +GEN_OPIVV_TRANS(vredminu_vs, reduction_check) +GEN_OPIVV_TRANS(vredmin_vs, reduction_check) +GEN_OPIVV_TRANS(vredand_vs, reduction_check) +GEN_OPIVV_TRANS(vredor_vs, reduction_check) +GEN_OPIVV_TRANS(vredxor_vs, reduction_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 05dcf7cd09..41564b3237 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4332,3 +4332,77 @@ RVVCALL(OPFVV1, vfncvt_f_f_v_h, NOP_UU_H, H2, H4, vfncvtffv16) RVVCALL(OPFVV1, vfncvt_f_f_v_w, NOP_UU_W, H4, H8, float64_to_float32) GEN_VEXT_V_ENV(vfncvt_f_f_v_h, 2, 2, clearh) GEN_VEXT_V_ENV(vfncvt_f_f_v_w, 4, 4, clearl) + +/* + *** Vector Reduction Operations + */ +/* Vector Single-Width Integer Reduction Instructions */ +#define GEN_VEXT_RED(NAME, TD, TS2, HD, HS2, OP, CLEAR_FN)\ +void HELPER(NAME)(void *vd, void *v0, void *vs1, \ + void *vs2, CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t i; \ + uint32_t tot = env_archcpu(env)->cfg.vlen / 8; \ + TD s1 = *((TD *)vs1 + HD(0)); \ + \ + for (i = 0; i < vl; i++) { \ + TS2 s2 = *((TS2 *)vs2 + HS2(i)); \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + s1 = OP(s1, (TD)s2); \ + } \ + *((TD *)vd + HD(0)) = s1; \ + CLEAR_FN(vd, 1, sizeof(TD), tot); \ +} + +/* vd[0] = sum(vs1[0], vs2[*]) */ +GEN_VEXT_RED(vredsum_vs_b, int8_t, int8_t, H1, H1, DO_ADD, clearb) +GEN_VEXT_RED(vredsum_vs_h, int16_t, int16_t, H2, H2, DO_ADD, clearh) +GEN_VEXT_RED(vredsum_vs_w, int32_t, int32_t, H4, H4, DO_ADD, clearl) +GEN_VEXT_RED(vredsum_vs_d, int64_t, int64_t, H8, H8, DO_ADD, clearq) + +/* vd[0] = maxu(vs1[0], vs2[*]) */ +GEN_VEXT_RED(vredmaxu_vs_b, uint8_t, uint8_t, H1, H1, DO_MAX, clearb) +GEN_VEXT_RED(vredmaxu_vs_h, uint16_t, uint16_t, H2, H2, DO_MAX, clearh) +GEN_VEXT_RED(vredmaxu_vs_w, uint32_t, uint32_t, H4, H4, DO_MAX, clearl) +GEN_VEXT_RED(vredmaxu_vs_d, uint64_t, uint64_t, H8, H8, DO_MAX, clearq) + +/* vd[0] = max(vs1[0], vs2[*]) */ +GEN_VEXT_RED(vredmax_vs_b, int8_t, int8_t, H1, H1, DO_MAX, clearb) +GEN_VEXT_RED(vredmax_vs_h, int16_t, int16_t, H2, H2, DO_MAX, clearh) +GEN_VEXT_RED(vredmax_vs_w, int32_t, int32_t, H4, H4, DO_MAX, clearl) +GEN_VEXT_RED(vredmax_vs_d, int64_t, int64_t, H8, H8, DO_MAX, clearq) + +/* vd[0] = minu(vs1[0], vs2[*]) */ +GEN_VEXT_RED(vredminu_vs_b, uint8_t, uint8_t, H1, H1, DO_MIN, clearb) +GEN_VEXT_RED(vredminu_vs_h, uint16_t, uint16_t, H2, H2, DO_MIN, clearh) +GEN_VEXT_RED(vredminu_vs_w, uint32_t, uint32_t, H4, H4, DO_MIN, clearl) +GEN_VEXT_RED(vredminu_vs_d, uint64_t, uint64_t, H8, H8, DO_MIN, clearq) + +/* vd[0] = min(vs1[0], vs2[*]) */ +GEN_VEXT_RED(vredmin_vs_b, int8_t, int8_t, H1, H1, DO_MIN, clearb) +GEN_VEXT_RED(vredmin_vs_h, int16_t, int16_t, H2, H2, DO_MIN, clearh) +GEN_VEXT_RED(vredmin_vs_w, int32_t, int32_t, H4, H4, DO_MIN, clearl) +GEN_VEXT_RED(vredmin_vs_d, int64_t, int64_t, H8, H8, DO_MIN, clearq) + +/* vd[0] = and(vs1[0], vs2[*]) */ +GEN_VEXT_RED(vredand_vs_b, int8_t, int8_t, H1, H1, DO_AND, clearb) +GEN_VEXT_RED(vredand_vs_h, int16_t, int16_t, H2, H2, DO_AND, clearh) +GEN_VEXT_RED(vredand_vs_w, int32_t, int32_t, H4, H4, DO_AND, clearl) +GEN_VEXT_RED(vredand_vs_d, int64_t, int64_t, H8, H8, DO_AND, clearq) + +/* vd[0] = or(vs1[0], vs2[*]) */ +GEN_VEXT_RED(vredor_vs_b, int8_t, int8_t, H1, H1, DO_OR, clearb) +GEN_VEXT_RED(vredor_vs_h, int16_t, int16_t, H2, H2, DO_OR, clearh) +GEN_VEXT_RED(vredor_vs_w, int32_t, int32_t, H4, H4, DO_OR, clearl) +GEN_VEXT_RED(vredor_vs_d, int64_t, int64_t, H8, H8, DO_OR, clearq) + +/* vd[0] = xor(vs1[0], vs2[*]) */ +GEN_VEXT_RED(vredxor_vs_b, int8_t, int8_t, H1, H1, DO_XOR, clearb) +GEN_VEXT_RED(vredxor_vs_h, int16_t, int16_t, H2, H2, DO_XOR, clearh) +GEN_VEXT_RED(vredxor_vs_w, int32_t, int32_t, H4, H4, DO_XOR, clearl) +GEN_VEXT_RED(vredxor_vs_d, int64_t, int64_t, H8, H8, DO_XOR, clearq) From bba718200b2d2aac6ab5031817f7125571c983a1 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:34 +0800 Subject: [PATCH 1847/2595] target/riscv: vector wideing integer reduction instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-47-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 7 +++++++ target/riscv/insn32.decode | 2 ++ target/riscv/insn_trans/trans_rvv.inc.c | 4 ++++ target/riscv/vector_helper.c | 11 +++++++++++ 4 files changed, 24 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index a7fe4443e4..1c1277c0d1 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1072,3 +1072,10 @@ DEF_HELPER_6(vredxor_vs_b, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vredxor_vs_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vredxor_vs_w, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vredxor_vs_d, void, ptr, ptr, ptr, ptr, env, i32) + +DEF_HELPER_6(vwredsumu_vs_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwredsumu_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwredsumu_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwredsum_vs_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vwredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 878eeecb7e..b78fd8bc04 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -539,6 +539,8 @@ vredminu_vs 000100 . ..... ..... 010 ..... 1010111 @r_vm vredmin_vs 000101 . ..... ..... 010 ..... 1010111 @r_vm vredmaxu_vs 000110 . ..... ..... 010 ..... 1010111 @r_vm vredmax_vs 000111 . ..... ..... 010 ..... 1010111 @r_vm +vwredsumu_vs 110000 . ..... ..... 000 ..... 1010111 @r_vm +vwredsum_vs 110001 . ..... ..... 000 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index b4e3f904d3..91fc1fd059 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2342,3 +2342,7 @@ GEN_OPIVV_TRANS(vredmin_vs, reduction_check) GEN_OPIVV_TRANS(vredand_vs, reduction_check) GEN_OPIVV_TRANS(vredor_vs, reduction_check) GEN_OPIVV_TRANS(vredxor_vs, reduction_check) + +/* Vector Widening Integer Reduction Instructions */ +GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_check) +GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 41564b3237..72b812c743 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4406,3 +4406,14 @@ GEN_VEXT_RED(vredxor_vs_b, int8_t, int8_t, H1, H1, DO_XOR, clearb) GEN_VEXT_RED(vredxor_vs_h, int16_t, int16_t, H2, H2, DO_XOR, clearh) GEN_VEXT_RED(vredxor_vs_w, int32_t, int32_t, H4, H4, DO_XOR, clearl) GEN_VEXT_RED(vredxor_vs_d, int64_t, int64_t, H8, H8, DO_XOR, clearq) + +/* Vector Widening Integer Reduction Instructions */ +/* signed sum reduction into double-width accumulator */ +GEN_VEXT_RED(vwredsum_vs_b, int16_t, int8_t, H2, H1, DO_ADD, clearh) +GEN_VEXT_RED(vwredsum_vs_h, int32_t, int16_t, H4, H2, DO_ADD, clearl) +GEN_VEXT_RED(vwredsum_vs_w, int64_t, int32_t, H8, H4, DO_ADD, clearq) + +/* Unsigned sum reduction into double-width accumulator */ +GEN_VEXT_RED(vwredsumu_vs_b, uint16_t, uint8_t, H2, H1, DO_ADD, clearh) +GEN_VEXT_RED(vwredsumu_vs_h, uint32_t, uint16_t, H4, H2, DO_ADD, clearl) +GEN_VEXT_RED(vwredsumu_vs_w, uint64_t, uint32_t, H8, H4, DO_ADD, clearq) From 523547f19e3914f11543e2da03907c724f15cd5e Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:35 +0800 Subject: [PATCH 1848/2595] target/riscv: vector single-width floating-point reduction instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-48-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 10 +++++++ target/riscv/insn32.decode | 4 +++ target/riscv/insn_trans/trans_rvv.inc.c | 5 ++++ target/riscv/vector_helper.c | 39 +++++++++++++++++++++++++ 4 files changed, 58 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 1c1277c0d1..8e8b8d0407 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1079,3 +1079,13 @@ DEF_HELPER_6(vwredsumu_vs_w, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vwredsum_vs_b, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vwredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vwredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) + +DEF_HELPER_6(vfredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredsum_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredmax_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredmax_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredmax_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredmin_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredmin_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredmin_vs_d, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index b78fd8bc04..986308e99a 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -541,6 +541,10 @@ vredmaxu_vs 000110 . ..... ..... 010 ..... 1010111 @r_vm vredmax_vs 000111 . ..... ..... 010 ..... 1010111 @r_vm vwredsumu_vs 110000 . ..... ..... 000 ..... 1010111 @r_vm vwredsum_vs 110001 . ..... ..... 000 ..... 1010111 @r_vm +# Vector ordered and unordered reduction sum +vfredsum_vs 0000-1 . ..... ..... 001 ..... 1010111 @r_vm +vfredmin_vs 000101 . ..... ..... 001 ..... 1010111 @r_vm +vfredmax_vs 000111 . ..... ..... 001 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 91fc1fd059..3dd4171898 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2346,3 +2346,8 @@ GEN_OPIVV_TRANS(vredxor_vs, reduction_check) /* Vector Widening Integer Reduction Instructions */ GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_check) GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_check) + +/* Vector Single-Width Floating-Point Reduction Instructions */ +GEN_OPFVV_TRANS(vfredsum_vs, reduction_check) +GEN_OPFVV_TRANS(vfredmax_vs, reduction_check) +GEN_OPFVV_TRANS(vfredmin_vs, reduction_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 72b812c743..73214534cb 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4417,3 +4417,42 @@ GEN_VEXT_RED(vwredsum_vs_w, int64_t, int32_t, H8, H4, DO_ADD, clearq) GEN_VEXT_RED(vwredsumu_vs_b, uint16_t, uint8_t, H2, H1, DO_ADD, clearh) GEN_VEXT_RED(vwredsumu_vs_h, uint32_t, uint16_t, H4, H2, DO_ADD, clearl) GEN_VEXT_RED(vwredsumu_vs_w, uint64_t, uint32_t, H8, H4, DO_ADD, clearq) + +/* Vector Single-Width Floating-Point Reduction Instructions */ +#define GEN_VEXT_FRED(NAME, TD, TS2, HD, HS2, OP, CLEAR_FN)\ +void HELPER(NAME)(void *vd, void *v0, void *vs1, \ + void *vs2, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t i; \ + uint32_t tot = env_archcpu(env)->cfg.vlen / 8; \ + TD s1 = *((TD *)vs1 + HD(0)); \ + \ + for (i = 0; i < vl; i++) { \ + TS2 s2 = *((TS2 *)vs2 + HS2(i)); \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + s1 = OP(s1, (TD)s2, &env->fp_status); \ + } \ + *((TD *)vd + HD(0)) = s1; \ + CLEAR_FN(vd, 1, sizeof(TD), tot); \ +} + +/* Unordered sum */ +GEN_VEXT_FRED(vfredsum_vs_h, uint16_t, uint16_t, H2, H2, float16_add, clearh) +GEN_VEXT_FRED(vfredsum_vs_w, uint32_t, uint32_t, H4, H4, float32_add, clearl) +GEN_VEXT_FRED(vfredsum_vs_d, uint64_t, uint64_t, H8, H8, float64_add, clearq) + +/* Maximum value */ +GEN_VEXT_FRED(vfredmax_vs_h, uint16_t, uint16_t, H2, H2, float16_maxnum, clearh) +GEN_VEXT_FRED(vfredmax_vs_w, uint32_t, uint32_t, H4, H4, float32_maxnum, clearl) +GEN_VEXT_FRED(vfredmax_vs_d, uint64_t, uint64_t, H8, H8, float64_maxnum, clearq) + +/* Minimum value */ +GEN_VEXT_FRED(vfredmin_vs_h, uint16_t, uint16_t, H2, H2, float16_minnum, clearh) +GEN_VEXT_FRED(vfredmin_vs_w, uint32_t, uint32_t, H4, H4, float32_minnum, clearl) +GEN_VEXT_FRED(vfredmin_vs_d, uint64_t, uint64_t, H8, H8, float64_minnum, clearq) From 696b0c260a0312c865cd0e4a8f09d0b9f13b07c9 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:36 +0800 Subject: [PATCH 1849/2595] target/riscv: vector widening floating-point reduction instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20200701152549.1218-49-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 3 ++ target/riscv/insn32.decode | 2 ++ target/riscv/insn_trans/trans_rvv.inc.c | 3 ++ target/riscv/vector_helper.c | 46 +++++++++++++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 8e8b8d0407..217f09a55c 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1089,3 +1089,6 @@ DEF_HELPER_6(vfredmax_vs_d, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmin_vs_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmin_vs_w, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmin_vs_d, void, ptr, ptr, ptr, ptr, env, i32) + +DEF_HELPER_6(vfwredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 986308e99a..2668d483a7 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -545,6 +545,8 @@ vwredsum_vs 110001 . ..... ..... 000 ..... 1010111 @r_vm vfredsum_vs 0000-1 . ..... ..... 001 ..... 1010111 @r_vm vfredmin_vs 000101 . ..... ..... 001 ..... 1010111 @r_vm vfredmax_vs 000111 . ..... ..... 001 ..... 1010111 @r_vm +# Vector widening ordered and unordered float reduction sum +vfwredsum_vs 1100-1 . ..... ..... 001 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 3dd4171898..b78829be36 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2351,3 +2351,6 @@ GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_check) GEN_OPFVV_TRANS(vfredsum_vs, reduction_check) GEN_OPFVV_TRANS(vfredmax_vs, reduction_check) GEN_OPFVV_TRANS(vfredmin_vs, reduction_check) + +/* Vector Widening Floating-Point Reduction Instructions */ +GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 73214534cb..3ebf2482b8 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4456,3 +4456,49 @@ GEN_VEXT_FRED(vfredmax_vs_d, uint64_t, uint64_t, H8, H8, float64_maxnum, clearq) GEN_VEXT_FRED(vfredmin_vs_h, uint16_t, uint16_t, H2, H2, float16_minnum, clearh) GEN_VEXT_FRED(vfredmin_vs_w, uint32_t, uint32_t, H4, H4, float32_minnum, clearl) GEN_VEXT_FRED(vfredmin_vs_d, uint64_t, uint64_t, H8, H8, float64_minnum, clearq) + +/* Vector Widening Floating-Point Reduction Instructions */ +/* Unordered reduce 2*SEW = 2*SEW + sum(promote(SEW)) */ +void HELPER(vfwredsum_vs_h)(void *vd, void *v0, void *vs1, + void *vs2, CPURISCVState *env, uint32_t desc) +{ + uint32_t mlen = vext_mlen(desc); + uint32_t vm = vext_vm(desc); + uint32_t vl = env->vl; + uint32_t i; + uint32_t tot = env_archcpu(env)->cfg.vlen / 8; + uint32_t s1 = *((uint32_t *)vs1 + H4(0)); + + for (i = 0; i < vl; i++) { + uint16_t s2 = *((uint16_t *)vs2 + H2(i)); + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + s1 = float32_add(s1, float16_to_float32(s2, true, &env->fp_status), + &env->fp_status); + } + *((uint32_t *)vd + H4(0)) = s1; + clearl(vd, 1, sizeof(uint32_t), tot); +} + +void HELPER(vfwredsum_vs_w)(void *vd, void *v0, void *vs1, + void *vs2, CPURISCVState *env, uint32_t desc) +{ + uint32_t mlen = vext_mlen(desc); + uint32_t vm = vext_vm(desc); + uint32_t vl = env->vl; + uint32_t i; + uint32_t tot = env_archcpu(env)->cfg.vlen / 8; + uint64_t s1 = *((uint64_t *)vs1); + + for (i = 0; i < vl; i++) { + uint32_t s2 = *((uint32_t *)vs2 + H4(i)); + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + s1 = float64_add(s1, float32_to_float64(s2, &env->fp_status), + &env->fp_status); + } + *((uint64_t *)vd) = s1; + clearq(vd, 1, sizeof(uint64_t), tot); +} From c21f34aebfb15c112131e36f425986170a3fcae9 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:37 +0800 Subject: [PATCH 1850/2595] target/riscv: vector mask-register logical instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-50-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 9 ++++++ target/riscv/insn32.decode | 8 +++++ target/riscv/insn_trans/trans_rvv.inc.c | 35 ++++++++++++++++++++++ target/riscv/vector_helper.c | 40 +++++++++++++++++++++++++ 4 files changed, 92 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 217f09a55c..292279f0c5 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1092,3 +1092,12 @@ DEF_HELPER_6(vfredmin_vs_d, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfwredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfwredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) + +DEF_HELPER_6(vmand_mm, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmnand_mm, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmandnot_mm, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmxor_mm, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmor_mm, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmnor_mm, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmornot_mm, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vmxnor_mm, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 2668d483a7..c71cbef182 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -547,6 +547,14 @@ vfredmin_vs 000101 . ..... ..... 001 ..... 1010111 @r_vm vfredmax_vs 000111 . ..... ..... 001 ..... 1010111 @r_vm # Vector widening ordered and unordered float reduction sum vfwredsum_vs 1100-1 . ..... ..... 001 ..... 1010111 @r_vm +vmand_mm 011001 - ..... ..... 010 ..... 1010111 @r +vmnand_mm 011101 - ..... ..... 010 ..... 1010111 @r +vmandnot_mm 011000 - ..... ..... 010 ..... 1010111 @r +vmxor_mm 011011 - ..... ..... 010 ..... 1010111 @r +vmor_mm 011010 - ..... ..... 010 ..... 1010111 @r +vmnor_mm 011110 - ..... ..... 010 ..... 1010111 @r +vmornot_mm 011100 - ..... ..... 010 ..... 1010111 @r +vmxnor_mm 011111 - ..... ..... 010 ..... 1010111 @r vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index b78829be36..e2954aa99a 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2354,3 +2354,38 @@ GEN_OPFVV_TRANS(vfredmin_vs, reduction_check) /* Vector Widening Floating-Point Reduction Instructions */ GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check) + +/* + *** Vector Mask Operations + */ + +/* Vector Mask-Register Logical Instructions */ +#define GEN_MM_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_r *a) \ +{ \ + if (vext_check_isa_ill(s)) { \ + uint32_t data = 0; \ + gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ + TCGLabel *over = gen_new_label(); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ + vreg_ofs(s, a->rs1), \ + vreg_ofs(s, a->rs2), cpu_env, 0, \ + s->vlen / 8, data, fn); \ + gen_set_label(over); \ + return true; \ + } \ + return false; \ +} + +GEN_MM_TRANS(vmand_mm) +GEN_MM_TRANS(vmnand_mm) +GEN_MM_TRANS(vmandnot_mm) +GEN_MM_TRANS(vmxor_mm) +GEN_MM_TRANS(vmor_mm) +GEN_MM_TRANS(vmnor_mm) +GEN_MM_TRANS(vmornot_mm) +GEN_MM_TRANS(vmxnor_mm) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 3ebf2482b8..ca44e733e8 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4502,3 +4502,43 @@ void HELPER(vfwredsum_vs_w)(void *vd, void *v0, void *vs1, *((uint64_t *)vd) = s1; clearq(vd, 1, sizeof(uint64_t), tot); } + +/* + *** Vector Mask Operations + */ +/* Vector Mask-Register Logical Instructions */ +#define GEN_VEXT_MASK_VV(NAME, OP) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, \ + void *vs2, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ + uint32_t vl = env->vl; \ + uint32_t i; \ + int a, b; \ + \ + for (i = 0; i < vl; i++) { \ + a = vext_elem_mask(vs1, mlen, i); \ + b = vext_elem_mask(vs2, mlen, i); \ + vext_set_elem_mask(vd, mlen, i, OP(b, a)); \ + } \ + for (; i < vlmax; i++) { \ + vext_set_elem_mask(vd, mlen, i, 0); \ + } \ +} + +#define DO_NAND(N, M) (!(N & M)) +#define DO_ANDNOT(N, M) (N & !M) +#define DO_NOR(N, M) (!(N | M)) +#define DO_ORNOT(N, M) (N | !M) +#define DO_XNOR(N, M) (!(N ^ M)) + +GEN_VEXT_MASK_VV(vmand_mm, DO_AND) +GEN_VEXT_MASK_VV(vmnand_mm, DO_NAND) +GEN_VEXT_MASK_VV(vmandnot_mm, DO_ANDNOT) +GEN_VEXT_MASK_VV(vmxor_mm, DO_XOR) +GEN_VEXT_MASK_VV(vmor_mm, DO_OR) +GEN_VEXT_MASK_VV(vmnor_mm, DO_NOR) +GEN_VEXT_MASK_VV(vmornot_mm, DO_ORNOT) +GEN_VEXT_MASK_VV(vmxnor_mm, DO_XNOR) From 2e88f551df8fe6af81c0f920b7341ae2c75d00f2 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:38 +0800 Subject: [PATCH 1851/2595] target/riscv: vector mask population count vmpopc Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-51-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 2 ++ target/riscv/insn32.decode | 1 + target/riscv/insn_trans/trans_rvv.inc.c | 32 +++++++++++++++++++++++++ target/riscv/vector_helper.c | 20 ++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 292279f0c5..abae503b9c 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1101,3 +1101,5 @@ DEF_HELPER_6(vmor_mm, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vmnor_mm, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vmornot_mm, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vmxnor_mm, void, ptr, ptr, ptr, ptr, env, i32) + +DEF_HELPER_4(vmpopc_m, tl, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index c71cbef182..971c06c09e 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -555,6 +555,7 @@ vmor_mm 011010 - ..... ..... 010 ..... 1010111 @r vmnor_mm 011110 - ..... ..... 010 ..... 1010111 @r vmornot_mm 011100 - ..... ..... 010 ..... 1010111 @r vmxnor_mm 011111 - ..... ..... 010 ..... 1010111 @r +vmpopc_m 010100 . ..... ----- 010 ..... 1010111 @r2_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index e2954aa99a..f2d229b151 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2389,3 +2389,35 @@ GEN_MM_TRANS(vmor_mm) GEN_MM_TRANS(vmnor_mm) GEN_MM_TRANS(vmornot_mm) GEN_MM_TRANS(vmxnor_mm) + +/* Vector mask population count vmpopc */ +static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a) +{ + if (vext_check_isa_ill(s)) { + TCGv_ptr src2, mask; + TCGv dst; + TCGv_i32 desc; + uint32_t data = 0; + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + + mask = tcg_temp_new_ptr(); + src2 = tcg_temp_new_ptr(); + dst = tcg_temp_new(); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + + tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); + tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + + gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc); + gen_set_gpr(a->rd, dst); + + tcg_temp_free_ptr(mask); + tcg_temp_free_ptr(src2); + tcg_temp_free(dst); + tcg_temp_free_i32(desc); + return true; + } + return false; +} diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index ca44e733e8..63933060fc 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4542,3 +4542,23 @@ GEN_VEXT_MASK_VV(vmor_mm, DO_OR) GEN_VEXT_MASK_VV(vmnor_mm, DO_NOR) GEN_VEXT_MASK_VV(vmornot_mm, DO_ORNOT) GEN_VEXT_MASK_VV(vmxnor_mm, DO_XNOR) + +/* Vector mask population count vmpopc */ +target_ulong HELPER(vmpopc_m)(void *v0, void *vs2, CPURISCVState *env, + uint32_t desc) +{ + target_ulong cnt = 0; + uint32_t mlen = vext_mlen(desc); + uint32_t vm = vext_vm(desc); + uint32_t vl = env->vl; + int i; + + for (i = 0; i < vl; i++) { + if (vm || vext_elem_mask(v0, mlen, i)) { + if (vext_elem_mask(vs2, mlen, i)) { + cnt++; + } + } + } + return cnt; +} From 0db67e1c0c49011eb09c4f5b790eef15a2b4c351 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:39 +0800 Subject: [PATCH 1852/2595] target/riscv: vmfirst find-first-set mask bit Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-52-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 2 ++ target/riscv/insn32.decode | 1 + target/riscv/insn_trans/trans_rvv.inc.c | 32 +++++++++++++++++++++++++ target/riscv/vector_helper.c | 19 +++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index abae503b9c..28aeb74f43 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1103,3 +1103,5 @@ DEF_HELPER_6(vmornot_mm, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vmxnor_mm, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_4(vmpopc_m, tl, ptr, ptr, env, i32) + +DEF_HELPER_4(vmfirst_m, tl, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 971c06c09e..a0f3315dbc 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -556,6 +556,7 @@ vmnor_mm 011110 - ..... ..... 010 ..... 1010111 @r vmornot_mm 011100 - ..... ..... 010 ..... 1010111 @r vmxnor_mm 011111 - ..... ..... 010 ..... 1010111 @r vmpopc_m 010100 . ..... ----- 010 ..... 1010111 @r2_vm +vmfirst_m 010101 . ..... ----- 010 ..... 1010111 @r2_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index f2d229b151..01c32a3278 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2421,3 +2421,35 @@ static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a) } return false; } + +/* vmfirst find-first-set mask bit */ +static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a) +{ + if (vext_check_isa_ill(s)) { + TCGv_ptr src2, mask; + TCGv dst; + TCGv_i32 desc; + uint32_t data = 0; + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + + mask = tcg_temp_new_ptr(); + src2 = tcg_temp_new_ptr(); + dst = tcg_temp_new(); + desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); + + tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); + tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); + + gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc); + gen_set_gpr(a->rd, dst); + + tcg_temp_free_ptr(mask); + tcg_temp_free_ptr(src2); + tcg_temp_free(dst); + tcg_temp_free_i32(desc); + return true; + } + return false; +} diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 63933060fc..e0ec02cda3 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4562,3 +4562,22 @@ target_ulong HELPER(vmpopc_m)(void *v0, void *vs2, CPURISCVState *env, } return cnt; } + +/* vmfirst find-first-set mask bit*/ +target_ulong HELPER(vmfirst_m)(void *v0, void *vs2, CPURISCVState *env, + uint32_t desc) +{ + uint32_t mlen = vext_mlen(desc); + uint32_t vm = vext_vm(desc); + uint32_t vl = env->vl; + int i; + + for (i = 0; i < vl; i++) { + if (vm || vext_elem_mask(v0, mlen, i)) { + if (vext_elem_mask(vs2, mlen, i)) { + return i; + } + } + } + return -1LL; +} From 81fbf7daf2eccadd6480b90db95a2e8c410d4414 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:40 +0800 Subject: [PATCH 1853/2595] target/riscv: set-X-first mask bit Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-53-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 4 ++ target/riscv/insn32.decode | 3 ++ target/riscv/insn_trans/trans_rvv.inc.c | 28 +++++++++++ target/riscv/vector_helper.c | 63 +++++++++++++++++++++++++ 4 files changed, 98 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 28aeb74f43..0f9012be7e 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1105,3 +1105,7 @@ DEF_HELPER_6(vmxnor_mm, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_4(vmpopc_m, tl, ptr, ptr, env, i32) DEF_HELPER_4(vmfirst_m, tl, ptr, ptr, env, i32) + +DEF_HELPER_5(vmsbf_m, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vmsif_m, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(vmsof_m, void, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index a0f3315dbc..fab4a0b7e2 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -557,6 +557,9 @@ vmornot_mm 011100 - ..... ..... 010 ..... 1010111 @r vmxnor_mm 011111 - ..... ..... 010 ..... 1010111 @r vmpopc_m 010100 . ..... ----- 010 ..... 1010111 @r2_vm vmfirst_m 010101 . ..... ----- 010 ..... 1010111 @r2_vm +vmsbf_m 010110 . ..... 00001 010 ..... 1010111 @r2_vm +vmsif_m 010110 . ..... 00011 010 ..... 1010111 @r2_vm +vmsof_m 010110 . ..... 00010 010 ..... 1010111 @r2_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 01c32a3278..33ffe5dc1a 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2453,3 +2453,31 @@ static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a) } return false; } + +/* vmsbf.m set-before-first mask bit */ +/* vmsif.m set-includ-first mask bit */ +/* vmsof.m set-only-first mask bit */ +#define GEN_M_TRANS(NAME) \ +static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ +{ \ + if (vext_check_isa_ill(s)) { \ + uint32_t data = 0; \ + gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ + TCGLabel *over = gen_new_label(); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ + \ + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ + data = FIELD_DP32(data, VDATA, VM, a->vm); \ + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ + tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ + vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ + cpu_env, 0, s->vlen / 8, data, fn); \ + gen_set_label(over); \ + return true; \ + } \ + return false; \ +} + +GEN_M_TRANS(vmsbf_m) +GEN_M_TRANS(vmsif_m) +GEN_M_TRANS(vmsof_m) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index e0ec02cda3..a58809a3cd 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4581,3 +4581,66 @@ target_ulong HELPER(vmfirst_m)(void *v0, void *vs2, CPURISCVState *env, } return -1LL; } + +enum set_mask_type { + ONLY_FIRST = 1, + INCLUDE_FIRST, + BEFORE_FIRST, +}; + +static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env, + uint32_t desc, enum set_mask_type type) +{ + uint32_t mlen = vext_mlen(desc); + uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; + uint32_t vm = vext_vm(desc); + uint32_t vl = env->vl; + int i; + bool first_mask_bit = false; + + for (i = 0; i < vl; i++) { + if (!vm && !vext_elem_mask(v0, mlen, i)) { + continue; + } + /* write a zero to all following active elements */ + if (first_mask_bit) { + vext_set_elem_mask(vd, mlen, i, 0); + continue; + } + if (vext_elem_mask(vs2, mlen, i)) { + first_mask_bit = true; + if (type == BEFORE_FIRST) { + vext_set_elem_mask(vd, mlen, i, 0); + } else { + vext_set_elem_mask(vd, mlen, i, 1); + } + } else { + if (type == ONLY_FIRST) { + vext_set_elem_mask(vd, mlen, i, 0); + } else { + vext_set_elem_mask(vd, mlen, i, 1); + } + } + } + for (; i < vlmax; i++) { + vext_set_elem_mask(vd, mlen, i, 0); + } +} + +void HELPER(vmsbf_m)(void *vd, void *v0, void *vs2, CPURISCVState *env, + uint32_t desc) +{ + vmsetm(vd, v0, vs2, env, desc, BEFORE_FIRST); +} + +void HELPER(vmsif_m)(void *vd, void *v0, void *vs2, CPURISCVState *env, + uint32_t desc) +{ + vmsetm(vd, v0, vs2, env, desc, INCLUDE_FIRST); +} + +void HELPER(vmsof_m)(void *vd, void *v0, void *vs2, CPURISCVState *env, + uint32_t desc) +{ + vmsetm(vd, v0, vs2, env, desc, ONLY_FIRST); +} From 78d90cfe859c8f5bd7baa0d41a4b5126e08eac24 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:41 +0800 Subject: [PATCH 1854/2595] target/riscv: vector iota instruction Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-54-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 5 +++++ target/riscv/insn32.decode | 1 + target/riscv/insn_trans/trans_rvv.inc.c | 27 +++++++++++++++++++++++ target/riscv/vector_helper.c | 29 +++++++++++++++++++++++++ 4 files changed, 62 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 0f9012be7e..91db396979 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1109,3 +1109,8 @@ DEF_HELPER_4(vmfirst_m, tl, ptr, ptr, env, i32) DEF_HELPER_5(vmsbf_m, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vmsif_m, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(vmsof_m, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_5(viota_m_b, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(viota_m_h, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(viota_m_w, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_5(viota_m_d, void, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index fab4a0b7e2..415523573d 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -560,6 +560,7 @@ vmfirst_m 010101 . ..... ----- 010 ..... 1010111 @r2_vm vmsbf_m 010110 . ..... 00001 010 ..... 1010111 @r2_vm vmsif_m 010110 . ..... 00011 010 ..... 1010111 @r2_vm vmsof_m 010110 . ..... 00010 010 ..... 1010111 @r2_vm +viota_m 010110 . ..... 10000 010 ..... 1010111 @r2_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 33ffe5dc1a..4dc893fa70 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2481,3 +2481,30 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ GEN_M_TRANS(vmsbf_m) GEN_M_TRANS(vmsif_m) GEN_M_TRANS(vmsof_m) + +/* Vector Iota Instruction */ +static bool trans_viota_m(DisasContext *s, arg_viota_m *a) +{ + if (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false) && + vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1) && + (a->vm != 0 || a->rd != 0)) { + uint32_t data = 0; + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + static gen_helper_gvec_3_ptr * const fns[4] = { + gen_helper_viota_m_b, gen_helper_viota_m_h, + gen_helper_viota_m_w, gen_helper_viota_m_d, + }; + tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), + vreg_ofs(s, a->rs2), cpu_env, 0, + s->vlen / 8, data, fns[s->sew]); + gen_set_label(over); + return true; + } + return false; +} diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index a58809a3cd..e0e6299e64 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4644,3 +4644,32 @@ void HELPER(vmsof_m)(void *vd, void *v0, void *vs2, CPURISCVState *env, { vmsetm(vd, v0, vs2, env, desc, ONLY_FIRST); } + +/* Vector Iota Instruction */ +#define GEN_VEXT_VIOTA_M(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, void *vs2, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t sum = 0; \ + int i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + *((ETYPE *)vd + H(i)) = sum; \ + if (vext_elem_mask(vs2, mlen, i)) { \ + sum++; \ + } \ + } \ + CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \ +} + +GEN_VEXT_VIOTA_M(viota_m_b, uint8_t, H1, clearb) +GEN_VEXT_VIOTA_M(viota_m_h, uint16_t, H2, clearh) +GEN_VEXT_VIOTA_M(viota_m_w, uint32_t, H4, clearl) +GEN_VEXT_VIOTA_M(viota_m_d, uint64_t, H8, clearq) From 126bec3f6ff3379e1a49f4a7d36922bfd079a3cc Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:42 +0800 Subject: [PATCH 1855/2595] target/riscv: vector element index instruction Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-55-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 5 +++++ target/riscv/insn32.decode | 2 ++ target/riscv/insn_trans/trans_rvv.inc.c | 25 +++++++++++++++++++++++++ target/riscv/vector_helper.c | 24 ++++++++++++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 91db396979..c6695ea7a8 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1114,3 +1114,8 @@ DEF_HELPER_5(viota_m_b, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(viota_m_h, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(viota_m_w, void, ptr, ptr, ptr, env, i32) DEF_HELPER_5(viota_m_d, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_4(vid_v_b, void, ptr, ptr, env, i32) +DEF_HELPER_4(vid_v_h, void, ptr, ptr, env, i32) +DEF_HELPER_4(vid_v_w, void, ptr, ptr, env, i32) +DEF_HELPER_4(vid_v_d, void, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 415523573d..6f2e2df7d3 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -70,6 +70,7 @@ @r2 ....... ..... ..... ... ..... ....... %rs1 %rd @r2_nfvm ... ... vm:1 ..... ..... ... ..... ....... &r2nfvm %nf %rs1 %rd @r2_vm ...... vm:1 ..... ..... ... ..... ....... &rmr %rs2 %rd +@r1_vm ...... vm:1 ..... ..... ... ..... ....... %rd @r_nfvm ... ... vm:1 ..... ..... ... ..... ....... &rnfvm %nf %rs2 %rs1 %rd @r_vm ...... vm:1 ..... ..... ... ..... ....... &rmrr %rs2 %rs1 %rd @r_vm_1 ...... . ..... ..... ... ..... ....... &rmrr vm=1 %rs2 %rs1 %rd @@ -561,6 +562,7 @@ vmsbf_m 010110 . ..... 00001 010 ..... 1010111 @r2_vm vmsif_m 010110 . ..... 00011 010 ..... 1010111 @r2_vm vmsof_m 010110 . ..... 00010 010 ..... 1010111 @r2_vm viota_m 010110 . ..... 10000 010 ..... 1010111 @r2_vm +vid_v 010110 . 00000 10001 010 ..... 1010111 @r1_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 4dc893fa70..e94d149d3b 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2508,3 +2508,28 @@ static bool trans_viota_m(DisasContext *s, arg_viota_m *a) } return false; } + +/* Vector Element Index Instruction */ +static bool trans_vid_v(DisasContext *s, arg_vid_v *a) +{ + if (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false) && + vext_check_overlap_mask(s, a->rd, a->vm, false)) { + uint32_t data = 0; + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, VM, a->vm); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + static gen_helper_gvec_2_ptr * const fns[4] = { + gen_helper_vid_v_b, gen_helper_vid_v_h, + gen_helper_vid_v_w, gen_helper_vid_v_d, + }; + tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), + cpu_env, 0, s->vlen / 8, data, fns[s->sew]); + gen_set_label(over); + return true; + } + return false; +} diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index e0e6299e64..0fa899b6ff 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4673,3 +4673,27 @@ GEN_VEXT_VIOTA_M(viota_m_b, uint8_t, H1, clearb) GEN_VEXT_VIOTA_M(viota_m_h, uint16_t, H2, clearh) GEN_VEXT_VIOTA_M(viota_m_w, uint32_t, H4, clearl) GEN_VEXT_VIOTA_M(viota_m_d, uint64_t, H8, clearq) + +/* Vector Element Index Instruction */ +#define GEN_VEXT_VID_V(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + int i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + *((ETYPE *)vd + H(i)) = i; \ + } \ + CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \ +} + +GEN_VEXT_VID_V(vid_v_b, uint8_t, H1, clearb) +GEN_VEXT_VID_V(vid_v_h, uint16_t, H2, clearh) +GEN_VEXT_VID_V(vid_v_w, uint32_t, H4, clearl) +GEN_VEXT_VID_V(vid_v_d, uint64_t, H8, clearq) From 90355f391d979ccd95d09ab42f647f103a3dbe69 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:43 +0800 Subject: [PATCH 1856/2595] target/riscv: integer extract instruction Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-56-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/insn32.decode | 1 + target/riscv/insn_trans/trans_rvv.inc.c | 116 ++++++++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 6f2e2df7d3..c4496cd010 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -563,6 +563,7 @@ vmsif_m 010110 . ..... 00011 010 ..... 1010111 @r2_vm vmsof_m 010110 . ..... 00010 010 ..... 1010111 @r2_vm viota_m 010110 . ..... 10000 010 ..... 1010111 @r2_vm vid_v 010110 . 00000 10001 010 ..... 1010111 @r1_vm +vext_x_v 001100 1 ..... ..... 010 ..... 1010111 @r vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index e94d149d3b..cfbbd88dbf 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2533,3 +2533,119 @@ static bool trans_vid_v(DisasContext *s, arg_vid_v *a) } return false; } + +/* + *** Vector Permutation Instructions + */ + +/* Integer Extract Instruction */ + +static void load_element(TCGv_i64 dest, TCGv_ptr base, + int ofs, int sew) +{ + switch (sew) { + case MO_8: + tcg_gen_ld8u_i64(dest, base, ofs); + break; + case MO_16: + tcg_gen_ld16u_i64(dest, base, ofs); + break; + case MO_32: + tcg_gen_ld32u_i64(dest, base, ofs); + break; + case MO_64: + tcg_gen_ld_i64(dest, base, ofs); + break; + default: + g_assert_not_reached(); + break; + } +} + +/* offset of the idx element with base regsiter r */ +static uint32_t endian_ofs(DisasContext *s, int r, int idx) +{ +#ifdef HOST_WORDS_BIGENDIAN + return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); +#else + return vreg_ofs(s, r) + (idx << s->sew); +#endif +} + +/* adjust the index according to the endian */ +static void endian_adjust(TCGv_i32 ofs, int sew) +{ +#ifdef HOST_WORDS_BIGENDIAN + tcg_gen_xori_i32(ofs, ofs, 7 >> sew); +#endif +} + +/* Load idx >= VLMAX ? 0 : vreg[idx] */ +static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, + int vreg, TCGv idx, int vlmax) +{ + TCGv_i32 ofs = tcg_temp_new_i32(); + TCGv_ptr base = tcg_temp_new_ptr(); + TCGv_i64 t_idx = tcg_temp_new_i64(); + TCGv_i64 t_vlmax, t_zero; + + /* + * Mask the index to the length so that we do + * not produce an out-of-range load. + */ + tcg_gen_trunc_tl_i32(ofs, idx); + tcg_gen_andi_i32(ofs, ofs, vlmax - 1); + + /* Convert the index to an offset. */ + endian_adjust(ofs, s->sew); + tcg_gen_shli_i32(ofs, ofs, s->sew); + + /* Convert the index to a pointer. */ + tcg_gen_ext_i32_ptr(base, ofs); + tcg_gen_add_ptr(base, base, cpu_env); + + /* Perform the load. */ + load_element(dest, base, + vreg_ofs(s, vreg), s->sew); + tcg_temp_free_ptr(base); + tcg_temp_free_i32(ofs); + + /* Flush out-of-range indexing to zero. */ + t_vlmax = tcg_const_i64(vlmax); + t_zero = tcg_const_i64(0); + tcg_gen_extu_tl_i64(t_idx, idx); + + tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, + t_vlmax, dest, t_zero); + + tcg_temp_free_i64(t_vlmax); + tcg_temp_free_i64(t_zero); + tcg_temp_free_i64(t_idx); +} + +static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, + int vreg, int idx) +{ + load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew); +} + +static bool trans_vext_x_v(DisasContext *s, arg_r *a) +{ + TCGv_i64 tmp = tcg_temp_new_i64(); + TCGv dest = tcg_temp_new(); + + if (a->rs1 == 0) { + /* Special case vmv.x.s rd, vs2. */ + vec_element_loadi(s, tmp, a->rs2, 0); + } else { + /* This instruction ignores LMUL and vector register groups */ + int vlmax = s->vlen >> (3 + s->sew); + vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax); + } + tcg_gen_trunc_i64_tl(dest, tmp); + gen_set_gpr(a->rd, dest); + + tcg_temp_free(dest); + tcg_temp_free_i64(tmp); + return true; +} From 9fc08be626a96ae1ac0cffb22f30ae652c1c645a Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:44 +0800 Subject: [PATCH 1857/2595] target/riscv: integer scalar move instruction Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-57-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/insn32.decode | 1 + target/riscv/insn_trans/trans_rvv.inc.c | 60 +++++++++++++++++++++++++ target/riscv/internals.h | 6 +++ 3 files changed, 67 insertions(+) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index c4496cd010..e06c0ffc22 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -564,6 +564,7 @@ vmsof_m 010110 . ..... 00010 010 ..... 1010111 @r2_vm viota_m 010110 . ..... 10000 010 ..... 1010111 @r2_vm vid_v 010110 . 00000 10001 010 ..... 1010111 @r1_vm vext_x_v 001100 1 ..... ..... 010 ..... 1010111 @r +vmv_s_x 001101 1 00000 ..... 110 ..... 1010111 @r2 vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index cfbbd88dbf..b10b89daa9 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2649,3 +2649,63 @@ static bool trans_vext_x_v(DisasContext *s, arg_r *a) tcg_temp_free_i64(tmp); return true; } + +/* Integer Scalar Move Instruction */ + +static void store_element(TCGv_i64 val, TCGv_ptr base, + int ofs, int sew) +{ + switch (sew) { + case MO_8: + tcg_gen_st8_i64(val, base, ofs); + break; + case MO_16: + tcg_gen_st16_i64(val, base, ofs); + break; + case MO_32: + tcg_gen_st32_i64(val, base, ofs); + break; + case MO_64: + tcg_gen_st_i64(val, base, ofs); + break; + default: + g_assert_not_reached(); + break; + } +} + +/* + * Store vreg[idx] = val. + * The index must be in range of VLMAX. + */ +static void vec_element_storei(DisasContext *s, int vreg, + int idx, TCGv_i64 val) +{ + store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew); +} + +/* vmv.s.x vd, rs1 # vd[0] = rs1 */ +static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) +{ + if (vext_check_isa_ill(s)) { + /* This instruction ignores LMUL and vector register groups */ + int maxsz = s->vlen >> 3; + TCGv_i64 t1; + TCGLabel *over = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0); + if (a->rs1 == 0) { + goto done; + } + + t1 = tcg_temp_new_i64(); + tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]); + vec_element_storei(s, a->rd, 0, t1); + tcg_temp_free_i64(t1); + done: + gen_set_label(over); + return true; + } + return false; +} diff --git a/target/riscv/internals.h b/target/riscv/internals.h index f3cea478f7..37d33820ad 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -32,4 +32,10 @@ FIELD(VDATA, WD, 11, 1) target_ulong fclass_h(uint64_t frs1); target_ulong fclass_s(uint64_t frs1); target_ulong fclass_d(uint64_t frs1); + +#define SEW8 0 +#define SEW16 1 +#define SEW32 2 +#define SEW64 3 + #endif From 2843420a562c107801bae20f74579e4fe540316f Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:45 +0800 Subject: [PATCH 1858/2595] target/riscv: floating-point scalar move instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-58-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/insn32.decode | 3 ++ target/riscv/insn_trans/trans_rvv.inc.c | 49 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index e06c0ffc22..17288a3c95 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -72,6 +72,7 @@ @r2_vm ...... vm:1 ..... ..... ... ..... ....... &rmr %rs2 %rd @r1_vm ...... vm:1 ..... ..... ... ..... ....... %rd @r_nfvm ... ... vm:1 ..... ..... ... ..... ....... &rnfvm %nf %rs2 %rs1 %rd +@r2rd ....... ..... ..... ... ..... ....... %rs2 %rd @r_vm ...... vm:1 ..... ..... ... ..... ....... &rmrr %rs2 %rs1 %rd @r_vm_1 ...... . ..... ..... ... ..... ....... &rmrr vm=1 %rs2 %rs1 %rd @r_vm_0 ...... . ..... ..... ... ..... ....... &rmrr vm=0 %rs2 %rs1 %rd @@ -565,6 +566,8 @@ viota_m 010110 . ..... 10000 010 ..... 1010111 @r2_vm vid_v 010110 . 00000 10001 010 ..... 1010111 @r1_vm vext_x_v 001100 1 ..... ..... 010 ..... 1010111 @r vmv_s_x 001101 1 00000 ..... 110 ..... 1010111 @r2 +vfmv_f_s 001100 1 ..... 00000 001 ..... 1010111 @r2rd +vfmv_s_f 001101 1 00000 ..... 101 ..... 1010111 @r2 vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index b10b89daa9..7af16ce0a8 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2709,3 +2709,52 @@ static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) } return false; } + +/* Floating-Point Scalar Move Instructions */ +static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) +{ + if (!s->vill && has_ext(s, RVF) && + (s->mstatus_fs != 0) && (s->sew != 0)) { + unsigned int len = 8 << s->sew; + + vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0); + if (len < 64) { + tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], + MAKE_64BIT_MASK(len, 64 - len)); + } + + mark_fs_dirty(s); + return true; + } + return false; +} + +/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ +static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) +{ + if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) { + TCGv_i64 t1; + /* The instructions ignore LMUL and vector register group. */ + uint32_t vlmax = s->vlen >> 3; + + /* if vl == 0, skip vector register write back */ + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + /* zeroed all elements */ + tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0); + + /* NaN-box f[rs1] as necessary for SEW */ + t1 = tcg_temp_new_i64(); + if (s->sew == MO_64 && !has_ext(s, RVD)) { + tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32)); + } else { + tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]); + } + vec_element_storei(s, a->rd, 0, t1); + tcg_temp_free_i64(t1); + gen_set_label(over); + return true; + } + return false; +} From ec17e03688ce4d0ae188db6d90b185b92a9a2087 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:46 +0800 Subject: [PATCH 1859/2595] target/riscv: vector slide instructions Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-59-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 17 ++++ target/riscv/insn32.decode | 6 ++ target/riscv/insn_trans/trans_rvv.inc.c | 18 ++++ target/riscv/vector_helper.c | 114 ++++++++++++++++++++++++ 4 files changed, 155 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index c6695ea7a8..29a5eb7049 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1119,3 +1119,20 @@ DEF_HELPER_4(vid_v_b, void, ptr, ptr, env, i32) DEF_HELPER_4(vid_v_h, void, ptr, ptr, env, i32) DEF_HELPER_4(vid_v_w, void, ptr, ptr, env, i32) DEF_HELPER_4(vid_v_d, void, ptr, ptr, env, i32) + +DEF_HELPER_6(vslideup_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslideup_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslideup_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslideup_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslidedown_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslidedown_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslidedown_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslidedown_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslide1up_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslide1up_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslide1up_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslide1up_vx_d, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslide1down_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslide1down_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslide1down_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vslide1down_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 17288a3c95..36123f71b9 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -568,6 +568,12 @@ vext_x_v 001100 1 ..... ..... 010 ..... 1010111 @r vmv_s_x 001101 1 00000 ..... 110 ..... 1010111 @r2 vfmv_f_s 001100 1 ..... 00000 001 ..... 1010111 @r2rd vfmv_s_f 001101 1 00000 ..... 101 ..... 1010111 @r2 +vslideup_vx 001110 . ..... ..... 100 ..... 1010111 @r_vm +vslideup_vi 001110 . ..... ..... 011 ..... 1010111 @r_vm +vslide1up_vx 001110 . ..... ..... 110 ..... 1010111 @r_vm +vslidedown_vx 001111 . ..... ..... 100 ..... 1010111 @r_vm +vslidedown_vi 001111 . ..... ..... 011 ..... 1010111 @r_vm +vslide1down_vx 001111 . ..... ..... 110 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 7af16ce0a8..4ed6d1ee2e 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2758,3 +2758,21 @@ static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) } return false; } + +/* Vector Slide Instructions */ +static bool slideup_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + (a->rd != a->rs2)); +} + +GEN_OPIVX_TRANS(vslideup_vx, slideup_check) +GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) +GEN_OPIVI_TRANS(vslideup_vi, 1, vslideup_vx, slideup_check) + +GEN_OPIVX_TRANS(vslidedown_vx, opivx_check) +GEN_OPIVX_TRANS(vslide1down_vx, opivx_check) +GEN_OPIVI_TRANS(vslidedown_vi, 1, vslidedown_vx, opivx_check) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 0fa899b6ff..51c4bc5756 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4697,3 +4697,117 @@ GEN_VEXT_VID_V(vid_v_b, uint8_t, H1, clearb) GEN_VEXT_VID_V(vid_v_h, uint16_t, H2, clearh) GEN_VEXT_VID_V(vid_v_w, uint32_t, H4, clearl) GEN_VEXT_VID_V(vid_v_d, uint64_t, H8, clearq) + +/* + *** Vector Permutation Instructions + */ + +/* Vector Slide Instructions */ +#define GEN_VEXT_VSLIDEUP_VX(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + target_ulong offset = s1, i; \ + \ + for (i = offset; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i - offset)); \ + } \ + CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \ +} + +/* vslideup.vx vd, vs2, rs1, vm # vd[i+rs1] = vs2[i] */ +GEN_VEXT_VSLIDEUP_VX(vslideup_vx_b, uint8_t, H1, clearb) +GEN_VEXT_VSLIDEUP_VX(vslideup_vx_h, uint16_t, H2, clearh) +GEN_VEXT_VSLIDEUP_VX(vslideup_vx_w, uint32_t, H4, clearl) +GEN_VEXT_VSLIDEUP_VX(vslideup_vx_d, uint64_t, H8, clearq) + +#define GEN_VEXT_VSLIDEDOWN_VX(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + target_ulong offset = s1, i; \ + \ + for (i = 0; i < vl; ++i) { \ + target_ulong j = i + offset; \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + *((ETYPE *)vd + H(i)) = j >= vlmax ? 0 : *((ETYPE *)vs2 + H(j)); \ + } \ + CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \ +} + +/* vslidedown.vx vd, vs2, rs1, vm # vd[i] = vs2[i+rs1] */ +GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_b, uint8_t, H1, clearb) +GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_h, uint16_t, H2, clearh) +GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_w, uint32_t, H4, clearl) +GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_d, uint64_t, H8, clearq) + +#define GEN_VEXT_VSLIDE1UP_VX(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + if (i == 0) { \ + *((ETYPE *)vd + H(i)) = s1; \ + } else { \ + *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i - 1)); \ + } \ + } \ + CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \ +} + +/* vslide1up.vx vd, vs2, rs1, vm # vd[0]=x[rs1], vd[i+1] = vs2[i] */ +GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_b, uint8_t, H1, clearb) +GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_h, uint16_t, H2, clearh) +GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_w, uint32_t, H4, clearl) +GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_d, uint64_t, H8, clearq) + +#define GEN_VEXT_VSLIDE1DOWN_VX(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + if (i == vl - 1) { \ + *((ETYPE *)vd + H(i)) = s1; \ + } else { \ + *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i + 1)); \ + } \ + } \ + CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \ +} + +/* vslide1down.vx vd, vs2, rs1, vm # vd[i] = vs2[i+1], vd[vl-1]=x[rs1] */ +GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_b, uint8_t, H1, clearb) +GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_h, uint16_t, H2, clearh) +GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_w, uint32_t, H4, clearl) +GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_d, uint64_t, H8, clearq) From e4b83d5c0928507cc27a0f613675b117db9993e4 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:47 +0800 Subject: [PATCH 1860/2595] target/riscv: vector register gather instruction Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-60-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 9 +++ target/riscv/insn32.decode | 3 + target/riscv/insn_trans/trans_rvv.inc.c | 78 +++++++++++++++++++++++++ target/riscv/vector_helper.c | 60 +++++++++++++++++++ 4 files changed, 150 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 29a5eb7049..eca1ab541b 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1136,3 +1136,12 @@ DEF_HELPER_6(vslide1down_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vslide1down_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vslide1down_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vslide1down_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vrgather_vv_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vrgather_vv_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vrgather_vv_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vrgather_vv_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vrgather_vx_b, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vrgather_vx_h, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vrgather_vx_w, void, ptr, ptr, tl, ptr, env, i32) +DEF_HELPER_6(vrgather_vx_d, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 36123f71b9..80d5ff74a9 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -574,6 +574,9 @@ vslide1up_vx 001110 . ..... ..... 110 ..... 1010111 @r_vm vslidedown_vx 001111 . ..... ..... 100 ..... 1010111 @r_vm vslidedown_vi 001111 . ..... ..... 011 ..... 1010111 @r_vm vslide1down_vx 001111 . ..... ..... 110 ..... 1010111 @r_vm +vrgather_vv 001100 . ..... ..... 000 ..... 1010111 @r_vm +vrgather_vx 001100 . ..... ..... 100 ..... 1010111 @r_vm +vrgather_vi 001100 . ..... ..... 011 ..... 1010111 @r_vm vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 4ed6d1ee2e..c0b7745a63 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2776,3 +2776,81 @@ GEN_OPIVI_TRANS(vslideup_vi, 1, vslideup_vx, slideup_check) GEN_OPIVX_TRANS(vslidedown_vx, opivx_check) GEN_OPIVX_TRANS(vslide1down_vx, opivx_check) GEN_OPIVI_TRANS(vslidedown_vi, 1, vslidedown_vx, opivx_check) + +/* Vector Register Gather Instruction */ +static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs1, false) && + vext_check_reg(s, a->rs2, false) && + (a->rd != a->rs2) && (a->rd != a->rs1)); +} + +GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) + +static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) +{ + return (vext_check_isa_ill(s) && + vext_check_overlap_mask(s, a->rd, a->vm, true) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + (a->rd != a->rs2)); +} + +/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ +static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) +{ + if (!vrgather_vx_check(s, a)) { + return false; + } + + if (a->vm && s->vl_eq_vlmax) { + int vlmax = s->vlen / s->mlen; + TCGv_i64 dest = tcg_temp_new_i64(); + + if (a->rs1 == 0) { + vec_element_loadi(s, dest, a->rs2, 0); + } else { + vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); + } + + tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), + MAXSZ(s), MAXSZ(s), dest); + tcg_temp_free_i64(dest); + } else { + static gen_helper_opivx * const fns[4] = { + gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, + gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d + }; + return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); + } + return true; +} + +/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ +static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) +{ + if (!vrgather_vx_check(s, a)) { + return false; + } + + if (a->vm && s->vl_eq_vlmax) { + if (a->rs1 >= s->vlen / s->mlen) { + tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), + MAXSZ(s), MAXSZ(s), 0); + } else { + tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), + endian_ofs(s, a->rs2, a->rs1), + MAXSZ(s), MAXSZ(s)); + } + } else { + static gen_helper_opivx * const fns[4] = { + gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, + gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d + }; + return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s, 1); + } + return true; +} diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 51c4bc5756..3179b1faef 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4811,3 +4811,63 @@ GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_b, uint8_t, H1, clearb) GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_h, uint16_t, H2, clearh) GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_w, uint32_t, H4, clearl) GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_d, uint64_t, H8, clearq) + +/* Vector Register Gather Instruction */ +#define GEN_VEXT_VRGATHER_VV(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t index, i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + index = *((ETYPE *)vs1 + H(i)); \ + if (index >= vlmax) { \ + *((ETYPE *)vd + H(i)) = 0; \ + } else { \ + *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(index)); \ + } \ + } \ + CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \ +} + +/* vd[i] = (vs1[i] >= VLMAX) ? 0 : vs2[vs1[i]]; */ +GEN_VEXT_VRGATHER_VV(vrgather_vv_b, uint8_t, H1, clearb) +GEN_VEXT_VRGATHER_VV(vrgather_vv_h, uint16_t, H2, clearh) +GEN_VEXT_VRGATHER_VV(vrgather_vv_w, uint32_t, H4, clearl) +GEN_VEXT_VRGATHER_VV(vrgather_vv_d, uint64_t, H8, clearq) + +#define GEN_VEXT_VRGATHER_VX(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ + uint32_t vm = vext_vm(desc); \ + uint32_t vl = env->vl; \ + uint32_t index = s1, i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vm && !vext_elem_mask(v0, mlen, i)) { \ + continue; \ + } \ + if (index >= vlmax) { \ + *((ETYPE *)vd + H(i)) = 0; \ + } else { \ + *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(index)); \ + } \ + } \ + CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \ +} + +/* vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ +GEN_VEXT_VRGATHER_VX(vrgather_vx_b, uint8_t, H1, clearb) +GEN_VEXT_VRGATHER_VX(vrgather_vx_h, uint16_t, H2, clearh) +GEN_VEXT_VRGATHER_VX(vrgather_vx_w, uint32_t, H4, clearl) +GEN_VEXT_VRGATHER_VX(vrgather_vx_d, uint64_t, H8, clearq) From 31bf42a26cf8b1e02f27acd302ee0ef14e877682 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:48 +0800 Subject: [PATCH 1861/2595] target/riscv: vector compress instruction Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-61-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 5 ++++ target/riscv/insn32.decode | 1 + target/riscv/insn_trans/trans_rvv.inc.c | 32 +++++++++++++++++++++++++ target/riscv/vector_helper.c | 26 ++++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index eca1ab541b..acc298219d 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1145,3 +1145,8 @@ DEF_HELPER_6(vrgather_vx_b, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vrgather_vx_h, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vrgather_vx_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vrgather_vx_d, void, ptr, ptr, tl, ptr, env, i32) + +DEF_HELPER_6(vcompress_vm_b, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vcompress_vm_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vcompress_vm_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vcompress_vm_d, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 80d5ff74a9..bdd8563067 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -577,6 +577,7 @@ vslide1down_vx 001111 . ..... ..... 110 ..... 1010111 @r_vm vrgather_vv 001100 . ..... ..... 000 ..... 1010111 @r_vm vrgather_vx 001100 . ..... ..... 100 ..... 1010111 @r_vm vrgather_vi 001100 . ..... ..... 011 ..... 1010111 @r_vm +vcompress_vm 010111 - ..... ..... 010 ..... 1010111 @r vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index c0b7745a63..dc333e6a91 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -2854,3 +2854,35 @@ static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) } return true; } + +/* Vector Compress Instruction */ +static bool vcompress_vm_check(DisasContext *s, arg_r *a) +{ + return (vext_check_isa_ill(s) && + vext_check_reg(s, a->rd, false) && + vext_check_reg(s, a->rs2, false) && + vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs1, 1) && + (a->rd != a->rs2)); +} + +static bool trans_vcompress_vm(DisasContext *s, arg_r *a) +{ + if (vcompress_vm_check(s, a)) { + uint32_t data = 0; + static gen_helper_gvec_4_ptr * const fns[4] = { + gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, + gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, + }; + TCGLabel *over = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); + + data = FIELD_DP32(data, VDATA, MLEN, s->mlen); + data = FIELD_DP32(data, VDATA, LMUL, s->lmul); + tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), + vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), + cpu_env, 0, s->vlen / 8, data, fns[s->sew]); + gen_set_label(over); + return true; + } + return false; +} diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 3179b1faef..39f44d1029 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4871,3 +4871,29 @@ GEN_VEXT_VRGATHER_VX(vrgather_vx_b, uint8_t, H1, clearb) GEN_VEXT_VRGATHER_VX(vrgather_vx_h, uint16_t, H2, clearh) GEN_VEXT_VRGATHER_VX(vrgather_vx_w, uint32_t, H4, clearl) GEN_VEXT_VRGATHER_VX(vrgather_vx_d, uint64_t, H8, clearq) + +/* Vector Compress Instruction */ +#define GEN_VEXT_VCOMPRESS_VM(NAME, ETYPE, H, CLEAR_FN) \ +void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ + CPURISCVState *env, uint32_t desc) \ +{ \ + uint32_t mlen = vext_mlen(desc); \ + uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ + uint32_t vl = env->vl; \ + uint32_t num = 0, i; \ + \ + for (i = 0; i < vl; i++) { \ + if (!vext_elem_mask(vs1, mlen, i)) { \ + continue; \ + } \ + *((ETYPE *)vd + H(num)) = *((ETYPE *)vs2 + H(i)); \ + num++; \ + } \ + CLEAR_FN(vd, num, num * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \ +} + +/* Compress into vd elements of vs2 where vs1 is enabled */ +GEN_VEXT_VCOMPRESS_VM(vcompress_vm_b, uint8_t, H1, clearb) +GEN_VEXT_VCOMPRESS_VM(vcompress_vm_h, uint16_t, H2, clearh) +GEN_VEXT_VCOMPRESS_VM(vcompress_vm_w, uint32_t, H4, clearl) +GEN_VEXT_VCOMPRESS_VM(vcompress_vm_d, uint64_t, H8, clearq) From 6bf91617f47c74efc99ef48236765d9677c0898e Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Wed, 1 Jul 2020 23:25:49 +0800 Subject: [PATCH 1862/2595] target/riscv: configure and turn on vector extension from command line Vector extension is default off. The only way to use vector extension is 1. use cpu rv32 or rv64 2. turn on it by command line "-cpu rv64,x-v=true,vlen=128,elen=64,vext_spec=v0.7.1". vlen is the vector register length, default value is 128 bit. elen is the max operator size in bits, default value is 64 bit. vext_spec is the vector specification version, default value is v0.7.1. These properties can be specified with other values. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-Id: <20200701152549.1218-62-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 43 +++++++++++++++++++++++++++++++++++++++++++ target/riscv/cpu.h | 4 +++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d525cfb687..228b9bdb5d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -430,6 +430,45 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) if (cpu->cfg.ext_h) { target_misa |= RVH; } + if (cpu->cfg.ext_v) { + target_misa |= RVV; + if (!is_power_of_2(cpu->cfg.vlen)) { + error_setg(errp, + "Vector extension VLEN must be power of 2"); + return; + } + if (cpu->cfg.vlen > RV_VLEN_MAX || cpu->cfg.vlen < 128) { + error_setg(errp, + "Vector extension implementation only supports VLEN " + "in the range [128, %d]", RV_VLEN_MAX); + return; + } + if (!is_power_of_2(cpu->cfg.elen)) { + error_setg(errp, + "Vector extension ELEN must be power of 2"); + return; + } + if (cpu->cfg.elen > 64 || cpu->cfg.vlen < 8) { + error_setg(errp, + "Vector extension implementation only supports ELEN " + "in the range [8, 64]"); + return; + } + if (cpu->cfg.vext_spec) { + if (!g_strcmp0(cpu->cfg.vext_spec, "v0.7.1")) { + vext_version = VEXT_VERSION_0_07_1; + } else { + error_setg(errp, + "Unsupported vector spec version '%s'", + cpu->cfg.vext_spec); + return; + } + } else { + qemu_log("vector verison is not specified, " + "use the default value v0.7.1\n"); + } + set_vext_version(env, vext_version); + } set_misa(env, RVXLEN | target_misa); } @@ -469,10 +508,14 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true), /* This is experimental so mark with 'x-' */ DEFINE_PROP_BOOL("x-h", RISCVCPU, cfg.ext_h, false), + DEFINE_PROP_BOOL("x-v", RISCVCPU, cfg.ext_v, false), DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true), DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true), DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true), DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), + DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec), + DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128), + DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), DEFINE_PROP_END_OF_LIST(), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 0ad51c6580..eef20ca6e5 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -92,7 +92,7 @@ typedef struct CPURISCVState CPURISCVState; #include "pmp.h" -#define RV_VLEN_MAX 512 +#define RV_VLEN_MAX 256 FIELD(VTYPE, VLMUL, 0, 2) FIELD(VTYPE, VSEW, 2, 3) @@ -279,12 +279,14 @@ typedef struct RISCVCPU { bool ext_s; bool ext_u; bool ext_h; + bool ext_v; bool ext_counters; bool ext_ifencei; bool ext_icsr; char *priv_spec; char *user_spec; + char *vext_spec; uint16_t vlen; uint16_t elen; bool mmu; From edafc70c0c8510862f2f213a3acf7067113bcd08 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 22 Jun 2020 17:12:03 +0200 Subject: [PATCH 1863/2595] qemu-img convert: Don't pre-zero images Since commit 5a37b60a61c, qemu-img create will pre-zero the target image if it isn't already zero-initialised (most importantly, for host block devices, but also iscsi etc.), so that writing explicit zeros wouldn't be necessary later. This could speed up the operation significantly, in particular when the source image file was only sparsely populated. However, it also means that some block are written twice: Once when pre-zeroing them, and then when they are overwritten with actual data. On a full image, the pre-zeroing is wasted work because everything will be overwritten. In practice, write_zeroes typically turns out faster than writing explicit zero buffers, but slow enough that first zeroing everything and then overwriting parts can be a significant net loss. Meanwhile, qemu-img convert was rewritten in 690c7301600 and zero blocks are now written to the target using bdrv_co_pwrite_zeroes() if the target could be pre-zeroed. This way we already make use of the faster write_zeroes operation, but avoid writing any blocks twice. Remove the pre-zeroing because these days this former optimisation has actually turned into a pessimisation in the common case. Reported-by: Nir Soffer Signed-off-by: Kevin Wolf Message-Id: <20200622151203.35624-1-kwolf@redhat.com> Tested-by: Nir Soffer Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- qemu-img.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index d7e846e607..bdb9f6aa46 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2084,15 +2084,6 @@ static int convert_do_copy(ImgConvertState *s) s->has_zero_init = bdrv_has_zero_init(blk_bs(s->target)); } - if (!s->has_zero_init && !s->target_has_backing && - bdrv_can_write_zeroes_with_unmap(blk_bs(s->target))) - { - ret = blk_make_zero(s->target, BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK); - if (ret == 0) { - s->has_zero_init = true; - } - } - /* Allocate buffer for copied data. For compressed images, only one cluster * can be copied at a time. */ if (s->compressed) { From 5b99bdea842d4190d2471769903cdcc1621eb493 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 19 Jun 2020 11:11:31 +0100 Subject: [PATCH 1864/2595] qemu-storage-daemon: remember to add qemu_object_opts The --object option is supported by qemu-storage-daemon but the qemu_object_opts QemuOptsList wasn't being added. As a result calls to qemu_find_opts("object") failed with "There is no option group 'object'". This patch fixes the object-del QMP command. Signed-off-by: Stefan Hajnoczi Message-Id: <20200619101132.2401756-2-stefanha@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- qemu-storage-daemon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c index 9e7adfe3a6..a01cbd6371 100644 --- a/qemu-storage-daemon.c +++ b/qemu-storage-daemon.c @@ -316,6 +316,7 @@ int main(int argc, char *argv[]) module_call_init(MODULE_INIT_QOM); module_call_init(MODULE_INIT_TRACE); + qemu_add_opts(&qemu_object_opts); qemu_add_opts(&qemu_trace_opts); qcrypto_init(&error_fatal); bdrv_init(); From f10802d2c9fd8bfd92c70f465da1a5992445157f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 19 Jun 2020 11:11:32 +0100 Subject: [PATCH 1865/2595] qemu-storage-daemon: add missing cleanup calls Several components used by qemu-storage-daemon have cleanup functions that aren't called. Keep the "valgrind --leak-check=full" as clean as possible by invoking the necessary cleanup functions. Signed-off-by: Stefan Hajnoczi Message-Id: <20200619101132.2401756-3-stefanha@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- qemu-storage-daemon.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c index a01cbd6371..7e9b0e0d3f 100644 --- a/qemu-storage-daemon.c +++ b/qemu-storage-daemon.c @@ -335,5 +335,9 @@ int main(int argc, char *argv[]) main_loop_wait(false); } + monitor_cleanup(); + qemu_chr_cleanup(); + user_creatable_cleanup(); + return EXIT_SUCCESS; } From c79e243ed67683d6d06692bd7040f7394da178b0 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 23 Jun 2020 19:55:33 +0200 Subject: [PATCH 1866/2595] vvfat: Check that updated filenames are valid FAT allows only a restricted set of characters in file names, and for some of the illegal characters, it's actually important that we catch them: If filenames can contain '/', the guest can construct filenames containing "../" and escape from the assigned vvfat directory. The same problem could arise if ".." was ever accepted as a literal filename. Fix this by adding a check that all filenames are valid in check_directory_consistency(). Reported-by: Nathan Huckleberry Signed-off-by: Kevin Wolf Message-Id: <20200623175534.38286-2-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/vvfat.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/block/vvfat.c b/block/vvfat.c index c65a98e3ee..62230542e5 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -520,12 +520,31 @@ static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin) direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff); } +static bool valid_filename(const unsigned char *name) +{ + unsigned char c; + if (!strcmp((const char*)name, ".") || !strcmp((const char*)name, "..")) { + return false; + } + for (; (c = *name); name++) { + if (!((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + c > 127 || + strchr("$%'-_@~`!(){}^#&.+,;=[]", c) != NULL)) + { + return false; + } + } + return true; +} + static uint8_t to_valid_short_char(gunichar c) { c = g_unichar_toupper(c); if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || - strchr("$%'-_@~`!(){}^#&", c) != 0) { + strchr("$%'-_@~`!(){}^#&", c) != NULL) { return c; } else { return 0; @@ -2098,6 +2117,10 @@ DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i)) } lfn.checksum = 0x100; /* cannot use long name twice */ + if (!valid_filename(lfn.name)) { + fprintf(stderr, "Invalid file name\n"); + goto fail; + } if (path_len + 1 + lfn.len >= PATH_MAX) { fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name); goto fail; From 3dfa23b9eff4315817c1acf59711b8414347de31 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 23 Jun 2020 19:55:34 +0200 Subject: [PATCH 1867/2595] vvfat: Fix array_remove_slice() array_remove_slice() calls array_roll() with array->next - 1 as the destination index. This is only correct for count == 1, otherwise we're writing past the end of the array. array->next - count would be correct. However, this is the only place ever calling array_roll(), so this rather complicated operation isn't even necessary. Fix the problem and simplify the code by replacing it with a single memmove() call. array_roll() can now be removed. Reported-by: Nathan Huckleberry Signed-off-by: Kevin Wolf Message-Id: <20200623175534.38286-3-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/vvfat.c | 42 +++++------------------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) diff --git a/block/vvfat.c b/block/vvfat.c index 62230542e5..2eb8cbb19f 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -140,48 +140,16 @@ static inline void* array_insert(array_t* array,unsigned int index,unsigned int return array->pointer+index*array->item_size; } -/* this performs a "roll", so that the element which was at index_from becomes - * index_to, but the order of all other elements is preserved. */ -static inline int array_roll(array_t* array,int index_to,int index_from,int count) -{ - char* buf; - char* from; - char* to; - int is; - - if(!array || - index_to<0 || index_to>=array->next || - index_from<0 || index_from>=array->next) - return -1; - - if(index_to==index_from) - return 0; - - is=array->item_size; - from=array->pointer+index_from*is; - to=array->pointer+index_to*is; - buf=g_malloc(is*count); - memcpy(buf,from,is*count); - - if(index_to=0); assert(count > 0); assert(index + count <= array->next); - if(array_roll(array,array->next-1,index,count)) - return -1; + + memmove(array->pointer + index * array->item_size, + array->pointer + (index + count) * array->item_size, + (array->next - index - count) * array->item_size); + array->next -= count; return 0; } From 49438972b8c2e16cf1f98b1b2355926e8c633e63 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 30 Jun 2020 10:37:11 +0200 Subject: [PATCH 1868/2595] iotests.py: Do not wait() before communicate() Waiting on a process for which we have a pipe will stall if the process outputs more data than fits into the OS-provided buffer. We must use communicate() before wait(), and in fact, communicate() perfectly replaces wait() already. We have to drop the stderr=subprocess.STDOUT parameter from subprocess.Popen() in qemu_nbd_early_pipe(), because stderr is passed on to the child process, so if we do not drop this parameter, communicate() will hang (because the pipe is not closed). Signed-off-by: Max Reitz Message-Id: <20200630083711.40567-1-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/iotests.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 5ea4c4df8b..ef739dd1e3 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -146,11 +146,12 @@ def qemu_img_pipe(*args): stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - exitcode = subp.wait() - if exitcode < 0: + output = subp.communicate()[0] + if subp.returncode < 0: sys.stderr.write('qemu-img received signal %i: %s\n' - % (-exitcode, ' '.join(qemu_img_args + list(args)))) - return subp.communicate()[0] + % (-subp.returncode, + ' '.join(qemu_img_args + list(args)))) + return output def qemu_img_log(*args): result = qemu_img_pipe(*args) @@ -177,11 +178,11 @@ def qemu_io(*args): subp = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - exitcode = subp.wait() - if exitcode < 0: + output = subp.communicate()[0] + if subp.returncode < 0: sys.stderr.write('qemu-io received signal %i: %s\n' - % (-exitcode, ' '.join(args))) - return subp.communicate()[0] + % (-subp.returncode, ' '.join(args))) + return output def qemu_io_log(*args): result = qemu_io(*args) @@ -257,15 +258,14 @@ def qemu_nbd_early_pipe(*args): and its output in case of an error''' subp = subprocess.Popen(qemu_nbd_args + ['--fork'] + list(args), stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, universal_newlines=True) - exitcode = subp.wait() - if exitcode < 0: + output = subp.communicate()[0] + if subp.returncode < 0: sys.stderr.write('qemu-nbd received signal %i: %s\n' % - (-exitcode, + (-subp.returncode, ' '.join(qemu_nbd_args + ['--fork'] + list(args)))) - return exitcode, subp.communicate()[0] if exitcode else '' + return subp.returncode, output if subp.returncode else '' def qemu_nbd_popen(*args): '''Run qemu-nbd in daemon mode and return the parent's exit code''' @@ -1062,11 +1062,11 @@ def qemu_pipe(*args): subp = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - exitcode = subp.wait() - if exitcode < 0: + output = subp.communicate()[0] + if subp.returncode < 0: sys.stderr.write('qemu received signal %i: %s\n' % - (-exitcode, ' '.join(args))) - return subp.communicate()[0] + (-subp.returncode, ' '.join(args))) + return output def supported_formats(read_only=False): '''Set 'read_only' to True to check ro-whitelist From 4f071a9460886667fde061c05b79dc786cc22e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jun 2020 15:04:22 +0100 Subject: [PATCH 1869/2595] iotests: Fix 051 output after qdev_init_nofail() removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 96927c744 replaced qdev_init_nofail() call by isa_realize_and_unref() which has a different error message. Update the test output accordingly. Gitlab CI error after merging b77b5b3dc7: https://gitlab.com/qemu-project/qemu/-/jobs/597414772#L4375 Reported-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Reviewed-by: John Snow Reviewed-by: Thomas Huth Message-Id: <20200616154949.6586-1-philmd@redhat.com> Message-Id: <20200624140446.15380-2-alex.bennee@linaro.org> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/051.pc.out | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out index 0ea80d35f0..da8ad87187 100644 --- a/tests/qemu-iotests/051.pc.out +++ b/tests/qemu-iotests/051.pc.out @@ -142,7 +142,7 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive if=ide QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Initialization of device ide-hd failed: Device needs media, but drive is empty +(qemu) QEMU_PROG: Device needs media, but drive is empty Testing: -drive if=virtio QEMU X.Y.Z monitor - type 'help' for more information @@ -214,7 +214,7 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Initialization of device ide-hd failed: Block node is read-only +(qemu) QEMU_PROG: Block node is read-only Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on QEMU X.Y.Z monitor - type 'help' for more information From 9bf728a09bf7509b27543664f9cca6f4f337f608 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 Jun 2020 21:21:40 -0700 Subject: [PATCH 1870/2595] target/s390x: Fix SQXBR The output is 128-bit, and thus requires a pair of 64-bit temps. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Buglink: https://bugs.launchpad.net/bugs/1883984 Message-Id: <20200620042140.42070-1-richard.henderson@linaro.org> Signed-off-by: Cornelia Huck --- target/s390x/insn-data.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 91ddaedd84..d79ae9e3f1 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -798,7 +798,7 @@ /* SQUARE ROOT */ F(0xb314, SQEBR, RRE, Z, 0, e2, new, e1, sqeb, 0, IF_BFP) F(0xb315, SQDBR, RRE, Z, 0, f2, new, f1, sqdb, 0, IF_BFP) - F(0xb316, SQXBR, RRE, Z, x2h, x2l, new, x1, sqxb, 0, IF_BFP) + F(0xb316, SQXBR, RRE, Z, x2h, x2l, new_P, x1, sqxb, 0, IF_BFP) F(0xed14, SQEB, RXE, Z, 0, m2_32u, new, e1, sqeb, 0, IF_BFP) F(0xed15, SQDB, RXE, Z, 0, m2_64, new, f1, sqdb, 0, IF_BFP) From 1a8242f7c3f53341dd66253b142ecd06ce1d2a97 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Tue, 16 Jun 2020 06:50:34 +0200 Subject: [PATCH 1871/2595] virtio-ccw: fix virtio_set_ind_atomic The atomic_cmpxchg() loop is broken because we occasionally end up with old and _old having different values (a legit compiler can generate code that accessed *ind_addr again to pick up a value for _old instead of using the value of old that was already fetched according to the rules of the abstract machine). This means the underlying CS instruction may use a different old (_old) than the one we intended to use if atomic_cmpxchg() performed the xchg part. Let us use volatile to force the rules of the abstract machine for accesses to *ind_addr. Let us also rewrite the loop so, we that the new old is used to compute the new desired value if the xchg part is not performed. Fixes: 7e7494627f ("s390x/virtio-ccw: Adapter interrupt support.") Reported-by: Andre Wild Signed-off-by: Halil Pasic Reviewed-by: Christian Borntraeger Message-Id: <20200616045035.51641-2-pasic@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/virtio-ccw.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index c1f4bb1d33..3c988a000b 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -786,9 +786,10 @@ static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d) static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, uint8_t to_be_set) { - uint8_t ind_old, ind_new; + uint8_t expected, actual; hwaddr len = 1; - uint8_t *ind_addr; + /* avoid multiple fetches */ + uint8_t volatile *ind_addr; ind_addr = cpu_physical_memory_map(ind_loc, &len, true); if (!ind_addr) { @@ -796,14 +797,15 @@ static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, __func__, sch->cssid, sch->ssid, sch->schid); return -1; } + actual = *ind_addr; do { - ind_old = *ind_addr; - ind_new = ind_old | to_be_set; - } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old); - trace_virtio_ccw_set_ind(ind_loc, ind_old, ind_new); - cpu_physical_memory_unmap(ind_addr, len, 1, len); + expected = actual; + actual = atomic_cmpxchg(ind_addr, expected, expected | to_be_set); + } while (actual != expected); + trace_virtio_ccw_set_ind(ind_loc, actual, actual | to_be_set); + cpu_physical_memory_unmap((void *)ind_addr, len, 1, len); - return ind_old; + return actual; } static void virtio_ccw_notify(DeviceState *d, uint16_t vector) From 45175361f1bfc2d3ccdcb4b22570c2352f3de754 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Tue, 16 Jun 2020 06:50:35 +0200 Subject: [PATCH 1872/2595] s390x/pci: fix set_ind_atomic The atomic_cmpxchg() loop is broken because we occasionally end up with old and _old having different values (a legit compiler can generate code that accessed *ind_addr again to pick up a value for _old instead of using the value of old that was already fetched according to the rules of the abstract machine). This means the underlying CS instruction may use a different old (_old) than the one we intended to use if atomic_cmpxchg() performed the xchg part. Let us use volatile to force the rules of the abstract machine for accesses to *ind_addr. Let us also rewrite the loop so, we that the new old is used to compute the new desired value if the xchg part is not performed. Fixes: 8cba80c3a0 ("s390: Add PCI bus support") Reported-by: Christian Borntraeger Signed-off-by: Halil Pasic Reviewed-by: Christian Borntraeger Message-Id: <20200616045035.51641-3-pasic@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-bus.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 142e52a8ff..736965c928 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -637,22 +637,24 @@ static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set) { - uint8_t ind_old, ind_new; + uint8_t expected, actual; hwaddr len = 1; - uint8_t *ind_addr; + /* avoid multiple fetches */ + uint8_t volatile *ind_addr; ind_addr = cpu_physical_memory_map(ind_loc, &len, true); if (!ind_addr) { s390_pci_generate_error_event(ERR_EVENT_AIRERR, 0, 0, 0, 0); return -1; } + actual = *ind_addr; do { - ind_old = *ind_addr; - ind_new = ind_old | to_be_set; - } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old); - cpu_physical_memory_unmap(ind_addr, len, 1, len); + expected = actual; + actual = atomic_cmpxchg(ind_addr, expected, expected | to_be_set); + } while (actual != expected); + cpu_physical_memory_unmap((void *)ind_addr, len, 1, len); - return ind_old; + return actual; } static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data, From 910b25766b336a94d69f5f6e1b55c10b3aeb4326 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:37 +0200 Subject: [PATCH 1873/2595] virtio-mem: Paravirtualized memory hot(un)plug This is the very basic/initial version of virtio-mem. An introduction to virtio-mem can be found in the Linux kernel driver [1]. While it can be used in the current state for hotplug of a smaller amount of memory, it will heavily benefit from resizeable memory regions in the future. Each virtio-mem device manages a memory region (provided via a memory backend). After requested by the hypervisor ("requested-size"), the guest can try to plug/unplug blocks of memory within that region, in order to reach the requested size. Initially, and after a reboot, all memory is unplugged (except in special cases - reboot during postcopy). The guest may only try to plug/unplug blocks of memory within the usable region size. The usable region size is a little bigger than the requested size, to give the device driver some flexibility. The usable region size will only grow, except on reboots or when all memory is requested to get unplugged. The guest can never plug more memory than requested. Unplugged memory will get zapped/discarded, similar to in a balloon device. The block size is variable, however, it is always chosen in a way such that THP splits are avoided (e.g., 2MB). The state of each block (plugged/unplugged) is tracked in a bitmap. As virtio-mem devices (e.g., virtio-mem-pci) will be memory devices, we now expose "VirtioMEMDeviceInfo" via "query-memory-devices". -------------------------------------------------------------------------- There are two important follow-up items that are in the works: 1. Resizeable memory regions: Use resizeable allocations/RAM blocks to grow/shrink along with the usable region size. This avoids creating initially very big VMAs, RAM blocks, and KVM slots. 2. Protection of unplugged memory: Make sure the gust cannot actually make use of unplugged memory. Other follow-up items that are in the works: 1. Exclude unplugged memory during migration (via precopy notifier). 2. Handle remapping of memory. 3. Support for other architectures. -------------------------------------------------------------------------- Example usage (virtio-mem-pci is introduced in follow-up patches): Start QEMU with two virtio-mem devices (one per NUMA node): $ qemu-system-x86_64 -m 4G,maxmem=20G \ -smp sockets=2,cores=2 \ -numa node,nodeid=0,cpus=0-1 -numa node,nodeid=1,cpus=2-3 \ [...] -object memory-backend-ram,id=mem0,size=8G \ -device virtio-mem-pci,id=vm0,memdev=mem0,node=0,requested-size=0M \ -object memory-backend-ram,id=mem1,size=8G \ -device virtio-mem-pci,id=vm1,memdev=mem1,node=1,requested-size=1G Query the configuration: (qemu) info memory-devices Memory device [virtio-mem]: "vm0" memaddr: 0x140000000 node: 0 requested-size: 0 size: 0 max-size: 8589934592 block-size: 2097152 memdev: /objects/mem0 Memory device [virtio-mem]: "vm1" memaddr: 0x340000000 node: 1 requested-size: 1073741824 size: 1073741824 max-size: 8589934592 block-size: 2097152 memdev: /objects/mem1 Add some memory to node 0: (qemu) qom-set vm0 requested-size 500M Remove some memory from node 1: (qemu) qom-set vm1 requested-size 200M Query the configuration again: (qemu) info memory-devices Memory device [virtio-mem]: "vm0" memaddr: 0x140000000 node: 0 requested-size: 524288000 size: 524288000 max-size: 8589934592 block-size: 2097152 memdev: /objects/mem0 Memory device [virtio-mem]: "vm1" memaddr: 0x340000000 node: 1 requested-size: 209715200 size: 209715200 max-size: 8589934592 block-size: 2097152 memdev: /objects/mem1 [1] https://lkml.kernel.org/r/20200311171422.10484-1-david@redhat.com Cc: "Michael S. Tsirkin" Cc: Eric Blake Cc: Markus Armbruster Cc: "Dr. David Alan Gilbert" Cc: Igor Mammedov Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-11-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Kconfig | 11 + hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-mem.c | 724 +++++++++++++++++++++++++++++++++ include/hw/virtio/virtio-mem.h | 78 ++++ qapi/misc.json | 39 +- 5 files changed, 852 insertions(+), 1 deletion(-) create mode 100644 hw/virtio/virtio-mem.c create mode 100644 include/hw/virtio/virtio-mem.h diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig index 83122424fa..0eda25c4e1 100644 --- a/hw/virtio/Kconfig +++ b/hw/virtio/Kconfig @@ -47,3 +47,14 @@ config VIRTIO_PMEM depends on VIRTIO depends on VIRTIO_PMEM_SUPPORTED select MEM_DEVICE + +config VIRTIO_MEM_SUPPORTED + bool + +config VIRTIO_MEM + bool + default y + depends on VIRTIO + depends on LINUX + depends on VIRTIO_MEM_SUPPORTED + select MEM_DEVICE diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 13e75f171f..f3a65e01b7 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -19,6 +19,7 @@ obj-$(call land,$(CONFIG_VHOST_USER_FS),$(CONFIG_VIRTIO_PCI)) += vhost-user-fs-p obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-common.o vhost-vsock.o obj-$(CONFIG_VHOST_USER_VSOCK) += vhost-vsock-common.o vhost-user-vsock.o +obj-$(CONFIG_VIRTIO_MEM) += virtio-mem.o ifeq ($(CONFIG_VIRTIO_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c new file mode 100644 index 0000000000..2d6f3061a6 --- /dev/null +++ b/hw/virtio/virtio-mem.c @@ -0,0 +1,724 @@ +/* + * Virtio MEM device + * + * Copyright (C) 2020 Red Hat, Inc. + * + * Authors: + * David Hildenbrand + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/iov.h" +#include "qemu/cutils.h" +#include "qemu/error-report.h" +#include "qemu/units.h" +#include "sysemu/numa.h" +#include "sysemu/sysemu.h" +#include "sysemu/reset.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-access.h" +#include "hw/virtio/virtio-mem.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "exec/ram_addr.h" +#include "migration/misc.h" +#include "hw/boards.h" +#include "hw/qdev-properties.h" +#include "config-devices.h" + +/* + * Use QEMU_VMALLOC_ALIGN, so no THP will have to be split when unplugging + * memory (e.g., 2MB on x86_64). + */ +#define VIRTIO_MEM_MIN_BLOCK_SIZE QEMU_VMALLOC_ALIGN +/* + * Size the usable region bigger than the requested size if possible. Esp. + * Linux guests will only add (aligned) memory blocks in case they fully + * fit into the usable region, but plug+online only a subset of the pages. + * The memory block size corresponds mostly to the section size. + * + * This allows e.g., to add 20MB with a section size of 128MB on x86_64, and + * a section size of 1GB on arm64 (as long as the start address is properly + * aligned, similar to ordinary DIMMs). + * + * We can change this at any time and maybe even make it configurable if + * necessary (as the section size can change). But it's more likely that the + * section size will rather get smaller and not bigger over time. + */ +#if defined(TARGET_X86_64) || defined(TARGET_I386) +#define VIRTIO_MEM_USABLE_EXTENT (2 * (128 * MiB)) +#else +#error VIRTIO_MEM_USABLE_EXTENT not defined +#endif + +static bool virtio_mem_is_busy(void) +{ + /* + * Postcopy cannot handle concurrent discards and we don't want to migrate + * pages on-demand with stale content when plugging new blocks. + */ + return migration_in_incoming_postcopy(); +} + +static bool virtio_mem_test_bitmap(VirtIOMEM *vmem, uint64_t start_gpa, + uint64_t size, bool plugged) +{ + const unsigned long first_bit = (start_gpa - vmem->addr) / vmem->block_size; + const unsigned long last_bit = first_bit + (size / vmem->block_size) - 1; + unsigned long found_bit; + + /* We fake a shorter bitmap to avoid searching too far. */ + if (plugged) { + found_bit = find_next_zero_bit(vmem->bitmap, last_bit + 1, first_bit); + } else { + found_bit = find_next_bit(vmem->bitmap, last_bit + 1, first_bit); + } + return found_bit > last_bit; +} + +static void virtio_mem_set_bitmap(VirtIOMEM *vmem, uint64_t start_gpa, + uint64_t size, bool plugged) +{ + const unsigned long bit = (start_gpa - vmem->addr) / vmem->block_size; + const unsigned long nbits = size / vmem->block_size; + + if (plugged) { + bitmap_set(vmem->bitmap, bit, nbits); + } else { + bitmap_clear(vmem->bitmap, bit, nbits); + } +} + +static void virtio_mem_send_response(VirtIOMEM *vmem, VirtQueueElement *elem, + struct virtio_mem_resp *resp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(vmem); + VirtQueue *vq = vmem->vq; + + iov_from_buf(elem->in_sg, elem->in_num, 0, resp, sizeof(*resp)); + + virtqueue_push(vq, elem, sizeof(*resp)); + virtio_notify(vdev, vq); +} + +static void virtio_mem_send_response_simple(VirtIOMEM *vmem, + VirtQueueElement *elem, + uint16_t type) +{ + struct virtio_mem_resp resp = { + .type = cpu_to_le16(type), + }; + + virtio_mem_send_response(vmem, elem, &resp); +} + +static bool virtio_mem_valid_range(VirtIOMEM *vmem, uint64_t gpa, uint64_t size) +{ + if (!QEMU_IS_ALIGNED(gpa, vmem->block_size)) { + return false; + } + if (gpa + size < gpa || !size) { + return false; + } + if (gpa < vmem->addr || gpa >= vmem->addr + vmem->usable_region_size) { + return false; + } + if (gpa + size > vmem->addr + vmem->usable_region_size) { + return false; + } + return true; +} + +static int virtio_mem_set_block_state(VirtIOMEM *vmem, uint64_t start_gpa, + uint64_t size, bool plug) +{ + const uint64_t offset = start_gpa - vmem->addr; + int ret; + + if (virtio_mem_is_busy()) { + return -EBUSY; + } + + if (!plug) { + ret = ram_block_discard_range(vmem->memdev->mr.ram_block, offset, size); + if (ret) { + error_report("Unexpected error discarding RAM: %s", + strerror(-ret)); + return -EBUSY; + } + } + virtio_mem_set_bitmap(vmem, start_gpa, size, plug); + return 0; +} + +static int virtio_mem_state_change_request(VirtIOMEM *vmem, uint64_t gpa, + uint16_t nb_blocks, bool plug) +{ + const uint64_t size = nb_blocks * vmem->block_size; + int ret; + + if (!virtio_mem_valid_range(vmem, gpa, size)) { + return VIRTIO_MEM_RESP_ERROR; + } + + if (plug && (vmem->size + size > vmem->requested_size)) { + return VIRTIO_MEM_RESP_NACK; + } + + /* test if really all blocks are in the opposite state */ + if (!virtio_mem_test_bitmap(vmem, gpa, size, !plug)) { + return VIRTIO_MEM_RESP_ERROR; + } + + ret = virtio_mem_set_block_state(vmem, gpa, size, plug); + if (ret) { + return VIRTIO_MEM_RESP_BUSY; + } + if (plug) { + vmem->size += size; + } else { + vmem->size -= size; + } + return VIRTIO_MEM_RESP_ACK; +} + +static void virtio_mem_plug_request(VirtIOMEM *vmem, VirtQueueElement *elem, + struct virtio_mem_req *req) +{ + const uint64_t gpa = le64_to_cpu(req->u.plug.addr); + const uint16_t nb_blocks = le16_to_cpu(req->u.plug.nb_blocks); + uint16_t type; + + type = virtio_mem_state_change_request(vmem, gpa, nb_blocks, true); + virtio_mem_send_response_simple(vmem, elem, type); +} + +static void virtio_mem_unplug_request(VirtIOMEM *vmem, VirtQueueElement *elem, + struct virtio_mem_req *req) +{ + const uint64_t gpa = le64_to_cpu(req->u.unplug.addr); + const uint16_t nb_blocks = le16_to_cpu(req->u.unplug.nb_blocks); + uint16_t type; + + type = virtio_mem_state_change_request(vmem, gpa, nb_blocks, false); + virtio_mem_send_response_simple(vmem, elem, type); +} + +static void virtio_mem_resize_usable_region(VirtIOMEM *vmem, + uint64_t requested_size, + bool can_shrink) +{ + uint64_t newsize = MIN(memory_region_size(&vmem->memdev->mr), + requested_size + VIRTIO_MEM_USABLE_EXTENT); + + if (!requested_size) { + newsize = 0; + } + + if (newsize < vmem->usable_region_size && !can_shrink) { + return; + } + + vmem->usable_region_size = newsize; +} + +static int virtio_mem_unplug_all(VirtIOMEM *vmem) +{ + RAMBlock *rb = vmem->memdev->mr.ram_block; + int ret; + + if (virtio_mem_is_busy()) { + return -EBUSY; + } + + ret = ram_block_discard_range(rb, 0, qemu_ram_get_used_length(rb)); + if (ret) { + error_report("Unexpected error discarding RAM: %s", strerror(-ret)); + return -EBUSY; + } + bitmap_clear(vmem->bitmap, 0, vmem->bitmap_size); + vmem->size = 0; + + virtio_mem_resize_usable_region(vmem, vmem->requested_size, true); + return 0; +} + +static void virtio_mem_unplug_all_request(VirtIOMEM *vmem, + VirtQueueElement *elem) +{ + if (virtio_mem_unplug_all(vmem)) { + virtio_mem_send_response_simple(vmem, elem, VIRTIO_MEM_RESP_BUSY); + } else { + virtio_mem_send_response_simple(vmem, elem, VIRTIO_MEM_RESP_ACK); + } +} + +static void virtio_mem_state_request(VirtIOMEM *vmem, VirtQueueElement *elem, + struct virtio_mem_req *req) +{ + const uint16_t nb_blocks = le16_to_cpu(req->u.state.nb_blocks); + const uint64_t gpa = le64_to_cpu(req->u.state.addr); + const uint64_t size = nb_blocks * vmem->block_size; + struct virtio_mem_resp resp = { + .type = cpu_to_le16(VIRTIO_MEM_RESP_ACK), + }; + + if (!virtio_mem_valid_range(vmem, gpa, size)) { + virtio_mem_send_response_simple(vmem, elem, VIRTIO_MEM_RESP_ERROR); + return; + } + + if (virtio_mem_test_bitmap(vmem, gpa, size, true)) { + resp.u.state.state = cpu_to_le16(VIRTIO_MEM_STATE_PLUGGED); + } else if (virtio_mem_test_bitmap(vmem, gpa, size, false)) { + resp.u.state.state = cpu_to_le16(VIRTIO_MEM_STATE_UNPLUGGED); + } else { + resp.u.state.state = cpu_to_le16(VIRTIO_MEM_STATE_MIXED); + } + virtio_mem_send_response(vmem, elem, &resp); +} + +static void virtio_mem_handle_request(VirtIODevice *vdev, VirtQueue *vq) +{ + const int len = sizeof(struct virtio_mem_req); + VirtIOMEM *vmem = VIRTIO_MEM(vdev); + VirtQueueElement *elem; + struct virtio_mem_req req; + uint16_t type; + + while (true) { + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + return; + } + + if (iov_to_buf(elem->out_sg, elem->out_num, 0, &req, len) < len) { + virtio_error(vdev, "virtio-mem protocol violation: invalid request" + " size: %d", len); + g_free(elem); + return; + } + + if (iov_size(elem->in_sg, elem->in_num) < + sizeof(struct virtio_mem_resp)) { + virtio_error(vdev, "virtio-mem protocol violation: not enough space" + " for response: %zu", + iov_size(elem->in_sg, elem->in_num)); + g_free(elem); + return; + } + + type = le16_to_cpu(req.type); + switch (type) { + case VIRTIO_MEM_REQ_PLUG: + virtio_mem_plug_request(vmem, elem, &req); + break; + case VIRTIO_MEM_REQ_UNPLUG: + virtio_mem_unplug_request(vmem, elem, &req); + break; + case VIRTIO_MEM_REQ_UNPLUG_ALL: + virtio_mem_unplug_all_request(vmem, elem); + break; + case VIRTIO_MEM_REQ_STATE: + virtio_mem_state_request(vmem, elem, &req); + break; + default: + virtio_error(vdev, "virtio-mem protocol violation: unknown request" + " type: %d", type); + g_free(elem); + return; + } + + g_free(elem); + } +} + +static void virtio_mem_get_config(VirtIODevice *vdev, uint8_t *config_data) +{ + VirtIOMEM *vmem = VIRTIO_MEM(vdev); + struct virtio_mem_config *config = (void *) config_data; + + config->block_size = cpu_to_le64(vmem->block_size); + config->node_id = cpu_to_le16(vmem->node); + config->requested_size = cpu_to_le64(vmem->requested_size); + config->plugged_size = cpu_to_le64(vmem->size); + config->addr = cpu_to_le64(vmem->addr); + config->region_size = cpu_to_le64(memory_region_size(&vmem->memdev->mr)); + config->usable_region_size = cpu_to_le64(vmem->usable_region_size); +} + +static uint64_t virtio_mem_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + + if (ms->numa_state) { +#if defined(CONFIG_ACPI) + virtio_add_feature(&features, VIRTIO_MEM_F_ACPI_PXM); +#endif + } + return features; +} + +static void virtio_mem_system_reset(void *opaque) +{ + VirtIOMEM *vmem = VIRTIO_MEM(opaque); + + /* + * During usual resets, we will unplug all memory and shrink the usable + * region size. This is, however, not possible in all scenarios. Then, + * the guest has to deal with this manually (VIRTIO_MEM_REQ_UNPLUG_ALL). + */ + virtio_mem_unplug_all(vmem); +} + +static void virtio_mem_device_realize(DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + int nb_numa_nodes = ms->numa_state ? ms->numa_state->num_nodes : 0; + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOMEM *vmem = VIRTIO_MEM(dev); + uint64_t page_size; + RAMBlock *rb; + int ret; + + if (!vmem->memdev) { + error_setg(errp, "'%s' property is not set", VIRTIO_MEM_MEMDEV_PROP); + return; + } else if (host_memory_backend_is_mapped(vmem->memdev)) { + char *path = object_get_canonical_path_component(OBJECT(vmem->memdev)); + + error_setg(errp, "'%s' property specifies a busy memdev: %s", + VIRTIO_MEM_MEMDEV_PROP, path); + g_free(path); + return; + } else if (!memory_region_is_ram(&vmem->memdev->mr) || + memory_region_is_rom(&vmem->memdev->mr) || + !vmem->memdev->mr.ram_block) { + error_setg(errp, "'%s' property specifies an unsupported memdev", + VIRTIO_MEM_MEMDEV_PROP); + return; + } + + if ((nb_numa_nodes && vmem->node >= nb_numa_nodes) || + (!nb_numa_nodes && vmem->node)) { + error_setg(errp, "'%s' property has value '%" PRIu32 "', which exceeds" + "the number of numa nodes: %d", VIRTIO_MEM_NODE_PROP, + vmem->node, nb_numa_nodes ? nb_numa_nodes : 1); + return; + } + + if (enable_mlock) { + error_setg(errp, "Incompatible with mlock"); + return; + } + + rb = vmem->memdev->mr.ram_block; + page_size = qemu_ram_pagesize(rb); + + if (vmem->block_size < page_size) { + error_setg(errp, "'%s' property has to be at least the page size (0x%" + PRIx64 ")", VIRTIO_MEM_BLOCK_SIZE_PROP, page_size); + return; + } else if (!QEMU_IS_ALIGNED(vmem->requested_size, vmem->block_size)) { + error_setg(errp, "'%s' property has to be multiples of '%s' (0x%" PRIx64 + ")", VIRTIO_MEM_REQUESTED_SIZE_PROP, + VIRTIO_MEM_BLOCK_SIZE_PROP, vmem->block_size); + return; + } else if (!QEMU_IS_ALIGNED(memory_region_size(&vmem->memdev->mr), + vmem->block_size)) { + error_setg(errp, "'%s' property memdev size has to be multiples of" + "'%s' (0x%" PRIx64 ")", VIRTIO_MEM_MEMDEV_PROP, + VIRTIO_MEM_BLOCK_SIZE_PROP, vmem->block_size); + return; + } + + if (ram_block_discard_require(true)) { + error_setg(errp, "Discarding RAM is disabled"); + return; + } + + ret = ram_block_discard_range(rb, 0, qemu_ram_get_used_length(rb)); + if (ret) { + error_setg_errno(errp, -ret, "Unexpected error discarding RAM"); + ram_block_discard_require(false); + return; + } + + virtio_mem_resize_usable_region(vmem, vmem->requested_size, true); + + vmem->bitmap_size = memory_region_size(&vmem->memdev->mr) / + vmem->block_size; + vmem->bitmap = bitmap_new(vmem->bitmap_size); + + virtio_init(vdev, TYPE_VIRTIO_MEM, VIRTIO_ID_MEM, + sizeof(struct virtio_mem_config)); + vmem->vq = virtio_add_queue(vdev, 128, virtio_mem_handle_request); + + host_memory_backend_set_mapped(vmem->memdev, true); + vmstate_register_ram(&vmem->memdev->mr, DEVICE(vmem)); + qemu_register_reset(virtio_mem_system_reset, vmem); +} + +static void virtio_mem_device_unrealize(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOMEM *vmem = VIRTIO_MEM(dev); + + qemu_unregister_reset(virtio_mem_system_reset, vmem); + vmstate_unregister_ram(&vmem->memdev->mr, DEVICE(vmem)); + host_memory_backend_set_mapped(vmem->memdev, false); + virtio_del_queue(vdev, 0); + virtio_cleanup(vdev); + g_free(vmem->bitmap); + ram_block_discard_require(false); +} + +static int virtio_mem_restore_unplugged(VirtIOMEM *vmem) +{ + RAMBlock *rb = vmem->memdev->mr.ram_block; + unsigned long first_zero_bit, last_zero_bit; + uint64_t offset, length; + int ret; + + /* Find consecutive unplugged blocks and discard the consecutive range. */ + first_zero_bit = find_first_zero_bit(vmem->bitmap, vmem->bitmap_size); + while (first_zero_bit < vmem->bitmap_size) { + offset = first_zero_bit * vmem->block_size; + last_zero_bit = find_next_bit(vmem->bitmap, vmem->bitmap_size, + first_zero_bit + 1) - 1; + length = (last_zero_bit - first_zero_bit + 1) * vmem->block_size; + + ret = ram_block_discard_range(rb, offset, length); + if (ret) { + error_report("Unexpected error discarding RAM: %s", + strerror(-ret)); + return -EINVAL; + } + first_zero_bit = find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, + last_zero_bit + 2); + } + return 0; +} + +static int virtio_mem_post_load(void *opaque, int version_id) +{ + if (migration_in_incoming_postcopy()) { + return 0; + } + + return virtio_mem_restore_unplugged(VIRTIO_MEM(opaque)); +} + +static const VMStateDescription vmstate_virtio_mem_device = { + .name = "virtio-mem-device", + .minimum_version_id = 1, + .version_id = 1, + .post_load = virtio_mem_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT64(usable_region_size, VirtIOMEM), + VMSTATE_UINT64(size, VirtIOMEM), + VMSTATE_UINT64(requested_size, VirtIOMEM), + VMSTATE_BITMAP(bitmap, VirtIOMEM, 0, bitmap_size), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_virtio_mem = { + .name = "virtio-mem", + .minimum_version_id = 1, + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, +}; + +static void virtio_mem_fill_device_info(const VirtIOMEM *vmem, + VirtioMEMDeviceInfo *vi) +{ + vi->memaddr = vmem->addr; + vi->node = vmem->node; + vi->requested_size = vmem->requested_size; + vi->size = vmem->size; + vi->max_size = memory_region_size(&vmem->memdev->mr); + vi->block_size = vmem->block_size; + vi->memdev = object_get_canonical_path(OBJECT(vmem->memdev)); +} + +static MemoryRegion *virtio_mem_get_memory_region(VirtIOMEM *vmem, Error **errp) +{ + if (!vmem->memdev) { + error_setg(errp, "'%s' property must be set", VIRTIO_MEM_MEMDEV_PROP); + return NULL; + } + + return &vmem->memdev->mr; +} + +static void virtio_mem_get_size(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + const VirtIOMEM *vmem = VIRTIO_MEM(obj); + uint64_t value = vmem->size; + + visit_type_size(v, name, &value, errp); +} + +static void virtio_mem_get_requested_size(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + const VirtIOMEM *vmem = VIRTIO_MEM(obj); + uint64_t value = vmem->requested_size; + + visit_type_size(v, name, &value, errp); +} + +static void virtio_mem_set_requested_size(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + VirtIOMEM *vmem = VIRTIO_MEM(obj); + Error *err = NULL; + uint64_t value; + + visit_type_size(v, name, &value, &err); + if (err) { + error_propagate(errp, err); + return; + } + + /* + * The block size and memory backend are not fixed until the device was + * realized. realize() will verify these properties then. + */ + if (DEVICE(obj)->realized) { + if (!QEMU_IS_ALIGNED(value, vmem->block_size)) { + error_setg(errp, "'%s' has to be multiples of '%s' (0x%" PRIx64 + ")", name, VIRTIO_MEM_BLOCK_SIZE_PROP, + vmem->block_size); + return; + } else if (value > memory_region_size(&vmem->memdev->mr)) { + error_setg(errp, "'%s' cannot exceed the memory backend size" + "(0x%" PRIx64 ")", name, + memory_region_size(&vmem->memdev->mr)); + return; + } + + if (value != vmem->requested_size) { + virtio_mem_resize_usable_region(vmem, value, false); + vmem->requested_size = value; + } + /* + * Trigger a config update so the guest gets notified. We trigger + * even if the size didn't change (especially helpful for debugging). + */ + virtio_notify_config(VIRTIO_DEVICE(vmem)); + } else { + vmem->requested_size = value; + } +} + +static void virtio_mem_get_block_size(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + const VirtIOMEM *vmem = VIRTIO_MEM(obj); + uint64_t value = vmem->block_size; + + visit_type_size(v, name, &value, errp); +} + +static void virtio_mem_set_block_size(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + VirtIOMEM *vmem = VIRTIO_MEM(obj); + Error *err = NULL; + uint64_t value; + + if (DEVICE(obj)->realized) { + error_setg(errp, "'%s' cannot be changed", name); + return; + } + + visit_type_size(v, name, &value, &err); + if (err) { + error_propagate(errp, err); + return; + } + + if (value < VIRTIO_MEM_MIN_BLOCK_SIZE) { + error_setg(errp, "'%s' property has to be at least 0x%" PRIx32, name, + VIRTIO_MEM_MIN_BLOCK_SIZE); + return; + } else if (!is_power_of_2(value)) { + error_setg(errp, "'%s' property has to be a power of two", name); + return; + } + vmem->block_size = value; +} + +static void virtio_mem_instance_init(Object *obj) +{ + VirtIOMEM *vmem = VIRTIO_MEM(obj); + + vmem->block_size = VIRTIO_MEM_MIN_BLOCK_SIZE; + + object_property_add(obj, VIRTIO_MEM_SIZE_PROP, "size", virtio_mem_get_size, + NULL, NULL, NULL); + object_property_add(obj, VIRTIO_MEM_REQUESTED_SIZE_PROP, "size", + virtio_mem_get_requested_size, + virtio_mem_set_requested_size, NULL, NULL); + object_property_add(obj, VIRTIO_MEM_BLOCK_SIZE_PROP, "size", + virtio_mem_get_block_size, virtio_mem_set_block_size, + NULL, NULL); +} + +static Property virtio_mem_properties[] = { + DEFINE_PROP_UINT64(VIRTIO_MEM_ADDR_PROP, VirtIOMEM, addr, 0), + DEFINE_PROP_UINT32(VIRTIO_MEM_NODE_PROP, VirtIOMEM, node, 0), + DEFINE_PROP_LINK(VIRTIO_MEM_MEMDEV_PROP, VirtIOMEM, memdev, + TYPE_MEMORY_BACKEND, HostMemoryBackend *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_mem_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + VirtIOMEMClass *vmc = VIRTIO_MEM_CLASS(klass); + + device_class_set_props(dc, virtio_mem_properties); + dc->vmsd = &vmstate_virtio_mem; + + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + vdc->realize = virtio_mem_device_realize; + vdc->unrealize = virtio_mem_device_unrealize; + vdc->get_config = virtio_mem_get_config; + vdc->get_features = virtio_mem_get_features; + vdc->vmsd = &vmstate_virtio_mem_device; + + vmc->fill_device_info = virtio_mem_fill_device_info; + vmc->get_memory_region = virtio_mem_get_memory_region; +} + +static const TypeInfo virtio_mem_info = { + .name = TYPE_VIRTIO_MEM, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VirtIOMEM), + .instance_init = virtio_mem_instance_init, + .class_init = virtio_mem_class_init, + .class_size = sizeof(VirtIOMEMClass), +}; + +static void virtio_register_types(void) +{ + type_register_static(&virtio_mem_info); +} + +type_init(virtio_register_types) diff --git a/include/hw/virtio/virtio-mem.h b/include/hw/virtio/virtio-mem.h new file mode 100644 index 0000000000..6981096f7c --- /dev/null +++ b/include/hw/virtio/virtio-mem.h @@ -0,0 +1,78 @@ +/* + * Virtio MEM device + * + * Copyright (C) 2020 Red Hat, Inc. + * + * Authors: + * David Hildenbrand + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_VIRTIO_MEM_H +#define HW_VIRTIO_MEM_H + +#include "standard-headers/linux/virtio_mem.h" +#include "hw/virtio/virtio.h" +#include "qapi/qapi-types-misc.h" +#include "sysemu/hostmem.h" + +#define TYPE_VIRTIO_MEM "virtio-mem" + +#define VIRTIO_MEM(obj) \ + OBJECT_CHECK(VirtIOMEM, (obj), TYPE_VIRTIO_MEM) +#define VIRTIO_MEM_CLASS(oc) \ + OBJECT_CLASS_CHECK(VirtIOMEMClass, (oc), TYPE_VIRTIO_MEM) +#define VIRTIO_MEM_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtIOMEMClass, (obj), TYPE_VIRTIO_MEM) + +#define VIRTIO_MEM_MEMDEV_PROP "memdev" +#define VIRTIO_MEM_NODE_PROP "node" +#define VIRTIO_MEM_SIZE_PROP "size" +#define VIRTIO_MEM_REQUESTED_SIZE_PROP "requested-size" +#define VIRTIO_MEM_BLOCK_SIZE_PROP "block-size" +#define VIRTIO_MEM_ADDR_PROP "memaddr" + +typedef struct VirtIOMEM { + VirtIODevice parent_obj; + + /* guest -> host request queue */ + VirtQueue *vq; + + /* bitmap used to track unplugged memory */ + int32_t bitmap_size; + unsigned long *bitmap; + + /* assigned memory backend and memory region */ + HostMemoryBackend *memdev; + + /* NUMA node */ + uint32_t node; + + /* assigned address of the region in guest physical memory */ + uint64_t addr; + + /* usable region size (<= region_size) */ + uint64_t usable_region_size; + + /* actual size (how much the guest plugged) */ + uint64_t size; + + /* requested size */ + uint64_t requested_size; + + /* block size and alignment */ + uint64_t block_size; +} VirtIOMEM; + +typedef struct VirtIOMEMClass { + /* private */ + VirtIODevice parent; + + /* public */ + void (*fill_device_info)(const VirtIOMEM *vmen, VirtioMEMDeviceInfo *vi); + MemoryRegion *(*get_memory_region)(VirtIOMEM *vmem, Error **errp); +} VirtIOMEMClass; + +#endif diff --git a/qapi/misc.json b/qapi/misc.json index a5a0beb902..65ca3edf32 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -1356,19 +1356,56 @@ } } +## +# @VirtioMEMDeviceInfo: +# +# VirtioMEMDevice state information +# +# @id: device's ID +# +# @memaddr: physical address in memory, where device is mapped +# +# @requested-size: the user requested size of the device +# +# @size: the (current) size of memory that the device provides +# +# @max-size: the maximum size of memory that the device can provide +# +# @block-size: the block size of memory that the device provides +# +# @node: NUMA node number where device is assigned to +# +# @memdev: memory backend linked with the region +# +# Since: 5.1 +## +{ 'struct': 'VirtioMEMDeviceInfo', + 'data': { '*id': 'str', + 'memaddr': 'size', + 'requested-size': 'size', + 'size': 'size', + 'max-size': 'size', + 'block-size': 'size', + 'node': 'int', + 'memdev': 'str' + } +} + ## # @MemoryDeviceInfo: # # Union containing information about a memory device # # nvdimm is included since 2.12. virtio-pmem is included since 4.1. +# virtio-mem is included since 5.1. # # Since: 2.1 ## { 'union': 'MemoryDeviceInfo', 'data': { 'dimm': 'PCDIMMDeviceInfo', 'nvdimm': 'PCDIMMDeviceInfo', - 'virtio-pmem': 'VirtioPMEMDeviceInfo' + 'virtio-pmem': 'VirtioPMEMDeviceInfo', + 'virtio-mem': 'VirtioMEMDeviceInfo' } } From 0b9a2443a48b806c775b47c4a1e9effdab03ddf2 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:38 +0200 Subject: [PATCH 1874/2595] virtio-pci: Proxy for virtio-mem Let's add a proxy for virtio-mem, make it a memory device, and pass-through the properties. Reviewed-by: Pankaj Gupta Cc: "Michael S. Tsirkin" Cc: Marcel Apfelbaum Cc: "Dr. David Alan Gilbert" Cc: Igor Mammedov Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-12-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-mem-pci.c | 129 +++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-mem-pci.h | 33 ++++++++++ include/hw/pci/pci.h | 1 + 4 files changed, 164 insertions(+) create mode 100644 hw/virtio/virtio-mem-pci.c create mode 100644 hw/virtio/virtio-mem-pci.h diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index f3a65e01b7..a986708186 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -20,6 +20,7 @@ obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-common.o vhost-vsock.o obj-$(CONFIG_VHOST_USER_VSOCK) += vhost-vsock-common.o vhost-user-vsock.o obj-$(CONFIG_VIRTIO_MEM) += virtio-mem.o +common-obj-$(call land,$(CONFIG_VIRTIO_MEM),$(CONFIG_VIRTIO_PCI)) += virtio-mem-pci.o ifeq ($(CONFIG_VIRTIO_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o diff --git a/hw/virtio/virtio-mem-pci.c b/hw/virtio/virtio-mem-pci.c new file mode 100644 index 0000000000..b325303b32 --- /dev/null +++ b/hw/virtio/virtio-mem-pci.c @@ -0,0 +1,129 @@ +/* + * Virtio MEM PCI device + * + * Copyright (C) 2020 Red Hat, Inc. + * + * Authors: + * David Hildenbrand + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "virtio-mem-pci.h" +#include "hw/mem/memory-device.h" +#include "qapi/error.h" + +static void virtio_mem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOMEMPCI *mem_pci = VIRTIO_MEM_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&mem_pci->vdev); + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_mem_pci_set_addr(MemoryDeviceState *md, uint64_t addr, + Error **errp) +{ + object_property_set_uint(OBJECT(md), addr, VIRTIO_MEM_ADDR_PROP, errp); +} + +static uint64_t virtio_mem_pci_get_addr(const MemoryDeviceState *md) +{ + return object_property_get_uint(OBJECT(md), VIRTIO_MEM_ADDR_PROP, + &error_abort); +} + +static MemoryRegion *virtio_mem_pci_get_memory_region(MemoryDeviceState *md, + Error **errp) +{ + VirtIOMEMPCI *pci_mem = VIRTIO_MEM_PCI(md); + VirtIOMEM *vmem = VIRTIO_MEM(&pci_mem->vdev); + VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem); + + return vmc->get_memory_region(vmem, errp); +} + +static uint64_t virtio_mem_pci_get_plugged_size(const MemoryDeviceState *md, + Error **errp) +{ + return object_property_get_uint(OBJECT(md), VIRTIO_MEM_SIZE_PROP, + errp); +} + +static void virtio_mem_pci_fill_device_info(const MemoryDeviceState *md, + MemoryDeviceInfo *info) +{ + VirtioMEMDeviceInfo *vi = g_new0(VirtioMEMDeviceInfo, 1); + VirtIOMEMPCI *pci_mem = VIRTIO_MEM_PCI(md); + VirtIOMEM *vmem = VIRTIO_MEM(&pci_mem->vdev); + VirtIOMEMClass *vpc = VIRTIO_MEM_GET_CLASS(vmem); + DeviceState *dev = DEVICE(md); + + if (dev->id) { + vi->has_id = true; + vi->id = g_strdup(dev->id); + } + + /* let the real device handle everything else */ + vpc->fill_device_info(vmem, vi); + + info->u.virtio_mem.data = vi; + info->type = MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM; +} + +static void virtio_mem_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(klass); + + k->realize = virtio_mem_pci_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_MEM; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_OTHERS; + + mdc->get_addr = virtio_mem_pci_get_addr; + mdc->set_addr = virtio_mem_pci_set_addr; + mdc->get_plugged_size = virtio_mem_pci_get_plugged_size; + mdc->get_memory_region = virtio_mem_pci_get_memory_region; + mdc->fill_device_info = virtio_mem_pci_fill_device_info; +} + +static void virtio_mem_pci_instance_init(Object *obj) +{ + VirtIOMEMPCI *dev = VIRTIO_MEM_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_MEM); + object_property_add_alias(obj, VIRTIO_MEM_BLOCK_SIZE_PROP, + OBJECT(&dev->vdev), VIRTIO_MEM_BLOCK_SIZE_PROP); + object_property_add_alias(obj, VIRTIO_MEM_SIZE_PROP, OBJECT(&dev->vdev), + VIRTIO_MEM_SIZE_PROP); + object_property_add_alias(obj, VIRTIO_MEM_REQUESTED_SIZE_PROP, + OBJECT(&dev->vdev), + VIRTIO_MEM_REQUESTED_SIZE_PROP); +} + +static const VirtioPCIDeviceTypeInfo virtio_mem_pci_info = { + .base_name = TYPE_VIRTIO_MEM_PCI, + .generic_name = "virtio-mem-pci", + .instance_size = sizeof(VirtIOMEMPCI), + .instance_init = virtio_mem_pci_instance_init, + .class_init = virtio_mem_pci_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_MEMORY_DEVICE }, + { } + }, +}; + +static void virtio_mem_pci_register_types(void) +{ + virtio_pci_types_register(&virtio_mem_pci_info); +} +type_init(virtio_mem_pci_register_types) diff --git a/hw/virtio/virtio-mem-pci.h b/hw/virtio/virtio-mem-pci.h new file mode 100644 index 0000000000..8820cd6628 --- /dev/null +++ b/hw/virtio/virtio-mem-pci.h @@ -0,0 +1,33 @@ +/* + * Virtio MEM PCI device + * + * Copyright (C) 2020 Red Hat, Inc. + * + * Authors: + * David Hildenbrand + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_VIRTIO_MEM_PCI_H +#define QEMU_VIRTIO_MEM_PCI_H + +#include "hw/virtio/virtio-pci.h" +#include "hw/virtio/virtio-mem.h" + +typedef struct VirtIOMEMPCI VirtIOMEMPCI; + +/* + * virtio-mem-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_MEM_PCI "virtio-mem-pci-base" +#define VIRTIO_MEM_PCI(obj) \ + OBJECT_CHECK(VirtIOMEMPCI, (obj), TYPE_VIRTIO_MEM_PCI) + +struct VirtIOMEMPCI { + VirtIOPCIProxy parent_obj; + VirtIOMEM vdev; +}; + +#endif /* QEMU_VIRTIO_MEM_PCI_H */ diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index a4e9c33416..c1bf7d5356 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -87,6 +87,7 @@ extern bool pci_available; #define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012 #define PCI_DEVICE_ID_VIRTIO_PMEM 0x1013 #define PCI_DEVICE_ID_VIRTIO_IOMMU 0x1014 +#define PCI_DEVICE_ID_VIRTIO_MEM 0x1015 #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 From 751c7bdd0422decea9b18c1dc61da907242e48d9 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:39 +0200 Subject: [PATCH 1875/2595] MAINTAINERS: Add myself as virtio-mem maintainer Let's make sure patches/bug reports find the right person. Reviewed-by: Dr. David Alan Gilbert Cc: "Michael S. Tsirkin" Cc: Peter Maydell Cc: Markus Armbruster Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-13-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index dec252f38b..5f02160436 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1790,6 +1790,15 @@ F: hw/virtio/virtio-crypto.c F: hw/virtio/virtio-crypto-pci.c F: include/hw/virtio/virtio-crypto.h +virtio-mem +M: David Hildenbrand +S: Supported +W: https://virtio-mem.gitlab.io/ +F: hw/virtio/virtio-mem.c +F: hw/virtio/virtio-mem-pci.h +F: hw/virtio/virtio-mem-pci.c +F: include/hw/virtio/virtio-mem.h + nvme M: Keith Busch L: qemu-block@nongnu.org From 2e70874b16ac1d228b7f88a9e45209a5f4265841 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:40 +0200 Subject: [PATCH 1876/2595] hmp: Handle virtio-mem when printing memory device info Print the memory device info just like for other memory devices. Reviewed-by: Dr. David Alan Gilbert Cc: "Dr. David Alan Gilbert" Cc: "Michael S. Tsirkin" Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-14-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- monitor/hmp-cmds.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 2b0b58a336..2ec13e4cc3 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -1821,6 +1821,7 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict) MemoryDeviceInfoList *info_list = qmp_query_memory_devices(&err); MemoryDeviceInfoList *info; VirtioPMEMDeviceInfo *vpi; + VirtioMEMDeviceInfo *vmi; MemoryDeviceInfo *value; PCDIMMDeviceInfo *di; @@ -1855,6 +1856,21 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict) monitor_printf(mon, " size: %" PRIu64 "\n", vpi->size); monitor_printf(mon, " memdev: %s\n", vpi->memdev); break; + case MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM: + vmi = value->u.virtio_mem.data; + monitor_printf(mon, "Memory device [%s]: \"%s\"\n", + MemoryDeviceInfoKind_str(value->type), + vmi->id ? vmi->id : ""); + monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", vmi->memaddr); + monitor_printf(mon, " node: %" PRId64 "\n", vmi->node); + monitor_printf(mon, " requested-size: %" PRIu64 "\n", + vmi->requested_size); + monitor_printf(mon, " size: %" PRIu64 "\n", vmi->size); + monitor_printf(mon, " max-size: %" PRIu64 "\n", vmi->max_size); + monitor_printf(mon, " block-size: %" PRIu64 "\n", + vmi->block_size); + monitor_printf(mon, " memdev: %s\n", vmi->memdev); + break; default: g_assert_not_reached(); } From 16647a82241fa6fb3cd4f8928c5cbf8b93a11671 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:41 +0200 Subject: [PATCH 1877/2595] numa: Handle virtio-mem in NUMA stats Account the memory to the configured nid. Reviewed-by: Pankaj Gupta Cc: Eduardo Habkost Cc: Marcel Apfelbaum Cc: "Michael S. Tsirkin" Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-15-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/numa.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/core/numa.c b/hw/core/numa.c index 2725886d06..e9aec69afd 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -824,6 +824,7 @@ static void numa_stat_memory_devices(NumaNodeMem node_mem[]) MemoryDeviceInfoList *info; PCDIMMDeviceInfo *pcdimm_info; VirtioPMEMDeviceInfo *vpi; + VirtioMEMDeviceInfo *vmi; for (info = info_list; info; info = info->next) { MemoryDeviceInfo *value = info->value; @@ -844,6 +845,11 @@ static void numa_stat_memory_devices(NumaNodeMem node_mem[]) node_mem[0].node_mem += vpi->size; node_mem[0].node_plugged_mem += vpi->size; break; + case MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM: + vmi = value->u.virtio_mem.data; + node_mem[vmi->node].node_mem += vmi->size; + node_mem[vmi->node].node_plugged_mem += vmi->size; + break; default: g_assert_not_reached(); } From 0ed48fd32eb8dbe0113d82b6316c0ee4741cc0b0 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:42 +0200 Subject: [PATCH 1878/2595] pc: Support for virtio-mem-pci Let's wire it up similar to virtio-pmem. Also disallow unplug, so it's harder for users to shoot themselves into the foot. Reviewed-by: Pankaj Gupta Cc: "Michael S. Tsirkin" Cc: Marcel Apfelbaum Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Cc: Eric Blake Cc: Markus Armbruster Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-16-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/Kconfig | 1 + hw/i386/pc.c | 49 ++++++++++++++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index c93f32f657..03e347b207 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -35,6 +35,7 @@ config PC select ACPI_PCI select ACPI_VMGENID select VIRTIO_PMEM_SUPPORTED + select VIRTIO_MEM_SUPPORTED config PC_PCI bool diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 58b1425c17..576f2502f9 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -88,6 +88,7 @@ #include "hw/net/ne2000-isa.h" #include "standard-headers/asm-x86/bootparam.h" #include "hw/virtio/virtio-pmem-pci.h" +#include "hw/virtio/virtio-mem-pci.h" #include "hw/mem/memory-device.h" #include "sysemu/replay.h" #include "qapi/qmp/qerror.h" @@ -1637,8 +1638,8 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev, numa_cpu_pre_plug(cpu_slot, dev, errp); } -static void pc_virtio_pmem_pci_pre_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) +static void pc_virtio_md_pci_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) { HotplugHandler *hotplug_dev2 = qdev_get_bus_hotplug_handler(dev); Error *local_err = NULL; @@ -1649,7 +1650,8 @@ static void pc_virtio_pmem_pci_pre_plug(HotplugHandler *hotplug_dev, * order. We should never reach this point when hotplugging on x86, * however, better add a safety net. */ - error_setg(errp, "virtio-pmem-pci hotplug not supported on this bus."); + error_setg(errp, "hotplug of virtio based memory devices not supported" + " on this bus."); return; } /* @@ -1664,8 +1666,8 @@ static void pc_virtio_pmem_pci_pre_plug(HotplugHandler *hotplug_dev, error_propagate(errp, local_err); } -static void pc_virtio_pmem_pci_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) +static void pc_virtio_md_pci_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) { HotplugHandler *hotplug_dev2 = qdev_get_bus_hotplug_handler(dev); Error *local_err = NULL; @@ -1685,17 +1687,17 @@ static void pc_virtio_pmem_pci_plug(HotplugHandler *hotplug_dev, error_propagate(errp, local_err); } -static void pc_virtio_pmem_pci_unplug_request(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) +static void pc_virtio_md_pci_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) { - /* We don't support virtio pmem hot unplug */ - error_setg(errp, "virtio pmem device unplug not supported."); + /* We don't support hot unplug of virtio based memory devices */ + error_setg(errp, "virtio based memory devices cannot be unplugged."); } -static void pc_virtio_pmem_pci_unplug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) +static void pc_virtio_md_pci_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) { - /* We don't support virtio pmem hot unplug */ + /* We don't support hot unplug of virtio based memory devices */ } static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, @@ -1705,8 +1707,9 @@ static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, pc_memory_pre_plug(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { pc_cpu_pre_plug(hotplug_dev, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) { - pc_virtio_pmem_pci_pre_plug(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) || + object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) { + pc_virtio_md_pci_pre_plug(hotplug_dev, dev, errp); } } @@ -1717,8 +1720,9 @@ static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev, pc_memory_plug(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { pc_cpu_plug(hotplug_dev, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) { - pc_virtio_pmem_pci_plug(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) || + object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) { + pc_virtio_md_pci_plug(hotplug_dev, dev, errp); } } @@ -1729,8 +1733,9 @@ static void pc_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev, pc_memory_unplug_request(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { pc_cpu_unplug_request_cb(hotplug_dev, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) { - pc_virtio_pmem_pci_unplug_request(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) || + object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) { + pc_virtio_md_pci_unplug_request(hotplug_dev, dev, errp); } else { error_setg(errp, "acpi: device unplug request for not supported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -1744,8 +1749,9 @@ static void pc_machine_device_unplug_cb(HotplugHandler *hotplug_dev, pc_memory_unplug(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { pc_cpu_unplug_cb(hotplug_dev, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) { - pc_virtio_pmem_pci_unplug(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) || + object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) { + pc_virtio_md_pci_unplug(hotplug_dev, dev, errp); } else { error_setg(errp, "acpi: device unplug for not supported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -1757,7 +1763,8 @@ static HotplugHandler *pc_get_hotplug_handler(MachineState *machine, { if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || object_dynamic_cast(OBJECT(dev), TYPE_CPU) || - object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) { + object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) || + object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) { return HOTPLUG_HANDLER(machine); } From c95b4437da6832f3bef9129de897cc7a8334ea8e Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:43 +0200 Subject: [PATCH 1879/2595] virtio-mem: Allow notifiers for size changes We want to send qapi events in case the size of a virtio-mem device changes. This allows upper layers to always know how much memory is actually currently consumed via a virtio-mem device. Unfortuantely, we have to report the id of our proxy device. Let's provide an easy way for our proxy device to register, so it can send the qapi events. Piggy-backing on the notifier infrastructure (although we'll only ever have one notifier registered) seems to be an easy way. Reviewed-by: Dr. David Alan Gilbert Cc: "Michael S. Tsirkin" Cc: "Dr. David Alan Gilbert" Cc: Igor Mammedov Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-17-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-mem.c | 21 ++++++++++++++++++++- include/hw/virtio/virtio-mem.h | 5 +++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 2d6f3061a6..6b5551515d 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -184,6 +184,7 @@ static int virtio_mem_state_change_request(VirtIOMEM *vmem, uint64_t gpa, } else { vmem->size -= size; } + notifier_list_notify(&vmem->size_change_notifiers, &vmem->size); return VIRTIO_MEM_RESP_ACK; } @@ -242,7 +243,10 @@ static int virtio_mem_unplug_all(VirtIOMEM *vmem) return -EBUSY; } bitmap_clear(vmem->bitmap, 0, vmem->bitmap_size); - vmem->size = 0; + if (vmem->size) { + vmem->size = 0; + notifier_list_notify(&vmem->size_change_notifiers, &vmem->size); + } virtio_mem_resize_usable_region(vmem, vmem->requested_size, true); return 0; @@ -561,6 +565,18 @@ static MemoryRegion *virtio_mem_get_memory_region(VirtIOMEM *vmem, Error **errp) return &vmem->memdev->mr; } +static void virtio_mem_add_size_change_notifier(VirtIOMEM *vmem, + Notifier *notifier) +{ + notifier_list_add(&vmem->size_change_notifiers, notifier); +} + +static void virtio_mem_remove_size_change_notifier(VirtIOMEM *vmem, + Notifier *notifier) +{ + notifier_remove(notifier); +} + static void virtio_mem_get_size(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -668,6 +684,7 @@ static void virtio_mem_instance_init(Object *obj) VirtIOMEM *vmem = VIRTIO_MEM(obj); vmem->block_size = VIRTIO_MEM_MIN_BLOCK_SIZE; + notifier_list_init(&vmem->size_change_notifiers); object_property_add(obj, VIRTIO_MEM_SIZE_PROP, "size", virtio_mem_get_size, NULL, NULL, NULL); @@ -705,6 +722,8 @@ static void virtio_mem_class_init(ObjectClass *klass, void *data) vmc->fill_device_info = virtio_mem_fill_device_info; vmc->get_memory_region = virtio_mem_get_memory_region; + vmc->add_size_change_notifier = virtio_mem_add_size_change_notifier; + vmc->remove_size_change_notifier = virtio_mem_remove_size_change_notifier; } static const TypeInfo virtio_mem_info = { diff --git a/include/hw/virtio/virtio-mem.h b/include/hw/virtio/virtio-mem.h index 6981096f7c..b74c77cd42 100644 --- a/include/hw/virtio/virtio-mem.h +++ b/include/hw/virtio/virtio-mem.h @@ -64,6 +64,9 @@ typedef struct VirtIOMEM { /* block size and alignment */ uint64_t block_size; + + /* notifiers to notify when "size" changes */ + NotifierList size_change_notifiers; } VirtIOMEM; typedef struct VirtIOMEMClass { @@ -73,6 +76,8 @@ typedef struct VirtIOMEMClass { /* public */ void (*fill_device_info)(const VirtIOMEM *vmen, VirtioMEMDeviceInfo *vi); MemoryRegion *(*get_memory_region)(VirtIOMEM *vmem, Error **errp); + void (*add_size_change_notifier)(VirtIOMEM *vmem, Notifier *notifier); + void (*remove_size_change_notifier)(VirtIOMEM *vmem, Notifier *notifier); } VirtIOMEMClass; #endif From 722a3c783ef4159b297d86e3c1f345360fb2a362 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:44 +0200 Subject: [PATCH 1880/2595] virtio-pci: Send qapi events when the virtio-mem size changes Let's register the notifier and trigger the qapi event with the right device id. MEMORY_DEVICE_SIZE_CHANGE is similar to BALLOON_CHANGE, however on a memory device level. Don't unregister the notifier (we neither have finalize() nor unrealize() for VirtIOPCIProxy, so it's not that simple to do it) - both devices are expected to vanish at the same time. Cc: "Michael S. Tsirkin" Cc: Markus Armbruster Cc: "Dr. David Alan Gilbert" Cc: Eric Blake Cc: Igor Mammedov Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-18-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-mem-pci.c | 28 ++++++++++++++++++++++++++++ hw/virtio/virtio-mem-pci.h | 1 + monitor/monitor.c | 1 + qapi/misc.json | 25 +++++++++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/hw/virtio/virtio-mem-pci.c b/hw/virtio/virtio-mem-pci.c index b325303b32..1a8e854123 100644 --- a/hw/virtio/virtio-mem-pci.c +++ b/hw/virtio/virtio-mem-pci.c @@ -14,6 +14,7 @@ #include "virtio-mem-pci.h" #include "hw/mem/memory-device.h" #include "qapi/error.h" +#include "qapi/qapi-events-misc.h" static void virtio_mem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { @@ -74,6 +75,21 @@ static void virtio_mem_pci_fill_device_info(const MemoryDeviceState *md, info->type = MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM; } +static void virtio_mem_pci_size_change_notify(Notifier *notifier, void *data) +{ + VirtIOMEMPCI *pci_mem = container_of(notifier, VirtIOMEMPCI, + size_change_notifier); + DeviceState *dev = DEVICE(pci_mem); + const uint64_t * const size_p = data; + const char *id = NULL; + + if (dev->id) { + id = g_strdup(dev->id); + } + + qapi_event_send_memory_device_size_change(!!id, id, *size_p); +} + static void virtio_mem_pci_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -98,9 +114,21 @@ static void virtio_mem_pci_class_init(ObjectClass *klass, void *data) static void virtio_mem_pci_instance_init(Object *obj) { VirtIOMEMPCI *dev = VIRTIO_MEM_PCI(obj); + VirtIOMEMClass *vmc; + VirtIOMEM *vmem; virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_MEM); + + dev->size_change_notifier.notify = virtio_mem_pci_size_change_notify; + vmem = VIRTIO_MEM(&dev->vdev); + vmc = VIRTIO_MEM_GET_CLASS(vmem); + /* + * We never remove the notifier again, as we expect both devices to + * disappear at the same time. + */ + vmc->add_size_change_notifier(vmem, &dev->size_change_notifier); + object_property_add_alias(obj, VIRTIO_MEM_BLOCK_SIZE_PROP, OBJECT(&dev->vdev), VIRTIO_MEM_BLOCK_SIZE_PROP); object_property_add_alias(obj, VIRTIO_MEM_SIZE_PROP, OBJECT(&dev->vdev), diff --git a/hw/virtio/virtio-mem-pci.h b/hw/virtio/virtio-mem-pci.h index 8820cd6628..b51a28b275 100644 --- a/hw/virtio/virtio-mem-pci.h +++ b/hw/virtio/virtio-mem-pci.h @@ -28,6 +28,7 @@ typedef struct VirtIOMEMPCI VirtIOMEMPCI; struct VirtIOMEMPCI { VirtIOPCIProxy parent_obj; VirtIOMEM vdev; + Notifier size_change_notifier; }; #endif /* QEMU_VIRTIO_MEM_PCI_H */ diff --git a/monitor/monitor.c b/monitor/monitor.c index 125494410a..19dcb8fbe3 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -235,6 +235,7 @@ static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = { [QAPI_EVENT_QUORUM_REPORT_BAD] = { 1000 * SCALE_MS }, [QAPI_EVENT_QUORUM_FAILURE] = { 1000 * SCALE_MS }, [QAPI_EVENT_VSERPORT_CHANGE] = { 1000 * SCALE_MS }, + [QAPI_EVENT_MEMORY_DEVICE_SIZE_CHANGE] = { 1000 * SCALE_MS }, }; /* diff --git a/qapi/misc.json b/qapi/misc.json index 65ca3edf32..149c925246 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -1434,6 +1434,31 @@ ## { 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] } +## +# @MEMORY_DEVICE_SIZE_CHANGE: +# +# Emitted when the size of a memory device changes. Only emitted for memory +# devices that can actually change the size (e.g., virtio-mem due to guest +# action). +# +# @id: device's ID +# @size: the new size of memory that the device provides +# +# Note: this event is rate-limited. +# +# Since: 5.1 +# +# Example: +# +# <- { "event": "MEMORY_DEVICE_SIZE_CHANGE", +# "data": { "id": "vm0", "size": 1073741824}, +# "timestamp": { "seconds": 1588168529, "microseconds": 201316 } } +# +## +{ 'event': 'MEMORY_DEVICE_SIZE_CHANGE', + 'data': { '*id': 'str', 'size': 'size' } } + + ## # @MEM_UNPLUG_ERROR: # From 383ee44555b4fdf37670176f704a8c8132fd5568 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:45 +0200 Subject: [PATCH 1881/2595] virtio-mem: Migration sanity checks We want to make sure that certain properties don't change during migration, especially to catch user errors in a nice way. Let's migrate a temporary structure and validate that the properties didn't change. Reviewed-by: Dr. David Alan Gilbert Cc: "Michael S. Tsirkin" Cc: "Dr. David Alan Gilbert" Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-19-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-mem.c | 70 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 6b5551515d..c1acfb9f24 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -519,12 +519,82 @@ static int virtio_mem_post_load(void *opaque, int version_id) return virtio_mem_restore_unplugged(VIRTIO_MEM(opaque)); } +typedef struct VirtIOMEMMigSanityChecks { + VirtIOMEM *parent; + uint64_t addr; + uint64_t region_size; + uint64_t block_size; + uint32_t node; +} VirtIOMEMMigSanityChecks; + +static int virtio_mem_mig_sanity_checks_pre_save(void *opaque) +{ + VirtIOMEMMigSanityChecks *tmp = opaque; + VirtIOMEM *vmem = tmp->parent; + + tmp->addr = vmem->addr; + tmp->region_size = memory_region_size(&vmem->memdev->mr); + tmp->block_size = vmem->block_size; + tmp->node = vmem->node; + return 0; +} + +static int virtio_mem_mig_sanity_checks_post_load(void *opaque, int version_id) +{ + VirtIOMEMMigSanityChecks *tmp = opaque; + VirtIOMEM *vmem = tmp->parent; + const uint64_t new_region_size = memory_region_size(&vmem->memdev->mr); + + if (tmp->addr != vmem->addr) { + error_report("Property '%s' changed from 0x%" PRIx64 " to 0x%" PRIx64, + VIRTIO_MEM_ADDR_PROP, tmp->addr, vmem->addr); + return -EINVAL; + } + /* + * Note: Preparation for resizeable memory regions. The maximum size + * of the memory region must not change during migration. + */ + if (tmp->region_size != new_region_size) { + error_report("Property '%s' size changed from 0x%" PRIx64 " to 0x%" + PRIx64, VIRTIO_MEM_MEMDEV_PROP, tmp->region_size, + new_region_size); + return -EINVAL; + } + if (tmp->block_size != vmem->block_size) { + error_report("Property '%s' changed from 0x%" PRIx64 " to 0x%" PRIx64, + VIRTIO_MEM_BLOCK_SIZE_PROP, tmp->block_size, + vmem->block_size); + return -EINVAL; + } + if (tmp->node != vmem->node) { + error_report("Property '%s' changed from %" PRIu32 " to %" PRIu32, + VIRTIO_MEM_NODE_PROP, tmp->node, vmem->node); + return -EINVAL; + } + return 0; +} + +static const VMStateDescription vmstate_virtio_mem_sanity_checks = { + .name = "virtio-mem-device/sanity-checks", + .pre_save = virtio_mem_mig_sanity_checks_pre_save, + .post_load = virtio_mem_mig_sanity_checks_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT64(addr, VirtIOMEMMigSanityChecks), + VMSTATE_UINT64(region_size, VirtIOMEMMigSanityChecks), + VMSTATE_UINT64(block_size, VirtIOMEMMigSanityChecks), + VMSTATE_UINT32(node, VirtIOMEMMigSanityChecks), + VMSTATE_END_OF_LIST(), + }, +}; + static const VMStateDescription vmstate_virtio_mem_device = { .name = "virtio-mem-device", .minimum_version_id = 1, .version_id = 1, .post_load = virtio_mem_post_load, .fields = (VMStateField[]) { + VMSTATE_WITH_TMP(VirtIOMEM, VirtIOMEMMigSanityChecks, + vmstate_virtio_mem_sanity_checks), VMSTATE_UINT64(usable_region_size, VirtIOMEM), VMSTATE_UINT64(size, VirtIOMEM), VMSTATE_UINT64(requested_size, VirtIOMEM), From 43e5495027c5b784d23bd0cd9e5a4308a43b9603 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:46 +0200 Subject: [PATCH 1882/2595] virtio-mem: Add trace events Let's add some trace events that might come in handy later. Cc: "Michael S. Tsirkin" Cc: "Dr. David Alan Gilbert" Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-20-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/trace-events | 10 ++++++++++ hw/virtio/virtio-mem.c | 10 +++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 6427a0047d..292fc15e29 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -74,3 +74,13 @@ virtio_iommu_get_domain(uint32_t domain_id) "Alloc domain=%d" virtio_iommu_put_domain(uint32_t domain_id) "Free domain=%d" virtio_iommu_translate_out(uint64_t virt_addr, uint64_t phys_addr, uint32_t sid) "0x%"PRIx64" -> 0x%"PRIx64 " for sid=%d" virtio_iommu_report_fault(uint8_t reason, uint32_t flags, uint32_t endpoint, uint64_t addr) "FAULT reason=%d flags=%d endpoint=%d address =0x%"PRIx64 + +# virtio-mem.c +virtio_mem_send_response(uint16_t type) "type=%" PRIu16 +virtio_mem_plug_request(uint64_t addr, uint16_t nb_blocks) "addr=0x%" PRIx64 " nb_blocks=%" PRIu16 +virtio_mem_unplug_request(uint64_t addr, uint16_t nb_blocks) "addr=0x%" PRIx64 " nb_blocks=%" PRIu16 +virtio_mem_unplugged_all(void) "" +virtio_mem_unplug_all_request(void) "" +virtio_mem_resized_usable_region(uint64_t old_size, uint64_t new_size) "old_size=0x%" PRIx64 "new_size=0x%" PRIx64 +virtio_mem_state_request(uint64_t addr, uint16_t nb_blocks) "addr=0x%" PRIx64 " nb_blocks=%" PRIu16 +virtio_mem_state_response(uint16_t state) "state=%" PRIu16 diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index c1acfb9f24..1ab9ef17fa 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -30,6 +30,7 @@ #include "hw/boards.h" #include "hw/qdev-properties.h" #include "config-devices.h" +#include "trace.h" /* * Use QEMU_VMALLOC_ALIGN, so no THP will have to be split when unplugging @@ -100,6 +101,7 @@ static void virtio_mem_send_response(VirtIOMEM *vmem, VirtQueueElement *elem, VirtIODevice *vdev = VIRTIO_DEVICE(vmem); VirtQueue *vq = vmem->vq; + trace_virtio_mem_send_response(le16_to_cpu(resp->type)); iov_from_buf(elem->in_sg, elem->in_num, 0, resp, sizeof(*resp)); virtqueue_push(vq, elem, sizeof(*resp)); @@ -195,6 +197,7 @@ static void virtio_mem_plug_request(VirtIOMEM *vmem, VirtQueueElement *elem, const uint16_t nb_blocks = le16_to_cpu(req->u.plug.nb_blocks); uint16_t type; + trace_virtio_mem_plug_request(gpa, nb_blocks); type = virtio_mem_state_change_request(vmem, gpa, nb_blocks, true); virtio_mem_send_response_simple(vmem, elem, type); } @@ -206,6 +209,7 @@ static void virtio_mem_unplug_request(VirtIOMEM *vmem, VirtQueueElement *elem, const uint16_t nb_blocks = le16_to_cpu(req->u.unplug.nb_blocks); uint16_t type; + trace_virtio_mem_unplug_request(gpa, nb_blocks); type = virtio_mem_state_change_request(vmem, gpa, nb_blocks, false); virtio_mem_send_response_simple(vmem, elem, type); } @@ -225,6 +229,7 @@ static void virtio_mem_resize_usable_region(VirtIOMEM *vmem, return; } + trace_virtio_mem_resized_usable_region(vmem->usable_region_size, newsize); vmem->usable_region_size = newsize; } @@ -247,7 +252,7 @@ static int virtio_mem_unplug_all(VirtIOMEM *vmem) vmem->size = 0; notifier_list_notify(&vmem->size_change_notifiers, &vmem->size); } - + trace_virtio_mem_unplugged_all(); virtio_mem_resize_usable_region(vmem, vmem->requested_size, true); return 0; } @@ -255,6 +260,7 @@ static int virtio_mem_unplug_all(VirtIOMEM *vmem) static void virtio_mem_unplug_all_request(VirtIOMEM *vmem, VirtQueueElement *elem) { + trace_virtio_mem_unplug_all_request(); if (virtio_mem_unplug_all(vmem)) { virtio_mem_send_response_simple(vmem, elem, VIRTIO_MEM_RESP_BUSY); } else { @@ -272,6 +278,7 @@ static void virtio_mem_state_request(VirtIOMEM *vmem, VirtQueueElement *elem, .type = cpu_to_le16(VIRTIO_MEM_RESP_ACK), }; + trace_virtio_mem_state_request(gpa, nb_blocks); if (!virtio_mem_valid_range(vmem, gpa, size)) { virtio_mem_send_response_simple(vmem, elem, VIRTIO_MEM_RESP_ERROR); return; @@ -284,6 +291,7 @@ static void virtio_mem_state_request(VirtIOMEM *vmem, VirtQueueElement *elem, } else { resp.u.state.state = cpu_to_le16(VIRTIO_MEM_STATE_MIXED); } + trace_virtio_mem_state_response(le16_to_cpu(resp.u.state.state)); virtio_mem_send_response(vmem, elem, &resp); } From 0bc7806c5a670fa0bd160caf07489a5106a67d55 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:47 +0200 Subject: [PATCH 1883/2595] virtio-mem: Exclude unplugged memory during migration The content of unplugged memory is undefined and should not be migrated, ever. Exclude all unplugged memory during precopy using the precopy notifier infrastructure introduced for free page hinting in virtio-balloon. Unplugged memory is marked as "not dirty", meaning it won't be considered for migration. Cc: "Michael S. Tsirkin" Cc: "Dr. David Alan Gilbert" Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-21-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-mem.c | 54 +++++++++++++++++++++++++++++++++- include/hw/virtio/virtio-mem.h | 3 ++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 1ab9ef17fa..65850530e7 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -62,8 +62,14 @@ static bool virtio_mem_is_busy(void) /* * Postcopy cannot handle concurrent discards and we don't want to migrate * pages on-demand with stale content when plugging new blocks. + * + * For precopy, we don't want unplugged blocks in our migration stream, and + * when plugging new blocks, the page content might differ between source + * and destination (observable by the guest when not initializing pages + * after plugging them) until we're running on the destination (as we didn't + * migrate these blocks when they were unplugged). */ - return migration_in_incoming_postcopy(); + return migration_in_incoming_postcopy() || !migration_is_idle(); } static bool virtio_mem_test_bitmap(VirtIOMEM *vmem, uint64_t start_gpa, @@ -475,6 +481,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) host_memory_backend_set_mapped(vmem->memdev, true); vmstate_register_ram(&vmem->memdev->mr, DEVICE(vmem)); qemu_register_reset(virtio_mem_system_reset, vmem); + precopy_add_notifier(&vmem->precopy_notifier); } static void virtio_mem_device_unrealize(DeviceState *dev) @@ -482,6 +489,7 @@ static void virtio_mem_device_unrealize(DeviceState *dev) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOMEM *vmem = VIRTIO_MEM(dev); + precopy_remove_notifier(&vmem->precopy_notifier); qemu_unregister_reset(virtio_mem_system_reset, vmem); vmstate_unregister_ram(&vmem->memdev->mr, DEVICE(vmem)); host_memory_backend_set_mapped(vmem->memdev, false); @@ -757,12 +765,56 @@ static void virtio_mem_set_block_size(Object *obj, Visitor *v, const char *name, vmem->block_size = value; } +static void virtio_mem_precopy_exclude_unplugged(VirtIOMEM *vmem) +{ + void * const host = qemu_ram_get_host_addr(vmem->memdev->mr.ram_block); + unsigned long first_zero_bit, last_zero_bit; + uint64_t offset, length; + + /* + * Find consecutive unplugged blocks and exclude them from migration. + * + * Note: Blocks cannot get (un)plugged during precopy, no locking needed. + */ + first_zero_bit = find_first_zero_bit(vmem->bitmap, vmem->bitmap_size); + while (first_zero_bit < vmem->bitmap_size) { + offset = first_zero_bit * vmem->block_size; + last_zero_bit = find_next_bit(vmem->bitmap, vmem->bitmap_size, + first_zero_bit + 1) - 1; + length = (last_zero_bit - first_zero_bit + 1) * vmem->block_size; + + qemu_guest_free_page_hint(host + offset, length); + first_zero_bit = find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, + last_zero_bit + 2); + } +} + +static int virtio_mem_precopy_notify(NotifierWithReturn *n, void *data) +{ + VirtIOMEM *vmem = container_of(n, VirtIOMEM, precopy_notifier); + PrecopyNotifyData *pnd = data; + + switch (pnd->reason) { + case PRECOPY_NOTIFY_SETUP: + precopy_enable_free_page_optimization(); + break; + case PRECOPY_NOTIFY_AFTER_BITMAP_SYNC: + virtio_mem_precopy_exclude_unplugged(vmem); + break; + default: + break; + } + + return 0; +} + static void virtio_mem_instance_init(Object *obj) { VirtIOMEM *vmem = VIRTIO_MEM(obj); vmem->block_size = VIRTIO_MEM_MIN_BLOCK_SIZE; notifier_list_init(&vmem->size_change_notifiers); + vmem->precopy_notifier.notify = virtio_mem_precopy_notify; object_property_add(obj, VIRTIO_MEM_SIZE_PROP, "size", virtio_mem_get_size, NULL, NULL, NULL); diff --git a/include/hw/virtio/virtio-mem.h b/include/hw/virtio/virtio-mem.h index b74c77cd42..0778224964 100644 --- a/include/hw/virtio/virtio-mem.h +++ b/include/hw/virtio/virtio-mem.h @@ -67,6 +67,9 @@ typedef struct VirtIOMEM { /* notifiers to notify when "size" changes */ NotifierList size_change_notifiers; + + /* don't migrate unplugged memory */ + NotifierWithReturn precopy_notifier; } VirtIOMEM; typedef struct VirtIOMEMClass { From 195784a0cfad57b06cba6d67f286039d5a01babf Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 26 Jun 2020 09:22:48 +0200 Subject: [PATCH 1884/2595] numa: Auto-enable NUMA when any memory devices are possible Let's auto-enable it also when maxmem is specified but no slots are defined. This will result in us properly creating ACPI srat tables, indicating the maximum possible PFN to the guest OS. Based on this, e.g., Linux will enable the swiotlb properly. This avoids having to manually force the switolb on (swiotlb=force) in Linux in case we're booting only using DMA memory (e.g., 2GB on x86-64), and virtio-mem adds memory later on that really needs the swiotlb to be used for DMA. Let's take care of backwards compatibility if somebody has a setup that specifies "maxram" without "slots". Reported-by: Alex Shi Cc: Peter Maydell Cc: Eduardo Habkost Cc: Marcel Apfelbaum Cc: Sergio Lopez Cc: Paolo Bonzini Cc: Richard Henderson Cc: "Michael S. Tsirkin" Cc: Igor Mammedov Cc: qemu-arm@nongnu.org Signed-off-by: David Hildenbrand Message-Id: <20200626072248.78761-22-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/virt.c | 2 ++ hw/core/numa.c | 11 ++++++----- hw/i386/microvm.c | 1 + hw/i386/pc.c | 1 + hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 1 + include/hw/boards.h | 1 + 7 files changed, 13 insertions(+), 5 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index cd0834ce7f..f97be80a86 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2373,6 +2373,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) hc->unplug = virt_machine_device_unplug_cb; mc->nvdimm_supported = true; mc->auto_enable_numa_with_memhp = true; + mc->auto_enable_numa_with_memdev = true; mc->default_ram_id = "mach-virt.ram"; object_class_property_add(oc, "acpi", "OnOffAuto", @@ -2485,6 +2486,7 @@ static void virt_machine_5_0_options(MachineClass *mc) virt_machine_5_1_options(mc); compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len); mc->numa_mem_supported = true; + mc->auto_enable_numa_with_memdev = false; } DEFINE_VIRT_MACHINE(5, 0) diff --git a/hw/core/numa.c b/hw/core/numa.c index e9aec69afd..6a20ce7cf1 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -688,8 +688,9 @@ void numa_complete_configuration(MachineState *ms) NodeInfo *numa_info = ms->numa_state->nodes; /* - * If memory hotplug is enabled (slots > 0) but without '-numa' - * options explicitly on CLI, guestes will break. + * If memory hotplug is enabled (slot > 0) or memory devices are enabled + * (ms->maxram_size > ram_size) but without '-numa' options explicitly on + * CLI, guests will break. * * Windows: won't enable memory hotplug without SRAT table at all * @@ -704,9 +705,9 @@ void numa_complete_configuration(MachineState *ms) * assume there is just one node with whole RAM. */ if (ms->numa_state->num_nodes == 0 && - ((ms->ram_slots > 0 && - mc->auto_enable_numa_with_memhp) || - mc->auto_enable_numa)) { + ((ms->ram_slots && mc->auto_enable_numa_with_memhp) || + (ms->maxram_size > ms->ram_size && mc->auto_enable_numa_with_memdev) || + mc->auto_enable_numa)) { NumaNodeOptions node = { }; parse_numa_node(ms, &node, &error_abort); numa_info[0].node_mem = ram_size; diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 5e931975a0..81d0888930 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -464,6 +464,7 @@ static void microvm_class_init(ObjectClass *oc, void *data) mc->max_cpus = 288; mc->has_hotpluggable_cpus = false; mc->auto_enable_numa_with_memhp = false; + mc->auto_enable_numa_with_memdev = false; mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE; mc->nvdimm_supported = false; mc->default_ram_id = "microvm.ram"; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 576f2502f9..61acc9e530 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1975,6 +1975,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) mc->get_default_cpu_node_id = x86_get_default_cpu_node_id; mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids; mc->auto_enable_numa_with_memhp = true; + mc->auto_enable_numa_with_memdev = true; mc->has_hotpluggable_cpus = true; mc->default_boot_order = "cad"; mc->hot_add_cpu = pc_hot_add_cpu; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 1d832b2878..fae487f57d 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -444,6 +444,7 @@ static void pc_i440fx_5_0_machine_options(MachineClass *m) m->numa_mem_supported = true; compat_props_add(m->compat_props, hw_compat_5_0, hw_compat_5_0_len); compat_props_add(m->compat_props, pc_compat_5_0, pc_compat_5_0_len); + m->auto_enable_numa_with_memdev = false; } DEFINE_I440FX_MACHINE(v5_0, "pc-i440fx-5.0", NULL, diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 047ea8db28..acd6d405f0 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -372,6 +372,7 @@ static void pc_q35_5_0_machine_options(MachineClass *m) m->numa_mem_supported = true; compat_props_add(m->compat_props, hw_compat_5_0, hw_compat_5_0_len); compat_props_add(m->compat_props, pc_compat_5_0, pc_compat_5_0_len); + m->auto_enable_numa_with_memhp = false; } DEFINE_Q35_MACHINE(v5_0, "pc-q35-5.0", NULL, diff --git a/include/hw/boards.h b/include/hw/boards.h index 18815d9be2..426ce5f625 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -207,6 +207,7 @@ struct MachineClass { const char **valid_cpu_types; strList *allowed_dynamic_sysbus_devices; bool auto_enable_numa_with_memhp; + bool auto_enable_numa_with_memdev; void (*numa_auto_assign_ram)(MachineClass *mc, NodeInfo *nodes, int nb_nodes, ram_addr_t size); bool ignore_boot_device_suffixes; From 3e1dc4d55ebe64cc52aa67baac7733a8e653ae2e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 29 Jun 2020 16:09:35 +0200 Subject: [PATCH 1885/2595] tests/acpi: remove stale allowed tables Fixes: 93dd625f8bf7 ("tests/acpi: update expected data files") Signed-off-by: Andrew Jones Message-Id: <20200629140938.17566-2-drjones@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 8992f1f12b..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,19 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/pc/DSDT", -"tests/data/acpi/pc/DSDT.acpihmat", -"tests/data/acpi/pc/DSDT.bridge", -"tests/data/acpi/pc/DSDT.cphp", -"tests/data/acpi/pc/DSDT.dimmpxm", -"tests/data/acpi/pc/DSDT.ipmikcs", -"tests/data/acpi/pc/DSDT.memhp", -"tests/data/acpi/pc/DSDT.numamem", -"tests/data/acpi/q35/DSDT", -"tests/data/acpi/q35/DSDT.acpihmat", -"tests/data/acpi/q35/DSDT.bridge", -"tests/data/acpi/q35/DSDT.cphp", -"tests/data/acpi/q35/DSDT.dimmpxm", -"tests/data/acpi/q35/DSDT.ipmibt", -"tests/data/acpi/q35/DSDT.memhp", -"tests/data/acpi/q35/DSDT.mmio64", -"tests/data/acpi/q35/DSDT.numamem", -"tests/data/acpi/q35/DSDT.tis", From 553dc662bbb4b5ce73b07db9202e9366aaba153c Mon Sep 17 00:00:00 2001 From: Maxime Coquelin Date: Thu, 18 Jun 2020 15:45:01 +0200 Subject: [PATCH 1886/2595] docs: vhost-user: add Virtio status protocol feature This patch specifies the VHOST_USER_SET_STATUS and VHOST_USER_GET_STATUS requests, which are sent by the master to update and query the Virtio status in the backend. Signed-off-by: Maxime Coquelin Message-Id: <20200618134501.145747-1-maxime.coquelin@redhat.com> Acked-by: Jason Wang Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/interop/vhost-user.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 688b7c6900..10e3e3475e 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -816,6 +816,7 @@ Protocol features #define VHOST_USER_PROTOCOL_F_RESET_DEVICE 13 #define VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS 14 #define VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS 15 + #define VHOST_USER_PROTOCOL_F_STATUS 16 Master message types -------------------- @@ -1307,6 +1308,29 @@ Master message types ``VHOST_USER_ADD_MEM_REG`` message, this message is used to set and update the memory tables of the slave device. +``VHOST_USER_SET_STATUS`` + :id: 39 + :equivalent ioctl: VHOST_VDPA_SET_STATUS + :slave payload: N/A + :master payload: ``u64`` + + When the ``VHOST_USER_PROTOCOL_F_STATUS`` protocol feature has been + successfully negotiated, this message is submitted by the master to + notify the backend with updated device status as defined in the Virtio + specification. + +``VHOST_USER_GET_STATUS`` + :id: 40 + :equivalent ioctl: VHOST_VDPA_GET_STATUS + :slave payload: ``u64`` + :master payload: N/A + + When the ``VHOST_USER_PROTOCOL_F_STATUS`` protocol feature has been + successfully negotiated, this message is submitted by the master to + query the backend for its device status as defined in the Virtio + specification. + + Slave message types ------------------- From 8bc43f39a911036467b95abcac59f22240ac1957 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 1 Jul 2020 08:44:18 -0400 Subject: [PATCH 1887/2595] MAINTAINERS: add VT-d entry Add this entry as suggested by Jason and Michael. CC: Jason Wang CC: Michael S. Tsirkin CC: Paolo Bonzini Signed-off-by: Peter Xu Message-Id: <20200701124418.63060-1-peterx@redhat.com> Acked-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5f02160436..49a0d837d7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2624,6 +2624,15 @@ F: tests/uefi-test-tools/ F: .gitlab-ci.d/edk2.yml F: .gitlab-ci.d/edk2/ +VT-d Emulation +M: Michael S. Tsirkin +M: Peter Xu +R: Jason Wang +S: Supported +F: hw/i386/intel_iommu.c +F: hw/i386/intel_iommu_internal.h +F: include/hw/i386/intel_iommu.h + Usermode Emulation ------------------ Overall usermode emulation From 0165daae5c353bd0d2b72fb39993ece8a845ad75 Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Wed, 1 Jul 2020 22:55:25 +0800 Subject: [PATCH 1888/2595] net: introduce qemu_get_peer This is a small function that can get the peer from given NetClientState and queue_index Signed-off-by: Cindy Lu Message-Id: <20200701145538.22333-2-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- include/net/net.h | 1 + net/net.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/net/net.h b/include/net/net.h index 39085d9444..e7ef42d62b 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -176,6 +176,7 @@ void hmp_info_network(Monitor *mon, const QDict *qdict); void net_socket_rs_init(SocketReadState *rs, SocketReadStateFinalize *finalize, bool vnet_hdr); +NetClientState *qemu_get_peer(NetClientState *nc, int queue_index); /* NIC info */ diff --git a/net/net.c b/net/net.c index d1130296e1..9099a327dd 100644 --- a/net/net.c +++ b/net/net.c @@ -325,6 +325,13 @@ void *qemu_get_nic_opaque(NetClientState *nc) return nic->opaque; } +NetClientState *qemu_get_peer(NetClientState *nc, int queue_index) +{ + assert(nc != NULL); + NetClientState *ncs = nc + queue_index; + return ncs->peer; +} + static void qemu_cleanup_net_client(NetClientState *nc) { QTAILQ_REMOVE(&net_clients, nc, next); From 92fbc3e07eb924bd5e03d22764e637b2e02e46bd Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Wed, 1 Jul 2020 22:55:26 +0800 Subject: [PATCH 1889/2595] vhost_net: use the function qemu_get_peer user the qemu_get_peer to replace the old process Signed-off-by: Cindy Lu Reviewed-by: Laurent Vivier Message-Id: <20200701145538.22333-3-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- hw/net/vhost_net.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 6b82803fa7..4096d64aaf 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -306,7 +306,9 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); VirtioBusState *vbus = VIRTIO_BUS(qbus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); + struct vhost_net *net; int r, e, i; + NetClientState *peer; if (!k->set_guest_notifiers) { error_report("binding does not support guest notifiers"); @@ -314,9 +316,9 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, } for (i = 0; i < total_queues; i++) { - struct vhost_net *net; - net = get_vhost_net(ncs[i].peer); + peer = qemu_get_peer(ncs, i); + net = get_vhost_net(peer); vhost_net_set_vq_index(net, i * 2); /* Suppress the masking guest notifiers on vhost user @@ -335,15 +337,16 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, } for (i = 0; i < total_queues; i++) { - r = vhost_net_start_one(get_vhost_net(ncs[i].peer), dev); + peer = qemu_get_peer(ncs, i); + r = vhost_net_start_one(get_vhost_net(peer), dev); if (r < 0) { goto err_start; } - if (ncs[i].peer->vring_enable) { + if (peer->vring_enable) { /* restore vring enable state */ - r = vhost_set_vring_enable(ncs[i].peer, ncs[i].peer->vring_enable); + r = vhost_set_vring_enable(peer, peer->vring_enable); if (r < 0) { goto err_start; @@ -355,7 +358,8 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, err_start: while (--i >= 0) { - vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev); + peer = qemu_get_peer(ncs , i); + vhost_net_stop_one(get_vhost_net(peer), dev); } e = k->set_guest_notifiers(qbus->parent, total_queues * 2, false); if (e < 0) { From b2a5f62a2284a8933f6f6cda48797b7263b96970 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 1 Jul 2020 22:55:27 +0800 Subject: [PATCH 1890/2595] virtio-bus: introduce queue_enabled method This patch introduces queue_enabled() method which allows the transport to implement its own way to report whether or not a queue is enabled. Signed-off-by: Jason Wang Signed-off-by: Cindy Lu Message-Id: <20200701145538.22333-4-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- hw/virtio/virtio.c | 6 ++++++ include/hw/virtio/virtio-bus.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index cc9c9dc162..5bd2a2f621 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3286,6 +3286,12 @@ hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n) bool virtio_queue_enabled(VirtIODevice *vdev, int n) { + BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + + if (k->queue_enabled) { + return k->queue_enabled(qbus->parent, n); + } return virtio_queue_get_desc_addr(vdev, n) != 0; } diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h index 38c9399cd4..0f6f215925 100644 --- a/include/hw/virtio/virtio-bus.h +++ b/include/hw/virtio/virtio-bus.h @@ -83,6 +83,10 @@ typedef struct VirtioBusClass { */ int (*ioeventfd_assign)(DeviceState *d, EventNotifier *notifier, int n, bool assign); + /* + * Whether queue number n is enabled. + */ + bool (*queue_enabled)(DeviceState *d, int n); /* * Does the transport have variable vring alignment? * (ie can it ever call virtio_queue_set_align()?) From f19bcdfedd53ee93412d535a842a89fa27cae7f2 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 1 Jul 2020 22:55:28 +0800 Subject: [PATCH 1891/2595] virtio-pci: implement queue_enabled method With version 1, we can detect whether a queue is enabled via queue_enabled. Signed-off-by: Jason Wang Signed-off-by: Cindy Lu Message-Id: <20200701145538.22333-5-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- hw/virtio/virtio-pci.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 7bc8c1c056..8554cf2a03 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1107,6 +1107,18 @@ static AddressSpace *virtio_pci_get_dma_as(DeviceState *d) return pci_get_address_space(dev); } +static bool virtio_pci_queue_enabled(DeviceState *d, int n) +{ + VirtIOPCIProxy *proxy = VIRTIO_PCI(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + + if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { + return proxy->vqs[vdev->queue_sel].enabled; + } + + return virtio_queue_enabled(vdev, n); +} + static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy, struct virtio_pci_cap *cap) { @@ -2064,6 +2076,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) k->ioeventfd_enabled = virtio_pci_ioeventfd_enabled; k->ioeventfd_assign = virtio_pci_ioeventfd_assign; k->get_dma_as = virtio_pci_get_dma_as; + k->queue_enabled = virtio_pci_queue_enabled; } static const TypeInfo virtio_pci_bus_info = { From 3f63b4c655047dad8bfe9443051f0bf1d56f029a Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 1 Jul 2020 22:55:29 +0800 Subject: [PATCH 1892/2595] vhost: check the existence of vhost_set_iotlb_callback Add the check of vhost_set_iotlb_callback before calling Signed-off-by: Jason Wang Signed-off-by: Cindy Lu Message-Id: <20200701145538.22333-6-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- hw/virtio/vhost.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 5fd25fe520..10304b583e 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1686,8 +1686,9 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) } } - if (vhost_dev_has_iommu(hdev)) { - hdev->vhost_ops->vhost_set_iotlb_callback(hdev, true); + if (vhost_dev_has_iommu(hdev) && + hdev->vhost_ops->vhost_set_iotlb_callback) { + hdev->vhost_ops->vhost_set_iotlb_callback(hdev, true); /* Update used ring information for IOTLB to work correctly, * vhost-kernel code requires for this.*/ @@ -1730,7 +1731,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) } if (vhost_dev_has_iommu(hdev)) { - hdev->vhost_ops->vhost_set_iotlb_callback(hdev, false); + if (hdev->vhost_ops->vhost_set_iotlb_callback) { + hdev->vhost_ops->vhost_set_iotlb_callback(hdev, false); + } memory_listener_unregister(&hdev->iommu_listener); } vhost_log_put(hdev, true); From 68513bcd88d5c6d81cfa6563537c20430facfca7 Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Wed, 1 Jul 2020 22:55:30 +0800 Subject: [PATCH 1893/2595] vhost: introduce new VhostOps vhost_dev_start This patch introduces new VhostOps vhost_dev_start callback which allows the vhost_net set the start/stop status to backend Signed-off-by: Cindy Lu Message-Id: <20200701145538.22333-7-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- include/hw/virtio/vhost-backend.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index 6f6670783f..b80f344cd6 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -112,6 +112,7 @@ typedef int (*vhost_get_inflight_fd_op)(struct vhost_dev *dev, typedef int (*vhost_set_inflight_fd_op)(struct vhost_dev *dev, struct vhost_inflight *inflight); +typedef int (*vhost_dev_start_op)(struct vhost_dev *dev, bool started); typedef struct VhostOps { VhostBackendType backend_type; vhost_backend_init vhost_backend_init; @@ -152,6 +153,7 @@ typedef struct VhostOps { vhost_backend_mem_section_filter_op vhost_backend_mem_section_filter; vhost_get_inflight_fd_op vhost_get_inflight_fd; vhost_set_inflight_fd_op vhost_set_inflight_fd; + vhost_dev_start_op vhost_dev_start; } VhostOps; extern const VhostOps user_ops; From ca71db438bdc317c7b8ef890c3d9a804cec109b5 Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Wed, 1 Jul 2020 22:55:31 +0800 Subject: [PATCH 1894/2595] vhost: implement vhost_dev_start method use the vhost_dev_start callback to send the status to backend Signed-off-by: Cindy Lu Message-Id: <20200701145538.22333-8-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- hw/virtio/vhost.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 10304b583e..32809e54b5 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1685,7 +1685,12 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) goto fail_log; } } - + if (hdev->vhost_ops->vhost_dev_start) { + r = hdev->vhost_ops->vhost_dev_start(hdev, true); + if (r) { + goto fail_log; + } + } if (vhost_dev_has_iommu(hdev) && hdev->vhost_ops->vhost_set_iotlb_callback) { hdev->vhost_ops->vhost_set_iotlb_callback(hdev, true); @@ -1723,6 +1728,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) /* should only be called after backend is connected */ assert(hdev->vhost_ops); + if (hdev->vhost_ops->vhost_dev_start) { + hdev->vhost_ops->vhost_dev_start(hdev, false); + } for (i = 0; i < hdev->nvqs; ++i) { vhost_virtqueue_stop(hdev, vdev, From 35f20bb76922420edce8196e6215b0ca49443378 Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Wed, 1 Jul 2020 22:55:32 +0800 Subject: [PATCH 1895/2595] vhost: introduce new VhostOps vhost_vq_get_addr This patch introduces new VhostOps vhost_vq_get_addr_op callback to get the vring addr from the backend Signed-off-by: Cindy Lu Message-Id: <20200701145538.22333-9-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- include/hw/virtio/vhost-backend.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index b80f344cd6..fa84abac97 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -34,6 +34,7 @@ struct vhost_vring_state; struct vhost_vring_addr; struct vhost_scsi_target; struct vhost_iotlb_msg; +struct vhost_virtqueue; typedef int (*vhost_backend_init)(struct vhost_dev *dev, void *opaque); typedef int (*vhost_backend_cleanup)(struct vhost_dev *dev); @@ -113,6 +114,10 @@ typedef int (*vhost_set_inflight_fd_op)(struct vhost_dev *dev, struct vhost_inflight *inflight); typedef int (*vhost_dev_start_op)(struct vhost_dev *dev, bool started); + +typedef int (*vhost_vq_get_addr_op)(struct vhost_dev *dev, + struct vhost_vring_addr *addr, + struct vhost_virtqueue *vq); typedef struct VhostOps { VhostBackendType backend_type; vhost_backend_init vhost_backend_init; @@ -154,6 +159,7 @@ typedef struct VhostOps { vhost_get_inflight_fd_op vhost_get_inflight_fd; vhost_set_inflight_fd_op vhost_set_inflight_fd; vhost_dev_start_op vhost_dev_start; + vhost_vq_get_addr_op vhost_vq_get_addr; } VhostOps; extern const VhostOps user_ops; From b4ab225c34944658ddff62e4ee8127c3838bcf1d Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Wed, 1 Jul 2020 22:55:33 +0800 Subject: [PATCH 1896/2595] vhost: implement vhost_vq_get_addr method use vhost_vq_get_addr callback to get the vq address from backend Signed-off-by: Cindy Lu Message-Id: <20200701145538.22333-10-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- hw/virtio/vhost.c | 28 +++++++++++++++++++--------- include/hw/virtio/vhost-backend.h | 4 ++++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 32809e54b5..1e083a8976 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -773,15 +773,25 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev, struct vhost_virtqueue *vq, unsigned idx, bool enable_log) { - struct vhost_vring_addr addr = { - .index = idx, - .desc_user_addr = (uint64_t)(unsigned long)vq->desc, - .avail_user_addr = (uint64_t)(unsigned long)vq->avail, - .used_user_addr = (uint64_t)(unsigned long)vq->used, - .log_guest_addr = vq->used_phys, - .flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0, - }; - int r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr); + struct vhost_vring_addr addr; + int r; + memset(&addr, 0, sizeof(struct vhost_vring_addr)); + + if (dev->vhost_ops->vhost_vq_get_addr) { + r = dev->vhost_ops->vhost_vq_get_addr(dev, &addr, vq); + if (r < 0) { + VHOST_OPS_DEBUG("vhost_vq_get_addr failed"); + return -errno; + } + } else { + addr.desc_user_addr = (uint64_t)(unsigned long)vq->desc; + addr.avail_user_addr = (uint64_t)(unsigned long)vq->avail; + addr.used_user_addr = (uint64_t)(unsigned long)vq->used; + } + addr.index = idx; + addr.log_guest_addr = vq->used_phys; + addr.flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0; + r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr); if (r < 0) { VHOST_OPS_DEBUG("vhost_set_vring_addr failed"); return -errno; diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index fa84abac97..bfc24207e2 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -118,6 +118,9 @@ typedef int (*vhost_dev_start_op)(struct vhost_dev *dev, bool started); typedef int (*vhost_vq_get_addr_op)(struct vhost_dev *dev, struct vhost_vring_addr *addr, struct vhost_virtqueue *vq); + +typedef int (*vhost_get_device_id_op)(struct vhost_dev *dev, uint32_t *dev_id); + typedef struct VhostOps { VhostBackendType backend_type; vhost_backend_init vhost_backend_init; @@ -160,6 +163,7 @@ typedef struct VhostOps { vhost_set_inflight_fd_op vhost_set_inflight_fd; vhost_dev_start_op vhost_dev_start; vhost_vq_get_addr_op vhost_vq_get_addr; + vhost_get_device_id_op vhost_get_device_id; } VhostOps; extern const VhostOps user_ops; From f6c99c3438c09706694f7bf1f3057c36d1bd0c21 Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Wed, 1 Jul 2020 22:55:34 +0800 Subject: [PATCH 1897/2595] vhost: introduce new VhostOps vhost_force_iommu This patch introduces new VhostOps vhost_force_iommu callback to force enable features bit VIRTIO_F_IOMMU_PLATFORM. Signed-off-by: Cindy Lu Message-Id: <20200701145538.22333-11-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- include/hw/virtio/vhost-backend.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index bfc24207e2..e7cb8d028c 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -121,6 +121,8 @@ typedef int (*vhost_vq_get_addr_op)(struct vhost_dev *dev, typedef int (*vhost_get_device_id_op)(struct vhost_dev *dev, uint32_t *dev_id); +typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev); + typedef struct VhostOps { VhostBackendType backend_type; vhost_backend_init vhost_backend_init; @@ -164,6 +166,7 @@ typedef struct VhostOps { vhost_dev_start_op vhost_dev_start; vhost_vq_get_addr_op vhost_vq_get_addr; vhost_get_device_id_op vhost_get_device_id; + vhost_force_iommu_op vhost_force_iommu; } VhostOps; extern const VhostOps user_ops; From 7a471694a19d692bd68872d7d256d2086c9c72d4 Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Wed, 1 Jul 2020 22:55:35 +0800 Subject: [PATCH 1898/2595] vhost: implement vhost_force_iommu method use the vhost_force_iommu callback to force enable feature bit VIRTIO_F_IOMMU_PLATFORM Signed-off-by: Cindy Lu Message-Id: <20200701145538.22333-12-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- hw/virtio/vhost.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 1e083a8976..1a1384e7a6 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -810,6 +810,11 @@ static int vhost_dev_set_features(struct vhost_dev *dev, if (!vhost_dev_has_iommu(dev)) { features &= ~(0x1ULL << VIRTIO_F_IOMMU_PLATFORM); } + if (dev->vhost_ops->vhost_force_iommu) { + if (dev->vhost_ops->vhost_force_iommu(dev) == true) { + features |= 0x1ULL << VIRTIO_F_IOMMU_PLATFORM; + } + } r = dev->vhost_ops->vhost_set_features(dev, features); if (r < 0) { VHOST_OPS_DEBUG("vhost_set_features failed"); From 38140cc4d9713dc9af78090503105bf9c82b6bff Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Wed, 1 Jul 2020 22:55:36 +0800 Subject: [PATCH 1899/2595] vhost_net: introduce set_config & get_config This patch introduces set_config & get_config method which allows vhost_net set/get the config to backend Signed-off-by: Cindy Lu Message-Id: <20200701145538.22333-13-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- hw/net/vhost_net-stub.c | 11 +++++++++++ hw/net/vhost_net.c | 10 ++++++++++ include/net/vhost_net.h | 5 +++++ 3 files changed, 26 insertions(+) diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c index aac0e98228..a7f4252630 100644 --- a/hw/net/vhost_net-stub.c +++ b/hw/net/vhost_net-stub.c @@ -52,6 +52,17 @@ uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) return features; } +int vhost_net_get_config(struct vhost_net *net, uint8_t *config, + uint32_t config_len) +{ + return 0; +} +int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, + uint32_t offset, uint32_t size, uint32_t flags) +{ + return 0; +} + void vhost_net_ack_features(struct vhost_net *net, uint64_t features) { } diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 4096d64aaf..4561665f6b 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -110,6 +110,16 @@ uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) return vhost_get_features(&net->dev, vhost_net_get_feature_bits(net), features); } +int vhost_net_get_config(struct vhost_net *net, uint8_t *config, + uint32_t config_len) +{ + return vhost_dev_get_config(&net->dev, config, config_len); +} +int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, + uint32_t offset, uint32_t size, uint32_t flags) +{ + return vhost_dev_set_config(&net->dev, data, offset, size, flags); +} void vhost_net_ack_features(struct vhost_net *net, uint64_t features) { diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h index 77e47398c4..172b0051d8 100644 --- a/include/net/vhost_net.h +++ b/include/net/vhost_net.h @@ -28,6 +28,11 @@ void vhost_net_cleanup(VHostNetState *net); uint64_t vhost_net_get_features(VHostNetState *net, uint64_t features); void vhost_net_ack_features(VHostNetState *net, uint64_t features); +int vhost_net_get_config(struct vhost_net *net, uint8_t *config, + uint32_t config_len); + +int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, + uint32_t offset, uint32_t size, uint32_t flags); bool vhost_net_virtqueue_pending(VHostNetState *net, int n); void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, int idx, bool mask); From b1288dfafbdfb64e86bf9cfa22fa0b399e44e198 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 29 Jun 2020 12:54:18 +0100 Subject: [PATCH 1900/2595] virtiofsd: Terminate capability list capng_updatev is a varargs function that needs a -1 to terminate it, but it was missing. In practice what seems to have been happening is that it's added the capabilities we asked for, then runs into junk on the stack, so if we're unlucky it might be adding some more, but in reality it's failing - but after adding the capabilities we asked for. Fixes: a59feb483b8 ("virtiofsd: only retain file system capabilities") Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Stefan Hajnoczi Acked-by: Vivek Goyal Message-Id: <20200629115420.98443-2-dgilbert@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/passthrough_ll.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index 2ce7c96085..e373e3b36e 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -2598,7 +2598,9 @@ static void setup_capabilities(void) CAP_SETGID, CAP_SETUID, CAP_MKNOD, - CAP_SETFCAP); + CAP_SETFCAP, + -1); + capng_apply(CAPNG_SELECT_BOTH); cap.saved = capng_save_state(); From 55b22a60cc7ac25565a13813deba3d548cb48bd3 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 29 Jun 2020 12:54:19 +0100 Subject: [PATCH 1901/2595] virtiofsd: Check capability calls Check the capability calls worked. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Stefan Hajnoczi Acked-by: Vivek Goyal Message-Id: <20200629115420.98443-3-dgilbert@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/passthrough_ll.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index e373e3b36e..99d562046a 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -2589,7 +2589,7 @@ static void setup_capabilities(void) */ capng_setpid(syscall(SYS_gettid)); capng_clear(CAPNG_SELECT_BOTH); - capng_updatev(CAPNG_ADD, CAPNG_PERMITTED | CAPNG_EFFECTIVE, + if (capng_updatev(CAPNG_ADD, CAPNG_PERMITTED | CAPNG_EFFECTIVE, CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, @@ -2599,11 +2599,21 @@ static void setup_capabilities(void) CAP_SETUID, CAP_MKNOD, CAP_SETFCAP, - -1); + -1)) { + fuse_log(FUSE_LOG_ERR, "%s: capng_updatev failed\n", __func__); + exit(1); + } - capng_apply(CAPNG_SELECT_BOTH); + if (capng_apply(CAPNG_SELECT_BOTH)) { + fuse_log(FUSE_LOG_ERR, "%s: capng_apply failed\n", __func__); + exit(1); + } cap.saved = capng_save_state(); + if (!cap.saved) { + fuse_log(FUSE_LOG_ERR, "%s: capng_save_state failed\n", __func__); + exit(1); + } pthread_mutex_unlock(&cap.mutex); } From 3005c099ef3c6b43213e1454296c1c6556345805 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 29 Jun 2020 12:54:20 +0100 Subject: [PATCH 1902/2595] virtiofsd: Allow addition or removal of capabilities Allow capabilities to be added or removed from the allowed set for the daemon; e.g. default: CapPrm: 00000000880000df CapEff: 00000000880000df -o modcaps=+sys_admin CapPrm: 00000000882000df CapEff: 00000000882000df -o modcaps=+sys_admin:-chown CapPrm: 00000000882000de CapEff: 00000000882000de Signed-off-by: Dr. David Alan Gilbert Message-Id: <20200629115420.98443-4-dgilbert@redhat.com> Acked-by: Vivek Goyal Reviewed-by: Stefan Hajnoczi Signed-off-by: Dr. David Alan Gilbert --- docs/tools/virtiofsd.rst | 5 +++ tools/virtiofsd/helper.c | 2 ++ tools/virtiofsd/passthrough_ll.c | 53 ++++++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst index 378594c422..824e713491 100644 --- a/docs/tools/virtiofsd.rst +++ b/docs/tools/virtiofsd.rst @@ -54,6 +54,11 @@ Options * flock|no_flock - Enable/disable flock. The default is ``no_flock``. + * modcaps=CAPLIST + Modify the list of capabilities allowed; CAPLIST is a colon separated + list of capabilities, each preceded by either + or -, e.g. + ''+sys_admin:-chown''. + * log_level=LEVEL - Print only log messages matching LEVEL or more severe. LEVEL is one of ``err``, ``warn``, ``info``, or ``debug``. The default is ``info``. diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c index 00a1ef666a..3105b6c23a 100644 --- a/tools/virtiofsd/helper.c +++ b/tools/virtiofsd/helper.c @@ -174,6 +174,8 @@ void fuse_cmdline_help(void) " default: no_writeback\n" " -o xattr|no_xattr enable/disable xattr\n" " default: no_xattr\n" + " -o modcaps=CAPLIST Modify the list of capabilities\n" + " e.g. -o modcaps=+sys_admin:-chown\n" " --rlimit-nofile= set maximum number of file descriptors\n" " (0 leaves rlimit unchanged)\n" " default: min(1000000, fs.file-max - 16384)\n" diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index 99d562046a..94e0de2d2b 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -145,6 +145,7 @@ struct lo_data { int posix_lock; int xattr; char *source; + char *modcaps; double timeout; int cache; int timeout_set; @@ -170,6 +171,7 @@ static const struct fuse_opt lo_opts[] = { { "no_posix_lock", offsetof(struct lo_data, posix_lock), 0 }, { "xattr", offsetof(struct lo_data, xattr), 1 }, { "no_xattr", offsetof(struct lo_data, xattr), 0 }, + { "modcaps=%s", offsetof(struct lo_data, modcaps), 0 }, { "timeout=%lf", offsetof(struct lo_data, timeout), 0 }, { "timeout=", offsetof(struct lo_data, timeout_set), 1 }, { "cache=none", offsetof(struct lo_data, cache), CACHE_NONE }, @@ -2570,9 +2572,11 @@ static void setup_mounts(const char *source) /* * Only keep whitelisted capabilities that are needed for file system operation + * The (possibly NULL) modcaps_in string passed in is free'd before exit. */ -static void setup_capabilities(void) +static void setup_capabilities(char *modcaps_in) { + char *modcaps = modcaps_in; pthread_mutex_lock(&cap.mutex); capng_restore_state(&cap.saved); @@ -2604,6 +2608,51 @@ static void setup_capabilities(void) exit(1); } + /* + * The modcaps option is a colon separated list of caps, + * each preceded by either + or -. + */ + while (modcaps) { + capng_act_t action; + int cap; + + char *next = strchr(modcaps, ':'); + if (next) { + *next = '\0'; + next++; + } + + switch (modcaps[0]) { + case '+': + action = CAPNG_ADD; + break; + + case '-': + action = CAPNG_DROP; + break; + + default: + fuse_log(FUSE_LOG_ERR, + "%s: Expecting '+'/'-' in modcaps but found '%c'\n", + __func__, modcaps[0]); + exit(1); + } + cap = capng_name_to_capability(modcaps + 1); + if (cap < 0) { + fuse_log(FUSE_LOG_ERR, "%s: Unknown capability '%s'\n", __func__, + modcaps); + exit(1); + } + if (capng_update(action, CAPNG_PERMITTED | CAPNG_EFFECTIVE, cap)) { + fuse_log(FUSE_LOG_ERR, "%s: capng_update failed for '%s'\n", + __func__, modcaps); + exit(1); + } + + modcaps = next; + } + g_free(modcaps_in); + if (capng_apply(CAPNG_SELECT_BOTH)) { fuse_log(FUSE_LOG_ERR, "%s: capng_apply failed\n", __func__); exit(1); @@ -2627,7 +2676,7 @@ static void setup_sandbox(struct lo_data *lo, struct fuse_session *se, setup_namespaces(lo, se); setup_mounts(lo->source); setup_seccomp(enable_syslog); - setup_capabilities(); + setup_capabilities(g_strdup(lo->modcaps)); } /* Set the maximum number of open file descriptors */ From 617a32f5295ee4efcc17abadcecc3cf482c98e80 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 1 Jul 2020 10:35:57 +0100 Subject: [PATCH 1903/2595] migration: postcopy take proper error return This function returns a boolean success and we're returning -1; lets just use the 'out' error path. Signed-off-by: Dr. David Alan Gilbert Fixes: 58b7c17e226 ("Disable mlock around incoming postcopy") Buglink: https://bugs.launchpad.net/qemu/+bug/1885720 Message-Id: <20200701093557.130096-1-dgilbert@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Dr. David Alan Gilbert --- migration/postcopy-ram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index a36402722b..bef2a3afed 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -389,7 +389,7 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis) */ if (munlockall()) { error_report("%s: munlockall: %s", __func__, strerror(errno)); - return -1; + goto out; } /* From fb6135807fcab4670d69663ac88e88e124348ffd Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 22 Jun 2020 11:20:37 +0800 Subject: [PATCH 1904/2595] migration: Count new_dirty instead of real_dirty real_dirty_pages becomes equal to total ram size after dirty log sync in ram_init_bitmaps, the reason is that the bitmap of ramblock is initialized to be all set, so old path counts them as "real dirty" at beginning. This causes wrong dirty rate and false positive throttling. Signed-off-by: Keqian Zhu Message-Id: <20200622032037.31112-1-zhukeqian1@huawei.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- include/exec/ram_addr.h | 5 +---- migration/ram.c | 8 +++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 7b5c24e928..3ef729a23c 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -442,8 +442,7 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start, static inline uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, ram_addr_t start, - ram_addr_t length, - uint64_t *real_dirty_pages) + ram_addr_t length) { ram_addr_t addr; unsigned long word = BIT_WORD((start + rb->offset) >> TARGET_PAGE_BITS); @@ -469,7 +468,6 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, if (src[idx][offset]) { unsigned long bits = atomic_xchg(&src[idx][offset], 0); unsigned long new_dirty; - *real_dirty_pages += ctpopl(bits); new_dirty = ~dest[k]; dest[k] |= bits; new_dirty &= bits; @@ -502,7 +500,6 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, start + addr + offset, TARGET_PAGE_SIZE, DIRTY_MEMORY_MIGRATION)) { - *real_dirty_pages += 1; long k = (start + addr) >> TARGET_PAGE_BITS; if (!test_and_set_bit(k, dest)) { num_dirty++; diff --git a/migration/ram.c b/migration/ram.c index 069b6e30bc..5554a7d2d8 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -859,9 +859,11 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs, /* Called with RCU critical section */ static void ramblock_sync_dirty_bitmap(RAMState *rs, RAMBlock *rb) { - rs->migration_dirty_pages += - cpu_physical_memory_sync_dirty_bitmap(rb, 0, rb->used_length, - &rs->num_dirty_pages_period); + uint64_t new_dirty_pages = + cpu_physical_memory_sync_dirty_bitmap(rb, 0, rb->used_length); + + rs->migration_dirty_pages += new_dirty_pages; + rs->num_dirty_pages_period += new_dirty_pages; } /** From 461c51ad4275f199d4b6ff400f39701541529e39 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Fri, 3 Jul 2020 16:59:41 +0100 Subject: [PATCH 1905/2595] Add a phy-num property to the i.MX FEC emulator We need a solution to use an Ethernet PHY that is not the first device on the MDIO bus (device 0 on MDIO bus). As an example with the i.MX6UL the NXP SOC has 2 Ethernet devices but only one MDIO bus on which the 2 related PHY are connected but at unique addresses. Signed-off-by: Jean-Christophe Dubois Message-id: a1a5c0e139d1c763194b8020573dcb6025daeefa.1593296112.git.jcd@tribudubois.net Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 24 +++++++++++++++++------- hw/net/trace-events | 4 ++-- include/hw/net/imx_fec.h | 1 + 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index eefedc252d..2c14804041 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -280,12 +280,16 @@ static void imx_phy_reset(IMXFECState *s) static uint32_t imx_phy_read(IMXFECState *s, int reg) { uint32_t val; + uint32_t phy = reg / 32; - if (reg > 31) { - /* we only advertise one phy */ + if (phy != s->phy_num) { + qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad phy num %u\n", + TYPE_IMX_FEC, __func__, phy); return 0; } + reg %= 32; + switch (reg) { case 0: /* Basic Control */ val = s->phy_control; @@ -331,20 +335,25 @@ static uint32_t imx_phy_read(IMXFECState *s, int reg) break; } - trace_imx_phy_read(val, reg); + trace_imx_phy_read(val, phy, reg); return val; } static void imx_phy_write(IMXFECState *s, int reg, uint32_t val) { - trace_imx_phy_write(val, reg); + uint32_t phy = reg / 32; - if (reg > 31) { - /* we only advertise one phy */ + if (phy != s->phy_num) { + qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad phy num %u\n", + TYPE_IMX_FEC, __func__, phy); return; } + reg %= 32; + + trace_imx_phy_write(val, phy, reg); + switch (reg) { case 0: /* Basic Control */ if (val & 0x8000) { @@ -926,7 +935,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, extract32(value, 18, 10))); } else { - /* This a write operation */ + /* This is a write operation */ imx_phy_write(s, extract32(value, 18, 10), extract32(value, 0, 16)); } /* raise the interrupt as the PHY operation is done */ @@ -1315,6 +1324,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) static Property imx_eth_properties[] = { DEFINE_NIC_PROPERTIES(IMXFECState, conf), DEFINE_PROP_UINT32("tx-ring-num", IMXFECState, tx_ring_num, 1), + DEFINE_PROP_UINT32("phy-num", IMXFECState, phy_num, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/net/trace-events b/hw/net/trace-events index e6875c4c0f..5db45456d9 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -413,8 +413,8 @@ i82596_set_multicast(uint16_t count) "Added %d multicast entries" i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION" # imx_fec.c -imx_phy_read(uint32_t val, int reg) "0x%04"PRIx32" <= reg[%d]" -imx_phy_write(uint32_t val, int reg) "0x%04"PRIx32" => reg[%d]" +imx_phy_read(uint32_t val, int phy, int reg) "0x%04"PRIx32" <= phy[%d].reg[%d]" +imx_phy_write(uint32_t val, int phy, int reg) "0x%04"PRIx32" => phy[%d].reg[%d]" imx_phy_update_link(const char *s) "%s" imx_phy_reset(void) "" imx_fec_read_bd(uint64_t addr, int flags, int len, int data) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x" diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 7b3faa4019..9f03034b89 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -268,6 +268,7 @@ typedef struct IMXFECState { uint32_t phy_advertise; uint32_t phy_int; uint32_t phy_int_mask; + uint32_t phy_num; bool is_fec; From 456914afc6348e57441bb80e9f0cc4396b26dcbd Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Fri, 3 Jul 2020 16:59:41 +0100 Subject: [PATCH 1906/2595] Add the ability to select a different PHY for each i.MX6UL FEC interface Add properties to the i.MX6UL processor to be able to select a particular PHY on the MDIO bus for each FEC device. Signed-off-by: Jean-Christophe Dubois Message-id: ea1d604198b6b73ea6521676e45bacfc597aba53.1593296112.git.jcd@tribudubois.net Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/fsl-imx6ul.c | 10 ++++++++++ include/hw/arm/fsl-imx6ul.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index 6446034711..51b2f256ec 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -427,6 +427,9 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_ENET2_TIMER_IRQ, }; + object_property_set_uint(OBJECT(&s->eth[i]), + s->phy_num[i], + "phy-num", &error_abort); object_property_set_uint(OBJECT(&s->eth[i]), FSL_IMX6UL_ETH_NUM_TX_RINGS, "tx-ring-num", &error_abort); @@ -607,10 +610,17 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_OCRAM_ALIAS_ADDR, &s->ocram_alias); } +static Property fsl_imx6ul_properties[] = { + DEFINE_PROP_UINT32("fec1-phy-num", FslIMX6ULState, phy_num[0], 0), + DEFINE_PROP_UINT32("fec2-phy-num", FslIMX6ULState, phy_num[1], 1), + DEFINE_PROP_END_OF_LIST(), +}; + static void fsl_imx6ul_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + device_class_set_props(dc, fsl_imx6ul_properties); dc->realize = fsl_imx6ul_realize; dc->desc = "i.MX6UL SOC"; /* Reason: Uses serial_hds and nd_table in realize() directly */ diff --git a/include/hw/arm/fsl-imx6ul.h b/include/hw/arm/fsl-imx6ul.h index 37c89cc5f9..fcbaf3dc86 100644 --- a/include/hw/arm/fsl-imx6ul.h +++ b/include/hw/arm/fsl-imx6ul.h @@ -87,6 +87,8 @@ typedef struct FslIMX6ULState { MemoryRegion caam; MemoryRegion ocram; MemoryRegion ocram_alias; + + uint32_t phy_num[FSL_IMX6UL_NUM_ETHS]; } FslIMX6ULState; enum FslIMX6ULMemoryMap { From 6552bbc6a3de22f0d975091a07f180e7baf1915b Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Fri, 3 Jul 2020 16:59:41 +0100 Subject: [PATCH 1907/2595] Select MDIO device 2 and 1 as PHY devices for i.MX6UL EVK board. The i.MX6UL EVK 14x14 board uses: - PHY 2 for FEC 1 - PHY 1 for FEC 2 Signed-off-by: Jean-Christophe Dubois Message-id: fb41992126c091a71d76ab3d1898959091f60583.1593296112.git.jcd@tribudubois.net Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mcimx6ul-evk.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c index 2f845cedfc..9033d3f8f3 100644 --- a/hw/arm/mcimx6ul-evk.c +++ b/hw/arm/mcimx6ul-evk.c @@ -40,6 +40,8 @@ static void mcimx6ul_evk_init(MachineState *machine) s = FSL_IMX6UL(object_new(TYPE_FSL_IMX6UL)); object_property_add_child(OBJECT(machine), "soc", OBJECT(s)); + object_property_set_uint(OBJECT(s), 2, "fec1-phy-num", &error_fatal); + object_property_set_uint(OBJECT(s), 1, "fec2-phy-num", &error_fatal); qdev_realize(DEVICE(s), NULL, &error_fatal); memory_region_add_subregion(get_system_memory(), FSL_IMX6UL_MMDC_ADDR, From f78069253ccf25c64e19e9889b98e499336f6c6e Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 3 Jul 2020 16:59:41 +0100 Subject: [PATCH 1908/2595] qdev: Introduce DEFINE_PROP_RESERVED_REGION Introduce a new property defining a reserved region: ::. This will be used to encode reserved IOVA regions. For instance, in virtio-iommu use case, reserved IOVA regions will be passed by the machine code to the virtio-iommu-pci device (an array of those). The type of the reserved region will match the virtio_iommu_probe_resv_mem subtype value: - VIRTIO_IOMMU_RESV_MEM_T_RESERVED (0) - VIRTIO_IOMMU_RESV_MEM_T_MSI (1) on PC/Q35 machine, this will be used to inform the virtio-iommu-pci device it should bypass the MSI region. The reserved region will be: 0xfee00000:0xfeefffff:1. On ARM, we can declare the ITS MSI doorbell as an MSI region to prevent MSIs from being mapped on guest side. Signed-off-by: Eric Auger Reviewed-by: Markus Armbruster Reviewed-by: Michael S. Tsirkin Message-id: 20200629070404.10969-2-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/core/qdev-properties.c | 89 ++++++++++++++++++++++++++++++++++++ include/exec/memory.h | 6 +++ include/hw/qdev-properties.h | 3 ++ include/qemu/typedefs.h | 1 + 4 files changed, 99 insertions(+) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 71f8aca7c6..ca7771f307 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -15,6 +15,7 @@ #include "chardev/char.h" #include "qemu/uuid.h" #include "qemu/units.h" +#include "qemu/cutils.h" void qdev_prop_set_after_realize(DeviceState *dev, const char *name, Error **errp) @@ -578,6 +579,94 @@ const PropertyInfo qdev_prop_macaddr = { .set = set_mac, }; +/* --- Reserved Region --- */ + +/* + * Accepted syntax: + * :: + * where low/high addresses are uint64_t in hexadecimal + * and type is a non-negative decimal integer + */ +static void get_reserved_region(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + ReservedRegion *rr = qdev_get_prop_ptr(dev, prop); + char buffer[64]; + char *p = buffer; + int rc; + + rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u", + rr->low, rr->high, rr->type); + assert(rc < sizeof(buffer)); + + visit_type_str(v, name, &p, errp); +} + +static void set_reserved_region(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + ReservedRegion *rr = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + const char *endptr; + char *str; + int ret; + + if (dev->realized) { + qdev_prop_set_after_realize(dev, name, errp); + return; + } + + visit_type_str(v, name, &str, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + ret = qemu_strtou64(str, &endptr, 16, &rr->low); + if (ret) { + error_setg(errp, "start address of '%s'" + " must be a hexadecimal integer", name); + goto out; + } + if (*endptr != ':') { + goto separator_error; + } + + ret = qemu_strtou64(endptr + 1, &endptr, 16, &rr->high); + if (ret) { + error_setg(errp, "end address of '%s'" + " must be a hexadecimal integer", name); + goto out; + } + if (*endptr != ':') { + goto separator_error; + } + + ret = qemu_strtoui(endptr + 1, &endptr, 10, &rr->type); + if (ret) { + error_setg(errp, "type of '%s'" + " must be a non-negative decimal integer", name); + } + goto out; + +separator_error: + error_setg(errp, "reserved region fields must be separated with ':'"); +out: + g_free(str); + return; +} + +const PropertyInfo qdev_prop_reserved_region = { + .name = "reserved_region", + .description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0", + .get = get_reserved_region, + .set = set_reserved_region, +}; + /* --- on/off/auto --- */ const PropertyInfo qdev_prop_on_off_auto = { diff --git a/include/exec/memory.h b/include/exec/memory.h index 7207025bd4..84ee5b7a01 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -51,6 +51,12 @@ extern bool global_dirty_log; typedef struct MemoryRegionOps MemoryRegionOps; +struct ReservedRegion { + hwaddr low; + hwaddr high; + unsigned type; +}; + typedef struct IOMMUTLBEntry IOMMUTLBEntry; /* See address_space_translate: bit 0 is read, bit 1 is write. */ diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 49c6cd2460..944e3f2e0c 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -19,6 +19,7 @@ extern const PropertyInfo qdev_prop_string; extern const PropertyInfo qdev_prop_chr; extern const PropertyInfo qdev_prop_tpm; extern const PropertyInfo qdev_prop_macaddr; +extern const PropertyInfo qdev_prop_reserved_region; extern const PropertyInfo qdev_prop_on_off_auto; extern const PropertyInfo qdev_prop_multifd_compression; extern const PropertyInfo qdev_prop_losttickpolicy; @@ -184,6 +185,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width; DEFINE_PROP(_n, _s, _f, qdev_prop_drive_iothread, BlockBackend *) #define DEFINE_PROP_MACADDR(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr) +#define DEFINE_PROP_RESERVED_REGION(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_reserved_region, ReservedRegion) #define DEFINE_PROP_ON_OFF_AUTO(_n, _s, _f, _d) \ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_on_off_auto, OnOffAuto) #define DEFINE_PROP_MULTIFD_COMPRESSION(_n, _s, _f, _d) \ diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index ce4a78b687..15f5047bf1 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -58,6 +58,7 @@ typedef struct ISABus ISABus; typedef struct ISADevice ISADevice; typedef struct IsaDma IsaDma; typedef struct MACAddr MACAddr; +typedef struct ReservedRegion ReservedRegion; typedef struct MachineClass MachineClass; typedef struct MachineState MachineState; typedef struct MemoryListener MemoryListener; From 1733eebb9e75b77120b462814f8f9b03ae918a7a Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 3 Jul 2020 16:59:42 +0100 Subject: [PATCH 1909/2595] virtio-iommu: Implement RESV_MEM probe request This patch implements the PROBE request. At the moment, only THE RESV_MEM property is handled. The first goal is to report iommu wide reserved regions such as the MSI regions set by the machine code. On x86 this will be the IOAPIC MSI region, [0xFEE00000 - 0xFEEFFFFF], on ARM this may be the ITS doorbell. In the future we may introduce per device reserved regions. This will be useful when protecting host assigned devices which may expose their own reserved regions Signed-off-by: Eric Auger Reviewed-by: Jean-Philippe Brucker Reviewed-by: Michael S. Tsirkin Message-id: 20200629070404.10969-3-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/virtio/trace-events | 1 + hw/virtio/virtio-iommu.c | 94 ++++++++++++++++++++++++++++++-- include/hw/virtio/virtio-iommu.h | 2 + 3 files changed, 93 insertions(+), 4 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 6427a0047d..23109f69bb 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -74,3 +74,4 @@ virtio_iommu_get_domain(uint32_t domain_id) "Alloc domain=%d" virtio_iommu_put_domain(uint32_t domain_id) "Free domain=%d" virtio_iommu_translate_out(uint64_t virt_addr, uint64_t phys_addr, uint32_t sid) "0x%"PRIx64" -> 0x%"PRIx64 " for sid=%d" virtio_iommu_report_fault(uint8_t reason, uint32_t flags, uint32_t endpoint, uint64_t addr) "FAULT reason=%d flags=%d endpoint=%d address =0x%"PRIx64 +virtio_iommu_fill_resv_property(uint32_t devid, uint8_t subtype, uint64_t start, uint64_t end) "dev= %d, type=%d start=0x%"PRIx64" end=0x%"PRIx64 diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 483883ec1d..2cdaa1969b 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -38,6 +38,7 @@ /* Max size */ #define VIOMMU_DEFAULT_QUEUE_SIZE 256 +#define VIOMMU_PROBE_SIZE 512 typedef struct VirtIOIOMMUDomain { uint32_t id; @@ -378,6 +379,65 @@ static int virtio_iommu_unmap(VirtIOIOMMU *s, return ret; } +static ssize_t virtio_iommu_fill_resv_mem_prop(VirtIOIOMMU *s, uint32_t ep, + uint8_t *buf, size_t free) +{ + struct virtio_iommu_probe_resv_mem prop = {}; + size_t size = sizeof(prop), length = size - sizeof(prop.head), total; + int i; + + total = size * s->nb_reserved_regions; + + if (total > free) { + return -ENOSPC; + } + + for (i = 0; i < s->nb_reserved_regions; i++) { + unsigned subtype = s->reserved_regions[i].type; + + assert(subtype == VIRTIO_IOMMU_RESV_MEM_T_RESERVED || + subtype == VIRTIO_IOMMU_RESV_MEM_T_MSI); + prop.head.type = cpu_to_le16(VIRTIO_IOMMU_PROBE_T_RESV_MEM); + prop.head.length = cpu_to_le16(length); + prop.subtype = subtype; + prop.start = cpu_to_le64(s->reserved_regions[i].low); + prop.end = cpu_to_le64(s->reserved_regions[i].high); + + memcpy(buf, &prop, size); + + trace_virtio_iommu_fill_resv_property(ep, prop.subtype, + prop.start, prop.end); + buf += size; + } + return total; +} + +/** + * virtio_iommu_probe - Fill the probe request buffer with + * the properties the device is able to return + */ +static int virtio_iommu_probe(VirtIOIOMMU *s, + struct virtio_iommu_req_probe *req, + uint8_t *buf) +{ + uint32_t ep_id = le32_to_cpu(req->endpoint); + size_t free = VIOMMU_PROBE_SIZE; + ssize_t count; + + if (!virtio_iommu_mr(s, ep_id)) { + return VIRTIO_IOMMU_S_NOENT; + } + + count = virtio_iommu_fill_resv_mem_prop(s, ep_id, buf, free); + if (count < 0) { + return VIRTIO_IOMMU_S_INVAL; + } + buf += count; + free -= count; + + return VIRTIO_IOMMU_S_OK; +} + static int virtio_iommu_iov_to_req(struct iovec *iov, unsigned int iov_cnt, void *req, size_t req_sz) @@ -407,15 +467,27 @@ virtio_iommu_handle_req(detach) virtio_iommu_handle_req(map) virtio_iommu_handle_req(unmap) +static int virtio_iommu_handle_probe(VirtIOIOMMU *s, + struct iovec *iov, + unsigned int iov_cnt, + uint8_t *buf) +{ + struct virtio_iommu_req_probe req; + int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, sizeof(req)); + + return ret ? ret : virtio_iommu_probe(s, &req, buf); +} + static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq) { VirtIOIOMMU *s = VIRTIO_IOMMU(vdev); struct virtio_iommu_req_head head; struct virtio_iommu_req_tail tail = {}; + size_t output_size = sizeof(tail), sz; VirtQueueElement *elem; unsigned int iov_cnt; struct iovec *iov; - size_t sz; + void *buf = NULL; for (;;) { elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); @@ -452,6 +524,17 @@ static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq) case VIRTIO_IOMMU_T_UNMAP: tail.status = virtio_iommu_handle_unmap(s, iov, iov_cnt); break; + case VIRTIO_IOMMU_T_PROBE: + { + struct virtio_iommu_req_tail *ptail; + + output_size = s->config.probe_size + sizeof(tail); + buf = g_malloc0(output_size); + + ptail = (struct virtio_iommu_req_tail *) + (buf + s->config.probe_size); + ptail->status = virtio_iommu_handle_probe(s, iov, iov_cnt, buf); + } default: tail.status = VIRTIO_IOMMU_S_UNSUPP; } @@ -459,12 +542,13 @@ static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq) out: sz = iov_from_buf(elem->in_sg, elem->in_num, 0, - &tail, sizeof(tail)); - assert(sz == sizeof(tail)); + buf ? buf : &tail, output_size); + assert(sz == output_size); - virtqueue_push(vq, elem, sizeof(tail)); + virtqueue_push(vq, elem, sz); virtio_notify(vdev, vq); g_free(elem); + g_free(buf); } } @@ -667,6 +751,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) s->config.page_size_mask = TARGET_PAGE_MASK; s->config.input_range.end = -1UL; s->config.domain_range.end = 32; + s->config.probe_size = VIOMMU_PROBE_SIZE; virtio_add_feature(&s->features, VIRTIO_RING_F_EVENT_IDX); virtio_add_feature(&s->features, VIRTIO_RING_F_INDIRECT_DESC); @@ -676,6 +761,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) virtio_add_feature(&s->features, VIRTIO_IOMMU_F_MAP_UNMAP); virtio_add_feature(&s->features, VIRTIO_IOMMU_F_BYPASS); virtio_add_feature(&s->features, VIRTIO_IOMMU_F_MMIO); + virtio_add_feature(&s->features, VIRTIO_IOMMU_F_PROBE); qemu_mutex_init(&s->mutex); diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-iommu.h index e653004d7c..49eb105cd8 100644 --- a/include/hw/virtio/virtio-iommu.h +++ b/include/hw/virtio/virtio-iommu.h @@ -53,6 +53,8 @@ typedef struct VirtIOIOMMU { GHashTable *as_by_busptr; IOMMUPciBus *iommu_pcibus_by_bus_num[PCI_BUS_MAX]; PCIBus *primary_bus; + ReservedRegion *reserved_regions; + uint32_t nb_reserved_regions; GTree *domains; QemuMutex mutex; GTree *endpoints; From 0f5a3092eef7a210e0503b561a4c0ccb98705c7f Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 3 Jul 2020 16:59:42 +0100 Subject: [PATCH 1910/2595] virtio-iommu: Handle reserved regions in the translation process When translating an address we need to check if it belongs to a reserved virtual address range. If it does, there are 2 cases: - it belongs to a RESERVED region: the guest should neither use this address in a MAP not instruct the end-point to DMA on them. We report an error - It belongs to an MSI region: we bypass the translation. Signed-off-by: Eric Auger Reviewed-by: Peter Xu Reviewed-by: Jean-Philippe Brucker Reviewed-by: Michael S. Tsirkin Message-id: 20200629070404.10969-4-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/virtio/virtio-iommu.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 2cdaa1969b..b39e836181 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -607,6 +607,7 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr, uint32_t sid, flags; bool bypass_allowed; bool found; + int i; interval.low = addr; interval.high = addr + 1; @@ -640,6 +641,25 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr, goto unlock; } + for (i = 0; i < s->nb_reserved_regions; i++) { + ReservedRegion *reg = &s->reserved_regions[i]; + + if (addr >= reg->low && addr <= reg->high) { + switch (reg->type) { + case VIRTIO_IOMMU_RESV_MEM_T_MSI: + entry.perm = flag; + break; + case VIRTIO_IOMMU_RESV_MEM_T_RESERVED: + default: + virtio_iommu_report_fault(s, VIRTIO_IOMMU_FAULT_R_MAPPING, + VIRTIO_IOMMU_FAULT_F_ADDRESS, + sid, addr); + break; + } + goto unlock; + } + } + if (!ep->domain) { if (!bypass_allowed) { error_report_once("%s %02x:%02x.%01x not attached to any domain", From 8077b8e549cf39d9501fe5b66342ae47abb65058 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 3 Jul 2020 16:59:42 +0100 Subject: [PATCH 1911/2595] virtio-iommu-pci: Add array of Interval properties The machine may need to pass reserved regions to the virtio-iommu-pci device (such as the MSI window on x86 or the MSI doorbells on ARM). So let's add an array of Interval properties. Note: if some reserved regions are already set by the machine code - which should be the case in general -, the length of the property array is already set and prevents the end-user from modifying them. For example, attempting to use: -device virtio-iommu-pci,\ len-reserved-regions=1,reserved-regions[0]=0xfee00000:0xfeefffff:1 would result in the following error message: qemu-system-aarch64: -device virtio-iommu-pci,addr=0xa, len-reserved-regions=1,reserved-regions[0]=0xfee00000:0xfeefffff:1: array size property len-reserved-regions may not be set more than once Otherwise, for example, adding two reserved regions is achieved using the following options: -device virtio-iommu-pci,addr=0xa,len-reserved-regions=2,\ reserved-regions[0]=0xfee00000:0xfeefffff:1,\ reserved-regions[1]=0x1000000:100ffff:1 Signed-off-by: Eric Auger Reviewed-by: Michael S. Tsirkin Reviewed-by: Jean-Philippe Brucker Reviewed-by: Peter Xu Message-id: 20200629070404.10969-5-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/virtio/virtio-iommu-pci.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c index 4588361d6b..592abc9279 100644 --- a/hw/virtio/virtio-iommu-pci.c +++ b/hw/virtio/virtio-iommu-pci.c @@ -33,6 +33,9 @@ struct VirtIOIOMMUPCI { static Property virtio_iommu_pci_properties[] = { DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_ARRAY("reserved-regions", VirtIOIOMMUPCI, + vdev.nb_reserved_regions, vdev.reserved_regions, + qdev_prop_reserved_region, ReservedRegion), DEFINE_PROP_END_OF_LIST(), }; @@ -40,6 +43,7 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { VirtIOIOMMUPCI *dev = VIRTIO_IOMMU_PCI(vpci_dev); DeviceState *vdev = DEVICE(&dev->vdev); + VirtIOIOMMU *s = VIRTIO_IOMMU(vdev); if (!qdev_get_machine_hotplug_handler(DEVICE(vpci_dev))) { MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); @@ -54,6 +58,13 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) "-no-acpi\n"); return; } + for (int i = 0; i < s->nb_reserved_regions; i++) { + if (s->reserved_regions[i].type != VIRTIO_IOMMU_RESV_MEM_T_RESERVED && + s->reserved_regions[i].type != VIRTIO_IOMMU_RESV_MEM_T_MSI) { + error_setg(errp, "reserved region %d has an invalid type", i); + error_append_hint(errp, "Valid values are 0 and 1\n"); + } + } object_property_set_link(OBJECT(dev), OBJECT(pci_get_bus(&vpci_dev->pci_dev)), "primary-bus", &error_abort); From 1b6f99d84f21473cf2d1adab312dd28dd315a083 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 3 Jul 2020 16:59:42 +0100 Subject: [PATCH 1912/2595] hw/arm/virt: Let the virtio-iommu bypass MSIs At the moment the virtio-iommu translates MSI transactions. This behavior is inherited from ARM SMMU. The virt machine code knows where the guest MSI doorbells are so we can easily declare those regions as VIRTIO_IOMMU_RESV_MEM_T_MSI. With that setting the guest will not map MSIs through the IOMMU and those transactions will be simply bypassed. Depending on which MSI controller is in use (ITS or GICV2M), we declare either: - the ITS interrupt translation space (ITS_base + 0x10000), containing the GITS_TRANSLATOR or - The GICV2M single frame, containing the MSI_SETSP_NS register. Signed-off-by: Eric Auger Message-id: 20200629070404.10969-6-eric.auger@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 30 ++++++++++++++++++++++++++++++ include/hw/arm/virt.h | 7 +++++++ 2 files changed, 37 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index af3050bc4b..7922f3c23a 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -600,6 +600,7 @@ static void create_its(VirtMachineState *vms) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_ITS].base); fdt_add_its_gic_node(vms); + vms->msi_controller = VIRT_MSI_CTRL_ITS; } static void create_v2m(VirtMachineState *vms) @@ -620,6 +621,7 @@ static void create_v2m(VirtMachineState *vms) } fdt_add_v2m_gic_node(vms); + vms->msi_controller = VIRT_MSI_CTRL_GICV2M; } static void create_gic(VirtMachineState *vms) @@ -2198,8 +2200,36 @@ out: static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { + VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { virt_memory_pre_plug(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) { + hwaddr db_start = 0, db_end = 0; + char *resv_prop_str; + + switch (vms->msi_controller) { + case VIRT_MSI_CTRL_NONE: + return; + case VIRT_MSI_CTRL_ITS: + /* GITS_TRANSLATER page */ + db_start = base_memmap[VIRT_GIC_ITS].base + 0x10000; + db_end = base_memmap[VIRT_GIC_ITS].base + + base_memmap[VIRT_GIC_ITS].size - 1; + break; + case VIRT_MSI_CTRL_GICV2M: + /* MSI_SETSPI_NS page */ + db_start = base_memmap[VIRT_GIC_V2M].base; + db_end = db_start + base_memmap[VIRT_GIC_V2M].size - 1; + break; + } + resv_prop_str = g_strdup_printf("0x%"PRIx64":0x%"PRIx64":%u", + db_start, db_end, + VIRTIO_IOMMU_RESV_MEM_T_MSI); + + qdev_prop_set_uint32(dev, "len-reserved-regions", 1); + qdev_prop_set_string(dev, "reserved-regions[0]", resv_prop_str); + g_free(resv_prop_str); } } diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 31878ddc72..a18b6b397b 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -96,6 +96,12 @@ typedef enum VirtIOMMUType { VIRT_IOMMU_VIRTIO, } VirtIOMMUType; +typedef enum VirtMSIControllerType { + VIRT_MSI_CTRL_NONE, + VIRT_MSI_CTRL_GICV2M, + VIRT_MSI_CTRL_ITS, +} VirtMSIControllerType; + typedef enum VirtGICType { VIRT_GIC_VERSION_MAX, VIRT_GIC_VERSION_HOST, @@ -136,6 +142,7 @@ typedef struct { OnOffAuto acpi; VirtGICType gic_version; VirtIOMMUType iommu; + VirtMSIControllerType msi_controller; uint16_t virtio_iommu_bdf; struct arm_boot_info bootinfo; MemMapEntry *memmap; From 694bcaa81f41b7fc5e07273debe1dc309b3dcf03 Mon Sep 17 00:00:00 2001 From: Beata Michalska Date: Fri, 3 Jul 2020 16:59:42 +0100 Subject: [PATCH 1913/2595] target/arm: kvm: Handle DABT with no valid ISS On ARMv7 & ARMv8 some load/store instructions might trigger a data abort exception with no valid ISS info to be decoded. The lack of decode info makes it at least tricky to emulate those instruction which is one of the (many) reasons why KVM will not even try to do so. Add support for handling those by requesting KVM to inject external dabt into the quest. Signed-off-by: Beata Michalska Reviewed-by: Andrew Jones Message-id: 20200629114110.30723-2-beata.michalska@linaro.org Signed-off-by: Peter Maydell --- target/arm/kvm.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 7c672c78b8..3a46f54f1f 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -39,6 +39,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { static bool cap_has_mp_state; static bool cap_has_inject_serror_esr; +static bool cap_has_inject_ext_dabt; static ARMHostCPUFeatures arm_host_cpu_features; @@ -245,6 +246,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s) ret = -EINVAL; } + if (kvm_check_extension(s, KVM_CAP_ARM_NISV_TO_USER)) { + if (kvm_vm_enable_cap(s, KVM_CAP_ARM_NISV_TO_USER, 0)) { + error_report("Failed to enable KVM_CAP_ARM_NISV_TO_USER cap"); + } else { + /* Set status for supporting the external dabt injection */ + cap_has_inject_ext_dabt = kvm_check_extension(s, + KVM_CAP_ARM_INJECT_EXT_DABT); + } + } + return ret; } @@ -810,6 +821,42 @@ void kvm_arm_vm_state_change(void *opaque, int running, RunState state) } } +/** + * kvm_arm_handle_dabt_nisv: + * @cs: CPUState + * @esr_iss: ISS encoding (limited) for the exception from Data Abort + * ISV bit set to '0b0' -> no valid instruction syndrome + * @fault_ipa: faulting address for the synchronous data abort + * + * Returns: 0 if the exception has been handled, < 0 otherwise + */ +static int kvm_arm_handle_dabt_nisv(CPUState *cs, uint64_t esr_iss, + uint64_t fault_ipa) +{ + /* + * Request KVM to inject the external data abort into the guest + */ + if (cap_has_inject_ext_dabt) { + struct kvm_vcpu_events events = { }; + /* + * The external data abort event will be handled immediately by KVM + * using the address fault that triggered the exit on given VCPU. + * Requesting injection of the external data abort does not rely + * on any other VCPU state. Therefore, in this particular case, the VCPU + * synchronization can be exceptionally skipped. + */ + events.exception.ext_dabt_pending = 1; + /* KVM_CAP_ARM_INJECT_EXT_DABT implies KVM_CAP_VCPU_EVENTS */ + return kvm_vcpu_ioctl(cs, KVM_SET_VCPU_EVENTS, &events); + } else { + error_report("Data abort exception triggered by guest memory access " + "at physical address: 0x" TARGET_FMT_lx, + (target_ulong)fault_ipa); + error_printf("KVM unable to emulate faulting instruction.\n"); + } + return -1; +} + int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { int ret = 0; @@ -820,6 +867,11 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ret = EXCP_DEBUG; } /* otherwise return to guest */ break; + case KVM_EXIT_ARM_NISV: + /* External DABT with no valid iss to decode */ + ret = kvm_arm_handle_dabt_nisv(cs, run->arm_nisv.esr_iss, + run->arm_nisv.fault_ipa); + break; default: qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n", __func__, run->exit_reason); From 1711bfa5f5b2b108901813f57246c9ff4a44a50f Mon Sep 17 00:00:00 2001 From: Beata Michalska Date: Fri, 3 Jul 2020 16:59:42 +0100 Subject: [PATCH 1914/2595] target/arm: kvm: Handle misconfigured dabt injection Injecting external data abort through KVM might trigger an issue on kernels that do not get updated to include the KVM fix. For those and aarch32 guests, the injected abort gets misconfigured to be an implementation defined exception. This leads to the guest repeatedly re-running the faulting instruction. Add support for handling that case. [ Fixed-by: 018f22f95e8a ('KVM: arm: Fix DFSR setting for non-LPAE aarch32 guests') Fixed-by: 21aecdbd7f3a ('KVM: arm: Make inject_abt32() inject an external abort instead') ] Signed-off-by: Beata Michalska Acked-by: Andrew Jones Message-id: 20200629114110.30723-3-beata.michalska@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu.h | 2 ++ target/arm/kvm.c | 30 ++++++++++++++++++++++++++- target/arm/kvm32.c | 34 ++++++++++++++++++++++++++++++ target/arm/kvm64.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ target/arm/kvm_arm.h | 10 +++++++++ 5 files changed, 124 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index cf99dcca9f..9e8ed423ea 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -573,6 +573,8 @@ typedef struct CPUARMState { uint64_t esr; } serror; + uint8_t ext_dabt_raised; /* Tracking/verifying injection of ext DABT */ + /* State of our input IRQ/FIQ/VIRQ/VFIQ lines */ uint32_t irq_line_state; diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 3a46f54f1f..8bb7318378 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -749,6 +749,29 @@ int kvm_get_vcpu_events(ARMCPU *cpu) void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) { + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + + if (unlikely(env->ext_dabt_raised)) { + /* + * Verifying that the ext DABT has been properly injected, + * otherwise risking indefinitely re-running the faulting instruction + * Covering a very narrow case for kernels 5.5..5.5.4 + * when injected abort was misconfigured to be + * an IMPLEMENTATION DEFINED exception (for 32-bit EL1) + */ + if (!arm_feature(env, ARM_FEATURE_AARCH64) && + unlikely(!kvm_arm_verify_ext_dabt_pending(cs))) { + + error_report("Data abort exception with no valid ISS generated by " + "guest memory access. KVM unable to emulate faulting " + "instruction. Failed to inject an external data abort " + "into the guest."); + abort(); + } + /* Clear the status */ + env->ext_dabt_raised = 0; + } } MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) @@ -833,6 +856,8 @@ void kvm_arm_vm_state_change(void *opaque, int running, RunState state) static int kvm_arm_handle_dabt_nisv(CPUState *cs, uint64_t esr_iss, uint64_t fault_ipa) { + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; /* * Request KVM to inject the external data abort into the guest */ @@ -847,7 +872,10 @@ static int kvm_arm_handle_dabt_nisv(CPUState *cs, uint64_t esr_iss, */ events.exception.ext_dabt_pending = 1; /* KVM_CAP_ARM_INJECT_EXT_DABT implies KVM_CAP_VCPU_EVENTS */ - return kvm_vcpu_ioctl(cs, KVM_SET_VCPU_EVENTS, &events); + if (!kvm_vcpu_ioctl(cs, KVM_SET_VCPU_EVENTS, &events)) { + env->ext_dabt_raised = 1; + return 0; + } } else { error_report("Data abort exception triggered by guest memory access " "at physical address: 0x" TARGET_FMT_lx, diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c index 7b3a19e9ae..0af46b41c8 100644 --- a/target/arm/kvm32.c +++ b/target/arm/kvm32.c @@ -559,3 +559,37 @@ void kvm_arm_pmu_init(CPUState *cs) { qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); } + +#define ARM_REG_DFSR ARM_CP15_REG32(0, 5, 0, 0) +#define ARM_REG_TTBCR ARM_CP15_REG32(0, 2, 0, 2) +/* + *DFSR: + * TTBCR.EAE == 0 + * FS[4] - DFSR[10] + * FS[3:0] - DFSR[3:0] + * TTBCR.EAE == 1 + * FS, bits [5:0] + */ +#define DFSR_FSC(lpae, v) \ + ((lpae) ? ((v) & 0x3F) : (((v) >> 6) | ((v) & 0x1F))) + +#define DFSC_EXTABT(lpae) ((lpae) ? 0x10 : 0x08) + +bool kvm_arm_verify_ext_dabt_pending(CPUState *cs) +{ + uint32_t dfsr_val; + + if (!kvm_get_one_reg(cs, ARM_REG_DFSR, &dfsr_val)) { + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + uint32_t ttbcr; + int lpae = 0; + + if (!kvm_get_one_reg(cs, ARM_REG_TTBCR, &ttbcr)) { + lpae = arm_feature(env, ARM_FEATURE_LPAE) && (ttbcr & TTBCR_EAE); + } + /* The verification is based on FS filed of the DFSR reg only*/ + return (DFSR_FSC(lpae, dfsr_val) == DFSC_EXTABT(lpae)); + } + return false; +} diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index 3dc494aaa7..1169237905 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -1493,3 +1493,52 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit) return false; } + +#define ARM64_REG_ESR_EL1 ARM64_SYS_REG(3, 0, 5, 2, 0) +#define ARM64_REG_TCR_EL1 ARM64_SYS_REG(3, 0, 2, 0, 2) + +/* + * ESR_EL1 + * ISS encoding + * AARCH64: DFSC, bits [5:0] + * AARCH32: + * TTBCR.EAE == 0 + * FS[4] - DFSR[10] + * FS[3:0] - DFSR[3:0] + * TTBCR.EAE == 1 + * FS, bits [5:0] + */ +#define ESR_DFSC(aarch64, lpae, v) \ + ((aarch64 || (lpae)) ? ((v) & 0x3F) \ + : (((v) >> 6) | ((v) & 0x1F))) + +#define ESR_DFSC_EXTABT(aarch64, lpae) \ + ((aarch64) ? 0x10 : (lpae) ? 0x10 : 0x8) + +bool kvm_arm_verify_ext_dabt_pending(CPUState *cs) +{ + uint64_t dfsr_val; + + if (!kvm_get_one_reg(cs, ARM64_REG_ESR_EL1, &dfsr_val)) { + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + int aarch64_mode = arm_feature(env, ARM_FEATURE_AARCH64); + int lpae = 0; + + if (!aarch64_mode) { + uint64_t ttbcr; + + if (!kvm_get_one_reg(cs, ARM64_REG_TCR_EL1, &ttbcr)) { + lpae = arm_feature(env, ARM_FEATURE_LPAE) + && (ttbcr & TTBCR_EAE); + } + } + /* + * The verification here is based on the DFSC bits + * of the ESR_EL1 reg only + */ + return (ESR_DFSC(aarch64_mode, lpae, dfsr_val) == + ESR_DFSC_EXTABT(aarch64_mode, lpae)); + } + return false; +} diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index a4ce4fd93d..adb38514bf 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -449,6 +449,16 @@ bool kvm_arm_hw_debug_active(CPUState *cs); struct kvm_guest_debug_arch; void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr); +/** + * kvm_arm_verify_ext_dabt_pending: + * @cs: CPUState + * + * Verify the fault status code wrt the Ext DABT injection + * + * Returns: true if the fault status code is as expected, false otherwise + */ +bool kvm_arm_verify_ext_dabt_pending(CPUState *cs); + /** * its_class_name: * From 4be3de38efc15eecbc14348356d5b4ca9aa92258 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 3 Jul 2020 16:59:42 +0100 Subject: [PATCH 1915/2595] tests/acpi: remove stale allowed tables Fixes: 93dd625f8bf7 ("tests/acpi: update expected data files") Signed-off-by: Andrew Jones Reviewed-by: Michael S. Tsirkin Reviewed-by: Eric Auger Message-id: 20200629140938.17566-2-drjones@redhat.com Signed-off-by: Peter Maydell --- tests/qtest/bios-tables-test-allowed-diff.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 8992f1f12b..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,19 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/pc/DSDT", -"tests/data/acpi/pc/DSDT.acpihmat", -"tests/data/acpi/pc/DSDT.bridge", -"tests/data/acpi/pc/DSDT.cphp", -"tests/data/acpi/pc/DSDT.dimmpxm", -"tests/data/acpi/pc/DSDT.ipmikcs", -"tests/data/acpi/pc/DSDT.memhp", -"tests/data/acpi/pc/DSDT.numamem", -"tests/data/acpi/q35/DSDT", -"tests/data/acpi/q35/DSDT.acpihmat", -"tests/data/acpi/q35/DSDT.bridge", -"tests/data/acpi/q35/DSDT.cphp", -"tests/data/acpi/q35/DSDT.dimmpxm", -"tests/data/acpi/q35/DSDT.ipmibt", -"tests/data/acpi/q35/DSDT.memhp", -"tests/data/acpi/q35/DSDT.mmio64", -"tests/data/acpi/q35/DSDT.numamem", -"tests/data/acpi/q35/DSDT.tis", From 50824a8c45dc07e0f67b32e65d0190cc2e83c397 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 3 Jul 2020 16:59:43 +0100 Subject: [PATCH 1916/2595] tests/acpi: virt: allow DSDT acpi table changes Signed-off-by: Andrew Jones Reviewed-by: Michael S. Tsirkin Reviewed-by: Eric Auger Message-id: 20200629140938.17566-3-drjones@redhat.com Signed-off-by: Peter Maydell --- tests/qtest/bios-tables-test-allowed-diff.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..32a401ae35 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,4 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/virt/DSDT", +"tests/data/acpi/virt/DSDT.memhp", +"tests/data/acpi/virt/DSDT.numamem", From 2c1fb4d5c0110a994ec6aeb3e57d36fe3aefdad2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 3 Jul 2020 16:59:43 +0100 Subject: [PATCH 1917/2595] hw/arm/virt-acpi-build: Only expose flash on older machine types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flash device is exclusively for the host-controlled firmware, so we should not expose it to the OS. Exposing it risks the OS messing with it, which could break firmware runtime services and surprise the OS when all its changes disappear after reboot. As firmware needs the device and uses DT, we leave the device exposed there. It's up to firmware to remove the nodes from DT before sending it on to the OS. However, there's no need to force firmware to remove tables from ACPI (which it doesn't know how to do anyway), so we simply don't add the tables in the first place. But, as we've been adding the tables for quite some time and don't want to change the default hardware exposed to versioned machines, then we only stop exposing the flash device tables for 5.1 and later machine types. Suggested-by: Ard Biesheuvel Suggested-by: Laszlo Ersek Signed-off-by: Andrew Jones Reviewed-by: Michael S. Tsirkin Reviewed-by: Eric Auger Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laszlo Ersek Message-id: 20200629140938.17566-4-drjones@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 5 ++++- hw/arm/virt.c | 3 +++ include/hw/arm/virt.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 1384a2cf2a..91f0df7b13 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -749,6 +749,7 @@ static void build_fadt_rev5(GArray *table_data, BIOSLinker *linker, static void build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); Aml *scope, *dsdt; MachineState *ms = MACHINE(vms); const MemMapEntry *memmap = vms->memmap; @@ -767,7 +768,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) acpi_dsdt_add_cpus(scope, vms->smp_cpus); acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], (irqmap[VIRT_UART] + ARM_SPI_BASE)); - acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); + if (vmc->acpi_expose_flash) { + acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); + } acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]); acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 7922f3c23a..c78972fb79 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2510,9 +2510,12 @@ DEFINE_VIRT_MACHINE_AS_LATEST(5, 1) static void virt_machine_5_0_options(MachineClass *mc) { + VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); + virt_machine_5_1_options(mc); compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len); mc->numa_mem_supported = true; + vmc->acpi_expose_flash = true; } DEFINE_VIRT_MACHINE(5, 0) diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index a18b6b397b..54bcf17afd 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -125,6 +125,7 @@ typedef struct { bool no_highmem_ecam; bool no_ged; /* Machines < 4.2 has no support for ACPI GED device */ bool kvm_no_adjvtime; + bool acpi_expose_flash; } VirtMachineClass; typedef struct { From 7fb3949d1f2365548a1d0e64e685642309029494 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 3 Jul 2020 16:59:43 +0100 Subject: [PATCH 1918/2595] tests/acpi: virt: update golden masters for DSDT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Differences between disassembled ASL files for DSDT: @@ -5,13 +5,13 @@ * * Disassembling to symbolic ASL+ operators * - * Disassembly of a, Mon Jun 29 09:50:01 2020 + * Disassembly of b, Mon Jun 29 09:50:03 2020 * * Original Table Header: * Signature "DSDT" - * Length 0x000014BB (5307) + * Length 0x00001455 (5205) * Revision 0x02 - * Checksum 0xD1 + * Checksum 0xE1 * OEM ID "BOCHS " * OEM Table ID "BXPCDSDT" * OEM Revision 0x00000001 (1) @@ -45,32 +45,6 @@ }) } - Device (FLS0) - { - Name (_HID, "LNRO0015") // _HID: Hardware ID - Name (_UID, Zero) // _UID: Unique ID - Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings - { - Memory32Fixed (ReadWrite, - 0x00000000, // Address Base - 0x04000000, // Address Length - ) - }) - } - - Device (FLS1) - { - Name (_HID, "LNRO0015") // _HID: Hardware ID - Name (_UID, One) // _UID: Unique ID - Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings - { - Memory32Fixed (ReadWrite, - 0x04000000, // Address Base - 0x04000000, // Address Length - ) - }) - } - Device (FWCF) { Name (_HID, "QEMU0002") // _HID: Hardware ID The other two binaries have the same changes (the removal of the flash devices). Signed-off-by: Andrew Jones Reviewed-by: Michael S. Tsirkin Reviewed-by: Eric Auger Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laszlo Ersek Message-id: 20200629140938.17566-5-drjones@redhat.com Signed-off-by: Peter Maydell --- tests/data/acpi/virt/DSDT | Bin 5307 -> 5205 bytes tests/data/acpi/virt/DSDT.memhp | Bin 6668 -> 6566 bytes tests/data/acpi/virt/DSDT.numamem | Bin 5307 -> 5205 bytes tests/qtest/bios-tables-test-allowed-diff.h | 3 --- 4 files changed, 3 deletions(-) diff --git a/tests/data/acpi/virt/DSDT b/tests/data/acpi/virt/DSDT index d6f5c617881c4247f55d4dcd06581f9693916b2f..e669508d175f1e3ddf355f8a9b0d419266cac8aa 100644 GIT binary patch delta 28 kcmdn3c~yhUCDET2!X{H9}iRuX(-<}f&0DgxFc>n+a delta 156 zcmcbrv0IbNCDP_UpN7hfAE10w?juv9WcH-WSmV$;Hiu7w4t3#`S$E!^1+q9xGPH`KtuzzAr5 LaERl^1zUvy_;n(J diff --git a/tests/data/acpi/virt/DSDT.memhp b/tests/data/acpi/virt/DSDT.memhp index 730e95a46d2cce0af011ffc051d7342beb8f1328..4cb81f692d73526542493a0c4da9c9793cc8366e 100644 GIT binary patch delta 28 kcmeA%S!T@T66_MPOp<|tiD@F2G*jb@iRuX(-^xn@0CHUjRR910 delta 156 zcmZ2x++)J!66_MfBgMeL^l>7WG*kP$iRuaUhHgH=1|0Doo-VvTenI{Q28N~#9Py!^ zEET2!X{H9}iRuX(-<}f&0DgxFc>n+a delta 156 zcmcbrv0IbNCDP_UpN7hfAE10w?juv9WcH-WSmV$;Hiu7w4t3#`S$E!^1+q9xGPH`KtuzzAr5 LaERl^1zUvy_;n(J diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 32a401ae35..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,4 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/virt/DSDT", -"tests/data/acpi/virt/DSDT.memhp", -"tests/data/acpi/virt/DSDT.numamem", From 4b4dc9750a0aa0b9766bd755bf6512a84744ce8a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 3 Jul 2020 16:59:43 +0100 Subject: [PATCH 1919/2595] target/arm: Fix temp double-free in sve ldr/str MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The temp that gets assigned to clean_addr has been allocated with new_tmp_a64, which means that it will be freed at the end of the instruction. Freeing it earlier leads to assertion failure. The loop creates a complication, in which we allocate a new local temp, which does need freeing, and the final code path is shared between the loop and non-loop. Fix this complication by adding new_tmp_a64_local so that the new local temp is freed at the end, and can be treated exactly like the non-loop path. Fixes: bba87d0a0f4 Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200702175605.1987125-1-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 6 ++++++ target/arm/translate-a64.h | 1 + target/arm/translate-sve.c | 8 ++------ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 73d753f11f..8c0764957c 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -461,6 +461,12 @@ TCGv_i64 new_tmp_a64(DisasContext *s) return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_new_i64(); } +TCGv_i64 new_tmp_a64_local(DisasContext *s) +{ + assert(s->tmp_a64_count < TMP_A64_MAX); + return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_local_new_i64(); +} + TCGv_i64 new_tmp_a64_zero(DisasContext *s) { TCGv_i64 t = new_tmp_a64(s); diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index 49e4865918..647f0c74f6 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -30,6 +30,7 @@ void unallocated_encoding(DisasContext *s); } while (0) TCGv_i64 new_tmp_a64(DisasContext *s); +TCGv_i64 new_tmp_a64_local(DisasContext *s); TCGv_i64 new_tmp_a64_zero(DisasContext *s); TCGv_i64 cpu_reg(DisasContext *s, int reg); TCGv_i64 cpu_reg_sp(DisasContext *s, int reg); diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index f318ca265f..08f0fd15b2 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4372,9 +4372,8 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm) /* Copy the clean address into a local temp, live across the loop. */ t0 = clean_addr; - clean_addr = tcg_temp_local_new_i64(); + clean_addr = new_tmp_a64_local(s); tcg_gen_mov_i64(clean_addr, t0); - tcg_temp_free_i64(t0); gen_set_label(loop); @@ -4422,7 +4421,6 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm) tcg_gen_st_i64(t0, cpu_env, vofs + len_align); tcg_temp_free_i64(t0); } - tcg_temp_free_i64(clean_addr); } /* Similarly for stores. */ @@ -4463,9 +4461,8 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) /* Copy the clean address into a local temp, live across the loop. */ t0 = clean_addr; - clean_addr = tcg_temp_local_new_i64(); + clean_addr = new_tmp_a64_local(s); tcg_gen_mov_i64(clean_addr, t0); - tcg_temp_free_i64(t0); gen_set_label(loop); @@ -4509,7 +4506,6 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) } tcg_temp_free_i64(t0); } - tcg_temp_free_i64(clean_addr); } static bool trans_LDR_zri(DisasContext *s, arg_rri *a) From e757db25aa3406e9098ae999a469d56c370f4447 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:43 +0100 Subject: [PATCH 1920/2595] hw/display/bcm2835_fb.c: Initialize all fields of struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In bcm2835_fb_mbox_push(), Coverity complains (CID 1429989) that we pass a pointer to a local struct to another function without initializing all its fields. This is a real bug: bcm2835_fb_reconfigure() copies the whole of our new BCM2385FBConfig struct into s->config, so any fields we don't initialize will corrupt the state of the device. Copy the two fields which we don't want to update (pixo and alpha) from the existing config so we don't accidentally change them. Fixes: cfb7ba983857e40e88 Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200628195436.27582-1-peter.maydell@linaro.org --- hw/display/bcm2835_fb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c index c6263808a2..7c0e5eef2d 100644 --- a/hw/display/bcm2835_fb.c +++ b/hw/display/bcm2835_fb.c @@ -282,6 +282,10 @@ static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value) newconf.base = s->vcram_base | (value & 0xc0000000); newconf.base += BCM2835_FB_OFFSET; + /* Copy fields which we don't want to change from the existing config */ + newconf.pixo = s->config.pixo; + newconf.alpha = s->config.alpha; + bcm2835_fb_validate_config(&newconf); pitch = bcm2835_fb_get_pitch(&newconf); From f6319db25d6f8f46d407f6fd267d74a3ce52cb7a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:43 +0100 Subject: [PATCH 1921/2595] hw/arm/spitz: Detabify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spitz board has been around a long time, and still has a fair number of hard-coded tab characters in it. We're about to do some work on this source file, so start out by expanding out the tabs. This commit is a pure whitespace only change. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-2-peter.maydell@linaro.org --- hw/arm/spitz.c | 156 ++++++++++++++++++++++++------------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index fc18212e68..9eaedab79b 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -34,25 +34,25 @@ #include "cpu.h" #undef REG_FMT -#define REG_FMT "0x%02lx" +#define REG_FMT "0x%02lx" /* Spitz Flash */ -#define FLASH_BASE 0x0c000000 -#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */ -#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */ -#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */ -#define FLASH_ECCCNTR 0x0c /* ECC byte counter */ -#define FLASH_ECCCLRR 0x10 /* Clear ECC */ -#define FLASH_FLASHIO 0x14 /* Flash I/O */ -#define FLASH_FLASHCTL 0x18 /* Flash Control */ +#define FLASH_BASE 0x0c000000 +#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */ +#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */ +#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */ +#define FLASH_ECCCNTR 0x0c /* ECC byte counter */ +#define FLASH_ECCCLRR 0x10 /* Clear ECC */ +#define FLASH_FLASHIO 0x14 /* Flash I/O */ +#define FLASH_FLASHCTL 0x18 /* Flash Control */ -#define FLASHCTL_CE0 (1 << 0) -#define FLASHCTL_CLE (1 << 1) -#define FLASHCTL_ALE (1 << 2) -#define FLASHCTL_WP (1 << 3) -#define FLASHCTL_CE1 (1 << 4) -#define FLASHCTL_RYBY (1 << 5) -#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1) +#define FLASHCTL_CE0 (1 << 0) +#define FLASHCTL_CLE (1 << 1) +#define FLASHCTL_ALE (1 << 2) +#define FLASHCTL_WP (1 << 3) +#define FLASHCTL_CE1 (1 << 4) +#define FLASHCTL_RYBY (1 << 5) +#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1) #define TYPE_SL_NAND "sl-nand" #define SL_NAND(obj) OBJECT_CHECK(SLNANDState, (obj), TYPE_SL_NAND) @@ -74,12 +74,12 @@ static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size) int ryby; switch (addr) { -#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to)) +#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to)) case FLASH_ECCLPLB: return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) | BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7); -#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to)) +#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to)) case FLASH_ECCLPUB: return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) | BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7); @@ -191,8 +191,8 @@ static void sl_nand_realize(DeviceState *dev, Error **errp) /* Spitz Keyboard */ -#define SPITZ_KEY_STROBE_NUM 11 -#define SPITZ_KEY_SENSE_NUM 7 +#define SPITZ_KEY_STROBE_NUM 11 +#define SPITZ_KEY_SENSE_NUM 7 static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = { 12, 17, 91, 34, 36, 38, 39 @@ -214,11 +214,11 @@ static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = { { 0x52, 0x43, 0x01, 0x47, 0x49, -1 , -1 , -1 , -1 , -1 , -1 }, }; -#define SPITZ_GPIO_AK_INT 13 /* Remote control */ -#define SPITZ_GPIO_SYNC 16 /* Sync button */ -#define SPITZ_GPIO_ON_KEY 95 /* Power button */ -#define SPITZ_GPIO_SWA 97 /* Lid */ -#define SPITZ_GPIO_SWB 96 /* Tablet mode */ +#define SPITZ_GPIO_AK_INT 13 /* Remote control */ +#define SPITZ_GPIO_SYNC 16 /* Sync button */ +#define SPITZ_GPIO_ON_KEY 95 /* Power button */ +#define SPITZ_GPIO_SWA 97 /* Lid */ +#define SPITZ_GPIO_SWB 96 /* Tablet mode */ /* The special buttons are mapped to unused keys */ static const int spitz_gpiomap[5] = { @@ -300,7 +300,7 @@ static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode) #define SPITZ_MOD_CTRL (1 << 8) #define SPITZ_MOD_FN (1 << 9) -#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c +#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c static void spitz_keyboard_handler(void *opaque, int keycode) { @@ -308,25 +308,25 @@ static void spitz_keyboard_handler(void *opaque, int keycode) uint16_t code; int mapcode; switch (keycode) { - case 0x2a: /* Left Shift */ + case 0x2a: /* Left Shift */ s->modifiers |= 1; break; case 0xaa: s->modifiers &= ~1; break; - case 0x36: /* Right Shift */ + case 0x36: /* Right Shift */ s->modifiers |= 2; break; case 0xb6: s->modifiers &= ~2; break; - case 0x1d: /* Control */ + case 0x1d: /* Control */ s->modifiers |= 4; break; case 0x9d: s->modifiers &= ~4; break; - case 0x38: /* Alt */ + case 0x38: /* Alt */ s->modifiers |= 8; break; case 0xb8: @@ -536,14 +536,14 @@ static void spitz_keyboard_realize(DeviceState *dev, Error **errp) /* LCD backlight controller */ -#define LCDTG_RESCTL 0x00 -#define LCDTG_PHACTRL 0x01 -#define LCDTG_DUTYCTRL 0x02 -#define LCDTG_POWERREG0 0x03 -#define LCDTG_POWERREG1 0x04 -#define LCDTG_GPOR3 0x05 -#define LCDTG_PICTRL 0x06 -#define LCDTG_POLCTRL 0x07 +#define LCDTG_RESCTL 0x00 +#define LCDTG_PHACTRL 0x01 +#define LCDTG_DUTYCTRL 0x02 +#define LCDTG_POWERREG0 0x03 +#define LCDTG_POWERREG1 0x04 +#define LCDTG_GPOR3 0x05 +#define LCDTG_PICTRL 0x06 +#define LCDTG_POLCTRL 0x07 typedef struct { SSISlave ssidev; @@ -623,12 +623,12 @@ static void spitz_lcdtg_realize(SSISlave *dev, Error **errp) /* SSP devices */ -#define CORGI_SSP_PORT 2 +#define CORGI_SSP_PORT 2 -#define SPITZ_GPIO_LCDCON_CS 53 -#define SPITZ_GPIO_ADS7846_CS 14 -#define SPITZ_GPIO_MAX1111_CS 20 -#define SPITZ_GPIO_TP_INT 11 +#define SPITZ_GPIO_LCDCON_CS 53 +#define SPITZ_GPIO_ADS7846_CS 14 +#define SPITZ_GPIO_MAX1111_CS 20 +#define SPITZ_GPIO_TP_INT 11 static DeviceState *max1111; @@ -659,13 +659,13 @@ static void corgi_ssp_gpio_cs(void *opaque, int line, int level) s->enable[line] = !level; } -#define MAX1111_BATT_VOLT 1 -#define MAX1111_BATT_TEMP 2 -#define MAX1111_ACIN_VOLT 3 +#define MAX1111_BATT_VOLT 1 +#define MAX1111_BATT_TEMP 2 +#define MAX1111_ACIN_VOLT 3 -#define SPITZ_BATTERY_TEMP 0xe0 /* About 2.9V */ -#define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */ -#define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */ +#define SPITZ_BATTERY_TEMP 0xe0 /* About 2.9V */ +#define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */ +#define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */ static void spitz_adc_temp_on(void *opaque, int line, int level) { @@ -735,11 +735,11 @@ static void spitz_microdrive_attach(PXA2xxState *cpu, int slot) /* Wm8750 and Max7310 on I2C */ -#define AKITA_MAX_ADDR 0x18 -#define SPITZ_WM_ADDRL 0x1b -#define SPITZ_WM_ADDRH 0x1a +#define AKITA_MAX_ADDR 0x18 +#define SPITZ_WM_ADDRL 0x1b +#define SPITZ_WM_ADDRH 0x1a -#define SPITZ_GPIO_WM 5 +#define SPITZ_GPIO_WM 5 static void spitz_wm8750_addr(void *opaque, int line, int level) { @@ -806,20 +806,20 @@ static void spitz_out_switch(void *opaque, int line, int level) } } -#define SPITZ_SCP_LED_GREEN 1 -#define SPITZ_SCP_JK_B 2 -#define SPITZ_SCP_CHRG_ON 3 -#define SPITZ_SCP_MUTE_L 4 -#define SPITZ_SCP_MUTE_R 5 -#define SPITZ_SCP_CF_POWER 6 -#define SPITZ_SCP_LED_ORANGE 7 -#define SPITZ_SCP_JK_A 8 -#define SPITZ_SCP_ADC_TEMP_ON 9 -#define SPITZ_SCP2_IR_ON 1 -#define SPITZ_SCP2_AKIN_PULLUP 2 -#define SPITZ_SCP2_BACKLIGHT_CONT 7 -#define SPITZ_SCP2_BACKLIGHT_ON 8 -#define SPITZ_SCP2_MIC_BIAS 9 +#define SPITZ_SCP_LED_GREEN 1 +#define SPITZ_SCP_JK_B 2 +#define SPITZ_SCP_CHRG_ON 3 +#define SPITZ_SCP_MUTE_L 4 +#define SPITZ_SCP_MUTE_R 5 +#define SPITZ_SCP_CF_POWER 6 +#define SPITZ_SCP_LED_ORANGE 7 +#define SPITZ_SCP_JK_A 8 +#define SPITZ_SCP_ADC_TEMP_ON 9 +#define SPITZ_SCP2_IR_ON 1 +#define SPITZ_SCP2_AKIN_PULLUP 2 +#define SPITZ_SCP2_BACKLIGHT_CONT 7 +#define SPITZ_SCP2_BACKLIGHT_ON 8 +#define SPITZ_SCP2_MIC_BIAS 9 static void spitz_scoop_gpio_setup(PXA2xxState *cpu, DeviceState *scp0, DeviceState *scp1) @@ -839,15 +839,15 @@ static void spitz_scoop_gpio_setup(PXA2xxState *cpu, qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]); } -#define SPITZ_GPIO_HSYNC 22 -#define SPITZ_GPIO_SD_DETECT 9 -#define SPITZ_GPIO_SD_WP 81 -#define SPITZ_GPIO_ON_RESET 89 -#define SPITZ_GPIO_BAT_COVER 90 -#define SPITZ_GPIO_CF1_IRQ 105 -#define SPITZ_GPIO_CF1_CD 94 -#define SPITZ_GPIO_CF2_IRQ 106 -#define SPITZ_GPIO_CF2_CD 93 +#define SPITZ_GPIO_HSYNC 22 +#define SPITZ_GPIO_SD_DETECT 9 +#define SPITZ_GPIO_SD_WP 81 +#define SPITZ_GPIO_ON_RESET 89 +#define SPITZ_GPIO_BAT_COVER 90 +#define SPITZ_GPIO_CF1_IRQ 105 +#define SPITZ_GPIO_CF1_CD 94 +#define SPITZ_GPIO_CF2_IRQ 106 +#define SPITZ_GPIO_CF2_CD 93 static int spitz_hsync; @@ -907,8 +907,8 @@ static void spitz_gpio_setup(PXA2xxState *cpu, int slots) /* Board init. */ enum spitz_model_e { spitz, akita, borzoi, terrier }; -#define SPITZ_RAM 0x04000000 -#define SPITZ_ROM 0x00800000 +#define SPITZ_RAM 0x04000000 +#define SPITZ_ROM 0x00800000 static struct arm_boot_info spitz_binfo = { .loader_start = PXA2XX_SDRAM_BASE, From e3d986da47c8163175c6c09b217ae45a935b0933 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:43 +0100 Subject: [PATCH 1922/2595] hw/arm/spitz: Create SpitzMachineClass abstract base class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the four Spitz-family machines (akita, borzoi, spitz, terrier) create a proper abstract class SpitzMachineClass which encapsulates the common behaviour, rather than having them all derive directly from TYPE_MACHINE: * instead of each machine class setting mc->init to a wrapper function which calls spitz_common_init() with parameters, put that data in the SpitzMachineClass and make spitz_common_init the SpitzMachineClass machine-init function * move the settings of mc->block_default_type and mc->ignore_memory_transaction_failures into the SpitzMachineClass class init rather than repeating them in each machine's class init (The motivation is that we're going to want to keep some state in the SpitzMachineState so we can connect GPIOs between devices created in one sub-function of the machine init to devices created in a different sub-function.) Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200628142429.17111-3-peter.maydell@linaro.org --- hw/arm/spitz.c | 91 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 9eaedab79b..c70e912a33 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -33,6 +33,26 @@ #include "exec/address-spaces.h" #include "cpu.h" +enum spitz_model_e { spitz, akita, borzoi, terrier }; + +typedef struct { + MachineClass parent; + enum spitz_model_e model; + int arm_id; +} SpitzMachineClass; + +typedef struct { + MachineState parent; +} SpitzMachineState; + +#define TYPE_SPITZ_MACHINE "spitz-common" +#define SPITZ_MACHINE(obj) \ + OBJECT_CHECK(SpitzMachineState, obj, TYPE_SPITZ_MACHINE) +#define SPITZ_MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SpitzMachineClass, obj, TYPE_SPITZ_MACHINE) +#define SPITZ_MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(SpitzMachineClass, klass, TYPE_SPITZ_MACHINE) + #undef REG_FMT #define REG_FMT "0x%02lx" @@ -905,8 +925,6 @@ static void spitz_gpio_setup(PXA2xxState *cpu, int slots) } /* Board init. */ -enum spitz_model_e { spitz, akita, borzoi, terrier }; - #define SPITZ_RAM 0x04000000 #define SPITZ_ROM 0x00800000 @@ -915,9 +933,10 @@ static struct arm_boot_info spitz_binfo = { .ram_size = 0x04000000, }; -static void spitz_common_init(MachineState *machine, - enum spitz_model_e model, int arm_id) +static void spitz_common_init(MachineState *machine) { + SpitzMachineClass *smc = SPITZ_MACHINE_GET_CLASS(machine); + enum spitz_model_e model = smc->model; PXA2xxState *mpu; DeviceState *scp0, *scp1 = NULL; MemoryRegion *address_space_mem = get_system_memory(); @@ -958,100 +977,100 @@ static void spitz_common_init(MachineState *machine, /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */ spitz_microdrive_attach(mpu, 0); - spitz_binfo.board_id = arm_id; + spitz_binfo.board_id = smc->arm_id; arm_load_kernel(mpu->cpu, machine, &spitz_binfo); sl_bootparam_write(SL_PXA_PARAM_BASE); } -static void spitz_init(MachineState *machine) +static void spitz_common_class_init(ObjectClass *oc, void *data) { - spitz_common_init(machine, spitz, 0x2c9); + MachineClass *mc = MACHINE_CLASS(oc); + + mc->block_default_type = IF_IDE; + mc->ignore_memory_transaction_failures = true; + mc->init = spitz_common_init; } -static void borzoi_init(MachineState *machine) -{ - spitz_common_init(machine, borzoi, 0x33f); -} - -static void akita_init(MachineState *machine) -{ - spitz_common_init(machine, akita, 0x2e8); -} - -static void terrier_init(MachineState *machine) -{ - spitz_common_init(machine, terrier, 0x33f); -} +static const TypeInfo spitz_common_info = { + .name = TYPE_SPITZ_MACHINE, + .parent = TYPE_MACHINE, + .abstract = true, + .instance_size = sizeof(SpitzMachineState), + .class_size = sizeof(SpitzMachineClass), + .class_init = spitz_common_class_init, +}; static void akitapda_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc); mc->desc = "Sharp SL-C1000 (Akita) PDA (PXA270)"; - mc->init = akita_init; - mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0"); + smc->model = akita; + smc->arm_id = 0x2e8; } static const TypeInfo akitapda_type = { .name = MACHINE_TYPE_NAME("akita"), - .parent = TYPE_MACHINE, + .parent = TYPE_SPITZ_MACHINE, .class_init = akitapda_class_init, }; static void spitzpda_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc); mc->desc = "Sharp SL-C3000 (Spitz) PDA (PXA270)"; - mc->init = spitz_init; - mc->block_default_type = IF_IDE; - mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0"); + smc->model = spitz; + smc->arm_id = 0x2c9; } static const TypeInfo spitzpda_type = { .name = MACHINE_TYPE_NAME("spitz"), - .parent = TYPE_MACHINE, + .parent = TYPE_SPITZ_MACHINE, .class_init = spitzpda_class_init, }; static void borzoipda_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc); mc->desc = "Sharp SL-C3100 (Borzoi) PDA (PXA270)"; - mc->init = borzoi_init; - mc->block_default_type = IF_IDE; - mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0"); + smc->model = borzoi; + smc->arm_id = 0x33f; } static const TypeInfo borzoipda_type = { .name = MACHINE_TYPE_NAME("borzoi"), - .parent = TYPE_MACHINE, + .parent = TYPE_SPITZ_MACHINE, .class_init = borzoipda_class_init, }; static void terrierpda_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc); mc->desc = "Sharp SL-C3200 (Terrier) PDA (PXA270)"; - mc->init = terrier_init; - mc->block_default_type = IF_IDE; - mc->ignore_memory_transaction_failures = true; mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5"); + smc->model = terrier; + smc->arm_id = 0x33f; } static const TypeInfo terrierpda_type = { .name = MACHINE_TYPE_NAME("terrier"), - .parent = TYPE_MACHINE, + .parent = TYPE_SPITZ_MACHINE, .class_init = terrierpda_class_init, }; static void spitz_machine_init(void) { + type_register_static(&spitz_common_info); type_register_static(&akitapda_type); type_register_static(&spitzpda_type); type_register_static(&borzoipda_type); From 39854425d7bb4a8b95829ac50ab92ff338eb7851 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:44 +0100 Subject: [PATCH 1923/2595] hw/arm/spitz: Keep pointers to MPU and SSI devices in SpitzMachineState Keep pointers to the MPU and the SSI devices in SpitzMachineState. We're going to want to make GPIO connections between some of the SSI devices and the SCPs, so we want to keep hold of a pointer to those; putting the MPU into the struct allows us to pass just one thing to spitz_ssp_attach() rather than two. We have to retain the setting of the global "max1111" variable for the moment as it is used in spitz_adc_temp_on(); later in this series of commits we will be able to remove it. Signed-off-by: Peter Maydell Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-4-peter.maydell@linaro.org --- hw/arm/spitz.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index c70e912a33..f48e966c04 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -43,6 +43,11 @@ typedef struct { typedef struct { MachineState parent; + PXA2xxState *mpu; + DeviceState *mux; + DeviceState *lcdtg; + DeviceState *ads7846; + DeviceState *max1111; } SpitzMachineState; #define TYPE_SPITZ_MACHINE "spitz-common" @@ -709,34 +714,33 @@ static void corgi_ssp_realize(SSISlave *d, Error **errp) s->bus[2] = ssi_create_bus(dev, "ssi2"); } -static void spitz_ssp_attach(PXA2xxState *cpu) +static void spitz_ssp_attach(SpitzMachineState *sms) { - DeviceState *mux; - DeviceState *dev; void *bus; - mux = ssi_create_slave(cpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp"); + sms->mux = ssi_create_slave(sms->mpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp"); - bus = qdev_get_child_bus(mux, "ssi0"); - ssi_create_slave(bus, "spitz-lcdtg"); + bus = qdev_get_child_bus(sms->mux, "ssi0"); + sms->lcdtg = ssi_create_slave(bus, "spitz-lcdtg"); - bus = qdev_get_child_bus(mux, "ssi1"); - dev = ssi_create_slave(bus, "ads7846"); - qdev_connect_gpio_out(dev, 0, - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT)); + bus = qdev_get_child_bus(sms->mux, "ssi1"); + sms->ads7846 = ssi_create_slave(bus, "ads7846"); + qdev_connect_gpio_out(sms->ads7846, 0, + qdev_get_gpio_in(sms->mpu->gpio, SPITZ_GPIO_TP_INT)); - bus = qdev_get_child_bus(mux, "ssi2"); - max1111 = ssi_create_slave(bus, "max1111"); - max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT); - max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); - max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN); + bus = qdev_get_child_bus(sms->mux, "ssi2"); + sms->max1111 = ssi_create_slave(bus, "max1111"); + max1111 = sms->max1111; + max111x_set_input(sms->max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT); + max111x_set_input(sms->max1111, MAX1111_BATT_TEMP, 0); + max111x_set_input(sms->max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN); - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_LCDCON_CS, - qdev_get_gpio_in(mux, 0)); - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ADS7846_CS, - qdev_get_gpio_in(mux, 1)); - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_MAX1111_CS, - qdev_get_gpio_in(mux, 2)); + qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_LCDCON_CS, + qdev_get_gpio_in(sms->mux, 0)); + qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_ADS7846_CS, + qdev_get_gpio_in(sms->mux, 1)); + qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_MAX1111_CS, + qdev_get_gpio_in(sms->mux, 2)); } /* CF Microdrive */ @@ -936,6 +940,7 @@ static struct arm_boot_info spitz_binfo = { static void spitz_common_init(MachineState *machine) { SpitzMachineClass *smc = SPITZ_MACHINE_GET_CLASS(machine); + SpitzMachineState *sms = SPITZ_MACHINE(machine); enum spitz_model_e model = smc->model; PXA2xxState *mpu; DeviceState *scp0, *scp1 = NULL; @@ -945,6 +950,7 @@ static void spitz_common_init(MachineState *machine) /* Setup CPU & memory */ mpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, machine->cpu_type); + sms->mpu = mpu; sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M); @@ -954,7 +960,7 @@ static void spitz_common_init(MachineState *machine) /* Setup peripherals */ spitz_keyboard_register(mpu); - spitz_ssp_attach(mpu); + spitz_ssp_attach(sms); scp0 = sysbus_create_simple("scoop", 0x10800000, NULL); if (model != akita) { From ffe7f90698099f0f702154492df05cf6a14c6b62 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:44 +0100 Subject: [PATCH 1924/2595] hw/arm/spitz: Keep pointers to scp0, scp1 in SpitzMachineState Keep pointers to scp0, scp1 in SpitzMachineState, and just pass that to spitz_scoop_gpio_setup(). (We'll want to use some of the other fields in SpitzMachineState in that function in the next commit.) Signed-off-by: Peter Maydell Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-5-peter.maydell@linaro.org --- hw/arm/spitz.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index f48e966c04..69bc2b3fa1 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -48,6 +48,8 @@ typedef struct { DeviceState *lcdtg; DeviceState *ads7846; DeviceState *max1111; + DeviceState *scp0; + DeviceState *scp1; } SpitzMachineState; #define TYPE_SPITZ_MACHINE "spitz-common" @@ -845,22 +847,23 @@ static void spitz_out_switch(void *opaque, int line, int level) #define SPITZ_SCP2_BACKLIGHT_ON 8 #define SPITZ_SCP2_MIC_BIAS 9 -static void spitz_scoop_gpio_setup(PXA2xxState *cpu, - DeviceState *scp0, DeviceState *scp1) +static void spitz_scoop_gpio_setup(SpitzMachineState *sms) { - qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8); + qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, sms->mpu, 8); - qdev_connect_gpio_out(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]); - qdev_connect_gpio_out(scp0, SPITZ_SCP_JK_B, outsignals[1]); - qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]); - qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]); + qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_CHRG_ON, outsignals[0]); + qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_JK_B, outsignals[1]); + qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_GREEN, outsignals[2]); + qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]); - if (scp1) { - qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]); - qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]); + if (sms->scp1) { + qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_CONT, + outsignals[4]); + qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_ON, + outsignals[5]); } - qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]); + qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]); } #define SPITZ_GPIO_HSYNC 22 @@ -943,7 +946,6 @@ static void spitz_common_init(MachineState *machine) SpitzMachineState *sms = SPITZ_MACHINE(machine); enum spitz_model_e model = smc->model; PXA2xxState *mpu; - DeviceState *scp0, *scp1 = NULL; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); @@ -962,12 +964,14 @@ static void spitz_common_init(MachineState *machine) spitz_ssp_attach(sms); - scp0 = sysbus_create_simple("scoop", 0x10800000, NULL); + sms->scp0 = sysbus_create_simple("scoop", 0x10800000, NULL); if (model != akita) { - scp1 = sysbus_create_simple("scoop", 0x08800040, NULL); + sms->scp1 = sysbus_create_simple("scoop", 0x08800040, NULL); + } else { + sms->scp1 = NULL; } - spitz_scoop_gpio_setup(mpu, scp0, scp1); + spitz_scoop_gpio_setup(sms); spitz_gpio_setup(mpu, (model == akita) ? 1 : 2); From 2e354c028a282b1bae56154ed52ac80746eb24b3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:44 +0100 Subject: [PATCH 1925/2595] hw/arm/spitz: Implement inbound GPIO lines for bit5 and power signals Currently the Spitz board uses a nasty hack for the GPIO lines that pass "bit5" and "power" information to the LCD controller: the lcdtg realize function sets a global variable to point to the instance it just realized, and then the functions spitz_bl_power() and spitz_bl_bit5() use that to find the device they are changing the internal state of. There is a comment reading: FIXME: Implement GPIO properly and remove this hack. which was added in 2009. Implement GPIO properly and remove this hack. Signed-off-by: Peter Maydell Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-6-peter.maydell@linaro.org --- hw/arm/spitz.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 69bc2b3fa1..11e413723f 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -586,12 +586,9 @@ static void spitz_bl_update(SpitzLCDTG *s) zaurus_printf("LCD Backlight now off\n"); } -/* FIXME: Implement GPIO properly and remove this hack. */ -static SpitzLCDTG *spitz_lcdtg; - static inline void spitz_bl_bit5(void *opaque, int line, int level) { - SpitzLCDTG *s = spitz_lcdtg; + SpitzLCDTG *s = opaque; int prev = s->bl_intensity; if (level) @@ -605,7 +602,7 @@ static inline void spitz_bl_bit5(void *opaque, int line, int level) static inline void spitz_bl_power(void *opaque, int line, int level) { - SpitzLCDTG *s = spitz_lcdtg; + SpitzLCDTG *s = opaque; s->bl_power = !!level; spitz_bl_update(s); } @@ -639,13 +636,16 @@ static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value) return 0; } -static void spitz_lcdtg_realize(SSISlave *dev, Error **errp) +static void spitz_lcdtg_realize(SSISlave *ssi, Error **errp) { - SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev); + SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, ssi); + DeviceState *dev = DEVICE(s); - spitz_lcdtg = s; s->bl_power = 0; s->bl_intensity = 0x20; + + qdev_init_gpio_in_named(dev, spitz_bl_bit5, "bl_bit5", 1); + qdev_init_gpio_in_named(dev, spitz_bl_power, "bl_power", 1); } /* SSP devices */ @@ -820,15 +820,11 @@ static void spitz_out_switch(void *opaque, int line, int level) case 3: zaurus_printf("Orange LED %s.\n", level ? "on" : "off"); break; - case 4: - spitz_bl_bit5(opaque, line, level); - break; - case 5: - spitz_bl_power(opaque, line, level); - break; case 6: spitz_adc_temp_on(opaque, line, level); break; + default: + g_assert_not_reached(); } } @@ -858,9 +854,9 @@ static void spitz_scoop_gpio_setup(SpitzMachineState *sms) if (sms->scp1) { qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_CONT, - outsignals[4]); + qdev_get_gpio_in_named(sms->lcdtg, "bl_bit5", 0)); qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_ON, - outsignals[5]); + qdev_get_gpio_in_named(sms->lcdtg, "bl_power", 0)); } qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]); From b064d51f6022c49ceab73c46e84ae05f9f704732 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:44 +0100 Subject: [PATCH 1926/2595] hw/misc/max111x: provide QOM properties for setting initial values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some QOM properties to the max111x ADC device to allow the initial values to be configured. Currently this is done by board code calling max111x_set_input() after it creates the device, which doesn't work on system reset. This requires us to implement a reset method for this device, so while we're doing that make sure we reset the other parts of the device state. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-7-peter.maydell@linaro.org --- hw/misc/max111x.c | 57 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c index 2b87bdee5b..d0e5534e4f 100644 --- a/hw/misc/max111x.c +++ b/hw/misc/max111x.c @@ -15,11 +15,15 @@ #include "hw/ssi/ssi.h" #include "migration/vmstate.h" #include "qemu/module.h" +#include "hw/qdev-properties.h" typedef struct { SSISlave parent_obj; qemu_irq interrupt; + /* Values of inputs at system reset (settable by QOM property) */ + uint8_t reset_input[8]; + uint8_t tb1, rb2, rb3; int cycle; @@ -135,16 +139,6 @@ static int max111x_init(SSISlave *d, int inputs) qdev_init_gpio_out(dev, &s->interrupt, 1); s->inputs = inputs; - /* TODO: add a user interface for setting these */ - s->input[0] = 0xf0; - s->input[1] = 0xe0; - s->input[2] = 0xd0; - s->input[3] = 0xc0; - s->input[4] = 0xb0; - s->input[5] = 0xa0; - s->input[6] = 0x90; - s->input[7] = 0x80; - s->com = 0; vmstate_register(VMSTATE_IF(dev), VMSTATE_INSTANCE_ID_ANY, &vmstate_max111x, s); @@ -168,11 +162,50 @@ void max111x_set_input(DeviceState *dev, int line, uint8_t value) s->input[line] = value; } +static void max111x_reset(DeviceState *dev) +{ + MAX111xState *s = MAX_111X(dev); + int i; + + for (i = 0; i < s->inputs; i++) { + s->input[i] = s->reset_input[i]; + } + s->com = 0; + s->tb1 = 0; + s->rb2 = 0; + s->rb3 = 0; + s->cycle = 0; +} + +static Property max1110_properties[] = { + /* Reset values for ADC inputs */ + DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0), + DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0), + DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0), + DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0), + DEFINE_PROP_END_OF_LIST(), +}; + +static Property max1111_properties[] = { + /* Reset values for ADC inputs */ + DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0), + DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0), + DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0), + DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0), + DEFINE_PROP_UINT8("input4", MAX111xState, reset_input[4], 0xb0), + DEFINE_PROP_UINT8("input5", MAX111xState, reset_input[5], 0xa0), + DEFINE_PROP_UINT8("input6", MAX111xState, reset_input[6], 0x90), + DEFINE_PROP_UINT8("input7", MAX111xState, reset_input[7], 0x80), + DEFINE_PROP_END_OF_LIST(), +}; + static void max111x_class_init(ObjectClass *klass, void *data) { SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); k->transfer = max111x_transfer; + dc->reset = max111x_reset; } static const TypeInfo max111x_info = { @@ -186,8 +219,10 @@ static const TypeInfo max111x_info = { static void max1110_class_init(ObjectClass *klass, void *data) { SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); k->realize = max1110_realize; + device_class_set_props(dc, max1110_properties); } static const TypeInfo max1110_info = { @@ -199,8 +234,10 @@ static const TypeInfo max1110_info = { static void max1111_class_init(ObjectClass *klass, void *data) { SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); k->realize = max1111_realize; + device_class_set_props(dc, max1111_properties); } static const TypeInfo max1111_info = { From 40d9d2f7682c789404ed5b249012ac44f9e6ea8f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:44 +0100 Subject: [PATCH 1927/2595] hw/misc/max111x: Don't use vmstate_register() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The max111x is a proper qdev device; we can use dc->vmsd rather than directly calling vmstate_register(). It's possible that this is a migration compat break, but the only boards that use this device are the spitz-family ('akita', 'borzoi', 'spitz', 'terrier'). Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-8-peter.maydell@linaro.org --- hw/misc/max111x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c index d0e5534e4f..abddfa3c66 100644 --- a/hw/misc/max111x.c +++ b/hw/misc/max111x.c @@ -140,8 +140,6 @@ static int max111x_init(SSISlave *d, int inputs) s->inputs = inputs; - vmstate_register(VMSTATE_IF(dev), VMSTATE_INSTANCE_ID_ANY, - &vmstate_max111x, s); return 0; } @@ -206,6 +204,7 @@ static void max111x_class_init(ObjectClass *klass, void *data) k->transfer = max111x_transfer; dc->reset = max111x_reset; + dc->vmsd = &vmstate_max111x; } static const TypeInfo max111x_info = { From 581e109d5836f5166d15a01c43e18632f93357c5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:44 +0100 Subject: [PATCH 1928/2595] ssi: Add ssi_realize_and_unref() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an ssi_realize_and_unref(), for the benefit of callers who want to be able to create an SSI device, set QOM properties on it, and then do the realize-and-unref afterwards. The API works on the same principle as the recently added qdev_realize_and_undef(), sysbus_realize_and_undef(), etc. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-9-peter.maydell@linaro.org --- hw/ssi/ssi.c | 7 ++++++- include/hw/ssi/ssi.h | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 67b48c31cd..a35d7ebb26 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -90,11 +90,16 @@ static const TypeInfo ssi_slave_info = { .abstract = true, }; +bool ssi_realize_and_unref(DeviceState *dev, SSIBus *bus, Error **errp) +{ + return qdev_realize_and_unref(dev, &bus->parent_obj, errp); +} + DeviceState *ssi_create_slave(SSIBus *bus, const char *name) { DeviceState *dev = qdev_new(name); - qdev_realize_and_unref(dev, &bus->parent_obj, &error_fatal); + ssi_realize_and_unref(dev, bus, &error_fatal); return dev; } diff --git a/include/hw/ssi/ssi.h b/include/hw/ssi/ssi.h index 93f2b8b0be..4be5325e65 100644 --- a/include/hw/ssi/ssi.h +++ b/include/hw/ssi/ssi.h @@ -79,6 +79,32 @@ extern const VMStateDescription vmstate_ssi_slave; } DeviceState *ssi_create_slave(SSIBus *bus, const char *name); +/** + * ssi_realize_and_unref: realize and unref an SSI slave device + * @dev: SSI slave device to realize + * @bus: SSI bus to put it on + * @errp: error pointer + * + * Call 'realize' on @dev, put it on the specified @bus, and drop the + * reference to it. Errors are reported via @errp and by returning + * false. + * + * This function is useful if you have created @dev via qdev_new() + * (which takes a reference to the device it returns to you), so that + * you can set properties on it before realizing it. If you don't need + * to set properties then ssi_create_slave() is probably better (as it + * does the create, init and realize in one step). + * + * If you are embedding the SSI slave into another QOM device and + * initialized it via some variant on object_initialize_child() then + * do not use this function, because that family of functions arrange + * for the only reference to the child device to be held by the parent + * via the child<> property, and so the reference-count-drop done here + * would be incorrect. (Instead you would want ssi_realize(), which + * doesn't currently exist but would be trivial to create if we had + * any code that wanted it.) + */ +bool ssi_realize_and_unref(DeviceState *dev, SSIBus *bus, Error **errp); /* Master interface. */ SSIBus *ssi_create_bus(DeviceState *parent, const char *name); From 4aed7b51c298e5497ff0d3d7d584f3c53acc9f3f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:44 +0100 Subject: [PATCH 1929/2595] hw/arm/spitz: Use max111x properties to set initial values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the new max111x qdev properties to set the initial input values rather than calling max111x_set_input(); this means that on system reset the inputs will correctly return to their initial values. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200628142429.17111-10-peter.maydell@linaro.org --- hw/arm/spitz.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 11e413723f..93a25edcb5 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -731,11 +731,14 @@ static void spitz_ssp_attach(SpitzMachineState *sms) qdev_get_gpio_in(sms->mpu->gpio, SPITZ_GPIO_TP_INT)); bus = qdev_get_child_bus(sms->mux, "ssi2"); - sms->max1111 = ssi_create_slave(bus, "max1111"); + sms->max1111 = qdev_new("max1111"); max1111 = sms->max1111; - max111x_set_input(sms->max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT); - max111x_set_input(sms->max1111, MAX1111_BATT_TEMP, 0); - max111x_set_input(sms->max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN); + qdev_prop_set_uint8(sms->max1111, "input1" /* BATT_VOLT */, + SPITZ_BATTERY_VOLT); + qdev_prop_set_uint8(sms->max1111, "input2" /* BATT_TEMP */, 0); + qdev_prop_set_uint8(sms->max1111, "input3" /* ACIN_VOLT */, + SPITZ_CHARGEON_ACIN); + ssi_realize_and_unref(sms->max1111, bus, &error_fatal); qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_LCDCON_CS, qdev_get_gpio_in(sms->mux, 0)); From 871f82722ccddf8886acf19989289072bc73e873 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:45 +0100 Subject: [PATCH 1930/2595] hw/misc/max111x: Use GPIO lines rather than max111x_set_input() The max111x ADC device model allows other code to set the level on the 8 ADC inputs using the max111x_set_input() function. Replace this with generic qdev GPIO inputs, which also allow inputs to be set to arbitrary values. Using GPIO lines will make it easier for board code to wire things up, so that if device A wants to set the ADC input it doesn't need to have a direct pointer to the max111x but can just set that value on its output GPIO, which is then wired up by the board to the appropriate max111x input. Signed-off-by: Peter Maydell Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-11-peter.maydell@linaro.org --- hw/arm/spitz.c | 9 +++++---- hw/misc/max111x.c | 16 +++++++++------- include/hw/ssi/ssi.h | 3 --- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 93a25edcb5..fa592aad6d 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -696,13 +696,14 @@ static void corgi_ssp_gpio_cs(void *opaque, int line, int level) static void spitz_adc_temp_on(void *opaque, int line, int level) { + int batt_temp; + if (!max1111) return; - if (level) - max111x_set_input(max1111, MAX1111_BATT_TEMP, SPITZ_BATTERY_TEMP); - else - max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); + batt_temp = level ? SPITZ_BATTERY_TEMP : 0; + + qemu_set_irq(qdev_get_gpio_in(max1111, MAX1111_BATT_TEMP), batt_temp); } static void corgi_ssp_realize(SSISlave *d, Error **errp) diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c index abddfa3c66..3a5cb83844 100644 --- a/hw/misc/max111x.c +++ b/hw/misc/max111x.c @@ -131,12 +131,21 @@ static const VMStateDescription vmstate_max111x = { } }; +static void max111x_input_set(void *opaque, int line, int value) +{ + MAX111xState *s = MAX_111X(opaque); + + assert(line >= 0 && line < s->inputs); + s->input[line] = value; +} + static int max111x_init(SSISlave *d, int inputs) { DeviceState *dev = DEVICE(d); MAX111xState *s = MAX_111X(dev); qdev_init_gpio_out(dev, &s->interrupt, 1); + qdev_init_gpio_in(dev, max111x_input_set, inputs); s->inputs = inputs; @@ -153,13 +162,6 @@ static void max1111_realize(SSISlave *dev, Error **errp) max111x_init(dev, 4); } -void max111x_set_input(DeviceState *dev, int line, uint8_t value) -{ - MAX111xState *s = MAX_111X(dev); - assert(line >= 0 && line < s->inputs); - s->input[line] = value; -} - static void max111x_reset(DeviceState *dev) { MAX111xState *s = MAX_111X(dev); diff --git a/include/hw/ssi/ssi.h b/include/hw/ssi/ssi.h index 4be5325e65..5fd411f2e4 100644 --- a/include/hw/ssi/ssi.h +++ b/include/hw/ssi/ssi.h @@ -111,7 +111,4 @@ SSIBus *ssi_create_bus(DeviceState *parent, const char *name); uint32_t ssi_transfer(SSIBus *bus, uint32_t val); -/* max111x.c */ -void max111x_set_input(DeviceState *dev, int line, uint8_t value); - #endif From 3029681235b492026739b831a24a75d1e94e7be5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:45 +0100 Subject: [PATCH 1931/2595] hw/misc/max111x: Create header file for documentation, TYPE_ macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a header file for the hw/misc/max111x device, in the usual modern style for QOM devices: * definition of the TYPE_ constants and macros * definition of the device's state struct so that it can be embedded in other structs if desired * documentation of the interface This allows us to use TYPE_MAX_1111 in the spitz.c code rather than the string "max1111". Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200628142429.17111-12-peter.maydell@linaro.org --- MAINTAINERS | 1 + hw/arm/spitz.c | 3 ++- hw/misc/max111x.c | 24 +---------------- include/hw/misc/max111x.h | 56 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 24 deletions(-) create mode 100644 include/hw/misc/max111x.h diff --git a/MAINTAINERS b/MAINTAINERS index dec252f38b..c31c878c63 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -787,6 +787,7 @@ F: hw/gpio/max7310.c F: hw/gpio/zaurus.c F: hw/misc/mst_fpga.c F: hw/misc/max111x.c +F: include/hw/misc/max111x.h F: include/hw/arm/pxa.h F: include/hw/arm/sharpsl.h F: include/hw/display/tc6393xb.h diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index fa592aad6d..1400a56729 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -29,6 +29,7 @@ #include "audio/audio.h" #include "hw/boards.h" #include "hw/sysbus.h" +#include "hw/misc/max111x.h" #include "migration/vmstate.h" #include "exec/address-spaces.h" #include "cpu.h" @@ -732,7 +733,7 @@ static void spitz_ssp_attach(SpitzMachineState *sms) qdev_get_gpio_in(sms->mpu->gpio, SPITZ_GPIO_TP_INT)); bus = qdev_get_child_bus(sms->mux, "ssi2"); - sms->max1111 = qdev_new("max1111"); + sms->max1111 = qdev_new(TYPE_MAX_1111); max1111 = sms->max1111; qdev_prop_set_uint8(sms->max1111, "input1" /* BATT_VOLT */, SPITZ_BATTERY_VOLT); diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c index 3a5cb83844..7e6723f343 100644 --- a/hw/misc/max111x.c +++ b/hw/misc/max111x.c @@ -11,34 +11,12 @@ */ #include "qemu/osdep.h" +#include "hw/misc/max111x.h" #include "hw/irq.h" -#include "hw/ssi/ssi.h" #include "migration/vmstate.h" #include "qemu/module.h" #include "hw/qdev-properties.h" -typedef struct { - SSISlave parent_obj; - - qemu_irq interrupt; - /* Values of inputs at system reset (settable by QOM property) */ - uint8_t reset_input[8]; - - uint8_t tb1, rb2, rb3; - int cycle; - - uint8_t input[8]; - int inputs, com; -} MAX111xState; - -#define TYPE_MAX_111X "max111x" - -#define MAX_111X(obj) \ - OBJECT_CHECK(MAX111xState, (obj), TYPE_MAX_111X) - -#define TYPE_MAX_1110 "max1110" -#define TYPE_MAX_1111 "max1111" - /* Control-byte bitfields */ #define CB_PD0 (1 << 0) #define CB_PD1 (1 << 1) diff --git a/include/hw/misc/max111x.h b/include/hw/misc/max111x.h new file mode 100644 index 0000000000..af7f1017ef --- /dev/null +++ b/include/hw/misc/max111x.h @@ -0,0 +1,56 @@ +/* + * Maxim MAX1110/1111 ADC chip emulation. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GNU GPLv2. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#ifndef HW_MISC_MAX111X_H +#define HW_MISC_MAX111X_H + +#include "hw/ssi/ssi.h" + +/* + * This is a model of the Maxim MAX1110/1111 ADC chip, which for QEMU + * is an SSI slave device. It has either 4 (max1110) or 8 (max1111) + * 8-bit ADC channels. + * + * QEMU interface: + * + GPIO inputs 0..3 (for max1110) or 0..7 (for max1111): set the value + * of each ADC input, as an unsigned 8-bit value + * + GPIO output 0: interrupt line + * + Properties "input0" to "input3" (max1110) or "input0" to "input7" + * (max1111): initial reset values for ADC inputs. + * + * Known bugs: + * + the interrupt line is not correctly implemented, and will never + * be lowered once it has been asserted. + */ +typedef struct { + SSISlave parent_obj; + + qemu_irq interrupt; + /* Values of inputs at system reset (settable by QOM property) */ + uint8_t reset_input[8]; + + uint8_t tb1, rb2, rb3; + int cycle; + + uint8_t input[8]; + int inputs, com; +} MAX111xState; + +#define TYPE_MAX_111X "max111x" + +#define MAX_111X(obj) \ + OBJECT_CHECK(MAX111xState, (obj), TYPE_MAX_111X) + +#define TYPE_MAX_1110 "max1110" +#define TYPE_MAX_1111 "max1111" + +#endif From eb2dc887a4c71d9e4efd0861fcf7094d0df9df99 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:45 +0100 Subject: [PATCH 1932/2595] hw/arm/spitz: Encapsulate misc GPIO handling in a device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we have a free-floating set of IRQs and a function spitz_out_switch() which handle some miscellaneous GPIO lines for the spitz board. Encapsulate this behaviour in a simple QOM device. At this point we can finally remove the 'max1111' global, because the ADC battery-temperature value is now handled by the misc-gpio device writing the value to its outbound "adc-temp" GPIO, which the board code wires up to the appropriate inbound GPIO line on the max1111. This commit also fixes Coverity issue CID 1421913 (which pointed out that the 'outsignals' in spitz_scoop_gpio_setup() were leaked), because it removes the use of the qemu_allocate_irqs() API from this code entirely. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-13-peter.maydell@linaro.org --- hw/arm/spitz.c | 129 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 87 insertions(+), 42 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 1400a56729..bab9968cce 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -51,6 +51,7 @@ typedef struct { DeviceState *max1111; DeviceState *scp0; DeviceState *scp1; + DeviceState *misc_gpio; } SpitzMachineState; #define TYPE_SPITZ_MACHINE "spitz-common" @@ -658,8 +659,6 @@ static void spitz_lcdtg_realize(SSISlave *ssi, Error **errp) #define SPITZ_GPIO_MAX1111_CS 20 #define SPITZ_GPIO_TP_INT 11 -static DeviceState *max1111; - /* "Demux" the signal based on current chipselect */ typedef struct { SSISlave ssidev; @@ -695,18 +694,6 @@ static void corgi_ssp_gpio_cs(void *opaque, int line, int level) #define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */ #define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */ -static void spitz_adc_temp_on(void *opaque, int line, int level) -{ - int batt_temp; - - if (!max1111) - return; - - batt_temp = level ? SPITZ_BATTERY_TEMP : 0; - - qemu_set_irq(qdev_get_gpio_in(max1111, MAX1111_BATT_TEMP), batt_temp); -} - static void corgi_ssp_realize(SSISlave *d, Error **errp) { DeviceState *dev = DEVICE(d); @@ -734,7 +721,6 @@ static void spitz_ssp_attach(SpitzMachineState *sms) bus = qdev_get_child_bus(sms->mux, "ssi2"); sms->max1111 = qdev_new(TYPE_MAX_1111); - max1111 = sms->max1111; qdev_prop_set_uint8(sms->max1111, "input1" /* BATT_VOLT */, SPITZ_BATTERY_VOLT); qdev_prop_set_uint8(sms->max1111, "input2" /* BATT_TEMP */, 0); @@ -810,27 +796,66 @@ static void spitz_akita_i2c_setup(PXA2xxState *cpu) /* Other peripherals */ -static void spitz_out_switch(void *opaque, int line, int level) +/* + * Encapsulation of some miscellaneous GPIO line behaviour for the Spitz boards. + * + * QEMU interface: + * + named GPIO inputs "green-led", "orange-led", "charging", "discharging": + * these currently just print messages that the line has been signalled + * + named GPIO input "adc-temp-on": set to cause the battery-temperature + * value to be passed to the max111x ADC + * + named GPIO output "adc-temp": the ADC value, to be wired up to the max111x + */ +#define TYPE_SPITZ_MISC_GPIO "spitz-misc-gpio" +#define SPITZ_MISC_GPIO(obj) \ + OBJECT_CHECK(SpitzMiscGPIOState, (obj), TYPE_SPITZ_MISC_GPIO) + +typedef struct SpitzMiscGPIOState { + SysBusDevice parent_obj; + + qemu_irq adc_value; +} SpitzMiscGPIOState; + +static void spitz_misc_charging(void *opaque, int n, int level) { - switch (line) { - case 0: - zaurus_printf("Charging %s.\n", level ? "off" : "on"); - break; - case 1: - zaurus_printf("Discharging %s.\n", level ? "on" : "off"); - break; - case 2: - zaurus_printf("Green LED %s.\n", level ? "on" : "off"); - break; - case 3: - zaurus_printf("Orange LED %s.\n", level ? "on" : "off"); - break; - case 6: - spitz_adc_temp_on(opaque, line, level); - break; - default: - g_assert_not_reached(); - } + zaurus_printf("Charging %s.\n", level ? "off" : "on"); +} + +static void spitz_misc_discharging(void *opaque, int n, int level) +{ + zaurus_printf("Discharging %s.\n", level ? "off" : "on"); +} + +static void spitz_misc_green_led(void *opaque, int n, int level) +{ + zaurus_printf("Green LED %s.\n", level ? "off" : "on"); +} + +static void spitz_misc_orange_led(void *opaque, int n, int level) +{ + zaurus_printf("Orange LED %s.\n", level ? "off" : "on"); +} + +static void spitz_misc_adc_temp(void *opaque, int n, int level) +{ + SpitzMiscGPIOState *s = SPITZ_MISC_GPIO(opaque); + int batt_temp = level ? SPITZ_BATTERY_TEMP : 0; + + qemu_set_irq(s->adc_value, batt_temp); +} + +static void spitz_misc_gpio_init(Object *obj) +{ + SpitzMiscGPIOState *s = SPITZ_MISC_GPIO(obj); + DeviceState *dev = DEVICE(obj); + + qdev_init_gpio_in_named(dev, spitz_misc_charging, "charging", 1); + qdev_init_gpio_in_named(dev, spitz_misc_discharging, "discharging", 1); + qdev_init_gpio_in_named(dev, spitz_misc_green_led, "green-led", 1); + qdev_init_gpio_in_named(dev, spitz_misc_orange_led, "orange-led", 1); + qdev_init_gpio_in_named(dev, spitz_misc_adc_temp, "adc-temp-on", 1); + + qdev_init_gpio_out_named(dev, &s->adc_value, "adc-temp", 1); } #define SPITZ_SCP_LED_GREEN 1 @@ -850,12 +875,22 @@ static void spitz_out_switch(void *opaque, int line, int level) static void spitz_scoop_gpio_setup(SpitzMachineState *sms) { - qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, sms->mpu, 8); + DeviceState *miscdev = sysbus_create_simple(TYPE_SPITZ_MISC_GPIO, -1, NULL); - qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_CHRG_ON, outsignals[0]); - qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_JK_B, outsignals[1]); - qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_GREEN, outsignals[2]); - qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]); + sms->misc_gpio = miscdev; + + qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_CHRG_ON, + qdev_get_gpio_in_named(miscdev, "charging", 0)); + qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_JK_B, + qdev_get_gpio_in_named(miscdev, "discharging", 0)); + qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_GREEN, + qdev_get_gpio_in_named(miscdev, "green-led", 0)); + qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_ORANGE, + qdev_get_gpio_in_named(miscdev, "orange-led", 0)); + qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_ADC_TEMP_ON, + qdev_get_gpio_in_named(miscdev, "adc-temp-on", 0)); + qdev_connect_gpio_out_named(miscdev, "adc-temp", 0, + qdev_get_gpio_in(sms->max1111, MAX1111_BATT_TEMP)); if (sms->scp1) { qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_CONT, @@ -863,8 +898,6 @@ static void spitz_scoop_gpio_setup(SpitzMachineState *sms) qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_ON, qdev_get_gpio_in_named(sms->lcdtg, "bl_power", 0)); } - - qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]); } #define SPITZ_GPIO_HSYNC 22 @@ -1217,12 +1250,24 @@ static const TypeInfo spitz_lcdtg_info = { .class_init = spitz_lcdtg_class_init, }; +static const TypeInfo spitz_misc_gpio_info = { + .name = TYPE_SPITZ_MISC_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SpitzMiscGPIOState), + .instance_init = spitz_misc_gpio_init, + /* + * No class_init required: device has no internal state so does not + * need to set up reset or vmstate, and does not have a realize method. + */ +}; + static void spitz_register_types(void) { type_register_static(&corgi_ssp_info); type_register_static(&spitz_lcdtg_info); type_register_static(&spitz_keyboard_info); type_register_static(&sl_nand_info); + type_register_static(&spitz_misc_gpio_info); } type_init(spitz_register_types) From a0a8cf78e0e1bdb8923ea1466518ea24be323292 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:45 +0100 Subject: [PATCH 1933/2595] hw/gpio/zaurus.c: Use LOG_GUEST_ERROR for bad guest register accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of logging guest accesses to invalid register offsets in this device using zaurus_printf() (which just prints to stderr), use the usual qemu_log_mask(LOG_GUEST_ERROR,...). Since this was the only use of the zaurus_printf() macro outside spitz.c, we can move the definition of that macro from sharpsl.h to spitz.c. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-14-peter.maydell@linaro.org --- hw/arm/spitz.c | 3 +++ hw/gpio/zaurus.c | 12 +++++++----- include/hw/arm/sharpsl.h | 3 --- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index bab9968cce..6eb4686915 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -62,6 +62,9 @@ typedef struct { #define SPITZ_MACHINE_CLASS(klass) \ OBJECT_CLASS_CHECK(SpitzMachineClass, klass, TYPE_SPITZ_MACHINE) +#define zaurus_printf(format, ...) \ + fprintf(stderr, "%s: " format, __func__, ##__VA_ARGS__) + #undef REG_FMT #define REG_FMT "0x%02lx" diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c index 9a12c68342..258e926493 100644 --- a/hw/gpio/zaurus.c +++ b/hw/gpio/zaurus.c @@ -22,9 +22,7 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" #include "qemu/module.h" - -#undef REG_FMT -#define REG_FMT "0x%02lx" +#include "qemu/log.h" /* SCOOP devices */ @@ -104,7 +102,9 @@ static uint64_t scoop_read(void *opaque, hwaddr addr, case SCOOP_GPRR: return s->gpio_level; default: - zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); + qemu_log_mask(LOG_GUEST_ERROR, + "scoop_read: bad register offset 0x%02" HWADDR_PRIx "\n", + addr); } return 0; @@ -150,7 +150,9 @@ static void scoop_write(void *opaque, hwaddr addr, scoop_gpio_handler_update(s); break; default: - zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); + qemu_log_mask(LOG_GUEST_ERROR, + "scoop_write: bad register offset 0x%02" HWADDR_PRIx "\n", + addr); } } diff --git a/include/hw/arm/sharpsl.h b/include/hw/arm/sharpsl.h index 89e168fbff..e986b28c52 100644 --- a/include/hw/arm/sharpsl.h +++ b/include/hw/arm/sharpsl.h @@ -9,9 +9,6 @@ #include "exec/hwaddr.h" -#define zaurus_printf(format, ...) \ - fprintf(stderr, "%s: " format, __func__, ##__VA_ARGS__) - /* zaurus.c */ #define SL_PXA_PARAM_BASE 0xa0000a00 From eb2d6dbc98404be76c0ebbad69a623599d163f94 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:45 +0100 Subject: [PATCH 1934/2595] hw/arm/spitz: Use LOG_GUEST_ERROR for bad guest register accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of logging guest accesses to invalid register offsets in the Spitz flash device with zaurus_printf() (which just prints to stderr), use the usual qemu_log_mask(LOG_GUEST_ERROR,...). Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-15-peter.maydell@linaro.org --- hw/arm/spitz.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 6eb4686915..49eae3fce4 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -23,6 +23,7 @@ #include "hw/ssi/ssi.h" #include "hw/block/flash.h" #include "qemu/timer.h" +#include "qemu/log.h" #include "hw/arm/sharpsl.h" #include "ui/console.h" #include "hw/audio/wm8750.h" @@ -65,9 +66,6 @@ typedef struct { #define zaurus_printf(format, ...) \ fprintf(stderr, "%s: " format, __func__, ##__VA_ARGS__) -#undef REG_FMT -#define REG_FMT "0x%02lx" - /* Spitz Flash */ #define FLASH_BASE 0x0c000000 #define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */ @@ -137,7 +135,9 @@ static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size) return ecc_digest(&s->ecc, nand_getio(s->nand)); default: - zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); + qemu_log_mask(LOG_GUEST_ERROR, + "sl_read: bad register offset 0x%02" HWADDR_PRIx "\n", + addr); } return 0; } @@ -168,7 +168,9 @@ static void sl_write(void *opaque, hwaddr addr, break; default: - zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); + qemu_log_mask(LOG_GUEST_ERROR, + "sl_write: bad register offset 0x%02" HWADDR_PRIx "\n", + addr); } } From e53652ebeaba50e4cc54608ac5e2fe1b8b8717dc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:45 +0100 Subject: [PATCH 1935/2595] hw/arm/pxa2xx_pic: Use LOG_GUEST_ERROR for bad guest register accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using printf() for logging guest accesses to invalid register offsets in the pxa2xx PIC device, use the usual qemu_log_mask(LOG_GUEST_ERROR,...). This was the only user of the REG_FMT macro in pxa.h, so we can remove that. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-16-peter.maydell@linaro.org --- hw/arm/pxa2xx_pic.c | 9 +++++++-- include/hw/arm/pxa.h | 1 - 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index 105c5e63f2..ceee6aa48d 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/module.h" +#include "qemu/log.h" #include "cpu.h" #include "hw/arm/pxa.h" #include "hw/sysbus.h" @@ -166,7 +167,9 @@ static uint64_t pxa2xx_pic_mem_read(void *opaque, hwaddr offset, case ICHP: /* Highest Priority register */ return pxa2xx_pic_highest(s); default: - printf("%s: Bad register offset " REG_FMT "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pxa2xx_pic_mem_read: bad register offset 0x%" HWADDR_PRIx + "\n", offset); return 0; } } @@ -199,7 +202,9 @@ static void pxa2xx_pic_mem_write(void *opaque, hwaddr offset, s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f; break; default: - printf("%s: Bad register offset " REG_FMT "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pxa2xx_pic_mem_write: bad register offset 0x%" + HWADDR_PRIx "\n", offset); return; } pxa2xx_pic_update(opaque); diff --git a/include/hw/arm/pxa.h b/include/hw/arm/pxa.h index f6dfb5c0cf..8843e5f910 100644 --- a/include/hw/arm/pxa.h +++ b/include/hw/arm/pxa.h @@ -184,7 +184,6 @@ struct PXA2xxI2SState { }; # define PA_FMT "0x%08lx" -# define REG_FMT "0x" TARGET_FMT_plx PXA2xxState *pxa270_init(MemoryRegion *address_space, unsigned int sdram_size, const char *revision); From 62a4d34020197e16e54ec79f7991a6acaedfecf6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:46 +0100 Subject: [PATCH 1936/2595] hw/arm/spitz: Provide usual QOM macros for corgi-ssp and spitz-lcdtg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QOM types "spitz-lcdtg" and "corgi-ssp" are missing the usual QOM TYPE and casting macros; provide and use them. In particular, we can safely use the QOM cast macros instead of FROM_SSI_SLAVE() because in both cases the 'ssidev' field of the instance state struct is the first field in it. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-17-peter.maydell@linaro.org --- hw/arm/spitz.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 49eae3fce4..f020aff974 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -579,6 +579,9 @@ static void spitz_keyboard_realize(DeviceState *dev, Error **errp) #define LCDTG_PICTRL 0x06 #define LCDTG_POLCTRL 0x07 +#define TYPE_SPITZ_LCDTG "spitz-lcdtg" +#define SPITZ_LCDTG(obj) OBJECT_CHECK(SpitzLCDTG, (obj), TYPE_SPITZ_LCDTG) + typedef struct { SSISlave ssidev; uint32_t bl_intensity; @@ -616,7 +619,7 @@ static inline void spitz_bl_power(void *opaque, int line, int level) static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value) { - SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev); + SpitzLCDTG *s = SPITZ_LCDTG(dev); int addr; addr = value >> 5; value &= 0x1f; @@ -645,7 +648,7 @@ static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value) static void spitz_lcdtg_realize(SSISlave *ssi, Error **errp) { - SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, ssi); + SpitzLCDTG *s = SPITZ_LCDTG(ssi); DeviceState *dev = DEVICE(s); s->bl_power = 0; @@ -664,6 +667,9 @@ static void spitz_lcdtg_realize(SSISlave *ssi, Error **errp) #define SPITZ_GPIO_MAX1111_CS 20 #define SPITZ_GPIO_TP_INT 11 +#define TYPE_CORGI_SSP "corgi-ssp" +#define CORGI_SSP(obj) OBJECT_CHECK(CorgiSSPState, (obj), TYPE_CORGI_SSP) + /* "Demux" the signal based on current chipselect */ typedef struct { SSISlave ssidev; @@ -673,7 +679,7 @@ typedef struct { static uint32_t corgi_ssp_transfer(SSISlave *dev, uint32_t value) { - CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev); + CorgiSSPState *s = CORGI_SSP(dev); int i; for (i = 0; i < 3; i++) { @@ -702,7 +708,7 @@ static void corgi_ssp_gpio_cs(void *opaque, int line, int level) static void corgi_ssp_realize(SSISlave *d, Error **errp) { DeviceState *dev = DEVICE(d); - CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d); + CorgiSSPState *s = CORGI_SSP(d); qdev_init_gpio_in(dev, corgi_ssp_gpio_cs, 3); s->bus[0] = ssi_create_bus(dev, "ssi0"); @@ -714,10 +720,11 @@ static void spitz_ssp_attach(SpitzMachineState *sms) { void *bus; - sms->mux = ssi_create_slave(sms->mpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp"); + sms->mux = ssi_create_slave(sms->mpu->ssp[CORGI_SSP_PORT - 1], + TYPE_CORGI_SSP); bus = qdev_get_child_bus(sms->mux, "ssi0"); - sms->lcdtg = ssi_create_slave(bus, "spitz-lcdtg"); + sms->lcdtg = ssi_create_slave(bus, TYPE_SPITZ_LCDTG); bus = qdev_get_child_bus(sms->mux, "ssi1"); sms->ads7846 = ssi_create_slave(bus, "ads7846"); @@ -1220,7 +1227,7 @@ static void corgi_ssp_class_init(ObjectClass *klass, void *data) } static const TypeInfo corgi_ssp_info = { - .name = "corgi-ssp", + .name = TYPE_CORGI_SSP, .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(CorgiSSPState), .class_init = corgi_ssp_class_init, @@ -1249,7 +1256,7 @@ static void spitz_lcdtg_class_init(ObjectClass *klass, void *data) } static const TypeInfo spitz_lcdtg_info = { - .name = "spitz-lcdtg", + .name = TYPE_SPITZ_LCDTG, .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(SpitzLCDTG), .class_init = spitz_lcdtg_class_init, From 213f63df77b08dc47dcb3df215749b46fd4d9e8c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:46 +0100 Subject: [PATCH 1937/2595] Replace uses of FROM_SSI_SLAVE() macro with QOM casts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FROM_SSI_SLAVE() macro predates QOM and is used as a typesafe way to cast from an SSISlave* to the instance struct of a subtype of TYPE_SSI_SLAVE. Switch to using the QOM cast macros instead, which have the same effect (by writing the QOM macros if the types were previously missing them.) (The FROM_SSI_SLAVE() macro allows the SSISlave member of the subtype's struct to be anywhere as long as it is named "ssidev", whereas a QOM cast macro insists that it is the first thing in the subtype's struct. This is true for all the types we convert here.) This removes all the uses of FROM_SSI_SLAVE() so we can delete the definition. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200628142429.17111-18-peter.maydell@linaro.org --- hw/arm/z2.c | 11 +++++++---- hw/display/ads7846.c | 9 ++++++--- hw/display/ssd0323.c | 10 +++++++--- hw/sd/ssi-sd.c | 4 ++-- include/hw/ssi/ssi.h | 2 -- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/hw/arm/z2.c b/hw/arm/z2.c index a0f4095990..e1f22f5868 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -111,9 +111,12 @@ typedef struct { int pos; } ZipitLCD; +#define TYPE_ZIPIT_LCD "zipit-lcd" +#define ZIPIT_LCD(obj) OBJECT_CHECK(ZipitLCD, (obj), TYPE_ZIPIT_LCD) + static uint32_t zipit_lcd_transfer(SSISlave *dev, uint32_t value) { - ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev); + ZipitLCD *z = ZIPIT_LCD(dev); uint16_t val; if (z->selected) { z->buf[z->pos] = value & 0xff; @@ -153,7 +156,7 @@ static void z2_lcd_cs(void *opaque, int line, int level) static void zipit_lcd_realize(SSISlave *dev, Error **errp) { - ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev); + ZipitLCD *z = ZIPIT_LCD(dev); z->selected = 0; z->enabled = 0; z->pos = 0; @@ -185,7 +188,7 @@ static void zipit_lcd_class_init(ObjectClass *klass, void *data) } static const TypeInfo zipit_lcd_info = { - .name = "zipit-lcd", + .name = TYPE_ZIPIT_LCD, .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ZipitLCD), .class_init = zipit_lcd_class_init, @@ -325,7 +328,7 @@ static void z2_init(MachineState *machine) type_register_static(&zipit_lcd_info); type_register_static(&aer915_info); - z2_lcd = ssi_create_slave(mpu->ssp[1], "zipit-lcd"); + z2_lcd = ssi_create_slave(mpu->ssp[1], TYPE_ZIPIT_LCD); bus = pxa2xx_i2c_bus(mpu->i2c[0]); i2c_create_slave(bus, TYPE_AER915, 0x55); wm = i2c_create_slave(bus, TYPE_WM8750, 0x1b); diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c index 9228b40b1a..56bf82fe07 100644 --- a/hw/display/ads7846.c +++ b/hw/display/ads7846.c @@ -29,6 +29,9 @@ typedef struct { int output; } ADS7846State; +#define TYPE_ADS7846 "ads7846" +#define ADS7846(obj) OBJECT_CHECK(ADS7846State, (obj), TYPE_ADS7846) + /* Control-byte bitfields */ #define CB_PD0 (1 << 0) #define CB_PD1 (1 << 1) @@ -61,7 +64,7 @@ static void ads7846_int_update(ADS7846State *s) static uint32_t ads7846_transfer(SSISlave *dev, uint32_t value) { - ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev); + ADS7846State *s = ADS7846(dev); switch (s->cycle ++) { case 0: @@ -139,7 +142,7 @@ static const VMStateDescription vmstate_ads7846 = { static void ads7846_realize(SSISlave *d, Error **errp) { DeviceState *dev = DEVICE(d); - ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, d); + ADS7846State *s = ADS7846(d); qdev_init_gpio_out(dev, &s->interrupt, 1); @@ -166,7 +169,7 @@ static void ads7846_class_init(ObjectClass *klass, void *data) } static const TypeInfo ads7846_info = { - .name = "ads7846", + .name = TYPE_ADS7846, .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ADS7846State), .class_init = ads7846_class_init, diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index c3bdb18742..32d27f008a 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -66,9 +66,13 @@ typedef struct { uint8_t framebuffer[128 * 80 / 2]; } ssd0323_state; +#define TYPE_SSD0323 "ssd0323" +#define SSD0323(obj) OBJECT_CHECK(ssd0323_state, (obj), TYPE_SSD0323) + + static uint32_t ssd0323_transfer(SSISlave *dev, uint32_t data) { - ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev); + ssd0323_state *s = SSD0323(dev); switch (s->mode) { case SSD0323_DATA: @@ -346,7 +350,7 @@ static const GraphicHwOps ssd0323_ops = { static void ssd0323_realize(SSISlave *d, Error **errp) { DeviceState *dev = DEVICE(d); - ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, d); + ssd0323_state *s = SSD0323(d); s->col_end = 63; s->row_end = 79; @@ -368,7 +372,7 @@ static void ssd0323_class_init(ObjectClass *klass, void *data) } static const TypeInfo ssd0323_info = { - .name = "ssd0323", + .name = TYPE_SSD0323, .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ssd0323_state), .class_init = ssd0323_class_init, diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 25cec2ddea..25cdf4c966 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -74,7 +74,7 @@ typedef struct { static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val) { - ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev); + ssi_sd_state *s = SSI_SD(dev); /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data. */ if (s->mode == SSI_SD_DATA_READ && val == 0x4d) { @@ -241,7 +241,7 @@ static const VMStateDescription vmstate_ssi_sd = { static void ssi_sd_realize(SSISlave *d, Error **errp) { - ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d); + ssi_sd_state *s = SSI_SD(d); DeviceState *carddev; DriveInfo *dinfo; Error *err = NULL; diff --git a/include/hw/ssi/ssi.h b/include/hw/ssi/ssi.h index 5fd411f2e4..eac168aa1d 100644 --- a/include/hw/ssi/ssi.h +++ b/include/hw/ssi/ssi.h @@ -66,8 +66,6 @@ struct SSISlave { bool cs; }; -#define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev) - extern const VMStateDescription vmstate_ssi_slave; #define VMSTATE_SSI_SLAVE(_field, _state) { \ From 0f10bf84a9d489259a5b11c6aa1b05c1175b76ea Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 3 Jul 2020 16:59:46 +0100 Subject: [PATCH 1938/2595] Deprecate TileGX port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deprecate our TileGX target support: * we have no active maintainer for it * it has had essentially no contributions (other than tree-wide cleanups and similar) since it was first added * the Linux kernel dropped support in 2018, as has glibc Note the deprecation in the manual, but don't try to print a warning when QEMU runs -- printing unsuppressable messages is more obtrusive for linux-user mode than it would be for system-emulation mode, and it doesn't seem worth trying to invent a new suppressible-error system for linux-user just for this. Signed-off-by: Peter Maydell Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-id: 20200619154831.26319-1-peter.maydell@linaro.org --- docs/system/deprecated.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 843ae71fc6..47f84be8e0 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -404,6 +404,17 @@ The above, converted to the current supported format:: json:{"file.driver":"rbd", "file.pool":"rbd", "file.image":"name"} +linux-user mode CPUs +-------------------- + +``tilegx`` CPUs (since 5.1.0) +''''''''''''''''''''''''''''' + +The ``tilegx`` guest CPU support (which was only implemented in +linux-user mode) is deprecated and will be removed in a future version +of QEMU. Support for this CPU was removed from the upstream Linux +kernel in 2018, and has also been dropped from glibc. + Related binaries ---------------- From 993aec27aa39aa90f89f227d8f82cc1f8062386e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 11 Oct 2018 20:21:11 +0200 Subject: [PATCH 1939/2595] crypto: Add tls-cipher-suites object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the host OS, various aspects of TLS operation are configurable. In particular it is possible for the sysadmin to control the TLS cipher/protocol algorithms that applications are permitted to use. * Any given crypto library has a built-in default priority list defined by the distro maintainer of the library package (or by upstream). * The "crypto-policies" RPM (or equivalent host OS package) provides a config file such as "/etc/crypto-policies/config", where the sysadmin can set a high level (library-independent) policy. The "update-crypto-policies --set" command (or equivalent) is used to translate the global policy to individual library representations, producing files such as "/etc/crypto-policies/back-ends/*.config". The generated files, if present, are loaded by the various crypto libraries to override their own built-in defaults. For example, the GNUTLS library may read "/etc/crypto-policies/back-ends/gnutls.config". * A management application (or the QEMU user) may overide the system-wide crypto-policies config via their own config, if they need to diverge from the former. Thus the priority order is "QEMU user config" > "crypto-policies system config" > "library built-in config". Introduce the "tls-cipher-suites" object for exposing the ordered list of permitted TLS cipher suites from the host side to the guest firmware, via fw_cfg. The list is represented as an array of bytes. The priority at which the host-side policy is retrieved is given by the "priority" property of the new object type. For example, "priority=@SYSTEM" may be used to refer to "/etc/crypto-policies/back-ends/gnutls.config" (given that QEMU uses GNUTLS). The firmware uses the IANA_TLS_CIPHER array for configuring guest-side TLS, for example in UEFI HTTPS Boot. [Description from Daniel P. Berrangé, edited by Laszlo Ersek.] Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Acked-by: Laszlo Ersek Message-Id: <20200623172726.21040-2-philmd@redhat.com> --- crypto/Makefile.objs | 1 + crypto/tls-cipher-suites.c | 115 +++++++++++++++++++++++++++++ crypto/trace-events | 5 ++ include/crypto/tls-cipher-suites.h | 39 ++++++++++ qemu-options.hx | 19 +++++ 5 files changed, 179 insertions(+) create mode 100644 crypto/tls-cipher-suites.c create mode 100644 include/crypto/tls-cipher-suites.h diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs index 707c02ad37..f1965b1a68 100644 --- a/crypto/Makefile.objs +++ b/crypto/Makefile.objs @@ -13,6 +13,7 @@ crypto-obj-y += cipher.o crypto-obj-$(CONFIG_AF_ALG) += afalg.o crypto-obj-$(CONFIG_AF_ALG) += cipher-afalg.o crypto-obj-$(CONFIG_AF_ALG) += hash-afalg.o +crypto-obj-$(CONFIG_GNUTLS) += tls-cipher-suites.o crypto-obj-y += tlscreds.o crypto-obj-y += tlscredsanon.o crypto-obj-y += tlscredspsk.o diff --git a/crypto/tls-cipher-suites.c b/crypto/tls-cipher-suites.c new file mode 100644 index 0000000000..a4e0f84307 --- /dev/null +++ b/crypto/tls-cipher-suites.c @@ -0,0 +1,115 @@ +/* + * QEMU TLS Cipher Suites + * + * Copyright (c) 2018-2020 Red Hat, Inc. + * + * Author: Philippe Mathieu-Daudé + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qom/object_interfaces.h" +#include "crypto/tlscreds.h" +#include "crypto/tls-cipher-suites.h" +#include "trace.h" + +/* + * IANA registered TLS ciphers: + * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4 + */ +typedef struct { + uint8_t data[2]; +} QEMU_PACKED IANA_TLS_CIPHER; + +GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj, + Error **errp) +{ + QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj); + gnutls_priority_t pcache; + GByteArray *byte_array; + const char *err; + size_t i; + int ret; + + trace_qcrypto_tls_cipher_suite_priority(creds->priority); + ret = gnutls_priority_init(&pcache, creds->priority, &err); + if (ret < 0) { + error_setg(errp, "Syntax error using priority '%s': %s", + creds->priority, gnutls_strerror(ret)); + return NULL; + } + + byte_array = g_byte_array_new(); + + for (i = 0;; i++) { + int ret; + unsigned idx; + const char *name; + IANA_TLS_CIPHER cipher; + gnutls_protocol_t protocol; + const char *version; + + ret = gnutls_priority_get_cipher_suite_index(pcache, i, &idx); + if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + break; + } + if (ret == GNUTLS_E_UNKNOWN_CIPHER_SUITE) { + continue; + } + + name = gnutls_cipher_suite_info(idx, (unsigned char *)&cipher, + NULL, NULL, NULL, &protocol); + if (name == NULL) { + continue; + } + + version = gnutls_protocol_get_name(protocol); + g_byte_array_append(byte_array, cipher.data, 2); + trace_qcrypto_tls_cipher_suite_info(cipher.data[0], + cipher.data[1], + version, name); + } + trace_qcrypto_tls_cipher_suite_count(byte_array->len); + gnutls_priority_deinit(pcache); + + return byte_array; +} + +static void qcrypto_tls_cipher_suites_complete(UserCreatable *uc, + Error **errp) +{ + QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(uc); + + if (!creds->priority) { + error_setg(errp, "'priority' property is not set"); + return; + } +} + +static void qcrypto_tls_cipher_suites_class_init(ObjectClass *oc, void *data) +{ + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + + ucc->complete = qcrypto_tls_cipher_suites_complete; +} + +static const TypeInfo qcrypto_tls_cipher_suites_info = { + .parent = TYPE_QCRYPTO_TLS_CREDS, + .name = TYPE_QCRYPTO_TLS_CIPHER_SUITES, + .instance_size = sizeof(QCryptoTLSCreds), + .class_size = sizeof(QCryptoTLSCredsClass), + .class_init = qcrypto_tls_cipher_suites_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void qcrypto_tls_cipher_suites_register_types(void) +{ + type_register_static(&qcrypto_tls_cipher_suites_info); +} + +type_init(qcrypto_tls_cipher_suites_register_types); diff --git a/crypto/trace-events b/crypto/trace-events index 9e594d30e8..798b6067ab 100644 --- a/crypto/trace-events +++ b/crypto/trace-events @@ -21,3 +21,8 @@ qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds # tlssession.c qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *authzid, int endpoint) "TLS session new session=%p creds=%p hostname=%s authzid=%s endpoint=%d" qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s" + +# tls-cipher-suites.c +qcrypto_tls_cipher_suite_priority(const char *name) "priority: %s" +qcrypto_tls_cipher_suite_info(uint8_t data0, uint8_t data1, const char *version, const char *name) "data=[0x%02x,0x%02x] version=%s name=%s" +qcrypto_tls_cipher_suite_count(unsigned count) "count: %u" diff --git a/include/crypto/tls-cipher-suites.h b/include/crypto/tls-cipher-suites.h new file mode 100644 index 0000000000..28b3a73ce1 --- /dev/null +++ b/include/crypto/tls-cipher-suites.h @@ -0,0 +1,39 @@ +/* + * QEMU TLS Cipher Suites Registry (RFC8447) + * + * Copyright (c) 2018-2020 Red Hat, Inc. + * + * Author: Philippe Mathieu-Daudé + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef QCRYPTO_TLSCIPHERSUITES_H +#define QCRYPTO_TLSCIPHERSUITES_H + +#include "qom/object.h" +#include "crypto/tlscreds.h" + +#define TYPE_QCRYPTO_TLS_CIPHER_SUITES "tls-cipher-suites" +#define QCRYPTO_TLS_CIPHER_SUITES(obj) \ + OBJECT_CHECK(QCryptoTLSCipherSuites, (obj), TYPE_QCRYPTO_TLS_CIPHER_SUITES) + +typedef struct QCryptoTLSCipherSuites { + /* */ + QCryptoTLSCreds parent_obj; + /* */ +} QCryptoTLSCipherSuites; + +/** + * qcrypto_tls_cipher_suites_get_data: + * @obj: pointer to a TLS cipher suites object + * @errp: pointer to a NULL-initialized error object + * + * Returns: reference to a byte array containing the data. + * The caller should release the reference when no longer + * required. + */ +GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj, + Error **errp); + +#endif /* QCRYPTO_TLSCIPHERSUITES_H */ diff --git a/qemu-options.hx b/qemu-options.hx index 196f468786..ecc4658e1f 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4567,6 +4567,25 @@ SRST string as described at https://gnutls.org/manual/html_node/Priority-Strings.html. + ``-object tls-cipher-suites,id=id,priority=priority`` + Creates a TLS cipher suites object, which can be used to control + the TLS cipher/protocol algorithms that applications are permitted + to use. + + The ``id`` parameter is a unique ID which frontends will use to + access the ordered list of permitted TLS cipher suites from the + host. + + The ``priority`` parameter allows to override the global default + priority used by gnutls. This can be useful if the system + administrator needs to use a weaker set of crypto priorities for + QEMU without potentially forcing the weakness onto all + applications. Or conversely if one wants wants a stronger + default for QEMU than for all other applications, they can do + this through this parameter. Its format is a gnutls priority + string as described at + https://gnutls.org/manual/html_node/Priority-Strings.html. + ``-object filter-buffer,id=id,netdev=netdevid,interval=t[,queue=all|rx|tx][,status=on|off][,position=head|tail|id=][,insert=behind|before]`` Interval t can't be 0, this filter batches the packet delivery: all packets arriving in a given interval on netdev netdevid are From 3203148917d035b09f71986ac2eaa19a352d6d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 May 2020 15:15:38 +0200 Subject: [PATCH 1940/2595] hw/nvram/fw_cfg: Add the FW_CFG_DATA_GENERATOR interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FW_CFG_DATA_GENERATOR allows any object to produce blob of data consumable by the fw_cfg device. Reviewed-by: Laszlo Ersek Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-Id: <20200623172726.21040-3-philmd@redhat.com> --- docs/specs/fw_cfg.txt | 9 +++++++- hw/nvram/fw_cfg.c | 35 +++++++++++++++++++++++++++++++ include/hw/nvram/fw_cfg.h | 43 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt index 8f1ebc66fa..bc16daa38a 100644 --- a/docs/specs/fw_cfg.txt +++ b/docs/specs/fw_cfg.txt @@ -219,7 +219,7 @@ To check the result, read the "control" field: = Externally Provided Items = -As of v2.4, "file" fw_cfg items (i.e., items with selector keys above +Since v2.4, "file" fw_cfg items (i.e., items with selector keys above FW_CFG_FILE_FIRST, and with a corresponding entry in the fw_cfg file directory structure) may be inserted via the QEMU command line, using the following syntax: @@ -230,6 +230,13 @@ Or -fw_cfg [name=],string= +Since v5.1, QEMU allows some objects to generate fw_cfg-specific content, +the content is then associated with a "file" item using the 'gen_id' option +in the command line, using the following syntax: + + -object ,id=,[generator-specific-options] \ + -fw_cfg [name=],gen_id= + See QEMU man page for more documentation. Using item_name with plain ASCII characters only is recommended. diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 0408a31f8e..694722b212 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -1032,6 +1032,35 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename, return NULL; } +void fw_cfg_add_from_generator(FWCfgState *s, const char *filename, + const char *gen_id, Error **errp) +{ + FWCfgDataGeneratorClass *klass; + Error *local_err = NULL; + GByteArray *array; + Object *obj; + gsize size; + + obj = object_resolve_path_component(object_get_objects_root(), gen_id); + if (!obj) { + error_setg(errp, "Cannot find object ID '%s'", gen_id); + return; + } + if (!object_dynamic_cast(obj, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE)) { + error_setg(errp, "Object ID '%s' is not a '%s' subclass", + gen_id, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE); + return; + } + klass = FW_CFG_DATA_GENERATOR_GET_CLASS(obj); + array = klass->get_data(obj, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + size = array->len; + fw_cfg_add_file(s, filename, g_byte_array_free(array, TRUE), size); +} + static void fw_cfg_machine_reset(void *opaque) { MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); @@ -1333,12 +1362,18 @@ static const TypeInfo fw_cfg_mem_info = { .class_init = fw_cfg_mem_class_init, }; +static const TypeInfo fw_cfg_data_generator_interface_info = { + .parent = TYPE_INTERFACE, + .name = TYPE_FW_CFG_DATA_GENERATOR_INTERFACE, + .class_size = sizeof(FWCfgDataGeneratorClass), +}; static void fw_cfg_register_types(void) { type_register_static(&fw_cfg_info); type_register_static(&fw_cfg_io_info); type_register_static(&fw_cfg_mem_info); + type_register_static(&fw_cfg_data_generator_interface_info); } type_init(fw_cfg_register_types) diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index 25d9307018..11feae3177 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -9,11 +9,36 @@ #define TYPE_FW_CFG "fw_cfg" #define TYPE_FW_CFG_IO "fw_cfg_io" #define TYPE_FW_CFG_MEM "fw_cfg_mem" +#define TYPE_FW_CFG_DATA_GENERATOR_INTERFACE "fw_cfg-data-generator" #define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG) #define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO) #define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM) +#define FW_CFG_DATA_GENERATOR_CLASS(class) \ + OBJECT_CLASS_CHECK(FWCfgDataGeneratorClass, (class), \ + TYPE_FW_CFG_DATA_GENERATOR_INTERFACE) +#define FW_CFG_DATA_GENERATOR_GET_CLASS(obj) \ + OBJECT_GET_CLASS(FWCfgDataGeneratorClass, (obj), \ + TYPE_FW_CFG_DATA_GENERATOR_INTERFACE) + +typedef struct FWCfgDataGeneratorClass { + /*< private >*/ + InterfaceClass parent_class; + /*< public >*/ + + /** + * get_data: + * @obj: the object implementing this interface + * @errp: pointer to a NULL-initialized error object + * + * Returns: reference to a byte array containing the data. + * The caller should release the reference when no longer + * required. + */ + GByteArray *(*get_data)(Object *obj, Error **errp); +} FWCfgDataGeneratorClass; + typedef struct fw_cfg_file FWCfgFile; #define FW_CFG_ORDER_OVERRIDE_VGA 70 @@ -263,6 +288,24 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data, size_t len); +/** + * fw_cfg_add_from_generator: + * @s: fw_cfg device being modified + * @filename: name of new fw_cfg file item + * @gen_id: name of object implementing FW_CFG_DATA_GENERATOR interface + * @errp: pointer to a NULL initialized error object + * + * Add a new NAMED fw_cfg item with the content generated from the + * @gen_id object. The data generated by the @gen_id object is copied + * into the data structure of the fw_cfg device. + * The next available (unused) selector key starting at FW_CFG_FILE_FIRST + * will be used; also, a new entry will be added to the file directory + * structure residing at key value FW_CFG_FILE_DIR, containing the item name, + * data size, and assigned selector key value. + */ +void fw_cfg_add_from_generator(FWCfgState *s, const char *filename, + const char *gen_id, Error **errp); + FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, AddressSpace *dma_as); FWCfgState *fw_cfg_init_io(uint32_t iobase); From 6552d87c48679e1ece2da3ddc0947d2146de53ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 19 May 2020 19:20:43 +0200 Subject: [PATCH 1941/2595] softmmu/vl: Let -fw_cfg option take a 'gen_id' argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'gen_id' argument refers to a QOM object able to produce data consumable by the fw_cfg device. The producer object must implement the FW_CFG_DATA_GENERATOR interface. Reviewed-by: Laszlo Ersek Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-Id: <20200623172726.21040-4-philmd@redhat.com> --- softmmu/vl.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index 3e15ee2435..13cada39d6 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -489,6 +489,11 @@ static QemuOptsList qemu_fw_cfg_opts = { .name = "string", .type = QEMU_OPT_STRING, .help = "Sets content of the blob to be inserted from a string", + }, { + .name = "gen_id", + .type = QEMU_OPT_STRING, + .help = "Sets id of the object generating the fw_cfg blob " + "to be inserted", }, { /* end of list */ } }, @@ -2020,7 +2025,7 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) { gchar *buf; size_t size; - const char *name, *file, *str; + const char *name, *file, *str, *gen_id; FWCfgState *fw_cfg = (FWCfgState *) opaque; if (fw_cfg == NULL) { @@ -2030,14 +2035,13 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) name = qemu_opt_get(opts, "name"); file = qemu_opt_get(opts, "file"); str = qemu_opt_get(opts, "string"); + gen_id = qemu_opt_get(opts, "gen_id"); - /* we need name and either a file or the content string */ - if (!(nonempty_str(name) && (nonempty_str(file) || nonempty_str(str)))) { - error_setg(errp, "invalid argument(s)"); - return -1; - } - if (nonempty_str(file) && nonempty_str(str)) { - error_setg(errp, "file and string are mutually exclusive"); + /* we need the name, and exactly one of: file, content string, gen_id */ + if (!nonempty_str(name) || + nonempty_str(file) + nonempty_str(str) + nonempty_str(gen_id) != 1) { + error_setg(errp, "name, plus exactly one of file," + " string and gen_id, are needed"); return -1; } if (strlen(name) > FW_CFG_MAX_FILE_PATH - 1) { @@ -2052,6 +2056,15 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) if (nonempty_str(str)) { size = strlen(str); /* NUL terminator NOT included in fw_cfg blob */ buf = g_memdup(str, size); + } else if (nonempty_str(gen_id)) { + Error *local_err = NULL; + + fw_cfg_add_from_generator(fw_cfg, name, gen_id, errp); + if (local_err) { + error_propagate(errp, local_err); + return -1; + } + return 0; } else { GError *err = NULL; if (!g_file_get_contents(file, &buf, &size, &err)) { From f7d8afb16dceb780270960692b949329c8752ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 19 May 2020 19:17:09 +0200 Subject: [PATCH 1942/2595] softmmu/vl: Allow -fw_cfg 'gen_id' option to use the 'etc/' namespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Names of user-provided fw_cfg items are supposed to start with "opt/". However FW_CFG_DATA_GENERATOR items are generated by QEMU, so allow the "etc/" namespace in this specific case. Reviewed-by: Laszlo Ersek Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-Id: <20200623172726.21040-5-philmd@redhat.com> --- docs/specs/fw_cfg.txt | 4 ++++ softmmu/vl.c | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt index bc16daa38a..3e6d586f66 100644 --- a/docs/specs/fw_cfg.txt +++ b/docs/specs/fw_cfg.txt @@ -258,4 +258,8 @@ Prefix "opt/org.qemu/" is reserved for QEMU itself. Use of names not beginning with "opt/" is potentially dangerous and entirely unsupported. QEMU will warn if you try. +Use of names not beginning with "opt/" is tolerated with 'gen_id' (that +is, the warning is suppressed), but you must know exactly what you're +doing. + All externally provided fw_cfg items are read-only to the guest. diff --git a/softmmu/vl.c b/softmmu/vl.c index 13cada39d6..159f0352a9 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2049,7 +2049,13 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) FW_CFG_MAX_FILE_PATH - 1); return -1; } - if (strncmp(name, "opt/", 4) != 0) { + if (nonempty_str(gen_id)) { + /* + * In this particular case where the content is populated + * internally, the "etc/" namespace protection is relaxed, + * so do not emit a warning. + */ + } else if (strncmp(name, "opt/", 4) != 0) { warn_report("externally provided fw_cfg item names " "should be prefixed with \"opt/\""); } From 69699f3055a59e24f1153c329ae6eff4b9a343e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 14 May 2020 15:15:47 +0200 Subject: [PATCH 1943/2595] crypto/tls-cipher-suites: Produce fw_cfg consumable blob MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since our format is consumable by the fw_cfg device, we can implement the FW_CFG_DATA_GENERATOR interface. Example of use to dump the cipher suites (if tracing enabled): $ qemu-system-x86_64 -S \ -object tls-cipher-suites,id=mysuite1,priority=@SYSTEM \ -fw_cfg name=etc/path/to/ciphers,gen_id=mysuite1 \ -trace qcrypto\* 1590664444.197123:qcrypto_tls_cipher_suite_priority priority: @SYSTEM 1590664444.197219:qcrypto_tls_cipher_suite_info data=[0x13,0x02] version=TLS1.3 name=TLS_AES_256_GCM_SHA384 1590664444.197228:qcrypto_tls_cipher_suite_info data=[0x13,0x03] version=TLS1.3 name=TLS_CHACHA20_POLY1305_SHA256 1590664444.197233:qcrypto_tls_cipher_suite_info data=[0x13,0x01] version=TLS1.3 name=TLS_AES_128_GCM_SHA256 1590664444.197236:qcrypto_tls_cipher_suite_info data=[0x13,0x04] version=TLS1.3 name=TLS_AES_128_CCM_SHA256 1590664444.197240:qcrypto_tls_cipher_suite_info data=[0xc0,0x30] version=TLS1.2 name=TLS_ECDHE_RSA_AES_256_GCM_SHA384 1590664444.197245:qcrypto_tls_cipher_suite_info data=[0xcc,0xa8] version=TLS1.2 name=TLS_ECDHE_RSA_CHACHA20_POLY1305 1590664444.197250:qcrypto_tls_cipher_suite_info data=[0xc0,0x14] version=TLS1.0 name=TLS_ECDHE_RSA_AES_256_CBC_SHA1 1590664444.197254:qcrypto_tls_cipher_suite_info data=[0xc0,0x2f] version=TLS1.2 name=TLS_ECDHE_RSA_AES_128_GCM_SHA256 1590664444.197258:qcrypto_tls_cipher_suite_info data=[0xc0,0x13] version=TLS1.0 name=TLS_ECDHE_RSA_AES_128_CBC_SHA1 1590664444.197261:qcrypto_tls_cipher_suite_info data=[0xc0,0x2c] version=TLS1.2 name=TLS_ECDHE_ECDSA_AES_256_GCM_SHA384 1590664444.197266:qcrypto_tls_cipher_suite_info data=[0xcc,0xa9] version=TLS1.2 name=TLS_ECDHE_ECDSA_CHACHA20_POLY1305 1590664444.197270:qcrypto_tls_cipher_suite_info data=[0xc0,0xad] version=TLS1.2 name=TLS_ECDHE_ECDSA_AES_256_CCM 1590664444.197274:qcrypto_tls_cipher_suite_info data=[0xc0,0x0a] version=TLS1.0 name=TLS_ECDHE_ECDSA_AES_256_CBC_SHA1 1590664444.197278:qcrypto_tls_cipher_suite_info data=[0xc0,0x2b] version=TLS1.2 name=TLS_ECDHE_ECDSA_AES_128_GCM_SHA256 1590664444.197283:qcrypto_tls_cipher_suite_info data=[0xc0,0xac] version=TLS1.2 name=TLS_ECDHE_ECDSA_AES_128_CCM 1590664444.197287:qcrypto_tls_cipher_suite_info data=[0xc0,0x09] version=TLS1.0 name=TLS_ECDHE_ECDSA_AES_128_CBC_SHA1 1590664444.197291:qcrypto_tls_cipher_suite_info data=[0x00,0x9d] version=TLS1.2 name=TLS_RSA_AES_256_GCM_SHA384 1590664444.197296:qcrypto_tls_cipher_suite_info data=[0xc0,0x9d] version=TLS1.2 name=TLS_RSA_AES_256_CCM 1590664444.197300:qcrypto_tls_cipher_suite_info data=[0x00,0x35] version=TLS1.0 name=TLS_RSA_AES_256_CBC_SHA1 1590664444.197304:qcrypto_tls_cipher_suite_info data=[0x00,0x9c] version=TLS1.2 name=TLS_RSA_AES_128_GCM_SHA256 1590664444.197308:qcrypto_tls_cipher_suite_info data=[0xc0,0x9c] version=TLS1.2 name=TLS_RSA_AES_128_CCM 1590664444.197312:qcrypto_tls_cipher_suite_info data=[0x00,0x2f] version=TLS1.0 name=TLS_RSA_AES_128_CBC_SHA1 1590664444.197316:qcrypto_tls_cipher_suite_info data=[0x00,0x9f] version=TLS1.2 name=TLS_DHE_RSA_AES_256_GCM_SHA384 1590664444.197320:qcrypto_tls_cipher_suite_info data=[0xcc,0xaa] version=TLS1.2 name=TLS_DHE_RSA_CHACHA20_POLY1305 1590664444.197325:qcrypto_tls_cipher_suite_info data=[0xc0,0x9f] version=TLS1.2 name=TLS_DHE_RSA_AES_256_CCM 1590664444.197329:qcrypto_tls_cipher_suite_info data=[0x00,0x39] version=TLS1.0 name=TLS_DHE_RSA_AES_256_CBC_SHA1 1590664444.197333:qcrypto_tls_cipher_suite_info data=[0x00,0x9e] version=TLS1.2 name=TLS_DHE_RSA_AES_128_GCM_SHA256 1590664444.197337:qcrypto_tls_cipher_suite_info data=[0xc0,0x9e] version=TLS1.2 name=TLS_DHE_RSA_AES_128_CCM 1590664444.197341:qcrypto_tls_cipher_suite_info data=[0x00,0x33] version=TLS1.0 name=TLS_DHE_RSA_AES_128_CBC_SHA1 1590664444.197345:qcrypto_tls_cipher_suite_count count: 29 Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Acked-by: Laszlo Ersek Message-Id: <20200623172726.21040-6-philmd@redhat.com> --- crypto/tls-cipher-suites.c | 11 +++++++++++ qemu-options.hx | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/crypto/tls-cipher-suites.c b/crypto/tls-cipher-suites.c index a4e0f84307..0d305b684b 100644 --- a/crypto/tls-cipher-suites.c +++ b/crypto/tls-cipher-suites.c @@ -13,6 +13,7 @@ #include "qom/object_interfaces.h" #include "crypto/tlscreds.h" #include "crypto/tls-cipher-suites.h" +#include "hw/nvram/fw_cfg.h" #include "trace.h" /* @@ -88,11 +89,20 @@ static void qcrypto_tls_cipher_suites_complete(UserCreatable *uc, } } +static GByteArray *qcrypto_tls_cipher_suites_fw_cfg_gen_data(Object *obj, + Error **errp) +{ + return qcrypto_tls_cipher_suites_get_data(QCRYPTO_TLS_CIPHER_SUITES(obj), + errp); +} + static void qcrypto_tls_cipher_suites_class_init(ObjectClass *oc, void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + FWCfgDataGeneratorClass *fwgc = FW_CFG_DATA_GENERATOR_CLASS(oc); ucc->complete = qcrypto_tls_cipher_suites_complete; + fwgc->get_data = qcrypto_tls_cipher_suites_fw_cfg_gen_data; } static const TypeInfo qcrypto_tls_cipher_suites_info = { @@ -103,6 +113,7 @@ static const TypeInfo qcrypto_tls_cipher_suites_info = { .class_init = qcrypto_tls_cipher_suites_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_USER_CREATABLE }, + { TYPE_FW_CFG_DATA_GENERATOR_INTERFACE }, { } } }; diff --git a/qemu-options.hx b/qemu-options.hx index ecc4658e1f..b2cbbbf281 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4586,6 +4586,24 @@ SRST string as described at https://gnutls.org/manual/html_node/Priority-Strings.html. + An example of use of this object is to control UEFI HTTPS Boot. + The tls-cipher-suites object exposes the ordered list of permitted + TLS cipher suites from the host side to the guest firmware, via + fw_cfg. The list is represented as an array of IANA_TLS_CIPHER + objects. The firmware uses the IANA_TLS_CIPHER array for configuring + guest-side TLS. + + In the following example, the priority at which the host-side policy + is retrieved is given by the ``priority`` property. + Given that QEMU uses GNUTLS, ``priority=@SYSTEM`` may be used to + refer to /etc/crypto-policies/back-ends/gnutls.config. + + .. parsed-literal:: + + # |qemu_system| \ + -object tls-cipher-suites,id=mysuite0,priority=@SYSTEM \ + -fw_cfg name=etc/edk2/https/ciphers,gen_id=mysuite0 + ``-object filter-buffer,id=id,netdev=netdevid,interval=t[,queue=all|rx|tx][,status=on|off][,position=head|tail|id=][,insert=behind|before]`` Interval t can't be 0, this filter batches the packet delivery: all packets arriving in a given interval on netdev netdevid are From 79482e5987c824086d8824ebcf95a0c8c9c16cd7 Mon Sep 17 00:00:00 2001 From: Filip Bozuta Date: Fri, 19 Jun 2020 14:47:27 +0200 Subject: [PATCH 1944/2595] linux-user: Add strace support for printing arguments of ioctl() This patch implements functionality for strace argument printing for ioctls. When running ioctls through qemu with "-strace", they get printed in format: "ioctl(fd_num,0x*,0x*) = ret_value" where the request code an the ioctl's third argument get printed in a hexadicemal format. This patch changes that by enabling strace to print both the request code name and the contents of the third argument. For example, when running ioctl RTC_SET_TIME with "-strace", with changes from this patch, it gets printed in this way: "ioctl(3,RTC_SET_TIME,{12,13,15,20,10,119,0,0,0}) = 0" In case of IOC_R type ioctls, the contents of the third argument get printed after the return value, and the argument inside the ioctl call gets printed as pointer in hexadecimal format. For example, when running RTC_RD_TIME with "-strace", with changes from this patch, it gets printed in this way: "ioctl(3,RTC_RD_TIME,0x40800374) = 0 ({22,9,13,11,5,120,0,0,0})" In case of IOC_RW type ioctls, the contents of the third argument get printed both inside the ioctl call and after the return value. Implementation notes: Functions "print_ioctl()" and "print_syscall_ret_ioctl()", that are defined in "strace.c", are listed in file "strace.list" as "call" and "result" value for ioctl. Structure definition "IOCTLEntry" as well as predefined values for IOC_R, IOC_W and IOC_RW were cut and pasted from file "syscall.c" to file "qemu.h" so that they can be used by these functions to print the contents of the third ioctl argument. Also, the "static" identifier for array "ioctl_entries[]" was removed and this array was declared as "extern" in "qemu.h" so that it can also be used by these functions. To decode the structure type of the ioctl third argument, function "thunk_print()" was defined in file "thunk.c" and its definition is somewhat simillar to that of function "thunk_convert()". Signed-off-by: Filip Bozuta Reviewed-by: Laurent Vivier Message-Id: <20200619124727.18080-3-filip.bozuta@syrmia.com> [lv: fix close-bracket] Signed-off-by: Laurent Vivier --- include/exec/user/thunk.h | 1 + linux-user/qemu.h | 20 +++++ linux-user/strace.c | 107 ++++++++++++++++++++++++++ linux-user/strace.list | 3 +- linux-user/syscall.c | 20 +---- thunk.c | 154 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 285 insertions(+), 20 deletions(-) diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h index eae2c27f99..7992475c9f 100644 --- a/include/exec/user/thunk.h +++ b/include/exec/user/thunk.h @@ -73,6 +73,7 @@ void thunk_register_struct_direct(int id, const char *name, const StructEntry *se1); const argtype *thunk_convert(void *dst, const void *src, const argtype *type_ptr, int to_host); +const argtype *thunk_print(void *arg, const argtype *type_ptr); extern StructEntry *struct_entries; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index be67391ba4..5c964389c1 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -184,6 +184,26 @@ struct linux_binprm { int (*core_dump)(int, const CPUArchState *); /* coredump routine */ }; +typedef struct IOCTLEntry IOCTLEntry; + +typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, int cmd, abi_long arg); + +struct IOCTLEntry { + int target_cmd; + unsigned int host_cmd; + const char *name; + int access; + do_ioctl_fn *do_ioctl; + const argtype arg_type[5]; +}; + +extern IOCTLEntry ioctl_entries[]; + +#define IOC_R 0x0001 +#define IOC_W 0x0002 +#define IOC_RW (IOC_R | IOC_W) + void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, abi_ulong stringp, int push_ptr); diff --git a/linux-user/strace.c b/linux-user/strace.c index 32e5e987ac..5235b2260c 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -860,6 +860,44 @@ print_syscall_ret_listxattr(const struct syscallname *name, abi_long ret, #define print_syscall_ret_flistxattr print_syscall_ret_listxattr #endif +#ifdef TARGET_NR_ioctl +static void +print_syscall_ret_ioctl(const struct syscallname *name, abi_long ret, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_err(ret); + + if (ret >= 0) { + qemu_log(TARGET_ABI_FMT_ld, ret); + + const IOCTLEntry *ie; + const argtype *arg_type; + void *argptr; + int target_size; + + for (ie = ioctl_entries; ie->target_cmd != 0; ie++) { + if (ie->target_cmd == arg1) { + break; + } + } + + if (ie->target_cmd == arg1 && + (ie->access == IOC_R || ie->access == IOC_RW)) { + arg_type = ie->arg_type; + qemu_log(" ("); + arg_type++; + target_size = thunk_type_size(arg_type, 0); + argptr = lock_user(VERIFY_READ, arg2, target_size, 1); + thunk_print(argptr, arg_type); + unlock_user(argptr, arg2, target_size); + qemu_log(")"); + } + } + qemu_log("\n"); +} +#endif + UNUSED static struct flags access_flags[] = { FLAG_GENERIC(F_OK), FLAG_GENERIC(R_OK), @@ -3026,6 +3064,75 @@ print_statx(const struct syscallname *name, } #endif +#ifdef TARGET_NR_ioctl +static void +print_ioctl(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_raw_param("%d", arg0, 0); + + const IOCTLEntry *ie; + const argtype *arg_type; + void *argptr; + int target_size; + + for (ie = ioctl_entries; ie->target_cmd != 0; ie++) { + if (ie->target_cmd == arg1) { + break; + } + } + + if (ie->target_cmd == 0) { + print_raw_param("%#x", arg1, 0); + print_raw_param("%#x", arg2, 1); + } else { + qemu_log("%s", ie->name); + arg_type = ie->arg_type; + + if (arg_type[0] != TYPE_NULL) { + qemu_log(","); + + switch (arg_type[0]) { + case TYPE_PTRVOID: + print_pointer(arg2, 1); + break; + case TYPE_CHAR: + case TYPE_SHORT: + case TYPE_INT: + print_raw_param("%d", arg2, 1); + break; + case TYPE_LONG: + print_raw_param(TARGET_ABI_FMT_ld, arg2, 1); + break; + case TYPE_ULONG: + print_raw_param(TARGET_ABI_FMT_lu, arg2, 1); + break; + case TYPE_PTR: + switch (ie->access) { + case IOC_R: + print_pointer(arg2, 1); + break; + case IOC_W: + case IOC_RW: + arg_type++; + target_size = thunk_type_size(arg_type, 0); + argptr = lock_user(VERIFY_READ, arg2, target_size, 1); + thunk_print(argptr, arg_type); + unlock_user(argptr, arg2, target_size); + break; + } + break; + default: + g_assert_not_reached(); + } + } + } + print_syscall_epilogue(name); +} +#endif + /* * An array of all of the syscalls we know about */ diff --git a/linux-user/strace.list b/linux-user/strace.list index ebb713252c..a04706a524 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -433,7 +433,8 @@ { TARGET_NR_io_cancel, "io_cancel" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_ioctl -{ TARGET_NR_ioctl, "ioctl" , "%s(%d,%#x,%#x)", NULL, NULL }, +{ TARGET_NR_ioctl, "ioctl" , NULL, print_ioctl, + print_syscall_ret_ioctl}, #endif #ifdef TARGET_NR_io_destroy { TARGET_NR_io_destroy, "io_destroy" , NULL, NULL, NULL }, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 506b94a12c..82afadcea0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4481,24 +4481,6 @@ STRUCT_MAX #undef STRUCT #undef STRUCT_SPECIAL -typedef struct IOCTLEntry IOCTLEntry; - -typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp, - int fd, int cmd, abi_long arg); - -struct IOCTLEntry { - int target_cmd; - unsigned int host_cmd; - const char *name; - int access; - do_ioctl_fn *do_ioctl; - const argtype arg_type[5]; -}; - -#define IOC_R 0x0001 -#define IOC_W 0x0002 -#define IOC_RW (IOC_R | IOC_W) - #define MAX_STRUCT_SIZE 4096 #ifdef CONFIG_FIEMAP @@ -5374,7 +5356,7 @@ static abi_long do_ioctl_drm(const IOCTLEntry *ie, uint8_t *buf_temp, #endif -static IOCTLEntry ioctl_entries[] = { +IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, #define IOCTL_SPECIAL(cmd, access, dofn, ...) \ diff --git a/thunk.c b/thunk.c index 7f31cffe09..c5d9719747 100644 --- a/thunk.c +++ b/thunk.c @@ -271,6 +271,160 @@ const argtype *thunk_convert(void *dst, const void *src, return type_ptr; } +const argtype *thunk_print(void *arg, const argtype *type_ptr) +{ + int type; + + type = *type_ptr++; + + switch (type) { + case TYPE_CHAR: + qemu_log("%c", *(uint8_t *)arg); + break; + case TYPE_SHORT: + qemu_log("%" PRId16, tswap16(*(uint16_t *)arg)); + break; + case TYPE_INT: + qemu_log("%" PRId32, tswap32(*(uint32_t *)arg)); + break; + case TYPE_LONGLONG: + qemu_log("%" PRId64, tswap64(*(uint64_t *)arg)); + break; + case TYPE_ULONGLONG: + qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg)); + break; +#if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32 + case TYPE_PTRVOID: + qemu_log("0x%" PRIx32, tswap32(*(uint32_t *)arg)); + break; + case TYPE_LONG: + qemu_log("%" PRId32, tswap32(*(uint32_t *)arg)); + break; + case TYPE_ULONG: + qemu_log("%" PRIu32, tswap32(*(uint32_t *)arg)); + break; +#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32 + case TYPE_PTRVOID: + qemu_log("0x%" PRIx32, tswap32(*(uint64_t *)arg & 0xffffffff)); + break; + case TYPE_LONG: + qemu_log("%" PRId32, tswap32(*(uint64_t *)arg & 0xffffffff)); + break; + case TYPE_ULONG: + qemu_log("%" PRIu32, tswap32(*(uint64_t *)arg & 0xffffffff)); + break; +#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64 + case TYPE_PTRVOID: + qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg)); + break; + case TYPE_LONG: + qemu_log("%" PRId64, tswap64(*(uint64_t *)arg)); + break; + case TYPE_ULONG: + qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg)); + break; +#else + case TYPE_PTRVOID: + qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg)); + break; + case TYPE_LONG: + qemu_log("%" PRId64, tswap64(*(uint64_t *)arg)); + break; + case TYPE_ULONG: + qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg)); + break; +#endif + case TYPE_OLDDEVT: + { + uint64_t val = 0; + switch (thunk_type_size(type_ptr - 1, 1)) { + case 2: + val = *(uint16_t *)arg; + break; + case 4: + val = *(uint32_t *)arg; + break; + case 8: + val = *(uint64_t *)arg; + break; + } + switch (thunk_type_size(type_ptr - 1, 0)) { + case 2: + qemu_log("%" PRIu16, tswap16(val)); + break; + case 4: + qemu_log("%" PRIu32, tswap32(val)); + break; + case 8: + qemu_log("%" PRIu64, tswap64(val)); + break; + } + } + break; + case TYPE_ARRAY: + { + int i, array_length, arg_size; + uint8_t *a; + int is_string = 0; + + array_length = *type_ptr++; + arg_size = thunk_type_size(type_ptr, 0); + a = arg; + + if (*type_ptr == TYPE_CHAR) { + qemu_log("\""); + is_string = 1; + } else { + qemu_log("["); + } + + for (i = 0; i < array_length; i++) { + if (i > 0 && !is_string) { + qemu_log(","); + } + thunk_print(a, type_ptr); + a += arg_size; + } + + if (is_string) { + qemu_log("\""); + } else { + qemu_log("]"); + } + + type_ptr = thunk_type_next(type_ptr); + } + break; + case TYPE_STRUCT: + { + int i; + const StructEntry *se; + uint8_t *a; + const argtype *field_types; + const int *arg_offsets; + + se = struct_entries + *type_ptr++; + a = arg; + + field_types = se->field_types; + arg_offsets = se->field_offsets[0]; + + qemu_log("{"); + for (i = 0; i < se->nb_fields; i++) { + if (i > 0) { + qemu_log(","); + } + field_types = thunk_print(a + arg_offsets[i], field_types); + } + qemu_log("}"); + } + break; + default: + g_assert_not_reached(); + } + return type_ptr; +} + /* from em86 */ /* Utility function: Table-driven functions to translate bitmasks From 8f902c540eccd72086e8f67d977e30e05659783f Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Thu, 2 Jul 2020 14:16:36 +0300 Subject: [PATCH 1945/2595] MAINTAINERS: update linux-user maintainer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I haven't been active for a while. Pass the maintainer hat forward to Laurent, who has done a stellar job filling in. Signed-off-by: Riku Voipio Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200702111636.25792-1-riku.voipio@linaro.org> Signed-off-by: Laurent Vivier --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index dec252f38b..29a23b6d3a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2629,8 +2629,7 @@ F: bsd-user/ F: default-configs/*-bsd-user.mak Linux user -M: Riku Voipio -R: Laurent Vivier +M: Laurent Vivier S: Maintained F: linux-user/ F: default-configs/*-linux-user.mak From 45222b9a9016488289a1938a528239c3b83eddb1 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Thu, 18 Jun 2020 12:05:16 -0400 Subject: [PATCH 1946/2595] fuzz: fix broken qtest check at rcu_disable_atfork The qtest_enabled check introduced in d6919e4 always returns false, as it is called prior to configure_accelerators(). Instead of trying to skip rcu_disable_atfork in qemu_main, simply call rcu_enable_atfork in the fuzzer, after qemu_main returns. Reported-by: Thomas Huth Signed-off-by: Alexander Bulekov Message-Id: <20200618160516.2817-1-alxndr@bu.edu> Signed-off-by: Thomas Huth --- softmmu/vl.c | 12 +----------- tests/qtest/fuzz/fuzz.c | 3 +++ 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index 3e15ee2435..9da2e23144 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -3832,17 +3832,7 @@ void qemu_init(int argc, char **argv, char **envp) machine_class); os_daemonize(); - - /* - * If QTest is enabled, keep the rcu_atfork enabled, since system processes - * may be forked testing purposes (e.g. fork-server based fuzzing) The fork - * should happen before a signle cpu instruction is executed, to prevent - * deadlocks. See commit 73c6e40, rcu: "completely disable pthread_atfork - * callbacks as soon as possible" - */ - if (!qtest_enabled()) { - rcu_disable_atfork(); - } + rcu_disable_atfork(); if (pid_file && !qemu_write_pidfile(pid_file, &err)) { error_reportf_err(err, "cannot create PID file: "); diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index a44fe479db..a36d9038e0 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -211,5 +211,8 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) qemu_init(result.we_wordc, result.we_wordv, NULL); + /* re-enable the rcu atfork, which was previously disabled in qemu_init */ + rcu_enable_atfork(); + return 0; } From dda2f556c3503758680b6a868fc49c4886a5039f Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Mon, 22 Jun 2020 12:50:40 -0400 Subject: [PATCH 1947/2595] fuzz: do not use POSIX shm for coverage bitmap We used shm_open with mmap to share libfuzzer's coverage bitmap with child (runner) processes. The same functionality can be achieved with MAP_SHARED | MAP_ANONYMOUS, since we do not care about naming or permissioning the shared memory object. Signed-off-by: Alexander Bulekov Message-Id: <20200622165040.15121-1-alxndr@bu.edu> Reviewed-by: Darren Kenny Reviewed-by: Stefan Hajnoczi Signed-off-by: Thomas Huth --- tests/qtest/fuzz/fork_fuzz.c | 40 ++++++++++++------------------------ 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/tests/qtest/fuzz/fork_fuzz.c b/tests/qtest/fuzz/fork_fuzz.c index 2bd0851903..6ffb2a7937 100644 --- a/tests/qtest/fuzz/fork_fuzz.c +++ b/tests/qtest/fuzz/fork_fuzz.c @@ -17,39 +17,25 @@ void counter_shm_init(void) { - char *shm_path = g_strdup_printf("/qemu-fuzz-cntrs.%d", getpid()); - int fd = shm_open(shm_path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); - g_free(shm_path); - - if (fd == -1) { - perror("Error: "); - exit(1); - } - if (ftruncate(fd, &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START) == -1) { - perror("Error: "); - exit(1); - } - /* Copy what's in the counter region to the shm.. */ - void *rptr = mmap(NULL , - &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START, - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - memcpy(rptr, + /* Copy what's in the counter region to a temporary buffer.. */ + void *copy = malloc(&__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START); + memcpy(copy, &__FUZZ_COUNTERS_START, &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START); - munmap(rptr, &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START); - - /* And map the shm over the counter region */ - rptr = mmap(&__FUZZ_COUNTERS_START, - &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START, - PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0); - - close(fd); - - if (!rptr) { + /* Map a shared region over the counter region */ + if (mmap(&__FUZZ_COUNTERS_START, + &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, + 0, 0) == MAP_FAILED) { perror("Error: "); exit(1); } + + /* Copy the original data back to the counter-region */ + memcpy(&__FUZZ_COUNTERS_START, copy, + &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START); + free(copy); } From 51b3ca97592964a0ece22f9df92592e0f80a78fe Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 17 Jun 2020 16:52:04 +0200 Subject: [PATCH 1948/2595] tests/qtest: Unify the test for the xenfv and xenpv machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have the same check in three places. Let's unify it in a central place instead. Message-Id: <20200622104339.21000-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- tests/qtest/device-introspect-test.c | 5 ----- tests/qtest/libqtest.c | 4 ++++ tests/qtest/qom-test.c | 5 ----- tests/qtest/test-hmp.c | 5 ----- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/tests/qtest/device-introspect-test.c b/tests/qtest/device-introspect-test.c index f2c1576cae..9abb5ec889 100644 --- a/tests/qtest/device-introspect-test.c +++ b/tests/qtest/device-introspect-test.c @@ -287,11 +287,6 @@ static void add_machine_test_case(const char *mname) { char *path, *args; - /* Ignore blacklisted machines */ - if (!memcmp("xenfv", mname, 5) || g_str_equal("xenpv", mname)) { - return; - } - path = g_strdup_printf("device/introspect/concrete/defaults/%s", mname); args = g_strdup_printf("-M %s", mname); qtest_add_data_func(path, args, test_device_intro_concrete); diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 49075b55a1..fd4680590d 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -1232,6 +1232,10 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine), qstr = qobject_to(QString, qobj); g_assert(qstr); mname = qstring_get_str(qstr); + /* Ignore machines that cannot be used for qtests */ + if (!memcmp("xenfv", mname, 5) || g_str_equal("xenpv", mname)) { + continue; + } if (!skip_old_versioned || !qtest_is_old_versioned_machine(mname)) { cb(mname); } diff --git a/tests/qtest/qom-test.c b/tests/qtest/qom-test.c index e338a41194..1acf0d7369 100644 --- a/tests/qtest/qom-test.c +++ b/tests/qtest/qom-test.c @@ -81,11 +81,6 @@ static void add_machine_test_case(const char *mname) { char *path; - /* Ignore blacklisted machines that have known problems */ - if (!memcmp("xenfv", mname, 5) || g_str_equal("xenpv", mname)) { - return; - } - path = g_strdup_printf("qom/%s", mname); qtest_add_data_func(path, g_strdup(mname), test_machine); g_free(path); diff --git a/tests/qtest/test-hmp.c b/tests/qtest/test-hmp.c index b8b1271b9e..d5e7ebd176 100644 --- a/tests/qtest/test-hmp.c +++ b/tests/qtest/test-hmp.c @@ -143,11 +143,6 @@ static void add_machine_test_case(const char *mname) { char *path; - /* Ignore blacklisted machines that have known problems */ - if (!memcmp("xenfv", mname, 5) || g_str_equal("xenpv", mname)) { - return; - } - path = g_strdup_printf("hmp/%s", mname); qtest_add_data_func(path, g_strdup(mname), test_machine); g_free(path); From 9df8b20d1632d108da316134d4d86a00b4028803 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 29 Jun 2020 14:13:24 +0200 Subject: [PATCH 1949/2595] configure / util: Auto-detect the availability of openpty() Recent versions of Solaris (v11.4) now feature an openpty() function, too, causing a build failure since we ship our own implementation of openpty() for Solaris in util/qemu-openpty.c so far. Since there are now both variants available in the wild, with and without this function (and illumos is said to not have this function yet), let's introduce a proper HAVE_OPENPTY define for this to fix the build failure. Message-Id: <20200702143955.678-1-thuth@redhat.com> Tested-by: Michele Denber Signed-off-by: Thomas Huth --- configure | 9 ++++++++- util/qemu-openpty.c | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 8a65240d4a..f8dc64beab 100755 --- a/configure +++ b/configure @@ -5134,10 +5134,14 @@ extern int openpty(int *am, int *as, char *name, void *termp, void *winp); int main(void) { return openpty(0, 0, 0, 0, 0); } EOF -if ! compile_prog "" "" ; then +have_openpty="no" +if compile_prog "" "" ; then + have_openpty="yes" +else if compile_prog "" "-lutil" ; then libs_softmmu="-lutil $libs_softmmu" libs_tools="-lutil $libs_tools" + have_openpty="yes" fi fi @@ -7380,6 +7384,9 @@ fi if test "$have_broken_size_max" = "yes" ; then echo "HAVE_BROKEN_SIZE_MAX=y" >> $config_host_mak fi +if test "$have_openpty" = "yes" ; then + echo "HAVE_OPENPTY=y" >> $config_host_mak +fi # Work around a system header bug with some kernel/XFS header # versions where they both try to define 'struct fsxattr': diff --git a/util/qemu-openpty.c b/util/qemu-openpty.c index 2e8b43bdf5..4b8df96f38 100644 --- a/util/qemu-openpty.c +++ b/util/qemu-openpty.c @@ -52,7 +52,9 @@ #endif #ifdef __sun__ -/* Once Solaris has openpty(), this is going to be removed. */ + +#if !defined(HAVE_OPENPTY) +/* Once illumos has openpty(), this is going to be removed. */ static int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp) { @@ -93,6 +95,7 @@ err: close(mfd); return -1; } +#endif static void cfmakeraw (struct termios *termios_p) { From e8de7ba9ea086c427cd36a10bc3506ac20aa4895 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 26 May 2020 21:13:47 +0300 Subject: [PATCH 1950/2595] block/block-copy: block_copy_dirty_clusters: fix failure check ret may be > 0 on success path at this point. Fix assertion, which may crash currently. Fixes: 4ce5dd3e9b5ee0fac18625860eb3727399ee965e Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200526181347.489557-1-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/block-copy.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block/block-copy.c b/block/block-copy.c index bb8d0569f2..f7428a7c08 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -622,8 +622,10 @@ out: * block_copy_task_run. If it fails, it means some task already failed * for real reason, let's return first failure. * Still, assert that we don't rewrite failure by success. + * + * Note: ret may be positive here because of block-status result. */ - assert(ret == 0 || aio_task_pool_status(aio) < 0); + assert(ret >= 0 || aio_task_pool_status(aio) < 0); ret = aio_task_pool_status(aio); aio_task_pool_free(aio); From a5675f390116a927e320984f02f473a6affc9fcd Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Wed, 17 Jun 2020 16:00:36 +0200 Subject: [PATCH 1951/2595] qcow2: Fix preallocation on images with unaligned sizes When resizing an image with qcow2_co_truncate() using the falloc or full preallocation modes the code assumes that both the old and new sizes are cluster-aligned. There are two problems with this: 1) The calculation of how many clusters are involved does not always get the right result. Example: creating a 60KB image and resizing it (with preallocation=full) to 80KB won't allocate the second cluster. 2) No copy-on-write is performed, so in the previous example if there is a backing file then the first 60KB of the first cluster won't be filled with data from the backing file. This patch fixes both issues. Signed-off-by: Alberto Garcia Message-Id: <20200617140036.20311-1-berto@igalia.com> Reviewed-by: Eric Blake Signed-off-by: Max Reitz --- block/qcow2.c | 17 ++++++++++++++--- tests/qemu-iotests/125 | 24 ++++++++++++++++++++++++ tests/qemu-iotests/125.out | 9 +++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 0cd2e6757e..e20590c3b7 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -4239,8 +4239,8 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, old_file_size = ROUND_UP(old_file_size, s->cluster_size); } - nb_new_data_clusters = DIV_ROUND_UP(offset - old_length, - s->cluster_size); + nb_new_data_clusters = (ROUND_UP(offset, s->cluster_size) - + start_of_cluster(s, old_length)) >> s->cluster_bits; /* This is an overestimation; we will not actually allocate space for * these in the file but just make sure the new refcount structures are @@ -4317,10 +4317,21 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, int64_t nb_clusters = MIN( nb_new_data_clusters, s->l2_slice_size - offset_to_l2_slice_index(s, guest_offset)); - QCowL2Meta allocation = { + unsigned cow_start_length = offset_into_cluster(s, guest_offset); + QCowL2Meta allocation; + guest_offset = start_of_cluster(s, guest_offset); + allocation = (QCowL2Meta) { .offset = guest_offset, .alloc_offset = host_offset, .nb_clusters = nb_clusters, + .cow_start = { + .offset = 0, + .nb_bytes = cow_start_length, + }, + .cow_end = { + .offset = nb_clusters << s->cluster_bits, + .nb_bytes = 0, + }, }; qemu_co_queue_init(&allocation.dependent_requests); diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125 index d510984045..7cb1c19730 100755 --- a/tests/qemu-iotests/125 +++ b/tests/qemu-iotests/125 @@ -164,6 +164,30 @@ for GROWTH_SIZE in 16 48 80; do done done +# Test image resizing using preallocation and unaligned offsets +$QEMU_IMG create -f raw "$TEST_IMG.base" 128k | _filter_img_create +$QEMU_IO -c 'write -q -P 1 0 128k' -f raw "$TEST_IMG.base" +for orig_size in 31k 33k; do + echo "--- Resizing image from $orig_size to 96k ---" + _make_test_img -F raw -b "$TEST_IMG.base" -o cluster_size=64k "$orig_size" + $QEMU_IMG resize -f "$IMGFMT" --preallocation=full "$TEST_IMG" 96k + # The first part of the image should contain data from the backing file + $QEMU_IO -c "read -q -P 1 0 ${orig_size}" "$TEST_IMG" + # The resized part of the image should contain zeroes + $QEMU_IO -c "read -q -P 0 ${orig_size} 63k" "$TEST_IMG" + # If the image does not have an external data file we can also verify its + # actual size. The resized image should have 7 clusters: + # header, L1 table, L2 table, refcount table, refcount block, 2 data clusters + if ! _get_data_file "$TEST_IMG" > /dev/null; then + expected_file_length=$((65536 * 7)) + file_length=$(stat -c '%s' "$TEST_IMG_FILE") + if [ "$file_length" != "$expected_file_length" ]; then + echo "ERROR: file length $file_length (expected $expected_file_length)" + fi + fi + echo +done + # success, all done echo '*** done' rm -f $seq.full diff --git a/tests/qemu-iotests/125.out b/tests/qemu-iotests/125.out index 596905f533..7f76f7af20 100644 --- a/tests/qemu-iotests/125.out +++ b/tests/qemu-iotests/125.out @@ -767,4 +767,13 @@ wrote 2048000/2048000 bytes at offset 0 wrote 81920/81920 bytes at offset 2048000 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=raw size=131072 +--- Resizing image from 31k to 96k --- +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=31744 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw +Image resized. + +--- Resizing image from 33k to 96k --- +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33792 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw +Image resized. + *** done From 57ee95ed4ee7b4c039ec5f0705c45734c56706bc Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Thu, 25 Jun 2020 14:55:30 +0200 Subject: [PATCH 1952/2595] iotests: Make _filter_img_create more active Right now, _filter_img_create just filters out everything that looks format-dependent, and applies some filename filters. That means that we have to add another filter line every time some format gets a new creation option. This can be avoided by instead discarding everything and just keeping what we know is format-independent (format, size, backing file, encryption information[1], preallocation) or just interesting to have in the reference output (external data file path). Furthermore, we probably want to sort these options. Format drivers are not required to define them in any specific order, so the output is effectively random (although this has never bothered us until now). We need a specific order for our reference outputs, though. Unfortunately, just using a plain "sort" would change a lot of existing reference outputs, so we have to pre-filter the option keys to keep our existing order (fmt, size, backing*, data, encryption info, preallocation). Finally, this makes it difficult for _filter_img_create to automagically work for QMP output. Thus, this patch adds a separate _filter_img_create_for_qmp function that echos every line verbatim that does not start with "Formatting", and pipes those "Formatting" lines to _filter_img_create. [1] Actually, the only thing that is really important is whether encryption is enabled or not. A patch by Maxim thus removes all other "encrypt.*" options from the output: https://lists.nongnu.org/archive/html/qemu-block/2020-06/msg00339.html But that patch needs to come later so we can get away with changing as few reference outputs in this patch here as possible. Signed-off-by: Max Reitz Message-Id: <20200625125548.870061-2-mreitz@redhat.com> Reviewed-by: Maxim Levitsky --- tests/qemu-iotests/112.out | 2 +- tests/qemu-iotests/141 | 2 +- tests/qemu-iotests/153 | 9 ++- tests/qemu-iotests/common.filter | 109 ++++++++++++++++++++++++------- 4 files changed, 91 insertions(+), 31 deletions(-) diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out index ae0318cabe..182655dbf6 100644 --- a/tests/qemu-iotests/112.out +++ b/tests/qemu-iotests/112.out @@ -5,7 +5,7 @@ QA output created by 112 qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 refcount_bits=-1 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141 index 5192d256e3..6d1b7b0d4c 100755 --- a/tests/qemu-iotests/141 +++ b/tests/qemu-iotests/141 @@ -68,7 +68,7 @@ test_blockjob() _send_qemu_cmd $QEMU_HANDLE \ "$1" \ "$2" \ - | _filter_img_create | _filter_qmp_empty_return + | _filter_img_create_in_qmp | _filter_qmp_empty_return # We want this to return an error because the block job is still running _send_qemu_cmd $QEMU_HANDLE \ diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 index cf961d3609..11e3d28841 100755 --- a/tests/qemu-iotests/153 +++ b/tests/qemu-iotests/153 @@ -167,11 +167,10 @@ done echo echo "== Creating ${TEST_IMG}.[abc] ==" | _filter_testdir -( - $QEMU_IMG create -f qcow2 "${TEST_IMG}.a" -b "${TEST_IMG}" - $QEMU_IMG create -f qcow2 "${TEST_IMG}.b" -b "${TEST_IMG}" - $QEMU_IMG create -f qcow2 "${TEST_IMG}.c" -b "${TEST_IMG}.b" -) | _filter_img_create +$QEMU_IMG create -f qcow2 "${TEST_IMG}.a" -b "${TEST_IMG}" | _filter_img_create +$QEMU_IMG create -f qcow2 "${TEST_IMG}.b" -b "${TEST_IMG}" | _filter_img_create +$QEMU_IMG create -f qcow2 "${TEST_IMG}.c" -b "${TEST_IMG}.b" \ + | _filter_img_create echo echo "== Two devices sharing the same file in backing chain ==" diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 03e4f71808..f8cd80ff1f 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -122,38 +122,99 @@ _filter_actual_image_size() # replace driver-specific options in the "Formatting..." line _filter_img_create() { - data_file_filter=() - if data_file=$(_get_data_file "$TEST_IMG"); then - data_file_filter=(-e "s# data_file=$data_file##") + # Split the line into the pre-options part ($filename_part, which + # precedes ", fmt=") and the options part ($options, which starts + # with "fmt=") + # (And just echo everything before the first "^Formatting") + readarray formatting_line < <($SED -e 's/, fmt=/\n/') + + filename_part='' + options='' + lines=${#formatting_line[@]} + for ((i = 0; i < $lines; i++)); do + line=${formatting_line[i]} + unset formatting_line[i] + + filename_part="$filename_part$line" + + if echo "$line" | grep -q '^Formatting'; then + next_i=$((i + 1)) + if [ -n "${formatting_line[next_i]}" ]; then + options="fmt=${formatting_line[@]}" + fi + break + fi + done + + # Set grep_data_file to '\|data_file' to keep it; make it empty + # to drop it. + # We want to drop it if it is part of the global $IMGOPTS, and we + # want to keep it otherwise (if the test specifically wants to + # test data files). + grep_data_file=(-e data_file) + if _get_data_file "$TEST_IMG" > /dev/null; then + grep_data_file=() fi - $SED "${data_file_filter[@]}" \ + filename_filters=( -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ -e "s#$TEST_DIR#TEST_DIR#g" \ -e "s#$SOCK_DIR#SOCK_DIR#g" \ -e "s#$IMGFMT#IMGFMT#g" \ -e 's#nbd:127.0.0.1:[0-9]\\+#TEST_DIR/t.IMGFMT#g' \ - -e 's#nbd+unix:///\??socket=SOCK_DIR/nbd#TEST_DIR/t.IMGFMT#g' \ - -e "s# encryption=off##g" \ - -e "s# cluster_size=[0-9]\\+##g" \ - -e "s# table_size=[0-9]\\+##g" \ - -e "s# compat=[^ ]*##g" \ - -e "s# compat6=\\(on\\|off\\)##g" \ - -e "s# static=\\(on\\|off\\)##g" \ - -e "s# zeroed_grain=\\(on\\|off\\)##g" \ - -e "s# subformat=[^ ]*##g" \ - -e "s# adapter_type=[^ ]*##g" \ - -e "s# hwversion=[^ ]*##g" \ - -e "s# lazy_refcounts=\\(on\\|off\\)##g" \ - -e "s# block_size=[0-9]\\+##g" \ - -e "s# block_state_zero=\\(on\\|off\\)##g" \ - -e "s# log_size=[0-9]\\+##g" \ - -e "s# refcount_bits=[0-9]\\+##g" \ - -e "s# key-secret=[a-zA-Z0-9]\\+##g" \ - -e "s# iter-time=[0-9]\\+##g" \ - -e "s# force_size=\\(on\\|off\\)##g" \ - -e "s# compression_type=[a-zA-Z0-9]\\+##g" + -e 's#nbd+unix:///\??socket=SOCK_DIR/nbd#TEST_DIR/t.IMGFMT#g' + ) + + filename_part=$(echo "$filename_part" | $SED "${filename_filters[@]}") + + # Break the option line before each option (preserving pre-existing + # line breaks by replacing them by \0 and restoring them at the end), + # then filter out the options we want to keep and sort them according + # to some order that all block drivers used at the time of writing + # this function. + options=$( + echo "$options" \ + | tr '\n' '\0' \ + | $SED -e 's/ \([a-z0-9_.-]*\)=/\n\1=/g' \ + | grep -a -e '^fmt' -e '^size' -e '^backing' -e '^preallocation' \ + -e '^encrypt' "${grep_data_file[@]}" \ + | $SED "${filename_filters[@]}" \ + -e 's/^\(fmt\)/0-\1/' \ + -e 's/^\(size\)/1-\1/' \ + -e 's/^\(backing\)/2-\1/' \ + -e 's/^\(data_file\)/3-\1/' \ + -e 's/^\(encryption\)/4-\1/' \ + -e 's/^\(encrypt\.format\)/5-\1/' \ + -e 's/^\(encrypt\.key-secret\)/6-\1/' \ + -e 's/^\(encrypt\.iter-time\)/7-\1/' \ + -e 's/^\(preallocation\)/8-\1/' \ + | sort \ + | $SED -e 's/^[0-9]-//' \ + | tr '\n\0' ' \n' \ + | $SED -e 's/^ *$//' -e 's/ *$//' + ) + + if [ -n "$options" ]; then + echo "$filename_part, $options" + elif [ -n "$filename_part" ]; then + echo "$filename_part" + fi +} + +# Filter the "Formatting..." line in QMP output (leaving the QMP output +# untouched) +# (In contrast to _filter_img_create(), this function does not support +# multi-line Formatting output) +_filter_img_create_in_qmp() +{ + while read -r line; do + if echo "$line" | grep -q '^Formatting'; then + echo "$line" | _filter_img_create + else + echo "$line" + fi + done } _filter_img_create_size() From cbb32e79dd13cc46137697de2c89d35b2b74a3f6 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:31 +0200 Subject: [PATCH 1953/2595] iotests: filter few more luks specific create options This allows more tests to be able to have same output on both qcow2 luks encrypted images and raw luks images Signed-off-by: Maxim Levitsky Signed-off-by: Max Reitz Reviewed-by: Maxim Levitsky Message-Id: <20200625125548.870061-3-mreitz@redhat.com> --- tests/qemu-iotests/087.out | 6 +++--- tests/qemu-iotests/134.out | 2 +- tests/qemu-iotests/158.out | 4 ++-- tests/qemu-iotests/188.out | 2 +- tests/qemu-iotests/189.out | 4 ++-- tests/qemu-iotests/198.out | 4 ++-- tests/qemu-iotests/263.out | 4 ++-- tests/qemu-iotests/284.out | 6 +++--- tests/qemu-iotests/common.filter | 5 +---- 9 files changed, 17 insertions(+), 20 deletions(-) diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out index 2d92ea847b..b61ba638af 100644 --- a/tests/qemu-iotests/087.out +++ b/tests/qemu-iotests/087.out @@ -34,7 +34,7 @@ QMP_VERSION === Encrypted image QCow === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on Testing: QMP_VERSION {"return": {}} @@ -46,7 +46,7 @@ QMP_VERSION === Encrypted image LUKS === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encrypt.format=luks encrypt.key-secret=sec0 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Testing: QMP_VERSION {"return": {}} @@ -58,7 +58,7 @@ QMP_VERSION === Missing driver === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on Testing: -S QMP_VERSION {"return": {}} diff --git a/tests/qemu-iotests/134.out b/tests/qemu-iotests/134.out index 09d46f6b17..4abc5b5f7d 100644 --- a/tests/qemu-iotests/134.out +++ b/tests/qemu-iotests/134.out @@ -1,5 +1,5 @@ QA output created by 134 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on == reading whole image == read 134217728/134217728 bytes at offset 0 diff --git a/tests/qemu-iotests/158.out b/tests/qemu-iotests/158.out index 6def216e55..f28a17626b 100644 --- a/tests/qemu-iotests/158.out +++ b/tests/qemu-iotests/158.out @@ -1,6 +1,6 @@ QA output created by 158 == create base == -Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on encrypt.key-secret=sec0 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on == writing whole image == wrote 134217728/134217728 bytes at offset 0 @@ -10,7 +10,7 @@ wrote 134217728/134217728 bytes at offset 0 read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == create overlay == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on encrypt.key-secret=sec0 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on == writing part of a cluster == wrote 1024/1024 bytes at offset 0 diff --git a/tests/qemu-iotests/188.out b/tests/qemu-iotests/188.out index c568ef3701..5426861b18 100644 --- a/tests/qemu-iotests/188.out +++ b/tests/qemu-iotests/188.out @@ -1,5 +1,5 @@ QA output created by 188 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 == reading whole image == read 16777216/16777216 bytes at offset 0 diff --git a/tests/qemu-iotests/189.out b/tests/qemu-iotests/189.out index a0b7c9c24c..bc213cbe14 100644 --- a/tests/qemu-iotests/189.out +++ b/tests/qemu-iotests/189.out @@ -1,6 +1,6 @@ QA output created by 189 == create base == -Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216 == writing whole image == wrote 16777216/16777216 bytes at offset 0 @@ -10,7 +10,7 @@ wrote 16777216/16777216 bytes at offset 0 read 16777216/16777216 bytes at offset 0 16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == create overlay == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base encrypt.format=luks encrypt.key-secret=sec1 encrypt.iter-time=10 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base == writing part of a cluster == wrote 1024/1024 bytes at offset 0 diff --git a/tests/qemu-iotests/198.out b/tests/qemu-iotests/198.out index 6280ae6eed..4b800e70db 100644 --- a/tests/qemu-iotests/198.out +++ b/tests/qemu-iotests/198.out @@ -1,12 +1,12 @@ QA output created by 198 == create base == -Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216 == writing whole image base == wrote 16777216/16777216 bytes at offset 0 16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == create overlay == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base encrypt.format=luks encrypt.key-secret=sec1 encrypt.iter-time=10 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base == writing whole image layer == wrote 16777216/16777216 bytes at offset 0 diff --git a/tests/qemu-iotests/263.out b/tests/qemu-iotests/263.out index 0c982c55cb..54bfbeeff8 100644 --- a/tests/qemu-iotests/263.out +++ b/tests/qemu-iotests/263.out @@ -2,7 +2,7 @@ QA output created by 263 testing LUKS qcow2 encryption -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 == reading the whole image == read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -21,7 +21,7 @@ read 982528/982528 bytes at offset 66048 testing legacy AES qcow2 encryption -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=aes encrypt.key-secret=sec0 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 == reading the whole image == read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/284.out b/tests/qemu-iotests/284.out index 48216f5742..a929239302 100644 --- a/tests/qemu-iotests/284.out +++ b/tests/qemu-iotests/284.out @@ -2,7 +2,7 @@ QA output created by 284 testing LUKS qcow2 encryption -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 == cluster size 512 == checking image refcounts == @@ -21,7 +21,7 @@ wrote 1/1 bytes at offset 512 == rechecking image refcounts == No errors were found on the image. -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 == cluster size 2048 == checking image refcounts == @@ -40,7 +40,7 @@ wrote 1/1 bytes at offset 2048 == rechecking image refcounts == No errors were found on the image. -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 == cluster size 32768 == checking image refcounts == diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index f8cd80ff1f..d967adc59a 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -178,16 +178,13 @@ _filter_img_create() | tr '\n' '\0' \ | $SED -e 's/ \([a-z0-9_.-]*\)=/\n\1=/g' \ | grep -a -e '^fmt' -e '^size' -e '^backing' -e '^preallocation' \ - -e '^encrypt' "${grep_data_file[@]}" \ + -e '^encryption' "${grep_data_file[@]}" \ | $SED "${filename_filters[@]}" \ -e 's/^\(fmt\)/0-\1/' \ -e 's/^\(size\)/1-\1/' \ -e 's/^\(backing\)/2-\1/' \ -e 's/^\(data_file\)/3-\1/' \ -e 's/^\(encryption\)/4-\1/' \ - -e 's/^\(encrypt\.format\)/5-\1/' \ - -e 's/^\(encrypt\.key-secret\)/6-\1/' \ - -e 's/^\(encrypt\.iter-time\)/7-\1/' \ -e 's/^\(preallocation\)/8-\1/' \ | sort \ | $SED -e 's/^[0-9]-//' \ From dc4ab0291983d4d0df7c32566e45da42817a343a Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Thu, 25 Jun 2020 14:55:32 +0200 Subject: [PATCH 1954/2595] iotests/common.rc: Add _require_working_luks That the luks driver is present is little indication on whether it is actually working. Without the crypto libraries linked in, it does not work. So add this function, which tries to create a luks image to see whether that actually works. Signed-off-by: Max Reitz Message-Id: <20200625125548.870061-4-mreitz@redhat.com> Reviewed-by: Maxim Levitsky --- tests/qemu-iotests/common.rc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index ba912555ca..f3667f48ab 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -740,6 +740,33 @@ _unsupported_imgopts() done } +# Caution: Overwrites $TEST_DIR/t.luks +_require_working_luks() +{ + file="$TEST_DIR/t.luks" + + output=$( + $QEMU_IMG create -f luks \ + --object secret,id=sec0,data=hunter0 \ + -o key-secret=sec0 \ + -o iter-time=10 \ + "$file" \ + 1M \ + 2>&1 + ) + status=$? + + IMGFMT='luks' _rm_test_img "$file" + + if [ $status != 0 ]; then + reason=$(echo "$output" | grep "$file:" | $SED -e "s#.*$file: *##") + if [ -z "$reason" ]; then + reason="Failed to create a LUKS image" + fi + _notrun "$reason" + fi +} + # this test requires that a specified command (executable) exists # _require_command() From d849acab4196b35339e55735889ed7481be6ff2f Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Thu, 25 Jun 2020 14:55:33 +0200 Subject: [PATCH 1955/2595] iotests.py: Add qemu_img_pipe_and_status() This function will be used by the next patch, which intends to check both the exit code and qemu-img's output. Signed-off-by: Max Reitz Message-Id: <20200625125548.870061-5-mreitz@redhat.com> Reviewed-by: Maxim Levitsky [mreitz: Rebased on 49438972b8c2e] Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index ef739dd1e3..423974d3f6 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -29,7 +29,7 @@ import struct import subprocess import sys from typing import (Any, Callable, Dict, Iterable, - List, Optional, Sequence, TypeVar) + List, Optional, Sequence, Tuple, TypeVar) import unittest # pylint: disable=import-error, wrong-import-position @@ -90,15 +90,24 @@ luks_default_secret_object = 'secret,id=keysec0,data=' + \ luks_default_key_secret_opt = 'key-secret=keysec0' -def qemu_img(*args): - '''Run qemu-img and return the exit code''' - devnull = open('/dev/null', 'r+') - exitcode = subprocess.call(qemu_img_args + list(args), - stdin=devnull, stdout=devnull) - if exitcode < 0: +def qemu_img_pipe_and_status(*args: str) -> Tuple[str, int]: + """ + Run qemu-img and return both its output and its exit code + """ + subp = subprocess.Popen(qemu_img_args + list(args), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True) + output = subp.communicate()[0] + if subp.returncode < 0: sys.stderr.write('qemu-img received signal %i: %s\n' - % (-exitcode, ' '.join(qemu_img_args + list(args)))) - return exitcode + % (-subp.returncode, + ' '.join(qemu_img_args + list(args)))) + return (output, subp.returncode) + +def qemu_img(*args: str) -> int: + '''Run qemu-img and return the exit code''' + return qemu_img_pipe_and_status(*args)[1] def ordered_qmp(qmsg, conv_keys=True): # Dictionaries are not ordered prior to 3.6, therefore: @@ -140,18 +149,9 @@ def qemu_img_verbose(*args): % (-exitcode, ' '.join(qemu_img_args + list(args)))) return exitcode -def qemu_img_pipe(*args): +def qemu_img_pipe(*args: str) -> str: '''Run qemu-img and return its output''' - subp = subprocess.Popen(qemu_img_args + list(args), - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - universal_newlines=True) - output = subp.communicate()[0] - if subp.returncode < 0: - sys.stderr.write('qemu-img received signal %i: %s\n' - % (-subp.returncode, - ' '.join(qemu_img_args + list(args)))) - return output + return qemu_img_pipe_and_status(*args)[0] def qemu_img_log(*args): result = qemu_img_pipe(*args) From 6649f4bd2920301e0ef0e8e14d10cf0e00b4071e Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Thu, 25 Jun 2020 14:55:34 +0200 Subject: [PATCH 1956/2595] iotests.py: Add (verify|has)_working_luks() Similar to _require_working_luks for bash tests, these functions can be used to check whether our luks driver can actually create images. Signed-off-by: Max Reitz Message-Id: <20200625125548.870061-6-mreitz@redhat.com> Reviewed-by: Maxim Levitsky --- tests/qemu-iotests/iotests.py | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 423974d3f6..1d8a45c02e 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -1052,6 +1052,45 @@ def verify_quorum(): if not supports_quorum(): notrun('quorum support missing') +def has_working_luks() -> Tuple[bool, str]: + """ + Check whether our LUKS driver can actually create images + (this extends to LUKS encryption for qcow2). + + If not, return the reason why. + """ + + img_file = f'{test_dir}/luks-test.luks' + (output, status) = \ + qemu_img_pipe_and_status('create', '-f', 'luks', + '--object', luks_default_secret_object, + '-o', luks_default_key_secret_opt, + '-o', 'iter-time=10', + img_file, '1G') + try: + os.remove(img_file) + except OSError: + pass + + if status != 0: + reason = output + for line in output.splitlines(): + if img_file + ':' in line: + reason = line.split(img_file + ':', 1)[1].strip() + break + + return (False, reason) + else: + return (True, '') + +def verify_working_luks(): + """ + Skip test suite if LUKS does not work + """ + (working, reason) = has_working_luks() + if not working: + notrun(reason) + def qemu_pipe(*args): """ Run qemu with an option to print something and exit (e.g. a help option). From d2a839ede850bbb23493ac03b1c2477026fe6bc7 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Thu, 25 Jun 2020 14:55:35 +0200 Subject: [PATCH 1957/2595] iotests: Check whether luks works Whenever running an iotest for the luks format, we should check whether luks actually really works. Tests that try to create luks-encrypted qcow2 images should do the same. Signed-off-by: Max Reitz Message-Id: <20200625125548.870061-7-mreitz@redhat.com> Reviewed-by: Maxim Levitsky --- tests/qemu-iotests/087 | 1 + tests/qemu-iotests/178 | 1 + tests/qemu-iotests/188 | 1 + tests/qemu-iotests/189 | 1 + tests/qemu-iotests/198 | 1 + tests/qemu-iotests/206 | 1 + tests/qemu-iotests/263 | 1 + tests/qemu-iotests/284 | 1 + tests/qemu-iotests/common.rc | 3 +++ tests/qemu-iotests/iotests.py | 5 +++++ 10 files changed, 16 insertions(+) diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 index bdfdad3454..678e748c58 100755 --- a/tests/qemu-iotests/087 +++ b/tests/qemu-iotests/087 @@ -39,6 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file _supported_os Linux +_require_working_luks do_run_qemu() { diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178 index 7cf0e27154..f09b27caac 100755 --- a/tests/qemu-iotests/178 +++ b/tests/qemu-iotests/178 @@ -41,6 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt raw qcow2 _supported_proto file _supported_os Linux +_require_working_luks echo "== Input validation ==" echo diff --git a/tests/qemu-iotests/188 b/tests/qemu-iotests/188 index 09b9b6083a..13b225fded 100755 --- a/tests/qemu-iotests/188 +++ b/tests/qemu-iotests/188 @@ -39,6 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic _supported_os Linux +_require_working_luks size=16M diff --git a/tests/qemu-iotests/189 b/tests/qemu-iotests/189 index c9ce9d3bed..e6a84b8a3b 100755 --- a/tests/qemu-iotests/189 +++ b/tests/qemu-iotests/189 @@ -39,6 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic _supported_os Linux +_require_working_luks size=16M diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198 index fb0d5a29d3..aeb059d5ea 100755 --- a/tests/qemu-iotests/198 +++ b/tests/qemu-iotests/198 @@ -39,6 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic _supported_os Linux +_require_working_luks size=16M diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206 index f42432a838..11bc51f256 100755 --- a/tests/qemu-iotests/206 +++ b/tests/qemu-iotests/206 @@ -24,6 +24,7 @@ import iotests from iotests import imgfmt iotests.script_initialize(supported_fmts=['qcow2']) +iotests.verify_working_luks() with iotests.FilePath('t.qcow2') as disk_path, \ iotests.FilePath('t.qcow2.base') as backing_path, \ diff --git a/tests/qemu-iotests/263 b/tests/qemu-iotests/263 index d2c030fae9..f598a12899 100755 --- a/tests/qemu-iotests/263 +++ b/tests/qemu-iotests/263 @@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic _supported_os Linux +_require_working_luks size=1M diff --git a/tests/qemu-iotests/284 b/tests/qemu-iotests/284 index 071e89b33e..9f6c29a79c 100755 --- a/tests/qemu-iotests/284 +++ b/tests/qemu-iotests/284 @@ -39,6 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic _supported_os Linux +_require_working_luks size=1M diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index f3667f48ab..7ac46edc1f 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -605,6 +605,9 @@ _supported_fmt() # setting IMGFMT_GENERIC to false. for f; do if [ "$f" = "$IMGFMT" -o "$f" = "generic" -a "$IMGFMT_GENERIC" = "true" ]; then + if [ "$IMGFMT" = "luks" ]; then + _require_working_luks + fi return fi done diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 1d8a45c02e..f1e0733dda 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -1010,12 +1010,17 @@ def _verify_image_format(supported_fmts: Sequence[str] = (), # similar to # _supported_fmt generic # for bash tests + if imgfmt == 'luks': + verify_working_luks() return not_sup = supported_fmts and (imgfmt not in supported_fmts) if not_sup or (imgfmt in unsupported_fmts): notrun('not suitable for this image format: %s' % imgfmt) + if imgfmt == 'luks': + verify_working_luks() + def _verify_protocol(supported: Sequence[str] = (), unsupported: Sequence[str] = ()) -> None: assert not (supported and unsupported) From 43cbd06df2dcdfe236e68351bb3c350e0d1d857a Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:36 +0200 Subject: [PATCH 1958/2595] qcrypto/core: add generic infrastructure for crypto options amendment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be used first to implement luks keyslot management. block_crypto_amend_opts_init will be used to convert qemu-img cmdline to QCryptoBlockAmendOptions Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé Message-Id: <20200608094030.670121-2-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- block/crypto.c | 17 +++++++++++++++++ block/crypto.h | 3 +++ crypto/block.c | 29 +++++++++++++++++++++++++++++ crypto/blockpriv.h | 8 ++++++++ include/crypto/block.h | 22 ++++++++++++++++++++++ qapi/crypto.json | 16 ++++++++++++++++ 6 files changed, 95 insertions(+) diff --git a/block/crypto.c b/block/crypto.c index 973b57b3eb..dcf8b42bb2 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -202,6 +202,23 @@ block_crypto_create_opts_init(QDict *opts, Error **errp) return ret; } +QCryptoBlockAmendOptions * +block_crypto_amend_opts_init(QDict *opts, Error **errp) +{ + Visitor *v; + QCryptoBlockAmendOptions *ret; + + v = qobject_input_visitor_new_flat_confused(opts, errp); + if (!v) { + return NULL; + } + + visit_type_QCryptoBlockAmendOptions(v, NULL, &ret, errp); + + visit_free(v); + return ret; +} + static int block_crypto_open_generic(QCryptoBlockFormat format, QemuOptsList *opts_spec, diff --git a/block/crypto.h b/block/crypto.h index b935695e79..06e044c9be 100644 --- a/block/crypto.h +++ b/block/crypto.h @@ -91,6 +91,9 @@ QCryptoBlockCreateOptions * block_crypto_create_opts_init(QDict *opts, Error **errp); +QCryptoBlockAmendOptions * +block_crypto_amend_opts_init(QDict *opts, Error **errp); + QCryptoBlockOpenOptions * block_crypto_open_opts_init(QDict *opts, Error **errp); diff --git a/crypto/block.c b/crypto/block.c index 6f42b32f1e..eb057948b5 100644 --- a/crypto/block.c +++ b/crypto/block.c @@ -150,6 +150,35 @@ qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts, return crypto != NULL; } +int qcrypto_block_amend_options(QCryptoBlock *block, + QCryptoBlockReadFunc readfunc, + QCryptoBlockWriteFunc writefunc, + void *opaque, + QCryptoBlockAmendOptions *options, + bool force, + Error **errp) +{ + if (options->format != block->format) { + error_setg(errp, + "Cannot amend encryption format"); + return -1; + } + + if (!block->driver->amend) { + error_setg(errp, + "Crypto format %s doesn't support format options amendment", + QCryptoBlockFormat_str(block->format)); + return -1; + } + + return block->driver->amend(block, + readfunc, + writefunc, + opaque, + options, + force, + errp); +} QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block, Error **errp) diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h index 71c59cb542..3c7ccea504 100644 --- a/crypto/blockpriv.h +++ b/crypto/blockpriv.h @@ -62,6 +62,14 @@ struct QCryptoBlockDriver { void *opaque, Error **errp); + int (*amend)(QCryptoBlock *block, + QCryptoBlockReadFunc readfunc, + QCryptoBlockWriteFunc writefunc, + void *opaque, + QCryptoBlockAmendOptions *options, + bool force, + Error **errp); + int (*get_info)(QCryptoBlock *block, QCryptoBlockInfo *info, Error **errp); diff --git a/include/crypto/block.h b/include/crypto/block.h index c77ccaf9c0..d274819791 100644 --- a/include/crypto/block.h +++ b/include/crypto/block.h @@ -144,6 +144,28 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, void *opaque, Error **errp); +/** + * qcrypto_block_amend_options: + * @block: the block encryption object + * + * @readfunc: callback for reading data from the volume header + * @writefunc: callback for writing data to the volume header + * @opaque: data to pass to @readfunc and @writefunc + * @options: the new/amended encryption options + * @force: hint for the driver to allow unsafe operation + * @errp: error pointer + * + * Changes the crypto options of the encryption format + * + */ +int qcrypto_block_amend_options(QCryptoBlock *block, + QCryptoBlockReadFunc readfunc, + QCryptoBlockWriteFunc writefunc, + void *opaque, + QCryptoBlockAmendOptions *options, + bool force, + Error **errp); + /** * qcrypto_block_calculate_payload_offset: diff --git a/qapi/crypto.json b/qapi/crypto.json index b2a4cff683..aeb6c7ef7b 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -309,3 +309,19 @@ 'base': 'QCryptoBlockInfoBase', 'discriminator': 'format', 'data': { 'luks': 'QCryptoBlockInfoLUKS' } } + + + +## +# @QCryptoBlockAmendOptions: +# +# The options that are available for all encryption formats +# when amending encryption settings +# +# Since: 5.1 +## +{ 'union': 'QCryptoBlockAmendOptions', + 'base': 'QCryptoBlockOptionsBase', + 'discriminator': 'format', + 'data': { + } } From 557d2bdcca8fa42e9aa956210e863192ddeb8acf Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:37 +0200 Subject: [PATCH 1959/2595] qcrypto/luks: implement encryption key management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Next few patches will expose that functionality to the user. Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé Message-Id: <20200608094030.670121-3-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- crypto/block-luks.c | 416 +++++++++++++++++++++++++++++++++++++++++++- qapi/crypto.json | 59 ++++++- 2 files changed, 469 insertions(+), 6 deletions(-) diff --git a/crypto/block-luks.c b/crypto/block-luks.c index 4861db810c..564caa1094 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -32,6 +32,7 @@ #include "qemu/uuid.h" #include "qemu/coroutine.h" +#include "qemu/bitmap.h" /* * Reference for the LUKS format implemented here is @@ -70,6 +71,9 @@ typedef struct QCryptoBlockLUKSKeySlot QCryptoBlockLUKSKeySlot; #define QCRYPTO_BLOCK_LUKS_SECTOR_SIZE 512LL +#define QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME_MS 2000 +#define QCRYPTO_BLOCK_LUKS_ERASE_ITERATIONS 40 + static const char qcrypto_block_luks_magic[QCRYPTO_BLOCK_LUKS_MAGIC_LEN] = { 'L', 'U', 'K', 'S', 0xBA, 0xBE }; @@ -219,6 +223,9 @@ struct QCryptoBlockLUKS { /* Hash algorithm used in pbkdf2 function */ QCryptoHashAlgorithm hash_alg; + + /* Name of the secret that was used to open the image */ + char *secret; }; @@ -720,7 +727,7 @@ qcrypto_block_luks_store_key(QCryptoBlock *block, Error **errp) { QCryptoBlockLUKS *luks = block->opaque; - QCryptoBlockLUKSKeySlot *slot = &luks->header.key_slots[slot_idx]; + QCryptoBlockLUKSKeySlot *slot; g_autofree uint8_t *splitkey = NULL; size_t splitkeylen; g_autofree uint8_t *slotkey = NULL; @@ -730,6 +737,8 @@ qcrypto_block_luks_store_key(QCryptoBlock *block, uint64_t iters; int ret = -1; + assert(slot_idx < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS); + slot = &luks->header.key_slots[slot_idx]; if (qcrypto_random_bytes(slot->salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, errp) < 0) { @@ -890,7 +899,7 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, Error **errp) { QCryptoBlockLUKS *luks = block->opaque; - const QCryptoBlockLUKSKeySlot *slot = &luks->header.key_slots[slot_idx]; + const QCryptoBlockLUKSKeySlot *slot; g_autofree uint8_t *splitkey = NULL; size_t splitkeylen; g_autofree uint8_t *possiblekey = NULL; @@ -900,6 +909,8 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, g_autoptr(QCryptoIVGen) ivgen = NULL; size_t niv; + assert(slot_idx < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS); + slot = &luks->header.key_slots[slot_idx]; if (slot->active != QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED) { return 0; } @@ -1069,6 +1080,126 @@ qcrypto_block_luks_find_key(QCryptoBlock *block, return -1; } +/* + * Returns true if a slot i is marked as active + * (contains encrypted copy of the master key) + */ +static bool +qcrypto_block_luks_slot_active(const QCryptoBlockLUKS *luks, + unsigned int slot_idx) +{ + uint32_t val; + + assert(slot_idx < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS); + val = luks->header.key_slots[slot_idx].active; + return val == QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED; +} + +/* + * Returns the number of slots that are marked as active + * (slots that contain encrypted copy of the master key) + */ +static unsigned int +qcrypto_block_luks_count_active_slots(const QCryptoBlockLUKS *luks) +{ + size_t i = 0; + unsigned int ret = 0; + + for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { + if (qcrypto_block_luks_slot_active(luks, i)) { + ret++; + } + } + return ret; +} + +/* + * Finds first key slot which is not active + * Returns the key slot index, or -1 if it doesn't exist + */ +static int +qcrypto_block_luks_find_free_keyslot(const QCryptoBlockLUKS *luks) +{ + size_t i; + + for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { + if (!qcrypto_block_luks_slot_active(luks, i)) { + return i; + } + } + return -1; +} + +/* + * Erases an keyslot given its index + * Returns: + * 0 if the keyslot was erased successfully + * -1 if a error occurred while erasing the keyslot + * + */ +static int +qcrypto_block_luks_erase_key(QCryptoBlock *block, + unsigned int slot_idx, + QCryptoBlockWriteFunc writefunc, + void *opaque, + Error **errp) +{ + QCryptoBlockLUKS *luks = block->opaque; + QCryptoBlockLUKSKeySlot *slot; + g_autofree uint8_t *garbagesplitkey = NULL; + size_t splitkeylen; + size_t i; + Error *local_err = NULL; + int ret; + + assert(slot_idx < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS); + slot = &luks->header.key_slots[slot_idx]; + + splitkeylen = luks->header.master_key_len * slot->stripes; + assert(splitkeylen > 0); + + garbagesplitkey = g_new0(uint8_t, splitkeylen); + + /* Reset the key slot header */ + memset(slot->salt, 0, QCRYPTO_BLOCK_LUKS_SALT_LEN); + slot->iterations = 0; + slot->active = QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED; + + ret = qcrypto_block_luks_store_header(block, writefunc, + opaque, &local_err); + + if (ret < 0) { + error_propagate(errp, local_err); + } + /* + * Now try to erase the key material, even if the header + * update failed + */ + for (i = 0; i < QCRYPTO_BLOCK_LUKS_ERASE_ITERATIONS; i++) { + if (qcrypto_random_bytes(garbagesplitkey, + splitkeylen, &local_err) < 0) { + /* + * If we failed to get the random data, still write + * at least zeros to the key slot at least once + */ + error_propagate(errp, local_err); + + if (i > 0) { + return -1; + } + } + if (writefunc(block, + slot->key_offset_sector * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, + garbagesplitkey, + splitkeylen, + opaque, + &local_err) != splitkeylen) { + error_propagate(errp, local_err); + return -1; + } + } + return ret; +} static int qcrypto_block_luks_open(QCryptoBlock *block, @@ -1099,6 +1230,7 @@ qcrypto_block_luks_open(QCryptoBlock *block, luks = g_new0(QCryptoBlockLUKS, 1); block->opaque = luks; + luks->secret = g_strdup(options->u.luks.key_secret); if (qcrypto_block_luks_load_header(block, readfunc, opaque, errp) < 0) { goto fail; @@ -1164,6 +1296,7 @@ qcrypto_block_luks_open(QCryptoBlock *block, fail: qcrypto_block_free_cipher(block); qcrypto_ivgen_free(block->ivgen); + g_free(luks->secret); g_free(luks); return -1; } @@ -1204,7 +1337,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts)); if (!luks_opts.has_iter_time) { - luks_opts.iter_time = 2000; + luks_opts.iter_time = QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME_MS; } if (!luks_opts.has_cipher_alg) { luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256; @@ -1244,6 +1377,8 @@ qcrypto_block_luks_create(QCryptoBlock *block, optprefix ? optprefix : ""); goto error; } + luks->secret = g_strdup(options->u.luks.key_secret); + password = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, errp); if (!password) { goto error; @@ -1471,10 +1606,278 @@ qcrypto_block_luks_create(QCryptoBlock *block, qcrypto_block_free_cipher(block); qcrypto_ivgen_free(block->ivgen); + g_free(luks->secret); g_free(luks); return -1; } +static int +qcrypto_block_luks_amend_add_keyslot(QCryptoBlock *block, + QCryptoBlockReadFunc readfunc, + QCryptoBlockWriteFunc writefunc, + void *opaque, + QCryptoBlockAmendOptionsLUKS *opts_luks, + bool force, + Error **errp) +{ + QCryptoBlockLUKS *luks = block->opaque; + uint64_t iter_time = opts_luks->has_iter_time ? + opts_luks->iter_time : + QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME_MS; + int keyslot; + g_autofree char *old_password = NULL; + g_autofree char *new_password = NULL; + g_autofree uint8_t *master_key = NULL; + + char *secret = opts_luks->has_secret ? opts_luks->secret : luks->secret; + + if (!opts_luks->has_new_secret) { + error_setg(errp, "'new-secret' is required to activate a keyslot"); + return -1; + } + if (opts_luks->has_old_secret) { + error_setg(errp, + "'old-secret' must not be given when activating keyslots"); + return -1; + } + + if (opts_luks->has_keyslot) { + keyslot = opts_luks->keyslot; + if (keyslot < 0 || keyslot >= QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS) { + error_setg(errp, + "Invalid keyslot %u specified, must be between 0 and %u", + keyslot, QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS - 1); + return -1; + } + } else { + keyslot = qcrypto_block_luks_find_free_keyslot(luks); + if (keyslot == -1) { + error_setg(errp, + "Can't add a keyslot - all keyslots are in use"); + return -1; + } + } + + if (!force && qcrypto_block_luks_slot_active(luks, keyslot)) { + error_setg(errp, + "Refusing to overwrite active keyslot %i - " + "please erase it first", + keyslot); + return -1; + } + + /* Locate the password that will be used to retrieve the master key */ + old_password = qcrypto_secret_lookup_as_utf8(secret, errp); + if (!old_password) { + return -1; + } + + /* Retrieve the master key */ + master_key = g_new0(uint8_t, luks->header.master_key_len); + + if (qcrypto_block_luks_find_key(block, old_password, master_key, + readfunc, opaque, errp) < 0) { + error_append_hint(errp, "Failed to retrieve the master key"); + return -1; + } + + /* Locate the new password*/ + new_password = qcrypto_secret_lookup_as_utf8(opts_luks->new_secret, errp); + if (!new_password) { + return -1; + } + + /* Now set the new keyslots */ + if (qcrypto_block_luks_store_key(block, keyslot, new_password, master_key, + iter_time, writefunc, opaque, errp)) { + error_append_hint(errp, "Failed to write to keyslot %i", keyslot); + return -1; + } + return 0; +} + +static int +qcrypto_block_luks_amend_erase_keyslots(QCryptoBlock *block, + QCryptoBlockReadFunc readfunc, + QCryptoBlockWriteFunc writefunc, + void *opaque, + QCryptoBlockAmendOptionsLUKS *opts_luks, + bool force, + Error **errp) +{ + QCryptoBlockLUKS *luks = block->opaque; + g_autofree uint8_t *tmpkey = NULL; + g_autofree char *old_password = NULL; + + if (opts_luks->has_new_secret) { + error_setg(errp, + "'new-secret' must not be given when erasing keyslots"); + return -1; + } + if (opts_luks->has_iter_time) { + error_setg(errp, + "'iter-time' must not be given when erasing keyslots"); + return -1; + } + if (opts_luks->has_secret) { + error_setg(errp, + "'secret' must not be given when erasing keyslots"); + return -1; + } + + /* Load the old password if given */ + if (opts_luks->has_old_secret) { + old_password = qcrypto_secret_lookup_as_utf8(opts_luks->old_secret, + errp); + if (!old_password) { + return -1; + } + + /* + * Allocate a temporary key buffer that we will need when + * checking if slot matches the given old password + */ + tmpkey = g_new0(uint8_t, luks->header.master_key_len); + } + + /* Erase an explicitly given keyslot */ + if (opts_luks->has_keyslot) { + int keyslot = opts_luks->keyslot; + + if (keyslot < 0 || keyslot >= QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS) { + error_setg(errp, + "Invalid keyslot %i specified, must be between 0 and %i", + keyslot, QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS - 1); + return -1; + } + + if (opts_luks->has_old_secret) { + int rv = qcrypto_block_luks_load_key(block, + keyslot, + old_password, + tmpkey, + readfunc, + opaque, + errp); + if (rv == -1) { + return -1; + } else if (rv == 0) { + error_setg(errp, + "Given keyslot %i doesn't contain the given " + "old password for erase operation", + keyslot); + return -1; + } + } + + if (!force && !qcrypto_block_luks_slot_active(luks, keyslot)) { + error_setg(errp, + "Given keyslot %i is already erased (inactive) ", + keyslot); + return -1; + } + + if (!force && qcrypto_block_luks_count_active_slots(luks) == 1) { + error_setg(errp, + "Attempt to erase the only active keyslot %i " + "which will erase all the data in the image " + "irreversibly - refusing operation", + keyslot); + return -1; + } + + if (qcrypto_block_luks_erase_key(block, keyslot, + writefunc, opaque, errp)) { + error_append_hint(errp, "Failed to erase keyslot %i", keyslot); + return -1; + } + + /* Erase all keyslots that match the given old password */ + } else if (opts_luks->has_old_secret) { + + unsigned long slots_to_erase_bitmap = 0; + size_t i; + int slot_count; + + assert(QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS <= + sizeof(slots_to_erase_bitmap) * 8); + + for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { + int rv = qcrypto_block_luks_load_key(block, + i, + old_password, + tmpkey, + readfunc, + opaque, + errp); + if (rv == -1) { + return -1; + } else if (rv == 1) { + bitmap_set(&slots_to_erase_bitmap, i, 1); + } + } + + slot_count = bitmap_count_one(&slots_to_erase_bitmap, + QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS); + if (slot_count == 0) { + error_setg(errp, + "No keyslots match given (old) password for erase operation"); + return -1; + } + + if (!force && + slot_count == qcrypto_block_luks_count_active_slots(luks)) { + error_setg(errp, + "All the active keyslots match the (old) password that " + "was given and erasing them will erase all the data in " + "the image irreversibly - refusing operation"); + return -1; + } + + /* Now apply the update */ + for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { + if (!test_bit(i, &slots_to_erase_bitmap)) { + continue; + } + if (qcrypto_block_luks_erase_key(block, i, writefunc, + opaque, errp)) { + error_append_hint(errp, "Failed to erase keyslot %zu", i); + return -1; + } + } + } else { + error_setg(errp, + "To erase keyslot(s), either explicit keyslot index " + "or the password currently contained in them must be given"); + return -1; + } + return 0; +} + +static int +qcrypto_block_luks_amend_options(QCryptoBlock *block, + QCryptoBlockReadFunc readfunc, + QCryptoBlockWriteFunc writefunc, + void *opaque, + QCryptoBlockAmendOptions *options, + bool force, + Error **errp) +{ + QCryptoBlockAmendOptionsLUKS *opts_luks = &options->u.luks; + + switch (opts_luks->state) { + case Q_CRYPTO_BLOCKLUKS_KEYSLOT_STATE_ACTIVE: + return qcrypto_block_luks_amend_add_keyslot(block, readfunc, + writefunc, opaque, + opts_luks, force, errp); + case Q_CRYPTO_BLOCKLUKS_KEYSLOT_STATE_INACTIVE: + return qcrypto_block_luks_amend_erase_keyslots(block, readfunc, + writefunc, opaque, + opts_luks, force, errp); + default: + g_assert_not_reached(); + } +} static int qcrypto_block_luks_get_info(QCryptoBlock *block, QCryptoBlockInfo *info, @@ -1523,7 +1926,11 @@ static int qcrypto_block_luks_get_info(QCryptoBlock *block, static void qcrypto_block_luks_cleanup(QCryptoBlock *block) { - g_free(block->opaque); + QCryptoBlockLUKS *luks = block->opaque; + if (luks) { + g_free(luks->secret); + g_free(luks); + } } @@ -1560,6 +1967,7 @@ qcrypto_block_luks_encrypt(QCryptoBlock *block, const QCryptoBlockDriver qcrypto_block_driver_luks = { .open = qcrypto_block_luks_open, .create = qcrypto_block_luks_create, + .amend = qcrypto_block_luks_amend_options, .get_info = qcrypto_block_luks_get_info, .cleanup = qcrypto_block_luks_cleanup, .decrypt = qcrypto_block_luks_decrypt, diff --git a/qapi/crypto.json b/qapi/crypto.json index aeb6c7ef7b..5a68e0db25 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -297,7 +297,6 @@ 'uuid': 'str', 'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }} - ## # @QCryptoBlockInfo: # @@ -310,8 +309,64 @@ 'discriminator': 'format', 'data': { 'luks': 'QCryptoBlockInfoLUKS' } } +## +# @QCryptoBlockLUKSKeyslotState: +# +# Defines state of keyslots that are affected by the update +# +# @active: The slots contain the given password and marked as active +# @inactive: The slots are erased (contain garbage) and marked as inactive +# +# Since: 5.1 +## +{ 'enum': 'QCryptoBlockLUKSKeyslotState', + 'data': [ 'active', 'inactive' ] } +## +# @QCryptoBlockAmendOptionsLUKS: +# +# This struct defines the update parameters that activate/de-activate set +# of keyslots +# +# @state: the desired state of the keyslots +# +# @new-secret: The ID of a QCryptoSecret object providing the password to be +# written into added active keyslots +# +# @old-secret: Optional (for deactivation only) +# If given will deactive all keyslots that +# match password located in QCryptoSecret with this ID +# +# @iter-time: Optional (for activation only) +# Number of milliseconds to spend in +# PBKDF passphrase processing for the newly activated keyslot. +# Currently defaults to 2000. +# +# @keyslot: Optional. ID of the keyslot to activate/deactivate. +# For keyslot activation, keyslot should not be active already +# (this is unsafe to update an active keyslot), +# but possible if 'force' parameter is given. +# If keyslot is not given, first free keyslot will be written. +# +# For keyslot deactivation, this parameter specifies the exact +# keyslot to deactivate +# +# @secret: Optional. The ID of a QCryptoSecret object providing the +# password to use to retrive current master key. +# Defaults to the same secret that was used to open the image +# +# +# Since 5.1 +## +{ 'struct': 'QCryptoBlockAmendOptionsLUKS', + 'data': { 'state': 'QCryptoBlockLUKSKeyslotState', + '*new-secret': 'str', + '*old-secret': 'str', + '*keyslot': 'int', + '*iter-time': 'int', + '*secret': 'str' } } + ## # @QCryptoBlockAmendOptions: # @@ -324,4 +379,4 @@ 'base': 'QCryptoBlockOptionsBase', 'discriminator': 'format', 'data': { - } } + 'luks': 'QCryptoBlockAmendOptionsLUKS' } } From a3579bfa0a209761c8526ccc96a5d6068f14768f Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:38 +0200 Subject: [PATCH 1960/2595] block/amend: add 'force' option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'force' option will be used for some unsafe amend operations. This includes things like erasing last keyslot in luks based formats (which destroys the data, unless the master key is backed up by external means), but that _might_ be desired result. Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé Reviewed-by: Max Reitz Message-Id: <20200608094030.670121-4-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- block.c | 4 +++- block/qcow2.c | 1 + docs/tools/qemu-img.rst | 5 ++++- include/block/block.h | 1 + include/block/block_int.h | 1 + qemu-img-cmds.hx | 4 ++-- qemu-img.c | 8 +++++++- 7 files changed, 19 insertions(+), 5 deletions(-) diff --git a/block.c b/block.c index 6dbcb7e083..144f52e413 100644 --- a/block.c +++ b/block.c @@ -6482,6 +6482,7 @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs, int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts, BlockDriverAmendStatusCB *status_cb, void *cb_opaque, + bool force, Error **errp) { if (!bs->drv) { @@ -6493,7 +6494,8 @@ int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts, bs->drv->format_name); return -ENOTSUP; } - return bs->drv->bdrv_amend_options(bs, opts, status_cb, cb_opaque, errp); + return bs->drv->bdrv_amend_options(bs, opts, status_cb, + cb_opaque, force, errp); } /* diff --git a/block/qcow2.c b/block/qcow2.c index e20590c3b7..f6c9207312 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5351,6 +5351,7 @@ static void qcow2_amend_helper_cb(BlockDriverState *bs, static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, BlockDriverAmendStatusCB *status_cb, void *cb_opaque, + bool force, Error **errp) { BDRVQcow2State *s = bs->opaque; diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index 7f0737488a..e33f5575e3 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -253,11 +253,14 @@ Command description: .. program:: qemu-img-commands -.. option:: amend [--object OBJECTDEF] [--image-opts] [-p] [-q] [-f FMT] [-t CACHE] -o OPTIONS FILENAME +.. option:: amend [--object OBJECTDEF] [--image-opts] [-p] [-q] [-f FMT] [-t CACHE] [--force] -o OPTIONS FILENAME Amends the image format specific *OPTIONS* for the image file *FILENAME*. Not all file formats support this operation. + --force allows some unsafe operations. Currently for -f luks, it allows to + erase the last encryption key, and to overwrite an active encryption key. + .. option:: bench [-c COUNT] [-d DEPTH] [-f FMT] [--flush-interval=FLUSH_INTERVAL] [-i AIO] [-n] [--no-drain] [-o OFFSET] [--pattern=PATTERN] [-q] [-s BUFFER_SIZE] [-S STEP_SIZE] [-t CACHE] [-w] [-U] FILENAME Run a simple sequential I/O benchmark on the specified image. If ``-w`` is diff --git a/include/block/block.h b/include/block/block.h index e8fc814996..a2414a58c5 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -450,6 +450,7 @@ typedef void BlockDriverAmendStatusCB(BlockDriverState *bs, int64_t offset, int64_t total_work_size, void *opaque); int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts, BlockDriverAmendStatusCB *status_cb, void *cb_opaque, + bool force, Error **errp); /* check if a named node can be replaced when doing drive-mirror */ diff --git a/include/block/block_int.h b/include/block/block_int.h index 791de6a59c..066b9eaa40 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -440,6 +440,7 @@ struct BlockDriver { int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts, BlockDriverAmendStatusCB *status_cb, void *cb_opaque, + bool force, Error **errp); void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event); diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 10b910b67c..b89c019b76 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -10,9 +10,9 @@ HXCOMM When amending the rST sections, please remember to copy the usage HXCOMM over to the per-command sections in docs/tools/qemu-img.rst. DEF("amend", img_amend, - "amend [--object objectdef] [--image-opts] [-p] [-q] [-f fmt] [-t cache] -o options filename") + "amend [--object objectdef] [--image-opts] [-p] [-q] [-f fmt] [-t cache] [--force] -o options filename") SRST -.. option:: amend [--object OBJECTDEF] [--image-opts] [-p] [-q] [-f FMT] [-t CACHE] -o OPTIONS FILENAME +.. option:: amend [--object OBJECTDEF] [--image-opts] [-p] [-q] [-f FMT] [-t CACHE] [--force] -o OPTIONS FILENAME ERST DEF("bench", img_bench, diff --git a/qemu-img.c b/qemu-img.c index bdb9f6aa46..8c26bfafc6 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -79,6 +79,7 @@ enum { OPTION_DISABLE = 273, OPTION_MERGE = 274, OPTION_BITMAPS = 275, + OPTION_FORCE = 276, }; typedef enum OutputFormat { @@ -4090,6 +4091,7 @@ static int img_amend(int argc, char **argv) BlockBackend *blk = NULL; BlockDriverState *bs = NULL; bool image_opts = false; + bool force = false; cache = BDRV_DEFAULT_CACHE; for (;;) { @@ -4097,6 +4099,7 @@ static int img_amend(int argc, char **argv) {"help", no_argument, 0, 'h'}, {"object", required_argument, 0, OPTION_OBJECT}, {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {"force", no_argument, 0, OPTION_FORCE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, ":ho:f:t:pq", @@ -4144,6 +4147,9 @@ static int img_amend(int argc, char **argv) case OPTION_IMAGE_OPTS: image_opts = true; break; + case OPTION_FORCE: + force = true; + break; } } @@ -4221,7 +4227,7 @@ static int img_amend(int argc, char **argv) /* In case the driver does not call amend_status_cb() */ qemu_progress_print(0.f, 0); - ret = bdrv_amend_options(bs, opts, &amend_status_cb, NULL, &err); + ret = bdrv_amend_options(bs, opts, &amend_status_cb, NULL, force, &err); qemu_progress_print(100.f, 0); if (ret < 0) { error_report_err(err); From df373fb0a3a26c2b1b92d27c91bea22a0f5b598d Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:39 +0200 Subject: [PATCH 1961/2595] block/amend: separate amend and create options for qemu-img MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some options are only useful for creation (or hard to be amended, like cluster size for qcow2), while some other options are only useful for amend, like upcoming keyslot management options for luks Since currently only qcow2 supports amend, move all its options to a common macro and then include it in each action option list. In future it might be useful to remove some options which are not supported anyway from amend list, which currently cause an error message if amended. Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé Reviewed-by: Max Reitz Message-Id: <20200608094030.670121-5-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- block/qcow2.c | 173 +++++++++++++++++++++----------------- include/block/block_int.h | 4 + qemu-img.c | 18 ++-- 3 files changed, 107 insertions(+), 88 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index f6c9207312..3898853ef8 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5660,89 +5660,103 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, s->signaled_corruption = true; } +#define QCOW_COMMON_OPTIONS \ + { \ + .name = BLOCK_OPT_SIZE, \ + .type = QEMU_OPT_SIZE, \ + .help = "Virtual disk size" \ + }, \ + { \ + .name = BLOCK_OPT_COMPAT_LEVEL, \ + .type = QEMU_OPT_STRING, \ + .help = "Compatibility level (v2 [0.10] or v3 [1.1])" \ + }, \ + { \ + .name = BLOCK_OPT_BACKING_FILE, \ + .type = QEMU_OPT_STRING, \ + .help = "File name of a base image" \ + }, \ + { \ + .name = BLOCK_OPT_BACKING_FMT, \ + .type = QEMU_OPT_STRING, \ + .help = "Image format of the base image" \ + }, \ + { \ + .name = BLOCK_OPT_DATA_FILE, \ + .type = QEMU_OPT_STRING, \ + .help = "File name of an external data file" \ + }, \ + { \ + .name = BLOCK_OPT_DATA_FILE_RAW, \ + .type = QEMU_OPT_BOOL, \ + .help = "The external data file must stay valid " \ + "as a raw image" \ + }, \ + { \ + .name = BLOCK_OPT_ENCRYPT, \ + .type = QEMU_OPT_BOOL, \ + .help = "Encrypt the image with format 'aes'. (Deprecated " \ + "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)", \ + }, \ + { \ + .name = BLOCK_OPT_ENCRYPT_FORMAT, \ + .type = QEMU_OPT_STRING, \ + .help = "Encrypt the image, format choices: 'aes', 'luks'", \ + }, \ + BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.", \ + "ID of secret providing qcow AES key or LUKS passphrase"), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG("encrypt."), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE("encrypt."), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG("encrypt."), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG("encrypt."), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG("encrypt."), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."), \ + { \ + .name = BLOCK_OPT_CLUSTER_SIZE, \ + .type = QEMU_OPT_SIZE, \ + .help = "qcow2 cluster size", \ + .def_value_str = stringify(DEFAULT_CLUSTER_SIZE) \ + }, \ + { \ + .name = BLOCK_OPT_PREALLOC, \ + .type = QEMU_OPT_STRING, \ + .help = "Preallocation mode (allowed values: off, " \ + "metadata, falloc, full)" \ + }, \ + { \ + .name = BLOCK_OPT_LAZY_REFCOUNTS, \ + .type = QEMU_OPT_BOOL, \ + .help = "Postpone refcount updates", \ + .def_value_str = "off" \ + }, \ + { \ + .name = BLOCK_OPT_REFCOUNT_BITS, \ + .type = QEMU_OPT_NUMBER, \ + .help = "Width of a reference count entry in bits", \ + .def_value_str = "16" \ + }, \ + { \ + .name = BLOCK_OPT_COMPRESSION_TYPE, \ + .type = QEMU_OPT_STRING, \ + .help = "Compression method used for image cluster " \ + "compression", \ + .def_value_str = "zlib" \ + } + static QemuOptsList qcow2_create_opts = { .name = "qcow2-create-opts", .head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head), .desc = { - { - .name = BLOCK_OPT_SIZE, - .type = QEMU_OPT_SIZE, - .help = "Virtual disk size" - }, - { - .name = BLOCK_OPT_COMPAT_LEVEL, - .type = QEMU_OPT_STRING, - .help = "Compatibility level (v2 [0.10] or v3 [1.1])" - }, - { - .name = BLOCK_OPT_BACKING_FILE, - .type = QEMU_OPT_STRING, - .help = "File name of a base image" - }, - { - .name = BLOCK_OPT_BACKING_FMT, - .type = QEMU_OPT_STRING, - .help = "Image format of the base image" - }, - { - .name = BLOCK_OPT_DATA_FILE, - .type = QEMU_OPT_STRING, - .help = "File name of an external data file" - }, - { - .name = BLOCK_OPT_DATA_FILE_RAW, - .type = QEMU_OPT_BOOL, - .help = "The external data file must stay valid as a raw image" - }, - { - .name = BLOCK_OPT_ENCRYPT, - .type = QEMU_OPT_BOOL, - .help = "Encrypt the image with format 'aes'. (Deprecated " - "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)", - }, - { - .name = BLOCK_OPT_ENCRYPT_FORMAT, - .type = QEMU_OPT_STRING, - .help = "Encrypt the image, format choices: 'aes', 'luks'", - }, - BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.", - "ID of secret providing qcow AES key or LUKS passphrase"), - BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG("encrypt."), - BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE("encrypt."), - BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG("encrypt."), - BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG("encrypt."), - BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG("encrypt."), - BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."), - { - .name = BLOCK_OPT_CLUSTER_SIZE, - .type = QEMU_OPT_SIZE, - .help = "qcow2 cluster size", - .def_value_str = stringify(DEFAULT_CLUSTER_SIZE) - }, - { - .name = BLOCK_OPT_PREALLOC, - .type = QEMU_OPT_STRING, - .help = "Preallocation mode (allowed values: off, metadata, " - "falloc, full)" - }, - { - .name = BLOCK_OPT_LAZY_REFCOUNTS, - .type = QEMU_OPT_BOOL, - .help = "Postpone refcount updates", - .def_value_str = "off" - }, - { - .name = BLOCK_OPT_REFCOUNT_BITS, - .type = QEMU_OPT_NUMBER, - .help = "Width of a reference count entry in bits", - .def_value_str = "16" - }, - { - .name = BLOCK_OPT_COMPRESSION_TYPE, - .type = QEMU_OPT_STRING, - .help = "Compression method used for image cluster compression", - .def_value_str = "zlib" - }, + QCOW_COMMON_OPTIONS, + { /* end of list */ } + } +}; + +static QemuOptsList qcow2_amend_opts = { + .name = "qcow2-amend-opts", + .head = QTAILQ_HEAD_INITIALIZER(qcow2_amend_opts.head), + .desc = { + QCOW_COMMON_OPTIONS, { /* end of list */ } } }; @@ -5803,6 +5817,7 @@ BlockDriver bdrv_qcow2 = { .bdrv_inactivate = qcow2_inactivate, .create_opts = &qcow2_create_opts, + .amend_opts = &qcow2_amend_opts, .strong_runtime_opts = qcow2_strong_runtime_opts, .mutable_opts = mutable_opts, .bdrv_co_check = qcow2_co_check, diff --git a/include/block/block_int.h b/include/block/block_int.h index 066b9eaa40..ed335519cc 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -420,6 +420,10 @@ struct BlockDriver { /* List of options for creating images, terminated by name == NULL */ QemuOptsList *create_opts; + + /* List of options for image amend */ + QemuOptsList *amend_opts; + /* * If this driver supports reopening images this contains a * NULL-terminated list of the runtime options that can be diff --git a/qemu-img.c b/qemu-img.c index 8c26bfafc6..1a0a85089b 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -4068,11 +4068,11 @@ static int print_amend_option_help(const char *format) return 1; } - /* Every driver supporting amendment must have create_opts */ - assert(drv->create_opts); + /* Every driver supporting amendment must have amend_opts */ + assert(drv->amend_opts); printf("Creation options for '%s':\n", format); - qemu_opts_print_help(drv->create_opts, false); + qemu_opts_print_help(drv->amend_opts, false); printf("\nNote that not all of these options may be amendable.\n"); return 0; } @@ -4082,7 +4082,7 @@ static int img_amend(int argc, char **argv) Error *err = NULL; int c, ret = 0; char *options = NULL; - QemuOptsList *create_opts = NULL; + QemuOptsList *amend_opts = NULL; QemuOpts *opts = NULL; const char *fmt = NULL, *filename, *cache; int flags; @@ -4213,11 +4213,11 @@ static int img_amend(int argc, char **argv) goto out; } - /* Every driver supporting amendment must have create_opts */ - assert(bs->drv->create_opts); + /* Every driver supporting amendment must have amend_opts */ + assert(bs->drv->amend_opts); - create_opts = qemu_opts_append(create_opts, bs->drv->create_opts); - opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); + amend_opts = qemu_opts_append(amend_opts, bs->drv->amend_opts); + opts = qemu_opts_create(amend_opts, NULL, 0, &error_abort); qemu_opts_do_parse(opts, options, NULL, &err); if (err) { error_report_err(err); @@ -4240,7 +4240,7 @@ out: out_no_progress: blk_unref(blk); qemu_opts_del(opts); - qemu_opts_free(create_opts); + qemu_opts_free(amend_opts); g_free(options); if (ret) { From 0b6786a9c1539c9bdacee71e09534e0bf972d865 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:40 +0200 Subject: [PATCH 1962/2595] block/amend: refactor qcow2 amend options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some qcow2 create options can't be used for amend. Remove them from the qcow2 create options and add generic logic to detect such options in qemu-img Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé [mreitz: Dropped some iotests reference output hunks that became unnecessary thanks to "iotests: Make _filter_img_create more active"] Signed-off-by: Max Reitz Message-Id: <20200625125548.870061-12-mreitz@redhat.com> --- block/qcow2.c | 138 +++++++++----------------------- qemu-img.c | 18 ++++- tests/qemu-iotests/049.out | 102 ++++++++++++------------ tests/qemu-iotests/061.out | 12 ++- tests/qemu-iotests/082.out | 158 ++++--------------------------------- tests/qemu-iotests/085.out | 38 ++++----- tests/qemu-iotests/144.out | 4 +- tests/qemu-iotests/182.out | 2 +- tests/qemu-iotests/185.out | 8 +- tests/qemu-iotests/255.out | 8 +- tests/qemu-iotests/274.out | 46 +++++------ tests/qemu-iotests/280.out | 2 +- 12 files changed, 183 insertions(+), 353 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 3898853ef8..389205dffd 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3042,17 +3042,6 @@ static int qcow2_change_backing_file(BlockDriverState *bs, return qcow2_update_header(bs); } -static int qcow2_crypt_method_from_format(const char *encryptfmt) -{ - if (g_str_equal(encryptfmt, "luks")) { - return QCOW_CRYPT_LUKS; - } else if (g_str_equal(encryptfmt, "aes")) { - return QCOW_CRYPT_AES; - } else { - return -EINVAL; - } -} - static int qcow2_set_up_encryption(BlockDriverState *bs, QCryptoBlockCreateOptions *cryptoopts, Error **errp) @@ -5361,9 +5350,6 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, bool lazy_refcounts = s->use_lazy_refcounts; bool data_file_raw = data_file_is_raw(bs); const char *compat = NULL; - uint64_t cluster_size = s->cluster_size; - bool encrypt; - int encformat; int refcount_bits = s->refcount_bits; int ret; QemuOptDesc *desc = opts->list->desc; @@ -5388,44 +5374,12 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, error_setg(errp, "Unknown compatibility level %s", compat); return -EINVAL; } - } else if (!strcmp(desc->name, BLOCK_OPT_PREALLOC)) { - error_setg(errp, "Cannot change preallocation mode"); - return -ENOTSUP; } else if (!strcmp(desc->name, BLOCK_OPT_SIZE)) { new_size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0); } else if (!strcmp(desc->name, BLOCK_OPT_BACKING_FILE)) { backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE); } else if (!strcmp(desc->name, BLOCK_OPT_BACKING_FMT)) { backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT); - } else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT)) { - encrypt = qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, - !!s->crypto); - - if (encrypt != !!s->crypto) { - error_setg(errp, - "Changing the encryption flag is not supported"); - return -ENOTSUP; - } - } else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT_FORMAT)) { - encformat = qcow2_crypt_method_from_format( - qemu_opt_get(opts, BLOCK_OPT_ENCRYPT_FORMAT)); - - if (encformat != s->crypt_method_header) { - error_setg(errp, - "Changing the encryption format is not supported"); - return -ENOTSUP; - } - } else if (g_str_has_prefix(desc->name, "encrypt.")) { - error_setg(errp, - "Changing the encryption parameters is not supported"); - return -ENOTSUP; - } else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) { - cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE, - cluster_size); - if (cluster_size != s->cluster_size) { - error_setg(errp, "Changing the cluster size is not supported"); - return -ENOTSUP; - } } else if (!strcmp(desc->name, BLOCK_OPT_LAZY_REFCOUNTS)) { lazy_refcounts = qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS, lazy_refcounts); @@ -5455,22 +5409,6 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, "images"); return -EINVAL; } - } else if (!strcmp(desc->name, BLOCK_OPT_COMPRESSION_TYPE)) { - const char *ct_name = - qemu_opt_get(opts, BLOCK_OPT_COMPRESSION_TYPE); - int compression_type = - qapi_enum_parse(&Qcow2CompressionType_lookup, ct_name, -1, - NULL); - if (compression_type == -1) { - error_setg(errp, "Unknown compression type: %s", ct_name); - return -ENOTSUP; - } - - if (compression_type != s->compression_type) { - error_setg(errp, "Changing the compression type " - "is not supported"); - return -ENOTSUP; - } } else { /* if this point is reached, this probably means a new option was * added without having it covered here */ @@ -5692,37 +5630,6 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, .help = "The external data file must stay valid " \ "as a raw image" \ }, \ - { \ - .name = BLOCK_OPT_ENCRYPT, \ - .type = QEMU_OPT_BOOL, \ - .help = "Encrypt the image with format 'aes'. (Deprecated " \ - "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)", \ - }, \ - { \ - .name = BLOCK_OPT_ENCRYPT_FORMAT, \ - .type = QEMU_OPT_STRING, \ - .help = "Encrypt the image, format choices: 'aes', 'luks'", \ - }, \ - BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.", \ - "ID of secret providing qcow AES key or LUKS passphrase"), \ - BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG("encrypt."), \ - BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE("encrypt."), \ - BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG("encrypt."), \ - BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG("encrypt."), \ - BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG("encrypt."), \ - BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."), \ - { \ - .name = BLOCK_OPT_CLUSTER_SIZE, \ - .type = QEMU_OPT_SIZE, \ - .help = "qcow2 cluster size", \ - .def_value_str = stringify(DEFAULT_CLUSTER_SIZE) \ - }, \ - { \ - .name = BLOCK_OPT_PREALLOC, \ - .type = QEMU_OPT_STRING, \ - .help = "Preallocation mode (allowed values: off, " \ - "metadata, falloc, full)" \ - }, \ { \ .name = BLOCK_OPT_LAZY_REFCOUNTS, \ .type = QEMU_OPT_BOOL, \ @@ -5734,19 +5641,50 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, .type = QEMU_OPT_NUMBER, \ .help = "Width of a reference count entry in bits", \ .def_value_str = "16" \ - }, \ - { \ - .name = BLOCK_OPT_COMPRESSION_TYPE, \ - .type = QEMU_OPT_STRING, \ - .help = "Compression method used for image cluster " \ - "compression", \ - .def_value_str = "zlib" \ } static QemuOptsList qcow2_create_opts = { .name = "qcow2-create-opts", .head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head), .desc = { + { \ + .name = BLOCK_OPT_ENCRYPT, \ + .type = QEMU_OPT_BOOL, \ + .help = "Encrypt the image with format 'aes'. (Deprecated " \ + "in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)", \ + }, \ + { \ + .name = BLOCK_OPT_ENCRYPT_FORMAT, \ + .type = QEMU_OPT_STRING, \ + .help = "Encrypt the image, format choices: 'aes', 'luks'", \ + }, \ + BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.", \ + "ID of secret providing qcow AES key or LUKS passphrase"), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG("encrypt."), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE("encrypt."), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG("encrypt."), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG("encrypt."), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG("encrypt."), \ + BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."), \ + { \ + .name = BLOCK_OPT_CLUSTER_SIZE, \ + .type = QEMU_OPT_SIZE, \ + .help = "qcow2 cluster size", \ + .def_value_str = stringify(DEFAULT_CLUSTER_SIZE) \ + }, \ + { \ + .name = BLOCK_OPT_PREALLOC, \ + .type = QEMU_OPT_STRING, \ + .help = "Preallocation mode (allowed values: off, " \ + "metadata, falloc, full)" \ + }, \ + { \ + .name = BLOCK_OPT_COMPRESSION_TYPE, \ + .type = QEMU_OPT_STRING, \ + .help = "Compression method used for image cluster " \ + "compression", \ + .def_value_str = "zlib" \ + }, QCOW_COMMON_OPTIONS, { /* end of list */ } } diff --git a/qemu-img.c b/qemu-img.c index 1a0a85089b..7f4938a5ef 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -4071,9 +4071,8 @@ static int print_amend_option_help(const char *format) /* Every driver supporting amendment must have amend_opts */ assert(drv->amend_opts); - printf("Creation options for '%s':\n", format); + printf("Amend options for '%s':\n", format); qemu_opts_print_help(drv->amend_opts, false); - printf("\nNote that not all of these options may be amendable.\n"); return 0; } @@ -4219,7 +4218,22 @@ static int img_amend(int argc, char **argv) amend_opts = qemu_opts_append(amend_opts, bs->drv->amend_opts); opts = qemu_opts_create(amend_opts, NULL, 0, &error_abort); qemu_opts_do_parse(opts, options, NULL, &err); + if (err) { + /* Try to parse options using the create options */ + Error *err1 = NULL; + amend_opts = qemu_opts_append(amend_opts, bs->drv->create_opts); + qemu_opts_del(opts); + opts = qemu_opts_create(amend_opts, NULL, 0, &error_abort); + qemu_opts_do_parse(opts, options, NULL, &err1); + + if (!err1) { + error_append_hint(&err, + "This option is only supported for image creation\n"); + } else { + error_free(err1); + } + error_report_err(err); ret = -1; goto out; diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out index c54ae21b86..e77966446b 100644 --- a/tests/qemu-iotests/049.out +++ b/tests/qemu-iotests/049.out @@ -4,90 +4,90 @@ QA output created by 049 == 1. Traditional size parameter == qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16 == 2. Specifying size via -o == qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2 -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16 == 3. Invalid sizes == @@ -129,84 +129,84 @@ qemu-img: TEST_DIR/t.qcow2: The image size must be specified only once == Check correct interpretation of suffixes for cluster size == qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1048576 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1048576 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=1024 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=512 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=524288 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=524288 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 == Check compat level option == qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M qemu-img: TEST_DIR/t.qcow2: Invalid parameter '0.42' -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.42 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M qemu-img: TEST_DIR/t.qcow2: Invalid parameter 'foobar' -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=foobar lazy_refcounts=off refcount_bits=16 == Check preallocation option == qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=off lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 preallocation=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 preallocation=metadata compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M qemu-img: TEST_DIR/t.qcow2: Invalid parameter '1234' -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 preallocation=1234 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 == Check encryption option == qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=off cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on encrypt.key-secret=sec0 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=on encrypt.key-secret=sec0 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 == Check lazy_refcounts option (only with v3) == qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=on refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=on refcount_bits=16 qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater) -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=on refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=on refcount_bits=16 *** done diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index 2f03cf045c..b0f8befe30 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -381,16 +381,20 @@ qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above ( qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) qemu-img: Unknown compatibility level 0.42 qemu-img: Invalid parameter 'foo' -qemu-img: Changing the cluster size is not supported -qemu-img: Changing the encryption flag is not supported -qemu-img: Cannot change preallocation mode +qemu-img: Invalid parameter 'cluster_size' +This option is only supported for image creation +qemu-img: Invalid parameter 'encryption' +This option is only supported for image creation +qemu-img: Invalid parameter 'preallocation' +This option is only supported for image creation === Testing correct handling of unset value === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Should work: Should not work: -qemu-img: Changing the cluster size is not supported +qemu-img: Invalid parameter 'cluster_size' +This option is only supported for image creation === Testing zero expansion on inactive clusters === diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index 529a1214e1..b1cf5dfe43 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -3,14 +3,14 @@ QA output created by 082 === create: Options specified more than once === Testing: create -f foo -f qcow2 TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16 image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 128 MiB (134217728 bytes) cluster_size: 65536 Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=4096 lazy_refcounts=on refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=4096 compression_type=zlib size=134217728 lazy_refcounts=on refcount_bits=16 image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 128 MiB (134217728 bytes) @@ -23,7 +23,7 @@ Format specific information: corrupt: false Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=on refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=8192 compression_type=zlib size=134217728 lazy_refcounts=on refcount_bits=16 image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 128 MiB (134217728 bytes) @@ -36,7 +36,7 @@ Format specific information: corrupt: false Testing: create -f qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=8192 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=8192 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16 image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 128 MiB (134217728 bytes) @@ -237,10 +237,10 @@ Supported options: size= - Virtual disk size Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,help lazy_refcounts=off refcount_bits=16 Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,? lazy_refcounts=off refcount_bits=16 Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 128M qemu-img: Invalid option list: backing_file=TEST_DIR/t.qcow2, @@ -290,7 +290,7 @@ qemu-img: Format driver 'bochs' does not support image creation === convert: Options specified more than once === Testing: create -f qcow2 TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16 Testing: convert -f foo -f qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base image: TEST_DIR/t.IMGFMT.base @@ -639,205 +639,93 @@ cluster_size: 65536 === amend: help for -o === Testing: amend -f qcow2 -o help TEST_DIR/t.qcow2 -Creation options for 'qcow2': +Amend options for 'qcow2': backing_file= - File name of a base image backing_fmt= - Image format of the base image - cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) - compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image - encrypt.cipher-alg= - Name of encryption cipher algorithm - encrypt.cipher-mode= - Name of encryption cipher mode - encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' - encrypt.hash-alg= - Name of encryption hash algorithm - encrypt.iter-time= - Time to spend in PBKDF in milliseconds - encrypt.ivgen-alg= - Name of IV generator algorithm - encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm - encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase - encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) lazy_refcounts= - Postpone refcount updates - preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size -Note that not all of these options may be amendable. - Testing: amend -f qcow2 -o ? TEST_DIR/t.qcow2 -Creation options for 'qcow2': +Amend options for 'qcow2': backing_file= - File name of a base image backing_fmt= - Image format of the base image - cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) - compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image - encrypt.cipher-alg= - Name of encryption cipher algorithm - encrypt.cipher-mode= - Name of encryption cipher mode - encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' - encrypt.hash-alg= - Name of encryption hash algorithm - encrypt.iter-time= - Time to spend in PBKDF in milliseconds - encrypt.ivgen-alg= - Name of IV generator algorithm - encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm - encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase - encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) lazy_refcounts= - Postpone refcount updates - preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size -Note that not all of these options may be amendable. - Testing: amend -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 -Creation options for 'qcow2': +Amend options for 'qcow2': backing_file= - File name of a base image backing_fmt= - Image format of the base image - cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) - compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image - encrypt.cipher-alg= - Name of encryption cipher algorithm - encrypt.cipher-mode= - Name of encryption cipher mode - encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' - encrypt.hash-alg= - Name of encryption hash algorithm - encrypt.iter-time= - Time to spend in PBKDF in milliseconds - encrypt.ivgen-alg= - Name of IV generator algorithm - encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm - encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase - encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) lazy_refcounts= - Postpone refcount updates - preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size -Note that not all of these options may be amendable. - Testing: amend -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 -Creation options for 'qcow2': +Amend options for 'qcow2': backing_file= - File name of a base image backing_fmt= - Image format of the base image - cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) - compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image - encrypt.cipher-alg= - Name of encryption cipher algorithm - encrypt.cipher-mode= - Name of encryption cipher mode - encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' - encrypt.hash-alg= - Name of encryption hash algorithm - encrypt.iter-time= - Time to spend in PBKDF in milliseconds - encrypt.ivgen-alg= - Name of IV generator algorithm - encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm - encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase - encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) lazy_refcounts= - Postpone refcount updates - preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size -Note that not all of these options may be amendable. - Testing: amend -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 -Creation options for 'qcow2': +Amend options for 'qcow2': backing_file= - File name of a base image backing_fmt= - Image format of the base image - cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) - compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image - encrypt.cipher-alg= - Name of encryption cipher algorithm - encrypt.cipher-mode= - Name of encryption cipher mode - encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' - encrypt.hash-alg= - Name of encryption hash algorithm - encrypt.iter-time= - Time to spend in PBKDF in milliseconds - encrypt.ivgen-alg= - Name of IV generator algorithm - encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm - encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase - encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) lazy_refcounts= - Postpone refcount updates - preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size -Note that not all of these options may be amendable. - Testing: amend -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 -Creation options for 'qcow2': +Amend options for 'qcow2': backing_file= - File name of a base image backing_fmt= - Image format of the base image - cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) - compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image - encrypt.cipher-alg= - Name of encryption cipher algorithm - encrypt.cipher-mode= - Name of encryption cipher mode - encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' - encrypt.hash-alg= - Name of encryption hash algorithm - encrypt.iter-time= - Time to spend in PBKDF in milliseconds - encrypt.ivgen-alg= - Name of IV generator algorithm - encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm - encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase - encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) lazy_refcounts= - Postpone refcount updates - preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size -Note that not all of these options may be amendable. - Testing: amend -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 -Creation options for 'qcow2': +Amend options for 'qcow2': backing_file= - File name of a base image backing_fmt= - Image format of the base image - cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) - compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image - encrypt.cipher-alg= - Name of encryption cipher algorithm - encrypt.cipher-mode= - Name of encryption cipher mode - encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' - encrypt.hash-alg= - Name of encryption hash algorithm - encrypt.iter-time= - Time to spend in PBKDF in milliseconds - encrypt.ivgen-alg= - Name of IV generator algorithm - encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm - encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase - encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) lazy_refcounts= - Postpone refcount updates - preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size -Note that not all of these options may be amendable. - Testing: amend -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 -Creation options for 'qcow2': +Amend options for 'qcow2': backing_file= - File name of a base image backing_fmt= - Image format of the base image - cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) - compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image - encrypt.cipher-alg= - Name of encryption cipher algorithm - encrypt.cipher-mode= - Name of encryption cipher mode - encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' - encrypt.hash-alg= - Name of encryption hash algorithm - encrypt.iter-time= - Time to spend in PBKDF in milliseconds - encrypt.ivgen-alg= - Name of IV generator algorithm - encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm - encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase - encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) lazy_refcounts= - Postpone refcount updates - preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size -Note that not all of these options may be amendable. - Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 Testing: rebase -u -b -f qcow2 TEST_DIR/t.qcow2 @@ -856,30 +744,16 @@ Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2 -o ,, -o help TEST_DIR/ qemu-img: Invalid option list: ,, Testing: amend -f qcow2 -o help -Creation options for 'qcow2': +Amend options for 'qcow2': backing_file= - File name of a base image backing_fmt= - Image format of the base image - cluster_size= - qcow2 cluster size compat= - Compatibility level (v2 [0.10] or v3 [1.1]) - compression_type= - Compression method used for image cluster compression data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image - encrypt.cipher-alg= - Name of encryption cipher algorithm - encrypt.cipher-mode= - Name of encryption cipher mode - encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' - encrypt.hash-alg= - Name of encryption hash algorithm - encrypt.iter-time= - Time to spend in PBKDF in milliseconds - encrypt.ivgen-alg= - Name of IV generator algorithm - encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm - encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase - encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) lazy_refcounts= - Postpone refcount updates - preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size -Note that not all of these options may be amendable. - Testing: amend -o help qemu-img: Expecting one image file name diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out index a822ff4ef6..d68c06efdf 100644 --- a/tests/qemu-iotests/085.out +++ b/tests/qemu-iotests/085.out @@ -13,7 +13,7 @@ Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=134217728 === Create a single snapshot on virtio0 === { 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/1-snapshot-v0.IMGFMT', 'format': 'IMGFMT' } } -Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} === Invalid command - missing device and nodename === @@ -30,40 +30,40 @@ Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file === Create several transactional group snapshots === { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/2-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/2-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/3-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/3-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/4-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/4-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/5-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/5-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/6-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/6-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/7-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/7-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/8-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/8-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/9-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/9-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} { 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/10-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/10-snapshot-v1.IMGFMT' } } ] } } -Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib -Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} === Create a couple of snapshots using blockdev-snapshot === diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out index 885a8874a5..a2172a1308 100644 --- a/tests/qemu-iotests/144.out +++ b/tests/qemu-iotests/144.out @@ -9,7 +9,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=536870912 { 'execute': 'qmp_capabilities' } {"return": {}} { 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/tmp.IMGFMT', 'format': 'IMGFMT' } } -Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} === Performing block-commit on active layer === @@ -31,6 +31,6 @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/ === Performing Live Snapshot 2 === { 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/tmp2.IMGFMT', 'format': 'IMGFMT' } } -Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} *** done diff --git a/tests/qemu-iotests/182.out b/tests/qemu-iotests/182.out index ae43654d32..29e9db3497 100644 --- a/tests/qemu-iotests/182.out +++ b/tests/qemu-iotests/182.out @@ -13,7 +13,7 @@ Is another process using the image [TEST_DIR/t.qcow2]? {'execute': 'blockdev-add', 'arguments': { 'node-name': 'node0', 'driver': 'file', 'filename': 'TEST_DIR/t.IMGFMT', 'locking': 'on' } } {"return": {}} {'execute': 'blockdev-snapshot-sync', 'arguments': { 'node-name': 'node0', 'snapshot-file': 'TEST_DIR/t.IMGFMT.overlay', 'snapshot-node-name': 'node1' } } -Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 size=197120 backing_file=TEST_DIR/t.qcow2 backing_fmt=file cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 cluster_size=65536 compression_type=zlib size=197120 backing_file=TEST_DIR/t.qcow2 backing_fmt=file lazy_refcounts=off refcount_bits=16 {"return": {}} {'execute': 'blockdev-add', 'arguments': { 'node-name': 'node1', 'driver': 'file', 'filename': 'TEST_DIR/t.IMGFMT', 'locking': 'on' } } {"return": {}} diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out index ac5ab16bc8..62d1ab74d3 100644 --- a/tests/qemu-iotests/185.out +++ b/tests/qemu-iotests/185.out @@ -9,14 +9,14 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 === Creating backing chain === { 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'disk', 'snapshot-file': 'TEST_DIR/t.IMGFMT.mid', 'format': 'IMGFMT', 'mode': 'absolute-paths' } } -Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} { 'execute': 'human-monitor-command', 'arguments': { 'command-line': 'qemu-io disk "write 0 4M"' } } wrote 4194304/4194304 bytes at offset 0 4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) {"return": ""} { 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'disk', 'snapshot-file': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'absolute-paths' } } -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 {"return": {}} === Start commit job and exit qemu === @@ -48,7 +48,7 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q { 'execute': 'qmp_capabilities' } {"return": {}} { 'execute': 'drive-mirror', 'arguments': { 'device': 'disk', 'target': 'TEST_DIR/t.IMGFMT.copy', 'format': 'IMGFMT', 'sync': 'full', 'speed': 65536 } } -Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} {"return": {}} @@ -62,7 +62,7 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l { 'execute': 'qmp_capabilities' } {"return": {}} { 'execute': 'drive-backup', 'arguments': { 'device': 'disk', 'target': 'TEST_DIR/t.IMGFMT.copy', 'format': 'IMGFMT', 'sync': 'full', 'speed': 65536 } } -Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} diff --git a/tests/qemu-iotests/255.out b/tests/qemu-iotests/255.out index a3c99fd62e..d74903db99 100644 --- a/tests/qemu-iotests/255.out +++ b/tests/qemu-iotests/255.out @@ -3,9 +3,9 @@ Finishing a commit job with background reads === Create backing chain and start VM === -Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16 === Start background read requests === @@ -23,9 +23,9 @@ Closing the VM while a job is being cancelled === Create images and start VM === -Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16 wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out index d24ff681af..d248a1e21b 100644 --- a/tests/qemu-iotests/274.out +++ b/tests/qemu-iotests/274.out @@ -1,9 +1,9 @@ == Commit tests == -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid lazy_refcounts=off refcount_bits=16 wrote 2097152/2097152 bytes at offset 0 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -64,11 +64,11 @@ read 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Testing HMP commit (top -> mid) === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid lazy_refcounts=off refcount_bits=16 wrote 2097152/2097152 bytes at offset 0 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -94,11 +94,11 @@ read 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Testing QMP active commit (top -> mid) === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid lazy_refcounts=off refcount_bits=16 wrote 2097152/2097152 bytes at offset 0 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -131,9 +131,9 @@ read 1048576/1048576 bytes at offset 1048576 == Resize tests == === preallocation=off === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=6442450944 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1073741824 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 5368709120 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -150,9 +150,9 @@ read 65536/65536 bytes at offset 5368709120 { "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}] === preallocation=metadata === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=34359738368 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=32212254720 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 33285996544 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -174,9 +174,9 @@ read 65536/65536 bytes at offset 33285996544 { "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}] === preallocation=falloc === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=10485760 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=5242880 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 9437184 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -193,9 +193,9 @@ read 65536/65536 bytes at offset 9437184 { "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}] === preallocation=full === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=16777216 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=8388608 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 11534336 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -212,9 +212,9 @@ read 65536/65536 bytes at offset 11534336 { "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}] === preallocation=off === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=393216 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=259072 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 259072 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -232,9 +232,9 @@ read 65536/65536 bytes at offset 259072 { "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}] === preallocation=off === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=409600 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 344064 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -251,9 +251,9 @@ read 65536/65536 bytes at offset 344064 { "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}] === preallocation=off === -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=524288 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 446464 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/280.out b/tests/qemu-iotests/280.out index 92e4d14079..fc59b9bc5c 100644 --- a/tests/qemu-iotests/280.out +++ b/tests/qemu-iotests/280.out @@ -1,4 +1,4 @@ -Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 compression_type=zlib +Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 === Launch VM === Enabling migration QMP events on VM... From e0d0ddc591a079d2a3da6aa913ba7dd9551fb5ef Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:41 +0200 Subject: [PATCH 1963/2595] block/crypto: rename two functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rename the write_func to create_write_func, and init_func to create_init_func. This is preparation for other write_func that will be used to update the encryption keys. No functional changes Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé Message-Id: <20200608094030.670121-7-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- block/crypto.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index dcf8b42bb2..1960b47ceb 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -79,12 +79,12 @@ struct BlockCryptoCreateData { }; -static ssize_t block_crypto_write_func(QCryptoBlock *block, - size_t offset, - const uint8_t *buf, - size_t buflen, - void *opaque, - Error **errp) +static ssize_t block_crypto_create_write_func(QCryptoBlock *block, + size_t offset, + const uint8_t *buf, + size_t buflen, + void *opaque, + Error **errp) { struct BlockCryptoCreateData *data = opaque; ssize_t ret; @@ -97,11 +97,10 @@ static ssize_t block_crypto_write_func(QCryptoBlock *block, return ret; } - -static ssize_t block_crypto_init_func(QCryptoBlock *block, - size_t headerlen, - void *opaque, - Error **errp) +static ssize_t block_crypto_create_init_func(QCryptoBlock *block, + size_t headerlen, + void *opaque, + Error **errp) { struct BlockCryptoCreateData *data = opaque; Error *local_error = NULL; @@ -313,8 +312,8 @@ static int block_crypto_co_create_generic(BlockDriverState *bs, }; crypto = qcrypto_block_create(opts, NULL, - block_crypto_init_func, - block_crypto_write_func, + block_crypto_create_init_func, + block_crypto_create_write_func, &data, errp); From bbfdae91fb68783fd54a0f817e3dd9b1c6fe8f8a Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:42 +0200 Subject: [PATCH 1964/2595] block/crypto: implement the encryption key management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements the encryption key management using the generic code in qcrypto layer and exposes it to the user via qemu-img This code adds another 'write_func' because the initialization write_func works directly on the underlying file, and amend works on instance of luks device. This commit also adds a 'hack/workaround' I and Kevin Wolf (thanks) made to make the driver both support write sharing (to avoid breaking the users), and be safe against concurrent metadata update (the keyslots) Eventually the write sharing for luks driver will be deprecated and removed together with this hack. The hack is that we ask (as a format driver) for BLK_PERM_CONSISTENT_READ and then when we want to update the keys, we unshare that permission. So if someone else has the image open, even readonly, encryption key update will fail gracefully. Also thanks to Daniel Berrange for the idea of unsharing read, rather that write permission which allows to avoid cases when the other user had opened the image read-only. Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé Reviewed-by: Max Reitz Message-Id: <20200608094030.670121-8-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- block/crypto.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++-- block/crypto.h | 34 +++++++++++++ 2 files changed, 161 insertions(+), 3 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index 1960b47ceb..b9c40e6922 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -37,6 +37,7 @@ typedef struct BlockCrypto BlockCrypto; struct BlockCrypto { QCryptoBlock *block; + bool updating_keys; }; @@ -71,6 +72,24 @@ static ssize_t block_crypto_read_func(QCryptoBlock *block, return ret; } +static ssize_t block_crypto_write_func(QCryptoBlock *block, + size_t offset, + const uint8_t *buf, + size_t buflen, + void *opaque, + Error **errp) +{ + BlockDriverState *bs = opaque; + ssize_t ret; + + ret = bdrv_pwrite(bs->file, offset, buf, buflen); + if (ret < 0) { + error_setg_errno(errp, -ret, "Could not write encryption header"); + return ret; + } + return ret; +} + struct BlockCryptoCreateData { BlockBackend *blk; @@ -166,6 +185,19 @@ static QemuOptsList block_crypto_create_opts_luks = { }; +static QemuOptsList block_crypto_amend_opts_luks = { + .name = "crypto", + .head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head), + .desc = { + BLOCK_CRYPTO_OPT_DEF_LUKS_STATE(""), + BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(""), + BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET(""), + BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET(""), + BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""), + { /* end of list */ } + }, +}; + QCryptoBlockOpenOptions * block_crypto_open_opts_init(QDict *opts, Error **errp) { @@ -758,6 +790,98 @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp) return spec_info; } +static int +block_crypto_amend_options_luks(BlockDriverState *bs, + QemuOpts *opts, + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque, + bool force, + Error **errp) +{ + BlockCrypto *crypto = bs->opaque; + QDict *cryptoopts = NULL; + QCryptoBlockAmendOptions *amend_options = NULL; + int ret; + + assert(crypto); + assert(crypto->block); + crypto->updating_keys = true; + + ret = bdrv_child_refresh_perms(bs, bs->file, errp); + if (ret < 0) { + goto cleanup; + } + + cryptoopts = qemu_opts_to_qdict(opts, NULL); + qdict_put_str(cryptoopts, "format", "luks"); + amend_options = block_crypto_amend_opts_init(cryptoopts, errp); + if (!amend_options) { + ret = -EINVAL; + goto cleanup; + } + + ret = qcrypto_block_amend_options(crypto->block, + block_crypto_read_func, + block_crypto_write_func, + bs, + amend_options, + force, + errp); +cleanup: + crypto->updating_keys = false; + bdrv_child_refresh_perms(bs, bs->file, errp); + qapi_free_QCryptoBlockAmendOptions(amend_options); + qobject_unref(cryptoopts); + return ret; +} + + +static void +block_crypto_child_perms(BlockDriverState *bs, BdrvChild *c, + const BdrvChildRole role, + BlockReopenQueue *reopen_queue, + uint64_t perm, uint64_t shared, + uint64_t *nperm, uint64_t *nshared) +{ + + BlockCrypto *crypto = bs->opaque; + + bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared); + + /* + * For backward compatibility, manually share the write + * and resize permission + */ + *nshared |= (BLK_PERM_WRITE | BLK_PERM_RESIZE); + /* + * Since we are not fully a format driver, don't always request + * the read/resize permission but only when explicitly + * requested + */ + *nperm &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); + *nperm |= perm & (BLK_PERM_WRITE | BLK_PERM_RESIZE); + + /* + * This driver doesn't modify LUKS metadata except + * when updating the encryption slots. + * Thus unlike a proper format driver we don't ask for + * shared write/read permission. However we need it + * when we are updating the keys, to ensure that only we + * have access to the device. + * + * Encryption update will set the crypto->updating_keys + * during that period and refresh permissions + * + */ + if (crypto->updating_keys) { + /* need exclusive write access for header update */ + *nperm |= BLK_PERM_WRITE; + /* unshare read and write permission */ + *nshared &= ~(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE); + } +} + + static const char *const block_crypto_strong_runtime_opts[] = { BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, @@ -770,13 +894,12 @@ static BlockDriver bdrv_crypto_luks = { .bdrv_probe = block_crypto_probe_luks, .bdrv_open = block_crypto_open_luks, .bdrv_close = block_crypto_close, - /* This driver doesn't modify LUKS metadata except when creating image. - * Allow share-rw=on as a special case. */ - .bdrv_child_perm = bdrv_default_perms, + .bdrv_child_perm = block_crypto_child_perms, .bdrv_co_create = block_crypto_co_create_luks, .bdrv_co_create_opts = block_crypto_co_create_opts_luks, .bdrv_co_truncate = block_crypto_co_truncate, .create_opts = &block_crypto_create_opts_luks, + .amend_opts = &block_crypto_amend_opts_luks, .bdrv_reopen_prepare = block_crypto_reopen_prepare, .bdrv_refresh_limits = block_crypto_refresh_limits, @@ -786,6 +909,7 @@ static BlockDriver bdrv_crypto_luks = { .bdrv_measure = block_crypto_measure, .bdrv_get_info = block_crypto_get_info_luks, .bdrv_get_specific_info = block_crypto_get_specific_info_luks, + .bdrv_amend_options = block_crypto_amend_options_luks, .is_format = true, diff --git a/block/crypto.h b/block/crypto.h index 06e044c9be..c72c3dec61 100644 --- a/block/crypto.h +++ b/block/crypto.h @@ -41,6 +41,11 @@ #define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg" #define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg" #define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time" +#define BLOCK_CRYPTO_OPT_LUKS_KEYSLOT "keyslot" +#define BLOCK_CRYPTO_OPT_LUKS_STATE "state" +#define BLOCK_CRYPTO_OPT_LUKS_OLD_SECRET "old-secret" +#define BLOCK_CRYPTO_OPT_LUKS_NEW_SECRET "new-secret" + #define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(prefix) \ BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, \ @@ -88,6 +93,35 @@ .help = "Time to spend in PBKDF in milliseconds", \ } +#define BLOCK_CRYPTO_OPT_DEF_LUKS_STATE(prefix) \ + { \ + .name = prefix BLOCK_CRYPTO_OPT_LUKS_STATE, \ + .type = QEMU_OPT_STRING, \ + .help = "Select new state of affected keyslots (active/inactive)",\ + } + +#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(prefix) \ + { \ + .name = prefix BLOCK_CRYPTO_OPT_LUKS_KEYSLOT, \ + .type = QEMU_OPT_NUMBER, \ + .help = "Select a single keyslot to modify explicitly",\ + } + +#define BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET(prefix) \ + { \ + .name = prefix BLOCK_CRYPTO_OPT_LUKS_OLD_SECRET, \ + .type = QEMU_OPT_STRING, \ + .help = "Select all keyslots that match this password", \ + } + +#define BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET(prefix) \ + { \ + .name = prefix BLOCK_CRYPTO_OPT_LUKS_NEW_SECRET, \ + .type = QEMU_OPT_STRING, \ + .help = "New secret to set in the matching keyslots. " \ + "Empty string to erase", \ + } + QCryptoBlockCreateOptions * block_crypto_create_opts_init(QDict *opts, Error **errp); From 90766d9db987a089ba271f6d30d6856745a7a3ce Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:43 +0200 Subject: [PATCH 1965/2595] block/qcow2: extend qemu-img amend interface with crypto options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we have all the infrastructure in place, wire it in the qcow2 driver and expose this to the user. Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé Reviewed-by: Max Reitz Message-Id: <20200608094030.670121-9-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- block/qcow2.c | 71 +++++++++++++++++++++++++++++++++----- tests/qemu-iotests/082.out | 45 ++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 9 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 389205dffd..750e9c4842 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -176,6 +176,19 @@ static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset, return ret; } +static QDict* +qcow2_extract_crypto_opts(QemuOpts *opts, const char *fmt, Error **errp) +{ + QDict *cryptoopts_qdict; + QDict *opts_qdict; + + /* Extract "encrypt." options into a qdict */ + opts_qdict = qemu_opts_to_qdict(opts, NULL); + qdict_extract_subqdict(opts_qdict, &cryptoopts_qdict, "encrypt."); + qobject_unref(opts_qdict); + qdict_put_str(cryptoopts_qdict, "format", fmt); + return cryptoopts_qdict; +} /* * read qcow2 extension and fill bs @@ -4860,16 +4873,9 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs, if (has_luks) { g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL; - QDict *opts_qdict; - QDict *cryptoopts; + QDict *cryptoopts = qcow2_extract_crypto_opts(opts, "luks", errp); size_t headerlen; - opts_qdict = qemu_opts_to_qdict(opts, NULL); - qdict_extract_subqdict(opts_qdict, &cryptoopts, "encrypt."); - qobject_unref(opts_qdict); - - qdict_put_str(cryptoopts, "format", "luks"); - create_opts = block_crypto_create_opts_init(cryptoopts, errp); qobject_unref(cryptoopts); if (!create_opts) { @@ -5273,6 +5279,7 @@ typedef enum Qcow2AmendOperation { QCOW2_NO_OPERATION = 0, QCOW2_UPGRADING, + QCOW2_UPDATING_ENCRYPTION, QCOW2_CHANGING_REFCOUNT_ORDER, QCOW2_DOWNGRADING, } Qcow2AmendOperation; @@ -5354,6 +5361,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, int ret; QemuOptDesc *desc = opts->list->desc; Qcow2AmendHelperCBInfo helper_cb_info; + bool encryption_update = false; while (desc && desc->name) { if (!qemu_opt_find(opts, desc->name)) { @@ -5380,6 +5388,18 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE); } else if (!strcmp(desc->name, BLOCK_OPT_BACKING_FMT)) { backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT); + } else if (g_str_has_prefix(desc->name, "encrypt.")) { + if (!s->crypto) { + error_setg(errp, + "Can't amend encryption options - encryption not present"); + return -EINVAL; + } + if (s->crypt_method_header != QCOW_CRYPT_LUKS) { + error_setg(errp, + "Only LUKS encryption options can be amended"); + return -ENOTSUP; + } + encryption_update = true; } else if (!strcmp(desc->name, BLOCK_OPT_LAZY_REFCOUNTS)) { lazy_refcounts = qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS, lazy_refcounts); @@ -5422,7 +5442,8 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, .original_status_cb = status_cb, .original_cb_opaque = cb_opaque, .total_operations = (new_version != old_version) - + (s->refcount_bits != refcount_bits) + + (s->refcount_bits != refcount_bits) + + (encryption_update == true) }; /* Upgrade first (some features may require compat=1.1) */ @@ -5435,6 +5456,33 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, } } + if (encryption_update) { + QDict *amend_opts_dict; + QCryptoBlockAmendOptions *amend_opts; + + helper_cb_info.current_operation = QCOW2_UPDATING_ENCRYPTION; + amend_opts_dict = qcow2_extract_crypto_opts(opts, "luks", errp); + if (!amend_opts_dict) { + return -EINVAL; + } + amend_opts = block_crypto_amend_opts_init(amend_opts_dict, errp); + qobject_unref(amend_opts_dict); + if (!amend_opts) { + return -EINVAL; + } + ret = qcrypto_block_amend_options(s->crypto, + qcow2_crypto_hdr_read_func, + qcow2_crypto_hdr_write_func, + bs, + amend_opts, + force, + errp); + qapi_free_QCryptoBlockAmendOptions(amend_opts); + if (ret < 0) { + return ret; + } + } + if (s->refcount_bits != refcount_bits) { int refcount_order = ctz32(refcount_bits); @@ -5694,6 +5742,11 @@ static QemuOptsList qcow2_amend_opts = { .name = "qcow2-amend-opts", .head = QTAILQ_HEAD_INITIALIZER(qcow2_amend_opts.head), .desc = { + BLOCK_CRYPTO_OPT_DEF_LUKS_STATE("encrypt."), + BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT("encrypt."), + BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET("encrypt."), + BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET("encrypt."), + BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."), QCOW_COMMON_OPTIONS, { /* end of list */ } } diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index b1cf5dfe43..a4a2b69030 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -645,6 +645,11 @@ Amend options for 'qcow2': compat= - Compatibility level (v2 [0.10] or v3 [1.1]) data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image + encrypt.iter-time= - Time to spend in PBKDF in milliseconds + encrypt.keyslot= - Select a single keyslot to modify explicitly + encrypt.new-secret= - New secret to set in the matching keyslots. Empty string to erase + encrypt.old-secret= - Select all keyslots that match this password + encrypt.state= - Select new state of affected keyslots (active/inactive) lazy_refcounts= - Postpone refcount updates refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size @@ -656,6 +661,11 @@ Amend options for 'qcow2': compat= - Compatibility level (v2 [0.10] or v3 [1.1]) data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image + encrypt.iter-time= - Time to spend in PBKDF in milliseconds + encrypt.keyslot= - Select a single keyslot to modify explicitly + encrypt.new-secret= - New secret to set in the matching keyslots. Empty string to erase + encrypt.old-secret= - Select all keyslots that match this password + encrypt.state= - Select new state of affected keyslots (active/inactive) lazy_refcounts= - Postpone refcount updates refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size @@ -667,6 +677,11 @@ Amend options for 'qcow2': compat= - Compatibility level (v2 [0.10] or v3 [1.1]) data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image + encrypt.iter-time= - Time to spend in PBKDF in milliseconds + encrypt.keyslot= - Select a single keyslot to modify explicitly + encrypt.new-secret= - New secret to set in the matching keyslots. Empty string to erase + encrypt.old-secret= - Select all keyslots that match this password + encrypt.state= - Select new state of affected keyslots (active/inactive) lazy_refcounts= - Postpone refcount updates refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size @@ -678,6 +693,11 @@ Amend options for 'qcow2': compat= - Compatibility level (v2 [0.10] or v3 [1.1]) data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image + encrypt.iter-time= - Time to spend in PBKDF in milliseconds + encrypt.keyslot= - Select a single keyslot to modify explicitly + encrypt.new-secret= - New secret to set in the matching keyslots. Empty string to erase + encrypt.old-secret= - Select all keyslots that match this password + encrypt.state= - Select new state of affected keyslots (active/inactive) lazy_refcounts= - Postpone refcount updates refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size @@ -689,6 +709,11 @@ Amend options for 'qcow2': compat= - Compatibility level (v2 [0.10] or v3 [1.1]) data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image + encrypt.iter-time= - Time to spend in PBKDF in milliseconds + encrypt.keyslot= - Select a single keyslot to modify explicitly + encrypt.new-secret= - New secret to set in the matching keyslots. Empty string to erase + encrypt.old-secret= - Select all keyslots that match this password + encrypt.state= - Select new state of affected keyslots (active/inactive) lazy_refcounts= - Postpone refcount updates refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size @@ -700,6 +725,11 @@ Amend options for 'qcow2': compat= - Compatibility level (v2 [0.10] or v3 [1.1]) data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image + encrypt.iter-time= - Time to spend in PBKDF in milliseconds + encrypt.keyslot= - Select a single keyslot to modify explicitly + encrypt.new-secret= - New secret to set in the matching keyslots. Empty string to erase + encrypt.old-secret= - Select all keyslots that match this password + encrypt.state= - Select new state of affected keyslots (active/inactive) lazy_refcounts= - Postpone refcount updates refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size @@ -711,6 +741,11 @@ Amend options for 'qcow2': compat= - Compatibility level (v2 [0.10] or v3 [1.1]) data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image + encrypt.iter-time= - Time to spend in PBKDF in milliseconds + encrypt.keyslot= - Select a single keyslot to modify explicitly + encrypt.new-secret= - New secret to set in the matching keyslots. Empty string to erase + encrypt.old-secret= - Select all keyslots that match this password + encrypt.state= - Select new state of affected keyslots (active/inactive) lazy_refcounts= - Postpone refcount updates refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size @@ -722,6 +757,11 @@ Amend options for 'qcow2': compat= - Compatibility level (v2 [0.10] or v3 [1.1]) data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image + encrypt.iter-time= - Time to spend in PBKDF in milliseconds + encrypt.keyslot= - Select a single keyslot to modify explicitly + encrypt.new-secret= - New secret to set in the matching keyslots. Empty string to erase + encrypt.old-secret= - Select all keyslots that match this password + encrypt.state= - Select new state of affected keyslots (active/inactive) lazy_refcounts= - Postpone refcount updates refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size @@ -750,6 +790,11 @@ Amend options for 'qcow2': compat= - Compatibility level (v2 [0.10] or v3 [1.1]) data_file= - File name of an external data file data_file_raw= - The external data file must stay valid as a raw image + encrypt.iter-time= - Time to spend in PBKDF in milliseconds + encrypt.keyslot= - Select a single keyslot to modify explicitly + encrypt.new-secret= - New secret to set in the matching keyslots. Empty string to erase + encrypt.old-secret= - Select all keyslots that match this password + encrypt.state= - Select new state of affected keyslots (active/inactive) lazy_refcounts= - Postpone refcount updates refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size From 11d80bfc6da00d8b53bf1cc2da19b4a2e0b23961 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:44 +0200 Subject: [PATCH 1966/2595] iotests: qemu-img tests for luks key management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds two tests, which test the new amend interface of both luks raw images and qcow2 luks encrypted images. Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé [mreitz: Let 293 verify that LUKS works; drop $(seq) usage from 293; drop 293 and 294 from the auto group] Signed-off-by: Max Reitz Message-Id: <20200625125548.870061-16-mreitz@redhat.com> --- tests/qemu-iotests/293 | 208 +++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/293.out | 99 ++++++++++++++++++ tests/qemu-iotests/294 | 90 ++++++++++++++++ tests/qemu-iotests/294.out | 30 ++++++ tests/qemu-iotests/group | 2 + 5 files changed, 429 insertions(+) create mode 100755 tests/qemu-iotests/293 create mode 100644 tests/qemu-iotests/293.out create mode 100755 tests/qemu-iotests/294 create mode 100644 tests/qemu-iotests/294.out diff --git a/tests/qemu-iotests/293 b/tests/qemu-iotests/293 new file mode 100755 index 0000000000..f86fe3b413 --- /dev/null +++ b/tests/qemu-iotests/293 @@ -0,0 +1,208 @@ +#!/usr/bin/env bash +# +# Test encryption key management with luks +# Based on 134 +# +# 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 . +# + +# creator +owner=mlevitsk@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 luks +_supported_proto file #TODO +_require_working_luks + +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT + +if [ "$IMGFMT" = "qcow2" ] ; then + PR="encrypt." + EXTRA_IMG_ARGS="-o encrypt.format=luks" +fi + + +# secrets: you are supposed to see the password as *******, see :-) +S0="--object secret,id=sec0,data=hunter0" +S1="--object secret,id=sec1,data=hunter1" +S2="--object secret,id=sec2,data=hunter2" +S3="--object secret,id=sec3,data=hunter3" +S4="--object secret,id=sec4,data=hunter4" +SECRETS="$S0 $S1 $S2 $S3 $S4" + +# image with given secret +IMGS0="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,${PR}key-secret=sec0" +IMGS1="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,${PR}key-secret=sec1" +IMGS2="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,${PR}key-secret=sec2" +IMGS3="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,${PR}key-secret=sec3" +IMGS4="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,${PR}key-secret=sec4" + + +echo "== creating a test image ==" +_make_test_img $S0 $EXTRA_IMG_ARGS -o ${PR}key-secret=sec0,${PR}iter-time=10 32M + +echo +echo "== test that key 0 opens the image ==" +$QEMU_IO $S0 -c "read 0 4096" $IMGS0 | _filter_qemu_io | _filter_testdir + +echo +echo "== adding a password to slot 4 ==" +$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=active,${PR}new-secret=sec4,${PR}iter-time=10,${PR}keyslot=4 +echo "== adding a password to slot 1 ==" +$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=active,${PR}new-secret=sec1,${PR}iter-time=10 +echo "== adding a password to slot 3 ==" +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=active,${PR}new-secret=sec3,${PR}iter-time=10,${PR}keyslot=3 + +echo "== adding a password to slot 2 ==" +$QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=active,${PR}new-secret=sec2,${PR}iter-time=10 + + +echo "== erase slot 4 ==" +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}keyslot=4 | _filter_img_create + + +echo +echo "== all secrets should work ==" +for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do + $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir +done + +echo +echo "== erase slot 0 and try it ==" +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec0 | _filter_img_create +$QEMU_IO $SECRETS -c "read 0 4096" $IMGS0 | _filter_qemu_io | _filter_testdir + +echo +echo "== erase slot 2 and try it ==" +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}keyslot=2 | _filter_img_create +$QEMU_IO $SECRETS -c "read 0 4096" $IMGS2 | _filter_qemu_io | _filter_testdir + + +# at this point slots 1 and 3 should be active + +echo +echo "== filling 4 slots with secret 2 ==" +for ((i = 0; i < 4; i++)); do + $QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=active,${PR}new-secret=sec2,${PR}iter-time=10 +done + +echo +echo "== adding secret 0 ==" + $QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=active,${PR}new-secret=sec0,${PR}iter-time=10 + +echo +echo "== adding secret 3 (last slot) ==" + $QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=active,${PR}new-secret=sec3,${PR}iter-time=10 + +echo +echo "== trying to add another slot (should fail) ==" +$QEMU_IMG amend $SECRETS $IMGS2 -o ${PR}state=active,${PR}new-secret=sec3,${PR}iter-time=10 + +echo +echo "== all secrets should work again ==" +for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do + $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir +done + + +echo + +echo "== erase all keys of secret 2==" +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec2 + +echo "== erase all keys of secret 1==" +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec1 + +echo "== erase all keys of secret 0==" +$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=inactive,${PR}old-secret=sec0 + +echo "== erasing secret3 will fail now since it is the only secret (in 3 slots) ==" +$QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=inactive,${PR}old-secret=sec3 + +echo +echo "== only secret3 should work now ==" +for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do + $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir +done + +echo +echo "== add secret0 ==" +$QEMU_IMG amend $SECRETS $IMGS3 -o ${PR}state=active,${PR}new-secret=sec0,${PR}iter-time=10 + +echo "== erase secret3 ==" +$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=inactive,${PR}old-secret=sec3 + +echo +echo "== only secret0 should work now ==" +for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do + $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir +done + +echo +echo "== replace secret0 with secret1 (should fail) ==" +$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=active,${PR}new-secret=sec1,${PR}keyslot=0 + +echo +echo "== replace secret0 with secret1 with force (should work) ==" +$QEMU_IMG amend $SECRETS $IMGS0 -o ${PR}state=active,${PR}new-secret=sec1,${PR}iter-time=10,${PR}keyslot=0 --force + +echo +echo "== only secret1 should work now ==" +for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do + $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir +done + + +echo +echo "== erase last secret (should fail) ==" +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}keyslot=0 +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec1 + + +echo "== erase non existing secrets (should fail) ==" +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec5 --force +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}old-secret=sec0 --force +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}keyslot=1 --force + +echo +echo "== erase last secret with force by slot (should work) ==" +$QEMU_IMG amend $SECRETS $IMGS1 -o ${PR}state=inactive,${PR}keyslot=0 --force + +echo +echo "== we have no secrets now, data is lost forever ==" +for IMG in "$IMGS0" "$IMGS1" "$IMGS2" "$IMGS3"; do + $QEMU_IO $SECRETS -c "read 0 4096" $IMG | _filter_qemu_io | _filter_testdir +done + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 + diff --git a/tests/qemu-iotests/293.out b/tests/qemu-iotests/293.out new file mode 100644 index 0000000000..7260783126 --- /dev/null +++ b/tests/qemu-iotests/293.out @@ -0,0 +1,99 @@ +QA output created by 293 +== creating a test image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 + +== test that key 0 opens the image == +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== adding a password to slot 4 == +== adding a password to slot 1 == +== adding a password to slot 3 == +== adding a password to slot 2 == +== erase slot 4 == + +== all secrets should work == +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== erase slot 0 and try it == +qemu-io: can't open: Invalid password, cannot unlock any keyslot + +== erase slot 2 and try it == +qemu-io: can't open: Invalid password, cannot unlock any keyslot + +== filling 4 slots with secret 2 == + +== adding secret 0 == + +== adding secret 3 (last slot) == + +== trying to add another slot (should fail) == +qemu-img: Can't add a keyslot - all keyslots are in use + +== all secrets should work again == +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== erase all keys of secret 2== +== erase all keys of secret 1== +== erase all keys of secret 0== +== erasing secret3 will fail now since it is the only secret (in 3 slots) == +qemu-img: All the active keyslots match the (old) password that was given and erasing them will erase all the data in the image irreversibly - refusing operation + +== only secret3 should work now == +qemu-io: can't open: Invalid password, cannot unlock any keyslot +qemu-io: can't open: Invalid password, cannot unlock any keyslot +qemu-io: can't open: Invalid password, cannot unlock any keyslot +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== add secret0 == +== erase secret3 == + +== only secret0 should work now == +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io: can't open: Invalid password, cannot unlock any keyslot +qemu-io: can't open: Invalid password, cannot unlock any keyslot +qemu-io: can't open: Invalid password, cannot unlock any keyslot + +== replace secret0 with secret1 (should fail) == +qemu-img: Refusing to overwrite active keyslot 0 - please erase it first + +== replace secret0 with secret1 with force (should work) == + +== only secret1 should work now == +qemu-io: can't open: Invalid password, cannot unlock any keyslot +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io: can't open: Invalid password, cannot unlock any keyslot +qemu-io: can't open: Invalid password, cannot unlock any keyslot + +== erase last secret (should fail) == +qemu-img: Attempt to erase the only active keyslot 0 which will erase all the data in the image irreversibly - refusing operation +qemu-img: All the active keyslots match the (old) password that was given and erasing them will erase all the data in the image irreversibly - refusing operation +== erase non existing secrets (should fail) == +qemu-img: No secret with id 'sec5' +qemu-img: No keyslots match given (old) password for erase operation + +== erase last secret with force by slot (should work) == + +== we have no secrets now, data is lost forever == +qemu-io: can't open: Invalid password, cannot unlock any keyslot +qemu-io: can't open: Invalid password, cannot unlock any keyslot +qemu-io: can't open: Invalid password, cannot unlock any keyslot +qemu-io: can't open: Invalid password, cannot unlock any keyslot +*** done diff --git a/tests/qemu-iotests/294 b/tests/qemu-iotests/294 new file mode 100755 index 0000000000..9c95ed8c9a --- /dev/null +++ b/tests/qemu-iotests/294 @@ -0,0 +1,90 @@ +# +# 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 . +# + +# creator +owner=mlevitsk@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt luks +_supported_proto file #TODO + +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT + +# you are supposed to see the password as *******, see :-) +S0="--object secret,id=sec0,data=hunter0" +S1="--object secret,id=sec1,data=hunter1" +SECRETS="$S0 $S1" + + +IMGS0="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,key-secret=sec0" +IMGS1="--image-opts driver=$IMGFMT,file.filename=$TEST_IMG,key-secret=sec1" + +echo "== creating a test image ==" +_make_test_img $S0 -o "key-secret=sec0,iter-time=10" 32M + +echo +echo "== test that key 0 opens the image ==" +$QEMU_IO $S0 -c "read 0 4096" $IMGS0 | _filter_qemu_io | _filter_testdir + +echo +echo "== adding a password to slot 1 ==" +$QEMU_IMG amend $SECRETS $IMGS0 -o state=active,new-secret=sec1,keyslot=1,iter-time=10 + +echo +echo "== 'backup' the image header ==" +dd if=$TEST_IMG_FILE of=${TEST_IMG_FILE}.bk bs=4K skip=0 count=1 + +echo +echo "== erase slot 0 ==" +$QEMU_IMG amend $SECRETS $IMGS1 -o state=inactive,keyslot=0 | _filter_img_create + +echo +echo "== test that key 0 doesn't open the image ==" +$QEMU_IO $S0 -c "read 0 4096" $IMGS0 | _filter_qemu_io | _filter_testdir + +echo +echo "== 'restore' the image header ==" +dd if=${TEST_IMG_FILE}.bk of=${TEST_IMG_FILE} bs=4K skip=0 count=1 conv=notrunc + +echo +echo "== test that key 0 still doesn't open the image (key material is erased) ==" +$QEMU_IO $SECRETS -c "read 0 4096" $IMGS0 | _filter_qemu_io | _filter_testdir + +echo +echo "== test that key 1 still works ==" +$QEMU_IO $SECRETS -c "read 0 4096" $IMGS1 | _filter_qemu_io | _filter_testdir + +echo "*** done" +rm -f $seq.full +status=0 + + +exit 0 diff --git a/tests/qemu-iotests/294.out b/tests/qemu-iotests/294.out new file mode 100644 index 0000000000..994ae87308 --- /dev/null +++ b/tests/qemu-iotests/294.out @@ -0,0 +1,30 @@ +QA output created by 294 +== creating a test image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 + +== test that key 0 opens the image == +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== adding a password to slot 1 == + +== 'backup' the image header == +1+0 records in +1+0 records out + +== erase slot 0 == + +== test that key 0 doesn't open the image == +qemu-io: can't open: Invalid password, cannot unlock any keyslot + +== 'restore' the image header == +1+0 records in +1+0 records out + +== test that key 0 still doesn't open the image (key material is erased) == +qemu-io: can't open: Invalid password, cannot unlock any keyslot + +== test that key 1 still works == +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index d886fa0cb3..b945dd4f20 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -301,4 +301,6 @@ 290 rw auto quick 291 rw quick 292 rw auto quick +293 rw +294 rw quick 297 meta From ced914d0ab9fb2c900f873f6349a0b8eecd1fdbe Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:45 +0200 Subject: [PATCH 1967/2595] block/core: add generic infrastructure for x-blockdev-amend qmp command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit blockdev-amend will be used similiar to blockdev-create to allow on the fly changes of the structure of the format based block devices. Current plan is to first support encryption keyslot management for luks based formats (raw and embedded in qcow2) Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé Message-Id: <20200608094030.670121-12-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- block/Makefile.objs | 2 +- block/amend.c | 113 ++++++++++++++++++++++++++++++++++++++ include/block/block_int.h | 21 +++++-- qapi/block-core.json | 42 ++++++++++++++ qapi/job.json | 4 +- 5 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 block/amend.c diff --git a/block/Makefile.objs b/block/Makefile.objs index 96028eedce..577e578bc2 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -19,7 +19,7 @@ block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o block-obj-$(CONFIG_POSIX) += file-posix.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o block-obj-$(CONFIG_LINUX_IO_URING) += io_uring.o -block-obj-y += null.o mirror.o commit.o io.o create.o +block-obj-y += null.o mirror.o commit.o io.o create.o amend.o block-obj-y += throttle-groups.o block-obj-$(CONFIG_LINUX) += nvme.o diff --git a/block/amend.c b/block/amend.c new file mode 100644 index 0000000000..f4612dcf08 --- /dev/null +++ b/block/amend.c @@ -0,0 +1,113 @@ +/* + * Block layer code related to image options amend + * + * Copyright (c) 2018 Kevin Wolf + * Copyright (c) 2020 Red Hat. Inc + * + * Heavily based on create.c + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "block/block_int.h" +#include "qemu/job.h" +#include "qemu/main-loop.h" +#include "qapi/qapi-commands-block-core.h" +#include "qapi/qapi-visit-block-core.h" +#include "qapi/clone-visitor.h" +#include "qapi/error.h" + +typedef struct BlockdevAmendJob { + Job common; + BlockdevAmendOptions *opts; + BlockDriverState *bs; + bool force; +} BlockdevAmendJob; + +static int coroutine_fn blockdev_amend_run(Job *job, Error **errp) +{ + BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common); + int ret; + + job_progress_set_remaining(&s->common, 1); + ret = s->bs->drv->bdrv_co_amend(s->bs, s->opts, s->force, errp); + job_progress_update(&s->common, 1); + qapi_free_BlockdevAmendOptions(s->opts); + return ret; +} + +static const JobDriver blockdev_amend_job_driver = { + .instance_size = sizeof(BlockdevAmendJob), + .job_type = JOB_TYPE_AMEND, + .run = blockdev_amend_run, +}; + +void qmp_x_blockdev_amend(const char *job_id, + const char *node_name, + BlockdevAmendOptions *options, + bool has_force, + bool force, + Error **errp) +{ + BlockdevAmendJob *s; + const char *fmt = BlockdevDriver_str(options->driver); + BlockDriver *drv = bdrv_find_format(fmt); + BlockDriverState *bs = bdrv_find_node(node_name); + + + if (!drv) { + error_setg(errp, "Block driver '%s' not found or not supported", fmt); + return; + } + + /* + * If the driver is in the schema, we know that it exists. But it may not + * be whitelisted. + */ + if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) { + error_setg(errp, "Driver is not whitelisted"); + return; + } + + if (bs->drv != drv) { + error_setg(errp, + "x-blockdev-amend doesn't support changing the block driver"); + return; + } + + /* Error out if the driver doesn't support .bdrv_co_amend */ + if (!drv->bdrv_co_amend) { + error_setg(errp, "Driver does not support x-blockdev-amend"); + return; + } + + /* Create the block job */ + s = job_create(job_id, &blockdev_amend_job_driver, NULL, + bdrv_get_aio_context(bs), JOB_DEFAULT | JOB_MANUAL_DISMISS, + NULL, NULL, errp); + if (!s) { + return; + } + + s->bs = bs, + s->opts = QAPI_CLONE(BlockdevAmendOptions, options), + s->force = has_force ? force : false; + job_start(&s->common); +} diff --git a/include/block/block_int.h b/include/block/block_int.h index ed335519cc..1b86b59af1 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -141,12 +141,27 @@ struct BlockDriver { int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags, Error **errp); void (*bdrv_close)(BlockDriverState *bs); + + int coroutine_fn (*bdrv_co_create)(BlockdevCreateOptions *opts, Error **errp); int coroutine_fn (*bdrv_co_create_opts)(BlockDriver *drv, const char *filename, QemuOpts *opts, Error **errp); + + int coroutine_fn (*bdrv_co_amend)(BlockDriverState *bs, + BlockdevAmendOptions *opts, + bool force, + Error **errp); + + int (*bdrv_amend_options)(BlockDriverState *bs, + QemuOpts *opts, + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque, + bool force, + Error **errp); + int (*bdrv_make_empty)(BlockDriverState *bs); /* @@ -441,12 +456,6 @@ struct BlockDriver { BdrvCheckResult *result, BdrvCheckMode fix); - int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts, - BlockDriverAmendStatusCB *status_cb, - void *cb_opaque, - bool force, - Error **errp); - void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event); /* TODO Better pass a option string/QDict/QemuOpts to add any rule? */ diff --git a/qapi/block-core.json b/qapi/block-core.json index 0e1c6a59f2..c22996282f 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4674,6 +4674,48 @@ 'data': { 'job-id': 'str', 'options': 'BlockdevCreateOptions' } } +## +# @BlockdevAmendOptions: +# +# Options for amending an image format +# +# @driver: Block driver of the node to amend. +# +# Since: 5.1 +## +{ 'union': 'BlockdevAmendOptions', + 'base': { + 'driver': 'BlockdevDriver' }, + 'discriminator': 'driver', + 'data': { + } } + +## +# @x-blockdev-amend: +# +# Starts a job to amend format specific options of an existing open block device +# The job is automatically finalized, but a manual job-dismiss is required. +# +# @job-id: Identifier for the newly created job. +# +# @node-name: Name of the block node to work on +# +# @options: Options (driver specific) +# +# @force: Allow unsafe operations, format specific +# For luks that allows erase of the last active keyslot +# (permanent loss of data), +# and replacement of an active keyslot +# (possible loss of data if IO error happens) +# +# Since: 5.1 +## +{ 'command': 'x-blockdev-amend', + 'data': { 'job-id': 'str', + 'node-name': 'str', + 'options': 'BlockdevAmendOptions', + '*force': 'bool' } } + ## # @BlockErrorAction: # diff --git a/qapi/job.json b/qapi/job.json index 5e658281f5..c48a0c3e34 100644 --- a/qapi/job.json +++ b/qapi/job.json @@ -19,10 +19,12 @@ # # @create: image creation job type, see "blockdev-create" (since 3.0) # +# @amend: image options amend job type, see "x-blockdev-amend" (since 5.1) +# # Since: 1.7 ## { 'enum': 'JobType', - 'data': ['commit', 'stream', 'mirror', 'backup', 'create'] } + 'data': ['commit', 'stream', 'mirror', 'backup', 'create', 'amend'] } ## # @JobStatus: From 30da9dd88a0315d73320e27dfb69093ee3ce5d1c Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:46 +0200 Subject: [PATCH 1968/2595] block/crypto: implement blockdev-amend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé Reviewed-by: Max Reitz Message-Id: <20200608094030.670121-13-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- block/crypto.c | 74 ++++++++++++++++++++++++++++++++------------ qapi/block-core.json | 14 ++++++++- 2 files changed, 67 insertions(+), 21 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index b9c40e6922..3fbd68832b 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -791,32 +791,21 @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp) } static int -block_crypto_amend_options_luks(BlockDriverState *bs, - QemuOpts *opts, - BlockDriverAmendStatusCB *status_cb, - void *cb_opaque, - bool force, - Error **errp) +block_crypto_amend_options_generic_luks(BlockDriverState *bs, + QCryptoBlockAmendOptions *amend_options, + bool force, + Error **errp) { BlockCrypto *crypto = bs->opaque; - QDict *cryptoopts = NULL; - QCryptoBlockAmendOptions *amend_options = NULL; int ret; assert(crypto); assert(crypto->block); + + /* apply for exclusive read/write permissions to the underlying file*/ crypto->updating_keys = true; - ret = bdrv_child_refresh_perms(bs, bs->file, errp); - if (ret < 0) { - goto cleanup; - } - - cryptoopts = qemu_opts_to_qdict(opts, NULL); - qdict_put_str(cryptoopts, "format", "luks"); - amend_options = block_crypto_amend_opts_init(cryptoopts, errp); - if (!amend_options) { - ret = -EINVAL; + if (ret) { goto cleanup; } @@ -828,13 +817,57 @@ block_crypto_amend_options_luks(BlockDriverState *bs, force, errp); cleanup: + /* release exclusive read/write permissions to the underlying file*/ crypto->updating_keys = false; bdrv_child_refresh_perms(bs, bs->file, errp); - qapi_free_QCryptoBlockAmendOptions(amend_options); - qobject_unref(cryptoopts); return ret; } +static int +block_crypto_amend_options_luks(BlockDriverState *bs, + QemuOpts *opts, + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque, + bool force, + Error **errp) +{ + BlockCrypto *crypto = bs->opaque; + QDict *cryptoopts = NULL; + QCryptoBlockAmendOptions *amend_options = NULL; + int ret = -EINVAL; + + assert(crypto); + assert(crypto->block); + + cryptoopts = qemu_opts_to_qdict(opts, NULL); + qdict_put_str(cryptoopts, "format", "luks"); + amend_options = block_crypto_amend_opts_init(cryptoopts, errp); + qobject_unref(cryptoopts); + if (!amend_options) { + goto cleanup; + } + ret = block_crypto_amend_options_generic_luks(bs, amend_options, + force, errp); +cleanup: + qapi_free_QCryptoBlockAmendOptions(amend_options); + return ret; +} + +static int +coroutine_fn block_crypto_co_amend_luks(BlockDriverState *bs, + BlockdevAmendOptions *opts, + bool force, + Error **errp) +{ + QCryptoBlockAmendOptions amend_opts; + + amend_opts = (QCryptoBlockAmendOptions) { + .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, + .u.luks = *qapi_BlockdevAmendOptionsLUKS_base(&opts->u.luks), + }; + return block_crypto_amend_options_generic_luks(bs, &amend_opts, + force, errp); +} static void block_crypto_child_perms(BlockDriverState *bs, BdrvChild *c, @@ -910,6 +943,7 @@ static BlockDriver bdrv_crypto_luks = { .bdrv_get_info = block_crypto_get_info_luks, .bdrv_get_specific_info = block_crypto_get_specific_info_luks, .bdrv_amend_options = block_crypto_amend_options_luks, + .bdrv_co_amend = block_crypto_co_amend_luks, .is_format = true, diff --git a/qapi/block-core.json b/qapi/block-core.json index c22996282f..cd679ad435 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4674,6 +4674,18 @@ 'data': { 'job-id': 'str', 'options': 'BlockdevCreateOptions' } } +## +# @BlockdevAmendOptionsLUKS: +# +# Driver specific image amend options for LUKS. +# +# Since: 5.1 +## +{ 'struct': 'BlockdevAmendOptionsLUKS', + 'base': 'QCryptoBlockAmendOptionsLUKS', + 'data': { } +} + ## # @BlockdevAmendOptions: # @@ -4688,7 +4700,7 @@ 'driver': 'BlockdevDriver' }, 'discriminator': 'driver', 'data': { - } } + 'luks': 'BlockdevAmendOptionsLUKS' } } ## # @x-blockdev-amend: From 8ea1613d91b2f515132f015430efaa35adb8f6d0 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:47 +0200 Subject: [PATCH 1969/2595] block/qcow2: implement blockdev-amend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the implementation only supports amending the encryption options, unlike the qemu-img version Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé Reviewed-by: Max Reitz Message-Id: <20200608094030.670121-14-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- block/qcow2.c | 39 +++++++++++++++++++++++++++++++++++++++ qapi/block-core.json | 16 +++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/block/qcow2.c b/block/qcow2.c index 750e9c4842..30f073cf2a 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5596,6 +5596,44 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, return 0; } +static int coroutine_fn qcow2_co_amend(BlockDriverState *bs, + BlockdevAmendOptions *opts, + bool force, + Error **errp) +{ + BlockdevAmendOptionsQcow2 *qopts = &opts->u.qcow2; + BDRVQcow2State *s = bs->opaque; + int ret = 0; + + if (qopts->has_encrypt) { + if (!s->crypto) { + error_setg(errp, "image is not encrypted, can't amend"); + return -EOPNOTSUPP; + } + + if (qopts->encrypt->format != Q_CRYPTO_BLOCK_FORMAT_LUKS) { + error_setg(errp, + "Amend can't be used to change the qcow2 encryption format"); + return -EOPNOTSUPP; + } + + if (s->crypt_method_header != QCOW_CRYPT_LUKS) { + error_setg(errp, + "Only LUKS encryption options can be amended for qcow2 with blockdev-amend"); + return -EOPNOTSUPP; + } + + ret = qcrypto_block_amend_options(s->crypto, + qcow2_crypto_hdr_read_func, + qcow2_crypto_hdr_write_func, + bs, + qopts->encrypt, + force, + errp); + } + return ret; +} + /* * If offset or size are negative, respectively, they will not be included in * the BLOCK_IMAGE_CORRUPTED event emitted. @@ -5813,6 +5851,7 @@ BlockDriver bdrv_qcow2 = { .mutable_opts = mutable_opts, .bdrv_co_check = qcow2_co_check, .bdrv_amend_options = qcow2_amend_options, + .bdrv_co_amend = qcow2_co_amend, .bdrv_detach_aio_context = qcow2_detach_aio_context, .bdrv_attach_aio_context = qcow2_attach_aio_context, diff --git a/qapi/block-core.json b/qapi/block-core.json index cd679ad435..b20332e592 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4686,6 +4686,19 @@ 'data': { } } +## +# @BlockdevAmendOptionsQcow2: +# +# Driver specific image amend options for qcow2. +# For now, only encryption options can be amended +# +# @encrypt Encryption options to be amended +# +# Since: 5.1 +## +{ 'struct': 'BlockdevAmendOptionsQcow2', + 'data': { '*encrypt': 'QCryptoBlockAmendOptions' } } + ## # @BlockdevAmendOptions: # @@ -4700,7 +4713,8 @@ 'driver': 'BlockdevDriver' }, 'discriminator': 'driver', 'data': { - 'luks': 'BlockdevAmendOptionsLUKS' } } + 'luks': 'BlockdevAmendOptionsLUKS', + 'qcow2': 'BlockdevAmendOptionsQcow2' } } ## # @x-blockdev-amend: From a2cd85f6acc3c3a6cfc1abd8ac732aa7cfd5e9ef Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 25 Jun 2020 14:55:48 +0200 Subject: [PATCH 1970/2595] iotests: add tests for blockdev-amend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds two tests that cover the new blockdev-amend functionality of luks and qcow2 driver Signed-off-by: Maxim Levitsky Reviewed-by: Daniel P. Berrangé [mreitz: Let 295 verify that LUKS works; drop 295 and 296 from the auto group] Signed-off-by: Max Reitz Message-Id: <20200625125548.870061-20-mreitz@redhat.com> --- tests/qemu-iotests/295 | 280 +++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/295.out | 40 ++++++ tests/qemu-iotests/296 | 234 +++++++++++++++++++++++++++++++ tests/qemu-iotests/296.out | 33 +++++ tests/qemu-iotests/group | 2 + 5 files changed, 589 insertions(+) create mode 100755 tests/qemu-iotests/295 create mode 100644 tests/qemu-iotests/295.out create mode 100755 tests/qemu-iotests/296 create mode 100644 tests/qemu-iotests/296.out diff --git a/tests/qemu-iotests/295 b/tests/qemu-iotests/295 new file mode 100755 index 0000000000..59e674fa85 --- /dev/null +++ b/tests/qemu-iotests/295 @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 +# +# Test case QMP's encrypted key management +# +# 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 . +# + +import iotests +import os +import time +import json + +test_img = os.path.join(iotests.test_dir, 'test.img') + +class Secret: + def __init__(self, index): + self._id = "keysec" + str(index) + # you are not supposed to see the password... + self._secret = "hunter" + str(index) + + def id(self): + return self._id + + def secret(self): + return self._secret + + def to_cmdline_object(self): + return [ "secret,id=" + self._id + ",data=" + self._secret] + + def to_qmp_object(self): + return { "qom_type" : "secret", "id": self.id(), + "props": { "data": self.secret() } } + +################################################################################ +class EncryptionSetupTestCase(iotests.QMPTestCase): + + # test case startup + def setUp(self): + # start the VM + self.vm = iotests.VM() + self.vm.launch() + + # create the secrets and load 'em into the VM + self.secrets = [ Secret(i) for i in range(0, 6) ] + for secret in self.secrets: + result = self.vm.qmp("object-add", **secret.to_qmp_object()) + self.assert_qmp(result, 'return', {}) + + if iotests.imgfmt == "qcow2": + self.pfx = "encrypt." + self.img_opts = [ '-o', "encrypt.format=luks" ] + else: + self.pfx = "" + self.img_opts = [] + + # test case shutdown + def tearDown(self): + # stop the VM + self.vm.shutdown() + + ########################################################################### + # create the encrypted block device + def createImg(self, file, secret): + + iotests.qemu_img( + 'create', + '--object', *secret.to_cmdline_object(), + '-f', iotests.imgfmt, + '-o', self.pfx + 'key-secret=' + secret.id(), + '-o', self.pfx + 'iter-time=10', + *self.img_opts, + file, + '1M') + + ########################################################################### + # open an encrypted block device + def openImageQmp(self, id, file, secret, read_only = False): + + encrypt_options = { + 'key-secret' : secret.id() + } + + if iotests.imgfmt == "qcow2": + encrypt_options = { + 'encrypt': { + 'format':'luks', + **encrypt_options + } + } + + result = self.vm.qmp('blockdev-add', ** + { + 'driver': iotests.imgfmt, + 'node-name': id, + 'read-only': read_only, + + **encrypt_options, + + 'file': { + 'driver': 'file', + 'filename': test_img, + } + } + ) + self.assert_qmp(result, 'return', {}) + + # close the encrypted block device + def closeImageQmp(self, id): + result = self.vm.qmp('blockdev-del', **{ 'node-name': id }) + self.assert_qmp(result, 'return', {}) + + ########################################################################### + # add a key to an encrypted block device + def addKeyQmp(self, id, new_secret, secret = None, + slot = None, force = False): + + crypt_options = { + 'state' : 'active', + 'new-secret' : new_secret.id(), + 'iter-time' : 10 + } + + if slot != None: + crypt_options['keyslot'] = slot + + + if secret != None: + crypt_options['secret'] = secret.id() + + if iotests.imgfmt == "qcow2": + crypt_options['format'] = 'luks' + crypt_options = { + 'encrypt': crypt_options + } + + args = { + 'node-name': id, + 'job-id' : 'job_add_key', + 'options' : { + 'driver' : iotests.imgfmt, + **crypt_options + }, + } + + if force == True: + args['force'] = True + + #TODO: check what jobs return + result = self.vm.qmp('x-blockdev-amend', **args) + assert result['return'] == {} + self.vm.run_job('job_add_key') + + # erase a key from an encrypted block device + def eraseKeyQmp(self, id, old_secret = None, slot = None, force = False): + + crypt_options = { + 'state' : 'inactive', + } + + if slot != None: + crypt_options['keyslot'] = slot + if old_secret != None: + crypt_options['old-secret'] = old_secret.id() + + if iotests.imgfmt == "qcow2": + crypt_options['format'] = 'luks' + crypt_options = { + 'encrypt': crypt_options + } + + args = { + 'node-name': id, + 'job-id' : 'job_erase_key', + 'options' : { + 'driver' : iotests.imgfmt, + **crypt_options + }, + } + + if force == True: + args['force'] = True + + result = self.vm.qmp('x-blockdev-amend', **args) + assert result['return'] == {} + self.vm.run_job('job_erase_key') + + ########################################################################### + # create image, and change its key + def testChangeKey(self): + + # create the image with secret0 and open it + self.createImg(test_img, self.secrets[0]); + self.openImageQmp("testdev", test_img, self.secrets[0]) + + # add key to slot 1 + self.addKeyQmp("testdev", new_secret = self.secrets[1]) + + # add key to slot 5 + self.addKeyQmp("testdev", new_secret = self.secrets[2], slot=5) + + # erase key from slot 0 + self.eraseKeyQmp("testdev", old_secret = self.secrets[0]) + + #reopen the image with secret1 + self.closeImageQmp("testdev") + self.openImageQmp("testdev", test_img, self.secrets[1]) + + # close and erase the image for good + self.closeImageQmp("testdev") + os.remove(test_img) + + # test that if we erase the old password, + # we can still change the encryption keys using 'old-secret' + def testOldPassword(self): + + # create the image with secret0 and open it + self.createImg(test_img, self.secrets[0]); + self.openImageQmp("testdev", test_img, self.secrets[0]) + + # add key to slot 1 + self.addKeyQmp("testdev", new_secret = self.secrets[1]) + + # erase key from slot 0 + self.eraseKeyQmp("testdev", old_secret = self.secrets[0]) + + # this will fail as the old password is no longer valid + self.addKeyQmp("testdev", new_secret = self.secrets[2]) + + # this will work + self.addKeyQmp("testdev", new_secret = self.secrets[2], secret = self.secrets[1]) + + # close and erase the image for good + self.closeImageQmp("testdev") + os.remove(test_img) + + def testUseForceLuke(self): + + self.createImg(test_img, self.secrets[0]); + self.openImageQmp("testdev", test_img, self.secrets[0]) + + # Add bunch of secrets + self.addKeyQmp("testdev", new_secret = self.secrets[1], slot=4) + self.addKeyQmp("testdev", new_secret = self.secrets[4], slot=2) + + # overwrite an active secret + self.addKeyQmp("testdev", new_secret = self.secrets[5], slot=2) + self.addKeyQmp("testdev", new_secret = self.secrets[5], slot=2, force=True) + + self.addKeyQmp("testdev", new_secret = self.secrets[0]) + + # Now erase all the secrets + self.eraseKeyQmp("testdev", old_secret = self.secrets[5]) + self.eraseKeyQmp("testdev", slot=4) + + # erase last keyslot + self.eraseKeyQmp("testdev", old_secret = self.secrets[0]) + self.eraseKeyQmp("testdev", old_secret = self.secrets[0], force=True) + + self.closeImageQmp("testdev") + os.remove(test_img) + + +if __name__ == '__main__': + iotests.verify_working_luks() + # Encrypted formats support + iotests.activate_logging() + iotests.main(supported_fmts = ['qcow2', 'luks']) diff --git a/tests/qemu-iotests/295.out b/tests/qemu-iotests/295.out new file mode 100644 index 0000000000..ad34b2ca2c --- /dev/null +++ b/tests/qemu-iotests/295.out @@ -0,0 +1,40 @@ +{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}} +{"return": {}} +Job failed: Invalid password, cannot unlock any keyslot +{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +{"return": {}} +Job failed: Refusing to overwrite active keyslot 2 - please erase it first +{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}} +{"return": {}} +Job failed: All the active keyslots match the (old) password that was given and erasing them will erase all the data in the image irreversibly - refusing operation +{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}} +{"return": {}} +... +---------------------------------------------------------------------- +Ran 3 tests + +OK diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296 new file mode 100755 index 0000000000..ec69ec8974 --- /dev/null +++ b/tests/qemu-iotests/296 @@ -0,0 +1,234 @@ +#!/usr/bin/env python3 +# +# Test case for encryption key management versus image sharing +# +# 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 . +# + +import iotests +import os +import time +import json + +test_img = os.path.join(iotests.test_dir, 'test.img') + +class Secret: + def __init__(self, index): + self._id = "keysec" + str(index) + # you are not supposed to see the password... + self._secret = "hunter" + str(index) + + def id(self): + return self._id + + def secret(self): + return self._secret + + def to_cmdline_object(self): + return [ "secret,id=" + self._id + ",data=" + self._secret] + + def to_qmp_object(self): + return { "qom_type" : "secret", "id": self.id(), + "props": { "data": self.secret() } } + +################################################################################ + +class EncryptionSetupTestCase(iotests.QMPTestCase): + + # test case startup + def setUp(self): + + # start the VMs + self.vm1 = iotests.VM(path_suffix = 'VM1') + self.vm2 = iotests.VM(path_suffix = 'VM2') + self.vm1.launch() + self.vm2.launch() + + # create the secrets and load 'em into the VMs + self.secrets = [ Secret(i) for i in range(0, 4) ] + for secret in self.secrets: + result = self.vm1.qmp("object-add", **secret.to_qmp_object()) + self.assert_qmp(result, 'return', {}) + result = self.vm2.qmp("object-add", **secret.to_qmp_object()) + self.assert_qmp(result, 'return', {}) + + # test case shutdown + def tearDown(self): + # stop the VM + self.vm1.shutdown() + self.vm2.shutdown() + + ########################################################################### + # create the encrypted block device using qemu-img + def createImg(self, file, secret): + + output = iotests.qemu_img_pipe( + 'create', + '--object', *secret.to_cmdline_object(), + '-f', iotests.imgfmt, + '-o', 'key-secret=' + secret.id(), + '-o', 'iter-time=10', + file, + '1M') + + iotests.log(output, filters=[iotests.filter_test_dir]) + + # attempts to add a key using qemu-img + def addKey(self, file, secret, new_secret): + + image_options = { + 'key-secret' : secret.id(), + 'driver' : iotests.imgfmt, + 'file' : { + 'driver':'file', + 'filename': file, + } + } + + output = iotests.qemu_img_pipe( + 'amend', + '--object', *secret.to_cmdline_object(), + '--object', *new_secret.to_cmdline_object(), + + '-o', 'state=active', + '-o', 'new-secret=' + new_secret.id(), + '-o', 'iter-time=10', + + "json:" + json.dumps(image_options) + ) + + iotests.log(output, filters=[iotests.filter_test_dir]) + + ########################################################################### + # open an encrypted block device + def openImageQmp(self, vm, id, file, secret, + readOnly = False, reOpen = False): + + command = 'x-blockdev-reopen' if reOpen else 'blockdev-add' + + result = vm.qmp(command, ** + { + 'driver': iotests.imgfmt, + 'node-name': id, + 'read-only': readOnly, + 'key-secret' : secret.id(), + 'file': { + 'driver': 'file', + 'filename': test_img, + } + } + ) + self.assert_qmp(result, 'return', {}) + + # close the encrypted block device + def closeImageQmp(self, vm, id): + result = vm.qmp('blockdev-del', **{ 'node-name': id }) + self.assert_qmp(result, 'return', {}) + + ########################################################################### + + # add a key to an encrypted block device + def addKeyQmp(self, vm, id, new_secret): + + args = { + 'node-name': id, + 'job-id' : 'job0', + 'options' : { + 'state' : 'active', + 'driver' : iotests.imgfmt, + 'new-secret': new_secret.id(), + 'iter-time' : 10 + }, + } + + result = vm.qmp('x-blockdev-amend', **args) + assert result['return'] == {} + vm.run_job('job0') + + # test that when the image opened by two qemu processes, + # neither of them can update the image + def test1(self): + self.createImg(test_img, self.secrets[0]); + + # VM1 opens the image and adds a key + self.openImageQmp(self.vm1, "testdev", test_img, self.secrets[0]) + self.addKeyQmp(self.vm1, "testdev", new_secret = self.secrets[1]) + + + # VM2 opens the image + self.openImageQmp(self.vm2, "testdev", test_img, self.secrets[0]) + + + # neither VMs now should be able to add a key + self.addKeyQmp(self.vm1, "testdev", new_secret = self.secrets[2]) + self.addKeyQmp(self.vm2, "testdev", new_secret = self.secrets[2]) + + + # VM 1 closes the image + self.closeImageQmp(self.vm1, "testdev") + + + # now VM2 can add the key + self.addKeyQmp(self.vm2, "testdev", new_secret = self.secrets[2]) + + + # qemu-img should also not be able to add a key + self.addKey(test_img, self.secrets[0], self.secrets[2]) + + # cleanup + self.closeImageQmp(self.vm2, "testdev") + os.remove(test_img) + + + def test2(self): + self.createImg(test_img, self.secrets[0]); + + # VM1 opens the image readonly + self.openImageQmp(self.vm1, "testdev", test_img, self.secrets[0], + readOnly = True) + + # VM2 opens the image + self.openImageQmp(self.vm2, "testdev", test_img, self.secrets[0]) + + # VM1 can't add a key since image is readonly + self.addKeyQmp(self.vm1, "testdev", new_secret = self.secrets[2]) + + # VM2 can't add a key since VM is has the image opened + self.addKeyQmp(self.vm2, "testdev", new_secret = self.secrets[2]) + + + #VM1 reopens the image read-write + self.openImageQmp(self.vm1, "testdev", test_img, self.secrets[0], + reOpen = True, readOnly = False) + + # VM1 still can't add the key + self.addKeyQmp(self.vm1, "testdev", new_secret = self.secrets[2]) + + # VM2 gets away + self.closeImageQmp(self.vm2, "testdev") + + # VM1 now can add the key + self.addKeyQmp(self.vm1, "testdev", new_secret = self.secrets[2]) + + self.closeImageQmp(self.vm1, "testdev") + os.remove(test_img) + + +if __name__ == '__main__': + # support only raw luks since luks encrypted qcow2 is a proper + # format driver which doesn't allow any sharing + iotests.activate_logging() + iotests.main(supported_fmts = ['luks']) diff --git a/tests/qemu-iotests/296.out b/tests/qemu-iotests/296.out new file mode 100644 index 0000000000..afb6d2d09d --- /dev/null +++ b/tests/qemu-iotests/296.out @@ -0,0 +1,33 @@ +Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10 + +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} +Job failed: Failed to get shared "consistent read" lock +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} +Job failed: Failed to get shared "consistent read" lock +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} +qemu-img: Failed to get shared "consistent read" lock +Is another process using the image [TEST_DIR/test.img]? + +Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10 + +Job failed: Block node is read-only +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} +Job failed: Failed to get shared "consistent read" lock +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} +Job failed: Failed to get shared "consistent read" lock +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} +.. +---------------------------------------------------------------------- +Ran 2 tests + +OK diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index b945dd4f20..9b07a7ed03 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -303,4 +303,6 @@ 292 rw auto quick 293 rw 294 rw quick +295 rw +296 rw 297 meta From 2253d86eb45e039dfdeb4bad0f18bd8d5639e1a3 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 May 2020 12:43:56 +0300 Subject: [PATCH 1971/2595] qemu-img: convert: don't use unallocated_blocks_are_zero qemu-img convert wants to distinguish ZERO which comes from short backing files. unallocated_blocks_are_zero field of bdi is unrelated: space after EOF is always considered to be zero anyway. So, just make post_backing_zero true in case of short backing file. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200528094405.145708-2-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- qemu-img.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 7f4938a5ef..53bd32bf8f 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1681,7 +1681,6 @@ typedef struct ImgConvertState { BlockBackend *target; bool has_zero_init; bool compressed; - bool unallocated_blocks_are_zero; bool target_is_new; bool target_has_backing; int64_t target_backing_sectors; /* negative if unknown */ @@ -1726,7 +1725,7 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) if (s->target_backing_sectors >= 0) { if (sector_num >= s->target_backing_sectors) { - post_backing_zero = s->unallocated_blocks_are_zero; + post_backing_zero = true; } else if (sector_num + n > s->target_backing_sectors) { /* Split requests around target_backing_sectors (because * starting from there, zeros are handled differently) */ @@ -2678,7 +2677,6 @@ static int img_convert(int argc, char **argv) } else { s.compressed = s.compressed || bdi.needs_compressed_writes; s.cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE; - s.unallocated_blocks_are_zero = bdi.unallocated_blocks_are_zero; } ret = convert_do_copy(&s); From 7b1efe996c5becfbc7c242164a52ec2779bbd431 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 May 2020 12:43:57 +0300 Subject: [PATCH 1972/2595] block: inline bdrv_unallocated_blocks_are_zero() The function has only one user: bdrv_co_block_status(). Inline it to simplify reviewing of the following patches, which will finally drop unallocated_blocks_are_zero field too. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200528094405.145708-3-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block.c | 15 --------------- block/io.c | 11 ++++++++--- include/block/block.h | 1 - 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/block.c b/block.c index 144f52e413..62e40db2f1 100644 --- a/block.c +++ b/block.c @@ -5408,21 +5408,6 @@ int bdrv_has_zero_init(BlockDriverState *bs) return 0; } -bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs) -{ - BlockDriverInfo bdi; - - if (bs->backing) { - return false; - } - - if (bdrv_get_info(bs, &bdi) == 0) { - return bdi.unallocated_blocks_are_zero; - } - - return false; -} - bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs) { if (!(bs->open_flags & BDRV_O_UNMAP)) { diff --git a/block/io.c b/block/io.c index df8f2a98d4..36d4d562a6 100644 --- a/block/io.c +++ b/block/io.c @@ -2407,15 +2407,20 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs, if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) { ret |= BDRV_BLOCK_ALLOCATED; } else if (want_zero) { - if (bdrv_unallocated_blocks_are_zero(bs)) { - ret |= BDRV_BLOCK_ZERO; - } else if (bs->backing) { + if (bs->backing) { BlockDriverState *bs2 = bs->backing->bs; int64_t size2 = bdrv_getlength(bs2); if (size2 >= 0 && offset >= size2) { ret |= BDRV_BLOCK_ZERO; } + } else { + BlockDriverInfo bdi; + int ret2 = bdrv_get_info(bs, &bdi); + + if (ret2 == 0 && bdi.unallocated_blocks_are_zero) { + ret |= BDRV_BLOCK_ZERO; + } } } diff --git a/include/block/block.h b/include/block/block.h index a2414a58c5..e7934e07f2 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -489,7 +489,6 @@ int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes); int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes); int bdrv_has_zero_init_1(BlockDriverState *bs); int bdrv_has_zero_init(BlockDriverState *bs); -bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs); bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, From 2ea0332f427e3c6582a6c82130814c0d4c9ceb40 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 May 2020 12:43:58 +0300 Subject: [PATCH 1973/2595] block/vdi: return ZERO block-status when appropriate In case of !VDI_IS_ALLOCATED[], we do zero out the corresponding chunk of qiov. So, this should be reported as ZERO. Note that this changes visible output of "qemu-img map --output=json" and "qemu-io -c map" commands. For qemu-img map, the change is obvious: we just mark as zero what is really zero. For qemu-io it's less obvious: what was unallocated now is allocated. There is an inconsistency in understanding of unallocated regions in Qemu: backing-supporting format-drivers return 0 block-status to report go-to-backing logic for this area. Some protocol-drivers (iscsi) return 0 to report fs-unallocated-non-zero status (i.e., don't occupy space on disk, read result is undefined). BDRV_BLOCK_ALLOCATED is defined as something more close to go-to-backing logic. Still it is calculated as ZERO | DATA, so 0 from iscsi is treated as unallocated. It doesn't influence backing-chain behavior, as iscsi can't have backing file. But it does influence "qemu-io -c map". We should solve this inconsistency at some future point. Now, let's just make backing-not-supporting format drivers (vdi at this patch and vpc with the following) to behave more like backing-supporting drivers and not report 0 block-status. More over, returning ZERO status is absolutely valid thing, and again, corresponds to how the other format-drivers (backing-supporting) work. After block-status update, it never reports 0, so setting unallocated_blocks_are_zero doesn't make sense (as the only user of it is bdrv_co_block_status and it checks unallocated_blocks_are_zero only for unallocated areas). Drop it. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200528094405.145708-4-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/vdi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/block/vdi.c b/block/vdi.c index 2f506a01ba..c4527a9d8c 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -334,7 +334,6 @@ static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) logout("\n"); bdi->cluster_size = s->block_size; bdi->vm_state_offset = 0; - bdi->unallocated_blocks_are_zero = true; return 0; } @@ -536,7 +535,7 @@ static int coroutine_fn vdi_co_block_status(BlockDriverState *bs, *pnum = MIN(s->block_size - index_in_block, bytes); result = VDI_IS_ALLOCATED(bmap_entry); if (!result) { - return 0; + return BDRV_BLOCK_ZERO; } *map = s->header.offset_data + (uint64_t)bmap_entry * s->block_size + From c7aab58ba0baaf82422b7f7b0d7ad63b0db8d166 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 11 Jun 2020 07:58:07 +0200 Subject: [PATCH 1974/2595] hw/m68k/mcf5206: Replace remaining hw_error()s by qemu_log_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw_error() dumps the CPU state and exits QEMU. This is ok during initial code development (to see where the guest code is currently executing), but it is certainly not the desired behavior that we want to present to normal users, and it can also cause trouble when e.g. fuzzing devices. Thus let's replace these hw_error()s by qemu_log_mask()s instead. Message-Id: <20200611055807.15921-1-huth@tuxfamily.org> Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- hw/m68k/mcf5206.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c index a2fef04f8e..94a37a1a46 100644 --- a/hw/m68k/mcf5206.c +++ b/hw/m68k/mcf5206.c @@ -10,7 +10,6 @@ #include "qemu/error-report.h" #include "qemu/log.h" #include "cpu.h" -#include "hw/hw.h" #include "hw/irq.h" #include "hw/m68k/mcf.h" #include "qemu/timer.h" @@ -69,10 +68,16 @@ static void m5206_timer_recalibrate(m5206_timer_state *s) if (mode == 2) prescale *= 16; - if (mode == 3 || mode == 0) - hw_error("m5206_timer: mode %d not implemented\n", mode); - if ((s->tmr & TMR_FRR) == 0) - hw_error("m5206_timer: free running mode not implemented\n"); + if (mode == 3 || mode == 0) { + qemu_log_mask(LOG_UNIMP, "m5206_timer: mode %d not implemented\n", + mode); + goto exit; + } + if ((s->tmr & TMR_FRR) == 0) { + qemu_log_mask(LOG_UNIMP, + "m5206_timer: free running mode not implemented\n"); + goto exit; + } /* Assume 66MHz system clock. */ ptimer_set_freq(s->timer, 66000000 / prescale); @@ -391,7 +396,9 @@ static uint32_t m5206_mbar_readb(void *opaque, hwaddr offset) m5206_mbar_state *s = (m5206_mbar_state *)opaque; offset &= 0x3ff; if (offset >= 0x200) { - hw_error("Bad MBAR read offset 0x%x", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR read offset 0x%" HWADDR_PRIX, + offset); + return 0; } if (m5206_mbar_width[offset >> 2] > 1) { uint16_t val; @@ -410,7 +417,9 @@ static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset) int width; offset &= 0x3ff; if (offset >= 0x200) { - hw_error("Bad MBAR read offset 0x%x", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR read offset 0x%" HWADDR_PRIX, + offset); + return 0; } width = m5206_mbar_width[offset >> 2]; if (width > 2) { @@ -434,7 +443,9 @@ static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset) int width; offset &= 0x3ff; if (offset >= 0x200) { - hw_error("Bad MBAR read offset 0x%x", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR read offset 0x%" HWADDR_PRIX, + offset); + return 0; } width = m5206_mbar_width[offset >> 2]; if (width < 4) { @@ -458,7 +469,9 @@ static void m5206_mbar_writeb(void *opaque, hwaddr offset, int width; offset &= 0x3ff; if (offset >= 0x200) { - hw_error("Bad MBAR write offset 0x%x", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR write offset 0x%" HWADDR_PRIX, + offset); + return; } width = m5206_mbar_width[offset >> 2]; if (width > 1) { @@ -482,7 +495,9 @@ static void m5206_mbar_writew(void *opaque, hwaddr offset, int width; offset &= 0x3ff; if (offset >= 0x200) { - hw_error("Bad MBAR write offset 0x%x", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR write offset 0x%" HWADDR_PRIX, + offset); + return; } width = m5206_mbar_width[offset >> 2]; if (width > 2) { @@ -510,7 +525,9 @@ static void m5206_mbar_writel(void *opaque, hwaddr offset, int width; offset &= 0x3ff; if (offset >= 0x200) { - hw_error("Bad MBAR write offset 0x%x", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR write offset 0x%" HWADDR_PRIX, + offset); + return; } width = m5206_mbar_width[offset >> 2]; if (width < 4) { From 8c4329214f1d4484205e6f7c48e98ff26969eb56 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 2 Jul 2020 16:03:16 +0200 Subject: [PATCH 1975/2595] tests/acceptance: Add a test for the sun4u sparc64 machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can use the image from the advent calendar 2018 to test the sun4u machine. It's not using the "QEMU advent calendar" string, so we can not use the do_test_advcal_2018() from boot_linux_console.py, thus let's also put it into a separate file to also be able to add an entry to the MAINTAINERS file. Message-Id: <20200704173519.26087-1-thuth@redhat.com> Tested-by: Mark Cave-Ayland Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- MAINTAINERS | 1 + tests/acceptance/machine_sparc64_sun4u.py | 36 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/acceptance/machine_sparc64_sun4u.py diff --git a/MAINTAINERS b/MAINTAINERS index c31c878c63..a8e2d46e9d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1319,6 +1319,7 @@ F: include/hw/pci-host/sabre.h F: hw/pci-bridge/simba.c F: include/hw/pci-bridge/simba.h F: pc-bios/openbios-sparc64 +F: tests/acceptance/machine_sparc64_sun4u.py Sun4v M: Artyom Tarasenko diff --git a/tests/acceptance/machine_sparc64_sun4u.py b/tests/acceptance/machine_sparc64_sun4u.py new file mode 100644 index 0000000000..458165500e --- /dev/null +++ b/tests/acceptance/machine_sparc64_sun4u.py @@ -0,0 +1,36 @@ +# Functional test that boots a Linux kernel and checks the console +# +# Copyright (c) 2020 Red Hat, Inc. +# +# Author: +# Thomas Huth +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +import os + +from avocado_qemu import wait_for_console_pattern +from avocado.utils import archive +from boot_linux_console import LinuxKernelTest + +class Sun4uMachine(LinuxKernelTest): + """Boots the Linux kernel and checks that the console is operational""" + + timeout = 90 + + def test_sparc64_sun4u(self): + """ + :avocado: tags=arch:sparc64 + :avocado: tags=machine:sun4u + """ + tar_url = ('https://www.qemu-advent-calendar.org' + '/2018/download/day23.tar.xz') + tar_hash = '142db83cd974ffadc4f75c8a5cad5bcc5722c240' + file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + archive.extract(file_path, self.workdir) + self.vm.set_console() + self.vm.add_args('-kernel', self.workdir + '/day23/vmlinux', + '-append', self.KERNEL_COMMON_COMMAND_LINE) + self.vm.launch() + wait_for_console_pattern(self, 'Starting logging: OK') From 2c060c0f50220bebabacccb8e321df049cca602e Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 May 2020 12:43:59 +0300 Subject: [PATCH 1976/2595] block/vpc: return ZERO block-status when appropriate In case when get_image_offset() returns -1, we do zero out the corresponding chunk of qiov. So, this should be reported as ZERO. Note that this changes visible output of "qemu-img map --output=json" and "qemu-io -c map" commands. For qemu-img map, the change is obvious: we just mark as zero what is really zero. For qemu-io it's less obvious: what was unallocated now is allocated. There is an inconsistency in understanding of unallocated regions in Qemu: backing-supporting format-drivers return 0 block-status to report go-to-backing logic for this area. Some protocol-drivers (iscsi) return 0 to report fs-unallocated-non-zero status (i.e., don't occupy space on disk, read result is undefined). BDRV_BLOCK_ALLOCATED is defined as something more close to go-to-backing logic. Still it is calculated as ZERO | DATA, so 0 from iscsi is treated as unallocated. It doesn't influence backing-chain behavior, as iscsi can't have backing file. But it does influence "qemu-io -c map". We should solve this inconsistency at some future point. Now, let's just make backing-not-supporting format drivers (vdi in the previous patch and vpc now) to behave more like backing-supporting drivers and not report 0 block-status. More over, returning ZERO status is absolutely valid thing, and again, corresponds to how the other format-drivers (backing-supporting) work. After block-status update, it never reports 0, so setting unallocated_blocks_are_zero doesn't make sense (as the only user of it is bdrv_co_block_status and it checks unallocated_blocks_are_zero only for unallocated areas). Drop it. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200528094405.145708-5-vsementsov@virtuozzo.com> [mreitz: qemu-io -c map as used by iotest 146 now reports everything as allocated; in order to make the test do something useful, we use qemu-img map --output=json now] Signed-off-by: Max Reitz --- block/vpc.c | 3 +- tests/qemu-iotests/146 | 60 ++++-- tests/qemu-iotests/146.out | 405 +++++++++++++++++++++++++++++++++++-- 3 files changed, 436 insertions(+), 32 deletions(-) diff --git a/block/vpc.c b/block/vpc.c index c055591641..01fcd37e3c 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -606,7 +606,6 @@ static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) bdi->cluster_size = s->block_size; } - bdi->unallocated_blocks_are_zero = true; return 0; } @@ -745,7 +744,7 @@ static int coroutine_fn vpc_co_block_status(BlockDriverState *bs, image_offset = get_image_offset(bs, offset, false, NULL); allocated = (image_offset != -1); *pnum = 0; - ret = 0; + ret = BDRV_BLOCK_ZERO; do { /* All sectors in a block are contiguous (without using the bitmap) */ diff --git a/tests/qemu-iotests/146 b/tests/qemu-iotests/146 index 2e43abddfc..ddc3c1fd80 100755 --- a/tests/qemu-iotests/146 +++ b/tests/qemu-iotests/146 @@ -51,19 +51,25 @@ echo === Testing VPC Autodetect === echo _use_sample_img virtualpc-dynamic.vhd.bz2 -${QEMU_IO} -c "open -o driver=vpc ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo echo === Testing VPC with current_size force === echo -${QEMU_IO} -c "open -o driver=vpc,force_size_calc=current_size ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,force_size_calc=current_size,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo echo === Testing VPC with chs force === echo -${QEMU_IO} -c "open -o driver=vpc,force_size_calc=chs ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,force_size_calc=chs,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map _cleanup_test_img @@ -72,19 +78,25 @@ echo === Testing Hyper-V Autodetect === echo _use_sample_img hyperv2012r2-dynamic.vhd.bz2 -${QEMU_IO} -c "open -o driver=vpc ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo echo === Testing Hyper-V with current_size force === echo -${QEMU_IO} -c "open -o driver=vpc,force_size_calc=current_size ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,force_size_calc=current_size,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo echo === Testing Hyper-V with chs force === echo -${QEMU_IO} -c "open -o driver=vpc,force_size_calc=chs ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,force_size_calc=chs,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map _cleanup_test_img @@ -93,19 +105,25 @@ echo === Testing d2v Autodetect === echo _use_sample_img d2v-zerofilled.vhd.bz2 -${QEMU_IO} -c "open -o driver=vpc ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo echo === Testing d2v with current_size force === echo -${QEMU_IO} -c "open -o driver=vpc,force_size_calc=current_size ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,force_size_calc=current_size,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo echo === Testing d2v with chs force === echo -${QEMU_IO} -c "open -o driver=vpc,force_size_calc=chs ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,force_size_calc=chs,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map _cleanup_test_img @@ -121,19 +139,25 @@ echo echo === Read created image, default opts ==== echo -${QEMU_IO} -c "open -o driver=vpc ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo echo === Read created image, force_size_calc=chs ==== echo -${QEMU_IO} -c "open -o driver=vpc,force_size_calc=chs ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,force_size_calc=chs,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo echo === Read created image, force_size_calc=current_size ==== echo -${QEMU_IO} -c "open -o driver=vpc,force_size_calc=current_size ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,force_size_calc=current_size,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo echo === Testing Image create, force_size === @@ -145,19 +169,25 @@ echo echo === Read created image, default opts ==== echo -${QEMU_IO} -c "open -o driver=vpc ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo echo === Read created image, force_size_calc=chs ==== echo -${QEMU_IO} -c "open -o driver=vpc,force_size_calc=chs ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,force_size_calc=chs,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo echo === Read created image, force_size_calc=current_size ==== echo -${QEMU_IO} -c "open -o driver=vpc,force_size_calc=current_size ${TEST_IMG}" -c 'map' +$QEMU_IMG map --output=json --image-opts \ + "driver=vpc,force_size_calc=current_size,file.filename=$TEST_IMG" \ + | _filter_qemu_img_map echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/146.out b/tests/qemu-iotests/146.out index 1332189d87..80513cdd06 100644 --- a/tests/qemu-iotests/146.out +++ b/tests/qemu-iotests/146.out @@ -2,39 +2,414 @@ QA output created by 146 === Testing VPC Autodetect === -126.998 GiB (0x1fbfe04000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false }] === Testing VPC with current_size force === -127 GiB (0x1fc0000000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false }] === Testing VPC with chs force === -126.998 GiB (0x1fbfe04000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false }] === Testing Hyper-V Autodetect === -127 GiB (0x1fc0000000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false }] === Testing Hyper-V with current_size force === -127 GiB (0x1fc0000000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false }] === Testing Hyper-V with chs force === -126.998 GiB (0x1fbfe04000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false }] === Testing d2v Autodetect === -251.250 MiB (0xfb40000) bytes allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET }] === Testing d2v with current_size force === -251.250 MiB (0xfb40000) bytes allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET }] === Testing d2v with chs force === -251.250 MiB (0xfb40000) bytes allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, +{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET }] === Testing Image create, default === @@ -42,15 +417,15 @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296 === Read created image, default opts ==== -4 GiB (0x10007a000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false }] === Read created image, force_size_calc=chs ==== -4 GiB (0x10007a000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false }] === Read created image, force_size_calc=current_size ==== -4 GiB (0x10007a000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false }] === Testing Image create, force_size === @@ -58,13 +433,13 @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296 === Read created image, default opts ==== -4 GiB (0x100000000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false }] === Read created image, force_size_calc=chs ==== -4 GiB (0x100000000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false }] === Read created image, force_size_calc=current_size ==== -4 GiB (0x100000000) bytes not allocated at offset 0 bytes (0x0) +[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false }] *** done From 74036395ea4a67a638c0ffc35ee4860ac36bcd16 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 May 2020 12:44:00 +0300 Subject: [PATCH 1977/2595] block/crypto: drop unallocated_blocks_are_zero It's false by default, no needs to set it. We are going to drop this variable at all, so drop it now here, it doesn't hurt. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200528094405.145708-6-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/crypto.c | 1 - 1 file changed, 1 deletion(-) diff --git a/block/crypto.c b/block/crypto.c index 3fbd68832b..2636e959ae 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -758,7 +758,6 @@ static int block_crypto_get_info_luks(BlockDriverState *bs, return ret; } - bdi->unallocated_blocks_are_zero = false; bdi->cluster_size = subbdi.cluster_size; return 0; From 32d293c8c668d4e0d19594d8af359627dd7260f9 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 May 2020 12:44:01 +0300 Subject: [PATCH 1978/2595] block/iscsi: drop unallocated_blocks_are_zero We set bdi->unallocated_blocks_are_zero = iscsilun->lbprz, but iscsi_co_block_status doesn't return 0 in case of iscsilun->lbprz, it returns ZERO when appropriate. So actually unallocated_blocks_are_zero is useless (it doesn't affect the only user of the field: bdrv_co_block_status()). Drop it now. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200528094405.145708-7-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/iscsi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/block/iscsi.c b/block/iscsi.c index a8b76979d8..767e3e75fd 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2163,7 +2163,6 @@ static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset, static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { IscsiLun *iscsilun = bs->opaque; - bdi->unallocated_blocks_are_zero = iscsilun->lbprz; bdi->cluster_size = iscsilun->cluster_size; return 0; } From ac9185603e5baaab6c53e4e98eefce31f047121c Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 May 2020 12:44:02 +0300 Subject: [PATCH 1979/2595] block/file-posix: drop unallocated_blocks_are_zero raw_co_block_status() in block/file-posix.c never returns 0, so unallocated_blocks_are_zero is useless (it doesn't affect the only user of the field: bdrv_co_block_status()). Drop it. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200528094405.145708-8-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/file-posix.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index 3ab8f5a0fa..d86ea57769 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -2878,9 +2878,6 @@ static int coroutine_fn raw_co_pwrite_zeroes( static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { - BDRVRawState *s = bs->opaque; - - bdi->unallocated_blocks_are_zero = s->discard_zeroes; return 0; } From cdf9ebf18f32f4b29f99af58e154a9afe93bbc92 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 May 2020 12:44:03 +0300 Subject: [PATCH 1980/2595] block/vhdx: drop unallocated_blocks_are_zero vhdx doesn't have .bdrv_co_block_status handler, so DATA|ALLOCATED is always assumed for it in bdrv_co_block_status(). unallocated_blocks_are_zero is useless (it doesn't affect the only user of the field: bdrv_co_block_status()), drop it. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200528094405.145708-9-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/vhdx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/block/vhdx.c b/block/vhdx.c index fa9e544a5e..645dc4b4f4 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1164,9 +1164,6 @@ static int vhdx_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) bdi->cluster_size = s->block_size; - bdi->unallocated_blocks_are_zero = - (s->params.data_bits & VHDX_PARAMS_HAS_PARENT) == 0; - return 0; } From a2adbbf603cee443ca923f6e8546267a706567d5 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 May 2020 12:44:04 +0300 Subject: [PATCH 1981/2595] block: drop unallocated_blocks_are_zero Currently this field only set by qed and qcow2. But in fact, all backing-supporting formats (parallels, qcow, qcow2, qed, vmdk) share these semantics: on unallocated blocks, if there is no backing file they just memset the buffer with zeroes. So, document this behavior for .supports_backing and drop .unallocated_blocks_are_zero Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200528094405.145708-10-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/io.c | 9 ++------- block/qcow2.c | 1 - block/qed.c | 1 - include/block/block.h | 5 ----- include/block/block_int.h | 12 +++++++++++- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/block/io.c b/block/io.c index 36d4d562a6..b6564e34c5 100644 --- a/block/io.c +++ b/block/io.c @@ -2406,7 +2406,7 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs, if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) { ret |= BDRV_BLOCK_ALLOCATED; - } else if (want_zero) { + } else if (want_zero && bs->drv->supports_backing) { if (bs->backing) { BlockDriverState *bs2 = bs->backing->bs; int64_t size2 = bdrv_getlength(bs2); @@ -2415,12 +2415,7 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs, ret |= BDRV_BLOCK_ZERO; } } else { - BlockDriverInfo bdi; - int ret2 = bdrv_get_info(bs, &bdi); - - if (ret2 == 0 && bdi.unallocated_blocks_are_zero) { - ret |= BDRV_BLOCK_ZERO; - } + ret |= BDRV_BLOCK_ZERO; } } diff --git a/block/qcow2.c b/block/qcow2.c index 30f073cf2a..38198b4e75 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -4987,7 +4987,6 @@ err: static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVQcow2State *s = bs->opaque; - bdi->unallocated_blocks_are_zero = true; bdi->cluster_size = s->cluster_size; bdi->vm_state_offset = qcow2_vm_state_offset(s); return 0; diff --git a/block/qed.c b/block/qed.c index c0c65015c7..a2dd952699 100644 --- a/block/qed.c +++ b/block/qed.c @@ -1514,7 +1514,6 @@ static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) memset(bdi, 0, sizeof(*bdi)); bdi->cluster_size = s->header.cluster_size; bdi->is_dirty = s->header.features & QED_F_NEED_CHECK; - bdi->unallocated_blocks_are_zero = true; return 0; } diff --git a/include/block/block.h b/include/block/block.h index e7934e07f2..bca3bb831c 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -21,11 +21,6 @@ typedef struct BlockDriverInfo { /* offset at which the VM state can be saved (0 if not possible) */ int64_t vm_state_offset; bool is_dirty; - /* - * True if unallocated blocks read back as zeroes. This is equivalent - * to the LBPRZ flag in the SCSI logical block provisioning page. - */ - bool unallocated_blocks_are_zero; /* * True if this block driver only supports compressed writes */ diff --git a/include/block/block_int.h b/include/block/block_int.h index 1b86b59af1..3d6cf88592 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -123,7 +123,17 @@ struct BlockDriver { */ bool bdrv_needs_filename; - /* Set if a driver can support backing files */ + /* + * Set if a driver can support backing files. This also implies the + * following semantics: + * + * - Return status 0 of .bdrv_co_block_status means that corresponding + * blocks are not allocated in this layer of backing-chain + * - For such (unallocated) blocks, read will: + * - fill buffer with zeros if there is no backing file + * - read from the backing file otherwise, where the block layer + * takes care of reading zeros beyond EOF if backing file is short + */ bool supports_backing; /* For handling image reopen for split or non-split files */ From 365fed5111b06d31c1632af63c7528dfe49d62a2 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 28 May 2020 12:44:05 +0300 Subject: [PATCH 1982/2595] qed: Simplify backing reads The other four drivers that support backing files (qcow, qcow2, parallels, vmdk) all rely on the block layer to populate zeroes when reading beyond EOF of a short backing file. We can simplify the qed code by doing likewise. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200528094405.145708-11-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/qed.c | 64 +++++------------------------------------------------ block/qed.h | 1 - 2 files changed, 6 insertions(+), 59 deletions(-) diff --git a/block/qed.c b/block/qed.c index a2dd952699..ece8b9bb60 100644 --- a/block/qed.c +++ b/block/qed.c @@ -849,56 +849,18 @@ static BDRVQEDState *acb_to_s(QEDAIOCB *acb) * @s: QED state * @pos: Byte position in device * @qiov: Destination I/O vector - * @backing_qiov: Possibly shortened copy of qiov, to be allocated here - * @cb: Completion function - * @opaque: User data for completion function * * This function reads qiov->size bytes starting at pos from the backing file. * If there is no backing file then zeroes are read. */ static int coroutine_fn qed_read_backing_file(BDRVQEDState *s, uint64_t pos, - QEMUIOVector *qiov, - QEMUIOVector **backing_qiov) + QEMUIOVector *qiov) { - uint64_t backing_length = 0; - size_t size; - int ret; - - /* If there is a backing file, get its length. Treat the absence of a - * backing file like a zero length backing file. - */ if (s->bs->backing) { - int64_t l = bdrv_getlength(s->bs->backing->bs); - if (l < 0) { - return l; - } - backing_length = l; - } - - /* Zero all sectors if reading beyond the end of the backing file */ - if (pos >= backing_length || - pos + qiov->size > backing_length) { - qemu_iovec_memset(qiov, 0, 0, qiov->size); - } - - /* Complete now if there are no backing file sectors to read */ - if (pos >= backing_length) { - return 0; - } - - /* If the read straddles the end of the backing file, shorten it */ - size = MIN((uint64_t)backing_length - pos, qiov->size); - - assert(*backing_qiov == NULL); - *backing_qiov = g_new(QEMUIOVector, 1); - qemu_iovec_init(*backing_qiov, qiov->niov); - qemu_iovec_concat(*backing_qiov, qiov, 0, size); - - BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO); - ret = bdrv_co_preadv(s->bs->backing, pos, size, *backing_qiov, 0); - if (ret < 0) { - return ret; + BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO); + return bdrv_co_preadv(s->bs->backing, pos, qiov->size, qiov, 0); } + qemu_iovec_memset(qiov, 0, 0, qiov->size); return 0; } @@ -915,7 +877,6 @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s, uint64_t offset) { QEMUIOVector qiov; - QEMUIOVector *backing_qiov = NULL; int ret; /* Skip copy entirely if there is no work to do */ @@ -925,13 +886,7 @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s, qemu_iovec_init_buf(&qiov, qemu_blockalign(s->bs, len), len); - ret = qed_read_backing_file(s, pos, &qiov, &backing_qiov); - - if (backing_qiov) { - qemu_iovec_destroy(backing_qiov); - g_free(backing_qiov); - backing_qiov = NULL; - } + ret = qed_read_backing_file(s, pos, &qiov); if (ret) { goto out; @@ -1339,8 +1294,7 @@ static int coroutine_fn qed_aio_read_data(void *opaque, int ret, qemu_iovec_memset(&acb->cur_qiov, 0, 0, acb->cur_qiov.size); r = 0; } else if (ret != QED_CLUSTER_FOUND) { - r = qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov, - &acb->backing_qiov); + r = qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov); } else { BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); r = bdrv_co_preadv(bs->file, offset, acb->cur_qiov.size, @@ -1365,12 +1319,6 @@ static int coroutine_fn qed_aio_next_io(QEDAIOCB *acb) while (1) { trace_qed_aio_next_io(s, acb, 0, acb->cur_pos + acb->cur_qiov.size); - if (acb->backing_qiov) { - qemu_iovec_destroy(acb->backing_qiov); - g_free(acb->backing_qiov); - acb->backing_qiov = NULL; - } - acb->qiov_offset += acb->cur_qiov.size; acb->cur_pos += acb->cur_qiov.size; qemu_iovec_reset(&acb->cur_qiov); diff --git a/block/qed.h b/block/qed.h index 42c115d822..3d12bf78d4 100644 --- a/block/qed.h +++ b/block/qed.h @@ -140,7 +140,6 @@ typedef struct QEDAIOCB { /* Current cluster scatter-gather list */ QEMUIOVector cur_qiov; - QEMUIOVector *backing_qiov; uint64_t cur_pos; /* position on block device, in bytes */ uint64_t cur_cluster; /* cluster offset in image file */ unsigned int cur_nclusters; /* number of clusters being accessed */ From 89aa165e1d66afbfe61056e24fc9fab7452418d7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:06 +0200 Subject: [PATCH 1983/2595] stubs: add isa_create_simple MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for -soundhw cleanup. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 20200702132525.6849-2-kraxel@redhat.com --- stubs/Makefile.objs | 1 + stubs/isa-bus.c | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 stubs/isa-bus.c diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index f32b9e47a3..ff0411d21f 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -8,6 +8,7 @@ stub-obj-y += fdset.o stub-obj-y += gdbstub.o stub-obj-y += iothread-lock.o stub-obj-y += is-daemonized.o +stub-obj-y += isa-bus.o stub-obj-$(CONFIG_LINUX_AIO) += linux-aio.o stub-obj-$(CONFIG_LINUX_IO_URING) += io_uring.o stub-obj-y += monitor-core.o diff --git a/stubs/isa-bus.c b/stubs/isa-bus.c new file mode 100644 index 0000000000..522f448997 --- /dev/null +++ b/stubs/isa-bus.c @@ -0,0 +1,7 @@ +#include "qemu/osdep.h" +#include "hw/isa/isa.h" + +ISADevice *isa_create_simple(ISABus *bus, const char *name) +{ + g_assert_not_reached(); +} From 3af87d91692e12d8abe85a3e8ada5d652c932490 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:07 +0200 Subject: [PATCH 1984/2595] stubs: add pci_create_simple MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for -soundhw cleanup. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 20200702132525.6849-3-kraxel@redhat.com --- stubs/Makefile.objs | 1 + stubs/pci-bus.c | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 stubs/pci-bus.c diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index ff0411d21f..918e46bdc1 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -13,6 +13,7 @@ stub-obj-$(CONFIG_LINUX_AIO) += linux-aio.o stub-obj-$(CONFIG_LINUX_IO_URING) += io_uring.o stub-obj-y += monitor-core.o stub-obj-y += notify-event.o +stub-obj-y += pci-bus.o stub-obj-y += qmp_memory_device.o stub-obj-y += qtest.o stub-obj-y += ramfb.o diff --git a/stubs/pci-bus.c b/stubs/pci-bus.c new file mode 100644 index 0000000000..a8932fa932 --- /dev/null +++ b/stubs/pci-bus.c @@ -0,0 +1,7 @@ +#include "qemu/osdep.h" +#include "hw/pci/pci.h" + +PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) +{ + g_assert_not_reached(); +} From 542e0c557b2cbf6ae5f3be694638d17042388a01 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:08 +0200 Subject: [PATCH 1985/2595] audio: add deprecated_register_soundhw Add helper function for -soundhw deprecation. It can replace the simple init functions which just call {isa,pci}_create_simple() with a hardcoded type. It also prints a deprecation message. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-4-kraxel@redhat.com --- hw/audio/soundhw.c | 24 +++++++++++++++++++++++- include/hw/audio/soundhw.h | 2 ++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c index c750473c8f..173b674ff5 100644 --- a/hw/audio/soundhw.c +++ b/hw/audio/soundhw.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qemu/option.h" #include "qemu/help_option.h" #include "qemu/error-report.h" #include "qom/object.h" @@ -32,6 +33,7 @@ struct soundhw { const char *name; const char *descr; + const char *typename; int enabled; int isa; union { @@ -65,6 +67,17 @@ void pci_register_soundhw(const char *name, const char *descr, soundhw_count++; } +void deprecated_register_soundhw(const char *name, const char *descr, + int isa, const char *typename) +{ + assert(soundhw_count < ARRAY_SIZE(soundhw) - 1); + soundhw[soundhw_count].name = name; + soundhw[soundhw_count].descr = descr; + soundhw[soundhw_count].isa = isa; + soundhw[soundhw_count].typename = typename; + soundhw_count++; +} + void select_soundhw(const char *optarg) { struct soundhw *c; @@ -136,7 +149,16 @@ void soundhw_init(void) for (c = soundhw; c->name; ++c) { if (c->enabled) { - if (c->isa) { + if (c->typename) { + warn_report("'-soundhw %s' is deprecated, " + "please use '-device %s' instead", + c->name, c->typename); + if (c->isa) { + isa_create_simple(isa_bus, c->typename); + } else { + pci_create_simple(pci_bus, -1, c->typename); + } + } else if (c->isa) { if (!isa_bus) { error_report("ISA bus not available for %s", c->name); exit(1); diff --git a/include/hw/audio/soundhw.h b/include/hw/audio/soundhw.h index c8eef82418..f09a297854 100644 --- a/include/hw/audio/soundhw.h +++ b/include/hw/audio/soundhw.h @@ -6,6 +6,8 @@ void isa_register_soundhw(const char *name, const char *descr, void pci_register_soundhw(const char *name, const char *descr, int (*init_pci)(PCIBus *bus)); +void deprecated_register_soundhw(const char *name, const char *descr, + int isa, const char *typename); void soundhw_init(void); void select_soundhw(const char *optarg); From 2957f5ada7514f72032a419d8e3ba380786fca04 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:09 +0200 Subject: [PATCH 1986/2595] audio: deprecate -soundhw ac97 Switch to deprecated_register_soundhw(). Remove the now obsolete init function. Add an alias so both ac97 and AC97 are working with -device. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-5-kraxel@redhat.com --- hw/audio/ac97.c | 9 ++------- qdev-monitor.c | 1 + 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 8a9b9924c4..38522cf0ba 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -1393,12 +1393,6 @@ static void ac97_exit(PCIDevice *dev) AUD_remove_card(&s->card); } -static int ac97_init (PCIBus *bus) -{ - pci_create_simple(bus, -1, TYPE_AC97); - return 0; -} - static Property ac97_properties[] = { DEFINE_AUDIO_PROPERTIES(AC97LinkState, card), DEFINE_PROP_END_OF_LIST (), @@ -1436,7 +1430,8 @@ static const TypeInfo ac97_info = { static void ac97_register_types (void) { type_register_static (&ac97_info); - pci_register_soundhw("ac97", "Intel 82801AA AC97 Audio", ac97_init); + deprecated_register_soundhw("ac97", "Intel 82801AA AC97 Audio", + 0, TYPE_AC97); } type_init (ac97_register_types) diff --git a/qdev-monitor.c b/qdev-monitor.c index 22da107484..105d9792ec 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -53,6 +53,7 @@ typedef struct QDevAlias /* Please keep this table sorted by typename. */ static const QDevAlias qdev_alias_table[] = { + { "AC97", "ac97" }, /* -soundhw name */ { "e1000", "e1000-82540em" }, { "ich9-ahci", "ahci" }, { "lsi53c895a", "lsi" }, From 0e933febfeba7e4fffd6319e42388ba132520461 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:10 +0200 Subject: [PATCH 1987/2595] audio: deprecate -soundhw es1370 Switch to deprecated_register_soundhw(). Remove the now obsolete init function. Add an alias so both es1370 and ES1370 are working with -device. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-6-kraxel@redhat.com --- hw/audio/es1370.c | 9 ++------- qdev-monitor.c | 1 + 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index 5f8a83ff56..4255463a49 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -884,12 +884,6 @@ static void es1370_exit(PCIDevice *dev) AUD_remove_card(&s->card); } -static int es1370_init (PCIBus *bus) -{ - pci_create_simple (bus, -1, TYPE_ES1370); - return 0; -} - static Property es1370_properties[] = { DEFINE_AUDIO_PROPERTIES(ES1370State, card), DEFINE_PROP_END_OF_LIST(), @@ -928,7 +922,8 @@ static const TypeInfo es1370_info = { static void es1370_register_types (void) { type_register_static (&es1370_info); - pci_register_soundhw("es1370", "ENSONIQ AudioPCI ES1370", es1370_init); + deprecated_register_soundhw("es1370", "ENSONIQ AudioPCI ES1370", + 0, TYPE_ES1370); } type_init (es1370_register_types) diff --git a/qdev-monitor.c b/qdev-monitor.c index 105d9792ec..e3083fae39 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -55,6 +55,7 @@ typedef struct QDevAlias static const QDevAlias qdev_alias_table[] = { { "AC97", "ac97" }, /* -soundhw name */ { "e1000", "e1000-82540em" }, + { "ES1370", "es1370" }, /* -soundhw name */ { "ich9-ahci", "ahci" }, { "lsi53c895a", "lsi" }, { "virtio-9p-ccw", "virtio-9p", QEMU_ARCH_S390X }, From 86388a3bfc30e49e439eb700ac6a2d189c110de7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:11 +0200 Subject: [PATCH 1988/2595] audio: deprecate -soundhw adlib Switch to deprecated_register_soundhw(). Remove the now obsolete init function. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-7-kraxel@redhat.com --- hw/audio/adlib.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index 7c3b67dcfb..65dff5b6fc 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -319,16 +319,10 @@ static const TypeInfo adlib_info = { .class_init = adlib_class_initfn, }; -static int Adlib_init (ISABus *bus) -{ - isa_create_simple (bus, TYPE_ADLIB); - return 0; -} - static void adlib_register_types (void) { type_register_static (&adlib_info); - isa_register_soundhw("adlib", ADLIB_DESC, Adlib_init); + deprecated_register_soundhw("adlib", ADLIB_DESC, 1, TYPE_ADLIB); } type_init (adlib_register_types) From 6497a63679dd8e0433acd0325257e49c6525c2a1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:12 +0200 Subject: [PATCH 1989/2595] audio: deprecate -soundhw cs4231a Switch to deprecated_register_soundhw(). Remove the now obsolete init function. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-8-kraxel@redhat.com --- hw/audio/cs4231a.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c index ffdbb58d6a..59705a8d47 100644 --- a/hw/audio/cs4231a.c +++ b/hw/audio/cs4231a.c @@ -683,12 +683,6 @@ static void cs4231a_realizefn (DeviceState *dev, Error **errp) AUD_register_card ("cs4231a", &s->card); } -static int cs4231a_init (ISABus *bus) -{ - isa_create_simple (bus, TYPE_CS4231A); - return 0; -} - static Property cs4231a_properties[] = { DEFINE_AUDIO_PROPERTIES(CSState, card), DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534), @@ -720,7 +714,7 @@ static const TypeInfo cs4231a_info = { static void cs4231a_register_types (void) { type_register_static (&cs4231a_info); - isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init); + deprecated_register_soundhw("cs4231a", "CS4231A", 1, TYPE_CS4231A); } type_init (cs4231a_register_types) From ba541176f4385749d56574cda55fb86053a9d0b6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:13 +0200 Subject: [PATCH 1990/2595] audio: deprecate -soundhw gus Switch to deprecated_register_soundhw(). Remove the now obsolete init function. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-9-kraxel@redhat.com --- hw/audio/gus.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/hw/audio/gus.c b/hw/audio/gus.c index c8df2bde6b..7e4a8cadad 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -286,12 +286,6 @@ static void gus_realizefn (DeviceState *dev, Error **errp) AUD_set_active_out (s->voice, 1); } -static int GUS_init (ISABus *bus) -{ - isa_create_simple (bus, TYPE_GUS); - return 0; -} - static Property gus_properties[] = { DEFINE_AUDIO_PROPERTIES(GUSState, card), DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100), @@ -322,7 +316,7 @@ static const TypeInfo gus_info = { static void gus_register_types (void) { type_register_static (&gus_info); - isa_register_soundhw("gus", "Gravis Ultrasound GF1", GUS_init); + deprecated_register_soundhw("gus", "Gravis Ultrasound GF1", 1, TYPE_GUS); } type_init (gus_register_types) From 4b96159ecca1c48a1f4cbbc940b59cd05b473400 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:14 +0200 Subject: [PATCH 1991/2595] audio: deprecate -soundhw sb16 Switch to deprecated_register_soundhw(). Remove the now obsolete init function. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-10-kraxel@redhat.com --- hw/audio/sb16.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index df6f755a37..2d9e50f99b 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -1415,12 +1415,6 @@ static void sb16_realizefn (DeviceState *dev, Error **errp) AUD_register_card ("sb16", &s->card); } -static int SB16_init (ISABus *bus) -{ - isa_create_simple (bus, TYPE_SB16); - return 0; -} - static Property sb16_properties[] = { DEFINE_AUDIO_PROPERTIES(SB16State, card), DEFINE_PROP_UINT32 ("version", SB16State, ver, 0x0405), /* 4.5 */ @@ -1453,7 +1447,8 @@ static const TypeInfo sb16_info = { static void sb16_register_types (void) { type_register_static (&sb16_info); - isa_register_soundhw("sb16", "Creative Sound Blaster 16", SB16_init); + deprecated_register_soundhw("sb16", "Creative Sound Blaster 16", + 1, TYPE_SB16); } type_init (sb16_register_types) From fcb541c14e2791829c0cbca3c6678bddaf121226 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:15 +0200 Subject: [PATCH 1992/2595] audio: deprecate -soundhw hda Add deprecation message to the audio init function. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-11-kraxel@redhat.com --- hw/audio/intel-hda.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index f673b8317a..f6cea49686 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -25,6 +25,7 @@ #include "qemu/bitops.h" #include "qemu/log.h" #include "qemu/module.h" +#include "qemu/error-report.h" #include "hw/audio/soundhw.h" #include "intel-hda.h" #include "migration/vmstate.h" @@ -1307,6 +1308,8 @@ static int intel_hda_and_codec_init(PCIBus *bus) BusState *hdabus; DeviceState *codec; + warn_report("'-soundhw hda' is deprecated, " + "please use '-device intel-hda -device hda-duplex' instead"); controller = DEVICE(pci_create_simple(bus, -1, "intel-hda")); hdabus = QLIST_FIRST(&controller->child_bus); codec = qdev_new("hda-duplex"); From 10e2483b5f4f288be394e49661fc60f334dd9930 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:16 +0200 Subject: [PATCH 1993/2595] pc_basic_device_init: pass PCMachineState Need access to pcms for pcspk initialization. Just preparation, no functional change. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-12-kraxel@redhat.com --- hw/i386/pc.c | 3 ++- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- include/hw/i386/pc.h | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 4af9679d03..d89e577f6f 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1155,7 +1155,8 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport) g_free(a20_line); } -void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, +void pc_basic_device_init(struct PCMachineState *pcms, + ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, bool create_fdctrl, bool no_vmport, diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 1d832b2878..a3b4165072 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -235,7 +235,7 @@ static void pc_init1(MachineState *machine, } /* init basic PC hardware */ - pc_basic_device_init(isa_bus, x86ms->gsi, &rtc_state, true, + pc_basic_device_init(pcms, isa_bus, x86ms->gsi, &rtc_state, true, (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit_enabled, 0x4); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 047ea8db28..b16e22c6cc 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -275,7 +275,7 @@ static void pc_q35_init(MachineState *machine) } /* init basic PC hardware */ - pc_basic_device_init(isa_bus, x86ms->gsi, &rtc_state, !mc->no_floppy, + pc_basic_device_init(pcms, isa_bus, x86ms->gsi, &rtc_state, !mc->no_floppy, (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit_enabled, 0xff0104); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index dce1273c7d..3a601dbe71 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -160,7 +160,8 @@ void pc_memory_init(PCMachineState *pcms, MemoryRegion **ram_memory); uint64_t pc_pci_hole64_start(void); DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus); -void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, +void pc_basic_device_init(struct PCMachineState *pcms, + ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, bool create_fdctrl, bool no_vmport, From c52e7bbbaf77ed240b3f5fb7aab5615cf3db98dc Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:17 +0200 Subject: [PATCH 1994/2595] pc_basic_device_init: drop has_pit arg Now that we pass pcms anyway, we don't need the has_pit arg any more. No functional change. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-13-kraxel@redhat.com --- hw/i386/pc.c | 3 +-- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- include/hw/i386/pc.h | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index d89e577f6f..9f5153b6f2 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1160,7 +1160,6 @@ void pc_basic_device_init(struct PCMachineState *pcms, ISADevice **rtc_state, bool create_fdctrl, bool no_vmport, - bool has_pit, uint32_t hpet_irqs) { int i; @@ -1211,7 +1210,7 @@ void pc_basic_device_init(struct PCMachineState *pcms, qemu_register_boot_set(pc_boot_set, *rtc_state); - if (!xen_enabled() && has_pit) { + if (!xen_enabled() && pcms->pit_enabled) { if (kvm_pit_in_kernel()) { pit = kvm_pit_init(isa_bus, 0x40); } else { diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index a3b4165072..6c1612d0ca 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -236,7 +236,7 @@ static void pc_init1(MachineState *machine, /* init basic PC hardware */ pc_basic_device_init(pcms, isa_bus, x86ms->gsi, &rtc_state, true, - (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit_enabled, + (pcms->vmport != ON_OFF_AUTO_ON), 0x4); pc_nic_init(pcmc, isa_bus, pci_bus); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index b16e22c6cc..6faf445854 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -276,7 +276,7 @@ static void pc_q35_init(MachineState *machine) /* init basic PC hardware */ pc_basic_device_init(pcms, isa_bus, x86ms->gsi, &rtc_state, !mc->no_floppy, - (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit_enabled, + (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104); /* connect pm stuff to lpc */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 3a601dbe71..bd447e380b 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -165,7 +165,6 @@ void pc_basic_device_init(struct PCMachineState *pcms, ISADevice **rtc_state, bool create_fdctrl, bool no_vmport, - bool has_pit, uint32_t hpet_irqs); void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd); void pc_cmos_init(PCMachineState *pcms, From 8859f0727927d830174dd7a94d871b9fe348452b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:18 +0200 Subject: [PATCH 1995/2595] pc_basic_device_init: drop no_vmport arg Now that we pass pcms anyway, we don't need the no_vmport arg any more. No functional change. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-14-kraxel@redhat.com --- hw/i386/pc.c | 3 +-- hw/i386/pc_piix.c | 1 - hw/i386/pc_q35.c | 1 - include/hw/i386/pc.h | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 9f5153b6f2..407c782b5d 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1159,7 +1159,6 @@ void pc_basic_device_init(struct PCMachineState *pcms, ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, bool create_fdctrl, - bool no_vmport, uint32_t hpet_irqs) { int i; @@ -1226,7 +1225,7 @@ void pc_basic_device_init(struct PCMachineState *pcms, i8257_dma_init(isa_bus, 0); /* Super I/O */ - pc_superio_init(isa_bus, create_fdctrl, no_vmport); + pc_superio_init(isa_bus, create_fdctrl, pcms->vmport != ON_OFF_AUTO_ON); } void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 6c1612d0ca..1ef3f39c55 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -236,7 +236,6 @@ static void pc_init1(MachineState *machine, /* init basic PC hardware */ pc_basic_device_init(pcms, isa_bus, x86ms->gsi, &rtc_state, true, - (pcms->vmport != ON_OFF_AUTO_ON), 0x4); pc_nic_init(pcmc, isa_bus, pci_bus); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 6faf445854..5f8f21b840 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -276,7 +276,6 @@ static void pc_q35_init(MachineState *machine) /* init basic PC hardware */ pc_basic_device_init(pcms, isa_bus, x86ms->gsi, &rtc_state, !mc->no_floppy, - (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104); /* connect pm stuff to lpc */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index bd447e380b..d7690bf429 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -164,7 +164,6 @@ void pc_basic_device_init(struct PCMachineState *pcms, ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, bool create_fdctrl, - bool no_vmport, uint32_t hpet_irqs); void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd); void pc_cmos_init(PCMachineState *pcms, From dea1fb887c37f163891fb18313403a07752948d8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:19 +0200 Subject: [PATCH 1996/2595] softmmu: initialize spice and audio earlier audiodev must be initialized before machine_set_property so the machine can have audiodev property aliases. spice must initialize before audiodev because the default audiodev is spice only in case spice is actually enabled. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-15-kraxel@redhat.com --- softmmu/vl.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index 3e15ee2435..8ee9121906 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -4131,12 +4131,17 @@ void qemu_init(int argc, char **argv, char **envp) fsdev_init_func, NULL, &error_fatal); #endif + /* spice needs the timers to be initialized by this point */ + /* spice must initialize before audio as it changes the default auiodev */ + qemu_spice_init(); + /* - * Note: we need to create block backends before + * Note: we need to create audio and block backends before * machine_set_property(), so machine properties can refer to * them. */ configure_blockdev(&bdo_queue, machine_class, snapshot); + audio_init_audiodevs(); machine_opts = qemu_get_machine_opts(); qemu_opt_foreach(machine_opts, machine_set_property, current_machine, @@ -4230,9 +4235,6 @@ void qemu_init(int argc, char **argv, char **envp) semihosting_arg_fallback(kernel_filename, kernel_cmdline); } - /* spice needs the timers to be initialized by this point */ - qemu_spice_init(); - cpu_ticks_init(); if (default_net) { @@ -4342,8 +4344,6 @@ void qemu_init(int argc, char **argv, char **envp) create_default_memdev(current_machine, mem_path); } - audio_init_audiodevs(); - /* from here on runstate is RUN_STATE_PRELAUNCH */ machine_run_board_init(current_machine); From 525d654d7a113e24e5c4efc21e6f2f8c952d21d9 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:20 +0200 Subject: [PATCH 1997/2595] audio: rework pcspk_init() Instead of creating and returning the pc speaker accept it as argument. That allows to rework the initialization workflow in followup patches. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-16-kraxel@redhat.com --- hw/i386/pc.c | 2 +- hw/isa/i82378.c | 2 +- hw/mips/jazz.c | 2 +- include/hw/audio/pcspk.h | 6 +----- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 407c782b5d..4fc1b7048b 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1219,7 +1219,7 @@ void pc_basic_device_init(struct PCMachineState *pcms, /* connect PIT to output control line of the HPET */ qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(DEVICE(pit), 0)); } - pcspk_init(isa_bus, pit); + pcspk_init(isa_new(TYPE_PC_SPEAKER), isa_bus, pit); } i8257_dma_init(isa_bus, 0); diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index d9e6c7fa00..75a2da2881 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -102,7 +102,7 @@ static void i82378_realize(PCIDevice *pci, Error **errp) pit = i8254_pit_init(isabus, 0x40, 0, NULL); /* speaker */ - pcspk_init(isabus, pit); + pcspk_init(isa_new(TYPE_PC_SPEAKER), isabus, pit); /* 2 82C37 (dma) */ isa_create_simple(isabus, "i82374"); diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index c3b0da60cc..0002bff695 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -250,7 +250,7 @@ static void mips_jazz_init(MachineState *machine, isa_bus_irqs(isa_bus, i8259); i8257_dma_init(isa_bus, 0); pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); - pcspk_init(isa_bus, pit); + pcspk_init(isa_new(TYPE_PC_SPEAKER), isa_bus, pit); /* Video card */ switch (jazz_model) { diff --git a/include/hw/audio/pcspk.h b/include/hw/audio/pcspk.h index 7e7f5f49dc..8b48560267 100644 --- a/include/hw/audio/pcspk.h +++ b/include/hw/audio/pcspk.h @@ -31,18 +31,14 @@ #define TYPE_PC_SPEAKER "isa-pcspk" -static inline ISADevice *pcspk_init(ISABus *bus, ISADevice *pit) +static inline void pcspk_init(ISADevice *isadev, ISABus *bus, ISADevice *pit) { DeviceState *dev; - ISADevice *isadev; - isadev = isa_new(TYPE_PC_SPEAKER); dev = DEVICE(isadev); qdev_prop_set_uint32(dev, "iobase", 0x61); object_property_set_link(OBJECT(dev), OBJECT(pit), "pit", NULL); isa_realize_and_unref(isadev, bus, &error_fatal); - - return isadev; } #endif /* HW_PCSPK_H */ From 6b8d1416482feb84f5c1d33a4e2acf7367a8f11f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:21 +0200 Subject: [PATCH 1998/2595] audio: create pcspk device early Create the pcspk device early, so it exists at machine type initialization time. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-17-kraxel@redhat.com --- hw/i386/pc.c | 3 ++- include/hw/i386/pc.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 4fc1b7048b..88785f9dcc 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1219,7 +1219,7 @@ void pc_basic_device_init(struct PCMachineState *pcms, /* connect PIT to output control line of the HPET */ qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(DEVICE(pit), 0)); } - pcspk_init(isa_new(TYPE_PC_SPEAKER), isa_bus, pit); + pcspk_init(pcms->pcspk, isa_bus, pit); } i8257_dma_init(isa_bus, 0); @@ -1891,6 +1891,7 @@ static void pc_machine_initfn(Object *obj) pcms->pit_enabled = true; pc_system_flash_create(pcms); + pcms->pcspk = isa_new(TYPE_PC_SPEAKER); } static void pc_machine_reset(MachineState *machine) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index d7690bf429..a802e69974 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -33,6 +33,7 @@ struct PCMachineState { PCIBus *bus; I2CBus *smbus; PFlashCFI01 *flash[2]; + ISADevice *pcspk; /* Configuration options: */ uint64_t max_ram_below_4g; From 2e16ec054199d0879572f850e3beb79045985342 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:22 +0200 Subject: [PATCH 1999/2595] audio: deprecate -soundhw pcspk Add deprecation message to the audio init function. Factor out audio initialization and call that from both audio init and realize, so setting the audiodev property is enough to properly initialize pcspk. Add a property alias to the machine type to set the audio device, so pcspk can be initialized using: "-machine pcspk-audiodev=" Using "-global isa-pcspk.audiodev=" works too but is not recommended. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-18-kraxel@redhat.com --- hw/audio/pcspk.c | 24 +++++++++++++++++++++--- hw/i386/pc.c | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index c37a387861..4c7e339ac2 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -28,6 +28,7 @@ #include "audio/audio.h" #include "qemu/module.h" #include "qemu/timer.h" +#include "qemu/error-report.h" #include "hw/timer/i8254.h" #include "migration/vmstate.h" #include "hw/audio/pcspk.h" @@ -112,11 +113,15 @@ static void pcspk_callback(void *opaque, int free) } } -static int pcspk_audio_init(ISABus *bus) +static int pcspk_audio_init(PCSpkState *s) { - PCSpkState *s = pcspk_state; struct audsettings as = {PCSPK_SAMPLE_RATE, 1, AUDIO_FORMAT_U8, 0}; + if (s->voice) { + /* already initialized */ + return 0; + } + AUD_register_card(s_spk, &s->card); s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as); @@ -185,6 +190,10 @@ static void pcspk_realizefn(DeviceState *dev, Error **errp) isa_register_ioport(isadev, &s->ioport, s->iobase); + if (s->card.state) { + pcspk_audio_init(s); + } + pcspk_state = s; } @@ -236,9 +245,18 @@ static const TypeInfo pcspk_info = { .class_init = pcspk_class_initfn, }; +static int pcspk_audio_init_soundhw(ISABus *bus) +{ + PCSpkState *s = pcspk_state; + + warn_report("'-soundhw pcspk' is deprecated, " + "please set a backend using '-machine pcspk-audiodev=' instead"); + return pcspk_audio_init(s); +} + static void pcspk_register(void) { type_register_static(&pcspk_info); - isa_register_soundhw("pcspk", "PC speaker", pcspk_audio_init); + isa_register_soundhw("pcspk", "PC speaker", pcspk_audio_init_soundhw); } type_init(pcspk_register) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 88785f9dcc..c45e7bfd86 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1892,6 +1892,8 @@ static void pc_machine_initfn(Object *obj) pc_system_flash_create(pcms); pcms->pcspk = isa_new(TYPE_PC_SPEAKER); + object_property_add_alias(OBJECT(pcms), "pcspk-audiodev", + OBJECT(pcms->pcspk), "audiodev"); } static void pc_machine_reset(MachineState *machine) From 825ff02911c9c90d5e635e9f588de2b3e27a0774 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:23 +0200 Subject: [PATCH 2000/2595] audio: add soundhw deprecation notice Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-19-kraxel@redhat.com --- docs/system/deprecated.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 47f84be8e0..58a9aeb851 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -82,6 +82,15 @@ should specify an ``audiodev=`` property. Additionally, when using vnc, you should specify an ``audiodev=`` propery if you plan to transmit audio through the VNC protocol. +Creating sound card devices using ``-soundhw`` (since 5.1) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Sound card devices should be created using ``-device`` instead. The +names are the same for most devices. The exceptions are ``hda`` which +needs two devices (``-device intel-hda -device hda-duplex``) and +``pcspk`` which can be activated using ``-machine +pcspk-audiodev=``. + ``-mon ...,control=readline,pretty=on|off`` (since 4.1) ''''''''''''''''''''''''''''''''''''''''''''''''''''''' From 59e75839057ec6e13538ef8b89aadfd9f237dc12 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:24 +0200 Subject: [PATCH 2001/2595] pcspk: update docs/system/target-i386-desc.rst.inc Add PC speaker with config hints. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-20-kraxel@redhat.com --- docs/system/target-i386-desc.rst.inc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/system/target-i386-desc.rst.inc b/docs/system/target-i386-desc.rst.inc index 47a169e0ae..7d1fffacbe 100644 --- a/docs/system/target-i386-desc.rst.inc +++ b/docs/system/target-i386-desc.rst.inc @@ -31,6 +31,8 @@ The QEMU PC System emulator simulates the following peripherals: - CS4231A compatible sound card +- PC speaker + - PCI UHCI, OHCI, EHCI or XHCI USB controller and a virtual USB-1.1 hub. @@ -49,7 +51,7 @@ must be told to not have parallel ports to have working GUS. .. parsed-literal:: - |qemu_system_x86| dos.img -soundhw gus -parallel none + |qemu_system_x86| dos.img -device gus -parallel none Alternatively: @@ -60,3 +62,12 @@ Alternatively: Or some other unclaimed IRQ. CS4231A is the chip used in Windows Sound System and GUSMAX products + +The PC speaker audio device can be configured using the pcspk-audiodev +machine property, i.e. + +.. parsed-literal:: + + |qemu_system_x86| some.img \ + -audiodev ,id= \ + -machine pcspk-audiodev= From 2336172d9b396b4fa4483712f5560a563c25352f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 2 Jul 2020 15:25:25 +0200 Subject: [PATCH 2002/2595] audio: set default value for pcspk.iobase property Allows dropping the explicit qdev_prop_set_uint32 call in pcspk_init. Signed-off-by: Gerd Hoffmann Message-id: 20200702132525.6849-21-kraxel@redhat.com --- hw/audio/pcspk.c | 2 +- include/hw/audio/pcspk.h | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index 4c7e339ac2..ea539e7605 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -219,7 +219,7 @@ static const VMStateDescription vmstate_spk = { static Property pcspk_properties[] = { DEFINE_AUDIO_PROPERTIES(PCSpkState, card), - DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1), + DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, 0x61), DEFINE_PROP_BOOL("migrate", PCSpkState, migrate, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/audio/pcspk.h b/include/hw/audio/pcspk.h index 8b48560267..06cba00b83 100644 --- a/include/hw/audio/pcspk.h +++ b/include/hw/audio/pcspk.h @@ -33,11 +33,7 @@ static inline void pcspk_init(ISADevice *isadev, ISABus *bus, ISADevice *pit) { - DeviceState *dev; - - dev = DEVICE(isadev); - qdev_prop_set_uint32(dev, "iobase", 0x61); - object_property_set_link(OBJECT(dev), OBJECT(pit), "pit", NULL); + object_property_set_link(OBJECT(isadev), OBJECT(pit), "pit", NULL); isa_realize_and_unref(isadev, bus, &error_fatal); } From db7b62e70667b06ae18b69382f4647f5673bbf75 Mon Sep 17 00:00:00 2001 From: Lijun Pan Date: Wed, 1 Jul 2020 18:43:44 -0500 Subject: [PATCH 2003/2595] fix the prototype of muls64/mulu64 The prototypes of muls64/mulu64 in host-utils.h should match the definitions in host-utils.c Signed-off-by: Lijun Pan Message-Id: <20200701234344.91843-10-ljp@linux.ibm.com> Reviewed-by: Richard Henderson Signed-off-by: Laurent Vivier --- include/qemu/host-utils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index 4cd170e6cd..cdca2991d8 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -77,8 +77,8 @@ static inline int divs128(int64_t *plow, int64_t *phigh, int64_t divisor) } } #else -void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b); -void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b); +void muls64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b); +void mulu64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b); int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor); int divs128(int64_t *plow, int64_t *phigh, int64_t divisor); From 94248cfc04dfa08e43aacd9d5bbfba7a47bff671 Mon Sep 17 00:00:00 2001 From: "Catherine A. Frederick" Date: Sun, 7 Jun 2020 17:10:59 -0400 Subject: [PATCH 2004/2595] tcg/ppc: Sanitize immediate shifts Sanitize shift constants so that shift operations with large constants don't generate invalid instructions. Signed-off-by: Catherine A. Frederick Message-Id: <20200607211100.22858-1-agrecascino123@gmail.com> Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.inc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tcg/ppc/tcg-target.inc.c b/tcg/ppc/tcg-target.inc.c index 7da67086c6..c8d1e765d9 100644 --- a/tcg/ppc/tcg-target.inc.c +++ b/tcg/ppc/tcg-target.inc.c @@ -2610,21 +2610,24 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_shl_i32: if (const_args[2]) { - tcg_out_shli32(s, args[0], args[1], args[2]); + /* Limit immediate shift count lest we create an illegal insn. */ + tcg_out_shli32(s, args[0], args[1], args[2] & 31); } else { tcg_out32(s, SLW | SAB(args[1], args[0], args[2])); } break; case INDEX_op_shr_i32: if (const_args[2]) { - tcg_out_shri32(s, args[0], args[1], args[2]); + /* Limit immediate shift count lest we create an illegal insn. */ + tcg_out_shri32(s, args[0], args[1], args[2] & 31); } else { tcg_out32(s, SRW | SAB(args[1], args[0], args[2])); } break; case INDEX_op_sar_i32: if (const_args[2]) { - tcg_out32(s, SRAWI | RS(args[1]) | RA(args[0]) | SH(args[2])); + /* Limit immediate shift count lest we create an illegal insn. */ + tcg_out32(s, SRAWI | RS(args[1]) | RA(args[0]) | SH(args[2] & 31)); } else { tcg_out32(s, SRAW | SAB(args[1], args[0], args[2])); } @@ -2696,14 +2699,16 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_shl_i64: if (const_args[2]) { - tcg_out_shli64(s, args[0], args[1], args[2]); + /* Limit immediate shift count lest we create an illegal insn. */ + tcg_out_shli64(s, args[0], args[1], args[2] & 63); } else { tcg_out32(s, SLD | SAB(args[1], args[0], args[2])); } break; case INDEX_op_shr_i64: if (const_args[2]) { - tcg_out_shri64(s, args[0], args[1], args[2]); + /* Limit immediate shift count lest we create an illegal insn. */ + tcg_out_shri64(s, args[0], args[1], args[2] & 63); } else { tcg_out32(s, SRD | SAB(args[1], args[0], args[2])); } From 852f933e482518797f7785a2e017a215b88df815 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 1 Jul 2020 09:28:15 -0700 Subject: [PATCH 2005/2595] tcg: Fix do_nonatomic_op_* vs signed operations The smin/smax/umin/umax operations require the operands to be properly sign extended. Do not drop the MO_SIGN bit from the load, and additionally extend the val input. Reviewed-by: LIU Zhiwei Reported-by: LIU Zhiwei Signed-off-by: Richard Henderson Message-Id: <20200701165646.1901320-1-richard.henderson@linaro.org> --- tcg/tcg-op.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index e60b74fb82..4b8a473fad 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -3189,8 +3189,9 @@ static void do_nonatomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, memop = tcg_canonicalize_memop(memop, 0, 0); - tcg_gen_qemu_ld_i32(t1, addr, idx, memop & ~MO_SIGN); - gen(t2, t1, val); + tcg_gen_qemu_ld_i32(t1, addr, idx, memop); + tcg_gen_ext_i32(t2, val, memop); + gen(t2, t1, t2); tcg_gen_qemu_st_i32(t2, addr, idx, memop); tcg_gen_ext_i32(ret, (new_val ? t2 : t1), memop); @@ -3232,8 +3233,9 @@ static void do_nonatomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val, memop = tcg_canonicalize_memop(memop, 1, 0); - tcg_gen_qemu_ld_i64(t1, addr, idx, memop & ~MO_SIGN); - gen(t2, t1, val); + tcg_gen_qemu_ld_i64(t1, addr, idx, memop); + tcg_gen_ext_i64(t2, val, memop); + gen(t2, t1, t2); tcg_gen_qemu_st_i64(t2, addr, idx, memop); tcg_gen_ext_i64(ret, (new_val ? t2 : t1), memop); From 78318119eead6aed050d1730a6b72d1c555302d2 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 1 Jul 2020 21:15:30 +0100 Subject: [PATCH 2006/2595] target/m68k: fix physical address translation in m68k_cpu_get_phys_page_debug() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The result of the get_physical_address() function should be combined with the offset of the original page access before being returned. Otherwise the m68k_cpu_get_phys_page_debug() function can round to the wrong page causing incorrect lookups in gdbstub and various "Disassembler disagrees with translator over instruction decoding" warnings to appear at translation time. Fixes: 88b2fef6c3 ("target/m68k: add MC68040 MMU") Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20200701201531.13828-2-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- target/m68k/helper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 79b0b10ea9..631eab7774 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -820,10 +820,14 @@ hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) if (env->sr & SR_S) { access_type |= ACCESS_SUPER; } + if (get_physical_address(env, &phys_addr, &prot, addr, access_type, &page_size) != 0) { return -1; } + + addr &= TARGET_PAGE_MASK; + phys_addr += addr & (page_size - 1); return phys_addr; } From 852002b5664bf079da05c5201dbf2345b870e5ed Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 1 Jul 2020 21:15:31 +0100 Subject: [PATCH 2007/2595] target/m68k: consolidate physical translation offset into get_physical_address() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since all callers to get_physical_address() now apply the same page offset to the translation result, move the logic into get_physical_address() itself to avoid duplication. Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-Id: <20200701201531.13828-3-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- target/m68k/helper.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 631eab7774..3ff5765795 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -643,7 +643,7 @@ static int get_physical_address(CPUM68KState *env, hwaddr *physical, /* Transparent Translation Register bit */ env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040; } - *physical = address & TARGET_PAGE_MASK; + *physical = address; *page_size = TARGET_PAGE_SIZE; return 0; } @@ -771,7 +771,7 @@ static int get_physical_address(CPUM68KState *env, hwaddr *physical, } *page_size = 1 << page_bits; page_mask = ~(*page_size - 1); - *physical = next & page_mask; + *physical = (next & page_mask) + (address & (*page_size - 1)); if (access_type & ACCESS_PTEST) { env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040; @@ -826,8 +826,6 @@ hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) return -1; } - addr &= TARGET_PAGE_MASK; - phys_addr += addr & (page_size - 1); return phys_addr; } @@ -891,10 +889,8 @@ bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size, ret = get_physical_address(&cpu->env, &physical, &prot, address, access_type, &page_size); if (likely(ret == 0)) { - address &= TARGET_PAGE_MASK; - physical += address & (page_size - 1); - tlb_set_page(cs, address, physical, - prot, mmu_idx, TARGET_PAGE_SIZE); + tlb_set_page(cs, address & TARGET_PAGE_MASK, + physical & TARGET_PAGE_MASK, prot, mmu_idx, page_size); return true; } @@ -1383,9 +1379,8 @@ void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read) ret = get_physical_address(env, &physical, &prot, addr, access_type, &page_size); if (ret == 0) { - addr &= TARGET_PAGE_MASK; - physical += addr & (page_size - 1); - tlb_set_page(env_cpu(env), addr, physical, + tlb_set_page(env_cpu(env), addr & TARGET_PAGE_MASK, + physical & TARGET_PAGE_MASK, prot, access_type & ACCESS_SUPER ? MMU_KERNEL_IDX : MMU_USER_IDX, page_size); } From d159dd058c7dc48a9291fde92eaae52a9f26a4d1 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 12 Jun 2020 16:04:00 +0200 Subject: [PATCH 2008/2595] softfloat,m68k: disable floatx80_invalid_encoding() for m68k MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the comment, this definition of invalid encoding is given by intel developer's manual, and doesn't comply with 680x0 FPU. With m68k, the explicit integer bit can be zero in the case of: - zeros (exp == 0, mantissa == 0) - denormalized numbers (exp == 0, mantissa != 0) - unnormalized numbers (exp != 0, exp < 0x7FFF) - infinities (exp == 0x7FFF, mantissa == 0) - not-a-numbers (exp == 0x7FFF, mantissa != 0) For infinities and NaNs, the explicit integer bit can be either one or zero. The IEEE 754 standard does not define a zero integer bit. Such a number is an unnormalized number. Hardware does not directly support denormalized and unnormalized numbers, but implicitly supports them by trapping them as unimplemented data types, allowing efficient conversion in software. See "M68000 FAMILY PROGRAMMER’S REFERENCE MANUAL", "1.6 FLOATING-POINT DATA TYPES" We will implement in the m68k TCG emulator the FP_UNIMP exception to trap into the kernel to normalize the number. In case of linux-user, the number will be normalized by QEMU. Signed-off-by: Laurent Vivier Reviewed-by: Alex Bennée Message-Id: <20200612140400.2130118-1-laurent@vivier.eu> --- include/fpu/softfloat.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index ff4e2605b1..f1a19df066 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -794,7 +794,31 @@ static inline bool floatx80_unordered_quiet(floatx80 a, floatx80 b, *----------------------------------------------------------------------------*/ static inline bool floatx80_invalid_encoding(floatx80 a) { +#if defined(TARGET_M68K) + /*------------------------------------------------------------------------- + | With m68k, the explicit integer bit can be zero in the case of: + | - zeros (exp == 0, mantissa == 0) + | - denormalized numbers (exp == 0, mantissa != 0) + | - unnormalized numbers (exp != 0, exp < 0x7FFF) + | - infinities (exp == 0x7FFF, mantissa == 0) + | - not-a-numbers (exp == 0x7FFF, mantissa != 0) + | + | For infinities and NaNs, the explicit integer bit can be either one or + | zero. + | + | The IEEE 754 standard does not define a zero integer bit. Such a number + | is an unnormalized number. Hardware does not directly support + | denormalized and unnormalized numbers, but implicitly supports them by + | trapping them as unimplemented data types, allowing efficient conversion + | in software. + | + | See "M68000 FAMILY PROGRAMMER’S REFERENCE MANUAL", + | "1.6 FLOATING-POINT DATA TYPES" + *------------------------------------------------------------------------*/ + return false; +#else return (a.low & (1ULL << 63)) == 0 && (a.high & 0x7FFF) != 0; +#endif } #define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL) From be99a9a09dcf8b056ec501591e4efdce8efeaf00 Mon Sep 17 00:00:00 2001 From: Christophe de Dinechin Date: Mon, 29 Jun 2020 11:49:34 +0200 Subject: [PATCH 2009/2595] trivial: Respect alphabetical order of .o files in Makefile.objs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vmgenid.o is the only file that is not in alphabetical order. Signed-off-by: Christophe de Dinechin Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200629094934.2081180-1-dinechin@redhat.com> Signed-off-by: Laurent Vivier --- stubs/Makefile.objs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index f32b9e47a3..1df8bb3814 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -19,10 +19,10 @@ stub-obj-y += replay.o stub-obj-y += runstate-check.o stub-obj-$(CONFIG_SOFTMMU) += semihost.o stub-obj-y += set-fd-handler.o -stub-obj-y += vmgenid.o stub-obj-y += sysbus.o stub-obj-y += tpm.o stub-obj-y += trace-control.o +stub-obj-y += vmgenid.o stub-obj-y += vmstate.o stub-obj-$(CONFIG_SOFTMMU) += win32-kbd-hook.o From 0f57f8d84f36a1769720dae70bd12725194f48d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 2 Jul 2020 19:38:00 +0200 Subject: [PATCH 2010/2595] .mailmap: Update Alexander Graf email address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update Alexander Graf email address to avoid emails bouncing. Suggested-by: Alexander Graf Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alexander Graf Message-Id: <20200702173818.14651-2-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 926cac6bb8..e46e6c7302 100644 --- a/.mailmap +++ b/.mailmap @@ -44,6 +44,7 @@ Aleksandar Markovic Aleksandar Rikalo Aleksandar Rikalo +Alexander Graf Anthony Liguori Anthony Liguori Filip Bozuta Frederic Konrad From 428a37770406346dac6d355a70ea5a8916aecb1f Mon Sep 17 00:00:00 2001 From: Radoslaw Biernacki Date: Tue, 12 May 2020 19:07:04 +0200 Subject: [PATCH 2011/2595] MAINTAINERS: Update Radoslaw Biernacki email address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My Linaro account is no longer active and stop forwarding emails to me. Changing it to my current employer domain. Signed-off-by: Radoslaw Biernacki Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Acked-by: Leif Lindholm Message-Id: <20200512170704.9290-1-rad@semihalf.com> Signed-off-by: Laurent Vivier --- .mailmap | 1 + MAINTAINERS | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index e46e6c7302..81c2ce0937 100644 --- a/.mailmap +++ b/.mailmap @@ -50,6 +50,7 @@ Filip Bozuta Frederic Konrad James Hogan Leif Lindholm +Radoslaw Biernacki Paul Burton Paul Burton Paul Burton diff --git a/MAINTAINERS b/MAINTAINERS index c31c878c63..36dce13bcc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -809,7 +809,7 @@ F: include/hw/misc/imx6_*.h F: include/hw/ssi/imx_spi.h SBSA-REF -M: Radoslaw Biernacki +M: Radoslaw Biernacki M: Peter Maydell R: Leif Lindholm L: qemu-arm@nongnu.org From 8f4d9555823636c329cb40afc6f36969ec5d35e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 29 Jun 2020 09:08:58 +0200 Subject: [PATCH 2012/2595] util/qemu-option: Document the get_opt_value() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coverity noticed commit 950c4e6c94 introduced a dereference before null check in get_opt_value (CID1391003): In get_opt_value: All paths that lead to this null pointer comparison already dereference the pointer earlier (CWE-476) We fixed this in commit 6e3ad3f0e31, but relaxed the check in commit 0c2f6e7ee99 because "No callers of get_opt_value() pass in a NULL for the 'value' parameter". Since this function is publicly exposed, it risks new users to do the same error again. Avoid that documenting the 'value' argument must not be NULL. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-Id: <20200629070858.19850-1-philmd@redhat.com> Signed-off-by: Laurent Vivier --- include/qemu/option.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/qemu/option.h b/include/qemu/option.h index eb4097889d..ac50d25774 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -28,6 +28,19 @@ #include "qemu/queue.h" +/** + * get_opt_value + * @p: a pointer to the option name, delimited by commas + * @value: a non-NULL pointer that will received the delimited options + * + * The @value char pointer will be allocated and filled with + * the delimited options. + * + * Returns the position of the comma delimiter/zero byte after the + * option name in @p. + * The memory pointer in @value must be released with a call to g_free() + * when no longer required. + */ const char *get_opt_value(const char *p, char **value); void parse_option_size(const char *name, const char *value, From 2a345149d1747d8625d5d2796e22f4bdd60bea83 Mon Sep 17 00:00:00 2001 From: Menno Lageman Date: Thu, 25 Jun 2020 17:52:58 +0200 Subject: [PATCH 2013/2595] intel_iommu: "aw-bits" error message still refers to "x-aw-bits" Commit 4b49b586c4 ('intel_iommu: remove "x-" prefix for "aw-bits"') removed the "x-" prefix but but didn't update the error message accordingly. Signed-off-by: Menno Lageman Reviewed-by: Laurent Vivier Message-Id: <20200625155258.1452425-1-menno.lageman@oracle.com> Signed-off-by: Laurent Vivier --- hw/i386/intel_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index df7ad254ac..c56398e991 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3758,7 +3758,7 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) /* Currently only address widths supported are 39 and 48 bits */ if ((s->aw_bits != VTD_HOST_AW_39BIT) && (s->aw_bits != VTD_HOST_AW_48BIT)) { - error_setg(errp, "Supported values for x-aw-bits are: %d, %d", + error_setg(errp, "Supported values for aw-bits are: %d, %d", VTD_HOST_AW_39BIT, VTD_HOST_AW_48BIT); return false; } From 89615cfef57e04da0e5a1bd212a62f8696468e79 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sat, 4 Jul 2020 10:23:17 +0100 Subject: [PATCH 2014/2595] net/tap-solaris.c: Include qemu-common.h for TFR macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit a8d2532645cf5ce4 we cleaned up usage of the qemu-common.h header so that it was always included from .c files and never from other .h files. We missed adding it to net/tap-solaris.c (which previously was pulling it in via tap-int.h), which broke building on Solaris hosts. Fixes: a8d2532645cf5ce4 Reported-by: Michele Denber Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Tested-by: Michele Denber Message-Id: <20200704092317.12943-1-peter.maydell@linaro.org> Signed-off-by: Laurent Vivier --- net/tap-solaris.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/tap-solaris.c b/net/tap-solaris.c index 4725d2314e..d03165c57c 100644 --- a/net/tap-solaris.c +++ b/net/tap-solaris.c @@ -27,6 +27,7 @@ #include "tap_int.h" #include "qemu/ctype.h" #include "qemu/cutils.h" +#include "qemu-common.h" #include #include From 108a64818e69be0a97cde3838d768f2d9910c08b Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Wed, 1 Jul 2020 22:55:37 +0800 Subject: [PATCH 2015/2595] vhost-vdpa: introduce vhost-vdpa backend Currently we have 2 types of vhost backends in QEMU: vhost kernel and vhost-user. The above patch provides a generic device for vDPA purpose, this vDPA device exposes to user space a non-vendor-specific configuration interface for setting up a vhost HW accelerator, this patch set introduces a third vhost backend called vhost-vdpa based on the vDPA interface. Vhost-vdpa usage: qemu-system-x86_64 -cpu host -enable-kvm \ ...... -netdev type=vhost-vdpa,vhostdev=/dev/vhost-vdpa-id,id=vhost-vdpa0 \ -device virtio-net-pci,netdev=vhost-vdpa0,page-per-vq=on \ Signed-off-by: Lingshan zhu Signed-off-by: Tiwei Bie Signed-off-by: Cindy Lu Signed-off-by: Jason Wang Message-Id: <20200701145538.22333-14-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- configure | 21 ++ docs/interop/index.rst | 1 + docs/interop/vhost-vdpa.rst | 17 ++ hw/net/vhost_net.c | 18 +- hw/net/virtio-net.c | 19 ++ hw/virtio/Makefile.objs | 1 + hw/virtio/vhost-backend.c | 6 + hw/virtio/vhost-vdpa.c | 475 ++++++++++++++++++++++++++++++ include/hw/virtio/vhost-backend.h | 4 +- include/hw/virtio/vhost-vdpa.h | 26 ++ include/hw/virtio/vhost.h | 7 + qemu-options.hx | 12 + 12 files changed, 600 insertions(+), 7 deletions(-) create mode 100644 docs/interop/vhost-vdpa.rst create mode 100644 hw/virtio/vhost-vdpa.c create mode 100644 include/hw/virtio/vhost-vdpa.h diff --git a/configure b/configure index 4a22dcd563..3db7f20185 100755 --- a/configure +++ b/configure @@ -1575,6 +1575,10 @@ for opt do ;; --enable-vhost-user) vhost_user="yes" ;; + --disable-vhost-vdpa) vhost_vdpa="no" + ;; + --enable-vhost-vdpa) vhost_vdpa="yes" + ;; --disable-vhost-kernel) vhost_kernel="no" ;; --enable-vhost-kernel) vhost_kernel="yes" @@ -1883,6 +1887,7 @@ disabled with --disable-FEATURE, default is enabled if available: vhost-crypto vhost-user-crypto backend support vhost-kernel vhost kernel backend support vhost-user vhost-user backend support + vhost-vdpa vhost-vdpa kernel backend support spice spice rbd rados block device (rbd) libiscsi iscsi support @@ -2394,6 +2399,10 @@ test "$vhost_user" = "" && vhost_user=yes if test "$vhost_user" = "yes" && test "$mingw32" = "yes"; then error_exit "vhost-user isn't available on win32" fi +test "$vhost_vdpa" = "" && vhost_vdpa=$linux +if test "$vhost_vdpa" = "yes" && test "$linux" != "yes"; then + error_exit "vhost-vdpa is only available on Linux" +fi test "$vhost_kernel" = "" && vhost_kernel=$linux if test "$vhost_kernel" = "yes" && test "$linux" != "yes"; then error_exit "vhost-kernel is only available on Linux" @@ -2422,6 +2431,11 @@ test "$vhost_user_fs" = "" && vhost_user_fs=$vhost_user if test "$vhost_user_fs" = "yes" && test "$vhost_user" = "no"; then error_exit "--enable-vhost-user-fs requires --enable-vhost-user" fi +#vhost-vdpa backends +test "$vhost_net_vdpa" = "" && vhost_net_vdpa=$vhost_vdpa +if test "$vhost_net_vdpa" = "yes" && test "$vhost_vdpa" = "no"; then + error_exit "--enable-vhost-net-vdpa requires --enable-vhost-vdpa" +fi # OR the vhost-kernel and vhost-user values for simplicity if test "$vhost_net" = ""; then @@ -6936,6 +6950,7 @@ echo "vhost-scsi support $vhost_scsi" echo "vhost-vsock support $vhost_vsock" echo "vhost-user support $vhost_user" echo "vhost-user-fs support $vhost_user_fs" +echo "vhost-vdpa support $vhost_vdpa" echo "Trace backends $trace_backends" if have_backend "simple"; then echo "Trace output file $trace_file-" @@ -7437,6 +7452,9 @@ fi if test "$vhost_net_user" = "yes" ; then echo "CONFIG_VHOST_NET_USER=y" >> $config_host_mak fi +if test "$vhost_net_vdpa" = "yes" ; then + echo "CONFIG_VHOST_NET_VDPA=y" >> $config_host_mak +fi if test "$vhost_crypto" = "yes" ; then echo "CONFIG_VHOST_CRYPTO=y" >> $config_host_mak fi @@ -7452,6 +7470,9 @@ fi if test "$vhost_user" = "yes" ; then echo "CONFIG_VHOST_USER=y" >> $config_host_mak fi +if test "$vhost_vdpa" = "yes" ; then + echo "CONFIG_VHOST_VDPA=y" >> $config_host_mak +fi if test "$vhost_user_fs" = "yes" ; then echo "CONFIG_VHOST_USER_FS=y" >> $config_host_mak fi diff --git a/docs/interop/index.rst b/docs/interop/index.rst index 049387ac6d..006f986420 100644 --- a/docs/interop/index.rst +++ b/docs/interop/index.rst @@ -20,3 +20,4 @@ Contents: qemu-ga vhost-user vhost-user-gpu + vhost-vdpa diff --git a/docs/interop/vhost-vdpa.rst b/docs/interop/vhost-vdpa.rst new file mode 100644 index 0000000000..0c70ba01bc --- /dev/null +++ b/docs/interop/vhost-vdpa.rst @@ -0,0 +1,17 @@ +===================== +Vhost-vdpa Protocol +===================== + +Introduction +============= +vDPA(Virtual data path acceleration) device is a device that uses +a datapath which complies with the virtio specifications with vendor +specific control path. vDPA devices can be both physically located on +the hardware or emulated by software. + +This document describes the vDPA support in qemu + +Here is the kernel commit here +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4c8cf31885f69e86be0b5b9e6677a26797365e1d + +TODO : More information will add later diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 4561665f6b..24d555e764 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -17,6 +17,7 @@ #include "net/net.h" #include "net/tap.h" #include "net/vhost-user.h" +#include "net/vhost-vdpa.h" #include "standard-headers/linux/vhost_types.h" #include "hw/virtio/virtio-net.h" @@ -33,12 +34,6 @@ #include "hw/virtio/vhost.h" #include "hw/virtio/virtio-bus.h" -struct vhost_net { - struct vhost_dev dev; - struct vhost_virtqueue vqs[2]; - int backend; - NetClientState *nc; -}; /* Features supported by host kernel. */ static const int kernel_feature_bits[] = { @@ -96,6 +91,11 @@ static const int *vhost_net_get_feature_bits(struct vhost_net *net) case NET_CLIENT_DRIVER_VHOST_USER: feature_bits = user_feature_bits; break; +#ifdef CONFIG_VHOST_NET_VDPA + case NET_CLIENT_DRIVER_VHOST_VDPA: + feature_bits = vdpa_feature_bits; + break; +#endif default: error_report("Feature bits not defined for this type: %d", net->nc->info->type); @@ -443,6 +443,12 @@ VHostNetState *get_vhost_net(NetClientState *nc) vhost_net = vhost_user_get_vhost_net(nc); assert(vhost_net); break; +#endif +#ifdef CONFIG_VHOST_NET_VDPA + case NET_CLIENT_DRIVER_VHOST_VDPA: + vhost_net = vhost_vdpa_get_vhost_net(nc); + assert(vhost_net); + break; #endif default: break; diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index aff67a92df..0a54b1910a 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -43,6 +43,7 @@ #include "monitor/qdev.h" #include "hw/pci/pci.h" #include "net_rx_pkt.h" +#include "hw/virtio/vhost.h" #define VIRTIO_NET_VM_VERSION 11 @@ -125,6 +126,8 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) VirtIONet *n = VIRTIO_NET(vdev); struct virtio_net_config netcfg; + int ret = 0; + memset(&netcfg, 0 , sizeof(struct virtio_net_config)); virtio_stw_p(vdev, &netcfg.status, n->status); virtio_stw_p(vdev, &netcfg.max_virtqueue_pairs, n->max_queues); virtio_stw_p(vdev, &netcfg.mtu, n->net_conf.mtu); @@ -138,6 +141,15 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) virtio_stl_p(vdev, &netcfg.supported_hash_types, VIRTIO_NET_RSS_SUPPORTED_HASHES); memcpy(config, &netcfg, n->config_size); + + NetClientState *nc = qemu_get_queue(n->nic); + if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { + ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg, + n->config_size); + if (ret != -1) { + memcpy(config, &netcfg, n->config_size); + } + } } static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) @@ -153,6 +165,13 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) memcpy(n->mac, netcfg.mac, ETH_ALEN); qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); } + + NetClientState *nc = qemu_get_queue(n->nic); + if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { + vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg, + 0, n->config_size, + VHOST_SET_CONFIG_TYPE_MASTER); + } } static bool virtio_net_started(VirtIONet *n, uint8_t status) diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index a986708186..fc91719b4a 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -5,6 +5,7 @@ obj-y += virtio.o obj-$(CONFIG_VHOST) += vhost.o vhost-backend.o common-obj-$(call lnot,$(CONFIG_VHOST)) += vhost-stub.o obj-$(CONFIG_VHOST_USER) += vhost-user.o +obj-$(CONFIG_VHOST_VDPA) += vhost-vdpa.o common-obj-$(CONFIG_VIRTIO_RNG) += virtio-rng.o common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index 48905383f8..782b1d67d9 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -15,6 +15,7 @@ #include "qemu/main-loop.h" #include "standard-headers/linux/vhost_types.h" +#include "hw/virtio/vhost-vdpa.h" #ifdef CONFIG_VHOST_KERNEL #include #include @@ -285,6 +286,11 @@ int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type) case VHOST_BACKEND_TYPE_USER: dev->vhost_ops = &user_ops; break; +#endif +#ifdef CONFIG_VHOST_VDPA + case VHOST_BACKEND_TYPE_VDPA: + dev->vhost_ops = &vdpa_ops; + break; #endif default: error_report("Unknown vhost backend type"); diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c new file mode 100644 index 0000000000..a3d17fe0f9 --- /dev/null +++ b/hw/virtio/vhost-vdpa.c @@ -0,0 +1,475 @@ +/* + * vhost-vdpa + * + * Copyright(c) 2017-2018 Intel Corporation. + * Copyright(c) 2020 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. + * + */ + +#include "qemu/osdep.h" +#include +#include +#include +#include +#include "hw/virtio/vhost.h" +#include "hw/virtio/vhost-backend.h" +#include "hw/virtio/virtio-net.h" +#include "hw/virtio/vhost-vdpa.h" +#include "qemu/main-loop.h" +#include +#include "sysemu/kvm.h" + +static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section) +{ + return (!memory_region_is_ram(section->mr) && + !memory_region_is_iommu(section->mr)) || + /* + * Sizing an enabled 64-bit BAR can cause spurious mappings to + * addresses in the upper part of the 64-bit address space. These + * are never accessed by the CPU and beyond the address width of + * some IOMMU hardware. TODO: VDPA should tell us the IOMMU width. + */ + section->offset_within_address_space & (1ULL << 63); +} + +static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, + void *vaddr, bool readonly) +{ + struct vhost_msg_v2 msg; + int fd = v->device_fd; + int ret = 0; + + msg.type = v->msg_type; + msg.iotlb.iova = iova; + msg.iotlb.size = size; + msg.iotlb.uaddr = (uint64_t)(uintptr_t)vaddr; + msg.iotlb.perm = readonly ? VHOST_ACCESS_RO : VHOST_ACCESS_RW; + msg.iotlb.type = VHOST_IOTLB_UPDATE; + + if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { + error_report("failed to write, fd=%d, errno=%d (%s)", + fd, errno, strerror(errno)); + return -EIO ; + } + + return ret; +} + +static int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, + hwaddr size) +{ + struct vhost_msg_v2 msg; + int fd = v->device_fd; + int ret = 0; + + msg.type = v->msg_type; + msg.iotlb.iova = iova; + msg.iotlb.size = size; + msg.iotlb.type = VHOST_IOTLB_INVALIDATE; + + if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { + error_report("failed to write, fd=%d, errno=%d (%s)", + fd, errno, strerror(errno)); + return -EIO ; + } + + return ret; +} + +static void vhost_vdpa_listener_region_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener); + hwaddr iova; + Int128 llend, llsize; + void *vaddr; + int ret; + + if (vhost_vdpa_listener_skipped_section(section)) { + return; + } + + if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != + (section->offset_within_region & ~TARGET_PAGE_MASK))) { + error_report("%s received unaligned region", __func__); + return; + } + + iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); + llend = int128_make64(section->offset_within_address_space); + llend = int128_add(llend, section->size); + llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK)); + + if (int128_ge(int128_make64(iova), llend)) { + return; + } + + memory_region_ref(section->mr); + + /* Here we assume that memory_region_is_ram(section->mr)==true */ + + vaddr = memory_region_get_ram_ptr(section->mr) + + section->offset_within_region + + (iova - section->offset_within_address_space); + + llsize = int128_sub(llend, int128_make64(iova)); + + ret = vhost_vdpa_dma_map(v, iova, int128_get64(llsize), + vaddr, section->readonly); + if (ret) { + error_report("vhost vdpa map fail!"); + if (memory_region_is_ram_device(section->mr)) { + /* Allow unexpected mappings not to be fatal for RAM devices */ + error_report("map ram fail!"); + return ; + } + goto fail; + } + + return; + +fail: + if (memory_region_is_ram_device(section->mr)) { + error_report("failed to vdpa_dma_map. pci p2p may not work"); + return; + + } + /* + * On the initfn path, store the first error in the container so we + * can gracefully fail. Runtime, there's not much we can do other + * than throw a hardware error. + */ + error_report("vhost-vdpa: DMA mapping failed, unable to continue"); + return; + +} + +static void vhost_vdpa_listener_region_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener); + hwaddr iova; + Int128 llend, llsize; + int ret; + bool try_unmap = true; + + if (vhost_vdpa_listener_skipped_section(section)) { + return; + } + + if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != + (section->offset_within_region & ~TARGET_PAGE_MASK))) { + error_report("%s received unaligned region", __func__); + return; + } + + iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); + llend = int128_make64(section->offset_within_address_space); + llend = int128_add(llend, section->size); + llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK)); + + if (int128_ge(int128_make64(iova), llend)) { + return; + } + + llsize = int128_sub(llend, int128_make64(iova)); + + if (try_unmap) { + ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize)); + if (ret) { + error_report("vhost_vdpa dma unmap error!"); + } + } + + memory_region_unref(section->mr); +} +/* + * IOTLB API is used by vhost-vpda which requires incremental updating + * of the mapping. So we can not use generic vhost memory listener which + * depends on the addnop(). + */ +static const MemoryListener vhost_vdpa_memory_listener = { + .region_add = vhost_vdpa_listener_region_add, + .region_del = vhost_vdpa_listener_region_del, +}; + +static int vhost_vdpa_call(struct vhost_dev *dev, unsigned long int request, + void *arg) +{ + struct vhost_vdpa *v = dev->opaque; + int fd = v->device_fd; + + assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA); + + return ioctl(fd, request, arg); +} + +static void vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) +{ + uint8_t s; + + if (vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s)) { + return; + } + + s |= status; + + vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &s); +} + +static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque) +{ + struct vhost_vdpa *v; + uint64_t features; + assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA); + + v = opaque; + dev->opaque = opaque ; + vhost_vdpa_call(dev, VHOST_GET_FEATURES, &features); + dev->backend_features = features; + v->listener = vhost_vdpa_memory_listener; + v->msg_type = VHOST_IOTLB_MSG_V2; + + vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER); + + return 0; +} + +static int vhost_vdpa_cleanup(struct vhost_dev *dev) +{ + struct vhost_vdpa *v; + assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA); + v = dev->opaque; + memory_listener_unregister(&v->listener); + + dev->opaque = NULL; + return 0; +} + +static int vhost_vdpa_memslots_limit(struct vhost_dev *dev) +{ + return INT_MAX; +} + +static int vhost_vdpa_set_mem_table(struct vhost_dev *dev, + struct vhost_memory *mem) +{ + + if (mem->padding) { + return -1; + } + + return 0; +} + +static int vhost_vdpa_set_features(struct vhost_dev *dev, + uint64_t features) +{ + int ret; + ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features); + uint8_t status = 0; + if (ret) { + return ret; + } + vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); + vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status); + + return !(status & VIRTIO_CONFIG_S_FEATURES_OK); +} + +int vhost_vdpa_get_device_id(struct vhost_dev *dev, + uint32_t *device_id) +{ + return vhost_vdpa_call(dev, VHOST_VDPA_GET_DEVICE_ID, device_id); +} + +static int vhost_vdpa_reset_device(struct vhost_dev *dev) +{ + uint8_t status = 0; + + return vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status); +} + +static int vhost_vdpa_get_vq_index(struct vhost_dev *dev, int idx) +{ + assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); + + return idx - dev->vq_index; +} + +static int vhost_vdpa_set_vring_ready(struct vhost_dev *dev) +{ + int i; + for (i = 0; i < dev->nvqs; ++i) { + struct vhost_vring_state state = { + .index = dev->vq_index + i, + .num = 1, + }; + vhost_vdpa_call(dev, VHOST_VDPA_SET_VRING_ENABLE, &state); + } + return 0; +} + +static int vhost_vdpa_set_config(struct vhost_dev *dev, const uint8_t *data, + uint32_t offset, uint32_t size, + uint32_t flags) +{ + struct vhost_vdpa_config *config; + int ret; + unsigned long config_size = offsetof(struct vhost_vdpa_config, buf); + config = g_malloc(size + config_size); + if (config == NULL) { + return -1; + } + config->off = offset; + config->len = size; + memcpy(config->buf, data, size); + ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG, config); + g_free(config); + return ret; +} + +static int vhost_vdpa_get_config(struct vhost_dev *dev, uint8_t *config, + uint32_t config_len) +{ + struct vhost_vdpa_config *v_config; + unsigned long config_size = offsetof(struct vhost_vdpa_config, buf); + int ret; + + v_config = g_malloc(config_len + config_size); + if (v_config == NULL) { + return -1; + } + v_config->len = config_len; + v_config->off = 0; + ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_CONFIG, v_config); + memcpy(config, v_config->buf, config_len); + g_free(v_config); + return ret; + } + +static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) +{ + struct vhost_vdpa *v = dev->opaque; + if (started) { + uint8_t status = 0; + memory_listener_register(&v->listener, &address_space_memory); + vhost_vdpa_set_vring_ready(dev); + vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); + vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status); + + return !(status & VIRTIO_CONFIG_S_DRIVER_OK); + } else { + vhost_vdpa_reset_device(dev); + vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER); + memory_listener_unregister(&v->listener); + + return 0; + } +} + +static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, + struct vhost_log *log) +{ + return vhost_vdpa_call(dev, VHOST_SET_LOG_BASE, &base); +} + +static int vhost_vdpa_set_vring_addr(struct vhost_dev *dev, + struct vhost_vring_addr *addr) +{ + return vhost_vdpa_call(dev, VHOST_SET_VRING_ADDR, addr); +} + +static int vhost_vdpa_set_vring_num(struct vhost_dev *dev, + struct vhost_vring_state *ring) +{ + return vhost_vdpa_call(dev, VHOST_SET_VRING_NUM, ring); +} + +static int vhost_vdpa_set_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) +{ + return vhost_vdpa_call(dev, VHOST_SET_VRING_BASE, ring); +} + +static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) +{ + return vhost_vdpa_call(dev, VHOST_GET_VRING_BASE, ring); +} + +static int vhost_vdpa_set_vring_kick(struct vhost_dev *dev, + struct vhost_vring_file *file) +{ + return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file); +} + +static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, + struct vhost_vring_file *file) +{ + return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); +} + +static int vhost_vdpa_get_features(struct vhost_dev *dev, + uint64_t *features) +{ + return vhost_vdpa_call(dev, VHOST_GET_FEATURES, features); +} + +static int vhost_vdpa_set_owner(struct vhost_dev *dev) +{ + return vhost_vdpa_call(dev, VHOST_SET_OWNER, NULL); +} + +static int vhost_vdpa_vq_get_addr(struct vhost_dev *dev, + struct vhost_vring_addr *addr, struct vhost_virtqueue *vq) +{ + assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA); + addr->desc_user_addr = (uint64_t)(unsigned long)vq->desc_phys; + addr->avail_user_addr = (uint64_t)(unsigned long)vq->avail_phys; + addr->used_user_addr = (uint64_t)(unsigned long)vq->used_phys; + return 0; +} + +static bool vhost_vdpa_force_iommu(struct vhost_dev *dev) +{ + return true; +} + +const VhostOps vdpa_ops = { + .backend_type = VHOST_BACKEND_TYPE_VDPA, + .vhost_backend_init = vhost_vdpa_init, + .vhost_backend_cleanup = vhost_vdpa_cleanup, + .vhost_set_log_base = vhost_vdpa_set_log_base, + .vhost_set_vring_addr = vhost_vdpa_set_vring_addr, + .vhost_set_vring_num = vhost_vdpa_set_vring_num, + .vhost_set_vring_base = vhost_vdpa_set_vring_base, + .vhost_get_vring_base = vhost_vdpa_get_vring_base, + .vhost_set_vring_kick = vhost_vdpa_set_vring_kick, + .vhost_set_vring_call = vhost_vdpa_set_vring_call, + .vhost_get_features = vhost_vdpa_get_features, + .vhost_set_owner = vhost_vdpa_set_owner, + .vhost_set_vring_endian = NULL, + .vhost_backend_memslots_limit = vhost_vdpa_memslots_limit, + .vhost_set_mem_table = vhost_vdpa_set_mem_table, + .vhost_set_features = vhost_vdpa_set_features, + .vhost_reset_device = vhost_vdpa_reset_device, + .vhost_get_vq_index = vhost_vdpa_get_vq_index, + .vhost_get_config = vhost_vdpa_get_config, + .vhost_set_config = vhost_vdpa_set_config, + .vhost_requires_shm_log = NULL, + .vhost_migration_done = NULL, + .vhost_backend_can_merge = NULL, + .vhost_net_set_mtu = NULL, + .vhost_set_iotlb_callback = NULL, + .vhost_send_device_iotlb_msg = NULL, + .vhost_dev_start = vhost_vdpa_dev_start, + .vhost_get_device_id = vhost_vdpa_get_device_id, + .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, + .vhost_force_iommu = vhost_vdpa_force_iommu, +}; diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index e7cb8d028c..8825bd278f 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -17,7 +17,8 @@ typedef enum VhostBackendType { VHOST_BACKEND_TYPE_NONE = 0, VHOST_BACKEND_TYPE_KERNEL = 1, VHOST_BACKEND_TYPE_USER = 2, - VHOST_BACKEND_TYPE_MAX = 3, + VHOST_BACKEND_TYPE_VDPA = 3, + VHOST_BACKEND_TYPE_MAX = 4, } VhostBackendType; typedef enum VhostSetConfigType { @@ -170,6 +171,7 @@ typedef struct VhostOps { } VhostOps; extern const VhostOps user_ops; +extern const VhostOps vdpa_ops; int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type); diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h new file mode 100644 index 0000000000..6455663388 --- /dev/null +++ b/include/hw/virtio/vhost-vdpa.h @@ -0,0 +1,26 @@ +/* + * vhost-vdpa.h + * + * Copyright(c) 2017-2018 Intel Corporation. + * Copyright(c) 2020 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. + * + */ + +#ifndef HW_VIRTIO_VHOST_VDPA_H +#define HW_VIRTIO_VHOST_VDPA_H + +#include "hw/virtio/virtio.h" + +typedef struct vhost_vdpa { + int device_fd; + uint32_t msg_type; + MemoryListener listener; +} VhostVDPA; + +extern AddressSpace address_space_memory; +extern int vhost_vdpa_get_device_id(struct vhost_dev *dev, + uint32_t *device_id); +#endif diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 085450c6f8..767a95ec0b 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -92,6 +92,13 @@ struct vhost_dev { const VhostDevConfigOps *config_ops; }; +struct vhost_net { + struct vhost_dev dev; + struct vhost_virtqueue vqs[2]; + int backend; + NetClientState *nc; +}; + int vhost_dev_init(struct vhost_dev *hdev, void *opaque, VhostBackendType backend_type, uint32_t busyloop_timeout); diff --git a/qemu-options.hx b/qemu-options.hx index 196f468786..fa1b19de4c 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2418,6 +2418,10 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, #ifdef CONFIG_POSIX "-netdev vhost-user,id=str,chardev=dev[,vhostforce=on|off]\n" " configure a vhost-user network, backed by a chardev 'dev'\n" +#endif +#ifdef __linux__ + "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n" + " configure a vhost-vdpa network,Establish a vhost-vdpa netdev\n" #endif "-netdev hubport,id=str,hubid=n[,netdev=nd]\n" " configure a hub port on the hub with ID 'n'\n", QEMU_ARCH_ALL) @@ -2897,6 +2901,14 @@ SRST -netdev type=vhost-user,id=net0,chardev=chr0 \ -device virtio-net-pci,netdev=net0 +``-netdev vhost-vdpa,vhostdev=/path/to/dev`` + Establish a vhost-vdpa netdev. + + vDPA device is a device that uses a datapath which complies with + the virtio specifications with a vendor specific control path. + vDPA devices can be both physically located on the hardware or + emulated by software. + ``-netdev hubport,id=id,hubid=hubid[,netdev=nd]`` Create a hub port on the emulated hub with ID hubid. From 1e0a84ea49b68b7cf60e229d91fd16333e0b7a90 Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Wed, 1 Jul 2020 22:55:38 +0800 Subject: [PATCH 2016/2595] vhost-vdpa: introduce vhost-vdpa net client This patch set introduces a new net client type: vhost-vdpa. vhost-vdpa net client will set up a vDPA device which is specified by a "vhostdev" parameter. Signed-off-by: Lingshan Zhu Signed-off-by: Tiwei Bie Signed-off-by: Cindy Lu Signed-off-by: Jason Wang Message-Id: <20200701145538.22333-15-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- include/net/vhost-vdpa.h | 22 ++++ net/Makefile.objs | 2 +- net/clients.h | 2 + net/net.c | 3 + net/vhost-vdpa.c | 228 +++++++++++++++++++++++++++++++++++++++ qapi/net.json | 28 ++++- 6 files changed, 282 insertions(+), 3 deletions(-) create mode 100644 include/net/vhost-vdpa.h create mode 100644 net/vhost-vdpa.c diff --git a/include/net/vhost-vdpa.h b/include/net/vhost-vdpa.h new file mode 100644 index 0000000000..45e34b7cfc --- /dev/null +++ b/include/net/vhost-vdpa.h @@ -0,0 +1,22 @@ +/* + * vhost-vdpa.h + * + * Copyright(c) 2017-2018 Intel Corporation. + * Copyright(c) 2020 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. + * + */ + +#ifndef VHOST_VDPA_H +#define VHOST_VDPA_H + +#define TYPE_VHOST_VDPA "vhost-vdpa" + +struct vhost_net *vhost_vdpa_get_vhost_net(NetClientState *nc); +uint64_t vhost_vdpa_get_acked_features(NetClientState *nc); + +extern const int vdpa_feature_bits[]; + +#endif /* VHOST_VDPA_H */ diff --git a/net/Makefile.objs b/net/Makefile.objs index c5d076d19c..5ab45545db 100644 --- a/net/Makefile.objs +++ b/net/Makefile.objs @@ -26,7 +26,7 @@ tap-obj-$(CONFIG_SOLARIS) = tap-solaris.o tap-obj-y ?= tap-stub.o common-obj-$(CONFIG_POSIX) += tap.o $(tap-obj-y) common-obj-$(CONFIG_WIN32) += tap-win32.o - +common-obj-$(CONFIG_VHOST_NET_VDPA) += vhost-vdpa.o vde.o-libs = $(VDE_LIBS) common-obj-$(CONFIG_CAN_BUS) += can/ diff --git a/net/clients.h b/net/clients.h index a6ef267e19..92f9b59aed 100644 --- a/net/clients.h +++ b/net/clients.h @@ -61,4 +61,6 @@ int net_init_netmap(const Netdev *netdev, const char *name, int net_init_vhost_user(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); +int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); #endif /* QEMU_NET_CLIENTS_H */ diff --git a/net/net.c b/net/net.c index 9099a327dd..94dc546fb2 100644 --- a/net/net.c +++ b/net/net.c @@ -966,6 +966,9 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( #ifdef CONFIG_VHOST_NET_USER [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user, #endif +#ifdef CONFIG_VHOST_NET_VDPA + [NET_CLIENT_DRIVER_VHOST_VDPA] = net_init_vhost_vdpa, +#endif #ifdef CONFIG_L2TPV3 [NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3, #endif diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c new file mode 100644 index 0000000000..bc0e0d2d35 --- /dev/null +++ b/net/vhost-vdpa.c @@ -0,0 +1,228 @@ +/* + * vhost-vdpa.c + * + * Copyright(c) 2017-2018 Intel Corporation. + * Copyright(c) 2020 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. + * + */ + +#include "qemu/osdep.h" +#include "clients.h" +#include "net/vhost_net.h" +#include "net/vhost-vdpa.h" +#include "hw/virtio/vhost-vdpa.h" +#include "qemu/config-file.h" +#include "qemu/error-report.h" +#include "qemu/option.h" +#include "qapi/error.h" +#include +#include +#include "standard-headers/linux/virtio_net.h" +#include "monitor/monitor.h" +#include "hw/virtio/vhost.h" + +/* Todo:need to add the multiqueue support here */ +typedef struct VhostVDPAState { + NetClientState nc; + struct vhost_vdpa vhost_vdpa; + VHostNetState *vhost_net; + uint64_t acked_features; + bool started; +} VhostVDPAState; + +const int vdpa_feature_bits[] = { + VIRTIO_F_NOTIFY_ON_EMPTY, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_F_ANY_LAYOUT, + VIRTIO_F_VERSION_1, + VIRTIO_NET_F_CSUM, + VIRTIO_NET_F_GUEST_CSUM, + VIRTIO_NET_F_GSO, + VIRTIO_NET_F_GUEST_TSO4, + VIRTIO_NET_F_GUEST_TSO6, + VIRTIO_NET_F_GUEST_ECN, + VIRTIO_NET_F_GUEST_UFO, + VIRTIO_NET_F_HOST_TSO4, + VIRTIO_NET_F_HOST_TSO6, + VIRTIO_NET_F_HOST_ECN, + VIRTIO_NET_F_HOST_UFO, + VIRTIO_NET_F_MRG_RXBUF, + VIRTIO_NET_F_MTU, + VIRTIO_F_IOMMU_PLATFORM, + VIRTIO_F_RING_PACKED, + VIRTIO_NET_F_GUEST_ANNOUNCE, + VHOST_INVALID_FEATURE_BIT +}; + +VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) +{ + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + return s->vhost_net; +} + +uint64_t vhost_vdpa_get_acked_features(NetClientState *nc) +{ + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + s->acked_features = vhost_net_get_acked_features(s->vhost_net); + + return s->acked_features; +} + +static int vhost_vdpa_net_check_device_id(struct vhost_net *net) +{ + uint32_t device_id; + int ret; + struct vhost_dev *hdev; + + hdev = (struct vhost_dev *)&net->dev; + ret = hdev->vhost_ops->vhost_get_device_id(hdev, &device_id); + if (device_id != VIRTIO_ID_NET) { + return -ENOTSUP; + } + return ret; +} + +static void vhost_vdpa_del(NetClientState *ncs) +{ + VhostVDPAState *s; + assert(ncs->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + s = DO_UPCAST(VhostVDPAState, nc, ncs); + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); + } +} + +static int vhost_vdpa_add(NetClientState *ncs, void *be) +{ + VhostNetOptions options; + struct vhost_net *net = NULL; + VhostVDPAState *s; + int ret; + + options.backend_type = VHOST_BACKEND_TYPE_VDPA; + assert(ncs->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + s = DO_UPCAST(VhostVDPAState, nc, ncs); + options.net_backend = ncs; + options.opaque = be; + options.busyloop_timeout = 0; + + net = vhost_net_init(&options); + if (!net) { + error_report("failed to init vhost_net for queue"); + goto err; + } + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); + } + s->vhost_net = net; + ret = vhost_vdpa_net_check_device_id(net); + if (ret) { + goto err; + } + return 0; +err: + if (net) { + vhost_net_cleanup(net); + } + vhost_vdpa_del(ncs); + return -1; +} + +static void vhost_vdpa_cleanup(NetClientState *nc) +{ + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); + + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); + s->vhost_net = NULL; + } +} + +static bool vhost_vdpa_has_vnet_hdr(NetClientState *nc) +{ + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + + return true; +} + +static bool vhost_vdpa_has_ufo(NetClientState *nc) +{ + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); + uint64_t features = 0; + features |= (1ULL << VIRTIO_NET_F_HOST_UFO); + features = vhost_net_get_features(s->vhost_net, features); + return !!(features & (1ULL << VIRTIO_NET_F_HOST_UFO)); + +} + +static NetClientInfo net_vhost_vdpa_info = { + .type = NET_CLIENT_DRIVER_VHOST_VDPA, + .size = sizeof(VhostVDPAState), + .cleanup = vhost_vdpa_cleanup, + .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, + .has_ufo = vhost_vdpa_has_ufo, +}; + +static int net_vhost_vdpa_init(NetClientState *peer, const char *device, + const char *name, const char *vhostdev) +{ + NetClientState *nc = NULL; + VhostVDPAState *s; + int vdpa_device_fd = -1; + int ret = 0; + assert(name); + nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, name); + snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA); + nc->queue_index = 0; + s = DO_UPCAST(VhostVDPAState, nc, nc); + vdpa_device_fd = qemu_open(vhostdev, O_RDWR); + if (vdpa_device_fd == -1) { + return -errno; + } + s->vhost_vdpa.device_fd = vdpa_device_fd; + ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa); + assert(s->vhost_net); + return ret; +} + +static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp) +{ + const char *name = opaque; + const char *driver, *netdev; + + driver = qemu_opt_get(opts, "driver"); + netdev = qemu_opt_get(opts, "netdev"); + if (!driver || !netdev) { + return 0; + } + if (strcmp(netdev, name) == 0 && + !g_str_has_prefix(driver, "virtio-net-")) { + error_setg(errp, "vhost-vdpa requires frontend driver virtio-net-*"); + return -1; + } + return 0; +} + +int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + const NetdevVhostVDPAOptions *opts; + + assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); + opts = &netdev->u.vhost_vdpa; + /* verify net frontend */ + if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net, + (char *)name, errp)) { + return -1; + } + return net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, opts->vhostdev); +} diff --git a/qapi/net.json b/qapi/net.json index 9244c9af56..558d520a2f 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -428,16 +428,39 @@ '*vhostforce': 'bool', '*queues': 'int' } } +## +# @NetdevVhostVDPAOptions: +# +# Vhost-vdpa network backend +# +# vDPA device is a device that uses a datapath which complies with the virtio +# specifications with a vendor specific control path. +# +# @vhostdev: path of vhost-vdpa device +# (default:'/dev/vhost-vdpa-0') +# +# @queues: number of queues to be created for multiqueue vhost-vdpa +# (default: 1) +# +# Since: 5.1 +## +{ 'struct': 'NetdevVhostVDPAOptions', + 'data': { + '*vhostdev': 'str', + '*queues': 'int' } } + ## # @NetClientDriver: # # Available netdev drivers. # # Since: 2.7 +# +# @vhost-vdpa since 5.1 ## { 'enum': 'NetClientDriver', 'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde', - 'bridge', 'hubport', 'netmap', 'vhost-user' ] } + 'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa' ] } ## # @Netdev: @@ -465,7 +488,8 @@ 'bridge': 'NetdevBridgeOptions', 'hubport': 'NetdevHubPortOptions', 'netmap': 'NetdevNetmapOptions', - 'vhost-user': 'NetdevVhostUserOptions' } } + 'vhost-user': 'NetdevVhostUserOptions', + 'vhost-vdpa': 'NetdevVhostVDPAOptions' } } ## # @NetFilterDirection: From 28457744c345ca4ccb58c984c9552e9c5955a9de Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2020 15:10:36 +0200 Subject: [PATCH 2017/2595] module: qom module support Add support for qom types provided by modules. For starters use a manually maintained list which maps qom type to module and prefix. Two load functions are added: One to load the module for a specific type, and one to load all modules (needed for object/device lists as printed by -- for example -- qemu -device help). Signed-off-by: Gerd Hoffmann Message-id: 20200624131045.14512-2-kraxel@redhat.com --- include/qemu/module.h | 2 ++ util/module.c | 55 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/include/qemu/module.h b/include/qemu/module.h index 011ae1ae76..9121a475c1 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -70,5 +70,7 @@ void register_dso_module_init(void (*fn)(void), module_init_type type); void module_call_init(module_init_type type); bool module_load_one(const char *prefix, const char *lib_name); +void module_load_qom_one(const char *type); +void module_load_qom_all(void); #endif diff --git a/util/module.c b/util/module.c index e48d9aacc0..ee560a4b42 100644 --- a/util/module.c +++ b/util/module.c @@ -245,3 +245,58 @@ bool module_load_one(const char *prefix, const char *lib_name) #endif return success; } + +/* + * Building devices and other qom objects modular is mostly useful in + * case they have dependencies to external shared libraries, so we can + * cut down the core qemu library dependencies. Which is the case for + * only a very few devices & objects. + * + * So with the expectation that this will be rather the exception than + * to rule and the list will not gain that many entries go with a + * simple manually maintained list for now. + */ +static struct { + const char *type; + const char *prefix; + const char *module; +} const qom_modules[] = { +}; + +static bool module_loaded_qom_all; + +void module_load_qom_one(const char *type) +{ + int i; + + if (module_loaded_qom_all) { + return; + } + for (i = 0; i < ARRAY_SIZE(qom_modules); i++) { + if (strcmp(qom_modules[i].type, type) == 0) { + module_load_one(qom_modules[i].prefix, + qom_modules[i].module); + return; + } + } +} + +void module_load_qom_all(void) +{ + int i; + + if (module_loaded_qom_all) { + return; + } + for (i = 0; i < ARRAY_SIZE(qom_modules); i++) { + if (i > 0 && (strcmp(qom_modules[i - 1].module, + qom_modules[i].module) == 0 && + strcmp(qom_modules[i - 1].prefix, + qom_modules[i].prefix) == 0)) { + /* one module implementing multiple types -> load only once */ + continue; + } + module_load_one(qom_modules[i].prefix, qom_modules[i].module); + } + module_loaded_qom_all = true; +} From 0f8198f1b2f3c33df2381c412ad8d8fd219b90b2 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2020 15:10:37 +0200 Subject: [PATCH 2018/2595] object: qom module support Little helper function to load modules on demand. In most cases adding module loading support for devices and other objects is just s/object_class_by_name/module_object_class_by_name/ in the right spot. Signed-off-by: Gerd Hoffmann Message-id: 20200624131045.14512-3-kraxel@redhat.com --- include/qom/object.h | 12 ++++++++++++ qom/object.c | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/include/qom/object.h b/include/qom/object.h index 94a61ccc3f..51f188137f 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -994,6 +994,18 @@ bool object_class_is_abstract(ObjectClass *klass); */ ObjectClass *object_class_by_name(const char *typename); +/** + * module_object_class_by_name: + * @typename: The QOM typename to obtain the class for. + * + * For objects which might be provided by a module. Behaves like + * object_class_by_name, but additionally tries to load the module + * needed in case the class is not available. + * + * Returns: The class for @typename or %NULL if not found. + */ +ObjectClass *module_object_class_by_name(const char *typename); + void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), const char *implements_type, bool include_abstract, void *opaque); diff --git a/qom/object.c b/qom/object.c index 6ece96bc2b..34daaf1280 100644 --- a/qom/object.c +++ b/qom/object.c @@ -985,6 +985,20 @@ ObjectClass *object_class_by_name(const char *typename) return type->class; } +ObjectClass *module_object_class_by_name(const char *typename) +{ + ObjectClass *oc; + + oc = object_class_by_name(typename); +#ifdef CONFIG_MODULES + if (!oc) { + module_load_qom_one(typename); + oc = object_class_by_name(typename); + } +#endif + return oc; +} + ObjectClass *object_class_get_parent(ObjectClass *class) { TypeImpl *type = type_get_parent(class->type); From 7ab6e7fcce9729d3a85e7e04737bc64a45a08772 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2020 15:10:38 +0200 Subject: [PATCH 2019/2595] qdev: device module support Hook module loading into the places where we need it when building devices as modules. Signed-off-by: Gerd Hoffmann Message-id: 20200624131045.14512-4-kraxel@redhat.com --- hw/core/qdev.c | 6 ++++-- qdev-monitor.c | 5 +++-- qom/qom-qmp-cmds.c | 3 ++- softmmu/vl.c | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 2131c7f951..9de16eae05 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -137,6 +137,9 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus) */ DeviceState *qdev_new(const char *name) { + if (!object_class_by_name(name)) { + module_load_qom_one(name); + } return DEVICE(object_new(name)); } @@ -147,10 +150,9 @@ DeviceState *qdev_new(const char *name) */ DeviceState *qdev_try_new(const char *name) { - if (!object_class_by_name(name)) { + if (!module_object_class_by_name(name)) { return NULL; } - return DEVICE(object_new(name)); } diff --git a/qdev-monitor.c b/qdev-monitor.c index 22da107484..8e7a7f7bbd 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -147,6 +147,7 @@ static void qdev_print_devinfos(bool show_no_user) int i; bool cat_printed; + module_load_qom_all(); list = object_class_get_list_sorted(TYPE_DEVICE, false); for (i = 0; i <= DEVICE_CATEGORY_MAX; i++) { @@ -215,13 +216,13 @@ static DeviceClass *qdev_get_device_class(const char **driver, Error **errp) DeviceClass *dc; const char *original_name = *driver; - oc = object_class_by_name(*driver); + oc = module_object_class_by_name(*driver); if (!oc) { const char *typename = find_typename_by_alias(*driver); if (typename) { *driver = typename; - oc = object_class_by_name(*driver); + oc = module_object_class_by_name(*driver); } } diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c index c5249e44d0..5e2c8cbf33 100644 --- a/qom/qom-qmp-cmds.c +++ b/qom/qom-qmp-cmds.c @@ -116,6 +116,7 @@ ObjectTypeInfoList *qmp_qom_list_types(bool has_implements, { ObjectTypeInfoList *ret = NULL; + module_load_qom_all(); object_class_foreach(qom_list_types_tramp, implements, abstract, &ret); return ret; @@ -130,7 +131,7 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename, ObjectPropertyIterator iter; ObjectPropertyInfoList *prop_list = NULL; - klass = object_class_by_name(typename); + klass = module_object_class_by_name(typename); if (klass == NULL) { error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found", typename); diff --git a/softmmu/vl.c b/softmmu/vl.c index 3e15ee2435..5acb65d7f4 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1772,8 +1772,8 @@ static bool vga_interface_available(VGAInterfaceType t) assert(t < VGA_TYPE_MAX); return !ti->class_names[0] || - object_class_by_name(ti->class_names[0]) || - object_class_by_name(ti->class_names[1]); + module_object_class_by_name(ti->class_names[0]) || + module_object_class_by_name(ti->class_names[1]); } static const char * From c4ddab7ae5362669837d5d63ccc55f1ffa190eca Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2020 15:10:39 +0200 Subject: [PATCH 2020/2595] build: fix device module builds Slightly hackish workaround, works ok as long as we don't have target-specific modules. meson will obsolete this. See comment in the patch for the --verbose description. Signed-off-by: Gerd Hoffmann Message-id: 20200624131045.14512-5-kraxel@redhat.com [ kraxel: updated comment from discussions ] Signed-off-by: Gerd Hoffmann --- Makefile.target | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Makefile.target b/Makefile.target index 8ed1eba95b..02bd9d7117 100644 --- a/Makefile.target +++ b/Makefile.target @@ -179,6 +179,20 @@ endif # CONFIG_SOFTMMU dummy := $(call unnest-vars,,obj-y) all-obj-y := $(obj-y) +# +# common-obj-m has some crap here, probably as side effect from +# unnest-vars recursing into target directories to fill obj-y and not +# properly handling the -m case. +# +# Clear common-obj-m as workaround. Fixes suspious dependency errors +# when building devices as modules. A bit hackish, but should be ok +# as long as we do not have any target-specific modules. +# +# The meson-based build system currently in development doesn't need +# unnest-vars and will obsolete this workaround. +# +common-obj-m := + include $(SRC_PATH)/Makefile.objs dummy := $(call unnest-vars,.., \ authz-obj-y \ From 8887312b406f71aee18aeb7e5ac4b18f461f4a79 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2020 15:10:40 +0200 Subject: [PATCH 2021/2595] ccid: build smartcard as module Drops libcacard.so dependency from core qemu. Signed-off-by: Gerd Hoffmann Message-id: 20200624131045.14512-6-kraxel@redhat.com --- Makefile.objs | 1 + hw/Makefile.objs | 1 + hw/usb/Makefile.objs | 4 +++- util/module.c | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile.objs b/Makefile.objs index 98383972ee..3d45492d8b 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -59,6 +59,7 @@ common-obj-y += migration/ common-obj-y += audio/ common-obj-m += audio/ common-obj-y += hw/ +common-obj-m += hw/ common-obj-y += replay/ diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 4cbe5e4e57..af8fd9a510 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -43,4 +43,5 @@ devices-dirs-y += smbios/ endif common-obj-y += $(devices-dirs-y) +common-obj-m += usb/ obj-y += $(devices-dirs-y) diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index fa5c3fa1b8..3c5b3d4fad 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -29,11 +29,13 @@ common-obj-$(CONFIG_USB_NETWORK) += dev-network.o ifeq ($(CONFIG_USB_SMARTCARD),y) common-obj-y += dev-smartcard-reader.o -common-obj-$(CONFIG_SMARTCARD) += smartcard.mo +ifeq ($(CONFIG_SMARTCARD),y) +common-obj-m += smartcard.mo smartcard.mo-objs := ccid-card-passthru.o ccid-card-emulated.o smartcard.mo-cflags := $(SMARTCARD_CFLAGS) smartcard.mo-libs := $(SMARTCARD_LIBS) endif +endif ifeq ($(CONFIG_POSIX),y) common-obj-$(CONFIG_USB_STORAGE_MTP) += dev-mtp.o diff --git a/util/module.c b/util/module.c index ee560a4b42..89da9a3cce 100644 --- a/util/module.c +++ b/util/module.c @@ -261,6 +261,8 @@ static struct { const char *prefix; const char *module; } const qom_modules[] = { + { "ccid-card-passthru", "hw-", "usb-smartcard" }, + { "ccid-card-emulated", "hw-", "usb-smartcard" }, }; static bool module_loaded_qom_all; From aa9c8573be01fd7cdf56ff31df3af0307017a258 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2020 15:10:41 +0200 Subject: [PATCH 2022/2595] usb: build usb-redir as module Drops libusbredirparser.so dependency from core qemu. Signed-off-by: Gerd Hoffmann Message-id: 20200624131045.14512-7-kraxel@redhat.com --- hw/usb/Makefile.objs | 9 ++++++--- util/module.c | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 3c5b3d4fad..e342ff59fa 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -43,9 +43,12 @@ endif # usb redirection ifeq ($(CONFIG_USB),y) -common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o -redirect.o-cflags = $(USB_REDIR_CFLAGS) -redirect.o-libs = $(USB_REDIR_LIBS) +ifeq ($(CONFIG_USB_REDIR),y) +common-obj-m += redirect.mo +redirect.mo-objs = redirect.o quirks.o +redirect.mo-cflags = $(USB_REDIR_CFLAGS) +redirect.mo-libs = $(USB_REDIR_LIBS) +endif endif # usb pass-through diff --git a/util/module.c b/util/module.c index 89da9a3cce..e3226165e9 100644 --- a/util/module.c +++ b/util/module.c @@ -263,6 +263,7 @@ static struct { } const qom_modules[] = { { "ccid-card-passthru", "hw-", "usb-smartcard" }, { "ccid-card-emulated", "hw-", "usb-smartcard" }, + { "usb-redir", "hw-", "usb-redirect" }, }; static bool module_loaded_qom_all; From d39e93d4833a75a86cbb60ca5daf45b299b7c78c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2020 15:10:42 +0200 Subject: [PATCH 2023/2595] vga: build qxl as module First step in making spice support modular. Signed-off-by: Gerd Hoffmann Message-id: 20200624131045.14512-8-kraxel@redhat.com --- hw/Makefile.objs | 1 + hw/display/Makefile.objs | 5 ++++- util/module.c | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/Makefile.objs b/hw/Makefile.objs index af8fd9a510..14b7ea4eb6 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -43,5 +43,6 @@ devices-dirs-y += smbios/ endif common-obj-y += $(devices-dirs-y) +common-obj-m += display/ common-obj-m += usb/ obj-y += $(devices-dirs-y) diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index 77a7d622bd..76b3571e49 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -44,7 +44,10 @@ common-obj-$(CONFIG_ARTIST) += artist.o obj-$(CONFIG_VGA) += vga.o -common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o +ifeq ($(CONFIG_QXL),y) +common-obj-m += qxl.mo +qxl.mo-objs = qxl.o qxl-logger.o qxl-render.o +endif obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o diff --git a/util/module.c b/util/module.c index e3226165e9..7c76d2a84b 100644 --- a/util/module.c +++ b/util/module.c @@ -264,6 +264,8 @@ static struct { { "ccid-card-passthru", "hw-", "usb-smartcard" }, { "ccid-card-emulated", "hw-", "usb-smartcard" }, { "usb-redir", "hw-", "usb-redirect" }, + { "qxl-vga", "hw-", "display-qxl" }, + { "qxl", "hw-", "display-qxl" }, }; static bool module_loaded_qom_all; From 9ad7ecf6a69f80c29734da24b285cf6d3d7448af Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2020 15:10:43 +0200 Subject: [PATCH 2024/2595] vga: build virtio-gpu only once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 20200624131045.14512-9-kraxel@redhat.com --- hw/display/Makefile.objs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index 76b3571e49..d619594ad4 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -49,12 +49,12 @@ common-obj-m += qxl.mo qxl.mo-objs = qxl.o qxl-logger.o qxl-render.o endif -obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o -obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o -obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o -obj-$(call land,$(CONFIG_VHOST_USER_GPU),$(CONFIG_VIRTIO_PCI)) += vhost-user-gpu-pci.o -obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o -obj-$(CONFIG_VHOST_USER_VGA) += vhost-user-vga.o +common-obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o +common-obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o +common-obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o +common-obj-$(call land,$(CONFIG_VHOST_USER_GPU),$(CONFIG_VIRTIO_PCI)) += vhost-user-gpu-pci.o +common-obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o +common-obj-$(CONFIG_VHOST_USER_VGA) += vhost-user-vga.o virtio-gpu.o-cflags := $(VIRGL_CFLAGS) virtio-gpu.o-libs += $(VIRGL_LIBS) virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS) From 8d5a24c83dba90b08ef163bbf166d6dfbad9019b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2020 15:10:44 +0200 Subject: [PATCH 2025/2595] vga: build virtio-gpu as module Drops libvirglrenderer.so dependency from core qemu. Signed-off-by: Gerd Hoffmann Message-id: 20200624131045.14512-10-kraxel@redhat.com --- hw/display/Makefile.objs | 23 +++++++++++++---------- util/module.c | 6 ++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index d619594ad4..e907f3182b 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -49,16 +49,19 @@ common-obj-m += qxl.mo qxl.mo-objs = qxl.o qxl-logger.o qxl-render.o endif -common-obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o -common-obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o -common-obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o -common-obj-$(call land,$(CONFIG_VHOST_USER_GPU),$(CONFIG_VIRTIO_PCI)) += vhost-user-gpu-pci.o -common-obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o -common-obj-$(CONFIG_VHOST_USER_VGA) += vhost-user-vga.o -virtio-gpu.o-cflags := $(VIRGL_CFLAGS) -virtio-gpu.o-libs += $(VIRGL_LIBS) -virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS) -virtio-gpu-3d.o-libs += $(VIRGL_LIBS) +ifeq ($(CONFIG_VIRTIO_GPU),y) +common-obj-m += virtio-gpu.mo +virtio-gpu-obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o +virtio-gpu-obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o +virtio-gpu-obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o +virtio-gpu-obj-$(call land,$(CONFIG_VHOST_USER_GPU),$(CONFIG_VIRTIO_PCI)) += vhost-user-gpu-pci.o +virtio-gpu-obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o +virtio-gpu-obj-$(CONFIG_VHOST_USER_VGA) += vhost-user-vga.o +virtio-gpu.mo-objs := $(virtio-gpu-obj-y) +virtio-gpu.mo-cflags := $(VIRGL_CFLAGS) +virtio-gpu.mo-libs := $(VIRGL_LIBS) +endif + common-obj-$(CONFIG_DPCD) += dpcd.o common-obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx_dp.o diff --git a/util/module.c b/util/module.c index 7c76d2a84b..a74214eac0 100644 --- a/util/module.c +++ b/util/module.c @@ -266,6 +266,12 @@ static struct { { "usb-redir", "hw-", "usb-redirect" }, { "qxl-vga", "hw-", "display-qxl" }, { "qxl", "hw-", "display-qxl" }, + { "virtio-gpu-device", "hw-", "display-virtio-gpu" }, + { "virtio-gpu-pci", "hw-", "display-virtio-gpu" }, + { "virtio-vga", "hw-", "display-virtio-gpu" }, + { "vhost-user-gpu-device", "hw-", "display-virtio-gpu" }, + { "vhost-user-gpu-pci", "hw-", "display-virtio-gpu" }, + { "vhost-user-vga", "hw-", "display-virtio-gpu" }, }; static bool module_loaded_qom_all; From ef138c77249771081d8c2d09b8e729f7e92cdf28 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2020 15:10:45 +0200 Subject: [PATCH 2026/2595] chardev: enable modules, use for braille Removes brlapi library dependency from core qemu. Signed-off-by: Gerd Hoffmann Message-id: 20200624131045.14512-11-kraxel@redhat.com --- Makefile.objs | 1 + chardev/Makefile.objs | 5 ++++- chardev/char.c | 2 +- util/module.c | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index 3d45492d8b..d22b3b45d7 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -71,6 +71,7 @@ common-obj-$(CONFIG_TPM) += tpm.o common-obj-y += backends/ common-obj-y += chardev/ +common-obj-m += chardev/ common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o qemu-seccomp.o-cflags := $(SECCOMP_CFLAGS) diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs index d68e1347f9..3a58c9d329 100644 --- a/chardev/Makefile.objs +++ b/chardev/Makefile.objs @@ -18,8 +18,11 @@ chardev-obj-$(CONFIG_WIN32) += char-win.o chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o common-obj-y += msmouse.o wctablet.o testdev.o -common-obj-$(CONFIG_BRLAPI) += baum.o + +ifeq ($(CONFIG_BRLAPI),y) +common-obj-m += baum.o baum.o-cflags := $(SDL_CFLAGS) baum.o-libs := $(BRLAPI_LIBS) +endif common-obj-$(CONFIG_SPICE) += spice.o diff --git a/chardev/char.c b/chardev/char.c index e3051295ac..df697f3ce9 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -527,7 +527,7 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp) const ChardevClass *cc; char *typename = g_strdup_printf("chardev-%s", driver); - oc = object_class_by_name(typename); + oc = module_object_class_by_name(typename); g_free(typename); if (!object_class_dynamic_cast(oc, TYPE_CHARDEV)) { diff --git a/util/module.c b/util/module.c index a74214eac0..32b0547b82 100644 --- a/util/module.c +++ b/util/module.c @@ -272,6 +272,7 @@ static struct { { "vhost-user-gpu-device", "hw-", "display-virtio-gpu" }, { "vhost-user-gpu-pci", "hw-", "display-virtio-gpu" }, { "vhost-user-vga", "hw-", "display-virtio-gpu" }, + { "chardev-braille", "chardev-", "baum" }, }; static bool module_loaded_qom_all; From 27e08bab94f7c6ebe0b75938c98c394c969e3fd8 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 25 Jun 2020 15:07:57 +0100 Subject: [PATCH 2027/2595] tracetool: work around ust include conflict Both the dtrace and ust backends may include but LTTng Userspace Tracer 2.11 and later requires SDT_USE_VARIADIC to be defined before including the header file. This is a classic problem with C header files included from different parts of a program. If the same header is included twice within the same compilation unit then the first inclusion determines the macro environment. Work around this by defining SDT_USE_VARIADIC in the dtrace backend too. It doesn't hurt and fixes a missing STAP_PROBEV() compiler error when the ust backend is enabled together with the dtrace backend. Signed-off-by: Stefan Hajnoczi Message-id: 20200625140757.237012-1-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/backend/dtrace.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py index 5711892ba0..b7fe4c1b50 100644 --- a/scripts/tracetool/backend/dtrace.py +++ b/scripts/tracetool/backend/dtrace.py @@ -40,6 +40,12 @@ def generate_h_begin(events, group): else: header = "trace-dtrace.h" + # Workaround for ust backend, which also includes and may + # require SDT_USE_VARIADIC to be defined. If dtrace includes + # first without defining SDT_USE_VARIADIC then ust breaks because the + # STAP_PROBEV() macro is not defined. + out('#define SDT_USE_VARIADIC 1') + out('#include "%s"' % header, '') From 1e04092feecfc8caaf314df2670bf9c645a0b122 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 7 Jul 2020 18:32:50 +0100 Subject: [PATCH 2028/2595] Update OpenBIOS images to 75fbb41d built from submodule. Signed-off-by: Mark Cave-Ayland --- pc-bios/openbios-ppc | Bin 696912 -> 696912 bytes pc-bios/openbios-sparc32 | Bin 382048 -> 382048 bytes pc-bios/openbios-sparc64 | Bin 1593408 -> 1593408 bytes roms/openbios | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc index 5da9363bff64e21ab61ecf70d571855a3714843f..a07757a987e9ad424067427d23a1a46762952939 100644 GIT binary patch delta 44172 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 a0&q9iKG3?Nat8t&V#CQzE)2)wWq$zv#%^-} diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index d68b5e5d30961f8b796d06e1e17374f310e201d5..2faaab83ba762392c9a548c49584c023f4d233c2 100644 GIT binary patch delta 35115 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 diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index 26d631ea64c501927c417cf4c5352808dbb1f7ca..dd7eeeeab440788f483d7ea0af6cde56c1a34ab1 100644 GIT binary patch delta 31970 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 W>zq~BIjeu|bUiw&v%>E>&G=s%>ce9I delta 31991 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 z Date: Wed, 8 Jul 2020 16:49:22 +0800 Subject: [PATCH 2029/2595] vhost-vdpa: fix the compile issue without kvm Fix the compile issue in the system without the kvm support Signed-off-by: Cindy Lu Message-Id: <20200708084922.21904-1-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index a3d17fe0f9..65d5aaf08a 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -19,8 +19,7 @@ #include "hw/virtio/virtio-net.h" #include "hw/virtio/vhost-vdpa.h" #include "qemu/main-loop.h" -#include -#include "sysemu/kvm.h" +#include "cpu.h" static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section) { From 353b5a91ccf2789b85967d19a8795816b8865562 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Thu, 9 Jul 2020 23:28:48 +0530 Subject: [PATCH 2030/2595] 9p: null terminate fs driver options list NULL terminate fs driver options' list, validate_opt() looks for a null entry to terminate the loop. Fixes: aee7f3ecd8b7 ("fsdev: Error out when unsupported option is passed") Signed-off-by: Prasad J Pandit Reviewed-by: Li Qiang Message-Id: <20200709175848.650400-1-ppandit@redhat.com> Signed-off-by: Greg Kurz --- fsdev/qemu-fsdev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c index a9e069c0c7..3da64e9f72 100644 --- a/fsdev/qemu-fsdev.c +++ b/fsdev/qemu-fsdev.c @@ -78,6 +78,7 @@ static FsDriverTable FsDrivers[] = { "throttling.iops-read-max-length", "throttling.iops-write-max-length", "throttling.iops-size", + NULL }, }, { @@ -85,6 +86,7 @@ static FsDriverTable FsDrivers[] = { .ops = &synth_ops, .opts = (const char * []) { COMMON_FS_DRIVER_OPTIONS, + NULL }, }, { @@ -95,6 +97,7 @@ static FsDriverTable FsDrivers[] = { "socket", "sock_fd", "writeout", + NULL }, }, }; From 104a7f4e1355493175b0ad6f49c524ee449c16f7 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Wed, 24 Jun 2020 08:19:39 -0400 Subject: [PATCH 2031/2595] xen: Fix xen-legacy-backend qdev types xen-sysdev is a TYPE_SYS_BUS_DEVICE. bus_type should not be changed so that it can plug into the System bus. Otherwise this assert triggers: qemu-system-i386: hw/core/qdev.c:102: qdev_set_parent_bus: Assertion `dc->bus_type && object_dynamic_cast(OBJECT(bus), dc->bus_type)' failed. TYPE_XENBACKEND attaches to TYPE_XENSYSBUS, so its class_init needs to be set accordingly to attach the qdev. Otherwise the following assert triggers: qemu-system-i386: hw/core/qdev.c:102: qdev_set_parent_bus: Assertion `dc->bus_type && object_dynamic_cast(OBJECT(bus), dc->bus_type)' failed. TYPE_XENBACKEND is not a subclass of XEN_XENSYSDEV, so it's parent is just TYPE_DEVICE. Change that. Signed-off-by: Jason Andryuk Acked-by: Paul Durrant Fixes: 81cb05732efb ("qdev: Assert devices are plugged into a bus that can take them") Message-Id: <20200624121939.10282-1-jandryuk@gmail.com> Signed-off-by: Anthony PERARD --- hw/xen/xen-legacy-backend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index 7d4b13351e..083d8dc1b2 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -789,11 +789,12 @@ static void xendev_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); /* xen-backend devices can be plugged/unplugged dynamically */ dc->user_creatable = true; + dc->bus_type = TYPE_XENSYSBUS; } static const TypeInfo xendev_type_info = { .name = TYPE_XENBACKEND, - .parent = TYPE_XENSYSDEV, + .parent = TYPE_DEVICE, .class_init = xendev_class_init, .instance_size = sizeof(struct XenLegacyDevice), }; @@ -824,7 +825,6 @@ static void xen_sysdev_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); device_class_set_props(dc, xen_sysdev_properties); - dc->bus_type = TYPE_XENSYSBUS; } static const TypeInfo xensysdev_info = { From dd29b5c30cd2a13f8c12376a8de84cb090c338bf Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Wed, 24 Jun 2020 13:18:41 +0100 Subject: [PATCH 2032/2595] xen: cleanup unrealized flash devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generic pc_machine_initfn() calls pc_system_flash_create() which creates 'system.flash0' and 'system.flash1' devices. These devices are then realized by pc_system_flash_map() which is called from pc_system_firmware_init() which itself is called via pc_memory_init(). The latter however is not called when xen_enable() is true and hence the following assertion fails: qemu-system-i386: hw/core/qdev.c:439: qdev_assert_realized_properly: Assertion `dev->realized' failed These flash devices are unneeded when using Xen so this patch avoids the assertion by simply removing them using pc_system_flash_cleanup_unused(). Reported-by: Jason Andryuk Fixes: ebc29e1beab0 ("pc: Support firmware configuration with -blockdev") Signed-off-by: Paul Durrant Tested-by: Jason Andryuk Reviewed-by: Anthony PERARD Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200624121841.17971-3-paul@xen.org> Fixes: dfe8c79c4468 ("qdev: Assert onboard devices all get realized properly") Signed-off-by: Anthony PERARD --- hw/i386/pc_piix.c | 9 ++++++--- hw/i386/pc_sysfw.c | 2 +- include/hw/i386/pc.h | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 2bb42a8141..3469b1fd10 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -186,9 +186,12 @@ static void pc_init1(MachineState *machine, if (!xen_enabled()) { pc_memory_init(pcms, system_memory, rom_memory, &ram_memory); - } else if (machine->kernel_filename != NULL) { - /* For xen HVM direct kernel boot, load linux here */ - xen_load_linux(pcms); + } else { + pc_system_flash_cleanup_unused(pcms); + if (machine->kernel_filename != NULL) { + /* For xen HVM direct kernel boot, load linux here */ + xen_load_linux(pcms); + } } gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled); diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index ec2a3b3e7e..0ff47a4b59 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -108,7 +108,7 @@ void pc_system_flash_create(PCMachineState *pcms) } } -static void pc_system_flash_cleanup_unused(PCMachineState *pcms) +void pc_system_flash_cleanup_unused(PCMachineState *pcms) { char *prop_name; int i; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index a802e69974..3d7ed3a55e 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -186,6 +186,7 @@ ISADevice *pc_find_fdc0(void); /* pc_sysfw.c */ void pc_system_flash_create(PCMachineState *pcms); +void pc_system_flash_cleanup_unused(PCMachineState *pcms); void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory); /* acpi-build.c */ From 47ff5ac81e8bb3096500de7b132051691d533d36 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:29 +0200 Subject: [PATCH 2033/2595] error: Fix examples in error.h's big comment Mark a bad example more clearly. Fix the error_propagate_prepend() example. Add a missing declaration and a second error pileup example. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Greg Kurz Message-Id: <20200707160613.848843-2-armbru@redhat.com> --- include/qapi/error.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/include/qapi/error.h b/include/qapi/error.h index ad5b6e896d..e8960eaad5 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -24,7 +24,7 @@ * "charm, top, bottom.\n"); * * Do *not* contract this to - * error_setg(&err, "invalid quark\n" + * error_setg(&err, "invalid quark\n" // WRONG! * "Valid quarks are up, down, strange, charm, top, bottom."); * * Report an error to the current monitor if we have one, else stderr: @@ -52,7 +52,8 @@ * where Error **errp is a parameter, by convention the last one. * * Pass an existing error to the caller with the message modified: - * error_propagate_prepend(errp, err); + * error_propagate_prepend(errp, err, + * "Could not frobnicate '%s': ", name); * * Avoid * error_propagate(errp, err); @@ -108,12 +109,23 @@ * } * * Do *not* "optimize" this to + * Error *err = NULL; * foo(arg, &err); * bar(arg, &err); // WRONG! * if (err) { * handle the error... * } * because this may pass a non-null err to bar(). + * + * Likewise, do *not* + * Error *err = NULL; + * if (cond1) { + * error_setg(&err, ...); + * } + * if (cond2) { + * error_setg(&err, ...); // WRONG! + * } + * because this may pass a non-null err to error_setg(). */ #ifndef ERROR_H From 9aac7d486cc792191c25c30851f501624b0c2751 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:30 +0200 Subject: [PATCH 2034/2595] error: Improve error.h's big comment Add headlines to the big comment. Explain examples for NULL, &error_abort and &error_fatal argument better. Tweak rationale for error_propagate_prepend(). Signed-off-by: Markus Armbruster Message-Id: <20200707160613.848843-3-armbru@redhat.com> Reviewed-by: Eric Blake Reviewed-by: Greg Kurz --- include/qapi/error.h | 51 +++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/include/qapi/error.h b/include/qapi/error.h index e8960eaad5..6d079c58b7 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -15,6 +15,8 @@ /* * Error reporting system loosely patterned after Glib's GError. * + * = Creating errors = + * * Create an error: * error_setg(&err, "situation normal, all fouled up"); * @@ -27,6 +29,8 @@ * error_setg(&err, "invalid quark\n" // WRONG! * "Valid quarks are up, down, strange, charm, top, bottom."); * + * = Reporting and destroying errors = + * * Report an error to the current monitor if we have one, else stderr: * error_report_err(err); * This frees the error object. @@ -40,6 +44,30 @@ * error_free(err); * Note that this loses hints added with error_append_hint(). * + * Call a function ignoring errors: + * foo(arg, NULL); + * This is more concise than + * Error *err = NULL; + * foo(arg, &err); + * error_free(err); // don't do this + * + * Call a function aborting on errors: + * foo(arg, &error_abort); + * This is more concise and fails more nicely than + * Error *err = NULL; + * foo(arg, &err); + * assert(!err); // don't do this + * + * Call a function treating errors as fatal: + * foo(arg, &error_fatal); + * This is more concise than + * Error *err = NULL; + * foo(arg, &err); + * if (err) { // don't do this + * error_report_err(err); + * exit(1); + * } + * * Handle an error without reporting it (just for completeness): * error_free(err); * @@ -47,6 +75,11 @@ * reporting it (primarily useful in testsuites): * error_free_or_abort(&err); * + * = Passing errors around = + * + * Errors get passed to the caller through the conventional @errp + * parameter. + * * Pass an existing error to the caller: * error_propagate(errp, err); * where Error **errp is a parameter, by convention the last one. @@ -54,11 +87,10 @@ * Pass an existing error to the caller with the message modified: * error_propagate_prepend(errp, err, * "Could not frobnicate '%s': ", name); - * - * Avoid - * error_propagate(errp, err); + * This is more concise than + * error_propagate(errp, err); // don't do this * error_prepend(errp, "Could not frobnicate '%s': ", name); - * because this fails to prepend when @errp is &error_fatal. + * and works even when @errp is &error_fatal. * * Create a new error and pass it to the caller: * error_setg(errp, "situation normal, all fouled up"); @@ -70,15 +102,6 @@ * handle the error... * } * - * Call a function ignoring errors: - * foo(arg, NULL); - * - * Call a function aborting on errors: - * foo(arg, &error_abort); - * - * Call a function treating errors as fatal: - * foo(arg, &error_fatal); - * * Receive an error and pass it on to the caller: * Error *err = NULL; * foo(arg, &err); @@ -86,8 +109,6 @@ * handle the error... * error_propagate(errp, err); * } - * where Error **errp is a parameter, by convention the last one. - * * Do *not* "optimize" this to * foo(arg, errp); * if (*errp) { // WRONG! From e3fe3988d7851cac30abffae06d2f555ff7bee62 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:31 +0200 Subject: [PATCH 2035/2595] error: Document Error API usage rules This merely codifies existing practice, with one exception: the rule advising against returning void, where existing practice is mixed. When the Error API was created, we adopted the (unwritten) rule to return void when the function returns no useful value on success, unlike GError, which recommends to return true on success and false on error then. When a function returns a distinct error value, say false, a checked call that passes the error up looks like if (!frobnicate(..., errp)) { handle the error... } When it returns void, we need Error *err = NULL; frobnicate(..., &err); if (err) { handle the error... error_propagate(errp, err); } Not only is this more verbose, it also creates an Error object even when @errp is null, &error_abort or &error_fatal. People got tired of the additional boilerplate, and started to ignore the unwritten rule. The result is confusion among developers about the preferred usage. Make the rule advising against returning void official by putting it in writing. This will hopefully reduce confusion. Update the examples accordingly. The remainder of this series will update a substantial amount of code to honor the rule. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Greg Kurz Message-Id: <20200707160613.848843-4-armbru@redhat.com> [Tweak prose as per advice from Eric] --- include/qapi/error.h | 52 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/include/qapi/error.h b/include/qapi/error.h index 6d079c58b7..2c189abb04 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -15,6 +15,33 @@ /* * Error reporting system loosely patterned after Glib's GError. * + * = Rules = + * + * - Functions that use Error to report errors have an Error **errp + * parameter. It should be the last parameter, except for functions + * taking variable arguments. + * + * - You may pass NULL to not receive the error, &error_abort to abort + * on error, &error_fatal to exit(1) on error, or a pointer to a + * variable containing NULL to receive the error. + * + * - Separation of concerns: the function is responsible for detecting + * errors and failing cleanly; handling the error is its caller's + * job. Since the value of @errp is about handling the error, the + * function should not examine it. + * + * - On success, the function should not touch *errp. On failure, it + * should set a new error, e.g. with error_setg(errp, ...), or + * propagate an existing one, e.g. with error_propagate(errp, ...). + * + * - Whenever practical, also return a value that indicates success / + * failure. This can make the error checking more concise, and can + * avoid useless error object creation and destruction. Note that + * we still have many functions returning void. We recommend + * • bool-valued functions return true on success / false on failure, + * • pointer-valued functions return non-null / null pointer, and + * • integer-valued functions return non-negative / negative. + * * = Creating errors = * * Create an error: @@ -95,14 +122,13 @@ * Create a new error and pass it to the caller: * error_setg(errp, "situation normal, all fouled up"); * - * Call a function and receive an error from it: - * Error *err = NULL; - * foo(arg, &err); - * if (err) { + * Call a function, receive an error from it, and pass it to the caller + * - when the function returns a value that indicates failure, say + * false: + * if (!foo(arg, errp)) { * handle the error... * } - * - * Receive an error and pass it on to the caller: + * - when it does not, say because it is a void function: * Error *err = NULL; * foo(arg, &err); * if (err) { @@ -120,6 +146,20 @@ * foo(arg, errp); * for readability. * + * Receive an error, and handle it locally + * - when the function returns a value that indicates failure, say + * false: + * Error *err = NULL; + * if (!foo(arg, &err)) { + * handle the error... + * } + * - when it does not, say because it is a void function: + * Error *err = NULL; + * foo(arg, &err); + * if (err) { + * handle the error... + * } + * * Receive and accumulate multiple errors (first one wins): * Error *err = NULL, *local_err = NULL; * foo(arg, &err); From 118bfd76c9c604588cb3f97811710576f58e5a76 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:32 +0200 Subject: [PATCH 2036/2595] qdev: Use returned bool to check for qdev_realize() etc. failure Convert foo(..., &err); if (err) { ... } to if (!foo(..., &err)) { ... } for qdev_realize(), qdev_realize_and_unref(), qbus_realize() and their wrappers isa_realize_and_unref(), pci_realize_and_unref(), sysbus_realize(), sysbus_realize_and_unref(), usb_realize_and_unref(). Coccinelle script: @@ identifier fun = { isa_realize_and_unref, pci_realize_and_unref, qbus_realize, qdev_realize, qdev_realize_and_unref, sysbus_realize, sysbus_realize_and_unref, usb_realize_and_unref }; expression list args, args2; typedef Error; Error *err; @@ - fun(args, &err, args2); - if (err) + if (!fun(args, &err, args2)) { ... } Chokes on hw/arm/musicpal.c's lcd_refresh() with the unhelpful error message "no position information". Nothing to convert there; skipped. Fails to convert hw/arm/armsse.c, because Coccinelle gets confused by ARMSSE being used both as typedef and function-like macro there. Converted manually. A few line breaks tidied up manually. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Greg Kurz Message-Id: <20200707160613.848843-5-armbru@redhat.com> --- hw/arm/allwinner-a10.c | 15 +++---- hw/arm/armsse.c | 78 +++++++++++---------------------- hw/arm/armv7m.c | 9 ++-- hw/arm/aspeed_ast2600.c | 51 +++++++-------------- hw/arm/aspeed_soc.c | 45 +++++++------------ hw/arm/bcm2835_peripherals.c | 45 +++++++------------ hw/arm/bcm2836.c | 9 ++-- hw/arm/cubieboard.c | 3 +- hw/arm/digic.c | 9 ++-- hw/arm/digic_boards.c | 3 +- hw/arm/fsl-imx25.c | 33 +++++--------- hw/arm/fsl-imx31.c | 24 ++++------ hw/arm/fsl-imx6.c | 36 +++++---------- hw/arm/msf2-soc.c | 15 +++---- hw/arm/nrf51_soc.c | 18 +++----- hw/arm/stm32f205_soc.c | 21 +++------ hw/arm/stm32f405_soc.c | 24 ++++------ hw/arm/xlnx-zynqmp.c | 45 +++++++------------ hw/block/fdc.c | 3 +- hw/block/xen-block.c | 3 +- hw/char/serial-pci-multi.c | 3 +- hw/char/serial-pci.c | 3 +- hw/char/serial.c | 6 +-- hw/core/cpu.c | 3 +- hw/cpu/a15mpcore.c | 3 +- hw/cpu/a9mpcore.c | 15 +++---- hw/cpu/arm11mpcore.c | 12 ++--- hw/cpu/realview_mpcore.c | 6 +-- hw/display/virtio-gpu-pci.c | 4 +- hw/display/virtio-vga.c | 3 +- hw/intc/armv7m_nvic.c | 6 +-- hw/intc/pnv_xive.c | 6 +-- hw/intc/realview_gic.c | 3 +- hw/intc/spapr_xive.c | 6 +-- hw/intc/xics.c | 3 +- hw/intc/xive.c | 3 +- hw/isa/piix4.c | 3 +- hw/microblaze/xlnx-zynqmp-pmu.c | 6 +-- hw/mips/cps.c | 12 ++--- hw/misc/macio/cuda.c | 3 +- hw/misc/macio/macio.c | 18 +++----- hw/misc/macio/pmu.c | 3 +- hw/pci-host/pnv_phb3.c | 9 ++-- hw/pci-host/pnv_phb4.c | 3 +- hw/pci-host/pnv_phb4_pec.c | 3 +- hw/ppc/e500.c | 3 +- hw/ppc/pnv.c | 39 ++++++----------- hw/ppc/pnv_core.c | 3 +- hw/ppc/pnv_psi.c | 6 +-- hw/ppc/spapr_cpu_core.c | 3 +- hw/ppc/spapr_irq.c | 3 +- hw/riscv/opentitan.c | 6 +-- hw/riscv/sifive_e.c | 3 +- hw/riscv/sifive_u.c | 3 +- hw/s390x/event-facility.c | 10 ++--- hw/s390x/s390-pci-bus.c | 3 +- hw/s390x/sclp.c | 3 +- hw/s390x/virtio-ccw-crypto.c | 3 +- hw/s390x/virtio-ccw-rng.c | 3 +- hw/scsi/scsi-bus.c | 3 +- hw/sd/aspeed_sdhci.c | 3 +- hw/sd/ssi-sd.c | 3 +- hw/usb/bus.c | 3 +- hw/virtio/virtio-rng-pci.c | 3 +- qdev-monitor.c | 3 +- 65 files changed, 248 insertions(+), 495 deletions(-) diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 52e0d83760..e1acffe5f6 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -74,14 +74,12 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) SysBusDevice *sysbusdev; Error *err = NULL; - qdev_realize(DEVICE(&s->cpu), NULL, &err); - if (err != NULL) { + if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) { error_propagate(errp, err); return; } - sysbus_realize(SYS_BUS_DEVICE(&s->intc), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->intc), &err)) { error_propagate(errp, err); return; } @@ -93,8 +91,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); qdev_pass_gpios(DEVICE(&s->intc), dev, NULL); - sysbus_realize(SYS_BUS_DEVICE(&s->timer), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer), &err)) { error_propagate(errp, err); return; } @@ -117,8 +114,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC); qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); } - sysbus_realize(SYS_BUS_DEVICE(&s->emac), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->emac), &err)) { error_propagate(errp, err); return; } @@ -126,8 +122,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(sysbusdev, 0, AW_A10_EMAC_BASE); sysbus_connect_irq(sysbusdev, 0, qdev_get_gpio_in(dev, 55)); - sysbus_realize(SYS_BUS_DEVICE(&s->sata), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sata), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 2fbd970b4f..9a48bf86c3 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -565,8 +565,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) object_property_set_link(cpuobj, OBJECT(&s->cpu_container[i]), "memory", &error_abort); object_property_set_link(cpuobj, OBJECT(s), "idau", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(cpuobj), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(cpuobj), &err)) { error_propagate(errp, err); return; } @@ -576,8 +575,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) * CPU must exist and have been parented into the cluster before * the cluster is realized. */ - qdev_realize(DEVICE(&s->cluster[i]), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->cluster[i]), NULL, &err)) { error_propagate(errp, err); return; } @@ -612,8 +610,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - qdev_realize(DEVICE(splitter), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(splitter), NULL, &err)) { error_propagate(errp, err); return; } @@ -645,8 +642,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) } /* Security controller */ - sysbus_realize(SYS_BUS_DEVICE(&s->secctl), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->secctl), &err)) { error_propagate(errp, err); return; } @@ -668,8 +664,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - qdev_realize(DEVICE(&s->sec_resp_splitter), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->sec_resp_splitter), NULL, &err)) { error_propagate(errp, err); return; } @@ -692,8 +687,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) } object_property_set_link(OBJECT(&s->mpc[i]), OBJECT(&s->sram[i]), "downstream", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->mpc[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mpc[i]), &err)) { error_propagate(errp, err); return; } @@ -715,8 +709,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - qdev_realize(DEVICE(&s->mpc_irq_orgate), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->mpc_irq_orgate), NULL, &err)) { error_propagate(errp, err); return; } @@ -734,8 +727,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) * map its upstream ends to the right place in the container. */ qdev_prop_set_uint32(DEVICE(&s->timer0), "pclk-frq", s->mainclk_frq); - sysbus_realize(SYS_BUS_DEVICE(&s->timer0), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer0), &err)) { error_propagate(errp, err); return; } @@ -746,8 +738,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) &error_abort); qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq); - sysbus_realize(SYS_BUS_DEVICE(&s->timer1), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer1), &err)) { error_propagate(errp, err); return; } @@ -758,8 +749,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) &error_abort); qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq); - sysbus_realize(SYS_BUS_DEVICE(&s->dualtimer), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->dualtimer), &err)) { error_propagate(errp, err); return; } @@ -784,8 +774,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) int cpunum; SysBusDevice *mhu_sbd = SYS_BUS_DEVICE(&s->mhu[i]); - sysbus_realize(SYS_BUS_DEVICE(&s->mhu[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mhu[i]), &err)) { error_propagate(errp, err); return; } @@ -811,8 +800,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) } } - sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc0), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc0), &err)) { error_propagate(errp, err); return; } @@ -860,8 +848,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - qdev_realize(DEVICE(&s->ppc_irq_orgate), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->ppc_irq_orgate), NULL, &err)) { error_propagate(errp, err); return; } @@ -883,8 +870,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_prop_set_string(DEVICE(&s->cachectrl[i]), "name", name); g_free(name); qdev_prop_set_uint64(DEVICE(&s->cachectrl[i]), "size", 0x1000); - sysbus_realize(SYS_BUS_DEVICE(&s->cachectrl[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cachectrl[i]), &err)) { error_propagate(errp, err); return; } @@ -901,8 +887,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_prop_set_string(DEVICE(&s->cpusecctrl[i]), "name", name); g_free(name); qdev_prop_set_uint64(DEVICE(&s->cpusecctrl[i]), "size", 0x1000); - sysbus_realize(SYS_BUS_DEVICE(&s->cpusecctrl[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpusecctrl[i]), &err)) { error_propagate(errp, err); return; } @@ -916,8 +901,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) MemoryRegion *mr; qdev_prop_set_uint32(DEVICE(&s->cpuid[i]), "CPUID", i); - sysbus_realize(SYS_BUS_DEVICE(&s->cpuid[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpuid[i]), &err)) { error_propagate(errp, err); return; } @@ -932,8 +916,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) * 0x4002f000: S32K timer */ qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK); - sysbus_realize(SYS_BUS_DEVICE(&s->s32ktimer), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->s32ktimer), &err)) { error_propagate(errp, err); return; } @@ -943,8 +926,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc1), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc1), &err)) { error_propagate(errp, err); return; } @@ -981,8 +963,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_realize(SYS_BUS_DEVICE(&s->sysinfo), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysinfo), &err)) { error_propagate(errp, err); return; } @@ -997,8 +978,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) "INITSVTOR0_RST", &error_abort); object_property_set_int(OBJECT(&s->sysctl), s->init_svtor, "INITSVTOR1_RST", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->sysctl), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysctl), &err)) { error_propagate(errp, err); return; } @@ -1032,8 +1012,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - qdev_realize(DEVICE(&s->nmi_orgate), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->nmi_orgate), NULL, &err)) { error_propagate(errp, err); return; } @@ -1041,8 +1020,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0)); qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK); - sysbus_realize(SYS_BUS_DEVICE(&s->s32kwatchdog), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->s32kwatchdog), &err)) { error_propagate(errp, err); return; } @@ -1053,8 +1031,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) /* 0x40080000 .. 0x4008ffff : ARMSSE second Base peripheral region */ qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq); - sysbus_realize(SYS_BUS_DEVICE(&s->nswatchdog), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->nswatchdog), &err)) { error_propagate(errp, err); return; } @@ -1063,8 +1040,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000); qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq); - sysbus_realize(SYS_BUS_DEVICE(&s->swatchdog), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->swatchdog), &err)) { error_propagate(errp, err); return; } @@ -1080,8 +1056,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - qdev_realize(DEVICE(splitter), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(splitter), NULL, &err)) { error_propagate(errp, err); return; } @@ -1127,8 +1102,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - qdev_realize(DEVICE(splitter), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(splitter), NULL, &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 3308211e9c..28baf330e5 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -213,15 +213,13 @@ static void armv7m_realize(DeviceState *dev, Error **errp) s->cpu->env.nvic = &s->nvic; s->nvic.cpu = s->cpu; - qdev_realize(DEVICE(s->cpu), NULL, &err); - if (err != NULL) { + if (!qdev_realize(DEVICE(s->cpu), NULL, &err)) { error_propagate(errp, err); return; } /* Note that we must realize the NVIC after the CPU */ - sysbus_realize(SYS_BUS_DEVICE(&s->nvic), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->nvic), &err)) { error_propagate(errp, err); return; } @@ -254,8 +252,7 @@ static void armv7m_realize(DeviceState *dev, Error **errp) } object_property_set_link(obj, OBJECT(s->board_memory), "source-memory", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(obj), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(obj), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 59a7a1370b..b9ae4c12b4 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -259,8 +259,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) * is needed when using -kernel */ - qdev_realize(DEVICE(&s->cpu[i]), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, &err)) { error_propagate(errp, err); return; } @@ -301,16 +300,14 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sc->memmap[ASPEED_SRAM], &s->sram); /* SCU */ - sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err)) { error_propagate(errp, err); return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_SCU]); /* RTC */ - sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err)) { error_propagate(errp, err); return; } @@ -321,8 +318,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* Timer */ object_property_set_link(OBJECT(&s->timerctrl), OBJECT(&s->scu), "scu", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), &err)) { error_propagate(errp, err); return; } @@ -343,8 +339,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* I2C */ object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err)) { error_propagate(errp, err); return; } @@ -368,8 +363,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_realize(SYS_BUS_DEVICE(&s->fmc), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), &err)) { error_propagate(errp, err); return; } @@ -385,8 +379,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) "dram", &error_abort); object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { error_propagate(errp, err); return; } @@ -398,8 +391,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* EHCI */ for (i = 0; i < sc->ehcis_num; i++) { - sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &err)) { error_propagate(errp, err); return; } @@ -410,8 +402,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* SDMC - SDRAM Memory Controller */ - sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), &err)) { error_propagate(errp, err); return; } @@ -423,8 +414,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->wdt[i]), OBJECT(&s->scu), "scu", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &err)) { error_propagate(errp, err); return; } @@ -436,8 +426,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err)) { error_propagate(errp, err); return; } @@ -448,8 +437,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->mii[i]), OBJECT(&s->ftgmac100[i]), "nic", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->mii[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mii[i]), &err)) { error_propagate(errp, err); return; } @@ -459,8 +447,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* XDMA */ - sysbus_realize(SYS_BUS_DEVICE(&s->xdma), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), &err)) { error_propagate(errp, err); return; } @@ -470,8 +457,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_XDMA)); /* GPIO */ - sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err)) { error_propagate(errp, err); return; } @@ -479,8 +465,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, aspeed_soc_get_irq(s, ASPEED_GPIO)); - sysbus_realize(SYS_BUS_DEVICE(&s->gpio_1_8v), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio_1_8v), &err)) { error_propagate(errp, err); return; } @@ -490,8 +475,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_GPIO_1_8V)); /* SDHCI */ - sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err)) { error_propagate(errp, err); return; } @@ -501,8 +485,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_SDHCI)); /* eMMC */ - sysbus_realize(SYS_BUS_DEVICE(&s->emmc), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->emmc), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 311458aa76..fa56f96f92 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -230,8 +230,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* CPU */ for (i = 0; i < sc->num_cpus; i++) { - qdev_realize(DEVICE(&s->cpu[i]), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, &err)) { error_propagate(errp, err); return; } @@ -248,16 +247,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sc->memmap[ASPEED_SRAM], &s->sram); /* SCU */ - sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err)) { error_propagate(errp, err); return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_SCU]); /* VIC */ - sysbus_realize(SYS_BUS_DEVICE(&s->vic), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->vic), &err)) { error_propagate(errp, err); return; } @@ -268,8 +265,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); /* RTC */ - sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err)) { error_propagate(errp, err); return; } @@ -280,8 +276,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* Timer */ object_property_set_link(OBJECT(&s->timerctrl), OBJECT(&s->scu), "scu", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), &err)) { error_propagate(errp, err); return; } @@ -302,8 +297,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* I2C */ object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err)) { error_propagate(errp, err); return; } @@ -320,8 +314,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_realize(SYS_BUS_DEVICE(&s->fmc), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), &err)) { error_propagate(errp, err); return; } @@ -335,8 +328,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->spis_num; i++) { object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { error_propagate(errp, err); return; } @@ -348,8 +340,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* EHCI */ for (i = 0; i < sc->ehcis_num; i++) { - sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &err)) { error_propagate(errp, err); return; } @@ -360,8 +351,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } /* SDMC - SDRAM Memory Controller */ - sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), &err)) { error_propagate(errp, err); return; } @@ -373,8 +363,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->wdt[i]), OBJECT(&s->scu), "scu", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &err)) { error_propagate(errp, err); return; } @@ -386,8 +375,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err)) { error_propagate(errp, err); return; } @@ -398,8 +386,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } /* XDMA */ - sysbus_realize(SYS_BUS_DEVICE(&s->xdma), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), &err)) { error_propagate(errp, err); return; } @@ -409,8 +396,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_XDMA)); /* GPIO */ - sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err)) { error_propagate(errp, err); return; } @@ -419,8 +405,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_GPIO)); /* SDHCI */ - sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 7ffdf62067..2df81168e4 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -161,8 +161,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) } /* Interrupt Controller */ - sysbus_realize(SYS_BUS_DEVICE(&s->ic), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ic), &err)) { error_propagate(errp, err); return; } @@ -172,8 +171,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic)); /* Sys Timer */ - sysbus_realize(SYS_BUS_DEVICE(&s->systmr), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->systmr), &err)) { error_propagate(errp, err); return; } @@ -185,8 +183,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) /* UART0 */ qdev_prop_set_chr(DEVICE(&s->uart0), "chardev", serial_hd(0)); - sysbus_realize(SYS_BUS_DEVICE(&s->uart0), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart0), &err)) { error_propagate(errp, err); return; } @@ -200,8 +197,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) /* AUX / UART1 */ qdev_prop_set_chr(DEVICE(&s->aux), "chardev", serial_hd(1)); - sysbus_realize(SYS_BUS_DEVICE(&s->aux), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->aux), &err)) { error_propagate(errp, err); return; } @@ -213,8 +209,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_AUX)); /* Mailboxes */ - sysbus_realize(SYS_BUS_DEVICE(&s->mboxes), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mboxes), &err)) { error_propagate(errp, err); return; } @@ -239,8 +234,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) return; } - sysbus_realize(SYS_BUS_DEVICE(&s->fb), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fb), &err)) { error_propagate(errp, err); return; } @@ -251,8 +245,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_FB)); /* Property channel */ - sysbus_realize(SYS_BUS_DEVICE(&s->property), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->property), &err)) { error_propagate(errp, err); return; } @@ -264,8 +257,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_PROPERTY)); /* Random Number Generator */ - sysbus_realize(SYS_BUS_DEVICE(&s->rng), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rng), &err)) { error_propagate(errp, err); return; } @@ -289,8 +281,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err)) { error_propagate(errp, err); return; } @@ -302,8 +293,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_ARASANSDIO)); /* SDHOST */ - sysbus_realize(SYS_BUS_DEVICE(&s->sdhost), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhost), &err)) { error_propagate(errp, err); return; } @@ -315,8 +305,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_SDIO)); /* DMA Channels */ - sysbus_realize(SYS_BUS_DEVICE(&s->dma), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->dma), &err)) { error_propagate(errp, err); return; } @@ -334,8 +323,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) } /* THERMAL */ - sysbus_realize(SYS_BUS_DEVICE(&s->thermal), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->thermal), &err)) { error_propagate(errp, err); return; } @@ -343,8 +331,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->thermal), 0)); /* GPIO */ - sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err)) { error_propagate(errp, err); return; } @@ -355,8 +342,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus"); /* Mphi */ - sysbus_realize(SYS_BUS_DEVICE(&s->mphi), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mphi), &err)) { error_propagate(errp, err); return; } @@ -368,8 +354,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_HOSTPORT)); /* DWC2 */ - sysbus_realize(SYS_BUS_DEVICE(&s->dwc2), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->dwc2), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index ed1793f7b7..1a7560ef30 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -86,8 +86,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj); - sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), &err)) { error_propagate(errp, err); return; } @@ -99,8 +98,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) info->peri_base, 1); /* bcm2836 interrupt controller (and mailboxes, etc.) */ - sysbus_realize(SYS_BUS_DEVICE(&s->control), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), &err)) { error_propagate(errp, err); return; } @@ -133,8 +131,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) return; } - qdev_realize(DEVICE(&s->cpu[n].core), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->cpu[n].core), NULL, &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 5cbd115c53..c720e24ced 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -80,8 +80,7 @@ static void cubieboard_init(MachineState *machine) exit(1); } - qdev_realize(DEVICE(a10), NULL, &err); - if (err != NULL) { + if (!qdev_realize(DEVICE(a10), NULL, &err)) { error_reportf_err(err, "Couldn't realize Allwinner A10: "); exit(1); } diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 13a83f7430..1494c2900a 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -62,15 +62,13 @@ static void digic_realize(DeviceState *dev, Error **errp) return; } - qdev_realize(DEVICE(&s->cpu), NULL, &err); - if (err != NULL) { + if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) { error_propagate(errp, err); return; } for (i = 0; i < DIGIC4_NB_TIMERS; i++) { - sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err)) { error_propagate(errp, err); return; } @@ -80,8 +78,7 @@ static void digic_realize(DeviceState *dev, Error **errp) } qdev_prop_set_chr(DEVICE(&s->uart), "chardev", serial_hd(0)); - sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c index b6452d918c..d5524d3e72 100644 --- a/hw/arm/digic_boards.c +++ b/hw/arm/digic_boards.c @@ -62,8 +62,7 @@ static void digic4_board_init(MachineState *machine, DigicBoard *board) exit(EXIT_FAILURE); } - qdev_realize(DEVICE(s), NULL, &err); - if (err != NULL) { + if (!qdev_realize(DEVICE(s), NULL, &err)) { error_reportf_err(err, "Couldn't realize DIGIC SoC: "); exit(1); } diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index 7ab5c98fbe..250681f045 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -85,14 +85,12 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) uint8_t i; Error *err = NULL; - qdev_realize(DEVICE(&s->cpu), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) { error_propagate(errp, err); return; } - sysbus_realize(SYS_BUS_DEVICE(&s->avic), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->avic), &err)) { error_propagate(errp, err); return; } @@ -102,8 +100,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1, qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); - sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err)) { error_propagate(errp, err); return; } @@ -124,8 +121,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err)) { error_propagate(errp, err); return; } @@ -149,8 +145,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) s->gpt[i].ccm = IMX_CCM(&s->ccm); - sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &err)) { error_propagate(errp, err); return; } @@ -172,8 +167,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) s->epit[i].ccm = IMX_CCM(&s->ccm); - sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err)) { error_propagate(errp, err); return; } @@ -185,8 +179,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]); - sysbus_realize(SYS_BUS_DEVICE(&s->fec), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fec), &err)) { error_propagate(errp, err); return; } @@ -194,8 +187,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->fec), 0, qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_FEC_IRQ)); - sysbus_realize(SYS_BUS_DEVICE(&s->rngc), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rngc), &err)) { error_propagate(errp, err); return; } @@ -214,8 +206,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) { FSL_IMX25_I2C3_ADDR, FSL_IMX25_I2C3_IRQ } }; - sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err)) { error_propagate(errp, err); return; } @@ -237,8 +228,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) { FSL_IMX25_GPIO4_ADDR, FSL_IMX25_GPIO4_IRQ } }; - sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err)) { error_propagate(errp, err); return; } @@ -267,8 +257,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) object_property_set_uint(OBJECT(&s->esdhc[i]), SDHCI_VENDOR_IMX, "vendor", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index 42cca529c3..4f007ea5e8 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -66,14 +66,12 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) uint16_t i; Error *err = NULL; - qdev_realize(DEVICE(&s->cpu), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) { error_propagate(errp, err); return; } - sysbus_realize(SYS_BUS_DEVICE(&s->avic), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->avic), &err)) { error_propagate(errp, err); return; } @@ -83,8 +81,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1, qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); - sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err)) { error_propagate(errp, err); return; } @@ -102,8 +99,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err)) { error_propagate(errp, err); return; } @@ -116,8 +112,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) s->gpt.ccm = IMX_CCM(&s->ccm); - sysbus_realize(SYS_BUS_DEVICE(&s->gpt), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt), &err)) { error_propagate(errp, err); return; } @@ -138,8 +133,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) s->epit[i].ccm = IMX_CCM(&s->ccm); - sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err)) { error_propagate(errp, err); return; } @@ -162,8 +156,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) }; /* Initialize the I2C */ - sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err)) { error_propagate(errp, err); return; } @@ -188,8 +181,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) object_property_set_bool(OBJECT(&s->gpio[i]), false, "has-edge-sel", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 4ae3c3efc2..417ca6889c 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -130,8 +130,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) "start-powered-off", &error_abort); } - qdev_realize(DEVICE(&s->cpu[i]), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, &err)) { error_propagate(errp, err); return; } @@ -144,8 +143,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) FSL_IMX6_MAX_IRQ + GIC_INTERNAL, "num-irq", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->a9mpcore), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->a9mpcore), &err)) { error_propagate(errp, err); return; } @@ -158,15 +156,13 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ)); } - sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err)) { error_propagate(errp, err); return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX6_CCM_ADDR); - sysbus_realize(SYS_BUS_DEVICE(&s->src), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->src), &err)) { error_propagate(errp, err); return; } @@ -187,8 +183,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err)) { error_propagate(errp, err); return; } @@ -201,8 +196,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) s->gpt.ccm = IMX_CCM(&s->ccm); - sysbus_realize(SYS_BUS_DEVICE(&s->gpt), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt), &err)) { error_propagate(errp, err); return; } @@ -224,8 +218,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) s->epit[i].ccm = IMX_CCM(&s->ccm); - sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err)) { error_propagate(errp, err); return; } @@ -247,8 +240,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) { FSL_IMX6_I2C3_ADDR, FSL_IMX6_I2C3_IRQ } }; - sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err)) { error_propagate(errp, err); return; } @@ -307,8 +299,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-upper-pin-irq", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err)) { error_propagate(errp, err); return; } @@ -343,8 +334,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) object_property_set_uint(OBJECT(&s->esdhc[i]), SDHCI_VENDOR_IMX, "vendor", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err)) { error_propagate(errp, err); return; } @@ -390,8 +380,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) }; /* Initialize the SPI */ - sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { error_propagate(errp, err); return; } @@ -403,8 +392,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) } qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]); - sysbus_realize(SYS_BUS_DEVICE(&s->eth), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->eth), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index 3235c76194..476112b2d9 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -125,8 +125,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_bit(armv7m, "enable-bitband", true); object_property_set_link(OBJECT(&s->armv7m), OBJECT(get_system_memory()), "memory", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err)) { error_propagate(errp, err); return; } @@ -153,8 +152,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) dev = DEVICE(&s->timer); /* APB0 clock is the timer input clock */ qdev_prop_set_uint32(dev, "clock-frequency", s->m3clk / s->apb0div); - sysbus_realize(SYS_BUS_DEVICE(&s->timer), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer), &err)) { error_propagate(errp, err); return; } @@ -168,8 +166,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) dev = DEVICE(&s->sysreg); qdev_prop_set_uint32(dev, "apb0divisor", s->apb0div); qdev_prop_set_uint32(dev, "apb1divisor", s->apb1div); - sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), &err)) { error_propagate(errp, err); return; } @@ -179,8 +176,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < MSF2_NUM_SPIS; i++) { gchar *bus_name; - sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { error_propagate(errp, err); return; } @@ -199,8 +195,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) dev = DEVICE(&s->emac); object_property_set_link(OBJECT(&s->emac), OBJECT(get_system_memory()), "ahb-bus", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->emac), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->emac), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index 20dd8b5897..e9c77e4c21 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -67,8 +67,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) object_property_set_link(OBJECT(&s->cpu), OBJECT(&s->container), "memory", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->cpu), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpu), &err)) { error_propagate(errp, err); return; } @@ -84,8 +83,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) memory_region_add_subregion(&s->container, NRF51_SRAM_BASE, &s->sram); /* UART */ - sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err)) { error_propagate(errp, err); return; } @@ -96,8 +94,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) BASE_TO_IRQ(NRF51_UART_BASE))); /* RNG */ - sysbus_realize(SYS_BUS_DEVICE(&s->rng), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rng), &err)) { error_propagate(errp, err); return; } @@ -116,8 +113,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) return; } - sysbus_realize(SYS_BUS_DEVICE(&s->nvm), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->nvm), &err)) { error_propagate(errp, err); return; } @@ -132,8 +128,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) memory_region_add_subregion_overlap(&s->container, NRF51_FLASH_BASE, mr, 0); /* GPIO */ - sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err)) { error_propagate(errp, err); return; } @@ -151,8 +146,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) error_propagate(errp, err); return; } - sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index 56aef686c9..46b5332470 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -107,16 +107,14 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_bit(armv7m, "enable-bitband", true); object_property_set_link(OBJECT(&s->armv7m), OBJECT(get_system_memory()), "memory", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err)) { error_propagate(errp, err); return; } /* System configuration controller */ dev = DEVICE(&s->syscfg); - sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), &err)) { error_propagate(errp, err); return; } @@ -128,8 +126,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_USARTS; i++) { dev = DEVICE(&(s->usart[i])); qdev_prop_set_chr(dev, "chardev", serial_hd(i)); - sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), &err)) { error_propagate(errp, err); return; } @@ -142,8 +139,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_TIMERS; i++) { dev = DEVICE(&(s->timer[i])); qdev_prop_set_uint64(dev, "clock-frequency", 1000000000); - sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err)) { error_propagate(errp, err); return; } @@ -155,8 +151,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) /* ADC 1 to 3 */ object_property_set_int(OBJECT(s->adc_irqs), STM_NUM_ADCS, "num-lines", &error_abort); - qdev_realize(DEVICE(s->adc_irqs), NULL, &err); - if (err != NULL) { + if (!qdev_realize(DEVICE(s->adc_irqs), NULL, &err)) { error_propagate(errp, err); return; } @@ -165,8 +160,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_ADCS; i++) { dev = DEVICE(&(s->adc[i])); - sysbus_realize(SYS_BUS_DEVICE(&s->adc[i]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc[i]), &err)) { error_propagate(errp, err); return; } @@ -179,8 +173,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) /* SPI 1 and 2 */ for (i = 0; i < STM_NUM_SPIS; i++) { dev = DEVICE(&(s->spi[i])); - sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index cf9228d8e7..f1f0dc40b1 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -118,16 +118,14 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_bit(armv7m, "enable-bitband", true); object_property_set_link(OBJECT(&s->armv7m), OBJECT(system_memory), "memory", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err)) { error_propagate(errp, err); return; } /* System configuration controller */ dev = DEVICE(&s->syscfg); - sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), &err)) { error_propagate(errp, err); return; } @@ -139,8 +137,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_USARTS; i++) { dev = DEVICE(&(s->usart[i])); qdev_prop_set_chr(dev, "chardev", serial_hd(i)); - sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), &err)) { error_propagate(errp, err); return; } @@ -153,8 +150,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_TIMERS; i++) { dev = DEVICE(&(s->timer[i])); qdev_prop_set_uint64(dev, "clock-frequency", 1000000000); - sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err)) { error_propagate(errp, err); return; } @@ -173,8 +169,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) } object_property_set_int(OBJECT(&s->adc_irqs), STM_NUM_ADCS, "num-lines", &error_abort); - qdev_realize(DEVICE(&s->adc_irqs), NULL, &err); - if (err != NULL) { + if (!qdev_realize(DEVICE(&s->adc_irqs), NULL, &err)) { error_propagate(errp, err); return; } @@ -183,8 +178,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_ADCS; i++) { dev = DEVICE(&(s->adc[i])); - sysbus_realize(SYS_BUS_DEVICE(&s->adc[i]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc[i]), &err)) { error_propagate(errp, err); return; } @@ -197,8 +191,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) /* SPI devices */ for (i = 0; i < STM_NUM_SPIS; i++) { dev = DEVICE(&(s->spi[i])); - sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { error_propagate(errp, err); return; } @@ -209,8 +202,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) /* EXTI device */ dev = DEVICE(&s->exti); - sysbus_realize(SYS_BUS_DEVICE(&s->exti), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->exti), &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 1de9d4a89d..d703158f8b 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -209,8 +209,7 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s, object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs", &error_abort); - qdev_realize(DEVICE(&s->rpu_cpu[i]), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->rpu_cpu[i]), NULL, &err)) { error_propagate(errp, err); return; } @@ -367,15 +366,13 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) "reset-cbar", &error_abort); object_property_set_int(OBJECT(&s->apu_cpu[i]), num_apus, "core-count", &error_abort); - qdev_realize(DEVICE(&s->apu_cpu[i]), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->apu_cpu[i]), NULL, &err)) { error_propagate(errp, err); return; } } - sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { error_propagate(errp, err); return; } @@ -470,8 +467,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->gem[i]), 2, "num-priority-queues", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), &err)) { error_propagate(errp, err); return; } @@ -482,8 +478,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) { qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err)) { error_propagate(errp, err); return; } @@ -494,8 +489,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(&s->sata), SATA_NUM_PORTS, "num-ports", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->sata), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sata), &err)) { error_propagate(errp, err); return; } @@ -528,8 +522,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_realize(SYS_BUS_DEVICE(sdhci), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(sdhci), &err)) { error_propagate(errp, err); return; } @@ -545,8 +538,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { gchar *bus_name; - sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { error_propagate(errp, err); return; } @@ -562,8 +554,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) g_free(bus_name); } - sysbus_realize(SYS_BUS_DEVICE(&s->qspi), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->qspi), &err)) { error_propagate(errp, err); return; } @@ -584,16 +575,14 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) g_free(target_bus); } - sysbus_realize(SYS_BUS_DEVICE(&s->dp), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->dp), &err)) { error_propagate(errp, err); return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->dp), 0, DP_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->dp), 0, gic_spi[DP_IRQ]); - sysbus_realize(SYS_BUS_DEVICE(&s->dpdma), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->dpdma), &err)) { error_propagate(errp, err); return; } @@ -602,16 +591,14 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->dpdma), 0, DPDMA_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->dpdma), 0, gic_spi[DPDMA_IRQ]); - sysbus_realize(SYS_BUS_DEVICE(&s->ipi), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ipi), &err)) { error_propagate(errp, err); return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ipi), 0, IPI_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ipi), 0, gic_spi[IPI_IRQ]); - sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err)) { error_propagate(errp, err); return; } @@ -624,8 +611,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_realize(SYS_BUS_DEVICE(&s->gdma[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gdma[i]), &err)) { error_propagate(errp, err); return; } @@ -636,8 +622,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) } for (i = 0; i < XLNX_ZYNQMP_NUM_ADMA_CH; i++) { - sysbus_realize(SYS_BUS_DEVICE(&s->adma[i]), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->adma[i]), &err)) { error_propagate(errp, err); return; } diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 3425d56e2a..3be8c7be5b 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2575,8 +2575,7 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, return; } - qdev_realize_and_unref(dev, &fdctrl->bus.bus, &local_err); - if (local_err) { + if (!qdev_realize_and_unref(dev, &fdctrl->bus.bus, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 1b7bc5de08..10c44dfda2 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -961,8 +961,7 @@ static void xen_block_device_create(XenBackendInstance *backend, blockdev->iothread = iothread; blockdev->drive = drive; - qdev_realize_and_unref(DEVICE(xendev), BUS(xenbus), &local_err); - if (local_err) { + if (!qdev_realize_and_unref(DEVICE(xendev), BUS(xenbus), &local_err)) { error_propagate_prepend(errp, local_err, "realization of device %s failed: ", type); diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c index 56f915e7c9..1328967461 100644 --- a/hw/char/serial-pci-multi.c +++ b/hw/char/serial-pci-multi.c @@ -106,8 +106,7 @@ static void multi_serial_pci_realize(PCIDevice *dev, Error **errp) for (i = 0; i < nports; i++) { s = pci->state + i; - qdev_realize(DEVICE(s), NULL, &err); - if (err != NULL) { + if (!qdev_realize(DEVICE(s), NULL, &err)) { error_propagate(errp, err); multi_serial_pci_exit(dev); return; diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index 298f3adba7..d22617426b 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -49,8 +49,7 @@ static void serial_pci_realize(PCIDevice *dev, Error **errp) SerialState *s = &pci->state; Error *err = NULL; - qdev_realize(DEVICE(s), NULL, &err); - if (err != NULL) { + if (!qdev_realize(DEVICE(s), NULL, &err)) { error_propagate(errp, err); return; } diff --git a/hw/char/serial.c b/hw/char/serial.c index 9eebcb27e7..e69096eace 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -991,8 +991,7 @@ static void serial_io_realize(DeviceState *dev, Error **errp) SerialState *s = &sio->serial; Error *local_err = NULL; - qdev_realize(DEVICE(s), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(s), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1098,8 +1097,7 @@ static void serial_mm_realize(DeviceState *dev, Error **errp) SerialState *s = &smm->serial; Error *local_err = NULL; - qdev_realize(DEVICE(s), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(s), NULL, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/core/cpu.c b/hw/core/cpu.c index 0f23409f1d..594441a150 100644 --- a/hw/core/cpu.c +++ b/hw/core/cpu.c @@ -59,8 +59,7 @@ CPUState *cpu_create(const char *typename) { Error *err = NULL; CPUState *cpu = CPU(object_new(typename)); - qdev_realize(DEVICE(cpu), NULL, &err); - if (err != NULL) { + if (!qdev_realize(DEVICE(cpu), NULL, &err)) { error_report_err(err); object_unref(OBJECT(cpu)); exit(EXIT_FAILURE); diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c index e6085f5d44..358c6152c7 100644 --- a/hw/cpu/a15mpcore.c +++ b/hw/cpu/a15mpcore.c @@ -76,8 +76,7 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp) qdev_prop_set_bit(gicdev, "has-virtualization-extensions", has_el2); } - sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { error_propagate(errp, err); return; } diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c index 642363d2f4..fc35dcf179 100644 --- a/hw/cpu/a9mpcore.c +++ b/hw/cpu/a9mpcore.c @@ -57,8 +57,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) scudev = DEVICE(&s->scu); qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu); - sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err)) { error_propagate(errp, err); return; } @@ -78,8 +77,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) object_property_get_bool(cpuobj, "has_el3", &error_abort); qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3); - sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { error_propagate(errp, err); return; } @@ -93,8 +91,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) gtimerdev = DEVICE(&s->gtimer); qdev_prop_set_uint32(gtimerdev, "num-cpu", s->num_cpu); - sysbus_realize(SYS_BUS_DEVICE(&s->gtimer), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gtimer), &err)) { error_propagate(errp, err); return; } @@ -102,8 +99,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) mptimerdev = DEVICE(&s->mptimer); qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu); - sysbus_realize(SYS_BUS_DEVICE(&s->mptimer), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mptimer), &err)) { error_propagate(errp, err); return; } @@ -111,8 +107,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) wdtdev = DEVICE(&s->wdt); qdev_prop_set_uint32(wdtdev, "num-cpu", s->num_cpu); - sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &err)) { error_propagate(errp, err); return; } diff --git a/hw/cpu/arm11mpcore.c b/hw/cpu/arm11mpcore.c index a2afb992fb..c5eef9514d 100644 --- a/hw/cpu/arm11mpcore.c +++ b/hw/cpu/arm11mpcore.c @@ -79,8 +79,7 @@ static void mpcore_priv_realize(DeviceState *dev, Error **errp) Error *err = NULL; qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu); - sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err)) { error_propagate(errp, err); return; } @@ -91,8 +90,7 @@ static void mpcore_priv_realize(DeviceState *dev, Error **errp) ARM11MPCORE_NUM_GIC_PRIORITY_BITS); - sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { error_propagate(errp, err); return; } @@ -104,15 +102,13 @@ static void mpcore_priv_realize(DeviceState *dev, Error **errp) qdev_init_gpio_in(dev, mpcore_priv_set_irq, s->num_irq - 32); qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu); - sysbus_realize(SYS_BUS_DEVICE(&s->mptimer), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mptimer), &err)) { error_propagate(errp, err); return; } qdev_prop_set_uint32(wdtimerdev, "num-cpu", s->num_cpu); - sysbus_realize(SYS_BUS_DEVICE(&s->wdtimer), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdtimer), &err)) { error_propagate(errp, err); return; } diff --git a/hw/cpu/realview_mpcore.c b/hw/cpu/realview_mpcore.c index d2e426fa45..bf3e48b48e 100644 --- a/hw/cpu/realview_mpcore.c +++ b/hw/cpu/realview_mpcore.c @@ -70,8 +70,7 @@ static void realview_mpcore_realize(DeviceState *dev, Error **errp) int i; qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu); - sysbus_realize(SYS_BUS_DEVICE(&s->priv), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->priv), &err)) { error_propagate(errp, err); return; } @@ -81,8 +80,7 @@ static void realview_mpcore_realize(DeviceState *dev, Error **errp) } /* ??? IRQ routing is hardcoded to "normal" mode. */ for (n = 0; n < 4; n++) { - sysbus_realize(SYS_BUS_DEVICE(&s->gic[n]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic[n]), &err)) { error_propagate(errp, err); return; } diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index 41b88b878d..357fefa3c0 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -34,9 +34,7 @@ static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) Error *local_error = NULL; virtio_pci_force_virtio_1(vpci_dev); - qdev_realize(vdev, BUS(&vpci_dev->bus), &local_error); - - if (local_error) { + if (!qdev_realize(vdev, BUS(&vpci_dev->bus), &local_error)) { error_propagate(errp, local_error); return; } diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 67f409e106..0fc00fee1f 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -138,8 +138,7 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) /* init virtio bits */ virtio_pci_force_virtio_1(vpci_dev); - qdev_realize(DEVICE(g), BUS(&vpci_dev->bus), &err); - if (err) { + if (!qdev_realize(DEVICE(g), BUS(&vpci_dev->bus), &err)) { error_propagate(errp, err); return; } diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index af9f4c5a85..80a915e922 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -2640,8 +2640,7 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) s->num_prio_bits = arm_feature(&s->cpu->env, ARM_FEATURE_V7) ? 8 : 2; - sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), &err)) { error_propagate(errp, err); return; } @@ -2657,8 +2656,7 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) object_initialize_child(OBJECT(dev), "systick-reg-s", &s->systick[M_REG_S], TYPE_SYSTICK); - sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_S]), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_S]), &err)) { error_propagate(errp, err); return; } diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index 85ba0b4655..3b2e87334d 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -1833,8 +1833,7 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp) &error_fatal); object_property_set_link(OBJECT(xsrc), OBJECT(xive), "xive", &error_abort); - qdev_realize(DEVICE(xsrc), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1843,8 +1842,7 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp) &error_fatal); object_property_set_link(OBJECT(end_xsrc), OBJECT(xive), "xive", &error_abort); - qdev_realize(DEVICE(end_xsrc), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(end_xsrc), NULL, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/intc/realview_gic.c b/hw/intc/realview_gic.c index f11fb5259a..aa0010e91f 100644 --- a/hw/intc/realview_gic.c +++ b/hw/intc/realview_gic.c @@ -34,8 +34,7 @@ static void realview_gic_realize(DeviceState *dev, Error **errp) int numirq = 96; qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", numirq); - sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { error_propagate(errp, err); return; } diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index b7fc8dde7a..615abf5462 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -312,8 +312,7 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) &error_fatal); object_property_set_link(OBJECT(xsrc), OBJECT(xive), "xive", &error_abort); - qdev_realize(DEVICE(xsrc), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -326,8 +325,7 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) &error_fatal); object_property_set_link(OBJECT(end_xsrc), OBJECT(xive), "xive", &error_abort); - qdev_realize(DEVICE(end_xsrc), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(end_xsrc), NULL, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/intc/xics.c b/hw/intc/xics.c index d365eeca66..811b0346e1 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -384,8 +384,7 @@ Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp) object_unref(obj); object_property_set_link(obj, OBJECT(xi), ICP_PROP_XICS, &error_abort); object_property_set_link(obj, cpu, ICP_PROP_CPU, &error_abort); - qdev_realize(DEVICE(obj), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(obj), NULL, &local_err)) { object_unparent(obj); error_propagate(errp, local_err); obj = NULL; diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 2c30dc53d8..8e167306e7 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -765,8 +765,7 @@ Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp) object_unref(obj); object_property_set_link(obj, cpu, "cpu", &error_abort); object_property_set_link(obj, OBJECT(xptr), "presenter", &error_abort); - qdev_realize(DEVICE(obj), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(obj), NULL, &local_err)) { goto error; } diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index f634bcb2d1..09d7daabed 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -183,8 +183,7 @@ static void piix4_realize(PCIDevice *dev, Error **errp) /* RTC */ qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000); - qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), &err); - if (err) { + if (!qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), &err)) { error_propagate(errp, err); return; } diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index abebc7e2ef..5e861f5ae2 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -96,8 +96,7 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) object_property_set_str(OBJECT(&s->cpu), "8.40.b", "version", &error_abort); object_property_set_uint(OBJECT(&s->cpu), 0, "pvr", &error_abort); - qdev_realize(DEVICE(&s->cpu), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) { error_propagate(errp, err); return; } @@ -108,8 +107,7 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_uint(OBJECT(&s->intc), 0xffff, "intc-positive", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->intc), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->intc), &err)) { error_propagate(errp, err); return; } diff --git a/hw/mips/cps.c b/hw/mips/cps.c index 0d7f3cf673..22b932890d 100644 --- a/hw/mips/cps.c +++ b/hw/mips/cps.c @@ -109,8 +109,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) if (saar_present) { s->itu.saar = &env->CP0_SAAR; } - sysbus_realize(SYS_BUS_DEVICE(&s->itu), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->itu), &err)) { error_propagate(errp, err); return; } @@ -125,8 +124,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->cpc), 1, "vp-start-running", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->cpc), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpc), &err)) { error_propagate(errp, err); return; } @@ -140,8 +138,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->gic), 128, "num-irq", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { error_propagate(errp, err); return; } @@ -163,8 +160,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->gcr), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), &err)) { error_propagate(errp, err); return; } diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 5bbc7770fa..cc7c26d67c 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -526,8 +526,7 @@ static void cuda_realize(DeviceState *dev, Error **errp) ADBBusState *adb_bus = &s->adb_bus; struct tm tm; - sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_cuda), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_cuda), &err)) { error_propagate(errp, err); return; } diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 3251c79f46..42414797e2 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -100,8 +100,7 @@ static void macio_common_realize(PCIDevice *d, Error **errp) SysBusDevice *sysbus_dev; Error *err = NULL; - qdev_realize(DEVICE(&s->dbdma), BUS(&s->macio_bus), &err); - if (err) { + if (!qdev_realize(DEVICE(&s->dbdma), BUS(&s->macio_bus), &err)) { error_propagate(errp, err); return; } @@ -116,8 +115,7 @@ static void macio_common_realize(PCIDevice *d, Error **errp) qdev_prop_set_chr(DEVICE(&s->escc), "chrB", serial_hd(1)); qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial); qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial); - qdev_realize(DEVICE(&s->escc), BUS(&s->macio_bus), &err); - if (err) { + if (!qdev_realize(DEVICE(&s->escc), BUS(&s->macio_bus), &err)) { error_propagate(errp, err); return; } @@ -159,8 +157,7 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp) qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency", s->frequency); - qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), &err); - if (err) { + if (!qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), &err)) { error_propagate(errp, err); return; } @@ -176,8 +173,7 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp) sysbus_connect_irq(sysbus_dev, 1, qdev_get_gpio_in(pic_dev, OLDWORLD_ESCCA_IRQ)); - qdev_realize(DEVICE(&os->nvram), BUS(&s->macio_bus), &err); - if (err) { + if (!qdev_realize(DEVICE(&os->nvram), BUS(&s->macio_bus), &err)) { error_propagate(errp, err); return; } @@ -345,8 +341,7 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) object_property_set_link(OBJECT(&s->pmu), OBJECT(sysbus_dev), "gpio", &error_abort); qdev_prop_set_bit(DEVICE(&s->pmu), "has-adb", ns->has_adb); - qdev_realize(DEVICE(&s->pmu), BUS(&s->macio_bus), &err); - if (err) { + if (!qdev_realize(DEVICE(&s->pmu), BUS(&s->macio_bus), &err)) { error_propagate(errp, err); return; } @@ -363,8 +358,7 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency", s->frequency); - qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), &err); - if (err) { + if (!qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), &err)) { error_propagate(errp, err); return; } diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index 598d8e7517..42ba963d8c 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -740,8 +740,7 @@ static void pmu_realize(DeviceState *dev, Error **errp) ADBBusState *adb_bus = &s->adb_bus; struct tm tm; - sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_pmu), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_pmu), &err)) { error_propagate(errp, err); return; } diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index 3ec904a55f..7b547b1d78 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -1003,8 +1003,7 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&phb->lsis), PNV_PHB3_NUM_LSI, "nr-irqs", &error_abort); - qdev_realize(DEVICE(&phb->lsis), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&phb->lsis), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1022,8 +1021,7 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&phb->msis), PHB3_MAX_MSI, "nr-irqs", &error_abort); - qdev_realize(DEVICE(&phb->msis), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&phb->msis), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1031,8 +1029,7 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) /* Power Bus Common Queue */ object_property_set_link(OBJECT(&phb->pbcq), OBJECT(phb), "phb", &error_abort); - qdev_realize(DEVICE(&phb->pbcq), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&phb->pbcq), NULL, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 10716d759d..53c2b1785b 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1218,8 +1218,7 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) } object_property_set_int(OBJECT(xsrc), nr_irqs, "nr-irqs", &error_fatal); object_property_set_link(OBJECT(xsrc), OBJECT(phb), "xive", &error_fatal); - qdev_realize(DEVICE(xsrc), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index 2d634c838e..45a1b3719d 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -390,8 +390,7 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp) object_property_set_int(stk_obj, i, "stack-no", &error_abort); object_property_set_link(stk_obj, OBJECT(pec), "pec", &error_abort); - qdev_realize(DEVICE(stk_obj), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(stk_obj), NULL, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 51bf95b303..97fa970e72 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -771,8 +771,7 @@ static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc, dev = qdev_new(TYPE_KVM_OPENPIC); qdev_prop_set_uint32(dev, "model", pmc->mpic_version); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &err); - if (err) { + if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &err)) { error_propagate(errp, err); object_unparent(OBJECT(dev)); return NULL; diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 643098ad5f..f2d70c3e18 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1140,8 +1140,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) "bar", &error_fatal); object_property_set_link(OBJECT(&chip8->psi), OBJECT(chip8->xics), ICS_PROP_XICS, &error_abort); - qdev_realize(DEVICE(&chip8->psi), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&chip8->psi), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1171,8 +1170,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) /* Create the simplified OCC model */ object_property_set_link(OBJECT(&chip8->occ), OBJECT(&chip8->psi), "psi", &error_abort); - qdev_realize(DEVICE(&chip8->occ), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&chip8->occ), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1185,8 +1183,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) /* HOMER */ object_property_set_link(OBJECT(&chip8->homer), OBJECT(chip), "chip", &error_abort); - qdev_realize(DEVICE(&chip8->homer), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&chip8->homer), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1205,8 +1202,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(phb), i, "index", &error_fatal); object_property_set_int(OBJECT(phb), chip->chip_id, "chip-id", &error_fatal); - sysbus_realize(SYS_BUS_DEVICE(phb), &local_err); - if (local_err) { + if (!sysbus_realize(SYS_BUS_DEVICE(phb), &local_err)) { error_propagate(errp, local_err); return; } @@ -1384,8 +1380,7 @@ static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp) &error_fatal); object_property_set_link(OBJECT(pec), OBJECT(get_system_memory()), "system-memory", &error_abort); - qdev_realize(DEVICE(pec), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(pec), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1409,8 +1404,7 @@ static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp) object_property_set_int(obj, PNV_PHB4_DEVICE_ID, "device-id", &error_fatal); object_property_set_link(obj, OBJECT(stack), "stack", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(obj), &local_err); - if (local_err) { + if (!sysbus_realize(SYS_BUS_DEVICE(obj), &local_err)) { error_propagate(errp, local_err); return; } @@ -1469,8 +1463,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) "tm-bar", &error_fatal); object_property_set_link(OBJECT(&chip9->xive), OBJECT(chip), "chip", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&chip9->xive), &local_err); - if (local_err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&chip9->xive), &local_err)) { error_propagate(errp, local_err); return; } @@ -1480,8 +1473,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* Processor Service Interface (PSI) Host Bridge */ object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip), "bar", &error_fatal); - qdev_realize(DEVICE(&chip9->psi), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&chip9->psi), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1491,8 +1483,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* LPC */ object_property_set_link(OBJECT(&chip9->lpc), OBJECT(&chip9->psi), "psi", &error_abort); - qdev_realize(DEVICE(&chip9->lpc), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&chip9->lpc), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1505,8 +1496,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* Create the simplified OCC model */ object_property_set_link(OBJECT(&chip9->occ), OBJECT(&chip9->psi), "psi", &error_abort); - qdev_realize(DEVICE(&chip9->occ), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&chip9->occ), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1519,8 +1509,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* HOMER */ object_property_set_link(OBJECT(&chip9->homer), OBJECT(chip), "chip", &error_abort); - qdev_realize(DEVICE(&chip9->homer), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&chip9->homer), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1601,8 +1590,7 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) /* Processor Service Interface (PSI) Host Bridge */ object_property_set_int(OBJECT(&chip10->psi), PNV10_PSIHB_BASE(chip), "bar", &error_fatal); - qdev_realize(DEVICE(&chip10->psi), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&chip10->psi), NULL, &local_err)) { error_propagate(errp, local_err); return; } @@ -1612,8 +1600,7 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) /* LPC */ object_property_set_link(OBJECT(&chip10->lpc), OBJECT(&chip10->psi), "psi", &error_abort); - qdev_realize(DEVICE(&chip10->lpc), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&chip10->lpc), NULL, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index c986c16db1..d699f077ad 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -173,8 +173,7 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp) Error *local_err = NULL; PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip); - qdev_realize(DEVICE(cpu), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(cpu), NULL, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 75b8ae9703..7efe6e138f 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -510,8 +510,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - qdev_realize(DEVICE(ics), NULL, &err); - if (err) { + if (!qdev_realize(DEVICE(ics), NULL, &err)) { error_propagate(errp, err); return; } @@ -851,8 +850,7 @@ static void pnv_psi_power9_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(xsrc), PSIHB9_NUM_IRQS, "nr-irqs", &error_fatal); object_property_set_link(OBJECT(xsrc), OBJECT(psi), "xive", &error_abort); - qdev_realize(DEVICE(xsrc), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 26ad566f42..85330d08a1 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -239,8 +239,7 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, CPUState *cs = CPU(cpu); Error *local_err = NULL; - qdev_realize(DEVICE(cpu), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(cpu), NULL, &local_err)) { goto error; } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 897bf98587..1d0db57fc5 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -311,8 +311,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) object_property_set_link(obj, OBJECT(spapr), ICS_PROP_XICS, &error_abort); object_property_set_int(obj, smc->nr_xirqs, "nr-irqs", &error_abort); - qdev_realize(DEVICE(obj), NULL, &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(obj), NULL, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 19223e4c29..5fce455d30 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -127,8 +127,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) &s->flash_mem); /* PLIC */ - sysbus_realize(SYS_BUS_DEVICE(&s->plic), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->plic), &err)) { error_propagate(errp, err); return; } @@ -136,8 +135,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) /* UART */ qdev_prop_set_chr(DEVICE(&(s->uart)), "chardev", serial_hd(0)); - sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err); - if (err != NULL) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err)) { error_propagate(errp, err); return; } diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 0cb66ac4e2..1b2e95a977 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -221,8 +221,7 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp) /* GPIO */ - sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err)) { error_propagate(errp, err); return; } diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index a1d2edfe13..7b9e7fdc7f 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -710,8 +710,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) } object_property_set_int(OBJECT(&s->gem), GEM_REVISION, "revision", &error_abort); - sysbus_realize(SYS_BUS_DEVICE(&s->gem), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem), &err)) { error_propagate(errp, err); return; } diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 164b1fd295..cee2908ae9 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -444,15 +444,13 @@ static void realize_event_facility(DeviceState *dev, Error **errp) SCLPEventFacility *event_facility = EVENT_FACILITY(dev); Error *local_err = NULL; - qdev_realize(DEVICE(&event_facility->quiesce), - BUS(&event_facility->sbus), &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&event_facility->quiesce), + BUS(&event_facility->sbus), &local_err)) { error_propagate(errp, local_err); return; } - qdev_realize(DEVICE(&event_facility->cpu_hotplug), - BUS(&event_facility->sbus), &local_err); - if (local_err) { + if (!qdev_realize(DEVICE(&event_facility->cpu_hotplug), + BUS(&event_facility->sbus), &local_err)) { error_propagate(errp, local_err); qdev_unrealize(DEVICE(&event_facility->quiesce)); return; diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 736965c928..9e6b170fa8 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -831,8 +831,7 @@ static S390PCIBusDevice *s390_pci_device_new(S390pciState *s, "zPCI device could not be created: "); return NULL; } - qdev_realize_and_unref(dev, BUS(s->bus), &local_err); - if (local_err) { + if (!qdev_realize_and_unref(dev, BUS(s->bus), &local_err)) { object_unparent(OBJECT(dev)); error_propagate_prepend(errp, local_err, "zPCI device could not be created: "); diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index d39f6d7785..03364343eb 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -338,8 +338,7 @@ static void sclp_realize(DeviceState *dev, Error **errp) * as we can't find a fitting bus via the qom tree, we have to add the * event facility to the sysbus, so e.g. a sclp console can be created. */ - sysbus_realize(SYS_BUS_DEVICE(sclp->event_facility), &err); - if (err) { + if (!sysbus_realize(SYS_BUS_DEVICE(sclp->event_facility), &err)) { goto out; } diff --git a/hw/s390x/virtio-ccw-crypto.c b/hw/s390x/virtio-ccw-crypto.c index ca6753bff3..36cfdf865c 100644 --- a/hw/s390x/virtio-ccw-crypto.c +++ b/hw/s390x/virtio-ccw-crypto.c @@ -21,8 +21,7 @@ static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) DeviceState *vdev = DEVICE(&dev->vdev); Error *err = NULL; - qdev_realize(vdev, BUS(&ccw_dev->bus), &err); - if (err) { + if (!qdev_realize(vdev, BUS(&ccw_dev->bus), &err)) { error_propagate(errp, err); return; } diff --git a/hw/s390x/virtio-ccw-rng.c b/hw/s390x/virtio-ccw-rng.c index 4077160f49..513f85ac63 100644 --- a/hw/s390x/virtio-ccw-rng.c +++ b/hw/s390x/virtio-ccw-rng.c @@ -22,8 +22,7 @@ static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) DeviceState *vdev = DEVICE(&dev->vdev); Error *err = NULL; - qdev_realize(vdev, BUS(&ccw_dev->bus), &err); - if (err) { + if (!qdev_realize(vdev, BUS(&ccw_dev->bus), &err)) { error_propagate(errp, err); return; } diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index b878a08080..365d09fb48 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -293,8 +293,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, qdev_prop_set_enum(dev, "rerror", rerror); qdev_prop_set_enum(dev, "werror", werror); - qdev_realize_and_unref(dev, &bus->qbus, &err); - if (err != NULL) { + if (!qdev_realize_and_unref(dev, &bus->qbus, &err)) { error_propagate(errp, err); object_unparent(OBJECT(dev)); return NULL; diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c index 538d3bad3d..2d0d5651e3 100644 --- a/hw/sd/aspeed_sdhci.c +++ b/hw/sd/aspeed_sdhci.c @@ -145,8 +145,7 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp) return; } - sysbus_realize(sbd_slot, &err); - if (err) { + if (!sysbus_realize(sbd_slot, &err)) { error_propagate(errp, err); return; } diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 25cdf4c966..c57d76b1c8 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -266,8 +266,7 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) goto fail; } - qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err); - if (err) { + if (!qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err)) { goto fail; } diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 957559b18d..ba27afe9f2 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -704,8 +704,7 @@ USBDevice *usbdevice_create(const char *cmdline) error_report("Failed to create USB device '%s'", f->name); return NULL; } - usb_realize_and_unref(dev, bus, &err); - if (err) { + if (!usb_realize_and_unref(dev, bus, &err)) { error_reportf_err(err, "Failed to initialize USB device '%s': ", f->name); object_unparent(OBJECT(dev)); diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c index cf1afb47a6..20ce1b113b 100644 --- a/hw/virtio/virtio-rng-pci.c +++ b/hw/virtio/virtio-rng-pci.c @@ -36,8 +36,7 @@ static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) DeviceState *vdev = DEVICE(&vrng->vdev); Error *err = NULL; - qdev_realize(vdev, BUS(&vpci_dev->bus), &err); - if (err) { + if (!qdev_realize(vdev, BUS(&vpci_dev->bus), &err)) { error_propagate(errp, err); return; } diff --git a/qdev-monitor.c b/qdev-monitor.c index 648b8ac4fa..cefd21b8e6 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -679,8 +679,7 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) } dev->opts = opts; - qdev_realize(DEVICE(dev), bus, &err); - if (err != NULL) { + if (!qdev_realize(DEVICE(dev), bus, &err)) { dev->opts = NULL; goto err_del_dev; } From 0a15a73236cb068cfd28f8c6846f66ab007f81bb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:33 +0200 Subject: [PATCH 2037/2595] macio: Tidy up error handling in macio_newworld_realize() macio_newworld_realize() effectively ignores ns->gpio realization errors, leaking the Error object. Fortunately, macio_gpio_realize() can't actually fail. Tidy up. Cc: Mark Cave-Ayland Cc: David Gibson Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Acked-by: David Gibson Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Greg Kurz Message-Id: <20200707160613.848843-6-armbru@redhat.com> --- hw/misc/macio/macio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 42414797e2..be66bb7758 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -334,7 +334,9 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) &error_abort); memory_region_add_subregion(&s->bar, 0x50, sysbus_mmio_get_region(sysbus_dev, 0)); - qdev_realize(DEVICE(&ns->gpio), BUS(&s->macio_bus), &err); + if (!qdev_realize(DEVICE(&ns->gpio), BUS(&s->macio_bus), errp)) { + return; + } /* PMU */ object_initialize_child(OBJECT(s), "pmu", &s->pmu, TYPE_VIA_PMU); From 79c3e2bc6e78eb9cb197a9b3a9fc885ec1b7c720 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:34 +0200 Subject: [PATCH 2038/2595] virtio-crypto-pci: Tidy up virtio_crypto_pci_realize() virtio_crypto_pci_realize() continues after realization of its "virtio-crypto-device" fails. Only an object_property_set_link() follows; looks harmless to me. Tidy up anyway: return after failure, just like virtio_rng_pci_realize() does. Cc: "Gonglei (Arei)" Cc: Michael S. Tsirkin Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Gonglei < arei.gonglei@huawei.com> Message-Id: <20200707160613.848843-7-armbru@redhat.com> --- hw/virtio/virtio-crypto-pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c index 72be531c95..0755722288 100644 --- a/hw/virtio/virtio-crypto-pci.c +++ b/hw/virtio/virtio-crypto-pci.c @@ -54,7 +54,9 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) } virtio_pci_force_virtio_1(vpci_dev); - qdev_realize(vdev, BUS(&vpci_dev->bus), errp); + if (!qdev_realize(vdev, BUS(&vpci_dev->bus), errp)) { + return; + } object_property_set_link(OBJECT(vcrypto), OBJECT(vcrypto->vdev.conf.cryptodev), "cryptodev", NULL); From c6ecec43b240b545ef2f1d6eed5b1e539dfdb2c1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:35 +0200 Subject: [PATCH 2039/2595] qemu-option: Check return value instead of @err where convenient Convert uses like opts = qemu_opts_create(..., &err); if (err) { ... } to opts = qemu_opts_create(..., errp); if (!opts) { ... } Eliminate error_propagate() that are now unnecessary. Delete @err that are now unused. Note that we can't drop parallels_open()'s error_propagate() here. We continue to execute it even in the converted case. It's a no-op then: local_err is null. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Greg Kurz Message-Id: <20200707160613.848843-8-armbru@redhat.com> --- block/parallels.c | 4 ++-- blockdev.c | 5 ++--- qdev-monitor.c | 5 ++--- util/qemu-config.c | 10 ++++------ util/qemu-option.c | 12 ++++-------- 5 files changed, 14 insertions(+), 22 deletions(-) diff --git a/block/parallels.c b/block/parallels.c index 63a1cde8af..f26f03c926 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -824,8 +824,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, } } - opts = qemu_opts_create(¶llels_runtime_opts, NULL, 0, &local_err); - if (local_err != NULL) { + opts = qemu_opts_create(¶llels_runtime_opts, NULL, 0, errp); + if (!opts) { goto fail_options; } diff --git a/blockdev.c b/blockdev.c index 31d5eaf6bf..b52ed9de86 100644 --- a/blockdev.c +++ b/blockdev.c @@ -504,9 +504,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, /* Check common options by copying from bs_opts to opts, all other options * stay in bs_opts for processing by bdrv_open(). */ id = qdict_get_try_str(bs_opts, "id"); - opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error); - if (error) { - error_propagate(errp, error); + opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, errp); + if (!opts) { goto err_no_opts; } diff --git a/qdev-monitor.c b/qdev-monitor.c index cefd21b8e6..cbcbbb5d50 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -802,9 +802,8 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp) QemuOpts *opts; DeviceState *dev; - opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err); - if (local_err) { - error_propagate(errp, local_err); + opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, errp); + if (!opts) { return; } if (!monitor_cur_is_qmp() && qdev_device_help(opts)) { diff --git a/util/qemu-config.c b/util/qemu-config.c index 772f5a219e..c0d0e9b8ef 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -493,9 +493,8 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, goto out; } - subopts = qemu_opts_create(opts, NULL, 0, &local_err); - if (local_err) { - error_propagate(errp, local_err); + subopts = qemu_opts_create(opts, NULL, 0, errp); + if (!subopts) { goto out; } @@ -538,10 +537,9 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, } opt_name = g_strdup_printf("%s.%u", opts->name, i++); - subopts = qemu_opts_create(opts, opt_name, 1, &local_err); + subopts = qemu_opts_create(opts, opt_name, 1, errp); g_free(opt_name); - if (local_err) { - error_propagate(errp, local_err); + if (!subopts) { goto out; } diff --git a/util/qemu-option.c b/util/qemu-option.c index 0ebfd97a98..fd1fd23521 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -670,11 +670,9 @@ void qemu_opts_set(QemuOptsList *list, const char *id, const char *name, const char *value, Error **errp) { QemuOpts *opts; - Error *local_err = NULL; - opts = qemu_opts_create(list, id, 1, &local_err); - if (local_err) { - error_propagate(errp, local_err); + opts = qemu_opts_create(list, id, 1, errp); + if (!opts) { return; } qemu_opt_set(opts, name, value, errp); @@ -1012,10 +1010,8 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, QemuOpts *opts; const QDictEntry *entry; - opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, - &local_err); - if (local_err) { - error_propagate(errp, local_err); + opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, errp); + if (!opts) { return NULL; } From 9da7197a801eef8a0015d1079b7015432cf9e6b6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:36 +0200 Subject: [PATCH 2040/2595] qemu-option: Make uses of find_desc_by_name() more similar This is to make the next commit easier to review. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Greg Kurz Message-Id: <20200707160613.848843-9-armbru@redhat.com> --- util/qemu-option.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/util/qemu-option.c b/util/qemu-option.c index fd1fd23521..1df55bc881 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -270,6 +270,7 @@ static void qemu_opt_del_all(QemuOpts *opts, const char *name) const char *qemu_opt_get(QemuOpts *opts, const char *name) { QemuOpt *opt; + const QemuOptDesc *desc; if (opts == NULL) { return NULL; @@ -277,7 +278,7 @@ const char *qemu_opt_get(QemuOpts *opts, const char *name) opt = qemu_opt_find(opts, name); if (!opt) { - const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); + desc = find_desc_by_name(opts->list->desc, name); if (desc && desc->def_value_str) { return desc->def_value_str; } @@ -348,6 +349,7 @@ static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name, bool defval, bool del) { QemuOpt *opt; + const QemuOptDesc *desc; bool ret = defval; if (opts == NULL) { @@ -356,7 +358,7 @@ static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name, opt = qemu_opt_find(opts, name); if (opt == NULL) { - const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); + desc = find_desc_by_name(opts->list->desc, name); if (desc && desc->def_value_str) { parse_option_bool(name, desc->def_value_str, &ret, &error_abort); } @@ -384,6 +386,7 @@ static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name, uint64_t defval, bool del) { QemuOpt *opt; + const QemuOptDesc *desc; uint64_t ret = defval; if (opts == NULL) { @@ -392,7 +395,7 @@ static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name, opt = qemu_opt_find(opts, name); if (opt == NULL) { - const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); + desc = find_desc_by_name(opts->list->desc, name); if (desc && desc->def_value_str) { parse_option_number(name, desc->def_value_str, &ret, &error_abort); } @@ -421,6 +424,7 @@ static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name, uint64_t defval, bool del) { QemuOpt *opt; + const QemuOptDesc *desc; uint64_t ret = defval; if (opts == NULL) { @@ -429,7 +433,7 @@ static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name, opt = qemu_opt_find(opts, name); if (opt == NULL) { - const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); + desc = find_desc_by_name(opts->list->desc, name); if (desc && desc->def_value_str) { parse_option_size(name, desc->def_value_str, &ret, &error_abort); } @@ -540,18 +544,18 @@ void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, Error **errp) { QemuOpt *opt; - const QemuOptDesc *desc = opts->list->desc; + const QemuOptDesc *desc; - opt = g_malloc0(sizeof(*opt)); - opt->desc = find_desc_by_name(desc, name); - if (!opt->desc && !opts_accepts_any(opts)) { + desc = find_desc_by_name(opts->list->desc, name); + if (!desc && !opts_accepts_any(opts)) { error_setg(errp, QERR_INVALID_PARAMETER, name); - g_free(opt); return; } + opt = g_malloc0(sizeof(*opt)); opt->name = g_strdup(name); opt->opts = opts; + opt->desc = desc; opt->value.boolean = !!val; opt->str = g_strdup(val ? "on" : "off"); QTAILQ_INSERT_TAIL(&opts->head, opt, next); @@ -561,18 +565,18 @@ void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, Error **errp) { QemuOpt *opt; - const QemuOptDesc *desc = opts->list->desc; + const QemuOptDesc *desc; - opt = g_malloc0(sizeof(*opt)); - opt->desc = find_desc_by_name(desc, name); - if (!opt->desc && !opts_accepts_any(opts)) { + desc = find_desc_by_name(opts->list->desc, name); + if (!desc && !opts_accepts_any(opts)) { error_setg(errp, QERR_INVALID_PARAMETER, name); - g_free(opt); return; } + opt = g_malloc0(sizeof(*opt)); opt->name = g_strdup(name); opt->opts = opts; + opt->desc = desc; opt->value.uint = val; opt->str = g_strdup_printf("%" PRId64, val); QTAILQ_INSERT_TAIL(&opts->head, opt, next); From f23db652cb87cfb9aacc7cfd92ea01c00ca0162b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:37 +0200 Subject: [PATCH 2041/2595] qemu-option: Factor out helper find_default_by_name() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Greg Kurz Message-Id: <20200707160613.848843-10-armbru@redhat.com> --- util/qemu-option.c | 47 ++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/util/qemu-option.c b/util/qemu-option.c index 1df55bc881..14e211ddd8 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -142,6 +142,13 @@ static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc, return NULL; } +static const char *find_default_by_name(QemuOpts *opts, const char *name) +{ + const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); + + return desc ? desc->def_value_str : NULL; +} + void parse_option_size(const char *name, const char *value, uint64_t *ret, Error **errp) { @@ -270,7 +277,7 @@ static void qemu_opt_del_all(QemuOpts *opts, const char *name) const char *qemu_opt_get(QemuOpts *opts, const char *name) { QemuOpt *opt; - const QemuOptDesc *desc; + const char *def_val; if (opts == NULL) { return NULL; @@ -278,9 +285,9 @@ const char *qemu_opt_get(QemuOpts *opts, const char *name) opt = qemu_opt_find(opts, name); if (!opt) { - desc = find_desc_by_name(opts->list->desc, name); - if (desc && desc->def_value_str) { - return desc->def_value_str; + def_val = find_default_by_name(opts, name); + if (def_val) { + return def_val; } } return opt ? opt->str : NULL; @@ -312,7 +319,7 @@ const char *qemu_opt_iter_next(QemuOptsIter *iter) char *qemu_opt_get_del(QemuOpts *opts, const char *name) { QemuOpt *opt; - const QemuOptDesc *desc; + const char *def_val; char *str = NULL; if (opts == NULL) { @@ -321,9 +328,9 @@ char *qemu_opt_get_del(QemuOpts *opts, const char *name) opt = qemu_opt_find(opts, name); if (!opt) { - desc = find_desc_by_name(opts->list->desc, name); - if (desc && desc->def_value_str) { - str = g_strdup(desc->def_value_str); + def_val = find_default_by_name(opts, name); + if (def_val) { + str = g_strdup(def_val); } return str; } @@ -349,7 +356,7 @@ static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name, bool defval, bool del) { QemuOpt *opt; - const QemuOptDesc *desc; + const char *def_val; bool ret = defval; if (opts == NULL) { @@ -358,9 +365,9 @@ static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name, opt = qemu_opt_find(opts, name); if (opt == NULL) { - desc = find_desc_by_name(opts->list->desc, name); - if (desc && desc->def_value_str) { - parse_option_bool(name, desc->def_value_str, &ret, &error_abort); + def_val = find_default_by_name(opts, name); + if (def_val) { + parse_option_bool(name, def_val, &ret, &error_abort); } return ret; } @@ -386,7 +393,7 @@ static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name, uint64_t defval, bool del) { QemuOpt *opt; - const QemuOptDesc *desc; + const char *def_val; uint64_t ret = defval; if (opts == NULL) { @@ -395,9 +402,9 @@ static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name, opt = qemu_opt_find(opts, name); if (opt == NULL) { - desc = find_desc_by_name(opts->list->desc, name); - if (desc && desc->def_value_str) { - parse_option_number(name, desc->def_value_str, &ret, &error_abort); + def_val = find_default_by_name(opts, name); + if (def_val) { + parse_option_number(name, def_val, &ret, &error_abort); } return ret; } @@ -424,7 +431,7 @@ static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name, uint64_t defval, bool del) { QemuOpt *opt; - const QemuOptDesc *desc; + const char *def_val; uint64_t ret = defval; if (opts == NULL) { @@ -433,9 +440,9 @@ static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name, opt = qemu_opt_find(opts, name); if (opt == NULL) { - desc = find_desc_by_name(opts->list->desc, name); - if (desc && desc->def_value_str) { - parse_option_size(name, desc->def_value_str, &ret, &error_abort); + def_val = find_default_by_name(opts, name); + if (def_val) { + parse_option_size(name, def_val, &ret, &error_abort); } return ret; } From 44b0b7d1758d105cea2d6156a071e8d9e2256f69 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:38 +0200 Subject: [PATCH 2042/2595] qemu-option: Simplify around find_default_by_name() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-11-armbru@redhat.com> Reviewed-by: Greg Kurz --- util/qemu-option.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/util/qemu-option.c b/util/qemu-option.c index 14e211ddd8..e7b540a21b 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -277,7 +277,6 @@ static void qemu_opt_del_all(QemuOpts *opts, const char *name) const char *qemu_opt_get(QemuOpts *opts, const char *name) { QemuOpt *opt; - const char *def_val; if (opts == NULL) { return NULL; @@ -285,12 +284,10 @@ const char *qemu_opt_get(QemuOpts *opts, const char *name) opt = qemu_opt_find(opts, name); if (!opt) { - def_val = find_default_by_name(opts, name); - if (def_val) { - return def_val; - } + return find_default_by_name(opts, name); } - return opt ? opt->str : NULL; + + return opt->str; } void qemu_opt_iter_init(QemuOptsIter *iter, QemuOpts *opts, const char *name) @@ -319,8 +316,7 @@ const char *qemu_opt_iter_next(QemuOptsIter *iter) char *qemu_opt_get_del(QemuOpts *opts, const char *name) { QemuOpt *opt; - const char *def_val; - char *str = NULL; + char *str; if (opts == NULL) { return NULL; @@ -328,11 +324,7 @@ char *qemu_opt_get_del(QemuOpts *opts, const char *name) opt = qemu_opt_find(opts, name); if (!opt) { - def_val = find_default_by_name(opts, name); - if (def_val) { - str = g_strdup(def_val); - } - return str; + return g_strdup(find_default_by_name(opts, name)); } str = opt->str; opt->str = NULL; From 81a8a0726a67b0f28d36201c1b9e0944e5849a76 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:39 +0200 Subject: [PATCH 2043/2595] qemu-option: Factor out helper opt_create() There is just one use so far. The next commit will add more. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-12-armbru@redhat.com> --- util/qemu-option.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/util/qemu-option.c b/util/qemu-option.c index e7b540a21b..1023fe7527 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -499,6 +499,23 @@ int qemu_opt_unset(QemuOpts *opts, const char *name) } } +static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value, + bool prepend) +{ + QemuOpt *opt = g_malloc0(sizeof(*opt)); + + opt->name = g_strdup(name); + opt->str = value; + opt->opts = opts; + if (prepend) { + QTAILQ_INSERT_HEAD(&opts->head, opt, next); + } else { + QTAILQ_INSERT_TAIL(&opts->head, opt, next); + } + + return opt; +} + static void opt_set(QemuOpts *opts, const char *name, char *value, bool prepend, bool *help_wanted, Error **errp) { @@ -516,16 +533,8 @@ static void opt_set(QemuOpts *opts, const char *name, char *value, return; } - opt = g_malloc0(sizeof(*opt)); - opt->name = g_strdup(name); - opt->opts = opts; - if (prepend) { - QTAILQ_INSERT_HEAD(&opts->head, opt, next); - } else { - QTAILQ_INSERT_TAIL(&opts->head, opt, next); - } + opt = opt_create(opts, name, value, prepend); opt->desc = desc; - opt->str = value; qemu_opt_parse(opt, &local_err); if (local_err) { error_propagate(errp, local_err); From 64af7a8bad2cbda178730a842fa0d43d02415dbc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:40 +0200 Subject: [PATCH 2044/2595] qemu-option: Replace opt_set() by cleaner opt_validate() opt_set() frees its argument @value on failure. Slightly unclean; functions ideally do nothing on failure. To tidy this up, move opt_create() from opt_set() into its callers, along with the cleanup. Rename opt_set() to opt_validate(), noting its similarity to qemu_opts_validate(). Drop redundant parameter @opts; use opt->opts instead. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-13-armbru@redhat.com> --- util/qemu-option.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/util/qemu-option.c b/util/qemu-option.c index 1023fe7527..d8233b3b35 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -516,36 +516,39 @@ static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value, return opt; } -static void opt_set(QemuOpts *opts, const char *name, char *value, - bool prepend, bool *help_wanted, Error **errp) +static bool opt_validate(QemuOpt *opt, bool *help_wanted, + Error **errp) { - QemuOpt *opt; const QemuOptDesc *desc; Error *local_err = NULL; - desc = find_desc_by_name(opts->list->desc, name); - if (!desc && !opts_accepts_any(opts)) { - g_free(value); - error_setg(errp, QERR_INVALID_PARAMETER, name); - if (help_wanted && is_help_option(name)) { + desc = find_desc_by_name(opt->opts->list->desc, opt->name); + if (!desc && !opts_accepts_any(opt->opts)) { + error_setg(errp, QERR_INVALID_PARAMETER, opt->name); + if (help_wanted && is_help_option(opt->name)) { *help_wanted = true; } - return; + return false; } - opt = opt_create(opts, name, value, prepend); opt->desc = desc; qemu_opt_parse(opt, &local_err); if (local_err) { error_propagate(errp, local_err); - qemu_opt_del(opt); + return false; } + + return true; } void qemu_opt_set(QemuOpts *opts, const char *name, const char *value, Error **errp) { - opt_set(opts, name, g_strdup(value), false, NULL, errp); + QemuOpt *opt = opt_create(opts, name, g_strdup(value), false); + + if (!opt_validate(opt, NULL, errp)) { + qemu_opt_del(opt); + } } void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, @@ -817,9 +820,9 @@ static void opts_do_parse(QemuOpts *opts, const char *params, const char *firstname, bool prepend, bool *help_wanted, Error **errp) { - Error *local_err = NULL; char *option, *value; const char *p; + QemuOpt *opt; for (p = params; *p;) { p = get_opt_name_value(p, firstname, &option, &value); @@ -831,10 +834,10 @@ static void opts_do_parse(QemuOpts *opts, const char *params, continue; } - opt_set(opts, option, value, prepend, help_wanted, &local_err); + opt = opt_create(opts, option, value, prepend); g_free(option); - if (local_err) { - error_propagate(errp, local_err); + if (!opt_validate(opt, help_wanted, errp)) { + qemu_opt_del(opt); return; } } From c75d7f71918b8497a710f3f2b646567c09db3770 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:41 +0200 Subject: [PATCH 2045/2595] qemu-option: Make functions taking Error ** return bool, not void See recent commit "error: Document Error API usage rules" for rationale. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-14-armbru@redhat.com> --- blockdev.c | 5 ++- include/qemu/option.h | 16 ++++---- util/qemu-option.c | 92 +++++++++++++++++++++++++------------------ 3 files changed, 64 insertions(+), 49 deletions(-) diff --git a/blockdev.c b/blockdev.c index b52ed9de86..39e12a62b3 100644 --- a/blockdev.c +++ b/blockdev.c @@ -705,7 +705,7 @@ BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs) : QTAILQ_FIRST(&monitor_bdrv_states); } -static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to, +static bool qemu_opt_rename(QemuOpts *opts, const char *from, const char *to, Error **errp) { const char *value; @@ -715,7 +715,7 @@ static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to, if (qemu_opt_find(opts, to)) { error_setg(errp, "'%s' and its alias '%s' can't be used at the " "same time", to, from); - return; + return false; } } @@ -724,6 +724,7 @@ static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to, qemu_opt_set(opts, to, value, &error_abort); qemu_opt_unset(opts, from); } + return true; } QemuOptsList qemu_legacy_drive_opts = { diff --git a/include/qemu/option.h b/include/qemu/option.h index ac50d25774..05e8a15c73 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -43,7 +43,7 @@ */ const char *get_opt_value(const char *p, char **value); -void parse_option_size(const char *name, const char *value, +bool parse_option_size(const char *name, const char *value, uint64_t *ret, Error **errp); bool has_help_option(const char *param); @@ -93,11 +93,11 @@ uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char *name, uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name, uint64_t defval); int qemu_opt_unset(QemuOpts *opts, const char *name); -void qemu_opt_set(QemuOpts *opts, const char *name, const char *value, +bool qemu_opt_set(QemuOpts *opts, const char *name, const char *value, Error **errp); -void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, +bool qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, Error **errp); -void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, +bool qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, Error **errp); typedef int (*qemu_opt_loopfunc)(void *opaque, const char *name, const char *value, @@ -119,13 +119,13 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists, Error **errp); void qemu_opts_reset(QemuOptsList *list); void qemu_opts_loc_restore(QemuOpts *opts); -void qemu_opts_set(QemuOptsList *list, const char *id, +bool qemu_opts_set(QemuOptsList *list, const char *id, const char *name, const char *value, Error **errp); const char *qemu_opts_id(QemuOpts *opts); void qemu_opts_set_id(QemuOpts *opts, char *id); void qemu_opts_del(QemuOpts *opts); -void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp); -void qemu_opts_do_parse(QemuOpts *opts, const char *params, +bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp); +bool qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname, Error **errp); QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params, bool permit_abbrev); @@ -138,7 +138,7 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict, QemuOptsList *list, bool del); QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict); -void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp); +bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp); typedef int (*qemu_opts_loopfunc)(void *opaque, QemuOpts *opts, Error **errp); int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, diff --git a/util/qemu-option.c b/util/qemu-option.c index d8233b3b35..2f4fb62120 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -96,7 +96,7 @@ const char *get_opt_value(const char *p, char **value) return offset; } -static void parse_option_bool(const char *name, const char *value, bool *ret, +static bool parse_option_bool(const char *name, const char *value, bool *ret, Error **errp) { if (!strcmp(value, "on")) { @@ -106,10 +106,12 @@ static void parse_option_bool(const char *name, const char *value, bool *ret, } else { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "'on' or 'off'"); + return false; } + return true; } -static void parse_option_number(const char *name, const char *value, +static bool parse_option_number(const char *name, const char *value, uint64_t *ret, Error **errp) { uint64_t number; @@ -119,13 +121,14 @@ static void parse_option_number(const char *name, const char *value, if (err == -ERANGE) { error_setg(errp, "Value '%s' is too large for parameter '%s'", value, name); - return; + return false; } if (err) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number"); - return; + return false; } *ret = number; + return true; } static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc, @@ -149,7 +152,7 @@ static const char *find_default_by_name(QemuOpts *opts, const char *name) return desc ? desc->def_value_str : NULL; } -void parse_option_size(const char *name, const char *value, +bool parse_option_size(const char *name, const char *value, uint64_t *ret, Error **errp) { uint64_t size; @@ -159,7 +162,7 @@ void parse_option_size(const char *name, const char *value, if (err == -ERANGE) { error_setg(errp, "Value '%s' is out of range for parameter '%s'", value, name); - return; + return false; } if (err) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, @@ -167,9 +170,10 @@ void parse_option_size(const char *name, const char *value, error_append_hint(errp, "Optional suffix k, M, G, T, P or E means" " kilo-, mega-, giga-, tera-, peta-\n" "and exabytes, respectively.\n"); - return; + return false; } *ret = size; + return true; } static const char *opt_type_to_string(enum QemuOptType type) @@ -457,24 +461,24 @@ uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name, return qemu_opt_get_size_helper(opts, name, defval, true); } -static void qemu_opt_parse(QemuOpt *opt, Error **errp) +static bool qemu_opt_parse(QemuOpt *opt, Error **errp) { if (opt->desc == NULL) - return; + return true; switch (opt->desc->type) { case QEMU_OPT_STRING: /* nothing */ - return; + return true; case QEMU_OPT_BOOL: - parse_option_bool(opt->name, opt->str, &opt->value.boolean, errp); - break; + return parse_option_bool(opt->name, opt->str, &opt->value.boolean, + errp); case QEMU_OPT_NUMBER: - parse_option_number(opt->name, opt->str, &opt->value.uint, errp); - break; + return parse_option_number(opt->name, opt->str, &opt->value.uint, + errp); case QEMU_OPT_SIZE: - parse_option_size(opt->name, opt->str, &opt->value.uint, errp); - break; + return parse_option_size(opt->name, opt->str, &opt->value.uint, + errp); default: abort(); } @@ -541,17 +545,19 @@ static bool opt_validate(QemuOpt *opt, bool *help_wanted, return true; } -void qemu_opt_set(QemuOpts *opts, const char *name, const char *value, +bool qemu_opt_set(QemuOpts *opts, const char *name, const char *value, Error **errp) { QemuOpt *opt = opt_create(opts, name, g_strdup(value), false); if (!opt_validate(opt, NULL, errp)) { qemu_opt_del(opt); + return false; } + return true; } -void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, +bool qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, Error **errp) { QemuOpt *opt; @@ -560,7 +566,7 @@ void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, desc = find_desc_by_name(opts->list->desc, name); if (!desc && !opts_accepts_any(opts)) { error_setg(errp, QERR_INVALID_PARAMETER, name); - return; + return false; } opt = g_malloc0(sizeof(*opt)); @@ -570,9 +576,10 @@ void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, opt->value.boolean = !!val; opt->str = g_strdup(val ? "on" : "off"); QTAILQ_INSERT_TAIL(&opts->head, opt, next); + return true; } -void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, +bool qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, Error **errp) { QemuOpt *opt; @@ -581,7 +588,7 @@ void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, desc = find_desc_by_name(opts->list->desc, name); if (!desc && !opts_accepts_any(opts)) { error_setg(errp, QERR_INVALID_PARAMETER, name); - return; + return false; } opt = g_malloc0(sizeof(*opt)); @@ -591,6 +598,7 @@ void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, opt->value.uint = val; opt->str = g_strdup_printf("%" PRId64, val); QTAILQ_INSERT_TAIL(&opts->head, opt, next); + return true; } /** @@ -681,16 +689,16 @@ void qemu_opts_loc_restore(QemuOpts *opts) loc_restore(&opts->loc); } -void qemu_opts_set(QemuOptsList *list, const char *id, +bool qemu_opts_set(QemuOptsList *list, const char *id, const char *name, const char *value, Error **errp) { QemuOpts *opts; opts = qemu_opts_create(list, id, 1, errp); if (!opts) { - return; + return false; } - qemu_opt_set(opts, name, value, errp); + return qemu_opt_set(opts, name, value, errp); } const char *qemu_opts_id(QemuOpts *opts) @@ -816,7 +824,7 @@ static const char *get_opt_name_value(const char *params, return p; } -static void opts_do_parse(QemuOpts *opts, const char *params, +static bool opts_do_parse(QemuOpts *opts, const char *params, const char *firstname, bool prepend, bool *help_wanted, Error **errp) { @@ -838,9 +846,11 @@ static void opts_do_parse(QemuOpts *opts, const char *params, g_free(option); if (!opt_validate(opt, help_wanted, errp)) { qemu_opt_del(opt); - return; + return false; } } + + return true; } static char *opts_parse_id(const char *params) @@ -886,10 +896,10 @@ bool has_help_option(const char *params) * key=, and is treated as if key was @firstname. * On error, store an error object through @errp if non-null. */ -void qemu_opts_do_parse(QemuOpts *opts, const char *params, +bool qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname, Error **errp) { - opts_do_parse(opts, params, firstname, false, NULL, errp); + return opts_do_parse(opts, params, firstname, false, NULL, errp); } static QemuOpts *opts_parse(QemuOptsList *list, const char *params, @@ -978,17 +988,18 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params, assert(opts); } -static void qemu_opts_from_qdict_entry(QemuOpts *opts, +static bool qemu_opts_from_qdict_entry(QemuOpts *opts, const QDictEntry *entry, Error **errp) { const char *key = qdict_entry_key(entry); QObject *obj = qdict_entry_value(entry); - char buf[32], *tmp = NULL; + char buf[32]; + g_autofree char *tmp = NULL; const char *value; if (!strcmp(key, "id")) { - return; + return true; } switch (qobject_type(obj)) { @@ -1005,11 +1016,10 @@ static void qemu_opts_from_qdict_entry(QemuOpts *opts, value = buf; break; default: - return; + return true; } - qemu_opt_set(opts, key, value, errp); - g_free(tmp); + return qemu_opt_set(opts, key, value, errp); } /* @@ -1051,7 +1061,7 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, * from the QDict. When this function returns, the QDict contains only those * entries that couldn't be added to the QemuOpts. */ -void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) +bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) { const QDictEntry *entry, *next; @@ -1066,13 +1076,15 @@ void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) qemu_opts_from_qdict_entry(opts, entry, &local_err); if (local_err) { error_propagate(errp, local_err); - return; + return false; } qdict_del(qdict, entry->key); } entry = next; } + + return true; } /* @@ -1132,7 +1144,7 @@ QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict) /* Validate parsed opts against descriptions where no * descriptions were provided in the QemuOptsList. */ -void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) +bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) { QemuOpt *opt; Error *local_err = NULL; @@ -1143,15 +1155,17 @@ void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) opt->desc = find_desc_by_name(desc, opt->name); if (!opt->desc) { error_setg(errp, QERR_INVALID_PARAMETER, opt->name); - return; + return false; } qemu_opt_parse(opt, &local_err); if (local_err) { error_propagate(errp, local_err); - return; + return false; } } + + return true; } /** From 235e59cf03ed75d0ce96c97343194ed11c146231 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:42 +0200 Subject: [PATCH 2046/2595] qemu-option: Use returned bool to check for failure The previous commit enables conversion of foo(..., &err); if (err) { ... } to if (!foo(..., &err)) { ... } for QemuOpts functions that now return true / false on success / error. Coccinelle script: @@ identifier fun = { opts_do_parse, parse_option_bool, parse_option_number, parse_option_size, qemu_opt_parse, qemu_opt_rename, qemu_opt_set, qemu_opt_set_bool, qemu_opt_set_number, qemu_opts_absorb_qdict, qemu_opts_do_parse, qemu_opts_from_qdict_entry, qemu_opts_set, qemu_opts_validate }; expression list args, args2; typedef Error; Error *err; @@ - fun(args, &err, args2); - if (err) + if (!fun(args, &err, args2)) { ... } A few line breaks tidied up manually. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-15-armbru@redhat.com> [Conflict with commit 0b6786a9c1 "block/amend: refactor qcow2 amend options" resolved by rerunning Coccinelle on master's version] --- block.c | 16 ++++++---------- block/blkdebug.c | 3 +-- block/blklogwrites.c | 3 +-- block/blkverify.c | 3 +-- block/crypto.c | 3 +-- block/curl.c | 3 +-- block/file-posix.c | 6 ++---- block/file-win32.c | 6 ++---- block/gluster.c | 15 +++++---------- block/iscsi.c | 3 +-- block/nbd.c | 3 +-- block/parallels.c | 3 +-- block/qcow2.c | 3 +-- block/quorum.c | 3 +-- block/raw-format.c | 3 +-- block/replication.c | 3 +-- block/sheepdog.c | 3 +-- block/ssh.c | 3 +-- block/throttle.c | 3 +-- block/vpc.c | 3 +-- block/vvfat.c | 3 +-- block/vxhs.c | 6 ++---- blockdev.c | 11 ++++------- chardev/char.c | 6 ++---- contrib/ivshmem-server/main.c | 4 ++-- hw/net/virtio-net.c | 5 ++--- hw/smbios/smbios.c | 24 ++++++++---------------- qapi/string-input-visitor.c | 3 +-- qemu-img.c | 20 +++++++------------- tpm.c | 3 +-- util/qemu-config.c | 12 ++++-------- util/qemu-option.c | 16 ++++++---------- 32 files changed, 71 insertions(+), 133 deletions(-) diff --git a/block.c b/block.c index 62e40db2f1..850755e04e 100644 --- a/block.c +++ b/block.c @@ -1629,8 +1629,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file, assert(options != NULL && bs->options != options); opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto fail_opts; @@ -4091,8 +4090,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, /* Process generic block layer options */ opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, reopen_state->options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, reopen_state->options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto error; @@ -6063,8 +6061,7 @@ void bdrv_img_create(const char *filename, const char *fmt, /* Parse -o options */ if (options) { - qemu_opts_do_parse(opts, options, NULL, &local_err); - if (local_err) { + if (!qemu_opts_do_parse(opts, options, NULL, &local_err)) { goto out; } } @@ -6077,8 +6074,8 @@ void bdrv_img_create(const char *filename, const char *fmt, } if (base_filename) { - qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename, &local_err); - if (local_err) { + if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename, + &local_err)) { error_setg(errp, "Backing file not supported for file format '%s'", fmt); goto out; @@ -6086,8 +6083,7 @@ void bdrv_img_create(const char *filename, const char *fmt, } if (base_fmt) { - qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, &local_err); - if (local_err) { + if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, &local_err)) { error_setg(errp, "Backing file format not supported for file " "format '%s'", fmt); goto out; diff --git a/block/blkdebug.c b/block/blkdebug.c index 7194bc7f06..d473dcf8c7 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -472,8 +472,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, uint64_t align; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto out; diff --git a/block/blklogwrites.c b/block/blklogwrites.c index 6753bd9a3e..0c93e926b1 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -149,8 +149,7 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, bool log_append; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { ret = -EINVAL; error_propagate(errp, local_err); goto fail; diff --git a/block/blkverify.c b/block/blkverify.c index 2f261de24b..666d626c57 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -116,8 +116,7 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, int ret; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto fail; diff --git a/block/crypto.c b/block/crypto.c index 2636e959ae..35aa5947d4 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -276,8 +276,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, bs->file->bs->supported_write_flags; opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); goto cleanup; } diff --git a/block/curl.c b/block/curl.c index 6e325901dc..d9552efe52 100644 --- a/block/curl.c +++ b/block/curl.c @@ -695,8 +695,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, qemu_mutex_init(&s->mutex); opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); goto out_noclean; } diff --git a/block/file-posix.c b/block/file-posix.c index d86ea57769..36acf7b911 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -490,8 +490,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, OnOffAuto locking; opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto fail; @@ -1000,8 +999,7 @@ static int raw_reopen_prepare(BDRVReopenState *state, /* Handle options changes */ opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, state->options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, state->options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto out; diff --git a/block/file-win32.c b/block/file-win32.c index 221aaf713e..5f8015319a 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -338,8 +338,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, s->type = FTYPE_FILE; opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto fail; @@ -739,8 +738,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags, QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto done; diff --git a/block/gluster.c b/block/gluster.c index 31233cac69..b68bd32d47 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -523,8 +523,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, /* create opts info from runtime_json_opts list */ opts = qemu_opts_create(&runtime_json_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { goto out; } @@ -555,8 +554,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, /* create opts info from runtime_type_opts list */ opts = qemu_opts_create(&runtime_type_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, backing_options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, backing_options, &local_err)) { goto out; } @@ -586,8 +584,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, if (gsconf->type == SOCKET_ADDRESS_TYPE_INET) { /* create opts info from runtime_inet_opts list */ opts = qemu_opts_create(&runtime_inet_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, backing_options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, backing_options, &local_err)) { goto out; } @@ -635,8 +632,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, } else { /* create opts info from runtime_unix_opts list */ opts = qemu_opts_create(&runtime_unix_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, backing_options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, backing_options, &local_err)) { goto out; } @@ -819,8 +815,7 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options, const char *filename, *logfile; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto out; diff --git a/block/iscsi.c b/block/iscsi.c index 767e3e75fd..d4dfa9914b 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1792,8 +1792,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, int i, ret = 0, timeout = 0, lun; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto out; diff --git a/block/nbd.c b/block/nbd.c index eed160c5cd..1b30d96a4f 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1840,8 +1840,7 @@ static int nbd_process_options(BlockDriverState *bs, QDict *options, int ret = -EINVAL; opts = qemu_opts_create(&nbd_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); goto error; } diff --git a/block/parallels.c b/block/parallels.c index f26f03c926..32d0ecd398 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -829,8 +829,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, goto fail_options; } - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err != NULL) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { goto fail_options; } diff --git a/block/qcow2.c b/block/qcow2.c index 38198b4e75..ce6333fd1e 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -990,8 +990,7 @@ static int qcow2_update_options_prepare(BlockDriverState *bs, encryptfmt = qdict_get_try_str(encryptopts, "format"); opts = qemu_opts_create(&qcow2_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto fail; diff --git a/block/quorum.c b/block/quorum.c index 7cf7ab1546..beb3b6dbcc 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -922,8 +922,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, } opts = qemu_opts_create(&quorum_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { ret = -EINVAL; goto exit; } diff --git a/block/raw-format.c b/block/raw-format.c index 233d019ca3..a66fbe77c7 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -79,8 +79,7 @@ static int raw_read_options(QDict *options, uint64_t *offset, bool *has_size, int ret; opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto end; diff --git a/block/replication.c b/block/replication.c index ccf7b78160..5701eeb9e8 100644 --- a/block/replication.c +++ b/block/replication.c @@ -99,8 +99,7 @@ static int replication_open(BlockDriverState *bs, QDict *options, ret = -EINVAL; opts = qemu_opts_create(&replication_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { goto fail; } diff --git a/block/sheepdog.c b/block/sheepdog.c index 27a30d17f4..a8d396dcdf 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1556,8 +1556,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags, s->aio_context = bdrv_get_aio_context(bs); opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto err_no_fd; diff --git a/block/ssh.c b/block/ssh.c index 098dbe03c1..13a2964621 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -622,8 +622,7 @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp) /* Translate legacy options */ opts = qemu_opts_create(&ssh_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); goto fail; } diff --git a/block/throttle.c b/block/throttle.c index 0ebbad0743..c0802addbb 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -49,8 +49,7 @@ static int throttle_parse_options(QDict *options, char **group, Error **errp) Error *local_err = NULL; QemuOpts *opts = qemu_opts_create(&throttle_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto fin; diff --git a/block/vpc.c b/block/vpc.c index 01fcd37e3c..119350d495 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -235,8 +235,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, } opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto fail; diff --git a/block/vvfat.c b/block/vvfat.c index 2eb8cbb19f..e3e27e0d6c 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -1149,8 +1149,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, #endif opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto fail; diff --git a/block/vxhs.c b/block/vxhs.c index d79fc97df6..237df4f185 100644 --- a/block/vxhs.c +++ b/block/vxhs.c @@ -318,8 +318,7 @@ static int vxhs_open(BlockDriverState *bs, QDict *options, opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); tcp_opts = qemu_opts_create(&runtime_tcp_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { ret = -EINVAL; goto out; } @@ -346,8 +345,7 @@ static int vxhs_open(BlockDriverState *bs, QDict *options, /* get the 'server.' arguments */ qdict_extract_subqdict(options, &backing_options, VXHS_OPT_SERVER"."); - qemu_opts_absorb_qdict(tcp_opts, backing_options, &local_err); - if (local_err != NULL) { + if (!qemu_opts_absorb_qdict(tcp_opts, backing_options, &local_err)) { ret = -EINVAL; goto out; } diff --git a/blockdev.c b/blockdev.c index 39e12a62b3..625c8ff3f2 100644 --- a/blockdev.c +++ b/blockdev.c @@ -509,8 +509,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, goto err_no_opts; } - qemu_opts_absorb_qdict(opts, bs_opts, &error); - if (error) { + if (!qemu_opts_absorb_qdict(opts, bs_opts, &error)) { error_propagate(errp, error); goto early_err; } @@ -827,9 +826,8 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, }; for (i = 0; i < ARRAY_SIZE(opt_renames); i++) { - qemu_opt_rename(all_opts, opt_renames[i].from, opt_renames[i].to, - &local_err); - if (local_err) { + if (!qemu_opt_rename(all_opts, opt_renames[i].from, + opt_renames[i].to, &local_err)) { error_propagate(errp, local_err); return NULL; } @@ -867,8 +865,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, legacy_opts = qemu_opts_create(&qemu_legacy_drive_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err)) { error_propagate(errp, local_err); goto fail; } diff --git a/chardev/char.c b/chardev/char.c index df697f3ce9..e5b43cb4b8 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -444,8 +444,7 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename, qemu_opt_set(opts, "host", host, &error_abort); qemu_opt_set(opts, "port", port, &error_abort); if (p[pos] == ',') { - qemu_opts_do_parse(opts, p+pos+1, NULL, &local_err); - if (local_err) { + if (!qemu_opts_do_parse(opts, p + pos + 1, NULL, &local_err)) { error_report_err(local_err); goto fail; } @@ -484,8 +483,7 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename, } if (strstart(filename, "unix:", &p)) { qemu_opt_set(opts, "backend", "socket", &error_abort); - qemu_opts_do_parse(opts, p, "path", &local_err); - if (local_err) { + if (!qemu_opts_do_parse(opts, p, "path", &local_err)) { error_report_err(local_err); goto fail; } diff --git a/contrib/ivshmem-server/main.c b/contrib/ivshmem-server/main.c index e4cd35f74c..ee08c4ced0 100644 --- a/contrib/ivshmem-server/main.c +++ b/contrib/ivshmem-server/main.c @@ -103,8 +103,8 @@ ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[]) break; case 'l': /* shm size */ - parse_option_size("shm_size", optarg, &args->shm_size, &err); - if (err) { + if (!parse_option_size("shm_size", optarg, &args->shm_size, + &err)) { error_report_err(err); ivshmem_server_help(argv[0]); exit(1); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 1596cb1397..48b07eb921 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3137,9 +3137,8 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp) } qdev_set_parent_bus(n->primary_dev, n->primary_bus); n->primary_should_be_hidden = false; - qemu_opt_set_bool(n->primary_device_opts, - "partially_hotplugged", true, &err); - if (err) { + if (!qemu_opt_set_bool(n->primary_device_opts, + "partially_hotplugged", true, &err)) { goto out; } hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index ffd98727ee..87afcf9142 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -964,8 +964,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) int size; struct smbios_table *table; /* legacy mode only */ - qemu_opts_validate(opts, qemu_smbios_file_opts, &err); - if (err) { + if (!qemu_opts_validate(opts, qemu_smbios_file_opts, &err)) { error_propagate(errp, err); return; } @@ -1051,8 +1050,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) switch (type) { case 0: - qemu_opts_validate(opts, qemu_smbios_type0_opts, &err); - if (err) { + if (!qemu_opts_validate(opts, qemu_smbios_type0_opts, &err)) { error_propagate(errp, err); return; } @@ -1071,8 +1069,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) } return; case 1: - qemu_opts_validate(opts, qemu_smbios_type1_opts, &err); - if (err) { + if (!qemu_opts_validate(opts, qemu_smbios_type1_opts, &err)) { error_propagate(errp, err); return; } @@ -1093,8 +1090,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) } return; case 2: - qemu_opts_validate(opts, qemu_smbios_type2_opts, &err); - if (err) { + if (!qemu_opts_validate(opts, qemu_smbios_type2_opts, &err)) { error_propagate(errp, err); return; } @@ -1106,8 +1102,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type2.location, opts, "location"); return; case 3: - qemu_opts_validate(opts, qemu_smbios_type3_opts, &err); - if (err) { + if (!qemu_opts_validate(opts, qemu_smbios_type3_opts, &err)) { error_propagate(errp, err); return; } @@ -1118,8 +1113,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type3.sku, opts, "sku"); return; case 4: - qemu_opts_validate(opts, qemu_smbios_type4_opts, &err); - if (err) { + if (!qemu_opts_validate(opts, qemu_smbios_type4_opts, &err)) { error_propagate(errp, err); return; } @@ -1131,16 +1125,14 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type4.part, opts, "part"); return; case 11: - qemu_opts_validate(opts, qemu_smbios_type11_opts, &err); - if (err) { + if (!qemu_opts_validate(opts, qemu_smbios_type11_opts, &err)) { error_propagate(errp, err); return; } save_opt_list(&type11.nvalues, &type11.values, opts, "value"); return; case 17: - qemu_opts_validate(opts, qemu_smbios_type17_opts, &err); - if (err) { + if (!qemu_opts_validate(opts, qemu_smbios_type17_opts, &err)) { error_propagate(errp, err); return; } diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c index 9be418b6d6..730fa4630d 100644 --- a/qapi/string-input-visitor.c +++ b/qapi/string-input-visitor.c @@ -318,8 +318,7 @@ static void parse_type_size(Visitor *v, const char *name, uint64_t *obj, uint64_t val; assert(siv->lm == LM_NONE); - parse_option_size(name, siv->string, &val, &err); - if (err) { + if (!parse_option_size(name, siv->string, &val, &err)) { error_propagate(errp, err); return; } diff --git a/qemu-img.c b/qemu-img.c index 53bd32bf8f..41d2b91091 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -468,8 +468,8 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts, Error *err = NULL; if (base_filename) { - qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename, &err); - if (err) { + if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename, + &err)) { error_report("Backing file not supported for file format '%s'", fmt); error_free(err); @@ -477,8 +477,7 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts, } } if (base_fmt) { - qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, &err); - if (err) { + if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, &err)) { error_report("Backing file format not supported for file " "format '%s'", fmt); error_free(err); @@ -2487,8 +2486,7 @@ static int img_convert(int argc, char **argv) opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); if (options) { - qemu_opts_do_parse(opts, options, NULL, &local_err); - if (local_err) { + if (!qemu_opts_do_parse(opts, options, NULL, &local_err)) { error_report_err(local_err); ret = -1; goto out; @@ -3963,8 +3961,7 @@ static int img_resize(int argc, char **argv) /* Parse size */ param = qemu_opts_create(&resize_options, NULL, 0, &error_abort); - qemu_opt_set(param, BLOCK_OPT_SIZE, size, &err); - if (err) { + if (!qemu_opt_set(param, BLOCK_OPT_SIZE, size, &err)) { error_report_err(err); ret = -1; qemu_opts_del(param); @@ -4215,9 +4212,7 @@ static int img_amend(int argc, char **argv) amend_opts = qemu_opts_append(amend_opts, bs->drv->amend_opts); opts = qemu_opts_create(amend_opts, NULL, 0, &error_abort); - qemu_opts_do_parse(opts, options, NULL, &err); - - if (err) { + if (!qemu_opts_do_parse(opts, options, NULL, &err)) { /* Try to parse options using the create options */ Error *err1 = NULL; amend_opts = qemu_opts_append(amend_opts, bs->drv->create_opts); @@ -5363,8 +5358,7 @@ static int img_measure(int argc, char **argv) create_opts = qemu_opts_append(create_opts, bdrv_file.create_opts); opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); if (options) { - qemu_opts_do_parse(opts, options, NULL, &local_err); - if (local_err) { + if (!qemu_opts_do_parse(opts, options, NULL, &local_err)) { error_report_err(local_err); error_report("Invalid options for file format '%s'", out_fmt); goto out; diff --git a/tpm.c b/tpm.c index 9c9e20bbb7..75bc937812 100644 --- a/tpm.c +++ b/tpm.c @@ -116,8 +116,7 @@ static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp) } /* validate backend specific opts */ - qemu_opts_validate(opts, be->opts, &local_err); - if (local_err) { + if (!qemu_opts_validate(opts, be->opts, &local_err)) { error_propagate(errp, local_err); return 1; } diff --git a/util/qemu-config.c b/util/qemu-config.c index c0d0e9b8ef..7229c79cc7 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -339,8 +339,7 @@ int qemu_set_option(const char *str) return -1; } - qemu_opt_set(opts, arg, str + offset + 1, &local_err); - if (local_err) { + if (!qemu_opt_set(opts, arg, str + offset + 1, &local_err)) { error_report_err(local_err); return -1; } @@ -441,8 +440,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) error_report("no group defined"); goto out; } - qemu_opt_set(opts, arg, value, &local_err); - if (local_err) { + if (!qemu_opt_set(opts, arg, value, &local_err)) { error_report_err(local_err); goto out; } @@ -498,8 +496,7 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, goto out; } - qemu_opts_absorb_qdict(subopts, subqdict, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(subopts, subqdict, &local_err)) { error_propagate(errp, local_err); goto out; } @@ -543,8 +540,7 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, goto out; } - qemu_opts_absorb_qdict(subopts, section, &local_err); - if (local_err) { + if (!qemu_opts_absorb_qdict(subopts, section, &local_err)) { error_propagate(errp, local_err); qemu_opts_del(subopts); goto out; diff --git a/util/qemu-option.c b/util/qemu-option.c index 2f4fb62120..1dd14a0634 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -536,8 +536,7 @@ static bool opt_validate(QemuOpt *opt, bool *help_wanted, } opt->desc = desc; - qemu_opt_parse(opt, &local_err); - if (local_err) { + if (!qemu_opt_parse(opt, &local_err)) { error_propagate(errp, local_err); return false; } @@ -929,8 +928,8 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, return NULL; } - opts_do_parse(opts, params, firstname, defaults, help_wanted, &local_err); - if (local_err) { + if (!opts_do_parse(opts, params, firstname, defaults, help_wanted, + &local_err)) { error_propagate(errp, local_err); qemu_opts_del(opts); return NULL; @@ -1045,8 +1044,7 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, for (entry = qdict_first(qdict); entry; entry = qdict_next(qdict, entry)) { - qemu_opts_from_qdict_entry(opts, entry, &local_err); - if (local_err) { + if (!qemu_opts_from_qdict_entry(opts, entry, &local_err)) { error_propagate(errp, local_err); qemu_opts_del(opts); return NULL; @@ -1073,8 +1071,7 @@ bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) next = qdict_next(qdict, entry); if (find_desc_by_name(opts->list->desc, entry->key)) { - qemu_opts_from_qdict_entry(opts, entry, &local_err); - if (local_err) { + if (!qemu_opts_from_qdict_entry(opts, entry, &local_err)) { error_propagate(errp, local_err); return false; } @@ -1158,8 +1155,7 @@ bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) return false; } - qemu_opt_parse(opt, &local_err); - if (local_err) { + if (!qemu_opt_parse(opt, &local_err)) { error_propagate(errp, local_err); return false; } From 3882578bb559e5caf9b79cabcb88b69270af68c0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:43 +0200 Subject: [PATCH 2047/2595] block: Avoid error accumulation in bdrv_img_create() When creating an image fails because the format doesn't support option "backing_file" or "backing_fmt", bdrv_img_create() first has qemu_opt_set() put a generic error into @local_err, then puts the real error into @errp with error_setg(), and then propagates the former to the latter, which throws away the generic error. A bit complicated, but works. Now that qemu_opt_set() returns a useful value, we can simply ignore the generic error instead. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-16-armbru@redhat.com> --- block.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index 850755e04e..3e1f3eb1aa 100644 --- a/block.c +++ b/block.c @@ -6075,7 +6075,7 @@ void bdrv_img_create(const char *filename, const char *fmt, if (base_filename) { if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename, - &local_err)) { + NULL)) { error_setg(errp, "Backing file not supported for file format '%s'", fmt); goto out; @@ -6083,7 +6083,7 @@ void bdrv_img_create(const char *filename, const char *fmt, } if (base_fmt) { - if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, &local_err)) { + if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, NULL)) { error_setg(errp, "Backing file format not supported for file " "format '%s'", fmt); goto out; From 3c4b89c3b209978f13bcb7ab4d375b81b6fdad99 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:44 +0200 Subject: [PATCH 2048/2595] hmp: Eliminate a variable in hmp_migrate_set_parameter() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-17-armbru@redhat.com> --- monitor/hmp-cmds.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 2ec13e4cc3..bb17b1b96c 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -1247,7 +1247,6 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) MigrateSetParameters *p = g_new0(MigrateSetParameters, 1); uint64_t valuebw = 0; uint64_t cache_size; - MultiFDCompression compress_type; Error *err = NULL; int val, ret; @@ -1343,11 +1342,8 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) break; case MIGRATION_PARAMETER_MULTIFD_COMPRESSION: p->has_multifd_compression = true; - visit_type_MultiFDCompression(v, param, &compress_type, &err); - if (err) { - break; - } - p->multifd_compression = compress_type; + visit_type_MultiFDCompression(v, param, &p->multifd_compression, + &err); break; case MIGRATION_PARAMETER_MULTIFD_ZLIB_LEVEL: p->has_multifd_zlib_level = true; From 012d4c96e260f99d5ca95cd033274af4fb73b825 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:45 +0200 Subject: [PATCH 2049/2595] qapi: Make visitor functions taking Error ** return bool, not void See recent commit "error: Document Error API usage rules" for rationale. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-18-armbru@redhat.com> --- audio/audio_legacy.c | 15 ++-- docs/devel/qapi-code-gen.txt | 51 +++++------ include/qapi/clone-visitor.h | 8 +- include/qapi/visitor-impl.h | 26 +++--- include/qapi/visitor.h | 102 ++++++++++++--------- qapi/opts-visitor.c | 66 ++++++++------ qapi/qapi-clone-visitor.c | 69 +++++++------- qapi/qapi-dealloc-visitor.c | 27 ++++-- qapi/qapi-visit-core.c | 165 ++++++++++++++++++---------------- qapi/qobject-input-visitor.c | 109 +++++++++++++--------- qapi/qobject-output-visitor.c | 27 ++++-- qapi/string-input-visitor.c | 62 +++++++------ qapi/string-output-visitor.c | 32 ++++--- scripts/qapi/visit.py | 58 +++++------- 14 files changed, 456 insertions(+), 361 deletions(-) diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c index ebd7d9fa0d..ffdbd0bcce 100644 --- a/audio/audio_legacy.c +++ b/audio/audio_legacy.c @@ -421,11 +421,12 @@ typedef struct { GList *path; } LegacyPrintVisitor; -static void lv_start_struct(Visitor *v, const char *name, void **obj, +static bool lv_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp) { LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v; lv->path = g_list_append(lv->path, g_strdup(name)); + return true; } static void lv_end_struct(Visitor *v, void **obj) @@ -453,27 +454,30 @@ static void lv_print_key(Visitor *v, const char *name) printf("%s=", name); } -static void lv_type_int64(Visitor *v, const char *name, int64_t *obj, +static bool lv_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { lv_print_key(v, name); printf("%" PRIi64, *obj); + return true; } -static void lv_type_uint64(Visitor *v, const char *name, uint64_t *obj, +static bool lv_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { lv_print_key(v, name); printf("%" PRIu64, *obj); + return true; } -static void lv_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) +static bool lv_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { lv_print_key(v, name); printf("%s", *obj ? "on" : "off"); + return true; } -static void lv_type_str(Visitor *v, const char *name, char **obj, Error **errp) +static bool lv_type_str(Visitor *v, const char *name, char **obj, Error **errp) { const char *str = *obj; lv_print_key(v, name); @@ -484,6 +488,7 @@ static void lv_type_str(Visitor *v, const char *name, char **obj, Error **errp) } putchar(*str++); } + return true; } static void lv_complete(Visitor *v, void *opaque) diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index a7794ef658..9bfc57063c 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -1408,42 +1408,38 @@ Example: #include "example-qapi-types.h" - void visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error **errp); - void visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, Error **errp); - void visit_type_UserDefOneList(Visitor *v, const char *name, UserDefOneList **obj, Error **errp); + bool visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error **errp); + bool visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, Error **errp); + bool visit_type_UserDefOneList(Visitor *v, const char *name, UserDefOneList **obj, Error **errp); - void visit_type_q_obj_my_command_arg_members(Visitor *v, q_obj_my_command_arg *obj, Error **errp); + bool visit_type_q_obj_my_command_arg_members(Visitor *v, q_obj_my_command_arg *obj, Error **errp); #endif /* EXAMPLE_QAPI_VISIT_H */ $ cat qapi-generated/example-qapi-visit.c [Uninteresting stuff omitted...] - void visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error **errp) + bool visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error **errp) { Error *err = NULL; - visit_type_int(v, "integer", &obj->integer, &err); - if (err) { - goto out; + if (!visit_type_int(v, "integer", &obj->integer, errp)) { + return false; } if (visit_optional(v, "string", &obj->has_string)) { - visit_type_str(v, "string", &obj->string, &err); - if (err) { - goto out; + if (!visit_type_str(v, "string", &obj->string, errp)) { + return false; } } - - out: error_propagate(errp, err); + return !err; } - void visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, Error **errp) + bool visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, Error **errp) { Error *err = NULL; - visit_start_struct(v, name, (void **)obj, sizeof(UserDefOne), &err); - if (err) { - goto out; + if (!visit_start_struct(v, name, (void **)obj, sizeof(UserDefOne), errp)) { + return false; } if (!*obj) { /* incomplete */ @@ -1461,19 +1457,18 @@ Example: qapi_free_UserDefOne(*obj); *obj = NULL; } - out: error_propagate(errp, err); + return !err; } - void visit_type_UserDefOneList(Visitor *v, const char *name, UserDefOneList **obj, Error **errp) + bool visit_type_UserDefOneList(Visitor *v, const char *name, UserDefOneList **obj, Error **errp) { Error *err = NULL; UserDefOneList *tail; size_t size = sizeof(**obj); - visit_start_list(v, name, (GenericList **)obj, size, &err); - if (err) { - goto out; + if (!visit_start_list(v, name, (GenericList **)obj, size, errp)) { + return false; } for (tail = *obj; tail; @@ -1492,21 +1487,19 @@ Example: qapi_free_UserDefOneList(*obj); *obj = NULL; } - out: error_propagate(errp, err); + return !err; } - void visit_type_q_obj_my_command_arg_members(Visitor *v, q_obj_my_command_arg *obj, Error **errp) + bool visit_type_q_obj_my_command_arg_members(Visitor *v, q_obj_my_command_arg *obj, Error **errp) { Error *err = NULL; - visit_type_UserDefOneList(v, "arg1", &obj->arg1, &err); - if (err) { - goto out; + if (!visit_type_UserDefOneList(v, "arg1", &obj->arg1, errp)) { + return false; } - - out: error_propagate(errp, err); + return !err; } [Uninteresting stuff omitted...] diff --git a/include/qapi/clone-visitor.h b/include/qapi/clone-visitor.h index 5b665ee38c..adf9a788e2 100644 --- a/include/qapi/clone-visitor.h +++ b/include/qapi/clone-visitor.h @@ -20,10 +20,10 @@ */ typedef struct QapiCloneVisitor QapiCloneVisitor; -void *qapi_clone(const void *src, void (*visit_type)(Visitor *, const char *, +void *qapi_clone(const void *src, bool (*visit_type)(Visitor *, const char *, void **, Error **)); void qapi_clone_members(void *dst, const void *src, size_t sz, - void (*visit_type_members)(Visitor *, void *, + bool (*visit_type_members)(Visitor *, void *, Error **)); /* @@ -34,7 +34,7 @@ void qapi_clone_members(void *dst, const void *src, size_t sz, */ #define QAPI_CLONE(type, src) \ ((type *)qapi_clone(src, \ - (void (*)(Visitor *, const char *, void**, \ + (bool (*)(Visitor *, const char *, void **, \ Error **))visit_type_ ## type)) /* @@ -45,7 +45,7 @@ void qapi_clone_members(void *dst, const void *src, size_t sz, */ #define QAPI_CLONE_MEMBERS(type, dst, src) \ qapi_clone_members(dst, src, sizeof(type), \ - (void (*)(Visitor *, void *, \ + (bool (*)(Visitor *, void *, \ Error **))visit_type_ ## type ## _members) #endif diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h index 98dc533d39..7362c043be 100644 --- a/include/qapi/visitor-impl.h +++ b/include/qapi/visitor-impl.h @@ -48,31 +48,31 @@ struct Visitor */ /* Must be set to visit structs */ - void (*start_struct)(Visitor *v, const char *name, void **obj, + bool (*start_struct)(Visitor *v, const char *name, void **obj, size_t size, Error **errp); /* Optional; intended for input visitors */ - void (*check_struct)(Visitor *v, Error **errp); + bool (*check_struct)(Visitor *v, Error **errp); /* Must be set to visit structs */ void (*end_struct)(Visitor *v, void **obj); /* Must be set; implementations may require @list to be non-null, * but must document it. */ - void (*start_list)(Visitor *v, const char *name, GenericList **list, + bool (*start_list)(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp); /* Must be set */ GenericList *(*next_list)(Visitor *v, GenericList *tail, size_t size); /* Optional; intended for input visitors */ - void (*check_list)(Visitor *v, Error **errp); + bool (*check_list)(Visitor *v, Error **errp); /* Must be set */ void (*end_list)(Visitor *v, void **list); /* Must be set by input and clone visitors to visit alternates */ - void (*start_alternate)(Visitor *v, const char *name, + bool (*start_alternate)(Visitor *v, const char *name, GenericAlternate **obj, size_t size, Error **errp); @@ -80,33 +80,33 @@ struct Visitor void (*end_alternate)(Visitor *v, void **obj); /* Must be set */ - void (*type_int64)(Visitor *v, const char *name, int64_t *obj, + bool (*type_int64)(Visitor *v, const char *name, int64_t *obj, Error **errp); /* Must be set */ - void (*type_uint64)(Visitor *v, const char *name, uint64_t *obj, + bool (*type_uint64)(Visitor *v, const char *name, uint64_t *obj, Error **errp); /* Optional; fallback is type_uint64() */ - void (*type_size)(Visitor *v, const char *name, uint64_t *obj, + bool (*type_size)(Visitor *v, const char *name, uint64_t *obj, Error **errp); /* Must be set */ - void (*type_bool)(Visitor *v, const char *name, bool *obj, Error **errp); + bool (*type_bool)(Visitor *v, const char *name, bool *obj, Error **errp); /* Must be set */ - void (*type_str)(Visitor *v, const char *name, char **obj, Error **errp); + bool (*type_str)(Visitor *v, const char *name, char **obj, Error **errp); /* Must be set to visit numbers */ - void (*type_number)(Visitor *v, const char *name, double *obj, + bool (*type_number)(Visitor *v, const char *name, double *obj, Error **errp); /* Must be set to visit arbitrary QTypes */ - void (*type_any)(Visitor *v, const char *name, QObject **obj, + bool (*type_any)(Visitor *v, const char *name, QObject **obj, Error **errp); /* Must be set to visit explicit null values. */ - void (*type_null)(Visitor *v, const char *name, QNull **obj, + bool (*type_null)(Visitor *v, const char *name, QNull **obj, Error **errp); /* Must be set for input visitors to visit structs, optional otherwise. diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 5573906966..ebc19ede7f 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -60,7 +60,7 @@ * All QAPI types have a corresponding function with a signature * roughly compatible with this: * - * void visit_type_FOO(Visitor *v, const char *name, T obj, Error **errp); + * bool visit_type_FOO(Visitor *v, const char *name, T obj, Error **errp); * * where T is FOO for scalar types, and FOO * otherwise. The scalar * visitors are declared here; the remaining visitors are generated in @@ -95,14 +95,16 @@ * incomplete object, such an object is possible only by manual * construction. * + * visit_type_FOO() returns true on success, false on error. + * * For the QAPI object types (structs, unions, and alternates), there * is an additional generated function in qapi-visit-MODULE.h * compatible with: * - * void visit_type_FOO_members(Visitor *v, FOO *obj, Error **errp); + * bool visit_type_FOO_members(Visitor *v, FOO *obj, Error **errp); * * for visiting the members of a type without also allocating the QAPI - * struct. + * struct. It also returns true on success, false on error. * * Additionally, QAPI pointer types (structs, unions, alternates, and * lists) have a generated function in qapi-types-MODULE.h compatible @@ -131,8 +133,7 @@ * Visitor *v; * * v = FOO_visitor_new(...); - * visit_type_Foo(v, NULL, &f, &err); - * if (err) { + * if (!visit_type_Foo(v, NULL, &f, &err)) { * ...handle error... * } else { * ...use f... @@ -148,8 +149,7 @@ * Visitor *v; * * v = FOO_visitor_new(...); - * visit_type_FooList(v, NULL, &l, &err); - * if (err) { + * if (!visit_type_FooList(v, NULL, &l, &err)) { * ...handle error... * } else { * for ( ; l; l = l->next) { @@ -186,34 +186,32 @@ * * Visitor *v; * Error *err = NULL; + * bool ok = false; * int value; * * v = FOO_visitor_new(...); - * visit_start_struct(v, NULL, NULL, 0, &err); - * if (err) { + * if (!visit_start_struct(v, NULL, NULL, 0, &err)) { * goto out; * } - * visit_start_list(v, "list", NULL, 0, &err); - * if (err) { + * if (!visit_start_list(v, "list", NULL, 0, &err)) { * goto outobj; * } * value = 1; - * visit_type_int(v, NULL, &value, &err); - * if (err) { + * if (!visit_type_int(v, NULL, &value, &err)) { * goto outlist; * } * value = 2; - * visit_type_int(v, NULL, &value, &err); - * if (err) { + * if (!visit_type_int(v, NULL, &value, &err)) { * goto outlist; * } + * ok = true; * outlist: - * if (!err) { - * visit_check_list(v, &err); + * if (ok) { + * ok = visit_check_list(v, &err); * } * visit_end_list(v, NULL); - * if (!err) { - * visit_check_struct(v, &err); + * if (ok) { + * ok = visit_check_struct(v, &err); * } * outobj: * visit_end_struct(v, NULL); @@ -286,6 +284,8 @@ void visit_free(Visitor *v); * On failure, set *@obj to NULL and store an error through @errp. * Can happen only when @v is an input visitor. * + * Return true on success, false on failure. + * * After visit_start_struct() succeeds, the caller may visit its * members one after the other, passing the member's name and address * within the struct. Finally, visit_end_struct() needs to be called @@ -295,7 +295,7 @@ void visit_free(Visitor *v); * FIXME Should this be named visit_start_object, since it is also * used for QAPI unions, and maps to JSON objects? */ -void visit_start_struct(Visitor *v, const char *name, void **obj, +bool visit_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp); /* @@ -304,12 +304,14 @@ void visit_start_struct(Visitor *v, const char *name, void **obj, * On failure, store an error through @errp. Can happen only when @v * is an input visitor. * + * Return true on success, false on failure. + * * Should be called prior to visit_end_struct() if all other * intermediate visit steps were successful, to allow the visitor one * last chance to report errors. May be skipped on a cleanup path, * where there is no need to check for further errors. */ -void visit_check_struct(Visitor *v, Error **errp); +bool visit_check_struct(Visitor *v, Error **errp); /* * Complete an object visit started earlier. @@ -341,6 +343,8 @@ void visit_end_struct(Visitor *v, void **obj); * On failure, set *@list to NULL and store an error through @errp. * Can happen only when @v is an input visitor. * + * Return true on success, false on failure. + * * After visit_start_list() succeeds, the caller may visit its members * one after the other. A real visit (where @list is non-NULL) uses * visit_next_list() for traversing the linked list, while a virtual @@ -351,7 +355,7 @@ void visit_end_struct(Visitor *v, void **obj); * same @list to clean up, even if intermediate visits fail. See the * examples above. */ -void visit_start_list(Visitor *v, const char *name, GenericList **list, +bool visit_start_list(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp); /* @@ -376,12 +380,14 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size); * On failure, store an error through @errp. Can happen only when @v * is an input visitor. * + * Return true on success, false on failure. + * * Should be called prior to visit_end_list() if all other * intermediate visit steps were successful, to allow the visitor one * last chance to report errors. May be skipped on a cleanup path, * where there is no need to check for further errors. */ -void visit_check_list(Visitor *v, Error **errp); +bool visit_check_list(Visitor *v, Error **errp); /* * Complete a list visit started earlier. @@ -412,11 +418,13 @@ void visit_end_list(Visitor *v, void **list); * On failure, set *@obj to NULL and store an error through @errp. * Can happen only when @v is an input visitor. * + * Return true on success, false on failure. + * * If successful, this must be paired with visit_end_alternate() with * the same @obj to clean up, even if visiting the contents of the * alternate fails. */ -void visit_start_alternate(Visitor *v, const char *name, +bool visit_start_alternate(Visitor *v, const char *name, GenericAlternate **obj, size_t size, Error **errp); @@ -468,12 +476,14 @@ bool visit_optional(Visitor *v, const char *name, bool *present); * On failure, store an error through @errp. Can happen only when @v * is an input visitor. * + * Return true on success, false on failure. + * * May call visit_type_str() under the hood, and the enum visit may * fail even if the corresponding string visit succeeded; this implies * that an input visitor's visit_type_str() must have no unwelcome * side effects. */ -void visit_type_enum(Visitor *v, const char *name, int *obj, +bool visit_type_enum(Visitor *v, const char *name, int *obj, const QEnumLookup *lookup, Error **errp); /* @@ -499,28 +509,30 @@ bool visit_is_dealloc(Visitor *v); * * On failure, store an error through @errp. Can happen only when @v * is an input visitor. + * + * Return true on success, false on failure. */ -void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp); +bool visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp); /* * Visit a uint8_t value. * Like visit_type_int(), except clamps the value to uint8_t range. */ -void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, +bool visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, Error **errp); /* * Visit a uint16_t value. * Like visit_type_int(), except clamps the value to uint16_t range. */ -void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, +bool visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, Error **errp); /* * Visit a uint32_t value. * Like visit_type_int(), except clamps the value to uint32_t range. */ -void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, +bool visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, Error **errp); /* @@ -528,34 +540,34 @@ void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, * Like visit_type_int(), except clamps the value to uint64_t range, * that is, ensures it is unsigned. */ -void visit_type_uint64(Visitor *v, const char *name, uint64_t *obj, +bool visit_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp); /* * Visit an int8_t value. * Like visit_type_int(), except clamps the value to int8_t range. */ -void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp); +bool visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp); /* * Visit an int16_t value. * Like visit_type_int(), except clamps the value to int16_t range. */ -void visit_type_int16(Visitor *v, const char *name, int16_t *obj, +bool visit_type_int16(Visitor *v, const char *name, int16_t *obj, Error **errp); /* * Visit an int32_t value. * Like visit_type_int(), except clamps the value to int32_t range. */ -void visit_type_int32(Visitor *v, const char *name, int32_t *obj, +bool visit_type_int32(Visitor *v, const char *name, int32_t *obj, Error **errp); /* * Visit an int64_t value. * Identical to visit_type_int(). */ -void visit_type_int64(Visitor *v, const char *name, int64_t *obj, +bool visit_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp); /* @@ -564,7 +576,7 @@ void visit_type_int64(Visitor *v, const char *name, int64_t *obj, * recognize additional syntax, such as suffixes for easily scaling * values. */ -void visit_type_size(Visitor *v, const char *name, uint64_t *obj, +bool visit_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp); /* @@ -578,8 +590,10 @@ void visit_type_size(Visitor *v, const char *name, uint64_t *obj, * * On failure, store an error through @errp. Can happen only when @v * is an input visitor. + * + * Return true on success, false on failure. */ -void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp); +bool visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp); /* * Visit a string value. @@ -598,9 +612,11 @@ void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp); * On failure, set *@obj to NULL and store an error through @errp. * Can happen only when @v is an input visitor. * + * Return true on success, false on failure. + * * FIXME: Callers that try to output NULL *obj should not be allowed. */ -void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp); +bool visit_type_str(Visitor *v, const char *name, char **obj, Error **errp); /* * Visit a number (i.e. double) value. @@ -614,8 +630,10 @@ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp); * * On failure, store an error through @errp. Can happen only when @v * is an input visitor. + * + * Return true on success, false on failure. */ -void visit_type_number(Visitor *v, const char *name, double *obj, +bool visit_type_number(Visitor *v, const char *name, double *obj, Error **errp); /* @@ -631,11 +649,13 @@ void visit_type_number(Visitor *v, const char *name, double *obj, * On failure, set *@obj to NULL and store an error through @errp. * Can happen only when @v is an input visitor. * + * Return true on success, false on failure. + * * Note that some kinds of input can't express arbitrary QObject. * E.g. the visitor returned by qobject_input_visitor_new_keyval() * can't create numbers or booleans, only strings. */ -void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp); +bool visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp); /* * Visit a JSON null value. @@ -648,8 +668,10 @@ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp); * * On failure, set *@obj to NULL and store an error through @errp. * Can happen only when @v is an input visitor. + * + * Return true on success, false on failure. */ -void visit_type_null(Visitor *v, const char *name, QNull **obj, +bool visit_type_null(Visitor *v, const char *name, QNull **obj, Error **errp); #endif diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 5fe0276c1c..7781c23a42 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -133,7 +133,7 @@ opts_visitor_insert(GHashTable *unprocessed_opts, const QemuOpt *opt) } -static void +static bool opts_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp) { @@ -144,7 +144,7 @@ opts_start_struct(Visitor *v, const char *name, void **obj, *obj = g_malloc0(size); } if (ov->depth++ > 0) { - return; + return true; } ov->unprocessed_opts = g_hash_table_new_full(&g_str_hash, &g_str_equal, @@ -163,10 +163,11 @@ opts_start_struct(Visitor *v, const char *name, void **obj, ov->fake_id_opt->str = g_strdup(ov->opts_root->id); opts_visitor_insert(ov->unprocessed_opts, ov->fake_id_opt); } + return true; } -static void +static bool opts_check_struct(Visitor *v, Error **errp) { OptsVisitor *ov = to_ov(v); @@ -174,7 +175,7 @@ opts_check_struct(Visitor *v, Error **errp) GQueue *any; if (ov->depth > 1) { - return; + return true; } /* we should have processed all (distinct) QemuOpt instances */ @@ -184,7 +185,9 @@ opts_check_struct(Visitor *v, Error **errp) first = g_queue_peek_head(any); error_setg(errp, QERR_INVALID_PARAMETER, first->name); + return false; } + return true; } @@ -221,7 +224,7 @@ lookup_distinct(const OptsVisitor *ov, const char *name, Error **errp) } -static void +static bool opts_start_list(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp) { @@ -232,12 +235,13 @@ opts_start_list(Visitor *v, const char *name, GenericList **list, size_t size, /* we don't support visits without a list */ assert(list); ov->repeated_opts = lookup_distinct(ov, name, errp); - if (ov->repeated_opts) { - ov->list_mode = LM_IN_PROGRESS; - *list = g_malloc0(size); - } else { + if (!ov->repeated_opts) { *list = NULL; + return false; } + ov->list_mode = LM_IN_PROGRESS; + *list = g_malloc0(size); + return true; } @@ -285,13 +289,14 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size) } -static void +static bool opts_check_list(Visitor *v, Error **errp) { /* * Unvisited list elements will be reported later when checking * whether unvisited struct members remain. */ + return true; } @@ -341,7 +346,7 @@ processed(OptsVisitor *ov, const char *name) } -static void +static bool opts_type_str(Visitor *v, const char *name, char **obj, Error **errp) { OptsVisitor *ov = to_ov(v); @@ -350,7 +355,7 @@ opts_type_str(Visitor *v, const char *name, char **obj, Error **errp) opt = lookup_scalar(ov, name, errp); if (!opt) { *obj = NULL; - return; + return false; } *obj = g_strdup(opt->str ? opt->str : ""); /* Note that we consume a string even if this is called as part of @@ -359,11 +364,12 @@ opts_type_str(Visitor *v, const char *name, char **obj, Error **errp) * consumed only matters to visit_end_struct() as the final error * check if there were no other failures during the visit. */ processed(ov, name); + return true; } /* mimics qemu-option.c::parse_option_bool() */ -static void +static bool opts_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { OptsVisitor *ov = to_ov(v); @@ -371,7 +377,7 @@ opts_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) opt = lookup_scalar(ov, name, errp); if (!opt) { - return; + return false; } if (opt->str) { @@ -386,17 +392,18 @@ opts_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) } else { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, "on|yes|y|off|no|n"); - return; + return false; } } else { *obj = true; } processed(ov, name); + return true; } -static void +static bool opts_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { OptsVisitor *ov = to_ov(v); @@ -407,12 +414,12 @@ opts_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) if (ov->list_mode == LM_SIGNED_INTERVAL) { *obj = ov->range_next.s; - return; + return true; } opt = lookup_scalar(ov, name, errp); if (!opt) { - return; + return false; } str = opt->str ? opt->str : ""; @@ -425,7 +432,7 @@ opts_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) if (*endptr == '\0') { *obj = val; processed(ov, name); - return; + return true; } if (*endptr == '-' && ov->list_mode == LM_IN_PROGRESS) { long long val2; @@ -442,17 +449,18 @@ opts_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) /* as if entering on the top */ *obj = ov->range_next.s; - return; + return true; } } } error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, (ov->list_mode == LM_NONE) ? "an int64 value" : "an int64 value or range"); + return false; } -static void +static bool opts_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { OptsVisitor *ov = to_ov(v); @@ -463,12 +471,12 @@ opts_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) if (ov->list_mode == LM_UNSIGNED_INTERVAL) { *obj = ov->range_next.u; - return; + return true; } opt = lookup_scalar(ov, name, errp); if (!opt) { - return; + return false; } str = opt->str; @@ -479,7 +487,7 @@ opts_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) if (*endptr == '\0') { *obj = val; processed(ov, name); - return; + return true; } if (*endptr == '-' && ov->list_mode == LM_IN_PROGRESS) { unsigned long long val2; @@ -494,17 +502,18 @@ opts_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) /* as if entering on the top */ *obj = ov->range_next.u; - return; + return true; } } } error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, (ov->list_mode == LM_NONE) ? "a uint64 value" : "a uint64 value or range"); + return false; } -static void +static bool opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) { OptsVisitor *ov = to_ov(v); @@ -513,17 +522,18 @@ opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) opt = lookup_scalar(ov, name, errp); if (!opt) { - return; + return false; } err = qemu_strtosz(opt->str ? opt->str : "", NULL, obj); if (err < 0) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, "a size value"); - return; + return false; } processed(ov, name); + return true; } diff --git a/qapi/qapi-clone-visitor.c b/qapi/qapi-clone-visitor.c index daab6819b4..c45c5caa3b 100644 --- a/qapi/qapi-clone-visitor.c +++ b/qapi/qapi-clone-visitor.c @@ -24,7 +24,7 @@ static QapiCloneVisitor *to_qcv(Visitor *v) return container_of(v, QapiCloneVisitor, visitor); } -static void qapi_clone_start_struct(Visitor *v, const char *name, void **obj, +static bool qapi_clone_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp) { QapiCloneVisitor *qcv = to_qcv(v); @@ -34,11 +34,12 @@ static void qapi_clone_start_struct(Visitor *v, const char *name, void **obj, /* Only possible when visiting an alternate's object * branch. Nothing further to do here, since the earlier * visit_start_alternate() already copied memory. */ - return; + return true; } *obj = g_memdup(*obj, size); qcv->depth++; + return true; } static void qapi_clone_end(Visitor *v, void **obj) @@ -51,11 +52,11 @@ static void qapi_clone_end(Visitor *v, void **obj) } } -static void qapi_clone_start_list(Visitor *v, const char *name, +static bool qapi_clone_start_list(Visitor *v, const char *name, GenericList **listp, size_t size, Error **errp) { - qapi_clone_start_struct(v, name, (void **)listp, size, errp); + return qapi_clone_start_struct(v, name, (void **)listp, size, errp); } static GenericList *qapi_clone_next_list(Visitor *v, GenericList *tail, @@ -69,45 +70,48 @@ static GenericList *qapi_clone_next_list(Visitor *v, GenericList *tail, return tail->next; } -static void qapi_clone_start_alternate(Visitor *v, const char *name, +static bool qapi_clone_start_alternate(Visitor *v, const char *name, GenericAlternate **obj, size_t size, Error **errp) { - qapi_clone_start_struct(v, name, (void **)obj, size, errp); + return qapi_clone_start_struct(v, name, (void **)obj, size, errp); } -static void qapi_clone_type_int64(Visitor *v, const char *name, int64_t *obj, - Error **errp) -{ - QapiCloneVisitor *qcv = to_qcv(v); - - assert(qcv->depth); - /* Value was already cloned by g_memdup() */ -} - -static void qapi_clone_type_uint64(Visitor *v, const char *name, - uint64_t *obj, Error **errp) -{ - QapiCloneVisitor *qcv = to_qcv(v); - - assert(qcv->depth); - /* Value was already cloned by g_memdup() */ -} - -static void qapi_clone_type_bool(Visitor *v, const char *name, bool *obj, +static bool qapi_clone_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { QapiCloneVisitor *qcv = to_qcv(v); assert(qcv->depth); /* Value was already cloned by g_memdup() */ + return true; } -static void qapi_clone_type_str(Visitor *v, const char *name, char **obj, +static bool qapi_clone_type_uint64(Visitor *v, const char *name, + uint64_t *obj, Error **errp) +{ + QapiCloneVisitor *qcv = to_qcv(v); + + assert(qcv->depth); + /* Value was already cloned by g_memdup() */ + return true; +} + +static bool qapi_clone_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { QapiCloneVisitor *qcv = to_qcv(v); + assert(qcv->depth); + /* Value was already cloned by g_memdup() */ + return true; +} + +static bool qapi_clone_type_str(Visitor *v, const char *name, char **obj, + Error **errp) +{ + QapiCloneVisitor *qcv = to_qcv(v); + assert(qcv->depth); /* * Pointer was already cloned by g_memdup; create fresh copy. @@ -117,24 +121,27 @@ static void qapi_clone_type_str(Visitor *v, const char *name, char **obj, * string is intended. */ *obj = g_strdup(*obj ?: ""); + return true; } -static void qapi_clone_type_number(Visitor *v, const char *name, double *obj, - Error **errp) +static bool qapi_clone_type_number(Visitor *v, const char *name, double *obj, + Error **errp) { QapiCloneVisitor *qcv = to_qcv(v); assert(qcv->depth); /* Value was already cloned by g_memdup() */ + return true; } -static void qapi_clone_type_null(Visitor *v, const char *name, QNull **obj, +static bool qapi_clone_type_null(Visitor *v, const char *name, QNull **obj, Error **errp) { QapiCloneVisitor *qcv = to_qcv(v); assert(qcv->depth); *obj = qnull(); + return true; } static void qapi_clone_free(Visitor *v) @@ -167,7 +174,7 @@ static Visitor *qapi_clone_visitor_new(void) return &v->visitor; } -void *qapi_clone(const void *src, void (*visit_type)(Visitor *, const char *, +void *qapi_clone(const void *src, bool (*visit_type)(Visitor *, const char *, void **, Error **)) { Visitor *v; @@ -184,7 +191,7 @@ void *qapi_clone(const void *src, void (*visit_type)(Visitor *, const char *, } void qapi_clone_members(void *dst, const void *src, size_t sz, - void (*visit_type_members)(Visitor *, void *, + bool (*visit_type_members)(Visitor *, void *, Error **)) { Visitor *v; diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c index 2239fc6417..ef283f2966 100644 --- a/qapi/qapi-dealloc-visitor.c +++ b/qapi/qapi-dealloc-visitor.c @@ -22,9 +22,10 @@ struct QapiDeallocVisitor Visitor visitor; }; -static void qapi_dealloc_start_struct(Visitor *v, const char *name, void **obj, +static bool qapi_dealloc_start_struct(Visitor *v, const char *name, void **obj, size_t unused, Error **errp) { + return true; } static void qapi_dealloc_end_struct(Visitor *v, void **obj) @@ -41,10 +42,11 @@ static void qapi_dealloc_end_alternate(Visitor *v, void **obj) } } -static void qapi_dealloc_start_list(Visitor *v, const char *name, +static bool qapi_dealloc_start_list(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp) { + return true; } static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList *tail, @@ -59,48 +61,55 @@ static void qapi_dealloc_end_list(Visitor *v, void **obj) { } -static void qapi_dealloc_type_str(Visitor *v, const char *name, char **obj, +static bool qapi_dealloc_type_str(Visitor *v, const char *name, char **obj, Error **errp) { if (obj) { g_free(*obj); } + return true; } -static void qapi_dealloc_type_int64(Visitor *v, const char *name, int64_t *obj, +static bool qapi_dealloc_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { + return true; } -static void qapi_dealloc_type_uint64(Visitor *v, const char *name, +static bool qapi_dealloc_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { + return true; } -static void qapi_dealloc_type_bool(Visitor *v, const char *name, bool *obj, +static bool qapi_dealloc_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { + return true; } -static void qapi_dealloc_type_number(Visitor *v, const char *name, double *obj, +static bool qapi_dealloc_type_number(Visitor *v, const char *name, double *obj, Error **errp) { + return true; } -static void qapi_dealloc_type_anything(Visitor *v, const char *name, +static bool qapi_dealloc_type_anything(Visitor *v, const char *name, QObject **obj, Error **errp) { if (obj) { qobject_unref(*obj); } + return true; } -static void qapi_dealloc_type_null(Visitor *v, const char *name, +static bool qapi_dealloc_type_null(Visitor *v, const char *name, QNull **obj, Error **errp) { if (obj) { qobject_unref(*obj); } + return true; } static void qapi_dealloc_free(Visitor *v) diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 74aa9c04bd..5a9c47aabf 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -36,7 +36,7 @@ void visit_free(Visitor *v) } } -void visit_start_struct(Visitor *v, const char *name, void **obj, +bool visit_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp) { Error *err = NULL; @@ -51,14 +51,13 @@ void visit_start_struct(Visitor *v, const char *name, void **obj, assert(!err != !*obj); } error_propagate(errp, err); + return !err; } -void visit_check_struct(Visitor *v, Error **errp) +bool visit_check_struct(Visitor *v, Error **errp) { trace_visit_check_struct(v); - if (v->check_struct) { - v->check_struct(v, errp); - } + return v->check_struct ? v->check_struct(v, errp) : true; } void visit_end_struct(Visitor *v, void **obj) @@ -67,7 +66,7 @@ void visit_end_struct(Visitor *v, void **obj) v->end_struct(v, obj); } -void visit_start_list(Visitor *v, const char *name, GenericList **list, +bool visit_start_list(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp) { Error *err = NULL; @@ -79,6 +78,7 @@ void visit_start_list(Visitor *v, const char *name, GenericList **list, assert(!(err && *list)); } error_propagate(errp, err); + return !err; } GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size) @@ -88,12 +88,10 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size) return v->next_list(v, tail, size); } -void visit_check_list(Visitor *v, Error **errp) +bool visit_check_list(Visitor *v, Error **errp) { trace_visit_check_list(v); - if (v->check_list) { - v->check_list(v, errp); - } + return v->check_list ? v->check_list(v, errp) : true; } void visit_end_list(Visitor *v, void **obj) @@ -102,7 +100,7 @@ void visit_end_list(Visitor *v, void **obj) v->end_list(v, obj); } -void visit_start_alternate(Visitor *v, const char *name, +bool visit_start_alternate(Visitor *v, const char *name, GenericAlternate **obj, size_t size, Error **errp) { @@ -118,6 +116,7 @@ void visit_start_alternate(Visitor *v, const char *name, assert(v->start_alternate && !err != !*obj); } error_propagate(errp, err); + return !err; } void visit_end_alternate(Visitor *v, void **obj) @@ -147,155 +146,168 @@ bool visit_is_dealloc(Visitor *v) return v->type == VISITOR_DEALLOC; } -void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp) +bool visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp) { assert(obj); trace_visit_type_int(v, name, obj); - v->type_int64(v, name, obj, errp); + return v->type_int64(v, name, obj, errp); } -static void visit_type_uintN(Visitor *v, uint64_t *obj, const char *name, +static bool visit_type_uintN(Visitor *v, uint64_t *obj, const char *name, uint64_t max, const char *type, Error **errp) { - Error *err = NULL; uint64_t value = *obj; assert(v->type == VISITOR_INPUT || value <= max); - v->type_uint64(v, name, &value, &err); - if (err) { - error_propagate(errp, err); - } else if (value > max) { + if (!v->type_uint64(v, name, &value, errp)) { + return false; + } + if (value > max) { assert(v->type == VISITOR_INPUT); error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", type); - } else { - *obj = value; + return false; } + *obj = value; + return true; } -void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, +bool visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, Error **errp) { uint64_t value; + bool ok; trace_visit_type_uint8(v, name, obj); value = *obj; - visit_type_uintN(v, &value, name, UINT8_MAX, "uint8_t", errp); + ok = visit_type_uintN(v, &value, name, UINT8_MAX, "uint8_t", errp); *obj = value; + return ok; } -void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, +bool visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, Error **errp) { uint64_t value; + bool ok; trace_visit_type_uint16(v, name, obj); value = *obj; - visit_type_uintN(v, &value, name, UINT16_MAX, "uint16_t", errp); + ok = visit_type_uintN(v, &value, name, UINT16_MAX, "uint16_t", errp); *obj = value; + return ok; } -void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, +bool visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, Error **errp) { uint64_t value; + bool ok; trace_visit_type_uint32(v, name, obj); value = *obj; - visit_type_uintN(v, &value, name, UINT32_MAX, "uint32_t", errp); + ok = visit_type_uintN(v, &value, name, UINT32_MAX, "uint32_t", errp); *obj = value; + return ok; } -void visit_type_uint64(Visitor *v, const char *name, uint64_t *obj, +bool visit_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { assert(obj); trace_visit_type_uint64(v, name, obj); - v->type_uint64(v, name, obj, errp); + return v->type_uint64(v, name, obj, errp); } -static void visit_type_intN(Visitor *v, int64_t *obj, const char *name, +static bool visit_type_intN(Visitor *v, int64_t *obj, const char *name, int64_t min, int64_t max, const char *type, Error **errp) { - Error *err = NULL; int64_t value = *obj; assert(v->type == VISITOR_INPUT || (value >= min && value <= max)); - v->type_int64(v, name, &value, &err); - if (err) { - error_propagate(errp, err); - } else if (value < min || value > max) { + if (!v->type_int64(v, name, &value, errp)) { + return false; + } + if (value < min || value > max) { assert(v->type == VISITOR_INPUT); error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", type); - } else { - *obj = value; + return false; } + *obj = value; + return true; } -void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp) +bool visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp) { int64_t value; + bool ok; trace_visit_type_int8(v, name, obj); value = *obj; - visit_type_intN(v, &value, name, INT8_MIN, INT8_MAX, "int8_t", errp); + ok = visit_type_intN(v, &value, name, INT8_MIN, INT8_MAX, "int8_t", errp); *obj = value; + return ok; } -void visit_type_int16(Visitor *v, const char *name, int16_t *obj, +bool visit_type_int16(Visitor *v, const char *name, int16_t *obj, Error **errp) { int64_t value; + bool ok; trace_visit_type_int16(v, name, obj); value = *obj; - visit_type_intN(v, &value, name, INT16_MIN, INT16_MAX, "int16_t", errp); + ok = visit_type_intN(v, &value, name, INT16_MIN, INT16_MAX, "int16_t", + errp); *obj = value; + return ok; } -void visit_type_int32(Visitor *v, const char *name, int32_t *obj, +bool visit_type_int32(Visitor *v, const char *name, int32_t *obj, Error **errp) { int64_t value; + bool ok; trace_visit_type_int32(v, name, obj); value = *obj; - visit_type_intN(v, &value, name, INT32_MIN, INT32_MAX, "int32_t", errp); + ok = visit_type_intN(v, &value, name, INT32_MIN, INT32_MAX, "int32_t", + errp); *obj = value; + return ok; } -void visit_type_int64(Visitor *v, const char *name, int64_t *obj, +bool visit_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { assert(obj); trace_visit_type_int64(v, name, obj); - v->type_int64(v, name, obj, errp); + return v->type_int64(v, name, obj, errp); } -void visit_type_size(Visitor *v, const char *name, uint64_t *obj, +bool visit_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) { assert(obj); trace_visit_type_size(v, name, obj); if (v->type_size) { - v->type_size(v, name, obj, errp); - } else { - v->type_uint64(v, name, obj, errp); + return v->type_size(v, name, obj, errp); } + return v->type_uint64(v, name, obj, errp); } -void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) +bool visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { assert(obj); trace_visit_type_bool(v, name, obj); - v->type_bool(v, name, obj, errp); + return v->type_bool(v, name, obj, errp); } -void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp) +bool visit_type_str(Visitor *v, const char *name, char **obj, Error **errp) { Error *err = NULL; @@ -310,89 +322,88 @@ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp) assert(!err != !*obj); } error_propagate(errp, err); + return !err; } -void visit_type_number(Visitor *v, const char *name, double *obj, +bool visit_type_number(Visitor *v, const char *name, double *obj, Error **errp) { assert(obj); trace_visit_type_number(v, name, obj); - v->type_number(v, name, obj, errp); + return v->type_number(v, name, obj, errp); } -void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) +bool visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) { - Error *err = NULL; + bool ok; assert(obj); assert(v->type != VISITOR_OUTPUT || *obj); trace_visit_type_any(v, name, obj); - v->type_any(v, name, obj, &err); + ok = v->type_any(v, name, obj, errp); if (v->type == VISITOR_INPUT) { - assert(!err != !*obj); + assert(ok != !*obj); } - error_propagate(errp, err); + return ok; } -void visit_type_null(Visitor *v, const char *name, QNull **obj, +bool visit_type_null(Visitor *v, const char *name, QNull **obj, Error **errp) { trace_visit_type_null(v, name, obj); - v->type_null(v, name, obj, errp); + return v->type_null(v, name, obj, errp); } -static void output_type_enum(Visitor *v, const char *name, int *obj, +static bool output_type_enum(Visitor *v, const char *name, int *obj, const QEnumLookup *lookup, Error **errp) { int value = *obj; char *enum_str; enum_str = (char *)qapi_enum_lookup(lookup, value); - visit_type_str(v, name, &enum_str, errp); + return visit_type_str(v, name, &enum_str, errp); } -static void input_type_enum(Visitor *v, const char *name, int *obj, +static bool input_type_enum(Visitor *v, const char *name, int *obj, const QEnumLookup *lookup, Error **errp) { - Error *local_err = NULL; int64_t value; char *enum_str; - visit_type_str(v, name, &enum_str, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + if (!visit_type_str(v, name, &enum_str, errp)) { + return false; } value = qapi_enum_parse(lookup, enum_str, -1, NULL); if (value < 0) { error_setg(errp, QERR_INVALID_PARAMETER, enum_str); g_free(enum_str); - return; + return false; } g_free(enum_str); *obj = value; + return true; } -void visit_type_enum(Visitor *v, const char *name, int *obj, +bool visit_type_enum(Visitor *v, const char *name, int *obj, const QEnumLookup *lookup, Error **errp) { assert(obj && lookup); trace_visit_type_enum(v, name, obj); switch (v->type) { case VISITOR_INPUT: - input_type_enum(v, name, obj, lookup, errp); - break; + return input_type_enum(v, name, obj, lookup, errp); case VISITOR_OUTPUT: - output_type_enum(v, name, obj, lookup, errp); - break; + return output_type_enum(v, name, obj, lookup, errp); case VISITOR_CLONE: /* nothing further to do, scalar value was already copied by * g_memdup() during visit_start_*() */ - break; + return true; case VISITOR_DEALLOC: /* nothing to deallocate for a scalar */ - break; + return true; + default: + abort(); } } diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c index 5ce3ec2e5f..f918a05e5f 100644 --- a/qapi/qobject-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -237,7 +237,7 @@ static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv, } -static void qobject_input_check_struct(Visitor *v, Error **errp) +static bool qobject_input_check_struct(Visitor *v, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); StackObject *tos = QSLIST_FIRST(&qiv->stack); @@ -250,7 +250,9 @@ static void qobject_input_check_struct(Visitor *v, Error **errp) if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) { error_setg(errp, "Parameter '%s' is unexpected", full_name(qiv, key)); + return false; } + return true; } static void qobject_input_stack_object_free(StackObject *tos) @@ -272,7 +274,7 @@ static void qobject_input_pop(Visitor *v, void **obj) qobject_input_stack_object_free(tos); } -static void qobject_input_start_struct(Visitor *v, const char *name, void **obj, +static bool qobject_input_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); @@ -282,12 +284,12 @@ static void qobject_input_start_struct(Visitor *v, const char *name, void **obj, *obj = NULL; } if (!qobj) { - return; + return false; } if (qobject_type(qobj) != QTYPE_QDICT) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, full_name(qiv, name), "object"); - return; + return false; } qobject_input_push(qiv, name, qobj, obj); @@ -295,6 +297,7 @@ static void qobject_input_start_struct(Visitor *v, const char *name, void **obj, if (obj) { *obj = g_malloc0(size); } + return true; } static void qobject_input_end_struct(Visitor *v, void **obj) @@ -307,7 +310,7 @@ static void qobject_input_end_struct(Visitor *v, void **obj) } -static void qobject_input_start_list(Visitor *v, const char *name, +static bool qobject_input_start_list(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp) { @@ -319,18 +322,19 @@ static void qobject_input_start_list(Visitor *v, const char *name, *list = NULL; } if (!qobj) { - return; + return false; } if (qobject_type(qobj) != QTYPE_QLIST) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, full_name(qiv, name), "array"); - return; + return false; } entry = qobject_input_push(qiv, name, qobj, list); if (entry && list) { *list = g_malloc0(size); } + return true; } static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail, @@ -348,7 +352,7 @@ static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail, return tail->next; } -static void qobject_input_check_list(Visitor *v, Error **errp) +static bool qobject_input_check_list(Visitor *v, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); StackObject *tos = QSLIST_FIRST(&qiv->stack); @@ -358,7 +362,9 @@ static void qobject_input_check_list(Visitor *v, Error **errp) if (tos->entry) { error_setg(errp, "Only %u list elements expected in %s", tos->index + 1, full_name_nth(qiv, NULL, 1)); + return false; } + return true; } static void qobject_input_end_list(Visitor *v, void **obj) @@ -370,7 +376,7 @@ static void qobject_input_end_list(Visitor *v, void **obj) qobject_input_pop(v, obj); } -static void qobject_input_start_alternate(Visitor *v, const char *name, +static bool qobject_input_start_alternate(Visitor *v, const char *name, GenericAlternate **obj, size_t size, Error **errp) { @@ -379,13 +385,14 @@ static void qobject_input_start_alternate(Visitor *v, const char *name, if (!qobj) { *obj = NULL; - return; + return false; } *obj = g_malloc0(size); (*obj)->type = qobject_type(qobj); + return true; } -static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj, +static bool qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); @@ -393,33 +400,37 @@ static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj, QNum *qnum; if (!qobj) { - return; + return false; } qnum = qobject_to(QNum, qobj); if (!qnum || !qnum_get_try_int(qnum, obj)) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, full_name(qiv, name), "integer"); + return false; } + return true; } -static void qobject_input_type_int64_keyval(Visitor *v, const char *name, +static bool qobject_input_type_int64_keyval(Visitor *v, const char *name, int64_t *obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); const char *str = qobject_input_get_keyval(qiv, name, errp); if (!str) { - return; + return false; } if (qemu_strtoi64(str, NULL, 0, obj) < 0) { /* TODO report -ERANGE more nicely */ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, full_name(qiv, name), "integer"); + return false; } + return true; } -static void qobject_input_type_uint64(Visitor *v, const char *name, +static bool qobject_input_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); @@ -428,7 +439,7 @@ static void qobject_input_type_uint64(Visitor *v, const char *name, int64_t val; if (!qobj) { - return; + return false; } qnum = qobject_to(QNum, qobj); if (!qnum) { @@ -436,38 +447,41 @@ static void qobject_input_type_uint64(Visitor *v, const char *name, } if (qnum_get_try_uint(qnum, obj)) { - return; + return true; } /* Need to accept negative values for backward compatibility */ if (qnum_get_try_int(qnum, &val)) { *obj = val; - return; + return true; } err: error_setg(errp, QERR_INVALID_PARAMETER_VALUE, full_name(qiv, name), "uint64"); + return false; } -static void qobject_input_type_uint64_keyval(Visitor *v, const char *name, +static bool qobject_input_type_uint64_keyval(Visitor *v, const char *name, uint64_t *obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); const char *str = qobject_input_get_keyval(qiv, name, errp); if (!str) { - return; + return false; } if (qemu_strtou64(str, NULL, 0, obj) < 0) { /* TODO report -ERANGE more nicely */ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, full_name(qiv, name), "integer"); + return false; } + return true; } -static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj, +static bool qobject_input_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); @@ -475,26 +489,27 @@ static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj, QBool *qbool; if (!qobj) { - return; + return false; } qbool = qobject_to(QBool, qobj); if (!qbool) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, full_name(qiv, name), "boolean"); - return; + return false; } *obj = qbool_get_bool(qbool); + return true; } -static void qobject_input_type_bool_keyval(Visitor *v, const char *name, +static bool qobject_input_type_bool_keyval(Visitor *v, const char *name, bool *obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); const char *str = qobject_input_get_keyval(qiv, name, errp); if (!str) { - return; + return false; } if (!strcmp(str, "on")) { @@ -504,10 +519,12 @@ static void qobject_input_type_bool_keyval(Visitor *v, const char *name, } else { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, full_name(qiv, name), "'on' or 'off'"); + return false; } + return true; } -static void qobject_input_type_str(Visitor *v, const char *name, char **obj, +static bool qobject_input_type_str(Visitor *v, const char *name, char **obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); @@ -516,28 +533,30 @@ static void qobject_input_type_str(Visitor *v, const char *name, char **obj, *obj = NULL; if (!qobj) { - return; + return false; } qstr = qobject_to(QString, qobj); if (!qstr) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, full_name(qiv, name), "string"); - return; + return false; } *obj = g_strdup(qstring_get_str(qstr)); + return true; } -static void qobject_input_type_str_keyval(Visitor *v, const char *name, +static bool qobject_input_type_str_keyval(Visitor *v, const char *name, char **obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); const char *str = qobject_input_get_keyval(qiv, name, errp); *obj = g_strdup(str); + return !!str; } -static void qobject_input_type_number(Visitor *v, const char *name, double *obj, +static bool qobject_input_type_number(Visitor *v, const char *name, double *obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); @@ -545,19 +564,20 @@ static void qobject_input_type_number(Visitor *v, const char *name, double *obj, QNum *qnum; if (!qobj) { - return; + return false; } qnum = qobject_to(QNum, qobj); if (!qnum) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, full_name(qiv, name), "number"); - return; + return false; } *obj = qnum_get_double(qnum); + return true; } -static void qobject_input_type_number_keyval(Visitor *v, const char *name, +static bool qobject_input_type_number_keyval(Visitor *v, const char *name, double *obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); @@ -565,20 +585,21 @@ static void qobject_input_type_number_keyval(Visitor *v, const char *name, double val; if (!str) { - return; + return false; } if (qemu_strtod_finite(str, NULL, &val)) { /* TODO report -ERANGE more nicely */ error_setg(errp, QERR_INVALID_PARAMETER_TYPE, full_name(qiv, name), "number"); - return; + return false; } *obj = val; + return true; } -static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj, +static bool qobject_input_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); @@ -586,13 +607,14 @@ static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj, *obj = NULL; if (!qobj) { - return; + return false; } *obj = qobject_ref(qobj); + return true; } -static void qobject_input_type_null(Visitor *v, const char *name, +static bool qobject_input_type_null(Visitor *v, const char *name, QNull **obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); @@ -600,32 +622,35 @@ static void qobject_input_type_null(Visitor *v, const char *name, *obj = NULL; if (!qobj) { - return; + return false; } if (qobject_type(qobj) != QTYPE_QNULL) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, full_name(qiv, name), "null"); - return; + return false; } *obj = qnull(); + return true; } -static void qobject_input_type_size_keyval(Visitor *v, const char *name, +static bool qobject_input_type_size_keyval(Visitor *v, const char *name, uint64_t *obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); const char *str = qobject_input_get_keyval(qiv, name, errp); if (!str) { - return; + return false; } if (qemu_strtosz(str, NULL, obj) < 0) { /* TODO report -ERANGE more nicely */ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, full_name(qiv, name), "size"); + return false; } + return true; } static void qobject_input_optional(Visitor *v, const char *name, bool *present) diff --git a/qapi/qobject-output-visitor.c b/qapi/qobject-output-visitor.c index 26d7be5ec9..ba6f6ac8a7 100644 --- a/qapi/qobject-output-visitor.c +++ b/qapi/qobject-output-visitor.c @@ -103,7 +103,7 @@ static void qobject_output_add_obj(QObjectOutputVisitor *qov, const char *name, } } -static void qobject_output_start_struct(Visitor *v, const char *name, +static bool qobject_output_start_struct(Visitor *v, const char *name, void **obj, size_t unused, Error **errp) { QObjectOutputVisitor *qov = to_qov(v); @@ -111,6 +111,7 @@ static void qobject_output_start_struct(Visitor *v, const char *name, qobject_output_add(qov, name, dict); qobject_output_push(qov, dict, obj); + return true; } static void qobject_output_end_struct(Visitor *v, void **obj) @@ -120,7 +121,7 @@ static void qobject_output_end_struct(Visitor *v, void **obj) assert(qobject_type(value) == QTYPE_QDICT); } -static void qobject_output_start_list(Visitor *v, const char *name, +static bool qobject_output_start_list(Visitor *v, const char *name, GenericList **listp, size_t size, Error **errp) { @@ -129,6 +130,7 @@ static void qobject_output_start_list(Visitor *v, const char *name, qobject_output_add(qov, name, list); qobject_output_push(qov, list, listp); + return true; } static GenericList *qobject_output_next_list(Visitor *v, GenericList *tail, @@ -144,28 +146,31 @@ static void qobject_output_end_list(Visitor *v, void **obj) assert(qobject_type(value) == QTYPE_QLIST); } -static void qobject_output_type_int64(Visitor *v, const char *name, +static bool qobject_output_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { QObjectOutputVisitor *qov = to_qov(v); qobject_output_add(qov, name, qnum_from_int(*obj)); + return true; } -static void qobject_output_type_uint64(Visitor *v, const char *name, +static bool qobject_output_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { QObjectOutputVisitor *qov = to_qov(v); qobject_output_add(qov, name, qnum_from_uint(*obj)); + return true; } -static void qobject_output_type_bool(Visitor *v, const char *name, bool *obj, +static bool qobject_output_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { QObjectOutputVisitor *qov = to_qov(v); qobject_output_add(qov, name, qbool_from_bool(*obj)); + return true; } -static void qobject_output_type_str(Visitor *v, const char *name, char **obj, +static bool qobject_output_type_str(Visitor *v, const char *name, char **obj, Error **errp) { QObjectOutputVisitor *qov = to_qov(v); @@ -174,28 +179,32 @@ static void qobject_output_type_str(Visitor *v, const char *name, char **obj, } else { qobject_output_add(qov, name, qstring_from_str("")); } + return true; } -static void qobject_output_type_number(Visitor *v, const char *name, +static bool qobject_output_type_number(Visitor *v, const char *name, double *obj, Error **errp) { QObjectOutputVisitor *qov = to_qov(v); qobject_output_add(qov, name, qnum_from_double(*obj)); + return true; } -static void qobject_output_type_any(Visitor *v, const char *name, +static bool qobject_output_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) { QObjectOutputVisitor *qov = to_qov(v); qobject_output_add_obj(qov, name, qobject_ref(*obj)); + return true; } -static void qobject_output_type_null(Visitor *v, const char *name, +static bool qobject_output_type_null(Visitor *v, const char *name, QNull **obj, Error **errp) { QObjectOutputVisitor *qov = to_qov(v); qobject_output_add(qov, name, qnull()); + return true; } /* Finish building, and return the root object. diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c index 730fa4630d..d0ca10aefa 100644 --- a/qapi/string-input-visitor.c +++ b/qapi/string-input-visitor.c @@ -60,7 +60,7 @@ static StringInputVisitor *to_siv(Visitor *v) return container_of(v, StringInputVisitor, visitor); } -static void start_list(Visitor *v, const char *name, GenericList **list, +static bool start_list(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp) { StringInputVisitor *siv = to_siv(v); @@ -80,6 +80,7 @@ static void start_list(Visitor *v, const char *name, GenericList **list, } siv->lm = LM_UNPARSED; } + return true; } static GenericList *next_list(Visitor *v, GenericList *tail, size_t size) @@ -102,7 +103,7 @@ static GenericList *next_list(Visitor *v, GenericList *tail, size_t size) return tail->next; } -static void check_list(Visitor *v, Error **errp) +static bool check_list(Visitor *v, Error **errp) { const StringInputVisitor *siv = to_siv(v); @@ -111,9 +112,9 @@ static void check_list(Visitor *v, Error **errp) case LM_UINT64_RANGE: case LM_UNPARSED: error_setg(errp, "Fewer list elements expected"); - return; + return false; case LM_END: - return; + return true; default: abort(); } @@ -178,7 +179,7 @@ static int try_parse_int64_list_entry(StringInputVisitor *siv, int64_t *obj) return 0; } -static void parse_type_int64(Visitor *v, const char *name, int64_t *obj, +static bool parse_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { StringInputVisitor *siv = to_siv(v); @@ -188,17 +189,17 @@ static void parse_type_int64(Visitor *v, const char *name, int64_t *obj, case LM_NONE: /* just parse a simple int64, bail out if not completely consumed */ if (qemu_strtoi64(siv->string, NULL, 0, &val)) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, - name ? name : "null", "int64"); - return; + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + name ? name : "null", "int64"); + return false; } *obj = val; - return; + return true; case LM_UNPARSED: if (try_parse_int64_list_entry(siv, obj)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", "list of int64 values or ranges"); - return; + return false; } assert(siv->lm == LM_INT64_RANGE); /* fall through */ @@ -211,10 +212,10 @@ static void parse_type_int64(Visitor *v, const char *name, int64_t *obj, /* end of range, check if there is more to parse */ siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END; } - return; + return true; case LM_END: error_setg(errp, "Fewer list elements expected"); - return; + return false; default: abort(); } @@ -268,7 +269,7 @@ static int try_parse_uint64_list_entry(StringInputVisitor *siv, uint64_t *obj) return 0; } -static void parse_type_uint64(Visitor *v, const char *name, uint64_t *obj, +static bool parse_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { StringInputVisitor *siv = to_siv(v); @@ -280,15 +281,15 @@ static void parse_type_uint64(Visitor *v, const char *name, uint64_t *obj, if (qemu_strtou64(siv->string, NULL, 0, &val)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", "uint64"); - return; + return false; } *obj = val; - return; + return true; case LM_UNPARSED: if (try_parse_uint64_list_entry(siv, obj)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", "list of uint64 values or ranges"); - return; + return false; } assert(siv->lm == LM_UINT64_RANGE); /* fall through */ @@ -301,16 +302,16 @@ static void parse_type_uint64(Visitor *v, const char *name, uint64_t *obj, /* end of range, check if there is more to parse */ siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END; } - return; + return true; case LM_END: error_setg(errp, "Fewer list elements expected"); - return; + return false; default: abort(); } } -static void parse_type_size(Visitor *v, const char *name, uint64_t *obj, +static bool parse_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) { StringInputVisitor *siv = to_siv(v); @@ -320,13 +321,14 @@ static void parse_type_size(Visitor *v, const char *name, uint64_t *obj, assert(siv->lm == LM_NONE); if (!parse_option_size(name, siv->string, &val, &err)) { error_propagate(errp, err); - return; + return false; } *obj = val; + return true; } -static void parse_type_bool(Visitor *v, const char *name, bool *obj, +static bool parse_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { StringInputVisitor *siv = to_siv(v); @@ -336,29 +338,31 @@ static void parse_type_bool(Visitor *v, const char *name, bool *obj, !strcasecmp(siv->string, "yes") || !strcasecmp(siv->string, "true")) { *obj = true; - return; + return true; } if (!strcasecmp(siv->string, "off") || !strcasecmp(siv->string, "no") || !strcasecmp(siv->string, "false")) { *obj = false; - return; + return true; } error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean"); + return false; } -static void parse_type_str(Visitor *v, const char *name, char **obj, +static bool parse_type_str(Visitor *v, const char *name, char **obj, Error **errp) { StringInputVisitor *siv = to_siv(v); assert(siv->lm == LM_NONE); *obj = g_strdup(siv->string); + return true; } -static void parse_type_number(Visitor *v, const char *name, double *obj, +static bool parse_type_number(Visitor *v, const char *name, double *obj, Error **errp) { StringInputVisitor *siv = to_siv(v); @@ -368,13 +372,14 @@ static void parse_type_number(Visitor *v, const char *name, double *obj, if (qemu_strtod_finite(siv->string, NULL, &val)) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "number"); - return; + return false; } *obj = val; + return true; } -static void parse_type_null(Visitor *v, const char *name, QNull **obj, +static bool parse_type_null(Visitor *v, const char *name, QNull **obj, Error **errp) { StringInputVisitor *siv = to_siv(v); @@ -385,10 +390,11 @@ static void parse_type_null(Visitor *v, const char *name, QNull **obj, if (siv->string[0]) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "null"); - return; + return false; } *obj = qnull(); + return true; } static void string_input_free(Visitor *v) diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c index 0d93605d77..b74aa4d44c 100644 --- a/qapi/string-output-visitor.c +++ b/qapi/string-output-visitor.c @@ -123,7 +123,7 @@ static void format_string(StringOutputVisitor *sov, Range *r, bool next, } } -static void print_type_int64(Visitor *v, const char *name, int64_t *obj, +static bool print_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { StringOutputVisitor *sov = to_sov(v); @@ -138,7 +138,7 @@ static void print_type_int64(Visitor *v, const char *name, int64_t *obj, sov->range_start.s = *obj; sov->range_end.s = *obj; sov->list_mode = LM_IN_PROGRESS; - return; + return true; case LM_IN_PROGRESS: if (sov->range_end.s + 1 == *obj) { @@ -155,7 +155,7 @@ static void print_type_int64(Visitor *v, const char *name, int64_t *obj, sov->range_start.s = *obj; sov->range_end.s = *obj; } - return; + return true; case LM_END: if (sov->range_end.s + 1 == *obj) { @@ -197,17 +197,19 @@ static void print_type_int64(Visitor *v, const char *name, int64_t *obj, } g_string_append(sov->string, ")"); } + + return true; } -static void print_type_uint64(Visitor *v, const char *name, uint64_t *obj, +static bool print_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { /* FIXME: print_type_int64 mishandles values over INT64_MAX */ int64_t i = *obj; - print_type_int64(v, name, &i, errp); + return print_type_int64(v, name, &i, errp); } -static void print_type_size(Visitor *v, const char *name, uint64_t *obj, +static bool print_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) { StringOutputVisitor *sov = to_sov(v); @@ -217,7 +219,7 @@ static void print_type_size(Visitor *v, const char *name, uint64_t *obj, if (!sov->human) { out = g_strdup_printf("%"PRIu64, *obj); string_output_set(sov, out); - return; + return true; } val = *obj; @@ -226,16 +228,18 @@ static void print_type_size(Visitor *v, const char *name, uint64_t *obj, string_output_set(sov, out); g_free(psize); + return true; } -static void print_type_bool(Visitor *v, const char *name, bool *obj, +static bool print_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { StringOutputVisitor *sov = to_sov(v); string_output_set(sov, g_strdup(*obj ? "true" : "false")); + return true; } -static void print_type_str(Visitor *v, const char *name, char **obj, +static bool print_type_str(Visitor *v, const char *name, char **obj, Error **errp) { StringOutputVisitor *sov = to_sov(v); @@ -247,16 +251,18 @@ static void print_type_str(Visitor *v, const char *name, char **obj, out = g_strdup(*obj ? *obj : ""); } string_output_set(sov, out); + return true; } -static void print_type_number(Visitor *v, const char *name, double *obj, +static bool print_type_number(Visitor *v, const char *name, double *obj, Error **errp) { StringOutputVisitor *sov = to_sov(v); string_output_set(sov, g_strdup_printf("%f", *obj)); + return true; } -static void print_type_null(Visitor *v, const char *name, QNull **obj, +static bool print_type_null(Visitor *v, const char *name, QNull **obj, Error **errp) { StringOutputVisitor *sov = to_sov(v); @@ -268,9 +274,10 @@ static void print_type_null(Visitor *v, const char *name, QNull **obj, out = g_strdup(""); } string_output_set(sov, out); + return true; } -static void +static bool start_list(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp) { @@ -285,6 +292,7 @@ start_list(Visitor *v, const char *name, GenericList **list, size_t size, if (*list && (*list)->next) { sov->list_mode = LM_STARTED; } + return true; } static GenericList *next_list(Visitor *v, GenericList *tail, size_t size) diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index d5d7a1031f..ba0cf0b074 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -23,7 +23,7 @@ def gen_visit_decl(name, scalar=False): if not scalar: c_type += '*' return mcgen(''' -void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_type)sobj, Error **errp); +bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_type)sobj, Error **errp); ''', c_name=c_name(name), c_type=c_type) @@ -31,7 +31,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_type)sobj, Error ** def gen_visit_members_decl(name): return mcgen(''' -void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp); +bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp); ''', c_name=c_name(name)) @@ -39,7 +39,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp); def gen_visit_object_members(name, base, members, variants): ret = mcgen(''' -void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) +bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) { Error *err = NULL; @@ -48,9 +48,8 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) if base: ret += mcgen(''' - visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, &err); - if (err) { - goto out; + if (!visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, errp)) { + return false; } ''', c_type=base.c_name()) @@ -64,9 +63,8 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) name=memb.name, c_name=c_name(memb.name)) push_indent() ret += mcgen(''' - visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, &err); - if (err) { - goto out; + if (!visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, errp)) { + return false; } ''', c_type=memb.type.c_name(), name=memb.name, @@ -112,15 +110,9 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) } ''') - # 'goto out' produced for base, for each member, and if variants were - # present - if base or members or variants: - ret += mcgen(''' - -out: -''') ret += mcgen(''' error_propagate(errp, err); + return !err; } ''') return ret @@ -129,15 +121,14 @@ out: def gen_visit_list(name, element_type): return mcgen(''' -void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) +bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) { Error *err = NULL; %(c_name)s *tail; size_t size = sizeof(**obj); - visit_start_list(v, name, (GenericList **)obj, size, &err); - if (err) { - goto out; + if (!visit_start_list(v, name, (GenericList **)obj, size, errp)) { + return false; } for (tail = *obj; tail; @@ -156,8 +147,8 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error qapi_free_%(c_name)s(*obj); *obj = NULL; } -out: error_propagate(errp, err); + return !err; } ''', c_name=c_name(name), c_elt_type=element_type.c_name()) @@ -166,11 +157,12 @@ out: def gen_visit_enum(name): return mcgen(''' -void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s *obj, Error **errp) +bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s *obj, Error **errp) { int value = *obj; - visit_type_enum(v, name, &value, &%(c_name)s_lookup, errp); + bool ok = visit_type_enum(v, name, &value, &%(c_name)s_lookup, errp); *obj = value; + return ok; } ''', c_name=c_name(name)) @@ -179,14 +171,13 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s *obj, Error def gen_visit_alternate(name, variants): ret = mcgen(''' -void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) +bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) { Error *err = NULL; - visit_start_alternate(v, name, (GenericAlternate **)obj, sizeof(**obj), - &err); - if (err) { - goto out; + if (!visit_start_alternate(v, name, (GenericAlternate **)obj, + sizeof(**obj), errp)) { + return false; } if (!*obj) { /* incomplete */ @@ -245,8 +236,8 @@ out_obj: qapi_free_%(c_name)s(*obj); *obj = NULL; } -out: error_propagate(errp, err); + return !err; } ''', name=name, c_name=c_name(name)) @@ -257,13 +248,12 @@ out: def gen_visit_object(name, base, members, variants): return mcgen(''' -void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) +bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) { Error *err = NULL; - visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), &err); - if (err) { - goto out; + if (!visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), errp)) { + return false; } if (!*obj) { /* incomplete */ @@ -281,8 +271,8 @@ out_obj: qapi_free_%(c_name)s(*obj); *obj = NULL; } -out: error_propagate(errp, err); + return !err; } ''', c_name=c_name(name)) From 62a35aaa310807fa161ca041ddb0f308faeb582b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:46 +0200 Subject: [PATCH 2050/2595] qapi: Use returned bool to check for failure, Coccinelle part The previous commit enables conversion of visit_foo(..., &err); if (err) { ... } to if (!visit_foo(..., errp)) { ... } for visitor functions that now return true / false on success / error. Coccinelle script: @@ identifier fun =~ "check_list|input_type_enum|lv_start_struct|lv_type_bool|lv_type_int64|lv_type_str|lv_type_uint64|output_type_enum|parse_type_bool|parse_type_int64|parse_type_null|parse_type_number|parse_type_size|parse_type_str|parse_type_uint64|print_type_bool|print_type_int64|print_type_null|print_type_number|print_type_size|print_type_str|print_type_uint64|qapi_clone_start_alternate|qapi_clone_start_list|qapi_clone_start_struct|qapi_clone_type_bool|qapi_clone_type_int64|qapi_clone_type_null|qapi_clone_type_number|qapi_clone_type_str|qapi_clone_type_uint64|qapi_dealloc_start_list|qapi_dealloc_start_struct|qapi_dealloc_type_anything|qapi_dealloc_type_bool|qapi_dealloc_type_int64|qapi_dealloc_type_null|qapi_dealloc_type_number|qapi_dealloc_type_str|qapi_dealloc_type_uint64|qobject_input_check_list|qobject_input_check_struct|qobject_input_start_alternate|qobject_input_start_list|qobject_input_start_struct|qobject_input_type_any|qobject_input_type_bool|qobject_input_type_bool_keyval|qobject_input_type_int64|qobject_input_type_int64_keyval|qobject_input_type_null|qobject_input_type_number|qobject_input_type_number_keyval|qobject_input_type_size_keyval|qobject_input_type_str|qobject_input_type_str_keyval|qobject_input_type_uint64|qobject_input_type_uint64_keyval|qobject_output_start_list|qobject_output_start_struct|qobject_output_type_any|qobject_output_type_bool|qobject_output_type_int64|qobject_output_type_null|qobject_output_type_number|qobject_output_type_str|qobject_output_type_uint64|start_list|visit_check_list|visit_check_struct|visit_start_alternate|visit_start_list|visit_start_struct|visit_type_.*"; expression list args; typedef Error; Error *err; @@ - fun(args, &err); - if (err) + if (!fun(args, &err)) { ... } A few line breaks tidied up manually. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-19-armbru@redhat.com> --- accel/kvm/kvm-all.c | 3 +-- accel/tcg/tcg-all.c | 3 +-- backends/cryptodev.c | 3 +-- backends/hostmem-file.c | 3 +-- backends/hostmem-memfd.c | 3 +-- backends/hostmem.c | 6 ++--- backends/tpm/tpm_util.c | 3 +-- block/blkdebug.c | 3 +-- block/nbd.c | 3 +-- block/sheepdog.c | 3 +-- block/throttle-groups.c | 6 ++--- bootdevice.c | 3 +-- hw/block/xen-block.c | 3 +-- hw/core/machine.c | 3 +-- hw/core/qdev-properties-system.c | 12 +++------ hw/core/qdev-properties.c | 38 +++++++++++------------------ hw/cpu/core.c | 6 ++--- hw/gpio/aspeed_gpio.c | 3 +-- hw/i386/pc.c | 3 +-- hw/ide/qdev.c | 3 +-- hw/intc/apic_common.c | 3 +-- hw/mem/nvdimm.c | 6 ++--- hw/misc/aspeed_sdmc.c | 3 +-- hw/misc/pca9552.c | 3 +-- hw/misc/tmp105.c | 3 +-- hw/misc/tmp421.c | 3 +-- hw/net/ne2000-isa.c | 3 +-- hw/ppc/spapr_caps.c | 9 +++---- hw/ppc/spapr_drc.c | 10 +++----- hw/s390x/css.c | 3 +-- hw/usb/dev-storage.c | 3 +-- hw/vfio/pci-quirks.c | 3 +-- hw/virtio/virtio-balloon.c | 15 ++++-------- iothread.c | 3 +-- monitor/hmp-cmds.c | 3 +-- net/colo-compare.c | 6 ++--- net/dump.c | 3 +-- net/filter-buffer.c | 3 +-- qom/object.c | 42 +++++++++++--------------------- qom/object_interfaces.c | 3 +-- target/arm/cpu64.c | 9 +++---- target/arm/monitor.c | 3 +-- target/i386/cpu.c | 15 ++++-------- target/ppc/compat.c | 3 +-- target/s390x/cpu_models.c | 9 +++---- target/sparc/cpu.c | 3 +-- 46 files changed, 97 insertions(+), 188 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index ab36fbfa0c..375e29fb69 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3116,8 +3116,7 @@ static void kvm_set_kvm_shadow_mem(Object *obj, Visitor *v, Error *error = NULL; int64_t value; - visit_type_int(v, name, &value, &error); - if (error) { + if (!visit_type_int(v, name, &value, &error)) { error_propagate(errp, error); return; } diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 3b4fda5640..d6b3d7fc07 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -185,8 +185,7 @@ static void tcg_set_tb_size(Object *obj, Visitor *v, Error *error = NULL; uint32_t value; - visit_type_uint32(v, name, &value, &error); - if (error) { + if (!visit_type_uint32(v, name, &value, &error)) { error_propagate(errp, error); return; } diff --git a/backends/cryptodev.c b/backends/cryptodev.c index a3841c4e41..7e7265102e 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -157,8 +157,7 @@ cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name, Error *local_err = NULL; uint32_t value; - visit_type_uint32(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint32(v, name, &value, &local_err)) { goto out; } if (!value) { diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index cdabb412e6..320dffbaa9 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -119,8 +119,7 @@ static void file_memory_backend_set_align(Object *o, Visitor *v, goto out; } - visit_type_size(v, name, &val, &local_err); - if (local_err) { + if (!visit_type_size(v, name, &val, &local_err)) { goto out; } fb->align = val; diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c index 1b5e4bfe0d..d4281c0032 100644 --- a/backends/hostmem-memfd.c +++ b/backends/hostmem-memfd.c @@ -85,8 +85,7 @@ memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name, goto out; } - visit_type_size(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_size(v, name, &value, &local_err)) { goto out; } if (!value) { diff --git a/backends/hostmem.c b/backends/hostmem.c index 61e3255f5c..4e4103ac09 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -63,8 +63,7 @@ host_memory_backend_set_size(Object *obj, Visitor *v, const char *name, goto out; } - visit_type_size(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_size(v, name, &value, &local_err)) { goto out; } if (!value) { @@ -257,8 +256,7 @@ static void host_memory_backend_set_prealloc_threads(Object *obj, Visitor *v, Error *local_err = NULL; uint32_t value; - visit_type_uint32(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint32(v, name, &value, &local_err)) { goto out; } if (value <= 0) { diff --git a/backends/tpm/tpm_util.c b/backends/tpm/tpm_util.c index cfc7572a61..971f3af047 100644 --- a/backends/tpm/tpm_util.c +++ b/backends/tpm/tpm_util.c @@ -58,8 +58,7 @@ static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/block/blkdebug.c b/block/blkdebug.c index d473dcf8c7..3c0a9d45cc 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -375,8 +375,7 @@ static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options, } v = qobject_input_visitor_new(crumpled_subqdict); - visit_type_BlockPermissionList(v, NULL, &perm_list, &local_err); - if (local_err) { + if (!visit_type_BlockPermissionList(v, NULL, &perm_list, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto out; diff --git a/block/nbd.c b/block/nbd.c index 1b30d96a4f..1331307ffb 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1739,8 +1739,7 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, goto done; } - visit_type_SocketAddress(iv, NULL, &saddr, &local_err); - if (local_err) { + if (!visit_type_SocketAddress(iv, NULL, &saddr, &local_err)) { error_propagate(errp, local_err); goto done; } diff --git a/block/sheepdog.c b/block/sheepdog.c index a8d396dcdf..e3bcb05f60 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -541,8 +541,7 @@ static SocketAddress *sd_server_config(QDict *options, Error **errp) goto done; } - visit_type_SocketAddress(iv, NULL, &saddr, &local_err); - if (local_err) { + if (!visit_type_SocketAddress(iv, NULL, &saddr, &local_err)) { error_propagate(errp, local_err); goto done; } diff --git a/block/throttle-groups.c b/block/throttle-groups.c index 784fa4a16c..bb242fde1a 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -823,8 +823,7 @@ static void throttle_group_set(Object *obj, Visitor *v, const char * name, goto ret; } - visit_type_int64(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_int64(v, name, &value, &local_err)) { goto ret; } if (value < 0) { @@ -896,8 +895,7 @@ static void throttle_group_set_limits(Object *obj, Visitor *v, ThrottleLimits *argp; Error *local_err = NULL; - visit_type_ThrottleLimits(v, name, &argp, &local_err); - if (local_err) { + if (!visit_type_ThrottleLimits(v, name, &argp, &local_err)) { goto ret; } qemu_mutex_lock(&tg->lock); diff --git a/bootdevice.c b/bootdevice.c index 0ff55e2b79..fb09d3c668 100644 --- a/bootdevice.c +++ b/bootdevice.c @@ -297,8 +297,7 @@ static void device_set_bootindex(Object *obj, Visitor *v, const char *name, int32_t boot_index; Error *local_err = NULL; - visit_type_int32(v, name, &boot_index, &local_err); - if (local_err) { + if (!visit_type_int32(v, name, &boot_index, &local_err)) { goto out; } /* check whether bootindex is present in fw_boot_order list */ diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 10c44dfda2..48890536a4 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -412,8 +412,7 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/core/machine.c b/hw/core/machine.c index 211b4e077a..7ff0af93ef 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -293,8 +293,7 @@ static void machine_set_phandle_start(Object *obj, Visitor *v, Error *error = NULL; int64_t value; - visit_type_int(v, name, &value, &error); - if (error) { + if (!visit_type_int(v, name, &value, &error)) { error_propagate(errp, error); return; } diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 38b0c9f09b..383a54578f 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -92,8 +92,7 @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_propagate(errp, local_err); return; } @@ -238,8 +237,7 @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_propagate(errp, local_err); return; } @@ -316,8 +314,7 @@ static void set_netdev(Object *obj, Visitor *v, const char *name, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_propagate(errp, local_err); return; } @@ -398,8 +395,7 @@ static void set_audiodev(Object *obj, Visitor *v, const char* name, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index ca7771f307..3cb6faa12b 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -125,8 +125,7 @@ static void prop_set_bit(Object *obj, Visitor *v, const char *name, return; } - visit_type_bool(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_bool(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -189,8 +188,7 @@ static void prop_set_bit64(Object *obj, Visitor *v, const char *name, return; } - visit_type_bool(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_bool(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -486,8 +484,7 @@ static void set_string(Object *obj, Visitor *v, const char *name, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_propagate(errp, local_err); return; } @@ -540,8 +537,7 @@ static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_propagate(errp, local_err); return; } @@ -762,8 +758,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, const char *name, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_free(local_err); local_err = NULL; visit_type_int32(v, name, &value, &local_err); @@ -844,8 +839,7 @@ static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque, return; } - visit_type_size(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_size(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -894,8 +888,7 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name, return; } - visit_type_size(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_size(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -976,8 +969,7 @@ static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_propagate(errp, local_err); return; } @@ -1076,8 +1068,7 @@ static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_propagate(errp, local_err); return; } @@ -1158,8 +1149,7 @@ static void set_prop_arraylen(Object *obj, Visitor *v, const char *name, name); return; } - visit_type_uint32(v, name, alenptr, &local_err); - if (local_err) { + if (!visit_type_uint32(v, name, alenptr, &local_err)) { error_propagate(errp, local_err); return; } @@ -1490,8 +1480,8 @@ static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name, return; } - visit_type_enum(v, prop->name, &speed, prop->info->enum_table, &local_err); - if (local_err) { + if (!visit_type_enum(v, prop->name, &speed, prop->info->enum_table, + &local_err)) { error_propagate(errp, local_err); return; } @@ -1578,8 +1568,8 @@ static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name, return; } - visit_type_enum(v, prop->name, &width, prop->info->enum_table, &local_err); - if (local_err) { + if (!visit_type_enum(v, prop->name, &width, prop->info->enum_table, + &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/cpu/core.c b/hw/cpu/core.c index a92ac597ca..d9857031ca 100644 --- a/hw/cpu/core.c +++ b/hw/cpu/core.c @@ -31,8 +31,7 @@ static void core_prop_set_core_id(Object *obj, Visitor *v, const char *name, Error *local_err = NULL; int64_t value; - visit_type_int(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_int(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -61,8 +60,7 @@ static void core_prop_set_nr_threads(Object *obj, Visitor *v, const char *name, Error *local_err = NULL; int64_t value; - visit_type_int(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_int(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index dfa9db3d33..3310fe62fe 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -762,8 +762,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name, AspeedGPIOState *s = ASPEED_GPIO(obj); int set_idx, group_idx = 0; - visit_type_bool(v, name, &level, &local_err); - if (local_err) { + if (!visit_type_bool(v, name, &level, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index d7f27bc16b..cb15261420 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1862,8 +1862,7 @@ static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v, Error *error = NULL; uint64_t value; - visit_type_size(v, name, &value, &error); - if (error) { + if (!visit_type_size(v, name, &value, &error)) { error_propagate(errp, error); return; } diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index f68fbee93d..358f10a92e 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -245,8 +245,7 @@ static void ide_dev_set_bootindex(Object *obj, Visitor *v, const char *name, int32_t boot_index; Error *local_err = NULL; - visit_type_int32(v, name, &boot_index, &local_err); - if (local_err) { + if (!visit_type_int32(v, name, &boot_index, &local_err)) { goto out; } /* check whether bootindex is present in fw_boot_order list */ diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 7da2862b3d..76c3f78e11 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -428,8 +428,7 @@ static void apic_common_set_id(Object *obj, Visitor *v, const char *name, return; } - visit_type_uint32(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint32(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index 76f66e0b19..ec92ffd415 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -53,8 +53,7 @@ static void nvdimm_set_label_size(Object *obj, Visitor *v, const char *name, goto out; } - visit_type_size(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_size(v, name, &value, &local_err)) { goto out; } if (value < MIN_NAMESPACE_LABEL_SIZE) { @@ -89,8 +88,7 @@ static void nvdimm_set_uuid(Object *obj, Visitor *v, const char *name, Error *local_err = NULL; char *value; - visit_type_str(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &value, &local_err)) { goto out; } diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index 25e1e58356..28874445c3 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -227,8 +227,7 @@ static void aspeed_sdmc_set_ram_size(Object *obj, Visitor *v, const char *name, AspeedSDMCState *s = ASPEED_SDMC(obj); AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s); - visit_type_int(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_int(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index 68b574d084..d2b99fc706 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -296,8 +296,7 @@ static void pca955x_set_led(Object *obj, Visitor *v, const char *name, uint8_t state; char *state_str; - visit_type_str(v, name, &state_str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &state_str, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c index 58dbebca90..2ae0b899be 100644 --- a/hw/misc/tmp105.c +++ b/hw/misc/tmp105.c @@ -75,8 +75,7 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, const char *name, Error *local_err = NULL; int64_t temp; - visit_type_int(v, name, &temp, &local_err); - if (local_err) { + if (!visit_type_int(v, name, &temp, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/misc/tmp421.c b/hw/misc/tmp421.c index 74864cd93d..9473382bd5 100644 --- a/hw/misc/tmp421.c +++ b/hw/misc/tmp421.c @@ -147,8 +147,7 @@ static void tmp421_set_temperature(Object *obj, Visitor *v, const char *name, int offset = ext_range * 64 * 256; int tempid; - visit_type_int(v, name, &temp, &local_err); - if (local_err) { + if (!visit_type_int(v, name, &temp, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index fdf8faa0d9..765bcd1f0b 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -113,8 +113,7 @@ static void isa_ne2000_set_bootindex(Object *obj, Visitor *v, int32_t boot_index; Error *local_err = NULL; - visit_type_int32(v, name, &boot_index, &local_err); - if (local_err) { + if (!visit_type_int32(v, name, &boot_index, &local_err)) { goto out; } /* check whether bootindex is present in fw_boot_order list */ diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 0c2bc8e06e..52be86e49c 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -88,8 +88,7 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, bool value; Error *local_err = NULL; - visit_type_bool(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_bool(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -127,8 +126,7 @@ static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name, uint8_t i; char *val; - visit_type_str(v, name, &val, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &val, &local_err)) { error_propagate(errp, local_err); return; } @@ -171,8 +169,7 @@ static void spapr_cap_set_pagesize(Object *obj, Visitor *v, const char *name, uint8_t val; Error *local_err = NULL; - visit_type_size(v, name, &pagesize, &local_err); - if (local_err) { + if (!visit_type_size(v, name, &pagesize, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 951bcdf2c0..d10193f39e 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -327,8 +327,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, case FDT_BEGIN_NODE: fdt_depth++; name = fdt_get_name(fdt, fdt_offset, &name_len); - visit_start_struct(v, name, NULL, 0, &err); - if (err) { + if (!visit_start_struct(v, name, NULL, 0, &err)) { error_propagate(errp, err); return; } @@ -348,14 +347,13 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, int i; prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len); name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - visit_start_list(v, name, NULL, 0, &err); - if (err) { + if (!visit_start_list(v, name, NULL, 0, &err)) { error_propagate(errp, err); return; } for (i = 0; i < prop_len; i++) { - visit_type_uint8(v, NULL, (uint8_t *)&prop->data[i], &err); - if (err) { + if (!visit_type_uint8(v, NULL, (uint8_t *)&prop->data[i], + &err)) { error_propagate(errp, err); return; } diff --git a/hw/s390x/css.c b/hw/s390x/css.c index d1e365e3e6..ab28b2fb30 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -2387,8 +2387,7 @@ static void set_css_devid(Object *obj, Visitor *v, const char *name, return; } - visit_type_str(v, name, &str, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &str, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index f5977eb72e..1c3bd2578c 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -736,8 +736,7 @@ static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name, int32_t boot_index; Error *local_err = NULL; - visit_type_int32(v, name, &boot_index, &local_err); - if (local_err) { + if (!visit_type_int32(v, name, &boot_index, &local_err)) { goto out; } /* check whether bootindex is present in fw_boot_order list */ diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index d304c81148..1467b8034e 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1509,8 +1509,7 @@ static void set_nv_gpudirect_clique_id(Object *obj, Visitor *v, return; } - visit_type_uint8(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint8(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index ae31f0817a..277747f4f1 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -239,22 +239,18 @@ static void balloon_stats_get_all(Object *obj, Visitor *v, const char *name, VirtIOBalloon *s = opaque; int i; - visit_start_struct(v, name, NULL, 0, &err); - if (err) { + if (!visit_start_struct(v, name, NULL, 0, &err)) { goto out; } - visit_type_int(v, "last-update", &s->stats_last_update, &err); - if (err) { + if (!visit_type_int(v, "last-update", &s->stats_last_update, &err)) { goto out_end; } - visit_start_struct(v, "stats", NULL, 0, &err); - if (err) { + if (!visit_start_struct(v, "stats", NULL, 0, &err)) { goto out_end; } for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) { - visit_type_uint64(v, balloon_stat_names[i], &s->stats[i], &err); - if (err) { + if (!visit_type_uint64(v, balloon_stat_names[i], &s->stats[i], &err)) { goto out_nested; } } @@ -287,8 +283,7 @@ static void balloon_stats_set_poll_interval(Object *obj, Visitor *v, Error *local_err = NULL; int64_t value; - visit_type_int(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_int(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/iothread.c b/iothread.c index cb082b9b26..cb65ef0e56 100644 --- a/iothread.c +++ b/iothread.c @@ -243,8 +243,7 @@ static void iothread_set_poll_param(Object *obj, Visitor *v, Error *local_err = NULL; int64_t value; - visit_type_int64(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_int64(v, name, &value, &local_err)) { goto out; } diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index bb17b1b96c..ae4b6a4246 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -1355,8 +1355,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) break; case MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE: p->has_xbzrle_cache_size = true; - visit_type_size(v, param, &cache_size, &err); - if (err) { + if (!visit_type_size(v, param, &cache_size, &err)) { break; } if (cache_size > INT64_MAX || (size_t)cache_size != cache_size) { diff --git a/net/colo-compare.c b/net/colo-compare.c index f15779dedc..6835d42363 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -1096,8 +1096,7 @@ static void compare_set_timeout(Object *obj, Visitor *v, Error *local_err = NULL; uint32_t value; - visit_type_uint32(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint32(v, name, &value, &local_err)) { goto out; } if (!value) { @@ -1129,8 +1128,7 @@ static void compare_set_expired_scan_cycle(Object *obj, Visitor *v, Error *local_err = NULL; uint32_t value; - visit_type_uint32(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint32(v, name, &value, &local_err)) { goto out; } if (!value) { diff --git a/net/dump.c b/net/dump.c index 61389e7dad..8c487a5590 100644 --- a/net/dump.c +++ b/net/dump.c @@ -195,8 +195,7 @@ static void filter_dump_set_maxlen(Object *obj, Visitor *v, const char *name, Error *local_err = NULL; uint32_t value; - visit_type_uint32(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint32(v, name, &value, &local_err)) { goto out; } if (value == 0) { diff --git a/net/filter-buffer.c b/net/filter-buffer.c index 93050f86cf..8e42934b37 100644 --- a/net/filter-buffer.c +++ b/net/filter-buffer.c @@ -173,8 +173,7 @@ static void filter_buffer_set_interval(Object *obj, Visitor *v, Error *local_err = NULL; uint32_t value; - visit_type_uint32(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint32(v, name, &value, &local_err)) { goto out; } if (!value) { diff --git a/qom/object.c b/qom/object.c index 34daaf1280..0213e87c86 100644 --- a/qom/object.c +++ b/qom/object.c @@ -2094,8 +2094,7 @@ static void property_set_str(Object *obj, Visitor *v, const char *name, char *value; Error *local_err = NULL; - visit_type_str(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -2175,8 +2174,7 @@ static void property_set_bool(Object *obj, Visitor *v, const char *name, bool value; Error *local_err = NULL; - visit_type_bool(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_bool(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -2248,8 +2246,7 @@ static void property_set_enum(Object *obj, Visitor *v, const char *name, int value; Error *err = NULL; - visit_type_enum(v, name, &value, prop->lookup, &err); - if (err) { + if (!visit_type_enum(v, name, &value, prop->lookup, &err)) { error_propagate(errp, err); return; } @@ -2319,32 +2316,25 @@ static void property_get_tm(Object *obj, Visitor *v, const char *name, goto out; } - visit_start_struct(v, name, NULL, 0, &err); - if (err) { + if (!visit_start_struct(v, name, NULL, 0, &err)) { goto out; } - visit_type_int32(v, "tm_year", &value.tm_year, &err); - if (err) { + if (!visit_type_int32(v, "tm_year", &value.tm_year, &err)) { goto out_end; } - visit_type_int32(v, "tm_mon", &value.tm_mon, &err); - if (err) { + if (!visit_type_int32(v, "tm_mon", &value.tm_mon, &err)) { goto out_end; } - visit_type_int32(v, "tm_mday", &value.tm_mday, &err); - if (err) { + if (!visit_type_int32(v, "tm_mday", &value.tm_mday, &err)) { goto out_end; } - visit_type_int32(v, "tm_hour", &value.tm_hour, &err); - if (err) { + if (!visit_type_int32(v, "tm_hour", &value.tm_hour, &err)) { goto out_end; } - visit_type_int32(v, "tm_min", &value.tm_min, &err); - if (err) { + if (!visit_type_int32(v, "tm_min", &value.tm_min, &err)) { goto out_end; } - visit_type_int32(v, "tm_sec", &value.tm_sec, &err); - if (err) { + if (!visit_type_int32(v, "tm_sec", &value.tm_sec, &err)) { goto out_end; } visit_check_struct(v, &err); @@ -2408,8 +2398,7 @@ static void property_set_uint8_ptr(Object *obj, Visitor *v, const char *name, uint8_t value; Error *local_err = NULL; - visit_type_uint8(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint8(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -2431,8 +2420,7 @@ static void property_set_uint16_ptr(Object *obj, Visitor *v, const char *name, uint16_t value; Error *local_err = NULL; - visit_type_uint16(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint16(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -2454,8 +2442,7 @@ static void property_set_uint32_ptr(Object *obj, Visitor *v, const char *name, uint32_t value; Error *local_err = NULL; - visit_type_uint32(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint32(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -2477,8 +2464,7 @@ static void property_set_uint64_ptr(Object *obj, Visitor *v, const char *name, uint64_t value; Error *local_err = NULL; - visit_type_uint64(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_uint64(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 7e26f86fa6..3085ae0b31 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -63,8 +63,7 @@ Object *user_creatable_add_type(const char *type, const char *id, assert(qdict); obj = object_new(type); - visit_start_struct(v, NULL, NULL, 0, &local_err); - if (local_err) { + if (!visit_start_struct(v, NULL, NULL, 0, &local_err)) { goto out; } for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) { diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index a2f4733eed..343c227c09 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -467,8 +467,7 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, Error *err = NULL; uint32_t max_vq; - visit_type_uint32(v, name, &max_vq, &err); - if (err) { + if (!visit_type_uint32(v, name, &max_vq, &err)) { error_propagate(errp, err); return; } @@ -513,8 +512,7 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name, Error *err = NULL; bool value; - visit_type_bool(v, name, &value, &err); - if (err) { + if (!visit_type_bool(v, name, &value, &err)) { error_propagate(errp, err); return; } @@ -550,8 +548,7 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name, bool value; uint64_t t; - visit_type_bool(v, name, &value, &err); - if (err) { + if (!visit_type_bool(v, name, &value, &err)) { error_propagate(errp, err); return; } diff --git a/target/arm/monitor.c b/target/arm/monitor.c index ea6598c412..98fe11ae69 100644 --- a/target/arm/monitor.c +++ b/target/arm/monitor.c @@ -174,8 +174,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, Error *err = NULL; visitor = qobject_input_visitor_new(model->props); - visit_start_struct(visitor, NULL, NULL, 0, &err); - if (err) { + if (!visit_start_struct(visitor, NULL, NULL, 0, &err)) { visit_free(visitor); object_unref(obj); error_propagate(errp, err); diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 36cbd3d027..c69d057df3 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -4420,8 +4420,7 @@ static void x86_cpuid_version_set_family(Object *obj, Visitor *v, Error *local_err = NULL; int64_t value; - visit_type_int(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_int(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -4463,8 +4462,7 @@ static void x86_cpuid_version_set_model(Object *obj, Visitor *v, Error *local_err = NULL; int64_t value; - visit_type_int(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_int(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -4501,8 +4499,7 @@ static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v, Error *local_err = NULL; int64_t value; - visit_type_int(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_int(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -4606,8 +4603,7 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, const char *name, Error *local_err = NULL; int64_t value; - visit_type_int(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_int(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } @@ -6816,8 +6812,7 @@ static void x86_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, return; } - visit_type_bool(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_bool(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/target/ppc/compat.c b/target/ppc/compat.c index fda0dfe8f8..42f87a4bfe 100644 --- a/target/ppc/compat.c +++ b/target/ppc/compat.c @@ -264,8 +264,7 @@ static void ppc_compat_prop_set(Object *obj, Visitor *v, const char *name, char *value; uint32_t compat_pvr; - visit_type_str(v, name, &value, &local_err); - if (local_err) { + if (!visit_type_str(v, name, &value, &local_err)) { error_propagate(errp, local_err); return; } diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 2fa609bffe..65c26c4c86 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -510,8 +510,7 @@ static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info, if (qdict) { visitor = qobject_input_visitor_new(info->props); - visit_start_struct(visitor, NULL, NULL, 0, &err); - if (err) { + if (!visit_start_struct(visitor, NULL, NULL, 0, &err)) { error_propagate(errp, err); visit_free(visitor); object_unref(obj); @@ -1017,8 +1016,7 @@ static void set_feature(Object *obj, Visitor *v, const char *name, return; } - visit_type_bool(v, name, &value, &err); - if (err) { + if (!visit_type_bool(v, name, &value, &err)) { error_propagate(errp, err); return; } @@ -1076,8 +1074,7 @@ static void set_feature_group(Object *obj, Visitor *v, const char *name, return; } - visit_type_bool(v, name, &value, &err); - if (err) { + if (!visit_type_bool(v, name, &value, &err)) { error_propagate(errp, err); return; } diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 3f05aba9d6..4a9257005d 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -804,8 +804,7 @@ static void sparc_set_nwindows(Object *obj, Visitor *v, const char *name, Error *err = NULL; int64_t value; - visit_type_int(v, name, &value, &err); - if (err) { + if (!visit_type_int(v, name, &value, &err)) { error_propagate(errp, err); return; } From 14217038bc9e36246d311fa8e026a01a5d7bbd42 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:47 +0200 Subject: [PATCH 2051/2595] qapi: Use returned bool to check for failure, manual part The previous commit used Coccinelle to convert from checking the Error object to checking the return value. Convert a few more manually. Also tweak control flow in places to conform to the conventional "if error bail out" pattern. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-20-armbru@redhat.com> --- accel/kvm/kvm-all.c | 50 ++++++++++++++++++--------------------- block/throttle-groups.c | 5 ++-- bootdevice.c | 4 ++-- hw/core/qdev-properties.c | 12 +++++----- hw/ide/qdev.c | 4 ++-- hw/mem/nvdimm.c | 9 +++---- hw/net/ne2000-isa.c | 4 ++-- hw/usb/dev-storage.c | 4 ++-- net/net.c | 8 ++----- 9 files changed, 44 insertions(+), 56 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 375e29fb69..ab1a6ff0ee 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3128,37 +3128,33 @@ static void kvm_set_kernel_irqchip(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - Error *err = NULL; KVMState *s = KVM_STATE(obj); OnOffSplit mode; - visit_type_OnOffSplit(v, name, &mode, &err); - if (err) { - error_propagate(errp, err); + if (!visit_type_OnOffSplit(v, name, &mode, errp)) { return; - } else { - switch (mode) { - case ON_OFF_SPLIT_ON: - s->kernel_irqchip_allowed = true; - s->kernel_irqchip_required = true; - s->kernel_irqchip_split = ON_OFF_AUTO_OFF; - break; - case ON_OFF_SPLIT_OFF: - s->kernel_irqchip_allowed = false; - s->kernel_irqchip_required = false; - s->kernel_irqchip_split = ON_OFF_AUTO_OFF; - break; - case ON_OFF_SPLIT_SPLIT: - s->kernel_irqchip_allowed = true; - s->kernel_irqchip_required = true; - s->kernel_irqchip_split = ON_OFF_AUTO_ON; - break; - default: - /* The value was checked in visit_type_OnOffSplit() above. If - * we get here, then something is wrong in QEMU. - */ - abort(); - } + } + switch (mode) { + case ON_OFF_SPLIT_ON: + s->kernel_irqchip_allowed = true; + s->kernel_irqchip_required = true; + s->kernel_irqchip_split = ON_OFF_AUTO_OFF; + break; + case ON_OFF_SPLIT_OFF: + s->kernel_irqchip_allowed = false; + s->kernel_irqchip_required = false; + s->kernel_irqchip_split = ON_OFF_AUTO_OFF; + break; + case ON_OFF_SPLIT_SPLIT: + s->kernel_irqchip_allowed = true; + s->kernel_irqchip_required = true; + s->kernel_irqchip_split = ON_OFF_AUTO_ON; + break; + default: + /* The value was checked in visit_type_OnOffSplit() above. If + * we get here, then something is wrong in QEMU. + */ + abort(); } } diff --git a/block/throttle-groups.c b/block/throttle-groups.c index bb242fde1a..e411051160 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -895,8 +895,8 @@ static void throttle_group_set_limits(Object *obj, Visitor *v, ThrottleLimits *argp; Error *local_err = NULL; - if (!visit_type_ThrottleLimits(v, name, &argp, &local_err)) { - goto ret; + if (!visit_type_ThrottleLimits(v, name, &argp, errp)) { + return; } qemu_mutex_lock(&tg->lock); throttle_get_config(&tg->ts, &cfg); @@ -908,7 +908,6 @@ static void throttle_group_set_limits(Object *obj, Visitor *v, unlock: qemu_mutex_unlock(&tg->lock); -ret: qapi_free_ThrottleLimits(argp); error_propagate(errp, local_err); return; diff --git a/bootdevice.c b/bootdevice.c index fb09d3c668..769f40c77d 100644 --- a/bootdevice.c +++ b/bootdevice.c @@ -297,8 +297,8 @@ static void device_set_bootindex(Object *obj, Visitor *v, const char *name, int32_t boot_index; Error *local_err = NULL; - if (!visit_type_int32(v, name, &boot_index, &local_err)) { - goto out; + if (!visit_type_int32(v, name, &boot_index, errp)) { + return; } /* check whether bootindex is present in fw_boot_order list */ check_boot_index(boot_index, &local_err); diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 3cb6faa12b..4c7a8a05a5 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -761,15 +761,15 @@ static void set_pci_devfn(Object *obj, Visitor *v, const char *name, if (!visit_type_str(v, name, &str, &local_err)) { error_free(local_err); local_err = NULL; - visit_type_int32(v, name, &value, &local_err); - if (local_err) { - error_propagate(errp, local_err); - } else if (value < -1 || value > 255) { + if (!visit_type_int32(v, name, &value, errp)) { + return; + } + if (value < -1 || value > 255) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", "pci_devfn"); - } else { - *ptr = value; + return; } + *ptr = value; return; } diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 358f10a92e..ba8b0d7f02 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -245,8 +245,8 @@ static void ide_dev_set_bootindex(Object *obj, Visitor *v, const char *name, int32_t boot_index; Error *local_err = NULL; - if (!visit_type_int32(v, name, &boot_index, &local_err)) { - goto out; + if (!visit_type_int32(v, name, &boot_index, errp)) { + return; } /* check whether bootindex is present in fw_boot_order list */ check_boot_index(boot_index, &local_err); diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index ec92ffd415..1fa976c56c 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -85,21 +85,18 @@ static void nvdimm_set_uuid(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { NVDIMMDevice *nvdimm = NVDIMM(obj); - Error *local_err = NULL; char *value; - if (!visit_type_str(v, name, &value, &local_err)) { - goto out; + if (!visit_type_str(v, name, &value, errp)) { + return; } if (qemu_uuid_parse(value, &nvdimm->uuid) != 0) { error_setg(errp, "Property '%s.%s' has invalid value", object_get_typename(obj), name); } - g_free(value); -out: - error_propagate(errp, local_err); + g_free(value); } diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index 765bcd1f0b..0594abd93a 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -113,8 +113,8 @@ static void isa_ne2000_set_bootindex(Object *obj, Visitor *v, int32_t boot_index; Error *local_err = NULL; - if (!visit_type_int32(v, name, &boot_index, &local_err)) { - goto out; + if (!visit_type_int32(v, name, &boot_index, errp)) { + return; } /* check whether bootindex is present in fw_boot_order list */ check_boot_index(boot_index, &local_err); diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 1c3bd2578c..721665191e 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -736,8 +736,8 @@ static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name, int32_t boot_index; Error *local_err = NULL; - if (!visit_type_int32(v, name, &boot_index, &local_err)) { - goto out; + if (!visit_type_int32(v, name, &boot_index, errp)) { + return; } /* check whether bootindex is present in fw_boot_order list */ check_boot_index(boot_index, &local_err); diff --git a/net/net.c b/net/net.c index 94dc546fb2..6fe74c80bb 100644 --- a/net/net.c +++ b/net/net.c @@ -1062,7 +1062,6 @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) { gchar **substrings = NULL; Netdev *object = NULL; - Error *err = NULL; int ret = -1; Visitor *v = opts_visitor_new(opts); @@ -1110,16 +1109,13 @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) qemu_opts_set_id(opts, g_strdup_printf("__org.qemu.net%i", idx++)); } - visit_type_Netdev(v, NULL, &object, &err); - - if (!err) { - ret = net_client_init1(object, is_netdev, &err); + if (visit_type_Netdev(v, NULL, &object, errp)) { + ret = net_client_init1(object, is_netdev, errp); } qapi_free_Netdev(object); out: - error_propagate(errp, err); g_strfreev(substrings); visit_free(v); return ret; From 5af3a05631daffc61a12dd2c25d15876f048fdd1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:48 +0200 Subject: [PATCH 2052/2595] s390x/pci: Fix harmless mistake in zpci's property fid's setter s390_pci_set_fid() sets zpci->fid_defined to true even when visit_type_uint32() failed. Reproducer: "-device zpci,fid=junk". Harmless in practice, because qdev_device_add() then fails, throwing away @zpci. Fix it anyway. Cc: Matthew Rosato Cc: Cornelia Huck Signed-off-by: Markus Armbruster Reviewed-by: Matthew Rosato Reviewed-by: Cornelia Huck Message-Id: <20200707160613.848843-21-armbru@redhat.com> --- hw/s390x/s390-pci-bus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 9e6b170fa8..1e4537f0e3 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -1269,7 +1269,9 @@ static void s390_pci_set_fid(Object *obj, Visitor *v, const char *name, return; } - visit_type_uint32(v, name, ptr, errp); + if (!visit_type_uint32(v, name, ptr, errp)) { + return; + } zpci->fid_defined = true; } From fdb0df8798dfe6f140f4febf7a1756a44ee2080e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:49 +0200 Subject: [PATCH 2053/2595] qom: Use error_reportf_err() instead of g_printerr() in examples Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-22-armbru@redhat.com> --- include/qom/object.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 51f188137f..19c9adeebe 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -671,8 +671,7 @@ Object *object_new(const char *typename); * NULL); * * if (!obj) { - * g_printerr("Cannot create memory backend: %s\n", - * error_get_pretty(err)); + * error_reportf_err(err, "Cannot create memory backend: "); * } * * @@ -739,8 +738,7 @@ void object_apply_compat_props(Object *obj); * NULL); * * if (!obj) { - * g_printerr("Cannot set properties: %s\n", - * error_get_pretty(err)); + * error_reportf_err(err, "Cannot set properties: "); * } * * From 90c69fb9fdd71f5e615145fd1dc43cdef61737b3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:50 +0200 Subject: [PATCH 2054/2595] qom: Rename qdev_get_type() to object_get_type() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 2f262e06f0 lifted qdev_get_type() from qdev to object without renaming it accordingly. Do that now. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-23-armbru@redhat.com> --- qom/object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qom/object.c b/qom/object.c index 0213e87c86..e062ac5c82 100644 --- a/qom/object.c +++ b/qom/object.c @@ -2379,7 +2379,7 @@ object_class_property_add_tm(ObjectClass *klass, const char *name, NULL, NULL, prop); } -static char *qdev_get_type(Object *obj, Error **errp) +static char *object_get_type(Object *obj, Error **errp) { return g_strdup(object_get_typename(obj)); } @@ -2730,7 +2730,7 @@ void object_class_property_set_description(ObjectClass *klass, static void object_class_init(ObjectClass *klass, void *data) { - object_class_property_add_str(klass, "type", qdev_get_type, + object_class_property_add_str(klass, "type", object_get_type, NULL); } From 552d7f49eebdb1c84ab6dc7d93bd152fd885af31 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:51 +0200 Subject: [PATCH 2055/2595] qom: Crash more nicely on object_property_get_link() failure Pass &error_abort instead of NULL where the returned value is dereferenced or asserted to be non-null. Drop a now redundant assertion. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-24-armbru@redhat.com> --- hw/core/platform-bus.c | 6 +++--- hw/ppc/spapr_drc.c | 3 ++- hw/ppc/spapr_hcall.c | 3 ++- hw/ppc/spapr_pci_nvlink2.c | 3 ++- ui/vnc.c | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/hw/core/platform-bus.c b/hw/core/platform-bus.c index d494e5cec1..5037ca265e 100644 --- a/hw/core/platform-bus.c +++ b/hw/core/platform-bus.c @@ -22,6 +22,7 @@ #include "qemu/osdep.h" #include "hw/platform-bus.h" #include "hw/qdev-properties.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/module.h" @@ -63,9 +64,8 @@ hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev, return -1; } - parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container", NULL); - - assert(parent_mr); + parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container", + &error_abort); if (parent_mr != pbus_mr_obj) { /* MMIO region is not mapped on platform bus */ return -1; diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index d10193f39e..1f18b79348 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -870,7 +870,8 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask) continue; } - obj = object_property_get_link(root_container, prop->name, NULL); + obj = object_property_get_link(root_container, prop->name, + &error_abort); drc = SPAPR_DR_CONNECTOR(obj); drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 0f54988f2e..c1d01228c6 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1655,7 +1655,8 @@ static void spapr_handle_transient_dev_before_cas(SpaprMachineState *spapr) continue; } drc = SPAPR_DR_CONNECTOR(object_property_get_link(drc_container, - prop->name, NULL)); + prop->name, + &error_abort)); if (spapr_drc_transient(drc)) { spapr_drc_reset(drc); diff --git a/hw/ppc/spapr_pci_nvlink2.c b/hw/ppc/spapr_pci_nvlink2.c index 8332d5694e..dd8cd6db96 100644 --- a/hw/ppc/spapr_pci_nvlink2.c +++ b/hw/ppc/spapr_pci_nvlink2.c @@ -358,7 +358,8 @@ void spapr_phb_nvgpu_ram_populate_dt(SpaprPhbState *sphb, void *fdt) for (i = 0; i < sphb->nvgpus->num; ++i) { SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i]; Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev), - "nvlink2-mr[0]", NULL); + "nvlink2-mr[0]", + &error_abort); uint32_t associativity[] = { cpu_to_be32(0x4), SPAPR_GPU_NUMA_ID, diff --git a/ui/vnc.c b/ui/vnc.c index 527ad25124..f006aa1afd 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -568,7 +568,7 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp) &info->vencrypt, &info->has_vencrypt); if (vd->dcl.con) { dev = DEVICE(object_property_get_link(OBJECT(vd->dcl.con), - "device", NULL)); + "device", &error_abort)); info->has_display = true; info->display = g_strdup(dev->id); } From 4d21fcd52404ff4bac1f94d8054dfb745f1b2ad6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:52 +0200 Subject: [PATCH 2056/2595] qom: Don't handle impossible object_property_get_link() failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't handle object_property_get_link() failure that can't happen unless the programmer screwed up, pass &error_abort. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200707160613.848843-25-armbru@redhat.com> --- hw/arm/bcm2835_peripherals.c | 7 +------ hw/arm/bcm2836.c | 7 +------ hw/display/bcm2835_fb.c | 8 +------- hw/dma/bcm2835_dma.c | 9 +-------- hw/gpio/bcm2835_gpio.c | 15 ++------------- hw/intc/nios2_iic.c | 8 +------- hw/misc/bcm2835_mbox.c | 9 +-------- hw/misc/bcm2835_property.c | 17 ++--------------- hw/usb/hcd-dwc2.c | 9 +-------- 9 files changed, 11 insertions(+), 78 deletions(-) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 2df81168e4..beade39e41 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -134,12 +134,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) uint64_t ram_size, vcram_size; int n; - obj = object_property_get_link(OBJECT(dev), "ram", &err); - if (obj == NULL) { - error_setg(errp, "%s: required ram link not found: %s", - __func__, error_get_pretty(err)); - return; - } + obj = object_property_get_link(OBJECT(dev), "ram", &error_abort); ram = MEMORY_REGION(obj); ram_size = memory_region_size(ram); diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index 1a7560ef30..70ca2f0d9a 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -77,12 +77,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) /* common peripherals from bcm2835 */ - obj = object_property_get_link(OBJECT(dev), "ram", &err); - if (obj == NULL) { - error_setg(errp, "%s: required ram link not found: %s", - __func__, error_get_pretty(err)); - return; - } + obj = object_property_get_link(OBJECT(dev), "ram", &error_abort); object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj); diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c index 7c0e5eef2d..986c994522 100644 --- a/hw/display/bcm2835_fb.c +++ b/hw/display/bcm2835_fb.c @@ -405,7 +405,6 @@ static void bcm2835_fb_reset(DeviceState *dev) static void bcm2835_fb_realize(DeviceState *dev, Error **errp) { BCM2835FBState *s = BCM2835_FB(dev); - Error *err = NULL; Object *obj; if (s->vcram_base == 0) { @@ -413,12 +412,7 @@ static void bcm2835_fb_realize(DeviceState *dev, Error **errp) return; } - obj = object_property_get_link(OBJECT(dev), "dma-mr", &err); - if (obj == NULL) { - error_setg(errp, "%s: required dma-mr link not found: %s", - __func__, error_get_pretty(err)); - return; - } + obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort); /* Fill in the parts of initial_config that are not set by QOM properties */ s->initial_config.xres_virtual = s->initial_config.xres; diff --git a/hw/dma/bcm2835_dma.c b/hw/dma/bcm2835_dma.c index 4cd9dab745..eb0002a2b9 100644 --- a/hw/dma/bcm2835_dma.c +++ b/hw/dma/bcm2835_dma.c @@ -376,16 +376,9 @@ static void bcm2835_dma_reset(DeviceState *dev) static void bcm2835_dma_realize(DeviceState *dev, Error **errp) { BCM2835DMAState *s = BCM2835_DMA(dev); - Error *err = NULL; Object *obj; - obj = object_property_get_link(OBJECT(dev), "dma-mr", &err); - if (obj == NULL) { - error_setg(errp, "%s: required dma-mr link not found: %s", - __func__, error_get_pretty(err)); - return; - } - + obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort); s->dma_mr = MEMORY_REGION(obj); address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_DMA "-memory"); diff --git a/hw/gpio/bcm2835_gpio.c b/hw/gpio/bcm2835_gpio.c index 91ce3d10cc..abdddbc67c 100644 --- a/hw/gpio/bcm2835_gpio.c +++ b/hw/gpio/bcm2835_gpio.c @@ -312,22 +312,11 @@ static void bcm2835_gpio_realize(DeviceState *dev, Error **errp) { BCM2835GpioState *s = BCM2835_GPIO(dev); Object *obj; - Error *err = NULL; - obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", &err); - if (obj == NULL) { - error_setg(errp, "%s: required sdhci link not found: %s", - __func__, error_get_pretty(err)); - return; - } + obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", &error_abort); s->sdbus_sdhci = SD_BUS(obj); - obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", &err); - if (obj == NULL) { - error_setg(errp, "%s: required sdhost link not found: %s", - __func__, error_get_pretty(err)); - return; - } + obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", &error_abort); s->sdbus_sdhost = SD_BUS(obj); } diff --git a/hw/intc/nios2_iic.c b/hw/intc/nios2_iic.c index 3a5d86c2a4..1a5df8c89a 100644 --- a/hw/intc/nios2_iic.c +++ b/hw/intc/nios2_iic.c @@ -66,14 +66,8 @@ static void altera_iic_init(Object *obj) static void altera_iic_realize(DeviceState *dev, Error **errp) { struct AlteraIIC *pv = ALTERA_IIC(dev); - Error *err = NULL; - pv->cpu = object_property_get_link(OBJECT(dev), "cpu", &err); - if (!pv->cpu) { - error_setg(errp, "altera,iic: CPU link not found: %s", - error_get_pretty(err)); - return; - } + pv->cpu = object_property_get_link(OBJECT(dev), "cpu", &error_abort); } static void altera_iic_class_init(ObjectClass *klass, void *data) diff --git a/hw/misc/bcm2835_mbox.c b/hw/misc/bcm2835_mbox.c index 2afa06a746..9f73cbd5e4 100644 --- a/hw/misc/bcm2835_mbox.c +++ b/hw/misc/bcm2835_mbox.c @@ -308,15 +308,8 @@ static void bcm2835_mbox_realize(DeviceState *dev, Error **errp) { BCM2835MboxState *s = BCM2835_MBOX(dev); Object *obj; - Error *err = NULL; - - obj = object_property_get_link(OBJECT(dev), "mbox-mr", &err); - if (obj == NULL) { - error_setg(errp, "%s: required mbox-mr link not found: %s", - __func__, error_get_pretty(err)); - return; - } + obj = object_property_get_link(OBJECT(dev), "mbox-mr", &error_abort); s->mbox_mr = MEMORY_REGION(obj); address_space_init(&s->mbox_as, s->mbox_mr, TYPE_BCM2835_MBOX "-memory"); bcm2835_mbox_reset(dev); diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index 3e228ca0ae..73941bdae9 100644 --- a/hw/misc/bcm2835_property.c +++ b/hw/misc/bcm2835_property.c @@ -392,24 +392,11 @@ static void bcm2835_property_realize(DeviceState *dev, Error **errp) { BCM2835PropertyState *s = BCM2835_PROPERTY(dev); Object *obj; - Error *err = NULL; - - obj = object_property_get_link(OBJECT(dev), "fb", &err); - if (obj == NULL) { - error_setg(errp, "%s: required fb link not found: %s", - __func__, error_get_pretty(err)); - return; - } + obj = object_property_get_link(OBJECT(dev), "fb", &error_abort); s->fbdev = BCM2835_FB(obj); - obj = object_property_get_link(OBJECT(dev), "dma-mr", &err); - if (obj == NULL) { - error_setg(errp, "%s: required dma-mr link not found: %s", - __func__, error_get_pretty(err)); - return; - } - + obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort); s->dma_mr = MEMORY_REGION(obj); address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_PROPERTY "-memory"); diff --git a/hw/usb/hcd-dwc2.c b/hw/usb/hcd-dwc2.c index 72cbd051f3..56f91f6bee 100644 --- a/hw/usb/hcd-dwc2.c +++ b/hw/usb/hcd-dwc2.c @@ -1274,15 +1274,8 @@ static void dwc2_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd = SYS_BUS_DEVICE(dev); DWC2State *s = DWC2_USB(dev); Object *obj; - Error *err = NULL; - obj = object_property_get_link(OBJECT(dev), "dma-mr", &err); - if (err) { - error_setg(errp, "dwc2: required dma-mr link not found: %s", - error_get_pretty(err)); - return; - } - assert(obj != NULL); + obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort); s->dma_mr = MEMORY_REGION(obj); address_space_init(&s->dma_as, s->dma_mr, "dwc2"); From 1c94a351644fb2555f34e63c8ddc29f70bd4803a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:53 +0200 Subject: [PATCH 2057/2595] qom: Use return values to check for error where that's simpler When using the Error object to check for error, we need to receive it into a local variable, then propagate() it to @errp. Using the return value permits allows receiving it straight to @errp. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-26-armbru@redhat.com> --- qom/object.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/qom/object.c b/qom/object.c index e062ac5c82..be8fed6688 100644 --- a/qom/object.c +++ b/qom/object.c @@ -549,8 +549,7 @@ void object_initialize_child_with_propsv(Object *parentobj, object_initialize(childobj, size, type); obj = OBJECT(childobj); - object_set_propv(obj, &local_err, vargs); - if (local_err) { + if (object_set_propv(obj, errp, vargs) < 0) { goto out; } @@ -743,7 +742,7 @@ Object *object_new_with_propv(const char *typename, } obj = object_new_with_type(klass->type); - if (object_set_propv(obj, &local_err, vargs) < 0) { + if (object_set_propv(obj, errp, vargs) < 0) { goto error; } @@ -1777,20 +1776,24 @@ static void object_set_link_property(Object *obj, Visitor *v, LinkProperty *prop = opaque; Object **targetp = object_link_get_targetp(obj, prop); Object *old_target = *targetp; - Object *new_target = NULL; + Object *new_target; char *path = NULL; - visit_type_str(v, name, &path, &local_err); + if (!visit_type_str(v, name, &path, errp)) { + return; + } - if (!local_err && strcmp(path, "") != 0) { - new_target = object_resolve_link(obj, name, path, &local_err); + if (*path) { + new_target = object_resolve_link(obj, name, path, errp); + if (!new_target) { + g_free(path); + return; + } + } else { + new_target = NULL; } g_free(path); - if (local_err) { - error_propagate(errp, local_err); - return; - } prop->check(obj, name, new_target, &local_err); if (local_err) { From 5325cc34a2ca985283134c7e264be7851b112d4e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:54 +0200 Subject: [PATCH 2058/2595] qom: Put name parameter before value / visitor parameter The object_property_set_FOO() setters take property name and value in an unusual order: void object_property_set_FOO(Object *obj, FOO_TYPE value, const char *name, Error **errp) Having to pass value before name feels grating. Swap them. Same for object_property_set(), object_property_get(), and object_property_parse(). Convert callers with this Coccinelle script: @@ identifier fun = { object_property_get, object_property_parse, object_property_set_str, object_property_set_link, object_property_set_bool, object_property_set_int, object_property_set_uint, object_property_set, object_property_set_qobject }; expression obj, v, name, errp; @@ - fun(obj, v, name, errp) + fun(obj, name, v, errp) Chokes on hw/arm/musicpal.c's lcd_refresh() with the unhelpful error message "no position information". Convert that one manually. Fails to convert hw/arm/armsse.c, because Coccinelle gets confused by ARMSSE being used both as typedef and function-like macro there. Convert manually. Fails to convert hw/rx/rx-gdbsim.c, because Coccinelle gets confused by RXCPU being used both as typedef and function-like macro there. Convert manually. The other files using RXCPU that way don't need conversion. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-27-armbru@redhat.com> [Straightforwad conflict with commit 2336172d9b "audio: set default value for pcspk.iobase property" resolved] --- backends/cryptodev.c | 2 +- backends/rng.c | 2 +- bootdevice.c | 2 +- crypto/secret.c | 2 +- crypto/secret_keyring.c | 2 +- crypto/tlscredsanon.c | 2 +- crypto/tlscredspsk.c | 2 +- crypto/tlscredsx509.c | 2 +- hw/acpi/cpu_hotplug.c | 4 +- hw/acpi/ich9.c | 2 +- hw/acpi/piix4.c | 2 +- hw/arm/allwinner-a10.c | 6 +- hw/arm/armsse.c | 76 +++++++-------- hw/arm/armv7m.c | 24 +++-- hw/arm/aspeed.c | 24 ++--- hw/arm/aspeed_ast2600.c | 54 +++++------ hw/arm/aspeed_soc.c | 23 +++-- hw/arm/bcm2835_peripherals.c | 12 +-- hw/arm/bcm2836.c | 9 +- hw/arm/cubieboard.c | 6 +- hw/arm/digic.c | 2 +- hw/arm/exynos4210.c | 13 +-- hw/arm/fsl-imx25.c | 14 ++- hw/arm/fsl-imx31.c | 2 +- hw/arm/fsl-imx6.c | 37 ++++--- hw/arm/fsl-imx6ul.c | 29 +++--- hw/arm/fsl-imx7.c | 31 +++--- hw/arm/highbank.c | 12 +-- hw/arm/integratorcp.c | 2 +- hw/arm/mcimx6ul-evk.c | 4 +- hw/arm/microbit.c | 4 +- hw/arm/mps2-tz.c | 31 +++--- hw/arm/mps2.c | 12 +-- hw/arm/msf2-soc.c | 8 +- hw/arm/musca.c | 18 ++-- hw/arm/musicpal.c | 4 +- hw/arm/nrf51_soc.c | 6 +- hw/arm/orangepi.c | 13 ++- hw/arm/raspi.c | 2 +- hw/arm/realview.c | 6 +- hw/arm/sbsa-ref.c | 16 +-- hw/arm/stellaris.c | 4 +- hw/arm/stm32f205_soc.c | 8 +- hw/arm/stm32f405_soc.c | 8 +- hw/arm/versatilepb.c | 4 +- hw/arm/vexpress.c | 8 +- hw/arm/virt.c | 44 +++++---- hw/arm/xilinx_zynq.c | 6 +- hw/arm/xlnx-versal-virt.c | 8 +- hw/arm/xlnx-versal.c | 30 +++--- hw/arm/xlnx-zcu102.c | 8 +- hw/arm/xlnx-zynqmp.c | 46 ++++----- hw/block/xen-block.c | 9 +- hw/core/bus.c | 8 +- hw/core/numa.c | 4 +- hw/core/qdev-properties-system.c | 10 +- hw/core/qdev-properties.c | 20 ++-- hw/core/qdev.c | 8 +- hw/display/virtio-gpu-pci.c | 5 +- hw/display/virtio-vga.c | 5 +- hw/dma/sparc32_dma.c | 6 +- hw/dma/xilinx_axidma.c | 4 +- hw/i386/pc.c | 8 +- hw/i386/pc_piix.c | 4 +- hw/i386/pc_q35.c | 28 +++--- hw/i386/x86.c | 2 +- hw/ide/qdev.c | 2 +- hw/intc/pnv_xive.c | 9 +- hw/intc/spapr_xive.c | 9 +- hw/intc/xics.c | 4 +- hw/intc/xive.c | 4 +- hw/m68k/q800.c | 4 +- hw/mem/pc-dimm.c | 4 +- hw/microblaze/petalogix_ml605_mmu.c | 24 ++--- hw/microblaze/petalogix_s3adsp1800_mmu.c | 2 +- hw/microblaze/xlnx-zynqmp-pmu.c | 30 +++--- hw/mips/boston.c | 4 +- hw/mips/cps.c | 24 ++--- hw/mips/jazz.c | 4 +- hw/mips/malta.c | 4 +- hw/misc/iotkit-sysctl.c | 2 +- hw/misc/macio/macio.c | 6 +- hw/net/ne2000-isa.c | 2 +- hw/net/xilinx_axienet.c | 4 +- hw/pci-host/pnv_phb3.c | 20 ++-- hw/pci-host/pnv_phb4.c | 4 +- hw/pci-host/pnv_phb4_pec.c | 4 +- hw/pci-host/prep.c | 4 +- hw/ppc/mac_newworld.c | 10 +- hw/ppc/mac_oldworld.c | 4 +- hw/ppc/pnv.c | 118 +++++++++++------------ hw/ppc/pnv_psi.c | 9 +- hw/ppc/spapr.c | 4 +- hw/ppc/spapr_irq.c | 6 +- hw/ppc/spapr_pci.c | 2 +- hw/riscv/opentitan.c | 4 +- hw/riscv/sifive_e.c | 4 +- hw/riscv/sifive_u.c | 6 +- hw/riscv/spike.c | 4 +- hw/riscv/virt.c | 4 +- hw/rx/rx-gdbsim.c | 12 +-- hw/s390x/ipl.c | 4 +- hw/s390x/s390-pci-bus.c | 2 +- hw/s390x/s390-skeys.c | 2 +- hw/s390x/s390-stattrib.c | 2 +- hw/s390x/s390-virtio-ccw.c | 6 +- hw/s390x/virtio-ccw-crypto.c | 5 +- hw/s390x/virtio-ccw-rng.c | 3 +- hw/scsi/scsi-bus.c | 4 +- hw/sd/aspeed_sdhci.c | 6 +- hw/sd/ssi-sd.c | 2 +- hw/sparc/sun4m.c | 2 +- hw/sparc64/sun4u.c | 2 +- hw/usb/dev-storage.c | 4 +- hw/virtio/virtio-crypto-pci.c | 5 +- hw/virtio/virtio-iommu-pci.c | 4 +- hw/virtio/virtio-mem-pci.c | 4 +- hw/virtio/virtio-pmem-pci.c | 2 +- hw/virtio/virtio-rng-pci.c | 3 +- hw/virtio/virtio-rng.c | 4 +- include/hw/audio/pcspk.h | 2 +- include/qom/object.h | 44 ++++----- include/qom/qom-qobject.h | 7 +- linux-user/syscall.c | 2 +- net/filter.c | 2 +- net/net.c | 2 +- qdev-monitor.c | 2 +- qom/object.c | 52 +++++----- qom/object_interfaces.c | 2 +- qom/qom-hmp-cmds.c | 2 +- qom/qom-qmp-cmds.c | 2 +- qom/qom-qobject.c | 9 +- softmmu/vl.c | 12 +-- target/arm/monitor.c | 2 +- target/i386/cpu.c | 57 ++++++----- target/ppc/translate_init.inc.c | 2 +- target/s390x/cpu_models.c | 2 +- ui/console.c | 4 +- 138 files changed, 712 insertions(+), 741 deletions(-) diff --git a/backends/cryptodev.c b/backends/cryptodev.c index 7e7265102e..72b7077475 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -214,7 +214,7 @@ static void cryptodev_backend_instance_init(Object *obj) cryptodev_backend_set_queues, NULL, NULL); /* Initialize devices' queues property to 1 */ - object_property_set_int(obj, 1, "queues", NULL); + object_property_set_int(obj, "queues", 1, NULL); } static void cryptodev_backend_finalize(Object *obj) diff --git a/backends/rng.c b/backends/rng.c index 597f0ec268..484f04e891 100644 --- a/backends/rng.c +++ b/backends/rng.c @@ -48,7 +48,7 @@ static bool rng_backend_prop_get_opened(Object *obj, Error **errp) static void rng_backend_complete(UserCreatable *uc, Error **errp) { - object_property_set_bool(OBJECT(uc), true, "opened", errp); + object_property_set_bool(OBJECT(uc), "opened", true, errp); } static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp) diff --git a/bootdevice.c b/bootdevice.c index 769f40c77d..8185402a5a 100644 --- a/bootdevice.c +++ b/bootdevice.c @@ -341,7 +341,7 @@ void device_add_bootindex_property(Object *obj, int32_t *bootindex, prop); /* initialize devices' bootindex property to -1 */ - object_property_set_int(obj, -1, name, NULL); + object_property_set_int(obj, name, -1, NULL); } typedef struct FWLCHSEntry FWLCHSEntry; diff --git a/crypto/secret.c b/crypto/secret.c index 3447e2f64b..281cb81f0f 100644 --- a/crypto/secret.c +++ b/crypto/secret.c @@ -110,7 +110,7 @@ qcrypto_secret_prop_get_file(Object *obj, static void qcrypto_secret_complete(UserCreatable *uc, Error **errp) { - object_property_set_bool(OBJECT(uc), true, "loaded", errp); + object_property_set_bool(OBJECT(uc), "loaded", true, errp); } diff --git a/crypto/secret_keyring.c b/crypto/secret_keyring.c index 4f132d6370..8bfc58ebf4 100644 --- a/crypto/secret_keyring.c +++ b/crypto/secret_keyring.c @@ -105,7 +105,7 @@ qcrypto_secret_prop_get_key(Object *obj, Visitor *v, static void qcrypto_secret_keyring_complete(UserCreatable *uc, Error **errp) { - object_property_set_bool(OBJECT(uc), true, "loaded", errp); + object_property_set_bool(OBJECT(uc), "loaded", true, errp); } diff --git a/crypto/tlscredsanon.c b/crypto/tlscredsanon.c index fc078d5b97..30275b6847 100644 --- a/crypto/tlscredsanon.c +++ b/crypto/tlscredsanon.c @@ -165,7 +165,7 @@ qcrypto_tls_creds_anon_prop_get_loaded(Object *obj G_GNUC_UNUSED, static void qcrypto_tls_creds_anon_complete(UserCreatable *uc, Error **errp) { - object_property_set_bool(OBJECT(uc), true, "loaded", errp); + object_property_set_bool(OBJECT(uc), "loaded", true, errp); } diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c index f01b64d8bc..e26807b899 100644 --- a/crypto/tlscredspsk.c +++ b/crypto/tlscredspsk.c @@ -234,7 +234,7 @@ qcrypto_tls_creds_psk_prop_get_loaded(Object *obj G_GNUC_UNUSED, static void qcrypto_tls_creds_psk_complete(UserCreatable *uc, Error **errp) { - object_property_set_bool(OBJECT(uc), true, "loaded", errp); + object_property_set_bool(OBJECT(uc), "loaded", true, errp); } diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c index e337d68c4f..dd7267ccdb 100644 --- a/crypto/tlscredsx509.c +++ b/crypto/tlscredsx509.c @@ -774,7 +774,7 @@ qcrypto_tls_creds_x509_prop_get_sanity(Object *obj, static void qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp) { - object_property_set_bool(OBJECT(uc), true, "loaded", errp); + object_property_set_bool(OBJECT(uc), "loaded", true, errp); } diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c index 3e687d227a..53654f8638 100644 --- a/hw/acpi/cpu_hotplug.c +++ b/hw/acpi/cpu_hotplug.c @@ -41,7 +41,7 @@ static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data, */ if (addr == 0 && data == 0) { AcpiCpuHotplug *cpus = opaque; - object_property_set_bool(cpus->device, false, "cpu-hotplug-legacy", + object_property_set_bool(cpus->device, "cpu-hotplug-legacy", false, &error_abort); } } @@ -63,7 +63,7 @@ static void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu) cpu_id = k->get_arch_id(cpu); if ((cpu_id / 8) >= ACPI_GPE_PROC_LEN) { - object_property_set_bool(g->device, false, "cpu-hotplug-legacy", + object_property_set_bool(g->device, "cpu-hotplug-legacy", false, &error_abort); return; } diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 2d204babc6..6a19070cec 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -201,7 +201,7 @@ static int vmstate_cpuhp_pre_load(void *opaque) { ICH9LPCPMRegs *s = opaque; Object *obj = OBJECT(s->gpe_cpu.device); - object_property_set_bool(obj, false, "cpu-hotplug-legacy", &error_abort); + object_property_set_bool(obj, "cpu-hotplug-legacy", false, &error_abort); return 0; } diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 283422e0d3..26bac4f16c 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -244,7 +244,7 @@ static bool vmstate_test_use_cpuhp(void *opaque) static int vmstate_cpuhp_pre_load(void *opaque) { Object *obj = OBJECT(opaque); - object_property_set_bool(obj, false, "cpu-hotplug-legacy", &error_abort); + object_property_set_bool(obj, "cpu-hotplug-legacy", false, &error_abort); return 0; } diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index e1acffe5f6..c5d604af68 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -142,15 +142,15 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) sprintf(bus, "usb-bus.%d", i); - object_property_set_bool(OBJECT(&s->ehci[i]), true, - "companion-enable", &error_fatal); + object_property_set_bool(OBJECT(&s->ehci[i]), "companion-enable", + true, &error_fatal); sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0, AW_A10_EHCI_BASE + i * 0x8000); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0, qdev_get_gpio_in(dev, 39 + i)); - object_property_set_str(OBJECT(&s->ohci[i]), bus, "masterbus", + object_property_set_str(OBJECT(&s->ohci[i]), "masterbus", bus, &error_fatal); sysbus_realize(SYS_BUS_DEVICE(&s->ohci[i]), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci[i]), 0, diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 9a48bf86c3..1f8ce94ecc 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -534,21 +534,21 @@ static void armsse_realize(DeviceState *dev, Error **errp) * later if necessary. */ if (extract32(info->cpuwait_rst, i, 1)) { - object_property_set_bool(cpuobj, true, "start-powered-off", &err); + object_property_set_bool(cpuobj, "start-powered-off", true, &err); if (err) { error_propagate(errp, err); return; } } if (!s->cpu_fpu[i]) { - object_property_set_bool(cpuobj, false, "vfp", &err); + object_property_set_bool(cpuobj, "vfp", false, &err); if (err) { error_propagate(errp, err); return; } } if (!s->cpu_dsp[i]) { - object_property_set_bool(cpuobj, false, "dsp", &err); + object_property_set_bool(cpuobj, "dsp", false, &err); if (err) { error_propagate(errp, err); return; @@ -562,9 +562,9 @@ static void armsse_realize(DeviceState *dev, Error **errp) memory_region_add_subregion_overlap(&s->cpu_container[i], 0, &s->container, -1); } - object_property_set_link(cpuobj, OBJECT(&s->cpu_container[i]), - "memory", &error_abort); - object_property_set_link(cpuobj, OBJECT(s), "idau", &error_abort); + object_property_set_link(cpuobj, "memory", + OBJECT(&s->cpu_container[i]), &error_abort); + object_property_set_link(cpuobj, "idau", OBJECT(s), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(cpuobj), &err)) { error_propagate(errp, err); return; @@ -604,8 +604,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) DeviceState *devs = DEVICE(splitter); int cpunum; - object_property_set_int(splitter, info->num_cpus, - "num-lines", &err); + object_property_set_int(splitter, "num-lines", info->num_cpus, + &err); if (err) { error_propagate(errp, err); return; @@ -658,8 +658,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) * multiple lines, one for each of the PPCs within the ARMSSE and one * that will be an output from the ARMSSE to the system. */ - object_property_set_int(OBJECT(&s->sec_resp_splitter), 3, - "num-lines", &err); + object_property_set_int(OBJECT(&s->sec_resp_splitter), "num-lines", 3, + &err); if (err) { error_propagate(errp, err); return; @@ -685,8 +685,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_link(OBJECT(&s->mpc[i]), OBJECT(&s->sram[i]), - "downstream", &error_abort); + object_property_set_link(OBJECT(&s->mpc[i]), "downstream", + OBJECT(&s->sram[i]), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->mpc[i]), &err)) { error_propagate(errp, err); return; @@ -702,9 +702,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) } /* We must OR together lines from the MPC splitters to go to the NVIC */ - object_property_set_int(OBJECT(&s->mpc_irq_orgate), - IOTS_NUM_EXP_MPC + info->sram_banks, - "num-lines", &err); + object_property_set_int(OBJECT(&s->mpc_irq_orgate), "num-lines", + IOTS_NUM_EXP_MPC + info->sram_banks, &err); if (err) { error_propagate(errp, err); return; @@ -734,7 +733,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer0), 0, armsse_get_common_irq_in(s, 3)); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer0), 0); - object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[0]", + object_property_set_link(OBJECT(&s->apb_ppc0), "port[0]", OBJECT(mr), &error_abort); qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq); @@ -745,7 +744,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer1), 0, armsse_get_common_irq_in(s, 4)); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer1), 0); - object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[1]", + object_property_set_link(OBJECT(&s->apb_ppc0), "port[1]", OBJECT(mr), &error_abort); qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq); @@ -756,7 +755,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0, armsse_get_common_irq_in(s, 5)); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0); - object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", + object_property_set_link(OBJECT(&s->apb_ppc0), "port[2]", OBJECT(mr), &error_abort); if (info->has_mhus) { @@ -780,8 +779,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) } port = g_strdup_printf("port[%d]", i + 3); mr = sysbus_mmio_get_region(mhu_sbd, 0); - object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), - port, &error_abort); + object_property_set_link(OBJECT(&s->apb_ppc0), port, OBJECT(mr), + &error_abort); g_free(port); /* @@ -842,8 +841,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) * ones) are sent individually to the security controller, and also * ORed together to give a single combined PPC interrupt to the NVIC. */ - object_property_set_int(OBJECT(&s->ppc_irq_orgate), - NUM_PPCS, "num-lines", &err); + object_property_set_int(OBJECT(&s->ppc_irq_orgate), "num-lines", NUM_PPCS, + &err); if (err) { error_propagate(errp, err); return; @@ -923,7 +922,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0, armsse_get_common_irq_in(s, 2)); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0); - object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", + object_property_set_link(OBJECT(&s->apb_ppc1), "port[0]", OBJECT(mr), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc1), &err)) { @@ -950,15 +949,14 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in_named(dev_apb_ppc1, "cfg_sec_resp", 0)); - object_property_set_int(OBJECT(&s->sysinfo), info->sys_version, - "SYS_VERSION", &err); + object_property_set_int(OBJECT(&s->sysinfo), "SYS_VERSION", + info->sys_version, &err); if (err) { error_propagate(errp, err); return; } - object_property_set_int(OBJECT(&s->sysinfo), - armsse_sys_config_value(s, info), - "SYS_CONFIG", &err); + object_property_set_int(OBJECT(&s->sysinfo), "SYS_CONFIG", + armsse_sys_config_value(s, info), &err); if (err) { error_propagate(errp, err); return; @@ -970,14 +968,14 @@ static void armsse_realize(DeviceState *dev, Error **errp) /* System information registers */ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000); /* System control registers */ - object_property_set_int(OBJECT(&s->sysctl), info->sys_version, - "SYS_VERSION", &error_abort); - object_property_set_int(OBJECT(&s->sysctl), info->cpuwait_rst, - "CPUWAIT_RST", &error_abort); - object_property_set_int(OBJECT(&s->sysctl), s->init_svtor, - "INITSVTOR0_RST", &error_abort); - object_property_set_int(OBJECT(&s->sysctl), s->init_svtor, - "INITSVTOR1_RST", &error_abort); + object_property_set_int(OBJECT(&s->sysctl), "SYS_VERSION", + info->sys_version, &error_abort); + object_property_set_int(OBJECT(&s->sysctl), "CPUWAIT_RST", + info->cpuwait_rst, &error_abort); + object_property_set_int(OBJECT(&s->sysctl), "INITSVTOR0_RST", + s->init_svtor, &error_abort); + object_property_set_int(OBJECT(&s->sysctl), "INITSVTOR1_RST", + s->init_svtor, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysctl), &err)) { error_propagate(errp, err); return; @@ -1007,7 +1005,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) } /* This OR gate wires together outputs from the secure watchdogs to NMI */ - object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err); + object_property_set_int(OBJECT(&s->nmi_orgate), "num-lines", 2, &err); if (err) { error_propagate(errp, err); return; @@ -1051,7 +1049,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) { Object *splitter = OBJECT(&s->ppc_irq_splitter[i]); - object_property_set_int(splitter, 2, "num-lines", &err); + object_property_set_int(splitter, "num-lines", 2, &err); if (err) { error_propagate(errp, err); return; @@ -1097,7 +1095,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) SplitIRQ *splitter = &s->mpc_irq_splitter[i]; DeviceState *dev_splitter = DEVICE(splitter); - object_property_set_int(OBJECT(splitter), 2, "num-lines", &err); + object_property_set_int(OBJECT(splitter), "num-lines", 2, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 28baf330e5..923f7fad40 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -167,39 +167,37 @@ static void armv7m_realize(DeviceState *dev, Error **errp) return; } - object_property_set_link(OBJECT(s->cpu), OBJECT(&s->container), "memory", + object_property_set_link(OBJECT(s->cpu), "memory", OBJECT(&s->container), &error_abort); if (object_property_find(OBJECT(s->cpu), "idau", NULL)) { - object_property_set_link(OBJECT(s->cpu), s->idau, "idau", + object_property_set_link(OBJECT(s->cpu), "idau", s->idau, &error_abort); } if (object_property_find(OBJECT(s->cpu), "init-svtor", NULL)) { - object_property_set_uint(OBJECT(s->cpu), s->init_svtor, - "init-svtor", &err); + object_property_set_uint(OBJECT(s->cpu), "init-svtor", s->init_svtor, + &err); if (err != NULL) { error_propagate(errp, err); return; } } if (object_property_find(OBJECT(s->cpu), "start-powered-off", NULL)) { - object_property_set_bool(OBJECT(s->cpu), s->start_powered_off, - "start-powered-off", &err); + object_property_set_bool(OBJECT(s->cpu), "start-powered-off", + s->start_powered_off, &err); if (err != NULL) { error_propagate(errp, err); return; } } if (object_property_find(OBJECT(s->cpu), "vfp", NULL)) { - object_property_set_bool(OBJECT(s->cpu), s->vfp, - "vfp", &err); + object_property_set_bool(OBJECT(s->cpu), "vfp", s->vfp, &err); if (err != NULL) { error_propagate(errp, err); return; } } if (object_property_find(OBJECT(s->cpu), "dsp", NULL)) { - object_property_set_bool(OBJECT(s->cpu), s->dsp, - "dsp", &err); + object_property_set_bool(OBJECT(s->cpu), "dsp", s->dsp, &err); if (err != NULL) { error_propagate(errp, err); return; @@ -245,13 +243,13 @@ static void armv7m_realize(DeviceState *dev, Error **errp) Object *obj = OBJECT(&s->bitband[i]); SysBusDevice *sbd = SYS_BUS_DEVICE(&s->bitband[i]); - object_property_set_int(obj, bitband_input_addr[i], "base", &err); + object_property_set_int(obj, "base", bitband_input_addr[i], &err); if (err != NULL) { error_propagate(errp, err); return; } - object_property_set_link(obj, OBJECT(s->board_memory), - "source-memory", &error_abort); + object_property_set_link(obj, "source-memory", + OBJECT(s->board_memory), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(obj), &err)) { error_propagate(errp, err); return; diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 379f9672a5..660dcb5414 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -277,7 +277,7 @@ static void aspeed_machine_init(MachineState *machine) /* * This will error out if isize is not supported by memory controller. */ - object_property_set_uint(OBJECT(&bmc->soc), ram_size, "ram-size", + object_property_set_uint(OBJECT(&bmc->soc), "ram-size", ram_size, &error_fatal); for (i = 0; i < sc->macs_num; i++) { @@ -288,22 +288,22 @@ static void aspeed_machine_init(MachineState *machine) } } - object_property_set_int(OBJECT(&bmc->soc), amc->hw_strap1, "hw-strap1", + object_property_set_int(OBJECT(&bmc->soc), "hw-strap1", amc->hw_strap1, &error_abort); - object_property_set_int(OBJECT(&bmc->soc), amc->hw_strap2, "hw-strap2", + object_property_set_int(OBJECT(&bmc->soc), "hw-strap2", amc->hw_strap2, &error_abort); - object_property_set_int(OBJECT(&bmc->soc), amc->num_cs, "num-cs", + object_property_set_int(OBJECT(&bmc->soc), "num-cs", amc->num_cs, &error_abort); - object_property_set_link(OBJECT(&bmc->soc), OBJECT(&bmc->ram_container), - "dram", &error_abort); + object_property_set_link(OBJECT(&bmc->soc), "dram", + OBJECT(&bmc->ram_container), &error_abort); if (machine->kernel_filename) { /* * When booting with a -kernel command line there is no u-boot * that runs to unlock the SCU. In this case set the default to * be unlocked as the kernel expects */ - object_property_set_int(OBJECT(&bmc->soc), ASPEED_SCU_PROT_KEY, - "hw-prot-key", &error_abort); + object_property_set_int(OBJECT(&bmc->soc), "hw-prot-key", + ASPEED_SCU_PROT_KEY, &error_abort); } qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort); @@ -393,10 +393,10 @@ static void palmetto_bmc_i2c_init(AspeedMachineState *bmc) /* add a TMP423 temperature sensor */ dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2), "tmp423", 0x4c); - object_property_set_int(OBJECT(dev), 31000, "temperature0", &error_abort); - object_property_set_int(OBJECT(dev), 28000, "temperature1", &error_abort); - object_property_set_int(OBJECT(dev), 20000, "temperature2", &error_abort); - object_property_set_int(OBJECT(dev), 110000, "temperature3", &error_abort); + object_property_set_int(OBJECT(dev), "temperature0", 31000, &error_abort); + object_property_set_int(OBJECT(dev), "temperature1", 28000, &error_abort); + object_property_set_int(OBJECT(dev), "temperature2", 20000, &error_abort); + object_property_set_int(OBJECT(dev), "temperature3", 110000, &error_abort); } static void ast2500_evb_i2c_init(AspeedMachineState *bmc) diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index b9ae4c12b4..e6e2cf0737 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -196,7 +196,7 @@ static void aspeed_soc_ast2600_init(Object *obj) object_initialize_child(obj, "sd-controller", &s->sdhci, TYPE_ASPEED_SDHCI); - object_property_set_int(OBJECT(&s->sdhci), 2, "num-slots", &error_abort); + object_property_set_int(OBJECT(&s->sdhci), "num-slots", 2, &error_abort); /* Init sd card slot class here so that they're under the correct parent */ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { @@ -207,7 +207,7 @@ static void aspeed_soc_ast2600_init(Object *obj) object_initialize_child(obj, "emmc-controller", &s->emmc, TYPE_ASPEED_SDHCI); - object_property_set_int(OBJECT(&s->emmc), 1, "num-slots", &error_abort); + object_property_set_int(OBJECT(&s->emmc), "num-slots", 1, &error_abort); object_initialize_child(obj, "emmc-controller.sdhci", &s->emmc.slots[0], TYPE_SYSBUS_SDHCI); @@ -241,17 +241,16 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* CPU */ for (i = 0; i < sc->num_cpus; i++) { - object_property_set_int(OBJECT(&s->cpu[i]), QEMU_PSCI_CONDUIT_SMC, - "psci-conduit", &error_abort); + object_property_set_int(OBJECT(&s->cpu[i]), "psci-conduit", + QEMU_PSCI_CONDUIT_SMC, &error_abort); if (sc->num_cpus > 1) { - object_property_set_int(OBJECT(&s->cpu[i]), - ASPEED_A7MPCORE_ADDR, - "reset-cbar", &error_abort); + object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar", + ASPEED_A7MPCORE_ADDR, &error_abort); } - object_property_set_int(OBJECT(&s->cpu[i]), aspeed_calc_affinity(i), - "mp-affinity", &error_abort); + object_property_set_int(OBJECT(&s->cpu[i]), "mp-affinity", + aspeed_calc_affinity(i), &error_abort); - object_property_set_int(OBJECT(&s->cpu[i]), 1125000000, "cntfrq", + object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 1125000000, &error_abort); /* @@ -266,11 +265,11 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* A7MPCORE */ - object_property_set_int(OBJECT(&s->a7mpcore), sc->num_cpus, "num-cpu", + object_property_set_int(OBJECT(&s->a7mpcore), "num-cpu", sc->num_cpus, &error_abort); - object_property_set_int(OBJECT(&s->a7mpcore), + object_property_set_int(OBJECT(&s->a7mpcore), "num-irq", ASPEED_SOC_AST2600_MAX_IRQ + GIC_INTERNAL, - "num-irq", &error_abort); + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->a7mpcore), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, ASPEED_A7MPCORE_ADDR); @@ -316,8 +315,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_RTC)); /* Timer */ - object_property_set_link(OBJECT(&s->timerctrl), - OBJECT(&s->scu), "scu", &error_abort); + object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu), + &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), &err)) { error_propagate(errp, err); return; @@ -337,7 +336,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* I2C */ - object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", + object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err)) { error_propagate(errp, err); @@ -355,10 +354,10 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* FMC, The number of CS is set at the board level */ - object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram", + object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), &error_abort); - object_property_set_int(OBJECT(&s->fmc), sc->memmap[ASPEED_SDRAM], - "sdram-base", &err); + object_property_set_int(OBJECT(&s->fmc), "sdram-base", + sc->memmap[ASPEED_SDRAM], &err); if (err) { error_propagate(errp, err); return; @@ -375,10 +374,9 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* SPI */ for (i = 0; i < sc->spis_num; i++) { - object_property_set_link(OBJECT(&s->spi[i]), OBJECT(s->dram_mr), - "dram", &error_abort); - object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", - &error_abort); + object_property_set_link(OBJECT(&s->spi[i]), "dram", + OBJECT(s->dram_mr), &error_abort); + object_property_set_int(OBJECT(&s->spi[i]), "num-cs", 1, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { error_propagate(errp, err); return; @@ -412,8 +410,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->wdts_num; i++) { AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]); - object_property_set_link(OBJECT(&s->wdt[i]), - OBJECT(&s->scu), "scu", &error_abort); + object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu), + &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &err)) { error_propagate(errp, err); return; @@ -424,7 +422,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* Net */ for (i = 0; i < sc->macs_num; i++) { - object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", + object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err)) { error_propagate(errp, err); @@ -435,8 +433,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, aspeed_soc_get_irq(s, ASPEED_ETH1 + i)); - object_property_set_link(OBJECT(&s->mii[i]), OBJECT(&s->ftgmac100[i]), - "nic", &error_abort); + object_property_set_link(OBJECT(&s->mii[i]), "nic", + OBJECT(&s->ftgmac100[i]), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->mii[i]), &err)) { error_propagate(errp, err); return; diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index fa56f96f92..27704d87ea 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -204,7 +204,7 @@ static void aspeed_soc_init(Object *obj) object_initialize_child(obj, "sdc", &s->sdhci, TYPE_ASPEED_SDHCI); - object_property_set_int(OBJECT(&s->sdhci), 2, "num-slots", &error_abort); + object_property_set_int(OBJECT(&s->sdhci), "num-slots", 2, &error_abort); /* Init sd card slot class here so that they're under the correct parent */ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { @@ -274,8 +274,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_RTC)); /* Timer */ - object_property_set_link(OBJECT(&s->timerctrl), - OBJECT(&s->scu), "scu", &error_abort); + object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu), + &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), &err)) { error_propagate(errp, err); return; @@ -295,7 +295,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } /* I2C */ - object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", + object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err)) { error_propagate(errp, err); @@ -306,10 +306,10 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_I2C)); /* FMC, The number of CS is set at the board level */ - object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram", + object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), &error_abort); - object_property_set_int(OBJECT(&s->fmc), sc->memmap[ASPEED_SDRAM], - "sdram-base", &err); + object_property_set_int(OBJECT(&s->fmc), "sdram-base", + sc->memmap[ASPEED_SDRAM], &err); if (err) { error_propagate(errp, err); return; @@ -326,8 +326,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* SPI */ for (i = 0; i < sc->spis_num; i++) { - object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", - &error_abort); + object_property_set_int(OBJECT(&s->spi[i]), "num-cs", 1, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { error_propagate(errp, err); return; @@ -361,8 +360,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->wdts_num; i++) { AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]); - object_property_set_link(OBJECT(&s->wdt[i]), - OBJECT(&s->scu), "scu", &error_abort); + object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu), + &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &err)) { error_propagate(errp, err); return; @@ -373,7 +372,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* Net */ for (i = 0; i < sc->macs_num; i++) { - object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", + object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err)) { error_propagate(errp, err); diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index beade39e41..a6ccf3b368 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -222,8 +222,8 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) return; } - object_property_set_uint(OBJECT(&s->fb), ram_size - vcram_size, - "vcram-base", &err); + object_property_set_uint(OBJECT(&s->fb), "vcram-base", + ram_size - vcram_size, &err); if (err) { error_propagate(errp, err); return; @@ -270,11 +270,11 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) * For the exact details please refer to the Arasan documentation: * SD3.0_Host_AHB_eMMC4.4_Usersguide_ver5.9_jan11_10.pdf */ - object_property_set_uint(OBJECT(&s->sdhci), 3, "sd-spec-version", + object_property_set_uint(OBJECT(&s->sdhci), "sd-spec-version", 3, &error_abort); - object_property_set_uint(OBJECT(&s->sdhci), BCM2835_SDHC_CAPAREG, "capareg", - &error_abort); - object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk", + object_property_set_uint(OBJECT(&s->sdhci), "capareg", + BCM2835_SDHC_CAPAREG, &error_abort); + object_property_set_bool(OBJECT(&s->sdhci), "pending-insert-quirk", true, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err)) { error_propagate(errp, err); diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index 70ca2f0d9a..91d31a5cb7 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -110,17 +110,16 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) s->cpu[n].core.mp_affinity = (info->clusterid << 8) | n; /* set periphbase/CBAR value for CPU-local registers */ - object_property_set_int(OBJECT(&s->cpu[n].core), - info->peri_base, - "reset-cbar", &err); + object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar", + info->peri_base, &err); if (err) { error_propagate(errp, err); return; } /* start powered off if not enabled */ - object_property_set_bool(OBJECT(&s->cpu[n].core), n >= s->enabled_cpus, - "start-powered-off", &err); + object_property_set_bool(OBJECT(&s->cpu[n].core), "start-powered-off", + n >= s->enabled_cpus, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index c720e24ced..302919246b 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -62,19 +62,19 @@ static void cubieboard_init(MachineState *machine) object_property_add_child(OBJECT(machine), "soc", OBJECT(a10)); object_unref(OBJECT(a10)); - object_property_set_int(OBJECT(&a10->emac), 1, "phy-addr", &err); + object_property_set_int(OBJECT(&a10->emac), "phy-addr", 1, &err); if (err != NULL) { error_reportf_err(err, "Couldn't set phy address: "); exit(1); } - object_property_set_int(OBJECT(&a10->timer), 32768, "clk0-freq", &err); + object_property_set_int(OBJECT(&a10->timer), "clk0-freq", 32768, &err); if (err != NULL) { error_reportf_err(err, "Couldn't set clk0 frequency: "); exit(1); } - object_property_set_int(OBJECT(&a10->timer), 24000000, "clk1-freq", &err); + object_property_set_int(OBJECT(&a10->timer), "clk1-freq", 24000000, &err); if (err != NULL) { error_reportf_err(err, "Couldn't set clk1 frequency: "); exit(1); diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 1494c2900a..ffc89d86b8 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -56,7 +56,7 @@ static void digic_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd; int i; - object_property_set_bool(OBJECT(&s->cpu), true, "reset-hivecs", &err); + object_property_set_bool(OBJECT(&s->cpu), "reset-hivecs", true, &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index fa639806ec..081bbff317 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -188,7 +188,7 @@ static DeviceState *pl330_create(uint32_t base, qemu_or_irq *orgate, sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, base); - object_property_set_int(OBJECT(orgate), nevents + 1, "num-lines", + object_property_set_int(OBJECT(orgate), "num-lines", nevents + 1, &error_abort); qdev_realize(DEVICE(orgate), NULL, &error_abort); @@ -215,14 +215,15 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) * support EL3 so the CPU EL3 property is disabled before realization. */ if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); + object_property_set_bool(cpuobj, "has_el3", false, &error_fatal); } s->cpu[n] = ARM_CPU(cpuobj); - object_property_set_int(cpuobj, exynos4210_calc_affinity(n), - "mp-affinity", &error_abort); - object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR, - "reset-cbar", &error_abort); + object_property_set_int(cpuobj, "mp-affinity", + exynos4210_calc_affinity(n), &error_abort); + object_property_set_int(cpuobj, "reset-cbar", + EXYNOS4210_SMP_PRIVATE_BASE_ADDR, + &error_abort); qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); } diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index 250681f045..ea72a02d06 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -249,14 +249,12 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) { FSL_IMX25_ESDHC2_ADDR, FSL_IMX25_ESDHC2_IRQ }, }; - object_property_set_uint(OBJECT(&s->esdhc[i]), 2, "sd-spec-version", - &error_abort); - object_property_set_uint(OBJECT(&s->esdhc[i]), IMX25_ESDHC_CAPABILITIES, - "capareg", - &error_abort); - object_property_set_uint(OBJECT(&s->esdhc[i]), SDHCI_VENDOR_IMX, - "vendor", + object_property_set_uint(OBJECT(&s->esdhc[i]), "sd-spec-version", 2, &error_abort); + object_property_set_uint(OBJECT(&s->esdhc[i]), "capareg", + IMX25_ESDHC_CAPABILITIES, &error_abort); + object_property_set_uint(OBJECT(&s->esdhc[i]), "vendor", + SDHCI_VENDOR_IMX, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err)) { error_propagate(errp, err); return; @@ -285,7 +283,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) } /* Watchdog */ - object_property_set_bool(OBJECT(&s->wdt), true, "pretimeout-support", + object_property_set_bool(OBJECT(&s->wdt), "pretimeout-support", true, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, FSL_IMX25_WDT_ADDR); diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index 4f007ea5e8..23a5f50175 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -179,7 +179,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) { FSL_IMX31_GPIO3_ADDR, FSL_IMX31_GPIO3_IRQ } }; - object_property_set_bool(OBJECT(&s->gpio[i]), false, "has-edge-sel", + object_property_set_bool(OBJECT(&s->gpio[i]), "has-edge-sel", false, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err)) { error_propagate(errp, err); diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 417ca6889c..e359ee579d 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -120,14 +120,14 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) /* On uniprocessor, the CBAR is set to 0 */ if (smp_cpus > 1) { - object_property_set_int(OBJECT(&s->cpu[i]), FSL_IMX6_A9MPCORE_ADDR, - "reset-cbar", &error_abort); + object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar", + FSL_IMX6_A9MPCORE_ADDR, &error_abort); } /* All CPU but CPU 0 start in power off mode */ if (i) { - object_property_set_bool(OBJECT(&s->cpu[i]), true, - "start-powered-off", &error_abort); + object_property_set_bool(OBJECT(&s->cpu[i]), "start-powered-off", + true, &error_abort); } if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, &err)) { @@ -136,12 +136,11 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) } } - object_property_set_int(OBJECT(&s->a9mpcore), smp_cpus, "num-cpu", + object_property_set_int(OBJECT(&s->a9mpcore), "num-cpu", smp_cpus, &error_abort); - object_property_set_int(OBJECT(&s->a9mpcore), - FSL_IMX6_MAX_IRQ + GIC_INTERNAL, "num-irq", - &error_abort); + object_property_set_int(OBJECT(&s->a9mpcore), "num-irq", + FSL_IMX6_MAX_IRQ + GIC_INTERNAL, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->a9mpcore), &err)) { error_propagate(errp, err); @@ -295,10 +294,10 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) }, }; - object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-edge-sel", - &error_abort); - object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-upper-pin-irq", + object_property_set_bool(OBJECT(&s->gpio[i]), "has-edge-sel", true, &error_abort); + object_property_set_bool(OBJECT(&s->gpio[i]), "has-upper-pin-irq", + true, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err)) { error_propagate(errp, err); return; @@ -326,14 +325,12 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) }; /* UHS-I SDIO3.0 SDR104 1.8V ADMA */ - object_property_set_uint(OBJECT(&s->esdhc[i]), 3, "sd-spec-version", - &error_abort); - object_property_set_uint(OBJECT(&s->esdhc[i]), IMX6_ESDHC_CAPABILITIES, - "capareg", - &error_abort); - object_property_set_uint(OBJECT(&s->esdhc[i]), SDHCI_VENDOR_IMX, - "vendor", + object_property_set_uint(OBJECT(&s->esdhc[i]), "sd-spec-version", 3, &error_abort); + object_property_set_uint(OBJECT(&s->esdhc[i]), "capareg", + IMX6_ESDHC_CAPABILITIES, &error_abort); + object_property_set_uint(OBJECT(&s->esdhc[i]), "vendor", + SDHCI_VENDOR_IMX, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err)) { error_propagate(errp, err); return; @@ -417,8 +414,8 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) FSL_IMX6_WDOG2_IRQ, }; - object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support", - &error_abort); + object_property_set_bool(OBJECT(&s->wdt[i]), "pretimeout-support", + true, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX6_WDOGn_ADDR[i]); diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index 51b2f256ec..e0128d7316 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -166,17 +166,16 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) return; } - object_property_set_int(OBJECT(&s->cpu), QEMU_PSCI_CONDUIT_SMC, - "psci-conduit", &error_abort); + object_property_set_int(OBJECT(&s->cpu), "psci-conduit", + QEMU_PSCI_CONDUIT_SMC, &error_abort); qdev_realize(DEVICE(&s->cpu), NULL, &error_abort); /* * A7MPCORE */ - object_property_set_int(OBJECT(&s->a7mpcore), 1, "num-cpu", &error_abort); - object_property_set_int(OBJECT(&s->a7mpcore), - FSL_IMX6UL_MAX_IRQ + GIC_INTERNAL, - "num-irq", &error_abort); + object_property_set_int(OBJECT(&s->a7mpcore), "num-cpu", 1, &error_abort); + object_property_set_int(OBJECT(&s->a7mpcore), "num-irq", + FSL_IMX6UL_MAX_IRQ + GIC_INTERNAL, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->a7mpcore), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, FSL_IMX6UL_A7MPCORE_ADDR); @@ -427,12 +426,10 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_ENET2_TIMER_IRQ, }; - object_property_set_uint(OBJECT(&s->eth[i]), - s->phy_num[i], - "phy-num", &error_abort); - object_property_set_uint(OBJECT(&s->eth[i]), - FSL_IMX6UL_ETH_NUM_TX_RINGS, - "tx-ring-num", &error_abort); + object_property_set_uint(OBJECT(&s->eth[i]), "phy-num", + s->phy_num[i], &error_abort); + object_property_set_uint(OBJECT(&s->eth[i]), "tx-ring-num", + FSL_IMX6UL_ETH_NUM_TX_RINGS, &error_abort); qdev_set_nic_properties(DEVICE(&s->eth[i]), &nd_table[i]); sysbus_realize(SYS_BUS_DEVICE(&s->eth[i]), &error_abort); @@ -482,8 +479,8 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_USDHC2_IRQ, }; - object_property_set_uint(OBJECT(&s->usdhc[i]), SDHCI_VENDOR_IMX, - "vendor", &error_abort); + object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor", + SDHCI_VENDOR_IMX, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, @@ -515,8 +512,8 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_WDOG3_IRQ, }; - object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support", - &error_abort); + object_property_set_bool(OBJECT(&s->wdt[i]), "pretimeout-support", + true, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index b49d895a41..fad637d328 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -159,19 +159,19 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) for (i = 0; i < smp_cpus; i++) { o = OBJECT(&s->cpu[i]); - object_property_set_int(o, QEMU_PSCI_CONDUIT_SMC, - "psci-conduit", &error_abort); + object_property_set_int(o, "psci-conduit", QEMU_PSCI_CONDUIT_SMC, + &error_abort); /* On uniprocessor, the CBAR is set to 0 */ if (smp_cpus > 1) { - object_property_set_int(o, FSL_IMX7_A7MPCORE_ADDR, - "reset-cbar", &error_abort); + object_property_set_int(o, "reset-cbar", FSL_IMX7_A7MPCORE_ADDR, + &error_abort); } if (i) { /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(o, true, - "start-powered-off", &error_abort); + object_property_set_bool(o, "start-powered-off", true, + &error_abort); } qdev_realize(DEVICE(o), NULL, &error_abort); @@ -180,11 +180,10 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) /* * A7MPCORE */ - object_property_set_int(OBJECT(&s->a7mpcore), smp_cpus, "num-cpu", + object_property_set_int(OBJECT(&s->a7mpcore), "num-cpu", smp_cpus, &error_abort); - object_property_set_int(OBJECT(&s->a7mpcore), - FSL_IMX7_MAX_IRQ + GIC_INTERNAL, - "num-irq", &error_abort); + object_property_set_int(OBJECT(&s->a7mpcore), "num-irq", + FSL_IMX7_MAX_IRQ + GIC_INTERNAL, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->a7mpcore), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, FSL_IMX7_A7MPCORE_ADDR); @@ -364,8 +363,8 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_ENET2_ADDR, }; - object_property_set_uint(OBJECT(&s->eth[i]), FSL_IMX7_ETH_NUM_TX_RINGS, - "tx-ring-num", &error_abort); + object_property_set_uint(OBJECT(&s->eth[i]), "tx-ring-num", + FSL_IMX7_ETH_NUM_TX_RINGS, &error_abort); qdev_set_nic_properties(DEVICE(&s->eth[i]), &nd_table[i]); sysbus_realize(SYS_BUS_DEVICE(&s->eth[i]), &error_abort); @@ -393,8 +392,8 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_USDHC3_IRQ, }; - object_property_set_uint(OBJECT(&s->usdhc[i]), SDHCI_VENDOR_IMX, - "vendor", &error_abort); + object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor", + SDHCI_VENDOR_IMX, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, @@ -432,8 +431,8 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_WDOG4_IRQ, }; - object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support", - &error_abort); + object_property_set_bool(OBJECT(&s->wdt[i]), "pretimeout-support", + true, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX7_WDOGn_ADDR[i]); diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index c7ef48ecde..c96f2ab9cf 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -267,18 +267,18 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) cpuobj = object_new(machine->cpu_type); cpu = ARM_CPU(cpuobj); - object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_SMC, - "psci-conduit", &error_abort); + object_property_set_int(cpuobj, "psci-conduit", QEMU_PSCI_CONDUIT_SMC, + &error_abort); if (n) { /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(cpuobj, true, - "start-powered-off", &error_abort); + object_property_set_bool(cpuobj, "start-powered-off", true, + &error_abort); } if (object_property_find(cpuobj, "reset-cbar", NULL)) { - object_property_set_int(cpuobj, MPCORE_PERIPHBASE, - "reset-cbar", &error_abort); + object_property_set_int(cpuobj, "reset-cbar", MPCORE_PERIPHBASE, + &error_abort); } qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ); diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index b11a846355..f304c2b4f0 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -604,7 +604,7 @@ static void integratorcp_init(MachineState *machine) * realization. */ if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); + object_property_set_bool(cpuobj, "has_el3", false, &error_fatal); } qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c index 9033d3f8f3..ed69a7b037 100644 --- a/hw/arm/mcimx6ul-evk.c +++ b/hw/arm/mcimx6ul-evk.c @@ -40,8 +40,8 @@ static void mcimx6ul_evk_init(MachineState *machine) s = FSL_IMX6UL(object_new(TYPE_FSL_IMX6UL)); object_property_add_child(OBJECT(machine), "soc", OBJECT(s)); - object_property_set_uint(OBJECT(s), 2, "fec1-phy-num", &error_fatal); - object_property_set_uint(OBJECT(s), 1, "fec2-phy-num", &error_fatal); + object_property_set_uint(OBJECT(s), "fec1-phy-num", 2, &error_fatal); + object_property_set_uint(OBJECT(s), "fec2-phy-num", 1, &error_fatal); qdev_realize(DEVICE(s), NULL, &error_fatal); memory_region_add_subregion(get_system_memory(), FSL_IMX6UL_MMDC_ADDR, diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c index 8fe42c9d6a..a91acab1cb 100644 --- a/hw/arm/microbit.c +++ b/hw/arm/microbit.c @@ -40,8 +40,8 @@ static void microbit_init(MachineState *machine) object_initialize_child(OBJECT(machine), "nrf51", &s->nrf51, TYPE_NRF51_SOC); qdev_prop_set_chr(DEVICE(&s->nrf51), "serial0", serial_hd(0)); - object_property_set_link(OBJECT(&s->nrf51), OBJECT(system_memory), - "memory", &error_fatal); + object_property_set_link(OBJECT(&s->nrf51), "memory", + OBJECT(system_memory), &error_fatal); sysbus_realize(SYS_BUS_DEVICE(&s->nrf51), &error_fatal); /* diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index a4fd5ddede..28d9e8bfac 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -265,8 +265,8 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque, memory_region_init_ram(ssram, NULL, name, ramsize[i], &error_fatal); object_initialize_child(OBJECT(mms), mpcname, mpc, TYPE_TZ_MPC); - object_property_set_link(OBJECT(mpc), OBJECT(ssram), - "downstream", &error_fatal); + object_property_set_link(OBJECT(mpc), "downstream", OBJECT(ssram), + &error_fatal); sysbus_realize(SYS_BUS_DEVICE(mpc), &error_fatal); /* Map the upstream end of the MPC into system memory */ upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1); @@ -308,10 +308,9 @@ static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque, */ object_initialize_child(OBJECT(mms), mscname, msc, TYPE_TZ_MSC); msc_downstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(&mms->iotkit), 0); - object_property_set_link(OBJECT(msc), OBJECT(msc_downstream), - "downstream", &error_fatal); - object_property_set_link(OBJECT(msc), OBJECT(mms), - "idau", &error_fatal); + object_property_set_link(OBJECT(msc), "downstream", + OBJECT(msc_downstream), &error_fatal); + object_property_set_link(OBJECT(msc), "idau", OBJECT(mms), &error_fatal); sysbus_realize(SYS_BUS_DEVICE(msc), &error_fatal); qdev_connect_gpio_out_named(DEVICE(msc), "irq", 0, @@ -330,8 +329,8 @@ static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque, msc_upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(msc), 0); object_initialize_child(OBJECT(mms), name, dma, TYPE_PL081); - object_property_set_link(OBJECT(dma), OBJECT(msc_upstream), - "downstream", &error_fatal); + object_property_set_link(OBJECT(dma), "downstream", OBJECT(msc_upstream), + &error_fatal); sysbus_realize(SYS_BUS_DEVICE(dma), &error_fatal); s = SYS_BUS_DEVICE(dma); @@ -404,8 +403,8 @@ static void mps2tz_common_init(MachineState *machine) object_initialize_child(OBJECT(machine), TYPE_IOTKIT, &mms->iotkit, mmc->armsse_type); iotkitdev = DEVICE(&mms->iotkit); - object_property_set_link(OBJECT(&mms->iotkit), OBJECT(system_memory), - "memory", &error_abort); + object_property_set_link(OBJECT(&mms->iotkit), "memory", + OBJECT(system_memory), &error_abort); qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", MPS2TZ_NUMIRQ); qdev_prop_set_uint32(iotkitdev, "MAINCLK", SYSCLK_FRQ); sysbus_realize(SYS_BUS_DEVICE(&mms->iotkit), &error_fatal); @@ -425,7 +424,7 @@ static void mps2tz_common_init(MachineState *machine) NULL); g_free(name); - object_property_set_int(OBJECT(splitter), 2, "num-lines", + object_property_set_int(OBJECT(splitter), "num-lines", 2, &error_fatal); qdev_realize(DEVICE(splitter), NULL, &error_fatal); qdev_connect_gpio_out(DEVICE(splitter), 0, @@ -442,9 +441,9 @@ static void mps2tz_common_init(MachineState *machine) */ object_initialize_child(OBJECT(machine), "sec-resp-splitter", &mms->sec_resp_splitter, TYPE_SPLIT_IRQ); - object_property_set_int(OBJECT(&mms->sec_resp_splitter), + object_property_set_int(OBJECT(&mms->sec_resp_splitter), "num-lines", ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc), - "num-lines", &error_fatal); + &error_fatal); qdev_realize(DEVICE(&mms->sec_resp_splitter), NULL, &error_fatal); dev_splitter = DEVICE(&mms->sec_resp_splitter); qdev_connect_gpio_out_named(iotkitdev, "sec_resp_cfg", 0, @@ -475,7 +474,7 @@ static void mps2tz_common_init(MachineState *machine) */ object_initialize_child(OBJECT(mms), "uart-irq-orgate", &mms->uart_irq_orgate, TYPE_OR_IRQ); - object_property_set_int(OBJECT(&mms->uart_irq_orgate), 10, "num-lines", + object_property_set_int(OBJECT(&mms->uart_irq_orgate), "num-lines", 10, &error_fatal); qdev_realize(DEVICE(&mms->uart_irq_orgate), NULL, &error_fatal); qdev_connect_gpio_out(DEVICE(&mms->uart_irq_orgate), 0, @@ -568,8 +567,8 @@ static void mps2tz_common_init(MachineState *machine) mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size); portname = g_strdup_printf("port[%d]", port); - object_property_set_link(OBJECT(ppc), OBJECT(mr), - portname, &error_fatal); + object_property_set_link(OBJECT(ppc), portname, OBJECT(mr), + &error_fatal); g_free(portname); } diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index d1653a7e6e..9f12934ca8 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -203,8 +203,8 @@ static void mps2_common_init(MachineState *machine) } qdev_prop_set_string(armv7m, "cpu-type", machine->cpu_type); qdev_prop_set_bit(armv7m, "enable-bitband", true); - object_property_set_link(OBJECT(&mms->armv7m), OBJECT(system_memory), - "memory", &error_abort); + object_property_set_link(OBJECT(&mms->armv7m), "memory", + OBJECT(system_memory), &error_abort); sysbus_realize(SYS_BUS_DEVICE(&mms->armv7m), &error_fatal); create_unimplemented_device("zbtsmram mirror", 0x00400000, 0x00400000); @@ -237,7 +237,7 @@ static void mps2_common_init(MachineState *machine) DeviceState *orgate_dev; orgate = object_new(TYPE_OR_IRQ); - object_property_set_int(orgate, 6, "num-lines", &error_fatal); + object_property_set_int(orgate, "num-lines", 6, &error_fatal); qdev_realize(DEVICE(orgate), NULL, &error_fatal); orgate_dev = DEVICE(orgate); qdev_connect_gpio_out(orgate_dev, 0, qdev_get_gpio_in(armv7m, 12)); @@ -273,7 +273,7 @@ static void mps2_common_init(MachineState *machine) DeviceState *orgate_dev; orgate = object_new(TYPE_OR_IRQ); - object_property_set_int(orgate, 10, "num-lines", &error_fatal); + object_property_set_int(orgate, "num-lines", 10, &error_fatal); qdev_realize(DEVICE(orgate), NULL, &error_fatal); orgate_dev = DEVICE(orgate); qdev_connect_gpio_out(orgate_dev, 0, qdev_get_gpio_in(armv7m, 12)); @@ -288,7 +288,7 @@ static void mps2_common_init(MachineState *machine) DeviceState *txrx_orgate_dev; txrx_orgate = object_new(TYPE_OR_IRQ); - object_property_set_int(txrx_orgate, 2, "num-lines", &error_fatal); + object_property_set_int(txrx_orgate, "num-lines", 2, &error_fatal); qdev_realize(DEVICE(txrx_orgate), NULL, &error_fatal); txrx_orgate_dev = DEVICE(txrx_orgate); qdev_connect_gpio_out(txrx_orgate_dev, 0, @@ -356,7 +356,7 @@ static void mps2_common_init(MachineState *machine) int j; orgate = object_new(TYPE_OR_IRQ); - object_property_set_int(orgate, 2, "num-lines", &error_fatal); + object_property_set_int(orgate, "num-lines", 2, &error_fatal); orgate_dev = DEVICE(orgate); qdev_realize(orgate_dev, NULL, &error_fatal); qdev_connect_gpio_out(orgate_dev, 0, diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index 476112b2d9..e6e4bb3153 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -123,8 +123,8 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_uint32(armv7m, "num-irq", 81); qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type); qdev_prop_set_bit(armv7m, "enable-bitband", true); - object_property_set_link(OBJECT(&s->armv7m), OBJECT(get_system_memory()), - "memory", &error_abort); + object_property_set_link(OBJECT(&s->armv7m), "memory", + OBJECT(get_system_memory()), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err)) { error_propagate(errp, err); return; @@ -193,8 +193,8 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) } dev = DEVICE(&s->emac); - object_property_set_link(OBJECT(&s->emac), OBJECT(get_system_memory()), - "ahb-bus", &error_abort); + object_property_set_link(OBJECT(&s->emac), "ahb-bus", + OBJECT(get_system_memory()), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->emac), &err)) { error_propagate(errp, err); return; diff --git a/hw/arm/musca.c b/hw/arm/musca.c index 34376328fc..4bc737f93b 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -256,8 +256,8 @@ static MemoryRegion *make_mpc(MuscaMachineState *mms, void *opaque, } object_initialize_child(OBJECT(mms), mpcname, mpc, TYPE_TZ_MPC); - object_property_set_link(OBJECT(mpc), OBJECT(downstream), - "downstream", &error_fatal); + object_property_set_link(OBJECT(mpc), "downstream", OBJECT(downstream), + &error_fatal); sysbus_realize(SYS_BUS_DEVICE(mpc), &error_fatal); /* Map the upstream end of the MPC into system memory */ upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1); @@ -374,8 +374,8 @@ static void musca_init(MachineState *machine) object_initialize_child(OBJECT(machine), "sse-200", &mms->sse, TYPE_SSE200); ssedev = DEVICE(&mms->sse); - object_property_set_link(OBJECT(&mms->sse), OBJECT(system_memory), - "memory", &error_fatal); + object_property_set_link(OBJECT(&mms->sse), "memory", + OBJECT(system_memory), &error_fatal); qdev_prop_set_uint32(ssedev, "EXP_NUMIRQ", mmc->num_irqs); qdev_prop_set_uint32(ssedev, "init-svtor", mmc->init_svtor); qdev_prop_set_uint32(ssedev, "SRAM_ADDR_WIDTH", mmc->sram_addr_width); @@ -403,7 +403,7 @@ static void musca_init(MachineState *machine) &error_fatal, NULL); g_free(name); - object_property_set_int(OBJECT(splitter), 2, "num-lines", + object_property_set_int(OBJECT(splitter), "num-lines", 2, &error_fatal); qdev_realize(DEVICE(splitter), NULL, &error_fatal); qdev_connect_gpio_out(DEVICE(splitter), 0, @@ -422,8 +422,8 @@ static void musca_init(MachineState *machine) sizeof(mms->sec_resp_splitter), TYPE_SPLIT_IRQ, &error_fatal, NULL); - object_property_set_int(OBJECT(&mms->sec_resp_splitter), - ARRAY_SIZE(mms->ppc), "num-lines", &error_fatal); + object_property_set_int(OBJECT(&mms->sec_resp_splitter), "num-lines", + ARRAY_SIZE(mms->ppc), &error_fatal); qdev_realize(DEVICE(&mms->sec_resp_splitter), NULL, &error_fatal); dev_splitter = DEVICE(&mms->sec_resp_splitter); qdev_connect_gpio_out_named(ssedev, "sec_resp_cfg", 0, @@ -541,8 +541,8 @@ static void musca_init(MachineState *machine) mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size); portname = g_strdup_printf("port[%d]", port); - object_property_set_link(OBJECT(ppc), OBJECT(mr), - portname, &error_fatal); + object_property_set_link(OBJECT(ppc), portname, OBJECT(mr), + &error_fatal); g_free(portname); } diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 394a3345bd..ff9a7c8cc6 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -1690,8 +1690,8 @@ static void musicpal_init(MachineState *machine) wm8750_dev = i2c_create_slave(i2c, TYPE_WM8750, MP_WM_ADDR); dev = qdev_new(TYPE_MV88W8618_AUDIO); s = SYS_BUS_DEVICE(dev); - object_property_set_link(OBJECT(dev), OBJECT(wm8750_dev), - "wm8750", NULL); + object_property_set_link(OBJECT(dev), "wm8750", OBJECT(wm8750_dev), + NULL); sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, MP_AUDIO_BASE); sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]); diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index e9c77e4c21..c440cd11e9 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -65,7 +65,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) return; } - object_property_set_link(OBJECT(&s->cpu), OBJECT(&s->container), "memory", + object_property_set_link(OBJECT(&s->cpu), "memory", OBJECT(&s->container), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpu), &err)) { error_propagate(errp, err); @@ -106,7 +106,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) BASE_TO_IRQ(NRF51_RNG_BASE))); /* UICR, FICR, NVMC, FLASH */ - object_property_set_uint(OBJECT(&s->nvm), s->flash_size, "flash-size", + object_property_set_uint(OBJECT(&s->nvm), "flash-size", s->flash_size, &err); if (err) { error_propagate(errp, err); @@ -141,7 +141,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) /* TIMER */ for (i = 0; i < NRF51_NUM_TIMERS; i++) { - object_property_set_uint(OBJECT(&s->timer[i]), i, "id", &err); + object_property_set_uint(OBJECT(&s->timer[i]), "id", i, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c index 843dcbbd62..1679468232 100644 --- a/hw/arm/orangepi.c +++ b/hw/arm/orangepi.c @@ -63,9 +63,8 @@ static void orangepi_init(MachineState *machine) object_unref(OBJECT(h3)); /* Setup timer properties */ - object_property_set_int(OBJECT(h3), 32768, "clk0-freq", - &error_abort); - object_property_set_int(OBJECT(h3), 24 * 1000 * 1000, "clk1-freq", + object_property_set_int(OBJECT(h3), "clk0-freq", 32768, &error_abort); + object_property_set_int(OBJECT(h3), "clk1-freq", 24 * 1000 * 1000, &error_abort); /* Setup SID properties. Currently using a default fixed SID identifier. */ @@ -77,12 +76,12 @@ static void orangepi_init(MachineState *machine) } /* Setup EMAC properties */ - object_property_set_int(OBJECT(&h3->emac), 1, "phy-addr", &error_abort); + object_property_set_int(OBJECT(&h3->emac), "phy-addr", 1, &error_abort); /* DRAMC */ - object_property_set_uint(OBJECT(h3), h3->memmap[AW_H3_SDRAM], - "ram-addr", &error_abort); - object_property_set_int(OBJECT(h3), machine->ram_size / MiB, "ram-size", + object_property_set_uint(OBJECT(h3), "ram-addr", h3->memmap[AW_H3_SDRAM], + &error_abort); + object_property_set_int(OBJECT(h3), "ram-size", machine->ram_size / MiB, &error_abort); /* Mark H3 object realized */ diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 09bf02ec9c..b2d6c9688f 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -285,7 +285,7 @@ static void raspi_machine_init(MachineState *machine) object_initialize_child(OBJECT(machine), "soc", &s->soc, board_soc_type(board_rev)); object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(machine->ram)); - object_property_set_int(OBJECT(&s->soc), board_rev, "board-rev", + object_property_set_int(OBJECT(&s->soc), "board-rev", board_rev, &error_abort); qdev_realize(DEVICE(&s->soc), NULL, &error_abort); diff --git a/hw/arm/realview.c b/hw/arm/realview.c index b6c0a1adb9..22e132058e 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -107,11 +107,11 @@ static void realview_init(MachineState *machine, * before realization. */ if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); + object_property_set_bool(cpuobj, "has_el3", false, &error_fatal); } if (is_pb && is_mpcore) { - object_property_set_int(cpuobj, periphbase, "reset-cbar", + object_property_set_int(cpuobj, "reset-cbar", periphbase, &error_fatal); } @@ -205,7 +205,7 @@ static void realview_init(MachineState *machine, /* DMA controller is optional, apparently. */ dev = qdev_new("pl081"); - object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream", + object_property_set_link(OBJECT(dev), "downstream", OBJECT(sysmem), &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(busdev, &error_fatal); diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index e40c868a82..f030a416fd 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -499,7 +499,7 @@ static void create_smmu(const SBSAMachineState *sms, PCIBus *bus) dev = qdev_new("arm-smmuv3"); - object_property_set_link(OBJECT(dev), OBJECT(bus), "primary-bus", + object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus), &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); @@ -659,8 +659,8 @@ static void sbsa_ref_init(MachineState *machine) } cpuobj = object_new(possible_cpus->cpus[n].type); - object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id, - "mp-affinity", NULL); + object_property_set_int(cpuobj, "mp-affinity", + possible_cpus->cpus[n].arch_id, NULL); cs = CPU(cpuobj); cs->cpu_index = n; @@ -669,16 +669,16 @@ static void sbsa_ref_init(MachineState *machine) &error_fatal); if (object_property_find(cpuobj, "reset-cbar", NULL)) { - object_property_set_int(cpuobj, + object_property_set_int(cpuobj, "reset-cbar", sbsa_ref_memmap[SBSA_CPUPERIPHS].base, - "reset-cbar", &error_abort); + &error_abort); } - object_property_set_link(cpuobj, OBJECT(sysmem), "memory", + object_property_set_link(cpuobj, "memory", OBJECT(sysmem), &error_abort); - object_property_set_link(cpuobj, OBJECT(secure_sysmem), - "secure-memory", &error_abort); + object_property_set_link(cpuobj, "secure-memory", + OBJECT(secure_sysmem), &error_abort); qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); object_unref(cpuobj); diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 97ef566c12..7156fb3ece 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -1312,8 +1312,8 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) qdev_prop_set_uint32(nvic, "num-irq", NUM_IRQ_LINES); qdev_prop_set_string(nvic, "cpu-type", ms->cpu_type); qdev_prop_set_bit(nvic, "enable-bitband", true); - object_property_set_link(OBJECT(nvic), OBJECT(get_system_memory()), - "memory", &error_abort); + object_property_set_link(OBJECT(nvic), "memory", + OBJECT(get_system_memory()), &error_abort); /* This will exit with an error if the user passed us a bad cpu_type */ sysbus_realize_and_unref(SYS_BUS_DEVICE(nvic), &error_fatal); diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index 46b5332470..9acf401fbf 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -105,8 +105,8 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_uint32(armv7m, "num-irq", 96); qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type); qdev_prop_set_bit(armv7m, "enable-bitband", true); - object_property_set_link(OBJECT(&s->armv7m), OBJECT(get_system_memory()), - "memory", &error_abort); + object_property_set_link(OBJECT(&s->armv7m), "memory", + OBJECT(get_system_memory()), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err)) { error_propagate(errp, err); return; @@ -149,8 +149,8 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) } /* ADC 1 to 3 */ - object_property_set_int(OBJECT(s->adc_irqs), STM_NUM_ADCS, - "num-lines", &error_abort); + object_property_set_int(OBJECT(s->adc_irqs), "num-lines", STM_NUM_ADCS, + &error_abort); if (!qdev_realize(DEVICE(s->adc_irqs), NULL, &err)) { error_propagate(errp, err); return; diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index f1f0dc40b1..07ce323a64 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -116,8 +116,8 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_uint32(armv7m, "num-irq", 96); qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type); qdev_prop_set_bit(armv7m, "enable-bitband", true); - object_property_set_link(OBJECT(&s->armv7m), OBJECT(system_memory), - "memory", &error_abort); + object_property_set_link(OBJECT(&s->armv7m), "memory", + OBJECT(system_memory), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err)) { error_propagate(errp, err); return; @@ -167,8 +167,8 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) error_propagate(errp, err); return; } - object_property_set_int(OBJECT(&s->adc_irqs), STM_NUM_ADCS, - "num-lines", &error_abort); + object_property_set_int(OBJECT(&s->adc_irqs), "num-lines", STM_NUM_ADCS, + &error_abort); if (!qdev_realize(DEVICE(&s->adc_irqs), NULL, &err)) { error_propagate(errp, err); return; diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index e596b8170f..d09ea24ae2 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -213,7 +213,7 @@ static void versatile_init(MachineState *machine, int board_id) * realization. */ if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); + object_property_set_bool(cpuobj, "has_el3", false, &error_fatal); } qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); @@ -288,7 +288,7 @@ static void versatile_init(MachineState *machine, int board_id) pl011_create(0x10009000, sic[6], serial_hd(3)); dev = qdev_new("pl080"); - object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream", + object_property_set_link(OBJECT(dev), "downstream", OBJECT(sysmem), &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(busdev, &error_fatal); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 5bf9cff8a8..762b068e90 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -218,17 +218,17 @@ static void init_cpus(MachineState *ms, const char *cpu_type, Object *cpuobj = object_new(cpu_type); if (!secure) { - object_property_set_bool(cpuobj, false, "has_el3", NULL); + object_property_set_bool(cpuobj, "has_el3", false, NULL); } if (!virt) { if (object_property_find(cpuobj, "has_el2", NULL)) { - object_property_set_bool(cpuobj, false, "has_el2", NULL); + object_property_set_bool(cpuobj, "has_el2", false, NULL); } } if (object_property_find(cpuobj, "reset-cbar", NULL)) { - object_property_set_int(cpuobj, periphbase, - "reset-cbar", &error_abort); + object_property_set_int(cpuobj, "reset-cbar", periphbase, + &error_abort); } qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 7d9f7157da..9005dae356 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -594,7 +594,7 @@ static void create_its(VirtMachineState *vms) dev = qdev_new(itsclass); - object_property_set_link(OBJECT(dev), OBJECT(vms->gic), "parent-gicv3", + object_property_set_link(OBJECT(dev), "parent-gicv3", OBJECT(vms->gic), &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_ITS].base); @@ -1175,7 +1175,7 @@ static void create_smmu(const VirtMachineState *vms, dev = qdev_new("arm-smmuv3"); - object_property_set_link(OBJECT(dev), OBJECT(bus), "primary-bus", + object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus), &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); @@ -1785,8 +1785,8 @@ static void machvirt_init(MachineState *machine) } cpuobj = object_new(possible_cpus->cpus[n].type); - object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id, - "mp-affinity", NULL); + object_property_set_int(cpuobj, "mp-affinity", + possible_cpus->cpus[n].arch_id, NULL); cs = CPU(cpuobj); cs->cpu_index = n; @@ -1797,43 +1797,44 @@ static void machvirt_init(MachineState *machine) aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL); if (!vms->secure) { - object_property_set_bool(cpuobj, false, "has_el3", NULL); + object_property_set_bool(cpuobj, "has_el3", false, NULL); } if (!vms->virt && object_property_find(cpuobj, "has_el2", NULL)) { - object_property_set_bool(cpuobj, false, "has_el2", NULL); + object_property_set_bool(cpuobj, "has_el2", false, NULL); } if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) { - object_property_set_int(cpuobj, vms->psci_conduit, - "psci-conduit", NULL); + object_property_set_int(cpuobj, "psci-conduit", vms->psci_conduit, + NULL); /* Secondary CPUs start in PSCI powered-down state */ if (n > 0) { - object_property_set_bool(cpuobj, true, - "start-powered-off", NULL); + object_property_set_bool(cpuobj, "start-powered-off", true, + NULL); } } if (vmc->kvm_no_adjvtime && object_property_find(cpuobj, "kvm-no-adjvtime", NULL)) { - object_property_set_bool(cpuobj, true, "kvm-no-adjvtime", NULL); + object_property_set_bool(cpuobj, "kvm-no-adjvtime", true, NULL); } if (vmc->no_pmu && object_property_find(cpuobj, "pmu", NULL)) { - object_property_set_bool(cpuobj, false, "pmu", NULL); + object_property_set_bool(cpuobj, "pmu", false, NULL); } if (object_property_find(cpuobj, "reset-cbar", NULL)) { - object_property_set_int(cpuobj, vms->memmap[VIRT_CPUPERIPHS].base, - "reset-cbar", &error_abort); + object_property_set_int(cpuobj, "reset-cbar", + vms->memmap[VIRT_CPUPERIPHS].base, + &error_abort); } - object_property_set_link(cpuobj, OBJECT(sysmem), "memory", + object_property_set_link(cpuobj, "memory", OBJECT(sysmem), &error_abort); if (vms->secure) { - object_property_set_link(cpuobj, OBJECT(secure_sysmem), - "secure-memory", &error_abort); + object_property_set_link(cpuobj, "secure-memory", + OBJECT(secure_sysmem), &error_abort); } /* @@ -1857,11 +1858,12 @@ static void machvirt_init(MachineState *machine) } } - object_property_set_link(cpuobj, OBJECT(tag_sysmem), - "tag-memory", &error_abort); + object_property_set_link(cpuobj, "tag-memory", OBJECT(tag_sysmem), + &error_abort); if (vms->secure) { - object_property_set_link(cpuobj, OBJECT(secure_tag_sysmem), - "secure-tag-memory", &error_abort); + object_property_set_link(cpuobj, "secure-tag-memory", + OBJECT(secure_tag_sysmem), + &error_abort); } } diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index ed970273f3..32aa7323d9 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -196,12 +196,12 @@ static void zynq_init(MachineState *machine) * realization. */ if (object_property_find(OBJECT(cpu), "has_el3", NULL)) { - object_property_set_bool(OBJECT(cpu), false, "has_el3", &error_fatal); + object_property_set_bool(OBJECT(cpu), "has_el3", false, &error_fatal); } - object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", + object_property_set_int(OBJECT(cpu), "midr", ZYNQ_BOARD_MIDR, &error_fatal); - object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar", + object_property_set_int(OBJECT(cpu), "reset-cbar", MPCORE_PERIPHBASE, &error_fatal); qdev_realize(DEVICE(cpu), NULL, &error_fatal); diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index a3b1ce9c7c..4b3152ee77 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -502,10 +502,10 @@ static void versal_virt_init(MachineState *machine) object_initialize_child(OBJECT(machine), "xlnx-versal", &s->soc, TYPE_XLNX_VERSAL); - object_property_set_link(OBJECT(&s->soc), OBJECT(machine->ram), - "ddr", &error_abort); - object_property_set_int(OBJECT(&s->soc), psci_conduit, - "psci-conduit", &error_abort); + object_property_set_link(OBJECT(&s->soc), "ddr", OBJECT(machine->ram), + &error_abort); + object_property_set_int(OBJECT(&s->soc), "psci-conduit", psci_conduit, + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal); fdt_create(s); diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index fed9d07ca2..ead038b971 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -35,17 +35,17 @@ static void versal_create_apu_cpus(Versal *s) object_initialize_child(OBJECT(s), "apu-cpu[*]", &s->fpd.apu.cpu[i], XLNX_VERSAL_ACPU_TYPE); obj = OBJECT(&s->fpd.apu.cpu[i]); - object_property_set_int(obj, s->cfg.psci_conduit, - "psci-conduit", &error_abort); + object_property_set_int(obj, "psci-conduit", s->cfg.psci_conduit, + &error_abort); if (i) { /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(obj, true, - "start-powered-off", &error_abort); + object_property_set_bool(obj, "start-powered-off", true, + &error_abort); } - object_property_set_int(obj, ARRAY_SIZE(s->fpd.apu.cpu), - "core-count", &error_abort); - object_property_set_link(obj, OBJECT(&s->fpd.apu.mr), "memory", + object_property_set_int(obj, "core-count", ARRAY_SIZE(s->fpd.apu.cpu), + &error_abort); + object_property_set_link(obj, "memory", OBJECT(&s->fpd.apu.mr), &error_abort); qdev_realize(DEVICE(obj), NULL, &error_fatal); } @@ -164,11 +164,9 @@ static void versal_create_gems(Versal *s, qemu_irq *pic) qemu_check_nic_model(nd, "cadence_gem"); qdev_set_nic_properties(dev, nd); } - object_property_set_int(OBJECT(dev), - 2, "num-priority-queues", + object_property_set_int(OBJECT(dev), "num-priority-queues", 2, &error_abort); - object_property_set_link(OBJECT(dev), - OBJECT(&s->mr_ps), "dma", + object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps), &error_abort); sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); @@ -192,7 +190,7 @@ static void versal_create_admas(Versal *s, qemu_irq *pic) object_initialize_child(OBJECT(s), name, &s->lpd.iou.adma[i], TYPE_XLNX_ZDMA); dev = DEVICE(&s->lpd.iou.adma[i]); - object_property_set_int(OBJECT(dev), 128, "bus-width", &error_abort); + object_property_set_int(OBJECT(dev), "bus-width", 128, &error_abort); sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); @@ -217,11 +215,11 @@ static void versal_create_sds(Versal *s, qemu_irq *pic) TYPE_SYSBUS_SDHCI); dev = DEVICE(&s->pmc.iou.sd[i]); - object_property_set_uint(OBJECT(dev), - 3, "sd-spec-version", &error_fatal); - object_property_set_uint(OBJECT(dev), SDHCI_CAPABILITIES, "capareg", + object_property_set_uint(OBJECT(dev), "sd-spec-version", 3, &error_fatal); - object_property_set_uint(OBJECT(dev), UHS_I, "uhs", &error_fatal); + object_property_set_uint(OBJECT(dev), "capareg", SDHCI_CAPABILITIES, + &error_fatal); + object_property_set_uint(OBJECT(dev), "uhs", UHS_I, &error_fatal); sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 77449759c6..5997262459 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -118,11 +118,11 @@ static void xlnx_zcu102_init(MachineState *machine) object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_XLNX_ZYNQMP); - object_property_set_link(OBJECT(&s->soc), OBJECT(machine->ram), - "ddr-ram", &error_abort); - object_property_set_bool(OBJECT(&s->soc), s->secure, "secure", + object_property_set_link(OBJECT(&s->soc), "ddr-ram", OBJECT(machine->ram), + &error_abort); + object_property_set_bool(OBJECT(&s->soc), "secure", s->secure, &error_fatal); - object_property_set_bool(OBJECT(&s->soc), s->virt, "virtualization", + object_property_set_bool(OBJECT(&s->soc), "virtualization", s->virt, &error_fatal); qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index d703158f8b..e7fe85f1d8 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -200,14 +200,14 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s, name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i])); if (strcmp(name, boot_cpu)) { /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, - "start-powered-off", &error_abort); + object_property_set_bool(OBJECT(&s->rpu_cpu[i]), + "start-powered-off", true, &error_abort); } else { s->boot_cpu_ptr = &s->rpu_cpu[i]; } g_free(name); - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs", + object_property_set_bool(OBJECT(&s->rpu_cpu[i]), "reset-hivecs", true, &error_abort); if (!qdev_realize(DEVICE(&s->rpu_cpu[i]), NULL, &err)) { error_propagate(errp, err); @@ -345,27 +345,27 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < num_apus; i++) { char *name; - object_property_set_int(OBJECT(&s->apu_cpu[i]), QEMU_PSCI_CONDUIT_SMC, - "psci-conduit", &error_abort); + object_property_set_int(OBJECT(&s->apu_cpu[i]), "psci-conduit", + QEMU_PSCI_CONDUIT_SMC, &error_abort); name = object_get_canonical_path_component(OBJECT(&s->apu_cpu[i])); if (strcmp(name, boot_cpu)) { /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, - "start-powered-off", &error_abort); + object_property_set_bool(OBJECT(&s->apu_cpu[i]), + "start-powered-off", true, &error_abort); } else { s->boot_cpu_ptr = &s->apu_cpu[i]; } g_free(name); - object_property_set_bool(OBJECT(&s->apu_cpu[i]), - s->secure, "has_el3", NULL); - object_property_set_bool(OBJECT(&s->apu_cpu[i]), - s->virt, "has_el2", NULL); - object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR, - "reset-cbar", &error_abort); - object_property_set_int(OBJECT(&s->apu_cpu[i]), num_apus, - "core-count", &error_abort); + object_property_set_bool(OBJECT(&s->apu_cpu[i]), "has_el3", s->secure, + NULL); + object_property_set_bool(OBJECT(&s->apu_cpu[i]), "has_el2", s->virt, + NULL); + object_property_set_int(OBJECT(&s->apu_cpu[i]), "reset-cbar", + GIC_BASE_ADDR, &error_abort); + object_property_set_int(OBJECT(&s->apu_cpu[i]), "core-count", + num_apus, &error_abort); if (!qdev_realize(DEVICE(&s->apu_cpu[i]), NULL, &err)) { error_propagate(errp, err); return; @@ -463,9 +463,9 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(DEVICE(&s->gem[i]), nd); } - object_property_set_int(OBJECT(&s->gem[i]), GEM_REVISION, "revision", + object_property_set_int(OBJECT(&s->gem[i]), "revision", GEM_REVISION, &error_abort); - object_property_set_int(OBJECT(&s->gem[i]), 2, "num-priority-queues", + object_property_set_int(OBJECT(&s->gem[i]), "num-priority-queues", 2, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), &err)) { error_propagate(errp, err); @@ -487,7 +487,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) gic_spi[uart_intr[i]]); } - object_property_set_int(OBJECT(&s->sata), SATA_NUM_PORTS, "num-ports", + object_property_set_int(OBJECT(&s->sata), "num-ports", SATA_NUM_PORTS, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->sata), &err)) { error_propagate(errp, err); @@ -507,17 +507,17 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) * - SDIO Specification Version 3.0 * - eMMC Specification Version 4.51 */ - object_property_set_uint(sdhci, 3, "sd-spec-version", &err); + object_property_set_uint(sdhci, "sd-spec-version", 3, &err); if (err) { error_propagate(errp, err); return; } - object_property_set_uint(sdhci, SDHCI_CAPABILITIES, "capareg", &err); + object_property_set_uint(sdhci, "capareg", SDHCI_CAPABILITIES, &err); if (err) { error_propagate(errp, err); return; } - object_property_set_uint(sdhci, UHS_I, "uhs", &err); + object_property_set_uint(sdhci, "uhs", UHS_I, &err); if (err) { error_propagate(errp, err); return; @@ -586,7 +586,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_link(OBJECT(&s->dp), OBJECT(&s->dpdma), "dpdma", + object_property_set_link(OBJECT(&s->dp), "dpdma", OBJECT(&s->dpdma), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->dpdma), 0, DPDMA_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->dpdma), 0, gic_spi[DPDMA_IRQ]); @@ -606,7 +606,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, gic_spi[RTC_IRQ]); for (i = 0; i < XLNX_ZYNQMP_NUM_GDMA_CH; i++) { - object_property_set_uint(OBJECT(&s->gdma[i]), 128, "bus-width", &err); + object_property_set_uint(OBJECT(&s->gdma[i]), "bus-width", 128, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 48890536a4..0e6e6df5fa 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -935,21 +935,20 @@ static void xen_block_device_create(XenBackendInstance *backend, xendev = XEN_DEVICE(qdev_new(type)); blockdev = XEN_BLOCK_DEVICE(xendev); - object_property_set_str(OBJECT(xendev), vdev, "vdev", &local_err); + object_property_set_str(OBJECT(xendev), "vdev", vdev, &local_err); if (local_err) { error_propagate_prepend(errp, local_err, "failed to set 'vdev': "); goto fail; } - object_property_set_str(OBJECT(xendev), - xen_block_drive_get_node_name(drive), "drive", - &local_err); + object_property_set_str(OBJECT(xendev), "drive", + xen_block_drive_get_node_name(drive), &local_err); if (local_err) { error_propagate_prepend(errp, local_err, "failed to set 'drive': "); goto fail; } - object_property_set_str(OBJECT(xendev), iothread->id, "iothread", + object_property_set_str(OBJECT(xendev), "iothread", iothread->id, &local_err); if (local_err) { error_propagate_prepend(errp, local_err, diff --git a/hw/core/bus.c b/hw/core/bus.c index 544dd8a6fa..00d1d31762 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -25,8 +25,8 @@ void qbus_set_hotplug_handler(BusState *bus, Object *handler) { - object_property_set_link(OBJECT(bus), handler, - QDEV_HOTPLUG_HANDLER_PROPERTY, &error_abort); + object_property_set_link(OBJECT(bus), QDEV_HOTPLUG_HANDLER_PROPERTY, + handler, &error_abort); } void qbus_set_bus_hotplug_handler(BusState *bus) @@ -168,14 +168,14 @@ bool qbus_realize(BusState *bus, Error **errp) { Error *err = NULL; - object_property_set_bool(OBJECT(bus), true, "realized", &err); + object_property_set_bool(OBJECT(bus), "realized", true, &err); error_propagate(errp, err); return !err; } void qbus_unrealize(BusState *bus) { - object_property_set_bool(OBJECT(bus), false, "realized", &error_abort); + object_property_set_bool(OBJECT(bus), "realized", false, &error_abort); } static bool bus_get_realized(Object *obj, Error **errp) diff --git a/hw/core/numa.c b/hw/core/numa.c index 6a20ce7cf1..de9a2f7e32 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -810,8 +810,8 @@ void numa_cpu_pre_plug(const CPUArchId *slot, DeviceState *dev, Error **errp) /* due to bug in libvirt, it doesn't pass node-id from props on * device_add as expected, so we have to fix it up here */ if (slot->props.has_node_id) { - object_property_set_int(OBJECT(dev), slot->props.node_id, - "node-id", errp); + object_property_set_int(OBJECT(dev), "node-id", + slot->props.node_id, errp); } } else if (node_id != slot->props.node_id) { error_setg(errp, "invalid node-id, must be %"PRId64, diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 383a54578f..810831b1df 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -436,7 +436,7 @@ void qdev_prop_set_drive_err(DeviceState *dev, const char *name, } } - object_property_set_str(OBJECT(dev), ref, name, errp); + object_property_set_str(OBJECT(dev), name, ref, errp); } void qdev_prop_set_drive(DeviceState *dev, const char *name, @@ -449,16 +449,16 @@ void qdev_prop_set_chr(DeviceState *dev, const char *name, Chardev *value) { assert(!value || value->label); - object_property_set_str(OBJECT(dev), - value ? value->label : "", name, &error_abort); + object_property_set_str(OBJECT(dev), name, value ? value->label : "", + &error_abort); } void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value) { assert(!value || value->name); - object_property_set_str(OBJECT(dev), - value ? value->name : "", name, &error_abort); + object_property_set_str(OBJECT(dev), name, value ? value->name : "", + &error_abort); } void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 4c7a8a05a5..be8d4eb9f6 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -1256,37 +1256,37 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) { - object_property_set_bool(OBJECT(dev), value, name, &error_abort); + object_property_set_bool(OBJECT(dev), name, value, &error_abort); } void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) { - object_property_set_int(OBJECT(dev), value, name, &error_abort); + object_property_set_int(OBJECT(dev), name, value, &error_abort); } void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) { - object_property_set_int(OBJECT(dev), value, name, &error_abort); + object_property_set_int(OBJECT(dev), name, value, &error_abort); } void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) { - object_property_set_int(OBJECT(dev), value, name, &error_abort); + object_property_set_int(OBJECT(dev), name, value, &error_abort); } void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) { - object_property_set_int(OBJECT(dev), value, name, &error_abort); + object_property_set_int(OBJECT(dev), name, value, &error_abort); } void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) { - object_property_set_int(OBJECT(dev), value, name, &error_abort); + object_property_set_int(OBJECT(dev), name, value, &error_abort); } void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) { - object_property_set_str(OBJECT(dev), value, name, &error_abort); + object_property_set_str(OBJECT(dev), name, value, &error_abort); } void qdev_prop_set_macaddr(DeviceState *dev, const char *name, @@ -1296,7 +1296,7 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name, snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", value[0], value[1], value[2], value[3], value[4], value[5]); - object_property_set_str(OBJECT(dev), str, name, &error_abort); + object_property_set_str(OBJECT(dev), name, str, &error_abort); } void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) @@ -1304,9 +1304,9 @@ void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) Property *prop; prop = qdev_prop_find(dev, name); - object_property_set_str(OBJECT(dev), + object_property_set_str(OBJECT(dev), name, qapi_enum_lookup(prop->info->enum_table, value), - name, &error_abort); + &error_abort); } static GPtrArray *global_props(void) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 9de16eae05..56daa7b456 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -398,7 +398,7 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) assert(!DEVICE_GET_CLASS(dev)->bus_type); } - object_property_set_bool(OBJECT(dev), true, "realized", &err); + object_property_set_bool(OBJECT(dev), "realized", true, &err); if (err) { error_propagate(errp, err); } @@ -426,7 +426,7 @@ bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp) void qdev_unrealize(DeviceState *dev) { - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + object_property_set_bool(OBJECT(dev), "realized", false, &error_abort); } static int qdev_assert_realized_properly(Object *obj, void *opaque) @@ -567,7 +567,7 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, "/unattached"), "non-qdev-gpio[*]", OBJECT(pin)); } - object_property_set_link(OBJECT(dev), OBJECT(pin), propname, &error_abort); + object_property_set_link(OBJECT(dev), propname, OBJECT(pin), &error_abort); g_free(propname); } @@ -593,7 +593,7 @@ static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev, qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname, NULL); if (ret) { - object_property_set_link(OBJECT(dev), NULL, propname, NULL); + object_property_set_link(OBJECT(dev), propname, NULL, NULL); } g_free(propname); return ret; diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index 357fefa3c0..d5b7d39bc4 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -40,9 +40,8 @@ static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) } for (i = 0; i < g->conf.max_outputs; i++) { - object_property_set_link(OBJECT(g->scanout[i].con), - OBJECT(vpci_dev), - "device", &error_abort); + object_property_set_link(OBJECT(g->scanout[i].con), "device", + OBJECT(vpci_dev), &error_abort); } } diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 0fc00fee1f..d5cebf686f 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -151,9 +151,8 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) graphic_console_set_hwops(vga->con, &virtio_vga_base_ops, vvga); for (i = 0; i < g->conf.max_outputs; i++) { - object_property_set_link(OBJECT(g->scanout[i].con), - OBJECT(vpci_dev), - "device", &error_abort); + object_property_set_link(OBJECT(g->scanout[i].con), "device", + OBJECT(vpci_dev), &error_abort); } } diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index 2d7dbbb92d..9459178866 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -346,7 +346,7 @@ static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp) d = qdev_new(TYPE_LANCE); object_property_add_child(OBJECT(dev), "lance", OBJECT(d)); qdev_set_nic_properties(d, nd); - object_property_set_link(OBJECT(d), OBJECT(dev), "dma", &error_abort); + object_property_set_link(OBJECT(d), "dma", OBJECT(dev), &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(d), &error_fatal); } @@ -379,7 +379,7 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) } espdma = qdev_new(TYPE_SPARC32_ESPDMA_DEVICE); - object_property_set_link(OBJECT(espdma), iommu, "iommu", &error_abort); + object_property_set_link(OBJECT(espdma), "iommu", iommu, &error_abort); object_property_add_child(OBJECT(s), "espdma", OBJECT(espdma)); sysbus_realize_and_unref(SYS_BUS_DEVICE(espdma), &error_fatal); @@ -394,7 +394,7 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(sbd, 0)); ledma = qdev_new(TYPE_SPARC32_LEDMA_DEVICE); - object_property_set_link(OBJECT(ledma), iommu, "iommu", &error_abort); + object_property_set_link(OBJECT(ledma), "iommu", iommu, &error_abort); object_property_add_child(OBJECT(s), "ledma", OBJECT(ledma)); sysbus_realize_and_unref(SYS_BUS_DEVICE(ledma), &error_fatal); diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index a069637bf2..a4812e480a 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -547,8 +547,8 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) (Object **)&cs->dma, object_property_allow_set_link, OBJ_PROP_LINK_STRONG); - object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &error_abort); - object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &error_abort); + object_property_set_link(OBJECT(ds), "dma", OBJECT(s), &error_abort); + object_property_set_link(OBJECT(cs), "dma", OBJECT(s), &error_abort); for (i = 0; i < 2; i++) { struct Stream *st = &s->streams[i]; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index cb15261420..3e933b65b9 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -640,8 +640,8 @@ void pc_cmos_init(PCMachineState *pcms, (Object **)&x86ms->rtc, object_property_allow_set_link, OBJ_PROP_LINK_STRONG); - object_property_set_link(OBJECT(pcms), OBJECT(s), - "rtc_state", &error_abort); + object_property_set_link(OBJECT(pcms), "rtc_state", OBJECT(s), + &error_abort); set_boot_dev(s, MACHINE(pcms)->boot_order, &error_fatal); @@ -1143,8 +1143,8 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport) vmmouse = NULL; } if (vmmouse) { - object_property_set_link(OBJECT(vmmouse), OBJECT(i8042), - "i8042", &error_abort); + object_property_set_link(OBJECT(vmmouse), "i8042", OBJECT(i8042), + &error_abort); isa_realize_and_unref(vmmouse, isa_bus, &error_fatal); } port92 = isa_create_simple(isa_bus, TYPE_PORT92); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 2bb42a8141..ae0dc9247b 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -293,8 +293,8 @@ static void pc_init1(MachineState *machine, (Object **)&pcms->acpi_dev, object_property_allow_set_link, OBJ_PROP_LINK_STRONG); - object_property_set_link(OBJECT(machine), OBJECT(piix4_pm), - PC_MACHINE_ACPI_DEVICE_PROP, &error_abort); + object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, + OBJECT(piix4_pm), &error_abort); } if (machine->nvdimms_state->is_enabled) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 33163ed18d..a3e607a544 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -217,18 +217,18 @@ static void pc_q35_init(MachineState *machine) q35_host = Q35_HOST_DEVICE(qdev_new(TYPE_Q35_HOST_DEVICE)); object_property_add_child(qdev_get_machine(), "q35", OBJECT(q35_host)); - object_property_set_link(OBJECT(q35_host), OBJECT(ram_memory), - MCH_HOST_PROP_RAM_MEM, NULL); - object_property_set_link(OBJECT(q35_host), OBJECT(pci_memory), - MCH_HOST_PROP_PCI_MEM, NULL); - object_property_set_link(OBJECT(q35_host), OBJECT(get_system_memory()), - MCH_HOST_PROP_SYSTEM_MEM, NULL); - object_property_set_link(OBJECT(q35_host), OBJECT(system_io), - MCH_HOST_PROP_IO_MEM, NULL); - object_property_set_int(OBJECT(q35_host), x86ms->below_4g_mem_size, - PCI_HOST_BELOW_4G_MEM_SIZE, NULL); - object_property_set_int(OBJECT(q35_host), x86ms->above_4g_mem_size, - PCI_HOST_ABOVE_4G_MEM_SIZE, NULL); + object_property_set_link(OBJECT(q35_host), MCH_HOST_PROP_RAM_MEM, + OBJECT(ram_memory), NULL); + object_property_set_link(OBJECT(q35_host), MCH_HOST_PROP_PCI_MEM, + OBJECT(pci_memory), NULL); + object_property_set_link(OBJECT(q35_host), MCH_HOST_PROP_SYSTEM_MEM, + OBJECT(get_system_memory()), NULL); + object_property_set_link(OBJECT(q35_host), MCH_HOST_PROP_IO_MEM, + OBJECT(system_io), NULL); + object_property_set_int(OBJECT(q35_host), PCI_HOST_BELOW_4G_MEM_SIZE, + x86ms->below_4g_mem_size, NULL); + object_property_set_int(OBJECT(q35_host), PCI_HOST_ABOVE_4G_MEM_SIZE, + x86ms->above_4g_mem_size, NULL); /* pci */ sysbus_realize_and_unref(SYS_BUS_DEVICE(q35_host), &error_fatal); phb = PCI_HOST_BRIDGE(q35_host); @@ -243,8 +243,8 @@ static void pc_q35_init(MachineState *machine) (Object **)&pcms->acpi_dev, object_property_allow_set_link, OBJ_PROP_LINK_STRONG); - object_property_set_link(OBJECT(machine), OBJECT(lpc), - PC_MACHINE_ACPI_DEVICE_PROP, &error_abort); + object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, + OBJECT(lpc), &error_abort); /* irq lines */ gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled); diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 93f7371a56..54760197cf 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -121,7 +121,7 @@ void x86_cpu_new(X86MachineState *x86ms, int64_t apic_id, Error **errp) Error *local_err = NULL; Object *cpu = object_new(MACHINE(x86ms)->cpu_type); - object_property_set_uint(cpu, apic_id, "apic-id", &local_err); + object_property_set_uint(cpu, "apic-id", apic_id, &local_err); if (local_err) { goto out; } diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index ba8b0d7f02..27ff1f7f66 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -269,7 +269,7 @@ static void ide_dev_instance_init(Object *obj) object_property_add(obj, "bootindex", "int32", ide_dev_get_bootindex, ide_dev_set_bootindex, NULL, NULL); - object_property_set_int(obj, -1, "bootindex", NULL); + object_property_set_int(obj, "bootindex", -1, NULL); } static void ide_hd_realize(IDEDevice *dev, Error **errp) diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index 3b2e87334d..d6780061f4 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -1829,18 +1829,17 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp) * resized dynamically when the controller is configured by the FW * to limit accesses to resources not provisioned. */ - object_property_set_int(OBJECT(xsrc), PNV_XIVE_NR_IRQS, "nr-irqs", + object_property_set_int(OBJECT(xsrc), "nr-irqs", PNV_XIVE_NR_IRQS, &error_fatal); - object_property_set_link(OBJECT(xsrc), OBJECT(xive), "xive", - &error_abort); + object_property_set_link(OBJECT(xsrc), "xive", OBJECT(xive), &error_abort); if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { error_propagate(errp, local_err); return; } - object_property_set_int(OBJECT(end_xsrc), PNV_XIVE_NR_ENDS, "nr-ends", + object_property_set_int(OBJECT(end_xsrc), "nr-ends", PNV_XIVE_NR_ENDS, &error_fatal); - object_property_set_link(OBJECT(end_xsrc), OBJECT(xive), "xive", + object_property_set_link(OBJECT(end_xsrc), "xive", OBJECT(xive), &error_abort); if (!qdev_realize(DEVICE(end_xsrc), NULL, &local_err)) { error_propagate(errp, local_err); diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 615abf5462..1f42bf4f43 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -308,10 +308,9 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) /* * Initialize the internal sources, for IPIs and virtual devices. */ - object_property_set_int(OBJECT(xsrc), xive->nr_irqs, "nr-irqs", + object_property_set_int(OBJECT(xsrc), "nr-irqs", xive->nr_irqs, &error_fatal); - object_property_set_link(OBJECT(xsrc), OBJECT(xive), "xive", - &error_abort); + object_property_set_link(OBJECT(xsrc), "xive", OBJECT(xive), &error_abort); if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { error_propagate(errp, local_err); return; @@ -321,9 +320,9 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) /* * Initialize the END ESB source */ - object_property_set_int(OBJECT(end_xsrc), xive->nr_irqs, "nr-ends", + object_property_set_int(OBJECT(end_xsrc), "nr-ends", xive->nr_irqs, &error_fatal); - object_property_set_link(OBJECT(end_xsrc), OBJECT(xive), "xive", + object_property_set_link(OBJECT(end_xsrc), "xive", OBJECT(xive), &error_abort); if (!qdev_realize(DEVICE(end_xsrc), NULL, &local_err)) { error_propagate(errp, local_err); diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 811b0346e1..c1feb649fb 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -382,8 +382,8 @@ Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp) obj = object_new(type); object_property_add_child(cpu, type, obj); object_unref(obj); - object_property_set_link(obj, OBJECT(xi), ICP_PROP_XICS, &error_abort); - object_property_set_link(obj, cpu, ICP_PROP_CPU, &error_abort); + object_property_set_link(obj, ICP_PROP_XICS, OBJECT(xi), &error_abort); + object_property_set_link(obj, ICP_PROP_CPU, cpu, &error_abort); if (!qdev_realize(DEVICE(obj), NULL, &local_err)) { object_unparent(obj); error_propagate(errp, local_err); diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 8e167306e7..34591659d3 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -763,8 +763,8 @@ Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp) obj = object_new(TYPE_XIVE_TCTX); object_property_add_child(cpu, TYPE_XIVE_TCTX, obj); object_unref(obj); - object_property_set_link(obj, cpu, "cpu", &error_abort); - object_property_set_link(obj, OBJECT(xptr), "presenter", &error_abort); + object_property_set_link(obj, "cpu", cpu, &error_abort); + object_property_set_link(obj, "presenter", OBJECT(xptr), &error_abort); if (!qdev_realize(DEVICE(obj), NULL, &local_err)) { goto error; } diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 459d326af0..1ca482ad81 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -262,8 +262,8 @@ static void q800_init(MachineState *machine) qdev_set_nic_properties(dev, &nd_table[0]); qdev_prop_set_uint8(dev, "it_shift", 2); qdev_prop_set_bit(dev, "big_endian", true); - object_property_set_link(OBJECT(dev), OBJECT(get_system_memory()), - "dma_mr", &error_abort); + object_property_set_link(OBJECT(dev), "dma_mr", + OBJECT(get_system_memory()), &error_abort); sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, SONIC_BASE); diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index f2a86ec4ee..8a075fbf72 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -54,7 +54,7 @@ void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine, if (local_err) { goto out; } - object_property_set_int(OBJECT(dimm), slot, PC_DIMM_SLOT_PROP, + object_property_set_int(OBJECT(dimm), PC_DIMM_SLOT_PROP, slot, &error_abort); trace_mhp_pc_dimm_assigned_slot(slot); @@ -225,7 +225,7 @@ static uint64_t pc_dimm_md_get_addr(const MemoryDeviceState *md) static void pc_dimm_md_set_addr(MemoryDeviceState *md, uint64_t addr, Error **errp) { - object_property_set_uint(OBJECT(md), addr, PC_DIMM_ADDR_PROP, errp); + object_property_set_uint(OBJECT(md), PC_DIMM_ADDR_PROP, addr, errp); } static MemoryRegion *pc_dimm_md_get_memory_region(MemoryDeviceState *md, diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index fff2c578ef..e49fc86eb8 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -83,14 +83,14 @@ petalogix_ml605_init(MachineState *machine) /* init CPUs */ cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU)); - object_property_set_str(OBJECT(cpu), "8.10.a", "version", &error_abort); + object_property_set_str(OBJECT(cpu), "version", "8.10.a", &error_abort); /* Use FPU but don't use floating point conversion and square * root instructions */ - object_property_set_int(OBJECT(cpu), 1, "use-fpu", &error_abort); - object_property_set_bool(OBJECT(cpu), true, "dcache-writeback", + object_property_set_int(OBJECT(cpu), "use-fpu", 1, &error_abort); + object_property_set_bool(OBJECT(cpu), "dcache-writeback", true, &error_abort); - object_property_set_bool(OBJECT(cpu), true, "endianness", &error_abort); + object_property_set_bool(OBJECT(cpu), "endianness", true, &error_abort); qdev_realize(DEVICE(cpu), NULL, &error_abort); /* Attach emulated BRAM through the LMB. */ @@ -148,10 +148,10 @@ petalogix_ml605_init(MachineState *machine) qdev_set_nic_properties(eth0, &nd_table[0]); qdev_prop_set_uint32(eth0, "rxmem", 0x1000); qdev_prop_set_uint32(eth0, "txmem", 0x1000); - object_property_set_link(OBJECT(eth0), ds, - "axistream-connected", &error_abort); - object_property_set_link(OBJECT(eth0), cs, - "axistream-control-connected", &error_abort); + object_property_set_link(OBJECT(eth0), "axistream-connected", ds, + &error_abort); + object_property_set_link(OBJECT(eth0), "axistream-control-connected", cs, + &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(eth0), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(eth0), 0, AXIENET_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(eth0), 0, irq[AXIENET_IRQ]); @@ -161,10 +161,10 @@ petalogix_ml605_init(MachineState *machine) cs = object_property_get_link(OBJECT(eth0), "axistream-control-connected-target", NULL); qdev_prop_set_uint32(dma, "freqhz", 100 * 1000000); - object_property_set_link(OBJECT(dma), ds, - "axistream-connected", &error_abort); - object_property_set_link(OBJECT(dma), cs, - "axistream-control-connected", &error_abort); + object_property_set_link(OBJECT(dma), "axistream-connected", ds, + &error_abort); + object_property_set_link(OBJECT(dma), "axistream-control-connected", cs, + &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(dma), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dma), 0, AXIDMA_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dma), 0, irq[AXIDMA_IRQ0]); diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c index a43c980fc9..9d959d1ad8 100644 --- a/hw/microblaze/petalogix_s3adsp1800_mmu.c +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -70,7 +70,7 @@ petalogix_s3adsp1800_init(MachineState *machine) MemoryRegion *sysmem = get_system_memory(); cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU)); - object_property_set_str(OBJECT(cpu), "7.10.d", "version", &error_abort); + object_property_set_str(OBJECT(cpu), "version", "7.10.d", &error_abort); qdev_realize(DEVICE(cpu), NULL, &error_abort); /* Attach emulated BRAM through the LMB. */ diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index 5e861f5ae2..d22d3e22d1 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -78,34 +78,34 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) XlnxZynqMPPMUSoCState *s = XLNX_ZYNQMP_PMU_SOC(dev); Error *err = NULL; - object_property_set_uint(OBJECT(&s->cpu), XLNX_ZYNQMP_PMU_ROM_ADDR, - "base-vectors", &error_abort); - object_property_set_bool(OBJECT(&s->cpu), true, "use-stack-protection", + object_property_set_uint(OBJECT(&s->cpu), "base-vectors", + XLNX_ZYNQMP_PMU_ROM_ADDR, &error_abort); + object_property_set_bool(OBJECT(&s->cpu), "use-stack-protection", true, &error_abort); - object_property_set_uint(OBJECT(&s->cpu), 0, "use-fpu", &error_abort); - object_property_set_uint(OBJECT(&s->cpu), 0, "use-hw-mul", &error_abort); - object_property_set_bool(OBJECT(&s->cpu), true, "use-barrel", + object_property_set_uint(OBJECT(&s->cpu), "use-fpu", 0, &error_abort); + object_property_set_uint(OBJECT(&s->cpu), "use-hw-mul", 0, &error_abort); + object_property_set_bool(OBJECT(&s->cpu), "use-barrel", true, &error_abort); - object_property_set_bool(OBJECT(&s->cpu), true, "use-msr-instr", + object_property_set_bool(OBJECT(&s->cpu), "use-msr-instr", true, &error_abort); - object_property_set_bool(OBJECT(&s->cpu), true, "use-pcmp-instr", + object_property_set_bool(OBJECT(&s->cpu), "use-pcmp-instr", true, &error_abort); - object_property_set_bool(OBJECT(&s->cpu), false, "use-mmu", &error_abort); - object_property_set_bool(OBJECT(&s->cpu), true, "endianness", + object_property_set_bool(OBJECT(&s->cpu), "use-mmu", false, &error_abort); + object_property_set_bool(OBJECT(&s->cpu), "endianness", true, &error_abort); - object_property_set_str(OBJECT(&s->cpu), "8.40.b", "version", + object_property_set_str(OBJECT(&s->cpu), "version", "8.40.b", &error_abort); - object_property_set_uint(OBJECT(&s->cpu), 0, "pvr", &error_abort); + object_property_set_uint(OBJECT(&s->cpu), "pvr", 0, &error_abort); if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) { error_propagate(errp, err); return; } - object_property_set_uint(OBJECT(&s->intc), 0x10, "intc-intr-size", + object_property_set_uint(OBJECT(&s->intc), "intc-intr-size", 0x10, &error_abort); - object_property_set_uint(OBJECT(&s->intc), 0x0, "intc-level-edge", + object_property_set_uint(OBJECT(&s->intc), "intc-level-edge", 0x0, &error_abort); - object_property_set_uint(OBJECT(&s->intc), 0xffff, "intc-positive", + object_property_set_uint(OBJECT(&s->intc), "intc-positive", 0xffff, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->intc), &err)) { error_propagate(errp, err); diff --git a/hw/mips/boston.c b/hw/mips/boston.c index f5d4ac8cd4..766458c015 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -455,9 +455,9 @@ static void boston_mach_init(MachineState *machine) is_64b = cpu_supports_isa(machine->cpu_type, ISA_MIPS64); object_initialize_child(OBJECT(machine), "cps", &s->cps, TYPE_MIPS_CPS); - object_property_set_str(OBJECT(&s->cps), machine->cpu_type, "cpu-type", + object_property_set_str(OBJECT(&s->cps), "cpu-type", machine->cpu_type, &error_fatal); - object_property_set_int(OBJECT(&s->cps), machine->smp.cpus, "num-vp", + object_property_set_int(OBJECT(&s->cps), "num-vp", machine->smp.cpus, &error_fatal); sysbus_realize(SYS_BUS_DEVICE(&s->cps), &error_fatal); diff --git a/hw/mips/cps.c b/hw/mips/cps.c index 22b932890d..83a073fba5 100644 --- a/hw/mips/cps.c +++ b/hw/mips/cps.c @@ -100,11 +100,11 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) /* Inter-Thread Communication Unit */ if (itu_present) { object_initialize_child(OBJECT(dev), "itu", &s->itu, TYPE_MIPS_ITU); - object_property_set_int(OBJECT(&s->itu), 16, "num-fifo", + object_property_set_int(OBJECT(&s->itu), "num-fifo", 16, &error_abort); - object_property_set_int(OBJECT(&s->itu), 16, "num-semaphores", + object_property_set_int(OBJECT(&s->itu), "num-semaphores", 16, &error_abort); - object_property_set_bool(OBJECT(&s->itu), saar_present, "saar-present", + object_property_set_bool(OBJECT(&s->itu), "saar-present", saar_present, &error_abort); if (saar_present) { s->itu.saar = &env->CP0_SAAR; @@ -120,9 +120,9 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) /* Cluster Power Controller */ object_initialize_child(OBJECT(dev), "cpc", &s->cpc, TYPE_MIPS_CPC); - object_property_set_int(OBJECT(&s->cpc), s->num_vp, "num-vp", + object_property_set_int(OBJECT(&s->cpc), "num-vp", s->num_vp, &error_abort); - object_property_set_int(OBJECT(&s->cpc), 1, "vp-start-running", + object_property_set_int(OBJECT(&s->cpc), "vp-start-running", 1, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpc), &err)) { error_propagate(errp, err); @@ -134,9 +134,9 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) /* Global Interrupt Controller */ object_initialize_child(OBJECT(dev), "gic", &s->gic, TYPE_MIPS_GIC); - object_property_set_int(OBJECT(&s->gic), s->num_vp, "num-vp", + object_property_set_int(OBJECT(&s->gic), "num-vp", s->num_vp, &error_abort); - object_property_set_int(OBJECT(&s->gic), 128, "num-irq", + object_property_set_int(OBJECT(&s->gic), "num-irq", 128, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { error_propagate(errp, err); @@ -150,15 +150,15 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) gcr_base = env->CP0_CMGCRBase << 4; object_initialize_child(OBJECT(dev), "gcr", &s->gcr, TYPE_MIPS_GCR); - object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp", + object_property_set_int(OBJECT(&s->gcr), "num-vp", s->num_vp, &error_abort); - object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev", + object_property_set_int(OBJECT(&s->gcr), "gcr-rev", 0x800, &error_abort); - object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base", + object_property_set_int(OBJECT(&s->gcr), "gcr-base", gcr_base, &error_abort); - object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->gic.mr), "gic", + object_property_set_link(OBJECT(&s->gcr), "gic", OBJECT(&s->gic.mr), &error_abort); - object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc", + object_property_set_link(OBJECT(&s->gcr), "cpc", OBJECT(&s->cpc.mr), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), &err)) { error_propagate(errp, err); diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index 0002bff695..82a6e3220e 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -290,8 +290,8 @@ static void mips_jazz_init(MachineState *machine, dev = qdev_new("dp8393x"); qdev_set_nic_properties(dev, nd); qdev_prop_set_uint8(dev, "it_shift", 2); - object_property_set_link(OBJECT(dev), OBJECT(rc4030_dma_mr), - "dma_mr", &error_abort); + object_property_set_link(OBJECT(dev), "dma_mr", + OBJECT(rc4030_dma_mr), &error_abort); sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, 0x80001000); diff --git a/hw/mips/malta.c b/hw/mips/malta.c index d95926a89c..a59e20c81c 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -1184,9 +1184,9 @@ static void create_cps(MachineState *ms, MaltaState *s, qemu_irq *cbus_irq, qemu_irq *i8259_irq) { object_initialize_child(OBJECT(s), "cps", &s->cps, TYPE_MIPS_CPS); - object_property_set_str(OBJECT(&s->cps), ms->cpu_type, "cpu-type", + object_property_set_str(OBJECT(&s->cps), "cpu-type", ms->cpu_type, &error_fatal); - object_property_set_int(OBJECT(&s->cps), ms->smp.cpus, "num-vp", + object_property_set_int(OBJECT(&s->cps), "num-vp", ms->smp.cpus, &error_fatal); sysbus_realize(SYS_BUS_DEVICE(&s->cps), &error_fatal); diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c index ec1cc1931a..269783366d 100644 --- a/hw/misc/iotkit-sysctl.c +++ b/hw/misc/iotkit-sysctl.c @@ -84,7 +84,7 @@ static void set_init_vtor(uint64_t cpuid, uint32_t vtor) if (cpuobj) { if (object_property_find(cpuobj, "init-svtor", NULL)) { - object_property_set_uint(cpuobj, vtor, "init-svtor", &error_abort); + object_property_set_uint(cpuobj, "init-svtor", vtor, &error_abort); } } } diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index be66bb7758..9b6e3f120e 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -134,7 +134,7 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide, sysbus_connect_irq(sysbus_dev, 0, irq0); sysbus_connect_irq(sysbus_dev, 1, irq1); qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid); - object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma", + object_property_set_link(OBJECT(ide), "dbdma", OBJECT(&s->dbdma), &error_abort); macio_ide_register_dma(ide); @@ -330,7 +330,7 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) if (ns->has_pmu) { /* GPIOs */ sysbus_dev = SYS_BUS_DEVICE(&ns->gpio); - object_property_set_link(OBJECT(&ns->gpio), OBJECT(pic_dev), "pic", + object_property_set_link(OBJECT(&ns->gpio), "pic", OBJECT(pic_dev), &error_abort); memory_region_add_subregion(&s->bar, 0x50, sysbus_mmio_get_region(sysbus_dev, 0)); @@ -340,7 +340,7 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) /* PMU */ object_initialize_child(OBJECT(s), "pmu", &s->pmu, TYPE_VIA_PMU); - object_property_set_link(OBJECT(&s->pmu), OBJECT(sysbus_dev), "gpio", + object_property_set_link(OBJECT(&s->pmu), "gpio", OBJECT(sysbus_dev), &error_abort); qdev_prop_set_bit(DEVICE(&s->pmu), "has-adb", ns->has_adb); if (!qdev_realize(DEVICE(&s->pmu), BUS(&s->macio_bus), &err)) { diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index 0594abd93a..a878056426 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -133,7 +133,7 @@ static void isa_ne2000_instance_init(Object *obj) object_property_add(obj, "bootindex", "int32", isa_ne2000_get_bootindex, isa_ne2000_set_bootindex, NULL, NULL); - object_property_set_int(obj, -1, "bootindex", NULL); + object_property_set_int(obj, "bootindex", -1, NULL); } static const TypeInfo ne2000_isa_info = { .name = TYPE_ISA_NE2000, diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 679a359f9a..1e48eb70c9 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -989,8 +989,8 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) (Object **) &cs->enet, object_property_allow_set_link, OBJ_PROP_LINK_STRONG); - object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &error_abort); - object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &error_abort); + object_property_set_link(OBJECT(ds), "enet", OBJECT(s), &error_abort); + object_property_set_link(OBJECT(cs), "enet", OBJECT(s), &error_abort); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf, diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index 7b547b1d78..94cb989136 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -999,9 +999,9 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) } /* LSI sources */ - object_property_set_link(OBJECT(&phb->lsis), OBJECT(pnv), "xics", - &error_abort); - object_property_set_int(OBJECT(&phb->lsis), PNV_PHB3_NUM_LSI, "nr-irqs", + object_property_set_link(OBJECT(&phb->lsis), "xics", OBJECT(pnv), + &error_abort); + object_property_set_int(OBJECT(&phb->lsis), "nr-irqs", PNV_PHB3_NUM_LSI, &error_abort); if (!qdev_realize(DEVICE(&phb->lsis), NULL, &local_err)) { error_propagate(errp, local_err); @@ -1015,11 +1015,11 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) phb->qirqs = qemu_allocate_irqs(ics_set_irq, &phb->lsis, phb->lsis.nr_irqs); /* MSI sources */ - object_property_set_link(OBJECT(&phb->msis), OBJECT(phb), "phb", - &error_abort); - object_property_set_link(OBJECT(&phb->msis), OBJECT(pnv), "xics", - &error_abort); - object_property_set_int(OBJECT(&phb->msis), PHB3_MAX_MSI, "nr-irqs", + object_property_set_link(OBJECT(&phb->msis), "phb", OBJECT(phb), + &error_abort); + object_property_set_link(OBJECT(&phb->msis), "xics", OBJECT(pnv), + &error_abort); + object_property_set_int(OBJECT(&phb->msis), "nr-irqs", PHB3_MAX_MSI, &error_abort); if (!qdev_realize(DEVICE(&phb->msis), NULL, &local_err)) { error_propagate(errp, local_err); @@ -1027,8 +1027,8 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) } /* Power Bus Common Queue */ - object_property_set_link(OBJECT(&phb->pbcq), OBJECT(phb), "phb", - &error_abort); + object_property_set_link(OBJECT(&phb->pbcq), "phb", OBJECT(phb), + &error_abort); if (!qdev_realize(DEVICE(&phb->pbcq), NULL, &local_err)) { error_propagate(errp, local_err); return; diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 53c2b1785b..a598c89eb0 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1216,8 +1216,8 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) } else { nr_irqs = PNV_PHB4_MAX_INTs >> 1; } - object_property_set_int(OBJECT(xsrc), nr_irqs, "nr-irqs", &error_fatal); - object_property_set_link(OBJECT(xsrc), OBJECT(phb), "xive", &error_fatal); + object_property_set_int(OBJECT(xsrc), "nr-irqs", nr_irqs, &error_fatal); + object_property_set_link(OBJECT(xsrc), "xive", OBJECT(phb), &error_fatal); if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { error_propagate(errp, local_err); return; diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index 45a1b3719d..088ab753aa 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -388,8 +388,8 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp) PnvPhb4PecStack *stack = &pec->stacks[i]; Object *stk_obj = OBJECT(stack); - object_property_set_int(stk_obj, i, "stack-no", &error_abort); - object_property_set_link(stk_obj, OBJECT(pec), "pec", &error_abort); + object_property_set_int(stk_obj, "stack-no", i, &error_abort); + object_property_set_link(stk_obj, "pec", OBJECT(pec), &error_abort); if (!qdev_realize(DEVICE(stk_obj), NULL, &local_err)) { error_propagate(errp, local_err); return; diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c index 367e408b91..4b93fd2b01 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -236,7 +236,7 @@ static void raven_pcihost_realizefn(DeviceState *d, Error **errp) /* According to PReP specification section 6.1.6 "System Interrupt * Assignments", all PCI interrupts are routed via IRQ 15 */ s->or_irq = OR_IRQ(object_new(TYPE_OR_IRQ)); - object_property_set_int(OBJECT(s->or_irq), PCI_NUM_PINS, "num-lines", + object_property_set_int(OBJECT(s->or_irq), "num-lines", PCI_NUM_PINS, &error_fatal); qdev_realize(DEVICE(s->or_irq), NULL, &error_fatal); sysbus_init_irq(dev, &s->or_irq->out_irq); @@ -307,7 +307,7 @@ static void raven_pcihost_initfn(Object *obj) object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_RAVEN_PCI_DEVICE); pci_dev = DEVICE(&s->pci_dev); - object_property_set_int(OBJECT(&s->pci_dev), PCI_DEVFN(0, 0), "addr", + object_property_set_int(OBJECT(&s->pci_dev), "addr", PCI_DEVFN(0, 0), NULL); qdev_prop_set_bit(pci_dev, "multifunction", false); } diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 828c5992ae..e42bd7a626 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -304,7 +304,7 @@ static void ppc_core99_init(MachineState *machine) /* 970 gets a U3 bus */ /* Uninorth AGP bus */ dev = qdev_new(TYPE_U3_AGP_HOST_BRIDGE); - object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", + object_property_set_link(OBJECT(dev), "pic", OBJECT(pic_dev), &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); uninorth_pci = U3_AGP_HOST_BRIDGE(dev); @@ -323,7 +323,7 @@ static void ppc_core99_init(MachineState *machine) /* Use values found on a real PowerMac */ /* Uninorth AGP bus */ dev = qdev_new(TYPE_UNI_NORTH_AGP_HOST_BRIDGE); - object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", + object_property_set_link(OBJECT(dev), "pic", OBJECT(pic_dev), &error_abort); s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); @@ -332,7 +332,7 @@ static void ppc_core99_init(MachineState *machine) /* Uninorth internal bus */ dev = qdev_new(TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE); - object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", + object_property_set_link(OBJECT(dev), "pic", OBJECT(pic_dev), &error_abort); s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); @@ -342,7 +342,7 @@ static void ppc_core99_init(MachineState *machine) /* Uninorth main bus */ dev = qdev_new(TYPE_UNI_NORTH_PCI_HOST_BRIDGE); qdev_prop_set_uint32(dev, "ofw-addr", 0xf2000000); - object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", + object_property_set_link(OBJECT(dev), "pic", OBJECT(pic_dev), &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); uninorth_pci = UNI_NORTH_PCI_HOST_BRIDGE(dev); @@ -380,7 +380,7 @@ static void ppc_core99_init(MachineState *machine) qdev_prop_set_uint64(dev, "frequency", tbfreq); qdev_prop_set_bit(dev, "has-pmu", has_pmu); qdev_prop_set_bit(dev, "has-adb", has_adb); - object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic", + object_property_set_link(OBJECT(macio), "pic", OBJECT(pic_dev), &error_abort); pci_realize_and_unref(macio, pci_bus, &error_fatal); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index f8c204ead7..7aba040f1b 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -254,7 +254,7 @@ static void ppc_heathrow_init(MachineState *machine) /* Grackle PCI host bridge */ dev = qdev_new(TYPE_GRACKLE_PCI_HOST_BRIDGE); qdev_prop_set_uint32(dev, "ofw-addr", 0x80000000); - object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", + object_property_set_link(OBJECT(dev), "pic", OBJECT(pic_dev), &error_abort); s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); @@ -281,7 +281,7 @@ static void ppc_heathrow_init(MachineState *machine) macio = pci_new(-1, TYPE_OLDWORLD_MACIO); dev = DEVICE(macio); qdev_prop_set_uint64(dev, "frequency", tbfreq); - object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic", + object_property_set_link(OBJECT(macio), "pic", OBJECT(pic_dev), &error_abort); pci_realize_and_unref(macio, pci_bus, &error_fatal); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index f2d70c3e18..194b457917 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -699,8 +699,8 @@ static void pnv_ipmi_bt_init(ISABus *bus, IPMIBmc *bmc, uint32_t irq) { ISADevice *dev = isa_new("isa-ipmi-bt"); - object_property_set_link(OBJECT(dev), OBJECT(bmc), "bmc", &error_fatal); - object_property_set_int(OBJECT(dev), irq, "irq", &error_fatal); + object_property_set_link(OBJECT(dev), "bmc", OBJECT(bmc), &error_fatal); + object_property_set_int(OBJECT(dev), "irq", irq, &error_fatal); isa_realize_and_unref(dev, bus, &error_fatal); } @@ -828,27 +828,27 @@ static void pnv_init(MachineState *machine) * way to specify different ranges for each chip */ if (i == 0) { - object_property_set_int(chip, machine->ram_size, "ram-size", + object_property_set_int(chip, "ram-size", machine->ram_size, &error_fatal); } snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i)); object_property_add_child(OBJECT(pnv), chip_name, chip); - object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id", + object_property_set_int(chip, "chip-id", PNV_CHIP_HWID(i), + &error_fatal); + object_property_set_int(chip, "nr-cores", machine->smp.cores, + &error_fatal); + object_property_set_int(chip, "nr-threads", machine->smp.threads, &error_fatal); - object_property_set_int(chip, machine->smp.cores, - "nr-cores", &error_fatal); - object_property_set_int(chip, machine->smp.threads, - "nr-threads", &error_fatal); /* * The POWER8 machine use the XICS interrupt interface. * Propagate the XICS fabric to the chip and its controllers. */ if (object_dynamic_cast(OBJECT(pnv), TYPE_XICS_FABRIC)) { - object_property_set_link(chip, OBJECT(pnv), "xics", &error_abort); + object_property_set_link(chip, "xics", OBJECT(pnv), &error_abort); } if (object_dynamic_cast(OBJECT(pnv), TYPE_XIVE_FABRIC)) { - object_property_set_link(chip, OBJECT(pnv), "xive-fabric", + object_property_set_link(chip, "xive-fabric", OBJECT(pnv), &error_abort); } sysbus_realize_and_unref(SYS_BUS_DEVICE(chip), &error_fatal); @@ -1136,10 +1136,10 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) } /* Processor Service Interface (PSI) Host Bridge */ - object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip), - "bar", &error_fatal); - object_property_set_link(OBJECT(&chip8->psi), OBJECT(chip8->xics), - ICS_PROP_XICS, &error_abort); + object_property_set_int(OBJECT(&chip8->psi), "bar", PNV_PSIHB_BASE(chip), + &error_fatal); + object_property_set_link(OBJECT(&chip8->psi), ICS_PROP_XICS, + OBJECT(chip8->xics), &error_abort); if (!qdev_realize(DEVICE(&chip8->psi), NULL, &local_err)) { error_propagate(errp, local_err); return; @@ -1148,7 +1148,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) &PNV_PSI(psi8)->xscom_regs); /* Create LPC controller */ - object_property_set_link(OBJECT(&chip8->lpc), OBJECT(&chip8->psi), "psi", + object_property_set_link(OBJECT(&chip8->lpc), "psi", OBJECT(&chip8->psi), &error_abort); qdev_realize(DEVICE(&chip8->lpc), NULL, &error_fatal); pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs); @@ -1168,7 +1168,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) } /* Create the simplified OCC model */ - object_property_set_link(OBJECT(&chip8->occ), OBJECT(&chip8->psi), "psi", + object_property_set_link(OBJECT(&chip8->occ), "psi", OBJECT(&chip8->psi), &error_abort); if (!qdev_realize(DEVICE(&chip8->occ), NULL, &local_err)) { error_propagate(errp, local_err); @@ -1181,7 +1181,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) &chip8->occ.sram_regs); /* HOMER */ - object_property_set_link(OBJECT(&chip8->homer), OBJECT(chip), "chip", + object_property_set_link(OBJECT(&chip8->homer), "chip", OBJECT(chip), &error_abort); if (!qdev_realize(DEVICE(&chip8->homer), NULL, &local_err)) { error_propagate(errp, local_err); @@ -1199,8 +1199,8 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) PnvPHB3 *phb = &chip8->phbs[i]; PnvPBCQState *pbcq = &phb->pbcq; - object_property_set_int(OBJECT(phb), i, "index", &error_fatal); - object_property_set_int(OBJECT(phb), chip->chip_id, "chip-id", + object_property_set_int(OBJECT(phb), "index", i, &error_fatal); + object_property_set_int(OBJECT(phb), "chip-id", chip->chip_id, &error_fatal); if (!sysbus_realize(SYS_BUS_DEVICE(phb), &local_err)) { error_propagate(errp, local_err); @@ -1347,7 +1347,7 @@ static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp) sizeof(*eq), TYPE_PNV_QUAD, &error_fatal, NULL); - object_property_set_int(OBJECT(eq), core_id, "id", &error_fatal); + object_property_set_int(OBJECT(eq), "id", core_id, &error_fatal); qdev_realize(DEVICE(eq), NULL, &error_fatal); pnv_xscom_add_subregion(chip, PNV9_XSCOM_EQ_BASE(eq->id), @@ -1368,18 +1368,18 @@ static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp) uint32_t pec_nest_base; uint32_t pec_pci_base; - object_property_set_int(OBJECT(pec), i, "index", &error_fatal); + object_property_set_int(OBJECT(pec), "index", i, &error_fatal); /* * PEC0 -> 1 stack * PEC1 -> 2 stacks * PEC2 -> 3 stacks */ - object_property_set_int(OBJECT(pec), i + 1, "num-stacks", + object_property_set_int(OBJECT(pec), "num-stacks", i + 1, &error_fatal); - object_property_set_int(OBJECT(pec), chip->chip_id, "chip-id", - &error_fatal); - object_property_set_link(OBJECT(pec), OBJECT(get_system_memory()), - "system-memory", &error_abort); + object_property_set_int(OBJECT(pec), "chip-id", chip->chip_id, + &error_fatal); + object_property_set_link(OBJECT(pec), "system-memory", + OBJECT(get_system_memory()), &error_abort); if (!qdev_realize(DEVICE(pec), NULL, &local_err)) { error_propagate(errp, local_err); return; @@ -1396,14 +1396,15 @@ static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp) PnvPhb4PecStack *stack = &pec->stacks[j]; Object *obj = OBJECT(&stack->phb); - object_property_set_int(obj, phb_id, "index", &error_fatal); - object_property_set_int(obj, chip->chip_id, "chip-id", + object_property_set_int(obj, "index", phb_id, &error_fatal); + object_property_set_int(obj, "chip-id", chip->chip_id, &error_fatal); - object_property_set_int(obj, PNV_PHB4_VERSION, "version", + object_property_set_int(obj, "version", PNV_PHB4_VERSION, &error_fatal); - object_property_set_int(obj, PNV_PHB4_DEVICE_ID, "device-id", + object_property_set_int(obj, "device-id", PNV_PHB4_DEVICE_ID, &error_fatal); - object_property_set_link(obj, OBJECT(stack), "stack", &error_abort); + object_property_set_link(obj, "stack", OBJECT(stack), + &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(obj), &local_err)) { error_propagate(errp, local_err); return; @@ -1453,15 +1454,15 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) } /* XIVE interrupt controller (POWER9) */ - object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_IC_BASE(chip), - "ic-bar", &error_fatal); - object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_VC_BASE(chip), - "vc-bar", &error_fatal); - object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_PC_BASE(chip), - "pc-bar", &error_fatal); - object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_TM_BASE(chip), - "tm-bar", &error_fatal); - object_property_set_link(OBJECT(&chip9->xive), OBJECT(chip), "chip", + object_property_set_int(OBJECT(&chip9->xive), "ic-bar", + PNV9_XIVE_IC_BASE(chip), &error_fatal); + object_property_set_int(OBJECT(&chip9->xive), "vc-bar", + PNV9_XIVE_VC_BASE(chip), &error_fatal); + object_property_set_int(OBJECT(&chip9->xive), "pc-bar", + PNV9_XIVE_PC_BASE(chip), &error_fatal); + object_property_set_int(OBJECT(&chip9->xive), "tm-bar", + PNV9_XIVE_TM_BASE(chip), &error_fatal); + object_property_set_link(OBJECT(&chip9->xive), "chip", OBJECT(chip), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&chip9->xive), &local_err)) { error_propagate(errp, local_err); @@ -1471,8 +1472,8 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) &chip9->xive.xscom_regs); /* Processor Service Interface (PSI) Host Bridge */ - object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip), - "bar", &error_fatal); + object_property_set_int(OBJECT(&chip9->psi), "bar", PNV9_PSIHB_BASE(chip), + &error_fatal); if (!qdev_realize(DEVICE(&chip9->psi), NULL, &local_err)) { error_propagate(errp, local_err); return; @@ -1481,7 +1482,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) &PNV_PSI(psi9)->xscom_regs); /* LPC */ - object_property_set_link(OBJECT(&chip9->lpc), OBJECT(&chip9->psi), "psi", + object_property_set_link(OBJECT(&chip9->lpc), "psi", OBJECT(&chip9->psi), &error_abort); if (!qdev_realize(DEVICE(&chip9->lpc), NULL, &local_err)) { error_propagate(errp, local_err); @@ -1494,7 +1495,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) (uint64_t) PNV9_LPCM_BASE(chip)); /* Create the simplified OCC model */ - object_property_set_link(OBJECT(&chip9->occ), OBJECT(&chip9->psi), "psi", + object_property_set_link(OBJECT(&chip9->occ), "psi", OBJECT(&chip9->psi), &error_abort); if (!qdev_realize(DEVICE(&chip9->occ), NULL, &local_err)) { error_propagate(errp, local_err); @@ -1507,7 +1508,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) &chip9->occ.sram_regs); /* HOMER */ - object_property_set_link(OBJECT(&chip9->homer), OBJECT(chip), "chip", + object_property_set_link(OBJECT(&chip9->homer), "chip", OBJECT(chip), &error_abort); if (!qdev_realize(DEVICE(&chip9->homer), NULL, &local_err)) { error_propagate(errp, local_err); @@ -1588,8 +1589,8 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) } /* Processor Service Interface (PSI) Host Bridge */ - object_property_set_int(OBJECT(&chip10->psi), PNV10_PSIHB_BASE(chip), - "bar", &error_fatal); + object_property_set_int(OBJECT(&chip10->psi), "bar", + PNV10_PSIHB_BASE(chip), &error_fatal); if (!qdev_realize(DEVICE(&chip10->psi), NULL, &local_err)) { error_propagate(errp, local_err); return; @@ -1598,8 +1599,8 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) &PNV_PSI(&chip10->psi)->xscom_regs); /* LPC */ - object_property_set_link(OBJECT(&chip10->lpc), OBJECT(&chip10->psi), "psi", - &error_abort); + object_property_set_link(OBJECT(&chip10->lpc), "psi", + OBJECT(&chip10->psi), &error_abort); if (!qdev_realize(DEVICE(&chip10->lpc), NULL, &local_err)) { error_propagate(errp, local_err); return; @@ -1707,16 +1708,15 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp) snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid); object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core)); chip->cores[i] = pnv_core; - object_property_set_int(OBJECT(pnv_core), chip->nr_threads, - "nr-threads", &error_fatal); - object_property_set_int(OBJECT(pnv_core), core_hwid, - CPU_CORE_PROP_CORE_ID, &error_fatal); - object_property_set_int(OBJECT(pnv_core), - pcc->core_pir(chip, core_hwid), - "pir", &error_fatal); - object_property_set_int(OBJECT(pnv_core), pnv->fw_load_addr, - "hrmor", &error_fatal); - object_property_set_link(OBJECT(pnv_core), OBJECT(chip), "chip", + object_property_set_int(OBJECT(pnv_core), "nr-threads", + chip->nr_threads, &error_fatal); + object_property_set_int(OBJECT(pnv_core), CPU_CORE_PROP_CORE_ID, + core_hwid, &error_fatal); + object_property_set_int(OBJECT(pnv_core), "pir", + pcc->core_pir(chip, core_hwid), &error_fatal); + object_property_set_int(OBJECT(pnv_core), "hrmor", pnv->fw_load_addr, + &error_fatal); + object_property_set_link(OBJECT(pnv_core), "chip", OBJECT(chip), &error_abort); qdev_realize(DEVICE(pnv_core), NULL, &error_fatal); diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 7efe6e138f..e23276983f 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -505,7 +505,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp) unsigned int i; /* Create PSI interrupt control source */ - object_property_set_int(OBJECT(ics), PSI_NUM_INTERRUPTS, "nr-irqs", &err); + object_property_set_int(OBJECT(ics), "nr-irqs", PSI_NUM_INTERRUPTS, &err); if (err) { error_propagate(errp, err); return; @@ -845,11 +845,10 @@ static void pnv_psi_power9_realize(DeviceState *dev, Error **errp) int i; /* This is the only device with 4k ESB pages */ - object_property_set_int(OBJECT(xsrc), XIVE_ESB_4K, "shift", + object_property_set_int(OBJECT(xsrc), "shift", XIVE_ESB_4K, &error_fatal); + object_property_set_int(OBJECT(xsrc), "nr-irqs", PSIHB9_NUM_IRQS, &error_fatal); - object_property_set_int(OBJECT(xsrc), PSIHB9_NUM_IRQS, "nr-irqs", - &error_fatal); - object_property_set_link(OBJECT(xsrc), OBJECT(psi), "xive", &error_abort); + object_property_set_link(OBJECT(xsrc), "xive", OBJECT(psi), &error_abort); if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { error_propagate(errp, local_err); return; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index f6f034d039..68e8b504b5 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2624,9 +2624,9 @@ static void spapr_init_cpus(SpaprMachineState *spapr) nr_threads = smp_cpus - i * smp_threads; } - object_property_set_int(core, nr_threads, "nr-threads", + object_property_set_int(core, "nr-threads", nr_threads, &error_fatal); - object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID, + object_property_set_int(core, CPU_CORE_PROP_CORE_ID, core_id, &error_fatal); qdev_realize(DEVICE(core), NULL, &error_fatal); diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 1d0db57fc5..eb55171d70 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -308,9 +308,9 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) obj = object_new(TYPE_ICS_SPAPR); object_property_add_child(OBJECT(spapr), "ics", obj); - object_property_set_link(obj, OBJECT(spapr), ICS_PROP_XICS, + object_property_set_link(obj, ICS_PROP_XICS, OBJECT(spapr), &error_abort); - object_property_set_int(obj, smc->nr_xirqs, "nr-irqs", &error_abort); + object_property_set_int(obj, "nr-irqs", smc->nr_xirqs, &error_abort); if (!qdev_realize(DEVICE(obj), NULL, &local_err)) { error_propagate(errp, local_err); return; @@ -331,7 +331,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) * priority */ qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3); - object_property_set_link(OBJECT(dev), OBJECT(spapr), "xive-fabric", + object_property_set_link(OBJECT(dev), "xive-fabric", OBJECT(spapr), &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 0f00e2421f..223bb8f464 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -2418,7 +2418,7 @@ static int spapr_switch_one_vga(DeviceState *dev, void *opaque) if (object_dynamic_cast(OBJECT(dev), "VGA") || object_dynamic_cast(OBJECT(dev), "secondary-vga")) { - object_property_set_bool(OBJECT(dev), be, "big-endian-framebuffer", + object_property_set_bool(OBJECT(dev), "big-endian-framebuffer", be, &error_abort); } return 0; diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 5fce455d30..7003b1f62d 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -108,9 +108,9 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) MemoryRegion *sys_mem = get_system_memory(); Error *err = NULL; - object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type", + object_property_set_str(OBJECT(&s->cpus), "cpu-type", ms->cpu_type, &error_abort); - object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts", + object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 1b2e95a977..f2df06cc43 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -175,7 +175,7 @@ static void sifive_e_soc_init(Object *obj) SiFiveESoCState *s = RISCV_E_SOC(obj); object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); - object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts", + object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus, &error_abort); object_initialize_child(obj, "riscv.sifive.e.gpio0", &s->gpio, TYPE_SIFIVE_GPIO); @@ -190,7 +190,7 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp) SiFiveESoCState *s = RISCV_E_SOC(dev); MemoryRegion *sys_mem = get_system_memory(); - object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type", + object_property_set_str(OBJECT(&s->cpus), "cpu-type", ms->cpu_type, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 7b9e7fdc7f..e70253d58f 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -383,8 +383,8 @@ static void sifive_u_machine_init(MachineState *machine) /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); - object_property_set_uint(OBJECT(&s->soc), s->serial, "serial", - &error_abort); + object_property_set_uint(OBJECT(&s->soc), "serial", s->serial, + &error_abort); qdev_realize(DEVICE(&s->soc), NULL, &error_abort); /* register RAM */ @@ -708,7 +708,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(DEVICE(&s->gem), nd); } - object_property_set_int(OBJECT(&s->gem), GEM_REVISION, "revision", + object_property_set_int(OBJECT(&s->gem), "revision", GEM_REVISION, &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem), &err)) { error_propagate(errp, err); diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 3c87e04fdc..c107bf3ba1 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -171,9 +171,9 @@ static void spike_board_init(MachineState *machine) /* Initialize SOC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_HART_ARRAY); - object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type", + object_property_set_str(OBJECT(&s->soc), "cpu-type", machine->cpu_type, &error_abort); - object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts", + object_property_set_int(OBJECT(&s->soc), "num-harts", smp_cpus, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_abort); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 616db6f5ac..f7630c8a89 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -487,9 +487,9 @@ static void virt_machine_init(MachineState *machine) /* Initialize SOC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_HART_ARRAY); - object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type", + object_property_set_str(OBJECT(&s->soc), "cpu-type", machine->cpu_type, &error_abort); - object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts", + object_property_set_int(OBJECT(&s->soc), "num-harts", smp_cpus, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_abort); diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c index b8a56fa7af..54992ebe57 100644 --- a/hw/rx/rx-gdbsim.c +++ b/hw/rx/rx-gdbsim.c @@ -101,12 +101,12 @@ static void rx_gdbsim_init(MachineState *machine) /* Initialize MCU */ object_initialize_child(OBJECT(machine), "mcu", &s->mcu, rxc->mcu_name); - object_property_set_link(OBJECT(&s->mcu), OBJECT(sysmem), - "main-bus", &error_abort); - object_property_set_uint(OBJECT(&s->mcu), rxc->xtal_freq_hz, - "xtal-frequency-hz", &error_abort); - object_property_set_bool(OBJECT(&s->mcu), kernel_filename != NULL, - "load-kernel", &error_abort); + object_property_set_link(OBJECT(&s->mcu), "main-bus", OBJECT(sysmem), + &error_abort); + object_property_set_uint(OBJECT(&s->mcu), "xtal-frequency-hz", + rxc->xtal_freq_hz, &error_abort); + object_property_set_bool(OBJECT(&s->mcu), "load-kernel", + kernel_filename != NULL, &error_abort); qdev_realize(DEVICE(&s->mcu), NULL, &error_abort); /* Load kernel and dtb */ diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index ce21494c08..7c893e5683 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -555,9 +555,9 @@ static void update_machine_ipl_properties(IplParameterBlock *iplb) ascii_loadparm[i] = ebcdic2ascii[(uint8_t) ebcdic_loadparm[i]]; } ascii_loadparm[i] = 0; - object_property_set_str(machine, ascii_loadparm, "loadparm", &err); + object_property_set_str(machine, "loadparm", ascii_loadparm, &err); } else { - object_property_set_str(machine, "", "loadparm", &err); + object_property_set_str(machine, "loadparm", "", &err); } if (err) { warn_report_err(err); diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 1e4537f0e3..a7b2a15a96 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -824,7 +824,7 @@ static S390PCIBusDevice *s390_pci_device_new(S390pciState *s, return NULL; } - object_property_set_str(OBJECT(dev), target, "target", &local_err); + object_property_set_str(OBJECT(dev), "target", target, &local_err); if (local_err) { object_unparent(OBJECT(dev)); error_propagate_prepend(errp, local_err, diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index 1e036cc602..db2f49cb27 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -401,7 +401,7 @@ static void s390_skeys_instance_init(Object *obj) object_property_add_bool(obj, "migration-enabled", s390_skeys_get_migration_enabled, s390_skeys_set_migration_enabled); - object_property_set_bool(obj, true, "migration-enabled", NULL); + object_property_set_bool(obj, "migration-enabled", true, NULL); } static void s390_skeys_class_init(ObjectClass *oc, void *data) diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index 0144b9021c..4441e1d331 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -388,7 +388,7 @@ static void s390_stattrib_instance_init(Object *obj) object_property_add_bool(obj, "migration-enabled", s390_stattrib_get_migration_enabled, s390_stattrib_set_migration_enabled); - object_property_set_bool(obj, true, "migration-enabled", NULL); + object_property_set_bool(obj, "migration-enabled", true, NULL); sas->migration_cur_gfn = 0; } diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 023fd25f2b..07609a9a58 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -70,7 +70,7 @@ static S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, S390CPU *cpu = S390_CPU(object_new(typename)); Error *err = NULL; - object_property_set_int(OBJECT(cpu), core_id, "core-id", &err); + object_property_set_int(OBJECT(cpu), "core-id", core_id, &err); if (err != NULL) { goto out; } @@ -736,14 +736,14 @@ static inline void s390_machine_initfn(Object *obj) machine_set_aes_key_wrap); object_property_set_description(obj, "aes-key-wrap", "enable/disable AES key wrapping using the CPACF wrapping key"); - object_property_set_bool(obj, true, "aes-key-wrap", NULL); + object_property_set_bool(obj, "aes-key-wrap", true, NULL); object_property_add_bool(obj, "dea-key-wrap", machine_get_dea_key_wrap, machine_set_dea_key_wrap); object_property_set_description(obj, "dea-key-wrap", "enable/disable DEA key wrapping using the CPACF wrapping key"); - object_property_set_bool(obj, true, "dea-key-wrap", NULL); + object_property_set_bool(obj, "dea-key-wrap", true, NULL); object_property_add_str(obj, "loadparm", machine_get_loadparm, machine_set_loadparm); object_property_set_description(obj, "loadparm", diff --git a/hw/s390x/virtio-ccw-crypto.c b/hw/s390x/virtio-ccw-crypto.c index 36cfdf865c..5720e84fc9 100644 --- a/hw/s390x/virtio-ccw-crypto.c +++ b/hw/s390x/virtio-ccw-crypto.c @@ -26,9 +26,8 @@ static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) return; } - object_property_set_link(OBJECT(vdev), - OBJECT(dev->vdev.conf.cryptodev), "cryptodev", - NULL); + object_property_set_link(OBJECT(vdev), "cryptodev", + OBJECT(dev->vdev.conf.cryptodev), NULL); } static void virtio_ccw_crypto_instance_init(Object *obj) diff --git a/hw/s390x/virtio-ccw-rng.c b/hw/s390x/virtio-ccw-rng.c index 513f85ac63..8cf01ce76c 100644 --- a/hw/s390x/virtio-ccw-rng.c +++ b/hw/s390x/virtio-ccw-rng.c @@ -27,8 +27,7 @@ static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) return; } - object_property_set_link(OBJECT(dev), - OBJECT(dev->vdev.conf.rng), "rng", + object_property_set_link(OBJECT(dev), "rng", OBJECT(dev->vdev.conf.rng), NULL); } diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 365d09fb48..4860863f1d 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -268,7 +268,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, qdev_prop_set_uint32(dev, "scsi-id", unit); if (bootindex >= 0) { - object_property_set_int(OBJECT(dev), bootindex, "bootindex", + object_property_set_int(OBJECT(dev), "bootindex", bootindex, &error_abort); } if (object_property_find(OBJECT(dev), "removable", NULL)) { @@ -283,7 +283,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, object_unparent(OBJECT(dev)); return NULL; } - object_property_set_bool(OBJECT(dev), share_rw, "share-rw", &err); + object_property_set_bool(OBJECT(dev), "share-rw", share_rw, &err); if (err != NULL) { error_propagate(errp, err); object_unparent(OBJECT(dev)); diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c index 2d0d5651e3..29aa11df66 100644 --- a/hw/sd/aspeed_sdhci.c +++ b/hw/sd/aspeed_sdhci.c @@ -132,14 +132,14 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp) Object *sdhci_slot = OBJECT(&sdhci->slots[i]); SysBusDevice *sbd_slot = SYS_BUS_DEVICE(&sdhci->slots[i]); - object_property_set_int(sdhci_slot, 2, "sd-spec-version", &err); + object_property_set_int(sdhci_slot, "sd-spec-version", 2, &err); if (err) { error_propagate(errp, err); return; } - object_property_set_uint(sdhci_slot, ASPEED_SDHCI_CAPABILITIES, - "capareg", &err); + object_property_set_uint(sdhci_slot, "capareg", + ASPEED_SDHCI_CAPABILITIES, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index c57d76b1c8..d4b57cda80 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -261,7 +261,7 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) } } - object_property_set_bool(OBJECT(carddev), true, "spi", &err); + object_property_set_bool(OBJECT(carddev), "spi", true, &err); if (err) { goto fail; } diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index ee52b5cbbc..9be930415f 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -878,7 +878,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, /* Create and map RAM frontend */ dev = qdev_new("memory"); - object_property_set_link(OBJECT(dev), ram_memdev, "memdev", &error_fatal); + object_property_set_link(OBJECT(dev), "memdev", ram_memdev, &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 9c8655cffc..9e30203dcc 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -579,7 +579,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, sabre = SABRE_DEVICE(qdev_new(TYPE_SABRE)); qdev_prop_set_uint64(DEVICE(sabre), "special-base", PBM_SPECIAL_BASE); qdev_prop_set_uint64(DEVICE(sabre), "mem-base", PBM_MEM_BASE); - object_property_set_link(OBJECT(sabre), OBJECT(iommu), "iommu", + object_property_set_link(OBJECT(sabre), "iommu", OBJECT(iommu), &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(sabre), &error_fatal); diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 721665191e..2ed6a8df24 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -748,7 +748,7 @@ static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name, s->conf.bootindex = boot_index; if (s->scsi_dev) { - object_property_set_int(OBJECT(s->scsi_dev), boot_index, "bootindex", + object_property_set_int(OBJECT(s->scsi_dev), "bootindex", boot_index, &error_abort); } @@ -769,7 +769,7 @@ static void usb_msd_instance_init(Object *obj) object_property_add(obj, "bootindex", "int32", usb_msd_get_bootindex, usb_msd_set_bootindex, NULL, NULL); - object_property_set_int(obj, -1, "bootindex", NULL); + object_property_set_int(obj, "bootindex", -1, NULL); } static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data) diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c index 0755722288..f1cc979d33 100644 --- a/hw/virtio/virtio-crypto-pci.c +++ b/hw/virtio/virtio-crypto-pci.c @@ -57,9 +57,8 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) if (!qdev_realize(vdev, BUS(&vpci_dev->bus), errp)) { return; } - object_property_set_link(OBJECT(vcrypto), - OBJECT(vcrypto->vdev.conf.cryptodev), "cryptodev", - NULL); + object_property_set_link(OBJECT(vcrypto), "cryptodev", + OBJECT(vcrypto->vdev.conf.cryptodev), NULL); } static void virtio_crypto_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c index 592abc9279..ba62d60a0a 100644 --- a/hw/virtio/virtio-iommu-pci.c +++ b/hw/virtio/virtio-iommu-pci.c @@ -65,9 +65,9 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) error_append_hint(errp, "Valid values are 0 and 1\n"); } } - object_property_set_link(OBJECT(dev), + object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(pci_get_bus(&vpci_dev->pci_dev)), - "primary-bus", &error_abort); + &error_abort); qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } diff --git a/hw/virtio/virtio-mem-pci.c b/hw/virtio/virtio-mem-pci.c index 1a8e854123..d375280ee1 100644 --- a/hw/virtio/virtio-mem-pci.c +++ b/hw/virtio/virtio-mem-pci.c @@ -22,13 +22,13 @@ static void virtio_mem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) DeviceState *vdev = DEVICE(&mem_pci->vdev); qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), "realized", true, errp); } static void virtio_mem_pci_set_addr(MemoryDeviceState *md, uint64_t addr, Error **errp) { - object_property_set_uint(OBJECT(md), addr, VIRTIO_MEM_ADDR_PROP, errp); + object_property_set_uint(OBJECT(md), VIRTIO_MEM_ADDR_PROP, addr, errp); } static uint64_t virtio_mem_pci_get_addr(const MemoryDeviceState *md) diff --git a/hw/virtio/virtio-pmem-pci.c b/hw/virtio/virtio-pmem-pci.c index 11d0c8ebc6..21a457d151 100644 --- a/hw/virtio/virtio-pmem-pci.c +++ b/hw/virtio/virtio-pmem-pci.c @@ -28,7 +28,7 @@ static void virtio_pmem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) static void virtio_pmem_pci_set_addr(MemoryDeviceState *md, uint64_t addr, Error **errp) { - object_property_set_uint(OBJECT(md), addr, VIRTIO_PMEM_ADDR_PROP, errp); + object_property_set_uint(OBJECT(md), VIRTIO_PMEM_ADDR_PROP, addr, errp); } static uint64_t virtio_pmem_pci_get_addr(const MemoryDeviceState *md) diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c index 20ce1b113b..8b11c4b425 100644 --- a/hw/virtio/virtio-rng-pci.c +++ b/hw/virtio/virtio-rng-pci.c @@ -41,8 +41,7 @@ static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) return; } - object_property_set_link(OBJECT(vrng), - OBJECT(vrng->vdev.conf.rng), "rng", + object_property_set_link(OBJECT(vrng), "rng", OBJECT(vrng->vdev.conf.rng), NULL); } diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index a8df41b11b..85f7163e2d 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -208,8 +208,8 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp) /* The child property took a reference, we can safely drop ours now */ object_unref(default_backend); - object_property_set_link(OBJECT(dev), default_backend, - "rng", &error_abort); + object_property_set_link(OBJECT(dev), "rng", default_backend, + &error_abort); } vrng->rng = vrng->conf.rng; diff --git a/include/hw/audio/pcspk.h b/include/hw/audio/pcspk.h index 06cba00b83..9506179587 100644 --- a/include/hw/audio/pcspk.h +++ b/include/hw/audio/pcspk.h @@ -33,7 +33,7 @@ static inline void pcspk_init(ISADevice *isadev, ISABus *bus, ISADevice *pit) { - object_property_set_link(OBJECT(isadev), OBJECT(pit), "pit", NULL); + object_property_set_link(OBJECT(isadev), "pit", OBJECT(pit), NULL); isa_realize_and_unref(isadev, bus, &error_fatal); } diff --git a/include/qom/object.h b/include/qom/object.h index 19c9adeebe..7c2c6791a4 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1203,26 +1203,26 @@ void object_unparent(Object *obj); /** * object_property_get: * @obj: the object + * @name: the name of the property * @v: the visitor that will receive the property value. This should be an * Output visitor and the data will be written with @name as the name. - * @name: the name of the property * @errp: returns an error if this function fails * * Reads a property from a object. */ -void object_property_get(Object *obj, Visitor *v, const char *name, +void object_property_get(Object *obj, const char *name, Visitor *v, Error **errp); /** * object_property_set_str: - * @value: the value to be written to the property * @name: the name of the property + * @value: the value to be written to the property * @errp: returns an error if this function fails * * Writes a string value to a property. */ -void object_property_set_str(Object *obj, const char *value, - const char *name, Error **errp); +void object_property_set_str(Object *obj, const char *name, + const char *value, Error **errp); /** * object_property_get_str: @@ -1239,8 +1239,8 @@ char *object_property_get_str(Object *obj, const char *name, /** * object_property_set_link: - * @value: the value to be written to the property * @name: the name of the property + * @value: the value to be written to the property * @errp: returns an error if this function fails * * Writes an object's canonical path to a property. @@ -1250,8 +1250,8 @@ char *object_property_get_str(Object *obj, const char *name, * unreferenced, and a reference is added to the new target object. * */ -void object_property_set_link(Object *obj, Object *value, - const char *name, Error **errp); +void object_property_set_link(Object *obj, const char *name, + Object *value, Error **errp); /** * object_property_get_link: @@ -1268,14 +1268,14 @@ Object *object_property_get_link(Object *obj, const char *name, /** * object_property_set_bool: - * @value: the value to be written to the property * @name: the name of the property + * @value: the value to be written to the property * @errp: returns an error if this function fails * * Writes a bool value to a property. */ -void object_property_set_bool(Object *obj, bool value, - const char *name, Error **errp); +void object_property_set_bool(Object *obj, const char *name, + bool value, Error **errp); /** * object_property_get_bool: @@ -1291,14 +1291,14 @@ bool object_property_get_bool(Object *obj, const char *name, /** * object_property_set_int: - * @value: the value to be written to the property * @name: the name of the property + * @value: the value to be written to the property * @errp: returns an error if this function fails * * Writes an integer value to a property. */ -void object_property_set_int(Object *obj, int64_t value, - const char *name, Error **errp); +void object_property_set_int(Object *obj, const char *name, + int64_t value, Error **errp); /** * object_property_get_int: @@ -1314,14 +1314,14 @@ int64_t object_property_get_int(Object *obj, const char *name, /** * object_property_set_uint: - * @value: the value to be written to the property * @name: the name of the property + * @value: the value to be written to the property * @errp: returns an error if this function fails * * Writes an unsigned integer value to a property. */ -void object_property_set_uint(Object *obj, uint64_t value, - const char *name, Error **errp); +void object_property_set_uint(Object *obj, const char *name, + uint64_t value, Error **errp); /** * object_property_get_uint: @@ -1352,28 +1352,28 @@ int object_property_get_enum(Object *obj, const char *name, /** * object_property_set: * @obj: the object + * @name: the name of the property * @v: the visitor that will be used to write the property value. This should * be an Input visitor and the data will be first read with @name as the * name and then written as the property value. - * @name: the name of the property * @errp: returns an error if this function fails * * Writes a property to a object. */ -void object_property_set(Object *obj, Visitor *v, const char *name, +void object_property_set(Object *obj, const char *name, Visitor *v, Error **errp); /** * object_property_parse: * @obj: the object - * @string: the string that will be used to parse the property value. * @name: the name of the property + * @string: the string that will be used to parse the property value. * @errp: returns an error if this function fails * * Parses a string and writes the result into a property of an object. */ -void object_property_parse(Object *obj, const char *string, - const char *name, Error **errp); +void object_property_parse(Object *obj, const char *name, + const char *string, Error **errp); /** * object_property_print: diff --git a/include/qom/qom-qobject.h b/include/qom/qom-qobject.h index 82136e6e80..ad9a98dd62 100644 --- a/include/qom/qom-qobject.h +++ b/include/qom/qom-qobject.h @@ -28,13 +28,14 @@ struct QObject *object_property_get_qobject(Object *obj, const char *name, /** * object_property_set_qobject: * @obj: the object - * @ret: The value that will be written to the property. * @name: the name of the property + * @value: The value that will be written to the property. * @errp: returns an error if this function fails * * Writes a property to a object. */ -void object_property_set_qobject(Object *obj, struct QObject *qobj, - const char *name, struct Error **errp); +void object_property_set_qobject(Object *obj, + const char *name, struct QObject *value, + struct Error **errp); #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 82afadcea0..98ea86ca81 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7722,7 +7722,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, if (CPU_NEXT(first_cpu)) { TaskState *ts = cpu->opaque; - object_property_set_bool(OBJECT(cpu), false, "realized", NULL); + object_property_set_bool(OBJECT(cpu), "realized", false, NULL); object_unref(OBJECT(cpu)); /* * At this point the CPU should be unrealized and removed diff --git a/net/filter.c b/net/filter.c index caf6443655..eac8ba1e9c 100644 --- a/net/filter.c +++ b/net/filter.c @@ -338,7 +338,7 @@ static void default_handle_event(NetFilterState *nf, int event, Error **errp) case COLO_EVENT_CHECKPOINT: break; case COLO_EVENT_FAILOVER: - object_property_set_str(OBJECT(nf), "off", "status", errp); + object_property_set_str(OBJECT(nf), "status", "off", errp); break; default: break; diff --git a/net/net.c b/net/net.c index 6fe74c80bb..7fddcebaa2 100644 --- a/net/net.c +++ b/net/net.c @@ -1164,7 +1164,7 @@ static void netfilter_print_info(Monitor *mon, NetFilterState *nf) continue; } v = string_output_visitor_new(false, &str); - object_property_get(OBJECT(nf), v, prop->name, NULL); + object_property_get(OBJECT(nf), prop->name, v, NULL); visit_complete(v, &str); visit_free(v); monitor_printf(mon, ",%s=%s", prop->name, str); diff --git a/qdev-monitor.c b/qdev-monitor.c index cbcbbb5d50..f4c6e6073a 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -186,7 +186,7 @@ static int set_property(void *opaque, const char *name, const char *value, if (strcmp(name, "bus") == 0) return 0; - object_property_parse(obj, value, name, &err); + object_property_parse(obj, name, value, &err); if (err != NULL) { error_propagate(errp, err); return -1; diff --git a/qom/object.c b/qom/object.c index be8fed6688..7d75c452b9 100644 --- a/qom/object.c +++ b/qom/object.c @@ -404,7 +404,7 @@ void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp continue; } p->used = true; - object_property_parse(obj, p->value, p->property, &err); + object_property_parse(obj, p->property, p->value, &err); if (err != NULL) { error_prepend(&err, "can't apply global %s.%s=%s: ", p->driver, p->property, p->value); @@ -798,7 +798,7 @@ int object_set_propv(Object *obj, const char *value = va_arg(vargs, char *); g_assert(value != NULL); - object_property_parse(obj, value, propname, &local_err); + object_property_parse(obj, propname, value, &local_err); if (local_err) { error_propagate(errp, local_err); return -1; @@ -1312,7 +1312,7 @@ void object_property_del(Object *obj, const char *name) g_hash_table_remove(obj->properties, name); } -void object_property_get(Object *obj, Visitor *v, const char *name, +void object_property_get(Object *obj, const char *name, Visitor *v, Error **errp) { ObjectProperty *prop = object_property_find(obj, name, errp); @@ -1327,7 +1327,7 @@ void object_property_get(Object *obj, Visitor *v, const char *name, } } -void object_property_set(Object *obj, Visitor *v, const char *name, +void object_property_set(Object *obj, const char *name, Visitor *v, Error **errp) { ObjectProperty *prop = object_property_find(obj, name, errp); @@ -1342,11 +1342,11 @@ void object_property_set(Object *obj, Visitor *v, const char *name, } } -void object_property_set_str(Object *obj, const char *value, - const char *name, Error **errp) +void object_property_set_str(Object *obj, const char *name, + const char *value, Error **errp) { QString *qstr = qstring_from_str(value); - object_property_set_qobject(obj, QOBJECT(qstr), name, errp); + object_property_set_qobject(obj, name, QOBJECT(qstr), errp); qobject_unref(qstr); } @@ -1370,15 +1370,15 @@ char *object_property_get_str(Object *obj, const char *name, return retval; } -void object_property_set_link(Object *obj, Object *value, - const char *name, Error **errp) +void object_property_set_link(Object *obj, const char *name, + Object *value, Error **errp) { if (value) { char *path = object_get_canonical_path(value); - object_property_set_str(obj, path, name, errp); + object_property_set_str(obj, name, path, errp); g_free(path); } else { - object_property_set_str(obj, "", name, errp); + object_property_set_str(obj, name, "", errp); } } @@ -1400,11 +1400,11 @@ Object *object_property_get_link(Object *obj, const char *name, return target; } -void object_property_set_bool(Object *obj, bool value, - const char *name, Error **errp) +void object_property_set_bool(Object *obj, const char *name, + bool value, Error **errp) { QBool *qbool = qbool_from_bool(value); - object_property_set_qobject(obj, QOBJECT(qbool), name, errp); + object_property_set_qobject(obj, name, QOBJECT(qbool), errp); qobject_unref(qbool); } @@ -1431,11 +1431,11 @@ bool object_property_get_bool(Object *obj, const char *name, return retval; } -void object_property_set_int(Object *obj, int64_t value, - const char *name, Error **errp) +void object_property_set_int(Object *obj, const char *name, + int64_t value, Error **errp) { QNum *qnum = qnum_from_int(value); - object_property_set_qobject(obj, QOBJECT(qnum), name, errp); + object_property_set_qobject(obj, name, QOBJECT(qnum), errp); qobject_unref(qnum); } @@ -1500,12 +1500,12 @@ void object_property_set_default_uint(ObjectProperty *prop, uint64_t value) object_property_set_default(prop, QOBJECT(qnum_from_uint(value))); } -void object_property_set_uint(Object *obj, uint64_t value, - const char *name, Error **errp) +void object_property_set_uint(Object *obj, const char *name, + uint64_t value, Error **errp) { QNum *qnum = qnum_from_uint(value); - object_property_set_qobject(obj, QOBJECT(qnum), name, errp); + object_property_set_qobject(obj, name, QOBJECT(qnum), errp); qobject_unref(qnum); } @@ -1567,11 +1567,11 @@ int object_property_get_enum(Object *obj, const char *name, return ret; } -void object_property_parse(Object *obj, const char *string, - const char *name, Error **errp) +void object_property_parse(Object *obj, const char *name, + const char *string, Error **errp) { Visitor *v = string_input_visitor_new(string); - object_property_set(obj, v, name, errp); + object_property_set(obj, name, v, errp); visit_free(v); } @@ -1583,7 +1583,7 @@ char *object_property_print(Object *obj, const char *name, bool human, Error *local_err = NULL; v = string_output_visitor_new(human, &string); - object_property_get(obj, v, name, &local_err); + object_property_get(obj, name, v, &local_err); if (local_err) { error_propagate(errp, local_err); goto out; @@ -2645,7 +2645,7 @@ static void property_get_alias(Object *obj, Visitor *v, const char *name, { AliasProperty *prop = opaque; - object_property_get(prop->target_obj, v, prop->target_name, errp); + object_property_get(prop->target_obj, prop->target_name, v, errp); } static void property_set_alias(Object *obj, Visitor *v, const char *name, @@ -2653,7 +2653,7 @@ static void property_set_alias(Object *obj, Visitor *v, const char *name, { AliasProperty *prop = opaque; - object_property_set(prop->target_obj, v, prop->target_name, errp); + object_property_set(prop->target_obj, prop->target_name, v, errp); } static Object *property_resolve_alias(Object *obj, void *opaque, diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 3085ae0b31..4c59ee56d5 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -67,7 +67,7 @@ Object *user_creatable_add_type(const char *type, const char *id, goto out; } for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) { - object_property_set(obj, v, e->key, &local_err); + object_property_set(obj, e->key, v, &local_err); if (local_err) { break; } diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index b0abe84cb1..9ed8bb1c9f 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -57,7 +57,7 @@ void hmp_qom_set(Monitor *mon, const QDict *qdict) error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found", path); } else { - object_property_parse(obj, value, property, &err); + object_property_parse(obj, property, value, &err); } } else { QObject *obj = qobject_from_json(value, &err); diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c index 5e2c8cbf33..310ab2d048 100644 --- a/qom/qom-qmp-cmds.c +++ b/qom/qom-qmp-cmds.c @@ -71,7 +71,7 @@ void qmp_qom_set(const char *path, const char *property, QObject *value, return; } - object_property_set_qobject(obj, value, property, errp); + object_property_set_qobject(obj, property, value, errp); } QObject *qmp_qom_get(const char *path, const char *property, Error **errp) diff --git a/qom/qom-qobject.c b/qom/qom-qobject.c index c3b95aa354..f949572d8a 100644 --- a/qom/qom-qobject.c +++ b/qom/qom-qobject.c @@ -17,13 +17,14 @@ #include "qapi/qobject-input-visitor.h" #include "qapi/qobject-output-visitor.h" -void object_property_set_qobject(Object *obj, QObject *value, - const char *name, Error **errp) +void object_property_set_qobject(Object *obj, + const char *name, QObject *value, + Error **errp) { Visitor *v; v = qobject_input_visitor_new(value); - object_property_set(obj, v, name, errp); + object_property_set(obj, name, v, errp); visit_free(v); } @@ -35,7 +36,7 @@ QObject *object_property_get_qobject(Object *obj, const char *name, Visitor *v; v = qobject_output_visitor_new(&ret); - object_property_get(obj, v, name, &local_err); + object_property_get(obj, name, v, &local_err); if (!local_err) { visit_complete(v, &ret); } diff --git a/softmmu/vl.c b/softmmu/vl.c index f3ff5d06ca..f6bcad1c07 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2469,7 +2469,7 @@ static int object_parse_property_opt(Object *obj, return 0; } - object_property_parse(obj, value, name, &local_err); + object_property_parse(obj, name, value, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -2817,17 +2817,17 @@ static void create_default_memdev(MachineState *ms, const char *path) obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM); if (path) { - object_property_set_str(obj, path, "mem-path", &error_fatal); + object_property_set_str(obj, "mem-path", path, &error_fatal); } - object_property_set_int(obj, ms->ram_size, "size", &error_fatal); + object_property_set_int(obj, "size", ms->ram_size, &error_fatal); object_property_add_child(object_get_objects_root(), mc->default_ram_id, obj); /* Ensure backend's memory region name is equal to mc->default_ram_id */ - object_property_set_bool(obj, false, "x-use-canonical-path-for-ramblock-id", - &error_fatal); + object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id", + false, &error_fatal); user_creatable_complete(USER_CREATABLE(obj), &error_fatal); object_unref(obj); - object_property_set_str(OBJECT(ms), mc->default_ram_id, "memory-backend", + object_property_set_str(OBJECT(ms), "memory-backend", mc->default_ram_id, &error_fatal); } diff --git a/target/arm/monitor.c b/target/arm/monitor.c index 98fe11ae69..087726a394 100644 --- a/target/arm/monitor.c +++ b/target/arm/monitor.c @@ -184,7 +184,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, i = 0; while ((name = cpu_model_advertised_features[i++]) != NULL) { if (qdict_get(qdict_in, name)) { - object_property_set(obj, visitor, name, &err); + object_property_set(obj, name, visitor, &err); if (err) { break; } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index c69d057df3..dd83cb7f72 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -4260,12 +4260,12 @@ static void max_x86_cpu_initfn(Object *obj) host_vendor_fms(vendor, &family, &model, &stepping); cpu_x86_fill_model_id(model_id); - object_property_set_str(OBJECT(cpu), vendor, "vendor", &error_abort); - object_property_set_int(OBJECT(cpu), family, "family", &error_abort); - object_property_set_int(OBJECT(cpu), model, "model", &error_abort); - object_property_set_int(OBJECT(cpu), stepping, "stepping", + object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); + object_property_set_int(OBJECT(cpu), "family", family, &error_abort); + object_property_set_int(OBJECT(cpu), "model", model, &error_abort); + object_property_set_int(OBJECT(cpu), "stepping", stepping, &error_abort); - object_property_set_str(OBJECT(cpu), model_id, "model-id", + object_property_set_str(OBJECT(cpu), "model-id", model_id, &error_abort); if (kvm_enabled()) { @@ -4285,20 +4285,20 @@ static void max_x86_cpu_initfn(Object *obj) } if (lmce_supported()) { - object_property_set_bool(OBJECT(cpu), true, "lmce", &error_abort); + object_property_set_bool(OBJECT(cpu), "lmce", true, &error_abort); } } else { - object_property_set_str(OBJECT(cpu), CPUID_VENDOR_AMD, - "vendor", &error_abort); - object_property_set_int(OBJECT(cpu), 6, "family", &error_abort); - object_property_set_int(OBJECT(cpu), 6, "model", &error_abort); - object_property_set_int(OBJECT(cpu), 3, "stepping", &error_abort); - object_property_set_str(OBJECT(cpu), + object_property_set_str(OBJECT(cpu), "vendor", CPUID_VENDOR_AMD, + &error_abort); + object_property_set_int(OBJECT(cpu), "family", 6, &error_abort); + object_property_set_int(OBJECT(cpu), "model", 6, &error_abort); + object_property_set_int(OBJECT(cpu), "stepping", 3, &error_abort); + object_property_set_str(OBJECT(cpu), "model-id", "QEMU TCG CPU version " QEMU_HW_VERSION, - "model-id", &error_abort); + &error_abort); } - object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort); + object_property_set_bool(OBJECT(cpu), "pmu", true, &error_abort); } static const TypeInfo max_x86_cpu_type_info = { @@ -5067,7 +5067,7 @@ static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props) if (!pv->value) { continue; } - object_property_parse(OBJECT(cpu), pv->value, pv->prop, + object_property_parse(OBJECT(cpu), pv->prop, pv->value, &error_abort); } } @@ -5086,7 +5086,7 @@ static void x86_cpu_apply_version_props(X86CPU *cpu, X86CPUModel *model) PropValue *p; for (p = vdef->props; p && p->prop; p++) { - object_property_parse(OBJECT(cpu), p->value, p->prop, + object_property_parse(OBJECT(cpu), p->prop, p->value, &error_abort); } @@ -5117,18 +5117,16 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) */ /* CPU models only set _minimum_ values for level/xlevel: */ - object_property_set_uint(OBJECT(cpu), def->level, "min-level", + object_property_set_uint(OBJECT(cpu), "min-level", def->level, &error_abort); - object_property_set_uint(OBJECT(cpu), def->xlevel, "min-xlevel", + object_property_set_uint(OBJECT(cpu), "min-xlevel", def->xlevel, &error_abort); - object_property_set_int(OBJECT(cpu), def->family, "family", + object_property_set_int(OBJECT(cpu), "family", def->family, &error_abort); + object_property_set_int(OBJECT(cpu), "model", def->model, &error_abort); + object_property_set_int(OBJECT(cpu), "stepping", def->stepping, &error_abort); - object_property_set_int(OBJECT(cpu), def->model, "model", - &error_abort); - object_property_set_int(OBJECT(cpu), def->stepping, "stepping", - &error_abort); - object_property_set_str(OBJECT(cpu), def->model_id, "model-id", + object_property_set_str(OBJECT(cpu), "model-id", def->model_id, &error_abort); for (w = 0; w < FEATURE_WORDS; w++) { env->features[w] = def->features[w]; @@ -5166,8 +5164,7 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) vendor = host_vendor; } - object_property_set_str(OBJECT(cpu), vendor, "vendor", - &error_abort); + object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); x86_cpu_apply_version_props(cpu, model); } @@ -5274,8 +5271,8 @@ static void object_apply_props(Object *obj, QDict *props, Error **errp) Error *err = NULL; for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) { - object_property_set_qobject(obj, qdict_entry_value(prop), - qdict_entry_key(prop), &err); + object_property_set_qobject(obj, qdict_entry_key(prop), + qdict_entry_value(prop), &err); if (err) { break; } @@ -6343,7 +6340,7 @@ 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); + object_property_set_bool(OBJECT(cpu), prop, true, &local_err); if (local_err) { goto out; } @@ -6351,7 +6348,7 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) for (l = minus_features; l; l = l->next) { const char *prop = l->data; - object_property_set_bool(OBJECT(cpu), false, prop, &local_err); + object_property_set_bool(OBJECT(cpu), prop, false, &local_err); if (local_err) { goto out; } diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index 49212bfd90..7e66822b5d 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -10482,7 +10482,7 @@ static void ppc_cpu_parse_featurestr(const char *type, char *features, if (compat_str) { char *v = compat_str + strlen("compat="); - object_property_set_str(machine, v, "max-cpu-compat", &local_err); + object_property_set_str(machine, "max-cpu-compat", v, &local_err); } g_strfreev(inpieces); if (local_err) { diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 65c26c4c86..8ab206186b 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -517,7 +517,7 @@ static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info, return; } for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) { - object_property_set(obj, visitor, e->key, &err); + object_property_set(obj, e->key, visitor, &err); if (err) { break; } diff --git a/ui/console.c b/ui/console.c index 865fa32635..08f75c9bf6 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1910,7 +1910,7 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, } graphic_console_set_hwops(s, hw_ops, opaque); if (dev) { - object_property_set_link(OBJECT(s), OBJECT(dev), "device", + object_property_set_link(OBJECT(s), "device", OBJECT(dev), &error_abort); } @@ -1937,7 +1937,7 @@ void graphic_console_close(QemuConsole *con) } trace_console_gfx_close(con->index); - object_property_set_link(OBJECT(con), NULL, "device", &error_abort); + object_property_set_link(OBJECT(con), "device", NULL, &error_abort); graphic_console_set_hwops(con, &unused_ops, NULL); if (con->gl) { From 6fd5bef10b8f0bf64df4e800bfda1da5fe17ca82 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:55 +0200 Subject: [PATCH 2059/2595] qom: Make functions taking Error ** return bool, not void See recent commit "error: Document Error API usage rules" for rationale. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-28-armbru@redhat.com> --- include/qom/object.h | 42 ++++++++++---- include/qom/object_interfaces.h | 12 +++- include/qom/qom-qobject.h | 4 +- qom/object.c | 99 +++++++++++++++++++++------------ qom/object_interfaces.c | 21 ++++--- qom/qom-qobject.c | 6 +- 6 files changed, 122 insertions(+), 62 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 7c2c6791a4..1088e5a34d 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -703,7 +703,7 @@ Object *object_new_with_propv(const char *typename, Error **errp, va_list vargs); -void object_apply_global_props(Object *obj, const GPtrArray *props, +bool object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp); void object_set_machine_compat_props(GPtrArray *compat_props); void object_set_accelerator_compat_props(GPtrArray *compat_props); @@ -798,8 +798,10 @@ void object_initialize(void *obj, size_t size, const char *typename); * strings. The propname of %NULL indicates the end of the property list. * If the object implements the user creatable interface, the object will * be marked complete once all the properties have been processed. + * + * Returns: %true on success, %false on failure. */ -void object_initialize_child_with_props(Object *parentobj, +bool object_initialize_child_with_props(Object *parentobj, const char *propname, void *childobj, size_t size, const char *type, Error **errp, ...) QEMU_SENTINEL; @@ -815,8 +817,10 @@ void object_initialize_child_with_props(Object *parentobj, * @vargs: list of property names and values * * See object_initialize_child() for documentation. + * + * Returns: %true on success, %false on failure. */ -void object_initialize_child_with_propsv(Object *parentobj, +bool object_initialize_child_with_propsv(Object *parentobj, const char *propname, void *childobj, size_t size, const char *type, Error **errp, va_list vargs); @@ -1209,8 +1213,10 @@ void object_unparent(Object *obj); * @errp: returns an error if this function fails * * Reads a property from a object. + * + * Returns: %true on success, %false on failure. */ -void object_property_get(Object *obj, const char *name, Visitor *v, +bool object_property_get(Object *obj, const char *name, Visitor *v, Error **errp); /** @@ -1220,8 +1226,10 @@ void object_property_get(Object *obj, const char *name, Visitor *v, * @errp: returns an error if this function fails * * Writes a string value to a property. + * + * Returns: %true on success, %false on failure. */ -void object_property_set_str(Object *obj, const char *name, +bool object_property_set_str(Object *obj, const char *name, const char *value, Error **errp); /** @@ -1249,8 +1257,9 @@ char *object_property_get_str(Object *obj, const char *name, * OBJ_PROP_LINK_STRONG bit, the old target object is * unreferenced, and a reference is added to the new target object. * + * Returns: %true on success, %false on failure. */ -void object_property_set_link(Object *obj, const char *name, +bool object_property_set_link(Object *obj, const char *name, Object *value, Error **errp); /** @@ -1273,8 +1282,10 @@ Object *object_property_get_link(Object *obj, const char *name, * @errp: returns an error if this function fails * * Writes a bool value to a property. + * + * Returns: %true on success, %false on failure. */ -void object_property_set_bool(Object *obj, const char *name, +bool object_property_set_bool(Object *obj, const char *name, bool value, Error **errp); /** @@ -1296,8 +1307,10 @@ bool object_property_get_bool(Object *obj, const char *name, * @errp: returns an error if this function fails * * Writes an integer value to a property. + * + * Returns: %true on success, %false on failure. */ -void object_property_set_int(Object *obj, const char *name, +bool object_property_set_int(Object *obj, const char *name, int64_t value, Error **errp); /** @@ -1319,8 +1332,10 @@ int64_t object_property_get_int(Object *obj, const char *name, * @errp: returns an error if this function fails * * Writes an unsigned integer value to a property. + * + * Returns: %true on success, %false on failure. */ -void object_property_set_uint(Object *obj, const char *name, +bool object_property_set_uint(Object *obj, const char *name, uint64_t value, Error **errp); /** @@ -1359,8 +1374,10 @@ int object_property_get_enum(Object *obj, const char *name, * @errp: returns an error if this function fails * * Writes a property to a object. + * + * Returns: %true on success, %false on failure. */ -void object_property_set(Object *obj, const char *name, Visitor *v, +bool object_property_set(Object *obj, const char *name, Visitor *v, Error **errp); /** @@ -1371,8 +1388,10 @@ void object_property_set(Object *obj, const char *name, Visitor *v, * @errp: returns an error if this function fails * * Parses a string and writes the result into a property of an object. + * + * Returns: %true on success, %false on failure. */ -void object_property_parse(Object *obj, const char *name, +bool object_property_parse(Object *obj, const char *name, const char *string, Error **errp); /** @@ -1815,6 +1834,7 @@ ObjectProperty *object_property_add_const_link(Object *obj, const char *name, * * Set an object property's description. * + * Returns: %true on success, %false on failure. */ void object_property_set_description(Object *obj, const char *name, const char *description); diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h index 65172120fa..7035829337 100644 --- a/include/qom/object_interfaces.h +++ b/include/qom/object_interfaces.h @@ -57,8 +57,10 @@ typedef struct UserCreatableClass { * Wrapper to call complete() method if one of types it's inherited * from implements USER_CREATABLE interface, otherwise the call does * nothing. + * + * Returns: %true on success, %false on failure. */ -void user_creatable_complete(UserCreatable *uc, Error **errp); +bool user_creatable_complete(UserCreatable *uc, Error **errp); /** * user_creatable_can_be_deleted: @@ -100,8 +102,10 @@ Object *user_creatable_add_type(const char *type, const char *id, * @qdict. The object type is taken from the QDict key 'qom-type', its * ID from the key 'id'. The remaining entries in @qdict are used to * initialize the object properties. + * + * Returns: %true on success, %false on failure. */ -void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp); +bool user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp); /** * user_creatable_add_opts: @@ -167,8 +171,10 @@ bool user_creatable_print_help(const char *type, QemuOpts *opts); * * Delete an instance of the user creatable object identified * by @id. + * + * Returns: %true on success, %false on failure. */ -void user_creatable_del(const char *id, Error **errp); +bool user_creatable_del(const char *id, Error **errp); /** * user_creatable_cleanup: diff --git a/include/qom/qom-qobject.h b/include/qom/qom-qobject.h index ad9a98dd62..73e4e0e474 100644 --- a/include/qom/qom-qobject.h +++ b/include/qom/qom-qobject.h @@ -33,8 +33,10 @@ struct QObject *object_property_get_qobject(Object *obj, const char *name, * @errp: returns an error if this function fails * * Writes a property to a object. + * + * Returns: %true on success, %false on failure. */ -void object_property_set_qobject(Object *obj, +bool object_property_set_qobject(Object *obj, const char *name, struct QObject *value, struct Error **errp); diff --git a/qom/object.c b/qom/object.c index 7d75c452b9..65ed2968b7 100644 --- a/qom/object.c +++ b/qom/object.c @@ -385,12 +385,13 @@ static void object_post_init_with_type(Object *obj, TypeImpl *ti) } } -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp) +bool object_apply_global_props(Object *obj, const GPtrArray *props, + Error **errp) { int i; if (!props) { - return; + return true; } for (i = 0; i < props->len; i++) { @@ -415,12 +416,14 @@ void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp */ if (errp) { error_propagate(errp, err); - return; + return false; } else { warn_report_err(err); } } } + + return true; } /* @@ -524,25 +527,31 @@ void object_initialize(void *data, size_t size, const char *typename) object_initialize_with_type(data, size, type); } -void object_initialize_child_with_props(Object *parentobj, - const char *propname, - void *childobj, size_t size, const char *type, - Error **errp, ...) +bool object_initialize_child_with_props(Object *parentobj, + const char *propname, + void *childobj, size_t size, + const char *type, + Error **errp, ...) { va_list vargs; + bool ok; va_start(vargs, errp); - object_initialize_child_with_propsv(parentobj, propname, - childobj, size, type, errp, vargs); + ok = object_initialize_child_with_propsv(parentobj, propname, + childobj, size, type, errp, + vargs); va_end(vargs); + return ok; } -void object_initialize_child_with_propsv(Object *parentobj, - const char *propname, - void *childobj, size_t size, const char *type, - Error **errp, va_list vargs) +bool object_initialize_child_with_propsv(Object *parentobj, + const char *propname, + void *childobj, size_t size, + const char *type, + Error **errp, va_list vargs) { Error *local_err = NULL; + bool ok = false; Object *obj; UserCreatable *uc; @@ -564,6 +573,8 @@ void object_initialize_child_with_propsv(Object *parentobj, } } + ok = true; + out: /* * We want @obj's reference to be 1 on success, 0 on failure. @@ -576,6 +587,7 @@ out: object_unref(obj); error_propagate(errp, local_err); + return ok; } void object_initialize_child_internal(Object *parent, @@ -1312,43 +1324,52 @@ void object_property_del(Object *obj, const char *name) g_hash_table_remove(obj->properties, name); } -void object_property_get(Object *obj, const char *name, Visitor *v, +bool object_property_get(Object *obj, const char *name, Visitor *v, Error **errp) { + Error *err = NULL; ObjectProperty *prop = object_property_find(obj, name, errp); + if (prop == NULL) { - return; + return false; } if (!prop->get) { error_setg(errp, QERR_PERMISSION_DENIED); - } else { - prop->get(obj, v, name, prop->opaque, errp); + return false; } + prop->get(obj, v, name, prop->opaque, &err); + error_propagate(errp, err); + return !err; } -void object_property_set(Object *obj, const char *name, Visitor *v, +bool object_property_set(Object *obj, const char *name, Visitor *v, Error **errp) { + Error *err = NULL; ObjectProperty *prop = object_property_find(obj, name, errp); + if (prop == NULL) { - return; + return false; } if (!prop->set) { error_setg(errp, QERR_PERMISSION_DENIED); - } else { - prop->set(obj, v, name, prop->opaque, errp); + return false; } + prop->set(obj, v, name, prop->opaque, &err); + error_propagate(errp, err); + return !err; } -void object_property_set_str(Object *obj, const char *name, +bool object_property_set_str(Object *obj, const char *name, const char *value, Error **errp) { QString *qstr = qstring_from_str(value); - object_property_set_qobject(obj, name, QOBJECT(qstr), errp); + bool ok = object_property_set_qobject(obj, name, QOBJECT(qstr), errp); qobject_unref(qstr); + return ok; } char *object_property_get_str(Object *obj, const char *name, @@ -1370,16 +1391,15 @@ char *object_property_get_str(Object *obj, const char *name, return retval; } -void object_property_set_link(Object *obj, const char *name, +bool object_property_set_link(Object *obj, const char *name, Object *value, Error **errp) { + g_autofree char *path = NULL; + if (value) { - char *path = object_get_canonical_path(value); - object_property_set_str(obj, name, path, errp); - g_free(path); - } else { - object_property_set_str(obj, name, "", errp); + path = object_get_canonical_path(value); } + return object_property_set_str(obj, name, path ?: "", errp); } Object *object_property_get_link(Object *obj, const char *name, @@ -1400,13 +1420,14 @@ Object *object_property_get_link(Object *obj, const char *name, return target; } -void object_property_set_bool(Object *obj, const char *name, +bool object_property_set_bool(Object *obj, const char *name, bool value, Error **errp) { QBool *qbool = qbool_from_bool(value); - object_property_set_qobject(obj, name, QOBJECT(qbool), errp); + bool ok = object_property_set_qobject(obj, name, QOBJECT(qbool), errp); qobject_unref(qbool); + return ok; } bool object_property_get_bool(Object *obj, const char *name, @@ -1431,13 +1452,14 @@ bool object_property_get_bool(Object *obj, const char *name, return retval; } -void object_property_set_int(Object *obj, const char *name, +bool object_property_set_int(Object *obj, const char *name, int64_t value, Error **errp) { QNum *qnum = qnum_from_int(value); - object_property_set_qobject(obj, name, QOBJECT(qnum), errp); + bool ok = object_property_set_qobject(obj, name, QOBJECT(qnum), errp); qobject_unref(qnum); + return ok; } int64_t object_property_get_int(Object *obj, const char *name, @@ -1500,13 +1522,14 @@ void object_property_set_default_uint(ObjectProperty *prop, uint64_t value) object_property_set_default(prop, QOBJECT(qnum_from_uint(value))); } -void object_property_set_uint(Object *obj, const char *name, +bool object_property_set_uint(Object *obj, const char *name, uint64_t value, Error **errp) { QNum *qnum = qnum_from_uint(value); + bool ok = object_property_set_qobject(obj, name, QOBJECT(qnum), errp); - object_property_set_qobject(obj, name, QOBJECT(qnum), errp); qobject_unref(qnum); + return ok; } uint64_t object_property_get_uint(Object *obj, const char *name, @@ -1567,12 +1590,14 @@ int object_property_get_enum(Object *obj, const char *name, return ret; } -void object_property_parse(Object *obj, const char *name, +bool object_property_parse(Object *obj, const char *name, const char *string, Error **errp) { Visitor *v = string_input_visitor_new(string); - object_property_set(obj, name, v, errp); + bool ok = object_property_set(obj, name, v, errp); + visit_free(v); + return ok; } char *object_property_print(Object *obj, const char *name, bool human, diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 4c59ee56d5..382198504c 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -14,13 +14,16 @@ #include "qapi/opts-visitor.h" #include "qemu/config-file.h" -void user_creatable_complete(UserCreatable *uc, Error **errp) +bool user_creatable_complete(UserCreatable *uc, Error **errp) { UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc); + Error *err = NULL; if (ucc->complete) { - ucc->complete(uc, errp); + ucc->complete(uc, &err); + error_propagate(errp, err); } + return !err; } bool user_creatable_can_be_deleted(UserCreatable *uc) @@ -101,7 +104,7 @@ out: return obj; } -void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp) +bool user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp) { Visitor *v; Object *obj; @@ -111,14 +114,14 @@ void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp) type = g_strdup(qdict_get_try_str(qdict, "qom-type")); if (!type) { error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); - return; + return false; } qdict_del(qdict, "qom-type"); id = g_strdup(qdict_get_try_str(qdict, "id")); if (!id) { error_setg(errp, QERR_MISSING_PARAMETER, "id"); - return; + return false; } qdict_del(qdict, "id"); @@ -130,6 +133,7 @@ void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp) obj = user_creatable_add_type(type, id, qdict, v, errp); visit_free(v); object_unref(obj); + return !!obj; } Object *user_creatable_add_opts(QemuOpts *opts, Error **errp) @@ -260,7 +264,7 @@ bool user_creatable_print_help(const char *type, QemuOpts *opts) return false; } -void user_creatable_del(const char *id, Error **errp) +bool user_creatable_del(const char *id, Error **errp) { Object *container; Object *obj; @@ -269,12 +273,12 @@ void user_creatable_del(const char *id, Error **errp) obj = object_resolve_path_component(container, id); if (!obj) { error_setg(errp, "object '%s' not found", id); - return; + return false; } if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) { error_setg(errp, "object '%s' is in use, can not be deleted", id); - return; + return false; } /* @@ -285,6 +289,7 @@ void user_creatable_del(const char *id, Error **errp) id)); object_unparent(obj); + return true; } void user_creatable_cleanup(void) diff --git a/qom/qom-qobject.c b/qom/qom-qobject.c index f949572d8a..62ac5e07ac 100644 --- a/qom/qom-qobject.c +++ b/qom/qom-qobject.c @@ -17,15 +17,17 @@ #include "qapi/qobject-input-visitor.h" #include "qapi/qobject-output-visitor.h" -void object_property_set_qobject(Object *obj, +bool object_property_set_qobject(Object *obj, const char *name, QObject *value, Error **errp) { Visitor *v; + bool ok; v = qobject_input_visitor_new(value); - object_property_set(obj, name, v, errp); + ok = object_property_set(obj, name, v, errp); visit_free(v); + return ok; } QObject *object_property_get_qobject(Object *obj, const char *name, From 778a2dc59213d789f5bf8409547b529af4eb9ead Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:56 +0200 Subject: [PATCH 2060/2595] qom: Use returned bool to check for failure, Coccinelle part The previous commit enables conversion of foo(..., &err); if (err) { ... } to if (!foo(..., errp)) { ... } for QOM functions that now return true / false on success / error. Coccinelle script: @@ identifier fun = { object_apply_global_props, object_initialize_child_with_props, object_initialize_child_with_propsv, object_property_get, object_property_get_bool, object_property_parse, object_property_set, object_property_set_bool, object_property_set_int, object_property_set_link, object_property_set_qobject, object_property_set_str, object_property_set_uint, object_set_props, object_set_propv, user_creatable_add_dict, user_creatable_complete, user_creatable_del }; expression list args, args2; typedef Error; Error *err; @@ - fun(args, &err, args2); - if (err) + if (!fun(args, &err, args2)) { ... } Fails to convert hw/arm/armsse.c, because Coccinelle gets confused by ARMSSE being used both as typedef and function-like macro there. Convert manually. Line breaks tidied up manually. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-29-armbru@redhat.com> --- hw/arm/armsse.c | 52 +++++++++++++++--------------------- hw/arm/armv7m.c | 20 ++++++-------- hw/arm/aspeed_ast2600.c | 5 ++-- hw/arm/aspeed_soc.c | 5 ++-- hw/arm/bcm2835_peripherals.c | 5 ++-- hw/arm/bcm2836.c | 12 ++++----- hw/arm/cubieboard.c | 11 ++++---- hw/arm/digic.c | 4 +-- hw/arm/nrf51_soc.c | 8 +++--- hw/arm/stm32f405_soc.c | 7 +++-- hw/arm/xlnx-zynqmp.c | 14 +++++----- hw/block/xen-block.c | 15 +++++------ hw/core/qdev.c | 3 +-- hw/i386/x86.c | 3 +-- hw/ppc/pnv_psi.c | 4 +-- hw/s390x/s390-pci-bus.c | 3 +-- hw/s390x/s390-virtio-ccw.c | 3 +-- hw/scsi/scsi-bus.c | 3 +-- hw/sd/aspeed_sdhci.c | 8 +++--- hw/sd/ssi-sd.c | 3 +-- hw/virtio/virtio-rng.c | 5 ++-- qdev-monitor.c | 3 +-- qom/object.c | 15 ++++------- qom/object_interfaces.c | 6 ++--- softmmu/vl.c | 4 +-- target/arm/monitor.c | 3 +-- target/i386/cpu.c | 11 +++----- target/s390x/cpu_models.c | 3 +-- 28 files changed, 96 insertions(+), 142 deletions(-) diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 1f8ce94ecc..c8604926a3 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -534,22 +534,20 @@ static void armsse_realize(DeviceState *dev, Error **errp) * later if necessary. */ if (extract32(info->cpuwait_rst, i, 1)) { - object_property_set_bool(cpuobj, "start-powered-off", true, &err); - if (err) { + if (!object_property_set_bool(cpuobj, "start-powered-off", true, + &err)) { error_propagate(errp, err); return; } } if (!s->cpu_fpu[i]) { - object_property_set_bool(cpuobj, "vfp", false, &err); - if (err) { + if (!object_property_set_bool(cpuobj, "vfp", false, &err)) { error_propagate(errp, err); return; } } if (!s->cpu_dsp[i]) { - object_property_set_bool(cpuobj, "dsp", false, &err); - if (err) { + if (!object_property_set_bool(cpuobj, "dsp", false, &err)) { error_propagate(errp, err); return; } @@ -604,9 +602,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) DeviceState *devs = DEVICE(splitter); int cpunum; - object_property_set_int(splitter, "num-lines", info->num_cpus, - &err); - if (err) { + if (!object_property_set_int(splitter, "num-lines", + info->num_cpus, &err)) { error_propagate(errp, err); return; } @@ -658,9 +655,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) * multiple lines, one for each of the PPCs within the ARMSSE and one * that will be an output from the ARMSSE to the system. */ - object_property_set_int(OBJECT(&s->sec_resp_splitter), "num-lines", 3, - &err); - if (err) { + if (!object_property_set_int(OBJECT(&s->sec_resp_splitter), + "num-lines", 3, &err)) { error_propagate(errp, err); return; } @@ -702,9 +698,9 @@ static void armsse_realize(DeviceState *dev, Error **errp) } /* We must OR together lines from the MPC splitters to go to the NVIC */ - object_property_set_int(OBJECT(&s->mpc_irq_orgate), "num-lines", - IOTS_NUM_EXP_MPC + info->sram_banks, &err); - if (err) { + if (!object_property_set_int(OBJECT(&s->mpc_irq_orgate), "num-lines", + IOTS_NUM_EXP_MPC + info->sram_banks, + &err)) { error_propagate(errp, err); return; } @@ -841,9 +837,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) * ones) are sent individually to the security controller, and also * ORed together to give a single combined PPC interrupt to the NVIC. */ - object_property_set_int(OBJECT(&s->ppc_irq_orgate), "num-lines", NUM_PPCS, - &err); - if (err) { + if (!object_property_set_int(OBJECT(&s->ppc_irq_orgate), + "num-lines", NUM_PPCS, &err)) { error_propagate(errp, err); return; } @@ -949,15 +944,13 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in_named(dev_apb_ppc1, "cfg_sec_resp", 0)); - object_property_set_int(OBJECT(&s->sysinfo), "SYS_VERSION", - info->sys_version, &err); - if (err) { + if (!object_property_set_int(OBJECT(&s->sysinfo), "SYS_VERSION", + info->sys_version, &err)) { error_propagate(errp, err); return; } - object_property_set_int(OBJECT(&s->sysinfo), "SYS_CONFIG", - armsse_sys_config_value(s, info), &err); - if (err) { + if (!object_property_set_int(OBJECT(&s->sysinfo), "SYS_CONFIG", + armsse_sys_config_value(s, info), &err)) { error_propagate(errp, err); return; } @@ -1005,8 +998,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) } /* This OR gate wires together outputs from the secure watchdogs to NMI */ - object_property_set_int(OBJECT(&s->nmi_orgate), "num-lines", 2, &err); - if (err) { + if (!object_property_set_int(OBJECT(&s->nmi_orgate), "num-lines", 2, + &err)) { error_propagate(errp, err); return; } @@ -1049,8 +1042,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) { Object *splitter = OBJECT(&s->ppc_irq_splitter[i]); - object_property_set_int(splitter, "num-lines", 2, &err); - if (err) { + if (!object_property_set_int(splitter, "num-lines", 2, &err)) { error_propagate(errp, err); return; } @@ -1095,8 +1087,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) SplitIRQ *splitter = &s->mpc_irq_splitter[i]; DeviceState *dev_splitter = DEVICE(splitter); - object_property_set_int(OBJECT(splitter), "num-lines", 2, &err); - if (err) { + if (!object_property_set_int(OBJECT(splitter), "num-lines", 2, + &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 923f7fad40..2e6dabbbaf 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -174,31 +174,27 @@ static void armv7m_realize(DeviceState *dev, Error **errp) &error_abort); } if (object_property_find(OBJECT(s->cpu), "init-svtor", NULL)) { - object_property_set_uint(OBJECT(s->cpu), "init-svtor", s->init_svtor, - &err); - if (err != NULL) { + if (!object_property_set_uint(OBJECT(s->cpu), "init-svtor", + s->init_svtor, &err)) { error_propagate(errp, err); return; } } if (object_property_find(OBJECT(s->cpu), "start-powered-off", NULL)) { - object_property_set_bool(OBJECT(s->cpu), "start-powered-off", - s->start_powered_off, &err); - if (err != NULL) { + if (!object_property_set_bool(OBJECT(s->cpu), "start-powered-off", + s->start_powered_off, &err)) { error_propagate(errp, err); return; } } if (object_property_find(OBJECT(s->cpu), "vfp", NULL)) { - object_property_set_bool(OBJECT(s->cpu), "vfp", s->vfp, &err); - if (err != NULL) { + if (!object_property_set_bool(OBJECT(s->cpu), "vfp", s->vfp, &err)) { error_propagate(errp, err); return; } } if (object_property_find(OBJECT(s->cpu), "dsp", NULL)) { - object_property_set_bool(OBJECT(s->cpu), "dsp", s->dsp, &err); - if (err != NULL) { + if (!object_property_set_bool(OBJECT(s->cpu), "dsp", s->dsp, &err)) { error_propagate(errp, err); return; } @@ -243,8 +239,8 @@ static void armv7m_realize(DeviceState *dev, Error **errp) Object *obj = OBJECT(&s->bitband[i]); SysBusDevice *sbd = SYS_BUS_DEVICE(&s->bitband[i]); - object_property_set_int(obj, "base", bitband_input_addr[i], &err); - if (err != NULL) { + if (!object_property_set_int(obj, "base", + bitband_input_addr[i], &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index e6e2cf0737..22cbe68449 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -356,9 +356,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* FMC, The number of CS is set at the board level */ object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), &error_abort); - object_property_set_int(OBJECT(&s->fmc), "sdram-base", - sc->memmap[ASPEED_SDRAM], &err); - if (err) { + if (!object_property_set_int(OBJECT(&s->fmc), "sdram-base", + sc->memmap[ASPEED_SDRAM], &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 27704d87ea..ff5f4d6a52 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -308,9 +308,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* FMC, The number of CS is set at the board level */ object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), &error_abort); - object_property_set_int(OBJECT(&s->fmc), "sdram-base", - sc->memmap[ASPEED_SDRAM], &err); - if (err) { + if (!object_property_set_int(OBJECT(&s->fmc), "sdram-base", + sc->memmap[ASPEED_SDRAM], &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index a6ccf3b368..cb724c18e8 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -222,9 +222,8 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) return; } - object_property_set_uint(OBJECT(&s->fb), "vcram-base", - ram_size - vcram_size, &err); - if (err) { + if (!object_property_set_uint(OBJECT(&s->fb), "vcram-base", + ram_size - vcram_size, &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index 91d31a5cb7..0d373af1a1 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -110,17 +110,17 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) s->cpu[n].core.mp_affinity = (info->clusterid << 8) | n; /* set periphbase/CBAR value for CPU-local registers */ - object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar", - info->peri_base, &err); - if (err) { + if (!object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar", + info->peri_base, &err)) { error_propagate(errp, err); return; } /* start powered off if not enabled */ - object_property_set_bool(OBJECT(&s->cpu[n].core), "start-powered-off", - n >= s->enabled_cpus, &err); - if (err) { + if (!object_property_set_bool(OBJECT(&s->cpu[n].core), + "start-powered-off", + n >= s->enabled_cpus, + &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 302919246b..1c6c792eb6 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -62,20 +62,19 @@ static void cubieboard_init(MachineState *machine) object_property_add_child(OBJECT(machine), "soc", OBJECT(a10)); object_unref(OBJECT(a10)); - object_property_set_int(OBJECT(&a10->emac), "phy-addr", 1, &err); - if (err != NULL) { + if (!object_property_set_int(OBJECT(&a10->emac), "phy-addr", 1, &err)) { error_reportf_err(err, "Couldn't set phy address: "); exit(1); } - object_property_set_int(OBJECT(&a10->timer), "clk0-freq", 32768, &err); - if (err != NULL) { + if (!object_property_set_int(OBJECT(&a10->timer), "clk0-freq", 32768, + &err)) { error_reportf_err(err, "Couldn't set clk0 frequency: "); exit(1); } - object_property_set_int(OBJECT(&a10->timer), "clk1-freq", 24000000, &err); - if (err != NULL) { + if (!object_property_set_int(OBJECT(&a10->timer), "clk1-freq", 24000000, + &err)) { error_reportf_err(err, "Couldn't set clk1 frequency: "); exit(1); } diff --git a/hw/arm/digic.c b/hw/arm/digic.c index ffc89d86b8..2306034840 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -56,8 +56,8 @@ static void digic_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd; int i; - object_property_set_bool(OBJECT(&s->cpu), "reset-hivecs", true, &err); - if (err != NULL) { + if (!object_property_set_bool(OBJECT(&s->cpu), "reset-hivecs", true, + &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index c440cd11e9..7877d2bf60 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -106,9 +106,8 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) BASE_TO_IRQ(NRF51_RNG_BASE))); /* UICR, FICR, NVMC, FLASH */ - object_property_set_uint(OBJECT(&s->nvm), "flash-size", s->flash_size, - &err); - if (err) { + if (!object_property_set_uint(OBJECT(&s->nvm), "flash-size", + s->flash_size, &err)) { error_propagate(errp, err); return; } @@ -141,8 +140,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) /* TIMER */ for (i = 0; i < NRF51_NUM_TIMERS; i++) { - object_property_set_uint(OBJECT(&s->timer[i]), "id", i, &err); - if (err) { + if (!object_property_set_uint(OBJECT(&s->timer[i]), "id", i, &err)) { error_propagate(errp, err); return; } diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index 07ce323a64..ddc680bfe0 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -160,10 +160,9 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) } /* ADC device, the IRQs are ORed together */ - object_initialize_child_with_props(OBJECT(s), "adc-orirq", &s->adc_irqs, - sizeof(s->adc_irqs), TYPE_OR_IRQ, &err, - NULL); - if (err != NULL) { + if (!object_initialize_child_with_props(OBJECT(s), "adc-orirq", + &s->adc_irqs, sizeof(s->adc_irqs), + TYPE_OR_IRQ, &err, NULL)) { error_propagate(errp, err); return; } diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index e7fe85f1d8..055b778d11 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -507,18 +507,16 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) * - SDIO Specification Version 3.0 * - eMMC Specification Version 4.51 */ - object_property_set_uint(sdhci, "sd-spec-version", 3, &err); - if (err) { + if (!object_property_set_uint(sdhci, "sd-spec-version", 3, &err)) { error_propagate(errp, err); return; } - object_property_set_uint(sdhci, "capareg", SDHCI_CAPABILITIES, &err); - if (err) { + if (!object_property_set_uint(sdhci, "capareg", SDHCI_CAPABILITIES, + &err)) { error_propagate(errp, err); return; } - object_property_set_uint(sdhci, "uhs", UHS_I, &err); - if (err) { + if (!object_property_set_uint(sdhci, "uhs", UHS_I, &err)) { error_propagate(errp, err); return; } @@ -606,8 +604,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, gic_spi[RTC_IRQ]); for (i = 0; i < XLNX_ZYNQMP_NUM_GDMA_CH; i++) { - object_property_set_uint(OBJECT(&s->gdma[i]), "bus-width", 128, &err); - if (err) { + if (!object_property_set_uint(OBJECT(&s->gdma[i]), "bus-width", 128, + &err)) { error_propagate(errp, err); return; } diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 0e6e6df5fa..89a4d02a1b 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -935,22 +935,21 @@ static void xen_block_device_create(XenBackendInstance *backend, xendev = XEN_DEVICE(qdev_new(type)); blockdev = XEN_BLOCK_DEVICE(xendev); - object_property_set_str(OBJECT(xendev), "vdev", vdev, &local_err); - if (local_err) { + if (!object_property_set_str(OBJECT(xendev), "vdev", vdev, + &local_err)) { error_propagate_prepend(errp, local_err, "failed to set 'vdev': "); goto fail; } - object_property_set_str(OBJECT(xendev), "drive", - xen_block_drive_get_node_name(drive), &local_err); - if (local_err) { + if (!object_property_set_str(OBJECT(xendev), "drive", + xen_block_drive_get_node_name(drive), + &local_err)) { error_propagate_prepend(errp, local_err, "failed to set 'drive': "); goto fail; } - object_property_set_str(OBJECT(xendev), "iothread", iothread->id, - &local_err); - if (local_err) { + if (!object_property_set_str(OBJECT(xendev), "iothread", iothread->id, + &local_err)) { error_propagate_prepend(errp, local_err, "failed to set 'iothread': "); goto fail; diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 56daa7b456..ae3b006f39 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -398,8 +398,7 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) assert(!DEVICE_GET_CLASS(dev)->bus_type); } - object_property_set_bool(OBJECT(dev), "realized", true, &err); - if (err) { + if (!object_property_set_bool(OBJECT(dev), "realized", true, &err)) { error_propagate(errp, err); } return !err; diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 54760197cf..22b524e0ab 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -121,8 +121,7 @@ void x86_cpu_new(X86MachineState *x86ms, int64_t apic_id, Error **errp) Error *local_err = NULL; Object *cpu = object_new(MACHINE(x86ms)->cpu_type); - object_property_set_uint(cpu, "apic-id", apic_id, &local_err); - if (local_err) { + if (!object_property_set_uint(cpu, "apic-id", apic_id, &local_err)) { goto out; } qdev_realize(DEVICE(cpu), NULL, &local_err); diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index e23276983f..604788a8eb 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -505,8 +505,8 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp) unsigned int i; /* Create PSI interrupt control source */ - object_property_set_int(OBJECT(ics), "nr-irqs", PSI_NUM_INTERRUPTS, &err); - if (err) { + if (!object_property_set_int(OBJECT(ics), "nr-irqs", PSI_NUM_INTERRUPTS, + &err)) { error_propagate(errp, err); return; } diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index a7b2a15a96..24de4edfc6 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -824,8 +824,7 @@ static S390PCIBusDevice *s390_pci_device_new(S390pciState *s, return NULL; } - object_property_set_str(OBJECT(dev), "target", target, &local_err); - if (local_err) { + if (!object_property_set_str(OBJECT(dev), "target", target, &local_err)) { object_unparent(OBJECT(dev)); error_propagate_prepend(errp, local_err, "zPCI device could not be created: "); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 07609a9a58..1a171f0c96 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -70,8 +70,7 @@ static S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, S390CPU *cpu = S390_CPU(object_new(typename)); Error *err = NULL; - object_property_set_int(OBJECT(cpu), "core-id", core_id, &err); - if (err != NULL) { + if (!object_property_set_int(OBJECT(cpu), "core-id", core_id, &err)) { goto out; } qdev_realize(DEVICE(cpu), NULL, &err); diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 4860863f1d..a83939f7d0 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -283,8 +283,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, object_unparent(OBJECT(dev)); return NULL; } - object_property_set_bool(OBJECT(dev), "share-rw", share_rw, &err); - if (err != NULL) { + if (!object_property_set_bool(OBJECT(dev), "share-rw", share_rw, &err)) { error_propagate(errp, err); object_unparent(OBJECT(dev)); return NULL; diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c index 29aa11df66..687b300773 100644 --- a/hw/sd/aspeed_sdhci.c +++ b/hw/sd/aspeed_sdhci.c @@ -132,15 +132,13 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp) Object *sdhci_slot = OBJECT(&sdhci->slots[i]); SysBusDevice *sbd_slot = SYS_BUS_DEVICE(&sdhci->slots[i]); - object_property_set_int(sdhci_slot, "sd-spec-version", 2, &err); - if (err) { + if (!object_property_set_int(sdhci_slot, "sd-spec-version", 2, &err)) { error_propagate(errp, err); return; } - object_property_set_uint(sdhci_slot, "capareg", - ASPEED_SDHCI_CAPABILITIES, &err); - if (err) { + if (!object_property_set_uint(sdhci_slot, "capareg", + ASPEED_SDHCI_CAPABILITIES, &err)) { error_propagate(errp, err); return; } diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index d4b57cda80..ad825220e2 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -261,8 +261,7 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) } } - object_property_set_bool(OBJECT(carddev), "spi", true, &err); - if (err) { + if (!object_property_set_bool(OBJECT(carddev), "spi", true, &err)) { goto fail; } diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index 85f7163e2d..8d052fbeed 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -194,9 +194,8 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp) if (vrng->conf.rng == NULL) { Object *default_backend = object_new(TYPE_RNG_BUILTIN); - user_creatable_complete(USER_CREATABLE(default_backend), - &local_err); - if (local_err) { + if (!user_creatable_complete(USER_CREATABLE(default_backend), + &local_err)) { error_propagate(errp, local_err); object_unref(default_backend); return; diff --git a/qdev-monitor.c b/qdev-monitor.c index f4c6e6073a..edb97bd310 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -186,8 +186,7 @@ static int set_property(void *opaque, const char *name, const char *value, if (strcmp(name, "bus") == 0) return 0; - object_property_parse(obj, name, value, &err); - if (err != NULL) { + if (!object_property_parse(obj, name, value, &err)) { error_propagate(errp, err); return -1; } diff --git a/qom/object.c b/qom/object.c index 65ed2968b7..e71266bdb8 100644 --- a/qom/object.c +++ b/qom/object.c @@ -405,8 +405,7 @@ bool object_apply_global_props(Object *obj, const GPtrArray *props, continue; } p->used = true; - object_property_parse(obj, p->property, p->value, &err); - if (err != NULL) { + if (!object_property_parse(obj, p->property, p->value, &err)) { error_prepend(&err, "can't apply global %s.%s=%s: ", p->driver, p->property, p->value); /* @@ -566,8 +565,7 @@ bool object_initialize_child_with_propsv(Object *parentobj, uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE); if (uc) { - user_creatable_complete(uc, &local_err); - if (local_err) { + if (!user_creatable_complete(uc, &local_err)) { object_unparent(obj); goto out; } @@ -764,8 +762,7 @@ Object *object_new_with_propv(const char *typename, uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE); if (uc) { - user_creatable_complete(uc, &local_err); - if (local_err) { + if (!user_creatable_complete(uc, &local_err)) { if (id != NULL) { object_unparent(obj); } @@ -810,8 +807,7 @@ int object_set_propv(Object *obj, const char *value = va_arg(vargs, char *); g_assert(value != NULL); - object_property_parse(obj, propname, value, &local_err); - if (local_err) { + if (!object_property_parse(obj, propname, value, &local_err)) { error_propagate(errp, local_err); return -1; } @@ -1608,8 +1604,7 @@ char *object_property_print(Object *obj, const char *name, bool human, Error *local_err = NULL; v = string_output_visitor_new(human, &string); - object_property_get(obj, name, v, &local_err); - if (local_err) { + if (!object_property_get(obj, name, v, &local_err)) { error_propagate(errp, local_err); goto out; } diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 382198504c..15fff66c3c 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -70,8 +70,7 @@ Object *user_creatable_add_type(const char *type, const char *id, goto out; } for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) { - object_property_set(obj, e->key, v, &local_err); - if (local_err) { + if (!object_property_set(obj, e->key, v, &local_err)) { break; } } @@ -88,8 +87,7 @@ Object *user_creatable_add_type(const char *type, const char *id, id, obj); } - user_creatable_complete(USER_CREATABLE(obj), &local_err); - if (local_err) { + if (!user_creatable_complete(USER_CREATABLE(obj), &local_err)) { if (id != NULL) { object_property_del(object_get_objects_root(), id); } diff --git a/softmmu/vl.c b/softmmu/vl.c index f6bcad1c07..b3c129be78 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2469,9 +2469,7 @@ static int object_parse_property_opt(Object *obj, return 0; } - object_property_parse(obj, name, value, &local_err); - - if (local_err) { + if (!object_property_parse(obj, name, value, &local_err)) { error_propagate(errp, local_err); return -1; } diff --git a/target/arm/monitor.c b/target/arm/monitor.c index 087726a394..c162c5fb68 100644 --- a/target/arm/monitor.c +++ b/target/arm/monitor.c @@ -184,8 +184,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, i = 0; while ((name = cpu_model_advertised_features[i++]) != NULL) { if (qdict_get(qdict_in, name)) { - object_property_set(obj, name, visitor, &err); - if (err) { + if (!object_property_set(obj, name, visitor, &err)) { break; } } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index dd83cb7f72..2b60b61ced 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5271,9 +5271,8 @@ static void object_apply_props(Object *obj, QDict *props, Error **errp) Error *err = NULL; for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) { - object_property_set_qobject(obj, qdict_entry_key(prop), - qdict_entry_value(prop), &err); - if (err) { + if (!object_property_set_qobject(obj, qdict_entry_key(prop), + qdict_entry_value(prop), &err)) { break; } } @@ -6340,16 +6339,14 @@ 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), prop, true, &local_err); - if (local_err) { + if (!object_property_set_bool(OBJECT(cpu), prop, true, &local_err)) { goto out; } } for (l = minus_features; l; l = l->next) { const char *prop = l->data; - object_property_set_bool(OBJECT(cpu), prop, false, &local_err); - if (local_err) { + if (!object_property_set_bool(OBJECT(cpu), prop, false, &local_err)) { goto out; } } diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 8ab206186b..f3ba30e93e 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -517,8 +517,7 @@ static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info, return; } for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) { - object_property_set(obj, e->key, visitor, &err); - if (err) { + if (!object_property_set(obj, e->key, visitor, &err)) { break; } } From f07ad48d46fdbc739dd72ac4ad1677dbbfe7ed44 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:57 +0200 Subject: [PATCH 2061/2595] qom: Use returned bool to check for failure, manual part The previous commit used Coccinelle to convert from checking the Error object to checking the return value. Convert a few more manually. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-30-armbru@redhat.com> --- hw/core/bus.c | 6 +----- hw/core/qdev.c | 7 +------ hw/s390x/s390-virtio-ccw.c | 13 +++++++------ 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/hw/core/bus.c b/hw/core/bus.c index 00d1d31762..6b987b6946 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -166,11 +166,7 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam bool qbus_realize(BusState *bus, Error **errp) { - Error *err = NULL; - - object_property_set_bool(OBJECT(bus), "realized", true, &err); - error_propagate(errp, err); - return !err; + return object_property_set_bool(OBJECT(bus), "realized", true, errp); } void qbus_unrealize(BusState *bus) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index ae3b006f39..68948761f2 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -388,8 +388,6 @@ void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, */ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) { - Error *err = NULL; - assert(!dev->realized && !dev->parent_bus); if (bus) { @@ -398,10 +396,7 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) assert(!DEVICE_GET_CLASS(dev)->bus_type); } - if (!object_property_set_bool(OBJECT(dev), "realized", true, &err)) { - error_propagate(errp, err); - } - return !err; + return object_property_set_bool(OBJECT(dev), "realized", true, errp); } /* diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 1a171f0c96..20e8e95c61 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -69,19 +69,20 @@ static S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, { S390CPU *cpu = S390_CPU(object_new(typename)); Error *err = NULL; + S390CPU *ret = NULL; if (!object_property_set_int(OBJECT(cpu), "core-id", core_id, &err)) { goto out; } - qdev_realize(DEVICE(cpu), NULL, &err); + if (!qdev_realize(DEVICE(cpu), NULL, &err)) { + goto out; + } + ret = cpu; out: object_unref(OBJECT(cpu)); - if (err) { - error_propagate(errp, err); - cpu = NULL; - } - return cpu; + error_propagate(errp, err); + return ret; } static void s390_init_cpus(MachineState *machine) From b783f54d60f8472aa61b44b682ca7af7929082e1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:58 +0200 Subject: [PATCH 2062/2595] qom: Make functions taking Error ** return bool, not 0/-1 Just for consistency. Also fix the example in object_set_props()'s documentation. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-31-armbru@redhat.com> --- include/qom/object.h | 28 +++++++++++----------------- qom/object.c | 14 +++++++------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 1088e5a34d..10fd4a2d4c 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -729,15 +729,13 @@ void object_apply_compat_props(Object *obj); * Error *err = NULL; * Object *obj = ...get / create object...; * - * obj = object_set_props(obj, - * &err, - * "share", "yes", - * "mem-path", "/dev/shm/somefile", - * "prealloc", "yes", - * "size", "1048576", - * NULL); - * - * if (!obj) { + * if (!object_set_props(obj, + * &err, + * "share", "yes", + * "mem-path", "/dev/shm/somefile", + * "prealloc", "yes", + * "size", "1048576", + * NULL)) { * error_reportf_err(err, "Cannot set properties: "); * } * @@ -746,11 +744,9 @@ void object_apply_compat_props(Object *obj); * The returned object will have one stable reference maintained * for as long as it is present in the object hierarchy. * - * Returns: -1 on error, 0 on success + * Returns: %true on success, %false on error. */ -int object_set_props(Object *obj, - Error **errp, - ...) QEMU_SENTINEL; +bool object_set_props(Object *obj, Error **errp, ...) QEMU_SENTINEL; /** * object_set_propv: @@ -760,11 +756,9 @@ int object_set_props(Object *obj, * * See object_set_props() for documentation. * - * Returns: -1 on error, 0 on success + * Returns: %true on success, %false on error. */ -int object_set_propv(Object *obj, - Error **errp, - va_list vargs); +bool object_set_propv(Object *obj, Error **errp, va_list vargs); /** * object_initialize: diff --git a/qom/object.c b/qom/object.c index e71266bdb8..07618816a7 100644 --- a/qom/object.c +++ b/qom/object.c @@ -557,7 +557,7 @@ bool object_initialize_child_with_propsv(Object *parentobj, object_initialize(childobj, size, type); obj = OBJECT(childobj); - if (object_set_propv(obj, errp, vargs) < 0) { + if (!object_set_propv(obj, errp, vargs)) { goto out; } @@ -752,7 +752,7 @@ Object *object_new_with_propv(const char *typename, } obj = object_new_with_type(klass->type); - if (object_set_propv(obj, errp, vargs) < 0) { + if (!object_set_propv(obj, errp, vargs)) { goto error; } @@ -780,12 +780,12 @@ Object *object_new_with_propv(const char *typename, } -int object_set_props(Object *obj, +bool object_set_props(Object *obj, Error **errp, ...) { va_list vargs; - int ret; + bool ret; va_start(vargs, errp); ret = object_set_propv(obj, errp, vargs); @@ -795,7 +795,7 @@ int object_set_props(Object *obj, } -int object_set_propv(Object *obj, +bool object_set_propv(Object *obj, Error **errp, va_list vargs) { @@ -809,12 +809,12 @@ int object_set_propv(Object *obj, g_assert(value != NULL); if (!object_property_parse(obj, propname, value, &local_err)) { error_propagate(errp, local_err); - return -1; + return false; } propname = va_arg(vargs, char *); } - return 0; + return true; } From 73ac1aac398576a30d3468abccbd9568adc1de76 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:05:59 +0200 Subject: [PATCH 2063/2595] qdev: Make functions taking Error ** return bool, not void See recent commit "error: Document Error API usage rules" for rationale. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-32-armbru@redhat.com> --- hw/core/qdev-properties-system.c | 4 ++-- include/hw/qdev-properties.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 810831b1df..7d2387f22c 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -421,7 +421,7 @@ const PropertyInfo qdev_prop_audiodev = { .set = set_audiodev, }; -void qdev_prop_set_drive_err(DeviceState *dev, const char *name, +bool qdev_prop_set_drive_err(DeviceState *dev, const char *name, BlockBackend *value, Error **errp) { const char *ref = ""; @@ -436,7 +436,7 @@ void qdev_prop_set_drive_err(DeviceState *dev, const char *name, } } - object_property_set_str(OBJECT(dev), name, ref, errp); + return object_property_set_str(OBJECT(dev), name, ref, errp); } void qdev_prop_set_drive(DeviceState *dev, const char *name, diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 944e3f2e0c..587e5b7d31 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -239,8 +239,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width; /* * Set properties between creation and realization. */ -void qdev_prop_set_drive_err(DeviceState *dev, const char *name, - BlockBackend *value, Error **errp); +bool qdev_prop_set_drive_err(DeviceState *dev, const char *name, + BlockBackend *value, Error **errp); /* * Set properties between creation and realization. From 0c0e618d233e3249f6b60678a1b013a2c8d83339 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:00 +0200 Subject: [PATCH 2064/2595] qdev: Use returned bool to check for failure, Coccinelle part The previous commit enables conversion of qdev_prop_set_drive_err(..., &err); if (err) { ... } to if (!qdev_prop_set_drive_err(..., errp)) { ... } Coccinelle script: @@ identifier fun = qdev_prop_set_drive_err; expression list args; typedef Error; Error *err; @@ - fun(args, &err); - if (err) + if (!fun(args, &err)) { ... } One line break tidied up manually. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-33-armbru@redhat.com> --- hw/scsi/scsi-bus.c | 3 +-- hw/sd/sd.c | 3 +-- hw/sd/ssi-sd.c | 5 ++--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index a83939f7d0..38b66a2f45 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -277,8 +277,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, if (serial && object_property_find(OBJECT(dev), "serial", NULL)) { qdev_prop_set_string(dev, "serial", serial); } - qdev_prop_set_drive_err(dev, "drive", blk, &err); - if (err) { + if (!qdev_prop_set_drive_err(dev, "drive", blk, &err)) { error_propagate(errp, err); object_unparent(OBJECT(dev)); return NULL; diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 97a9d32964..5137168d66 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -706,8 +706,7 @@ SDState *sd_init(BlockBackend *blk, bool is_spi) obj = object_new(TYPE_SD_CARD); dev = DEVICE(obj); - qdev_prop_set_drive_err(dev, "drive", blk, &err); - if (err) { + if (!qdev_prop_set_drive_err(dev, "drive", blk, &err)) { error_reportf_err(err, "sd_init failed: "); return NULL; } diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index ad825220e2..3717b2e721 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -254,9 +254,8 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) dinfo = drive_get_next(IF_SD); carddev = qdev_new(TYPE_SD_CARD); if (dinfo) { - qdev_prop_set_drive_err(carddev, "drive", blk_by_legacy_dinfo(dinfo), - &err); - if (err) { + if (!qdev_prop_set_drive_err(carddev, "drive", + blk_by_legacy_dinfo(dinfo), &err)) { goto fail; } } From dcfe480544eef72d666cb1695624449e2c22da2d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:01 +0200 Subject: [PATCH 2065/2595] error: Avoid unnecessary error_propagate() after error_setg() Replace error_setg(&err, ...); error_propagate(errp, err); by error_setg(errp, ...); Related pattern: if (...) { error_setg(&err, ...); goto out; } ... out: error_propagate(errp, err); return; When all paths to label out are that way, replace by if (...) { error_setg(errp, ...); return; } and delete the label along with the error_propagate(). When we have at most one other path that actually needs to propagate, and maybe one at the end that where propagation is unnecessary, e.g. foo(..., &err); if (err) { goto out; } ... bar(..., &err); out: error_propagate(errp, err); return; move the error_propagate() to where it's needed, like if (...) { foo(..., &err); error_propagate(errp, err); return; } ... bar(..., errp); return; and transform the error_setg() as above. In some places, the transformation results in obviously unnecessary error_propagate(). The next few commits will eliminate them. Bonus: the elimination of gotos will make later patches in this series easier to review. Candidates for conversion tracked down with this Coccinelle script: @@ identifier err, errp; expression list args; @@ - error_setg(&err, args); + error_setg(errp, args); ... when != err error_propagate(errp, err); Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-34-armbru@redhat.com> --- backends/cryptodev.c | 11 +++--- backends/hostmem-file.c | 19 +++------- backends/hostmem-memfd.c | 15 ++++---- backends/hostmem.c | 27 ++++++-------- block/quorum.c | 16 ++++---- block/replication.c | 11 +++--- block/throttle-groups.c | 22 +++++------ block/vxhs.c | 9 ++--- hw/acpi/core.c | 14 +++---- hw/hyperv/vmbus.c | 5 +-- hw/i386/pc.c | 35 ++++++------------ hw/mem/nvdimm.c | 17 ++++----- hw/mem/pc-dimm.c | 14 +++---- hw/misc/aspeed_sdmc.c | 3 +- hw/ppc/rs6000_mc.c | 9 ++--- hw/ppc/spapr.c | 73 ++++++++++++++++--------------------- hw/ppc/spapr_pci.c | 14 +++---- hw/s390x/ipl.c | 23 +++++------- hw/xen/xen_pt_config_init.c | 3 +- iothread.c | 12 +++--- net/colo-compare.c | 20 ++++------ net/dump.c | 10 ++--- net/filter-buffer.c | 10 ++--- qga/commands-win32.c | 19 +++------- 24 files changed, 169 insertions(+), 242 deletions(-) diff --git a/backends/cryptodev.c b/backends/cryptodev.c index 72b7077475..4de378532b 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -158,16 +158,15 @@ cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name, uint32_t value; if (!visit_type_uint32(v, name, &value, &local_err)) { - goto out; + error_propagate(errp, local_err); + return; } if (!value) { - error_setg(&local_err, "Property '%s.%s' doesn't take value '%" - PRIu32 "'", object_get_typename(obj), name, value); - goto out; + error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu32 "'", + object_get_typename(obj), name, value); + return; } backend->conf.peers.queues = value; -out: - error_propagate(errp, local_err); } static void diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index 320dffbaa9..a44f5a61ac 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -114,18 +114,16 @@ static void file_memory_backend_set_align(Object *o, Visitor *v, uint64_t val; if (host_memory_backend_mr_inited(backend)) { - error_setg(&local_err, "cannot change property '%s' of %s", - name, object_get_typename(o)); - goto out; + error_setg(errp, "cannot change property '%s' of %s", name, + object_get_typename(o)); + return; } if (!visit_type_size(v, name, &val, &local_err)) { - goto out; + error_propagate(errp, local_err); + return; } fb->align = val; - - out: - error_propagate(errp, local_err); } static bool file_memory_backend_get_pmem(Object *o, Error **errp) @@ -139,7 +137,6 @@ static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp) HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); if (host_memory_backend_mr_inited(backend)) { - error_setg(errp, "cannot change property 'pmem' of %s.", object_get_typename(o)); return; @@ -147,13 +144,9 @@ static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp) #ifndef CONFIG_LIBPMEM if (value) { - Error *local_err = NULL; - - error_setg(&local_err, - "Lack of libpmem support while setting the 'pmem=on'" + error_setg(errp, "Lack of libpmem support while setting the 'pmem=on'" " of %s. We can't ensure data persistence.", object_get_typename(o)); - error_propagate(errp, local_err); return; } #endif diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c index d4281c0032..1e74a2b92f 100644 --- a/backends/hostmem-memfd.c +++ b/backends/hostmem-memfd.c @@ -81,21 +81,20 @@ memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name, uint64_t value; if (host_memory_backend_mr_inited(MEMORY_BACKEND(obj))) { - error_setg(&local_err, "cannot change property value"); - goto out; + error_setg(errp, "cannot change property value"); + return; } if (!visit_type_size(v, name, &value, &local_err)) { - goto out; + error_propagate(errp, local_err); + return; } if (!value) { - error_setg(&local_err, "Property '%s.%s' doesn't take value '%" - PRIu64 "'", object_get_typename(obj), name, value); - goto out; + error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu64 "'", + object_get_typename(obj), name, value); + return; } m->hugetlbsize = value; -out: - error_propagate(errp, local_err); } static void diff --git a/backends/hostmem.c b/backends/hostmem.c index 4e4103ac09..5cc264b0db 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -58,23 +58,22 @@ host_memory_backend_set_size(Object *obj, Visitor *v, const char *name, uint64_t value; if (host_memory_backend_mr_inited(backend)) { - error_setg(&local_err, "cannot change property %s of %s ", - name, object_get_typename(obj)); - goto out; + error_setg(errp, "cannot change property %s of %s ", name, + object_get_typename(obj)); + return; } if (!visit_type_size(v, name, &value, &local_err)) { - goto out; + error_propagate(errp, local_err); + return; } if (!value) { - error_setg(&local_err, + error_setg(errp, "property '%s' of %s doesn't take value '%" PRIu64 "'", name, object_get_typename(obj), value); - goto out; + return; } backend->size = value; -out: - error_propagate(errp, local_err); } static void @@ -257,17 +256,15 @@ static void host_memory_backend_set_prealloc_threads(Object *obj, Visitor *v, uint32_t value; if (!visit_type_uint32(v, name, &value, &local_err)) { - goto out; + error_propagate(errp, local_err); + return; } if (value <= 0) { - error_setg(&local_err, - "property '%s' of %s doesn't take value '%d'", - name, object_get_typename(obj), value); - goto out; + error_setg(errp, "property '%s' of %s doesn't take value '%d'", name, + object_get_typename(obj), value); + return; } backend->prealloc_threads = value; -out: - error_propagate(errp, local_err); } static void host_memory_backend_init(Object *obj) diff --git a/block/quorum.c b/block/quorum.c index beb3b6dbcc..5d52e605db 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -910,13 +910,12 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, /* count how many different children are present */ s->num_children = qdict_array_entries(options, "children."); if (s->num_children < 0) { - error_setg(&local_err, "Option children is not a valid array"); + error_setg(errp, "Option children is not a valid array"); ret = -EINVAL; goto exit; } if (s->num_children < 1) { - error_setg(&local_err, - "Number of provided children must be 1 or more"); + error_setg(errp, "Number of provided children must be 1 or more"); ret = -EINVAL; goto exit; } @@ -929,7 +928,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, s->threshold = qemu_opt_get_number(opts, QUORUM_OPT_VOTE_THRESHOLD, 0); /* and validate it against s->num_children */ - ret = quorum_valid_threshold(s->threshold, s->num_children, &local_err); + ret = quorum_valid_threshold(s->threshold, s->num_children, errp); if (ret < 0) { goto exit; } @@ -942,7 +941,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, -EINVAL, NULL); } if (ret < 0) { - error_setg(&local_err, "Please set read-pattern as fifo or quorum"); + error_setg(errp, "Please set read-pattern as fifo or quorum"); goto exit; } s->read_pattern = ret; @@ -950,7 +949,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, if (s->read_pattern == QUORUM_READ_PATTERN_QUORUM) { s->is_blkverify = qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false); if (s->is_blkverify && (s->num_children != 2 || s->threshold != 2)) { - error_setg(&local_err, "blkverify=on can only be set if there are " + error_setg(errp, "blkverify=on can only be set if there are " "exactly two files and vote-threshold is 2"); ret = -EINVAL; goto exit; @@ -959,7 +958,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, s->rewrite_corrupted = qemu_opt_get_bool(opts, QUORUM_OPT_REWRITE, false); if (s->rewrite_corrupted && s->is_blkverify) { - error_setg(&local_err, + error_setg(errp, "rewrite-corrupted=on cannot be used with blkverify=on"); ret = -EINVAL; goto exit; @@ -979,6 +978,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, &child_of_bds, BDRV_CHILD_DATA, false, &local_err); if (local_err) { + error_propagate(errp, local_err); ret = -EINVAL; goto close_exit; } @@ -1004,8 +1004,6 @@ close_exit: g_free(opened); exit: qemu_opts_del(opts); - /* propagate error */ - error_propagate(errp, local_err); return ret; } diff --git a/block/replication.c b/block/replication.c index 5701eeb9e8..b844a09eb1 100644 --- a/block/replication.c +++ b/block/replication.c @@ -105,7 +105,7 @@ static int replication_open(BlockDriverState *bs, QDict *options, mode = qemu_opt_get(opts, REPLICATION_MODE); if (!mode) { - error_setg(&local_err, "Missing the option mode"); + error_setg(errp, "Missing the option mode"); goto fail; } @@ -113,7 +113,8 @@ static int replication_open(BlockDriverState *bs, QDict *options, s->mode = REPLICATION_MODE_PRIMARY; top_id = qemu_opt_get(opts, REPLICATION_TOP_ID); if (top_id) { - error_setg(&local_err, "The primary side does not support option top-id"); + error_setg(errp, + "The primary side does not support option top-id"); goto fail; } } else if (!strcmp(mode, "secondary")) { @@ -121,11 +122,11 @@ static int replication_open(BlockDriverState *bs, QDict *options, top_id = qemu_opt_get(opts, REPLICATION_TOP_ID); s->top_id = g_strdup(top_id); if (!s->top_id) { - error_setg(&local_err, "Missing the option top-id"); + error_setg(errp, "Missing the option top-id"); goto fail; } } else { - error_setg(&local_err, + error_setg(errp, "The option mode's value should be primary or secondary"); goto fail; } @@ -136,8 +137,6 @@ static int replication_open(BlockDriverState *bs, QDict *options, fail: qemu_opts_del(opts); - error_propagate(errp, local_err); - return ret; } diff --git a/block/throttle-groups.c b/block/throttle-groups.c index e411051160..3d7e7cf990 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -819,16 +819,17 @@ static void throttle_group_set(Object *obj, Visitor *v, const char * name, * transaction, as certain combinations are invalid. */ if (tg->is_initialized) { - error_setg(&local_err, "Property cannot be set after initialization"); - goto ret; + error_setg(errp, "Property cannot be set after initialization"); + return; } if (!visit_type_int64(v, name, &value, &local_err)) { - goto ret; + error_propagate(errp, local_err); + return; } if (value < 0) { - error_setg(&local_err, "Property values cannot be negative"); - goto ret; + error_setg(errp, "Property values cannot be negative"); + return; } cfg = &tg->ts.cfg; @@ -841,9 +842,9 @@ static void throttle_group_set(Object *obj, Visitor *v, const char * name, break; case BURST_LENGTH: if (value > UINT_MAX) { - error_setg(&local_err, "%s value must be in the" - "range [0, %u]", info->name, UINT_MAX); - goto ret; + error_setg(errp, "%s value must be in the" "range [0, %u]", + info->name, UINT_MAX); + return; } cfg->buckets[info->type].burst_length = value; break; @@ -851,11 +852,6 @@ static void throttle_group_set(Object *obj, Visitor *v, const char * name, cfg->op_size = value; break; } - -ret: - error_propagate(errp, local_err); - return; - } static void throttle_group_get(Object *obj, Visitor *v, const char *name, diff --git a/block/vxhs.c b/block/vxhs.c index 237df4f185..fecaeb82c9 100644 --- a/block/vxhs.c +++ b/block/vxhs.c @@ -326,14 +326,14 @@ static int vxhs_open(BlockDriverState *bs, QDict *options, /* vdisk-id is the disk UUID */ vdisk_id_opt = qemu_opt_get(opts, VXHS_OPT_VDISK_ID); if (!vdisk_id_opt) { - error_setg(&local_err, QERR_MISSING_PARAMETER, VXHS_OPT_VDISK_ID); + error_setg(errp, QERR_MISSING_PARAMETER, VXHS_OPT_VDISK_ID); ret = -EINVAL; goto out; } /* vdisk-id may contain a leading '/' */ if (strlen(vdisk_id_opt) > UUID_FMT_LEN + 1) { - error_setg(&local_err, "vdisk-id cannot be more than %d characters", + error_setg(errp, "vdisk-id cannot be more than %d characters", UUID_FMT_LEN); ret = -EINVAL; goto out; @@ -352,14 +352,14 @@ static int vxhs_open(BlockDriverState *bs, QDict *options, server_host_opt = qemu_opt_get(tcp_opts, VXHS_OPT_HOST); if (!server_host_opt) { - error_setg(&local_err, QERR_MISSING_PARAMETER, + error_setg(errp, QERR_MISSING_PARAMETER, VXHS_OPT_SERVER"."VXHS_OPT_HOST); ret = -EINVAL; goto out; } if (strlen(server_host_opt) > MAXHOSTNAMELEN) { - error_setg(&local_err, "server.host cannot be more than %d characters", + error_setg(errp, "server.host cannot be more than %d characters", MAXHOSTNAMELEN); ret = -EINVAL; goto out; @@ -412,7 +412,6 @@ out: if (ret < 0) { vxhs_unref(); - error_propagate(errp, local_err); g_free(s->vdisk_hostinfo.host); g_free(s->vdisk_guid); g_free(s->tlscredsid); diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 45cbed49ab..8b240c3e09 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -257,13 +257,13 @@ void acpi_table_add(const QemuOpts *opts, Error **errp) goto out; } if (hdrs->has_file == hdrs->has_data) { - error_setg(&err, "'-acpitable' requires one of 'data' or 'file'"); + error_setg(errp, "'-acpitable' requires one of 'data' or 'file'"); goto out; } pathnames = g_strsplit(hdrs->has_file ? hdrs->file : hdrs->data, ":", 0); if (pathnames == NULL || pathnames[0] == NULL) { - error_setg(&err, "'-acpitable' requires at least one pathname"); + error_setg(errp, "'-acpitable' requires at least one pathname"); goto out; } @@ -272,7 +272,7 @@ void acpi_table_add(const QemuOpts *opts, Error **errp) int fd = open(*cur, O_RDONLY | O_BINARY); if (fd < 0) { - error_setg(&err, "can't open file %s: %s", *cur, strerror(errno)); + error_setg(errp, "can't open file %s: %s", *cur, strerror(errno)); goto out; } @@ -288,8 +288,8 @@ void acpi_table_add(const QemuOpts *opts, Error **errp) memcpy(blob + bloblen, data, r); bloblen += r; } else if (errno != EINTR) { - error_setg(&err, "can't read file %s: %s", - *cur, strerror(errno)); + error_setg(errp, "can't read file %s: %s", *cur, + strerror(errno)); close(fd); goto out; } @@ -298,14 +298,12 @@ void acpi_table_add(const QemuOpts *opts, Error **errp) close(fd); } - acpi_table_install(blob, bloblen, hdrs->has_file, hdrs, &err); + acpi_table_install(blob, bloblen, hdrs->has_file, hdrs, errp); out: g_free(blob); g_strfreev(pathnames); qapi_free_AcpiTableOptions(hdrs); - - error_propagate(errp, err); } unsigned acpi_table_len(void *current) diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index a8bcb41026..34392e892a 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -1459,8 +1459,8 @@ static void create_channels(VMBus *vmbus, VMBusDevice *dev, Error **errp) dev->num_channels = vdc->num_channels ? vdc->num_channels(dev) : 1; if (dev->num_channels < 1) { - error_setg(&err, "invalid #channels: %u", dev->num_channels); - goto error_out; + error_setg(errp, "invalid #channels: %u", dev->num_channels); + return; } dev->channels = g_new0(VMBusChannel, dev->num_channels); @@ -1477,7 +1477,6 @@ err_init: while (i--) { deinit_channel(&dev->channels[i]); } -error_out: error_propagate(errp, err); } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 3e933b65b9..d1fed1bf87 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1327,7 +1327,6 @@ out: static void pc_memory_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - Error *local_err = NULL; PCMachineState *pcms = PC_MACHINE(hotplug_dev); /* @@ -1336,21 +1335,18 @@ static void pc_memory_unplug_request(HotplugHandler *hotplug_dev, * addition to cover this case. */ if (!pcms->acpi_dev || !x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) { - error_setg(&local_err, + error_setg(errp, "memory hotplug is not enabled: missing acpi device or acpi disabled"); - goto out; + return; } if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { - error_setg(&local_err, - "nvdimm device hot unplug is not supported yet."); - goto out; + error_setg(errp, "nvdimm device hot unplug is not supported yet."); + return; } hotplug_handler_unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, - &local_err); -out: - error_propagate(errp, local_err); + errp); } static void pc_memory_unplug(HotplugHandler *hotplug_dev, @@ -1430,31 +1426,23 @@ static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { int idx = -1; - Error *local_err = NULL; X86CPU *cpu = X86_CPU(dev); PCMachineState *pcms = PC_MACHINE(hotplug_dev); if (!pcms->acpi_dev) { - error_setg(&local_err, "CPU hot unplug not supported without ACPI"); - goto out; + error_setg(errp, "CPU hot unplug not supported without ACPI"); + return; } pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx); assert(idx != -1); if (idx == 0) { - error_setg(&local_err, "Boot CPU is unpluggable"); - goto out; + error_setg(errp, "Boot CPU is unpluggable"); + return; } hotplug_handler_unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, - &local_err); - if (local_err) { - goto out; - } - - out: - error_propagate(errp, local_err); - + errp); } static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev, @@ -1867,10 +1855,9 @@ static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v, return; } if (value > 4 * GiB) { - error_setg(&error, + error_setg(errp, "Machine option 'max-ram-below-4g=%"PRIu64 "' expects size less than or equal to 4G", value); - error_propagate(errp, error); return; } diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index 1fa976c56c..838ebcd227 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -49,23 +49,22 @@ static void nvdimm_set_label_size(Object *obj, Visitor *v, const char *name, uint64_t value; if (nvdimm->nvdimm_mr) { - error_setg(&local_err, "cannot change property value"); - goto out; + error_setg(errp, "cannot change property value"); + return; } if (!visit_type_size(v, name, &value, &local_err)) { - goto out; + error_propagate(errp, local_err); + return; } if (value < MIN_NAMESPACE_LABEL_SIZE) { - error_setg(&local_err, "Property '%s.%s' (0x%" PRIx64 ") is required" - " at least 0x%lx", object_get_typename(obj), - name, value, MIN_NAMESPACE_LABEL_SIZE); - goto out; + error_setg(errp, "Property '%s.%s' (0x%" PRIx64 ") is required" + " at least 0x%lx", object_get_typename(obj), name, value, + MIN_NAMESPACE_LABEL_SIZE); + return; } nvdimm->label_size = value; -out: - error_propagate(errp, local_err); } static void nvdimm_get_uuid(Object *obj, Visitor *v, const char *name, diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 8a075fbf72..9d3f0b9691 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -44,24 +44,24 @@ void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine, &error_abort); if ((slot < 0 || slot >= machine->ram_slots) && slot != PC_DIMM_UNASSIGNED_SLOT) { - error_setg(&local_err, "invalid slot number %d, valid range is [0-%" - PRIu64 "]", slot, machine->ram_slots - 1); - goto out; + error_setg(errp, + "invalid slot number %d, valid range is [0-%" PRIu64 "]", + slot, machine->ram_slots - 1); + return; } slot = pc_dimm_get_free_slot(slot == PC_DIMM_UNASSIGNED_SLOT ? NULL : &slot, machine->ram_slots, &local_err); if (local_err) { - goto out; + error_propagate(errp, local_err); + return; } object_property_set_int(OBJECT(dimm), PC_DIMM_SLOT_PROP, slot, &error_abort); trace_mhp_pc_dimm_assigned_slot(slot); memory_device_pre_plug(MEMORY_DEVICE(dimm), machine, legacy_align, - &local_err); -out: - error_propagate(errp, local_err); + errp); } void pc_dimm_plug(PCDIMMDevice *dimm, MachineState *machine, Error **errp) diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index 28874445c3..40682af0b3 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -240,9 +240,8 @@ static void aspeed_sdmc_set_ram_size(Object *obj, Visitor *v, const char *name, } sz = size_to_str(value); - error_setg(&local_err, "Invalid RAM size %s", sz); + error_setg(errp, "Invalid RAM size %s", sz); g_free(sz); - error_propagate(errp, local_err); } static void aspeed_sdmc_initfn(Object *obj) diff --git a/hw/ppc/rs6000_mc.c b/hw/ppc/rs6000_mc.c index f8a498bd8a..ce97365f5e 100644 --- a/hw/ppc/rs6000_mc.c +++ b/hw/ppc/rs6000_mc.c @@ -169,7 +169,8 @@ static void rs6000mc_realize(DeviceState *dev, Error **errp) memory_region_init_ram(&s->simm[socket], OBJECT(dev), name, s->simm_size[socket] * MiB, &local_err); if (local_err) { - goto out; + error_propagate(errp, local_err); + return; } memory_region_add_subregion_overlap(get_system_memory(), 0, &s->simm[socket], socket); @@ -177,10 +178,10 @@ static void rs6000mc_realize(DeviceState *dev, Error **errp) } if (ram_size) { /* unable to push all requested RAM in SIMMs */ - error_setg(&local_err, "RAM size incompatible with this board. " + error_setg(errp, "RAM size incompatible with this board. " "Try again with something else, like %" PRId64 " MB", s->ram_size / MiB - ram_size); - goto out; + return; } if (s->autoconfigure) { @@ -196,8 +197,6 @@ static void rs6000mc_realize(DeviceState *dev, Error **errp) isa_register_portio_list(ISA_DEVICE(dev), &s->portio, 0x0, rs6000mc_port_list, s, "rs6000mc"); -out: - error_propagate(errp, local_err); } static const VMStateDescription vmstate_rs6000mc = { diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 68e8b504b5..299908cc73 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2497,23 +2497,23 @@ static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) unsigned int smp_threads = ms->smp.threads; if (!kvm_enabled() && (smp_threads > 1)) { - error_setg(&local_err, "TCG cannot support more than 1 thread/core " - "on a pseries machine"); - goto out; + error_setg(errp, "TCG cannot support more than 1 thread/core " + "on a pseries machine"); + return; } if (!is_power_of_2(smp_threads)) { - error_setg(&local_err, "Cannot support %d threads/core on a pseries " - "machine because it must be a power of 2", smp_threads); - goto out; + error_setg(errp, "Cannot support %d threads/core on a pseries " + "machine because it must be a power of 2", smp_threads); + return; } /* Detemine the VSMT mode to use: */ if (vsmt_user) { if (spapr->vsmt < smp_threads) { - error_setg(&local_err, "Cannot support VSMT mode %d" - " because it must be >= threads/core (%d)", - spapr->vsmt, smp_threads); - goto out; + error_setg(errp, "Cannot support VSMT mode %d" + " because it must be >= threads/core (%d)", + spapr->vsmt, smp_threads); + return; } /* In this case, spapr->vsmt has been set by the command line */ } else if (!smc->smp_threads_vsmt) { @@ -2543,8 +2543,6 @@ static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) * behaviour will be correct */ if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) { warn_report_err(local_err); - local_err = NULL; - goto out; } else { if (!vsmt_user) { error_append_hint(&local_err, @@ -2554,13 +2552,11 @@ static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) smp_threads, kvm_smt, spapr->vsmt); } kvmppc_error_append_smt_possible_hint(&local_err); - goto out; + error_propagate(errp, local_err); } } } /* else TCG: nothing to do currently */ -out: - error_propagate(errp, local_err); } static void spapr_init_cpus(SpaprMachineState *spapr) @@ -3686,9 +3682,8 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, SpaprDrc *drc; if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { - error_setg(&local_err, - "nvdimm device hot unplug is not supported yet."); - goto out; + error_setg(errp, "nvdimm device hot unplug is not supported yet."); + return; } size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort); @@ -3697,7 +3692,8 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err); if (local_err) { - goto out; + error_propagate(errp, local_err); + return; } /* @@ -3707,10 +3703,9 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, * bail out to avoid detaching DRCs that were already released. */ if (spapr_pending_dimm_unplugs_find(spapr, dimm)) { - error_setg(&local_err, - "Memory unplug already in progress for device %s", + error_setg(errp, "Memory unplug already in progress for device %s", dev->id); - goto out; + return; } spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm); @@ -3729,8 +3724,6 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, addr_start / SPAPR_MEMORY_BLOCK_SIZE); spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs, spapr_drc_index(drc)); -out: - error_propagate(errp, local_err); } /* Callback to be called during DRC release. */ @@ -3891,7 +3884,6 @@ static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, { MachineState *machine = MACHINE(OBJECT(hotplug_dev)); MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); - Error *local_err = NULL; CPUCore *cc = CPU_CORE(dev); const char *base_core_type = spapr_get_cpu_core_type(machine->cpu_type); const char *type = object_get_typename(OBJECT(dev)); @@ -3900,18 +3892,18 @@ static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, unsigned int smp_threads = machine->smp.threads; if (dev->hotplugged && !mc->has_hotpluggable_cpus) { - error_setg(&local_err, "CPU hotplug not supported for this machine"); - goto out; + error_setg(errp, "CPU hotplug not supported for this machine"); + return; } if (strcmp(base_core_type, type)) { - error_setg(&local_err, "CPU core type should be %s", base_core_type); - goto out; + error_setg(errp, "CPU core type should be %s", base_core_type); + return; } if (cc->core_id % smp_threads) { - error_setg(&local_err, "invalid core id %d", cc->core_id); - goto out; + error_setg(errp, "invalid core id %d", cc->core_id); + return; } /* @@ -3921,26 +3913,23 @@ static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, * total vcpus not a multiple of threads-per-core. */ if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) { - error_setg(&local_err, "invalid nr-threads %d, must be %d", - cc->nr_threads, smp_threads); - goto out; + error_setg(errp, "invalid nr-threads %d, must be %d", cc->nr_threads, + smp_threads); + return; } core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index); if (!core_slot) { - error_setg(&local_err, "core id %d out of range", cc->core_id); - goto out; + error_setg(errp, "core id %d out of range", cc->core_id); + return; } if (core_slot->cpu) { - error_setg(&local_err, "core %d already populated", cc->core_id); - goto out; + error_setg(errp, "core %d already populated", cc->core_id); + return; } - numa_cpu_pre_plug(core_slot, dev, &local_err); - -out: - error_propagate(errp, local_err); + numa_cpu_pre_plug(core_slot, dev, errp); } int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 223bb8f464..2a6a48744a 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1499,10 +1499,10 @@ static void spapr_pci_plug(HotplugHandler *plug_handler, * we need to let them know it's not enabled */ if (plugged_dev->hotplugged) { - error_setg(&local_err, QERR_BUS_NO_HOTPLUG, + error_setg(errp, QERR_BUS_NO_HOTPLUG, object_get_typename(OBJECT(phb))); } - goto out; + return; } g_assert(drc); @@ -1517,15 +1517,16 @@ static void spapr_pci_plug(HotplugHandler *plug_handler, */ if (plugged_dev->hotplugged && bus->devices[PCI_DEVFN(slotnr, 0)] && PCI_FUNC(pdev->devfn) != 0) { - error_setg(&local_err, "PCI: slot %d function 0 already ocuppied by %s," + error_setg(errp, "PCI: slot %d function 0 already ocuppied by %s," " additional functions can no longer be exposed to guest.", slotnr, bus->devices[PCI_DEVFN(slotnr, 0)]->name); - goto out; + return; } spapr_drc_attach(drc, DEVICE(pdev), &local_err); if (local_err) { - goto out; + error_propagate(errp, local_err); + return; } /* If this is function 0, signal hotplug for all the device functions. @@ -1551,9 +1552,6 @@ static void spapr_pci_plug(HotplugHandler *plug_handler, } } } - -out: - error_propagate(errp, local_err); } static void spapr_pci_bridge_unplug(SpaprPhbState *phb, diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 7c893e5683..d46b1f094f 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -117,7 +117,6 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) uint64_t pentry; char *magic; int kernel_size; - Error *err = NULL; int bios_size; char *bios_filename; @@ -135,8 +134,8 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); if (bios_filename == NULL) { - error_setg(&err, "could not find stage1 bootloader"); - goto error; + error_setg(errp, "could not find stage1 bootloader"); + return; } bios_size = load_elf(bios_filename, NULL, @@ -155,8 +154,8 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) g_free(bios_filename); if (bios_size == -1) { - error_setg(&err, "could not load bootloader '%s'", bios_name); - goto error; + error_setg(errp, "could not load bootloader '%s'", bios_name); + return; } /* default boot target is the bios */ @@ -170,8 +169,8 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) if (kernel_size < 0) { kernel_size = load_image_targphys(ipl->kernel, 0, ram_size); if (kernel_size < 0) { - error_setg(&err, "could not load kernel '%s'", ipl->kernel); - goto error; + error_setg(errp, "could not load kernel '%s'", ipl->kernel); + return; } /* if this is Linux use KERN_IMAGE_START */ magic = rom_ptr(LINUX_MAGIC_ADDR, 6); @@ -183,8 +182,8 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) if (ipl_psw) { pentry = be32_to_cpu(*ipl_psw) & PSW_MASK_SHORT_ADDR; } else { - error_setg(&err, "Could not get IPL PSW"); - goto error; + error_setg(errp, "Could not get IPL PSW"); + return; } } } @@ -217,8 +216,8 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) initrd_size = load_image_targphys(ipl->initrd, initrd_offset, ram_size - initrd_offset); if (initrd_size == -1) { - error_setg(&err, "could not load initrd '%s'", ipl->initrd); - goto error; + error_setg(errp, "could not load initrd '%s'", ipl->initrd); + return; } /* @@ -248,8 +247,6 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) * TODO: there should be a better way to do this. */ qemu_register_reset(resettable_cold_reset_fn, dev); -error: - error_propagate(errp, err); } static Property s390_ipl_properties[] = { diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index 31ec5add1d..d0d7c720a6 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -2052,10 +2052,9 @@ void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp) reg_grp_offset, ®_grp_entry->size); if (rc < 0) { - error_setg(&err, "Failed to initialize %d/%zu, type = 0x%x," + error_setg(errp, "Failed to initialize %d/%zu, type = 0x%x," " rc: %d", i, ARRAY_SIZE(xen_pt_emu_reg_grps), xen_pt_emu_reg_grps[i].grp_type, rc); - error_propagate(errp, err); xen_pt_config_delete(s); return; } diff --git a/iothread.c b/iothread.c index cb65ef0e56..aa8830fed2 100644 --- a/iothread.c +++ b/iothread.c @@ -244,13 +244,14 @@ static void iothread_set_poll_param(Object *obj, Visitor *v, int64_t value; if (!visit_type_int64(v, name, &value, &local_err)) { - goto out; + error_propagate(errp, local_err); + return; } if (value < 0) { - error_setg(&local_err, "%s value must be in range [0, %"PRId64"]", + error_setg(errp, "%s value must be in range [0, %" PRId64 "]", info->name, INT64_MAX); - goto out; + return; } *field = value; @@ -260,11 +261,8 @@ static void iothread_set_poll_param(Object *obj, Visitor *v, iothread->poll_max_ns, iothread->poll_grow, iothread->poll_shrink, - &local_err); + errp); } - -out: - error_propagate(errp, local_err); } static void iothread_class_init(ObjectClass *klass, void *class_data) diff --git a/net/colo-compare.c b/net/colo-compare.c index 6835d42363..d75169e28f 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -1097,17 +1097,15 @@ static void compare_set_timeout(Object *obj, Visitor *v, uint32_t value; if (!visit_type_uint32(v, name, &value, &local_err)) { - goto out; + error_propagate(errp, local_err); + return; } if (!value) { - error_setg(&local_err, "Property '%s.%s' requires a positive value", + error_setg(errp, "Property '%s.%s' requires a positive value", object_get_typename(obj), name); - goto out; + return; } s->compare_timeout = value; - -out: - error_propagate(errp, local_err); } static void compare_get_expired_scan_cycle(Object *obj, Visitor *v, @@ -1129,17 +1127,15 @@ static void compare_set_expired_scan_cycle(Object *obj, Visitor *v, uint32_t value; if (!visit_type_uint32(v, name, &value, &local_err)) { - goto out; + error_propagate(errp, local_err); + return; } if (!value) { - error_setg(&local_err, "Property '%s.%s' requires a positive value", + error_setg(errp, "Property '%s.%s' requires a positive value", object_get_typename(obj), name); - goto out; + return; } s->expired_scan_cycle = value; - -out: - error_propagate(errp, local_err); } static void compare_pri_rs_finalize(SocketReadState *pri_rs) diff --git a/net/dump.c b/net/dump.c index 8c487a5590..f7a302f56c 100644 --- a/net/dump.c +++ b/net/dump.c @@ -196,17 +196,15 @@ static void filter_dump_set_maxlen(Object *obj, Visitor *v, const char *name, uint32_t value; if (!visit_type_uint32(v, name, &value, &local_err)) { - goto out; + error_propagate(errp, local_err); + return; } if (value == 0) { - error_setg(&local_err, "Property '%s.%s' doesn't take value '%u'", + error_setg(errp, "Property '%s.%s' doesn't take value '%u'", object_get_typename(obj), name, value); - goto out; + return; } nfds->maxlen = value; - -out: - error_propagate(errp, local_err); } static char *file_dump_get_filename(Object *obj, Error **errp) diff --git a/net/filter-buffer.c b/net/filter-buffer.c index 8e42934b37..143627fcaf 100644 --- a/net/filter-buffer.c +++ b/net/filter-buffer.c @@ -174,17 +174,15 @@ static void filter_buffer_set_interval(Object *obj, Visitor *v, uint32_t value; if (!visit_type_uint32(v, name, &value, &local_err)) { - goto out; + error_propagate(errp, local_err); + return; } if (!value) { - error_setg(&local_err, "Property '%s.%s' requires a positive value", + error_setg(errp, "Property '%s.%s' requires a positive value", object_get_typename(obj), name); - goto out; + return; } s->interval = value; - -out: - error_propagate(errp, local_err); } static void filter_buffer_init(Object *obj) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 5ba56327dd..0f4911082f 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -278,13 +278,10 @@ out: static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque, Error **errp) { - Error *local_err = NULL; - HANDLE thread = CreateThread(NULL, 0, func, opaque, 0, NULL); if (!thread) { - error_setg(&local_err, QERR_QGA_COMMAND_FAILED, + error_setg(errp, QERR_QGA_COMMAND_FAILED, "failed to dispatch asynchronous command"); - error_propagate(errp, local_err); } } @@ -1270,35 +1267,31 @@ typedef enum { static void check_suspend_mode(GuestSuspendMode mode, Error **errp) { SYSTEM_POWER_CAPABILITIES sys_pwr_caps; - Error *local_err = NULL; ZeroMemory(&sys_pwr_caps, sizeof(sys_pwr_caps)); if (!GetPwrCapabilities(&sys_pwr_caps)) { - error_setg(&local_err, QERR_QGA_COMMAND_FAILED, + error_setg(errp, QERR_QGA_COMMAND_FAILED, "failed to determine guest suspend capabilities"); - goto out; + return; } switch (mode) { case GUEST_SUSPEND_MODE_DISK: if (!sys_pwr_caps.SystemS4) { - error_setg(&local_err, QERR_QGA_COMMAND_FAILED, + error_setg(errp, QERR_QGA_COMMAND_FAILED, "suspend-to-disk not supported by OS"); } break; case GUEST_SUSPEND_MODE_RAM: if (!sys_pwr_caps.SystemS3) { - error_setg(&local_err, QERR_QGA_COMMAND_FAILED, + error_setg(errp, QERR_QGA_COMMAND_FAILED, "suspend-to-ram not supported by OS"); } break; default: - error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "mode", + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "mode", "GuestSuspendMode"); } - -out: - error_propagate(errp, local_err); } static DWORD WINAPI do_suspend(LPVOID opaque) From 668f62ec621e4e2919fb7d4caa5d805764c5852d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:02 +0200 Subject: [PATCH 2066/2595] error: Eliminate error_propagate() with Coccinelle, part 1 When all we do with an Error we receive into a local variable is propagating to somewhere else, we can just as well receive it there right away. Convert if (!foo(..., &err)) { ... error_propagate(errp, err); ... return ... } to if (!foo(..., errp)) { ... ... return ... } where nothing else needs @err. Coccinelle script: @rule1 forall@ identifier fun, err, errp, lbl; expression list args, args2; binary operator op; constant c1, c2; symbol false; @@ if ( ( - fun(args, &err, args2) + fun(args, errp, args2) | - !fun(args, &err, args2) + !fun(args, errp, args2) | - fun(args, &err, args2) op c1 + fun(args, errp, args2) op c1 ) ) { ... when != err when != lbl: when strict - error_propagate(errp, err); ... when != err ( return; | return c2; | return false; ) } @rule2 forall@ identifier fun, err, errp, lbl; expression list args, args2; expression var; binary operator op; constant c1, c2; symbol false; @@ - var = fun(args, &err, args2); + var = fun(args, errp, args2); ... when != err if ( ( var | !var | var op c1 ) ) { ... when != err when != lbl: when strict - error_propagate(errp, err); ... when != err ( return; | return c2; | return false; | return var; ) } @depends on rule1 || rule2@ identifier err; @@ - Error *err = NULL; ... when != err Not exactly elegant, I'm afraid. The "when != lbl:" is necessary to avoid transforming if (fun(args, &err)) { goto out } ... out: error_propagate(errp, err); even though other paths to label out still need the error_propagate(). For an actual example, see sclp_realize(). Without the "when strict", Coccinelle transforms vfio_msix_setup(), incorrectly. I don't know what exactly "when strict" does, only that it helps here. The match of return is narrower than what I want, but I can't figure out how to express "return where the operand doesn't use @err". For an example where it's too narrow, see vfio_intx_enable(). Silently fails to convert hw/arm/armsse.c, because Coccinelle gets confused by ARMSSE being used both as typedef and function-like macro there. Converted manually. Line breaks tidied up manually. One nested declaration of @local_err deleted manually. Preexisting unwanted blank line dropped in hw/riscv/sifive_e.c. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-35-armbru@redhat.com> --- accel/kvm/kvm-all.c | 4 +- accel/tcg/tcg-all.c | 4 +- backends/cryptodev-vhost-user.c | 3 +- backends/cryptodev.c | 4 +- backends/hostmem-file.c | 4 +- backends/hostmem-memfd.c | 4 +- backends/hostmem.c | 8 +-- backends/tpm/tpm_util.c | 4 +- block.c | 3 +- block/curl.c | 4 +- block/file-posix.c | 8 +-- block/parallels.c | 3 +- block/qcow.c | 3 +- block/qed.c | 3 +- block/throttle-groups.c | 4 +- block/vhdx.c | 3 +- block/vmdk.c | 3 +- block/vpc.c | 3 +- blockdev.c | 6 +- hw/arm/allwinner-a10.c | 16 ++--- hw/arm/armsse.c | 114 +++++++++++-------------------- hw/arm/armv7m.c | 24 +++---- hw/arm/aspeed_ast2600.c | 54 +++++---------- hw/arm/aspeed_soc.c | 48 +++++-------- hw/arm/bcm2835_peripherals.c | 48 +++++-------- hw/arm/bcm2836.c | 16 ++--- hw/arm/digic.c | 13 ++-- hw/arm/fsl-imx25.c | 33 +++------ hw/arm/fsl-imx31.c | 24 +++---- hw/arm/fsl-imx6.c | 36 ++++------ hw/arm/msf2-soc.c | 16 ++--- hw/arm/nrf51_soc.c | 24 +++---- hw/arm/stm32f205_soc.c | 22 ++---- hw/arm/stm32f405_soc.c | 27 +++----- hw/arm/xlnx-zynqmp.c | 58 ++++++---------- hw/block/fdc.c | 3 +- hw/block/xen-block.c | 4 +- hw/char/serial-pci-multi.c | 4 +- hw/char/serial-pci.c | 4 +- hw/char/serial.c | 8 +-- hw/core/machine.c | 4 +- hw/core/qdev-properties-system.c | 16 ++--- hw/core/qdev-properties.c | 44 +++--------- hw/cpu/a15mpcore.c | 4 +- hw/cpu/a9mpcore.c | 16 ++--- hw/cpu/arm11mpcore.c | 13 ++-- hw/cpu/core.c | 8 +-- hw/cpu/realview_mpcore.c | 7 +- hw/display/virtio-gpu-pci.c | 4 +- hw/display/virtio-vga.c | 4 +- hw/gpio/aspeed_gpio.c | 4 +- hw/i386/pc.c | 4 +- hw/intc/apic_common.c | 4 +- hw/intc/armv7m_nvic.c | 7 +- hw/intc/pnv_xive.c | 6 +- hw/intc/realview_gic.c | 4 +- hw/intc/spapr_xive.c | 6 +- hw/intc/xics_kvm.c | 4 +- hw/isa/piix4.c | 4 +- hw/mem/nvdimm.c | 4 +- hw/microblaze/xlnx-zynqmp-pmu.c | 7 +- hw/mips/cps.c | 13 ++-- hw/misc/aspeed_sdmc.c | 4 +- hw/misc/macio/cuda.c | 4 +- hw/misc/macio/macio.c | 19 ++---- hw/misc/macio/pmu.c | 4 +- hw/misc/pca9552.c | 4 +- hw/misc/tmp105.c | 4 +- hw/misc/tmp421.c | 4 +- hw/pci-host/pnv_phb3.c | 10 +-- hw/pci-host/pnv_phb4.c | 4 +- hw/pci-host/pnv_phb4_pec.c | 4 +- hw/ppc/e500.c | 4 +- hw/ppc/pnv.c | 40 ++++------- hw/ppc/pnv_core.c | 3 +- hw/ppc/pnv_psi.c | 11 +-- hw/ppc/spapr_caps.c | 12 +--- hw/ppc/spapr_drc.c | 9 +-- hw/ppc/spapr_irq.c | 4 +- hw/riscv/opentitan.c | 7 +- hw/riscv/sifive_e.c | 5 +- hw/riscv/sifive_u.c | 4 +- hw/s390x/css.c | 4 +- hw/s390x/event-facility.c | 7 +- hw/s390x/virtio-ccw-crypto.c | 4 +- hw/s390x/virtio-ccw-rng.c | 4 +- hw/scsi/scsi-bus.c | 10 +-- hw/sd/aspeed_sdhci.c | 10 +-- hw/smbios/smbios.c | 25 +++---- hw/vfio/pci-quirks.c | 4 +- hw/vfio/pci.c | 7 +- hw/virtio/virtio-balloon.c | 4 +- hw/virtio/virtio-rng-pci.c | 4 +- hw/virtio/virtio-rng.c | 4 +- iothread.c | 7 +- net/colo-compare.c | 8 +-- net/dump.c | 4 +- net/filter-buffer.c | 4 +- net/tap.c | 3 +- qapi/string-input-visitor.c | 4 +- qdev-monitor.c | 8 +-- qga/commands-win32.c | 3 +- qom/object.c | 32 +++------ softmmu/vl.c | 5 +- target/arm/cpu64.c | 12 +--- target/arm/monitor.c | 3 +- target/i386/cpu.c | 20 ++---- target/ppc/compat.c | 4 +- target/s390x/cpu_models.c | 11 +-- target/sparc/cpu.c | 4 +- tpm.c | 4 +- util/main-loop.c | 4 +- util/qemu-config.c | 7 +- util/qemu-option.c | 24 ++----- 114 files changed, 383 insertions(+), 896 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index ab1a6ff0ee..63ef6af9a1 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3113,11 +3113,9 @@ static void kvm_set_kvm_shadow_mem(Object *obj, Visitor *v, Error **errp) { KVMState *s = KVM_STATE(obj); - Error *error = NULL; int64_t value; - if (!visit_type_int(v, name, &value, &error)) { - error_propagate(errp, error); + if (!visit_type_int(v, name, &value, errp)) { return; } diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index d6b3d7fc07..eace2c113b 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -182,11 +182,9 @@ static void tcg_set_tb_size(Object *obj, Visitor *v, Error **errp) { TCGState *s = TCG_STATE(obj); - Error *error = NULL; uint32_t value; - if (!visit_type_uint32(v, name, &value, &error)) { - error_propagate(errp, error); + if (!visit_type_uint32(v, name, &value, errp)) { return; } diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c index 8b8cbc4223..dbe5a8aae6 100644 --- a/backends/cryptodev-vhost-user.c +++ b/backends/cryptodev-vhost-user.c @@ -209,8 +209,7 @@ static void cryptodev_vhost_user_init( backend->conf.peers.ccs[i] = cc; if (i == 0) { - if (!qemu_chr_fe_init(&s->chr, chr, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_chr_fe_init(&s->chr, chr, errp)) { return; } } diff --git a/backends/cryptodev.c b/backends/cryptodev.c index 4de378532b..ada4ebe78b 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -154,11 +154,9 @@ cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj); - Error *local_err = NULL; uint32_t value; - if (!visit_type_uint32(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint32(v, name, &value, errp)) { return; } if (!value) { diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index a44f5a61ac..5b819020b4 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -110,7 +110,6 @@ static void file_memory_backend_set_align(Object *o, Visitor *v, { HostMemoryBackend *backend = MEMORY_BACKEND(o); HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); - Error *local_err = NULL; uint64_t val; if (host_memory_backend_mr_inited(backend)) { @@ -119,8 +118,7 @@ static void file_memory_backend_set_align(Object *o, Visitor *v, return; } - if (!visit_type_size(v, name, &val, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_size(v, name, &val, errp)) { return; } fb->align = val; diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c index 1e74a2b92f..4c040a7541 100644 --- a/backends/hostmem-memfd.c +++ b/backends/hostmem-memfd.c @@ -77,7 +77,6 @@ memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); - Error *local_err = NULL; uint64_t value; if (host_memory_backend_mr_inited(MEMORY_BACKEND(obj))) { @@ -85,8 +84,7 @@ memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_size(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_size(v, name, &value, errp)) { return; } if (!value) { diff --git a/backends/hostmem.c b/backends/hostmem.c index 5cc264b0db..c614f1bdc1 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -54,7 +54,6 @@ host_memory_backend_set_size(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { HostMemoryBackend *backend = MEMORY_BACKEND(obj); - Error *local_err = NULL; uint64_t value; if (host_memory_backend_mr_inited(backend)) { @@ -63,8 +62,7 @@ host_memory_backend_set_size(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_size(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_size(v, name, &value, errp)) { return; } if (!value) { @@ -252,11 +250,9 @@ static void host_memory_backend_set_prealloc_threads(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { HostMemoryBackend *backend = MEMORY_BACKEND(obj); - Error *local_err = NULL; uint32_t value; - if (!visit_type_uint32(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint32(v, name, &value, errp)) { return; } if (value <= 0) { diff --git a/backends/tpm/tpm_util.c b/backends/tpm/tpm_util.c index 971f3af047..b58d298c1a 100644 --- a/backends/tpm/tpm_util.c +++ b/backends/tpm/tpm_util.c @@ -48,7 +48,6 @@ static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { DeviceState *dev = DEVICE(obj); - Error *local_err = NULL; Property *prop = opaque; TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop); char *str; @@ -58,8 +57,7 @@ static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } diff --git a/block.c b/block.c index 3e1f3eb1aa..99fe5729b0 100644 --- a/block.c +++ b/block.c @@ -5663,10 +5663,9 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, if (bs->open_flags & BDRV_O_INACTIVE) { bs->open_flags &= ~BDRV_O_INACTIVE; bdrv_get_cumulative_perm(bs, &perm, &shared_perm); - ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, &local_err); + ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, errp); if (ret < 0) { bs->open_flags |= BDRV_O_INACTIVE; - error_propagate(errp, local_err); return; } bdrv_set_perm(bs, perm, shared_perm); diff --git a/block/curl.c b/block/curl.c index d9552efe52..4f907c47be 100644 --- a/block/curl.c +++ b/block/curl.c @@ -669,7 +669,6 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, BDRVCURLState *s = bs->opaque; CURLState *state = NULL; QemuOpts *opts; - Error *local_err = NULL; const char *file; const char *cookie; const char *cookie_secret; @@ -695,8 +694,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, qemu_mutex_init(&s->mutex); opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { goto out_noclean; } diff --git a/block/file-posix.c b/block/file-posix.c index 36acf7b911..b35ea99d42 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -3331,7 +3331,6 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVRawState *s = bs->opaque; - Error *local_err = NULL; int ret; #if defined(__APPLE__) && defined(__MACH__) @@ -3396,9 +3395,8 @@ hdev_open_Mac_error: s->type = FTYPE_FILE; - ret = raw_open_common(bs, options, flags, 0, true, &local_err); + ret = raw_open_common(bs, options, flags, 0, true, errp); if (ret < 0) { - error_propagate(errp, local_err); #if defined(__APPLE__) && defined(__MACH__) if (*bsd_path) { filename = bsd_path; @@ -3674,14 +3672,12 @@ static int cdrom_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVRawState *s = bs->opaque; - Error *local_err = NULL; int ret; s->type = FTYPE_CD; - ret = raw_open_common(bs, options, flags, 0, true, &local_err); + ret = raw_open_common(bs, options, flags, 0, true, errp); if (ret) { - error_propagate(errp, local_err); return ret; } diff --git a/block/parallels.c b/block/parallels.c index 32d0ecd398..ff27a85c01 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -646,9 +646,8 @@ static int coroutine_fn parallels_co_create_opts(BlockDriver *drv, } /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, &local_err); + ret = bdrv_create_file(filename, opts, errp); if (ret < 0) { - error_propagate(errp, local_err); goto done; } diff --git a/block/qcow.c b/block/qcow.c index ee5d35fe20..dca2a1fe7d 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -973,9 +973,8 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv, } /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, &local_err); + ret = bdrv_create_file(filename, opts, errp); if (ret < 0) { - error_propagate(errp, local_err); goto fail; } diff --git a/block/qed.c b/block/qed.c index ece8b9bb60..e04b7ab5f0 100644 --- a/block/qed.c +++ b/block/qed.c @@ -749,9 +749,8 @@ static int coroutine_fn bdrv_qed_co_create_opts(BlockDriver *drv, } /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, &local_err); + ret = bdrv_create_file(filename, opts, errp); if (ret < 0) { - error_propagate(errp, local_err); goto fail; } diff --git a/block/throttle-groups.c b/block/throttle-groups.c index 3d7e7cf990..03a53c89ea 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -811,7 +811,6 @@ static void throttle_group_set(Object *obj, Visitor *v, const char * name, ThrottleGroup *tg = THROTTLE_GROUP(obj); ThrottleConfig *cfg; ThrottleParamInfo *info = opaque; - Error *local_err = NULL; int64_t value; /* If we have finished initialization, don't accept individual property @@ -823,8 +822,7 @@ static void throttle_group_set(Object *obj, Visitor *v, const char * name, return; } - if (!visit_type_int64(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int64(v, name, &value, errp)) { return; } if (value < 0) { diff --git a/block/vhdx.c b/block/vhdx.c index 645dc4b4f4..327675cc7c 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -2083,9 +2083,8 @@ static int coroutine_fn vhdx_co_create_opts(BlockDriver *drv, } /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, &local_err); + ret = bdrv_create_file(filename, opts, errp); if (ret < 0) { - error_propagate(errp, local_err); goto fail; } diff --git a/block/vmdk.c b/block/vmdk.c index 62da465126..4d42d2fbe1 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2252,9 +2252,8 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, BlockBackend *blk = NULL; Error *local_err = NULL; - ret = bdrv_create_file(filename, opts, &local_err); + ret = bdrv_create_file(filename, opts, errp); if (ret < 0) { - error_propagate(errp, local_err); goto exit; } diff --git a/block/vpc.c b/block/vpc.c index 119350d495..04da71e9e6 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -1113,9 +1113,8 @@ static int coroutine_fn vpc_co_create_opts(BlockDriver *drv, } /* Create and open the file (protocol layer) */ - ret = bdrv_create_file(filename, opts, &local_err); + ret = bdrv_create_file(filename, opts, errp); if (ret < 0) { - error_propagate(errp, local_err); goto fail; } diff --git a/blockdev.c b/blockdev.c index 625c8ff3f2..705869d849 100644 --- a/blockdev.c +++ b/blockdev.c @@ -509,8 +509,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, goto err_no_opts; } - if (!qemu_opts_absorb_qdict(opts, bs_opts, &error)) { - error_propagate(errp, error); + if (!qemu_opts_absorb_qdict(opts, bs_opts, errp)) { goto early_err; } @@ -827,8 +826,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, for (i = 0; i < ARRAY_SIZE(opt_renames); i++) { if (!qemu_opt_rename(all_opts, opt_renames[i].from, - opt_renames[i].to, &local_err)) { - error_propagate(errp, local_err); + opt_renames[i].to, errp)) { return NULL; } } diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index c5d604af68..e258463747 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -72,15 +72,12 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) { AwA10State *s = AW_A10(dev); SysBusDevice *sysbusdev; - Error *err = NULL; - if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cpu), NULL, errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->intc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->intc), errp)) { return; } sysbusdev = SYS_BUS_DEVICE(&s->intc); @@ -91,8 +88,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); qdev_pass_gpios(DEVICE(&s->intc), dev, NULL); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer), errp)) { return; } sysbusdev = SYS_BUS_DEVICE(&s->timer); @@ -114,16 +110,14 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC); qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->emac), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->emac), errp)) { return; } sysbusdev = SYS_BUS_DEVICE(&s->emac); sysbus_mmio_map(sysbusdev, 0, AW_A10_EMAC_BASE); sysbus_connect_irq(sysbusdev, 0, qdev_get_gpio_in(dev, 55)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->sata), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sata), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, AW_A10_SATA_BASE); diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index c8604926a3..64fcab895f 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -535,20 +535,17 @@ static void armsse_realize(DeviceState *dev, Error **errp) */ if (extract32(info->cpuwait_rst, i, 1)) { if (!object_property_set_bool(cpuobj, "start-powered-off", true, - &err)) { - error_propagate(errp, err); + errp)) { return; } } if (!s->cpu_fpu[i]) { - if (!object_property_set_bool(cpuobj, "vfp", false, &err)) { - error_propagate(errp, err); + if (!object_property_set_bool(cpuobj, "vfp", false, errp)) { return; } } if (!s->cpu_dsp[i]) { - if (!object_property_set_bool(cpuobj, "dsp", false, &err)) { - error_propagate(errp, err); + if (!object_property_set_bool(cpuobj, "dsp", false, errp)) { return; } } @@ -563,8 +560,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) object_property_set_link(cpuobj, "memory", OBJECT(&s->cpu_container[i]), &error_abort); object_property_set_link(cpuobj, "idau", OBJECT(s), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(cpuobj), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(cpuobj), errp)) { return; } /* @@ -573,8 +569,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) * CPU must exist and have been parented into the cluster before * the cluster is realized. */ - if (!qdev_realize(DEVICE(&s->cluster[i]), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cluster[i]), NULL, errp)) { return; } @@ -603,12 +598,10 @@ static void armsse_realize(DeviceState *dev, Error **errp) int cpunum; if (!object_property_set_int(splitter, "num-lines", - info->num_cpus, &err)) { - error_propagate(errp, err); + info->num_cpus, errp)) { return; } - if (!qdev_realize(DEVICE(splitter), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(splitter), NULL, errp)) { return; } for (cpunum = 0; cpunum < info->num_cpus; cpunum++) { @@ -639,8 +632,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) } /* Security controller */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->secctl), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->secctl), errp)) { return; } sbd_secctl = SYS_BUS_DEVICE(&s->secctl); @@ -656,12 +648,10 @@ static void armsse_realize(DeviceState *dev, Error **errp) * that will be an output from the ARMSSE to the system. */ if (!object_property_set_int(OBJECT(&s->sec_resp_splitter), - "num-lines", 3, &err)) { - error_propagate(errp, err); + "num-lines", 3, errp)) { return; } - if (!qdev_realize(DEVICE(&s->sec_resp_splitter), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->sec_resp_splitter), NULL, errp)) { return; } dev_splitter = DEVICE(&s->sec_resp_splitter); @@ -683,8 +673,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) } object_property_set_link(OBJECT(&s->mpc[i]), "downstream", OBJECT(&s->sram[i]), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->mpc[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mpc[i]), errp)) { return; } /* Map the upstream end of the MPC into the right place... */ @@ -700,12 +689,10 @@ static void armsse_realize(DeviceState *dev, Error **errp) /* We must OR together lines from the MPC splitters to go to the NVIC */ if (!object_property_set_int(OBJECT(&s->mpc_irq_orgate), "num-lines", IOTS_NUM_EXP_MPC + info->sram_banks, - &err)) { - error_propagate(errp, err); + errp)) { return; } - if (!qdev_realize(DEVICE(&s->mpc_irq_orgate), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->mpc_irq_orgate), NULL, errp)) { return; } qdev_connect_gpio_out(DEVICE(&s->mpc_irq_orgate), 0, @@ -722,8 +709,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) * map its upstream ends to the right place in the container. */ qdev_prop_set_uint32(DEVICE(&s->timer0), "pclk-frq", s->mainclk_frq); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer0), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer0), errp)) { return; } sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer0), 0, @@ -733,8 +719,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) &error_abort); qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer1), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer1), errp)) { return; } sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer1), 0, @@ -744,8 +729,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) &error_abort); qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->dualtimer), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->dualtimer), errp)) { return; } sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0, @@ -769,8 +753,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) int cpunum; SysBusDevice *mhu_sbd = SYS_BUS_DEVICE(&s->mhu[i]); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->mhu[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mhu[i]), errp)) { return; } port = g_strdup_printf("port[%d]", i + 3); @@ -795,8 +778,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) } } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc0), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc0), errp)) { return; } @@ -838,12 +820,10 @@ static void armsse_realize(DeviceState *dev, Error **errp) * ORed together to give a single combined PPC interrupt to the NVIC. */ if (!object_property_set_int(OBJECT(&s->ppc_irq_orgate), - "num-lines", NUM_PPCS, &err)) { - error_propagate(errp, err); + "num-lines", NUM_PPCS, errp)) { return; } - if (!qdev_realize(DEVICE(&s->ppc_irq_orgate), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->ppc_irq_orgate), NULL, errp)) { return; } qdev_connect_gpio_out(DEVICE(&s->ppc_irq_orgate), 0, @@ -864,8 +844,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_prop_set_string(DEVICE(&s->cachectrl[i]), "name", name); g_free(name); qdev_prop_set_uint64(DEVICE(&s->cachectrl[i]), "size", 0x1000); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->cachectrl[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cachectrl[i]), errp)) { return; } @@ -881,8 +860,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_prop_set_string(DEVICE(&s->cpusecctrl[i]), "name", name); g_free(name); qdev_prop_set_uint64(DEVICE(&s->cpusecctrl[i]), "size", 0x1000); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpusecctrl[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpusecctrl[i]), errp)) { return; } @@ -895,8 +873,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) MemoryRegion *mr; qdev_prop_set_uint32(DEVICE(&s->cpuid[i]), "CPUID", i); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpuid[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpuid[i]), errp)) { return; } @@ -910,8 +887,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) * 0x4002f000: S32K timer */ qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->s32ktimer), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->s32ktimer), errp)) { return; } sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0, @@ -920,8 +896,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->apb_ppc1), "port[0]", OBJECT(mr), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc1), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc1), errp)) { return; } mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->apb_ppc1), 0); @@ -945,17 +920,14 @@ static void armsse_realize(DeviceState *dev, Error **errp) "cfg_sec_resp", 0)); if (!object_property_set_int(OBJECT(&s->sysinfo), "SYS_VERSION", - info->sys_version, &err)) { - error_propagate(errp, err); + info->sys_version, errp)) { return; } if (!object_property_set_int(OBJECT(&s->sysinfo), "SYS_CONFIG", - armsse_sys_config_value(s, info), &err)) { - error_propagate(errp, err); + armsse_sys_config_value(s, info), errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysinfo), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysinfo), errp)) { return; } /* System information registers */ @@ -969,8 +941,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) s->init_svtor, &error_abort); object_property_set_int(OBJECT(&s->sysctl), "INITSVTOR1_RST", s->init_svtor, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysctl), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysctl), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x50021000); @@ -999,20 +970,17 @@ static void armsse_realize(DeviceState *dev, Error **errp) /* This OR gate wires together outputs from the secure watchdogs to NMI */ if (!object_property_set_int(OBJECT(&s->nmi_orgate), "num-lines", 2, - &err)) { - error_propagate(errp, err); + errp)) { return; } - if (!qdev_realize(DEVICE(&s->nmi_orgate), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->nmi_orgate), NULL, errp)) { return; } qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0, qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0)); qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->s32kwatchdog), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->s32kwatchdog), errp)) { return; } sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32kwatchdog), 0, @@ -1022,8 +990,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) /* 0x40080000 .. 0x4008ffff : ARMSSE second Base peripheral region */ qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->nswatchdog), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->nswatchdog), errp)) { return; } sysbus_connect_irq(SYS_BUS_DEVICE(&s->nswatchdog), 0, @@ -1031,8 +998,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000); qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->swatchdog), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->swatchdog), errp)) { return; } sysbus_connect_irq(SYS_BUS_DEVICE(&s->swatchdog), 0, @@ -1042,12 +1008,10 @@ static void armsse_realize(DeviceState *dev, Error **errp) for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) { Object *splitter = OBJECT(&s->ppc_irq_splitter[i]); - if (!object_property_set_int(splitter, "num-lines", 2, &err)) { - error_propagate(errp, err); + if (!object_property_set_int(splitter, "num-lines", 2, errp)) { return; } - if (!qdev_realize(DEVICE(splitter), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(splitter), NULL, errp)) { return; } } @@ -1088,12 +1052,10 @@ static void armsse_realize(DeviceState *dev, Error **errp) DeviceState *dev_splitter = DEVICE(splitter); if (!object_property_set_int(OBJECT(splitter), "num-lines", 2, - &err)) { - error_propagate(errp, err); + errp)) { return; } - if (!qdev_realize(DEVICE(splitter), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(splitter), NULL, errp)) { return; } diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 2e6dabbbaf..aa831d6653 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -175,27 +175,23 @@ static void armv7m_realize(DeviceState *dev, Error **errp) } if (object_property_find(OBJECT(s->cpu), "init-svtor", NULL)) { if (!object_property_set_uint(OBJECT(s->cpu), "init-svtor", - s->init_svtor, &err)) { - error_propagate(errp, err); + s->init_svtor, errp)) { return; } } if (object_property_find(OBJECT(s->cpu), "start-powered-off", NULL)) { if (!object_property_set_bool(OBJECT(s->cpu), "start-powered-off", - s->start_powered_off, &err)) { - error_propagate(errp, err); + s->start_powered_off, errp)) { return; } } if (object_property_find(OBJECT(s->cpu), "vfp", NULL)) { - if (!object_property_set_bool(OBJECT(s->cpu), "vfp", s->vfp, &err)) { - error_propagate(errp, err); + if (!object_property_set_bool(OBJECT(s->cpu), "vfp", s->vfp, errp)) { return; } } if (object_property_find(OBJECT(s->cpu), "dsp", NULL)) { - if (!object_property_set_bool(OBJECT(s->cpu), "dsp", s->dsp, &err)) { - error_propagate(errp, err); + if (!object_property_set_bool(OBJECT(s->cpu), "dsp", s->dsp, errp)) { return; } } @@ -207,14 +203,12 @@ static void armv7m_realize(DeviceState *dev, Error **errp) s->cpu->env.nvic = &s->nvic; s->nvic.cpu = s->cpu; - if (!qdev_realize(DEVICE(s->cpu), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(s->cpu), NULL, errp)) { return; } /* Note that we must realize the NVIC after the CPU */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->nvic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->nvic), errp)) { return; } @@ -240,14 +234,12 @@ static void armv7m_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd = SYS_BUS_DEVICE(&s->bitband[i]); if (!object_property_set_int(obj, "base", - bitband_input_addr[i], &err)) { - error_propagate(errp, err); + bitband_input_addr[i], errp)) { return; } object_property_set_link(obj, "source-memory", OBJECT(s->board_memory), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(obj), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(obj), errp)) { return; } diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 22cbe68449..3767f7d8d0 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -258,8 +258,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) * is needed when using -kernel */ - if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) { return; } } @@ -299,15 +298,13 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sc->memmap[ASPEED_SRAM], &s->sram); /* SCU */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_SCU]); /* RTC */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_RTC]); @@ -317,8 +314,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* Timer */ object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, @@ -338,8 +334,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* I2C */ object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_I2C]); @@ -357,12 +352,10 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), &error_abort); if (!object_property_set_int(OBJECT(&s->fmc), "sdram-base", - sc->memmap[ASPEED_SDRAM], &err)) { - error_propagate(errp, err); + sc->memmap[ASPEED_SDRAM], errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_FMC]); @@ -376,8 +369,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->spi[i]), "dram", OBJECT(s->dram_mr), &error_abort); object_property_set_int(OBJECT(&s->spi[i]), "num-cs", 1, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, @@ -388,8 +380,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* EHCI */ for (i = 0; i < sc->ehcis_num; i++) { - if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0, @@ -399,8 +390,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* SDMC - SDRAM Memory Controller */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->memmap[ASPEED_SDMC]); @@ -411,8 +401,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, @@ -423,8 +412,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, @@ -434,8 +422,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->mii[i]), "nic", OBJECT(&s->ftgmac100[i]), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->mii[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mii[i]), errp)) { return; } @@ -444,8 +431,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* XDMA */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0, @@ -454,16 +440,14 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_XDMA)); /* GPIO */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_GPIO]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, aspeed_soc_get_irq(s, ASPEED_GPIO)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio_1_8v), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio_1_8v), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio_1_8v), 0, @@ -472,8 +456,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_GPIO_1_8V)); /* SDHCI */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0, @@ -482,8 +465,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_SDHCI)); /* eMMC */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->emmc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->emmc), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->emmc), 0, sc->memmap[ASPEED_EMMC]); diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index ff5f4d6a52..a1a8684216 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -230,8 +230,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* CPU */ for (i = 0; i < sc->num_cpus; i++) { - if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) { return; } } @@ -247,15 +246,13 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sc->memmap[ASPEED_SRAM], &s->sram); /* SCU */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_SCU]); /* VIC */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->vic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->vic), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, sc->memmap[ASPEED_VIC]); @@ -265,8 +262,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); /* RTC */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_RTC]); @@ -276,8 +272,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* Timer */ object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, @@ -297,8 +292,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* I2C */ object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_I2C]); @@ -309,12 +303,10 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), &error_abort); if (!object_property_set_int(OBJECT(&s->fmc), "sdram-base", - sc->memmap[ASPEED_SDRAM], &err)) { - error_propagate(errp, err); + sc->memmap[ASPEED_SDRAM], errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_FMC]); @@ -326,8 +318,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* SPI */ for (i = 0; i < sc->spis_num; i++) { object_property_set_int(OBJECT(&s->spi[i]), "num-cs", 1, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, @@ -338,8 +329,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* EHCI */ for (i = 0; i < sc->ehcis_num; i++) { - if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0, @@ -349,8 +339,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } /* SDMC - SDRAM Memory Controller */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->memmap[ASPEED_SDMC]); @@ -361,8 +350,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, @@ -373,8 +361,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, @@ -384,8 +371,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } /* XDMA */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0, @@ -394,8 +380,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_XDMA)); /* GPIO */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_GPIO]); @@ -403,8 +388,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_GPIO)); /* SDHCI */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0, diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index cb724c18e8..a9d7f53f6e 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -156,8 +156,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) } /* Interrupt Controller */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->ic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ic), errp)) { return; } @@ -166,8 +165,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic)); /* Sys Timer */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->systmr), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->systmr), errp)) { return; } memory_region_add_subregion(&s->peri_mr, ST_OFFSET, @@ -178,8 +176,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) /* UART0 */ qdev_prop_set_chr(DEVICE(&s->uart0), "chardev", serial_hd(0)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart0), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart0), errp)) { return; } @@ -192,8 +189,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) /* AUX / UART1 */ qdev_prop_set_chr(DEVICE(&s->aux), "chardev", serial_hd(1)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->aux), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->aux), errp)) { return; } @@ -204,8 +200,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_AUX)); /* Mailboxes */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->mboxes), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mboxes), errp)) { return; } @@ -223,13 +218,11 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) } if (!object_property_set_uint(OBJECT(&s->fb), "vcram-base", - ram_size - vcram_size, &err)) { - error_propagate(errp, err); + ram_size - vcram_size, errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->fb), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fb), errp)) { return; } @@ -239,8 +232,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_FB)); /* Property channel */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->property), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->property), errp)) { return; } @@ -251,8 +243,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_PROPERTY)); /* Random Number Generator */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->rng), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rng), errp)) { return; } @@ -275,8 +266,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) BCM2835_SDHC_CAPAREG, &error_abort); object_property_set_bool(OBJECT(&s->sdhci), "pending-insert-quirk", true, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) { return; } @@ -287,8 +277,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_ARASANSDIO)); /* SDHOST */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhost), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhost), errp)) { return; } @@ -299,8 +288,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_SDIO)); /* DMA Channels */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->dma), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->dma), errp)) { return; } @@ -317,16 +305,14 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) } /* THERMAL */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->thermal), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->thermal), errp)) { return; } memory_region_add_subregion(&s->peri_mr, THERMAL_OFFSET, sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->thermal), 0)); /* GPIO */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; } @@ -336,8 +322,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus"); /* Mphi */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->mphi), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mphi), errp)) { return; } @@ -348,8 +333,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_HOSTPORT)); /* DWC2 */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->dwc2), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->dwc2), errp)) { return; } diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index 0d373af1a1..f15cc3b405 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -72,7 +72,6 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) BCM283XClass *bc = BCM283X_GET_CLASS(dev); const BCM283XInfo *info = bc->info; Object *obj; - Error *err = NULL; int n; /* common peripherals from bcm2835 */ @@ -81,8 +80,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), errp)) { return; } @@ -93,8 +91,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) info->peri_base, 1); /* bcm2836 interrupt controller (and mailboxes, etc.) */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) { return; } @@ -111,8 +108,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) /* set periphbase/CBAR value for CPU-local registers */ if (!object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar", - info->peri_base, &err)) { - error_propagate(errp, err); + info->peri_base, errp)) { return; } @@ -120,13 +116,11 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) if (!object_property_set_bool(OBJECT(&s->cpu[n].core), "start-powered-off", n >= s->enabled_cpus, - &err)) { - error_propagate(errp, err); + errp)) { return; } - if (!qdev_realize(DEVICE(&s->cpu[n].core), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cpu[n].core), NULL, errp)) { return; } diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 2306034840..614232165c 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -52,24 +52,20 @@ static void digic_init(Object *obj) static void digic_realize(DeviceState *dev, Error **errp) { DigicState *s = DIGIC(dev); - Error *err = NULL; SysBusDevice *sbd; int i; if (!object_property_set_bool(OBJECT(&s->cpu), "reset-hivecs", true, - &err)) { - error_propagate(errp, err); + errp)) { return; } - if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cpu), NULL, errp)) { return; } for (i = 0; i < DIGIC4_NB_TIMERS; i++) { - if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), errp)) { return; } @@ -78,8 +74,7 @@ static void digic_realize(DeviceState *dev, Error **errp) } qdev_prop_set_chr(DEVICE(&s->uart), "chardev", serial_hd(0)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart), errp)) { return; } diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index ea72a02d06..b4ddceae45 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -85,13 +85,11 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) uint8_t i; Error *err = NULL; - if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cpu), NULL, errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->avic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->avic), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX25_AVIC_ADDR); @@ -100,8 +98,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1, qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX25_CCM_ADDR); @@ -121,8 +118,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr); @@ -145,8 +141,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) s->gpt[i].ccm = IMX_CCM(&s->ccm); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_table[i].addr); @@ -167,8 +162,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) s->epit[i].ccm = IMX_CCM(&s->ccm); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr); @@ -179,16 +173,14 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->fec), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fec), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->fec), 0, FSL_IMX25_FEC_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->fec), 0, qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_FEC_IRQ)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->rngc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rngc), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->rngc), 0, FSL_IMX25_RNGC_ADDR); @@ -206,8 +198,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) { FSL_IMX25_I2C3_ADDR, FSL_IMX25_I2C3_IRQ } }; - if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr); @@ -228,8 +219,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) { FSL_IMX25_GPIO4_ADDR, FSL_IMX25_GPIO4_IRQ } }; - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr); @@ -255,8 +245,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) IMX25_ESDHC_CAPABILITIES, &error_abort); object_property_set_uint(OBJECT(&s->esdhc[i]), "vendor", SDHCI_VENDOR_IMX, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->esdhc[i]), 0, esdhc_table[i].addr); diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index 23a5f50175..0983998bb4 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -66,13 +66,11 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) uint16_t i; Error *err = NULL; - if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cpu), NULL, errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->avic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->avic), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX31_AVIC_ADDR); @@ -81,8 +79,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1, qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX31_CCM_ADDR); @@ -99,8 +96,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) { return; } @@ -112,8 +108,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) s->gpt.ccm = IMX_CCM(&s->ccm); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt), errp)) { return; } @@ -133,8 +128,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) s->epit[i].ccm = IMX_CCM(&s->ccm); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), errp)) { return; } @@ -156,8 +150,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) }; /* Initialize the I2C */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), errp)) { return; } /* Map I2C memory */ @@ -181,8 +174,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) object_property_set_bool(OBJECT(&s->gpio[i]), "has-edge-sel", false, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr); diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index e359ee579d..0bc9f0b60d 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -130,8 +130,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) true, &error_abort); } - if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) { return; } } @@ -142,8 +141,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(&s->a9mpcore), "num-irq", FSL_IMX6_MAX_IRQ + GIC_INTERNAL, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->a9mpcore), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->a9mpcore), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, FSL_IMX6_A9MPCORE_ADDR); @@ -155,14 +153,12 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ)); } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX6_CCM_ADDR); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->src), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->src), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->src), 0, FSL_IMX6_SRC_ADDR); @@ -182,8 +178,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) { return; } @@ -195,8 +190,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) s->gpt.ccm = IMX_CCM(&s->ccm); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt), errp)) { return; } @@ -217,8 +211,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) s->epit[i].ccm = IMX_CCM(&s->ccm); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), errp)) { return; } @@ -239,8 +232,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) { FSL_IMX6_I2C3_ADDR, FSL_IMX6_I2C3_IRQ } }; - if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), errp)) { return; } @@ -298,8 +290,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_bool(OBJECT(&s->gpio[i]), "has-upper-pin-irq", true, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) { return; } @@ -331,8 +322,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) IMX6_ESDHC_CAPABILITIES, &error_abort); object_property_set_uint(OBJECT(&s->esdhc[i]), "vendor", SDHCI_VENDOR_IMX, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->esdhc[i]), 0, esdhc_table[i].addr); @@ -377,8 +367,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) }; /* Initialize the SPI */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } @@ -389,8 +378,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) } qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->eth), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->eth), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->eth), 0, FSL_IMX6_ENET_ADDR); diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index e6e4bb3153..16bb7c9916 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -93,7 +93,6 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) MSF2State *s = MSF2_SOC(dev_soc); DeviceState *dev, *armv7m; SysBusDevice *busdev; - Error *err = NULL; int i; MemoryRegion *system_memory = get_system_memory(); @@ -125,8 +124,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_bit(armv7m, "enable-bitband", true); object_property_set_link(OBJECT(&s->armv7m), "memory", OBJECT(get_system_memory()), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) { return; } @@ -152,8 +150,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) dev = DEVICE(&s->timer); /* APB0 clock is the timer input clock */ qdev_prop_set_uint32(dev, "clock-frequency", s->m3clk / s->apb0div); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); @@ -166,8 +163,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) dev = DEVICE(&s->sysreg); qdev_prop_set_uint32(dev, "apb0divisor", s->apb0div); qdev_prop_set_uint32(dev, "apb1divisor", s->apb1div); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); @@ -176,8 +172,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < MSF2_NUM_SPIS; i++) { gchar *bus_name; - if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } @@ -195,8 +190,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) dev = DEVICE(&s->emac); object_property_set_link(OBJECT(&s->emac), "ahb-bus", OBJECT(get_system_memory()), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->emac), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->emac), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index 7877d2bf60..45e6cc97d7 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -67,8 +67,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) object_property_set_link(OBJECT(&s->cpu), "memory", OBJECT(&s->container), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpu), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpu), errp)) { return; } @@ -83,8 +82,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) memory_region_add_subregion(&s->container, NRF51_SRAM_BASE, &s->sram); /* UART */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart), errp)) { return; } mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->uart), 0); @@ -94,8 +92,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) BASE_TO_IRQ(NRF51_UART_BASE))); /* RNG */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->rng), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rng), errp)) { return; } @@ -107,13 +104,11 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) /* UICR, FICR, NVMC, FLASH */ if (!object_property_set_uint(OBJECT(&s->nvm), "flash-size", - s->flash_size, &err)) { - error_propagate(errp, err); + s->flash_size, errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->nvm), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->nvm), errp)) { return; } @@ -127,8 +122,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) memory_region_add_subregion_overlap(&s->container, NRF51_FLASH_BASE, mr, 0); /* GPIO */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; } @@ -140,12 +134,10 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) /* TIMER */ for (i = 0; i < NRF51_NUM_TIMERS; i++) { - if (!object_property_set_uint(OBJECT(&s->timer[i]), "id", i, &err)) { - error_propagate(errp, err); + if (!object_property_set_uint(OBJECT(&s->timer[i]), "id", i, errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), errp)) { return; } diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index 9acf401fbf..a4f3344db2 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -81,7 +81,6 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) STM32F205State *s = STM32F205_SOC(dev_soc); DeviceState *dev, *armv7m; SysBusDevice *busdev; - Error *err = NULL; int i; MemoryRegion *system_memory = get_system_memory(); @@ -107,15 +106,13 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_bit(armv7m, "enable-bitband", true); object_property_set_link(OBJECT(&s->armv7m), "memory", OBJECT(get_system_memory()), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) { return; } /* System configuration controller */ dev = DEVICE(&s->syscfg); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); @@ -126,8 +123,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_USARTS; i++) { dev = DEVICE(&(s->usart[i])); qdev_prop_set_chr(dev, "chardev", serial_hd(i)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); @@ -139,8 +135,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_TIMERS; i++) { dev = DEVICE(&(s->timer[i])); qdev_prop_set_uint64(dev, "clock-frequency", 1000000000); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); @@ -151,8 +146,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) /* ADC 1 to 3 */ object_property_set_int(OBJECT(s->adc_irqs), "num-lines", STM_NUM_ADCS, &error_abort); - if (!qdev_realize(DEVICE(s->adc_irqs), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(s->adc_irqs), NULL, errp)) { return; } qdev_connect_gpio_out(DEVICE(s->adc_irqs), 0, @@ -160,8 +154,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_ADCS; i++) { dev = DEVICE(&(s->adc[i])); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc[i]), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); @@ -173,8 +166,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) /* SPI 1 and 2 */ for (i = 0; i < STM_NUM_SPIS; i++) { dev = DEVICE(&(s->spi[i])); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index ddc680bfe0..cb04c11198 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -118,15 +118,13 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_bit(armv7m, "enable-bitband", true); object_property_set_link(OBJECT(&s->armv7m), "memory", OBJECT(system_memory), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) { return; } /* System configuration controller */ dev = DEVICE(&s->syscfg); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); @@ -137,8 +135,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_USARTS; i++) { dev = DEVICE(&(s->usart[i])); qdev_prop_set_chr(dev, "chardev", serial_hd(i)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); @@ -150,8 +147,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_TIMERS; i++) { dev = DEVICE(&(s->timer[i])); qdev_prop_set_uint64(dev, "clock-frequency", 1000000000); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); @@ -162,14 +158,12 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) /* ADC device, the IRQs are ORed together */ if (!object_initialize_child_with_props(OBJECT(s), "adc-orirq", &s->adc_irqs, sizeof(s->adc_irqs), - TYPE_OR_IRQ, &err, NULL)) { - error_propagate(errp, err); + TYPE_OR_IRQ, errp, NULL)) { return; } object_property_set_int(OBJECT(&s->adc_irqs), "num-lines", STM_NUM_ADCS, &error_abort); - if (!qdev_realize(DEVICE(&s->adc_irqs), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->adc_irqs), NULL, errp)) { return; } qdev_connect_gpio_out(DEVICE(&s->adc_irqs), 0, @@ -177,8 +171,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_ADCS; i++) { dev = DEVICE(&(s->adc[i])); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc[i]), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); @@ -190,8 +183,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) /* SPI devices */ for (i = 0; i < STM_NUM_SPIS; i++) { dev = DEVICE(&(s->spi[i])); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); @@ -201,8 +193,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) /* EXTI device */ dev = DEVICE(&s->exti); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->exti), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->exti), errp)) { return; } busdev = SYS_BUS_DEVICE(dev); diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 055b778d11..772cfa3771 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -176,7 +176,6 @@ static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index) static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s, const char *boot_cpu, Error **errp) { - Error *err = NULL; int i; int num_rpus = MIN(ms->smp.cpus - XLNX_ZYNQMP_NUM_APU_CPUS, XLNX_ZYNQMP_NUM_RPU_CPUS); @@ -209,8 +208,7 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s, object_property_set_bool(OBJECT(&s->rpu_cpu[i]), "reset-hivecs", true, &error_abort); - if (!qdev_realize(DEVICE(&s->rpu_cpu[i]), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->rpu_cpu[i]), NULL, errp)) { return; } } @@ -366,14 +364,12 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) GIC_BASE_ADDR, &error_abort); object_property_set_int(OBJECT(&s->apu_cpu[i]), "core-count", num_apus, &error_abort); - if (!qdev_realize(DEVICE(&s->apu_cpu[i]), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->apu_cpu[i]), NULL, errp)) { return; } } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) { return; } @@ -467,8 +463,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->gem[i]), "num-priority-queues", 2, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]); @@ -478,8 +473,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) { qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, uart_addr[i]); @@ -489,8 +483,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(&s->sata), "num-ports", SATA_NUM_PORTS, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->sata), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->sata), errp)) { return; } @@ -507,21 +500,17 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) * - SDIO Specification Version 3.0 * - eMMC Specification Version 4.51 */ - if (!object_property_set_uint(sdhci, "sd-spec-version", 3, &err)) { - error_propagate(errp, err); + if (!object_property_set_uint(sdhci, "sd-spec-version", 3, errp)) { return; } if (!object_property_set_uint(sdhci, "capareg", SDHCI_CAPABILITIES, - &err)) { - error_propagate(errp, err); + errp)) { return; } - if (!object_property_set_uint(sdhci, "uhs", UHS_I, &err)) { - error_propagate(errp, err); + if (!object_property_set_uint(sdhci, "uhs", UHS_I, errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(sdhci), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(sdhci), errp)) { return; } sysbus_mmio_map(sbd, 0, sdhci_addr[i]); @@ -536,8 +525,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { gchar *bus_name; - if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } @@ -552,8 +540,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) g_free(bus_name); } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->qspi), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->qspi), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 0, QSPI_ADDR); @@ -573,15 +560,13 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) g_free(target_bus); } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->dp), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->dp), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->dp), 0, DP_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->dp), 0, gic_spi[DP_IRQ]); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->dpdma), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->dpdma), errp)) { return; } object_property_set_link(OBJECT(&s->dp), "dpdma", OBJECT(&s->dpdma), @@ -589,15 +574,13 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->dpdma), 0, DPDMA_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->dpdma), 0, gic_spi[DPDMA_IRQ]); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->ipi), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ipi), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ipi), 0, IPI_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ipi), 0, gic_spi[IPI_IRQ]); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, RTC_ADDR); @@ -605,12 +588,10 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < XLNX_ZYNQMP_NUM_GDMA_CH; i++) { if (!object_property_set_uint(OBJECT(&s->gdma[i]), "bus-width", 128, - &err)) { - error_propagate(errp, err); + errp)) { return; } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gdma[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gdma[i]), errp)) { return; } @@ -620,8 +601,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) } for (i = 0; i < XLNX_ZYNQMP_NUM_ADMA_CH; i++) { - if (!sysbus_realize(SYS_BUS_DEVICE(&s->adma[i]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->adma[i]), errp)) { return; } diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 3be8c7be5b..f22f46c9c9 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2575,8 +2575,7 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, return; } - if (!qdev_realize_and_unref(dev, &fdctrl->bus.bus, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize_and_unref(dev, &fdctrl->bus.bus, errp)) { return; } } diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 89a4d02a1b..96c6c009c7 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -403,7 +403,6 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name, DeviceState *dev = DEVICE(obj); Property *prop = opaque; XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; char *str, *p; const char *end; @@ -412,8 +411,7 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c index 1328967461..2cf3e44177 100644 --- a/hw/char/serial-pci-multi.c +++ b/hw/char/serial-pci-multi.c @@ -95,7 +95,6 @@ static void multi_serial_pci_realize(PCIDevice *dev, Error **errp) PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); SerialState *s; - Error *err = NULL; size_t i, nports = multi_serial_get_port_count(pc); pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; @@ -106,8 +105,7 @@ static void multi_serial_pci_realize(PCIDevice *dev, Error **errp) for (i = 0; i < nports; i++) { s = pci->state + i; - if (!qdev_realize(DEVICE(s), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(s), NULL, errp)) { multi_serial_pci_exit(dev); return; } diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index d22617426b..cd56924a43 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -47,10 +47,8 @@ static void serial_pci_realize(PCIDevice *dev, Error **errp) { PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); SerialState *s = &pci->state; - Error *err = NULL; - if (!qdev_realize(DEVICE(s), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(s), NULL, errp)) { return; } diff --git a/hw/char/serial.c b/hw/char/serial.c index e69096eace..2386479492 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -989,10 +989,8 @@ static void serial_io_realize(DeviceState *dev, Error **errp) { SerialIO *sio = SERIAL_IO(dev); SerialState *s = &sio->serial; - Error *local_err = NULL; - if (!qdev_realize(DEVICE(s), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(s), NULL, errp)) { return; } @@ -1095,10 +1093,8 @@ static void serial_mm_realize(DeviceState *dev, Error **errp) { SerialMM *smm = SERIAL_MM(dev); SerialState *s = &smm->serial; - Error *local_err = NULL; - if (!qdev_realize(DEVICE(s), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(s), NULL, errp)) { return; } diff --git a/hw/core/machine.c b/hw/core/machine.c index 7ff0af93ef..eb267b828d 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -290,11 +290,9 @@ static void machine_set_phandle_start(Object *obj, Visitor *v, Error **errp) { MachineState *ms = MACHINE(obj); - Error *error = NULL; int64_t value; - if (!visit_type_int(v, name, &value, &error)) { - error_propagate(errp, error); + if (!visit_type_int(v, name, &value, errp)) { return; } diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 7d2387f22c..3e4f16fc21 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -80,7 +80,6 @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name, { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - Error *local_err = NULL; void **ptr = qdev_get_prop_ptr(dev, prop); char *str; BlockBackend *blk; @@ -92,8 +91,7 @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } @@ -226,7 +224,6 @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { DeviceState *dev = DEVICE(obj); - Error *local_err = NULL; Property *prop = opaque; CharBackend *be = qdev_get_prop_ptr(dev, prop); Chardev *s; @@ -237,8 +234,7 @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } @@ -305,7 +301,6 @@ static void set_netdev(Object *obj, Visitor *v, const char *name, NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop); NetClientState **ncs = peers_ptr->ncs; NetClientState *peers[MAX_QUEUE_NUM]; - Error *local_err = NULL; int queues, err = 0, i = 0; char *str; @@ -314,8 +309,7 @@ static void set_netdev(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } @@ -386,7 +380,6 @@ static void set_audiodev(Object *obj, Visitor *v, const char* name, Property *prop = opaque; QEMUSoundCard *card = qdev_get_prop_ptr(dev, prop); AudioState *state; - Error *local_err = NULL; int err = 0; char *str; @@ -395,8 +388,7 @@ static void set_audiodev(Object *obj, Visitor *v, const char* name, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index be8d4eb9f6..2bec8a80b8 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -117,7 +117,6 @@ static void prop_set_bit(Object *obj, Visitor *v, const char *name, { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - Error *local_err = NULL; bool value; if (dev->realized) { @@ -125,8 +124,7 @@ static void prop_set_bit(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_bool(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_bool(v, name, &value, errp)) { return; } bit_prop_set(dev, prop, value); @@ -180,7 +178,6 @@ static void prop_set_bit64(Object *obj, Visitor *v, const char *name, { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - Error *local_err = NULL; bool value; if (dev->realized) { @@ -188,8 +185,7 @@ static void prop_set_bit64(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_bool(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_bool(v, name, &value, errp)) { return; } bit64_prop_set(dev, prop, value); @@ -476,7 +472,6 @@ static void set_string(Object *obj, Visitor *v, const char *name, DeviceState *dev = DEVICE(obj); Property *prop = opaque; char **ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; char *str; if (dev->realized) { @@ -484,8 +479,7 @@ static void set_string(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } g_free(*ptr); @@ -528,7 +522,6 @@ static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque, DeviceState *dev = DEVICE(obj); Property *prop = opaque; MACAddr *mac = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; int i, pos; char *str, *p; @@ -537,8 +530,7 @@ static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } @@ -832,15 +824,13 @@ static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque, Property *prop = opaque; uint32_t *ptr = qdev_get_prop_ptr(dev, prop); uint64_t value; - Error *local_err = NULL; if (dev->realized) { qdev_prop_set_after_realize(dev, name, errp); return; } - if (!visit_type_size(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_size(v, name, &value, errp)) { return; } @@ -881,15 +871,13 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name, Property *prop = opaque; uint32_t *ptr = qdev_get_prop_ptr(dev, prop); uint64_t value; - Error *local_err = NULL; if (dev->realized) { qdev_prop_set_after_realize(dev, name, errp); return; } - if (!visit_type_size(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_size(v, name, &value, errp)) { return; } /* value of 0 means "unset" */ @@ -957,7 +945,6 @@ static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name, DeviceState *dev = DEVICE(obj); Property *prop = opaque; PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; char *str, *p; char *e; unsigned long val; @@ -969,8 +956,7 @@ static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } @@ -1060,7 +1046,6 @@ static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque, DeviceState *dev = DEVICE(obj); Property *prop = opaque; QemuUUID *uuid = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; char *str; if (dev->realized) { @@ -1068,8 +1053,7 @@ static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } @@ -1135,7 +1119,6 @@ static void set_prop_arraylen(Object *obj, Visitor *v, const char *name, Property *prop = opaque; uint32_t *alenptr = qdev_get_prop_ptr(dev, prop); void **arrayptr = (void *)dev + prop->arrayoffset; - Error *local_err = NULL; void *eltptr; const char *arrayname; int i; @@ -1149,8 +1132,7 @@ static void set_prop_arraylen(Object *obj, Visitor *v, const char *name, name); return; } - if (!visit_type_uint32(v, name, alenptr, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint32(v, name, alenptr, errp)) { return; } if (!*alenptr) { @@ -1473,7 +1455,6 @@ static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name, Property *prop = opaque; PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop); int speed; - Error *local_err = NULL; if (dev->realized) { qdev_prop_set_after_realize(dev, name, errp); @@ -1481,8 +1462,7 @@ static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name, } if (!visit_type_enum(v, prop->name, &speed, prop->info->enum_table, - &local_err)) { - error_propagate(errp, local_err); + errp)) { return; } @@ -1561,7 +1541,6 @@ static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name, Property *prop = opaque; PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop); int width; - Error *local_err = NULL; if (dev->realized) { qdev_prop_set_after_realize(dev, name, errp); @@ -1569,8 +1548,7 @@ static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name, } if (!visit_type_enum(v, prop->name, &width, prop->info->enum_table, - &local_err)) { - error_propagate(errp, local_err); + errp)) { return; } diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c index 358c6152c7..c377be398d 100644 --- a/hw/cpu/a15mpcore.c +++ b/hw/cpu/a15mpcore.c @@ -53,7 +53,6 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp) DeviceState *gicdev; SysBusDevice *busdev; int i; - Error *err = NULL; bool has_el3; bool has_el2 = false; Object *cpuobj; @@ -76,8 +75,7 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp) qdev_prop_set_bit(gicdev, "has-virtualization-extensions", has_el2); } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) { return; } busdev = SYS_BUS_DEVICE(&s->gic); diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c index fc35dcf179..351295e518 100644 --- a/hw/cpu/a9mpcore.c +++ b/hw/cpu/a9mpcore.c @@ -50,15 +50,13 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) DeviceState *scudev, *gicdev, *gtimerdev, *mptimerdev, *wdtdev; SysBusDevice *scubusdev, *gicbusdev, *gtimerbusdev, *mptimerbusdev, *wdtbusdev; - Error *err = NULL; int i; bool has_el3; Object *cpuobj; scudev = DEVICE(&s->scu); qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } scubusdev = SYS_BUS_DEVICE(&s->scu); @@ -77,8 +75,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) object_property_get_bool(cpuobj, "has_el3", &error_abort); qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) { return; } gicbusdev = SYS_BUS_DEVICE(&s->gic); @@ -91,24 +88,21 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) gtimerdev = DEVICE(&s->gtimer); qdev_prop_set_uint32(gtimerdev, "num-cpu", s->num_cpu); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gtimer), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gtimer), errp)) { return; } gtimerbusdev = SYS_BUS_DEVICE(&s->gtimer); mptimerdev = DEVICE(&s->mptimer); qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->mptimer), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mptimer), errp)) { return; } mptimerbusdev = SYS_BUS_DEVICE(&s->mptimer); wdtdev = DEVICE(&s->wdt); qdev_prop_set_uint32(wdtdev, "num-cpu", s->num_cpu); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt), errp)) { return; } wdtbusdev = SYS_BUS_DEVICE(&s->wdt); diff --git a/hw/cpu/arm11mpcore.c b/hw/cpu/arm11mpcore.c index c5eef9514d..89c4e35143 100644 --- a/hw/cpu/arm11mpcore.c +++ b/hw/cpu/arm11mpcore.c @@ -76,11 +76,9 @@ static void mpcore_priv_realize(DeviceState *dev, Error **errp) DeviceState *gicdev = DEVICE(&s->gic); DeviceState *mptimerdev = DEVICE(&s->mptimer); DeviceState *wdtimerdev = DEVICE(&s->wdtimer); - Error *err = NULL; qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } @@ -90,8 +88,7 @@ static void mpcore_priv_realize(DeviceState *dev, Error **errp) ARM11MPCORE_NUM_GIC_PRIORITY_BITS); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) { return; } @@ -102,14 +99,12 @@ static void mpcore_priv_realize(DeviceState *dev, Error **errp) qdev_init_gpio_in(dev, mpcore_priv_set_irq, s->num_irq - 32); qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->mptimer), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mptimer), errp)) { return; } qdev_prop_set_uint32(wdtimerdev, "num-cpu", s->num_cpu); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdtimer), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdtimer), errp)) { return; } diff --git a/hw/cpu/core.c b/hw/cpu/core.c index d9857031ca..3a659291ea 100644 --- a/hw/cpu/core.c +++ b/hw/cpu/core.c @@ -28,11 +28,9 @@ static void core_prop_set_core_id(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { CPUCore *core = CPU_CORE(obj); - Error *local_err = NULL; int64_t value; - if (!visit_type_int(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int(v, name, &value, errp)) { return; } @@ -57,11 +55,9 @@ static void core_prop_set_nr_threads(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { CPUCore *core = CPU_CORE(obj); - Error *local_err = NULL; int64_t value; - if (!visit_type_int(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int(v, name, &value, errp)) { return; } diff --git a/hw/cpu/realview_mpcore.c b/hw/cpu/realview_mpcore.c index bf3e48b48e..96f4d2517a 100644 --- a/hw/cpu/realview_mpcore.c +++ b/hw/cpu/realview_mpcore.c @@ -65,13 +65,11 @@ static void realview_mpcore_realize(DeviceState *dev, Error **errp) DeviceState *priv = DEVICE(&s->priv); DeviceState *gic; SysBusDevice *gicbusdev; - Error *err = NULL; int n; int i; qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->priv), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->priv), errp)) { return; } sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->priv)); @@ -80,8 +78,7 @@ static void realview_mpcore_realize(DeviceState *dev, Error **errp) } /* ??? IRQ routing is hardcoded to "normal" mode. */ for (n = 0; n < 4; n++) { - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic[n]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic[n]), errp)) { return; } gic = DEVICE(&s->gic[n]); diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index d5b7d39bc4..34d8e93f28 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -31,11 +31,9 @@ static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) VirtIOGPUBase *g = vgpu->vgpu; DeviceState *vdev = DEVICE(g); int i; - Error *local_error = NULL; virtio_pci_force_virtio_1(vpci_dev); - if (!qdev_realize(vdev, BUS(&vpci_dev->bus), &local_error)) { - error_propagate(errp, local_error); + if (!qdev_realize(vdev, BUS(&vpci_dev->bus), errp)) { return; } diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index d5cebf686f..f533d7d1b4 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -93,7 +93,6 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) VirtIOVGABase *vvga = VIRTIO_VGA_BASE(vpci_dev); VirtIOGPUBase *g = vvga->vgpu; VGACommonState *vga = &vvga->vga; - Error *err = NULL; uint32_t offset; int i; @@ -138,8 +137,7 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) /* init virtio bits */ virtio_pci_force_virtio_1(vpci_dev); - if (!qdev_realize(DEVICE(g), BUS(&vpci_dev->bus), &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(g), BUS(&vpci_dev->bus), errp)) { return; } diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index 3310fe62fe..985a259e05 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -755,15 +755,13 @@ static void aspeed_gpio_get_pin(Object *obj, Visitor *v, const char *name, static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - Error *local_err = NULL; bool level; int pin = 0xfff; char group[4]; AspeedGPIOState *s = ASPEED_GPIO(obj); int set_idx, group_idx = 0; - if (!visit_type_bool(v, name, &level, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_bool(v, name, &level, errp)) { return; } if (sscanf(name, "gpio%2[A-Z]%1d", group, &pin) != 2) { diff --git a/hw/i386/pc.c b/hw/i386/pc.c index d1fed1bf87..3d419d5991 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1847,11 +1847,9 @@ static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v, Error **errp) { PCMachineState *pcms = PC_MACHINE(obj); - Error *error = NULL; uint64_t value; - if (!visit_type_size(v, name, &value, &error)) { - error_propagate(errp, error); + if (!visit_type_size(v, name, &value, errp)) { return; } if (value > 4 * GiB) { diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 76c3f78e11..dc070343c0 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -420,7 +420,6 @@ static void apic_common_set_id(Object *obj, Visitor *v, const char *name, { APICCommonState *s = APIC_COMMON(obj); DeviceState *dev = DEVICE(obj); - Error *local_err = NULL; uint32_t value; if (dev->realized) { @@ -428,8 +427,7 @@ static void apic_common_set_id(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_uint32(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint32(v, name, &value, errp)) { return; } diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 80a915e922..3c4b6e6d70 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -2619,7 +2619,6 @@ static void nvic_systick_trigger(void *opaque, int n, int level) static void armv7m_nvic_realize(DeviceState *dev, Error **errp) { NVICState *s = NVIC(dev); - Error *err = NULL; int regionlen; /* The armv7m container object will have set our CPU pointer */ @@ -2640,8 +2639,7 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) s->num_prio_bits = arm_feature(&s->cpu->env, ARM_FEATURE_V7) ? 8 : 2; - if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), errp)) { return; } sysbus_connect_irq(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), 0, @@ -2656,8 +2654,7 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) object_initialize_child(OBJECT(dev), "systick-reg-s", &s->systick[M_REG_S], TYPE_SYSTICK); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_S]), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_S]), errp)) { return; } sysbus_connect_irq(SYS_BUS_DEVICE(&s->systick[M_REG_S]), 0, diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index d6780061f4..5f69626b3a 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -1832,8 +1832,7 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(xsrc), "nr-irqs", PNV_XIVE_NR_IRQS, &error_fatal); object_property_set_link(OBJECT(xsrc), "xive", OBJECT(xive), &error_abort); - if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(xsrc), NULL, errp)) { return; } @@ -1841,8 +1840,7 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp) &error_fatal); object_property_set_link(OBJECT(end_xsrc), "xive", OBJECT(xive), &error_abort); - if (!qdev_realize(DEVICE(end_xsrc), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(end_xsrc), NULL, errp)) { return; } diff --git a/hw/intc/realview_gic.c b/hw/intc/realview_gic.c index aa0010e91f..9b12116b2a 100644 --- a/hw/intc/realview_gic.c +++ b/hw/intc/realview_gic.c @@ -26,7 +26,6 @@ static void realview_gic_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd = SYS_BUS_DEVICE(dev); RealViewGICState *s = REALVIEW_GIC(dev); SysBusDevice *busdev; - Error *err = NULL; /* The GICs on the RealView boards have a fixed nonconfigurable * number of interrupt lines, so we don't need to expose this as * a qdev property. @@ -34,8 +33,7 @@ static void realview_gic_realize(DeviceState *dev, Error **errp) int numirq = 96; qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", numirq); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) { return; } busdev = SYS_BUS_DEVICE(&s->gic); diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 1f42bf4f43..89c8cd9667 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -311,8 +311,7 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(xsrc), "nr-irqs", xive->nr_irqs, &error_fatal); object_property_set_link(OBJECT(xsrc), "xive", OBJECT(xive), &error_abort); - if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(xsrc), NULL, errp)) { return; } sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xsrc->esb_mmio); @@ -324,8 +323,7 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) &error_fatal); object_property_set_link(OBJECT(end_xsrc), "xive", OBJECT(xive), &error_abort); - if (!qdev_realize(DEVICE(end_xsrc), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(end_xsrc), NULL, errp)) { return; } sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio); diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index 8d6156578f..68bb1914b9 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -309,16 +309,14 @@ int ics_set_kvm_state(ICSState *ics, Error **errp) } for (i = 0; i < ics->nr_irqs; i++) { - Error *local_err = NULL; int ret; if (ics_irq_free(ics, i)) { continue; } - ret = ics_set_kvm_state_one(ics, i, &local_err); + ret = ics_set_kvm_state_one(ics, i, errp); if (ret < 0) { - error_propagate(errp, local_err); return ret; } } diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 09d7daabed..ac044afa95 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -150,7 +150,6 @@ static void piix4_realize(PCIDevice *dev, Error **errp) PIIX4State *s = PIIX4_PCI_DEVICE(dev); ISABus *isa_bus; qemu_irq *i8259_out_irq; - Error *err = NULL; isa_bus = isa_bus_new(DEVICE(dev), pci_address_space(dev), pci_address_space_io(dev), errp); @@ -183,8 +182,7 @@ static void piix4_realize(PCIDevice *dev, Error **errp) /* RTC */ qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000); - if (!qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), errp)) { return; } isa_init_irq(ISA_DEVICE(&s->rtc), &s->rtc.irq, RTC_ISA_IRQ); diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index 838ebcd227..d0d6e553cf 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -45,7 +45,6 @@ static void nvdimm_set_label_size(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { NVDIMMDevice *nvdimm = NVDIMM(obj); - Error *local_err = NULL; uint64_t value; if (nvdimm->nvdimm_mr) { @@ -53,8 +52,7 @@ static void nvdimm_set_label_size(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_size(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_size(v, name, &value, errp)) { return; } if (value < MIN_NAMESPACE_LABEL_SIZE) { diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index d22d3e22d1..5f994547f7 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -76,7 +76,6 @@ static void xlnx_zynqmp_pmu_soc_init(Object *obj) static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) { XlnxZynqMPPMUSoCState *s = XLNX_ZYNQMP_PMU_SOC(dev); - Error *err = NULL; object_property_set_uint(OBJECT(&s->cpu), "base-vectors", XLNX_ZYNQMP_PMU_ROM_ADDR, &error_abort); @@ -96,8 +95,7 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) object_property_set_str(OBJECT(&s->cpu), "version", "8.40.b", &error_abort); object_property_set_uint(OBJECT(&s->cpu), "pvr", 0, &error_abort); - if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cpu), NULL, errp)) { return; } @@ -107,8 +105,7 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_uint(OBJECT(&s->intc), "intc-positive", 0xffff, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->intc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->intc), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->intc), 0, XLNX_ZYNQMP_PMU_INTC_ADDR); diff --git a/hw/mips/cps.c b/hw/mips/cps.c index 83a073fba5..615e1a1ad2 100644 --- a/hw/mips/cps.c +++ b/hw/mips/cps.c @@ -71,7 +71,6 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) CPUMIPSState *env; MIPSCPU *cpu; int i; - Error *err = NULL; target_ulong gcr_base; bool itu_present = false; bool saar_present = false; @@ -109,8 +108,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) if (saar_present) { s->itu.saar = &env->CP0_SAAR; } - if (!sysbus_realize(SYS_BUS_DEVICE(&s->itu), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->itu), errp)) { return; } @@ -124,8 +122,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->cpc), "vp-start-running", 1, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpc), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpc), errp)) { return; } @@ -138,8 +135,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->gic), "num-irq", 128, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) { return; } @@ -160,8 +156,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_link(OBJECT(&s->gcr), "cpc", OBJECT(&s->cpc.mr), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) { return; } diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index 40682af0b3..0737d8de81 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -223,12 +223,10 @@ static void aspeed_sdmc_set_ram_size(Object *obj, Visitor *v, const char *name, int i; char *sz; int64_t value; - Error *local_err = NULL; AspeedSDMCState *s = ASPEED_SDMC(obj); AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s); - if (!visit_type_int(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int(v, name, &value, errp)) { return; } diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index cc7c26d67c..286e7a55f4 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -521,13 +521,11 @@ static void cuda_reset(DeviceState *dev) static void cuda_realize(DeviceState *dev, Error **errp) { CUDAState *s = CUDA(dev); - Error *err = NULL; SysBusDevice *sbd; ADBBusState *adb_bus = &s->adb_bus; struct tm tm; - if (!sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_cuda), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_cuda), errp)) { return; } diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 9b6e3f120e..679722628e 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -98,10 +98,8 @@ static void macio_common_realize(PCIDevice *d, Error **errp) { MacIOState *s = MACIO(d); SysBusDevice *sysbus_dev; - Error *err = NULL; - if (!qdev_realize(DEVICE(&s->dbdma), BUS(&s->macio_bus), &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->dbdma), BUS(&s->macio_bus), errp)) { return; } sysbus_dev = SYS_BUS_DEVICE(&s->dbdma); @@ -115,8 +113,7 @@ static void macio_common_realize(PCIDevice *d, Error **errp) qdev_prop_set_chr(DEVICE(&s->escc), "chrB", serial_hd(1)); qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial); qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial); - if (!qdev_realize(DEVICE(&s->escc), BUS(&s->macio_bus), &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->escc), BUS(&s->macio_bus), errp)) { return; } @@ -157,8 +154,7 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp) qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency", s->frequency); - if (!qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), errp)) { return; } sysbus_dev = SYS_BUS_DEVICE(&s->cuda); @@ -173,8 +169,7 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp) sysbus_connect_irq(sysbus_dev, 1, qdev_get_gpio_in(pic_dev, OLDWORLD_ESCCA_IRQ)); - if (!qdev_realize(DEVICE(&os->nvram), BUS(&s->macio_bus), &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&os->nvram), BUS(&s->macio_bus), errp)) { return; } sysbus_dev = SYS_BUS_DEVICE(&os->nvram); @@ -343,8 +338,7 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) object_property_set_link(OBJECT(&s->pmu), "gpio", OBJECT(sysbus_dev), &error_abort); qdev_prop_set_bit(DEVICE(&s->pmu), "has-adb", ns->has_adb); - if (!qdev_realize(DEVICE(&s->pmu), BUS(&s->macio_bus), &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->pmu), BUS(&s->macio_bus), errp)) { return; } sysbus_dev = SYS_BUS_DEVICE(&s->pmu); @@ -360,8 +354,7 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency", s->frequency); - if (!qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), errp)) { return; } sysbus_dev = SYS_BUS_DEVICE(&s->cuda); diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index 42ba963d8c..09022995ad 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -735,13 +735,11 @@ static void pmu_reset(DeviceState *dev) static void pmu_realize(DeviceState *dev, Error **errp) { PMUState *s = VIA_PMU(dev); - Error *err = NULL; SysBusDevice *sbd; ADBBusState *adb_bus = &s->adb_bus; struct tm tm; - if (!sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_pmu), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_pmu), errp)) { return; } diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index d2b99fc706..e4ccdeaf78 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -291,13 +291,11 @@ static void pca955x_set_led(Object *obj, Visitor *v, const char *name, { PCA955xClass *k = PCA955X_GET_CLASS(obj); PCA955xState *s = PCA955X(obj); - Error *local_err = NULL; int led, rc, reg, val; uint8_t state; char *state_str; - if (!visit_type_str(v, name, &state_str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &state_str, errp)) { return; } rc = sscanf(name, "led%2d", &led); diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c index 2ae0b899be..b47120492a 100644 --- a/hw/misc/tmp105.c +++ b/hw/misc/tmp105.c @@ -72,11 +72,9 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { TMP105State *s = TMP105(obj); - Error *local_err = NULL; int64_t temp; - if (!visit_type_int(v, name, &temp, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int(v, name, &temp, errp)) { return; } if (temp >= 128000 || temp < -128000) { diff --git a/hw/misc/tmp421.c b/hw/misc/tmp421.c index 9473382bd5..49abe2d246 100644 --- a/hw/misc/tmp421.c +++ b/hw/misc/tmp421.c @@ -141,14 +141,12 @@ static void tmp421_set_temperature(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { TMP421State *s = TMP421(obj); - Error *local_err = NULL; int64_t temp; bool ext_range = (s->config[0] & TMP421_CONFIG_RANGE); int offset = ext_range * 64 * 256; int tempid; - if (!visit_type_int(v, name, &temp, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int(v, name, &temp, errp)) { return; } diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index 94cb989136..82132c12ca 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -990,7 +990,6 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) PnvPHB3 *phb = PNV_PHB3(dev); PCIHostState *pci = PCI_HOST_BRIDGE(dev); PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); - Error *local_err = NULL; int i; if (phb->phb_id >= PNV8_CHIP_PHB3_MAX) { @@ -1003,8 +1002,7 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&phb->lsis), "nr-irqs", PNV_PHB3_NUM_LSI, &error_abort); - if (!qdev_realize(DEVICE(&phb->lsis), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&phb->lsis), NULL, errp)) { return; } @@ -1021,16 +1019,14 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&phb->msis), "nr-irqs", PHB3_MAX_MSI, &error_abort); - if (!qdev_realize(DEVICE(&phb->msis), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&phb->msis), NULL, errp)) { return; } /* Power Bus Common Queue */ object_property_set_link(OBJECT(&phb->pbcq), "phb", OBJECT(phb), &error_abort); - if (!qdev_realize(DEVICE(&phb->pbcq), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&phb->pbcq), NULL, errp)) { return; } diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index a598c89eb0..75ad766fe0 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1169,7 +1169,6 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) PnvPHB4 *phb = PNV_PHB4(dev); PCIHostState *pci = PCI_HOST_BRIDGE(dev); XiveSource *xsrc = &phb->xsrc; - Error *local_err = NULL; int nr_irqs; char name[32]; @@ -1218,8 +1217,7 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) } object_property_set_int(OBJECT(xsrc), "nr-irqs", nr_irqs, &error_fatal); object_property_set_link(OBJECT(xsrc), "xive", OBJECT(phb), &error_fatal); - if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(xsrc), NULL, errp)) { return; } diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index 088ab753aa..741ddc90ed 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -377,7 +377,6 @@ static void pnv_pec_instance_init(Object *obj) static void pnv_pec_realize(DeviceState *dev, Error **errp) { PnvPhb4PecState *pec = PNV_PHB4_PEC(dev); - Error *local_err = NULL; char name[64]; int i; @@ -390,8 +389,7 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp) object_property_set_int(stk_obj, "stack-no", i, &error_abort); object_property_set_link(stk_obj, "pec", OBJECT(pec), &error_abort); - if (!qdev_realize(DEVICE(stk_obj), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(stk_obj), NULL, errp)) { return; } } diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 97fa970e72..5448d101d9 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -764,15 +764,13 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms, static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc, IrqLines *irqs, Error **errp) { - Error *err = NULL; DeviceState *dev; CPUState *cs; dev = qdev_new(TYPE_KVM_OPENPIC); qdev_prop_set_uint32(dev, "model", pmc->mpic_version); - if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &err)) { - error_propagate(errp, err); + if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp)) { object_unparent(OBJECT(dev)); return NULL; } diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 194b457917..6670967e26 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1140,8 +1140,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) &error_fatal); object_property_set_link(OBJECT(&chip8->psi), ICS_PROP_XICS, OBJECT(chip8->xics), &error_abort); - if (!qdev_realize(DEVICE(&chip8->psi), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&chip8->psi), NULL, errp)) { return; } pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, @@ -1170,8 +1169,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) /* Create the simplified OCC model */ object_property_set_link(OBJECT(&chip8->occ), "psi", OBJECT(&chip8->psi), &error_abort); - if (!qdev_realize(DEVICE(&chip8->occ), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&chip8->occ), NULL, errp)) { return; } pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs); @@ -1183,8 +1181,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) /* HOMER */ object_property_set_link(OBJECT(&chip8->homer), "chip", OBJECT(chip), &error_abort); - if (!qdev_realize(DEVICE(&chip8->homer), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&chip8->homer), NULL, errp)) { return; } /* Homer Xscom region */ @@ -1202,8 +1199,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(phb), "index", i, &error_fatal); object_property_set_int(OBJECT(phb), "chip-id", chip->chip_id, &error_fatal); - if (!sysbus_realize(SYS_BUS_DEVICE(phb), &local_err)) { - error_propagate(errp, local_err); + if (!sysbus_realize(SYS_BUS_DEVICE(phb), errp)) { return; } @@ -1358,7 +1354,6 @@ static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp) static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp) { Pnv9Chip *chip9 = PNV9_CHIP(chip); - Error *local_err = NULL; int i, j; int phb_id = 0; @@ -1380,8 +1375,7 @@ static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp) &error_fatal); object_property_set_link(OBJECT(pec), "system-memory", OBJECT(get_system_memory()), &error_abort); - if (!qdev_realize(DEVICE(pec), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(pec), NULL, errp)) { return; } @@ -1405,8 +1399,7 @@ static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp) &error_fatal); object_property_set_link(obj, "stack", OBJECT(stack), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(obj), &local_err)) { - error_propagate(errp, local_err); + if (!sysbus_realize(SYS_BUS_DEVICE(obj), errp)) { return; } @@ -1464,8 +1457,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) PNV9_XIVE_TM_BASE(chip), &error_fatal); object_property_set_link(OBJECT(&chip9->xive), "chip", OBJECT(chip), &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&chip9->xive), &local_err)) { - error_propagate(errp, local_err); + if (!sysbus_realize(SYS_BUS_DEVICE(&chip9->xive), errp)) { return; } pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE, @@ -1474,8 +1466,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* Processor Service Interface (PSI) Host Bridge */ object_property_set_int(OBJECT(&chip9->psi), "bar", PNV9_PSIHB_BASE(chip), &error_fatal); - if (!qdev_realize(DEVICE(&chip9->psi), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&chip9->psi), NULL, errp)) { return; } pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE, @@ -1484,8 +1475,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* LPC */ object_property_set_link(OBJECT(&chip9->lpc), "psi", OBJECT(&chip9->psi), &error_abort); - if (!qdev_realize(DEVICE(&chip9->lpc), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&chip9->lpc), NULL, errp)) { return; } memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip), @@ -1497,8 +1487,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* Create the simplified OCC model */ object_property_set_link(OBJECT(&chip9->occ), "psi", OBJECT(&chip9->psi), &error_abort); - if (!qdev_realize(DEVICE(&chip9->occ), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&chip9->occ), NULL, errp)) { return; } pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs); @@ -1510,8 +1499,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* HOMER */ object_property_set_link(OBJECT(&chip9->homer), "chip", OBJECT(chip), &error_abort); - if (!qdev_realize(DEVICE(&chip9->homer), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&chip9->homer), NULL, errp)) { return; } /* Homer Xscom region */ @@ -1591,8 +1579,7 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) /* Processor Service Interface (PSI) Host Bridge */ object_property_set_int(OBJECT(&chip10->psi), "bar", PNV10_PSIHB_BASE(chip), &error_fatal); - if (!qdev_realize(DEVICE(&chip10->psi), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&chip10->psi), NULL, errp)) { return; } pnv_xscom_add_subregion(chip, PNV10_XSCOM_PSIHB_BASE, @@ -1601,8 +1588,7 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) /* LPC */ object_property_set_link(OBJECT(&chip10->lpc), "psi", OBJECT(&chip10->psi), &error_abort); - if (!qdev_realize(DEVICE(&chip10->lpc), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(&chip10->lpc), NULL, errp)) { return; } memory_region_add_subregion(get_system_memory(), PNV10_LPCM_BASE(chip), diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index d699f077ad..4724ddf96c 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -173,8 +173,7 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp) Error *local_err = NULL; PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip); - if (!qdev_realize(DEVICE(cpu), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(cpu), NULL, errp)) { return; } diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 604788a8eb..5bdeec700e 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -501,17 +501,14 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp) { PnvPsi *psi = PNV_PSI(dev); ICSState *ics = &PNV8_PSI(psi)->ics; - Error *err = NULL; unsigned int i; /* Create PSI interrupt control source */ if (!object_property_set_int(OBJECT(ics), "nr-irqs", PSI_NUM_INTERRUPTS, - &err)) { - error_propagate(errp, err); + errp)) { return; } - if (!qdev_realize(DEVICE(ics), NULL, &err)) { - error_propagate(errp, err); + if (!qdev_realize(DEVICE(ics), NULL, errp)) { return; } @@ -841,7 +838,6 @@ static void pnv_psi_power9_realize(DeviceState *dev, Error **errp) { PnvPsi *psi = PNV_PSI(dev); XiveSource *xsrc = &PNV9_PSI(psi)->source; - Error *local_err = NULL; int i; /* This is the only device with 4k ESB pages */ @@ -849,8 +845,7 @@ static void pnv_psi_power9_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(xsrc), "nr-irqs", PSIHB9_NUM_IRQS, &error_fatal); object_property_set_link(OBJECT(xsrc), "xive", OBJECT(psi), &error_abort); - if (!qdev_realize(DEVICE(xsrc), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(xsrc), NULL, errp)) { return; } diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 52be86e49c..3225fc5a2e 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -86,10 +86,8 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, SpaprCapabilityInfo *cap = opaque; SpaprMachineState *spapr = SPAPR_MACHINE(obj); bool value; - Error *local_err = NULL; - if (!visit_type_bool(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_bool(v, name, &value, errp)) { return; } @@ -122,12 +120,10 @@ static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name, { SpaprCapabilityInfo *cap = opaque; SpaprMachineState *spapr = SPAPR_MACHINE(obj); - Error *local_err = NULL; uint8_t i; char *val; - if (!visit_type_str(v, name, &val, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &val, errp)) { return; } @@ -167,10 +163,8 @@ static void spapr_cap_set_pagesize(Object *obj, Visitor *v, const char *name, SpaprMachineState *spapr = SPAPR_MACHINE(obj); uint64_t pagesize; uint8_t val; - Error *local_err = NULL; - if (!visit_type_size(v, name, &pagesize, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_size(v, name, &pagesize, errp)) { return; } diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 1f18b79348..43d12bc33a 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -327,8 +327,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, case FDT_BEGIN_NODE: fdt_depth++; name = fdt_get_name(fdt, fdt_offset, &name_len); - if (!visit_start_struct(v, name, NULL, 0, &err)) { - error_propagate(errp, err); + if (!visit_start_struct(v, name, NULL, 0, errp)) { return; } break; @@ -347,14 +346,12 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, int i; prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len); name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - if (!visit_start_list(v, name, NULL, 0, &err)) { - error_propagate(errp, err); + if (!visit_start_list(v, name, NULL, 0, errp)) { return; } for (i = 0; i < prop_len; i++) { if (!visit_type_uint8(v, NULL, (uint8_t *)&prop->data[i], - &err)) { - error_propagate(errp, err); + errp)) { return; } } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index eb55171d70..2f8f7d62f8 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -302,7 +302,6 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) spapr_irq_msi_init(spapr); if (spapr->irq->xics) { - Error *local_err = NULL; Object *obj; obj = object_new(TYPE_ICS_SPAPR); @@ -311,8 +310,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) object_property_set_link(obj, ICS_PROP_XICS, OBJECT(spapr), &error_abort); object_property_set_int(obj, "nr-irqs", smc->nr_xirqs, &error_abort); - if (!qdev_realize(DEVICE(obj), NULL, &local_err)) { - error_propagate(errp, local_err); + if (!qdev_realize(DEVICE(obj), NULL, errp)) { return; } diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 7003b1f62d..a8f0039e51 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -106,7 +106,6 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) MachineState *ms = MACHINE(qdev_get_machine()); LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc); MemoryRegion *sys_mem = get_system_memory(); - Error *err = NULL; object_property_set_str(OBJECT(&s->cpus), "cpu-type", ms->cpu_type, &error_abort); @@ -127,16 +126,14 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) &s->flash_mem); /* PLIC */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->plic), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->plic), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->plic), 0, memmap[IBEX_PLIC].base); /* UART */ qdev_prop_set_chr(DEVICE(&(s->uart)), "chardev", serial_hd(0)); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart), 0, memmap[IBEX_UART].base); diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index f2df06cc43..7bb97b463d 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -185,8 +185,6 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); const struct MemmapEntry *memmap = sifive_e_memmap; - Error *err = NULL; - SiFiveESoCState *s = RISCV_E_SOC(dev); MemoryRegion *sys_mem = get_system_memory(); @@ -221,8 +219,7 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp) /* GPIO */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; } diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index e70253d58f..7851326988 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -608,7 +608,6 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) char *plic_hart_config; size_t plic_hart_config_len; int i; - Error *err = NULL; NICInfo *nd = &nd_table[0]; sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort); @@ -710,8 +709,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) } object_property_set_int(OBJECT(&s->gem), "revision", GEM_REVISION, &error_abort); - if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem), &err)) { - error_propagate(errp, err); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem), errp)) { return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem), 0, memmap[SIFIVE_U_GEM].base); diff --git a/hw/s390x/css.c b/hw/s390x/css.c index ab28b2fb30..519dc91316 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -2377,7 +2377,6 @@ static void set_css_devid(Object *obj, Visitor *v, const char *name, DeviceState *dev = DEVICE(obj); Property *prop = opaque; CssDevId *dev_id = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; char *str; int num, n1, n2; unsigned int cssid, ssid, devid; @@ -2387,8 +2386,7 @@ static void set_css_devid(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &str, errp)) { return; } diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index cee2908ae9..645b4080c5 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -442,16 +442,13 @@ static void init_event_facility(Object *obj) static void realize_event_facility(DeviceState *dev, Error **errp) { SCLPEventFacility *event_facility = EVENT_FACILITY(dev); - Error *local_err = NULL; if (!qdev_realize(DEVICE(&event_facility->quiesce), - BUS(&event_facility->sbus), &local_err)) { - error_propagate(errp, local_err); + BUS(&event_facility->sbus), errp)) { return; } if (!qdev_realize(DEVICE(&event_facility->cpu_hotplug), - BUS(&event_facility->sbus), &local_err)) { - error_propagate(errp, local_err); + BUS(&event_facility->sbus), errp)) { qdev_unrealize(DEVICE(&event_facility->quiesce)); return; } diff --git a/hw/s390x/virtio-ccw-crypto.c b/hw/s390x/virtio-ccw-crypto.c index 5720e84fc9..570c0333fc 100644 --- a/hw/s390x/virtio-ccw-crypto.c +++ b/hw/s390x/virtio-ccw-crypto.c @@ -19,10 +19,8 @@ static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) { VirtIOCryptoCcw *dev = VIRTIO_CRYPTO_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); - Error *err = NULL; - if (!qdev_realize(vdev, BUS(&ccw_dev->bus), &err)) { - error_propagate(errp, err); + if (!qdev_realize(vdev, BUS(&ccw_dev->bus), errp)) { return; } diff --git a/hw/s390x/virtio-ccw-rng.c b/hw/s390x/virtio-ccw-rng.c index 8cf01ce76c..4bb8c16d79 100644 --- a/hw/s390x/virtio-ccw-rng.c +++ b/hw/s390x/virtio-ccw-rng.c @@ -20,10 +20,8 @@ static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) { VirtIORNGCcw *dev = VIRTIO_RNG_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); - Error *err = NULL; - if (!qdev_realize(vdev, BUS(&ccw_dev->bus), &err)) { - error_propagate(errp, err); + if (!qdev_realize(vdev, BUS(&ccw_dev->bus), errp)) { return; } diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 38b66a2f45..df65cc2223 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -248,7 +248,6 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, const char *driver; char *name; DeviceState *dev; - Error *err = NULL; DriveInfo *dinfo; if (blk_is_sg(blk)) { @@ -277,13 +276,11 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, if (serial && object_property_find(OBJECT(dev), "serial", NULL)) { qdev_prop_set_string(dev, "serial", serial); } - if (!qdev_prop_set_drive_err(dev, "drive", blk, &err)) { - error_propagate(errp, err); + if (!qdev_prop_set_drive_err(dev, "drive", blk, errp)) { object_unparent(OBJECT(dev)); return NULL; } - if (!object_property_set_bool(OBJECT(dev), "share-rw", share_rw, &err)) { - error_propagate(errp, err); + if (!object_property_set_bool(OBJECT(dev), "share-rw", share_rw, errp)) { object_unparent(OBJECT(dev)); return NULL; } @@ -291,8 +288,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, qdev_prop_set_enum(dev, "rerror", rerror); qdev_prop_set_enum(dev, "werror", werror); - if (!qdev_realize_and_unref(dev, &bus->qbus, &err)) { - error_propagate(errp, err); + if (!qdev_realize_and_unref(dev, &bus->qbus, errp)) { object_unparent(OBJECT(dev)); return NULL; } diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c index 687b300773..22cafce0fb 100644 --- a/hw/sd/aspeed_sdhci.c +++ b/hw/sd/aspeed_sdhci.c @@ -115,7 +115,6 @@ static void aspeed_sdhci_set_irq(void *opaque, int n, int level) static void aspeed_sdhci_realize(DeviceState *dev, Error **errp) { - Error *err = NULL; SysBusDevice *sbd = SYS_BUS_DEVICE(dev); AspeedSDHCIState *sdhci = ASPEED_SDHCI(dev); @@ -132,19 +131,16 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp) Object *sdhci_slot = OBJECT(&sdhci->slots[i]); SysBusDevice *sbd_slot = SYS_BUS_DEVICE(&sdhci->slots[i]); - if (!object_property_set_int(sdhci_slot, "sd-spec-version", 2, &err)) { - error_propagate(errp, err); + if (!object_property_set_int(sdhci_slot, "sd-spec-version", 2, errp)) { return; } if (!object_property_set_uint(sdhci_slot, "capareg", - ASPEED_SDHCI_CAPABILITIES, &err)) { - error_propagate(errp, err); + ASPEED_SDHCI_CAPABILITIES, errp)) { return; } - if (!sysbus_realize(sbd_slot, &err)) { - error_propagate(errp, err); + if (!sysbus_realize(sbd_slot, errp)) { return; } diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index 87afcf9142..f560826904 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -953,7 +953,6 @@ static void save_opt_list(size_t *ndest, const char ***dest, void smbios_entry_add(QemuOpts *opts, Error **errp) { - Error *err = NULL; const char *val; assert(!smbios_immutable); @@ -964,8 +963,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) int size; struct smbios_table *table; /* legacy mode only */ - if (!qemu_opts_validate(opts, qemu_smbios_file_opts, &err)) { - error_propagate(errp, err); + if (!qemu_opts_validate(opts, qemu_smbios_file_opts, errp)) { return; } @@ -1050,8 +1048,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) switch (type) { case 0: - if (!qemu_opts_validate(opts, qemu_smbios_type0_opts, &err)) { - error_propagate(errp, err); + if (!qemu_opts_validate(opts, qemu_smbios_type0_opts, errp)) { return; } save_opt(&type0.vendor, opts, "vendor"); @@ -1069,8 +1066,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) } return; case 1: - if (!qemu_opts_validate(opts, qemu_smbios_type1_opts, &err)) { - error_propagate(errp, err); + if (!qemu_opts_validate(opts, qemu_smbios_type1_opts, errp)) { return; } save_opt(&type1.manufacturer, opts, "manufacturer"); @@ -1090,8 +1086,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) } return; case 2: - if (!qemu_opts_validate(opts, qemu_smbios_type2_opts, &err)) { - error_propagate(errp, err); + if (!qemu_opts_validate(opts, qemu_smbios_type2_opts, errp)) { return; } save_opt(&type2.manufacturer, opts, "manufacturer"); @@ -1102,8 +1097,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type2.location, opts, "location"); return; case 3: - if (!qemu_opts_validate(opts, qemu_smbios_type3_opts, &err)) { - error_propagate(errp, err); + if (!qemu_opts_validate(opts, qemu_smbios_type3_opts, errp)) { return; } save_opt(&type3.manufacturer, opts, "manufacturer"); @@ -1113,8 +1107,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type3.sku, opts, "sku"); return; case 4: - if (!qemu_opts_validate(opts, qemu_smbios_type4_opts, &err)) { - error_propagate(errp, err); + if (!qemu_opts_validate(opts, qemu_smbios_type4_opts, errp)) { return; } save_opt(&type4.sock_pfx, opts, "sock_pfx"); @@ -1125,15 +1118,13 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type4.part, opts, "part"); return; case 11: - if (!qemu_opts_validate(opts, qemu_smbios_type11_opts, &err)) { - error_propagate(errp, err); + if (!qemu_opts_validate(opts, qemu_smbios_type11_opts, errp)) { return; } save_opt_list(&type11.nvalues, &type11.values, opts, "value"); return; case 17: - if (!qemu_opts_validate(opts, qemu_smbios_type17_opts, &err)) { - error_propagate(errp, err); + if (!qemu_opts_validate(opts, qemu_smbios_type17_opts, errp)) { return; } save_opt(&type17.loc_pfx, opts, "loc_pfx"); diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index 1467b8034e..3a14b7c303 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1502,15 +1502,13 @@ static void set_nv_gpudirect_clique_id(Object *obj, Visitor *v, DeviceState *dev = DEVICE(obj); Property *prop = opaque; uint8_t value, *ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; if (dev->realized) { qdev_prop_set_after_realize(dev, name, errp); return; } - if (!visit_type_uint8(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint8(v, name, &value, errp)) { return; } diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index d020ea9f82..6fde80cb9a 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -116,7 +116,6 @@ static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp) { #ifdef CONFIG_KVM int irq_fd = event_notifier_get_fd(&vdev->intx.interrupt); - Error *err = NULL; if (vdev->no_kvm_intx || !kvm_irqfds_enabled() || vdev->intx.route.mode != PCI_INTX_ENABLED || @@ -147,8 +146,7 @@ static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp) if (vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX, 0, VFIO_IRQ_SET_ACTION_UNMASK, event_notifier_get_fd(&vdev->intx.unmask), - &err)) { - error_propagate(errp, err); + errp)) { goto fail_vfio; } @@ -2741,9 +2739,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (!pdev->failover_pair_id) { error_setg(&vdev->migration_blocker, "VFIO device doesn't support migration"); - ret = migrate_add_blocker(vdev->migration_blocker, &err); + ret = migrate_add_blocker(vdev->migration_blocker, errp); if (ret) { - error_propagate(errp, err); error_free(vdev->migration_blocker); vdev->migration_blocker = NULL; return; diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 277747f4f1..e670f1e595 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -280,11 +280,9 @@ static void balloon_stats_set_poll_interval(Object *obj, Visitor *v, Error **errp) { VirtIOBalloon *s = opaque; - Error *local_err = NULL; int64_t value; - if (!visit_type_int(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int(v, name, &value, errp)) { return; } diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c index 8b11c4b425..2f0b529b62 100644 --- a/hw/virtio/virtio-rng-pci.c +++ b/hw/virtio/virtio-rng-pci.c @@ -34,10 +34,8 @@ static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev); DeviceState *vdev = DEVICE(&vrng->vdev); - Error *err = NULL; - if (!qdev_realize(vdev, BUS(&vpci_dev->bus), &err)) { - error_propagate(errp, err); + if (!qdev_realize(vdev, BUS(&vpci_dev->bus), errp)) { return; } diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index 8d052fbeed..2886c0ce2a 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -176,7 +176,6 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIORNG *vrng = VIRTIO_RNG(dev); - Error *local_err = NULL; if (vrng->conf.period_ms <= 0) { error_setg(errp, "'period' parameter expects a positive integer"); @@ -195,8 +194,7 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp) Object *default_backend = object_new(TYPE_RNG_BUILTIN); if (!user_creatable_complete(USER_CREATABLE(default_backend), - &local_err)) { - error_propagate(errp, local_err); + errp)) { object_unref(default_backend); return; } diff --git a/iothread.c b/iothread.c index aa8830fed2..0598a6d20d 100644 --- a/iothread.c +++ b/iothread.c @@ -169,9 +169,8 @@ static void iothread_complete(UserCreatable *obj, Error **errp) iothread->stopping = false; iothread->running = true; - iothread->ctx = aio_context_new(&local_error); + iothread->ctx = aio_context_new(errp); if (!iothread->ctx) { - error_propagate(errp, local_error); return; } @@ -240,11 +239,9 @@ static void iothread_set_poll_param(Object *obj, Visitor *v, IOThread *iothread = IOTHREAD(obj); PollParamInfo *info = opaque; int64_t *field = (void *)iothread + info->offset; - Error *local_err = NULL; int64_t value; - if (!visit_type_int64(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int64(v, name, &value, errp)) { return; } diff --git a/net/colo-compare.c b/net/colo-compare.c index d75169e28f..398b7546ff 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -1093,11 +1093,9 @@ static void compare_set_timeout(Object *obj, Visitor *v, Error **errp) { CompareState *s = COLO_COMPARE(obj); - Error *local_err = NULL; uint32_t value; - if (!visit_type_uint32(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint32(v, name, &value, errp)) { return; } if (!value) { @@ -1123,11 +1121,9 @@ static void compare_set_expired_scan_cycle(Object *obj, Visitor *v, Error **errp) { CompareState *s = COLO_COMPARE(obj); - Error *local_err = NULL; uint32_t value; - if (!visit_type_uint32(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint32(v, name, &value, errp)) { return; } if (!value) { diff --git a/net/dump.c b/net/dump.c index f7a302f56c..11a737a4bc 100644 --- a/net/dump.c +++ b/net/dump.c @@ -192,11 +192,9 @@ static void filter_dump_set_maxlen(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { NetFilterDumpState *nfds = FILTER_DUMP(obj); - Error *local_err = NULL; uint32_t value; - if (!visit_type_uint32(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint32(v, name, &value, errp)) { return; } if (value == 0) { diff --git a/net/filter-buffer.c b/net/filter-buffer.c index 143627fcaf..dfa211794b 100644 --- a/net/filter-buffer.c +++ b/net/filter-buffer.c @@ -170,11 +170,9 @@ static void filter_buffer_set_interval(Object *obj, Visitor *v, Error **errp) { FilterBufferState *s = FILTER_BUFFER(obj); - Error *local_err = NULL; uint32_t value; - if (!visit_type_uint32(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint32(v, name, &value, errp)) { return; } if (!value) { diff --git a/net/tap.c b/net/tap.c index ca48f2a285..2d8d83a30b 100644 --- a/net/tap.c +++ b/net/tap.c @@ -790,9 +790,8 @@ int net_init_tap(const Netdev *netdev, const char *name, return -1; } - fd = monitor_fd_param(cur_mon, tap->fd, &err); + fd = monitor_fd_param(cur_mon, tap->fd, errp); if (fd == -1) { - error_propagate(errp, err); return -1; } diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c index d0ca10aefa..6e53396ea3 100644 --- a/qapi/string-input-visitor.c +++ b/qapi/string-input-visitor.c @@ -315,12 +315,10 @@ static bool parse_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) { StringInputVisitor *siv = to_siv(v); - Error *err = NULL; uint64_t val; assert(siv->lm == LM_NONE); - if (!parse_option_size(name, siv->string, &val, &err)) { - error_propagate(errp, err); + if (!parse_option_size(name, siv->string, &val, errp)) { return false; } diff --git a/qdev-monitor.c b/qdev-monitor.c index edb97bd310..e2fd24e1a4 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -179,15 +179,13 @@ static int set_property(void *opaque, const char *name, const char *value, Error **errp) { Object *obj = opaque; - Error *err = NULL; if (strcmp(name, "driver") == 0) return 0; if (strcmp(name, "bus") == 0) return 0; - if (!object_property_parse(obj, name, value, &err)) { - error_propagate(errp, err); + if (!object_property_parse(obj, name, value, errp)) { return -1; } return 0; @@ -797,7 +795,6 @@ void hmp_info_qdm(Monitor *mon, const QDict *qdict) void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp) { - Error *local_err = NULL; QemuOpts *opts; DeviceState *dev; @@ -809,9 +806,8 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp) qemu_opts_del(opts); return; } - dev = qdev_device_add(opts, &local_err); + dev = qdev_device_add(opts, errp); if (!dev) { - error_propagate(errp, local_err); qemu_opts_del(opts); return; } diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 0f4911082f..aaa71f147b 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -2195,9 +2195,8 @@ GuestOSInfo *qmp_guest_get_osinfo(Error **errp) } server = os_version.wProductType != VER_NT_WORKSTATION; - product_name = ga_get_win_product_name(&local_err); + product_name = ga_get_win_product_name(errp); if (product_name == NULL) { - error_propagate(errp, local_err); return NULL; } diff --git a/qom/object.c b/qom/object.c index 07618816a7..08b2cad445 100644 --- a/qom/object.c +++ b/qom/object.c @@ -800,15 +800,13 @@ bool object_set_propv(Object *obj, va_list vargs) { const char *propname; - Error *local_err = NULL; propname = va_arg(vargs, char *); while (propname != NULL) { const char *value = va_arg(vargs, char *); g_assert(value != NULL); - if (!object_property_parse(obj, propname, value, &local_err)) { - error_propagate(errp, local_err); + if (!object_property_parse(obj, propname, value, errp)) { return false; } propname = va_arg(vargs, char *); @@ -2115,10 +2113,8 @@ static void property_set_str(Object *obj, Visitor *v, const char *name, { StringProperty *prop = opaque; char *value; - Error *local_err = NULL; - if (!visit_type_str(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &value, errp)) { return; } @@ -2195,10 +2191,8 @@ static void property_set_bool(Object *obj, Visitor *v, const char *name, { BoolProperty *prop = opaque; bool value; - Error *local_err = NULL; - if (!visit_type_bool(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_bool(v, name, &value, errp)) { return; } @@ -2267,10 +2261,8 @@ static void property_set_enum(Object *obj, Visitor *v, const char *name, { EnumProperty *prop = opaque; int value; - Error *err = NULL; - if (!visit_type_enum(v, name, &value, prop->lookup, &err)) { - error_propagate(errp, err); + if (!visit_type_enum(v, name, &value, prop->lookup, errp)) { return; } prop->set(obj, value, errp); @@ -2419,10 +2411,8 @@ static void property_set_uint8_ptr(Object *obj, Visitor *v, const char *name, { uint8_t *field = opaque; uint8_t value; - Error *local_err = NULL; - if (!visit_type_uint8(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint8(v, name, &value, errp)) { return; } @@ -2441,10 +2431,8 @@ static void property_set_uint16_ptr(Object *obj, Visitor *v, const char *name, { uint16_t *field = opaque; uint16_t value; - Error *local_err = NULL; - if (!visit_type_uint16(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint16(v, name, &value, errp)) { return; } @@ -2463,10 +2451,8 @@ static void property_set_uint32_ptr(Object *obj, Visitor *v, const char *name, { uint32_t *field = opaque; uint32_t value; - Error *local_err = NULL; - if (!visit_type_uint32(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint32(v, name, &value, errp)) { return; } @@ -2485,10 +2471,8 @@ static void property_set_uint64_ptr(Object *obj, Visitor *v, const char *name, { uint64_t *field = opaque; uint64_t value; - Error *local_err = NULL; - if (!visit_type_uint64(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_uint64(v, name, &value, errp)) { return; } diff --git a/softmmu/vl.c b/softmmu/vl.c index b3c129be78..96417a7c3a 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2463,14 +2463,11 @@ static int object_parse_property_opt(Object *obj, const char *name, const char *value, const char *skip, Error **errp) { - Error *local_err = NULL; - if (g_str_equal(name, skip)) { return 0; } - if (!object_property_parse(obj, name, value, &local_err)) { - error_propagate(errp, local_err); + if (!object_property_parse(obj, name, value, errp)) { return -1; } diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 343c227c09..15494002d2 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -464,11 +464,9 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { ARMCPU *cpu = ARM_CPU(obj); - Error *err = NULL; uint32_t max_vq; - if (!visit_type_uint32(v, name, &max_vq, &err)) { - error_propagate(errp, err); + if (!visit_type_uint32(v, name, &max_vq, errp)) { return; } @@ -509,11 +507,9 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name, { ARMCPU *cpu = ARM_CPU(obj); uint32_t vq = atoi(&name[3]) / 128; - Error *err = NULL; bool value; - if (!visit_type_bool(v, name, &value, &err)) { - error_propagate(errp, err); + if (!visit_type_bool(v, name, &value, errp)) { return; } @@ -544,12 +540,10 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { ARMCPU *cpu = ARM_CPU(obj); - Error *err = NULL; bool value; uint64_t t; - if (!visit_type_bool(v, name, &value, &err)) { - error_propagate(errp, err); + if (!visit_type_bool(v, name, &value, errp)) { return; } diff --git a/target/arm/monitor.c b/target/arm/monitor.c index c162c5fb68..ba6e01abd0 100644 --- a/target/arm/monitor.c +++ b/target/arm/monitor.c @@ -174,10 +174,9 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, Error *err = NULL; visitor = qobject_input_visitor_new(model->props); - if (!visit_start_struct(visitor, NULL, NULL, 0, &err)) { + if (!visit_start_struct(visitor, NULL, NULL, 0, errp)) { visit_free(visitor); object_unref(obj); - error_propagate(errp, err); return NULL; } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 2b60b61ced..6f27f12ec7 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -4417,11 +4417,9 @@ static void x86_cpuid_version_set_family(Object *obj, Visitor *v, CPUX86State *env = &cpu->env; const int64_t min = 0; const int64_t max = 0xff + 0xf; - Error *local_err = NULL; int64_t value; - if (!visit_type_int(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int(v, name, &value, errp)) { return; } if (value < min || value > max) { @@ -4459,11 +4457,9 @@ static void x86_cpuid_version_set_model(Object *obj, Visitor *v, CPUX86State *env = &cpu->env; const int64_t min = 0; const int64_t max = 0xff; - Error *local_err = NULL; int64_t value; - if (!visit_type_int(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int(v, name, &value, errp)) { return; } if (value < min || value > max) { @@ -4496,11 +4492,9 @@ static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v, CPUX86State *env = &cpu->env; const int64_t min = 0; const int64_t max = 0xf; - Error *local_err = NULL; int64_t value; - if (!visit_type_int(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int(v, name, &value, errp)) { return; } if (value < min || value > max) { @@ -4600,11 +4594,9 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, const char *name, X86CPU *cpu = X86_CPU(obj); const int64_t min = 0; const int64_t max = INT64_MAX; - Error *local_err = NULL; int64_t value; - if (!visit_type_int(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_int(v, name, &value, errp)) { return; } if (value < min || value > max) { @@ -6798,7 +6790,6 @@ static void x86_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, DeviceState *dev = DEVICE(obj); X86CPU *cpu = X86_CPU(obj); BitProperty *fp = opaque; - Error *local_err = NULL; bool value; if (dev->realized) { @@ -6806,8 +6797,7 @@ static void x86_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_bool(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_bool(v, name, &value, errp)) { return; } diff --git a/target/ppc/compat.c b/target/ppc/compat.c index 42f87a4bfe..08aede88dc 100644 --- a/target/ppc/compat.c +++ b/target/ppc/compat.c @@ -260,12 +260,10 @@ static void ppc_compat_prop_get(Object *obj, Visitor *v, const char *name, static void ppc_compat_prop_set(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - Error *local_err = NULL; char *value; uint32_t compat_pvr; - if (!visit_type_str(v, name, &value, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_str(v, name, &value, errp)) { return; } diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index f3ba30e93e..c2af226174 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -510,8 +510,7 @@ static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info, if (qdict) { visitor = qobject_input_visitor_new(info->props); - if (!visit_start_struct(visitor, NULL, NULL, 0, &err)) { - error_propagate(errp, err); + if (!visit_start_struct(visitor, NULL, NULL, 0, errp)) { visit_free(visitor); object_unref(obj); return; @@ -999,7 +998,6 @@ static void get_feature(Object *obj, Visitor *v, const char *name, static void set_feature(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - Error *err = NULL; S390Feat feat = (S390Feat) opaque; DeviceState *dev = DEVICE(obj); S390CPU *cpu = S390_CPU(obj); @@ -1015,8 +1013,7 @@ static void set_feature(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_bool(v, name, &value, &err)) { - error_propagate(errp, err); + if (!visit_type_bool(v, name, &value, errp)) { return; } if (value) { @@ -1056,7 +1053,6 @@ static void get_feature_group(Object *obj, Visitor *v, const char *name, static void set_feature_group(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - Error *err = NULL; S390FeatGroup group = (S390FeatGroup) opaque; const S390FeatGroupDef *def = s390_feat_group_def(group); DeviceState *dev = DEVICE(obj); @@ -1073,8 +1069,7 @@ static void set_feature_group(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_bool(v, name, &value, &err)) { - error_propagate(errp, err); + if (!visit_type_bool(v, name, &value, errp)) { return; } if (value) { diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 4a9257005d..cf21efd85f 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -801,11 +801,9 @@ static void sparc_set_nwindows(Object *obj, Visitor *v, const char *name, const int64_t min = MIN_NWINDOWS; const int64_t max = MAX_NWINDOWS; SPARCCPU *cpu = SPARC_CPU(obj); - Error *err = NULL; int64_t value; - if (!visit_type_int(v, name, &value, &err)) { - error_propagate(errp, err); + if (!visit_type_int(v, name, &value, errp)) { return; } diff --git a/tpm.c b/tpm.c index 75bc937812..fe03b24858 100644 --- a/tpm.c +++ b/tpm.c @@ -85,7 +85,6 @@ static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp) const char *id; const TPMBackendClass *be; TPMBackend *drv; - Error *local_err = NULL; int i; if (!QLIST_EMPTY(&tpm_backends)) { @@ -116,8 +115,7 @@ static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp) } /* validate backend specific opts */ - if (!qemu_opts_validate(opts, be->opts, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_validate(opts, be->opts, errp)) { return 1; } diff --git a/util/main-loop.c b/util/main-loop.c index eda63fe4e0..f69f055013 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -148,7 +148,6 @@ int qemu_init_main_loop(Error **errp) { int ret; GSource *src; - Error *local_error = NULL; init_clocks(qemu_timer_notify_cb); @@ -157,9 +156,8 @@ int qemu_init_main_loop(Error **errp) return ret; } - qemu_aio_context = aio_context_new(&local_error); + qemu_aio_context = aio_context_new(errp); if (!qemu_aio_context) { - error_propagate(errp, local_error); return -EMFILE; } qemu_notify_bh = qemu_bh_new(notify_event_cb, NULL); diff --git a/util/qemu-config.c b/util/qemu-config.c index 7229c79cc7..660f47b005 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -479,7 +479,6 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, QemuOpts *subopts; QDict *subqdict; QList *list = NULL; - Error *local_err = NULL; size_t orig_size, enum_size; char *prefix; @@ -496,8 +495,7 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, goto out; } - if (!qemu_opts_absorb_qdict(subopts, subqdict, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) { goto out; } @@ -540,8 +538,7 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, goto out; } - if (!qemu_opts_absorb_qdict(subopts, section, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(subopts, section, errp)) { qemu_opts_del(subopts); goto out; } diff --git a/util/qemu-option.c b/util/qemu-option.c index 1dd14a0634..b9f93a7f8b 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -524,7 +524,6 @@ static bool opt_validate(QemuOpt *opt, bool *help_wanted, Error **errp) { const QemuOptDesc *desc; - Error *local_err = NULL; desc = find_desc_by_name(opt->opts->list->desc, opt->name); if (!desc && !opts_accepts_any(opt->opts)) { @@ -536,8 +535,7 @@ static bool opt_validate(QemuOpt *opt, bool *help_wanted, } opt->desc = desc; - if (!qemu_opt_parse(opt, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opt_parse(opt, errp)) { return false; } @@ -908,7 +906,6 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, const char *firstname; char *id = opts_parse_id(params); QemuOpts *opts; - Error *local_err = NULL; assert(!permit_abbrev || list->implied_opt_name); firstname = permit_abbrev ? list->implied_opt_name : NULL; @@ -921,16 +918,14 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, * (if unlikely) future misuse: */ assert(!defaults || list->merge_lists); - opts = qemu_opts_create(list, id, !defaults, &local_err); + opts = qemu_opts_create(list, id, !defaults, errp); g_free(id); if (opts == NULL) { - error_propagate(errp, local_err); return NULL; } if (!opts_do_parse(opts, params, firstname, defaults, help_wanted, - &local_err)) { - error_propagate(errp, local_err); + errp)) { qemu_opts_del(opts); return NULL; } @@ -1030,7 +1025,6 @@ static bool qemu_opts_from_qdict_entry(QemuOpts *opts, QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, Error **errp) { - Error *local_err = NULL; QemuOpts *opts; const QDictEntry *entry; @@ -1044,8 +1038,7 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, for (entry = qdict_first(qdict); entry; entry = qdict_next(qdict, entry)) { - if (!qemu_opts_from_qdict_entry(opts, entry, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_from_qdict_entry(opts, entry, errp)) { qemu_opts_del(opts); return NULL; } @@ -1066,13 +1059,10 @@ bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) entry = qdict_first(qdict); while (entry != NULL) { - Error *local_err = NULL; - next = qdict_next(qdict, entry); if (find_desc_by_name(opts->list->desc, entry->key)) { - if (!qemu_opts_from_qdict_entry(opts, entry, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_from_qdict_entry(opts, entry, errp)) { return false; } qdict_del(qdict, entry->key); @@ -1144,7 +1134,6 @@ QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict) bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) { QemuOpt *opt; - Error *local_err = NULL; assert(opts_accepts_any(opts)); @@ -1155,8 +1144,7 @@ bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) return false; } - if (!qemu_opt_parse(opt, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opt_parse(opt, errp)) { return false; } } From af175e85f92c870386ad74f466e29537b79611d3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:03 +0200 Subject: [PATCH 2067/2595] error: Eliminate error_propagate() with Coccinelle, part 2 When all we do with an Error we receive into a local variable is propagating to somewhere else, we can just as well receive it there right away. The previous commit did that with a Coccinelle script I consider fairly trustworthy. This commit uses the same script with the matching of return taken out, i.e. we convert if (!foo(..., &err)) { ... error_propagate(errp, err); ... } to if (!foo(..., errp)) { ... ... } This is unsound: @err could still be read between afterwards. I don't know how to express "no read of @err without an intervening write" in Coccinelle. Instead, I manually double-checked for uses of @err. Suboptimal line breaks tweaked manually. qdev_realize() simplified further to placate scripts/checkpatch.pl. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-36-armbru@redhat.com> --- block.c | 6 ++---- block/blkdebug.c | 7 ++----- block/blklogwrites.c | 3 +-- block/blkverify.c | 3 +-- block/crypto.c | 4 +--- block/file-posix.c | 6 ++---- block/file-win32.c | 6 ++---- block/gluster.c | 4 +--- block/iscsi.c | 3 +-- block/nbd.c | 8 ++------ block/qcow2.c | 13 ++++--------- block/raw-format.c | 4 +--- block/sheepdog.c | 8 ++------ block/ssh.c | 3 +-- block/throttle.c | 4 +--- block/vmdk.c | 4 +--- block/vpc.c | 3 +-- block/vvfat.c | 3 +-- blockdev.c | 3 +-- hw/intc/xics.c | 4 +--- hw/vfio/pci.c | 3 +-- net/tap.c | 3 +-- qom/object.c | 4 +--- 23 files changed, 32 insertions(+), 77 deletions(-) diff --git a/block.c b/block.c index 99fe5729b0..ef781f88a3 100644 --- a/block.c +++ b/block.c @@ -1629,8 +1629,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file, assert(options != NULL && bs->options != options); opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto fail_opts; } @@ -4090,8 +4089,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, /* Process generic block layer options */ opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, reopen_state->options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, reopen_state->options, errp)) { ret = -EINVAL; goto error; } diff --git a/block/blkdebug.c b/block/blkdebug.c index 3c0a9d45cc..9c08d8a005 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -359,7 +359,6 @@ static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options, QObject *crumpled_subqdict = NULL; Visitor *v = NULL; BlockPermissionList *perm_list = NULL, *element; - Error *local_err = NULL; *dest = 0; @@ -375,8 +374,7 @@ static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options, } v = qobject_input_visitor_new(crumpled_subqdict); - if (!visit_type_BlockPermissionList(v, NULL, &perm_list, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_BlockPermissionList(v, NULL, &perm_list, errp)) { ret = -EINVAL; goto out; } @@ -471,8 +469,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, uint64_t align; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto out; } diff --git a/block/blklogwrites.c b/block/blklogwrites.c index 0c93e926b1..57315f56b4 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -149,9 +149,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, bool log_append; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; - error_propagate(errp, local_err); goto fail; } diff --git a/block/blkverify.c b/block/blkverify.c index 666d626c57..4aed53ab59 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -116,8 +116,7 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, int ret; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto fail; } diff --git a/block/crypto.c b/block/crypto.c index 35aa5947d4..8725c1bc02 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -260,7 +260,6 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, { BlockCrypto *crypto = bs->opaque; QemuOpts *opts = NULL; - Error *local_err = NULL; int ret = -EINVAL; QCryptoBlockOpenOptions *open_opts = NULL; unsigned int cflags = 0; @@ -276,8 +275,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, bs->file->bs->supported_write_flags; opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { goto cleanup; } diff --git a/block/file-posix.c b/block/file-posix.c index b35ea99d42..1989eae85f 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -490,8 +490,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, OnOffAuto locking; opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto fail; } @@ -999,8 +998,7 @@ static int raw_reopen_prepare(BDRVReopenState *state, /* Handle options changes */ opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, state->options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, state->options, errp)) { ret = -EINVAL; goto out; } diff --git a/block/file-win32.c b/block/file-win32.c index 5f8015319a..ab69bd811a 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -338,8 +338,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, s->type = FTYPE_FILE; opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto fail; } @@ -738,8 +737,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags, QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto done; } diff --git a/block/gluster.c b/block/gluster.c index b68bd32d47..c620880f27 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -811,12 +811,10 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options, int ret = 0; BlockdevOptionsGluster *gconf = NULL; QemuOpts *opts; - Error *local_err = NULL; const char *filename, *logfile; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto out; } diff --git a/block/iscsi.c b/block/iscsi.c index d4dfa9914b..6c2e353e1a 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1792,8 +1792,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, int i, ret = 0, timeout = 0, lun; opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto out; } diff --git a/block/nbd.c b/block/nbd.c index 1331307ffb..6876da04a7 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1726,7 +1726,6 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, SocketAddress *saddr = NULL; QDict *addr = NULL; Visitor *iv = NULL; - Error *local_err = NULL; qdict_extract_subqdict(options, &addr, "server."); if (!qdict_size(addr)) { @@ -1739,8 +1738,7 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, goto done; } - if (!visit_type_SocketAddress(iv, NULL, &saddr, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_SocketAddress(iv, NULL, &saddr, errp)) { goto done; } @@ -1835,12 +1833,10 @@ static int nbd_process_options(BlockDriverState *bs, QDict *options, { BDRVNBDState *s = bs->opaque; QemuOpts *opts; - Error *local_err = NULL; int ret = -EINVAL; opts = qemu_opts_create(&nbd_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { goto error; } diff --git a/block/qcow2.c b/block/qcow2.c index ce6333fd1e..f419860e67 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -990,8 +990,7 @@ static int qcow2_update_options_prepare(BlockDriverState *bs, encryptfmt = qdict_get_try_str(encryptopts, "format"); opts = qemu_opts_create(&qcow2_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto fail; } @@ -1595,8 +1594,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, /* read qcow2 extensions */ if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL, - flags, &update_header, &local_err)) { - error_propagate(errp, local_err); + flags, &update_header, errp)) { ret = -EINVAL; goto fail; } @@ -3357,7 +3355,6 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) int version; int refcount_order; uint64_t* refcount_table; - Error *local_err = NULL; int ret; uint8_t compression_type = QCOW2_COMPRESSION_TYPE_ZLIB; @@ -3583,9 +3580,8 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } blk = blk_new_open(NULL, NULL, options, BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH, - &local_err); + errp); if (blk == NULL) { - error_propagate(errp, local_err); ret = -EIO; goto out; } @@ -3665,9 +3661,8 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } blk = blk_new_open(NULL, NULL, options, BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO, - &local_err); + errp); if (blk == NULL) { - error_propagate(errp, local_err); ret = -EIO; goto out; } diff --git a/block/raw-format.c b/block/raw-format.c index a66fbe77c7..42ec50802b 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -74,13 +74,11 @@ static QemuOptsList raw_create_opts = { static int raw_read_options(QDict *options, uint64_t *offset, bool *has_size, uint64_t *size, Error **errp) { - Error *local_err = NULL; QemuOpts *opts = NULL; int ret; opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto end; } diff --git a/block/sheepdog.c b/block/sheepdog.c index e3bcb05f60..a6a91442c9 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -532,7 +532,6 @@ static SocketAddress *sd_server_config(QDict *options, Error **errp) QDict *server = NULL; Visitor *iv = NULL; SocketAddress *saddr = NULL; - Error *local_err = NULL; qdict_extract_subqdict(options, &server, "server."); @@ -541,8 +540,7 @@ static SocketAddress *sd_server_config(QDict *options, Error **errp) goto done; } - if (!visit_type_SocketAddress(iv, NULL, &saddr, &local_err)) { - error_propagate(errp, local_err); + if (!visit_type_SocketAddress(iv, NULL, &saddr, errp)) { goto done; } @@ -1549,14 +1547,12 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags, uint64_t snap_id; char *buf = NULL; QemuOpts *opts; - Error *local_err = NULL; s->bs = bs; s->aio_context = bdrv_get_aio_context(bs); opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto err_no_fd; } diff --git a/block/ssh.c b/block/ssh.c index 13a2964621..f00b89684a 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -622,8 +622,7 @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp) /* Translate legacy options */ opts = qemu_opts_create(&ssh_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { goto fail; } diff --git a/block/throttle.c b/block/throttle.c index c0802addbb..1c1ac57bee 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -46,11 +46,9 @@ static int throttle_parse_options(QDict *options, char **group, Error **errp) { int ret; const char *group_name; - Error *local_err = NULL; QemuOpts *opts = qemu_opts_create(&throttle_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto fin; } diff --git a/block/vmdk.c b/block/vmdk.c index 4d42d2fbe1..9a09193f3b 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2250,7 +2250,6 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, { int ret; BlockBackend *blk = NULL; - Error *local_err = NULL; ret = bdrv_create_file(filename, opts, errp); if (ret < 0) { @@ -2259,9 +2258,8 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, blk = blk_new_open(filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, - &local_err); + errp); if (blk == NULL) { - error_propagate(errp, local_err); ret = -EIO; goto exit; } diff --git a/block/vpc.c b/block/vpc.c index 04da71e9e6..cfec15f562 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -235,8 +235,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, } opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto fail; } diff --git a/block/vvfat.c b/block/vvfat.c index e3e27e0d6c..24d36220d3 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -1149,8 +1149,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, #endif opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto fail; } diff --git a/blockdev.c b/blockdev.c index 705869d849..1f254e7110 100644 --- a/blockdev.c +++ b/blockdev.c @@ -863,8 +863,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, legacy_opts = qemu_opts_create(&qemu_legacy_drive_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err)) { - error_propagate(errp, local_err); + if (!qemu_opts_absorb_qdict(legacy_opts, bs_opts, errp)) { goto fail; } diff --git a/hw/intc/xics.c b/hw/intc/xics.c index c1feb649fb..68f9d44feb 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -376,7 +376,6 @@ static const TypeInfo icp_info = { Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp) { - Error *local_err = NULL; Object *obj; obj = object_new(type); @@ -384,9 +383,8 @@ Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp) object_unref(obj); object_property_set_link(obj, ICP_PROP_XICS, OBJECT(xi), &error_abort); object_property_set_link(obj, ICP_PROP_CPU, cpu, &error_abort); - if (!qdev_realize(DEVICE(obj), NULL, &local_err)) { + if (!qdev_realize(DEVICE(obj), NULL, errp)) { object_unparent(obj); - error_propagate(errp, local_err); obj = NULL; } diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 6fde80cb9a..2e561c06d6 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -292,8 +292,7 @@ static int vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp) qemu_set_fd_handler(fd, vfio_intx_interrupt, NULL, vdev); if (vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX, 0, - VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { - error_propagate(errp, err); + VFIO_IRQ_SET_ACTION_TRIGGER, fd, errp)) { qemu_set_fd_handler(fd, NULL, NULL, vdev); event_notifier_cleanup(&vdev->intx.interrupt); return -errno; diff --git a/net/tap.c b/net/tap.c index 2d8d83a30b..f9dcc2ef51 100644 --- a/net/tap.c +++ b/net/tap.c @@ -836,9 +836,8 @@ int net_init_tap(const Netdev *netdev, const char *name, } for (i = 0; i < nfds; i++) { - fd = monitor_fd_param(cur_mon, fds[i], &err); + fd = monitor_fd_param(cur_mon, fds[i], errp); if (fd == -1) { - error_propagate(errp, err); ret = -1; goto free_fail; } diff --git a/qom/object.c b/qom/object.c index 08b2cad445..37e4bc45b1 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1599,11 +1599,9 @@ char *object_property_print(Object *obj, const char *name, bool human, { Visitor *v; char *string = NULL; - Error *local_err = NULL; v = string_output_visitor_new(human, &string); - if (!object_property_get(obj, name, v, &local_err)) { - error_propagate(errp, local_err); + if (!object_property_get(obj, name, v, errp)) { goto out; } From 992861fb1e4cf410f30ec8f05bd2dc2a14a5a027 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:04 +0200 Subject: [PATCH 2068/2595] error: Eliminate error_propagate() manually When all we do with an Error we receive into a local variable is propagating to somewhere else, we can just as well receive it there right away. The previous two commits did that for sufficiently simple cases with Coccinelle. Do it for several more manually. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-37-armbru@redhat.com> --- block/replication.c | 4 +--- blockdev.c | 16 ++++---------- bootdevice.c | 6 ++---- dump/dump.c | 7 ++---- hw/block/fdc.c | 8 +++---- hw/core/numa.c | 44 ++++++++++++-------------------------- hw/i386/x86.c | 6 ++---- hw/intc/xive.c | 12 +++-------- hw/ppc/spapr_cpu_core.c | 14 ++++-------- hw/s390x/s390-pci-bus.c | 4 +--- hw/s390x/s390-virtio-ccw.c | 6 ++---- hw/s390x/sclp.c | 12 ++++------- hw/usb/bus.c | 4 +--- qdev-monitor.c | 12 ++++------- qga/commands-posix.c | 4 +--- qom/object.c | 33 +++++++++++----------------- qom/qom-qobject.c | 5 +---- target/i386/cpu.c | 19 +++++----------- 18 files changed, 67 insertions(+), 149 deletions(-) diff --git a/block/replication.c b/block/replication.c index b844a09eb1..dcd430624e 100644 --- a/block/replication.c +++ b/block/replication.c @@ -367,7 +367,6 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, { BDRVReplicationState *s = bs->opaque; BlockReopenQueue *reopen_queue = NULL; - Error *local_err = NULL; if (writable) { s->orig_hidden_read_only = bdrv_is_read_only(s->hidden_disk->bs); @@ -392,8 +391,7 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, } if (reopen_queue) { - bdrv_reopen_multiple(reopen_queue, &local_err); - error_propagate(errp, local_err); + bdrv_reopen_multiple(reopen_queue, errp); } bdrv_subtree_drained_end(s->hidden_disk->bs); diff --git a/blockdev.c b/blockdev.c index 1f254e7110..59b0b8ffaf 100644 --- a/blockdev.c +++ b/blockdev.c @@ -793,7 +793,6 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, bool read_only = false; bool copy_on_read; const char *filename; - Error *local_err = NULL; int i; /* Change legacy command line options into QMP ones */ @@ -1003,13 +1002,10 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type, } /* Actual block device init: Functionality shared with blockdev-add */ - blk = blockdev_init(filename, bs_opts, &local_err); + blk = blockdev_init(filename, bs_opts, errp); bs_opts = NULL; if (!blk) { - error_propagate(errp, local_err); goto fail; - } else { - assert(!local_err); } /* Create legacy DriveInfo */ @@ -3141,9 +3137,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) arg->has_copy_mode, arg->copy_mode, arg->has_auto_finalize, arg->auto_finalize, arg->has_auto_dismiss, arg->auto_dismiss, - &local_err); + errp); bdrv_unref(target_bs); - error_propagate(errp, local_err); out: aio_context_release(aio_context); } @@ -3171,7 +3166,6 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, AioContext *aio_context; AioContext *old_context; BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN; - Error *local_err = NULL; bool zero_target; int ret; @@ -3213,8 +3207,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, has_copy_mode, copy_mode, has_auto_finalize, auto_finalize, has_auto_dismiss, auto_dismiss, - &local_err); - error_propagate(errp, local_err); + errp); out: aio_context_release(aio_context); } @@ -3433,8 +3426,7 @@ void qmp_change_backing_file(const char *device, } if (ro) { - bdrv_reopen_set_read_only(image_bs, true, &local_err); - error_propagate(errp, local_err); + bdrv_reopen_set_read_only(image_bs, true, errp); } out: diff --git a/bootdevice.c b/bootdevice.c index 8185402a5a..add4e3d2d1 100644 --- a/bootdevice.c +++ b/bootdevice.c @@ -303,15 +303,13 @@ static void device_set_bootindex(Object *obj, Visitor *v, const char *name, /* check whether bootindex is present in fw_boot_order list */ check_boot_index(boot_index, &local_err); if (local_err) { - goto out; + error_propagate(errp, local_err); + return; } /* change bootindex to a new one */ *prop->bootindex = boot_index; add_boot_device_path(*prop->bootindex, prop->dev, prop->suffix); - -out: - error_propagate(errp, local_err); } static void property_release_bootindex(Object *obj, const char *name, diff --git a/dump/dump.c b/dump/dump.c index 248ea06370..383bc7876b 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -1031,14 +1031,11 @@ out: static void write_dump_header(DumpState *s, Error **errp) { - Error *local_err = NULL; - if (s->dump_info.d_class == ELFCLASS32) { - create_header32(s, &local_err); + create_header32(s, errp); } else { - create_header64(s, &local_err); + create_header64(s, errp); } - error_propagate(errp, local_err); } static size_t dump_bitmap_get_bufsize(DumpState *s) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index f22f46c9c9..e9ed3eef45 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2528,7 +2528,7 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, FDrive *drive; DeviceState *dev; BlockBackend *blk; - Error *local_err = NULL; + bool ok; const char *fdc_name, *drive_suffix; for (i = 0; i < MAX_FD; i++) { @@ -2567,11 +2567,9 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, blk_ref(blk); blk_detach_dev(blk, fdc_dev); fdctrl->qdev_for_drives[i].blk = NULL; - qdev_prop_set_drive_err(dev, "drive", blk, &local_err); + ok = qdev_prop_set_drive_err(dev, "drive", blk, errp); blk_unref(blk); - - if (local_err) { - error_propagate(errp, local_err); + if (!ok) { return; } diff --git a/hw/core/numa.c b/hw/core/numa.c index de9a2f7e32..1b3267a607 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -456,40 +456,33 @@ void parse_numa_hmat_cache(MachineState *ms, NumaHmatCacheOptions *node, void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp) { - Error *err = NULL; - if (!ms->numa_state) { error_setg(errp, "NUMA is not supported by this machine-type"); - goto end; + return; } switch (object->type) { case NUMA_OPTIONS_TYPE_NODE: - parse_numa_node(ms, &object->u.node, &err); - if (err) { - goto end; - } + parse_numa_node(ms, &object->u.node, errp); break; case NUMA_OPTIONS_TYPE_DIST: - parse_numa_distance(ms, &object->u.dist, &err); - if (err) { - goto end; - } + parse_numa_distance(ms, &object->u.dist, errp); break; case NUMA_OPTIONS_TYPE_CPU: if (!object->u.cpu.has_node_id) { - error_setg(&err, "Missing mandatory node-id property"); - goto end; + error_setg(errp, "Missing mandatory node-id property"); + return; } if (!ms->numa_state->nodes[object->u.cpu.node_id].present) { - error_setg(&err, "Invalid node-id=%" PRId64 ", NUMA node must be " - "defined with -numa node,nodeid=ID before it's used with " - "-numa cpu,node-id=ID", object->u.cpu.node_id); - goto end; + error_setg(errp, "Invalid node-id=%" PRId64 ", NUMA node must be " + "defined with -numa node,nodeid=ID before it's used with " + "-numa cpu,node-id=ID", object->u.cpu.node_id); + return; } - machine_set_cpu_numa_node(ms, qapi_NumaCpuOptions_base(&object->u.cpu), - &err); + machine_set_cpu_numa_node(ms, + qapi_NumaCpuOptions_base(&object->u.cpu), + errp); break; case NUMA_OPTIONS_TYPE_HMAT_LB: if (!ms->numa_state->hmat_enabled) { @@ -499,10 +492,7 @@ void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp) return; } - parse_numa_hmat_lb(ms->numa_state, &object->u.hmat_lb, &err); - if (err) { - goto end; - } + parse_numa_hmat_lb(ms->numa_state, &object->u.hmat_lb, errp); break; case NUMA_OPTIONS_TYPE_HMAT_CACHE: if (!ms->numa_state->hmat_enabled) { @@ -512,17 +502,11 @@ void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp) return; } - parse_numa_hmat_cache(ms, &object->u.hmat_cache, &err); - if (err) { - goto end; - } + parse_numa_hmat_cache(ms, &object->u.hmat_cache, errp); break; default: abort(); } - -end: - error_propagate(errp, err); } static int parse_numa(void *opaque, QemuOpts *opts, Error **errp) diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 22b524e0ab..67bee1bcb8 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -118,17 +118,15 @@ uint32_t x86_cpu_apic_id_from_index(X86MachineState *x86ms, void x86_cpu_new(X86MachineState *x86ms, int64_t apic_id, Error **errp) { - Error *local_err = NULL; Object *cpu = object_new(MACHINE(x86ms)->cpu_type); - if (!object_property_set_uint(cpu, "apic-id", apic_id, &local_err)) { + if (!object_property_set_uint(cpu, "apic-id", apic_id, errp)) { goto out; } - qdev_realize(DEVICE(cpu), NULL, &local_err); + qdev_realize(DEVICE(cpu), NULL, errp); out: object_unref(cpu); - error_propagate(errp, local_err); } void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version) diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 34591659d3..9a162431e0 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -757,7 +757,6 @@ static const TypeInfo xive_tctx_info = { Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp) { - Error *local_err = NULL; Object *obj; obj = object_new(TYPE_XIVE_TCTX); @@ -765,16 +764,11 @@ Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp) object_unref(obj); object_property_set_link(obj, "cpu", cpu, &error_abort); object_property_set_link(obj, "presenter", OBJECT(xptr), &error_abort); - if (!qdev_realize(DEVICE(obj), NULL, &local_err)) { - goto error; + if (!qdev_realize(DEVICE(obj), NULL, errp)) { + object_unparent(obj); + return NULL; } - return obj; - -error: - object_unparent(obj); - error_propagate(errp, local_err); - return NULL; } void xive_tctx_destroy(XiveTCTX *tctx) diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 85330d08a1..c4f47dcc04 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -239,8 +239,8 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, CPUState *cs = CPU(cpu); Error *local_err = NULL; - if (!qdev_realize(DEVICE(cpu), NULL, &local_err)) { - goto error; + if (!qdev_realize(DEVICE(cpu), NULL, errp)) { + return; } /* Set time-base frequency to 512 MHz */ @@ -250,20 +250,14 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, kvmppc_set_papr(cpu); if (spapr_irq_cpu_intc_create(spapr, cpu, &local_err) < 0) { - goto error_intc_create; + cpu_remove_sync(CPU(cpu)); + return; } if (!sc->pre_3_0_migration) { vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state, cpu->machine_data); } - - return; - -error_intc_create: - cpu_remove_sync(CPU(cpu)); -error: - error_propagate(errp, local_err); } static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 24de4edfc6..92146a2119 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -743,7 +743,6 @@ static void s390_pcihost_realize(DeviceState *dev, Error **errp) BusState *bus; PCIHostState *phb = PCI_HOST_BRIDGE(dev); S390pciState *s = S390_PCI_HOST_BRIDGE(dev); - Error *local_err = NULL; DPRINTF("host_init\n"); @@ -767,8 +766,7 @@ static void s390_pcihost_realize(DeviceState *dev, Error **errp) QTAILQ_INIT(&s->zpci_devs); css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false, - S390_ADAPTER_SUPPRESSIBLE, &local_err); - error_propagate(errp, local_err); + S390_ADAPTER_SUPPRESSIBLE, errp); } static int s390_pci_msix_init(S390PCIBusDevice *pbdev) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 20e8e95c61..8cc2f25d8a 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -68,20 +68,18 @@ static S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, Error **errp) { S390CPU *cpu = S390_CPU(object_new(typename)); - Error *err = NULL; S390CPU *ret = NULL; - if (!object_property_set_int(OBJECT(cpu), "core-id", core_id, &err)) { + if (!object_property_set_int(OBJECT(cpu), "core-id", core_id, errp)) { goto out; } - if (!qdev_realize(DEVICE(cpu), NULL, &err)) { + if (!qdev_realize(DEVICE(cpu), NULL, errp)) { goto out; } ret = cpu; out: object_unref(OBJECT(cpu)); - error_propagate(errp, err); return ret; } diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 03364343eb..a0ce444b4b 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -329,7 +329,6 @@ static void sclp_realize(DeviceState *dev, Error **errp) { MachineState *machine = MACHINE(qdev_get_machine()); SCLPDevice *sclp = SCLP(dev); - Error *err = NULL; uint64_t hw_limit; int ret; @@ -338,20 +337,17 @@ static void sclp_realize(DeviceState *dev, Error **errp) * as we can't find a fitting bus via the qom tree, we have to add the * event facility to the sysbus, so e.g. a sclp console can be created. */ - if (!sysbus_realize(SYS_BUS_DEVICE(sclp->event_facility), &err)) { - goto out; + if (!sysbus_realize(SYS_BUS_DEVICE(sclp->event_facility), errp)) { + return; } ret = s390_set_memory_limit(machine->maxram_size, &hw_limit); if (ret == -E2BIG) { - error_setg(&err, "host supports a maximum of %" PRIu64 " GB", + error_setg(errp, "host supports a maximum of %" PRIu64 " GB", hw_limit / GiB); } else if (ret) { - error_setg(&err, "setting the guest size failed"); + error_setg(errp, "setting the guest size failed"); } - -out: - error_propagate(errp, err); } static void sclp_memory_init(SCLPDevice *sclp) diff --git a/hw/usb/bus.c b/hw/usb/bus.c index ba27afe9f2..b17bda3b29 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -723,15 +723,13 @@ static bool usb_get_attached(Object *obj, Error **errp) static void usb_set_attached(Object *obj, bool value, Error **errp) { USBDevice *dev = USB_DEVICE(obj); - Error *err = NULL; if (dev->attached == value) { return; } if (value) { - usb_device_attach(dev, &err); - error_propagate(errp, err); + usb_device_attach(dev, errp); } else { usb_device_detach(dev); } diff --git a/qdev-monitor.c b/qdev-monitor.c index e2fd24e1a4..9665a5398c 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -600,7 +600,6 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) const char *driver, *path; DeviceState *dev = NULL; BusState *bus = NULL; - Error *err = NULL; bool hide; driver = qemu_opt_get(opts, "driver"); @@ -655,15 +654,13 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) dev = qdev_new(driver); /* Check whether the hotplug is allowed by the machine */ - if (qdev_hotplug && !qdev_hotplug_allowed(dev, &err)) { - /* Error must be set in the machine hook */ - assert(err); + if (qdev_hotplug && !qdev_hotplug_allowed(dev, errp)) { goto err_del_dev; } if (!bus && qdev_hotplug && !qdev_get_machine_hotplug_handler(dev)) { /* No bus, no machine hotplug handler --> device is not hotpluggable */ - error_setg(&err, "Device '%s' can not be hotplugged on this machine", + error_setg(errp, "Device '%s' can not be hotplugged on this machine", driver); goto err_del_dev; } @@ -671,19 +668,18 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) qdev_set_id(dev, qemu_opts_id(opts)); /* set properties */ - if (qemu_opt_foreach(opts, set_property, dev, &err)) { + if (qemu_opt_foreach(opts, set_property, dev, errp)) { goto err_del_dev; } dev->opts = opts; - if (!qdev_realize(DEVICE(dev), bus, &err)) { + if (!qdev_realize(DEVICE(dev), bus, errp)) { dev->opts = NULL; goto err_del_dev; } return dev; err_del_dev: - error_propagate(errp, err); if (dev) { object_unparent(OBJECT(dev)); object_unref(OBJECT(dev)); diff --git a/qga/commands-posix.c b/qga/commands-posix.c index cdbeb59dcc..1a62a3a70d 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -1552,13 +1552,12 @@ static int run_process_child(const char *command[], Error **errp) static bool systemd_supports_mode(SuspendMode mode, Error **errp) { - Error *local_err = NULL; const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend", "systemd-hybrid-sleep"}; const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL}; int status; - status = run_process_child(cmd, &local_err); + status = run_process_child(cmd, errp); /* * systemctl status uses LSB return codes so we can expect @@ -1572,7 +1571,6 @@ static bool systemd_supports_mode(SuspendMode mode, Error **errp) return true; } - error_propagate(errp, local_err); return false; } diff --git a/qom/object.c b/qom/object.c index 37e4bc45b1..4c91de8183 100644 --- a/qom/object.c +++ b/qom/object.c @@ -549,7 +549,6 @@ bool object_initialize_child_with_propsv(Object *parentobj, const char *type, Error **errp, va_list vargs) { - Error *local_err = NULL; bool ok = false; Object *obj; UserCreatable *uc; @@ -565,7 +564,7 @@ bool object_initialize_child_with_propsv(Object *parentobj, uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE); if (uc) { - if (!user_creatable_complete(uc, &local_err)) { + if (!user_creatable_complete(uc, errp)) { object_unparent(obj); goto out; } @@ -583,8 +582,6 @@ out: * the reference taken by object_property_add_child(). */ object_unref(obj); - - error_propagate(errp, local_err); return ok; } @@ -737,7 +734,6 @@ Object *object_new_with_propv(const char *typename, { Object *obj; ObjectClass *klass; - Error *local_err = NULL; UserCreatable *uc; klass = object_class_by_name(typename); @@ -762,7 +758,7 @@ Object *object_new_with_propv(const char *typename, uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE); if (uc) { - if (!user_creatable_complete(uc, &local_err)) { + if (!user_creatable_complete(uc, errp)) { if (id != NULL) { object_unparent(obj); } @@ -774,7 +770,6 @@ Object *object_new_with_propv(const char *typename, return obj; error: - error_propagate(errp, local_err); object_unref(obj); return NULL; } @@ -2326,36 +2321,34 @@ static void property_get_tm(Object *obj, Visitor *v, const char *name, prop->get(obj, &value, &err); if (err) { - goto out; + error_propagate(errp, err); + return; } - if (!visit_start_struct(v, name, NULL, 0, &err)) { - goto out; + if (!visit_start_struct(v, name, NULL, 0, errp)) { + return; } - if (!visit_type_int32(v, "tm_year", &value.tm_year, &err)) { + if (!visit_type_int32(v, "tm_year", &value.tm_year, errp)) { goto out_end; } - if (!visit_type_int32(v, "tm_mon", &value.tm_mon, &err)) { + if (!visit_type_int32(v, "tm_mon", &value.tm_mon, errp)) { goto out_end; } - if (!visit_type_int32(v, "tm_mday", &value.tm_mday, &err)) { + if (!visit_type_int32(v, "tm_mday", &value.tm_mday, errp)) { goto out_end; } - if (!visit_type_int32(v, "tm_hour", &value.tm_hour, &err)) { + if (!visit_type_int32(v, "tm_hour", &value.tm_hour, errp)) { goto out_end; } - if (!visit_type_int32(v, "tm_min", &value.tm_min, &err)) { + if (!visit_type_int32(v, "tm_min", &value.tm_min, errp)) { goto out_end; } - if (!visit_type_int32(v, "tm_sec", &value.tm_sec, &err)) { + if (!visit_type_int32(v, "tm_sec", &value.tm_sec, errp)) { goto out_end; } - visit_check_struct(v, &err); + visit_check_struct(v, errp); out_end: visit_end_struct(v, NULL); -out: - error_propagate(errp, err); - } static void property_release_tm(Object *obj, const char *name, diff --git a/qom/qom-qobject.c b/qom/qom-qobject.c index 62ac5e07ac..21ce22de94 100644 --- a/qom/qom-qobject.c +++ b/qom/qom-qobject.c @@ -34,15 +34,12 @@ QObject *object_property_get_qobject(Object *obj, const char *name, Error **errp) { QObject *ret = NULL; - Error *local_err = NULL; Visitor *v; v = qobject_output_visitor_new(&ret); - object_property_get(obj, name, v, &local_err); - if (!local_err) { + if (object_property_get(obj, name, v, errp)) { visit_complete(v, &ret); } - error_propagate(errp, local_err); visit_free(v); return ret; } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 6f27f12ec7..e46ab8f774 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5260,16 +5260,13 @@ static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props) static void object_apply_props(Object *obj, QDict *props, Error **errp) { const QDictEntry *prop; - Error *err = NULL; for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) { if (!object_property_set_qobject(obj, qdict_entry_key(prop), - qdict_entry_value(prop), &err)) { + qdict_entry_value(prop), errp)) { break; } } - - error_propagate(errp, err); } /* Create X86CPU object according to model+props specification */ @@ -6327,19 +6324,18 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) FeatureWord w; int i; GList *l; - Error *local_err = NULL; for (l = plus_features; l; l = l->next) { const char *prop = l->data; - if (!object_property_set_bool(OBJECT(cpu), prop, true, &local_err)) { - goto out; + if (!object_property_set_bool(OBJECT(cpu), prop, true, errp)) { + return; } } for (l = minus_features; l; l = l->next) { const char *prop = l->data; - if (!object_property_set_bool(OBJECT(cpu), prop, false, &local_err)) { - goto out; + if (!object_property_set_bool(OBJECT(cpu), prop, false, errp)) { + return; } } @@ -6437,11 +6433,6 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) if (env->cpuid_xlevel2 == UINT32_MAX) { env->cpuid_xlevel2 = env->cpuid_min_xlevel2; } - -out: - if (local_err != NULL) { - error_propagate(errp, local_err); - } } /* From a5f9b9df252d0dfb407178ef4c3769f78a64b2ff Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:05 +0200 Subject: [PATCH 2069/2595] error: Reduce unnecessary error propagation When all we do with an Error we receive into a local variable is propagating to somewhere else, we can just as well receive it there right away, even when we need to keep error_propagate() for other error paths. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-38-armbru@redhat.com> --- block.c | 2 +- block/gluster.c | 8 ++++---- block/parallels.c | 2 +- block/quorum.c | 2 +- block/replication.c | 3 +-- block/vxhs.c | 4 ++-- hw/core/qdev.c | 2 +- hw/net/virtio-net.c | 4 ++-- 8 files changed, 13 insertions(+), 14 deletions(-) diff --git a/block.c b/block.c index ef781f88a3..3031413deb 100644 --- a/block.c +++ b/block.c @@ -6058,7 +6058,7 @@ void bdrv_img_create(const char *filename, const char *fmt, /* Parse -o options */ if (options) { - if (!qemu_opts_do_parse(opts, options, NULL, &local_err)) { + if (!qemu_opts_do_parse(opts, options, NULL, errp)) { goto out; } } diff --git a/block/gluster.c b/block/gluster.c index c620880f27..4f1448e2bc 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -523,7 +523,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, /* create opts info from runtime_json_opts list */ opts = qemu_opts_create(&runtime_json_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { + if (!qemu_opts_absorb_qdict(opts, options, errp)) { goto out; } @@ -554,7 +554,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, /* create opts info from runtime_type_opts list */ opts = qemu_opts_create(&runtime_type_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, backing_options, &local_err)) { + if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) { goto out; } @@ -584,7 +584,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, if (gsconf->type == SOCKET_ADDRESS_TYPE_INET) { /* create opts info from runtime_inet_opts list */ opts = qemu_opts_create(&runtime_inet_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, backing_options, &local_err)) { + if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) { goto out; } @@ -632,7 +632,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, } else { /* create opts info from runtime_unix_opts list */ opts = qemu_opts_create(&runtime_unix_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, backing_options, &local_err)) { + if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) { goto out; } diff --git a/block/parallels.c b/block/parallels.c index ff27a85c01..180dd41e2b 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -828,7 +828,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, goto fail_options; } - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { + if (!qemu_opts_absorb_qdict(opts, options, errp)) { goto fail_options; } diff --git a/block/quorum.c b/block/quorum.c index 5d52e605db..6df9449fc2 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -921,7 +921,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, } opts = qemu_opts_create(&quorum_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto exit; } diff --git a/block/replication.c b/block/replication.c index dcd430624e..0c70215784 100644 --- a/block/replication.c +++ b/block/replication.c @@ -85,7 +85,6 @@ static int replication_open(BlockDriverState *bs, QDict *options, { int ret; BDRVReplicationState *s = bs->opaque; - Error *local_err = NULL; QemuOpts *opts = NULL; const char *mode; const char *top_id; @@ -99,7 +98,7 @@ static int replication_open(BlockDriverState *bs, QDict *options, ret = -EINVAL; opts = qemu_opts_create(&replication_runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { + if (!qemu_opts_absorb_qdict(opts, options, errp)) { goto fail; } diff --git a/block/vxhs.c b/block/vxhs.c index fecaeb82c9..dc0e254730 100644 --- a/block/vxhs.c +++ b/block/vxhs.c @@ -318,7 +318,7 @@ static int vxhs_open(BlockDriverState *bs, QDict *options, opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); tcp_opts = qemu_opts_create(&runtime_tcp_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, &local_err)) { + if (!qemu_opts_absorb_qdict(opts, options, errp)) { ret = -EINVAL; goto out; } @@ -345,7 +345,7 @@ static int vxhs_open(BlockDriverState *bs, QDict *options, /* get the 'server.' arguments */ qdict_extract_subqdict(options, &backing_options, VXHS_OPT_SERVER"."); - if (!qemu_opts_absorb_qdict(tcp_opts, backing_options, &local_err)) { + if (!qemu_opts_absorb_qdict(tcp_opts, backing_options, errp)) { ret = -EINVAL; goto out; } diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 68948761f2..01796823b4 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -871,7 +871,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) } if (value && !dev->realized) { - if (!check_only_migratable(obj, &local_err)) { + if (!check_only_migratable(obj, errp)) { goto fail; } diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 48b07eb921..10cc958396 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3138,8 +3138,8 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp) qdev_set_parent_bus(n->primary_dev, n->primary_bus); n->primary_should_be_hidden = false; if (!qemu_opt_set_bool(n->primary_device_opts, - "partially_hotplugged", true, &err)) { - goto out; + "partially_hotplugged", true, errp)) { + return false; } hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); if (hotplug_ctrl) { From 4bc6d7ee0e95b879b7f4823b6e765cf9bf5845e7 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:06 +0200 Subject: [PATCH 2070/2595] block/parallels: Simplify parallels_open() after previous commit Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-39-armbru@redhat.com> --- block/parallels.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/block/parallels.c b/block/parallels.c index 180dd41e2b..cb5259ac44 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -842,6 +842,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, &local_err); g_free(buf); if (local_err != NULL) { + error_propagate(errp, local_err); goto fail_options; } @@ -872,15 +873,11 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, fail_format: error_setg(errp, "Image not in Parallels format"); +fail_options: ret = -EINVAL; fail: qemu_vfree(s->header); return ret; - -fail_options: - error_propagate(errp, local_err); - ret = -EINVAL; - goto fail; } From b11a093c6025635b4504d79d30daa334a01279a5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:07 +0200 Subject: [PATCH 2071/2595] qapi: Smooth another visitor error checking pattern Convert visit_type_FOO(v, ..., &ptr, &err); ... if (err) { ... } to visit_type_FOO(v, ..., &ptr, errp); ... if (!ptr) { ... } for functions that set @ptr to non-null / null on success / error. Eliminate error_propagate() that are now unnecessary. Delete @err that are now unused. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-40-armbru@redhat.com> --- block/nfs.c | 7 ++----- block/parallels.c | 7 ++----- block/qcow.c | 7 ++----- block/qcow2.c | 7 ++----- block/qed.c | 7 ++----- block/rbd.c | 7 ++----- block/sheepdog.c | 6 ++---- block/ssh.c | 7 ++----- block/vdi.c | 7 ++----- block/vhdx.c | 7 ++----- block/vpc.c | 7 ++----- hw/acpi/core.c | 5 ++--- hw/block/xen-block.c | 6 ++---- hw/core/numa.c | 7 +++---- monitor/monitor.c | 21 +++++++-------------- 15 files changed, 36 insertions(+), 79 deletions(-) diff --git a/block/nfs.c b/block/nfs.c index b1718d125a..61a249a9fc 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -563,18 +563,15 @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options, BlockdevOptionsNfs *opts = NULL; Visitor *v; const QDictEntry *e; - Error *local_err = NULL; v = qobject_input_visitor_new_flat_confused(options, errp); if (!v) { return NULL; } - visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err); + visit_type_BlockdevOptionsNfs(v, NULL, &opts, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!opts) { return NULL; } diff --git a/block/parallels.c b/block/parallels.c index cb5259ac44..f489c0d4ba 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -625,7 +625,6 @@ static int coroutine_fn parallels_co_create_opts(BlockDriver *drv, Error **errp) { BlockdevCreateOptions *create_options = NULL; - Error *local_err = NULL; BlockDriverState *bs = NULL; QDict *qdict; Visitor *v; @@ -668,11 +667,9 @@ static int coroutine_fn parallels_co_create_opts(BlockDriver *drv, goto done; } - visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!create_options) { ret = -EINVAL; goto done; } diff --git a/block/qcow.c b/block/qcow.c index dca2a1fe7d..c22d1bf6b8 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -943,7 +943,6 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv, QDict *qdict; Visitor *v; const char *val; - Error *local_err = NULL; int ret; static const QDictRenames opt_renames[] = { @@ -995,11 +994,9 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv, goto fail; } - visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!create_options) { ret = -EINVAL; goto fail; } diff --git a/block/qcow2.c b/block/qcow2.c index f419860e67..ea33673c55 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3685,7 +3685,6 @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv, Visitor *v; BlockDriverState *bs = NULL; BlockDriverState *data_bs = NULL; - Error *local_err = NULL; const char *val; int ret; @@ -3781,11 +3780,9 @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv, goto finish; } - visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!create_options) { ret = -EINVAL; goto finish; } diff --git a/block/qed.c b/block/qed.c index e04b7ab5f0..b27e7546ca 100644 --- a/block/qed.c +++ b/block/qed.c @@ -729,7 +729,6 @@ static int coroutine_fn bdrv_qed_co_create_opts(BlockDriver *drv, QDict *qdict; Visitor *v; BlockDriverState *bs = NULL; - Error *local_err = NULL; int ret; static const QDictRenames opt_renames[] = { @@ -771,11 +770,9 @@ static int coroutine_fn bdrv_qed_co_create_opts(BlockDriver *drv, goto fail; } - visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!create_options) { ret = -EINVAL; goto fail; } diff --git a/block/rbd.c b/block/rbd.c index 617553b022..688074c64b 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -681,7 +681,6 @@ static int qemu_rbd_convert_options(QDict *options, BlockdevOptionsRbd **opts, Error **errp) { Visitor *v; - Error *local_err = NULL; /* Convert the remaining options into a QAPI object */ v = qobject_input_visitor_new_flat_confused(options, errp); @@ -689,11 +688,9 @@ static int qemu_rbd_convert_options(QDict *options, BlockdevOptionsRbd **opts, return -EINVAL; } - visit_type_BlockdevOptionsRbd(v, NULL, opts, &local_err); + visit_type_BlockdevOptionsRbd(v, NULL, opts, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!opts) { return -EINVAL; } diff --git a/block/sheepdog.c b/block/sheepdog.c index a6a91442c9..6c487c8322 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -2193,11 +2193,9 @@ static int coroutine_fn sd_co_create_opts(BlockDriver *drv, goto fail; } - visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!create_options) { ret = -EINVAL; goto fail; } diff --git a/block/ssh.c b/block/ssh.c index f00b89684a..ebe3d8b631 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -616,7 +616,6 @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp) { BlockdevOptionsSsh *result = NULL; QemuOpts *opts = NULL; - Error *local_err = NULL; const QDictEntry *e; Visitor *v; @@ -636,11 +635,9 @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp) goto fail; } - visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err); + visit_type_BlockdevOptionsSsh(v, NULL, &result, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!result) { goto fail; } diff --git a/block/vdi.c b/block/vdi.c index c4527a9d8c..2496d51a4d 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -906,7 +906,6 @@ static int coroutine_fn vdi_co_create_opts(BlockDriver *drv, uint64_t block_size = DEFAULT_CLUSTER_SIZE; bool is_static = false; Visitor *v; - Error *local_err = NULL; int ret; /* Parse options and convert legacy syntax. @@ -957,11 +956,9 @@ static int coroutine_fn vdi_co_create_opts(BlockDriver *drv, ret = -EINVAL; goto done; } - visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!create_options) { ret = -EINVAL; goto done; } diff --git a/block/vhdx.c b/block/vhdx.c index 327675cc7c..a36d9d924a 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -2064,7 +2064,6 @@ static int coroutine_fn vhdx_co_create_opts(BlockDriver *drv, QDict *qdict; Visitor *v; BlockDriverState *bs = NULL; - Error *local_err = NULL; int ret; static const QDictRenames opt_renames[] = { @@ -2105,11 +2104,9 @@ static int coroutine_fn vhdx_co_create_opts(BlockDriver *drv, goto fail; } - visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!create_options) { ret = -EINVAL; goto fail; } diff --git a/block/vpc.c b/block/vpc.c index cfec15f562..131b9db6cc 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -1095,7 +1095,6 @@ static int coroutine_fn vpc_co_create_opts(BlockDriver *drv, QDict *qdict; Visitor *v; BlockDriverState *bs = NULL; - Error *local_err = NULL; int ret; static const QDictRenames opt_renames[] = { @@ -1134,11 +1133,9 @@ static int coroutine_fn vpc_co_create_opts(BlockDriver *drv, goto fail; } - visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!create_options) { ret = -EINVAL; goto fail; } diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 8b240c3e09..f6d9ec4f13 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -239,7 +239,6 @@ static void acpi_table_install(const char unsigned *blob, size_t bloblen, void acpi_table_add(const QemuOpts *opts, Error **errp) { AcpiTableOptions *hdrs = NULL; - Error *err = NULL; char **pathnames = NULL; char **cur; size_t bloblen = 0; @@ -249,11 +248,11 @@ void acpi_table_add(const QemuOpts *opts, Error **errp) Visitor *v; v = opts_visitor_new(opts); - visit_type_AcpiTableOptions(v, NULL, &hdrs, &err); + visit_type_AcpiTableOptions(v, NULL, &hdrs, errp); visit_free(v); } - if (err) { + if (!hdrs) { goto out; } if (hdrs->has_file == hdrs->has_data) { diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 96c6c009c7..a775fba7c0 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -682,11 +682,9 @@ static char *xen_block_blockdev_add(const char *id, QDict *qdict, trace_xen_block_blockdev_add(node_name); v = qobject_input_visitor_new(QOBJECT(qdict)); - visit_type_BlockdevOptions(v, NULL, &options, &local_err); + visit_type_BlockdevOptions(v, NULL, &options, errp); visit_free(v); - - if (local_err) { - error_propagate(errp, local_err); + if (!options) { goto fail; } diff --git a/hw/core/numa.c b/hw/core/numa.c index 1b3267a607..d1a94a14f8 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -516,10 +516,10 @@ static int parse_numa(void *opaque, QemuOpts *opts, Error **errp) Error *err = NULL; Visitor *v = opts_visitor_new(opts); - visit_type_NumaOptions(v, NULL, &object, &err); + visit_type_NumaOptions(v, NULL, &object, errp); visit_free(v); - if (err) { - goto end; + if (!object) { + return -1; } /* Fix up legacy suffix-less format */ @@ -530,7 +530,6 @@ static int parse_numa(void *opaque, QemuOpts *opts, Error **errp) set_numa_options(ms, object, &err); -end: qapi_free_NumaOptions(object); if (err) { error_propagate(errp, err); diff --git a/monitor/monitor.c b/monitor/monitor.c index 19dcb8fbe3..b385a3d569 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -657,25 +657,18 @@ int monitor_init_opts(QemuOpts *opts, Error **errp) { Visitor *v; MonitorOptions *options; - Error *local_err = NULL; + int ret; v = opts_visitor_new(opts); - visit_type_MonitorOptions(v, NULL, &options, &local_err); + visit_type_MonitorOptions(v, NULL, &options, errp); visit_free(v); - - if (local_err) { - goto out; - } - - monitor_init(options, true, &local_err); - qapi_free_MonitorOptions(options); - -out: - if (local_err) { - error_propagate(errp, local_err); + if (!options) { return -1; } - return 0; + + ret = monitor_init(options, true, errp); + qapi_free_MonitorOptions(options); + return ret; } QemuOptsList qemu_mon_opts = { From cdd2b228b973d2a29edf7696ef6e8b08ec329019 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:08 +0200 Subject: [PATCH 2072/2595] qapi: Smooth visitor error checking in generated code Use visitor functions' return values to check for failure. Eliminate error_propagate() that are now unnecessary. Delete @err that are now unused. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-41-armbru@redhat.com> --- docs/devel/qapi-code-gen.txt | 60 ++++++++++++++---------------------- scripts/qapi/commands.py | 22 ++++++------- scripts/qapi/visit.py | 57 ++++++++++++++-------------------- 3 files changed, 55 insertions(+), 84 deletions(-) diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index 9bfc57063c..69eede6c28 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -1420,8 +1420,6 @@ Example: bool visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error **errp) { - Error *err = NULL; - if (!visit_type_int(v, "integer", &obj->integer, errp)) { return false; } @@ -1430,13 +1428,12 @@ Example: return false; } } - error_propagate(errp, err); - return !err; + return true; } bool visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, Error **errp) { - Error *err = NULL; + bool ok = false; if (!visit_start_struct(v, name, (void **)obj, sizeof(UserDefOne), errp)) { return false; @@ -1446,24 +1443,22 @@ Example: assert(visit_is_dealloc(v)); goto out_obj; } - visit_type_UserDefOne_members(v, *obj, &err); - if (err) { + if (!visit_type_UserDefOne_members(v, *obj, errp)) { goto out_obj; } - visit_check_struct(v, &err); + ok = visit_check_struct(v, errp); out_obj: visit_end_struct(v, (void **)obj); - if (err && visit_is_input(v)) { + if (!ok && visit_is_input(v)) { qapi_free_UserDefOne(*obj); *obj = NULL; } - error_propagate(errp, err); - return !err; + return ok; } bool visit_type_UserDefOneList(Visitor *v, const char *name, UserDefOneList **obj, Error **errp) { - Error *err = NULL; + bool ok = false; UserDefOneList *tail; size_t size = sizeof(**obj); @@ -1473,33 +1468,27 @@ Example: for (tail = *obj; tail; tail = (UserDefOneList *)visit_next_list(v, (GenericList *)tail, size)) { - visit_type_UserDefOne(v, NULL, &tail->value, &err); - if (err) { - break; + if (!visit_type_UserDefOne(v, NULL, &tail->value, errp)) { + goto out_obj; } } - if (!err) { - visit_check_list(v, &err); - } + ok = visit_check_list(v, errp); + out_obj: visit_end_list(v, (void **)obj); - if (err && visit_is_input(v)) { + if (!ok && visit_is_input(v)) { qapi_free_UserDefOneList(*obj); *obj = NULL; } - error_propagate(errp, err); - return !err; + return ok; } bool visit_type_q_obj_my_command_arg_members(Visitor *v, q_obj_my_command_arg *obj, Error **errp) { - Error *err = NULL; - if (!visit_type_UserDefOneList(v, "arg1", &obj->arg1, errp)) { return false; } - error_propagate(errp, err); - return !err; + return true; } [Uninteresting stuff omitted...] @@ -1554,15 +1543,12 @@ Example: static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject **ret_out, Error **errp) { - Error *err = NULL; Visitor *v; v = qobject_output_visitor_new(ret_out); - visit_type_UserDefOne(v, "unused", &ret_in, &err); - if (!err) { + if (visit_type_UserDefOne(v, "unused", &ret_in, errp)) { visit_complete(v, ret_out); } - error_propagate(errp, err); visit_free(v); v = qapi_dealloc_visitor_new(); visit_type_UserDefOne(v, "unused", &ret_in, NULL); @@ -1572,33 +1558,32 @@ Example: void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp) { Error *err = NULL; + bool ok = false; Visitor *v; UserDefOne *retval; q_obj_my_command_arg arg = {0}; v = qobject_input_visitor_new(QOBJECT(args)); - visit_start_struct(v, NULL, NULL, 0, &err); - if (err) { + if (!visit_start_struct(v, NULL, NULL, 0, errp)) { goto out; } - visit_type_q_obj_my_command_arg_members(v, &arg, &err); - if (!err) { - visit_check_struct(v, &err); + if (visit_type_q_obj_my_command_arg_members(v, &arg, errp)) { + ok = visit_check_struct(v, errp); } visit_end_struct(v, NULL); - if (err) { + if (!ok) { goto out; } retval = qmp_my_command(arg.arg1, &err); + error_propagate(errp, err); if (err) { goto out; } - qmp_marshal_output_UserDefOne(retval, ret, &err); + qmp_marshal_output_UserDefOne(retval, ret, errp); out: - error_propagate(errp, err); visit_free(v); v = qapi_dealloc_visitor_new(); visit_start_struct(v, NULL, NULL, 0, NULL); @@ -1606,6 +1591,7 @@ Example: visit_end_struct(v, NULL); visit_free(v); } + [Uninteresting stuff omitted...] $ cat qapi-generated/example-qapi-init-commands.h [Uninteresting stuff omitted...] diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index 6809b0fb6e..3cf9e1110b 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -47,6 +47,7 @@ def gen_call(name, arg_type, boxed, ret_type): ret = mcgen(''' %(lhs)sqmp_%(c_name)s(%(args)s&err); + error_propagate(errp, err); ''', c_name=c_name(name), args=argstr, lhs=lhs) if ret_type: @@ -55,7 +56,7 @@ def gen_call(name, arg_type, boxed, ret_type): goto out; } - qmp_marshal_output_%(c_name)s(retval, ret, &err); + qmp_marshal_output_%(c_name)s(retval, ret, errp); ''', c_name=ret_type.c_name()) return ret @@ -66,15 +67,12 @@ def gen_marshal_output(ret_type): static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp) { - Error *err = NULL; Visitor *v; v = qobject_output_visitor_new(ret_out); - visit_type_%(c_name)s(v, "unused", &ret_in, &err); - if (!err) { + if (visit_type_%(c_name)s(v, "unused", &ret_in, errp)) { visit_complete(v, ret_out); } - error_propagate(errp, err); visit_free(v); v = qapi_dealloc_visitor_new(); visit_type_%(c_name)s(v, "unused", &ret_in, NULL); @@ -104,6 +102,7 @@ def gen_marshal(name, arg_type, boxed, ret_type): %(proto)s { Error *err = NULL; + bool ok = false; Visitor *v; ''', proto=build_marshal_proto(name)) @@ -123,28 +122,26 @@ def gen_marshal(name, arg_type, boxed, ret_type): ret += mcgen(''' v = qobject_input_visitor_new(QOBJECT(args)); - visit_start_struct(v, NULL, NULL, 0, &err); - if (err) { + if (!visit_start_struct(v, NULL, NULL, 0, errp)) { goto out; } ''') if have_args: ret += mcgen(''' - visit_type_%(c_arg_type)s_members(v, &arg, &err); - if (!err) { - visit_check_struct(v, &err); + if (visit_type_%(c_arg_type)s_members(v, &arg, errp)) { + ok = visit_check_struct(v, errp); } ''', c_arg_type=arg_type.c_name()) else: ret += mcgen(''' - visit_check_struct(v, &err); + ok = visit_check_struct(v, errp); ''') ret += mcgen(''' visit_end_struct(v, NULL); - if (err) { + if (!ok) { goto out; } ''') @@ -154,7 +151,6 @@ def gen_marshal(name, arg_type, boxed, ret_type): ret += mcgen(''' out: - error_propagate(errp, err); visit_free(v); ''') diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index ba0cf0b074..3fb2f30510 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -41,8 +41,6 @@ def gen_visit_object_members(name, base, members, variants): bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) { - Error *err = NULL; - ''', c_name=c_name(name)) @@ -97,8 +95,7 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) else: ret += mcgen(''' case %(case)s: - visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err); - break; + return visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, errp); ''', case=case_str, c_type=var.type.c_name(), c_name=c_name(var.name)) @@ -111,8 +108,7 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) ''') ret += mcgen(''' - error_propagate(errp, err); - return !err; + return true; } ''') return ret @@ -123,7 +119,7 @@ def gen_visit_list(name, element_type): bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) { - Error *err = NULL; + bool ok = false; %(c_name)s *tail; size_t size = sizeof(**obj); @@ -133,22 +129,19 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error for (tail = *obj; tail; tail = (%(c_name)s *)visit_next_list(v, (GenericList *)tail, size)) { - visit_type_%(c_elt_type)s(v, NULL, &tail->value, &err); - if (err) { - break; + if (!visit_type_%(c_elt_type)s(v, NULL, &tail->value, errp)) { + goto out_obj; } } - if (!err) { - visit_check_list(v, &err); - } + ok = visit_check_list(v, errp); +out_obj: visit_end_list(v, (void **)obj); - if (err && visit_is_input(v)) { + if (!ok && visit_is_input(v)) { qapi_free_%(c_name)s(*obj); *obj = NULL; } - error_propagate(errp, err); - return !err; + return ok; } ''', c_name=c_name(name), c_elt_type=element_type.c_name()) @@ -173,7 +166,7 @@ def gen_visit_alternate(name, variants): bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) { - Error *err = NULL; + bool ok = false; if (!visit_start_alternate(v, name, (GenericAlternate **)obj, sizeof(**obj), errp)) { @@ -182,6 +175,7 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error if (!*obj) { /* incomplete */ assert(visit_is_dealloc(v)); + ok = true; goto out_obj; } switch ((*obj)->type) { @@ -196,13 +190,11 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error case=var.type.alternate_qtype()) if isinstance(var.type, QAPISchemaObjectType): ret += mcgen(''' - visit_start_struct(v, name, NULL, 0, &err); - if (err) { + if (!visit_start_struct(v, name, NULL, 0, errp)) { break; } - visit_type_%(c_type)s_members(v, &(*obj)->u.%(c_name)s, &err); - if (!err) { - visit_check_struct(v, &err); + if (visit_type_%(c_type)s_members(v, &(*obj)->u.%(c_name)s, errp)) { + ok = visit_check_struct(v, errp); } visit_end_struct(v, NULL); ''', @@ -210,7 +202,7 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error c_name=c_name(var.name)) else: ret += mcgen(''' - visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, &err); + ok = visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, errp); ''', c_type=var.type.c_name(), c_name=c_name(var.name)) @@ -224,7 +216,7 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error abort(); default: assert(visit_is_input(v)); - error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "%(name)s"); /* Avoid passing invalid *obj to qapi_free_%(c_name)s() */ g_free(*obj); @@ -232,12 +224,11 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error } out_obj: visit_end_alternate(v, (void **)obj); - if (err && visit_is_input(v)) { + if (!ok && visit_is_input(v)) { qapi_free_%(c_name)s(*obj); *obj = NULL; } - error_propagate(errp, err); - return !err; + return ok; } ''', name=name, c_name=c_name(name)) @@ -250,7 +241,7 @@ def gen_visit_object(name, base, members, variants): bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) { - Error *err = NULL; + bool ok = false; if (!visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), errp)) { return false; @@ -260,19 +251,17 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error assert(visit_is_dealloc(v)); goto out_obj; } - visit_type_%(c_name)s_members(v, *obj, &err); - if (err) { + if (!visit_type_%(c_name)s_members(v, *obj, errp)) { goto out_obj; } - visit_check_struct(v, &err); + ok = visit_check_struct(v, errp); out_obj: visit_end_struct(v, (void **)obj); - if (err && visit_is_input(v)) { + if (!ok && visit_is_input(v)) { qapi_free_%(c_name)s(*obj); *obj = NULL; } - error_propagate(errp, err); - return !err; + return ok; } ''', c_name=c_name(name)) From 7b3cb8037c369cbc3072548ef0bd2cfa850bfae5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:09 +0200 Subject: [PATCH 2073/2595] qapi: Purge error_propagate() from QAPI core Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-42-armbru@redhat.com> --- qapi/qapi-visit-core.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 5a9c47aabf..7e5f40e7f0 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -39,19 +39,18 @@ void visit_free(Visitor *v) bool visit_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp) { - Error *err = NULL; + bool ok; trace_visit_start_struct(v, name, obj, size); if (obj) { assert(size); assert(!(v->type & VISITOR_OUTPUT) || *obj); } - v->start_struct(v, name, obj, size, &err); + ok = v->start_struct(v, name, obj, size, errp); if (obj && (v->type & VISITOR_INPUT)) { - assert(!err != !*obj); + assert(ok != !*obj); } - error_propagate(errp, err); - return !err; + return ok; } bool visit_check_struct(Visitor *v, Error **errp) @@ -69,16 +68,15 @@ void visit_end_struct(Visitor *v, void **obj) bool visit_start_list(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp) { - Error *err = NULL; + bool ok; assert(!list || size >= sizeof(GenericList)); trace_visit_start_list(v, name, list, size); - v->start_list(v, name, list, size, &err); + ok = v->start_list(v, name, list, size, errp); if (list && (v->type & VISITOR_INPUT)) { - assert(!(err && *list)); + assert(ok || !*list); } - error_propagate(errp, err); - return !err; + return ok; } GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size) @@ -104,19 +102,20 @@ bool visit_start_alternate(Visitor *v, const char *name, GenericAlternate **obj, size_t size, Error **errp) { - Error *err = NULL; + bool ok; assert(obj && size >= sizeof(GenericAlternate)); assert(!(v->type & VISITOR_OUTPUT) || *obj); trace_visit_start_alternate(v, name, obj, size); - if (v->start_alternate) { - v->start_alternate(v, name, obj, size, &err); + if (!v->start_alternate) { + assert(!(v->type & VISITOR_INPUT)); + return true; } + ok = v->start_alternate(v, name, obj, size, errp); if (v->type & VISITOR_INPUT) { - assert(v->start_alternate && !err != !*obj); + assert(ok != !*obj); } - error_propagate(errp, err); - return !err; + return ok; } void visit_end_alternate(Visitor *v, void **obj) @@ -309,7 +308,7 @@ bool visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) bool visit_type_str(Visitor *v, const char *name, char **obj, Error **errp) { - Error *err = NULL; + bool ok; assert(obj); /* TODO: Fix callers to not pass NULL when they mean "", so that we @@ -317,12 +316,11 @@ bool visit_type_str(Visitor *v, const char *name, char **obj, Error **errp) assert(!(v->type & VISITOR_OUTPUT) || *obj); */ trace_visit_type_str(v, name, obj); - v->type_str(v, name, obj, &err); + ok = v->type_str(v, name, obj, errp); if (v->type & VISITOR_INPUT) { - assert(!err != !*obj); + assert(ok != !*obj); } - error_propagate(errp, err); - return !err; + return ok; } bool visit_type_number(Visitor *v, const char *name, double *obj, From 386f6c07d28cf1b51e5d0f398faf67d396ff62a1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:10 +0200 Subject: [PATCH 2074/2595] error: Avoid error_propagate() after migrate_add_blocker() When migrate_add_blocker(blocker, &errp) is followed by error_propagate(errp, err), we can often just as well do migrate_add_blocker(..., errp). Do that with this Coccinelle script: @@ expression blocker, err, errp; expression ret; @@ - ret = migrate_add_blocker(blocker, &err); - if (err) { + ret = migrate_add_blocker(blocker, errp); + if (ret < 0) { ... when != err; - error_propagate(errp, err); ... } @@ expression blocker, err, errp; @@ - migrate_add_blocker(blocker, &err); - if (err) { + if (migrate_add_blocker(blocker, errp) < 0) { ... when != err; - error_propagate(errp, err); ... } Double-check @err is not used afterwards. Dereferencing it would be use after free, but checking whether it's null would be legitimate. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200707160613.848843-43-armbru@redhat.com> --- block/parallels.c | 5 ++--- block/qcow.c | 6 ++---- block/vdi.c | 6 ++---- block/vhdx.c | 5 ++--- block/vmdk.c | 6 ++---- block/vpc.c | 5 ++--- block/vvfat.c | 6 ++---- hw/display/virtio-gpu-base.c | 5 +---- hw/intc/arm_gic_kvm.c | 4 +--- hw/intc/arm_gicv3_its_kvm.c | 5 +---- hw/intc/arm_gicv3_kvm.c | 4 +--- hw/misc/ivshmem.c | 4 +--- hw/scsi/vhost-scsi.c | 4 +--- 13 files changed, 20 insertions(+), 45 deletions(-) diff --git a/block/parallels.c b/block/parallels.c index f489c0d4ba..3c22dfdc9d 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -859,9 +859,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, error_setg(&s->migration_blocker, "The Parallels format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); - ret = migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); + ret = migrate_add_blocker(s->migration_blocker, errp); + if (ret < 0) { error_free(s->migration_blocker); goto fail; } diff --git a/block/qcow.c b/block/qcow.c index c22d1bf6b8..1e134f3445 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -121,7 +121,6 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, unsigned int len, i, shift; int ret; QCowHeader header; - Error *local_err = NULL; QCryptoBlockOpenOptions *crypto_opts = NULL; unsigned int cflags = 0; QDict *encryptopts = NULL; @@ -314,9 +313,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, error_setg(&s->migration_blocker, "The qcow format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); - ret = migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); + ret = migrate_add_blocker(s->migration_blocker, errp); + if (ret < 0) { error_free(s->migration_blocker); goto fail; } diff --git a/block/vdi.c b/block/vdi.c index 2496d51a4d..5627e7d764 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -374,7 +374,6 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, VdiHeader header; size_t bmap_size; int ret; - Error *local_err = NULL; QemuUUID uuid_link, uuid_parent; bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, @@ -495,9 +494,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, error_setg(&s->migration_blocker, "The vdi format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); - ret = migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); + ret = migrate_add_blocker(s->migration_blocker, errp); + if (ret < 0) { error_free(s->migration_blocker); goto fail_free_bmap; } diff --git a/block/vhdx.c b/block/vhdx.c index a36d9d924a..791eb90263 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1089,9 +1089,8 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, error_setg(&s->migration_blocker, "The vhdx format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); - ret = migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); + ret = migrate_add_blocker(s->migration_blocker, errp); + if (ret < 0) { error_free(s->migration_blocker); goto fail; } diff --git a/block/vmdk.c b/block/vmdk.c index 9a09193f3b..28cec50f38 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1263,7 +1263,6 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, int ret; BDRVVmdkState *s = bs->opaque; uint32_t magic; - Error *local_err = NULL; bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, BDRV_CHILD_IMAGE, false, errp); @@ -1317,9 +1316,8 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, error_setg(&s->migration_blocker, "The vmdk format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); - ret = migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); + ret = migrate_add_blocker(s->migration_blocker, errp); + if (ret < 0) { error_free(s->migration_blocker); goto fail; } diff --git a/block/vpc.c b/block/vpc.c index 131b9db6cc..890554277e 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -446,9 +446,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, error_setg(&s->migration_blocker, "The vpc format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); - ret = migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); + ret = migrate_add_blocker(s->migration_blocker, errp); + if (ret < 0) { error_free(s->migration_blocker); goto fail; } diff --git a/block/vvfat.c b/block/vvfat.c index 24d36220d3..36b53c8757 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -1141,7 +1141,6 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, bool floppy; const char *dirname, *label; QemuOpts *opts; - Error *local_err = NULL; int ret; #ifdef DEBUG @@ -1267,9 +1266,8 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, "The vvfat (rw) format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); - ret = migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); + ret = migrate_add_blocker(s->migration_blocker, errp); + if (ret < 0) { error_free(s->migration_blocker); goto fail; } diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index c159351be3..7961308606 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -128,7 +128,6 @@ virtio_gpu_base_device_realize(DeviceState *qdev, { VirtIODevice *vdev = VIRTIO_DEVICE(qdev); VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev); - Error *local_err = NULL; int i; if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) { @@ -139,9 +138,7 @@ virtio_gpu_base_device_realize(DeviceState *qdev, g->use_virgl_renderer = false; if (virtio_gpu_virgl_enabled(g->conf)) { error_setg(&g->migration_blocker, "virgl is not yet migratable"); - migrate_add_blocker(g->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (migrate_add_blocker(g->migration_blocker, errp) < 0) { error_free(g->migration_blocker); return false; } diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index d7df423a7a..07b95143c9 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -517,9 +517,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) if (!kvm_arm_gic_can_save_restore(s)) { error_setg(&s->migration_blocker, "This operating system kernel does " "not support vGICv2 migration"); - migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (migrate_add_blocker(s->migration_blocker, errp) < 0) { error_free(s->migration_blocker); return; } diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index ad0ebabc87..46835ed085 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -91,7 +91,6 @@ static void vm_change_state_handler(void *opaque, int running, static void kvm_arm_its_realize(DeviceState *dev, Error **errp) { GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); - Error *local_err = NULL; s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false); if (s->dev_fd < 0) { @@ -113,9 +112,7 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) GITS_CTLR)) { error_setg(&s->migration_blocker, "This operating system kernel " "does not support vITS migration"); - migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (migrate_add_blocker(s->migration_blocker, errp) < 0) { error_free(s->migration_blocker); return; } diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index ca43bf87ca..eddd07c743 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -858,9 +858,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) GICD_CTLR)) { error_setg(&s->migration_blocker, "This operating system kernel does " "not support vGICv3 migration"); - migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (migrate_add_blocker(s->migration_blocker, errp) < 0) { error_free(s->migration_blocker); return; } diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index a8dc9b377d..fc128b25e2 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -898,9 +898,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) if (!ivshmem_is_master(s)) { error_setg(&s->migration_blocker, "Migration is disabled when using feature 'peer mode' in device 'ivshmem'"); - migrate_add_blocker(s->migration_blocker, &err); - if (err) { - error_propagate(errp, err); + if (migrate_add_blocker(s->migration_blocker, errp) < 0) { error_free(s->migration_blocker); return; } diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index c1b012aea4..13b05af29b 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -207,9 +207,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) "When external environment supports it (Orchestrator migrates " "target SCSI device state or use shared storage over network), " "set 'migratable' property to true to enable migration."); - migrate_add_blocker(vsc->migration_blocker, &err); - if (err) { - error_propagate(errp, err); + if (migrate_add_blocker(vsc->migration_blocker, errp) < 0) { error_free(vsc->migration_blocker); goto free_virtio; } From 9e194e063f813b95bc01e69a5357c1c341ee93c5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:11 +0200 Subject: [PATCH 2075/2595] qemu-img: Ignore Error objects where the return value suffices Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-44-armbru@redhat.com> [One more in img_amend() due to commit 0bc2a50e17 "qemu-option: Use returned bool to check for failure"] --- qemu-img.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 41d2b91091..498fbf42fe 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -465,22 +465,18 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts, const char *base_filename, const char *base_fmt) { - Error *err = NULL; - if (base_filename) { if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename, - &err)) { + NULL)) { error_report("Backing file not supported for file format '%s'", fmt); - error_free(err); return -1; } } if (base_fmt) { - if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, &err)) { + if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, NULL)) { error_report("Backing file format not supported for file " "format '%s'", fmt); - error_free(err); return -1; } } @@ -4214,17 +4210,12 @@ static int img_amend(int argc, char **argv) opts = qemu_opts_create(amend_opts, NULL, 0, &error_abort); if (!qemu_opts_do_parse(opts, options, NULL, &err)) { /* Try to parse options using the create options */ - Error *err1 = NULL; amend_opts = qemu_opts_append(amend_opts, bs->drv->create_opts); qemu_opts_del(opts); opts = qemu_opts_create(amend_opts, NULL, 0, &error_abort); - qemu_opts_do_parse(opts, options, NULL, &err1); - - if (!err1) { + if (qemu_opts_do_parse(opts, options, NULL, NULL)) { error_append_hint(&err, "This option is only supported for image creation\n"); - } else { - error_free(err1); } error_report_err(err); From 2d226cf6d18c853a3dca3fae1442be399caa2e6f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:12 +0200 Subject: [PATCH 2076/2595] qdev: Ignore Error objects where the return value suffices Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-45-armbru@redhat.com> --- hw/core/qdev-properties.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 2bec8a80b8..098298c78e 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -742,7 +742,6 @@ static void set_pci_devfn(Object *obj, Visitor *v, const char *name, Property *prop = opaque; int32_t value, *ptr = qdev_get_prop_ptr(dev, prop); unsigned int slot, fn, n; - Error *local_err = NULL; char *str; if (dev->realized) { @@ -750,9 +749,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, const char *name, return; } - if (!visit_type_str(v, name, &str, &local_err)) { - error_free(local_err); - local_err = NULL; + if (!visit_type_str(v, name, &str, NULL)) { if (!visit_type_int32(v, name, &value, errp)) { return; } From a43770df5dbbe90bbe8ccb25e7c570169d10710b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 7 Jul 2020 18:06:13 +0200 Subject: [PATCH 2077/2595] hmp: Ignore Error objects where the return value suffices qdev_print_props() receives and throws away Error objects just to check for object_property_get_str() and object_property_print() failure. Unnecessary, both return suitable values, so use those instead. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20200707160613.848843-46-armbru@redhat.com> --- qdev-monitor.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/qdev-monitor.c b/qdev-monitor.c index 9665a5398c..71ebce19df 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -697,22 +697,22 @@ static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props, if (!props) return; for (; props->name; props++) { - Error *err = NULL; char *value; char *legacy_name = g_strdup_printf("legacy-%s", props->name); + if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { - value = object_property_get_str(OBJECT(dev), legacy_name, &err); + value = object_property_get_str(OBJECT(dev), legacy_name, NULL); } else { - value = object_property_print(OBJECT(dev), props->name, true, &err); + value = object_property_print(OBJECT(dev), props->name, true, + NULL); } g_free(legacy_name); - if (err) { - error_free(err); + if (!value) { continue; } qdev_printf("%s = %s\n", props->name, - value && *value ? value : ""); + *value ? value : ""); g_free(value); } } From ae7c80a7bd73685437bf6ba9d7c26098351f4166 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 7 Jul 2020 18:50:30 +0200 Subject: [PATCH 2078/2595] error: New macro ERRP_GUARD() Introduce a new ERRP_GUARD() macro, to be used at start of functions with an errp OUT parameter. It has three goals: 1. Fix issue with error_fatal and error_prepend/error_append_hint: the user can't see this additional information, because exit() happens in error_setg earlier than information is added. [Reported by Greg Kurz] 2. Fix issue with error_abort and error_propagate: when we wrap error_abort by local_err+error_propagate, the resulting coredump will refer to error_propagate and not to the place where error happened. (the macro itself doesn't fix the issue, but it allows us to [3.] drop the local_err+error_propagate pattern, which will definitely fix the issue) [Reported by Kevin Wolf] 3. Drop local_err+error_propagate pattern, which is used to workaround void functions with errp parameter, when caller wants to know resulting status. (Note: actually these functions could be merely updated to return int error code). To achieve these goals, later patches will add invocations of this macro at the start of functions with either use error_prepend/error_append_hint (solving 1) or which use local_err+error_propagate to check errors, switching those functions to use *errp instead (solving 2 and 3). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Paul Durrant Reviewed-by: Greg Kurz Reviewed-by: Eric Blake [Merge comments properly with recent commit "error: Document Error API usage rules", and edit for clarity. Put ERRP_AUTO_PROPAGATE() before its helpers, and touch up style. Tweak commit message.] Signed-off-by: Markus Armbruster Message-Id: <20200707165037.1026246-2-armbru@redhat.com> [Rename ERRP_AUTO_PROPAGATE() to ERRP_GUARD(), tweak commit message again] --- include/qapi/error.h | 158 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 139 insertions(+), 19 deletions(-) diff --git a/include/qapi/error.h b/include/qapi/error.h index 2c189abb04..85df875a3a 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -30,6 +30,10 @@ * job. Since the value of @errp is about handling the error, the * function should not examine it. * + * - The function may pass @errp to functions it calls to pass on + * their errors to its caller. If it dereferences @errp to check + * for errors, it must use ERRP_GUARD(). + * * - On success, the function should not touch *errp. On failure, it * should set a new error, e.g. with error_setg(errp, ...), or * propagate an existing one, e.g. with error_propagate(errp, ...). @@ -45,15 +49,17 @@ * = Creating errors = * * Create an error: - * error_setg(&err, "situation normal, all fouled up"); + * error_setg(errp, "situation normal, all fouled up"); + * where @errp points to the location to receive the error. * * Create an error and add additional explanation: - * error_setg(&err, "invalid quark"); - * error_append_hint(&err, "Valid quarks are up, down, strange, " + * error_setg(errp, "invalid quark"); + * error_append_hint(errp, "Valid quarks are up, down, strange, " * "charm, top, bottom.\n"); + * This may require use of ERRP_GUARD(); more on that below. * * Do *not* contract this to - * error_setg(&err, "invalid quark\n" // WRONG! + * error_setg(errp, "invalid quark\n" // WRONG! * "Valid quarks are up, down, strange, charm, top, bottom."); * * = Reporting and destroying errors = @@ -107,18 +113,6 @@ * Errors get passed to the caller through the conventional @errp * parameter. * - * Pass an existing error to the caller: - * error_propagate(errp, err); - * where Error **errp is a parameter, by convention the last one. - * - * Pass an existing error to the caller with the message modified: - * error_propagate_prepend(errp, err, - * "Could not frobnicate '%s': ", name); - * This is more concise than - * error_propagate(errp, err); // don't do this - * error_prepend(errp, "Could not frobnicate '%s': ", name); - * and works even when @errp is &error_fatal. - * * Create a new error and pass it to the caller: * error_setg(errp, "situation normal, all fouled up"); * @@ -129,18 +123,26 @@ * handle the error... * } * - when it does not, say because it is a void function: + * ERRP_GUARD(); + * foo(arg, errp); + * if (*errp) { + * handle the error... + * } + * More on ERRP_GUARD() below. + * + * Code predating ERRP_GUARD() still exists, and looks like this: * Error *err = NULL; * foo(arg, &err); * if (err) { * handle the error... - * error_propagate(errp, err); + * error_propagate(errp, err); // deprecated * } - * Do *not* "optimize" this to + * Avoid in new code. Do *not* "optimize" it to * foo(arg, errp); * if (*errp) { // WRONG! * handle the error... * } - * because errp may be NULL! + * because errp may be NULL without the ERRP_GUARD() guard. * * But when all you do with the error is pass it on, please use * foo(arg, errp); @@ -160,6 +162,19 @@ * handle the error... * } * + * Pass an existing error to the caller: + * error_propagate(errp, err); + * This is rarely needed. When @err is a local variable, use of + * ERRP_GUARD() commonly results in more readable code. + * + * Pass an existing error to the caller with the message modified: + * error_propagate_prepend(errp, err, + * "Could not frobnicate '%s': ", name); + * This is more concise than + * error_propagate(errp, err); // don't do this + * error_prepend(errp, "Could not frobnicate '%s': ", name); + * and works even when @errp is &error_fatal. + * * Receive and accumulate multiple errors (first one wins): * Error *err = NULL, *local_err = NULL; * foo(arg, &err); @@ -187,6 +202,69 @@ * error_setg(&err, ...); // WRONG! * } * because this may pass a non-null err to error_setg(). + * + * = Why, when and how to use ERRP_GUARD() = + * + * Without ERRP_GUARD(), use of the @errp parameter is restricted: + * - It must not be dereferenced, because it may be null. + * - It should not be passed to error_prepend() or + * error_append_hint(), because that doesn't work with &error_fatal. + * ERRP_GUARD() lifts these restrictions. + * + * To use ERRP_GUARD(), add it right at the beginning of the function. + * @errp can then be used without worrying about the argument being + * NULL or &error_fatal. + * + * Using it when it's not needed is safe, but please avoid cluttering + * the source with useless code. + * + * = Converting to ERRP_GUARD() = + * + * To convert a function to use ERRP_GUARD(): + * + * 0. If the Error ** parameter is not named @errp, rename it to + * @errp. + * + * 1. Add an ERRP_GUARD() invocation, by convention right at the + * beginning of the function. This makes @errp safe to use. + * + * 2. Replace &err by errp, and err by *errp. Delete local variable + * @err. + * + * 3. Delete error_propagate(errp, *errp), replace + * error_propagate_prepend(errp, *errp, ...) by error_prepend(errp, ...) + * + * 4. Ensure @errp is valid at return: when you destroy *errp, set + * errp = NULL. + * + * Example: + * + * bool fn(..., Error **errp) + * { + * Error *err = NULL; + * + * foo(arg, &err); + * if (err) { + * handle the error... + * error_propagate(errp, err); + * return false; + * } + * ... + * } + * + * becomes + * + * bool fn(..., Error **errp) + * { + * ERRP_GUARD(); + * + * foo(arg, errp); + * if (*errp) { + * handle the error... + * return false; + * } + * ... + * } */ #ifndef ERROR_H @@ -287,6 +365,7 @@ void error_setg_win32_internal(Error **errp, * the error object. * Else, move the error object from @local_err to *@dst_errp. * On return, @local_err is invalid. + * Please use ERRP_GUARD() instead when possible. * Please don't error_propagate(&error_fatal, ...), use * error_report_err() and exit(), because that's more obvious. */ @@ -298,6 +377,7 @@ void error_propagate(Error **dst_errp, Error *local_err); * Behaves like * error_prepend(&local_err, fmt, ...); * error_propagate(dst_errp, local_err); + * Please use ERRP_GUARD() and error_prepend() instead when possible. */ void error_propagate_prepend(Error **dst_errp, Error *local_err, const char *fmt, ...); @@ -395,6 +475,46 @@ void error_set_internal(Error **errp, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(6, 7); +/* + * Make @errp parameter easier to use regardless of argument value + * + * This macro is for use right at the beginning of a function that + * takes an Error **errp parameter to pass errors to its caller. The + * parameter must be named @errp. + * + * It must be used when the function dereferences @errp or passes + * @errp to error_prepend(), error_vprepend(), or error_append_hint(). + * It is safe to use even when it's not needed, but please avoid + * cluttering the source with useless code. + * + * If @errp is NULL or &error_fatal, rewrite it to point to a local + * Error variable, which will be automatically propagated to the + * original @errp on function exit. + * + * Note: &error_abort is not rewritten, because that would move the + * abort from the place where the error is created to the place where + * it's propagated. + */ +#define ERRP_GUARD() \ + g_auto(ErrorPropagator) _auto_errp_prop = {.errp = errp}; \ + do { \ + if (!errp || errp == &error_fatal) { \ + errp = &_auto_errp_prop.local_err; \ + } \ + } while (0) + +typedef struct ErrorPropagator { + Error *local_err; + Error **errp; +} ErrorPropagator; + +static inline void error_propagator_cleanup(ErrorPropagator *prop) +{ + error_propagate(prop->errp, prop->local_err); +} + +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ErrorPropagator, error_propagator_cleanup); + /* * Special error destination to abort on error. * See error_setg() and error_propagate() for details. From 8220f3ac74a4698b0734aa882e74c5d9337e3d99 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 7 Jul 2020 18:50:31 +0200 Subject: [PATCH 2079/2595] scripts: Coccinelle script to use ERRP_GUARD() Script adds ERRP_GUARD() macro invocations where appropriate and does corresponding changes in code (look for details in include/qapi/error.h) Usage example: spatch --sp-file scripts/coccinelle/errp-guard.cocci \ --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \ --max-width 80 FILES... Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster Message-Id: <20200707165037.1026246-3-armbru@redhat.com> Reviewed-by: Eric Blake [ERRP_AUTO_PROPAGATE() renamed to ERRP_GUARD(), and auto-propagated-errp.cocci to errp-guard.cocci] --- MAINTAINERS | 1 + include/qapi/error.h | 2 + scripts/coccinelle/errp-guard.cocci | 336 ++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 scripts/coccinelle/errp-guard.cocci diff --git a/MAINTAINERS b/MAINTAINERS index f01284ebce..6aa54f7f8f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2176,6 +2176,7 @@ F: scripts/coccinelle/error-use-after-free.cocci F: scripts/coccinelle/error_propagate_null.cocci F: scripts/coccinelle/remove_local_err.cocci F: scripts/coccinelle/use-error_fatal.cocci +F: scripts/coccinelle/errp-guard.cocci GDB stub M: Alex Bennée diff --git a/include/qapi/error.h b/include/qapi/error.h index 85df875a3a..7932594dce 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -265,6 +265,8 @@ * } * ... * } + * + * For mass-conversion, use scripts/coccinelle/errp-guard.cocci. */ #ifndef ERROR_H diff --git a/scripts/coccinelle/errp-guard.cocci b/scripts/coccinelle/errp-guard.cocci new file mode 100644 index 0000000000..6e789acf2d --- /dev/null +++ b/scripts/coccinelle/errp-guard.cocci @@ -0,0 +1,336 @@ +// Use ERRP_GUARD() (see include/qapi/error.h) +// +// Copyright (c) 2020 Virtuozzo International GmbH. +// +// 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 +// . +// +// Usage example: +// spatch --sp-file scripts/coccinelle/errp-guard.cocci \ +// --macro-file scripts/cocci-macro-file.h --in-place \ +// --no-show-diff --max-width 80 FILES... +// +// Note: --max-width 80 is needed because coccinelle default is less +// than 80, and without this parameter coccinelle may reindent some +// lines which fit into 80 characters but not to coccinelle default, +// which in turn produces extra patch hunks for no reason. + +// Switch unusual Error ** parameter names to errp +// (this is necessary to use ERRP_GUARD). +// +// Disable optional_qualifier to skip functions with +// "Error *const *errp" parameter. +// +// Skip functions with "assert(_errp && *_errp)" statement, because +// that signals unusual semantics, and the parameter name may well +// serve a purpose. (like nbd_iter_channel_error()). +// +// Skip util/error.c to not touch, for example, error_propagate() and +// error_propagate_prepend(). +@ depends on !(file in "util/error.c") disable optional_qualifier@ +identifier fn; +identifier _errp != errp; +@@ + + fn(..., +- Error **_errp ++ Error **errp + ,...) + { +( + ... when != assert(_errp && *_errp) +& + <... +- _errp ++ errp + ...> +) + } + +// Add invocation of ERRP_GUARD() to errp-functions where // necessary +// +// Note, that without "when any" the final "..." does not mach +// something matched by previous pattern, i.e. the rule will not match +// double error_prepend in control flow like in +// vfio_set_irq_signaling(). +// +// Note, "exists" says that we want apply rule even if it does not +// match on all possible control flows (otherwise, it will not match +// standard pattern when error_propagate() call is in if branch). +@ disable optional_qualifier exists@ +identifier fn, local_err; +symbol errp; +@@ + + fn(..., Error **errp, ...) + { ++ ERRP_GUARD(); + ... when != ERRP_GUARD(); +( +( + error_append_hint(errp, ...); +| + error_prepend(errp, ...); +| + error_vprepend(errp, ...); +) + ... when any +| + Error *local_err = NULL; + ... +( + error_propagate_prepend(errp, local_err, ...); +| + error_propagate(errp, local_err); +) + ... +) + } + +// Warn when several Error * definitions are in the control flow. +// This rule is not chained to rule1 and less restrictive, to cover more +// functions to warn (even those we are not going to convert). +// +// Note, that even with one (or zero) Error * definition in the each +// control flow we may have several (in total) Error * definitions in +// the function. This case deserves attention too, but I don't see +// simple way to match with help of coccinelle. +@check1 disable optional_qualifier exists@ +identifier fn, _errp, local_err, local_err2; +position p1, p2; +@@ + + fn(..., Error **_errp, ...) + { + ... + Error *local_err = NULL;@p1 + ... when any + Error *local_err2 = NULL;@p2 + ... when any + } + +@ script:python @ +fn << check1.fn; +p1 << check1.p1; +p2 << check1.p2; +@@ + +print('Warning: function {} has several definitions of ' + 'Error * local variable: at {}:{} and then at {}:{}'.format( + fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line)) + +// Warn when several propagations are in the control flow. +@check2 disable optional_qualifier exists@ +identifier fn, _errp; +position p1, p2; +@@ + + fn(..., Error **_errp, ...) + { + ... +( + error_propagate_prepend(_errp, ...);@p1 +| + error_propagate(_errp, ...);@p1 +) + ... +( + error_propagate_prepend(_errp, ...);@p2 +| + error_propagate(_errp, ...);@p2 +) + ... when any + } + +@ script:python @ +fn << check2.fn; +p1 << check2.p1; +p2 << check2.p2; +@@ + +print('Warning: function {} propagates to errp several times in ' + 'one control flow: at {}:{} and then at {}:{}'.format( + fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line)) + +// Match functions with propagation of local error to errp. +// We want to refer these functions in several following rules, but I +// don't know a proper way to inherit a function, not just its name +// (to not match another functions with same name in following rules). +// Not-proper way is as follows: rename errp parameter in functions +// header and match it in following rules. Rename it back after all +// transformations. +// +// The common case is a single definition of local_err with at most one +// error_propagate_prepend() or error_propagate() on each control-flow +// path. Functions with multiple definitions or propagates we want to +// examine manually. Rules check1 and check2 emit warnings to guide us +// to them. +// +// Note that we match not only this "common case", but any function, +// which has the "common case" on at least one control-flow path. +@rule1 disable optional_qualifier exists@ +identifier fn, local_err; +symbol errp; +@@ + + fn(..., Error ** +- errp ++ ____ + , ...) + { + ... + Error *local_err = NULL; + ... +( + error_propagate_prepend(errp, local_err, ...); +| + error_propagate(errp, local_err); +) + ... + } + +// Convert special case with goto separately. +// I tried merging this into the following rule the obvious way, but +// it made Coccinelle hang on block.c +// +// Note interesting thing: if we don't do it here, and try to fixup +// "out: }" things later after all transformations (the rule will be +// the same, just without error_propagate() call), coccinelle fails to +// match this "out: }". +@ disable optional_qualifier@ +identifier rule1.fn, rule1.local_err, out; +symbol errp; +@@ + + fn(..., Error ** ____, ...) + { + <... +- goto out; ++ return; + ...> +- out: +- error_propagate(errp, local_err); + } + +// Convert most of local_err related stuff. +// +// Note, that we inherit rule1.fn and rule1.local_err names, not +// objects themselves. We may match something not related to the +// pattern matched by rule1. For example, local_err may be defined with +// the same name in different blocks inside one function, and in one +// block follow the propagation pattern and in other block doesn't. +// +// Note also that errp-cleaning functions +// error_free_errp +// error_report_errp +// error_reportf_errp +// warn_report_errp +// warn_reportf_errp +// are not yet implemented. They must call corresponding Error* - +// freeing function and then set *errp to NULL, to avoid further +// propagation to original errp (consider ERRP_GUARD in use). +// For example, error_free_errp may look like this: +// +// void error_free_errp(Error **errp) +// { +// error_free(*errp); +// *errp = NULL; +// } +@ disable optional_qualifier exists@ +identifier rule1.fn, rule1.local_err; +expression list args; +symbol errp; +@@ + + fn(..., Error ** ____, ...) + { + <... +( +- Error *local_err = NULL; +| + +// Convert error clearing functions +( +- error_free(local_err); ++ error_free_errp(errp); +| +- error_report_err(local_err); ++ error_report_errp(errp); +| +- error_reportf_err(local_err, args); ++ error_reportf_errp(errp, args); +| +- warn_report_err(local_err); ++ warn_report_errp(errp); +| +- warn_reportf_err(local_err, args); ++ warn_reportf_errp(errp, args); +) +?- local_err = NULL; + +| +- error_propagate_prepend(errp, local_err, args); ++ error_prepend(errp, args); +| +- error_propagate(errp, local_err); +| +- &local_err ++ errp +) + ...> + } + +// Convert remaining local_err usage. For example, different kinds of +// error checking in if conditionals. We can't merge this into +// previous hunk, as this conflicts with other substitutions in it (at +// least with "- local_err = NULL"). +@ disable optional_qualifier@ +identifier rule1.fn, rule1.local_err; +symbol errp; +@@ + + fn(..., Error ** ____, ...) + { + <... +- local_err ++ *errp + ...> + } + +// Always use the same pattern for checking error +@ disable optional_qualifier@ +identifier rule1.fn; +symbol errp; +@@ + + fn(..., Error ** ____, ...) + { + <... +- *errp != NULL ++ *errp + ...> + } + +// Revert temporary ___ identifier. +@ disable optional_qualifier@ +identifier rule1.fn; +@@ + + fn(..., Error ** +- ____ ++ errp + , ...) + { + ... + } From de1b3800b7ec929f95371e6ab0345bf8b583043d Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 7 Jul 2020 18:50:32 +0200 Subject: [PATCH 2080/2595] sd: Use ERRP_GUARD() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we want to check error after errp-function call, we need to introduce local_err and then propagate it to errp. Instead, use the ERRP_GUARD() macro, benefits are: 1. No need of explicit error_propagate call 2. No need of explicit local_err variable: use errp directly 3. ERRP_GUARD() leaves errp as is if it's not NULL or &error_fatal, this means that we don't break error_abort (we'll abort on error_set, not on error_propagate) If we want to add some info to errp (by error_prepend() or error_append_hint()), we must use the ERRP_GUARD() macro. Otherwise, this info will not be added when errp == &error_fatal (the program will exit prior to the error_append_hint() or error_prepend() call). No such cases are being fixed here. This commit is generated by command sed -n '/^SD (Secure Card)$/,/^$/{s/^F: //p}' \ MAINTAINERS | \ xargs git ls-files | grep '\.[hc]$' | \ xargs spatch \ --sp-file scripts/coccinelle/errp-guard.cocci \ --macro-file scripts/cocci-macro-file.h \ --in-place --no-show-diff --max-width 80 Reported-by: Kevin Wolf Reported-by: Greg Kurz Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Philippe Mathieu-Daudé [Commit message tweaked] Signed-off-by: Markus Armbruster Message-Id: <20200707165037.1026246-4-armbru@redhat.com> [ERRP_AUTO_PROPAGATE() renamed to ERRP_GUARD(), and auto-propagated-errp.cocci to errp-guard.cocci. Commit message tweaked again.] --- hw/sd/sdhci-pci.c | 7 +++---- hw/sd/sdhci.c | 21 +++++++++------------ hw/sd/ssi-sd.c | 10 +++++----- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/hw/sd/sdhci-pci.c b/hw/sd/sdhci-pci.c index 4f5977d487..c737c8b930 100644 --- a/hw/sd/sdhci-pci.c +++ b/hw/sd/sdhci-pci.c @@ -29,13 +29,12 @@ static Property sdhci_pci_properties[] = { static void sdhci_pci_realize(PCIDevice *dev, Error **errp) { + ERRP_GUARD(); SDHCIState *s = PCI_SDHCI(dev); - Error *local_err = NULL; sdhci_initfn(s); - sdhci_common_realize(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); + sdhci_common_realize(s, errp); + if (*errp) { return; } diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index eb2be6529e..deac181865 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1288,7 +1288,7 @@ static const MemoryRegionOps sdhci_mmio_ops = { static void sdhci_init_readonly_registers(SDHCIState *s, Error **errp) { - Error *local_err = NULL; + ERRP_GUARD(); switch (s->sd_spec_version) { case 2 ... 3: @@ -1299,9 +1299,8 @@ static void sdhci_init_readonly_registers(SDHCIState *s, Error **errp) } s->version = (SDHC_HCVER_VENDOR << 8) | (s->sd_spec_version - 1); - sdhci_check_capareg(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); + sdhci_check_capareg(s, errp); + if (*errp) { return; } } @@ -1332,11 +1331,10 @@ void sdhci_uninitfn(SDHCIState *s) void sdhci_common_realize(SDHCIState *s, Error **errp) { - Error *local_err = NULL; + ERRP_GUARD(); - sdhci_init_readonly_registers(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); + sdhci_init_readonly_registers(s, errp); + if (*errp) { return; } s->buf_maxsz = sdhci_get_fifolen(s); @@ -1456,13 +1454,12 @@ static void sdhci_sysbus_finalize(Object *obj) static void sdhci_sysbus_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); SDHCIState *s = SYSBUS_SDHCI(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - Error *local_err = NULL; - sdhci_common_realize(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); + sdhci_common_realize(s, errp); + if (*errp) { return; } diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 3717b2e721..9210ef567f 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -241,10 +241,10 @@ static const VMStateDescription vmstate_ssi_sd = { static void ssi_sd_realize(SSISlave *d, Error **errp) { + ERRP_GUARD(); ssi_sd_state *s = SSI_SD(d); DeviceState *carddev; DriveInfo *dinfo; - Error *err = NULL; qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(d), "sd-bus"); @@ -255,23 +255,23 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) carddev = qdev_new(TYPE_SD_CARD); if (dinfo) { if (!qdev_prop_set_drive_err(carddev, "drive", - blk_by_legacy_dinfo(dinfo), &err)) { + blk_by_legacy_dinfo(dinfo), errp)) { goto fail; } } - if (!object_property_set_bool(OBJECT(carddev), "spi", true, &err)) { + if (!object_property_set_bool(OBJECT(carddev), "spi", true, errp)) { goto fail; } - if (!qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err)) { + if (!qdev_realize_and_unref(carddev, BUS(&s->sdbus), errp)) { goto fail; } return; fail: - error_propagate_prepend(errp, err, "failed to init SD card: "); + error_prepend(errp, "failed to init SD card: "); } static void ssi_sd_reset(DeviceState *dev) From 76612456aad55c7a2a57aa533a6f935aedb55475 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 7 Jul 2020 18:50:33 +0200 Subject: [PATCH 2081/2595] pflash: Use ERRP_GUARD() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we want to check error after errp-function call, we need to introduce local_err and then propagate it to errp. Instead, use the ERRP_GUARD() macro, benefits are: 1. No need of explicit error_propagate call 2. No need of explicit local_err variable: use errp directly 3. ERRP_GUARD() leaves errp as is if it's not NULL or &error_fatal, this means that we don't break error_abort (we'll abort on error_set, not on error_propagate) If we want to add some info to errp (by error_prepend() or error_append_hint()), we must use the ERRP_GUARD() macro. Otherwise, this info will not be added when errp == &error_fatal (the program will exit prior to the error_append_hint() or error_prepend() call). No such cases are being fixed here. This commit is generated by command sed -n '/^Parallel NOR Flash devices$/,/^$/{s/^F: //p}' \ MAINTAINERS | \ xargs git ls-files | grep '\.[hc]$' | \ xargs spatch \ --sp-file scripts/coccinelle/errp-guard.cocci \ --macro-file scripts/cocci-macro-file.h \ --in-place --no-show-diff --max-width 80 Reported-by: Kevin Wolf Reported-by: Greg Kurz Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Philippe Mathieu-Daudé [Commit message tweaked] Signed-off-by: Markus Armbruster Message-Id: <20200707165037.1026246-5-armbru@redhat.com> [ERRP_AUTO_PROPAGATE() renamed to ERRP_GUARD(), and auto-propagated-errp.cocci to errp-guard.cocci. Commit message tweaked again.] --- hw/block/pflash_cfi01.c | 7 +++---- hw/block/pflash_cfi02.c | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index cddc3a5a0c..8ab1d66310 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -696,12 +696,12 @@ static const MemoryRegionOps pflash_cfi01_ops = { static void pflash_cfi01_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); PFlashCFI01 *pfl = PFLASH_CFI01(dev); uint64_t total_len; int ret; uint64_t blocks_per_device, sector_len_per_device, device_len; int num_devices; - Error *local_err = NULL; if (pfl->sector_len == 0) { error_setg(errp, "attribute \"sector-length\" not specified or zero."); @@ -735,9 +735,8 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) &pfl->mem, OBJECT(dev), &pflash_cfi01_ops, pfl, - pfl->name, total_len, &local_err); - if (local_err) { - error_propagate(errp, local_err); + pfl->name, total_len, errp); + if (*errp) { return; } diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index b40ce2335a..eb02fccfa5 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -724,9 +724,9 @@ static const MemoryRegionOps pflash_cfi02_ops = { static void pflash_cfi02_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); PFlashCFI02 *pfl = PFLASH_CFI02(dev); int ret; - Error *local_err = NULL; if (pfl->uniform_sector_len == 0 && pfl->sector_len[0] == 0) { error_setg(errp, "attribute \"sector-length\" not specified or zero."); @@ -792,9 +792,8 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl), &pflash_cfi02_ops, pfl, pfl->name, - pfl->chip_len, &local_err); - if (local_err) { - error_propagate(errp, local_err); + pfl->chip_len, errp); + if (*errp) { return; } From 8b4b52759a7c472ee3427d6c82f60091b6f69196 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 7 Jul 2020 18:50:34 +0200 Subject: [PATCH 2082/2595] fw_cfg: Use ERRP_GUARD() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we want to check error after errp-function call, we need to introduce local_err and then propagate it to errp. Instead, use the ERRP_GUARD() macro, benefits are: 1. No need of explicit error_propagate call 2. No need of explicit local_err variable: use errp directly 3. ERRP_GUARD() leaves errp as is if it's not NULL or &error_fatal, this means that we don't break error_abort (we'll abort on error_set, not on error_propagate) If we want to add some info to errp (by error_prepend() or error_append_hint()), we must use the ERRP_GUARD() macro. Otherwise, this info will not be added when errp == &error_fatal (the program will exit prior to the error_append_hint() or error_prepend() call). No such cases are being fixed here. This commit is generated by command sed -n '/^Firmware configuration (fw_cfg)$/,/^$/{s/^F: //p}' \ MAINTAINERS | \ xargs git ls-files | grep '\.[hc]$' | \ xargs spatch \ --sp-file scripts/coccinelle/errp-guard.cocci \ --macro-file scripts/cocci-macro-file.h \ --in-place --no-show-diff --max-width 80 Reported-by: Kevin Wolf Reported-by: Greg Kurz Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Philippe Mathieu-Daudé [Commit message tweaked] Signed-off-by: Markus Armbruster Message-Id: <20200707165037.1026246-6-armbru@redhat.com> [ERRP_AUTO_PROPAGATE() renamed to ERRP_GUARD(), and auto-propagated-errp.cocci to errp-guard.cocci. Commit message tweaked again. Coccinelle script rerun for commit 3203148917 "hw/nvram/fw_cfg: Add the FW_CFG_DATA_GENERATOR interface"] --- hw/nvram/fw_cfg.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 694722b212..3b1811d3bf 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -1035,8 +1035,8 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void fw_cfg_add_from_generator(FWCfgState *s, const char *filename, const char *gen_id, Error **errp) { + ERRP_GUARD(); FWCfgDataGeneratorClass *klass; - Error *local_err = NULL; GByteArray *array; Object *obj; gsize size; @@ -1052,9 +1052,8 @@ void fw_cfg_add_from_generator(FWCfgState *s, const char *filename, return; } klass = FW_CFG_DATA_GENERATOR_GET_CLASS(obj); - array = klass->get_data(obj, &local_err); - if (local_err) { - error_propagate(errp, local_err); + array = klass->get_data(obj, errp); + if (*errp) { return; } size = array->len; @@ -1260,12 +1259,11 @@ static Property fw_cfg_io_properties[] = { static void fw_cfg_io_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); FWCfgIoState *s = FW_CFG_IO(dev); - Error *local_err = NULL; - fw_cfg_file_slots_allocate(FW_CFG(s), &local_err); - if (local_err) { - error_propagate(errp, local_err); + fw_cfg_file_slots_allocate(FW_CFG(s), errp); + if (*errp) { return; } @@ -1311,14 +1309,13 @@ static Property fw_cfg_mem_properties[] = { static void fw_cfg_mem_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); FWCfgMemState *s = FW_CFG_MEM(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops; - Error *local_err = NULL; - fw_cfg_file_slots_allocate(FW_CFG(s), &local_err); - if (local_err) { - error_propagate(errp, local_err); + fw_cfg_file_slots_allocate(FW_CFG(s), errp); + if (*errp) { return; } From 92c451222c541ce2bdcd0483550f472ec5fcfb5f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 7 Jul 2020 18:50:35 +0200 Subject: [PATCH 2083/2595] virtio-9p: Use ERRP_GUARD() If we want to check error after errp-function call, we need to introduce local_err and then propagate it to errp. Instead, use the ERRP_GUARD() macro, benefits are: 1. No need of explicit error_propagate call 2. No need of explicit local_err variable: use errp directly 3. ERRP_GUARD() leaves errp as is if it's not NULL or &error_fatal, this means that we don't break error_abort (we'll abort on error_set, not on error_propagate) If we want to add some info to errp (by error_prepend() or error_append_hint()), we must use the ERRP_GUARD() macro. Otherwise, this info will not be added when errp == &error_fatal (the program will exit prior to the error_append_hint() or error_prepend() call). Fix such a case in v9fs_device_realize_common(). This commit is generated by command sed -n '/^virtio-9p$/,/^$/{s/^F: //p}' MAINTAINERS | \ xargs git ls-files | grep '\.[hc]$' | \ xargs spatch \ --sp-file scripts/coccinelle/errp-guard.cocci \ --macro-file scripts/cocci-macro-file.h \ --in-place --no-show-diff --max-width 80 Reported-by: Kevin Wolf Reported-by: Greg Kurz Signed-off-by: Vladimir Sementsov-Ogievskiy Acked-by: Greg Kurz Reviewed-by: Christian Schoenebeck [Commit message tweaked] Signed-off-by: Markus Armbruster Message-Id: <20200707165037.1026246-7-armbru@redhat.com> [ERRP_AUTO_PROPAGATE() renamed to ERRP_GUARD(), and auto-propagated-errp.cocci to errp-guard.cocci. Commit message tweaked again.] --- hw/9pfs/9p-local.c | 12 +++++------- hw/9pfs/9p.c | 1 + 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 54e012e5b4..3107637209 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -1479,10 +1479,10 @@ static void error_append_security_model_hint(Error *const *errp) static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp) { + ERRP_GUARD(); const char *sec_model = qemu_opt_get(opts, "security_model"); const char *path = qemu_opt_get(opts, "path"); const char *multidevs = qemu_opt_get(opts, "multidevs"); - Error *local_err = NULL; if (!sec_model) { error_setg(errp, "security_model property not set"); @@ -1516,11 +1516,10 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp) fse->export_flags &= ~V9FS_FORBID_MULTIDEVS; fse->export_flags &= ~V9FS_REMAP_INODES; } else { - error_setg(&local_err, "invalid multidevs property '%s'", + error_setg(errp, "invalid multidevs property '%s'", multidevs); - error_append_hint(&local_err, "Valid options are: multidevs=" + error_append_hint(errp, "Valid options are: multidevs=" "[remap|forbid|warn]\n"); - error_propagate(errp, local_err); return -1; } } @@ -1530,9 +1529,8 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp) return -1; } - if (fsdev_throttle_parse_opts(opts, &fse->fst, &local_err)) { - error_propagate_prepend(errp, local_err, - "invalid throttle configuration: "); + if (fsdev_throttle_parse_opts(opts, &fse->fst, errp)) { + error_prepend(errp, "invalid throttle configuration: "); return -1; } diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 9755fba9a9..2ffd96ade9 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -4011,6 +4011,7 @@ void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr) int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t, Error **errp) { + ERRP_GUARD(); int i, len; struct stat stat; FsDriverEntry *fse; From 795d946d0797e7ba28ed97c86e2592e346b02b0e Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 7 Jul 2020 18:50:36 +0200 Subject: [PATCH 2084/2595] nbd: Use ERRP_GUARD() If we want to check error after errp-function call, we need to introduce local_err and then propagate it to errp. Instead, use the ERRP_GUARD() macro, benefits are: 1. No need of explicit error_propagate call 2. No need of explicit local_err variable: use errp directly 3. ERRP_GUARD() leaves errp as is if it's not NULL or &error_fatal, this means that we don't break error_abort (we'll abort on error_set, not on error_propagate) If we want to add some info to errp (by error_prepend() or error_append_hint()), we must use the ERRP_GUARD() macro. Otherwise, this info will not be added when errp == &error_fatal (the program will exit prior to the error_append_hint() or error_prepend() call). Fix several such cases, e.g. in nbd_read(). This commit is generated by command sed -n '/^Network Block Device (NBD)$/,/^$/{s/^F: //p}' \ MAINTAINERS | \ xargs git ls-files | grep '\.[hc]$' | \ xargs spatch \ --sp-file scripts/coccinelle/errp-guard.cocci \ --macro-file scripts/cocci-macro-file.h \ --in-place --no-show-diff --max-width 80 Reported-by: Kevin Wolf Reported-by: Greg Kurz Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Markus Armbruster [Commit message tweaked] Signed-off-by: Markus Armbruster Message-Id: <20200707165037.1026246-8-armbru@redhat.com> Reviewed-by: Eric Blake [ERRP_AUTO_PROPAGATE() renamed to ERRP_GUARD(), and auto-propagated-errp.cocci to errp-guard.cocci. Commit message tweaked again.] --- block/nbd.c | 7 +++---- include/block/nbd.h | 1 + nbd/client.c | 5 +++++ nbd/server.c | 5 +++++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index 6876da04a7..c297336ffc 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1408,16 +1408,15 @@ static void nbd_client_close(BlockDriverState *bs) static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr, Error **errp) { + ERRP_GUARD(); QIOChannelSocket *sioc; - Error *local_err = NULL; sioc = qio_channel_socket_new(); qio_channel_set_name(QIO_CHANNEL(sioc), "nbd-client"); - qio_channel_socket_connect_sync(sioc, saddr, &local_err); - if (local_err) { + qio_channel_socket_connect_sync(sioc, saddr, errp); + if (*errp) { object_unref(OBJECT(sioc)); - error_propagate(errp, local_err); return NULL; } diff --git a/include/block/nbd.h b/include/block/nbd.h index 20363280ae..9bc3bfaeec 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -361,6 +361,7 @@ void nbd_server_start_options(NbdServerOptions *arg, Error **errp); static inline int nbd_read(QIOChannel *ioc, void *buffer, size_t size, const char *desc, Error **errp) { + ERRP_GUARD(); int ret = qio_channel_read_all(ioc, buffer, size, errp) < 0 ? -EIO : 0; if (ret < 0) { diff --git a/nbd/client.c b/nbd/client.c index ba173108ba..0c2db4bcba 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -68,6 +68,7 @@ static int nbd_send_option_request(QIOChannel *ioc, uint32_t opt, uint32_t len, const char *data, Error **errp) { + ERRP_GUARD(); NBDOption req; QEMU_BUILD_BUG_ON(sizeof(req) != 16); @@ -153,6 +154,7 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, bool strict, Error **errp) { + ERRP_GUARD(); g_autofree char *msg = NULL; if (!(reply->type & (1 << 31))) { @@ -337,6 +339,7 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description, static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, NBDExportInfo *info, Error **errp) { + ERRP_GUARD(); NBDOptionReply reply; uint32_t len = strlen(info->name); uint16_t type; @@ -882,6 +885,7 @@ static int nbd_start_negotiate(AioContext *aio_context, QIOChannel *ioc, bool structured_reply, bool *zeroes, Error **errp) { + ERRP_GUARD(); uint64_t magic; trace_nbd_start_negotiate(tlscreds, hostname ? hostname : ""); @@ -1017,6 +1021,7 @@ int nbd_receive_negotiate(AioContext *aio_context, QIOChannel *ioc, const char *hostname, QIOChannel **outioc, NBDExportInfo *info, Error **errp) { + ERRP_GUARD(); int result; bool zeroes; bool base_allocation = info->base_allocation; diff --git a/nbd/server.c b/nbd/server.c index 20754e9ebc..5357f588f0 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -211,6 +211,7 @@ static int GCC_FMT_ATTR(4, 0) nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type, Error **errp, const char *fmt, va_list va) { + ERRP_GUARD(); g_autofree char *msg = NULL; int ret; size_t len; @@ -382,6 +383,7 @@ static int nbd_opt_read_name(NBDClient *client, char **name, uint32_t *length, static int nbd_negotiate_send_rep_list(NBDClient *client, NBDExport *exp, Error **errp) { + ERRP_GUARD(); size_t name_len, desc_len; uint32_t len; const char *name = exp->name ? exp->name : ""; @@ -445,6 +447,7 @@ static void nbd_check_meta_export(NBDClient *client) static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes, Error **errp) { + ERRP_GUARD(); g_autofree char *name = NULL; char buf[NBD_REPLY_EXPORT_NAME_SIZE] = ""; size_t len; @@ -1289,6 +1292,7 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp) */ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) { + ERRP_GUARD(); char buf[NBD_OLDSTYLE_NEGOTIATE_SIZE] = ""; int ret; @@ -1663,6 +1667,7 @@ void nbd_export_close(NBDExport *exp) void nbd_export_remove(NBDExport *exp, NbdServerRemoveMode mode, Error **errp) { + ERRP_GUARD(); if (mode == NBD_SERVER_REMOVE_MODE_HARD || QTAILQ_EMPTY(&exp->clients)) { nbd_export_close(exp); return; From 1de7096d8378a57e2d75d9cacc9a119e7e41640d Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 7 Jul 2020 18:50:37 +0200 Subject: [PATCH 2085/2595] xen: Use ERRP_GUARD() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we want to check error after errp-function call, we need to introduce local_err and then propagate it to errp. Instead, use the ERRP_GUARD() macro, benefits are: 1. No need of explicit error_propagate call 2. No need of explicit local_err variable: use errp directly 3. ERRP_GUARD() leaves errp as is if it's not NULL or &error_fatal, this means that we don't break error_abort (we'll abort on error_set, not on error_propagate) If we want to add some info to errp (by error_prepend() or error_append_hint()), we must use the ERRP_GUARD() macro. Otherwise, this info will not be added when errp == &error_fatal (the program will exit prior to the error_append_hint() or error_prepend() call). No such cases are being fixed here. This commit is generated by command sed -n '/^X86 Xen CPUs$/,/^$/{s/^F: //p}' MAINTAINERS | \ xargs git ls-files | grep '\.[hc]$' | \ xargs spatch \ --sp-file scripts/coccinelle/errp-guard.cocci \ --macro-file scripts/cocci-macro-file.h \ --in-place --no-show-diff --max-width 80 Reported-by: Kevin Wolf Reported-by: Greg Kurz Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Philippe Mathieu-Daudé [Commit message tweaked] Signed-off-by: Markus Armbruster Message-Id: <20200707165037.1026246-9-armbru@redhat.com> [ERRP_AUTO_PROPAGATE() renamed to ERRP_GUARD(), and auto-propagated-errp.cocci to errp-guard.cocci. Commit message tweaked again.] --- hw/block/dataplane/xen-block.c | 17 +++--- hw/block/xen-block.c | 102 ++++++++++++++------------------- hw/pci-host/xen_igd_pt.c | 7 +-- hw/xen/xen-backend.c | 7 +-- hw/xen/xen-bus.c | 92 +++++++++++++---------------- hw/xen/xen-host-pci-device.c | 27 +++++---- hw/xen/xen_pt.c | 25 ++++---- hw/xen/xen_pt_config_init.c | 17 +++--- 8 files changed, 128 insertions(+), 166 deletions(-) diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index 5f8f15778b..71c337c7b7 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -723,8 +723,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane, unsigned int protocol, Error **errp) { + ERRP_GUARD(); XenDevice *xendev = dataplane->xendev; - Error *local_err = NULL; unsigned int ring_size; unsigned int i; @@ -760,9 +760,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane, } xen_device_set_max_grant_refs(xendev, dataplane->nr_ring_ref, - &local_err); - if (local_err) { - error_propagate(errp, local_err); + errp); + if (*errp) { goto stop; } @@ -770,9 +769,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane, dataplane->ring_ref, dataplane->nr_ring_ref, PROT_READ | PROT_WRITE, - &local_err); - if (local_err) { - error_propagate(errp, local_err); + errp); + if (*errp) { goto stop; } @@ -805,9 +803,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane, dataplane->event_channel = xen_device_bind_event_channel(xendev, event_channel, xen_block_dataplane_event, dataplane, - &local_err); - if (local_err) { - error_propagate(errp, local_err); + errp); + if (*errp) { goto stop; } diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index a775fba7c0..8a7a3f5452 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -195,6 +195,7 @@ static const BlockDevOps xen_block_dev_ops = { static void xen_block_realize(XenDevice *xendev, Error **errp) { + ERRP_GUARD(); XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_GET_CLASS(xendev); @@ -202,7 +203,6 @@ static void xen_block_realize(XenDevice *xendev, Error **errp) XenBlockVdev *vdev = &blockdev->props.vdev; BlockConf *conf = &blockdev->props.conf; BlockBackend *blk = conf->blk; - Error *local_err = NULL; if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) { error_setg(errp, "vdev property not set"); @@ -212,9 +212,8 @@ static void xen_block_realize(XenDevice *xendev, Error **errp) trace_xen_block_realize(type, vdev->disk, vdev->partition); if (blockdev_class->realize) { - blockdev_class->realize(blockdev, &local_err); - if (local_err) { - error_propagate(errp, local_err); + blockdev_class->realize(blockdev, errp); + if (*errp) { return; } } @@ -280,8 +279,8 @@ static void xen_block_frontend_changed(XenDevice *xendev, enum xenbus_state frontend_state, Error **errp) { + ERRP_GUARD(); enum xenbus_state backend_state = xen_device_backend_get_state(xendev); - Error *local_err = NULL; switch (frontend_state) { case XenbusStateInitialised: @@ -290,15 +289,13 @@ static void xen_block_frontend_changed(XenDevice *xendev, break; } - xen_block_disconnect(xendev, &local_err); - if (local_err) { - error_propagate(errp, local_err); + xen_block_disconnect(xendev, errp); + if (*errp) { break; } - xen_block_connect(xendev, &local_err); - if (local_err) { - error_propagate(errp, local_err); + xen_block_connect(xendev, errp); + if (*errp) { break; } @@ -311,9 +308,8 @@ static void xen_block_frontend_changed(XenDevice *xendev, case XenbusStateClosed: case XenbusStateUnknown: - xen_block_disconnect(xendev, &local_err); - if (local_err) { - error_propagate(errp, local_err); + xen_block_disconnect(xendev, errp); + if (*errp) { break; } @@ -665,9 +661,9 @@ static void xen_block_blockdev_del(const char *node_name, Error **errp) static char *xen_block_blockdev_add(const char *id, QDict *qdict, Error **errp) { + ERRP_GUARD(); const char *driver = qdict_get_try_str(qdict, "driver"); BlockdevOptions *options = NULL; - Error *local_err = NULL; char *node_name; Visitor *v; @@ -688,10 +684,9 @@ static char *xen_block_blockdev_add(const char *id, QDict *qdict, goto fail; } - qmp_blockdev_add(options, &local_err); + qmp_blockdev_add(options, errp); - if (local_err) { - error_propagate(errp, local_err); + if (*errp) { goto fail; } @@ -710,14 +705,12 @@ fail: static void xen_block_drive_destroy(XenBlockDrive *drive, Error **errp) { + ERRP_GUARD(); char *node_name = drive->node_name; if (node_name) { - Error *local_err = NULL; - - xen_block_blockdev_del(node_name, &local_err); - if (local_err) { - error_propagate(errp, local_err); + xen_block_blockdev_del(node_name, errp); + if (*errp) { return; } g_free(node_name); @@ -731,6 +724,7 @@ static XenBlockDrive *xen_block_drive_create(const char *id, const char *device_type, QDict *opts, Error **errp) { + ERRP_GUARD(); const char *params = qdict_get_try_str(opts, "params"); const char *mode = qdict_get_try_str(opts, "mode"); const char *direct_io_safe = qdict_get_try_str(opts, "direct-io-safe"); @@ -738,7 +732,6 @@ static XenBlockDrive *xen_block_drive_create(const char *id, char *driver = NULL; char *filename = NULL; XenBlockDrive *drive = NULL; - Error *local_err = NULL; QDict *file_layer; QDict *driver_layer; @@ -817,13 +810,12 @@ static XenBlockDrive *xen_block_drive_create(const char *id, g_assert(!drive->node_name); drive->node_name = xen_block_blockdev_add(drive->id, driver_layer, - &local_err); + errp); qobject_unref(driver_layer); done: - if (local_err) { - error_propagate(errp, local_err); + if (*errp) { xen_block_drive_destroy(drive, NULL); return NULL; } @@ -848,8 +840,8 @@ static void xen_block_iothread_destroy(XenBlockIOThread *iothread, static XenBlockIOThread *xen_block_iothread_create(const char *id, Error **errp) { + ERRP_GUARD(); XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1); - Error *local_err = NULL; QDict *opts; QObject *ret_data = NULL; @@ -858,13 +850,11 @@ static XenBlockIOThread *xen_block_iothread_create(const char *id, opts = qdict_new(); qdict_put_str(opts, "qom-type", TYPE_IOTHREAD); qdict_put_str(opts, "id", id); - qmp_object_add(opts, &ret_data, &local_err); + qmp_object_add(opts, &ret_data, errp); qobject_unref(opts); qobject_unref(ret_data); - if (local_err) { - error_propagate(errp, local_err); - + if (*errp) { g_free(iothread->id); g_free(iothread); return NULL; @@ -876,6 +866,7 @@ static XenBlockIOThread *xen_block_iothread_create(const char *id, static void xen_block_device_create(XenBackendInstance *backend, QDict *opts, Error **errp) { + ERRP_GUARD(); XenBus *xenbus = xen_backend_get_bus(backend); const char *name = xen_backend_get_name(backend); unsigned long number; @@ -883,7 +874,6 @@ static void xen_block_device_create(XenBackendInstance *backend, XenBlockDrive *drive = NULL; XenBlockIOThread *iothread = NULL; XenDevice *xendev = NULL; - Error *local_err = NULL; const char *type; XenBlockDevice *blockdev; @@ -915,16 +905,15 @@ static void xen_block_device_create(XenBackendInstance *backend, goto fail; } - drive = xen_block_drive_create(vdev, device_type, opts, &local_err); + drive = xen_block_drive_create(vdev, device_type, opts, errp); if (!drive) { - error_propagate_prepend(errp, local_err, "failed to create drive: "); + error_prepend(errp, "failed to create drive: "); goto fail; } - iothread = xen_block_iothread_create(vdev, &local_err); - if (local_err) { - error_propagate_prepend(errp, local_err, - "failed to create iothread: "); + iothread = xen_block_iothread_create(vdev, errp); + if (*errp) { + error_prepend(errp, "failed to create iothread: "); goto fail; } @@ -932,32 +921,29 @@ static void xen_block_device_create(XenBackendInstance *backend, blockdev = XEN_BLOCK_DEVICE(xendev); if (!object_property_set_str(OBJECT(xendev), "vdev", vdev, - &local_err)) { - error_propagate_prepend(errp, local_err, "failed to set 'vdev': "); + errp)) { + error_prepend(errp, "failed to set 'vdev': "); goto fail; } if (!object_property_set_str(OBJECT(xendev), "drive", xen_block_drive_get_node_name(drive), - &local_err)) { - error_propagate_prepend(errp, local_err, "failed to set 'drive': "); + errp)) { + error_prepend(errp, "failed to set 'drive': "); goto fail; } if (!object_property_set_str(OBJECT(xendev), "iothread", iothread->id, - &local_err)) { - error_propagate_prepend(errp, local_err, - "failed to set 'iothread': "); + errp)) { + error_prepend(errp, "failed to set 'iothread': "); goto fail; } blockdev->iothread = iothread; blockdev->drive = drive; - if (!qdev_realize_and_unref(DEVICE(xendev), BUS(xenbus), &local_err)) { - error_propagate_prepend(errp, local_err, - "realization of device %s failed: ", - type); + if (!qdev_realize_and_unref(DEVICE(xendev), BUS(xenbus), errp)) { + error_prepend(errp, "realization of device %s failed: ", type); goto fail; } @@ -981,31 +967,29 @@ fail: static void xen_block_device_destroy(XenBackendInstance *backend, Error **errp) { + ERRP_GUARD(); XenDevice *xendev = xen_backend_get_device(backend); XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); XenBlockVdev *vdev = &blockdev->props.vdev; XenBlockDrive *drive = blockdev->drive; XenBlockIOThread *iothread = blockdev->iothread; - Error *local_err = NULL; trace_xen_block_device_destroy(vdev->number); object_unparent(OBJECT(xendev)); if (iothread) { - xen_block_iothread_destroy(iothread, &local_err); - if (local_err) { - error_propagate_prepend(errp, local_err, - "failed to destroy iothread: "); + xen_block_iothread_destroy(iothread, errp); + if (*errp) { + error_prepend(errp, "failed to destroy iothread: "); return; } } if (drive) { - xen_block_drive_destroy(drive, &local_err); - if (local_err) { - error_propagate_prepend(errp, local_err, - "failed to destroy drive: "); + xen_block_drive_destroy(drive, errp); + if (*errp) { + error_prepend(errp, "failed to destroy drive: "); return; } } diff --git a/hw/pci-host/xen_igd_pt.c b/hw/pci-host/xen_igd_pt.c index efcc9347ff..d094b675d6 100644 --- a/hw/pci-host/xen_igd_pt.c +++ b/hw/pci-host/xen_igd_pt.c @@ -79,17 +79,16 @@ static void host_pci_config_read(int pos, int len, uint32_t *val, Error **errp) static void igd_pt_i440fx_realize(PCIDevice *pci_dev, Error **errp) { + ERRP_GUARD(); uint32_t val = 0; size_t i; int pos, len; - Error *local_err = NULL; for (i = 0; i < ARRAY_SIZE(igd_host_bridge_infos); i++) { pos = igd_host_bridge_infos[i].offset; len = igd_host_bridge_infos[i].len; - host_pci_config_read(pos, len, &val, &local_err); - if (local_err) { - error_propagate(errp, local_err); + host_pci_config_read(pos, len, &val, errp); + if (*errp) { return; } pci_default_write_config(pci_dev, pos, val, len); diff --git a/hw/xen/xen-backend.c b/hw/xen/xen-backend.c index da065f81b7..10199fb58d 100644 --- a/hw/xen/xen-backend.c +++ b/hw/xen/xen-backend.c @@ -98,9 +98,9 @@ static void xen_backend_list_remove(XenBackendInstance *backend) void xen_backend_device_create(XenBus *xenbus, const char *type, const char *name, QDict *opts, Error **errp) { + ERRP_GUARD(); const XenBackendImpl *impl = xen_backend_table_lookup(type); XenBackendInstance *backend; - Error *local_error = NULL; if (!impl) { return; @@ -110,9 +110,8 @@ void xen_backend_device_create(XenBus *xenbus, const char *type, backend->xenbus = xenbus; backend->name = g_strdup(name); - impl->create(backend, opts, &local_error); - if (local_error) { - error_propagate(errp, local_error); + impl->create(backend, opts, errp); + if (*errp) { g_free(backend->name); g_free(backend); return; diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index c4e2162ae9..9ce1c9540b 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -53,9 +53,9 @@ static char *xen_device_get_frontend_path(XenDevice *xendev) static void xen_device_unplug(XenDevice *xendev, Error **errp) { + ERRP_GUARD(); XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); const char *type = object_get_typename(OBJECT(xendev)); - Error *local_err = NULL; xs_transaction_t tid; trace_xen_device_unplug(type, xendev->name); @@ -69,14 +69,14 @@ again: } xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online", - &local_err, "%u", 0); - if (local_err) { + errp, "%u", 0); + if (*errp) { goto abort; } xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state", - &local_err, "%u", XenbusStateClosing); - if (local_err) { + errp, "%u", XenbusStateClosing); + if (*errp) { goto abort; } @@ -96,7 +96,6 @@ abort: * from ending the transaction. */ xs_transaction_end(xenbus->xsh, tid, true); - error_propagate(errp, local_err); } static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) @@ -205,15 +204,13 @@ static XenWatch *watch_list_add(XenWatchList *watch_list, const char *node, const char *key, XenWatchHandler handler, void *opaque, Error **errp) { + ERRP_GUARD(); XenWatch *watch = new_watch(node, key, handler, opaque); - Error *local_err = NULL; notifier_list_add(&watch_list->notifiers, &watch->notifier); - xs_node_watch(watch_list->xsh, node, key, watch->token, &local_err); - if (local_err) { - error_propagate(errp, local_err); - + xs_node_watch(watch_list->xsh, node, key, watch->token, errp); + if (*errp) { notifier_remove(&watch->notifier); free_watch(watch); @@ -255,11 +252,11 @@ static void xen_bus_backend_create(XenBus *xenbus, const char *type, const char *name, char *path, Error **errp) { + ERRP_GUARD(); xs_transaction_t tid; char **key; QDict *opts; unsigned int i, n; - Error *local_err = NULL; trace_xen_bus_backend_create(type, path); @@ -314,13 +311,11 @@ again: return; } - xen_backend_device_create(xenbus, type, name, opts, &local_err); + xen_backend_device_create(xenbus, type, name, opts, errp); qobject_unref(opts); - if (local_err) { - error_propagate_prepend(errp, local_err, - "failed to create '%s' device '%s': ", - type, name); + if (*errp) { + error_prepend(errp, "failed to create '%s' device '%s': ", type, name); } } @@ -692,9 +687,9 @@ static void xen_device_remove_watch(XenDevice *xendev, XenWatch *watch, static void xen_device_backend_create(XenDevice *xendev, Error **errp) { + ERRP_GUARD(); XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); struct xs_permissions perms[2]; - Error *local_err = NULL; xendev->backend_path = xen_device_get_backend_path(xendev); @@ -706,30 +701,27 @@ static void xen_device_backend_create(XenDevice *xendev, Error **errp) g_assert(xenbus->xsh); xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms, - ARRAY_SIZE(perms), &local_err); - if (local_err) { - error_propagate_prepend(errp, local_err, - "failed to create backend: "); + ARRAY_SIZE(perms), errp); + if (*errp) { + error_prepend(errp, "failed to create backend: "); return; } xendev->backend_state_watch = 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: "); + errp); + if (*errp) { + error_prepend(errp, "failed to watch backend state: "); return; } xendev->backend_online_watch = 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: "); + errp); + if (*errp) { + error_prepend(errp, "failed to watch backend online: "); return; } } @@ -866,9 +858,9 @@ static bool xen_device_frontend_exists(XenDevice *xendev) static void xen_device_frontend_create(XenDevice *xendev, Error **errp) { + ERRP_GUARD(); XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); struct xs_permissions perms[2]; - Error *local_err = NULL; xendev->frontend_path = xen_device_get_frontend_path(xendev); @@ -885,20 +877,18 @@ static void xen_device_frontend_create(XenDevice *xendev, Error **errp) 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: "); + ARRAY_SIZE(perms), errp); + if (*errp) { + error_prepend(errp, "failed to create frontend: "); return; } } xendev->frontend_state_watch = 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: "); + xen_device_frontend_changed, errp); + if (*errp) { + error_prepend(errp, "failed to watch frontend state: "); } } @@ -1247,11 +1237,11 @@ static void xen_device_exit(Notifier *n, void *data) static void xen_device_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); XenDevice *xendev = XEN_DEVICE(dev); XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); const char *type = object_get_typename(OBJECT(xendev)); - Error *local_err = NULL; if (xendev->frontend_id == DOMID_INVALID) { xendev->frontend_id = xen_domid; @@ -1267,10 +1257,9 @@ static void xen_device_realize(DeviceState *dev, Error **errp) goto unrealize; } - xendev->name = xendev_class->get_name(xendev, &local_err); - if (local_err) { - error_propagate_prepend(errp, local_err, - "failed to get device name: "); + xendev->name = xendev_class->get_name(xendev, errp); + if (*errp) { + error_prepend(errp, "failed to get device name: "); goto unrealize; } @@ -1293,22 +1282,19 @@ static void xen_device_realize(DeviceState *dev, Error **errp) xendev->feature_grant_copy = (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0); - xen_device_backend_create(xendev, &local_err); - if (local_err) { - error_propagate(errp, local_err); + xen_device_backend_create(xendev, errp); + if (*errp) { goto unrealize; } - xen_device_frontend_create(xendev, &local_err); - if (local_err) { - error_propagate(errp, local_err); + xen_device_frontend_create(xendev, errp); + if (*errp) { goto unrealize; } if (xendev_class->realize) { - xendev_class->realize(xendev, &local_err); - if (local_err) { - error_propagate(errp, local_err); + xendev_class->realize(xendev, errp); + if (*errp) { goto unrealize; } } diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c index 1b44dcafaf..8c6e9a1716 100644 --- a/hw/xen/xen-host-pci-device.c +++ b/hw/xen/xen-host-pci-device.c @@ -333,8 +333,8 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain, uint8_t bus, uint8_t dev, uint8_t func, Error **errp) { + ERRP_GUARD(); unsigned int v; - Error *err = NULL; d->config_fd = -1; d->domain = domain; @@ -342,36 +342,36 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain, d->dev = dev; d->func = func; - xen_host_pci_config_open(d, &err); - if (err) { + xen_host_pci_config_open(d, errp); + if (*errp) { goto error; } - xen_host_pci_get_resource(d, &err); - if (err) { + xen_host_pci_get_resource(d, errp); + if (*errp) { goto error; } - xen_host_pci_get_hex_value(d, "vendor", &v, &err); - if (err) { + xen_host_pci_get_hex_value(d, "vendor", &v, errp); + if (*errp) { goto error; } d->vendor_id = v; - xen_host_pci_get_hex_value(d, "device", &v, &err); - if (err) { + xen_host_pci_get_hex_value(d, "device", &v, errp); + if (*errp) { goto error; } d->device_id = v; - xen_host_pci_get_dec_value(d, "irq", &v, &err); - if (err) { + xen_host_pci_get_dec_value(d, "irq", &v, errp); + if (*errp) { goto error; } d->irq = v; - xen_host_pci_get_hex_value(d, "class", &v, &err); - if (err) { + xen_host_pci_get_hex_value(d, "class", &v, errp); + if (*errp) { goto error; } d->class_code = v; @@ -381,7 +381,6 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain, return; error: - error_propagate(errp, err); if (d->config_fd >= 0) { close(d->config_fd); diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index ab84443d5e..6d359ee486 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -777,12 +777,12 @@ static void xen_pt_destroy(PCIDevice *d) { static void xen_pt_realize(PCIDevice *d, Error **errp) { + ERRP_GUARD(); XenPCIPassthroughState *s = XEN_PT_DEVICE(d); int i, rc = 0; uint8_t machine_irq = 0, scratch; uint16_t cmd = 0; int pirq = XEN_PT_UNASSIGNED_PIRQ; - Error *err = NULL; /* register real device */ XEN_PT_LOG(d, "Assigning real physical device %02x:%02x.%d" @@ -793,10 +793,9 @@ static void xen_pt_realize(PCIDevice *d, Error **errp) xen_host_pci_device_get(&s->real_device, s->hostaddr.domain, s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function, - &err); - if (err) { - error_append_hint(&err, "Failed to \"open\" the real pci device"); - error_propagate(errp, err); + errp); + if (*errp) { + error_append_hint(errp, "Failed to \"open\" the real pci device"); return; } @@ -823,11 +822,10 @@ static void xen_pt_realize(PCIDevice *d, Error **errp) return; } - xen_pt_setup_vga(s, &s->real_device, &err); - if (err) { - error_append_hint(&err, "Setup VGA BIOS of passthrough" - " GFX failed"); - error_propagate(errp, err); + xen_pt_setup_vga(s, &s->real_device, errp); + if (*errp) { + error_append_hint(errp, "Setup VGA BIOS of passthrough" + " GFX failed"); xen_host_pci_device_put(&s->real_device); return; } @@ -840,10 +838,9 @@ static void xen_pt_realize(PCIDevice *d, Error **errp) xen_pt_register_regions(s, &cmd); /* reinitialize each config register to be emulated */ - xen_pt_config_init(s, &err); - if (err) { - error_append_hint(&err, "PCI Config space initialisation failed"); - error_propagate(errp, err); + xen_pt_config_init(s, errp); + if (*errp) { + error_append_hint(errp, "PCI Config space initialisation failed"); rc = -1; goto err_out; } diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index d0d7c720a6..c8724cc7c8 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -2008,8 +2008,8 @@ static void xen_pt_config_reg_init(XenPCIPassthroughState *s, void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp) { + ERRP_GUARD(); int i, rc; - Error *err = NULL; QLIST_INIT(&s->reg_grps); @@ -2067,13 +2067,14 @@ void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp) /* initialize capability register */ for (j = 0; regs->size != 0; j++, regs++) { - xen_pt_config_reg_init(s, reg_grp_entry, regs, &err); - if (err) { - error_append_hint(&err, "Failed to init register %d" - " offsets 0x%x in grp_type = 0x%x (%d/%zu)", j, - regs->offset, xen_pt_emu_reg_grps[i].grp_type, - i, ARRAY_SIZE(xen_pt_emu_reg_grps)); - error_propagate(errp, err); + xen_pt_config_reg_init(s, reg_grp_entry, regs, errp); + if (*errp) { + error_append_hint(errp, "Failed to init register %d" + " offsets 0x%x in grp_type = 0x%x (%d/%zu)", + j, + regs->offset, + xen_pt_emu_reg_grps[i].grp_type, + i, ARRAY_SIZE(xen_pt_emu_reg_grps)); xen_pt_config_delete(s); return; } From c8c0d267fd423dcda81fec5dc35ca7a6c3207213 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:07 +0100 Subject: [PATCH 2086/2595] target/avr: Add basic parameters of the new platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This includes definitions of various basic parameters needed for integration of a new platform into QEMU. [AM: Split a larger AVR introduction patch into logical units] Suggested-by: Aleksandar Markovic Co-developed-by: Michael Rolnik Co-developed-by: Sarah Harris Signed-off-by: Michael Rolnik Signed-off-by: Sarah Harris Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Acked-by: Igor Mammedov Tested-by: Philippe Mathieu-Daudé [thuth: Simplify MAINTAINERS right from the start] Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-2-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 6 ++++ target/avr/cpu-param.h | 36 +++++++++++++++++++++++ target/avr/cpu.h | 66 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 target/avr/cpu-param.h create mode 100644 target/avr/cpu.h diff --git a/MAINTAINERS b/MAINTAINERS index 6aa54f7f8f..dda872ef2a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -167,6 +167,12 @@ S: Maintained F: hw/arm/smmu* F: include/hw/arm/smmu* +AVR TCG CPUs +M: Michael Rolnik +R: Sarah Harris +S: Maintained +F: target/avr/ + CRIS TCG CPUs M: Edgar E. Iglesias S: Maintained diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h new file mode 100644 index 0000000000..7ef4e7c679 --- /dev/null +++ b/target/avr/cpu-param.h @@ -0,0 +1,36 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * 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.1 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 + * + */ + +#ifndef AVR_CPU_PARAM_H +#define AVR_CPU_PARAM_H + +#define TARGET_LONG_BITS 32 +/* + * TARGET_PAGE_BITS cannot be more than 8 bits because + * 1. all IO registers occupy [0x0000 .. 0x00ff] address range, and they + * should be implemented as a device and not memory + * 2. SRAM starts at the address 0x0100 + */ +#define TARGET_PAGE_BITS 8 +#define TARGET_PHYS_ADDR_SPACE_BITS 24 +#define TARGET_VIRT_ADDR_SPACE_BITS 24 +#define NB_MMU_MODES 2 + +#endif diff --git a/target/avr/cpu.h b/target/avr/cpu.h new file mode 100644 index 0000000000..45a87c5452 --- /dev/null +++ b/target/avr/cpu.h @@ -0,0 +1,66 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * 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.1 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 + * + */ + +#ifndef QEMU_AVR_CPU_H +#define QEMU_AVR_CPU_H + +#include "exec/cpu-defs.h" + +#define TCG_GUEST_DEFAULT_MO 0 + +/* + * AVR has two memory spaces, data & code. + * e.g. both have 0 address + * ST/LD instructions access data space + * LPM/SPM and instruction fetching access code memory space + */ +#define MMU_CODE_IDX 0 +#define MMU_DATA_IDX 1 + +#define EXCP_RESET 1 +#define EXCP_INT(n) (EXCP_RESET + (n) + 1) + +/* Number of CPU registers */ +#define NUMBER_OF_CPU_REGISTERS 32 +/* Number of IO registers accessible by ld/st/in/out */ +#define NUMBER_OF_IO_REGISTERS 64 + +/* + * Offsets of AVR memory regions in host memory space. + * + * This is needed because the AVR has separate code and data address + * spaces that both have start from zero but have to go somewhere in + * host memory. + * + * It's also useful to know where some things are, like the IO registers. + */ +/* Flash program memory */ +#define OFFSET_CODE 0x00000000 +/* CPU registers, IO registers, and SRAM */ +#define OFFSET_DATA 0x00800000 +/* CPU registers specifically, these are mapped at the start of data */ +#define OFFSET_CPU_REGISTERS OFFSET_DATA +/* + * IO registers, including status register, stack pointer, and memory + * mapped peripherals, mapped just after CPU registers + */ +#define OFFSET_IO_REGISTERS (OFFSET_DATA + NUMBER_OF_CPU_REGISTERS) + +#endif /* !defined (QEMU_AVR_CPU_H) */ From f1c671f96cb34deb28418c1b856f4132a752e87d Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Sun, 26 Jan 2020 19:51:34 +0100 Subject: [PATCH 2087/2595] target/avr: Introduce basic CPU class object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces AVR CPU class object and its basic elements and functions. [AM: Split a larger AVR introduction patch into logical units] Suggested-by: Aleksandar Markovic Co-developed-by: Michael Rolnik Co-developed-by: Sarah Harris Signed-off-by: Michael Rolnik Signed-off-by: Sarah Harris Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Acked-by: Igor Mammedov Tested-by: Philippe Mathieu-Daudé [thuth: Adjusted reset and parent_reset handling] Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-3-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/cpu-qom.h | 53 +++++++++++ target/avr/cpu.c | 207 +++++++++++++++++++++++++++++++++++++++++++ target/avr/cpu.h | 139 +++++++++++++++++++++++++++++ 3 files changed, 399 insertions(+) create mode 100644 target/avr/cpu-qom.h create mode 100644 target/avr/cpu.c diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h new file mode 100644 index 0000000000..d23ad43a99 --- /dev/null +++ b/target/avr/cpu-qom.h @@ -0,0 +1,53 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * 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.1 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 + * + */ + +#ifndef QEMU_AVR_QOM_H +#define QEMU_AVR_QOM_H + +#include "hw/core/cpu.h" + +#define TYPE_AVR_CPU "avr-cpu" + +#define AVR_CPU_CLASS(klass) \ + OBJECT_CLASS_CHECK(AVRCPUClass, (klass), TYPE_AVR_CPU) +#define AVR_CPU(obj) \ + OBJECT_CHECK(AVRCPU, (obj), TYPE_AVR_CPU) +#define AVR_CPU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(AVRCPUClass, (obj), TYPE_AVR_CPU) + +/** + * AVRCPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_reset: The parent class' reset handler. + * @vr: Version Register value. + * + * A AVR CPU model. + */ +typedef struct AVRCPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + DeviceRealize parent_realize; + DeviceReset parent_reset; +} AVRCPUClass; + +typedef struct AVRCPU AVRCPU; + +#endif /* !defined (QEMU_AVR_CPU_QOM_H) */ diff --git a/target/avr/cpu.c b/target/avr/cpu.c new file mode 100644 index 0000000000..6b045f1967 --- /dev/null +++ b/target/avr/cpu.c @@ -0,0 +1,207 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019-2020 Michael Rolnik + * + * 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.1 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 + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/qemu-print.h" +#include "exec/exec-all.h" +#include "cpu.h" +#include "disas/dis-asm.h" + +static void avr_cpu_set_pc(CPUState *cs, vaddr value) +{ + AVRCPU *cpu = AVR_CPU(cs); + + cpu->env.pc_w = value / 2; /* internally PC points to words */ +} + +static bool avr_cpu_has_work(CPUState *cs) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + return (cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_RESET)) + && cpu_interrupts_enabled(env); +} + +static void avr_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + env->pc_w = tb->pc / 2; /* internally PC points to words */ +} + +static void avr_cpu_reset(DeviceState *ds) +{ + CPUState *cs = CPU(ds); + AVRCPU *cpu = AVR_CPU(cs); + AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu); + CPUAVRState *env = &cpu->env; + + mcc->parent_reset(ds); + + env->pc_w = 0; + env->sregI = 1; + env->sregC = 0; + env->sregZ = 0; + env->sregN = 0; + env->sregV = 0; + env->sregS = 0; + env->sregH = 0; + env->sregT = 0; + + env->rampD = 0; + env->rampX = 0; + env->rampY = 0; + env->rampZ = 0; + env->eind = 0; + env->sp = 0; + + env->skip = 0; + + memset(env->r, 0, sizeof(env->r)); + + tlb_flush(cs); +} + +static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) +{ + info->mach = bfd_arch_avr; + info->print_insn = NULL; +} + +static void avr_cpu_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cs = CPU(dev); + AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + qemu_init_vcpu(cs); + cpu_reset(cs); + + mcc->parent_realize(dev, errp); +} + +static void avr_cpu_set_int(void *opaque, int irq, int level) +{ + AVRCPU *cpu = opaque; + CPUAVRState *env = &cpu->env; + CPUState *cs = CPU(cpu); + uint64_t mask = (1ull << irq); + + if (level) { + env->intsrc |= mask; + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + env->intsrc &= ~mask; + if (env->intsrc == 0) { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + } +} + +static void avr_cpu_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + + cpu_set_cpustate_pointers(cpu); + + /* Set the number of interrupts supported by the CPU. */ + qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, + sizeof(cpu->env.intsrc) * 8); +} + +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + + oc = object_class_by_name(cpu_model); + if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) == NULL || + object_class_is_abstract(oc)) { + oc = NULL; + } + return oc; +} + +static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + int i; + + qemu_fprintf(f, "\n"); + qemu_fprintf(f, "PC: %06x\n", env->pc_w); + qemu_fprintf(f, "SP: %04x\n", env->sp); + qemu_fprintf(f, "rampD: %02x\n", env->rampD >> 16); + qemu_fprintf(f, "rampX: %02x\n", env->rampX >> 16); + qemu_fprintf(f, "rampY: %02x\n", env->rampY >> 16); + qemu_fprintf(f, "rampZ: %02x\n", env->rampZ >> 16); + qemu_fprintf(f, "EIND: %02x\n", env->eind >> 16); + qemu_fprintf(f, "X: %02x%02x\n", env->r[27], env->r[26]); + qemu_fprintf(f, "Y: %02x%02x\n", env->r[29], env->r[28]); + qemu_fprintf(f, "Z: %02x%02x\n", env->r[31], env->r[30]); + qemu_fprintf(f, "SREG: [ %c %c %c %c %c %c %c %c ]\n", + env->sregI ? 'I' : '-', + env->sregT ? 'T' : '-', + env->sregH ? 'H' : '-', + env->sregS ? 'S' : '-', + env->sregV ? 'V' : '-', + env->sregN ? '-' : 'N', /* Zf has negative logic */ + env->sregZ ? 'Z' : '-', + env->sregC ? 'I' : '-'); + qemu_fprintf(f, "SKIP: %02x\n", env->skip); + + qemu_fprintf(f, "\n"); + for (i = 0; i < ARRAY_SIZE(env->r); i++) { + qemu_fprintf(f, "R[%02d]: %02x ", i, env->r[i]); + + if ((i % 8) == 7) { + qemu_fprintf(f, "\n"); + } + } + qemu_fprintf(f, "\n"); +} + +static void avr_cpu_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + CPUClass *cc = CPU_CLASS(oc); + AVRCPUClass *mcc = AVR_CPU_CLASS(oc); + + mcc->parent_realize = dc->realize; + dc->realize = avr_cpu_realizefn; + + device_class_set_parent_reset(dc, avr_cpu_reset, &mcc->parent_reset); + + cc->class_by_name = avr_cpu_class_by_name; + + cc->has_work = avr_cpu_has_work; + cc->dump_state = avr_cpu_dump_state; + cc->set_pc = avr_cpu_set_pc; + cc->disas_set_info = avr_cpu_disas_set_info; + cc->tcg_initialize = avr_cpu_tcg_init; + cc->synchronize_from_tb = avr_cpu_synchronize_from_tb; +} diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 45a87c5452..eed56b1ac8 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -21,8 +21,17 @@ #ifndef QEMU_AVR_CPU_H #define QEMU_AVR_CPU_H +#include "cpu-qom.h" #include "exec/cpu-defs.h" +#ifdef CONFIG_USER_ONLY +#error "AVR 8-bit does not support user mode" +#endif + +#define AVR_CPU_TYPE_SUFFIX "-" TYPE_AVR_CPU +#define AVR_CPU_TYPE_NAME(name) (name AVR_CPU_TYPE_SUFFIX) +#define CPU_RESOLVING_TYPE TYPE_AVR_CPU + #define TCG_GUEST_DEFAULT_MO 0 /* @@ -63,4 +72,134 @@ */ #define OFFSET_IO_REGISTERS (OFFSET_DATA + NUMBER_OF_CPU_REGISTERS) +typedef struct CPUAVRState CPUAVRState; + +struct CPUAVRState { + uint32_t pc_w; /* 0x003fffff up to 22 bits */ + + uint32_t sregC; /* 0x00000001 1 bit */ + uint32_t sregZ; /* 0x00000001 1 bit */ + uint32_t sregN; /* 0x00000001 1 bit */ + uint32_t sregV; /* 0x00000001 1 bit */ + uint32_t sregS; /* 0x00000001 1 bit */ + uint32_t sregH; /* 0x00000001 1 bit */ + uint32_t sregT; /* 0x00000001 1 bit */ + uint32_t sregI; /* 0x00000001 1 bit */ + + uint32_t rampD; /* 0x00ff0000 8 bits */ + uint32_t rampX; /* 0x00ff0000 8 bits */ + uint32_t rampY; /* 0x00ff0000 8 bits */ + uint32_t rampZ; /* 0x00ff0000 8 bits */ + uint32_t eind; /* 0x00ff0000 8 bits */ + + uint32_t r[NUMBER_OF_CPU_REGISTERS]; /* 8 bits each */ + uint32_t sp; /* 16 bits */ + + uint32_t skip; /* if set skip instruction */ + + uint64_t intsrc; /* interrupt sources */ + bool fullacc; /* CPU/MEM if true MEM only otherwise */ + + uint64_t features; +}; + +/** + * AVRCPU: + * @env: #CPUAVRState + * + * A AVR CPU. + */ +typedef struct AVRCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + + CPUNegativeOffsetState neg; + CPUAVRState env; +} AVRCPU; + +void avr_cpu_do_interrupt(CPUState *cpu); +bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req); +hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); + +#define cpu_list avr_cpu_list +#define cpu_signal_handler cpu_avr_signal_handler +#define cpu_mmu_index avr_cpu_mmu_index + +static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch) +{ + return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX; +} + +void avr_cpu_tcg_init(void); + +void avr_cpu_list(void); +int cpu_avr_exec(CPUState *cpu); +int cpu_avr_signal_handler(int host_signum, void *pinfo, void *puc); +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf, + int len, bool is_write); + +enum { + TB_FLAGS_FULL_ACCESS = 1, + TB_FLAGS_SKIP = 2, +}; + +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *pflags) +{ + uint32_t flags = 0; + + *pc = env->pc_w * 2; + *cs_base = 0; + + if (env->fullacc) { + flags |= TB_FLAGS_FULL_ACCESS; + } + if (env->skip) { + flags |= TB_FLAGS_SKIP; + } + + *pflags = flags; +} + +static inline int cpu_interrupts_enabled(CPUAVRState *env) +{ + return env->sregI != 0; +} + +static inline uint8_t cpu_get_sreg(CPUAVRState *env) +{ + uint8_t sreg; + sreg = (env->sregC) << 0 + | (env->sregZ) << 1 + | (env->sregN) << 2 + | (env->sregV) << 3 + | (env->sregS) << 4 + | (env->sregH) << 5 + | (env->sregT) << 6 + | (env->sregI) << 7; + return sreg; +} + +static inline void cpu_set_sreg(CPUAVRState *env, uint8_t sreg) +{ + env->sregC = (sreg >> 0) & 0x01; + env->sregZ = (sreg >> 1) & 0x01; + env->sregN = (sreg >> 2) & 0x01; + env->sregV = (sreg >> 3) & 0x01; + env->sregS = (sreg >> 4) & 0x01; + env->sregH = (sreg >> 5) & 0x01; + env->sregT = (sreg >> 6) & 0x01; + env->sregI = (sreg >> 7) & 0x01; +} + +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); + +typedef CPUAVRState CPUArchState; +typedef AVRCPU ArchCPU; + +#include "exec/cpu-all.h" + #endif /* !defined (QEMU_AVR_CPU_H) */ From 7ccda78ff3a1c4d7005eb211207ca11ed719cc11 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 7 Feb 2020 00:20:49 +0100 Subject: [PATCH 2088/2595] target/avr: CPU class: Add interrupt handling support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces functions avr_cpu_do_interrupt() and avr_cpu_exec_interrupt() that are part of AVR CPU class object. [AM: Split a larger AVR introduction patch into logical units] Suggested-by: Aleksandar Markovic Co-developed-by: Michael Rolnik Co-developed-by: Sarah Harris Signed-off-by: Michael Rolnik Signed-off-by: Sarah Harris Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Acked-by: Igor Mammedov Tested-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-4-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/cpu.c | 2 + target/avr/helper.c | 89 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 target/avr/helper.c diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 6b045f1967..854e7ee1ff 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -199,6 +199,8 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) cc->class_by_name = avr_cpu_class_by_name; cc->has_work = avr_cpu_has_work; + cc->do_interrupt = avr_cpu_do_interrupt; + cc->cpu_exec_interrupt = avr_cpu_exec_interrupt; cc->dump_state = avr_cpu_dump_state; cc->set_pc = avr_cpu_set_pc; cc->disas_set_info = avr_cpu_disas_set_info; diff --git a/target/avr/helper.c b/target/avr/helper.c new file mode 100644 index 0000000000..7174e4858e --- /dev/null +++ b/target/avr/helper.c @@ -0,0 +1,89 @@ +/* + * QEMU AVR CPU helpers + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * 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.1 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 + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" + +bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + bool ret = false; + CPUClass *cc = CPU_GET_CLASS(cs); + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + if (interrupt_request & CPU_INTERRUPT_RESET) { + if (cpu_interrupts_enabled(env)) { + cs->exception_index = EXCP_RESET; + cc->do_interrupt(cs); + + cs->interrupt_request &= ~CPU_INTERRUPT_RESET; + + ret = true; + } + } + if (interrupt_request & CPU_INTERRUPT_HARD) { + if (cpu_interrupts_enabled(env) && env->intsrc != 0) { + int index = ctz32(env->intsrc); + cs->exception_index = EXCP_INT(index); + cc->do_interrupt(cs); + + env->intsrc &= env->intsrc - 1; /* clear the interrupt */ + cs->interrupt_request &= ~CPU_INTERRUPT_HARD; + + ret = true; + } + } + return ret; +} + +void avr_cpu_do_interrupt(CPUState *cs) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + uint32_t ret = env->pc_w; + int vector = 0; + int size = avr_feature(env, AVR_FEATURE_JMP_CALL) ? 2 : 1; + int base = 0; + + if (cs->exception_index == EXCP_RESET) { + vector = 0; + } else if (env->intsrc != 0) { + vector = ctz32(env->intsrc) + 1; + } + + if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); + cpu_stb_data(env, env->sp--, (ret & 0xff0000) >> 16); + } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); + } else { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + } + + env->pc_w = base + vector * size; + env->sregI = 0; /* clear Global Interrupt Flag */ + + cs->exception_index = -1; +} From e2a2b0b9187308c450a109ff967f720af4e399e6 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Thu, 6 Feb 2020 23:08:31 +0100 Subject: [PATCH 2089/2595] target/avr: CPU class: Add memory management support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces three memory-management-related functions that will become part of AVR CPU class object. [AM: Split a larger AVR introduction patch into logical units] Suggested-by: Aleksandar Markovic Co-developed-by: Michael Rolnik Co-developed-by: Sarah Harris Signed-off-by: Michael Rolnik Signed-off-by: Sarah Harris Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Acked-by: Igor Mammedov Tested-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-5-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/cpu.c | 3 +++ target/avr/helper.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 854e7ee1ff..6c68e6e4ab 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -203,6 +203,9 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) cc->cpu_exec_interrupt = avr_cpu_exec_interrupt; cc->dump_state = avr_cpu_dump_state; cc->set_pc = avr_cpu_set_pc; + cc->memory_rw_debug = avr_cpu_memory_rw_debug; + cc->get_phys_page_debug = avr_cpu_get_phys_page_debug; + cc->tlb_fill = avr_cpu_tlb_fill; cc->disas_set_info = avr_cpu_disas_set_info; cc->tcg_initialize = avr_cpu_tcg_init; cc->synchronize_from_tb = avr_cpu_synchronize_from_tb; diff --git a/target/avr/helper.c b/target/avr/helper.c index 7174e4858e..d6985ff3f4 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -87,3 +87,53 @@ void avr_cpu_do_interrupt(CPUState *cs) cs->exception_index = -1; } + +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, + int len, bool is_write) +{ + return cpu_memory_rw_debug(cs, addr, buf, len, is_write); +} + +hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + return addr; /* I assume 1:1 address correspondance */ +} + +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + int prot = 0; + MemTxAttrs attrs = {}; + uint32_t paddr; + + address &= TARGET_PAGE_MASK; + + if (mmu_idx == MMU_CODE_IDX) { + /* access to code in flash */ + paddr = OFFSET_CODE + address; + prot = PAGE_READ | PAGE_EXEC; + if (paddr + TARGET_PAGE_SIZE > OFFSET_DATA) { + error_report("execution left flash memory"); + abort(); + } + } else if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { + /* + * access to CPU registers, exit and rebuilt this TB to use full access + * incase it touches specially handled registers like SREG or SP + */ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + env->fullacc = 1; + cpu_loop_exit_restore(cs, retaddr); + } else { + /* access to memory. nothing special */ + paddr = OFFSET_DATA + address; + prot = PAGE_READ | PAGE_WRITE; + } + + tlb_set_page_with_attrs(cs, address, paddr, attrs, prot, + mmu_idx, TARGET_PAGE_SIZE); + + return true; +} From 3fa28dd6cf848c5f7fddba84a6d7789027c58a25 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Sun, 26 Jan 2020 19:12:14 +0100 Subject: [PATCH 2090/2595] target/avr: CPU class: Add migration support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add migration-related functions of AVR CPU class object. [AM: Split a larger AVR introduction patch into logical units] Suggested-by: Aleksandar Markovic Co-developed-by: Michael Rolnik Co-developed-by: Sarah Harris Signed-off-by: Michael Rolnik Signed-off-by: Sarah Harris Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Acked-by: Igor Mammedov Tested-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-6-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/cpu.c | 1 + target/avr/cpu.h | 2 + target/avr/machine.c | 119 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 target/avr/machine.c diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 6c68e6e4ab..be06875225 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -206,6 +206,7 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) cc->memory_rw_debug = avr_cpu_memory_rw_debug; cc->get_phys_page_debug = avr_cpu_get_phys_page_debug; cc->tlb_fill = avr_cpu_tlb_fill; + cc->vmsd = &vms_avr_cpu; cc->disas_set_info = avr_cpu_disas_set_info; cc->tcg_initialize = avr_cpu_tcg_init; cc->synchronize_from_tb = avr_cpu_synchronize_from_tb; diff --git a/target/avr/cpu.h b/target/avr/cpu.h index eed56b1ac8..99875e50b1 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -118,6 +118,8 @@ typedef struct AVRCPU { CPUAVRState env; } AVRCPU; +extern const struct VMStateDescription vms_avr_cpu; + void avr_cpu_do_interrupt(CPUState *cpu); bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req); hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); diff --git a/target/avr/machine.c b/target/avr/machine.c new file mode 100644 index 0000000000..e315442787 --- /dev/null +++ b/target/avr/machine.c @@ -0,0 +1,119 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * 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.1 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 + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "migration/cpu.h" + +static int get_sreg(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field) +{ + CPUAVRState *env = opaque; + uint8_t sreg; + + sreg = qemu_get_byte(f); + cpu_set_sreg(env, sreg); + return 0; +} + +static int put_sreg(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field, QJSON *vmdesc) +{ + CPUAVRState *env = opaque; + uint8_t sreg = cpu_get_sreg(env); + + qemu_put_byte(f, sreg); + return 0; +} + +static const VMStateInfo vms_sreg = { + .name = "sreg", + .get = get_sreg, + .put = put_sreg, +}; + +static int get_segment(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field) +{ + uint32_t *ramp = opaque; + uint8_t temp; + + temp = qemu_get_byte(f); + *ramp = ((uint32_t)temp) << 16; + return 0; +} + +static int put_segment(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field, QJSON *vmdesc) +{ + uint32_t *ramp = opaque; + uint8_t temp = *ramp >> 16; + + qemu_put_byte(f, temp); + return 0; +} + +static const VMStateInfo vms_rampD = { + .name = "rampD", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_rampX = { + .name = "rampX", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_rampY = { + .name = "rampY", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_rampZ = { + .name = "rampZ", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_eind = { + .name = "eind", + .get = get_segment, + .put = put_segment, +}; + +const VMStateDescription vms_avr_cpu = { + .name = "cpu", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(env.pc_w, AVRCPU), + VMSTATE_UINT32(env.sp, AVRCPU), + VMSTATE_UINT32(env.skip, AVRCPU), + + VMSTATE_UINT32_ARRAY(env.r, AVRCPU, NUMBER_OF_CPU_REGISTERS), + + VMSTATE_SINGLE(env, AVRCPU, 0, vms_sreg, CPUAVRState), + VMSTATE_SINGLE(env.rampD, AVRCPU, 0, vms_rampD, uint32_t), + VMSTATE_SINGLE(env.rampX, AVRCPU, 0, vms_rampX, uint32_t), + VMSTATE_SINGLE(env.rampY, AVRCPU, 0, vms_rampY, uint32_t), + VMSTATE_SINGLE(env.rampZ, AVRCPU, 0, vms_rampZ, uint32_t), + VMSTATE_SINGLE(env.eind, AVRCPU, 0, vms_eind, uint32_t), + + VMSTATE_END_OF_LIST() + } +}; From 12b35405476fa7f733538ec6bb3ffc91129c0555 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Sun, 26 Jan 2020 18:52:23 +0100 Subject: [PATCH 2091/2595] target/avr: CPU class: Add GDB support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This includes GDB hooks for reading from wnd wrtiting to AVR registers, and xml register definition file as well. [AM: Split a larger AVR introduction patch into logical units] Suggested-by: Aleksandar Markovic Co-developed-by: Michael Rolnik Co-developed-by: Sarah Harris Signed-off-by: Michael Rolnik Signed-off-by: Sarah Harris Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Acked-by: Igor Mammedov Tested-by: Philippe Mathieu-Daudé [thuth: Fixed avr_cpu_gdb_read_register() parameter] Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-7-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 1 + gdb-xml/avr-cpu.xml | 49 ++++++++++++++++++++++++++ target/avr/cpu.c | 4 +++ target/avr/cpu.h | 2 ++ target/avr/gdbstub.c | 84 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+) create mode 100644 gdb-xml/avr-cpu.xml create mode 100644 target/avr/gdbstub.c diff --git a/MAINTAINERS b/MAINTAINERS index dda872ef2a..7833db3abe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -171,6 +171,7 @@ AVR TCG CPUs M: Michael Rolnik R: Sarah Harris S: Maintained +F: gdb-xml/avr-cpu.xml F: target/avr/ CRIS TCG CPUs diff --git a/gdb-xml/avr-cpu.xml b/gdb-xml/avr-cpu.xml new file mode 100644 index 0000000000..c4747f5b40 --- /dev/null +++ b/gdb-xml/avr-cpu.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/target/avr/cpu.c b/target/avr/cpu.c index be06875225..05dd5551c7 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -210,4 +210,8 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) cc->disas_set_info = avr_cpu_disas_set_info; cc->tcg_initialize = avr_cpu_tcg_init; cc->synchronize_from_tb = avr_cpu_synchronize_from_tb; + cc->gdb_read_register = avr_cpu_gdb_read_register; + cc->gdb_write_register = avr_cpu_gdb_write_register; + cc->gdb_num_core_regs = 35; + cc->gdb_core_xml_file = "avr-cpu.xml"; } diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 99875e50b1..8d99122804 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -123,6 +123,8 @@ extern const struct VMStateDescription vms_avr_cpu; void avr_cpu_do_interrupt(CPUState *cpu); bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req); hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int avr_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); +int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #define cpu_list avr_cpu_list #define cpu_signal_handler cpu_avr_signal_handler diff --git a/target/avr/gdbstub.c b/target/avr/gdbstub.c new file mode 100644 index 0000000000..c28ed67efe --- /dev/null +++ b/target/avr/gdbstub.c @@ -0,0 +1,84 @@ +/* + * QEMU AVR gdbstub + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * 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.1 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 + * + */ + +#include "qemu/osdep.h" +#include "exec/gdbstub.h" + +int avr_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + /* R */ + if (n < 32) { + return gdb_get_reg8(mem_buf, env->r[n]); + } + + /* SREG */ + if (n == 32) { + uint8_t sreg = cpu_get_sreg(env); + + return gdb_get_reg8(mem_buf, sreg); + } + + /* SP */ + if (n == 33) { + return gdb_get_reg16(mem_buf, env->sp & 0x0000ffff); + } + + /* PC */ + if (n == 34) { + return gdb_get_reg32(mem_buf, env->pc_w * 2); + } + + return 0; +} + +int avr_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + /* R */ + if (n < 32) { + env->r[n] = *mem_buf; + return 1; + } + + /* SREG */ + if (n == 32) { + cpu_set_sreg(env, *mem_buf); + return 1; + } + + /* SP */ + if (n == 33) { + env->sp = lduw_p(mem_buf); + return 2; + } + + /* PC */ + if (n == 34) { + env->pc_w = ldl_p(mem_buf) / 2; + return 4; + } + + return 0; +} From 25a08409ab449fe9666e3dc15fe87b2a8e5bb979 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Sun, 26 Jan 2020 19:32:33 +0100 Subject: [PATCH 2092/2595] target/avr: Introduce enumeration AVRFeature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces enumeration "AVRFeature" that will be used for defining various AVR core types. [AM: Split a larger AVR introduction patch into logical units] Suggested-by: Aleksandar Markovic Co-developed-by: Michael Rolnik Co-developed-by: Sarah Harris Signed-off-by: Michael Rolnik Signed-off-by: Sarah Harris Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Acked-by: Igor Mammedov Tested-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-8-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/cpu.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 8d99122804..d2c2e40c19 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -72,6 +72,42 @@ */ #define OFFSET_IO_REGISTERS (OFFSET_DATA + NUMBER_OF_CPU_REGISTERS) +typedef enum AVRFeature { + AVR_FEATURE_SRAM, + + AVR_FEATURE_1_BYTE_PC, + AVR_FEATURE_2_BYTE_PC, + AVR_FEATURE_3_BYTE_PC, + + AVR_FEATURE_1_BYTE_SP, + AVR_FEATURE_2_BYTE_SP, + + AVR_FEATURE_BREAK, + AVR_FEATURE_DES, + AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */ + + AVR_FEATURE_EIJMP_EICALL, + AVR_FEATURE_IJMP_ICALL, + AVR_FEATURE_JMP_CALL, + + AVR_FEATURE_ADIW_SBIW, + + AVR_FEATURE_SPM, + AVR_FEATURE_SPMX, + + AVR_FEATURE_ELPMX, + AVR_FEATURE_ELPM, + AVR_FEATURE_LPMX, + AVR_FEATURE_LPM, + + AVR_FEATURE_MOVW, + AVR_FEATURE_MUL, + AVR_FEATURE_RAMPD, + AVR_FEATURE_RAMPX, + AVR_FEATURE_RAMPY, + AVR_FEATURE_RAMPZ, +} AVRFeature; + typedef struct CPUAVRState CPUAVRState; struct CPUAVRState { @@ -126,6 +162,16 @@ hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int avr_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +static inline int avr_feature(CPUAVRState *env, AVRFeature feature) +{ + return (env->features & (1U << feature)) != 0; +} + +static inline void set_avr_feature(CPUAVRState *env, int feature) +{ + env->features |= (1U << feature); +} + #define cpu_list avr_cpu_list #define cpu_signal_handler cpu_avr_signal_handler #define cpu_mmu_index avr_cpu_mmu_index From 669d27e2f57a5c016caebf859196ec77c420a330 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Sun, 26 Jan 2020 18:34:33 +0100 Subject: [PATCH 2093/2595] target/avr: Add definitions of AVR core types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AVR core types are: - avr5 - avr51 - avr6 Each core type covers multiple AVR MCUs, mentioned in the comments before definition of particular AVR core type (part of this patch). AVR core type defines shared features that are valid for all AVR MCUs belonging in that type. [AM: Split a larger AVR introduction patch into logical units] Suggested-by: Aleksandar Markovic Co-developed-by: Michael Rolnik Co-developed-by: Sarah Harris Signed-off-by: Michael Rolnik Signed-off-by: Sarah Harris Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Acked-by: Igor Mammedov Tested-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-9-huth@tuxfamily.org> [PMD: Only include reviewed cores: avr5/avr51/avr6] Signed-off-by: Philippe Mathieu-Daudé --- target/avr/cpu.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 05dd5551c7..b20a116892 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -215,3 +215,154 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_num_core_regs = 35; cc->gdb_core_xml_file = "avr-cpu.xml"; } + +/* + * Setting features of AVR core type avr5 + * -------------------------------------- + * + * This type of AVR core is present in the following AVR MCUs: + * + * ata5702m322, ata5782, ata5790, ata5790n, ata5791, ata5795, ata5831, ata6613c, + * ata6614q, ata8210, ata8510, atmega16, atmega16a, atmega161, atmega162, + * atmega163, atmega164a, atmega164p, atmega164pa, atmega165, atmega165a, + * atmega165p, atmega165pa, atmega168, atmega168a, atmega168p, atmega168pa, + * atmega168pb, atmega169, atmega169a, atmega169p, atmega169pa, atmega16hvb, + * atmega16hvbrevb, atmega16m1, atmega16u4, atmega32a, atmega32, atmega323, + * atmega324a, atmega324p, atmega324pa, atmega325, atmega325a, atmega325p, + * atmega325pa, atmega3250, atmega3250a, atmega3250p, atmega3250pa, atmega328, + * atmega328p, atmega328pb, atmega329, atmega329a, atmega329p, atmega329pa, + * atmega3290, atmega3290a, atmega3290p, atmega3290pa, atmega32c1, atmega32m1, + * atmega32u4, atmega32u6, atmega406, atmega64, atmega64a, atmega640, atmega644, + * atmega644a, atmega644p, atmega644pa, atmega645, atmega645a, atmega645p, + * atmega6450, atmega6450a, atmega6450p, atmega649, atmega649a, atmega649p, + * atmega6490, atmega16hva, atmega16hva2, atmega32hvb, atmega6490a, atmega6490p, + * atmega64c1, atmega64m1, atmega64hve, atmega64hve2, atmega64rfr2, + * atmega644rfr2, atmega32hvbrevb, at90can32, at90can64, at90pwm161, at90pwm216, + * at90pwm316, at90scr100, at90usb646, at90usb647, at94k, m3000 + */ +static void avr_avr5_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + CPUAVRState *env = &cpu->env; + + set_avr_feature(env, AVR_FEATURE_LPM); + set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); + set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); + set_avr_feature(env, AVR_FEATURE_SRAM); + set_avr_feature(env, AVR_FEATURE_BREAK); + + set_avr_feature(env, AVR_FEATURE_2_BYTE_PC); + set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); + set_avr_feature(env, AVR_FEATURE_JMP_CALL); + set_avr_feature(env, AVR_FEATURE_LPMX); + set_avr_feature(env, AVR_FEATURE_MOVW); + set_avr_feature(env, AVR_FEATURE_MUL); +} + +/* + * Setting features of AVR core type avr51 + * -------------------------------------- + * + * This type of AVR core is present in the following AVR MCUs: + * + * atmega128, atmega128a, atmega1280, atmega1281, atmega1284, atmega1284p, + * atmega128rfa1, atmega128rfr2, atmega1284rfr2, at90can128, at90usb1286, + * at90usb1287 + */ +static void avr_avr51_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + CPUAVRState *env = &cpu->env; + + set_avr_feature(env, AVR_FEATURE_LPM); + set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); + set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); + set_avr_feature(env, AVR_FEATURE_SRAM); + set_avr_feature(env, AVR_FEATURE_BREAK); + + set_avr_feature(env, AVR_FEATURE_2_BYTE_PC); + set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); + set_avr_feature(env, AVR_FEATURE_RAMPZ); + set_avr_feature(env, AVR_FEATURE_ELPMX); + set_avr_feature(env, AVR_FEATURE_ELPM); + set_avr_feature(env, AVR_FEATURE_JMP_CALL); + set_avr_feature(env, AVR_FEATURE_LPMX); + set_avr_feature(env, AVR_FEATURE_MOVW); + set_avr_feature(env, AVR_FEATURE_MUL); +} + +/* + * Setting features of AVR core type avr6 + * -------------------------------------- + * + * This type of AVR core is present in the following AVR MCUs: + * + * atmega2560, atmega2561, atmega256rfr2, atmega2564rfr2 + */ +static void avr_avr6_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + CPUAVRState *env = &cpu->env; + + set_avr_feature(env, AVR_FEATURE_LPM); + set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); + set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); + set_avr_feature(env, AVR_FEATURE_SRAM); + set_avr_feature(env, AVR_FEATURE_BREAK); + + set_avr_feature(env, AVR_FEATURE_3_BYTE_PC); + set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); + set_avr_feature(env, AVR_FEATURE_RAMPZ); + set_avr_feature(env, AVR_FEATURE_EIJMP_EICALL); + set_avr_feature(env, AVR_FEATURE_ELPMX); + set_avr_feature(env, AVR_FEATURE_ELPM); + set_avr_feature(env, AVR_FEATURE_JMP_CALL); + set_avr_feature(env, AVR_FEATURE_LPMX); + set_avr_feature(env, AVR_FEATURE_MOVW); + set_avr_feature(env, AVR_FEATURE_MUL); +} + +typedef struct AVRCPUInfo { + const char *name; + void (*initfn)(Object *obj); +} AVRCPUInfo; + + +static void avr_cpu_list_entry(gpointer data, gpointer user_data) +{ + const char *typename = object_class_get_name(OBJECT_CLASS(data)); + + qemu_printf("%s\n", typename); +} + +void avr_cpu_list(void) +{ + GSList *list; + list = object_class_get_list_sorted(TYPE_AVR_CPU, false); + g_slist_foreach(list, avr_cpu_list_entry, NULL); + g_slist_free(list); +} + +#define DEFINE_AVR_CPU_TYPE(model, initfn) \ + { \ + .parent = TYPE_AVR_CPU, \ + .instance_init = initfn, \ + .name = AVR_CPU_TYPE_NAME(model), \ + } + +static const TypeInfo avr_cpu_type_info[] = { + { + .name = TYPE_AVR_CPU, + .parent = TYPE_CPU, + .instance_size = sizeof(AVRCPU), + .instance_init = avr_cpu_initfn, + .class_size = sizeof(AVRCPUClass), + .class_init = avr_cpu_class_init, + .abstract = true, + }, + DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn), + DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn), + DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn), +}; + +DEFINE_TYPES(avr_cpu_type_info) From a2d57703b3e735c700689b030c126fa8ba6793b9 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Mon, 29 Jun 2020 15:25:03 +0200 Subject: [PATCH 2094/2595] tcg/svm: use host cr4 during NPT page table walk During a page table walk of TCG+SVM the code in target/i386/excp_helper.c get_hphys() uses the cr4 register of the guest instead of the hypervisor to check for the PSE bit. In the test case we have, the guest have not enabled (yet) the PSE bit and so the page table walk results in a wrong host physical address resolution and wrong content read by the guest. Attached patch is against 4.2.1, but works also on 3.1.0. It fixes the issue for our automated testcase, which is a 32bit hypervisor w/o PAE support running a guest VM with tcg+svm. The test worked beforehand up to qemu 2.12, started to fail with qemu 3.0 and later. The added TCG/SVM NPT commit seems to introduce the regression. In case someone want to try to reproduce it, the iso is at [0], the good case is [1] and the failing case is [2]. The used commandline is: qemu-system-i386 -no-kvm -nographic -cpu phenom -m 512 -machine q35 -cdrom seoul-vmm-test.iso [0] https://depot.genode.org/alex-ab/images/seoul-vmm-test.iso [1] https://depot.genode.org/alex-ab/images/seoul-vmm-good.txt [2] https://depot.genode.org/alex-ab/images/seoul-vmm-bad.txt Signed-off-by: Alexander Boettcher Signed-off-by: Paolo Bonzini --- target/i386/excp_helper.c | 4 ++-- target/i386/svm.h | 1 + target/i386/svm_helper.c | 7 ++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/target/i386/excp_helper.c b/target/i386/excp_helper.c index 1447bda7a9..b10c7ecbcc 100644 --- a/target/i386/excp_helper.c +++ b/target/i386/excp_helper.c @@ -262,8 +262,8 @@ static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, } ptep = pde | PG_NX_MASK; - /* if PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + /* if host cr4 PSE bit is set, then we use a 4MB page */ + if ((pde & PG_PSE_MASK) && (env->nested_pg_mode & SVM_NPT_PSE)) { page_size = 4096 * 1024; pte_addr = pde_addr; diff --git a/target/i386/svm.h b/target/i386/svm.h index 23a3a040b8..ae30fc6f79 100644 --- a/target/i386/svm.h +++ b/target/i386/svm.h @@ -135,6 +135,7 @@ #define SVM_NPT_PAE (1 << 0) #define SVM_NPT_LMA (1 << 1) #define SVM_NPT_NXE (1 << 2) +#define SVM_NPT_PSE (1 << 3) #define SVM_NPTEXIT_P (1ULL << 0) #define SVM_NPTEXIT_RW (1ULL << 1) diff --git a/target/i386/svm_helper.c b/target/i386/svm_helper.c index 7b8105a1c3..6224387eab 100644 --- a/target/i386/svm_helper.c +++ b/target/i386/svm_helper.c @@ -209,16 +209,21 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) nested_ctl = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.nested_ctl)); + + env->nested_pg_mode = 0; + if (nested_ctl & SVM_NPT_ENABLED) { env->nested_cr3 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.nested_cr3)); env->hflags2 |= HF2_NPT_MASK; - env->nested_pg_mode = 0; if (env->cr[4] & CR4_PAE_MASK) { env->nested_pg_mode |= SVM_NPT_PAE; } + if (env->cr[4] & CR4_PSE_MASK) { + env->nested_pg_mode |= SVM_NPT_PSE; + } if (env->hflags & HF_LMA_MASK) { env->nested_pg_mode |= SVM_NPT_LMA; } From 3bcb5840f1b3ef9970da963bf94f637b665387ef Mon Sep 17 00:00:00 2001 From: Havard Skinnemoen Date: Sun, 28 Jun 2020 14:30:46 -0700 Subject: [PATCH 2095/2595] tests: Inject test name also when the test fails If a test is unsuccessful, the result is "not ok", which does not match the regex because it includes a space. This regex matches both "ok" and "not ok". Signed-off-by: Havard Skinnemoen Message-Id: <20200628213046.2028271-1-hskinnemoen@google.com> Signed-off-by: Paolo Bonzini --- tests/Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 3f4448a20b..09df2d3f86 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -637,7 +637,7 @@ define do_test_tap { export MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$(( $${RANDOM:-0} % 255 + 1))} $2; \ $(foreach COMMAND, $1, \ $(COMMAND) -m=$(SPEED) -k --tap < /dev/null \ - | sed "s/^[a-z][a-z]* [0-9]* /&$(notdir $(COMMAND)) /" || true; ) } \ + | sed "s/^\(not \)\?ok [0-9]* /&$(notdir $(COMMAND)) /" || true; ) } \ | ./scripts/tap-merge.pl | tee "$@" \ | ./scripts/tap-driver.pl $(if $(V),, --show-failures-only), \ "TAP","$@") From 2880ffb08995238714b175db703c13fac4725cc1 Mon Sep 17 00:00:00 2001 From: Mario Smarduch Date: Fri, 26 Jun 2020 13:19:00 -0700 Subject: [PATCH 2096/2595] util/qemu-error: prepend guest name to error message to identify affected VM owner This is followup patch to the one submitted back in Oct, 19 https://lists.gnu.org/archive/html/qemu-devel/2019-10/msg02102.html My mistake here, I took my eyes of the mailing list after I got the initial thumbs up. This patch follows up on Markus comments in the above link. Purpose of this patch: We want to print guest name for errors, warnings and info messages. This was the first of two patches the second being MCE errors targeting a VM with guest name prepended. But in a large fleet we see many other errors that disable a VM or crash it. In a large fleet and centralized logging having the guest name enables identify of owner and customer. Signed-off-by: Mario Smarduch Message-Id: <20200626201900.8876-1-msmarduch@digitalocean.com> Signed-off-by: Paolo Bonzini --- include/qemu/error-report.h | 2 ++ qemu-options.hx | 12 +++++++++--- softmmu/vl.c | 9 +++++++++ util/qemu-error.c | 7 +++++++ 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/include/qemu/error-report.h b/include/qemu/error-report.h index 87532d8596..a5ad95ff1b 100644 --- a/include/qemu/error-report.h +++ b/include/qemu/error-report.h @@ -75,5 +75,7 @@ void error_init(const char *argv0); const char *error_get_progname(void); extern bool error_with_timestamp; +extern bool error_with_guestname; +extern const char *error_guest_name; #endif diff --git a/qemu-options.hx b/qemu-options.hx index c6edb4047b..d2c1e95bcf 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4303,16 +4303,22 @@ HXCOMM Deprecated by -accel tcg DEF("no-kvm", 0, QEMU_OPTION_no_kvm, "", QEMU_ARCH_I386) DEF("msg", HAS_ARG, QEMU_OPTION_msg, - "-msg timestamp[=on|off]\n" + "-msg [timestamp[=on|off]][,guest-name=[on|off]]\n" " control error message format\n" - " timestamp=on enables timestamps (default: off)\n", + " timestamp=on enables timestamps (default: off)\n" + " guest-name=on enables guest name prefix but only if\n" + " -name guest option is set (default: off)\n", QEMU_ARCH_ALL) SRST -``-msg timestamp[=on|off]`` +``-msg [timestamp[=on|off]][,guest-name[=on|off]]`` Control error message format. ``timestamp=on|off`` Prefix messages with a timestamp. Default is off. + + ``guest-name=on|off`` + Prefix messages with guest name but only if -name guest option is set + otherwise the option is ignored. Default is off. ERST DEF("dump-vmstate", HAS_ARG, QEMU_OPTION_dump_vmstate, diff --git a/softmmu/vl.c b/softmmu/vl.c index 96417a7c3a..a7a2e9e44a 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -389,6 +389,12 @@ static QemuOptsList qemu_msg_opts = { .name = "timestamp", .type = QEMU_OPT_BOOL, }, + { + .name = "guest-name", + .type = QEMU_OPT_BOOL, + .help = "Prepends guest name for error messages but only if " + "-name guest is set otherwise option is ignored\n", + }, { /* end of list */ } }, }; @@ -1114,6 +1120,7 @@ static void realtime_init(void) static void configure_msg(QemuOpts *opts) { error_with_timestamp = qemu_opt_get_bool(opts, "timestamp", false); + error_with_guestname = qemu_opt_get_bool(opts, "guest-name", false); } @@ -3592,6 +3599,8 @@ void qemu_init(int argc, char **argv, char **envp) if (!opts) { exit(1); } + /* Capture guest name if -msg guest-name is used later */ + error_guest_name = qemu_opt_get(opts, "guest"); break; case QEMU_OPTION_prom_env: if (nb_prom_envs >= MAX_PROM_ENVS) { diff --git a/util/qemu-error.c b/util/qemu-error.c index dac7c7dc50..3ee41438e9 100644 --- a/util/qemu-error.c +++ b/util/qemu-error.c @@ -26,6 +26,8 @@ typedef enum { /* Prepend timestamp to messages */ bool error_with_timestamp; +bool error_with_guestname; +const char *error_guest_name; int error_printf(const char *fmt, ...) { @@ -213,6 +215,11 @@ static void vreport(report_type type, const char *fmt, va_list ap) g_free(timestr); } + /* Only prepend guest name if -msg guest-name and -name guest=... are set */ + if (error_with_guestname && error_guest_name && !cur_mon) { + error_printf("%s ", error_guest_name); + } + print_loc(); switch (type) { From db57fef1e285a1f56a2d99b83456abf2f0b86e96 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 29 Jun 2020 21:34:22 +0200 Subject: [PATCH 2097/2595] qom: Introduce object_property_try_add_child() object_property_add() does not allow object_property_try_add() to gracefully fail as &error_abort is passed as an error handle. However such failure can easily be triggered from the QMP shell when, for instance, one attempts to create an object with an id that already exists. This is achieved from the following call path: qmp_object_add -> user_creatable_add_dict -> user_creatable_add_type -> object_property_add_child -> object_property_add For instance, from the qmp-shell, call twice: object-add qom-type=memory-backend-ram id=mem1 props.size=1073741824 and QEMU aborts. This behavior is undesired as a user/management application mistake in reusing a property ID shouldn't result in loss of the VM and live data within. This patch introduces a new function, object_property_try_add_child() which takes an error handle and turn object_property_try_add() into a non-static one. Now the call path becomes: user_creatable_add_type -> object_property_try_add_child -> object_property_try_add and the error is returned gracefully to the QMP client. (QEMU) object-add qom-type=memory-backend-ram id=mem2 props.size=4294967296 {"return": {}} (QEMU) object-add qom-type=memory-backend-ram id=mem2 props.size=4294967296 {"error": {"class": "GenericError", "desc": "attempt to add duplicate property 'mem2' to object (type 'container')"}} Signed-off-by: Eric Auger Fixes: d2623129a7de ("qom: Drop parameter @errp of object_property_add() & friends") Reviewed-by: Markus Armbruster Reviewed-by: Greg Kurz Tested-by: Greg Kurz Message-Id: <20200629193424.30280-2-eric.auger@redhat.com> Signed-off-by: Paolo Bonzini --- include/qom/object.h | 26 ++++++++++++++++++++++++-- qom/object.c | 21 ++++++++++++++++----- qom/object_interfaces.c | 7 +++++-- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 10fd4a2d4c..79c8f838b6 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1047,7 +1047,7 @@ Object *object_ref(Object *obj); void object_unref(Object *obj); /** - * object_property_add: + * object_property_try_add: * @obj: the object to add a property to * @name: the name of the property. This can contain any character except for * a forward slash. In general, you should use hyphens '-' instead of @@ -1064,10 +1064,23 @@ void object_unref(Object *obj); * meant to allow a property to free its opaque upon object * destruction. This may be NULL. * @opaque: an opaque pointer to pass to the callbacks for the property + * @errp: pointer to error object * * Returns: The #ObjectProperty; this can be used to set the @resolve * callback for child and link properties. */ +ObjectProperty *object_property_try_add(Object *obj, const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp); + +/** + * object_property_add: + * Same as object_property_try_add() with @errp hardcoded to + * &error_abort. + */ ObjectProperty *object_property_add(Object *obj, const char *name, const char *type, ObjectPropertyAccessor *get, @@ -1518,10 +1531,11 @@ Object *object_resolve_path_type(const char *path, const char *typename, Object *object_resolve_path_component(Object *parent, const char *part); /** - * object_property_add_child: + * object_property_try_add_child: * @obj: the object to add a property to * @name: the name of the property * @child: the child object + * @errp: pointer to error object * * Child properties form the composition tree. All objects need to be a child * of another object. Objects can only be a child of one object. @@ -1535,6 +1549,14 @@ Object *object_resolve_path_component(Object *parent, const char *part); * * Returns: The newly added property on success, or %NULL on failure. */ +ObjectProperty *object_property_try_add_child(Object *obj, const char *name, + Object *child, Error **errp); + +/** + * object_property_add_child: + * Same as object_property_try_add_child() with @errp hardcoded to + * &error_abort + */ ObjectProperty *object_property_add_child(Object *obj, const char *name, Object *child); diff --git a/qom/object.c b/qom/object.c index 4c91de8183..76f5f75239 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1146,7 +1146,7 @@ void object_unref(Object *obj) } } -static ObjectProperty * +ObjectProperty * object_property_try_add(Object *obj, const char *name, const char *type, ObjectPropertyAccessor *get, ObjectPropertyAccessor *set, @@ -1675,8 +1675,8 @@ static void object_finalize_child_property(Object *obj, const char *name, } ObjectProperty * -object_property_add_child(Object *obj, const char *name, - Object *child) +object_property_try_add_child(Object *obj, const char *name, + Object *child, Error **errp) { g_autofree char *type = NULL; ObjectProperty *op; @@ -1685,14 +1685,25 @@ object_property_add_child(Object *obj, const char *name, type = g_strdup_printf("child<%s>", object_get_typename(child)); - op = object_property_add(obj, name, type, object_get_child_property, NULL, - object_finalize_child_property, child); + op = object_property_try_add(obj, name, type, object_get_child_property, + NULL, object_finalize_child_property, + child, errp); + if (!op) { + return NULL; + } op->resolve = object_resolve_child_property; object_ref(child); child->parent = obj; return op; } +ObjectProperty * +object_property_add_child(Object *obj, const char *name, + Object *child) +{ + return object_property_try_add_child(obj, name, child, &error_abort); +} + void object_property_allow_set_link(const Object *obj, const char *name, Object *val, Error **errp) { diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 15fff66c3c..e8e1523960 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -83,8 +83,11 @@ Object *user_creatable_add_type(const char *type, const char *id, } if (id != NULL) { - object_property_add_child(object_get_objects_root(), - id, obj); + object_property_try_add_child(object_get_objects_root(), + id, obj, &local_err); + if (local_err) { + goto out; + } } if (!user_creatable_complete(USER_CREATABLE(obj), &local_err)) { From 9fc719b869264824db0be615122754909facc929 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 29 Jun 2020 21:34:23 +0200 Subject: [PATCH 2098/2595] tests/qmp-cmd-test: Add qmp/object-add-duplicate-id This new test checks that attempting to create an object with an existing ID gracefully fails. Signed-off-by: Eric Auger Acked-by: Thomas Huth Reviewed-by: Markus Armbruster Message-Id: <20200629193424.30280-3-eric.auger@redhat.com> Signed-off-by: Paolo Bonzini --- tests/qtest/qmp-cmd-test.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c index 9f5228cd99..fc65fa3726 100644 --- a/tests/qtest/qmp-cmd-test.c +++ b/tests/qtest/qmp-cmd-test.c @@ -213,6 +213,23 @@ static void test_object_add_without_props(void) qtest_quit(qts); } +static void test_object_add_with_duplicate_id(void) +{ + QTestState *qts; + QDict *resp; + + qts = qtest_init(common_args); + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1', 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1', 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + qtest_quit(qts); +} + int main(int argc, char *argv[]) { QmpSchema schema; @@ -225,6 +242,8 @@ int main(int argc, char *argv[]) qtest_add_func("qmp/object-add-without-props", test_object_add_without_props); + qtest_add_func("qmp/object-add-duplicate-id", + test_object_add_with_duplicate_id); /* TODO: add coverage of generic object-add failure modes */ ret = g_test_run(); From 5b88849e7b92945c4d4a6bc1a84ea463242c9fb3 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 29 Jun 2020 21:34:24 +0200 Subject: [PATCH 2099/2595] tests/qmp-cmd-test: Add qmp/object-add-failure-modes Merge the existing object-add test cases into a single test functions and cover more failure cases. Signed-off-by: Eric Auger Message-Id: <20200629193424.30280-4-eric.auger@redhat.com> Signed-off-by: Paolo Bonzini --- tests/qtest/qmp-cmd-test.c | 114 +++++++++++++++++++++++++++++++------ 1 file changed, 97 insertions(+), 17 deletions(-) diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c index fc65fa3726..c68f99f659 100644 --- a/tests/qtest/qmp-cmd-test.c +++ b/tests/qtest/qmp-cmd-test.c @@ -200,33 +200,116 @@ static void add_query_tests(QmpSchema *schema) } } -static void test_object_add_without_props(void) +static void test_object_add_failure_modes(void) { QTestState *qts; QDict *resp; + /* attempt to create an object without props */ qts = qtest_init(common_args); resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" - " {'qom-type': 'memory-backend-ram', 'id': 'ram1' } }"); + " {'qom-type': 'memory-backend-ram', 'id': 'ram1' } }"); g_assert_nonnull(resp); qmp_assert_error_class(resp, "GenericError"); - qtest_quit(qts); -} -static void test_object_add_with_duplicate_id(void) -{ - QTestState *qts; - QDict *resp; - - qts = qtest_init(common_args); + /* attempt to create an object without qom-type */ resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" - " {'qom-type': 'memory-backend-ram', 'id': 'ram1', 'props': {'size': 1048576 } } }"); + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + + /* attempt to delete an object that does not exist */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + + /* attempt to create 2 objects with duplicate id */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': 1048576 } } }"); g_assert_nonnull(resp); g_assert(qdict_haskey(resp, "return")); resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" - " {'qom-type': 'memory-backend-ram', 'id': 'ram1', 'props': {'size': 1048576 } } }"); + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': 1048576 } } }"); g_assert_nonnull(resp); qmp_assert_error_class(resp, "GenericError"); + + /* delete ram1 object */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* attempt to create an object with a property of a wrong type */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': '1048576' } } }"); + g_assert_nonnull(resp); + /* now do it right */ + qmp_assert_error_class(resp, "GenericError"); + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* delete ram1 object */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* attempt to create an object without the id */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram'," + " 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + /* now do it right */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* delete ram1 object */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* attempt to set a non existing property */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'sized': 1048576 } } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + /* now do it right */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* delete ram1 object without id */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'ida': 'ram1' } }"); + g_assert_nonnull(resp); + + /* delete ram1 object */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* delete ram1 object that does not exist anymore*/ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + qtest_quit(qts); } @@ -240,11 +323,8 @@ int main(int argc, char *argv[]) qmp_schema_init(&schema); add_query_tests(&schema); - qtest_add_func("qmp/object-add-without-props", - test_object_add_without_props); - qtest_add_func("qmp/object-add-duplicate-id", - test_object_add_with_duplicate_id); - /* TODO: add coverage of generic object-add failure modes */ + qtest_add_func("qmp/object-add-failure-modes", + test_object_add_failure_modes); ret = g_test_run(); From 9e7871b1fca452e6ca125ff74baa3332e99ad5fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jun 2020 12:56:11 +0200 Subject: [PATCH 2100/2595] hw/core/null-machine: Do not initialize unused chardev backends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MachineClass uses an inverted logic (inherited from the PC machines [*]) to create the chardev backends for the default devices (see commits 998bbd74b9d..aa40fc9c964 and ac33f8fad14). As the none-machine doesn't have any hardware device, it is pointless to initialize chardev backends. Fix by setting the 'no_defaults' bits in its MachineClass. Suggested-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Message-Id: <20200624105611.1049-1-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/core/null-machine.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c index cb47d9d4f8..7e693523d7 100644 --- a/hw/core/null-machine.c +++ b/hw/core/null-machine.c @@ -50,6 +50,11 @@ static void machine_none_machine_init(MachineClass *mc) mc->max_cpus = 1; mc->default_ram_size = 0; mc->default_ram_id = "ram"; + mc->no_serial = 1; + mc->no_parallel = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_sdcard = 1; } DEFINE_MACHINE("none", machine_none_machine_init) From 3ddc0eca2229846bfecc3485648a6cb85a466dc7 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 25 Jun 2020 23:57:44 +0000 Subject: [PATCH 2101/2595] target/i386: set SSE FTZ in correct floating-point state The code to set floating-point state when MXCSR changes calls set_flush_to_zero on &env->fp_status, so affecting the x87 floating-point state rather than the SSE state. Fix to call it for &env->sse_status instead. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 71cec3962f..ec5b9db8b9 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -2972,7 +2972,7 @@ void update_mxcsr_status(CPUX86State *env) set_flush_inputs_to_zero((mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status); /* set flush to zero */ - set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status); + set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->sse_status); } void helper_ldmxcsr(CPUX86State *env, uint32_t val) From 418b0f93d12a1589d5031405de857844f32e9ccc Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 25 Jun 2020 23:58:31 +0000 Subject: [PATCH 2102/2595] target/i386: fix IEEE SSE floating-point exception raising The SSE instruction implementations all fail to raise the expected IEEE floating-point exceptions because they do nothing to convert the exception state from the softfloat machinery into the exception flags in MXCSR. Fix this by adding such conversions. Unlike for x87, emulated SSE floating-point operations might be optimized using hardware floating point on the host, and so a different approach is taken that is compatible with such optimizations. The required invariant is that all exceptions set in env->sse_status (other than "denormal operand", for which the SSE semantics are different from those in the softfloat code) are ones that are set in the MXCSR; the emulated MXCSR is updated lazily when code reads MXCSR, while when code sets MXCSR, the exceptions in env->sse_status are set accordingly. A few instructions do not raise all the exceptions that would be raised by the softfloat code, and those instructions are made to save and restore the softfloat exception state accordingly. Nothing is done about "denormal operand"; setting that (only for the case when input denormals are *not* flushed to zero, the opposite of the logic in the softfloat code for such an exception) will require custom code for relevant instructions, or else architecture-specific conditionals in the softfloat code for when to set such an exception together with custom code for various SSE conversion and rounding instructions that do not set that exception. Nothing is done about trapping exceptions (for which there is minimal and largely broken support in QEMU's emulation in the x87 case and no support at all in the SSE case). Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/Makefile.objs | 1 + target/i386/cpu.h | 1 + target/i386/fpu_helper.c | 35 + target/i386/gdbstub.c | 1 + target/i386/helper.c | 1 + target/i386/helper.h | 1 + target/i386/ops_sse.h | 28 +- target/i386/tcg-stub.c | 25 + target/i386/translate.c | 1 + tests/tcg/i386/Makefile.target | 4 + tests/tcg/i386/test-i386-sse-exceptions.c | 813 ++++++++++++++++++++++ 11 files changed, 899 insertions(+), 12 deletions(-) create mode 100644 target/i386/tcg-stub.c create mode 100644 tests/tcg/i386/test-i386-sse-exceptions.c diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs index 48e0c28434..0b93143e27 100644 --- a/target/i386/Makefile.objs +++ b/target/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-$(CONFIG_TCG) += translate.o obj-$(CONFIG_TCG) += bpt_helper.o cc_helper.o excp_helper.o fpu_helper.o obj-$(CONFIG_TCG) += int_helper.o mem_helper.o misc_helper.o mpx_helper.o obj-$(CONFIG_TCG) += seg_helper.o smm_helper.o svm_helper.o +obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o ifeq ($(CONFIG_SOFTMMU),y) obj-y += machine.o arch_memory_mapping.o arch_dump.o monitor.o diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 7d77efd9e4..06b2e3a5c6 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2143,6 +2143,7 @@ static inline bool cpu_vmx_maybe_enabled(CPUX86State *env) /* fpu_helper.c */ void update_fp_status(CPUX86State *env); void update_mxcsr_status(CPUX86State *env); +void update_mxcsr_from_sse_status(CPUX86State *env); static inline void cpu_set_mxcsr(CPUX86State *env, uint32_t mxcsr) { diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index ec5b9db8b9..f5e6c4b88d 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -2539,6 +2539,7 @@ static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) static void do_xsave_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra) { + update_mxcsr_from_sse_status(env); cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr), env->mxcsr, ra); cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr_mask), 0x0000ffff, ra); } @@ -2968,6 +2969,14 @@ void update_mxcsr_status(CPUX86State *env) } set_float_rounding_mode(rnd_type, &env->sse_status); + /* Set exception flags. */ + set_float_exception_flags((mxcsr & FPUS_IE ? float_flag_invalid : 0) | + (mxcsr & FPUS_ZE ? float_flag_divbyzero : 0) | + (mxcsr & FPUS_OE ? float_flag_overflow : 0) | + (mxcsr & FPUS_UE ? float_flag_underflow : 0) | + (mxcsr & FPUS_PE ? float_flag_inexact : 0), + &env->sse_status); + /* set denormals are zero */ set_flush_inputs_to_zero((mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status); @@ -2975,6 +2984,32 @@ void update_mxcsr_status(CPUX86State *env) set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->sse_status); } +void update_mxcsr_from_sse_status(CPUX86State *env) +{ + if (tcg_enabled()) { + uint8_t flags = get_float_exception_flags(&env->sse_status); + /* + * The MXCSR denormal flag has opposite semantics to + * float_flag_input_denormal (the softfloat code sets that flag + * only when flushing input denormals to zero, but SSE sets it + * only when not flushing them to zero), so is not converted + * here. + */ + env->mxcsr |= ((flags & float_flag_invalid ? FPUS_IE : 0) | + (flags & float_flag_divbyzero ? FPUS_ZE : 0) | + (flags & float_flag_overflow ? FPUS_OE : 0) | + (flags & float_flag_underflow ? FPUS_UE : 0) | + (flags & float_flag_inexact ? FPUS_PE : 0) | + (flags & float_flag_output_denormal ? FPUS_UE | FPUS_PE : + 0)); + } +} + +void helper_update_mxcsr(CPUX86State *env) +{ + update_mxcsr_from_sse_status(env); +} + void helper_ldmxcsr(CPUX86State *env, uint32_t val) { cpu_set_mxcsr(env, val); diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c index b98a99500a..9ae43bda0f 100644 --- a/target/i386/gdbstub.c +++ b/target/i386/gdbstub.c @@ -184,6 +184,7 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) return gdb_get_reg32(mem_buf, 0); /* fop */ case IDX_MXCSR_REG: + update_mxcsr_from_sse_status(env); return gdb_get_reg32(mem_buf, env->mxcsr); case IDX_CTL_CR0_REG: diff --git a/target/i386/helper.c b/target/i386/helper.c index c3a6e4fabe..fa2a1dcdda 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -544,6 +544,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags) for(i = 0; i < 8; i++) { fptag |= ((!env->fptags[i]) << i); } + update_mxcsr_from_sse_status(env); qemu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n", env->fpuc, (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11, diff --git a/target/i386/helper.h b/target/i386/helper.h index 8f9e1905c3..c2ae2f7e61 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -207,6 +207,7 @@ DEF_HELPER_FLAGS_2(pext, TCG_CALL_NO_RWG_SE, tl, tl, tl) /* MMX/SSE */ DEF_HELPER_2(ldmxcsr, void, env, i32) +DEF_HELPER_1(update_mxcsr, void, env) DEF_HELPER_1(enter_mmx, void, env) DEF_HELPER_1(emms, void, env) DEF_HELPER_3(movq, void, env, ptr, ptr) diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h index 14f2b16abd..c7614f8b0b 100644 --- a/target/i386/ops_sse.h +++ b/target/i386/ops_sse.h @@ -843,6 +843,7 @@ int64_t helper_cvttsd2sq(CPUX86State *env, ZMMReg *s) void helper_rsqrtps(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); d->ZMM_S(0) = float32_div(float32_one, float32_sqrt(s->ZMM_S(0), &env->sse_status), &env->sse_status); @@ -855,26 +856,33 @@ void helper_rsqrtps(CPUX86State *env, ZMMReg *d, ZMMReg *s) d->ZMM_S(3) = float32_div(float32_one, float32_sqrt(s->ZMM_S(3), &env->sse_status), &env->sse_status); + set_float_exception_flags(old_flags, &env->sse_status); } void helper_rsqrtss(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); d->ZMM_S(0) = float32_div(float32_one, float32_sqrt(s->ZMM_S(0), &env->sse_status), &env->sse_status); + set_float_exception_flags(old_flags, &env->sse_status); } void helper_rcpps(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); d->ZMM_S(0) = float32_div(float32_one, s->ZMM_S(0), &env->sse_status); d->ZMM_S(1) = float32_div(float32_one, s->ZMM_S(1), &env->sse_status); d->ZMM_S(2) = float32_div(float32_one, s->ZMM_S(2), &env->sse_status); d->ZMM_S(3) = float32_div(float32_one, s->ZMM_S(3), &env->sse_status); + set_float_exception_flags(old_flags, &env->sse_status); } void helper_rcpss(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); d->ZMM_S(0) = float32_div(float32_one, s->ZMM_S(0), &env->sse_status); + set_float_exception_flags(old_flags, &env->sse_status); } static inline uint64_t helper_extrq(uint64_t src, int shift, int len) @@ -1764,6 +1772,7 @@ void glue(helper_phminposuw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) void glue(helper_roundps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; prev_rounding_mode = env->sse_status.float_rounding_mode; @@ -1789,19 +1798,18 @@ void glue(helper_roundps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, d->ZMM_S(2) = float32_round_to_int(s->ZMM_S(2), &env->sse_status); d->ZMM_S(3) = float32_round_to_int(s->ZMM_S(3), &env->sse_status); -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode = prev_rounding_mode; } void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; prev_rounding_mode = env->sse_status.float_rounding_mode; @@ -1825,19 +1833,18 @@ void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, d->ZMM_D(0) = float64_round_to_int(s->ZMM_D(0), &env->sse_status); d->ZMM_D(1) = float64_round_to_int(s->ZMM_D(1), &env->sse_status); -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode = prev_rounding_mode; } void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; prev_rounding_mode = env->sse_status.float_rounding_mode; @@ -1860,19 +1867,18 @@ void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, d->ZMM_S(0) = float32_round_to_int(s->ZMM_S(0), &env->sse_status); -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode = prev_rounding_mode; } void glue(helper_roundsd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; prev_rounding_mode = env->sse_status.float_rounding_mode; @@ -1895,13 +1901,11 @@ void glue(helper_roundsd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, d->ZMM_D(0) = float64_round_to_int(s->ZMM_D(0), &env->sse_status); -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode = prev_rounding_mode; } diff --git a/target/i386/tcg-stub.c b/target/i386/tcg-stub.c new file mode 100644 index 0000000000..b00e23d606 --- /dev/null +++ b/target/i386/tcg-stub.c @@ -0,0 +1,25 @@ +/* + * x86 FPU, MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4/PNI helpers + * + * Copyright (c) 2003 Fabrice Bellard + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "cpu.h" + +void update_mxcsr_from_sse_status(CPUX86State *env) +{ +} diff --git a/target/i386/translate.c b/target/i386/translate.c index 5e5dbb41b0..b3fea54411 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -8157,6 +8157,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; } + gen_helper_update_mxcsr(cpu_env); gen_lea_modrm(env, s, modrm); tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, mxcsr)); gen_op_st_v(s, MO_32, s->T0, s->A0); diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index 1a6463a7dc..a66232a67d 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -10,6 +10,10 @@ ALL_X86_TESTS=$(I386_SRCS:.c=) SKIP_I386_TESTS=test-i386-ssse3 X86_64_TESTS:=$(filter test-i386-ssse3, $(ALL_X86_TESTS)) +test-i386-sse-exceptions: CFLAGS += -msse4.1 -mfpmath=sse +run-test-i386-sse-exceptions: QEMU_OPTS += -cpu max +run-plugin-test-i386-sse-exceptions-%: QEMU_OPTS += -cpu max + test-i386-pcmpistri: CFLAGS += -msse4.2 run-test-i386-pcmpistri: QEMU_OPTS += -cpu max run-plugin-test-i386-pcmpistri-%: QEMU_OPTS += -cpu max diff --git a/tests/tcg/i386/test-i386-sse-exceptions.c b/tests/tcg/i386/test-i386-sse-exceptions.c new file mode 100644 index 0000000000..a104f46c11 --- /dev/null +++ b/tests/tcg/i386/test-i386-sse-exceptions.c @@ -0,0 +1,813 @@ +/* Test SSE exceptions. */ + +#include +#include +#include + +volatile float f_res; +volatile double d_res; + +volatile float f_snan = __builtin_nansf(""); +volatile float f_half = 0.5f; +volatile float f_third = 1.0f / 3.0f; +volatile float f_nan = __builtin_nanl(""); +volatile float f_inf = __builtin_inff(); +volatile float f_ninf = -__builtin_inff(); +volatile float f_one = 1.0f; +volatile float f_two = 2.0f; +volatile float f_zero = 0.0f; +volatile float f_nzero = -0.0f; +volatile float f_min = FLT_MIN; +volatile float f_true_min = 0x1p-149f; +volatile float f_max = FLT_MAX; +volatile float f_nmax = -FLT_MAX; + +volatile double d_snan = __builtin_nans(""); +volatile double d_half = 0.5; +volatile double d_third = 1.0 / 3.0; +volatile double d_nan = __builtin_nan(""); +volatile double d_inf = __builtin_inf(); +volatile double d_ninf = -__builtin_inf(); +volatile double d_one = 1.0; +volatile double d_two = 2.0; +volatile double d_zero = 0.0; +volatile double d_nzero = -0.0; +volatile double d_min = DBL_MIN; +volatile double d_true_min = 0x1p-1074; +volatile double d_max = DBL_MAX; +volatile double d_nmax = -DBL_MAX; + +volatile int32_t i32_max = INT32_MAX; + +#define IE (1 << 0) +#define ZE (1 << 2) +#define OE (1 << 3) +#define UE (1 << 4) +#define PE (1 << 5) +#define EXC (IE | ZE | OE | UE | PE) + +uint32_t mxcsr_default = 0x1f80; +uint32_t mxcsr_ftz = 0x9f80; + +int main(void) +{ + uint32_t mxcsr; + int32_t i32_res; + int ret = 0; + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = f_snan; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: widen float snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = d_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: narrow float underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = d_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: narrow float overflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: narrow float inexact\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = d_snan; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: narrow float snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $4, %0, %0" : "=x" (f_res) : "0" (f_min)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: roundss min\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $12, %0, %0" : "=x" (f_res) : "0" (f_min)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: roundss no-inexact min\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $4, %0, %0" : "=x" (f_res) : "0" (f_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: roundss snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $12, %0, %0" : "=x" (f_res) : "0" (f_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: roundss no-inexact snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $4, %0, %0" : "=x" (d_res) : "0" (d_min)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: roundsd min\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $12, %0, %0" : "=x" (d_res) : "0" (d_min)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: roundsd no-inexact min\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $4, %0, %0" : "=x" (d_res) : "0" (d_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: roundsd snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $12, %0, %0" : "=x" (d_res) : "0" (d_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: roundsd no-inexact snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("comiss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: comiss nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomiss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: ucomiss nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomiss %1, %0" : : "x" (f_snan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: ucomiss snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("comisd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: comisd nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomisd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: ucomisd nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomisd %1, %0" : : "x" (d_snan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: ucomisd snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max + f_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: float add overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max + f_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: float add inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_inf + f_ninf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float add inf -inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_snan + f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float add snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res = f_true_min + f_true_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float add FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max + d_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: double add overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max + d_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: double add inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_inf + d_ninf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double add inf -inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_snan + d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double add snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res = d_true_min + d_true_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double add FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max - f_nmax; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: float sub overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max - f_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: float sub inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_inf - f_inf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float sub inf inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_snan - f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float sub snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res = f_min - f_true_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float sub FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max - d_nmax; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: double sub overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max - d_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: double sub inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_inf - d_inf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double sub inf inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_snan - d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double sub snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res = d_min - d_true_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double sub FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max * f_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: float mul overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_third * f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: float mul inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_min * f_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float mul underflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_inf * f_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float mul inf 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_snan * f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float mul snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res = f_min * f_half; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float mul FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max * d_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: double mul overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_third * d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: double mul inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_min * d_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double mul underflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_inf * d_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double mul inf 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_snan * d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double mul snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res = d_min * d_half; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double mul FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max / f_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: float div overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_one / f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: float div inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_min / f_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float div underflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_one / f_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != ZE) { + printf("FAIL: float div 1 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_inf / f_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: float div inf 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_nan / f_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: float div nan 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_zero / f_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float div 0 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_inf / f_inf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float div inf inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_snan / f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float div snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res = f_min / f_two; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float div FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max / d_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: double div overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_one / d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: double div inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_min / d_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double div underflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_one / d_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != ZE) { + printf("FAIL: double div 1 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_inf / d_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: double div inf 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_nan / d_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: double div nan 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_zero / d_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double div 0 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_inf / d_inf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double div inf inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_snan / d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double div snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res = d_min / d_two; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double div FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_max)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: sqrtss inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_nmax)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtss -max\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_ninf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtss -inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtss snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_nzero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: sqrtss -0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : + "0" (-__builtin_nanf(""))); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: sqrtss -nan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_max)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: sqrtsd inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_nmax)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtsd -max\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_ninf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtsd -inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtsd snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_nzero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: sqrtsd -0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : + "0" (-__builtin_nan(""))); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: sqrtsd -nan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("maxss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: maxss nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("minss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: minss nan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("maxsd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: maxsd nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("minsd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: minsd nan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsi2ss %1, %0" : "=x" (f_res) : "m" (i32_max)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: cvtsi2ss inexact\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsi2sd %1, %0" : "=x" (d_res) : "m" (i32_max)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: cvtsi2sd exact\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtss2si %1, %0" : "=r" (i32_res) : "x" (1.5f)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: cvtss2si inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtss2si %1, %0" : "=r" (i32_res) : "x" (0x1p31f)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvtss2si 0x1p31\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtss2si %1, %0" : "=r" (i32_res) : "x" (f_inf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvtss2si inf\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsd2si %1, %0" : "=r" (i32_res) : "x" (1.5)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: cvtsd2si inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsd2si %1, %0" : "=r" (i32_res) : "x" (0x1p31)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvtsd2si 0x1p31\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsd2si %1, %0" : "=r" (i32_res) : "x" (d_inf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvtsd2si inf\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttss2si %1, %0" : "=r" (i32_res) : "x" (1.5f)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: cvttss2si inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttss2si %1, %0" : "=r" (i32_res) : "x" (0x1p31f)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvttss2si 0x1p31\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttss2si %1, %0" : "=r" (i32_res) : "x" (f_inf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvttss2si inf\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttsd2si %1, %0" : "=r" (i32_res) : "x" (1.5)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: cvttsd2si inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttsd2si %1, %0" : "=r" (i32_res) : "x" (0x1p31)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvttsd2si 0x1p31\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttsd2si %1, %0" : "=r" (i32_res) : "x" (d_inf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvttsd2si inf\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("rcpss %0, %0" : "=x" (f_res) : "0" (f_snan)); + f_res += f_one; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: rcpss snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("rsqrtss %0, %0" : "=x" (f_res) : "0" (f_snan)); + f_res += f_one; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: rsqrtss snan\n"); + ret = 1; + } + + return ret; +} From b16c0e20c74218f2d69710cedad11da7dd4d2190 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 May 2020 10:49:22 -0400 Subject: [PATCH 2103/2595] KVM: add support for AMD nested live migration Support for nested guest live migration is part of Linux 5.8, add the corresponding code to QEMU. The migration format consists of a few flags, is an opaque 4k blob. The blob is in VMCB format (the control area represents the L1 VMCB control fields, the save area represents the pre-vmentry state; KVM does not use the host save area since the AMD manual allows that) but QEMU does not really care about that. However, the flags need to be copied to hflags/hflags2 and back. In addition, support for retrieving and setting the AMD nested virtualization states allows the L1 guest to be reset while running a nested guest, but a small bug in CPU reset needs to be fixed for that to work. Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 1 + target/i386/cpu.h | 5 +++++ target/i386/kvm.c | 42 ++++++++++++++++++++++++++++++++++-------- target/i386/machine.c | 31 ++++++++++++++++++++++++++++++- 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index e46ab8f774..008fd93ff1 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5968,6 +5968,7 @@ static void x86_cpu_reset(DeviceState *dev) /* init to reset state */ env->hflags2 |= HF2_GIF_MASK; + env->hflags &= ~HF_GUEST_MASK; cpu_x86_update_cr0(env, 0x60000010); env->a20_mask = ~0x0; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 06b2e3a5c6..9284f96896 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2118,6 +2118,11 @@ static inline bool cpu_has_vmx(CPUX86State *env) return env->features[FEAT_1_ECX] & CPUID_EXT_VMX; } +static inline bool cpu_has_svm(CPUX86State *env) +{ + return env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM; +} + /* * In order for a vCPU to enter VMX operation it must have CR4.VMXE set. * Since it was set, CR4.VMXE must remain set as long as vCPU is in diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 6adbff3d74..2b6b7443d2 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -1840,16 +1840,18 @@ int kvm_arch_init_vcpu(CPUState *cs) if (max_nested_state_len > 0) { assert(max_nested_state_len >= offsetof(struct kvm_nested_state, data)); - if (cpu_has_vmx(env)) { + if (cpu_has_vmx(env) || cpu_has_svm(env)) { struct kvm_vmx_nested_state_hdr *vmx_hdr; env->nested_state = g_malloc0(max_nested_state_len); env->nested_state->size = max_nested_state_len; env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX; - vmx_hdr = &env->nested_state->hdr.vmx; - vmx_hdr->vmxon_pa = -1ull; - vmx_hdr->vmcs12_pa = -1ull; + if (cpu_has_vmx(env)) { + vmx_hdr = &env->nested_state->hdr.vmx; + vmx_hdr->vmxon_pa = -1ull; + vmx_hdr->vmcs12_pa = -1ull; + } } } @@ -3873,6 +3875,20 @@ static int kvm_put_nested_state(X86CPU *cpu) return 0; } + /* + * Copy flags that are affected by reset from env->hflags and env->hflags2. + */ + if (env->hflags & HF_GUEST_MASK) { + env->nested_state->flags |= KVM_STATE_NESTED_GUEST_MODE; + } else { + env->nested_state->flags &= ~KVM_STATE_NESTED_GUEST_MODE; + } + if (env->hflags2 & HF2_GIF_MASK) { + env->nested_state->flags |= KVM_STATE_NESTED_GIF_SET; + } else { + env->nested_state->flags &= ~KVM_STATE_NESTED_GIF_SET; + } + assert(env->nested_state->size <= max_nested_state_len); return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_NESTED_STATE, env->nested_state); } @@ -3901,11 +3917,19 @@ static int kvm_get_nested_state(X86CPU *cpu) return ret; } + /* + * Copy flags that are affected by reset to env->hflags and env->hflags2. + */ if (env->nested_state->flags & KVM_STATE_NESTED_GUEST_MODE) { env->hflags |= HF_GUEST_MASK; } else { env->hflags &= ~HF_GUEST_MASK; } + if (env->nested_state->flags & KVM_STATE_NESTED_GIF_SET) { + env->hflags2 |= HF2_GIF_MASK; + } else { + env->hflags2 &= ~HF2_GIF_MASK; + } return ret; } @@ -3917,6 +3941,12 @@ int kvm_arch_put_registers(CPUState *cpu, int level) assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); + /* must be before kvm_put_nested_state so that EFER.SVME is set */ + ret = kvm_put_sregs(x86_cpu); + if (ret < 0) { + return ret; + } + if (level >= KVM_PUT_RESET_STATE) { ret = kvm_put_nested_state(x86_cpu); if (ret < 0) { @@ -3950,10 +3980,6 @@ int kvm_arch_put_registers(CPUState *cpu, int level) if (ret < 0) { return ret; } - ret = kvm_put_sregs(x86_cpu); - if (ret < 0) { - return ret; - } /* must be before kvm_put_msrs */ ret = kvm_inject_mce_oldstyle(x86_cpu); if (ret < 0) { diff --git a/target/i386/machine.c b/target/i386/machine.c index 0c96531a56..b1acf7d0ef 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -1071,13 +1071,41 @@ static const VMStateDescription vmstate_vmx_nested_state = { } }; +static bool svm_nested_state_needed(void *opaque) +{ + struct kvm_nested_state *nested_state = opaque; + + /* + * HF_GUEST_MASK and HF2_GIF_MASK are already serialized + * via hflags and hflags2, all that's left is the opaque + * nested state blob. + */ + return (nested_state->format == KVM_STATE_NESTED_FORMAT_SVM && + nested_state->size > offsetof(struct kvm_nested_state, data)); +} + +static const VMStateDescription vmstate_svm_nested_state = { + .name = "cpu/kvm_nested_state/svm", + .version_id = 1, + .minimum_version_id = 1, + .needed = svm_nested_state_needed, + .fields = (VMStateField[]) { + VMSTATE_U64(hdr.svm.vmcb_pa, struct kvm_nested_state), + VMSTATE_UINT8_ARRAY(data.svm[0].vmcb12, + struct kvm_nested_state, + KVM_STATE_NESTED_SVM_VMCB_SIZE), + VMSTATE_END_OF_LIST() + } +}; + static bool nested_state_needed(void *opaque) { X86CPU *cpu = opaque; CPUX86State *env = &cpu->env; return (env->nested_state && - vmx_nested_state_needed(env->nested_state)); + (vmx_nested_state_needed(env->nested_state) || + svm_nested_state_needed(env->nested_state))); } static int nested_state_post_load(void *opaque, int version_id) @@ -1139,6 +1167,7 @@ static const VMStateDescription vmstate_kvm_nested_state = { }, .subsections = (const VMStateDescription*[]) { &vmstate_vmx_nested_state, + &vmstate_svm_nested_state, NULL } }; From 6553aa1d1166b4257f1294b898fc9f09e7276639 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 29 Jun 2020 11:28:04 -0500 Subject: [PATCH 2104/2595] coverity: provide Coverity-friendly MIN_CONST and MAX_CONST Coverity has problems seeing through __builtin_choose_expr, which result in it abandoning analysis of later functions that utilize a definition that used MIN_CONST or MAX_CONST, such as in qemu-file.c: 50 DECLARE_BITMAP(may_free, MAX_IOV_SIZE); CID 1429992 (#1 of 1): Unrecoverable parse warning (PARSE_ERROR)1. expr_not_constant: expression must have a constant value As has been done in the past (see 07d66672), it's okay to dumb things down when compiling for static analyzers. (Of course, now the syntax-checker has a false positive on our reference to __COVERITY__...) Reported-by: Peter Maydell Fixes: CID 1429992, CID 1429995, CID 1429997, CID 1429999 Signed-off-by: Eric Blake Message-Id: <20200629162804.1096180-1-eblake@redhat.com> Signed-off-by: Paolo Bonzini --- include/qemu/osdep.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 0d26a1b9bd..0fc206ae61 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -250,7 +250,8 @@ extern int daemon(int, int); * Note that neither form is usable as an #if condition; if you truly * need to write conditional code that depends on a minimum or maximum * determined by the pre-processor instead of the compiler, you'll - * have to open-code it. + * have to open-code it. Sadly, Coverity is severely confused by the + * constant variants, so we have to dumb things down there. */ #undef MIN #define MIN(a, b) \ @@ -258,22 +259,28 @@ extern int daemon(int, int); typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ _a < _b ? _a : _b; \ }) -#define MIN_CONST(a, b) \ - __builtin_choose_expr( \ - __builtin_constant_p(a) && __builtin_constant_p(b), \ - (a) < (b) ? (a) : (b), \ - ((void)0)) #undef MAX #define MAX(a, b) \ ({ \ typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ _a > _b ? _a : _b; \ }) -#define MAX_CONST(a, b) \ + +#ifdef __COVERITY__ +# define MIN_CONST(a, b) ((a) < (b) ? (a) : (b)) +# define MAX_CONST(a, b) ((a) > (b) ? (a) : (b)) +#else +# define MIN_CONST(a, b) \ + __builtin_choose_expr( \ + __builtin_constant_p(a) && __builtin_constant_p(b), \ + (a) < (b) ? (a) : (b), \ + ((void)0)) +# define MAX_CONST(a, b) \ __builtin_choose_expr( \ __builtin_constant_p(a) && __builtin_constant_p(b), \ (a) > (b) ? (a) : (b), \ ((void)0)) +#endif /* * Minimum function that returns zero only if both values are zero. From b8d864f64341eb5825aed28aa9a6d1c98316b3e9 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:16 +0300 Subject: [PATCH 2105/2595] i386: hvf: Set env->eip in macvm_set_rip() cpu_synchronize_state() is currently no-op for hvf but BIOS will hang in vAPIC option ROM when cpu_synchronize_state() is wired to hvf_cpu_synchronize_state(). cpu_synchronize_state() state is called from vapic_write() during option ROM initialization. It sets dirty flag on the cpu. macvm_set_rip() is then invoked to advance IP after the I/O write to vAPIC port. macvm_set_rip() only modifies VMCS, it doesn't change env->eip. Therefore on the next iteration of vCPU loop, vcpu_dirty flag is checked and hvf_put_registers() overwrites correct RIP in VMCS with the value of env->eip that points to the I/O write instruction. Execution of the CPU gets stuck on the instruction. The issue can be avoided if eip doesn't contain stale value when dirty flag is set on cpu. Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-2-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/vmx.h | 1 + 1 file changed, 1 insertion(+) diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index ce2a1532d5..1e8b29bf7d 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -173,6 +173,7 @@ static inline void macvm_set_rip(CPUState *cpu, uint64_t rip) /* BUG, should take considering overlap.. */ wreg(cpu->hvf_fd, HV_X86_RIP, rip); + env->eip = rip; /* after moving forward in rip, we need to clean INTERRUPTABILITY */ val = rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY); From 4bb19f98d34302d627a1267b608de4df6d0988f9 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:17 +0300 Subject: [PATCH 2106/2595] i386: hvf: Move synchronize functions to sysemu Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-3-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- cpus.c | 12 ------------ include/sysemu/hw_accel.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/cpus.c b/cpus.c index 41d1c5099f..d94456ed29 100644 --- a/cpus.c +++ b/cpus.c @@ -1017,10 +1017,6 @@ void cpu_synchronize_all_states(void) CPU_FOREACH(cpu) { cpu_synchronize_state(cpu); - /* TODO: move to cpu_synchronize_state() */ - if (hvf_enabled()) { - hvf_cpu_synchronize_state(cpu); - } } } @@ -1030,10 +1026,6 @@ void cpu_synchronize_all_post_reset(void) CPU_FOREACH(cpu) { cpu_synchronize_post_reset(cpu); - /* TODO: move to cpu_synchronize_post_reset() */ - if (hvf_enabled()) { - hvf_cpu_synchronize_post_reset(cpu); - } } } @@ -1043,10 +1035,6 @@ void cpu_synchronize_all_post_init(void) CPU_FOREACH(cpu) { cpu_synchronize_post_init(cpu); - /* TODO: move to cpu_synchronize_post_init() */ - if (hvf_enabled()) { - hvf_cpu_synchronize_post_init(cpu); - } } } diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h index 0ec2372477..80bce75921 100644 --- a/include/sysemu/hw_accel.h +++ b/include/sysemu/hw_accel.h @@ -14,6 +14,7 @@ #include "hw/core/cpu.h" #include "sysemu/hax.h" #include "sysemu/kvm.h" +#include "sysemu/hvf.h" #include "sysemu/whpx.h" static inline void cpu_synchronize_state(CPUState *cpu) @@ -24,6 +25,9 @@ static inline void cpu_synchronize_state(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_state(cpu); } + if (hvf_enabled()) { + hvf_cpu_synchronize_state(cpu); + } if (whpx_enabled()) { whpx_cpu_synchronize_state(cpu); } @@ -37,6 +41,9 @@ static inline void cpu_synchronize_post_reset(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_post_reset(cpu); } + if (hvf_enabled()) { + hvf_cpu_synchronize_post_reset(cpu); + } if (whpx_enabled()) { whpx_cpu_synchronize_post_reset(cpu); } @@ -50,6 +57,9 @@ static inline void cpu_synchronize_post_init(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_post_init(cpu); } + if (hvf_enabled()) { + hvf_cpu_synchronize_post_init(cpu); + } if (whpx_enabled()) { whpx_cpu_synchronize_post_init(cpu); } From 5536c98e449fe832c6cb59612baf0f2936fb436d Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:18 +0300 Subject: [PATCH 2107/2595] i386: hvf: Add hvf_cpu_synchronize_pre_loadvm() hvf lacks an implementation of cpu_synchronize_pre_loadvm(). Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-4-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- include/sysemu/hvf.h | 1 + include/sysemu/hw_accel.h | 3 +++ target/i386/hvf/hvf.c | 11 +++++++++++ 3 files changed, 15 insertions(+) diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index 5214ed5202..1d40a8ec01 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -28,6 +28,7 @@ int hvf_vcpu_exec(CPUState *); void hvf_cpu_synchronize_state(CPUState *); void hvf_cpu_synchronize_post_reset(CPUState *); void hvf_cpu_synchronize_post_init(CPUState *); +void hvf_cpu_synchronize_pre_loadvm(CPUState *); void hvf_vcpu_destroy(CPUState *); void hvf_reset_vcpu(CPUState *); diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h index 80bce75921..e128f8b06b 100644 --- a/include/sysemu/hw_accel.h +++ b/include/sysemu/hw_accel.h @@ -73,6 +73,9 @@ static inline void cpu_synchronize_pre_loadvm(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_pre_loadvm(cpu); } + if (hvf_enabled()) { + hvf_cpu_synchronize_pre_loadvm(cpu); + } if (whpx_enabled()) { whpx_cpu_synchronize_pre_loadvm(cpu); } diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index be016b951a..efe9802962 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -325,6 +325,17 @@ void hvf_cpu_synchronize_post_init(CPUState *cpu_state) run_on_cpu(cpu_state, do_hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL); } +static void do_hvf_cpu_synchronize_pre_loadvm(CPUState *cpu, + run_on_cpu_data arg) +{ + cpu->vcpu_dirty = true; +} + +void hvf_cpu_synchronize_pre_loadvm(CPUState *cpu) +{ + run_on_cpu(cpu, do_hvf_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL); +} + static bool ept_emulation_fault(hvf_slot *slot, uint64_t gpa, uint64_t ept_qual) { int read, write; From a4e26fa8583a215aa61107a623bfa25afd09a860 Mon Sep 17 00:00:00 2001 From: Cameron Esfahani Date: Tue, 30 Jun 2020 13:28:20 +0300 Subject: [PATCH 2108/2595] i386: hvf: Make long mode enter and exit clearer Intel SDM "9.8.5 Initializing IA-32e Mode" and "9.8.5.4 Switching Out of IA-32e Mode Operation" define activation and deactivation of long mode only upon a change of CR0.PG but current code invokes exit_long_mode() unconditionally until LME is cleared. Signed-off-by: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-6-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/vmx.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 1e8b29bf7d..437238f11d 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -121,6 +121,7 @@ static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0) uint64_t pdpte[4] = {0, 0, 0, 0}; uint64_t efer = rvmcs(vcpu, VMCS_GUEST_IA32_EFER); uint64_t old_cr0 = rvmcs(vcpu, VMCS_GUEST_CR0); + uint64_t changed_cr0 = old_cr0 ^ cr0; uint64_t mask = CR0_PG | CR0_CD | CR0_NW | CR0_NE | CR0_ET; if ((cr0 & CR0_PG) && (rvmcs(vcpu, VMCS_GUEST_CR4) & CR4_PAE) && @@ -138,11 +139,12 @@ static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0) wvmcs(vcpu, VMCS_CR0_SHADOW, cr0); if (efer & MSR_EFER_LME) { - if (!(old_cr0 & CR0_PG) && (cr0 & CR0_PG)) { - enter_long_mode(vcpu, cr0, efer); - } - if (/*(old_cr0 & CR0_PG) &&*/ !(cr0 & CR0_PG)) { - exit_long_mode(vcpu, cr0, efer); + if (changed_cr0 & CR0_PG) { + if (cr0 & CR0_PG) { + enter_long_mode(vcpu, cr0, efer); + } else { + exit_long_mode(vcpu, cr0, efer); + } } } From 82695a1b9c696aaea491e932548f9787adb7d78b Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:21 +0300 Subject: [PATCH 2109/2595] i386: hvf: Move Guest LMA reset to macvm_set_cr0() The only useful purpose of hvf_reset_vcpu() is to clear "IA-32e mode guest" (LMA) VM-Entry control. But it can be moved to macvm_set_cr0() which is indirectly used by post-init and post-reset to flush emulator state. That enables clean removal of hvf_reset_vcpu(). LMA is set only if IA32_EFER.LME = 1, according to Intel SDM "9.8.5 Initializing IA-32e Mode" and "9.8.5.4 Switching Out of IA-32e Mode Operation", otherwise the entry control can be safely cleared. Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-7-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 1 - target/i386/hvf/vmx.h | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index efe9802962..31980f9076 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -459,7 +459,6 @@ void hvf_reset_vcpu(CPUState *cpu) { /* TODO: this shouldn't be needed; there is already a call to * cpu_synchronize_all_post_reset in vl.c */ - wvmcs(cpu->hvf_fd, VMCS_ENTRY_CTLS, 0); wvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER, 0); /* Initialize PDPTE */ diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 437238f11d..75ba1e2a5f 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -123,6 +123,7 @@ static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0) uint64_t old_cr0 = rvmcs(vcpu, VMCS_GUEST_CR0); uint64_t changed_cr0 = old_cr0 ^ cr0; uint64_t mask = CR0_PG | CR0_CD | CR0_NW | CR0_NE | CR0_ET; + uint64_t entry_ctls; if ((cr0 & CR0_PG) && (rvmcs(vcpu, VMCS_GUEST_CR4) & CR4_PAE) && !(efer & MSR_EFER_LME)) { @@ -146,6 +147,9 @@ static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0) exit_long_mode(vcpu, cr0, efer); } } + } else { + entry_ctls = rvmcs(vcpu, VMCS_ENTRY_CTLS); + wvmcs(vcpu, VMCS_ENTRY_CTLS, entry_ctls & ~VM_ENTRY_GUEST_LMA); } /* Filter new CR0 after we are finished examining it above. */ From 5009ef22c6bb21aa741e9e354ccaa97edf56911d Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:22 +0300 Subject: [PATCH 2110/2595] i386: hvf: Don't duplicate register reset hvf_reset_vcpu() duplicates actions performed by x86_cpu_reset(). The difference is that hvf_reset_vcpu() stores initial values directly to VMCS while x86_cpu_reset() stores it in CPUX86State and then cpu_synchronize_all_post_init() or cpu_synchronize_all_post_reset() flushes CPUX86State into VMCS. That makes hvf_reset_vcpu() a kind of no-op. Here's the trace of CPU state modifications during VM start: hvf_reset_vcpu (resets VMCS) cpu_synchronize_all_post_init (overwrites VMCS fields written by hvf_reset_vcpu()) cpu_synchronize_all_states hvf_reset_vcpu (resets VMCS) cpu_synchronize_all_post_reset (overwrites VMCS fields written by hvf_reset_vcpu()) General purpose registers, system registers, segment descriptors, flags and IP are set by hvf_put_segments() in post-init and post-reset, therefore it's safe to remove them from hvf_reset_vcpu(). PDPTE initialization can be dropped because Intel SDM (26.3.1.6 Checks on Guest Page-Directory-Pointer-Table Entries) doesn't require PDPTE to be clear unless PAE is used: "A VM entry to a guest that does not use PAE paging does not check the validity of any PDPTEs." And if PAE is used, PDPTE's are initialized from CR3 in macvm_set_cr0(). Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-8-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- include/sysemu/hvf.h | 1 - target/i386/cpu.c | 3 -- target/i386/hvf/hvf.c | 89 ------------------------------------------- 3 files changed, 93 deletions(-) diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index 1d40a8ec01..6d3ee4fdb7 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -30,7 +30,6 @@ void hvf_cpu_synchronize_post_reset(CPUState *); void hvf_cpu_synchronize_post_init(CPUState *); void hvf_cpu_synchronize_pre_loadvm(CPUState *); void hvf_vcpu_destroy(CPUState *); -void hvf_reset_vcpu(CPUState *); #define TYPE_HVF_ACCEL ACCEL_CLASS_NAME("hvf") diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 008fd93ff1..1546cd78ff 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6080,9 +6080,6 @@ static void x86_cpu_reset(DeviceState *dev) if (kvm_enabled()) { kvm_arch_reset_vcpu(cpu); } - else if (hvf_enabled()) { - hvf_reset_vcpu(s); - } #endif } diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 31980f9076..2a12867ef0 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -452,95 +452,6 @@ static MemoryListener hvf_memory_listener = { .log_sync = hvf_log_sync, }; -void hvf_reset_vcpu(CPUState *cpu) { - uint64_t pdpte[4] = {0, 0, 0, 0}; - int i; - - /* TODO: this shouldn't be needed; there is already a call to - * cpu_synchronize_all_post_reset in vl.c - */ - wvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER, 0); - - /* Initialize PDPTE */ - for (i = 0; i < 4; i++) { - wvmcs(cpu->hvf_fd, VMCS_GUEST_PDPTE0 + i * 2, pdpte[i]); - } - - macvm_set_cr0(cpu->hvf_fd, 0x60000010); - - wvmcs(cpu->hvf_fd, VMCS_CR4_MASK, CR4_VMXE_MASK); - wvmcs(cpu->hvf_fd, VMCS_CR4_SHADOW, 0x0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_CR4, CR4_VMXE_MASK); - - /* set VMCS guest state fields */ - wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_SELECTOR, 0xf000); - wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_ACCESS_RIGHTS, 0x9b); - wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_BASE, 0xffff0000); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_ACCESS_RIGHTS, 0x93); - wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_ACCESS_RIGHTS, 0x93); - wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_ACCESS_RIGHTS, 0x93); - wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_ACCESS_RIGHTS, 0x93); - wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_ACCESS_RIGHTS, 0x93); - wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_LIMIT, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_ACCESS_RIGHTS, 0x10000); - wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_LIMIT, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_ACCESS_RIGHTS, 0x83); - wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_LIMIT, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_LIMIT, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_BASE, 0); - - /*wvmcs(cpu->hvf_fd, VMCS_GUEST_CR2, 0x0);*/ - wvmcs(cpu->hvf_fd, VMCS_GUEST_CR3, 0x0); - - wreg(cpu->hvf_fd, HV_X86_RIP, 0xfff0); - wreg(cpu->hvf_fd, HV_X86_RDX, 0x623); - wreg(cpu->hvf_fd, HV_X86_RFLAGS, 0x2); - wreg(cpu->hvf_fd, HV_X86_RSP, 0x0); - wreg(cpu->hvf_fd, HV_X86_RAX, 0x0); - wreg(cpu->hvf_fd, HV_X86_RBX, 0x0); - wreg(cpu->hvf_fd, HV_X86_RCX, 0x0); - wreg(cpu->hvf_fd, HV_X86_RSI, 0x0); - wreg(cpu->hvf_fd, HV_X86_RDI, 0x0); - wreg(cpu->hvf_fd, HV_X86_RBP, 0x0); - - for (int i = 0; i < 8; i++) { - wreg(cpu->hvf_fd, HV_X86_R8 + i, 0x0); - } - - hv_vcpu_invalidate_tlb(cpu->hvf_fd); - hv_vcpu_flush(cpu->hvf_fd); -} - void hvf_vcpu_destroy(CPUState *cpu) { X86CPU *x86_cpu = X86_CPU(cpu); From eae009de78b62e67ec887b4934cf62f4f5fb33c8 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:23 +0300 Subject: [PATCH 2111/2595] i386: hvf: Clean up synchronize functions Make them more concise and consitent with the rest of the code in the file and drop non-relevant TODO. Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-9-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 44 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 2a12867ef0..d81f569aed 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -282,47 +282,43 @@ void hvf_handle_io(CPUArchState *env, uint16_t port, void *buffer, } } -/* TODO: synchronize vcpu state */ static void do_hvf_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) { - CPUState *cpu_state = cpu; - if (cpu_state->vcpu_dirty == 0) { - hvf_get_registers(cpu_state); - } - - cpu_state->vcpu_dirty = 1; -} - -void hvf_cpu_synchronize_state(CPUState *cpu_state) -{ - if (cpu_state->vcpu_dirty == 0) { - run_on_cpu(cpu_state, do_hvf_cpu_synchronize_state, RUN_ON_CPU_NULL); + if (!cpu->vcpu_dirty) { + hvf_get_registers(cpu); + cpu->vcpu_dirty = true; } } -static void do_hvf_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg) +void hvf_cpu_synchronize_state(CPUState *cpu) { - CPUState *cpu_state = cpu; - hvf_put_registers(cpu_state); - cpu_state->vcpu_dirty = false; + if (!cpu->vcpu_dirty) { + run_on_cpu(cpu, do_hvf_cpu_synchronize_state, RUN_ON_CPU_NULL); + } } -void hvf_cpu_synchronize_post_reset(CPUState *cpu_state) +static void do_hvf_cpu_synchronize_post_reset(CPUState *cpu, + run_on_cpu_data arg) { - run_on_cpu(cpu_state, do_hvf_cpu_synchronize_post_reset, RUN_ON_CPU_NULL); + hvf_put_registers(cpu); + cpu->vcpu_dirty = false; +} + +void hvf_cpu_synchronize_post_reset(CPUState *cpu) +{ + run_on_cpu(cpu, do_hvf_cpu_synchronize_post_reset, RUN_ON_CPU_NULL); } static void do_hvf_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) { - CPUState *cpu_state = cpu; - hvf_put_registers(cpu_state); - cpu_state->vcpu_dirty = false; + hvf_put_registers(cpu); + cpu->vcpu_dirty = false; } -void hvf_cpu_synchronize_post_init(CPUState *cpu_state) +void hvf_cpu_synchronize_post_init(CPUState *cpu) { - run_on_cpu(cpu_state, do_hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL); + run_on_cpu(cpu, do_hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL); } static void do_hvf_cpu_synchronize_pre_loadvm(CPUState *cpu, From de6b528be41fabfdde32982ba62f2cddc7e10330 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 25 Jun 2020 01:58:51 +0300 Subject: [PATCH 2112/2595] MAINTAINERS: Add Cameron as HVF co-maintainer Similar patch was sent a while ago but got lost. While at it, add a status wiki page. Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200624225850.16982-9-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6aa54f7f8f..ee89d67d68 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -417,7 +417,9 @@ F: target/i386/kvm.c F: scripts/kvm/vmxcap X86 HVF CPUs +M: Cameron Esfahani M: Roman Bolshakov +W: https://wiki.qemu.org/Features/HVF S: Maintained F: accel/stubs/hvf-stub.c F: target/i386/hvf/ From a6bb42f2239b85fccf93734bfb73bb8b2ddc8cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:33 +0200 Subject: [PATCH 2113/2595] MAINTAINERS: Fix KVM path expansion glob MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The KVM files has been moved from target-ARCH to the target/ARCH/ folder in commit fcf5ef2a. Fix the pathname expansion. Fixes: fcf5ef2a ("Move target-* CPU file into a target/ folder") Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index ee89d67d68..4f001eda15 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -362,7 +362,7 @@ Overall KVM CPUs M: Paolo Bonzini L: kvm@vger.kernel.org S: Supported -F: */kvm.* +F: */*/kvm* F: accel/kvm/ F: accel/stubs/kvm-stub.c F: include/hw/kvm/ From 79ac391592c4853bc4d83bba6e513324ea56e44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:34 +0200 Subject: [PATCH 2114/2595] MAINTAINERS: Add an 'overall' entry for accelerators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4f001eda15..39bea4a0f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -416,6 +416,17 @@ S: Supported F: target/i386/kvm.c F: scripts/kvm/vmxcap +Guest CPU Cores (other accelerators) +------------------------------------ +Overall +M: Richard Henderson +R: Paolo Bonzini +S: Maintained +F: include/sysemu/accel.h +F: accel/accel.c +F: accel/Makefile.objs +F: accel/stubs/Makefile.objs + X86 HVF CPUs M: Cameron Esfahani M: Roman Bolshakov From f7091f5f052a6173a563319cb8c6c48f861276d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:35 +0200 Subject: [PATCH 2115/2595] MAINTAINERS: Cover the HAX accelerator stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cover accel/stubs/hax-stub.c in the HAXM section. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 39bea4a0f1..51f6ddf814 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -478,6 +478,7 @@ M: Colin Xu L: haxm-team@intel.com W: https://github.com/intel/haxm/issues S: Maintained +F: accel/stubs/hax-stub.c F: include/sysemu/hax.h F: target/i386/hax-* From f4bda37d3d580d5d28a07f7290f23be005322c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:37 +0200 Subject: [PATCH 2116/2595] Makefile: Remove dangerous EOL trailing backslash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One might get caught trying to understand unexpected Makefile behavior. Trailing backslash can help to split very long lines, but are rather dangerous when nothing follow. Preserve other developers debugging time by removing this one. Reviewed-by: Thomas Huth Reviewed-by: Alistair Francis Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b1b8a5a6d0..e7d8f1f027 100644 --- a/Makefile +++ b/Makefile @@ -420,7 +420,7 @@ MINIKCONF_ARGS = \ MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/backends/Kconfig $(SRC_PATH)/hw/Kconfig MINIKCONF_DEPS = $(MINIKCONF_INPUTS) $(wildcard $(SRC_PATH)/hw/*/Kconfig) -MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \ +MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py $(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_DEPS) $(BUILD_DIR)/config-host.mak $(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) > $@.tmp, "GEN", "$@.tmp") From 1e0ef873d9b271d373ce6d3aac6c99552b0d4a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:38 +0200 Subject: [PATCH 2117/2595] Makefile: Write MINIKCONF variables as one entry per line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having one entry per line helps reviews/refactors. As we are going to modify the MINIKCONF variables, split them now to ease further review. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- Makefile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index e7d8f1f027..b96a2d8790 100644 --- a/Makefile +++ b/Makefile @@ -418,12 +418,16 @@ MINIKCONF_ARGS = \ CONFIG_LINUX=$(CONFIG_LINUX) \ CONFIG_PVRDMA=$(CONFIG_PVRDMA) -MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/backends/Kconfig $(SRC_PATH)/hw/Kconfig -MINIKCONF_DEPS = $(MINIKCONF_INPUTS) $(wildcard $(SRC_PATH)/hw/*/Kconfig) +MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host \ + $(SRC_PATH)/backends/Kconfig \ + $(SRC_PATH)/hw/Kconfig +MINIKCONF_DEPS = $(MINIKCONF_INPUTS) \ + $(wildcard $(SRC_PATH)/hw/*/Kconfig) MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py $(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_DEPS) $(BUILD_DIR)/config-host.mak - $(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) > $@.tmp, "GEN", "$@.tmp") + $(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) \ + > $@.tmp, "GEN", "$@.tmp") $(call quiet-command, if test -f $@; then \ if cmp -s $@.old $@; then \ mv $@.tmp $@; \ From 06e89e13be25ef48196cb8ff40e9aeb3bf72f86b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:39 +0200 Subject: [PATCH 2118/2595] accel/Kconfig: Extract accel selectors into their own config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the accel selectors from the global Kconfig.host to their own Kconfig file. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- Kconfig.host | 7 ------- Makefile | 1 + accel/Kconfig | 6 ++++++ 3 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 accel/Kconfig diff --git a/Kconfig.host b/Kconfig.host index 55136e037d..a6d871c399 100644 --- a/Kconfig.host +++ b/Kconfig.host @@ -2,9 +2,6 @@ # down to Kconfig. See also MINIKCONF_ARGS in the Makefile: # these two need to be kept in sync. -config KVM - bool - config LINUX bool @@ -31,10 +28,6 @@ config VHOST_KERNEL bool select VHOST -config XEN - bool - select FSDEV_9P if VIRTFS - config VIRTFS bool diff --git a/Makefile b/Makefile index b96a2d8790..ae025d41ea 100644 --- a/Makefile +++ b/Makefile @@ -420,6 +420,7 @@ MINIKCONF_ARGS = \ MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host \ $(SRC_PATH)/backends/Kconfig \ + $(SRC_PATH)/accel/Kconfig \ $(SRC_PATH)/hw/Kconfig MINIKCONF_DEPS = $(MINIKCONF_INPUTS) \ $(wildcard $(SRC_PATH)/hw/*/Kconfig) diff --git a/accel/Kconfig b/accel/Kconfig new file mode 100644 index 0000000000..c21802bb49 --- /dev/null +++ b/accel/Kconfig @@ -0,0 +1,6 @@ +config KVM + bool + +config XEN + bool + select FSDEV_9P if VIRTFS From 96df0fdd7f14107c1fb223742340c76669bcc9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:40 +0200 Subject: [PATCH 2119/2595] accel/Kconfig: Add the TCG selector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose the CONFIG_TCG selector to let minikconf.py uses it. When building with --disable-tcg build, this helps to deselect devices that are TCG-dependent. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- Makefile | 1 + accel/Kconfig | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Makefile b/Makefile index ae025d41ea..d4a971283c 100644 --- a/Makefile +++ b/Makefile @@ -405,6 +405,7 @@ endif MINIKCONF_ARGS = \ $(CONFIG_MINIKCONF_MODE) \ $@ $*/config-devices.mak.d $< $(MINIKCONF_INPUTS) \ + CONFIG_TCG=$(CONFIG_TCG) \ CONFIG_KVM=$(CONFIG_KVM) \ CONFIG_SPICE=$(CONFIG_SPICE) \ CONFIG_IVSHMEM=$(CONFIG_IVSHMEM) \ diff --git a/accel/Kconfig b/accel/Kconfig index c21802bb49..2ad94a3839 100644 --- a/accel/Kconfig +++ b/accel/Kconfig @@ -1,3 +1,6 @@ +config TCG + bool + config KVM bool From bb321b299e6879cd602bf6509eeecd62d3098d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:42 +0200 Subject: [PATCH 2120/2595] accel/tcg: Add stub for probe_access() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TCG helpers were added in b92e5a22ec3 in softmmu_template.h. probe_write() was added in there in 3b4afc9e75a to be moved out to accel/tcg/cputlb.c in 3b08f0a9254, and was later refactored as probe_access() in c25c283df0f. Since it is a TCG specific helper, add a stub to avoid failures when building without TCG, such: target/arm/helper.o: In function `probe_read': include/exec/exec-all.h:362: undefined reference to `probe_access' Reviewed-by: Richard Henderson Reviewed-by: David Hildenbrand Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- accel/stubs/tcg-stub.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c index 677191a69c..e4bbf997aa 100644 --- a/accel/stubs/tcg-stub.c +++ b/accel/stubs/tcg-stub.c @@ -22,3 +22,10 @@ void tb_flush(CPUState *cpu) void tlb_set_dirty(CPUState *cpu, target_ulong vaddr) { } + +void *probe_access(CPUArchState *env, target_ulong addr, int size, + MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) +{ + /* Handled by hardware accelerator. */ + g_assert_not_reached(); +} From aaa1b70a0bb1fc1357c6c6828bcc8ff702e7eac4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Jun 2020 07:18:16 -0400 Subject: [PATCH 2121/2595] Makefile: simplify MINIKCONF rules There is no reason to write MINIKCONF_DEPS manually, since minikconf.py emits a dependency file, and also no reason to list multiple Kconfig files on the command line since they can be included from a master file in the top-level source directory. Signed-off-by: Paolo Bonzini --- Kconfig | 4 ++++ Makefile | 10 ++-------- 2 files changed, 6 insertions(+), 8 deletions(-) create mode 100644 Kconfig diff --git a/Kconfig b/Kconfig new file mode 100644 index 0000000000..bf694c42af --- /dev/null +++ b/Kconfig @@ -0,0 +1,4 @@ +source Kconfig.host +source backends/Kconfig +source accel/Kconfig +source hw/Kconfig diff --git a/Makefile b/Makefile index d4a971283c..32345c610e 100644 --- a/Makefile +++ b/Makefile @@ -404,7 +404,7 @@ endif # This has to be kept in sync with Kconfig.host. MINIKCONF_ARGS = \ $(CONFIG_MINIKCONF_MODE) \ - $@ $*/config-devices.mak.d $< $(MINIKCONF_INPUTS) \ + $@ $*/config-devices.mak.d $< $(SRC_PATH)/Kconfig \ CONFIG_TCG=$(CONFIG_TCG) \ CONFIG_KVM=$(CONFIG_KVM) \ CONFIG_SPICE=$(CONFIG_SPICE) \ @@ -419,15 +419,9 @@ MINIKCONF_ARGS = \ CONFIG_LINUX=$(CONFIG_LINUX) \ CONFIG_PVRDMA=$(CONFIG_PVRDMA) -MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host \ - $(SRC_PATH)/backends/Kconfig \ - $(SRC_PATH)/accel/Kconfig \ - $(SRC_PATH)/hw/Kconfig -MINIKCONF_DEPS = $(MINIKCONF_INPUTS) \ - $(wildcard $(SRC_PATH)/hw/*/Kconfig) MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py -$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_DEPS) $(BUILD_DIR)/config-host.mak +$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(SRC_PATH)/Kconfig $(BUILD_DIR)/config-host.mak $(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) \ > $@.tmp, "GEN", "$@.tmp") $(call quiet-command, if test -f $@; then \ From 6c9cce1ff348709869262e4bd15ad4fedf513f17 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Jun 2020 05:19:27 -0400 Subject: [PATCH 2122/2595] target/i386: remove gen_io_end Force the end of a translation block after an I/O instruction in icount mode. For consistency, all CF_USE_ICOUNT code is kept in disas_insn instead of having it in gen_ins and gen_outs. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/translate.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/target/i386/translate.c b/target/i386/translate.c index b3fea54411..5ef72ff401 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -1128,9 +1128,6 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot) static inline void gen_ins(DisasContext *s, MemOp ot) { - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } gen_string_movl_A0_EDI(s); /* Note: we must do this dummy write first to be restartable in case of page fault. */ @@ -1143,16 +1140,10 @@ static inline void gen_ins(DisasContext *s, MemOp ot) gen_op_movl_T0_Dshift(s, ot); gen_op_add_reg_T0(s, s->aflag, R_EDI); gen_bpt_io(s, s->tmp2_i32, ot); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } } static inline void gen_outs(DisasContext *s, MemOp ot) { - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } gen_string_movl_A0_ESI(s); gen_op_ld_v(s, ot, s->T0, s->A0); @@ -1163,9 +1154,6 @@ static inline void gen_outs(DisasContext *s, MemOp ot) gen_op_movl_T0_Dshift(s, ot); gen_op_add_reg_T0(s, s->aflag, R_ESI); gen_bpt_io(s, s->tmp2_i32, ot); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } } /* same method as Valgrind : we generate jumps to current or next @@ -6400,8 +6388,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]); gen_check_io(s, ot, pc_start - s->cs_base, SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4); + if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + /* jump generated by gen_repz_ins */ } else { gen_ins(s, ot); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { @@ -6415,8 +6407,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]); gen_check_io(s, ot, pc_start - s->cs_base, svm_is_rep(prefixes) | 4); + if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + /* jump generated by gen_repz_outs */ } else { gen_outs(s, ot); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { @@ -8039,7 +8035,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_helper_read_crN(s->T0, cpu_env, tcg_const_i32(reg)); gen_op_mov_reg_v(s, ot, rm, s->T0); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); + gen_jmp(s, s->pc - s->cs_base); } } break; From c0c8445255b2b5b440c355431c8b01b7b7b7c8cf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Jun 2020 05:53:36 -0400 Subject: [PATCH 2123/2595] target/i386: implement undocumented "smsw r32" behavior In 32-bit mode, the higher 16 bits of the destination register are undefined. In practice CR0[31:0] is stored, just like in 64-bit mode, so just remove the "if" that currently differentiates the behavior. Reviewed-by: Richard Henderson Reported-by: Roman Bolshakov Reviewed-by: Roman Bolshakov Signed-off-by: Paolo Bonzini --- target/i386/translate.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/target/i386/translate.c b/target/i386/translate.c index 5ef72ff401..a1d31f09c1 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -7579,12 +7579,13 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) CASE_MODRM_OP(4): /* smsw */ gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0); tcg_gen_ld_tl(s->T0, cpu_env, offsetof(CPUX86State, cr[0])); - if (CODE64(s)) { - mod = (modrm >> 6) & 3; - ot = (mod != 3 ? MO_16 : s->dflag); - } else { - ot = MO_16; - } + /* + * In 32-bit mode, the higher 16 bits of the destination + * register are undefined. In practice CR0[31:0] is stored + * just like in 64-bit mode. + */ + mod = (modrm >> 6) & 3; + ot = (mod != 3 ? MO_16 : s->dflag); gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1); break; case 0xee: /* rdpkru */ From e1e43813e7908b063938a3d01f172f88f6190c80 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 30 Jun 2020 09:49:27 -0400 Subject: [PATCH 2124/2595] KVM: x86: believe what KVM says about WAITPKG Currently, QEMU is overriding KVM_GET_SUPPORTED_CPUID's answer for the WAITPKG bit depending on the "-overcommit cpu-pm" setting. This is a bad idea because it does not even check if the host supports it, but it can be done in x86_cpu_realizefn just like we do for the MONITOR bit. This patch moves it there, while making it conditional on host support for the related UMWAIT MSR. Cc: qemu-stable@nongnu.org Reported-by: Maxim Levitsky Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 3 +++ target/i386/kvm.c | 11 +++++------ target/i386/kvm_i386.h | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 1546cd78ff..105eb47eab 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6509,6 +6509,9 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) host_cpuid(5, 0, &cpu->mwait.eax, &cpu->mwait.ebx, &cpu->mwait.ecx, &cpu->mwait.edx); env->features[FEAT_1_ECX] |= CPUID_EXT_MONITOR; + if (kvm_enabled() && kvm_has_waitpkg()) { + env->features[FEAT_7_0_ECX] |= CPUID_7_0_ECX_WAITPKG; + } } if (kvm_enabled() && cpu->ucode_rev == 0) { cpu->ucode_rev = kvm_arch_get_supported_msr_feature(kvm_state, diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 2b6b7443d2..b8455c89ed 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -411,12 +411,6 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, if (host_tsx_blacklisted()) { ret &= ~(CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_HLE); } - } else if (function == 7 && index == 0 && reg == R_ECX) { - if (enable_cpu_pm) { - ret |= CPUID_7_0_ECX_WAITPKG; - } else { - ret &= ~CPUID_7_0_ECX_WAITPKG; - } } else if (function == 7 && index == 0 && reg == R_EDX) { /* * Linux v4.17-v4.20 incorrectly return ARCH_CAPABILITIES on SVM hosts. @@ -4730,3 +4724,8 @@ int kvm_arch_msi_data_to_gsi(uint32_t data) { abort(); } + +bool kvm_has_waitpkg(void) +{ + return has_msr_umwait; +} diff --git a/target/i386/kvm_i386.h b/target/i386/kvm_i386.h index 00bde7acaf..064b8798a2 100644 --- a/target/i386/kvm_i386.h +++ b/target/i386/kvm_i386.h @@ -44,6 +44,7 @@ void kvm_put_apicbase(X86CPU *cpu, uint64_t value); bool kvm_enable_x2apic(void); bool kvm_has_x2apic_api(void); +bool kvm_has_waitpkg(void); bool kvm_hv_vpindex_settable(void); From e4f6278557148151e77260b872b41bcd7ceb4737 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 30 Jun 2020 11:35:46 -0400 Subject: [PATCH 2125/2595] target/i386: sev: provide proper error reporting for query-sev-capabilities The query-sev-capabilities was reporting errors through error_report; change it to use Error** so that the cause of the failure is clearer. Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini --- target/i386/monitor.c | 10 +--------- target/i386/sev-stub.c | 3 ++- target/i386/sev.c | 18 +++++++++--------- target/i386/sev_i386.h | 2 +- 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/target/i386/monitor.c b/target/i386/monitor.c index 27ebfa3ad2..7abae3c8df 100644 --- a/target/i386/monitor.c +++ b/target/i386/monitor.c @@ -726,13 +726,5 @@ SevLaunchMeasureInfo *qmp_query_sev_launch_measure(Error **errp) SevCapability *qmp_query_sev_capabilities(Error **errp) { - SevCapability *data; - - data = sev_get_capabilities(); - if (!data) { - error_setg(errp, "SEV feature is not available"); - return NULL; - } - - return data; + return sev_get_capabilities(errp); } diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c index e5ee13309c..88e3f39a1e 100644 --- a/target/i386/sev-stub.c +++ b/target/i386/sev-stub.c @@ -44,7 +44,8 @@ char *sev_get_launch_measurement(void) return NULL; } -SevCapability *sev_get_capabilities(void) +SevCapability *sev_get_capabilities(Error **errp) { + error_setg(errp, "SEV is not available in this QEMU"); return NULL; } diff --git a/target/i386/sev.c b/target/i386/sev.c index f100a53231..7012b1d4b1 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -399,7 +399,7 @@ sev_get_info(void) static int sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain, - size_t *cert_chain_len) + size_t *cert_chain_len, Error **errp) { guchar *pdh_data = NULL; guchar *cert_chain_data = NULL; @@ -410,8 +410,8 @@ sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain, r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err); if (r < 0) { if (err != SEV_RET_INVALID_LEN) { - error_report("failed to export PDH cert ret=%d fw_err=%d (%s)", - r, err, fw_error_to_str(err)); + error_setg(errp, "failed to export PDH cert ret=%d fw_err=%d (%s)", + r, err, fw_error_to_str(err)); return 1; } } @@ -423,8 +423,8 @@ sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain, r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err); if (r < 0) { - error_report("failed to export PDH cert ret=%d fw_err=%d (%s)", - r, err, fw_error_to_str(err)); + error_setg(errp, "failed to export PDH cert ret=%d fw_err=%d (%s)", + r, err, fw_error_to_str(err)); goto e_free; } @@ -441,7 +441,7 @@ e_free: } SevCapability * -sev_get_capabilities(void) +sev_get_capabilities(Error **errp) { SevCapability *cap = NULL; guchar *pdh_data = NULL; @@ -452,13 +452,13 @@ sev_get_capabilities(void) fd = open(DEFAULT_SEV_DEVICE, O_RDWR); if (fd < 0) { - error_report("%s: Failed to open %s '%s'", __func__, - DEFAULT_SEV_DEVICE, strerror(errno)); + error_setg_errno(errp, errno, "Failed to open %s", + DEFAULT_SEV_DEVICE); return NULL; } if (sev_get_pdh_info(fd, &pdh_data, &pdh_len, - &cert_chain_data, &cert_chain_len)) { + &cert_chain_data, &cert_chain_len, errp)) { goto out; } diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h index 8eb7de1bef..4db6960f60 100644 --- a/target/i386/sev_i386.h +++ b/target/i386/sev_i386.h @@ -34,6 +34,6 @@ extern SevInfo *sev_get_info(void); extern uint32_t sev_get_cbit_position(void); extern uint32_t sev_get_reduced_phys_bits(void); extern char *sev_get_launch_measurement(void); -extern SevCapability *sev_get_capabilities(void); +extern SevCapability *sev_get_capabilities(Error **errp); #endif From 1b38750c40281dd0d068f8536b2ea95d7b9bd585 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 30 Jun 2020 11:38:18 -0400 Subject: [PATCH 2126/2595] target/i386: sev: fail query-sev-capabilities if QEMU cannot use SEV In some cases, such as if the kvm-amd "sev" module parameter is set to 0, SEV will be unavailable but query-sev-capabilities will still return all the information. This tricks libvirt into erroneously reporting that SEV is available. Check the actual usability of the feature and return the appropriate error if QEMU cannot use KVM or KVM cannot use SEV. Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/i386/sev.c b/target/i386/sev.c index 7012b1d4b1..c3ecf86704 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -450,6 +450,15 @@ sev_get_capabilities(Error **errp) uint32_t ebx; int fd; + if (!kvm_enabled()) { + error_setg(errp, "KVM not enabled"); + return NULL; + } + if (kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, NULL) < 0) { + error_setg(errp, "SEV is not enabled in KVM"); + return NULL; + } + fd = open(DEFAULT_SEV_DEVICE, O_RDWR); if (fd < 0) { error_setg_errno(errp, errno, "Failed to open %s", From dd3b00202a5ff4153a0088917ac69d2e6cd2bc1f Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Wed, 1 Jul 2020 18:54:43 +0800 Subject: [PATCH 2127/2595] iscsi: handle check condition status in retry loop The handling of check condition was incorrect because we would only do it after retries exceed maximum. Fixes: 8c460269aa ("iscsi: base all handling of check condition on scsi_sense_to_errno") Signed-off-by: Xie Yongji Message-Id: <20200701105444.3226-1-xieyongji@bytedance.com> Signed-off-by: Paolo Bonzini --- block/iscsi.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index 6c2e353e1a..7519b0970f 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -266,16 +266,16 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, timer_mod(&iTask->retry_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + retry_time); iTask->do_retry = 1; - } - } else if (status == SCSI_STATUS_CHECK_CONDITION) { - int error = iscsi_translate_sense(&task->sense); - if (error == EAGAIN) { - error_report("iSCSI CheckCondition: %s", - iscsi_get_error(iscsi)); - iTask->do_retry = 1; - } else { - iTask->err_code = -error; - iTask->err_str = g_strdup(iscsi_get_error(iscsi)); + } else if (status == SCSI_STATUS_CHECK_CONDITION) { + int error = iscsi_translate_sense(&task->sense); + if (error == EAGAIN) { + error_report("iSCSI CheckCondition: %s", + iscsi_get_error(iscsi)); + iTask->do_retry = 1; + } else { + iTask->err_code = -error; + iTask->err_str = g_strdup(iscsi_get_error(iscsi)); + } } } } From c58daf76a6d9aee7502d0fcd5f3e7ec9b9861646 Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Wed, 1 Jul 2020 18:54:44 +0800 Subject: [PATCH 2128/2595] iscsi: return -EIO when sense fields are meaningless When an I/O request failed, now we only return correct value on scsi check condition. We should also have a default errno such as -EIO in other case. Signed-off-by: Xie Yongji Message-Id: <20200701105444.3226-2-xieyongji@bytedance.com> Signed-off-by: Paolo Bonzini --- block/iscsi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/block/iscsi.c b/block/iscsi.c index 7519b0970f..bd2122a3a4 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -241,9 +241,11 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, iTask->status = status; iTask->do_retry = 0; + iTask->err_code = 0; iTask->task = task; if (status != SCSI_STATUS_GOOD) { + iTask->err_code = -EIO; if (iTask->retries++ < ISCSI_CMD_RETRIES) { if (status == SCSI_STATUS_BUSY || status == SCSI_STATUS_TIMEOUT || From 143a768c57b8d77b348f727c55f073eb40360955 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 20 Jun 2020 15:32:07 +0200 Subject: [PATCH 2129/2595] checkpatch: Change occurences of 'kernel' to 'qemu' in user messages It is odd that we inform user that, for example, his current working directory is not kernel root, when, in face, we mean qemu root. Replace that and few other similar odd user messages. Signed-off-by: Aleksandar Markovic Message-Id: <20200620133207.26849-3-aleksandar.qemu.devel@gmail.com> Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- scripts/checkpatch.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 2d2e922d89..bd3faa154c 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -49,7 +49,7 @@ Version: $V Options: -q, --quiet quiet - --no-tree run without a kernel tree + --no-tree run without a qemu tree --no-signoff do not check for 'Signed-off-by' line --patch treat FILE as patchfile --branch treat args as GIT revision list @@ -57,7 +57,7 @@ Options: --terse one line per report -f, --file treat FILE as regular source file --strict fail if only warnings are found - --root=PATH PATH to the kernel tree root + --root=PATH PATH to the qemu tree root --no-summary suppress the per-file summary --mailback only produce a report in case of warnings/errors --summary-file include the filename in summary @@ -203,7 +203,7 @@ if ($tree) { } if (!defined $root) { - print "Must be run from the top-level dir. of a kernel tree\n"; + print "Must be run from the top-level dir. of a qemu tree\n"; exit(2); } } From cbe0dad1906d29d9ea83169b672e9e709c9fc1f8 Mon Sep 17 00:00:00 2001 From: Luwei Kang Date: Tue, 30 Jun 2020 14:38:33 +0800 Subject: [PATCH 2130/2595] target/i386: Correct the warning message of Intel PT The CPUID level need to be set to 0x14 manually on old machine-type if Intel PT is enabled in guest. E.g. the CPUID[0].EAX(level)=7 and CPUID[7].EBX[25](intel-pt)=1 when the Qemu with "-machine pc-i440fx-3.1 -cpu qemu64,+intel-pt" parameter. This patch corrects the warning message of the previous submission(ddc2fc9). Signed-off-by: Luwei Kang Message-Id: <1593499113-4768-1-git-send-email-luwei.kang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 105eb47eab..1dde34dce7 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6398,7 +6398,7 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) } else if (cpu->env.cpuid_min_level < 0x14) { mark_unavailable_features(cpu, FEAT_7_0_EBX, CPUID_7_0_EBX_INTEL_PT, - "Intel PT need CPUID leaf 0x14, please set by \"-cpu ...,+intel-pt,level=0x14\""); + "Intel PT need CPUID leaf 0x14, please set by \"-cpu ...,+intel-pt,min-level=0x14\""); } } From 421a75e283f6bad2ac64119ecf6a1dfd3ebfda61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 2 Jul 2020 12:40:17 +0200 Subject: [PATCH 2131/2595] cpus: Move CPU code from exec.c to cpus-common.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code was introduced with SMP support in commit 6a00d60127, later commit 267f685b8b moved CPU list management to common code but forgot this code. Move now and simplify ifdef'ry. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200702104017.14057-1-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- cpus-common.c | 18 ++++++++++++++++++ exec.c | 22 ---------------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/cpus-common.c b/cpus-common.c index 8f5512b3d7..34044f4e4c 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -72,6 +72,8 @@ static int cpu_get_free_index(void) return max_cpu_index; } +CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus); + void cpu_list_add(CPUState *cpu) { QEMU_LOCK_GUARD(&qemu_cpu_list_lock); @@ -96,6 +98,22 @@ void cpu_list_remove(CPUState *cpu) cpu->cpu_index = UNASSIGNED_CPU_INDEX; } +CPUState *qemu_get_cpu(int index) +{ + CPUState *cpu; + + CPU_FOREACH(cpu) { + if (cpu->cpu_index == index) { + return cpu; + } + } + + return NULL; +} + +/* current CPU in the current thread. It is only valid inside cpu_exec() */ +__thread CPUState *current_cpu; + struct qemu_work_item { QSIMPLEQ_ENTRY(qemu_work_item) node; run_on_cpu_func func; diff --git a/exec.c b/exec.c index 893636176e..6f381f98e2 100644 --- a/exec.c +++ b/exec.c @@ -98,12 +98,6 @@ AddressSpace address_space_memory; static MemoryRegion io_mem_unassigned; #endif -CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus); - -/* current CPU in the current thread. It is only valid inside - cpu_exec() */ -__thread CPUState *current_cpu; - uintptr_t qemu_host_page_size; intptr_t qemu_host_page_mask; @@ -832,22 +826,6 @@ const VMStateDescription vmstate_cpu_common = { } }; -#endif - -CPUState *qemu_get_cpu(int index) -{ - CPUState *cpu; - - CPU_FOREACH(cpu) { - if (cpu->cpu_index == index) { - return cpu; - } - } - - return NULL; -} - -#if !defined(CONFIG_USER_ONLY) void cpu_address_space_init(CPUState *cpu, int asidx, const char *prefix, MemoryRegion *mr) { From 0b33521ea16463d7f942ddb2b354fa029c96231f Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Wed, 1 Jul 2020 10:52:31 -0400 Subject: [PATCH 2132/2595] pc: fix leak in pc_system_flash_cleanup_unused tries to fix a leak detected when building with --enable-sanitizers: ./i386-softmmu/qemu-system-i386 Upon exit: ==13576==ERROR: LeakSanitizer: detected memory leaks Direct leak of 1216 byte(s) in 1 object(s) allocated from: #0 0x7f9d2ed5c628 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5) #1 0x7f9d2e963500 in g_malloc (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.) #2 0x55fa646d25cc in object_new_with_type /tmp/qemu/qom/object.c:686 #3 0x55fa63dbaa88 in qdev_new /tmp/qemu/hw/core/qdev.c:140 #4 0x55fa638a533f in pc_pflash_create /tmp/qemu/hw/i386/pc_sysfw.c:88 #5 0x55fa638a54c4 in pc_system_flash_create /tmp/qemu/hw/i386/pc_sysfw.c:106 #6 0x55fa646caa1d in object_init_with_type /tmp/qemu/qom/object.c:369 #7 0x55fa646d20b5 in object_initialize_with_type /tmp/qemu/qom/object.c:511 #8 0x55fa646d2606 in object_new_with_type /tmp/qemu/qom/object.c:687 #9 0x55fa639431e9 in qemu_init /tmp/qemu/softmmu/vl.c:3878 #10 0x55fa6335c1b8 in main /tmp/qemu/softmmu/main.c:48 #11 0x7f9d2cf06e0a in __libc_start_main ../csu/libc-start.c:308 #12 0x55fa6335f8e9 in _start (/tmp/qemu/build/i386-softmmu/qemu-system-i386) Signed-off-by: Alexander Bulekov Message-Id: <20200701145231.19531-1-alxndr@bu.edu> Signed-off-by: Paolo Bonzini --- hw/i386/pc_sysfw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index ec2a3b3e7e..71ce273a14 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -93,6 +93,11 @@ static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms, object_property_add_child(OBJECT(pcms), name, OBJECT(dev)); object_property_add_alias(OBJECT(pcms), alias_prop_name, OBJECT(dev), "drive"); + /* + * The returned reference is tied to the child property and + * will be removed with object_unparent. + */ + object_unref(OBJECT(dev)); return PFLASH_CFI01(dev); } From c7f419f5841a840f3b90e839ef014b94131e5df8 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 29 Jun 2020 11:35:02 +0200 Subject: [PATCH 2133/2595] softmmu: move softmmu only files from root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit move arch_init, balloon, cpus, ioport, memory, memory_mapping, qtest. They are all specific to CONFIG_SOFTMMU. Signed-off-by: Claudio Fontana Reviewed-by: Alex Bennée Reviewed-by: Laurent Vivier Reviewed-by: Thomas Huth Message-Id: <20200629093504.3228-2-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 12 ++++++------ Makefile.target | 7 ++----- softmmu/Makefile.objs | 10 ++++++++++ arch_init.c => softmmu/arch_init.c | 0 balloon.c => softmmu/balloon.c | 0 cpus.c => softmmu/cpus.c | 0 ioport.c => softmmu/ioport.c | 0 memory.c => softmmu/memory.c | 0 memory_mapping.c => softmmu/memory_mapping.c | 0 qtest.c => softmmu/qtest.c | 0 10 files changed, 18 insertions(+), 11 deletions(-) rename arch_init.c => softmmu/arch_init.c (100%) rename balloon.c => softmmu/balloon.c (100%) rename cpus.c => softmmu/cpus.c (100%) rename ioport.c => softmmu/ioport.c (100%) rename memory.c => softmmu/memory.c (100%) rename memory_mapping.c => softmmu/memory_mapping.c (100%) rename qtest.c => softmmu/qtest.c (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 51f6ddf814..28f33123ec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -115,7 +115,7 @@ Overall TCG CPUs M: Richard Henderson R: Paolo Bonzini S: Maintained -F: cpus.c +F: softmmu/cpus.c F: cpus-common.c F: exec.c F: accel/tcg/ @@ -1724,7 +1724,7 @@ M: David Hildenbrand S: Maintained F: hw/virtio/virtio-balloon*.c F: include/hw/virtio/virtio-balloon.h -F: balloon.c +F: softmmu/balloon.c F: include/sysemu/balloon.h virtio-9p @@ -2203,12 +2203,12 @@ Memory API M: Paolo Bonzini S: Supported F: include/exec/ioport.h -F: ioport.c F: include/exec/memop.h F: include/exec/memory.h F: include/exec/ram_addr.h F: include/exec/ramblock.h -F: memory.c +F: softmmu/ioport.c +F: softmmu/memory.c F: include/exec/memory-internal.h F: exec.c F: scripts/coccinelle/memory-region-housekeeping.cocci @@ -2240,13 +2240,13 @@ F: ui/cocoa.m Main loop M: Paolo Bonzini S: Maintained -F: cpus.c F: include/qemu/main-loop.h F: include/sysemu/runstate.h F: util/main-loop.c F: util/qemu-timer.c F: softmmu/vl.c F: softmmu/main.c +F: softmmu/cpus.c F: qapi/run-state.json Human Monitor (HMP) @@ -2401,7 +2401,7 @@ M: Thomas Huth M: Laurent Vivier R: Paolo Bonzini S: Maintained -F: qtest.c +F: softmmu/qtest.c F: accel/qtest.c F: tests/qtest/ X: tests/qtest/bios-tables-test-allowed-diff.h diff --git a/Makefile.target b/Makefile.target index 02bd9d7117..ffa2657269 100644 --- a/Makefile.target +++ b/Makefile.target @@ -152,16 +152,13 @@ endif #CONFIG_BSD_USER ######################################################### # System emulator target ifdef CONFIG_SOFTMMU -obj-y += arch_init.o cpus.o gdbstub.o balloon.o ioport.o -obj-y += qtest.o +obj-y += softmmu/ +obj-y += gdbstub.o obj-y += dump/ obj-y += hw/ obj-y += monitor/ obj-y += qapi/ -obj-y += memory.o -obj-y += memory_mapping.o obj-y += migration/ram.o -obj-y += softmmu/ LIBS := $(libs_softmmu) $(LIBS) # Hardware support diff --git a/softmmu/Makefile.objs b/softmmu/Makefile.objs index dd15c24346..a4bd9f2f52 100644 --- a/softmmu/Makefile.objs +++ b/softmmu/Makefile.objs @@ -1,3 +1,13 @@ softmmu-main-y = softmmu/main.o + +obj-y += arch_init.o +obj-y += cpus.o +obj-y += balloon.o +obj-y += ioport.o +obj-y += memory.o +obj-y += memory_mapping.o + +obj-y += qtest.o + obj-y += vl.o vl.o-cflags := $(GPROF_CFLAGS) $(SDL_CFLAGS) diff --git a/arch_init.c b/softmmu/arch_init.c similarity index 100% rename from arch_init.c rename to softmmu/arch_init.c diff --git a/balloon.c b/softmmu/balloon.c similarity index 100% rename from balloon.c rename to softmmu/balloon.c diff --git a/cpus.c b/softmmu/cpus.c similarity index 100% rename from cpus.c rename to softmmu/cpus.c diff --git a/ioport.c b/softmmu/ioport.c similarity index 100% rename from ioport.c rename to softmmu/ioport.c diff --git a/memory.c b/softmmu/memory.c similarity index 100% rename from memory.c rename to softmmu/memory.c diff --git a/memory_mapping.c b/softmmu/memory_mapping.c similarity index 100% rename from memory_mapping.c rename to softmmu/memory_mapping.c diff --git a/qtest.c b/softmmu/qtest.c similarity index 100% rename from qtest.c rename to softmmu/qtest.c From b0c3cf9407e642d74d1bbd18f8846872152a92df Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 29 Jun 2020 11:35:03 +0200 Subject: [PATCH 2134/2595] cpu-throttle: new module, extracted from cpus.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit move the vcpu throttling functionality into its own module. This functionality is not specific to any accelerator, and it is used currently by migration to slow down guests to try to have migrations converge, and by the cocoa MacOS UI to throttle speed. cpu-throttle contains the controls to adjust and inspect throttle settings, start (set) and stop vcpu throttling, and the throttling function itself that is run periodically on vcpus to make them take a nap. Execution of the throttling function on all vcpus is triggered by a timer, registered at module initialization. No functionality change. Signed-off-by: Claudio Fontana Reviewed-by: Alex Bennée Reviewed-by: Laurent Vivier Message-Id: <20200629093504.3228-3-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 1 + include/hw/core/cpu.h | 37 ----------- include/qemu/main-loop.h | 5 ++ include/sysemu/cpu-throttle.h | 68 +++++++++++++++++++ migration/migration.c | 1 + migration/ram.c | 1 + softmmu/Makefile.objs | 1 + softmmu/cpu-throttle.c | 122 ++++++++++++++++++++++++++++++++++ softmmu/cpus.c | 95 +++----------------------- ui/cocoa.m | 1 + 10 files changed, 208 insertions(+), 124 deletions(-) create mode 100644 include/sysemu/cpu-throttle.h create mode 100644 softmmu/cpu-throttle.c diff --git a/MAINTAINERS b/MAINTAINERS index 28f33123ec..361ae5c662 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2247,6 +2247,7 @@ F: util/qemu-timer.c F: softmmu/vl.c F: softmmu/main.c F: softmmu/cpus.c +F: softmmu/cpu-throttle.c F: qapi/run-state.json Human Monitor (HMP) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index b3f4b79318..5542577d2b 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -822,43 +822,6 @@ bool cpu_exists(int64_t id); */ CPUState *cpu_by_arch_id(int64_t id); -/** - * cpu_throttle_set: - * @new_throttle_pct: Percent of sleep time. Valid range is 1 to 99. - * - * Throttles all vcpus by forcing them to sleep for the given percentage of - * time. A throttle_percentage of 25 corresponds to a 75% duty cycle roughly. - * (example: 10ms sleep for every 30ms awake). - * - * cpu_throttle_set can be called as needed to adjust new_throttle_pct. - * Once the throttling starts, it will remain in effect until cpu_throttle_stop - * is called. - */ -void cpu_throttle_set(int new_throttle_pct); - -/** - * cpu_throttle_stop: - * - * Stops the vcpu throttling started by cpu_throttle_set. - */ -void cpu_throttle_stop(void); - -/** - * cpu_throttle_active: - * - * Returns: %true if the vcpus are currently being throttled, %false otherwise. - */ -bool cpu_throttle_active(void); - -/** - * cpu_throttle_get_percentage: - * - * Returns the vcpu throttle percentage. See cpu_throttle_set for details. - * - * Returns: The throttle percentage in range 1 to 99. - */ -int cpu_throttle_get_percentage(void); - #ifndef CONFIG_USER_ONLY typedef void (*CPUInterruptHandler)(CPUState *, int); diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index a6d20b0719..8e98613656 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -303,6 +303,11 @@ void qemu_mutex_unlock_iothread(void); */ void qemu_cond_wait_iothread(QemuCond *cond); +/* + * qemu_cond_timedwait_iothread: like the previous, but with timeout + */ +void qemu_cond_timedwait_iothread(QemuCond *cond, int ms); + /* internal interfaces */ void qemu_fd_register(int fd); diff --git a/include/sysemu/cpu-throttle.h b/include/sysemu/cpu-throttle.h new file mode 100644 index 0000000000..d65bdef6d0 --- /dev/null +++ b/include/sysemu/cpu-throttle.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012 SUSE LINUX Products GmbH + * + * 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 + * + */ + +#ifndef SYSEMU_CPU_THROTTLE_H +#define SYSEMU_CPU_THROTTLE_H + +#include "qemu/timer.h" + +/** + * cpu_throttle_init: + * + * Initialize the CPU throttling API. + */ +void cpu_throttle_init(void); + +/** + * cpu_throttle_set: + * @new_throttle_pct: Percent of sleep time. Valid range is 1 to 99. + * + * Throttles all vcpus by forcing them to sleep for the given percentage of + * time. A throttle_percentage of 25 corresponds to a 75% duty cycle roughly. + * (example: 10ms sleep for every 30ms awake). + * + * cpu_throttle_set can be called as needed to adjust new_throttle_pct. + * Once the throttling starts, it will remain in effect until cpu_throttle_stop + * is called. + */ +void cpu_throttle_set(int new_throttle_pct); + +/** + * cpu_throttle_stop: + * + * Stops the vcpu throttling started by cpu_throttle_set. + */ +void cpu_throttle_stop(void); + +/** + * cpu_throttle_active: + * + * Returns: %true if the vcpus are currently being throttled, %false otherwise. + */ +bool cpu_throttle_active(void); + +/** + * cpu_throttle_get_percentage: + * + * Returns the vcpu throttle percentage. See cpu_throttle_set for details. + * + * Returns: The throttle percentage in range 1 to 99. + */ +int cpu_throttle_get_percentage(void); + +#endif /* SYSEMU_CPU_THROTTLE_H */ diff --git a/migration/migration.c b/migration/migration.c index 92e44e021e..4e658c397e 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -23,6 +23,7 @@ #include "socket.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" +#include "sysemu/cpu-throttle.h" #include "rdma.h" #include "ram.h" #include "migration/global_state.h" diff --git a/migration/ram.c b/migration/ram.c index 5554a7d2d8..76d4fee5d5 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -52,6 +52,7 @@ #include "migration/colo.h" #include "block.h" #include "sysemu/sysemu.h" +#include "sysemu/cpu-throttle.h" #include "savevm.h" #include "qemu/iov.h" #include "multifd.h" diff --git a/softmmu/Makefile.objs b/softmmu/Makefile.objs index a4bd9f2f52..a414a74c50 100644 --- a/softmmu/Makefile.objs +++ b/softmmu/Makefile.objs @@ -2,6 +2,7 @@ softmmu-main-y = softmmu/main.o obj-y += arch_init.o obj-y += cpus.o +obj-y += cpu-throttle.o obj-y += balloon.o obj-y += ioport.o obj-y += memory.o diff --git a/softmmu/cpu-throttle.c b/softmmu/cpu-throttle.c new file mode 100644 index 0000000000..4e6b2818ca --- /dev/null +++ b/softmmu/cpu-throttle.c @@ -0,0 +1,122 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/thread.h" +#include "hw/core/cpu.h" +#include "qemu/main-loop.h" +#include "sysemu/cpus.h" +#include "sysemu/cpu-throttle.h" + +/* vcpu throttling controls */ +static QEMUTimer *throttle_timer; +static unsigned int throttle_percentage; + +#define CPU_THROTTLE_PCT_MIN 1 +#define CPU_THROTTLE_PCT_MAX 99 +#define CPU_THROTTLE_TIMESLICE_NS 10000000 + +static void cpu_throttle_thread(CPUState *cpu, run_on_cpu_data opaque) +{ + double pct; + double throttle_ratio; + int64_t sleeptime_ns, endtime_ns; + + if (!cpu_throttle_get_percentage()) { + return; + } + + pct = (double)cpu_throttle_get_percentage() / 100; + throttle_ratio = pct / (1 - pct); + /* Add 1ns to fix double's rounding error (like 0.9999999...) */ + sleeptime_ns = (int64_t)(throttle_ratio * CPU_THROTTLE_TIMESLICE_NS + 1); + endtime_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + sleeptime_ns; + while (sleeptime_ns > 0 && !cpu->stop) { + if (sleeptime_ns > SCALE_MS) { + qemu_cond_timedwait_iothread(cpu->halt_cond, + sleeptime_ns / SCALE_MS); + } else { + qemu_mutex_unlock_iothread(); + g_usleep(sleeptime_ns / SCALE_US); + qemu_mutex_lock_iothread(); + } + sleeptime_ns = endtime_ns - qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + } + atomic_set(&cpu->throttle_thread_scheduled, 0); +} + +static void cpu_throttle_timer_tick(void *opaque) +{ + CPUState *cpu; + double pct; + + /* Stop the timer if needed */ + if (!cpu_throttle_get_percentage()) { + return; + } + CPU_FOREACH(cpu) { + if (!atomic_xchg(&cpu->throttle_thread_scheduled, 1)) { + async_run_on_cpu(cpu, cpu_throttle_thread, + RUN_ON_CPU_NULL); + } + } + + pct = (double)cpu_throttle_get_percentage() / 100; + timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + + CPU_THROTTLE_TIMESLICE_NS / (1 - pct)); +} + +void cpu_throttle_set(int new_throttle_pct) +{ + /* Ensure throttle percentage is within valid range */ + new_throttle_pct = MIN(new_throttle_pct, CPU_THROTTLE_PCT_MAX); + new_throttle_pct = MAX(new_throttle_pct, CPU_THROTTLE_PCT_MIN); + + atomic_set(&throttle_percentage, new_throttle_pct); + + timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + + CPU_THROTTLE_TIMESLICE_NS); +} + +void cpu_throttle_stop(void) +{ + atomic_set(&throttle_percentage, 0); +} + +bool cpu_throttle_active(void) +{ + return (cpu_throttle_get_percentage() != 0); +} + +int cpu_throttle_get_percentage(void) +{ + return atomic_read(&throttle_percentage); +} + +void cpu_throttle_init(void) +{ + throttle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, + cpu_throttle_timer_tick, NULL); +} diff --git a/softmmu/cpus.c b/softmmu/cpus.c index d94456ed29..a802e899ab 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -61,6 +61,8 @@ #include "hw/boards.h" #include "hw/hw.h" +#include "sysemu/cpu-throttle.h" + #ifdef CONFIG_LINUX #include @@ -84,14 +86,6 @@ static QemuMutex qemu_global_mutex; int64_t max_delay; int64_t max_advance; -/* vcpu throttling controls */ -static QEMUTimer *throttle_timer; -static unsigned int throttle_percentage; - -#define CPU_THROTTLE_PCT_MIN 1 -#define CPU_THROTTLE_PCT_MAX 99 -#define CPU_THROTTLE_TIMESLICE_NS 10000000 - bool cpu_is_stopped(CPUState *cpu) { return cpu->stopped || !runstate_is_running(); @@ -738,90 +732,12 @@ static const VMStateDescription vmstate_timers = { } }; -static void cpu_throttle_thread(CPUState *cpu, run_on_cpu_data opaque) -{ - double pct; - double throttle_ratio; - int64_t sleeptime_ns, endtime_ns; - - if (!cpu_throttle_get_percentage()) { - return; - } - - pct = (double)cpu_throttle_get_percentage()/100; - throttle_ratio = pct / (1 - pct); - /* Add 1ns to fix double's rounding error (like 0.9999999...) */ - sleeptime_ns = (int64_t)(throttle_ratio * CPU_THROTTLE_TIMESLICE_NS + 1); - endtime_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + sleeptime_ns; - while (sleeptime_ns > 0 && !cpu->stop) { - if (sleeptime_ns > SCALE_MS) { - qemu_cond_timedwait(cpu->halt_cond, &qemu_global_mutex, - sleeptime_ns / SCALE_MS); - } else { - qemu_mutex_unlock_iothread(); - g_usleep(sleeptime_ns / SCALE_US); - qemu_mutex_lock_iothread(); - } - sleeptime_ns = endtime_ns - qemu_clock_get_ns(QEMU_CLOCK_REALTIME); - } - atomic_set(&cpu->throttle_thread_scheduled, 0); -} - -static void cpu_throttle_timer_tick(void *opaque) -{ - CPUState *cpu; - double pct; - - /* Stop the timer if needed */ - if (!cpu_throttle_get_percentage()) { - return; - } - CPU_FOREACH(cpu) { - if (!atomic_xchg(&cpu->throttle_thread_scheduled, 1)) { - async_run_on_cpu(cpu, cpu_throttle_thread, - RUN_ON_CPU_NULL); - } - } - - pct = (double)cpu_throttle_get_percentage()/100; - timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + - CPU_THROTTLE_TIMESLICE_NS / (1-pct)); -} - -void cpu_throttle_set(int new_throttle_pct) -{ - /* Ensure throttle percentage is within valid range */ - new_throttle_pct = MIN(new_throttle_pct, CPU_THROTTLE_PCT_MAX); - new_throttle_pct = MAX(new_throttle_pct, CPU_THROTTLE_PCT_MIN); - - atomic_set(&throttle_percentage, new_throttle_pct); - - timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + - CPU_THROTTLE_TIMESLICE_NS); -} - -void cpu_throttle_stop(void) -{ - atomic_set(&throttle_percentage, 0); -} - -bool cpu_throttle_active(void) -{ - return (cpu_throttle_get_percentage() != 0); -} - -int cpu_throttle_get_percentage(void) -{ - return atomic_read(&throttle_percentage); -} - void cpu_ticks_init(void) { seqlock_init(&timers_state.vm_clock_seqlock); qemu_spin_init(&timers_state.vm_clock_lock); vmstate_register(NULL, 0, &vmstate_timers, &timers_state); - throttle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, - cpu_throttle_timer_tick, NULL); + cpu_throttle_init(); } void configure_icount(QemuOpts *opts, Error **errp) @@ -1879,6 +1795,11 @@ void qemu_cond_wait_iothread(QemuCond *cond) qemu_cond_wait(cond, &qemu_global_mutex); } +void qemu_cond_timedwait_iothread(QemuCond *cond, int ms) +{ + qemu_cond_timedwait(cond, &qemu_global_mutex, ms); +} + static bool all_vcpus_paused(void) { CPUState *cpu; diff --git a/ui/cocoa.m b/ui/cocoa.m index cb556e4e66..0910b4a716 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -32,6 +32,7 @@ #include "ui/input.h" #include "sysemu/sysemu.h" #include "sysemu/runstate.h" +#include "sysemu/cpu-throttle.h" #include "qapi/error.h" #include "qapi/qapi-commands-block.h" #include "qapi/qapi-commands-misc.h" From 2f7057ac97579f940139ac85d8b757d47ef0efab Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 18 Jun 2020 09:40:01 +0200 Subject: [PATCH 2135/2595] softmmu/vl: Remove the check for colons in -accel parameters The new -accel option does not accept colons in the parameters anymore (since it does not convert the parameters to -machine accel=... parameters anymore). Thus we can now remove the check for colons in -accel: $ qemu-system-x86_64 -accel kvm:tcg qemu-system-x86_64: -accel kvm:tcg: invalid accelerator kvm:tcg Signed-off-by: Thomas Huth Reviewed-by: Claudio Fontana Message-Id: <20200618074001.13642-1-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- softmmu/vl.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index a7a2e9e44a..f476ef89ed 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -3506,11 +3506,6 @@ void qemu_init(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); - } break; case QEMU_OPTION_usb: olist = qemu_find_opts("machine"); From 5dd13f2a5b4d7335b2b0924e6fb28b63b34e70fe Mon Sep 17 00:00:00 2001 From: Cathy Zhang Date: Mon, 6 Jul 2020 07:17:15 +0800 Subject: [PATCH 2136/2595] target/i386: Add SERIALIZE cpu feature The availability of the SERIALIZATION instruction is indicated by the presence of the CPUID feature flag SERIALIZE, which is defined as CPUID.(EAX=7,ECX=0):ECX[bit 14]. The release spec link is as follows: https://software.intel.com/content/dam/develop/public/us/en/documents/\ architecture-instruction-set-extensions-programming-reference.pdf The associated kvm patch link is as follows: https://lore.kernel.org/patchwork/patch/1268025/ Signed-off-by: Cathy Zhang Message-Id: <1593991036-12183-2-git-send-email-cathy.zhang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 +- target/i386/cpu.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 1dde34dce7..a05d3a641b 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -986,7 +986,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { NULL, NULL, "avx512-4vnniw", "avx512-4fmaps", NULL, NULL, NULL, NULL, "avx512-vp2intersect", NULL, "md-clear", NULL, - NULL, NULL, NULL, NULL, + NULL, NULL, "serialize", NULL, NULL, NULL, NULL /* pconfig */, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "spec-ctrl", "stibp", diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 9284f96896..bd71fe3ef2 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -777,6 +777,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Vector Pair Intersection to a Pair of Mask Registers */ #define CPUID_7_0_EDX_AVX512_VP2INTERSECT (1U << 8) +/* SERIALIZE instruction */ +#define CPUID_7_0_EDX_SERIALIZE (1U << 14) /* Speculation Control */ #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Single Thread Indirect Branch Predictors */ From b3c7344e338b04be9feaf7ac6693c2f7fc951b89 Mon Sep 17 00:00:00 2001 From: Cathy Zhang Date: Mon, 6 Jul 2020 07:17:16 +0800 Subject: [PATCH 2137/2595] target/i386: Enable TSX Suspend Load Address Tracking feature This instruction aims to give a way to choose which memory accesses do not need to be tracked in the TSX read set, which is defined as CPUID.(EAX=7,ECX=0):EDX[bit 16]. The release spec link is as follows: https://software.intel.com/content/dam/develop/public/us/en/documents/\ architecture-instruction-set-extensions-programming-reference.pdf The associated kvm patch link is as follows: https://lore.kernel.org/patchwork/patch/1268026/ Signed-off-by: Cathy Zhang Message-Id: <1593991036-12183-3-git-send-email-cathy.zhang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 +- target/i386/cpu.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index a05d3a641b..1e5123251d 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -987,7 +987,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { NULL, NULL, NULL, NULL, "avx512-vp2intersect", NULL, "md-clear", NULL, NULL, NULL, "serialize", NULL, - NULL, NULL, NULL /* pconfig */, NULL, + "tsx-ldtrk", NULL, NULL /* pconfig */, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "spec-ctrl", "stibp", NULL, "arch-capabilities", "core-capability", "ssbd", diff --git a/target/i386/cpu.h b/target/i386/cpu.h index bd71fe3ef2..37fffa5cac 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -779,6 +779,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_EDX_AVX512_VP2INTERSECT (1U << 8) /* SERIALIZE instruction */ #define CPUID_7_0_EDX_SERIALIZE (1U << 14) +/* TSX Suspend Load Address Tracking instruction */ +#define CPUID_7_0_EDX_TSX_LDTRK (1U << 16) /* Speculation Control */ #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Single Thread Indirect Branch Predictors */ From 86f13ef31806e5f829ee3d9ed82694f44dd1c02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 6 Jul 2020 13:50:54 +0100 Subject: [PATCH 2138/2595] scripts: improve message when TAP based tests fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If one of the qtests fails, the TAP driver prints out a message like: ERROR - too few tests run (expected 3, got 1) which fails to tell you which test program failed. This is a critical ommission when many tests are running in parallel as their output is interleaved. The improved message is: ERROR endianness-test - too few tests run (expected 3, got 1) Signed-off-by: Daniel P. Berrangé Message-Id: <20200706125054.2619012-1-berrange@redhat.com> Signed-off-by: Paolo Bonzini --- scripts/tap-driver.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tap-driver.pl b/scripts/tap-driver.pl index 6621a5cd67..b1d3880c50 100755 --- a/scripts/tap-driver.pl +++ b/scripts/tap-driver.pl @@ -217,7 +217,7 @@ sub report ($;$) sub testsuite_error ($) { - report "ERROR", "- $_[0]"; + report "ERROR", "$test_name - $_[0]"; } sub handle_tap_result ($) From 6e083c0de41a606f304168fce75ea77f3c031f98 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 7 Feb 2020 07:43:42 +0100 Subject: [PATCH 2139/2595] apic: Report current_count via 'info lapic' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is helpful when debugging stuck guest timers. As we need apic_get_current_count for that, and it is really not emulation specific, move it to apic_common.c and export it. Fix its style at this chance as well. Signed-off-by: Jan Kiszka Reviewed-by: Philippe Mathieu-Daudé Message-Id: Signed-off-by: Paolo Bonzini --- hw/intc/apic.c | 18 ------------------ hw/intc/apic_common.c | 19 +++++++++++++++++++ include/hw/i386/apic_internal.h | 1 + target/i386/helper.c | 5 +++-- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 6b46839ef4..38aabd60cd 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -615,24 +615,6 @@ int apic_accept_pic_intr(DeviceState *dev) return 0; } -static uint32_t apic_get_current_count(APICCommonState *s) -{ - int64_t d; - uint32_t val; - d = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->initial_count_load_time) >> - s->count_shift; - if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { - /* periodic */ - val = s->initial_count - (d % ((uint64_t)s->initial_count + 1)); - } else { - if (d >= s->initial_count) - val = 0; - else - val = s->initial_count - d; - } - return val; -} - static void apic_timer_update(APICCommonState *s, int64_t current_time) { if (apic_next_timer(s, current_time)) { diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index dc070343c0..81addd6390 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -189,6 +189,25 @@ bool apic_next_timer(APICCommonState *s, int64_t current_time) return true; } +uint32_t apic_get_current_count(APICCommonState *s) +{ + int64_t d; + uint32_t val; + d = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->initial_count_load_time) >> + s->count_shift; + if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { + /* periodic */ + val = s->initial_count - (d % ((uint64_t)s->initial_count + 1)); + } else { + if (d >= s->initial_count) { + val = 0; + } else { + val = s->initial_count - d; + } + } + return val; +} + void apic_init_reset(DeviceState *dev) { APICCommonState *s; diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index b04bdd947f..2597000e03 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -211,6 +211,7 @@ void vapic_report_tpr_access(DeviceState *dev, CPUState *cpu, target_ulong ip, TPRAccess access); int apic_get_ppr(APICCommonState *s); +uint32_t apic_get_current_count(APICCommonState *s); static inline void apic_set_bit(uint32_t *tab, int index) { diff --git a/target/i386/helper.c b/target/i386/helper.c index fa2a1dcdda..70be53e2c3 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -370,10 +370,11 @@ void x86_cpu_dump_local_apic_state(CPUState *cs, int flags) dump_apic_lvt("LVTTHMR", lvt[APIC_LVT_THERMAL], false); dump_apic_lvt("LVTT", lvt[APIC_LVT_TIMER], true); - qemu_printf("Timer\t DCR=0x%x (divide by %u) initial_count = %u\n", + qemu_printf("Timer\t DCR=0x%x (divide by %u) initial_count = %u" + " current_count = %u\n", s->divide_conf & APIC_DCR_MASK, divider_conf(s->divide_conf), - s->initial_count); + s->initial_count, apic_get_current_count(s)); qemu_printf("SPIV\t 0x%08x APIC %s, focus=%s, spurious vec %u\n", s->spurious_vec, From 56908dc5041aa424fd1495b6c6beb78c539d93e1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 9 Jul 2020 14:27:34 -0400 Subject: [PATCH 2140/2595] linux-headers: update again to 5.8 5.8-rc1 inadvertently broke userspace ABI compatibility. Merge again with latest kvm/master to undo that. Signed-off-by: Paolo Bonzini --- linux-headers/asm-arm/unistd-common.h | 1 + linux-headers/asm-x86/kvm.h | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-headers/asm-arm/unistd-common.h b/linux-headers/asm-arm/unistd-common.h index 23de64e44c..57cd1f21db 100644 --- a/linux-headers/asm-arm/unistd-common.h +++ b/linux-headers/asm-arm/unistd-common.h @@ -392,5 +392,6 @@ #define __NR_clone3 (__NR_SYSCALL_BASE + 435) #define __NR_openat2 (__NR_SYSCALL_BASE + 437) #define __NR_pidfd_getfd (__NR_SYSCALL_BASE + 438) +#define __NR_faccessat2 (__NR_SYSCALL_BASE + 439) #endif /* _ASM_ARM_UNISTD_COMMON_H */ diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index 17c5a038f4..0780f97c18 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -408,14 +408,15 @@ struct kvm_vmx_nested_state_data { }; struct kvm_vmx_nested_state_hdr { - __u32 flags; __u64 vmxon_pa; __u64 vmcs12_pa; - __u64 preemption_timer_deadline; struct { __u16 flags; } smm; + + __u32 flags; + __u64 preemption_timer_deadline; }; struct kvm_svm_nested_state_data { From 84a71e9a447b50ddfc818aed4d626574423d7945 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:08 +0100 Subject: [PATCH 2141/2595] target/avr: Add instruction helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helpers for instructions that need to interact with QEMU. Also, add stubs for unimplemented instructions. Instructions SPM and WDR are left unimplemented because they require emulation of complex peripherals. The implementation of instruction SLEEP is very limited due to the lack of peripherals to generate wake interrupts. Memory access instructions are implemented here because some address ranges actually refer to CPU registers. Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-10-huth@tuxfamily.org> [PMD: Replace cpu_physical_memory() API by address_space_ldst() API to fix running on big-endian host, reported and suggested by Peter Maydell] Signed-off-by: Philippe Mathieu-Daudé --- target/avr/helper.c | 209 ++++++++++++++++++++++++++++++++++++++++++++ target/avr/helper.h | 29 ++++++ 2 files changed, 238 insertions(+) create mode 100644 target/avr/helper.h diff --git a/target/avr/helper.c b/target/avr/helper.c index d6985ff3f4..d96d14372b 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/exec-all.h" +#include "exec/address-spaces.h" #include "exec/helper-proto.h" bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) @@ -137,3 +138,211 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, return true; } + +/* + * helpers + */ + +void helper_sleep(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_HLT; + cpu_loop_exit(cs); +} + +void helper_unsupported(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + /* + * I count not find what happens on the real platform, so + * it's EXCP_DEBUG for meanwhile + */ + cs->exception_index = EXCP_DEBUG; + if (qemu_loglevel_mask(LOG_UNIMP)) { + qemu_log("UNSUPPORTED\n"); + cpu_dump_state(cs, stderr, 0); + } + cpu_loop_exit(cs); +} + +void helper_debug(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_DEBUG; + cpu_loop_exit(cs); +} + +void helper_break(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_DEBUG; + cpu_loop_exit(cs); +} + +void helper_wdr(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + /* WD is not implemented yet, placeholder */ + cs->exception_index = EXCP_DEBUG; + cpu_loop_exit(cs); +} + +/* + * This function implements IN instruction + * + * It does the following + * a. if an IO register belongs to CPU, its value is read and returned + * b. otherwise io address is translated to mem address and physical memory + * is read. + * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation + * + */ +target_ulong helper_inb(CPUAVRState *env, uint32_t port) +{ + target_ulong data = 0; + + switch (port) { + case 0x38: /* RAMPD */ + data = 0xff & (env->rampD >> 16); + break; + case 0x39: /* RAMPX */ + data = 0xff & (env->rampX >> 16); + break; + case 0x3a: /* RAMPY */ + data = 0xff & (env->rampY >> 16); + break; + case 0x3b: /* RAMPZ */ + data = 0xff & (env->rampZ >> 16); + break; + case 0x3c: /* EIND */ + data = 0xff & (env->eind >> 16); + break; + case 0x3d: /* SPL */ + data = env->sp & 0x00ff; + break; + case 0x3e: /* SPH */ + data = env->sp >> 8; + break; + case 0x3f: /* SREG */ + data = cpu_get_sreg(env); + break; + default: + /* not a special register, pass to normal memory access */ + data = address_space_ldub(&address_space_memory, + OFFSET_IO_REGISTERS + port, + MEMTXATTRS_UNSPECIFIED, NULL); + } + + return data; +} + +/* + * This function implements OUT instruction + * + * It does the following + * a. if an IO register belongs to CPU, its value is written into the register + * b. otherwise io address is translated to mem address and physical memory + * is written. + * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation + * + */ +void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) +{ + data &= 0x000000ff; + + switch (port) { + case 0x38: /* RAMPD */ + if (avr_feature(env, AVR_FEATURE_RAMPD)) { + env->rampD = (data & 0xff) << 16; + } + break; + case 0x39: /* RAMPX */ + if (avr_feature(env, AVR_FEATURE_RAMPX)) { + env->rampX = (data & 0xff) << 16; + } + break; + case 0x3a: /* RAMPY */ + if (avr_feature(env, AVR_FEATURE_RAMPY)) { + env->rampY = (data & 0xff) << 16; + } + break; + case 0x3b: /* RAMPZ */ + if (avr_feature(env, AVR_FEATURE_RAMPZ)) { + env->rampZ = (data & 0xff) << 16; + } + break; + case 0x3c: /* EIDN */ + env->eind = (data & 0xff) << 16; + break; + case 0x3d: /* SPL */ + env->sp = (env->sp & 0xff00) | (data); + break; + case 0x3e: /* SPH */ + if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { + env->sp = (env->sp & 0x00ff) | (data << 8); + } + break; + case 0x3f: /* SREG */ + cpu_set_sreg(env, data); + break; + default: + /* not a special register, pass to normal memory access */ + address_space_stb(&address_space_memory, OFFSET_IO_REGISTERS + port, + data, MEMTXATTRS_UNSPECIFIED, NULL); + } +} + +/* + * this function implements LD instruction when there is a posibility to read + * from a CPU register + */ +target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr) +{ + uint8_t data; + + env->fullacc = false; + + if (addr < NUMBER_OF_CPU_REGISTERS) { + /* CPU registers */ + data = env->r[addr]; + } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { + /* IO registers */ + data = helper_inb(env, addr - NUMBER_OF_CPU_REGISTERS); + } else { + /* memory */ + data = address_space_ldub(&address_space_memory, OFFSET_DATA + addr, + MEMTXATTRS_UNSPECIFIED, NULL); + } + return data; +} + +/* + * this function implements ST instruction when there is a posibility to write + * into a CPU register + */ +void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) +{ + env->fullacc = false; + + /* Following logic assumes this: */ + assert(OFFSET_CPU_REGISTERS == OFFSET_DATA); + assert(OFFSET_IO_REGISTERS == OFFSET_CPU_REGISTERS + + NUMBER_OF_CPU_REGISTERS); + + if (addr < NUMBER_OF_CPU_REGISTERS) { + /* CPU registers */ + env->r[addr] = data; + } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { + /* IO registers */ + helper_outb(env, addr - NUMBER_OF_CPU_REGISTERS, data); + } else { + /* memory */ + address_space_stb(&address_space_memory, OFFSET_DATA + addr, data, + MEMTXATTRS_UNSPECIFIED, NULL); + } +} diff --git a/target/avr/helper.h b/target/avr/helper.h new file mode 100644 index 0000000000..8e1ae7fda0 --- /dev/null +++ b/target/avr/helper.h @@ -0,0 +1,29 @@ +/* + * QEMU AVR CPU helpers + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * 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.1 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 + * + */ + +DEF_HELPER_1(wdr, void, env) +DEF_HELPER_1(debug, void, env) +DEF_HELPER_1(break, void, env) +DEF_HELPER_1(sleep, void, env) +DEF_HELPER_1(unsupported, void, env) +DEF_HELPER_3(outb, void, env, i32, i32) +DEF_HELPER_2(inb, tl, env, i32) +DEF_HELPER_3(fullwr, void, env, i32, i32) +DEF_HELPER_2(fullrd, tl, env, i32) From e03feba0079472da577cd940adb43041a40ea337 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:09 +0100 Subject: [PATCH 2142/2595] target/avr: Add instruction translation - Register definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Start implementation of instructions by adding register definitions. Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-11-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/translate.c | 142 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 target/avr/translate.c diff --git a/target/avr/translate.c b/target/avr/translate.c new file mode 100644 index 0000000000..f802e6b29c --- /dev/null +++ b/target/avr/translate.c @@ -0,0 +1,142 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019-2020 Michael Rolnik + * + * 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.1 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 + * + */ + +#include "qemu/osdep.h" +#include "qemu/qemu-print.h" +#include "tcg/tcg.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "tcg/tcg-op.h" +#include "exec/cpu_ldst.h" +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" +#include "exec/log.h" +#include "exec/translator.h" +#include "exec/gen-icount.h" + +/* + * Define if you want a BREAK instruction translated to a breakpoint + * Active debugging connection is assumed + * This is for + * https://github.com/seharris/qemu-avr-tests/tree/master/instruction-tests + * tests + */ +#undef BREAKPOINT_ON_BREAK + +static TCGv cpu_pc; + +static TCGv cpu_Cf; +static TCGv cpu_Zf; +static TCGv cpu_Nf; +static TCGv cpu_Vf; +static TCGv cpu_Sf; +static TCGv cpu_Hf; +static TCGv cpu_Tf; +static TCGv cpu_If; + +static TCGv cpu_rampD; +static TCGv cpu_rampX; +static TCGv cpu_rampY; +static TCGv cpu_rampZ; + +static TCGv cpu_r[NUMBER_OF_CPU_REGISTERS]; +static TCGv cpu_eind; +static TCGv cpu_sp; + +static TCGv cpu_skip; + +static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", +}; +#define REG(x) (cpu_r[x]) + +enum { + DISAS_EXIT = DISAS_TARGET_0, /* We want return to the cpu main loop. */ + DISAS_LOOKUP = DISAS_TARGET_1, /* We have a variable condition exit. */ + DISAS_CHAIN = DISAS_TARGET_2, /* We have a single condition exit. */ +}; + +typedef struct DisasContext DisasContext; + +/* This is the state at translation time. */ +struct DisasContext { + TranslationBlock *tb; + + CPUAVRState *env; + CPUState *cs; + + target_long npc; + uint32_t opcode; + + /* Routine used to access memory */ + int memidx; + int bstate; + int singlestep; + + /* + * some AVR instructions can make the following instruction to be skipped + * Let's name those instructions + * A - instruction that can skip the next one + * B - instruction that can be skipped. this depends on execution of A + * there are two scenarios + * 1. A and B belong to the same translation block + * 2. A is the last instruction in the translation block and B is the last + * + * following variables are used to simplify the skipping logic, they are + * used in the following manner (sketch) + * + * TCGLabel *skip_label = NULL; + * if (ctx.skip_cond != TCG_COND_NEVER) { + * skip_label = gen_new_label(); + * tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label); + * } + * + * if (free_skip_var0) { + * tcg_temp_free(skip_var0); + * free_skip_var0 = false; + * } + * + * translate(&ctx); + * + * if (skip_label) { + * gen_set_label(skip_label); + * } + */ + TCGv skip_var0; + TCGv skip_var1; + TCGCond skip_cond; + bool free_skip_var0; +}; + +static bool avr_have_feature(DisasContext *ctx, int feature) +{ + if (!avr_feature(ctx->env, feature)) { + gen_helper_unsupported(cpu_env); + ctx->bstate = DISAS_NORETURN; + return false; + } + return true; +} + +static bool decode_insn(DisasContext *ctx, uint16_t insn); +#include "decode_insn.inc.c" From 865f3bb9e16365a27efaf3e5b4787fd402764484 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:10 +0100 Subject: [PATCH 2143/2595] target/avr: Add instruction translation - Arithmetic and Logic Instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This includes: - ADD, ADC, ADIW - SBIW, SUB, SUBI, SBC, SBCI - AND, ANDI - OR, ORI, EOR - COM, NEG - INC, DEC - MUL, MULS, MULSU - FMUL, FMULS, FMULSU - DES Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-12-huth@tuxfamily.org> [PMD: Added qemu_log_mask(LOG_UNIMP) in trans_DES()] Signed-off-by: Philippe Mathieu-Daudé --- target/avr/insn.decode | 76 ++++ target/avr/translate.c | 820 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 896 insertions(+) create mode 100644 target/avr/insn.decode diff --git a/target/avr/insn.decode b/target/avr/insn.decode new file mode 100644 index 0000000000..94351ca787 --- /dev/null +++ b/target/avr/insn.decode @@ -0,0 +1,76 @@ +# +# AVR instruction decode definitions. +# +# Copyright (c) 2019-2020 Michael Rolnik +# +# 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.1 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 . +# + +# +# regs_16_31_by_one = [16 .. 31] +# regs_16_23_by_one = [16 .. 23] +# regs_24_30_by_two = [24, 26, 28, 30] +# regs_00_30_by_two = [0, 2, 4, 6, 8, .. 30] + +%rd 4:5 +%rr 9:1 0:4 + +%rd_a 4:4 !function=to_regs_16_31_by_one +%rd_b 4:3 !function=to_regs_16_23_by_one +%rd_c 4:2 !function=to_regs_24_30_by_two +%rr_a 0:4 !function=to_regs_16_31_by_one +%rr_b 0:3 !function=to_regs_16_23_by_one + +%imm6 6:2 0:4 +%imm8 8:4 0:4 + +%io_imm 9:2 0:4 +%ldst_d_imm 13:1 10:2 0:3 + + +&rd_rr rd rr +&rd_imm rd imm + +@op_rd_rr .... .. . ..... .... &rd_rr rd=%rd rr=%rr +@op_rd_imm6 .... .... .. .. .... &rd_imm rd=%rd_c imm=%imm6 +@op_rd_imm8 .... .... .... .... &rd_imm rd=%rd_a imm=%imm8 +@fmul .... .... . ... . ... &rd_rr rd=%rd_b rr=%rr_b + +# +# Arithmetic Instructions +# +ADD 0000 11 . ..... .... @op_rd_rr +ADC 0001 11 . ..... .... @op_rd_rr +ADIW 1001 0110 .. .. .... @op_rd_imm6 +SUB 0001 10 . ..... .... @op_rd_rr +SUBI 0101 .... .... .... @op_rd_imm8 +SBC 0000 10 . ..... .... @op_rd_rr +SBCI 0100 .... .... .... @op_rd_imm8 +SBIW 1001 0111 .. .. .... @op_rd_imm6 +AND 0010 00 . ..... .... @op_rd_rr +ANDI 0111 .... .... .... @op_rd_imm8 +OR 0010 10 . ..... .... @op_rd_rr +ORI 0110 .... .... .... @op_rd_imm8 +EOR 0010 01 . ..... .... @op_rd_rr +COM 1001 010 rd:5 0000 +NEG 1001 010 rd:5 0001 +INC 1001 010 rd:5 0011 +DEC 1001 010 rd:5 1010 +MUL 1001 11 . ..... .... @op_rd_rr +MULS 0000 0010 .... .... &rd_rr rd=%rd_a rr=%rr_a +MULSU 0000 0011 0 ... 0 ... @fmul +FMUL 0000 0011 0 ... 1 ... @fmul +FMULS 0000 0011 1 ... 0 ... @fmul +FMULSU 0000 0011 1 ... 1 ... @fmul +DES 1001 0100 imm:4 1011 diff --git a/target/avr/translate.c b/target/avr/translate.c index f802e6b29c..fae9ed742d 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -128,6 +128,22 @@ struct DisasContext { bool free_skip_var0; }; +static int to_regs_16_31_by_one(DisasContext *ctx, int indx) +{ + return 16 + (indx % 16); +} + +static int to_regs_16_23_by_one(DisasContext *ctx, int indx) +{ + return 16 + (indx % 8); +} + +static int to_regs_24_30_by_two(DisasContext *ctx, int indx) +{ + return 24 + (indx % 4) * 2; +} + + static bool avr_have_feature(DisasContext *ctx, int feature) { if (!avr_feature(ctx->env, feature)) { @@ -140,3 +156,807 @@ static bool avr_have_feature(DisasContext *ctx, int feature) static bool decode_insn(DisasContext *ctx, uint16_t insn); #include "decode_insn.inc.c" + +/* + * Arithmetic Instructions + */ + +/* + * Utility functions for updating status registers: + * + * - gen_add_CHf() + * - gen_add_Vf() + * - gen_sub_CHf() + * - gen_sub_Vf() + * - gen_NSf() + * - gen_ZNSf() + * + */ + +static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + TCGv t3 = tcg_temp_new_i32(); + + tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */ + tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */ + tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */ + tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */ + tcg_gen_or_tl(t1, t1, t3); + + tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */ + tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */ + tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + + /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */ + /* = (Rd ^ R) & ~(Rd ^ Rr) */ + tcg_gen_xor_tl(t1, Rd, R); + tcg_gen_xor_tl(t2, Rd, Rr); + tcg_gen_andc_tl(t1, t1, t2); + + tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + TCGv t3 = tcg_temp_new_i32(); + + tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */ + tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */ + tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */ + tcg_gen_and_tl(t3, t3, R); + tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */ + + tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */ + tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */ + tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + + /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */ + /* = (Rd ^ R) & (Rd ^ R) */ + tcg_gen_xor_tl(t1, Rd, R); + tcg_gen_xor_tl(t2, Rd, Rr); + tcg_gen_and_tl(t1, t1, t2); + + tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_NSf(TCGv R) +{ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +static void gen_ZNSf(TCGv R) +{ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +/* + * Adds two registers without the C Flag and places the result in the + * destination register Rd. + */ +static bool trans_ADD(DisasContext *ctx, arg_ADD *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_add_CHf(R, Rd, Rr); + gen_add_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Adds two registers and the contents of the C Flag and places the result in + * the destination register Rd. + */ +static bool trans_ADC(DisasContext *ctx, arg_ADC *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */ + tcg_gen_add_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_add_CHf(R, Rd, Rr); + gen_add_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Adds an immediate value (0 - 63) to a register pair and places the result + * in the register pair. This instruction operates on the upper four register + * pairs, and is well suited for operations on the pointer registers. This + * instruction is not available in all devices. Refer to the device specific + * instruction set summary. + */ +static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { + return true; + } + + TCGv RdL = cpu_r[a->rd]; + TCGv RdH = cpu_r[a->rd + 1]; + int Imm = (a->imm); + TCGv R = tcg_temp_new_i32(); + TCGv Rd = tcg_temp_new_i32(); + + tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ + tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ + tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); + tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */ + tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */ + + /* update output registers */ + tcg_gen_andi_tl(RdL, R, 0xff); + tcg_gen_shri_tl(RdH, R, 8); + + tcg_temp_free_i32(Rd); + tcg_temp_free_i32(R); + + return true; +} + +/* + * Subtracts two registers and places the result in the destination + * register Rd. + */ +static bool trans_SUB(DisasContext *ctx, arg_SUB *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Subtracts a register and a constant and places the result in the + * destination register Rd. This instruction is working on Register R16 to R31 + * and is very well suited for operations on the X, Y, and Z-pointers. + */ +static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = tcg_const_i32(a->imm); + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + +/* + * Subtracts two registers and subtracts with the C Flag and places the + * result in the destination register Rd. + */ +static bool trans_SBC(DisasContext *ctx, arg_SBC *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv zero = tcg_const_i32(0); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(zero); + tcg_temp_free_i32(R); + + return true; +} + +/* + * SBCI -- Subtract Immediate with Carry + */ +static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = tcg_const_i32(a->imm); + TCGv R = tcg_temp_new_i32(); + TCGv zero = tcg_const_i32(0); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(zero); + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + +/* + * Subtracts an immediate value (0-63) from a register pair and places the + * result in the register pair. This instruction operates on the upper four + * register pairs, and is well suited for operations on the Pointer Registers. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { + return true; + } + + TCGv RdL = cpu_r[a->rd]; + TCGv RdH = cpu_r[a->rd + 1]; + int Imm = (a->imm); + TCGv R = tcg_temp_new_i32(); + TCGv Rd = tcg_temp_new_i32(); + + tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ + tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_andc_tl(cpu_Cf, R, Rd); + tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */ + tcg_gen_andc_tl(cpu_Vf, Rd, R); + tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ + + /* update output registers */ + tcg_gen_andi_tl(RdL, R, 0xff); + tcg_gen_shri_tl(RdH, R, 8); + + tcg_temp_free_i32(Rd); + tcg_temp_free_i32(R); + + return true; +} + +/* + * Performs the logical AND between the contents of register Rd and register + * Rr and places the result in the destination register Rd. + */ +static bool trans_AND(DisasContext *ctx, arg_AND *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */ + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Performs the logical AND between the contents of register Rd and a constant + * and places the result in the destination register Rd. + */ +static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a) +{ + TCGv Rd = cpu_r[a->rd]; + int Imm = (a->imm); + + tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */ + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ + gen_ZNSf(Rd); + + return true; +} + +/* + * Performs the logical OR between the contents of register Rd and register + * Rr and places the result in the destination register Rd. + */ +static bool trans_OR(DisasContext *ctx, arg_OR *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_or_tl(R, Rd, Rr); + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Performs the logical OR between the contents of register Rd and a + * constant and places the result in the destination register Rd. + */ +static bool trans_ORI(DisasContext *ctx, arg_ORI *a) +{ + TCGv Rd = cpu_r[a->rd]; + int Imm = (a->imm); + + tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */ + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ + gen_ZNSf(Rd); + + return true; +} + +/* + * Performs the logical EOR between the contents of register Rd and + * register Rr and places the result in the destination register Rd. + */ +static bool trans_EOR(DisasContext *ctx, arg_EOR *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + + tcg_gen_xor_tl(Rd, Rd, Rr); + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0); + gen_ZNSf(Rd); + + return true; +} + +/* + * Clears the specified bits in register Rd. Performs the logical AND + * between the contents of register Rd and the complement of the constant mask + * K. The result will be placed in register Rd. + */ +static bool trans_COM(DisasContext *ctx, arg_COM *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_xori_tl(Rd, Rd, 0xff); + + /* update status register */ + tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */ + tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ + gen_ZNSf(Rd); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Replaces the contents of register Rd with its two's complement; the + * value $80 is left unchanged. + */ +static bool trans_NEG(DisasContext *ctx, arg_NEG *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_const_i32(0); + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, t0, Rd); + gen_sub_Vf(R, t0, Rd); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * Adds one -1- to the contents of register Rd and places the result in the + * destination register Rd. The C Flag in SREG is not affected by the + * operation, thus allowing the INC instruction to be used on a loop counter in + * multiple-precision computations. When operating on unsigned numbers, only + * BREQ and BRNE branches can be expected to perform consistently. When + * operating on two's complement values, all signed branches are available. + */ +static bool trans_INC(DisasContext *ctx, arg_INC *a) +{ + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_addi_tl(Rd, Rd, 1); + tcg_gen_andi_tl(Rd, Rd, 0xff); + + /* update status register */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */ + gen_ZNSf(Rd); + + return true; +} + +/* + * Subtracts one -1- from the contents of register Rd and places the result + * in the destination register Rd. The C Flag in SREG is not affected by the + * operation, thus allowing the DEC instruction to be used on a loop counter in + * multiple-precision computations. When operating on unsigned values, only + * BREQ and BRNE branches can be expected to perform consistently. When + * operating on two's complement values, all signed branches are available. + */ +static bool trans_DEC(DisasContext *ctx, arg_DEC *a) +{ + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */ + tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */ + + /* update status register */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */ + gen_ZNSf(Rd); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication. + */ +static bool trans_MUL(DisasContext *ctx, arg_MUL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication. + */ +static bool trans_MULS(DisasContext *ctx, arg_MULS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ + tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a + * signed and an unsigned number. + */ +static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */ + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit unsigned + * multiplication and shifts the result one bit left. + */ +static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update output registers */ + tcg_gen_shli_tl(R, R, 1); + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication + * and shifts the result one bit left. + */ +static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ + tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update output registers */ + tcg_gen_shli_tl(R, R, 1); + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication + * and shifts the result one bit left. + */ +static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update output registers */ + tcg_gen_shli_tl(R, R, 1); + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * The module is an instruction set extension to the AVR CPU, performing + * DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in + * the CPU register file, registers R0-R7, where LSB of data is placed in LSB + * of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including + * parity bits) is placed in registers R8- R15, organized in the register file + * with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES + * instruction performs one round in the DES algorithm. Sixteen rounds must be + * executed in increasing order to form the correct DES ciphertext or + * plaintext. Intermediate results are stored in the register file (R0-R15) + * after each DES instruction. The instruction's operand (K) determines which + * round is executed, and the half carry flag (H) determines whether encryption + * or decryption is performed. The DES algorithm is described in + * "Specifications for the Data Encryption Standard" (Federal Information + * Processing Standards Publication 46). Intermediate results in this + * implementation differ from the standard because the initial permutation and + * the inverse initial permutation are performed each iteration. This does not + * affect the result in the final ciphertext or plaintext, but reduces + * execution time. + */ +static bool trans_DES(DisasContext *ctx, arg_DES *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_DES)) { + return true; + } + + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); + + return true; +} From 9d316c75abafbefb1e40e8429e41858b2ab3eeb0 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:11 +0100 Subject: [PATCH 2144/2595] target/avr: Add instruction translation - Branch Instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This includes: - RJMP, IJMP, EIJMP, JMP - RCALL, ICALL, EICALL, CALL - RET, RETI - CPSE, CP, CPC, CPI - SBRC, SBRS, SBIC, SBIS - BRBC, BRBS Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-13-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/insn.decode | 33 +++ target/avr/translate.c | 543 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 576 insertions(+) diff --git a/target/avr/insn.decode b/target/avr/insn.decode index 94351ca787..851eddedc7 100644 --- a/target/avr/insn.decode +++ b/target/avr/insn.decode @@ -74,3 +74,36 @@ FMUL 0000 0011 0 ... 1 ... @fmul FMULS 0000 0011 1 ... 0 ... @fmul FMULSU 0000 0011 1 ... 1 ... @fmul DES 1001 0100 imm:4 1011 + +# +# Branch Instructions +# + +# The 22-bit immediate is partially in the opcode word, +# and partially in the next. Use append_16 to build the +# complete 22-bit value. +%imm_call 4:5 0:1 !function=append_16 + +@op_bit .... .... . bit:3 .... +@op_bit_imm .... .. imm:s7 bit:3 + +RJMP 1100 imm:s12 +IJMP 1001 0100 0000 1001 +EIJMP 1001 0100 0001 1001 +JMP 1001 010 ..... 110 . imm=%imm_call +RCALL 1101 imm:s12 +ICALL 1001 0101 0000 1001 +EICALL 1001 0101 0001 1001 +CALL 1001 010 ..... 111 . imm=%imm_call +RET 1001 0101 0000 1000 +RETI 1001 0101 0001 1000 +CPSE 0001 00 . ..... .... @op_rd_rr +CP 0001 01 . ..... .... @op_rd_rr +CPC 0000 01 . ..... .... @op_rd_rr +CPI 0011 .... .... .... @op_rd_imm8 +SBRC 1111 110 rr:5 0 bit:3 +SBRS 1111 111 rr:5 0 bit:3 +SBIC 1001 1001 reg:5 bit:3 +SBIS 1001 1011 reg:5 bit:3 +BRBS 1111 00 ....... ... @op_bit_imm +BRBC 1111 01 ....... ... @op_bit_imm diff --git a/target/avr/translate.c b/target/avr/translate.c index fae9ed742d..5581264045 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -144,6 +144,16 @@ static int to_regs_24_30_by_two(DisasContext *ctx, int indx) } +static uint16_t next_word(DisasContext *ctx) +{ + return cpu_lduw_code(ctx->env, ctx->npc++ * 2); +} + +static int append_16(DisasContext *ctx, int x) +{ + return x << 16 | next_word(ctx); +} + static bool avr_have_feature(DisasContext *ctx, int feature) { if (!avr_feature(ctx->env, feature)) { @@ -960,3 +970,536 @@ static bool trans_DES(DisasContext *ctx, arg_DES *a) return true; } + +/* + * Branch Instructions + */ +static void gen_jmp_ez(DisasContext *ctx) +{ + tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); + tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind); + ctx->bstate = DISAS_LOOKUP; +} + +static void gen_jmp_z(DisasContext *ctx) +{ + tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); + ctx->bstate = DISAS_LOOKUP; +} + +static void gen_push_ret(DisasContext *ctx, int ret) +{ + if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { + + TCGv t0 = tcg_const_i32((ret & 0x0000ff)); + + tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(t0); + } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { + + TCGv t0 = tcg_const_i32((ret & 0x00ffff)); + + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(t0); + + } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { + + TCGv lo = tcg_const_i32((ret & 0x0000ff)); + TCGv hi = tcg_const_i32((ret & 0xffff00) >> 8); + + tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 2); + tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); + } +} + +static void gen_pop_ret(DisasContext *ctx, TCGv ret) +{ + if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB); + } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { + TCGv lo = tcg_temp_new_i32(); + TCGv hi = tcg_temp_new_i32(); + + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); + + tcg_gen_addi_tl(cpu_sp, cpu_sp, 2); + tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); + + tcg_gen_deposit_tl(ret, lo, hi, 8, 16); + + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); + } +} + +static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +{ + TranslationBlock *tb = ctx->tb; + + if (ctx->singlestep == 0) { + tcg_gen_goto_tb(n); + tcg_gen_movi_i32(cpu_pc, dest); + tcg_gen_exit_tb(tb, n); + } else { + tcg_gen_movi_i32(cpu_pc, dest); + gen_helper_debug(cpu_env); + tcg_gen_exit_tb(NULL, 0); + } + ctx->bstate = DISAS_NORETURN; +} + +/* + * Relative jump to an address within PC - 2K +1 and PC + 2K (words). For + * AVR microcontrollers with Program memory not exceeding 4K words (8KB) this + * instruction can address the entire memory from every address location. See + * also JMP. + */ +static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a) +{ + int dst = ctx->npc + a->imm; + + gen_goto_tb(ctx, 0, dst); + + return true; +} + +/* + * Indirect jump to the address pointed to by the Z (16 bits) Pointer + * Register in the Register File. The Z-pointer Register is 16 bits wide and + * allows jump within the lowest 64K words (128KB) section of Program memory. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { + return true; + } + + gen_jmp_z(ctx); + + return true; +} + +/* + * Indirect jump to the address pointed to by the Z (16 bits) Pointer + * Register in the Register File and the EIND Register in the I/O space. This + * instruction allows for indirect jumps to the entire 4M (words) Program + * memory space. See also IJMP. This instruction is not available in all + * devices. Refer to the device specific instruction set summary. + */ +static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { + return true; + } + + gen_jmp_ez(ctx); + return true; +} + +/* + * Jump to an address within the entire 4M (words) Program memory. See also + * RJMP. This instruction is not available in all devices. Refer to the device + * specific instruction set summary.0 + */ +static bool trans_JMP(DisasContext *ctx, arg_JMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { + return true; + } + + gen_goto_tb(ctx, 0, a->imm); + + return true; +} + +/* + * Relative call to an address within PC - 2K + 1 and PC + 2K (words). The + * return address (the instruction after the RCALL) is stored onto the Stack. + * See also CALL. For AVR microcontrollers with Program memory not exceeding 4K + * words (8KB) this instruction can address the entire memory from every + * address location. The Stack Pointer uses a post-decrement scheme during + * RCALL. + */ +static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a) +{ + int ret = ctx->npc; + int dst = ctx->npc + a->imm; + + gen_push_ret(ctx, ret); + gen_goto_tb(ctx, 0, dst); + + return true; +} + +/* + * Calls to a subroutine within the entire 4M (words) Program memory. The + * return address (to the instruction after the CALL) will be stored onto the + * Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme during + * CALL. This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { + return true; + } + + int ret = ctx->npc; + + gen_push_ret(ctx, ret); + gen_jmp_z(ctx); + + return true; +} + +/* + * Indirect call of a subroutine pointed to by the Z (16 bits) Pointer + * Register in the Register File and the EIND Register in the I/O space. This + * instruction allows for indirect calls to the entire 4M (words) Program + * memory space. See also ICALL. The Stack Pointer uses a post-decrement scheme + * during EICALL. This instruction is not available in all devices. Refer to + * the device specific instruction set summary. + */ +static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { + return true; + } + + int ret = ctx->npc; + + gen_push_ret(ctx, ret); + gen_jmp_ez(ctx); + return true; +} + +/* + * Calls to a subroutine within the entire Program memory. The return + * address (to the instruction after the CALL) will be stored onto the Stack. + * (See also RCALL). The Stack Pointer uses a post-decrement scheme during + * CALL. This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_CALL(DisasContext *ctx, arg_CALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { + return true; + } + + int Imm = a->imm; + int ret = ctx->npc; + + gen_push_ret(ctx, ret); + gen_goto_tb(ctx, 0, Imm); + + return true; +} + +/* + * Returns from subroutine. The return address is loaded from the STACK. + * The Stack Pointer uses a preincrement scheme during RET. + */ +static bool trans_RET(DisasContext *ctx, arg_RET *a) +{ + gen_pop_ret(ctx, cpu_pc); + + ctx->bstate = DISAS_LOOKUP; + return true; +} + +/* + * Returns from interrupt. The return address is loaded from the STACK and + * the Global Interrupt Flag is set. Note that the Status Register is not + * automatically stored when entering an interrupt routine, and it is not + * restored when returning from an interrupt routine. This must be handled by + * the application program. The Stack Pointer uses a pre-increment scheme + * during RETI. + */ +static bool trans_RETI(DisasContext *ctx, arg_RETI *a) +{ + gen_pop_ret(ctx, cpu_pc); + tcg_gen_movi_tl(cpu_If, 1); + + /* Need to return to main loop to re-evaluate interrupts. */ + ctx->bstate = DISAS_EXIT; + return true; +} + +/* + * This instruction performs a compare between two registers Rd and Rr, and + * skips the next instruction if Rd = Rr. + */ +static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a) +{ + ctx->skip_cond = TCG_COND_EQ; + ctx->skip_var0 = cpu_r[a->rd]; + ctx->skip_var1 = cpu_r[a->rr]; + return true; +} + +/* + * This instruction performs a compare between two registers Rd and Rr. + * None of the registers are changed. All conditional branches can be used + * after this instruction. + */ +static bool trans_CP(DisasContext *ctx, arg_CP *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs a compare between two registers Rd and Rr and + * also takes into account the previous carry. None of the registers are + * changed. All conditional branches can be used after this instruction. + */ +static bool trans_CPC(DisasContext *ctx, arg_CPC *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv zero = tcg_const_i32(0); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); + + tcg_temp_free_i32(zero); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs a compare between register Rd and a constant. + * The register is not changed. All conditional branches can be used after this + * instruction. + */ +static bool trans_CPI(DisasContext *ctx, arg_CPI *a) +{ + TCGv Rd = cpu_r[a->rd]; + int Imm = a->imm; + TCGv Rr = tcg_const_i32(Imm); + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + +/* + * This instruction tests a single bit in a register and skips the next + * instruction if the bit is cleared. + */ +static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a) +{ + TCGv Rr = cpu_r[a->rr]; + + ctx->skip_cond = TCG_COND_EQ; + ctx->skip_var0 = tcg_temp_new(); + ctx->free_skip_var0 = true; + + tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); + return true; +} + +/* + * This instruction tests a single bit in a register and skips the next + * instruction if the bit is set. + */ +static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a) +{ + TCGv Rr = cpu_r[a->rr]; + + ctx->skip_cond = TCG_COND_NE; + ctx->skip_var0 = tcg_temp_new(); + ctx->free_skip_var0 = true; + + tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); + return true; +} + +/* + * This instruction tests a single bit in an I/O Register and skips the + * next instruction if the bit is cleared. This instruction operates on the + * lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) +{ + TCGv temp = tcg_const_i32(a->reg); + + gen_helper_inb(temp, cpu_env, temp); + tcg_gen_andi_tl(temp, temp, 1 << a->bit); + ctx->skip_cond = TCG_COND_EQ; + ctx->skip_var0 = temp; + ctx->free_skip_var0 = true; + + return true; +} + +/* + * This instruction tests a single bit in an I/O Register and skips the + * next instruction if the bit is set. This instruction operates on the lower + * 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a) +{ + TCGv temp = tcg_const_i32(a->reg); + + gen_helper_inb(temp, cpu_env, temp); + tcg_gen_andi_tl(temp, temp, 1 << a->bit); + ctx->skip_cond = TCG_COND_NE; + ctx->skip_var0 = temp; + ctx->free_skip_var0 = true; + + return true; +} + +/* + * Conditional relative branch. Tests a single bit in SREG and branches + * relatively to PC if the bit is cleared. This instruction branches relatively + * to PC in either direction (PC - 63 < = destination <= PC + 64). The + * parameter k is the offset from PC and is represented in two's complement + * form. + */ +static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a) +{ + TCGLabel *not_taken = gen_new_label(); + + TCGv var; + + switch (a->bit) { + case 0x00: + var = cpu_Cf; + break; + case 0x01: + var = cpu_Zf; + break; + case 0x02: + var = cpu_Nf; + break; + case 0x03: + var = cpu_Vf; + break; + case 0x04: + var = cpu_Sf; + break; + case 0x05: + var = cpu_Hf; + break; + case 0x06: + var = cpu_Tf; + break; + case 0x07: + var = cpu_If; + break; + default: + g_assert_not_reached(); + } + + tcg_gen_brcondi_i32(TCG_COND_NE, var, 0, not_taken); + gen_goto_tb(ctx, 0, ctx->npc + a->imm); + gen_set_label(not_taken); + + ctx->bstate = DISAS_CHAIN; + return true; +} + +/* + * Conditional relative branch. Tests a single bit in SREG and branches + * relatively to PC if the bit is set. This instruction branches relatively to + * PC in either direction (PC - 63 < = destination <= PC + 64). The parameter k + * is the offset from PC and is represented in two's complement form. + */ +static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a) +{ + TCGLabel *not_taken = gen_new_label(); + + TCGv var; + + switch (a->bit) { + case 0x00: + var = cpu_Cf; + break; + case 0x01: + var = cpu_Zf; + break; + case 0x02: + var = cpu_Nf; + break; + case 0x03: + var = cpu_Vf; + break; + case 0x04: + var = cpu_Sf; + break; + case 0x05: + var = cpu_Hf; + break; + case 0x06: + var = cpu_Tf; + break; + case 0x07: + var = cpu_If; + break; + default: + g_assert_not_reached(); + } + + tcg_gen_brcondi_i32(TCG_COND_EQ, var, 0, not_taken); + gen_goto_tb(ctx, 0, ctx->npc + a->imm); + gen_set_label(not_taken); + + ctx->bstate = DISAS_CHAIN; + return true; +} From 9732b024f79217fbc685895791c4897d14096ef3 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:12 +0100 Subject: [PATCH 2145/2595] target/avr: Add instruction translation - Data Transfer Instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This includes: - MOV, MOVW - LDI, LDS LDX LDY LDZ - LDDY, LDDZ - STS, STX STY STZ - STDY, STDZ - LPM, LPMX - ELPM, ELPMX - SPM, SPMX - IN, OUT - PUSH, POP - XCH - LAS, LAC LAT Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-14-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/insn.decode | 56 +++ target/avr/translate.c | 990 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1046 insertions(+) diff --git a/target/avr/insn.decode b/target/avr/insn.decode index 851eddedc7..279ddfbc0c 100644 --- a/target/avr/insn.decode +++ b/target/avr/insn.decode @@ -107,3 +107,59 @@ SBIC 1001 1001 reg:5 bit:3 SBIS 1001 1011 reg:5 bit:3 BRBS 1111 00 ....... ... @op_bit_imm BRBC 1111 01 ....... ... @op_bit_imm + +# +# Data Transfer Instructions +# + +%rd_d 4:4 !function=to_regs_00_30_by_two +%rr_d 0:4 !function=to_regs_00_30_by_two + +@io_rd_imm .... . .. ..... .... &rd_imm rd=%rd imm=%io_imm +@ldst_d .. . . .. . rd:5 . ... &rd_imm imm=%ldst_d_imm + +# The 16-bit immediate is completely in the next word. +# Fields cannot be defined with no bits, so we cannot play +# the same trick and append to a zero-bit value. +# Defer reading the immediate until trans_{LDS,STS}. +@ldst_s .... ... rd:5 .... imm=0 + +MOV 0010 11 . ..... .... @op_rd_rr +MOVW 0000 0001 .... .... &rd_rr rd=%rd_d rr=%rr_d +LDI 1110 .... .... .... @op_rd_imm8 +LDS 1001 000 ..... 0000 @ldst_s +LDX1 1001 000 rd:5 1100 +LDX2 1001 000 rd:5 1101 +LDX3 1001 000 rd:5 1110 +LDY2 1001 000 rd:5 1001 +LDY3 1001 000 rd:5 1010 +LDZ2 1001 000 rd:5 0001 +LDZ3 1001 000 rd:5 0010 +LDDY 10 . 0 .. 0 ..... 1 ... @ldst_d +LDDZ 10 . 0 .. 0 ..... 0 ... @ldst_d +STS 1001 001 ..... 0000 @ldst_s +STX1 1001 001 rr:5 1100 +STX2 1001 001 rr:5 1101 +STX3 1001 001 rr:5 1110 +STY2 1001 001 rd:5 1001 +STY3 1001 001 rd:5 1010 +STZ2 1001 001 rd:5 0001 +STZ3 1001 001 rd:5 0010 +STDY 10 . 0 .. 1 ..... 1 ... @ldst_d +STDZ 10 . 0 .. 1 ..... 0 ... @ldst_d +LPM1 1001 0101 1100 1000 +LPM2 1001 000 rd:5 0100 +LPMX 1001 000 rd:5 0101 +ELPM1 1001 0101 1101 1000 +ELPM2 1001 000 rd:5 0110 +ELPMX 1001 000 rd:5 0111 +SPM 1001 0101 1110 1000 +SPMX 1001 0101 1111 1000 +IN 1011 0 .. ..... .... @io_rd_imm +OUT 1011 1 .. ..... .... @io_rd_imm +PUSH 1001 001 rd:5 1111 +POP 1001 000 rd:5 1111 +XCH 1001 001 rd:5 0100 +LAC 1001 001 rd:5 0110 +LAS 1001 001 rd:5 0101 +LAT 1001 001 rd:5 0111 diff --git a/target/avr/translate.c b/target/avr/translate.c index 5581264045..fce8b5af9a 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -143,6 +143,10 @@ static int to_regs_24_30_by_two(DisasContext *ctx, int indx) return 24 + (indx % 4) * 2; } +static int to_regs_00_30_by_two(DisasContext *ctx, int indx) +{ + return (indx % 16) * 2; +} static uint16_t next_word(DisasContext *ctx) { @@ -1503,3 +1507,989 @@ static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a) ctx->bstate = DISAS_CHAIN; return true; } + +/* + * Data Transfer Instructions + */ + +/* + * in the gen_set_addr & gen_get_addr functions + * H assumed to be in 0x00ff0000 format + * M assumed to be in 0x000000ff format + * L assumed to be in 0x000000ff format + */ +static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L) +{ + + tcg_gen_andi_tl(L, addr, 0x000000ff); + + tcg_gen_andi_tl(M, addr, 0x0000ff00); + tcg_gen_shri_tl(M, M, 8); + + tcg_gen_andi_tl(H, addr, 0x00ff0000); +} + +static void gen_set_xaddr(TCGv addr) +{ + gen_set_addr(addr, cpu_rampX, cpu_r[27], cpu_r[26]); +} + +static void gen_set_yaddr(TCGv addr) +{ + gen_set_addr(addr, cpu_rampY, cpu_r[29], cpu_r[28]); +} + +static void gen_set_zaddr(TCGv addr) +{ + gen_set_addr(addr, cpu_rampZ, cpu_r[31], cpu_r[30]); +} + +static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L) +{ + TCGv addr = tcg_temp_new_i32(); + + tcg_gen_deposit_tl(addr, M, H, 8, 8); + tcg_gen_deposit_tl(addr, L, addr, 8, 16); + + return addr; +} + +static TCGv gen_get_xaddr(void) +{ + return gen_get_addr(cpu_rampX, cpu_r[27], cpu_r[26]); +} + +static TCGv gen_get_yaddr(void) +{ + return gen_get_addr(cpu_rampY, cpu_r[29], cpu_r[28]); +} + +static TCGv gen_get_zaddr(void) +{ + return gen_get_addr(cpu_rampZ, cpu_r[31], cpu_r[30]); +} + +/* + * Load one byte indirect from data space to register and stores an clear + * the bits in data space specified by the register. The instruction can only + * be used towards internal SRAM. The data location is pointed to by the Z (16 + * bits) Pointer Register in the Register File. Memory access is limited to the + * current data segment of 64KB. To access another data segment in devices with + * more than 64KB data space, the RAMPZ in register in the I/O area has to be + * changed. The Z-pointer Register is left unchanged by the operation. This + * instruction is especially suited for clearing status bits stored in SRAM. + */ +static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) +{ + if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) { + gen_helper_fullwr(cpu_env, data, addr); + } else { + tcg_gen_qemu_st8(data, addr, MMU_DATA_IDX); /* mem[addr] = data */ + } +} + +static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) +{ + if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) { + gen_helper_fullrd(data, cpu_env, addr); + } else { + tcg_gen_qemu_ld8u(data, addr, MMU_DATA_IDX); /* data = mem[addr] */ + } +} + +/* + * This instruction makes a copy of one register into another. The source + * register Rr is left unchanged, while the destination register Rd is loaded + * with a copy of Rr. + */ +static bool trans_MOV(DisasContext *ctx, arg_MOV *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + + tcg_gen_mov_tl(Rd, Rr); + + return true; +} + +/* + * This instruction makes a copy of one register pair into another register + * pair. The source register pair Rr+1:Rr is left unchanged, while the + * destination register pair Rd+1:Rd is loaded with a copy of Rr + 1:Rr. This + * instruction is not available in all devices. Refer to the device specific + * instruction set summary. + */ +static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MOVW)) { + return true; + } + + TCGv RdL = cpu_r[a->rd]; + TCGv RdH = cpu_r[a->rd + 1]; + TCGv RrL = cpu_r[a->rr]; + TCGv RrH = cpu_r[a->rr + 1]; + + tcg_gen_mov_tl(RdH, RrH); + tcg_gen_mov_tl(RdL, RrL); + + return true; +} + +/* + * Loads an 8 bit constant directly to register 16 to 31. + */ +static bool trans_LDI(DisasContext *ctx, arg_LDI *a) +{ + TCGv Rd = cpu_r[a->rd]; + int imm = a->imm; + + tcg_gen_movi_tl(Rd, imm); + + return true; +} + +/* + * Loads one byte from the data space to a register. For parts with SRAM, + * the data space consists of the Register File, I/O memory and internal SRAM + * (and external SRAM if applicable). For parts without SRAM, the data space + * consists of the register file only. The EEPROM has a separate address space. + * A 16-bit address must be supplied. Memory access is limited to the current + * data segment of 64KB. The LDS instruction uses the RAMPD Register to access + * memory above 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPD in register in the I/O area has to be changed. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_LDS(DisasContext *ctx, arg_LDS *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_rampD; + a->imm = next_word(ctx); + + tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ + tcg_gen_shli_tl(addr, addr, 16); + tcg_gen_ori_tl(addr, addr, a->imm); + + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte indirect from the data space to a register. For parts + * with SRAM, the data space consists of the Register File, I/O memory and + * internal SRAM (and external SRAM if applicable). For parts without SRAM, the + * data space consists of the Register File only. In some parts the Flash + * Memory has been mapped to the data space and can be read using this command. + * The EEPROM has a separate address space. The data location is pointed to by + * the X (16 bits) Pointer Register in the Register File. Memory access is + * limited to the current data segment of 64KB. To access another data segment + * in devices with more than 64KB data space, the RAMPX in register in the I/O + * area has to be changed. The X-pointer Register can either be left unchanged + * by the operation, or it can be post-incremented or predecremented. These + * features are especially suited for accessing arrays, tables, and Stack + * Pointer usage of the X-pointer Register. Note that only the low byte of the + * X-pointer is updated in devices with no more than 256 bytes data space. For + * such devices, the high byte of the pointer is not used by this instruction + * and can be used for other purposes. The RAMPX Register in the I/O area is + * updated in parts with more than 64KB data space or more than 64KB Program + * memory, and the increment/decrement is added to the entire 24-bit address on + * such devices. Not all variants of this instruction is available in all + * devices. Refer to the device specific instruction set summary. In the + * Reduced Core tinyAVR the LD instruction can be used to achieve the same + * operation as LPM since the program memory is mapped to the data memory + * space. + */ +static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_xaddr(); + + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_xaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_xaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_load(ctx, Rd, addr); + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte indirect with or without displacement from the data space + * to a register. For parts with SRAM, the data space consists of the Register + * File, I/O memory and internal SRAM (and external SRAM if applicable). For + * parts without SRAM, the data space consists of the Register File only. In + * some parts the Flash Memory has been mapped to the data space and can be + * read using this command. The EEPROM has a separate address space. The data + * location is pointed to by the Y (16 bits) Pointer Register in the Register + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space, the + * RAMPY in register in the I/O area has to be changed. The Y-pointer Register + * can either be left unchanged by the operation, or it can be post-incremented + * or predecremented. These features are especially suited for accessing + * arrays, tables, and Stack Pointer usage of the Y-pointer Register. Note that + * only the low byte of the Y-pointer is updated in devices with no more than + * 256 bytes data space. For such devices, the high byte of the pointer is not + * used by this instruction and can be used for other purposes. The RAMPY + * Register in the I/O area is updated in parts with more than 64KB data space + * or more than 64KB Program memory, and the increment/decrement/displacement + * is added to the entire 24-bit address on such devices. Not all variants of + * this instruction is available in all devices. Refer to the device specific + * instruction set summary. In the Reduced Core tinyAVR the LD instruction can + * be used to achieve the same operation as LPM since the program memory is + * mapped to the data memory space. + */ +static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_load(ctx, Rd, addr); + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte indirect with or without displacement from the data space + * to a register. For parts with SRAM, the data space consists of the Register + * File, I/O memory and internal SRAM (and external SRAM if applicable). For + * parts without SRAM, the data space consists of the Register File only. In + * some parts the Flash Memory has been mapped to the data space and can be + * read using this command. The EEPROM has a separate address space. The data + * location is pointed to by the Z (16 bits) Pointer Register in the Register + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space, the + * RAMPZ in register in the I/O area has to be changed. The Z-pointer Register + * can either be left unchanged by the operation, or it can be post-incremented + * or predecremented. These features are especially suited for Stack Pointer + * usage of the Z-pointer Register, however because the Z-pointer Register can + * be used for indirect subroutine calls, indirect jumps and table lookup, it + * is often more convenient to use the X or Y-pointer as a dedicated Stack + * Pointer. Note that only the low byte of the Z-pointer is updated in devices + * with no more than 256 bytes data space. For such devices, the high byte of + * the pointer is not used by this instruction and can be used for other + * purposes. The RAMPZ Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the + * increment/decrement/displacement is added to the entire 24-bit address on + * such devices. Not all variants of this instruction is available in all + * devices. Refer to the device specific instruction set summary. In the + * Reduced Core tinyAVR the LD instruction can be used to achieve the same + * operation as LPM since the program memory is mapped to the data memory + * space. For using the Z-pointer for table lookup in Program memory see the + * LPM and ELPM instructions. + */ +static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_load(ctx, Rd, addr); + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte from a Register to the data space. For parts with SRAM, + * the data space consists of the Register File, I/O memory and internal SRAM + * (and external SRAM if applicable). For parts without SRAM, the data space + * consists of the Register File only. The EEPROM has a separate address space. + * A 16-bit address must be supplied. Memory access is limited to the current + * data segment of 64KB. The STS instruction uses the RAMPD Register to access + * memory above 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPD in register in the I/O area has to be changed. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_STS(DisasContext *ctx, arg_STS *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_rampD; + a->imm = next_word(ctx); + + tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ + tcg_gen_shli_tl(addr, addr, 16); + tcg_gen_ori_tl(addr, addr, a->imm); + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte indirect from a register to data space. For parts with SRAM, + * the data space consists of the Register File, I/O memory, and internal SRAM + * (and external SRAM if applicable). For parts without SRAM, the data space + * consists of the Register File only. The EEPROM has a separate address space. + * + * The data location is pointed to by the X (16 bits) Pointer Register in the + * Register File. Memory access is limited to the current data segment of 64KB. + * To access another data segment in devices with more than 64KB data space, the + * RAMPX in register in the I/O area has to be changed. + * + * The X-pointer Register can either be left unchanged by the operation, or it + * can be post-incremented or pre-decremented. These features are especially + * suited for accessing arrays, tables, and Stack Pointer usage of the + * X-pointer Register. Note that only the low byte of the X-pointer is updated + * in devices with no more than 256 bytes data space. For such devices, the high + * byte of the pointer is not used by this instruction and can be used for other + * purposes. The RAMPX Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the increment / + * decrement is added to the entire 24-bit address on such devices. + */ +static bool trans_STX1(DisasContext *ctx, arg_STX1 *a) +{ + TCGv Rd = cpu_r[a->rr]; + TCGv addr = gen_get_xaddr(); + + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STX2(DisasContext *ctx, arg_STX2 *a) +{ + TCGv Rd = cpu_r[a->rr]; + TCGv addr = gen_get_xaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STX3(DisasContext *ctx, arg_STX3 *a) +{ + TCGv Rd = cpu_r[a->rr]; + TCGv addr = gen_get_xaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_store(ctx, Rd, addr); + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte indirect with or without displacement from a register to data + * space. For parts with SRAM, the data space consists of the Register File, I/O + * memory, and internal SRAM (and external SRAM if applicable). For parts + * without SRAM, the data space consists of the Register File only. The EEPROM + * has a separate address space. + * + * The data location is pointed to by the Y (16 bits) Pointer Register in the + * Register File. Memory access is limited to the current data segment of 64KB. + * To access another data segment in devices with more than 64KB data space, the + * RAMPY in register in the I/O area has to be changed. + * + * The Y-pointer Register can either be left unchanged by the operation, or it + * can be post-incremented or pre-decremented. These features are especially + * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer + * Register. Note that only the low byte of the Y-pointer is updated in devices + * with no more than 256 bytes data space. For such devices, the high byte of + * the pointer is not used by this instruction and can be used for other + * purposes. The RAMPY Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the increment / + * decrement / displacement is added to the entire 24-bit address on such + * devices. + */ +static bool trans_STY2(DisasContext *ctx, arg_STY2 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STY3(DisasContext *ctx, arg_STY3 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_store(ctx, Rd, addr); + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STDY(DisasContext *ctx, arg_STDY *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte indirect with or without displacement from a register to data + * space. For parts with SRAM, the data space consists of the Register File, I/O + * memory, and internal SRAM (and external SRAM if applicable). For parts + * without SRAM, the data space consists of the Register File only. The EEPROM + * has a separate address space. + * + * The data location is pointed to by the Y (16 bits) Pointer Register in the + * Register File. Memory access is limited to the current data segment of 64KB. + * To access another data segment in devices with more than 64KB data space, the + * RAMPY in register in the I/O area has to be changed. + * + * The Y-pointer Register can either be left unchanged by the operation, or it + * can be post-incremented or pre-decremented. These features are especially + * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer + * Register. Note that only the low byte of the Y-pointer is updated in devices + * with no more than 256 bytes data space. For such devices, the high byte of + * the pointer is not used by this instruction and can be used for other + * purposes. The RAMPY Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the increment / + * decrement / displacement is added to the entire 24-bit address on such + * devices. + */ +static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_store(ctx, Rd, addr); + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte pointed to by the Z-register into the destination + * register Rd. This instruction features a 100% space effective constant + * initialization or constant data fetch. The Program memory is organized in + * 16-bit words while the Z-pointer is a byte address. Thus, the least + * significant bit of the Z-pointer selects either low byte (ZLSB = 0) or high + * byte (ZLSB = 1). This instruction can address the first 64KB (32K words) of + * Program memory. The Zpointer Register can either be left unchanged by the + * operation, or it can be incremented. The incrementation does not apply to + * the RAMPZ Register. + * + * Devices with Self-Programming capability can use the LPM instruction to read + * the Fuse and Lock bit values. + */ +static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { + return true; + } + + TCGv Rd = cpu_r[0]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_r[31]; + TCGv L = cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ + tcg_gen_or_tl(addr, addr, L); + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_r[31]; + TCGv L = cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ + tcg_gen_or_tl(addr, addr, L); + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPMX)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_r[31]; + TCGv L = cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ + tcg_gen_or_tl(addr, addr, L); + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + tcg_gen_andi_tl(L, addr, 0xff); + tcg_gen_shri_tl(addr, addr, 8); + tcg_gen_andi_tl(H, addr, 0xff); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte pointed to by the Z-register and the RAMPZ Register in + * the I/O space, and places this byte in the destination register Rd. This + * instruction features a 100% space effective constant initialization or + * constant data fetch. The Program memory is organized in 16-bit words while + * the Z-pointer is a byte address. Thus, the least significant bit of the + * Z-pointer selects either low byte (ZLSB = 0) or high byte (ZLSB = 1). This + * instruction can address the entire Program memory space. The Z-pointer + * Register can either be left unchanged by the operation, or it can be + * incremented. The incrementation applies to the entire 24-bit concatenation + * of the RAMPZ and Z-pointer Registers. + * + * Devices with Self-Programming capability can use the ELPM instruction to + * read the Fuse and Lock bit value. + */ +static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { + return true; + } + + TCGv Rd = cpu_r[0]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPMX)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * SPM can be used to erase a page in the Program memory, to write a page + * in the Program memory (that is already erased), and to set Boot Loader Lock + * bits. In some devices, the Program memory can be written one word at a time, + * in other devices an entire page can be programmed simultaneously after first + * filling a temporary page buffer. In all cases, the Program memory must be + * erased one page at a time. When erasing the Program memory, the RAMPZ and + * Z-register are used as page address. When writing the Program memory, the + * RAMPZ and Z-register are used as page or word address, and the R1:R0 + * register pair is used as data(1). When setting the Boot Loader Lock bits, + * the R1:R0 register pair is used as data. Refer to the device documentation + * for detailed description of SPM usage. This instruction can address the + * entire Program memory. + * + * The SPM instruction is not available in all devices. Refer to the device + * specific instruction set summary. + * + * Note: 1. R1 determines the instruction high byte, and R0 determines the + * instruction low byte. + */ +static bool trans_SPM(DisasContext *ctx, arg_SPM *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_SPM)) { + return true; + } + + return true; +} + +static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_SPMX)) { + return true; + } + + return true; +} + +/* + * Loads data from the I/O Space (Ports, Timers, Configuration Registers, + * etc.) into register Rd in the Register File. + */ +static bool trans_IN(DisasContext *ctx, arg_IN *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv port = tcg_const_i32(a->imm); + + gen_helper_inb(Rd, cpu_env, port); + + tcg_temp_free_i32(port); + + return true; +} + +/* + * Stores data from register Rr in the Register File to I/O Space (Ports, + * Timers, Configuration Registers, etc.). + */ +static bool trans_OUT(DisasContext *ctx, arg_OUT *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv port = tcg_const_i32(a->imm); + + gen_helper_outb(cpu_env, port, Rd); + + tcg_temp_free_i32(port); + + return true; +} + +/* + * This instruction stores the contents of register Rr on the STACK. The + * Stack Pointer is post-decremented by 1 after the PUSH. This instruction is + * not available in all devices. Refer to the device specific instruction set + * summary. + */ +static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a) +{ + TCGv Rd = cpu_r[a->rd]; + + gen_data_store(ctx, Rd, cpu_sp); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + return true; +} + +/* + * This instruction loads register Rd with a byte from the STACK. The Stack + * Pointer is pre-incremented by 1 before the POP. This instruction is not + * available in all devices. Refer to the device specific instruction set + * summary. + */ +static bool trans_POP(DisasContext *ctx, arg_POP *a) +{ + /* + * Using a temp to work around some strange behaviour: + * tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + * gen_data_load(ctx, Rd, cpu_sp); + * seems to cause the add to happen twice. + * This doesn't happen if either the add or the load is removed. + */ + TCGv t1 = tcg_temp_new_i32(); + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_addi_tl(t1, cpu_sp, 1); + gen_data_load(ctx, Rd, t1); + tcg_gen_mov_tl(cpu_sp, t1); + + return true; +} + +/* + * Exchanges one byte indirect between register and data space. The data + * location is pointed to by the Z (16 bits) Pointer Register in the Register + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space, the + * RAMPZ in register in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for writing/reading status bits stored in SRAM. + */ +static bool trans_XCH(DisasContext *ctx, arg_XCH *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + TCGv addr = gen_get_zaddr(); + + gen_data_load(ctx, t0, addr); + gen_data_store(ctx, Rd, addr); + tcg_gen_mov_tl(Rd, t0); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Load one byte indirect from data space to register and set bits in data + * space specified by the register. The instruction can only be used towards + * internal SRAM. The data location is pointed to by the Z (16 bits) Pointer + * Register in the Register File. Memory access is limited to the current data + * segment of 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPZ in register in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for setting status bits stored in SRAM. + */ +static bool trans_LAS(DisasContext *ctx, arg_LAS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rr = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ + tcg_gen_or_tl(t1, t0, Rr); + tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Load one byte indirect from data space to register and stores and clear + * the bits in data space specified by the register. The instruction can + * only be used towards internal SRAM. The data location is pointed to by + * the Z (16 bits) Pointer Register in the Register File. Memory access is + * limited to the current data segment of 64KB. To access another data + * segment in devices with more than 64KB data space, the RAMPZ in register + * in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for clearing status bits stored in SRAM. + */ +static bool trans_LAC(DisasContext *ctx, arg_LAC *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rr = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ + tcg_gen_andc_tl(t1, t0, Rr); /* t1 = t0 & (0xff - Rr) = t0 & ~Rr */ + tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Load one byte indirect from data space to register and toggles bits in + * the data space specified by the register. The instruction can only be used + * towards SRAM. The data location is pointed to by the Z (16 bits) Pointer + * Register in the Register File. Memory access is limited to the current data + * segment of 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPZ in register in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for changing status bits stored in SRAM. + */ +static bool trans_LAT(DisasContext *ctx, arg_LAT *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ + tcg_gen_xor_tl(t1, t0, Rd); + tcg_gen_mov_tl(Rd, t0); /* Rd = t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} From 5718cef05a0fe306646dd0481eb6ccf4fef3979e Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:13 +0100 Subject: [PATCH 2146/2595] target/avr: Add instruction translation - Bit and Bit-test Instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This includes: - LSR, ROR - ASR - SWAP - SBI, CBI - BST, BLD - BSET, BCLR Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-15-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/insn.decode | 14 +++ target/avr/translate.c | 247 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 261 insertions(+) diff --git a/target/avr/insn.decode b/target/avr/insn.decode index 279ddfbc0c..7bb6ce7495 100644 --- a/target/avr/insn.decode +++ b/target/avr/insn.decode @@ -163,3 +163,17 @@ XCH 1001 001 rd:5 0100 LAC 1001 001 rd:5 0110 LAS 1001 001 rd:5 0101 LAT 1001 001 rd:5 0111 + +# +# Bit and Bit-test Instructions +# +LSR 1001 010 rd:5 0110 +ROR 1001 010 rd:5 0111 +ASR 1001 010 rd:5 0101 +SWAP 1001 010 rd:5 0010 +SBI 1001 1010 reg:5 bit:3 +CBI 1001 1000 reg:5 bit:3 +BST 1111 101 rd:5 0 bit:3 +BLD 1111 100 rd:5 0 bit:3 +BSET 1001 0100 0 bit:3 1000 +BCLR 1001 0100 1 bit:3 1000 diff --git a/target/avr/translate.c b/target/avr/translate.c index fce8b5af9a..884fbb6081 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -2493,3 +2493,250 @@ static bool trans_LAT(DisasContext *ctx, arg_LAT *a) return true; } + +/* + * Bit and Bit-test Instructions + */ +static void gen_rshift_ZNVSf(TCGv R) +{ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ + tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf); + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +/* + * Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is + * loaded into the C Flag of the SREG. This operation effectively divides an + * unsigned value by two. The C Flag can be used to round the result. + */ +static bool trans_LSR(DisasContext *ctx, arg_LSR *a) +{ + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_andi_tl(cpu_Cf, Rd, 1); + tcg_gen_shri_tl(Rd, Rd, 1); + + /* update status register */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, Rd, 0); /* Zf = Rd == 0 */ + tcg_gen_movi_tl(cpu_Nf, 0); + tcg_gen_mov_tl(cpu_Vf, cpu_Cf); + tcg_gen_mov_tl(cpu_Sf, cpu_Vf); + + return true; +} + +/* + * Shifts all bits in Rd one place to the right. The C Flag is shifted into + * bit 7 of Rd. Bit 0 is shifted into the C Flag. This operation, combined + * with ASR, effectively divides multi-byte signed values by two. Combined with + * LSR it effectively divides multi-byte unsigned values by two. The Carry Flag + * can be used to round the result. + */ +static bool trans_ROR(DisasContext *ctx, arg_ROR *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + + tcg_gen_shli_tl(t0, cpu_Cf, 7); + + /* update status register */ + tcg_gen_andi_tl(cpu_Cf, Rd, 1); + + /* update output register */ + tcg_gen_shri_tl(Rd, Rd, 1); + tcg_gen_or_tl(Rd, Rd, t0); + + /* update status register */ + gen_rshift_ZNVSf(Rd); + + tcg_temp_free_i32(t0); + + return true; +} + +/* + * Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0 + * is loaded into the C Flag of the SREG. This operation effectively divides a + * signed value by two without changing its sign. The Carry Flag can be used to + * round the result. + */ +static bool trans_ASR(DisasContext *ctx, arg_ASR *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + + /* update status register */ + tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf = Rd(0) */ + + /* update output register */ + tcg_gen_andi_tl(t0, Rd, 0x80); /* Rd = (Rd & 0x80) | (Rd >> 1) */ + tcg_gen_shri_tl(Rd, Rd, 1); + tcg_gen_or_tl(Rd, Rd, t0); + + /* update status register */ + gen_rshift_ZNVSf(Rd); + + tcg_temp_free_i32(t0); + + return true; +} + +/* + * Swaps high and low nibbles in a register. + */ +static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_andi_tl(t0, Rd, 0x0f); + tcg_gen_shli_tl(t0, t0, 4); + tcg_gen_andi_tl(t1, Rd, 0xf0); + tcg_gen_shri_tl(t1, t1, 4); + tcg_gen_or_tl(Rd, t0, t1); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + + return true; +} + +/* + * Sets a specified bit in an I/O Register. This instruction operates on + * the lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBI(DisasContext *ctx, arg_SBI *a) +{ + TCGv data = tcg_temp_new_i32(); + TCGv port = tcg_const_i32(a->reg); + + gen_helper_inb(data, cpu_env, port); + tcg_gen_ori_tl(data, data, 1 << a->bit); + gen_helper_outb(cpu_env, port, data); + + tcg_temp_free_i32(port); + tcg_temp_free_i32(data); + + return true; +} + +/* + * Clears a specified bit in an I/O Register. This instruction operates on + * the lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_CBI(DisasContext *ctx, arg_CBI *a) +{ + TCGv data = tcg_temp_new_i32(); + TCGv port = tcg_const_i32(a->reg); + + gen_helper_inb(data, cpu_env, port); + tcg_gen_andi_tl(data, data, ~(1 << a->bit)); + gen_helper_outb(cpu_env, port, data); + + tcg_temp_free_i32(data); + tcg_temp_free_i32(port); + + return true; +} + +/* + * Stores bit b from Rd to the T Flag in SREG (Status Register). + */ +static bool trans_BST(DisasContext *ctx, arg_BST *a) +{ + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_andi_tl(cpu_Tf, Rd, 1 << a->bit); + tcg_gen_shri_tl(cpu_Tf, cpu_Tf, a->bit); + + return true; +} + +/* + * Copies the T Flag in the SREG (Status Register) to bit b in register Rd. + */ +static bool trans_BLD(DisasContext *ctx, arg_BLD *a) +{ + TCGv Rd = cpu_r[a->rd]; + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_andi_tl(Rd, Rd, ~(1u << a->bit)); /* clear bit */ + tcg_gen_shli_tl(t1, cpu_Tf, a->bit); /* create mask */ + tcg_gen_or_tl(Rd, Rd, t1); + + tcg_temp_free_i32(t1); + + return true; +} + +/* + * Sets a single Flag or bit in SREG. + */ +static bool trans_BSET(DisasContext *ctx, arg_BSET *a) +{ + switch (a->bit) { + case 0x00: + tcg_gen_movi_tl(cpu_Cf, 0x01); + break; + case 0x01: + tcg_gen_movi_tl(cpu_Zf, 0x01); + break; + case 0x02: + tcg_gen_movi_tl(cpu_Nf, 0x01); + break; + case 0x03: + tcg_gen_movi_tl(cpu_Vf, 0x01); + break; + case 0x04: + tcg_gen_movi_tl(cpu_Sf, 0x01); + break; + case 0x05: + tcg_gen_movi_tl(cpu_Hf, 0x01); + break; + case 0x06: + tcg_gen_movi_tl(cpu_Tf, 0x01); + break; + case 0x07: + tcg_gen_movi_tl(cpu_If, 0x01); + break; + } + + return true; +} + +/* + * Clears a single Flag in SREG. + */ +static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a) +{ + switch (a->bit) { + case 0x00: + tcg_gen_movi_tl(cpu_Cf, 0x00); + break; + case 0x01: + tcg_gen_movi_tl(cpu_Zf, 0x00); + break; + case 0x02: + tcg_gen_movi_tl(cpu_Nf, 0x00); + break; + case 0x03: + tcg_gen_movi_tl(cpu_Vf, 0x00); + break; + case 0x04: + tcg_gen_movi_tl(cpu_Sf, 0x00); + break; + case 0x05: + tcg_gen_movi_tl(cpu_Hf, 0x00); + break; + case 0x06: + tcg_gen_movi_tl(cpu_Tf, 0x00); + break; + case 0x07: + tcg_gen_movi_tl(cpu_If, 0x00); + break; + } + + return true; +} From 46188cabae4a13add28493f85b0f65ddde3ead41 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:14 +0100 Subject: [PATCH 2147/2595] target/avr: Add instruction translation - MCU Control Instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This includes: - BREAK - NOP - SLEEP - WDR Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-16-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/insn.decode | 8 ++++++ target/avr/translate.c | 65 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/target/avr/insn.decode b/target/avr/insn.decode index 7bb6ce7495..482c23ad0c 100644 --- a/target/avr/insn.decode +++ b/target/avr/insn.decode @@ -177,3 +177,11 @@ BST 1111 101 rd:5 0 bit:3 BLD 1111 100 rd:5 0 bit:3 BSET 1001 0100 0 bit:3 1000 BCLR 1001 0100 1 bit:3 1000 + +# +# MCU Control Instructions +# +BREAK 1001 0101 1001 1000 +NOP 0000 0000 0000 0000 +SLEEP 1001 0101 1000 1000 +WDR 1001 0101 1010 1000 diff --git a/target/avr/translate.c b/target/avr/translate.c index 884fbb6081..ee7811995a 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -2740,3 +2740,68 @@ static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a) return true; } + +/* + * MCU Control Instructions + */ + +/* + * The BREAK instruction is used by the On-chip Debug system, and is + * normally not used in the application software. When the BREAK instruction is + * executed, the AVR CPU is set in the Stopped Mode. This gives the On-chip + * Debugger access to internal resources. If any Lock bits are set, or either + * the JTAGEN or OCDEN Fuses are unprogrammed, the CPU will treat the BREAK + * instruction as a NOP and will not enter the Stopped mode. This instruction + * is not available in all devices. Refer to the device specific instruction + * set summary. + */ +static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_BREAK)) { + return true; + } + +#ifdef BREAKPOINT_ON_BREAK + tcg_gen_movi_tl(cpu_pc, ctx->npc - 1); + gen_helper_debug(cpu_env); + ctx->bstate = DISAS_EXIT; +#else + /* NOP */ +#endif + + return true; +} + +/* + * This instruction performs a single cycle No Operation. + */ +static bool trans_NOP(DisasContext *ctx, arg_NOP *a) +{ + + /* NOP */ + + return true; +} + +/* + * This instruction sets the circuit in sleep mode defined by the MCU + * Control Register. + */ +static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a) +{ + gen_helper_sleep(cpu_env); + ctx->bstate = DISAS_NORETURN; + return true; +} + +/* + * This instruction resets the Watchdog Timer. This instruction must be + * executed within a limited time given by the WD prescaler. See the Watchdog + * Timer hardware specification. + */ +static bool trans_WDR(DisasContext *ctx, arg_WDR *a) +{ + gen_helper_wdr(cpu_env); + + return true; +} From 9baade8d3be8506daa9962ce54d39e25b2b220f1 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:15 +0100 Subject: [PATCH 2148/2595] target/avr: Add instruction translation - CPU main translation function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the core of translation mechanism. Co-developed-by: Richard Henderson Co-developed-by: Michael Rolnik Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-17-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/translate.c | 213 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) diff --git a/target/avr/translate.c b/target/avr/translate.c index ee7811995a..7ad3dec031 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -2805,3 +2805,216 @@ static bool trans_WDR(DisasContext *ctx, arg_WDR *a) return true; } + +/* + * Core translation mechanism functions: + * + * - translate() + * - canonicalize_skip() + * - gen_intermediate_code() + * - restore_state_to_opc() + * + */ +static void translate(DisasContext *ctx) +{ + uint32_t opcode = next_word(ctx); + + if (!decode_insn(ctx, opcode)) { + gen_helper_unsupported(cpu_env); + ctx->bstate = DISAS_NORETURN; + } +} + +/* Standardize the cpu_skip condition to NE. */ +static bool canonicalize_skip(DisasContext *ctx) +{ + switch (ctx->skip_cond) { + case TCG_COND_NEVER: + /* Normal case: cpu_skip is known to be false. */ + return false; + + case TCG_COND_ALWAYS: + /* + * Breakpoint case: cpu_skip is known to be true, via TB_FLAGS_SKIP. + * The breakpoint is on the instruction being skipped, at the start + * of the TranslationBlock. No need to update. + */ + return false; + + case TCG_COND_NE: + if (ctx->skip_var1 == NULL) { + tcg_gen_mov_tl(cpu_skip, ctx->skip_var0); + } else { + tcg_gen_xor_tl(cpu_skip, ctx->skip_var0, ctx->skip_var1); + ctx->skip_var1 = NULL; + } + break; + + default: + /* Convert to a NE condition vs 0. */ + if (ctx->skip_var1 == NULL) { + tcg_gen_setcondi_tl(ctx->skip_cond, cpu_skip, ctx->skip_var0, 0); + } else { + tcg_gen_setcond_tl(ctx->skip_cond, cpu_skip, + ctx->skip_var0, ctx->skip_var1); + ctx->skip_var1 = NULL; + } + ctx->skip_cond = TCG_COND_NE; + break; + } + if (ctx->free_skip_var0) { + tcg_temp_free(ctx->skip_var0); + ctx->free_skip_var0 = false; + } + ctx->skip_var0 = cpu_skip; + return true; +} + +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +{ + CPUAVRState *env = cs->env_ptr; + DisasContext ctx = { + .tb = tb, + .cs = cs, + .env = env, + .memidx = 0, + .bstate = DISAS_NEXT, + .skip_cond = TCG_COND_NEVER, + .singlestep = cs->singlestep_enabled, + }; + target_ulong pc_start = tb->pc / 2; + int num_insns = 0; + + if (tb->flags & TB_FLAGS_FULL_ACCESS) { + /* + * This flag is set by ST/LD instruction we will regenerate it ONLY + * with mem/cpu memory access instead of mem access + */ + max_insns = 1; + } + if (ctx.singlestep) { + max_insns = 1; + } + + gen_tb_start(tb); + + ctx.npc = pc_start; + if (tb->flags & TB_FLAGS_SKIP) { + ctx.skip_cond = TCG_COND_ALWAYS; + ctx.skip_var0 = cpu_skip; + } + + do { + TCGLabel *skip_label = NULL; + + /* translate current instruction */ + tcg_gen_insn_start(ctx.npc); + num_insns++; + + /* + * this is due to some strange GDB behavior + * let's assume main has address 0x100 + * b main - sets breakpoint at address 0x00000100 (code) + * b *0x100 - sets breakpoint at address 0x00800100 (data) + */ + if (unlikely(!ctx.singlestep && + (cpu_breakpoint_test(cs, OFFSET_CODE + ctx.npc * 2, BP_ANY) || + cpu_breakpoint_test(cs, OFFSET_DATA + ctx.npc * 2, BP_ANY)))) { + canonicalize_skip(&ctx); + tcg_gen_movi_tl(cpu_pc, ctx.npc); + gen_helper_debug(cpu_env); + goto done_generating; + } + + /* Conditionally skip the next instruction, if indicated. */ + if (ctx.skip_cond != TCG_COND_NEVER) { + skip_label = gen_new_label(); + if (ctx.skip_var0 == cpu_skip) { + /* + * Copy cpu_skip so that we may zero it before the branch. + * This ensures that cpu_skip is non-zero after the label + * if and only if the skipped insn itself sets a skip. + */ + ctx.free_skip_var0 = true; + ctx.skip_var0 = tcg_temp_new(); + tcg_gen_mov_tl(ctx.skip_var0, cpu_skip); + tcg_gen_movi_tl(cpu_skip, 0); + } + if (ctx.skip_var1 == NULL) { + tcg_gen_brcondi_tl(ctx.skip_cond, ctx.skip_var0, 0, skip_label); + } else { + tcg_gen_brcond_tl(ctx.skip_cond, ctx.skip_var0, + ctx.skip_var1, skip_label); + ctx.skip_var1 = NULL; + } + if (ctx.free_skip_var0) { + tcg_temp_free(ctx.skip_var0); + ctx.free_skip_var0 = false; + } + ctx.skip_cond = TCG_COND_NEVER; + ctx.skip_var0 = NULL; + } + + translate(&ctx); + + if (skip_label) { + canonicalize_skip(&ctx); + gen_set_label(skip_label); + if (ctx.bstate == DISAS_NORETURN) { + ctx.bstate = DISAS_CHAIN; + } + } + } while (ctx.bstate == DISAS_NEXT + && num_insns < max_insns + && (ctx.npc - pc_start) * 2 < TARGET_PAGE_SIZE - 4 + && !tcg_op_buf_full()); + + if (tb->cflags & CF_LAST_IO) { + gen_io_end(); + } + + bool nonconst_skip = canonicalize_skip(&ctx); + + switch (ctx.bstate) { + case DISAS_NORETURN: + assert(!nonconst_skip); + break; + case DISAS_NEXT: + case DISAS_TOO_MANY: + case DISAS_CHAIN: + if (!nonconst_skip) { + /* Note gen_goto_tb checks singlestep. */ + gen_goto_tb(&ctx, 1, ctx.npc); + break; + } + tcg_gen_movi_tl(cpu_pc, ctx.npc); + /* fall through */ + case DISAS_LOOKUP: + if (!ctx.singlestep) { + tcg_gen_lookup_and_goto_ptr(); + break; + } + /* fall through */ + case DISAS_EXIT: + if (ctx.singlestep) { + gen_helper_debug(cpu_env); + } else { + tcg_gen_exit_tb(NULL, 0); + } + break; + default: + g_assert_not_reached(); + } + +done_generating: + gen_tb_end(tb, num_insns); + + tb->size = (ctx.npc - pc_start) * 2; + tb->icount = num_insns; +} + +void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, + target_ulong *data) +{ + env->pc_w = data[0]; +} From a107fdb07264098295af806706001f62d39fdddd Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 7 Feb 2020 02:27:13 +0100 Subject: [PATCH 2149/2595] target/avr: Initialize TCG register variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize TCG register variables. Co-developed-by: Richard Henderson Co-developed-by: Michael Rolnik Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-18-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/translate.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/target/avr/translate.c b/target/avr/translate.c index 7ad3dec031..3d8a77e5ae 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -128,6 +128,35 @@ struct DisasContext { bool free_skip_var0; }; +void avr_cpu_tcg_init(void) +{ + int i; + +#define AVR_REG_OFFS(x) offsetof(CPUAVRState, x) + cpu_pc = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w), "pc"); + cpu_Cf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf"); + cpu_Zf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregZ), "Zf"); + cpu_Nf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregN), "Nf"); + cpu_Vf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregV), "Vf"); + cpu_Sf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregS), "Sf"); + cpu_Hf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregH), "Hf"); + cpu_Tf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregT), "Tf"); + cpu_If = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregI), "If"); + cpu_rampD = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampD), "rampD"); + cpu_rampX = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampX), "rampX"); + cpu_rampY = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampY), "rampY"); + cpu_rampZ = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampZ), "rampZ"); + cpu_eind = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(eind), "eind"); + cpu_sp = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sp), "sp"); + cpu_skip = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(skip), "skip"); + + for (i = 0; i < NUMBER_OF_CPU_REGISTERS; i++) { + cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]), + reg_names[i]); + } +#undef AVR_REG_OFFS +} + static int to_regs_16_31_by_one(DisasContext *ctx, int indx) { return 16 + (indx % 16); From 9d8caa67a24ea4375a6dd110d8e7704acb1c8030 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:16 +0100 Subject: [PATCH 2150/2595] target/avr: Add support for disassembling via option '-d in_asm' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide function disassembles executed instruction when '-d in_asm' is provided. Example: $ qemu-system-avr -bios free-rtos/Demo/AVR_ATMega2560_GCC/demo.elf -d in_asm ... IN: 0x0000014a: CALL 0x3808 IN: main 0x00003808: CALL 0x4b4 IN: vParTestInitialise 0x000004b4: LDI r24, 255 0x000004b6: STS r24, 0 0x000004b8: MULS r16, r20 0x000004ba: OUT $1, r24 0x000004bc: LDS r24, 0 0x000004be: MULS r16, r20 0x000004c0: OUT $2, r24 0x000004c2: RET ... Suggested-by: Richard Henderson Suggested-by: Philippe Mathieu-Daudé Suggested-by: Aleksandar Markovic Signed-off-by: Michael Rolnik [rth: Fix spacing and const mnemonic arrays] Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-19-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/cpu.c | 2 +- target/avr/cpu.h | 1 + target/avr/disas.c | 245 +++++++++++++++++++++++++++++++++++++++++ target/avr/translate.c | 12 ++ 4 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 target/avr/disas.c diff --git a/target/avr/cpu.c b/target/avr/cpu.c index b20a116892..e5979c9a9f 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -85,7 +85,7 @@ static void avr_cpu_reset(DeviceState *ds) static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) { info->mach = bfd_arch_avr; - info->print_insn = NULL; + info->print_insn = avr_print_insn; } static void avr_cpu_realizefn(DeviceState *dev, Error **errp) diff --git a/target/avr/cpu.h b/target/avr/cpu.h index d2c2e40c19..d148e8c75a 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -161,6 +161,7 @@ bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req); hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int avr_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +int avr_print_insn(bfd_vma addr, disassemble_info *info); static inline int avr_feature(CPUAVRState *env, AVRFeature feature) { diff --git a/target/avr/disas.c b/target/avr/disas.c new file mode 100644 index 0000000000..60b2cc1325 --- /dev/null +++ b/target/avr/disas.c @@ -0,0 +1,245 @@ +/* + * AVR disassembler + * + * Copyright (c) 2019-2020 Richard Henderson + * Copyright (c) 2019-2020 Michael Rolnik + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "cpu.h" + +typedef struct { + disassemble_info *info; + uint16_t next_word; + bool next_word_used; +} DisasContext; + +static int to_regs_16_31_by_one(DisasContext *ctx, int indx) +{ + return 16 + (indx % 16); +} + +static int to_regs_16_23_by_one(DisasContext *ctx, int indx) +{ + return 16 + (indx % 8); +} + +static int to_regs_24_30_by_two(DisasContext *ctx, int indx) +{ + return 24 + (indx % 4) * 2; +} + +static int to_regs_00_30_by_two(DisasContext *ctx, int indx) +{ + return (indx % 16) * 2; +} + +static uint16_t next_word(DisasContext *ctx) +{ + ctx->next_word_used = true; + return ctx->next_word; +} + +static int append_16(DisasContext *ctx, int x) +{ + return x << 16 | next_word(ctx); +} + +/* Include the auto-generated decoder. */ +static bool decode_insn(DisasContext *ctx, uint16_t insn); +#include "decode_insn.inc.c" + +#define output(mnemonic, format, ...) \ + (pctx->info->fprintf_func(pctx->info->stream, "%-9s " format, \ + mnemonic, ##__VA_ARGS__)) + +int avr_print_insn(bfd_vma addr, disassemble_info *info) +{ + DisasContext ctx; + DisasContext *pctx = &ctx; + bfd_byte buffer[4]; + uint16_t insn; + int status; + + ctx.info = info; + + status = info->read_memory_func(addr, buffer, 4, info); + if (status != 0) { + info->memory_error_func(status, addr, info); + return -1; + } + insn = bfd_getl16(buffer); + ctx.next_word = bfd_getl16(buffer + 2); + ctx.next_word_used = false; + + if (!decode_insn(&ctx, insn)) { + output(".db", "0x%02x, 0x%02x", buffer[0], buffer[1]); + } + + return ctx.next_word_used ? 4 : 2; +} + + +#define INSN(opcode, format, ...) \ +static bool trans_##opcode(DisasContext *pctx, arg_##opcode * a) \ +{ \ + output(#opcode, format, ##__VA_ARGS__); \ + return true; \ +} + +#define INSN_MNEMONIC(opcode, mnemonic, format, ...) \ +static bool trans_##opcode(DisasContext *pctx, arg_##opcode * a) \ +{ \ + output(mnemonic, format, ##__VA_ARGS__); \ + return true; \ +} + +/* + * C Z N V S H T I + * 0 1 2 3 4 5 6 7 + */ +static const char brbc[][5] = { + "BRCC", "BRNE", "BRPL", "BRVC", "BRGE", "BRHC", "BRTC", "BRID" +}; + +static const char brbs[][5] = { + "BRCS", "BREQ", "BRMI", "BRVS", "BRLT", "BRHS", "BRTS", "BRIE" +}; + +static const char bset[][4] = { + "SEC", "SEZ", "SEN", "SEZ", "SES", "SEH", "SET", "SEI" +}; + +static const char bclr[][4] = { + "CLC", "CLZ", "CLN", "CLZ", "CLS", "CLH", "CLT", "CLI" +}; + +/* + * Arithmetic Instructions + */ +INSN(ADD, "r%d, r%d", a->rd, a->rr) +INSN(ADC, "r%d, r%d", a->rd, a->rr) +INSN(ADIW, "r%d:r%d, %d", a->rd + 1, a->rd, a->imm) +INSN(SUB, "r%d, r%d", a->rd, a->rr) +INSN(SUBI, "r%d, %d", a->rd, a->imm) +INSN(SBC, "r%d, r%d", a->rd, a->rr) +INSN(SBCI, "r%d, %d", a->rd, a->imm) +INSN(SBIW, "r%d:r%d, %d", a->rd + 1, a->rd, a->imm) +INSN(AND, "r%d, r%d", a->rd, a->rr) +INSN(ANDI, "r%d, %d", a->rd, a->imm) +INSN(OR, "r%d, r%d", a->rd, a->rr) +INSN(ORI, "r%d, %d", a->rd, a->imm) +INSN(EOR, "r%d, r%d", a->rd, a->rr) +INSN(COM, "r%d", a->rd) +INSN(NEG, "r%d", a->rd) +INSN(INC, "r%d", a->rd) +INSN(DEC, "r%d", a->rd) +INSN(MUL, "r%d, r%d", a->rd, a->rr) +INSN(MULS, "r%d, r%d", a->rd, a->rr) +INSN(MULSU, "r%d, r%d", a->rd, a->rr) +INSN(FMUL, "r%d, r%d", a->rd, a->rr) +INSN(FMULS, "r%d, r%d", a->rd, a->rr) +INSN(FMULSU, "r%d, r%d", a->rd, a->rr) +INSN(DES, "%d", a->imm) + +/* + * Branch Instructions + */ +INSN(RJMP, ".%+d", a->imm * 2) +INSN(IJMP, "") +INSN(EIJMP, "") +INSN(JMP, "0x%x", a->imm * 2) +INSN(RCALL, ".%+d", a->imm * 2) +INSN(ICALL, "") +INSN(EICALL, "") +INSN(CALL, "0x%x", a->imm * 2) +INSN(RET, "") +INSN(RETI, "") +INSN(CPSE, "r%d, r%d", a->rd, a->rr) +INSN(CP, "r%d, r%d", a->rd, a->rr) +INSN(CPC, "r%d, r%d", a->rd, a->rr) +INSN(CPI, "r%d, %d", a->rd, a->imm) +INSN(SBRC, "r%d, %d", a->rr, a->bit) +INSN(SBRS, "r%d, %d", a->rr, a->bit) +INSN(SBIC, "$%d, %d", a->reg, a->bit) +INSN(SBIS, "$%d, %d", a->reg, a->bit) +INSN_MNEMONIC(BRBS, brbs[a->bit], ".%+d", a->imm * 2) +INSN_MNEMONIC(BRBC, brbc[a->bit], ".%+d", a->imm * 2) + +/* + * Data Transfer Instructions + */ +INSN(MOV, "r%d, r%d", a->rd, a->rr) +INSN(MOVW, "r%d:r%d, r%d:r%d", a->rd + 1, a->rd, a->rr + 1, a->rr) +INSN(LDI, "r%d, %d", a->rd, a->imm) +INSN(LDS, "r%d, %d", a->rd, a->imm) +INSN(LDX1, "r%d, X", a->rd) +INSN(LDX2, "r%d, X+", a->rd) +INSN(LDX3, "r%d, -X", a->rd) +INSN(LDY2, "r%d, Y+", a->rd) +INSN(LDY3, "r%d, -Y", a->rd) +INSN(LDZ2, "r%d, Z+", a->rd) +INSN(LDZ3, "r%d, -Z", a->rd) +INSN(LDDY, "r%d, Y+%d", a->rd, a->imm) +INSN(LDDZ, "r%d, Z+%d", a->rd, a->imm) +INSN(STS, "r%d, %d", a->rd, a->imm) +INSN(STX1, "r%d, X", a->rr) +INSN(STX2, "r%d, X+", a->rr) +INSN(STX3, "r%d, -X", a->rr) +INSN(STY2, "r%d, Y+", a->rd) +INSN(STY3, "r%d, -Y", a->rd) +INSN(STZ2, "r%d, Z+", a->rd) +INSN(STZ3, "r%d, -Z", a->rd) +INSN(STDY, "r%d, Y+%d", a->rd, a->imm) +INSN(STDZ, "r%d, Z+%d", a->rd, a->imm) +INSN(LPM1, "") +INSN(LPM2, "r%d, Z", a->rd) +INSN(LPMX, "r%d, Z+", a->rd) +INSN(ELPM1, "") +INSN(ELPM2, "r%d, Z", a->rd) +INSN(ELPMX, "r%d, Z+", a->rd) +INSN(SPM, "") +INSN(SPMX, "Z+") +INSN(IN, "r%d, $%d", a->rd, a->imm) +INSN(OUT, "$%d, r%d", a->imm, a->rd) +INSN(PUSH, "r%d", a->rd) +INSN(POP, "r%d", a->rd) +INSN(XCH, "Z, r%d", a->rd) +INSN(LAC, "Z, r%d", a->rd) +INSN(LAS, "Z, r%d", a->rd) +INSN(LAT, "Z, r%d", a->rd) + +/* + * Bit and Bit-test Instructions + */ +INSN(LSR, "r%d", a->rd) +INSN(ROR, "r%d", a->rd) +INSN(ASR, "r%d", a->rd) +INSN(SWAP, "r%d", a->rd) +INSN(SBI, "$%d, %d", a->reg, a->bit) +INSN(CBI, "%d, %d", a->reg, a->bit) +INSN(BST, "r%d, %d", a->rd, a->bit) +INSN(BLD, "r%d, %d", a->rd, a->bit) +INSN_MNEMONIC(BSET, bset[a->bit], "") +INSN_MNEMONIC(BCLR, bclr[a->bit], "") + +/* + * MCU Control Instructions + */ +INSN(BREAK, "") +INSN(NOP, "") +INSN(SLEEP, "") +INSN(WDR, "") diff --git a/target/avr/translate.c b/target/avr/translate.c index 3d8a77e5ae..648dcd5c3e 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -3040,6 +3040,18 @@ done_generating: tb->size = (ctx.npc - pc_start) * 2; tb->icount = num_insns; + +#ifdef DEBUG_DISAS + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) + && qemu_log_in_addr_range(tb->pc)) { + FILE *fd; + fd = qemu_log_lock(); + qemu_log("IN: %s\n", lookup_symbol(tb->pc)); + log_target_disas(cs, tb->pc, tb->size); + qemu_log("\n"); + qemu_log_unlock(fd); + } +#endif } void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, From 42f3ff001339e37df4f13b709d2db00a488ee45c Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:21 +0100 Subject: [PATCH 2151/2595] target/avr: Register AVR support with the rest of QEMU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add AVR related definitions into QEMU, make AVR support buildable. [AM: Remove word 'Atmel' from filenames and all elements of code] Suggested-by: Aleksandar Markovic Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-23-huth@tuxfamily.org> [PMD: Fixed @avr tag in qapi/machine.json] Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 9 +++++++++ arch_init.c | 2 ++ configure | 7 +++++++ default-configs/avr-softmmu.mak | 1 + include/disas/dis-asm.h | 19 ++++++++++++++++++ include/sysemu/arch_init.h | 1 + qapi/machine.json | 3 ++- target/avr/Makefile.objs | 34 +++++++++++++++++++++++++++++++++ 8 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 target/avr/Makefile.objs diff --git a/MAINTAINERS b/MAINTAINERS index 7833db3abe..659a9c789f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -975,6 +975,15 @@ F: include/hw/*/nrf51*.h F: include/hw/*/microbit*.h F: tests/qtest/microbit-test.c +AVR Machines +------------- + +AVR MCUs +M: Michael Rolnik +R: Sarah Harris +S: Maintained +F: default-configs/avr-softmmu.mak + CRIS Machines ------------- Axis Dev88 diff --git a/arch_init.c b/arch_init.c index 8afea4748b..7fd5c09b2b 100644 --- a/arch_init.c +++ b/arch_init.c @@ -90,6 +90,8 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_UNICORE32 #elif defined(TARGET_XTENSA) #define QEMU_ARCH QEMU_ARCH_XTENSA +#elif defined(TARGET_AVR) +#define QEMU_ARCH QEMU_ARCH_AVR #endif const uint32_t arch_type = QEMU_ARCH; diff --git a/configure b/configure index ee6c3c6792..31e2ddbf28 100755 --- a/configure +++ b/configure @@ -8143,6 +8143,10 @@ case "$target_name" in mttcg="yes" gdb_xml_files="aarch64-core.xml aarch64-fpu.xml arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml arm-m-profile.xml" ;; + avr) + gdb_xml_files="avr-cpu.xml" + target_compiler=$cross_cc_avr + ;; cris) ;; hppa) @@ -8387,6 +8391,9 @@ for i in $ARCH $TARGET_BASE_ARCH ; do disas_config "ARM_A64" fi ;; + avr) + disas_config "AVR" + ;; cris) disas_config "CRIS" ;; diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak new file mode 100644 index 0000000000..ca94aad4e1 --- /dev/null +++ b/default-configs/avr-softmmu.mak @@ -0,0 +1 @@ +# Default configuration for avr-softmmu diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index c5f9fa08ab..9856bf7921 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -211,6 +211,25 @@ enum bfd_architecture #define bfd_mach_m32r 0 /* backwards compatibility */ bfd_arch_mn10200, /* Matsushita MN10200 */ bfd_arch_mn10300, /* Matsushita MN10300 */ + bfd_arch_avr, /* AVR microcontrollers */ +#define bfd_mach_avr1 1 +#define bfd_mach_avr2 2 +#define bfd_mach_avr25 25 +#define bfd_mach_avr3 3 +#define bfd_mach_avr31 31 +#define bfd_mach_avr35 35 +#define bfd_mach_avr4 4 +#define bfd_mach_avr5 5 +#define bfd_mach_avr51 51 +#define bfd_mach_avr6 6 +#define bfd_mach_avrtiny 100 +#define bfd_mach_avrxmega1 101 +#define bfd_mach_avrxmega2 102 +#define bfd_mach_avrxmega3 103 +#define bfd_mach_avrxmega4 104 +#define bfd_mach_avrxmega5 105 +#define bfd_mach_avrxmega6 106 +#define bfd_mach_avrxmega7 107 bfd_arch_cris, /* Axis CRIS */ #define bfd_mach_cris_v0_v10 255 #define bfd_mach_cris_v32 32 diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 71a7a285ee..54f069d491 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -25,6 +25,7 @@ enum { QEMU_ARCH_HPPA = (1 << 18), QEMU_ARCH_RISCV = (1 << 19), QEMU_ARCH_RX = (1 << 20), + QEMU_ARCH_AVR = (1 << 21), QEMU_ARCH_NONE = (1 << 31), }; diff --git a/qapi/machine.json b/qapi/machine.json index ff7b5032e3..f59144023c 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -17,6 +17,7 @@ # being. # # @rx: since 5.0 +# @avr: since 5.1 # # Notes: The resulting QMP strings can be appended to the "qemu-system-" # prefix to produce the corresponding QEMU executable name. This @@ -25,7 +26,7 @@ # Since: 3.0 ## { 'enum' : 'SysEmuTarget', - 'data' : [ 'aarch64', 'alpha', 'arm', 'cris', 'hppa', 'i386', 'lm32', + 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386', 'lm32', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', 'mips64el', 'mipsel', 'moxie', 'nios2', 'or1k', 'ppc', 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', diff --git a/target/avr/Makefile.objs b/target/avr/Makefile.objs new file mode 100644 index 0000000000..6e35ba2c5c --- /dev/null +++ b/target/avr/Makefile.objs @@ -0,0 +1,34 @@ +# +# QEMU AVR +# +# Copyright (c) 2016-2020 Michael Rolnik +# +# 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.1 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 +# +# + +DECODETREE = $(SRC_PATH)/scripts/decodetree.py +decode-y = $(SRC_PATH)/target/avr/insn.decode + +target/avr/decode_insn.inc.c: $(decode-y) $(DECODETREE) + $(call quiet-command, \ + $(PYTHON) $(DECODETREE) -o $@ --decode decode_insn --insnwidth 16 $<, \ + "GEN", $(TARGET_DIR)$@) + +target/avr/translate.o: target/avr/decode_insn.inc.c + +obj-y += translate.o cpu.o helper.o +obj-y += gdbstub.o +obj-y += disas.o +obj-$(CONFIG_SOFTMMU) += machine.o From 754cea8c4e5e1dea6465fa7a13077ecbf0e03f08 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:22 +0100 Subject: [PATCH 2152/2595] tests/machine-none: Add AVR support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a single code line that will automatically provide 'machine none' test. Signed-off-by: Michael Rolnik Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-28-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- tests/qtest/machine-none-test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c index 8b7abea8af..57107f1aec 100644 --- a/tests/qtest/machine-none-test.c +++ b/tests/qtest/machine-none-test.c @@ -27,6 +27,7 @@ static struct arch2cpu cpus_map[] = { /* tested targets list */ { "arm", "cortex-a15" }, { "aarch64", "cortex-a57" }, + { "avr", "avr6-avr-cpu" }, { "x86_64", "qemu64,apic-id=0" }, { "i386", "qemu32,apic-id=0" }, { "alpha", "ev67" }, From 429ca9d6658019e27ee07e459a495f112f4dbb96 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:17 +0100 Subject: [PATCH 2153/2595] hw/char: avr: Add limited support for USART peripheral MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These were designed to facilitate testing but should provide enough function to be useful in other contexts. Only a subset of the functions of each peripheral is implemented, mainly due to the lack of a standard way to handle electrical connections (like GPIO pins). [AM: Remove word 'Atmel' from filenames and all elements of code] Suggested-by: Aleksandar Markovic Signed-off-by: Michael Rolnik Signed-off-by: Sarah Harris Signed-off-by: Philippe Mathieu-Daudé [rth: Squash I/O size fix and file rename from f4bug] Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-20-huth@tuxfamily.org> --- MAINTAINERS | 2 + hw/char/Kconfig | 3 + hw/char/Makefile.objs | 1 + hw/char/avr_usart.c | 320 ++++++++++++++++++++++++++++++++++++ include/hw/char/avr_usart.h | 93 +++++++++++ 5 files changed, 419 insertions(+) create mode 100644 hw/char/avr_usart.c create mode 100644 include/hw/char/avr_usart.h diff --git a/MAINTAINERS b/MAINTAINERS index 659a9c789f..be903053de 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -983,6 +983,8 @@ M: Michael Rolnik R: Sarah Harris S: Maintained F: default-configs/avr-softmmu.mak +F: include/hw/char/avr_usart.h +F: hw/char/avr_usart.c CRIS Machines ------------- diff --git a/hw/char/Kconfig b/hw/char/Kconfig index 874627520c..b7e0e4d5fa 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig @@ -49,3 +49,6 @@ config TERMINAL3270 config RENESAS_SCI bool + +config AVR_USART + bool diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs index 8306c4a789..bf177ac41d 100644 --- a/hw/char/Makefile.objs +++ b/hw/char/Makefile.objs @@ -22,6 +22,7 @@ common-obj-$(CONFIG_DIGIC) += digic-uart.o common-obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o common-obj-$(CONFIG_RASPI) += bcm2835_aux.o common-obj-$(CONFIG_RENESAS_SCI) += renesas_sci.o +common-obj-$(CONFIG_AVR_USART) += avr_usart.o common-obj-$(CONFIG_CMSDK_APB_UART) += cmsdk-apb-uart.o common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o diff --git a/hw/char/avr_usart.c b/hw/char/avr_usart.c new file mode 100644 index 0000000000..fbe2a112b7 --- /dev/null +++ b/hw/char/avr_usart.c @@ -0,0 +1,320 @@ +/* + * AVR USART + * + * Copyright (c) 2018 University of Kent + * Author: Sarah Harris + * + * 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.1 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 + * + */ + +#include "qemu/osdep.h" +#include "hw/char/avr_usart.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" + +static int avr_usart_can_receive(void *opaque) +{ + AVRUsartState *usart = opaque; + + if (usart->data_valid || !(usart->csrb & USART_CSRB_RXEN)) { + return 0; + } + return 1; +} + +static void avr_usart_receive(void *opaque, const uint8_t *buffer, int size) +{ + AVRUsartState *usart = opaque; + assert(size == 1); + assert(!usart->data_valid); + usart->data = buffer[0]; + usart->data_valid = true; + usart->csra |= USART_CSRA_RXC; + if (usart->csrb & USART_CSRB_RXCIE) { + qemu_set_irq(usart->rxc_irq, 1); + } +} + +static void update_char_mask(AVRUsartState *usart) +{ + uint8_t mode = ((usart->csrc & USART_CSRC_CSZ0) ? 1 : 0) | + ((usart->csrc & USART_CSRC_CSZ1) ? 2 : 0) | + ((usart->csrb & USART_CSRB_CSZ2) ? 4 : 0); + switch (mode) { + case 0: + usart->char_mask = 0b11111; + break; + case 1: + usart->char_mask = 0b111111; + break; + case 2: + usart->char_mask = 0b1111111; + break; + case 3: + usart->char_mask = 0b11111111; + break; + case 4: + /* Fallthrough. */ + case 5: + /* Fallthrough. */ + case 6: + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Reserved character size 0x%x\n", + __func__, + mode); + break; + case 7: + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Nine bit character size not supported (forcing eight)\n", + __func__); + usart->char_mask = 0b11111111; + break; + default: + assert(0); + } +} + +static void avr_usart_reset(DeviceState *dev) +{ + AVRUsartState *usart = AVR_USART(dev); + usart->data_valid = false; + usart->csra = 0b00100000; + usart->csrb = 0b00000000; + usart->csrc = 0b00000110; + usart->brrl = 0; + usart->brrh = 0; + update_char_mask(usart); + qemu_set_irq(usart->rxc_irq, 0); + qemu_set_irq(usart->txc_irq, 0); + qemu_set_irq(usart->dre_irq, 0); +} + +static uint64_t avr_usart_read(void *opaque, hwaddr addr, unsigned int size) +{ + AVRUsartState *usart = opaque; + uint8_t data; + assert(size == 1); + + if (!usart->enabled) { + return 0; + } + + switch (addr) { + case USART_DR: + if (!(usart->csrb & USART_CSRB_RXEN)) { + /* Receiver disabled, ignore. */ + return 0; + } + if (usart->data_valid) { + data = usart->data & usart->char_mask; + usart->data_valid = false; + } else { + data = 0; + } + usart->csra &= 0xff ^ USART_CSRA_RXC; + qemu_set_irq(usart->rxc_irq, 0); + qemu_chr_fe_accept_input(&usart->chr); + return data; + case USART_CSRA: + return usart->csra; + case USART_CSRB: + return usart->csrb; + case USART_CSRC: + return usart->csrc; + case USART_BRRL: + return usart->brrl; + case USART_BRRH: + return usart->brrh; + default: + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", + __func__, + addr); + } + return 0; +} + +static void avr_usart_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) +{ + AVRUsartState *usart = opaque; + uint8_t mask; + uint8_t data; + assert((value & 0xff) == value); + assert(size == 1); + + if (!usart->enabled) { + return; + } + + switch (addr) { + case USART_DR: + if (!(usart->csrb & USART_CSRB_TXEN)) { + /* Transmitter disabled, ignore. */ + return; + } + usart->csra |= USART_CSRA_TXC; + usart->csra |= USART_CSRA_DRE; + if (usart->csrb & USART_CSRB_TXCIE) { + qemu_set_irq(usart->txc_irq, 1); + usart->csra &= 0xff ^ USART_CSRA_TXC; + } + if (usart->csrb & USART_CSRB_DREIE) { + qemu_set_irq(usart->dre_irq, 1); + } + data = value; + qemu_chr_fe_write_all(&usart->chr, &data, 1); + break; + case USART_CSRA: + mask = 0b01000011; + /* Mask read-only bits. */ + value = (value & mask) | (usart->csra & (0xff ^ mask)); + usart->csra = value; + if (value & USART_CSRA_TXC) { + usart->csra ^= USART_CSRA_TXC; + qemu_set_irq(usart->txc_irq, 0); + } + if (value & USART_CSRA_MPCM) { + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: MPCM not supported by USART\n", + __func__); + } + break; + case USART_CSRB: + mask = 0b11111101; + /* Mask read-only bits. */ + value = (value & mask) | (usart->csrb & (0xff ^ mask)); + usart->csrb = value; + if (!(value & USART_CSRB_RXEN)) { + /* Receiver disabled, flush input buffer. */ + usart->data_valid = false; + } + qemu_set_irq(usart->rxc_irq, + ((value & USART_CSRB_RXCIE) && + (usart->csra & USART_CSRA_RXC)) ? 1 : 0); + qemu_set_irq(usart->txc_irq, + ((value & USART_CSRB_TXCIE) && + (usart->csra & USART_CSRA_TXC)) ? 1 : 0); + qemu_set_irq(usart->dre_irq, + ((value & USART_CSRB_DREIE) && + (usart->csra & USART_CSRA_DRE)) ? 1 : 0); + update_char_mask(usart); + break; + case USART_CSRC: + usart->csrc = value; + if ((value & USART_CSRC_MSEL1) && (value & USART_CSRC_MSEL0)) { + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: SPI mode not supported by USART\n", + __func__); + } + if ((value & USART_CSRC_MSEL1) && !(value & USART_CSRC_MSEL0)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad USART mode\n", __func__); + } + if (!(value & USART_CSRC_PM1) && (value & USART_CSRC_PM0)) { + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Bad USART parity mode\n", + __func__); + } + update_char_mask(usart); + break; + case USART_BRRL: + usart->brrl = value; + break; + case USART_BRRH: + usart->brrh = value & 0b00001111; + break; + default: + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", + __func__, + addr); + } +} + +static const MemoryRegionOps avr_usart_ops = { + .read = avr_usart_read, + .write = avr_usart_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = {.min_access_size = 1, .max_access_size = 1} +}; + +static Property avr_usart_properties[] = { + DEFINE_PROP_CHR("chardev", AVRUsartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void avr_usart_pr(void *opaque, int irq, int level) +{ + AVRUsartState *s = AVR_USART(opaque); + + s->enabled = !level; + + if (!s->enabled) { + avr_usart_reset(DEVICE(s)); + } +} + +static void avr_usart_init(Object *obj) +{ + AVRUsartState *s = AVR_USART(obj); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rxc_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->dre_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->txc_irq); + memory_region_init_io(&s->mmio, obj, &avr_usart_ops, s, TYPE_AVR_USART, 7); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + qdev_init_gpio_in(DEVICE(s), avr_usart_pr, 1); + s->enabled = true; +} + +static void avr_usart_realize(DeviceState *dev, Error **errp) +{ + AVRUsartState *s = AVR_USART(dev); + qemu_chr_fe_set_handlers(&s->chr, avr_usart_can_receive, + avr_usart_receive, NULL, NULL, + s, NULL, true); + avr_usart_reset(dev); +} + +static void avr_usart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = avr_usart_reset; + device_class_set_props(dc, avr_usart_properties); + dc->realize = avr_usart_realize; +} + +static const TypeInfo avr_usart_info = { + .name = TYPE_AVR_USART, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AVRUsartState), + .instance_init = avr_usart_init, + .class_init = avr_usart_class_init, +}; + +static void avr_usart_register_types(void) +{ + type_register_static(&avr_usart_info); +} + +type_init(avr_usart_register_types) diff --git a/include/hw/char/avr_usart.h b/include/hw/char/avr_usart.h new file mode 100644 index 0000000000..5739aaf26f --- /dev/null +++ b/include/hw/char/avr_usart.h @@ -0,0 +1,93 @@ +/* + * AVR USART + * + * Copyright (c) 2018 University of Kent + * Author: Sarah Harris + * + * 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.1 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 + * + */ + +#ifndef HW_CHAR_AVR_USART_H +#define HW_CHAR_AVR_USART_H + +#include "hw/sysbus.h" +#include "chardev/char-fe.h" +#include "hw/hw.h" + +/* Offsets of registers. */ +#define USART_DR 0x06 +#define USART_CSRA 0x00 +#define USART_CSRB 0x01 +#define USART_CSRC 0x02 +#define USART_BRRH 0x05 +#define USART_BRRL 0x04 + +/* Relevant bits in regiters. */ +#define USART_CSRA_RXC (1 << 7) +#define USART_CSRA_TXC (1 << 6) +#define USART_CSRA_DRE (1 << 5) +#define USART_CSRA_MPCM (1 << 0) + +#define USART_CSRB_RXCIE (1 << 7) +#define USART_CSRB_TXCIE (1 << 6) +#define USART_CSRB_DREIE (1 << 5) +#define USART_CSRB_RXEN (1 << 4) +#define USART_CSRB_TXEN (1 << 3) +#define USART_CSRB_CSZ2 (1 << 2) +#define USART_CSRB_RXB8 (1 << 1) +#define USART_CSRB_TXB8 (1 << 0) + +#define USART_CSRC_MSEL1 (1 << 7) +#define USART_CSRC_MSEL0 (1 << 6) +#define USART_CSRC_PM1 (1 << 5) +#define USART_CSRC_PM0 (1 << 4) +#define USART_CSRC_CSZ1 (1 << 2) +#define USART_CSRC_CSZ0 (1 << 1) + +#define TYPE_AVR_USART "avr-usart" +#define AVR_USART(obj) \ + OBJECT_CHECK(AVRUsartState, (obj), TYPE_AVR_USART) + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + + CharBackend chr; + + bool enabled; + + uint8_t data; + bool data_valid; + uint8_t char_mask; + /* Control and Status Registers */ + uint8_t csra; + uint8_t csrb; + uint8_t csrc; + /* Baud Rate Registers (low/high byte) */ + uint8_t brrh; + uint8_t brrl; + + /* Receive Complete */ + qemu_irq rxc_irq; + /* Transmit Complete */ + qemu_irq txc_irq; + /* Data Register Empty */ + qemu_irq dre_irq; +} AVRUsartState; + +#endif /* HW_CHAR_AVR_USART_H */ From 8ff47bc1a0c798141479530bf9cb3836b49fc5e1 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:18 +0100 Subject: [PATCH 2154/2595] hw/timer: avr: Add limited support for 16-bit timer peripheral MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These were designed to facilitate testing but should provide enough function to be useful in other contexts. Only a subset of the functions of each peripheral is implemented, mainly due to the lack of a standard way to handle electrical connections (like GPIO pins). [AM: Remove word 'Atmel' from filenames and all elements of code] Suggested-by: Aleksandar Markovic Signed-off-by: Sarah Harris Signed-off-by: Ed Robbins Signed-off-by: Philippe Mathieu-Daudé [rth: Squash info mtree fixes and a file rename from f4bug] Signed-off-by: Richard Henderson [PMD: Use qemu_log_mask(LOG_UNIMP), replace goto by return] Signed-off-by: Aleksandar Markovic Reviewed-by: Alex Bennée Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-21-huth@tuxfamily.org> [PMD: Check cpu-frequency-hz property in realize()] Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 2 + hw/timer/Kconfig | 3 + hw/timer/Makefile.objs | 2 + hw/timer/avr_timer16.c | 621 +++++++++++++++++++++++++++++++++ hw/timer/trace-events | 12 + include/hw/timer/avr_timer16.h | 94 +++++ 6 files changed, 734 insertions(+) create mode 100644 hw/timer/avr_timer16.c create mode 100644 include/hw/timer/avr_timer16.h diff --git a/MAINTAINERS b/MAINTAINERS index be903053de..3541955f5f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -985,6 +985,8 @@ S: Maintained F: default-configs/avr-softmmu.mak F: include/hw/char/avr_usart.h F: hw/char/avr_usart.c +F: include/hw/timer/avr_timer16.h +F: hw/timer/avr_timer16.c CRIS Machines ------------- diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index 59a667c503..8749edfb6a 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -41,3 +41,6 @@ config RENESAS_TMR config RENESAS_CMT bool + +config AVR_TIMER16 + bool diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index a39f6ec0c2..1303b13e0d 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -37,3 +37,5 @@ common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o common-obj-$(CONFIG_CMSDK_APB_DUALTIMER) += cmsdk-apb-dualtimer.o common-obj-$(CONFIG_MSF2) += mss-timer.o common-obj-$(CONFIG_RASPI) += bcm2835_systmr.o + +obj-$(CONFIG_AVR_TIMER16) += avr_timer16.o diff --git a/hw/timer/avr_timer16.c b/hw/timer/avr_timer16.c new file mode 100644 index 0000000000..c48555da52 --- /dev/null +++ b/hw/timer/avr_timer16.c @@ -0,0 +1,621 @@ +/* + * AVR 16-bit timer + * + * Copyright (c) 2018 University of Kent + * Author: Ed Robbins + * + * 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.1 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 + * + */ + +/* + * Driver for 16 bit timers on 8 bit AVR devices. + * Note: + * ATmega640/V-1280/V-1281/V-2560/V-2561/V timers 1, 3, 4 and 5 are 16 bit + */ + +/* + * XXX TODO: Power Reduction Register support + * prescaler pause support + * PWM modes, GPIO, output capture pins, input compare pin + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/timer/avr_timer16.h" +#include "trace.h" + +/* Register offsets */ +#define T16_CRA 0x0 +#define T16_CRB 0x1 +#define T16_CRC 0x2 +#define T16_CNTL 0x4 +#define T16_CNTH 0x5 +#define T16_ICRL 0x6 +#define T16_ICRH 0x7 +#define T16_OCRAL 0x8 +#define T16_OCRAH 0x9 +#define T16_OCRBL 0xa +#define T16_OCRBH 0xb +#define T16_OCRCL 0xc +#define T16_OCRCH 0xd + +/* Field masks */ +#define T16_CRA_WGM01 0x3 +#define T16_CRA_COMC 0xc +#define T16_CRA_COMB 0x30 +#define T16_CRA_COMA 0xc0 +#define T16_CRA_OC_CONF \ + (T16_CRA_COMA | T16_CRA_COMB | T16_CRA_COMC) + +#define T16_CRB_CS 0x7 +#define T16_CRB_WGM23 0x18 +#define T16_CRB_ICES 0x40 +#define T16_CRB_ICNC 0x80 + +#define T16_CRC_FOCC 0x20 +#define T16_CRC_FOCB 0x40 +#define T16_CRC_FOCA 0x80 + +/* Fields masks both TIMSK and TIFR (interrupt mask/flag registers) */ +#define T16_INT_TOV 0x1 /* Timer overflow */ +#define T16_INT_OCA 0x2 /* Output compare A */ +#define T16_INT_OCB 0x4 /* Output compare B */ +#define T16_INT_OCC 0x8 /* Output compare C */ +#define T16_INT_IC 0x20 /* Input capture */ + +/* Clock source values */ +#define T16_CLKSRC_STOPPED 0 +#define T16_CLKSRC_DIV1 1 +#define T16_CLKSRC_DIV8 2 +#define T16_CLKSRC_DIV64 3 +#define T16_CLKSRC_DIV256 4 +#define T16_CLKSRC_DIV1024 5 +#define T16_CLKSRC_EXT_FALLING 6 +#define T16_CLKSRC_EXT_RISING 7 + +/* Timer mode values (not including PWM modes) */ +#define T16_MODE_NORMAL 0 +#define T16_MODE_CTC_OCRA 4 +#define T16_MODE_CTC_ICR 12 + +/* Accessors */ +#define CLKSRC(t16) (t16->crb & T16_CRB_CS) +#define MODE(t16) (((t16->crb & T16_CRB_WGM23) >> 1) | \ + (t16->cra & T16_CRA_WGM01)) +#define CNT(t16) VAL16(t16->cntl, t16->cnth) +#define OCRA(t16) VAL16(t16->ocral, t16->ocrah) +#define OCRB(t16) VAL16(t16->ocrbl, t16->ocrbh) +#define OCRC(t16) VAL16(t16->ocrcl, t16->ocrch) +#define ICR(t16) VAL16(t16->icrl, t16->icrh) + +/* Helper macros */ +#define VAL16(l, h) ((h << 8) | l) +#define DB_PRINT(fmt, args...) /* Nothing */ + +static inline int64_t avr_timer16_ns_to_ticks(AVRTimer16State *t16, int64_t t) +{ + if (t16->period_ns == 0) { + return 0; + } + return t / t16->period_ns; +} + +static void avr_timer16_update_cnt(AVRTimer16State *t16) +{ + uint16_t cnt; + cnt = avr_timer16_ns_to_ticks(t16, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - + t16->reset_time_ns); + t16->cntl = (uint8_t)(cnt & 0xff); + t16->cnth = (uint8_t)((cnt & 0xff00) >> 8); +} + +static inline void avr_timer16_recalc_reset_time(AVRTimer16State *t16) +{ + t16->reset_time_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - + CNT(t16) * t16->period_ns; +} + +static void avr_timer16_clock_reset(AVRTimer16State *t16) +{ + t16->cntl = 0; + t16->cnth = 0; + t16->reset_time_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + +static void avr_timer16_clksrc_update(AVRTimer16State *t16) +{ + uint16_t divider = 0; + switch (CLKSRC(t16)) { + case T16_CLKSRC_EXT_FALLING: + case T16_CLKSRC_EXT_RISING: + qemu_log_mask(LOG_UNIMP, "%s: external clock source unsupported\n", + __func__); + break; + case T16_CLKSRC_STOPPED: + break; + case T16_CLKSRC_DIV1: + divider = 1; + break; + case T16_CLKSRC_DIV8: + divider = 8; + break; + case T16_CLKSRC_DIV64: + divider = 64; + break; + case T16_CLKSRC_DIV256: + divider = 256; + break; + case T16_CLKSRC_DIV1024: + divider = 1024; + break; + default: + break; + } + if (divider) { + t16->freq_hz = t16->cpu_freq_hz / divider; + t16->period_ns = NANOSECONDS_PER_SECOND / t16->freq_hz; + trace_avr_timer16_clksrc_update(t16->freq_hz, t16->period_ns, + (uint64_t)(1e6 / t16->freq_hz)); + } +} + +static void avr_timer16_set_alarm(AVRTimer16State *t16) +{ + if (CLKSRC(t16) == T16_CLKSRC_EXT_FALLING || + CLKSRC(t16) == T16_CLKSRC_EXT_RISING || + CLKSRC(t16) == T16_CLKSRC_STOPPED) { + /* Timer is disabled or set to external clock source (unsupported) */ + return; + } + + uint64_t alarm_offset = 0xffff; + enum NextInterrupt next_interrupt = OVERFLOW; + + switch (MODE(t16)) { + case T16_MODE_NORMAL: + /* Normal mode */ + if (OCRA(t16) < alarm_offset && OCRA(t16) > CNT(t16) && + (t16->imsk & T16_INT_OCA)) { + alarm_offset = OCRA(t16); + next_interrupt = COMPA; + } + break; + case T16_MODE_CTC_OCRA: + /* CTC mode, top = ocra */ + if (OCRA(t16) < alarm_offset && OCRA(t16) > CNT(t16)) { + alarm_offset = OCRA(t16); + next_interrupt = COMPA; + } + break; + case T16_MODE_CTC_ICR: + /* CTC mode, top = icr */ + if (ICR(t16) < alarm_offset && ICR(t16) > CNT(t16)) { + alarm_offset = ICR(t16); + next_interrupt = CAPT; + } + if (OCRA(t16) < alarm_offset && OCRA(t16) > CNT(t16) && + (t16->imsk & T16_INT_OCA)) { + alarm_offset = OCRA(t16); + next_interrupt = COMPA; + } + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: pwm modes are unsupported\n", + __func__); + return; + } + if (OCRB(t16) < alarm_offset && OCRB(t16) > CNT(t16) && + (t16->imsk & T16_INT_OCB)) { + alarm_offset = OCRB(t16); + next_interrupt = COMPB; + } + if (OCRC(t16) < alarm_offset && OCRB(t16) > CNT(t16) && + (t16->imsk & T16_INT_OCC)) { + alarm_offset = OCRB(t16); + next_interrupt = COMPC; + } + alarm_offset -= CNT(t16); + + t16->next_interrupt = next_interrupt; + uint64_t alarm_ns = + t16->reset_time_ns + ((CNT(t16) + alarm_offset) * t16->period_ns); + timer_mod(t16->timer, alarm_ns); + + trace_avr_timer16_next_alarm(alarm_offset * t16->period_ns); +} + +static void avr_timer16_interrupt(void *opaque) +{ + AVRTimer16State *t16 = opaque; + uint8_t mode = MODE(t16); + + avr_timer16_update_cnt(t16); + + if (CLKSRC(t16) == T16_CLKSRC_EXT_FALLING || + CLKSRC(t16) == T16_CLKSRC_EXT_RISING || + CLKSRC(t16) == T16_CLKSRC_STOPPED) { + /* Timer is disabled or set to external clock source (unsupported) */ + return; + } + + trace_avr_timer16_interrupt_count(CNT(t16)); + + /* Counter overflow */ + if (t16->next_interrupt == OVERFLOW) { + trace_avr_timer16_interrupt_overflow("counter 0xffff"); + avr_timer16_clock_reset(t16); + if (t16->imsk & T16_INT_TOV) { + t16->ifr |= T16_INT_TOV; + qemu_set_irq(t16->ovf_irq, 1); + } + } + /* Check for ocra overflow in CTC mode */ + if (mode == T16_MODE_CTC_OCRA && t16->next_interrupt == COMPA) { + trace_avr_timer16_interrupt_overflow("CTC OCRA"); + avr_timer16_clock_reset(t16); + } + /* Check for icr overflow in CTC mode */ + if (mode == T16_MODE_CTC_ICR && t16->next_interrupt == CAPT) { + trace_avr_timer16_interrupt_overflow("CTC ICR"); + avr_timer16_clock_reset(t16); + if (t16->imsk & T16_INT_IC) { + t16->ifr |= T16_INT_IC; + qemu_set_irq(t16->capt_irq, 1); + } + } + /* Check for output compare interrupts */ + if (t16->imsk & T16_INT_OCA && t16->next_interrupt == COMPA) { + t16->ifr |= T16_INT_OCA; + qemu_set_irq(t16->compa_irq, 1); + } + if (t16->imsk & T16_INT_OCB && t16->next_interrupt == COMPB) { + t16->ifr |= T16_INT_OCB; + qemu_set_irq(t16->compb_irq, 1); + } + if (t16->imsk & T16_INT_OCC && t16->next_interrupt == COMPC) { + t16->ifr |= T16_INT_OCC; + qemu_set_irq(t16->compc_irq, 1); + } + avr_timer16_set_alarm(t16); +} + +static void avr_timer16_reset(DeviceState *dev) +{ + AVRTimer16State *t16 = AVR_TIMER16(dev); + + avr_timer16_clock_reset(t16); + avr_timer16_clksrc_update(t16); + avr_timer16_set_alarm(t16); + + qemu_set_irq(t16->capt_irq, 0); + qemu_set_irq(t16->compa_irq, 0); + qemu_set_irq(t16->compb_irq, 0); + qemu_set_irq(t16->compc_irq, 0); + qemu_set_irq(t16->ovf_irq, 0); +} + +static uint64_t avr_timer16_read(void *opaque, hwaddr offset, unsigned size) +{ + assert(size == 1); + AVRTimer16State *t16 = opaque; + uint8_t retval = 0; + + switch (offset) { + case T16_CRA: + retval = t16->cra; + break; + case T16_CRB: + retval = t16->crb; + break; + case T16_CRC: + retval = t16->crc; + break; + case T16_CNTL: + avr_timer16_update_cnt(t16); + t16->rtmp = t16->cnth; + retval = t16->cntl; + break; + case T16_CNTH: + retval = t16->rtmp; + break; + case T16_ICRL: + /* + * The timer copies cnt to icr when the input capture pin changes + * state or when the analog comparator has a match. We don't + * emulate this behaviour. We do support it's use for defining a + * TOP value in T16_MODE_CTC_ICR + */ + t16->rtmp = t16->icrh; + retval = t16->icrl; + break; + case T16_ICRH: + retval = t16->rtmp; + break; + case T16_OCRAL: + retval = t16->ocral; + break; + case T16_OCRAH: + retval = t16->ocrah; + break; + case T16_OCRBL: + retval = t16->ocrbl; + break; + case T16_OCRBH: + retval = t16->ocrbh; + break; + case T16_OCRCL: + retval = t16->ocrcl; + break; + case T16_OCRCH: + retval = t16->ocrch; + break; + default: + break; + } + trace_avr_timer16_read(offset, retval); + + return (uint64_t)retval; +} + +static void avr_timer16_write(void *opaque, hwaddr offset, + uint64_t val64, unsigned size) +{ + assert(size == 1); + AVRTimer16State *t16 = opaque; + uint8_t val8 = (uint8_t)val64; + uint8_t prev_clk_src = CLKSRC(t16); + + trace_avr_timer16_write(offset, val8); + + switch (offset) { + case T16_CRA: + t16->cra = val8; + if (t16->cra & T16_CRA_OC_CONF) { + qemu_log_mask(LOG_UNIMP, "%s: output compare pins unsupported\n", + __func__); + } + break; + case T16_CRB: + t16->crb = val8; + if (t16->crb & T16_CRB_ICNC) { + qemu_log_mask(LOG_UNIMP, + "%s: input capture noise canceller unsupported\n", + __func__); + } + if (t16->crb & T16_CRB_ICES) { + qemu_log_mask(LOG_UNIMP, "%s: input capture unsupported\n", + __func__); + } + if (CLKSRC(t16) != prev_clk_src) { + avr_timer16_clksrc_update(t16); + if (prev_clk_src == T16_CLKSRC_STOPPED) { + t16->reset_time_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + } + } + break; + case T16_CRC: + t16->crc = val8; + qemu_log_mask(LOG_UNIMP, "%s: output compare pins unsupported\n", + __func__); + break; + case T16_CNTL: + /* + * CNT is the 16-bit counter value, it must be read/written via + * a temporary register (rtmp) to make the read/write atomic. + */ + /* ICR also has this behaviour, and shares rtmp */ + /* + * Writing CNT blocks compare matches for one clock cycle. + * Writing CNT to TOP or to an OCR value (if in use) will + * skip the relevant interrupt + */ + t16->cntl = val8; + t16->cnth = t16->rtmp; + avr_timer16_recalc_reset_time(t16); + break; + case T16_CNTH: + t16->rtmp = val8; + break; + case T16_ICRL: + /* ICR can only be written in mode T16_MODE_CTC_ICR */ + if (MODE(t16) == T16_MODE_CTC_ICR) { + t16->icrl = val8; + t16->icrh = t16->rtmp; + } + break; + case T16_ICRH: + if (MODE(t16) == T16_MODE_CTC_ICR) { + t16->rtmp = val8; + } + break; + case T16_OCRAL: + /* + * OCRn cause the relevant output compare flag to be raised, and + * trigger an interrupt, when CNT is equal to the value here + */ + t16->ocral = val8; + break; + case T16_OCRAH: + t16->ocrah = val8; + break; + case T16_OCRBL: + t16->ocrbl = val8; + break; + case T16_OCRBH: + t16->ocrbh = val8; + break; + case T16_OCRCL: + t16->ocrcl = val8; + break; + case T16_OCRCH: + t16->ocrch = val8; + break; + default: + break; + } + avr_timer16_set_alarm(t16); +} + +static uint64_t avr_timer16_imsk_read(void *opaque, + hwaddr offset, + unsigned size) +{ + assert(size == 1); + AVRTimer16State *t16 = opaque; + trace_avr_timer16_read_imsk(offset ? 0 : t16->imsk); + if (offset != 0) { + return 0; + } + return t16->imsk; +} + +static void avr_timer16_imsk_write(void *opaque, hwaddr offset, + uint64_t val64, unsigned size) +{ + assert(size == 1); + AVRTimer16State *t16 = opaque; + trace_avr_timer16_write_imsk(val64); + if (offset != 0) { + return; + } + t16->imsk = (uint8_t)val64; +} + +static uint64_t avr_timer16_ifr_read(void *opaque, + hwaddr offset, + unsigned size) +{ + assert(size == 1); + AVRTimer16State *t16 = opaque; + trace_avr_timer16_read_ifr(offset ? 0 : t16->ifr); + if (offset != 0) { + return 0; + } + return t16->ifr; +} + +static void avr_timer16_ifr_write(void *opaque, hwaddr offset, + uint64_t val64, unsigned size) +{ + assert(size == 1); + AVRTimer16State *t16 = opaque; + trace_avr_timer16_write_imsk(val64); + if (offset != 0) { + return; + } + t16->ifr = (uint8_t)val64; +} + +static const MemoryRegionOps avr_timer16_ops = { + .read = avr_timer16_read, + .write = avr_timer16_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = {.max_access_size = 1} +}; + +static const MemoryRegionOps avr_timer16_imsk_ops = { + .read = avr_timer16_imsk_read, + .write = avr_timer16_imsk_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = {.max_access_size = 1} +}; + +static const MemoryRegionOps avr_timer16_ifr_ops = { + .read = avr_timer16_ifr_read, + .write = avr_timer16_ifr_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = {.max_access_size = 1} +}; + +static Property avr_timer16_properties[] = { + DEFINE_PROP_UINT8("id", struct AVRTimer16State, id, 0), + DEFINE_PROP_UINT64("cpu-frequency-hz", struct AVRTimer16State, + cpu_freq_hz, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void avr_timer16_pr(void *opaque, int irq, int level) +{ + AVRTimer16State *s = AVR_TIMER16(opaque); + + s->enabled = !level; + + if (!s->enabled) { + avr_timer16_reset(DEVICE(s)); + } +} + +static void avr_timer16_init(Object *obj) +{ + AVRTimer16State *s = AVR_TIMER16(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->capt_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->compa_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->compb_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->compc_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->ovf_irq); + + memory_region_init_io(&s->iomem, obj, &avr_timer16_ops, + s, "avr-timer16", 0xe); + memory_region_init_io(&s->imsk_iomem, obj, &avr_timer16_imsk_ops, + s, "avr-timer16-intmask", 0x1); + memory_region_init_io(&s->ifr_iomem, obj, &avr_timer16_ifr_ops, + s, "avr-timer16-intflag", 0x1); + + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->imsk_iomem); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->ifr_iomem); + qdev_init_gpio_in(DEVICE(s), avr_timer16_pr, 1); +} + +static void avr_timer16_realize(DeviceState *dev, Error **errp) +{ + AVRTimer16State *s = AVR_TIMER16(dev); + + if (s->cpu_freq_hz == 0) { + error_setg(errp, "AVR timer16: cpu-frequency-hz property must be set"); + return; + } + + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, avr_timer16_interrupt, s); + s->enabled = true; +} + +static void avr_timer16_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = avr_timer16_reset; + dc->realize = avr_timer16_realize; + device_class_set_props(dc, avr_timer16_properties); +} + +static const TypeInfo avr_timer16_info = { + .name = TYPE_AVR_TIMER16, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AVRTimer16State), + .instance_init = avr_timer16_init, + .class_init = avr_timer16_class_init, +}; + +static void avr_timer16_register_types(void) +{ + type_register_static(&avr_timer16_info); +} + +type_init(avr_timer16_register_types) diff --git a/hw/timer/trace-events b/hw/timer/trace-events index 866c9f546a..447b7c405b 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -75,3 +75,15 @@ nrf51_timer_set_count(uint8_t timer_id, uint8_t counter_id, uint32_t value) "tim bcm2835_systmr_irq(bool enable) "timer irq state %u" bcm2835_systmr_read(uint64_t offset, uint64_t data) "timer read: offset 0x%" PRIx64 " data 0x%" PRIx64 bcm2835_systmr_write(uint64_t offset, uint64_t data) "timer write: offset 0x%" PRIx64 " data 0x%" PRIx64 + +# avr_timer16.c +avr_timer16_read(uint8_t addr, uint8_t value) "timer16 read addr:%u value:%u" +avr_timer16_read_ifr(uint8_t value) "timer16 read addr:ifr value:%u" +avr_timer16_read_imsk(uint8_t value) "timer16 read addr:imsk value:%u" +avr_timer16_write(uint8_t addr, uint8_t value) "timer16 write addr:%u value:%u" +avr_timer16_write_ifr(uint8_t value) "timer16 write addr:ifr value:%u" +avr_timer16_write_imsk(uint8_t value) "timer16 write addr:imsk value:%u" +avr_timer16_interrupt_count(uint8_t cnt) "count: %u" +avr_timer16_interrupt_overflow(const char *reason) "overflow: %s" +avr_timer16_next_alarm(uint64_t delay_ns) "next alarm: %" PRIu64 " ns from now" +avr_timer16_clksrc_update(uint64_t freq_hz, uint64_t period_ns, uint64_t delay_s) "timer frequency: %" PRIu64 " Hz, period: %" PRIu64 " ns (%" PRId64 " us)" diff --git a/include/hw/timer/avr_timer16.h b/include/hw/timer/avr_timer16.h new file mode 100644 index 0000000000..982019d242 --- /dev/null +++ b/include/hw/timer/avr_timer16.h @@ -0,0 +1,94 @@ +/* + * AVR 16-bit timer + * + * Copyright (c) 2018 University of Kent + * Author: Ed Robbins + * + * 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.1 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 + * + */ + +/* + * Driver for 16 bit timers on 8 bit AVR devices. + * Note: + * On ATmega640/V-1280/V-1281/V-2560/V-2561/V timers 1, 3, 4 and 5 are 16 bit + */ + +#ifndef HW_TIMER_AVR_TIMER16_H +#define HW_TIMER_AVR_TIMER16_H + +#include "hw/sysbus.h" +#include "qemu/timer.h" +#include "hw/hw.h" + +enum NextInterrupt { + OVERFLOW, + COMPA, + COMPB, + COMPC, + CAPT +}; + +#define TYPE_AVR_TIMER16 "avr-timer16" +#define AVR_TIMER16(obj) \ + OBJECT_CHECK(AVRTimer16State, (obj), TYPE_AVR_TIMER16) + +typedef struct AVRTimer16State { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion iomem; + MemoryRegion imsk_iomem; + MemoryRegion ifr_iomem; + QEMUTimer *timer; + qemu_irq capt_irq; + qemu_irq compa_irq; + qemu_irq compb_irq; + qemu_irq compc_irq; + qemu_irq ovf_irq; + + bool enabled; + + /* registers */ + uint8_t cra; + uint8_t crb; + uint8_t crc; + uint8_t cntl; + uint8_t cnth; + uint8_t icrl; + uint8_t icrh; + uint8_t ocral; + uint8_t ocrah; + uint8_t ocrbl; + uint8_t ocrbh; + uint8_t ocrcl; + uint8_t ocrch; + /* + * Reads and writes to CNT and ICR utilise a bizarre temporary + * register, which we emulate + */ + uint8_t rtmp; + uint8_t imsk; + uint8_t ifr; + + uint8_t id; + uint64_t cpu_freq_hz; + uint64_t freq_hz; + uint64_t period_ns; + uint64_t reset_time_ns; + enum NextInterrupt next_interrupt; +} AVRTimer16State; + +#endif /* HW_TIMER_AVR_TIMER16_H */ From dc288de082a3e4e6970737fde2286bfc1d5ab9d7 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:19 +0100 Subject: [PATCH 2155/2595] hw/misc: avr: Add limited support for power reduction device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a simple device of just one register, and whenever this register is written to it calls qemu_set_irq function for each of 8 bits/IRQs. It is used to implement AVR Power Reduction. [AM: Remove word 'Atmel' from filenames and all elements of code] Suggested-by: Aleksandar Markovic Signed-off-by: Michael Rolnik Signed-off-by: Philippe Mathieu-Daudé [rth: Squash include fix and file rename from f4bug] Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Reviewed-by: Alex Bennée Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-22-huth@tuxfamily.org> --- MAINTAINERS | 2 + hw/misc/Kconfig | 3 + hw/misc/Makefile.objs | 2 + hw/misc/avr_power.c | 113 ++++++++++++++++++++++++++++++++++++ hw/misc/trace-events | 4 ++ include/hw/misc/avr_power.h | 46 +++++++++++++++ 6 files changed, 170 insertions(+) create mode 100644 hw/misc/avr_power.c create mode 100644 include/hw/misc/avr_power.h diff --git a/MAINTAINERS b/MAINTAINERS index 3541955f5f..accb86d811 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -987,6 +987,8 @@ F: include/hw/char/avr_usart.h F: hw/char/avr_usart.c F: include/hw/timer/avr_timer16.h F: hw/timer/avr_timer16.c +F: include/hw/misc/avr_power.h +F: hw/misc/avr_power.c CRIS Machines ------------- diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index bdd77d8020..92c397ca07 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -131,4 +131,7 @@ config MAC_VIA select MOS6522 select ADB +config AVR_POWER + bool + source macio/Kconfig diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 5aaca8a039..6be3d255ab 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -91,3 +91,5 @@ common-obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o obj-$(CONFIG_MAC_VIA) += mac_via.o common-obj-$(CONFIG_GRLIB) += grlib_ahb_apb_pnp.o + +obj-$(CONFIG_AVR_POWER) += avr_power.o diff --git a/hw/misc/avr_power.c b/hw/misc/avr_power.c new file mode 100644 index 0000000000..a5412f2cfe --- /dev/null +++ b/hw/misc/avr_power.c @@ -0,0 +1,113 @@ +/* + * AVR Power Reduction Management + * + * Copyright (c) 2019-2020 Michael Rolnik + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/misc/avr_power.h" +#include "qemu/log.h" +#include "hw/qdev-properties.h" +#include "hw/irq.h" +#include "trace.h" + +static void avr_mask_reset(DeviceState *dev) +{ + AVRMaskState *s = AVR_MASK(dev); + + s->val = 0x00; + + for (int i = 0; i < 8; i++) { + qemu_set_irq(s->irq[i], 0); + } +} + +static uint64_t avr_mask_read(void *opaque, hwaddr offset, unsigned size) +{ + assert(size == 1); + assert(offset == 0); + AVRMaskState *s = opaque; + + trace_avr_power_read(s->val); + + return (uint64_t)s->val; +} + +static void avr_mask_write(void *opaque, hwaddr offset, + uint64_t val64, unsigned size) +{ + assert(size == 1); + assert(offset == 0); + AVRMaskState *s = opaque; + uint8_t val8 = val64; + + trace_avr_power_write(val8); + s->val = val8; + for (int i = 0; i < 8; i++) { + qemu_set_irq(s->irq[i], (val8 & (1 << i)) != 0); + } +} + +static const MemoryRegionOps avr_mask_ops = { + .read = avr_mask_read, + .write = avr_mask_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .max_access_size = 1, + }, +}; + +static void avr_mask_init(Object *dev) +{ + AVRMaskState *s = AVR_MASK(dev); + SysBusDevice *busdev = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, dev, &avr_mask_ops, s, TYPE_AVR_MASK, + 0x01); + sysbus_init_mmio(busdev, &s->iomem); + + for (int i = 0; i < 8; i++) { + sysbus_init_irq(busdev, &s->irq[i]); + } + s->val = 0x00; +} + +static void avr_mask_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = avr_mask_reset; +} + +static const TypeInfo avr_mask_info = { + .name = TYPE_AVR_MASK, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AVRMaskState), + .class_init = avr_mask_class_init, + .instance_init = avr_mask_init, +}; + +static void avr_mask_register_types(void) +{ + type_register_static(&avr_mask_info); +} + +type_init(avr_mask_register_types) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index ebea53735c..066752aa90 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -19,6 +19,10 @@ allwinner_h3_dramphy_write(uint64_t offset, uint64_t data, unsigned size) "write allwinner_sid_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 allwinner_sid_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 +# avr_power.c +avr_power_read(uint8_t value) "power_reduc read value:%u" +avr_power_write(uint8_t value) "power_reduc write value:%u" + # eccmemctl.c ecc_mem_writel_mer(uint32_t val) "Write memory enable 0x%08x" ecc_mem_writel_mdr(uint32_t val) "Write memory delay 0x%08x" diff --git a/include/hw/misc/avr_power.h b/include/hw/misc/avr_power.h new file mode 100644 index 0000000000..e08e44f629 --- /dev/null +++ b/include/hw/misc/avr_power.h @@ -0,0 +1,46 @@ +/* + * AVR Power Reduction Management + * + * Copyright (c) 2019-2020 Michael Rolnik + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_MISC_AVR_POWER_H +#define HW_MISC_AVR_POWER_H + +#include "hw/sysbus.h" +#include "hw/hw.h" + + +#define TYPE_AVR_MASK "avr-power" +#define AVR_MASK(obj) OBJECT_CHECK(AVRMaskState, (obj), TYPE_AVR_MASK) + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion iomem; + + uint8_t val; + qemu_irq irq[8]; +} AVRMaskState; + +#endif /* HW_MISC_AVR_POWER_H */ From 7dd8f6fde417a7625de15cd759a79988f09aae0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 24 Jan 2020 01:51:25 +0100 Subject: [PATCH 2156/2595] hw/avr: Add support for loading ELF/raw binaries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add avr_load_firmware() function to load firmware in ELF or raw binary format. [AM: Corrected the type of the variable containing e_flags] [AM: Moved definition of e_flags conversion function to boot.c] Suggested-by: Aleksandar Markovic Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Aleksandar Markovic Reviewed-by: Aleksandar Markovic Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-24-huth@tuxfamily.org> [PMD: Replace load_image_targphys() by load_image_mr()] Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 1 + hw/avr/Makefile.objs | 1 + hw/avr/boot.c | 115 +++++++++++++++++++++++++++++++++++++++++++ hw/avr/boot.h | 33 +++++++++++++ include/elf.h | 4 ++ 5 files changed, 154 insertions(+) create mode 100644 hw/avr/Makefile.objs create mode 100644 hw/avr/boot.c create mode 100644 hw/avr/boot.h diff --git a/MAINTAINERS b/MAINTAINERS index accb86d811..a54bbd7e0d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -983,6 +983,7 @@ M: Michael Rolnik R: Sarah Harris S: Maintained F: default-configs/avr-softmmu.mak +F: hw/avr/ F: include/hw/char/avr_usart.h F: hw/char/avr_usart.c F: include/hw/timer/avr_timer16.h diff --git a/hw/avr/Makefile.objs b/hw/avr/Makefile.objs new file mode 100644 index 0000000000..123f174f0e --- /dev/null +++ b/hw/avr/Makefile.objs @@ -0,0 +1 @@ +obj-y += boot.o diff --git a/hw/avr/boot.c b/hw/avr/boot.c new file mode 100644 index 0000000000..6fbcde4061 --- /dev/null +++ b/hw/avr/boot.c @@ -0,0 +1,115 @@ +/* + * AVR loader helpers + * + * Copyright (c) 2019-2020 Philippe Mathieu-Daudé + * + * This work is licensed under the terms of the GNU GPLv2 or later. + * See the COPYING file in the top-level directory. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "hw/loader.h" +#include "elf.h" +#include "boot.h" +#include "qemu/error-report.h" + +static const char *avr_elf_e_flags_to_cpu_type(uint32_t flags) +{ + switch (flags & EF_AVR_MACH) { + case bfd_mach_avr1: + return AVR_CPU_TYPE_NAME("avr1"); + case bfd_mach_avr2: + return AVR_CPU_TYPE_NAME("avr2"); + case bfd_mach_avr25: + return AVR_CPU_TYPE_NAME("avr25"); + case bfd_mach_avr3: + return AVR_CPU_TYPE_NAME("avr3"); + case bfd_mach_avr31: + return AVR_CPU_TYPE_NAME("avr31"); + case bfd_mach_avr35: + return AVR_CPU_TYPE_NAME("avr35"); + case bfd_mach_avr4: + return AVR_CPU_TYPE_NAME("avr4"); + case bfd_mach_avr5: + return AVR_CPU_TYPE_NAME("avr5"); + case bfd_mach_avr51: + return AVR_CPU_TYPE_NAME("avr51"); + case bfd_mach_avr6: + return AVR_CPU_TYPE_NAME("avr6"); + case bfd_mach_avrtiny: + return AVR_CPU_TYPE_NAME("avrtiny"); + case bfd_mach_avrxmega2: + return AVR_CPU_TYPE_NAME("xmega2"); + case bfd_mach_avrxmega3: + return AVR_CPU_TYPE_NAME("xmega3"); + case bfd_mach_avrxmega4: + return AVR_CPU_TYPE_NAME("xmega4"); + case bfd_mach_avrxmega5: + return AVR_CPU_TYPE_NAME("xmega5"); + case bfd_mach_avrxmega6: + return AVR_CPU_TYPE_NAME("xmega6"); + case bfd_mach_avrxmega7: + return AVR_CPU_TYPE_NAME("xmega7"); + default: + return NULL; + } +} + +bool avr_load_firmware(AVRCPU *cpu, MachineState *ms, + MemoryRegion *program_mr, const char *firmware) +{ + const char *filename; + int bytes_loaded; + uint64_t entry; + uint32_t e_flags; + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware); + if (filename == NULL) { + error_report("Unable to find %s", firmware); + return false; + } + + bytes_loaded = load_elf_ram_sym(filename, + NULL, NULL, NULL, + &entry, NULL, NULL, + &e_flags, 0, EM_AVR, 0, 0, + NULL, true, NULL); + if (bytes_loaded >= 0) { + /* If ELF file is provided, determine CPU type reading ELF e_flags. */ + const char *elf_cpu = avr_elf_e_flags_to_cpu_type(e_flags); + const char *mcu_cpu_type = object_get_typename(OBJECT(cpu)); + int cpu_len = strlen(mcu_cpu_type) - strlen(AVR_CPU_TYPE_SUFFIX); + + if (entry) { + error_report("BIOS entry_point must be 0x0000 " + "(ELF image '%s' has entry_point 0x%04" PRIx64 ")", + firmware, entry); + return false; + } + if (!elf_cpu) { + warn_report("Could not determine CPU type for ELF image '%s', " + "assuming '%.*s' CPU", + firmware, cpu_len, mcu_cpu_type); + return true; + } + if (strcmp(elf_cpu, mcu_cpu_type)) { + error_report("Current machine: %s with '%.*s' CPU", + MACHINE_GET_CLASS(ms)->desc, cpu_len, mcu_cpu_type); + error_report("ELF image '%s' is for '%.*s' CPU", + firmware, + (int)(strlen(elf_cpu) - strlen(AVR_CPU_TYPE_SUFFIX)), + elf_cpu); + return false; + } + } else { + bytes_loaded = load_image_mr(filename, program_mr); + } + if (bytes_loaded < 0) { + error_report("Unable to load firmware image %s as ELF or raw binary", + firmware); + return false; + } + return true; +} diff --git a/hw/avr/boot.h b/hw/avr/boot.h new file mode 100644 index 0000000000..684d553322 --- /dev/null +++ b/hw/avr/boot.h @@ -0,0 +1,33 @@ +/* + * AVR loader helpers + * + * Copyright (c) 2019-2020 Philippe Mathieu-Daudé + * + * This work is licensed under the terms of the GNU GPLv2 or later. + * See the COPYING file in the top-level directory. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_AVR_BOOT_H +#define HW_AVR_BOOT_H + +#include "hw/boards.h" +#include "cpu.h" + +/** + * avr_load_firmware: load an image into a memory region + * + * @cpu: Handle a AVR CPU object + * @ms: A MachineState + * @mr: Memory Region to load into + * @firmware: Path to the firmware file (raw binary or ELF format) + * + * Load a firmware supplied by the machine or by the user with the + * '-bios' command line option, and put it in target memory. + * + * Returns: true on success, false on error. + */ +bool avr_load_firmware(AVRCPU *cpu, MachineState *ms, + MemoryRegion *mr, const char *firmware); + +#endif diff --git a/include/elf.h b/include/elf.h index 8fbfe60e09..5b06b55f28 100644 --- a/include/elf.h +++ b/include/elf.h @@ -160,6 +160,8 @@ typedef struct mips_elf_abiflags_v0 { #define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_AVR 83 /* AVR 8-bit microcontroller */ + #define EM_V850 87 /* NEC v850 */ #define EM_H8_300H 47 /* Hitachi H8/300H */ @@ -202,6 +204,8 @@ typedef struct mips_elf_abiflags_v0 { #define EM_MOXIE 223 /* Moxie processor family */ #define EM_MOXIE_OLD 0xFEED +#define EF_AVR_MACH 0x7F /* Mask for AVR e_flags to get core type */ + /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 #define DT_NEEDED 1 From af55b781aaf2f50a00869a0c9fdab521f8ba78ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 24 Jan 2020 01:51:26 +0100 Subject: [PATCH 2157/2595] hw/avr: Add some ATmega microcontrollers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some AVR microcontrollers from the ATmega family: - middle range: ATmega168 and ATmega328 - high range: ATmega1280 and ATmega2560 For product comparison: https://www.microchip.com/wwwproducts/ProductCompare/ATmega168P/ATmega328P https://www.microchip.com/wwwproducts/ProductCompare/ATmega1280/ATmega2560 Datasheets: http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2549-8-bit-AVR-Microcontroller-ATmega640-1280-1281-2560-2561_datasheet.pdf [AM: Remove word 'Atmel' from filenames and all elements of code] Suggested-by: Aleksandar Markovic Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic [thuth: Rebased to master, fixed object_initialize_child() calls etc.] Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-25-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/avr/Kconfig | 5 + hw/avr/Makefile.objs | 1 + hw/avr/atmega.c | 458 +++++++++++++++++++++++++++++++++++++++++++ hw/avr/atmega.h | 48 +++++ 4 files changed, 512 insertions(+) create mode 100644 hw/avr/Kconfig create mode 100644 hw/avr/atmega.c create mode 100644 hw/avr/atmega.h diff --git a/hw/avr/Kconfig b/hw/avr/Kconfig new file mode 100644 index 0000000000..9e6527e1f3 --- /dev/null +++ b/hw/avr/Kconfig @@ -0,0 +1,5 @@ +config AVR_ATMEGA_MCU + bool + select AVR_TIMER16 + select AVR_USART + select AVR_POWER diff --git a/hw/avr/Makefile.objs b/hw/avr/Makefile.objs index 123f174f0e..af0fddeb13 100644 --- a/hw/avr/Makefile.objs +++ b/hw/avr/Makefile.objs @@ -1 +1,2 @@ obj-y += boot.o +obj-$(CONFIG_AVR_ATMEGA_MCU) += atmega.o diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c new file mode 100644 index 0000000000..7131224431 --- /dev/null +++ b/hw/avr/atmega.c @@ -0,0 +1,458 @@ +/* + * QEMU ATmega MCU + * + * Copyright (c) 2019-2020 Philippe Mathieu-Daudé + * + * This work is licensed under the terms of the GNU GPLv2 or later. + * See the COPYING file in the top-level directory. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "hw/boards.h" /* FIXME memory_region_allocate_system_memory for sram */ +#include "hw/misc/unimp.h" +#include "atmega.h" + +enum AtmegaPeripheral { + POWER0, POWER1, + GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, + GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK, GPIOL, + USART0, USART1, USART2, USART3, + TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5, + PERIFMAX +}; + +#define GPIO(n) (n + GPIOA) +#define USART(n) (n + USART0) +#define TIMER(n) (n + TIMER0) +#define POWER(n) (n + POWER0) + +typedef struct { + uint16_t addr; + enum AtmegaPeripheral power_index; + uint8_t power_bit; + /* timer specific */ + uint16_t intmask_addr; + uint16_t intflag_addr; + bool is_timer16; +} peripheral_cfg; + +typedef struct AtmegaMcuClass { + /*< private >*/ + SysBusDeviceClass parent_class; + /*< public >*/ + const char *uc_name; + const char *cpu_type; + size_t flash_size; + size_t eeprom_size; + size_t sram_size; + size_t io_size; + size_t gpio_count; + size_t adc_count; + const uint8_t *irq; + const peripheral_cfg *dev; +} AtmegaMcuClass; + +#define ATMEGA_MCU_CLASS(klass) \ + OBJECT_CLASS_CHECK(AtmegaMcuClass, (klass), TYPE_ATMEGA_MCU) +#define ATMEGA_MCU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(AtmegaMcuClass, (obj), TYPE_ATMEGA_MCU) + +static const peripheral_cfg dev168_328[PERIFMAX] = { + [USART0] = { 0xc0, POWER0, 1 }, + [TIMER2] = { 0xb0, POWER0, 6, 0x70, 0x37, false }, + [TIMER1] = { 0x80, POWER0, 3, 0x6f, 0x36, true }, + [POWER0] = { 0x64 }, + [TIMER0] = { 0x44, POWER0, 5, 0x6e, 0x35, false }, + [GPIOD] = { 0x29 }, + [GPIOC] = { 0x26 }, + [GPIOB] = { 0x23 }, +}, dev1280_2560[PERIFMAX] = { + [USART3] = { 0x130, POWER1, 2 }, + [TIMER5] = { 0x120, POWER1, 5, 0x73, 0x3a, true }, + [GPIOL] = { 0x109 }, + [GPIOK] = { 0x106 }, + [GPIOJ] = { 0x103 }, + [GPIOH] = { 0x100 }, + [USART2] = { 0xd0, POWER1, 1 }, + [USART1] = { 0xc8, POWER1, 0 }, + [USART0] = { 0xc0, POWER0, 1 }, + [TIMER2] = { 0xb0, POWER0, 6, 0x70, 0x37, false }, /* TODO async */ + [TIMER4] = { 0xa0, POWER1, 4, 0x72, 0x39, true }, + [TIMER3] = { 0x90, POWER1, 3, 0x71, 0x38, true }, + [TIMER1] = { 0x80, POWER0, 3, 0x6f, 0x36, true }, + [POWER1] = { 0x65 }, + [POWER0] = { 0x64 }, + [TIMER0] = { 0x44, POWER0, 5, 0x6e, 0x35, false }, + [GPIOG] = { 0x32 }, + [GPIOF] = { 0x2f }, + [GPIOE] = { 0x2c }, + [GPIOD] = { 0x29 }, + [GPIOC] = { 0x26 }, + [GPIOB] = { 0x23 }, + [GPIOA] = { 0x20 }, +}; + +enum AtmegaIrq { + USART0_RXC_IRQ, USART0_DRE_IRQ, USART0_TXC_IRQ, + USART1_RXC_IRQ, USART1_DRE_IRQ, USART1_TXC_IRQ, + USART2_RXC_IRQ, USART2_DRE_IRQ, USART2_TXC_IRQ, + USART3_RXC_IRQ, USART3_DRE_IRQ, USART3_TXC_IRQ, + TIMER0_CAPT_IRQ, TIMER0_COMPA_IRQ, TIMER0_COMPB_IRQ, + TIMER0_COMPC_IRQ, TIMER0_OVF_IRQ, + TIMER1_CAPT_IRQ, TIMER1_COMPA_IRQ, TIMER1_COMPB_IRQ, + TIMER1_COMPC_IRQ, TIMER1_OVF_IRQ, + TIMER2_CAPT_IRQ, TIMER2_COMPA_IRQ, TIMER2_COMPB_IRQ, + TIMER2_COMPC_IRQ, TIMER2_OVF_IRQ, + TIMER3_CAPT_IRQ, TIMER3_COMPA_IRQ, TIMER3_COMPB_IRQ, + TIMER3_COMPC_IRQ, TIMER3_OVF_IRQ, + TIMER4_CAPT_IRQ, TIMER4_COMPA_IRQ, TIMER4_COMPB_IRQ, + TIMER4_COMPC_IRQ, TIMER4_OVF_IRQ, + TIMER5_CAPT_IRQ, TIMER5_COMPA_IRQ, TIMER5_COMPB_IRQ, + TIMER5_COMPC_IRQ, TIMER5_OVF_IRQ, + IRQ_COUNT +}; + +#define USART_IRQ_COUNT 3 +#define USART_RXC_IRQ(n) (n * USART_IRQ_COUNT + USART0_RXC_IRQ) +#define USART_DRE_IRQ(n) (n * USART_IRQ_COUNT + USART0_DRE_IRQ) +#define USART_TXC_IRQ(n) (n * USART_IRQ_COUNT + USART0_TXC_IRQ) +#define TIMER_IRQ_COUNT 5 +#define TIMER_CAPT_IRQ(n) (n * TIMER_IRQ_COUNT + TIMER0_CAPT_IRQ) +#define TIMER_COMPA_IRQ(n) (n * TIMER_IRQ_COUNT + TIMER0_COMPA_IRQ) +#define TIMER_COMPB_IRQ(n) (n * TIMER_IRQ_COUNT + TIMER0_COMPB_IRQ) +#define TIMER_COMPC_IRQ(n) (n * TIMER_IRQ_COUNT + TIMER0_COMPC_IRQ) +#define TIMER_OVF_IRQ(n) (n * TIMER_IRQ_COUNT + TIMER0_OVF_IRQ) + +static const uint8_t irq168_328[IRQ_COUNT] = { + [TIMER2_COMPA_IRQ] = 8, + [TIMER2_COMPB_IRQ] = 9, + [TIMER2_OVF_IRQ] = 10, + [TIMER1_CAPT_IRQ] = 11, + [TIMER1_COMPA_IRQ] = 12, + [TIMER1_COMPB_IRQ] = 13, + [TIMER1_OVF_IRQ] = 14, + [TIMER0_COMPA_IRQ] = 15, + [TIMER0_COMPB_IRQ] = 16, + [TIMER0_OVF_IRQ] = 17, + [USART0_RXC_IRQ] = 19, + [USART0_DRE_IRQ] = 20, + [USART0_TXC_IRQ] = 21, +}, irq1280_2560[IRQ_COUNT] = { + [TIMER2_COMPA_IRQ] = 14, + [TIMER2_COMPB_IRQ] = 15, + [TIMER2_OVF_IRQ] = 16, + [TIMER1_CAPT_IRQ] = 17, + [TIMER1_COMPA_IRQ] = 18, + [TIMER1_COMPB_IRQ] = 19, + [TIMER1_COMPC_IRQ] = 20, + [TIMER1_OVF_IRQ] = 21, + [TIMER0_COMPA_IRQ] = 22, + [TIMER0_COMPB_IRQ] = 23, + [TIMER0_OVF_IRQ] = 24, + [USART0_RXC_IRQ] = 26, + [USART0_DRE_IRQ] = 27, + [USART0_TXC_IRQ] = 28, + [TIMER3_CAPT_IRQ] = 32, + [TIMER3_COMPA_IRQ] = 33, + [TIMER3_COMPB_IRQ] = 34, + [TIMER3_COMPC_IRQ] = 35, + [TIMER3_OVF_IRQ] = 36, + [USART1_RXC_IRQ] = 37, + [USART1_DRE_IRQ] = 38, + [USART1_TXC_IRQ] = 39, + [TIMER4_CAPT_IRQ] = 42, + [TIMER4_COMPA_IRQ] = 43, + [TIMER4_COMPB_IRQ] = 44, + [TIMER4_COMPC_IRQ] = 45, + [TIMER4_OVF_IRQ] = 46, + [TIMER5_CAPT_IRQ] = 47, + [TIMER5_COMPA_IRQ] = 48, + [TIMER5_COMPB_IRQ] = 49, + [TIMER5_COMPC_IRQ] = 50, + [TIMER5_OVF_IRQ] = 51, + [USART2_RXC_IRQ] = 52, + [USART2_DRE_IRQ] = 53, + [USART2_TXC_IRQ] = 54, + [USART3_RXC_IRQ] = 55, + [USART3_DRE_IRQ] = 56, + [USART3_TXC_IRQ] = 57, +}; + +static void connect_peripheral_irq(const AtmegaMcuClass *k, + SysBusDevice *dev, int dev_irqn, + DeviceState *cpu, + unsigned peripheral_index) +{ + int cpu_irq = k->irq[peripheral_index]; + + if (!cpu_irq) { + return; + } + /* FIXME move that to avr_cpu_set_int() once 'sample' board is removed */ + assert(cpu_irq >= 2); + cpu_irq -= 2; + + sysbus_connect_irq(dev, dev_irqn, qdev_get_gpio_in(cpu, cpu_irq)); +} + +static void connect_power_reduction_gpio(AtmegaMcuState *s, + const AtmegaMcuClass *k, + DeviceState *cpu, + unsigned peripheral_index) +{ + unsigned power_index = k->dev[peripheral_index].power_index; + assert(k->dev[power_index].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pwr[power_index - POWER0]), + k->dev[peripheral_index].power_bit, + qdev_get_gpio_in(cpu, 0)); +} + +static void atmega_realize(DeviceState *dev, Error **errp) +{ + AtmegaMcuState *s = ATMEGA_MCU(dev); + const AtmegaMcuClass *mc = ATMEGA_MCU_GET_CLASS(dev); + DeviceState *cpudev; + SysBusDevice *sbd; + char *devname; + size_t i; + + assert(mc->io_size <= 0x200); + + if (!s->xtal_freq_hz) { + error_setg(errp, "\"xtal-frequency-hz\" property must be provided."); + return; + } + + /* CPU */ + object_initialize_child(OBJECT(dev), "cpu", &s->cpu, mc->cpu_type); + object_property_set_bool(OBJECT(&s->cpu), "realized", true, &error_abort); + cpudev = DEVICE(&s->cpu); + + /* SRAM */ + memory_region_init_ram(&s->sram, OBJECT(dev), "sram", mc->sram_size, + &error_abort); + memory_region_add_subregion(get_system_memory(), + OFFSET_DATA + mc->io_size, &s->sram); + + /* Flash */ + memory_region_init_rom(&s->flash, OBJECT(dev), + "flash", mc->flash_size, &error_fatal); + memory_region_add_subregion(get_system_memory(), OFFSET_CODE, &s->flash); + + /* + * I/O + * + * 0x00 - 0x1f: Registers + * 0x20 - 0x5f: I/O memory + * 0x60 - 0xff: Extended I/O + */ + s->io = qdev_new(TYPE_UNIMPLEMENTED_DEVICE); + qdev_prop_set_string(s->io, "name", "I/O"); + qdev_prop_set_uint64(s->io, "size", mc->io_size); + sysbus_realize_and_unref(SYS_BUS_DEVICE(s->io), &error_fatal); + sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->io), 0, OFFSET_DATA, -1234); + + /* Power Reduction */ + for (i = 0; i < POWER_MAX; i++) { + int idx = POWER(i); + if (!mc->dev[idx].addr) { + continue; + } + devname = g_strdup_printf("power%zu", i); + object_initialize_child(OBJECT(dev), devname, &s->pwr[i], + TYPE_AVR_MASK); + sysbus_realize(SYS_BUS_DEVICE(&s->pwr[i]), &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->pwr[i]), 0, + OFFSET_DATA + mc->dev[idx].addr); + g_free(devname); + } + + /* GPIO */ + for (i = 0; i < GPIO_MAX; i++) { + int idx = GPIO(i); + if (!mc->dev[idx].addr) { + continue; + } + devname = g_strdup_printf("atmega-gpio-%c", 'a' + (char)i); + create_unimplemented_device(devname, + OFFSET_DATA + mc->dev[idx].addr, 3); + g_free(devname); + } + + /* USART */ + for (i = 0; i < USART_MAX; i++) { + int idx = USART(i); + if (!mc->dev[idx].addr) { + continue; + } + devname = g_strdup_printf("usart%zu", i); + object_initialize_child(OBJECT(dev), devname, &s->usart[i], + TYPE_AVR_USART); + qdev_prop_set_chr(DEVICE(&s->usart[i]), "chardev", serial_hd(i)); + sbd = SYS_BUS_DEVICE(&s->usart[i]); + sysbus_realize(sbd, &error_abort); + sysbus_mmio_map(sbd, 0, OFFSET_DATA + mc->dev[USART(i)].addr); + connect_peripheral_irq(mc, sbd, 0, cpudev, USART_RXC_IRQ(i)); + connect_peripheral_irq(mc, sbd, 1, cpudev, USART_DRE_IRQ(i)); + connect_peripheral_irq(mc, sbd, 2, cpudev, USART_TXC_IRQ(i)); + connect_power_reduction_gpio(s, mc, DEVICE(&s->usart[i]), idx); + g_free(devname); + } + + /* Timer */ + for (i = 0; i < TIMER_MAX; i++) { + int idx = TIMER(i); + if (!mc->dev[idx].addr) { + continue; + } + if (!mc->dev[idx].is_timer16) { + create_unimplemented_device("avr-timer8", + OFFSET_DATA + mc->dev[idx].addr, 5); + create_unimplemented_device("avr-timer8-intmask", + OFFSET_DATA + + mc->dev[idx].intmask_addr, 1); + create_unimplemented_device("avr-timer8-intflag", + OFFSET_DATA + + mc->dev[idx].intflag_addr, 1); + continue; + } + devname = g_strdup_printf("timer%zu", i); + object_initialize_child(OBJECT(dev), devname, &s->timer[i], + TYPE_AVR_TIMER16); + object_property_set_uint(OBJECT(&s->timer[i]), "cpu-frequency-hz", + s->xtal_freq_hz, &error_abort); + sbd = SYS_BUS_DEVICE(&s->timer[i]); + sysbus_realize(sbd, &error_abort); + sysbus_mmio_map(sbd, 0, OFFSET_DATA + mc->dev[idx].addr); + sysbus_mmio_map(sbd, 1, OFFSET_DATA + mc->dev[idx].intmask_addr); + sysbus_mmio_map(sbd, 2, OFFSET_DATA + mc->dev[idx].intflag_addr); + connect_peripheral_irq(mc, sbd, 0, cpudev, TIMER_CAPT_IRQ(i)); + connect_peripheral_irq(mc, sbd, 1, cpudev, TIMER_COMPA_IRQ(i)); + connect_peripheral_irq(mc, sbd, 2, cpudev, TIMER_COMPB_IRQ(i)); + connect_peripheral_irq(mc, sbd, 3, cpudev, TIMER_COMPC_IRQ(i)); + connect_peripheral_irq(mc, sbd, 4, cpudev, TIMER_OVF_IRQ(i)); + connect_power_reduction_gpio(s, mc, DEVICE(&s->timer[i]), idx); + g_free(devname); + } + + create_unimplemented_device("avr-twi", OFFSET_DATA + 0x0b8, 6); + create_unimplemented_device("avr-adc", OFFSET_DATA + 0x078, 8); + create_unimplemented_device("avr-ext-mem-ctrl", OFFSET_DATA + 0x074, 2); + create_unimplemented_device("avr-watchdog", OFFSET_DATA + 0x060, 1); + create_unimplemented_device("avr-spi", OFFSET_DATA + 0x04c, 3); + create_unimplemented_device("avr-eeprom", OFFSET_DATA + 0x03f, 3); +} + +static Property atmega_props[] = { + DEFINE_PROP_UINT64("xtal-frequency-hz", AtmegaMcuState, + xtal_freq_hz, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void atmega_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = atmega_realize; + device_class_set_props(dc, atmega_props); + /* Reason: Mapped at fixed location on the system bus */ + dc->user_creatable = false; +} + +static void atmega168_class_init(ObjectClass *oc, void *data) +{ + AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc); + + amc->cpu_type = AVR_CPU_TYPE_NAME("avr5"); + amc->flash_size = 16 * KiB; + amc->eeprom_size = 512; + amc->sram_size = 1 * KiB; + amc->io_size = 256; + amc->gpio_count = 23; + amc->adc_count = 6; + amc->irq = irq168_328; + amc->dev = dev168_328; +}; + +static void atmega328_class_init(ObjectClass *oc, void *data) +{ + AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc); + + amc->cpu_type = AVR_CPU_TYPE_NAME("avr5"); + amc->flash_size = 32 * KiB; + amc->eeprom_size = 1 * KiB; + amc->sram_size = 2 * KiB; + amc->io_size = 256; + amc->gpio_count = 23; + amc->adc_count = 6; + amc->irq = irq168_328; + amc->dev = dev168_328; +}; + +static void atmega1280_class_init(ObjectClass *oc, void *data) +{ + AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc); + + amc->cpu_type = AVR_CPU_TYPE_NAME("avr6"); + amc->flash_size = 128 * KiB; + amc->eeprom_size = 4 * KiB; + amc->sram_size = 8 * KiB; + amc->io_size = 512; + amc->gpio_count = 86; + amc->adc_count = 16; + amc->irq = irq1280_2560; + amc->dev = dev1280_2560; +}; + +static void atmega2560_class_init(ObjectClass *oc, void *data) +{ + AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc); + + amc->cpu_type = AVR_CPU_TYPE_NAME("avr6"); + amc->flash_size = 256 * KiB; + amc->eeprom_size = 4 * KiB; + amc->sram_size = 8 * KiB; + amc->io_size = 512; + amc->gpio_count = 54; + amc->adc_count = 16; + amc->irq = irq1280_2560; + amc->dev = dev1280_2560; +}; + +static const TypeInfo atmega_mcu_types[] = { + { + .name = TYPE_ATMEGA168_MCU, + .parent = TYPE_ATMEGA_MCU, + .class_init = atmega168_class_init, + }, { + .name = TYPE_ATMEGA328_MCU, + .parent = TYPE_ATMEGA_MCU, + .class_init = atmega328_class_init, + }, { + .name = TYPE_ATMEGA1280_MCU, + .parent = TYPE_ATMEGA_MCU, + .class_init = atmega1280_class_init, + }, { + .name = TYPE_ATMEGA2560_MCU, + .parent = TYPE_ATMEGA_MCU, + .class_init = atmega2560_class_init, + }, { + .name = TYPE_ATMEGA_MCU, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AtmegaMcuState), + .class_size = sizeof(AtmegaMcuClass), + .class_init = atmega_class_init, + .abstract = true, + } +}; + +DEFINE_TYPES(atmega_mcu_types) diff --git a/hw/avr/atmega.h b/hw/avr/atmega.h new file mode 100644 index 0000000000..0928cb0ce6 --- /dev/null +++ b/hw/avr/atmega.h @@ -0,0 +1,48 @@ +/* + * QEMU ATmega MCU + * + * Copyright (c) 2019-2020 Philippe Mathieu-Daudé + * + * This work is licensed under the terms of the GNU GPLv2 or later. + * See the COPYING file in the top-level directory. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_AVR_ATMEGA_H +#define HW_AVR_ATMEGA_H + +#include "hw/char/avr_usart.h" +#include "hw/timer/avr_timer16.h" +#include "hw/misc/avr_power.h" +#include "target/avr/cpu.h" + +#define TYPE_ATMEGA_MCU "ATmega" +#define TYPE_ATMEGA168_MCU "ATmega168" +#define TYPE_ATMEGA328_MCU "ATmega328" +#define TYPE_ATMEGA1280_MCU "ATmega1280" +#define TYPE_ATMEGA2560_MCU "ATmega2560" + +#define ATMEGA_MCU(obj) OBJECT_CHECK(AtmegaMcuState, (obj), TYPE_ATMEGA_MCU) + +#define POWER_MAX 2 +#define USART_MAX 4 +#define TIMER_MAX 6 +#define GPIO_MAX 12 + +typedef struct AtmegaMcuState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + AVRCPU cpu; + MemoryRegion flash; + MemoryRegion eeprom; + MemoryRegion sram; + DeviceState *io; + AVRMaskState pwr[POWER_MAX]; + AVRUsartState usart[USART_MAX]; + AVRTimer16State timer[TIMER_MAX]; + uint64_t xtal_freq_hz; +} AtmegaMcuState; + +#endif /* HW_AVR_ATMEGA_H */ From 50486d63fba7451b7a04bf85cec61369391a90c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 24 Jan 2020 01:51:27 +0100 Subject: [PATCH 2158/2595] hw/avr: Add limited support for some Arduino boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Arduino boards are build with AVR chipsets. Add some of these boards: - Arduino Duemilanove - Arduino Uno - Arduino Mega For more information: https://www.arduino.cc/en/Main/Products https://store.arduino.cc/arduino-genuino/most-popular [AM: Remove word 'Atmel' from filenames and all elements of code] Suggested-by: Aleksandar Markovic Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Reviewed-by: Igor Mammedov Reviewed-by: Joaquin de Andres [thuth: sysbus_init_child_obj() ==> object_initialize_child()] Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-26-huth@tuxfamily.org> --- MAINTAINERS | 6 ++ default-configs/avr-softmmu.mak | 4 + hw/Kconfig | 1 + hw/avr/Kconfig | 4 + hw/avr/Makefile.objs | 1 + hw/avr/arduino.c | 149 ++++++++++++++++++++++++++++++++ 6 files changed, 165 insertions(+) create mode 100644 hw/avr/arduino.c diff --git a/MAINTAINERS b/MAINTAINERS index a54bbd7e0d..702e3a2f91 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -991,6 +991,12 @@ F: hw/timer/avr_timer16.c F: include/hw/misc/avr_power.h F: hw/misc/avr_power.c +Arduino +M: Philippe Mathieu-Daudé +R: Sarah Harris +S: Maintained +F: hw/avr/arduino.c + CRIS Machines ------------- Axis Dev88 diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak index ca94aad4e1..80218add98 100644 --- a/default-configs/avr-softmmu.mak +++ b/default-configs/avr-softmmu.mak @@ -1 +1,5 @@ # Default configuration for avr-softmmu + +# Boards: +# +CONFIG_ARDUINO=y diff --git a/hw/Kconfig b/hw/Kconfig index 62f9ebdc22..4de1797ffd 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -43,6 +43,7 @@ source watchdog/Kconfig # arch Kconfig source arm/Kconfig source alpha/Kconfig +source avr/Kconfig source cris/Kconfig source hppa/Kconfig source i386/Kconfig diff --git a/hw/avr/Kconfig b/hw/avr/Kconfig index 9e6527e1f3..d31298c3cc 100644 --- a/hw/avr/Kconfig +++ b/hw/avr/Kconfig @@ -3,3 +3,7 @@ config AVR_ATMEGA_MCU select AVR_TIMER16 select AVR_USART select AVR_POWER + +config ARDUINO + select AVR_ATMEGA_MCU + select UNIMP diff --git a/hw/avr/Makefile.objs b/hw/avr/Makefile.objs index af0fddeb13..4dca064bfc 100644 --- a/hw/avr/Makefile.objs +++ b/hw/avr/Makefile.objs @@ -1,2 +1,3 @@ obj-y += boot.o obj-$(CONFIG_AVR_ATMEGA_MCU) += atmega.o +obj-$(CONFIG_ARDUINO) += arduino.o diff --git a/hw/avr/arduino.c b/hw/avr/arduino.c new file mode 100644 index 0000000000..65093ab6fd --- /dev/null +++ b/hw/avr/arduino.c @@ -0,0 +1,149 @@ +/* + * QEMU Arduino boards + * + * Copyright (c) 2019-2020 Philippe Mathieu-Daudé + * + * This work is licensed under the terms of the GNU GPLv2 or later. + * See the COPYING file in the top-level directory. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* TODO: Implement the use of EXTRAM */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/boards.h" +#include "atmega.h" +#include "boot.h" + +typedef struct ArduinoMachineState { + /*< private >*/ + MachineState parent_obj; + /*< public >*/ + AtmegaMcuState mcu; +} ArduinoMachineState; + +typedef struct ArduinoMachineClass { + /*< private >*/ + MachineClass parent_class; + /*< public >*/ + const char *mcu_type; + uint64_t xtal_hz; +} ArduinoMachineClass; + +#define TYPE_ARDUINO_MACHINE \ + MACHINE_TYPE_NAME("arduino") +#define ARDUINO_MACHINE(obj) \ + OBJECT_CHECK(ArduinoMachineState, (obj), TYPE_ARDUINO_MACHINE) +#define ARDUINO_MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(ArduinoMachineClass, (klass), TYPE_ARDUINO_MACHINE) +#define ARDUINO_MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ArduinoMachineClass, (obj), TYPE_ARDUINO_MACHINE) + +static void arduino_machine_init(MachineState *machine) +{ + ArduinoMachineClass *amc = ARDUINO_MACHINE_GET_CLASS(machine); + ArduinoMachineState *ams = ARDUINO_MACHINE(machine); + + object_initialize_child(OBJECT(machine), "mcu", &ams->mcu, amc->mcu_type); + object_property_set_uint(OBJECT(&ams->mcu), "xtal-frequency-hz", + amc->xtal_hz, &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&ams->mcu), &error_abort); + + if (machine->firmware) { + if (!avr_load_firmware(&ams->mcu.cpu, machine, + &ams->mcu.flash, machine->firmware)) { + exit(1); + } + } +} + +static void arduino_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->init = arduino_machine_init; + mc->default_cpus = 1; + mc->min_cpus = mc->default_cpus; + mc->max_cpus = mc->default_cpus; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_parallel = 1; +} + +static void arduino_duemilanove_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc); + + /* https://www.arduino.cc/en/Main/ArduinoBoardDuemilanove */ + mc->desc = "Arduino Duemilanove (ATmega168)", + mc->alias = "2009"; + amc->mcu_type = TYPE_ATMEGA168_MCU; + amc->xtal_hz = 16 * 1000 * 1000; +}; + +static void arduino_uno_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc); + + /* https://store.arduino.cc/arduino-uno-rev3 */ + mc->desc = "Arduino UNO (ATmega328P)"; + mc->alias = "uno"; + amc->mcu_type = TYPE_ATMEGA328_MCU; + amc->xtal_hz = 16 * 1000 * 1000; +}; + +static void arduino_mega_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc); + + /* https://www.arduino.cc/en/Main/ArduinoBoardMega */ + mc->desc = "Arduino Mega (ATmega1280)"; + mc->alias = "mega"; + amc->mcu_type = TYPE_ATMEGA1280_MCU; + amc->xtal_hz = 16 * 1000 * 1000; +}; + +static void arduino_mega2560_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc); + + /* https://store.arduino.cc/arduino-mega-2560-rev3 */ + mc->desc = "Arduino Mega 2560 (ATmega2560)"; + mc->alias = "mega2560"; + amc->mcu_type = TYPE_ATMEGA2560_MCU; + amc->xtal_hz = 16 * 1000 * 1000; /* CSTCE16M0V53-R0 */ +}; + +static const TypeInfo arduino_machine_types[] = { + { + .name = MACHINE_TYPE_NAME("arduino-duemilanove"), + .parent = TYPE_ARDUINO_MACHINE, + .class_init = arduino_duemilanove_class_init, + }, { + .name = MACHINE_TYPE_NAME("arduino-uno"), + .parent = TYPE_ARDUINO_MACHINE, + .class_init = arduino_uno_class_init, + }, { + .name = MACHINE_TYPE_NAME("arduino-mega"), + .parent = TYPE_ARDUINO_MACHINE, + .class_init = arduino_mega_class_init, + }, { + .name = MACHINE_TYPE_NAME("arduino-mega-2560-v3"), + .parent = TYPE_ARDUINO_MACHINE, + .class_init = arduino_mega2560_class_init, + }, { + .name = TYPE_ARDUINO_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(ArduinoMachineState), + .class_size = sizeof(ArduinoMachineClass), + .class_init = arduino_machine_class_init, + .abstract = true, + } +}; + +DEFINE_TYPES(arduino_machine_types) From 36838e5f7827fc81b406659c4cf6fcfb01c3c2f8 Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:29 +0100 Subject: [PATCH 2159/2595] tests/boot-serial: Test some Arduino boards (AVR based) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print out 'T' through serial port. The Arduino Duemilanove is based on a AVR5 CPU, while the Arduino MEGA2560 on a AVR6 CPU. Signed-off-by: Michael Rolnik Signed-off-by: Philippe Mathieu-Daudé [rth: Squash Arduino adjustments from f4bug] Tested-by: Richard Henderson Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Acked-by: Thomas Huth Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-29-huth@tuxfamily.org> --- tests/qtest/Makefile.include | 2 ++ tests/qtest/boot-serial-test.c | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/tests/qtest/Makefile.include b/tests/qtest/Makefile.include index 98af2c2d93..994ac47399 100644 --- a/tests/qtest/Makefile.include +++ b/tests/qtest/Makefile.include @@ -66,6 +66,8 @@ check-qtest-i386-y += numa-test check-qtest-x86_64-y += $(check-qtest-i386-y) +check-qtest-avr-y += boot-serial-test + check-qtest-alpha-y += boot-serial-test check-qtest-alpha-$(CONFIG_VGA) += display-vga-test diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c index 85a3614286..bfe7624dc6 100644 --- a/tests/qtest/boot-serial-test.c +++ b/tests/qtest/boot-serial-test.c @@ -17,6 +17,15 @@ #include "libqtest.h" #include "libqos/libqos-spapr.h" +static const uint8_t bios_avr[] = { + 0x88, 0xe0, /* ldi r24, 0x08 */ + 0x80, 0x93, 0xc1, 0x00, /* sts 0x00C1, r24 ; Enable tx */ + 0x86, 0xe0, /* ldi r24, 0x06 */ + 0x80, 0x93, 0xc2, 0x00, /* sts 0x00C2, r24 ; Set the data bits to 8 */ + 0x84, 0xe5, /* ldi r24, 0x54 */ + 0x80, 0x93, 0xc6, 0x00, /* sts 0x00C6, r24 ; Output 'T' */ +}; + static const uint8_t kernel_mcf5208[] = { 0x41, 0xf9, 0xfc, 0x06, 0x00, 0x00, /* lea 0xfc060000,%a0 */ 0x10, 0x3c, 0x00, 0x54, /* move.b #'T',%d0 */ @@ -104,6 +113,8 @@ typedef struct testdef { static testdef_t tests[] = { { "alpha", "clipper", "", "PCI:" }, + { "avr", "arduino-duemilanove", "", "T", sizeof(bios_avr), NULL, bios_avr }, + { "avr", "arduino-mega-2560-v3", "", "T", sizeof(bios_avr), NULL, bios_avr}, { "ppc", "ppce500", "", "U-Boot" }, { "ppc", "40p", "-vga none -boot d", "Trying cd:," }, { "ppc", "g3beige", "", "PowerPC,750" }, From f5d31d6541ca0943d564d061a6764d1cb8b8024e Mon Sep 17 00:00:00 2001 From: Michael Rolnik Date: Fri, 24 Jan 2020 01:51:30 +0100 Subject: [PATCH 2160/2595] tests/acceptance: Test the Arduino MEGA2560 board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test is based on https://github.com/seharris/qemu-avr-tests/tree/master/free-rtos/Demo demo which. If working correctly, prints 'ABCDEFGHIJKLMNOPQRSTUVWX' out. it also demostrates that timer and IRQ are working As the path name demonstrates, the FreeRTOS tests target a board based on a ATMega2560 MCU. We have one, the Arduino MEGA2560. Complementary documentation: https://feilipu.me/2012/01/15/ethermega-arduino-mega-2560-and-freertos/ https://feilipu.me/2015/11/24/arduino_freertos/ (see 'Compatibility') Signed-off-by: Michael Rolnik Signed-off-by: Philippe Mathieu-Daudé [rth: Squash multiple avocado fixups from f4bug] Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Tested-by: Richard Henderson Tested-by: Philippe Mathieu-Daudé Acked-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé --- MAINTAINERS | 1 + tests/acceptance/machine_avr6.py | 50 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 tests/acceptance/machine_avr6.py diff --git a/MAINTAINERS b/MAINTAINERS index 702e3a2f91..655317688a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -173,6 +173,7 @@ R: Sarah Harris S: Maintained F: gdb-xml/avr-cpu.xml F: target/avr/ +F: tests/acceptance/machine_avr6.py CRIS TCG CPUs M: Edgar E. Iglesias diff --git a/tests/acceptance/machine_avr6.py b/tests/acceptance/machine_avr6.py new file mode 100644 index 0000000000..6baf4e9c7f --- /dev/null +++ b/tests/acceptance/machine_avr6.py @@ -0,0 +1,50 @@ +# +# QEMU AVR acceptance tests +# +# Copyright (c) 2019-2020 Michael Rolnik +# +# 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 . +# + +import time + +from avocado_qemu import Test + +class AVR6Machine(Test): + timeout = 5 + + def test_freertos(self): + """ + :avocado: tags=arch:avr + :avocado: tags=machine:arduino-mega-2560-v3 + """ + """ + https://github.com/seharris/qemu-avr-tests/raw/master/free-rtos/Demo/AVR_ATMega2560_GCC/demo.elf + constantly prints out 'ABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWX' + """ + rom_url = ('https://github.com/seharris/qemu-avr-tests' + '/raw/36c3e67b8755dcf/free-rtos/Demo' + '/AVR_ATMega2560_GCC/demo.elf') + rom_hash = '7eb521f511ca8f2622e0a3c5e8dd686efbb911d4' + rom_path = self.fetch_asset(rom_url, asset_hash=rom_hash) + + self.vm.add_args('-bios', rom_path) + self.vm.add_args('-nographic') + self.vm.launch() + + time.sleep(2) + self.vm.shutdown() + + self.assertIn('ABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWX', + self.vm.get_log()) From c0a659f9de8230289f6d1906b6a24c7d228c12de Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Sun, 5 Jul 2020 16:03:15 +0200 Subject: [PATCH 2161/2595] target/avr: Add section into QEMU documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new section explains basic ways of using AVR target in QEMU. Signed-off-by: Michael Rolnik [thuth: Converted doc from texi to Sphinx syntax] Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-31-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- docs/system/target-avr.rst | 37 +++++++++++++++++++++++++++++++++++++ docs/system/targets.rst | 1 + 2 files changed, 38 insertions(+) create mode 100644 docs/system/target-avr.rst diff --git a/docs/system/target-avr.rst b/docs/system/target-avr.rst new file mode 100644 index 0000000000..dc99afc895 --- /dev/null +++ b/docs/system/target-avr.rst @@ -0,0 +1,37 @@ +.. _AVR-System-emulator: + +AVR System emulator +------------------- + +Use the executable ``qemu-system-avr`` to emulate a AVR 8 bit based machine. +These can have one of the following cores: avr1, avr2, avr25, avr3, avr31, +avr35, avr4, avr5, avr51, avr6, avrtiny, xmega2, xmega3, xmega4, xmega5, +xmega6 and xmega7. + +As for now it supports few Arduino boards for educational and testing purposes. +These boards use a ATmega controller, which model is limited to USART & 16-bit +timer devices, enought to run FreeRTOS based applications (like +https://github.com/seharris/qemu-avr-tests/blob/master/free-rtos/Demo/AVR_ATMega2560_GCC/demo.elf +). + +Following are examples of possible usages, assuming demo.elf is compiled for +AVR cpu + + - Continuous non interrupted execution: + ``qemu-system-avr -machine mega2560 -bios demo.elf`` + + - Continuous non interrupted execution with serial output into telnet window: + ``qemu-system-avr -machine mega2560 -bios demo.elf -serial + tcp::5678,server,nowait -nographic`` + and then in another shell + ``telnet localhost 5678`` + + - Debugging wit GDB debugger: + ``qemu-system-avr -machine mega2560 -bios demo.elf -s -S`` + and then in another shell + ``avr-gdb demo.elf`` + and then within GDB shell + ``target remote :1234`` + + - Print out executed instructions: + ``qemu-system-avr -machine mega2560 -bios demo.elf -d in_asm`` diff --git a/docs/system/targets.rst b/docs/system/targets.rst index 99435a3eba..560783644d 100644 --- a/docs/system/targets.rst +++ b/docs/system/targets.rst @@ -19,3 +19,4 @@ Contents: target-xtensa target-s390x target-rx + target-avr From a291bc851d482907d643db990b70c1cdb98c730a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 23 Mar 2020 16:56:11 +0100 Subject: [PATCH 2162/2595] target/avr/cpu: Drop tlb_flush() in avr_cpu_reset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 1f5c00cfdb tlb_flush() is called from cpu_common_reset(). Reviewed-by: Thomas Huth Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200707070021.10031-2-f4bug@amsat.org> --- target/avr/cpu.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/target/avr/cpu.c b/target/avr/cpu.c index e5979c9a9f..0cfc5f2e4b 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -78,8 +78,6 @@ static void avr_cpu_reset(DeviceState *ds) env->skip = 0; memset(env->r, 0, sizeof(env->r)); - - tlb_flush(cs); } static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) From 2e34e622c2cbda6828bbb395b6bdd4e0240b8217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 30 Mar 2020 11:30:27 +0200 Subject: [PATCH 2163/2595] target/avr/cpu: Fix $PC displayed address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit $PC is 16-bit wide. Other registers display addresses on a byte granularity. To have a coherent ouput, display $PC using byte granularity too. Reviewed-by: Thomas Huth Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200707070021.10031-3-f4bug@amsat.org> --- target/avr/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 0cfc5f2e4b..5d9c4ad5bf 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -151,7 +151,7 @@ static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags) int i; qemu_fprintf(f, "\n"); - qemu_fprintf(f, "PC: %06x\n", env->pc_w); + qemu_fprintf(f, "PC: %06x\n", env->pc_w * 2); /* PC points to words */ qemu_fprintf(f, "SP: %04x\n", env->sp); qemu_fprintf(f, "rampD: %02x\n", env->rampD >> 16); qemu_fprintf(f, "rampX: %02x\n", env->rampX >> 16); From 19b293472f1514b5424ef4d9b092e02bd9b106c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 26 Mar 2020 10:38:29 +0100 Subject: [PATCH 2164/2595] target/avr/disas: Fix store instructions display order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While LOAD instructions use the target register as first argument, STORE instructions use it as second argument: LD Rd, X // Rd <- (X) ST Y, Rd // (Y) <- Rr Reported-by: Joaquin de Andres Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200707070021.10031-4-f4bug@amsat.org> --- target/avr/disas.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/target/avr/disas.c b/target/avr/disas.c index 60b2cc1325..8e1bac4d76 100644 --- a/target/avr/disas.c +++ b/target/avr/disas.c @@ -195,16 +195,16 @@ INSN(LDZ2, "r%d, Z+", a->rd) INSN(LDZ3, "r%d, -Z", a->rd) INSN(LDDY, "r%d, Y+%d", a->rd, a->imm) INSN(LDDZ, "r%d, Z+%d", a->rd, a->imm) -INSN(STS, "r%d, %d", a->rd, a->imm) -INSN(STX1, "r%d, X", a->rr) -INSN(STX2, "r%d, X+", a->rr) -INSN(STX3, "r%d, -X", a->rr) -INSN(STY2, "r%d, Y+", a->rd) -INSN(STY3, "r%d, -Y", a->rd) -INSN(STZ2, "r%d, Z+", a->rd) -INSN(STZ3, "r%d, -Z", a->rd) -INSN(STDY, "r%d, Y+%d", a->rd, a->imm) -INSN(STDZ, "r%d, Z+%d", a->rd, a->imm) +INSN(STS, "%d, r%d", a->imm, a->rd) +INSN(STX1, "X, r%d", a->rr) +INSN(STX2, "X+, r%d", a->rr) +INSN(STX3, "-X, r%d", a->rr) +INSN(STY2, "Y+, r%d", a->rd) +INSN(STY3, "-Y, r%d", a->rd) +INSN(STZ2, "Z+, r%d", a->rd) +INSN(STZ3, "-Z, r%d", a->rd) +INSN(STDY, "Y+%d, r%d", a->imm, a->rd) +INSN(STDZ, "Z+%d, r%d", a->imm, a->rd) INSN(LPM1, "") INSN(LPM2, "r%d, Z", a->rd) INSN(LPMX, "r%d, Z+", a->rd) From b418d2656112174ce27117ae4f75594b6a8abc5f Mon Sep 17 00:00:00 2001 From: David Edmondson Date: Wed, 1 Jul 2020 14:56:15 +0100 Subject: [PATCH 2165/2595] crypto/linux_keyring: fix 'secret_keyring' configure test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The configure test for 'secret_keyring' incorrectly checked the 'have_keyring' variable. Fixes: 54e7aac0562452e4fcab65ca5001d030eef2de15 Signed-off-by: David Edmondson Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20200618092636.71832-1-david.edmondson@oracle.com> Message-Id: <20200701135652.1366-4-alex.bennee@linaro.org> --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index ee6c3c6792..22377aa627 100755 --- a/configure +++ b/configure @@ -6486,7 +6486,7 @@ EOF fi if test "$secret_keyring" != "no" then - if test "$have_keyring" == "yes" + if test "$have_keyring" = "yes" then secret_keyring=yes else From 995f5c3c323a4703716c58fae78bee6276d49bef Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Wed, 1 Jul 2020 14:56:16 +0100 Subject: [PATCH 2166/2595] util/coroutine: Cleanup start_switch_fiber_ for TSAN. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a cleanup patch to follow-up the patch which introduced TSAN. This patch makes separate start_switch_fiber_ functions for TSAN and ASAN. This does two things: 1. Unrelated ASAN and TSAN code is separate and each function only has arguments that are actually needed. 2. The co->tsan_caller_fiber and co->tsan_co_fiber fields are only access from within #ifdef CONFIG_TSAN. Signed-off-by: Robert Foley Reviewed-by: Stefan Hajnoczi Signed-off-by: Alex Bennée Message-Id: <20200626170001.27017-1-robert.foley@linaro.org> Message-Id: <20200701135652.1366-5-alex.bennee@linaro.org> --- util/coroutine-ucontext.c | 52 +++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index f0b66320e1..fff20aad80 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -52,8 +52,10 @@ typedef struct { #endif sigjmp_buf env; +#ifdef CONFIG_TSAN void *tsan_co_fiber; void *tsan_caller_fiber; +#endif #ifdef CONFIG_VALGRIND_H unsigned int valgrind_stack_id; @@ -77,7 +79,10 @@ union cc_arg { int i[2]; }; -/* QEMU_ALWAYS_INLINE only does so if __OPTIMIZE__, so we cannot use it. */ +/* + * QEMU_ALWAYS_INLINE only does so if __OPTIMIZE__, so we cannot use it. + * always_inline is required to avoid TSan runtime fatal errors. + */ static inline __attribute__((always_inline)) void on_new_fiber(CoroutineUContext *co) { @@ -87,6 +92,7 @@ void on_new_fiber(CoroutineUContext *co) #endif } +/* always_inline is required to avoid TSan runtime fatal errors. */ static inline __attribute__((always_inline)) void finish_switch_fiber(void *fake_stack_save) { @@ -109,18 +115,29 @@ void finish_switch_fiber(void *fake_stack_save) #endif } -static inline __attribute__((always_inline)) void start_switch_fiber( - CoroutineAction action, void **fake_stack_save, - const void *bottom, size_t size, void *new_fiber) +/* always_inline is required to avoid TSan runtime fatal errors. */ +static inline __attribute__((always_inline)) +void start_switch_fiber_asan(CoroutineAction action, void **fake_stack_save, + const void *bottom, size_t size) { #ifdef CONFIG_ASAN __sanitizer_start_switch_fiber( action == COROUTINE_TERMINATE ? NULL : fake_stack_save, bottom, size); #endif +} + +/* always_inline is required to avoid TSan runtime fatal errors. */ +static inline __attribute__((always_inline)) +void start_switch_fiber_tsan(void **fake_stack_save, + CoroutineUContext *co, + bool caller) +{ #ifdef CONFIG_TSAN - void *curr_fiber = - __tsan_get_current_fiber(); + void *new_fiber = caller ? + co->tsan_caller_fiber : + co->tsan_co_fiber; + void *curr_fiber = __tsan_get_current_fiber(); __tsan_acquire(curr_fiber); *fake_stack_save = curr_fiber; @@ -144,12 +161,9 @@ static void coroutine_trampoline(int i0, int i1) /* Initialize longjmp environment and switch back the caller */ if (!sigsetjmp(self->env, 0)) { - start_switch_fiber( - COROUTINE_YIELD, - &fake_stack_save, - leader.stack, - leader.stack_size, - self->tsan_caller_fiber); + start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save, leader.stack, + leader.stack_size); + start_switch_fiber_tsan(&fake_stack_save, self, true); /* true=caller */ siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); } @@ -208,10 +222,10 @@ Coroutine *qemu_coroutine_new(void) /* swapcontext() in, siglongjmp() back out */ if (!sigsetjmp(old_env, 0)) { - start_switch_fiber( - COROUTINE_YIELD, - &fake_stack_save, - co->stack, co->stack_size, co->tsan_co_fiber); + start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save, co->stack, + co->stack_size); + start_switch_fiber_tsan(&fake_stack_save, + co, false); /* false=not caller */ #ifdef CONFIG_SAFESTACK /* @@ -287,8 +301,10 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, ret = sigsetjmp(from->env, 0); if (ret == 0) { - start_switch_fiber(action, &fake_stack_save, - to->stack, to->stack_size, to->tsan_co_fiber); + start_switch_fiber_asan(action, &fake_stack_save, to->stack, + to->stack_size); + start_switch_fiber_tsan(&fake_stack_save, + to, false); /* false=not caller */ siglongjmp(to->env, action); } From 1f335d18e57ba9494e09184008ce7eccfd6755c9 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Wed, 1 Jul 2020 14:56:17 +0100 Subject: [PATCH 2167/2595] tests/vm: pass args through to BaseVM's __init__ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding the args parameter to BaseVM's __init__. We will shortly need to pass more parameters to the class so let's just pass args rather than growing the parameter list. Signed-off-by: Robert Foley Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200601211421.1277-2-robert.foley@linaro.org> Message-Id: <20200701135652.1366-6-alex.bennee@linaro.org> --- tests/vm/basevm.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index a80b616a08..5a58e6c393 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -61,11 +61,10 @@ class BaseVM(object): # 4 is arbitrary, but greater than 2, # since we found we need to wait more than twice as long. tcg_ssh_timeout_multiplier = 4 - def __init__(self, debug=False, vcpus=None, genisoimage=None, - build_path=None): + def __init__(self, args): self._guest = None - self._genisoimage = genisoimage - self._build_path = build_path + self._genisoimage = args.genisoimage + self._build_path = args.build_path self._tmpdir = os.path.realpath(tempfile.mkdtemp(prefix="vm-test-", suffix=".tmp", dir=".")) @@ -78,7 +77,7 @@ class BaseVM(object): self._ssh_pub_key_file = os.path.join(self._tmpdir, "id_rsa.pub") open(self._ssh_pub_key_file, "w").write(SSH_PUB_KEY) - self.debug = debug + self.debug = args.debug self._stderr = sys.stderr self._devnull = open(os.devnull, "w") if self.debug: @@ -92,8 +91,8 @@ class BaseVM(object): (",ipv6=no" if not self.ipv6 else ""), "-device", "virtio-net-pci,netdev=vnet", "-vnc", "127.0.0.1:0,to=20"] - if vcpus and vcpus > 1: - self._args += ["-smp", "%d" % vcpus] + if args.jobs and args.jobs > 1: + self._args += ["-smp", "%d" % args.jobs] if kvm_available(self.arch): self._args += ["-enable-kvm"] else: @@ -456,8 +455,7 @@ def main(vmcls): return 1 logging.basicConfig(level=(logging.DEBUG if args.debug else logging.WARN)) - vm = vmcls(debug=args.debug, vcpus=args.jobs, - genisoimage=args.genisoimage, build_path=args.build_path) + vm = vmcls(args) if args.build_image: if os.path.exists(args.image) and not args.force: sys.stderr.writelines(["Image file exists: %s\n" % args.image, From 5d676197ebe9bfe0ecc466c5375bcdbc7a7e48f5 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Wed, 1 Jul 2020 14:56:18 +0100 Subject: [PATCH 2168/2595] tests/vm: Add configuration to basevm.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added use of a configuration to tests/vm/basevm.py. The configuration provides parameters used to configure a VM. This allows for providing alternate configurations to the VM being created/launched. cpu, machine, memory, and NUMA configuration are all examples of configuration which we might want to vary on the VM being created or launched. This will for example allow for creating an aarch64 vm. Signed-off-by: Robert Foley Reviewed-by: Peter Puhov Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200601211421.1277-3-robert.foley@linaro.org> Message-Id: <20200701135652.1366-7-alex.bennee@linaro.org> --- tests/vm/basevm.py | 166 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 130 insertions(+), 36 deletions(-) diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 5a58e6c393..5ae39ad113 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -29,16 +29,41 @@ import tempfile import shutil import multiprocessing import traceback +import shlex -SSH_KEY = open(os.path.join(os.path.dirname(__file__), - "..", "keys", "id_rsa")).read() -SSH_PUB_KEY = open(os.path.join(os.path.dirname(__file__), - "..", "keys", "id_rsa.pub")).read() +SSH_KEY_FILE = os.path.join(os.path.dirname(__file__), + "..", "keys", "id_rsa") +SSH_PUB_KEY_FILE = os.path.join(os.path.dirname(__file__), + "..", "keys", "id_rsa.pub") +# This is the standard configuration. +# Any or all of these can be overridden by +# passing in a config argument to the VM constructor. +DEFAULT_CONFIG = { + 'cpu' : "max", + 'machine' : 'pc', + 'guest_user' : "qemu", + 'guest_pass' : "qemupass", + 'root_pass' : "qemupass", + 'ssh_key_file' : SSH_KEY_FILE, + 'ssh_pub_key_file': SSH_PUB_KEY_FILE, + 'memory' : "4G", + 'extra_args' : [], + 'qemu_args' : "", + 'dns' : "", + 'ssh_port' : 0, + 'install_cmds' : "", + 'boot_dev_type' : "block", + 'ssh_timeout' : 1, +} +BOOT_DEVICE = { + 'block' : "-drive file={},if=none,id=drive0,cache=writeback "\ + "-device virtio-blk,drive=drive0,bootindex=0", + 'scsi' : "-device virtio-scsi-device,id=scsi "\ + "-drive file={},format=raw,if=none,id=hd0 "\ + "-device scsi-hd,drive=hd0,bootindex=0", +} class BaseVM(object): - GUEST_USER = "qemu" - GUEST_PASS = "qemupass" - ROOT_PASS = "qemupass" envvars = [ "https_proxy", @@ -57,25 +82,38 @@ class BaseVM(object): poweroff = "poweroff" # enable IPv6 networking ipv6 = True + # This is the timeout on the wait for console bytes. + socket_timeout = 120 # Scale up some timeouts under TCG. # 4 is arbitrary, but greater than 2, # since we found we need to wait more than twice as long. tcg_ssh_timeout_multiplier = 4 - def __init__(self, args): + def __init__(self, args, config=None): self._guest = None self._genisoimage = args.genisoimage self._build_path = args.build_path + # Allow input config to override defaults. + self._config = DEFAULT_CONFIG.copy() + if config != None: + self._config.update(config) + self.validate_ssh_keys() self._tmpdir = os.path.realpath(tempfile.mkdtemp(prefix="vm-test-", suffix=".tmp", dir=".")) atexit.register(shutil.rmtree, self._tmpdir) + # Copy the key files to a temporary directory. + # Also chmod the key file to agree with ssh requirements. + self._config['ssh_key'] = \ + open(self._config['ssh_key_file']).read().rstrip() + self._config['ssh_pub_key'] = \ + open(self._config['ssh_pub_key_file']).read().rstrip() + self._ssh_tmp_key_file = os.path.join(self._tmpdir, "id_rsa") + open(self._ssh_tmp_key_file, "w").write(self._config['ssh_key']) + subprocess.check_call(["chmod", "600", self._ssh_tmp_key_file]) - self._ssh_key_file = os.path.join(self._tmpdir, "id_rsa") - open(self._ssh_key_file, "w").write(SSH_KEY) - subprocess.check_call(["chmod", "600", self._ssh_key_file]) - - self._ssh_pub_key_file = os.path.join(self._tmpdir, "id_rsa.pub") - open(self._ssh_pub_key_file, "w").write(SSH_PUB_KEY) + self._ssh_tmp_pub_key_file = os.path.join(self._tmpdir, "id_rsa.pub") + open(self._ssh_tmp_pub_key_file, + "w").write(self._config['ssh_pub_key']) self.debug = args.debug self._stderr = sys.stderr @@ -84,11 +122,14 @@ class BaseVM(object): self._stdout = sys.stdout else: self._stdout = self._devnull + netdev = "user,id=vnet,hostfwd=:127.0.0.1:{}-:22" self._args = [ \ - "-nodefaults", "-m", "4G", - "-cpu", "max", - "-netdev", "user,id=vnet,hostfwd=:127.0.0.1:0-:22" + - (",ipv6=no" if not self.ipv6 else ""), + "-nodefaults", "-m", self._config['memory'], + "-cpu", self._config['cpu'], + "-netdev", + netdev.format(self._config['ssh_port']) + + (",ipv6=no" if not self.ipv6 else "") + + (",dns=" + self._config['dns'] if self._config['dns'] else ""), "-device", "virtio-net-pci,netdev=vnet", "-vnc", "127.0.0.1:0,to=20"] if args.jobs and args.jobs > 1: @@ -99,6 +140,55 @@ class BaseVM(object): logging.info("KVM not available, not using -enable-kvm") self._data_args = [] + if self._config['qemu_args'] != None: + qemu_args = self._config['qemu_args'] + qemu_args = qemu_args.replace('\n',' ').replace('\r','') + # shlex groups quoted arguments together + # we need this to keep the quoted args together for when + # the QEMU command is issued later. + args = shlex.split(qemu_args) + self._config['extra_args'] = [] + for arg in args: + if arg: + # Preserve quotes around arguments. + # shlex above takes them out, so add them in. + if " " in arg: + arg = '"{}"'.format(arg) + self._config['extra_args'].append(arg) + + def validate_ssh_keys(self): + """Check to see if the ssh key files exist.""" + if 'ssh_key_file' not in self._config or\ + not os.path.exists(self._config['ssh_key_file']): + raise Exception("ssh key file not found.") + if 'ssh_pub_key_file' not in self._config or\ + not os.path.exists(self._config['ssh_pub_key_file']): + raise Exception("ssh pub key file not found.") + + def wait_boot(self, wait_string=None): + """Wait for the standard string we expect + on completion of a normal boot. + The user can also choose to override with an + alternate string to wait for.""" + if wait_string is None: + if self.login_prompt is None: + raise Exception("self.login_prompt not defined") + wait_string = self.login_prompt + # Intentionally bump up the default timeout under TCG, + # since the console wait below takes longer. + timeout = self.socket_timeout + if not kvm_available(self.arch): + timeout *= 8 + self.console_init(timeout=timeout) + self.console_wait(wait_string) + + def __getattr__(self, name): + # Support direct access to config by key. + # for example, access self._config['cpu'] by self.cpu + if name.lower() in self._config.keys(): + return self._config[name.lower()] + return object.__getattribute__(self, name) + def _download_with_cache(self, url, sha256sum=None, sha512sum=None): def check_sha256sum(fname): if not sha256sum: @@ -130,8 +220,9 @@ class BaseVM(object): "-t", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=" + os.devnull, - "-o", "ConnectTimeout=1", - "-p", self.ssh_port, "-i", self._ssh_key_file] + "-o", + "ConnectTimeout={}".format(self._config["ssh_timeout"]), + "-p", self.ssh_port, "-i", self._ssh_tmp_key_file] # If not in debug mode, set ssh to quiet mode to # avoid printing the results of commands. if not self.debug: @@ -180,14 +271,14 @@ class BaseVM(object): "virtio-blk,drive=%s,serial=%s,bootindex=1" % (name, name)] def boot(self, img, extra_args=[]): - args = self._args + [ - "-drive", "file=%s,if=none,id=drive0,cache=writeback" % img, - "-device", "virtio-blk,drive=drive0,bootindex=0"] - args += self._data_args + extra_args + boot_dev = BOOT_DEVICE[self._config['boot_dev_type']] + boot_params = boot_dev.format(img) + args = self._args + boot_params.split(' ') + args += self._data_args + extra_args + self._config['extra_args'] logging.debug("QEMU args: %s", " ".join(args)) qemu_path = get_qemu_path(self.arch, self._build_path) guest = QEMUMachine(binary=qemu_path, args=args) - guest.set_machine('pc') + guest.set_machine(self._config['machine']) guest.set_console() try: guest.launch() @@ -301,7 +392,8 @@ class BaseVM(object): self.console_send(command) def console_ssh_init(self, prompt, user, pw): - sshkey_cmd = "echo '%s' > .ssh/authorized_keys\n" % SSH_PUB_KEY.rstrip() + sshkey_cmd = "echo '%s' > .ssh/authorized_keys\n" \ + % self._config['ssh_pub_key'].rstrip() self.console_wait_send("login:", "%s\n" % user) self.console_wait_send("Password:", "%s\n" % pw) self.console_wait_send(prompt, "mkdir .ssh\n") @@ -360,23 +452,23 @@ class BaseVM(object): "local-hostname: {}-guest\n".format(name)]) mdata.close() udata = open(os.path.join(cidir, "user-data"), "w") - print("guest user:pw {}:{}".format(self.GUEST_USER, - self.GUEST_PASS)) + print("guest user:pw {}:{}".format(self._config['guest_user'], + self._config['guest_pass'])) udata.writelines(["#cloud-config\n", "chpasswd:\n", " list: |\n", - " root:%s\n" % self.ROOT_PASS, - " %s:%s\n" % (self.GUEST_USER, - self.GUEST_PASS), + " root:%s\n" % self._config['root_pass'], + " %s:%s\n" % (self._config['guest_user'], + self._config['guest_pass']), " expire: False\n", "users:\n", - " - name: %s\n" % self.GUEST_USER, + " - name: %s\n" % self._config['guest_user'], " sudo: ALL=(ALL) NOPASSWD:ALL\n", " ssh-authorized-keys:\n", - " - %s\n" % SSH_PUB_KEY, + " - %s\n" % self._config['ssh_pub_key'], " - name: root\n", " ssh-authorized-keys:\n", - " - %s\n" % SSH_PUB_KEY, + " - %s\n" % self._config['ssh_pub_key'], "locale: en_US.UTF-8\n"]) proxy = os.environ.get("http_proxy") if not proxy is None: @@ -447,15 +539,17 @@ def parse_args(vmcls): parser.disable_interspersed_args() return parser.parse_args() -def main(vmcls): +def main(vmcls, config=None): try: + if config == None: + config = DEFAULT_CONFIG args, argv = parse_args(vmcls) if not argv and not args.build_qemu and not args.build_image: print("Nothing to do?") return 1 logging.basicConfig(level=(logging.DEBUG if args.debug else logging.WARN)) - vm = vmcls(args) + vm = vmcls(args, config=config) if args.build_image: if os.path.exists(args.image) and not args.force: sys.stderr.writelines(["Image file exists: %s\n" % args.image, From 3f1e8137f29b824c69d316143cc873c2239ecaed Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Wed, 1 Jul 2020 14:56:19 +0100 Subject: [PATCH 2169/2595] tests/vm: Added configuration file support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes to tests/vm/basevm.py to allow accepting a configuration file as a parameter. Allows for specifying VM options such as cpu, machine, memory, and arbitrary qemu arguments for specifying options such as NUMA configuration. Also added an example conf_example_aarch64.yml and conf_example_x86.yml. Signed-off-by: Robert Foley Reviewed-by: Peter Puhov Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200601211421.1277-4-robert.foley@linaro.org> Message-Id: <20200701135652.1366-8-alex.bennee@linaro.org> --- configure | 9 ++++++ tests/vm/Makefile.include | 6 ++++ tests/vm/basevm.py | 40 +++++++++++++++++++++++- tests/vm/conf_example_aarch64.yml | 51 +++++++++++++++++++++++++++++++ tests/vm/conf_example_x86.yml | 50 ++++++++++++++++++++++++++++++ 5 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 tests/vm/conf_example_aarch64.yml create mode 100644 tests/vm/conf_example_x86.yml diff --git a/configure b/configure index 22377aa627..c0cda32484 100755 --- a/configure +++ b/configure @@ -960,6 +960,13 @@ do fi done +# Check for existence of python3 yaml, needed to +# import yaml config files into vm-build. +python_yaml="no" +if $(python3 -c "import yaml" 2> /dev/null); then + python_yaml="yes" +fi + : ${smbd=${SMBD-/usr/sbin/smbd}} # Default objcc to clang if available, otherwise use CC @@ -6868,6 +6875,7 @@ if test "$docs" != "no"; then echo "sphinx-build $sphinx_build" fi echo "genisoimage $genisoimage" +echo "python_yaml $python_yaml" echo "slirp support $slirp $(echo_version $slirp $slirp_version)" if test "$slirp" != "no" ; then echo "smbd $smbd" @@ -7966,6 +7974,7 @@ echo "PYTHON=$python" >> $config_host_mak echo "SPHINX_BUILD=$sphinx_build" >> $config_host_mak echo "SPHINX_WERROR=$sphinx_werror" >> $config_host_mak echo "GENISOIMAGE=$genisoimage" >> $config_host_mak +echo "PYTHON_YAML=$python_yaml" >> $config_host_mak echo "CC=$cc" >> $config_host_mak if $iasl -h > /dev/null 2>&1; then echo "IASL=$iasl" >> $config_host_mak diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include index a253aba457..f6c3892bb2 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -44,6 +44,12 @@ endif @echo " QEMU_LOCAL=1 - Use QEMU binary local to this build." @echo " QEMU=/path/to/qemu - Change path to QEMU binary" @echo " QEMU_IMG=/path/to/qemu-img - Change path to qemu-img tool" +ifeq ($(PYTHON_YAML),yes) + @echo " QEMU_CONFIG=/path/conf.yml - Change path to VM configuration .yml file." +else + @echo " (install python3-yaml to enable support for yaml file to configure a VM.)" +endif + @echo " See conf_example_*.yml for file format details." vm-build-all: $(addprefix vm-build-, $(IMAGES)) diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 5ae39ad113..f3a8fbbe34 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -481,7 +481,6 @@ class BaseVM(object): cwd=cidir, stdin=self._devnull, stdout=self._stdout, stderr=self._stdout) - return os.path.join(cidir, "cloud-init.iso") def get_qemu_path(arch, build_path=None): @@ -497,6 +496,41 @@ def get_qemu_path(arch, build_path=None): qemu_path = "qemu-system-" + arch return qemu_path +def parse_config(config, args): + """ Parse yaml config and populate our config structure. + The yaml config allows the user to override the + defaults for VM parameters. In many cases these + defaults can be overridden without rebuilding the VM.""" + if args.config: + config_file = args.config + elif 'QEMU_CONFIG' in os.environ: + config_file = os.environ['QEMU_CONFIG'] + else: + return config + if not os.path.exists(config_file): + raise Exception("config file {} does not exist".format(config_file)) + # We gracefully handle importing the yaml module + # since it might not be installed. + # If we are here it means the user supplied a .yml file, + # so if the yaml module is not installed we will exit with error. + try: + import yaml + except ImportError: + print("The python3-yaml package is needed "\ + "to support config.yaml files") + # Instead of raising an exception we exit to avoid + # a raft of messy (expected) errors to stdout. + exit(1) + with open(config_file) as f: + yaml_dict = yaml.safe_load(f) + + if 'qemu-conf' in yaml_dict: + config.update(yaml_dict['qemu-conf']) + else: + raise Exception("config file {} is not valid"\ + " missing qemu-conf".format(config_file)) + return config + def parse_args(vmcls): def get_default_jobs(): @@ -536,6 +570,9 @@ def parse_args(vmcls): help="run tests with a snapshot") parser.add_option("--genisoimage", default="genisoimage", help="iso imaging tool") + parser.add_option("--config", "-c", default=None, + help="Provide config yaml for configuration. "\ + "See config_example.yaml for example.") parser.disable_interspersed_args() return parser.parse_args() @@ -547,6 +584,7 @@ def main(vmcls, config=None): if not argv and not args.build_qemu and not args.build_image: print("Nothing to do?") return 1 + config = parse_config(config, args) logging.basicConfig(level=(logging.DEBUG if args.debug else logging.WARN)) vm = vmcls(args, config=config) diff --git a/tests/vm/conf_example_aarch64.yml b/tests/vm/conf_example_aarch64.yml new file mode 100644 index 0000000000..9d44ae356f --- /dev/null +++ b/tests/vm/conf_example_aarch64.yml @@ -0,0 +1,51 @@ +# +# Example yaml for use by any of the scripts in tests/vm. +# Can be provided as an environment variable QEMU_CONFIG +# +qemu-conf: + + # If any of the below are not provided, we will just use the qemu defaults. + + # Login username and password(has to be sudo enabled) + guest_user: qemu + guest_pass: "qemupass" + + # Password for root user can be different from guest. + root_pass: "qemupass" + + # If one key is provided, both must be provided. + #ssh_key: /complete/path/of/your/keyfile/id_rsa + #ssh_pub_key: /complete/path/of/your/keyfile/id_rsa.pub + + cpu: max + machine: virt,gic-version=max + memory: 16G + + # The below is a example for how to configure NUMA topology with + # 4 NUMA nodes and 2 different NUMA distances. + qemu_args: "-smp cpus=16,sockets=2,cores=8 + -numa node,cpus=0-3,nodeid=0 -numa node,cpus=4-7,nodeid=1 + -numa node,cpus=8-11,nodeid=2 -numa node,cpus=12-15,nodeid=3 + -numa dist,src=0,dst=1,val=15 -numa dist,src=2,dst=3,val=15 + -numa dist,src=0,dst=2,val=20 -numa dist,src=0,dst=3,val=20 + -numa dist,src=1,dst=2,val=20 -numa dist,src=1,dst=3,val=20" + + # By default we do not set the DNS. + # You override the defaults by setting the below. + #dns: 1.234.567.89 + + # By default we will use a "block" device, but + # you can also boot from a "scsi" device. + # Just keep in mind your scripts might need to change + # As you will have /dev/sda instead of /dev/vda (for block device) + boot_dev_type: "block" + + # By default the ssh port is not fixed. + # A fixed ssh port makes it easier for automated tests. + #ssh_port: 5555 + + # To install a different set of packages, provide a command to issue + #install_cmds: "apt-get update ; apt-get build-dep -y qemu" + + # Or to skip the install entirely, just provide "" + #install_cmds: "" diff --git a/tests/vm/conf_example_x86.yml b/tests/vm/conf_example_x86.yml new file mode 100644 index 0000000000..78d3f5830f --- /dev/null +++ b/tests/vm/conf_example_x86.yml @@ -0,0 +1,50 @@ +# +# Example yaml for use by any of the x86 based scripts in tests/vm. +# Can be provided as an environment variable QEMU_CONFIG +# +qemu-conf: + + # If any of the below are not provided, we will just use the qemu defaults. + + # Login username and password(has to be sudo enabled) + guest_user: "qemu" + guest_pass: "qemupass" + + # Password for root user can be different from guest. + root_pass: "qemupass" + + # Provide default ssh keys of current user. + # You need to edit the below for your user. + #ssh_key_file: /home//.ssh/id_rsa + #ssh_pub_key_file: /home//.ssh/id_rsa.pub + + cpu: max + machine: pc + memory: 8G + + # The below is a example for how to configure NUMA topology with + # 4 NUMA nodes and 2 different NUMA distances. + qemu_args: "-smp cpus=8,sockets=2,cores=4 + -object memory-backend-ram,size=4G,policy=bind,host-nodes=0,id=ram-node0 + -object memory-backend-ram,size=4G,policy=bind,host-nodes=0,id=ram-node1 + -object memory-backend-ram,size=4G,policy=bind,host-nodes=1,id=ram-node2 + -object memory-backend-ram,size=4G,policy=bind,host-nodes=1,id=ram-node3 + -numa node,cpus=0-1,nodeid=0 -numa node,cpus=2-3,nodeid=1 + -numa node,cpus=4-5,nodeid=2 -numa node,cpus=6-7,nodeid=3 + -numa dist,src=0,dst=1,val=15 -numa dist,src=2,dst=3,val=15 + -numa dist,src=0,dst=2,val=20 -numa dist,src=0,dst=3,val=20 + -numa dist,src=1,dst=2,val=20 -numa dist,src=1,dst=3,val=20" + + # By default we do not set the DNS. + # You override the defaults by setting the below. + #dns: "1.234.567.89" + + # By default we will use a "block" device, but + # you can also boot from a "scsi" device. + # Just keep in mind your scripts might need to change + # As you will have /dev/sda instead of /dev/vda (for block device) + boot_dev_type: "block" + + # By default the ssh port is not fixed. + # A fixed ssh port makes it easier for automated tests. + ssh_port: 5555 From e56833b48bdedba89ab9f874eb8747bdaf382ff6 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Wed, 1 Jul 2020 14:56:20 +0100 Subject: [PATCH 2170/2595] tests/vm: Add common Ubuntu python module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a common Ubuntu python module and make use of it with the ubuntu.i386 script. This is preparation for adding an Ubuntu script ubuntu.aarch64. Splitting out the common logic such as build_image() will reduce duplication. Signed-off-by: Robert Foley Tested-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200601211421.1277-5-robert.foley@linaro.org> Message-Id: <20200701135652.1366-9-alex.bennee@linaro.org> --- tests/vm/ubuntu.i386 | 46 +++++++++------------------------ tests/vm/ubuntuvm.py | 60 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 34 deletions(-) create mode 100644 tests/vm/ubuntuvm.py diff --git a/tests/vm/ubuntu.i386 b/tests/vm/ubuntu.i386 index 24527cc78c..5ce72610a6 100755 --- a/tests/vm/ubuntu.i386 +++ b/tests/vm/ubuntu.i386 @@ -11,15 +11,22 @@ # the COPYING file in the top-level directory. # -import os import sys -import subprocess import basevm -import time +import ubuntuvm -class UbuntuX86VM(basevm.BaseVM): +DEFAULT_CONFIG = { + 'install_cmds' : "apt-get update,"\ + "apt-get build-dep -y qemu,"\ + "apt-get install -y libfdt-dev language-pack-en", +} + +class UbuntuX86VM(ubuntuvm.UbuntuVM): name = "ubuntu.i386" arch = "i386" + image_link="https://cloud-images.ubuntu.com/releases/bionic/"\ + "release-20191114/ubuntu-18.04-server-cloudimg-i386.img" + image_sha256="28969840626d1ea80bb249c08eef1a4533e8904aa51a327b40f37ac4b4ff04ef" BUILD_SCRIPT = """ set -e; cd $(mktemp -d); @@ -29,34 +36,5 @@ class UbuntuX86VM(basevm.BaseVM): make --output-sync {target} -j{jobs} {verbose}; """ - def build_image(self, img): - cimg = self._download_with_cache( - "https://cloud-images.ubuntu.com/releases/bionic/release-20191114/ubuntu-18.04-server-cloudimg-i386.img", - sha256sum="28969840626d1ea80bb249c08eef1a4533e8904aa51a327b40f37ac4b4ff04ef") - img_tmp = img + ".tmp" - subprocess.check_call(["cp", "-f", cimg, img_tmp]) - self.exec_qemu_img("resize", img_tmp, "50G") - self.boot(img_tmp, extra_args = [ - "-device", "VGA", - "-cdrom", self.gen_cloud_init_iso() - ]) - self.wait_ssh() - self.ssh_root_check("touch /etc/cloud/cloud-init.disabled") - self.ssh_root_check("apt-get update") - self.ssh_root_check("apt-get install -y cloud-initramfs-growroot") - # Don't check the status in case the guest hang up too quickly - self.ssh_root("sync && reboot") - time.sleep(5) - self.wait_ssh() - # The previous update sometimes doesn't survive a reboot, so do it again - self.ssh_root_check("sed -ie s/^#\ deb-src/deb-src/g /etc/apt/sources.list") - self.ssh_root_check("apt-get update") - self.ssh_root_check("apt-get build-dep -y qemu") - self.ssh_root_check("apt-get install -y libfdt-dev language-pack-en") - self.ssh_root("poweroff") - self.wait() - os.rename(img_tmp, img) - return 0 - if __name__ == "__main__": - sys.exit(basevm.main(UbuntuX86VM)) + sys.exit(basevm.main(UbuntuX86VM, DEFAULT_CONFIG)) diff --git a/tests/vm/ubuntuvm.py b/tests/vm/ubuntuvm.py new file mode 100644 index 0000000000..6689ad87aa --- /dev/null +++ b/tests/vm/ubuntuvm.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +# +# Ubuntu VM testing library +# +# Copyright 2017 Red Hat Inc. +# Copyright 2020 Linaro +# +# Authors: +# Robert Foley +# Originally based on ubuntu.i386 Fam Zheng +# +# This code is licensed under the GPL version 2 or later. See +# the COPYING file in the top-level directory. + +import os +import subprocess +import basevm + +class UbuntuVM(basevm.BaseVM): + + def __init__(self, args, config=None): + self.login_prompt = "ubuntu-{}-guest login:".format(self.arch) + basevm.BaseVM.__init__(self, args, config) + + def build_image(self, img): + """Build an Ubuntu VM image. The child class will + define the install_cmds to init the VM.""" + os_img = self._download_with_cache(self.image_link, + sha256sum=self.image_sha256) + img_tmp = img + ".tmp" + subprocess.check_call(["cp", "-f", os_img, img_tmp]) + self.exec_qemu_img("resize", img_tmp, "+50G") + ci_img = self.gen_cloud_init_iso() + + self.boot(img_tmp, extra_args = [ "-device", "VGA", "-cdrom", ci_img, ]) + + # First command we issue is fix for slow ssh login. + self.wait_ssh(wait_root=True, + cmd="chmod -x /etc/update-motd.d/*") + # Wait for cloud init to finish + self.wait_ssh(wait_root=True, + cmd="ls /var/lib/cloud/instance/boot-finished") + self.ssh_root("touch /etc/cloud/cloud-init.disabled") + # Disable auto upgrades. + # We want to keep the VM system state stable. + self.ssh_root('sed -ie \'s/"1"/"0"/g\' '\ + '/etc/apt/apt.conf.d/20auto-upgrades') + self.ssh_root("sed -ie s/^#\ deb-src/deb-src/g /etc/apt/sources.list") + + # If the user chooses not to do the install phase, + # then we will jump right to the graceful shutdown + if self._config['install_cmds'] != "": + # Issue the install commands. + # This can be overriden by the user in the config .yml. + install_cmds = self._config['install_cmds'].split(',') + for cmd in install_cmds: + self.ssh_root(cmd) + self.graceful_shutdown() + os.rename(img_tmp, img) + return 0 From 13336606a5ef9d6beeb8c0763ac0a9d11c249cac Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Wed, 1 Jul 2020 14:56:21 +0100 Subject: [PATCH 2171/2595] tests/vm: Added a new script for ubuntu.aarch64. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ubuntu.aarch64 provides a script to create an Ubuntu 18.04 VM. Another new file is also added aarch64vm.py, which is a module with common methods used by aarch64 VMs, such as how to create the flash images. Signed-off-by: Robert Foley Reviewed-by: Peter Puhov Signed-off-by: Alex Bennée Message-Id: <20200601211421.1277-6-robert.foley@linaro.org> Message-Id: <20200701135652.1366-10-alex.bennee@linaro.org> --- configure | 20 +++++++ tests/vm/Makefile.include | 11 ++++ tests/vm/aarch64vm.py | 106 ++++++++++++++++++++++++++++++++++++++ tests/vm/basevm.py | 12 +++++ tests/vm/ubuntu.aarch64 | 68 ++++++++++++++++++++++++ 5 files changed, 217 insertions(+) create mode 100644 tests/vm/aarch64vm.py create mode 100755 tests/vm/ubuntu.aarch64 diff --git a/configure b/configure index c0cda32484..1e977601a4 100755 --- a/configure +++ b/configure @@ -418,6 +418,7 @@ prefix="/usr/local" mandir="\${prefix}/share/man" datadir="\${prefix}/share" firmwarepath="\${prefix}/share/qemu-firmware" +efi_aarch64="" qemu_docdir="\${prefix}/share/doc/qemu" bindir="\${prefix}/bin" libdir="\${prefix}/lib" @@ -1109,6 +1110,8 @@ for opt do ;; --firmwarepath=*) firmwarepath="$optarg" ;; + --efi-aarch64=*) efi_aarch64="$optarg" + ;; --host=*|--build=*|\ --disable-dependency-tracking|\ --sbindir=*|--sharedstatedir=*|\ @@ -1791,6 +1794,7 @@ Advanced options (experts only): --sysconfdir=PATH install config in PATH$confsuffix --localstatedir=PATH install local state in PATH (set at runtime on win32) --firmwarepath=PATH search PATH for firmware files + --efi-aarch64=PATH PATH of efi file to use for aarch64 VMs. --with-confsuffix=SUFFIX suffix for QEMU data inside datadir/libdir/sysconfdir [$confsuffix] --with-pkgversion=VERS use specified string as sub-version of the package --enable-debug enable common debug build options @@ -3627,6 +3631,20 @@ EOF fi fi +############################################ +# efi-aarch64 probe +# Check for efi files needed by aarch64 VMs. +# By default we will use the efi included with QEMU. +# Allow user to override the path for efi also. +if ! test -f "$efi_aarch64"; then + if test -f $source_path/pc-bios/edk2-aarch64-code.fd.bz2; then + # valid after build + efi_aarch64=$PWD/pc-bios/edk2-aarch64-code.fd + else + efi_aarch64="" + fi +fi + ########################################## # libcap-ng library probe if test "$cap_ng" != "no" ; then @@ -6875,6 +6893,7 @@ if test "$docs" != "no"; then echo "sphinx-build $sphinx_build" fi echo "genisoimage $genisoimage" +echo "efi_aarch64 $efi_aarch64" echo "python_yaml $python_yaml" echo "slirp support $slirp $(echo_version $slirp $slirp_version)" if test "$slirp" != "no" ; then @@ -7974,6 +7993,7 @@ echo "PYTHON=$python" >> $config_host_mak echo "SPHINX_BUILD=$sphinx_build" >> $config_host_mak echo "SPHINX_WERROR=$sphinx_werror" >> $config_host_mak echo "GENISOIMAGE=$genisoimage" >> $config_host_mak +echo "EFI_AARCH64=$efi_aarch64" >> $config_host_mak echo "PYTHON_YAML=$python_yaml" >> $config_host_mak echo "CC=$cc" >> $config_host_mak if $iasl -h > /dev/null 2>&1; then diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include index f6c3892bb2..4fa292765d 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -5,6 +5,9 @@ IMAGES := freebsd netbsd openbsd centos fedora ifneq ($(GENISOIMAGE),) IMAGES += ubuntu.i386 centos +ifneq ($(EFI_AARCH64),) +IMAGES += ubuntu.aarch64 +endif endif IMAGES_DIR := $(HOME)/.cache/qemu-vm/images @@ -23,6 +26,11 @@ vm-help vm-test: ifneq ($(GENISOIMAGE),) @echo " vm-build-centos - Build QEMU in CentOS VM, with Docker" @echo " vm-build-ubuntu.i386 - Build QEMU in ubuntu i386 VM" +ifneq ($(EFI_AARCH64),) + @echo " vm-build-ubuntu.aarch64 - Build QEMU in ubuntu aarch64 VM" +else + @echo " (to build centos/ubuntu aarch64 images use configure --efi-aarch64)" +endif else @echo " (install genisoimage to build centos/ubuntu images)" endif @@ -65,6 +73,7 @@ $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \ $(if $(V)$(DEBUG), --debug) \ $(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ + $(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \ --image "$@" \ --force \ --build-image $@, \ @@ -80,6 +89,7 @@ vm-build-%: $(IMAGES_DIR)/%.img $(if $(J),--jobs $(J)) \ $(if $(V),--verbose) \ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ + $(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \ --image "$<" \ $(if $(BUILD_TARGET),--build-target $(BUILD_TARGET)) \ --snapshot \ @@ -102,6 +112,7 @@ vm-boot-ssh-%: $(IMAGES_DIR)/%.img $(if $(J),--jobs $(J)) \ $(if $(V)$(DEBUG), --debug) \ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ + $(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \ --image "$<" \ --interactive \ false, \ diff --git a/tests/vm/aarch64vm.py b/tests/vm/aarch64vm.py new file mode 100644 index 0000000000..bb04cb19c9 --- /dev/null +++ b/tests/vm/aarch64vm.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +# +# VM testing aarch64 library +# +# Copyright 2020 Linaro +# +# Authors: +# Robert Foley +# +# This code is licensed under the GPL version 2 or later. See +# the COPYING file in the top-level directory. +# +import os +import sys +import subprocess +import basevm +from qemu.accel import kvm_available + +# This is the config needed for current version of QEMU. +# This works for both kvm and tcg. +CURRENT_CONFIG = { + 'cpu' : "max", + 'machine' : "virt,gic-version=max", +} + +# The minimum minor version of QEMU we will support with aarch64 VMs is 3. +# QEMU versions less than 3 have various issues running these VMs. +QEMU_AARCH64_MIN_VERSION = 3 + +# The DEFAULT_CONFIG will default to a version of +# parameters that works for backwards compatibility. +DEFAULT_CONFIG = {'kvm' : {'cpu' : "host", + 'machine' : "virt,gic-version=host"}, + 'tcg' : {'cpu' : "cortex-a57", + 'machine' : "virt"}, +} + +def get_config_defaults(vmcls, default_config): + """Fetch the configuration defaults for this VM, + taking into consideration the defaults for + aarch64 first, followed by the defaults for this VM.""" + config = default_config + config.update(aarch_get_config_defaults(vmcls)) + return config + +def aarch_get_config_defaults(vmcls): + """Set the defaults for current version of QEMU.""" + config = CURRENT_CONFIG + args, argv = basevm.parse_args(vmcls) + qemu_path = basevm.get_qemu_path(vmcls.arch, args.build_path) + qemu_version = basevm.get_qemu_version(qemu_path) + if qemu_version < QEMU_AARCH64_MIN_VERSION: + error = "\nThis major version of QEMU {} is to old for aarch64 VMs.\n"\ + "The major version must be at least {}.\n"\ + "To continue with the current build of QEMU, "\ + "please restart with QEMU_LOCAL=1 .\n" + print(error.format(qemu_version, QEMU_AARCH64_MIN_VERSION)) + exit(1) + if qemu_version == QEMU_AARCH64_MIN_VERSION: + # We have an older version of QEMU, + # set the config values for backwards compatibility. + if kvm_available('aarch64'): + config.update(DEFAULT_CONFIG['kvm']) + else: + config.update(DEFAULT_CONFIG['tcg']) + return config + +def create_flash_images(flash_dir="./", efi_img=""): + """Creates the appropriate pflash files + for an aarch64 VM.""" + flash0_path = get_flash_path(flash_dir, "flash0") + flash1_path = get_flash_path(flash_dir, "flash1") + fd_null = open(os.devnull, 'w') + subprocess.check_call(["dd", "if=/dev/zero", "of={}".format(flash0_path), + "bs=1M", "count=64"], + stdout=fd_null, stderr=subprocess.STDOUT) + # A reliable way to get the QEMU EFI image is via an installed package or + # via the bios included with qemu. + if not os.path.exists(efi_img): + sys.stderr.write("*** efi argument is invalid ({})\n".format(efi_img)) + sys.stderr.write("*** please check --efi-aarch64 argument or "\ + "install qemu-efi-aarch64 package\n") + exit(3) + subprocess.check_call(["dd", "if={}".format(efi_img), + "of={}".format(flash0_path), + "conv=notrunc"], + stdout=fd_null, stderr=subprocess.STDOUT) + subprocess.check_call(["dd", "if=/dev/zero", + "of={}".format(flash1_path), + "bs=1M", "count=64"], + stdout=fd_null, stderr=subprocess.STDOUT) + fd_null.close() + +def get_pflash_args(flash_dir="./"): + """Returns a string that can be used to + boot qemu using the appropriate pflash files + for aarch64.""" + flash0_path = get_flash_path(flash_dir, "flash0") + flash1_path = get_flash_path(flash_dir, "flash1") + pflash_args_str = "-drive file={},format=raw,if=pflash "\ + "-drive file={},format=raw,if=pflash" + pflash_args = pflash_args_str.format(flash0_path, flash1_path) + return pflash_args.split(" ") + +def get_flash_path(flash_dir, name): + return os.path.join(flash_dir, "{}.img".format(name)) diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index f3a8fbbe34..53c35fadde 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -92,6 +92,7 @@ class BaseVM(object): self._guest = None self._genisoimage = args.genisoimage self._build_path = args.build_path + self._efi_aarch64 = args.efi_aarch64 # Allow input config to override defaults. self._config = DEFAULT_CONFIG.copy() if config != None: @@ -496,6 +497,14 @@ def get_qemu_path(arch, build_path=None): qemu_path = "qemu-system-" + arch return qemu_path +def get_qemu_version(qemu_path): + """Get the version number from the current QEMU, + and return the major number.""" + output = subprocess.check_output([qemu_path, '--version']) + version_line = output.decode("utf-8") + version_num = re.split(' |\(', version_line)[3].split('.')[0] + return int(version_num) + def parse_config(config, args): """ Parse yaml config and populate our config structure. The yaml config allows the user to override the @@ -573,6 +582,9 @@ def parse_args(vmcls): parser.add_option("--config", "-c", default=None, help="Provide config yaml for configuration. "\ "See config_example.yaml for example.") + parser.add_option("--efi-aarch64", + default="/usr/share/qemu-efi-aarch64/QEMU_EFI.fd", + help="Path to efi image for aarch64 VMs.") parser.disable_interspersed_args() return parser.parse_args() diff --git a/tests/vm/ubuntu.aarch64 b/tests/vm/ubuntu.aarch64 new file mode 100755 index 0000000000..21d454c27f --- /dev/null +++ b/tests/vm/ubuntu.aarch64 @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# +# Ubuntu aarch64 image +# +# Copyright 2020 Linaro +# +# Authors: +# Robert Foley +# Originally based on ubuntu.i386 Fam Zheng +# +# This code is licensed under the GPL version 2 or later. See +# the COPYING file in the top-level directory. +# + +import sys +import basevm +import aarch64vm +import ubuntuvm + +DEFAULT_CONFIG = { + 'cpu' : "cortex-a57", + 'machine' : "virt,gic-version=3", + 'install_cmds' : "apt-get update,"\ + "apt-get build-dep -y --arch-only qemu,"\ + "apt-get install -y libfdt-dev pkg-config language-pack-en", + # We increase beyond the default time since during boot + # it can take some time (many seconds) to log into the VM + # especially using softmmu. + 'ssh_timeout' : 60, +} + +class UbuntuAarch64VM(ubuntuvm.UbuntuVM): + name = "ubuntu.aarch64" + arch = "aarch64" + image_name = "ubuntu-18.04-server-cloudimg-arm64.img" + image_link = "https://cloud-images.ubuntu.com/releases/18.04/release/" + image_name + image_sha256="0fdcba761965735a8a903d8b88df8e47f156f48715c00508e4315c506d7d3cb1" + BUILD_SCRIPT = """ + set -e; + cd $(mktemp -d); + sudo chmod a+r /dev/vdb; + tar --checkpoint=.10 -xf /dev/vdb; + ./configure {configure_opts}; + make --output-sync {target} -j{jobs} {verbose}; + """ + def boot(self, img, extra_args=None): + aarch64vm.create_flash_images(self._tmpdir, self._efi_aarch64) + default_args = aarch64vm.get_pflash_args(self._tmpdir) + if extra_args: + extra_args.extend(default_args) + else: + extra_args = default_args + # We always add these performance tweaks + # because without them, we boot so slowly that we + # can time out finding the boot efi device. + if '-smp' not in extra_args and \ + '-smp' not in self._config['extra_args'] and \ + '-smp' not in self._args: + # Only add if not already there to give caller option to change it. + extra_args.extend(["-smp", "8"]) + + # We have overridden boot() since aarch64 has additional parameters. + # Call down to the base class method. + super(UbuntuAarch64VM, self).boot(img, extra_args=extra_args) + +if __name__ == "__main__": + defaults = aarch64vm.get_config_defaults(UbuntuAarch64VM, DEFAULT_CONFIG) + sys.exit(basevm.main(UbuntuAarch64VM, defaults)) From d322fe2daf1bd3572b7917f6beafbc1cfbfe50fe Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Wed, 1 Jul 2020 14:56:22 +0100 Subject: [PATCH 2172/2595] tests/vm: Added a new script for centos.aarch64. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit centos.aarch64 creates a CentOS 8 image. Also added a new kickstart script used to build the centos.aarch64 image. Signed-off-by: Robert Foley Reviewed-by: Peter Puhov Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200601211421.1277-7-robert.foley@linaro.org> Message-Id: <20200701135652.1366-11-alex.bennee@linaro.org> --- tests/vm/Makefile.include | 3 +- tests/vm/centos-8-aarch64.ks | 51 ++++++++ tests/vm/centos.aarch64 | 227 +++++++++++++++++++++++++++++++++++ 3 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 tests/vm/centos-8-aarch64.ks create mode 100755 tests/vm/centos.aarch64 diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include index 4fa292765d..39f918a430 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -6,7 +6,7 @@ IMAGES := freebsd netbsd openbsd centos fedora ifneq ($(GENISOIMAGE),) IMAGES += ubuntu.i386 centos ifneq ($(EFI_AARCH64),) -IMAGES += ubuntu.aarch64 +IMAGES += ubuntu.aarch64 centos.aarch64 endif endif @@ -28,6 +28,7 @@ ifneq ($(GENISOIMAGE),) @echo " vm-build-ubuntu.i386 - Build QEMU in ubuntu i386 VM" ifneq ($(EFI_AARCH64),) @echo " vm-build-ubuntu.aarch64 - Build QEMU in ubuntu aarch64 VM" + @echo " vm-build-centos.aarch64 - Build QEMU in CentOS aarch64 VM" else @echo " (to build centos/ubuntu aarch64 images use configure --efi-aarch64)" endif diff --git a/tests/vm/centos-8-aarch64.ks b/tests/vm/centos-8-aarch64.ks new file mode 100644 index 0000000000..fd6ebe4d49 --- /dev/null +++ b/tests/vm/centos-8-aarch64.ks @@ -0,0 +1,51 @@ +# CentOS aarch64 image kickstart file. +# This file is used by the CentOS installer to +# script the generation of the image. +# +# Copyright 2020 Linaro +# +ignoredisk --only-use=vda +# System bootloader configuration +bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=vda +autopart --type=plain +# Partition clearing information +clearpart --linux --initlabel --drives=vda +# Use text mode install +text +repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream +# Use CDROM installation media +cdrom +# Keyboard layouts +keyboard --vckeymap=us --xlayouts='' +# System language +lang en_US.UTF-8 + +# Network information +network --bootproto=dhcp --device=enp0s1 --onboot=off --ipv6=auto --no-activate +network --hostname=localhost.localdomain +# Run the Setup Agent on first boot +firstboot --enable +# Do not configure the X Window System +skipx +# System services +services --enabled="chronyd" +# System timezone +timezone America/New_York --isUtc + +# Shutdown after installation is complete. +shutdown + +%packages +@^server-product-environment +kexec-tools + +%end + +%addon com_redhat_kdump --enable --reserve-mb='auto' + +%end +%anaconda +pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty +pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok +pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty +%end diff --git a/tests/vm/centos.aarch64 b/tests/vm/centos.aarch64 new file mode 100755 index 0000000000..d5232ecdb8 --- /dev/null +++ b/tests/vm/centos.aarch64 @@ -0,0 +1,227 @@ +#!/usr/bin/env python3 +# +# Centos aarch64 image +# +# Copyright 2020 Linaro +# +# Authors: +# Robert Foley +# Originally based on ubuntu.aarch64 +# +# This code is licensed under the GPL version 2 or later. See +# the COPYING file in the top-level directory. +# + +import os +import sys +import subprocess +import basevm +import time +import traceback +import aarch64vm + +DEFAULT_CONFIG = { + 'cpu' : "max", + 'machine' : "virt,gic-version=max", + 'install_cmds' : "yum install -y make git python3 gcc gcc-c++ flex bison, "\ + "yum install -y glib2-devel pixman-devel zlib-devel, "\ + "yum install -y perl-Test-Harness, "\ + "alternatives --set python /usr/bin/python3, "\ + "sudo dnf config-manager "\ + "--add-repo=https://download.docker.com/linux/centos/docker-ce.repo,"\ + "sudo dnf install --nobest -y docker-ce.aarch64,"\ + "systemctl enable docker", + # We increase beyond the default time since during boot + # it can take some time (many seconds) to log into the VM. + 'ssh_timeout' : 60, +} + +class CentosAarch64VM(basevm.BaseVM): + name = "centos.aarch64" + arch = "aarch64" + login_prompt = "localhost login:" + prompt = '[root@localhost ~]#' + image_name = "CentOS-8-aarch64-1905-dvd1.iso" + image_link = "http://mirrors.usc.edu/pub/linux/distributions/centos/8.0.1905/isos/aarch64/" + image_link += image_name + BUILD_SCRIPT = """ + set -e; + cd $(mktemp -d); + sudo chmod a+r /dev/vdb; + tar --checkpoint=.10 -xf /dev/vdb; + ./configure {configure_opts}; + make --output-sync {target} -j{jobs} {verbose}; + """ + def set_key_perm(self): + """Set permissions properly on certain files to allow + ssh access.""" + self.console_wait_send(self.prompt, + "/usr/sbin/restorecon -R -v /root/.ssh\n") + self.console_wait_send(self.prompt, + "/usr/sbin/restorecon -R -v "\ + "/home/{}/.ssh\n".format(self._config["guest_user"])) + + def create_kickstart(self): + """Generate the kickstart file used to generate the centos image.""" + # Start with the template for the kickstart. + ks_file = "../tests/vm/centos-8-aarch64.ks" + subprocess.check_call("cp {} ./ks.cfg".format(ks_file), shell=True) + # Append the ssh keys to the kickstart file + # as the post processing phase of installation. + with open("ks.cfg", "a") as f: + # Add in the root pw and guest user. + rootpw = "rootpw --plaintext {}\n" + f.write(rootpw.format(self._config["root_pass"])) + add_user = "user --groups=wheel --name={} "\ + "--password={} --plaintext\n" + f.write(add_user.format(self._config["guest_user"], + self._config["guest_pass"])) + # Add the ssh keys. + f.write("%post --log=/root/ks-post.log\n") + f.write("mkdir -p /root/.ssh\n") + addkey = 'echo "{}" >> /root/.ssh/authorized_keys\n' + addkey_cmd = addkey.format(self._config["ssh_pub_key"]) + f.write(addkey_cmd) + f.write('mkdir -p /home/{}/.ssh\n'.format(self._config["guest_user"])) + addkey = 'echo "{}" >> /home/{}/.ssh/authorized_keys\n' + addkey_cmd = addkey.format(self._config["ssh_pub_key"], + self._config["guest_user"]) + f.write(addkey_cmd) + f.write("%end\n") + # Take our kickstart file and create an .iso from it. + # The .iso will be provided to qemu as we boot + # from the install dvd. + # Anaconda will recognize the label "OEMDRV" and will + # start the automated installation. + gen_iso_img = 'genisoimage -output ks.iso -volid "OEMDRV" ks.cfg' + subprocess.check_call(gen_iso_img, shell=True) + + def wait_for_shutdown(self): + """We wait for qemu to shutdown the VM and exit. + While this happens we display the console view + for easier debugging.""" + # The image creation is essentially done, + # so whether or not the wait is successful we want to + # wait for qemu to exit (the self.wait()) before we return. + try: + self.console_wait("reboot: Power down") + except Exception as e: + sys.stderr.write("Exception hit\n") + if isinstance(e, SystemExit) and e.code == 0: + return 0 + traceback.print_exc() + finally: + self.wait() + + def build_base_image(self, dest_img): + """Run through the centos installer to create + a base image with name dest_img.""" + # We create the temp image, and only rename + # to destination when we are done. + img = dest_img + ".tmp" + # Create an empty image. + # We will provide this as the install destination. + qemu_img_create = "qemu-img create {} 50G".format(img) + subprocess.check_call(qemu_img_create, shell=True) + + # Create our kickstart file to be fed to the installer. + self.create_kickstart() + # Boot the install dvd with the params as our ks.iso + os_img = self._download_with_cache(self.image_link) + dvd_iso = "centos-8-dvd.iso" + subprocess.check_call(["cp", "-f", os_img, dvd_iso]) + extra_args = "-cdrom ks.iso" + extra_args += " -drive file={},if=none,id=drive1,cache=writeback" + extra_args += " -device virtio-blk,drive=drive1,bootindex=1" + extra_args = extra_args.format(dvd_iso).split(" ") + self.boot(img, extra_args=extra_args) + self.console_wait_send("change the selection", "\n") + # We seem to need to hit esc (chr(27)) twice to abort the + # media check, which takes a long time. + # Waiting a bit seems to be more reliable before hitting esc. + self.console_wait("Checking") + time.sleep(5) + self.console_wait_send("Checking", chr(27)) + time.sleep(5) + self.console_wait_send("Checking", chr(27)) + print("Found Checking") + # Give sufficient time for the installer to create the image. + self.console_init(timeout=7200) + self.wait_for_shutdown() + os.rename(img, dest_img) + print("Done with base image build: {}".format(dest_img)) + + def check_create_base_img(self, img_base, img_dest): + """Create a base image using the installer. + We will use the base image if it exists. + This helps cut down on install time in case we + need to restart image creation, + since the base image creation can take a long time.""" + if not os.path.exists(img_base): + print("Generate new base image: {}".format(img_base)) + self.build_base_image(img_base); + else: + print("Use existing base image: {}".format(img_base)) + # Save a copy of the base image and copy it to dest. + # which we will use going forward. + subprocess.check_call(["cp", img_base, img_dest]) + + def boot(self, img, extra_args=None): + aarch64vm.create_flash_images(self._tmpdir, self._efi_aarch64) + default_args = aarch64vm.get_pflash_args(self._tmpdir) + if extra_args: + extra_args.extend(default_args) + else: + extra_args = default_args + # We always add these performance tweaks + # because without them, we boot so slowly that we + # can time out finding the boot efi device. + if '-smp' not in extra_args and \ + '-smp' not in self._config['extra_args'] and \ + '-smp' not in self._args: + # Only add if not already there to give caller option to change it. + extra_args.extend(["-smp", "8"]) + # We have overridden boot() since aarch64 has additional parameters. + # Call down to the base class method. + super(CentosAarch64VM, self).boot(img, extra_args=extra_args) + + def build_image(self, img): + img_tmp = img + ".tmp" + self.check_create_base_img(img + ".base", img_tmp) + + # Boot the new image for the first time to finish installation. + self.boot(img_tmp) + self.console_init() + self.console_wait_send(self.login_prompt, "root\n") + self.console_wait_send("Password:", + "{}\n".format(self._config["root_pass"])) + + self.set_key_perm() + self.console_wait_send(self.prompt, "rpm -q centos-release\n") + enable_adapter = "sed -i 's/ONBOOT=no/ONBOOT=yes/g'" \ + " /etc/sysconfig/network-scripts/ifcfg-enp0s1\n" + self.console_wait_send(self.prompt, enable_adapter) + self.console_wait_send(self.prompt, "ifup enp0s1\n") + self.console_wait_send(self.prompt, + 'echo "qemu ALL=(ALL) NOPASSWD:ALL" | '\ + 'sudo tee /etc/sudoers.d/qemu\n') + self.console_wait(self.prompt) + + # Rest of the commands we issue through ssh. + self.wait_ssh(wait_root=True) + + # If the user chooses *not* to do the second phase, + # then we will jump right to the graceful shutdown + if self._config['install_cmds'] != "": + install_cmds = self._config['install_cmds'].split(',') + for cmd in install_cmds: + self.ssh_root(cmd) + self.ssh_root("poweroff") + self.wait_for_shutdown() + os.rename(img_tmp, img) + print("image creation complete: {}".format(img)) + return 0 + +if __name__ == "__main__": + defaults = aarch64vm.get_config_defaults(CentosAarch64VM, DEFAULT_CONFIG) + sys.exit(basevm.main(CentosAarch64VM, defaults)) From df00168039c8a58db3c33456db2c00da51043ee2 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Wed, 1 Jul 2020 14:56:23 +0100 Subject: [PATCH 2173/2595] tests/vm: change scripts to use self._config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change converts existing scripts to using for example self.ROOT_PASS, to self._config['root_pass']. We made similar changes for GUEST_USER, and GUEST_PASS. This allows us also to remove the change in basevm.py, which adds __getattr__ for backwards compatibility. Signed-off-by: Robert Foley Reviewed-by: Peter Puhov Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200601211421.1277-8-robert.foley@linaro.org> Message-Id: <20200701135652.1366-12-alex.bennee@linaro.org> --- tests/vm/basevm.py | 11 ++--------- tests/vm/fedora | 17 +++++++++-------- tests/vm/freebsd | 16 ++++++++-------- tests/vm/netbsd | 19 ++++++++++--------- tests/vm/openbsd | 17 +++++++++-------- 5 files changed, 38 insertions(+), 42 deletions(-) diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 53c35fadde..15aec593e5 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -183,13 +183,6 @@ class BaseVM(object): self.console_init(timeout=timeout) self.console_wait(wait_string) - def __getattr__(self, name): - # Support direct access to config by key. - # for example, access self._config['cpu'] by self.cpu - if name.lower() in self._config.keys(): - return self._config[name.lower()] - return object.__getattribute__(self, name) - def _download_with_cache(self, url, sha256sum=None, sha512sum=None): def check_sha256sum(fname): if not sha256sum: @@ -239,13 +232,13 @@ class BaseVM(object): return r def ssh(self, *cmd): - return self._ssh_do(self.GUEST_USER, cmd, False) + return self._ssh_do(self._config["guest_user"], cmd, False) def ssh_root(self, *cmd): return self._ssh_do("root", cmd, False) def ssh_check(self, *cmd): - self._ssh_do(self.GUEST_USER, cmd, True) + self._ssh_do(self._config["guest_user"], cmd, True) def ssh_root_check(self, *cmd): self._ssh_do("root", cmd, True) diff --git a/tests/vm/fedora b/tests/vm/fedora index a9195670f4..b2b478fdbc 100755 --- a/tests/vm/fedora +++ b/tests/vm/fedora @@ -108,20 +108,20 @@ class FedoraVM(basevm.BaseVM): self.console_wait_send("7) [!] Root password", "7\n") self.console_wait("Password:") - self.console_send("%s\n" % self.ROOT_PASS) + self.console_send("%s\n" % self._config["root_pass"]) self.console_wait("Password (confirm):") - self.console_send("%s\n" % self.ROOT_PASS) + self.console_send("%s\n" % self._config["root_pass"]) self.console_wait_send("8) [ ] User creation", "8\n") self.console_wait_send("1) [ ] Create user", "1\n") self.console_wait_send("3) User name", "3\n") - self.console_wait_send("ENTER:", "%s\n" % self.GUEST_USER) + self.console_wait_send("ENTER:", "%s\n" % self._config["guest_user"]) self.console_wait_send("4) [ ] Use password", "4\n") self.console_wait_send("5) Password", "5\n") self.console_wait("Password:") - self.console_send("%s\n" % self.GUEST_PASS) + self.console_send("%s\n" % self._config["guest_pass"]) self.console_wait("Password (confirm):") - self.console_send("%s\n" % self.GUEST_PASS) + self.console_send("%s\n" % self._config["guest_pass"]) self.console_wait_send("7) Groups", "c\n") while True: @@ -139,7 +139,7 @@ class FedoraVM(basevm.BaseVM): if good: break time.sleep(10) - self.console_send("r\n" % self.GUEST_PASS) + self.console_send("r\n" % self._config["guest_pass"]) self.console_wait_send("'b' to begin install", "b\n") @@ -150,12 +150,13 @@ class FedoraVM(basevm.BaseVM): # setup qemu user prompt = " ~]$" - self.console_ssh_init(prompt, self.GUEST_USER, self.GUEST_PASS) + self.console_ssh_init(prompt, self._config["guest_user"], + self._config["guest_pass"]) self.console_wait_send(prompt, "exit\n") # setup root user prompt = " ~]#" - self.console_ssh_init(prompt, "root", self.ROOT_PASS) + self.console_ssh_init(prompt, "root", self._config["root_pass"]) self.console_sshd_config(prompt) # setup virtio-blk #1 (tarfile) diff --git a/tests/vm/freebsd b/tests/vm/freebsd index f87db2b126..29252fa4a6 100755 --- a/tests/vm/freebsd +++ b/tests/vm/freebsd @@ -113,9 +113,9 @@ class FreeBSDVM(basevm.BaseVM): # post-install configuration self.console_wait("New Password:") - self.console_send("%s\n" % self.ROOT_PASS) + self.console_send("%s\n" % self._config["root_pass"]) self.console_wait("Retype New Password:") - self.console_send("%s\n" % self.ROOT_PASS) + self.console_send("%s\n" % self._config["root_pass"]) self.console_wait_send("Network Configuration", "\n") self.console_wait_send("IPv4", "y") @@ -134,9 +134,9 @@ class FreeBSDVM(basevm.BaseVM): # qemu user self.console_wait_send("Add User Accounts", "y") self.console_wait("Username") - self.console_send("%s\n" % self.GUEST_USER) + self.console_send("%s\n" % self._config["guest_user"]) self.console_wait("Full name") - self.console_send("%s\n" % self.GUEST_USER) + self.console_send("%s\n" % self._config["guest_user"]) self.console_wait_send("Uid", "\n") self.console_wait_send("Login group", "\n") self.console_wait_send("Login group", "\n") @@ -148,9 +148,9 @@ class FreeBSDVM(basevm.BaseVM): self.console_wait_send("Use an empty password", "\n") self.console_wait_send("Use a random password", "\n") self.console_wait("Enter password:") - self.console_send("%s\n" % self.GUEST_PASS) + self.console_send("%s\n" % self._config["guest_pass"]) self.console_wait("Enter password again:") - self.console_send("%s\n" % self.GUEST_PASS) + self.console_send("%s\n" % self._config["guest_pass"]) self.console_wait_send("Lock out", "\n") self.console_wait_send("OK", "yes\n") self.console_wait_send("Add another user", "no\n") @@ -164,12 +164,12 @@ class FreeBSDVM(basevm.BaseVM): # setup qemu user prompt = "$" - self.console_ssh_init(prompt, self.GUEST_USER, self.GUEST_PASS) + self.console_ssh_init(prompt, self._config["guest_user"], self._config["guest_pass"]) self.console_wait_send(prompt, "exit\n") # setup root user prompt = "root@freebsd:~ #" - self.console_ssh_init(prompt, "root", self.ROOT_PASS) + self.console_ssh_init(prompt, "root", self._config["root_pass"]) self.console_sshd_config(prompt) # setup serial console diff --git a/tests/vm/netbsd b/tests/vm/netbsd index cdac502dad..2e87199211 100755 --- a/tests/vm/netbsd +++ b/tests/vm/netbsd @@ -120,24 +120,24 @@ class NetBSDVM(basevm.BaseVM): self.console_wait_send("d: Change root password", "d\n") self.console_wait_send("a: Yes", "a\n") self.console_wait("New password:") - self.console_send("%s\n" % self.ROOT_PASS) + self.console_send("%s\n" % self._config["root_pass"]) self.console_wait("New password:") - self.console_send("%s\n" % self.ROOT_PASS) + self.console_send("%s\n" % self._config["root_pass"]) self.console_wait("Retype new password:") - self.console_send("%s\n" % self.ROOT_PASS) + self.console_send("%s\n" % self._config["root_pass"]) self.console_wait_send("o: Add a user", "o\n") self.console_wait("username") - self.console_send("%s\n" % self.GUEST_USER) + self.console_send("%s\n" % self._config["guest_user"]) self.console_wait("to group wheel") self.console_wait_send("a: Yes", "a\n") self.console_wait_send("a: /bin/sh", "a\n") self.console_wait("New password:") - self.console_send("%s\n" % self.GUEST_PASS) + self.console_send("%s\n" % self._config["guest_pass"]) self.console_wait("New password:") - self.console_send("%s\n" % self.GUEST_PASS) + self.console_send("%s\n" % self._config["guest_pass"]) self.console_wait("Retype new password:") - self.console_send("%s\n" % self.GUEST_PASS) + self.console_send("%s\n" % self._config["guest_pass"]) self.console_wait_send("a: Configure network", "a\n") self.console_wait_send("a: vioif0", "a\n") @@ -170,12 +170,13 @@ class NetBSDVM(basevm.BaseVM): # setup qemu user prompt = "localhost$" - self.console_ssh_init(prompt, self.GUEST_USER, self.GUEST_PASS) + self.console_ssh_init(prompt, self._config["guest_user"], + self._config["guest_pass"]) self.console_wait_send(prompt, "exit\n") # setup root user prompt = "localhost#" - self.console_ssh_init(prompt, "root", self.ROOT_PASS) + self.console_ssh_init(prompt, "root", self._config["root_pass"]) self.console_sshd_config(prompt) # setup virtio-blk #1 (tarfile) diff --git a/tests/vm/openbsd b/tests/vm/openbsd index 13e7f9a6d5..dfe633e453 100755 --- a/tests/vm/openbsd +++ b/tests/vm/openbsd @@ -98,9 +98,9 @@ class OpenBSDVM(basevm.BaseVM): self.console_wait_send("Which network interface", "done\n") self.console_wait_send("DNS domain name", "localnet\n") self.console_wait("Password for root account") - self.console_send("%s\n" % self.ROOT_PASS) + self.console_send("%s\n" % self._config["root_pass"]) self.console_wait("Password for root account") - self.console_send("%s\n" % self.ROOT_PASS) + self.console_send("%s\n" % self._config["root_pass"]) self.console_wait_send("Start sshd(8)", "yes\n") self.console_wait_send("X Window System", "\n") self.console_wait_send("xenodm", "\n") @@ -108,13 +108,13 @@ class OpenBSDVM(basevm.BaseVM): self.console_wait_send("Which speed", "\n") self.console_wait("Setup a user") - self.console_send("%s\n" % self.GUEST_USER) + self.console_send("%s\n" % self._config["guest_user"]) self.console_wait("Full name") - self.console_send("%s\n" % self.GUEST_USER) + self.console_send("%s\n" % self._config["guest_user"]) self.console_wait("Password") - self.console_send("%s\n" % self.GUEST_PASS) + self.console_send("%s\n" % self._config["guest_pass"]) self.console_wait("Password") - self.console_send("%s\n" % self.GUEST_PASS) + self.console_send("%s\n" % self._config["guest_pass"]) self.console_wait_send("Allow root ssh login", "yes\n") self.console_wait_send("timezone", "UTC\n") @@ -135,12 +135,13 @@ class OpenBSDVM(basevm.BaseVM): # setup qemu user prompt = "$" - self.console_ssh_init(prompt, self.GUEST_USER, self.GUEST_PASS) + self.console_ssh_init(prompt, self._config["guest_user"], + self._config["guest_pass"]) self.console_wait_send(prompt, "exit\n") # setup root user prompt = "openbsd#" - self.console_ssh_init(prompt, "root", self.ROOT_PASS) + self.console_ssh_init(prompt, "root", self._config["root_pass"]) self.console_sshd_config(prompt) # setup virtio-blk #1 (tarfile) From 0fc8f660c5c0d7b4513805f4798e97e4c371e486 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Wed, 1 Jul 2020 14:56:24 +0100 Subject: [PATCH 2174/2595] python/qemu: Add ConsoleSocket for optional use in QEMUMachine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We add the ConsoleSocket object, which has a socket interface and which will consume all arriving characters on the socket, placing them into an in memory buffer. This will also provide those chars via recv() as would a regular socket. ConsoleSocket also has the option of dumping the console bytes to a log file. We also give QEMUMachine the option of using ConsoleSocket to drain and to use for logging console to a file. By default QEMUMachine does not use ConsoleSocket. This is added in preparation for use by basevm.py in a later commit. This is a workaround we found was needed for basevm.py since there is a known issue where QEMU will hang waiting for console characters to be consumed. Cc: Eduardo Habkost Cc: Cleber Rosa Signed-off-by: Robert Foley Reviewed-by: Peter Puhov Acked-by: Alex Bennée Tested-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200601211421.1277-9-robert.foley@linaro.org> Message-Id: <20200701135652.1366-13-alex.bennee@linaro.org> --- python/qemu/console_socket.py | 110 ++++++++++++++++++++++++++++++++++ python/qemu/machine.py | 23 +++++-- 2 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 python/qemu/console_socket.py diff --git a/python/qemu/console_socket.py b/python/qemu/console_socket.py new file mode 100644 index 0000000000..830cb7c628 --- /dev/null +++ b/python/qemu/console_socket.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +# +# This python module implements a ConsoleSocket object which is +# designed always drain the socket itself, and place +# the bytes into a in memory buffer for later processing. +# +# Optionally a file path can be passed in and we will also +# dump the characters to this file for debug. +# +# Copyright 2020 Linaro +# +# Authors: +# Robert Foley +# +# This code is licensed under the GPL version 2 or later. See +# the COPYING file in the top-level directory. +# +import asyncore +import socket +import threading +import io +import os +import sys +from collections import deque +import time +import traceback + +class ConsoleSocket(asyncore.dispatcher): + + def __init__(self, address, file=None): + self._recv_timeout_sec = 300 + self._buffer = deque() + self._asyncore_thread = None + self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self._sock.connect(address) + self._logfile = None + if file: + self._logfile = open(file, "w") + asyncore.dispatcher.__init__(self, sock=self._sock) + self._open = True + self._thread_start() + + def _thread_start(self): + """Kick off a thread to wait on the asyncore.loop""" + if self._asyncore_thread is not None: + return + self._asyncore_thread = threading.Thread(target=asyncore.loop, + kwargs={'timeout':1}) + self._asyncore_thread.daemon = True + self._asyncore_thread.start() + + def handle_close(self): + """redirect close to base class""" + # Call the base class close, but not self.close() since + # handle_close() occurs in the context of the thread which + # self.close() attempts to join. + asyncore.dispatcher.close(self) + + def close(self): + """Close the base object and wait for the thread to terminate""" + if self._open: + self._open = False + asyncore.dispatcher.close(self) + if self._asyncore_thread is not None: + thread, self._asyncore_thread = self._asyncore_thread, None + thread.join() + if self._logfile: + self._logfile.close() + self._logfile = None + + def handle_read(self): + """process arriving characters into in memory _buffer""" + try: + data = asyncore.dispatcher.recv(self, 1) + # latin1 is needed since there are some chars + # we are receiving that cannot be encoded to utf-8 + # such as 0xe2, 0x80, 0xA6. + string = data.decode("latin1") + except: + print("Exception seen.") + traceback.print_exc() + return + if self._logfile: + self._logfile.write("{}".format(string)) + self._logfile.flush() + for c in string: + self._buffer.extend(c) + + def recv(self, n=1, sleep_delay_s=0.1): + """Return chars from in memory buffer""" + start_time = time.time() + while len(self._buffer) < n: + time.sleep(sleep_delay_s) + elapsed_sec = time.time() - start_time + if elapsed_sec > self._recv_timeout_sec: + raise socket.timeout + chars = ''.join([self._buffer.popleft() for i in range(n)]) + # We choose to use latin1 to remain consistent with + # handle_read() and give back the same data as the user would + # receive if they were reading directly from the + # socket w/o our intervention. + return chars.encode("latin1") + + def set_blocking(self): + """Maintain compatibility with socket API""" + pass + + def settimeout(self, seconds): + """Set current timeout on recv""" + self._recv_timeout_sec = seconds diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 041c615052..c25f0b42cf 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -26,6 +26,7 @@ import socket import tempfile from typing import Optional, Type from types import TracebackType +from qemu.console_socket import ConsoleSocket from . import qmp @@ -75,7 +76,8 @@ class QEMUMachine: def __init__(self, binary, args=None, wrapper=None, name=None, test_dir="/var/tmp", monitor_address=None, - socket_scm_helper=None, sock_dir=None): + socket_scm_helper=None, sock_dir=None, + drain_console=False, console_log=None): ''' Initialize a QEMUMachine @@ -86,6 +88,9 @@ class QEMUMachine: @param test_dir: where to create socket and log file @param monitor_address: address for QMP monitor @param socket_scm_helper: helper program, required for send_fd_scm() + @param sock_dir: where to create socket (overrides test_dir for sock) + @param console_log: (optional) path to console log file + @param drain_console: (optional) True to drain console socket to buffer @note: Qemu process is not started until launch() is used. ''' if args is None: @@ -122,6 +127,12 @@ class QEMUMachine: self._console_address = None self._console_socket = None self._remove_files = [] + self._console_log_path = console_log + if self._console_log_path: + # In order to log the console, buffering needs to be enabled. + self._drain_console = True + else: + self._drain_console = drain_console def __enter__(self): return self @@ -580,7 +591,11 @@ class QEMUMachine: Returns a socket connected to the console """ if self._console_socket is None: - self._console_socket = socket.socket(socket.AF_UNIX, - socket.SOCK_STREAM) - self._console_socket.connect(self._console_address) + if self._drain_console: + self._console_socket = ConsoleSocket(self._console_address, + file=self._console_log_path) + else: + self._console_socket = socket.socket(socket.AF_UNIX, + socket.SOCK_STREAM) + self._console_socket.connect(self._console_address) return self._console_socket From ff14ab0c13ee470f8f3fdcdea14104cef3d9fe2f Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Wed, 1 Jul 2020 14:56:25 +0100 Subject: [PATCH 2175/2595] tests/vm: Add workaround to consume console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support to basevm.py so that we always drain the console chars. This makes use of support added in an earlier commit that allows QEMUMachine to use the ConsoleSocket. This is a workaround we found was needed since there is a known issue where QEMU will hang waiting for console characters to be consumed. We also added the option of logging the console to a file. LOG_CONSOLE=1 will now log the output to a file. Signed-off-by: Robert Foley Reviewed-by: Peter Puhov Acked-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200601211421.1277-10-robert.foley@linaro.org> Message-Id: <20200701135652.1366-14-alex.bennee@linaro.org> --- tests/vm/Makefile.include | 4 ++++ tests/vm/basevm.py | 21 +++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include index 39f918a430..f21948c46a 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -49,6 +49,7 @@ endif @echo ' EXTRA_CONFIGURE_OPTS="..."' @echo " J=[0..9]* - Override the -jN parameter for make commands" @echo " DEBUG=1 - Enable verbose output on host and interactive debugging" + @echo " LOG_CONSOLE=1 - Log console to file in: ~/.cache/qemu-vm " @echo " V=1 - Enable verbose ouput on host and guest commands" @echo " QEMU_LOCAL=1 - Use QEMU binary local to this build." @echo " QEMU=/path/to/qemu - Change path to QEMU binary" @@ -75,6 +76,7 @@ $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \ $(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ $(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \ + $(if $(LOG_CONSOLE),--log-console) \ --image "$@" \ --force \ --build-image $@, \ @@ -91,6 +93,7 @@ vm-build-%: $(IMAGES_DIR)/%.img $(if $(V),--verbose) \ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ $(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \ + $(if $(LOG_CONSOLE),--log-console) \ --image "$<" \ $(if $(BUILD_TARGET),--build-target $(BUILD_TARGET)) \ --snapshot \ @@ -114,6 +117,7 @@ vm-boot-ssh-%: $(IMAGES_DIR)/%.img $(if $(V)$(DEBUG), --debug) \ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ $(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \ + $(if $(LOG_CONSOLE),--log-console) \ --image "$<" \ --interactive \ false, \ diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 15aec593e5..4c2878f022 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -117,6 +117,11 @@ class BaseVM(object): "w").write(self._config['ssh_pub_key']) self.debug = args.debug + self._console_log_path = None + if args.log_console: + self._console_log_path = \ + os.path.join(os.path.expanduser("~/.cache/qemu-vm"), + "{}.install.log".format(self.name)) self._stderr = sys.stderr self._devnull = open(os.devnull, "w") if self.debug: @@ -271,7 +276,13 @@ class BaseVM(object): args += self._data_args + extra_args + self._config['extra_args'] logging.debug("QEMU args: %s", " ".join(args)) qemu_path = get_qemu_path(self.arch, self._build_path) - guest = QEMUMachine(binary=qemu_path, args=args) + + # Since console_log_path is only set when the user provides the + # log_console option, we will set drain_console=True so the + # console is always drained. + guest = QEMUMachine(binary=qemu_path, args=args, + console_log=self._console_log_path, + drain_console=True) guest.set_machine(self._config['machine']) guest.set_console() try: @@ -285,6 +296,8 @@ class BaseVM(object): raise atexit.register(self.shutdown) self._guest = guest + # Init console so we can start consuming the chars. + self.console_init() usernet_info = guest.qmp("human-monitor-command", command_line="info usernet") self.ssh_port = None @@ -296,7 +309,9 @@ class BaseVM(object): raise Exception("Cannot find ssh port from 'info usernet':\n%s" % \ usernet_info) - def console_init(self, timeout = 120): + def console_init(self, timeout = None): + if timeout == None: + timeout = self.socket_timeout vm = self._guest vm.console_socket.settimeout(timeout) self.console_raw_path = os.path.join(vm._temp_dir, @@ -578,6 +593,8 @@ def parse_args(vmcls): parser.add_option("--efi-aarch64", default="/usr/share/qemu-efi-aarch64/QEMU_EFI.fd", help="Path to efi image for aarch64 VMs.") + parser.add_option("--log-console", action="store_true", + help="Log console to file.") parser.disable_interspersed_args() return parser.parse_args() From 2fea3a125dd8ff05c0a8d324573d31f24cc6d422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:26 +0100 Subject: [PATCH 2176/2595] tests/vm: switch from optsparse to argparse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit optparse has been deprecated since version 3.2 and argparse is the blessed replacement. Take the opportunity to enhance our help output showing defaults when called. Signed-off-by: Alex Bennée Reviewed-by: Daniel P. Berrangé Reviewed-by: Robert Foley Message-Id: <20200701135652.1366-15-alex.bennee@linaro.org> --- tests/vm/aarch64vm.py | 2 +- tests/vm/basevm.py | 93 ++++++++++++++++++++++--------------------- 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/tests/vm/aarch64vm.py b/tests/vm/aarch64vm.py index bb04cb19c9..d70ab843b6 100644 --- a/tests/vm/aarch64vm.py +++ b/tests/vm/aarch64vm.py @@ -46,7 +46,7 @@ def get_config_defaults(vmcls, default_config): def aarch_get_config_defaults(vmcls): """Set the defaults for current version of QEMU.""" config = CURRENT_CONFIG - args, argv = basevm.parse_args(vmcls) + args = basevm.parse_args(vmcls) qemu_path = basevm.get_qemu_path(vmcls.arch, args.build_path) qemu_version = basevm.get_qemu_version(qemu_path) if qemu_version < QEMU_AARCH64_MIN_VERSION: diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 4c2878f022..cc0809b6c7 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -23,7 +23,7 @@ from qemu.accel import kvm_available from qemu.machine import QEMUMachine import subprocess import hashlib -import optparse +import argparse import atexit import tempfile import shutil @@ -556,54 +556,57 @@ def parse_args(vmcls): else: return 1 - parser = optparse.OptionParser( - description="VM test utility. Exit codes: " - "0 = success, " - "1 = command line error, " - "2 = environment initialization failed, " - "3 = test command failed") - parser.add_option("--debug", "-D", action="store_true", - help="enable debug output") - parser.add_option("--image", "-i", default="%s.img" % vmcls.name, - help="image file name") - parser.add_option("--force", "-f", action="store_true", - help="force build image even if image exists") - parser.add_option("--jobs", type=int, default=get_default_jobs(), - help="number of virtual CPUs") - parser.add_option("--verbose", "-V", action="store_true", - help="Pass V=1 to builds within the guest") - parser.add_option("--build-image", "-b", action="store_true", - help="build image") - parser.add_option("--build-qemu", - help="build QEMU from source in guest") - parser.add_option("--build-target", - help="QEMU build target", default="check") - parser.add_option("--build-path", default=None, - help="Path of build directory, "\ - "for using build tree QEMU binary. ") - parser.add_option("--interactive", "-I", action="store_true", - help="Interactively run command") - parser.add_option("--snapshot", "-s", action="store_true", - help="run tests with a snapshot") - parser.add_option("--genisoimage", default="genisoimage", - help="iso imaging tool") - parser.add_option("--config", "-c", default=None, - help="Provide config yaml for configuration. "\ - "See config_example.yaml for example.") - parser.add_option("--efi-aarch64", - default="/usr/share/qemu-efi-aarch64/QEMU_EFI.fd", - help="Path to efi image for aarch64 VMs.") - parser.add_option("--log-console", action="store_true", - help="Log console to file.") - parser.disable_interspersed_args() + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + description="Utility for provisioning VMs and running builds", + epilog="""Remaining arguments are passed to the command. + Exit codes: 0 = success, 1 = command line error, + 2 = environment initialization failed, + 3 = test command failed""") + parser.add_argument("--debug", "-D", action="store_true", + help="enable debug output") + parser.add_argument("--image", "-i", default="%s.img" % vmcls.name, + help="image file name") + parser.add_argument("--force", "-f", action="store_true", + help="force build image even if image exists") + parser.add_argument("--jobs", type=int, default=get_default_jobs(), + help="number of virtual CPUs") + parser.add_argument("--verbose", "-V", action="store_true", + help="Pass V=1 to builds within the guest") + parser.add_argument("--build-image", "-b", action="store_true", + help="build image") + parser.add_argument("--build-qemu", + help="build QEMU from source in guest") + parser.add_argument("--build-target", + help="QEMU build target", default="check") + parser.add_argument("--build-path", default=None, + help="Path of build directory, "\ + "for using build tree QEMU binary. ") + parser.add_argument("--interactive", "-I", action="store_true", + help="Interactively run command") + parser.add_argument("--snapshot", "-s", action="store_true", + help="run tests with a snapshot") + parser.add_argument("--genisoimage", default="genisoimage", + help="iso imaging tool") + parser.add_argument("--config", "-c", default=None, + help="Provide config yaml for configuration. "\ + "See config_example.yaml for example.") + parser.add_argument("--efi-aarch64", + default="/usr/share/qemu-efi-aarch64/QEMU_EFI.fd", + help="Path to efi image for aarch64 VMs.") + parser.add_argument("--log-console", action="store_true", + help="Log console to file.") + parser.add_argument("commands", nargs="*", help="""Remaining + commands after -- are passed to command inside the VM""") + return parser.parse_args() def main(vmcls, config=None): try: if config == None: config = DEFAULT_CONFIG - args, argv = parse_args(vmcls) - if not argv and not args.build_qemu and not args.build_image: + args = parse_args(vmcls) + if not args.commands and not args.build_qemu and not args.build_image: print("Nothing to do?") return 1 config = parse_config(config, args) @@ -619,12 +622,12 @@ def main(vmcls, config=None): if args.build_qemu: vm.add_source_dir(args.build_qemu) cmd = [vm.BUILD_SCRIPT.format( - configure_opts = " ".join(argv), + configure_opts = " ".join(args.commands), jobs=int(args.jobs), target=args.build_target, verbose = "V=1" if args.verbose else "")] else: - cmd = argv + cmd = args.commands img = args.image if args.snapshot: img += ",snapshot=on" From b09539444a4b319b02043638682867ad02b1f47e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:27 +0100 Subject: [PATCH 2177/2595] tests/vm: allow us to take advantage of MTTCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently limit TCG guests to -smp 1 but now we have added some aarch64 guests we can do better when running on x86_64 hardware. Raise the limit for TCG guests when it is safe to do so. Signed-off-by: Alex Bennée Reviewed-by: Robert Foley Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200701135652.1366-16-alex.bennee@linaro.org> --- tests/vm/basevm.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index cc0809b6c7..7acb48b876 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -551,8 +551,15 @@ def parse_config(config, args): def parse_args(vmcls): def get_default_jobs(): - if kvm_available(vmcls.arch): - return multiprocessing.cpu_count() // 2 + if multiprocessing.cpu_count() > 1: + if kvm_available(vmcls.arch): + return multiprocessing.cpu_count() // 2 + elif os.uname().machine == "x86_64" and \ + vmcls.arch in ["aarch64", "x86_64", "i386"]: + # MTTCG is available on these arches and we can allow + # more cores. but only up to a reasonable limit. User + # can always override these limits with --jobs. + return min(multiprocessing.cpu_count() // 2, 8) else: return 1 From 10c927dcc5075c317187fa525021af5d6a1f511e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:28 +0100 Subject: [PATCH 2178/2595] tests/docker: check for an parameters not empty string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Suggested-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200701135652.1366-17-alex.bennee@linaro.org> --- tests/docker/common.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docker/common.rc b/tests/docker/common.rc index 02cd67a8c5..ebc5b97ecf 100755 --- a/tests/docker/common.rc +++ b/tests/docker/common.rc @@ -47,7 +47,7 @@ build_qemu() check_qemu() { # default to make check unless the caller specifies - if test -z "$@"; then + if [ $# = 0 ]; then INVOCATION="check" else INVOCATION="$@" From 767b6bd22bc94287e88367dc4ec5c7f9a765c603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:29 +0100 Subject: [PATCH 2179/2595] tests/docker: change tag naming scheme of our images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We've been misusing the tag naming scheme for some time by overloading the post : section with the image type. Really it should be saved for the revision of that particular build. Move the details to the other side so we have: qemu/image-name with the implied :latest version added by the tooling. Suggested-by: Daniel P. Berrangé Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200701135652.1366-18-alex.bennee@linaro.org> --- .shippable.yml | 4 ++-- tests/docker/Makefile.include | 10 +++++----- tests/docker/docker.py | 2 +- tests/docker/dockerfiles/debian-alpha-cross.docker | 2 +- tests/docker/dockerfiles/debian-amd64-cross.docker | 2 +- tests/docker/dockerfiles/debian-amd64.docker | 2 +- tests/docker/dockerfiles/debian-arm64-cross.docker | 2 +- .../docker/dockerfiles/debian-arm64-test-cross.docker | 2 +- tests/docker/dockerfiles/debian-armel-cross.docker | 2 +- tests/docker/dockerfiles/debian-armhf-cross.docker | 2 +- tests/docker/dockerfiles/debian-hppa-cross.docker | 2 +- tests/docker/dockerfiles/debian-m68k-cross.docker | 2 +- tests/docker/dockerfiles/debian-mips-cross.docker | 2 +- tests/docker/dockerfiles/debian-mips64-cross.docker | 2 +- tests/docker/dockerfiles/debian-mips64el-cross.docker | 2 +- tests/docker/dockerfiles/debian-mipsel-cross.docker | 2 +- tests/docker/dockerfiles/debian-powerpc-cross.docker | 2 +- tests/docker/dockerfiles/debian-ppc64-cross.docker | 2 +- tests/docker/dockerfiles/debian-ppc64el-cross.docker | 2 +- tests/docker/dockerfiles/debian-riscv64-cross.docker | 2 +- tests/docker/dockerfiles/debian-s390x-cross.docker | 2 +- tests/docker/dockerfiles/debian-sh4-cross.docker | 2 +- tests/docker/dockerfiles/debian-sparc64-cross.docker | 2 +- tests/docker/dockerfiles/debian-tricore-cross.docker | 2 +- tests/docker/dockerfiles/debian-win32-cross.docker | 2 +- tests/docker/dockerfiles/debian-win64-cross.docker | 2 +- tests/docker/dockerfiles/debian9-mxe.docker | 2 +- tests/tcg/Makefile.qemu | 4 ++-- 28 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.shippable.yml b/.shippable.yml index 2cce7b5689..81905727d1 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -29,8 +29,8 @@ build: pre_ci: - make docker-image-${IMAGE} V=1 pre_ci_boot: - image_name: qemu - image_tag: ${IMAGE} + image_name: qemu/${IMAGE} + image_tag: latest pull: false options: "-e HOME=/root" ci: diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 3e3617816e..e23b4af20e 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -50,12 +50,12 @@ docker-image: ${DOCKER_TARGETS} ifdef SKIP_DOCKER_BUILD docker-image-%: $(DOCKER_FILES_DIR)/%.docker $(call quiet-command, \ - $(DOCKER_SCRIPT) check --quiet qemu:$* $<, \ + $(DOCKER_SCRIPT) check --quiet qemu/$* $<, \ "CHECK", "$*") else docker-image-%: $(DOCKER_FILES_DIR)/%.docker $(call quiet-command,\ - $(DOCKER_SCRIPT) build -t qemu:$* -f $< \ + $(DOCKER_SCRIPT) build -t qemu/$* -f $< \ $(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \ $(if $(NOUSER),,--add-current-user) \ $(if $(EXTRA_FILES),--extra-files $(EXTRA_FILES))\ @@ -75,14 +75,14 @@ docker-binfmt-image-debian-%: $(DOCKER_FILES_DIR)/debian-bootstrap.docker DEB_ARCH=$(DEB_ARCH) \ DEB_TYPE=$(DEB_TYPE) \ $(if $(DEB_URL),DEB_URL=$(DEB_URL),) \ - $(DOCKER_SCRIPT) build qemu:debian-$* $< \ + $(DOCKER_SCRIPT) build qemu/debian-$* $< \ $(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \ $(if $(NOUSER),,--add-current-user) \ $(if $(EXTRA_FILES),--extra-files $(EXTRA_FILES)) \ $(if $(EXECUTABLE),--include-executable=$(EXECUTABLE)), \ "BUILD","binfmt debian-$* (debootstrapped)"), \ $(call quiet-command, \ - $(DOCKER_SCRIPT) check --quiet qemu:debian-$* $< || \ + $(DOCKER_SCRIPT) check --quiet qemu/debian-$* $< || \ { echo "You will need to build $(EXECUTABLE)"; exit 1;},\ "CHECK", "debian-$* exists")) @@ -258,7 +258,7 @@ docker-run: docker-qemu-src docker-run-%: CMD = $(shell echo '$@' | sed -e 's/docker-run-\([^@]*\)@\(.*\)/\1/') docker-run-%: IMAGE = $(shell echo '$@' | sed -e 's/docker-run-\([^@]*\)@\(.*\)/\2/') docker-run-%: - @$(MAKE) docker-run TEST=$(CMD) IMAGE=qemu:$(IMAGE) + @$(MAKE) docker-run TEST=$(CMD) IMAGE=qemu/$(IMAGE) docker-clean: $(call quiet-command, $(DOCKER_SCRIPT) clean) diff --git a/tests/docker/docker.py b/tests/docker/docker.py index e630aae108..cc6f76caa6 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -204,7 +204,7 @@ def _dockerfile_preprocess(df): for l in df.splitlines(): if len(l.strip()) == 0 or l.startswith("#"): continue - from_pref = "FROM qemu:" + from_pref = "FROM qemu/" if l.startswith(from_pref): # TODO: Alternatively we could replace this line with "FROM $ID" # where $ID is the image's hex id obtained with diff --git a/tests/docker/dockerfiles/debian-alpha-cross.docker b/tests/docker/dockerfiles/debian-alpha-cross.docker index 74bcabfdb1..10fe30df0d 100644 --- a/tests/docker/dockerfiles/debian-alpha-cross.docker +++ b/tests/docker/dockerfiles/debian-alpha-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Buster base image. # -FROM qemu:debian10 +FROM qemu/debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker index 5d89041925..870109ef6a 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -4,7 +4,7 @@ # This docker target is used on non-x86_64 machines which need the # x86_64 cross compilers installed. # -FROM qemu:debian10 +FROM qemu/debian10 MAINTAINER Alex Bennée # Add the foreign architecture we want and install dependencies diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker index 957f0bc2e7..8fdfd6a6b0 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -4,7 +4,7 @@ # This docker target builds on the debian Stretch base image. Further # libraries which are not widely available are installed by hand. # -FROM qemu:debian10 +FROM qemu/debian10 MAINTAINER Philippe Mathieu-Daudé RUN apt update && \ diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index 09ca0a1ba7..166e24df13 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Buster base image. # -FROM qemu:debian10 +FROM qemu/debian10 # Add the foreign architecture we want and install dependencies RUN dpkg --add-architecture arm64 diff --git a/tests/docker/dockerfiles/debian-arm64-test-cross.docker b/tests/docker/dockerfiles/debian-arm64-test-cross.docker index a44e76d942..53a9012beb 100644 --- a/tests/docker/dockerfiles/debian-arm64-test-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-test-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Bullseye base image. # -FROM qemu:debian11 +FROM qemu/debian11 # Add the foreign architecture we want and install dependencies RUN dpkg --add-architecture arm64 diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker index e3794a61c9..b7b1a3585f 100644 --- a/tests/docker/dockerfiles/debian-armel-cross.docker +++ b/tests/docker/dockerfiles/debian-armel-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Stretch base image. # -FROM qemu:debian10 +FROM qemu/debian10 MAINTAINER Philippe Mathieu-Daudé # Add the foreign architecture we want and install dependencies diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index e163b8b956..25d7618833 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Stretch base image. # -FROM qemu:debian10 +FROM qemu/debian10 # Add the foreign architecture we want and install dependencies RUN dpkg --add-architecture armhf diff --git a/tests/docker/dockerfiles/debian-hppa-cross.docker b/tests/docker/dockerfiles/debian-hppa-cross.docker index 5c68b2d330..3d6c65a3ef 100644 --- a/tests/docker/dockerfiles/debian-hppa-cross.docker +++ b/tests/docker/dockerfiles/debian-hppa-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Buster base image. # -FROM qemu:debian10 +FROM qemu/debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-m68k-cross.docker b/tests/docker/dockerfiles/debian-m68k-cross.docker index 25edc80e9a..fcb10e3534 100644 --- a/tests/docker/dockerfiles/debian-m68k-cross.docker +++ b/tests/docker/dockerfiles/debian-m68k-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Buster base image. # -FROM qemu:debian10 +FROM qemu/debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-mips-cross.docker b/tests/docker/dockerfiles/debian-mips-cross.docker index 08a8e1c29c..26c154014d 100644 --- a/tests/docker/dockerfiles/debian-mips-cross.docker +++ b/tests/docker/dockerfiles/debian-mips-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Buster base image. # -FROM qemu:debian10 +FROM qemu/debian10 MAINTAINER Philippe Mathieu-Daudé diff --git a/tests/docker/dockerfiles/debian-mips64-cross.docker b/tests/docker/dockerfiles/debian-mips64-cross.docker index 1a79505d69..09c2ba584e 100644 --- a/tests/docker/dockerfiles/debian-mips64-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Buster base image. # -FROM qemu:debian10 +FROM qemu/debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker index 453b53ef72..c990b683b7 100644 --- a/tests/docker/dockerfiles/debian-mips64el-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker @@ -4,7 +4,7 @@ # This docker target builds on the debian Stretch base image. # -FROM qemu:debian10 +FROM qemu/debian10 MAINTAINER Philippe Mathieu-Daudé diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker index 3b6e975c68..0e5dd42d3c 100644 --- a/tests/docker/dockerfiles/debian-mipsel-cross.docker +++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Stretch base image. # -FROM qemu:debian10 +FROM qemu/debian10 MAINTAINER Philippe Mathieu-Daudé diff --git a/tests/docker/dockerfiles/debian-powerpc-cross.docker b/tests/docker/dockerfiles/debian-powerpc-cross.docker index 89dd4fbf87..07e1789650 100644 --- a/tests/docker/dockerfiles/debian-powerpc-cross.docker +++ b/tests/docker/dockerfiles/debian-powerpc-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Buster base image. # -FROM qemu:debian10 +FROM qemu/debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-ppc64-cross.docker b/tests/docker/dockerfiles/debian-ppc64-cross.docker index 4bf88ab02d..8efe68874e 100644 --- a/tests/docker/dockerfiles/debian-ppc64-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64-cross.docker @@ -2,7 +2,7 @@ # Docker ppc64 cross-compiler target # # This docker target builds on the debian Buster base image. -FROM qemu:debian10 +FROM qemu/debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index cd386f01d9..1146a06be6 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Stretch base image. # -FROM qemu:debian10 +FROM qemu/debian10 # Add the foreign architecture we want and install dependencies RUN dpkg --add-architecture ppc64el && \ diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker index 5e2d6ddb60..2bbff19772 100644 --- a/tests/docker/dockerfiles/debian-riscv64-cross.docker +++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Buster base image. # -FROM qemu:debian10 +FROM qemu/debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index 43fe59836f..9f2ab51eb0 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Stretch base image. # -FROM qemu:debian10 +FROM qemu/debian10 # Add the s390x architecture RUN dpkg --add-architecture s390x diff --git a/tests/docker/dockerfiles/debian-sh4-cross.docker b/tests/docker/dockerfiles/debian-sh4-cross.docker index 9d7663764e..fd3af89575 100644 --- a/tests/docker/dockerfiles/debian-sh4-cross.docker +++ b/tests/docker/dockerfiles/debian-sh4-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Buster base image. # -FROM qemu:debian10 +FROM qemu/debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-sparc64-cross.docker b/tests/docker/dockerfiles/debian-sparc64-cross.docker index 31fd34f120..f4bb9b561c 100644 --- a/tests/docker/dockerfiles/debian-sparc64-cross.docker +++ b/tests/docker/dockerfiles/debian-sparc64-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Buster base image. # -FROM qemu:debian10 +FROM qemu/debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker index 4a0f7706a3..769d95c77b 100644 --- a/tests/docker/dockerfiles/debian-tricore-cross.docker +++ b/tests/docker/dockerfiles/debian-tricore-cross.docker @@ -7,7 +7,7 @@ # # SPDX-License-Identifier: GPL-2.0-or-later # -FROM qemu:debian9 +FROM qemu/debian9 MAINTAINER Philippe Mathieu-Daudé diff --git a/tests/docker/dockerfiles/debian-win32-cross.docker b/tests/docker/dockerfiles/debian-win32-cross.docker index d16d6431bc..b045e821b9 100644 --- a/tests/docker/dockerfiles/debian-win32-cross.docker +++ b/tests/docker/dockerfiles/debian-win32-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Stretch MXE base image. # -FROM qemu:debian9-mxe +FROM qemu/debian9-mxe MAINTAINER Philippe Mathieu-Daudé diff --git a/tests/docker/dockerfiles/debian-win64-cross.docker b/tests/docker/dockerfiles/debian-win64-cross.docker index b0bc960445..2fc9cfcbc6 100644 --- a/tests/docker/dockerfiles/debian-win64-cross.docker +++ b/tests/docker/dockerfiles/debian-win64-cross.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Stretch MXE base image. # -FROM qemu:debian9-mxe +FROM qemu/debian9-mxe MAINTAINER Philippe Mathieu-Daudé diff --git a/tests/docker/dockerfiles/debian9-mxe.docker b/tests/docker/dockerfiles/debian9-mxe.docker index 62ff1cecf2..ae2c222a6f 100644 --- a/tests/docker/dockerfiles/debian9-mxe.docker +++ b/tests/docker/dockerfiles/debian9-mxe.docker @@ -3,7 +3,7 @@ # # This docker target builds on the debian Stretch base image. # -FROM qemu:debian9 +FROM qemu/debian9 MAINTAINER Philippe Mathieu-Daudé diff --git a/tests/tcg/Makefile.qemu b/tests/tcg/Makefile.qemu index 9c23aeaa2a..f8ad4c47be 100644 --- a/tests/tcg/Makefile.qemu +++ b/tests/tcg/Makefile.qemu @@ -47,7 +47,7 @@ ifneq ($(DOCKER_IMAGE),) DOCKER_COMPILE_CMD="$(DOCKER_SCRIPT) cc \ --cc $(DOCKER_CROSS_CC_GUEST) \ - -i qemu:$(DOCKER_IMAGE) \ + -i qemu/$(DOCKER_IMAGE) \ -s $(SRC_PATH) -- " .PHONY: docker-build-guest-tests @@ -57,7 +57,7 @@ docker-build-guest-tests: docker-image-$(DOCKER_IMAGE) $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" CC=$(DOCKER_COMPILE_CMD) \ SRC_PATH="$(SRC_PATH)" BUILD_STATIC=y \ EXTRA_CFLAGS="$(CROSS_CC_GUEST_CFLAGS)"), \ - "BUILD","$(TARGET) guest-tests with docker qemu:$(DOCKER_IMAGE)") + "BUILD","$(TARGET) guest-tests with docker qemu/$(DOCKER_IMAGE)") GUEST_BUILD=docker-build-guest-tests From 91f6ff72b66cf5038fa2700a4d4384685f077b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:30 +0100 Subject: [PATCH 2180/2595] .gitignore: un-ignore .gitlab-ci.d MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sooner we deprecate in-tree builds the sooner this mess of regexes can be thrown away. Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200701135652.1366-19-alex.bennee@linaro.org> --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 90acb4347d..2992d15931 100644 --- a/.gitignore +++ b/.gitignore @@ -93,6 +93,7 @@ *.tp *.vr *.d +!/.gitlab-ci.d !/scripts/qemu-guest-agent/fsfreeze-hook.d *.o .sdk From 5117ba25d2b8bf8e1217620b7446a5bf708a4027 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 1 Jul 2020 14:56:31 +0100 Subject: [PATCH 2181/2595] gitlab-ci: Fix the change rules after moving the YML files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The edk2.yml and opensbi.yml files have recently been moved/renamed, but the change has not been reflected in the rules in the YML files yet. Fixes: 922febe2af ("Move edk2 and opensbi YAML files to .gitlab-ci.d folder") Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Reviewed-by: Laszlo Ersek Message-Id: <20200625151627.24986-1-thuth@redhat.com> Message-Id: <20200701135652.1366-20-alex.bennee@linaro.org> --- .gitlab-ci.d/edk2.yml | 2 +- .gitlab-ci.d/opensbi.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.d/edk2.yml b/.gitlab-ci.d/edk2.yml index 088ba4b43a..a9990b7147 100644 --- a/.gitlab-ci.d/edk2.yml +++ b/.gitlab-ci.d/edk2.yml @@ -2,7 +2,7 @@ docker-edk2: stage: build rules: # Only run this job when the Dockerfile is modified - changes: - - .gitlab-ci-edk2.yml + - .gitlab-ci.d/edk2.yml - .gitlab-ci.d/edk2/Dockerfile when: always image: docker:19.03.1 diff --git a/.gitlab-ci.d/opensbi.yml b/.gitlab-ci.d/opensbi.yml index dd051c0124..6a1750784a 100644 --- a/.gitlab-ci.d/opensbi.yml +++ b/.gitlab-ci.d/opensbi.yml @@ -2,7 +2,7 @@ docker-opensbi: stage: build rules: # Only run this job when the Dockerfile is modified - changes: - - .gitlab-ci-opensbi.yml + - .gitlab-ci.d/opensbi.yml - .gitlab-ci.d/opensbi/Dockerfile when: always image: docker:19.03.1 From d0caa0a8813d474749f4cac4ed7029b142a82189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 1 Jul 2020 14:56:32 +0100 Subject: [PATCH 2182/2595] gitlab: introduce explicit "container" and "build" stages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If no stage is listed, jobs get put in an implicit "test" stage. Some jobs which create container images to be used by later stages are currently listed as in a "build" stages. Signed-off-by: Daniel P. Berrangé Acked-by: Laszlo Ersek Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200622153318.751107-2-berrange@redhat.com> Message-Id: <20200701135652.1366-21-alex.bennee@linaro.org> --- .gitlab-ci.d/edk2.yml | 3 ++- .gitlab-ci.d/opensbi.yml | 3 ++- .gitlab-ci.yml | 11 +++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.d/edk2.yml b/.gitlab-ci.d/edk2.yml index a9990b7147..e1e0452416 100644 --- a/.gitlab-ci.d/edk2.yml +++ b/.gitlab-ci.d/edk2.yml @@ -1,5 +1,5 @@ docker-edk2: - stage: build + stage: containers rules: # Only run this job when the Dockerfile is modified - changes: - .gitlab-ci.d/edk2.yml @@ -24,6 +24,7 @@ docker-edk2: - docker push $IMAGE_TAG build-edk2: + stage: build rules: # Only run this job when ... - changes: # ... roms/edk2/ is modified (submodule updated) - roms/edk2/* diff --git a/.gitlab-ci.d/opensbi.yml b/.gitlab-ci.d/opensbi.yml index 6a1750784a..62088ec5ec 100644 --- a/.gitlab-ci.d/opensbi.yml +++ b/.gitlab-ci.d/opensbi.yml @@ -1,5 +1,5 @@ docker-opensbi: - stage: build + stage: containers rules: # Only run this job when the Dockerfile is modified - changes: - .gitlab-ci.d/opensbi.yml @@ -24,6 +24,7 @@ docker-opensbi: - docker push $IMAGE_TAG build-opensbi: + stage: build rules: # Only run this job when ... - changes: # ... roms/opensbi/ is modified (submodule updated) - roms/opensbi/* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 349c77aa58..9fdc752ea6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,7 @@ +stages: + - containers + - build + include: - local: '/.gitlab-ci.d/edk2.yml' - local: '/.gitlab-ci.d/opensbi.yml' @@ -17,6 +21,7 @@ include: - JOBS=$(expr $(nproc) + 1) build-system1: + stage: build image: ubuntu:19.10 <<: *before_script_apt script: @@ -31,6 +36,7 @@ build-system1: - make -j"$JOBS" check build-system2: + stage: build image: fedora:latest <<: *before_script_dnf script: @@ -46,6 +52,7 @@ build-system2: - make -j"$JOBS" check build-disabled: + stage: build image: fedora:latest <<: *before_script_dnf script: @@ -62,6 +69,7 @@ build-disabled: - make -j"$JOBS" check-qtest SPEED=slow build-tcg-disabled: + stage: build image: centos:8 <<: *before_script_dnf script: @@ -82,6 +90,7 @@ build-tcg-disabled: 260 261 262 263 264 270 272 273 277 279 build-user: + stage: build <<: *before_script_apt script: - mkdir build @@ -92,6 +101,7 @@ build-user: - make run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user build-clang: + stage: build image: fedora:latest <<: *before_script_dnf script: @@ -106,6 +116,7 @@ build-clang: - make -j"$JOBS" check build-tci: + stage: build image: centos:8 <<: *before_script_dnf script: From fa821f23e14c4509bd1dc76b22635e2bbe111808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 1 Jul 2020 14:56:33 +0100 Subject: [PATCH 2183/2595] gitlab: build all container images during CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have a number of container images in tests/docker/dockerfiles that are intended to provide well defined environments for doing test builds. We want our CI system to use these containers too. This introduces builds of all of them as the first stage in the CI, so that the built containers are available for later build jobs. The containers are setup to use the GitLab container registry as the cache, so we only pay the penalty of the full build when the dockerfiles change. The main qemu-project/qemu repo is used as a second cache, so that users forking QEMU will see a fast turnaround time on their CI jobs. Signed-off-by: Daniel P. Berrangé Message-Id: <20200622153318.751107-3-berrange@redhat.com> [AJB: tweak the tag format] Signed-off-by: Alex Bennée Acked-by: Thomas Huth Message-Id: <20200701135652.1366-22-alex.bennee@linaro.org> --- .gitlab-ci.d/containers.yml | 245 ++++++++++++++++++++++++++++++++++++ .gitlab-ci.yml | 3 + 2 files changed, 248 insertions(+) create mode 100644 .gitlab-ci.d/containers.yml diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml new file mode 100644 index 0000000000..2afd01f1d1 --- /dev/null +++ b/.gitlab-ci.d/containers.yml @@ -0,0 +1,245 @@ +.container_job_template: &container_job_definition + image: docker:stable + stage: containers + services: + - docker:dind + before_script: + - export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest" + - export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/$NAME:latest" + - docker info + - docker login registry.gitlab.com -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" + script: + - docker pull "$TAG" || docker pull "$COMMON_TAG" || true + - sed -i -e "s,FROM qemu/,FROM $CI_REGISTRY_IMAGE/qemu/," tests/docker/dockerfiles/$NAME.docker + - docker build --cache-from "$TAG" --cache-from "$COMMON_TAG" --tag "$TAG" -f "tests/docker/dockerfiles/$NAME.docker" tests/docker/dockerfiles + - docker push "$TAG" + after_script: + - docker logout + +amd64-centos7-container: + <<: *container_job_definition + variables: + NAME: centos7 + +amd64-centos8-container: + <<: *container_job_definition + variables: + NAME: centos8 + +amd64-debian10-container: + <<: *container_job_definition + variables: + NAME: debian10 + +amd64-debian11-container: + <<: *container_job_definition + variables: + NAME: debian11 + +amd64-debian9-container: + <<: *container_job_definition + variables: + NAME: debian9 + +amd64-debian9-mxe-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian9-container'] + variables: + NAME: debian9-mxe + +alpha-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-alpha-cross + +amd64-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-amd64-cross + +amd64-debian-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-amd64 + +arm64-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-arm64-cross + +arm64-test-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian11-container'] + variables: + NAME: debian-arm64-test-cross + +armel-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-armel-cross + +armhf-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-armhf-cross + +hppa-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-hppa-cross + +m68k-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-m68k-cross + +mips64-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-mips64-cross + +mips64el-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-mips64el-cross + +mips-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-mips-cross + +mipsel-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-mipsel-cross + +powerpc-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-powerpc-cross + +ppc64-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-ppc64-cross + +ppc64el-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-ppc64el-cross + +riscv64-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-riscv64-cross + +s390x-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-s390x-cross + +sh4-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-sh4-cross + +sparc64-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-sparc64-cross + +tricore-debian-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian9-container'] + variables: + NAME: debian-tricore-cross + +win32-debian-cross-container: + <<: *container_job_definition + stage: containers-layer3 + needs: ['amd64-debian9-mxe-container'] + variables: + NAME: debian-win32-cross + +win64-debian-cross-container: + <<: *container_job_definition + stage: containers-layer3 + needs: ['amd64-debian9-mxe-container'] + variables: + NAME: debian-win64-cross + +xtensa-debian-cross-container: + <<: *container_job_definition + variables: + NAME: debian-xtensa-cross + +cris-fedora-cross-container: + <<: *container_job_definition + variables: + NAME: fedora-cris-cross + +amd64-fedora-container: + <<: *container_job_definition + variables: + NAME: fedora + +i386-fedora-cross-container: + <<: *container_job_definition + variables: + NAME: fedora-i386-cross + +amd64-ubuntu1804-container: + <<: *container_job_definition + variables: + NAME: ubuntu1804 + +amd64-ubuntu2004-container: + <<: *container_job_definition + variables: + NAME: ubuntu2004 + +amd64-ubuntu-container: + <<: *container_job_definition + variables: + NAME: ubuntu diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9fdc752ea6..72d688875f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,10 +1,13 @@ stages: - containers + - containers-layer2 + - containers-layer3 - build include: - local: '/.gitlab-ci.d/edk2.yml' - local: '/.gitlab-ci.d/opensbi.yml' + - local: '/.gitlab-ci.d/containers.yml' .update_apt_template: &before_script_apt before_script: From c962864f1de4078330d02a0b75029fd9b1db40a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 1 Jul 2020 14:56:34 +0100 Subject: [PATCH 2184/2595] gitlab: convert jobs to use custom built containers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we're building standard container images from dockerfiles in tests/docker/dockerfiles, we can convert the build jobs to use them. The key benefit of this is that a contributor can now more easily replicate the CI environment on their local machine. The container images are cached too, so we are not spending time waiting for the apt-get/dnf package installs to complete. Signed-off-by: Daniel P. Berrangé Message-Id: <20200622153318.751107-4-berrange@redhat.com> [AJB: tweak naming convention] Signed-off-by: Alex Bennée Acked-by: Thomas Huth Message-Id: <20200701135652.1366-23-alex.bennee@linaro.org> --- .gitlab-ci.yml | 187 +++++++++++++++++++++---------------------------- 1 file changed, 81 insertions(+), 106 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 72d688875f..a7abc55a5c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,133 +9,108 @@ include: - local: '/.gitlab-ci.d/opensbi.yml' - local: '/.gitlab-ci.d/containers.yml' -.update_apt_template: &before_script_apt - before_script: - - apt-get update -qq - - apt-get install -y -qq git gcc libglib2.0-dev libpixman-1-dev make - genisoimage - - JOBS=$(expr $(nproc) + 1) - -.update_dnf_template: &before_script_dnf - before_script: - - dnf update -y - - dnf install -y bzip2 diffutils gcc git genisoimage findutils glib2-devel - make python3 perl-podlators perl-Test-Harness pixman-devel zlib-devel - - JOBS=$(expr $(nproc) + 1) +.native_build_job_template: &native_build_job_definition + stage: build + image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest + before_script: + - JOBS=$(expr $(nproc) + 1) + script: + - mkdir build + - cd build + - if test -n "$TARGETS"; + then + ../configure --enable-werror $CONFIGURE_ARGS --target-list="$TARGETS" ; + else + ../configure --enable-werror $CONFIGURE_ARGS ; + fi + - make -j"$JOBS" + - make -j"$JOBS" $MAKE_CHECK_ARGS build-system1: - stage: build - image: ubuntu:19.10 - <<: *before_script_apt - script: - - apt-get install -y -qq libgtk-3-dev libvte-dev nettle-dev libcacard-dev - libusb-dev libvde-dev libspice-protocol-dev libgl1-mesa-dev libvdeplug-dev - - mkdir build - - cd build - - ../configure --enable-werror --target-list="aarch64-softmmu alpha-softmmu - cris-softmmu hppa-softmmu lm32-softmmu moxie-softmmu microblazeel-softmmu - mips64el-softmmu m68k-softmmu ppc-softmmu riscv64-softmmu sparc-softmmu" - - make -j"$JOBS" - - make -j"$JOBS" check + <<: *native_build_job_definition + variables: + IMAGE: ubuntu2004 + TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu lm32-softmmu + moxie-softmmu microblazeel-softmmu mips64el-softmmu m68k-softmmu ppc-softmmu + riscv64-softmmu sparc-softmmu + MAKE_CHECK_ARGS: check build-system2: - stage: build - image: fedora:latest - <<: *before_script_dnf - script: - - yum install -y SDL2-devel libgcrypt-devel brlapi-devel libaio-devel - libfdt-devel lzo-devel librdmacm-devel libibverbs-devel libibumad-devel - libzstd-devel - - mkdir build - - cd build - - ../configure --enable-werror --target-list="tricore-softmmu unicore32-softmmu - microblaze-softmmu mips-softmmu riscv32-softmmu s390x-softmmu sh4-softmmu - sparc64-softmmu x86_64-softmmu xtensa-softmmu nios2-softmmu or1k-softmmu" - - make -j"$JOBS" - - make -j"$JOBS" check + <<: *native_build_job_definition + variables: + IMAGE: fedora + TARGETS: tricore-softmmu unicore32-softmmu microblaze-softmmu mips-softmmu + riscv32-softmmu s390x-softmmu sh4-softmmu sparc64-softmmu x86_64-softmmu + xtensa-softmmu nios2-softmmu or1k-softmmu + MAKE_CHECK_ARGS: check build-disabled: - stage: build - image: fedora:latest - <<: *before_script_dnf - script: - - mkdir build - - cd build - - ../configure --enable-werror --disable-rdma --disable-slirp --disable-curl + <<: *native_build_job_definition + variables: + IMAGE: fedora + CONFIGURE_ARGS: --disable-rdma --disable-slirp --disable-curl --disable-capstone --disable-live-block-migration --disable-glusterfs --disable-replication --disable-coroutine-pool --disable-smartcard --disable-guest-agent --disable-curses --disable-libxml2 --disable-tpm --disable-qom-cast-debug --disable-spice --disable-vhost-vsock --disable-vhost-net --disable-vhost-crypto --disable-vhost-user - --target-list="i386-softmmu ppc64-softmmu mips64-softmmu i386-linux-user" - - make -j"$JOBS" - - make -j"$JOBS" check-qtest SPEED=slow + TARGETS: i386-softmmu ppc64-softmmu mips64-softmmu i386-linux-user + MAKE_CHECK_ARGS: check-qtest SPEED=slow build-tcg-disabled: - stage: build - image: centos:8 - <<: *before_script_dnf - script: - - dnf install -y clang gtk3-devel libusbx-devel libgcrypt-devel - - mkdir build - - cd build - - ../configure --cc=clang --enable-werror --disable-tcg --audio-drv-list="" - - make -j"$JOBS" - - make check-unit - - make check-qapi-schema - - cd tests/qemu-iotests/ - - ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048 + <<: *native_build_job_definition + variables: + IMAGE: centos8 + script: + - mkdir build + - cd build + - ../configure --disable-tcg --audio-drv-list="" + - make -j"$JOBS" + - make check-unit + - make check-qapi-schema + - cd tests/qemu-iotests/ + - ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048 052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163 170 171 183 184 192 194 197 208 215 221 222 226 227 236 253 277 - - ./check -qcow2 028 051 056 057 058 065 067 068 082 085 091 095 096 102 122 + - ./check -qcow2 028 051 056 057 058 065 067 068 082 085 091 095 096 102 122 124 132 139 142 144 145 151 152 155 157 165 194 196 197 200 202 208 209 215 216 218 222 227 234 246 247 248 250 254 255 257 258 260 261 262 263 264 270 272 273 277 279 build-user: - stage: build - <<: *before_script_apt - script: - - mkdir build - - cd build - - ../configure --enable-werror --disable-system --disable-guest-agent - --disable-capstone --disable-slirp --disable-fdt - - make -j"$JOBS" - - make run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user + <<: *native_build_job_definition + variables: + IMAGE: ubuntu2004 + CONFIGURE_ARGS: --disable-system --disable-guest-agent + --disable-capstone --disable-slirp --disable-fdt + MAKE_CHECK_ARGS: run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user build-clang: - stage: build - image: fedora:latest - <<: *before_script_dnf - script: - - yum install -y clang SDL2-devel libattr-devel libcap-ng-devel xfsprogs-devel - libiscsi-devel libnfs-devel libseccomp-devel gnutls-devel librbd-devel - - mkdir build - - cd build - - ../configure --cc=clang --cxx=clang++ --enable-werror - --target-list="alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu - ppc-softmmu s390x-softmmu x86_64-softmmu arm-linux-user" - - make -j"$JOBS" - - make -j"$JOBS" check + <<: *native_build_job_definition + variables: + IMAGE: fedora + CONFIGURE_ARGS: --cc=clang --cxx=clang++ + TARGETS: alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu + ppc-softmmu s390x-softmmu x86_64-softmmu arm-linux-user + MAKE_CHECK_ARGS: check build-tci: - stage: build - image: centos:8 - <<: *before_script_dnf - script: - - TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64" - - mkdir build - - cd build - - ../configure --enable-tcg-interpreter - --target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)" - - make -j"$JOBS" - - make run-tcg-tests-x86_64-softmmu - - make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test - - for tg in $TARGETS ; do - export QTEST_QEMU_BINARY="${tg}-softmmu/qemu-system-${tg}" ; - ./tests/qtest/boot-serial-test || exit 1 ; - ./tests/qtest/cdrom-test || exit 1 ; - done - - QTEST_QEMU_BINARY="x86_64-softmmu/qemu-system-x86_64" ./tests/qtest/pxe-test - - QTEST_QEMU_BINARY="s390x-softmmu/qemu-system-s390x" - ./tests/qtest/pxe-test -m slow + <<: *native_build_job_definition + variables: + IMAGE: fedora + script: + - TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64" + - mkdir build + - cd build + - ../configure --enable-tcg-interpreter + --target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)" + - make -j"$JOBS" + - make run-tcg-tests-x86_64-softmmu + - make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test + - for tg in $TARGETS ; do + export QTEST_QEMU_BINARY="${tg}-softmmu/qemu-system-${tg}" ; + ./tests/qtest/boot-serial-test || exit 1 ; + ./tests/qtest/cdrom-test || exit 1 ; + done + - QTEST_QEMU_BINARY="x86_64-softmmu/qemu-system-x86_64" ./tests/qtest/pxe-test + - QTEST_QEMU_BINARY="s390x-softmmu/qemu-system-s390x" ./tests/qtest/pxe-test -m slow From 8a8a50a95701994f6c4dc2c9afc66c2abdce1503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:35 +0100 Subject: [PATCH 2185/2595] gitlab: build containers with buildkit and metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the documentation to be able to use --cache-from for remote registries you need to enable both buildkit and inline the metadata. We want to do this to support pulling from gitlab when users build their local docker images. Signed-off-by: Alex Bennée Message-Id: <20200701135652.1366-24-alex.bennee@linaro.org> --- .gitlab-ci.d/containers.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index 2afd01f1d1..f353359fd8 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -11,7 +11,9 @@ script: - docker pull "$TAG" || docker pull "$COMMON_TAG" || true - sed -i -e "s,FROM qemu/,FROM $CI_REGISTRY_IMAGE/qemu/," tests/docker/dockerfiles/$NAME.docker - - docker build --cache-from "$TAG" --cache-from "$COMMON_TAG" --tag "$TAG" -f "tests/docker/dockerfiles/$NAME.docker" tests/docker/dockerfiles + - DOCKER_BUILDKIT=1 docker build --cache-from "$TAG" --cache-from "$COMMON_TAG" --tag "$TAG" + --build-arg BUILDKIT_INLINE_CACHE=1 + -f "tests/docker/dockerfiles/$NAME.docker" tests/docker/dockerfiles - docker push "$TAG" after_script: - docker logout From e6f1306b1003e2ce4e63c8e5dbe362d27fb8766c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:36 +0100 Subject: [PATCH 2186/2595] tests/docker: add --registry support to tooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to point the tools towards a registry from which they can grab pre-built layers instead of doing everything from scratch each time. To enable this we need to be using the DOCKER_BUILDKIT engine. Signed-off-by: Alex Bennée Message-Id: <20200701135652.1366-25-alex.bennee@linaro.org> --- tests/docker/Makefile.include | 6 ++++- tests/docker/docker.py | 44 ++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index e23b4af20e..a26177abc2 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -13,6 +13,7 @@ DOCKER_IMAGES := $(sort $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.doc 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 +DOCKER_REGISTRY := $(if $(REGISTRY),$(REGISTRY),registry.gitlab.com/qemu-project/qemu) DOCKER_TESTS := $(notdir $(shell \ find $(SRC_PATH)/tests/docker/ -name 'test-*' -type f)) @@ -56,7 +57,9 @@ else docker-image-%: $(DOCKER_FILES_DIR)/%.docker $(call quiet-command,\ $(DOCKER_SCRIPT) build -t qemu/$* -f $< \ - $(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \ + $(if $V,,--quiet) \ + $(if $(NOCACHE),--no-cache, \ + $(if $(DOCKER_REGISTRY),--registry $(DOCKER_REGISTRY))) \ $(if $(NOUSER),,--add-current-user) \ $(if $(EXTRA_FILES),--extra-files $(EXTRA_FILES))\ $(if $(EXECUTABLE),--include-executable=$(EXECUTABLE)),\ @@ -213,6 +216,7 @@ endif @echo ' Include extra files in image.' @echo ' ENGINE=auto/docker/podman' @echo ' Specify which container engine to run.' + @echo ' REGISTRY=url Cache builds from registry (default:$(DOCKER_REGISTRY))' # This rule if for directly running against an arbitrary docker target. # It is called by the expanded docker targets (e.g. make diff --git a/tests/docker/docker.py b/tests/docker/docker.py index cc6f76caa6..9684f07bde 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -221,6 +221,13 @@ class Docker(object): """ Running Docker commands """ def __init__(self): self._command = _guess_engine_command() + + if "docker" in self._command and "TRAVIS" not in os.environ: + os.environ["DOCKER_BUILDKIT"] = "1" + self._buildkit = True + else: + self._buildkit = False + self._instance = None atexit.register(self._kill_instances) signal.signal(signal.SIGTERM, self._kill_instances) @@ -289,10 +296,24 @@ class Docker(object): return labels.get("com.qemu.dockerfile-checksum", "") def build_image(self, tag, docker_dir, dockerfile, - quiet=True, user=False, argv=None, extra_files_cksum=[]): + quiet=True, user=False, argv=None, registry=None, + extra_files_cksum=[]): if argv is None: argv = [] + # pre-calculate the docker checksum before any + # substitutions we make for caching + checksum = _text_checksum(_dockerfile_preprocess(dockerfile)) + + if registry is not None: + dockerfile = dockerfile.replace("FROM qemu/", + "FROM %s/qemu/" % + (registry)) + # see if we can fetch a cache copy, may fail... + pull_args = ["pull", "%s/%s" % (registry, tag)] + self._do(pull_args, quiet=quiet) + + tmp_df = tempfile.NamedTemporaryFile(mode="w+t", encoding='utf-8', dir=docker_dir, suffix=".docker") @@ -306,15 +327,23 @@ class Docker(object): (uname, uid, uname)) tmp_df.write("\n") - tmp_df.write("LABEL com.qemu.dockerfile-checksum=%s" % - _text_checksum(_dockerfile_preprocess(dockerfile))) + tmp_df.write("LABEL com.qemu.dockerfile-checksum=%s" % (checksum)) for f, c in extra_files_cksum: tmp_df.write("LABEL com.qemu.%s-checksum=%s" % (f, c)) tmp_df.flush() - self._do_check(["build", "-t", tag, "-f", tmp_df.name] + argv + - [docker_dir], + build_args = ["build", "-t", tag, "-f", tmp_df.name] + if self._buildkit: + build_args += ["--build-arg", "BUILDKIT_INLINE_CACHE=1"] + + if registry is not None: + cache = "%s/%s" % (registry, tag) + build_args += ["--cache-from", cache] + build_args += argv + build_args += [docker_dir] + + self._do_check(build_args, quiet=quiet) def update_image(self, tag, tarball, quiet=True): @@ -403,6 +432,8 @@ class BuildCommand(SubCommand): parser.add_argument("--add-current-user", "-u", dest="user", action="store_true", help="Add the current user to image's passwd") + parser.add_argument("--registry", "-r", + help="cache from docker registry") parser.add_argument("-t", dest="tag", help="Image Tag") parser.add_argument("-f", dest="dockerfile", @@ -458,7 +489,8 @@ class BuildCommand(SubCommand): for k, v in os.environ.items() if k.lower() in FILTERED_ENV_NAMES] dkr.build_image(tag, docker_dir, dockerfile, - quiet=args.quiet, user=args.user, argv=argv, + quiet=args.quiet, user=args.user, + argv=argv, registry=args.registry, extra_files_cksum=cksum) rmtree(docker_dir) From cdc61815c7da72469514aa230414d22df6fc087d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:37 +0100 Subject: [PATCH 2187/2595] tests/docker: add packages needed for check-acceptance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need additional python packages to run check-acceptance. Add them to the docker images we will be using later. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20200701135652.1366-26-alex.bennee@linaro.org> --- tests/docker/dockerfiles/fedora.docker | 7 +++++++ tests/docker/dockerfiles/ubuntu2004.docker | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 798ddd2c3e..70b6186bd3 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -80,7 +80,12 @@ ENV PACKAGES \ pixman-devel \ python3 \ python3-PyYAML \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ python3-sphinx \ + python3-virtualenv \ rdma-core-devel \ SDL2-devel \ snappy-devel \ @@ -89,6 +94,8 @@ ENV PACKAGES \ systemd-devel \ systemtap-sdt-devel \ tar \ + tesseract \ + tesseract-langpack-eng \ texinfo \ usbredir-devel \ virglrenderer-devel \ diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index 6050ce7e8a..f7aac840bf 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -46,9 +46,17 @@ ENV PACKAGES flex bison \ libxen-dev \ libzstd-dev \ make \ - python3-yaml \ + python3-numpy \ + python3-opencv \ + python3-pil \ + python3-pip \ python3-sphinx \ + python3-venv \ + python3-yaml \ + rpm2cpio \ sparse \ + tesseract-ocr \ + tesseract-ocr-eng \ texinfo \ xfslibs-dev\ vim From 0f26d94ec9ec0dc71a778f162326287b1d32df8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:38 +0100 Subject: [PATCH 2188/2595] tests/acceptance: skip s390x_ccw_vrtio_tcg on GitLab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the test takes more the 900 seconds on GitLab and then times out. Running on Travis seems to be OK. Signed-off-by: Alex Bennée Message-Id: <20200701135652.1366-27-alex.bennee@linaro.org> --- tests/acceptance/boot_linux.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/acceptance/boot_linux.py b/tests/acceptance/boot_linux.py index 3aa57e88b0..0055dc7cee 100644 --- a/tests/acceptance/boot_linux.py +++ b/tests/acceptance/boot_linux.py @@ -20,6 +20,7 @@ from avocado.utils import network from avocado.utils import vmimage from avocado.utils import datadrainer from avocado.utils.path import find_command +from avocado import skipIf ACCEL_NOT_AVAILABLE_FMT = "%s accelerator does not seem to be available" KVM_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "KVM" @@ -220,6 +221,7 @@ class BootLinuxS390X(BootLinux): chksum = '4caaab5a434fd4d1079149a072fdc7891e354f834d355069ca982fdcaf5a122d' + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_s390_ccw_virtio_tcg(self): """ :avocado: tags=machine:s390-ccw-virtio From fcae60436f925d99436a3bc5dc83d034349ee26e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:39 +0100 Subject: [PATCH 2189/2595] tests/acceptance: fix dtb path for machine_rx_gdbsim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old path doesn't exist but the rx-virt.dtb file has the same checksum so lets use that. Signed-off-by: Alex Bennée Acked-by: Philippe Mathieu-Daudé Message-Id: <20200701135652.1366-28-alex.bennee@linaro.org> --- tests/acceptance/machine_rx_gdbsim.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/acceptance/machine_rx_gdbsim.py b/tests/acceptance/machine_rx_gdbsim.py index a44f2c87da..bff63e421d 100644 --- a/tests/acceptance/machine_rx_gdbsim.py +++ b/tests/acceptance/machine_rx_gdbsim.py @@ -50,7 +50,7 @@ class RxGdbSimMachine(Test): :avocado: tags=machine:gdbsim-r5f562n7 :avocado: tags=endian:little """ - dtb_url = ('https://acc.dl.osdn.jp/users/23/23887/rx-qemu.dtb') + dtb_url = ('https://acc.dl.osdn.jp/users/23/23887/rx-virt.dtb') dtb_hash = '7b4e4e2c71905da44e86ce47adee2210b026ac18' dtb_path = self.fetch_asset(dtb_url, asset_hash=dtb_hash) kernel_url = ('http://acc.dl.osdn.jp/users/23/23845/zImage') From 61bbce96fe4c8e3a2b7df5a67ba7dc6ba418e54b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:40 +0100 Subject: [PATCH 2190/2595] tests/acceptance: skip multicore mips_malta tests on GitLab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some reason these tests fail all the time on GitLab. I can re-create the hang around 3% of the time locally but it doesn't seem to be MTTCG related. For now skipIf on GITLAB_CI. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Cc: Aleksandar Markovic Message-Id: <20200701135652.1366-29-alex.bennee@linaro.org> --- tests/acceptance/machine_mips_malta.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/acceptance/machine_mips_malta.py b/tests/acceptance/machine_mips_malta.py index 92b4f28a11..7c9a4ee4d2 100644 --- a/tests/acceptance/machine_mips_malta.py +++ b/tests/acceptance/machine_mips_malta.py @@ -15,6 +15,7 @@ from avocado import skipUnless from avocado_qemu import Test from avocado_qemu import wait_for_console_pattern from avocado.utils import archive +from avocado import skipIf NUMPY_AVAILABLE = True @@ -99,6 +100,7 @@ class MaltaMachineFramebuffer(Test): """ self.do_test_i6400_framebuffer_logo(1) + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_mips_malta_i6400_framebuffer_logo_7cores(self): """ :avocado: tags=arch:mips64el @@ -108,6 +110,7 @@ class MaltaMachineFramebuffer(Test): """ self.do_test_i6400_framebuffer_logo(7) + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_mips_malta_i6400_framebuffer_logo_8cores(self): """ :avocado: tags=arch:mips64el From 3c1de3af46e43be709294f8f67c2b979f71b1657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:41 +0100 Subject: [PATCH 2191/2595] tests/acceptance: skip LinuxInitrd 2gib with v4.16 on GitLab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fails on GitLab but not when run locally on the same container image. It's very confusing. Signed-off-by: Alex Bennée Acked-by: Philippe Mathieu-Daudé Message-Id: <20200701135652.1366-30-alex.bennee@linaro.org> --- tests/acceptance/linux_initrd.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/acceptance/linux_initrd.py b/tests/acceptance/linux_initrd.py index a3e54d3fc9..a249e2f14a 100644 --- a/tests/acceptance/linux_initrd.py +++ b/tests/acceptance/linux_initrd.py @@ -8,10 +8,12 @@ # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. +import os import logging import tempfile from avocado_qemu import Test +from avocado import skipIf class LinuxInitrd(Test): @@ -51,6 +53,7 @@ class LinuxInitrd(Test): max_size + 1) self.assertRegex(self.vm.get_log(), expected_msg) + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_with_2gib_file_should_work_with_linux_v4_16(self): """ QEMU has supported up to 4 GiB initrd for recent kernel From c5008c76eef0531a901ddb2951a08e81165a4365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:42 +0100 Subject: [PATCH 2192/2595] gitlab: add acceptance testing to system builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As part of migrating things from Travis to GitLab add the acceptance tests. To do this: - rename system1 to system-ubuntu-main - rename system2 to system-fedora-misc - split into build/check/acceptance - remove -j from check stages - use artifacts to save build stage - add post acceptance template and use Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200701135652.1366-31-alex.bennee@linaro.org> --- .gitlab-ci.yml | 69 +++++++++++++++++++++++++++++-- .travis.yml | 23 ----------- tests/Makefile.include | 2 +- tests/acceptance/replay_kernel.py | 2 +- 4 files changed, 68 insertions(+), 28 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a7abc55a5c..93baf98232 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,8 +1,12 @@ +# Currently we have two build stages after our containers are built: +# - build (for traditional build and test or first stage build) +# - test (for test stages, using build artefacts from a build stage) stages: - containers - containers-layer2 - containers-layer3 - build + - test include: - local: '/.gitlab-ci.d/edk2.yml' @@ -24,26 +28,85 @@ include: ../configure --enable-werror $CONFIGURE_ARGS ; fi - make -j"$JOBS" - - make -j"$JOBS" $MAKE_CHECK_ARGS + - if test -n "$MAKE_CHECK_ARGS"; + then + make $MAKE_CHECK_ARGS ; + fi -build-system1: +.native_test_job_template: &native_test_job_definition + stage: test + image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest + script: + - cd build + - find . -type f -exec touch {} + + - make $MAKE_CHECK_ARGS + +.post_acceptance_template: &post_acceptance + after_script: + - cd build + - python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat + - du -chs $HOME/avocado/data/cache + +build-system-ubuntu-main: <<: *native_build_job_definition variables: IMAGE: ubuntu2004 TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu lm32-softmmu moxie-softmmu microblazeel-softmmu mips64el-softmmu m68k-softmmu ppc-softmmu riscv64-softmmu sparc-softmmu + artifacts: + paths: + - build + +check-system-ubuntu-main: + <<: *native_test_job_definition + needs: + - job: build-system-ubuntu-main + artifacts: true + variables: + IMAGE: ubuntu2004 MAKE_CHECK_ARGS: check -build-system2: +acceptance-system-ubuntu-main: + <<: *native_test_job_definition + needs: + - job: build-system-ubuntu-main + artifacts: true + variables: + IMAGE: ubuntu2004 + MAKE_CHECK_ARGS: check-acceptance + <<: *post_acceptance + +build-system-fedora-alt: <<: *native_build_job_definition variables: IMAGE: fedora TARGETS: tricore-softmmu unicore32-softmmu microblaze-softmmu mips-softmmu riscv32-softmmu s390x-softmmu sh4-softmmu sparc64-softmmu x86_64-softmmu xtensa-softmmu nios2-softmmu or1k-softmmu + artifacts: + paths: + - build + +check-system-fedora-alt: + <<: *native_test_job_definition + needs: + - job: build-system-fedora-alt + artifacts: true + variables: + IMAGE: fedora MAKE_CHECK_ARGS: check +acceptance-system-fedora-alt: + <<: *native_test_job_definition + needs: + - job: build-system-fedora-alt + artifacts: true + variables: + IMAGE: fedora + MAKE_CHECK_ARGS: check-acceptance + <<: *post_acceptance + build-disabled: <<: *native_build_job_definition variables: diff --git a/.travis.yml b/.travis.yml index 74158f741b..c24dfbe377 100644 --- a/.travis.yml +++ b/.travis.yml @@ -289,29 +289,6 @@ jobs: python: 3.6 - # Acceptance (Functional) tests - - name: "GCC check-acceptance" - dist: bionic - env: - - CONFIG="--enable-tools --target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sh4-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu" - - TEST_CMD="make check-acceptance" - - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-acceptance" - after_script: - - python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat - - du -chs $HOME/avocado/data/cache - addons: - apt: - packages: - - python3-pil - - python3-pip - - python3-numpy - - python3-opencv - - python3-venv - - rpm2cpio - - tesseract-ocr - - tesseract-ocr-eng - - # Using newer GCC with sanitizers - name: "GCC9 with sanitizers (softmmu)" addons: diff --git a/tests/Makefile.include b/tests/Makefile.include index 3f4448a20b..c316e0d664 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -944,7 +944,7 @@ check-acceptance: check-venv $(TESTS_RESULTS_DIR) get-vm-images --show=$(AVOCADO_SHOW) run --job-results-dir=$(TESTS_RESULTS_DIR) \ --filter-by-tags-include-empty --filter-by-tags-include-empty-key \ $(AVOCADO_TAGS) \ - --failfast=on tests/acceptance, \ + $(if $(GITLAB_CI),,--failfast=on) tests/acceptance, \ "AVOCADO", "tests/acceptance") # Consolidated targets diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py index 60621417dd..62d2db8c64 100644 --- a/tests/acceptance/replay_kernel.py +++ b/tests/acceptance/replay_kernel.py @@ -73,7 +73,7 @@ class ReplayKernel(LinuxKernelTest): logger = logging.getLogger('replay') logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1)) - @skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI') + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_x86_64_pc(self): """ :avocado: tags=arch:x86_64 From 634ef789f8eea104ec49ead116eb52a8fcaa48a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:43 +0100 Subject: [PATCH 2193/2595] tests/tcg: add more default compilers to configure.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were missing a bunch of compilers which we could use if they were locally installed. The defaults are based on Debian as they seem to be the best distro for well distributed cross-build compilers. Signed-off-by: Alex Bennée Message-Id: <20200701135652.1366-32-alex.bennee@linaro.org> --- tests/tcg/configure.sh | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh index 2326f97856..37e49736ca 100755 --- a/tests/tcg/configure.sh +++ b/tests/tcg/configure.sh @@ -46,20 +46,29 @@ fi : ${cross_cc_aarch64="aarch64-linux-gnu-gcc"} : ${cross_cc_aarch64_be="$cross_cc_aarch64"} : ${cross_cc_cflags_aarch64_be="-mbig-endian"} +: $(cross_cc_alpha="alpha-linux-gnu-gcc") : ${cross_cc_arm="arm-linux-gnueabihf-gcc"} : ${cross_cc_cflags_armeb="-mbig-endian"} +: ${cross_cc_hppa="hppa-linux-gnu-gcc"} : ${cross_cc_i386="i386-pc-linux-gnu-gcc"} : ${cross_cc_cflags_i386="-m32"} -: ${cross_cc_x86_64="x86_64-pc-linux-gnu-gcc"} -: ${cross_cc_cflags_x86_64="-m64"} +: ${cross_cc_m68k="m68k-linux-gnu-gcc"} +: $(cross_cc_mips64el="mips64el-linux-gnuabi64-gcc") +: $(cross_cc_mips64="mips64-linux-gnuabi64-gcc") +: $(cross_cc_mipsel="mipsel-linux-gnu-gcc") +: $(cross_cc_mips="mips-linux-gnu-gcc") : ${cross_cc_ppc="powerpc-linux-gnu-gcc"} : ${cross_cc_cflags_ppc="-m32"} -: ${cross_cc_ppc64="powerpc-linux-gnu-gcc"} -: ${cross_cc_cflags_ppc64="-m64"} +: ${cross_cc_ppc64="powerpc64-linux-gnu-gcc"} : ${cross_cc_ppc64le="powerpc64le-linux-gnu-gcc"} -: ${cross_cc_cflags_s390x="-m64"} +: $(cross_cc_riscv64="riscv64-linux-gnu-gcc") +: ${cross_cc_s390x="s390x-linux-gnu-gcc"} +: $(cross_cc_sh4="sh4-linux-gnu-gcc") : ${cross_cc_cflags_sparc="-m32 -mv8plus -mcpu=ultrasparc"} +: ${cross_cc_sparc64="sparc64-linux-gnu-gcc"} : ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"} +: ${cross_cc_x86_64="x86_64-pc-linux-gnu-gcc"} +: ${cross_cc_cflags_x86_64="-m64"} for target in $target_list; do arch=${target%%-*} From 27ebeda0c07dcc2e9eec98ed1f70115ffa1e3797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:44 +0100 Subject: [PATCH 2194/2595] tests/docker: add a linux-user testing focused image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We happily use all the cross images for both cross-building QEMU as well as building the linux-user tests. However calling docker from within docker seems not to work. As we can build in Debian anyway why not include an image that has all the compilers available for non-docker invocation. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200701135652.1366-33-alex.bennee@linaro.org> --- .gitlab-ci.d/containers.yml | 7 +++ tests/docker/Makefile.include | 1 + .../dockerfiles/debian-all-test-cross.docker | 53 +++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 tests/docker/dockerfiles/debian-all-test-cross.docker diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index f353359fd8..a7621c4204 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -64,6 +64,13 @@ amd64-debian-cross-container: variables: NAME: debian-amd64-cross +amd64-debian-user-cross-container: + <<: *container_job_definition + stage: containers-layer2 + needs: ['amd64-debian10-container'] + variables: + NAME: debian-all-test-cross + amd64-debian-container: <<: *container_job_definition stage: containers-layer2 diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index a26177abc2..a104e9df28 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -134,6 +134,7 @@ docker-image-travis: NOUSER=1 # Specialist build images, sometimes very limited tools docker-image-debian-tricore-cross: docker-image-debian9 +docker-image-debian-all-test-cross: docker-image-debian10 docker-image-debian-arm64-test-cross: docker-image-debian11 # These images may be good enough for building tests but not for test builds diff --git a/tests/docker/dockerfiles/debian-all-test-cross.docker b/tests/docker/dockerfiles/debian-all-test-cross.docker new file mode 100644 index 0000000000..dedcea58b4 --- /dev/null +++ b/tests/docker/dockerfiles/debian-all-test-cross.docker @@ -0,0 +1,53 @@ +# +# Docker all cross-compiler target (tests only) +# +# While the normal cross builds take care to setup proper multiarch +# build environments which can cross build QEMU this just installs the +# basic compilers for as many targets as possible. We shall use this +# to build and run linux-user tests on GitLab +# +FROM qemu/debian10 + +# What we need to build QEMU itself +RUN apt update && \ + DEBIAN_FRONTEND=noninteractive eatmydata \ + apt build-dep -yy qemu + +# Add the foreign architecture we want and install dependencies +RUN DEBIAN_FRONTEND=noninteractive eatmydata \ + apt install -y --no-install-recommends \ + gcc-aarch64-linux-gnu \ + libc6-dev-arm64-cross \ + gcc-alpha-linux-gnu \ + libc6.1-dev-alpha-cross \ + gcc-arm-linux-gnueabihf \ + libc6-dev-armhf-cross \ + gcc-hppa-linux-gnu \ + libc6-dev-hppa-cross \ + gcc-m68k-linux-gnu \ + libc6-dev-m68k-cross \ + gcc-mips-linux-gnu \ + libc6-dev-mips-cross \ + gcc-mips64-linux-gnuabi64 \ + libc6-dev-mips64-cross \ + gcc-mips64el-linux-gnuabi64 \ + libc6-dev-mips64el-cross \ + gcc-mipsel-linux-gnu \ + libc6-dev-mipsel-cross \ + gcc-powerpc-linux-gnu \ + libc6-dev-powerpc-cross \ + gcc-powerpc64-linux-gnu \ + libc6-dev-ppc64-cross \ + gcc-powerpc64le-linux-gnu \ + libc6-dev-ppc64el-cross \ + gcc-riscv64-linux-gnu \ + libc6-dev-riscv64-cross \ + gcc-s390x-linux-gnu \ + libc6-dev-s390x-cross \ + gcc-sh4-linux-gnu \ + libc6-dev-sh4-cross \ + gcc-sparc64-linux-gnu \ + libc6-dev-sparc64-cross + +ENV QEMU_CONFIGURE_OPTS --disable-system --disable-docs --disable-tools +ENV DEF_TARGET_LIST aarch64-linux-user,alpha-linux-user,arm-linux-user,hppa-linux-user,i386-linux-user,m68k-linux-user,mips-linux-user,mips64-linux-user,mips64el-linux-user,mipsel-linux-user,ppc-linux-user,ppc64-linux-user,ppc64le-linux-user,riscv64-linux-user,s390x-linux-user,sh4-linux-user,sparc64-linux-user From c1f6ad798c7bb328a6f387f2509bf86305383d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:45 +0100 Subject: [PATCH 2195/2595] linux-user/elfload: use MAP_FIXED_NOREPLACE in pgb_reserved_va MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Given we assert the requested address matches what we asked we should also make that clear in the mmap flags. Otherwise we see failures in the GitLab environment for some currently unknown but allowable reason. We use MAP_FIXED_NOREPLACE if we can so we don't just clobber an existing mapping. Also include the strerror string for a bit more info on failure. Signed-off-by: Alex Bennée Message-Id: <20200701135652.1366-34-alex.bennee@linaro.org> --- linux-user/elfload.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index b5cb21384a..7e7f642332 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2294,7 +2294,7 @@ static void pgb_dynamic(const char *image_name, long align) static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr, abi_ulong guest_hiaddr, long align) { - const int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE; + int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE; void *addr, *test; if (guest_hiaddr > reserved_va) { @@ -2307,15 +2307,19 @@ static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr, /* Widen the "image" to the entire reserved address space. */ pgb_static(image_name, 0, reserved_va, align); +#ifdef MAP_FIXED_NOREPLACE + flags |= MAP_FIXED_NOREPLACE; +#endif + /* Reserve the memory on the host. */ assert(guest_base != 0); test = g2h(0); addr = mmap(test, reserved_va, PROT_NONE, flags, -1, 0); if (addr == MAP_FAILED) { error_report("Unable to reserve 0x%lx bytes of virtual address " - "space for use as guest address space (check your " + "space (%s) for use as guest address space (check your " "virtual memory ulimit setting or reserve less " - "using -R option)", reserved_va); + "using -R option)", reserved_va, strerror(errno)); exit(EXIT_FAILURE); } assert(addr == test); From 62c902e03b166de71ae93afdd21c1f2028a53100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:46 +0100 Subject: [PATCH 2196/2595] gitlab: enable check-tcg for linux-user tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch to building in the new debian-all-test-cross image which has most of the cross compilers inline. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20200701135652.1366-35-alex.bennee@linaro.org> --- .gitlab-ci.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 93baf98232..257947853b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -143,10 +143,9 @@ build-tcg-disabled: build-user: <<: *native_build_job_definition variables: - IMAGE: ubuntu2004 - CONFIGURE_ARGS: --disable-system --disable-guest-agent - --disable-capstone --disable-slirp --disable-fdt - MAKE_CHECK_ARGS: run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user + IMAGE: debian-all-test-cross + CONFIGURE_ARGS: --disable-tools --disable-system + MAKE_CHECK_ARGS: check-tcg build-clang: <<: *native_build_job_definition From 6957fd98dc1b5c9501cb8e16d4b39d39a80a1820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:47 +0100 Subject: [PATCH 2197/2595] gitlab: add avocado asset caching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These can be quite big so lets cache them. I couldn't find any nots on ccache in the gitlab docs so I've just ignored it for now. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200701135652.1366-36-alex.bennee@linaro.org> --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 257947853b..13e9531724 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,6 +8,12 @@ stages: - build - test +# We assume GitLab has it's own caching set up for RPM/APT repositories so we +# just take care of avocado assets here. +cache: + paths: + - $HOME/avocado/data/cache + include: - local: '/.gitlab-ci.d/edk2.yml' - local: '/.gitlab-ci.d/opensbi.yml' From 3e7b80f84d4584dc3ed6a088cc914f2de6ed0796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 10 Jul 2020 08:07:19 +0200 Subject: [PATCH 2198/2595] tests: improve performance of device-introspect-test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Total execution time with "-m slow" and x86_64 QEMU, drops from 3 minutes 15 seconds, down to 54 seconds. Individual tests drop from 17-20 seconds, down to 3-4 seconds. The cost of this change is that any QOM bugs resulting in the test failure will not be directly associated with the device that caused the failure. The test case is not frequently identifying such bugs though, and the cause is likely easily visible in the patch series that causes the failure. So overall the shorter running time is considered the more important factor. Signed-off-by: Daniel P. Berrangé [thuth: Add the tree check to test_device_intro_none() and test_device_intro_abstract(), too, just to be sure...] Signed-off-by: Thomas Huth Reviewed-by: Laurent Vivier Signed-off-by: Alex Bennée Message-Id: <20200710060719.22386-1-thuth@redhat.com> --- tests/qtest/device-introspect-test.c | 60 ++++++++++++++++++---------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/tests/qtest/device-introspect-test.c b/tests/qtest/device-introspect-test.c index 9abb5ec889..d68b7856a7 100644 --- a/tests/qtest/device-introspect-test.c +++ b/tests/qtest/device-introspect-test.c @@ -105,14 +105,9 @@ static void test_one_device(QTestState *qts, const char *type) { QDict *resp; char *help; - char *qom_tree_start, *qom_tree_end; - char *qtree_start, *qtree_end; g_test_message("Testing device '%s'", type); - qom_tree_start = qtest_hmp(qts, "info qom-tree"); - qtree_start = qtest_hmp(qts, "info qtree"); - resp = qtest_qmp(qts, "{'execute': 'device-list-properties'," " 'arguments': {'typename': %s}}", type); @@ -120,21 +115,6 @@ static void test_one_device(QTestState *qts, const char *type) help = qtest_hmp(qts, "device_add \"%s,help\"", type); g_free(help); - - /* - * Some devices leave dangling pointers in QOM behind. - * "info qom-tree" or "info qtree" have a good chance at crashing then. - * Also make sure that the tree did not change. - */ - qom_tree_end = qtest_hmp(qts, "info qom-tree"); - g_assert_cmpstr(qom_tree_start, ==, qom_tree_end); - g_free(qom_tree_start); - g_free(qom_tree_end); - - qtree_end = qtest_hmp(qts, "info qtree"); - g_assert_cmpstr(qtree_start, ==, qtree_end); - g_free(qtree_start); - g_free(qtree_end); } static void test_device_intro_list(void) @@ -213,16 +193,38 @@ static void test_qom_list_fields(void) static void test_device_intro_none(void) { QTestState *qts = qtest_init(common_args); + g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree"); + g_autofree char *qom_tree_end = NULL; + g_autofree char *qtree_start = qtest_hmp(qts, "info qtree"); + g_autofree char *qtree_end = NULL; test_one_device(qts, "nonexistent"); + + /* Make sure that really nothing changed in the trees */ + qom_tree_end = qtest_hmp(qts, "info qom-tree"); + g_assert_cmpstr(qom_tree_start, ==, qom_tree_end); + qtree_end = qtest_hmp(qts, "info qtree"); + g_assert_cmpstr(qtree_start, ==, qtree_end); + qtest_quit(qts); } static void test_device_intro_abstract(void) { QTestState *qts = qtest_init(common_args); + g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree"); + g_autofree char *qom_tree_end = NULL; + g_autofree char *qtree_start = qtest_hmp(qts, "info qtree"); + g_autofree char *qtree_end = NULL; test_one_device(qts, "device"); + + /* Make sure that really nothing changed in the trees */ + qom_tree_end = qtest_hmp(qts, "info qom-tree"); + g_assert_cmpstr(qom_tree_start, ==, qom_tree_end); + qtree_end = qtest_hmp(qts, "info qtree"); + g_assert_cmpstr(qtree_start, ==, qtree_end); + qtest_quit(qts); } @@ -231,9 +233,12 @@ static void test_device_intro_concrete(const void *args) QList *types; QListEntry *entry; const char *type; - QTestState *qts; + QTestState *qts = qtest_init(args); + g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree"); + g_autofree char *qom_tree_end = NULL; + g_autofree char *qtree_start = qtest_hmp(qts, "info qtree"); + g_autofree char *qtree_end = NULL; - qts = qtest_init(args); types = device_type_list(qts, false); QLIST_FOREACH_ENTRY(types, entry) { @@ -243,6 +248,17 @@ static void test_device_intro_concrete(const void *args) test_one_device(qts, type); } + /* + * Some devices leave dangling pointers in QOM behind. + * "info qom-tree" or "info qtree" have a good chance at crashing then. + * Also make sure that the tree did not change. + */ + qom_tree_end = qtest_hmp(qts, "info qom-tree"); + g_assert_cmpstr(qom_tree_start, ==, qom_tree_end); + + qtree_end = qtest_hmp(qts, "info qtree"); + g_assert_cmpstr(qtree_start, ==, qtree_end); + qobject_unref(types); qtest_quit(qts); g_free((void *)args); From f2c5466c78da786dbf6506e3a15b856b7427708e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:49 +0100 Subject: [PATCH 2199/2595] gitlab: limit re-builds of the containers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the time we are just rebuilding the same things. We can skip this although currently there is no mechanism for picking up new distro releases. Rather than try to be too fine grained allow any change to trigger all the images being rebuilt. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200701135652.1366-38-alex.bennee@linaro.org> --- .gitlab-ci.d/containers.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index a7621c4204..ea350eacff 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -17,6 +17,12 @@ - docker push "$TAG" after_script: - docker logout + rules: + - changes: + - .gitlab-ci.d/containers.yml + - tests/docker/* + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' + - if: '$CI_COMMIT_REF_NAME == "testing/next"' amd64-centos7-container: <<: *container_job_definition From c8e6793903385fe30caf5d23eaed0d339f7aa6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:50 +0100 Subject: [PATCH 2200/2595] containers.yml: build with docker.py tooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of building the docker files directly use the same docker.py scripting as we do for building locally. This should help ensure we use the exact same steps and allow us to cache properly when building locally. To get this working you have to have a fairly recent docker binary otherwise you will see the error message: => ERROR importing cache manifest from registry.gitlab.... So far docker 19.03.12 works (from the docker apt repos) but 18.09.1, build 4c52b90 which is packaged in Debian Buster fails. Signed-off-by: Alex Bennée Message-Id: <20200701135652.1366-39-alex.bennee@linaro.org> --- .gitlab-ci.d/containers.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index ea350eacff..f3c0ca4d61 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -6,14 +6,17 @@ before_script: - export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest" - export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/$NAME:latest" + - apk add python3 - docker info - docker login registry.gitlab.com -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" script: + - echo "TAG:$TAG" + - echo "COMMON_TAG:$COMMON_TAG" - docker pull "$TAG" || docker pull "$COMMON_TAG" || true - - sed -i -e "s,FROM qemu/,FROM $CI_REGISTRY_IMAGE/qemu/," tests/docker/dockerfiles/$NAME.docker - - DOCKER_BUILDKIT=1 docker build --cache-from "$TAG" --cache-from "$COMMON_TAG" --tag "$TAG" - --build-arg BUILDKIT_INLINE_CACHE=1 - -f "tests/docker/dockerfiles/$NAME.docker" tests/docker/dockerfiles + - ./tests/docker/docker.py --engine docker build + -t "qemu/$NAME" -f "tests/docker/dockerfiles/$NAME.docker" + -r $CI_REGISTRY_IMAGE + - docker tag "qemu/$NAME" "$TAG" - docker push "$TAG" after_script: - docker logout From a6eeac3bf535514a2a4b29f5dd8c24306796d8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:51 +0100 Subject: [PATCH 2201/2595] testing: add check-build target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we want to continue to split build and check phase it seems like a good idea to allow building of the tests during our multi-threaded build phase. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Cc: Daniel P. Berrangé Message-Id: <20200701135652.1366-40-alex.bennee@linaro.org> --- .gitlab-ci.yml | 4 +++- tests/Makefile.include | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 13e9531724..5eeba2791b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,7 +36,7 @@ include: - make -j"$JOBS" - if test -n "$MAKE_CHECK_ARGS"; then - make $MAKE_CHECK_ARGS ; + make -j"$JOBS" $MAKE_CHECK_ARGS ; fi .native_test_job_template: &native_test_job_definition @@ -60,6 +60,7 @@ build-system-ubuntu-main: TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu lm32-softmmu moxie-softmmu microblazeel-softmmu mips64el-softmmu m68k-softmmu ppc-softmmu riscv64-softmmu sparc-softmmu + MAKE_CHECK_ARGS: check-build artifacts: paths: - build @@ -90,6 +91,7 @@ build-system-fedora-alt: TARGETS: tricore-softmmu unicore32-softmmu microblaze-softmmu mips-softmmu riscv32-softmmu s390x-softmmu sh4-softmmu sparc64-softmmu x86_64-softmmu xtensa-softmmu nios2-softmmu or1k-softmmu + MAKE_CHECK_ARGS: check-build artifacts: paths: - build diff --git a/tests/Makefile.include b/tests/Makefile.include index c316e0d664..94b1cc8302 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -22,6 +22,8 @@ endif @echo " $(MAKE) check-venv Creates a Python venv for tests" @echo " $(MAKE) check-clean Clean the tests and related data" @echo + @echo "The following are useful for CI builds" + @echo " $(MAKE) check-build Build most test binaris" @echo " $(MAKE) get-vm-images Downloads all images used by acceptance tests, according to configured targets (~350 MB each, 1.5 GB max)" @echo @echo @@ -649,6 +651,10 @@ $(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: %-softmmu/all $(c QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \ QTEST_QEMU_IMG=qemu-img$(EXESUF)) +build-qtest: $(patsubst %, %-softmmu/all, $(QTEST_TARGETS)) $(check-qtest-y) + +build-unit: $(check-unit-y) + check-unit: $(check-unit-y) $(call do_test_human, $^) @@ -680,7 +686,6 @@ check-report.tap: $(patsubst %,check-report-qtest-%.tap, $(QTEST_TARGETS)) check FP_TEST_BIN=$(BUILD_DIR)/tests/fp/fp-test # the build dir is created by configure -.PHONY: $(FP_TEST_BIN) $(FP_TEST_BIN): config-host.h $(test-util-obj-y) $(call quiet-command, \ $(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" $(notdir $@), \ @@ -814,9 +819,10 @@ check-softfloat-ops: $(SF_MATH_RULES) .PHONY: check-softfloat ifeq ($(CONFIG_TCG),y) -check-softfloat: check-softfloat-conv check-softfloat-compare check-softfloat-ops +build-softfloat: $(FP_TEST_BIN) +check-softfloat: build-softfloat check-softfloat-conv check-softfloat-compare check-softfloat-ops else -check-softfloat: +build-softfloat check-softfloat: $(call quiet-command, /bin/true, "FLOAT TEST", \ "SKIPPED for non-TCG builds") endif @@ -955,7 +961,8 @@ check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS)) ifeq ($(CONFIG_TOOLS),y) check-block: $(patsubst %,check-%, $(check-block-y)) endif -check: check-block check-qapi-schema check-unit check-softfloat check-qtest check-decodetree +check-build: build-unit build-softfloat build-qtest + check-clean: rm -rf $(check-unit-y) tests/*.o tests/*/*.o $(QEMU_IOTESTS_HELPERS-y) rm -rf $(sort $(foreach target,$(SYSEMU_TARGET_LIST), $(check-qtest-$(target)-y:%=tests/qtest/%$(EXESUF))) $(check-qtest-generic-y:%=tests/qtest/%$(EXESUF))) @@ -963,6 +970,8 @@ check-clean: rm -f tests/qtest/dbus-vmstate1-gen-timestamp rm -rf $(TESTS_VENV_DIR) $(TESTS_RESULTS_DIR) +check: check-block check-qapi-schema check-unit check-softfloat check-qtest check-decodetree + clean: check-clean # Build the help program automatically From 6e3ede39e2cbffef3f878bc4901f26ebf8d2f1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 1 Jul 2020 14:56:52 +0100 Subject: [PATCH 2202/2595] shippable: pull images from registry instead of building MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now we have a source for registry images pull from there rather than re-building every time on shippable. Signed-off-by: Alex Bennée Message-Id: <20200701135652.1366-41-alex.bennee@linaro.org> --- .shippable.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.shippable.yml b/.shippable.yml index 81905727d1..f6b742432e 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -26,12 +26,10 @@ env: - IMAGE=debian-ppc64el-cross TARGET_LIST=ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user build: - pre_ci: - - make docker-image-${IMAGE} V=1 pre_ci_boot: - image_name: qemu/${IMAGE} + image_name: registry.gitlab.com/qemu-project/qemu/${IMAGE} image_tag: latest - pull: false + pull: true options: "-e HOME=/root" ci: - unset CC From 100a5efbbcffef50d187c045492bcd09d871845e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 8 Jun 2020 13:40:49 +0200 Subject: [PATCH 2203/2595] travis.yml: Test also the other targets on s390x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit s390x is our only big endian host in our CI, so building and testing QEMU there is quite valuable. Thus let's also test the other targets with additional jobs (also using different sets of pre-installed libraries to get a better coverage of the things that we test). Signed-off-by: Thomas Huth Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200608114049.4693-1-thuth@redhat.com> --- .travis.yml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/.travis.yml b/.travis.yml index c24dfbe377..ab429500fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -482,6 +482,45 @@ jobs: $(exit $BUILD_RC); fi + - name: "[s390x] GCC (other-softmmu)" + arch: s390x + dist: bionic + addons: + apt_packages: + - libaio-dev + - libattr1-dev + - libcap-ng-dev + - libgnutls28-dev + - libiscsi-dev + - liblttng-ust-dev + - liblzo2-dev + - libncurses-dev + - libnfs-dev + - libnss3-dev + - libpixman-1-dev + - libsdl2-dev + - libsdl2-image-dev + - libseccomp-dev + - libsnappy-dev + - libzstd-dev + - nettle-dev + - xfslibs-dev + # Tests dependencies + - genisoimage + env: + - CONFIG="--disable-containers --audio-drv-list=sdl --disable-user + --target-list-exclude=${MAIN_SOFTMMU_TARGETS}" + + - name: "[s390x] GCC (user)" + arch: s390x + dist: bionic + addons: + apt_packages: + - libgcrypt20-dev + - libgnutls28-dev + env: + - CONFIG="--disable-containers --disable-system" + - name: "[s390x] Clang (disable-tcg)" arch: s390x dist: bionic From d11f824991749c4b28c3c08ca737e82d0d9d01e6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 26 Jun 2020 13:09:49 -0700 Subject: [PATCH 2204/2595] tests/qht-bench: Adjust testing rate by -1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the seed must be non-zero, subtracting 1 means puts the rate in 0..UINT64_MAX-1, which allows the 0 and UINT64_MAX thresholds to corrspond to 0% (never) and 100% (always). Suggested-by: Emilio G. Cota Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200626200950.1015121-2-richard.henderson@linaro.org> --- tests/qht-bench.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/tests/qht-bench.c b/tests/qht-bench.c index eb88a90137..ad885d89d0 100644 --- a/tests/qht-bench.c +++ b/tests/qht-bench.c @@ -25,7 +25,13 @@ struct thread_stats { struct thread_info { void (*func)(struct thread_info *); struct thread_stats stats; - uint64_t r; + /* + * Seed is in the range [1..UINT64_MAX], because the RNG requires + * a non-zero seed. To use, subtract 1 and compare against the + * threshold with =. This lets threshold = 0 never match (0% hit), + * and threshold = UINT64_MAX always match (100% hit). + */ + uint64_t seed; bool write_op; /* writes alternate between insertions and removals */ bool resize_down; } QEMU_ALIGNED(64); /* avoid false sharing among threads */ @@ -131,8 +137,9 @@ static uint64_t xorshift64star(uint64_t x) static void do_rz(struct thread_info *info) { struct thread_stats *stats = &info->stats; + uint64_t r = info->seed - 1; - if (info->r < resize_threshold) { + if (r < resize_threshold) { size_t size = info->resize_down ? resize_min : resize_max; bool resized; @@ -151,13 +158,14 @@ static void do_rz(struct thread_info *info) static void do_rw(struct thread_info *info) { struct thread_stats *stats = &info->stats; + uint64_t r = info->seed - 1; uint32_t hash; long *p; - if (info->r >= update_threshold) { + if (r >= update_threshold) { bool read; - p = &keys[info->r & (lookup_range - 1)]; + p = &keys[r & (lookup_range - 1)]; hash = hfunc(*p); read = qht_lookup(&ht, p, hash); if (read) { @@ -166,7 +174,7 @@ static void do_rw(struct thread_info *info) stats->not_rd++; } } else { - p = &keys[info->r & (update_range - 1)]; + p = &keys[r & (update_range - 1)]; hash = hfunc(*p); if (info->write_op) { bool written = false; @@ -208,7 +216,7 @@ static void *thread_func(void *p) rcu_read_lock(); while (!atomic_read(&test_stop)) { - info->r = xorshift64star(info->r); + info->seed = xorshift64star(info->seed); info->func(info); } rcu_read_unlock(); @@ -221,7 +229,7 @@ static void *thread_func(void *p) static void prepare_thread_info(struct thread_info *info, int i) { /* seed for the RNG; each thread should have a different one */ - info->r = (i + 1) ^ time(NULL); + info->seed = (i + 1) ^ time(NULL); /* the first update will be a write */ info->write_op = true; /* the first resize will be down */ From 78441c04ca4356e40620bbd24dffffdee3978a22 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 26 Jun 2020 13:09:50 -0700 Subject: [PATCH 2205/2595] tests/qht-bench: Adjust threshold computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 06c4cc3660b3, we split the multiplication in two parts to avoid a clang warning. But because double still rounds to 53 bits, this does not provide additional precision beyond multiplication by nextafter(0x1p64, 0), the largest representable value smaller than 2**64. However, since we have eliminated 1.0, mutiplying by 2**64 produces a better distribution of input values to the output values. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200626200950.1015121-3-richard.henderson@linaro.org> --- tests/qht-bench.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/qht-bench.c b/tests/qht-bench.c index ad885d89d0..362f03cb03 100644 --- a/tests/qht-bench.c +++ b/tests/qht-bench.c @@ -289,11 +289,25 @@ static void pr_params(void) static void do_threshold(double rate, uint64_t *threshold) { + /* + * For 0 <= rate <= 1, scale to fit in a uint64_t. + * + * Scale by 2**64, with a special case for 1.0. + * The remainder of the possible values are scattered between 0 + * and 0xfffffffffffff800 (nextafter(0x1p64, 0)). + * + * Note that we cannot simply scale by UINT64_MAX, because that + * value is not representable as an IEEE double value. + * + * If we scale by the next largest value, nextafter(0x1p64, 0), + * then the remainder of the possible values are scattered between + * 0 and 0xfffffffffffff000. Which leaves us with a gap between + * the final two inputs that is twice as large as any other. + */ if (rate == 1.0) { *threshold = UINT64_MAX; } else { - *threshold = (rate * 0xffff000000000000ull) - + (rate * 0x0000ffffffffffffull); + *threshold = rate * 0x1p64; } } From c8c06e520d389dcde5963cc5a73d5ecbaf6b8e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 9 Jul 2020 15:13:15 +0100 Subject: [PATCH 2206/2595] docs/devel: convert and update MTTCG design document MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do a light conversion to .rst and clean-up some of the language at the start now MTTCG has been merged for a while. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200709141327.14631-2-alex.bennee@linaro.org> --- docs/devel/index.rst | 1 + ...ti-thread-tcg.txt => multi-thread-tcg.rst} | 52 ++++++++++++------- 2 files changed, 34 insertions(+), 19 deletions(-) rename docs/devel/{multi-thread-tcg.txt => multi-thread-tcg.rst} (90%) diff --git a/docs/devel/index.rst b/docs/devel/index.rst index bb8238c5d6..4ecaea3643 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -23,6 +23,7 @@ Contents: decodetree secure-coding-practices tcg + multi-thread-tcg tcg-plugins bitops reset diff --git a/docs/devel/multi-thread-tcg.txt b/docs/devel/multi-thread-tcg.rst similarity index 90% rename from docs/devel/multi-thread-tcg.txt rename to docs/devel/multi-thread-tcg.rst index 3c85ac0eab..42158b77c7 100644 --- a/docs/devel/multi-thread-tcg.txt +++ b/docs/devel/multi-thread-tcg.rst @@ -1,15 +1,17 @@ -Copyright (c) 2015-2016 Linaro Ltd. +.. + Copyright (c) 2015-2020 Linaro Ltd. -This work is licensed under the terms of the GNU GPL, version 2 or -later. See the COPYING file in the top-level directory. + This work is licensed under the terms of the GNU GPL, version 2 or + later. See the COPYING file in the top-level directory. Introduction ============ -This document outlines the design for multi-threaded TCG system-mode -emulation. The current user-mode emulation mirrors the thread -structure of the translated executable. Some of the work will be -applicable to both system and linux-user emulation. +This document outlines the design for multi-threaded TCG (a.k.a MTTCG) +system-mode emulation. user-mode emulation has always mirrored the +thread structure of the translated executable although some of the +changes done for MTTCG system emulation have improved the stability of +linux-user emulation. The original system-mode TCG implementation was single threaded and dealt with multiple CPUs with simple round-robin scheduling. This @@ -21,9 +23,18 @@ vCPU Scheduling =============== We introduce a new running mode where each vCPU will run on its own -user-space thread. This will be enabled by default for all FE/BE -combinations that have had the required work done to support this -safely. +user-space thread. This is enabled by default for all FE/BE +combinations where the host memory model is able to accommodate the +guest (TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO is zero) and the +guest has had the required work done to support this safely +(TARGET_SUPPORTS_MTTCG). + +System emulation will fall back to the original round robin approach +if: + +* forced by --accel tcg,thread=single +* enabling --icount mode +* 64 bit guests on 32 bit hosts (TCG_OVERSIZED_GUEST) In the general case of running translated code there should be no inter-vCPU dependencies and all vCPUs should be able to run at full @@ -61,7 +72,9 @@ have their block-to-block jumps patched. Global TCG State ---------------- -### User-mode emulation +User-mode emulation +~~~~~~~~~~~~~~~~~~~ + We need to protect the entire code generation cycle including any post generation patching of the translated code. This also implies a shared translation buffer which contains code running on all cores. Any @@ -78,9 +91,11 @@ patching. Code generation is serialised with mmap_lock(). -### !User-mode emulation +!User-mode emulation +~~~~~~~~~~~~~~~~~~~~ + Each vCPU has its own TCG context and associated TCG region, thereby -requiring no locking. +requiring no locking during translation. Translation Blocks ------------------ @@ -92,6 +107,7 @@ including: - debugging operations (breakpoint insertion/removal) - some CPU helper functions + - linux-user spawning it's first thread This is done with the async_safe_run_on_cpu() mechanism to ensure all vCPUs are quiescent when changes are being made to shared global @@ -250,8 +266,10 @@ to enforce a particular ordering of memory operations from the point of view of external observers (e.g. another processor core). They can apply to any memory operations as well as just loads or stores. -The Linux kernel has an excellent write-up on the various forms of -memory barrier and the guarantees they can provide [1]. +The Linux kernel has an excellent `write-up +` +on the various forms of memory barrier and the guarantees they can +provide. Barriers are often wrapped around synchronisation primitives to provide explicit memory ordering semantics. However they can be used @@ -352,7 +370,3 @@ an exclusive lock which ensures all emulation is serialised. While the atomic helpers look good enough for now there may be a need to look at solutions that can more closely model the guest architectures semantics. - -========== - -[1] https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/Documentation/memory-barriers.txt From 4d7fe02be39e855cdd11376b4d17a85e343fd5c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 9 Jul 2020 15:13:16 +0100 Subject: [PATCH 2207/2595] docs/devel: add some notes on tcg-icount for developers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This attempts to bring together my understanding of the requirements for icount behaviour into one reference document for our developer notes. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Cc: Paolo Bonzini Cc: Pavel Dovgalyuk Cc: Peter Maydell Message-Id: <20200709141327.14631-3-alex.bennee@linaro.org> --- docs/devel/index.rst | 1 + docs/devel/tcg-icount.rst | 97 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 docs/devel/tcg-icount.rst diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 4ecaea3643..ae6eac7c9c 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -23,6 +23,7 @@ Contents: decodetree secure-coding-practices tcg + tcg-icount multi-thread-tcg tcg-plugins bitops diff --git a/docs/devel/tcg-icount.rst b/docs/devel/tcg-icount.rst new file mode 100644 index 0000000000..8d67b6c076 --- /dev/null +++ b/docs/devel/tcg-icount.rst @@ -0,0 +1,97 @@ +.. + Copyright (c) 2020, Linaro Limited + Written by Alex Bennée + + +======================== +TCG Instruction Counting +======================== + +TCG has long supported a feature known as icount which allows for +instruction counting during execution. This should not be confused +with cycle accurate emulation - QEMU does not attempt to emulate how +long an instruction would take on real hardware. That is a job for +other more detailed (and slower) tools that simulate the rest of a +micro-architecture. + +This feature is only available for system emulation and is +incompatible with multi-threaded TCG. It can be used to better align +execution time with wall-clock time so a "slow" device doesn't run too +fast on modern hardware. It can also provides for a degree of +deterministic execution and is an essential part of the record/replay +support in QEMU. + +Core Concepts +============= + +At its heart icount is simply a count of executed instructions which +is stored in the TimersState of QEMU's timer sub-system. The number of +executed instructions can then be used to calculate QEMU_CLOCK_VIRTUAL +which represents the amount of elapsed time in the system since +execution started. Depending on the icount mode this may either be a +fixed number of ns per instruction or adjusted as execution continues +to keep wall clock time and virtual time in sync. + +To be able to calculate the number of executed instructions the +translator starts by allocating a budget of instructions to be +executed. The budget of instructions is limited by how long it will be +until the next timer will expire. We store this budget as part of a +vCPU icount_decr field which shared with the machinery for handling +cpu_exit(). The whole field is checked at the start of every +translated block and will cause a return to the outer loop to deal +with whatever caused the exit. + +In the case of icount, before the flag is checked we subtract the +number of instructions the translation block would execute. If this +would cause the instruction budget to go negative we exit the main +loop and regenerate a new translation block with exactly the right +number of instructions to take the budget to 0 meaning whatever timer +was due to expire will expire exactly when we exit the main run loop. + +Dealing with MMIO +----------------- + +While we can adjust the instruction budget for known events like timer +expiry we cannot do the same for MMIO. Every load/store we execute +might potentially trigger an I/O event, at which point we will need an +up to date and accurate reading of the icount number. + +To deal with this case, when an I/O access is made we: + + - restore un-executed instructions to the icount budget + - re-compile a single [1]_ instruction block for the current PC + - exit the cpu loop and execute the re-compiled block + +The new block is created with the CF_LAST_IO compile flag which +ensures the final instruction translation starts with a call to +gen_io_start() so we don't enter a perpetual loop constantly +recompiling a single instruction block. For translators using the +common translator_loop this is done automatically. + +.. [1] sometimes two instructions if dealing with delay slots + +Other I/O operations +-------------------- + +MMIO isn't the only type of operation for which we might need a +correct and accurate clock. IO port instructions and accesses to +system registers are the common examples here. These instructions have +to be handled by the individual translators which have the knowledge +of which operations are I/O operations. + +When the translator is handling an instruction of this kind: + +* it must call gen_io_start() if icount is enabled, at some + point before the generation of the code which actually does + the I/O, using a code fragment similar to: + +.. code:: c + + if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } + +* it must end the TB immediately after this instruction + +Note that some older front-ends call a "gen_io_end()" function: +this is obsolete and should not be used. From 506794677594120ff02a0ad3bfbdcb7b0acca608 Mon Sep 17 00:00:00 2001 From: Jon Doron Date: Thu, 9 Jul 2020 15:13:17 +0100 Subject: [PATCH 2208/2595] docs: Add to gdbstub documentation the PhyMemMode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PhyMemMode gdb extension command was missing from the gdb.rst document. Signed-off-by: Jon Doron Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200601171609.1665397-1-arilou@gmail.com> Message-Id: <20200709141327.14631-4-alex.bennee@linaro.org> --- docs/system/gdb.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/system/gdb.rst b/docs/system/gdb.rst index a40145fcf8..abda961e2b 100644 --- a/docs/system/gdb.rst +++ b/docs/system/gdb.rst @@ -87,3 +87,23 @@ three commands you can query and set the single step behavior: (gdb) maintenance packet Qqemu.sstep=0x5 sending: "qemu.sstep=0x5" received: "OK" + + +Another feature that QEMU gdbstub provides is to toggle the memory GDB +works with, by default GDB will show the current process memory respecting +the virtual address translation. + +If you want to examine/change the physical memory you can set the gdbstub +to work with the physical memory rather with the virtual one. + +The memory mode can be checked by sending the following command: + +``maintenance packet qqemu.PhyMemMode`` + This will return either 0 or 1, 1 indicates you are currently in the + physical memory mode. + +``maintenance packet Qqemu.PhyMemMode:1`` + This will change the memory mode to physical memory. + +``maintenance packet Qqemu.PhyMemMode:0`` + This will change it back to normal memory mode. From 85c5e69923ebd27aa3bc796d322b4c5f304de9e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 9 Jul 2020 15:13:25 +0100 Subject: [PATCH 2209/2595] tests/docker: fall back more gracefully when pull fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I only spotted this in the small window between my testing with my registry while waiting for the gitlab PR to go in. As we pre-pull the registry image we know if that fails there isn't any point attempting to use the cache. Fall back to the way we used to do it at that point. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200709141327.14631-12-alex.bennee@linaro.org> --- tests/docker/docker.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/docker/docker.py b/tests/docker/docker.py index 9684f07bde..2d67bbd15a 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -306,13 +306,14 @@ class Docker(object): checksum = _text_checksum(_dockerfile_preprocess(dockerfile)) if registry is not None: - dockerfile = dockerfile.replace("FROM qemu/", - "FROM %s/qemu/" % - (registry)) # see if we can fetch a cache copy, may fail... pull_args = ["pull", "%s/%s" % (registry, tag)] - self._do(pull_args, quiet=quiet) - + if self._do(pull_args, quiet=quiet) == 0: + dockerfile = dockerfile.replace("FROM qemu/", + "FROM %s/qemu/" % + (registry)) + else: + registry = None tmp_df = tempfile.NamedTemporaryFile(mode="w+t", encoding='utf-8', From bf7801df66e694bd88a57b336ebbec64b36b24f8 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 9 Jul 2020 15:13:26 +0100 Subject: [PATCH 2210/2595] tests/docker: update toolchain set in debian-xtensa-cross MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch to the prebuilt xtensa toolchains release 2020.07. Drop csp toolchain as the csp core is not a part of QEMU. Add de233_fpu and dsp3400 toolchains to enable DFPU and FPU2000 tests. Signed-off-by: Max Filippov Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [AJB: fix path in configure.sh] Signed-off-by: Alex Bennée Message-Id: <20200708082347.27318-1-jcmvbkbc@gmail.com> Message-Id: <20200709141327.14631-13-alex.bennee@linaro.org> --- tests/docker/dockerfiles/debian-xtensa-cross.docker | 6 +++--- tests/tcg/configure.sh | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/docker/dockerfiles/debian-xtensa-cross.docker b/tests/docker/dockerfiles/debian-xtensa-cross.docker index beb73f46ba..ba4148299c 100644 --- a/tests/docker/dockerfiles/debian-xtensa-cross.docker +++ b/tests/docker/dockerfiles/debian-xtensa-cross.docker @@ -18,12 +18,12 @@ RUN apt-get update && \ git \ python3-minimal -ENV CPU_LIST csp dc232b dc233c -ENV TOOLCHAIN_RELEASE 2018.02 +ENV CPU_LIST dc232b dc233c de233_fpu dsp3400 +ENV TOOLCHAIN_RELEASE 2020.07 RUN for cpu in $CPU_LIST; do \ curl -#SL http://github.com/foss-xtensa/toolchain/releases/download/$TOOLCHAIN_RELEASE/x86_64-$TOOLCHAIN_RELEASE-xtensa-$cpu-elf.tar.gz \ | tar -xzC /opt; \ done -ENV PATH $PATH:/opt/$TOOLCHAIN_RELEASE/xtensa-dc232b-elf/bin:/opt/$TOOLCHAIN_RELEASE/xtensa-dc233c-elf/bin:/opt/$TOOLCHAIN_RELEASE/xtensa-csp-elf/bin +ENV PATH $PATH:/opt/$TOOLCHAIN_RELEASE/xtensa-dc232b-elf/bin:/opt/$TOOLCHAIN_RELEASE/xtensa-dc233c-elf/bin:/opt/$TOOLCHAIN_RELEASE/xtensa-de233_fpu-elf/bin:/opt/$TOOLCHAIN_RELEASE/xtensa-dsp3400-elf/bin diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh index 37e49736ca..102578caa5 100755 --- a/tests/tcg/configure.sh +++ b/tests/tcg/configure.sh @@ -182,7 +182,7 @@ for target in $target_list; do container_image=debian-xtensa-cross # default to the dc232b cpu - container_cross_cc=/opt/2018.02/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-gcc + container_cross_cc=/opt/2020.07/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-gcc ;; esac From 83c85bf1d68d360bb16353cdd12e873563d00fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 10 Jul 2020 17:30:21 +0100 Subject: [PATCH 2211/2595] .cirrus.yml: add bash to the brew packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like the sed we include earlier we want something more recent for iotests to work. Fixes: 57ee95ed Cc: Max Reitz Signed-off-by: Alex Bennée Message-Id: <20200710182238.10675-1-alex.bennee@linaro.org> --- .cirrus.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 69342ae031..f287d23c5b 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -20,7 +20,7 @@ macos_task: osx_instance: image: mojave-base install_script: - - brew install pkg-config python gnu-sed glib pixman make sdl2 + - brew install pkg-config python gnu-sed glib pixman make sdl2 bash script: - mkdir build - cd build @@ -33,7 +33,7 @@ macos_xcode_task: # this is an alias for the latest Xcode image: mojave-xcode install_script: - - brew install pkg-config gnu-sed glib pixman make sdl2 + - brew install pkg-config gnu-sed glib pixman make sdl2 bash script: - mkdir build - cd build From 024ce1ef7c47934e979b1ec15f528928542e80f4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 10 Jul 2020 22:36:51 +0200 Subject: [PATCH 2212/2595] tests: fix "make check-qtest" for modular builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gerd Hoffmann Signed-off-by: Alex Bennée Message-Id: <20200710203652.9708-2-kraxel@redhat.com> --- tests/qtest/Makefile.include | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qtest/Makefile.include b/tests/qtest/Makefile.include index 98af2c2d93..6a0276fd42 100644 --- a/tests/qtest/Makefile.include +++ b/tests/qtest/Makefile.include @@ -277,6 +277,7 @@ tests/qtest/tco-test$(EXESUF): tests/qtest/tco-test.o $(libqos-pc-obj-y) tests/qtest/virtio-ccw-test$(EXESUF): tests/qtest/virtio-ccw-test.o tests/qtest/display-vga-test$(EXESUF): tests/qtest/display-vga-test.o tests/qtest/qom-test$(EXESUF): tests/qtest/qom-test.o +tests/qtest/modules-test$(EXESUF): tests/qtest/modules-test.o tests/qtest/test-hmp$(EXESUF): tests/qtest/test-hmp.o tests/qtest/machine-none-test$(EXESUF): tests/qtest/machine-none-test.o tests/qtest/device-plug-test$(EXESUF): tests/qtest/device-plug-test.o From e94f0687200ea4adced3f3fbecf233a24440458d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 10 Jul 2020 22:36:52 +0200 Subject: [PATCH 2213/2595] Revert "vga: build virtio-gpu as module" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 8d5a24c83dba90b08ef163bbf166d6dfbad9019b. Compiling all virtio-gpu objects into a single module isn't a good plan because the individual objects have different CONFIG_* dependencies. Leads to module load failures on s390x due to vga support being disabled, which in turn breaks '-device virtio-gpu-device' (flagged by travis ci). So back to the drawing board for modular virtio-gpu ... Signed-off-by: Gerd Hoffmann Signed-off-by: Alex Bennée Message-Id: <20200710203652.9708-3-kraxel@redhat.com> --- hw/display/Makefile.objs | 23 ++++++++++------------- util/module.c | 6 ------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index e907f3182b..d619594ad4 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -49,19 +49,16 @@ common-obj-m += qxl.mo qxl.mo-objs = qxl.o qxl-logger.o qxl-render.o endif -ifeq ($(CONFIG_VIRTIO_GPU),y) -common-obj-m += virtio-gpu.mo -virtio-gpu-obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o -virtio-gpu-obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o -virtio-gpu-obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o -virtio-gpu-obj-$(call land,$(CONFIG_VHOST_USER_GPU),$(CONFIG_VIRTIO_PCI)) += vhost-user-gpu-pci.o -virtio-gpu-obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o -virtio-gpu-obj-$(CONFIG_VHOST_USER_VGA) += vhost-user-vga.o -virtio-gpu.mo-objs := $(virtio-gpu-obj-y) -virtio-gpu.mo-cflags := $(VIRGL_CFLAGS) -virtio-gpu.mo-libs := $(VIRGL_LIBS) -endif - +common-obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o +common-obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o +common-obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o +common-obj-$(call land,$(CONFIG_VHOST_USER_GPU),$(CONFIG_VIRTIO_PCI)) += vhost-user-gpu-pci.o +common-obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o +common-obj-$(CONFIG_VHOST_USER_VGA) += vhost-user-vga.o +virtio-gpu.o-cflags := $(VIRGL_CFLAGS) +virtio-gpu.o-libs += $(VIRGL_LIBS) +virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS) +virtio-gpu-3d.o-libs += $(VIRGL_LIBS) common-obj-$(CONFIG_DPCD) += dpcd.o common-obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx_dp.o diff --git a/util/module.c b/util/module.c index 32b0547b82..90e9bd42c6 100644 --- a/util/module.c +++ b/util/module.c @@ -266,12 +266,6 @@ static struct { { "usb-redir", "hw-", "usb-redirect" }, { "qxl-vga", "hw-", "display-qxl" }, { "qxl", "hw-", "display-qxl" }, - { "virtio-gpu-device", "hw-", "display-virtio-gpu" }, - { "virtio-gpu-pci", "hw-", "display-virtio-gpu" }, - { "virtio-vga", "hw-", "display-virtio-gpu" }, - { "vhost-user-gpu-device", "hw-", "display-virtio-gpu" }, - { "vhost-user-gpu-pci", "hw-", "display-virtio-gpu" }, - { "vhost-user-vga", "hw-", "display-virtio-gpu" }, { "chardev-braille", "chardev-", "baum" }, }; From 4a40f561d5ebb5050a8c6dcbdcee85621056590a Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Fri, 10 Jul 2020 18:32:52 +0200 Subject: [PATCH 2214/2595] iotests: Set LC_ALL=C for sort MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise the result is basically unpredictable. (Note that the precise environment variable to control sorting order is LC_COLLATE, but LC_ALL overrides LC_COLLATE, and we do not want the sorting order to be messed up if LC_ALL is set in the environment.) Reported-by: John Snow Signed-off-by: Max Reitz Reviewed-by: Eric Blake Signed-off-by: Alex Bennée Message-Id: <20200710163253.381630-3-mreitz@redhat.com> --- tests/qemu-iotests/common.filter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index d967adc59a..c9f978abce 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -186,7 +186,7 @@ _filter_img_create() -e 's/^\(data_file\)/3-\1/' \ -e 's/^\(encryption\)/4-\1/' \ -e 's/^\(preallocation\)/8-\1/' \ - | sort \ + | LC_ALL=C sort \ | $SED -e 's/^[0-9]-//' \ | tr '\n\0' ' \n' \ | $SED -e 's/^ *$//' -e 's/ *$//' From 2b61bb716cd45ffe10fc92512b6134084c0ffcde Mon Sep 17 00:00:00 2001 From: Li Feng Date: Fri, 22 May 2020 10:55:54 +0800 Subject: [PATCH 2215/2595] char-socket: initialize reconnect timer only when the timer doesn't start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 ) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 ) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 ) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 ) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng Acked-by: Marc-André Lureau Message-Id: <20200522025554.41063-1-fengli@smartx.com> --- chardev/char-socket.c | 2 +- tests/test-char.c | 73 +++++++++++++++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 5758d9900f..320aa7c642 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -490,7 +490,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr) if (emit_close) { qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } - if (s->reconnect_time) { + if (s->reconnect_time && !s->reconnect_timer) { qemu_chr_socket_restart_timer(chr); } } diff --git a/tests/test-char.c b/tests/test-char.c index 3afc9b1b8d..73ba1cf601 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -625,12 +625,14 @@ static void char_udp_test(void) typedef struct { int event; bool got_pong; + CharBackend *be; } CharSocketTestData; #define SOCKET_PING "Hello" #define SOCKET_PONG "World" +typedef void (*char_socket_cb)(void *opaque, QEMUChrEvent event); static void char_socket_event(void *opaque, QEMUChrEvent event) @@ -639,6 +641,27 @@ char_socket_event(void *opaque, QEMUChrEvent event) data->event = event; } +static void +char_socket_event_with_error(void *opaque, QEMUChrEvent event) +{ + static bool first_error; + CharSocketTestData *data = opaque; + CharBackend *be = data->be; + data->event = event; + switch (event) { + case CHR_EVENT_OPENED: + if (!first_error) { + first_error = true; + qemu_chr_fe_disconnect(be); + } + return; + case CHR_EVENT_CLOSED: + return; + default: + return; + } +} + static void char_socket_read(void *opaque, const uint8_t *buf, int size) @@ -699,19 +722,24 @@ char_socket_addr_to_opt_str(SocketAddress *addr, bool fd_pass, } -static void -char_socket_ping_pong(QIOChannel *ioc) +static int +char_socket_ping_pong(QIOChannel *ioc, Error **errp) { char greeting[sizeof(SOCKET_PING)]; const char *response = SOCKET_PONG; - qio_channel_read_all(ioc, greeting, sizeof(greeting), &error_abort); + int ret; + ret = qio_channel_read_all(ioc, greeting, sizeof(greeting), errp); + if (ret != 0) { + object_unref(OBJECT(ioc)); + return -1; + } g_assert(memcmp(greeting, SOCKET_PING, sizeof(greeting)) == 0); - qio_channel_write_all(ioc, response, sizeof(SOCKET_PONG), &error_abort); - + qio_channel_write_all(ioc, response, sizeof(SOCKET_PONG), errp); object_unref(OBJECT(ioc)); + return 0; } @@ -723,7 +751,7 @@ char_socket_server_client_thread(gpointer data) qio_channel_socket_connect_sync(ioc, addr, &error_abort); - char_socket_ping_pong(QIO_CHANNEL(ioc)); + char_socket_ping_pong(QIO_CHANNEL(ioc), &error_abort); return NULL; } @@ -783,6 +811,7 @@ static void char_socket_server_test(gconstpointer opaque) reconnect: data.event = -1; + data.be = &be; qemu_chr_fe_set_handlers(&be, NULL, NULL, char_socket_event, NULL, &data, NULL, true); @@ -855,10 +884,13 @@ char_socket_client_server_thread(gpointer data) QIOChannelSocket *ioc = data; QIOChannelSocket *cioc; +retry: cioc = qio_channel_socket_accept(ioc, &error_abort); g_assert_nonnull(cioc); - char_socket_ping_pong(QIO_CHANNEL(cioc)); + if (char_socket_ping_pong(QIO_CHANNEL(cioc), NULL) != 0) { + goto retry; + } return NULL; } @@ -869,12 +901,13 @@ typedef struct { const char *reconnect; bool wait_connected; bool fd_pass; + char_socket_cb event_cb; } CharSocketClientTestConfig; - static void char_socket_client_test(gconstpointer opaque) { const CharSocketClientTestConfig *config = opaque; + const char_socket_cb event_cb = config->event_cb; QIOChannelSocket *ioc; char *optstr; Chardev *chr; @@ -938,8 +971,9 @@ static void char_socket_client_test(gconstpointer opaque) reconnect: data.event = -1; + data.be = &be; qemu_chr_fe_set_handlers(&be, NULL, NULL, - char_socket_event, NULL, + event_cb, NULL, &data, NULL, true); if (config->reconnect) { g_assert(data.event == -1); @@ -977,7 +1011,7 @@ static void char_socket_client_test(gconstpointer opaque) /* Setup a callback to receive the reply to our greeting */ qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_read, - char_socket_event, NULL, + event_cb, NULL, &data, NULL, true); g_assert(data.event == CHR_EVENT_OPENED); data.event = -1; @@ -1422,17 +1456,20 @@ int main(int argc, char **argv) #define SOCKET_CLIENT_TEST(name, addr) \ static CharSocketClientTestConfig client1 ## name = \ - { addr, NULL, false, false }; \ + { addr, NULL, false, false, char_socket_event}; \ static CharSocketClientTestConfig client2 ## name = \ - { addr, NULL, true, false }; \ + { addr, NULL, true, false, char_socket_event }; \ static CharSocketClientTestConfig client3 ## name = \ - { addr, ",reconnect=1", false }; \ + { addr, ",reconnect=1", false, false, char_socket_event }; \ static CharSocketClientTestConfig client4 ## name = \ - { addr, ",reconnect=1", true }; \ + { addr, ",reconnect=1", true, false, char_socket_event }; \ static CharSocketClientTestConfig client5 ## name = \ - { addr, NULL, false, true }; \ + { addr, NULL, false, true, char_socket_event }; \ static CharSocketClientTestConfig client6 ## name = \ - { addr, NULL, true, true }; \ + { addr, NULL, true, true, char_socket_event }; \ + static CharSocketClientTestConfig client7 ## name = \ + { addr, ",reconnect=1", true, false, \ + char_socket_event_with_error }; \ g_test_add_data_func("/char/socket/client/mainloop/" # name, \ &client1 ##name, char_socket_client_test); \ g_test_add_data_func("/char/socket/client/wait-conn/" # name, \ @@ -1444,7 +1481,9 @@ int main(int argc, char **argv) g_test_add_data_func("/char/socket/client/mainloop-fdpass/" # name, \ &client5 ##name, char_socket_client_test); \ g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \ - &client6 ##name, char_socket_client_test) + &client6 ##name, char_socket_client_test); \ + g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \ + &client7 ##name, char_socket_client_test) if (has_ipv4) { SOCKET_SERVER_TEST(tcp, &tcpaddr); From 14a7a203063694ff932f3371ed93e97987dcafc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Jul 2020 22:10:34 +0400 Subject: [PATCH 2216/2595] chardev: don't abort on attempt to add duplicated chardev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a regression from commit d2623129a7d ("qom: Drop parameter @errp of object_property_add() & friends"). (qemu) chardev-add id=null,backend=null (qemu) chardev-add id=null,backend=null Unexpected error in object_property_try_add() at /home/elmarco/src/qemu/qom/object.c:1166: attempt to add duplicate property 'null' to object (type 'container') That case is currently not covered in the test suite, but will be with the queued patch "char: fix use-after-free with dup chardev & reconnect". Fixes: d2623129a7dec1d3041ad1221dda1ca49c667532 Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster --- chardev/char.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/chardev/char.c b/chardev/char.c index e5b43cb4b8..a0626d04d5 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -996,7 +996,11 @@ static Chardev *chardev_new(const char *id, const char *typename, } if (id) { - object_property_add_child(get_chardevs_root(), id, obj); + object_property_try_add_child(get_chardevs_root(), id, obj, + &local_err); + if (local_err) { + goto end; + } object_unref(obj); } From 6806601969a0d6c095e3836423fef1dedec55289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 20 Apr 2020 13:20:12 +0200 Subject: [PATCH 2217/2595] char: fix use-after-free with dup chardev & reconnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With a reconnect socket, qemu_char_open() will start a background thread. It should keep a reference on the chardev. Fixes invalid read: READ of size 8 at 0x6040000ac858 thread T7 #0 0x5555598d37b8 in unix_connect_saddr /home/elmarco/src/qq/util/qemu-sockets.c:954 #1 0x5555598d4751 in socket_connect /home/elmarco/src/qq/util/qemu-sockets.c:1109 #2 0x555559707c34 in qio_channel_socket_connect_sync /home/elmarco/src/qq/io/channel-socket.c:145 #3 0x5555596adebb in tcp_chr_connect_client_task /home/elmarco/src/qq/chardev/char-socket.c:1104 #4 0x555559723d55 in qio_task_thread_worker /home/elmarco/src/qq/io/task.c:123 #5 0x5555598a6731 in qemu_thread_start /home/elmarco/src/qq/util/qemu-thread-posix.c:519 #6 0x7ffff40d4431 in start_thread (/lib64/libpthread.so.0+0x9431) #7 0x7ffff40029d2 in __clone (/lib64/libc.so.6+0x1019d2) Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20200420112012.567284-1-marcandre.lureau@redhat.com> --- chardev/char-socket.c | 3 ++- tests/test-char.c | 54 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 320aa7c642..ef62dbf3d7 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1129,7 +1129,8 @@ static void tcp_chr_connect_client_async(Chardev *chr) */ s->connect_task = qio_task_new(OBJECT(sioc), qemu_chr_socket_connected, - chr, NULL); + object_ref(OBJECT(chr)), + (GDestroyNotify)object_unref); qio_task_run_in_thread(s->connect_task, tcp_chr_connect_client_task, s->addr, diff --git a/tests/test-char.c b/tests/test-char.c index 73ba1cf601..9d8746414d 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -904,6 +904,52 @@ typedef struct { char_socket_cb event_cb; } CharSocketClientTestConfig; +static void char_socket_client_dupid_test(gconstpointer opaque) +{ + const CharSocketClientTestConfig *config = opaque; + QIOChannelSocket *ioc; + char *optstr; + Chardev *chr1, *chr2; + SocketAddress *addr; + QemuOpts *opts; + Error *local_err = NULL; + + /* + * Setup a listener socket and determine get its address + * so we know the TCP port for the client later + */ + ioc = qio_channel_socket_new(); + g_assert_nonnull(ioc); + qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort); + addr = qio_channel_socket_get_local_address(ioc, &error_abort); + g_assert_nonnull(addr); + + /* + * Populate the chardev address based on what the server + * is actually listening on + */ + optstr = char_socket_addr_to_opt_str(addr, + config->fd_pass, + config->reconnect, + false); + + opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), + optstr, true); + g_assert_nonnull(opts); + chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort); + g_assert_nonnull(chr1); + + chr2 = qemu_chr_new_from_opts(opts, NULL, &local_err); + g_assert_null(chr2); + error_free_or_abort(&local_err); + + object_unref(OBJECT(ioc)); + qemu_opts_del(opts); + object_unparent(OBJECT(chr1)); + qapi_free_SocketAddress(addr); + g_free(optstr); +} + static void char_socket_client_test(gconstpointer opaque) { const CharSocketClientTestConfig *config = opaque; @@ -1456,7 +1502,7 @@ int main(int argc, char **argv) #define SOCKET_CLIENT_TEST(name, addr) \ static CharSocketClientTestConfig client1 ## name = \ - { addr, NULL, false, false, char_socket_event}; \ + { addr, NULL, false, false, char_socket_event }; \ static CharSocketClientTestConfig client2 ## name = \ { addr, NULL, true, false, char_socket_event }; \ static CharSocketClientTestConfig client3 ## name = \ @@ -1470,6 +1516,8 @@ int main(int argc, char **argv) static CharSocketClientTestConfig client7 ## name = \ { addr, ",reconnect=1", true, false, \ char_socket_event_with_error }; \ + static CharSocketClientTestConfig client8 ## name = \ + { addr, ",reconnect=1", false, false, char_socket_event }; \ g_test_add_data_func("/char/socket/client/mainloop/" # name, \ &client1 ##name, char_socket_client_test); \ g_test_add_data_func("/char/socket/client/wait-conn/" # name, \ @@ -1483,7 +1531,9 @@ int main(int argc, char **argv) g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \ &client6 ##name, char_socket_client_test); \ g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \ - &client7 ##name, char_socket_client_test) + &client7 ##name, char_socket_client_test); \ + g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \ + &client8 ##name, char_socket_client_dupid_test) if (has_ipv4) { SOCKET_SERVER_TEST(tcp, &tcpaddr); From 833ef7ec5677ac3f6627f44fbd599cfb16581220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 22:21:06 +0200 Subject: [PATCH 2218/2595] monitor/misc: Remove unused "chardev/char-mux.h" include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit monitor/misc.c never required "chardev/char-mux.h", remove it. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200423202112.644-2-philmd@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Marc-André Lureau --- monitor/misc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/monitor/misc.c b/monitor/misc.c index 89bb970b00..e847b58a8c 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -33,7 +33,6 @@ #include "exec/gdbstub.h" #include "net/net.h" #include "net/slirp.h" -#include "chardev/char-mux.h" #include "ui/qemu-spice.h" #include "qemu/config-file.h" #include "qemu/ctype.h" From 35b49e93fda0498fe1a8663a6ad3db11756d7e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 22:21:07 +0200 Subject: [PATCH 2219/2595] tests/test-char: Remove unused "chardev/char-mux.h" include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test never required "chardev/char-mux.h", remove it. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200423202112.644-3-philmd@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Marc-André Lureau --- tests/test-char.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test-char.c b/tests/test-char.c index 9d8746414d..614bdac2df 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -6,7 +6,6 @@ #include "qemu/option.h" #include "qemu/sockets.h" #include "chardev/char-fe.h" -#include "chardev/char-mux.h" #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qapi/qapi-commands-char.h" From c383efd50a12991a23921e37541c6e5f1bfec1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 22:21:08 +0200 Subject: [PATCH 2220/2595] chardev: Restrict msmouse / wctablet / testdev to system emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The msmouse / wctablet / testdev character devices are only used by system emulation. Remove them from user mode and tools. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200423202112.644-4-philmd@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Marc-André Lureau --- chardev/Makefile.objs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs index 3a58c9d329..62ec0a3323 100644 --- a/chardev/Makefile.objs +++ b/chardev/Makefile.objs @@ -17,7 +17,7 @@ chardev-obj-y += char-udp.o chardev-obj-$(CONFIG_WIN32) += char-win.o chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o -common-obj-y += msmouse.o wctablet.o testdev.o +common-obj-$(CONFIG_SOFTMMU) += msmouse.o wctablet.o testdev.o ifeq ($(CONFIG_BRLAPI),y) common-obj-m += baum.o From ffa0f7eb57f3fbb4947e5bf12040108481ea46c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 22:21:09 +0200 Subject: [PATCH 2221/2595] chardev: Reduce "char-mux.h" scope, rename it "chardev-internal.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No file out of chardev/ requires access to this header, restrict its scope. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200423202112.644-5-philmd@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Marc-André Lureau --- chardev/char-fe.c | 2 +- chardev/char-mux.c | 2 +- chardev/char.c | 2 +- include/chardev/char-mux.h => chardev/chardev-internal.h | 7 ++++--- 4 files changed, 7 insertions(+), 6 deletions(-) rename include/chardev/char-mux.h => chardev/chardev-internal.h (96%) diff --git a/chardev/char-fe.c b/chardev/char-fe.c index f3530a90e6..474715c5a9 100644 --- a/chardev/char-fe.c +++ b/chardev/char-fe.c @@ -29,7 +29,7 @@ #include "chardev/char-fe.h" #include "chardev/char-io.h" -#include "chardev/char-mux.h" +#include "chardev-internal.h" int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len) { diff --git a/chardev/char-mux.c b/chardev/char-mux.c index 46c44af67c..6f980bb836 100644 --- a/chardev/char-mux.c +++ b/chardev/char-mux.c @@ -29,7 +29,7 @@ #include "chardev/char.h" #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" -#include "chardev/char-mux.h" +#include "chardev-internal.h" /* MUX driver for serial I/O splitting */ diff --git a/chardev/char.c b/chardev/char.c index a0626d04d5..807be52300 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -40,7 +40,7 @@ #include "qemu/id.h" #include "qemu/coroutine.h" -#include "chardev/char-mux.h" +#include "chardev-internal.h" /***********************************************************/ /* character device */ diff --git a/include/chardev/char-mux.h b/chardev/chardev-internal.h similarity index 96% rename from include/chardev/char-mux.h rename to chardev/chardev-internal.h index 417fe32eed..e0264ac349 100644 --- a/include/chardev/char-mux.h +++ b/chardev/chardev-internal.h @@ -1,5 +1,5 @@ /* - * QEMU System Emulator + * QEMU Character device internals * * Copyright (c) 2003-2008 Fabrice Bellard * @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef CHAR_MUX_H -#define CHAR_MUX_H +#ifndef CHARDEV_INTERNAL_H +#define CHARDEV_INTERNAL_H #include "chardev/char.h" #include "chardev/char-fe.h" @@ -30,6 +30,7 @@ #define MAX_MUX 4 #define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */ #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1) + typedef struct MuxChardev { Chardev parent; CharBackend *backends[MAX_MUX]; From 30827bad3852fd85d86995e7ccab429679442889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 22:21:10 +0200 Subject: [PATCH 2222/2595] chardev: Extract system emulation specific code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split out code only used during system emulation, to reduce code pulled in user emulation and tools. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200423202112.644-6-philmd@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Marc-André Lureau --- chardev/Makefile.objs | 1 + chardev/char.c | 35 +------------------ chardev/chardev-internal.h | 3 ++ chardev/chardev-sysemu.c | 69 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 34 deletions(-) create mode 100644 chardev/chardev-sysemu.c diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs index 62ec0a3323..3783dadc4c 100644 --- a/chardev/Makefile.objs +++ b/chardev/Makefile.objs @@ -1,4 +1,5 @@ chardev-obj-y += char.o +chardev-obj-$(CONFIG_SOFTMMU) += chardev-sysemu.o chardev-obj-$(CONFIG_WIN32) += char-console.o chardev-obj-$(CONFIG_POSIX) += char-fd.o chardev-obj-y += char-fe.o diff --git a/chardev/char.c b/chardev/char.c index 807be52300..77e7ec814f 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -45,7 +45,7 @@ /***********************************************************/ /* character device */ -static Object *get_chardevs_root(void) +Object *get_chardevs_root(void) { return container_get(object_get_root(), "/chardevs"); } @@ -305,33 +305,6 @@ static const TypeInfo char_type_info = { .class_init = char_class_init, }; -static int chardev_machine_done_notify_one(Object *child, void *opaque) -{ - Chardev *chr = (Chardev *)child; - ChardevClass *class = CHARDEV_GET_CLASS(chr); - - if (class->chr_machine_done) { - return class->chr_machine_done(chr); - } - - return 0; -} - -static void chardev_machine_done_hook(Notifier *notifier, void *unused) -{ - int ret = object_child_foreach(get_chardevs_root(), - chardev_machine_done_notify_one, NULL); - - if (ret) { - error_report("Failed to call chardev machine_done hooks"); - exit(1); - } -} - -static Notifier chardev_machine_done_notify = { - .notify = chardev_machine_done_hook, -}; - static bool qemu_chr_is_busy(Chardev *s) { if (CHARDEV_IS_MUX(s)) { @@ -1198,12 +1171,6 @@ void qemu_chr_cleanup(void) static void register_types(void) { type_register_static(&char_type_info); - - /* this must be done after machine init, since we register FEs with muxes - * as part of realize functions like serial_isa_realizefn when -nographic - * is specified - */ - qemu_add_machine_init_done_notifier(&chardev_machine_done_notify); } type_init(register_types); diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h index e0264ac349..f4d0429763 100644 --- a/chardev/chardev-internal.h +++ b/chardev/chardev-internal.h @@ -26,6 +26,7 @@ #include "chardev/char.h" #include "chardev/char-fe.h" +#include "qom/object.h" #define MAX_MUX 4 #define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */ @@ -59,4 +60,6 @@ typedef struct MuxChardev { void mux_set_focus(Chardev *chr, int focus); void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event); +Object *get_chardevs_root(void); + #endif /* CHAR_MUX_H */ diff --git a/chardev/chardev-sysemu.c b/chardev/chardev-sysemu.c new file mode 100644 index 0000000000..eecdc615ee --- /dev/null +++ b/chardev/chardev-sysemu.c @@ -0,0 +1,69 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "sysemu/sysemu.h" +#include "chardev/char.h" +#include "qemu/error-report.h" +#include "chardev-internal.h" + +static int chardev_machine_done_notify_one(Object *child, void *opaque) +{ + Chardev *chr = (Chardev *)child; + ChardevClass *class = CHARDEV_GET_CLASS(chr); + + if (class->chr_machine_done) { + return class->chr_machine_done(chr); + } + + return 0; +} + +static void chardev_machine_done_hook(Notifier *notifier, void *unused) +{ + int ret = object_child_foreach(get_chardevs_root(), + chardev_machine_done_notify_one, NULL); + + if (ret) { + error_report("Failed to call chardev machine_done hooks"); + exit(1); + } +} + + +static Notifier chardev_machine_done_notify = { + .notify = chardev_machine_done_hook, +}; + +static void register_types(void) +{ + /* + * This must be done after machine init, since we register FEs with muxes + * as part of realize functions like serial_isa_realizefn when -nographic + * is specified. + */ + qemu_add_machine_init_done_notifier(&chardev_machine_done_notify); +} + +type_init(register_types); From 4f50d4a48e0caa1aad591f3ca437502e33b8699d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Tue, 7 Jul 2020 20:08:36 +0200 Subject: [PATCH 2223/2595] ossaudio: fix out of bounds write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In function oss_read() a read error currently does not exit the read loop. With no data to read the variable pos will quickly underflow and a subsequent successful read overwrites memory outside the buffer. This patch adds the missing break statement to the error path of the function. To reproduce start qemu with -audiodev oss,id=audio0 and in the guest start audio recording. After some time this will trigger an exception. Fixes: 3ba4066d08 "ossaudio: port to the new audio backend api" Signed-off-by: Volker Rümelin Message-id: 20200707180836.5435-1-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- audio/ossaudio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index f88d076ec2..a7dcaa31ad 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -691,6 +691,7 @@ static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len) len, dst); break; } + break; } pos += nread; From 480324ec8d76582fa1c367cc9a0fdb653d4ea96e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 10 Jul 2020 08:55:20 +0200 Subject: [PATCH 2224/2595] docs/qdev-device-use: Clean up the sentences related to -usbdevice Most of the -usbdevice paramaters have been removed already. Update the doc accordingly. Signed-off-by: Thomas Huth Message-id: 20200710065520.24784-1-thuth@redhat.com Signed-off-by: Gerd Hoffmann --- docs/qdev-device-use.txt | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt index 4bbbcf561f..f8d0d2fe29 100644 --- a/docs/qdev-device-use.txt +++ b/docs/qdev-device-use.txt @@ -125,12 +125,7 @@ The -device argument differs in detail for each type of drive: * if=pflash, if=mtd, if=sd, if=xen are not yet available with -device -For USB devices, the old way is actually different: - - -usbdevice disk:format=FMT:FILENAME - -Provides much less control than -drive's OPTS... The new way fixes -that: +For USB storage devices, you can use something like: -device usb-storage,drive=DRIVE-ID,removable=RMB @@ -177,8 +172,6 @@ The appropriate DEVNAME depends on the machine type. For type "pc": This lets you control I/O ports and IRQs. -* -usbdevice serial::chardev becomes -device usb-serial,chardev=dev. - * -usbdevice braille doesn't support LEGACY-CHARDEV syntax. It always uses "braille". With -device, this useful default is gone, so you have to use something like @@ -238,10 +231,6 @@ The old way to define the guest part looks like this: -net nic,netdev=NET-ID,macaddr=MACADDR,model=MODEL,name=ID,addr=STR,vectors=V -Except for USB it looks like this: - - -usbdevice net:netdev=NET-ID,macaddr=MACADDR,name=ID - The new way is -device: -device DEVNAME,netdev=NET-ID,mac=MACADDR,DEV-OPTS... @@ -336,12 +325,7 @@ The new way is -device DEVNAME,DEV-OPTS... Details depend on DRIVER: * mouse -device usb-mouse * tablet -device usb-tablet * wacom-tablet -device usb-wacom-tablet -* host:... See "Host Device Assignment" -* disk:... See "Block Devices" -* serial:... See "Character Devices" * braille See "Character Devices" -* net:... See "Network Devices" -* bt:... not yet available with -device === Watchdog Devices === @@ -358,17 +342,11 @@ and host USB devices. PCI devices can only be assigned with -device: -device vfio-pci,host=ADDR,id=ID -The old way to assign a host USB device is - - -usbdevice host:auto:BUS.ADDR:VID:PRID - -where any of BUS, ADDR, VID, PRID can be the wildcard *. - -The new way is +To assign a host USB device use: -device usb-host,hostbus=BUS,hostaddr=ADDR,vendorid=VID,productid=PRID -Omitted options match anything, just like the old way's wildcard. +Omitted options match anything. === Default Devices === From d1abf3fc6abc01fd5f8985af92726f87b5efd80a Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Tue, 7 Jul 2020 19:13:25 +0200 Subject: [PATCH 2225/2595] configure: fix malloc check Avoid random return value. Fixes commit f2dfe54c74f768a5bf78c9e5918918727f9d9459 Signed-off-by: Olaf Hering Message-Id: <20200707171326.16422-1-olaf@aepfle.de> Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 814ed81279..f59418f6de 100755 --- a/configure +++ b/configure @@ -6343,6 +6343,7 @@ int main(void) { if (tmp != NULL) { return *(int *)(tmp + 2); } + return 1; } EOF if compile_prog "$CPU_CFLAGS -Werror -fsanitize=undefined" ""; then From 0ab6c2384ccae8968517f6883897509cd5f51a40 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Wed, 8 Jul 2020 16:01:03 -0400 Subject: [PATCH 2226/2595] configure: do not clobber CFLAGS with --enable-fuzzing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When configuring with --enable-fuzzing, we overwrote the CFLAGS added by all the preceding checks. Instead of overwriting CFLAGS, append the ones we need. Fixes: adc28027ff ("fuzz: add configure flag --enable-fuzzing") Reported-by: Li Qiang Signed-off-by: Alexander Bulekov Message-Id: <20200708200104.21978-2-alxndr@bu.edu> Tested-by: Li Qiang Reviewed-by: Li Qiang Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index f59418f6de..69a89113f7 100755 --- a/configure +++ b/configure @@ -7926,7 +7926,7 @@ if test "$fuzzing" = "yes" ; then if test "$have_fuzzer" = "yes"; then FUZZ_LDFLAGS=" -fsanitize=address,fuzzer" FUZZ_CFLAGS=" -fsanitize=address,fuzzer" - CFLAGS=" -fsanitize=address,fuzzer-no-link" + CFLAGS="$CFLAGS -fsanitize=address,fuzzer-no-link" else error_exit "Your compiler doesn't support -fsanitize=address,fuzzer" exit 1 From 230225eaaa47f23acffef2f21f9bfb1e99b27b31 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Wed, 8 Jul 2020 16:01:04 -0400 Subject: [PATCH 2227/2595] fuzz: add missing header for rcu_enable_atfork MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 45222b9a90, I fixed a broken check for rcu_enable_atfork introduced in d6919e4cb6. I added a call to rcu_enable_atfork after the call to qemu_init in fuzz.c, but forgot to include the corresponding header, breaking --enable-fuzzing --enable-werror builds. Fixes: 45222b9a90 ("fuzz: fix broken qtest check at rcu_disable_atfork") Signed-off-by: Alexander Bulekov Message-Id: <20200708200104.21978-3-alxndr@bu.edu> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- tests/qtest/fuzz/fuzz.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index a36d9038e0..0b66e43409 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -19,6 +19,7 @@ #include "sysemu/runstate.h" #include "sysemu/sysemu.h" #include "qemu/main-loop.h" +#include "qemu/rcu.h" #include "tests/qtest/libqtest.h" #include "tests/qtest/libqos/qgraph.h" #include "fuzz.h" From 2c65fefa054fb8aa60b138efc48aa24e7d8e00bc Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 9 Jul 2020 10:37:19 +0200 Subject: [PATCH 2228/2595] tests/qtest/fuzz: Add missing spaces in description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There should be a space between "forking" and "for". Message-Id: <20200709083719.22221-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alexander Bulekov Signed-off-by: Thomas Huth --- tests/qtest/fuzz/virtio_scsi_fuzz.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/fuzz/virtio_scsi_fuzz.c b/tests/qtest/fuzz/virtio_scsi_fuzz.c index 51dce491ab..3a9ea13736 100644 --- a/tests/qtest/fuzz/virtio_scsi_fuzz.c +++ b/tests/qtest/fuzz/virtio_scsi_fuzz.c @@ -191,7 +191,7 @@ static void register_virtio_scsi_fuzz_targets(void) { fuzz_add_qos_target(&(FuzzTarget){ .name = "virtio-scsi-fuzz", - .description = "Fuzz the virtio-scsi virtual queues, forking" + .description = "Fuzz the virtio-scsi virtual queues, forking " "for each fuzz run", .pre_vm_init = &counter_shm_init, .pre_fuzz = &virtio_scsi_pre_fuzz, @@ -202,7 +202,7 @@ static void register_virtio_scsi_fuzz_targets(void) fuzz_add_qos_target(&(FuzzTarget){ .name = "virtio-scsi-flags-fuzz", - .description = "Fuzz the virtio-scsi virtual queues, forking" + .description = "Fuzz the virtio-scsi virtual queues, forking " "for each fuzz run (also fuzzes the virtio flags)", .pre_vm_init = &counter_shm_init, .pre_fuzz = &virtio_scsi_pre_fuzz, From 590246ead7e5628e9e365c88aeb1ff3eab24de0d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 9 Jul 2020 10:40:59 +0200 Subject: [PATCH 2229/2595] docs/devel/fuzzing: Fix bugs in documentation Fix typo - the option is called "--fuzz-target" and not "--fuzz_taget". Also use a different fuzzer in the example, since "virtio-net-fork-fuzz" does not seem to be a valid fuzzer target (anymore?). Signed-off-by: Thomas Huth Message-Id: <20200709084059.22539-1-thuth@redhat.com> --- docs/devel/fuzzing.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/devel/fuzzing.txt b/docs/devel/fuzzing.txt index 324d2cd92b..db5641de74 100644 --- a/docs/devel/fuzzing.txt +++ b/docs/devel/fuzzing.txt @@ -33,11 +33,11 @@ Fuzz targets are built similarly to system/softmmu: This builds ./i386-softmmu/qemu-fuzz-i386 -The first option to this command is: --fuzz_taget=FUZZ_NAME +The first option to this command is: --fuzz-target=FUZZ_NAME To list all of the available fuzzers run qemu-fuzz-i386 with no arguments. -eg: - ./i386-softmmu/qemu-fuzz-i386 --fuzz-target=virtio-net-fork-fuzz +For example: + ./i386-softmmu/qemu-fuzz-i386 --fuzz-target=virtio-scsi-fuzz Internally, libfuzzer parses all arguments that do not begin with "--". Information about these is available by passing -help=1 From 7aa12aa215e12ab2d41c60ba57e82d3e2af9f38e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 8 Jul 2020 20:19:44 +0200 Subject: [PATCH 2230/2595] Remove the CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC supports "#pragma GCC diagnostic" since version 4.6, and Clang seems to support it, too, since its early versions 3.x. That means that our minimum required compiler versions all support this pragma already and we can remove the test from configure and all the related #ifdefs in the code. Reviewed-by: Daniel P. Berrangé Message-Id: <20200710045515.25986-1-thuth@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Thomas Huth --- configure | 29 ----------------------------- include/ui/gtk.h | 4 ---- include/ui/qemu-pixman.h | 4 ---- scripts/decodetree.py | 12 ++++-------- ui/gtk.c | 4 ---- util/coroutine-ucontext.c | 4 ++-- 6 files changed, 6 insertions(+), 51 deletions(-) diff --git a/configure b/configure index 69a89113f7..9b6ab9d3ca 100755 --- a/configure +++ b/configure @@ -5728,31 +5728,6 @@ if compile_prog "" "" ; then linux_magic_h=yes fi -######################################## -# check whether we can disable warning option with a pragma (this is needed -# to silence warnings in the headers of some versions of external libraries). -# This test has to be compiled with -Werror as otherwise an unknown pragma is -# only a warning. -# -# If we can't selectively disable warning in the code, disable -Werror so that -# the build doesn't fail anyway. - -pragma_disable_unused_but_set=no -cat > $TMPC << EOF -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-prototypes" -#pragma GCC diagnostic pop - -int main(void) { - return 0; -} -EOF -if compile_prog "-Werror" "" ; then - pragma_diagnostic_available=yes -else - werror=no -fi - ######################################## # check if we have valgrind/valgrind.h @@ -7689,10 +7664,6 @@ if test "$linux_magic_h" = "yes" ; then echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak fi -if test "$pragma_diagnostic_available" = "yes" ; then - echo "CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE=y" >> $config_host_mak -fi - if test "$valgrind_h" = "yes" ; then echo "CONFIG_VALGRIND_H=y" >> $config_host_mak fi diff --git a/include/ui/gtk.h b/include/ui/gtk.h index d1b230848a..eaeb450f91 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -1,15 +1,11 @@ #ifndef UI_GTK_H #define UI_GTK_H -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE /* Work around an -Wstrict-prototypes warning in GTK headers */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-prototypes" -#endif #include -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE #pragma GCC diagnostic pop -#endif #include diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index 3b7cf70157..87737a6f16 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -7,14 +7,10 @@ #define QEMU_PIXMAN_H /* pixman-0.16.0 headers have a redundant declaration */ -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wredundant-decls" -#endif #include -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE #pragma GCC diagnostic pop -#endif /* * pixman image formats are defined to be native endian, diff --git a/scripts/decodetree.py b/scripts/decodetree.py index 530d41ca62..694757b6c2 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -1327,12 +1327,10 @@ def main(): # but we can't tell which ones. Prevent issues from the compiler by # suppressing redundant declaration warnings. if anyextern: - output("#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE\n", - "# pragma GCC diagnostic push\n", - "# pragma GCC diagnostic ignored \"-Wredundant-decls\"\n", - "# ifdef __clang__\n" + output("#pragma GCC diagnostic push\n", + "#pragma GCC diagnostic ignored \"-Wredundant-decls\"\n", + "#ifdef __clang__\n" "# pragma GCC diagnostic ignored \"-Wtypedef-redefinition\"\n", - "# endif\n", "#endif\n\n") out_pats = {} @@ -1347,9 +1345,7 @@ def main(): output('\n') if anyextern: - output("#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE\n", - "# pragma GCC diagnostic pop\n", - "#endif\n\n") + output("#pragma GCC diagnostic pop\n\n") for n in sorted(formats.keys()): f = formats[n] diff --git a/ui/gtk.c b/ui/gtk.c index d4b49bd7da..b0cc08ad6d 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1996,14 +1996,10 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, * proper replacement (native opengl support) is only * available in 3.16+. Silence the warning if possible. */ -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE); -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE #pragma GCC diagnostic pop -#endif vc->gfx.dcl.ops = &dcl_egl_ops; } } else diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index fff20aad80..904b375192 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -251,8 +251,8 @@ Coroutine *qemu_coroutine_new(void) } #ifdef CONFIG_VALGRIND_H -#if defined(CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE) && !defined(__clang__) /* Work around an unused variable in the valgrind.h macro... */ +#if !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif @@ -260,7 +260,7 @@ static inline void valgrind_stack_deregister(CoroutineUContext *co) { VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id); } -#if defined(CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE) && !defined(__clang__) +#if !defined(__clang__) #pragma GCC diagnostic pop #endif #endif From ccb237090fdafedce56cb8b62f451a09ad5031c9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 30 Jun 2020 07:03:44 +0200 Subject: [PATCH 2231/2595] disas/sh4: Add missing fallthrough annotations Add fallthrough annotations to be able to compile the code without warnings with -Wimplicit-fallthrough. Looking at the code, it seems like the fallthrough is indeed intended here, so the comments should be appropriate. Message-Id: <20200630055953.9309-1-thuth@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- disas/sh4.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/disas/sh4.c b/disas/sh4.c index 55ef865a36..dcdbdf26d8 100644 --- a/disas/sh4.c +++ b/disas/sh4.c @@ -1963,6 +1963,7 @@ print_insn_sh (bfd_vma memaddr, struct disassemble_info *info) fprintf_fn (stream, "xd%d", rn & ~1); break; } + /* fallthrough */ case D_REG_N: fprintf_fn (stream, "dr%d", rn); break; @@ -1972,6 +1973,7 @@ print_insn_sh (bfd_vma memaddr, struct disassemble_info *info) fprintf_fn (stream, "xd%d", rm & ~1); break; } + /* fallthrough */ case D_REG_M: fprintf_fn (stream, "dr%d", rm); break; From c02b2eac55ef72dd17b2ea8408c312d83f9e0482 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Wed, 8 Jul 2020 22:46:56 -0400 Subject: [PATCH 2232/2595] GitLab Gating CI: introduce pipeline-status contrib script This script is intended to be used right after a push to a branch. By default, it will look for the pipeline associated with the commit that is the HEAD of the *local* staging branch. It can be used as a one time check, or with the `--wait` option to wait until the pipeline completes. If the pipeline is successful, then a merge of the staging branch into the master branch should be the next step. Signed-off-by: Cleber Rosa Message-Id: <20200709024657.2500558-2-crosa@redhat.com> [thuth: Added the changes suggested by Erik Skultety] Signed-off-by: Thomas Huth --- scripts/ci/gitlab-pipeline-status | 157 ++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100755 scripts/ci/gitlab-pipeline-status diff --git a/scripts/ci/gitlab-pipeline-status b/scripts/ci/gitlab-pipeline-status new file mode 100755 index 0000000000..348a49b6a4 --- /dev/null +++ b/scripts/ci/gitlab-pipeline-status @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2019-2020 Red Hat, Inc. +# +# Author: +# Cleber Rosa +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +""" +Checks the GitLab pipeline status for a given commit ID +""" + +# pylint: disable=C0103 + +import argparse +import http.client +import json +import os +import subprocess +import time +import sys + + +def get_local_staging_branch_commit(): + """ + Returns the commit sha1 for the *local* branch named "staging" + """ + result = subprocess.run(['git', 'rev-parse', 'staging'], + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + cwd=os.path.dirname(__file__), + universal_newlines=True).stdout.strip() + if result == 'staging': + raise ValueError("There's no local branch named 'staging'") + if len(result) != 40: + raise ValueError("Branch staging HEAD doesn't look like a sha1") + return result + + +def get_pipeline_status(project_id, commit_sha1): + """ + Returns the JSON content of the pipeline status API response + """ + url = '/api/v4/projects/{}/pipelines?sha={}'.format(project_id, + commit_sha1) + connection = http.client.HTTPSConnection('gitlab.com') + connection.request('GET', url=url) + response = connection.getresponse() + if response.code != http.HTTPStatus.OK: + raise ValueError("Failed to receive a successful response") + json_response = json.loads(response.read()) + + # As far as I can tell, there should be only one pipeline for the same + # project + commit. If this assumption is false, we can add further + # filters to the url, such as username, and order_by. + if not json_response: + raise ValueError("No pipeline found") + return json_response[0] + + +def wait_on_pipeline_success(timeout, interval, + project_id, commit_sha): + """ + Waits for the pipeline to finish within the given timeout + """ + start = time.time() + while True: + if time.time() >= (start + timeout): + print("Waiting on the pipeline timed out") + return False + + status = get_pipeline_status(project_id, commit_sha) + if status['status'] == 'running': + time.sleep(interval) + print('running...') + continue + + if status['status'] == 'success': + return True + + msg = "Pipeline failed, check: %s" % status['web_url'] + print(msg) + return False + + +def main(): + """ + Script entry point + """ + parser = argparse.ArgumentParser( + prog='pipeline-status', + description='check or wait on a pipeline status') + + parser.add_argument('-t', '--timeout', type=int, default=7200, + help=('Amount of time (in seconds) to wait for the ' + 'pipeline to complete. Defaults to ' + '%(default)s')) + parser.add_argument('-i', '--interval', type=int, default=60, + help=('Amount of time (in seconds) to wait between ' + 'checks of the pipeline status. Defaults ' + 'to %(default)s')) + parser.add_argument('-w', '--wait', action='store_true', default=False, + help=('Wether to wait, instead of checking only once ' + 'the status of a pipeline')) + parser.add_argument('-p', '--project-id', type=int, default=11167699, + help=('The GitLab project ID. Defaults to the project ' + 'for https://gitlab.com/qemu-project/qemu, that ' + 'is, "%(default)s"')) + try: + default_commit = get_local_staging_branch_commit() + commit_required = False + except ValueError: + default_commit = '' + commit_required = True + parser.add_argument('-c', '--commit', required=commit_required, + default=default_commit, + help=('Look for a pipeline associated with the given ' + 'commit. If one is not explicitly given, the ' + 'commit associated with the local branch named ' + '"staging" is used. Default: %(default)s')) + parser.add_argument('--verbose', action='store_true', default=False, + help=('A minimal verbosity level that prints the ' + 'overall result of the check/wait')) + + args = parser.parse_args() + + try: + if args.wait: + success = wait_on_pipeline_success( + args.timeout, + args.interval, + args.project_id, + args.commit) + else: + status = get_pipeline_status(args.project_id, + args.commit) + success = status['status'] == 'success' + except Exception as error: # pylint: disable=W0703 + success = False + if args.verbose: + print("ERROR: %s" % error.args[0]) + + if success: + if args.verbose: + print('success') + sys.exit(0) + else: + if args.verbose: + print('failure') + sys.exit(1) + + +if __name__ == '__main__': + main() From 2a84f48c2b387877422ee85f6425d2c1b25bace0 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 9 Jul 2020 18:00:39 +0200 Subject: [PATCH 2233/2595] docs/system/s390x: Improve the 3270 documentation There is some additional information about the 3270 support in our Wiki at https://wiki.qemu.org/Features/3270 - so let's include this information into the main documentation now to have one single source of information (the Wiki page could later be removed). While at it, I also shortened the lines of the first example a little bit. Otherwise they showed up with a horizontal scrollbar in my Firefox browser. Message-Id: <20200713075112.442-1-thuth@redhat.com> Reviewed-by: Cornelia Huck Signed-off-by: Thomas Huth --- docs/system/s390x/3270.rst | 43 ++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/docs/system/s390x/3270.rst b/docs/system/s390x/3270.rst index 1774cdcadf..0554a70a9f 100644 --- a/docs/system/s390x/3270.rst +++ b/docs/system/s390x/3270.rst @@ -1,9 +1,15 @@ 3270 devices ============ -QEMU supports connecting an external 3270 terminal emulator (such as -``x3270``) to make a single 3270 device available to a guest. Note that this -supports basic features only. +The 3270 is the classic 'green-screen' console of the mainframes (see the +`IBM 3270 Wikipedia article `__). + +The 3270 data stream is not implemented within QEMU; the device only provides +TN3270 (a telnet extension; see `RFC 854 `__ +and `RFC 1576 `__) and leaves the heavy +lifting to an external 3270 terminal emulator (such as ``x3270``) to make a +single 3270 device available to a guest. Note that this supports basic +features only. To provide a 3270 device to a guest, create a ``x-terminal3270`` linked to a ``tn3270`` chardev. The guest will see a 3270 channel device. In order @@ -12,10 +18,14 @@ to actually be able to use it, attach the ``x3270`` emulator to the chardev. Example configuration --------------------- +* Make sure that 3270 support is enabled in the guest's Linux kernel. You need + ``CONFIG_TN3270`` and at least one of ``CONFIG_TN3270_TTY`` (for additional + ttys) or ``CONFIG_TN3270_CONSOLE`` (for a 3270 console). + * Add a ``tn3270`` chardev and a ``x-terminal3270`` to the QEMU command line:: - -chardev socket,id=char_0,host=0.0.0.0,port=2300,nowait,server,tn3270 - -device x-terminal3270,chardev=char_0,devno=fe.0.000a,id=terminal_0 + -chardev socket,id=ch0,host=0.0.0.0,port=2300,nowait,server,tn3270 + -device x-terminal3270,chardev=ch0,devno=fe.0.000a,id=terminal0 * Start the guest. In the guest, use ``chccwdev -e 0.0.000a`` to enable the device. @@ -29,4 +39,25 @@ Example configuration systemctl start serial-getty@3270-tty1.service -This should get you an addtional tty for logging into the guest. + This should get you an additional tty for logging into the guest. + +* If you want to use the 3270 device as the Linux kernel console instead of + an additional tty, you can also append ``conmode=3270 condev=000a`` to + the guest's kernel command line. The kernel then should use the 3270 as + console after the next boot. + +Restrictions +------------ + +3270 support is very basic. In particular: + +* Only one 3270 device is supported. + +* It has only been tested with Linux guests and the x3270 emulator. + +* TLS/SSL is not supported. + +* Resizing on reattach is not supported. + +* Multiple commands in one inbound buffer (for example, when the reset key + is pressed while the network is slow) are not supported. From 185951817dede3dfe4eb1c4c6d262607bee605ef Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 1 Jul 2020 20:18:01 +0200 Subject: [PATCH 2234/2595] ui: fix vc_chr_write call in text_console_do_init In case the string doesn't fit into the buffer snprintf returns the size it would need, so len can be larger than the buffer. Fix this by simply using g_strdup_printf() instead of a static buffer. Reported-by: Wenxiang Qian Signed-off-by: Gerd Hoffmann Message-id: 20200701181801.27935-1-kraxel@redhat.com --- ui/console.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/console.c b/ui/console.c index 08f75c9bf6..0579be792f 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2184,12 +2184,12 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds) text_console_resize(s); if (chr->label) { - char msg[128]; - int len; + char *msg; s->t_attrib.bgcol = QEMU_COLOR_BLUE; - len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label); - vc_chr_write(chr, (uint8_t *)msg, len); + msg = g_strdup_printf("%s console\r\n", chr->label); + vc_chr_write(chr, (uint8_t *)msg, strlen(msg)); + g_free(msg); s->t_attrib = s->t_attrib_default; } From 631009e775a91018a62e2670b4473e99916f858f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2020 15:45:10 +0200 Subject: [PATCH 2235/2595] usb: fix usb-host build on windows. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seems the new API is not available on windows. Update #ifdefs accordingly. Fixes: 9f815e83e983 ("usb: add hostdevice property to usb-host") Reported-by: Howard Spoelstra Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Tested-by: Howard Spoelstra Message-id: 20200624134510.9381-1-kraxel@redhat.com --- hw/usb/host-libusb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index ad7ed8fb0c..c474551d84 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -907,7 +907,7 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev, int hostfd) goto fail; } } else { -#if LIBUSB_API_VERSION >= 0x01000107 +#if LIBUSB_API_VERSION >= 0x01000107 && !defined(CONFIG_WIN32) trace_usb_host_open_hostfd(hostfd); rc = libusb_wrap_sys_device(ctx, hostfd, &s->dh); @@ -1107,7 +1107,7 @@ static void usb_host_realize(USBDevice *udev, Error **errp) QTAILQ_INIT(&s->isorings); s->hostfd = -1; -#if LIBUSB_API_VERSION >= 0x01000107 +#if LIBUSB_API_VERSION >= 0x01000107 && !defined(CONFIG_WIN32) if (s->hostdevice) { int fd; s->needs_autoscan = false; From 75a73a11d3597275bc9ef237bcb38cb53de3166d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 13 Jul 2020 14:36:07 +0100 Subject: [PATCH 2236/2595] hw/arm/bcm2836: Remove unused 'cpu_type' field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'cpu_type' has been moved from BCM283XState to BCM283XClass in commit 210f47840d, but we forgot to remove the old variable. Do it now. Fixes: 210f47840d ("hw/arm/bcm2836: Hardcode correct CPU type") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200703200459.23294-1-f4bug@amsat.org Signed-off-by: Peter Maydell --- include/hw/arm/bcm2836.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h index 024af8aae4..79dfff9d73 100644 --- a/include/hw/arm/bcm2836.h +++ b/include/hw/arm/bcm2836.h @@ -33,7 +33,6 @@ typedef struct BCM283XState { DeviceState parent_obj; /*< public >*/ - char *cpu_type; uint32_t enabled_cpus; struct { From cdecb3fc1eb182d90666348a47afe63c493686e7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 13 Jul 2020 14:36:07 +0100 Subject: [PATCH 2237/2595] target/arm: Fix mtedesc for do_mem_zpz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mtedesc that was constructed was not actually passed in. Found by Coverity (CID 1429996). Fixes: d28d12f008e Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200706202345.193676-1-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 08f0fd15b2..88a2fb271d 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -5275,7 +5275,7 @@ static void do_mem_zpz(DisasContext *s, int zt, int pg, int zm, desc = FIELD_DP32(desc, MTEDESC, ESIZE, 1 << msz); desc <<= SVE_MTEDESC_SHIFT; } - desc = simd_desc(vsz, vsz, scale); + desc = simd_desc(vsz, vsz, desc | scale); t_desc = tcg_const_i32(desc); tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg)); From 74c13305827237e8ca99180b3b43b5c75f11f6c5 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Mon, 13 Jul 2020 14:36:07 +0100 Subject: [PATCH 2238/2595] Add the ability to change the FEC PHY MDIO device number on i.MX25 processor Signed-off-by: Jean-Christophe Dubois Message-id: 9f8923ecd974160ae8f634c275b1100c2cbe66d7.1593806826.git.jcd@tribudubois.net Reviewed-by: Peter Maydell [PMM: updated for object_property_set_uint() argument reordering] Signed-off-by: Peter Maydell --- hw/arm/fsl-imx25.c | 7 +++++++ include/hw/arm/fsl-imx25.h | 1 + 2 files changed, 8 insertions(+) diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index b4ddceae45..08a98f828f 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -171,6 +171,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) epit_table[i].irq)); } + object_property_set_uint(OBJECT(&s->fec), "phy-num", s->phy_num, &err); qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]); if (!sysbus_realize(SYS_BUS_DEVICE(&s->fec), errp)) { @@ -315,10 +316,16 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) &s->iram_alias); } +static Property fsl_imx25_properties[] = { + DEFINE_PROP_UINT32("fec-phy-num", FslIMX25State, phy_num, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void fsl_imx25_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + device_class_set_props(dc, fsl_imx25_properties); dc->realize = fsl_imx25_realize; dc->desc = "i.MX25 SOC"; /* diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h index 9e228dacea..54ee1bfd78 100644 --- a/include/hw/arm/fsl-imx25.h +++ b/include/hw/arm/fsl-imx25.h @@ -65,6 +65,7 @@ typedef struct FslIMX25State { MemoryRegion rom[2]; MemoryRegion iram; MemoryRegion iram_alias; + uint32_t phy_num; } FslIMX25State; /** From a9c167a3c45a2a77fadf8a6f7fa6982b05e64395 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Mon, 13 Jul 2020 14:36:08 +0100 Subject: [PATCH 2239/2595] Add the ability to change the FEC PHY MDIO device number on i.MX6 processor Signed-off-by: Jean-Christophe Dubois Message-id: 05a64e83eb1c0c865ac077b22c599425c024c02c.1593806826.git.jcd@tribudubois.net Reviewed-by: Peter Maydell [PMM: updated for object_property_set_uint() argument reordering] Signed-off-by: Peter Maydell --- hw/arm/fsl-imx6.c | 7 +++++++ include/hw/arm/fsl-imx6.h | 1 + 2 files changed, 8 insertions(+) diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 0bc9f0b60d..00dafe3f62 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -377,6 +377,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) spi_table[i].irq)); } + object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num, &err); qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]); if (!sysbus_realize(SYS_BUS_DEVICE(&s->eth), errp)) { return; @@ -449,10 +450,16 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) &s->ocram_alias); } +static Property fsl_imx6_properties[] = { + DEFINE_PROP_UINT32("fec-phy-num", FslIMX6State, phy_num, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void fsl_imx6_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + device_class_set_props(dc, fsl_imx6_properties); dc->realize = fsl_imx6_realize; dc->desc = "i.MX6 SOC"; /* Reason: Uses serial_hd() in the realize() function */ diff --git a/include/hw/arm/fsl-imx6.h b/include/hw/arm/fsl-imx6.h index 1ebd751324..162fe99375 100644 --- a/include/hw/arm/fsl-imx6.h +++ b/include/hw/arm/fsl-imx6.h @@ -73,6 +73,7 @@ typedef struct FslIMX6State { MemoryRegion caam; MemoryRegion ocram; MemoryRegion ocram_alias; + uint32_t phy_num; } FslIMX6State; From 1f7197deb0b33d858538df8e664d97d57be68e26 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Mon, 13 Jul 2020 14:36:08 +0100 Subject: [PATCH 2240/2595] Add the ability to change the FEC PHY MDIO devices numbers on i.MX7 processor Signed-off-by: Jean-Christophe Dubois Message-id: c850187322be9930e47c8b234c385a7d0da245cb.1593806826.git.jcd@tribudubois.net Reviewed-by: Peter Maydell [PMM: updated for object_property_set_uint() argument reordering] Signed-off-by: Peter Maydell --- hw/arm/fsl-imx7.c | 9 +++++++++ include/hw/arm/fsl-imx7.h | 1 + 2 files changed, 10 insertions(+) diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index fad637d328..2ff2cab924 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -363,6 +363,8 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_ENET2_ADDR, }; + object_property_set_uint(OBJECT(&s->eth[i]), "phy-num", + s->phy_num[i], &error_abort); object_property_set_uint(OBJECT(&s->eth[i]), "tx-ring-num", FSL_IMX7_ETH_NUM_TX_RINGS, &error_abort); qdev_set_nic_properties(DEVICE(&s->eth[i]), &nd_table[i]); @@ -550,10 +552,17 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_PCIE_PHY_SIZE); } +static Property fsl_imx7_properties[] = { + DEFINE_PROP_UINT32("fec1-phy-num", FslIMX7State, phy_num[0], 0), + DEFINE_PROP_UINT32("fec2-phy-num", FslIMX7State, phy_num[1], 1), + DEFINE_PROP_END_OF_LIST(), +}; + static void fsl_imx7_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + device_class_set_props(dc, fsl_imx7_properties); dc->realize = fsl_imx7_realize; /* Reason: Uses serial_hds and nd_table in realize() directly */ diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index da977f9ffb..ad88923707 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -81,6 +81,7 @@ typedef struct FslIMX7State { IMX7GPRState gpr; ChipideaState usb[FSL_IMX7_NUM_USBS]; DesignwarePCIEHost pcie; + uint32_t phy_num[FSL_IMX7_NUM_ETHS]; } FslIMX7State; enum FslIMX7MemoryMap { From 887c0f1544991f567543b7c214aa11ab0cea0a29 Mon Sep 17 00:00:00 2001 From: Aaron Lindsay Date: Mon, 13 Jul 2020 14:36:08 +0100 Subject: [PATCH 2241/2595] target/arm: Don't do raw writes for PMINTENCLR Raw writes to this register when in KVM mode can cause interrupts to be raised (even when the PMU is disabled). Because the underlying state is already aliased to PMINTENSET (which already provides raw write functions), we can safely disable raw accesses to PMINTENCLR entirely. Signed-off-by: Aaron Lindsay Message-id: 20200707152616.1917154-1-aaron@os.amperecomputing.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index dc9c29f998..c69a2baf1d 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2269,13 +2269,13 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .resetvalue = 0x0 }, { .name = "PMINTENCLR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 2, .access = PL1_RW, .accessfn = access_tpm, - .type = ARM_CP_ALIAS | ARM_CP_IO, + .type = ARM_CP_ALIAS | ARM_CP_IO | ARM_CP_NO_RAW, .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), .writefn = pmintenclr_write, }, { .name = "PMINTENCLR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 2, .access = PL1_RW, .accessfn = access_tpm, - .type = ARM_CP_ALIAS | ARM_CP_IO, + .type = ARM_CP_ALIAS | ARM_CP_IO | ARM_CP_NO_RAW, .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), .writefn = pmintenclr_write }, { .name = "CCSIDR", .state = ARM_CP_STATE_BOTH, From e95e05dab6607d9e86cd2eaa3ae4508bf7bb8fbb Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 13 Jul 2020 14:36:08 +0100 Subject: [PATCH 2242/2595] virtio-iommu: Fix coverity issue in virtio_iommu_handle_command() Coverity points out (CID 1430180) that the new case is missing break or a /* fallthrough */ comment. Break is the right thing to do as in that case, tail is not used. Fixes 1733eebb9e ("virtio-iommu: Implement RESV_MEM probe request") Signed-off-by: Eric Auger Reported-by: Peter Maydell Message-id: 20200708160147.18426-1-eric.auger@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/virtio/virtio-iommu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index b39e836181..5d56865e56 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -534,6 +534,7 @@ static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq) ptail = (struct virtio_iommu_req_tail *) (buf + s->config.probe_size); ptail->status = virtio_iommu_handle_probe(s, iov, iov_cnt, buf); + break; } default: tail.status = VIRTIO_IOMMU_S_UNSUPP; From fc4334303e042a78b672a2f31c55960958ba14ca Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 13 Jul 2020 14:36:08 +0100 Subject: [PATCH 2243/2595] build: Enable BSD symbols for Haiku Tell Haiku to provide various BSD functions by setting BSD_SOURCE and linking libbsd. Signed-off-by: David Carlier Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell Message-id: 20200703145614.16684-2-peter.maydell@linaro.org [PMM: expanded commit message] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 9b6ab9d3ca..c70b43d139 100755 --- a/configure +++ b/configure @@ -904,8 +904,8 @@ SunOS) ;; Haiku) haiku="yes" - QEMU_CFLAGS="-DB_USE_POSITIVE_POSIX_ERRORS $QEMU_CFLAGS" - LIBS="-lposix_error_mapper -lnetwork $LIBS" + QEMU_CFLAGS="-DB_USE_POSITIVE_POSIX_ERRORS -DBSD_SOURCE $QEMU_CFLAGS" + LIBS="-lposix_error_mapper -lnetwork -lbsd $LIBS" ;; Linux) audio_drv_list="try-pa oss" From c9c8b88f0bee1bf9e5f2011c67f8b579b6cf68d0 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 13 Jul 2020 14:36:09 +0100 Subject: [PATCH 2244/2595] util/qemu-openpty.c: Don't assume pty.h is glibc-only Instead of using an OS-specific ifdef test to select the "openpty() is in pty.h" codepath, make configure check for the existence of the header and use the new CONFIG_PTY instead. This is necessary to build on Haiku, which also provides openpty() via pty.h. Signed-off-by: David Carlier Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell Message-id: 20200703145614.16684-3-peter.maydell@linaro.org [PMM: Expanded commit message; rename to HAVE_PTY_H] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- configure | 9 +++++++++ util/qemu-openpty.c | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/configure b/configure index c70b43d139..978505611b 100755 --- a/configure +++ b/configure @@ -2402,6 +2402,12 @@ else l2tpv3=no fi +if check_include "pty.h" ; then + pty_h=yes +else + pty_h=no +fi + ######################################### # vhost interdependencies and host support @@ -7893,6 +7899,9 @@ fi if test "$sheepdog" = "yes" ; then echo "CONFIG_SHEEPDOG=y" >> $config_host_mak fi +if test "$pty_h" = "yes" ; then + echo "HAVE_PTY_H=y" >> $config_host_mak +fi if test "$fuzzing" = "yes" ; then if test "$have_fuzzer" = "yes"; then FUZZ_LDFLAGS=" -fsanitize=address,fuzzer" diff --git a/util/qemu-openpty.c b/util/qemu-openpty.c index 4b8df96f38..eb17f5b0bc 100644 --- a/util/qemu-openpty.c +++ b/util/qemu-openpty.c @@ -35,7 +35,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#if defined(__GLIBC__) +#if defined HAVE_PTY_H # include #elif defined CONFIG_BSD # include From 195588ccd55d3afa8621af3b4718babbf6cdca19 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 13 Jul 2020 14:36:09 +0100 Subject: [PATCH 2245/2595] build: Check that mlockall() exists Instead of assuming that all POSIX platforms provide mlockall(), test for it in configure. If the host doesn't provide this platform then os_mlock() will fail -ENOSYS, as it does already on Windows. This is necessary for Haiku, which does not have mlockall(). Signed-off-by: David Carlier Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell Message-id: 20200703145614.16684-4-peter.maydell@linaro.org [PMM: Expanded commit message; rename to HAVE_MLOCKALL] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- configure | 15 +++++++++++++++ os-posix.c | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/configure b/configure index 978505611b..429c938708 100755 --- a/configure +++ b/configure @@ -2408,6 +2408,18 @@ else pty_h=no fi +cat > $TMPC < +int main(int argc, char *argv[]) { + return mlockall(MCL_FUTURE); +} +EOF +if compile_prog "" "" ; then + have_mlockall=yes +else + have_mlockall=no +fi + ######################################### # vhost interdependencies and host support @@ -7902,6 +7914,9 @@ fi if test "$pty_h" = "yes" ; then echo "HAVE_PTY_H=y" >> $config_host_mak fi +if test "$have_mlockall" = "yes" ; then + echo "HAVE_MLOCKALL=y" >> $config_host_mak +fi if test "$fuzzing" = "yes" ; then if test "$have_fuzzer" = "yes"; then FUZZ_LDFLAGS=" -fsanitize=address,fuzzer" diff --git a/os-posix.c b/os-posix.c index 3cd52e1e70..b674b20b1b 100644 --- a/os-posix.c +++ b/os-posix.c @@ -337,6 +337,7 @@ bool is_daemonized(void) int os_mlock(void) { +#ifdef HAVE_MLOCKALL int ret = 0; ret = mlockall(MCL_CURRENT | MCL_FUTURE); @@ -345,4 +346,7 @@ int os_mlock(void) } return ret; +#else + return -ENOSYS; +#endif } From 2a4b472c3c8fbbb95b104f9b7699a5ceeeb5b006 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 13 Jul 2020 14:36:09 +0100 Subject: [PATCH 2246/2595] osdep.h: Always include if it exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regularize our handling of : currently we include it in osdep.h, but only for OpenBSD, and we include it without an ifdef guard in a couple of C files. This causes problems for Haiku, which doesn't have that header. Instead, check in configure whether sys/signal.h exists, and if it does then always include it from osdep.h. Signed-off-by: David Carlier Reviewed-by: Peter Maydell Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell Message-id: 20200703145614.16684-5-peter.maydell@linaro.org [PMM: Expanded commit message; rename to HAVE_SYS_SIGNAL_H] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- configure | 10 ++++++++++ hw/xen/xen-legacy-backend.c | 1 - include/qemu/osdep.h | 2 +- util/oslib-posix.c | 1 - 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 429c938708..bc3b9ad931 100755 --- a/configure +++ b/configure @@ -3244,6 +3244,13 @@ if check_include "libdrm/drm.h" ; then have_drm_h=yes fi +######################################### +# sys/signal.h check +have_sys_signal_h=no +if check_include "sys/signal.h" ; then + have_sys_signal_h=yes +fi + ########################################## # VTE probe @@ -7433,6 +7440,9 @@ fi if test "$have_openpty" = "yes" ; then echo "HAVE_OPENPTY=y" >> $config_host_mak fi +if test "$have_sys_signal_h" = "yes" ; then + echo "HAVE_SYS_SIGNAL_H=y" >> $config_host_mak +fi # Work around a system header bug with some kernel/XFS header # versions where they both try to define 'struct fsxattr': diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index 083d8dc1b2..b61a4855b7 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include #include "hw/sysbus.h" #include "hw/boards.h" diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 0fc206ae61..14059bce5a 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -104,7 +104,7 @@ extern int daemon(int, int); #include #include -#ifdef __OpenBSD__ +#ifdef HAVE_SYS_SIGNAL_H #include #endif diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 39ddc77c85..7ad9195c44 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -38,7 +38,6 @@ #include "qemu/sockets.h" #include "qemu/thread.h" #include -#include #include "qemu/cutils.h" #ifdef CONFIG_LINUX From 8bf0f1754a8321568d536c2f33b013279fc4aaaa Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 13 Jul 2020 14:36:09 +0100 Subject: [PATCH 2247/2595] osdep.h: For Haiku, define SIGIO as equivalent to SIGPOLL Haiku doesn't provide SIGIO; fix this up in osdep.h by defining it as equal to SIGPOLL. Signed-off-by: David Carlier Reviewed-by: Peter Maydell Reviewed-by: Thomas Huth Signed-off-by: Peter Maydell Message-id: 20200703145614.16684-6-peter.maydell@linaro.org [PMM: Expanded commit message] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- include/qemu/osdep.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 14059bce5a..979a403984 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -432,6 +432,10 @@ void qemu_anon_ram_free(void *ptr, size_t size); #define HAVE_CHARDEV_PARPORT 1 #endif +#if defined(__HAIKU__) +#define SIGIO SIGPOLL +#endif + #if defined(CONFIG_LINUX) #ifndef BUS_MCEERR_AR #define BUS_MCEERR_AR 4 From 652a46ebba970017c7a23767dcc983265cdb8eb7 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 13 Jul 2020 14:36:10 +0100 Subject: [PATCH 2248/2595] bswap.h: Include on Haiku for bswap operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Haiku puts the bswap* functions in ; pull in that include file on that platform. Signed-off-by: David Carlier Reviewed-by: Peter Maydell Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell Message-id: 20200703145614.16684-7-peter.maydell@linaro.org [PMM: Expanded commit message] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- include/qemu/bswap.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 2a9f3fe783..1d3e4c24e4 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -8,6 +8,8 @@ # include #elif defined(__FreeBSD__) # include +#elif defined(__HAIKU__) +# include #elif defined(CONFIG_BYTESWAP_H) # include From 81b7b1e21d5da37faef1dbb5404f3adae7e68ac2 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 13 Jul 2020 14:36:10 +0100 Subject: [PATCH 2249/2595] util/compatfd.c: Only include if CONFIG_SIGNALFD util/compatfd.c includes so that the CONFIG_SIGNALFD code can use SYS_signalfd. Guard the #include with CONFIG_SIGNALFD to avoid portability issues on hosts like Haiku which do not provide that header file. Signed-off-by: David Carlier Reviewed-by: Peter Maydell Reviewed-by: Thomas Huth Signed-off-by: Peter Maydell Message-id: 20200703145614.16684-8-peter.maydell@linaro.org [PMM: Expanded commit message] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- util/compatfd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/compatfd.c b/util/compatfd.c index c296f55d14..ee47dd8089 100644 --- a/util/compatfd.c +++ b/util/compatfd.c @@ -16,7 +16,9 @@ #include "qemu/osdep.h" #include "qemu/thread.h" +#if defined(CONFIG_SIGNALFD) #include +#endif struct sigfd_compat_info { From 2b9b9e701041dfbe5efd9af2205b21b35a49f971 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 13 Jul 2020 14:36:10 +0100 Subject: [PATCH 2250/2595] util/oslib-posix.c: Implement qemu_init_exec_dir() for Haiku The qemu_init_exec_dir() function is inherently non-portable; provide an implementation for Haiku hosts. Signed-off-by: David Carlier Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell Message-id: 20200703145614.16684-9-peter.maydell@linaro.org [PMM: Expanded commit message] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- util/oslib-posix.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 7ad9195c44..72907d4d7f 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -60,6 +60,10 @@ #include #endif +#ifdef __HAIKU__ +#include +#endif + #include "qemu/mmap-alloc.h" #ifdef CONFIG_DEBUG_STACK_USAGE @@ -389,6 +393,21 @@ void qemu_init_exec_dir(const char *argv0) } } } +#elif defined(__HAIKU__) + { + image_info ii; + int32_t c = 0; + + *buf = '\0'; + while (get_next_image_info(0, &c, &ii) == B_OK) { + if (ii.type == B_APP_IMAGE) { + strncpy(buf, ii.name, sizeof(buf)); + buf[sizeof(buf) - 1] = 0; + p = buf; + break; + } + } + } #endif /* If we don't have any way of figuring out the actual executable location then try argv[0]. */ From 0b823cb07eade4e7e133cc09dfaccceec04cb6a2 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 13 Jul 2020 14:36:10 +0100 Subject: [PATCH 2251/2595] util/drm: make portable by avoiding struct dirent d_type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Given this isn't perforance critical at all lets avoid the non-portable d_type and use fstat instead to check whenever the file is a chardev. Signed-off-by: Gerd Hoffmann Reported-by: David Carlier Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell Message-id: 20200703145614.16684-10-peter.maydell@linaro.org Message-id: 20200701180302.14821-1-kraxel@redhat.com [PMM: fixed comment style; tweaked subject line] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- util/drm.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/util/drm.c b/util/drm.c index a23ff24538..dae8ffebc8 100644 --- a/util/drm.c +++ b/util/drm.c @@ -24,7 +24,8 @@ int qemu_drm_rendernode_open(const char *rendernode) { DIR *dir; struct dirent *e; - int r, fd; + struct stat st; + int r, fd, ret; char *p; if (rendernode) { @@ -38,10 +39,6 @@ int qemu_drm_rendernode_open(const char *rendernode) fd = -1; while ((e = readdir(dir))) { - if (e->d_type != DT_CHR) { - continue; - } - if (strncmp(e->d_name, "renderD", 7)) { continue; } @@ -53,6 +50,18 @@ int qemu_drm_rendernode_open(const char *rendernode) g_free(p); continue; } + + /* + * prefer fstat() over checking e->d_type == DT_CHR for + * portability reasons + */ + ret = fstat(r, &st); + if (ret < 0 || (st.st_mode & S_IFMT) != S_IFCHR) { + close(r); + g_free(p); + continue; + } + fd = r; g_free(p); break; From 42928f2c9cd6185e3bda5e214f5c8f3603125ba9 Mon Sep 17 00:00:00 2001 From: Wentong Wu Date: Mon, 13 Jul 2020 14:36:10 +0100 Subject: [PATCH 2252/2595] target/nios2: add DISAS_NORETURN case for nothing more to generate Add DISAS_NORETURN case for nothing more to generate because at runtime execution will never return from some helper call. And at the same time replace DISAS_UPDATE in t_gen_helper_raise_exception and gen_exception with the newly added DISAS_NORETURN. Signed-off-by: Wentong Wu Message-id: 20200710233433.19729-1-wentong.wu@intel.com Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/nios2/translate.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/nios2/translate.c b/target/nios2/translate.c index 6c34cd3193..00b591cc29 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -149,7 +149,7 @@ static void t_gen_helper_raise_exception(DisasContext *dc, tcg_gen_movi_tl(dc->cpu_R[R_PC], dc->pc); gen_helper_raise_exception(dc->cpu_env, tmp); tcg_temp_free_i32(tmp); - dc->is_jmp = DISAS_UPDATE; + dc->is_jmp = DISAS_NORETURN; } static bool use_goto_tb(DisasContext *dc, uint32_t dest) @@ -802,7 +802,7 @@ static void gen_exception(DisasContext *dc, uint32_t excp) tcg_gen_movi_tl(cpu_R[R_PC], dc->pc); gen_helper_raise_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); - dc->is_jmp = DISAS_UPDATE; + dc->is_jmp = DISAS_NORETURN; } /* generate intermediate code for basic block 'tb'. */ @@ -877,6 +877,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) tcg_gen_exit_tb(NULL, 0); break; + case DISAS_NORETURN: case DISAS_TB_JUMP: /* nothing more to generate */ break; From c7694535718273c5a38c18a0f08e48509ba26e38 Mon Sep 17 00:00:00 2001 From: Wentong Wu Date: Mon, 13 Jul 2020 14:36:10 +0100 Subject: [PATCH 2253/2595] target/nios2: in line the semantics of DISAS_UPDATE with other targets In line the semantics of DISAS_UPDATE on nios2 target with other targets which is to explicitly write the PC back into the cpu state before doing a tcg_gen_exit_tb(). Signed-off-by: Wentong Wu Message-id: 20200710233433.19729-2-wentong.wu@intel.com Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/nios2/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/nios2/translate.c b/target/nios2/translate.c index 00b591cc29..c2a134f932 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -865,6 +865,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) /* Indicate where the next block should start */ switch (dc->is_jmp) { case DISAS_NEXT: + case DISAS_UPDATE: /* Save the current PC back into the CPU register */ tcg_gen_movi_tl(cpu_R[R_PC], dc->pc); tcg_gen_exit_tb(NULL, 0); @@ -872,7 +873,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) default: case DISAS_JUMP: - case DISAS_UPDATE: /* The jump will already have updated the PC register */ tcg_gen_exit_tb(NULL, 0); break; From 77b3f2af57a37b1c30174a911e03d6ff715ef4aa Mon Sep 17 00:00:00 2001 From: Wentong Wu Date: Mon, 13 Jul 2020 14:36:11 +0100 Subject: [PATCH 2254/2595] target/nios2: Use gen_io_start around wrctl instruction wrctl instruction on nios2 target will cause checking cpu interrupt but tcg_handle_interrupt() will call cpu_abort() if the CPU gets an interrupt while it's not in 'can do IO' state, so add gen_io_start around wrctl instruction. Also at the same time, end the onging TB with DISAS_UPDATE. Signed-off-by: Wentong Wu Message-id: 20200710233433.19729-3-wentong.wu@intel.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/nios2/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/nios2/translate.c b/target/nios2/translate.c index c2a134f932..9824544eb3 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -32,6 +32,7 @@ #include "exec/cpu_ldst.h" #include "exec/translator.h" #include "qemu/qemu-print.h" +#include "exec/gen-icount.h" /* is_jmp field values */ #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ @@ -518,7 +519,11 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags) /* If interrupts were enabled using WRCTL, trigger them. */ #if !defined(CONFIG_USER_ONLY) if ((instr.imm5 + CR_BASE) == CR_STATUS) { + if (tb_cflags(dc->tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_helper_check_interrupts(dc->cpu_env); + dc->is_jmp = DISAS_UPDATE; } #endif } From dcef727e5e45f679908c90a7ff3b816c5d61f602 Mon Sep 17 00:00:00 2001 From: Wentong Wu Date: Mon, 13 Jul 2020 14:36:11 +0100 Subject: [PATCH 2255/2595] hw/nios2: exit to main CPU loop only when unmasking interrupts Only when guest code is unmasking interrupts, terminate the excution of translated code and exit to the main CPU loop to handle previous pended interrupts because of the interrupts mask by guest code. Signed-off-by: Wentong Wu Message-id: 20200710233433.19729-4-wentong.wu@intel.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/nios2/cpu_pic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/nios2/cpu_pic.c b/hw/nios2/cpu_pic.c index 1c1989d56a..5ea7e52ab8 100644 --- a/hw/nios2/cpu_pic.c +++ b/hw/nios2/cpu_pic.c @@ -54,7 +54,8 @@ static void nios2_pic_cpu_handler(void *opaque, int irq, int level) void nios2_check_interrupts(CPUNios2State *env) { - if (env->irq_pending) { + if (env->irq_pending && + (env->regs[CR_STATUS] & CR_STATUS_PIE)) { env->irq_pending = 0; cpu_interrupt(env_cpu(env), CPU_INTERRUPT_HARD); } From ad9d854b70b4587d6785a961b3a5860d8bf215ae Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 13 Jul 2020 14:36:11 +0100 Subject: [PATCH 2256/2595] hw/arm/tosa.c: Detabify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the hardcoded tabs from hw/arm/tosa.c. There aren't many, but since they're all in constant #defines they're not going to go away with our usual "only when we touch a function" policy on reformatting. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200628203748.14250-2-peter.maydell@linaro.org --- hw/arm/tosa.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index 5dee2d76c6..06ecf1e782 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -26,32 +26,32 @@ #include "hw/sysbus.h" #include "exec/address-spaces.h" -#define TOSA_RAM 0x04000000 -#define TOSA_ROM 0x00800000 +#define TOSA_RAM 0x04000000 +#define TOSA_ROM 0x00800000 -#define TOSA_GPIO_USB_IN (5) -#define TOSA_GPIO_nSD_DETECT (9) -#define TOSA_GPIO_ON_RESET (19) -#define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */ -#define TOSA_GPIO_CF_CD (13) -#define TOSA_GPIO_TC6393XB_INT (15) -#define TOSA_GPIO_JC_CF_IRQ (36) /* CF slot1 Ready */ +#define TOSA_GPIO_USB_IN (5) +#define TOSA_GPIO_nSD_DETECT (9) +#define TOSA_GPIO_ON_RESET (19) +#define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */ +#define TOSA_GPIO_CF_CD (13) +#define TOSA_GPIO_TC6393XB_INT (15) +#define TOSA_GPIO_JC_CF_IRQ (36) /* CF slot1 Ready */ -#define TOSA_SCOOP_GPIO_BASE 1 -#define TOSA_GPIO_IR_POWERDWN (TOSA_SCOOP_GPIO_BASE + 2) -#define TOSA_GPIO_SD_WP (TOSA_SCOOP_GPIO_BASE + 3) -#define TOSA_GPIO_PWR_ON (TOSA_SCOOP_GPIO_BASE + 4) +#define TOSA_SCOOP_GPIO_BASE 1 +#define TOSA_GPIO_IR_POWERDWN (TOSA_SCOOP_GPIO_BASE + 2) +#define TOSA_GPIO_SD_WP (TOSA_SCOOP_GPIO_BASE + 3) +#define TOSA_GPIO_PWR_ON (TOSA_SCOOP_GPIO_BASE + 4) -#define TOSA_SCOOP_JC_GPIO_BASE 1 -#define TOSA_GPIO_BT_LED (TOSA_SCOOP_JC_GPIO_BASE + 0) -#define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1) -#define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2) -#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5) -#define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7) +#define TOSA_SCOOP_JC_GPIO_BASE 1 +#define TOSA_GPIO_BT_LED (TOSA_SCOOP_JC_GPIO_BASE + 0) +#define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1) +#define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2) +#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5) +#define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7) -#define DAC_BASE 0x4e -#define DAC_CH1 0 -#define DAC_CH2 1 +#define DAC_BASE 0x4e +#define DAC_CH1 0 +#define DAC_CH2 1 static void tosa_microdrive_attach(PXA2xxState *cpu) { From d4e1d8f57eb2e6d0017ae5e8285fc788556ce427 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 13 Jul 2020 14:36:11 +0100 Subject: [PATCH 2257/2595] hw/arm/tosa: Encapsulate misc GPIO handling in a device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we have a free-floating set of IRQs and a function tosa_out_switch() which handle the GPIO lines on the tosa board which connect to LEDs, and another free-floating IRQ and tosa_reset() function to handle the GPIO line that resets the system. Encapsulate this behaviour in a simple QOM device. This commit fixes Coverity issue CID 1421929 (which pointed out that the 'outsignals' in tosa_gpio_setup() were leaked), because it removes the use of the qemu_allocate_irqs() API from this code entirely. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200628203748.14250-3-peter.maydell@linaro.org --- hw/arm/tosa.c | 88 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 24 deletions(-) diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index 06ecf1e782..383b3b22e2 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -65,24 +65,39 @@ static void tosa_microdrive_attach(PXA2xxState *cpu) pxa2xx_pcmcia_attach(cpu->pcmcia[0], md); } -static void tosa_out_switch(void *opaque, int line, int level) +/* + * Encapsulation of some GPIO line behaviour for the Tosa board + * + * QEMU interface: + * + named GPIO inputs "leds[0..3]": assert to light LEDs + * + named GPIO input "reset": when asserted, resets the system + */ + +#define TYPE_TOSA_MISC_GPIO "tosa-misc-gpio" +#define TOSA_MISC_GPIO(obj) \ + OBJECT_CHECK(TosaMiscGPIOState, (obj), TYPE_TOSA_MISC_GPIO) + +typedef struct TosaMiscGPIOState { + SysBusDevice parent_obj; +} TosaMiscGPIOState; + +static void tosa_gpio_leds(void *opaque, int line, int level) { switch (line) { - case 0: - fprintf(stderr, "blue LED %s.\n", level ? "on" : "off"); - break; - case 1: - fprintf(stderr, "green LED %s.\n", level ? "on" : "off"); - break; - case 2: - fprintf(stderr, "amber LED %s.\n", level ? "on" : "off"); - break; - case 3: - fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off"); - break; - default: - fprintf(stderr, "Uhandled out event: %d = %d\n", line, level); - break; + case 0: + fprintf(stderr, "blue LED %s.\n", level ? "on" : "off"); + break; + case 1: + fprintf(stderr, "green LED %s.\n", level ? "on" : "off"); + break; + case 2: + fprintf(stderr, "amber LED %s.\n", level ? "on" : "off"); + break; + case 3: + fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off"); + break; + default: + g_assert_not_reached(); } } @@ -93,13 +108,22 @@ static void tosa_reset(void *opaque, int line, int level) } } +static void tosa_misc_gpio_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + + qdev_init_gpio_in_named(dev, tosa_gpio_leds, "leds", 4); + qdev_init_gpio_in_named(dev, tosa_reset, "reset", 1); +} + static void tosa_gpio_setup(PXA2xxState *cpu, DeviceState *scp0, DeviceState *scp1, TC6393xbState *tmio) { - qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4); - qemu_irq reset; + DeviceState *misc_gpio; + + misc_gpio = sysbus_create_simple(TYPE_TOSA_MISC_GPIO, -1, NULL); /* MMC/SD host */ pxa2xx_mmci_handlers(cpu->mmc, @@ -107,8 +131,8 @@ static void tosa_gpio_setup(PXA2xxState *cpu, qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT))); /* Handle reset */ - reset = qemu_allocate_irq(tosa_reset, cpu, 0); - qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET, reset); + qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET, + qdev_get_gpio_in_named(misc_gpio, "reset", 0)); /* PCMCIA signals: card's IRQ and Card-Detect */ pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], @@ -119,10 +143,14 @@ static void tosa_gpio_setup(PXA2xxState *cpu, qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ), NULL); - qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED, outsignals[0]); - qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]); - qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]); - qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]); + qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED, + qdev_get_gpio_in_named(misc_gpio, "leds", 0)); + qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED, + qdev_get_gpio_in_named(misc_gpio, "leds", 1)); + qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED, + qdev_get_gpio_in_named(misc_gpio, "leds", 2)); + qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, + qdev_get_gpio_in_named(misc_gpio, "leds", 3)); qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio)); @@ -287,10 +315,22 @@ static const TypeInfo tosa_ssp_info = { .class_init = tosa_ssp_class_init, }; +static const TypeInfo tosa_misc_gpio_info = { + .name = "tosa-misc-gpio", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(TosaMiscGPIOState), + .instance_init = tosa_misc_gpio_init, + /* + * No class init required: device has no internal state so does not + * need to set up reset or vmstate, and has no realize method. + */ +}; + static void tosa_register_types(void) { type_register_static(&tosa_dac_info); type_register_static(&tosa_ssp_info); + type_register_static(&tosa_misc_gpio_info); } type_init(tosa_register_types) From c1abd462d99d8d94dd2c94eb9bb33108859407b2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 13 Jul 2020 14:36:11 +0100 Subject: [PATCH 2258/2595] hw/arm/palm.c: Detabify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove hard-tabs from palm.c. Signed-off-by: Peter Maydell Reviewed-by: Li Qiang Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200628214230.2592-2-peter.maydell@linaro.org --- hw/arm/palm.c | 64 +++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/hw/arm/palm.c b/hw/arm/palm.c index 97ca105d29..569836178f 100644 --- a/hw/arm/palm.c +++ b/hw/arm/palm.c @@ -61,21 +61,21 @@ static const MemoryRegionOps static_ops = { /* Palm Tunsgten|E support */ /* Shared GPIOs */ -#define PALMTE_USBDETECT_GPIO 0 -#define PALMTE_USB_OR_DC_GPIO 1 -#define PALMTE_TSC_GPIO 4 -#define PALMTE_PINTDAV_GPIO 6 -#define PALMTE_MMC_WP_GPIO 8 -#define PALMTE_MMC_POWER_GPIO 9 -#define PALMTE_HDQ_GPIO 11 -#define PALMTE_HEADPHONES_GPIO 14 -#define PALMTE_SPEAKER_GPIO 15 +#define PALMTE_USBDETECT_GPIO 0 +#define PALMTE_USB_OR_DC_GPIO 1 +#define PALMTE_TSC_GPIO 4 +#define PALMTE_PINTDAV_GPIO 6 +#define PALMTE_MMC_WP_GPIO 8 +#define PALMTE_MMC_POWER_GPIO 9 +#define PALMTE_HDQ_GPIO 11 +#define PALMTE_HEADPHONES_GPIO 14 +#define PALMTE_SPEAKER_GPIO 15 /* MPU private GPIOs */ -#define PALMTE_DC_GPIO 2 -#define PALMTE_MMC_SWITCH_GPIO 4 -#define PALMTE_MMC1_GPIO 6 -#define PALMTE_MMC2_GPIO 7 -#define PALMTE_MMC3_GPIO 11 +#define PALMTE_DC_GPIO 2 +#define PALMTE_MMC_SWITCH_GPIO 4 +#define PALMTE_MMC1_GPIO 6 +#define PALMTE_MMC2_GPIO 7 +#define PALMTE_MMC3_GPIO 11 static MouseTransformInfo palmte_pointercal = { .x = 320, @@ -100,17 +100,17 @@ static struct { int column; } palmte_keymap[0x80] = { [0 ... 0x7f] = { -1, -1 }, - [0x3b] = { 0, 0 }, /* F1 -> Calendar */ - [0x3c] = { 1, 0 }, /* F2 -> Contacts */ - [0x3d] = { 2, 0 }, /* F3 -> Tasks List */ - [0x3e] = { 3, 0 }, /* F4 -> Note Pad */ - [0x01] = { 4, 0 }, /* Esc -> Power */ - [0x4b] = { 0, 1 }, /* Left */ - [0x50] = { 1, 1 }, /* Down */ - [0x48] = { 2, 1 }, /* Up */ - [0x4d] = { 3, 1 }, /* Right */ - [0x4c] = { 4, 1 }, /* Centre */ - [0x39] = { 4, 1 }, /* Spc -> Centre */ + [0x3b] = { 0, 0 }, /* F1 -> Calendar */ + [0x3c] = { 1, 0 }, /* F2 -> Contacts */ + [0x3d] = { 2, 0 }, /* F3 -> Tasks List */ + [0x3e] = { 3, 0 }, /* F4 -> Note Pad */ + [0x01] = { 4, 0 }, /* Esc -> Power */ + [0x4b] = { 0, 1 }, /* Left */ + [0x50] = { 1, 1 }, /* Down */ + [0x48] = { 2, 1 }, /* Up */ + [0x4d] = { 3, 1 }, /* Right */ + [0x4c] = { 4, 1 }, /* Centre */ + [0x39] = { 4, 1 }, /* Spc -> Centre */ }; static void palmte_button_event(void *opaque, int keycode) @@ -161,13 +161,13 @@ static void palmte_gpio_setup(struct omap_mpu_state_s *cpu) [PALMTE_MMC_SWITCH_GPIO])); misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7); - qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]); - qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]); - qdev_connect_gpio_out(cpu->gpio, 11, misc_gpio[2]); - qdev_connect_gpio_out(cpu->gpio, 12, misc_gpio[3]); - qdev_connect_gpio_out(cpu->gpio, 13, misc_gpio[4]); - omap_mpuio_out_set(cpu->mpuio, 1, misc_gpio[5]); - omap_mpuio_out_set(cpu->mpuio, 3, misc_gpio[6]); + qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]); + qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]); + qdev_connect_gpio_out(cpu->gpio, 11, misc_gpio[2]); + qdev_connect_gpio_out(cpu->gpio, 12, misc_gpio[3]); + qdev_connect_gpio_out(cpu->gpio, 13, misc_gpio[4]); + omap_mpuio_out_set(cpu->mpuio, 1, misc_gpio[5]); + omap_mpuio_out_set(cpu->mpuio, 3, misc_gpio[6]); /* Reset some inputs to initial state. */ qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO)); From ad938fc1d53c99b264ecfc81291a4814204ff3dd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 13 Jul 2020 14:36:12 +0100 Subject: [PATCH 2259/2595] hw/arm/palm.c: Encapsulate misc GPIO handling in a device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the free-floating set of IRQs and palmte_onoff_gpios() function with a simple QOM device that encapsulates this behaviour. This fixes Coverity issue CID 1421944, which points out that the memory returned by qemu_allocate_irqs() is leaked. Signed-off-by: Peter Maydell Reviewed-by: Li Qiang Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200628214230.2592-3-peter.maydell@linaro.org --- hw/arm/palm.c | 61 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/hw/arm/palm.c b/hw/arm/palm.c index 569836178f..e7bc9ea4c6 100644 --- a/hw/arm/palm.c +++ b/hw/arm/palm.c @@ -124,6 +124,21 @@ static void palmte_button_event(void *opaque, int keycode) !(keycode & 0x80)); } +/* + * Encapsulation of some GPIO line behaviour for the Palm board + * + * QEMU interface: + * + unnamed GPIO inputs 0..6: for the various miscellaneous input lines + */ + +#define TYPE_PALM_MISC_GPIO "palm-misc-gpio" +#define PALM_MISC_GPIO(obj) \ + OBJECT_CHECK(PalmMiscGPIOState, (obj), TYPE_PALM_MISC_GPIO) + +typedef struct PalmMiscGPIOState { + SysBusDevice parent_obj; +} PalmMiscGPIOState; + static void palmte_onoff_gpios(void *opaque, int line, int level) { switch (line) { @@ -151,23 +166,44 @@ static void palmte_onoff_gpios(void *opaque, int line, int level) } } +static void palm_misc_gpio_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + + qdev_init_gpio_in(dev, palmte_onoff_gpios, 7); +} + +static const TypeInfo palm_misc_gpio_info = { + .name = TYPE_PALM_MISC_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PalmMiscGPIOState), + .instance_init = palm_misc_gpio_init, + /* + * No class init required: device has no internal state so does not + * need to set up reset or vmstate, and has no realize method. + */ +}; + static void palmte_gpio_setup(struct omap_mpu_state_s *cpu) { - qemu_irq *misc_gpio; + DeviceState *misc_gpio; + + misc_gpio = sysbus_create_simple(TYPE_PALM_MISC_GPIO, -1, NULL); omap_mmc_handlers(cpu->mmc, qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO), qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio) [PALMTE_MMC_SWITCH_GPIO])); - misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7); - qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]); - qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]); - qdev_connect_gpio_out(cpu->gpio, 11, misc_gpio[2]); - qdev_connect_gpio_out(cpu->gpio, 12, misc_gpio[3]); - qdev_connect_gpio_out(cpu->gpio, 13, misc_gpio[4]); - omap_mpuio_out_set(cpu->mpuio, 1, misc_gpio[5]); - omap_mpuio_out_set(cpu->mpuio, 3, misc_gpio[6]); + qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO, + qdev_get_gpio_in(misc_gpio, 0)); + qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO, + qdev_get_gpio_in(misc_gpio, 1)); + qdev_connect_gpio_out(cpu->gpio, 11, qdev_get_gpio_in(misc_gpio, 2)); + qdev_connect_gpio_out(cpu->gpio, 12, qdev_get_gpio_in(misc_gpio, 3)); + qdev_connect_gpio_out(cpu->gpio, 13, qdev_get_gpio_in(misc_gpio, 4)); + omap_mpuio_out_set(cpu->mpuio, 1, qdev_get_gpio_in(misc_gpio, 5)); + omap_mpuio_out_set(cpu->mpuio, 3, qdev_get_gpio_in(misc_gpio, 6)); /* Reset some inputs to initial state. */ qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO)); @@ -276,3 +312,10 @@ static void palmte_machine_init(MachineClass *mc) } DEFINE_MACHINE("cheetah", palmte_machine_init) + +static void palm_register_types(void) +{ + type_register_static(&palm_misc_gpio_info); +} + +type_init(palm_register_types) From 756f739b1682bf131994ec96dad7fbdf8b54493a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 13 Jul 2020 14:36:12 +0100 Subject: [PATCH 2260/2595] hw/arm/aspeed: Do not create and attach empty SD cards by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since added in commit 2bea128c3d, each SDHCI is wired with a SD card, using empty card when no block drive provided. This is not the desired behavior. The SDHCI exposes a SD bus to plug cards on, if no card available, it is fine to have an unplugged bus. Avoid creating unnecessary SD card device when no block drive provided. Fixes: 2bea128c3d ("hw/sd/aspeed_sdhci: New device") Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200705173402.15620-1-f4bug@amsat.org Reviewed-by: Cédric Le Goater Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 660dcb5414..6a3a345a6f 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -246,11 +246,12 @@ static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo) { DeviceState *card; - card = qdev_new(TYPE_SD_CARD); - if (dinfo) { - qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); + if (!dinfo) { + return; } + card = qdev_new(TYPE_SD_CARD); + qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo), + &error_fatal); qdev_realize_and_unref(card, qdev_get_child_bus(DEVICE(sdhci), "sd-bus"), &error_fatal); From 00d69986da83a74f6f5731c80f8dd09fde95d19a Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 22 Jun 2020 16:03:55 -0500 Subject: [PATCH 2261/2595] nbd: Avoid off-by-one in long export name truncation When snprintf returns the same value as the buffer size, the final byte was truncated to ensure a NUL terminator. Fortunately, such long export names are unusual enough, with no real impact other than what is displayed to the user. Fixes: 5c86bdf12089 Reported-by: Max Reitz Signed-off-by: Eric Blake Message-Id: <20200622210355.414941-1-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- block/nbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/nbd.c b/block/nbd.c index c297336ffc..65a4f56924 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -2002,7 +2002,7 @@ static void nbd_refresh_filename(BlockDriverState *bs) len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nbd://%s:%s", host, port); } - if (len > sizeof(bs->exact_filename)) { + if (len >= sizeof(bs->exact_filename)) { /* Name is too long to represent exactly, so leave it empty. */ bs->exact_filename[0] = '\0'; } From 8cf58a49f883f089e7d4b6e19acc987085d024fd Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 20 Apr 2020 12:53:07 -0500 Subject: [PATCH 2262/2595] hax: Fix setting of FD_CLOEXEC Blindly setting FD_CLOEXEC without a read-modify-write will inadvertently clear any other intentionally-set bits, such as a proposed new bit for designating a fd that must behave in 32-bit mode. Use our wrapper function instead of an incorrect hand-rolled version. Signed-off-by: Eric Blake Message-Id: <20200420175309.75894-2-eblake@redhat.com> Reviewed-by: Colin Xu --- target/i386/hax-posix.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/i386/hax-posix.c b/target/i386/hax-posix.c index 3bad89f133..5f9d1b803d 100644 --- a/target/i386/hax-posix.c +++ b/target/i386/hax-posix.c @@ -23,7 +23,7 @@ hax_fd hax_mod_open(void) fprintf(stderr, "Failed to open the hax module\n"); } - fcntl(fd, F_SETFD, FD_CLOEXEC); + qemu_set_cloexec(fd); return fd; } @@ -147,7 +147,7 @@ hax_fd hax_host_open_vm(struct hax_state *hax, int vm_id) fd = open(vm_name, O_RDWR); g_free(vm_name); - fcntl(fd, F_SETFD, FD_CLOEXEC); + qemu_set_cloexec(fd); return fd; } @@ -200,7 +200,7 @@ hax_fd hax_host_open_vcpu(int vmid, int vcpuid) if (fd < 0) { fprintf(stderr, "Failed to open the vcpu devfs\n"); } - fcntl(fd, F_SETFD, FD_CLOEXEC); + qemu_set_cloexec(fd); return fd; } From a1a7f56cdd1ddc99fcd1078c9285849aaaaaeca9 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 1 Jul 2020 13:53:27 +0300 Subject: [PATCH 2263/2595] iotests: QemuIoInteractive: use qemu_io_args_no_fmt The only user (iotest 205) of QemuIoInteractive provides -f argument, so it's a bit inefficient to use qemu_io_args, which contains -f too. And we are going to add one more test, which wants to specify -f by hand. Let's use qemu_io_args_no_fmt. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200701105331.121670-2-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/iotests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index f1e0733dda..109fb3884a 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -212,7 +212,7 @@ def get_virtio_scsi_device(): class QemuIoInteractive: def __init__(self, *args): - self.args = qemu_io_args + list(args) + self.args = qemu_io_args_no_fmt + list(args) self._p = subprocess.Popen(self.args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, From 1f4b774a6444575b86f27b17d3d01e4f41df6581 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 1 Jul 2020 13:53:28 +0300 Subject: [PATCH 2264/2595] iotests.py: QemuIoInteractive: print output on failure Make it simpler to debug when qemu-io fails due to wrong arguments or environment. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200701105331.121670-3-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/iotests.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 109fb3884a..2a08fea3c9 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -217,7 +217,13 @@ class QemuIoInteractive: stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - assert self._p.stdout.read(9) == 'qemu-io> ' + out = self._p.stdout.read(9) + if out != 'qemu-io> ': + # Most probably qemu-io just failed to start. + # Let's collect the whole output and exit. + out += self._p.stdout.read() + self._p.wait(timeout=1) + raise ValueError(out) def close(self): self._p.communicate('q\n') From df0e032b6196934b2b12180a6a05aa8b7e6553fc Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 1 Jul 2020 13:53:30 +0300 Subject: [PATCH 2265/2595] iotests.py: filter_testfiles(): filter SOCK_DIR too Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200701105331.121670-5-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/iotests.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 2a08fea3c9..8b760405ee 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -345,8 +345,9 @@ def filter_qmp(qmsg, filter_fn): return qmsg def filter_testfiles(msg): - prefix = os.path.join(test_dir, "%s-" % (os.getpid())) - return msg.replace(prefix, 'TEST_DIR/PID-') + pref1 = os.path.join(test_dir, "%s-" % (os.getpid())) + pref2 = os.path.join(sock_dir, "%s-" % (os.getpid())) + return msg.replace(pref1, 'TEST_DIR/PID-').replace(pref2, 'SOCK_DIR/PID-') def filter_qmp_testfiles(qmsg): def _filter(_key, value): From 9728ebfb77f0159f4c358103ac4b49a72109d972 Mon Sep 17 00:00:00 2001 From: Zheng Chuan Date: Thu, 9 Jul 2020 16:28:25 +0800 Subject: [PATCH 2266/2595] migration: fix memory leak in qmp_migrate_set_parameters "tmp.tls_hostname" and "tmp.tls_creds" allocated by migrate_params_test_apply() is forgot to free at the end of qmp_migrate_set_parameters(). Fix that. The leak stack: Direct leak of 2 byte(s) in 2 object(s) allocated from: #0 0xffffb597c20b in __interceptor_malloc (/usr/lib64/libasan.so.4+0xd320b) #1 0xffffb52dcb1b in g_malloc (/usr/lib64/libglib-2.0.so.0+0x58b1b) #2 0xffffb52f8143 in g_strdup (/usr/lib64/libglib-2.0.so.0+0x74143) #3 0xaaaac52447fb in migrate_params_test_apply (/usr/src/debug/qemu-4.1.0/migration/migration.c:1377) #4 0xaaaac52fdca7 in qmp_migrate_set_parameters (/usr/src/debug/qemu-4.1.0/qapi/qapi-commands-migration.c:192) #5 0xaaaac551d543 in qmp_dispatch (/usr/src/debug/qemu-4.1.0/qapi/qmp-dispatch.c:165) #6 0xaaaac52a0a8f in qmp_dispatch (/usr/src/debug/qemu-4.1.0/monitor/qmp.c:125) #7 0xaaaac52a1c7f in monitor_qmp_dispatch (/usr/src/debug/qemu-4.1.0/monitor/qmp.c:214) #8 0xaaaac55cb0cf in aio_bh_call (/usr/src/debug/qemu-4.1.0/util/async.c:117) #9 0xaaaac55d4543 in aio_bh_poll (/usr/src/debug/qemu-4.1.0/util/aio-posix.c:459) #10 0xaaaac55cae0f in aio_dispatch (/usr/src/debug/qemu-4.1.0/util/async.c:268) #11 0xffffb52d6a7b in g_main_context_dispatch (/usr/lib64/libglib-2.0.so.0+0x52a7b) #12 0xaaaac55d1e3b(/usr/bin/qemu-kvm-4.1.0+0x1622e3b) #13 0xaaaac4e314bb(/usr/bin/qemu-kvm-4.1.0+0xe824bb) #14 0xaaaac47f45ef(/usr/bin/qemu-kvm-4.1.0+0x8455ef) #15 0xffffb4bfef3f in __libc_start_main (/usr/lib64/libc.so.6+0x23f3f) #16 0xaaaac47ffacb(/usr/bin/qemu-kvm-4.1.0+0x850acb) Direct leak of 2 byte(s) in 2 object(s) allocated from: #0 0xffffb597c20b in __interceptor_malloc (/usr/lib64/libasan.so.4+0xd320b) #1 0xffffb52dcb1b in g_malloc (/usr/lib64/libglib-2.0.so.0+0x58b1b) #2 0xffffb52f8143 in g_strdup (/usr/lib64/libglib-2.0.so.0+0x74143) #3 0xaaaac5244893 in migrate_params_test_apply (/usr/src/debug/qemu-4.1.0/migration/migration.c:1382) #4 0xaaaac52fdca7 in qmp_migrate_set_parameters (/usr/src/debug/qemu-4.1.0/qapi/qapi-commands-migration.c:192) #5 0xaaaac551d543 in qmp_dispatch (/usr/src/debug/qemu-4.1.0/qapi/qmp-dispatch.c) #6 0xaaaac52a0a8f in qmp_dispatch (/usr/src/debug/qemu-4.1.0/monitor/qmp.c:125) #7 0xaaaac52a1c7f in monitor_qmp_dispatch (/usr/src/debug/qemu-4.1.0/monitor/qmp.c:214) #8 0xaaaac55cb0cf in aio_bh_call (/usr/src/debug/qemu-4.1.0/util/async.c:117) #9 0xaaaac55d4543 in aio_bh_poll (/usr/src/debug/qemu-4.1.0/util/aio-posix.c:459) #10 0xaaaac55cae0f in in aio_dispatch (/usr/src/debug/qemu-4.1.0/util/async.c:268) #11 0xffffb52d6a7b in g_main_context_dispatch (/usr/lib64/libglib-2.0.so.0+0x52a7b) #12 0xaaaac55d1e3b(/usr/bin/qemu-kvm-4.1.0+0x1622e3b) #13 0xaaaac4e314bb(/usr/bin/qemu-kvm-4.1.0+0xe824bb) #14 0xaaaac47f45ef (/usr/bin/qemu-kvm-4.1.0+0x8455ef) #15 0xffffb4bfef3f in __libc_start_main (/usr/lib64/libc.so.6+0x23f3f) #16 0xaaaac47ffacb(/usr/bin/qemu-kvm-4.1.0+0x850acb) Signed-off-by: Chuan Zheng Reviewed-by: KeQian Zhu Reviewed-by: HaiLiang Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/migration.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 4e658c397e..08519de56f 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1343,12 +1343,12 @@ static void migrate_params_test_apply(MigrateSetParameters *params, if (params->has_tls_creds) { assert(params->tls_creds->type == QTYPE_QSTRING); - dest->tls_creds = g_strdup(params->tls_creds->u.s); + dest->tls_creds = params->tls_creds->u.s; } if (params->has_tls_hostname) { assert(params->tls_hostname->type == QTYPE_QSTRING); - dest->tls_hostname = g_strdup(params->tls_hostname->u.s); + dest->tls_hostname = params->tls_hostname->u.s; } if (params->has_max_bandwidth) { From 66270a475cb81f24b53c8cc9ccaf152baf6bb10f Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 3 Jul 2020 19:11:24 +0300 Subject: [PATCH 2267/2595] migration/savevm: respect qemu_fclose() error code in save_snapshot() qemu_fclose() could return error, f.e. if bdrv_co_flush() will return the error. This validation will become more important once we will start waiting of asynchronous IO operations, started from bdrv_write_vmstate(), which are coming soon. Signed-off-by: Denis V. Lunev Reviewed-by: "Dr. David Alan Gilbert" Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Juan Quintela CC: Kevin Wolf CC: Max Reitz CC: Stefan Hajnoczi CC: Fam Zheng CC: Juan Quintela CC: Denis Plotnikov Signed-off-by: Juan Quintela --- migration/savevm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/migration/savevm.c b/migration/savevm.c index 6e01724605..45c9dd9d8a 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -2635,7 +2635,7 @@ int save_snapshot(const char *name, Error **errp) { BlockDriverState *bs, *bs1; QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1; - int ret = -1; + int ret = -1, ret2; QEMUFile *f; int saved_vm_running; uint64_t vm_state_size; @@ -2719,10 +2719,14 @@ int save_snapshot(const char *name, Error **errp) } ret = qemu_savevm_state(f, errp); vm_state_size = qemu_ftell(f); - qemu_fclose(f); + ret2 = qemu_fclose(f); if (ret < 0) { goto the_end; } + if (ret2 < 0) { + ret = ret2; + goto the_end; + } /* The bdrv_all_create_snapshot() call that follows acquires the AioContext * for itself. BDRV_POLL_WHILE() does not support nested locking because From eb9bd46ff658e05e2c0c71fc308f3b811afa87e1 Mon Sep 17 00:00:00 2001 From: Liao Pingfang Date: Mon, 13 Jul 2020 17:04:38 +0800 Subject: [PATCH 2268/2595] migration/migration.c: Remove superfluous breaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove superfluous breaks, as there is a "return" before them. Signed-off-by: Liao Pingfang Signed-off-by: Yi Wang Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Juan Quintela Reviewed-by: Thomas Huth Signed-off-by: Juan Quintela --- migration/migration.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 08519de56f..2ed9923227 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -986,7 +986,6 @@ static void fill_source_migration_info(MigrationInfo *info) /* no migration has happened ever */ /* do not overwrite destination migration status */ return; - break; case MIGRATION_STATUS_SETUP: info->has_status = true; info->has_total_time = false; @@ -1105,7 +1104,6 @@ static void fill_destination_migration_info(MigrationInfo *info) switch (mis->state) { case MIGRATION_STATUS_NONE: return; - break; case MIGRATION_STATUS_SETUP: case MIGRATION_STATUS_CANCELLING: case MIGRATION_STATUS_CANCELLED: From 71e2443e4ca1540db63c0bbf58ae78944c97e993 Mon Sep 17 00:00:00 2001 From: Josh Kunz Date: Mon, 6 Jul 2020 17:10:36 -0700 Subject: [PATCH 2269/2595] linux-user: Use EPROTONOSUPPORT for unimplemented netlink protocols Linux uses the EPROTONOSUPPORT error code[1] if the users requests a netlink socket with an unsupported netlink protocol. This change switches linux-user to use the same code as Linux, instead of EPFNOSUPPORT (which AFAIK is just an anachronistic version of EAFNOSUPPORT). Tested by compiling all linux-user targets on x86. [1]: https://github.com/torvalds/linux/blob/bfe91da29bfad9941d5d703d45e29f0812a20724/net/netlink/af_netlink.c#L683 Signed-off-by: Josh Kunz Reviewed-by: Laurent Vivier Message-Id: <20200707001036.1671982-1-jkz@google.com> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 98ea86ca81..e9f53340cd 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2990,7 +2990,7 @@ static abi_long do_socket(int domain, int type, int protocol) #endif protocol == NETLINK_KOBJECT_UEVENT || protocol == NETLINK_AUDIT)) { - return -TARGET_EPFNOSUPPORT; + return -TARGET_EPROTONOSUPPORT; } if (domain == AF_PACKET || From d8c08b1e6c7b1a5be1ec70e339437823a41b1946 Mon Sep 17 00:00:00 2001 From: Matus Kysel Date: Fri, 26 Jun 2020 14:46:11 +0200 Subject: [PATCH 2270/2595] linux-user: refactor ipc syscall and support of semtimedop syscall Refactoring ipc syscall for s390x and SPARC, so it matches glibc implementation We should add support of semtimedop syscall as new version of glibc 2.31 uses semop based on semtimedop (commit: https://gitlab.com/freedesktop-sdk/mirrors/sourceware/glibc/-/commit/765cdd0bffd77960ae852104fc4ea5edcdb8aed3 ). Signed-off-by: Matus Kysel Message-Id: <20200626124612.58593-2-mkysel@tachyum.com> Message-Id: <20200626124612.58593-3-mkysel@tachyum.com> Reviewed-by: Laurent Vivier [lv: merged PATCH 1 & 2 to avoid build break on PATCH 1] Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 84 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 7 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e9f53340cd..1211e759c2 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -817,9 +817,14 @@ safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags, const struct timespec *, req, struct timespec *, rem) #endif #ifdef __NR_ipc +#ifdef __s390x__ +safe_syscall5(int, ipc, int, call, long, first, long, second, long, third, + void *, ptr) +#else safe_syscall6(int, ipc, int, call, long, first, long, second, long, third, void *, ptr, long, fifth) #endif +#endif #ifdef __NR_msgsnd safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz, int, flags) @@ -1230,7 +1235,8 @@ static inline abi_long copy_to_user_timeval64(abi_ulong target_tv_addr, defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6) || \ defined(TARGET_NR_nanosleep) || defined(TARGET_NR_clock_settime) || \ defined(TARGET_NR_utimensat) || defined(TARGET_NR_mq_timedsend) || \ - defined(TARGET_NR_mq_timedreceive) + defined(TARGET_NR_mq_timedreceive) || defined(TARGET_NR_ipc) || \ + defined(TARGET_NR_semop) || defined(TARGET_NR_semtimedop) static inline abi_long target_to_host_timespec(struct timespec *host_ts, abi_ulong target_addr) { @@ -3878,25 +3884,53 @@ static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf, return 0; } -static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops) +#if defined(TARGET_NR_ipc) || defined(TARGET_NR_semop) || \ + defined(TARGET_NR_semtimedop) + +/* + * This macro is required to handle the s390 variants, which passes the + * arguments in a different order than default. + */ +#ifdef __s390x__ +#define SEMTIMEDOP_IPC_ARGS(__nsops, __sops, __timeout) \ + (__nsops), (__timeout), (__sops) +#else +#define SEMTIMEDOP_IPC_ARGS(__nsops, __sops, __timeout) \ + (__nsops), 0, (__sops), (__timeout) +#endif + +static inline abi_long do_semtimedop(int semid, + abi_long ptr, + unsigned nsops, + abi_long timeout) { struct sembuf sops[nsops]; + struct timespec ts, *pts = NULL; abi_long ret; + if (timeout) { + pts = &ts; + if (target_to_host_timespec(pts, timeout)) { + return -TARGET_EFAULT; + } + } + if (target_to_host_sembuf(sops, ptr, nsops)) return -TARGET_EFAULT; ret = -TARGET_ENOSYS; #ifdef __NR_semtimedop - ret = get_errno(safe_semtimedop(semid, sops, nsops, NULL)); + ret = get_errno(safe_semtimedop(semid, sops, nsops, pts)); #endif #ifdef __NR_ipc if (ret == -TARGET_ENOSYS) { - ret = get_errno(safe_ipc(IPCOP_semtimedop, semid, nsops, 0, sops, 0)); + ret = get_errno(safe_ipc(IPCOP_semtimedop, semid, + SEMTIMEDOP_IPC_ARGS(nsops, sops, (long)pts))); } #endif return ret; } +#endif struct target_msqid_ds { @@ -4056,8 +4090,13 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp, #endif #ifdef __NR_ipc if (ret == -TARGET_ENOSYS) { +#ifdef __s390x__ + ret = get_errno(safe_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg, + host_mb)); +#else ret = get_errno(safe_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg, host_mb, 0)); +#endif } #endif g_free(host_mb); @@ -4066,6 +4105,20 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp, return ret; } +#ifdef __NR_ipc +#if defined(__sparc__) +/* SPARC for msgrcv it does not use the kludge on final 2 arguments. */ +#define MSGRCV_ARGS(__msgp, __msgtyp) __msgp, __msgtyp +#elif defined(__s390x__) +/* The s390 sys_ipc variant has only five parameters. */ +#define MSGRCV_ARGS(__msgp, __msgtyp) \ + ((long int[]){(long int)__msgp, __msgtyp}) +#else +#define MSGRCV_ARGS(__msgp, __msgtyp) \ + ((long int[]){(long int)__msgp, __msgtyp}), 0 +#endif +#endif + static inline abi_long do_msgrcv(int msqid, abi_long msgp, ssize_t msgsz, abi_long msgtyp, int msgflg) @@ -4094,7 +4147,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, #ifdef __NR_ipc if (ret == -TARGET_ENOSYS) { ret = get_errno(safe_ipc(IPCOP_CALL(1, IPCOP_msgrcv), msqid, msgsz, - msgflg, host_mb, msgtyp)); + msgflg, MSGRCV_ARGS(host_mb, msgtyp))); } #endif @@ -4372,7 +4425,20 @@ static abi_long do_ipc(CPUArchState *cpu_env, switch (call) { case IPCOP_semop: - ret = do_semop(first, ptr, second); + ret = do_semtimedop(first, ptr, second, 0); + break; + case IPCOP_semtimedop: + /* + * The s390 sys_ipc variant has only five parameters instead of six + * (as for default variant) and the only difference is the handling of + * SEMTIMEDOP where on s390 the third parameter is used as a pointer + * to a struct timespec where the generic variant uses fifth parameter. + */ +#if defined(TARGET_S390X) + ret = do_semtimedop(first, ptr, second, third); +#else + ret = do_semtimedop(first, ptr, second, fifth); +#endif break; case IPCOP_semget: @@ -9684,7 +9750,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_semop case TARGET_NR_semop: - return do_semop(arg1, arg2, arg3); + return do_semtimedop(arg1, arg2, arg3, 0); +#endif +#ifdef TARGET_NR_semtimedop + case TARGET_NR_semtimedop: + return do_semtimedop(arg1, arg2, arg3, arg4); #endif #ifdef TARGET_NR_semctl case TARGET_NR_semctl: From 4c1850c130a31e6f3cc896a5ba5fb7a602540bc9 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 9 Jul 2020 21:22:17 +0200 Subject: [PATCH 2271/2595] linux-user: Fix Coverity CID 1430271 / CID 1430272 In new functions print_ioctl() and print_syscall_ret_ioctl(), we don't check if lock_user() returns NULL and this would cause a segfault in thunk_print(). If lock_user() returns NULL don't call thunk_print() but prints only the value of the (invalid) pointer. Tested with: # cat ioctl.c #include #include int main(void) { int ret; ret = ioctl(STDOUT_FILENO, TCGETS, 0xdeadbeef); ret = ioctl(STDOUT_FILENO, TCSETSF, 0xdeadbeef); return 0; } # QEMU_STRACE= ./ioctl ... 578 ioctl(1,TCGETS,0xdeadbeef) = -1 errno=2 (Bad address) 578 ioctl(1,TCSETSF,0xdeadbeef) = -1 errno=2 (Bad address) ... # QEMU_STRACE= passwd ... 623 ioctl(0,TCGETS,0x3fffed04) = 0 ({}) 623 ioctl(0,TCSETSF,{}) = 0 ... Reported-by: Peter Maydell Fixes: 79482e5987c8 ("linux-user: Add strace support for printing arguments of ioctl()") Signed-off-by: Laurent Vivier Reviewed-by: Peter Maydell --- linux-user/strace.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 5235b2260c..39554d9039 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -889,8 +889,12 @@ print_syscall_ret_ioctl(const struct syscallname *name, abi_long ret, arg_type++; target_size = thunk_type_size(arg_type, 0); argptr = lock_user(VERIFY_READ, arg2, target_size, 1); - thunk_print(argptr, arg_type); - unlock_user(argptr, arg2, target_size); + if (argptr) { + thunk_print(argptr, arg_type); + unlock_user(argptr, arg2, target_size); + } else { + print_pointer(arg2, 1); + } qemu_log(")"); } } @@ -3119,8 +3123,12 @@ print_ioctl(const struct syscallname *name, arg_type++; target_size = thunk_type_size(arg_type, 0); argptr = lock_user(VERIFY_READ, arg2, target_size, 1); - thunk_print(argptr, arg_type); - unlock_user(argptr, arg2, target_size); + if (argptr) { + thunk_print(argptr, arg_type); + unlock_user(argptr, arg2, target_size); + } else { + print_pointer(arg2, 1); + } break; } break; From d9679ee592dd181854a39ed05db4038c0a6bbf80 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 9 Jul 2020 09:23:31 +0200 Subject: [PATCH 2272/2595] linux-user: add new netlink types Only implement IFLA_PERM_ADDRESS to fix the following error: Unknown host QEMU_IFLA type: 54 The couple of other ones, IFLA_PROP_LIST and IFLA_ALT_IFNAME, have been introduced to be used with RTM_NEWLINKPROP, RTM_DELLINKPROP and RTM_GETLINKPROP that are not implemented by QEMU. Signed-off-by: Laurent Vivier Message-Id: <20200709072332.890440-1-laurent@vivier.eu> --- linux-user/fd-trans.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/fd-trans.c b/linux-user/fd-trans.c index c0687c52e6..5d49a53552 100644 --- a/linux-user/fd-trans.c +++ b/linux-user/fd-trans.c @@ -133,6 +133,9 @@ enum { QEMU_IFLA_NEW_IFINDEX, QEMU_IFLA_MIN_MTU, QEMU_IFLA_MAX_MTU, + QEMU_IFLA_PROP_LIST, + QEMU_IFLA_ALT_IFNAME, + QEMU_IFLA_PERM_ADDRESS, QEMU___IFLA_MAX }; @@ -807,6 +810,7 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr) /* binary stream */ case QEMU_IFLA_ADDRESS: case QEMU_IFLA_BROADCAST: + case QEMU_IFLA_PERM_ADDRESS: /* string */ case QEMU_IFLA_IFNAME: case QEMU_IFLA_QDISC: From 65b261a63a48fbb3b11193361d4ea0c38a3c3dfd Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 9 Jul 2020 09:23:32 +0200 Subject: [PATCH 2273/2595] linux-user: add netlink RTM_SETLINK command This command is needed to be able to boot systemd in a container. $ sudo systemd-nspawn -D /chroot/armhf/sid/ -b Spawning container sid on /chroot/armhf/sid. Press ^] three times within 1s to kill container. systemd 245.6-2 running in system mode. Detected virtualization systemd-nspawn. Detected architecture arm. Welcome to Debian GNU/Linux bullseye/sid! Set hostname to . Failed to enqueue loopback interface start request: Operation not supported Caught , dumped core as pid 3. Exiting PID 1... Container sid failed with error code 255. Signed-off-by: Laurent Vivier Message-Id: <20200709072332.890440-2-laurent@vivier.eu> --- linux-user/fd-trans.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-user/fd-trans.c b/linux-user/fd-trans.c index 5d49a53552..1486c81aaa 100644 --- a/linux-user/fd-trans.c +++ b/linux-user/fd-trans.c @@ -1204,6 +1204,7 @@ static abi_long target_to_host_data_route(struct nlmsghdr *nlh) break; case RTM_NEWLINK: case RTM_DELLINK: + case RTM_SETLINK: if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) { ifi = NLMSG_DATA(nlh); ifi->ifi_type = tswap16(ifi->ifi_type); From 917ebcb170273913bca33d44263bc5fd14f72fd7 Mon Sep 17 00:00:00 2001 From: Basil Salman Date: Mon, 6 Jul 2020 18:50:39 +0300 Subject: [PATCH 2274/2595] qga-win: Fix QGA VSS Provider service stop failure On one hand "guest-fsfreeze-freeze" command, "COM+ System Application service" is stopped, on the other hand "guest-fsfreeze-thaw" stops QGA VSS Provider service from "COM+ Application Admin Catalog". Invoking a series of freeze and thaw commands may result in QGA failing to stop VSS Provider service as "COM+ System Application service" is stopped, which can cause some delay in qga response. In this commit StopService function was changed and VSS Provider service is now stopped using Winsvc library API. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1549425 Signed-off-by: Basil Salman Signed-off-by: Basil Salman Signed-off-by: Michael Roth --- qga/vss-win32/install.cpp | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/qga/vss-win32/install.cpp b/qga/vss-win32/install.cpp index a456841360..40de133774 100644 --- a/qga/vss-win32/install.cpp +++ b/qga/vss-win32/install.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #define BUFFER_SIZE 1024 @@ -509,26 +510,32 @@ namespace _com_util } } -/* Stop QGA VSS provider service from COM+ Application Admin Catalog */ - +/* Stop QGA VSS provider service using Winsvc API */ STDAPI StopService(void) { HRESULT hr; - COMInitializer initializer; - COMPointer pUnknown; - COMPointer pCatalog; + SC_HANDLE manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + SC_HANDLE service = NULL; - int count = 0; + if (!manager) { + errmsg(E_FAIL, "Failed to open service manager"); + hr = E_FAIL; + goto out; + } + service = OpenService(manager, QGA_PROVIDER_NAME, SC_MANAGER_ALL_ACCESS); - chk(QGAProviderFind(QGAProviderCount, (void *)&count)); - if (count) { - chk(CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_INPROC_SERVER, - IID_IUnknown, (void **)pUnknown.replace())); - chk(pUnknown->QueryInterface(IID_ICOMAdminCatalog2, - (void **)pCatalog.replace())); - chk(pCatalog->ShutdownApplication(_bstr_t(QGA_PROVIDER_LNAME))); + if (!service) { + errmsg(E_FAIL, "Failed to open service"); + hr = E_FAIL; + goto out; + } + if (!(ControlService(service, SERVICE_CONTROL_STOP, NULL))) { + errmsg(E_FAIL, "Failed to stop service"); + hr = E_FAIL; } out: + CloseServiceHandle(service); + CloseServiceHandle(manager); return hr; } From 844bd70b5652f30bbace89499f513e3fbbb6457a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 4 Jun 2020 11:44:25 +0200 Subject: [PATCH 2275/2595] qga: fix assert regression on guest-shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 781f2b3d1e ("qga: process_event() simplification"), send_response() is called unconditionally, but will assert when "rsp" is NULL. This may happen with QCO_NO_SUCCESS_RESP commands, such as "guest-shutdown". Fixes: 781f2b3d1e5ef389b44016a897fd55e7a780bf35 Cc: Michael Roth Reported-by: Christian Ehrhardt Signed-off-by: Marc-André Lureau Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Christian Ehrhardt Tested-by: Christian Ehrhardt Cc: qemu-stable@nongnu.org Signed-off-by: Michael Roth --- qga/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qga/main.c b/qga/main.c index f0e454f28d..3febf3b0fd 100644 --- a/qga/main.c +++ b/qga/main.c @@ -531,7 +531,11 @@ static int send_response(GAState *s, const QDict *rsp) QString *payload_qstr, *response_qstr; GIOStatus status; - g_assert(rsp && s->channel); + g_assert(s->channel); + + if (!rsp) { + return 0; + } payload_qstr = qobject_to_json(QOBJECT(rsp)); if (!payload_qstr) { From e47f4765afcab2b78dfa5b0115abf64d1d49a5d3 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Mon, 22 Jun 2020 20:19:35 +0200 Subject: [PATCH 2276/2595] util: Introduce qemu_get_host_name() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function offers operating system agnostic way to fetch host name. It is implemented for both POSIX-like and Windows systems. Signed-off-by: Michal Privoznik Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Cc: qemu-stable@nongnu.org Signed-off-by: Michael Roth --- include/qemu/osdep.h | 10 ++++++++++ util/oslib-posix.c | 35 +++++++++++++++++++++++++++++++++++ util/oslib-win32.c | 13 +++++++++++++ 3 files changed, 58 insertions(+) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 979a403984..4841b5c6b5 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -655,4 +655,14 @@ static inline void qemu_reset_optind(void) #endif } +/** + * qemu_get_host_name: + * @errp: Error object + * + * Operating system agnostic way of querying host name. + * + * Returns allocated hostname (caller should free), NULL on failure. + */ +char *qemu_get_host_name(Error **errp); + #endif diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 72907d4d7f..e60aea85b6 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -794,3 +794,38 @@ void sigaction_invoke(struct sigaction *action, } action->sa_sigaction(info->ssi_signo, &si, NULL); } + +#ifndef HOST_NAME_MAX +# ifdef _POSIX_HOST_NAME_MAX +# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX +# else +# define HOST_NAME_MAX 255 +# endif +#endif + +char *qemu_get_host_name(Error **errp) +{ + long len = -1; + g_autofree char *hostname = NULL; + +#ifdef _SC_HOST_NAME_MAX + len = sysconf(_SC_HOST_NAME_MAX); +#endif /* _SC_HOST_NAME_MAX */ + + if (len < 0) { + len = HOST_NAME_MAX; + } + + /* Unfortunately, gethostname() below does not guarantee a + * NULL terminated string. Therefore, allocate one byte more + * to be sure. */ + hostname = g_new0(char, len + 1); + + if (gethostname(hostname, len) < 0) { + error_setg_errno(errp, errno, + "cannot get hostname"); + return NULL; + } + + return g_steal_pointer(&hostname); +} diff --git a/util/oslib-win32.c b/util/oslib-win32.c index e9b14ab178..3b49d27297 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -808,3 +808,16 @@ bool qemu_write_pidfile(const char *filename, Error **errp) } return true; } + +char *qemu_get_host_name(Error **errp) +{ + wchar_t tmp[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD size = G_N_ELEMENTS(tmp); + + if (GetComputerNameW(tmp, &size) == 0) { + error_setg_win32(errp, GetLastError(), "failed close handle"); + return NULL; + } + + return g_utf16_to_utf8(tmp, size, NULL, NULL, NULL); +} From 0d3a8f32b1e0eca279da1b0cc793efc7250c3daf Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Mon, 22 Jun 2020 20:19:36 +0200 Subject: [PATCH 2277/2595] qga: Use qemu_get_host_name() instead of g_get_host_name() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem with g_get_host_name() is that on the first call it saves the hostname into a global variable and from then on, every subsequent call returns the saved hostname. Even if the hostname changes. This doesn't play nicely with guest agent, because if the hostname is acquired before the guest is set up (e.g. on the first boot, or before DHCP) we will report old, invalid hostname. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1845127 Signed-off-by: Michal Privoznik Reviewed-by: Daniel P. Berrangé Cc: qemu-stable@nongnu.org Signed-off-by: Michael Roth --- qga/commands.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/qga/commands.c b/qga/commands.c index efc8b90281..d3fec807c1 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -515,11 +515,20 @@ int ga_parse_whence(GuestFileWhence *whence, Error **errp) GuestHostName *qmp_guest_get_host_name(Error **errp) { GuestHostName *result = NULL; - gchar const *hostname = g_get_host_name(); - if (hostname != NULL) { - result = g_new0(GuestHostName, 1); - result->host_name = g_strdup(hostname); + g_autofree char *hostname = qemu_get_host_name(errp); + + /* + * We want to avoid using g_get_host_name() because that + * caches the result and we wouldn't reflect changes in the + * host name. + */ + + if (!hostname) { + hostname = g_strdup("localhost"); } + + result = g_new0(GuestHostName, 1); + result->host_name = g_steal_pointer(&hostname); return result; } From e92fb01639cadbeb9c6fc5d5189e35ef3e45836f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 26 Jun 2020 06:13:40 -0700 Subject: [PATCH 2278/2595] MAINTAINERS: Add an entry for OpenSBI firmware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit List me as the maintainer for OpenSBI firmware related files. Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Message-Id: <1593177220-28143-1-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe8139f367..80fa8837e9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2681,6 +2681,13 @@ F: hw/i386/intel_iommu.c F: hw/i386/intel_iommu_internal.h F: include/hw/i386/intel_iommu.h +OpenSBI Firmware +M: Bin Meng +S: Supported +F: pc-bios/opensbi-* +F: .gitlab-ci.d/opensbi.yml +F: .gitlab-ci.d/opensbi/ + Usermode Emulation ------------------ Overall usermode emulation From 2c44bbf32cda5fbf85b697e3a12127f59d2c2e80 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 2 Jul 2020 20:21:51 -0700 Subject: [PATCH 2279/2595] hw/riscv: virt: Sort the SoC memmap table entries Adjust the PCIe memory maps to follow the order. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1593746511-19517-1-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index f7630c8a89..18283e262e 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -60,14 +60,14 @@ static const struct MemmapEntry { [VIRT_TEST] = { 0x100000, 0x1000 }, [VIRT_RTC] = { 0x101000, 0x1000 }, [VIRT_CLINT] = { 0x2000000, 0x10000 }, + [VIRT_PCIE_PIO] = { 0x3000000, 0x10000 }, [VIRT_PLIC] = { 0xc000000, 0x4000000 }, [VIRT_UART0] = { 0x10000000, 0x100 }, [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, [VIRT_FLASH] = { 0x20000000, 0x4000000 }, - [VIRT_DRAM] = { 0x80000000, 0x0 }, - [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 }, - [VIRT_PCIE_PIO] = { 0x03000000, 0x00010000 }, [VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 }, + [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 }, + [VIRT_DRAM] = { 0x80000000, 0x0 }, }; #define VIRT_FLASH_SECTOR_SIZE (256 * KiB) From 43cf723adca9a5e188c664c3b606a585192a599c Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 1 Jul 2020 11:39:46 -0700 Subject: [PATCH 2280/2595] riscv: Unify Qemu's reset vector code path Currently, all riscv machines except sifive_u have identical reset vector code implementations with memory addresses being different for all machines. They can be easily combined into a single function in common code. Move it to common function and let all the machines use the common function. Signed-off-by: Atish Patra Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Tested-by: Bin Meng Message-Id: <20200701183949.398134-2-atish.patra@wdc.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 46 +++++++++++++++++++++++++++++++++++++++++ hw/riscv/sifive_u.c | 1 - hw/riscv/spike.c | 41 +++--------------------------------- hw/riscv/virt.c | 40 +++-------------------------------- include/hw/riscv/boot.h | 2 ++ 5 files changed, 54 insertions(+), 76 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index adb421b91b..3df802380a 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -26,8 +26,11 @@ #include "hw/loader.h" #include "hw/riscv/boot.h" #include "elf.h" +#include "sysemu/device_tree.h" #include "sysemu/qtest.h" +#include + #if defined(TARGET_RISCV32) # define KERNEL_BOOT_ADDRESS 0x80400000 #else @@ -155,3 +158,46 @@ hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, return *start + size; } + +void riscv_setup_rom_reset_vec(hwaddr start_addr, hwaddr rom_base, + hwaddr rom_size, void *fdt) +{ + int i; + + /* reset vector */ + uint32_t reset_vec[8] = { + 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ + 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */ + 0xf1402573, /* csrr a0, mhartid */ +#if defined(TARGET_RISCV32) + 0x0182a283, /* lw t0, 24(t0) */ +#elif defined(TARGET_RISCV64) + 0x0182b283, /* ld t0, 24(t0) */ +#endif + 0x00028067, /* jr t0 */ + 0x00000000, + start_addr, /* start: .dword */ + 0x00000000, + /* dtb: */ + }; + + /* copy in the reset vector in little_endian byte order */ + for (i = 0; i < sizeof(reset_vec) >> 2; i++) { + reset_vec[i] = cpu_to_le32(reset_vec[i]); + } + rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), + rom_base, &address_space_memory); + + /* copy in the device tree */ + if (fdt_pack(fdt) || fdt_totalsize(fdt) > + rom_size - sizeof(reset_vec)) { + error_report("not enough space to store device-tree"); + exit(1); + } + qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt)); + rom_add_blob_fixed_as("mrom.fdt", fdt, fdt_totalsize(fdt), + rom_base + sizeof(reset_vec), + &address_space_memory); + + return; +} diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 7851326988..0695c93d2c 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -56,7 +56,6 @@ #include "sysemu/device_tree.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" -#include "exec/address-spaces.h" #include diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index c107bf3ba1..a8a0588824 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -41,9 +41,6 @@ #include "sysemu/device_tree.h" #include "sysemu/qtest.h" #include "sysemu/sysemu.h" -#include "exec/address-spaces.h" - -#include #if defined(TARGET_RISCV32) # define BIOS_FILENAME "opensbi-riscv32-spike-fw_jump.elf" @@ -165,7 +162,6 @@ static void spike_board_init(MachineState *machine) MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); - int i; unsigned int smp_cpus = machine->smp.cpus; /* Initialize SOC */ @@ -212,40 +208,9 @@ static void spike_board_init(MachineState *machine) } } - /* reset vector */ - uint32_t reset_vec[8] = { - 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ - 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */ - 0xf1402573, /* csrr a0, mhartid */ -#if defined(TARGET_RISCV32) - 0x0182a283, /* lw t0, 24(t0) */ -#elif defined(TARGET_RISCV64) - 0x0182b283, /* ld t0, 24(t0) */ -#endif - 0x00028067, /* jr t0 */ - 0x00000000, - memmap[SPIKE_DRAM].base, /* start: .dword DRAM_BASE */ - 0x00000000, - /* dtb: */ - }; - - /* copy in the reset vector in little_endian byte order */ - for (i = 0; i < sizeof(reset_vec) >> 2; i++) { - reset_vec[i] = cpu_to_le32(reset_vec[i]); - } - rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), - memmap[SPIKE_MROM].base, &address_space_memory); - - /* copy in the device tree */ - if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) > - memmap[SPIKE_MROM].size - sizeof(reset_vec)) { - error_report("not enough space to store device-tree"); - exit(1); - } - qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt)); - rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt), - memmap[SPIKE_MROM].base + sizeof(reset_vec), - &address_space_memory); + /* load the reset vector */ + riscv_setup_rom_reset_vec(memmap[SPIKE_DRAM].base, memmap[SPIKE_MROM].base, + memmap[SPIKE_MROM].size, s->fdt); /* initialize HTIF using symbols found in load_kernel */ htif_mm_init(system_memory, mask_rom, &s->soc.harts[0].env, serial_hd(0)); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 18283e262e..3463cf54aa 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -39,12 +39,9 @@ #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" #include "sysemu/sysemu.h" -#include "exec/address-spaces.h" #include "hw/pci/pci.h" #include "hw/pci-host/gpex.h" -#include - #if defined(TARGET_RISCV32) # define BIOS_FILENAME "opensbi-riscv32-virt-fw_jump.bin" #else @@ -535,40 +532,9 @@ static void virt_machine_init(MachineState *machine) start_addr = virt_memmap[VIRT_FLASH].base; } - /* reset vector */ - uint32_t reset_vec[8] = { - 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ - 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */ - 0xf1402573, /* csrr a0, mhartid */ -#if defined(TARGET_RISCV32) - 0x0182a283, /* lw t0, 24(t0) */ -#elif defined(TARGET_RISCV64) - 0x0182b283, /* ld t0, 24(t0) */ -#endif - 0x00028067, /* jr t0 */ - 0x00000000, - start_addr, /* start: .dword */ - 0x00000000, - /* dtb: */ - }; - - /* copy in the reset vector in little_endian byte order */ - for (i = 0; i < sizeof(reset_vec) >> 2; i++) { - reset_vec[i] = cpu_to_le32(reset_vec[i]); - } - rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), - memmap[VIRT_MROM].base, &address_space_memory); - - /* copy in the device tree */ - if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) > - memmap[VIRT_MROM].size - sizeof(reset_vec)) { - error_report("not enough space to store device-tree"); - exit(1); - } - qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt)); - rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt), - memmap[VIRT_MROM].base + sizeof(reset_vec), - &address_space_memory); + /* load the reset vector */ + riscv_setup_rom_reset_vec(start_addr, virt_memmap[VIRT_MROM].base, + virt_memmap[VIRT_MROM].size, s->fdt); /* create PLIC hart topology configuration string */ plic_hart_config_len = (strlen(VIRT_PLIC_HART_CONFIG) + 1) * smp_cpus; diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index 9daa98da08..3e9759c89a 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -35,5 +35,7 @@ target_ulong riscv_load_kernel(const char *kernel_filename, symbol_fn_t sym_cb); hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, uint64_t kernel_entry, hwaddr *start); +void riscv_setup_rom_reset_vec(hwaddr saddr, hwaddr rom_base, + hwaddr rom_size, void *fdt); #endif /* RISCV_BOOT_H */ From 66b1205bc5ab8bb3f5e12fa4155bbeb56e6724e9 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 1 Jul 2020 11:39:47 -0700 Subject: [PATCH 2281/2595] RISC-V: Copy the fdt in dram instead of ROM Currently, the fdt is copied to the ROM after the reset vector. The firmware has to copy it to DRAM. Instead of this, directly copy the device tree to a pre-computed dram address. The device tree load address should be as far as possible from kernel and initrd images. That's why it is kept at the end of the DRAM or 4GB whichever is lesser. Signed-off-by: Atish Patra Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Tested-by: Bin Meng Message-Id: <20200701183949.398134-3-atish.patra@wdc.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 53 +++++++++++++++++++++++++++++------------ hw/riscv/sifive_u.c | 28 ++++++++++------------ hw/riscv/spike.c | 7 +++++- hw/riscv/virt.c | 7 +++++- include/hw/riscv/boot.h | 4 +++- 5 files changed, 66 insertions(+), 33 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 3df802380a..c62f545f15 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -159,45 +159,68 @@ hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, return *start + size; } +uint32_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) +{ + uint32_t temp, fdt_addr; + hwaddr dram_end = dram_base + mem_size; + int fdtsize = fdt_totalsize(fdt); + + if (fdtsize <= 0) { + error_report("invalid device-tree"); + exit(1); + } + + /* + * We should put fdt as far as possible to avoid kernel/initrd overwriting + * its content. But it should be addressable by 32 bit system as well. + * Thus, put it at an aligned address that less than fdt size from end of + * dram or 4GB whichever is lesser. + */ + temp = MIN(dram_end, 4096 * MiB); + fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB); + + fdt_pack(fdt); + /* copy in the device tree */ + qemu_fdt_dumpdtb(fdt, fdtsize); + + rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, + &address_space_memory); + + return fdt_addr; +} + void riscv_setup_rom_reset_vec(hwaddr start_addr, hwaddr rom_base, - hwaddr rom_size, void *fdt) + hwaddr rom_size, + uint32_t fdt_load_addr, void *fdt) { int i; /* reset vector */ - uint32_t reset_vec[8] = { + uint32_t reset_vec[10] = { 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ - 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */ 0xf1402573, /* csrr a0, mhartid */ #if defined(TARGET_RISCV32) + 0x0202a583, /* lw a1, 32(t0) */ 0x0182a283, /* lw t0, 24(t0) */ #elif defined(TARGET_RISCV64) + 0x0202b583, /* ld a1, 32(t0) */ 0x0182b283, /* ld t0, 24(t0) */ #endif 0x00028067, /* jr t0 */ 0x00000000, start_addr, /* start: .dword */ + 0x00000000, + fdt_load_addr, /* fdt_laddr: .dword */ 0x00000000, /* dtb: */ }; /* copy in the reset vector in little_endian byte order */ - for (i = 0; i < sizeof(reset_vec) >> 2; i++) { + for (i = 0; i < ARRAY_SIZE(reset_vec); i++) { reset_vec[i] = cpu_to_le32(reset_vec[i]); } rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), rom_base, &address_space_memory); - /* copy in the device tree */ - if (fdt_pack(fdt) || fdt_totalsize(fdt) > - rom_size - sizeof(reset_vec)) { - error_report("not enough space to store device-tree"); - exit(1); - } - qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt)); - rom_add_blob_fixed_as("mrom.fdt", fdt, fdt_totalsize(fdt), - rom_base + sizeof(reset_vec), - &address_space_memory); - return; } diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 0695c93d2c..39923209f4 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -379,6 +379,7 @@ static void sifive_u_machine_init(MachineState *machine) MemoryRegion *flash0 = g_new(MemoryRegion, 1); target_ulong start_addr = memmap[SIFIVE_U_DRAM].base; int i; + uint32_t fdt_load_addr; /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); @@ -450,40 +451,37 @@ static void sifive_u_machine_init(MachineState *machine) } } + /* Compute the fdt load address in dram */ + fdt_load_addr = riscv_load_fdt(memmap[SIFIVE_U_DRAM].base, + machine->ram_size, s->fdt); + /* reset vector */ - uint32_t reset_vec[8] = { + uint32_t reset_vec[11] = { s->msel, /* MSEL pin state */ 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ - 0x01c28593, /* addi a1, t0, %pcrel_lo(1b) */ 0xf1402573, /* csrr a0, mhartid */ #if defined(TARGET_RISCV32) + 0x0202a583, /* lw a1, 32(t0) */ 0x0182a283, /* lw t0, 24(t0) */ #elif defined(TARGET_RISCV64) - 0x0182e283, /* lwu t0, 24(t0) */ + 0x0202b583, /* ld a1, 32(t0) */ + 0x0182b283, /* ld t0, 24(t0) */ #endif 0x00028067, /* jr t0 */ 0x00000000, start_addr, /* start: .dword */ + 0x00000000, + fdt_load_addr, /* fdt_laddr: .dword */ + 0x00000000, /* dtb: */ }; /* copy in the reset vector in little_endian byte order */ - for (i = 0; i < sizeof(reset_vec) >> 2; i++) { + for (i = 0; i < ARRAY_SIZE(reset_vec); i++) { reset_vec[i] = cpu_to_le32(reset_vec[i]); } rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), memmap[SIFIVE_U_MROM].base, &address_space_memory); - - /* copy in the device tree */ - if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) > - memmap[SIFIVE_U_MROM].size - sizeof(reset_vec)) { - error_report("not enough space to store device-tree"); - exit(1); - } - qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt)); - rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt), - memmap[SIFIVE_U_MROM].base + sizeof(reset_vec), - &address_space_memory); } static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index a8a0588824..13fa0455e3 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -163,6 +163,7 @@ static void spike_board_init(MachineState *machine) MemoryRegion *main_mem = g_new(MemoryRegion, 1); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); unsigned int smp_cpus = machine->smp.cpus; + uint32_t fdt_load_addr; /* Initialize SOC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, @@ -208,9 +209,13 @@ static void spike_board_init(MachineState *machine) } } + /* Compute the fdt load address in dram */ + fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base, + machine->ram_size, s->fdt); /* load the reset vector */ riscv_setup_rom_reset_vec(memmap[SPIKE_DRAM].base, memmap[SPIKE_MROM].base, - memmap[SPIKE_MROM].size, s->fdt); + memmap[SPIKE_MROM].size, + fdt_load_addr, s->fdt); /* initialize HTIF using symbols found in load_kernel */ htif_mm_init(system_memory, mask_rom, &s->soc.harts[0].env, serial_hd(0)); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 3463cf54aa..9d87319f70 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -478,6 +478,7 @@ static void virt_machine_init(MachineState *machine) char *plic_hart_config; size_t plic_hart_config_len; target_ulong start_addr = memmap[VIRT_DRAM].base; + uint32_t fdt_load_addr; int i; unsigned int smp_cpus = machine->smp.cpus; @@ -532,9 +533,13 @@ static void virt_machine_init(MachineState *machine) start_addr = virt_memmap[VIRT_FLASH].base; } + /* Compute the fdt load address in dram */ + fdt_load_addr = riscv_load_fdt(memmap[VIRT_DRAM].base, + machine->ram_size, s->fdt); /* load the reset vector */ riscv_setup_rom_reset_vec(start_addr, virt_memmap[VIRT_MROM].base, - virt_memmap[VIRT_MROM].size, s->fdt); + virt_memmap[VIRT_MROM].size, + fdt_load_addr, s->fdt); /* create PLIC hart topology configuration string */ plic_hart_config_len = (strlen(VIRT_PLIC_HART_CONFIG) + 1) * smp_cpus; diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index 3e9759c89a..35b6ddf710 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -35,7 +35,9 @@ target_ulong riscv_load_kernel(const char *kernel_filename, symbol_fn_t sym_cb); hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, uint64_t kernel_entry, hwaddr *start); +uint32_t riscv_load_fdt(hwaddr dram_start, uint64_t dram_size, void *fdt); void riscv_setup_rom_reset_vec(hwaddr saddr, hwaddr rom_base, - hwaddr rom_size, void *fdt); + hwaddr rom_size, + uint32_t fdt_load_addr, void *fdt); #endif /* RISCV_BOOT_H */ From dc144fe13d336caac2f03b57f1df738e84f984ec Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 1 Jul 2020 11:39:48 -0700 Subject: [PATCH 2282/2595] riscv: Add opensbi firmware dynamic support OpenSBI is the default firmware in Qemu and has various firmware loading options. Currently, qemu loader uses fw_jump which has a compile time pre-defined address where fdt & kernel image must reside. This puts a constraint on image size of the Linux kernel depending on the fdt location and available memory. However, fw_dynamic allows the loader to specify the next stage location (i.e. Linux kernel/U-Boot) in memory and other configurable boot options available in OpenSBI. Add support for OpenSBI dynamic firmware loading support. This doesn't break existing setup and fw_jump will continue to work as it is. Any other firmware will continue to work without any issues as long as it doesn't expect anything specific from loader in "a2" register. Signed-off-by: Atish Patra Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Tested-by: Bin Meng Message-Id: <20200701183949.398134-4-atish.patra@wdc.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 42 +++++++++++++++++++++--- hw/riscv/sifive_u.c | 20 +++++++++--- hw/riscv/spike.c | 13 ++++++-- hw/riscv/virt.c | 12 +++++-- include/hw/riscv/boot.h | 5 ++- include/hw/riscv/boot_opensbi.h | 58 +++++++++++++++++++++++++++++++++ 6 files changed, 134 insertions(+), 16 deletions(-) create mode 100644 include/hw/riscv/boot_opensbi.h diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index c62f545f15..feff6e3f4e 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -25,6 +25,7 @@ #include "hw/boards.h" #include "hw/loader.h" #include "hw/riscv/boot.h" +#include "hw/riscv/boot_opensbi.h" #include "elf.h" #include "sysemu/device_tree.h" #include "sysemu/qtest.h" @@ -33,8 +34,10 @@ #if defined(TARGET_RISCV32) # define KERNEL_BOOT_ADDRESS 0x80400000 +#define fw_dynamic_info_data(__val) cpu_to_le32(__val) #else # define KERNEL_BOOT_ADDRESS 0x80200000 +#define fw_dynamic_info_data(__val) cpu_to_le64(__val) #endif void riscv_find_and_load_firmware(MachineState *machine, @@ -189,15 +192,45 @@ uint32_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) return fdt_addr; } +void riscv_rom_copy_firmware_info(hwaddr rom_base, hwaddr rom_size, + uint32_t reset_vec_size, uint64_t kernel_entry) +{ + struct fw_dynamic_info dinfo; + size_t dinfo_len; + + dinfo.magic = fw_dynamic_info_data(FW_DYNAMIC_INFO_MAGIC_VALUE); + dinfo.version = fw_dynamic_info_data(FW_DYNAMIC_INFO_VERSION); + dinfo.next_mode = fw_dynamic_info_data(FW_DYNAMIC_INFO_NEXT_MODE_S); + dinfo.next_addr = fw_dynamic_info_data(kernel_entry); + dinfo.options = 0; + dinfo.boot_hart = 0; + dinfo_len = sizeof(dinfo); + + /** + * copy the dynamic firmware info. This information is specific to + * OpenSBI but doesn't break any other firmware as long as they don't + * expect any certain value in "a2" register. + */ + if (dinfo_len > (rom_size - reset_vec_size)) { + error_report("not enough space to store dynamic firmware info"); + exit(1); + } + + rom_add_blob_fixed_as("mrom.finfo", &dinfo, dinfo_len, + rom_base + reset_vec_size, + &address_space_memory); +} + void riscv_setup_rom_reset_vec(hwaddr start_addr, hwaddr rom_base, - hwaddr rom_size, + hwaddr rom_size, uint64_t kernel_entry, uint32_t fdt_load_addr, void *fdt) { int i; /* reset vector */ uint32_t reset_vec[10] = { - 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ + 0x00000297, /* 1: auipc t0, %pcrel_hi(fw_dyn) */ + 0x02828613, /* addi a2, t0, %pcrel_lo(1b) */ 0xf1402573, /* csrr a0, mhartid */ #if defined(TARGET_RISCV32) 0x0202a583, /* lw a1, 32(t0) */ @@ -207,12 +240,11 @@ void riscv_setup_rom_reset_vec(hwaddr start_addr, hwaddr rom_base, 0x0182b283, /* ld t0, 24(t0) */ #endif 0x00028067, /* jr t0 */ - 0x00000000, start_addr, /* start: .dword */ 0x00000000, fdt_load_addr, /* fdt_laddr: .dword */ 0x00000000, - /* dtb: */ + /* fw_dyn: */ }; /* copy in the reset vector in little_endian byte order */ @@ -221,6 +253,8 @@ void riscv_setup_rom_reset_vec(hwaddr start_addr, hwaddr rom_base, } rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), rom_base, &address_space_memory); + riscv_rom_copy_firmware_info(rom_base, rom_size, sizeof(reset_vec), + kernel_entry); return; } diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 39923209f4..46e6ed90ca 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -380,6 +380,7 @@ static void sifive_u_machine_init(MachineState *machine) target_ulong start_addr = memmap[SIFIVE_U_DRAM].base; int i; uint32_t fdt_load_addr; + uint64_t kernel_entry; /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); @@ -436,8 +437,7 @@ static void sifive_u_machine_init(MachineState *machine) riscv_find_and_load_firmware(machine, BIOS_FILENAME, start_addr, NULL); if (machine->kernel_filename) { - uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename, - NULL); + kernel_entry = riscv_load_kernel(machine->kernel_filename, NULL); if (machine->initrd_filename) { hwaddr start; @@ -449,6 +449,12 @@ static void sifive_u_machine_init(MachineState *machine) qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end", end); } + } else { + /* + * If dynamic firmware is used, it doesn't know where is the next mode + * if kernel argument is not set. + */ + kernel_entry = 0; } /* Compute the fdt load address in dram */ @@ -458,7 +464,8 @@ static void sifive_u_machine_init(MachineState *machine) /* reset vector */ uint32_t reset_vec[11] = { s->msel, /* MSEL pin state */ - 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ + 0x00000297, /* 1: auipc t0, %pcrel_hi(fw_dyn) */ + 0x02828613, /* addi a2, t0, %pcrel_lo(1b) */ 0xf1402573, /* csrr a0, mhartid */ #if defined(TARGET_RISCV32) 0x0202a583, /* lw a1, 32(t0) */ @@ -468,12 +475,11 @@ static void sifive_u_machine_init(MachineState *machine) 0x0182b283, /* ld t0, 24(t0) */ #endif 0x00028067, /* jr t0 */ - 0x00000000, start_addr, /* start: .dword */ 0x00000000, fdt_load_addr, /* fdt_laddr: .dword */ 0x00000000, - /* dtb: */ + /* fw_dyn: */ }; /* copy in the reset vector in little_endian byte order */ @@ -482,6 +488,10 @@ static void sifive_u_machine_init(MachineState *machine) } rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), memmap[SIFIVE_U_MROM].base, &address_space_memory); + + riscv_rom_copy_firmware_info(memmap[SIFIVE_U_MROM].base, + memmap[SIFIVE_U_MROM].size, + sizeof(reset_vec), kernel_entry); } static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 13fa0455e3..b17d96aec7 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -164,6 +164,7 @@ static void spike_board_init(MachineState *machine) MemoryRegion *mask_rom = g_new(MemoryRegion, 1); unsigned int smp_cpus = machine->smp.cpus; uint32_t fdt_load_addr; + uint64_t kernel_entry; /* Initialize SOC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, @@ -194,8 +195,8 @@ static void spike_board_init(MachineState *machine) htif_symbol_callback); if (machine->kernel_filename) { - uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename, - htif_symbol_callback); + kernel_entry = riscv_load_kernel(machine->kernel_filename, + htif_symbol_callback); if (machine->initrd_filename) { hwaddr start; @@ -207,6 +208,12 @@ static void spike_board_init(MachineState *machine) qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end", end); } + } else { + /* + * If dynamic firmware is used, it doesn't know where is the next mode + * if kernel argument is not set. + */ + kernel_entry = 0; } /* Compute the fdt load address in dram */ @@ -214,7 +221,7 @@ static void spike_board_init(MachineState *machine) machine->ram_size, s->fdt); /* load the reset vector */ riscv_setup_rom_reset_vec(memmap[SPIKE_DRAM].base, memmap[SPIKE_MROM].base, - memmap[SPIKE_MROM].size, + memmap[SPIKE_MROM].size, kernel_entry, fdt_load_addr, s->fdt); /* initialize HTIF using symbols found in load_kernel */ diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 9d87319f70..bc25ec69f7 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -479,6 +479,7 @@ static void virt_machine_init(MachineState *machine) size_t plic_hart_config_len; target_ulong start_addr = memmap[VIRT_DRAM].base; uint32_t fdt_load_addr; + uint64_t kernel_entry; int i; unsigned int smp_cpus = machine->smp.cpus; @@ -510,8 +511,7 @@ static void virt_machine_init(MachineState *machine) memmap[VIRT_DRAM].base, NULL); if (machine->kernel_filename) { - uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename, - NULL); + kernel_entry = riscv_load_kernel(machine->kernel_filename, NULL); if (machine->initrd_filename) { hwaddr start; @@ -523,6 +523,12 @@ static void virt_machine_init(MachineState *machine) qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end", end); } + } else { + /* + * If dynamic firmware is used, it doesn't know where is the next mode + * if kernel argument is not set. + */ + kernel_entry = 0; } if (drive_get(IF_PFLASH, 0, 0)) { @@ -538,7 +544,7 @@ static void virt_machine_init(MachineState *machine) machine->ram_size, s->fdt); /* load the reset vector */ riscv_setup_rom_reset_vec(start_addr, virt_memmap[VIRT_MROM].base, - virt_memmap[VIRT_MROM].size, + virt_memmap[VIRT_MROM].size, kernel_entry, fdt_load_addr, s->fdt); /* create PLIC hart topology configuration string */ diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index 35b6ddf710..451338780a 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -37,7 +37,10 @@ hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, uint64_t kernel_entry, hwaddr *start); uint32_t riscv_load_fdt(hwaddr dram_start, uint64_t dram_size, void *fdt); void riscv_setup_rom_reset_vec(hwaddr saddr, hwaddr rom_base, - hwaddr rom_size, + hwaddr rom_size, uint64_t kernel_entry, uint32_t fdt_load_addr, void *fdt); +void riscv_rom_copy_firmware_info(hwaddr rom_base, hwaddr rom_size, + uint32_t reset_vec_size, + uint64_t kernel_entry); #endif /* RISCV_BOOT_H */ diff --git a/include/hw/riscv/boot_opensbi.h b/include/hw/riscv/boot_opensbi.h new file mode 100644 index 0000000000..0d5ddd6c3d --- /dev/null +++ b/include/hw/riscv/boot_opensbi.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Based on include/sbi/{fw_dynamic.h,sbi_scratch.h} from the OpenSBI project. + */ +#ifndef OPENSBI_H +#define OPENSBI_H + +/** Expected value of info magic ('OSBI' ascii string in hex) */ +#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f + +/** Maximum supported info version */ +#define FW_DYNAMIC_INFO_VERSION 0x2 + +/** Possible next mode values */ +#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0 +#define FW_DYNAMIC_INFO_NEXT_MODE_S 0x1 +#define FW_DYNAMIC_INFO_NEXT_MODE_M 0x3 + +enum sbi_scratch_options { + /** Disable prints during boot */ + SBI_SCRATCH_NO_BOOT_PRINTS = (1 << 0), + /** Enable runtime debug prints */ + SBI_SCRATCH_DEBUG_PRINTS = (1 << 1), +}; + +/** Representation dynamic info passed by previous booting stage */ +struct fw_dynamic_info { + /** Info magic */ + target_long magic; + /** Info version */ + target_long version; + /** Next booting stage address */ + target_long next_addr; + /** Next booting stage mode */ + target_long next_mode; + /** Options for OpenSBI library */ + target_long options; + /** + * Preferred boot HART id + * + * It is possible that the previous booting stage uses same link + * address as the FW_DYNAMIC firmware. In this case, the relocation + * lottery mechanism can potentially overwrite the previous booting + * stage while other HARTs are still running in the previous booting + * stage leading to boot-time crash. To avoid this boot-time crash, + * the previous booting stage can specify last HART that will jump + * to the FW_DYNAMIC firmware as the preferred boot HART. + * + * To avoid specifying a preferred boot HART, the previous booting + * stage can set it to -1UL which will force the FW_DYNAMIC firmware + * to use the relocation lottery mechanism. + */ + target_long boot_hart; +}; + +#endif From 8590f53661ec678fd3aa97b4da212b0c00056c2e Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 1 Jul 2020 11:39:49 -0700 Subject: [PATCH 2283/2595] RISC-V: Support 64 bit start address Even though the start address in ROM code is declared as a 64 bit address for RV64, it can't be used as upper bits are set to zero in ROM code. Update the ROM code correctly to reflect the 64bit value. Signed-off-by: Atish Patra Reviewed-by: Bin Meng Tested-by: Bin Meng Message-Id: <20200701183949.398134-5-atish.patra@wdc.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 6 +++++- hw/riscv/sifive_u.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index feff6e3f4e..4c6c101ff1 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -226,7 +226,11 @@ void riscv_setup_rom_reset_vec(hwaddr start_addr, hwaddr rom_base, uint32_t fdt_load_addr, void *fdt) { int i; + uint32_t start_addr_hi32 = 0x00000000; + #if defined(TARGET_RISCV64) + start_addr_hi32 = start_addr >> 32; + #endif /* reset vector */ uint32_t reset_vec[10] = { 0x00000297, /* 1: auipc t0, %pcrel_hi(fw_dyn) */ @@ -241,7 +245,7 @@ void riscv_setup_rom_reset_vec(hwaddr start_addr, hwaddr rom_base, #endif 0x00028067, /* jr t0 */ start_addr, /* start: .dword */ - 0x00000000, + start_addr_hi32, fdt_load_addr, /* fdt_laddr: .dword */ 0x00000000, /* fw_dyn: */ diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 46e6ed90ca..6595ab3f87 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -378,6 +378,7 @@ static void sifive_u_machine_init(MachineState *machine) MemoryRegion *main_mem = g_new(MemoryRegion, 1); MemoryRegion *flash0 = g_new(MemoryRegion, 1); target_ulong start_addr = memmap[SIFIVE_U_DRAM].base; + uint32_t start_addr_hi32 = 0x00000000; int i; uint32_t fdt_load_addr; uint64_t kernel_entry; @@ -460,6 +461,9 @@ static void sifive_u_machine_init(MachineState *machine) /* Compute the fdt load address in dram */ fdt_load_addr = riscv_load_fdt(memmap[SIFIVE_U_DRAM].base, machine->ram_size, s->fdt); + #if defined(TARGET_RISCV64) + start_addr_hi32 = start_addr >> 32; + #endif /* reset vector */ uint32_t reset_vec[11] = { @@ -476,7 +480,7 @@ static void sifive_u_machine_init(MachineState *machine) #endif 0x00028067, /* jr t0 */ start_addr, /* start: .dword */ - 0x00000000, + start_addr_hi32, fdt_load_addr, /* fdt_laddr: .dword */ 0x00000000, /* fw_dyn: */ From 9eb8b14a70e57bc1449afc08aa4bf3131ee680d8 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 9 Jul 2020 03:05:43 -0700 Subject: [PATCH 2284/2595] hw/riscv: Modify MROM size to end at 0x10000 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At present the size of Mask ROM for sifive_u / spike / virt machines is set to 0x11000, which ends at an unusual address. This changes the size to 0xf000 so that it ends at 0x10000. Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Message-Id: <1594289144-24723-1-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 2 +- hw/riscv/spike.c | 2 +- hw/riscv/virt.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 6595ab3f87..19a976c9a6 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -70,7 +70,7 @@ static const struct MemmapEntry { hwaddr size; } sifive_u_memmap[] = { [SIFIVE_U_DEBUG] = { 0x0, 0x100 }, - [SIFIVE_U_MROM] = { 0x1000, 0x11000 }, + [SIFIVE_U_MROM] = { 0x1000, 0xf000 }, [SIFIVE_U_CLINT] = { 0x2000000, 0x10000 }, [SIFIVE_U_L2LIM] = { 0x8000000, 0x2000000 }, [SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 }, diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index b17d96aec7..7b23a297fc 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -52,7 +52,7 @@ static const struct MemmapEntry { hwaddr base; hwaddr size; } spike_memmap[] = { - [SPIKE_MROM] = { 0x1000, 0x11000 }, + [SPIKE_MROM] = { 0x1000, 0xf000 }, [SPIKE_CLINT] = { 0x2000000, 0x10000 }, [SPIKE_DRAM] = { 0x80000000, 0x0 }, }; diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index bc25ec69f7..55a907bb35 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -53,7 +53,7 @@ static const struct MemmapEntry { hwaddr size; } virt_memmap[] = { [VIRT_DEBUG] = { 0x0, 0x100 }, - [VIRT_MROM] = { 0x1000, 0x11000 }, + [VIRT_MROM] = { 0x1000, 0xf000 }, [VIRT_TEST] = { 0x100000, 0x1000 }, [VIRT_RTC] = { 0x101000, 0x1000 }, [VIRT_CLINT] = { 0x2000000, 0x10000 }, From 7acafcfa844fd93f5ff073077007627338bd6739 Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Fri, 10 Jul 2020 18:48:15 +0800 Subject: [PATCH 2285/2595] target/riscv: fix rsub gvec tcg_assert_listed_vecop assertion gvec should provide vecop_list to avoid: "tcg_tcg_assert_listed_vecop: code should not be reached bug" assertion. Signed-off-by: Frank Chang Reviewed-by: Richard Henderson Message-Id: <20200710104920.13550-2-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.inc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index dc333e6a91..433cdacbe1 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -958,22 +958,27 @@ static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs, TCGv_i64 c, uint32_t oprsz, uint32_t maxsz) { + static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 }; static const GVecGen2s rsub_op[4] = { { .fni8 = gen_vec_rsub8_i64, .fniv = gen_rsub_vec, .fno = gen_helper_vec_rsubs8, + .opt_opc = vecop_list, .vece = MO_8 }, { .fni8 = gen_vec_rsub16_i64, .fniv = gen_rsub_vec, .fno = gen_helper_vec_rsubs16, + .opt_opc = vecop_list, .vece = MO_16 }, { .fni4 = gen_rsub_i32, .fniv = gen_rsub_vec, .fno = gen_helper_vec_rsubs32, + .opt_opc = vecop_list, .vece = MO_32 }, { .fni8 = gen_rsub_i64, .fniv = gen_rsub_vec, .fno = gen_helper_vec_rsubs64, + .opt_opc = vecop_list, .prefer_i64 = TCG_TARGET_REG_BITS == 64, .vece = MO_64 }, }; From 1989205c4e973bc7f9fac0ce0700993f30582538 Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Fri, 10 Jul 2020 18:48:16 +0800 Subject: [PATCH 2286/2595] target/riscv: correct the gvec IR called in gen_vec_rsub16_i64() Signed-off-by: Frank Chang Reviewed-by: Richard Henderson Message-Id: <20200710104920.13550-3-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.inc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 433cdacbe1..7cd08f0868 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -937,7 +937,7 @@ static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) { - tcg_gen_vec_sub8_i64(d, b, a); + tcg_gen_vec_sub16_i64(d, b, a); } static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) From a69f97c1110205bc173657c77ce2d16877cad683 Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Fri, 10 Jul 2020 18:48:17 +0800 Subject: [PATCH 2287/2595] target/riscv: fix return value of do_opivx_widen() do_opivx_widen() should return false if check function returns false. Signed-off-by: Frank Chang Reviewed-by: Richard Henderson Message-Id: <20200710104920.13550-4-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.inc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 7cd08f0868..c0b7375927 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -1151,7 +1151,7 @@ static bool do_opivx_widen(DisasContext *s, arg_rmrr *a, if (opivx_widen_check(s, a)) { return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); } - return true; + return false; } #define GEN_OPIVX_WIDEN_TRANS(NAME) \ From fbcbafa2c1c33ae6630e7717f7f4141befb5b31a Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Fri, 10 Jul 2020 18:48:18 +0800 Subject: [PATCH 2288/2595] target/riscv: fix vill bit index in vtype register vill bit is at vtype[XLEN-1]. Signed-off-by: Frank Chang Reviewed-by: Richard Henderson Message-Id: <20200710104920.13550-5-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index eef20ca6e5..a804a5d0ba 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -98,7 +98,7 @@ FIELD(VTYPE, VLMUL, 0, 2) FIELD(VTYPE, VSEW, 2, 3) FIELD(VTYPE, VEDIV, 5, 2) FIELD(VTYPE, RESERVED, 7, sizeof(target_ulong) * 8 - 9) -FIELD(VTYPE, VILL, sizeof(target_ulong) * 8 - 2, 1) +FIELD(VTYPE, VILL, sizeof(target_ulong) * 8 - 1, 1) struct CPURISCVState { target_ulong gpr[32]; From 940aabb9f47712da87182fee7163f1d3f7def36d Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 9 Jul 2020 15:04:48 -0700 Subject: [PATCH 2289/2595] hw/char: Convert the Ibex UART to use the qdev Clock model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Conver the Ibex UART to use the recently added qdev-clock functions. Signed-off-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-id: b0136fad870a29049959ec161c1217b967d7e19d.1594332223.git.alistair.francis@wdc.com Message-Id: --- hw/char/ibex_uart.c | 30 +++++++++++++++++++++++++++--- include/hw/char/ibex_uart.h | 3 +++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c index 45cd724998..ab6247de89 100644 --- a/hw/char/ibex_uart.c +++ b/hw/char/ibex_uart.c @@ -28,6 +28,7 @@ #include "qemu/osdep.h" #include "hw/char/ibex_uart.h" #include "hw/irq.h" +#include "hw/qdev-clock.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qemu/log.h" @@ -203,6 +204,17 @@ static void ibex_uart_reset(DeviceState *dev) ibex_uart_update_irqs(s); } +static uint64_t ibex_uart_get_baud(IbexUartState *s) +{ + uint64_t baud; + + baud = ((s->uart_ctrl & UART_CTRL_NCO) >> 16); + baud *= clock_get_hz(s->f_clk); + baud >>= 20; + + return baud; +} + static uint64_t ibex_uart_read(void *opaque, hwaddr addr, unsigned int size) { @@ -329,9 +341,7 @@ static void ibex_uart_write(void *opaque, hwaddr addr, "%s: UART_CTRL_RXBLVL is not supported\n", __func__); } if (value & UART_CTRL_NCO) { - uint64_t baud = ((value & UART_CTRL_NCO) >> 16); - baud *= 1000; - baud >>= 20; + uint64_t baud = ibex_uart_get_baud(s); s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; } @@ -385,6 +395,16 @@ static void ibex_uart_write(void *opaque, hwaddr addr, } } +static void ibex_uart_clk_update(void *opaque) +{ + IbexUartState *s = opaque; + + /* recompute uart's speed on clock change */ + uint64_t baud = ibex_uart_get_baud(s); + + s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; +} + static void fifo_trigger_update(void *opaque) { IbexUartState *s = opaque; @@ -444,6 +464,10 @@ static void ibex_uart_init(Object *obj) { IbexUartState *s = IBEX_UART(obj); + s->f_clk = qdev_init_clock_in(DEVICE(obj), "f_clock", + ibex_uart_clk_update, s); + clock_set_hz(s->f_clk, IBEX_UART_CLOCK); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark); sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark); sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty); diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h index 2bec772615..6d81051161 100644 --- a/include/hw/char/ibex_uart.h +++ b/include/hw/char/ibex_uart.h @@ -72,6 +72,7 @@ #define IBEX_UART_TIMEOUT_CTRL 0x2c #define IBEX_UART_TX_FIFO_SIZE 16 +#define IBEX_UART_CLOCK 50000000 /* 50MHz clock */ #define TYPE_IBEX_UART "ibex-uart" #define IBEX_UART(obj) \ @@ -101,6 +102,8 @@ typedef struct { uint32_t uart_val; uint32_t uart_timeout_ctrl; + Clock *f_clk; + CharBackend chr; qemu_irq tx_watermark; qemu_irq rx_watermark; From 59093cc407cb044c72aa786006a07bd404eb36b9 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 9 Jul 2020 15:04:51 -0700 Subject: [PATCH 2290/2595] hw/char: Convert the Ibex UART to use the registerfields API Signed-off-by: Alistair Francis Message-id: 06372c9cdeec715077899e71c858d9f0a2a3395b.1594332223.git.alistair.francis@wdc.com Message-Id: <06372c9cdeec715077899e71c858d9f0a2a3395b.1594332223.git.alistair.francis@wdc.com> --- hw/char/ibex_uart.c | 130 ++++++++++++++++++------------------ include/hw/char/ibex_uart.h | 76 ++++++++++----------- 2 files changed, 100 insertions(+), 106 deletions(-) diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c index ab6247de89..cc49a35013 100644 --- a/hw/char/ibex_uart.c +++ b/hw/char/ibex_uart.c @@ -36,25 +36,25 @@ static void ibex_uart_update_irqs(IbexUartState *s) { - if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) { + if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_WATERMARK_MASK) { qemu_set_irq(s->tx_watermark, 1); } else { qemu_set_irq(s->tx_watermark, 0); } - if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) { + if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_WATERMARK_MASK) { qemu_set_irq(s->rx_watermark, 1); } else { qemu_set_irq(s->rx_watermark, 0); } - if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) { + if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_EMPTY_MASK) { qemu_set_irq(s->tx_empty, 1); } else { qemu_set_irq(s->tx_empty, 0); } - if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) { + if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_OVERFLOW_MASK) { qemu_set_irq(s->rx_overflow, 1); } else { qemu_set_irq(s->rx_overflow, 0); @@ -65,7 +65,7 @@ static int ibex_uart_can_receive(void *opaque) { IbexUartState *s = opaque; - if (s->uart_ctrl & UART_CTRL_RX_ENABLE) { + if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) { return 1; } @@ -75,16 +75,16 @@ static int ibex_uart_can_receive(void *opaque) static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size) { IbexUartState *s = opaque; - uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL) - >> FIFO_CTRL_RXILVL_SHIFT; + uint8_t rx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_RXILVL_MASK) + >> R_FIFO_CTRL_RXILVL_SHIFT; s->uart_rdata = *buf; - s->uart_status &= ~UART_STATUS_RXIDLE; - s->uart_status &= ~UART_STATUS_RXEMPTY; + s->uart_status &= ~R_STATUS_RXIDLE_MASK; + s->uart_status &= ~R_STATUS_RXEMPTY_MASK; if (size > rx_fifo_level) { - s->uart_intr_state |= INTR_STATE_RX_WATERMARK; + s->uart_intr_state |= R_INTR_STATE_RX_WATERMARK_MASK; } ibex_uart_update_irqs(s); @@ -94,8 +94,8 @@ static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) { IbexUartState *s = opaque; - uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL) - >> FIFO_CTRL_TXILVL_SHIFT; + uint8_t tx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) + >> R_FIFO_CTRL_TXILVL_SHIFT; int ret; /* instant drain the fifo when there's no back-end */ @@ -105,10 +105,10 @@ static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond, } if (!s->tx_level) { - s->uart_status &= ~UART_STATUS_TXFULL; - s->uart_status |= UART_STATUS_TXEMPTY; - s->uart_intr_state |= INTR_STATE_TX_EMPTY; - s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK; + s->uart_status &= ~R_STATUS_TXFULL_MASK; + s->uart_status |= R_STATUS_TXEMPTY_MASK; + s->uart_intr_state |= R_INTR_STATE_TX_EMPTY_MASK; + s->uart_intr_state &= ~R_INTR_STATE_TX_WATERMARK_MASK; ibex_uart_update_irqs(s); return FALSE; } @@ -131,18 +131,18 @@ static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond, /* Clear the TX Full bit */ if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) { - s->uart_status &= ~UART_STATUS_TXFULL; + s->uart_status &= ~R_STATUS_TXFULL_MASK; } /* Disable the TX_WATERMARK IRQ */ if (s->tx_level < tx_fifo_level) { - s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK; + s->uart_intr_state &= ~R_INTR_STATE_TX_WATERMARK_MASK; } /* Set TX empty */ if (s->tx_level == 0) { - s->uart_status |= UART_STATUS_TXEMPTY; - s->uart_intr_state |= INTR_STATE_TX_EMPTY; + s->uart_status |= R_STATUS_TXEMPTY_MASK; + s->uart_intr_state |= R_INTR_STATE_TX_EMPTY_MASK; } ibex_uart_update_irqs(s); @@ -153,8 +153,8 @@ static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf, int size) { uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL) - >> FIFO_CTRL_TXILVL_SHIFT; + uint8_t tx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) + >> R_FIFO_CTRL_TXILVL_SHIFT; if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) { size = IBEX_UART_TX_FIFO_SIZE - s->tx_level; @@ -165,16 +165,16 @@ static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf, s->tx_level += size; if (s->tx_level > 0) { - s->uart_status &= ~UART_STATUS_TXEMPTY; + s->uart_status &= ~R_STATUS_TXEMPTY_MASK; } if (s->tx_level >= tx_fifo_level) { - s->uart_intr_state |= INTR_STATE_TX_WATERMARK; + s->uart_intr_state |= R_INTR_STATE_TX_WATERMARK_MASK; ibex_uart_update_irqs(s); } if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) { - s->uart_status |= UART_STATUS_TXFULL; + s->uart_status |= R_STATUS_TXFULL_MASK; } timer_mod(s->fifo_trigger_handle, current_time + @@ -208,7 +208,7 @@ static uint64_t ibex_uart_get_baud(IbexUartState *s) { uint64_t baud; - baud = ((s->uart_ctrl & UART_CTRL_NCO) >> 16); + baud = ((s->uart_ctrl & R_CTRL_NCO_MASK) >> 16); baud *= clock_get_hz(s->f_clk); baud >>= 20; @@ -221,43 +221,43 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr addr, IbexUartState *s = opaque; uint64_t retvalue = 0; - switch (addr) { - case IBEX_UART_INTR_STATE: + switch (addr >> 2) { + case R_INTR_STATE: retvalue = s->uart_intr_state; break; - case IBEX_UART_INTR_ENABLE: + case R_INTR_ENABLE: retvalue = s->uart_intr_enable; break; - case IBEX_UART_INTR_TEST: + case R_INTR_TEST: qemu_log_mask(LOG_GUEST_ERROR, "%s: wdata is write only\n", __func__); break; - case IBEX_UART_CTRL: + case R_CTRL: retvalue = s->uart_ctrl; break; - case IBEX_UART_STATUS: + case R_STATUS: retvalue = s->uart_status; break; - case IBEX_UART_RDATA: + case R_RDATA: retvalue = s->uart_rdata; - if (s->uart_ctrl & UART_CTRL_RX_ENABLE) { + if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) { qemu_chr_fe_accept_input(&s->chr); - s->uart_status |= UART_STATUS_RXIDLE; - s->uart_status |= UART_STATUS_RXEMPTY; + s->uart_status |= R_STATUS_RXIDLE_MASK; + s->uart_status |= R_STATUS_RXEMPTY_MASK; } break; - case IBEX_UART_WDATA: + case R_WDATA: qemu_log_mask(LOG_GUEST_ERROR, "%s: wdata is write only\n", __func__); break; - case IBEX_UART_FIFO_CTRL: + case R_FIFO_CTRL: retvalue = s->uart_fifo_ctrl; break; - case IBEX_UART_FIFO_STATUS: + case R_FIFO_STATUS: retvalue = s->uart_fifo_status; retvalue |= s->tx_level & 0x1F; @@ -266,17 +266,17 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr addr, "%s: RX fifos are not supported\n", __func__); break; - case IBEX_UART_OVRD: + case R_OVRD: retvalue = s->uart_ovrd; qemu_log_mask(LOG_UNIMP, "%s: ovrd is not supported\n", __func__); break; - case IBEX_UART_VAL: + case R_VAL: retvalue = s->uart_val; qemu_log_mask(LOG_UNIMP, "%s: val is not supported\n", __func__); break; - case IBEX_UART_TIMEOUT_CTRL: + case R_TIMEOUT_CTRL: retvalue = s->uart_timeout_ctrl; qemu_log_mask(LOG_UNIMP, "%s: timeout_ctrl is not supported\n", __func__); @@ -296,95 +296,95 @@ static void ibex_uart_write(void *opaque, hwaddr addr, IbexUartState *s = opaque; uint32_t value = val64; - switch (addr) { - case IBEX_UART_INTR_STATE: + switch (addr >> 2) { + case R_INTR_STATE: /* Write 1 clear */ s->uart_intr_state &= ~value; ibex_uart_update_irqs(s); break; - case IBEX_UART_INTR_ENABLE: + case R_INTR_ENABLE: s->uart_intr_enable = value; ibex_uart_update_irqs(s); break; - case IBEX_UART_INTR_TEST: + case R_INTR_TEST: s->uart_intr_state |= value; ibex_uart_update_irqs(s); break; - case IBEX_UART_CTRL: + case R_CTRL: s->uart_ctrl = value; - if (value & UART_CTRL_NF) { + if (value & R_CTRL_NF_MASK) { qemu_log_mask(LOG_UNIMP, "%s: UART_CTRL_NF is not supported\n", __func__); } - if (value & UART_CTRL_SLPBK) { + if (value & R_CTRL_SLPBK_MASK) { qemu_log_mask(LOG_UNIMP, "%s: UART_CTRL_SLPBK is not supported\n", __func__); } - if (value & UART_CTRL_LLPBK) { + if (value & R_CTRL_LLPBK_MASK) { qemu_log_mask(LOG_UNIMP, "%s: UART_CTRL_LLPBK is not supported\n", __func__); } - if (value & UART_CTRL_PARITY_EN) { + if (value & R_CTRL_PARITY_EN_MASK) { qemu_log_mask(LOG_UNIMP, "%s: UART_CTRL_PARITY_EN is not supported\n", __func__); } - if (value & UART_CTRL_PARITY_ODD) { + if (value & R_CTRL_PARITY_ODD_MASK) { qemu_log_mask(LOG_UNIMP, "%s: UART_CTRL_PARITY_ODD is not supported\n", __func__); } - if (value & UART_CTRL_RXBLVL) { + if (value & R_CTRL_RXBLVL_MASK) { qemu_log_mask(LOG_UNIMP, "%s: UART_CTRL_RXBLVL is not supported\n", __func__); } - if (value & UART_CTRL_NCO) { + if (value & R_CTRL_NCO_MASK) { uint64_t baud = ibex_uart_get_baud(s); s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; } break; - case IBEX_UART_STATUS: + case R_STATUS: qemu_log_mask(LOG_GUEST_ERROR, "%s: status is read only\n", __func__); break; - case IBEX_UART_RDATA: + case R_RDATA: qemu_log_mask(LOG_GUEST_ERROR, "%s: rdata is read only\n", __func__); break; - case IBEX_UART_WDATA: + case R_WDATA: uart_write_tx_fifo(s, (uint8_t *) &value, 1); break; - case IBEX_UART_FIFO_CTRL: + case R_FIFO_CTRL: s->uart_fifo_ctrl = value; - if (value & FIFO_CTRL_RXRST) { + if (value & R_FIFO_CTRL_RXRST_MASK) { qemu_log_mask(LOG_UNIMP, "%s: RX fifos are not supported\n", __func__); } - if (value & FIFO_CTRL_TXRST) { + if (value & R_FIFO_CTRL_TXRST_MASK) { s->tx_level = 0; } break; - case IBEX_UART_FIFO_STATUS: + case R_FIFO_STATUS: qemu_log_mask(LOG_GUEST_ERROR, "%s: fifo_status is read only\n", __func__); break; - case IBEX_UART_OVRD: + case R_OVRD: s->uart_ovrd = value; qemu_log_mask(LOG_UNIMP, "%s: ovrd is not supported\n", __func__); break; - case IBEX_UART_VAL: + case R_VAL: qemu_log_mask(LOG_GUEST_ERROR, "%s: val is read only\n", __func__); break; - case IBEX_UART_TIMEOUT_CTRL: + case R_TIMEOUT_CTRL: s->uart_timeout_ctrl = value; qemu_log_mask(LOG_UNIMP, "%s: timeout_ctrl is not supported\n", __func__); @@ -409,7 +409,7 @@ static void fifo_trigger_update(void *opaque) { IbexUartState *s = opaque; - if (s->uart_ctrl & UART_CTRL_TX_ENABLE) { + if (s->uart_ctrl & R_CTRL_TX_ENABLE_MASK) { ibex_uart_xmit(NULL, G_IO_OUT, s); } } diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h index 6d81051161..b6bd5a6700 100644 --- a/include/hw/char/ibex_uart.h +++ b/include/hw/char/ibex_uart.h @@ -26,50 +26,44 @@ #define HW_IBEX_UART_H #include "hw/sysbus.h" +#include "hw/registerfields.h" #include "chardev/char-fe.h" #include "qemu/timer.h" -#define IBEX_UART_INTR_STATE 0x00 - #define INTR_STATE_TX_WATERMARK (1 << 0) - #define INTR_STATE_RX_WATERMARK (1 << 1) - #define INTR_STATE_TX_EMPTY (1 << 2) - #define INTR_STATE_RX_OVERFLOW (1 << 3) -#define IBEX_UART_INTR_ENABLE 0x04 -#define IBEX_UART_INTR_TEST 0x08 - -#define IBEX_UART_CTRL 0x0c - #define UART_CTRL_TX_ENABLE (1 << 0) - #define UART_CTRL_RX_ENABLE (1 << 1) - #define UART_CTRL_NF (1 << 2) - #define UART_CTRL_SLPBK (1 << 4) - #define UART_CTRL_LLPBK (1 << 5) - #define UART_CTRL_PARITY_EN (1 << 6) - #define UART_CTRL_PARITY_ODD (1 << 7) - #define UART_CTRL_RXBLVL (3 << 8) - #define UART_CTRL_NCO (0xFFFF << 16) - -#define IBEX_UART_STATUS 0x10 - #define UART_STATUS_TXFULL (1 << 0) - #define UART_STATUS_RXFULL (1 << 1) - #define UART_STATUS_TXEMPTY (1 << 2) - #define UART_STATUS_RXIDLE (1 << 4) - #define UART_STATUS_RXEMPTY (1 << 5) - -#define IBEX_UART_RDATA 0x14 -#define IBEX_UART_WDATA 0x18 - -#define IBEX_UART_FIFO_CTRL 0x1c - #define FIFO_CTRL_RXRST (1 << 0) - #define FIFO_CTRL_TXRST (1 << 1) - #define FIFO_CTRL_RXILVL (7 << 2) - #define FIFO_CTRL_RXILVL_SHIFT (2) - #define FIFO_CTRL_TXILVL (3 << 5) - #define FIFO_CTRL_TXILVL_SHIFT (5) - -#define IBEX_UART_FIFO_STATUS 0x20 -#define IBEX_UART_OVRD 0x24 -#define IBEX_UART_VAL 0x28 -#define IBEX_UART_TIMEOUT_CTRL 0x2c +REG32(INTR_STATE, 0x00) + FIELD(INTR_STATE, TX_WATERMARK, 0, 1) + FIELD(INTR_STATE, RX_WATERMARK, 1, 1) + FIELD(INTR_STATE, TX_EMPTY, 2, 1) + FIELD(INTR_STATE, RX_OVERFLOW, 3, 1) +REG32(INTR_ENABLE, 0x04) +REG32(INTR_TEST, 0x08) +REG32(CTRL, 0x0C) + FIELD(CTRL, TX_ENABLE, 0, 1) + FIELD(CTRL, RX_ENABLE, 1, 1) + FIELD(CTRL, NF, 2, 1) + FIELD(CTRL, SLPBK, 4, 1) + FIELD(CTRL, LLPBK, 5, 1) + FIELD(CTRL, PARITY_EN, 6, 1) + FIELD(CTRL, PARITY_ODD, 7, 1) + FIELD(CTRL, RXBLVL, 8, 2) + FIELD(CTRL, NCO, 16, 16) +REG32(STATUS, 0x10) + FIELD(STATUS, TXFULL, 0, 1) + FIELD(STATUS, RXFULL, 1, 1) + FIELD(STATUS, TXEMPTY, 2, 1) + FIELD(STATUS, RXIDLE, 4, 1) + FIELD(STATUS, RXEMPTY, 5, 1) +REG32(RDATA, 0x14) +REG32(WDATA, 0x18) +REG32(FIFO_CTRL, 0x1c) + FIELD(FIFO_CTRL, RXRST, 0, 1) + FIELD(FIFO_CTRL, TXRST, 1, 1) + FIELD(FIFO_CTRL, RXILVL, 2, 3) + FIELD(FIFO_CTRL, TXILVL, 5, 2) +REG32(FIFO_STATUS, 0x20) +REG32(OVRD, 0x24) +REG32(VAL, 0x28) +REG32(TIMEOUT_CTRL, 0x2c) #define IBEX_UART_TX_FIFO_SIZE 16 #define IBEX_UART_CLOCK 50000000 /* 50MHz clock */ From 895bfa84fec27899bf8e8c17f46358d31df2ab4f Mon Sep 17 00:00:00 2001 From: Liao Pingfang Date: Mon, 13 Jul 2020 08:33:41 +0800 Subject: [PATCH 2291/2595] tcg/riscv: Remove superfluous breaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove superfluous breaks, as there is a "return" before them. Signed-off-by: Liao Pingfang Signed-off-by: Yi Wang Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Alistair Francis Message-Id: <1594600421-22942-1-git-send-email-wang.yi59@zte.com.cn> Signed-off-by: Alistair Francis --- tcg/riscv/tcg-target.inc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tcg/riscv/tcg-target.inc.c b/tcg/riscv/tcg-target.inc.c index 2bc0ba71f2..3c11ab8b7a 100644 --- a/tcg/riscv/tcg-target.inc.c +++ b/tcg/riscv/tcg-target.inc.c @@ -502,10 +502,8 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, break; case R_RISCV_JAL: return reloc_jimm20(code_ptr, (tcg_insn_unit *)value); - break; case R_RISCV_CALL: return reloc_call(code_ptr, (tcg_insn_unit *)value); - break; default: tcg_abort(); } From cfad709bceb629a4ebeb5d8a3acd1871b9a6436b Mon Sep 17 00:00:00 2001 From: Alexandre Mergnat Date: Mon, 6 Jul 2020 10:45:50 +0200 Subject: [PATCH 2292/2595] target/riscv: Fix pmp NA4 implementation The end address calculation for NA4 mode is wrong because the address used isn't shifted. It doesn't watch 4 bytes but a huge range because the end address calculation is wrong. The solution is to use the shifted address calculated for start address variable. Modifications are tested on Zephyr OS userspace test suite which works for other RISC-V boards (E31 and E34 core). Signed-off-by: Alexandre Mergnat Reviewed-by: Alistair Francis Message-id: 20200706084550.24117-1-amergnat@baylibre.com Message-Id: <20200706084550.24117-1-amergnat@baylibre.com> [ Changes by AF: - Improve the commit title and message ] Signed-off-by: Alistair Francis --- target/riscv/pmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 9418660f1b..2a2b9f5363 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -171,7 +171,7 @@ static void pmp_update_rule(CPURISCVState *env, uint32_t pmp_index) case PMP_AMATCH_NA4: sa = this_addr << 2; /* shift up from [xx:0] to [xx+2:2] */ - ea = (this_addr + 4u) - 1u; + ea = (sa + 4u) - 1u; break; case PMP_AMATCH_NAPOT: From 6733d57035d1c4a67070b8d737334c28e5c63bc6 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 8 Jul 2020 17:24:34 +0200 Subject: [PATCH 2293/2595] linux-user: fix the errno value in print_syscall_err() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit errno of the target is returned as a negative value by the syscall, not in the host errno variable. The emulation of the target syscall can return an error while the host doesn't set an errno value. Target errnos and host errnos can also differ in some cases. Fixes: c84be71f6854 ("linux-user: Extend strace support to enable argument printing after syscall execution") Cc: Filip.Bozuta@syrmia.com Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Filip Bozuta Message-Id: <20200708152435.706070-2-laurent@vivier.eu> --- linux-user/strace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 39554d9039..7769f53bd5 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -731,7 +731,7 @@ print_syscall_err(abi_long ret) qemu_log(" = "); if (ret < 0) { - qemu_log("-1 errno=%d", errno); + qemu_log("-1 errno=%d", (int)-ret); errstr = target_strerror(-ret); if (errstr) { qemu_log(" (%s)", errstr); From 42b16184d016d48d167229a1ddb89b3671c77440 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 8 Jul 2020 17:24:35 +0200 Subject: [PATCH 2294/2595] linux-user: fix print_syscall_err() when syscall returned value is negative print_syscall_err() relies on the sign of the returned value to know if it is an errno value or not. But in some cases the returned value can have the most signicant bit set without being an errno. This patch restores previous behaviour that was also checking if we can decode the errno to validate it. This patch fixes this kind of problem (qemu-m68k): root@sid:/# QEMU_STRACE= ls 3 brk(NULL) = -1 errno=21473607683 uname(0x407fff8a) = 0 to become: root@sid:/# QEMU_STRACE= ls 3 brk(NULL) = 0x8001e000 3 uname(0xffffdf8a) = 0 Fixes: c84be71f6854 ("linux-user: Extend strace support to enable argument printing after syscall execution") Cc: Filip.Bozuta@syrmia.com Signed-off-by: Laurent Vivier Message-Id: <20200708152435.706070-3-laurent@vivier.eu> --- linux-user/strace.c | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 7769f53bd5..13981341b3 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -724,19 +724,20 @@ print_ipc(const struct syscallname *name, * Variants for the return value output function */ -static void +static bool print_syscall_err(abi_long ret) { - const char *errstr = NULL; + const char *errstr; qemu_log(" = "); if (ret < 0) { - qemu_log("-1 errno=%d", (int)-ret); errstr = target_strerror(-ret); if (errstr) { - qemu_log(" (%s)", errstr); + qemu_log("-1 errno=%d (%s)", (int)-ret, errstr); + return true; } } + return false; } static void @@ -744,11 +745,10 @@ print_syscall_ret_addr(const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { - print_syscall_err(ret); - - if (ret >= 0) { - qemu_log("0x" TARGET_ABI_FMT_lx "\n", ret); + if (!print_syscall_err(ret)) { + qemu_log("0x" TARGET_ABI_FMT_lx, ret); } + qemu_log("\n"); } #if 0 /* currently unused */ @@ -765,9 +765,7 @@ print_syscall_ret_newselect(const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { - print_syscall_err(ret); - - if (ret >= 0) { + if (!print_syscall_err(ret)) { qemu_log(" = 0x" TARGET_ABI_FMT_lx " (", ret); print_fdset(arg0, arg1); qemu_log(","); @@ -796,9 +794,7 @@ print_syscall_ret_adjtimex(const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { - print_syscall_err(ret); - - if (ret >= 0) { + if (!print_syscall_err(ret)) { qemu_log(TARGET_ABI_FMT_ld, ret); switch (ret) { case TARGET_TIME_OK: @@ -833,9 +829,7 @@ print_syscall_ret_listxattr(const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { - print_syscall_err(ret); - - if (ret >= 0) { + if (!print_syscall_err(ret)) { qemu_log(TARGET_ABI_FMT_ld, ret); qemu_log(" (list = "); if (arg1 != 0) { @@ -866,9 +860,7 @@ print_syscall_ret_ioctl(const struct syscallname *name, abi_long ret, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { - print_syscall_err(ret); - - if (ret >= 0) { + if (!print_syscall_err(ret)) { qemu_log(TARGET_ABI_FMT_ld, ret); const IOCTLEntry *ie; @@ -3197,9 +3189,7 @@ print_syscall_ret(int num, abi_long ret, arg1, arg2, arg3, arg4, arg5, arg6); } else { - print_syscall_err(ret); - - if (ret >= 0) { + if (!print_syscall_err(ret)) { qemu_log(TARGET_ABI_FMT_ld, ret); } qemu_log("\n"); From 4b196cd16dcfb17de19a4121f12aa4ef4bf7925f Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Thu, 9 Jul 2020 13:02:05 +0200 Subject: [PATCH 2295/2595] iotests: Simplify _filter_img_create() a bit Not only is it a bit stupid to try to filter multi-line "Formatting" output (because we only need it for a single test, which can easily be amended to no longer need it), it is also problematic when there can be output after a "Formatting" line that we do not want to filter as if it were part of it. So rename _filter_img_create to _do_filter_img_create, let it filter only a single line, and let _filter_img_create loop over all input lines, calling _do_filter_img_create only on those that match /^Formatting/ (basically, what _filter_img_create_in_qmp did already). (And fix 020 to work with that.) Reported-by: Kevin Wolf Signed-off-by: Max Reitz Message-Id: <20200709110205.310942-1-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/020 | 29 ++++++++------- tests/qemu-iotests/020.out | 13 +------ tests/qemu-iotests/141 | 2 +- tests/qemu-iotests/common.filter | 62 ++++++++++++++------------------ 4 files changed, 45 insertions(+), 61 deletions(-) diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020 index 20f8f185d0..b488000cb9 100755 --- a/tests/qemu-iotests/020 +++ b/tests/qemu-iotests/020 @@ -115,18 +115,23 @@ TEST_IMG="$TEST_IMG.base" _make_test_img 1M # Create an image with a null backing file to which committing will fail (with # ENOSPC so we can distinguish the result from some generic EIO which may be # generated anywhere in the block layer) -_make_test_img -b "json:{'driver': '$IMGFMT', - 'file': { - 'driver': 'blkdebug', - 'inject-error': [{ - 'event': 'write_aio', - 'errno': 28, - 'once': true - }], - 'image': { - 'driver': 'file', - 'filename': '$TEST_IMG.base' - }}}" +backing="json:{'driver': '$IMGFMT', + 'file': { + 'driver': 'blkdebug', + 'inject-error': [{ + 'event': 'write_aio', + 'errno': 28, + 'once': true + }], + 'image': { + 'driver': 'file', + 'filename': '$TEST_IMG.base' + }}}" + +# Filter out newlines and collapse spaces +backing=$(echo "$backing" | tr -d '\n' | tr -s ' ') + +_make_test_img -b "$backing" # Just write anything so committing will not be a no-op $QEMU_IO -c 'writev 0 64k' "$TEST_IMG" | _filter_qemu_io diff --git a/tests/qemu-iotests/020.out b/tests/qemu-iotests/020.out index 4b722b2dd0..4668ac59df 100644 --- a/tests/qemu-iotests/020.out +++ b/tests/qemu-iotests/020.out @@ -1079,18 +1079,7 @@ No errors were found on the image. Testing failing commit Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=json:{'driver': 'IMGFMT',, - 'file': { - 'driver': 'blkdebug',, - 'inject-error': [{ - 'event': 'write_aio',, - 'errno': 28,, - 'once': true - }],, - 'image': { - 'driver': 'file',, - 'filename': 'TEST_DIR/t.IMGFMT.base' - }}} +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=json:{'driver': 'IMGFMT',, 'file': { 'driver': 'blkdebug',, 'inject-error': [{ 'event': 'write_aio',, 'errno': 28,, 'once': true }],, 'image': { 'driver': 'file',, 'filename': 'TEST_DIR/t.IMGFMT.base' }}} wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-img: Block job failed: No space left on device diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141 index 6d1b7b0d4c..5192d256e3 100755 --- a/tests/qemu-iotests/141 +++ b/tests/qemu-iotests/141 @@ -68,7 +68,7 @@ test_blockjob() _send_qemu_cmd $QEMU_HANDLE \ "$1" \ "$2" \ - | _filter_img_create_in_qmp | _filter_qmp_empty_return + | _filter_img_create | _filter_qmp_empty_return # We want this to return an error because the block job is still running _send_qemu_cmd $QEMU_HANDLE \ diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index c9f978abce..9b772245cd 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -119,8 +119,21 @@ _filter_actual_image_size() $SED -s 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' } +# Filename filters for qemu-img create +_filter_img_create_filenames() +{ + $SED \ + -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ + -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ + -e "s#$TEST_DIR#TEST_DIR#g" \ + -e "s#$SOCK_DIR#SOCK_DIR#g" \ + -e "s#$IMGFMT#IMGFMT#g" \ + -e 's#nbd:127.0.0.1:[0-9]\\+#TEST_DIR/t.IMGFMT#g' \ + -e 's#nbd+unix:///\??socket=SOCK_DIR/nbd#TEST_DIR/t.IMGFMT#g' +} + # replace driver-specific options in the "Formatting..." line -_filter_img_create() +_do_filter_img_create() { # Split the line into the pre-options part ($filename_part, which # precedes ", fmt=") and the options part ($options, which starts @@ -128,23 +141,10 @@ _filter_img_create() # (And just echo everything before the first "^Formatting") readarray formatting_line < <($SED -e 's/, fmt=/\n/') - filename_part='' - options='' - lines=${#formatting_line[@]} - for ((i = 0; i < $lines; i++)); do - line=${formatting_line[i]} - unset formatting_line[i] + filename_part=${formatting_line[0]} + unset formatting_line[0] - filename_part="$filename_part$line" - - if echo "$line" | grep -q '^Formatting'; then - next_i=$((i + 1)) - if [ -n "${formatting_line[next_i]}" ]; then - options="fmt=${formatting_line[@]}" - fi - break - fi - done + options="fmt=${formatting_line[@]}" # Set grep_data_file to '\|data_file' to keep it; make it empty # to drop it. @@ -156,17 +156,7 @@ _filter_img_create() grep_data_file=() fi - filename_filters=( - -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ - -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ - -e "s#$TEST_DIR#TEST_DIR#g" \ - -e "s#$SOCK_DIR#SOCK_DIR#g" \ - -e "s#$IMGFMT#IMGFMT#g" \ - -e 's#nbd:127.0.0.1:[0-9]\\+#TEST_DIR/t.IMGFMT#g' \ - -e 's#nbd+unix:///\??socket=SOCK_DIR/nbd#TEST_DIR/t.IMGFMT#g' - ) - - filename_part=$(echo "$filename_part" | $SED "${filename_filters[@]}") + filename_part=$(echo "$filename_part" | _filter_img_create_filenames) # Break the option line before each option (preserving pre-existing # line breaks by replacing them by \0 and restoring them at the end), @@ -179,7 +169,8 @@ _filter_img_create() | $SED -e 's/ \([a-z0-9_.-]*\)=/\n\1=/g' \ | grep -a -e '^fmt' -e '^size' -e '^backing' -e '^preallocation' \ -e '^encryption' "${grep_data_file[@]}" \ - | $SED "${filename_filters[@]}" \ + | _filter_img_create_filenames \ + | $SED \ -e 's/^\(fmt\)/0-\1/' \ -e 's/^\(size\)/1-\1/' \ -e 's/^\(backing\)/2-\1/' \ @@ -199,17 +190,16 @@ _filter_img_create() fi } -# Filter the "Formatting..." line in QMP output (leaving the QMP output -# untouched) -# (In contrast to _filter_img_create(), this function does not support -# multi-line Formatting output) -_filter_img_create_in_qmp() +# Filter qemu-img create output: +# Pipe all ^Formatting lines through _do_filter_img_create, and all +# other lines through _filter_img_create_filenames +_filter_img_create() { while read -r line; do if echo "$line" | grep -q '^Formatting'; then - echo "$line" | _filter_img_create + echo "$line" | _do_filter_img_create else - echo "$line" + echo "$line" | _filter_img_create_filenames fi done } From d0ceea88dea053e0c1c038d42ca98782c2e3872d Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 7 Jul 2020 16:46:29 +0200 Subject: [PATCH 2296/2595] qemu-img map: Don't limit block status request size Limiting each loop iteration of qemu-img map to 1 GB was arbitrary from the beginning, though it only cut the maximum in half then because the interface was a signed 32 bit byte count. These days, bdrv_block_status supports a 64 bit byte count, so the arbitrary limit is even worse. On file-posix, bdrv_block_status() eventually maps to SEEK_HOLE and SEEK_DATA, which don't support a limit, but always do all of the work necessary to find the start of the next hole/data. Much of this work may be repeated if we don't use this information fully, but query with an only slightly larger offset in the next loop iteration. Therefore, if bdrv_block_status() is called in a loop, it should always pass the full number of bytes that the whole loop is interested in. This removes the arbitrary limit and speeds up 'qemu-img map' significantly on heavily fragmented images. Signed-off-by: Kevin Wolf Message-Id: <20200707144629.51235-1-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- qemu-img.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 498fbf42fe..4548dbff82 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -3210,12 +3210,9 @@ static int img_map(int argc, char **argv) curr.start = start_offset; while (curr.start + curr.length < length) { int64_t offset = curr.start + curr.length; - int64_t n; + int64_t n = length - offset; - /* Probe up to 1 GiB at a time. */ - n = MIN(1 * GiB, length - offset); ret = get_block_status(bs, offset, n, &next); - if (ret < 0) { error_report("Could not read file metadata: %s", strerror(-ret)); goto out; From 046e07ca556b3eb44ac5c64911b5bda204403113 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 13 Jul 2020 15:45:37 +0200 Subject: [PATCH 2297/2595] iotests/059: Filter out disk size with more standard filter The actual disk space used by an image can vary between filesystems and depending on other settings like an extent size hint. Replace the one call of "$QEMU_IMG info" and the associated one-off sed filter with the more standard "_img_info" and the standard filter from common.filter. Apart from turning "vmdk" into "IMGFMT" and changing the placeholder for cid fields, this only removes the "disk size" line. Signed-off-by: Kevin Wolf --- tests/qemu-iotests/059 | 2 +- tests/qemu-iotests/059.out | 1009 ++++++++++++++++++------------------ 2 files changed, 505 insertions(+), 506 deletions(-) diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index 4c90fc0363..dcc442be9f 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -82,7 +82,7 @@ _cleanup_test_img echo echo "=== Testing big twoGbMaxExtentFlat ===" _make_test_img -o "subformat=twoGbMaxExtentFlat" 1000G -$QEMU_IMG info $TEST_IMG | _filter_testdir | sed -e 's/cid: [0-9]*/cid: XXXXXXXX/' +_img_info --format-specific | _filter_img_info --format-specific _cleanup_test_img echo diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out index 39bf7e211d..6d127e28d8 100644 --- a/tests/qemu-iotests/059.out +++ b/tests/qemu-iotests/059.out @@ -24,2014 +24,2013 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 === Testing big twoGbMaxExtentFlat === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 -image: TEST_DIR/t.vmdk -file format: vmdk +image: TEST_DIR/t.IMGFMT +file format: IMGFMT virtual size: 0.977 TiB (1073741824000 bytes) -disk size: 1.97 MiB Format specific information: - cid: XXXXXXXX - parent cid: XXXXXXXX + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX create type: twoGbMaxExtentFlat extents: [0]: virtual size: 2147483648 - filename: TEST_DIR/t-f001.vmdk + filename: TEST_DIR/t-f001.IMGFMT format: FLAT [1]: virtual size: 2147483648 - filename: TEST_DIR/t-f002.vmdk + filename: TEST_DIR/t-f002.IMGFMT format: FLAT [2]: virtual size: 2147483648 - filename: TEST_DIR/t-f003.vmdk + filename: TEST_DIR/t-f003.IMGFMT format: FLAT [3]: virtual size: 2147483648 - filename: TEST_DIR/t-f004.vmdk + filename: TEST_DIR/t-f004.IMGFMT format: FLAT [4]: virtual size: 2147483648 - filename: TEST_DIR/t-f005.vmdk + filename: TEST_DIR/t-f005.IMGFMT format: FLAT [5]: virtual size: 2147483648 - filename: TEST_DIR/t-f006.vmdk + filename: TEST_DIR/t-f006.IMGFMT format: FLAT [6]: virtual size: 2147483648 - filename: TEST_DIR/t-f007.vmdk + filename: TEST_DIR/t-f007.IMGFMT format: FLAT [7]: virtual size: 2147483648 - filename: TEST_DIR/t-f008.vmdk + filename: TEST_DIR/t-f008.IMGFMT format: FLAT [8]: virtual size: 2147483648 - filename: TEST_DIR/t-f009.vmdk + filename: TEST_DIR/t-f009.IMGFMT format: FLAT [9]: virtual size: 2147483648 - filename: TEST_DIR/t-f010.vmdk + filename: TEST_DIR/t-f010.IMGFMT format: FLAT [10]: virtual size: 2147483648 - filename: TEST_DIR/t-f011.vmdk + filename: TEST_DIR/t-f011.IMGFMT format: FLAT [11]: virtual size: 2147483648 - filename: TEST_DIR/t-f012.vmdk + filename: TEST_DIR/t-f012.IMGFMT format: FLAT [12]: virtual size: 2147483648 - filename: TEST_DIR/t-f013.vmdk + filename: TEST_DIR/t-f013.IMGFMT format: FLAT [13]: virtual size: 2147483648 - filename: TEST_DIR/t-f014.vmdk + filename: TEST_DIR/t-f014.IMGFMT format: FLAT [14]: virtual size: 2147483648 - filename: TEST_DIR/t-f015.vmdk + filename: TEST_DIR/t-f015.IMGFMT format: FLAT [15]: virtual size: 2147483648 - filename: TEST_DIR/t-f016.vmdk + filename: TEST_DIR/t-f016.IMGFMT format: FLAT [16]: virtual size: 2147483648 - filename: TEST_DIR/t-f017.vmdk + filename: TEST_DIR/t-f017.IMGFMT format: FLAT [17]: virtual size: 2147483648 - filename: TEST_DIR/t-f018.vmdk + filename: TEST_DIR/t-f018.IMGFMT format: FLAT [18]: virtual size: 2147483648 - filename: TEST_DIR/t-f019.vmdk + filename: TEST_DIR/t-f019.IMGFMT format: FLAT [19]: virtual size: 2147483648 - filename: TEST_DIR/t-f020.vmdk + filename: TEST_DIR/t-f020.IMGFMT format: FLAT [20]: virtual size: 2147483648 - filename: TEST_DIR/t-f021.vmdk + filename: TEST_DIR/t-f021.IMGFMT format: FLAT [21]: virtual size: 2147483648 - filename: TEST_DIR/t-f022.vmdk + filename: TEST_DIR/t-f022.IMGFMT format: FLAT [22]: virtual size: 2147483648 - filename: TEST_DIR/t-f023.vmdk + filename: TEST_DIR/t-f023.IMGFMT format: FLAT [23]: virtual size: 2147483648 - filename: TEST_DIR/t-f024.vmdk + filename: TEST_DIR/t-f024.IMGFMT format: FLAT [24]: virtual size: 2147483648 - filename: TEST_DIR/t-f025.vmdk + filename: TEST_DIR/t-f025.IMGFMT format: FLAT [25]: virtual size: 2147483648 - filename: TEST_DIR/t-f026.vmdk + filename: TEST_DIR/t-f026.IMGFMT format: FLAT [26]: virtual size: 2147483648 - filename: TEST_DIR/t-f027.vmdk + filename: TEST_DIR/t-f027.IMGFMT format: FLAT [27]: virtual size: 2147483648 - filename: TEST_DIR/t-f028.vmdk + filename: TEST_DIR/t-f028.IMGFMT format: FLAT [28]: virtual size: 2147483648 - filename: TEST_DIR/t-f029.vmdk + filename: TEST_DIR/t-f029.IMGFMT format: FLAT [29]: virtual size: 2147483648 - filename: TEST_DIR/t-f030.vmdk + filename: TEST_DIR/t-f030.IMGFMT format: FLAT [30]: virtual size: 2147483648 - filename: TEST_DIR/t-f031.vmdk + filename: TEST_DIR/t-f031.IMGFMT format: FLAT [31]: virtual size: 2147483648 - filename: TEST_DIR/t-f032.vmdk + filename: TEST_DIR/t-f032.IMGFMT format: FLAT [32]: virtual size: 2147483648 - filename: TEST_DIR/t-f033.vmdk + filename: TEST_DIR/t-f033.IMGFMT format: FLAT [33]: virtual size: 2147483648 - filename: TEST_DIR/t-f034.vmdk + filename: TEST_DIR/t-f034.IMGFMT format: FLAT [34]: virtual size: 2147483648 - filename: TEST_DIR/t-f035.vmdk + filename: TEST_DIR/t-f035.IMGFMT format: FLAT [35]: virtual size: 2147483648 - filename: TEST_DIR/t-f036.vmdk + filename: TEST_DIR/t-f036.IMGFMT format: FLAT [36]: virtual size: 2147483648 - filename: TEST_DIR/t-f037.vmdk + filename: TEST_DIR/t-f037.IMGFMT format: FLAT [37]: virtual size: 2147483648 - filename: TEST_DIR/t-f038.vmdk + filename: TEST_DIR/t-f038.IMGFMT format: FLAT [38]: virtual size: 2147483648 - filename: TEST_DIR/t-f039.vmdk + filename: TEST_DIR/t-f039.IMGFMT format: FLAT [39]: virtual size: 2147483648 - filename: TEST_DIR/t-f040.vmdk + filename: TEST_DIR/t-f040.IMGFMT format: FLAT [40]: virtual size: 2147483648 - filename: TEST_DIR/t-f041.vmdk + filename: TEST_DIR/t-f041.IMGFMT format: FLAT [41]: virtual size: 2147483648 - filename: TEST_DIR/t-f042.vmdk + filename: TEST_DIR/t-f042.IMGFMT format: FLAT [42]: virtual size: 2147483648 - filename: TEST_DIR/t-f043.vmdk + filename: TEST_DIR/t-f043.IMGFMT format: FLAT [43]: virtual size: 2147483648 - filename: TEST_DIR/t-f044.vmdk + filename: TEST_DIR/t-f044.IMGFMT format: FLAT [44]: virtual size: 2147483648 - filename: TEST_DIR/t-f045.vmdk + filename: TEST_DIR/t-f045.IMGFMT format: FLAT [45]: virtual size: 2147483648 - filename: TEST_DIR/t-f046.vmdk + filename: TEST_DIR/t-f046.IMGFMT format: FLAT [46]: virtual size: 2147483648 - filename: TEST_DIR/t-f047.vmdk + filename: TEST_DIR/t-f047.IMGFMT format: FLAT [47]: virtual size: 2147483648 - filename: TEST_DIR/t-f048.vmdk + filename: TEST_DIR/t-f048.IMGFMT format: FLAT [48]: virtual size: 2147483648 - filename: TEST_DIR/t-f049.vmdk + filename: TEST_DIR/t-f049.IMGFMT format: FLAT [49]: virtual size: 2147483648 - filename: TEST_DIR/t-f050.vmdk + filename: TEST_DIR/t-f050.IMGFMT format: FLAT [50]: virtual size: 2147483648 - filename: TEST_DIR/t-f051.vmdk + filename: TEST_DIR/t-f051.IMGFMT format: FLAT [51]: virtual size: 2147483648 - filename: TEST_DIR/t-f052.vmdk + filename: TEST_DIR/t-f052.IMGFMT format: FLAT [52]: virtual size: 2147483648 - filename: TEST_DIR/t-f053.vmdk + filename: TEST_DIR/t-f053.IMGFMT format: FLAT [53]: virtual size: 2147483648 - filename: TEST_DIR/t-f054.vmdk + filename: TEST_DIR/t-f054.IMGFMT format: FLAT [54]: virtual size: 2147483648 - filename: TEST_DIR/t-f055.vmdk + filename: TEST_DIR/t-f055.IMGFMT format: FLAT [55]: virtual size: 2147483648 - filename: TEST_DIR/t-f056.vmdk + filename: TEST_DIR/t-f056.IMGFMT format: FLAT [56]: virtual size: 2147483648 - filename: TEST_DIR/t-f057.vmdk + filename: TEST_DIR/t-f057.IMGFMT format: FLAT [57]: virtual size: 2147483648 - filename: TEST_DIR/t-f058.vmdk + filename: TEST_DIR/t-f058.IMGFMT format: FLAT [58]: virtual size: 2147483648 - filename: TEST_DIR/t-f059.vmdk + filename: TEST_DIR/t-f059.IMGFMT format: FLAT [59]: virtual size: 2147483648 - filename: TEST_DIR/t-f060.vmdk + filename: TEST_DIR/t-f060.IMGFMT format: FLAT [60]: virtual size: 2147483648 - filename: TEST_DIR/t-f061.vmdk + filename: TEST_DIR/t-f061.IMGFMT format: FLAT [61]: virtual size: 2147483648 - filename: TEST_DIR/t-f062.vmdk + filename: TEST_DIR/t-f062.IMGFMT format: FLAT [62]: virtual size: 2147483648 - filename: TEST_DIR/t-f063.vmdk + filename: TEST_DIR/t-f063.IMGFMT format: FLAT [63]: virtual size: 2147483648 - filename: TEST_DIR/t-f064.vmdk + filename: TEST_DIR/t-f064.IMGFMT format: FLAT [64]: virtual size: 2147483648 - filename: TEST_DIR/t-f065.vmdk + filename: TEST_DIR/t-f065.IMGFMT format: FLAT [65]: virtual size: 2147483648 - filename: TEST_DIR/t-f066.vmdk + filename: TEST_DIR/t-f066.IMGFMT format: FLAT [66]: virtual size: 2147483648 - filename: TEST_DIR/t-f067.vmdk + filename: TEST_DIR/t-f067.IMGFMT format: FLAT [67]: virtual size: 2147483648 - filename: TEST_DIR/t-f068.vmdk + filename: TEST_DIR/t-f068.IMGFMT format: FLAT [68]: virtual size: 2147483648 - filename: TEST_DIR/t-f069.vmdk + filename: TEST_DIR/t-f069.IMGFMT format: FLAT [69]: virtual size: 2147483648 - filename: TEST_DIR/t-f070.vmdk + filename: TEST_DIR/t-f070.IMGFMT format: FLAT [70]: virtual size: 2147483648 - filename: TEST_DIR/t-f071.vmdk + filename: TEST_DIR/t-f071.IMGFMT format: FLAT [71]: virtual size: 2147483648 - filename: TEST_DIR/t-f072.vmdk + filename: TEST_DIR/t-f072.IMGFMT format: FLAT [72]: virtual size: 2147483648 - filename: TEST_DIR/t-f073.vmdk + filename: TEST_DIR/t-f073.IMGFMT format: FLAT [73]: virtual size: 2147483648 - filename: TEST_DIR/t-f074.vmdk + filename: TEST_DIR/t-f074.IMGFMT format: FLAT [74]: virtual size: 2147483648 - filename: TEST_DIR/t-f075.vmdk + filename: TEST_DIR/t-f075.IMGFMT format: FLAT [75]: virtual size: 2147483648 - filename: TEST_DIR/t-f076.vmdk + filename: TEST_DIR/t-f076.IMGFMT format: FLAT [76]: virtual size: 2147483648 - filename: TEST_DIR/t-f077.vmdk + filename: TEST_DIR/t-f077.IMGFMT format: FLAT [77]: virtual size: 2147483648 - filename: TEST_DIR/t-f078.vmdk + filename: TEST_DIR/t-f078.IMGFMT format: FLAT [78]: virtual size: 2147483648 - filename: TEST_DIR/t-f079.vmdk + filename: TEST_DIR/t-f079.IMGFMT format: FLAT [79]: virtual size: 2147483648 - filename: TEST_DIR/t-f080.vmdk + filename: TEST_DIR/t-f080.IMGFMT format: FLAT [80]: virtual size: 2147483648 - filename: TEST_DIR/t-f081.vmdk + filename: TEST_DIR/t-f081.IMGFMT format: FLAT [81]: virtual size: 2147483648 - filename: TEST_DIR/t-f082.vmdk + filename: TEST_DIR/t-f082.IMGFMT format: FLAT [82]: virtual size: 2147483648 - filename: TEST_DIR/t-f083.vmdk + filename: TEST_DIR/t-f083.IMGFMT format: FLAT [83]: virtual size: 2147483648 - filename: TEST_DIR/t-f084.vmdk + filename: TEST_DIR/t-f084.IMGFMT format: FLAT [84]: virtual size: 2147483648 - filename: TEST_DIR/t-f085.vmdk + filename: TEST_DIR/t-f085.IMGFMT format: FLAT [85]: virtual size: 2147483648 - filename: TEST_DIR/t-f086.vmdk + filename: TEST_DIR/t-f086.IMGFMT format: FLAT [86]: virtual size: 2147483648 - filename: TEST_DIR/t-f087.vmdk + filename: TEST_DIR/t-f087.IMGFMT format: FLAT [87]: virtual size: 2147483648 - filename: TEST_DIR/t-f088.vmdk + filename: TEST_DIR/t-f088.IMGFMT format: FLAT [88]: virtual size: 2147483648 - filename: TEST_DIR/t-f089.vmdk + filename: TEST_DIR/t-f089.IMGFMT format: FLAT [89]: virtual size: 2147483648 - filename: TEST_DIR/t-f090.vmdk + filename: TEST_DIR/t-f090.IMGFMT format: FLAT [90]: virtual size: 2147483648 - filename: TEST_DIR/t-f091.vmdk + filename: TEST_DIR/t-f091.IMGFMT format: FLAT [91]: virtual size: 2147483648 - filename: TEST_DIR/t-f092.vmdk + filename: TEST_DIR/t-f092.IMGFMT format: FLAT [92]: virtual size: 2147483648 - filename: TEST_DIR/t-f093.vmdk + filename: TEST_DIR/t-f093.IMGFMT format: FLAT [93]: virtual size: 2147483648 - filename: TEST_DIR/t-f094.vmdk + filename: TEST_DIR/t-f094.IMGFMT format: FLAT [94]: virtual size: 2147483648 - filename: TEST_DIR/t-f095.vmdk + filename: TEST_DIR/t-f095.IMGFMT format: FLAT [95]: virtual size: 2147483648 - filename: TEST_DIR/t-f096.vmdk + filename: TEST_DIR/t-f096.IMGFMT format: FLAT [96]: virtual size: 2147483648 - filename: TEST_DIR/t-f097.vmdk + filename: TEST_DIR/t-f097.IMGFMT format: FLAT [97]: virtual size: 2147483648 - filename: TEST_DIR/t-f098.vmdk + filename: TEST_DIR/t-f098.IMGFMT format: FLAT [98]: virtual size: 2147483648 - filename: TEST_DIR/t-f099.vmdk + filename: TEST_DIR/t-f099.IMGFMT format: FLAT [99]: virtual size: 2147483648 - filename: TEST_DIR/t-f100.vmdk + filename: TEST_DIR/t-f100.IMGFMT format: FLAT [100]: virtual size: 2147483648 - filename: TEST_DIR/t-f101.vmdk + filename: TEST_DIR/t-f101.IMGFMT format: FLAT [101]: virtual size: 2147483648 - filename: TEST_DIR/t-f102.vmdk + filename: TEST_DIR/t-f102.IMGFMT format: FLAT [102]: virtual size: 2147483648 - filename: TEST_DIR/t-f103.vmdk + filename: TEST_DIR/t-f103.IMGFMT format: FLAT [103]: virtual size: 2147483648 - filename: TEST_DIR/t-f104.vmdk + filename: TEST_DIR/t-f104.IMGFMT format: FLAT [104]: virtual size: 2147483648 - filename: TEST_DIR/t-f105.vmdk + filename: TEST_DIR/t-f105.IMGFMT format: FLAT [105]: virtual size: 2147483648 - filename: TEST_DIR/t-f106.vmdk + filename: TEST_DIR/t-f106.IMGFMT format: FLAT [106]: virtual size: 2147483648 - filename: TEST_DIR/t-f107.vmdk + filename: TEST_DIR/t-f107.IMGFMT format: FLAT [107]: virtual size: 2147483648 - filename: TEST_DIR/t-f108.vmdk + filename: TEST_DIR/t-f108.IMGFMT format: FLAT [108]: virtual size: 2147483648 - filename: TEST_DIR/t-f109.vmdk + filename: TEST_DIR/t-f109.IMGFMT format: FLAT [109]: virtual size: 2147483648 - filename: TEST_DIR/t-f110.vmdk + filename: TEST_DIR/t-f110.IMGFMT format: FLAT [110]: virtual size: 2147483648 - filename: TEST_DIR/t-f111.vmdk + filename: TEST_DIR/t-f111.IMGFMT format: FLAT [111]: virtual size: 2147483648 - filename: TEST_DIR/t-f112.vmdk + filename: TEST_DIR/t-f112.IMGFMT format: FLAT [112]: virtual size: 2147483648 - filename: TEST_DIR/t-f113.vmdk + filename: TEST_DIR/t-f113.IMGFMT format: FLAT [113]: virtual size: 2147483648 - filename: TEST_DIR/t-f114.vmdk + filename: TEST_DIR/t-f114.IMGFMT format: FLAT [114]: virtual size: 2147483648 - filename: TEST_DIR/t-f115.vmdk + filename: TEST_DIR/t-f115.IMGFMT format: FLAT [115]: virtual size: 2147483648 - filename: TEST_DIR/t-f116.vmdk + filename: TEST_DIR/t-f116.IMGFMT format: FLAT [116]: virtual size: 2147483648 - filename: TEST_DIR/t-f117.vmdk + filename: TEST_DIR/t-f117.IMGFMT format: FLAT [117]: virtual size: 2147483648 - filename: TEST_DIR/t-f118.vmdk + filename: TEST_DIR/t-f118.IMGFMT format: FLAT [118]: virtual size: 2147483648 - filename: TEST_DIR/t-f119.vmdk + filename: TEST_DIR/t-f119.IMGFMT format: FLAT [119]: virtual size: 2147483648 - filename: TEST_DIR/t-f120.vmdk + filename: TEST_DIR/t-f120.IMGFMT format: FLAT [120]: virtual size: 2147483648 - filename: TEST_DIR/t-f121.vmdk + filename: TEST_DIR/t-f121.IMGFMT format: FLAT [121]: virtual size: 2147483648 - filename: TEST_DIR/t-f122.vmdk + filename: TEST_DIR/t-f122.IMGFMT format: FLAT [122]: virtual size: 2147483648 - filename: TEST_DIR/t-f123.vmdk + filename: TEST_DIR/t-f123.IMGFMT format: FLAT [123]: virtual size: 2147483648 - filename: TEST_DIR/t-f124.vmdk + filename: TEST_DIR/t-f124.IMGFMT format: FLAT [124]: virtual size: 2147483648 - filename: TEST_DIR/t-f125.vmdk + filename: TEST_DIR/t-f125.IMGFMT format: FLAT [125]: virtual size: 2147483648 - filename: TEST_DIR/t-f126.vmdk + filename: TEST_DIR/t-f126.IMGFMT format: FLAT [126]: virtual size: 2147483648 - filename: TEST_DIR/t-f127.vmdk + filename: TEST_DIR/t-f127.IMGFMT format: FLAT [127]: virtual size: 2147483648 - filename: TEST_DIR/t-f128.vmdk + filename: TEST_DIR/t-f128.IMGFMT format: FLAT [128]: virtual size: 2147483648 - filename: TEST_DIR/t-f129.vmdk + filename: TEST_DIR/t-f129.IMGFMT format: FLAT [129]: virtual size: 2147483648 - filename: TEST_DIR/t-f130.vmdk + filename: TEST_DIR/t-f130.IMGFMT format: FLAT [130]: virtual size: 2147483648 - filename: TEST_DIR/t-f131.vmdk + filename: TEST_DIR/t-f131.IMGFMT format: FLAT [131]: virtual size: 2147483648 - filename: TEST_DIR/t-f132.vmdk + filename: TEST_DIR/t-f132.IMGFMT format: FLAT [132]: virtual size: 2147483648 - filename: TEST_DIR/t-f133.vmdk + filename: TEST_DIR/t-f133.IMGFMT format: FLAT [133]: virtual size: 2147483648 - filename: TEST_DIR/t-f134.vmdk + filename: TEST_DIR/t-f134.IMGFMT format: FLAT [134]: virtual size: 2147483648 - filename: TEST_DIR/t-f135.vmdk + filename: TEST_DIR/t-f135.IMGFMT format: FLAT [135]: virtual size: 2147483648 - filename: TEST_DIR/t-f136.vmdk + filename: TEST_DIR/t-f136.IMGFMT format: FLAT [136]: virtual size: 2147483648 - filename: TEST_DIR/t-f137.vmdk + filename: TEST_DIR/t-f137.IMGFMT format: FLAT [137]: virtual size: 2147483648 - filename: TEST_DIR/t-f138.vmdk + filename: TEST_DIR/t-f138.IMGFMT format: FLAT [138]: virtual size: 2147483648 - filename: TEST_DIR/t-f139.vmdk + filename: TEST_DIR/t-f139.IMGFMT format: FLAT [139]: virtual size: 2147483648 - filename: TEST_DIR/t-f140.vmdk + filename: TEST_DIR/t-f140.IMGFMT format: FLAT [140]: virtual size: 2147483648 - filename: TEST_DIR/t-f141.vmdk + filename: TEST_DIR/t-f141.IMGFMT format: FLAT [141]: virtual size: 2147483648 - filename: TEST_DIR/t-f142.vmdk + filename: TEST_DIR/t-f142.IMGFMT format: FLAT [142]: virtual size: 2147483648 - filename: TEST_DIR/t-f143.vmdk + filename: TEST_DIR/t-f143.IMGFMT format: FLAT [143]: virtual size: 2147483648 - filename: TEST_DIR/t-f144.vmdk + filename: TEST_DIR/t-f144.IMGFMT format: FLAT [144]: virtual size: 2147483648 - filename: TEST_DIR/t-f145.vmdk + filename: TEST_DIR/t-f145.IMGFMT format: FLAT [145]: virtual size: 2147483648 - filename: TEST_DIR/t-f146.vmdk + filename: TEST_DIR/t-f146.IMGFMT format: FLAT [146]: virtual size: 2147483648 - filename: TEST_DIR/t-f147.vmdk + filename: TEST_DIR/t-f147.IMGFMT format: FLAT [147]: virtual size: 2147483648 - filename: TEST_DIR/t-f148.vmdk + filename: TEST_DIR/t-f148.IMGFMT format: FLAT [148]: virtual size: 2147483648 - filename: TEST_DIR/t-f149.vmdk + filename: TEST_DIR/t-f149.IMGFMT format: FLAT [149]: virtual size: 2147483648 - filename: TEST_DIR/t-f150.vmdk + filename: TEST_DIR/t-f150.IMGFMT format: FLAT [150]: virtual size: 2147483648 - filename: TEST_DIR/t-f151.vmdk + filename: TEST_DIR/t-f151.IMGFMT format: FLAT [151]: virtual size: 2147483648 - filename: TEST_DIR/t-f152.vmdk + filename: TEST_DIR/t-f152.IMGFMT format: FLAT [152]: virtual size: 2147483648 - filename: TEST_DIR/t-f153.vmdk + filename: TEST_DIR/t-f153.IMGFMT format: FLAT [153]: virtual size: 2147483648 - filename: TEST_DIR/t-f154.vmdk + filename: TEST_DIR/t-f154.IMGFMT format: FLAT [154]: virtual size: 2147483648 - filename: TEST_DIR/t-f155.vmdk + filename: TEST_DIR/t-f155.IMGFMT format: FLAT [155]: virtual size: 2147483648 - filename: TEST_DIR/t-f156.vmdk + filename: TEST_DIR/t-f156.IMGFMT format: FLAT [156]: virtual size: 2147483648 - filename: TEST_DIR/t-f157.vmdk + filename: TEST_DIR/t-f157.IMGFMT format: FLAT [157]: virtual size: 2147483648 - filename: TEST_DIR/t-f158.vmdk + filename: TEST_DIR/t-f158.IMGFMT format: FLAT [158]: virtual size: 2147483648 - filename: TEST_DIR/t-f159.vmdk + filename: TEST_DIR/t-f159.IMGFMT format: FLAT [159]: virtual size: 2147483648 - filename: TEST_DIR/t-f160.vmdk + filename: TEST_DIR/t-f160.IMGFMT format: FLAT [160]: virtual size: 2147483648 - filename: TEST_DIR/t-f161.vmdk + filename: TEST_DIR/t-f161.IMGFMT format: FLAT [161]: virtual size: 2147483648 - filename: TEST_DIR/t-f162.vmdk + filename: TEST_DIR/t-f162.IMGFMT format: FLAT [162]: virtual size: 2147483648 - filename: TEST_DIR/t-f163.vmdk + filename: TEST_DIR/t-f163.IMGFMT format: FLAT [163]: virtual size: 2147483648 - filename: TEST_DIR/t-f164.vmdk + filename: TEST_DIR/t-f164.IMGFMT format: FLAT [164]: virtual size: 2147483648 - filename: TEST_DIR/t-f165.vmdk + filename: TEST_DIR/t-f165.IMGFMT format: FLAT [165]: virtual size: 2147483648 - filename: TEST_DIR/t-f166.vmdk + filename: TEST_DIR/t-f166.IMGFMT format: FLAT [166]: virtual size: 2147483648 - filename: TEST_DIR/t-f167.vmdk + filename: TEST_DIR/t-f167.IMGFMT format: FLAT [167]: virtual size: 2147483648 - filename: TEST_DIR/t-f168.vmdk + filename: TEST_DIR/t-f168.IMGFMT format: FLAT [168]: virtual size: 2147483648 - filename: TEST_DIR/t-f169.vmdk + filename: TEST_DIR/t-f169.IMGFMT format: FLAT [169]: virtual size: 2147483648 - filename: TEST_DIR/t-f170.vmdk + filename: TEST_DIR/t-f170.IMGFMT format: FLAT [170]: virtual size: 2147483648 - filename: TEST_DIR/t-f171.vmdk + filename: TEST_DIR/t-f171.IMGFMT format: FLAT [171]: virtual size: 2147483648 - filename: TEST_DIR/t-f172.vmdk + filename: TEST_DIR/t-f172.IMGFMT format: FLAT [172]: virtual size: 2147483648 - filename: TEST_DIR/t-f173.vmdk + filename: TEST_DIR/t-f173.IMGFMT format: FLAT [173]: virtual size: 2147483648 - filename: TEST_DIR/t-f174.vmdk + filename: TEST_DIR/t-f174.IMGFMT format: FLAT [174]: virtual size: 2147483648 - filename: TEST_DIR/t-f175.vmdk + filename: TEST_DIR/t-f175.IMGFMT format: FLAT [175]: virtual size: 2147483648 - filename: TEST_DIR/t-f176.vmdk + filename: TEST_DIR/t-f176.IMGFMT format: FLAT [176]: virtual size: 2147483648 - filename: TEST_DIR/t-f177.vmdk + filename: TEST_DIR/t-f177.IMGFMT format: FLAT [177]: virtual size: 2147483648 - filename: TEST_DIR/t-f178.vmdk + filename: TEST_DIR/t-f178.IMGFMT format: FLAT [178]: virtual size: 2147483648 - filename: TEST_DIR/t-f179.vmdk + filename: TEST_DIR/t-f179.IMGFMT format: FLAT [179]: virtual size: 2147483648 - filename: TEST_DIR/t-f180.vmdk + filename: TEST_DIR/t-f180.IMGFMT format: FLAT [180]: virtual size: 2147483648 - filename: TEST_DIR/t-f181.vmdk + filename: TEST_DIR/t-f181.IMGFMT format: FLAT [181]: virtual size: 2147483648 - filename: TEST_DIR/t-f182.vmdk + filename: TEST_DIR/t-f182.IMGFMT format: FLAT [182]: virtual size: 2147483648 - filename: TEST_DIR/t-f183.vmdk + filename: TEST_DIR/t-f183.IMGFMT format: FLAT [183]: virtual size: 2147483648 - filename: TEST_DIR/t-f184.vmdk + filename: TEST_DIR/t-f184.IMGFMT format: FLAT [184]: virtual size: 2147483648 - filename: TEST_DIR/t-f185.vmdk + filename: TEST_DIR/t-f185.IMGFMT format: FLAT [185]: virtual size: 2147483648 - filename: TEST_DIR/t-f186.vmdk + filename: TEST_DIR/t-f186.IMGFMT format: FLAT [186]: virtual size: 2147483648 - filename: TEST_DIR/t-f187.vmdk + filename: TEST_DIR/t-f187.IMGFMT format: FLAT [187]: virtual size: 2147483648 - filename: TEST_DIR/t-f188.vmdk + filename: TEST_DIR/t-f188.IMGFMT format: FLAT [188]: virtual size: 2147483648 - filename: TEST_DIR/t-f189.vmdk + filename: TEST_DIR/t-f189.IMGFMT format: FLAT [189]: virtual size: 2147483648 - filename: TEST_DIR/t-f190.vmdk + filename: TEST_DIR/t-f190.IMGFMT format: FLAT [190]: virtual size: 2147483648 - filename: TEST_DIR/t-f191.vmdk + filename: TEST_DIR/t-f191.IMGFMT format: FLAT [191]: virtual size: 2147483648 - filename: TEST_DIR/t-f192.vmdk + filename: TEST_DIR/t-f192.IMGFMT format: FLAT [192]: virtual size: 2147483648 - filename: TEST_DIR/t-f193.vmdk + filename: TEST_DIR/t-f193.IMGFMT format: FLAT [193]: virtual size: 2147483648 - filename: TEST_DIR/t-f194.vmdk + filename: TEST_DIR/t-f194.IMGFMT format: FLAT [194]: virtual size: 2147483648 - filename: TEST_DIR/t-f195.vmdk + filename: TEST_DIR/t-f195.IMGFMT format: FLAT [195]: virtual size: 2147483648 - filename: TEST_DIR/t-f196.vmdk + filename: TEST_DIR/t-f196.IMGFMT format: FLAT [196]: virtual size: 2147483648 - filename: TEST_DIR/t-f197.vmdk + filename: TEST_DIR/t-f197.IMGFMT format: FLAT [197]: virtual size: 2147483648 - filename: TEST_DIR/t-f198.vmdk + filename: TEST_DIR/t-f198.IMGFMT format: FLAT [198]: virtual size: 2147483648 - filename: TEST_DIR/t-f199.vmdk + filename: TEST_DIR/t-f199.IMGFMT format: FLAT [199]: virtual size: 2147483648 - filename: TEST_DIR/t-f200.vmdk + filename: TEST_DIR/t-f200.IMGFMT format: FLAT [200]: virtual size: 2147483648 - filename: TEST_DIR/t-f201.vmdk + filename: TEST_DIR/t-f201.IMGFMT format: FLAT [201]: virtual size: 2147483648 - filename: TEST_DIR/t-f202.vmdk + filename: TEST_DIR/t-f202.IMGFMT format: FLAT [202]: virtual size: 2147483648 - filename: TEST_DIR/t-f203.vmdk + filename: TEST_DIR/t-f203.IMGFMT format: FLAT [203]: virtual size: 2147483648 - filename: TEST_DIR/t-f204.vmdk + filename: TEST_DIR/t-f204.IMGFMT format: FLAT [204]: virtual size: 2147483648 - filename: TEST_DIR/t-f205.vmdk + filename: TEST_DIR/t-f205.IMGFMT format: FLAT [205]: virtual size: 2147483648 - filename: TEST_DIR/t-f206.vmdk + filename: TEST_DIR/t-f206.IMGFMT format: FLAT [206]: virtual size: 2147483648 - filename: TEST_DIR/t-f207.vmdk + filename: TEST_DIR/t-f207.IMGFMT format: FLAT [207]: virtual size: 2147483648 - filename: TEST_DIR/t-f208.vmdk + filename: TEST_DIR/t-f208.IMGFMT format: FLAT [208]: virtual size: 2147483648 - filename: TEST_DIR/t-f209.vmdk + filename: TEST_DIR/t-f209.IMGFMT format: FLAT [209]: virtual size: 2147483648 - filename: TEST_DIR/t-f210.vmdk + filename: TEST_DIR/t-f210.IMGFMT format: FLAT [210]: virtual size: 2147483648 - filename: TEST_DIR/t-f211.vmdk + filename: TEST_DIR/t-f211.IMGFMT format: FLAT [211]: virtual size: 2147483648 - filename: TEST_DIR/t-f212.vmdk + filename: TEST_DIR/t-f212.IMGFMT format: FLAT [212]: virtual size: 2147483648 - filename: TEST_DIR/t-f213.vmdk + filename: TEST_DIR/t-f213.IMGFMT format: FLAT [213]: virtual size: 2147483648 - filename: TEST_DIR/t-f214.vmdk + filename: TEST_DIR/t-f214.IMGFMT format: FLAT [214]: virtual size: 2147483648 - filename: TEST_DIR/t-f215.vmdk + filename: TEST_DIR/t-f215.IMGFMT format: FLAT [215]: virtual size: 2147483648 - filename: TEST_DIR/t-f216.vmdk + filename: TEST_DIR/t-f216.IMGFMT format: FLAT [216]: virtual size: 2147483648 - filename: TEST_DIR/t-f217.vmdk + filename: TEST_DIR/t-f217.IMGFMT format: FLAT [217]: virtual size: 2147483648 - filename: TEST_DIR/t-f218.vmdk + filename: TEST_DIR/t-f218.IMGFMT format: FLAT [218]: virtual size: 2147483648 - filename: TEST_DIR/t-f219.vmdk + filename: TEST_DIR/t-f219.IMGFMT format: FLAT [219]: virtual size: 2147483648 - filename: TEST_DIR/t-f220.vmdk + filename: TEST_DIR/t-f220.IMGFMT format: FLAT [220]: virtual size: 2147483648 - filename: TEST_DIR/t-f221.vmdk + filename: TEST_DIR/t-f221.IMGFMT format: FLAT [221]: virtual size: 2147483648 - filename: TEST_DIR/t-f222.vmdk + filename: TEST_DIR/t-f222.IMGFMT format: FLAT [222]: virtual size: 2147483648 - filename: TEST_DIR/t-f223.vmdk + filename: TEST_DIR/t-f223.IMGFMT format: FLAT [223]: virtual size: 2147483648 - filename: TEST_DIR/t-f224.vmdk + filename: TEST_DIR/t-f224.IMGFMT format: FLAT [224]: virtual size: 2147483648 - filename: TEST_DIR/t-f225.vmdk + filename: TEST_DIR/t-f225.IMGFMT format: FLAT [225]: virtual size: 2147483648 - filename: TEST_DIR/t-f226.vmdk + filename: TEST_DIR/t-f226.IMGFMT format: FLAT [226]: virtual size: 2147483648 - filename: TEST_DIR/t-f227.vmdk + filename: TEST_DIR/t-f227.IMGFMT format: FLAT [227]: virtual size: 2147483648 - filename: TEST_DIR/t-f228.vmdk + filename: TEST_DIR/t-f228.IMGFMT format: FLAT [228]: virtual size: 2147483648 - filename: TEST_DIR/t-f229.vmdk + filename: TEST_DIR/t-f229.IMGFMT format: FLAT [229]: virtual size: 2147483648 - filename: TEST_DIR/t-f230.vmdk + filename: TEST_DIR/t-f230.IMGFMT format: FLAT [230]: virtual size: 2147483648 - filename: TEST_DIR/t-f231.vmdk + filename: TEST_DIR/t-f231.IMGFMT format: FLAT [231]: virtual size: 2147483648 - filename: TEST_DIR/t-f232.vmdk + filename: TEST_DIR/t-f232.IMGFMT format: FLAT [232]: virtual size: 2147483648 - filename: TEST_DIR/t-f233.vmdk + filename: TEST_DIR/t-f233.IMGFMT format: FLAT [233]: virtual size: 2147483648 - filename: TEST_DIR/t-f234.vmdk + filename: TEST_DIR/t-f234.IMGFMT format: FLAT [234]: virtual size: 2147483648 - filename: TEST_DIR/t-f235.vmdk + filename: TEST_DIR/t-f235.IMGFMT format: FLAT [235]: virtual size: 2147483648 - filename: TEST_DIR/t-f236.vmdk + filename: TEST_DIR/t-f236.IMGFMT format: FLAT [236]: virtual size: 2147483648 - filename: TEST_DIR/t-f237.vmdk + filename: TEST_DIR/t-f237.IMGFMT format: FLAT [237]: virtual size: 2147483648 - filename: TEST_DIR/t-f238.vmdk + filename: TEST_DIR/t-f238.IMGFMT format: FLAT [238]: virtual size: 2147483648 - filename: TEST_DIR/t-f239.vmdk + filename: TEST_DIR/t-f239.IMGFMT format: FLAT [239]: virtual size: 2147483648 - filename: TEST_DIR/t-f240.vmdk + filename: TEST_DIR/t-f240.IMGFMT format: FLAT [240]: virtual size: 2147483648 - filename: TEST_DIR/t-f241.vmdk + filename: TEST_DIR/t-f241.IMGFMT format: FLAT [241]: virtual size: 2147483648 - filename: TEST_DIR/t-f242.vmdk + filename: TEST_DIR/t-f242.IMGFMT format: FLAT [242]: virtual size: 2147483648 - filename: TEST_DIR/t-f243.vmdk + filename: TEST_DIR/t-f243.IMGFMT format: FLAT [243]: virtual size: 2147483648 - filename: TEST_DIR/t-f244.vmdk + filename: TEST_DIR/t-f244.IMGFMT format: FLAT [244]: virtual size: 2147483648 - filename: TEST_DIR/t-f245.vmdk + filename: TEST_DIR/t-f245.IMGFMT format: FLAT [245]: virtual size: 2147483648 - filename: TEST_DIR/t-f246.vmdk + filename: TEST_DIR/t-f246.IMGFMT format: FLAT [246]: virtual size: 2147483648 - filename: TEST_DIR/t-f247.vmdk + filename: TEST_DIR/t-f247.IMGFMT format: FLAT [247]: virtual size: 2147483648 - filename: TEST_DIR/t-f248.vmdk + filename: TEST_DIR/t-f248.IMGFMT format: FLAT [248]: virtual size: 2147483648 - filename: TEST_DIR/t-f249.vmdk + filename: TEST_DIR/t-f249.IMGFMT format: FLAT [249]: virtual size: 2147483648 - filename: TEST_DIR/t-f250.vmdk + filename: TEST_DIR/t-f250.IMGFMT format: FLAT [250]: virtual size: 2147483648 - filename: TEST_DIR/t-f251.vmdk + filename: TEST_DIR/t-f251.IMGFMT format: FLAT [251]: virtual size: 2147483648 - filename: TEST_DIR/t-f252.vmdk + filename: TEST_DIR/t-f252.IMGFMT format: FLAT [252]: virtual size: 2147483648 - filename: TEST_DIR/t-f253.vmdk + filename: TEST_DIR/t-f253.IMGFMT format: FLAT [253]: virtual size: 2147483648 - filename: TEST_DIR/t-f254.vmdk + filename: TEST_DIR/t-f254.IMGFMT format: FLAT [254]: virtual size: 2147483648 - filename: TEST_DIR/t-f255.vmdk + filename: TEST_DIR/t-f255.IMGFMT format: FLAT [255]: virtual size: 2147483648 - filename: TEST_DIR/t-f256.vmdk + filename: TEST_DIR/t-f256.IMGFMT format: FLAT [256]: virtual size: 2147483648 - filename: TEST_DIR/t-f257.vmdk + filename: TEST_DIR/t-f257.IMGFMT format: FLAT [257]: virtual size: 2147483648 - filename: TEST_DIR/t-f258.vmdk + filename: TEST_DIR/t-f258.IMGFMT format: FLAT [258]: virtual size: 2147483648 - filename: TEST_DIR/t-f259.vmdk + filename: TEST_DIR/t-f259.IMGFMT format: FLAT [259]: virtual size: 2147483648 - filename: TEST_DIR/t-f260.vmdk + filename: TEST_DIR/t-f260.IMGFMT format: FLAT [260]: virtual size: 2147483648 - filename: TEST_DIR/t-f261.vmdk + filename: TEST_DIR/t-f261.IMGFMT format: FLAT [261]: virtual size: 2147483648 - filename: TEST_DIR/t-f262.vmdk + filename: TEST_DIR/t-f262.IMGFMT format: FLAT [262]: virtual size: 2147483648 - filename: TEST_DIR/t-f263.vmdk + filename: TEST_DIR/t-f263.IMGFMT format: FLAT [263]: virtual size: 2147483648 - filename: TEST_DIR/t-f264.vmdk + filename: TEST_DIR/t-f264.IMGFMT format: FLAT [264]: virtual size: 2147483648 - filename: TEST_DIR/t-f265.vmdk + filename: TEST_DIR/t-f265.IMGFMT format: FLAT [265]: virtual size: 2147483648 - filename: TEST_DIR/t-f266.vmdk + filename: TEST_DIR/t-f266.IMGFMT format: FLAT [266]: virtual size: 2147483648 - filename: TEST_DIR/t-f267.vmdk + filename: TEST_DIR/t-f267.IMGFMT format: FLAT [267]: virtual size: 2147483648 - filename: TEST_DIR/t-f268.vmdk + filename: TEST_DIR/t-f268.IMGFMT format: FLAT [268]: virtual size: 2147483648 - filename: TEST_DIR/t-f269.vmdk + filename: TEST_DIR/t-f269.IMGFMT format: FLAT [269]: virtual size: 2147483648 - filename: TEST_DIR/t-f270.vmdk + filename: TEST_DIR/t-f270.IMGFMT format: FLAT [270]: virtual size: 2147483648 - filename: TEST_DIR/t-f271.vmdk + filename: TEST_DIR/t-f271.IMGFMT format: FLAT [271]: virtual size: 2147483648 - filename: TEST_DIR/t-f272.vmdk + filename: TEST_DIR/t-f272.IMGFMT format: FLAT [272]: virtual size: 2147483648 - filename: TEST_DIR/t-f273.vmdk + filename: TEST_DIR/t-f273.IMGFMT format: FLAT [273]: virtual size: 2147483648 - filename: TEST_DIR/t-f274.vmdk + filename: TEST_DIR/t-f274.IMGFMT format: FLAT [274]: virtual size: 2147483648 - filename: TEST_DIR/t-f275.vmdk + filename: TEST_DIR/t-f275.IMGFMT format: FLAT [275]: virtual size: 2147483648 - filename: TEST_DIR/t-f276.vmdk + filename: TEST_DIR/t-f276.IMGFMT format: FLAT [276]: virtual size: 2147483648 - filename: TEST_DIR/t-f277.vmdk + filename: TEST_DIR/t-f277.IMGFMT format: FLAT [277]: virtual size: 2147483648 - filename: TEST_DIR/t-f278.vmdk + filename: TEST_DIR/t-f278.IMGFMT format: FLAT [278]: virtual size: 2147483648 - filename: TEST_DIR/t-f279.vmdk + filename: TEST_DIR/t-f279.IMGFMT format: FLAT [279]: virtual size: 2147483648 - filename: TEST_DIR/t-f280.vmdk + filename: TEST_DIR/t-f280.IMGFMT format: FLAT [280]: virtual size: 2147483648 - filename: TEST_DIR/t-f281.vmdk + filename: TEST_DIR/t-f281.IMGFMT format: FLAT [281]: virtual size: 2147483648 - filename: TEST_DIR/t-f282.vmdk + filename: TEST_DIR/t-f282.IMGFMT format: FLAT [282]: virtual size: 2147483648 - filename: TEST_DIR/t-f283.vmdk + filename: TEST_DIR/t-f283.IMGFMT format: FLAT [283]: virtual size: 2147483648 - filename: TEST_DIR/t-f284.vmdk + filename: TEST_DIR/t-f284.IMGFMT format: FLAT [284]: virtual size: 2147483648 - filename: TEST_DIR/t-f285.vmdk + filename: TEST_DIR/t-f285.IMGFMT format: FLAT [285]: virtual size: 2147483648 - filename: TEST_DIR/t-f286.vmdk + filename: TEST_DIR/t-f286.IMGFMT format: FLAT [286]: virtual size: 2147483648 - filename: TEST_DIR/t-f287.vmdk + filename: TEST_DIR/t-f287.IMGFMT format: FLAT [287]: virtual size: 2147483648 - filename: TEST_DIR/t-f288.vmdk + filename: TEST_DIR/t-f288.IMGFMT format: FLAT [288]: virtual size: 2147483648 - filename: TEST_DIR/t-f289.vmdk + filename: TEST_DIR/t-f289.IMGFMT format: FLAT [289]: virtual size: 2147483648 - filename: TEST_DIR/t-f290.vmdk + filename: TEST_DIR/t-f290.IMGFMT format: FLAT [290]: virtual size: 2147483648 - filename: TEST_DIR/t-f291.vmdk + filename: TEST_DIR/t-f291.IMGFMT format: FLAT [291]: virtual size: 2147483648 - filename: TEST_DIR/t-f292.vmdk + filename: TEST_DIR/t-f292.IMGFMT format: FLAT [292]: virtual size: 2147483648 - filename: TEST_DIR/t-f293.vmdk + filename: TEST_DIR/t-f293.IMGFMT format: FLAT [293]: virtual size: 2147483648 - filename: TEST_DIR/t-f294.vmdk + filename: TEST_DIR/t-f294.IMGFMT format: FLAT [294]: virtual size: 2147483648 - filename: TEST_DIR/t-f295.vmdk + filename: TEST_DIR/t-f295.IMGFMT format: FLAT [295]: virtual size: 2147483648 - filename: TEST_DIR/t-f296.vmdk + filename: TEST_DIR/t-f296.IMGFMT format: FLAT [296]: virtual size: 2147483648 - filename: TEST_DIR/t-f297.vmdk + filename: TEST_DIR/t-f297.IMGFMT format: FLAT [297]: virtual size: 2147483648 - filename: TEST_DIR/t-f298.vmdk + filename: TEST_DIR/t-f298.IMGFMT format: FLAT [298]: virtual size: 2147483648 - filename: TEST_DIR/t-f299.vmdk + filename: TEST_DIR/t-f299.IMGFMT format: FLAT [299]: virtual size: 2147483648 - filename: TEST_DIR/t-f300.vmdk + filename: TEST_DIR/t-f300.IMGFMT format: FLAT [300]: virtual size: 2147483648 - filename: TEST_DIR/t-f301.vmdk + filename: TEST_DIR/t-f301.IMGFMT format: FLAT [301]: virtual size: 2147483648 - filename: TEST_DIR/t-f302.vmdk + filename: TEST_DIR/t-f302.IMGFMT format: FLAT [302]: virtual size: 2147483648 - filename: TEST_DIR/t-f303.vmdk + filename: TEST_DIR/t-f303.IMGFMT format: FLAT [303]: virtual size: 2147483648 - filename: TEST_DIR/t-f304.vmdk + filename: TEST_DIR/t-f304.IMGFMT format: FLAT [304]: virtual size: 2147483648 - filename: TEST_DIR/t-f305.vmdk + filename: TEST_DIR/t-f305.IMGFMT format: FLAT [305]: virtual size: 2147483648 - filename: TEST_DIR/t-f306.vmdk + filename: TEST_DIR/t-f306.IMGFMT format: FLAT [306]: virtual size: 2147483648 - filename: TEST_DIR/t-f307.vmdk + filename: TEST_DIR/t-f307.IMGFMT format: FLAT [307]: virtual size: 2147483648 - filename: TEST_DIR/t-f308.vmdk + filename: TEST_DIR/t-f308.IMGFMT format: FLAT [308]: virtual size: 2147483648 - filename: TEST_DIR/t-f309.vmdk + filename: TEST_DIR/t-f309.IMGFMT format: FLAT [309]: virtual size: 2147483648 - filename: TEST_DIR/t-f310.vmdk + filename: TEST_DIR/t-f310.IMGFMT format: FLAT [310]: virtual size: 2147483648 - filename: TEST_DIR/t-f311.vmdk + filename: TEST_DIR/t-f311.IMGFMT format: FLAT [311]: virtual size: 2147483648 - filename: TEST_DIR/t-f312.vmdk + filename: TEST_DIR/t-f312.IMGFMT format: FLAT [312]: virtual size: 2147483648 - filename: TEST_DIR/t-f313.vmdk + filename: TEST_DIR/t-f313.IMGFMT format: FLAT [313]: virtual size: 2147483648 - filename: TEST_DIR/t-f314.vmdk + filename: TEST_DIR/t-f314.IMGFMT format: FLAT [314]: virtual size: 2147483648 - filename: TEST_DIR/t-f315.vmdk + filename: TEST_DIR/t-f315.IMGFMT format: FLAT [315]: virtual size: 2147483648 - filename: TEST_DIR/t-f316.vmdk + filename: TEST_DIR/t-f316.IMGFMT format: FLAT [316]: virtual size: 2147483648 - filename: TEST_DIR/t-f317.vmdk + filename: TEST_DIR/t-f317.IMGFMT format: FLAT [317]: virtual size: 2147483648 - filename: TEST_DIR/t-f318.vmdk + filename: TEST_DIR/t-f318.IMGFMT format: FLAT [318]: virtual size: 2147483648 - filename: TEST_DIR/t-f319.vmdk + filename: TEST_DIR/t-f319.IMGFMT format: FLAT [319]: virtual size: 2147483648 - filename: TEST_DIR/t-f320.vmdk + filename: TEST_DIR/t-f320.IMGFMT format: FLAT [320]: virtual size: 2147483648 - filename: TEST_DIR/t-f321.vmdk + filename: TEST_DIR/t-f321.IMGFMT format: FLAT [321]: virtual size: 2147483648 - filename: TEST_DIR/t-f322.vmdk + filename: TEST_DIR/t-f322.IMGFMT format: FLAT [322]: virtual size: 2147483648 - filename: TEST_DIR/t-f323.vmdk + filename: TEST_DIR/t-f323.IMGFMT format: FLAT [323]: virtual size: 2147483648 - filename: TEST_DIR/t-f324.vmdk + filename: TEST_DIR/t-f324.IMGFMT format: FLAT [324]: virtual size: 2147483648 - filename: TEST_DIR/t-f325.vmdk + filename: TEST_DIR/t-f325.IMGFMT format: FLAT [325]: virtual size: 2147483648 - filename: TEST_DIR/t-f326.vmdk + filename: TEST_DIR/t-f326.IMGFMT format: FLAT [326]: virtual size: 2147483648 - filename: TEST_DIR/t-f327.vmdk + filename: TEST_DIR/t-f327.IMGFMT format: FLAT [327]: virtual size: 2147483648 - filename: TEST_DIR/t-f328.vmdk + filename: TEST_DIR/t-f328.IMGFMT format: FLAT [328]: virtual size: 2147483648 - filename: TEST_DIR/t-f329.vmdk + filename: TEST_DIR/t-f329.IMGFMT format: FLAT [329]: virtual size: 2147483648 - filename: TEST_DIR/t-f330.vmdk + filename: TEST_DIR/t-f330.IMGFMT format: FLAT [330]: virtual size: 2147483648 - filename: TEST_DIR/t-f331.vmdk + filename: TEST_DIR/t-f331.IMGFMT format: FLAT [331]: virtual size: 2147483648 - filename: TEST_DIR/t-f332.vmdk + filename: TEST_DIR/t-f332.IMGFMT format: FLAT [332]: virtual size: 2147483648 - filename: TEST_DIR/t-f333.vmdk + filename: TEST_DIR/t-f333.IMGFMT format: FLAT [333]: virtual size: 2147483648 - filename: TEST_DIR/t-f334.vmdk + filename: TEST_DIR/t-f334.IMGFMT format: FLAT [334]: virtual size: 2147483648 - filename: TEST_DIR/t-f335.vmdk + filename: TEST_DIR/t-f335.IMGFMT format: FLAT [335]: virtual size: 2147483648 - filename: TEST_DIR/t-f336.vmdk + filename: TEST_DIR/t-f336.IMGFMT format: FLAT [336]: virtual size: 2147483648 - filename: TEST_DIR/t-f337.vmdk + filename: TEST_DIR/t-f337.IMGFMT format: FLAT [337]: virtual size: 2147483648 - filename: TEST_DIR/t-f338.vmdk + filename: TEST_DIR/t-f338.IMGFMT format: FLAT [338]: virtual size: 2147483648 - filename: TEST_DIR/t-f339.vmdk + filename: TEST_DIR/t-f339.IMGFMT format: FLAT [339]: virtual size: 2147483648 - filename: TEST_DIR/t-f340.vmdk + filename: TEST_DIR/t-f340.IMGFMT format: FLAT [340]: virtual size: 2147483648 - filename: TEST_DIR/t-f341.vmdk + filename: TEST_DIR/t-f341.IMGFMT format: FLAT [341]: virtual size: 2147483648 - filename: TEST_DIR/t-f342.vmdk + filename: TEST_DIR/t-f342.IMGFMT format: FLAT [342]: virtual size: 2147483648 - filename: TEST_DIR/t-f343.vmdk + filename: TEST_DIR/t-f343.IMGFMT format: FLAT [343]: virtual size: 2147483648 - filename: TEST_DIR/t-f344.vmdk + filename: TEST_DIR/t-f344.IMGFMT format: FLAT [344]: virtual size: 2147483648 - filename: TEST_DIR/t-f345.vmdk + filename: TEST_DIR/t-f345.IMGFMT format: FLAT [345]: virtual size: 2147483648 - filename: TEST_DIR/t-f346.vmdk + filename: TEST_DIR/t-f346.IMGFMT format: FLAT [346]: virtual size: 2147483648 - filename: TEST_DIR/t-f347.vmdk + filename: TEST_DIR/t-f347.IMGFMT format: FLAT [347]: virtual size: 2147483648 - filename: TEST_DIR/t-f348.vmdk + filename: TEST_DIR/t-f348.IMGFMT format: FLAT [348]: virtual size: 2147483648 - filename: TEST_DIR/t-f349.vmdk + filename: TEST_DIR/t-f349.IMGFMT format: FLAT [349]: virtual size: 2147483648 - filename: TEST_DIR/t-f350.vmdk + filename: TEST_DIR/t-f350.IMGFMT format: FLAT [350]: virtual size: 2147483648 - filename: TEST_DIR/t-f351.vmdk + filename: TEST_DIR/t-f351.IMGFMT format: FLAT [351]: virtual size: 2147483648 - filename: TEST_DIR/t-f352.vmdk + filename: TEST_DIR/t-f352.IMGFMT format: FLAT [352]: virtual size: 2147483648 - filename: TEST_DIR/t-f353.vmdk + filename: TEST_DIR/t-f353.IMGFMT format: FLAT [353]: virtual size: 2147483648 - filename: TEST_DIR/t-f354.vmdk + filename: TEST_DIR/t-f354.IMGFMT format: FLAT [354]: virtual size: 2147483648 - filename: TEST_DIR/t-f355.vmdk + filename: TEST_DIR/t-f355.IMGFMT format: FLAT [355]: virtual size: 2147483648 - filename: TEST_DIR/t-f356.vmdk + filename: TEST_DIR/t-f356.IMGFMT format: FLAT [356]: virtual size: 2147483648 - filename: TEST_DIR/t-f357.vmdk + filename: TEST_DIR/t-f357.IMGFMT format: FLAT [357]: virtual size: 2147483648 - filename: TEST_DIR/t-f358.vmdk + filename: TEST_DIR/t-f358.IMGFMT format: FLAT [358]: virtual size: 2147483648 - filename: TEST_DIR/t-f359.vmdk + filename: TEST_DIR/t-f359.IMGFMT format: FLAT [359]: virtual size: 2147483648 - filename: TEST_DIR/t-f360.vmdk + filename: TEST_DIR/t-f360.IMGFMT format: FLAT [360]: virtual size: 2147483648 - filename: TEST_DIR/t-f361.vmdk + filename: TEST_DIR/t-f361.IMGFMT format: FLAT [361]: virtual size: 2147483648 - filename: TEST_DIR/t-f362.vmdk + filename: TEST_DIR/t-f362.IMGFMT format: FLAT [362]: virtual size: 2147483648 - filename: TEST_DIR/t-f363.vmdk + filename: TEST_DIR/t-f363.IMGFMT format: FLAT [363]: virtual size: 2147483648 - filename: TEST_DIR/t-f364.vmdk + filename: TEST_DIR/t-f364.IMGFMT format: FLAT [364]: virtual size: 2147483648 - filename: TEST_DIR/t-f365.vmdk + filename: TEST_DIR/t-f365.IMGFMT format: FLAT [365]: virtual size: 2147483648 - filename: TEST_DIR/t-f366.vmdk + filename: TEST_DIR/t-f366.IMGFMT format: FLAT [366]: virtual size: 2147483648 - filename: TEST_DIR/t-f367.vmdk + filename: TEST_DIR/t-f367.IMGFMT format: FLAT [367]: virtual size: 2147483648 - filename: TEST_DIR/t-f368.vmdk + filename: TEST_DIR/t-f368.IMGFMT format: FLAT [368]: virtual size: 2147483648 - filename: TEST_DIR/t-f369.vmdk + filename: TEST_DIR/t-f369.IMGFMT format: FLAT [369]: virtual size: 2147483648 - filename: TEST_DIR/t-f370.vmdk + filename: TEST_DIR/t-f370.IMGFMT format: FLAT [370]: virtual size: 2147483648 - filename: TEST_DIR/t-f371.vmdk + filename: TEST_DIR/t-f371.IMGFMT format: FLAT [371]: virtual size: 2147483648 - filename: TEST_DIR/t-f372.vmdk + filename: TEST_DIR/t-f372.IMGFMT format: FLAT [372]: virtual size: 2147483648 - filename: TEST_DIR/t-f373.vmdk + filename: TEST_DIR/t-f373.IMGFMT format: FLAT [373]: virtual size: 2147483648 - filename: TEST_DIR/t-f374.vmdk + filename: TEST_DIR/t-f374.IMGFMT format: FLAT [374]: virtual size: 2147483648 - filename: TEST_DIR/t-f375.vmdk + filename: TEST_DIR/t-f375.IMGFMT format: FLAT [375]: virtual size: 2147483648 - filename: TEST_DIR/t-f376.vmdk + filename: TEST_DIR/t-f376.IMGFMT format: FLAT [376]: virtual size: 2147483648 - filename: TEST_DIR/t-f377.vmdk + filename: TEST_DIR/t-f377.IMGFMT format: FLAT [377]: virtual size: 2147483648 - filename: TEST_DIR/t-f378.vmdk + filename: TEST_DIR/t-f378.IMGFMT format: FLAT [378]: virtual size: 2147483648 - filename: TEST_DIR/t-f379.vmdk + filename: TEST_DIR/t-f379.IMGFMT format: FLAT [379]: virtual size: 2147483648 - filename: TEST_DIR/t-f380.vmdk + filename: TEST_DIR/t-f380.IMGFMT format: FLAT [380]: virtual size: 2147483648 - filename: TEST_DIR/t-f381.vmdk + filename: TEST_DIR/t-f381.IMGFMT format: FLAT [381]: virtual size: 2147483648 - filename: TEST_DIR/t-f382.vmdk + filename: TEST_DIR/t-f382.IMGFMT format: FLAT [382]: virtual size: 2147483648 - filename: TEST_DIR/t-f383.vmdk + filename: TEST_DIR/t-f383.IMGFMT format: FLAT [383]: virtual size: 2147483648 - filename: TEST_DIR/t-f384.vmdk + filename: TEST_DIR/t-f384.IMGFMT format: FLAT [384]: virtual size: 2147483648 - filename: TEST_DIR/t-f385.vmdk + filename: TEST_DIR/t-f385.IMGFMT format: FLAT [385]: virtual size: 2147483648 - filename: TEST_DIR/t-f386.vmdk + filename: TEST_DIR/t-f386.IMGFMT format: FLAT [386]: virtual size: 2147483648 - filename: TEST_DIR/t-f387.vmdk + filename: TEST_DIR/t-f387.IMGFMT format: FLAT [387]: virtual size: 2147483648 - filename: TEST_DIR/t-f388.vmdk + filename: TEST_DIR/t-f388.IMGFMT format: FLAT [388]: virtual size: 2147483648 - filename: TEST_DIR/t-f389.vmdk + filename: TEST_DIR/t-f389.IMGFMT format: FLAT [389]: virtual size: 2147483648 - filename: TEST_DIR/t-f390.vmdk + filename: TEST_DIR/t-f390.IMGFMT format: FLAT [390]: virtual size: 2147483648 - filename: TEST_DIR/t-f391.vmdk + filename: TEST_DIR/t-f391.IMGFMT format: FLAT [391]: virtual size: 2147483648 - filename: TEST_DIR/t-f392.vmdk + filename: TEST_DIR/t-f392.IMGFMT format: FLAT [392]: virtual size: 2147483648 - filename: TEST_DIR/t-f393.vmdk + filename: TEST_DIR/t-f393.IMGFMT format: FLAT [393]: virtual size: 2147483648 - filename: TEST_DIR/t-f394.vmdk + filename: TEST_DIR/t-f394.IMGFMT format: FLAT [394]: virtual size: 2147483648 - filename: TEST_DIR/t-f395.vmdk + filename: TEST_DIR/t-f395.IMGFMT format: FLAT [395]: virtual size: 2147483648 - filename: TEST_DIR/t-f396.vmdk + filename: TEST_DIR/t-f396.IMGFMT format: FLAT [396]: virtual size: 2147483648 - filename: TEST_DIR/t-f397.vmdk + filename: TEST_DIR/t-f397.IMGFMT format: FLAT [397]: virtual size: 2147483648 - filename: TEST_DIR/t-f398.vmdk + filename: TEST_DIR/t-f398.IMGFMT format: FLAT [398]: virtual size: 2147483648 - filename: TEST_DIR/t-f399.vmdk + filename: TEST_DIR/t-f399.IMGFMT format: FLAT [399]: virtual size: 2147483648 - filename: TEST_DIR/t-f400.vmdk + filename: TEST_DIR/t-f400.IMGFMT format: FLAT [400]: virtual size: 2147483648 - filename: TEST_DIR/t-f401.vmdk + filename: TEST_DIR/t-f401.IMGFMT format: FLAT [401]: virtual size: 2147483648 - filename: TEST_DIR/t-f402.vmdk + filename: TEST_DIR/t-f402.IMGFMT format: FLAT [402]: virtual size: 2147483648 - filename: TEST_DIR/t-f403.vmdk + filename: TEST_DIR/t-f403.IMGFMT format: FLAT [403]: virtual size: 2147483648 - filename: TEST_DIR/t-f404.vmdk + filename: TEST_DIR/t-f404.IMGFMT format: FLAT [404]: virtual size: 2147483648 - filename: TEST_DIR/t-f405.vmdk + filename: TEST_DIR/t-f405.IMGFMT format: FLAT [405]: virtual size: 2147483648 - filename: TEST_DIR/t-f406.vmdk + filename: TEST_DIR/t-f406.IMGFMT format: FLAT [406]: virtual size: 2147483648 - filename: TEST_DIR/t-f407.vmdk + filename: TEST_DIR/t-f407.IMGFMT format: FLAT [407]: virtual size: 2147483648 - filename: TEST_DIR/t-f408.vmdk + filename: TEST_DIR/t-f408.IMGFMT format: FLAT [408]: virtual size: 2147483648 - filename: TEST_DIR/t-f409.vmdk + filename: TEST_DIR/t-f409.IMGFMT format: FLAT [409]: virtual size: 2147483648 - filename: TEST_DIR/t-f410.vmdk + filename: TEST_DIR/t-f410.IMGFMT format: FLAT [410]: virtual size: 2147483648 - filename: TEST_DIR/t-f411.vmdk + filename: TEST_DIR/t-f411.IMGFMT format: FLAT [411]: virtual size: 2147483648 - filename: TEST_DIR/t-f412.vmdk + filename: TEST_DIR/t-f412.IMGFMT format: FLAT [412]: virtual size: 2147483648 - filename: TEST_DIR/t-f413.vmdk + filename: TEST_DIR/t-f413.IMGFMT format: FLAT [413]: virtual size: 2147483648 - filename: TEST_DIR/t-f414.vmdk + filename: TEST_DIR/t-f414.IMGFMT format: FLAT [414]: virtual size: 2147483648 - filename: TEST_DIR/t-f415.vmdk + filename: TEST_DIR/t-f415.IMGFMT format: FLAT [415]: virtual size: 2147483648 - filename: TEST_DIR/t-f416.vmdk + filename: TEST_DIR/t-f416.IMGFMT format: FLAT [416]: virtual size: 2147483648 - filename: TEST_DIR/t-f417.vmdk + filename: TEST_DIR/t-f417.IMGFMT format: FLAT [417]: virtual size: 2147483648 - filename: TEST_DIR/t-f418.vmdk + filename: TEST_DIR/t-f418.IMGFMT format: FLAT [418]: virtual size: 2147483648 - filename: TEST_DIR/t-f419.vmdk + filename: TEST_DIR/t-f419.IMGFMT format: FLAT [419]: virtual size: 2147483648 - filename: TEST_DIR/t-f420.vmdk + filename: TEST_DIR/t-f420.IMGFMT format: FLAT [420]: virtual size: 2147483648 - filename: TEST_DIR/t-f421.vmdk + filename: TEST_DIR/t-f421.IMGFMT format: FLAT [421]: virtual size: 2147483648 - filename: TEST_DIR/t-f422.vmdk + filename: TEST_DIR/t-f422.IMGFMT format: FLAT [422]: virtual size: 2147483648 - filename: TEST_DIR/t-f423.vmdk + filename: TEST_DIR/t-f423.IMGFMT format: FLAT [423]: virtual size: 2147483648 - filename: TEST_DIR/t-f424.vmdk + filename: TEST_DIR/t-f424.IMGFMT format: FLAT [424]: virtual size: 2147483648 - filename: TEST_DIR/t-f425.vmdk + filename: TEST_DIR/t-f425.IMGFMT format: FLAT [425]: virtual size: 2147483648 - filename: TEST_DIR/t-f426.vmdk + filename: TEST_DIR/t-f426.IMGFMT format: FLAT [426]: virtual size: 2147483648 - filename: TEST_DIR/t-f427.vmdk + filename: TEST_DIR/t-f427.IMGFMT format: FLAT [427]: virtual size: 2147483648 - filename: TEST_DIR/t-f428.vmdk + filename: TEST_DIR/t-f428.IMGFMT format: FLAT [428]: virtual size: 2147483648 - filename: TEST_DIR/t-f429.vmdk + filename: TEST_DIR/t-f429.IMGFMT format: FLAT [429]: virtual size: 2147483648 - filename: TEST_DIR/t-f430.vmdk + filename: TEST_DIR/t-f430.IMGFMT format: FLAT [430]: virtual size: 2147483648 - filename: TEST_DIR/t-f431.vmdk + filename: TEST_DIR/t-f431.IMGFMT format: FLAT [431]: virtual size: 2147483648 - filename: TEST_DIR/t-f432.vmdk + filename: TEST_DIR/t-f432.IMGFMT format: FLAT [432]: virtual size: 2147483648 - filename: TEST_DIR/t-f433.vmdk + filename: TEST_DIR/t-f433.IMGFMT format: FLAT [433]: virtual size: 2147483648 - filename: TEST_DIR/t-f434.vmdk + filename: TEST_DIR/t-f434.IMGFMT format: FLAT [434]: virtual size: 2147483648 - filename: TEST_DIR/t-f435.vmdk + filename: TEST_DIR/t-f435.IMGFMT format: FLAT [435]: virtual size: 2147483648 - filename: TEST_DIR/t-f436.vmdk + filename: TEST_DIR/t-f436.IMGFMT format: FLAT [436]: virtual size: 2147483648 - filename: TEST_DIR/t-f437.vmdk + filename: TEST_DIR/t-f437.IMGFMT format: FLAT [437]: virtual size: 2147483648 - filename: TEST_DIR/t-f438.vmdk + filename: TEST_DIR/t-f438.IMGFMT format: FLAT [438]: virtual size: 2147483648 - filename: TEST_DIR/t-f439.vmdk + filename: TEST_DIR/t-f439.IMGFMT format: FLAT [439]: virtual size: 2147483648 - filename: TEST_DIR/t-f440.vmdk + filename: TEST_DIR/t-f440.IMGFMT format: FLAT [440]: virtual size: 2147483648 - filename: TEST_DIR/t-f441.vmdk + filename: TEST_DIR/t-f441.IMGFMT format: FLAT [441]: virtual size: 2147483648 - filename: TEST_DIR/t-f442.vmdk + filename: TEST_DIR/t-f442.IMGFMT format: FLAT [442]: virtual size: 2147483648 - filename: TEST_DIR/t-f443.vmdk + filename: TEST_DIR/t-f443.IMGFMT format: FLAT [443]: virtual size: 2147483648 - filename: TEST_DIR/t-f444.vmdk + filename: TEST_DIR/t-f444.IMGFMT format: FLAT [444]: virtual size: 2147483648 - filename: TEST_DIR/t-f445.vmdk + filename: TEST_DIR/t-f445.IMGFMT format: FLAT [445]: virtual size: 2147483648 - filename: TEST_DIR/t-f446.vmdk + filename: TEST_DIR/t-f446.IMGFMT format: FLAT [446]: virtual size: 2147483648 - filename: TEST_DIR/t-f447.vmdk + filename: TEST_DIR/t-f447.IMGFMT format: FLAT [447]: virtual size: 2147483648 - filename: TEST_DIR/t-f448.vmdk + filename: TEST_DIR/t-f448.IMGFMT format: FLAT [448]: virtual size: 2147483648 - filename: TEST_DIR/t-f449.vmdk + filename: TEST_DIR/t-f449.IMGFMT format: FLAT [449]: virtual size: 2147483648 - filename: TEST_DIR/t-f450.vmdk + filename: TEST_DIR/t-f450.IMGFMT format: FLAT [450]: virtual size: 2147483648 - filename: TEST_DIR/t-f451.vmdk + filename: TEST_DIR/t-f451.IMGFMT format: FLAT [451]: virtual size: 2147483648 - filename: TEST_DIR/t-f452.vmdk + filename: TEST_DIR/t-f452.IMGFMT format: FLAT [452]: virtual size: 2147483648 - filename: TEST_DIR/t-f453.vmdk + filename: TEST_DIR/t-f453.IMGFMT format: FLAT [453]: virtual size: 2147483648 - filename: TEST_DIR/t-f454.vmdk + filename: TEST_DIR/t-f454.IMGFMT format: FLAT [454]: virtual size: 2147483648 - filename: TEST_DIR/t-f455.vmdk + filename: TEST_DIR/t-f455.IMGFMT format: FLAT [455]: virtual size: 2147483648 - filename: TEST_DIR/t-f456.vmdk + filename: TEST_DIR/t-f456.IMGFMT format: FLAT [456]: virtual size: 2147483648 - filename: TEST_DIR/t-f457.vmdk + filename: TEST_DIR/t-f457.IMGFMT format: FLAT [457]: virtual size: 2147483648 - filename: TEST_DIR/t-f458.vmdk + filename: TEST_DIR/t-f458.IMGFMT format: FLAT [458]: virtual size: 2147483648 - filename: TEST_DIR/t-f459.vmdk + filename: TEST_DIR/t-f459.IMGFMT format: FLAT [459]: virtual size: 2147483648 - filename: TEST_DIR/t-f460.vmdk + filename: TEST_DIR/t-f460.IMGFMT format: FLAT [460]: virtual size: 2147483648 - filename: TEST_DIR/t-f461.vmdk + filename: TEST_DIR/t-f461.IMGFMT format: FLAT [461]: virtual size: 2147483648 - filename: TEST_DIR/t-f462.vmdk + filename: TEST_DIR/t-f462.IMGFMT format: FLAT [462]: virtual size: 2147483648 - filename: TEST_DIR/t-f463.vmdk + filename: TEST_DIR/t-f463.IMGFMT format: FLAT [463]: virtual size: 2147483648 - filename: TEST_DIR/t-f464.vmdk + filename: TEST_DIR/t-f464.IMGFMT format: FLAT [464]: virtual size: 2147483648 - filename: TEST_DIR/t-f465.vmdk + filename: TEST_DIR/t-f465.IMGFMT format: FLAT [465]: virtual size: 2147483648 - filename: TEST_DIR/t-f466.vmdk + filename: TEST_DIR/t-f466.IMGFMT format: FLAT [466]: virtual size: 2147483648 - filename: TEST_DIR/t-f467.vmdk + filename: TEST_DIR/t-f467.IMGFMT format: FLAT [467]: virtual size: 2147483648 - filename: TEST_DIR/t-f468.vmdk + filename: TEST_DIR/t-f468.IMGFMT format: FLAT [468]: virtual size: 2147483648 - filename: TEST_DIR/t-f469.vmdk + filename: TEST_DIR/t-f469.IMGFMT format: FLAT [469]: virtual size: 2147483648 - filename: TEST_DIR/t-f470.vmdk + filename: TEST_DIR/t-f470.IMGFMT format: FLAT [470]: virtual size: 2147483648 - filename: TEST_DIR/t-f471.vmdk + filename: TEST_DIR/t-f471.IMGFMT format: FLAT [471]: virtual size: 2147483648 - filename: TEST_DIR/t-f472.vmdk + filename: TEST_DIR/t-f472.IMGFMT format: FLAT [472]: virtual size: 2147483648 - filename: TEST_DIR/t-f473.vmdk + filename: TEST_DIR/t-f473.IMGFMT format: FLAT [473]: virtual size: 2147483648 - filename: TEST_DIR/t-f474.vmdk + filename: TEST_DIR/t-f474.IMGFMT format: FLAT [474]: virtual size: 2147483648 - filename: TEST_DIR/t-f475.vmdk + filename: TEST_DIR/t-f475.IMGFMT format: FLAT [475]: virtual size: 2147483648 - filename: TEST_DIR/t-f476.vmdk + filename: TEST_DIR/t-f476.IMGFMT format: FLAT [476]: virtual size: 2147483648 - filename: TEST_DIR/t-f477.vmdk + filename: TEST_DIR/t-f477.IMGFMT format: FLAT [477]: virtual size: 2147483648 - filename: TEST_DIR/t-f478.vmdk + filename: TEST_DIR/t-f478.IMGFMT format: FLAT [478]: virtual size: 2147483648 - filename: TEST_DIR/t-f479.vmdk + filename: TEST_DIR/t-f479.IMGFMT format: FLAT [479]: virtual size: 2147483648 - filename: TEST_DIR/t-f480.vmdk + filename: TEST_DIR/t-f480.IMGFMT format: FLAT [480]: virtual size: 2147483648 - filename: TEST_DIR/t-f481.vmdk + filename: TEST_DIR/t-f481.IMGFMT format: FLAT [481]: virtual size: 2147483648 - filename: TEST_DIR/t-f482.vmdk + filename: TEST_DIR/t-f482.IMGFMT format: FLAT [482]: virtual size: 2147483648 - filename: TEST_DIR/t-f483.vmdk + filename: TEST_DIR/t-f483.IMGFMT format: FLAT [483]: virtual size: 2147483648 - filename: TEST_DIR/t-f484.vmdk + filename: TEST_DIR/t-f484.IMGFMT format: FLAT [484]: virtual size: 2147483648 - filename: TEST_DIR/t-f485.vmdk + filename: TEST_DIR/t-f485.IMGFMT format: FLAT [485]: virtual size: 2147483648 - filename: TEST_DIR/t-f486.vmdk + filename: TEST_DIR/t-f486.IMGFMT format: FLAT [486]: virtual size: 2147483648 - filename: TEST_DIR/t-f487.vmdk + filename: TEST_DIR/t-f487.IMGFMT format: FLAT [487]: virtual size: 2147483648 - filename: TEST_DIR/t-f488.vmdk + filename: TEST_DIR/t-f488.IMGFMT format: FLAT [488]: virtual size: 2147483648 - filename: TEST_DIR/t-f489.vmdk + filename: TEST_DIR/t-f489.IMGFMT format: FLAT [489]: virtual size: 2147483648 - filename: TEST_DIR/t-f490.vmdk + filename: TEST_DIR/t-f490.IMGFMT format: FLAT [490]: virtual size: 2147483648 - filename: TEST_DIR/t-f491.vmdk + filename: TEST_DIR/t-f491.IMGFMT format: FLAT [491]: virtual size: 2147483648 - filename: TEST_DIR/t-f492.vmdk + filename: TEST_DIR/t-f492.IMGFMT format: FLAT [492]: virtual size: 2147483648 - filename: TEST_DIR/t-f493.vmdk + filename: TEST_DIR/t-f493.IMGFMT format: FLAT [493]: virtual size: 2147483648 - filename: TEST_DIR/t-f494.vmdk + filename: TEST_DIR/t-f494.IMGFMT format: FLAT [494]: virtual size: 2147483648 - filename: TEST_DIR/t-f495.vmdk + filename: TEST_DIR/t-f495.IMGFMT format: FLAT [495]: virtual size: 2147483648 - filename: TEST_DIR/t-f496.vmdk + filename: TEST_DIR/t-f496.IMGFMT format: FLAT [496]: virtual size: 2147483648 - filename: TEST_DIR/t-f497.vmdk + filename: TEST_DIR/t-f497.IMGFMT format: FLAT [497]: virtual size: 2147483648 - filename: TEST_DIR/t-f498.vmdk + filename: TEST_DIR/t-f498.IMGFMT format: FLAT [498]: virtual size: 2147483648 - filename: TEST_DIR/t-f499.vmdk + filename: TEST_DIR/t-f499.IMGFMT format: FLAT [499]: virtual size: 2147483648 - filename: TEST_DIR/t-f500.vmdk + filename: TEST_DIR/t-f500.IMGFMT format: FLAT === Testing malformed VMFS extent description line === From ffa244c84a1a30dff69ecc80b0137a2b6d428ecb Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 7 Jul 2020 16:23:29 +0200 Subject: [PATCH 2298/2595] file-posix: Mitigate file fragmentation with extent size hints Especially when O_DIRECT is used with image files so that the page cache indirection can't cause a merge of allocating requests, the file will fragment on the file system layer, with a potentially very small fragment size (this depends on the requests the guest sent). On Linux, fragmentation can be reduced by setting an extent size hint when creating the file (at least on XFS, it can't be set any more after the first extent has been allocated), basically giving raw files a "cluster size" for allocation. This adds a create option to set the extent size hint, and changes the default from not setting a hint to setting it to 1 MB. The main reason why qcow2 defaults to smaller cluster sizes is that COW becomes more expensive, which is not an issue with raw files, so we can choose a larger size. The tradeoff here is only potentially wasted disk space. For qcow2 (or other image formats) over file-posix, the advantage should even be greater because they grow sequentially without leaving holes, so there won't be wasted space. Setting even larger extent size hints for such images may make sense. This can be done with the new option, but let's keep the default conservative for now. The effect is very visible with a test that intentionally creates a badly fragmented file with qemu-img bench (the time difference while creating the file is already remarkable) and then looks at the number of extents and the time a simple "qemu-img map" takes. Without an extent size hint: $ ./qemu-img create -f raw -o extent_size_hint=0 ~/tmp/test.raw 10G Formatting '/home/kwolf/tmp/test.raw', fmt=raw size=10737418240 extent_size_hint=0 $ ./qemu-img bench -f raw -t none -n -w ~/tmp/test.raw -c 1000000 -S 8192 -o 0 Sending 1000000 write requests, 4096 bytes each, 64 in parallel (starting at offset 0, step size 8192) Run completed in 25.848 seconds. $ ./qemu-img bench -f raw -t none -n -w ~/tmp/test.raw -c 1000000 -S 8192 -o 4096 Sending 1000000 write requests, 4096 bytes each, 64 in parallel (starting at offset 4096, step size 8192) Run completed in 19.616 seconds. $ filefrag ~/tmp/test.raw /home/kwolf/tmp/test.raw: 2000000 extents found $ time ./qemu-img map ~/tmp/test.raw Offset Length Mapped to File 0 0x1e8480000 0 /home/kwolf/tmp/test.raw real 0m1,279s user 0m0,043s sys 0m1,226s With the new default extent size hint of 1 MB: $ ./qemu-img create -f raw -o extent_size_hint=1M ~/tmp/test.raw 10G Formatting '/home/kwolf/tmp/test.raw', fmt=raw size=10737418240 extent_size_hint=1048576 $ ./qemu-img bench -f raw -t none -n -w ~/tmp/test.raw -c 1000000 -S 8192 -o 0 Sending 1000000 write requests, 4096 bytes each, 64 in parallel (starting at offset 0, step size 8192) Run completed in 11.833 seconds. $ ./qemu-img bench -f raw -t none -n -w ~/tmp/test.raw -c 1000000 -S 8192 -o 4096 Sending 1000000 write requests, 4096 bytes each, 64 in parallel (starting at offset 4096, step size 8192) Run completed in 10.155 seconds. $ filefrag ~/tmp/test.raw /home/kwolf/tmp/test.raw: 178 extents found $ time ./qemu-img map ~/tmp/test.raw Offset Length Mapped to File 0 0x1e8480000 0 /home/kwolf/tmp/test.raw real 0m0,061s user 0m0,040s sys 0m0,014s Signed-off-by: Kevin Wolf Message-Id: <20200707142329.48303-1-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/file-posix.c | 44 ++++++++++++++++++++++++++++++++++++++ include/block/block_int.h | 1 + qapi/block-core.json | 11 ++++++---- tests/qemu-iotests/082.out | 16 ++++++++++++++ tests/qemu-iotests/106 | 7 ++++-- tests/qemu-iotests/175 | 6 +++--- tests/qemu-iotests/243 | 7 +++--- 7 files changed, 80 insertions(+), 12 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index 1989eae85f..8067e238cb 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -30,6 +30,7 @@ #include "block/block_int.h" #include "qemu/module.h" #include "qemu/option.h" +#include "qemu/units.h" #include "trace.h" #include "block/thread-pool.h" #include "qemu/iov.h" @@ -2318,6 +2319,14 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) if (!file_opts->has_preallocation) { file_opts->preallocation = PREALLOC_MODE_OFF; } + if (!file_opts->has_extent_size_hint) { + file_opts->extent_size_hint = 1 * MiB; + } + if (file_opts->extent_size_hint > UINT32_MAX) { + result = -EINVAL; + error_setg(errp, "Extent size hint is too large"); + goto out; + } /* Create file */ fd = qemu_open(file_opts->filename, O_RDWR | O_CREAT | O_BINARY, 0644); @@ -2375,6 +2384,27 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) } #endif } +#ifdef FS_IOC_FSSETXATTR + /* + * Try to set the extent size hint. Failure is not fatal, and a warning is + * only printed if the option was explicitly specified. + */ + { + struct fsxattr attr; + result = ioctl(fd, FS_IOC_FSGETXATTR, &attr); + if (result == 0) { + attr.fsx_xflags |= FS_XFLAG_EXTSIZE; + attr.fsx_extsize = file_opts->extent_size_hint; + result = ioctl(fd, FS_IOC_FSSETXATTR, &attr); + } + if (result < 0 && file_opts->has_extent_size_hint && + file_opts->extent_size_hint) + { + warn_report("Failed to set extent size hint: %s", + strerror(errno)); + } + } +#endif /* Resize and potentially preallocate the file to the desired * final size */ @@ -2410,6 +2440,8 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv, { BlockdevCreateOptions options; int64_t total_size = 0; + int64_t extent_size_hint = 0; + bool has_extent_size_hint = false; bool nocow = false; PreallocMode prealloc; char *buf = NULL; @@ -2421,6 +2453,11 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv, /* Read out options */ total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), BDRV_SECTOR_SIZE); + if (qemu_opt_get(opts, BLOCK_OPT_EXTENT_SIZE_HINT)) { + has_extent_size_hint = true; + extent_size_hint = + qemu_opt_get_size_del(opts, BLOCK_OPT_EXTENT_SIZE_HINT, -1); + } nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false); buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); prealloc = qapi_enum_parse(&PreallocMode_lookup, buf, @@ -2440,6 +2477,8 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv, .preallocation = prealloc, .has_nocow = true, .nocow = nocow, + .has_extent_size_hint = has_extent_size_hint, + .extent_size_hint = extent_size_hint, }, }; return raw_co_create(&options, errp); @@ -2930,6 +2969,11 @@ static QemuOptsList raw_create_opts = { #endif ", full)" }, + { + .name = BLOCK_OPT_EXTENT_SIZE_HINT, + .type = QEMU_OPT_SIZE, + .help = "Extent size hint for the image file, 0 to disable" + }, { /* end of list */ } } }; diff --git a/include/block/block_int.h b/include/block/block_int.h index 3d6cf88592..38dec0275b 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -53,6 +53,7 @@ #define BLOCK_OPT_ADAPTER_TYPE "adapter_type" #define BLOCK_OPT_REDUNDANCY "redundancy" #define BLOCK_OPT_NOCOW "nocow" +#define BLOCK_OPT_EXTENT_SIZE_HINT "extent_size_hint" #define BLOCK_OPT_OBJECT_SIZE "object_size" #define BLOCK_OPT_REFCOUNT_BITS "refcount_bits" #define BLOCK_OPT_DATA_FILE "data_file" diff --git a/qapi/block-core.json b/qapi/block-core.json index b20332e592..463ffd83da 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4185,14 +4185,17 @@ # falloc (if defined CONFIG_POSIX_FALLOCATE), # full (if defined CONFIG_POSIX)) # @nocow: Turn off copy-on-write (valid only on btrfs; default: off) +# @extent-size-hint: Extent size hint to add to the image file; 0 for not +# adding an extent size hint (default: 1 MB, since 5.1) # # Since: 2.12 ## { 'struct': 'BlockdevCreateOptionsFile', - 'data': { 'filename': 'str', - 'size': 'size', - '*preallocation': 'PreallocMode', - '*nocow': 'bool' } } + 'data': { 'filename': 'str', + 'size': 'size', + '*preallocation': 'PreallocMode', + '*nocow': 'bool', + '*extent-size-hint': 'size'} } ## # @BlockdevCreateOptionsGluster: diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index a4a2b69030..f7b3d54b28 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -62,6 +62,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -86,6 +87,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -110,6 +112,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -134,6 +137,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -158,6 +162,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -182,6 +187,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -206,6 +212,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -230,6 +237,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -353,6 +361,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -377,6 +386,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -401,6 +411,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -425,6 +436,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -449,6 +461,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -473,6 +486,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -497,6 +511,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) @@ -521,6 +536,7 @@ Supported options: encrypt.ivgen-hash-alg= - Name of IV generator hash algorithm encrypt.key-secret= - ID of secret providing qcow AES key or LUKS passphrase encryption= - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) + extent_size_hint= - Extent size hint for the image file, 0 to disable lazy_refcounts= - Postpone refcount updates nocow= - Turn off copy-on-write (valid only on btrfs) preallocation= - Preallocation mode (allowed values: off, metadata, falloc, full) diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106 index b5d1ec4078..a20659d443 100755 --- a/tests/qemu-iotests/106 +++ b/tests/qemu-iotests/106 @@ -51,7 +51,10 @@ for create_mode in off falloc full; do echo echo "--- create_mode=$create_mode growth_mode=$growth_mode ---" - _make_test_img -o "preallocation=$create_mode" ${CREATION_SIZE}K + # Our calculation below assumes kilobytes as unit for the actual size. + # Disable the extent size hint because it would give us a result in + # megabytes. + _make_test_img -o "preallocation=$create_mode,extent_size_hint=0" ${CREATION_SIZE}K $QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K expected_size=0 @@ -98,7 +101,7 @@ for growth_mode in falloc full; do # plain int. We should use the correct type for the result, and # this tests we do. - _make_test_img 2G + _make_test_img -o "extent_size_hint=0" 2G $QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size') diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175 index 020ed8e61f..00a626aa63 100755 --- a/tests/qemu-iotests/175 +++ b/tests/qemu-iotests/175 @@ -89,20 +89,20 @@ min_blocks=$(stat -c '%b' "$TEST_DIR/empty") echo echo "== creating image with default preallocation ==" -_make_test_img $size | _filter_imgfmt +_make_test_img -o extent_size_hint=0 $size | _filter_imgfmt stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size for mode in off full falloc; do echo echo "== creating image with preallocation $mode ==" - _make_test_img -o preallocation=$mode $size | _filter_imgfmt + _make_test_img -o preallocation=$mode,extent_size_hint=0 $size | _filter_imgfmt stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size done for new_size in 4096 1048576; do echo echo "== resize empty image with block_resize ==" - _make_test_img 0 | _filter_imgfmt + _make_test_img -o extent_size_hint=0 0 | _filter_imgfmt _block_resize $TEST_IMG $new_size >/dev/null stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $new_size done diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243 index a61852f6d9..17388a4644 100755 --- a/tests/qemu-iotests/243 +++ b/tests/qemu-iotests/243 @@ -51,7 +51,7 @@ for mode in off metadata falloc full; do echo "=== preallocation=$mode ===" echo - _make_test_img -o "preallocation=$mode" 64M + _make_test_img -o "preallocation=$mode,extent_size_hint=0" 64M printf "File size: " du -b $TEST_IMG | cut -f1 @@ -68,7 +68,8 @@ for mode in off metadata falloc full; do echo "=== External data file: preallocation=$mode ===" echo - _make_test_img -o "data_file=$TEST_IMG.data,preallocation=$mode" 64M + _make_test_img \ + -o "data_file=$TEST_IMG.data,preallocation=$mode,extent_size_hint=0" 64M echo -n "qcow2 file size: " du -b $TEST_IMG | cut -f1 @@ -79,7 +80,7 @@ for mode in off metadata falloc full; do echo -n "qcow2 disk usage: " [ $(du -B1 $TEST_IMG | cut -f1) -lt 1048576 ] && echo "low" || echo "high" echo -n "data disk usage: " - [ $(du -B1 $TEST_IMG.data | cut -f1) -lt 1048576 ] && echo "low" || echo "high" + [ $(du -B1 $TEST_IMG.data | cut -f1) -lt 2097152 ] && echo "low" || echo "high" done From 4e2f4418784da09cb106264340241856cd2846df Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Jul 2020 15:39:45 -0500 Subject: [PATCH 2299/2595] qemu-img: Flush stdout before before potential stderr messages During 'qemu-img create ... 2>&1', if --quiet is not in force, we can end up with buffered I/O in stdout that was produced before failure, but which appears in output after failure. This is confusing; the fix is to flush stdout prior to attempting anything that might produce an error message. Several iotests demonstrate the resulting ordering change now that the merged outputs now reflect chronology. (An even better fix would be to avoid printf from within block.c altogether, but that's much more invasive...) Signed-off-by: Eric Blake Message-Id: <20200706203954.341758-2-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 1 + tests/qemu-iotests/049.out | 8 ++++---- tests/qemu-iotests/054.out | 2 +- tests/qemu-iotests/079.out | 2 +- tests/qemu-iotests/112.out | 4 ++-- tests/qemu-iotests/259.out | 2 +- tests/qemu-iotests/282.out | 6 +++--- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/block.c b/block.c index 3031413deb..98cad57cda 100644 --- a/block.c +++ b/block.c @@ -6164,6 +6164,7 @@ void bdrv_img_create(const char *filename, const char *fmt, printf("Formatting '%s', fmt=%s ", filename, fmt); qemu_opts_print(opts, " "); puts(""); + fflush(stdout); } ret = bdrv_create(drv, filename, opts, &local_err); diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out index e77966446b..4c21dc70a5 100644 --- a/tests/qemu-iotests/049.out +++ b/tests/qemu-iotests/049.out @@ -167,12 +167,12 @@ qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M -qemu-img: TEST_DIR/t.qcow2: Invalid parameter '0.42' Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.42 lazy_refcounts=off refcount_bits=16 +qemu-img: TEST_DIR/t.qcow2: Invalid parameter '0.42' qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M -qemu-img: TEST_DIR/t.qcow2: Invalid parameter 'foobar' Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=foobar lazy_refcounts=off refcount_bits=16 +qemu-img: TEST_DIR/t.qcow2: Invalid parameter 'foobar' == Check preallocation option == @@ -183,8 +183,8 @@ qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 preallocation=metadata compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M -qemu-img: TEST_DIR/t.qcow2: Invalid parameter '1234' Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 preallocation=1234 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 +qemu-img: TEST_DIR/t.qcow2: Invalid parameter '1234' == Check encryption option == @@ -206,7 +206,7 @@ qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M -qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater) Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=on refcount_bits=16 +qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater) *** done diff --git a/tests/qemu-iotests/054.out b/tests/qemu-iotests/054.out index e6ec430edd..71f18bb987 100644 --- a/tests/qemu-iotests/054.out +++ b/tests/qemu-iotests/054.out @@ -1,8 +1,8 @@ QA output created by 054 creating too large image (1 EB) -qemu-img: TEST_DIR/t.IMGFMT: The image size is too large for file format 'IMGFMT' (try using a larger cluster size) Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1152921504606846976 +qemu-img: TEST_DIR/t.IMGFMT: The image size is too large for file format 'IMGFMT' (try using a larger cluster size) creating too large image (1 EB) using qcow2.py Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 diff --git a/tests/qemu-iotests/079.out b/tests/qemu-iotests/079.out index aab922fb36..f65a9ca84f 100644 --- a/tests/qemu-iotests/079.out +++ b/tests/qemu-iotests/079.out @@ -9,6 +9,6 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadat Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata -qemu-img: TEST_DIR/t.IMGFMT: Cluster size must be a power of two between 512 and 2048k Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata +qemu-img: TEST_DIR/t.IMGFMT: Cluster size must be a power of two between 512 and 2048k *** done diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out index 182655dbf6..dd3cc4383c 100644 --- a/tests/qemu-iotests/112.out +++ b/tests/qemu-iotests/112.out @@ -2,7 +2,6 @@ QA output created by 112 === refcount_bits limits === -qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 @@ -10,6 +9,7 @@ qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not e Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 refcount bits: 1 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 @@ -21,10 +21,10 @@ refcount bits: 16 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 refcount bits: 16 -qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater) Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater) Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater) === Snapshot limit on refcount_bits=1 === diff --git a/tests/qemu-iotests/259.out b/tests/qemu-iotests/259.out index ffed19c2a0..e27b9ff38d 100644 --- a/tests/qemu-iotests/259.out +++ b/tests/qemu-iotests/259.out @@ -9,6 +9,6 @@ virtual size: 64 MiB (67108864 bytes) disk size: unavailable --- Testing creation for which the node would need to grow --- -qemu-img: TEST_DIR/t.IMGFMT: Could not resize image: Image format driver does not support resize Formatting 'TEST_DIR/t.IMGFMT', fmt=qcow2 size=67108864 preallocation=metadata +qemu-img: TEST_DIR/t.IMGFMT: Could not resize image: Image format driver does not support resize *** done diff --git a/tests/qemu-iotests/282.out b/tests/qemu-iotests/282.out index 5d079dabce..67db7ab15a 100644 --- a/tests/qemu-iotests/282.out +++ b/tests/qemu-iotests/282.out @@ -1,11 +1,11 @@ QA output created by 282 == Create non-UTF8 secret == == Throws an error because of invalid UTF-8 secret == -qemu-img: vol.img: Data from secret sec0 is not valid UTF-8 Formatting 'vol.img', fmt=luks size=4194304 key-secret=sec0 +qemu-img: vol.img: Data from secret sec0 is not valid UTF-8 == Image file should not exist after the error == == Create a stub image file and run qemu-img again == -qemu-img: vol.img: Data from secret sec0 is not valid UTF-8 Formatting 'vol.img', fmt=luks size=4194304 key-secret=sec0 +qemu-img: vol.img: Data from secret sec0 is not valid UTF-8 == Pre-existing image file should also be deleted after the error == - *** done +*** done From 25956af3fe5dd0385ad8017bc768a6afe41e2a74 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Jul 2020 15:39:46 -0500 Subject: [PATCH 2300/2595] block: Finish deprecation of 'qemu-img convert -n -o' It's been two releases since we started warning; time to make the combination an error as promised. There was no iotest coverage, so add some. While touching the documentation, tweak another section heading for consistent style. Signed-off-by: Eric Blake Message-Id: <20200706203954.341758-3-eblake@redhat.com> Signed-off-by: Kevin Wolf --- docs/system/deprecated.rst | 18 ++++++++---------- qemu-img.c | 4 ++-- tests/qemu-iotests/122 | 7 +++++++ tests/qemu-iotests/122.out | 4 ++++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 58a9aeb851..aa9fdc8c53 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -427,14 +427,6 @@ kernel in 2018, and has also been dropped from glibc. Related binaries ---------------- -``qemu-img convert -n -o`` (since 4.2.0) -'''''''''''''''''''''''''''''''''''''''' - -All options specified in ``-o`` are image creation options, so -they have no effect when used with ``-n`` to skip image creation. -Silently ignored options can be confusing, so this combination of -options will be made an error in future versions. - Backwards compatibility ----------------------- @@ -540,8 +532,8 @@ spec you can use the ``-cpu rv64gcsu,priv_spec=v1.10.0`` command line argument. Related binaries ---------------- -``qemu-nbd --partition`` (removed in 5.0.0) -''''''''''''''''''''''''''''''''''''''''''' +``qemu-nbd --partition`` (removed in 5.0) +''''''''''''''''''''''''''''''''''''''''' The ``qemu-nbd --partition $digit`` code (also spelled ``-P``) could only handle MBR partitions, and never correctly handled logical @@ -557,6 +549,12 @@ can be rewritten as:: qemu-nbd -t --image-opts driver=raw,offset=1M,size=100M,file.driver=qcow2,file.file.driver=file,file.file.filename=file.qcow2 +``qemu-img convert -n -o`` (removed in 5.1) +''''''''''''''''''''''''''''''''''''''''''' + +All options specified in ``-o`` are image creation options, so +they are now rejected when used with ``-n`` to skip image creation. + Command line options -------------------- diff --git a/qemu-img.c b/qemu-img.c index 4548dbff82..46d2796fb2 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2364,8 +2364,8 @@ static int img_convert(int argc, char **argv) } if (skip_create && options) { - warn_report("-o has no effect when skipping image creation"); - warn_report("This will become an error in future QEMU versions."); + error_report("-o has no effect when skipping image creation"); + goto fail_getopt; } if (s.has_zero_init && !skip_create) { diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 index f7a3ae684a..2dc16b2ca4 100755 --- a/tests/qemu-iotests/122 +++ b/tests/qemu-iotests/122 @@ -290,6 +290,13 @@ TEST_IMG="$TEST_IMG".orig _make_test_img 64M # backing file" $QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -n "$TEST_IMG" "$TEST_IMG".orig +echo +echo '=== -n incompatible with -o ===' +echo + +$QEMU_IMG convert -O $IMGFMT -o preallocation=metadata -n \ + "$TEST_IMG" "$TEST_IMG".orig && echo "unexpected success" + # success, all done echo '*** done' rm -f $seq.full diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out index 1a35951a80..c2e154a1e5 100644 --- a/tests/qemu-iotests/122.out +++ b/tests/qemu-iotests/122.out @@ -233,4 +233,8 @@ Images are identical. Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 + +=== -n incompatible with -o === + +qemu-img: -o has no effect when skipping image creation *** done From 80fa43e7df5d68d60a2662036b7d3d95ca8b68f3 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Jul 2020 15:39:47 -0500 Subject: [PATCH 2301/2595] sheepdog: Add trivial backing_fmt support Sheepdog already requires that if backing_file is present, that it be another sheepdog image (see sd_co_create). Meanwhile, we want to move towards always being explicit about the backing format for other drivers where it matters. So for convenience, make qemu-img create -F sheepdog work, while rejecting all other explicit formats (note that this is only for QemuOpts usage; there is no change to the QAPI to allow a format through -blockdev). Signed-off-by: Eric Blake Message-Id: <20200706203954.341758-4-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block/sheepdog.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 6c487c8322..cbbebc1aaf 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -2151,13 +2151,21 @@ static int coroutine_fn sd_co_create_opts(BlockDriver *drv, Error **errp) { BlockdevCreateOptions *create_options = NULL; - QDict *qdict, *location_qdict; + QDict *qdict = NULL, *location_qdict; Visitor *v; - char *redundancy; + char *redundancy = NULL; Error *local_err = NULL; int ret; + char *backing_fmt = NULL; redundancy = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY); + backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT); + + if (backing_fmt && strcmp(backing_fmt, "sheepdog") != 0) { + error_setg(errp, "backing_file must be a sheepdog image"); + ret = -EINVAL; + goto fail; + } qdict = qemu_opts_to_qdict(opts, NULL); qdict_put_str(qdict, "driver", "sheepdog"); @@ -2220,6 +2228,7 @@ fail: qapi_free_BlockdevCreateOptions(create_options); qobject_unref(qdict); g_free(redundancy); + g_free(backing_fmt); return ret; } @@ -3177,6 +3186,11 @@ static QemuOptsList sd_create_opts = { .type = QEMU_OPT_STRING, .help = "File name of a base image" }, + { + .name = BLOCK_OPT_BACKING_FMT, + .type = QEMU_OPT_STRING, + .help = "Must be 'sheepdog' if present", + }, { .name = BLOCK_OPT_PREALLOC, .type = QEMU_OPT_STRING, From d51a814cf41033d2d29b050e04d85155ac941221 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Jul 2020 15:39:48 -0500 Subject: [PATCH 2302/2595] vmdk: Add trivial backing_fmt support vmdk already requires that if backing_file is present, that it be another vmdk image (see vmdk_co_do_create). Meanwhile, we want to move towards always being explicit about the backing format for other drivers where it matters. So for convenience, make qemu-img create -F vmdk work, while rejecting all other explicit formats (note that this is only for QemuOpts usage; there is no change to the QAPI to allow a format through -blockdev). Signed-off-by: Eric Blake Message-Id: <20200706203954.341758-5-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block/vmdk.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/block/vmdk.c b/block/vmdk.c index 28cec50f38..bf9df5ce92 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2633,6 +2633,14 @@ static int coroutine_fn vmdk_co_create_opts(BlockDriver *drv, bool zeroed_grain; bool compat6; VMDKCreateOptsData data; + char *backing_fmt = NULL; + + backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT); + if (backing_fmt && strcmp(backing_fmt, "vmdk") != 0) { + error_setg(errp, "backing_file must be a vmdk image"); + ret = -EINVAL; + goto exit; + } if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) { ret = -EINVAL; @@ -2691,6 +2699,7 @@ static int coroutine_fn vmdk_co_create_opts(BlockDriver *drv, vmdk_co_create_opts_cb, &data, errp); exit: + g_free(backing_fmt); g_free(adapter_type); g_free(backing_file); g_free(hw_version); @@ -3026,6 +3035,11 @@ static QemuOptsList vmdk_create_opts = { .type = QEMU_OPT_STRING, .help = "File name of a base image" }, + { + .name = BLOCK_OPT_BACKING_FMT, + .type = QEMU_OPT_STRING, + .help = "Must be 'vmdk' if present", + }, { .name = BLOCK_OPT_COMPAT6, .type = QEMU_OPT_BOOL, From 344acbd62ffdbeb7f803644ad46a8129059f6823 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Jul 2020 15:39:49 -0500 Subject: [PATCH 2303/2595] qcow: Tolerate backing_fmt= qcow has no space in the metadata to store a backing format, and there are existing qcow images backed both by raw or by other formats (usually qcow) images, reliant on probing to tell the difference. On the bright side, because we probe every time, raw files are marked as probed and we thus forbid a commit action into the backing file where guest-controlled contents could change the result of the probe next time around (the iotest added here proves that). Still, allowing the user to specify the backing format during creation, even if we can't record it, is a good thing. This patch blindly allows any value that resolves to a known driver, even if the user's request is a mismatch from what probing finds; then the next patch will further enhance things to verify that the user's request matches what we actually probe. With this and the next patch in place, we will finally be ready to deprecate the creation of images where a backing format was not explicitly specified by the user. Note that this is only for QemuOpts usage; there is no change to the QAPI to allow a format through -blockdev. Add a new iotest 301 just for qcow, to demonstrate the latest behavior, and to make it easier to show the improvements made in the next patch. Signed-off-by: Eric Blake Message-Id: <20200706203954.341758-6-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block/qcow.c | 20 ++++++++- tests/qemu-iotests/301 | 88 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/301.out | 60 ++++++++++++++++++++++++++ tests/qemu-iotests/group | 1 + 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100755 tests/qemu-iotests/301 create mode 100644 tests/qemu-iotests/301.out diff --git a/block/qcow.c b/block/qcow.c index 1e134f3445..e514a86fe5 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -938,10 +938,11 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv, { BlockdevCreateOptions *create_options = NULL; BlockDriverState *bs = NULL; - QDict *qdict; + QDict *qdict = NULL; Visitor *v; const char *val; int ret; + char *backing_fmt; static const QDictRenames opt_renames[] = { { BLOCK_OPT_BACKING_FILE, "backing-file" }, @@ -949,6 +950,17 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv, { NULL, NULL }, }; + /* + * We can't actually store a backing format, but can check that + * the user's request made sense. + */ + backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT); + if (backing_fmt && !bdrv_find_format(backing_fmt)) { + error_setg(errp, "unrecognized backing format '%s'", backing_fmt); + ret = -EINVAL; + goto fail; + } + /* Parse options and convert legacy syntax */ qdict = qemu_opts_to_qdict_filtered(opts, NULL, &qcow_create_opts, true); @@ -1012,6 +1024,7 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv, ret = 0; fail: + g_free(backing_fmt); qobject_unref(qdict); bdrv_unref(bs); qapi_free_BlockdevCreateOptions(create_options); @@ -1146,6 +1159,11 @@ static QemuOptsList qcow_create_opts = { .type = QEMU_OPT_STRING, .help = "File name of a base image" }, + { + .name = BLOCK_OPT_BACKING_FMT, + .type = QEMU_OPT_STRING, + .help = "Format of the backing image", + }, { .name = BLOCK_OPT_ENCRYPT, .type = QEMU_OPT_BOOL, diff --git a/tests/qemu-iotests/301 b/tests/qemu-iotests/301 new file mode 100755 index 0000000000..3823e95617 --- /dev/null +++ b/tests/qemu-iotests/301 @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +# +# Test qcow backing file warnings +# +# Copyright (C) 2020 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 . +# + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + _rm_test_img "$TEST_IMG.qcow2" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow +_supported_proto file +_supported_os Linux + +size=32M + +echo +echo "== qcow backed by qcow ==" + +TEST_IMG="$TEST_IMG.base" _make_test_img $size +_make_test_img -b "$TEST_IMG.base" $size +_img_info +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $size +_img_info + +echo +echo "== mismatched command line detection ==" + +_make_test_img -b "$TEST_IMG.base" -F vmdk +_make_test_img -b "$TEST_IMG.base" -F vmdk $size +echo +# Use of -u bypasses the backing format sanity check +_make_test_img -u -b "$TEST_IMG.base" -F vmdk +_make_test_img -u -b "$TEST_IMG.base" -F vmdk $size +echo +# But the format must still be recognized +_make_test_img -b "$TEST_IMG.base" -F garbage $size +_make_test_img -u -b "$TEST_IMG.base" -F garbage $size +_img_info + +echo +echo "== qcow backed by raw ==" + +rm "$TEST_IMG.base" +truncate --size=$size "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" $size +_img_info +_make_test_img -b "$TEST_IMG.base" -F raw $size +_img_info + +echo +echo "== commit cannot change type of raw backing file ==" +TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 _make_test_img $size +truncate --size=$size "$TEST_IMG.qcow2" +$QEMU_IMG convert -n -f raw -O $IMGFMT "$TEST_IMG.qcow2" "$TEST_IMG" +$QEMU_IMG commit -f $IMGFMT "$TEST_IMG" && echo "unexpected success" +TEST_IMG="$TEST_IMG.base" _img_info + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/301.out b/tests/qemu-iotests/301.out new file mode 100644 index 0000000000..adaf11d42d --- /dev/null +++ b/tests/qemu-iotests/301.out @@ -0,0 +1,60 @@ +QA output created by 301 + +== qcow backed by qcow == +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=33554432 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 32 MiB (33554432 bytes) +cluster_size: 512 +backing file: TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 32 MiB (33554432 bytes) +cluster_size: 512 +backing file: TEST_DIR/t.IMGFMT.base + +== mismatched command line detection == +qemu-img: TEST_DIR/t.IMGFMT: invalid VMDK image descriptor +Could not open backing image to determine size. +qemu-img: warning: Could not verify backing image. This may become an error in future versions. +invalid VMDK image descriptor +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=vmdk + +qemu-img: TEST_DIR/t.IMGFMT: Image creation needs a size parameter +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=vmdk + +qemu-img: warning: Could not verify backing image. This may become an error in future versions. +Unknown driver 'garbage' +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=garbage +qemu-img: TEST_DIR/t.IMGFMT: unrecognized backing format 'garbage' +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=garbage +qemu-img: TEST_DIR/t.IMGFMT: unrecognized backing format 'garbage' +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 32 MiB (33554432 bytes) +cluster_size: 512 +backing file: TEST_DIR/t.IMGFMT.base + +== qcow backed by raw == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 32 MiB (33554432 bytes) +cluster_size: 512 +backing file: TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 32 MiB (33554432 bytes) +cluster_size: 512 +backing file: TEST_DIR/t.IMGFMT.base + +== commit cannot change type of raw backing file == +Formatting 'TEST_DIR/t.qcow.IMGFMT', fmt=IMGFMT size=33554432 +qemu-img: Block job failed: Operation not permitted +image: TEST_DIR/t.IMGFMT.base +file format: raw +virtual size: 32 MiB (33554432 bytes) +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 9b07a7ed03..a4f9e11e7a 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -306,3 +306,4 @@ 295 rw 296 rw 297 meta +301 backing quick From add8200dd14041d059cc376eff91461fadd93ec5 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Jul 2020 15:39:50 -0500 Subject: [PATCH 2304/2595] block: Error if backing file fails during creation without -u Back in commit 6e6e55f5 (Jul 2017, v2.10), we tweaked the code to warn if the backing file could not be opened but the user gave a size, unless the user also passes the -u option to bypass the open of the backing file. As one common reason for failure to open the backing file is when there is mismatch in the requested backing format in relation to what the backing file actually contains, we actually want to open the backing file and ensure that it has the right format in as many cases as possible. iotest 301 for qcow demonstrates how detecting explicit format mismatch is useful to prevent the creation of an image that would probe differently than the user requested. Now is the time to finally turn the warning an error, as promised. Note that the original warning was added prior to our documentation of an official deprecation policy (eb22aeca, also Jul 2017), and because the warning didn't mention the word "deprecated", we never actually remembered to document it as such. But the warning has been around long enough that I don't see prolonging it another two releases. Signed-off-by: Eric Blake Message-Id: <20200706203954.341758-7-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 12 ++---------- docs/system/deprecated.rst | 12 ++++++++++++ tests/qemu-iotests/111.out | 2 +- tests/qemu-iotests/301.out | 13 +++++-------- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/block.c b/block.c index 98cad57cda..6925e57d7c 100644 --- a/block.c +++ b/block.c @@ -6128,16 +6128,8 @@ void bdrv_img_create(const char *filename, const char *fmt, bs = bdrv_open(full_backing, NULL, backing_options, back_flags, &local_err); g_free(full_backing); - if (!bs && size != -1) { - /* Couldn't open BS, but we have a size, so it's nonfatal */ - warn_reportf_err(local_err, - "Could not verify backing image. " - "This may become an error in future versions.\n"); - local_err = NULL; - } else if (!bs) { - /* Couldn't open bs, do not have size */ - error_append_hint(&local_err, - "Could not open backing image to determine size.\n"); + if (!bs) { + error_append_hint(&local_err, "Could not open backing image.\n"); goto out; } else { if (size == -1) { diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index aa9fdc8c53..c014e049c3 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -555,6 +555,18 @@ can be rewritten as:: All options specified in ``-o`` are image creation options, so they are now rejected when used with ``-n`` to skip image creation. + +``qemu-img create -b bad file $size`` (removed in 5.1) +'''''''''''''''''''''''''''''''''''''''''''''''''''''' + +When creating an image with a backing file that could not be opened, +``qemu-img create`` used to issue a warning about the failure but +proceed with the image creation if an explicit size was provided. +However, as the ``-u`` option exists for this purpose, it is safer to +enforce that any failure to open the backing image (including if the +backing file is missing or an incorrect format was specified) is an +error when ``-u`` is not used. + Command line options -------------------- diff --git a/tests/qemu-iotests/111.out b/tests/qemu-iotests/111.out index 5279c462fc..ba034e5c58 100644 --- a/tests/qemu-iotests/111.out +++ b/tests/qemu-iotests/111.out @@ -1,4 +1,4 @@ QA output created by 111 qemu-img: TEST_DIR/t.IMGFMT: Could not open 'TEST_DIR/t.IMGFMT.inexistent': No such file or directory -Could not open backing image to determine size. +Could not open backing image. *** done diff --git a/tests/qemu-iotests/301.out b/tests/qemu-iotests/301.out index adaf11d42d..281a16d87a 100644 --- a/tests/qemu-iotests/301.out +++ b/tests/qemu-iotests/301.out @@ -17,18 +17,15 @@ backing file: TEST_DIR/t.IMGFMT.base == mismatched command line detection == qemu-img: TEST_DIR/t.IMGFMT: invalid VMDK image descriptor -Could not open backing image to determine size. -qemu-img: warning: Could not verify backing image. This may become an error in future versions. -invalid VMDK image descriptor -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=vmdk +Could not open backing image. +qemu-img: TEST_DIR/t.IMGFMT: invalid VMDK image descriptor +Could not open backing image. qemu-img: TEST_DIR/t.IMGFMT: Image creation needs a size parameter Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=vmdk -qemu-img: warning: Could not verify backing image. This may become an error in future versions. -Unknown driver 'garbage' -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=garbage -qemu-img: TEST_DIR/t.IMGFMT: unrecognized backing format 'garbage' +qemu-img: TEST_DIR/t.IMGFMT: Unknown driver 'garbage' +Could not open backing image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=garbage qemu-img: TEST_DIR/t.IMGFMT: unrecognized backing format 'garbage' image: TEST_DIR/t.IMGFMT From bc5ee6da7122f6fe93ed07241a44315a331487e9 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Jul 2020 15:39:51 -0500 Subject: [PATCH 2305/2595] qcow2: Deprecate use of qemu-img amend to change backing file The use of 'qemu-img amend' to change qcow2 backing files is not tested very well. In particular, our implementation has a bug where if a new backing file is provided without a format, then the prior format is blindly reused, even if this results in data corruption, but this is not caught by iotests. There are also situations where amending other options needs access to the original backing file (for example, on a downgrade to a v2 image, knowing whether a v3 zero cluster must be allocated or may be left unallocated depends on knowing whether the backing file already reads as zero), but the command line does not have a nice way to tell us both the backing file to use for opening the image as well as the backing file to install after the operation is complete. Even if we do allow changing the backing file, it is redundant with the existing ability to change backing files via 'qemu-img rebase -u'. It is time to deprecate this support (leaving the existing behavior intact, even if it is buggy), and at a point in the future, require the use of only 'qemu-img rebase' for adjusting backing chain relations, saving 'qemu-img amend' for changes unrelated to the backing chain. Signed-off-by: Eric Blake Message-Id: <20200706203954.341758-8-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block/qcow2.c | 5 +++++ docs/system/deprecated.rst | 12 ++++++++++++ docs/tools/qemu-img.rst | 4 ++++ tests/qemu-iotests/061.out | 1 + tests/qemu-iotests/082.out | 2 ++ 5 files changed, 24 insertions(+) diff --git a/block/qcow2.c b/block/qcow2.c index ea33673c55..f3fc2707cd 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5511,6 +5511,11 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, } if (backing_file || backing_format) { + if (g_strcmp0(backing_file, s->image_backing_file) || + g_strcmp0(backing_format, s->image_backing_format)) { + warn_report("Deprecated use of amend to alter the backing file; " + "use qemu-img rebase instead"); + } ret = qcow2_change_backing_file(bs, backing_file ?: s->image_backing_file, backing_format ?: s->image_backing_format); diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index c014e049c3..c1f019b9d2 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -427,6 +427,18 @@ kernel in 2018, and has also been dropped from glibc. Related binaries ---------------- +qemu-img amend to adjust backing file (since 5.1) +''''''''''''''''''''''''''''''''''''''''''''''''' + +The use of ``qemu-img amend`` to modify the name or format of a qcow2 +backing image is deprecated; this functionality was never fully +documented or tested, and interferes with other amend operations that +need access to the original backing image (such as deciding whether a +v3 zero cluster may be left unallocated when converting to a v2 +image). Rather, any changes to the backing chain should be performed +with ``qemu-img rebase -u`` either before or after the remaining +changes being performed by amend, as appropriate. + Backwards compatibility ----------------------- diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index e33f5575e3..c35bd64822 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -258,6 +258,10 @@ Command description: Amends the image format specific *OPTIONS* for the image file *FILENAME*. Not all file formats support this operation. + The set of options that can be amended are dependent on the image + format, but note that amending the backing chain relationship should + instead be performed with ``qemu-img rebase``. + --force allows some unsafe operations. Currently for -f luks, it allows to erase the last encryption key, and to overwrite an active encryption key. diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index b0f8befe30..44e3c624f9 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -370,6 +370,7 @@ wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: warning: Deprecated use of amend to alter the backing file; use qemu-img rebase instead read 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index f7b3d54b28..a38a26fc57 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -783,10 +783,12 @@ Amend options for 'qcow2': size= - Virtual disk size Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 +qemu-img: warning: Deprecated use of amend to alter the backing file; use qemu-img rebase instead Testing: rebase -u -b -f qcow2 TEST_DIR/t.qcow2 Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 +qemu-img: warning: Deprecated use of amend to alter the backing file; use qemu-img rebase instead Testing: rebase -u -b -f qcow2 TEST_DIR/t.qcow2 From b66ff2c29817f5efa18f5120fd6f089fbf59a933 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Jul 2020 15:39:52 -0500 Subject: [PATCH 2306/2595] iotests: Specify explicit backing format where sensible There are many existing qcow2 images that specify a backing file but no format. This has been the source of CVEs in the past, but has become more prominent of a problem now that libvirt has switched to -blockdev. With older -drive, at least the probing was always done by qemu (so the only risk of a changed format between successive boots of a guest was if qemu was upgraded and probed differently). But with newer -blockdev, libvirt must specify a format; if libvirt guesses raw where the image was formatted, this results in data corruption visible to the guest; conversely, if libvirt guesses qcow2 where qemu was using raw, this can result in potential security holes, so modern libvirt instead refuses to use images without explicit backing format. The change in libvirt to reject images without explicit backing format has pointed out that a number of tools have been far too reliant on probing in the past. It's time to set a better example in our own iotests of properly setting this parameter. iotest calls to create, rebase, and convert are all impacted to some degree. It's a bit annoying that we are inconsistent on command line - while all of those accept -o backing_file=...,backing_fmt=..., the shortcuts are different: create and rebase have -b and -F, while convert has -B but no -F. (amend has no shortcuts, but the previous patch just deprecated the use of amend to change backing chains). Signed-off-by: Eric Blake Message-Id: <20200706203954.341758-9-eblake@redhat.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/017 | 2 +- tests/qemu-iotests/017.out | 2 +- tests/qemu-iotests/018 | 2 +- tests/qemu-iotests/018.out | 2 +- tests/qemu-iotests/019 | 5 ++-- tests/qemu-iotests/019.out | 2 +- tests/qemu-iotests/020 | 4 +-- tests/qemu-iotests/020.out | 4 +-- tests/qemu-iotests/024 | 10 ++++---- tests/qemu-iotests/024.out | 4 +-- tests/qemu-iotests/028 | 4 +-- tests/qemu-iotests/028.out | 2 +- tests/qemu-iotests/030 | 26 +++++++++++++------ tests/qemu-iotests/034 | 2 +- tests/qemu-iotests/034.out | 2 +- tests/qemu-iotests/037 | 2 +- tests/qemu-iotests/037.out | 2 +- tests/qemu-iotests/038 | 2 +- tests/qemu-iotests/038.out | 2 +- tests/qemu-iotests/039 | 3 ++- tests/qemu-iotests/039.out | 2 +- tests/qemu-iotests/040 | 47 +++++++++++++++++++++++++---------- tests/qemu-iotests/041 | 37 ++++++++++++++++++--------- tests/qemu-iotests/042 | 4 +-- tests/qemu-iotests/043 | 23 +++++++++-------- tests/qemu-iotests/043.out | 12 ++++----- tests/qemu-iotests/046 | 2 +- tests/qemu-iotests/046.out | 2 +- tests/qemu-iotests/050 | 4 +-- tests/qemu-iotests/050.out | 2 +- tests/qemu-iotests/051 | 2 +- tests/qemu-iotests/051.out | 2 +- tests/qemu-iotests/051.pc.out | 2 +- tests/qemu-iotests/056 | 3 ++- tests/qemu-iotests/060 | 2 +- tests/qemu-iotests/060.out | 2 +- tests/qemu-iotests/061 | 10 ++++---- tests/qemu-iotests/061.out | 10 ++++---- tests/qemu-iotests/069 | 2 +- tests/qemu-iotests/069.out | 2 +- tests/qemu-iotests/073 | 2 +- tests/qemu-iotests/073.out | 2 +- tests/qemu-iotests/082 | 10 +++++--- tests/qemu-iotests/082.out | 12 ++++----- tests/qemu-iotests/085 | 4 +-- tests/qemu-iotests/085.out | 6 ++--- tests/qemu-iotests/089 | 2 +- tests/qemu-iotests/089.out | 2 +- tests/qemu-iotests/095 | 4 +-- tests/qemu-iotests/095.out | 4 +-- tests/qemu-iotests/097 | 4 +-- tests/qemu-iotests/097.out | 16 ++++++------ tests/qemu-iotests/098 | 2 +- tests/qemu-iotests/098.out | 8 +++--- tests/qemu-iotests/110 | 4 +-- tests/qemu-iotests/110.out | 4 +-- tests/qemu-iotests/122 | 27 ++++++++++++-------- tests/qemu-iotests/122.out | 8 +++--- tests/qemu-iotests/126 | 4 +-- tests/qemu-iotests/126.out | 4 +-- tests/qemu-iotests/127 | 4 +-- tests/qemu-iotests/127.out | 4 +-- tests/qemu-iotests/129 | 3 ++- tests/qemu-iotests/133 | 2 +- tests/qemu-iotests/133.out | 2 +- tests/qemu-iotests/139 | 2 +- tests/qemu-iotests/141 | 4 +-- tests/qemu-iotests/141.out | 4 +-- tests/qemu-iotests/142 | 2 +- tests/qemu-iotests/142.out | 2 +- tests/qemu-iotests/153 | 14 +++++------ tests/qemu-iotests/153.out | 35 ++++++++++++++------------ tests/qemu-iotests/154 | 42 +++++++++++++++---------------- tests/qemu-iotests/154.out | 42 +++++++++++++++---------------- tests/qemu-iotests/155 | 12 ++++++--- tests/qemu-iotests/156 | 9 ++++--- tests/qemu-iotests/156.out | 6 ++--- tests/qemu-iotests/158 | 2 +- tests/qemu-iotests/158.out | 2 +- tests/qemu-iotests/161 | 8 +++--- tests/qemu-iotests/161.out | 8 +++--- tests/qemu-iotests/176 | 4 +-- tests/qemu-iotests/176.out | 32 ++++++++++++------------ tests/qemu-iotests/177 | 2 +- tests/qemu-iotests/177.out | 2 +- tests/qemu-iotests/179 | 2 +- tests/qemu-iotests/179.out | 2 +- tests/qemu-iotests/189 | 2 +- tests/qemu-iotests/189.out | 2 +- tests/qemu-iotests/191 | 12 ++++----- tests/qemu-iotests/191.out | 12 ++++----- tests/qemu-iotests/195 | 6 ++--- tests/qemu-iotests/195.out | 6 ++--- tests/qemu-iotests/198 | 2 +- tests/qemu-iotests/198.out | 3 ++- tests/qemu-iotests/204 | 2 +- tests/qemu-iotests/204.out | 2 +- tests/qemu-iotests/216 | 2 +- tests/qemu-iotests/224 | 4 +-- tests/qemu-iotests/225 | 2 +- tests/qemu-iotests/225.out | 2 +- tests/qemu-iotests/228 | 5 ++-- tests/qemu-iotests/245 | 3 ++- tests/qemu-iotests/249 | 4 +-- tests/qemu-iotests/249.out | 4 +-- tests/qemu-iotests/252 | 2 +- tests/qemu-iotests/257 | 3 ++- tests/qemu-iotests/267 | 4 +-- tests/qemu-iotests/267.out | 6 ++--- tests/qemu-iotests/270 | 2 +- tests/qemu-iotests/270.out | 2 +- tests/qemu-iotests/273 | 4 +-- tests/qemu-iotests/273.out | 4 +-- tests/qemu-iotests/274 | 12 ++++----- tests/qemu-iotests/274.out | 29 +++++++++++---------- tests/qemu-iotests/279 | 4 +-- tests/qemu-iotests/279.out | 4 +-- tests/qemu-iotests/290 | 2 +- tests/qemu-iotests/290.out | 4 +-- 119 files changed, 434 insertions(+), 361 deletions(-) diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017 index 0a4b854e65..585512bb29 100755 --- a/tests/qemu-iotests/017 +++ b/tests/qemu-iotests/017 @@ -66,7 +66,7 @@ echo "Creating test image with backing file" echo TEST_IMG=$TEST_IMG_SAVE -_make_test_img -b "$TEST_IMG.base" 6G +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT 6G echo "Filling test image" echo diff --git a/tests/qemu-iotests/017.out b/tests/qemu-iotests/017.out index 8fc9241942..f439d3ece3 100644 --- a/tests/qemu-iotests/017.out +++ b/tests/qemu-iotests/017.out @@ -269,7 +269,7 @@ wrote 65536/65536 bytes at offset 4295032832 No errors were found on the image. Creating test image with backing file -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT Filling test image === IO: pattern 1 diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018 index c69ce09209..191b461a4d 100755 --- a/tests/qemu-iotests/018 +++ b/tests/qemu-iotests/018 @@ -66,7 +66,7 @@ echo "Creating test image with backing file" echo TEST_IMG="$TEST_IMG_SAVE.orig" -_make_test_img -b "$TEST_IMG_SAVE.base" 6G +_make_test_img -b "$TEST_IMG_SAVE.base" -F $IMGFMT 6G echo "Filling test image" echo diff --git a/tests/qemu-iotests/018.out b/tests/qemu-iotests/018.out index 5df966727f..0ab664ca4b 100644 --- a/tests/qemu-iotests/018.out +++ b/tests/qemu-iotests/018.out @@ -269,7 +269,7 @@ wrote 65536/65536 bytes at offset 4295032832 No errors were found on the image. Creating test image with backing file -Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT Filling test image === IO: pattern 1 diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019 index 813a84acac..d3c11256dc 100755 --- a/tests/qemu-iotests/019 +++ b/tests/qemu-iotests/019 @@ -74,7 +74,7 @@ echo "Creating test image with backing file" echo TEST_IMG="$TEST_IMG_SAVE.orig" -_make_test_img -b "$TEST_IMG_SAVE.base" 6G +_make_test_img -b "$TEST_IMG_SAVE.base" -F $IMGFMT 6G echo "Filling test image" echo @@ -98,7 +98,8 @@ for backing_option in "-B " "-o backing_file="; do echo echo Testing conversion with $backing_option"$TEST_IMG.base" | _filter_testdir | _filter_imgfmt echo - $QEMU_IMG convert -f $IMGFMT -O $IMGFMT $backing_option"$TEST_IMG.base" "$TEST_IMG.orig" "$TEST_IMG" + $QEMU_IMG convert -f $IMGFMT -O $IMGFMT $backing_option"$TEST_IMG.base" \ + -o backing_fmt=$IMGFMT "$TEST_IMG.orig" "$TEST_IMG" echo "Checking if backing clusters are allocated when they shouldn't" echo diff --git a/tests/qemu-iotests/019.out b/tests/qemu-iotests/019.out index 17a7c036b9..0fa73bd69a 100644 --- a/tests/qemu-iotests/019.out +++ b/tests/qemu-iotests/019.out @@ -269,7 +269,7 @@ wrote 65536/65536 bytes at offset 4296015872 No errors were found on the image. Creating test image with backing file -Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT Filling test image === IO: pattern 43 diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020 index b488000cb9..a0782937b0 100755 --- a/tests/qemu-iotests/020 +++ b/tests/qemu-iotests/020 @@ -70,7 +70,7 @@ echo "Creating test image with backing file" echo TEST_IMG="$TEST_IMG_SAVE" -_make_test_img -b "$TEST_IMG.base" 6G +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT 6G echo "Filling test image" echo @@ -131,7 +131,7 @@ backing="json:{'driver': '$IMGFMT', # Filter out newlines and collapse spaces backing=$(echo "$backing" | tr -d '\n' | tr -s ' ') -_make_test_img -b "$backing" +_make_test_img -b "$backing" -F $IMGFMT # Just write anything so committing will not be a no-op $QEMU_IO -c 'writev 0 64k' "$TEST_IMG" | _filter_qemu_io diff --git a/tests/qemu-iotests/020.out b/tests/qemu-iotests/020.out index 4668ac59df..5936bc1cae 100644 --- a/tests/qemu-iotests/020.out +++ b/tests/qemu-iotests/020.out @@ -269,7 +269,7 @@ wrote 65536/65536 bytes at offset 4295032832 No errors were found on the image. Creating test image with backing file -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT Filling test image === IO: pattern 1 @@ -1079,7 +1079,7 @@ No errors were found on the image. Testing failing commit Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=json:{'driver': 'IMGFMT',, 'file': { 'driver': 'blkdebug',, 'inject-error': [{ 'event': 'write_aio',, 'errno': 28,, 'once': true }],, 'image': { 'driver': 'file',, 'filename': 'TEST_DIR/t.IMGFMT.base' }}} +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=json:{'driver': 'IMGFMT',, 'file': { 'driver': 'blkdebug',, 'inject-error': [{ 'event': 'write_aio',, 'errno': 28,, 'once': true }],, 'image': { 'driver': 'file',, 'filename': 'TEST_DIR/t.IMGFMT.base' }}} backing_fmt=IMGFMT wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-img: Block job failed: No space left on device diff --git a/tests/qemu-iotests/024 b/tests/qemu-iotests/024 index e2e766241e..12aceb2d41 100755 --- a/tests/qemu-iotests/024 +++ b/tests/qemu-iotests/024 @@ -83,7 +83,7 @@ TEST_IMG="$TEST_IMG_SAVE" echo "Creating COW image" echo -_make_test_img -b "$TEST_IMG.base_old" 1G +_make_test_img -b "$TEST_IMG.base_old" -F $IMGFMT 1G io_pattern writev 0 $((4 * CLUSTER_SIZE)) 0 1 0x33 io_pattern writev $((8 * CLUSTER_SIZE)) $((4 * CLUSTER_SIZE)) 0 1 0x33 @@ -109,7 +109,7 @@ io_pattern readv $((15 * CLUSTER_SIZE)) $CLUSTER_SIZE 0 1 0x00 echo echo Rebase and test again echo -$QEMU_IMG rebase -b "$TEST_IMG.base_new" "$TEST_IMG" +$QEMU_IMG rebase -b "$TEST_IMG.base_new" -F $IMGFMT "$TEST_IMG" io_pattern readv $((0 * CLUSTER_SIZE)) $CLUSTER_SIZE 0 1 0x33 io_pattern readv $((1 * CLUSTER_SIZE)) $CLUSTER_SIZE 0 1 0x33 io_pattern readv $((2 * CLUSTER_SIZE)) $CLUSTER_SIZE 0 1 0x33 @@ -159,7 +159,7 @@ OVERLAY="$TEST_DIR/$OVERLAY_WREL" TEST_IMG=$BASE_OLD _make_test_img 1M TEST_IMG=$BASE_NEW _make_test_img 1M -TEST_IMG=$OVERLAY _make_test_img -b "$BASE_OLD_OREL" 1M +TEST_IMG=$OVERLAY _make_test_img -b "$BASE_OLD_OREL" -F $IMGFMT 1M echo @@ -176,11 +176,11 @@ $QEMU_IO "$BASE_NEW" \ echo pushd "$TEST_DIR" >/dev/null -$QEMU_IMG rebase -f "$IMGFMT" -b "$BASE_NEW_OREL" "$OVERLAY_WREL" +$QEMU_IMG rebase -f "$IMGFMT" -b "$BASE_NEW_OREL" -F $IMGFMT "$OVERLAY_WREL" popd >/dev/null # Verify the backing path is correct -TEST_IMG=$OVERLAY _img_info | grep '^backing file' +TEST_IMG=$OVERLAY _img_info | grep '^backing file:' echo diff --git a/tests/qemu-iotests/024.out b/tests/qemu-iotests/024.out index 024dc786b3..973a5a3711 100644 --- a/tests/qemu-iotests/024.out +++ b/tests/qemu-iotests/024.out @@ -33,7 +33,7 @@ wrote 131072/131072 bytes at offset 786432 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Creating COW image -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file=TEST_DIR/t.IMGFMT.base_old +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file=TEST_DIR/t.IMGFMT.base_old backing_fmt=IMGFMT === IO: pattern 0x33 wrote 262144/262144 bytes at offset 0 256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -146,7 +146,7 @@ read 65536/65536 bytes at offset 983040 Formatting 'TEST_DIR/subdir/t.IMGFMT.base_old', fmt=IMGFMT size=1048576 Formatting 'TEST_DIR/subdir/t.IMGFMT.base_new', fmt=IMGFMT size=1048576 -Formatting 'TEST_DIR/subdir/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=t.IMGFMT.base_old +Formatting 'TEST_DIR/subdir/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=t.IMGFMT.base_old backing_fmt=IMGFMT wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028 index 797dae5350..5d043cef92 100755 --- a/tests/qemu-iotests/028 +++ b/tests/qemu-iotests/028 @@ -76,7 +76,7 @@ echo "Creating test image with backing file" echo TEST_IMG="$TEST_IMG_SAVE" -_make_test_img -b "$TEST_IMG.base" $image_size +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $image_size echo "Filling test image" echo @@ -101,7 +101,7 @@ io_zero readv $(( offset + 32 * 1024 )) 512 1024 32 _check_test_img # Rebase it on top of its base image -$QEMU_IMG rebase -b "$TEST_IMG.base" "$TEST_IMG" +$QEMU_IMG rebase -b "$TEST_IMG.base" -F $IMGFMT "$TEST_IMG" echo echo block-backup diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out index 37aed84436..12f82c6a6c 100644 --- a/tests/qemu-iotests/028.out +++ b/tests/qemu-iotests/028.out @@ -70,7 +70,7 @@ wrote 512/512 bytes at offset 3221225984 No errors were found on the image. Creating test image with backing file -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294968832 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294968832 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT Filling test image === IO: pattern 196 diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index 1cdd7e2999..256b2bfbc6 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -32,8 +32,12 @@ class TestSingleDrive(iotests.QMPTestCase): def setUp(self): iotests.create_image(backing_img, TestSingleDrive.image_len) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, + '-F', 'raw', mid_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % mid_img, + '-F', iotests.imgfmt, test_img) qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 512', backing_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 524288 512', mid_img) self.vm = iotests.VM().add_drive("blkdebug::" + test_img, @@ -199,7 +203,8 @@ class TestParallelOps(iotests.QMPTestCase): iotests.create_image(self.imgs[0], self.image_len) for i in range(1, self.num_imgs): qemu_img('create', '-f', iotests.imgfmt, - '-o', 'backing_file=%s' % self.imgs[i-1], self.imgs[i]) + '-o', 'backing_file=%s' % self.imgs[i-1], + '-F', 'raw' if i == 1 else iotests.imgfmt, self.imgs[i]) # Put data into the images we are copying data from odd_img_indexes = [x for x in reversed(range(self.num_imgs)) if x % 2 == 1] @@ -544,7 +549,8 @@ class TestQuorum(iotests.QMPTestCase): qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x55 0 1024', backing_img) qemu_img('create', '-f', iotests.imgfmt, - '-o', 'backing_file=%s' % backing_img, child_img) + '-o', 'backing_file=%s' % backing_img, + '-F', iotests.imgfmt, child_img) opts.append("children.%d.file.filename=%s" % (i, child_img)) opts.append("children.%d.node-name=node%d" % (i, i)) @@ -585,7 +591,9 @@ class TestSmallerBackingFile(iotests.QMPTestCase): def setUp(self): iotests.create_image(backing_img, self.backing_len) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img, str(self.image_len)) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, + '-F', 'raw', test_img, str(self.image_len)) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() @@ -848,7 +856,9 @@ class TestStreamStop(iotests.QMPTestCase): def setUp(self): qemu_img('create', backing_img, str(TestStreamStop.image_len)) qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 32M', backing_img) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, + '-F', 'raw', test_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 32M 32M', test_img) self.vm = iotests.VM().add_drive("blkdebug::" + test_img) self.vm.launch() @@ -879,7 +889,9 @@ class TestSetSpeed(iotests.QMPTestCase): def setUp(self): qemu_img('create', backing_img, str(TestSetSpeed.image_len)) qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 32M', backing_img) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, + '-F', 'raw', test_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 32M 32M', test_img) self.vm = iotests.VM().add_drive('blkdebug::' + test_img) self.vm.launch() diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034 index da4cea1571..ac2d687c71 100755 --- a/tests/qemu-iotests/034 +++ b/tests/qemu-iotests/034 @@ -58,7 +58,7 @@ $QEMU_IO -c "write -P 0x55 0 1M" "$TEST_IMG" | _filter_qemu_io TEST_IMG="$TEST_IMG_SAVE" -_make_test_img -b "$TEST_IMG.base" 6G +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT 6G echo echo "== zero write with backing file ==" diff --git a/tests/qemu-iotests/034.out b/tests/qemu-iotests/034.out index 0764ead8b9..478205ad25 100644 --- a/tests/qemu-iotests/034.out +++ b/tests/qemu-iotests/034.out @@ -4,7 +4,7 @@ QA output created by 034 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT == zero write with backing file == wrote 196608/196608 bytes at offset 65536 diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037 index e6517acbd4..e1187ac24a 100755 --- a/tests/qemu-iotests/037 +++ b/tests/qemu-iotests/037 @@ -74,7 +74,7 @@ backing_io 0 256 write | $QEMU_IO "$TEST_IMG" | _filter_qemu_io TEST_IMG="$TEST_IMG_SAVE" -_make_test_img -b "$TEST_IMG.base" 6G +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT 6G echo echo "== COW in a single cluster ==" diff --git a/tests/qemu-iotests/037.out b/tests/qemu-iotests/037.out index cd6710c901..30ef989b64 100644 --- a/tests/qemu-iotests/037.out +++ b/tests/qemu-iotests/037.out @@ -514,7 +514,7 @@ wrote 512/512 bytes at offset 130048 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 512/512 bytes at offset 130560 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT == COW in a single cluster == wrote 2048/2048 bytes at offset 0 diff --git a/tests/qemu-iotests/038 b/tests/qemu-iotests/038 index 707e2d72e9..a253231f5b 100755 --- a/tests/qemu-iotests/038 +++ b/tests/qemu-iotests/038 @@ -71,7 +71,7 @@ backing_io 0 256 write | $QEMU_IO "$TEST_IMG" | _filter_qemu_io TEST_IMG="$TEST_IMG_SAVE" -_make_test_img -b "$TEST_IMG.base" 6G +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT 6G echo echo "== Some concurrent requests touching the same cluster ==" diff --git a/tests/qemu-iotests/038.out b/tests/qemu-iotests/038.out index 0bdfb19faa..fe2108593a 100644 --- a/tests/qemu-iotests/038.out +++ b/tests/qemu-iotests/038.out @@ -514,7 +514,7 @@ wrote 65536/65536 bytes at offset 16646144 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 65536/65536 bytes at offset 16711680 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT == Some concurrent requests touching the same cluster == wrote 65536/65536 bytes at offset XXX diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039 index ddce48ab47..42f6503138 100755 --- a/tests/qemu-iotests/039 +++ b/tests/qemu-iotests/039 @@ -133,7 +133,8 @@ echo "== Committing to a backing file with lazy_refcounts=on ==" TEST_IMG="$TEST_IMG".base _make_test_img -o "compat=1.1,lazy_refcounts=on" $size -_make_test_img -o "compat=1.1,lazy_refcounts=on,backing_file=$TEST_IMG.base" $size +_make_test_img -o "compat=1.1,lazy_refcounts=on,backing_file=$TEST_IMG.base" \ + -F $IMGFMT $size $QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG commit "$TEST_IMG" diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out index bdafa3ace3..e52484d4be 100644 --- a/tests/qemu-iotests/039.out +++ b/tests/qemu-iotests/039.out @@ -66,7 +66,7 @@ No errors were found on the image. == Committing to a backing file with lazy_refcounts=on == 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Image committed. diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index 32c82b4ec6..f58f50d023 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -80,8 +80,11 @@ class TestSingleDrive(ImageCommitTestCase): def setUp(self): iotests.create_image(backing_img, self.image_len) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, '-F', 'raw', mid_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % mid_img, + '-F', iotests.imgfmt, test_img) qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', backing_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img) self.vm = iotests.VM().add_drive(test_img, "node-name=top,backing.node-name=mid,backing.backing.node-name=base", interface="none") @@ -305,10 +308,16 @@ class TestRelativePaths(ImageCommitTestCase): if exception.errno != errno.EEXIST: raise iotests.create_image(self.backing_img_abs, TestRelativePaths.image_len) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % self.backing_img_abs, self.mid_img_abs) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % self.mid_img_abs, self.test_img) - qemu_img('rebase', '-u', '-b', self.backing_img, self.mid_img_abs) - qemu_img('rebase', '-u', '-b', self.mid_img, self.test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % self.backing_img_abs, + '-F', 'raw', self.mid_img_abs) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % self.mid_img_abs, + '-F', iotests.imgfmt, self.test_img) + qemu_img('rebase', '-u', '-b', self.backing_img, + '-F', 'raw', self.mid_img_abs) + qemu_img('rebase', '-u', '-b', self.mid_img, + '-F', iotests.imgfmt, self.test_img) qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', self.backing_img_abs) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', self.mid_img_abs) self.vm = iotests.VM().add_drive(self.test_img) @@ -371,8 +380,11 @@ class TestSetSpeed(ImageCommitTestCase): def setUp(self): qemu_img('create', backing_img, str(TestSetSpeed.image_len)) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, '-F', 'raw', mid_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % mid_img, + '-F', iotests.imgfmt, test_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 0 512', test_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img) self.vm = iotests.VM().add_drive('blkdebug::' + test_img) @@ -410,9 +422,14 @@ class TestReopenOverlay(ImageCommitTestCase): def setUp(self): iotests.create_image(self.img0, self.image_len) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % self.img0, self.img1) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % self.img1, self.img2) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % self.img2, self.img3) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % self.img0, '-F', 'raw', self.img1) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % self.img1, + '-F', iotests.imgfmt, self.img2) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % self.img2, + '-F', iotests.imgfmt, self.img3) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xab 0 128K', self.img1) self.vm = iotests.VM().add_drive(self.img3) self.vm.launch() @@ -435,8 +452,12 @@ class TestErrorHandling(iotests.QMPTestCase): def setUp(self): iotests.create_image(backing_img, self.image_len) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, + '-F', 'raw', mid_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % mid_img, + '-F', iotests.imgfmt, test_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x11 0 512k', mid_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x22 0 512k', test_img) diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index b843f88a66..f0a7bf6650 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -44,7 +44,8 @@ class TestSingleDrive(iotests.QMPTestCase): def setUp(self): iotests.create_image(backing_img, self.image_len) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, '-F', 'raw', test_img) self.vm = iotests.VM().add_drive(test_img, "node-name=top,backing.node-name=base") if iotests.qemu_default_machine == 'pc': self.vm.add_drive(None, 'media=cdrom', 'ide') @@ -157,7 +158,8 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' - % (self.image_len, backing_img), target_img) + % (self.image_len, backing_img), + '-F', 'raw', target_img) result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', mode='existing', target=self.qmp_target) self.assert_qmp(result, 'return', {}) @@ -227,7 +229,8 @@ class TestSingleBlockdev(TestSingleDrive): def setUp(self): TestSingleDrive.setUp(self) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, '-F', 'raw', target_img) args = {'driver': iotests.imgfmt, 'node-name': self.qmp_target, 'file': { 'filename': target_img, 'driver': 'file' } } @@ -312,7 +315,8 @@ class TestMirrorNoBacking(iotests.QMPTestCase): def setUp(self): iotests.create_image(backing_img, TestMirrorNoBacking.image_len) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, '-F', 'raw', test_img) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() @@ -329,7 +333,8 @@ class TestMirrorNoBacking(iotests.QMPTestCase): def test_complete(self): self.assert_no_active_block_jobs() - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, '-F', 'raw', target_img) result = self.vm.qmp('drive-mirror', device='drive0', sync='full', mode='existing', target=target_img) self.assert_qmp(result, 'return', {}) @@ -344,7 +349,8 @@ class TestMirrorNoBacking(iotests.QMPTestCase): def test_cancel(self): self.assert_no_active_block_jobs() - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, '-F', 'raw', target_img) result = self.vm.qmp('drive-mirror', device='drive0', sync='full', mode='existing', target=target_img) self.assert_qmp(result, 'return', {}) @@ -363,7 +369,8 @@ class TestMirrorNoBacking(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d' %(TestMirrorNoBacking.image_len), target_backing_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' - % (TestMirrorNoBacking.image_len, target_backing_img), target_img) + % (TestMirrorNoBacking.image_len, target_backing_img), + '-F', iotests.imgfmt, target_img) result = self.vm.qmp('drive-mirror', device='drive0', sync='full', mode='existing', target=target_img) @@ -382,7 +389,8 @@ class TestMirrorResized(iotests.QMPTestCase): def setUp(self): iotests.create_image(backing_img, TestMirrorResized.backing_len) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, '-F', 'raw', test_img) qemu_img('resize', test_img, '2M') self.vm = iotests.VM().add_drive(test_img) self.vm.launch() @@ -528,7 +536,9 @@ new_state = "1" # Test COW into the target image. The first half of the # cluster at MIRROR_GRANULARITY has to be copied from # backing_img, even though sync='top'. - qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img) + qemu_img('create', '-f', iotests.imgfmt, + '-ocluster_size=131072,backing_file=%s' %(backing_img), + '-F', 'raw', target_img) result = self.vm.qmp('drive-mirror', device='drive0', sync='top', on_source_error='ignore', mode='existing', target=target_img) @@ -548,7 +558,8 @@ new_state = "1" self.vm.shutdown() # Detach blkdebug to compare images successfully - qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img) + qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, + '-F', 'raw', test_img) self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') @@ -620,7 +631,8 @@ new_state = "1" self.blkdebug_file = target_img + ".blkdebug" iotests.create_image(backing_img, TestWriteErrors.image_len) self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5) - qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-obacking_file=%s' %(backing_img), '-F', 'raw', test_img) self.vm = iotests.VM().add_drive(test_img) self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img) qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img) @@ -715,7 +727,8 @@ class TestSetSpeed(iotests.QMPTestCase): def setUp(self): qemu_img('create', backing_img, str(TestSetSpeed.image_len)) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, '-F', 'raw', test_img) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() diff --git a/tests/qemu-iotests/042 b/tests/qemu-iotests/042 index 0e85b356b7..e8f23a174c 100755 --- a/tests/qemu-iotests/042 +++ b/tests/qemu-iotests/042 @@ -64,8 +64,8 @@ _check_test_img echo echo "== Rebasing the image ==" -$QEMU_IMG rebase -u -b "$TEST_IMG.orig" "$TEST_IMG" -$QEMU_IMG rebase -b "$TEST_IMG.orig" "$TEST_IMG" +$QEMU_IMG rebase -u -b "$TEST_IMG.orig" -F $IMGFMT "$TEST_IMG" +$QEMU_IMG rebase -b "$TEST_IMG.orig" -F $IMGFMT "$TEST_IMG" _check_test_img # success, all done diff --git a/tests/qemu-iotests/043 b/tests/qemu-iotests/043 index b102e49208..3271737f69 100755 --- a/tests/qemu-iotests/043 +++ b/tests/qemu-iotests/043 @@ -46,7 +46,7 @@ _supported_proto file size=128M _make_test_img $size -$QEMU_IMG rebase -u -b "$TEST_IMG" "$TEST_IMG" +$QEMU_IMG rebase -u -b "$TEST_IMG" -F $IMGFMT "$TEST_IMG" echo echo "== backing file references self ==" @@ -54,8 +54,8 @@ _img_info --backing-chain _make_test_img $size mv "$TEST_IMG" "$TEST_IMG.base" -_make_test_img -b "$TEST_IMG.base" $size -$QEMU_IMG rebase -u -b "$TEST_IMG" "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $size +$QEMU_IMG rebase -u -b "$TEST_IMG" -F $IMGFMT "$TEST_IMG.base" echo echo "== parent references self ==" @@ -63,12 +63,12 @@ _img_info --backing-chain _make_test_img $size mv "$TEST_IMG" "$TEST_IMG.1.base" -_make_test_img -b "$TEST_IMG.1.base" $size +_make_test_img -b "$TEST_IMG.1.base" -F $IMGFMT $size mv "$TEST_IMG" "$TEST_IMG.2.base" -_make_test_img -b "$TEST_IMG.2.base" $size +_make_test_img -b "$TEST_IMG.2.base" -F $IMGFMT $size mv "$TEST_IMG" "$TEST_IMG.3.base" -_make_test_img -b "$TEST_IMG.3.base" $size -$QEMU_IMG rebase -u -b "$TEST_IMG.2.base" "$TEST_IMG.1.base" +_make_test_img -b "$TEST_IMG.3.base" -F $IMGFMT $size +$QEMU_IMG rebase -u -b "$TEST_IMG.2.base" -F $IMGFMT "$TEST_IMG.1.base" echo echo "== ancestor references another ancestor ==" @@ -76,17 +76,18 @@ _img_info --backing-chain _make_test_img $size mv "$TEST_IMG" "$TEST_IMG.1.base" -_make_test_img -b "$TEST_IMG.1.base" $size +_make_test_img -b "$TEST_IMG.1.base" -F $IMGFMT $size mv "$TEST_IMG" "$TEST_IMG.2.base" -_make_test_img -b "$TEST_IMG.2.base" $size +_make_test_img -b "$TEST_IMG.2.base" -F $IMGFMT $size echo echo "== finite chain of length 3 (human) ==" -_img_info --backing-chain +# Exclude backing format, since qed differs from qcow2 on what gets stored +_img_info --backing-chain | grep -v '^backing file format:' echo echo "== finite chain of length 3 (json) ==" -_img_info --backing-chain --output=json +_img_info --backing-chain --output=json | grep -v 'backing-filename-format' # success, all done echo "*** done" diff --git a/tests/qemu-iotests/043.out b/tests/qemu-iotests/043.out index 0280f999ce..63ecb21816 100644 --- a/tests/qemu-iotests/043.out +++ b/tests/qemu-iotests/043.out @@ -4,20 +4,20 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 == backing file references self == qemu-img: Backing file 'TEST_DIR/t.IMGFMT' creates an infinite loop. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT == parent references self == qemu-img: Backing file 'TEST_DIR/t.IMGFMT' creates an infinite loop. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.1.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.2.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.3.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.1.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.2.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.3.base backing_fmt=IMGFMT == ancestor references another ancestor == qemu-img: Backing file 'TEST_DIR/t.IMGFMT.2.base' creates an infinite loop. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.1.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.2.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.1.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.2.base backing_fmt=IMGFMT == finite chain of length 3 (human) == image: TEST_DIR/t.IMGFMT diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046 index ecbe5fc0f4..88b3363c19 100755 --- a/tests/qemu-iotests/046 +++ b/tests/qemu-iotests/046 @@ -69,7 +69,7 @@ backing_io 0 32 write | $QEMU_IO "$TEST_IMG" | _filter_qemu_io mv "$TEST_IMG" "$TEST_IMG.base" -_make_test_img -b "$TEST_IMG.base" 6G +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT 6G echo echo "== Some concurrent requests touching the same cluster ==" diff --git a/tests/qemu-iotests/046.out b/tests/qemu-iotests/046.out index 70783041e2..b022bcddd5 100644 --- a/tests/qemu-iotests/046.out +++ b/tests/qemu-iotests/046.out @@ -66,7 +66,7 @@ wrote 65536/65536 bytes at offset 1966080 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 65536/65536 bytes at offset 2031616 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT == Some concurrent requests touching the same cluster == blkdebug: Suspended request 'A' diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050 index cdc5356541..4b0a390c43 100755 --- a/tests/qemu-iotests/050 +++ b/tests/qemu-iotests/050 @@ -58,13 +58,13 @@ $QEMU_IO -c "write -P 0x5a 0 1048576" "$TEST_IMG" | _filter_qemu_io TEST_IMG="$TEST_IMG_SAVE" -_make_test_img -b "$TEST_IMG.old" $size +_make_test_img -b "$TEST_IMG.old" -F $IMGFMT $size $QEMU_IO -c "write -z 0 1048576" "$TEST_IMG" | _filter_qemu_io echo echo "== Rebasing the image ==" -$QEMU_IMG rebase -b "$TEST_IMG.new" "$TEST_IMG" +$QEMU_IMG rebase -b "$TEST_IMG.new" -F $IMGFMT "$TEST_IMG" $QEMU_IO -c "read -P 0x00 0 1048576" "$TEST_IMG" | _filter_qemu_io # success, all done diff --git a/tests/qemu-iotests/050.out b/tests/qemu-iotests/050.out index 3602d580dc..ab3daeddca 100644 --- a/tests/qemu-iotests/050.out +++ b/tests/qemu-iotests/050.out @@ -7,7 +7,7 @@ wrote 1048576/1048576 bytes at offset 0 Formatting 'TEST_DIR/t.IMGFMT.new', fmt=IMGFMT size=10485760 wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760 backing_file=TEST_DIR/t.IMGFMT.old +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760 backing_file=TEST_DIR/t.IMGFMT.old backing_fmt=IMGFMT wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 034d3a3250..bee26075b2 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -70,7 +70,7 @@ device_id="drive0" _make_test_img $size cp "$TEST_IMG" "$TEST_IMG.orig" mv "$TEST_IMG" "$TEST_IMG.base" -_make_test_img -b "$TEST_IMG.base" $size +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $size echo echo === Unknown option === diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 554c5ca90a..de4771bcb3 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -1,6 +1,6 @@ QA output created by 051 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT === Unknown option === diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out index da8ad87187..f707471fb0 100644 --- a/tests/qemu-iotests/051.pc.out +++ b/tests/qemu-iotests/051.pc.out @@ -1,6 +1,6 @@ QA output created by 051 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT === Unknown option === diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056 index f73fc74457..052456aa00 100755 --- a/tests/qemu-iotests/056 +++ b/tests/qemu-iotests/056 @@ -54,7 +54,8 @@ class TestSyncModesNoneAndTop(iotests.QMPTestCase): def setUp(self): create_image(backing_img, TestSyncModesNoneAndTop.image_len) - qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, + '-o', 'backing_file=%s' % backing_img, '-F', 'raw', test_img) qemu_io('-c', 'write -P0x41 0 512', test_img) qemu_io('-c', 'write -P0xd5 1M 32k', test_img) qemu_io('-c', 'write -P0xdc 32M 124k', test_img) diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index 32c0ecce9e..94c0d5accc 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -160,7 +160,7 @@ TEST_IMG=$BACKING_IMG _make_test_img 1G $QEMU_IO -c 'write 0k 64k' "$BACKING_IMG" | _filter_qemu_io -_make_test_img -b "$BACKING_IMG" 1G +_make_test_img -b "$BACKING_IMG" -F $IMGFMT 1G # Write two clusters, the second one enforces creation of an L2 table after # the first data cluster. $QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index be5f8707a3..e574c38797 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -101,7 +101,7 @@ read 512/512 bytes at offset 0 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1073741824 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 65536/65536 bytes at offset 536870912 diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061 index 10eb243164..08ddbdd10c 100755 --- a/tests/qemu-iotests/061 +++ b/tests/qemu-iotests/061 @@ -224,7 +224,7 @@ echo "=== Testing zero expansion on backed image ===" echo TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M $QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io -_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M +_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" -F $IMGFMT 64M $QEMU_IO -c "read -P 0x2a 0 128k" -c "write -z 0 64k" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG amend -o "compat=0.10" "$TEST_IMG" _check_test_img @@ -235,7 +235,7 @@ echo "=== Testing zero expansion on backed inactive clusters ===" echo TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M $QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io -_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M +_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" -F $IMGFMT 64M $QEMU_IO -c "write -z 0 64k" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG snapshot -c foo "$TEST_IMG" $QEMU_IO -c "write -P 0x42 0 128k" "$TEST_IMG" | _filter_qemu_io @@ -251,7 +251,7 @@ echo "=== Testing zero expansion on backed image with shared L2 table ===" echo TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M $QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io -_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M +_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" -F $IMGFMT 64M $QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG snapshot -c foo "$TEST_IMG" $QEMU_IMG amend -o "compat=0.10" "$TEST_IMG" @@ -274,7 +274,7 @@ echo echo "=== Testing progress report without snapshot ===" echo TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 4G -_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 4G +_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" -F $IMGFMT 4G $QEMU_IO -c "write -z 0 64k" \ -c "write -z 1G 64k" \ -c "write -z 2G 64k" \ @@ -286,7 +286,7 @@ echo echo "=== Testing progress report with snapshot ===" echo TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 4G -_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 4G +_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" -F $IMGFMT 4G $QEMU_IO -c "write -z 0 64k" \ -c "write -z 1G 64k" \ -c "write -z 2G 64k" \ diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index 44e3c624f9..b2d2dfed04 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -428,7 +428,7 @@ read 131072/131072 bytes at offset 0 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT read 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 65536/65536 bytes at offset 0 @@ -444,7 +444,7 @@ read 65536/65536 bytes at offset 65536 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 131072/131072 bytes at offset 0 @@ -463,7 +463,7 @@ read 65536/65536 bytes at offset 65536 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. @@ -487,7 +487,7 @@ read 67108864/67108864 bytes at offset 0 === Testing progress report without snapshot === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=4294967296 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 65536/65536 bytes at offset 1073741824 @@ -502,7 +502,7 @@ No errors were found on the image. === Testing progress report with snapshot === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=4294967296 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 65536/65536 bytes at offset 1073741824 diff --git a/tests/qemu-iotests/069 b/tests/qemu-iotests/069 index b997b127f0..a4da83b2d9 100755 --- a/tests/qemu-iotests/069 +++ b/tests/qemu-iotests/069 @@ -46,7 +46,7 @@ echo echo "=== Creating an image with a backing file and deleting that file ===" echo TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE -_make_test_img -b "$TEST_IMG.base" $IMG_SIZE +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $IMG_SIZE _rm_test_img "$TEST_IMG.base" # Just open the image and close it right again (this should print an error message) $QEMU_IO -c quit "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt diff --git a/tests/qemu-iotests/069.out b/tests/qemu-iotests/069.out index c78e8c2b72..126b4d2d51 100644 --- a/tests/qemu-iotests/069.out +++ b/tests/qemu-iotests/069.out @@ -3,6 +3,6 @@ QA output created by 069 === Creating an image with a backing file and deleting that file === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=131072 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT qemu-io: can't open device TEST_DIR/t.IMGFMT: Could not open backing file: Could not open 'TEST_DIR/t.IMGFMT.base': No such file or directory *** done diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073 index 23a1bdf890..1dce478709 100755 --- a/tests/qemu-iotests/073 +++ b/tests/qemu-iotests/073 @@ -52,7 +52,7 @@ echo "== creating backing file ==" TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $QEMU_IO -c "write -P 0xa5 0 $size" "$TEST_IMG.base" | _filter_qemu_io echo diff --git a/tests/qemu-iotests/073.out b/tests/qemu-iotests/073.out index de5452492c..7a718b525e 100644 --- a/tests/qemu-iotests/073.out +++ b/tests/qemu-iotests/073.out @@ -2,7 +2,7 @@ QA output created by 073 == creating 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082 index 1998965ed4..2135581867 100755 --- a/tests/qemu-iotests/082 +++ b/tests/qemu-iotests/082 @@ -84,8 +84,10 @@ run_qemu_img create -f $IMGFMT -o cluster_size=4k -o help "$TEST_IMG" $size run_qemu_img create -f $IMGFMT -o cluster_size=4k -o \? "$TEST_IMG" $size # Looks like a help option, but is part of the backing file name -run_qemu_img create -f $IMGFMT -u -o backing_file="$TEST_IMG",,help "$TEST_IMG" $size -run_qemu_img create -f $IMGFMT -u -o backing_file="$TEST_IMG",,\? "$TEST_IMG" $size +run_qemu_img create -f $IMGFMT -u -o backing_file="$TEST_IMG",,help \ + -F $IMGFMT "$TEST_IMG" $size +run_qemu_img create -f $IMGFMT -u -o backing_file="$TEST_IMG",,\? \ + -F $IMGFMT "$TEST_IMG" $size # Try to trick qemu-img into creating escaped commas run_qemu_img create -f $IMGFMT -o backing_file="$TEST_IMG", -o help "$TEST_IMG" $size @@ -141,8 +143,8 @@ run_qemu_img convert -O $IMGFMT -o cluster_size=4k -o help "$TEST_IMG" "$TEST_IM run_qemu_img convert -O $IMGFMT -o cluster_size=4k -o \? "$TEST_IMG" "$TEST_IMG".base # Looks like a help option, but is part of the backing file name -run_qemu_img convert -O $IMGFMT -o backing_file="$TEST_IMG",,help "$TEST_IMG" "$TEST_IMG".base -run_qemu_img convert -O $IMGFMT -o backing_file="$TEST_IMG",,\? "$TEST_IMG" "$TEST_IMG".base +run_qemu_img convert -O $IMGFMT -o backing_fmt=$IMGFMT,backing_file="$TEST_IMG",,help "$TEST_IMG" "$TEST_IMG".base +run_qemu_img convert -O $IMGFMT -o backing_fmt=$IMGFMT,backing_file="$TEST_IMG",,\? "$TEST_IMG" "$TEST_IMG".base # Try to trick qemu-img into creating escaped commas run_qemu_img convert -O $IMGFMT -o backing_file="$TEST_IMG", -o help "$TEST_IMG" "$TEST_IMG".base diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index a38a26fc57..1728aff1e0 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -244,11 +244,11 @@ Supported options: refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size -Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,help lazy_refcounts=off refcount_bits=16 +Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,help -F qcow2 TEST_DIR/t.qcow2 128M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,help backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 -Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 128M -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,? lazy_refcounts=off refcount_bits=16 +Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,? -F qcow2 TEST_DIR/t.qcow2 128M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,? backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 128M qemu-img: Invalid option list: backing_file=TEST_DIR/t.qcow2, @@ -543,10 +543,10 @@ Supported options: refcount_bits= - Width of a reference count entry in bits size= - Virtual disk size -Testing: convert -O qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base +Testing: convert -O qcow2 -o backing_fmt=qcow2,backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base qemu-img: Could not open 'TEST_DIR/t.qcow2.base': Could not open backing file: Could not open 'TEST_DIR/t.qcow2,help': No such file or directory -Testing: convert -O qcow2 -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base +Testing: convert -O qcow2 -o backing_fmt=qcow2,backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base qemu-img: Could not open 'TEST_DIR/t.qcow2.base': Could not open backing file: Could not open 'TEST_DIR/t.qcow2,?': No such file or directory Testing: convert -O qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085 index dd3c993a2d..e99eb44581 100755 --- a/tests/qemu-iotests/085 +++ b/tests/qemu-iotests/085 @@ -106,7 +106,7 @@ add_snapshot_image() { base_image="${TEST_DIR}/$((${1}-1))-${snapshot_virt0}" snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}" - TEST_IMG=$snapshot_file _make_test_img -u -b "${base_image}" "$size" + TEST_IMG=$snapshot_file _make_test_img -u -b "${base_image}" -F $IMGFMT "$size" do_blockdev_add "$1" "'backing': null, " "${snapshot_file}" } @@ -225,7 +225,7 @@ echo SNAPSHOTS=$((${SNAPSHOTS}+1)) TEST_IMG="$TEST_IMG.base" _make_test_img "$size" -_make_test_img -b "${TEST_IMG}.base" "$size" +_make_test_img -b "${TEST_IMG}.base" -F $IMGFMT "$size" do_blockdev_add ${SNAPSHOTS} "" "${TEST_IMG}" blockdev_snapshot ${SNAPSHOTS} error diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out index d68c06efdf..700658d5a3 100644 --- a/tests/qemu-iotests/085.out +++ b/tests/qemu-iotests/085.out @@ -68,12 +68,12 @@ Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compres === Create a couple of snapshots using blockdev-snapshot === -Formatting 'TEST_DIR/11-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/10-snapshot-v0.IMGFMT +Formatting 'TEST_DIR/11-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/10-snapshot-v0.IMGFMT backing_fmt=IMGFMT { 'execute': 'blockdev-add', 'arguments': { 'driver': 'IMGFMT', 'node-name': 'snap_11', 'backing': null, 'file': { 'driver': 'file', 'filename': 'TEST_DIR/11-snapshot-v0.IMGFMT', 'node-name': 'file_11' } } } {"return": {}} { 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_11' } } {"return": {}} -Formatting 'TEST_DIR/12-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/11-snapshot-v0.IMGFMT +Formatting 'TEST_DIR/12-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/11-snapshot-v0.IMGFMT backing_fmt=IMGFMT { 'execute': 'blockdev-add', 'arguments': { 'driver': 'IMGFMT', 'node-name': 'snap_12', 'backing': null, 'file': { 'driver': 'file', 'filename': 'TEST_DIR/12-snapshot-v0.IMGFMT', 'node-name': 'file_12' } } } {"return": {}} { 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_12' } } @@ -101,7 +101,7 @@ Formatting 'TEST_DIR/12-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_f === Invalid command - snapshot node has a backing image === 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT { 'execute': 'blockdev-add', 'arguments': { 'driver': 'IMGFMT', 'node-name': 'snap_13', 'file': { 'driver': 'file', 'filename': 'TEST_DIR/t.IMGFMT', 'node-name': 'file_13' } } } {"return": {}} { 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_13' } } diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089 index 059ad75e28..66c5415abe 100755 --- a/tests/qemu-iotests/089 +++ b/tests/qemu-iotests/089 @@ -84,7 +84,7 @@ echo echo "=== Testing correct handling of 'backing':null ===" echo -_make_test_img -b "$TEST_IMG.base" $IMG_SIZE +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $IMG_SIZE # This should read 42 $QEMU_IO -c 'read -P 42 0 512' "$TEST_IMG" | _filter_qemu_io diff --git a/tests/qemu-iotests/089.out b/tests/qemu-iotests/089.out index 20c8ce8f0e..15682c2886 100644 --- a/tests/qemu-iotests/089.out +++ b/tests/qemu-iotests/089.out @@ -21,7 +21,7 @@ read 512/512 bytes at offset 0 === Testing correct handling of 'backing':null === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 512/512 bytes at offset 0 diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095 index 155ae86aa7..77a5f0f3f5 100755 --- a/tests/qemu-iotests/095 +++ b/tests/qemu-iotests/095 @@ -51,9 +51,9 @@ size_larger=100M TEST_IMG="$TEST_IMG.base" _make_test_img $size_smaller -TEST_IMG="$TEST_IMG.snp1" _make_test_img -b "$TEST_IMG.base" $size_larger +TEST_IMG="$TEST_IMG.snp1" _make_test_img -b "$TEST_IMG.base" -F $IMGFMT $size_larger -_make_test_img -b "${TEST_IMG}.snp1" $size_larger +_make_test_img -b "${TEST_IMG}.snp1" -F $IMGFMT $size_larger echo echo "=== Base image info before commit and resize ===" diff --git a/tests/qemu-iotests/095.out b/tests/qemu-iotests/095.out index 614e5ccbbb..e66ced58f8 100644 --- a/tests/qemu-iotests/095.out +++ b/tests/qemu-iotests/095.out @@ -1,7 +1,7 @@ QA output created by 095 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=5242880 -Formatting 'TEST_DIR/t.IMGFMT.snp1', fmt=IMGFMT size=104857600 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=104857600 backing_file=TEST_DIR/t.IMGFMT.snp1 +Formatting 'TEST_DIR/t.IMGFMT.snp1', fmt=IMGFMT size=104857600 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=104857600 backing_file=TEST_DIR/t.IMGFMT.snp1 backing_fmt=IMGFMT === Base image info before commit and resize === image: TEST_DIR/t.IMGFMT.base diff --git a/tests/qemu-iotests/097 b/tests/qemu-iotests/097 index 690f3d3ce1..d910a8b107 100755 --- a/tests/qemu-iotests/097 +++ b/tests/qemu-iotests/097 @@ -67,8 +67,8 @@ echo len=$((2100 * 1024 * 1024 + 512)) # larger than 2G, and not cluster aligned TEST_IMG="$TEST_IMG.base" _make_test_img $len -TEST_IMG="$TEST_IMG.itmd" _make_test_img -b "$TEST_IMG.base" $len -_make_test_img -b "$TEST_IMG.itmd" $len +TEST_IMG="$TEST_IMG.itmd" _make_test_img -b "$TEST_IMG.base" -F $IMGFMT $len +_make_test_img -b "$TEST_IMG.itmd" -F $IMGFMT $len $QEMU_IO -c "write -P 1 0x7ffd0000 192k" "$TEST_IMG.base" | _filter_qemu_io $QEMU_IO -c "write -P 2 0x7ffe0000 128k" "$TEST_IMG.itmd" | _filter_qemu_io diff --git a/tests/qemu-iotests/097.out b/tests/qemu-iotests/097.out index f6705a1cc7..3038ddab31 100644 --- a/tests/qemu-iotests/097.out +++ b/tests/qemu-iotests/097.out @@ -3,8 +3,8 @@ QA output created by 097 === Test pass 0 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT wrote 196608/196608 bytes at offset 2147287040 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 131072/131072 bytes at offset 2147352576 @@ -40,8 +40,8 @@ Offset Length File === Test pass 1 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT wrote 196608/196608 bytes at offset 2147287040 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 131072/131072 bytes at offset 2147352576 @@ -78,8 +78,8 @@ Offset Length File === Test pass 2 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT wrote 196608/196608 bytes at offset 2147287040 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 131072/131072 bytes at offset 2147352576 @@ -116,8 +116,8 @@ Offset Length File === Test pass 3 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT wrote 196608/196608 bytes at offset 2147287040 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 131072/131072 bytes at offset 2147352576 diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098 index 1e29d96b3d..f2ccdd7909 100755 --- a/tests/qemu-iotests/098 +++ b/tests/qemu-iotests/098 @@ -52,7 +52,7 @@ echo "=== $event ===" echo TEST_IMG="$TEST_IMG.base" _make_test_img 64M -_make_test_img -b "$TEST_IMG.base" 64M +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT 64M # Some data that can be leaked when emptying the top image $QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io diff --git a/tests/qemu-iotests/098.out b/tests/qemu-iotests/098.out index 23cf371f53..6c73dd0977 100644 --- a/tests/qemu-iotests/098.out +++ b/tests/qemu-iotests/098.out @@ -3,7 +3,7 @@ QA output created by 098 === l1_update === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error @@ -12,7 +12,7 @@ No errors were found on the image. === empty_image_prepare === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error @@ -25,7 +25,7 @@ No errors were found on the image. === reftable_update === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error @@ -39,7 +39,7 @@ No errors were found on the image. === refblock_alloc === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110 index 139c02c2cf..f1813d0dfb 100755 --- a/tests/qemu-iotests/110 +++ b/tests/qemu-iotests/110 @@ -50,7 +50,7 @@ echo '=== Reconstructable filename ===' echo TEST_IMG="$TEST_IMG.base" _make_test_img 64M -_make_test_img -b "$TEST_IMG_REL.base" 64M +_make_test_img -b "$TEST_IMG_REL.base" -F $IMGFMT 64M # qemu should be able to reconstruct the filename, so relative backing names # should work # (We have to filter the backing file format because vmdk always @@ -91,7 +91,7 @@ echo '=== Backing name is always relative to the backed image ===' echo # omit the image size; it should work anyway -_make_test_img -b "$TEST_IMG_REL.base" +_make_test_img -b "$TEST_IMG_REL.base" -F $IMGFMT echo echo '=== Nodes without a common directory ===' diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out index f835553a99..cf8f6c025d 100644 --- a/tests/qemu-iotests/110.out +++ b/tests/qemu-iotests/110.out @@ -3,7 +3,7 @@ QA output created by 110 === Reconstructable filename === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.base backing_fmt=IMGFMT image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 64 MiB (67108864 bytes) @@ -18,7 +18,7 @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base) === Backing name is always relative to the backed image === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.base backing_fmt=IMGFMT === Nodes without a common directory === diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 index 2dc16b2ca4..dfd1cd05d6 100755 --- a/tests/qemu-iotests/122 +++ b/tests/qemu-iotests/122 @@ -52,9 +52,10 @@ echo echo "=== Check allocation status regression with -B ===" echo -_make_test_img -b "$TEST_IMG".base +_make_test_img -b "$TEST_IMG".base -F $IMGFMT $QEMU_IO -c "write -P 0x22 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir -$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base "$TEST_IMG" "$TEST_IMG".orig +$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base \ + -o backing_fmt=$IMGFMT "$TEST_IMG" "$TEST_IMG".orig $QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map @@ -62,18 +63,22 @@ echo echo "=== Check that zero clusters are kept in overlay ===" echo -_make_test_img -b "$TEST_IMG".base +_make_test_img -b "$TEST_IMG".base -F $IMGFMT $QEMU_IO -c "write -P 0 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir -$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base "$TEST_IMG" "$TEST_IMG".orig +$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \ + "$TEST_IMG" "$TEST_IMG".orig $QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir -$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base "$TEST_IMG" "$TEST_IMG".orig +$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \ + "$TEST_IMG" "$TEST_IMG".orig $QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir $QEMU_IO -c "write -z 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir -$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base "$TEST_IMG" "$TEST_IMG".orig +$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \ + "$TEST_IMG" "$TEST_IMG".orig $QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir -$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base "$TEST_IMG" "$TEST_IMG".orig +$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \ + "$TEST_IMG" "$TEST_IMG".orig $QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir @@ -94,11 +99,11 @@ TEST_IMG="$TEST_IMG".base _make_test_img 256M # We do not want such a zero write, however, because we are past the # end of the backing file on the target as well, so we do not need to # write anything there. -_make_test_img -b "$TEST_IMG".base 768M +_make_test_img -b "$TEST_IMG".base 768M -F $IMGFMT # Use compat=0.10 as the output so there is no zero cluster support $QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o compat=0.10 \ - "$TEST_IMG" "$TEST_IMG".orig + -o backing_fmt=$IMGFMT "$TEST_IMG" "$TEST_IMG".orig # See that nothing has been allocated past 64M $QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map @@ -110,7 +115,7 @@ $QEMU_IO -c 'write -P 0x11 255M 1M' "$TEST_IMG".base 2>&1 | _filter_qemu_io $QEMU_IO -c 'write -P 0x22 600M 1M' "$TEST_IMG" 2>&1 | _filter_qemu_io $QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o compat=0.10 \ - "$TEST_IMG" "$TEST_IMG".orig + -o backing_fmt=$IMGFMT "$TEST_IMG" "$TEST_IMG".orig $QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map $QEMU_IO -c 'read -P 0x11 255M 1M' \ @@ -199,7 +204,7 @@ $QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map TEST_IMG="$TEST_IMG".base _make_test_img 64M $QEMU_IO -c "write -P 0x11 0 32M" "$TEST_IMG".base 2>&1 | _filter_qemu_io | _filter_testdir -_make_test_img -b "$TEST_IMG".base 64M +_make_test_img -b "$TEST_IMG".base 64M -F $IMGFMT $QEMU_IO -c "write -P 0x22 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir echo diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out index c2e154a1e5..f1f195ed77 100644 --- a/tests/qemu-iotests/122.out +++ b/tests/qemu-iotests/122.out @@ -5,7 +5,7 @@ wrote 67108864/67108864 bytes at offset 0 === Check allocation status regression with -B === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 3145728/3145728 bytes at offset 0 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Offset Length File @@ -14,7 +14,7 @@ Offset Length File === Check that zero clusters are kept in overlay === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 3145728/3145728 bytes at offset 0 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 3145728/3145728 bytes at offset 0 @@ -31,7 +31,7 @@ read 3145728/3145728 bytes at offset 0 === Converting to an overlay larger than its backing file === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=268435456 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=805306368 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=805306368 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT Offset Length File wrote 1048576/1048576 bytes at offset 267386880 @@ -141,7 +141,7 @@ read 63963136/63963136 bytes at offset 3145728 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 wrote 33554432/33554432 bytes at offset 0 32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 3145728/3145728 bytes at offset 0 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126 index b7fce1e59d..dd5a211227 100755 --- a/tests/qemu-iotests/126 +++ b/tests/qemu-iotests/126 @@ -61,7 +61,7 @@ BASE_IMG="$TEST_DIR/image:base.$IMGFMT" TOP_IMG="$TEST_DIR/image:top.$IMGFMT" TEST_IMG=$BASE_IMG _make_test_img 64M -TEST_IMG=$TOP_IMG _make_test_img -b ./image:base.$IMGFMT +TEST_IMG=$TOP_IMG _make_test_img -b ./image:base.$IMGFMT -F $IMGFMT # (1) The default cluster size depends on the image format # (2) vmdk only supports vmdk backing files, so it always reports the @@ -82,7 +82,7 @@ BASE_IMG="base.$IMGFMT" TOP_IMG="file:image:top.$IMGFMT" TEST_IMG=$BASE_IMG _make_test_img 64M -TEST_IMG=$TOP_IMG _make_test_img -b "$BASE_IMG" +TEST_IMG=$TOP_IMG _make_test_img -b "$BASE_IMG" -F $IMGFMT TEST_IMG=$TOP_IMG _img_info | grep -ve 'cluster_size' -e 'backing file format' diff --git a/tests/qemu-iotests/126.out b/tests/qemu-iotests/126.out index e3c4d61916..7d6634685e 100644 --- a/tests/qemu-iotests/126.out +++ b/tests/qemu-iotests/126.out @@ -8,14 +8,14 @@ Formatting 'file:TEST_DIR/a:b.IMGFMT', fmt=IMGFMT size=67108864 === Testing relative backing filename resolution === Formatting 'TEST_DIR/image:base.IMGFMT', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/image:top.IMGFMT', fmt=IMGFMT size=67108864 backing_file=./image:base.IMGFMT +Formatting 'TEST_DIR/image:top.IMGFMT', fmt=IMGFMT size=67108864 backing_file=./image:base.IMGFMT backing_fmt=IMGFMT image: TEST_DIR/image:top.IMGFMT file format: IMGFMT virtual size: 64 MiB (67108864 bytes) backing file: ./image:base.IMGFMT (actual path: TEST_DIR/./image:base.IMGFMT) Formatting 'base.IMGFMT', fmt=IMGFMT size=67108864 -Formatting 'file:image:top.IMGFMT', fmt=IMGFMT size=67108864 backing_file=base.IMGFMT +Formatting 'file:image:top.IMGFMT', fmt=IMGFMT size=67108864 backing_file=base.IMGFMT backing_fmt=IMGFMT image: ./image:top.IMGFMT file format: IMGFMT virtual size: 64 MiB (67108864 bytes) diff --git a/tests/qemu-iotests/127 b/tests/qemu-iotests/127 index a4fc866038..e2ac2f5536 100755 --- a/tests/qemu-iotests/127 +++ b/tests/qemu-iotests/127 @@ -48,8 +48,8 @@ _require_devices virtio-scsi scsi-hd IMG_SIZE=64K _make_test_img $IMG_SIZE -TEST_IMG="$TEST_IMG.overlay0" _make_test_img -b "$TEST_IMG" $IMG_SIZE -TEST_IMG="$TEST_IMG.overlay1" _make_test_img -b "$TEST_IMG" $IMG_SIZE +TEST_IMG="$TEST_IMG.overlay0" _make_test_img -b "$TEST_IMG" -F $IMGFMT $IMG_SIZE +TEST_IMG="$TEST_IMG.overlay1" _make_test_img -b "$TEST_IMG" -F $IMGFMT $IMG_SIZE # So that we actually have something to mirror and the job does not return # immediately (which may be bad because then we cannot know whether the diff --git a/tests/qemu-iotests/127.out b/tests/qemu-iotests/127.out index 623d52bbd1..efd6cb327f 100644 --- a/tests/qemu-iotests/127.out +++ b/tests/qemu-iotests/127.out @@ -1,7 +1,7 @@ QA output created by 127 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536 -Formatting 'TEST_DIR/t.IMGFMT.overlay0', fmt=IMGFMT size=65536 backing_file=TEST_DIR/t.IMGFMT -Formatting 'TEST_DIR/t.IMGFMT.overlay1', fmt=IMGFMT size=65536 backing_file=TEST_DIR/t.IMGFMT +Formatting 'TEST_DIR/t.IMGFMT.overlay0', fmt=IMGFMT size=65536 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT.overlay1', fmt=IMGFMT size=65536 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT wrote 42/42 bytes at offset 0 42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } diff --git a/tests/qemu-iotests/129 b/tests/qemu-iotests/129 index b0da4a5541..0e13244d85 100755 --- a/tests/qemu-iotests/129 +++ b/tests/qemu-iotests/129 @@ -29,7 +29,8 @@ class TestStopWithBlockJob(iotests.QMPTestCase): def setUp(self): iotests.qemu_img('create', '-f', iotests.imgfmt, self.base_img, "1G") - iotests.qemu_img('create', '-f', iotests.imgfmt, self.test_img, "-b", self.base_img) + iotests.qemu_img('create', '-f', iotests.imgfmt, self.test_img, + "-b", self.base_img, '-F', iotests.imgfmt) iotests.qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 1M 128M', self.test_img) self.vm = iotests.VM().add_drive(self.test_img) self.vm.launch() diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133 index 6f7cacc091..4070fd9457 100755 --- a/tests/qemu-iotests/133 +++ b/tests/qemu-iotests/133 @@ -40,7 +40,7 @@ _supported_fmt qcow2 _supported_proto file TEST_IMG="$TEST_IMG.base" _make_test_img 64M -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT echo echo "=== Check that node-name can't be changed ===" diff --git a/tests/qemu-iotests/133.out b/tests/qemu-iotests/133.out index 1491ef45a9..d70c2e8041 100644 --- a/tests/qemu-iotests/133.out +++ b/tests/qemu-iotests/133.out @@ -1,6 +1,6 @@ QA output created by 133 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT === Check that node-name can't be changed === diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139 index 7120d3142b..1452fd24b3 100755 --- a/tests/qemu-iotests/139 +++ b/tests/qemu-iotests/139 @@ -71,7 +71,7 @@ class TestBlockdevDel(iotests.QMPTestCase): def addBlockDriverStateOverlay(self, node): self.checkBlockDriverState(node, False) iotests.qemu_img('create', '-u', '-f', iotests.imgfmt, - '-b', base_img, new_img, '1M') + '-b', base_img, '-F', iotests.imgfmt, new_img, '1M') opts = {'driver': iotests.imgfmt, 'node-name': node, 'backing': None, diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141 index 5192d256e3..21aa0b42d8 100755 --- a/tests/qemu-iotests/141 +++ b/tests/qemu-iotests/141 @@ -89,8 +89,8 @@ test_blockjob() TEST_IMG="$TEST_DIR/b.$IMGFMT" _make_test_img 1M -TEST_IMG="$TEST_DIR/m.$IMGFMT" _make_test_img -b "$TEST_DIR/b.$IMGFMT" 1M -_make_test_img -b "$TEST_DIR/m.$IMGFMT" 1M +TEST_IMG="$TEST_DIR/m.$IMGFMT" _make_test_img -b "$TEST_DIR/b.$IMGFMT" -F $IMGFMT 1M +_make_test_img -b "$TEST_DIR/m.$IMGFMT" 1M -F $IMGFMT _launch_qemu -nodefaults diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out index 263b680bdf..08e0aecd65 100644 --- a/tests/qemu-iotests/141.out +++ b/tests/qemu-iotests/141.out @@ -1,7 +1,7 @@ QA output created by 141 Formatting 'TEST_DIR/b.IMGFMT', fmt=IMGFMT size=1048576 -Formatting 'TEST_DIR/m.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/b.IMGFMT -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m.IMGFMT +Formatting 'TEST_DIR/m.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/b.IMGFMT backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m.IMGFMT backing_fmt=IMGFMT {'execute': 'qmp_capabilities'} {"return": {}} diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142 index daefcbaa58..69fd10ef51 100755 --- a/tests/qemu-iotests/142 +++ b/tests/qemu-iotests/142 @@ -67,7 +67,7 @@ size=128M TEST_IMG="$TEST_IMG.base" _make_test_img $size TEST_IMG="$TEST_IMG.snap" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" $size +_make_test_img -b "$TEST_IMG.base" $size -F $IMGFMT echo echo === Simple test for all cache modes === diff --git a/tests/qemu-iotests/142.out b/tests/qemu-iotests/142.out index 3667e38def..a92b948edd 100644 --- a/tests/qemu-iotests/142.out +++ b/tests/qemu-iotests/142.out @@ -1,7 +1,7 @@ QA output created by 142 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT.snap', fmt=IMGFMT size=134217728 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT === Simple test for all cache modes === diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 index 11e3d28841..34045ea3cf 100755 --- a/tests/qemu-iotests/153 +++ b/tests/qemu-iotests/153 @@ -94,7 +94,7 @@ for opts1 in "" "read-only=on" "read-only=on,force-share=on"; do echo echo "== Creating test image ==" - _make_test_img -b "${TEST_IMG}.base" + _make_test_img -b "${TEST_IMG}.base" -F $IMGFMT echo echo "== Launching QEMU, opts: '$opts1' ==" @@ -125,7 +125,7 @@ for opts1 in "" "read-only=on" "read-only=on,force-share=on"; do _run_cmd $QEMU_IMG amend -o "size=$size" $L "${TEST_IMG}" _run_cmd $QEMU_IMG commit $L "${TEST_IMG}" _run_cmd $QEMU_IMG resize $L "${TEST_IMG}" $size - _run_cmd $QEMU_IMG rebase $L "${TEST_IMG}" -b "${TEST_IMG}.base" + _run_cmd $QEMU_IMG rebase $L "${TEST_IMG}" -b "${TEST_IMG}.base" -F $IMGFMT _run_cmd $QEMU_IMG snapshot -l $L "${TEST_IMG}" _run_cmd $QEMU_IMG convert $L "${TEST_IMG}" "${TEST_IMG}.convert" _run_cmd $QEMU_IMG dd $L if="${TEST_IMG}" of="${TEST_IMG}.convert" bs=512 count=1 @@ -135,7 +135,7 @@ for opts1 in "" "read-only=on" "read-only=on,force-share=on"; do # qemu-img create does not support -U if [ -z "$L" ]; then _run_cmd $QEMU_IMG create -f $IMGFMT "${TEST_IMG}" \ - -b ${TEST_IMG}.base + -b ${TEST_IMG}.base -F $IMGFMT # Read the file format. It used to be the case that # file-posix simply truncated the file, but the qcow2 # driver then failed to format it because it was unable @@ -167,9 +167,9 @@ done echo echo "== Creating ${TEST_IMG}.[abc] ==" | _filter_testdir -$QEMU_IMG create -f qcow2 "${TEST_IMG}.a" -b "${TEST_IMG}" | _filter_img_create -$QEMU_IMG create -f qcow2 "${TEST_IMG}.b" -b "${TEST_IMG}" | _filter_img_create -$QEMU_IMG create -f qcow2 "${TEST_IMG}.c" -b "${TEST_IMG}.b" \ +$QEMU_IMG create -f qcow2 "${TEST_IMG}.a" -b "${TEST_IMG}" -F $IMGFMT | _filter_img_create +$QEMU_IMG create -f qcow2 "${TEST_IMG}.b" -b "${TEST_IMG}" -F $IMGFMT | _filter_img_create +$QEMU_IMG create -f qcow2 "${TEST_IMG}.c" -b "${TEST_IMG}.b" -F $IMGFMT \ | _filter_img_create echo @@ -218,7 +218,7 @@ _send_qemu_cmd $QEMU_HANDLE \ _run_cmd $QEMU_IO "${TEST_IMG}" -c 'write 0 512' echo "Creating overlay with qemu-img when the guest is running should be allowed" -_run_cmd $QEMU_IMG create -f $IMGFMT -b "${TEST_IMG}" "${TEST_IMG}.overlay" +_run_cmd $QEMU_IMG create -f $IMGFMT -b "${TEST_IMG}" -F $IMGFMT "${TEST_IMG}.overlay" echo "== Closing an image should unlock it ==" _send_qemu_cmd $QEMU_HANDLE \ diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out index b2a90caa6b..8a79e1ee87 100644 --- a/tests/qemu-iotests/153.out +++ b/tests/qemu-iotests/153.out @@ -6,7 +6,7 @@ QEMU_PROG: -drive if=none,file=null-co://,readonly=off,force-share=on: force-sha Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=33554432 == Creating test image == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT == Launching QEMU, opts: '' == @@ -68,7 +68,7 @@ _qemu_img_wrapper resize TEST_DIR/t.qcow2 32M qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? -_qemu_img_wrapper rebase TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base +_qemu_img_wrapper rebase TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2 qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? @@ -92,10 +92,11 @@ _qemu_img_wrapper bench -w -c 1 TEST_DIR/t.qcow2 qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? -_qemu_img_wrapper create -f qcow2 TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base +_qemu_img_wrapper create -f qcow2 TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2 qemu-img: TEST_DIR/t.qcow2: Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? file format: IMGFMT +backing file format: IMGFMT == Running utility commands -U == @@ -130,7 +131,7 @@ _qemu_img_wrapper resize -U TEST_DIR/t.qcow2 32M qemu-img: unrecognized option '-U' Try 'qemu-img --help' for more information -_qemu_img_wrapper rebase -U TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base +_qemu_img_wrapper rebase -U TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2 qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? @@ -152,7 +153,7 @@ Round done Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=33554432 == Creating test image == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT == Launching QEMU, opts: 'read-only=on' == @@ -199,7 +200,7 @@ _qemu_img_wrapper resize TEST_DIR/t.qcow2 32M qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? -_qemu_img_wrapper rebase TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base +_qemu_img_wrapper rebase TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2 qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? @@ -215,10 +216,11 @@ _qemu_img_wrapper bench -w -c 1 TEST_DIR/t.qcow2 qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? -_qemu_img_wrapper create -f qcow2 TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base +_qemu_img_wrapper create -f qcow2 TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2 qemu-img: TEST_DIR/t.qcow2: Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? file format: IMGFMT +backing file format: IMGFMT == Running utility commands -U == @@ -253,7 +255,7 @@ _qemu_img_wrapper resize -U TEST_DIR/t.qcow2 32M qemu-img: unrecognized option '-U' Try 'qemu-img --help' for more information -_qemu_img_wrapper rebase -U TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base +_qemu_img_wrapper rebase -U TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2 qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? @@ -275,7 +277,7 @@ Round done Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=33554432 == Creating test image == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT == Launching QEMU, opts: 'read-only=on,force-share=on' == @@ -309,7 +311,7 @@ _qemu_img_wrapper commit TEST_DIR/t.qcow2 _qemu_img_wrapper resize TEST_DIR/t.qcow2 32M -_qemu_img_wrapper rebase TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base +_qemu_img_wrapper rebase TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2 _qemu_img_wrapper snapshot -l TEST_DIR/t.qcow2 @@ -321,8 +323,9 @@ _qemu_img_wrapper bench -c 1 TEST_DIR/t.qcow2 _qemu_img_wrapper bench -w -c 1 TEST_DIR/t.qcow2 -_qemu_img_wrapper create -f qcow2 TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base +_qemu_img_wrapper create -f qcow2 TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2 file format: IMGFMT +backing file format: IMGFMT == Running utility commands -U == @@ -357,7 +360,7 @@ _qemu_img_wrapper resize -U TEST_DIR/t.qcow2 32M qemu-img: unrecognized option '-U' Try 'qemu-img --help' for more information -_qemu_img_wrapper rebase -U TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base +_qemu_img_wrapper rebase -U TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2 _qemu_img_wrapper snapshot -l -U TEST_DIR/t.qcow2 @@ -398,9 +401,9 @@ Is another process using the image [TEST_DIR/t.qcow2]? == Two devices with the same image (read-only=on,force-share=on - read-only=on,force-share=on) == == Creating TEST_DIR/t.qcow2.[abc] == -Formatting 'TEST_DIR/t.IMGFMT.a', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT -Formatting 'TEST_DIR/t.IMGFMT.b', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT -Formatting 'TEST_DIR/t.IMGFMT.c', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.b +Formatting 'TEST_DIR/t.IMGFMT.a', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT.b', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT.c', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.b backing_fmt=IMGFMT == Two devices sharing the same file in backing chain == @@ -430,7 +433,7 @@ qemu-io: can't open device TEST_DIR/t.qcow2: Failed to get "write" lock Is another process using the image [TEST_DIR/t.qcow2]? Creating overlay with qemu-img when the guest is running should be allowed -_qemu_img_wrapper create -f qcow2 -b TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.overlay +_qemu_img_wrapper create -f qcow2 -b TEST_DIR/t.qcow2 -F qcow2 TEST_DIR/t.qcow2.overlay == Closing an image should unlock it == { 'execute': 'human-monitor-command', 'arguments': { 'command-line': 'drive_del d0' } } {"return": ""} diff --git a/tests/qemu-iotests/154 b/tests/qemu-iotests/154 index d68f66b9e0..7f1c0d9bd9 100755 --- a/tests/qemu-iotests/154 +++ b/tests/qemu-iotests/154 @@ -50,7 +50,7 @@ echo echo == backing file contains zeros == CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # Make sure that the whole cluster is allocated even for partial write_zeroes # when the backing file contains zeros @@ -74,7 +74,7 @@ echo echo == backing file contains non-zero data before write_zeroes == CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # Single cluster; non-zero data at the cluster start # ... | XX -- 00 -- | ... @@ -97,7 +97,7 @@ echo echo == backing file contains non-zero data after write_zeroes == CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # Single cluster; non-zero data directly after request # ... | -- 00 XX -- | ... @@ -120,7 +120,7 @@ echo echo == write_zeroes covers non-zero data == CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # non-zero data at front of request # Backing file: -- XX -- -- @@ -160,7 +160,7 @@ echo echo == spanning two clusters, non-zero before request == CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # Two clusters; non-zero data before request: # 1. At cluster start: 32k: XX -- -- 00 | 00 -- -- -- @@ -190,7 +190,7 @@ echo echo == spanning two clusters, non-zero after request == CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # Two clusters; non-zero data after request: # 1. Directly after request: 32k: -- -- -- 00 | 00 XX -- -- @@ -220,7 +220,7 @@ echo echo == spanning two clusters, partially overwriting backing file == CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # Backing file: -- -- XX XX | XX XX -- -- # Active layer: -- -- XX 00 | 00 XX -- -- @@ -239,7 +239,7 @@ echo echo == spanning multiple clusters, non-zero in first cluster == CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # Backing file: 64k: XX XX -- -- | -- -- -- -- | -- -- -- -- # Active layer: 64k: XX XX 00 00 | 00 00 00 00 | 00 -- -- -- @@ -255,7 +255,7 @@ echo echo == spanning multiple clusters, non-zero in intermediate cluster == CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # Backing file: 64k: -- -- -- -- | -- XX XX -- | -- -- -- -- # Active layer: 64k: -- -- 00 00 | 00 00 00 00 | 00 -- -- -- @@ -270,7 +270,7 @@ echo echo == spanning multiple clusters, non-zero in final cluster == CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # Backing file: 64k: -- -- -- -- | -- -- -- -- | -- -- XX XX # Active layer: 64k: -- -- 00 00 | 00 00 00 00 | 00 -- XX XX @@ -286,7 +286,7 @@ echo echo == spanning multiple clusters, partially overwriting backing file == CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $size -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # Backing file: 64k: -- XX XX XX | XX XX XX XX | XX XX XX -- # Active layer: 64k: -- XX 00 00 | 00 00 00 00 | 00 XX XX -- @@ -338,7 +338,7 @@ CLUSTER_SIZE=2048 TEST_IMG="$TEST_IMG.base" _make_test_img $((size + 1024)) # Write at the front: sector-wise, the request is: # backing: 128m... | -- -- # active: 128m... | 00 -- -- -- -_make_test_img -b "$TEST_IMG.base" $((size + 2048)) +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $((size + 2048)) $QEMU_IO -c "write -z $size 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "alloc $size 2048" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map @@ -346,7 +346,7 @@ $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map # Write at the back: sector-wise, the request is: # backing: 128m... | -- -- # active: 128m... | -- -- -- 00 -_make_test_img -b "$TEST_IMG.base" $((size + 2048)) +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $((size + 2048)) $QEMU_IO -c "write -z $((size + 1536)) 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "alloc $size 2048" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map @@ -354,7 +354,7 @@ $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map # Write at middle: sector-wise, the request is: # backing: 128m... | -- -- # active: 128m... | -- 00 00 -- -_make_test_img -b "$TEST_IMG.base" $((size + 2048)) +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $((size + 2048)) $QEMU_IO -c "write -z $((size + 512)) 1024" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "alloc $size 2048" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map @@ -362,7 +362,7 @@ $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map # Write entire cluster: sector-wise, the request is: # backing: 128m... | -- -- # active: 128m... | 00 00 00 00 -_make_test_img -b "$TEST_IMG.base" $((size + 2048)) +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $((size + 2048)) $QEMU_IO -c "write -z $size 2048" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "alloc $size 2048" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map @@ -373,7 +373,7 @@ $QEMU_IO -c "write -z $size 512" "$TEST_IMG.base" | _filter_qemu_io # Write at the front: sector-wise, the request is: # backing: 128m... | 00 00 # active: 128m... | 00 -- -- -- -_make_test_img -b "$TEST_IMG.base" $((size + 2048)) +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $((size + 2048)) $QEMU_IO -c "write -z $size 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "alloc $size 2048" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map @@ -381,7 +381,7 @@ $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map # Write at the back: sector-wise, the request is: # backing: 128m... | 00 00 # active: 128m... | -- -- -- 00 -_make_test_img -b "$TEST_IMG.base" $((size + 2048)) +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $((size + 2048)) $QEMU_IO -c "write -z $((size + 1536)) 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "alloc $size 2048" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map @@ -389,7 +389,7 @@ $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map # Write at middle: sector-wise, the request is: # backing: 128m... | 00 00 # active: 128m... | -- 00 00 -- -_make_test_img -b "$TEST_IMG.base" $((size + 2048)) +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $((size + 2048)) $QEMU_IO -c "write -z $((size + 512)) 1024" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "alloc $size 2048" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map @@ -397,7 +397,7 @@ $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map # Write entire cluster: sector-wise, the request is: # backing: 128m... | 00 00 # active: 128m... | 00 00 00 00 -_make_test_img -b "$TEST_IMG.base" $((size + 2048)) +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $((size + 2048)) $QEMU_IO -c "write -z $size 2048" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "alloc $size 2048" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map @@ -427,7 +427,7 @@ echo == unaligned image tail cluster, allocation required == # Backing file: 128m... | XX -- # Active layer: 128m... | -- -- 00 -- CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $((size + 1024)) -_make_test_img -b "$TEST_IMG.base" $((size + 2048)) +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $((size + 2048)) $QEMU_IO -c "write -P 1 $((size)) 512" "$TEST_IMG.base" | _filter_qemu_io $QEMU_IO -c "write -z $((size + 1024)) 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "read -P 1 $((size)) 512" "$TEST_IMG" | _filter_qemu_io @@ -438,7 +438,7 @@ $QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map # Backing file: 128m: ... | -- XX # Active layer: 128m: ... | 00 -- -- 00 CLUSTER_SIZE=512 TEST_IMG="$TEST_IMG.base" _make_test_img $((size + 1024)) -_make_test_img -b "$TEST_IMG.base" $((size + 2048)) +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $((size + 2048)) $QEMU_IO -c "write -P 1 $((size + 512)) 512" "$TEST_IMG.base" | _filter_qemu_io $QEMU_IO -c "write -z $((size)) 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "read -P 0 $((size)) 512" "$TEST_IMG" | _filter_qemu_io diff --git a/tests/qemu-iotests/154.out b/tests/qemu-iotests/154.out index fa3673317f..4863e24838 100644 --- a/tests/qemu-iotests/154.out +++ b/tests/qemu-iotests/154.out @@ -2,7 +2,7 @@ QA output created by 154 == backing file contains zeros == 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 2048/2048 bytes at offset 0 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2048/2048 bytes at offset 10240 @@ -22,7 +22,7 @@ wrote 2048/2048 bytes at offset 27648 == backing file contains non-zero data before write_zeroes == 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 1024/1024 bytes at offset 32768 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1024/1024 bytes at offset 34816 @@ -49,7 +49,7 @@ read 2048/2048 bytes at offset 67584 == backing file contains non-zero data after write_zeroes == 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 1024/1024 bytes at offset 34816 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1024/1024 bytes at offset 33792 @@ -76,7 +76,7 @@ read 3072/3072 bytes at offset 40960 == write_zeroes covers non-zero data == 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 1024/1024 bytes at offset 5120 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2048/2048 bytes at offset 5120 @@ -113,7 +113,7 @@ read 4096/4096 bytes at offset 28672 == spanning two clusters, non-zero before request == 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 1024/1024 bytes at offset 32768 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2048/2048 bytes at offset 35840 @@ -155,7 +155,7 @@ read 5120/5120 bytes at offset 68608 == spanning two clusters, non-zero after request == 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 1024/1024 bytes at offset 37888 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2048/2048 bytes at offset 35840 @@ -197,7 +197,7 @@ read 1024/1024 bytes at offset 72704 == spanning two clusters, partially overwriting 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 4096/4096 bytes at offset 2048 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2048/2048 bytes at offset 3072 @@ -217,7 +217,7 @@ read 2048/2048 bytes at offset 6144 == spanning multiple clusters, non-zero in first cluster == 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 2048/2048 bytes at offset 65536 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 7168/7168 bytes at offset 67584 @@ -233,7 +233,7 @@ read 10240/10240 bytes at offset 67584 == spanning multiple clusters, non-zero in intermediate cluster == 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 2048/2048 bytes at offset 70656 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 7168/7168 bytes at offset 67584 @@ -246,7 +246,7 @@ read 12288/12288 bytes at offset 65536 == spanning multiple clusters, non-zero in final cluster == 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 2048/2048 bytes at offset 75776 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 7168/7168 bytes at offset 67584 @@ -262,7 +262,7 @@ read 2048/2048 bytes at offset 75776 == spanning multiple clusters, partially overwriting 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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 10240/10240 bytes at offset 66560 10 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 7168/7168 bytes at offset 67584 @@ -305,25 +305,25 @@ wrote 2048/2048 bytes at offset 134217728 2048/2048 bytes allocated at offset 128 MiB [{ "start": 0, "length": 134219776, "depth": 0, "zero": true, "data": false}] Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 134217728 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB [{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, { "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 134219264 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB [{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, { "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 1024/1024 bytes at offset 134218240 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB [{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, { "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 2048/2048 bytes at offset 134217728 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB @@ -331,25 +331,25 @@ wrote 2048/2048 bytes at offset 134217728 { "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] wrote 512/512 bytes at offset 134217728 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 134217728 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB [{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, { "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 134219264 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB [{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, { "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 1024/1024 bytes at offset 134218240 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB [{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, { "start": 134217728, "length": 2048, "depth": 0, "zero": true, "data": false}] -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 2048/2048 bytes at offset 134217728 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 2048/2048 bytes allocated at offset 128 MiB @@ -377,7 +377,7 @@ read 1024/1024 bytes at offset 134217728 == unaligned image tail cluster, allocation required == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 134217728 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 512/512 bytes at offset 134218752 @@ -389,7 +389,7 @@ read 1536/1536 bytes at offset 134218240 [{ "start": 0, "length": 134217728, "depth": 1, "zero": true, "data": false}, { "start": 134217728, "length": 2048, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 512/512 bytes at offset 134218240 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 512/512 bytes at offset 134217728 diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155 index cb371d4649..988f986144 100755 --- a/tests/qemu-iotests/155 +++ b/tests/qemu-iotests/155 @@ -60,9 +60,12 @@ class BaseClass(iotests.QMPTestCase): def setUp(self): qemu_img('create', '-f', iotests.imgfmt, back0_img, '1440K') - qemu_img('create', '-f', iotests.imgfmt, '-b', back0_img, back1_img) - qemu_img('create', '-f', iotests.imgfmt, '-b', back1_img, back2_img) - qemu_img('create', '-f', iotests.imgfmt, '-b', back2_img, source_img) + qemu_img('create', '-f', iotests.imgfmt, '-b', back0_img, + '-F', iotests.imgfmt, back1_img) + qemu_img('create', '-f', iotests.imgfmt, '-b', back1_img, + '-F', iotests.imgfmt, back2_img) + qemu_img('create', '-f', iotests.imgfmt, '-b', back2_img, + '-F', iotests.imgfmt, source_img) self.vm = iotests.VM() # Add the BDS via blockdev-add so it stays around after the mirror block @@ -89,7 +92,8 @@ class BaseClass(iotests.QMPTestCase): if self.existing: if self.target_backing: qemu_img('create', '-f', iotests.imgfmt, - '-b', self.target_backing, target_img, '1440K') + '-b', self.target_backing, '-F', 'raw', + target_img, '1440K') else: qemu_img('create', '-f', iotests.imgfmt, target_img, '1440K') diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 index 5559df63a5..7c69a6c3fa 100755 --- a/tests/qemu-iotests/156 +++ b/tests/qemu-iotests/156 @@ -56,7 +56,7 @@ _unsupported_imgopts data_file # Create source disk TEST_IMG="$TEST_IMG.backing" _make_test_img 1M -_make_test_img -b "$TEST_IMG.backing" 1M +_make_test_img -b "$TEST_IMG.backing" -F $IMGFMT 1M $QEMU_IO -c 'write -P 1 0 256k' "$TEST_IMG.backing" | _filter_qemu_io $QEMU_IO -c 'write -P 2 64k 192k' "$TEST_IMG" | _filter_qemu_io @@ -68,7 +68,7 @@ _send_qemu_cmd $QEMU_HANDLE \ 'return' # Create snapshot -TEST_IMG="$TEST_IMG.overlay" _make_test_img -u -b "$TEST_IMG" 1M +TEST_IMG="$TEST_IMG.overlay" _make_test_img -u -b "$TEST_IMG" -F $IMGFMT 1M _send_qemu_cmd $QEMU_HANDLE \ "{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'source', @@ -85,7 +85,8 @@ _send_qemu_cmd $QEMU_HANDLE \ 'return' # Create target image -TEST_IMG="$TEST_IMG.target.overlay" _make_test_img -u -b "$TEST_IMG.target" 1M +TEST_IMG="$TEST_IMG.target.overlay" _make_test_img -u -b "$TEST_IMG.target" \ + -F $IMGFMT 1M # Mirror snapshot _send_qemu_cmd $QEMU_HANDLE \ @@ -111,7 +112,7 @@ _send_qemu_cmd $QEMU_HANDLE \ # Copy source backing chain to the target before completing the job cp "$TEST_IMG.backing" "$TEST_IMG.target.backing" cp "$TEST_IMG" "$TEST_IMG.target" -$QEMU_IMG rebase -u -b "$TEST_IMG.target.backing" "$TEST_IMG.target" +$QEMU_IMG rebase -u -b "$TEST_IMG.target.backing" -F $IMGFMT "$TEST_IMG.target" # Complete block job _send_qemu_cmd $QEMU_HANDLE \ diff --git a/tests/qemu-iotests/156.out b/tests/qemu-iotests/156.out index 084be5ad71..cce167b63f 100644 --- a/tests/qemu-iotests/156.out +++ b/tests/qemu-iotests/156.out @@ -1,20 +1,20 @@ QA output created by 156 Formatting 'TEST_DIR/t.IMGFMT.backing', fmt=IMGFMT size=1048576 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.backing +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.backing backing_fmt=IMGFMT wrote 262144/262144 bytes at offset 0 256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 196608/196608 bytes at offset 65536 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } {"return": {}} -Formatting 'TEST_DIR/t.IMGFMT.overlay', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT +Formatting 'TEST_DIR/t.IMGFMT.overlay', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT { 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'source', 'snapshot-file': 'TEST_DIR/t.IMGFMT.overlay', 'format': 'IMGFMT', 'mode': 'existing' } } {"return": {}} { 'execute': 'human-monitor-command', 'arguments': { 'command-line': 'qemu-io source "write -P 3 128k 128k"' } } wrote 131072/131072 bytes at offset 131072 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) {"return": ""} -Formatting 'TEST_DIR/t.IMGFMT.target.overlay', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.target +Formatting 'TEST_DIR/t.IMGFMT.target.overlay', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.target backing_fmt=IMGFMT { 'execute': 'drive-mirror', 'arguments': { 'device': 'source', 'target': 'TEST_DIR/t.IMGFMT.target.overlay', 'mode': 'existing', 'sync': 'top' } } {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "source"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "source"}} diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158 index ba4db6116a..3175968e2b 100755 --- a/tests/qemu-iotests/158 +++ b/tests/qemu-iotests/158 @@ -64,7 +64,7 @@ echo "== verify pattern ==" $QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir echo "== create overlay ==" -_make_test_img -u --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" -b "$TEST_IMG_BASE" $size +_make_test_img -u --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" -b "$TEST_IMG_BASE" -F $IMGFMT $size echo echo "== writing part of a cluster ==" diff --git a/tests/qemu-iotests/158.out b/tests/qemu-iotests/158.out index f28a17626b..83f19699bb 100644 --- a/tests/qemu-iotests/158.out +++ b/tests/qemu-iotests/158.out @@ -10,7 +10,7 @@ wrote 134217728/134217728 bytes at offset 0 read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == create overlay == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT encryption=on == writing part of a cluster == wrote 1024/1024 bytes at offset 0 diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161 index f572a19af2..e270976d87 100755 --- a/tests/qemu-iotests/161 +++ b/tests/qemu-iotests/161 @@ -49,8 +49,8 @@ IMG_SIZE=1M # Create the images TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE | _filter_imgfmt -TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base" | _filter_imgfmt -_make_test_img -b "$TEST_IMG.int" | _filter_imgfmt +TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base" -F $IMGFMT | _filter_imgfmt +_make_test_img -b "$TEST_IMG.int" -F $IMGFMT -F $IMGFMT | _filter_imgfmt # First test: reopen $TEST.IMG changing the detect-zeroes option on # its backing file ($TEST_IMG.int). @@ -106,8 +106,8 @@ echo "*** Commit and then change an option on the backing file" echo # Create the images again TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE | _filter_imgfmt -TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base" | _filter_imgfmt -_make_test_img -b "$TEST_IMG.int" | _filter_imgfmt +TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base" -F $IMGFMT| _filter_imgfmt +_make_test_img -b "$TEST_IMG.int" -F $IMGFMT | _filter_imgfmt _launch_qemu -drive if=none,file="${TEST_IMG}" _send_qemu_cmd $QEMU_HANDLE \ diff --git a/tests/qemu-iotests/161.out b/tests/qemu-iotests/161.out index aef9741ed3..3d8d89a9da 100644 --- a/tests/qemu-iotests/161.out +++ b/tests/qemu-iotests/161.out @@ -1,7 +1,7 @@ QA output created by 161 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576 -Formatting 'TEST_DIR/t.IMGFMT.int', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.int +Formatting 'TEST_DIR/t.IMGFMT.int', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.int backing_fmt=IMGFMT *** Change an option on the backing file @@ -29,8 +29,8 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. *** Commit and then change an option on the backing file Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576 -Formatting 'TEST_DIR/t.IMGFMT.int', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.int +Formatting 'TEST_DIR/t.IMGFMT.int', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.int backing_fmt=IMGFMT { 'execute': 'qmp_capabilities' } {"return": {}} { 'execute': 'block-commit', 'arguments': { 'device': 'none0', 'top': 'TEST_DIR/t.IMGFMT.int' } } diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176 index 117c8b6954..2565ff12ee 100755 --- a/tests/qemu-iotests/176 +++ b/tests/qemu-iotests/176 @@ -84,8 +84,8 @@ echo len=$((2100 * 1024 * 1024 + 512)) # larger than 2G, and not cluster aligned TEST_IMG="$TEST_IMG.base" _make_test_img $len -TEST_IMG="$TEST_IMG.itmd" _make_test_img -b "$TEST_IMG.base" $len -_make_test_img -b "$TEST_IMG.itmd" $len +TEST_IMG="$TEST_IMG.itmd" _make_test_img -b "$TEST_IMG.base" -F $IMGFMT $len +_make_test_img -b "$TEST_IMG.itmd" -F $IMGFMT $len # Update the top image to use a feature that is incompatible with fast path case $reason in snapshot) $QEMU_IMG snapshot -c snap "$TEST_IMG" ;; diff --git a/tests/qemu-iotests/176.out b/tests/qemu-iotests/176.out index cc33def96b..9d09b60452 100644 --- a/tests/qemu-iotests/176.out +++ b/tests/qemu-iotests/176.out @@ -3,8 +3,8 @@ QA output created by 176 === Test pass snapshot.0 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT wrote 196608/196608 bytes at offset 2147287040 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 131072/131072 bytes at offset 2147352576 @@ -43,8 +43,8 @@ ID TAG === Test pass snapshot.1 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT wrote 196608/196608 bytes at offset 2147287040 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 131072/131072 bytes at offset 2147352576 @@ -84,8 +84,8 @@ ID TAG === Test pass snapshot.2 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT wrote 196608/196608 bytes at offset 2147287040 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 131072/131072 bytes at offset 2147352576 @@ -125,8 +125,8 @@ ID TAG === Test pass snapshot.3 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT wrote 196608/196608 bytes at offset 2147287040 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 131072/131072 bytes at offset 2147352576 @@ -163,8 +163,8 @@ ID TAG === Test pass bitmap.0 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT QMP_VERSION {"return": {}} {"return": {}} @@ -212,8 +212,8 @@ QMP_VERSION === Test pass bitmap.1 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT QMP_VERSION {"return": {}} {"return": {}} @@ -262,8 +262,8 @@ QMP_VERSION === Test pass bitmap.2 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT QMP_VERSION {"return": {}} {"return": {}} @@ -312,8 +312,8 @@ QMP_VERSION === Test pass bitmap.3 === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112 -Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd +Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd backing_fmt=IMGFMT QMP_VERSION {"return": {}} {"return": {}} diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177 index eadc2c7ef6..5d4a77a6ab 100755 --- a/tests/qemu-iotests/177 +++ b/tests/qemu-iotests/177 @@ -51,7 +51,7 @@ echo "== setting up files ==" TEST_IMG="$TEST_IMG.base" _make_test_img $size $QEMU_IO -c "write -P 11 0 $size" "$TEST_IMG.base" | _filter_qemu_io -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $QEMU_IO -c "write -P 22 0 $size" "$TEST_IMG" | _filter_qemu_io # Limited to 64k max-transfer diff --git a/tests/qemu-iotests/177.out b/tests/qemu-iotests/177.out index e887542678..ba1e1e212e 100644 --- a/tests/qemu-iotests/177.out +++ b/tests/qemu-iotests/177.out @@ -4,7 +4,7 @@ QA output created by 177 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 wrote 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/179 b/tests/qemu-iotests/179 index 9372dc30ef..11a20cb1bf 100755 --- a/tests/qemu-iotests/179 +++ b/tests/qemu-iotests/179 @@ -49,7 +49,7 @@ echo '=== Testing write zeroes with unmap ===' echo TEST_IMG="$TEST_IMG.base" _make_test_img 64M -_make_test_img -b "$TEST_IMG.base" +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT # Offsets chosen at or near 2M boundaries so test works at all cluster sizes # 8k and larger (smaller clusters fail due to non-contiguous allocations) diff --git a/tests/qemu-iotests/179.out b/tests/qemu-iotests/179.out index 80722b2289..1f7680002c 100644 --- a/tests/qemu-iotests/179.out +++ b/tests/qemu-iotests/179.out @@ -3,7 +3,7 @@ QA output created by 179 === Testing write zeroes with unmap === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT wrote 2097152/2097152 bytes at offset 2097152 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2097152/2097152 bytes at offset 6291456 diff --git a/tests/qemu-iotests/189 b/tests/qemu-iotests/189 index e6a84b8a3b..3e5ded14c6 100755 --- a/tests/qemu-iotests/189 +++ b/tests/qemu-iotests/189 @@ -66,7 +66,7 @@ echo "== verify pattern ==" $QEMU_IO --object $SECRET0 -c "read -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir echo "== create overlay ==" -_make_test_img --object $SECRET1 -o "encrypt.format=luks,encrypt.key-secret=sec1,encrypt.iter-time=10" -u -b "$TEST_IMG_BASE" $size +_make_test_img --object $SECRET1 -o "encrypt.format=luks,encrypt.key-secret=sec1,encrypt.iter-time=10" -u -b "$TEST_IMG_BASE" -F $IMGFMT $size echo echo "== writing part of a cluster ==" diff --git a/tests/qemu-iotests/189.out b/tests/qemu-iotests/189.out index bc213cbe14..30af0a8608 100644 --- a/tests/qemu-iotests/189.out +++ b/tests/qemu-iotests/189.out @@ -10,7 +10,7 @@ wrote 16777216/16777216 bytes at offset 0 read 16777216/16777216 bytes at offset 0 16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == create overlay == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT == writing part of a cluster == wrote 1024/1024 bytes at offset 0 diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191 index b05db68141..d17462e1e4 100755 --- a/tests/qemu-iotests/191 +++ b/tests/qemu-iotests/191 @@ -54,8 +54,8 @@ echo TEST_IMG="${TEST_IMG}.base" _make_test_img $size TEST_IMG="${TEST_IMG}.mid" _make_test_img -o "backing_fmt=$IMGFMT" -b "${TEST_IMG}.base" -_make_test_img -b "${TEST_IMG}.mid" -TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid" +_make_test_img -b "${TEST_IMG}.mid" -F $IMGFMT +TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid" -F $IMGFMT $QEMU_IO -c 'write -P 0x55 1M 64k' "${TEST_IMG}.mid" | _filter_qemu_io @@ -102,10 +102,10 @@ echo === Preparing and starting VM with -drive === echo TEST_IMG="${TEST_IMG}.base" _make_test_img $size -TEST_IMG="${TEST_IMG}.mid" _make_test_img -b "${TEST_IMG}.base" -_make_test_img -b "${TEST_IMG}.mid" -TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid" -TEST_IMG="${TEST_IMG}.ovl3" _make_test_img -b "${TEST_IMG}.ovl2" +TEST_IMG="${TEST_IMG}.mid" _make_test_img -b "${TEST_IMG}.base" -F $IMGFMT +_make_test_img -b "${TEST_IMG}.mid" -F $IMGFMT +TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid" -F $IMGFMT +TEST_IMG="${TEST_IMG}.ovl3" _make_test_img -b "${TEST_IMG}.ovl2" -F $IMGFMT $QEMU_IO -c 'write -P 0x55 1M 64k' "${TEST_IMG}.mid" | _filter_qemu_io diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out index 34cec7b9ec..11aaf3b691 100644 --- a/tests/qemu-iotests/191.out +++ b/tests/qemu-iotests/191.out @@ -4,8 +4,8 @@ QA output created by 191 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid -Formatting 'TEST_DIR/t.IMGFMT.ovl2', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT.ovl2', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid backing_fmt=IMGFMT wrote 65536/65536 bytes at offset 1048576 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } @@ -413,10 +413,10 @@ backing file format: IMGFMT === Preparing and starting VM with -drive === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid -Formatting 'TEST_DIR/t.IMGFMT.ovl2', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid -Formatting 'TEST_DIR/t.IMGFMT.ovl3', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.ovl2 +Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT.ovl2', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT.ovl3', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.ovl2 backing_fmt=IMGFMT wrote 65536/65536 bytes at offset 1048576 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { 'execute': 'qmp_capabilities' } diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195 index 48984b7ac1..2351d55fe1 100755 --- a/tests/qemu-iotests/195 +++ b/tests/qemu-iotests/195 @@ -56,8 +56,8 @@ run_qemu() size=64M TEST_IMG="$TEST_IMG.base" _make_test_img $size -TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" -_make_test_img -b "$TEST_IMG.mid" +TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" -F $IMGFMT +_make_test_img -b "$TEST_IMG.mid" -F $IMGFMT echo echo "Change backing file of mid (opened read-only)" @@ -75,7 +75,7 @@ echo echo "Change backing file of top (opened writable)" echo -TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" +TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" -F $IMGFMT run_qemu -drive if=none,file="$TEST_IMG",node-name=top < {:s}, {:s}'.format( image, reference, diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267 index 3146273eef..e44be49c77 100755 --- a/tests/qemu-iotests/267 +++ b/tests/qemu-iotests/267 @@ -73,7 +73,7 @@ size=128M run_test() { if [ -n "$BACKING_FILE" ]; then - _make_test_img -b "$BACKING_FILE" $size + _make_test_img -b "$BACKING_FILE" -F $IMGFMT $size else _make_test_img $size fi @@ -149,7 +149,7 @@ echo echo "=== -blockdev with NBD server on the backing file ===" echo -_make_test_img -b "$TEST_IMG.base" $size +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $size cat < None: iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, str(size_long)) - iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid, - str(size_short)) - iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top, - str(size_long)) + iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, + '-F', iotests.imgfmt, mid, str(size_short)) + iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, + '-F', iotests.imgfmt, top, str(size_long)) iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base) @@ -139,8 +139,8 @@ with iotests.FilePath('base') as base, \ iotests.log('=== preallocation=%s ===' % prealloc) iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size) - iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top, - top_size_old) + iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, + '-F', iotests.imgfmt, top, top_size_old) iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base) # After this, top_size_old to base_size should be allocated/zeroed. diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out index d248a1e21b..3a36fe7dfd 100644 --- a/tests/qemu-iotests/274.out +++ b/tests/qemu-iotests/274.out @@ -1,9 +1,9 @@ == Commit tests == Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 wrote 2097152/2097152 bytes at offset 0 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -50,6 +50,7 @@ file format: IMGFMT virtual size: 2 MiB (2097152 bytes) cluster_size: 65536 backing file: TEST_DIR/PID-base +backing file format: IMGFMT Format specific information: compat: 1.1 compression type: zlib @@ -66,9 +67,9 @@ read 1048576/1048576 bytes at offset 1048576 === Testing HMP commit (top -> mid) === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 wrote 2097152/2097152 bytes at offset 0 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -80,6 +81,7 @@ file format: IMGFMT virtual size: 2 MiB (2097152 bytes) cluster_size: 65536 backing file: TEST_DIR/PID-base +backing file format: IMGFMT Format specific information: compat: 1.1 compression type: zlib @@ -96,9 +98,9 @@ read 1048576/1048576 bytes at offset 1048576 === Testing QMP active commit (top -> mid) === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 wrote 2097152/2097152 bytes at offset 0 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -116,6 +118,7 @@ file format: IMGFMT virtual size: 2 MiB (2097152 bytes) cluster_size: 65536 backing file: TEST_DIR/PID-base +backing file format: IMGFMT Format specific information: compat: 1.1 compression type: zlib @@ -133,7 +136,7 @@ read 1048576/1048576 bytes at offset 1048576 === preallocation=off === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=6442450944 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1073741824 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1073741824 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 5368709120 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -152,7 +155,7 @@ read 65536/65536 bytes at offset 5368709120 === preallocation=metadata === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=34359738368 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=32212254720 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=32212254720 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 33285996544 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -176,7 +179,7 @@ read 65536/65536 bytes at offset 33285996544 === preallocation=falloc === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=10485760 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=5242880 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=5242880 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 9437184 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -195,7 +198,7 @@ read 65536/65536 bytes at offset 9437184 === preallocation=full === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=16777216 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=8388608 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=8388608 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 11534336 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -214,7 +217,7 @@ read 65536/65536 bytes at offset 11534336 === preallocation=off === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=393216 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=259072 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=259072 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 259072 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -234,7 +237,7 @@ read 65536/65536 bytes at offset 259072 === preallocation=off === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=409600 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 344064 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -253,7 +256,7 @@ read 65536/65536 bytes at offset 344064 === preallocation=off === Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=524288 lazy_refcounts=off refcount_bits=16 -Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16 wrote 65536/65536 bytes at offset 446464 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/279 b/tests/qemu-iotests/279 index 75a4747e6b..5515d4ed01 100755 --- a/tests/qemu-iotests/279 +++ b/tests/qemu-iotests/279 @@ -42,8 +42,8 @@ _unsupported_imgopts "subformat=monolithicFlat" \ "subformat=twoGbMaxExtentFlat" \ TEST_IMG="$TEST_IMG.base" _make_test_img 64M -TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" -_make_test_img -b "$TEST_IMG.mid" +TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" -F $IMGFMT +_make_test_img -b "$TEST_IMG.mid" -F $IMGFMT echo echo '== qemu-img info --backing-chain ==' diff --git a/tests/qemu-iotests/279.out b/tests/qemu-iotests/279.out index f4dc6c69cb..adb2e47a1a 100644 --- a/tests/qemu-iotests/279.out +++ b/tests/qemu-iotests/279.out @@ -1,7 +1,7 @@ QA output created by 279 Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid +Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid backing_fmt=IMGFMT == qemu-img info --backing-chain == image: TEST_DIR/t.IMGFMT diff --git a/tests/qemu-iotests/290 b/tests/qemu-iotests/290 index 776b65e915..01ee14dcfb 100755 --- a/tests/qemu-iotests/290 +++ b/tests/qemu-iotests/290 @@ -71,7 +71,7 @@ $QEMU_IO -c 'write -P 0xff 0 128k' "$BACKING_IMG" | _filter_qemu_io for qcow2_compat in 0.10 1.1; do echo "# Create an image with compat=$qcow2_compat and a backing file" - _make_test_img -o "compat=$qcow2_compat" -b "$BACKING_IMG" + _make_test_img -o "compat=$qcow2_compat" -b "$BACKING_IMG" -F $IMGFMT echo "# Fill all clusters with data and then discard them" $QEMU_IO -c 'write -P 0x01 0 128k' "$TEST_IMG" | _filter_qemu_io diff --git a/tests/qemu-iotests/290.out b/tests/qemu-iotests/290.out index d2259c823b..22b476594f 100644 --- a/tests/qemu-iotests/290.out +++ b/tests/qemu-iotests/290.out @@ -34,7 +34,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=131072 wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Create an image with compat=0.10 and a backing file -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT # Fill all clusters with data and then discard them wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -47,7 +47,7 @@ read 131072/131072 bytes at offset 0 Offset Length Mapped to File 0 0x20000 0x50000 TEST_DIR/t.qcow2 # Create an image with compat=1.1 and a backing file -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT # Fill all clusters with data and then discard them wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) From e54ee1b385a9d084b4052b6db7391ea2fd799fa8 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Jul 2020 15:39:53 -0500 Subject: [PATCH 2307/2595] block: Add support to warn on backing file change without format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For now, this is a mechanical addition; all callers pass false. But the next patch will use it to improve 'qemu-img rebase -u' when selecting a backing file with no format. Signed-off-by: Eric Blake Reviewed-by: Peter Krempa Reviewed-by: Ján Tomko Message-Id: <20200706203954.341758-10-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 13 ++++++++++--- block/qcow2.c | 2 +- block/stream.c | 2 +- blockdev.c | 3 ++- include/block/block.h | 4 ++-- qemu-img.c | 4 ++-- 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/block.c b/block.c index 6925e57d7c..4acfebf0e8 100644 --- a/block.c +++ b/block.c @@ -1206,7 +1206,8 @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, } ret = bdrv_change_backing_file(parent, filename, - base->drv ? base->drv->format_name : ""); + base->drv ? base->drv->format_name : "", + false); if (ret < 0) { error_setg_errno(errp, -ret, "Could not update backing file link"); } @@ -4680,8 +4681,8 @@ int bdrv_check(BlockDriverState *bs, * image file header * -ENOTSUP - format driver doesn't support changing the backing file */ -int bdrv_change_backing_file(BlockDriverState *bs, - const char *backing_file, const char *backing_fmt) +int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, + const char *backing_fmt, bool warn) { BlockDriver *drv = bs->drv; int ret; @@ -4695,6 +4696,12 @@ int bdrv_change_backing_file(BlockDriverState *bs, return -EINVAL; } + if (warn && backing_file && !backing_fmt) { + warn_report("Deprecated use of backing file without explicit " + "backing format, use of this image requires " + "potentially unsafe format probing"); + } + if (drv->bdrv_change_backing_file != NULL) { ret = drv->bdrv_change_backing_file(bs, backing_file, backing_fmt); } else { diff --git a/block/qcow2.c b/block/qcow2.c index f3fc2707cd..fadf3422f8 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3627,7 +3627,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } ret = bdrv_change_backing_file(blk_bs(blk), qcow2_opts->backing_file, - backing_format); + backing_format, false); if (ret < 0) { error_setg_errno(errp, -ret, "Could not assign backing file '%s' " "with format '%s'", qcow2_opts->backing_file, diff --git a/block/stream.c b/block/stream.c index aa2e7af98e..310ccbaa4c 100644 --- a/block/stream.c +++ b/block/stream.c @@ -78,7 +78,7 @@ static int stream_prepare(Job *job) } } bdrv_set_backing_hd(bs, base, &local_err); - ret = bdrv_change_backing_file(bs, base_id, base_fmt); + ret = bdrv_change_backing_file(bs, base_id, base_fmt, false); if (local_err) { error_report_err(local_err); return -EPERM; diff --git a/blockdev.c b/blockdev.c index 59b0b8ffaf..3848a9c8ab 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3416,7 +3416,8 @@ void qmp_change_backing_file(const char *device, } ret = bdrv_change_backing_file(image_bs, backing_file, - image_bs->drv ? image_bs->drv->format_name : ""); + image_bs->drv ? image_bs->drv->format_name : "", + false); if (ret < 0) { error_setg_errno(errp, -ret, "Could not change backing file to '%s'", diff --git a/include/block/block.h b/include/block/block.h index bca3bb831c..6e36154061 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -405,8 +405,8 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); void bdrv_refresh_limits(BlockDriverState *bs, Error **errp); int bdrv_commit(BlockDriverState *bs); int bdrv_make_empty(BdrvChild *c, Error **errp); -int bdrv_change_backing_file(BlockDriverState *bs, - const char *backing_file, const char *backing_fmt); +int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, + const char *backing_fmt, bool warn); void bdrv_register(BlockDriver *bdrv); int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, const char *backing_file_str); diff --git a/qemu-img.c b/qemu-img.c index 46d2796fb2..a6df64a949 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -3797,9 +3797,9 @@ static int img_rebase(int argc, char **argv) * doesn't change when we switch the backing file. */ if (out_baseimg && *out_baseimg) { - ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt); + ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt, false); } else { - ret = bdrv_change_backing_file(bs, NULL, NULL); + ret = bdrv_change_backing_file(bs, NULL, NULL, false); } if (ret == -ENOSPC) { From d9f059aa6cfccefaffa3532556e966df4a99ece2 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Jul 2020 15:39:54 -0500 Subject: [PATCH 2308/2595] qemu-img: Deprecate use of -b without -F Creating an image that requires format probing of the backing image is potentially unsafe (we've had several CVEs over the years based on probes leaking information to the guest on a subsequent boot, although these days tools like libvirt are aware of the issue enough to prevent the worst effects). For example, if our probing algorithm ever changes, or if other tools like libvirt determine a different probe result than we do, then subsequent use of that backing file under a different format will present corrupted data to the guest. Fortunately, the worst effects occur only when the backing image is originally raw, and we at least prevent commit into a probed raw backing file that would change its probed type. Still, it is worth starting a deprecation clock so that future qemu-img can refuse to create backing chains that would rely on probing, to encourage clients to avoid unsafe practices. Most warnings are intentionally emitted from bdrv_img_create() in the block layer, but qemu-img convert uses bdrv_create() which cannot emit its own warning without causing spurious warnings on other code paths. In the end, all command-line image creation or backing file rewriting now performs a check. Furthermore, if we probe a backing file as non-raw, then it is safe to explicitly record that result (rather than relying on future probes); only where we probe a raw image do we care about further warnings to the user when using such an image (for example, commits into a probed-raw backing file are prevented), to help them improve their tooling. But whether or not we make the probe results explicit, we still warn the user to remind them to upgrade their workflow to supply -F always. iotest 114 specifically wants to create an unsafe image for later amendment rather than defaulting to our new default of recording a probed format, so it needs an update. While touching it, expand it to cover all of the various warnings enabled by this patch. iotest 301 also shows a change to qcow messages. Signed-off-by: Eric Blake Message-Id: <20200706203954.341758-11-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block.c | 27 ++++++++++++++++++++++++++- docs/system/deprecated.rst | 20 ++++++++++++++++++++ qemu-img.c | 9 ++++++++- tests/qemu-iotests/114 | 14 ++++++++++++++ tests/qemu-iotests/114.out | 9 +++++++++ tests/qemu-iotests/301.out | 4 +++- 6 files changed, 80 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 4acfebf0e8..35a372df57 100644 --- a/block.c +++ b/block.c @@ -6139,6 +6139,26 @@ void bdrv_img_create(const char *filename, const char *fmt, error_append_hint(&local_err, "Could not open backing image.\n"); goto out; } else { + if (!backing_fmt) { + warn_report("Deprecated use of backing file without explicit " + "backing format (detected format of %s)", + bs->drv->format_name); + if (bs->drv != &bdrv_raw) { + /* + * A probe of raw deserves the most attention: + * leaving the backing format out of the image + * will ensure bs->probed is set (ensuring we + * don't accidentally commit into the backing + * file), and allow more spots to warn the users + * to fix their toolchain when opening this image + * later. For other images, we can safely record + * the format that we probed. + */ + backing_fmt = bs->drv->format_name; + qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, backing_fmt, + NULL); + } + } if (size == -1) { /* Opened BS, have no size */ size = bdrv_getlength(bs); @@ -6152,7 +6172,12 @@ void bdrv_img_create(const char *filename, const char *fmt, } bdrv_unref(bs); } - } /* (backing_file && !(flags & BDRV_O_NO_BACKING)) */ + /* (backing_file && !(flags & BDRV_O_NO_BACKING)) */ + } else if (backing_file && !backing_fmt) { + warn_report("Deprecated use of unopened backing file without " + "explicit backing format, use of this image requires " + "potentially unsafe format probing"); + } if (size == -1) { error_setg(errp, "Image creation needs a size parameter"); diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index c1f019b9d2..971b65be75 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -439,6 +439,26 @@ image). Rather, any changes to the backing chain should be performed with ``qemu-img rebase -u`` either before or after the remaining changes being performed by amend, as appropriate. +qemu-img backing file without format (since 5.1) +'''''''''''''''''''''''''''''''''''''''''''''''' + +The use of ``qemu-img create``, ``qemu-img rebase``, or ``qemu-img +convert`` to create or modify an image that depends on a backing file +now recommends that an explicit backing format be provided. This is +for safety: if QEMU probes a different format than what you thought, +the data presented to the guest will be corrupt; similarly, presenting +a raw image to a guest allows a potential security exploit if a future +probe sees a non-raw image based on guest writes. + +To avoid the warning message, or even future refusal to create an +unsafe image, you must pass ``-o backing_fmt=`` (or the shorthand +``-F`` during create) to specify the intended backing format. You may +use ``qemu-img rebase -u`` to retroactively add a backing format to an +existing image. However, be aware that there are already potential +security risks to blindly using ``qemu-img info`` to probe the format +of an untrusted backing image, when deciding what format to add into +an existing image. + Backwards compatibility ----------------------- diff --git a/qemu-img.c b/qemu-img.c index a6df64a949..efb6ca139e 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2517,6 +2517,13 @@ static int img_convert(int argc, char **argv) goto out; } + if (out_baseimg_param) { + if (!qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT)) { + warn_report("Deprecated use of backing file without explicit " + "backing format"); + } + } + /* Check if compression is supported */ if (s.compressed) { bool encryption = @@ -3797,7 +3804,7 @@ static int img_rebase(int argc, char **argv) * doesn't change when we switch the backing file. */ if (out_baseimg && *out_baseimg) { - ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt, false); + ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt, true); } else { ret = bdrv_change_backing_file(bs, NULL, NULL, false); } diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114 index 26104fff6c..5a7b0a4998 100755 --- a/tests/qemu-iotests/114 +++ b/tests/qemu-iotests/114 @@ -39,12 +39,21 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic _unsupported_proto vxhs +# At least OpenBSD doesn't seem to have truncate +_supported_os Linux # qcow2.py does not work too well with external data files _unsupported_imgopts data_file +# Intentionally specify backing file without backing format; demonstrate +# the difference in warning messages when backing file could be probed. +# Note that only a non-raw probe result will affect the resulting image. +truncate -s $((64 * 1024 * 1024)) "$TEST_IMG.orig" +_make_test_img -b "$TEST_IMG.orig" 64M TEST_IMG="$TEST_IMG.base" _make_test_img 64M +$QEMU_IMG convert -O qcow2 -B "$TEST_IMG.orig" "$TEST_IMG.orig" "$TEST_IMG" _make_test_img -b "$TEST_IMG.base" 64M +_make_test_img -u -b "$TEST_IMG.base" 64M # Set an invalid backing file format $PYTHON qcow2.py "$TEST_IMG" add-header-ext 0xE2792ACA "foo" @@ -55,6 +64,11 @@ _img_info $QEMU_IO -c "open $TEST_IMG" -c "read 0 4k" 2>&1 | _filter_qemu_io | _filter_testdir $QEMU_IO -c "open -o backing.driver=$IMGFMT $TEST_IMG" -c "read 0 4k" | _filter_qemu_io +# Rebase the image, to show that omitting backing format triggers a warning, +# but probing now lets us use the backing file. +$QEMU_IMG rebase -u -b "$TEST_IMG.base" "$TEST_IMG" +$QEMU_IO -c "open $TEST_IMG" -c "read 0 4k" 2>&1 | _filter_qemu_io | _filter_testdir + # success, all done echo '*** done' rm -f $seq.full diff --git a/tests/qemu-iotests/114.out b/tests/qemu-iotests/114.out index 67adef37a4..0a37d20c82 100644 --- a/tests/qemu-iotests/114.out +++ b/tests/qemu-iotests/114.out @@ -1,5 +1,11 @@ QA output created by 114 +qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of raw) +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.orig Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 +qemu-img: warning: Deprecated use of backing file without explicit backing format +qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of IMGFMT) +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +qemu-img: warning: Deprecated use of unopened backing file without explicit backing format, use of this image requires potentially unsafe format probing Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base image: TEST_DIR/t.IMGFMT file format: IMGFMT @@ -11,4 +17,7 @@ qemu-io: can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknow no file open, try 'help open' read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: warning: Deprecated use of backing file without explicit backing format, use of this image requires potentially unsafe format probing +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/301.out b/tests/qemu-iotests/301.out index 281a16d87a..9004dad639 100644 --- a/tests/qemu-iotests/301.out +++ b/tests/qemu-iotests/301.out @@ -2,7 +2,8 @@ QA output created by 301 == qcow backed by qcow == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=33554432 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base +qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of IMGFMT) +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 32 MiB (33554432 bytes) @@ -35,6 +36,7 @@ cluster_size: 512 backing file: TEST_DIR/t.IMGFMT.base == qcow backed by raw == +qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of raw) Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base image: TEST_DIR/t.IMGFMT file format: IMGFMT From e6cada9231af022ffc2e351c70dfaea8530496e1 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 9 Jul 2020 15:50:45 +0200 Subject: [PATCH 2309/2595] block: Avoid stale pointer dereference in blk_get_aio_context() It is possible for blk_remove_bs() to race with blk_drain_all(), causing the latter to dereference a stale blk->root pointer: blk_remove_bs(blk) bdrv_root_unref_child(blk->root) child_bs = blk->root->bs bdrv_detach_child(blk->root) ... g_free(blk->root) <============== blk->root becomes stale bdrv_unref(child_bs) <============ yield at some point A blk_drain_all() can be triggered by some guest action in the meantime, eg. on POWER, SLOF might disable bus mastering on a virtio-scsi-pci device: virtio_write_config() virtio_pci_stop_ioeventfd() virtio_bus_stop_ioeventfd() virtio_scsi_dataplane_stop() blk_drain_all() blk_get_aio_context() bs = blk->root ? blk->root->bs : NULL ^^^^^^^^^ stale Then, depending on one's luck, QEMU either crashes with SEGV or hits the assertion in blk_get_aio_context(). blk->root is set by blk_insert_bs() which calls bdrv_root_attach_child() first. The blk_remove_bs() function should rollback the changes made by blk_insert_bs() in the opposite order (or it should be documented somewhere why this isn't the case). Clear blk->root before calling bdrv_root_unref_child() in blk_remove_bs(). Signed-off-by: Greg Kurz Message-Id: <159430264541.389456.11925072456012783045.stgit@bahia.lan> Signed-off-by: Kevin Wolf --- block/block-backend.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block/block-backend.c b/block/block-backend.c index 6936b25c83..0bf0188133 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -808,6 +808,7 @@ void blk_remove_bs(BlockBackend *blk) { ThrottleGroupMember *tgm = &blk->public.throttle_group_member; BlockDriverState *bs; + BdrvChild *root; notifier_list_notify(&blk->remove_bs_notifiers, blk); if (tgm->throttle_state) { @@ -825,8 +826,9 @@ void blk_remove_bs(BlockBackend *blk) * to avoid that and a potential QEMU crash. */ blk_drain(blk); - bdrv_root_unref_child(blk->root); + root = blk->root; blk->root = NULL; + bdrv_root_unref_child(root); } /* From ba412478d16ca6abb4f240d92e6528eac7d3c337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 5 Jun 2020 06:56:38 +0200 Subject: [PATCH 2310/2595] MAINTAINERS: Cc qemu-block mailing list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We forgot to include the qemu-block mailing list while adding this section in commit 076a0fc32a7. Fix this. Suggested-by: Paolo Bonzini Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200630133912.9428-2-f4bug@amsat.org> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe8139f367..d9c71d0bb3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1674,6 +1674,7 @@ F: hw/ssi/xilinx_* SD (Secure Card) M: Philippe Mathieu-Daudé +L: qemu-block@nongnu.org S: Odd Fixes F: include/hw/sd/sd* F: hw/sd/core.c From 1c2329b5d644bad16e888d095e2021ad682201d9 Mon Sep 17 00:00:00 2001 From: Niek Linnenbank Date: Sun, 12 Jul 2020 20:37:08 +0200 Subject: [PATCH 2311/2595] docs/orangepi: Add instructions for resizing SD image to power of two MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SD cards need to have a size of a power of two. Update the Orange Pi machine documentation to include instructions for resizing downloaded images using the qemu-img command. Signed-off-by: Niek Linnenbank Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200712183708.15450-1-nieklinnenbank@gmail.com> Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- docs/system/arm/orangepi.rst | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/system/arm/orangepi.rst b/docs/system/arm/orangepi.rst index c41adad488..6f23907fb6 100644 --- a/docs/system/arm/orangepi.rst +++ b/docs/system/arm/orangepi.rst @@ -127,6 +127,16 @@ can be downloaded from: Alternatively, you can also choose to build you own image with buildroot using the orangepi_pc_defconfig. Also see https://buildroot.org for more information. +When using an image as an SD card, it must be resized to a power of two. This can be +done with the qemu-img command. It is recommended to only increase the image size +instead of shrinking it to a power of two, to avoid loss of data. For example, +to prepare a downloaded Armbian image, first extract it and then increase +its size to one gigabyte as follows: + +.. code-block:: bash + + $ qemu-img resize Armbian_19.11.3_Orangepipc_bionic_current_5.3.9.img 1G + You can choose to attach the selected image either as an SD card or as USB mass storage. For example, to boot using the Orange Pi PC Debian image on SD card, simply add the -sd argument and provide the proper root= kernel parameter: @@ -213,12 +223,12 @@ Next, unzip the NetBSD image and write the U-Boot binary including SPL using: $ dd if=/path/to/u-boot-sunxi-with-spl.bin of=armv7.img bs=1024 seek=8 conv=notrunc Finally, before starting the machine the SD image must be extended such -that the NetBSD kernel will not conclude the NetBSD partition is larger than -the emulated SD card: +that the size of the SD image is a power of two and that the NetBSD kernel +will not conclude the NetBSD partition is larger than the emulated SD card: .. code-block:: bash - $ dd if=/dev/zero bs=1M count=64 >> armv7.img + $ qemu-img resize armv7.img 2G Start the machine using the following command: From b7dcbf1395da960ec3c313300dc0030674de8cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 13 Jul 2020 09:45:33 +0200 Subject: [PATCH 2312/2595] tests/acceptance/boot_linux: Tag tests using a SD card with 'device:sd' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avocado tags are handy to automatically select tests matching the tags. Since these tests use a SD card, tag them. We can run all the tests using a SD card at once with: $ avocado --show=app run -t u-boot tests/acceptance/ $ AVOCADO_ALLOW_LARGE_STORAGE=ok \ avocado --show=app \ run -t device:sd tests/acceptance/ Fetching asset from tests/acceptance/boot_linux_console.py:BootLinuxConsole.test_arm_orangepi_sd Fetching asset from tests/acceptance/boot_linux_console.py:BootLinuxConsole.test_arm_orangepi_bionic Fetching asset from tests/acceptance/boot_linux_console.py:BootLinuxConsole.test_arm_orangepi_uboot_netbsd9 (1/3) tests/acceptance/boot_linux_console.py:BootLinuxConsole.test_arm_orangepi_sd: PASS (19.56 s) (2/3) tests/acceptance/boot_linux_console.py:BootLinuxConsole.test_arm_orangepi_bionic: PASS (49.97 s) (3/3) tests/acceptance/boot_linux_console.py:BootLinuxConsole.test_arm_orangepi_uboot_netbsd9: PASS (20.06 s) RESULTS : PASS 3 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0 JOB TIME : 90.02 s Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Message-Id: <20200713183209.26308-4-f4bug@amsat.org> --- tests/acceptance/boot_linux_console.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 3d02519660..b7e8858c2d 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -620,6 +620,7 @@ class BootLinuxConsole(LinuxKernelTest): """ :avocado: tags=arch:arm :avocado: tags=machine:orangepi-pc + :avocado: tags=device:sd """ deb_url = ('https://apt.armbian.com/pool/main/l/' 'linux-4.20.7-sunxi/linux-image-dev-sunxi_5.75_armhf.deb') @@ -669,6 +670,7 @@ class BootLinuxConsole(LinuxKernelTest): """ :avocado: tags=arch:arm :avocado: tags=machine:orangepi-pc + :avocado: tags=device:sd """ # This test download a 196MB compressed image and expand it to 932MB... @@ -710,6 +712,7 @@ class BootLinuxConsole(LinuxKernelTest): """ :avocado: tags=arch:arm :avocado: tags=machine:orangepi-pc + :avocado: tags=device:sd """ # This test download a 304MB compressed image and expand it to 1.3GB... deb_url = ('http://snapshot.debian.org/archive/debian/' From 6a289a5ba3383e17fb47029720425bef42e424d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Jul 2020 15:05:27 +0200 Subject: [PATCH 2313/2595] tests/acceptance/boot_linux: Expand SD card image to power of 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In few commits we won't allow SD card images with invalid size (not aligned to a power of 2). Prepare the tests: add the pow2ceil() and image_pow2ceil_expand() methods and resize the images (expanding) of the tests using SD cards. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Cleber Rosa Message-Id: <20200713183209.26308-5-f4bug@amsat.org> --- tests/acceptance/boot_linux_console.py | 31 ++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index b7e8858c2d..67c3b2f3d1 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -28,6 +28,22 @@ try: except CmdNotFoundError: P7ZIP_AVAILABLE = False +""" +Round up to next power of 2 +""" +def pow2ceil(x): + return 1 if x == 0 else 2**(x - 1).bit_length() + +""" +Expand file size to next power of 2 +""" +def image_pow2ceil_expand(path): + size = os.path.getsize(path) + size_aligned = pow2ceil(size) + if size != size_aligned: + with open(path, 'ab+') as fd: + fd.truncate(size_aligned) + class LinuxKernelTest(Test): KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' @@ -636,6 +652,7 @@ class BootLinuxConsole(LinuxKernelTest): rootfs_path_xz = self.fetch_asset(rootfs_url, asset_hash=rootfs_hash) rootfs_path = os.path.join(self.workdir, 'rootfs.cpio') archive.lzma_uncompress(rootfs_path_xz, rootfs_path) + image_pow2ceil_expand(rootfs_path) self.vm.set_console() kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + @@ -673,7 +690,7 @@ class BootLinuxConsole(LinuxKernelTest): :avocado: tags=device:sd """ - # This test download a 196MB compressed image and expand it to 932MB... + # This test download a 196MB compressed image and expand it to 1GB image_url = ('https://dl.armbian.com/orangepipc/archive/' 'Armbian_19.11.3_Orangepipc_bionic_current_5.3.9.7z') image_hash = '196a8ffb72b0123d92cea4a070894813d305c71e' @@ -681,6 +698,7 @@ class BootLinuxConsole(LinuxKernelTest): image_name = 'Armbian_19.11.3_Orangepipc_bionic_current_5.3.9.img' image_path = os.path.join(self.workdir, image_name) process.run("7z e -o%s %s" % (self.workdir, image_path_7z)) + image_pow2ceil_expand(image_path) self.vm.set_console() self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw', @@ -714,7 +732,7 @@ class BootLinuxConsole(LinuxKernelTest): :avocado: tags=machine:orangepi-pc :avocado: tags=device:sd """ - # This test download a 304MB compressed image and expand it to 1.3GB... + # This test download a 304MB compressed image and expand it to 2GB deb_url = ('http://snapshot.debian.org/archive/debian/' '20200108T145233Z/pool/main/u/u-boot/' 'u-boot-sunxi_2020.01%2Bdfsg-1_armhf.deb') @@ -731,8 +749,9 @@ class BootLinuxConsole(LinuxKernelTest): image_hash = '2babb29d36d8360adcb39c09e31060945259917a' image_path_gz = self.fetch_asset(image_url, asset_hash=image_hash) image_path = os.path.join(self.workdir, 'armv7.img') - image_drive_args = 'if=sd,format=raw,snapshot=on,file=' + image_path archive.gzip_uncompress(image_path_gz, image_path) + image_pow2ceil_expand(image_path) + image_drive_args = 'if=sd,format=raw,snapshot=on,file=' + image_path # dd if=u-boot-sunxi-with-spl.bin of=armv7.img bs=1K seek=8 conv=notrunc with open(uboot_path, 'rb') as f_in: @@ -740,12 +759,6 @@ class BootLinuxConsole(LinuxKernelTest): f_out.seek(8 * 1024) shutil.copyfileobj(f_in, f_out) - # Extend image, to avoid that NetBSD thinks the partition - # inside the image is larger than device size itself - f_out.seek(0, 2) - f_out.seek(64 * 1024 * 1024, 1) - f_out.write(bytearray([0x00])) - self.vm.set_console() self.vm.add_args('-nic', 'user', '-drive', image_drive_args, From 9157dd597d293ab7f599f4d96c3fe8a6e07c633d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 3 Jun 2020 19:59:16 +0200 Subject: [PATCH 2314/2595] hw/sd/sdcard: Restrict Class 6 commands to SCSD cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only SCSD cards support Class 6 (Block Oriented Write Protection) commands. "SD Specifications Part 1 Physical Layer Simplified Spec. v3.01" 4.3.14 Command Functional Difference in Card Capacity Types * Write Protected Group SDHC and SDXC do not support write-protected groups. Issuing CMD28, CMD29 and CMD30 generates the ILLEGAL_COMMAND error. Cc: qemu-stable@nongnu.org Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20200630133912.9428-7-f4bug@amsat.org> --- hw/sd/sd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 5137168d66..1cc16bfd31 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -920,6 +920,11 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) sd->multi_blk_cnt = 0; } + if (sd_cmd_class[req.cmd] == 6 && FIELD_EX32(sd->ocr, OCR, CARD_CAPACITY)) { + /* Only Standard Capacity cards support class 6 commands */ + return sd_illegal; + } + switch (req.cmd) { /* Basic commands (Class 0 and Class 1) */ case 0: /* CMD0: GO_IDLE_STATE */ From 6dd3a164f5b31c703c7d8372841ad3bd6a57de6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 5 Jun 2018 22:28:51 -0300 Subject: [PATCH 2315/2595] hw/sd/sdcard: Simplify realize() a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need to check if sd->blk is set twice. Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20200630133912.9428-18-f4bug@amsat.org> --- hw/sd/sd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 1cc16bfd31..edd60a09c0 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -2105,12 +2105,12 @@ static void sd_realize(DeviceState *dev, Error **errp) return; } - if (sd->blk && blk_is_read_only(sd->blk)) { - error_setg(errp, "Cannot use read-only drive as SD card"); - return; - } - if (sd->blk) { + if (blk_is_read_only(sd->blk)) { + error_setg(errp, "Cannot use read-only drive as SD card"); + return; + } + ret = blk_set_perm(sd->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, BLK_PERM_ALL, errp); if (ret < 0) { From a9bcedd15a5834ca9ae6c3a97933e85ac7edbd36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Jul 2020 13:02:34 +0200 Subject: [PATCH 2316/2595] hw/sd/sdcard: Do not allow invalid SD card sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU allows to create SD card with unrealistic sizes. This could work, but some guests (at least Linux) consider sizes that are not a power of 2 as a firmware bug and fix the card size to the next power of 2. While the possibility to use small SD card images has been seen as a feature, it became a bug with CVE-2020-13253, where the guest is able to do OOB read/write accesses past the image size end. In a pair of commits we will fix CVE-2020-13253 as: Read command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR occurred and no data transfer is performed. Write command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR occurred and no data transfer is performed. WP_VIOLATION errors are not modified: the error bit is set, we stay in receive-data state, wait for a stop command. All further data transfer is ignored. See the check on sd->card_status at the beginning of sd_read_data() and sd_write_data(). While this is the correct behavior, in case QEMU create smaller SD cards, guests still try to access past the image size end, and QEMU considers this is an invalid address, thus "all further data transfer is ignored". This is wrong and make the guest looping until eventually timeouts. Fix by not allowing invalid SD card sizes (suggesting the expected size as a hint): $ qemu-system-arm -M orangepi-pc -drive file=rootfs.ext2,if=sd,format=raw qemu-system-arm: Invalid SD card size: 60 MiB SD card size has to be a power of 2, e.g. 64 MiB. You can resize disk images with 'qemu-img resize ' (note that this will lose data if you make the image smaller than it currently is). Cc: qemu-stable@nongnu.org Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Peter Maydell Message-Id: <20200713183209.26308-8-f4bug@amsat.org> --- hw/sd/sd.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index edd60a09c0..76d68359a4 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -32,6 +32,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" +#include "qemu/cutils.h" #include "hw/irq.h" #include "hw/registerfields.h" #include "sysemu/block-backend.h" @@ -2106,11 +2107,35 @@ static void sd_realize(DeviceState *dev, Error **errp) } if (sd->blk) { + int64_t blk_size; + if (blk_is_read_only(sd->blk)) { error_setg(errp, "Cannot use read-only drive as SD card"); return; } + blk_size = blk_getlength(sd->blk); + if (blk_size > 0 && !is_power_of_2(blk_size)) { + int64_t blk_size_aligned = pow2ceil(blk_size); + char *blk_size_str; + + blk_size_str = size_to_str(blk_size); + error_setg(errp, "Invalid SD card size: %s", blk_size_str); + g_free(blk_size_str); + + blk_size_str = size_to_str(blk_size_aligned); + error_append_hint(errp, + "SD card size has to be a power of 2, e.g. %s.\n" + "You can resize disk images with" + " 'qemu-img resize '\n" + "(note that this will lose data if you make the" + " image smaller than it currently is).\n", + blk_size_str); + g_free(blk_size_str); + + return; + } + ret = blk_set_perm(sd->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, BLK_PERM_ALL, errp); if (ret < 0) { From 794d68de2f021a6d3874df41d6bbe8590ec05207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 13 Jul 2020 09:27:35 +0200 Subject: [PATCH 2317/2595] hw/sd/sdcard: Update coding style to make checkpatch.pl happy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make the next commit easier to review, clean this code first. Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Alexander Bulekov Message-Id: <20200630133912.9428-3-f4bug@amsat.org> --- hw/sd/sd.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 76d68359a4..f4f76f8fd2 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1175,8 +1175,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) sd->data_start = addr; sd->data_offset = 0; - if (sd->data_start + sd->blk_len > sd->size) + if (sd->data_start + sd->blk_len > sd->size) { sd->card_status |= ADDRESS_ERROR; + } return sd_r1; default: @@ -1191,8 +1192,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) sd->data_start = addr; sd->data_offset = 0; - if (sd->data_start + sd->blk_len > sd->size) + if (sd->data_start + sd->blk_len > sd->size) { sd->card_status |= ADDRESS_ERROR; + } return sd_r1; default: @@ -1237,12 +1239,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) sd->data_offset = 0; sd->blk_written = 0; - if (sd->data_start + sd->blk_len > sd->size) + if (sd->data_start + sd->blk_len > sd->size) { sd->card_status |= ADDRESS_ERROR; - if (sd_wp_addr(sd, sd->data_start)) + } + if (sd_wp_addr(sd, sd->data_start)) { sd->card_status |= WP_VIOLATION; - if (sd->csd[14] & 0x30) + } + if (sd->csd[14] & 0x30) { sd->card_status |= WP_VIOLATION; + } return sd_r1; default: @@ -1261,12 +1266,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) sd->data_offset = 0; sd->blk_written = 0; - if (sd->data_start + sd->blk_len > sd->size) + if (sd->data_start + sd->blk_len > sd->size) { sd->card_status |= ADDRESS_ERROR; - if (sd_wp_addr(sd, sd->data_start)) + } + if (sd_wp_addr(sd, sd->data_start)) { sd->card_status |= WP_VIOLATION; - if (sd->csd[14] & 0x30) + } + if (sd->csd[14] & 0x30) { sd->card_status |= WP_VIOLATION; + } return sd_r1; default: From 790762e5487114341cccc5bffcec4cb3c022c3cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 4 Jun 2020 19:22:29 +0200 Subject: [PATCH 2318/2595] hw/sd/sdcard: Do not switch to ReceivingData if address is invalid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only move the state machine to ReceivingData if there is no pending error. This avoids later OOB access while processing commands queued. "SD Specifications Part 1 Physical Layer Simplified Spec. v3.01" 4.3.3 Data Read Read command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR occurred and no data transfer is performed. 4.3.4 Data Write Write command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR occurred and no data transfer is performed. WP_VIOLATION errors are not modified: the error bit is set, we stay in receive-data state, wait for a stop command. All further data transfer is ignored. See the check on sd->card_status at the beginning of sd_read_data() and sd_write_data(). Fixes: CVE-2020-13253 Cc: qemu-stable@nongnu.org Reported-by: Alexander Bulekov Buglink: https://bugs.launchpad.net/qemu/+bug/1880822 Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20200630133912.9428-6-f4bug@amsat.org> --- hw/sd/sd.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index f4f76f8fd2..fad9cf1ee7 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1171,13 +1171,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 17: /* CMD17: READ_SINGLE_BLOCK */ switch (sd->state) { case sd_transfer_state: + + if (addr + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; + return sd_r1; + } + sd->state = sd_sendingdata_state; sd->data_start = addr; sd->data_offset = 0; - - if (sd->data_start + sd->blk_len > sd->size) { - sd->card_status |= ADDRESS_ERROR; - } return sd_r1; default: @@ -1188,13 +1190,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 18: /* CMD18: READ_MULTIPLE_BLOCK */ switch (sd->state) { case sd_transfer_state: + + if (addr + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; + return sd_r1; + } + sd->state = sd_sendingdata_state; sd->data_start = addr; sd->data_offset = 0; - - if (sd->data_start + sd->blk_len > sd->size) { - sd->card_status |= ADDRESS_ERROR; - } return sd_r1; default: @@ -1234,14 +1238,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Writing in SPI mode not implemented. */ if (sd->spi) break; + + if (addr + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; + return sd_r1; + } + sd->state = sd_receivingdata_state; sd->data_start = addr; sd->data_offset = 0; sd->blk_written = 0; - if (sd->data_start + sd->blk_len > sd->size) { - sd->card_status |= ADDRESS_ERROR; - } if (sd_wp_addr(sd, sd->data_start)) { sd->card_status |= WP_VIOLATION; } @@ -1261,14 +1268,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* Writing in SPI mode not implemented. */ if (sd->spi) break; + + if (addr + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; + return sd_r1; + } + sd->state = sd_receivingdata_state; sd->data_start = addr; sd->data_offset = 0; sd->blk_written = 0; - if (sd->data_start + sd->blk_len > sd->size) { - sd->card_status |= ADDRESS_ERROR; - } if (sd_wp_addr(sd, sd->data_start)) { sd->card_status |= WP_VIOLATION; } From 9788e8c9b64e4cebb01c96bab2b0e4c2d4454041 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Wed, 1 Jul 2020 20:25:57 +0200 Subject: [PATCH 2319/2595] target/mips: Remove identical if/else branches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the segment: if (other_tc == other->current_tc) { tccause = other->CP0_Cause; } else { tccause = other->CP0_Cause; } Original contributor can't remember what was his intention. Fixes: 5a25ce9487 ("mips: Hook in more reg accesses via mttr/mftr") Buglink: https://bugs.launchpad.net/qemu/+bug/1885718 Signed-off-by: Aleksandar Markovic Message-Id: <20200701182559.28841-2-aleksandar.qemu.devel@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/cp0_helper.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/target/mips/cp0_helper.c b/target/mips/cp0_helper.c index bbf12e4a97..de64add038 100644 --- a/target/mips/cp0_helper.c +++ b/target/mips/cp0_helper.c @@ -375,16 +375,9 @@ target_ulong helper_mftc0_entryhi(CPUMIPSState *env) target_ulong helper_mftc0_cause(CPUMIPSState *env) { int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); - int32_t tccause; CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); - if (other_tc == other->current_tc) { - tccause = other->CP0_Cause; - } else { - tccause = other->CP0_Cause; - } - - return tccause; + return other->CP0_Cause; } target_ulong helper_mftc0_status(CPUMIPSState *env) From dda97e385b2f0fa84267a497596fe79898d48123 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Fri, 3 Jul 2020 17:15:15 +0100 Subject: [PATCH 2320/2595] target/mips: Fix ADD.S FPU instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After merging latest QEMU upstream into our CHERI fork, I noticed that some of the FPU tests in our MIPS baremetal testsuite [*] started failing. It turns out commit 1ace099f2a accidentally changed add.s into a subtract. [*] https://github.com/CTSRD-CHERI/cheritest Fixes: 1ace099f2a ("target/mips: fpu: Demacro ADD.") Signed-off-by: Alex Richardson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200703161515.25966-1-Alexander.Richardson@cl.cam.ac.uk> Signed-off-by: Aleksandar Markovic Signed-off-by: Philippe Mathieu-Daudé --- target/mips/fpu_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index 7a3a61cab3..56beda49d8 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1221,7 +1221,7 @@ uint32_t helper_float_add_s(CPUMIPSState *env, { uint32_t wt2; - wt2 = float32_sub(fst0, fst1, &env->active_fpu.fp_status); + wt2 = float32_add(fst0, fst1, &env->active_fpu.fp_status); update_fcr31(env, GETPC()); return wt2; } From 15d983dee95edff1dc4c0bed71ce02fff877e766 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Wed, 1 Jul 2020 20:25:58 +0200 Subject: [PATCH 2321/2595] MAINTAINERS: Adjust MIPS maintainership (add Huacai Chen & Jiaxun Yang) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Huacai Chen and Jiaxun Yang step in as new energy [1]. Aurelien Jarno comment [2]: It happens that I known Huacai Chen from the time he was upstreaming the Loongson 3 support to the kernel, I have been testing and reviewing his patches. I also know Jiaxun Yang from the #debian-mips IRC channel. I know that they are both very competent and have a good knowledge of the open source world. I therefore agree that they are good additions to maintain and/or review the MIPS part of QEMU. [1] https://www.mail-archive.com/qemu-devel@nongnu.org/msg718434.html [2] https://www.mail-archive.com/qemu-devel@nongnu.org/msg718738.html Signed-off-by: Aleksandar Markovic Message-Id: <20200701182559.28841-3-aleksandar.qemu.devel@gmail.com> PMD: [Split patch, added Aurelien's comment] Signed-off-by: Philippe Mathieu-Daudé Acked-by: Jiaxun Yang Acked-by: Huacai Chen --- MAINTAINERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe8139f367..cdb5c6f171 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -222,6 +222,7 @@ F: disas/microblaze.c MIPS TCG CPUs M: Aleksandar Markovic R: Aurelien Jarno +R: Jiaxun Yang R: Aleksandar Rikalo S: Maintained F: target/mips/ @@ -384,6 +385,7 @@ S: Maintained F: target/arm/kvm.c MIPS KVM CPUs +M: Huacai Chen M: Aleksandar Markovic S: Odd Fixes F: target/mips/kvm.c @@ -2743,6 +2745,8 @@ F: disas/i386.c MIPS TCG target M: Aleksandar Markovic R: Aurelien Jarno +R: Huacai Chen +R: Jiaxun Yang R: Aleksandar Rikalo S: Maintained F: tcg/mips/ From 01afa757b6f1b8c7858cc29b8332e9fb6aa1e16f Mon Sep 17 00:00:00 2001 From: Ahmed Karaman Date: Thu, 9 Jul 2020 07:20:55 +0200 Subject: [PATCH 2322/2595] scripts/performance: Add dissect.py script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Python script that dissects QEMU execution into three main phases: code generation, JIT execution and helpers execution. Syntax: dissect.py [-h] -- [] \ [] [-h] - Print the script arguments help message. Example of usage: dissect.py -- qemu-arm coulomb_double-arm Example output: Total Instructions: 4,702,865,362 Code Generation: 115,819,309 2.463% JIT Execution: 1,081,980,528 23.007% Helpers: 3,505,065,525 74.530% Signed-off-by: Ahmed Karaman Reviewed-by: Aleksandar Markovic Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200709052055.2650-2-ahmedkhaledkaraman@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- scripts/performance/dissect.py | 166 +++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100755 scripts/performance/dissect.py diff --git a/scripts/performance/dissect.py b/scripts/performance/dissect.py new file mode 100755 index 0000000000..bf24f50922 --- /dev/null +++ b/scripts/performance/dissect.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 + +# Print the percentage of instructions spent in each phase of QEMU +# execution. +# +# Syntax: +# dissect.py [-h] -- [] \ +# [] +# +# [-h] - Print the script arguments help message. +# +# Example of usage: +# dissect.py -- qemu-arm coulomb_double-arm +# +# This file is a part of the project "TCG Continuous Benchmarking". +# +# Copyright (C) 2020 Ahmed Karaman +# Copyright (C) 2020 Aleksandar Markovic +# +# 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 . + +import argparse +import os +import subprocess +import sys +import tempfile + + +def get_JIT_line(callgrind_data): + """ + Search for the first instance of the JIT call in + the callgrind_annotate output when ran using --tree=caller + This is equivalent to the self number of instructions of JIT. + + Parameters: + callgrind_data (list): callgrind_annotate output + + Returns: + (int): Line number + """ + line = -1 + for i in range(len(callgrind_data)): + if callgrind_data[i].strip('\n') and \ + callgrind_data[i].split()[-1] == "[???]": + line = i + break + if line == -1: + sys.exit("Couldn't locate the JIT call ... Exiting.") + return line + + +def main(): + # Parse the command line arguments + parser = argparse.ArgumentParser( + usage='dissect.py [-h] -- ' + ' [] ' + ' []') + + parser.add_argument('command', type=str, nargs='+', help=argparse.SUPPRESS) + + args = parser.parse_args() + + # Extract the needed variables from the args + command = args.command + + # Insure that valgrind is installed + check_valgrind = subprocess.run( + ["which", "valgrind"], stdout=subprocess.DEVNULL) + if check_valgrind.returncode: + sys.exit("Please install valgrind before running the script.") + + # Save all intermediate files in a temporary directory + with tempfile.TemporaryDirectory() as tmpdirname: + # callgrind output file path + data_path = os.path.join(tmpdirname, "callgrind.data") + # callgrind_annotate output file path + annotate_out_path = os.path.join(tmpdirname, "callgrind_annotate.out") + + # Run callgrind + callgrind = subprocess.run((["valgrind", + "--tool=callgrind", + "--callgrind-out-file=" + data_path] + + command), + stdout=subprocess.DEVNULL, + stderr=subprocess.PIPE) + if callgrind.returncode: + sys.exit(callgrind.stderr.decode("utf-8")) + + # Save callgrind_annotate output + with open(annotate_out_path, "w") as output: + callgrind_annotate = subprocess.run( + ["callgrind_annotate", data_path, "--tree=caller"], + stdout=output, + stderr=subprocess.PIPE) + if callgrind_annotate.returncode: + sys.exit(callgrind_annotate.stderr.decode("utf-8")) + + # Read the callgrind_annotate output to callgrind_data[] + callgrind_data = [] + with open(annotate_out_path, 'r') as data: + callgrind_data = data.readlines() + + # Line number with the total number of instructions + total_instructions_line_number = 20 + # Get the total number of instructions + total_instructions_line_data = \ + callgrind_data[total_instructions_line_number] + total_instructions = total_instructions_line_data.split()[0] + total_instructions = int(total_instructions.replace(',', '')) + + # Line number with the JIT self number of instructions + JIT_self_instructions_line_number = get_JIT_line(callgrind_data) + # Get the JIT self number of instructions + JIT_self_instructions_line_data = \ + callgrind_data[JIT_self_instructions_line_number] + JIT_self_instructions = JIT_self_instructions_line_data.split()[0] + JIT_self_instructions = int(JIT_self_instructions.replace(',', '')) + + # Line number with the JIT self + inclusive number of instructions + # It's the line above the first JIT call when running with --tree=caller + JIT_total_instructions_line_number = JIT_self_instructions_line_number-1 + # Get the JIT self + inclusive number of instructions + JIT_total_instructions_line_data = \ + callgrind_data[JIT_total_instructions_line_number] + JIT_total_instructions = JIT_total_instructions_line_data.split()[0] + JIT_total_instructions = int(JIT_total_instructions.replace(',', '')) + + # Calculate number of instructions in helpers and code generation + helpers_instructions = JIT_total_instructions-JIT_self_instructions + code_generation_instructions = total_instructions-JIT_total_instructions + + # Print results (Insert commas in large numbers) + # Print total number of instructions + print('{:<20}{:>20}\n'. + format("Total Instructions:", + format(total_instructions, ','))) + # Print code generation instructions and percentage + print('{:<20}{:>20}\t{:>6.3f}%'. + format("Code Generation:", + format(code_generation_instructions, ","), + (code_generation_instructions / total_instructions) * 100)) + # Print JIT instructions and percentage + print('{:<20}{:>20}\t{:>6.3f}%'. + format("JIT Execution:", + format(JIT_self_instructions, ","), + (JIT_self_instructions / total_instructions) * 100)) + # Print helpers instructions and percentage + print('{:<20}{:>20}\t{:>6.3f}%'. + format("Helpers:", + format(helpers_instructions, ","), + (helpers_instructions/total_instructions)*100)) + + +if __name__ == "__main__": + main() From 14661d93d787846833b0e62d5995195c8851f741 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:38 -0400 Subject: [PATCH 2323/2595] python/machine.py: consolidate _post_shutdown() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move more cleanup actions into _post_shutdown. As a change, if QEMU should so happen to be terminated during a call to wait(), that event will now be logged. This is not likely to occur during normative use. Signed-off-by: John Snow Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200710050649.32434-2-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index c25f0b42cf..ca1f2114e6 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -294,6 +294,8 @@ class QEMUMachine: self._qmp.accept() def _post_shutdown(self): + self._load_io_log() + if self._qemu_log_file is not None: self._qemu_log_file.close() self._qemu_log_file = None @@ -307,6 +309,17 @@ class QEMUMachine: while len(self._remove_files) > 0: self._remove_if_exists(self._remove_files.pop()) + exitcode = self.exitcode() + if exitcode is not None and exitcode < 0: + msg = 'qemu received signal %i; command: "%s"' + if self._qemu_full_args: + command = ' '.join(self._qemu_full_args) + else: + command = '' + LOG.warning(msg, -int(exitcode), command) + + self._launched = False + def launch(self): """ Launch the VM and make sure we cleanup and expose the @@ -355,7 +368,6 @@ class QEMUMachine: self._popen.wait() if self._qmp: self._qmp.close() - self._load_io_log() self._post_shutdown() def shutdown(self, has_quit=False, hard=False): @@ -382,21 +394,8 @@ class QEMUMachine: self._popen.kill() self._popen.wait() - self._load_io_log() self._post_shutdown() - exitcode = self.exitcode() - if exitcode is not None and exitcode < 0 and \ - not (exitcode == -9 and hard): - msg = 'qemu received signal %i: %s' - if self._qemu_full_args: - command = ' '.join(self._qemu_full_args) - else: - command = '' - LOG.warning(msg, -int(exitcode), command) - - self._launched = False - def kill(self): self.shutdown(hard=True) From 671940e633b83ac489e0b4bb407749723ff8a879 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:39 -0400 Subject: [PATCH 2324/2595] python/machine.py: Close QMP socket in cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not important to do this before waiting for the process to exit, so it can be done during generic post-shutdown cleanup. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Message-Id: <20200710050649.32434-3-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index ca1f2114e6..d3faa9a84c 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -294,6 +294,10 @@ class QEMUMachine: self._qmp.accept() def _post_shutdown(self): + if self._qmp: + self._qmp.close() + self._qmp = None + self._load_io_log() if self._qemu_log_file is not None: @@ -366,8 +370,6 @@ class QEMUMachine: Wait for the VM to power off """ self._popen.wait() - if self._qmp: - self._qmp.close() self._post_shutdown() def shutdown(self, has_quit=False, hard=False): @@ -388,7 +390,6 @@ class QEMUMachine: try: if not has_quit: self._qmp.cmd('quit') - self._qmp.close() self._popen.wait(timeout=3) except: self._popen.kill() From e2c97f161294c702ee4a2dd08532d5df67f6bff4 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:40 -0400 Subject: [PATCH 2325/2595] python/machine.py: Add _early_cleanup hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some parts of cleanup need to occur prior to shutdown, otherwise shutdown might break. Move this into a suitably named method/callback. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Message-Id: <20200710050649.32434-4-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index d3faa9a84c..127926b276 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -365,6 +365,17 @@ class QEMUMachine: close_fds=False) self._post_launch() + def _early_cleanup(self) -> None: + """ + Perform any cleanup that needs to happen before the VM exits. + """ + # If we keep the console socket open, we may deadlock waiting + # for QEMU to exit, while QEMU is waiting for the socket to + # become writeable. + if self._console_socket is not None: + self._console_socket.close() + self._console_socket = None + def wait(self): """ Wait for the VM to power off @@ -376,12 +387,7 @@ class QEMUMachine: """ Terminate the VM and clean up """ - # If we keep the console socket open, we may deadlock waiting - # for QEMU to exit, while QEMU is waiting for the socket to - # become writeable. - if self._console_socket is not None: - self._console_socket.close() - self._console_socket = None + self._early_cleanup() if self.is_running(): if hard: From 3a7d64b6fc8ddce3987005e0ee6eadbe2cbba5c8 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:41 -0400 Subject: [PATCH 2326/2595] python/machine.py: Perform early cleanup for wait() calls, too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is primarily for consistency, and is a step towards wait() and shutdown() sharing the same implementation so that the two cleanup paths cannot diverge. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Message-Id: <20200710050649.32434-5-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 127926b276..63e40879e2 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -380,6 +380,7 @@ class QEMUMachine: """ Wait for the VM to power off """ + self._early_cleanup() self._popen.wait() self._post_shutdown() From a3842cb078a195db0715b00edd7812adcb8b077f Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:42 -0400 Subject: [PATCH 2327/2595] python/machine.py: Prohibit multiple shutdown() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the VM is not launched, don't try to shut it down. As a change, _post_shutdown now unconditionally also calls _early_cleanup in order to offer comprehensive object cleanup in failure cases. As a courtesy, treat it as a NOP instead of rejecting it as an error. This is slightly nicer for acceptance tests where vm.shutdown() is issued unconditionally in tearDown callbacks. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200710050649.32434-6-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 63e40879e2..c28957ee82 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -294,6 +294,13 @@ class QEMUMachine: self._qmp.accept() def _post_shutdown(self): + """ + Called to cleanup the VM instance after the process has exited. + May also be called after a failed launch. + """ + # Comprehensive reset for the failed launch case: + self._early_cleanup() + if self._qmp: self._qmp.close() self._qmp = None @@ -339,7 +346,7 @@ class QEMUMachine: self._launch() self._launched = True except: - self.shutdown() + self._post_shutdown() LOG.debug('Error launching VM') if self._qemu_full_args: @@ -368,6 +375,8 @@ class QEMUMachine: def _early_cleanup(self) -> None: """ Perform any cleanup that needs to happen before the VM exits. + + Called additionally by _post_shutdown for comprehensive cleanup. """ # If we keep the console socket open, we may deadlock waiting # for QEMU to exit, while QEMU is waiting for the socket to @@ -388,6 +397,9 @@ class QEMUMachine: """ Terminate the VM and clean up """ + if not self._launched: + return + self._early_cleanup() if self.is_running(): From c9b3045bc2f52aca8825b6a04e9367b87d64d1cf Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:43 -0400 Subject: [PATCH 2328/2595] python/machine.py: Add a configurable timeout to shutdown() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three seconds is hardcoded. Use it as a default parameter instead, and use that value for both waits that may occur in the function. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cleber Rosa Message-Id: <20200710050649.32434-7-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index c28957ee82..e825f0bdc6 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -393,7 +393,9 @@ class QEMUMachine: self._popen.wait() self._post_shutdown() - def shutdown(self, has_quit=False, hard=False): + def shutdown(self, has_quit: bool = False, + hard: bool = False, + timeout: Optional[int] = 3) -> None: """ Terminate the VM and clean up """ @@ -409,10 +411,10 @@ class QEMUMachine: try: if not has_quit: self._qmp.cmd('quit') - self._popen.wait(timeout=3) + self._popen.wait(timeout=timeout) except: self._popen.kill() - self._popen.wait() + self._popen.wait(timeout=timeout) self._post_shutdown() From 895280593139a1c34e59526835ba8fda903f8aaa Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:44 -0400 Subject: [PATCH 2329/2595] python/machine.py: Make wait() call shutdown() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At this point, shutdown(has_quit=True) and wait() do essentially the same thing; they perform cleanup without actually instructing QEMU to quit. Define one in terms of the other. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Message-Id: <20200710050649.32434-8-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index e825f0bdc6..3f0b873f58 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -385,14 +385,6 @@ class QEMUMachine: self._console_socket.close() self._console_socket = None - def wait(self): - """ - Wait for the VM to power off - """ - self._early_cleanup() - self._popen.wait() - self._post_shutdown() - def shutdown(self, has_quit: bool = False, hard: bool = False, timeout: Optional[int] = 3) -> None: @@ -421,6 +413,15 @@ class QEMUMachine: def kill(self): self.shutdown(hard=True) + def wait(self, timeout: Optional[int] = None) -> None: + """ + Wait for the VM to power off and perform post-shutdown cleanup. + + :param timeout: Optional timeout in seconds. + Default None, an infinite wait. + """ + self.shutdown(has_quit=True, timeout=timeout) + def set_qmp_monitor(self, enabled=True): """ Set the QMP monitor. From a0690c39006b897d6453daf591909948ac553650 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:45 -0400 Subject: [PATCH 2330/2595] tests/acceptance: wait() instead of shutdown() where appropriate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When issuing 'reboot' to a VM with the no-reboot option, that VM will exit. When then issuing a shutdown command, the cleanup may race. Add calls to vm.wait() which will gracefully mark the VM as having exited. Subsequent vm.shutdown() calls in generic tearDown code will not race when called after completion of the call. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Message-Id: <20200710050649.32434-9-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/boot_linux_console.py | 10 ++++++++++ tests/acceptance/linux_ssh_mips_malta.py | 2 ++ 2 files changed, 12 insertions(+) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 3d02519660..5867ef760c 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -191,6 +191,8 @@ class BootLinuxConsole(LinuxKernelTest): 'Debian') exec_command_and_wait_for_pattern(self, 'reboot', 'reboot: Restarting system') + # Wait for VM to shut down gracefully + self.vm.wait() @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code') def test_mips64el_malta_5KEc_cpio(self): @@ -231,6 +233,8 @@ class BootLinuxConsole(LinuxKernelTest): '3.19.3.mtoman.20150408') exec_command_and_wait_for_pattern(self, 'reboot', 'reboot: Restarting system') + # Wait for VM to shut down gracefully + self.vm.wait() def do_test_mips_malta32el_nanomips(self, kernel_url, kernel_hash): kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash) @@ -506,6 +510,7 @@ class BootLinuxConsole(LinuxKernelTest): 'system-control@1c00000') exec_command_and_wait_for_pattern(self, 'reboot', 'reboot: Restarting system') + # NB: Do not issue vm.wait() here, cubieboard's reboot does not exit! def test_arm_cubieboard_sata(self): """ @@ -550,6 +555,7 @@ class BootLinuxConsole(LinuxKernelTest): 'sda') exec_command_and_wait_for_pattern(self, 'reboot', 'reboot: Restarting system') + # NB: Do not issue vm.wait() here, cubieboard's reboot does not exit! def test_arm_orangepi(self): """ @@ -615,6 +621,8 @@ class BootLinuxConsole(LinuxKernelTest): 'system-control@1c00000') exec_command_and_wait_for_pattern(self, 'reboot', 'reboot: Restarting system') + # Wait for VM to shut down gracefully + self.vm.wait() def test_arm_orangepi_sd(self): """ @@ -662,6 +670,8 @@ class BootLinuxConsole(LinuxKernelTest): '3 packets transmitted, 3 packets received, 0% packet loss') exec_command_and_wait_for_pattern(self, 'reboot', 'reboot: Restarting system') + # Wait for VM to shut down gracefully + self.vm.wait() @skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited') @skipUnless(P7ZIP_AVAILABLE, '7z not installed') diff --git a/tests/acceptance/linux_ssh_mips_malta.py b/tests/acceptance/linux_ssh_mips_malta.py index 90d7f2f167..25c5c5f741 100644 --- a/tests/acceptance/linux_ssh_mips_malta.py +++ b/tests/acceptance/linux_ssh_mips_malta.py @@ -212,6 +212,8 @@ class LinuxSSH(Test): self.run_common_commands(wordsize) self.shutdown_via_ssh() + # Wait for VM to shut down gracefully + self.vm.wait() def test_mips_malta32eb_kernel3_2_0(self): """ From fdb87f0dc2ed8e4f712a88fb5f9382ceea620223 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:46 -0400 Subject: [PATCH 2331/2595] tests/acceptance: Don't test reboot on cubieboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cubieboard does not have a functioning reboot, it halts and QEMU does not exit. vm.shutdown() is modified in a forthcoming patch that makes it less tolerant of race conditions on shutdown; tests should consciously decide to WAIT or to SHUTDOWN qemu. So long as this test is attempting to reboot, the correct choice would be to WAIT for the VM to exit. However, since that's broken, we should SHUTDOWN instead. SHUTDOWN is indeed what already happens when the test performs teardown, however, if anyone fixes cubieboard reboot in the future, this test will develop a new race condition that might be hard to debug. Therefore: remove the reboot test and make it obvious that the VM is still running when the test concludes, where the test teardown will do the right thing. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Message-Id: <20200710050649.32434-10-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/boot_linux_console.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 5867ef760c..8b8b828bc5 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -508,9 +508,7 @@ class BootLinuxConsole(LinuxKernelTest): 'Allwinner sun4i/sun5i') exec_command_and_wait_for_pattern(self, 'cat /proc/iomem', 'system-control@1c00000') - exec_command_and_wait_for_pattern(self, 'reboot', - 'reboot: Restarting system') - # NB: Do not issue vm.wait() here, cubieboard's reboot does not exit! + # cubieboard's reboot is not functioning; omit reboot test. def test_arm_cubieboard_sata(self): """ @@ -553,9 +551,7 @@ class BootLinuxConsole(LinuxKernelTest): 'Allwinner sun4i/sun5i') exec_command_and_wait_for_pattern(self, 'cat /proc/partitions', 'sda') - exec_command_and_wait_for_pattern(self, 'reboot', - 'reboot: Restarting system') - # NB: Do not issue vm.wait() here, cubieboard's reboot does not exit! + # cubieboard's reboot is not functioning; omit reboot test. def test_arm_orangepi(self): """ From 193bf1c061ce0bb078ebc153facb9f31fe139d72 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:47 -0400 Subject: [PATCH 2332/2595] python/machine.py: split shutdown into hard and soft flavors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is done primarily to avoid the 'bare except' pattern, which suppresses all exceptions during shutdown and can obscure errors. Replace this with a pattern that isolates the different kind of shutdown paradigms (_hard_shutdown and _soft_shutdown), and a new fallback shutdown handler (_do_shutdown) that gracefully attempts one before the other. This split now also ensures that no matter what happens, _post_shutdown() is always invoked. shutdown() changes in behavior such that if it attempts to do a graceful shutdown and is unable to, it will now always raise an exception to indicate this. This can be avoided by the test writer in three ways: 1. If the VM is expected to have already exited or is in the process of exiting, wait() can be used instead of shutdown() to clean up resources instead. This helps avoid race conditions in shutdown. 2. If a test writer is expecting graceful shutdown to fail, shutdown should be called in a try...except block. 3. If the test writer has no interest in performing a graceful shutdown at all, kill() can be used instead. Handling shutdown in this way makes it much more explicit which type of shutdown we want and allows the library to report problems with this process. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Message-Id: <20200710050649.32434-11-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 98 +++++++++++++++++++++++++++++++++++------- 1 file changed, 83 insertions(+), 15 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 3f0b873f58..a955e3f221 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -49,6 +49,12 @@ class QEMUMachineAddDeviceError(QEMUMachineError): """ +class AbnormalShutdown(QEMUMachineError): + """ + Exception raised when a graceful shutdown was requested, but not performed. + """ + + class MonitorResponseError(qmp.QMPError): """ Represents erroneous QMP monitor reply @@ -376,6 +382,7 @@ class QEMUMachine: """ Perform any cleanup that needs to happen before the VM exits. + May be invoked by both soft and hard shutdown in failover scenarios. Called additionally by _post_shutdown for comprehensive cleanup. """ # If we keep the console socket open, we may deadlock waiting @@ -385,32 +392,93 @@ class QEMUMachine: self._console_socket.close() self._console_socket = None + def _hard_shutdown(self) -> None: + """ + Perform early cleanup, kill the VM, and wait for it to terminate. + + :raise subprocess.Timeout: When timeout is exceeds 60 seconds + waiting for the QEMU process to terminate. + """ + self._early_cleanup() + self._popen.kill() + self._popen.wait(timeout=60) + + def _soft_shutdown(self, has_quit: bool = False, + timeout: Optional[int] = 3) -> None: + """ + Perform early cleanup, attempt to gracefully shut down the VM, and wait + for it to terminate. + + :param has_quit: When True, don't attempt to issue 'quit' QMP command + :param timeout: Optional timeout in seconds for graceful shutdown. + Default 3 seconds, A value of None is an infinite wait. + + :raise ConnectionReset: On QMP communication errors + :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for + the QEMU process to terminate. + """ + self._early_cleanup() + + if self._qmp is not None: + if not has_quit: + # Might raise ConnectionReset + self._qmp.cmd('quit') + + # May raise subprocess.TimeoutExpired + self._popen.wait(timeout=timeout) + + def _do_shutdown(self, has_quit: bool = False, + timeout: Optional[int] = 3) -> None: + """ + Attempt to shutdown the VM gracefully; fallback to a hard shutdown. + + :param has_quit: When True, don't attempt to issue 'quit' QMP command + :param timeout: Optional timeout in seconds for graceful shutdown. + Default 3 seconds, A value of None is an infinite wait. + + :raise AbnormalShutdown: When the VM could not be shut down gracefully. + The inner exception will likely be ConnectionReset or + subprocess.TimeoutExpired. In rare cases, non-graceful termination + may result in its own exceptions, likely subprocess.TimeoutExpired. + """ + try: + self._soft_shutdown(has_quit, timeout) + except Exception as exc: + self._hard_shutdown() + raise AbnormalShutdown("Could not perform graceful shutdown") \ + from exc + def shutdown(self, has_quit: bool = False, hard: bool = False, timeout: Optional[int] = 3) -> None: """ - Terminate the VM and clean up + Terminate the VM (gracefully if possible) and perform cleanup. + Cleanup will always be performed. + + If the VM has not yet been launched, or shutdown(), wait(), or kill() + have already been called, this method does nothing. + + :param has_quit: When true, do not attempt to issue 'quit' QMP command. + :param hard: When true, do not attempt graceful shutdown, and + suppress the SIGKILL warning log message. + :param timeout: Optional timeout in seconds for graceful shutdown. + Default 3 seconds, A value of None is an infinite wait. """ if not self._launched: return - self._early_cleanup() - - if self.is_running(): + try: if hard: - self._popen.kill() - elif self._qmp: - try: - if not has_quit: - self._qmp.cmd('quit') - self._popen.wait(timeout=timeout) - except: - self._popen.kill() - self._popen.wait(timeout=timeout) - - self._post_shutdown() + self._hard_shutdown() + else: + self._do_shutdown(has_quit, timeout=timeout) + finally: + self._post_shutdown() def kill(self): + """ + Terminate the VM forcefully, wait for it to exit, and perform cleanup. + """ self.shutdown(hard=True) def wait(self, timeout: Optional[int] = None) -> None: From de6e08b5b987afbaf22e37e7f9e34421fb76ef3f Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:48 -0400 Subject: [PATCH 2333/2595] python/machine.py: re-add sigkill warning suppression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the user kills QEMU on purpose, we don't need to warn them about that having happened: they know already. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cleber Rosa Message-Id: <20200710050649.32434-12-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index a955e3f221..736a3c906f 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -22,6 +22,7 @@ import logging import os import subprocess import shutil +import signal import socket import tempfile from typing import Optional, Type @@ -133,6 +134,7 @@ class QEMUMachine: self._console_address = None self._console_socket = None self._remove_files = [] + self._user_killed = False self._console_log_path = console_log if self._console_log_path: # In order to log the console, buffering needs to be enabled. @@ -327,7 +329,8 @@ class QEMUMachine: self._remove_if_exists(self._remove_files.pop()) exitcode = self.exitcode() - if exitcode is not None and exitcode < 0: + if (exitcode is not None and exitcode < 0 + and not (self._user_killed and exitcode == -signal.SIGKILL)): msg = 'qemu received signal %i; command: "%s"' if self._qemu_full_args: command = ' '.join(self._qemu_full_args) @@ -335,6 +338,7 @@ class QEMUMachine: command = '' LOG.warning(msg, -int(exitcode), command) + self._user_killed = False self._launched = False def launch(self): @@ -469,6 +473,7 @@ class QEMUMachine: try: if hard: + self._user_killed = True self._hard_shutdown() else: self._do_shutdown(has_quit, timeout=timeout) From 04f0e36eba7b1a06e413a0690d4b1a24994d99fe Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:06:49 -0400 Subject: [PATCH 2334/2595] python/machine.py: change default wait timeout to 3 seconds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Machine.wait() does not appear to be used except in the acceptance tests, and an infinite timeout by default in a test suite is not the most helpful. Change it to 3 seconds, like the default shutdown timeout. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Message-Id: <20200710050649.32434-13-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 736a3c906f..69055189bd 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -486,12 +486,12 @@ class QEMUMachine: """ self.shutdown(hard=True) - def wait(self, timeout: Optional[int] = None) -> None: + def wait(self, timeout: Optional[int] = 3) -> None: """ Wait for the VM to power off and perform post-shutdown cleanup. :param timeout: Optional timeout in seconds. - Default None, an infinite wait. + Default 3 seconds, A value of None is an infinite wait. """ self.shutdown(has_quit=True, timeout=timeout) From a5d76376d65d8777f28bb064412a8d72fa2c7953 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:22:05 -0400 Subject: [PATCH 2335/2595] python/qmp.py: Define common types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define some common types that we'll need to annotate a lot of other functions going forward. Signed-off-by: John Snow Reviewed-by: Kevin Wolf Message-Id: <20200710052220.3306-2-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/qmp.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index e64b6b5faa..8388c7b603 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -12,13 +12,31 @@ import errno import socket import logging from typing import ( + Any, + Dict, Optional, TextIO, Type, + Tuple, + Union, ) from types import TracebackType +# QMPMessage is a QMP Message of any kind. +# e.g. {'yee': 'haw'} +# +# QMPReturnValue is the inner value of return values only. +# {'return': {}} is the QMPMessage, +# {} is the QMPReturnValue. +QMPMessage = Dict[str, Any] +QMPReturnValue = Dict[str, Any] + +InternetAddrT = Tuple[str, str] +UnixAddrT = str +SocketAddrT = Union[InternetAddrT, UnixAddrT] + + class QMPError(Exception): """ QMP base exception From 2012453ddde0506d044d4739257227c6868028b6 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:22:06 -0400 Subject: [PATCH 2336/2595] iotests.py: use qemu.qmp type aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit iotests.py should use the type definitions from qmp.py instead of its own. Signed-off-by: John Snow Reviewed-by: Kevin Wolf Message-Id: <20200710052220.3306-3-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- tests/qemu-iotests/iotests.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 8b760405ee..3590ed78a0 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -35,13 +35,10 @@ import unittest # pylint: disable=import-error, wrong-import-position sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu import qtest +from qemu.qmp import QMPMessage assert sys.version_info >= (3, 6) -# Type Aliases -QMPResponse = Dict[str, Any] - - # Use this logger for logging messages directly from the iotests module logger = logging.getLogger('qemu.iotests') logger.addHandler(logging.NullHandler()) @@ -561,7 +558,7 @@ class VM(qtest.QEMUQtestMachine): self._args.append(addr) return self - def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse: + def hmp(self, command_line: str, use_log: bool = False) -> QMPMessage: cmd = 'human-monitor-command' kwargs = {'command-line': command_line} if use_log: @@ -582,7 +579,7 @@ class VM(qtest.QEMUQtestMachine): self.hmp(f'qemu-io {drive} "remove_break bp_{drive}"') def hmp_qemu_io(self, drive: str, cmd: str, - use_log: bool = False) -> QMPResponse: + use_log: bool = False) -> QMPMessage: """Write to a given drive using an HMP command""" return self.hmp(f'qemu-io {drive} "{cmd}"', use_log=use_log) From e3a23b4803a3939c7e24e8946880f5ef369ef781 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:22:07 -0400 Subject: [PATCH 2337/2595] python/qmp.py: re-absorb MonitorResponseError MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When I initially split this out, I considered this more of a machine error than a QMP protocol error, but I think that's misguided. Move this back to qmp.py and name it QMPResponseError. Convert qmp.command() to use this exception type. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Kevin Wolf Message-Id: <20200710052220.3306-4-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 15 +-------------- python/qemu/qmp.py | 17 +++++++++++++++-- scripts/render_block_graph.py | 7 +++++-- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 69055189bd..80c4d4a8b6 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -56,19 +56,6 @@ class AbnormalShutdown(QEMUMachineError): """ -class MonitorResponseError(qmp.QMPError): - """ - Represents erroneous QMP monitor reply - """ - def __init__(self, reply): - try: - desc = reply["error"]["desc"] - except KeyError: - desc = reply - super().__init__(desc) - self.reply = reply - - class QEMUMachine: """ A QEMU VM @@ -533,7 +520,7 @@ class QEMUMachine: if reply is None: raise qmp.QMPError("Monitor is closed") if "error" in reply: - raise MonitorResponseError(reply) + raise qmp.QMPResponseError(reply) return reply["return"] def get_qmp_event(self, wait=False): diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index 8388c7b603..aa8a666b8a 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -61,6 +61,19 @@ class QMPTimeoutError(QMPError): """ +class QMPResponseError(QMPError): + """ + Represents erroneous QMP monitor reply + """ + def __init__(self, reply: QMPMessage): + try: + desc = reply['error']['desc'] + except KeyError: + desc = reply + super().__init__(desc) + self.reply = reply + + class QEMUMonitorProtocol: """ Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP) and then @@ -251,8 +264,8 @@ class QEMUMonitorProtocol: Build and send a QMP command to the monitor, report errors if any """ ret = self.cmd(cmd, kwds) - if "error" in ret: - raise Exception(ret['error']['desc']) + if 'error' in ret: + raise QMPResponseError(ret) return ret['return'] def pull_event(self, wait=False): diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py index 409b4321f2..da6acf050d 100755 --- a/scripts/render_block_graph.py +++ b/scripts/render_block_graph.py @@ -25,7 +25,10 @@ import json from graphviz import Digraph sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python')) -from qemu.machine import MonitorResponseError +from qemu.qmp import ( + QEMUMonitorProtocol, + QMPResponseError, +) def perm(arr): @@ -102,7 +105,7 @@ class LibvirtGuest(): reply = json.loads(subprocess.check_output(ar)) if 'error' in reply: - raise MonitorResponseError(reply) + raise QMPResponseError(reply) return reply['return'] From ef5d474472426eda6abf8128cdb1d026af94862b Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:22:08 -0400 Subject: [PATCH 2338/2595] python/qmp.py: Do not return None from cmd_obj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes typing the qmp library difficult, as it necessitates wrapping Optional[] around the type for every return type up the stack. At some point, it becomes difficult to discern or remember why it's None instead of the expected object. Use the python exception system to tell us exactly why we didn't get an object. Remove this special-cased return. Signed-off-by: John Snow Reviewed-by: Kevin Wolf Message-Id: <20200710052220.3306-5-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/qmp.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index aa8a666b8a..ef3c919b76 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -225,22 +225,18 @@ class QEMUMonitorProtocol: self.__sockfile = self.__sock.makefile(mode='r') return self.__negotiate_capabilities() - def cmd_obj(self, qmp_cmd): + def cmd_obj(self, qmp_cmd: QMPMessage) -> QMPMessage: """ Send a QMP command to the QMP Monitor. @param qmp_cmd: QMP command to be sent as a Python dict - @return QMP response as a Python dict or None if the connection has - been closed + @return QMP response as a Python dict """ self.logger.debug(">>> %s", qmp_cmd) - try: - self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8')) - except OSError as err: - if err.errno == errno.EPIPE: - return None - raise err + self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8')) resp = self.__json_read() + if resp is None: + raise QMPConnectError("Unexpected empty reply from server") self.logger.debug("<<< %s", resp) return resp From 2e2d93051753067fc5b888fdc18831127a4a900e Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:22:09 -0400 Subject: [PATCH 2339/2595] python/qmp.py: add casts to JSON deserialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mypy and python type hints are not powerful enough to properly describe JSON messages in Python 3.6. The best we can do, generally, is describe them as Dict[str, Any]. Add casts to coerce this type for static analysis; but do NOT enforce this type at runtime in any way. Note: Python 3.8 adds a TypedDict construct which allows for the description of more arbitrary Dictionary shapes. There is a third-party module, "Pydantic", which is compatible with 3.6 that can be used instead of the JSON library that parses JSON messages to fully-typed Python objects, and may be preferable in some cases. (That is well beyond the scope of this commit or series.) Signed-off-by: John Snow Reviewed-by: Kevin Wolf Message-Id: <20200710052220.3306-6-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/qmp.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index ef3c919b76..1ae36050a4 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -13,6 +13,7 @@ import socket import logging from typing import ( Any, + cast, Dict, Optional, TextIO, @@ -130,7 +131,10 @@ class QEMUMonitorProtocol: data = self.__sockfile.readline() if not data: return None - resp = json.loads(data) + # By definition, any JSON received from QMP is a QMPMessage, + # and we are asserting only at static analysis time that it + # has a particular shape. + resp: QMPMessage = json.loads(data) if 'event' in resp: self.logger.debug("<<< %s", resp) self.__events.append(resp) @@ -262,7 +266,7 @@ class QEMUMonitorProtocol: ret = self.cmd(cmd, kwds) if 'error' in ret: raise QMPResponseError(ret) - return ret['return'] + return cast(QMPReturnValue, ret['return']) def pull_event(self, wait=False): """ From 84dcdf0887cdaaba7300442482c99e5064865a2d Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 10 Jul 2020 01:22:10 -0400 Subject: [PATCH 2340/2595] python/qmp.py: add QMPProtocolError MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the case that we receive a reply but are unable to understand it, use this exception name to indicate that case. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Kevin Wolf Message-Id: <20200710052220.3306-7-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/qmp.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index 1ae36050a4..7935dababb 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -62,6 +62,12 @@ class QMPTimeoutError(QMPError): """ +class QMPProtocolError(QMPError): + """ + QMP protocol error; unexpected response + """ + + class QMPResponseError(QMPError): """ Represents erroneous QMP monitor reply @@ -266,6 +272,10 @@ class QEMUMonitorProtocol: ret = self.cmd(cmd, kwds) if 'error' in ret: raise QMPResponseError(ret) + if 'return' not in ret: + raise QMPProtocolError( + "'return' key not found in QMP response '{}'".format(str(ret)) + ) return cast(QMPReturnValue, ret['return']) def pull_event(self, wait=False): From 93154e767f1b886e6d258178821d400333042a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 13 Jul 2020 21:04:12 +0100 Subject: [PATCH 2341/2595] docs/devel: fix grammar in multi-thread-tcg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review comment came just too late ;-) Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200713200415.26214-9-alex.bennee@linaro.org> --- docs/devel/multi-thread-tcg.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/devel/multi-thread-tcg.rst b/docs/devel/multi-thread-tcg.rst index 42158b77c7..21483870db 100644 --- a/docs/devel/multi-thread-tcg.rst +++ b/docs/devel/multi-thread-tcg.rst @@ -107,7 +107,7 @@ including: - debugging operations (breakpoint insertion/removal) - some CPU helper functions - - linux-user spawning it's first thread + - linux-user spawning its first thread This is done with the async_safe_run_on_cpu() mechanism to ensure all vCPUs are quiescent when changes are being made to shared global From a77312e77c7d19702aa4e2ddefd20cae060a7fb9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 13 Jul 2020 21:04:06 +0100 Subject: [PATCH 2342/2595] tests/docker: Remove the libssh workaround from the ubuntu 20.04 image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The libssh problem only exists in Ubuntu 18.04 - we can enable it in 20.04 again. Signed-off-by: Thomas Huth Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200713185237.9419-1-thuth@redhat.com> Message-Id: <20200713200415.26214-3-alex.bennee@linaro.org> --- tests/docker/dockerfiles/ubuntu2004.docker | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index f7aac840bf..8d10934a2a 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -65,9 +65,6 @@ RUN apt-get update && \ RUN dpkg -l $PACKAGES | sort > /packages.txt ENV FEATURES clang tsan pyyaml sdl2 -# https://bugs.launchpad.net/qemu/+bug/1838763 -ENV QEMU_CONFIGURE_OPTS --disable-libssh - # Apply patch https://reviews.llvm.org/D75820 # This is required for TSan in clang-10 to compile with QEMU. RUN sed -i 's/^const/static const/g' /usr/lib/llvm-10/lib/clang/10.0.0/include/sanitizer/tsan_interface.h From f73e485285bc2da944a08e1dd20a30df93e23f25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 13 Jul 2020 21:04:07 +0100 Subject: [PATCH 2343/2595] docker.py: fix fetching of FROM layers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This worked on a system that was already bootstrapped because the stage 2 images already existed even if they wouldn't be used. What we should have pulled down was the FROM line containers first because building on gitlab doesn't have the advantage of using our build system to build the pre-requisite bits. We still pull the image we want to build just in case we can use the cached data. Signed-off-by: Alex Bennée Reviewed-by: Daniel P. Berrangé Tested-by: Philippe Mathieu-Daudé Message-Id: <20200713200415.26214-4-alex.bennee@linaro.org> --- tests/docker/docker.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/docker/docker.py b/tests/docker/docker.py index 2d67bbd15a..c9f20d8d09 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -306,14 +306,18 @@ class Docker(object): checksum = _text_checksum(_dockerfile_preprocess(dockerfile)) if registry is not None: - # see if we can fetch a cache copy, may fail... - pull_args = ["pull", "%s/%s" % (registry, tag)] - if self._do(pull_args, quiet=quiet) == 0: + sources = re.findall("FROM qemu\/(.*)", dockerfile) + # Fetch any cache layers we can, may fail + for s in sources: + pull_args = ["pull", "%s/qemu/%s" % (registry, s)] + if self._do(pull_args, quiet=quiet) != 0: + registry = None + break + # Make substitutions + if registry is not None: dockerfile = dockerfile.replace("FROM qemu/", "FROM %s/qemu/" % (registry)) - else: - registry = None tmp_df = tempfile.NamedTemporaryFile(mode="w+t", encoding='utf-8', @@ -339,6 +343,8 @@ class Docker(object): build_args += ["--build-arg", "BUILDKIT_INLINE_CACHE=1"] if registry is not None: + pull_args = ["pull", "%s/%s" % (registry, tag)] + self._do(pull_args, quiet=quiet) cache = "%s/%s" % (registry, tag) build_args += ["--cache-from", cache] build_args += argv From 6f60a240f60122fe2df402402311bf425f34e553 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 13 Jul 2020 20:22:35 +0200 Subject: [PATCH 2344/2595] gitlab-ci/containers: Add missing wildcard where we should look for changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tests/docker/* wildcard seems to only match the files that are directly in the tests/docker folder - but changes to the files in the directory tests/docker/dockerfiles are currently ignored. Seems like we need a separate entry to match the files in that folder. With this wildcard added, the stages now get re-run successfully when something in the dockerfiles has been changed. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200713182235.30379-1-thuth@redhat.com> --- .gitlab-ci.d/containers.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index f3c0ca4d61..8c89efeb6d 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -24,6 +24,7 @@ - changes: - .gitlab-ci.d/containers.yml - tests/docker/* + - tests/docker/dockerfiles/* - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - if: '$CI_COMMIT_REF_NAME == "testing/next"' From 8cdf91243f7515f424b78d5469d64c34ee534783 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Mon, 13 Jul 2020 21:04:08 +0100 Subject: [PATCH 2345/2595] fpu/softfloat: fix up float16 nan recognition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: LIU Zhiwei Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200712234521.3972-2-zhiwei_liu@c-sky.com> Message-Id: <20200713200415.26214-5-alex.bennee@linaro.org> --- fpu/softfloat-specialize.inc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fpu/softfloat-specialize.inc.c b/fpu/softfloat-specialize.inc.c index 44f5b661f8..034d18199c 100644 --- a/fpu/softfloat-specialize.inc.c +++ b/fpu/softfloat-specialize.inc.c @@ -254,7 +254,7 @@ bool float16_is_quiet_nan(float16 a_, float_status *status) if (snan_bit_is_one(status)) { return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF); } else { - return ((a & ~0x8000) >= 0x7C80); + return ((a >> 9) & 0x3F) == 0x3F; } #endif } @@ -271,7 +271,7 @@ bool float16_is_signaling_nan(float16 a_, float_status *status) #else uint16_t a = float16_val(a_); if (snan_bit_is_one(status)) { - return ((a & ~0x8000) >= 0x7C80); + return ((a >> 9) & 0x3F) == 0x3F; } else { return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF); } From 777dddc501fa31bc9afff6de5e55dbf799e1703b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 13 Jul 2020 21:04:09 +0100 Subject: [PATCH 2346/2595] tests/plugins: don't unconditionally add -Wpsabi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not all compilers support the -Wpsabi (clang-9 in my case). To handle this gracefully we pare back the shared build machinery so the Makefile is relatively "standalone". We still take advantage of config-host.mak as configure has done a bunch of probing for us but that is it. Fixes: bac8d222a Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20200713200415.26214-6-alex.bennee@linaro.org> --- configure | 3 +++ tests/plugin/Makefile | 22 ++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/configure b/configure index bc3b9ad931..b751c853f5 100755 --- a/configure +++ b/configure @@ -7115,6 +7115,9 @@ echo "GIT_UPDATE=$git_update" >> $config_host_mak echo "ARCH=$ARCH" >> $config_host_mak +echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak +echo "GLIB_LDFLAGS=$glib_ldflags" >> $config_host_mak + if test "$default_devices" = "yes" ; then echo "CONFIG_MINIKCONF_MODE=--defconfig" >> $config_host_mak else diff --git a/tests/plugin/Makefile b/tests/plugin/Makefile index 3a50451428..e9348fde4a 100644 --- a/tests/plugin/Makefile +++ b/tests/plugin/Makefile @@ -1,9 +1,16 @@ +# -*- Mode: makefile -*- +# +# This Makefile example is fairly independent from the main makefile +# so users can take and adapt it for their build. We only really +# include config-host.mak so we don't have to repeat probing for +# cflags that the main configure has already done for us. +# + BUILD_DIR := $(CURDIR)/../.. include $(BUILD_DIR)/config-host.mak -include $(SRC_PATH)/rules.mak -$(call set-vpath, $(SRC_PATH)/tests/plugin) +VPATH += $(SRC_PATH)/tests/plugin NAMES := NAMES += bb @@ -17,11 +24,18 @@ NAMES += lockstep SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES))) -QEMU_CFLAGS += -fPIC -Wpsabi -QEMU_CFLAGS += -I$(SRC_PATH)/include/qemu +# The main QEMU uses Glib extensively so it's perfectly fine to use it +# in plugins (which many example do). +CFLAGS = $(GLIB_CFLAGS) +CFLAGS += -fPIC +CFLAGS += $(if $(findstring no-psabi,$(QEMU_CFLAGS)),-Wpsabi) +CFLAGS += -I$(SRC_PATH)/include/qemu all: $(SONAMES) +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + lib%.so: %.o $(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDLIBS) From 2f3a57ee47df970d19fa5b324d44aab857d43517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 13 Jul 2020 21:04:10 +0100 Subject: [PATCH 2347/2595] cputlb: ensure we save the IOTLB data in case of reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Any write to a device might cause a re-arrangement of memory triggering a TLB flush and potential re-size of the TLB invalidating previous entries. This would cause users of qemu_plugin_get_hwaddr() to see the warning: invalid use of qemu_plugin_get_hwaddr because of the failed tlb_lookup which should always succeed. To prevent this we save the IOTLB data in case it is later needed by a plugin doing a lookup. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200713200415.26214-7-alex.bennee@linaro.org> --- accel/tcg/cputlb.c | 38 +++++++++++++++++++++++++++++++++++--- include/hw/core/cpu.h | 16 ++++++++++++++++ include/qemu/typedefs.h | 1 + 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 1e815357c7..d370aedb47 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1073,6 +1073,24 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, return val; } +/* + * Save a potentially trashed IOTLB entry for later lookup by plugin. + * + * We also need to track the thread storage address because the RCU + * cleanup that runs when we leave the critical region (the current + * execution) is actually in a different thread. + */ +static void save_iotlb_data(CPUState *cs, hwaddr addr, + MemoryRegionSection *section, hwaddr mr_offset) +{ +#ifdef CONFIG_PLUGIN + SavedIOTLB *saved = &cs->saved_iotlb; + saved->addr = addr; + saved->section = section; + saved->mr_offset = mr_offset; +#endif +} + static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, int mmu_idx, uint64_t val, target_ulong addr, uintptr_t retaddr, MemOp op) @@ -1092,6 +1110,12 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, } cpu->mem_io_pc = retaddr; + /* + * The memory_region_dispatch may trigger a flush/resize + * so for plugins we save the iotlb_data just in case. + */ + save_iotlb_data(cpu, iotlbentry->addr, section, mr_offset); + if (mr->global_locking && !qemu_mutex_iothread_locked()) { qemu_mutex_lock_iothread(); locked = true; @@ -1381,8 +1405,11 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, * in the softmmu lookup code (or helper). We don't handle re-fills or * checking the victim table. This is purely informational. * - * This should never fail as the memory access being instrumented - * should have just filled the TLB. + * This almost never fails as the memory access being instrumented + * should have just filled the TLB. The one corner case is io_writex + * which can cause TLB flushes and potential resizing of the TLBs + * loosing the information we need. In those cases we need to recover + * data from a copy of the io_tlb entry. */ bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, @@ -1406,8 +1433,13 @@ bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, data->v.ram.hostaddr = addr + tlbe->addend; } return true; + } else { + SavedIOTLB *saved = &cpu->saved_iotlb; + data->is_io = true; + data->v.io.section = saved->section; + data->v.io.offset = saved->mr_offset; + return true; } - return false; } #endif diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 5542577d2b..8f145733ce 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -259,6 +259,18 @@ struct CPUWatchpoint { QTAILQ_ENTRY(CPUWatchpoint) entry; }; +#ifdef CONFIG_PLUGIN +/* + * For plugins we sometime need to save the resolved iotlb data before + * the memory regions get moved around by io_writex. + */ +typedef struct SavedIOTLB { + hwaddr addr; + MemoryRegionSection *section; + hwaddr mr_offset; +} SavedIOTLB; +#endif + struct KVMState; struct kvm_run; @@ -417,7 +429,11 @@ struct CPUState { DECLARE_BITMAP(plugin_mask, QEMU_PLUGIN_EV_MAX); +#ifdef CONFIG_PLUGIN GArray *plugin_mem_cbs; + /* saved iotlb data from io_writex */ + SavedIOTLB saved_iotlb; +#endif /* TODO Move common fields from CPUArchState here. */ int cpu_index; diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 15f5047bf1..427027a970 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -116,6 +116,7 @@ typedef struct QObject QObject; typedef struct QString QString; typedef struct RAMBlock RAMBlock; typedef struct Range Range; +typedef struct SavedIOTLB SavedIOTLB; typedef struct SHPCDevice SHPCDevice; typedef struct SSIBus SSIBus; typedef struct VirtIODevice VirtIODevice; From 406b53c9ca669b8551d4cde27f2cde03135d0d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 13 Jul 2020 21:04:11 +0100 Subject: [PATCH 2348/2595] plugins: expand the bb plugin to be thread safe and track per-cpu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While there isn't any easy way to make the inline counts thread safe we can ensure the callback based ones are. While we are at it we can reduce introduce a new option ("idle") to dump a report of the current bb and insn count each time a vCPU enters the idle state. Signed-off-by: Alex Bennée Reviewed-by: Robert Foley Cc: Dave Bort Message-Id: <20200713200415.26214-8-alex.bennee@linaro.org> --- tests/plugin/bb.c | 97 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 84 insertions(+), 13 deletions(-) diff --git a/tests/plugin/bb.c b/tests/plugin/bb.c index df19fd359d..e4cc7fdd6e 100644 --- a/tests/plugin/bb.c +++ b/tests/plugin/bb.c @@ -16,24 +16,67 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; -static uint64_t bb_count; -static uint64_t insn_count; +typedef struct { + GMutex lock; + int index; + uint64_t bb_count; + uint64_t insn_count; +} CPUCount; + +/* Used by the inline & linux-user counts */ static bool do_inline; +static CPUCount inline_count; + +/* Dump running CPU total on idle? */ +static bool idle_report; +static GPtrArray *counts; +static int max_cpus; + +static void gen_one_cpu_report(CPUCount *count, GString *report) +{ + if (count->bb_count) { + g_string_append_printf(report, "CPU%d: " + "bb's: %" PRIu64", insns: %" PRIu64 "\n", + count->index, + count->bb_count, count->insn_count); + } +} static void plugin_exit(qemu_plugin_id_t id, void *p) { - g_autofree gchar *out = g_strdup_printf( - "bb's: %" PRIu64", insns: %" PRIu64 "\n", - bb_count, insn_count); - qemu_plugin_outs(out); + g_autoptr(GString) report = g_string_new(""); + + if (do_inline || !max_cpus) { + g_string_printf(report, "bb's: %" PRIu64", insns: %" PRIu64 "\n", + inline_count.bb_count, inline_count.insn_count); + } else { + g_ptr_array_foreach(counts, (GFunc) gen_one_cpu_report, report); + } + qemu_plugin_outs(report->str); +} + +static void vcpu_idle(qemu_plugin_id_t id, unsigned int cpu_index) +{ + CPUCount *count = g_ptr_array_index(counts, cpu_index); + g_autoptr(GString) report = g_string_new(""); + gen_one_cpu_report(count, report); + + if (report->len > 0) { + g_string_prepend(report, "Idling "); + qemu_plugin_outs(report->str); + } } static void vcpu_tb_exec(unsigned int cpu_index, void *udata) { - unsigned long n_insns = (unsigned long)udata; + CPUCount *count = max_cpus ? + g_ptr_array_index(counts, cpu_index) : &inline_count; - insn_count += n_insns; - bb_count++; + unsigned long n_insns = (unsigned long)udata; + g_mutex_lock(&count->lock); + count->insn_count += n_insns; + count->bb_count++; + g_mutex_unlock(&count->lock); } static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) @@ -42,9 +85,10 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) if (do_inline) { qemu_plugin_register_vcpu_tb_exec_inline(tb, QEMU_PLUGIN_INLINE_ADD_U64, - &bb_count, 1); + &inline_count.bb_count, 1); qemu_plugin_register_vcpu_tb_exec_inline(tb, QEMU_PLUGIN_INLINE_ADD_U64, - &insn_count, n_insns); + &inline_count.insn_count, + n_insns); } else { qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec, QEMU_PLUGIN_CB_NO_REGS, @@ -56,8 +100,35 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, int argc, char **argv) { - if (argc && strcmp(argv[0], "inline") == 0) { - do_inline = true; + int i; + + for (i = 0; i < argc; i++) { + char *opt = argv[i]; + if (g_strcmp0(opt, "inline") == 0) { + do_inline = true; + } else if (g_strcmp0(opt, "idle") == 0) { + idle_report = true; + } else { + fprintf(stderr, "option parsing failed: %s\n", opt); + return -1; + } + } + + if (info->system_emulation && !do_inline) { + max_cpus = info->system.max_vcpus; + counts = g_ptr_array_new(); + for (i = 0; i < max_cpus; i++) { + CPUCount *count = g_new0(CPUCount, 1); + g_mutex_init(&count->lock); + count->index = i; + g_ptr_array_add(counts, count); + } + } else if (!do_inline) { + g_mutex_init(&inline_count.lock); + } + + if (idle_report) { + qemu_plugin_register_vcpu_idle_cb(id, vcpu_idle); } qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); From 0571d280d057b851e3bb3ea7c350b86c950aea6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 14 Jul 2020 18:55:16 +0100 Subject: [PATCH 2349/2595] .travis.yml: skip ppc64abi32-linux-user with plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We actually see failures on threadcount running without plugins: retry.py -n 1000 -c -- \ ./ppc64abi32-linux-user/qemu-ppc64abi32 \ ./tests/tcg/ppc64abi32-linux-user/threadcount which reports: 0: 978 times (97.80%), avg time 0.270 (0.01 varience/0.08 deviation) -6: 21 times (2.10%), avg time 0.336 (0.01 varience/0.12 deviation) -11: 1 times (0.10%), avg time 0.502 (0.00 varience/0.00 deviation) Ran command 1000 times, 978 passes But when running with plugins we hit the failure a lot more often: 0: 91 times (91.00%), avg time 0.302 (0.04 varience/0.19 deviation) -11: 9 times (9.00%), avg time 0.558 (0.01 varience/0.11 deviation) Ran command 100 times, 91 passes The crash occurs in guest code which is the same in both pass and fail cases. However we see various messages reported on the console about corrupted memory lists which seems to imply the guest memory allocation is corrupted. This lines up with the seg fault being in the guest __libc_free function. So we think this is a guest bug which is exacerbated by various modes of translation. If anyone has access to real hardware to soak test the test case we could prove this properly. Signed-off-by: Alex Bennée Acked-by: David Gibson Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20200714175516.5475-1-alex.bennee@linaro.org> --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ab429500fc..6695c0620f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -350,9 +350,10 @@ jobs: # Run check-tcg against linux-user (with plugins) # we skip sparc64-linux-user until it has been fixed somewhat # we skip cris-linux-user as it doesn't use the common run loop + # we skip ppc64abi32-linux-user as it seems to have a broken libc - name: "GCC plugins check-tcg (user)" env: - - CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user" + - CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user,ppc64abi32-linux-user" - TEST_BUILD_CMD="make build-tcg" - TEST_CMD="make check-tcg" - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg" From 650181007a027034620995eb3d5044cea1ec9b49 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 3 Jul 2020 13:48:13 +0200 Subject: [PATCH 2350/2595] virtio-net: fix removal of failover device If you have a networking device and its virtio failover device, and you remove them in this order: - virtio device - the real device You get qemu crash. See bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1820120 Bug exist on qemu 4.2 and 5.0. But in 5.0 don't shows because commit 77b06bba62034a87cc61a9c8de1309ae3e527d97 somehow papers over it. CC: Jason Wang CC: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin Acked-by: Laurent Vivier Signed-off-by: Juan Quintela Signed-off-by: Jason Wang --- hw/net/virtio-net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 10cc958396..4895af1cbe 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3416,6 +3416,7 @@ static void virtio_net_device_unrealize(DeviceState *dev) g_free(n->vlans); if (n->failover) { + device_listener_unregister(&n->primary_listener); g_free(n->primary_device_id); g_free(n->standby_id); qobject_unref(n->primary_device_dict); From 9a8d949245a0a3f90842d1611f56df6ae705560d Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 29 Jun 2020 04:17:59 +0300 Subject: [PATCH 2351/2595] hw/net: Added CSO for IPv6 Added fix for checksum offload for IPv6 if a backend doesn't have a virtual header. This patch is a part of IPv6 fragmentation. Signed-off-by: Andrew Melnychenko Signed-off-by: Jason Wang --- hw/net/net_tx_pkt.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index 162f802dd7..331c73cfc0 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -468,8 +468,8 @@ static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt) /* num of iovec without vhdr */ uint32_t iov_len = pkt->payload_frags + NET_TX_PKT_PL_START_FRAG - 1; uint16_t csl; - struct ip_header *iphdr; size_t csum_offset = pkt->virt_hdr.csum_start + pkt->virt_hdr.csum_offset; + uint16_t l3_proto = eth_get_l3_proto(iov, 1, iov->iov_len); /* Put zero to checksum field */ iov_from_buf(iov, iov_len, csum_offset, &csum, sizeof csum); @@ -477,9 +477,18 @@ static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt) /* Calculate L4 TCP/UDP checksum */ csl = pkt->payload_len; + csum_cntr = 0; + cso = 0; /* add pseudo header to csum */ - iphdr = pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_base; - csum_cntr = eth_calc_ip4_pseudo_hdr_csum(iphdr, csl, &cso); + if (l3_proto == ETH_P_IP) { + csum_cntr = eth_calc_ip4_pseudo_hdr_csum( + pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_base, + csl, &cso); + } else if (l3_proto == ETH_P_IPV6) { + csum_cntr = eth_calc_ip6_pseudo_hdr_csum( + pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_base, + csl, pkt->l4proto, &cso); + } /* data checksum */ csum_cntr += From a2e5cb7a87206b916506697d22dc31aa0a43d8fe Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Wed, 24 Jun 2020 09:20:41 +0800 Subject: [PATCH 2352/2595] net/colo-compare.c: Expose compare "max_queue_size" to users This patch allow users to set the "max_queue_size" according to their environment. Signed-off-by: Zhang Chen Signed-off-by: Jason Wang --- net/colo-compare.c | 43 ++++++++++++++++++++++++++++++++++++++++++- qemu-options.hx | 5 +++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/net/colo-compare.c b/net/colo-compare.c index 398b7546ff..cc15f23dea 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -59,6 +59,7 @@ static bool colo_compare_active; static QemuMutex event_mtx; static QemuCond event_complete_cond; static int event_unhandled_count; +static uint32_t max_queue_size; /* * + CompareState ++ @@ -222,7 +223,7 @@ static void fill_pkt_tcp_info(void *data, uint32_t *max_ack) */ static int colo_insert_packet(GQueue *queue, Packet *pkt, uint32_t *max_ack) { - if (g_queue_get_length(queue) <= MAX_QUEUE_SIZE) { + if (g_queue_get_length(queue) <= max_queue_size) { if (pkt->ip->ip_p == IPPROTO_TCP) { fill_pkt_tcp_info(pkt, max_ack); g_queue_insert_sorted(queue, @@ -1134,6 +1135,37 @@ static void compare_set_expired_scan_cycle(Object *obj, Visitor *v, s->expired_scan_cycle = value; } +static void get_max_queue_size(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + uint32_t value = max_queue_size; + + visit_type_uint32(v, name, &value, errp); +} + +static void set_max_queue_size(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + Error *local_err = NULL; + uint32_t value; + + visit_type_uint32(v, name, &value, &local_err); + if (local_err) { + goto out; + } + if (!value) { + error_setg(&local_err, "Property '%s.%s' requires a positive value", + object_get_typename(obj), name); + goto out; + } + max_queue_size = value; + +out: + error_propagate(errp, local_err); +} + static void compare_pri_rs_finalize(SocketReadState *pri_rs) { CompareState *s = container_of(pri_rs, CompareState, pri_rs); @@ -1251,6 +1283,11 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) s->expired_scan_cycle = REGULAR_PACKET_CHECK_MS; } + if (!max_queue_size) { + /* Set default queue size to 1024 */ + max_queue_size = MAX_QUEUE_SIZE; + } + if (find_and_check_chardev(&chr, s->pri_indev, errp) || !qemu_chr_fe_init(&s->chr_pri_in, chr, errp)) { return; @@ -1370,6 +1407,10 @@ static void colo_compare_init(Object *obj) compare_get_expired_scan_cycle, compare_set_expired_scan_cycle, NULL, NULL); + object_property_add(obj, "max_queue_size", "uint32", + get_max_queue_size, + set_max_queue_size, NULL, NULL); + s->vnet_hdr = false; object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr, compare_set_vnet_hdr); diff --git a/qemu-options.hx b/qemu-options.hx index d2c1e95bcf..310885c60e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4695,7 +4695,7 @@ SRST stored. The file format is libpcap, so it can be analyzed with tools such as tcpdump or Wireshark. - ``-object colo-compare,id=id,primary_in=chardevid,secondary_in=chardevid,outdev=chardevid,iothread=id[,vnet_hdr_support][,notify_dev=id][,compare_timeout=@var{ms}][,expired_scan_cycle=@var{ms}`` + ``-object colo-compare,id=id,primary_in=chardevid,secondary_in=chardevid,outdev=chardevid,iothread=id[,vnet_hdr_support][,notify_dev=id][,compare_timeout=@var{ms}][,expired_scan_cycle=@var{ms}][,max_queue_size=@var{size}]`` Colo-compare gets packet from primary\_inchardevid and secondary\_inchardevid, than compare primary packet with secondary packet. If the packets are same, we will output @@ -4707,7 +4707,8 @@ SRST vnet\_hdr\_len. Then compare\_timeout=@var{ms} determines the maximum delay colo-compare wait for the packet. The expired\_scan\_cycle=@var{ms} to set the period of scanning - expired primary node network packets. + expired primary node network packets. The max\_queue\_size=@var{size} + is to set the max compare queue size depend on user environment. If you want to use Xen COLO, will need the notify\_dev to notify Xen colo-frame to do checkpoint. From 2b28a7ef90d79ed757f6b1cc512840389dc25748 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Wed, 24 Jun 2020 09:20:42 +0800 Subject: [PATCH 2353/2595] qemu-options.hx: Clean up and fix typo for colo-compare Fix some typo and optimized some descriptions. Signed-off-by: Zhang Chen Signed-off-by: Jason Wang --- qemu-options.hx | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 310885c60e..65147ad971 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4696,24 +4696,24 @@ SRST tools such as tcpdump or Wireshark. ``-object colo-compare,id=id,primary_in=chardevid,secondary_in=chardevid,outdev=chardevid,iothread=id[,vnet_hdr_support][,notify_dev=id][,compare_timeout=@var{ms}][,expired_scan_cycle=@var{ms}][,max_queue_size=@var{size}]`` - Colo-compare gets packet from primary\_inchardevid and - secondary\_inchardevid, than compare primary packet with - secondary packet. If the packets are same, we will output - primary packet to outdevchardevid, else we will notify - colo-frame do checkpoint and send primary packet to - outdevchardevid. In order to improve efficiency, we need to put - the task of comparison in another thread. If it has the - vnet\_hdr\_support flag, colo compare will send/recv packet with - vnet\_hdr\_len. Then compare\_timeout=@var{ms} determines the - maximum delay colo-compare wait for the packet. - The expired\_scan\_cycle=@var{ms} to set the period of scanning - expired primary node network packets. The max\_queue\_size=@var{size} - is to set the max compare queue size depend on user environment. - If you want to use Xen COLO, will need the notify\_dev to + Colo-compare gets packet from primary\_in chardevid and + secondary\_in, then compare whether the payload of primary packet + and secondary packet are the same. If same, it will output + primary packet to out\_dev, else it will notify COLO-framework to do + checkpoint and send primary packet to out\_dev. In order to + improve efficiency, we need to put the task of comparison in + another iothread. If it has the vnet\_hdr\_support flag, + colo compare will send/recv packet with vnet\_hdr\_len. + The compare\_timeout=@var{ms} determines the maximum time of the + colo-compare hold the packet. The expired\_scan\_cycle=@var{ms} + is to set the period of scanning expired primary node network packets. + The max\_queue\_size=@var{size} is to set the max compare queue + size depend on user environment. + If user want to use Xen COLO, need to add the notify\_dev to notify Xen colo-frame to do checkpoint. - we must use it with the help of filter-mirror and - filter-redirector. + COLO-compare must be used with the help of filter-mirror, + filter-redirector and filter-rewriter. :: From 894022e616016fe81745753f14adfbd680a1c7ee Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 7 Jul 2020 20:45:14 +0200 Subject: [PATCH 2354/2595] net: check if the file descriptor is valid before using it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qemu_set_nonblock() checks that the file descriptor can be used and, if not, crashes QEMU. An assert() is used for that. The use of assert() is used to detect programming error and the coredump will allow to debug the problem. But in the case of the tap device, this assert() can be triggered by a misconfiguration by the user. At startup, it's not a real problem, but it can also happen during the hot-plug of a new device, and here it's a problem because we can crash a perfectly healthy system. For instance: # ip link add link virbr0 name macvtap0 type macvtap mode bridge # ip link set macvtap0 up # TAP=/dev/tap$(ip -o link show macvtap0 | cut -d: -f1) # qemu-system-x86_64 -machine q35 -device pcie-root-port,id=pcie-root-port-0 -monitor stdio 9<> $TAP (qemu) netdev_add type=tap,id=hostnet0,vhost=on,fd=9 (qemu) device_add driver=virtio-net-pci,netdev=hostnet0,id=net0,bus=pcie-root-port-0 (qemu) device_del net0 (qemu) netdev_del hostnet0 (qemu) netdev_add type=tap,id=hostnet1,vhost=on,fd=9 qemu-system-x86_64: .../util/oslib-posix.c:247: qemu_set_nonblock: Assertion `f != -1' failed. Aborted (core dumped) To avoid that, add a function, qemu_try_set_nonblock(), that allows to report the problem without crashing. In the same way, we also update the function for vhostfd in net_init_tap_one() and for fd in net_init_socket() (both descriptors are provided by the user and can be wrong). Signed-off-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- include/qemu/sockets.h | 1 + net/socket.c | 9 +++++-- net/tap.c | 25 +++++++++++++++--- util/oslib-posix.c | 26 +++++++++++++------ util/oslib-win32.c | 57 ++++++++++++++++++++++++------------------ 5 files changed, 79 insertions(+), 39 deletions(-) diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 57cd049d6e..7d1f813576 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -18,6 +18,7 @@ int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); int socket_set_cork(int fd, int v); int socket_set_nodelay(int fd); void qemu_set_block(int fd); +int qemu_try_set_nonblock(int fd); void qemu_set_nonblock(int fd); int socket_set_fast_reuse(int fd); diff --git a/net/socket.c b/net/socket.c index c92354049b..2d21fddd9c 100644 --- a/net/socket.c +++ b/net/socket.c @@ -725,13 +725,18 @@ int net_init_socket(const Netdev *netdev, const char *name, } if (sock->has_fd) { - int fd; + int fd, ret; fd = monitor_fd_param(cur_mon, sock->fd, errp); if (fd == -1) { return -1; } - qemu_set_nonblock(fd); + ret = qemu_try_set_nonblock(fd); + if (ret < 0) { + error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + name, fd); + return -1; + } if (!net_socket_fd_init(peer, "socket", name, fd, 1, sock->mcast, errp)) { return -1; diff --git a/net/tap.c b/net/tap.c index f9dcc2ef51..32e4813dbc 100644 --- a/net/tap.c +++ b/net/tap.c @@ -690,6 +690,8 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, } if (vhostfdname) { + int ret; + vhostfd = monitor_fd_param(cur_mon, vhostfdname, &err); if (vhostfd == -1) { if (tap->has_vhostforce && tap->vhostforce) { @@ -699,7 +701,12 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, } return; } - qemu_set_nonblock(vhostfd); + ret = qemu_try_set_nonblock(vhostfd); + if (ret < 0) { + error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + name, fd); + return; + } } else { vhostfd = open("/dev/vhost-net", O_RDWR); if (vhostfd < 0) { @@ -767,6 +774,7 @@ int net_init_tap(const Netdev *netdev, const char *name, Error *err = NULL; const char *vhostfdname; char ifname[128]; + int ret = 0; assert(netdev->type == NET_CLIENT_DRIVER_TAP); tap = &netdev->u.tap; @@ -795,7 +803,12 @@ int net_init_tap(const Netdev *netdev, const char *name, return -1; } - qemu_set_nonblock(fd); + ret = qemu_try_set_nonblock(fd); + if (ret < 0) { + error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + name, fd); + return -1; + } vnet_hdr = tap_probe_vnet_hdr(fd); @@ -810,7 +823,6 @@ int net_init_tap(const Netdev *netdev, const char *name, char **fds; char **vhost_fds; int nfds = 0, nvhosts = 0; - int ret = 0; if (tap->has_ifname || tap->has_script || tap->has_downscript || tap->has_vnet_hdr || tap->has_helper || tap->has_queues || @@ -842,7 +854,12 @@ int net_init_tap(const Netdev *netdev, const char *name, goto free_fail; } - qemu_set_nonblock(fd); + ret = qemu_try_set_nonblock(fd); + if (ret < 0) { + error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + name, fd); + goto free_fail; + } if (i == 0) { vnet_hdr = tap_probe_vnet_hdr(fd); diff --git a/util/oslib-posix.c b/util/oslib-posix.c index e60aea85b6..36bf8593f8 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -260,25 +260,35 @@ void qemu_set_block(int fd) assert(f != -1); } -void qemu_set_nonblock(int fd) +int qemu_try_set_nonblock(int fd) { int f; f = fcntl(fd, F_GETFL); - assert(f != -1); - f = fcntl(fd, F_SETFL, f | O_NONBLOCK); -#ifdef __OpenBSD__ if (f == -1) { + return -errno; + } + if (fcntl(fd, F_SETFL, f | O_NONBLOCK) == -1) { +#ifdef __OpenBSD__ /* * Previous to OpenBSD 6.3, fcntl(F_SETFL) is not permitted on * memory devices and sets errno to ENODEV. * It's OK if we fail to set O_NONBLOCK on devices like /dev/null, * because they will never block anyway. */ - assert(errno == ENODEV); - } -#else - assert(f != -1); + if (errno == ENODEV) { + return 0; + } #endif + return -errno; + } + return 0; +} + +void qemu_set_nonblock(int fd) +{ + int f; + f = qemu_try_set_nonblock(fd); + assert(f == 0); } int socket_set_fast_reuse(int fd) diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 3b49d27297..7eedbe5859 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -132,31 +132,6 @@ struct tm *localtime_r(const time_t *timep, struct tm *result) } #endif /* CONFIG_LOCALTIME_R */ -void qemu_set_block(int fd) -{ - unsigned long opt = 0; - WSAEventSelect(fd, NULL, 0); - ioctlsocket(fd, FIONBIO, &opt); -} - -void qemu_set_nonblock(int fd) -{ - unsigned long opt = 1; - ioctlsocket(fd, FIONBIO, &opt); - qemu_fd_register(fd); -} - -int socket_set_fast_reuse(int fd) -{ - /* Enabling the reuse of an endpoint that was used by a socket still in - * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows - * fast reuse is the default and SO_REUSEADDR does strange things. So we - * don't have to do anything here. More info can be found at: - * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */ - return 0; -} - - static int socket_error(void) { switch (WSAGetLastError()) { @@ -233,6 +208,38 @@ static int socket_error(void) } } +void qemu_set_block(int fd) +{ + unsigned long opt = 0; + WSAEventSelect(fd, NULL, 0); + ioctlsocket(fd, FIONBIO, &opt); +} + +int qemu_try_set_nonblock(int fd) +{ + unsigned long opt = 1; + if (ioctlsocket(fd, FIONBIO, &opt) != NO_ERROR) { + return -socket_error(); + } + qemu_fd_register(fd); + return 0; +} + +void qemu_set_nonblock(int fd) +{ + (void)qemu_try_set_nonblock(fd); +} + +int socket_set_fast_reuse(int fd) +{ + /* Enabling the reuse of an endpoint that was used by a socket still in + * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows + * fast reuse is the default and SO_REUSEADDR does strange things. So we + * don't have to do anything here. More info can be found at: + * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */ + return 0; +} + int inet_aton(const char *cp, struct in_addr *ia) { uint32_t addr = inet_addr(cp); From e7b347d0bf640adb1c998d317eaf44d2d7cbd973 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 7 Jul 2020 20:45:15 +0200 Subject: [PATCH 2355/2595] net: detect errors from probing vnet hdr flag for TAP devices When QEMU sets up a tap based network device backend, it mostly ignores errors reported from various ioctl() calls it makes, assuming the TAP file descriptor is valid. This assumption can easily be violated when the user is passing in a pre-opened file descriptor. At best, the ioctls may fail with a -EBADF, but if the user passes in a bogus FD number that happens to clash with a FD number that QEMU has opened internally for another reason, a wide variety of errnos may result, as the TUNGETIFF ioctl number may map to a completely different command on a different type of file. By ignoring all these errors, QEMU sets up a zombie network backend that will never pass any data. Even worse, when QEMU shuts down, or that network backend is hot-removed, it will close this bogus file descriptor, which could belong to another QEMU device backend. There's no obvious guaranteed reliable way to detect that a FD genuinely is a TAP device, as opposed to a UNIX socket, or pipe, or something else. Checking the errno from probing vnet hdr flag though, does catch the big common cases. ie calling TUNGETIFF will return EBADF for an invalid FD, and ENOTTY when FD is a UNIX socket, or pipe which catches accidental collisions with FDs used for stdio, or monitor socket. Previously the example below where bogus fd 9 collides with the FD used for the chardev saw: $ ./x86_64-softmmu/qemu-system-x86_64 -netdev tap,id=hostnet0,fd=9 \ -chardev socket,id=charchannel0,path=/tmp/qga,server,nowait \ -monitor stdio -vnc :0 qemu-system-x86_64: -netdev tap,id=hostnet0,fd=9: TUNGETIFF ioctl() failed: Inappropriate ioctl for device TUNSETOFFLOAD ioctl() failed: Bad address QEMU 2.9.1 monitor - type 'help' for more information (qemu) Warning: netdev hostnet0 has no peer which gives a running QEMU with a zombie network backend. With this change applied we get an error message and QEMU immediately exits before carrying on and making a bigger disaster: $ ./x86_64-softmmu/qemu-system-x86_64 -netdev tap,id=hostnet0,fd=9 \ -chardev socket,id=charchannel0,path=/tmp/qga,server,nowait \ -monitor stdio -vnc :0 qemu-system-x86_64: -netdev tap,id=hostnet0,vhost=on,fd=9: Unable to query TUNGETIFF on FD 9: Inappropriate ioctl for device Reported-by: Dr. David Alan Gilbert Signed-off-by: Daniel P. Berrange Tested-by: Dr. David Alan Gilbert Message-id: 20171027085548.3472-1-berrange@redhat.com [lv: to simplify, don't check on EINVAL with TUNGETIFF as it exists since v2.6.27] Signed-off-by: Laurent Vivier Signed-off-by: Jason Wang --- net/tap-bsd.c | 2 +- net/tap-linux.c | 8 +++++--- net/tap-solaris.c | 2 +- net/tap-stub.c | 2 +- net/tap.c | 25 ++++++++++++++++++++----- net/tap_int.h | 2 +- 6 files changed, 29 insertions(+), 12 deletions(-) diff --git a/net/tap-bsd.c b/net/tap-bsd.c index a5c3707f80..77aaf674b1 100644 --- a/net/tap-bsd.c +++ b/net/tap-bsd.c @@ -211,7 +211,7 @@ void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) { } -int tap_probe_vnet_hdr(int fd) +int tap_probe_vnet_hdr(int fd, Error **errp) { return 0; } diff --git a/net/tap-linux.c b/net/tap-linux.c index e0dd442ee3..b0635e9e32 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -147,13 +147,15 @@ void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) } } -int tap_probe_vnet_hdr(int fd) +int tap_probe_vnet_hdr(int fd, Error **errp) { struct ifreq ifr; if (ioctl(fd, TUNGETIFF, &ifr) != 0) { - error_report("TUNGETIFF ioctl() failed: %s", strerror(errno)); - return 0; + /* TUNGETIFF is available since kernel v2.6.27 */ + error_setg_errno(errp, errno, + "Unable to query TUNGETIFF on FD %d", fd); + return -1; } return ifr.ifr_flags & IFF_VNET_HDR; diff --git a/net/tap-solaris.c b/net/tap-solaris.c index d03165c57c..0475a58207 100644 --- a/net/tap-solaris.c +++ b/net/tap-solaris.c @@ -207,7 +207,7 @@ void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) { } -int tap_probe_vnet_hdr(int fd) +int tap_probe_vnet_hdr(int fd, Error **errp) { return 0; } diff --git a/net/tap-stub.c b/net/tap-stub.c index a9ab8f8293..de525a2e69 100644 --- a/net/tap-stub.c +++ b/net/tap-stub.c @@ -37,7 +37,7 @@ void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) { } -int tap_probe_vnet_hdr(int fd) +int tap_probe_vnet_hdr(int fd, Error **errp) { return 0; } diff --git a/net/tap.c b/net/tap.c index 32e4813dbc..14dc904fca 100644 --- a/net/tap.c +++ b/net/tap.c @@ -598,7 +598,11 @@ int net_init_bridge(const Netdev *netdev, const char *name, } qemu_set_nonblock(fd); - vnet_hdr = tap_probe_vnet_hdr(fd); + vnet_hdr = tap_probe_vnet_hdr(fd, errp); + if (vnet_hdr < 0) { + close(fd); + return -1; + } s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr); snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", helper, @@ -810,7 +814,11 @@ int net_init_tap(const Netdev *netdev, const char *name, return -1; } - vnet_hdr = tap_probe_vnet_hdr(fd); + vnet_hdr = tap_probe_vnet_hdr(fd, errp); + if (vnet_hdr < 0) { + close(fd); + return -1; + } net_init_tap_one(tap, peer, "tap", name, NULL, script, downscript, @@ -862,8 +870,11 @@ int net_init_tap(const Netdev *netdev, const char *name, } if (i == 0) { - vnet_hdr = tap_probe_vnet_hdr(fd); - } else if (vnet_hdr != tap_probe_vnet_hdr(fd)) { + vnet_hdr = tap_probe_vnet_hdr(fd, errp); + if (vnet_hdr < 0) { + goto free_fail; + } + } else if (vnet_hdr != tap_probe_vnet_hdr(fd, NULL)) { error_setg(errp, "vnet_hdr not consistent across given tap fds"); ret = -1; @@ -908,7 +919,11 @@ free_fail: } qemu_set_nonblock(fd); - vnet_hdr = tap_probe_vnet_hdr(fd); + vnet_hdr = tap_probe_vnet_hdr(fd, errp); + if (vnet_hdr < 0) { + close(fd); + return -1; + } net_init_tap_one(tap, peer, "bridge", name, ifname, script, downscript, vhostfdname, diff --git a/net/tap_int.h b/net/tap_int.h index e3194b23f4..225a49ea48 100644 --- a/net/tap_int.h +++ b/net/tap_int.h @@ -34,7 +34,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen); void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp); -int tap_probe_vnet_hdr(int fd); +int tap_probe_vnet_hdr(int fd, Error **errp); int tap_probe_vnet_hdr_len(int fd, int len); int tap_probe_has_ufo(int fd); void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo); From a134321ef676723768973537bb9b49365ae2062e Mon Sep 17 00:00:00 2001 From: erik-smit Date: Sun, 28 Jun 2020 16:26:59 +0200 Subject: [PATCH 2356/2595] ftgmac100: fix dblac write test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test of the write of the dblac register was testing the old value instead of the new value. This would accept the write of an invalid value but subsequently refuse any following valid writes. Signed-off-by: erik-smit Reviewed-by: Cédric Le Goater Signed-off-by: Jason Wang --- hw/net/ftgmac100.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 043ba61b86..5f4b26fc5f 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -810,16 +810,18 @@ static void ftgmac100_write(void *opaque, hwaddr addr, s->phydata = value & 0xffff; break; case FTGMAC100_DBLAC: /* DMA Burst Length and Arbitration Control */ - if (FTGMAC100_DBLAC_TXDES_SIZE(s->dblac) < sizeof(FTGMAC100Desc)) { + if (FTGMAC100_DBLAC_TXDES_SIZE(value) < sizeof(FTGMAC100Desc)) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: transmit descriptor too small : %d bytes\n", - __func__, FTGMAC100_DBLAC_TXDES_SIZE(s->dblac)); + "%s: transmit descriptor too small: %" PRIx64 + " bytes\n", __func__, + FTGMAC100_DBLAC_TXDES_SIZE(value)); break; } - if (FTGMAC100_DBLAC_RXDES_SIZE(s->dblac) < sizeof(FTGMAC100Desc)) { + if (FTGMAC100_DBLAC_RXDES_SIZE(value) < sizeof(FTGMAC100Desc)) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: receive descriptor too small : %d bytes\n", - __func__, FTGMAC100_DBLAC_RXDES_SIZE(s->dblac)); + "%s: receive descriptor too small : %" PRIx64 + " bytes\n", __func__, + FTGMAC100_DBLAC_RXDES_SIZE(value)); break; } s->dblac = value; From 8746309137ba470d1b2e8f5ce86ac228625db940 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 15 Jul 2020 19:08:07 +0100 Subject: [PATCH 2357/2595] Update version for v5.1.0-rc0 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a480698ce5..e427b98203 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.50 +5.0.90 From f8b332a1ff107dc014a52eaf9bf547995205f18a Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Tue, 7 Jul 2020 16:16:24 -0400 Subject: [PATCH 2358/2595] tpm: tpm_spapr: Exit on TPM backend failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exit on TPM backend failures in the same way as the TPM CRB and TIS device models do. With this change we now get an error report when the backend did not start up properly: error: internal error: qemu unexpectedly closed the monitor: 2020-07-07T12:49:28.333928Z qemu-system-ppc64: tpm-emulator: \ TPM result for CMD_INIT: 0x101 operation failed Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau Message-id: 20200707201625.4177419-2-stefanb@linux.vnet.ibm.com --- hw/tpm/tpm_spapr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c index cb4dfd1e6a..8288ab0a15 100644 --- a/hw/tpm/tpm_spapr.c +++ b/hw/tpm/tpm_spapr.c @@ -306,7 +306,10 @@ static void tpm_spapr_reset(SpaprVioDevice *dev) TPM_SPAPR_BUFFER_MAX); tpm_backend_reset(s->be_driver); - tpm_spapr_do_startup_tpm(s, s->be_buffer_size); + + if (tpm_spapr_do_startup_tpm(s, s->be_buffer_size) < 0) { + exit(1); + } } static enum TPMVersion tpm_spapr_get_version(TPMIf *ti) From df8a7568932e4c3c930fdfeb228dd72b4bb71a1f Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Tue, 7 Jul 2020 16:16:25 -0400 Subject: [PATCH 2359/2595] tests: tpm: Skip over pcrUpdateCounter byte in result comparison MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TPM 2 code in libtpms was fixed to handle the PCR 'TCB group' according to the PCClient profile. The change of the PCRs belonging to the 'TCB group' now affects the pcrUpdateCounter in the TPM2_PCRRead() responses where its value is now different (typically lower by '1') than what it was before. To not fail the tests, we skip the comparison of the 14th byte, which represents the pcrUpdateCounter. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau Message-id: 20200707201625.4177419-3-stefanb@linux.vnet.ibm.com --- tests/qtest/tpm-util.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c index 34efae8f18..58a9593745 100644 --- a/tests/qtest/tpm-util.c +++ b/tests/qtest/tpm-util.c @@ -139,7 +139,11 @@ void tpm_util_pcrread(QTestState *s, tx_func *tx, tx(s, tpm_pcrread, sizeof(tpm_pcrread), buffer, sizeof(buffer)); - g_assert_cmpmem(buffer, exp_resp_size, exp_resp, exp_resp_size); + /* skip pcrUpdateCounter (14th byte) in comparison */ + g_assert(exp_resp_size >= 15); + g_assert_cmpmem(buffer, 13, exp_resp, 13); + g_assert_cmpmem(&buffer[14], exp_resp_size - 14, + &exp_resp[14], exp_resp_size - 14); } bool tpm_util_swtpm_has_tpm2(void) From 8ec1415935ff4214ef9b47448ff7ac52cfa8b77e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 13 Jul 2020 14:45:20 +0200 Subject: [PATCH 2360/2595] vfio: fix use-after-free in display Calling ramfb_display_update() might replace the DisplaySurface with the boot display, which in turn will free the currently active DisplaySurface. So clear our DisplaySurface pinter (dpy->region.surface pointer) to (a) avoid use-after-free and (b) force replacing the boot display with the real display when switching back. Signed-off-by: Gerd Hoffmann Reviewed-by: Alex Williamson Acked-by: Alex Williamson Message-id: 20200713124520.23266-1-kraxel@redhat.com --- hw/vfio/display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/vfio/display.c b/hw/vfio/display.c index a57a22674d..342054193b 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -405,6 +405,7 @@ static void vfio_display_region_update(void *opaque) if (!plane.drm_format || !plane.size) { if (dpy->ramfb) { ramfb_display_update(dpy->con, dpy->ramfb); + dpy->region.surface = NULL; } return; } From 4084e35068772cf4f81bbae5174019f277c61084 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 13 Jul 2020 08:27:12 +0200 Subject: [PATCH 2361/2595] usb: fix storage regression Fix the contition to figure whenever we need to wait for more data or not. Simply check the mode, if we are not in DATAIN state any more we are done already and don't need to go ASYNC. Fixes: 7ad3d51ebb8a ("usb: add short-packet handling to usb-storage driver") Reported-by: Sai Pavan Boddu Tested-by: Paul Zimmerman Signed-off-by: Gerd Hoffmann Message-id: 20200713062712.1476-1-kraxel@redhat.com --- hw/usb/dev-storage.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 2ed6a8df24..405a4ccfe7 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -546,8 +546,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) } } } - if (p->actual_length < p->iov.size && (p->short_not_ok || - s->scsi_len >= p->ep->max_packet_size)) { + if (p->actual_length < p->iov.size && s->mode == USB_MSDM_DATAIN) { DPRINTF("Deferring packet %p [wait data-in]\n", p); s->packet = p; p->status = USB_RET_ASYNC; From 1f43671a0d55d863f9111535ca4241e9fa238506 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Tue, 14 Jul 2020 01:44:35 +0800 Subject: [PATCH 2362/2595] i368/cpu: Clear env->user_features after loading versioned CPU model Features defined in versioned CPU model are recorded in env->user_features since they are updated as property. It's unwated because they are not user specified. Simply clear env->user_features as a fix. It won't clear user specified features because user specified features are filled to env->user_features later in x86_cpu_expand_features(). Cc: Chenyi Qiang Suggested-by: Eduardo Habkost Signed-off-by: Xiaoyao Li Message-Id: <20200713174436.41070-2-xiaoyao.li@intel.com> [ehabkost: fix coding style] Signed-off-by: Eduardo Habkost --- target/i386/cpu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 1e5123251d..caf0334f3a 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5159,6 +5159,13 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); x86_cpu_apply_version_props(cpu, model); + + /* + * Properties in versioned CPU model are not user specified features. + * We can simply clear env->user_features here since it will be filled later + * in x86_cpu_expand_features() based on plus_features and minus_features. + */ + memset(&env->user_features, 0, sizeof(env->user_features)); } #ifndef CONFIG_USER_ONLY From f9f08e7cae8a6c292cacaf6531ede88786fcb3d3 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Tue, 14 Jul 2020 01:44:36 +0800 Subject: [PATCH 2363/2595] i386/cpu: Don't add unavailable_features to env->user_features Features unavailable due to absent of their dependent features should not be added to env->user_features. env->user_features only contains the feature explicity specified with -feature/+feature by user. Fixes: 99e24dbdaa68 ("target/i386: introduce generic feature dependency mechanism") Signed-off-by: Xiaoyao Li Message-Id: <20200713174436.41070-3-xiaoyao.li@intel.com> Signed-off-by: Eduardo Habkost --- target/i386/cpu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index caf0334f3a..93b62b2eca 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6371,7 +6371,6 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) 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; } } From 5cb287d2bd578dfe4897458793b4fce35bc4f744 Mon Sep 17 00:00:00 2001 From: Chenyi Qiang Date: Tue, 14 Jul 2020 16:41:46 +0800 Subject: [PATCH 2364/2595] target/i386: add fast short REP MOV support For CPUs support fast short REP MOV[CPUID.(EAX=7,ECX=0):EDX(bit4)], e.g Icelake and Tigerlake, expose it to the guest VM. Reviewed-by: Eduardo Habkost Signed-off-by: Chenyi Qiang Message-Id: <20200714084148.26690-2-chenyi.qiang@intel.com> Signed-off-by: Eduardo Habkost --- target/i386/cpu.c | 2 +- target/i386/cpu.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 93b62b2eca..3885826bc4 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -984,7 +984,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .type = CPUID_FEATURE_WORD, .feat_names = { NULL, NULL, "avx512-4vnniw", "avx512-4fmaps", - NULL, NULL, NULL, NULL, + "fsrm", NULL, NULL, NULL, "avx512-vp2intersect", NULL, "md-clear", NULL, NULL, NULL, "serialize", NULL, "tsx-ldtrk", NULL, NULL /* pconfig */, NULL, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 37fffa5cac..e1a5c174dc 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -775,6 +775,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Multiply Accumulation Single Precision */ #define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) +/* Fast Short Rep Mov */ +#define CPUID_7_0_EDX_FSRM (1U << 4) /* AVX512 Vector Pair Intersection to a Pair of Mask Registers */ #define CPUID_7_0_EDX_AVX512_VP2INTERSECT (1U << 8) /* SERIALIZE instruction */ From e0013791b9326945ccd09b5b602437beb322cab8 Mon Sep 17 00:00:00 2001 From: Chenyi Qiang Date: Tue, 14 Jul 2020 16:41:47 +0800 Subject: [PATCH 2365/2595] target/i386: fix model number and add missing features for Icelake-Server CPU model Add the missing features(sha_ni, avx512ifma, rdpid, fsrm, vmx-rdseed-exit, vmx-pml, vmx-eptp-switching) and change the model number to 106 in the Icelake-Server-v4 CPU model. Signed-off-by: Chenyi Qiang Message-Id: <20200714084148.26690-3-chenyi.qiang@intel.com> Signed-off-by: Eduardo Habkost --- target/i386/cpu.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 3885826bc4..132ef90421 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3512,6 +3512,20 @@ static X86CPUDefinition builtin_x86_defs[] = { { /* end of list */ } }, }, + { + .version = 4, + .props = (PropValue[]) { + { "sha-ni", "on" }, + { "avx512ifma", "on" }, + { "rdpid", "on" }, + { "fsrm", "on" }, + { "vmx-rdseed-exit", "on" }, + { "vmx-pml", "on" }, + { "vmx-eptp-switching", "on" }, + { "model", "106" }, + { /* end of list */ } + }, + }, { /* end of list */ } } }, From 644e3c5d812d1d672388124eeb43d0e26b3ff58c Mon Sep 17 00:00:00 2001 From: Chenyi Qiang Date: Tue, 14 Jul 2020 16:41:48 +0800 Subject: [PATCH 2366/2595] target/i386: add the missing vmx features for Skylake-Server and Cascadelake-Server CPU models Add the missing vmx features in Skylake-Server and Cascadelake-Server CPU models based on the output of Paolo's script. Signed-off-by: Chenyi Qiang Message-Id: <20200714084148.26690-4-chenyi.qiang@intel.com> Signed-off-by: Eduardo Habkost --- target/i386/cpu.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 132ef90421..588f32e136 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3034,6 +3034,13 @@ static X86CPUDefinition builtin_x86_defs[] = { { /* end of list */ } } }, + { + .version = 4, + .props = (PropValue[]) { + { "vmx-eptp-switching", "on" }, + { /* end of list */ } + } + }, { /* end of list */ } } }, @@ -3158,6 +3165,13 @@ static X86CPUDefinition builtin_x86_defs[] = { { /* end of list */ } }, }, + { .version = 4, + .note = "ARCH_CAPABILITIES, no TSX", + .props = (PropValue[]) { + { "vmx-eptp-switching", "on" }, + { /* end of list */ } + }, + }, { /* end of list */ } } }, From ae163b8d9588f02de6a4b6dba310307ba485d4a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 31 Dec 2019 19:32:07 +0100 Subject: [PATCH 2367/2595] hw/i2c/Kconfig: Add an entry for the SMBus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The System Management Bus is more or less a derivative of the I2C bus, thus the Kconfig entry depends of I2C. Not all boards providing an I2C bus support SMBus. Use two different Kconfig entries to be able to select I2C without selecting SMBus. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20191231183216.6781-6-philmd@redhat.com> Signed-off-by: Corey Minyard --- hw/i2c/Kconfig | 8 ++++++-- hw/i2c/Makefile.objs | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index 2bbd395813..09642a6dcb 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -1,9 +1,13 @@ config I2C bool +config SMBUS + bool + select I2C + config SMBUS_EEPROM bool - depends on I2C + select SMBUS config VERSATILE_I2C bool @@ -11,7 +15,7 @@ config VERSATILE_I2C config ACPI_SMBUS bool - select I2C + select SMBUS config BITBANG_I2C bool diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs index 6ba976b257..f2c61eaa8b 100644 --- a/hw/i2c/Makefile.objs +++ b/hw/i2c/Makefile.objs @@ -1,4 +1,5 @@ -common-obj-$(CONFIG_I2C) += core.o smbus_slave.o smbus_master.o +common-obj-$(CONFIG_I2C) += core.o +common-obj-$(CONFIG_SMBUS) += smbus_slave.o smbus_master.o common-obj-$(CONFIG_SMBUS_EEPROM) += smbus_eeprom.o common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o common-obj-$(CONFIG_ACPI_X86_ICH) += smbus_ich9.o From 7a204cbdc280fd9ab6c8d34a01f112ea5e809f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Jul 2020 00:41:50 +0200 Subject: [PATCH 2368/2595] hw/i2c/aspeed_i2c: Simplify aspeed_i2c_get_bus() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the callers of aspeed_i2c_get_bus() have a AspeedI2CState and cast it to a DeviceState with DEVICE(), then aspeed_i2c_get_bus() cast the DeviceState to an AspeedI2CState with ASPEED_I2C()... Simplify aspeed_i2c_get_bus() callers by using AspeedI2CState argument. Reviewed-by: Markus Armbruster Reviewed-by: Andrew Jeffery Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200705224154.16917-2-f4bug@amsat.org> Signed-off-by: Corey Minyard --- hw/arm/aspeed.c | 70 ++++++++++++++++++------------------- hw/i2c/aspeed_i2c.c | 3 +- include/hw/i2c/aspeed_i2c.h | 2 +- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 660dcb5414..dc3f44393f 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -385,13 +385,13 @@ static void palmetto_bmc_i2c_init(AspeedMachineState *bmc) /* The palmetto platform expects a ds3231 RTC but a ds1338 is * enough to provide basic RTC features. Alarms will be missing */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), "ds1338", 0x68); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 0), "ds1338", 0x68); - smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), 0x50, + smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 0), 0x50, eeprom_buf); /* add a TMP423 temperature sensor */ - dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2), + dev = i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 2), "tmp423", 0x4c); object_property_set_int(OBJECT(dev), "temperature0", 31000, &error_abort); object_property_set_int(OBJECT(dev), "temperature1", 28000, &error_abort); @@ -404,16 +404,16 @@ static void ast2500_evb_i2c_init(AspeedMachineState *bmc) AspeedSoCState *soc = &bmc->soc; uint8_t *eeprom_buf = g_malloc0(8 * 1024); - smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), 0x50, + smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 3), 0x50, eeprom_buf); /* The AST2500 EVB expects a LM75 but a TMP105 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 7), TYPE_TMP105, 0x4d); /* The AST2500 EVB does not have an RTC. Let's pretend that one is * plugged on the I2C bus header */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32); } static void ast2600_evb_i2c_init(AspeedMachineState *bmc) @@ -428,36 +428,36 @@ static void romulus_bmc_i2c_init(AspeedMachineState *bmc) /* The romulus board expects Epson RX8900 I2C RTC but a ds1338 is * good enough */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32); } static void swift_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), "pca9552", 0x60); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 3), "pca9552", 0x60); /* The swift board expects a TMP275 but a TMP105 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "tmp105", 0x48); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 7), "tmp105", 0x48); /* The swift board expects a pca9551 but a pca9552 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "pca9552", 0x60); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 7), "pca9552", 0x60); /* The swift board expects an Epson RX8900 RTC but a ds1338 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "ds1338", 0x32); - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "pca9552", 0x60); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 8), "ds1338", 0x32); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x60); - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), "tmp423", 0x4c); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4c); /* The swift board expects a pca9539 but a pca9552 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), "pca9552", 0x74); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 9), "pca9552", 0x74); - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 10), "tmp423", 0x4c); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4c); /* The swift board expects a pca9539 but a pca9552 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 10), "pca9552", + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 10), "pca9552", 0x74); /* The swift board expects a TMP275 but a TMP105 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 12), "tmp105", 0x48); - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 12), "tmp105", 0x4a); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 12), "tmp105", 0x48); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 12), "tmp105", 0x4a); } static void sonorapass_bmc_i2c_init(AspeedMachineState *bmc) @@ -465,32 +465,32 @@ static void sonorapass_bmc_i2c_init(AspeedMachineState *bmc) AspeedSoCState *soc = &bmc->soc; /* bus 2 : */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2), "tmp105", 0x48); - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2), "tmp105", 0x49); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 2), "tmp105", 0x48); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 2), "tmp105", 0x49); /* bus 2 : pca9546 @ 0x73 */ /* bus 3 : pca9548 @ 0x70 */ /* bus 4 : */ uint8_t *eeprom4_54 = g_malloc0(8 * 1024); - smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), 0x54, + smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 4), 0x54, eeprom4_54); /* PCA9539 @ 0x76, but PCA9552 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), "pca9552", 0x76); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 4), "pca9552", 0x76); /* PCA9539 @ 0x77, but PCA9552 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), "pca9552", 0x77); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 4), "pca9552", 0x77); /* bus 6 : */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 6), "tmp105", 0x48); - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 6), "tmp105", 0x49); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 6), "tmp105", 0x48); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 6), "tmp105", 0x49); /* bus 6 : pca9546 @ 0x73 */ /* bus 8 : */ uint8_t *eeprom8_56 = g_malloc0(8 * 1024); - smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), 0x56, + smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 8), 0x56, eeprom8_56); - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "pca9552", 0x60); - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "pca9552", 0x61); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x60); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x61); /* bus 8 : adc128d818 @ 0x1d */ /* bus 8 : adc128d818 @ 0x1f */ @@ -515,25 +515,25 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) /* Bus 3: TODO dps310@76 */ dev = i2c_try_create_slave(TYPE_PCA9552, 0x60); qdev_prop_set_string(dev, "description", "pca1"); - i2c_realize_and_unref(dev, aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), + i2c_realize_and_unref(dev, aspeed_i2c_get_bus(&soc->i2c, 3), &error_fatal); - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), "tmp423", 0x4c); - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 5), "tmp423", 0x4c); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 4), "tmp423", 0x4c); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 5), "tmp423", 0x4c); /* The Witherspoon expects a TMP275 but a TMP105 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), TYPE_TMP105, + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 9), TYPE_TMP105, 0x4a); /* The witherspoon board expects Epson RX8900 I2C RTC but a ds1338 is * good enough */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32); + i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32); - smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), 0x51, + smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 11), 0x51, eeprom_buf); dev = i2c_try_create_slave(TYPE_PCA9552, 0x60); qdev_prop_set_string(dev, "description", "pca0"); - i2c_realize_and_unref(dev, aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), + i2c_realize_and_unref(dev, aspeed_i2c_get_bus(&soc->i2c, 11), &error_fatal); /* Bus 11: TODO ucd90160@64 */ } diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index fb973a983d..518a3f5c6f 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -959,9 +959,8 @@ static void aspeed_i2c_register_types(void) type_init(aspeed_i2c_register_types) -I2CBus *aspeed_i2c_get_bus(DeviceState *dev, int busnr) +I2CBus *aspeed_i2c_get_bus(AspeedI2CState *s, int busnr) { - AspeedI2CState *s = ASPEED_I2C(dev); AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); I2CBus *bus = NULL; diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h index f1b9e5bf91..243789ae5d 100644 --- a/include/hw/i2c/aspeed_i2c.h +++ b/include/hw/i2c/aspeed_i2c.h @@ -93,6 +93,6 @@ typedef struct AspeedI2CClass { } AspeedI2CClass; -I2CBus *aspeed_i2c_get_bus(DeviceState *dev, int busnr); +I2CBus *aspeed_i2c_get_bus(AspeedI2CState *s, int busnr); #endif /* ASPEED_I2C_H */ From db437ca6dfc8db3d91ee75babc4b1fee8c95e9ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Jul 2020 00:41:51 +0200 Subject: [PATCH 2369/2595] hw/i2c: Rename i2c_try_create_slave() as i2c_slave_new() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use "new" names for functions that allocate and initialize device objects: pci_new(), isa_new(), usb_new(). Let's call this one i2c_slave_new(). Since we have to update all the callers, also let it return a I2CSlave object. Suggested-by: Markus Armbruster Reviewed-by: Markus Armbruster Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200705224154.16917-3-f4bug@amsat.org> Signed-off-by: Corey Minyard --- hw/arm/aspeed.c | 4 ++-- hw/i2c/core.c | 11 +++++------ include/hw/i2c/i2c.h | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index dc3f44393f..51687fd3b3 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -513,7 +513,7 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) /* Bus 3: TODO bmp280@77 */ /* Bus 3: TODO max31785@52 */ /* Bus 3: TODO dps310@76 */ - dev = i2c_try_create_slave(TYPE_PCA9552, 0x60); + dev = DEVICE(i2c_slave_new(TYPE_PCA9552, 0x60)); qdev_prop_set_string(dev, "description", "pca1"); i2c_realize_and_unref(dev, aspeed_i2c_get_bus(&soc->i2c, 3), &error_fatal); @@ -531,7 +531,7 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 11), 0x51, eeprom_buf); - dev = i2c_try_create_slave(TYPE_PCA9552, 0x60); + dev = DEVICE(i2c_slave_new(TYPE_PCA9552, 0x60)); qdev_prop_set_string(dev, "description", "pca0"); i2c_realize_and_unref(dev, aspeed_i2c_get_bus(&soc->i2c, 11), &error_fatal); diff --git a/hw/i2c/core.c b/hw/i2c/core.c index acf34a12d6..144786f17a 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -267,13 +267,13 @@ const VMStateDescription vmstate_i2c_slave = { } }; -DeviceState *i2c_try_create_slave(const char *name, uint8_t addr) +I2CSlave *i2c_slave_new(const char *name, uint8_t addr) { DeviceState *dev; dev = qdev_new(name); qdev_prop_set_uint8(dev, "address", addr); - return dev; + return I2C_SLAVE(dev); } bool i2c_realize_and_unref(DeviceState *dev, I2CBus *bus, Error **errp) @@ -283,12 +283,11 @@ bool i2c_realize_and_unref(DeviceState *dev, I2CBus *bus, Error **errp) DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr) { - DeviceState *dev; + I2CSlave *dev = i2c_slave_new(name, addr); - dev = i2c_try_create_slave(name, addr); - i2c_realize_and_unref(dev, bus, &error_fatal); + i2c_realize_and_unref(DEVICE(dev), bus, &error_fatal); - return dev; + return DEVICE(dev); } static void i2c_slave_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index d6e3d85faf..18efc668f1 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -79,8 +79,8 @@ int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send); int i2c_send(I2CBus *bus, uint8_t data); uint8_t i2c_recv(I2CBus *bus); +I2CSlave *i2c_slave_new(const char *name, uint8_t addr); DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr); -DeviceState *i2c_try_create_slave(const char *name, uint8_t addr); bool i2c_realize_and_unref(DeviceState *dev, I2CBus *bus, Error **errp); /* lm832x.c */ From 2616f57231c8e065df77de894a8f018cd1842c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Jul 2020 00:41:52 +0200 Subject: [PATCH 2370/2595] hw/i2c: Rename i2c_realize_and_unref() as i2c_slave_realize_and_unref() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The other i2c functions are called i2c_slave_FOO(). Rename as i2c_slave_realize_and_unref() to be consistent. Suggested-by: Markus Armbruster Reviewed-by: Corey Minyard Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200705224154.16917-4-f4bug@amsat.org> Signed-off-by: Corey Minyard --- hw/arm/aspeed.c | 10 ++++++---- hw/i2c/core.c | 6 +++--- include/hw/i2c/i2c.h | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 51687fd3b3..78432e267b 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -515,8 +515,9 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) /* Bus 3: TODO dps310@76 */ dev = DEVICE(i2c_slave_new(TYPE_PCA9552, 0x60)); qdev_prop_set_string(dev, "description", "pca1"); - i2c_realize_and_unref(dev, aspeed_i2c_get_bus(&soc->i2c, 3), - &error_fatal); + i2c_slave_realize_and_unref(I2C_SLAVE(dev), + aspeed_i2c_get_bus(&soc->i2c, 3), + &error_fatal); i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 4), "tmp423", 0x4c); i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 5), "tmp423", 0x4c); @@ -533,8 +534,9 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) eeprom_buf); dev = DEVICE(i2c_slave_new(TYPE_PCA9552, 0x60)); qdev_prop_set_string(dev, "description", "pca0"); - i2c_realize_and_unref(dev, aspeed_i2c_get_bus(&soc->i2c, 11), - &error_fatal); + i2c_slave_realize_and_unref(I2C_SLAVE(dev), + aspeed_i2c_get_bus(&soc->i2c, 11), + &error_fatal); /* Bus 11: TODO ucd90160@64 */ } diff --git a/hw/i2c/core.c b/hw/i2c/core.c index 144786f17a..f81601a5b9 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -276,16 +276,16 @@ I2CSlave *i2c_slave_new(const char *name, uint8_t addr) return I2C_SLAVE(dev); } -bool i2c_realize_and_unref(DeviceState *dev, I2CBus *bus, Error **errp) +bool i2c_slave_realize_and_unref(I2CSlave *dev, I2CBus *bus, Error **errp) { - return qdev_realize_and_unref(dev, &bus->qbus, errp); + return qdev_realize_and_unref(&dev->qdev, &bus->qbus, errp); } DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr) { I2CSlave *dev = i2c_slave_new(name, addr); - i2c_realize_and_unref(DEVICE(dev), bus, &error_fatal); + i2c_slave_realize_and_unref(dev, bus, &error_fatal); return DEVICE(dev); } diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index 18efc668f1..cb7211f027 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -81,7 +81,7 @@ uint8_t i2c_recv(I2CBus *bus); I2CSlave *i2c_slave_new(const char *name, uint8_t addr); DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr); -bool i2c_realize_and_unref(DeviceState *dev, I2CBus *bus, Error **errp); +bool i2c_slave_realize_and_unref(I2CSlave *dev, I2CBus *bus, Error **errp); /* lm832x.c */ void lm832x_key_event(DeviceState *dev, int key, int state); From 1373b15bb55e46b067f84f70c60d3d03af62fd62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Jul 2020 00:41:53 +0200 Subject: [PATCH 2371/2595] hw/i2c: Rename i2c_create_slave() as i2c_slave_create_simple() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use "create_simple" names for functions that allocate, initialize, configure and realize device objects: pci_create_simple(), isa_create_simple(), usb_create_simple(). For consistency, rename i2c_create_slave() as i2c_slave_create_simple(). Since we have to update all the callers, also let it return a I2CSlave object. Suggested-by: Markus Armbruster Reviewed-by: Corey Minyard Reviewed-by: Markus Armbruster Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200705224154.16917-5-f4bug@amsat.org> Signed-off-by: Corey Minyard --- hw/arm/aspeed.c | 58 ++++++++++++++++++++++---------------------- hw/arm/musicpal.c | 4 +-- hw/arm/nseries.c | 8 +++--- hw/arm/pxa2xx.c | 5 ++-- hw/arm/realview.c | 2 +- hw/arm/spitz.c | 4 +-- hw/arm/stellaris.c | 2 +- hw/arm/tosa.c | 2 +- hw/arm/versatilepb.c | 2 +- hw/arm/vexpress.c | 2 +- hw/arm/z2.c | 4 +-- hw/display/sii9022.c | 2 +- hw/i2c/core.c | 6 ++--- hw/ppc/e500.c | 2 +- hw/ppc/sam460ex.c | 2 +- include/hw/i2c/i2c.h | 2 +- 16 files changed, 54 insertions(+), 53 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 78432e267b..c4288b5fb1 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -385,14 +385,14 @@ static void palmetto_bmc_i2c_init(AspeedMachineState *bmc) /* The palmetto platform expects a ds3231 RTC but a ds1338 is * enough to provide basic RTC features. Alarms will be missing */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 0), "ds1338", 0x68); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0), "ds1338", 0x68); smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 0), 0x50, eeprom_buf); /* add a TMP423 temperature sensor */ - dev = i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 2), - "tmp423", 0x4c); + dev = DEVICE(i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 2), + "tmp423", 0x4c)); object_property_set_int(OBJECT(dev), "temperature0", 31000, &error_abort); object_property_set_int(OBJECT(dev), "temperature1", 28000, &error_abort); object_property_set_int(OBJECT(dev), "temperature2", 20000, &error_abort); @@ -408,12 +408,12 @@ static void ast2500_evb_i2c_init(AspeedMachineState *bmc) eeprom_buf); /* The AST2500 EVB expects a LM75 but a TMP105 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 7), + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), TYPE_TMP105, 0x4d); /* The AST2500 EVB does not have an RTC. Let's pretend that one is * plugged on the I2C bus header */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32); } static void ast2600_evb_i2c_init(AspeedMachineState *bmc) @@ -428,36 +428,36 @@ static void romulus_bmc_i2c_init(AspeedMachineState *bmc) /* The romulus board expects Epson RX8900 I2C RTC but a ds1338 is * good enough */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32); } static void swift_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 3), "pca9552", 0x60); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 3), "pca9552", 0x60); /* The swift board expects a TMP275 but a TMP105 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 7), "tmp105", 0x48); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), "tmp105", 0x48); /* The swift board expects a pca9551 but a pca9552 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 7), "pca9552", 0x60); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), "pca9552", 0x60); /* The swift board expects an Epson RX8900 RTC but a ds1338 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 8), "ds1338", 0x32); - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x60); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), "ds1338", 0x32); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x60); - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4c); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4c); /* The swift board expects a pca9539 but a pca9552 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 9), "pca9552", 0x74); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "pca9552", 0x74); - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4c); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4c); /* The swift board expects a pca9539 but a pca9552 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 10), "pca9552", + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "pca9552", 0x74); /* The swift board expects a TMP275 but a TMP105 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 12), "tmp105", 0x48); - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 12), "tmp105", 0x4a); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 12), "tmp105", 0x48); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 12), "tmp105", 0x4a); } static void sonorapass_bmc_i2c_init(AspeedMachineState *bmc) @@ -465,8 +465,8 @@ static void sonorapass_bmc_i2c_init(AspeedMachineState *bmc) AspeedSoCState *soc = &bmc->soc; /* bus 2 : */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 2), "tmp105", 0x48); - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 2), "tmp105", 0x49); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 2), "tmp105", 0x48); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 2), "tmp105", 0x49); /* bus 2 : pca9546 @ 0x73 */ /* bus 3 : pca9548 @ 0x70 */ @@ -476,21 +476,21 @@ static void sonorapass_bmc_i2c_init(AspeedMachineState *bmc) smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 4), 0x54, eeprom4_54); /* PCA9539 @ 0x76, but PCA9552 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 4), "pca9552", 0x76); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), "pca9552", 0x76); /* PCA9539 @ 0x77, but PCA9552 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 4), "pca9552", 0x77); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), "pca9552", 0x77); /* bus 6 : */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 6), "tmp105", 0x48); - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 6), "tmp105", 0x49); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), "tmp105", 0x48); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), "tmp105", 0x49); /* bus 6 : pca9546 @ 0x73 */ /* bus 8 : */ uint8_t *eeprom8_56 = g_malloc0(8 * 1024); smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 8), 0x56, eeprom8_56); - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x60); - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x61); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x60); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x61); /* bus 8 : adc128d818 @ 0x1d */ /* bus 8 : adc128d818 @ 0x1f */ @@ -519,16 +519,16 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) aspeed_i2c_get_bus(&soc->i2c, 3), &error_fatal); - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 4), "tmp423", 0x4c); - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 5), "tmp423", 0x4c); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), "tmp423", 0x4c); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), "tmp423", 0x4c); /* The Witherspoon expects a TMP275 but a TMP105 is compatible */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 9), TYPE_TMP105, + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), TYPE_TMP105, 0x4a); /* The witherspoon board expects Epson RX8900 I2C RTC but a ds1338 is * good enough */ - i2c_create_slave(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32); smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 11), 0x51, eeprom_buf); diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index ff9a7c8cc6..c3b9780f35 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -1584,7 +1584,7 @@ static void musicpal_init(MachineState *machine) DeviceState *i2c_dev; DeviceState *lcd_dev; DeviceState *key_dev; - DeviceState *wm8750_dev; + I2CSlave *wm8750_dev; SysBusDevice *s; I2CBus *i2c; int i; @@ -1687,7 +1687,7 @@ static void musicpal_init(MachineState *machine) qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15)); } - wm8750_dev = i2c_create_slave(i2c, TYPE_WM8750, MP_WM_ADDR); + wm8750_dev = i2c_slave_create_simple(i2c, TYPE_WM8750, MP_WM_ADDR); dev = qdev_new(TYPE_MV88W8618_AUDIO); s = SYS_BUS_DEVICE(dev); object_property_set_link(OBJECT(dev), "wm8750", OBJECT(wm8750_dev), diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index 428a2a2c5a..e48092ca04 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -215,7 +215,7 @@ static void n8x0_i2c_setup(struct n800_s *s) I2CBus *i2c = omap_i2c_bus(s->mpu->i2c[0]); /* Attach a menelaus PM chip */ - dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR); + dev = DEVICE(i2c_slave_create_simple(i2c, "twl92230", N8X0_MENELAUS_ADDR)); qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(s->mpu->ih[0], OMAP_INT_24XX_SYS_NIRQ)); @@ -224,7 +224,7 @@ static void n8x0_i2c_setup(struct n800_s *s) qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier); /* Attach a TMP105 PM chip (A0 wired to ground) */ - dev = i2c_create_slave(i2c, TYPE_TMP105, N8X0_TMP105_ADDR); + dev = DEVICE(i2c_slave_create_simple(i2c, TYPE_TMP105, N8X0_TMP105_ADDR)); qdev_connect_gpio_out(dev, 0, tmp_irq); } @@ -416,8 +416,8 @@ static void n810_kbd_setup(struct n800_s *s) /* Attach the LM8322 keyboard to the I2C bus, * should happen in n8x0_i2c_setup and s->kbd be initialised here. */ - s->kbd = i2c_create_slave(omap_i2c_bus(s->mpu->i2c[0]), - "lm8323", N810_LM8323_ADDR); + s->kbd = DEVICE(i2c_slave_create_simple(omap_i2c_bus(s->mpu->i2c[0]), + "lm8323", N810_LM8323_ADDR)); qdev_connect_gpio_out(s->kbd, 0, kbd_irq); } diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index f104a33463..6203c4cfe0 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1522,8 +1522,9 @@ PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, s = PXA2XX_I2C(i2c_dev); /* FIXME: Should the slave device really be on a separate bus? */ i2cbus = i2c_init_bus(dev, "dummy"); - dev = i2c_create_slave(i2cbus, TYPE_PXA2XX_I2C_SLAVE, 0); - s->slave = PXA2XX_I2C_SLAVE(dev); + s->slave = PXA2XX_I2C_SLAVE(i2c_slave_create_simple(i2cbus, + TYPE_PXA2XX_I2C_SLAVE, + 0)); s->slave->host = s; return s; diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 22e132058e..c1ff172b13 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -285,7 +285,7 @@ static void realview_init(MachineState *machine, dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); - i2c_create_slave(i2c, "ds1338", 0x68); + i2c_slave_create_simple(i2c, "ds1338", 0x68); /* Memory map for RealView Emulation Baseboard: */ /* 0x10000000 System registers. */ diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index f020aff974..7ac8254aa6 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -787,7 +787,7 @@ static void spitz_i2c_setup(PXA2xxState *cpu) DeviceState *wm; /* Attach a WM8750 to the bus */ - wm = i2c_create_slave(bus, TYPE_WM8750, 0); + wm = DEVICE(i2c_slave_create_simple(bus, TYPE_WM8750, 0)); spitz_wm8750_addr(wm, 0, 0); qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM, @@ -802,7 +802,7 @@ static void spitz_i2c_setup(PXA2xxState *cpu) static void spitz_akita_i2c_setup(PXA2xxState *cpu) { /* Attach a Max7310 to Akita I2C bus. */ - i2c_create_slave(pxa2xx_i2c_bus(cpu->i2c[0]), "max7310", + i2c_slave_create_simple(pxa2xx_i2c_bus(cpu->i2c[0]), "max7310", AKITA_MAX_ADDR); } diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 7156fb3ece..28eb15c76c 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -1380,7 +1380,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) qdev_get_gpio_in(nvic, 8)); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); if (board->peripherals & BP_OLED_I2C) { - i2c_create_slave(i2c, "ssd0303", 0x3d); + i2c_slave_create_simple(i2c, "ssd0303", 0x3d); } } diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index 5dee2d76c6..8c1ee0cdd1 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -206,7 +206,7 @@ static uint8_t tosa_dac_recv(I2CSlave *s) static void tosa_tg_init(PXA2xxState *cpu) { I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); - i2c_create_slave(bus, TYPE_TOSA_DAC, DAC_BASE); + i2c_slave_create_simple(bus, TYPE_TOSA_DAC, DAC_BASE); ssi_create_slave(cpu->ssp[1], "tosa-ssp"); } diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index d09ea24ae2..9dc93182b6 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -317,7 +317,7 @@ static void versatile_init(MachineState *machine, int board_id) dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); - i2c_create_slave(i2c, "ds1338", 0x68); + i2c_slave_create_simple(i2c, "ds1338", 0x68); /* Add PL041 AACI Interface to the LM4549 codec */ pl041 = qdev_new("pl041"); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 762b068e90..1dc971c34f 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -642,7 +642,7 @@ static void vexpress_common_init(MachineState *machine) dev = sysbus_create_simple(TYPE_VERSATILE_I2C, map[VE_SERIALDVI], NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); - i2c_create_slave(i2c, "sii9022", 0x39); + i2c_slave_create_simple(i2c, "sii9022", 0x39); sysbus_create_simple("pl031", map[VE_RTC], pic[4]); /* RTC */ diff --git a/hw/arm/z2.c b/hw/arm/z2.c index e1f22f5868..9a9bbc653b 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -330,8 +330,8 @@ static void z2_init(MachineState *machine) type_register_static(&aer915_info); z2_lcd = ssi_create_slave(mpu->ssp[1], TYPE_ZIPIT_LCD); bus = pxa2xx_i2c_bus(mpu->i2c[0]); - i2c_create_slave(bus, TYPE_AER915, 0x55); - wm = i2c_create_slave(bus, TYPE_WM8750, 0x1b); + i2c_slave_create_simple(bus, TYPE_AER915, 0x55); + wm = DEVICE(i2c_slave_create_simple(bus, TYPE_WM8750, 0x1b)); mpu->i2s->opaque = wm; mpu->i2s->codec_out = wm8750_dac_dat; mpu->i2s->codec_in = wm8750_adc_dat; diff --git a/hw/display/sii9022.c b/hw/display/sii9022.c index 0710ce9de5..3b82a8567f 100644 --- a/hw/display/sii9022.c +++ b/hw/display/sii9022.c @@ -161,7 +161,7 @@ static void sii9022_realize(DeviceState *dev, Error **errp) I2CBus *bus; bus = I2C_BUS(qdev_get_parent_bus(dev)); - i2c_create_slave(bus, TYPE_I2CDDC, 0x50); + i2c_slave_create_simple(bus, TYPE_I2CDDC, 0x50); } static void sii9022_class_init(ObjectClass *klass, void *data) diff --git a/hw/i2c/core.c b/hw/i2c/core.c index f81601a5b9..21ec52ac5a 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -281,13 +281,13 @@ bool i2c_slave_realize_and_unref(I2CSlave *dev, I2CBus *bus, Error **errp) return qdev_realize_and_unref(&dev->qdev, &bus->qbus, errp); } -DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr) +I2CSlave *i2c_slave_create_simple(I2CBus *bus, const char *name, uint8_t addr) { I2CSlave *dev = i2c_slave_new(name, addr); - i2c_slave_realize_and_unref(dev, bus, &error_fatal); + i2c_slave_realize_and_unref(dev, bus, &error_abort); - return DEVICE(dev); + return dev; } static void i2c_slave_class_init(ObjectClass *klass, void *data) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 5448d101d9..ab9884e315 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -941,7 +941,7 @@ void ppce500_init(MachineState *machine) memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET, sysbus_mmio_get_region(s, 0)); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); - i2c_create_slave(i2c, "ds1338", RTC_REGS_OFFSET); + i2c_slave_create_simple(i2c, "ds1338", RTC_REGS_OFFSET); /* General Utility device */ diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 1a106a68de..1702344c46 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -339,7 +339,7 @@ static void sam460ex_init(MachineState *machine) spd_data[20] = 4; /* SO-DIMM module */ smbus_eeprom_init_one(i2c, 0x50, spd_data); /* RTC */ - i2c_create_slave(i2c, "m41t80", 0x68); + i2c_slave_create_simple(i2c, "m41t80", 0x68); dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]); diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index cb7211f027..c533058998 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -80,7 +80,7 @@ int i2c_send(I2CBus *bus, uint8_t data); uint8_t i2c_recv(I2CBus *bus); I2CSlave *i2c_slave_new(const char *name, uint8_t addr); -DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr); +I2CSlave *i2c_slave_create_simple(I2CBus *bus, const char *name, uint8_t addr); bool i2c_slave_realize_and_unref(I2CSlave *dev, I2CBus *bus, Error **errp); /* lm832x.c */ From 73d5f22ecbb76dfc785876779d47787084ff0f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Jul 2020 00:41:54 +0200 Subject: [PATCH 2372/2595] hw/i2c: Document the I2C qdev helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit d88c42ff2c we added new prototype but neglected to add their documentation. Fix that. Reported-by: Peter Maydell Reviewed-by: Corey Minyard Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200705224154.16917-6-f4bug@amsat.org> Signed-off-by: Corey Minyard --- include/hw/i2c/i2c.h | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index c533058998..a9c030a512 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -79,8 +79,56 @@ int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send); int i2c_send(I2CBus *bus, uint8_t data); uint8_t i2c_recv(I2CBus *bus); +/** + * Create an I2C slave device on the heap. + * @name: a device type name + * @addr: I2C address of the slave when put on a bus + * + * This only initializes the device state structure and allows + * properties to be set. Type @name must exist. The device still + * needs to be realized. See qdev-core.h. + */ I2CSlave *i2c_slave_new(const char *name, uint8_t addr); + +/** + * Create and realize an I2C slave device on the heap. + * @bus: I2C bus to put it on + * @name: I2C slave device type name + * @addr: I2C address of the slave when put on a bus + * + * Create the device state structure, initialize it, put it on the + * specified @bus, and drop the reference to it (the device is realized). + */ I2CSlave *i2c_slave_create_simple(I2CBus *bus, const char *name, uint8_t addr); + +/** + * Realize and and drop a reference an I2C slave device + * @dev: I2C slave device to realize + * @bus: I2C bus to put it on + * @addr: I2C address of the slave on the bus + * @errp: pointer to NULL initialized error object + * + * Returns: %true on success, %false on failure. + * + * Call 'realize' on @dev, put it on the specified @bus, and drop the + * reference to it. + * + * This function is useful if you have created @dev via qdev_new(), + * i2c_slave_new() or i2c_slave_try_new() (which take a reference to + * the device it returns to you), so that you can set properties on it + * before realizing it. If you don't need to set properties then + * i2c_slave_create_simple() is probably better (as it does the create, + * init and realize in one step). + * + * If you are embedding the I2C slave into another QOM device and + * initialized it via some variant on object_initialize_child() then + * do not use this function, because that family of functions arrange + * for the only reference to the child device to be held by the parent + * via the child<> property, and so the reference-count-drop done here + * would be incorrect. (Instead you would want i2c_slave_realize(), + * which doesn't currently exist but would be trivial to create if we + * had any code that wanted it.) + */ bool i2c_slave_realize_and_unref(I2CSlave *dev, I2CBus *bus, Error **errp); /* lm832x.c */ From 818b9f111d64b40661d08f5e23236ac1ca5df505 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 14 Jul 2020 12:07:27 +0300 Subject: [PATCH 2373/2595] i386: hvf: Explicitly set CR4 guest/host mask Removal of register reset omitted initialization of CR4 guest/host mask. x86_64 guests aren't booting without it. Fixes: 5009ef22c6bb2 ("i386: hvf: Don't duplicate register reset") Signed-off-by: Roman Bolshakov Message-Id: <20200714090726.41082-1-r.bolshakov@yadro.com> Signed-off-by: Eduardo Habkost --- target/i386/hvf/vmx.h | 1 + 1 file changed, 1 insertion(+) diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 75ba1e2a5f..587b1b8375 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -166,6 +166,7 @@ static inline void macvm_set_cr4(hv_vcpuid_t vcpu, uint64_t cr4) wvmcs(vcpu, VMCS_GUEST_CR4, guest_cr4); wvmcs(vcpu, VMCS_CR4_SHADOW, cr4); + wvmcs(vcpu, VMCS_CR4_MASK, CR4_VMXE); hv_vcpu_invalidate_tlb(vcpu); hv_vcpu_flush(vcpu); From 69c918d2ef319ac63cd759c527debc2a2bdf3a0c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 9 Jun 2020 16:32:09 -0700 Subject: [PATCH 2374/2595] tcg: Save/restore vecop_list around minmax fallback Forgetting this asserts when tcg_gen_cmp_vec is called from within tcg_gen_cmpsel_vec. Fixes: 72b4c792c7a Signed-off-by: Richard Henderson --- tcg/tcg-op-vec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c index f784517d84..ed6fb55fe1 100644 --- a/tcg/tcg-op-vec.c +++ b/tcg/tcg-op-vec.c @@ -657,7 +657,9 @@ static void do_minmax(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b, TCGOpcode opc, TCGCond cond) { if (!do_op3(vece, r, a, b, opc)) { + const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL); tcg_gen_cmpsel_vec(cond, vece, r, a, b, a, b); + tcg_swap_vecop_list(hold_list); } } From a7ba744f4082abbd3e36a9265dd1682ad0980477 Mon Sep 17 00:00:00 2001 From: Luc Michel Date: Thu, 16 Jul 2020 21:39:47 +0200 Subject: [PATCH 2375/2595] tcg/cpu-exec: precise single-stepping after an exception When single-stepping with a debugger attached to QEMU, and when an exception is raised, the debugger misses the first instruction after the exception: $ qemu-system-aarch64 -M virt -display none -cpu cortex-a53 -s -S $ aarch64-linux-gnu-gdb GNU gdb (GDB) 9.2 [...] (gdb) tar rem :1234 Remote debugging using :1234 warning: No executable has been specified and target does not support determining executable automatically. Try using the "file" command. 0x0000000000000000 in ?? () (gdb) # writing nop insns to 0x200 and 0x204 (gdb) set *0x200 = 0xd503201f (gdb) set *0x204 = 0xd503201f (gdb) # 0x0 address contains 0 which is an invalid opcode. (gdb) # The CPU should raise an exception and jump to 0x200 (gdb) si 0x0000000000000204 in ?? () With this commit, the same run steps correctly on the first instruction of the exception vector: (gdb) si 0x0000000000000200 in ?? () Buglink: https://bugs.launchpad.net/qemu/+bug/757702 Signed-off-by: Luc Michel Message-Id: <20200716193947.3058389-1-luc.michel@greensocs.com> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index d95c4848a4..6a3d3a3cfc 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -504,6 +504,17 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) cc->do_interrupt(cpu); qemu_mutex_unlock_iothread(); cpu->exception_index = -1; + + if (unlikely(cpu->singlestep_enabled)) { + /* + * After processing the exception, ensure an EXCP_DEBUG is + * raised when single-stepping so that GDB doesn't miss the + * next instruction. + */ + *ret = EXCP_DEBUG; + cpu_handle_debug_exception(cpu); + return true; + } } else if (!replay_has_interrupt()) { /* give a chance to iothread in replay mode */ *ret = EXCP_INTERRUPT; From 82e258db15dc563e1d015c19b3af2d585695a7b1 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Tue, 14 Jul 2020 08:35:36 -0700 Subject: [PATCH 2376/2595] qtest: bios-tables-test: fix a memory leak Fixes: 5da7c35e25a("bios-tables-test: Add Q35/TPM-TIS test") Signed-off-by: Li Qiang Message-Id: <20200714153536.66060-1-liq3ea@163.com> Reviewed-by: Eric Auger Reviewed-by: Igor Mammedov Signed-off-by: Thomas Huth --- tests/qtest/bios-tables-test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index c315156858..d49b3988ec 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -924,6 +924,7 @@ static void test_acpi_tcg_tpm(const char *machine, const char *tpm_if, g_free(variant); g_free(tmp_path); g_free(tmp_dir_name); + g_free(args); free_test_data(&data); #else g_test_skip("TPM disabled"); From 15c51f724ec61ab6a6910c41113d6d07164b6ca4 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Wed, 15 Jul 2020 08:41:17 -0700 Subject: [PATCH 2377/2595] tests: qmp-cmd-test: fix memory leak Properly free each test response to avoid memory leak and separate qtest_qmp() calls with spare lines, in a consistent manner. Fixes: 5b88849e7b9("tests/qmp-cmd-test: Add qmp/object-add-failure-modes") Reviewed-by: Eric Auger Signed-off-by: Li Qiang Message-Id: <20200715154117.15456-1-liq3ea@163.com> Fixes: 9fc719b869 ("tests/qmp-cmd-test: Add qmp/object-add-duplicate-id") Reviewed-by: Markus Armbruster Signed-off-by: Thomas Huth --- tests/qtest/qmp-cmd-test.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c index c68f99f659..f7b1aa7fdc 100644 --- a/tests/qtest/qmp-cmd-test.c +++ b/tests/qtest/qmp-cmd-test.c @@ -230,6 +230,8 @@ static void test_object_add_failure_modes(void) " 'props': {'size': 1048576 } } }"); g_assert_nonnull(resp); g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," " 'props': {'size': 1048576 } } }"); @@ -241,6 +243,7 @@ static void test_object_add_failure_modes(void) " {'id': 'ram1' } }"); g_assert_nonnull(resp); g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); /* attempt to create an object with a property of a wrong type */ resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" @@ -249,17 +252,20 @@ static void test_object_add_failure_modes(void) g_assert_nonnull(resp); /* now do it right */ qmp_assert_error_class(resp, "GenericError"); + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," " 'props': {'size': 1048576 } } }"); g_assert_nonnull(resp); g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); /* delete ram1 object */ resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" " {'id': 'ram1' } }"); g_assert_nonnull(resp); g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); /* attempt to create an object without the id */ resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" @@ -267,18 +273,21 @@ static void test_object_add_failure_modes(void) " 'props': {'size': 1048576 } } }"); g_assert_nonnull(resp); qmp_assert_error_class(resp, "GenericError"); + /* now do it right */ resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," " 'props': {'size': 1048576 } } }"); g_assert_nonnull(resp); g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); /* delete ram1 object */ resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" " {'id': 'ram1' } }"); g_assert_nonnull(resp); g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); /* attempt to set a non existing property */ resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" @@ -286,23 +295,27 @@ static void test_object_add_failure_modes(void) " 'props': {'sized': 1048576 } } }"); g_assert_nonnull(resp); qmp_assert_error_class(resp, "GenericError"); + /* now do it right */ resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," " 'props': {'size': 1048576 } } }"); g_assert_nonnull(resp); g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); /* delete ram1 object without id */ resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" " {'ida': 'ram1' } }"); g_assert_nonnull(resp); + qobject_unref(resp); /* delete ram1 object */ resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" " {'id': 'ram1' } }"); g_assert_nonnull(resp); g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); /* delete ram1 object that does not exist anymore*/ resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" From f5ec79f5e0a3a307fc2a11b3ba8066a2d0a90233 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Tue, 14 Jul 2020 13:46:16 -0400 Subject: [PATCH 2378/2595] fuzz: Expect the cmdline in a freeable GString In the initial FuzzTarget, get_init_cmdline returned a char *. With this API, we had no guarantee about where the string came from. For example, i440fx-qtest-reboot-fuzz simply returned a pointer to a string literal, while the QOS-based targets build the arguments out in a GString an return the gchar *str pointer. Since we did not try to free the cmdline, we have a leak for any targets that do not simply return string literals. Clean up this mess by forcing fuzz-targets to return a GString, that we can free. Signed-off-by: Alexander Bulekov Message-Id: <20200714174616.20709-1-alxndr@bu.edu> Reviewed-by: Darren Kenny Signed-off-by: Thomas Huth --- tests/qtest/fuzz/fuzz.c | 13 ++++++------- tests/qtest/fuzz/fuzz.h | 6 +++--- tests/qtest/fuzz/i440fx_fuzz.c | 4 ++-- tests/qtest/fuzz/qos_fuzz.c | 6 +++--- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 0b66e43409..6bc17ef313 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -199,16 +199,15 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) } /* Run QEMU's softmmu main with the fuzz-target dependent arguments */ - const char *init_cmdline = fuzz_target->get_init_cmdline(fuzz_target); - init_cmdline = g_strdup_printf("%s -qtest /dev/null -qtest-log %s", - init_cmdline, - getenv("QTEST_LOG") ? "/dev/fd/2" - : "/dev/null"); - + GString *cmd_line = fuzz_target->get_init_cmdline(fuzz_target); + g_string_append_printf(cmd_line, + " -qtest /dev/null -qtest-log %s", + getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null"); /* Split the runcmd into an argv and argc */ wordexp_t result; - wordexp(init_cmdline, &result, 0); + wordexp(cmd_line->str, &result, 0); + g_string_free(cmd_line, true); qemu_init(result.we_wordc, result.we_wordv, NULL); diff --git a/tests/qtest/fuzz/fuzz.h b/tests/qtest/fuzz/fuzz.h index 72d5710f6c..9ca3d107c5 100644 --- a/tests/qtest/fuzz/fuzz.h +++ b/tests/qtest/fuzz/fuzz.h @@ -50,10 +50,10 @@ typedef struct FuzzTarget { /* - * returns the arg-list that is passed to qemu/softmmu init() - * Cannot be NULL + * Returns the arguments that are passed to qemu/softmmu init(). Freed by + * the caller. */ - const char* (*get_init_cmdline)(struct FuzzTarget *); + GString *(*get_init_cmdline)(struct FuzzTarget *); /* * will run once, prior to running qemu/softmmu init. diff --git a/tests/qtest/fuzz/i440fx_fuzz.c b/tests/qtest/fuzz/i440fx_fuzz.c index e2f31e56f9..bf966d478b 100644 --- a/tests/qtest/fuzz/i440fx_fuzz.c +++ b/tests/qtest/fuzz/i440fx_fuzz.c @@ -158,9 +158,9 @@ static void i440fx_fuzz_qos_fork(QTestState *s, static const char *i440fx_qtest_argv = TARGET_NAME " -machine accel=qtest" " -m 0 -display none"; -static const char *i440fx_argv(FuzzTarget *t) +static GString *i440fx_argv(FuzzTarget *t) { - return i440fx_qtest_argv; + return g_string_new(i440fx_qtest_argv); } static void fork_init(void) diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c index 0c68f5361f..d52f3ebd83 100644 --- a/tests/qtest/fuzz/qos_fuzz.c +++ b/tests/qtest/fuzz/qos_fuzz.c @@ -66,7 +66,7 @@ void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc) return allocate_objects(qts, current_path + 1, p_alloc); } -static const char *qos_build_main_args(void) +static GString *qos_build_main_args(void) { char **path = fuzz_path_vec; QOSGraphNode *test_node; @@ -88,7 +88,7 @@ static const char *qos_build_main_args(void) /* Prepend the arguments that we need */ g_string_prepend(cmd_line, TARGET_NAME " -display none -machine accel=qtest -m 64 "); - return cmd_line->str; + return cmd_line; } /* @@ -189,7 +189,7 @@ static void walk_path(QOSGraphNode *orig_path, int len) g_free(path_str); } -static const char *qos_get_cmdline(FuzzTarget *t) +static GString *qos_get_cmdline(FuzzTarget *t) { /* * Set a global variable that we use to identify the qos_path for our From 12a9b8d8240aaddf14774b9fb03af5e2e0b9f60a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 16 Jul 2020 07:12:22 +0200 Subject: [PATCH 2379/2595] configure: Fix for running with --enable-werror on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The configure script currently refuses to succeed when run on macOS with --enable-werror: ERROR: configure test passed without -Werror but failed with -Werror. The information in config.log indicates: config-temp/qemu-conf.c:3:55: error: control reaches end of non-void function [-Werror,-Wreturn-type] static void *f(void *p) { pthread_setname_np("QEMU"); } ^ And indeed, the return statement is missing here. Fixes: 479a57475e ("util: Implement debug-threads for macOS") Message-Id: <20200716055655.24507-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index b751c853f5..e93836aaae 100755 --- a/configure +++ b/configure @@ -4198,7 +4198,7 @@ pthread_setname_np_wo_tid=no cat > $TMPC << EOF #include -static void *f(void *p) { pthread_setname_np("QEMU"); } +static void *f(void *p) { pthread_setname_np("QEMU"); return NULL; } int main(void) { pthread_t thread; From ab2d185d6b1d3aa1ab2416a896347d235e32ac3d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 14 Jul 2020 18:01:59 +0200 Subject: [PATCH 2380/2595] qom: Plug memory leak in "info qom-tree" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit e8c9e65816 "qom: Make "info qom-tree" show children sorted" created a memory leak, because I didn't realize object_get_canonical_path_component()'s value needs to be freed. Reproducer: $ qemu-system-x86_64 -nodefaults -display none -S -monitor stdio QEMU 5.0.50 monitor - type 'help' for more information (qemu) info qom-tree This leaks some 4500 path components, 12-13 characters on average, i.e. roughly 100kBytes depending on the allocator. A couple of hundred "info qom-tree" here, a couple of hundred there, and soon enough we're talking about real memory. Plug the leak. Fixes: e8c9e65816f5dbfe18ad3b2be938d0d8192d459a Signed-off-by: Markus Armbruster Reported-by: Reviewed-by: Li Qiang [sent same patch] Message-Id: <20200714160202.3121879-3-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- qom/qom-hmp-cmds.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index 9ed8bb1c9f..aaacadacca 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -96,8 +96,10 @@ static void print_qom_composition(Monitor *mon, Object *obj, int indent); static int qom_composition_compare(const void *a, const void *b, void *ignore) { - return g_strcmp0(a ? object_get_canonical_path_component(a) : NULL, - b ? object_get_canonical_path_component(b) : NULL); + g_autofree char *ac = object_get_canonical_path_component(a); + g_autofree char *bc = object_get_canonical_path_component(b); + + return g_strcmp0(ac, bc); } static int insert_qom_composition_child(Object *obj, void *opaque) From b610eba335d5c8ac7484dbb1c886b125e2dea058 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 15 Jul 2020 06:32:48 +0200 Subject: [PATCH 2381/2595] gitlab-ci.yml: Add fuzzer tests So far we neither compile-tested nor run any of the new fuzzers in our CI, which led to some build failures of the fuzzer code in the past weeks. To avoid this problem, add a job to compile the fuzzer code and run some loops (which likely don't find any new bugs via fuzzing, but at least we know that the code can still be run). A nice side-effect of this test is that the leak tests are enabled here, so we should now notice some of the memory leaks in our code base earlier. Message-Id: <20200716100950.27396-1-thuth@redhat.com> Reviewed-by: Alexander Bulekov Signed-off-by: Thomas Huth --- .gitlab-ci.yml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5eeba2791b..41597c3603 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -161,9 +161,27 @@ build-clang: IMAGE: fedora CONFIGURE_ARGS: --cc=clang --cxx=clang++ TARGETS: alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu - ppc-softmmu s390x-softmmu x86_64-softmmu arm-linux-user + ppc-softmmu s390x-softmmu arm-linux-user MAKE_CHECK_ARGS: check +build-fuzzer: + <<: *native_build_job_definition + variables: + IMAGE: fedora + script: + - mkdir build + - cd build + - ../configure --cc=clang --cxx=clang++ --enable-fuzzing + --enable-sanitizers --target-list=x86_64-softmmu + - make -j"$JOBS" all check-build x86_64-softmmu/fuzz + - make check + - for fuzzer in i440fx-qos-fork-fuzz i440fx-qos-noreset-fuzz + i440fx-qtest-reboot-fuzz virtio-scsi-flags-fuzz virtio-scsi-fuzz ; do + echo Testing ${fuzzer} ... ; + x86_64-softmmu/qemu-fuzz-x86_64 --fuzz-target=${fuzzer} -runs=1000 + || exit 1 ; + done + build-tci: <<: *native_build_job_definition variables: From 9ece07d7a3941eeb845a6f000a191bba19557231 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 16 Jul 2020 16:50:31 +0200 Subject: [PATCH 2382/2595] docs/s390x: fix vfio-ccw type Fix the type name in the mdevctl example. Signed-off-by: Cornelia Huck Reviewed-by: Eric Farman Message-Id: <20200716145031.771476-1-cohuck@redhat.com> --- docs/system/s390x/vfio-ccw.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/system/s390x/vfio-ccw.rst b/docs/system/s390x/vfio-ccw.rst index 8f65442c0f..41e0bad5b4 100644 --- a/docs/system/s390x/vfio-ccw.rst +++ b/docs/system/s390x/vfio-ccw.rst @@ -29,7 +29,7 @@ automatically, use [root@host ~]# driverctl -b css set-override 0.0.0313 vfio_ccw [root@host ~]# mdevctl define -u 7e270a25-e163-4922-af60-757fc8ed48c6 \ - -p 0.0.0313 -t vfio-ccw_io -a + -p 0.0.0313 -t vfio_ccw-io -a If using ``mdevctl`` is not possible or wanted, follow the manual procedure below. From 4b7c5bc447070bd1573bc8ae7294f3a64525c20b Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Sat, 11 Jul 2020 00:34:51 +0530 Subject: [PATCH 2383/2595] vvfat: set status to odd fixes Virtual VFAT driver is quite old and rarely used. Set its status to Odd Fixes. Signed-off-by: Prasad J Pandit Message-Id: <20200710190451.761286-1-ppandit@redhat.com> Signed-off-by: Kevin Wolf --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 030faf0249..5d9c56e441 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2987,7 +2987,7 @@ F: block/vpc.c vvfat M: Kevin Wolf L: qemu-block@nongnu.org -S: Supported +S: Odd Fixes F: block/vvfat.c Image format fuzzer From a08464521ccb302a24c7785f50ce32473904136c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sat, 11 Jul 2020 10:59:26 +0400 Subject: [PATCH 2384/2595] Remove VXHS block device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vxhs code doesn't compile since v2.12.0. There's no point in fixing and then adding CI for a config that our users have demonstrated that they do not use; better to just remove it. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster Message-Id: <20200711065926.2204721-1-marcandre.lureau@redhat.com> Signed-off-by: Kevin Wolf --- block/Makefile.objs | 2 - block/trace-events | 17 - block/vxhs.c | 587 ------------------------------- configure | 39 -- docs/system/deprecated.rst | 8 + qapi/block-core.json | 22 +- tests/qemu-iotests/017 | 1 - tests/qemu-iotests/029 | 1 - tests/qemu-iotests/073 | 1 - tests/qemu-iotests/114 | 1 - tests/qemu-iotests/130 | 1 - tests/qemu-iotests/134 | 1 - tests/qemu-iotests/156 | 1 - tests/qemu-iotests/158 | 1 - tests/qemu-iotests/282 | 1 - tests/qemu-iotests/check | 10 - tests/qemu-iotests/common.filter | 1 - tests/qemu-iotests/common.rc | 33 -- 18 files changed, 10 insertions(+), 718 deletions(-) delete mode 100644 block/vxhs.c diff --git a/block/Makefile.objs b/block/Makefile.objs index 577e578bc2..19c6f371c9 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -31,7 +31,6 @@ block-obj-$(CONFIG_LIBNFS) += nfs.o block-obj-$(CONFIG_CURL) += curl.o block-obj-$(CONFIG_RBD) += rbd.o block-obj-$(CONFIG_GLUSTERFS) += gluster.o -block-obj-$(CONFIG_VXHS) += vxhs.o block-obj-$(CONFIG_LIBSSH) += ssh.o block-obj-y += accounting.o dirty-bitmap.o block-obj-y += write-threshold.o @@ -61,7 +60,6 @@ rbd.o-cflags := $(RBD_CFLAGS) rbd.o-libs := $(RBD_LIBS) gluster.o-cflags := $(GLUSTERFS_CFLAGS) gluster.o-libs := $(GLUSTERFS_LIBS) -vxhs.o-libs := $(VXHS_LIBS) ssh.o-cflags := $(LIBSSH_CFLAGS) ssh.o-libs := $(LIBSSH_LIBS) block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o diff --git a/block/trace-events b/block/trace-events index dbe76a7613..d3533ca896 100644 --- a/block/trace-events +++ b/block/trace-events @@ -136,23 +136,6 @@ qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t o qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64 qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu" -# vxhs.c -vxhs_iio_callback(int error) "ctx is NULL: error %d" -vxhs_iio_callback_chnfail(int err, int error) "QNIO channel failed, no i/o %d, %d" -vxhs_iio_callback_unknwn(int opcode, int err) "unexpected opcode %d, errno %d" -vxhs_aio_rw_invalid(int req) "Invalid I/O request iodir %d" -vxhs_aio_rw_ioerr(char *guid, int iodir, uint64_t size, uint64_t off, void *acb, int ret, int err) "IO ERROR (vDisk %s) FOR : Read/Write = %d size = %"PRIu64" offset = %"PRIu64" ACB = %p. Error = %d, errno = %d" -vxhs_get_vdisk_stat_err(char *guid, int ret, int err) "vDisk (%s) stat ioctl failed, ret = %d, errno = %d" -vxhs_get_vdisk_stat(char *vdisk_guid, uint64_t vdisk_size) "vDisk %s stat ioctl returned size %"PRIu64 -vxhs_complete_aio(void *acb, uint64_t ret) "aio failed acb %p ret %"PRIu64 -vxhs_parse_uri_filename(const char *filename) "URI passed via bdrv_parse_filename %s" -vxhs_open_vdiskid(const char *vdisk_id) "Opening vdisk-id %s" -vxhs_open_hostinfo(char *of_vsa_addr, int port) "Adding host %s:%d to BDRVVXHSState" -vxhs_open_iio_open(const char *host) "Failed to connect to storage agent on host %s" -vxhs_parse_uri_hostinfo(char *host, int port) "Host: IP %s, Port %d" -vxhs_close(char *vdisk_guid) "Closing vdisk %s" -vxhs_get_creds(const char *cacert, const char *client_key, const char *client_cert) "cacert %s, client_key %s, client_cert %s" - # nvme.c nvme_kick(void *s, int queue) "s %p queue %d" nvme_dma_flush_queue_wait(void *s) "s %p" diff --git a/block/vxhs.c b/block/vxhs.c deleted file mode 100644 index dc0e254730..0000000000 --- a/block/vxhs.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - * QEMU Block driver for Veritas HyperScale (VxHS) - * - * Copyright (c) 2017 Veritas Technologies LLC. - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include -#include -#include "block/block_int.h" -#include "block/qdict.h" -#include "qapi/qmp/qerror.h" -#include "qapi/qmp/qdict.h" -#include "qapi/qmp/qstring.h" -#include "trace.h" -#include "qemu/module.h" -#include "qemu/uri.h" -#include "qapi/error.h" -#include "qemu/uuid.h" -#include "crypto/tlscredsx509.h" -#include "sysemu/replay.h" - -#define VXHS_OPT_FILENAME "filename" -#define VXHS_OPT_VDISK_ID "vdisk-id" -#define VXHS_OPT_SERVER "server" -#define VXHS_OPT_HOST "host" -#define VXHS_OPT_PORT "port" - -/* Only accessed under QEMU global mutex */ -static uint32_t vxhs_ref; - -typedef enum { - VDISK_AIO_READ, - VDISK_AIO_WRITE, -} VDISKAIOCmd; - -/* - * HyperScale AIO callbacks structure - */ -typedef struct VXHSAIOCB { - BlockAIOCB common; - int err; -} VXHSAIOCB; - -typedef struct VXHSvDiskHostsInfo { - void *dev_handle; /* Device handle */ - char *host; /* Host name or IP */ - int port; /* Host's port number */ -} VXHSvDiskHostsInfo; - -/* - * Structure per vDisk maintained for state - */ -typedef struct BDRVVXHSState { - VXHSvDiskHostsInfo vdisk_hostinfo; /* Per host info */ - char *vdisk_guid; - char *tlscredsid; /* tlscredsid */ -} BDRVVXHSState; - -static void vxhs_complete_aio_bh(void *opaque) -{ - VXHSAIOCB *acb = opaque; - BlockCompletionFunc *cb = acb->common.cb; - void *cb_opaque = acb->common.opaque; - int ret = 0; - - if (acb->err != 0) { - trace_vxhs_complete_aio(acb, acb->err); - ret = (-EIO); - } - - qemu_aio_unref(acb); - cb(cb_opaque, ret); -} - -/* - * Called from a libqnio thread - */ -static void vxhs_iio_callback(void *ctx, uint32_t opcode, uint32_t error) -{ - VXHSAIOCB *acb = NULL; - - switch (opcode) { - case IRP_READ_REQUEST: - case IRP_WRITE_REQUEST: - - /* - * ctx is VXHSAIOCB* - * ctx is NULL if error is QNIOERROR_CHANNEL_HUP - */ - if (ctx) { - acb = ctx; - } else { - trace_vxhs_iio_callback(error); - goto out; - } - - if (error) { - if (!acb->err) { - acb->err = error; - } - trace_vxhs_iio_callback(error); - } - - replay_bh_schedule_oneshot_event(bdrv_get_aio_context(acb->common.bs), - vxhs_complete_aio_bh, acb); - break; - - default: - if (error == QNIOERROR_HUP) { - /* - * Channel failed, spontaneous notification, - * not in response to I/O - */ - trace_vxhs_iio_callback_chnfail(error, errno); - } else { - trace_vxhs_iio_callback_unknwn(opcode, error); - } - break; - } -out: - return; -} - -static QemuOptsList runtime_opts = { - .name = "vxhs", - .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), - .desc = { - { - .name = VXHS_OPT_FILENAME, - .type = QEMU_OPT_STRING, - .help = "URI to the Veritas HyperScale image", - }, - { - .name = VXHS_OPT_VDISK_ID, - .type = QEMU_OPT_STRING, - .help = "UUID of the VxHS vdisk", - }, - { - .name = "tls-creds", - .type = QEMU_OPT_STRING, - .help = "ID of the TLS/SSL credentials to use", - }, - { /* end of list */ } - }, -}; - -static QemuOptsList runtime_tcp_opts = { - .name = "vxhs_tcp", - .head = QTAILQ_HEAD_INITIALIZER(runtime_tcp_opts.head), - .desc = { - { - .name = VXHS_OPT_HOST, - .type = QEMU_OPT_STRING, - .help = "host address (ipv4 addresses)", - }, - { - .name = VXHS_OPT_PORT, - .type = QEMU_OPT_NUMBER, - .help = "port number on which VxHSD is listening (default 9999)", - .def_value_str = "9999" - }, - { /* end of list */ } - }, -}; - -/* - * Parse incoming URI and populate *options with the host - * and device information - */ -static int vxhs_parse_uri(const char *filename, QDict *options) -{ - URI *uri = NULL; - char *port; - int ret = 0; - - trace_vxhs_parse_uri_filename(filename); - uri = uri_parse(filename); - if (!uri || !uri->server || !uri->path) { - uri_free(uri); - return -EINVAL; - } - - qdict_put_str(options, VXHS_OPT_SERVER ".host", uri->server); - - if (uri->port) { - port = g_strdup_printf("%d", uri->port); - qdict_put_str(options, VXHS_OPT_SERVER ".port", port); - g_free(port); - } - - qdict_put_str(options, "vdisk-id", uri->path); - - trace_vxhs_parse_uri_hostinfo(uri->server, uri->port); - uri_free(uri); - - return ret; -} - -static void vxhs_parse_filename(const char *filename, QDict *options, - Error **errp) -{ - if (qdict_haskey(options, "vdisk-id") || qdict_haskey(options, "server")) { - error_setg(errp, "vdisk-id/server and a file name may not be specified " - "at the same time"); - return; - } - - if (strstr(filename, "://")) { - int ret = vxhs_parse_uri(filename, options); - if (ret < 0) { - error_setg(errp, "Invalid URI. URI should be of the form " - " vxhs://:/"); - } - } -} - -static void vxhs_refresh_limits(BlockDriverState *bs, Error **errp) -{ - /* XXX Does VXHS support AIO on less than 512-byte alignment? */ - bs->bl.request_alignment = 512; -} - -static int vxhs_init_and_ref(void) -{ - if (vxhs_ref++ == 0) { - if (iio_init(QNIO_VERSION, vxhs_iio_callback)) { - return -ENODEV; - } - } - return 0; -} - -static void vxhs_unref(void) -{ - if (--vxhs_ref == 0) { - iio_fini(); - } -} - -static void vxhs_get_tls_creds(const char *id, char **cacert, - char **key, char **cert, Error **errp) -{ - Object *obj; - QCryptoTLSCreds *creds; - QCryptoTLSCredsX509 *creds_x509; - - obj = object_resolve_path_component( - object_get_objects_root(), id); - - if (!obj) { - error_setg(errp, "No TLS credentials with id '%s'", - id); - return; - } - - creds_x509 = (QCryptoTLSCredsX509 *) - object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS_X509); - - if (!creds_x509) { - error_setg(errp, "Object with id '%s' is not TLS credentials", - id); - return; - } - - creds = &creds_x509->parent_obj; - - if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) { - error_setg(errp, - "Expecting TLS credentials with a client endpoint"); - return; - } - - /* - * Get the cacert, client_cert and client_key file names. - */ - if (!creds->dir) { - error_setg(errp, "TLS object missing 'dir' property value"); - return; - } - - *cacert = g_strdup_printf("%s/%s", creds->dir, - QCRYPTO_TLS_CREDS_X509_CA_CERT); - *cert = g_strdup_printf("%s/%s", creds->dir, - QCRYPTO_TLS_CREDS_X509_CLIENT_CERT); - *key = g_strdup_printf("%s/%s", creds->dir, - QCRYPTO_TLS_CREDS_X509_CLIENT_KEY); -} - -static int vxhs_open(BlockDriverState *bs, QDict *options, - int bdrv_flags, Error **errp) -{ - BDRVVXHSState *s = bs->opaque; - void *dev_handlep; - QDict *backing_options = NULL; - QemuOpts *opts = NULL; - QemuOpts *tcp_opts = NULL; - char *of_vsa_addr = NULL; - Error *local_err = NULL; - const char *vdisk_id_opt; - const char *server_host_opt; - int ret = 0; - char *cacert = NULL; - char *client_key = NULL; - char *client_cert = NULL; - - ret = vxhs_init_and_ref(); - if (ret < 0) { - ret = -EINVAL; - goto out; - } - - /* Create opts info from runtime_opts and runtime_tcp_opts list */ - opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - tcp_opts = qemu_opts_create(&runtime_tcp_opts, NULL, 0, &error_abort); - - if (!qemu_opts_absorb_qdict(opts, options, errp)) { - ret = -EINVAL; - goto out; - } - - /* vdisk-id is the disk UUID */ - vdisk_id_opt = qemu_opt_get(opts, VXHS_OPT_VDISK_ID); - if (!vdisk_id_opt) { - error_setg(errp, QERR_MISSING_PARAMETER, VXHS_OPT_VDISK_ID); - ret = -EINVAL; - goto out; - } - - /* vdisk-id may contain a leading '/' */ - if (strlen(vdisk_id_opt) > UUID_FMT_LEN + 1) { - error_setg(errp, "vdisk-id cannot be more than %d characters", - UUID_FMT_LEN); - ret = -EINVAL; - goto out; - } - - s->vdisk_guid = g_strdup(vdisk_id_opt); - trace_vxhs_open_vdiskid(vdisk_id_opt); - - /* get the 'server.' arguments */ - qdict_extract_subqdict(options, &backing_options, VXHS_OPT_SERVER"."); - - if (!qemu_opts_absorb_qdict(tcp_opts, backing_options, errp)) { - ret = -EINVAL; - goto out; - } - - server_host_opt = qemu_opt_get(tcp_opts, VXHS_OPT_HOST); - if (!server_host_opt) { - error_setg(errp, QERR_MISSING_PARAMETER, - VXHS_OPT_SERVER"."VXHS_OPT_HOST); - ret = -EINVAL; - goto out; - } - - if (strlen(server_host_opt) > MAXHOSTNAMELEN) { - error_setg(errp, "server.host cannot be more than %d characters", - MAXHOSTNAMELEN); - ret = -EINVAL; - goto out; - } - - /* check if we got tls-creds via the --object argument */ - s->tlscredsid = g_strdup(qemu_opt_get(opts, "tls-creds")); - if (s->tlscredsid) { - vxhs_get_tls_creds(s->tlscredsid, &cacert, &client_key, - &client_cert, &local_err); - if (local_err != NULL) { - ret = -EINVAL; - goto out; - } - trace_vxhs_get_creds(cacert, client_key, client_cert); - } - - s->vdisk_hostinfo.host = g_strdup(server_host_opt); - s->vdisk_hostinfo.port = g_ascii_strtoll(qemu_opt_get(tcp_opts, - VXHS_OPT_PORT), - NULL, 0); - - trace_vxhs_open_hostinfo(s->vdisk_hostinfo.host, - s->vdisk_hostinfo.port); - - of_vsa_addr = g_strdup_printf("of://%s:%d", - s->vdisk_hostinfo.host, - s->vdisk_hostinfo.port); - - /* - * Open qnio channel to storage agent if not opened before - */ - dev_handlep = iio_open(of_vsa_addr, s->vdisk_guid, 0, - cacert, client_key, client_cert); - if (dev_handlep == NULL) { - trace_vxhs_open_iio_open(of_vsa_addr); - ret = -ENODEV; - goto out; - } - s->vdisk_hostinfo.dev_handle = dev_handlep; - -out: - g_free(of_vsa_addr); - qobject_unref(backing_options); - qemu_opts_del(tcp_opts); - qemu_opts_del(opts); - g_free(cacert); - g_free(client_key); - g_free(client_cert); - - if (ret < 0) { - vxhs_unref(); - g_free(s->vdisk_hostinfo.host); - g_free(s->vdisk_guid); - g_free(s->tlscredsid); - s->vdisk_guid = NULL; - } - - return ret; -} - -static const AIOCBInfo vxhs_aiocb_info = { - .aiocb_size = sizeof(VXHSAIOCB) -}; - -/* - * This allocates QEMU-VXHS callback for each IO - * and is passed to QNIO. When QNIO completes the work, - * it will be passed back through the callback. - */ -static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, uint64_t offset, - QEMUIOVector *qiov, uint64_t size, - BlockCompletionFunc *cb, void *opaque, - VDISKAIOCmd iodir) -{ - VXHSAIOCB *acb = NULL; - BDRVVXHSState *s = bs->opaque; - int iio_flags = 0; - int ret = 0; - void *dev_handle = s->vdisk_hostinfo.dev_handle; - - acb = qemu_aio_get(&vxhs_aiocb_info, bs, cb, opaque); - - /* - * Initialize VXHSAIOCB. - */ - acb->err = 0; - - iio_flags = IIO_FLAG_ASYNC; - - switch (iodir) { - case VDISK_AIO_WRITE: - ret = iio_writev(dev_handle, acb, qiov->iov, qiov->niov, - offset, size, iio_flags); - break; - case VDISK_AIO_READ: - ret = iio_readv(dev_handle, acb, qiov->iov, qiov->niov, - offset, size, iio_flags); - break; - default: - trace_vxhs_aio_rw_invalid(iodir); - goto errout; - } - - if (ret != 0) { - trace_vxhs_aio_rw_ioerr(s->vdisk_guid, iodir, size, offset, - acb, ret, errno); - goto errout; - } - return &acb->common; - -errout: - qemu_aio_unref(acb); - return NULL; -} - -static BlockAIOCB *vxhs_aio_preadv(BlockDriverState *bs, - uint64_t offset, uint64_t bytes, - QEMUIOVector *qiov, int flags, - BlockCompletionFunc *cb, void *opaque) -{ - return vxhs_aio_rw(bs, offset, qiov, bytes, cb, opaque, VDISK_AIO_READ); -} - -static BlockAIOCB *vxhs_aio_pwritev(BlockDriverState *bs, - uint64_t offset, uint64_t bytes, - QEMUIOVector *qiov, int flags, - BlockCompletionFunc *cb, void *opaque) -{ - return vxhs_aio_rw(bs, offset, qiov, bytes, cb, opaque, VDISK_AIO_WRITE); -} - -static void vxhs_close(BlockDriverState *bs) -{ - BDRVVXHSState *s = bs->opaque; - - trace_vxhs_close(s->vdisk_guid); - - g_free(s->vdisk_guid); - s->vdisk_guid = NULL; - - /* - * Close vDisk device - */ - if (s->vdisk_hostinfo.dev_handle) { - iio_close(s->vdisk_hostinfo.dev_handle); - s->vdisk_hostinfo.dev_handle = NULL; - } - - vxhs_unref(); - - /* - * Free the dynamically allocated host string etc - */ - g_free(s->vdisk_hostinfo.host); - g_free(s->tlscredsid); - s->tlscredsid = NULL; - s->vdisk_hostinfo.host = NULL; - s->vdisk_hostinfo.port = 0; -} - -static int64_t vxhs_get_vdisk_stat(BDRVVXHSState *s) -{ - int64_t vdisk_size = -1; - int ret = 0; - void *dev_handle = s->vdisk_hostinfo.dev_handle; - - ret = iio_ioctl(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0); - if (ret < 0) { - trace_vxhs_get_vdisk_stat_err(s->vdisk_guid, ret, errno); - return -EIO; - } - - trace_vxhs_get_vdisk_stat(s->vdisk_guid, vdisk_size); - return vdisk_size; -} - -/* - * Returns the size of vDisk in bytes. This is required - * by QEMU block upper block layer so that it is visible - * to guest. - */ -static int64_t vxhs_getlength(BlockDriverState *bs) -{ - BDRVVXHSState *s = bs->opaque; - int64_t vdisk_size; - - vdisk_size = vxhs_get_vdisk_stat(s); - if (vdisk_size < 0) { - return -EIO; - } - - return vdisk_size; -} - -static const char *const vxhs_strong_runtime_opts[] = { - VXHS_OPT_VDISK_ID, - "tls-creds", - VXHS_OPT_HOST, - VXHS_OPT_PORT, - VXHS_OPT_SERVER".", - - NULL -}; - -static BlockDriver bdrv_vxhs = { - .format_name = "vxhs", - .protocol_name = "vxhs", - .instance_size = sizeof(BDRVVXHSState), - .bdrv_file_open = vxhs_open, - .bdrv_parse_filename = vxhs_parse_filename, - .bdrv_refresh_limits = vxhs_refresh_limits, - .bdrv_close = vxhs_close, - .bdrv_getlength = vxhs_getlength, - .bdrv_aio_preadv = vxhs_aio_preadv, - .bdrv_aio_pwritev = vxhs_aio_pwritev, - .strong_runtime_opts = vxhs_strong_runtime_opts, -}; - -static void bdrv_vxhs_init(void) -{ - bdrv_register(&bdrv_vxhs); -} - -block_init(bdrv_vxhs_init); diff --git a/configure b/configure index b751c853f5..8227962b45 100755 --- a/configure +++ b/configure @@ -501,7 +501,6 @@ numa="" tcmalloc="no" jemalloc="no" replication="yes" -vxhs="" bochs="yes" cloop="yes" dmg="yes" @@ -1541,10 +1540,6 @@ for opt do ;; --enable-replication) replication="yes" ;; - --disable-vxhs) vxhs="no" - ;; - --enable-vxhs) vxhs="yes" - ;; --disable-bochs) bochs="no" ;; --enable-bochs) bochs="yes" @@ -1932,7 +1927,6 @@ disabled with --disable-FEATURE, default is enabled if available: xfsctl xfsctl support qom-cast-debug cast debugging support tools build qemu-io, qemu-nbd and qemu-img tools - vxhs Veritas HyperScale vDisk backend support bochs bochs image format support cloop cloop image format support dmg dmg image format support @@ -6249,33 +6243,6 @@ if compile_prog "" "" ; then have_sysmacros=yes fi -########################################## -# Veritas HyperScale block driver VxHS -# Check if libvxhs is installed - -if test "$vxhs" != "no" ; then - cat > $TMPC < -#include - -void *vxhs_callback; - -int main(void) { - iio_init(QNIO_VERSION, vxhs_callback); - return 0; -} -EOF - vxhs_libs="-lvxhs -lssl" - if compile_prog "" "$vxhs_libs" ; then - vxhs=yes - else - if test "$vxhs" = "yes" ; then - feature_not_found "vxhs block device" "Install libvxhs See github" - fi - vxhs=no - fi -fi - ########################################## # check for _Static_assert() @@ -7033,7 +7000,6 @@ echo "jemalloc support $jemalloc" echo "avx2 optimization $avx2_opt" echo "avx512f optimization $avx512f_opt" echo "replication support $replication" -echo "VxHS block device $vxhs" echo "bochs support $bochs" echo "cloop support $cloop" echo "dmg support $dmg" @@ -7884,11 +7850,6 @@ elif test "$pthread_setname_np_wo_tid" = "yes" ; then echo "CONFIG_PTHREAD_SETNAME_NP_WO_TID=y" >> $config_host_mak fi -if test "$vxhs" = "yes" ; then - echo "CONFIG_VXHS=y" >> $config_host_mak - echo "VXHS_LIBS=$vxhs_libs" >> $config_host_mak -fi - if test "$libpmem" = "yes" ; then echo "CONFIG_LIBPMEM=y" >> $config_host_mak fi diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 971b65be75..851dbdeb8a 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -618,3 +618,11 @@ to achieve the same fake NUMA effect or a properly configured New machine versions (since 5.1) will not accept the option but it will still work with old machine types. User can check the QAPI schema to see if the legacy option is supported by looking at MachineInfo::numa-mem-supported property. + +Block devices +------------- + +VXHS backend (removed in 5.1) +''''''''''''''''''''''''''''' + +The VXHS code does not compile since v2.12.0. It was removed in 5.1. diff --git a/qapi/block-core.json b/qapi/block-core.json index 463ffd83da..ab7bf3c612 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2790,7 +2790,6 @@ # # Drivers that are supported in block device operations. # -# @vxhs: Since 2.10 # @throttle: Since 2.11 # @nvme: Since 2.12 # @copy-on-read: Since 3.0 @@ -2808,7 +2807,7 @@ 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'rbd', { 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' }, 'sheepdog', - 'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] } + 'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] } ## # @BlockdevOptionsFile: @@ -3895,22 +3894,6 @@ 'base': 'BlockdevOptionsGenericFormat', 'data': { '*offset': 'int', '*size': 'int' } } -## -# @BlockdevOptionsVxHS: -# -# Driver specific block device options for VxHS -# -# @vdisk-id: UUID of VxHS volume -# @server: vxhs server IP, port -# @tls-creds: TLS credentials ID -# -# Since: 2.10 -## -{ 'struct': 'BlockdevOptionsVxHS', - 'data': { 'vdisk-id': 'str', - 'server': 'InetSocketAddressBase', - '*tls-creds': 'str' } } - ## # @BlockdevOptionsThrottle: # @@ -4010,8 +3993,7 @@ 'vhdx': 'BlockdevOptionsGenericFormat', 'vmdk': 'BlockdevOptionsGenericCOWFormat', 'vpc': 'BlockdevOptionsGenericFormat', - 'vvfat': 'BlockdevOptionsVVFAT', - 'vxhs': 'BlockdevOptionsVxHS' + 'vvfat': 'BlockdevOptionsVVFAT' } } ## diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017 index 585512bb29..3413e34f27 100755 --- a/tests/qemu-iotests/017 +++ b/tests/qemu-iotests/017 @@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 # Any format supporting backing files _supported_fmt qcow qcow2 vmdk qed _supported_proto generic -_unsupported_proto vxhs _unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \ "subformat=streamOptimized" diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029 index 2161a4b87a..61d78c00a4 100755 --- a/tests/qemu-iotests/029 +++ b/tests/qemu-iotests/029 @@ -41,7 +41,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 # Any format supporting intenal snapshots _supported_fmt qcow2 _supported_proto generic -_unsupported_proto vxhs # Internal snapshots are (currently) impossible with refcount_bits=1, # and generally impossible with external data files _unsupported_imgopts 'refcount_bits=1[^0-9]' data_file diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073 index 1dce478709..68517821e8 100755 --- a/tests/qemu-iotests/073 +++ b/tests/qemu-iotests/073 @@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic -_unsupported_proto vxhs # External data files do not support compressed clusters # (TODO: Consider writing a version for external data files that does # not test compressed clusters) diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114 index 5a7b0a4998..80e5e5e591 100755 --- a/tests/qemu-iotests/114 +++ b/tests/qemu-iotests/114 @@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic -_unsupported_proto vxhs # At least OpenBSD doesn't seem to have truncate _supported_os Linux # qcow2.py does not work too well with external data files diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130 index 77ad2aa13a..a7b365701c 100755 --- a/tests/qemu-iotests/130 +++ b/tests/qemu-iotests/130 @@ -42,7 +42,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic -_unsupported_proto vxhs _supported_os Linux # We are going to use lazy-refcounts _unsupported_imgopts 'compat=0.10' diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134 index 5162d21662..17fe1d6ed4 100755 --- a/tests/qemu-iotests/134 +++ b/tests/qemu-iotests/134 @@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 _supported_proto generic -_unsupported_proto vxhs size=128M diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 index 7c69a6c3fa..9c7878dd2d 100755 --- a/tests/qemu-iotests/156 +++ b/tests/qemu-iotests/156 @@ -50,7 +50,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 qed _supported_proto generic -_unsupported_proto vxhs # Copying files around with cp does not work with external data files _unsupported_imgopts data_file diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158 index 3175968e2b..cf23742c59 100755 --- a/tests/qemu-iotests/158 +++ b/tests/qemu-iotests/158 @@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 _supported_proto generic -_unsupported_proto vxhs size=128M diff --git a/tests/qemu-iotests/282 b/tests/qemu-iotests/282 index 081eb12080..27da2a0023 100755 --- a/tests/qemu-iotests/282 +++ b/tests/qemu-iotests/282 @@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt luks _supported_proto generic -_unsupported_proto vxhs echo "== Create non-UTF8 secret ==" echo -n -e '\x3a\x3c\x3b\xff' > non_utf8_secret diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 9c461cf76d..e0d8049012 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -272,7 +272,6 @@ image protocol options -nbd test nbd -ssh test ssh -nfs test nfs - -vxhs test vxhs other options -xdiff graphical mode diff @@ -383,11 +382,6 @@ testlist options xpand=false ;; - -vxhs) - IMGPROTO=vxhs - xpand=false - ;; - -ssh) IMGPROTO=ssh xpand=false @@ -646,10 +640,6 @@ if [ -z $QEMU_NBD_PROG ]; then fi export QEMU_NBD_PROG="$(type -p "$QEMU_NBD_PROG")" -if [ -z "$QEMU_VXHS_PROG" ]; then - export QEMU_VXHS_PROG="$(set_prog_path qnio_server)" -fi - if [ -x "$build_iotests/socket_scm_helper" ] then export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper" diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 9b772245cd..c6912be009 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -227,7 +227,6 @@ _filter_img_info() -e "s#$IMGFMT#IMGFMT#g" \ -e 's#nbd://127.0.0.1:[0-9]\\+$#TEST_DIR/t.IMGFMT#g' \ -e 's#nbd+unix:///\??socket=SOCK_DIR/nbd#TEST_DIR/t.IMGFMT#g' \ - -e 's#json.*vdisk-id.*vxhs"}}#TEST_DIR/t.IMGFMT#' \ -e "/encrypted: yes/d" \ -e "/cluster_size: [0-9]\\+/d" \ -e "/table_size: [0-9]\\+/d" \ diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 7ac46edc1f..494490a272 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -124,7 +124,6 @@ fi : ${VALGRIND_QEMU_IMG=$VALGRIND_QEMU} : ${VALGRIND_QEMU_IO=$VALGRIND_QEMU} : ${VALGRIND_QEMU_NBD=$VALGRIND_QEMU} -: ${VALGRIND_QEMU_VXHS=$VALGRIND_QEMU} # The Valgrind own parameters may be set with # its environment variable VALGRIND_OPTS, e.g. @@ -212,19 +211,6 @@ _qemu_nbd_wrapper() return $RETVAL } -_qemu_vxhs_wrapper() -{ - local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind - ( - echo $BASHPID > "${TEST_DIR}/qemu-vxhs.pid" - VALGRIND_QEMU="${VALGRIND_QEMU_VXHS}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \ - "$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@" - ) - RETVAL=$? - _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL - return $RETVAL -} - # Valgrind bug #409141 https://bugs.kde.org/show_bug.cgi?id=409141 # Until valgrind 3.16+ is ubiquitous, we must work around a hang in # valgrind when issuing sigkill. Disable valgrind for this invocation. @@ -237,7 +223,6 @@ export QEMU=_qemu_wrapper export QEMU_IMG=_qemu_img_wrapper export QEMU_IO=_qemu_io_wrapper export QEMU_NBD=_qemu_nbd_wrapper -export QEMU_VXHS=_qemu_vxhs_wrapper if [ "$IMGOPTSSYNTAX" = "true" ]; then DRIVER="driver=$IMGFMT" @@ -279,9 +264,6 @@ else TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT REMOTE_TEST_DIR="nfs://127.0.0.1$TEST_DIR" TEST_IMG="nfs://127.0.0.1$TEST_IMG_FILE" - elif [ "$IMGPROTO" = "vxhs" ]; then - TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT - TEST_IMG="vxhs://127.0.0.1:9999/t.$IMGFMT" else TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT fi @@ -436,12 +418,6 @@ _make_test_img() eval "$QEMU_NBD -v -t -k '$SOCK_DIR/nbd' -f $IMGFMT -e 42 -x '' $TEST_IMG_FILE >/dev/null &" sleep 1 # FIXME: qemu-nbd needs to be listening before we continue fi - - # Start QNIO server on image directory for vxhs protocol - if [ $IMGPROTO = "vxhs" ]; then - eval "$QEMU_VXHS -d $TEST_DIR > /dev/null &" - sleep 1 # Wait for server to come up. - fi } _rm_test_img() @@ -468,15 +444,6 @@ _cleanup_test_img() _stop_nbd_server rm -f "$TEST_IMG_FILE" ;; - vxhs) - if [ -f "${TEST_DIR}/qemu-vxhs.pid" ]; then - local QEMU_VXHS_PID - read QEMU_VXHS_PID < "${TEST_DIR}/qemu-vxhs.pid" - kill ${QEMU_VXHS_PID} >/dev/null 2>&1 - rm -f "${TEST_DIR}/qemu-vxhs.pid" - fi - rm -f "$TEST_IMG_FILE" - ;; file) _rm_test_img "$TEST_DIR/t.$IMGFMT" From 1c404d756fd59ecee09dec924b88c492d24b3fc8 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 10 Jul 2020 14:17:17 +0200 Subject: [PATCH 2385/2595] qemu-img resize: Require --shrink for shrinking all image formats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU 2.11 introduced the --shrink option for qemu-img resize to avoid accidentally shrinking images (commit 4ffca8904a3). However, for compatibility reasons, it was not enforced for raw images yet, but only a deprecation warning was printed. This warning has existed for long enough that we can now finally require --shrink for raw images, too, and error out if it's not given. Documentation already describes the state as it is after this patch. Signed-off-by: Kevin Wolf Message-Id: <20200710121717.28339-1-kwolf@redhat.com> Reviewed-by: Daniel P. Berrangé Signed-off-by: Kevin Wolf --- qemu-img.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index efb6ca139e..5308773811 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -4004,20 +4004,12 @@ static int img_resize(int argc, char **argv) } if (total_size < current_size && !shrink) { + error_report("Use the --shrink option to perform a shrink operation."); warn_report("Shrinking an image will delete all data beyond the " "shrunken image's end. Before performing such an " "operation, make sure there is no important data there."); - - if (g_strcmp0(bdrv_get_format_name(blk_bs(blk)), "raw") != 0) { - error_report( - "Use the --shrink option to perform a shrink operation."); - ret = -1; - goto out; - } else { - warn_report("Using the --shrink option will suppress this message. " - "Note that future versions of qemu-img may refuse to " - "shrink images without this option."); - } + ret = -1; + goto out; } /* From 3e018afbfe005a3448949bfe3954888b9d8460c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 15 Jul 2020 16:47:01 +0100 Subject: [PATCH 2386/2595] crypto: use a stronger private key for tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The unit tests using the x509 crypto functionality have started failing in Fedora 33 rawhide with a message like The certificate uses an insecure algorithm This is result of Fedora changes to support strong crypto [1]. RSA with 1024 bit key is viewed as legacy and thus insecure. Generate a new private key which is 3072 bits long and reasonable future proof. [1] https://fedoraproject.org/wiki/Changes/StrongCryptoSettings2 Signed-off-by: Daniel P. Berrangé Message-Id: <20200715154701.1041325-1-berrange@redhat.com> Reviewed-by: Kashyap Chamarthy Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- tests/crypto-tls-x509-helpers.c | 59 ++++++++++++++++++++++----------- tests/qemu-iotests/common.tls | 57 +++++++++++++++++++++---------- 2 files changed, 79 insertions(+), 37 deletions(-) diff --git a/tests/crypto-tls-x509-helpers.c b/tests/crypto-tls-x509-helpers.c index 9b669c2a4b..01b3daf358 100644 --- a/tests/crypto-tls-x509-helpers.c +++ b/tests/crypto-tls-x509-helpers.c @@ -37,25 +37,46 @@ ASN1_TYPE pkix_asn1; * here's one we prepared earlier :-) */ gnutls_x509_privkey_t privkey; -# define PRIVATE_KEY \ - "-----BEGIN PRIVATE KEY-----\n" \ - "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALVcr\n" \ - "BL40Tm6yq88FBhJNw1aaoCjmtg0l4dWQZ/e9Fimx4ARxFpT+ji4FE\n" \ - "Cgl9s/SGqC+1nvlkm9ViSo0j7MKDbnDB+VRHDvMAzQhA2X7e8M0n9\n" \ - "rPolUY2lIVC83q0BBaOBkCj2RSmT2xTEbbC2xLukSrg2WP/ihVOxc\n" \ - "kXRuyFtzAgMBAAECgYB7slBexDwXrtItAMIH6m/U+LUpNe0Xx48OL\n" \ - "IOn4a4whNgO/o84uIwygUK27ZGFZT0kAGAk8CdF9hA6ArcbQ62s1H\n" \ - "myxrUbF9/mrLsQw1NEqpuUk9Ay2Tx5U/wPx35S3W/X2AvR/ZpTnCn\n" \ - "2q/7ym9fyiSoj86drD7BTvmKXlOnOwQJBAPOFMp4mMa9NGpGuEssO\n" \ - "m3Uwbp6lhcP0cA9MK+iOmeANpoKWfBdk5O34VbmeXnGYWEkrnX+9J\n" \ - "bM4wVhnnBWtgBMCQQC+qAEmvwcfhauERKYznMVUVksyeuhxhCe7EK\n" \ - "mPh+U2+g0WwdKvGDgO0PPt1gq0ILEjspMDeMHVdTwkaVBo/uMhAkA\n" \ - "Z5SsZyCP2aTOPFDypXRdI4eqRcjaEPOUBq27r3uYb/jeboVb2weLa\n" \ - "L1MmVuHiIHoa5clswPdWVI2y0em2IGoDAkBPSp/v9VKJEZabk9Frd\n" \ - "a+7u4fanrM9QrEjY3KhduslSilXZZSxrWjjAJPyPiqFb3M8XXA26W\n" \ - "nz1KYGnqYKhLcBAkB7dt57n9xfrhDpuyVEv+Uv1D3VVAhZlsaZ5Pp\n" \ - "dcrhrkJn2sa/+O8OKvdrPSeeu/N5WwYhJf61+CPoenMp7IFci\n" \ - "-----END PRIVATE KEY-----\n" +# define PRIVATE_KEY \ + "-----BEGIN RSA PRIVATE KEY-----\n" \ + "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\n" \ + "-----END RSA PRIVATE KEY-----\n" /* * This loads the private key we defined earlier diff --git a/tests/qemu-iotests/common.tls b/tests/qemu-iotests/common.tls index 54c331d7a5..6ba28a78d3 100644 --- a/tests/qemu-iotests/common.tls +++ b/tests/qemu-iotests/common.tls @@ -50,24 +50,45 @@ tls_x509_init() # use a fixed key so we don't waste system entropy on # each test run cat > "${tls_dir}/key.pem" < Date: Thu, 16 Jul 2020 15:28:29 +0200 Subject: [PATCH 2387/2595] iotests/030: Reduce job speed to make race less likely It can happen that the throttling of the stream job doesn't make it slow enough that we can be sure that it still exists when it is referenced again. Just use a much smaller speed to make this very unlikely to happen again. Reported-by: Peter Maydell Signed-off-by: Kevin Wolf Message-Id: <20200716132829.20127-1-kwolf@redhat.com> Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- tests/qemu-iotests/030 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index 256b2bfbc6..31c028306b 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -243,7 +243,7 @@ class TestParallelOps(iotests.QMPTestCase): node_name = 'node%d' % i job_id = 'stream-%s' % node_name pending_jobs.append(job_id) - result = self.vm.qmp('block-stream', device=node_name, job_id=job_id, base=self.imgs[i-2], speed=512*1024) + result = self.vm.qmp('block-stream', device=node_name, job_id=job_id, base=self.imgs[i-2], speed=1024) self.assert_qmp(result, 'return', {}) for job in pending_jobs: From 453cc6be0a954ecdb4e0cdbf5b5b87f07b3e1075 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 14 Jul 2020 19:22:33 +0300 Subject: [PATCH 2388/2595] nbd: make nbd_export_close_all() synchronous Consider nbd_export_close_all(). The call-stack looks like this: nbd_export_close_all() -> nbd_export_close -> call client_close() for each client. client_close() doesn't guarantee that client is closed: nbd_trip() keeps reference to it. So, nbd_export_close_all() just reduce reference counter on export and removes it from the list, but doesn't guarantee that nbd_trip() finished neither export actually removed. Let's wait for all exports actually removed. Without this fix, the following crash is possible: - export bitmap through internal Qemu NBD server - connect a client - shutdown Qemu On shutdown nbd_export_close_all is called, but it actually don't wait for nbd_trip() to finish and to release its references. So, export is not release, and exported bitmap remains busy, and on try to remove the bitmap (which is part of bdrv_close()) the assertion fails: bdrv_release_dirty_bitmap_locked: Assertion `!bdrv_dirty_bitmap_busy(bitmap)' failed Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200714162234.13113-2-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- nbd/server.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nbd/server.c b/nbd/server.c index 5357f588f0..4752a6c8bc 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -102,6 +102,8 @@ struct NBDExport { }; static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); +static QTAILQ_HEAD(, NBDExport) closed_exports = + QTAILQ_HEAD_INITIALIZER(closed_exports); /* NBDExportMetaContexts represents a list of contexts to be exported, * as selected by NBD_OPT_SET_META_CONTEXT. Also used for @@ -1659,6 +1661,7 @@ void nbd_export_close(NBDExport *exp) g_free(exp->name); exp->name = NULL; QTAILQ_REMOVE(&exports, exp, next); + QTAILQ_INSERT_TAIL(&closed_exports, exp, next); } g_free(exp->description); exp->description = NULL; @@ -1722,7 +1725,9 @@ void nbd_export_put(NBDExport *exp) g_free(exp->export_bitmap_context); } + QTAILQ_REMOVE(&closed_exports, exp, next); g_free(exp); + aio_wait_kick(); } } @@ -1742,6 +1747,9 @@ void nbd_export_close_all(void) nbd_export_close(exp); aio_context_release(aio_context); } + + AIO_WAIT_WHILE(NULL, !(QTAILQ_EMPTY(&exports) && + QTAILQ_EMPTY(&closed_exports))); } static int coroutine_fn nbd_co_send_iov(NBDClient *client, struct iovec *iov, From d047cfa78dc76fb8c7768620106bf1acb7c79797 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 14 Jul 2020 19:22:34 +0300 Subject: [PATCH 2389/2595] iotests: test shutdown when bitmap is exported through NBD Test shutdown when bitmap is exported through NBD and active client exists. The previous patch fixes a crash, provoked by this scenario. Signed-off-by: Vladimir Sementsov-Ogievskiy Tested-by: Eric Blake Reviewed-by: Eric Blake Message-Id: <20200714162234.13113-3-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/299 | 65 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/299.out | 10 ++++++ tests/qemu-iotests/group | 1 + 3 files changed, 76 insertions(+) create mode 100644 tests/qemu-iotests/299 create mode 100644 tests/qemu-iotests/299.out diff --git a/tests/qemu-iotests/299 b/tests/qemu-iotests/299 new file mode 100644 index 0000000000..e129c7f7cb --- /dev/null +++ b/tests/qemu-iotests/299 @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# +# Test shutdown when bitmap is exported through NBD server +# +# Copyright (c) 2020 Virtuozzo International GmbH. +# +# 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 . +# + +import iotests + +# The test is unrelated to formats, restrict it to qcow2 to avoid extra runs +iotests.script_initialize( + supported_fmts=['qcow2'], +) + +nbd_sock = iotests.file_path('nbd.sock', base_dir=iotests.sock_dir) +nbd_uri = 'nbd+unix:///disk?socket=' + nbd_sock +size = 1024 * 1024 + +vm = iotests.VM() +vm.launch() + +vm.qmp_log('blockdev-add', **{ + 'node-name': 'disk', + 'driver': 'null-co', + 'size': 1024 * 1024, +}) + +vm.qmp_log('block-dirty-bitmap-add', **{ + 'node': 'disk', + 'name': 'bitmap0' +}) + +vm.qmp_log('nbd-server-start', **{ + 'addr': { + 'type': 'unix', + 'data': {'path': nbd_sock} + } +}, filters=[iotests.filter_qmp_testfiles]) + +vm.qmp_log('nbd-server-add', **{ + 'device': 'disk', + 'writable': True, + 'bitmap': 'bitmap0' +}) + +p = iotests.QemuIoInteractive('-f', 'raw', nbd_uri) +# wait for connection and check it: +iotests.log(p.cmd('read 0 512').rstrip(), filters=[iotests.filter_qemu_io]) + +vm.shutdown() + +p.close() diff --git a/tests/qemu-iotests/299.out b/tests/qemu-iotests/299.out new file mode 100644 index 0000000000..bba4252923 --- /dev/null +++ b/tests/qemu-iotests/299.out @@ -0,0 +1,10 @@ +{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "disk", "size": 1048576}} +{"return": {}} +{"execute": "block-dirty-bitmap-add", "arguments": {"name": "bitmap0", "node": "disk"}} +{"return": {}} +{"execute": "nbd-server-start", "arguments": {"addr": {"data": {"path": "SOCK_DIR/PID-nbd.sock"}, "type": "unix"}}} +{"return": {}} +{"execute": "nbd-server-add", "arguments": {"bitmap": "bitmap0", "device": "disk", "writable": true}} +{"return": {}} +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index a4f9e11e7a..1d0252e1f0 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -306,4 +306,5 @@ 295 rw 296 rw 297 meta +299 auto quick 301 backing quick From 9c60a5d1978e6dcf85c0e01b50e6f7f54ca09104 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 16 Jul 2020 16:26:00 +0200 Subject: [PATCH 2390/2595] block: Require aligned image size to avoid assertion failure Unaligned requests will automatically be aligned to bl.request_alignment and we can't extend write requests to access space beyond the end of the image without resizing the image, so if we have the WRITE permission, but not the RESIZE one, it's required that the image size is aligned. Failing to meet this requirement could cause assertion failures like this if RESIZE permissions weren't requested: qemu-img: block/io.c:1910: bdrv_co_write_req_prepare: Assertion `end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE' failed. This was e.g. triggered by qemu-img converting to a target image with 4k request alignment when the image was only aligned to 512 bytes, but not to 4k. Turn this into a graceful error in bdrv_check_perm() so that WRITE without RESIZE can only be taken if the image size is aligned. If a user holds both permissions and drops only RESIZE, the function will return an error, but bdrv_child_try_set_perm() will ignore the failure silently if permissions are only requested to be relaxed and just keep both permissions while returning success. Signed-off-by: Kevin Wolf Message-Id: <20200716142601.111237-2-kwolf@redhat.com> Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/block.c b/block.c index 35a372df57..d9ac0e07eb 100644 --- a/block.c +++ b/block.c @@ -2025,6 +2025,22 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, return -EPERM; } + /* + * Unaligned requests will automatically be aligned to bl.request_alignment + * and without RESIZE we can't extend requests to write to space beyond the + * end of the image, so it's required that the image size is aligned. + */ + if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) && + !(cumulative_perms & BLK_PERM_RESIZE)) + { + if ((bs->total_sectors * BDRV_SECTOR_SIZE) % bs->bl.request_alignment) { + error_setg(errp, "Cannot get 'write' permission without 'resize': " + "Image size is not a multiple of request " + "alignment"); + return -EPERM; + } + } + /* Check this node */ if (!drv) { return 0; From 5edc85571e7b7269dce408735eba7507f18ac666 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 16 Jul 2020 16:26:01 +0200 Subject: [PATCH 2391/2595] file-posix: Allow byte-aligned O_DIRECT with NFS Since commit a6b257a08e3 ('file-posix: Handle undetectable alignment'), we assume that if we open a file with O_DIRECT and alignment probing returns 1, we just couldn't find out the real alignment requirement because some filesystems make the requirement only for allocated blocks. In this case, a safe default of 4k is used. This is too strict for NFS, which does actually allow byte-aligned requests even with O_DIRECT. Because we can't distinguish both cases with generic code, let's just look at the file system magic and disable s->needs_alignment for NFS. This way, O_DIRECT can still be used on NFS for images that are not aligned to 4k. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Message-Id: <20200716142601.111237-3-kwolf@redhat.com> Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block/file-posix.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/block/file-posix.c b/block/file-posix.c index 8067e238cb..ae8190edab 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -62,10 +62,12 @@ #include #include #include +#include #include #include #include #include +#include #include #ifdef __s390__ #include @@ -300,6 +302,28 @@ static int probe_physical_blocksize(int fd, unsigned int *blk_size) #endif } +/* + * Returns true if no alignment restrictions are necessary even for files + * opened with O_DIRECT. + * + * raw_probe_alignment() probes the required alignment and assume that 1 means + * the probing failed, so it falls back to a safe default of 4k. This can be + * avoided if we know that byte alignment is okay for the file. + */ +static bool dio_byte_aligned(int fd) +{ +#ifdef __linux__ + struct statfs buf; + int ret; + + ret = fstatfs(fd, &buf); + if (ret == 0 && buf.f_type == NFS_SUPER_MAGIC) { + return true; + } +#endif + return false; +} + /* Check if read is allowed with given memory buffer and length. * * This function is used to check O_DIRECT memory buffer and request alignment. @@ -629,7 +653,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, s->has_discard = true; s->has_write_zeroes = true; - if ((bs->open_flags & BDRV_O_NOCACHE) != 0) { + if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) { s->needs_alignment = true; } From 20eaf1bf6ef1df916cb7ea2d06d1e868f238835f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 17 Jul 2020 12:54:24 +0200 Subject: [PATCH 2392/2595] file-posix: Move check_hdev_writable() up We'll need to call it in raw_open_common(), so move the function to avoid a forward declaration. Signed-off-by: Kevin Wolf Message-Id: <20200717105426.51134-2-kwolf@redhat.com> Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block/file-posix.c | 66 +++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index ae8190edab..dd7dab07d6 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -425,6 +425,39 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) } } +static int check_hdev_writable(BDRVRawState *s) +{ +#if defined(BLKROGET) + /* Linux block devices can be configured "read-only" using blockdev(8). + * This is independent of device node permissions and therefore open(2) + * with O_RDWR succeeds. Actual writes fail with EPERM. + * + * bdrv_open() is supposed to fail if the disk is read-only. Explicitly + * check for read-only block devices so that Linux block devices behave + * properly. + */ + struct stat st; + int readonly = 0; + + if (fstat(s->fd, &st)) { + return -errno; + } + + if (!S_ISBLK(st.st_mode)) { + return 0; + } + + if (ioctl(s->fd, BLKROGET, &readonly) < 0) { + return -errno; + } + + if (readonly) { + return -EACCES; + } +#endif /* defined(BLKROGET) */ + return 0; +} + static void raw_parse_flags(int bdrv_flags, int *open_flags, bool has_writers) { bool read_write = false; @@ -3323,39 +3356,6 @@ static int hdev_probe_device(const char *filename) return 0; } -static int check_hdev_writable(BDRVRawState *s) -{ -#if defined(BLKROGET) - /* Linux block devices can be configured "read-only" using blockdev(8). - * This is independent of device node permissions and therefore open(2) - * with O_RDWR succeeds. Actual writes fail with EPERM. - * - * bdrv_open() is supposed to fail if the disk is read-only. Explicitly - * check for read-only block devices so that Linux block devices behave - * properly. - */ - struct stat st; - int readonly = 0; - - if (fstat(s->fd, &st)) { - return -errno; - } - - if (!S_ISBLK(st.st_mode)) { - return 0; - } - - if (ioctl(s->fd, BLKROGET, &readonly) < 0) { - return -errno; - } - - if (readonly) { - return -EACCES; - } -#endif /* defined(BLKROGET) */ - return 0; -} - static void hdev_parse_filename(const char *filename, QDict *options, Error **errp) { From bca5283bd4a086bcbfaddc024491a400cc9b2fa9 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 17 Jul 2020 12:54:25 +0200 Subject: [PATCH 2393/2595] file-posix: Fix check_hdev_writable() with auto-read-only For Linux block devices, being able to open the device read-write doesn't necessarily mean that the device is actually writable (one example is a read-only LV, as you get with lvchange -pr ). We have check_hdev_writable() to check this condition and fail opening the image read-write if it's not actually writable. However, this check doesn't take auto-read-only into account, but results in a hard failure instead of downgrading to read-only where possible. Fix this and do the writable check not based on BDRV_O_RDWR, but only when this actually results in opening the file read-write. A second check is inserted in raw_reconfigure_getfd() to have the same check when dynamic auto-read-only upgrades an image file from read-only to read-write. Signed-off-by: Kevin Wolf Message-Id: <20200717105426.51134-3-kwolf@redhat.com> Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block/file-posix.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index dd7dab07d6..996e45ab95 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -425,7 +425,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) } } -static int check_hdev_writable(BDRVRawState *s) +static int check_hdev_writable(int fd) { #if defined(BLKROGET) /* Linux block devices can be configured "read-only" using blockdev(8). @@ -439,7 +439,7 @@ static int check_hdev_writable(BDRVRawState *s) struct stat st; int readonly = 0; - if (fstat(s->fd, &st)) { + if (fstat(fd, &st)) { return -errno; } @@ -447,7 +447,7 @@ static int check_hdev_writable(BDRVRawState *s) return 0; } - if (ioctl(s->fd, BLKROGET, &readonly) < 0) { + if (ioctl(fd, BLKROGET, &readonly) < 0) { return -errno; } @@ -642,6 +642,15 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, } s->fd = fd; + /* Check s->open_flags rather than bdrv_flags due to auto-read-only */ + if (s->open_flags & O_RDWR) { + ret = check_hdev_writable(s->fd); + if (ret < 0) { + error_setg_errno(errp, -ret, "The device is not writable"); + goto fail; + } + } + s->perm = 0; s->shared_perm = BLK_PERM_ALL; @@ -1034,6 +1043,15 @@ static int raw_reconfigure_getfd(BlockDriverState *bs, int flags, } } + if (fd != -1 && (*open_flags & O_RDWR)) { + ret = check_hdev_writable(fd); + if (ret < 0) { + qemu_close(fd); + error_setg_errno(errp, -ret, "The device is not writable"); + return -1; + } + } + return fd; } @@ -3478,15 +3496,6 @@ hdev_open_Mac_error: /* Since this does ioctl the device must be already opened */ bs->sg = hdev_is_sg(bs); - if (flags & BDRV_O_RDWR) { - ret = check_hdev_writable(s); - if (ret < 0) { - raw_close(bs); - error_setg_errno(errp, -ret, "The device is not writable"); - return ret; - } - } - return ret; } From a8c5cf27c945d392edd85b0b0c64cd5c52cae658 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 17 Jul 2020 12:54:26 +0200 Subject: [PATCH 2394/2595] file-posix: Fix leaked fd in raw_open_common() error path Signed-off-by: Kevin Wolf Message-Id: <20200717105426.51134-4-kwolf@redhat.com> Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block/file-posix.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block/file-posix.c b/block/file-posix.c index 996e45ab95..8cc39a1ef6 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -773,6 +773,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, } ret = 0; fail: + if (ret < 0 && s->fd != -1) { + qemu_close(s->fd); + } if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) { unlink(filename); } From 7cb015197b383a62f5729d2c92b1050db0185c1c Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 26 Jun 2020 16:06:58 +0300 Subject: [PATCH 2395/2595] migration/block-dirty-bitmap: fix add_bitmaps_to_list We shouldn't fail when finding an unnamed bitmap in a unnamed node or node with auto-generated node name, as bitmap migration ignores such bitmaps in the first place. Fixes: 82640edb88faa Fixes: 4ff5cc121b089 Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200626130658.76498-1-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake [eblake: commit message grammar tweaks] Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 47bc0f650c..b0dbf9eeed 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -274,7 +274,11 @@ static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name) DirtyBitmapMigBitmapState *dbms; Error *local_err = NULL; - bitmap = bdrv_dirty_bitmap_first(bs); + FOR_EACH_DIRTY_BITMAP(bs, bitmap) { + if (bdrv_dirty_bitmap_name(bitmap)) { + break; + } + } if (!bitmap) { return 0; } From 323679da77b2fd4dc9be3731ecac96613beea4f1 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 23 Sep 2019 13:50:33 -0500 Subject: [PATCH 2396/2595] ipmi: Add man page pieces for the IPMI PCI devices This was forgotten when the devices were added. Signed-off-by: Corey Minyard --- qemu-options.hx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/qemu-options.hx b/qemu-options.hx index 65147ad971..fb31fe3df6 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -876,6 +876,15 @@ SRST ``-device isa-ipmi-bt,bmc=id[,ioport=val][,irq=val]`` Like the KCS interface, but defines a BT interface. The default port is 0xe4 and the default interrupt is 5. + +``-device pci-ipmi-kcs,bmc=id`` + Add a KCS IPMI interafce on the PCI bus. + + ``bmc=id`` + The BMC to connect to, one of ipmi-bmc-sim or ipmi-bmc-extern above. + +``-device pci-ipmi-bt,bmc=id`` + Like the KCS interface, but defines a BT interface on the PCI bus. ERST DEF("name", HAS_ARG, QEMU_OPTION_name, From 789101b73d93ab11f37a44c24fff44336f041345 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 17 Jul 2020 11:37:02 -0500 Subject: [PATCH 2397/2595] ipmi: Fix a man page entry The line was too long, and some of the entries were wrong (fur instead of fru). Just use the prop=val thing tha other entries use. Signed-off-by: Corey Minyard --- qemu-options.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-options.hx b/qemu-options.hx index fb31fe3df6..708583b4ce 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -806,7 +806,7 @@ SRST Some drivers are: -``-device ipmi-bmc-sim,id=id[,slave_addr=val][,sdrfile=file][,furareasize=val][,furdatafile=file][,guid=uuid]`` +``-device ipmi-bmc-sim,id=id[,prop[=value][,...]]`` Add an IPMI BMC. This is a simulation of a hardware management interface processor that normally sits on a system. It provides a watchdog and the ability to reset and power control the system. You From e3f7320caa1cc08a9b752e555b79abd6218c7c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 18 Nov 2019 10:24:29 +0100 Subject: [PATCH 2398/2595] ipmi: add SET_SENSOR_READING command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SET_SENSOR_READING is a complex IPMI command (see IPMI spec 35.17) which enables the host software to set the reading value and the event status of sensors supporting it. Below is a proposal for all the operations (reading, assert, deassert, event data) with the following limitations : - No event are generated for threshold-based sensors. - The case in which the BMC needs to generate its own events is not supported. Signed-off-by: Cédric Le Goater Reviewed-by: Corey Minyard Message-Id: <20191118092429.16149-1-clg@kaod.org> [Moved the break statement for case SENSOR_GEN_EVENT_DATA above the closing brace to keep the indention consistent.] Signed-off-by: Corey Minyard --- hw/ipmi/ipmi_bmc_sim.c | 223 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 0b97e04774..f78e92d3d5 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -49,6 +49,7 @@ #define IPMI_CMD_GET_SENSOR_READING 0x2d #define IPMI_CMD_SET_SENSOR_TYPE 0x2e #define IPMI_CMD_GET_SENSOR_TYPE 0x2f +#define IPMI_CMD_SET_SENSOR_READING 0x30 /* #define IPMI_NETFN_APP 0x06 In ipmi.h */ @@ -1747,6 +1748,227 @@ static void get_sensor_type(IPMIBmcSim *ibs, rsp_buffer_push(rsp, sens->evt_reading_type_code); } +/* + * bytes parameter + * 1 sensor number + * 2 operation (see below for bits meaning) + * 3 sensor reading + * 4:5 assertion states (optional) + * 6:7 deassertion states (optional) + * 8:10 event data 1,2,3 (optional) + */ +static void set_sensor_reading(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + RspBuffer *rsp) +{ + IPMISensor *sens; + uint8_t evd1 = 0; + uint8_t evd2 = 0; + uint8_t evd3 = 0; + uint8_t new_reading = 0; + uint16_t new_assert_states = 0; + uint16_t new_deassert_states = 0; + bool change_reading = false; + bool change_assert = false; + bool change_deassert = false; + enum { + SENSOR_GEN_EVENT_NONE, + SENSOR_GEN_EVENT_DATA, + SENSOR_GEN_EVENT_BMC, + } do_gen_event = SENSOR_GEN_EVENT_NONE; + + if ((cmd[2] >= MAX_SENSORS) || + !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { + rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); + return; + } + + sens = ibs->sensors + cmd[2]; + + /* [1:0] Sensor Reading operation */ + switch ((cmd[3]) & 0x3) { + case 0: /* Do not change */ + break; + case 1: /* write given value to sensor reading byte */ + new_reading = cmd[4]; + if (sens->reading != new_reading) { + change_reading = true; + } + break; + case 2: + case 3: + rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); + return; + } + + /* [3:2] Deassertion bits operation */ + switch ((cmd[3] >> 2) & 0x3) { + case 0: /* Do not change */ + break; + case 1: /* write given value */ + if (cmd_len > 7) { + new_deassert_states = cmd[7]; + change_deassert = true; + } + if (cmd_len > 8) { + new_deassert_states |= (cmd[8] << 8); + } + break; + + case 2: /* mask on */ + if (cmd_len > 7) { + new_deassert_states = (sens->deassert_states | cmd[7]); + change_deassert = true; + } + if (cmd_len > 8) { + new_deassert_states |= (sens->deassert_states | (cmd[8] << 8)); + } + break; + + case 3: /* mask off */ + if (cmd_len > 7) { + new_deassert_states = (sens->deassert_states & cmd[7]); + change_deassert = true; + } + if (cmd_len > 8) { + new_deassert_states |= (sens->deassert_states & (cmd[8] << 8)); + } + break; + } + + if (change_deassert && (new_deassert_states == sens->deassert_states)) { + change_deassert = false; + } + + /* [5:4] Assertion bits operation */ + switch ((cmd[3] >> 4) & 0x3) { + case 0: /* Do not change */ + break; + case 1: /* write given value */ + if (cmd_len > 5) { + new_assert_states = cmd[5]; + change_assert = true; + } + if (cmd_len > 6) { + new_assert_states |= (cmd[6] << 8); + } + break; + + case 2: /* mask on */ + if (cmd_len > 5) { + new_assert_states = (sens->assert_states | cmd[5]); + change_assert = true; + } + if (cmd_len > 6) { + new_assert_states |= (sens->assert_states | (cmd[6] << 8)); + } + break; + + case 3: /* mask off */ + if (cmd_len > 5) { + new_assert_states = (sens->assert_states & cmd[5]); + change_assert = true; + } + if (cmd_len > 6) { + new_assert_states |= (sens->assert_states & (cmd[6] << 8)); + } + break; + } + + if (change_assert && (new_assert_states == sens->assert_states)) { + change_assert = false; + } + + if (cmd_len > 9) { + evd1 = cmd[9]; + } + if (cmd_len > 10) { + evd2 = cmd[10]; + } + if (cmd_len > 11) { + evd3 = cmd[11]; + } + + /* [7:6] Event Data Bytes operation */ + switch ((cmd[3] >> 6) & 0x3) { + case 0: /* + * Don’t use Event Data bytes from this command. BMC will + * generate it's own Event Data bytes based on its sensor + * implementation. + */ + evd1 = evd2 = evd3 = 0x0; + do_gen_event = SENSOR_GEN_EVENT_BMC; + break; + case 1: /* + * Write given values to event data bytes including bits + * [3:0] Event Data 1. + */ + do_gen_event = SENSOR_GEN_EVENT_DATA; + break; + case 2: /* + * Write given values to event data bytes excluding bits + * [3:0] Event Data 1. + */ + evd1 &= 0xf0; + do_gen_event = SENSOR_GEN_EVENT_DATA; + break; + case 3: + rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); + return; + } + + /* + * Event Data Bytes operation and parameter are inconsistent. The + * Specs are not clear on that topic but generating an error seems + * correct. + */ + if (do_gen_event == SENSOR_GEN_EVENT_DATA && cmd_len < 10) { + rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); + return; + } + + /* commit values */ + if (change_reading) { + sens->reading = new_reading; + } + + if (change_assert) { + sens->assert_states = new_assert_states; + } + + if (change_deassert) { + sens->deassert_states = new_deassert_states; + } + + /* TODO: handle threshold sensor */ + if (!IPMI_SENSOR_IS_DISCRETE(sens)) { + return; + } + + switch (do_gen_event) { + case SENSOR_GEN_EVENT_DATA: { + unsigned int bit = evd1 & 0xf; + uint16_t mask = (1 << bit); + + if (sens->assert_states & mask & sens->assert_enable) { + gen_event(ibs, cmd[2], 0, evd1, evd2, evd3); + } + + if (sens->deassert_states & mask & sens->deassert_enable) { + gen_event(ibs, cmd[2], 1, evd1, evd2, evd3); + } + break; + } + case SENSOR_GEN_EVENT_BMC: + /* + * TODO: generate event and event data bytes depending on the + * sensor + */ + break; + case SENSOR_GEN_EVENT_NONE: + break; + } +} static const IPMICmdHandler chassis_cmds[] = { [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities }, @@ -1768,6 +1990,7 @@ static const IPMICmdHandler sensor_event_cmds[] = { [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 }, [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 }, [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 }, + [IPMI_CMD_SET_SENSOR_READING] = { set_sensor_reading, 5 }, }; static const IPMINetfn sensor_event_netfn = { .cmd_nums = ARRAY_SIZE(sensor_event_cmds), From ba3c35d9c4026361fd380b269dc6def9510b7166 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Jul 2020 09:26:59 -0700 Subject: [PATCH 2399/2595] tcg/cpu-exec: precise single-stepping after an interrupt When single-stepping with a debugger attached to QEMU, and when an interrupt is raised, the debugger misses the first instruction after the interrupt. Tested-by: Luc Michel Reviewed-by: Luc Michel Buglink: https://bugs.launchpad.net/qemu/+bug/757702 Message-Id: <20200717163029.2737546-1-richard.henderson@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 6a3d3a3cfc..66d38f9d85 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -588,7 +588,13 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, else { if (cc->cpu_exec_interrupt(cpu, interrupt_request)) { replay_interrupt(); - cpu->exception_index = -1; + /* + * After processing the interrupt, ensure an EXCP_DEBUG is + * raised when single-stepping so that GDB doesn't miss the + * next instruction. + */ + cpu->exception_index = + (cpu->singlestep_enabled ? EXCP_DEBUG : -1); *last_tb = NULL; } /* The target hook may have updated the 'cpu->interrupt_request'; From 14de3d4ac58c0f63e9f5560c7e01e62e39467edd Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 7 Jul 2020 18:35:57 +0200 Subject: [PATCH 2400/2595] ppc/pnv: Make PSI device types not user creatable QEMU aborts with -device pnv-psi-POWER8: $ qemu-system-ppc64 -device pnv-psi-POWER8 qemu-system-ppc64: hw/intc/xics.c:605: ics_realize: Assertion `ics->xics' failed. Aborted (core dumped) The Processor Service Interface Controller is an internal device. It should only be instantiated by the chip, which takes care of configuring the link required by the ICS object in the case of POWER8. It doesn't make sense for a user to specify it on the command line. Note that the PSI model for POWER8 was added 3 yrs ago but the devices weren't available on the command line because of a bug that was fixed by recent commit 2f35254aa0 ("pnv/psi: Correct the pnv-psi* devices not to be sysbus devices"). Fixes: 54f59d786c ("ppc/pnv: Add cut down PSI bridge model and hookup external interrupt") Reported-by: Thomas Huth Signed-off-by: Greg Kurz Message-Id: <159413975752.169116.5808968580649255382.stgit@bahia.lan> Signed-off-by: David Gibson --- hw/ppc/pnv_psi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 5bdeec700e..6a479cac53 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -929,6 +929,7 @@ static void pnv_psi_class_init(ObjectClass *klass, void *data) dc->desc = "PowerNV PSI Controller"; device_class_set_props(dc, pnv_psi_properties); dc->reset = pnv_psi_reset; + dc->user_creatable = false; } static const TypeInfo pnv_psi_info = { From a4beb5f5d4672400a76cc0551c4f0878e42d921c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 9 Jul 2020 19:12:47 +0200 Subject: [PATCH 2401/2595] spapr_pci: Robustify support of PCI bridges Some recent error handling cleanups unveiled issues with our support of PCI bridges: 1) QEMU aborts when using non-standard PCI bridge types, unveiled by commit 7ef1553dac "spapr_pci: Drop some dead error handling" $ qemu-system-ppc64 -M pseries -device pcie-pci-bridge Unexpected error in object_property_find() at qom/object.c:1240: qemu-system-ppc64: -device pcie-pci-bridge: Property '.chassis_nr' not found Aborted (core dumped) This happens because we assume all PCI bridge types to have a "chassis_nr" property. This property only exists with the standard PCI bridge type "pci-bridge" actually. We could possibly revert 7ef1553dac but it seems much simpler to check the presence of "chassis_nr" earlier. 2) QEMU abort if same "chassis_nr" value is used several times, unveiled by commit d2623129a7de "qom: Drop parameter @errp of object_property_add() & friends" $ qemu-system-ppc64 -M pseries -device pci-bridge,chassis_nr=1 \ -device pci-bridge,chassis_nr=1 Unexpected error in object_property_try_add() at qom/object.c:1167: qemu-system-ppc64: -device pci-bridge,chassis_nr=1: attempt to add duplicate property '40000100' to object (type 'container') Aborted (core dumped) This happens because we assume that "chassis_nr" values are unique, but nobody enforces that and we end up generating duplicate DRC ids. The PCI code doesn't really care for duplicate "chassis_nr" properties since it is only used to initialize the "Chassis Number Register" of the bridge, with no functional impact on QEMU. So, even if passing the same value several times might look weird, it never broke anything before, so I guess we don't necessarily want to enforce strict checking in the PCI code now. Workaround both issues in the PAPR code: check that the bridge has a unique and non null "chassis_nr" when plugging it into its parent bus. Fixes: 05929a6c5dfe ("spapr: Don't use bus number for building DRC ids") Fixes: 7ef1553dac ("spapr_pci: Drop some dead error handling") Fixes: d2623129a7de ("qom: Drop parameter @errp of object_property_add() & friends") Reported-by: Thomas Huth Signed-off-by: Greg Kurz Message-Id: <159431476748.407044.16711294833569014964.stgit@bahia.lan> [dwg: Move check slightly to a better place] Signed-off-by: David Gibson --- hw/ppc/spapr_pci.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 2a6a48744a..21681215d4 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1480,6 +1480,57 @@ static void spapr_pci_bridge_plug(SpaprPhbState *phb, add_drcs(phb, bus); } +/* Returns non-zero if the value of "chassis_nr" is already in use */ +static int check_chassis_nr(Object *obj, void *opaque) +{ + int new_chassis_nr = + object_property_get_uint(opaque, "chassis_nr", &error_abort); + int chassis_nr = + object_property_get_uint(obj, "chassis_nr", NULL); + + if (!object_dynamic_cast(obj, TYPE_PCI_BRIDGE)) { + return 0; + } + + /* Skip unsupported bridge types */ + if (!chassis_nr) { + return 0; + } + + /* Skip self */ + if (obj == opaque) { + return 0; + } + + return chassis_nr == new_chassis_nr; +} + +static bool bridge_has_valid_chassis_nr(Object *bridge, Error **errp) +{ + int chassis_nr = + object_property_get_uint(bridge, "chassis_nr", NULL); + + /* + * slotid_cap_init() already ensures that "chassis_nr" isn't null for + * standard PCI bridges, so this really tells if "chassis_nr" is present + * or not. + */ + if (!chassis_nr) { + error_setg(errp, "PCI Bridge lacks a \"chassis_nr\" property"); + error_append_hint(errp, "Try -device pci-bridge instead.\n"); + return false; + } + + /* We want unique values for "chassis_nr" */ + if (object_child_foreach_recursive(object_get_root(), check_chassis_nr, + bridge)) { + error_setg(errp, "Bridge chassis %d already in use", chassis_nr); + return false; + } + + return true; +} + static void spapr_pci_plug(HotplugHandler *plug_handler, DeviceState *plugged_dev, Error **errp) { @@ -1508,6 +1559,9 @@ static void spapr_pci_plug(HotplugHandler *plug_handler, g_assert(drc); if (pc->is_bridge) { + if (!bridge_has_valid_chassis_nr(OBJECT(plugged_dev), errp)) { + return; + } spapr_pci_bridge_plug(phb, PCI_BRIDGE(plugged_dev)); } From a6030d7e0b35a23c82e4a765b53dc3847bcdb4d1 Mon Sep 17 00:00:00 2001 From: Reza Arbab Date: Thu, 16 Jul 2020 17:56:55 -0500 Subject: [PATCH 2402/2595] spapr: Add a new level of NUMA for GPUs NUMA nodes corresponding to GPU memory currently have the same affinity/distance as normal memory nodes. Add a third NUMA associativity reference point enabling us to give GPU nodes more distance. This is guest visible information, which shouldn't change under a running guest across migration between different qemu versions, so make the change effective only in new (pseries > 5.0) machine types. Before, `numactl -H` output in a guest with 4 GPUs (nodes 2-5): node distances: node 0 1 2 3 4 5 0: 10 40 40 40 40 40 1: 40 10 40 40 40 40 2: 40 40 10 40 40 40 3: 40 40 40 10 40 40 4: 40 40 40 40 10 40 5: 40 40 40 40 40 10 After: node distances: node 0 1 2 3 4 5 0: 10 40 80 80 80 80 1: 40 10 80 80 80 80 2: 80 80 10 80 80 80 3: 80 80 80 10 80 80 4: 80 80 80 80 10 80 5: 80 80 80 80 80 10 These are the same distances as on the host, mirroring the change made to host firmware in skiboot commit f845a648b8cb ("numa/associativity: Add a new level of NUMA for GPU's"). Signed-off-by: Reza Arbab Message-Id: <20200716225655.24289-1-arbab@linux.ibm.com> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 21 +++++++++++++++++++-- hw/ppc/spapr_pci.c | 2 ++ hw/ppc/spapr_pci_nvlink2.c | 13 ++++++++++--- include/hw/pci-host/spapr.h | 1 + include/hw/ppc/spapr.h | 1 + 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 299908cc73..0ae293ec94 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -890,10 +890,16 @@ static int spapr_dt_rng(void *fdt) static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt) { MachineState *ms = MACHINE(spapr); + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms); int rtas; GString *hypertas = g_string_sized_new(256); GString *qemu_hypertas = g_string_sized_new(256); - uint32_t refpoints[] = { cpu_to_be32(0x4), cpu_to_be32(0x4) }; + uint32_t refpoints[] = { + cpu_to_be32(0x4), + cpu_to_be32(0x4), + cpu_to_be32(0x2), + }; + uint32_t nr_refpoints = ARRAY_SIZE(refpoints); uint64_t max_device_addr = MACHINE(spapr)->device_memory->base + memory_region_size(&MACHINE(spapr)->device_memory->mr); uint32_t lrdr_capacity[] = { @@ -945,8 +951,12 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt) qemu_hypertas->str, qemu_hypertas->len)); g_string_free(qemu_hypertas, TRUE); + if (smc->pre_5_1_assoc_refpoints) { + nr_refpoints = 2; + } + _FDT(fdt_setprop(fdt, rtas, "ibm,associativity-reference-points", - refpoints, sizeof(refpoints))); + refpoints, nr_refpoints * sizeof(refpoints[0]))); _FDT(fdt_setprop(fdt, rtas, "ibm,max-associativity-domains", maxdomains, sizeof(maxdomains))); @@ -4584,9 +4594,16 @@ DEFINE_SPAPR_MACHINE(5_1, "5.1", true); */ static void spapr_machine_5_0_class_options(MachineClass *mc) { + SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + static GlobalProperty compat[] = { + { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-5.1-associativity", "on" }, + }; + spapr_machine_5_1_class_options(mc); compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); mc->numa_mem_supported = true; + smc->pre_5_1_assoc_refpoints = true; } DEFINE_SPAPR_MACHINE(5_0, "5.0", false); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 21681215d4..363cdb3f7b 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -2089,6 +2089,8 @@ static Property spapr_phb_properties[] = { pcie_ecs, true), DEFINE_PROP_UINT64("gpa", SpaprPhbState, nv2_gpa_win_addr, 0), DEFINE_PROP_UINT64("atsd", SpaprPhbState, nv2_atsd_win_addr, 0), + DEFINE_PROP_BOOL("pre-5.1-associativity", SpaprPhbState, + pre_5_1_assoc, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/ppc/spapr_pci_nvlink2.c b/hw/ppc/spapr_pci_nvlink2.c index dd8cd6db96..76ae77ebc8 100644 --- a/hw/ppc/spapr_pci_nvlink2.c +++ b/hw/ppc/spapr_pci_nvlink2.c @@ -362,9 +362,9 @@ void spapr_phb_nvgpu_ram_populate_dt(SpaprPhbState *sphb, void *fdt) &error_abort); uint32_t associativity[] = { cpu_to_be32(0x4), - SPAPR_GPU_NUMA_ID, - SPAPR_GPU_NUMA_ID, - SPAPR_GPU_NUMA_ID, + cpu_to_be32(nvslot->numa_id), + cpu_to_be32(nvslot->numa_id), + cpu_to_be32(nvslot->numa_id), cpu_to_be32(nvslot->numa_id) }; uint64_t size = object_property_get_uint(nv_mrobj, "size", NULL); @@ -375,6 +375,13 @@ void spapr_phb_nvgpu_ram_populate_dt(SpaprPhbState *sphb, void *fdt) _FDT(off); _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); _FDT((fdt_setprop(fdt, off, "reg", mem_reg, sizeof(mem_reg)))); + + if (sphb->pre_5_1_assoc) { + associativity[1] = SPAPR_GPU_NUMA_ID; + associativity[2] = SPAPR_GPU_NUMA_ID; + associativity[3] = SPAPR_GPU_NUMA_ID; + } + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, sizeof(associativity)))); diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 8877ff51fb..600eb55c34 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -94,6 +94,7 @@ struct SpaprPhbState { hwaddr nv2_gpa_win_addr; hwaddr nv2_atsd_win_addr; SpaprPhbPciNvGpuConfig *nvgpus; + bool pre_5_1_assoc; }; #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index c421410e3f..3134d339e8 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -129,6 +129,7 @@ struct SpaprMachineClass { bool linux_pci_probe; bool smp_threads_vsmt; /* set VSMT to smp_threads by default */ hwaddr rma_limit; /* clamp the RMA to this size */ + bool pre_5_1_assoc_refpoints; void (*phb_placement)(SpaprMachineState *spapr, uint32_t index, uint64_t *buid, hwaddr *pio, From b25fbd6a1302c0eac5b326be3e1f828e905c0c9a Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 17 Jul 2020 11:15:31 +1000 Subject: [PATCH 2403/2595] pseries: Update SLOF firmware image This adds tcgbios (this was posted earlier [1] but got lost) and fixes FDT update at ibm,client-architecture-support for huge guests. The full list of changes: Alexey Kardashevskiy (4): make: Define default rule for .c when V=1 or V=2 version: update to 20200513 fdt: Avoid recursion when traversing tree version: update to 20200717 Gustavo Romero (1): board-qemu: Fix comment about SLOF start address Stefan Berger (6): tcgbios: Only write logs for PCRs that are allocated tcgbios: Fix the vendorInfoSize to be of type uint8_t tcgbios: Add support for SHA3 type of algorithms elf: Implement elf_get_file_size to determine size of an ELF image tcgbios: Implement tpm_hash_log_extend_event_buffer tcgbios: Measure the bootloader file read from disk [1] https://patchwork.ozlabs.org/project/qemu-devel/patch/20200513024355.121476-1-aik@ozlabs.ru/ Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson --- pc-bios/README | 2 +- pc-bios/slof.bin | Bin 965112 -> 968368 bytes roms/SLOF | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index a5a770f066..fa8b58b797 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,7 +14,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-20200327. + built from git tag qemu-slof-20200717. - 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 index 80bbf91a186c7eec76af3ae6af50c2c841a77579..448dcada367f32130ff6ccc6dcb482dcc3fa853e 100644 GIT binary patch delta 244496 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 W*YmKln=E0{eWkZ&+SfsM(D@ z;;ke$i;L}!*`+M+7x`8@hJ1X|J0jm{j9kCAytt}jd9nWO?Lcr+hoJXry7LD)C+!gQ zK|!xhlNT=DQ>f_<`I*6q=<(b@aqsTWKqc-o{xx4AM8;iH?+O?C9X@TH`u%Nfwjo{C_@FyaV;~$n60eX9% z-No|4|9AN9KGJ`oXrDVuj8XV;_u`s5R9|iX1Htja|97DJyP<#lVy^!VRDU<@9Zy-f z?+#R-@>2&y9@VG(xHm-})u;S4(Oxb1p;bn2<@A=YJwW+O6C#iA9ql3h`63^)ODI28 z<`Z^wk8fh#lxqb&X^gn#_FbErinngtyyr#&aRq`?3Rr5jbQ^hhY;WFH%$OLF(@O=t z->@(n*gJ3cT@WC_ONHTk;ix^nsd-adIOEJfR|M!Eyukw;5+;%7ryzCqCO1`*4LdHyc^5IE(h^^1JT;TFnviY$VU@-sza z-G!e5XZaFA#{k9hgCgH)Cn!IIvIvH|P&~`Gi9CvD`E@+M55=>*D1Kkb;k_9CB7%z2 zDcdEoD4eoV7G>{6S%o778D$e$szT9}?GRLyOj*$j_M_mvaN}}L-48F{iLB^?`{Cp} zF|>^lF}^=x6x#c81BGLVonL|A1q1X~z}nwow~}zX$YO4}6D0|cA3%JQt_un|`9RpX z$o|u30~cA8M|_PrDhO2|d;^5JlCVz@T8zBi%}w)4ikr6GvWF4zPas(Ek)U_jEq9@O zQPTsMfhc>epke~L3*&3S1fGu<8ewQF#)761a|i~Jmff`W*mnE2TXq+3-gCnZ+tf0N zO0h(>;&@iLs(N_|pP+#Y*WvYchDS&}@r&k&w=sOK;ExAGKVb}391q?>(cB1SArN|q zrB*z}@cFWUkZ9+4FUKRqM*OlOcvcvCE|>iI?=ZTR@N+yuS@7q7lTthloe1Nnme=XP6eBbLTtv@I#mS_hauXYeb z(<;p-!mBST03fu&ZW4`(iAm21HTY>Gsn4$fX@;*KJ83; zc;f@#%0Jy|9ZYhZaaW6 zVdUE)Uubt8Kwm5n*;2cQvO7e!!5%<1{-nsZ;1^0NDzmORc-ne!y8#gy;DL z-iZ$_)mGH=E)fWh6t%y*8?XD+R;aicF(CNy;g{-)@@mSFo)NsmhA#e~#Tc=2eQmV3 zqNZBEYzu~F#%SFWv^(OyiJ`P(`p^d*c5mD_$%-(x(4%66xhG~6*l)#sA2OF?ujh#LhiEb}Ru`1%-IOouKSuo;~EZlL_2Y+9$F_hQGYF zm|mP`Y6xW>EM=*6D2mg_+Ts=Ul|%Qz{&xhu8K2g}mq@E9OP<*(@HYC*82#qO8a5Ug z%%9-1u0GU(Uw2nuuF$nT)WsC2+RA%LCtC=|<)ME9mf(|*(5ij#p>DhVAfC=x)B3rt zgT9x$4(5#BIqH_3TepRai^J3Nw(e=RJ=1e8oUm)#mOZ;}+m_e7ZQHIq{&ZU2)?GWB z8Aos+r_g@uPdPz*`3E^`?A?FPnQR~ZAjfa_{xh)Oe30{h?Bjn1%fEe?6SCv4jLLoa zw;$&GZr;?UZJTb}vuj&1t@3D*zin5zD72t#h7F#*0Y>%8SBSv2GzZ!iR8^ee1iv3toQn(%b`H-_F~&?Xu^-n>*P~w&e~Rv1#kp zUE$3;c5b=(Hak+3JKauA%gvd1+x9z2b{-laoarWe?!?>+h6x^f@|j_UcBCq2l$|_~ zn`;lu%DwV)FBav#{9@6tUw(kovmV~NLOm=dkWa9f2=%myRCLdtPLb~xX|G88MLNjS z|L~`!g(6=h(o#oCM;kpc4tzrt@D0K6?0~>Uf!}Bs`LIY6A{7OGBT9L3vB0Lk1EK%y z;ORFbB5mO5HwF!3DlvSsOAuN`S|rk>NP`cou`c4LZ$JW}U-ogrw}qx}^*ykr0AIrU zR+!`85;ggDP~?S$-x{q@RP4G|j{>reU7x@bwi1~ei5HhU*bALt59(&dV z|9J1O!gesX98HCT||Nry9jCSuc*o%e16$qV8<@<=X!sILusyY0yHM@)xmLO zg1Ewz2137Sw38S4$Bh3?0(52~;kbmkziG337`+qFUQQZ9?>Rh?#0NmWE0g?I&@LhR zTP2|9JLtj-Z$<1FqenrX=0cCzZH(S*82Q5-bUxpN-b&ahMsI_><)E_`3WVND+5?Q< z3Ht3WbUb=CiR|kEy~TyzXGa-*0Q3tSbUs*y-WtTmydnQK>JuEBNq-xYE$H62iyl~0 zX!lL>&yD*$Z0052K`6BFB<}=9R108|Uu&DE68Edi`6! z{%l|M8{;-#y8QTmp1QK4Vqv&w{pLNl?A{ap%Npjry1^is5@gHkSm%Np+-5IFcfPip*SQGjPYa2mLU`|XI}N8))&^FP@p@L9mS9YK(k zHAsT+Yc24-J|WNw{C_n5eelucLHm0CsPWgB2SIoQ_*sp=9wTmGRfaM0O9H2P^ob}Z z(7)b*7I+4gVOJmUi5mY-gu^tfd1q++sf5503f^TJf2@?_#tz`Cpj3JY6@vfy<=vtM zo^BRk4Fqo2_~UH?ZvcK!M{-QS38dcpHUD!hf%Kk%zG zesqAtMl*0nlRaA^aEw&uUd{iy@Tdo#GQXnnjzP{JH~K($!a;~~f~N=g^BR96#&Kf` z@K-ecl5{l+GXGWMoo#|29?JbN2qNVJ!99p6d6{p8;D0gXzcIjJ^9Asp(29}~!JYvA ziN=q}nxP=yaE<=}d~^-Nc;K@%{&W||J?+3RmN?eYFD5yGThS{P&8Sfe2IeN_v*(Z&g^ z244qNxKu50iT_)g{|VHTE)RNv@2JLKqk?gHA42&)M>p$g76cOL(E`sma@|^y{TmJoH8fCwN`}p~@l9Ed-_jUk6-7`|bvTBgu6vOkRx$ z9G=MCp*?Xs0avmMh7EHp4WA$6 zF!h>Yj&;M47LI!l0T+`K>K_O_ALaxDv(_-j!r^gP&aN=Q;9-Qd7|8qe2l z9D1Tu<0H4~3P0My$3MgK4iw#~3D3%!p(d7NF8D#GP=x3mc0UTHB@iYRmI%_Y!`h(R ziv);d*yCFNtNj9RK>dfMG$GX|3BZ4>@mG2U4uwI-T=4xaftP^)SDL?5@;?c@U*lho zaDIxdVdsFy#q9T;2B8SX`}5e)2mm8vo520RM{7mjtrCh5ME(hmsBRVf2x`A$ZTMYb zkdO3SruD?1jR^q^82*SRJQERk2k=^rKQ8zwxct{^{ONwq@BIk)EgC;6J<$mKvkn{{ z!xc9?i$QPYWYxE46pDk!MINXO*yMoQrGA#h6bKh`ergkcPKEI?lE;<$Gmx~pR~{OEw-{|Wdn z5C&oWUwEs)gGh&8stb4?7P1S9hF_uaV+{gFa1CFo@uzzP4*GD%TJmYZ?@0iUY5wQh z`1ofSyFqZY*|BD!=po>a_5V|i95<=p&uc|*2zFXa4nM5%&O$-BANUcCe_wj~5w!pC zmvq}46#QYN!yVnPBf$w?cx3p0Xhly&InE0HoyI#$1deq0U$y?n1x#(9=OKPJ{|7>y zk^q6c{Gb|o?Q10gOLoTq^2z|m%>?+Jv!zso8s|;Z27Om}f|gu)js?pL@jg+&RuC$* z!1ux&H&ehjIB-}_ml*|qqsBYBIc^LBcPu`?)5CG5O`g8n@+*+LptI=HJ;*l zf|3z$EBuXzS~!8a*@$Nybm&Js^(8Mk{)V*xM?pPAN0z=rf4uq$)z_VavS3CY~*Z2>@95&$UQMB6-F?84`a3rG~ zE2S4m9#=sGINF}JeyD#S^qqc&<5(4h|I`I^lyaPQJfn_l{FxqsldJ!%@u#7fT^-Qs z)A);!r_1aFJ~pTf&AFfXpA!SqRj|B5vmU!V5O5sHJPXC_LX86vDDqP-Fm}?rmP#R;Am2;ExXsI)W*{FfSkv7hrB^MN1NhVFe+;7B~*RGw&0 zfrVXu@PDB7#GeWa!Z$I1cs1cU0ec`gdXl36)JR^Vr)&NfMFE~!;Ge7Umj?wm>2d5Y z9v@&h*8lip^lB~e?IJEfXEmc8L+|(6g(5V?=qAnoy7bW7z#Yr^R5#~m`ai2Y@ro&M zik;C9I0QNxg}_4~IQI9?igIapJo;Nu1VK1)?9`|rgn>JT*r!`LZuS9pY)Dd~0<`@e z{kEt8o&Ud4;!vb_DsOzNTj1ygqyMC9e1yBspd;F#qno|dEBN7|;02ohJIxM!N>Fvb zy-)J-k5Pk;ZkFs90-aE_Oe=b|f#aSM;HxyADi!?b1wqFM_+0^;2-2XV$)4#FghS~6 z!8=vkv>y{VY&3#*YfJC+2?F5{>Vl6}37l&DgvMWofpmEYe^ukD1cMFgu0ghspz$9~ zaHNeBXwMdOjC4nOIqvxgxMN{*G{tcPX}+lp4SmhgJMu%iV*er7DR%NN(gr;d?-P`V zKya*BI%Uo72Tt8at`FXnnt-pWJG3)XpWpyX3mtHk~8OwDVdp>DKj(XoG>%ToKxnE z$IKMT8JP*1|7NC0W<(}L=A1Jnb7rn3KUe0=^!I(vITv0I=f0oMea}75dHz4odG5LQ zz4yMza_8d@I@oM1Q_wxYf3=y>{tF784R~cU{I9DO93J%tE$7Q2Pkhn=KNqzAKcL_t zDH!;=nb84QBt9oXLIOeAzI(cYLxF&|8Gm?DJRD8fNz&{+RoM@Y<;Aq-C*oE23L@cw`Y9kh0P6dZ~LtOkCtryCSOKIV5|RI}i9Bh^!~fbK;UOom&QEHFzwJ@*9>7m%g7*uocLs7Xa97hn zVB2a%5C?dA5IlYNh+&?op`9O{Ic+i?beKHt@tKcK=9}jFrR{$0C!P)#-^w?cZx5f0 z+ruZz+ruY|+ruZz+rxM7xX<%Y`_>Ew^xy3rCMdeD>529FblT2Sgg*syeN z{s7(%J%)!hLy_3NP%ozUy@2WXut&gke0~arE1`}b4_H1A=mg1t@d`yJ=&9g3{y@Md z8Sn=yxQ?IMj6W2+>I2J0W0x7}1Y=D(_o zle_RE0=?9j;O_Ocy-s!YxUZ;PIyHO{-i4l<=vkSc1f2h2OH;U_@%q{`Ylf$4@ZRWS zDdpg|L&9;4+A}@F6@C+Z0AQFV4nFqq0Y1ABa4LStMVHPNVjl zU0kx&#U(W^_(xsvFGB@WK3oxS%tBqiYZwS}&s`1Z!%mN-;0nJ9o=hdb^mNTXs!#y=2`1F5Mr z29nGI0u#*w0y37ZDrvwaWP#?8HTfTY!egOMY_yyR95*Y}*$It?-#Ord-)fd+aeVN= z>u47OM^jzEIx~J`7&V;7K{V3wphg$z%n~gWk;5qKS4`)4Qm1p76p^c`@t5IU`uQR^ zD}{7ICx>)_=P31IoJ@4_P{niz?t)w}r9v0S5RJY|1~t}ULEFVe;Vv!;cPW6s_hQ3j zYyRLlY!^p&adC8)6QF(~gg(v+_vQP#Tz1j^iaAVCSowwi2plvmqK2CJL}9sWI!;AR z1$+#Rqi}yeU(`Yu;zcgRTd3$OxIU`Nh3>Em-8m}B;uUAq4Kra^%S_l6m!d*PwYIuz zt69O3@%p;DOp30!;uP|eNCP9hZR9Oj)YVBkEg8FRcTud4692&#b>%BIIjtE-d(DPBSmgdnVRPrCBc{EbiG(DpCn-z%hfES-6XbQx*Bv_0~ zg2m*5|GW^Kx9N7vjUs=S{IMNEwg;ZYYtydfr)3GH@fLK~Wy=7!yavhEG< z@`%qK>_X`HLi4$u3BSQ&ePLjaR&X7E0cAal7}=X$f5E>A39mvaiR$=G0U z^T+Fp#l<;15kL=q=<%n;_BJaKi>YApQfxLgT*j1%UE)Hw)P-&zj#5!?j}hi+d|#!Li0 z9$qk2mUypOYJ3V+)N!qhcS?rluJ}wBLL93?F10p0evyj;PDX0eAie}V22$kPo zOUU9~LKc6Dd>X$gn?!sB#Z-(A%=3AFvo?FlM}i^ zt0}RDqmZ!Gg>buz2FIWQKliI!auxWaTf-B%xO`xMX8^y8;SiTN-mFmKM6*JPb1C;E z7m~!4E`-G{gm}#L8N@QN#)ZzA5Sr_{hXEhj>mKNCoB4E)H_PwNJT8RLzmDMwbaxl4 zySrH3eJ+SG!&)h^+(ik;Il3{`z&9mS_p>gH&YP`C!i(J4n@KK-nB(BJVaAdAF6V;<<9$VY7E{ zbLN7UCbu;fKLu&Y1I%Q}1I2|KW ze=}5>+Z~P5fY9{u`feX=R_OK#c)=VzaQiH?A-B(Qp<6`_cd`d=-{nHM*M;ya7ktM9 zT7*)P&G;!j8O|Qi2`0G^!0o10M@j)TyvxhslyxqIr7nc^F8IgI_;;jG;yZBl9WEid z!zDy_U<&r<MSHe0)Abw#uYQS5D_uP&y6|y4u0^6} z0eC!RIH>nr>B6YkMWKC^$|vMKFS^hG-CZG6SH($t7X+Cq_d>Hmy%)JK+6W$e zd!o+A#Us6gJ#q`^LmTaSI$yLP{U{NNa_?9!f9qpQrCjV zCk6$!yYO*Br5n-!{QC_hG1Vyonn(ItW`+93QORLXRA%1+W(E4XRJOic)eM!bZvo{_ z=GoKNiKVW{au-F`fgzO8XGz~u1=l>#cQfF;$k+LAWw_yZ-uJkRg(qDU!i$-4{+^!} zFw><)nd#ETL4jOsTCS$eaN#q{g-;RS6Ad9wgGWr2FwH5+ny1oEQQhxQdebhu&|NVr z&~F&!{swgYCYtH`O>&`IMZV4*P_p|WL?%W1Aw;GXRKFv|^H|J~(h=D#q2e`y#fJ%(<%2H zD$NfTxzITQ)aiI_{nOTlq_+d?9&B1dr*}|rjZeA^3=Xe4fn$hH07HxdFwq2D$43N> z_?UUk_*^%|$LmYyrRF(otZ~x^@HJ)+rLR+PUGP3}wIV;=C6&`%Qu!XoaLpn2xJ2-t zQnOz7Y!YyIR#WVr3m9kv%QOS;amm4ZTyk)rOUevvkutoN6d$kehXJ#uKa5gvP0>L~ zX8b|PX8a#*h9Ld^M7{^&M_bi^CSb5-7BCn|Y&u8`<{Z-nfdAmZF8q;W`9^{{E(G&k z6k6z_&`}rs`X>A)|3jkJH^jx_AubjV8EY0WWPFnV@O3`m@5DaMfeHB-Sn5LHXxc=; zgup*;#?R=DVM7Qqn4aNUh%@phnJvhe;v!(Vi-46b0;*i_4@-D{D~+7#q*?r9Cp4M` zKTa|W_;IpXp&yTJVXzZ_ukXh$F&pX#))X4*k`qI@ZWux^)N4`*_w?WEFwz9v3r41C zcCSmw?w#U-@8p)wAE6A*kB3&8OYf~|;UXaL2Z|mw3mE3&p<#|;8vkLa6V5@{@xKr- zY_N-fIn4w@7xCrw4V&kJzX=G25DeR_;LQrLd@ypRljfpfC(QzWl4(}xC!<~P+12c6 zjsH(pLcS@+KdE;ia1?E}Ko~GQ%8WnUHuE1oQNi;yjfOkPr3+Z+BB0boz*!gk^DXgJ z{Jp;WlFbD7^=wH1bA`qCvEqgp-#0+PH3ROOW8|OjyKkP0fcaqbCN|AO_bpU#UBDtG zSjS(Y;5z+-ikj^SW9;;iDM zi6=MlN*0-|K?E z-+<3c#gSKB2(B3jfS>8iUd=<9@PsL)GLZr%12Shgx65iF$Xw$>;N*&qk4a$^aMG;M z{q36YoBWSpd42bHa3RQSA^@KA0sd$g{FN^F#X7!_4@O5_2l3Agj zPHDm4i9h}&qtr#fCKmxta%nF8>FE{%K+GTTKZ|BFwiftPF>qcDXcmmN%@&M~Hwze@ z1U?6J0bbweWb&=Y<&M!4UHCbk(&e+K__n&N4 z;X1yH$49$(d^CHUPx^%ckl(8S9fV>udz=R{u;Jst$3&Se7~@1jQ)mn#(JTOb@|c^~ zHzrBJGq|tdTxrLQbrFChHdW3s2wBKquxTL}gOCZhuF!H9{wrN7?U-UPsxSyZECpN_ zP~#%Nsb4yNJ@{k@{&J=jU|+cCIGPM>il6|y49{w37LesqnX|mW=VyC05AkF70^X#M zkPiVvT?7nQ@FoJK5K4atKU=H|7_Hzs{z4c2eHXb1SOP})-MW>4rPS~(|FV;{*M;ML z7lu`U4>T}5tl+xFmx0?fO+rHMYCxYuafRXRHbvkJJmADabIAi73!W01fCpS${(y_i zA3*Xo9nNLifGIS3V4aJA`XB;E6(8Uu$xI53bunP9!2rnj`o`kQZ|Hb%1!40C@atyy zxJ+RE37h7jahx;^*E}?ic^@?3PYl6ditvC&@Zc=U!Q;=?gLA0yU2f-55&HIn^MT8; z)bSTk?nK5zQe|_yTs%H)|9mWP!>}nunUoFw`FP4$kEg6l#FO!Dd_S*rc8;i>2>~j> zQN^BMgCJO9isUdMl^RRHVVG=2i3`KlgdEwONk!j#aC_T?WeUEZau~Z(4j-l>^ypHF zCpz?$!f2$d4T2vxG3>~ooDE5rQh$*puBeP$2FSdfE4)Dbs3!-dYt z11CNsfCq8e(F4iZ`Kmg&H@(m)TdT zh`SagzJjKc>_tkC{xU^&i$#7}zg$C=jC)8zk28m^p(kYTtYq+|?0qd6O!812=AAWZ zITe6?%(|8uhUQ2OCmmAgCn%!~EC*7W2r2XN zZ0irj^AfmTD^Qkt#m1oa%PKQAI9f$5?37)OPHvR>bFo z`t}o-6>~=!XZ$)f?)3C=ESQO97aKH48a*>hcBjgwKsI>B88}qF%i{}epvqm?pS;V{ z-g;6N4!W`nS=gU)cZ1Oks@R3>cvAPp1*zVX3#6bYizIpt`9Rfbs$5mrrxbRhJc!K- z6Rkaq*T0;v%6ReOCgk3%iBz&1$unza@gC?hkLsAYw#IFfE}73-z(^yvw`3Kas780S zgr}q^`2Lpg9*7dB{j9^319p5DTkuS38a~+)?y#F3LWzHas^dfxGf!bTb`_!z=CkKh zBOA0pB5#D^QC4n$QI`Apa;F0695yY#p3+opqf~wBFcq-OV}i|Giz@zxh|O&W4t)5O z3G=({9_&N*T-4Jlh^UG3yWJ3IZIoh-G3zm(_KbG7mPI-RoiAy?0Q5FUkIjsu?V>^PEt zohJ}O3!DKQ_yQf6Ly-f)VO8=hqk_q}IQHubIOhg7&F8<~he_KVaOVX@*kv#N`Un~m z{s|X+zIVugKR*xf$3kf5N&M;G{AzU8VAGWNO%@g5O+xl>Sjm4H#*a|yPuN2XQYizs z9$E{qf&_uJ;A_en$Twy4OZrWezr`#FeXKRd-)0DovA*A~!XVFHO{L#fNJ$GLrKE*8 zHGrg8-$G7a1Hr-*RDh=_tc6$|_5$Y!?@S#ymK|Skm=X_w zPeHZF_9dgJ@hz6SWV)Hp?=30-zWsZi4nc>+uxQEe_a5eB|Nf#HR^r0))bLl-Ajq$2 zX>*b0D)qW}KXc6w#Uyt#kNY!2ycLTTa{kc)?tn{h-ga5(`8~ptIS?HaOG40iQ z&!1OtE+I`HukU#{Dl`HB9UsdT0oU-0XThO z)@6LW8lU4bK2MBWw2vBxa_$pbeF~eVz-rda1kVTn!B4Yi26ZYZetBf)Ca#0bX#@R-z9+ zYYIj7tSz8AydJ`ODM?-pdMR064SK036*2is?BZbZ21))>s=ONX67D<|kHf9shyiw! z=A!j{0(idx4!4C)ZVfLvxb;c{<@}oQuA2Fjg^6*iY^;oM*?1Y@ zvWZlL>wb3G6z~p;aNAt;VQ|@08R4?!if*N#v&)JVzA95~GZg+BO00%HWordp=4;S9 z<0)SeoiUj^NsuTDN75z#@UqK}~ z%;#&_mgA`t^fSxXg3DXjw6K`d7;9shVRDtELm{ApxVkg#D!I>2l;dYop zoRJl{0`)#rsu(1uV#P}GLG!c%QCAA%?=YJz6+2 zbUUrj;r~(QX=3o_8#sj(Zh51Zv$Mt7sdRR5dG9Dhy>S^lf@6$aV~6c%M_Cx3vZDvO zh8)|`-<*>>vRvRZ0XNK%9r$Sgb7abn5*ND7kZ)mACBp+ep&zeV7_K7M1ZSU2#HQug zj_a}%?8KkbqvTmT(=!9C_Hk6W43R_+T~eWQa4K!HJZ)Gsmp?C7}MObYb_-ffd8(o7z;AL-30WRKlJ&K`R@_)Wmh$2@v?Wfhcce#Hl7MFZ13jv zWw3gAl6-dxli9noA^qn7Y0`Jkrv^d3P$Mr=xE$&?A}TlcyqG7dzVJ8X76sP z^lnG#6H@s-(Ug&gwf`QPJOi_5kF&Z_nbq!u6uxI^@kcOm&oZj}7^k({DHUCNkF!R0 z0#T{38W?o8ah&cuClsw}E+7OJ*F&FD9e zDZo|HrtL$jm{M>bt6*3(>{}*h$i6LdQLwKLc!n9fuR+XMYv0$heaj<{a&HYX^L=YR z<>DnV_FGP{mA{>X>s$EoNsK%3P#$g?FQlA*;K~YSj!Ese5H=(H93o&ST>E>8>l}~x z_H&4aV$+gyf36E*fmzW0Y8UufDmaM*xpNH`X7WMKB}2{~JSSJeRRN*1 zRh2}k|9}lu_~CLeFO{ogA*pi7t*T{m1zlBX=3fOLn3ACCr1WLgY3a+VMybc!ov85| zo@y}eG-ymQt*hijxlhcC$Fd$*G;I`0;Ni@}h0>j4kL=4dnu z`_SlJ{N{KH2EBV0-Js)8`vNt7o)SNSymv3KVVTuTW|-8~+2;6H<9KAsyXw_4r>i$p z1=!ow+F{VCJ=NQ(L5yohnx=7aq_L}A&coj8BZp7N6naV&$wxGD zh-mHiJAumJ%=cwXGmpTjrdS?f?F`4TBa2<&&JpT^03|j+{|{_14$j^S=tKVx;)MPm zOh@k=HZ2=Jm`?>Dw?4qH}n8nmi19}*?3~YQ>l*5hJS4-=~@GSI#huIo2T#I3=b{DF3QZe4sjLobiVP@xH?oZ*1nF)Kf?m-!>QnA zu<^rXl=?t;7u)xtljll*=RY7mq=<8H<%cDlE}(_!O*Hw*gJud0bf)nd2$%j`XwDHv+<&atR^&--t z^)&fkh)w-9P2Cjq;oFb6*^W(P`_VGV_M^3;&HMTfn=4xT zSRrH^%sRG8;cZc^{0-GU#sM_pH%h#ZGlU!N_kFzDtnkO{%nE;8YF7Aoq+n?Kj?aPQ zphJd@vd11gPP0EpJ{)(EcictZaTj@i=b2~-$lnjkr2adOgov+wA`W;4N1PZa@lIep z$9ZrfOXbChO6j2!#}&d!g>b<^xFQng#5IvPng4*NO%eYG65o`_|F~>+;K^LY|Kvi! z|KuXc|D?-A`Deh)|DR43&}RETS1bPi+$8w_bF<(-<)2)v3=TRq$ZXds;F|0@HQa31 zsU1r0sVX7&6mH{#!!tkeLN3?rG;B>DukRDsCE%L=pFkf|S^8wIIEbhDJ~^)lb%qzs z3{TVKf1_NT#$8+gLA^RnD@1pH@mENP)0N_w*N_BSt|%JMhGeR^g==BMJPZb9yQc_! zWP1Z8dwn#IzsPmfapx}l%a88O-*3hP;l z_z!T;E|Gelr6HobTGw#g#HU4Bb;li3BL^R25cIi^NjyoYxw6rz($7Ph^i5MK9_vI zF$?-4+XY@A z820mhvBivV(S_l~bjlU)CAsJl+KVMF4EG6%w(sBYiKzhmn(Z6XuhV6fsq8EIecZTI{4FASq7jILK^?jKKJj3eZKXKy6lQzEp^mlefD3Y&w znMp3;)i^M{jqlQ2@w-sWCGAp1IOtf#OLXA>kfxXF#H?z>g%Uy5h=2OR&q-FI@g#UaN#*le2O|{c7w({?}6|_rIQ~n6GD;$G@Rk zkjH$p9mCCYKI|c67?XcPH!+-lh0{JLpy3=i3}4~8-3)IcyTWz586FZ|r0}DWe}>bN zD|5~8ZvhX9#0zJ?@dTosq*CQKT-BX#=>S}3eOp1P-@+e0(c~Wkp&_%btuhO`cE|<( zCHS!Ms+!y~9s4l+yOn5~{S^|fGW@$W5>89L@%XIo)`}wi9hHBB5PespXk>^&!mH6| zULqA^t~)+c_I2>d;p-G}1@>K!7QC+05cFcM_f)(b-%gqiN2R}&;EWH@D1Mo9`6T& z+>tk2ynW+>ISMzOG*i}k8l`?W=@LR7b2GlBdd&##R2SPHI;W-R4uwKpe<;=d&lAhZ6K5y*<@Jy48LUa}V{P&UAkVnGcq~BPHB`D?28)P#~le z=ONVZnEHHbINxi^*_qjq!)_4Qaffl<``Ph^!-c<-I@tR=WvjI8G*c(n&7UNFlLvi!K=O%zjqqbym0 zP6`l+Q-E{_AQq8PR$!_Fz&Qa|xd4&|RW7r04|BeC?(YJ3$=k>YD#s!VRW?SJz%)ZP zM(z*@Q~X^j%_6#h$TS6_d@gWjBC>Ds@urAxe-xF6Ap%jUl+_-t&jK{)$mCUFjKZ`Q z&Wu{%?BF&l2`Lf2iix@m(x5!OrO^>EyDba2F4C(jtw+!9>MT=I8423>#J9g|FUE@L zx&U2+8eQoosAIY=$8eA+Zx4;T}=z_wkQE;hfGyIr1l*Gi%Z$TFlp)`%7 z^~^nPHQ#57wN2bczI4VrxPuB1%O6KKff2+19U~m2JQ3lMg1b?la13|rtqrF*!;{6Z zR{J7GIKwM2YuVaG0KI7>267h&7{L#jL+g1g+ZM%Zph5L4d&+ft_Xac9t00rqY zP(bqieK>#CVbcul!wzG(W@sv>V*xe|pWi|);2M6vbimJHVq0+|Va!;|~0> zioYMO3k6r2h-k(H5(o_!to;2WUEnDoGYIQ%zV77jpUZN=%+byf+&@np&-yQ-0)9-w z-+u`;U?pxt2E~b1L|{Vj zt9Dz=)u!PC7`E;nCuZ5*6?}0o%DTJCVSiY#hrl{{{2IXaS=dwrB1D9|{sD5H3=s1q zWZm8#p0kZ~BIi`_4U@>|oCQGS=({;ddjGM?;QU&UdJ%A5g!Q&<9Gkg5R z$mu+wlnQ`n4Z!1SX!C#2%N*e!6u7_}!0sG2EzQz>X8iO4zzsTh`IJ-A2MRc~4TSsc z^ik*p8(oP$luqAAxi*wdKO`2yQ__z>Nb8F{{`3YH_;s)`@V%!8;Ou|Rh@~N~o9SA9&Tw{)fF>;4~x>?0>ir+=AKXO7=e#7X<7dWua@x zfFC&vyB{r+Yu~{m)G5>u+;kNSw+;b7toVlHI6M0kN=A;T1F`;$WoGUfB?|M$9!2}( zXdx!;$FRnv&yTm5;Y0BN0xrzP`iHV1LD}J(jy~Kt6x!hmNgMyYc)kdF_q}(mnbWYL zfCuMx4*Fm)jPj#USB7bI#n&`kj$vzCtS%5dJX5I8w_8K zKEw^5puv?L!<{qN;RS+otpC0|4O4L#F_Vg-aSk?ukA=YoHJ}d(BdE43G#()mz#4%o zLIQh@hF#!b_laig5;2KJ9s<;GIVUq$oEh1fdoUhsRkh@jSx1eWG?^z<+o0MDs=cc6 z;C_!xxBKH90Ir^7f%1Ob!zt43{|Zlqi0-{}+pZ9F)s`H7kBWv%A6DzbFz% z^qjGh!Lc;NY~l&PgWaOC^P!D^8?yQ#x(V*~Lzk8CRJ8c`5mPqip|4qL%tJTO z3)YRLU^ts5$3wSlaiuggn^vG_XFEqwhgX3@P8SwrFIMF&n^iKHknPmiU!t60-devz zB5{kid5DNiN>`zpq^@F2nyyOHq(W6Vaw@>v;D#I=m~X}6{}|O$abSj-mf}T@PQ|j%| zq7JqenyFO?&EBpbW#7!5l(1d~|^uum4fp_MZZhc2vofxJwmstw-_9B0~pA z=y=LPk8XmI_2_D4;Gv3jGcG|N;vZX$#>Dud^zma~QOO?i40!_nvhU1!L_we@C_|C2do9L>8piRb%XdL(<=5Fbz2|N_seEn} zCH6)a@2_M>EGSihxI~XYdLygwJ|rl8nMLvw&`h!ZQm5zkL5QJAhzt@iSbCP4KTZ zcqRG>>oeEQ@I2-bTx&R_z|Z4kZ$n|J;enVu50*T?L0`+MJnDm}rsdg;icQXokjNtJ zGmAtt1{L#=iX5FhnTb~3G!cxvE&R{!0G|?V=&$J#bN@9j?%6|X)*XW~%>CEwm~+@P zrGAZ9_UPvvK}Z7x*S>OvNmo&ol;kzroAlz&HOl>1O)htTMwF>;pW=3z3EB zL;v5pB+74lVc3vBzm*gI-c|-LWJU%73llYX3HlJcaFq1(LYzG0^F&`*COx+BON<*N z=d&mOh)wf!eu|n5`A6jc^!oGhdJ9|-@8{3w(rD1BK-aYdc+jaJPU%uGT`E^ls9Kp6 z`M+aAgKobYvrqe05uN4Df+XK zAQ*~GbJnxTfN@%-VMDn+&Umo=Svu1nb>Ue&0&@@6j?YrW-Q3M|xFEM?ry%*SCO zwtnM)|5>ey9FKOGuLpU|vvXa@s8(=aLRmk6DbFqwro=p33~E+2gSkM}CT@KOU_p0f zV7OoWsLtANrV=P-J$qdpT^47E9oxTn5lDmU${yzB^)IFaU}7y6KfZ=8rc3DAi(Mox z-Y8Fh7jLCHhynVTA24yH0@qL~d~Pp33f932i&6nu4GOPOw4u+@8Iar0aVUc8RRj7^ z?YR_jPV}5}nj<3>61iFp(~xuse{PUC+j$P>^nB=eZjZA3xhjzW_H&1U9;}S=-g7wJ z6a=S*E!J~qrPrU6%306hb#pK#<~cqk3#M1bETLMQWY|l_t6?pVmQ19E{vcm64dX$6 z@4}N8#x0=(_b~Z9H7vM>gftB=5gBGJIaNFe2kNhdQL+Bt^E5JK^Y3v_Ar50Ph4G4= z@>Q1%^dYT~@(03Kg~Fqug;XwjknuyftZ+Fc{s=3V> zC{L!BmI|=7bQ9$a0_h*|pc>GuKMp4!ScU$PYJqP5ak)~%u}U4p{wU9_|9FxLmNV7a z;yMg(AUxMhj6Hn3{y*iaD|~;#qsVO7pO#V)(`}NC zyquf4yg#smW#>uqh8L*`QG{Ik2mfAKMC)O?_2&?g(|^YA6s*Lbhf~f_ zC^3bbSbF(q;hn8NFOjfyve_k@qp~?KqG7GXSsK%?#Cu^m&@1u23(-#&fwxz3u?{w) zOq#KBn25H$GRtLrg3N}MdFrfwC4A3wY2|Sx@T3&@mv&O%U%WEY{xU`NXNZ2YtYV=e?5u^HI{k=hMynpC2#jo}Vb_?BZJZ4UxEhy4GjXCj3Y1(IH94zUzo3MO z;sk&nUZ69ej(MRSdco#gb%rB`Vb;IkRl}(a4hiY%4Es2nLtmiDg`TK>{udH4_B=LC z_zOJ&3+7&eJ`3+nb={yG|f zYB8r?s1pdb|An)PpDLAIRr0?;D}KWKz7$HYp#$i}tZ}h?4PC;py~f4zHNtXh4bFyf zT5S2((3s(jK3p@U0ex7yW`t02&6Xzga-heo;YbBLM)`FOoe|vlXv@QnW1QhS$?XK? z6mo4@LqqOk;Z9CE=zBm4;V+7sllGzyDVPk17M&M+0A`q~FBVhDF!=e!QmPZ}Mp0q= zzIX`uhN<$Rqpfm#^aS9sc%m8{Y3i;`RC%yAqc{f# zrnPhc>_@K60&450?fq+WUDzxKJjnIYj0bJkQo=|?X00~wo%yns#$cGHjS2T9#j;2y zsYGL#TWfJ02(`2C+7obm9&mI^;6xMrB{~Bc_DfnWMHhhu#Jwcu!^oGWqQ^@Vjq6KX z$u1h;#efAH46Ot^nvFS_`BDjbhVZ;p4Y(oNFI@%PkTvTpnKkR$QO^DNkzpNYT+q!S zYctS?73+E`cq;cpLYv@RsIFtv%vv{J@WoPQ^8J{^>$WN}+l3fw-4Rts*QXYXQ?2!Q z>+dL}$9lR1{FwD)!7|8tTZMZ)C5+S*xGmf z7NE>9pw$2tEW84J_+UMq0lB@NBVlm;`m@3WYyEk_K6CvAbH0>>f!^SX&X|^^czOFz_Y30Z+u|bFiqyfh8coU-wlNz*osZFf5S?^g2EA#gFX!2KnY_I z%?)eC@nHjvK`(8?UWKf@6H}m&>(E-*6mzFQY&apjlUB+>F?gr67vP3qm5$(Nprg`C zXJXti-%9fUe+QdpOzCoIbZN0LI;QkIaDt7CMjytN((EkcS}9jsgW9Fnh1%B3xYCE< zS})@@+q?PT`tmZ$=!Rr@nQk)u%j*<-#~sWa>|ZXSjK}%Tv6pu#1a%aM@hAkE`~aMb zH{daz<$sx0h(4~ZU-9x+UP1gdN&4=u$&~tY+{nhRHzep^m$|?`P3Jbd*y;B7(z&XuhY{?7qc_*Ggz9@+nDqsacvAtJleHe=?Q)_a@d%5kT0mJ3W3iwA5Q@cC zZ5?12f(Xvs%9GWk{Wowp7Ss$x1ZYxD(W4OGX8s-GVCpLw@z5a3< zf?=!NN4{(vvC8|4Wv=ZncTNr*{0s+wyUr(h^Z8M{GIvnLG3 zlve<5@KE_Fzzq>E=b2zwtW?0N(4-LhNjKa9T9FPU!(pUif|w3=1uJ73FObuwVy(hs z<;t*WwpLWjqeDd_#th0=I1zDNSO+|~yn@C|g3Gswv*y0rq5(9VhHldW5SJyXw^6yE z7AI+G+ol3K9-F4ywnD(J8{j2sExQfxZ+IBXu5C1AGAnb4%VOVcJkx(TKw>!K-maZlci=d(G+L3v>_ml6+rAM(nS(C0!UeuhE=;%MeeS$6d?Qju|BW8t zVaSpRF27Sy@6LxPG)&xX&LiIHAoB*c!MIQ zz|(J>#&FQYira%eY=5Ic92DQUsD@R_#W6P?rrDsjc8HV<-9hV_*A81DJ5g(t$UEYg zm$gGKn)>d@0@&by9n%!KliuuX$l5`D9${Izl8c%|JGQuR!9PW@yLZTAoW0{J@C*lL zyk#|YKdv+|Vjt3XQo>Y7-#Ln!}0K8B-kwK%H9>~T(K6}Eaykbe(FJPOHsDyRSx%i2>-jqJufxW|;+ zzxj$Ehu$gRY%uR{xni`?WpuT=_^>yH|7R}B+Kc2vOUEA%kHH11B5)2BuTknU#lM$p zV;MFr@!lK(Sd{@@0N7yzd<|eh9`2TdKD_cK9he3?-z*Uxev>YtXTPcCWw&UBEb@}P zPlWqD84|RQ#=x7_K5>CFbRXrT7qf3727`s|agfW!@C3|+^j;n`yNJg|eNR<|Y<)??V-_mwuBCz-$HlOcI)wQ4V@McsZZ;&3L~ z#=n0H)h!h}CnU;#xsJwrIwisZoQ4U^1GvjZ?uhiY4&ZOgWWP-9RE`swVEHR4VFqlf zT%xp6$r!JuK_!jBuwA(f!-nH+rSrI3+UI2xKO=VBl3D`%}57HSh zv<`~*PGcG#q=+XV|DYG6L2*l9Y=J%m!}dX~#54`#)ua>IB?mKv*uDo@j7jVwz=Qb5 zSE4WY*Mh%w5U1_pM~#DAUQG0y*g^E&Ry*_&2ZTK(`r7ptqXQN-CqZ7x-@n+px_ zm4F3_i_bwH>Q>Q#nGjdCR#SH zw`s^M82|QHR5A-^1#dS3Z74R)r-uTRfpPqG;Ci6j;)SQ@3}{0Inso^0OhC5|%~Jh& zlKr7opfS!KS1k4bkciDaud@SH$c<~LCu-=_W4Y`QpyA<&&g#F!V6#cQ=B=Ic%Ed@9qceGi=i9*x`@Y|85l;hNp7h`2fx?NW`Y&(@hpvJ(N=O zAibLU%;D}{p{iBApK_t2RgHVLp^a62SmGFNMB`n_%*ABtKe=@4hZEsNqR& zh(S%H;!@L#3ifert;wK*_r=awXe;-#x-ea}j zUn7ELy^sILoWq2rl*7S$pAI|?ecwM1dP6kczbM>oy^p&GgyD%= zM;$>na=edF{=D$6Q$Ao@3<3LqldoBFSk83xVdn>&d<>Tf&)rm zaHtKn;3yt6;Iup%F9KyB9jy3ke2$K#MmWemIv(S!vzCB(Ev=Aqbczc-?oogq*3p&H z;YW*w!()zW1wA?%^sw_N^+AGKM|TOd(4#aNUHj^hRx;ZR|OES!^ z?Wy5A@PQ&P(`s9Wr^x}enHrr+m)g<7F?Q`Zj2qIdc9Gy~)#CN+aG+INDzcN`=v#oF z*J5hRKxbj=fDIofJb0_{e1xYK|Dwmg!r?8#qI;eyIZ0|S0M$TMhhNE%`&J#E1mW5C zA%0)QY_mS>AftkD5@Nv9!$j5lYJUi@T z=>Y3v{8=CBPQL$R*1#~Wj}HgDIk7_$iqMCx$HywToW9NQ34ojU>d^ki{{=d_hL-^A=|KB;4O{^BX!12yt99m-ie{VD+oCs4T^~5yktrN3E zykkz(f#4iAO}Bs07;2bEE0@tV!S&etd9{3%WFlUf9p+5tvCie_o!mxE_I8`$C8A@1$S$k#@FxfIG z?6n!3kx=5yR5S*w&TJO$1$jQmtuyiA(7qu`W_F6sSGDd9P|@6+>?SO~p7{Zi23UAy?R=BQZzS)Te9HWfoV zMe1`lTCBg$Cd&2K*(`t!>#ws@#rmtC|7;Zyg2Pau_|z!4W0wOzBChy-7OB+#3{^(h z@!13!*UzSD467x>&$x86Acvs?7ncw-Kih*LgFT<=`dv`$bp0Io5lZ|cay(v1Q{hS! zQoa6j$&~vCxbs|!KpT+-w4vCvnQ$)G1@2M`{zV6VkE!x6p3Fg0<;fECk!=4OfhO2E zpMn=t;&Yg3|DuFK#QI-VqV8D#!WjvsihZ8Z3}ok1)wQPcc+3_Toznd0x42*)1)LR< zZg_2`noQ^E3hfwMHPR913stPKfnQ>*D*Bnb5`pdHZ3X_Fn3LL>jG%1$hmeQOB@no{THSJ(GcznIGX3f;TPDACc!(zq`H7#YVjLJ=mom86yEzH7ubfm z^@X_g$NFL``CzmC#V())C4OQd`ta2k`-BU=s20lE{x41dY*+z&LFGtj>x-|bj@eyg zYJ&|IRbjcK{=Dpw zxA#<;$p1pDnuqf;{WE5S^IA|!wtf&0NkR^ zaj20BSNIrbnAcb0Dd#Vkhgax85$55QbaPp_f(Pd?tF0>~)Hs@39Fj#_!$zThlqv{n z-;m3}Z@qG%@~tgH{Vkq?SOK(eN69MkZMJHsQN*`p_Ve0Wz#LaZ6*wr~w@vHNsMpqYcA_9Af)a)v*V2M78Ff^rkFNDX?m{rVI zEiSH##l`*p|FPo@zXtw~)6`J${+9#z*Vwdz{l6Ni(f>|LSN`w32wd9#z5;F-Hg#B< zSBZT%<$qVv7!u@~MY#w?=rx*+oU^WZsYG_yi!S~rMs{mOw`XyYz`coH%rzDfBx-gB z`Ve)E`XFVkYw7CHaBUR8hB9((JXK0|D}bMNjSqaxjy(|)^4hEhZoqCP8k6SpD3S0p z_q8I7TiBF`Y?b2IHUefy@oSWT)U>W`7t-x(mF5(`c1#|)z8e8H2Jzobk*WS2ZffOR z{!W##?{GaG{VCrq0-d2QHN8t*n%Pu@zgq=-LlOS&5a7Y))u9i!e0PzG)}l(xMv`0C zbJSAt`Z8yyOe~5+uT!l+*h_UULd)w_RKkgRy`E=Bl=b~6d8^U)>?lKwzONB!Wqn^y zsi+Iq_xMW`#LW8sw45&AHz;}E*izDsBq7PZ;Vj^^#Jtf{gweXu zTS~f-CMDeHuYTvhLFH>;;*Fu?gXZ>)Y_p~}3aIfB9$$udvJ7p)+}J~nHT*#CO?G^+ zL-{BNhu$2g!Ih(L;&$o>!1(5Bj2m2Z6E{9!+`3sqb#N(OCSLm@4of$A!nGC?zzgop zaI;#05bCowJSsL2vIcZv*ccDfV{QdE-arU`FK34bLU4Trf6|1V^Xz%vxyY{X5*rAO z25RdZ4utmSDH@e8UiR49v_L5P+C-NJxCy_=1-=jPU|+~78VIced;z~8vSqLWp^e5# z8L+~5Qo=N=KjrL()2$Jz#rqC~@zx^B*nlWl6tONm3W%kYwO#awpx-ZGRY7F)vIh zAx&`H5CM~E>n1$GdEbWc2&>IyVWS=90fiwS!UB}@8k`drRa}bu9mCRr#sx)-YFHMc z%4I-@=gEsQfv_SM!p(qxhE4hkJN)qm!nUGexC$CW8Q#{SikA^|y!m|t4peP>n6s%Z z4Z*P07LPbOfOk=UT%&gBb*-vlqixWQR%@k9)q1#vfp zbi9}cx>{{($cMzW+8$H$x$QZz6B}rI8H|D>e?keyJ^9<1;<}<}*GW;dV^s_RXqV+6 zOfs`=z#SKHyo8Mde01wqJgzP!>V(B7k1 zwvSUR+h>^7Z9iJNru|sSs=YkQ#Rl5X1p&_oEs@$UR0Oy<&a&GVI-8apOf}zV<>%r?nkqNd(Pc#*8PpP!Z zvq=WYQ{iY*>Fh}5+XOu7upIE<$2@pqWVp{f1;RO*n{z8Hr$FiwK0v`UxQ|oC0&cv4 zaEf>Z!41bkeJ30oK1Wu=aQrHbDP)Ip(plJ4U}9Af3@@P6w~_PVv|fU8V@($-74 zKu7#eibHj5pko#geu+)X-;Q|ne>)7AK}Ar(>WCFCcjrrcIxYrqP6(P3y$rZhqL$>cC5LxTF(@o8jy-2x)@P5rMKgNfoS4 zi-hZ}PB`y@hA}RGyMUMSPkxQ1Z|37c-%dxs(@>7YKN%Pdx`hrf^)2|*%gwOsmSn2r zqsuM5RUa48MSryFPgDI_s=q|_my3SrEmXdR*&U_~!S1Mtw{=TB6|ie=p@`Rc_@qqf zTkvx$bNAxJ2v-hVyrBM5%?tt1;CC#$uwNx3q;^Y zXwJ2W{UXV%hv_d2-yxYUJVleWH=2dA-3 zzTVR3zBH+g50`wPO^k1#!k0d1#-||_%zlzkI?Xo)XhCzZN0DO7E@ZfJVH13w46SdW zn8TJ27Yq<$%eO>mZ~2yrL$B>y4q8@MiGQXJ`>gIt%7G7UA1?ud^f9yGEXz}L zHx!+WXww0}&$!Gl16xo{_TxtwRCvqZiAqpSE&K(A$UA==u!8yXstB(1<5o@Fr4k$P z^XYx-3m*a8<}VrUQ4FgEL0Z6n4Ft`>Y1YiqI0NHBngwXZ4wSyYH~q&(a2%W4o+Vr1b=Lg zQ@y^CTR_h~s!vnF_2Hk9Sc9Wd&GaK3*m5}Z#@?D$^a-8G9D+NEh3l5V;P0x~VAF5K9 zi;AzJPg2qA@};0p>*7oRCny=fhu%@`TGDlQ;BY?9^U|WC)VQKc@}bXk@e1z9bKvkC z=rW@KH|ZNSxFx^tjf&s!mi(IFczjjxo8ZFF$xg>ERYIa>Y5W}cT){6ts=$RGSO4Jn zICRA>{MKpsMd-7CHfi_{oD)^e*!-wHW+l4L2U5^VjFX9(c3r68a4tSp6MQpzK}si0 z=V9P;<}+O4hcv-=0ft*jpMNXdABta0-b4xPx?kZcN8Wk?edbZ4;EG2R{D?T9d{5%_`y(G%5x63_&9a#2})YYy-je;%5k@Z6e% zKEs!y309~;!B;A{!yj-s2Lw3jdka-CT8sCsjti?4p`$=0`bGCTgh$0=aOuayHd!rW1K0gtnMM`!4EIRg&uZ{Gj$c; zrtu1q*=+(brxhdZfOhLurPz7J=py>TadgJ7D@Jxt$;j@l5FL$jBqKXbGO`D>WYohM zM-jy0?f!tRWm3`}#b8cL!Y2591y=%-GSG)h?S+&G7g#o4=82aalT+BWgG| zjjaZJC^jv^;t4ntoGyV~S{x?~2UI%vwY=%rhxBf|>@$ezhT9*Yjn!=|6^XWpvZmus zx{BjjP@dGI6aD@YR-o*yGox^}ZuWq;)#y4#T;s;SdZg`h|f%t5* zD)GGVGpHC}N)5Ouj(?4sU4@Gi@fBu4@pXV(*p$QKvak=!;qLDY=I?Z7jHtotCq^IG%mK29yXx{KSh5Xq!H=#|RgAwhNr?H1XjixhoQ1nsaZnZcIF0CcJi)ot7D+yMG z$x+7_7I5PYB-c>ly9h|~adb`NSLKPs?P-$j?E?f``*!xX!K~X0$@d$c&9@(s{<-~v z3*u!lX|3C@h|I84Jis&fBPAg5QlexArQly9As|1Hl7tjW1(7PF*u%#gNJ&<39&7pl z-V>eAvFZ3+{~5014+QKp1O8x!) zoH^QXfirvn!&b@y<>-_G$_?ufWu+{m3h_%@$|}nGEr%clFG1%s{FE)SAf;4-gP|a$ z9FwD`yD9yNJ{IDH8L1?tdl{zgBQ+*B)wy=!oy=mnD%LR zTm_z?#P;ObX~?3UGgZauS*CXGME;?0Sa%MjtPi*yL=BhN$U8@q? zE-fkpdsJc{f_tr_x?`}ZS1Fail>ArF!JdO5cg_EQy50p&&aylk z-)sWe%wm|#kYrg9hCq_#luUNB$>jXzJS?Z-n1w)?BtVvMa7rs#5ZMtCwrX*zu+M63 zog%_ktxi#4Yporv%6|PkOs&e6TAflf`?r2}3P@J8^1rV4y`OiV`(={fZ*%W+UH9p^ zpZh((Gpikk_^>S2g+B^b@j|?ez*W4k?z_G?ap4;gk2Ucax&Amu@D*L)pTSRLO;!ZC z_9RyHMI25B4p&?$xUHeZua-7hachv`3cUNw6jv1dn;G3J7|ofpE!v7NYlk6@&$#*J zTk(5S`)8b;tTg}qJ)D27WCJv5`IV=m_}FztXS6c7Yu%GrnFD!$6NNi~HEGY4!8Y5u z^2y`yQzp#^^63lsCKyiW(&nc%94XT4q0ik?P@&KG-=L1gO>gw|Iuq$#qRu(e+KecWzKe;>n{ox%+L1K_Rrk@k7J_4*UhkGgy5IDTFZ_OR(+2Dd!Z({hh= zl?Q_+yV_OQ)X@yBt8kA0J?ynseFJ(;c8uMp`zKO8iS8Xxcpg8IM(_SOuqLbC{l(y= znM4n#H`A}-)O$`8JXqct{D$Co-Gd4?>%*QW{ii3h6FvTiHy7>iVa=Lk(8C)3Cw_t& z;urp#pXgx?i3foR;@|wl>No-p;@8LwSDR1#0PVDTm&yGIhmh6L4Z1GomqE@famzUt z&-ov??@X+I5DM&|AfL|+rSLoBnw3AK|8E56X{+l%U&c=)jowuAdh`aLOF1pk+Yh5A zb?C*Xsc_6Z(93PM8UKFZP3qM9sNj)0^?s#!oqBO6;9v3d@bVvF@6sFDk1j=VIoaOG ze$?V?TKp>YB-Rw5*Cfj|4;=@8+2ohwGhc}{h}i5jYz-p%cw`!D|ERgcwcI3|B#>dh zHd(&RGUDcsUYM8Y%;b(^i`NfuMR{5xbDTBE_=^u7!J9RGX4-H1(-P}g$0pgW3(nRL ztXq8?egJrru3Cq3Hw(D#IOSgVLBE-X)|HPF=X1cDG}F3g1dpu3x;o-F+341D@4FH| zk*#1okGI(tbHd5<;;o7G!KS%hHqG^sO>?OSWi;LT$fg7W4Bj&YKH*<-bw;8B==^yY~&xQmu8v zYuvY7oY=_jY0?E7S=A<8wGp{C#qo^~bieUFKdH`*--g~#@e`TTrtUy*)0!apP3H0+ zBfCwXGxZ;1E}P7dKg4@X!SM6`5bw(c!=L)YS4y`(C5^s6XFY%U#12CnrsBDgijj#$mKgfXISJ%tN8JFzwGPqcF@7q&?=ZXK5! zrd#p1L|KuoKbE;}Z3uunc>d(K#RFg)K6VJr&TUV^IZ|BroXY9@#!0(vScI<_l`P+UyXt(ec(cdSyEv3Z|0LP=4_hI{|M7!PMVCLv6n&;%i)d-52p?@%w$d*6n!B^*>RQ?GH!vs$!38B=~RLjs`}vv~K^f z$zj#|w*Q6b+oqWk{ig)Cxm$b;c$1oMe@6UbyMy2E?cdUV{rgd@A#VgZ8-~Sq1kWB@ zci?gXYty;|pBaVh+;Iu?o24z_)(C^ju%b5PK96i33cwo4xrf~ zX(t{lAH{v}59@rFPGF3Dca8{d>tOLw;7#hVQ_|S^ipd{E_?@qtv@h`%5yGspTT4*x zIr&l$W*4V8Q;Z_GdA5Z3 zFz{x6Sbl6Oy+`q~LlzHlrts_ve`kdy%|7MVraNm}DpJ$zODa}a)4tP9aSHZ**yYnt z-vg$|x%T1fA^h>fzTX3V-xd3a-#)#E4E<)(bOEM&H4a9(u zcL&1{`(hQ>!ks`Nn820aZjN7t3uS*zuENc!JNT62Dx9&gORl=dU$xGw9)e|)+Ftc& z&`no;Ea=j!s*wmD#wguY--mDx9?K-7t6nte24;gN8h96?^J?zC)& z=1%3>M=^AH*(qI%?`z`D>smae@g*LpvEi?M(vuAo@XK5(o4R3zAAW{dMz!>EY5xZa{NU7{{V5X#_{|v z-q_p|yr!Q_^fOfz){Opo-kJC-uKrfszsuBqjRVg;&~lUL!Wc#Ej~wv*2R6i+jPfe_ zFPSpj&H9CSZv^e%kGDWy2fQQ@c(r*Nqw9mwt^US!9sckqHnPs^J`7LpzPS>3zApH( z%+nIrjW-W{{i0xFz8+tzMDOPWp|4*N4EOnB)q~$3+^>`Z^QW zfA%<0&FA01iPQCX2Jl-n)Air*^?MT6PdC@!%c8l3t_2C~#Wyg%4hMUe1hd$Sy$N?s zdpG;l*?YIZ_X%7KX1DkKGJaMhzDVE|RB+;?R#k$u+(iSP5fyK^76 zuO{aE?hDGiZw!1Zex%H)e*BJk?fbsCdr{oggLU60b-F3x{$6F-r5&)c1`B;Q3n%sOw+&Lo)-XYy{9d>;BgQFwUPmVe2| z@lKZnSndH}fM5B9y`el~@QUD8KaVl>f3NW_3A~?6=_J(UVGRBK^9A?y?!b}78g#k@ za1Ub|oDsqEf-li{7ts@@Z3hbKb&( z;S0$7xk0)U%86fFVSgUTn>%9WJq5uc$jY86d&K>(1EU|&@9KIyA6wYo(k1>5$R*){ zhl2bLd|YJkdTi@~Uozj;gK<-8jV)ePg{LM_ZszvA4L^~-y4jxX+yc%uOce;sPuy}6 zLn;zd(!LupFBSny?KJ!gN~XZUYH%oJ?S{uIW< zzYjq?@D4k{*+(zqC$b>7z5=Y7zU{A|PILBm`F@5Hx4t0;9)T81Bo5gHiUdB?39Xqj zgb5we1)sqmjOcq9V`7I&5Up%0nZc4aQ;EeE9p3K&qrzW6xPjt=KOwkH%;KMm=Egyw6rtv@H=Kc za2bTVhT>@8!-Ctu9il%XxW_S;(Bfb8|2pqbV!$?6)X>g6YWND=xTUuV*e0_2g5Q>C zu7BGi;(SBc&d?gHi5R3X#>{V9FSy4sW|E=+&V81fkgWM_ehI-@{}#XA(O*hOHt;?n ztbxT3n=)SP>AdYO#}L1sJBI(5z}=?i^Y;iJ*w65T{_c3_Hrt%G(!pkyxa}#i^B|qA z?6yy1|E`KNXTNNuw|`&xo53gjjj<U%+p-4QHxSZKQdcSN?;^NJEjuXMNocibI`WA#S_ z=X_Wv+3nx)F(1bfDoAXGc)}-aLUZ=VX@?0uCAihM__reZS<(Neh`zm$B3_=78tV^9a)q<8+H0lXDI(o;(+_#J`o_8^+* z-(3LyGJf119HPN6z-Ep{n;204i@=)&_{MSk;5L3U{XfJG%shBkTXJ^d4{r#*UFx2) zJaxVY55{np`r^br+`B!4A2(|xac@6P$*ygJ4;%*%UUnEtJn#gJW{yL1_QMg&_JD0v zk7I0!7XLa%?v`lrmjn;ieMa9loCn_VGt|kEdHLj6qH|~kf5%T6KX`feJ(Cpk6YrU0 zDqrVKy!Y&|zu-CE$vAa>&&QxZ3lBez#e2IC+QF1UeE6ThJ0HJ&m>mfJ!`y6UahDqyv|8ei z*)6U3kp*9x!|yQo3_5%+3v^lv_JS6gf-@qx(c^-?Lq z2bgRV-yfiF7Z?2xRwKCN{wG{HSKs2l1b(%7dEdMRvlEYIOllm@f*-vH30?p~Rs_G{ z-~7a*_X(a3kl=sdqhg0WU{kvnk7E~nUlaoWZsdoE`=Jxzac0A4xuC!Z^AjJMFSx`F z@eZ1`mfB3Yn-6eHH~YT~CI0ko7&uG*p$`U*{uC2)zx&4GAKn4nsg8Xj_hDAm#p8jW z57VEEcM1Mk;%q5ton_WwLK`fd4h%kWj>c`^kK6%#5I^FF+N{J!juZGJa~jlz1!!w8;nZ9y?A+9vh1|l&L>fi{LWz$0Lnr6MOs=ti;vkp}X1^ z985gEI$|tNA0IvrUWwo~*kp5jWKQtf*a(7#Wx}tv+#@&e4-sNtKXU(Z6r!`1fFnPS z=v(}kauhLgSTXneKu=;c9kGz9j`l}z@ih9RpW0Aj^cxWcYuJe3V))Tq1Q-2}vaM{Z z;8(jKAEkeCk(T@D%hY#!S{!|hfton_SX$$@*FTm$4xT>_&TYW@e;a-e9X;f)=Fp!- zE8;;38_CBb3D{Ns_%_gdX)v-|`}i)wX&3&3pGd-?pU0qtmjZsaZysI>`12N1-^abr zpZj|w^R07Y@z&X8GkH#IMQnD1{^lqCB4z65#1@<7OJgU;=A;D71mGSY%nOKzhSYq- z2P*>NjTeH?5xmAv6F!Rpcobmko|Kthih%4QKVT&wcQ1p*^<@Dk0`LgIy+r}*0r)h* z8}b59o7{2)e1YJN67Uo80Gzv=U^&qIL{|W=1=zZ;#blQwi+u$l`vcO@VqaCjLI6Hb z@TRzc!vT2A2W`M|050#MW<@l|18@((*1Ts1x)3mLeNP4CbF|o>3oOblrgSbQbJPcG z0(J!8;&Y*Spd?^A0Cy8Sm=+KZ(P(}IVC%t(89o;QZ?+_Em6Cjc7B^SKq7;C0&jWai zC*W8BuJys1fVh`J^Fsu0%?mggfW`;w0ya$jJZL@-u=P;MOrD1<1_}ZBmuN4N%g=|K z+wuaUy$J5{!J>d@FM^NwU|B%47s2NU9&QMT_9A!`VC(I9Gkrb+-d+_F?L~6;1+cgy zEg;&9;1Pm%T1~VU!KVqz_dF;5676*%z!wM>q!v%0y$H^|5FiiW?BgfUUH}(laJ1lN zy3EJ%pUGYrJ9{B>4IxsnK+nPA)B%j%-GoN>G0O9dGANlpf$k%CjNrW~SkV!>kKpnZ z0Piaci0&h}2jHyx&7l>sm9hIv!lC)dJx7Cgi|bFenCeP^M+pw40?ki$1mNP81jYQ5 z=>XjAgB8)t2H+8b?}-bT55T7Zw!XJu##dr#-j^2=kLVb1ZW)>+BlxrrT5~jC55O0Eun}l}3e87wZV!C^Sx!JSAHlT%TR)DL>p>PDF9?Y~BWY;y z=hgz(=nlWQ3E%jv-AX*3+^MavO=#7C=n zLD6$WpYzeLd4i(ph#mzxyX7BiW_m5de#?eM+mYU#Vc3bP7@_Zo9`VutV_l)~h(7J3 z|JS1Eymdfd@X_x`ieqR!qI1{L?|1Tn-!b$a(X~Klw|u8$vg?=(uUXkrW9UB8#y9$2 zO;EHS(dT{ip9_Mb{fHj((SIoliuNPAd_BYdKqfhc_9MCn=fQM|8K3{@4=~?ML)TfHnk0`w@K_ z=cxf>baCuKp=eni*$=ueA+qWy>-^3l5Wfc7J50< zp9ea-`> zdC^7t5k2OkZ!`o&`w?C4G3=XG7wt!MkB2?(i8#6Qu*W?yCnjh{{lNbY{cf;|>Qvk`obAg{9-@UM#jc+>|A0;1KZxp)V% zSluvPJCH?hPDnHw$s-_Ry%hn`X9S-nn5hbgHromC1%m7A0r)v|8NsE<-4G{)e{iyMQ{(n zT~z^V0r&{O)~shncOi>DAwQ4y+6{}Nw766X^?9@x!Nt1)UT!tfUIcd&yh;l6d9)Y7 zBLw$YbF>%1rvbL!R5ate5%4DK2JJ<1ZWb1KuLb|+Cq9q%BDj{|ehZ?#2p;mms%WCU z2pWP1Y67CYvH+h4*m|(VOlA?#UfxvDUL==a1dD^>rh@h&xW@+@ftw22i{K*!Z!QXm z_9FNk!CUGAqP++nC3tI2K(rS@dXY-|)INa6w3P7fC~lJ97e}y9hq- zgAD=ET?CI2d`DhDbQi(pmk=xpi0&e|#|N!Bx{Kf=09y++GkOWK_yckC47%%5kVk28 zcO`K147!Wp;!6SkAu$x_8FUxH-2~q$`96d0B6x)0Jr+cF5quh8>pgiheklUpQxrGo zE|POEgT;}8faorQYY7gP1VnccJVfw5YmV+BXb8TmCYtE3%K$zPu=U;8d0mEp#cDu) z0o_G%`Q@;9Z(cxj7r{LQ`P_gr`~td*;3EXzR~8W6Mew=Hag><#uqPqbmef!n)Uv=7@@^T9|7Gyi}&FDsOT}GPy6VHQi7t%t^oRikCv(d z`bBgZ(YaU9!-tE4qRoh|1v-1yV`-DUf?*%43ynr2ZG5B0tAe7_h(7P5BV|F+YDACu z=tn(4(Q8DPU&*k4T@)0}Ms$ylexWQVx{c@~KxfZF!lPF*nJFJh0ME*LdNrfzF=w<+K^Uiedl0E;PE1 z^xUf%;A=HO(RM`F`smj^LD6?a4+UsmP&6J<xBSK1-j3n`-slnLl57T zyq`n&5nT&(_N?#LOm+_^`~8L(q5DW1-{?nqLD79gpZC!ha)P4!h#m{jf}rR=qRaak zcCsQUx{v4{AN^N?DD89TKBA8RojvPc(`K}v$^5GX7)SSA2l{AWln;!?(S1Z0U&jFU z;$a-!M|8K3{(D+<(S1aZ1ZYW6bRW^DfzF=wQpJp4$FM)MM(94$bFXKBsj?WM`-raf z(f`k)=su!{eDuF8itZz7e6&#)59q$VK%e)~SG@rJTXY}MV?bxmdaY#I_A;5*8bYJ{ zNblLpWR6t?MfVYX#7BP<7Zlw`^trv*BeoO;MDr0mN^n+HK=dBL#W!FVJliu}H((b$ zSLXk>Xg!igK*ruy6AN@6!KVq%Cx-R=+i6q05#S317Zd~V%lK0l1n1re@Dwrsa#sMZ zCD>6GO)mfs0c<_BWCm|U7M&#_3jz5&EzW2Nh(Fpw-^U21tR|ko6I{NJU_~_XVQ_+b z2%c3Iuoi%i0Bl{7GNbzt(7uH5cj&g8U~!ZdXVU;P{5v!o!NoTbEC`5RBe>fKYXYLx z2p%DLj@3k`5quh8>(a6rzX<`CTMP6V$+>x0*iUNw9omfGT7u^l#W%W);30w+)CEM7 z5i|r>qy$8d?Fab04;BOPD`+u-#{jnC%evb3Ba2m@kZ3THd-lUkx3xfj5q!i4%c6<) zBKRD^)oB6IUIdR4T$dLR?L~0$0R&u!OV9%dxL#`V6|@)0BOqfNtQ)i!!KZz&EN;+V z2LZl7aAQ0G{~ql{aPC2Z6#>y+1lJPWB!T`O?M3hqz}8I_Gk6eLY)**<+Kc4#wAfq{ z5bZ_q7(uTlAli%I@|yu}%?XJ1BDja(_J)9HFM^K%oVC-Kn{mRrD;;oOZ5io|Eiym9 zITnv)#mQGYd~DGzz%Hg58t$uUAKT?)b-}Veb`P;jtiL?5&aW1r!UxyOsM^wcS&;&6 z1_OE+BZs~`FLWuO%bND{qV-rnk8Ao$8k4RDbS*;L)FuOZO4C;tF{X9Hr~iQ?C$+2V z1m-9Hp)H_0G<{86=u|*6mScTwO6W{LXEnXY6FL{rc}-uJ5_%w@2Q__tLFgjsQ~#l) z=^JuFn>SC5E$;k>F-_mdR5`Iq;Jm8oeQ}{D0(vq+=Y_5ZbR$Angr4^4YMZ9*1Ey*` zpi`Q@B^Ov%y8=3+>03)edjU;tr{=ddgzgXM0Zku@3tb54VuVf$Jsi-Znm$|-x*X6I zP2ZUkdOV;fH2n@w=vqM6HT?%R_EbPmM`(%twHBZLT0BD28y56y9Rb~?>AUknrvuuH z&{d(c0o||ZKTHXo59mUKt_eLD(8HSkBdRmCQb3nA{Z31d1@w4?u3${-YCtoVv)=D) z2t66lQ<}Dyj9+W`^w+8ESRdgS&cEIk&>a!FE_5oO)0!SE2%QP&Y=kZeoeSuEgsuxc z5YU5~zBev(k@Trwr!yz>dp)6p?fdIvn!c|tbR}?J)%5*kp(g@*GD6pdt_O5O)9)tB zs!jX!KelPwUN!$?JfKq%n%-djk6i(s(e!)rLVE$7)AWNCq5A`RK-2H73tb54qNX1z z2|XOpqniFeP3Uq!GnP~H55|Qa59o;qofoF_2;!~`N{~5q|reH0Xw}}ELa|}OG zhl9Xo&){F}!tV?;3gP)~6a}uiN zO!<%Sany^;!0B&V^Q)=>{tAU-*PRla1#s}q{es6eevo;>|0^9D7ym$^fut z`UNapLi8Cw_yQ;d|2b*j7u87a9Z?7HJ(R;yL?AwO;nMgk8_4j zLTk!`S2X@H+(Ee~wrGj%rB`a2{|GC=geOhme)QZcb6#&p6;}R_`ToNDmH2#>KL004YG4%Cw8n-L;YQHI?;s;*MYrY3V-;VLZ#9CTx zWnX1}EXc!%h(s`)U#i3o1< znACWfU)|4d=+%bizgonYc}#2EY95N_uU z#)a^FBJ8{i>6ixn5U!)L;CV`tAjv1h8(s$vi{Iyzy-zfZ~$%8-dwW$bCn)ZTbVT11{cJ@462WtjuK&D`4<&v*fM47IOaux4x&YxC6a{Ajj{YS- z5WEEG>X!u{gLL&D6TAXB`vUwYJE?S4hzUs70ITUIR5RtrV)%-oUr$98P7#HMDSm_} zF|W62g^MM{*EuyO#Z{@m@O4Tj;&zL70eAI1j8U4`DINW7)_)fGZ1aOVV~M`k^AVjV zF{bSRgzHoK>vc-kC-$Dce$nLq1b3I7y&rdowyhQr-vaj`G~?@I+Gy+Vgs+(V?c}Qw zUYhOo2~+)J@{3@;H_Q?o?{m$3>sK>#rdAfY#r6j^N~7{b3(JKXI&x zU)%sTFcn;bvPnO{girAe6UWLCeq8Vhq~mXARdDjIznb8buD-OwvB`-3l&^nU;uwE% z40hCgB5|x?3LlFtJU=nbv8x~@n{ET{WYCi`4a_LEqd#ykoif$0aFd%(M;yqMr}5`p zpNiqb64P0&uwCXdor^>m5YPFD{s#pgFx4N#7A6zZgAs+SsSlwgzx&UzxyYxa*^3w+ zJvBXQ8gtv3@K{7)jwn=2Bkn6ywL;b=JYfp|;wQjrJ2lHbW@<&8{Pp<7M5soD&tuFK zrcM3@mgF~W5e4bH-^77CMPJ<&82%=u^>;G>9R8-uR9|F9zsW=tzG$lNLI17p7sZ_B z`>0O`++> zkDEH=fxe39RUuvbn&6X=j(wkO2*0UE^c$i-9nqgQ<@d5@j>Ou`kKP-LcW=DiFIK%V7UAzOIq==R6XK{E;R!PUd3TQ3sl#sl2Kpmk zkMOJ>@kkXt!oYuvzw+?O7(U$cTYMGYk1?HhJ{((MzWZ=&-l-WVI5Y6S#hn&-O0%OK z2jt)8A_^CX%YH~F#We-NDIJGfQi2acy86R{M@qO^I{CMw)Hff0Bo-T5Bh&sZrR$ry zG1&@r@gt`rYbFG*LOS}HqTu9R{kq_jkdFS^X&*m7@mngm1_6=yZ6jiUhf>4nxqa`7 zwIzPnrpYyH1{GnulcFZVDeUNPm*vekcA#n|zVY)f!p&Ulnlt-pnA(0c|j zz5FkQG8Q~;%3q`R|4l^|Oz{IOWFt0rd*Xk+D2p-OMkx3%m4zr`qz zG5wVwoXTd(f>SDgf>$72{i@)UZ`C&^{7Gy__eOr_lyaUn+ zx-KPn7o_%=dK4wxT#U7K{yrNe#i-wS*dLsh`2E0f6b4NS2P*UPNAYnub|}tWuUt1K z)|4uw;Ny^PiW7oUHq)OR!Qnaa`>7~Bf-~8n^=*Omo0N{Vy_NH39Jm{8Q1l~(>d6Y8 z()#xL^vy1f`+xGJWqva8W(I@`Y^prPK4S>2|0caU(R;F{0kSXj+OPTb9AkOk9DqWD<9(P#c`(*?-kWspOd?Fau5lz^fKm7QDd2QE4WXR+c#{9S{?=zq4R)P99l}Ri zU`=`CBdEy+OLsx7ncH;4?SQz;XuPMx3Sv)*NMNkl!!}JNg}lP<~D7F_vvY_)$p5e^{2X#^E;yyS@!$VmA({{0d%$bo{NK z7M$@M9CfKYhR^7gg`U*(hDlR*>4v7)4Vw7l$i`;NL|pH-+Oyg;zL8^8WmX4-%H9;< zkDKM(WO7!QwnDCDMhm@WG{2E!dd)&8uY%_wow=_Y9~p6z&ucmiGobN}95c)ygbHKw z@YgAuWpdWAwnO?Q@UhS@P9{!iU(`8kEb0ei`mdPygE+D#XN|wbQ3H3Q7g14F6BTTF{4nRAo!$J3^lqhyVHgk~H zc4#ASlp7OqB;M*lXuk#Wo3g;k_d_VZrVO4tF0@VSfVS>Qn;O`#T&;te-^4M!4nt_K z>5n4n`i$_SkUFb8_@PZ>!dIg9f{$xEyD7F-HE#Q&bwcBtY8W%WNeGpnkDFhA6sIH` zx}EeC%juXcoAj^(8=Z&fszIB60JTKaa)2L(80D zt-FO|#vFxc7PAc8DOx6N;(viQ?`{K5yUJU55ByNbSED?}w42a)s9)1~SgT2mZyCp! zex@Manz#AkU*IOf=6Bna7}v@;bfiCl-GnFeJ)x^< zyyOXKZP%T`82O!$iQ=Y2e|BCcWHs+`OuK%Fx6UhhLLRuY9^JUL3V)qpyuw@fRC(q! z=!BxCy+M<6=}}F0XH2o|dLPp~s#5`P&M>&zIH3wsrEKc(Z9ad0?8Id9gvi2n5pruCNS~@ZYPHBJkV~q9L6+@EMcfm-qjxv{eF$3hq8+k(WTXCKR zzB^1}Qu85R*EsAdvGOztTzY%DYmh4P9pX! zx2?mZ*SF)o%u_5EvueYcDvrnJC)+%2VpC|#MsPd;dKxK)q53tCQ{Mu3e|5}LPdn9Y z8`PTHCNV}e+lC>URI{z5^}7c~#t?XG3NX#e5Y8O238cYy+l{=f66G!nEtXFx92+ZavHZiIn2&4T?)m0b zHNJymrcr}%(zv)h@)_PVjtgCfbh7Cg6nskKVVH)-cW{g_F$xt%@HR-tzr@{}j4=U+ z=qZUohsJH-SW4qNIcDHAgbHjLm|$41mTcb0)OpD_rXPyDZOG#K*Fjbh_q9qXP+rAe!g2g^Z5;d1Z&BmD=FHFIN;h;{ z()2ElnSL2UrEiL##}e*hc=8npCtPpURKO2~eyf__#WC$_5X!IMlaQ`Iwg~m>5xj~q z@hOcl7Mf1BkX5cD>a%_sQGoQOZHn%5vQVp!*b$1$LT18gTcEd?{ zD*hba+dHWd^(uDLkdD7yIPQD_8&hvJ;NRA!dF%IWagAp=MjmfVLFnuYU%)Pe)g;Yy zop5O0GQ)*#J6+dz~yY49;ywYLq*`QY1zwW3GA zj9b$9t{lEd9WAw{D114>7X%;k9Ve4-8;>aDOal(OLkANPo&{pyn#R$7sV~7UYXdaE zH!H}rw!;Cx2)pnx%KXTBW{ajmzjguUcWC>IsE>T+cR{FlCjKn^?qHteGZ4-~tZEpK zd~Zqktmb**3_d(Bn%}Sa&~IMjIBzRIJ99{y&vH0nFUp#lOAl+hJ2!%jp>rotKk3m3 zT{P+E@Rz^F@TIG)Szgq}wOS9p$r5U(4hTJ=>76a63iGh1=TB<>qO#acL8_7p-hg!G zgj4<0xRbU2)lDvsS17@^t{O8%>e;kUPH8_#y8=GEDn2=_`JEhNDNoL59IaQU-@Z2C zbC4=;6aQP;K_!zX=e0F1;ykc@_M+_Mg63`Gojj=VKI$=>VF(?q41Y`PCVuj$wzCa) za#^;(lPg-GuQ>8$r{PboM(8n&8Mg+ZH$&`)A;Tn*#6qJKSxyXCd*N)(kV~*SKAW zcwXZddl)n00))y)@IgptCQ=`>@GH18Vb59O{^tttKr7DbIoha8fyenUD^}m(QI|6K zzKcr|tqR#JiwSMllNJ4%#_`bm@3Ht7*M**fZ04?^&9E2E!!F#5E}*$ivjo2Hk~R|a zlM6Z^n)qFi0`Az^>!t-=8pqzT!94AvEXZj75{?;%(^PRx?yIoNq=oN?bmH|eFWTib zjxrZ%cgcY8gOJLv;6+HsAMV1}VHa-P3rd;~^B>jtB^)!4F$fjMc>jRo^CdRVaemSW zuj2hfY(bxWc(Y(aI}3xGbU-4b`Aa#b^Bjb7ZW^!~+BqqF9@6n^ z??WU8G~QRlnEnbH5Az$;cyASB>K7qg|Mc53-(2%GOfIZgNh_hfi(hjmSJwQcfs}(0Hhy(s&Q`kX|y<0HL3>)|VS?=7fJlf#r3_WYUW≠z$ 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

    3GxaAWeRDSR)(0d3pBcQU}K z3?F8pGD^Tj8D>?^l{IejR5Whpcdn}OcSwi4&RhdlB@UV>%x-3LE$wKIk>?`wZ?2cl zb+mqMGw35;c!ly2XRfc=Hqt5vtkXxaMaz4dw|GwD<`UuYyvEI3 z9xrJ8oi^IkY3jV1$`F6VIbOyeViYgMLc%#-(fB)52nDKY9E-J!j;#N2jrj)b^@*J0 zP3>nE>+zPxF);DhFfewYJDRrx)BO{8PvdrA`WpW+#YKNkkh#9zN1PKe5Mp4=`TmKx z#*ZW@0s>8F{2AQtMn`yYpGa!FJ4#=FQ?hk>%6P z6FDtd?+0xfS92@jL_za^M**oIU*lF^ir`hWNnh6ZPh7^UunUfB4TR{iSqLZU8o$&< zn-VlMj*ITe*X^bH6K&0!WpkpVaeCAPUbANToakxZ;(d+V?hiC>PLNIlmc79veP!ga zmw8UcHUE<)+UV8E1kClr|$xK5@u&ddEv&dI5ujWeh{C$kVNl*rSL zDN0O*eoUybVw^ElKq+t*1yNaEb(o|9$h7Rp!A{`fV54E&2Weq>pg>oh0p z+Rx@|X#A(7qx#!03+3-<{rP^VFFGf?ny?8XE99rtMuJmh7D#X^23*XXIaNLt*SMLv zQxk*-f0!R#QZ%Q@r(CTytMXJryr*%x*cV{)%H@EQUtaU(PSmM_#?4izQ@+M+{*uPAdF7GEK9q5)qWPMKHs!Cu zEHnUh;A#MZD&jqC^EEYZ``gmExjJ{MJx@PUda9#oT%>CwY|(bFr+J&MuW@tR^3*`% zX1-4YmgU!|EOhsD9OnA&-s_y6&<;G|&S_WU_yw0_1>t#9RI@)kXPy7}4Ricr8uHSD3GAe$5|)KKSCh z4d$B>-r$jWez(K=ZbTnmT}B;|iG6o4)IUl_)VF43h!>qlWB5ZXz@JTog!8BiD;!q; zE8_`RsZTMUhL!qDj8DNzeU|YY>5KS}&*74^WH6GC=3%5mf$#>A(6=g*q>kBA10aF`r0-h?#{`15BS#@nz`{{`d3OMRd5Uf|Km+@sVM z{Clw>pC=>ZB^f7P>RrYsf+phKlc%=iQ_PdUi1*Mt^Kanw$?s*Drty$;mT}@`xE$ko ztxxtDFGTb{O58jF7-5UR96#5=H0JI2+xI|DFYYr?s%E~DiM8^@kWq;3$xga&@HCBurl0j zjQ3z=c{DC4`)mwG=>LM_oQ-S!`xC5B4)qV4t@1Cp-m|HQLz*43LkFwJrL-z`WAEpf z_app$jF(_V!SB;JQNcABS#XT;I;_+;7;gve6>QaKI}yIid>>ZC`*VsUedY(6zdiULZ)27I zDn6v2a3l0t#uKn&5Pp?pd`jz={~P0(h(61BE}|cPmKU8T@(~B09m)|03V>O8f(Azx zRAsylD`sW6%XkA;>RXI=U>AJ@|M9ec?O&Ma!b*qU5Py=4Nbt2wLGm5U$_H`g6G0!_ zO>p!b{Fc=RDF!nUC*F9T%mNolKJZwd*ZK*(x&ldxAC#D{M0n}|M&-#WjEq-fya6kU zo*YW-b4;~uQk=NYHMWd1cFey>yT@rQIMhlEq8zzT{awEeyr1H{ z=_BKp)%?mr&;(!n$YXzB^DFv{)4l+b0wXxEk>c9y7zpIA$z0Olz z{2>$cLc%#uMmnT|_`4|h<2dt?4&UiBo`em_`M?I$wnmqC2{16JCRnMbsH@1zkEjKHrY;9p-BKp5!JPZ3Jab2U~F;RdO32ys0#(h}X zgA(IaSgGgF(r2h6QeS6%Tj;-xza4y$`+aO*jSdS2LO^_FzK-SkX>3S8I}xF?jJvQR z-={Pn82M+@Frq$({0X0ek$M^^!t*dff7=%!UUZ%<;1B6QZE~o>NQb8xj|{-4)Fyos zM(CIRk?|I+jNf6rM|v?+OHH7D#9=UWD8|VF|9H(V-N*O@tVr;g%XkV_>c7r-8rJCP z3e;y)Ohkt0)(YbV;Xr!Qp~uA%j7V@Rufbv&xJiINKjV%S@y0s(FfUSD@=dfUUIRwN zi}NvO^kng~4(r=N6Y+{gYRh<2IItAJ@S8^W5R=#3C=Q3ymf%yXS@I_ z^kY2YKJijtVSQQaZ@B^OA`Jxzq(hw@YT9A!HO7gT`WE9&SXmISai4gp@1jk4JCt8K ztYm@&(qX`OA6DqU@(0F=7y2*aL;PE@i2iBDi681|6CN4)B0>L;Ip1<&WP*>-CY*Sg zAkBCRR_bqNoOr3vGM<5z`o9VDBLNAdL!KRS+TrFm87E%qON{%lBEil7g>mAgzRGy9 zfO#)+5uHsdX=AN_)H;-N2^9pV=~Cc3a9!RQ|uCtf7@M}lc; z1~5{;afn|aBlQ!E$6>GOizB0#m>_|4NHR|Ln#0JFe`P!s(N8g+(fZNb7|%xZIl^xk zb1vX50d(wlp%4+2NC3VJBMW$k@d~UgxW+hHp}+B87_Ue4EykO$a!(k$fe8}G1YO2E zup+?{UNaYnm-+$g`&xe!wW(voTm8)=BfpLhiHmrZ5RN{I7pZLpBO~{54=*Nwivn)S zvtLr{f1PGL11t2?CB{8i8J{|a!Y=wSazv)n0Ei&R#rVgc;v*A`mtjSqUsId(br_M@ zJi2cWV`G2W3~>;V^r{sv9bhueVA z-xLSDiHI2fkPh7AOD=HX5c>w&q))&|eTs2B!SPE>>7`7B&oZBb74dE~e))*rXMIWQ z|Lk{+mtkf8D&u73l-_ihi5jeQXfob_6$MRK7;nK!eTQ+fLT{$}QdjCRrN8O116dKs zO!cL{#@D1+KhXF?R5(Wba!lhU{^hvF_cYL^DZMkMX=+x5qP$w_u4^Uni@K+h({bUj3+f7D>F{K zEXZRVtMX%PTq{T?d7t@u;DKMiq8;Ju%+q8Fzpqw?_+4Zq&icFX1Ows~?@C7aE;)>i z-!-N2WdsxM!H9UvT(k)U4(RQW=L$R&VM%gz>?p#!{*}Ow!gDw zJedA$^p2(1ppd#@=68Yr89Yz*!}g+WQ$dqlSB1xZBR8)4D5x$O8xL;z9L~ck2n@yV zUBK`2y0P1Xy`PWXzGPK51V`?|cj-Sz#P$BLeH$X8z4$+;o*#TZihnm>9enL&Z*s4WK*FKQEfAzW9bEnUqd+6DRQV%58T%G-RY;IBf$myBclSl5Kee}_@XU;x8 slfU}kJ{eoR*oEFr>|eK9(A!{7eDzd!x|0oNFpSpWb4 delta 239140 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

    1+DUw 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

      y-9Da1czen-Si=?Llt)nmQd>w}rU+w~@{8Wd? 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 CS|0oW diff --git a/roms/SLOF b/roms/SLOF index 8e012d6fdd..e18ddad851 160000 --- a/roms/SLOF +++ b/roms/SLOF @@ -1 +1 @@ -Subproject commit 8e012d6fddb62be833d746cef3f03e6c8beecde0 +Subproject commit e18ddad8516ff2cfe36ec130200318f7251aa78c From d69cda7ed722e445d03e1ace6563bab3a76e023e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 17 Jul 2020 16:25:08 +0100 Subject: [PATCH 2404/2595] Makefile: Remove config-devices.mak on "make clean" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The config-devices.mak files are generated by "make", and so they should be deleted by "make clean". (This is different from config-host.mak and config-all-disas.mak, which are created by "configure" and so only deleted by "make distclean".) If we don't delete these files on "make clean", then the build tree is left in a state where it has the config-devices.mak file but not the config-devices.mak.d file, and make will not realize that it needs to rebuild config-devices.mak if, for instance, hw/sd/Kconfig changes. NB: config-all-devices.mak is also generated by "make", but we already remove it on "make clean". Suggested-by: Paolo Bonzini Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200717152508.10272-1-peter.maydell@linaro.org --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 32345c610e..c2120d8d48 100644 --- a/Makefile +++ b/Makefile @@ -775,6 +775,7 @@ clean: recurse-clean rm -f storage-daemon/qapi/qapi-gen-timestamp rm -rf qga/qapi-generated rm -f config-all-devices.mak + rm -f $(SUBDIR_DEVICES_MAK) VERSION ?= $(shell cat VERSION) From 6f4e1405b91da0d0a1084ae3aff2bd308432778f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jul 2020 10:25:36 +0100 Subject: [PATCH 2405/2595] hw/arm/virt: Enable MTE via a machine property Control this cpu feature via a machine property, much as we do with secure=on, since both require specialized support in the machine setup to be functional. Default MTE to off, since this feature implies extra overhead. Signed-off-by: Richard Henderson Message-id: 20200713213341.590275-2-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 39 ++++++++++++++++++++++++++++++++++----- include/hw/arm/virt.h | 1 + target/arm/cpu.c | 19 +++++++++++-------- target/arm/cpu64.c | 5 +++-- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 9005dae356..5866c4ce20 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1837,12 +1837,19 @@ static void machvirt_init(MachineState *machine) OBJECT(secure_sysmem), &error_abort); } - /* - * The cpu adds the property if and only if MemTag is supported. - * If it is, we must allocate the ram to back that up. - */ - if (object_property_find(cpuobj, "tag-memory", NULL)) { + if (vms->mte) { + /* Create the memory region only once, but link to all cpus. */ if (!tag_sysmem) { + /* + * The property exists only if MemTag is supported. + * If it is, we must allocate the ram to back that up. + */ + if (!object_property_find(cpuobj, "tag-memory", NULL)) { + error_report("MTE requested, but not supported " + "by the guest CPU"); + exit(1); + } + tag_sysmem = g_new(MemoryRegion, 1); memory_region_init(tag_sysmem, OBJECT(machine), "tag-memory", UINT64_MAX / 32); @@ -2061,6 +2068,20 @@ static void virt_set_ras(Object *obj, bool value, Error **errp) vms->ras = value; } +static bool virt_get_mte(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->mte; +} + +static void virt_set_mte(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->mte = value; +} + static char *virt_get_gic_version(Object *obj, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -2481,6 +2502,14 @@ static void virt_instance_init(Object *obj) "Set on/off to enable/disable reporting host memory errors " "to a KVM guest using ACPI and guest external abort exceptions"); + /* MTE is disabled by default. */ + vms->mte = false; + object_property_add_bool(obj, "mte", virt_get_mte, virt_set_mte); + object_property_set_description(obj, "mte", + "Set on/off to enable/disable emulating a " + "guest CPU which implements the ARM " + "Memory Tagging Extension"); + vms->irqmap = a15irqmap; virt_flash_create(vms); diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 54bcf17afd..dff67e1bef 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -140,6 +140,7 @@ typedef struct { bool its; bool virt; bool ras; + bool mte; OnOffAuto acpi; VirtGICType gic_version; VirtIOMMUType iommu; diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 5050e1843a..111579554f 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1698,6 +1698,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) cpu->id_pfr1 &= ~0xf000; } +#ifndef CONFIG_USER_ONLY + if (cpu->tag_memory == NULL && cpu_isar_feature(aa64_mte, cpu)) { + /* + * Disable the MTE feature bits if we do not have tag-memory + * provided by the machine. + */ + cpu->isar.id_aa64pfr1 = + FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 0); + } +#endif + /* MPU can be configured out of a PMSA CPU either by setting has-mpu * to false or by setting pmsav7-dregion to 0. */ @@ -1787,14 +1798,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) cpu_address_space_init(cs, ARMASIdx_TagS, "cpu-tag-memory", cpu->secure_tag_memory); } - } else if (cpu_isar_feature(aa64_mte, cpu)) { - /* - * Since there is no tag memory, we can't meaningfully support MTE - * to its fullest. To avoid problems later, when we would come to - * use the tag memory, downgrade support to insns only. - */ - cpu->isar.id_aa64pfr1 = - FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 1); } cpu_address_space_init(cs, ARMASIdx_NS, "cpu-memory", cs->memory); diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 15494002d2..dd696183df 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -646,8 +646,9 @@ static void aarch64_max_initfn(Object *obj) t = cpu->isar.id_aa64pfr1; t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); /* - * Begin with full support for MTE; will be downgraded to MTE=1 - * during realize if the board provides no tag memory. + * Begin with full support for MTE. This will be downgraded to MTE=0 + * during realize if the board provides no tag memory, much like + * we do for EL2 with the virtualization=on property. */ t = FIELD_DP64(t, ID_AA64PFR1, MTE, 2); cpu->isar.id_aa64pfr1 = t; From 7f6185ed9ca977a9836f35b994e4f85cecae8437 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jul 2020 10:25:36 +0100 Subject: [PATCH 2406/2595] hw/arm/virt: Error for MTE enabled with KVM While we expect KVM to support MTE at some future point, it certainly won't be ready in time for qemu 5.1. Signed-off-by: Richard Henderson Message-id: 20200713213341.590275-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 5866c4ce20..a7f3d442db 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1773,6 +1773,12 @@ static void machvirt_init(MachineState *machine) exit(1); } + if (vms->mte && kvm_enabled()) { + error_report("mach-virt: KVM does not support providing " + "MTE to the guest CPU"); + exit(1); + } + create_fdt(vms); possible_cpus = mc->possible_cpu_arch_ids(machine); From 19bd6aafbd184be963d2b7c24874e3252a7088b7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jul 2020 10:25:36 +0100 Subject: [PATCH 2407/2595] hw/arm/virt: Disable memory hotplug when MTE is enabled When MTE is enabled, tag memory must exist for all RAM. It might be possible to simultaneously hot plug tag memory alongside the corresponding normal memory, but for now just disable hotplug. Signed-off-by: Richard Henderson Message-id: 20200713213341.590275-4-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index a7f3d442db..ecfee362a1 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2194,6 +2194,11 @@ static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } + if (vms->mte) { + error_setg(errp, "memory hotplug is not enabled: MTE is enabled"); + return; + } + if (is_nvdimm && !ms->nvdimms_state->is_enabled) { error_setg(errp, "nvdimm is not enabled: add 'nvdimm=on' to '-M'"); return; From 8edbca515c20bdbb3d2dca3c60dcc5b8ca4fc718 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 20 Jul 2020 10:25:36 +0100 Subject: [PATCH 2408/2595] util: Implement qemu_get_thread_id() for OpenBSD Implement qemu_get_thread_id() for OpenBSD hosts, using getthrid(). Signed-off-by: David Carlier Reviewed-by: Brad Smith Message-id: CA+XhMqxD6gQDBaj8tX0CMEj3si7qYKsM8u1km47e_-U7MC37Pg@mail.gmail.com Reviewed-by: Peter Maydell [PMM: tidied up commit message] Signed-off-by: Peter Maydell --- util/oslib-posix.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 36bf8593f8..d923674624 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -100,6 +100,8 @@ int qemu_get_thread_id(void) return (int)tid; #elif defined(__NetBSD__) return _lwp_self(); +#elif defined(__OpenBSD__) + return getthrid(); #else return getpid(); #endif From b51238e251cefb496b60d3db992af175fb354a68 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sat, 11 Jul 2020 15:24:23 +0100 Subject: [PATCH 2409/2595] qdev: Move doc comments from qdev.c to qdev-core.h The doc-comments which document the qdev API are split between the header file and the C source files, because as a project we haven't been consistent about where we put them. Move all the doc-comments in qdev.c to the header files, so that users of the APIs don't have to look at the implementation files for this information. In the process, unify them into our doc-comment format and expand on them in some cases to clarify expected use cases. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200711142425.16283-2-peter.maydell@linaro.org --- hw/core/qdev.c | 33 --------------------- include/hw/qdev-core.h | 57 ++++++++++++++++++++++++++++++++++++ include/hw/qdev-properties.h | 13 ++++++++ 3 files changed, 70 insertions(+), 33 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 01796823b4..96772a15bd 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -128,13 +128,6 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus) } } -/* - * Create a device on the heap. - * A type @name must exist. - * This only initializes the device state structure and allows - * properties to be set. The device still needs to be realized. See - * qdev-core.h. - */ DeviceState *qdev_new(const char *name) { if (!object_class_by_name(name)) { @@ -143,11 +136,6 @@ DeviceState *qdev_new(const char *name) return DEVICE(object_new(name)); } -/* - * Try to create a device on the heap. - * This is like qdev_new(), except it returns %NULL when type @name - * does not exist. - */ DeviceState *qdev_try_new(const char *name) { if (!module_object_class_by_name(name)) { @@ -378,14 +366,6 @@ void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, qdev_unrealize(dev); } -/* - * Realize @dev. - * @dev must not be plugged into a bus. - * If @bus, plug @dev into @bus. This takes a reference to @dev. - * If @dev has no QOM parent, make one up, taking another reference. - * On success, return true. - * On failure, store an error through @errp and return false. - */ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) { assert(!dev->realized && !dev->parent_bus); @@ -399,16 +379,6 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) return object_property_set_bool(OBJECT(dev), "realized", true, errp); } -/* - * Realize @dev and drop a reference. - * This is like qdev_realize(), except the caller must hold a - * (private) reference, which is dropped on return regardless of - * success or failure. Intended use: - * dev = qdev_new(); - * [...] - * qdev_realize_and_unref(dev, bus, errp); - * Now @dev can go away without further ado. - */ bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp) { bool ret; @@ -814,9 +784,6 @@ static void qdev_class_add_property(DeviceClass *klass, Property *prop) prop->info->description); } -/* @qdev_alias_all_properties - Add alias properties to the source object for - * all qdev properties on the target DeviceState. - */ void qdev_alias_all_properties(DeviceState *target, Object *source) { ObjectClass *class; diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index fe78073c70..2d441d1fb2 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -320,9 +320,66 @@ compat_props_add(GPtrArray *arr, /*** Board API. This should go away once we have a machine config file. ***/ +/** + * qdev_new: Create a device on the heap + * @name: device type to create (we assert() that this type exists) + * + * This only allocates the memory and initializes the device state + * structure, ready for the caller to set properties if they wish. + * The device still needs to be realized. + * The returned object has a reference count of 1. + */ DeviceState *qdev_new(const char *name); +/** + * qdev_try_new: Try to create a device on the heap + * @name: device type to create + * + * This is like qdev_new(), except it returns %NULL when type @name + * does not exist, rather than asserting. + */ DeviceState *qdev_try_new(const char *name); +/** + * qdev_realize: Realize @dev. + * @dev: device to realize + * @bus: bus to plug it into (may be NULL) + * @errp: pointer to error object + * + * "Realize" the device, i.e. perform the second phase of device + * initialization. + * @dev must not be plugged into a bus already. + * If @bus, plug @dev into @bus. This takes a reference to @dev. + * If @dev has no QOM parent, make one up, taking another reference. + * On success, return true. + * On failure, store an error through @errp and return false. + * + * If you created @dev using qdev_new(), you probably want to use + * qdev_realize_and_unref() instead. + */ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp); +/** + * qdev_realize_and_unref: Realize @dev and drop a reference + * @dev: device to realize + * @bus: bus to plug it into (may be NULL) + * @errp: pointer to error object + * + * Realize @dev and drop a reference. + * This is like qdev_realize(), except the caller must hold a + * (private) reference, which is dropped on return regardless of + * success or failure. Intended use:: + * + * dev = qdev_new(); + * [...] + * qdev_realize_and_unref(dev, bus, errp); + * + * Now @dev can go away without further ado. + * + * If you are embedding the device into some other QOM device and + * initialized it via some variant on object_initialize_child() then + * do not use this function, because that family of functions arrange + * for the only reference to the child device to be held by the parent + * via the child<> property, and so the reference-count-drop done here + * would be incorrect. For that use case you want qdev_realize(). + */ bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp); void qdev_unrealize(DeviceState *dev); void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 587e5b7d31..8f3a98cba6 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -282,6 +282,19 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, */ void qdev_property_add_static(DeviceState *dev, Property *prop); +/** + * qdev_alias_all_properties: Create aliases on source for all target properties + * @target: Device which has properties to be aliased + * @source: Object to add alias properties to + * + * Add alias properties to the @source object for all qdev properties on + * the @target DeviceState. + * + * This is useful when @target is an internal implementation object + * owned by @source, and you want to expose all the properties of that + * implementation object as properties on the @source object so that users + * of @source can set them. + */ void qdev_alias_all_properties(DeviceState *target, Object *source); /** From 46ea1be1ee72b778043e60c8a59cbcb53fb8be34 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sat, 11 Jul 2020 15:24:24 +0100 Subject: [PATCH 2410/2595] qdev: Document qdev_unrealize() Add a doc comment for qdev_unrealize(), to go with the new documentation for the realize part of the qdev lifecycle. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200711142425.16283-3-peter.maydell@linaro.org --- include/hw/qdev-core.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 2d441d1fb2..1d2bf5f37d 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -381,6 +381,25 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp); * would be incorrect. For that use case you want qdev_realize(). */ bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp); +/** + * qdev_unrealize: Unrealize a device + * @dev: device to unrealize + * + * This function will "unrealize" a device, which is the first phase + * of correctly destroying a device that has been realized. It will: + * + * - unrealize any child buses by calling qbus_unrealize() + * (this will recursively unrealize any devices on those buses) + * - call the the unrealize method of @dev + * + * The device can then be freed by causing its reference count to go + * to zero. + * + * Warning: most devices in QEMU do not expect to be unrealized. Only + * devices which are hot-unpluggable should be unrealized (as part of + * the unplugging process); all other devices are expected to last for + * the life of the simulation and should not be unrealized and freed. + */ void qdev_unrealize(DeviceState *dev); void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, int required_for_version); From cd07d7f9f5117954edd9a9bbd97b0442eecf5c49 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sat, 11 Jul 2020 15:24:25 +0100 Subject: [PATCH 2411/2595] qdev: Document GPIO related functions Add documentation comments for the various qdev functions related to creating and connecting GPIO lines. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200711142425.16283-4-peter.maydell@linaro.org --- include/hw/qdev-core.h | 191 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 189 insertions(+), 2 deletions(-) diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 1d2bf5f37d..ea3f73a282 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -424,13 +424,132 @@ void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, void qdev_machine_creation_done(void); bool qdev_machine_modified(void); +/** + * qdev_get_gpio_in: Get one of a device's anonymous input GPIO lines + * @dev: Device whose GPIO we want + * @n: Number of the anonymous GPIO line (which must be in range) + * + * Returns the qemu_irq corresponding to an anonymous input GPIO line + * (which the device has set up with qdev_init_gpio_in()). The index + * @n of the GPIO line must be valid (i.e. be at least 0 and less than + * the total number of anonymous input GPIOs the device has); this + * function will assert() if passed an invalid index. + * + * This function is intended to be used by board code or SoC "container" + * device models to wire up the GPIO lines; usually the return value + * will be passed to qdev_connect_gpio_out() or a similar function to + * connect another device's output GPIO line to this input. + * + * For named input GPIO lines, use qdev_get_gpio_in_named(). + */ qemu_irq qdev_get_gpio_in(DeviceState *dev, int n); +/** + * qdev_get_gpio_in_named: Get one of a device's named input GPIO lines + * @dev: Device whose GPIO we want + * @name: Name of the input GPIO array + * @n: Number of the GPIO line in that array (which must be in range) + * + * Returns the qemu_irq corresponding to a named input GPIO line + * (which the device has set up with qdev_init_gpio_in_named()). + * The @name string must correspond to an input GPIO array which exists on + * the device, and the index @n of the GPIO line must be valid (i.e. + * be at least 0 and less than the total number of input GPIOs in that + * array); this function will assert() if passed an invalid name or index. + * + * For anonymous input GPIO lines, use qdev_get_gpio_in(). + */ qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n); +/** + * qdev_connect_gpio_out: Connect one of a device's anonymous output GPIO lines + * @dev: Device whose GPIO to connect + * @n: Number of the anonymous output GPIO line (which must be in range) + * @pin: qemu_irq to connect the output line to + * + * This function connects an anonymous output GPIO line on a device + * up to an arbitrary qemu_irq, so that when the device asserts that + * output GPIO line, the qemu_irq's callback is invoked. + * The index @n of the GPIO line must be valid (i.e. be at least 0 and + * less than the total number of anonymous output GPIOs the device has + * created with qdev_init_gpio_out()); otherwise this function will assert(). + * + * Outbound GPIO lines can be connected to any qemu_irq, but the common + * case is connecting them to another device's inbound GPIO line, using + * the qemu_irq returned by qdev_get_gpio_in() or qdev_get_gpio_in_named(). + * + * It is not valid to try to connect one outbound GPIO to multiple + * qemu_irqs at once, or to connect multiple outbound GPIOs to the + * same qemu_irq. (Warning: there is no assertion or other guard to + * catch this error: the model will just not do the right thing.) + * Instead, for fan-out you can use the TYPE_IRQ_SPLIT device: connect + * a device's outbound GPIO to the splitter's input, and connect each + * of the splitter's outputs to a different device. For fan-in you + * can use the TYPE_OR_IRQ device, which is a model of a logical OR + * gate with multiple inputs and one output. + * + * For named output GPIO lines, use qdev_connect_gpio_out_named(). + */ void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin); +/** + * qdev_connect_gpio_out: Connect one of a device's anonymous output GPIO lines + * @dev: Device whose GPIO to connect + * @name: Name of the output GPIO array + * @n: Number of the anonymous output GPIO line (which must be in range) + * @pin: qemu_irq to connect the output line to + * + * This function connects an anonymous output GPIO line on a device + * up to an arbitrary qemu_irq, so that when the device asserts that + * output GPIO line, the qemu_irq's callback is invoked. + * The @name string must correspond to an output GPIO array which exists on + * the device, and the index @n of the GPIO line must be valid (i.e. + * be at least 0 and less than the total number of input GPIOs in that + * array); this function will assert() if passed an invalid name or index. + * + * Outbound GPIO lines can be connected to any qemu_irq, but the common + * case is connecting them to another device's inbound GPIO line, using + * the qemu_irq returned by qdev_get_gpio_in() or qdev_get_gpio_in_named(). + * + * It is not valid to try to connect one outbound GPIO to multiple + * qemu_irqs at once, or to connect multiple outbound GPIOs to the + * same qemu_irq; see qdev_connect_gpio_out() for details. + * + * For named output GPIO lines, use qdev_connect_gpio_out_named(). + */ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, qemu_irq pin); +/** + * qdev_get_gpio_out_connector: Get the qemu_irq connected to an output GPIO + * @dev: Device whose output GPIO we are interested in + * @name: Name of the output GPIO array + * @n: Number of the output GPIO line within that array + * + * Returns whatever qemu_irq is currently connected to the specified + * output GPIO line of @dev. This will be NULL if the output GPIO line + * has never been wired up to the anything. Note that the qemu_irq + * returned does not belong to @dev -- it will be the input GPIO or + * IRQ of whichever device the board code has connected up to @dev's + * output GPIO. + * + * You probably don't need to use this function -- it is used only + * by the platform-bus subsystem. + */ qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n); +/** + * qdev_intercept_gpio_out: Intercept an existing GPIO connection + * @dev: Device to intercept the outbound GPIO line from + * @icpt: New qemu_irq to connect instead + * @name: Name of the output GPIO array + * @n: Number of the GPIO line in the array + * + * This function is provided only for use by the qtest testing framework + * and is not suitable for use in non-testing parts of QEMU. + * + * This function breaks an existing connection of an outbound GPIO + * line from @dev, and replaces it with the new qemu_irq @icpt, as if + * ``qdev_connect_gpio_out_named(dev, icpt, name, n)`` had been called. + * The previously connected qemu_irq is returned, so it can be restored + * by a second call to qdev_intercept_gpio_out() if desired. + */ qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt, const char *name, int n); @@ -438,10 +557,59 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name); /*** Device API. ***/ -/* Register device properties. */ -/* GPIO inputs also double as IRQ sinks. */ +/** + * qdev_init_gpio_in: create an array of anonymous input GPIO lines + * @dev: Device to create input GPIOs for + * @handler: Function to call when GPIO line value is set + * @n: Number of GPIO lines to create + * + * Devices should use functions in the qdev_init_gpio_in* family in + * their instance_init or realize methods to create any input GPIO + * lines they need. There is no functional difference between + * anonymous and named GPIO lines. Stylistically, named GPIOs are + * preferable (easier to understand at callsites) unless a device + * has exactly one uniform kind of GPIO input whose purpose is obvious. + * Note that input GPIO lines can serve as 'sinks' for IRQ lines. + * + * See qdev_get_gpio_in() for how code that uses such a device can get + * hold of an input GPIO line to manipulate it. + */ void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n); +/** + * qdev_init_gpio_out: create an array of anonymous output GPIO lines + * @dev: Device to create output GPIOs for + * @pins: Pointer to qemu_irq or qemu_irq array for the GPIO lines + * @n: Number of GPIO lines to create + * + * Devices should use functions in the qdev_init_gpio_out* family + * in their instance_init or realize methods to create any output + * GPIO lines they need. There is no functional difference between + * anonymous and named GPIO lines. Stylistically, named GPIOs are + * preferable (easier to understand at callsites) unless a device + * has exactly one uniform kind of GPIO output whose purpose is obvious. + * + * The @pins argument should be a pointer to either a "qemu_irq" + * (if @n == 1) or a "qemu_irq []" array (if @n > 1) in the device's + * state structure. The device implementation can then raise and + * lower the GPIO line by calling qemu_set_irq(). (If anything is + * connected to the other end of the GPIO this will cause the handler + * function for that input GPIO to be called.) + * + * See qdev_connect_gpio_out() for how code that uses such a device + * can connect to one of its output GPIO lines. + */ void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n); +/** + * qdev_init_gpio_out: create an array of named output GPIO lines + * @dev: Device to create output GPIOs for + * @pins: Pointer to qemu_irq or qemu_irq array for the GPIO lines + * @name: Name to give this array of GPIO lines + * @n: Number of GPIO lines to create + * + * Like qdev_init_gpio_out(), but creates an array of GPIO output lines + * with a name. Code using the device can then connect these GPIO lines + * using qdev_connect_gpio_out_named(). + */ void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins, const char *name, int n); /** @@ -473,6 +641,25 @@ static inline void qdev_init_gpio_in_named(DeviceState *dev, qdev_init_gpio_in_named_with_opaque(dev, handler, dev, name, n); } +/** + * qdev_pass_gpios: create GPIO lines on container which pass through to device + * @dev: Device which has GPIO lines + * @container: Container device which needs to expose them + * @name: Name of GPIO array to pass through (NULL for the anonymous GPIO array) + * + * In QEMU, complicated devices like SoCs are often modelled with a + * "container" QOM device which itself contains other QOM devices and + * which wires them up appropriately. This function allows the container + * to create GPIO arrays on itself which simply pass through to a GPIO + * array of one of its internal devices. + * + * If @dev has both input and output GPIOs named @name then both will + * be passed through. It is not possible to pass a subset of the array + * with this function. + * + * To users of the container device, the GPIO array created on @container + * behaves exactly like any other. + */ void qdev_pass_gpios(DeviceState *dev, DeviceState *container, const char *name); From 3f410039b79c0468e18142c6ddfede6f6f7b0427 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 13 Jul 2020 15:37:16 +0100 Subject: [PATCH 2412/2595] hw/arm/armsse: Assert info->num_cpus is in-bounds in armsse_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In armsse_realize() we have a loop over [0, info->num_cpus), which indexes into various fixed-size arrays in the ARMSSE struct. This confuses Coverity, which warns that we might overrun those arrays (CID 1430326, 1430337, 1430371, 1430414, 1430430). This can't actually happen, because the info struct is always one of the entries in the armsse_variants[] array and num_cpus is either 1 or 2; we also already assert in armsse_init() that num_cpus is not too large. However, adding an assert to armsse_realize() like the one in armsse_init() should help Coverity figure out that these code paths aren't possible. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200713143716.9881-1-peter.maydell@linaro.org --- hw/arm/armsse.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 64fcab895f..dcbff9bd8f 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -452,6 +452,8 @@ static void armsse_realize(DeviceState *dev, Error **errp) return; } + assert(info->num_cpus <= SSE_MAX_CPUS); + /* max SRAM_ADDR_WIDTH: 24 - log2(SRAM_NUM_BANK) */ assert(is_power_of_2(info->sram_banks)); addr_width_max = 24 - ctz32(info->sram_banks); From 2d21dd17c560a574e19ba94d07173924bf74571b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 13 Jul 2020 18:57:43 +0100 Subject: [PATCH 2413/2595] docs/system: Briefly document canon-a1100 board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add skeletal documentation of the canon-a1100 board. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-id: 20200713175746.5936-2-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/digic.rst | 11 +++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 13 insertions(+) create mode 100644 docs/system/arm/digic.rst diff --git a/MAINTAINERS b/MAINTAINERS index 5d9c56e441..9ed36dcf73 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -636,6 +636,7 @@ F: include/hw/arm/digic.h F: hw/*/digic* F: include/hw/*/digic* F: tests/acceptance/machine_arm_canona1100.py +F: docs/system/arm/digic.rst Goldfish RTC M: Anup Patel diff --git a/docs/system/arm/digic.rst b/docs/system/arm/digic.rst new file mode 100644 index 0000000000..2b3520ff5e --- /dev/null +++ b/docs/system/arm/digic.rst @@ -0,0 +1,11 @@ +Canon A1100 (``canon-a1100``) +============================= + +This machine is a model of the Canon PowerShot A1100 camera, which +uses the DIGIC SoC. This model is based on reverse engineering efforts +by the contributors to the `CHDK `_ and +`Magic Lantern `_ projects. + +The emulation is incomplete. In particular it can't be used +to run the original camera firmware, but it can successfully run +an experimental version of the `barebox bootloader `_. diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index 1bd477a293..8fa51a2281 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -82,6 +82,7 @@ undocumented; you can get a complete list by running arm/versatile arm/vexpress arm/aspeed + arm/digic arm/musicpal arm/nseries arm/orangepi From b76b60f59bb95f9184bb70ea62f3db7b65730478 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 13 Jul 2020 18:57:44 +0100 Subject: [PATCH 2414/2595] docs/system: Briefly document collie board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add skeletal documentation of the collie board. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-id: 20200713175746.5936-3-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/collie.rst | 16 ++++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 18 insertions(+) create mode 100644 docs/system/arm/collie.rst diff --git a/MAINTAINERS b/MAINTAINERS index 9ed36dcf73..6973b68975 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -847,6 +847,7 @@ L: qemu-arm@nongnu.org S: Odd Fixes F: hw/arm/collie.c F: hw/arm/strongarm* +F: docs/system/arm/collie.rst Stellaris M: Peter Maydell diff --git a/docs/system/arm/collie.rst b/docs/system/arm/collie.rst new file mode 100644 index 0000000000..5cc67b6d1b --- /dev/null +++ b/docs/system/arm/collie.rst @@ -0,0 +1,16 @@ +Sharp Zaurus SL-5500 (``collie``) +================================= + +This machine is a model of the Sharp Zaurus SL-5500, which was +a 1990s PDA based on the StrongARM SA1110. + +Implemented devices: + + * NOR flash + * Interrupt controller + * Timer + * RTC + * GPIO + * Peripheral Pin Controller (PPC) + * UARTs + * Synchronous Serial Ports (SSP) diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index 8fa51a2281..376c18f0b1 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -88,6 +88,7 @@ undocumented; you can get a complete list by running arm/orangepi arm/palm arm/xscale + arm/collie arm/sx1 arm/stellaris From bb309000c818b4ff4763ebc38b1c4bfae56ddf37 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 13 Jul 2020 18:57:45 +0100 Subject: [PATCH 2415/2595] docs/system: Briefly document gumstix boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add skeletal documentation of the gumstix boards ('connex' and 'verdex'). Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-id: 20200713175746.5936-4-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/gumstix.rst | 21 +++++++++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 23 insertions(+) create mode 100644 docs/system/arm/gumstix.rst diff --git a/MAINTAINERS b/MAINTAINERS index 6973b68975..935ccb3ab3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -652,6 +652,7 @@ R: Philippe Mathieu-Daudé L: qemu-arm@nongnu.org S: Odd Fixes F: hw/arm/gumstix.c +F: docs/system/arm/gumstix.rst i.MX25 PDK M: Peter Maydell diff --git a/docs/system/arm/gumstix.rst b/docs/system/arm/gumstix.rst new file mode 100644 index 0000000000..cb373139dc --- /dev/null +++ b/docs/system/arm/gumstix.rst @@ -0,0 +1,21 @@ +Gumstix Connex and Verdex (``connex``, ``verdex``) +================================================== + +These machines model the Gumstix Connex and Verdex boards. +The Connex has a PXA255 CPU and the Verdex has a PXA270. + +Implemented devices: + + * NOR flash + * SMC91C111 ethernet + * Interrupt controller + * DMA + * Timer + * GPIO + * MMC/SD card + * Fast infra-red communications port (FIR) + * LCD controller + * Synchronous serial ports (SPI) + * PCMCIA interface + * I2C + * I2S diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index 376c18f0b1..163ab91559 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -84,6 +84,7 @@ undocumented; you can get a complete list by running arm/aspeed arm/digic arm/musicpal + arm/gumstix arm/nseries arm/orangepi arm/palm From 6a0b7505f1fd6769c3f1558fda76464d51e4118a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 13 Jul 2020 18:57:46 +0100 Subject: [PATCH 2416/2595] docs/system: Document the arm virt board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the arm 'virt' board, which has been undocumented for far too long given that it is the main recommended board type for arm guests. Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Message-id: 20200713175746.5936-5-peter.maydell@linaro.org --- MAINTAINERS | 1 + docs/system/arm/virt.rst | 161 +++++++++++++++++++++++++++++++++++++ docs/system/target-arm.rst | 1 + 3 files changed, 163 insertions(+) create mode 100644 docs/system/arm/virt.rst diff --git a/MAINTAINERS b/MAINTAINERS index 935ccb3ab3..5e8616821a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -880,6 +880,7 @@ L: qemu-arm@nongnu.org S: Maintained F: hw/arm/virt* F: include/hw/arm/virt.h +F: docs/system/arm/virt.rst Xilinx Zynq M: Edgar E. Iglesias diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst new file mode 100644 index 0000000000..6621ab7205 --- /dev/null +++ b/docs/system/arm/virt.rst @@ -0,0 +1,161 @@ +'virt' generic virtual platform (``virt``) +========================================== + +The `virt` board is a platform which does not correspond to any +real hardware; it is designed for use in virtual machines. +It is the recommended board type if you simply want to run +a guest such as Linux and do not care about reproducing the +idiosyncrasies and limitations of a particular bit of real-world +hardware. + +This is a "versioned" board model, so as well as the ``virt`` machine +type itself (which may have improvements, bugfixes and other minor +changes between QEMU versions) a version is provided that guarantees +to have the same behaviour as that of previous QEMU releases, so +that VM migration will work between QEMU versions. For instance the +``virt-5.0`` machine type will behave like the ``virt`` machine from +the QEMU 5.0 release, and migration should work between ``virt-5.0`` +of the 5.0 release and ``virt-5.0`` of the 5.1 release. Migration +is not guaranteed to work between different QEMU releases for +the non-versioned ``virt`` machine type. + +Supported devices +""""""""""""""""" + +The virt board supports: + +- PCI/PCIe devices +- Flash memory +- One PL011 UART +- An RTC +- The fw_cfg device that allows a guest to obtain data from QEMU +- A PL061 GPIO controller +- An optional SMMUv3 IOMMU +- hotpluggable DIMMs +- hotpluggable NVDIMMs +- An MSI controller (GICv2M or ITS). GICv2M is selected by default along + with GICv2. ITS is selected by default with GICv3 (>= virt-2.7). Note + that ITS is not modeled in TCG mode. +- 32 virtio-mmio transport devices +- running guests using the KVM accelerator on aarch64 hardware +- large amounts of RAM (at least 255GB, and more if using highmem) +- many CPUs (up to 512 if using a GICv3 and highmem) +- Secure-World-only devices if the CPU has TrustZone: + + - A second PL011 UART + - A secure flash memory + - 16MB of secure RAM + +Supported guest CPU types: + +- ``cortex-a7`` (32-bit) +- ``cortex-a15`` (32-bit; the default) +- ``cortex-a53`` (64-bit) +- ``cortex-a57`` (64-bit) +- ``cortex-a72`` (64-bit) +- ``host`` (with KVM only) +- ``max`` (same as ``host`` for KVM; best possible emulation with TCG) + +Note that the default is ``cortex-a15``, so for an AArch64 guest you must +specify a CPU type. + +Graphics output is available, but unlike the x86 PC machine types +there is no default display device enabled: you should select one from +the Display devices section of "-device help". The recommended option +is ``virtio-gpu-pci``; this is the only one which will work correctly +with KVM. You may also need to ensure your guest kernel is configured +with support for this; see below. + +Machine-specific options +"""""""""""""""""""""""" + +The following machine-specific options are supported: + +secure + Set ``on``/``off`` to enable/disable emulating a guest CPU which implements the + Arm Security Extensions (TrustZone). The default is ``off``. + +virtualization + Set ``on``/``off`` to enable/disable emulating a guest CPU which implements the + Arm Virtualization Extensions. The default is ``off``. + +highmem + Set ``on``/``off`` to enable/disable placing devices and RAM in physical + address space above 32 bits. The default is ``on`` for machine types + later than ``virt-2.12``. + +gic-version + Specify the version of the Generic Interrupt Controller (GIC) to provide. + Valid values are: + + ``2`` + GICv2 + ``3`` + GICv3 + ``host`` + Use the same GIC version the host provides, when using KVM + ``max`` + Use the best GIC version possible (same as host when using KVM; + currently same as ``3``` for TCG, but this may change in future) + +its + Set ``on``/``off`` to enable/disable ITS instantiation. The default is ``on`` + for machine types later than ``virt-2.7``. + +iommu + Set the IOMMU type to create for the guest. Valid values are: + + ``none`` + Don't create an IOMMU (the default) + ``smmuv3`` + Create an SMMUv3 + +ras + Set ``on``/``off`` to enable/disable reporting host memory errors to a guest + using ACPI and guest external abort exceptions. The default is off. + +Linux guest kernel configuration +"""""""""""""""""""""""""""""""" + +The 'defconfig' for Linux arm and arm64 kernels should include the +right device drivers for virtio and the PCI controller; however some older +kernel versions, especially for 32-bit Arm, did not have everything +enabled by default. If you're not seeing PCI devices that you expect, +then check that your guest config has:: + + CONFIG_PCI=y + CONFIG_VIRTIO_PCI=y + CONFIG_PCI_HOST_GENERIC=y + +If you want to use the ``virtio-gpu-pci`` graphics device you will also +need:: + + CONFIG_DRM=y + CONFIG_DRM_VIRTIO_GPU=y + +Hardware configuration information for bare-metal programming +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +The ``virt`` board automatically generates a device tree blob ("dtb") +which it passes to the guest. This provides information about the +addresses, interrupt lines and other configuration of the various devices +in the system. Guest code can rely on and hard-code the following +addresses: + +- Flash memory starts at address 0x0000_0000 + +- RAM starts at 0x4000_0000 + +All other information about device locations may change between +QEMU versions, so guest code must look in the DTB. + +QEMU supports two types of guest image boot for ``virt``, and +the way for the guest code to locate the dtb binary differs: + +- For guests using the Linux kernel boot protocol (this means any + non-ELF file passed to the QEMU ``-kernel`` option) the address + of the DTB is passed in a register (``r2`` for 32-bit guests, + or ``x0`` for 64-bit guests) + +- For guests booting as "bare-metal" (any other kind of boot), + the DTB is at the start of RAM (0x4000_0000) diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index 163ab91559..4c5b0e4aab 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -92,6 +92,7 @@ undocumented; you can get a complete list by running arm/collie arm/sx1 arm/stellaris + arm/virt Arm CPU features ================ From 7cee363bc2eff06068db0dc3e59cbc5f1906067e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 17 Jul 2020 08:57:42 +0200 Subject: [PATCH 2417/2595] scripts/oss-fuzz: Limit target list to i386-softmmu The build.sh script only copies qemu-fuzz-i386 to the destination folder, so we can speed up the compilation step quite a bit by not compiling the other targets here. Signed-off-by: Thomas Huth --- scripts/oss-fuzz/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/oss-fuzz/build.sh b/scripts/oss-fuzz/build.sh index f5cee3d67e..a07b3022e8 100755 --- a/scripts/oss-fuzz/build.sh +++ b/scripts/oss-fuzz/build.sh @@ -68,7 +68,7 @@ mkdir -p "$DEST_DIR/lib/" # Copy the shared libraries here # Build once to get the list of dynamic lib paths, and copy them over ../configure --disable-werror --cc="$CC" --cxx="$CXX" \ - --extra-cflags="$EXTRA_CFLAGS" + --extra-cflags="$EXTRA_CFLAGS" --target-list="i386-softmmu" if ! make CONFIG_FUZZ=y CFLAGS="$LIB_FUZZING_ENGINE" "-j$(nproc)" \ i386-softmmu/fuzz; then From bcbad8b05c7f9072cadd3d3ebef2992196b73801 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Fri, 17 Jul 2020 12:35:23 -0400 Subject: [PATCH 2418/2595] fuzz: Fix leak when assembling datadir path string We freed the string containing the final datadir path, but did not free the path to the executable's directory that we get from g_path_get_dirname(). Fix that. Reported-by: Thomas Huth Signed-off-by: Alexander Bulekov Message-Id: <20200717163523.1591-1-alxndr@bu.edu> Signed-off-by: Thomas Huth --- tests/qtest/fuzz/fuzz.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 6bc17ef313..031594a686 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -143,7 +143,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) { char *target_name; - char *dir; + char *bindir, *datadir; bool serialize = false; /* Initialize qgraph and modules */ @@ -164,11 +164,13 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) * location of the executable. Using this we add exec_dir/pc-bios to * the datadirs. */ - dir = g_build_filename(g_path_get_dirname(**argv), "pc-bios", NULL); - if (g_file_test(dir, G_FILE_TEST_IS_DIR)) { - qemu_add_data_dir(dir); + bindir = g_path_get_dirname(**argv); + datadir = g_build_filename(bindir, "pc-bios", NULL); + g_free(bindir); + if (g_file_test(datadir, G_FILE_TEST_IS_DIR)) { + qemu_add_data_dir(datadir); } - g_free(dir); + g_free(datadir); } else if (*argc > 1) { /* The target is specified as an argument */ target_name = (*argv)[1]; if (!strstr(target_name, "--fuzz-target=")) { From 48eac1019769ebc4647ba380a828c25d8014be37 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Thu, 16 Jul 2020 12:33:30 -0400 Subject: [PATCH 2419/2595] gitlab-ci.yml: Add oss-fuzz build tests This tries to build and run the fuzzers with the same build-script used by oss-fuzz. This doesn't guarantee that the builds on oss-fuzz will also succeed, since oss-fuzz provides its own compiler and fuzzer vars, but it can catch changes that are not compatible with the the ./scripts/oss-fuzz/build.sh script. The strange way of finding fuzzer binaries stems from the method used by oss-fuzz: https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-runner/targets_list Signed-off-by: Alexander Bulekov Message-Id: <20200720073223.22945-1-thuth@redhat.com> [thuth: Tweak the "script" to make it work, exclude slirp test, etc.] Signed-off-by: Thomas Huth --- .gitlab-ci.yml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 41597c3603..362e5ee755 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -164,22 +164,20 @@ build-clang: ppc-softmmu s390x-softmmu arm-linux-user MAKE_CHECK_ARGS: check -build-fuzzer: +build-oss-fuzz: <<: *native_build_job_definition variables: IMAGE: fedora script: - - mkdir build - - cd build - - ../configure --cc=clang --cxx=clang++ --enable-fuzzing - --enable-sanitizers --target-list=x86_64-softmmu - - make -j"$JOBS" all check-build x86_64-softmmu/fuzz - - make check - - for fuzzer in i440fx-qos-fork-fuzz i440fx-qos-noreset-fuzz - i440fx-qtest-reboot-fuzz virtio-scsi-flags-fuzz virtio-scsi-fuzz ; do - echo Testing ${fuzzer} ... ; - x86_64-softmmu/qemu-fuzz-x86_64 --fuzz-target=${fuzzer} -runs=1000 - || exit 1 ; + - mkdir build-oss-fuzz + - CC="clang" CXX="clang++" CFLAGS="-fsanitize=address" + ./scripts/oss-fuzz/build.sh + - for fuzzer in $(find ./build-oss-fuzz/DEST_DIR/ -executable -type f + | grep -v slirp); do + grep "LLVMFuzzerTestOneInput" ${fuzzer} > /dev/null 2>&1 || continue ; + echo Testing ${fuzzer} ... ; + ASAN_OPTIONS="fast_unwind_on_malloc=0" + "${fuzzer}" -runs=1000 -seed=1 || exit 1 ; done build-tci: From dd0162653c11de58331506beb8b3d85c8923149c Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Mon, 6 Jul 2020 15:55:31 -0400 Subject: [PATCH 2420/2595] fuzz: build without AddressSanitizer, by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have a nice --enable-sanitizers option to enable AddressSanitizer. There is no reason to duplicate and force this functionality in --enable-fuzzing. In the future, if more sanitizers are added to --enable-sanitizers, it might be impossible to build with both --enable-sanitizers and --enable-fuzzing, since not all sanitizers are compatible with libFuzzer. In that case, we could enable ASAN with --extra-cflags="-fsanitize=address" Signed-off-by: Alexander Bulekov Message-Id: <20200706195534.14962-2-alxndr@bu.edu> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth [thuth: Added missing $CFLAGS] Signed-off-by: Thomas Huth --- configure | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 33cee41f9c..4bd80ed507 100755 --- a/configure +++ b/configure @@ -6337,7 +6337,7 @@ fi # checks for fuzzer if test "$fuzzing" = "yes" ; then write_c_fuzzer_skeleton - if compile_prog "$CPU_CFLAGS -Werror -fsanitize=address,fuzzer" ""; then + if compile_prog "$CPU_CFLAGS -Werror -fsanitize=fuzzer" ""; then have_fuzzer=yes fi fi @@ -7893,11 +7893,11 @@ if test "$have_mlockall" = "yes" ; then fi if test "$fuzzing" = "yes" ; then if test "$have_fuzzer" = "yes"; then - FUZZ_LDFLAGS=" -fsanitize=address,fuzzer" - FUZZ_CFLAGS=" -fsanitize=address,fuzzer" - CFLAGS="$CFLAGS -fsanitize=address,fuzzer-no-link" + FUZZ_LDFLAGS=" -fsanitize=fuzzer" + FUZZ_CFLAGS=" -fsanitize=fuzzer" + CFLAGS="$CFLAGS -fsanitize=fuzzer-no-link" else - error_exit "Your compiler doesn't support -fsanitize=address,fuzzer" + error_exit "Your compiler doesn't support -fsanitize=fuzzer" exit 1 fi fi From ee16da12d7035bffb1c990c794de8fb1a96815d7 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Mon, 6 Jul 2020 15:55:32 -0400 Subject: [PATCH 2421/2595] docs/fuzz: describe building fuzzers with enable-sanitizers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexander Bulekov Message-Id: <20200706195534.14962-3-alxndr@bu.edu> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- docs/devel/fuzzing.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/devel/fuzzing.txt b/docs/devel/fuzzing.txt index db5641de74..12bf6aa0ca 100644 --- a/docs/devel/fuzzing.txt +++ b/docs/devel/fuzzing.txt @@ -23,9 +23,12 @@ AddressSanitizer mmaps ~20TB of memory, as part of its detection. This results in a large page-map, and a much slower fork(). To build the fuzzers, install a recent version of clang: -Configure with (substitute the clang binaries with the version you installed): +Configure with (substitute the clang binaries with the version you installed). +Here, enable-sanitizers, is optional but it allows us to reliably detect bugs +such as out-of-bounds accesses, use-after-frees, double-frees etc. - CC=clang-8 CXX=clang++-8 /path/to/configure --enable-fuzzing + CC=clang-8 CXX=clang++-8 /path/to/configure --enable-fuzzing \ + --enable-sanitizers Fuzz targets are built similarly to system/softmmu: From 19a91e4af86c578420e9fdfe2efdc3b3b3826222 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Mon, 6 Jul 2020 15:55:33 -0400 Subject: [PATCH 2422/2595] docs/fuzz: add information about useful libFuzzer flags Signed-off-by: Alexander Bulekov Message-Id: <20200706195534.14962-4-alxndr@bu.edu> Signed-off-by: Thomas Huth --- docs/devel/fuzzing.txt | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/devel/fuzzing.txt b/docs/devel/fuzzing.txt index 12bf6aa0ca..6d18115239 100644 --- a/docs/devel/fuzzing.txt +++ b/docs/devel/fuzzing.txt @@ -48,6 +48,43 @@ Information about these is available by passing -help=1 Now the only thing left to do is wait for the fuzzer to trigger potential crashes. +== Useful libFuzzer flags == + +As mentioned above, libFuzzer accepts some arguments. Passing -help=1 will list +the available arguments. In particular, these arguments might be helpful: + +$CORPUS_DIR/ : Specify a directory as the last argument to libFuzzer. libFuzzer +stores each "interesting" input in this corpus directory. The next time you run +libFuzzer, it will read all of the inputs from the corpus, and continue fuzzing +from there. You can also specify multiple directories. libFuzzer loads existing +inputs from all specified directories, but will only write new ones to the +first one specified. + +-max_len=4096 : specify the maximum byte-length of the inputs libFuzzer will +generate. + +-close_fd_mask={1,2,3} : close, stderr, or both. Useful for targets that +trigger many debug/error messages, or create output on the serial console. + +-jobs=4 -workers=4 : These arguments configure libFuzzer to run 4 fuzzers in +parallel (4 fuzzing jobs in 4 worker processes). Alternatively, with only +-jobs=N, libFuzzer automatically spawns a number of workers less than or equal +to half the available CPU cores. Replace 4 with a number appropriate for your +machine. Make sure to specify a $CORPUS_DIR, which will allow the parallel +fuzzers to share information about the interesting inputs they find. + +-use_value_profile=1 : For each comparison operation, libFuzzer computes +(caller_pc&4095) | (popcnt(Arg1 ^ Arg2) << 12) and places this in the coverage +table. Useful for targets with "magic" constants. If Arg1 came from the fuzzer's +input and Arg2 is a magic constant, then each time the Hamming distance +between Arg1 and Arg2 decreases, libFuzzer adds the input to the corpus. + +-shrink=1 : Tries to make elements of the corpus "smaller". Might lead to +better coverage performance, depending on the target. + +Note that libFuzzer's exact behavior will depend on the version of +clang and libFuzzer used to build the device fuzzers. + == Adding a new fuzzer == Coverage over virtual devices can be improved by adding additional fuzzers. Fuzzers are kept in tests/qtest/fuzz/ and should be added to From 09a14f586c315b01411dc1ef1bfe99b034b302de Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Mon, 6 Jul 2020 15:55:34 -0400 Subject: [PATCH 2423/2595] docs/fuzz: add instructions for generating a coverage report Signed-off-by: Alexander Bulekov Message-Id: <20200706195534.14962-5-alxndr@bu.edu> [thuth: Replaced --enable-sanitizers with --enable-fuzzing] Signed-off-by: Thomas Huth --- docs/devel/fuzzing.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/devel/fuzzing.txt b/docs/devel/fuzzing.txt index 6d18115239..96d71c94d7 100644 --- a/docs/devel/fuzzing.txt +++ b/docs/devel/fuzzing.txt @@ -85,6 +85,25 @@ better coverage performance, depending on the target. Note that libFuzzer's exact behavior will depend on the version of clang and libFuzzer used to build the device fuzzers. +== Generating Coverage Reports == +Code coverage is a crucial metric for evaluating a fuzzer's performance. +libFuzzer's output provides a "cov: " column that provides a total number of +unique blocks/edges covered. To examine coverage on a line-by-line basis we +can use Clang coverage: + + 1. Configure libFuzzer to store a corpus of all interesting inputs (see + CORPUS_DIR above) + 2. ./configure the QEMU build with: + --enable-fuzzing \ + --extra-cflags="-fprofile-instr-generate -fcoverage-mapping" + 3. Re-run the fuzzer. Specify $CORPUS_DIR/* as an argument, telling libfuzzer + to execute all of the inputs in $CORPUS_DIR and exit. Once the process + exits, you should find a file, "default.profraw" in the working directory. + 4. Execute these commands to generate a detailed HTML coverage-report: + llvm-profdata merge -output=default.profdata default.profraw + llvm-cov show ./path/to/qemu-fuzz-i386 -instr-profile=default.profdata \ + --format html -output-dir=/path/to/output/report + == Adding a new fuzzer == Coverage over virtual devices can be improved by adding additional fuzzers. Fuzzers are kept in tests/qtest/fuzz/ and should be added to From 6184e5fb4221ec5dd6f0c27d05a8e575b81eb89b Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 21 Jul 2020 07:36:09 +0200 Subject: [PATCH 2424/2595] MAINTAINERS: Extend the device fuzzing section The file docs/devel/fuzzing.txt should be in this section, too, and add myself as a reviewer (since I often take the fuzzer patches through the qtest-next tree, I should be notified on patches, too). Message-Id: <20200721053926.17197-1-thuth@redhat.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5e8616821a..3395abd4e1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2449,9 +2449,11 @@ M: Alexander Bulekov R: Paolo Bonzini R: Bandan Das R: Stefan Hajnoczi +R: Thomas Huth S: Maintained F: tests/qtest/fuzz/ F: scripts/oss-fuzz/ +F: docs/devel/fuzzing.txt Register API M: Alistair Francis From 2b0650205b71c2aa8bf6f877a8333ef25bf288b2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Jul 2020 16:04:39 +0200 Subject: [PATCH 2425/2595] msf2: Unbreak device-list-properties for "msf-soc" Watch this: $ qemu-system-aarch64 -M ast2600-evb -S -display none -qmp stdio {"QMP": {"version": {"qemu": {"micro": 50, "minor": 0, "major": 5}, "package": "v5.0.0-2464-g3a9163af4e"}, "capabilities": ["oob"]}} {"execute": "qmp_capabilities"} {"return": {}} {"execute": "device-list-properties", "arguments": {"typename": "msf2-soc"}} Unsupported NIC model: ftgmac100 armbru@dusky:~/work/images$ echo $? 1 This is what breaks "make check SPEED=slow". Root cause is m2sxxx_soc_initfn()'s messing with nd_table[] via qemu_check_nic_model(). That's wrong. We fixed the exact same bug for device "allwinner-a10" in commit 8aabc5437b "hw/arm/allwinner-a10: Do not use nd_table in instance_init function". Fix this instance the same way: move the offending code to m2sxxx_soc_realize(), where it's less wrong, and add a FIXME comment. Fixes: 05b7374a58 ("msf2: Add EMAC block to SmartFusion2 SoC") Signed-off-by: Markus Armbruster Message-Id: <20200715140440.3540942-2-armbru@redhat.com> Reviewed-by: Alistair Francis Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- hw/arm/msf2-soc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index 16bb7c9916..33ea7df342 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -82,10 +82,6 @@ static void m2sxxx_soc_initfn(Object *obj) } object_initialize_child(obj, "emac", &s->emac, TYPE_MSS_EMAC); - if (nd_table[0].used) { - qemu_check_nic_model(&nd_table[0], TYPE_MSS_EMAC); - qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); - } } static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) @@ -187,6 +183,11 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) g_free(bus_name); } + /* FIXME use qdev NIC properties instead of nd_table[] */ + if (nd_table[0].used) { + qemu_check_nic_model(&nd_table[0], TYPE_MSS_EMAC); + qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); + } dev = DEVICE(&s->emac); object_property_set_link(OBJECT(&s->emac), "ahb-bus", OBJECT(get_system_memory()), &error_abort); From 7ad36e2e241bd924f774a1f9fb208c102da58e50 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Jul 2020 16:04:40 +0200 Subject: [PATCH 2426/2595] hw: Mark nd_table[] misuse in realize methods FIXME nd_table[] contains NIC configuration for boards to pick up. Device code has no business looking there. Several devices do it anyway. Two of them already have a suitable FIXME comment: "allwinner-a10" and "msf2-soc". Copy it to the others: "allwinner-h3", "xlnx-versal", "xlnx,zynqmp", "sparc32-ledma", "riscv.sifive.u.soc". Signed-off-by: Markus Armbruster Message-Id: <20200715140440.3540942-3-armbru@redhat.com> Reviewed-by: Alistair Francis Reviewed-by: Niek Linnenbank Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- hw/arm/allwinner-h3.c | 1 + hw/arm/xlnx-versal.c | 1 + hw/arm/xlnx-zynqmp.c | 1 + hw/dma/sparc32_dma.c | 1 + hw/riscv/sifive_u.c | 1 + 5 files changed, 5 insertions(+) diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c index 8e09468e86..ff92ded82c 100644 --- a/hw/arm/allwinner-h3.c +++ b/hw/arm/allwinner-h3.c @@ -358,6 +358,7 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) "sd-bus"); /* EMAC */ + /* FIXME use qdev NIC properties instead of nd_table[] */ if (nd_table[0].used) { qemu_check_nic_model(&nd_table[0], TYPE_AW_SUN8I_EMAC); qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index ead038b971..e3aa4bd1e5 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -160,6 +160,7 @@ static void versal_create_gems(Versal *s, qemu_irq *pic) object_initialize_child(OBJECT(s), name, &s->lpd.iou.gem[i], TYPE_CADENCE_GEM); dev = DEVICE(&s->lpd.iou.gem[i]); + /* FIXME use qdev NIC properties instead of nd_table[] */ if (nd->used) { qemu_check_nic_model(nd, "cadence_gem"); qdev_set_nic_properties(dev, nd); diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 772cfa3771..5855e5d5bf 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -455,6 +455,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) { NICInfo *nd = &nd_table[i]; + /* FIXME use qdev NIC properties instead of nd_table[] */ if (nd->used) { qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(DEVICE(&s->gem[i]), nd); diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index 9459178866..bcd1626fbd 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -341,6 +341,7 @@ static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp) DeviceState *d; NICInfo *nd = &nd_table[0]; + /* FIXME use qdev NIC properties instead of nd_table[] */ qemu_check_nic_model(nd, TYPE_LANCE); d = qdev_new(TYPE_LANCE); diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 19a976c9a6..e5682c38a9 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -714,6 +714,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) } sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base); + /* FIXME use qdev NIC properties instead of nd_table[] */ if (nd->used) { qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(DEVICE(&s->gem), nd); From 662d0c5392a272aa0357aa7205e77fa3ca89c316 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Sun, 19 Jul 2020 15:20:58 +0300 Subject: [PATCH 2427/2595] block/crypto: disallow write sharing by default My commit 'block/crypto: implement the encryption key management' accidently allowed raw luks images to be shared between different qemu processes without share-rw=on explicit override. Fix that. Fixes: bbfdae91fb ("block/crypto: implement the encryption key management") Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1857490 Signed-off-by: Maxim Levitsky Message-Id: <20200719122059.59843-2-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- block/crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/crypto.c b/block/crypto.c index 8725c1bc02..0807557763 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -881,7 +881,7 @@ block_crypto_child_perms(BlockDriverState *bs, BdrvChild *c, * For backward compatibility, manually share the write * and resize permission */ - *nshared |= (BLK_PERM_WRITE | BLK_PERM_RESIZE); + *nshared |= shared & (BLK_PERM_WRITE | BLK_PERM_RESIZE); /* * Since we are not fully a format driver, don't always request * the read/resize permission but only when explicitly From 0fca43de1b617a95f2472691ca1e740932ab2fea Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Sun, 19 Jul 2020 15:20:59 +0300 Subject: [PATCH 2428/2595] qemu-iotests: add testcase for bz #1857490 Test that we can't write-share raw luks images by default, but we still can with share-rw=on Signed-off-by: Maxim Levitsky Message-Id: <20200719122059.59843-3-mlevitsk@redhat.com> Signed-off-by: Max Reitz --- tests/qemu-iotests/296 | 44 +++++++++++++++++++++++++++++++++++++- tests/qemu-iotests/296.out | 12 +++++++++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296 index ec69ec8974..fb7dec88aa 100755 --- a/tests/qemu-iotests/296 +++ b/tests/qemu-iotests/296 @@ -133,6 +133,21 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): ) self.assert_qmp(result, 'return', {}) + + ########################################################################### + # add virtio-blk consumer for a block device + def addImageUser(self, vm, id, disk_id, share_rw=False): + result = vm.qmp('device_add', ** + { + 'driver': 'virtio-blk', + 'id': id, + 'drive': disk_id, + 'share-rw' : share_rw + } + ) + + iotests.log(result) + # close the encrypted block device def closeImageQmp(self, vm, id): result = vm.qmp('blockdev-del', **{ 'node-name': id }) @@ -159,7 +174,7 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): vm.run_job('job0') # test that when the image opened by two qemu processes, - # neither of them can update the image + # neither of them can update the encryption keys def test1(self): self.createImg(test_img, self.secrets[0]); @@ -193,6 +208,9 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): os.remove(test_img) + # test that when the image opened by two qemu processes, + # even if first VM opens it read-only, the second can't update encryption + # keys def test2(self): self.createImg(test_img, self.secrets[0]); @@ -226,6 +244,30 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): self.closeImageQmp(self.vm1, "testdev") os.remove(test_img) + # test that two VMs can't open the same luks image by default + # and attach it to a guest device + def test3(self): + self.createImg(test_img, self.secrets[0]); + + self.openImageQmp(self.vm1, "testdev", test_img, self.secrets[0]) + self.addImageUser(self.vm1, "testctrl", "testdev") + + self.openImageQmp(self.vm2, "testdev", test_img, self.secrets[0]) + self.addImageUser(self.vm2, "testctrl", "testdev") + + + # test that two VMs can attach the same luks image to a guest device, + # if both use share-rw=on + def test4(self): + self.createImg(test_img, self.secrets[0]); + + self.openImageQmp(self.vm1, "testdev", test_img, self.secrets[0]) + self.addImageUser(self.vm1, "testctrl", "testdev", share_rw=True) + + self.openImageQmp(self.vm2, "testdev", test_img, self.secrets[0]) + self.addImageUser(self.vm2, "testctrl", "testdev", share_rw=True) + + if __name__ == '__main__': # support only raw luks since luks encrypted qcow2 is a proper diff --git a/tests/qemu-iotests/296.out b/tests/qemu-iotests/296.out index afb6d2d09d..cb2859a15c 100644 --- a/tests/qemu-iotests/296.out +++ b/tests/qemu-iotests/296.out @@ -26,8 +26,16 @@ Job failed: Failed to get shared "consistent read" lock {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -.. +Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10 + +{"return": {}} +{"error": {"class": "GenericError", "desc": "Failed to get \"write\" lock"}} +Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10 + +{"return": {}} +{"return": {}} +.... ---------------------------------------------------------------------- -Ran 2 tests +Ran 4 tests OK From 8e67fda2dd6202ccec093fda561107ba14830a17 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 21 Jul 2020 10:33:22 +0200 Subject: [PATCH 2429/2595] xhci: fix valid.max_access_size to access address registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU XHCI advertises AC64 (64-bit addressing) but doesn't allow 64-bit mode access in "runtime" and "operational" MemoryRegionOps. Set the max_access_size based on sizeof(dma_addr_t) as AC64 is set. XHCI specs: "If the xHC supports 64-bit addressing (AC64 = ‘1’), then software should write 64-bit registers using only Qword accesses. If a system is incapable of issuing Qword accesses, then writes to the 64-bit address fields shall be performed using 2 Dword accesses; low Dword-first, high-Dword second. If the xHC supports 32-bit addressing (AC64 = ‘0’), then the high Dword of registers containing 64-bit address fields are unused and software should write addresses using only Dword accesses" The problem has been detected with SLOF, as linux kernel always accesses registers using 32-bit access even if AC64 is set and revealed by 5d971f9e6725 ("memory: Revert "memory: accept mismatching sizes in memory_region_access_valid"") Suggested-by: Alexey Kardashevskiy Signed-off-by: Laurent Vivier Message-id: 20200721083322.90651-1-lvivier@redhat.com Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-xhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index b330e36fe6..67a18fe2b6 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -3184,7 +3184,7 @@ static const MemoryRegionOps xhci_oper_ops = { .read = xhci_oper_read, .write = xhci_oper_write, .valid.min_access_size = 4, - .valid.max_access_size = 4, + .valid.max_access_size = sizeof(dma_addr_t), .endianness = DEVICE_LITTLE_ENDIAN, }; @@ -3200,7 +3200,7 @@ static const MemoryRegionOps xhci_runtime_ops = { .read = xhci_runtime_read, .write = xhci_runtime_write, .valid.min_access_size = 4, - .valid.max_access_size = 4, + .valid.max_access_size = sizeof(dma_addr_t), .endianness = DEVICE_LITTLE_ENDIAN, }; From d97df4b84bc42613cf9a03619de453ebd0be30b7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 20 Jul 2020 12:03:50 +0200 Subject: [PATCH 2430/2595] qxl: fix modular builds with dtrace Checking the enable/disable state of tracepoints via trace_event_get_state_backends() does not work for modules. qxl checks the state for a small optimization (avoid g_strndup call in case log_buf will not be used anyway), so we can just drop that check for modular builds. Signed-off-by: Gerd Hoffmann Message-Id: <20200720100352.2477-2-kraxel@redhat.com> --- hw/display/qxl.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index d5627119ec..11871340e7 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -1762,7 +1762,16 @@ async_common: qxl_set_mode(d, val, 0); break; case QXL_IO_LOG: +#ifdef CONFIG_MODULES + /* + * FIXME + * trace_event_get_state_backends() does not work for modules, + * it leads to "undefined symbol: qemu_qxl_io_log_semaphore" + */ + if (true) { +#else if (trace_event_get_state_backends(TRACE_QXL_IO_LOG) || d->guestdebug) { +#endif /* We cannot trust the guest to NUL terminate d->ram->log_buf */ char *log_buf = g_strndup((const char *)d->ram->log_buf, sizeof(d->ram->log_buf)); From d87350b065128e8156e7aca93e89a1ab9e5fa63d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 20 Jul 2020 12:03:51 +0200 Subject: [PATCH 2431/2595] module: ignore NULL type Just return in case module_load_qom_one(NULL) is called. vga_interface_available() can do that. Signed-off-by: Gerd Hoffmann Message-Id: <20200720100352.2477-3-kraxel@redhat.com> --- util/module.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/module.c b/util/module.c index 90e9bd42c6..0ab00851f0 100644 --- a/util/module.c +++ b/util/module.c @@ -275,6 +275,9 @@ void module_load_qom_one(const char *type) { int i; + if (!type) { + return; + } if (module_loaded_qom_all) { return; } From 1d719ddc35e9827b6e5df771555874df34301a0d Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 20 Jul 2020 11:01:41 +0100 Subject: [PATCH 2432/2595] block: fix bdrv_aio_cancel() for ENOMEDIUM requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bdrv_aio_cancel() calls aio_poll() on the AioContext for the given I/O request until it has completed. ENOMEDIUM requests are special because there is no BlockDriverState when the drive has no medium! Define a .get_aio_context() function for BlkAioEmAIOCB requests so that bdrv_aio_cancel() can find the AioContext where the completion BH is pending. Without this function bdrv_aio_cancel() aborts on ENOMEDIUM requests! libFuzzer triggered the following assertion: cat << EOF | qemu-system-i386 -M pc-q35-5.0 \ -nographic -monitor none -serial none \ -qtest stdio -trace ide\* outl 0xcf8 0x8000fa24 outl 0xcfc 0xe106c000 outl 0xcf8 0x8000fa04 outw 0xcfc 0x7 outl 0xcf8 0x8000fb20 write 0x0 0x3 0x2780e7 write 0xe106c22c 0xd 0x1130c218021130c218021130c2 write 0xe106c218 0x15 0x110010110010110010110010110010110010110010 EOF ide_exec_cmd IDE exec cmd: bus 0x56170a77a2b8; state 0x56170a77a340; cmd 0xe7 ide_reset IDEstate 0x56170a77a340 Aborted (core dumped) (gdb) bt #1 0x00007ffff4f93895 in abort () at /lib64/libc.so.6 #2 0x0000555555dc6c00 in bdrv_aio_cancel (acb=0x555556765550) at block/io.c:2745 #3 0x0000555555dac202 in blk_aio_cancel (acb=0x555556765550) at block/block-backend.c:1546 #4 0x0000555555b1bd74 in ide_reset (s=0x555557213340) at hw/ide/core.c:1318 #5 0x0000555555b1e3a1 in ide_bus_reset (bus=0x5555572132b8) at hw/ide/core.c:2422 #6 0x0000555555b2aa27 in ahci_reset_port (s=0x55555720eb50, port=2) at hw/ide/ahci.c:650 #7 0x0000555555b29fd7 in ahci_port_write (s=0x55555720eb50, port=2, offset=44, val=16) at hw/ide/ahci.c:360 #8 0x0000555555b2a564 in ahci_mem_write (opaque=0x55555720eb50, addr=556, val=16, size=1) at hw/ide/ahci.c:513 #9 0x000055555598415b in memory_region_write_accessor (mr=0x55555720eb80, addr=556, value=0x7fffffffb838, size=1, shift=0, mask=255, attrs=...) at softmmu/memory.c:483 Looking at bdrv_aio_cancel: 2728 /* async I/Os */ 2729 2730 void bdrv_aio_cancel(BlockAIOCB *acb) 2731 { 2732 qemu_aio_ref(acb); 2733 bdrv_aio_cancel_async(acb); 2734 while (acb->refcnt > 1) { 2735 if (acb->aiocb_info->get_aio_context) { 2736 aio_poll(acb->aiocb_info->get_aio_context(acb), true); 2737 } else if (acb->bs) { 2738 /* qemu_aio_ref and qemu_aio_unref are not thread-safe, so 2739 * assert that we're not using an I/O thread. Thread-safe 2740 * code should use bdrv_aio_cancel_async exclusively. 2741 */ 2742 assert(bdrv_get_aio_context(acb->bs) == qemu_get_aio_context()); 2743 aio_poll(bdrv_get_aio_context(acb->bs), true); 2744 } else { 2745 abort(); <=============== 2746 } 2747 } 2748 qemu_aio_unref(acb); 2749 } Fixes: 02c50efe08736116048d5fc355043080f4d5859c ("block: Add bdrv_aio_cancel_async") Reported-by: Alexander Bulekov Buglink: https://bugs.launchpad.net/qemu/+bug/1878255 Originally-by: Philippe Mathieu-Daudé Signed-off-by: Stefan Hajnoczi Message-Id: <20200720100141.129739-1-stefanha@redhat.com> Signed-off-by: Max Reitz --- block/block-backend.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/block/block-backend.c b/block/block-backend.c index 0bf0188133..3a13cb5f0b 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1394,8 +1394,16 @@ typedef struct BlkAioEmAIOCB { bool has_returned; } BlkAioEmAIOCB; +static AioContext *blk_aio_em_aiocb_get_aio_context(BlockAIOCB *acb_) +{ + BlkAioEmAIOCB *acb = container_of(acb_, BlkAioEmAIOCB, common); + + return blk_get_aio_context(acb->rwco.blk); +} + static const AIOCBInfo blk_aio_em_aiocb_info = { .aiocb_size = sizeof(BlkAioEmAIOCB), + .get_aio_context = blk_aio_em_aiocb_get_aio_context, }; static void blk_aio_complete(BlkAioEmAIOCB *acb) From cbf97d5b799f4bc47b9e825100d1a98d3cf77c80 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 16 Jul 2020 17:06:17 +0200 Subject: [PATCH 2433/2595] qapi: Fix visit_type_STRUCT() not to fail for null object To make deallocating partially constructed objects work, the visit_type_STRUCT() need to succeed without doing anything when passed a null object. Commit cdd2b228b9 "qapi: Smooth visitor error checking in generated code" broke that. To reproduce, run tests/test-qobject-input-visitor with AddressSanitizer: ==4353==ERROR: LeakSanitizer: detected memory leaks Direct leak of 16 byte(s) in 1 object(s) allocated from: #0 0x7f192d0c5d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) #1 0x7f192cd21b10 in g_malloc0 (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x51b10) #2 0x556725f6bbee in visit_next_list qapi/qapi-visit-core.c:86 #3 0x556725f49e15 in visit_type_UserDefOneList tests/test-qapi-visit.c:474 #4 0x556725f4489b in test_visitor_in_fail_struct_in_list tests/test-qobject-input-visitor.c:1086 #5 0x7f192cd42f29 (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x72f29) SUMMARY: AddressSanitizer: 16 byte(s) leaked in 1 allocation(s). Test case /visitor/input/fail/struct-in-list feeds a list with a bad element to the QObject input visitor. Visiting that element duly fails, and aborts the visit with the list only partially constructed: the faulty object is null. Cleaning up the partially constructed list visits that null object, fails, and aborts the visit before the list node gets freed. Fix the the generated visit_type_STRUCT() to succeed for null objects. Fixes: cdd2b228b973d2a29edf7696ef6e8b08ec329019 Reported-by: Li Qiang Signed-off-by: Markus Armbruster Message-Id: <20200716150617.4027356-1-armbru@redhat.com> Tested-by: Li Qiang Reviewed-by: Li Qiang --- scripts/qapi/visit.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index 3fb2f30510..cdabc5fa28 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -249,6 +249,7 @@ bool visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error if (!*obj) { /* incomplete */ assert(visit_is_dealloc(v)); + ok = true; goto out_obj; } if (!visit_type_%(c_name)s_members(v, *obj, errp)) { From e219d30910d8584868dd5c11df10ba2a1336034c Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 16 Jul 2020 06:53:24 +0300 Subject: [PATCH 2434/2595] hw/net: Added plen fix for IPv6 Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1708065 With network backend with 'virtual header' - there was an issue in 'plen' field. Overall, during TSO, 'plen' would be changed, but with 'vheader' this field should be set to the size of the payload itself instead of '0'. Signed-off-by: Andrew Melnychenko Signed-off-by: Jason Wang --- hw/net/net_tx_pkt.c | 23 +++++++++++++++++++++++ hw/net/net_tx_pkt.h | 14 ++++++++++++++ include/net/eth.h | 1 + 3 files changed, 38 insertions(+) diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index 331c73cfc0..9560e4a49e 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -626,6 +626,7 @@ bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc) if (pkt->has_virt_hdr || pkt->virt_hdr.gso_type == VIRTIO_NET_HDR_GSO_NONE) { + net_tx_pkt_fix_ip6_payload_len(pkt); net_tx_pkt_sendv(pkt, nc, pkt->vec, pkt->payload_frags + NET_TX_PKT_PL_START_FRAG); return true; @@ -644,3 +645,25 @@ bool net_tx_pkt_send_loopback(struct NetTxPkt *pkt, NetClientState *nc) return res; } + +void net_tx_pkt_fix_ip6_payload_len(struct NetTxPkt *pkt) +{ + struct iovec *l2 = &pkt->vec[NET_TX_PKT_L2HDR_FRAG]; + if (eth_get_l3_proto(l2, 1, l2->iov_len) == ETH_P_IPV6) { + struct ip6_header *ip6 = (struct ip6_header *) pkt->l3_hdr; + /* + * TODO: if qemu would support >64K packets - add jumbo option check + * something like that: + * 'if (ip6->ip6_plen == 0 && !has_jumbo_option(ip6)) {' + */ + if (ip6->ip6_plen == 0) { + if (pkt->payload_len <= ETH_MAX_IP_DGRAM_LEN) { + ip6->ip6_plen = htons(pkt->payload_len); + } + /* + * TODO: if qemu would support >64K packets + * add jumbo option for packets greater then 65,535 bytes + */ + } + } +} diff --git a/hw/net/net_tx_pkt.h b/hw/net/net_tx_pkt.h index 212ecc62fc..4ec8bbe9bd 100644 --- a/hw/net/net_tx_pkt.h +++ b/hw/net/net_tx_pkt.h @@ -187,4 +187,18 @@ bool net_tx_pkt_parse(struct NetTxPkt *pkt); */ bool net_tx_pkt_has_fragments(struct NetTxPkt *pkt); +/** + * Fix IPv6 'plen' field. + * If ipv6 payload length field is 0 - then there should be Hop-by-Hop + * option for packets greater than 65,535. + * For packets with a payload less than 65,535: fix 'plen' field. + * For backends with vheader, we need just one packet with proper + * payload size. For now, qemu drops every packet with size greater 64K + * (see net_tx_pkt_send()) so, there is no reason to add jumbo option to ip6 + * hop-by-hop extension if it's missed + * + * @pkt packet + */ +void net_tx_pkt_fix_ip6_payload_len(struct NetTxPkt *pkt); + #endif diff --git a/include/net/eth.h b/include/net/eth.h index 7f45c678e7..0671be6916 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -186,6 +186,7 @@ struct tcp_hdr { #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt #define ip6_ecn_acc ip6_ctlun.ip6_un3.ip6_un3_ecn +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen #define PKT_GET_ETH_HDR(p) \ ((struct eth_header *)(p)) From 5519724a13664b43e225ca05351c60b4468e4555 Mon Sep 17 00:00:00 2001 From: Mauro Matteo Cascella Date: Fri, 10 Jul 2020 11:19:41 +0200 Subject: [PATCH 2435/2595] hw/net/xgmac: Fix buffer overflow in xgmac_enet_send() A buffer overflow issue was reported by Mr. Ziming Zhang, CC'd here. It occurs while sending an Ethernet frame due to missing break statements and improper checking of the buffer size. Reported-by: Ziming Zhang Signed-off-by: Mauro Matteo Cascella Reviewed-by: Peter Maydell Signed-off-by: Jason Wang --- hw/net/xgmac.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index 574dd47b41..5bf1b61012 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -220,21 +220,31 @@ static void xgmac_enet_send(XgmacState *s) } len = (bd.buffer1_size & 0xfff) + (bd.buffer2_size & 0xfff); + /* + * FIXME: these cases of malformed tx descriptors (bad sizes) + * should probably be reported back to the guest somehow + * rather than simply silently stopping processing, but we + * don't know what the hardware does in this situation. + * This will only happen for buggy guests anyway. + */ if ((bd.buffer1_size & 0xfff) > 2048) { DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- " "xgmac buffer 1 len on send > 2048 (0x%x)\n", __func__, bd.buffer1_size & 0xfff); + break; } if ((bd.buffer2_size & 0xfff) != 0) { DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- " "xgmac buffer 2 len on send != 0 (0x%x)\n", __func__, bd.buffer2_size & 0xfff); + break; } - if (len >= sizeof(frame)) { + if (frame_size + len >= sizeof(frame)) { DEBUGF_BRK("qemu:%s: buffer overflow %d read into %zu " - "buffer\n" , __func__, len, sizeof(frame)); + "buffer\n" , __func__, frame_size + len, sizeof(frame)); DEBUGF_BRK("qemu:%s: buffer1.size=%d; buffer2.size=%d\n", __func__, bd.buffer1_size, bd.buffer2_size); + break; } cpu_physical_memory_read(bd.buffer1_addr, ptr, len); From 7da1d7dcc0c08519b92d8af579fec2e2ea9e60b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 14 Jul 2020 18:10:44 +0200 Subject: [PATCH 2436/2595] qemu/osdep: Document os_find_datadir() return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document os_find_datadir() returned data must be freed. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael Rolnik Tested-by: Michael Rolnik Reviewed-by: Daniel P. Berrangé Message-Id: <20200714164257.23330-2-f4bug@amsat.org> --- os-posix.c | 3 +++ os-win32.c | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/os-posix.c b/os-posix.c index b674b20b1b..3572db3f44 100644 --- a/os-posix.c +++ b/os-posix.c @@ -84,6 +84,9 @@ void os_setup_signal_handling(void) * Find a likely location for support files using the location of the binary. * When running from the build tree this will be "$bindir/../pc-bios". * Otherwise, this is CONFIG_QEMU_DATADIR. + * + * The caller must use g_free() to free the returned data when it is + * no longer required. */ char *os_find_datadir(void) { diff --git a/os-win32.c b/os-win32.c index 6b86e022f0..c9c3afe648 100644 --- a/os-win32.c +++ b/os-win32.c @@ -57,7 +57,12 @@ void os_setup_early_signal_handling(void) atexit(os_undo_timer_resolution); } -/* Look for support files in the same directory as the executable. */ +/* + * Look for support files in the same directory as the executable. + * + * The caller must use g_free() to free the returned data when it is + * no longer required. + */ char *os_find_datadir(void) { return qemu_get_exec_dir(); From d450cccc9a4f4409434f4bd0a80270836f6bc3c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 14 Jul 2020 18:14:33 +0200 Subject: [PATCH 2437/2595] qemu/osdep: Reword qemu_get_exec_dir() documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This comment is confuse, reword it a bit. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael Rolnik Tested-by: Michael Rolnik Reviewed-by: Daniel P. Berrangé Message-Id: <20200714164257.23330-3-f4bug@amsat.org> --- include/qemu/osdep.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 4841b5c6b5..45c217aa28 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -588,7 +588,10 @@ char *qemu_get_local_state_pathname(const char *relative_pathname); void qemu_init_exec_dir(const char *argv0); /* Get the saved exec dir. - * Caller needs to release the returned string by g_free() */ + * + * The caller is responsible for releasing the value returned with g_free() + * after use. + */ char *qemu_get_exec_dir(void); /** From b6c61f69349ca3706c7e757ec1f2df916b70de7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 14 Jul 2020 18:10:10 +0200 Subject: [PATCH 2438/2595] qemu-common: Document qemu_find_file() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document qemu_find_file(), in particular the returned value which must be freed. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: Li Qiang Reviewed-by: Michael Rolnik Tested-by: Michael Rolnik Reviewed-by: Daniel P. Berrangé Message-Id: <20200714164257.23330-4-f4bug@amsat.org> --- include/qemu-common.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/qemu-common.h b/include/qemu-common.h index d0142f29ac..bb9496bd80 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -110,6 +110,23 @@ const char *qemu_get_vm_name(void); #define QEMU_FILE_TYPE_BIOS 0 #define QEMU_FILE_TYPE_KEYMAP 1 +/** + * qemu_find_file: + * @type: QEMU_FILE_TYPE_BIOS (for BIOS, VGA BIOS) + * or QEMU_FILE_TYPE_KEYMAP (for keymaps). + * @name: Relative or absolute file name + * + * If @name exists on disk as an absolute path, or a path relative + * to the current directory, then returns @name unchanged. + * Otherwise searches for @name file in the data directories, either + * configured at build time (DATADIR) or registered with the -L command + * line option. + * + * The caller must use g_free() to free the returned data when it is + * no longer required. + * + * Returns: a path that can access @name, or NULL if no matching file exists. + */ char *qemu_find_file(int type, const char *name); /* OS specific functions */ From 5e29521a82e540552880c3572cb8274bcaa1002c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 14 Jul 2020 18:15:05 +0200 Subject: [PATCH 2439/2595] hw/avr/boot: Fix memory leak in avr_load_firmware() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value returned by qemu_find_file() must be freed. This fixes Coverity issue CID 1430449, which points out that the memory returned by qemu_find_file() is leaked. Fixes: Coverity CID 1430449 (RESOURCE_LEAK) Fixes: 7dd8f6fde4 ('hw/avr: Add support for loading ELF/raw binaries') Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael Rolnik Tested-by: Michael Rolnik Reviewed-by: Daniel P. Berrangé Message-Id: <20200714164257.23330-5-f4bug@amsat.org> --- hw/avr/boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/avr/boot.c b/hw/avr/boot.c index 6fbcde4061..d16bb3dbe1 100644 --- a/hw/avr/boot.c +++ b/hw/avr/boot.c @@ -60,7 +60,7 @@ static const char *avr_elf_e_flags_to_cpu_type(uint32_t flags) bool avr_load_firmware(AVRCPU *cpu, MachineState *ms, MemoryRegion *program_mr, const char *firmware) { - const char *filename; + g_autofree char *filename = NULL; int bytes_loaded; uint64_t entry; uint32_t e_flags; From 7a309cc95b862be74711e7a35997daa3f885651a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 14 Jul 2020 18:02:00 +0200 Subject: [PATCH 2440/2595] qom: Change object_get_canonical_path_component() not to malloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit object_get_canonical_path_component() returns a malloced copy of a property name on success, null on failure. 19 of its 25 callers immediately free the returned copy. Change object_get_canonical_path_component() to return the property name directly. Since modifying the name would be wrong, adjust the return type to const char *. Drop the free from the 19 callers become simpler, add the g_strdup() to the other six. Signed-off-by: Markus Armbruster Message-Id: <20200714160202.3121879-4-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Li Qiang --- backends/hostmem.c | 2 +- block/throttle-groups.c | 2 +- gdbstub.c | 2 +- hw/arm/xlnx-zynqmp.c | 6 ++---- hw/block/nvme.c | 5 ++--- hw/core/machine-qmp-cmds.c | 2 +- hw/core/machine.c | 5 ++--- hw/mem/nvdimm.c | 5 ++--- hw/mem/pc-dimm.c | 5 ++--- hw/misc/ivshmem.c | 5 ++--- hw/ppc/spapr_drc.c | 3 +-- hw/ppc/trace-events | 2 +- hw/virtio/virtio-crypto.c | 5 ++--- hw/virtio/virtio-mem.c | 6 ++---- hw/virtio/virtio-pmem.c | 5 ++--- include/qom/object.h | 2 +- iothread.c | 9 ++++----- net/net.c | 6 ++---- qom/object.c | 7 +++---- qom/qom-hmp-cmds.c | 11 ++++------- scsi/pr-manager-helper.c | 3 +-- scsi/pr-manager.c | 2 +- softmmu/memory.c | 2 +- 23 files changed, 41 insertions(+), 61 deletions(-) diff --git a/backends/hostmem.c b/backends/hostmem.c index c614f1bdc1..4bde00e8e7 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -33,7 +33,7 @@ char * host_memory_backend_get_name(HostMemoryBackend *backend) { if (!backend->use_canonical_path) { - return object_get_canonical_path_component(OBJECT(backend)); + return g_strdup(object_get_canonical_path_component(OBJECT(backend))); } return object_get_canonical_path(OBJECT(backend)); diff --git a/block/throttle-groups.c b/block/throttle-groups.c index 03a53c89ea..98fea7fd47 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -771,7 +771,7 @@ static void throttle_group_obj_complete(UserCreatable *obj, Error **errp) /* set group name to object id if it exists */ if (!tg->name && tg->parent_obj.parent) { - tg->name = object_get_canonical_path_component(OBJECT(obj)); + tg->name = g_strdup(object_get_canonical_path_component(OBJECT(obj))); } /* We must have a group name at this point */ assert(tg->name); diff --git a/gdbstub.c b/gdbstub.c index 6950fd243f..f3a318cd7f 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2059,7 +2059,7 @@ static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx) /* Print the CPU model and name in multiprocess mode */ ObjectClass *oc = object_get_class(OBJECT(cpu)); const char *cpu_model = object_class_get_name(oc); - g_autofree char *cpu_name = + const char *cpu_name = object_get_canonical_path_component(OBJECT(cpu)); g_string_printf(rs, "%s %s [%s]", cpu_model, cpu_name, cpu->halted ? "halted " : "running"); diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 772cfa3771..e14323c991 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -190,7 +190,7 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s, qdev_prop_set_uint32(DEVICE(&s->rpu_cluster), "cluster-id", 1); for (i = 0; i < num_rpus; i++) { - char *name; + const char *name; object_initialize_child(OBJECT(&s->rpu_cluster), "rpu-cpu[*]", &s->rpu_cpu[i], @@ -204,7 +204,6 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s, } else { s->boot_cpu_ptr = &s->rpu_cpu[i]; } - g_free(name); object_property_set_bool(OBJECT(&s->rpu_cpu[i]), "reset-hivecs", true, &error_abort); @@ -341,7 +340,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) /* Realize APUs before realizing the GIC. KVM requires this. */ for (i = 0; i < num_apus; i++) { - char *name; + const char *name; object_property_set_int(OBJECT(&s->apu_cpu[i]), "psci-conduit", QEMU_PSCI_CONDUIT_SMC, &error_abort); @@ -354,7 +353,6 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) } else { s->boot_cpu_ptr = &s->apu_cpu[i]; } - g_free(name); object_property_set_bool(OBJECT(&s->apu_cpu[i]), "has_el3", s->secure, NULL); diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 1aee042d4c..3426e17e65 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1397,9 +1397,8 @@ static void nvme_check_constraints(NvmeCtrl *n, Error **errp) if (!n->params.cmb_size_mb && n->pmrdev) { if (host_memory_backend_is_mapped(n->pmrdev)) { - char *path = object_get_canonical_path_component(OBJECT(n->pmrdev)); - error_setg(errp, "can't use already busy memdev: %s", path); - g_free(path); + error_setg(errp, "can't use already busy memdev: %s", + object_get_canonical_path_component(OBJECT(n->pmrdev))); return; } diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index 2c5da8413d..963088b798 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -315,7 +315,7 @@ static int query_memdev(Object *obj, void *opaque) m->value = g_malloc0(sizeof(*m->value)); - m->value->id = object_get_canonical_path_component(obj); + m->value->id = g_strdup(object_get_canonical_path_component(obj)); m->value->has_id = !!m->value->id; m->value->size = object_property_get_uint(obj, "size", diff --git a/hw/core/machine.c b/hw/core/machine.c index eb267b828d..2f881d6d75 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -1073,9 +1073,8 @@ MemoryRegion *machine_consume_memdev(MachineState *machine, MemoryRegion *ret = host_memory_backend_get_memory(backend); if (memory_region_is_mapped(ret)) { - char *path = object_get_canonical_path_component(OBJECT(backend)); - error_report("memory backend %s can't be used multiple times.", path); - g_free(path); + error_report("memory backend %s can't be used multiple times.", + object_get_canonical_path_component(OBJECT(backend))); exit(EXIT_FAILURE); } host_memory_backend_set_mapped(backend, true); diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index d0d6e553cf..e1574bc07c 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -137,13 +137,12 @@ static void nvdimm_prepare_memory_region(NVDIMMDevice *nvdimm, Error **errp) if (size <= nvdimm->label_size || !pmem_size) { HostMemoryBackend *hostmem = dimm->hostmem; - char *path = object_get_canonical_path_component(OBJECT(hostmem)); error_setg(errp, "the size of memdev %s (0x%" PRIx64 ") is too " "small to contain nvdimm label (0x%" PRIx64 ") and " "aligned PMEM (0x%" PRIx64 ")", - path, memory_region_size(mr), nvdimm->label_size, align); - g_free(path); + object_get_canonical_path_component(OBJECT(hostmem)), + memory_region_size(mr), nvdimm->label_size, align); return; } diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 9d3f0b9691..c30351070b 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -179,9 +179,8 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp) error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set"); return; } else if (host_memory_backend_is_mapped(dimm->hostmem)) { - char *path = object_get_canonical_path_component(OBJECT(dimm->hostmem)); - error_setg(errp, "can't use already busy memdev: %s", path); - g_free(path); + error_setg(errp, "can't use already busy memdev: %s", + object_get_canonical_path_component(OBJECT(dimm->hostmem))); return; } if (((nb_numa_nodes > 0) && (dimm->node >= nb_numa_nodes)) || diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index fc128b25e2..2b6882face 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -1037,9 +1037,8 @@ static void ivshmem_plain_realize(PCIDevice *dev, Error **errp) error_setg(errp, "You must specify a 'memdev'"); return; } else if (host_memory_backend_is_mapped(s->hostmem)) { - char *path = object_get_canonical_path_component(OBJECT(s->hostmem)); - error_setg(errp, "can't use already busy memdev: %s", path); - g_free(path); + error_setg(errp, "can't use already busy memdev: %s", + object_get_canonical_path_component(OBJECT(s->hostmem))); return; } diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 43d12bc33a..fe998d8108 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -513,7 +513,7 @@ static void realize(DeviceState *d, Error **errp) SpaprDrc *drc = SPAPR_DR_CONNECTOR(d); Object *root_container; gchar *link_name; - char *child_name; + const char *child_name; trace_spapr_drc_realize(spapr_drc_index(drc)); /* NOTE: we do this as part of realize/unrealize due to the fact @@ -529,7 +529,6 @@ static void realize(DeviceState *d, Error **errp) trace_spapr_drc_realize_child(spapr_drc_index(drc), child_name); object_property_add_alias(root_container, link_name, drc->owner, child_name); - g_free(child_name); g_free(link_name); vmstate_register(VMSTATE_IF(drc), spapr_drc_index(drc), &vmstate_spapr_drc, drc); diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 9ea620f23c..7c0be4102e 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -57,7 +57,7 @@ spapr_drc_detach(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_awaiting_quiesce(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_reset(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_realize(uint32_t index) "drc: 0x%"PRIx32 -spapr_drc_realize_child(uint32_t index, char *childname) "drc: 0x%"PRIx32", child name: %s" +spapr_drc_realize_child(uint32_t index, const char *childname) "drc: 0x%"PRIx32", child name: %s" spapr_drc_realize_complete(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_unrealize(uint32_t index) "drc: 0x%"PRIx32 diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index bd9165c565..6da12e315f 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -786,9 +786,8 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp) error_setg(errp, "'cryptodev' parameter expects a valid object"); return; } else if (cryptodev_backend_is_used(vcrypto->cryptodev)) { - char *path = object_get_canonical_path_component(OBJECT(vcrypto->conf.cryptodev)); - error_setg(errp, "can't use already used cryptodev backend: %s", path); - g_free(path); + error_setg(errp, "can't use already used cryptodev backend: %s", + object_get_canonical_path_component(OBJECT(vcrypto->conf.cryptodev))); return; } diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 65850530e7..c12e9f79b0 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -409,11 +409,9 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) error_setg(errp, "'%s' property is not set", VIRTIO_MEM_MEMDEV_PROP); return; } else if (host_memory_backend_is_mapped(vmem->memdev)) { - char *path = object_get_canonical_path_component(OBJECT(vmem->memdev)); - error_setg(errp, "'%s' property specifies a busy memdev: %s", - VIRTIO_MEM_MEMDEV_PROP, path); - g_free(path); + VIRTIO_MEM_MEMDEV_PROP, + object_get_canonical_path_component(OBJECT(vmem->memdev))); return; } else if (!memory_region_is_ram(&vmem->memdev->mr) || memory_region_is_rom(&vmem->memdev->mr) || diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c index c3374b2f3f..1e0c137497 100644 --- a/hw/virtio/virtio-pmem.c +++ b/hw/virtio/virtio-pmem.c @@ -112,9 +112,8 @@ static void virtio_pmem_realize(DeviceState *dev, Error **errp) } if (host_memory_backend_is_mapped(pmem->memdev)) { - char *path = object_get_canonical_path_component(OBJECT(pmem->memdev)); - error_setg(errp, "can't use already busy memdev: %s", path); - g_free(path); + error_setg(errp, "can't use already busy memdev: %s", + object_get_canonical_path_component(OBJECT(pmem->memdev))); return; } diff --git a/include/qom/object.h b/include/qom/object.h index 79c8f838b6..55d925d2c8 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1462,7 +1462,7 @@ Object *object_get_internal_root(void); * path is the path within the composition tree starting from the root. * %NULL if the object doesn't have a parent (and thus a canonical path). */ -char *object_get_canonical_path_component(const Object *obj); +const char *object_get_canonical_path_component(const Object *obj); /** * object_get_canonical_path: diff --git a/iothread.c b/iothread.c index 0598a6d20d..263ec6e5bc 100644 --- a/iothread.c +++ b/iothread.c @@ -165,7 +165,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp) { Error *local_error = NULL; IOThread *iothread = IOTHREAD(obj); - char *name, *thread_name; + char *thread_name; iothread->stopping = false; iothread->running = true; @@ -195,12 +195,11 @@ static void iothread_complete(UserCreatable *obj, Error **errp) /* This assumes we are called from a thread with useful CPU affinity for us * to inherit. */ - name = object_get_canonical_path_component(OBJECT(obj)); - thread_name = g_strdup_printf("IO %s", name); + thread_name = g_strdup_printf("IO %s", + object_get_canonical_path_component(OBJECT(obj))); qemu_thread_create(&iothread->thread, thread_name, iothread_run, iothread, QEMU_THREAD_JOINABLE); g_free(thread_name); - g_free(name); /* Wait for initialization to complete */ while (iothread->thread_id == -1) { @@ -303,7 +302,7 @@ type_init(iothread_register_types) char *iothread_get_id(IOThread *iothread) { - return object_get_canonical_path_component(OBJECT(iothread)); + return g_strdup(object_get_canonical_path_component(OBJECT(iothread))); } AioContext *iothread_get_aio_context(IOThread *iothread) diff --git a/net/net.c b/net/net.c index 7fddcebaa2..bbaedb3c7a 100644 --- a/net/net.c +++ b/net/net.c @@ -1185,12 +1185,10 @@ void print_net_client(Monitor *mon, NetClientState *nc) monitor_printf(mon, "filters:\n"); } QTAILQ_FOREACH(nf, &nc->filters, next) { - char *path = object_get_canonical_path_component(OBJECT(nf)); - - monitor_printf(mon, " - %s: type=%s", path, + monitor_printf(mon, " - %s: type=%s", + object_get_canonical_path_component(OBJECT(nf)), object_get_typename(OBJECT(nf))); netfilter_print_info(mon, nf); - g_free(path); } } diff --git a/qom/object.c b/qom/object.c index 76f5f75239..00fdf89b3b 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1931,7 +1931,7 @@ object_property_add_const_link(Object *obj, const char *name, NULL, OBJ_PROP_LINK_DIRECT); } -char *object_get_canonical_path_component(const Object *obj) +const char *object_get_canonical_path_component(const Object *obj) { ObjectProperty *prop = NULL; GHashTableIter iter; @@ -1947,7 +1947,7 @@ char *object_get_canonical_path_component(const Object *obj) } if (prop->opaque == obj) { - return g_strdup(prop->name); + return prop->name; } } @@ -1966,7 +1966,7 @@ char *object_get_canonical_path(const Object *obj) } do { - char *component = object_get_canonical_path_component(obj); + const char *component = object_get_canonical_path_component(obj); if (!component) { /* A canonical path must be complete, so discard what was @@ -1978,7 +1978,6 @@ char *object_get_canonical_path(const Object *obj) newpath = g_strdup_printf("/%s%s", component, path ? path : ""); g_free(path); - g_free(component); path = newpath; obj = obj->parent; } while (obj != root); diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index aaacadacca..4032c96089 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -96,10 +96,8 @@ static void print_qom_composition(Monitor *mon, Object *obj, int indent); static int qom_composition_compare(const void *a, const void *b, void *ignore) { - g_autofree char *ac = object_get_canonical_path_component(a); - g_autofree char *bc = object_get_canonical_path_component(b); - - return g_strcmp0(ac, bc); + return g_strcmp0(object_get_canonical_path_component(a), + object_get_canonical_path_component(b)); } static int insert_qom_composition_child(Object *obj, void *opaque) @@ -112,18 +110,17 @@ static int insert_qom_composition_child(Object *obj, void *opaque) static void print_qom_composition(Monitor *mon, Object *obj, int indent) { - char *name; + const char *name; GQueue children; Object *child; if (obj == object_get_root()) { - name = g_strdup(""); + name = ""; } else { name = object_get_canonical_path_component(obj); } monitor_printf(mon, "%*s/%s (%s)\n", indent, "", name, object_get_typename(obj)); - g_free(name); g_queue_init(&children); object_child_foreach(obj, insert_qom_composition_child, &children); diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c index bf62cbec11..5acccfb4e3 100644 --- a/scsi/pr-manager-helper.c +++ b/scsi/pr-manager-helper.c @@ -42,11 +42,10 @@ typedef struct PRManagerHelper { static void pr_manager_send_status_changed_event(PRManagerHelper *pr_mgr) { - char *id = object_get_canonical_path_component(OBJECT(pr_mgr)); + const char *id = object_get_canonical_path_component(OBJECT(pr_mgr)); if (id) { qapi_event_send_pr_manager_status_changed(id, !!pr_mgr->ioc); - g_free(id); } } diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c index 0c866e8698..32b9287e68 100644 --- a/scsi/pr-manager.c +++ b/scsi/pr-manager.c @@ -128,7 +128,7 @@ static int query_one_pr_manager(Object *object, void *opaque) elem = g_new0(PRManagerInfoList, 1); info = g_new0(PRManagerInfo, 1); - info->id = object_get_canonical_path_component(object); + info->id = g_strdup(object_get_canonical_path_component(object)); info->connected = pr_manager_is_connected(pr_mgr); elem->value = info; elem->next = NULL; diff --git a/softmmu/memory.c b/softmmu/memory.c index 9200b20130..af25987518 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -1764,7 +1764,7 @@ const char *memory_region_name(const MemoryRegion *mr) { if (!mr->name) { ((MemoryRegion *)mr)->name = - object_get_canonical_path_component(OBJECT(mr)); + g_strdup(object_get_canonical_path_component(OBJECT(mr))); } return mr->name; } From 5bd929d2fff068f829688f27b54f2f159ff06eb6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 14 Jul 2020 18:02:01 +0200 Subject: [PATCH 2441/2595] qom: Document object_get_canonical_path() returns malloced string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Message-Id: <20200714160202.3121879-5-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- include/qom/object.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 55d925d2c8..0f3a60617c 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1467,8 +1467,9 @@ const char *object_get_canonical_path_component(const Object *obj); /** * object_get_canonical_path: * - * Returns: The canonical path for a object. This is the path within the - * composition tree starting from the root. + * Returns: The canonical path for a object, newly allocated. This is + * the path within the composition tree starting from the root. Use + * g_free() to free it. */ char *object_get_canonical_path(const Object *obj); From bae127d4dcf6158c5042e2eee9582430839a9967 Mon Sep 17 00:00:00 2001 From: Antoine Damhet Date: Fri, 17 Jul 2020 15:56:04 +0200 Subject: [PATCH 2442/2595] file-posix: Handle `EINVAL` fallocate return value The `detect-zeroes=unmap` option may issue unaligned `FALLOC_FL_PUNCH_HOLE` requests, raw block devices can (and will) return `EINVAL`, qemu should then write the zeroes to the blockdev instead of issuing an `IO_ERROR`. The problem can be reprodced like this: $ qemu-io -c 'write -P 0 42 1234' --image-opts driver=host_device,filename=/dev/loop0,detect-zeroes=unmap write failed: Invalid argument Signed-off-by: Antoine Damhet Message-Id: <20200717135603.51180-1-antoine.damhet@blade-group.com> Signed-off-by: Kevin Wolf --- block/file-posix.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/block/file-posix.c b/block/file-posix.c index 8cc39a1ef6..9a00d4190a 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1698,7 +1698,11 @@ static int handle_aiocb_write_zeroes_unmap(void *opaque) #ifdef CONFIG_FALLOCATE_PUNCH_HOLE int ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, aiocb->aio_offset, aiocb->aio_nbytes); - if (ret != -ENOTSUP) { + switch (ret) { + case -ENOTSUP: + case -EINVAL: + break; + default: return ret; } #endif From 61b3043965fe3552ee2684a97e7cc809ca7a71b3 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 21 Jul 2020 15:55:19 +0200 Subject: [PATCH 2443/2595] qcow2: Implement v2 zero writes with discard if possible qcow2 version 2 images don't support the zero flag for clusters, so for write_zeroes requests, we return -ENOTSUP and get explicit zero buffer writes. If the image doesn't have a backing file, we can do better: Just discard the respective clusters. This is relevant for 'qemu-img convert -O qcow2 -n', where qemu-img has to assume that the existing target image may contain any data, so it has to write zeroes. Without this patch, this results in a fully allocated target image, even if the source image was empty. Reported-by: Nir Soffer Signed-off-by: Kevin Wolf Message-Id: <20200721135520.72355-2-kwolf@redhat.com> Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block/qcow2-cluster.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 4b5fc8c4a7..a677ba9f5c 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1797,8 +1797,15 @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset, assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) || end_offset >= bs->total_sectors << BDRV_SECTOR_BITS); - /* The zero flag is only supported by version 3 and newer */ + /* + * The zero flag is only supported by version 3 and newer. However, if we + * have no backing file, we can resort to discard in version 2. + */ if (s->qcow_version < 3) { + if (!bs->backing) { + return qcow2_cluster_discard(bs, offset, bytes, + QCOW2_DISCARD_REQUEST, false); + } return -ENOTSUP; } From a3ad58342a9d88d1baafc0aee39302f79faad480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 21 Jul 2020 15:05:51 +0200 Subject: [PATCH 2444/2595] hw/nvram/fw_cfg: Simplify fw_cfg_add_from_generator() error propagation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document FWCfgDataGeneratorClass::get_data() return NULL on error, and non-NULL on success. This allow us to simplify fw_cfg_add_from_generator(). Since we don't need a local variable to propagate the error, we can remove the ERRP_GUARD() macro. Suggested-by: Markus Armbruster Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Markus Armbruster Message-Id: <20200721131911.27380-2-philmd@redhat.com> --- hw/nvram/fw_cfg.c | 3 +-- include/hw/nvram/fw_cfg.h | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 3b1811d3bf..dfa1f2012a 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -1035,7 +1035,6 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void fw_cfg_add_from_generator(FWCfgState *s, const char *filename, const char *gen_id, Error **errp) { - ERRP_GUARD(); FWCfgDataGeneratorClass *klass; GByteArray *array; Object *obj; @@ -1053,7 +1052,7 @@ void fw_cfg_add_from_generator(FWCfgState *s, const char *filename, } klass = FW_CFG_DATA_GENERATOR_GET_CLASS(obj); array = klass->get_data(obj, errp); - if (*errp) { + if (!array) { return; } size = array->len; diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index 11feae3177..bbcf405649 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -32,7 +32,9 @@ typedef struct FWCfgDataGeneratorClass { * @obj: the object implementing this interface * @errp: pointer to a NULL-initialized error object * - * Returns: reference to a byte array containing the data. + * Returns: reference to a byte array containing the data on success, + * or NULL on error. + * * The caller should release the reference when no longer * required. */ From 077195187b47d83418e5fb521c89d7881fab3049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 20 Jul 2020 14:20:15 +0200 Subject: [PATCH 2445/2595] hw/nvram/fw_cfg: Let fw_cfg_add_from_generator() return boolean value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commits b6d7e9b66f..a43770df5d simplified the error propagation. Similarly to commit 6fd5bef10b "qom: Make functions taking Error** return bool, not void", let fw_cfg_add_from_generator() return a boolean value, not void. This allow to simplify parse_fw_cfg() and fixes the error handling issue reported by Coverity (CID 1430396): In parse_fw_cfg(): Variable assigned once to a constant guards dead code. Local variable local_err is assigned only once, to a constant value, making it effectively constant throughout its scope. If this is not the intent, examine the logic to see if there is a missing assignment that would make local_err not remain constant. It's the call of fw_cfg_add_from_generator(): Error *local_err = NULL; fw_cfg_add_from_generator(fw_cfg, name, gen_id, errp); if (local_err) { error_propagate(errp, local_err); return -1; } return 0; If it fails, parse_fw_cfg() sets an error and returns 0, which is wrong. Harmless, because the only caller passes &error_fatal. Reported-by: Peter Maydell Fixes: Coverity CID 1430396: 'Constant' variable guards dead code (DEADCODE) Fixes: 6552d87c48 ("softmmu/vl: Let -fw_cfg option take a 'gen_id' argument") Reviewed-by: Laszlo Ersek Reviewed-by: Markus Armbruster Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200721131911.27380-3-philmd@redhat.com> --- hw/nvram/fw_cfg.c | 10 ++++++---- include/hw/nvram/fw_cfg.h | 4 +++- softmmu/vl.c | 6 +----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index dfa1f2012a..f3a4728288 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -1032,7 +1032,7 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename, return NULL; } -void fw_cfg_add_from_generator(FWCfgState *s, const char *filename, +bool fw_cfg_add_from_generator(FWCfgState *s, const char *filename, const char *gen_id, Error **errp) { FWCfgDataGeneratorClass *klass; @@ -1043,20 +1043,22 @@ void fw_cfg_add_from_generator(FWCfgState *s, const char *filename, obj = object_resolve_path_component(object_get_objects_root(), gen_id); if (!obj) { error_setg(errp, "Cannot find object ID '%s'", gen_id); - return; + return false; } if (!object_dynamic_cast(obj, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE)) { error_setg(errp, "Object ID '%s' is not a '%s' subclass", gen_id, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE); - return; + return false; } klass = FW_CFG_DATA_GENERATOR_GET_CLASS(obj); array = klass->get_data(obj, errp); if (!array) { - return; + return false; } size = array->len; fw_cfg_add_file(s, filename, g_byte_array_free(array, TRUE), size); + + return true; } static void fw_cfg_machine_reset(void *opaque) diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index bbcf405649..f190c428e8 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -304,8 +304,10 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data, * will be used; also, a new entry will be added to the file directory * structure residing at key value FW_CFG_FILE_DIR, containing the item name, * data size, and assigned selector key value. + * + * Returns: %true on success, %false on error. */ -void fw_cfg_add_from_generator(FWCfgState *s, const char *filename, +bool fw_cfg_add_from_generator(FWCfgState *s, const char *filename, const char *gen_id, Error **errp); FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, diff --git a/softmmu/vl.c b/softmmu/vl.c index f476ef89ed..3416241557 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2070,11 +2070,7 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) size = strlen(str); /* NUL terminator NOT included in fw_cfg blob */ buf = g_memdup(str, size); } else if (nonempty_str(gen_id)) { - Error *local_err = NULL; - - fw_cfg_add_from_generator(fw_cfg, name, gen_id, errp); - if (local_err) { - error_propagate(errp, local_err); + if (!fw_cfg_add_from_generator(fw_cfg, name, gen_id, errp)) { return -1; } return 0; From 029afc4e76041e1a320530d97f99122a1b3d5da2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 14 Jul 2020 18:01:58 +0200 Subject: [PATCH 2446/2595] qdev: Fix device_add DRIVER,help to print to monitor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Help on device properties gets printed to stdout instead of the monitor. If you have the monitor anywhere else, no help for you. Broken when commit e1043d674d "qdev: use object_property_help()" accidentally switched from qemu_printf() to printf(). Switch right back. Fixes: e1043d674d792ff64aebae1a3eafc08b38a8a085 Cc: Marc-André Lureau Cc: qemu-stable@nongnu.org Signed-off-by: Markus Armbruster Message-Id: <20200714160202.3121879-2-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Li Qiang Reviewed-by: Dr. David Alan Gilbert --- qdev-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qdev-monitor.c b/qdev-monitor.c index 71ebce19df..e9b7228480 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -300,7 +300,7 @@ int qdev_device_help(QemuOpts *opts) } g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0); for (i = 0; i < array->len; i++) { - printf("%s\n", (char *)array->pdata[i]); + qemu_printf("%s\n", (char *)array->pdata[i]); } g_ptr_array_set_free_func(array, g_free); g_ptr_array_free(array, true); From 0dde9fd12fd39762ff68fca80d2f0a735d66e7bd Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 14 Jul 2020 18:02:02 +0200 Subject: [PATCH 2447/2595] qom: Make info qom-tree sort children more efficiently Commit e8c9e65816 "qom: Make "info qom-tree" show children sorted" sorts children the simple, stupid, quadratic way. I thought the number of children would be small enough for this not to matter. I was wrong: there are outliers with several hundred children, e.g ARM machines nuri and smdkc210 each have a node with 513 children. While n^2 sorting isn't noticeable in normal, human usage even for n=513, it can be quite noticeable in certain automated tests. In particular, the sort made device-introspect-test even slower. Commit 3e7b80f84d "tests: improve performance of device-introspect-test" just fixed that by cutting back its excessive use of "info qom-tree". Sorting more efficiently makes sense regardless, so do it. Signed-off-by: Markus Armbruster Message-Id: <20200714160202.3121879-6-armbru@redhat.com> Reviewed-by: Dr. David Alan Gilbert --- qom/qom-hmp-cmds.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index 4032c96089..8861a109d5 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -94,25 +94,23 @@ typedef struct QOMCompositionState { static void print_qom_composition(Monitor *mon, Object *obj, int indent); -static int qom_composition_compare(const void *a, const void *b, void *ignore) +static int qom_composition_compare(const void *a, const void *b) { - return g_strcmp0(object_get_canonical_path_component(a), - object_get_canonical_path_component(b)); + return g_strcmp0(object_get_canonical_path_component(*(Object **)a), + object_get_canonical_path_component(*(Object **)b)); } static int insert_qom_composition_child(Object *obj, void *opaque) { - GQueue *children = opaque; - - g_queue_insert_sorted(children, obj, qom_composition_compare, NULL); + g_array_append_val(opaque, obj); return 0; } static void print_qom_composition(Monitor *mon, Object *obj, int indent) { + GArray *children = g_array_new(false, false, sizeof(Object *)); const char *name; - GQueue children; - Object *child; + int i; if (obj == object_get_root()) { name = ""; @@ -122,11 +120,14 @@ static void print_qom_composition(Monitor *mon, Object *obj, int indent) monitor_printf(mon, "%*s/%s (%s)\n", indent, "", name, object_get_typename(obj)); - g_queue_init(&children); - object_child_foreach(obj, insert_qom_composition_child, &children); - while ((child = g_queue_pop_head(&children))) { - print_qom_composition(mon, child, indent + 2); + object_child_foreach(obj, insert_qom_composition_child, children); + g_array_sort(children, qom_composition_compare); + + for (i = 0; i < children->len; i++) { + print_qom_composition(mon, g_array_index(children, Object *, i), + indent + 2); } + g_array_free(children, TRUE); } void hmp_info_qom_tree(Monitor *mon, const QDict *dict) From 4a01e27ddcb5921efd68820d05d85ba71293fea6 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 21 Jul 2020 15:55:20 +0200 Subject: [PATCH 2448/2595] iotests: Test sparseness for qemu-img convert -n Signed-off-by: Kevin Wolf Message-Id: <20200721135520.72355-3-kwolf@redhat.com> Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- tests/qemu-iotests/122 | 30 ++++++++++++++++++++++++++++++ tests/qemu-iotests/122.out | 17 +++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 index dfd1cd05d6..0f3d4ca851 100755 --- a/tests/qemu-iotests/122 +++ b/tests/qemu-iotests/122 @@ -281,6 +281,36 @@ $QEMU_IMG convert -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG".orig $QEMU_IMG compare "$TEST_IMG" "$TEST_IMG".orig +echo +echo '=== -n to an empty image ===' +echo + +TEST_IMG="$TEST_IMG".orig _make_test_img 64M + +# Convert with -n, which should not result in a fully allocated image, not even +# with compat=0.10 (because the target doesn't have a backing file) +for compat in "1.1" "0.10"; do + IMGOPTS="compat=$compat" _make_test_img 64M + $QEMU_IMG convert -O $IMGFMT -n "$TEST_IMG".orig "$TEST_IMG" + $QEMU_IMG map --output=json "$TEST_IMG" +done + +echo +echo '=== -n to an empty image with a backing file ===' +echo + +TEST_IMG="$TEST_IMG".orig _make_test_img 64M +TEST_IMG="$TEST_IMG".base _make_test_img 64M + +# Convert with -n, which should still not result in a fully allocated image for +# compat=1.1 (because it can use zero clusters), but it should be fully +# allocated with compat=0.10 +for compat in "1.1" "0.10"; do + IMGOPTS="compat=$compat" _make_test_img -b "$TEST_IMG".base -F $IMGFMT 64M + $QEMU_IMG convert -O $IMGFMT -n "$TEST_IMG".orig "$TEST_IMG" + $QEMU_IMG map --output=json "$TEST_IMG" +done + echo echo '=== -n -B to an image without a backing file ===' echo diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out index f1f195ed77..3a3e121d57 100644 --- a/tests/qemu-iotests/122.out +++ b/tests/qemu-iotests/122.out @@ -229,6 +229,23 @@ wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Images are identical. +=== -n to an empty image === + +Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}] +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}] + +=== -n to an empty image with a backing file === + +Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}] +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true, "offset": 327680}] + === -n -B to an image without a backing file === Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 From c8004fe6bbfc0d9c2e7b942c418a85efb3ac4b00 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 21 Jul 2020 20:28:59 +0100 Subject: [PATCH 2449/2595] Update version for v5.1.0-rc1 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e427b98203..023d5c9cfb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.90 +5.0.91 From dba04c3488c4699f5afe96f66e448b1d447cf3fb Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Mon, 20 Jul 2020 19:06:27 +0300 Subject: [PATCH 2450/2595] acpi: accept byte and word access to core ACPI registers All ISA registers should be accessible as bytes, words or dwords (if wide enough). Fix the access constraints for acpi-pm-evt, acpi-pm-tmr & acpi-cnt registers. Fixes: 5d971f9e67 (memory: Revert "memory: accept mismatching sizes in memory_region_access_valid") Fixes: afafe4bbe0 (apci: switch cnt to memory api) Fixes: 77d58b1e47 (apci: switch timer to memory api) Fixes: b5a7c024d2 (apci: switch evt to memory api) Buglink: https://lore.kernel.org/xen-devel/20200630170913.123646-1-anthony.perard@citrix.com/T/ Buglink: https://bugs.debian.org/964793 BugLink: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=964247 BugLink: https://bugs.launchpad.net/bugs/1886318 Reported-By: Simon John Signed-off-by: Michael Tokarev Message-Id: <20200720160627.15491-1-mjt@msgid.tls.msk.ru> Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/acpi/core.c b/hw/acpi/core.c index f6d9ec4f13..ac06db3450 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -458,7 +458,8 @@ static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val, static const MemoryRegionOps acpi_pm_evt_ops = { .read = acpi_pm_evt_read, .write = acpi_pm_evt_write, - .valid.min_access_size = 2, + .impl.min_access_size = 2, + .valid.min_access_size = 1, .valid.max_access_size = 2, .endianness = DEVICE_LITTLE_ENDIAN, }; @@ -527,7 +528,8 @@ static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val, static const MemoryRegionOps acpi_pm_tmr_ops = { .read = acpi_pm_tmr_read, .write = acpi_pm_tmr_write, - .valid.min_access_size = 4, + .impl.min_access_size = 4, + .valid.min_access_size = 1, .valid.max_access_size = 4, .endianness = DEVICE_LITTLE_ENDIAN, }; @@ -599,7 +601,8 @@ static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, static const MemoryRegionOps acpi_pm_cnt_ops = { .read = acpi_pm_cnt_read, .write = acpi_pm_cnt_write, - .valid.min_access_size = 2, + .impl.min_access_size = 2, + .valid.min_access_size = 1, .valid.max_access_size = 2, .endianness = DEVICE_LITTLE_ENDIAN, }; From cf4e3d000e438d04077a56c401b41f3336a2a09d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Jul 2020 14:11:53 +0200 Subject: [PATCH 2451/2595] virtio: Drop broken and superfluous object_property_set_link() virtio_crypto_pci_realize() and copies the value of vcrypto->vdev's property "cryptodev" to vcrypto's property: object_property_set_link(OBJECT(vrng), "rng", OBJECT(vrng->vdev.conf.rng), NULL); Since it does so only after realize, this always fails, but the error is ignored. It's actually superfluous: vcrypto's property is an alias of vcrypto->vdev's property, created by virtio_instance_init_common(). Drop the call. Same for virtio_ccw_crypto_realize(), virtio_rng_pci_realize(), virtio_ccw_rng_realize(). Signed-off-by: Markus Armbruster Message-Id: <20200721121153.1128844-1-armbru@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/s390x/virtio-ccw-crypto.c | 3 --- hw/s390x/virtio-ccw-rng.c | 3 --- hw/virtio/virtio-crypto-pci.c | 2 -- hw/virtio/virtio-rng-pci.c | 3 --- 4 files changed, 11 deletions(-) diff --git a/hw/s390x/virtio-ccw-crypto.c b/hw/s390x/virtio-ccw-crypto.c index 570c0333fc..358c74fb4b 100644 --- a/hw/s390x/virtio-ccw-crypto.c +++ b/hw/s390x/virtio-ccw-crypto.c @@ -23,9 +23,6 @@ static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) if (!qdev_realize(vdev, BUS(&ccw_dev->bus), errp)) { return; } - - object_property_set_link(OBJECT(vdev), "cryptodev", - OBJECT(dev->vdev.conf.cryptodev), NULL); } static void virtio_ccw_crypto_instance_init(Object *obj) diff --git a/hw/s390x/virtio-ccw-rng.c b/hw/s390x/virtio-ccw-rng.c index 4bb8c16d79..2e3a9da5e8 100644 --- a/hw/s390x/virtio-ccw-rng.c +++ b/hw/s390x/virtio-ccw-rng.c @@ -24,9 +24,6 @@ static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) if (!qdev_realize(vdev, BUS(&ccw_dev->bus), errp)) { return; } - - object_property_set_link(OBJECT(dev), "rng", OBJECT(dev->vdev.conf.rng), - NULL); } static void virtio_ccw_rng_instance_init(Object *obj) diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c index f1cc979d33..198f86e08c 100644 --- a/hw/virtio/virtio-crypto-pci.c +++ b/hw/virtio/virtio-crypto-pci.c @@ -57,8 +57,6 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) if (!qdev_realize(vdev, BUS(&vpci_dev->bus), errp)) { return; } - object_property_set_link(OBJECT(vcrypto), "cryptodev", - OBJECT(vcrypto->vdev.conf.cryptodev), NULL); } static void virtio_crypto_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c index 2f0b529b62..8afbb4c209 100644 --- a/hw/virtio/virtio-rng-pci.c +++ b/hw/virtio/virtio-rng-pci.c @@ -38,9 +38,6 @@ static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) if (!qdev_realize(vdev, BUS(&vpci_dev->bus), errp)) { return; } - - object_property_set_link(OBJECT(vrng), "rng", OBJECT(vrng->vdev.conf.rng), - NULL); } static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) From 20a4da0f23078deeff5ea6d1e12f47d968d7c3c9 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 20 Jul 2020 10:51:15 -0700 Subject: [PATCH 2452/2595] virtio-balloon: Prevent guest from starting a report when we didn't request one Based on code review it appears possible for the driver to force the device out of a stopped state when hinting by repeating the last ID it was provided. Prevent this by only allowing a transition to the start state when we are in the requested state. This way the driver is only allowed to send one descriptor that will transition the device into the start state. All others will leave it in the stop state once it has finished. Fixes: c13c4153f76d ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT") Acked-by: David Hildenbrand Signed-off-by: Alexander Duyck Message-Id: <20200720175115.21935.99563.stgit@localhost.localdomain> Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index e670f1e595..ce70adcc69 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -526,7 +526,8 @@ static bool get_free_page_hints(VirtIOBalloon *dev) ret = false; goto out; } - if (id == dev->free_page_report_cmd_id) { + if (dev->free_page_report_status == FREE_PAGE_REPORT_S_REQUESTED && + id == dev->free_page_report_cmd_id) { dev->free_page_report_status = FREE_PAGE_REPORT_S_START; } else { /* From 1a83e0b9c492a0eaeacd6fbb858fc81d04ab9c3e Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 20 Jul 2020 10:51:22 -0700 Subject: [PATCH 2453/2595] virtio-balloon: Add locking to prevent possible race when starting hinting There is already locking in place when we are stopping free page hinting but there is not similar protections in place when we start. I can only assume this was overlooked as in most cases the page hinting should not be occurring when we are starting the hinting, however there is still a chance we could be processing hints by the time we get back around to restarting the hinting so we are better off making sure to protect the state with the mutex lock rather than just updating the value with no protections. Based on feedback from Peter Maydell this issue had also been spotted by Coverity: CID 1430269 Acked-by: David Hildenbrand Signed-off-by: Alexander Duyck Message-Id: <20200720175122.21935.78013.stgit@localhost.localdomain> Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index ce70adcc69..6e2d129340 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -592,6 +592,8 @@ static void virtio_balloon_free_page_start(VirtIOBalloon *s) return; } + qemu_mutex_lock(&s->free_page_lock); + if (s->free_page_report_cmd_id == UINT_MAX) { s->free_page_report_cmd_id = VIRTIO_BALLOON_FREE_PAGE_REPORT_CMD_ID_MIN; @@ -600,6 +602,8 @@ static void virtio_balloon_free_page_start(VirtIOBalloon *s) } s->free_page_report_status = FREE_PAGE_REPORT_S_REQUESTED; + qemu_mutex_unlock(&s->free_page_lock); + virtio_notify_config(vdev); } From 3219b42f025d4d7a9c463235e9f937ab38067de3 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 20 Jul 2020 10:51:28 -0700 Subject: [PATCH 2454/2595] virtio-balloon: Replace free page hinting references to 'report' with 'hint' Recently a feature named Free Page Reporting was added to the virtio balloon. In order to avoid any confusion we should drop the use of the word 'report' when referring to Free Page Hinting. So what this patch does is go through and replace all instances of 'report' with 'hint" when we are referring to free page hinting. Acked-by: David Hildenbrand Signed-off-by: Alexander Duyck Message-Id: <20200720175128.21935.93927.stgit@localhost.localdomain> Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 76 +++++++++++++++--------------- include/hw/virtio/virtio-balloon.h | 20 ++++---- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 6e2d129340..22cb5df717 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -526,22 +526,22 @@ static bool get_free_page_hints(VirtIOBalloon *dev) ret = false; goto out; } - if (dev->free_page_report_status == FREE_PAGE_REPORT_S_REQUESTED && - id == dev->free_page_report_cmd_id) { - dev->free_page_report_status = FREE_PAGE_REPORT_S_START; + if (dev->free_page_hint_status == FREE_PAGE_HINT_S_REQUESTED && + id == dev->free_page_hint_cmd_id) { + dev->free_page_hint_status = FREE_PAGE_HINT_S_START; } else { /* * Stop the optimization only when it has started. This * avoids a stale stop sign for the previous command. */ - if (dev->free_page_report_status == FREE_PAGE_REPORT_S_START) { - dev->free_page_report_status = FREE_PAGE_REPORT_S_STOP; + if (dev->free_page_hint_status == FREE_PAGE_HINT_S_START) { + dev->free_page_hint_status = FREE_PAGE_HINT_S_STOP; } } } if (elem->in_num) { - if (dev->free_page_report_status == FREE_PAGE_REPORT_S_START) { + if (dev->free_page_hint_status == FREE_PAGE_HINT_S_START) { qemu_guest_free_page_hint(elem->in_sg[0].iov_base, elem->in_sg[0].iov_len); } @@ -567,11 +567,11 @@ static void virtio_ballloon_get_free_page_hints(void *opaque) qemu_mutex_unlock(&dev->free_page_lock); virtio_notify(vdev, vq); /* - * Start to poll the vq once the reporting started. Otherwise, continue + * Start to poll the vq once the hinting started. Otherwise, continue * only when there are entries on the vq, which need to be given back. */ } while (continue_to_get_hints || - dev->free_page_report_status == FREE_PAGE_REPORT_S_START); + dev->free_page_hint_status == FREE_PAGE_HINT_S_START); virtio_queue_set_notification(vq, 1); } @@ -594,14 +594,14 @@ static void virtio_balloon_free_page_start(VirtIOBalloon *s) qemu_mutex_lock(&s->free_page_lock); - if (s->free_page_report_cmd_id == UINT_MAX) { - s->free_page_report_cmd_id = - VIRTIO_BALLOON_FREE_PAGE_REPORT_CMD_ID_MIN; + if (s->free_page_hint_cmd_id == UINT_MAX) { + s->free_page_hint_cmd_id = + VIRTIO_BALLOON_FREE_PAGE_HINT_CMD_ID_MIN; } else { - s->free_page_report_cmd_id++; + s->free_page_hint_cmd_id++; } - s->free_page_report_status = FREE_PAGE_REPORT_S_REQUESTED; + s->free_page_hint_status = FREE_PAGE_HINT_S_REQUESTED; qemu_mutex_unlock(&s->free_page_lock); virtio_notify_config(vdev); @@ -611,18 +611,18 @@ static void virtio_balloon_free_page_stop(VirtIOBalloon *s) { VirtIODevice *vdev = VIRTIO_DEVICE(s); - if (s->free_page_report_status != FREE_PAGE_REPORT_S_STOP) { + if (s->free_page_hint_status != FREE_PAGE_HINT_S_STOP) { /* * The lock also guarantees us that the * virtio_ballloon_get_free_page_hints exits after the - * free_page_report_status is set to S_STOP. + * free_page_hint_status is set to S_STOP. */ qemu_mutex_lock(&s->free_page_lock); /* - * The guest hasn't done the reporting, so host sends a notification - * to the guest to actively stop the reporting. + * The guest isn't done hinting, so send a notification + * to the guest to actively stop the hinting. */ - s->free_page_report_status = FREE_PAGE_REPORT_S_STOP; + s->free_page_hint_status = FREE_PAGE_HINT_S_STOP; qemu_mutex_unlock(&s->free_page_lock); virtio_notify_config(vdev); } @@ -632,20 +632,20 @@ static void virtio_balloon_free_page_done(VirtIOBalloon *s) { VirtIODevice *vdev = VIRTIO_DEVICE(s); - if (s->free_page_report_status != FREE_PAGE_REPORT_S_DONE) { + if (s->free_page_hint_status != FREE_PAGE_HINT_S_DONE) { /* See virtio_balloon_free_page_stop() */ qemu_mutex_lock(&s->free_page_lock); - s->free_page_report_status = FREE_PAGE_REPORT_S_DONE; + s->free_page_hint_status = FREE_PAGE_HINT_S_DONE; qemu_mutex_unlock(&s->free_page_lock); virtio_notify_config(vdev); } } static int -virtio_balloon_free_page_report_notify(NotifierWithReturn *n, void *data) +virtio_balloon_free_page_hint_notify(NotifierWithReturn *n, void *data) { VirtIOBalloon *dev = container_of(n, VirtIOBalloon, - free_page_report_notify); + free_page_hint_notify); VirtIODevice *vdev = VIRTIO_DEVICE(dev); PrecopyNotifyData *pnd = data; @@ -703,7 +703,7 @@ static size_t virtio_balloon_config_size(VirtIOBalloon *s) if (virtio_has_feature(features, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) { return offsetof(struct virtio_balloon_config, poison_val); } - return offsetof(struct virtio_balloon_config, free_page_report_cmd_id); + return offsetof(struct virtio_balloon_config, free_page_hint_cmd_id); } static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data) @@ -715,14 +715,14 @@ static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data) config.actual = cpu_to_le32(dev->actual); config.poison_val = cpu_to_le32(dev->poison_val); - if (dev->free_page_report_status == FREE_PAGE_REPORT_S_REQUESTED) { - config.free_page_report_cmd_id = - cpu_to_le32(dev->free_page_report_cmd_id); - } else if (dev->free_page_report_status == FREE_PAGE_REPORT_S_STOP) { - config.free_page_report_cmd_id = + if (dev->free_page_hint_status == FREE_PAGE_HINT_S_REQUESTED) { + config.free_page_hint_cmd_id = + cpu_to_le32(dev->free_page_hint_cmd_id); + } else if (dev->free_page_hint_status == FREE_PAGE_HINT_S_STOP) { + config.free_page_hint_cmd_id = cpu_to_le32(VIRTIO_BALLOON_CMD_ID_STOP); - } else if (dev->free_page_report_status == FREE_PAGE_REPORT_S_DONE) { - config.free_page_report_cmd_id = + } else if (dev->free_page_hint_status == FREE_PAGE_HINT_S_DONE) { + config.free_page_hint_cmd_id = cpu_to_le32(VIRTIO_BALLOON_CMD_ID_DONE); } @@ -835,14 +835,14 @@ static int virtio_balloon_post_load_device(void *opaque, int version_id) return 0; } -static const VMStateDescription vmstate_virtio_balloon_free_page_report = { +static const VMStateDescription vmstate_virtio_balloon_free_page_hint = { .name = "virtio-balloon-device/free-page-report", .version_id = 1, .minimum_version_id = 1, .needed = virtio_balloon_free_page_support, .fields = (VMStateField[]) { - VMSTATE_UINT32(free_page_report_cmd_id, VirtIOBalloon), - VMSTATE_UINT32(free_page_report_status, VirtIOBalloon), + VMSTATE_UINT32(free_page_hint_cmd_id, VirtIOBalloon), + VMSTATE_UINT32(free_page_hint_status, VirtIOBalloon), VMSTATE_END_OF_LIST() } }; @@ -869,7 +869,7 @@ static const VMStateDescription vmstate_virtio_balloon_device = { VMSTATE_END_OF_LIST() }, .subsections = (const VMStateDescription * []) { - &vmstate_virtio_balloon_free_page_report, + &vmstate_virtio_balloon_free_page_hint, &vmstate_virtio_balloon_page_poison, NULL } @@ -908,7 +908,7 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) VIRTIO_BALLOON_F_FREE_PAGE_HINT)) { s->free_page_vq = virtio_add_queue(vdev, VIRTQUEUE_MAX_SIZE, virtio_balloon_handle_free_page_vq); - precopy_add_notifier(&s->free_page_report_notify); + precopy_add_notifier(&s->free_page_hint_notify); object_ref(OBJECT(s->iothread)); s->free_page_bh = aio_bh_new(iothread_get_aio_context(s->iothread), @@ -932,7 +932,7 @@ static void virtio_balloon_device_unrealize(DeviceState *dev) qemu_bh_delete(s->free_page_bh); object_unref(OBJECT(s->iothread)); virtio_balloon_free_page_stop(s); - precopy_remove_notifier(&s->free_page_report_notify); + precopy_remove_notifier(&s->free_page_hint_notify); } balloon_stats_destroy_timer(s); qemu_remove_balloon_handler(s); @@ -1004,8 +1004,8 @@ static void virtio_balloon_instance_init(Object *obj) qemu_mutex_init(&s->free_page_lock); qemu_cond_init(&s->free_page_cond); - s->free_page_report_cmd_id = VIRTIO_BALLOON_FREE_PAGE_REPORT_CMD_ID_MIN; - s->free_page_report_notify.notify = virtio_balloon_free_page_report_notify; + s->free_page_hint_cmd_id = VIRTIO_BALLOON_FREE_PAGE_HINT_CMD_ID_MIN; + s->free_page_hint_notify.notify = virtio_balloon_free_page_hint_notify; object_property_add(obj, "guest-stats", "guest statistics", balloon_stats_get_all, NULL, NULL, s); diff --git a/include/hw/virtio/virtio-balloon.h b/include/hw/virtio/virtio-balloon.h index d49fef00ce..28fd2b3960 100644 --- a/include/hw/virtio/virtio-balloon.h +++ b/include/hw/virtio/virtio-balloon.h @@ -23,7 +23,7 @@ #define VIRTIO_BALLOON(obj) \ OBJECT_CHECK(VirtIOBalloon, (obj), TYPE_VIRTIO_BALLOON) -#define VIRTIO_BALLOON_FREE_PAGE_REPORT_CMD_ID_MIN 0x80000000 +#define VIRTIO_BALLOON_FREE_PAGE_HINT_CMD_ID_MIN 0x80000000 typedef struct virtio_balloon_stat VirtIOBalloonStat; @@ -33,20 +33,20 @@ typedef struct virtio_balloon_stat_modern { uint64_t val; } VirtIOBalloonStatModern; -enum virtio_balloon_free_page_report_status { - FREE_PAGE_REPORT_S_STOP = 0, - FREE_PAGE_REPORT_S_REQUESTED = 1, - FREE_PAGE_REPORT_S_START = 2, - FREE_PAGE_REPORT_S_DONE = 3, +enum virtio_balloon_free_page_hint_status { + FREE_PAGE_HINT_S_STOP = 0, + FREE_PAGE_HINT_S_REQUESTED = 1, + FREE_PAGE_HINT_S_START = 2, + FREE_PAGE_HINT_S_DONE = 3, }; typedef struct VirtIOBalloon { VirtIODevice parent_obj; VirtQueue *ivq, *dvq, *svq, *free_page_vq, *reporting_vq; - uint32_t free_page_report_status; + uint32_t free_page_hint_status; uint32_t num_pages; uint32_t actual; - uint32_t free_page_report_cmd_id; + uint32_t free_page_hint_cmd_id; uint64_t stats[VIRTIO_BALLOON_S_NR]; VirtQueueElement *stats_vq_elem; size_t stats_vq_offset; @@ -55,7 +55,7 @@ typedef struct VirtIOBalloon { QEMUBH *free_page_bh; /* * Lock to synchronize threads to access the free page reporting related - * fields (e.g. free_page_report_status). + * fields (e.g. free_page_hint_status). */ QemuMutex free_page_lock; QemuCond free_page_cond; @@ -64,7 +64,7 @@ typedef struct VirtIOBalloon { * stopped. */ bool block_iothread; - NotifierWithReturn free_page_report_notify; + NotifierWithReturn free_page_hint_notify; int64_t stats_last_update; int64_t stats_poll_interval; uint32_t host_features; From 7c78bdd7a3d0086179331f10d1f6f8cdac34731a Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 7 Jul 2020 12:54:45 +0200 Subject: [PATCH 2455/2595] virtio: list legacy-capable devices Several types of virtio devices had already been around before the virtio standard was specified. These devices support virtio in legacy (and transitional) mode. Devices that have been added in the virtio standard are considered non-transitional (i.e. with no support for legacy virtio). Provide a helper function so virtio transports can figure that out easily. Signed-off-by: Cornelia Huck Message-Id: <20200707105446.677966-2-cohuck@redhat.com> Cc: qemu-stable@nongnu.org Acked-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 25 +++++++++++++++++++++++++ include/hw/virtio/virtio.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 5bd2a2f621..546a198e79 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -27,6 +27,7 @@ #include "hw/virtio/virtio-access.h" #include "sysemu/dma.h" #include "sysemu/runstate.h" +#include "standard-headers/linux/virtio_ids.h" /* * The alignment to use between consumer and producer parts of vring. @@ -3279,6 +3280,30 @@ void virtio_init(VirtIODevice *vdev, const char *name, vdev->use_guest_notifier_mask = true; } +/* + * Only devices that have already been around prior to defining the virtio + * standard support legacy mode; this includes devices not specified in the + * standard. All newer devices conform to the virtio standard only. + */ +bool virtio_legacy_allowed(VirtIODevice *vdev) +{ + switch (vdev->device_id) { + case VIRTIO_ID_NET: + case VIRTIO_ID_BLOCK: + case VIRTIO_ID_CONSOLE: + case VIRTIO_ID_RNG: + case VIRTIO_ID_BALLOON: + case VIRTIO_ID_RPMSG: + case VIRTIO_ID_SCSI: + case VIRTIO_ID_9P: + case VIRTIO_ID_RPROC_SERIAL: + case VIRTIO_ID_CAIF: + return true; + default: + return false; + } +} + hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n) { return vdev->vq[n].vring.desc; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index b69d517496..198ffc7626 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -396,4 +396,6 @@ static inline bool virtio_device_disabled(VirtIODevice *vdev) return unlikely(vdev->disabled || vdev->broken); } +bool virtio_legacy_allowed(VirtIODevice *vdev); + #endif From 9b3a35ec8236933ab958a4c3ad883163f1ca66e7 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 7 Jul 2020 12:54:46 +0200 Subject: [PATCH 2456/2595] virtio: verify that legacy support is not accidentally on If a virtio device does not have legacy support, make sure that it is actually off, and bail out if not. For virtio-pci, this means that any device without legacy support that has been specified to modern-only (or that has been forced to it) will work. For virtio-ccw, this duplicates the check that is currently done prior to realization for any device that explicitly specified no support for legacy. This catches devices that have not been fenced properly. Signed-off-by: Cornelia Huck Message-Id: <20200707105446.677966-3-cohuck@redhat.com> Cc: qemu-stable@nongnu.org Acked-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/s390x/virtio-ccw.c | 6 ++++++ hw/virtio/virtio-pci.c | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 3c988a000b..0e60270297 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1121,6 +1121,12 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp) dev->max_rev = 0; } + if (!virtio_ccw_rev_max(dev) && !virtio_legacy_allowed(vdev)) { + error_setg(errp, "Invalid value of property max_rev " + "(is %d expected >= 1)", virtio_ccw_rev_max(dev)); + return; + } + if (virtio_get_num_queues(vdev) > VIRTIO_QUEUE_MAX) { error_setg(errp, "The number of virtqueues %d " "exceeds virtio limit %d", n, diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 8554cf2a03..db8b711b35 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1581,6 +1581,10 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) } if (legacy) { + if (!virtio_legacy_allowed(vdev)) { + error_setg(errp, "device is modern-only, use disable-legacy=on"); + return; + } if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { error_setg(errp, "VIRTIO_F_IOMMU_PLATFORM was supported by" " neither legacy nor transitional device"); From a4544c45e109ceee87ee8c19baff28be3890d788 Mon Sep 17 00:00:00 2001 From: Liu Yi L Date: Sat, 4 Jul 2020 01:07:15 -0700 Subject: [PATCH 2457/2595] intel_iommu: Use correct shift for 256 bits qi descriptor In chapter 10.4.23 of VT-d spec 3.0, Descriptor Width bit was introduced in VTD_IQA_REG. Software could set this bit to tell VT-d the QI descriptor from software would be 256 bits. Accordingly, the VTD_IQH_QH_SHIFT should be 5 when descriptor size is 256 bits. This patch adds the DW bit check when deciding the shift used to update VTD_IQH_REG. Signed-off-by: Liu Yi L Message-Id: <1593850035-35483-1-git-send-email-yi.l.liu@intel.com> Reviewed-by: Peter Xu Acked-by: Jason Wang Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 7 ++++++- hw/i386/intel_iommu_internal.h | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index c56398e991..0c286635cf 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2549,6 +2549,11 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s) /* Try to fetch and process more Invalidation Descriptors */ static void vtd_fetch_inv_desc(IntelIOMMUState *s) { + int qi_shift; + + /* Refer to 10.4.23 of VT-d spec 3.0 */ + qi_shift = s->iq_dw ? VTD_IQH_QH_SHIFT_5 : VTD_IQH_QH_SHIFT_4; + trace_vtd_inv_qi_fetch(); if (s->iq_tail >= s->iq_size) { @@ -2567,7 +2572,7 @@ static void vtd_fetch_inv_desc(IntelIOMMUState *s) } /* Must update the IQH_REG in time */ vtd_set_quad_raw(s, DMAR_IQH_REG, - (((uint64_t)(s->iq_head)) << VTD_IQH_QH_SHIFT) & + (((uint64_t)(s->iq_head)) << qi_shift) & VTD_IQH_QH_MASK); } } diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 862033ebe6..3d5487fe2c 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -230,7 +230,8 @@ #define VTD_IQA_DW_MASK 0x800 /* IQH_REG */ -#define VTD_IQH_QH_SHIFT 4 +#define VTD_IQH_QH_SHIFT_4 4 +#define VTD_IQH_QH_SHIFT_5 5 #define VTD_IQH_QH_MASK 0x7fff0ULL /* ICS_REG */ From ccec7e9603f446fe75c6c563ba335c00cfda6a06 Mon Sep 17 00:00:00 2001 From: Andrew Melnychenko Date: Mon, 6 Jul 2020 14:21:23 +0300 Subject: [PATCH 2458/2595] virtio-pci: Changed vdev to proxy for VirtIO PCI BAR callbacks. There is an issue when callback may be called with invalid vdev. It happens on unplug when vdev already deleted and VirtIOPciProxy is not. So now, callbacks accept proxy device, and vdev retrieved from it. Technically memio callbacks should be removed during the flatview update, but memoryregions remain til PCI device(and it's address space) completely deleted. Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1716352 Signed-off-by: Andrew Melnychenko Message-Id: <20200706112123.971087-1-andrew@daynix.com> Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index db8b711b35..ada1101d07 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1333,11 +1333,12 @@ static uint64_t virtio_pci_notify_read(void *opaque, hwaddr addr, static void virtio_pci_notify_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - VirtIODevice *vdev = opaque; - VirtIOPCIProxy *proxy = VIRTIO_PCI(DEVICE(vdev)->parent_bus->parent); + VirtIOPCIProxy *proxy = opaque; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + unsigned queue = addr / virtio_pci_queue_mem_mult(proxy); - if (queue < VIRTIO_QUEUE_MAX) { + if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) { virtio_queue_notify(vdev, queue); } } @@ -1345,10 +1346,12 @@ static void virtio_pci_notify_write(void *opaque, hwaddr addr, static void virtio_pci_notify_write_pio(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - VirtIODevice *vdev = opaque; + VirtIOPCIProxy *proxy = opaque; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + unsigned queue = val; - if (queue < VIRTIO_QUEUE_MAX) { + if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) { virtio_queue_notify(vdev, queue); } } @@ -1372,9 +1375,14 @@ static void virtio_pci_isr_write(void *opaque, hwaddr addr, static uint64_t virtio_pci_device_read(void *opaque, hwaddr addr, unsigned size) { - VirtIODevice *vdev = opaque; + VirtIOPCIProxy *proxy = opaque; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); uint64_t val = 0; + if (vdev == NULL) { + return val; + } + switch (size) { case 1: val = virtio_config_modern_readb(vdev, addr); @@ -1392,7 +1400,13 @@ static uint64_t virtio_pci_device_read(void *opaque, hwaddr addr, static void virtio_pci_device_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - VirtIODevice *vdev = opaque; + VirtIOPCIProxy *proxy = opaque; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + + if (vdev == NULL) { + return; + } + switch (size) { case 1: virtio_config_modern_writeb(vdev, addr, val); @@ -1469,19 +1483,19 @@ static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy) memory_region_init_io(&proxy->device.mr, OBJECT(proxy), &device_ops, - virtio_bus_get_device(&proxy->bus), + proxy, "virtio-pci-device", proxy->device.size); memory_region_init_io(&proxy->notify.mr, OBJECT(proxy), ¬ify_ops, - virtio_bus_get_device(&proxy->bus), + proxy, "virtio-pci-notify", proxy->notify.size); memory_region_init_io(&proxy->notify_pio.mr, OBJECT(proxy), ¬ify_pio_ops, - virtio_bus_get_device(&proxy->bus), + proxy, "virtio-pci-notify-pio", proxy->notify_pio.size); } From 8380b3a453c38f040e7ca2105418802344cc23d0 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Sat, 18 Jul 2020 01:49:34 +0100 Subject: [PATCH 2459/2595] goldfish_rtc: Fix non-atomic read behaviour of TIME_LOW/TIME_HIGH The specification says: 0x00 TIME_LOW R: Get current time, then return low-order 32-bits. 0x04 TIME_HIGH R: Return high 32-bits from previous TIME_LOW read. ... To read the value, the kernel must perform an IO_READ(TIME_LOW), which returns an unsigned 32-bit value, before an IO_READ(TIME_HIGH), which returns a signed 32-bit value, corresponding to the higher half of the full value. However, we were just returning the current time for both. If the guest is unlucky enough to read TIME_LOW and TIME_HIGH either side of an overflow of the lower half, it will see time be in the future, before jumping backwards on the next read, and Linux currently relies on the atomicity guaranteed by the spec so is affected by this. Fix this violation of the spec by caching the correct value for TIME_HIGH whenever TIME_LOW is read, and returning that value for any TIME_HIGH read. Signed-off-by: Jessica Clarke Reviewed-by: Peter Maydell Reviewed-by: Richard Henderson Message-Id: <20200718004934.83174-1-jrtc27@jrtc27.com> Signed-off-by: Alistair Francis --- hw/rtc/goldfish_rtc.c | 17 ++++++++++++++--- include/hw/rtc/goldfish_rtc.h | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 01e9d2b083..6ddd45cce0 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -94,12 +94,22 @@ static uint64_t goldfish_rtc_read(void *opaque, hwaddr offset, GoldfishRTCState *s = opaque; uint64_t r = 0; + /* + * From the documentation linked at the top of the file: + * + * To read the value, the kernel must perform an IO_READ(TIME_LOW), which + * returns an unsigned 32-bit value, before an IO_READ(TIME_HIGH), which + * returns a signed 32-bit value, corresponding to the higher half of the + * full value. + */ switch (offset) { case RTC_TIME_LOW: - r = goldfish_rtc_get_count(s) & 0xffffffff; + r = goldfish_rtc_get_count(s); + s->time_high = r >> 32; + r &= 0xffffffff; break; case RTC_TIME_HIGH: - r = goldfish_rtc_get_count(s) >> 32; + r = s->time_high; break; case RTC_ALARM_LOW: r = s->alarm_next & 0xffffffff; @@ -216,7 +226,7 @@ static const MemoryRegionOps goldfish_rtc_ops = { static const VMStateDescription goldfish_rtc_vmstate = { .name = TYPE_GOLDFISH_RTC, - .version_id = 1, + .version_id = 2, .pre_save = goldfish_rtc_pre_save, .post_load = goldfish_rtc_post_load, .fields = (VMStateField[]) { @@ -225,6 +235,7 @@ static const VMStateDescription goldfish_rtc_vmstate = { VMSTATE_UINT32(alarm_running, GoldfishRTCState), VMSTATE_UINT32(irq_pending, GoldfishRTCState), VMSTATE_UINT32(irq_enabled, GoldfishRTCState), + VMSTATE_UINT32(time_high, GoldfishRTCState), VMSTATE_END_OF_LIST() } }; diff --git a/include/hw/rtc/goldfish_rtc.h b/include/hw/rtc/goldfish_rtc.h index 16f9f9e29d..9bd8924f5f 100644 --- a/include/hw/rtc/goldfish_rtc.h +++ b/include/hw/rtc/goldfish_rtc.h @@ -41,6 +41,7 @@ typedef struct GoldfishRTCState { uint32_t alarm_running; uint32_t irq_pending; uint32_t irq_enabled; + uint32_t time_high; } GoldfishRTCState; #endif From eabfeb0cb9e054108b3e29a3a85363b3d80d9c38 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 21 Jul 2020 21:37:41 +0800 Subject: [PATCH 2460/2595] target/riscv: Quiet Coverity complains about vamo* Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-Id: <20200721133742.2298-1-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.inc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index c0b7375927..7b4752b911 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -733,6 +733,7 @@ static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq) g_assert_not_reached(); #endif } else { + assert(seq < ARRAY_SIZE(fnsw)); fn = fnsw[seq]; } } From 3e09396e36dff4234afd6f6fd51861949be383e1 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 21 Jul 2020 21:37:42 +0800 Subject: [PATCH 2461/2595] target/riscv: fix vector index load/store constraints Although not explicitly specified that the the destination vector register groups cannot overlap the source vector register group, it is still necessary. And this constraint has been added to the v0.8 spec. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-Id: <20200721133742.2298-2-zhiwei_liu@c-sky.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.inc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c index 7b4752b911..887c6b8883 100644 --- a/target/riscv/insn_trans/trans_rvv.inc.c +++ b/target/riscv/insn_trans/trans_rvv.inc.c @@ -513,13 +513,21 @@ static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq) return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s); } +/* + * For vector indexed segment loads, the destination vector register + * groups cannot overlap the source vector register group (specified by + * `vs2`), else an illegal instruction exception is raised. + */ static bool ld_index_check(DisasContext *s, arg_rnfvm* a) { return (vext_check_isa_ill(s) && vext_check_overlap_mask(s, a->rd, a->vm, false) && vext_check_reg(s, a->rd, false) && vext_check_reg(s, a->rs2, false) && - vext_check_nf(s, a->nf)); + vext_check_nf(s, a->nf) && + ((a->nf == 1) || + vext_check_overlap_group(a->rd, a->nf << s->lmul, + a->rs2, 1 << s->lmul))); } GEN_VEXT_TRANS(vlxb_v, 0, rnfvm, ld_index_op, ld_index_check) From e79d27cb322b60b460b709d2c74ff7d77cde0565 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 16 Jul 2020 02:30:56 -0700 Subject: [PATCH 2462/2595] hw/riscv: sifive_e: Correct debug block size Currently the debug region size is set to 0x100, but according to FE310-G000 and FE310-G002 manuals: FE310-G000: 0x100 - 0xFFF FE310-G002: 0x0 - 0xFFF Change the size to 0x1000 that applies to both. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1594891856-15474-1-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_e.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 7bb97b463d..c8b060486a 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -54,7 +54,7 @@ static const struct MemmapEntry { hwaddr base; hwaddr size; } sifive_e_memmap[] = { - [SIFIVE_E_DEBUG] = { 0x0, 0x100 }, + [SIFIVE_E_DEBUG] = { 0x0, 0x1000 }, [SIFIVE_E_MROM] = { 0x1000, 0x2000 }, [SIFIVE_E_OTP] = { 0x20000, 0x2000 }, [SIFIVE_E_CLINT] = { 0x2000000, 0x10000 }, From 8ba26b0b2b00dd5849a6c0981e358dc7a7cc315d Mon Sep 17 00:00:00 2001 From: Zong Li Date: Tue, 21 Jul 2020 20:40:50 +0800 Subject: [PATCH 2463/2595] target/riscv: Fix the range of pmpcfg of CSR funcion table The range of Physical Memory Protection should be from CSR_PMPCFG0 to CSR_PMPCFG3, not to CSR_PMPADDR9. Signed-off-by: Zong Li Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Message-Id: Signed-off-by: Alistair Francis --- target/riscv/csr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index ac01c835e1..6a96a01b1c 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1353,7 +1353,7 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MTINST] = { hmode, read_mtinst, write_mtinst }, /* Physical Memory Protection */ - [CSR_PMPCFG0 ... CSR_PMPADDR9] = { pmp, read_pmpcfg, write_pmpcfg }, + [CSR_PMPCFG0 ... CSR_PMPCFG3] = { pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPADDR0 ... CSR_PMPADDR15] = { pmp, read_pmpaddr, write_pmpaddr }, /* Performance Counters */ From 0baa4b445e28f37243e5dc72e7efe32f0c9d7801 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Thu, 23 Jul 2020 16:27:01 +0200 Subject: [PATCH 2464/2595] KVM: fix CPU reset wrt HF2_GIF_MASK HF2_GIF_MASK is set in env->hflags2 unconditionally on CPU reset (see x86_cpu_reset()) but when calling KVM_SET_NESTED_STATE, KVM_STATE_NESTED_GIF_SET is only valid for nSVM as e.g. nVMX code looks like if (kvm_state->hdr.vmx.vmxon_pa == -1ull) { if (kvm_state->flags & ~KVM_STATE_NESTED_EVMCS) return -EINVAL; } Also, when adjusting the environment after KVM_GET_NESTED_STATE we need not reset HF2_GIF_MASK on VMX as e.g. x86_cpu_pending_interrupt() expects it to be set. Alternatively, we could've made env->hflags2 SVM-only. Reported-by: Jan Kiszka Fixes: b16c0e20c742 ("KVM: add support for AMD nested live migration") Signed-off-by: Vitaly Kuznetsov Message-Id: <20200723142701.2521161-1-vkuznets@redhat.com> Tested-by: Jan Kiszka Signed-off-by: Eduardo Habkost --- target/i386/kvm.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/target/i386/kvm.c b/target/i386/kvm.c index b8455c89ed..6f18d940a5 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -3877,7 +3877,9 @@ static int kvm_put_nested_state(X86CPU *cpu) } else { env->nested_state->flags &= ~KVM_STATE_NESTED_GUEST_MODE; } - if (env->hflags2 & HF2_GIF_MASK) { + + /* Don't set KVM_STATE_NESTED_GIF_SET on VMX as it is illegal */ + if (cpu_has_svm(env) && (env->hflags2 & HF2_GIF_MASK)) { env->nested_state->flags |= KVM_STATE_NESTED_GIF_SET; } else { env->nested_state->flags &= ~KVM_STATE_NESTED_GIF_SET; @@ -3919,10 +3921,14 @@ static int kvm_get_nested_state(X86CPU *cpu) } else { env->hflags &= ~HF_GUEST_MASK; } - if (env->nested_state->flags & KVM_STATE_NESTED_GIF_SET) { - env->hflags2 |= HF2_GIF_MASK; - } else { - env->hflags2 &= ~HF2_GIF_MASK; + + /* Keep HF2_GIF_MASK set on !SVM as x86_cpu_pending_interrupt() needs it */ + if (cpu_has_svm(env)) { + if (env->nested_state->flags & KVM_STATE_NESTED_GIF_SET) { + env->hflags2 |= HF2_GIF_MASK; + } else { + env->hflags2 &= ~HF2_GIF_MASK; + } } return ret; From d1bb69db4ceb6897ef6a17bf263146b53a123632 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 21 Jul 2020 06:32:02 -0400 Subject: [PATCH 2465/2595] s390x/protvirt: allow to IPL secure guests with -no-reboot Right now, -no-reboot prevents secure guests from running. This is correct from an implementation point of view, as we have modeled the transition from non-secure to secure as a program directed IPL. From a user perspective, this is not the behavior of least surprise. We should implement the IPL into protected mode similar to the functions that we use for kdump/kexec. In other words, we do not stop here when -no-reboot is specified on the command line. Like function 0 or function 1, function 10 is not a classic reboot. For example, it can only be called once. Before calling it a second time, a real reboot/reset must happen in-between. So function code 10 is more or less a state transition reset, but not a "standard" reset or reboot. Fixes: 4d226deafc44 ("s390x: protvirt: Support unpack facility") Signed-off-by: Christian Borntraeger Reviewed-by: Janosch Frank Reviewed-by: David Hildenbrand Acked-by: Viktor Mihajlovski Message-Id: <20200721103202.30610-1-borntraeger@de.ibm.com> [CH: tweaked description] Signed-off-by: Cornelia Huck --- hw/s390x/ipl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index d46b1f094f..3d2652d75a 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -630,7 +630,8 @@ void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type) } } if (reset_type == S390_RESET_MODIFIED_CLEAR || - reset_type == S390_RESET_LOAD_NORMAL) { + reset_type == S390_RESET_LOAD_NORMAL || + reset_type == S390_RESET_PV) { /* ignore -no-reboot, send no event */ qemu_system_reset_request(SHUTDOWN_CAUSE_SUBSYSTEM_RESET); } else { From d6645483285feaa0aa26fe2b0c3bac6989250d2f Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 23 Jul 2020 18:27:17 +0200 Subject: [PATCH 2466/2595] s390x/s390-virtio-ccw: fix loadparm property getter The function machine_get_loadparm() is supposed to produce a C-string, that is a NUL-terminated one, but it does not. ElectricFence can detect this problem if the loadparm machine property is used. Let us make the returned string a NUL-terminated one. Fixes: 7104bae9de ("hw/s390x: provide loadparm property for the machine") Signed-off-by: Halil Pasic Reviewed-by: Thomas Huth Message-Id: <20200723162717.88485-1-pasic@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 8cc2f25d8a..403d30e13b 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -701,8 +701,12 @@ bool hpage_1m_allowed(void) static char *machine_get_loadparm(Object *obj, Error **errp) { S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + char *loadparm_str; - return g_memdup(ms->loadparm, sizeof(ms->loadparm)); + /* make a NUL-terminated string */ + loadparm_str = g_memdup(ms->loadparm, sizeof(ms->loadparm) + 1); + loadparm_str[sizeof(ms->loadparm)] = 0; + return loadparm_str; } static void machine_set_loadparm(Object *obj, const char *val, Error **errp) From cb3fa1e4c05a4ad2563b39cdb1146e617f3b5424 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Jul 2020 10:40:45 +0200 Subject: [PATCH 2467/2595] coccinelle/err-bad-newline: Fix for Python 3, and add patterns Signed-off-by: Markus Armbruster Message-Id: <20200722084048.1726105-2-armbru@redhat.com> Reviewed-by: Eric Blake --- scripts/coccinelle/err-bad-newline.cocci | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/scripts/coccinelle/err-bad-newline.cocci b/scripts/coccinelle/err-bad-newline.cocci index 1316cc86a6..5394421873 100644 --- a/scripts/coccinelle/err-bad-newline.cocci +++ b/scripts/coccinelle/err-bad-newline.cocci @@ -1,22 +1,42 @@ // Error messages should not contain newlines. This script finds // messages that do. Fixing them is manual. @r@ -expression errp, eno, cls, fmt; +expression errp, err, eno, cls, fmt, ap; position p; @@ ( +error_vreport(fmt, ap)@p +| +warn_vreport(fmt, ap)@p +| +info_vreport(fmt, ap)@p +| error_report(fmt, ...)@p | +warn_report(fmt, ...)@p +| +info_report(fmt, ...)@p +| +error_report_once(fmt, ...)@p +| +warn_report_once(fmt, ...)@p +| error_setg(errp, fmt, ...)@p | error_setg_errno(errp, eno, fmt, ...)@p | error_setg_win32(errp, eno, cls, fmt, ...)@p | +error_propagate_prepend(errp, err, fmt, ...)@p +| +error_vprepend(errp, fmt, ap)@p +| error_prepend(errp, fmt, ...)@p | error_setg_file_open(errp, eno, cls, fmt, ...)@p | +warn_reportf_err(errp, fmt, ...)@p +| error_reportf_err(errp, fmt, ...)@p | error_set(errp, cls, fmt, ...)@p @@ -26,4 +46,4 @@ fmt << r.fmt; p << r.p; @@ if "\\n" in str(fmt): - print "%s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt) + print("%s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt)) From ff5b5d5b6df5655946142820912b28f1a67efc94 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 22 Jul 2020 10:40:46 +0200 Subject: [PATCH 2468/2595] error: Strip trailing '\n' from error string arguments (again) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tracked down with scripts/coccinelle/err-bad-newline.cocci. Cc: Peter Xu Cc: David Gibson Signed-off-by: Markus Armbruster Message-Id: <20200722084048.1726105-3-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Acked-by: David Gibson Reviewed-by: Peter Xu --- hw/i386/intel_iommu.c | 6 +++--- target/ppc/mmu-hash64.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 0c286635cf..5284bb68b6 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2356,7 +2356,7 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) if ((inv_desc->lo & VTD_INV_DESC_IOTLB_RSVD_LO) || (inv_desc->hi & VTD_INV_DESC_IOTLB_RSVD_HI)) { error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64 - ", lo=0x%"PRIx64" (reserved bits unzero)\n", + ", lo=0x%"PRIx64" (reserved bits unzero)", __func__, inv_desc->hi, inv_desc->lo); return false; } @@ -2377,7 +2377,7 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) am = VTD_INV_DESC_IOTLB_AM(inv_desc->hi); if (am > VTD_MAMV) { error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64 - ", lo=0x%"PRIx64" (am=%u > VTD_MAMV=%u)\n", + ", lo=0x%"PRIx64" (am=%u > VTD_MAMV=%u)", __func__, inv_desc->hi, inv_desc->lo, am, (unsigned)VTD_MAMV); return false; @@ -2387,7 +2387,7 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) default: error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64 - ", lo=0x%"PRIx64" (type mismatch: 0x%llx)\n", + ", lo=0x%"PRIx64" (type mismatch: 0x%llx)", __func__, inv_desc->hi, inv_desc->lo, inv_desc->lo & VTD_INV_DESC_IOTLB_G); return false; diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index e5baabf0e1..c31d21e6a9 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -859,7 +859,7 @@ static int build_vrma_slbe(PowerPCCPU *cpu, ppc_slb_t *slb) } error_report("Bad page size encoding in LPCR[VRMASD]; LPCR=0x" - TARGET_FMT_lx"\n", lpcr); + TARGET_FMT_lx, lpcr); return -1; } From 838886378eac879771708100a08a1099173d6935 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Wed, 22 Jul 2020 22:40:54 +0200 Subject: [PATCH 2469/2595] sd/milkymist-memcard: Fix format string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: b98e8d1230ff7023bb34ddeb7194424dfcbaf789 Signed-off-by: Stefan Weil Message-Id: <20200722204054.1400555-1-sw@weilnetz.de> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Markus Armbruster Reviewed-by: Li Qiang [Commit message tweaked] Signed-off-by: Markus Armbruster --- hw/sd/milkymist-memcard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index afdb8aa0c0..11f61294fc 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -281,7 +281,7 @@ static void milkymist_memcard_realize(DeviceState *dev, Error **errp) carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk); if (!qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err)) { - error_propagate_prepend(errp, err, "failed to init SD card: %s"); + error_propagate_prepend(errp, err, "failed to init SD card"); return; } s->enabled = blk && blk_is_inserted(blk); From 192cf54ac5408d21c20c17b3794a632970bbb880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Jul 2020 19:12:05 +0200 Subject: [PATCH 2470/2595] qapi/error: Check format string argument in error_*prepend() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit error_propagate_prepend() "behaves like error_prepend()", and error_prepend() uses "formatting @fmt, ... like printf()". error_prepend() checks its format string argument, but error_propagate_prepend() does not. Fix by addint the format attribute to error_propagate_prepend() and error_vprepend(). This would have caught the bug fixed in the previous commit. Missed in commit 4b5766488f "error: Fix use of error_prepend() with &error_fatal, &error_abort". Inspired-by: Stefan Weil Suggested-by: Eric Blake Reviewed-by: Stefan Weil Reviewed-by: Markus Armbruster Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200723171205.14949-1-philmd@redhat.com> Reviewed-by: Markus Armbruster [Commit message tweaked] Signed-off-by: Markus Armbruster --- include/qapi/error.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/qapi/error.h b/include/qapi/error.h index 7932594dce..eaa05c4837 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -382,13 +382,15 @@ void error_propagate(Error **dst_errp, Error *local_err); * Please use ERRP_GUARD() and error_prepend() instead when possible. */ void error_propagate_prepend(Error **dst_errp, Error *local_err, - const char *fmt, ...); + const char *fmt, ...) + GCC_FMT_ATTR(3, 4); /* * Prepend some text to @errp's human-readable error message. * The text is made by formatting @fmt, @ap like vprintf(). */ -void error_vprepend(Error *const *errp, const char *fmt, va_list ap); +void error_vprepend(Error *const *errp, const char *fmt, va_list ap) + GCC_FMT_ATTR(2, 0); /* * Prepend some text to @errp's human-readable error message. From 8d942986be27bb40e6faca2032af763d7db57082 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 22 Jul 2020 17:47:19 +0200 Subject: [PATCH 2471/2595] hw: Only compile the usb-dwc2 controller if it is really needed The USB_DWC2 switch is currently "default y", so it is included in all qemu-system-* builds, even if it is not needed. Even worse, it does a "select USB", so USB devices are now showing up as available on targets that do not support USB at all. This sysbus device should only be included by the boards that need it, i.e. by the Raspi machines. Fixes: 153ef1662c ("dwc-hsotg (dwc2) USB host controller emulation") Signed-off-by: Thomas Huth Reviewed-by: Paul Zimmerman Message-id: 20200722154719.10130-1-thuth@redhat.com Signed-off-by: Gerd Hoffmann --- hw/arm/Kconfig | 1 + hw/usb/Kconfig | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 4a224a6351..bc3a423940 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -315,6 +315,7 @@ config RASPI select FRAMEBUFFER select PL011 # UART select SDHCI + select USB_DWC2 config STM32F205_SOC bool diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig index d4d8c37c28..5e63dc75f8 100644 --- a/hw/usb/Kconfig +++ b/hw/usb/Kconfig @@ -48,7 +48,6 @@ config USB_MUSB config USB_DWC2 bool - default y select USB config TUSB6010 From 2c9728c0db8c02bf2f4f067548433af9f4102948 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 23 Jul 2020 20:24:57 +0100 Subject: [PATCH 2472/2595] hw/input/virtio-input-hid.c: Don't undef CONFIG_CURSES virtio-input-hid.c undefines CONFIG_CURSES before including ui/console.h. However since commits e2f82e924d057935 and b0766612d16da18 that header does not have behaviour dependent on CONFIG_CURSES. Remove the now-unneeded undef. Signed-off-by: Peter Maydell Reviewed-by: Thomas Huth Acked-by: Michael S. Tsirkin Message-id: 20200723192457.28136-1-peter.maydell@linaro.org Signed-off-by: Gerd Hoffmann --- hw/input/virtio-input-hid.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c index 09cf260985..a7a244a95d 100644 --- a/hw/input/virtio-input-hid.c +++ b/hw/input/virtio-input-hid.c @@ -12,7 +12,6 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio-input.h" -#undef CONFIG_CURSES #include "ui/console.h" #include "standard-headers/linux/input.h" From 9b52b17ba5e96cec182537715e87308108b47117 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 23 Jul 2020 16:11:23 +0200 Subject: [PATCH 2473/2595] configure: Allow to build tools without pixman If pixman is not installed, it is currently not possible to run: .../configure --disable-system --enable-tools Seems like there was a dependency from one of the required source files to pixman in the past, but since commit 1ac0206b2ae1ffaeec56 ("qemu-timer.c: Trim list of included headers"), this dependency should be gone. Thus allow to compile the tools without pixman now. Signed-off-by: Thomas Huth Message-id: 20200723141123.14765-1-thuth@redhat.com Signed-off-by: Gerd Hoffmann --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 4bd80ed507..2acc4d1465 100755 --- a/configure +++ b/configure @@ -4065,7 +4065,7 @@ fi ########################################## # pixman support probe -if test "$want_tools" = "no" && test "$softmmu" = "no"; then +if test "$softmmu" = "no"; then pixman_cflags= pixman_libs= elif $pkg_config --atleast-version=0.21.8 pixman-1 > /dev/null 2>&1; then From d64072c0ac6f73413026695bb33a4aa232e69617 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 23 Jul 2020 13:58:44 +0200 Subject: [PATCH 2474/2595] Revert "tpm: Clean up error reporting in tpm_init_tpmdev()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit d10e05f15d5c3dd5e5cc59c5dfff460d89d48580. We report some -tpmdev failures, but then continue as if all was fine. Reproducer: $ qemu-system-x86_64 -nodefaults -S -display none -monitor stdio -chardev null,id=tpm0 -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0 qemu-system-x86_64: -tpmdev emulator,id=tpm0,chardev=chrtpm: tpm-emulator: tpm chardev 'chrtpm' not found. qemu-system-x86_64: -tpmdev emulator,id=tpm0,chardev=chrtpm: tpm-emulator: Could not cleanly shutdown the TPM: No such file or directory QEMU 5.0.90 monitor - type 'help' for more information (qemu) qemu-system-x86_64: -device tpm-tis,tpmdev=tpm0: Property 'tpm-tis.tpmdev' can't find value 'tpm0' $ echo $? 1 This is a regression caused by commit d10e05f15d "tpm: Clean up error reporting in tpm_init_tpmdev()". It's incomplete: be->create(opts) continues to use error_report(), and we don't set an error when it fails. I figure converting the create() methods to Error would make some sense, but I'm not sure it's worth the effort right now. Revert the broken commit instead, and add a comment to tpm_init_tpmdev(). Straightforward conflict in tpm.c resolved. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- include/sysemu/tpm.h | 2 +- softmmu/vl.c | 4 +++- stubs/tpm.c | 3 ++- tpm.c | 30 +++++++++++++++++++++--------- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index 03fb25941c..730c61ac97 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -16,7 +16,7 @@ #include "qom/object.h" int tpm_config_parse(QemuOptsList *opts_list, const char *optarg); -void tpm_init(void); +int tpm_init(void); void tpm_cleanup(void); typedef enum TPMVersion { diff --git a/softmmu/vl.c b/softmmu/vl.c index 3416241557..660537a709 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -4258,7 +4258,9 @@ void qemu_init(int argc, char **argv, char **envp) user_creatable_add_opts_foreach, object_create_delayed, &error_fatal); - tpm_init(); + if (tpm_init() < 0) { + exit(1); + } blk_mig_init(); ram_mig_init(); diff --git a/stubs/tpm.c b/stubs/tpm.c index 66c99d667d..9bded191d9 100644 --- a/stubs/tpm.c +++ b/stubs/tpm.c @@ -10,8 +10,9 @@ #include "sysemu/tpm.h" #include "hw/acpi/tpm.h" -void tpm_init(void) +int tpm_init(void) { + return 0; } void tpm_cleanup(void) diff --git a/tpm.c b/tpm.c index fe03b24858..f6045bb6da 100644 --- a/tpm.c +++ b/tpm.c @@ -81,26 +81,33 @@ TPMBackend *qemu_find_tpm_be(const char *id) static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp) { + /* + * Use of error_report() in a function with an Error ** parameter + * is suspicious. It is okay here. The parameter only exists to + * make the function usable with qemu_opts_foreach(). It is not + * actually used. + */ const char *value; const char *id; const TPMBackendClass *be; TPMBackend *drv; + Error *local_err = NULL; int i; if (!QLIST_EMPTY(&tpm_backends)) { - error_setg(errp, "Only one TPM is allowed."); + error_report("Only one TPM is allowed."); return 1; } id = qemu_opts_id(opts); if (id == NULL) { - error_setg(errp, QERR_MISSING_PARAMETER, "id"); + error_report(QERR_MISSING_PARAMETER, "id"); return 1; } value = qemu_opt_get(opts, "type"); if (!value) { - error_setg(errp, QERR_MISSING_PARAMETER, "type"); + error_report(QERR_MISSING_PARAMETER, "type"); tpm_display_backend_drivers(); return 1; } @@ -108,14 +115,15 @@ static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp) i = qapi_enum_parse(&TpmType_lookup, value, -1, NULL); be = i >= 0 ? tpm_be_find_by_type(i) : NULL; if (be == NULL) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", - "a TPM backend type"); + error_report(QERR_INVALID_PARAMETER_VALUE, + "type", "a TPM backend type"); tpm_display_backend_drivers(); return 1; } /* validate backend specific opts */ - if (!qemu_opts_validate(opts, be->opts, errp)) { + if (!qemu_opts_validate(opts, be->opts, &local_err)) { + error_report_err(local_err); return 1; } @@ -148,10 +156,14 @@ void tpm_cleanup(void) * Initialize the TPM. Process the tpmdev command line options describing the * TPM backend. */ -void tpm_init(void) +int tpm_init(void) { - qemu_opts_foreach(qemu_find_opts("tpmdev"), - tpm_init_tpmdev, NULL, &error_fatal); + if (qemu_opts_foreach(qemu_find_opts("tpmdev"), + tpm_init_tpmdev, NULL, NULL)) { + return -1; + } + + return 0; } /* From 5a6791c3d4a7719e8d0797afe0e2822a54bda6a2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 23 Jul 2020 13:58:45 +0200 Subject: [PATCH 2475/2595] tpm: Improve help on TPM types when none are available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Help is a bit awkward when no TPM types are built into QEMU: $ qemu-system-x86_64 -tpmdev nonexistent,id=tpm0 qemu-system-x86_64: -tpmdev nonexistent,id=tpm0: Parameter 'type' expects a TPM backend type Supported TPM types (choose only one): Improve to qemu-system-x86_64: -tpmdev nonexistent,id=tpm0: Parameter 'type' expects a TPM backend type No TPM backend types are available Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- tpm.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tpm.c b/tpm.c index f6045bb6da..cab206355a 100644 --- a/tpm.c +++ b/tpm.c @@ -47,18 +47,23 @@ tpm_be_find_by_type(enum TpmType type) */ static void tpm_display_backend_drivers(void) { + bool got_one = false; int i; - fprintf(stderr, "Supported TPM types (choose only one):\n"); - for (i = 0; i < TPM_TYPE__MAX; i++) { const TPMBackendClass *bc = tpm_be_find_by_type(i); if (!bc) { continue; } - fprintf(stderr, "%12s %s\n", TpmType_str(i), bc->desc); + if (!got_one) { + error_printf("Supported TPM types (choose only one):\n"); + got_one = true; + } + error_printf("%12s %s\n", TpmType_str(i), bc->desc); + } + if (!got_one) { + error_printf("No TPM backend types are available\n"); } - fprintf(stderr, "\n"); } /* From 88f830745721ba8c9e9d2831c01045a6f130c1a6 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Fri, 24 Jul 2020 08:57:26 -0400 Subject: [PATCH 2476/2595] tpm_emulator: Report an error if chardev is missing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the odd error reporting when trying to send a file descriptor to the TPM emulator if one has not passed a valid chardev. $ x86_64-softmmu/qemu-system-x86_64 -tpmdev emulator,id=tpm0 qemu-system-x86_64: -tpmdev emulator,id=tpm0: tpm-emulator: Failed to send CMD_SET_DATAFD: Success qemu-system-x86_64: -tpmdev emulator,id=tpm0: tpm-emulator: Could not cleanly shutdown the TPM: Success This is the new error report: $ x86_64-softmmu/qemu-system-x86_64 -tpmdev emulator,id=tpm0 qemu-system-x86_64: -tpmdev emulator,id=tpm0: tpm-emulator: parameter 'chardev' is missing This change does not hide the display of supported TPM types if a non-existent type is passed: $ x86_64-softmmu/qemu-system-x86_64 -tpmdev nonexistent,id=tpm0 qemu-system-x86_64: -tpmdev nonexistent,id=tpm0: Parameter 'type' expects a TPM backend type Supported TPM types (choose only one): passthrough Passthrough TPM backend driver emulator TPM emulator backend driver Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau Reviewed-by: Markus Armbruster --- backends/tpm/tpm_emulator.c | 42 ++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c index 9605339f93..a9b0f55e67 100644 --- a/backends/tpm/tpm_emulator.c +++ b/backends/tpm/tpm_emulator.c @@ -549,27 +549,30 @@ err_exit: static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts) { const char *value; + Error *err = NULL; + Chardev *dev; value = qemu_opt_get(opts, "chardev"); - if (value) { - Error *err = NULL; - Chardev *dev = qemu_chr_find(value); - - if (!dev) { - error_report("tpm-emulator: tpm chardev '%s' not found.", value); - goto err; - } - - if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) { - error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':", - value); - error_report_err(err); - goto err; - } - - tpm_emu->options->chardev = g_strdup(value); + if (!value) { + error_report("tpm-emulator: parameter 'chardev' is missing"); + goto err; } + dev = qemu_chr_find(value); + if (!dev) { + error_report("tpm-emulator: tpm chardev '%s' not found", value); + goto err; + } + + if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) { + error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':", + value); + error_report_err(err); + goto err; + } + + tpm_emu->options->chardev = g_strdup(value); + if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) { goto err; } @@ -925,6 +928,11 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu) { ptm_res res; + if (!tpm_emu->options->chardev) { + /* was never properly initialized */ + return; + } + if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0, sizeof(res)) < 0) { error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s", strerror(errno)); From 570ef3093b5ed327249397ad0295cf01c67d9db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 20 Jul 2020 13:23:58 +0100 Subject: [PATCH 2477/2595] tcg: update comments for save_iotlb_data in cputlb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I missed Emilio's review comments: Message-ID: <20200718205107.GA994221@sff> and the patch got merged. Correcting the comments now. Reviewed-by: Emilio G. Cota Signed-off-by: Alex Bennée Message-Id: <20200720122358.26881-1-alex.bennee@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index d370aedb47..5698292749 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1075,10 +1075,8 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, /* * Save a potentially trashed IOTLB entry for later lookup by plugin. - * - * We also need to track the thread storage address because the RCU - * cleanup that runs when we leave the critical region (the current - * execution) is actually in a different thread. + * This is read by tlb_plugin_lookup if the iotlb entry doesn't match + * because of the side effect of io_writex changing memory layout. */ static void save_iotlb_data(CPUState *cs, hwaddr addr, MemoryRegionSection *section, hwaddr mr_offset) @@ -1408,8 +1406,9 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, * This almost never fails as the memory access being instrumented * should have just filled the TLB. The one corner case is io_writex * which can cause TLB flushes and potential resizing of the TLBs - * loosing the information we need. In those cases we need to recover - * data from a copy of the io_tlb entry. + * losing the information we need. In those cases we need to recover + * data from a copy of the iotlbentry. As long as this always occurs + * from the same thread (which a mem callback will be) this is safe. */ bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, From 79826f99feb7222b7804058f0b4ace9ee0546361 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jul 2020 10:35:00 -0700 Subject: [PATCH 2478/2595] target/hppa: Free some temps in do_sub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two temps allocated but not freed. Do enough subtractions within a single TB and one can run out of temps entirely. Fixes: b2167459ae ("target-hppa: Implement basic arithmetic") Buglink: https://bugs.launchpad.net/qemu/+bug/1880287 Tested-by: Sven Schnelle Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-Id: <20200720174039.517902-1-richard.henderson@linaro.org> --- target/hppa/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 52d7bea1ea..4bd22d4820 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -1294,6 +1294,8 @@ static void do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1, save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); save_gpr(ctx, rt, dest); tcg_temp_free(dest); + tcg_temp_free(cb); + tcg_temp_free(cb_msb); /* Install the new nullification. */ cond_free(&ctx->null_cond); From 3cb3a7720b01830abd5fbb81819dbb9271bf7821 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jul 2020 08:30:40 -0700 Subject: [PATCH 2479/2595] target/i386: Save cc_op before loop insns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We forgot to update cc_op before these branch insns, which lead to losing track of the current eflags. Buglink: https://bugs.launchpad.net/qemu/+bug/1888165 Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson Message-Id: <20200720154028.477457-1-richard.henderson@linaro.org> --- target/i386/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/i386/translate.c b/target/i386/translate.c index a1d31f09c1..caea6f5fb1 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -7148,6 +7148,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) l1 = gen_new_label(); l2 = gen_new_label(); l3 = gen_new_label(); + gen_update_cc_op(s); b &= 3; switch(b) { case 0: /* loopnz */ From 8226a4b88b35aab2d7c95f9dbe2fcd662276685a Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 20 Jul 2020 12:02:52 -0400 Subject: [PATCH 2480/2595] python/machine: Change default timeout to 30 seconds 3 seconds is too short for some tests running inside busy VMs. Build it out to a rather generous 30 seconds to find out conclusively if there are more severe problems in the merge/CI tests. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Message-id: 20200720160252.104139-2-jsnow@redhat.com Signed-off-by: Peter Maydell --- python/qemu/machine.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 80c4d4a8b6..51aa255ef9 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -394,15 +394,15 @@ class QEMUMachine: self._popen.kill() self._popen.wait(timeout=60) - def _soft_shutdown(self, has_quit: bool = False, - timeout: Optional[int] = 3) -> None: + def _soft_shutdown(self, timeout: Optional[int], + has_quit: bool = False) -> None: """ Perform early cleanup, attempt to gracefully shut down the VM, and wait for it to terminate. + :param timeout: Timeout in seconds for graceful shutdown. + A value of None is an infinite wait. :param has_quit: When True, don't attempt to issue 'quit' QMP command - :param timeout: Optional timeout in seconds for graceful shutdown. - Default 3 seconds, A value of None is an infinite wait. :raise ConnectionReset: On QMP communication errors :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for @@ -418,14 +418,14 @@ class QEMUMachine: # May raise subprocess.TimeoutExpired self._popen.wait(timeout=timeout) - def _do_shutdown(self, has_quit: bool = False, - timeout: Optional[int] = 3) -> None: + def _do_shutdown(self, timeout: Optional[int], + has_quit: bool = False) -> None: """ Attempt to shutdown the VM gracefully; fallback to a hard shutdown. + :param timeout: Timeout in seconds for graceful shutdown. + A value of None is an infinite wait. :param has_quit: When True, don't attempt to issue 'quit' QMP command - :param timeout: Optional timeout in seconds for graceful shutdown. - Default 3 seconds, A value of None is an infinite wait. :raise AbnormalShutdown: When the VM could not be shut down gracefully. The inner exception will likely be ConnectionReset or @@ -433,7 +433,7 @@ class QEMUMachine: may result in its own exceptions, likely subprocess.TimeoutExpired. """ try: - self._soft_shutdown(has_quit, timeout) + self._soft_shutdown(timeout, has_quit) except Exception as exc: self._hard_shutdown() raise AbnormalShutdown("Could not perform graceful shutdown") \ @@ -441,7 +441,7 @@ class QEMUMachine: def shutdown(self, has_quit: bool = False, hard: bool = False, - timeout: Optional[int] = 3) -> None: + timeout: Optional[int] = 30) -> None: """ Terminate the VM (gracefully if possible) and perform cleanup. Cleanup will always be performed. @@ -453,7 +453,7 @@ class QEMUMachine: :param hard: When true, do not attempt graceful shutdown, and suppress the SIGKILL warning log message. :param timeout: Optional timeout in seconds for graceful shutdown. - Default 3 seconds, A value of None is an infinite wait. + Default 30 seconds, A `None` value is an infinite wait. """ if not self._launched: return @@ -463,7 +463,7 @@ class QEMUMachine: self._user_killed = True self._hard_shutdown() else: - self._do_shutdown(has_quit, timeout=timeout) + self._do_shutdown(timeout, has_quit) finally: self._post_shutdown() @@ -473,12 +473,12 @@ class QEMUMachine: """ self.shutdown(hard=True) - def wait(self, timeout: Optional[int] = 3) -> None: + def wait(self, timeout: Optional[int] = 30) -> None: """ Wait for the VM to power off and perform post-shutdown cleanup. - :param timeout: Optional timeout in seconds. - Default 3 seconds, A value of None is an infinite wait. + :param timeout: Optional timeout in seconds. Default 30 seconds. + A value of `None` is an infinite wait. """ self.shutdown(has_quit=True, timeout=timeout) From aef92d87c59d257c0ff24ba1dc82506a03f1f522 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 24 Jul 2020 10:35:33 +0200 Subject: [PATCH 2481/2595] pseries: fix kvmppc_set_fwnmi() QEMU issues the ioctl(KVM_CAP_PPC_FWNMI) on the first vCPU. If the first vCPU is currently running, the vCPU mutex is held and the ioctl() cannot be done and waits until the mutex is released. This never happens and the VM is stuck. To avoid this deadlock, issue the ioctl on the same vCPU doing the RTAS call. The problem can be reproduced by booting a guest with several vCPUs (the probability to have the problem is (n - 1) / n, n = # of CPUs), and then by triggering a kernel crash with "echo c >/proc/sysrq-trigger". On the reboot, the kernel hangs after: ... [ 0.000000] ----------------------------------------------------- [ 0.000000] ppc64_pft_size = 0x0 [ 0.000000] phys_mem_size = 0x48000000 [ 0.000000] dcache_bsize = 0x80 [ 0.000000] icache_bsize = 0x80 [ 0.000000] cpu_features = 0x0001c06f8f4f91a7 [ 0.000000] possible = 0x0003fbffcf5fb1a7 [ 0.000000] always = 0x00000003800081a1 [ 0.000000] cpu_user_features = 0xdc0065c2 0xaee00000 [ 0.000000] mmu_features = 0x3c006041 [ 0.000000] firmware_features = 0x00000085455a445f [ 0.000000] physical_start = 0x8000000 [ 0.000000] ----------------------------------------------------- [ 0.000000] numa: NODE_DATA [mem 0x47f33c80-0x47f3ffff] Fixes: ec010c00665b ("ppc/spapr: KVM FWNMI should not be enabled until guest requests it") Cc: npiggin@gmail.com Signed-off-by: Laurent Vivier Message-Id: <20200724083533.281700-1-lvivier@redhat.com> Signed-off-by: David Gibson --- hw/ppc/spapr_rtas.c | 2 +- target/ppc/kvm.c | 3 +-- target/ppc/kvm_ppc.h | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index bcac0d00e7..513c7a8435 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -438,7 +438,7 @@ static void rtas_ibm_nmi_register(PowerPCCPU *cpu, } if (kvm_enabled()) { - if (kvmppc_set_fwnmi() < 0) { + if (kvmppc_set_fwnmi(cpu) < 0) { rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED); return; } diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 2692f76130..d85ba8ffe0 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -2071,9 +2071,8 @@ bool kvmppc_get_fwnmi(void) return cap_fwnmi; } -int kvmppc_set_fwnmi(void) +int kvmppc_set_fwnmi(PowerPCCPU *cpu) { - PowerPCCPU *cpu = POWERPC_CPU(first_cpu); CPUState *cs = CPU(cpu); return kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_FWNMI, 0); diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index 701c0c262b..72e05f1cd2 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -28,7 +28,7 @@ void kvmppc_set_papr(PowerPCCPU *cpu); int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr); void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy); bool kvmppc_get_fwnmi(void); -int kvmppc_set_fwnmi(void); +int kvmppc_set_fwnmi(PowerPCCPU *cpu); int kvmppc_smt_threads(void); void kvmppc_error_append_smt_possible_hint(Error *const *errp); int kvmppc_set_smt_threads(int smt); @@ -169,7 +169,7 @@ static inline bool kvmppc_get_fwnmi(void) return false; } -static inline int kvmppc_set_fwnmi(void) +static inline int kvmppc_set_fwnmi(PowerPCCPU *cpu) { return -1; } From 3b6b4997b378c4e7685ab7f04491f3077284df4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 24 Jul 2020 07:44:54 +0100 Subject: [PATCH 2482/2595] shippable: add one more qemu to registry url MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The registry url is //qemu/ Perhaps we should rationalise that some day but for now. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200724064509.331-2-alex.bennee@linaro.org> --- .shippable.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.shippable.yml b/.shippable.yml index f6b742432e..89d8be4291 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -27,7 +27,7 @@ env: TARGET_LIST=ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user build: pre_ci_boot: - image_name: registry.gitlab.com/qemu-project/qemu/${IMAGE} + image_name: registry.gitlab.com/qemu-project/qemu/qemu/${IMAGE} image_tag: latest pull: true options: "-e HOME=/root" From 619985e937c2f6a61ae7d52ae4e9973c83387dce Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Fri, 24 Jul 2020 07:44:55 +0100 Subject: [PATCH 2483/2595] semihosting: defer connect_chardevs a little more to use serialx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With that we can just use -semihosting-config chardev=serial0. [AJB: tweak commit message] Signed-off-by: KONRAD Frederic Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <1592215252-26742-1-git-send-email-frederic.konrad@adacore.com> Message-Id: <20200724064509.331-3-alex.bennee@linaro.org> --- softmmu/vl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index 660537a709..4eb9d1f7fd 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -4127,8 +4127,6 @@ void qemu_init(int argc, char **argv, char **envp) qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, &error_fatal); - /* now chardevs have been created we may have semihosting to connect */ - qemu_semihosting_connect_chardevs(); #ifdef CONFIG_VIRTFS qemu_opts_foreach(qemu_find_opts("fsdev"), @@ -4279,6 +4277,9 @@ void qemu_init(int argc, char **argv, char **envp) if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0) exit(1); + /* now chardevs have been created we may have semihosting to connect */ + qemu_semihosting_connect_chardevs(); + /* If no default VGA is requested, the default is "none". */ if (default_vga) { vga_model = get_default_vga_model(machine_class); From 7d2d6522bbadfa8d9877e38bfa7413444fa64fbb Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Fri, 24 Jul 2020 07:44:56 +0100 Subject: [PATCH 2484/2595] semihosting: don't send the trailing '\0' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't send the trailing 0 from the string. Signed-off-by: KONRAD Frederic Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <1592215252-26742-2-git-send-email-frederic.konrad@adacore.com> Message-Id: <20200724064509.331-4-alex.bennee@linaro.org> --- hw/semihosting/console.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/semihosting/console.c b/hw/semihosting/console.c index 22e7827824..9b4fee9260 100644 --- a/hw/semihosting/console.c +++ b/hw/semihosting/console.c @@ -52,7 +52,9 @@ static GString *copy_user_string(CPUArchState *env, target_ulong addr) do { if (cpu_memory_rw_debug(cpu, addr++, &c, 1, 0) == 0) { - s = g_string_append_c(s, c); + if (c) { + s = g_string_append_c(s, c); + } } else { qemu_log_mask(LOG_GUEST_ERROR, "%s: passed inaccessible address " TARGET_FMT_lx, From ad06ef0efbf7cafba5074a183fef1ad586f38caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 24 Jul 2020 07:44:57 +0100 Subject: [PATCH 2485/2595] util: add qemu_get_host_physmem utility function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be used in a future patch. For POSIX systems _SC_PHYS_PAGES isn't standardised but at least appears in the man pages for Open/FreeBSD. The result is advisory so any users of it shouldn't just fail if we can't work it out. The win32 stub currently returns 0 until someone with a Windows system can develop and test a patch. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Cc: BALATON Zoltan Cc: Christian Ehrhardt Message-Id: <20200724064509.331-5-alex.bennee@linaro.org> --- include/qemu/osdep.h | 12 ++++++++++++ util/oslib-posix.c | 15 +++++++++++++++ util/oslib-win32.c | 6 ++++++ 3 files changed, 33 insertions(+) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 45c217aa28..0b1298b3c9 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -668,4 +668,16 @@ static inline void qemu_reset_optind(void) */ char *qemu_get_host_name(Error **errp); +/** + * qemu_get_host_physmem: + * + * Operating system agnostic way of querying host memory. + * + * Returns amount of physical memory on the system. This is purely + * advisery and may return 0 if we can't work it out. At the other + * end we saturate to SIZE_MAX if you are lucky enough to have that + * much memory. + */ +size_t qemu_get_host_physmem(void); + #endif diff --git a/util/oslib-posix.c b/util/oslib-posix.c index d923674624..ad8001a4ad 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -841,3 +841,18 @@ char *qemu_get_host_name(Error **errp) return g_steal_pointer(&hostname); } + +size_t qemu_get_host_physmem(void) +{ +#ifdef _SC_PHYS_PAGES + long pages = sysconf(_SC_PHYS_PAGES); + if (pages > 0) { + if (pages > SIZE_MAX / qemu_real_host_page_size) { + return SIZE_MAX; + } else { + return pages * qemu_real_host_page_size; + } + } +#endif + return 0; +} diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 7eedbe5859..31030463cc 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -828,3 +828,9 @@ char *qemu_get_host_name(Error **errp) return g_utf16_to_utf8(tmp, size, NULL, NULL, NULL); } + +size_t qemu_get_host_physmem(void) +{ + /* currently unimplemented */ + return 0; +} From 986babaab30279a4962648d03730bf1291d89f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 24 Jul 2020 07:44:58 +0100 Subject: [PATCH 2486/2595] util/oslib-win32: add qemu_get_host_physmem implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compile tested only. Signed-off-by: Alex Bennée Reviewed-by: Stefan Weil Message-Id: <20200724064509.331-6-alex.bennee@linaro.org> --- util/oslib-win32.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 31030463cc..c654dafd93 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -831,6 +831,11 @@ char *qemu_get_host_name(Error **errp) size_t qemu_get_host_physmem(void) { - /* currently unimplemented */ + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + + if (GlobalMemoryStatusEx(&statex)) { + return statex.ullTotalPhys; + } return 0; } From c83d628b7fba050e59ccf7bda050bc27af241b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 24 Jul 2020 07:44:59 +0100 Subject: [PATCH 2487/2595] accel/tcg: better handle memory constrained systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turns out there are some 64 bit systems that have relatively low amounts of physical memory available to them (typically CI system). Even with swapping available a 1GB translation buffer that fills up can put the machine under increased memory pressure. Detect these low memory situations and reduce tb_size appropriately. Fixes: 600e17b2615 ("accel/tcg: increase default code gen buffer size for 64 bit") Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Robert Foley Cc: BALATON Zoltan Cc: Christian Ehrhardt Message-Id: <20200724064509.331-7-alex.bennee@linaro.org> --- accel/tcg/translate-all.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 2afa46bd2b..2d83013633 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -976,7 +976,12 @@ static inline size_t size_code_gen_buffer(size_t tb_size) { /* Size the buffer. */ if (tb_size == 0) { - tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE; + size_t phys_mem = qemu_get_host_physmem(); + if (phys_mem == 0) { + tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE; + } else { + tb_size = MIN(DEFAULT_CODE_GEN_BUFFER_SIZE, phys_mem / 8); + } } if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) { tb_size = MIN_CODE_GEN_BUFFER_SIZE; From 163b3d1af2552845a60967979aca8d78a6b1b088 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Fri, 24 Jul 2020 07:45:00 +0100 Subject: [PATCH 2488/2595] target/i386: floatx80: avoid compound literals in static initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quoting ISO C99 6.7.8p4, "All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals". The compound literal produced by the make_floatx80() macro is not such a constant expression, per 6.6p7-9. (An implementation may accept it, according to 6.6p10, but is not required to.) Therefore using "floatx80_zero" and make_floatx80() for initializing "f2xm1_table" and "fpatan_table" is not portable. And gcc-4.8 in RHEL-7.6 actually chokes on them: > target/i386/fpu_helper.c:871:5: error: initializer element is not constant > { make_floatx80(0xbfff, 0x8000000000000000ULL), > ^ We've had the make_floatx80_init() macro for this purpose since commit 3bf7e40ab914 ("softfloat: fix for C99", 2012-03-17), so let's use that macro again. Fixes: eca30647fc0 ("target/i386: reimplement f2xm1 using floatx80 operations") Fixes: ff57bb7b632 ("target/i386: reimplement fpatan using floatx80 operations") Signed-off-by: Laszlo Ersek Signed-off-by: Alex Bennée Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Cc: Aurelien Jarno Cc: Eduardo Habkost Cc: Joseph Myers Cc: Paolo Bonzini Cc: Peter Maydell Link: https://lists.gnu.org/archive/html/qemu-devel/2017-08/msg06566.html Link: https://lists.gnu.org/archive/html/qemu-devel/2020-07/msg04714.html Message-Id: <20200716144251.23004-1-lersek@redhat.com> Message-Id: <20200724064509.331-8-alex.bennee@linaro.org> --- include/fpu/softfloat.h | 1 + target/i386/fpu_helper.c | 426 +++++++++++++++++++-------------------- 2 files changed, 214 insertions(+), 213 deletions(-) diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index f1a19df066..659218b5c7 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -822,6 +822,7 @@ static inline bool floatx80_invalid_encoding(floatx80 a) } #define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL) +#define floatx80_zero_init make_floatx80_init(0x0000, 0x0000000000000000LL) #define floatx80_one make_floatx80(0x3fff, 0x8000000000000000LL) #define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL) #define floatx80_pi make_floatx80(0x4000, 0xc90fdaa22168c235LL) diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index f5e6c4b88d..4ea73874d8 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -868,201 +868,201 @@ struct f2xm1_data { }; static const struct f2xm1_data f2xm1_table[65] = { - { make_floatx80(0xbfff, 0x8000000000000000ULL), - make_floatx80(0x3ffe, 0x8000000000000000ULL), - make_floatx80(0xbffe, 0x8000000000000000ULL) }, - { make_floatx80(0xbffe, 0xf800000000002e7eULL), - make_floatx80(0x3ffe, 0x82cd8698ac2b9160ULL), - make_floatx80(0xbffd, 0xfa64f2cea7a8dd40ULL) }, - { make_floatx80(0xbffe, 0xefffffffffffe960ULL), - make_floatx80(0x3ffe, 0x85aac367cc488345ULL), - make_floatx80(0xbffd, 0xf4aa7930676ef976ULL) }, - { make_floatx80(0xbffe, 0xe800000000006f10ULL), - make_floatx80(0x3ffe, 0x88980e8092da5c14ULL), - make_floatx80(0xbffd, 0xeecfe2feda4b47d8ULL) }, - { make_floatx80(0xbffe, 0xe000000000008a45ULL), - make_floatx80(0x3ffe, 0x8b95c1e3ea8ba2a5ULL), - make_floatx80(0xbffd, 0xe8d47c382ae8bab6ULL) }, - { make_floatx80(0xbffe, 0xd7ffffffffff8a9eULL), - make_floatx80(0x3ffe, 0x8ea4398b45cd8116ULL), - make_floatx80(0xbffd, 0xe2b78ce97464fdd4ULL) }, - { make_floatx80(0xbffe, 0xd0000000000019a0ULL), - make_floatx80(0x3ffe, 0x91c3d373ab11b919ULL), - make_floatx80(0xbffd, 0xdc785918a9dc8dceULL) }, - { make_floatx80(0xbffe, 0xc7ffffffffff14dfULL), - make_floatx80(0x3ffe, 0x94f4efa8fef76836ULL), - make_floatx80(0xbffd, 0xd61620ae02112f94ULL) }, - { make_floatx80(0xbffe, 0xc000000000006530ULL), - make_floatx80(0x3ffe, 0x9837f0518db87fbbULL), - make_floatx80(0xbffd, 0xcf901f5ce48f008aULL) }, - { make_floatx80(0xbffe, 0xb7ffffffffff1723ULL), - make_floatx80(0x3ffe, 0x9b8d39b9d54eb74cULL), - make_floatx80(0xbffd, 0xc8e58c8c55629168ULL) }, - { make_floatx80(0xbffe, 0xb00000000000b5e1ULL), - make_floatx80(0x3ffe, 0x9ef5326091a0c366ULL), - make_floatx80(0xbffd, 0xc2159b3edcbe7934ULL) }, - { make_floatx80(0xbffe, 0xa800000000006f8aULL), - make_floatx80(0x3ffe, 0xa27043030c49370aULL), - make_floatx80(0xbffd, 0xbb1f79f9e76d91ecULL) }, - { make_floatx80(0xbffe, 0x9fffffffffff816aULL), - make_floatx80(0x3ffe, 0xa5fed6a9b15171cfULL), - make_floatx80(0xbffd, 0xb40252ac9d5d1c62ULL) }, - { make_floatx80(0xbffe, 0x97ffffffffffb621ULL), - make_floatx80(0x3ffe, 0xa9a15ab4ea7c30e6ULL), - make_floatx80(0xbffd, 0xacbd4a962b079e34ULL) }, - { make_floatx80(0xbffe, 0x8fffffffffff162bULL), - make_floatx80(0x3ffe, 0xad583eea42a1b886ULL), - make_floatx80(0xbffd, 0xa54f822b7abc8ef4ULL) }, - { make_floatx80(0xbffe, 0x87ffffffffff4d34ULL), - make_floatx80(0x3ffe, 0xb123f581d2ac7b51ULL), - make_floatx80(0xbffd, 0x9db814fc5aa7095eULL) }, - { make_floatx80(0xbffe, 0x800000000000227dULL), - make_floatx80(0x3ffe, 0xb504f333f9de539dULL), - make_floatx80(0xbffd, 0x95f619980c4358c6ULL) }, - { make_floatx80(0xbffd, 0xefffffffffff3978ULL), - make_floatx80(0x3ffe, 0xb8fbaf4762fbd0a1ULL), - make_floatx80(0xbffd, 0x8e08a1713a085ebeULL) }, - { make_floatx80(0xbffd, 0xe00000000000df81ULL), - make_floatx80(0x3ffe, 0xbd08a39f580bfd8cULL), - make_floatx80(0xbffd, 0x85eeb8c14fe804e8ULL) }, - { make_floatx80(0xbffd, 0xd00000000000bccfULL), - make_floatx80(0x3ffe, 0xc12c4cca667062f6ULL), - make_floatx80(0xbffc, 0xfb4eccd6663e7428ULL) }, - { make_floatx80(0xbffd, 0xc00000000000eff0ULL), - make_floatx80(0x3ffe, 0xc5672a1155069abeULL), - make_floatx80(0xbffc, 0xea6357baabe59508ULL) }, - { make_floatx80(0xbffd, 0xb000000000000fe6ULL), - make_floatx80(0x3ffe, 0xc9b9bd866e2f234bULL), - make_floatx80(0xbffc, 0xd91909e6474372d4ULL) }, - { make_floatx80(0xbffd, 0x9fffffffffff2172ULL), - make_floatx80(0x3ffe, 0xce248c151f84bf00ULL), - make_floatx80(0xbffc, 0xc76dcfab81ed0400ULL) }, - { make_floatx80(0xbffd, 0x8fffffffffffafffULL), - make_floatx80(0x3ffe, 0xd2a81d91f12afb2bULL), - make_floatx80(0xbffc, 0xb55f89b83b541354ULL) }, - { make_floatx80(0xbffc, 0xffffffffffff81a3ULL), - make_floatx80(0x3ffe, 0xd744fccad69d7d5eULL), - make_floatx80(0xbffc, 0xa2ec0cd4a58a0a88ULL) }, - { make_floatx80(0xbffc, 0xdfffffffffff1568ULL), - make_floatx80(0x3ffe, 0xdbfbb797daf25a44ULL), - make_floatx80(0xbffc, 0x901121a0943696f0ULL) }, - { make_floatx80(0xbffc, 0xbfffffffffff68daULL), - make_floatx80(0x3ffe, 0xe0ccdeec2a94f811ULL), - make_floatx80(0xbffb, 0xf999089eab583f78ULL) }, - { make_floatx80(0xbffc, 0x9fffffffffff4690ULL), - make_floatx80(0x3ffe, 0xe5b906e77c83657eULL), - make_floatx80(0xbffb, 0xd237c8c41be4d410ULL) }, - { make_floatx80(0xbffb, 0xffffffffffff8aeeULL), - make_floatx80(0x3ffe, 0xeac0c6e7dd24427cULL), - make_floatx80(0xbffb, 0xa9f9c8c116ddec20ULL) }, - { make_floatx80(0xbffb, 0xbfffffffffff2d18ULL), - make_floatx80(0x3ffe, 0xefe4b99bdcdb06ebULL), - make_floatx80(0xbffb, 0x80da33211927c8a8ULL) }, - { make_floatx80(0xbffa, 0xffffffffffff8ccbULL), - make_floatx80(0x3ffe, 0xf5257d152486d0f4ULL), - make_floatx80(0xbffa, 0xada82eadb792f0c0ULL) }, - { make_floatx80(0xbff9, 0xffffffffffff11feULL), - make_floatx80(0x3ffe, 0xfa83b2db722a0846ULL), - make_floatx80(0xbff9, 0xaf89a491babef740ULL) }, - { floatx80_zero, - make_floatx80(0x3fff, 0x8000000000000000ULL), - floatx80_zero }, - { make_floatx80(0x3ff9, 0xffffffffffff2680ULL), - make_floatx80(0x3fff, 0x82cd8698ac2b9f6fULL), - make_floatx80(0x3ff9, 0xb361a62b0ae7dbc0ULL) }, - { make_floatx80(0x3ffb, 0x800000000000b500ULL), - make_floatx80(0x3fff, 0x85aac367cc488345ULL), - make_floatx80(0x3ffa, 0xb5586cf9891068a0ULL) }, - { make_floatx80(0x3ffb, 0xbfffffffffff4b67ULL), - make_floatx80(0x3fff, 0x88980e8092da7cceULL), - make_floatx80(0x3ffb, 0x8980e8092da7cce0ULL) }, - { make_floatx80(0x3ffb, 0xffffffffffffff57ULL), - make_floatx80(0x3fff, 0x8b95c1e3ea8bd6dfULL), - make_floatx80(0x3ffb, 0xb95c1e3ea8bd6df0ULL) }, - { make_floatx80(0x3ffc, 0x9fffffffffff811fULL), - make_floatx80(0x3fff, 0x8ea4398b45cd4780ULL), - make_floatx80(0x3ffb, 0xea4398b45cd47800ULL) }, - { make_floatx80(0x3ffc, 0xbfffffffffff9980ULL), - make_floatx80(0x3fff, 0x91c3d373ab11b919ULL), - make_floatx80(0x3ffc, 0x8e1e9b9d588dc8c8ULL) }, - { make_floatx80(0x3ffc, 0xdffffffffffff631ULL), - make_floatx80(0x3fff, 0x94f4efa8fef70864ULL), - make_floatx80(0x3ffc, 0xa7a77d47f7b84320ULL) }, - { make_floatx80(0x3ffc, 0xffffffffffff2499ULL), - make_floatx80(0x3fff, 0x9837f0518db892d4ULL), - make_floatx80(0x3ffc, 0xc1bf828c6dc496a0ULL) }, - { make_floatx80(0x3ffd, 0x8fffffffffff80fbULL), - make_floatx80(0x3fff, 0x9b8d39b9d54e3a79ULL), - make_floatx80(0x3ffc, 0xdc69cdceaa71d3c8ULL) }, - { make_floatx80(0x3ffd, 0x9fffffffffffbc23ULL), - make_floatx80(0x3fff, 0x9ef5326091a10313ULL), - make_floatx80(0x3ffc, 0xf7a993048d081898ULL) }, - { make_floatx80(0x3ffd, 0xafffffffffff20ecULL), - make_floatx80(0x3fff, 0xa27043030c49370aULL), - make_floatx80(0x3ffd, 0x89c10c0c3124dc28ULL) }, - { make_floatx80(0x3ffd, 0xc00000000000fd2cULL), - make_floatx80(0x3fff, 0xa5fed6a9b15171cfULL), - make_floatx80(0x3ffd, 0x97fb5aa6c545c73cULL) }, - { make_floatx80(0x3ffd, 0xd0000000000093beULL), - make_floatx80(0x3fff, 0xa9a15ab4ea7c30e6ULL), - make_floatx80(0x3ffd, 0xa6856ad3a9f0c398ULL) }, - { make_floatx80(0x3ffd, 0xe00000000000c2aeULL), - make_floatx80(0x3fff, 0xad583eea42a17876ULL), - make_floatx80(0x3ffd, 0xb560fba90a85e1d8ULL) }, - { make_floatx80(0x3ffd, 0xefffffffffff1e3fULL), - make_floatx80(0x3fff, 0xb123f581d2abef6cULL), - make_floatx80(0x3ffd, 0xc48fd6074aafbdb0ULL) }, - { make_floatx80(0x3ffd, 0xffffffffffff1c23ULL), - make_floatx80(0x3fff, 0xb504f333f9de2cadULL), - make_floatx80(0x3ffd, 0xd413cccfe778b2b4ULL) }, - { make_floatx80(0x3ffe, 0x8800000000006344ULL), - make_floatx80(0x3fff, 0xb8fbaf4762fbd0a1ULL), - make_floatx80(0x3ffd, 0xe3eebd1d8bef4284ULL) }, - { make_floatx80(0x3ffe, 0x9000000000005d67ULL), - make_floatx80(0x3fff, 0xbd08a39f580c668dULL), - make_floatx80(0x3ffd, 0xf4228e7d60319a34ULL) }, - { make_floatx80(0x3ffe, 0x9800000000009127ULL), - make_floatx80(0x3fff, 0xc12c4cca6670e042ULL), - make_floatx80(0x3ffe, 0x82589994cce1c084ULL) }, - { make_floatx80(0x3ffe, 0x9fffffffffff06f9ULL), - make_floatx80(0x3fff, 0xc5672a11550655c3ULL), - make_floatx80(0x3ffe, 0x8ace5422aa0cab86ULL) }, - { make_floatx80(0x3ffe, 0xa7fffffffffff80dULL), - make_floatx80(0x3fff, 0xc9b9bd866e2f234bULL), - make_floatx80(0x3ffe, 0x93737b0cdc5e4696ULL) }, - { make_floatx80(0x3ffe, 0xafffffffffff1470ULL), - make_floatx80(0x3fff, 0xce248c151f83fd69ULL), - make_floatx80(0x3ffe, 0x9c49182a3f07fad2ULL) }, - { make_floatx80(0x3ffe, 0xb800000000000e0aULL), - make_floatx80(0x3fff, 0xd2a81d91f12aec5cULL), - make_floatx80(0x3ffe, 0xa5503b23e255d8b8ULL) }, - { make_floatx80(0x3ffe, 0xc00000000000b7faULL), - make_floatx80(0x3fff, 0xd744fccad69dd630ULL), - make_floatx80(0x3ffe, 0xae89f995ad3bac60ULL) }, - { make_floatx80(0x3ffe, 0xc800000000003aa6ULL), - make_floatx80(0x3fff, 0xdbfbb797daf25a44ULL), - make_floatx80(0x3ffe, 0xb7f76f2fb5e4b488ULL) }, - { make_floatx80(0x3ffe, 0xd00000000000a6aeULL), - make_floatx80(0x3fff, 0xe0ccdeec2a954685ULL), - make_floatx80(0x3ffe, 0xc199bdd8552a8d0aULL) }, - { make_floatx80(0x3ffe, 0xd800000000004165ULL), - make_floatx80(0x3fff, 0xe5b906e77c837155ULL), - make_floatx80(0x3ffe, 0xcb720dcef906e2aaULL) }, - { make_floatx80(0x3ffe, 0xe00000000000582cULL), - make_floatx80(0x3fff, 0xeac0c6e7dd24713aULL), - make_floatx80(0x3ffe, 0xd5818dcfba48e274ULL) }, - { make_floatx80(0x3ffe, 0xe800000000001a5dULL), - make_floatx80(0x3fff, 0xefe4b99bdcdb06ebULL), - make_floatx80(0x3ffe, 0xdfc97337b9b60dd6ULL) }, - { make_floatx80(0x3ffe, 0xefffffffffffc1efULL), - make_floatx80(0x3fff, 0xf5257d152486a2faULL), - make_floatx80(0x3ffe, 0xea4afa2a490d45f4ULL) }, - { make_floatx80(0x3ffe, 0xf800000000001069ULL), - make_floatx80(0x3fff, 0xfa83b2db722a0e5cULL), - make_floatx80(0x3ffe, 0xf50765b6e4541cb8ULL) }, - { make_floatx80(0x3fff, 0x8000000000000000ULL), - make_floatx80(0x4000, 0x8000000000000000ULL), - make_floatx80(0x3fff, 0x8000000000000000ULL) }, + { make_floatx80_init(0xbfff, 0x8000000000000000ULL), + make_floatx80_init(0x3ffe, 0x8000000000000000ULL), + make_floatx80_init(0xbffe, 0x8000000000000000ULL) }, + { make_floatx80_init(0xbffe, 0xf800000000002e7eULL), + make_floatx80_init(0x3ffe, 0x82cd8698ac2b9160ULL), + make_floatx80_init(0xbffd, 0xfa64f2cea7a8dd40ULL) }, + { make_floatx80_init(0xbffe, 0xefffffffffffe960ULL), + make_floatx80_init(0x3ffe, 0x85aac367cc488345ULL), + make_floatx80_init(0xbffd, 0xf4aa7930676ef976ULL) }, + { make_floatx80_init(0xbffe, 0xe800000000006f10ULL), + make_floatx80_init(0x3ffe, 0x88980e8092da5c14ULL), + make_floatx80_init(0xbffd, 0xeecfe2feda4b47d8ULL) }, + { make_floatx80_init(0xbffe, 0xe000000000008a45ULL), + make_floatx80_init(0x3ffe, 0x8b95c1e3ea8ba2a5ULL), + make_floatx80_init(0xbffd, 0xe8d47c382ae8bab6ULL) }, + { make_floatx80_init(0xbffe, 0xd7ffffffffff8a9eULL), + make_floatx80_init(0x3ffe, 0x8ea4398b45cd8116ULL), + make_floatx80_init(0xbffd, 0xe2b78ce97464fdd4ULL) }, + { make_floatx80_init(0xbffe, 0xd0000000000019a0ULL), + make_floatx80_init(0x3ffe, 0x91c3d373ab11b919ULL), + make_floatx80_init(0xbffd, 0xdc785918a9dc8dceULL) }, + { make_floatx80_init(0xbffe, 0xc7ffffffffff14dfULL), + make_floatx80_init(0x3ffe, 0x94f4efa8fef76836ULL), + make_floatx80_init(0xbffd, 0xd61620ae02112f94ULL) }, + { make_floatx80_init(0xbffe, 0xc000000000006530ULL), + make_floatx80_init(0x3ffe, 0x9837f0518db87fbbULL), + make_floatx80_init(0xbffd, 0xcf901f5ce48f008aULL) }, + { make_floatx80_init(0xbffe, 0xb7ffffffffff1723ULL), + make_floatx80_init(0x3ffe, 0x9b8d39b9d54eb74cULL), + make_floatx80_init(0xbffd, 0xc8e58c8c55629168ULL) }, + { make_floatx80_init(0xbffe, 0xb00000000000b5e1ULL), + make_floatx80_init(0x3ffe, 0x9ef5326091a0c366ULL), + make_floatx80_init(0xbffd, 0xc2159b3edcbe7934ULL) }, + { make_floatx80_init(0xbffe, 0xa800000000006f8aULL), + make_floatx80_init(0x3ffe, 0xa27043030c49370aULL), + make_floatx80_init(0xbffd, 0xbb1f79f9e76d91ecULL) }, + { make_floatx80_init(0xbffe, 0x9fffffffffff816aULL), + make_floatx80_init(0x3ffe, 0xa5fed6a9b15171cfULL), + make_floatx80_init(0xbffd, 0xb40252ac9d5d1c62ULL) }, + { make_floatx80_init(0xbffe, 0x97ffffffffffb621ULL), + make_floatx80_init(0x3ffe, 0xa9a15ab4ea7c30e6ULL), + make_floatx80_init(0xbffd, 0xacbd4a962b079e34ULL) }, + { make_floatx80_init(0xbffe, 0x8fffffffffff162bULL), + make_floatx80_init(0x3ffe, 0xad583eea42a1b886ULL), + make_floatx80_init(0xbffd, 0xa54f822b7abc8ef4ULL) }, + { make_floatx80_init(0xbffe, 0x87ffffffffff4d34ULL), + make_floatx80_init(0x3ffe, 0xb123f581d2ac7b51ULL), + make_floatx80_init(0xbffd, 0x9db814fc5aa7095eULL) }, + { make_floatx80_init(0xbffe, 0x800000000000227dULL), + make_floatx80_init(0x3ffe, 0xb504f333f9de539dULL), + make_floatx80_init(0xbffd, 0x95f619980c4358c6ULL) }, + { make_floatx80_init(0xbffd, 0xefffffffffff3978ULL), + make_floatx80_init(0x3ffe, 0xb8fbaf4762fbd0a1ULL), + make_floatx80_init(0xbffd, 0x8e08a1713a085ebeULL) }, + { make_floatx80_init(0xbffd, 0xe00000000000df81ULL), + make_floatx80_init(0x3ffe, 0xbd08a39f580bfd8cULL), + make_floatx80_init(0xbffd, 0x85eeb8c14fe804e8ULL) }, + { make_floatx80_init(0xbffd, 0xd00000000000bccfULL), + make_floatx80_init(0x3ffe, 0xc12c4cca667062f6ULL), + make_floatx80_init(0xbffc, 0xfb4eccd6663e7428ULL) }, + { make_floatx80_init(0xbffd, 0xc00000000000eff0ULL), + make_floatx80_init(0x3ffe, 0xc5672a1155069abeULL), + make_floatx80_init(0xbffc, 0xea6357baabe59508ULL) }, + { make_floatx80_init(0xbffd, 0xb000000000000fe6ULL), + make_floatx80_init(0x3ffe, 0xc9b9bd866e2f234bULL), + make_floatx80_init(0xbffc, 0xd91909e6474372d4ULL) }, + { make_floatx80_init(0xbffd, 0x9fffffffffff2172ULL), + make_floatx80_init(0x3ffe, 0xce248c151f84bf00ULL), + make_floatx80_init(0xbffc, 0xc76dcfab81ed0400ULL) }, + { make_floatx80_init(0xbffd, 0x8fffffffffffafffULL), + make_floatx80_init(0x3ffe, 0xd2a81d91f12afb2bULL), + make_floatx80_init(0xbffc, 0xb55f89b83b541354ULL) }, + { make_floatx80_init(0xbffc, 0xffffffffffff81a3ULL), + make_floatx80_init(0x3ffe, 0xd744fccad69d7d5eULL), + make_floatx80_init(0xbffc, 0xa2ec0cd4a58a0a88ULL) }, + { make_floatx80_init(0xbffc, 0xdfffffffffff1568ULL), + make_floatx80_init(0x3ffe, 0xdbfbb797daf25a44ULL), + make_floatx80_init(0xbffc, 0x901121a0943696f0ULL) }, + { make_floatx80_init(0xbffc, 0xbfffffffffff68daULL), + make_floatx80_init(0x3ffe, 0xe0ccdeec2a94f811ULL), + make_floatx80_init(0xbffb, 0xf999089eab583f78ULL) }, + { make_floatx80_init(0xbffc, 0x9fffffffffff4690ULL), + make_floatx80_init(0x3ffe, 0xe5b906e77c83657eULL), + make_floatx80_init(0xbffb, 0xd237c8c41be4d410ULL) }, + { make_floatx80_init(0xbffb, 0xffffffffffff8aeeULL), + make_floatx80_init(0x3ffe, 0xeac0c6e7dd24427cULL), + make_floatx80_init(0xbffb, 0xa9f9c8c116ddec20ULL) }, + { make_floatx80_init(0xbffb, 0xbfffffffffff2d18ULL), + make_floatx80_init(0x3ffe, 0xefe4b99bdcdb06ebULL), + make_floatx80_init(0xbffb, 0x80da33211927c8a8ULL) }, + { make_floatx80_init(0xbffa, 0xffffffffffff8ccbULL), + make_floatx80_init(0x3ffe, 0xf5257d152486d0f4ULL), + make_floatx80_init(0xbffa, 0xada82eadb792f0c0ULL) }, + { make_floatx80_init(0xbff9, 0xffffffffffff11feULL), + make_floatx80_init(0x3ffe, 0xfa83b2db722a0846ULL), + make_floatx80_init(0xbff9, 0xaf89a491babef740ULL) }, + { floatx80_zero_init, + make_floatx80_init(0x3fff, 0x8000000000000000ULL), + floatx80_zero_init }, + { make_floatx80_init(0x3ff9, 0xffffffffffff2680ULL), + make_floatx80_init(0x3fff, 0x82cd8698ac2b9f6fULL), + make_floatx80_init(0x3ff9, 0xb361a62b0ae7dbc0ULL) }, + { make_floatx80_init(0x3ffb, 0x800000000000b500ULL), + make_floatx80_init(0x3fff, 0x85aac367cc488345ULL), + make_floatx80_init(0x3ffa, 0xb5586cf9891068a0ULL) }, + { make_floatx80_init(0x3ffb, 0xbfffffffffff4b67ULL), + make_floatx80_init(0x3fff, 0x88980e8092da7cceULL), + make_floatx80_init(0x3ffb, 0x8980e8092da7cce0ULL) }, + { make_floatx80_init(0x3ffb, 0xffffffffffffff57ULL), + make_floatx80_init(0x3fff, 0x8b95c1e3ea8bd6dfULL), + make_floatx80_init(0x3ffb, 0xb95c1e3ea8bd6df0ULL) }, + { make_floatx80_init(0x3ffc, 0x9fffffffffff811fULL), + make_floatx80_init(0x3fff, 0x8ea4398b45cd4780ULL), + make_floatx80_init(0x3ffb, 0xea4398b45cd47800ULL) }, + { make_floatx80_init(0x3ffc, 0xbfffffffffff9980ULL), + make_floatx80_init(0x3fff, 0x91c3d373ab11b919ULL), + make_floatx80_init(0x3ffc, 0x8e1e9b9d588dc8c8ULL) }, + { make_floatx80_init(0x3ffc, 0xdffffffffffff631ULL), + make_floatx80_init(0x3fff, 0x94f4efa8fef70864ULL), + make_floatx80_init(0x3ffc, 0xa7a77d47f7b84320ULL) }, + { make_floatx80_init(0x3ffc, 0xffffffffffff2499ULL), + make_floatx80_init(0x3fff, 0x9837f0518db892d4ULL), + make_floatx80_init(0x3ffc, 0xc1bf828c6dc496a0ULL) }, + { make_floatx80_init(0x3ffd, 0x8fffffffffff80fbULL), + make_floatx80_init(0x3fff, 0x9b8d39b9d54e3a79ULL), + make_floatx80_init(0x3ffc, 0xdc69cdceaa71d3c8ULL) }, + { make_floatx80_init(0x3ffd, 0x9fffffffffffbc23ULL), + make_floatx80_init(0x3fff, 0x9ef5326091a10313ULL), + make_floatx80_init(0x3ffc, 0xf7a993048d081898ULL) }, + { make_floatx80_init(0x3ffd, 0xafffffffffff20ecULL), + make_floatx80_init(0x3fff, 0xa27043030c49370aULL), + make_floatx80_init(0x3ffd, 0x89c10c0c3124dc28ULL) }, + { make_floatx80_init(0x3ffd, 0xc00000000000fd2cULL), + make_floatx80_init(0x3fff, 0xa5fed6a9b15171cfULL), + make_floatx80_init(0x3ffd, 0x97fb5aa6c545c73cULL) }, + { make_floatx80_init(0x3ffd, 0xd0000000000093beULL), + make_floatx80_init(0x3fff, 0xa9a15ab4ea7c30e6ULL), + make_floatx80_init(0x3ffd, 0xa6856ad3a9f0c398ULL) }, + { make_floatx80_init(0x3ffd, 0xe00000000000c2aeULL), + make_floatx80_init(0x3fff, 0xad583eea42a17876ULL), + make_floatx80_init(0x3ffd, 0xb560fba90a85e1d8ULL) }, + { make_floatx80_init(0x3ffd, 0xefffffffffff1e3fULL), + make_floatx80_init(0x3fff, 0xb123f581d2abef6cULL), + make_floatx80_init(0x3ffd, 0xc48fd6074aafbdb0ULL) }, + { make_floatx80_init(0x3ffd, 0xffffffffffff1c23ULL), + make_floatx80_init(0x3fff, 0xb504f333f9de2cadULL), + make_floatx80_init(0x3ffd, 0xd413cccfe778b2b4ULL) }, + { make_floatx80_init(0x3ffe, 0x8800000000006344ULL), + make_floatx80_init(0x3fff, 0xb8fbaf4762fbd0a1ULL), + make_floatx80_init(0x3ffd, 0xe3eebd1d8bef4284ULL) }, + { make_floatx80_init(0x3ffe, 0x9000000000005d67ULL), + make_floatx80_init(0x3fff, 0xbd08a39f580c668dULL), + make_floatx80_init(0x3ffd, 0xf4228e7d60319a34ULL) }, + { make_floatx80_init(0x3ffe, 0x9800000000009127ULL), + make_floatx80_init(0x3fff, 0xc12c4cca6670e042ULL), + make_floatx80_init(0x3ffe, 0x82589994cce1c084ULL) }, + { make_floatx80_init(0x3ffe, 0x9fffffffffff06f9ULL), + make_floatx80_init(0x3fff, 0xc5672a11550655c3ULL), + make_floatx80_init(0x3ffe, 0x8ace5422aa0cab86ULL) }, + { make_floatx80_init(0x3ffe, 0xa7fffffffffff80dULL), + make_floatx80_init(0x3fff, 0xc9b9bd866e2f234bULL), + make_floatx80_init(0x3ffe, 0x93737b0cdc5e4696ULL) }, + { make_floatx80_init(0x3ffe, 0xafffffffffff1470ULL), + make_floatx80_init(0x3fff, 0xce248c151f83fd69ULL), + make_floatx80_init(0x3ffe, 0x9c49182a3f07fad2ULL) }, + { make_floatx80_init(0x3ffe, 0xb800000000000e0aULL), + make_floatx80_init(0x3fff, 0xd2a81d91f12aec5cULL), + make_floatx80_init(0x3ffe, 0xa5503b23e255d8b8ULL) }, + { make_floatx80_init(0x3ffe, 0xc00000000000b7faULL), + make_floatx80_init(0x3fff, 0xd744fccad69dd630ULL), + make_floatx80_init(0x3ffe, 0xae89f995ad3bac60ULL) }, + { make_floatx80_init(0x3ffe, 0xc800000000003aa6ULL), + make_floatx80_init(0x3fff, 0xdbfbb797daf25a44ULL), + make_floatx80_init(0x3ffe, 0xb7f76f2fb5e4b488ULL) }, + { make_floatx80_init(0x3ffe, 0xd00000000000a6aeULL), + make_floatx80_init(0x3fff, 0xe0ccdeec2a954685ULL), + make_floatx80_init(0x3ffe, 0xc199bdd8552a8d0aULL) }, + { make_floatx80_init(0x3ffe, 0xd800000000004165ULL), + make_floatx80_init(0x3fff, 0xe5b906e77c837155ULL), + make_floatx80_init(0x3ffe, 0xcb720dcef906e2aaULL) }, + { make_floatx80_init(0x3ffe, 0xe00000000000582cULL), + make_floatx80_init(0x3fff, 0xeac0c6e7dd24713aULL), + make_floatx80_init(0x3ffe, 0xd5818dcfba48e274ULL) }, + { make_floatx80_init(0x3ffe, 0xe800000000001a5dULL), + make_floatx80_init(0x3fff, 0xefe4b99bdcdb06ebULL), + make_floatx80_init(0x3ffe, 0xdfc97337b9b60dd6ULL) }, + { make_floatx80_init(0x3ffe, 0xefffffffffffc1efULL), + make_floatx80_init(0x3fff, 0xf5257d152486a2faULL), + make_floatx80_init(0x3ffe, 0xea4afa2a490d45f4ULL) }, + { make_floatx80_init(0x3ffe, 0xf800000000001069ULL), + make_floatx80_init(0x3fff, 0xfa83b2db722a0e5cULL), + make_floatx80_init(0x3ffe, 0xf50765b6e4541cb8ULL) }, + { make_floatx80_init(0x3fff, 0x8000000000000000ULL), + make_floatx80_init(0x4000, 0x8000000000000000ULL), + make_floatx80_init(0x3fff, 0x8000000000000000ULL) }, }; void helper_f2xm1(CPUX86State *env) @@ -1275,24 +1275,24 @@ struct fpatan_data { }; static const struct fpatan_data fpatan_table[9] = { - { floatx80_zero, - floatx80_zero }, - { make_floatx80(0x3ffb, 0xfeadd4d5617b6e33ULL), - make_floatx80(0xbfb9, 0xdda19d8305ddc420ULL) }, - { make_floatx80(0x3ffc, 0xfadbafc96406eb15ULL), - make_floatx80(0x3fbb, 0xdb8f3debef442fccULL) }, - { make_floatx80(0x3ffd, 0xb7b0ca0f26f78474ULL), - make_floatx80(0xbfbc, 0xeab9bdba460376faULL) }, - { make_floatx80(0x3ffd, 0xed63382b0dda7b45ULL), - make_floatx80(0x3fbc, 0xdfc88bd978751a06ULL) }, - { make_floatx80(0x3ffe, 0x8f005d5ef7f59f9bULL), - make_floatx80(0x3fbd, 0xb906bc2ccb886e90ULL) }, - { make_floatx80(0x3ffe, 0xa4bc7d1934f70924ULL), - make_floatx80(0x3fbb, 0xcd43f9522bed64f8ULL) }, - { make_floatx80(0x3ffe, 0xb8053e2bc2319e74ULL), - make_floatx80(0xbfbc, 0xd3496ab7bd6eef0cULL) }, - { make_floatx80(0x3ffe, 0xc90fdaa22168c235ULL), - make_floatx80(0xbfbc, 0xece675d1fc8f8cbcULL) }, + { floatx80_zero_init, + floatx80_zero_init }, + { make_floatx80_init(0x3ffb, 0xfeadd4d5617b6e33ULL), + make_floatx80_init(0xbfb9, 0xdda19d8305ddc420ULL) }, + { make_floatx80_init(0x3ffc, 0xfadbafc96406eb15ULL), + make_floatx80_init(0x3fbb, 0xdb8f3debef442fccULL) }, + { make_floatx80_init(0x3ffd, 0xb7b0ca0f26f78474ULL), + make_floatx80_init(0xbfbc, 0xeab9bdba460376faULL) }, + { make_floatx80_init(0x3ffd, 0xed63382b0dda7b45ULL), + make_floatx80_init(0x3fbc, 0xdfc88bd978751a06ULL) }, + { make_floatx80_init(0x3ffe, 0x8f005d5ef7f59f9bULL), + make_floatx80_init(0x3fbd, 0xb906bc2ccb886e90ULL) }, + { make_floatx80_init(0x3ffe, 0xa4bc7d1934f70924ULL), + make_floatx80_init(0x3fbb, 0xcd43f9522bed64f8ULL) }, + { make_floatx80_init(0x3ffe, 0xb8053e2bc2319e74ULL), + make_floatx80_init(0xbfbc, 0xd3496ab7bd6eef0cULL) }, + { make_floatx80_init(0x3ffe, 0xc90fdaa22168c235ULL), + make_floatx80_init(0xbfbc, 0xece675d1fc8f8cbcULL) }, }; void helper_fpatan(CPUX86State *env) From 2667e069e7b5807c69f32109d930967bc1b222cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 24 Jul 2020 07:45:01 +0100 Subject: [PATCH 2489/2595] linux-user: don't use MAP_FIXED in pgd_find_hole_fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plain MAP_FIXED has the undesirable behaviour of splatting exiting maps so we don't actually achieve what we want when looking for gaps. We should be using MAP_FIXED_NOREPLACE. As this isn't always available we need to potentially check the returned address to see if the kernel gave us what we asked for. Fixes: ad592e37dfc ("linux-user: provide fallback pgd_find_hole for bare chroots") Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200724064509.331-9-alex.bennee@linaro.org> --- include/qemu/osdep.h | 3 +++ linux-user/elfload.c | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 0b1298b3c9..20872e793e 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -173,6 +173,9 @@ extern int daemon(int, int); #ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS MAP_ANON #endif +#ifndef MAP_FIXED_NOREPLACE +#define MAP_FIXED_NOREPLACE 0 +#endif #ifndef ENOMEDIUM #define ENOMEDIUM ENODEV #endif diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 7e7f642332..fe9dfe795d 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2134,12 +2134,15 @@ static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk, /* we have run out of space */ return -1; } else { - int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE | MAP_FIXED; + int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE | + MAP_FIXED_NOREPLACE; void * mmap_start = mmap((void *) align_start, guest_size, PROT_NONE, flags, -1, 0); if (mmap_start != MAP_FAILED) { munmap((void *) align_start, guest_size); - return (uintptr_t) mmap_start + offset; + if (MAP_FIXED_NOREPLACE || mmap_start == (void *) align_start) { + return (uintptr_t) mmap_start + offset; + } } base += qemu_host_page_size; } @@ -2307,9 +2310,8 @@ static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr, /* Widen the "image" to the entire reserved address space. */ pgb_static(image_name, 0, reserved_va, align); -#ifdef MAP_FIXED_NOREPLACE + /* osdep.h defines this as 0 if it's missing */ flags |= MAP_FIXED_NOREPLACE; -#endif /* Reserve the memory on the host. */ assert(guest_base != 0); From e336cec3a59df5c4e79f6f9625780dccd8a607db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 24 Jul 2020 07:45:02 +0100 Subject: [PATCH 2490/2595] tests/docker: fix update command due to python3 str/bytes distinction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Does this seem convoluted to you? It feels a little complicated to me. Signed-off-by: Alex Bennée Message-Id: <20200724064509.331-10-alex.bennee@linaro.org> --- tests/docker/docker.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/docker/docker.py b/tests/docker/docker.py index c9f20d8d09..356d7618f1 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -24,7 +24,7 @@ import tempfile import re import signal from tarfile import TarFile, TarInfo -from io import StringIO +from io import StringIO, BytesIO from shutil import copy, rmtree from pwd import getpwuid from datetime import datetime, timedelta @@ -541,13 +541,14 @@ class UpdateCommand(SubCommand): # Create a Docker buildfile df = StringIO() - df.write("FROM %s\n" % args.tag) - df.write("ADD . /\n") - df.seek(0) + df.write(u"FROM %s\n" % args.tag) + df.write(u"ADD . /\n") + + df_bytes = BytesIO(bytes(df.getvalue(), "UTF-8")) df_tar = TarInfo(name="Dockerfile") - df_tar.size = len(df.buf) - tmp_tar.addfile(df_tar, fileobj=df) + df_tar.size = df_bytes.getbuffer().nbytes + tmp_tar.addfile(df_tar, fileobj=df_bytes) tmp_tar.close() From 182ec0607600f23e7768a1c3c490f61e36b15bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 24 Jul 2020 07:45:03 +0100 Subject: [PATCH 2491/2595] tests/docker: fix binfmt_misc image building MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we updated the arguments for docker.py we missed a bit. Fixes: dfae628459 ("docker.py/build: support -t and -f arguments") Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200724064509.331-11-alex.bennee@linaro.org> --- tests/docker/Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index a104e9df28..9119dff97d 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -78,7 +78,7 @@ docker-binfmt-image-debian-%: $(DOCKER_FILES_DIR)/debian-bootstrap.docker DEB_ARCH=$(DEB_ARCH) \ DEB_TYPE=$(DEB_TYPE) \ $(if $(DEB_URL),DEB_URL=$(DEB_URL),) \ - $(DOCKER_SCRIPT) build qemu/debian-$* $< \ + $(DOCKER_SCRIPT) build -t qemu/debian-$* -f $< \ $(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \ $(if $(NOUSER),,--add-current-user) \ $(if $(EXTRA_FILES),--extra-files $(EXTRA_FILES)) \ From 4c5aeb12387f05348d3ea25c138c450005086ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 24 Jul 2020 07:45:04 +0100 Subject: [PATCH 2492/2595] tests/docker: add support for DEB_KEYRING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For installing stuff from sid or ports you may need to manually specify the location of the keyring. You can even import keys into your personal keyring and point it there, e.g.: gpg --keyserver keyring.debian.org --recv-keys 84C573CD4E1AFD6C make docker-binfmt-image-debian-sid-hppa DEB_TYPE=sid DEB_ARCH=hppa \ DEB_URL=http://ftp.ports.debian.org/debian-ports/ \ EXECUTABLE=./hppa-linux-user/qemu-hppa V=1 \ DEB_KEYRING=${HOME}/.gnupg/pubring.kbx Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200724064509.331-12-alex.bennee@linaro.org> --- tests/docker/dockerfiles/debian-bootstrap.pre | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/docker/dockerfiles/debian-bootstrap.pre b/tests/docker/dockerfiles/debian-bootstrap.pre index c164778c30..35c85f7db8 100755 --- a/tests/docker/dockerfiles/debian-bootstrap.pre +++ b/tests/docker/dockerfiles/debian-bootstrap.pre @@ -79,6 +79,13 @@ else fi fi +# +# Add optional args +# +if [ -n "${DEB_KEYRING}" ]; then + DEBOOTSTRAP="${DEBOOTSTRAP} --keyring=${DEB_KEYRING}" +fi + # # Finally check to see if any qemu's are installed # From 8ec68a0a873d24d3f81e0f34892ec4b8b1215ccf Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 24 Jul 2020 07:45:05 +0100 Subject: [PATCH 2493/2595] linux-user: fix clock_nanosleep() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the call is interrupted by a signal handler, it fails with error EINTR and if "remain" is not NULL and "flags" is not TIMER_ABSTIME, it returns the remaining unslept time in "remain". Update linux-user to not overwrite the "remain" structure if there is no error. Found with "make check-tcg", linux-test fails on nanosleep test: TEST linux-test on x86_64 .../tests/tcg/multiarch/linux-test.c:242: nanosleep Reported-by: Philippe Mathieu-Daudé Signed-off-by: Laurent Vivier Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200722174612.2917566-2-laurent@vivier.eu> Message-Id: <20200724064509.331-13-alex.bennee@linaro.org> --- linux-user/syscall.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1211e759c2..43a6e28396 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -11831,8 +11831,14 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, target_to_host_timespec(&ts, arg3); ret = get_errno(safe_clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL)); - if (arg4) + /* + * if the call is interrupted by a signal handler, it fails + * with error -TARGET_EINTR and if arg4 is not NULL and arg2 is not + * TIMER_ABSTIME, it returns the remaining unslept time in arg4. + */ + if (ret == -TARGET_EINTR && arg4 && arg2 != TIMER_ABSTIME) { host_to_target_timespec(arg4, &ts); + } #if defined(TARGET_PPC) /* clock_nanosleep is odd in that it returns positive errno values. From 445883885a3507e3a0898df0084a59ba65ee9979 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 24 Jul 2020 07:45:06 +0100 Subject: [PATCH 2494/2595] linux-user, ppc: fix clock_nanosleep() for linux-user-ppc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our safe_clock_nanosleep() returns -1 and updates errno. We don't need to update the CRF bit in syscall.c because it will be updated in ppc/cpu_loop.c as the return value is negative. Signed-off-by: Laurent Vivier Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200722174612.2917566-3-laurent@vivier.eu> Message-Id: <20200724064509.331-14-alex.bennee@linaro.org> --- linux-user/syscall.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 43a6e28396..f5c4f6b95d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -11840,13 +11840,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, host_to_target_timespec(arg4, &ts); } -#if defined(TARGET_PPC) - /* clock_nanosleep is odd in that it returns positive errno values. - * On PPC, CR0 bit 3 should be set in such a situation. */ - if (ret && ret != -TARGET_ERESTARTSYS) { - ((CPUPPCState *)cpu_env)->crf[0] |= 1; - } -#endif return ret; } #endif From 4b84d87449f7f7cae5a032f40200915332b32a70 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Fri, 24 Jul 2020 07:45:07 +0100 Subject: [PATCH 2495/2595] python/qemu: Cleanup changes to ConsoleSocket MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The changes to console_socket.py and machine.py are to cleanup for pylint and flake8. Signed-off-by: Robert Foley Signed-off-by: Alex Bennée Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200717203041.9867-2-robert.foley@linaro.org> Message-Id: <20200724064509.331-15-alex.bennee@linaro.org> --- python/qemu/console_socket.py | 57 ++++++++++++++++++----------------- python/qemu/machine.py | 7 +++-- python/qemu/pylintrc | 2 +- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/python/qemu/console_socket.py b/python/qemu/console_socket.py index 830cb7c628..09986bc215 100644 --- a/python/qemu/console_socket.py +++ b/python/qemu/console_socket.py @@ -1,12 +1,9 @@ -#!/usr/bin/env python3 -# -# This python module implements a ConsoleSocket object which is -# designed always drain the socket itself, and place -# the bytes into a in memory buffer for later processing. -# -# Optionally a file path can be passed in and we will also -# dump the characters to this file for debug. -# +""" +QEMU Console Socket Module: + +This python module implements a ConsoleSocket object, +which can drain a socket and optionally dump the bytes to file. +""" # Copyright 2020 Linaro # # Authors: @@ -15,20 +12,27 @@ # This code is licensed under the GPL version 2 or later. See # the COPYING file in the top-level directory. # + import asyncore import socket import threading -import io -import os -import sys from collections import deque import time -import traceback + class ConsoleSocket(asyncore.dispatcher): + """ + ConsoleSocket represents a socket attached to a char device. + Drains the socket and places the bytes into an in memory buffer + for later processing. + + Optionally a file path can be passed in and we will also + dump the characters to this file for debugging purposes. + """ def __init__(self, address, file=None): self._recv_timeout_sec = 300 + self._sleep_time = 0.5 self._buffer = deque() self._asyncore_thread = None self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) @@ -70,31 +74,28 @@ class ConsoleSocket(asyncore.dispatcher): def handle_read(self): """process arriving characters into in memory _buffer""" - try: - data = asyncore.dispatcher.recv(self, 1) - # latin1 is needed since there are some chars - # we are receiving that cannot be encoded to utf-8 - # such as 0xe2, 0x80, 0xA6. - string = data.decode("latin1") - except: - print("Exception seen.") - traceback.print_exc() - return + data = asyncore.dispatcher.recv(self, 1) + # latin1 is needed since there are some chars + # we are receiving that cannot be encoded to utf-8 + # such as 0xe2, 0x80, 0xA6. + string = data.decode("latin1") if self._logfile: self._logfile.write("{}".format(string)) self._logfile.flush() for c in string: self._buffer.extend(c) - def recv(self, n=1, sleep_delay_s=0.1): - """Return chars from in memory buffer""" + def recv(self, buffer_size=1): + """Return chars from in memory buffer. + Maintains the same API as socket.socket.recv. + """ start_time = time.time() - while len(self._buffer) < n: - time.sleep(sleep_delay_s) + while len(self._buffer) < buffer_size: + time.sleep(self._sleep_time) elapsed_sec = time.time() - start_time if elapsed_sec > self._recv_timeout_sec: raise socket.timeout - chars = ''.join([self._buffer.popleft() for i in range(n)]) + chars = ''.join([self._buffer.popleft() for i in range(buffer_size)]) # We choose to use latin1 to remain consistent with # handle_read() and give back the same data as the user would # receive if they were reading directly from the diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 51aa255ef9..a09768e9f9 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -27,7 +27,7 @@ import socket import tempfile from typing import Optional, Type from types import TracebackType -from qemu.console_socket import ConsoleSocket +from . import console_socket from . import qmp @@ -674,8 +674,9 @@ class QEMUMachine: """ if self._console_socket is None: if self._drain_console: - self._console_socket = ConsoleSocket(self._console_address, - file=self._console_log_path) + self._console_socket = console_socket.ConsoleSocket( + self._console_address, + file=self._console_log_path) else: self._console_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) diff --git a/python/qemu/pylintrc b/python/qemu/pylintrc index 5d6ae7367d..3f69205000 100644 --- a/python/qemu/pylintrc +++ b/python/qemu/pylintrc @@ -33,7 +33,7 @@ good-names=i, Run, _, fd, - + c, [VARIABLES] [STRING] From 80ded8e99d9fc44c206f6b2fae6638df7dcf9305 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Fri, 24 Jul 2020 07:45:08 +0100 Subject: [PATCH 2496/2595] python/qemu: Change ConsoleSocket to optionally drain socket. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The primary purpose of this change is to clean up machine.py's console_socket property to return a single type, a ConsoleSocket. ConsoleSocket now derives from a socket, which means that in the default case (of not draining), machine.py will see the same behavior as it did prior to ConsoleSocket. Signed-off-by: Robert Foley Signed-off-by: Alex Bennée Message-Id: <20200717203041.9867-3-robert.foley@linaro.org> Message-Id: <20200724064509.331-16-alex.bennee@linaro.org> --- python/qemu/console_socket.py | 92 +++++++++++++++++++++-------------- python/qemu/machine.py | 13 ++--- 2 files changed, 59 insertions(+), 46 deletions(-) diff --git a/python/qemu/console_socket.py b/python/qemu/console_socket.py index 09986bc215..70869fbbdc 100644 --- a/python/qemu/console_socket.py +++ b/python/qemu/console_socket.py @@ -13,68 +13,75 @@ which can drain a socket and optionally dump the bytes to file. # the COPYING file in the top-level directory. # -import asyncore import socket import threading from collections import deque import time -class ConsoleSocket(asyncore.dispatcher): +class ConsoleSocket(socket.socket): """ ConsoleSocket represents a socket attached to a char device. - Drains the socket and places the bytes into an in memory buffer - for later processing. + Optionally (if drain==True), drains the socket and places the bytes + into an in memory buffer for later processing. Optionally a file path can be passed in and we will also dump the characters to this file for debugging purposes. """ - def __init__(self, address, file=None): + def __init__(self, address, file=None, drain=False): self._recv_timeout_sec = 300 self._sleep_time = 0.5 self._buffer = deque() - self._asyncore_thread = None - self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self._sock.connect(address) + socket.socket.__init__(self, socket.AF_UNIX, socket.SOCK_STREAM) + self.connect(address) self._logfile = None if file: self._logfile = open(file, "w") - asyncore.dispatcher.__init__(self, sock=self._sock) self._open = True - self._thread_start() + if drain: + self._drain_thread = self._thread_start() + else: + self._drain_thread = None + + def _drain_fn(self): + """Drains the socket and runs while the socket is open.""" + while self._open: + try: + self._drain_socket() + except socket.timeout: + # The socket is expected to timeout since we set a + # short timeout to allow the thread to exit when + # self._open is set to False. + time.sleep(self._sleep_time) def _thread_start(self): - """Kick off a thread to wait on the asyncore.loop""" - if self._asyncore_thread is not None: - return - self._asyncore_thread = threading.Thread(target=asyncore.loop, - kwargs={'timeout':1}) - self._asyncore_thread.daemon = True - self._asyncore_thread.start() - - def handle_close(self): - """redirect close to base class""" - # Call the base class close, but not self.close() since - # handle_close() occurs in the context of the thread which - # self.close() attempts to join. - asyncore.dispatcher.close(self) + """Kick off a thread to drain the socket.""" + # Configure socket to not block and timeout. + # This allows our drain thread to not block + # on recieve and exit smoothly. + socket.socket.setblocking(self, False) + socket.socket.settimeout(self, 1) + drain_thread = threading.Thread(target=self._drain_fn) + drain_thread.daemon = True + drain_thread.start() + return drain_thread def close(self): """Close the base object and wait for the thread to terminate""" if self._open: self._open = False - asyncore.dispatcher.close(self) - if self._asyncore_thread is not None: - thread, self._asyncore_thread = self._asyncore_thread, None + if self._drain_thread is not None: + thread, self._drain_thread = self._drain_thread, None thread.join() + socket.socket.close(self) if self._logfile: self._logfile.close() self._logfile = None - def handle_read(self): + def _drain_socket(self): """process arriving characters into in memory _buffer""" - data = asyncore.dispatcher.recv(self, 1) + data = socket.socket.recv(self, 1) # latin1 is needed since there are some chars # we are receiving that cannot be encoded to utf-8 # such as 0xe2, 0x80, 0xA6. @@ -85,27 +92,38 @@ class ConsoleSocket(asyncore.dispatcher): for c in string: self._buffer.extend(c) - def recv(self, buffer_size=1): + def recv(self, bufsize=1): """Return chars from in memory buffer. Maintains the same API as socket.socket.recv. """ + if self._drain_thread is None: + # Not buffering the socket, pass thru to socket. + return socket.socket.recv(self, bufsize) start_time = time.time() - while len(self._buffer) < buffer_size: + while len(self._buffer) < bufsize: time.sleep(self._sleep_time) elapsed_sec = time.time() - start_time if elapsed_sec > self._recv_timeout_sec: raise socket.timeout - chars = ''.join([self._buffer.popleft() for i in range(buffer_size)]) + chars = ''.join([self._buffer.popleft() for i in range(bufsize)]) # We choose to use latin1 to remain consistent with # handle_read() and give back the same data as the user would # receive if they were reading directly from the # socket w/o our intervention. return chars.encode("latin1") - def set_blocking(self): - """Maintain compatibility with socket API""" - pass + def setblocking(self, value): + """When not draining we pass thru to the socket, + since when draining we control socket blocking. + """ + if self._drain_thread is None: + socket.socket.setblocking(self, value) def settimeout(self, seconds): - """Set current timeout on recv""" - self._recv_timeout_sec = seconds + """When not draining we pass thru to the socket, + since when draining we control the timeout. + """ + if seconds is not None: + self._recv_timeout_sec = seconds + if self._drain_thread is None: + socket.socket.settimeout(self, seconds) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index a09768e9f9..82f3731fc3 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -23,7 +23,6 @@ import os import subprocess import shutil import signal -import socket import tempfile from typing import Optional, Type from types import TracebackType @@ -673,12 +672,8 @@ class QEMUMachine: Returns a socket connected to the console """ if self._console_socket is None: - if self._drain_console: - self._console_socket = console_socket.ConsoleSocket( - self._console_address, - file=self._console_log_path) - else: - self._console_socket = socket.socket(socket.AF_UNIX, - socket.SOCK_STREAM) - self._console_socket.connect(self._console_address) + self._console_socket = console_socket.ConsoleSocket( + self._console_address, + file=self._console_log_path, + drain=self._drain_console) return self._console_socket From 4a70232b1d26b0d73e1bce60b2c3bdb7e4279d16 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Fri, 24 Jul 2020 07:45:09 +0100 Subject: [PATCH 2497/2595] tests/vm: add shutdown timeout in basevm.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are adding the shutdown timeout to solve an issue we now see where the aarch64 VMs timeout on shutdown under TCG. There is a new 3 second timeout in machine.py, which we override in basevm.py when shutting down. Signed-off-by: Robert Foley Signed-off-by: Alex Bennée Message-Id: <20200717203041.9867-4-robert.foley@linaro.org> Message-Id: <20200724064509.331-17-alex.bennee@linaro.org> --- tests/vm/basevm.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 7acb48b876..3fac20e929 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -80,6 +80,8 @@ class BaseVM(object): arch = "#arch" # command to halt the guest, can be overridden by subclasses poweroff = "poweroff" + # Time to wait for shutdown to finish. + shutdown_timeout_default = 30 # enable IPv6 networking ipv6 = True # This is the timeout on the wait for console bytes. @@ -87,7 +89,7 @@ class BaseVM(object): # Scale up some timeouts under TCG. # 4 is arbitrary, but greater than 2, # since we found we need to wait more than twice as long. - tcg_ssh_timeout_multiplier = 4 + tcg_timeout_multiplier = 4 def __init__(self, args, config=None): self._guest = None self._genisoimage = args.genisoimage @@ -141,9 +143,12 @@ class BaseVM(object): if args.jobs and args.jobs > 1: self._args += ["-smp", "%d" % args.jobs] if kvm_available(self.arch): + self._shutdown_timeout = self.shutdown_timeout_default self._args += ["-enable-kvm"] else: logging.info("KVM not available, not using -enable-kvm") + self._shutdown_timeout = \ + self.shutdown_timeout_default * self.tcg_timeout_multiplier self._data_args = [] if self._config['qemu_args'] != None: @@ -423,7 +428,7 @@ class BaseVM(object): def wait_ssh(self, wait_root=False, seconds=300, cmd="exit 0"): # Allow more time for VM to boot under TCG. if not kvm_available(self.arch): - seconds *= self.tcg_ssh_timeout_multiplier + seconds *= self.tcg_timeout_multiplier starttime = datetime.datetime.now() endtime = starttime + datetime.timedelta(seconds=seconds) cmd_success = False @@ -441,14 +446,14 @@ class BaseVM(object): raise Exception("Timeout while waiting for guest ssh") def shutdown(self): - self._guest.shutdown() + self._guest.shutdown(timeout=self._shutdown_timeout) def wait(self): - self._guest.wait() + self._guest.wait(timeout=self._shutdown_timeout) def graceful_shutdown(self): self.ssh_root(self.poweroff) - self._guest.wait() + self._guest.wait(timeout=self._shutdown_timeout) def qmp(self, *args, **kwargs): return self._guest.qmp(*args, **kwargs) From 984c36781404592a6fbaa31ec6d25d6b8f933489 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Fri, 10 Jul 2020 11:50:37 +0200 Subject: [PATCH 2498/2595] block/amend: Check whether the node exists We should check whether the user-specified node-name actually refers to a node. The simplest way to do that is to use bdrv_lookup_bs() instead of bdrv_find_node() (the former wraps the latter, and produces an error message if necessary). Reported-by: Coverity (CID 1430268) Fixes: ced914d0ab9fb2c900f873f6349a0b8eecd1fdbe Signed-off-by: Max Reitz Message-Id: <20200710095037.10885-1-mreitz@redhat.com> Reviewed-by: Maxim Levitsky --- block/amend.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/block/amend.c b/block/amend.c index f4612dcf08..392df9ef83 100644 --- a/block/amend.c +++ b/block/amend.c @@ -69,8 +69,12 @@ void qmp_x_blockdev_amend(const char *job_id, BlockdevAmendJob *s; const char *fmt = BlockdevDriver_str(options->driver); BlockDriver *drv = bdrv_find_format(fmt); - BlockDriverState *bs = bdrv_find_node(node_name); + BlockDriverState *bs; + bs = bdrv_lookup_bs(NULL, node_name, errp); + if (!bs) { + return; + } if (!drv) { error_setg(errp, "Block driver '%s' not found or not supported", fmt); From 733dafe4914ef2e6d6a9d546b7fdbb429f3590e7 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 22 Jul 2020 18:19:08 +0200 Subject: [PATCH 2499/2595] iotests: Select a default machine for the rx and avr targets If you are building only with either the new rx-softmmu or avr-softmmu target, "make check-block" fails a couple of tests since there is no default machine defined in these new targets. We have to select a machine in the "check" script for these, just like we already do for the arm- and tricore-softmmu targets. Signed-off-by: Thomas Huth Message-Id: <20200722161908.25383-1-thuth@redhat.com> Signed-off-by: Max Reitz --- tests/qemu-iotests/check | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index e0d8049012..0657f7286c 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -595,15 +595,19 @@ then fi export QEMU_PROG="$(type -p "$QEMU_PROG")" +export QEMU_OPTIONS="-nodefaults -display none -accel qtest" case "$QEMU_PROG" in *qemu-system-arm|*qemu-system-aarch64) - export QEMU_OPTIONS="-nodefaults -display none -machine virt -accel qtest" + export QEMU_OPTIONS="$QEMU_OPTIONS -machine virt" + ;; + *qemu-system-avr) + export QEMU_OPTIONS="$QEMU_OPTIONS -machine mega2560" + ;; + *qemu-system-rx) + export QEMU_OPTIONS="$QEMU_OPTIONS -machine gdbsim-r5f562n8" ;; *qemu-system-tricore) - export QEMU_OPTIONS="-nodefaults -display none -machine tricore_testboard -accel qtest" - ;; - *) - export QEMU_OPTIONS="-nodefaults -display none -accel qtest" + export QEMU_OPTIONS="-$QEMU_OPTIONS -machine tricore_testboard" ;; esac From c22aba196341995f2e45c37eed36cc7be09e4bc3 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 27 Jul 2020 13:59:05 +0200 Subject: [PATCH 2500/2595] virtio-mem-pci: force virtio version 1 Trying to run simple virtio-mem-pci examples currently fails with qemu-system-x86_64: -device virtio-mem-pci,id=vm0,memdev=mem0,node=0, requested-size=300M: device is modern-only, use disable-legacy=on due to the added safety checks in 9b3a35ec8236 ("virtio: verify that legacy support is not accidentally on"). As noted by Conny, we have to force virtio version 1. While at it, use qdev_realize() to set the parent bus and realize - like most other virtio-*-pci implementations. Fixes: 0b9a2443a48b ("virtio-pci: Proxy for virtio-mem") Reviewed-by: Cornelia Huck Cc: Cornelia Huck Cc: "Michael S. Tsirkin" Signed-off-by: David Hildenbrand Message-Id: <20200727115905.129397-1-david@redhat.com> Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-mem-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio-mem-pci.c b/hw/virtio/virtio-mem-pci.c index d375280ee1..590cec041b 100644 --- a/hw/virtio/virtio-mem-pci.c +++ b/hw/virtio/virtio-mem-pci.c @@ -21,8 +21,8 @@ static void virtio_mem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) VirtIOMEMPCI *mem_pci = VIRTIO_MEM_PCI(vpci_dev); DeviceState *vdev = DEVICE(&mem_pci->vdev); - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), "realized", true, errp); + virtio_pci_force_virtio_1(vpci_dev); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void virtio_mem_pci_set_addr(MemoryDeviceState *md, uint64_t addr, From 2ebc21216f58f6fcbf16f7ec0bebe7f72ab3d8ca Mon Sep 17 00:00:00 2001 From: Hogan Wang Date: Mon, 27 Jul 2020 16:46:20 +0800 Subject: [PATCH 2501/2595] hw/pci-host: save/restore pci host config register The pci host config register is used to save PCI address for read/write config data. If guest writes a value to config register, and then QEMU pauses the vcpu to migrate, after the migration, the guest will continue to write pci config data, and the write data will be ignored because of new qemu process losing the config register state. To trigger the bug: 1. guest is booting in seabios. 2. guest enables the SMRAM in seabios:piix4_apmc_smm_setup, and then expects to disable the SMRAM by pci_config_writeb. 3. after guest writes the pci host config register, QEMU pauses vcpu to finish migration. 4. guest write of config data(0x0A) fails to disable the SMRAM because the config register state is lost. 5. guest continues to boot and crashes in ipxe option ROM due to SMRAM in enabled state. Example Reproducer: step 1. Make modifications to seabios and qemu for increase reproduction efficiency, write 0xf0 to 0x402 port notify qemu to stop vcpu after 0x0cf8 port wrote i440 configure register. qemu stop vcpu when catch 0x402 port wrote 0xf0. seabios:/src/hw/pci.c @@ -52,6 +52,11 @@ void pci_config_writeb(u16 bdf, u32 addr, u8 val) writeb(mmconfig_addr(bdf, addr), val); } else { outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD); + if (bdf == 0 && addr == 0x72 && val == 0xa) { + dprintf(1, "stop vcpu\n"); + outb(0xf0, 0x402); // notify qemu to stop vcpu + dprintf(1, "resume vcpu\n"); + } outb(val, PORT_PCI_DATA + (addr & 3)); } } qemu:hw/char/debugcon.c @@ -60,6 +61,9 @@ static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val, printf(" [debugcon: write addr=0x%04" HWADDR_PRIx " val=0x%02" PRIx64 "]\n", addr, val); #endif + if (ch == 0xf0) { + vm_stop(RUN_STATE_PAUSED); + } /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1); step 2. start vm1 by the following command line, and then vm stopped. $ qemu-system-x86_64 -machine pc-i440fx-5.0,accel=kvm\ -netdev tap,ifname=tap-test,id=hostnet0,vhost=on,downscript=no,script=no\ -device virtio-net-pci,netdev=hostnet0,id=net0,bus=pci.0,addr=0x13,bootindex=3\ -device cirrus-vga,id=video0,vgamem_mb=16,bus=pci.0,addr=0x2\ -chardev file,id=seabios,path=/var/log/test.seabios,append=on\ -device isa-debugcon,iobase=0x402,chardev=seabios\ -monitor stdio step 3. start vm2 to accept vm1 state. $ qemu-system-x86_64 -machine pc-i440fx-5.0,accel=kvm\ -netdev tap,ifname=tap-test1,id=hostnet0,vhost=on,downscript=no,script=no\ -device virtio-net-pci,netdev=hostnet0,id=net0,bus=pci.0,addr=0x13,bootindex=3\ -device cirrus-vga,id=video0,vgamem_mb=16,bus=pci.0,addr=0x2\ -chardev file,id=seabios,path=/var/log/test.seabios,append=on\ -device isa-debugcon,iobase=0x402,chardev=seabios\ -monitor stdio \ -incoming tcp:127.0.0.1:8000 step 4. execute the following qmp command in vm1 to migrate. (qemu) migrate tcp:127.0.0.1:8000 step 5. execute the following qmp command in vm2 to resume vcpu. (qemu) cont Before this patch, we get KVM "emulation failure" error on vm2. This patch fixes it. Cc: qemu-stable@nongnu.org Signed-off-by: Hogan Wang Message-Id: <20200727084621.3279-1-hogan.wang@huawei.com> Reported-by: "Dr. David Alan Gilbert" Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/machine.c | 1 + hw/i386/pc.c | 3 ++- hw/pci/pci_host.c | 33 +++++++++++++++++++++++++++++++++ include/hw/pci/pci_host.h | 1 + 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 2f881d6d75..8d1a90c6cf 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -29,6 +29,7 @@ #include "migration/vmstate.h" GlobalProperty hw_compat_5_0[] = { + { "pci-host-bridge", "x-config-reg-migration-enabled", "off" }, { "virtio-balloon-device", "page-poison", "false" }, { "vmport", "x-read-set-eax", "off" }, { "vmport", "x-signal-unsupported-cmd", "off" }, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 3d419d5991..47c5ca3e34 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -97,7 +97,8 @@ #include "fw_cfg.h" #include "trace.h" -GlobalProperty pc_compat_5_0[] = {}; +GlobalProperty pc_compat_5_0[] = { +}; const size_t pc_compat_5_0_len = G_N_ELEMENTS(pc_compat_5_0); GlobalProperty pc_compat_4_2[] = { diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c index ce7bcdb1d5..8ca5fadcbd 100644 --- a/hw/pci/pci_host.c +++ b/hw/pci/pci_host.c @@ -22,8 +22,10 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_host.h" +#include "hw/qdev-properties.h" #include "qemu/module.h" #include "hw/pci/pci_bus.h" +#include "migration/vmstate.h" #include "trace.h" /* debug PCI */ @@ -200,12 +202,43 @@ const MemoryRegionOps pci_host_data_be_ops = { .endianness = DEVICE_BIG_ENDIAN, }; +static bool pci_host_needed(void *opaque) +{ + PCIHostState *s = opaque; + return s->mig_enabled; +} + +const VMStateDescription vmstate_pcihost = { + .name = "PCIHost", + .needed = pci_host_needed, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(config_reg, PCIHostState), + VMSTATE_END_OF_LIST() + } +}; + +static Property pci_host_properties_common[] = { + DEFINE_PROP_BOOL("x-config-reg-migration-enabled", PCIHostState, + mig_enabled, true), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pci_host_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + device_class_set_props(dc, pci_host_properties_common); + dc->vmsd = &vmstate_pcihost; +} + static const TypeInfo pci_host_type_info = { .name = TYPE_PCI_HOST_BRIDGE, .parent = TYPE_SYS_BUS_DEVICE, .abstract = true, .class_size = sizeof(PCIHostBridgeClass), .instance_size = sizeof(PCIHostState), + .class_init = pci_host_class_init, }; static void pci_host_register_types(void) diff --git a/include/hw/pci/pci_host.h b/include/hw/pci/pci_host.h index 9ce088bd13..6210a7e14d 100644 --- a/include/hw/pci/pci_host.h +++ b/include/hw/pci/pci_host.h @@ -45,6 +45,7 @@ struct PCIHostState { MemoryRegion data_mem; MemoryRegion mmcfg; uint32_t config_reg; + bool mig_enabled; PCIBus *bus; QLIST_ENTRY(PCIHostState) next; From 4fdecf0543b49b8e171510104f3117538b9d1fe9 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Fri, 17 Jul 2020 04:21:30 +0000 Subject: [PATCH 2502/2595] Fix vhost-user buffer over-read on ram hot-unplug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS vhost-user protocol feature introduced a shadow-table, used by the backend to dynamically determine how a vdev's memory regions have changed since the last vhost_user_set_mem_table() call. On hot-remove, a memmove() operation is used to overwrite the removed shadow region descriptor(s). The size parameter of this memmove was off by 1 such that if a VM with a backend supporting the VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS filled it's shadow-table (by performing the maximum number of supported hot-add operatons) and attempted to remove the last region, Qemu would read an out of bounds value and potentially crash. This change fixes the memmove() bounds such that this erroneous read can never happen. Signed-off-by: Peter Turschmid Signed-off-by: Raphael Norwitz Message-Id: <1594799958-31356-1-git-send-email-raphael.norwitz@nutanix.com> Fixes: f1aeb14b0809 ("Transmit vhost-user memory regions individually") Reviewed-by: Marc-André Lureau Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 31231218dc..d7e2423762 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -672,7 +672,7 @@ static int send_remove_regions(struct vhost_dev *dev, memmove(&u->shadow_regions[shadow_reg_idx], &u->shadow_regions[shadow_reg_idx + 1], sizeof(struct vhost_memory_region) * - (u->num_shadow_regions - shadow_reg_idx)); + (u->num_shadow_regions - shadow_reg_idx - 1)); u->num_shadow_regions--; } From 8fe9805c73c277dc2feeaa83de73d6a58bf23f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Jul 2020 19:19:35 +0200 Subject: [PATCH 2503/2595] libvhost-user: Report descriptor index on panic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to report the index of the descriptor, not its pointer. Fixes: 7b2e5c65f4 ("contrib: add libvhost-user") Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200723171935.18535-1-philmd@redhat.com> Reviewed-by: Marc-André Lureau Reviewed-by: Raphael Norwitz Reviewed-by: Stefan Hajnoczi Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- contrib/libvhost-user/libvhost-user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index d315db1396..53f16bdf08 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -2074,7 +2074,7 @@ virtqueue_get_head(VuDev *dev, VuVirtq *vq, /* If their number is silly, that's a fatal mistake. */ if (*head >= vq->vring.num) { - vu_panic(dev, "Guest says index %u is available", head); + vu_panic(dev, "Guest says index %u is available", *head); return false; } @@ -2133,7 +2133,7 @@ virtqueue_read_next_desc(VuDev *dev, struct vring_desc *desc, smp_wmb(); if (*next >= max) { - vu_panic(dev, "Desc next is %u", next); + vu_panic(dev, "Desc next is %u", *next); return VIRTQUEUE_READ_DESC_ERROR; } From 386494f29e2b902bc501176573bb4c69eab666c4 Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Fri, 10 Jul 2020 14:46:42 +0800 Subject: [PATCH 2504/2595] vhost-vdpa :Fix Coverity CID 1430270 / CID 1420267 In the function vhost_vdpa_dma_map/unmap, The struct msg was not initialized all its fields. Signed-off-by: Cindy Lu Message-Id: <20200710064642.24505-1-lulu@redhat.com> Reviewed-by: Peter Maydell Acked-by: Jason Wang Reviewed-by: Li Qiang Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 65d5aaf08a..4580f3efd8 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -37,7 +37,7 @@ static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section) static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, void *vaddr, bool readonly) { - struct vhost_msg_v2 msg; + struct vhost_msg_v2 msg = {}; int fd = v->device_fd; int ret = 0; @@ -60,7 +60,7 @@ static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, static int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, hwaddr size) { - struct vhost_msg_v2 msg; + struct vhost_msg_v2 msg = {}; int fd = v->device_fd; int ret = 0; From d0d89526f70ded5ac41a4c6bb071c0d919b772db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 3 Jul 2020 20:34:50 +0200 Subject: [PATCH 2505/2595] MAINTAINERS: Cover the firmware JSON schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an entry to cover firmware.json (see commit 3a0adfc9bf: schema that describes the different uses and properties of virtual machine firmware). Cc: Laszlo Ersek Cc: Gerd Hoffmann Cc: Michael S. Tsirkin Cc: Kashyap Chamarthy Cc: Daniel P. Berrange Suggested-by: Laszlo Ersek Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200703183450.32398-1-philmd@redhat.com> Reviewed-by: Daniel P. Berrangé Reviewed-by: Laszlo Ersek Reviewed-by: Kashyap Chamarthy Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3395abd4e1..0886eb3d2b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2667,6 +2667,14 @@ F: include/hw/i2c/smbus_master.h F: include/hw/i2c/smbus_slave.h F: include/hw/i2c/smbus_eeprom.h +Firmware schema specifications +M: Laszlo Ersek +M: Philippe Mathieu-Daudé +R: Daniel P. Berrange +R: Kashyap Chamarthy +S: Maintained +F: docs/interop/firmware.json + EDK2 Firmware M: Laszlo Ersek M: Philippe Mathieu-Daudé From 1855536256eb0a5708b04b85f744de69559ea323 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 27 Jul 2020 15:52:37 +0200 Subject: [PATCH 2506/2595] iotests/197: Fix for compat=0.10 Writing zeroes to a qcow2 v2 images without a backing file results in an unallocated cluster as of 61b3043965. 197 has a test for COR-ing a cluster on an image without a backing file, which means that the data will be zero, so now on a v2 image that cluster will just stay unallocated, and so the test fails. Just force compat=1.1 for that particular case to enforce the cluster to get allocated. Fixes: 61b3043965fe3552ee2684a97e7cc809ca7a71b3 Signed-off-by: Max Reitz Message-Id: <20200727135237.1096841-1-mreitz@redhat.com> Reviewed-by: Eric Blake --- tests/qemu-iotests/197 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 index 95f05b0e34..121959a09c 100755 --- a/tests/qemu-iotests/197 +++ b/tests/qemu-iotests/197 @@ -112,7 +112,9 @@ echo echo '=== Partial final cluster ===' echo -_make_test_img 1024 +# Force compat=1.1, because writing zeroes on a v2 image without a +# backing file would just result in an unallocated cluster +_make_test_img -o compat=1.1 1024 $QEMU_IO -f $IMGFMT -C -c 'read 0 1024' "$TEST_IMG" | _filter_qemu_io $QEMU_IO -f $IMGFMT -c map "$TEST_IMG" _check_test_img From 54414d0fb11314ede939ec80238787c5b2079f4e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 27 Jul 2020 09:15:42 +0100 Subject: [PATCH 2507/2595] Update OpenBIOS images to 7f28286f built from submodule. Signed-off-by: Mark Cave-Ayland Cc: qemu-stable@nongnu.org --- pc-bios/openbios-ppc | Bin 696912 -> 696912 bytes pc-bios/openbios-sparc32 | Bin 382048 -> 382048 bytes pc-bios/openbios-sparc64 | Bin 1593408 -> 1593408 bytes roms/openbios | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc index a07757a987e9ad424067427d23a1a46762952939..def6d4cf63380d2601f35e2320b38055b8c4d6f1 100644 GIT binary patch delta 43765 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 A5&!@I delta 44195 zcmce<4_sWu)jzyT_7Xr+HwiH$5JQ9rF^~{L3{gzbU`2yJv8I()S{K;mkJ-QqOF|;L zBq0$EQDTt6h)N<=tke+2guY^>ii(v!QbkP_D{WD+(hBU}lu{n=?|WwE?k-WEfA9Oe zd_IS{bLPyMGiT16`Frp7_gvE7b4mM?hZdL(m3Ku{BwGxIbi@8XB{v%k$yMg(Up%yR znbE$_eBvJS3FB$=iGZzdhpvyhH1X2Js5R>^Uz>RPj=N{wmvnmSxmmVnjW;k$j;X}> z1J+ML7E8@Vki*(@O=ZU4vdlcw^4Y-#gXXS!pCT)bf1x0THRqXT8^;=~rkEf@5T)-i z@QB$LS!pEH^4S4?$yK2|5-Ku^$RgHm1>+btNI@bCvLV>Wl5D0}SEe@hi$u-6H%l9P zaune@z0X3Ow6UkMHMeW2#91V+QggQjAfFxa<)EoTxKbNyokn;*!e)ev5Lyv} z-_w5wjR(&*gw+VQX=81}fM#v%^oKUnOUi<5dydmq<~&fPd2aU@3xtkO<=SzWs+jMcqknr}SA zrr$MP!v5_Y({`hYrMzo;+1Ny=XXa)L32Z%(vRU)I)66;tP`@B%de3w-l#unFX|=JF z)x3w|M?h=RJnw}G7(nswMI1gkU%35=g6!zUvYJiI^u`C|*G16ljWrukRGgblNh7-lcY z%dwXwK*-#A7{$t{jk%@7!E=`qY_&JhEkWag2q_6d+ zN6GY&8R<#h^i+}l84SaZ|2jS0^|?h7q|G3>OegrfN~Sw!q_6j;H_LSN55EGEz3JUD zePBlVnq{JbF3;yff`Drv%clWJ;33QQYQUGi)|(zB(@6uq^dxV3sz~P=@TIR4=`PJP zVvz)-0UyC-UItY%oiyM}U++zCmg%GcUwX1Py<4V}27Kvd38l6iD|_S%Q|O8zPy}k8 zJ7B(_n*cEYNb|WBPz`7S^ZURHPz zdC={@NJq%+9B$2`c?yD{aR=GG=5b_;aE6eH36%Q~&s#0>29i(wqK4W3YFfIeTi~{V zcR?6C)I-_luYtFHP2t;HBV6$%9Ckdpq?cr;OxMK3VNs{>2Ic$ zb8AGB&2py@sfs!NW?H(UUQm4r&ZKElA}_^yPCT7;{>`-0Sj`guj#0zPoFeG_yXlHG zTffPJOCY8Fv=Z8HlaiXD4F`+)%5?3DZ>dz-AdzX>*A-xCN!Yj-${X!x^{j83HG1g9jne|hU$i~J@3pY@Ez%Eaco(vnU#j6}SrM6-x zjfG={erYC3%PTChTkj>i8mnfhGs_+avo2Oi!60iIH(eAkHqE*z8pVbvNNt$F ze+!GEpo*nVpx9$yUWky!lL{wIFV5`{%!<&#&!QuXG9p>#KTQjlpa#N|7ZsN|bBgn9+{1EHoUCTm z|1_Q0Ff6j`bKGA*I} z=PYw>#dY!qa{X?pY_vl3w}d?;R7Z>)XDs@!7id8kXd*%-;p zM&$~4>I@^&+gPDdxjDF3WEvY{mSANe`^cz-Vxcu+RAMo_m;;p6$d-!Wx*_2Y`5+3* z&TrFHV-y5}J@AfflKxVU2VqR1N#|2!#V?$D-xP{xq^kB9Oq*(4t0?GCC@Tp zW>K@0wZ^S%>ntUDZih@UA=OGkuo|G3%*Y@}wx?^JT`8L9s{z&v1}mf?Z94;$;Gza_ zQ?}ap@KnS{V0BhDi!mwJg0bDCEJfcKgJz5!EL%aWhV__~)eDe~*BZ6lR>wg zRyJKFO?z9WrW%}J*Qt55UgXFm3$YdR+LSpZMFoGYi>8%}xH*lgtj_S@OY zqB+vXfQQ7#!k>f(DbY8Hey9eXLHUs9PBc58i;+xWLi?09oBEFQ#Bd9_<=7r5c9w3; zbCmPaXE%W!!+B6Bs||wX4YSrD<=RC-LMB?U+Xldm%5UfG85FF z5=C{%=E%1814qxWMUOCGniEw8qnVtnIarBUcSbOwdFg~?NW_vUl?Q#%Jjhn++=X5b zT?J+8?H3fHEWK_k8k+oo2}So2b)3~^w>fPIdaf0RDOYeNugy$*4j1B)9glZ0M~D); zs9jXL4HdQxOB)JB_72t_qC{_)6kKM*tPY1!sWiMG8B*9RR@;suj7`p64x1Qi)Q}{d zo|&7K1ujWgYAe`>1c()4>-?uo~J}FGsu38wi=HS&)XpK zt7v52W-%-=6g?n=Z4Fgc&Xv^E`G^9%>Oz(E8#;JVykW;%gtd@?@uJC6z5= zX~4BK%z@Q(v#2@BN|#B@#m1m@p203Myn@UWAE&ajG>hdkzA#nV9u^O0-Lk8B|Ic72io*Wl252p&H!JnKhNxfZk$I z6%v)~iSU^CVNqIEm>|r8cl$Xbq6WPB;3Zuy-=X`8RDs&C!1I;42{k-IdhoY;t{d{t zQUD&GGs@D=S60uFa#Qagv$HCoT+~WnNmcj?R-v~DwIX?~LR5u24ug+wazx@#6+N#P zS1r|n{Ds5fne(P{AQe@M$EhlavsGqgnQ?$+nw5pilQhphLtji3u9%Vx`YNxVkvvSLvY+=S`3+gh!EOV8WR|?DKtwh!M3e_Qzy)6_* zqyp#PNC?nLH_almJKu%j{3 zD2nHH6-4$V;x-Fkt#T(ax1QPODG|Xk3D#Oi(LPZUdThr$440v7Y@V`th47!koj0Q@ z9h{#!4`q4VAI3IsE6bj*tXv`elNnuSUZb=>D_Ng#IrGT&Fyvg?%-ZKG3)cmSGTWda za)s36=A*}u`I6Of^R*^8a`Lw26o~C=b$%S1o{ts@ZD>^%%~I#bH>|~od3~6&C|I`6 z_s%eTn6h$7lIE!n(oGjbNwF{tOxhtE>j+a;uR(2SGGepDP`X|a?2IK;mXAU!PBfV9G-oYHH9k? zIW;KA1Te^^PQZFEZyRri@Nl5TUZJ`W+6>=Jbbfz{!11F1+UC=nu$K3b@FdWo0^yM? ze35e758=#7`Etih4Nn$JakvSP$h0bs6LH{$89GWFI%he=hdaEi`xYs;xcsxDVK_T~ zw$MXC6!3bHaXRbUtVKBm31vHroOy+On?+p|1J>vyCm<^3HR$l$R$%3>F6tNf#RkGx z@ft1?#^Yhf7b{_|Mblg;zAnWcrn+d9D0dPE-t!leE-~WMy0tJ>Pq+Khll{^&^z=9f zR?%F7#aT#)WQ*a)bqN+%h&)&Wvvm>5JQq~&EdyO`aix#}JcJCbe(9BZx}C}p>AimG zHF|n!ZmOI*EtWO5SxR^6xQHN`$5Lwli5D5^MdmJ(nInWnL-^92UR;`&&hEugMM+VX z(hAORkETXoV>S{dYhbC7%F0D(1R80@(!aEV=On5sqKZ&fV`-p_vw!AW0&#RGzyi_$ZQ`q9ZAlY%uNRv43*uxRWa7W{X-0J0Vu~D_XY%lSu zlDyDwX}gJL5ujHi5oZUMD9biTf1jU3)hsWwl_uommXy+7r@F+ePq9Z=iWzQMQAsiO zM${!SY-ouX5h=)K;TI}P7f2(3zsf1wR?SUwNh8ZZlB-P!vS@(HLBB3_CXzKTk>%4I zfcC^_tp0b%@(*|mNw+zu{BCHUsJ>DbfNXzg%Ltyi!%{*hZS7dDCn>evQlhWqIR?bw5}1#xv*OhV1%=k zmX?%qfreQ9QjENftbeHzvCN}W(1uPDr*QOe3?=;Gc%2<=SGNq}jP zIu~7U9H*>N$`;y@(PuuriDH&C1{@8Lw07E_laOP_Vap2X-j-5Dy(beqJs(So6=WSz z;?5;&?gEkukAZW@a@PDY0{#QQdm~B-VYAQUD#sMT370 zOQ)cf6;ja4YA6_CtrP^Y-e?pW$3`j0VCEPE4wghgJqpYYnzhqTe(QewaSEI2%6r)7oq6K#%G>O+&(idSq8H3G*Q5L#fSv$uf8>~}P zk&>|-^^Esr!Zeo9P0N+&;7RThurI=Tmm_~7^DM`%#OO@om@)7}rszzTcCixcm&wwB zZ8)n;jc4^2D_dx4d$F=#lDoJ`@eq{v;d zVBF(ld~q)^j$(0f*s;lGsc~51G>c@;_&mAOLsK0Cq{QrqW|-cY18;myjcp-Q!ji_C zz^AjM>{wZhT#%_3^$AP&PNqBfGEv!)fW&=%IY0#-7~23IJtbA%@NPRLj{Ghd=CTmUCq2&>d* z$dor0lg3Mw^>aggy2Z3t#bmYrQf%;PE0x(UE=HHow>}^ zsZpb%GJ3_xMbYyL2up5^gyyTPEFbN?lY(Ytl;G=KY1x5?a`^K7!+2#b4#I|7ObZu8 zq0&9Rl^JTPhBY_*8awpy3ChA7GDIVBeN}N%HF{9A3&+Js9JL4ZX(J_7A&*H@<6$pc zVd**zs{>1N07ObU^(W^GhI6vhI34Yjto@pr;~P0%%u9(b)a%&Qm@pQ)N?E$R#b;t% ziM5U5l47aLrKt>9W_UaiEs&_ZOs z)Y6XB87;;OM=Oc2p40KV=%texb3cy>6koeYpYMGJKYHf$qe2S)+~<2%p&rXNh21w)GKTOa-+l4Vnzw|$n-ACEVRV#s07BD4GSqpgTb0FZ18mOo^n{a>n!x76r_R-sZ%4Y;QU13u=j851({ z{_hmESmR-tYq6sZM%1-&g{>H8aSohC^9k{#O(F|bI0_0Re+M7OT?Dl$j`>Q86NDm@@zIm%sjMyKOt> zfHaF;2NbQjMcp?#3U`$i;X)i2c3qf%8g@yrFOjodEPmD{`lr!B1tcea87SY!&{|pq z`FKHA{|p7CCFKrWxU=#Z*t$ypGzgw67MJV9yj%*$@d-PMN}c67cCL+e?f&`VN=vrq zmlQjLRtV|)S?y)$`=hLlf>2!A3qL)4nKC!v z6o8?KtfjW-Ol z#>-K)N!E#AiC22mAJ*o`!NHEx#vADJWLDX2qT841kl8` zVG$*L1u^~qfV*OrxM!(e5v@OL#y!jMS!{ZvG9Sm9=1pio2XgUxPy=x{!S~QM*05A0 zWl3Hn6Tus7@psq#%V&Q;^LfQxR0M6bhPHb}BO9SPa2Whfs)j zwT0Ub@HYwEAVhnnn*7t{L6?7e%#8HXoSoRkD=6Vso0`^el@hVS!YR}rPm(LN+8oY8 zQ5WfvQe}tPSj*C`QeqcStD+OH8-r1s0Z`XviLB}>tmn~yd~3u3dm0fwnf&tx>7V&C z{5gEJx)E+(-gQwo)cDb2AS7STX{Y70Wg}S@?>kqa2r8aK!%~$~Sv!2aLUN9*Sg>8;w ziD^p2O|VlDB~9h$u0iK1D6rcS^2$r$`}nEi=C*TbY^As#kRW;@`ZPq@+^^HHCa?__ z%XuoL8__jnvHli2$nrWT+&i>Iu?2jlrQVInU82BoWHS%g419#GgZ$i$&ONf8OFG5*m80ah^*+{ozvDdFBFMQ!i?;A(LB* zx*-{1l%}S_^tc5XB;HOqR`q=)+SVbnz*33i8dw|Ved-38MP`+TM>6M?IChDCN+NyV zB=YO|^e}nIp9c%NR#~f$=$EI6*%P0Mk)caz{j!MJFjSR~^lK^*@`(}^&)dXnFf{Y{ zzBG97Rg73 z?+|gClahNu8Pe4t-}w@k5_1j_nnCy@5NUcwHkghcHy|3-zrq{N(dGLw2b@_ttp`-efdR(tZsnf$P~ywCBp?^W}$0|`=|77 z&hQ&~NZBONHP~Xj4)XxBDEGQBuyPm-Q3mV}_iHMTOV)fS^4geiO4nsbd54hCg9b-E zp&#L@rN!x;1?eIU#z2PkeF`hZb09@F)G){ON`$Qi`Ga8H)i4m>v$(*5VPH4JCh;ln zcUiSxJMe8D>M>qg7~VA%Z0vfhHmd)>5g*bEyB0NY`K11jYCsxO(Z4C{42}HuVb7@KB8?*w?qE?A|m|zxw@jY7vf`;Rn8tW)%f}b1>Ng z)1d(;8D+Y7?W|xB1R(v-ESwketp%W9VxZfTH(w9Od-+JMap6fQp9Z)$WOHs%LR`aK zAWwch*Rr11>s|G+K-ajRlcGGT&;Rg?r`|y=qeAc{ze2L=Qy6MZ{TW@;!;c*J+y-6~ z3B1qxyL2eVQ<;d$f)NS9X<*=BstZfX^U=UlQvteDqs}%X4u$*0qrG0yo1sGzoDqd? z>|)9P2X`}|K<^<_6koQh8@u>bByrd~+geoSu;=W8W58V}vFYT19AHD`k^JAE6yc^Q zA1>V@aR_y~^d5<;^5I<9p<={jQ?m~#yb*BSemGbWryKU+uCEZd)F2;ji&Ns_{BR=@ zm+r%5K!M=5P)(JZBj(piD z$sAy{H{ssFDC@XMxz!lP%s)^T29M$NFHKW3&#=TFD9@}BZKB>3j;dMWw&&nHIe}Qq z8QD#;mu7#22%iwBz+{~&5fIJNdh|E7bQm~=#{@H zgP|VYocCtx31H~K1YOTI@E>IZ8F?D&G&8bQvZSrwS(>K+-H6Qo8$wpHdStumzb&L_ zNpAjU>I{jyhP__0Wmk-IOO>Wbb&Wz5hPH@4a1hM1KO$+#ZpExA71H1(GN*_FxYyl5_^?J?6k^c zbY4*w^#-uv5NzO9NYdPp4S(WfaR`>fF1@1wjY5c1 z&*a(@HcR=O*~-dbMClYFd5E=UE1M}w%0j9KsV;Z~T?#TFs*u;%B`NT{3+-)|x`*Dq zGndc$&;7ISWpDJ^ggV0+WSTG6lO(tyMr^?zzLZ)-e zS2y7f$IsBtzS?E|Oj)~pOg34SP|b`cYeYenfFaiYGi9O6SJ`tF!e>?FL%a%rrvDoX z;OfU%D_RLwvs(4D1eM(Zoh0=_!4^d;v4<& zcqTkuOMzf@7A0cNjAYhnfw?vE66sd#s0HT@XNQx>axP+7o=a+Dw8 z0KYp&iJnsp89a)!!xGG*oRFJTkKBSps(W_LAjx#EW9NapQl7D zmt5%P1if09kZ;?OV_(5HEpo-m1aGV{dmiQ#k*q6Exp`TSU_iPO??_2Knlv>RmV}pY z60JCWZDfU3Y-fpap5CMyu;Ti}0E@FJt8YM8q3%dWNU#|GIvtPGGYpz{RbklP8#dCb z@>lVYuI8GBGj=z!7902M{Wj(8Wl*&zimG2;Y_;LU2d`am9mum7Ydq`DS2p9V4O0Px zw6c@}XtarC6)2lsov4|-+jk)>C%^E244&yU+_DQ>;*Y$u7z<_u^ z?RJ>N*OPcJBVF^HUR=PGR)#{S2nrgke-RN4LbmJ`)4Bnyrw|^FU0=^ zUQ2nsy#K?X1<0P*cZny0Z}^BisQ(&)_oN8yqY&81#w z#s#Jnz<;4NE}R5i6Kda!a99Wt1#N_l@@u2&x^PWhSc{G1r2kyNbVYzA}#pn96RrN)Vo6U!RfdgB{Ke8VV{FEnQek_t^-W#S7?bp!a&)*m+5 zT{DROC$+|kkk(QvR)Mt2QL)IQEhY838coHbO~oQj-7=!7ScIt=1LtZQ?f*Y1)IU#B zI<(aah!eb)KoI}*|M1yW_}?J@U!ZmUhtmBo6nIW~uK&8K{u5zBlHmj31+iN|x9D+u zo-Wz&n_YNcfUb|@PJAc7rpU|0ttnj0NBf7tde^}+lSTl@v?LTR7SBsFHP2&J;=bd7 zVc_HV1#?^~*Hk4#Qv<*(cp70At_?>5QUKY2Hb5U>RP$89^;TtoM-rS?-M2Kg-u@Ax zxXhalhys8~1TsW8@Nygc|9%ey>;Mc12AJija~tuFT#Ke!6Cr3JF4UX9g*ot2-JWd@ z@3W5M;o@`J!!MCdI+P0+=TBqM#3n)T)?(ToFWq4iw-y{YQoaLYDrOznjpGyJAPf`q zhB{q7p;3RLUX1h<(o8_iJ87!J(|J)2nMM=qK;)-zww@lNsYqAxY8u~wb6~us3t~33 zuHy{KHN+LMi97Jd+kg;)3Zhr*iHR-@W$?#Q+W9jJ07K-D2N*Q9v{!~`(L1IQr|677 zdbMo^!f^QId9WXCfHjrkK2$O?#Un~Iq4egSB*va4MrgGZt*nKzp;BeN%Yr0+@7wP} zqTE0!tq^H%!Fs$ebJB%HJ-uF}(|hs1g2fX#42@otYmTJm}|ANx^iXVm1D>^qZ){VeR(aw z39teR3FrR@9I8pxh+#oHl=H8t2F4DGAYEWQLn>hunz|ze>7#%_z>q&DdIk=q32s$8 zl=GGc0W%F4M&fKgj-cED``>})+hJnuJCuc2q53UgT(Kj2ahpNxt`NWI07TV7;$(u+0t1Fj8FPmR55*JISRxk(C##S#XrsN1KE{%>onLCGIK%39;SR9}Nwi;T zwwL5s>7^kjzy7l;95}wNKuCX3(5}t&z)A3JE}VADvUeo{ZK5=sK;sA>cer^GyRvos zGQnJ4?%w4D9-d=Yh32`QU&h4;uc&Zu##$eNP>#)>pOA|_RKwSUyV{UWLK}eJhXBgi z)yJxKW8Yv1QA!G^$ScXu=XW7?O-kG>hixxNcZbTjDF-H3&9m<&cS89TzVhPvc2m6w zXU@l49fbmyCUJ8~9J(weMB1Gt@Ru0oIZAB~$2%o(=uMoEYiw*o;!OFK_6AN2E+v+|{FV~Pu5&5#j7cop zrQGcL)|z`2C`1mTW^?2?3&9g&2ce?0KLh2eyIW8ew?xr;ccltF?E?OOxU)Oqy6#FN z8f#Ihv^tl?M{@y)_%IF6i4XPRd4Q`dtx73FhwQ9UHZMRM+AIYnWQ8u2!h3;*nfEBq zy9xy-n`I?VjD!SxVszZ9T!$=iPqL0%>BD8{xC9^0;>7_e`H7AP5po@R=h!3K7RQcw zvq(4GJxzLM!j*B$-_x$+3QN4g^!VX)q0i{Jf|4>_=usW##2pnO%wC|#^6`Qg-QIK+ zlk3|XrXyG7;?ro`93{BMDBaB7IByzB#f93N=Ec!LV`+Jw6ZbAf58F#!k{7Tl$11Nv z?)7S*Y}a-v++MB$7fAx-MtHVz;lK8JwZL&3k;?tr-VU9y_;iz9zNNaiZzjG>z682= zSjXo$9QIv8@M#?vw~A|tM)`ea*0WD3m=hz@96;e)gw;3{t7X{;TwQvuRk#pp=a(J# z4e7X;vZ8!(`)i*^#}NwO%8-&&2kCfpfjr^Ss-tvV97pQcd#jUlJl|yFQU_FLH0)PO z;GrD*aj~y|21No)itDF(gf$}>clbK@V@o?6RI`W@Cvvz0Rw_^G_RFTD&AWf=c8PpzHU@Jxj@ z%6i%-*>BOkZxluWTMoU7!^teCyJ~PahU<-^_d<@L)8Y3i%(zT;T-K_o_j2EWtKNLd z3Y&yM9K^TP4nom15OGV6DV~v>-cXAn&*GO_j;}Cb#!J(MgB3a+Or@hLKX?pKyxWA+<_f`oM(;#Nd2kQQSc zr+KOn@KBWyP>gYe7lQ@f9IL%wSwCk$Bx77s58+tqew3ZXM(GcR;OHt4cNrP$~L^))_g=+HjB;$x({O)yoN^g2)wA5cm$N!Kd2-J)J+pj zG?+`O{}Uhw|0QIIJ@O5qI6t+;Y3c(>#G(Y{d`D)sx?TyLixC{7tEYDmA!Zg|d00lh zl9vFz(TH~ljeA&h3^cC2jEt||ER;�O|ArkimMq8HV!Ff9QmOP9e+>;m9ribn-*W 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 WM8evvZ( diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 2faaab83ba762392c9a548c49584c023f4d233c2..67b8b83d984a3f4f804dab117b54b89783579824 100644 GIT binary patch delta 34491 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 N#q^GWUiS&w{{gI7Wo!Td delta 32070 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 diff --git a/roms/openbios b/roms/openbios index 75fbb41d28..7f28286f5c 160000 --- a/roms/openbios +++ b/roms/openbios @@ -1 +1 @@ -Subproject commit 75fbb41d2857d93208c74a8e0228b29fd7bf04c0 +Subproject commit 7f28286f5cb1ca682e3ba0a8706d8884f12bc49e From 4bf7c0cb09a59314aca261291e3a20a24c7dd3b3 Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Mon, 27 Jul 2020 16:12:10 +0100 Subject: [PATCH 2508/2595] ACPI: Assert that we don't run out of the preallocated memory data_length is a constant value, so we use assert instead of condition check. Signed-off-by: Dongjiu Geng Message-id: 20200622113146.33421-1-gengdongjiu@huawei.com Reviewed-by: Michael S. Tsirkin Signed-off-by: Peter Maydell --- hw/acpi/ghes.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index b363bc331d..f0ee9f51ca 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -204,16 +204,12 @@ static int acpi_ghes_record_mem_error(uint64_t error_block_address, /* This is the length if adding a new generic error data entry*/ data_length = ACPI_GHES_DATA_LENGTH + ACPI_GHES_MEM_CPER_LENGTH; - /* - * Check whether it will run out of the preallocated memory if adding a new - * generic error data entry + * It should not run out of the preallocated memory if adding a new generic + * error data entry */ - if ((data_length + ACPI_GHES_GESB_SIZE) > ACPI_GHES_MAX_RAW_DATA_LENGTH) { - error_report("Not enough memory to record new CPER!!!"); - g_array_free(block, true); - return -1; - } + assert((data_length + ACPI_GHES_GESB_SIZE) <= + ACPI_GHES_MAX_RAW_DATA_LENGTH); /* Build the new generic error status block header */ acpi_ghes_generic_error_status(block, ACPI_GEBS_UNCORRECTABLE, From ca05a240d4fa2ce880c630058b635482d3d472f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 27 Jul 2020 16:12:10 +0100 Subject: [PATCH 2509/2595] hw/misc/aspeed_sdmc: Fix incorrect memory size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDRAM Memory Controller has a 32-bit address bus, thus supports up to 4 GiB of DRAM. There is a signed to unsigned conversion error with the AST2600 maximum memory size: (uint64_t)(2048 << 20) = (uint64_t)(-2147483648) = 0xffffffff40000000 = 16 EiB - 2 GiB Fix by using the IEC suffixes which are usually safer, and add an assertion check to verify the memory is valid. This would have caught this bug: $ qemu-system-arm -M ast2600-evb qemu-system-arm: hw/misc/aspeed_sdmc.c:258: aspeed_sdmc_realize: Assertion `asc->max_ram_size < 4 * GiB' failed. Aborted (core dumped) Fixes: 1550d72679 ("aspeed/sdmc: Add AST2600 support") Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- hw/misc/aspeed_sdmc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index 0737d8de81..855848b7d2 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -255,6 +255,7 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp) AspeedSDMCState *s = ASPEED_SDMC(dev); AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s); + assert(asc->max_ram_size < 4 * GiB); /* 32-bit address bus */ s->max_ram_size = asc->max_ram_size; memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s, @@ -341,7 +342,7 @@ static void aspeed_2400_sdmc_class_init(ObjectClass *klass, void *data) AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass); dc->desc = "ASPEED 2400 SDRAM Memory Controller"; - asc->max_ram_size = 512 << 20; + asc->max_ram_size = 512 * MiB; asc->compute_conf = aspeed_2400_sdmc_compute_conf; asc->write = aspeed_2400_sdmc_write; asc->valid_ram_sizes = aspeed_2400_ram_sizes; @@ -408,7 +409,7 @@ static void aspeed_2500_sdmc_class_init(ObjectClass *klass, void *data) AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass); dc->desc = "ASPEED 2500 SDRAM Memory Controller"; - asc->max_ram_size = 1024 << 20; + asc->max_ram_size = 1 * GiB; asc->compute_conf = aspeed_2500_sdmc_compute_conf; asc->write = aspeed_2500_sdmc_write; asc->valid_ram_sizes = aspeed_2500_ram_sizes; @@ -485,7 +486,7 @@ static void aspeed_2600_sdmc_class_init(ObjectClass *klass, void *data) AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass); dc->desc = "ASPEED 2600 SDRAM Memory Controller"; - asc->max_ram_size = 2048 << 20; + asc->max_ram_size = 2 * GiB; asc->compute_conf = aspeed_2600_sdmc_compute_conf; asc->write = aspeed_2600_sdmc_write; asc->valid_ram_sizes = aspeed_2600_ram_sizes; From a6d6f37aed4b171d121cd4a9363fbb41e90dcb53 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Jul 2020 16:12:10 +0100 Subject: [PATCH 2510/2595] target/arm: Always pass cacheattr in S1_ptw_translate When we changed the interface of get_phys_addr_lpae to require the cacheattr parameter, this spot was missed. The compiler is unable to detect the use of NULL vs the nonnull attribute here. Fixes: 7e98e21c098 Reported-by: Jan Kiszka Signed-off-by: Richard Henderson Tested-by: Jan Kiszka Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index c69a2baf1d..8ef0fb478f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10204,21 +10204,11 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, int s2prot; int ret; ARMCacheAttrs cacheattrs = {}; - ARMCacheAttrs *pcacheattrs = NULL; - - if (env->cp15.hcr_el2 & HCR_PTW) { - /* - * PTW means we must fault if this S1 walk touches S2 Device - * memory; otherwise we don't care about the attributes and can - * save the S2 translation the effort of computing them. - */ - pcacheattrs = &cacheattrs; - } ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, ARMMMUIdx_Stage2, false, &s2pa, &txattrs, &s2prot, &s2size, fi, - pcacheattrs); + &cacheattrs); if (ret) { assert(fi->type != ARMFault_None); fi->s2addr = addr; @@ -10226,8 +10216,11 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, fi->s1ptw = true; return ~0; } - if (pcacheattrs && (pcacheattrs->attrs & 0xf0) == 0) { - /* Access was to Device memory: generate Permission fault */ + if ((env->cp15.hcr_el2 & HCR_PTW) && (cacheattrs.attrs & 0xf0) == 0) { + /* + * PTW set and S1 walk touched S2 Device memory: + * generate Permission fault. + */ fi->type = ARMFault_Permission; fi->s2addr = addr; fi->stage2 = true; From 222f45b75970452b864f80cc4c0d3eb8f4862f64 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 27 Jul 2020 16:12:10 +0100 Subject: [PATCH 2511/2595] docs/system/arm/virt: Document 'mte' machine option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 6a0b7505f1fd6769c which added documentation of the virt board crossed in the post with commit 6f4e1405b91da0d0 which added a new 'mte' machine option. Update the docs to include the new option. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson --- docs/system/arm/virt.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 6621ab7205..32dc5eb22e 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -79,6 +79,10 @@ virtualization Set ``on``/``off`` to enable/disable emulating a guest CPU which implements the Arm Virtualization Extensions. The default is ``off``. +mte + Set ``on``/``off`` to enable/disable emulating a guest CPU which implements the + Arm Memory Tagging Extensions. The default is ``off``. + highmem Set ``on``/``off`` to enable/disable placing devices and RAM in physical address space above 32 bits. The default is ``on`` for machine types From 24ac0d309ab379cd0347f198c2db5b2b48b02887 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Jul 2020 16:12:10 +0100 Subject: [PATCH 2512/2595] hw/arm/boot: Fix PAUTH for EL3 direct kernel boot When booting an EL3 cpu with -kernel, we set up EL3 and then drop down to EL2. We need to enable access to v8.3-PAuth keys and instructions at EL3 before doing so. Signed-off-by: Richard Henderson Message-id: 20200724163853.504655-2-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/boot.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index fef4072db1..c44fd3382d 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -736,6 +736,9 @@ static void do_cpu_reset(void *opaque) } else { env->pstate = PSTATE_MODE_EL1h; } + if (cpu_isar_feature(aa64_pauth, cpu)) { + env->cp15.scr_el3 |= SCR_API | SCR_APK; + } /* AArch64 kernels never boot in secure mode */ assert(!info->secure_boot); /* This hook is only supported for AArch32 currently: From 7ad01d78a9f2e80d1be41226d98f34059f7fff90 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Jul 2020 16:12:10 +0100 Subject: [PATCH 2513/2595] hw/arm/boot: Fix MTE for EL3 direct kernel boot When booting an EL3 cpu with -kernel, we set up EL3 and then drop down to EL2. We need to enable access to v8.5-MemTag tag allocation at EL3 before doing so. Reported-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200724163853.504655-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/boot.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index c44fd3382d..3e9816af80 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -739,6 +739,9 @@ static void do_cpu_reset(void *opaque) if (cpu_isar_feature(aa64_pauth, cpu)) { env->cp15.scr_el3 |= SCR_API | SCR_APK; } + if (cpu_isar_feature(aa64_mte, cpu)) { + env->cp15.scr_el3 |= SCR_ATA; + } /* AArch64 kernels never boot in secure mode */ assert(!info->secure_boot); /* This hook is only supported for AArch32 currently: From d4f6dda182e19afa75706936805e18397cb95f07 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Jul 2020 16:12:11 +0100 Subject: [PATCH 2514/2595] target/arm: Improve IMPDEF algorithm for IRG When GCR_EL1.RRND==1, the choosing of the random value is IMPDEF, and the kernel is not expected to have set RGSR_EL1. Force a non-zero value into SEED, so that we do not continually return the same tag. Reported-by: Vincenzo Frascino Signed-off-by: Richard Henderson Message-id: 20200724163853.504655-4-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/mte_helper.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 5ea57d487a..104752041f 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -24,6 +24,8 @@ #include "exec/ram_addr.h" #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" +#include "qapi/error.h" +#include "qemu/guest-random.h" static int choose_nonexcluded_tag(int tag, int offset, uint16_t exclude) @@ -211,16 +213,37 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, uint64_t HELPER(irg)(CPUARMState *env, uint64_t rn, uint64_t rm) { - int rtag; - - /* - * Our IMPDEF choice for GCR_EL1.RRND==1 is to behave as if - * GCR_EL1.RRND==0, always producing deterministic results. - */ uint16_t exclude = extract32(rm | env->cp15.gcr_el1, 0, 16); + int rrnd = extract32(env->cp15.gcr_el1, 16, 1); int start = extract32(env->cp15.rgsr_el1, 0, 4); int seed = extract32(env->cp15.rgsr_el1, 8, 16); - int offset, i; + int offset, i, rtag; + + /* + * Our IMPDEF choice for GCR_EL1.RRND==1 is to continue to use the + * deterministic algorithm. Except that with RRND==1 the kernel is + * not required to have set RGSR_EL1.SEED != 0, which is required for + * the deterministic algorithm to function. So we force a non-zero + * SEED for that case. + */ + if (unlikely(seed == 0) && rrnd) { + do { + Error *err = NULL; + uint16_t two; + + if (qemu_guest_getrandom(&two, sizeof(two), &err) < 0) { + /* + * Failed, for unknown reasons in the crypto subsystem. + * Best we can do is log the reason and use a constant seed. + */ + qemu_log_mask(LOG_UNIMP, "IRG: Crypto failure: %s\n", + error_get_pretty(err)); + error_free(err); + two = 1; + } + seed = two; + } while (seed == 0); + } /* RandomTag */ for (i = offset = 0; i < 4; ++i) { From 0c9753ebda274b0e618d7b4032bb2d83d27483ed Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 27 Jul 2020 17:33:19 +0200 Subject: [PATCH 2515/2595] virtio-pci: fix virtio_pci_queue_enabled() In legacy mode, virtio_pci_queue_enabled() falls back to virtio_queue_enabled() to know if the queue is enabled. But virtio_queue_enabled() calls again virtio_pci_queue_enabled() if k->queue_enabled is set. This ends in a crash after a stack overflow. The problem can be reproduced with "-device virtio-net-pci,disable-legacy=off,disable-modern=true -net tap,vhost=on" And a look to the backtrace is very explicit: ... #4 0x000000010029a438 in virtio_queue_enabled () #5 0x0000000100497a9c in virtio_pci_queue_enabled () ... #130902 0x000000010029a460 in virtio_queue_enabled () #130903 0x0000000100497a9c in virtio_pci_queue_enabled () #130904 0x000000010029a460 in virtio_queue_enabled () #130905 0x0000000100454a20 in vhost_net_start () ... This patch fixes the problem by introducing a new function for the legacy case and calls it from virtio_pci_queue_enabled(). It also calls it from virtio_queue_enabled() to avoid code duplication. Fixes: f19bcdfedd53 ("virtio-pci: implement queue_enabled method") Cc: Jason Wang Cc: Cindy Lu CC: Michael S. Tsirkin Signed-off-by: Laurent Vivier Message-Id: <20200727153319.43716-1-lvivier@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 2 +- hw/virtio/virtio.c | 7 ++++++- include/hw/virtio/virtio.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index ada1101d07..4ad3ad81a2 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1116,7 +1116,7 @@ static bool virtio_pci_queue_enabled(DeviceState *d, int n) return proxy->vqs[vdev->queue_sel].enabled; } - return virtio_queue_enabled(vdev, n); + return virtio_queue_enabled_legacy(vdev, n); } static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy, diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 546a198e79..e983025217 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3309,6 +3309,11 @@ hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n) return vdev->vq[n].vring.desc; } +bool virtio_queue_enabled_legacy(VirtIODevice *vdev, int n) +{ + return virtio_queue_get_desc_addr(vdev, n) != 0; +} + bool virtio_queue_enabled(VirtIODevice *vdev, int n) { BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); @@ -3317,7 +3322,7 @@ bool virtio_queue_enabled(VirtIODevice *vdev, int n) if (k->queue_enabled) { return k->queue_enabled(qbus->parent, n); } - return virtio_queue_get_desc_addr(vdev, n) != 0; + return virtio_queue_enabled_legacy(vdev, n); } hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n) diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 198ffc7626..e424df12cf 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -295,6 +295,7 @@ typedef struct VirtIORNGConf VirtIORNGConf; VIRTIO_F_RING_PACKED, false) hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n); +bool virtio_queue_enabled_legacy(VirtIODevice *vdev, int n); bool virtio_queue_enabled(VirtIODevice *vdev, int n); hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n); hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n); From c9f8066697e0d3e77b97f6df423e9d6540b693be Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Jul 2020 14:23:14 -0700 Subject: [PATCH 2516/2595] linux-user: Ensure mmap_min_addr is non-zero When the chroot does not have /proc mounted, we can read neither /proc/sys/vm/mmap_min_addr nor /proc/sys/maps. The enforcement of mmap_min_addr in the host kernel is done by the security module, and so does not apply to processes owned by root. Which leads pgd_find_hole_fallback to succeed in probing a reservation at address 0. Which confuses pgb_reserved_va to believe that guest_base has not actually been initialized. We don't actually want NULL addresses to become accessible, so make sure that mmap_min_addr is initialized with a non-zero value. Buglink: https://bugs.launchpad.net/qemu/+bug/1888728 Reported-by: John Paul Adrian Glaubitz Signed-off-by: Richard Henderson Tested-by: John Paul Adrian Glaubitz Acked-by: Laurent Vivier Message-Id: <20200724212314.545877-1-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/main.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 3597e99bb1..75c9785157 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -758,14 +758,26 @@ int main(int argc, char **argv, char **envp) if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) { unsigned long tmp; - if (fscanf(fp, "%lu", &tmp) == 1) { + if (fscanf(fp, "%lu", &tmp) == 1 && tmp != 0) { mmap_min_addr = tmp; - qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n", mmap_min_addr); + qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n", + mmap_min_addr); } fclose(fp); } } + /* + * We prefer to not make NULL pointers accessible to QEMU. + * If we're in a chroot with no /proc, fall back to 1 page. + */ + if (mmap_min_addr == 0) { + mmap_min_addr = qemu_host_page_size; + qemu_log_mask(CPU_LOG_PAGE, + "host mmap_min_addr=0x%lx (fallback)\n", + mmap_min_addr); + } + /* * Prepare copy of argv vector for target. */ From 4d213001b356c4a24c05afbc72f4860088900627 Mon Sep 17 00:00:00 2001 From: Filip Bozuta Date: Fri, 24 Jul 2020 20:16:51 +0200 Subject: [PATCH 2517/2595] linux-user: Fix syscall rt_sigtimedwait() implementation Implementation of 'rt_sigtimedwait()' in 'syscall.c' uses the function 'target_to_host_timespec()' to transfer the value of 'struct timespec' from target to host. However, the implementation doesn't check whether this conversion succeeds and thus can cause an unaproppriate error instead of the 'EFAULT (Bad address)' which is supposed to be set if the conversion from target to host fails. This was confirmed with the LTP test for rt_sigtimedwait: "/testcases/kernel/syscalls/rt_sigtimedwait/rt_sigtimedwait01.c" which causes an unapropriate error in test case "test_bad_adress3" which is run with a bad adress for the 'struct timespec' argument: FAIL: test_bad_address3 (349): Unexpected failure: EAGAIN/EWOULDBLOCK (11) The test fails with an unexptected errno 'EAGAIN/EWOULDBLOCK' instead of the expected EFAULT. After the changes from this patch, the test case is executed successfully along with the other LTP test cases for 'rt_sigtimedwait()': PASS: test_bad_address3 (349): Test passed Signed-off-by: Filip Bozuta Reviewed-by: Laurent Vivier Message-Id: <20200724181651.167819-1-Filip.Bozuta@syrmia.com> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f5c4f6b95d..c1ebf7b8f3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8868,7 +8868,9 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); if (arg3) { puts = &uts; - target_to_host_timespec(puts, arg3); + if (target_to_host_timespec(puts, arg3)) { + return -TARGET_EFAULT; + } } else { puts = NULL; } From 0f6bb1958f3aae0171996941df7fb7ea7536bb12 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Thu, 23 Jul 2020 12:27:13 +0200 Subject: [PATCH 2518/2595] linux-user: Use getcwd syscall directly The glibc getcwd function returns different errors than the getcwd syscall, which triggers an assertion failure in the glibc getcwd function when running under the emulation. When the syscall returns ENAMETOOLONG, the glibc wrapper uses a fallback implementation that potentially handles an unlimited path length, and returns with ERANGE if the provided buffer is too small. The qemu emulation cannot distinguish the two cases, and thus always returns ERANGE. This is unexpected by the glibc wrapper. Signed-off-by: Andreas Schwab Reviewed-by: Laurent Vivier Message-Id: [lv: updated description] Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c1ebf7b8f3..945fc25279 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -388,14 +388,7 @@ static bitmask_transtbl fcntl_flags_tbl[] = { { 0, 0, 0, 0 } }; -static int sys_getcwd1(char *buf, size_t size) -{ - if (getcwd(buf, size) == NULL) { - /* getcwd() sets errno */ - return (-1); - } - return strlen(buf)+1; -} +_syscall2(int, sys_getcwd1, char *, buf, size_t, size) #ifdef TARGET_NR_utimensat #if defined(__NR_utimensat) From 8098969cf2f0acb794b69bd63ee90c9173b6122c Mon Sep 17 00:00:00 2001 From: Andrey Shinkevich Date: Fri, 17 Jul 2020 11:14:49 +0300 Subject: [PATCH 2519/2595] qcow2: Fix capitalization of header extension constant. Make the capitalization of the hexadecimal numbers consistent for the QCOW2 header extension constants in docs/interop/qcow2.txt. Suggested-by: Eric Blake Signed-off-by: Andrey Shinkevich Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <1594973699-781898-2-git-send-email-andrey.shinkevich@virtuozzo.com> Reviewed-by: Eric Blake Signed-off-by: Eric Blake --- block/qcow2.c | 2 +- docs/interop/qcow2.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index fadf3422f8..6ad6bdc166 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -66,7 +66,7 @@ typedef struct { } QEMU_PACKED QCowExtension; #define QCOW2_EXT_MAGIC_END 0 -#define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA +#define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xe2792aca #define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857 #define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 #define QCOW2_EXT_MAGIC_BITMAPS 0x23852875 diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index cb723463f2..f072e27900 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -231,7 +231,7 @@ be stored. Each extension has a structure like the following: Byte 0 - 3: Header extension type: 0x00000000 - End of the header extension area - 0xE2792ACA - Backing file format name string + 0xe2792aca - Backing file format name string 0x6803f857 - Feature name table 0x23852875 - Bitmaps extension 0x0537be77 - Full disk encryption header pointer From 8243219fa565d7285b520cba0f1579744ae0b3e9 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:16 +0300 Subject: [PATCH 2520/2595] qemu-iotests/199: fix style Mostly, satisfy pep8 complaints. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Tested-by: Eric Blake Message-Id: <20200727194236.19551-2-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/199 | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199 index 40774eed74..de9ba8d94c 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/199 @@ -28,8 +28,8 @@ disk_b = os.path.join(iotests.test_dir, 'disk_b') size = '256G' fifo = os.path.join(iotests.test_dir, 'mig_fifo') -class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): +class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): def tearDown(self): self.vm_a.shutdown() self.vm_b.shutdown() @@ -54,7 +54,7 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): result = self.vm_a.qmp('block-dirty-bitmap-add', node='drive0', name='bitmap', granularity=granularity) - self.assert_qmp(result, 'return', {}); + self.assert_qmp(result, 'return', {}) s = 0 while s < write_size: @@ -71,7 +71,7 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): result = self.vm_a.qmp('block-dirty-bitmap-clear', node='drive0', name='bitmap') - self.assert_qmp(result, 'return', {}); + self.assert_qmp(result, 'return', {}) s = 0 while s < write_size: self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) @@ -104,15 +104,16 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): self.vm_b.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) s += 0x10000 - result = self.vm_b.qmp('query-block'); + result = self.vm_b.qmp('query-block') while len(result['return'][0]['dirty-bitmaps']) > 1: time.sleep(2) - result = self.vm_b.qmp('query-block'); + result = self.vm_b.qmp('query-block') result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256', node='drive0', name='bitmap') - self.assert_qmp(result, 'return/sha256', sha256); + self.assert_qmp(result, 'return/sha256', sha256) + if __name__ == '__main__': iotests.main(supported_fmts=['qcow2'], supported_cache_modes=['none'], From f3f483ac6310f26bd17ce5518cba14730a4d0546 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:17 +0300 Subject: [PATCH 2521/2595] qemu-iotests/199: drop extra constraints We don't need any specific format constraints here. Still keep qcow2 for two reasons: 1. No extra calls of format-unrelated test 2. Add some check around persistent bitmap in future (require qcow2) Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Tested-by: Eric Blake Message-Id: <20200727194236.19551-3-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/199 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199 index de9ba8d94c..dda918450a 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/199 @@ -116,5 +116,4 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): if __name__ == '__main__': - iotests.main(supported_fmts=['qcow2'], supported_cache_modes=['none'], - supported_protocols=['file']) + iotests.main(supported_fmts=['qcow2']) From 09feea6cf528b3158640d6530174cf21cb579bc0 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:18 +0300 Subject: [PATCH 2522/2595] qemu-iotests/199: better catch postcopy time The test aims to test _postcopy_ migration, and wants to do some write operations during postcopy time. Test considers migrate status=complete event on source as start of postcopy. This is completely wrong, completion is completion of the whole migration process. Let's instead consider destination start as start of postcopy, and use RESUME event for it. Next, as migration finish, let's use migration status=complete event on target, as such method is closer to what libvirt or another user will do, than tracking number of dirty-bitmaps. Finally, add a possibility to dump events for debug. And if set debug to True, we see, that actual postcopy period is very small relatively to the whole test duration time (~0.2 seconds to >40 seconds for me). This means, that test is very inefficient in what it supposed to do. Let's improve it in following commits. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Tested-by: Eric Blake Message-Id: <20200727194236.19551-4-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/199 | 74 +++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199 index dda918450a..dd6044768c 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/199 @@ -20,17 +20,43 @@ import os import iotests -import time from iotests import qemu_img +debug = False + disk_a = os.path.join(iotests.test_dir, 'disk_a') disk_b = os.path.join(iotests.test_dir, 'disk_b') size = '256G' fifo = os.path.join(iotests.test_dir, 'mig_fifo') +def event_seconds(event): + return event['timestamp']['seconds'] + \ + event['timestamp']['microseconds'] / 1000000.0 + + +def event_dist(e1, e2): + return event_seconds(e2) - event_seconds(e1) + + class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): def tearDown(self): + if debug: + self.vm_a_events += self.vm_a.get_qmp_events() + self.vm_b_events += self.vm_b.get_qmp_events() + for e in self.vm_a_events: + e['vm'] = 'SRC' + for e in self.vm_b_events: + e['vm'] = 'DST' + events = (self.vm_a_events + self.vm_b_events) + events = [(e['timestamp']['seconds'], + e['timestamp']['microseconds'], + e['vm'], + e['event'], + e.get('data', '')) for e in events] + for e in sorted(events): + print('{}.{:06} {} {} {}'.format(*e)) + self.vm_a.shutdown() self.vm_b.shutdown() os.remove(disk_a) @@ -47,6 +73,10 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): self.vm_a.launch() self.vm_b.launch() + # collect received events for debug + self.vm_a_events = [] + self.vm_b_events = [] + def test_postcopy(self): write_size = 0x40000000 granularity = 512 @@ -77,15 +107,13 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) s += 0x10000 - bitmaps_cap = {'capability': 'dirty-bitmaps', 'state': True} - events_cap = {'capability': 'events', 'state': True} + caps = [{'capability': 'dirty-bitmaps', 'state': True}, + {'capability': 'events', 'state': True}] - result = self.vm_a.qmp('migrate-set-capabilities', - capabilities=[bitmaps_cap, events_cap]) + result = self.vm_a.qmp('migrate-set-capabilities', capabilities=caps) self.assert_qmp(result, 'return', {}) - result = self.vm_b.qmp('migrate-set-capabilities', - capabilities=[bitmaps_cap]) + result = self.vm_b.qmp('migrate-set-capabilities', capabilities=caps) self.assert_qmp(result, 'return', {}) result = self.vm_a.qmp('migrate', uri='exec:cat>' + fifo) @@ -94,24 +122,38 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): result = self.vm_a.qmp('migrate-start-postcopy') self.assert_qmp(result, 'return', {}) - while True: - event = self.vm_a.event_wait('MIGRATION') - if event['data']['status'] == 'completed': - break + event_resume = self.vm_b.event_wait('RESUME') + self.vm_b_events.append(event_resume) s = 0x8000 while s < write_size: self.vm_b.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) s += 0x10000 - result = self.vm_b.qmp('query-block') - while len(result['return'][0]['dirty-bitmaps']) > 1: - time.sleep(2) - result = self.vm_b.qmp('query-block') + match = {'data': {'status': 'completed'}} + event_complete = self.vm_b.event_wait('MIGRATION', match=match) + self.vm_b_events.append(event_complete) + # take queued event, should already been happened + event_stop = self.vm_a.event_wait('STOP') + self.vm_a_events.append(event_stop) + + downtime = event_dist(event_stop, event_resume) + postcopy_time = event_dist(event_resume, event_complete) + + # TODO: assert downtime * 10 < postcopy_time + if debug: + print('downtime:', downtime) + print('postcopy_time:', postcopy_time) + + # Assert that bitmap migration is finished (check that successor bitmap + # is removed) + result = self.vm_b.qmp('query-block') + assert len(result['return'][0]['dirty-bitmaps']) == 1 + + # Check content of migrated (and updated by new writes) bitmap result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256', node='drive0', name='bitmap') - self.assert_qmp(result, 'return/sha256', sha256) From edb90bbdf33f6e96788b454fae9abfed18274692 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:19 +0300 Subject: [PATCH 2523/2595] qemu-iotests/199: improve performance: set bitmap by discard Discard dirties dirty-bitmap as well as write, but works faster. Let's use it instead. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Tested-by: Eric Blake Message-Id: <20200727194236.19551-5-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/199 | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199 index dd6044768c..190e820b84 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/199 @@ -67,8 +67,10 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): os.mkfifo(fifo) qemu_img('create', '-f', iotests.imgfmt, disk_a, size) qemu_img('create', '-f', iotests.imgfmt, disk_b, size) - self.vm_a = iotests.VM(path_suffix='a').add_drive(disk_a) - self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b) + self.vm_a = iotests.VM(path_suffix='a').add_drive(disk_a, + 'discard=unmap') + self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b, + 'discard=unmap') self.vm_b.add_incoming("exec: cat '" + fifo + "'") self.vm_a.launch() self.vm_b.launch() @@ -78,7 +80,7 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): self.vm_b_events = [] def test_postcopy(self): - write_size = 0x40000000 + discard_size = 0x40000000 granularity = 512 chunk = 4096 @@ -86,25 +88,32 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): name='bitmap', granularity=granularity) self.assert_qmp(result, 'return', {}) + result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', + node='drive0', name='bitmap') + empty_sha256 = result['return']['sha256'] + s = 0 - while s < write_size: - self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) + while s < discard_size: + self.vm_a.hmp_qemu_io('drive0', 'discard %d %d' % (s, chunk)) s += 0x10000 s = 0x8000 - while s < write_size: - self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) + while s < discard_size: + self.vm_a.hmp_qemu_io('drive0', 'discard %d %d' % (s, chunk)) s += 0x10000 result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', node='drive0', name='bitmap') sha256 = result['return']['sha256'] + # Check, that updating the bitmap by discards works + assert sha256 != empty_sha256 + result = self.vm_a.qmp('block-dirty-bitmap-clear', node='drive0', name='bitmap') self.assert_qmp(result, 'return', {}) s = 0 - while s < write_size: - self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) + while s < discard_size: + self.vm_a.hmp_qemu_io('drive0', 'discard %d %d' % (s, chunk)) s += 0x10000 caps = [{'capability': 'dirty-bitmaps', 'state': True}, @@ -126,8 +135,8 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): self.vm_b_events.append(event_resume) s = 0x8000 - while s < write_size: - self.vm_b.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk)) + while s < discard_size: + self.vm_b.hmp_qemu_io('drive0', 'discard %d %d' % (s, chunk)) s += 0x10000 match = {'data': {'status': 'completed'}} From 31e382791352ed1f6fa2894f84286d0d4ee28e4f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:20 +0300 Subject: [PATCH 2524/2595] qemu-iotests/199: change discard patterns iotest 199 works too long because of many discard operations. At the same time, postcopy period is very short, in spite of all these efforts. So, let's use less discards (and with more interesting patterns) to reduce test timing. In the next commit we'll increase postcopy period. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Tested-by: Eric Blake Message-Id: <20200727194236.19551-6-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/199 | 44 +++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199 index 190e820b84..da4dae01fb 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/199 @@ -30,6 +30,28 @@ size = '256G' fifo = os.path.join(iotests.test_dir, 'mig_fifo') +GiB = 1024 * 1024 * 1024 + +discards1 = ( + (0, GiB), + (2 * GiB + 512 * 5, 512), + (3 * GiB + 512 * 5, 512), + (100 * GiB, GiB) +) + +discards2 = ( + (3 * GiB + 512 * 8, 512), + (4 * GiB + 512 * 8, 512), + (50 * GiB, GiB), + (100 * GiB + GiB // 2, GiB) +) + + +def apply_discards(vm, discards): + for d in discards: + vm.hmp_qemu_io('drive0', 'discard {} {}'.format(*d)) + + def event_seconds(event): return event['timestamp']['seconds'] + \ event['timestamp']['microseconds'] / 1000000.0 @@ -80,9 +102,7 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): self.vm_b_events = [] def test_postcopy(self): - discard_size = 0x40000000 granularity = 512 - chunk = 4096 result = self.vm_a.qmp('block-dirty-bitmap-add', node='drive0', name='bitmap', granularity=granularity) @@ -92,14 +112,7 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): node='drive0', name='bitmap') empty_sha256 = result['return']['sha256'] - s = 0 - while s < discard_size: - self.vm_a.hmp_qemu_io('drive0', 'discard %d %d' % (s, chunk)) - s += 0x10000 - s = 0x8000 - while s < discard_size: - self.vm_a.hmp_qemu_io('drive0', 'discard %d %d' % (s, chunk)) - s += 0x10000 + apply_discards(self.vm_a, discards1 + discards2) result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', node='drive0', name='bitmap') @@ -111,10 +124,8 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): result = self.vm_a.qmp('block-dirty-bitmap-clear', node='drive0', name='bitmap') self.assert_qmp(result, 'return', {}) - s = 0 - while s < discard_size: - self.vm_a.hmp_qemu_io('drive0', 'discard %d %d' % (s, chunk)) - s += 0x10000 + + apply_discards(self.vm_a, discards1) caps = [{'capability': 'dirty-bitmaps', 'state': True}, {'capability': 'events', 'state': True}] @@ -134,10 +145,7 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): event_resume = self.vm_b.event_wait('RESUME') self.vm_b_events.append(event_resume) - s = 0x8000 - while s < discard_size: - self.vm_b.hmp_qemu_io('drive0', 'discard %d %d' % (s, chunk)) - s += 0x10000 + apply_discards(self.vm_b, discards2) match = {'data': {'status': 'completed'}} event_complete = self.vm_b.event_wait('MIGRATION', match=match) From e80a4150a54d69a56e31de2c96e7655109e4c60a Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:21 +0300 Subject: [PATCH 2525/2595] qemu-iotests/199: increase postcopy period The test wants to force a bitmap postcopy. Still, the resulting postcopy period is very small. Let's increase it by adding more bitmaps to migrate. Also, test disabled bitmaps migration. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Tested-by: Eric Blake Message-Id: <20200727194236.19551-7-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/199 | 56 ++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199 index da4dae01fb..d8532e49da 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/199 @@ -103,29 +103,45 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): def test_postcopy(self): granularity = 512 + nb_bitmaps = 15 - result = self.vm_a.qmp('block-dirty-bitmap-add', node='drive0', - name='bitmap', granularity=granularity) - self.assert_qmp(result, 'return', {}) + for i in range(nb_bitmaps): + result = self.vm_a.qmp('block-dirty-bitmap-add', node='drive0', + name='bitmap{}'.format(i), + granularity=granularity) + self.assert_qmp(result, 'return', {}) result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', - node='drive0', name='bitmap') + node='drive0', name='bitmap0') empty_sha256 = result['return']['sha256'] - apply_discards(self.vm_a, discards1 + discards2) + apply_discards(self.vm_a, discards1) result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', - node='drive0', name='bitmap') - sha256 = result['return']['sha256'] + node='drive0', name='bitmap0') + discards1_sha256 = result['return']['sha256'] # Check, that updating the bitmap by discards works - assert sha256 != empty_sha256 + assert discards1_sha256 != empty_sha256 - result = self.vm_a.qmp('block-dirty-bitmap-clear', node='drive0', - name='bitmap') - self.assert_qmp(result, 'return', {}) + # We want to calculate resulting sha256. Do it in bitmap0, so, disable + # other bitmaps + for i in range(1, nb_bitmaps): + result = self.vm_a.qmp('block-dirty-bitmap-disable', node='drive0', + name='bitmap{}'.format(i)) + self.assert_qmp(result, 'return', {}) - apply_discards(self.vm_a, discards1) + apply_discards(self.vm_a, discards2) + + result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', + node='drive0', name='bitmap0') + all_discards_sha256 = result['return']['sha256'] + + # Now, enable some bitmaps, to be updated during migration + for i in range(2, nb_bitmaps, 2): + result = self.vm_a.qmp('block-dirty-bitmap-enable', node='drive0', + name='bitmap{}'.format(i)) + self.assert_qmp(result, 'return', {}) caps = [{'capability': 'dirty-bitmaps', 'state': True}, {'capability': 'events', 'state': True}] @@ -145,6 +161,7 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): event_resume = self.vm_b.event_wait('RESUME') self.vm_b_events.append(event_resume) + # enabled bitmaps should be updated apply_discards(self.vm_b, discards2) match = {'data': {'status': 'completed'}} @@ -158,7 +175,7 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): downtime = event_dist(event_stop, event_resume) postcopy_time = event_dist(event_resume, event_complete) - # TODO: assert downtime * 10 < postcopy_time + assert downtime * 10 < postcopy_time if debug: print('downtime:', downtime) print('postcopy_time:', postcopy_time) @@ -166,12 +183,15 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): # Assert that bitmap migration is finished (check that successor bitmap # is removed) result = self.vm_b.qmp('query-block') - assert len(result['return'][0]['dirty-bitmaps']) == 1 + assert len(result['return'][0]['dirty-bitmaps']) == nb_bitmaps - # Check content of migrated (and updated by new writes) bitmap - result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256', - node='drive0', name='bitmap') - self.assert_qmp(result, 'return/sha256', sha256) + # Check content of migrated bitmaps. Still, don't waste time checking + # every bitmap + for i in range(0, nb_bitmaps, 5): + result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256', + node='drive0', name='bitmap{}'.format(i)) + sha256 = discards1_sha256 if i % 2 else all_discards_sha256 + self.assert_qmp(result, 'return/sha256', sha256) if __name__ == '__main__': From e6ce5e92248be5547daaee3eb6cd226e9820cf7b Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:22 +0300 Subject: [PATCH 2526/2595] migration/block-dirty-bitmap: fix dirty_bitmap_mig_before_vm_start Using the _locked version of bdrv_enable_dirty_bitmap to bypass locking is wrong as we do not already own the mutex. Moreover, the adjacent call to bdrv_dirty_bitmap_enable_successor grabs the mutex. Fixes: 58f72b965e9e1q Cc: qemu-stable@nongnu.org # v3.0 Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Reviewed-by: Eric Blake Message-Id: <20200727194236.19551-8-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index b0dbf9eeed..0739f1259e 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -566,7 +566,7 @@ void dirty_bitmap_mig_before_vm_start(void) DirtyBitmapLoadBitmapState *b = item->data; if (b->migrated) { - bdrv_enable_dirty_bitmap_locked(b->bitmap); + bdrv_enable_dirty_bitmap(b->bitmap); } else { bdrv_dirty_bitmap_enable_successor(b->bitmap); } From fbbc6b14705ea8c2f6326d4fab455d6432d83d08 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:23 +0300 Subject: [PATCH 2527/2595] migration/block-dirty-bitmap: rename state structure types Rename types to be symmetrical for load/save part and shorter. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Reviewed-by: Eric Blake Message-Id: <20200727194236.19551-9-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 70 ++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 0739f1259e..1d57bff4f6 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -100,23 +100,25 @@ /* 0x04 was "AUTOLOAD" flags on elder versions, no it is ignored */ #define DIRTY_BITMAP_MIG_START_FLAG_RESERVED_MASK 0xf8 -typedef struct DirtyBitmapMigBitmapState { +/* State of one bitmap during save process */ +typedef struct SaveBitmapState { /* Written during setup phase. */ BlockDriverState *bs; const char *node_name; BdrvDirtyBitmap *bitmap; uint64_t total_sectors; uint64_t sectors_per_chunk; - QSIMPLEQ_ENTRY(DirtyBitmapMigBitmapState) entry; + QSIMPLEQ_ENTRY(SaveBitmapState) entry; uint8_t flags; /* For bulk phase. */ bool bulk_completed; uint64_t cur_sector; -} DirtyBitmapMigBitmapState; +} SaveBitmapState; -typedef struct DirtyBitmapMigState { - QSIMPLEQ_HEAD(, DirtyBitmapMigBitmapState) dbms_list; +/* State of the dirty bitmap migration (DBM) during save process */ +typedef struct DBMSaveState { + QSIMPLEQ_HEAD(, SaveBitmapState) dbms_list; bool bulk_completed; bool no_bitmaps; @@ -124,23 +126,25 @@ typedef struct DirtyBitmapMigState { /* for send_bitmap_bits() */ BlockDriverState *prev_bs; BdrvDirtyBitmap *prev_bitmap; -} DirtyBitmapMigState; +} DBMSaveState; -typedef struct DirtyBitmapLoadState { +/* State of the dirty bitmap migration (DBM) during load process */ +typedef struct DBMLoadState { uint32_t flags; char node_name[256]; char bitmap_name[256]; BlockDriverState *bs; BdrvDirtyBitmap *bitmap; -} DirtyBitmapLoadState; +} DBMLoadState; -static DirtyBitmapMigState dirty_bitmap_mig_state; +static DBMSaveState dirty_bitmap_mig_state; -typedef struct DirtyBitmapLoadBitmapState { +/* State of one bitmap during load process */ +typedef struct LoadBitmapState { BlockDriverState *bs; BdrvDirtyBitmap *bitmap; bool migrated; -} DirtyBitmapLoadBitmapState; +} LoadBitmapState; static GSList *enabled_bitmaps; QemuMutex finish_lock; @@ -170,7 +174,7 @@ static void qemu_put_bitmap_flags(QEMUFile *f, uint32_t flags) qemu_put_byte(f, flags); } -static void send_bitmap_header(QEMUFile *f, DirtyBitmapMigBitmapState *dbms, +static void send_bitmap_header(QEMUFile *f, SaveBitmapState *dbms, uint32_t additional_flags) { BlockDriverState *bs = dbms->bs; @@ -199,19 +203,19 @@ static void send_bitmap_header(QEMUFile *f, DirtyBitmapMigBitmapState *dbms, } } -static void send_bitmap_start(QEMUFile *f, DirtyBitmapMigBitmapState *dbms) +static void send_bitmap_start(QEMUFile *f, SaveBitmapState *dbms) { send_bitmap_header(f, dbms, DIRTY_BITMAP_MIG_FLAG_START); qemu_put_be32(f, bdrv_dirty_bitmap_granularity(dbms->bitmap)); qemu_put_byte(f, dbms->flags); } -static void send_bitmap_complete(QEMUFile *f, DirtyBitmapMigBitmapState *dbms) +static void send_bitmap_complete(QEMUFile *f, SaveBitmapState *dbms) { send_bitmap_header(f, dbms, DIRTY_BITMAP_MIG_FLAG_COMPLETE); } -static void send_bitmap_bits(QEMUFile *f, DirtyBitmapMigBitmapState *dbms, +static void send_bitmap_bits(QEMUFile *f, SaveBitmapState *dbms, uint64_t start_sector, uint32_t nr_sectors) { /* align for buffer_is_zero() */ @@ -257,7 +261,7 @@ static void send_bitmap_bits(QEMUFile *f, DirtyBitmapMigBitmapState *dbms, /* Called with iothread lock taken. */ static void dirty_bitmap_mig_cleanup(void) { - DirtyBitmapMigBitmapState *dbms; + SaveBitmapState *dbms; while ((dbms = QSIMPLEQ_FIRST(&dirty_bitmap_mig_state.dbms_list)) != NULL) { QSIMPLEQ_REMOVE_HEAD(&dirty_bitmap_mig_state.dbms_list, entry); @@ -271,7 +275,7 @@ static void dirty_bitmap_mig_cleanup(void) static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name) { BdrvDirtyBitmap *bitmap; - DirtyBitmapMigBitmapState *dbms; + SaveBitmapState *dbms; Error *local_err = NULL; FOR_EACH_DIRTY_BITMAP(bs, bitmap) { @@ -309,7 +313,7 @@ static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name) bdrv_ref(bs); bdrv_dirty_bitmap_set_busy(bitmap, true); - dbms = g_new0(DirtyBitmapMigBitmapState, 1); + dbms = g_new0(SaveBitmapState, 1); dbms->bs = bs; dbms->node_name = bs_name; dbms->bitmap = bitmap; @@ -334,7 +338,7 @@ static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name) static int init_dirty_bitmap_migration(void) { BlockDriverState *bs; - DirtyBitmapMigBitmapState *dbms; + SaveBitmapState *dbms; GHashTable *handled_by_blk = g_hash_table_new(NULL, NULL); BlockBackend *blk; @@ -408,7 +412,7 @@ fail: } /* Called with no lock taken. */ -static void bulk_phase_send_chunk(QEMUFile *f, DirtyBitmapMigBitmapState *dbms) +static void bulk_phase_send_chunk(QEMUFile *f, SaveBitmapState *dbms) { uint32_t nr_sectors = MIN(dbms->total_sectors - dbms->cur_sector, dbms->sectors_per_chunk); @@ -424,7 +428,7 @@ static void bulk_phase_send_chunk(QEMUFile *f, DirtyBitmapMigBitmapState *dbms) /* Called with no lock taken. */ static void bulk_phase(QEMUFile *f, bool limit) { - DirtyBitmapMigBitmapState *dbms; + SaveBitmapState *dbms; QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) { while (!dbms->bulk_completed) { @@ -461,7 +465,7 @@ static int dirty_bitmap_save_iterate(QEMUFile *f, void *opaque) static int dirty_bitmap_save_complete(QEMUFile *f, void *opaque) { - DirtyBitmapMigBitmapState *dbms; + SaveBitmapState *dbms; trace_dirty_bitmap_save_complete_enter(); if (!dirty_bitmap_mig_state.bulk_completed) { @@ -486,7 +490,7 @@ static void dirty_bitmap_save_pending(QEMUFile *f, void *opaque, uint64_t *res_compatible, uint64_t *res_postcopy_only) { - DirtyBitmapMigBitmapState *dbms; + SaveBitmapState *dbms; uint64_t pending = 0; qemu_mutex_lock_iothread(); @@ -507,7 +511,7 @@ static void dirty_bitmap_save_pending(QEMUFile *f, void *opaque, } /* First occurrence of this bitmap. It should be created if doesn't exist */ -static int dirty_bitmap_load_start(QEMUFile *f, DirtyBitmapLoadState *s) +static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s) { Error *local_err = NULL; uint32_t granularity = qemu_get_be32(f); @@ -538,7 +542,7 @@ static int dirty_bitmap_load_start(QEMUFile *f, DirtyBitmapLoadState *s) bdrv_disable_dirty_bitmap(s->bitmap); if (flags & DIRTY_BITMAP_MIG_START_FLAG_ENABLED) { - DirtyBitmapLoadBitmapState *b; + LoadBitmapState *b; bdrv_dirty_bitmap_create_successor(s->bitmap, &local_err); if (local_err) { @@ -546,7 +550,7 @@ static int dirty_bitmap_load_start(QEMUFile *f, DirtyBitmapLoadState *s) return -EINVAL; } - b = g_new(DirtyBitmapLoadBitmapState, 1); + b = g_new(LoadBitmapState, 1); b->bs = s->bs; b->bitmap = s->bitmap; b->migrated = false; @@ -563,7 +567,7 @@ void dirty_bitmap_mig_before_vm_start(void) qemu_mutex_lock(&finish_lock); for (item = enabled_bitmaps; item; item = g_slist_next(item)) { - DirtyBitmapLoadBitmapState *b = item->data; + LoadBitmapState *b = item->data; if (b->migrated) { bdrv_enable_dirty_bitmap(b->bitmap); @@ -580,7 +584,7 @@ void dirty_bitmap_mig_before_vm_start(void) qemu_mutex_unlock(&finish_lock); } -static void dirty_bitmap_load_complete(QEMUFile *f, DirtyBitmapLoadState *s) +static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) { GSList *item; trace_dirty_bitmap_load_complete(); @@ -589,7 +593,7 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DirtyBitmapLoadState *s) qemu_mutex_lock(&finish_lock); for (item = enabled_bitmaps; item; item = g_slist_next(item)) { - DirtyBitmapLoadBitmapState *b = item->data; + LoadBitmapState *b = item->data; if (b->bitmap == s->bitmap) { b->migrated = true; @@ -621,7 +625,7 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DirtyBitmapLoadState *s) qemu_mutex_unlock(&finish_lock); } -static int dirty_bitmap_load_bits(QEMUFile *f, DirtyBitmapLoadState *s) +static int dirty_bitmap_load_bits(QEMUFile *f, DBMLoadState *s) { uint64_t first_byte = qemu_get_be64(f) << BDRV_SECTOR_BITS; uint64_t nr_bytes = (uint64_t)qemu_get_be32(f) << BDRV_SECTOR_BITS; @@ -666,7 +670,7 @@ static int dirty_bitmap_load_bits(QEMUFile *f, DirtyBitmapLoadState *s) return 0; } -static int dirty_bitmap_load_header(QEMUFile *f, DirtyBitmapLoadState *s) +static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s) { Error *local_err = NULL; bool nothing; @@ -715,7 +719,7 @@ static int dirty_bitmap_load_header(QEMUFile *f, DirtyBitmapLoadState *s) static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) { - static DirtyBitmapLoadState s; + static DBMLoadState s; int ret = 0; trace_dirty_bitmap_load_enter(); @@ -753,7 +757,7 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque) { - DirtyBitmapMigBitmapState *dbms = NULL; + SaveBitmapState *dbms = NULL; if (init_dirty_bitmap_migration() < 0) { return -1; } From b25d364102686f9fb3854f44c75625bd79f5aee2 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:24 +0300 Subject: [PATCH 2528/2595] migration/block-dirty-bitmap: rename dirty_bitmap_mig_cleanup Rename dirty_bitmap_mig_cleanup to dirty_bitmap_do_save_cleanup, to stress that it is on save part. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Reviewed-by: Eric Blake Message-Id: <20200727194236.19551-10-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 1d57bff4f6..01a536d7d3 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -259,7 +259,7 @@ static void send_bitmap_bits(QEMUFile *f, SaveBitmapState *dbms, } /* Called with iothread lock taken. */ -static void dirty_bitmap_mig_cleanup(void) +static void dirty_bitmap_do_save_cleanup(void) { SaveBitmapState *dbms; @@ -406,7 +406,7 @@ static int init_dirty_bitmap_migration(void) fail: g_hash_table_destroy(handled_by_blk); - dirty_bitmap_mig_cleanup(); + dirty_bitmap_do_save_cleanup(); return -1; } @@ -445,7 +445,7 @@ static void bulk_phase(QEMUFile *f, bool limit) /* for SaveVMHandlers */ static void dirty_bitmap_save_cleanup(void *opaque) { - dirty_bitmap_mig_cleanup(); + dirty_bitmap_do_save_cleanup(); } static int dirty_bitmap_save_iterate(QEMUFile *f, void *opaque) @@ -480,7 +480,7 @@ static int dirty_bitmap_save_complete(QEMUFile *f, void *opaque) trace_dirty_bitmap_save_complete_finish(); - dirty_bitmap_mig_cleanup(); + dirty_bitmap_do_save_cleanup(); return 0; } From d0cccbd1183eccc731deafa1b4c5a2c9dcedca08 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:25 +0300 Subject: [PATCH 2529/2595] migration/block-dirty-bitmap: move mutex init to dirty_bitmap_mig_init No reasons to keep two public init functions. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Reviewed-by: Dr. David Alan Gilbert Message-Id: <20200727194236.19551-11-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 6 +----- migration/migration.c | 2 -- migration/migration.h | 1 - 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 01a536d7d3..4b67e4f4fb 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -148,11 +148,6 @@ typedef struct LoadBitmapState { static GSList *enabled_bitmaps; QemuMutex finish_lock; -void init_dirty_bitmap_incoming_migration(void) -{ - qemu_mutex_init(&finish_lock); -} - static uint32_t qemu_get_bitmap_flags(QEMUFile *f) { uint8_t flags = qemu_get_byte(f); @@ -801,6 +796,7 @@ static SaveVMHandlers savevm_dirty_bitmap_handlers = { void dirty_bitmap_mig_init(void) { QSIMPLEQ_INIT(&dirty_bitmap_mig_state.dbms_list); + qemu_mutex_init(&finish_lock); register_savevm_live("dirty-bitmap", 0, 1, &savevm_dirty_bitmap_handlers, diff --git a/migration/migration.c b/migration/migration.c index 2ed9923227..1c61428988 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -165,8 +165,6 @@ void migration_object_init(void) qemu_sem_init(¤t_incoming->postcopy_pause_sem_dst, 0); qemu_sem_init(¤t_incoming->postcopy_pause_sem_fault, 0); - init_dirty_bitmap_incoming_migration(); - if (!migration_object_check(current_migration, &err)) { error_report_err(err); exit(1); diff --git a/migration/migration.h b/migration/migration.h index f617960522..ab20c756f5 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -335,7 +335,6 @@ void migrate_send_rp_recv_bitmap(MigrationIncomingState *mis, void migrate_send_rp_resume_ack(MigrationIncomingState *mis, uint32_t value); void dirty_bitmap_mig_before_vm_start(void); -void init_dirty_bitmap_incoming_migration(void); void migrate_add_address(SocketAddress *address); int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque); From 3b52726ec0e2f5c5732fe5f9d76af700463b73d3 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:26 +0300 Subject: [PATCH 2530/2595] migration/block-dirty-bitmap: refactor state global variables Move all state variables into one global struct. Reduce global variable usage, utilizing opaque pointer where possible. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200727194236.19551-12-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 179 ++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 80 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 4b67e4f4fb..9b39e7aa2b 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -128,6 +128,12 @@ typedef struct DBMSaveState { BdrvDirtyBitmap *prev_bitmap; } DBMSaveState; +typedef struct LoadBitmapState { + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; + bool migrated; +} LoadBitmapState; + /* State of the dirty bitmap migration (DBM) during load process */ typedef struct DBMLoadState { uint32_t flags; @@ -135,18 +141,17 @@ typedef struct DBMLoadState { char bitmap_name[256]; BlockDriverState *bs; BdrvDirtyBitmap *bitmap; + + GSList *enabled_bitmaps; + QemuMutex finish_lock; } DBMLoadState; -static DBMSaveState dirty_bitmap_mig_state; +typedef struct DBMState { + DBMSaveState save; + DBMLoadState load; +} DBMState; -/* State of one bitmap during load process */ -typedef struct LoadBitmapState { - BlockDriverState *bs; - BdrvDirtyBitmap *bitmap; - bool migrated; -} LoadBitmapState; -static GSList *enabled_bitmaps; -QemuMutex finish_lock; +static DBMState dbm_state; static uint32_t qemu_get_bitmap_flags(QEMUFile *f) { @@ -169,21 +174,21 @@ static void qemu_put_bitmap_flags(QEMUFile *f, uint32_t flags) qemu_put_byte(f, flags); } -static void send_bitmap_header(QEMUFile *f, SaveBitmapState *dbms, - uint32_t additional_flags) +static void send_bitmap_header(QEMUFile *f, DBMSaveState *s, + SaveBitmapState *dbms, uint32_t additional_flags) { BlockDriverState *bs = dbms->bs; BdrvDirtyBitmap *bitmap = dbms->bitmap; uint32_t flags = additional_flags; trace_send_bitmap_header_enter(); - if (bs != dirty_bitmap_mig_state.prev_bs) { - dirty_bitmap_mig_state.prev_bs = bs; + if (bs != s->prev_bs) { + s->prev_bs = bs; flags |= DIRTY_BITMAP_MIG_FLAG_DEVICE_NAME; } - if (bitmap != dirty_bitmap_mig_state.prev_bitmap) { - dirty_bitmap_mig_state.prev_bitmap = bitmap; + if (bitmap != s->prev_bitmap) { + s->prev_bitmap = bitmap; flags |= DIRTY_BITMAP_MIG_FLAG_BITMAP_NAME; } @@ -198,19 +203,22 @@ static void send_bitmap_header(QEMUFile *f, SaveBitmapState *dbms, } } -static void send_bitmap_start(QEMUFile *f, SaveBitmapState *dbms) +static void send_bitmap_start(QEMUFile *f, DBMSaveState *s, + SaveBitmapState *dbms) { - send_bitmap_header(f, dbms, DIRTY_BITMAP_MIG_FLAG_START); + send_bitmap_header(f, s, dbms, DIRTY_BITMAP_MIG_FLAG_START); qemu_put_be32(f, bdrv_dirty_bitmap_granularity(dbms->bitmap)); qemu_put_byte(f, dbms->flags); } -static void send_bitmap_complete(QEMUFile *f, SaveBitmapState *dbms) +static void send_bitmap_complete(QEMUFile *f, DBMSaveState *s, + SaveBitmapState *dbms) { - send_bitmap_header(f, dbms, DIRTY_BITMAP_MIG_FLAG_COMPLETE); + send_bitmap_header(f, s, dbms, DIRTY_BITMAP_MIG_FLAG_COMPLETE); } -static void send_bitmap_bits(QEMUFile *f, SaveBitmapState *dbms, +static void send_bitmap_bits(QEMUFile *f, DBMSaveState *s, + SaveBitmapState *dbms, uint64_t start_sector, uint32_t nr_sectors) { /* align for buffer_is_zero() */ @@ -235,7 +243,7 @@ static void send_bitmap_bits(QEMUFile *f, SaveBitmapState *dbms, trace_send_bitmap_bits(flags, start_sector, nr_sectors, buf_size); - send_bitmap_header(f, dbms, flags); + send_bitmap_header(f, s, dbms, flags); qemu_put_be64(f, start_sector); qemu_put_be32(f, nr_sectors); @@ -254,12 +262,12 @@ static void send_bitmap_bits(QEMUFile *f, SaveBitmapState *dbms, } /* Called with iothread lock taken. */ -static void dirty_bitmap_do_save_cleanup(void) +static void dirty_bitmap_do_save_cleanup(DBMSaveState *s) { SaveBitmapState *dbms; - while ((dbms = QSIMPLEQ_FIRST(&dirty_bitmap_mig_state.dbms_list)) != NULL) { - QSIMPLEQ_REMOVE_HEAD(&dirty_bitmap_mig_state.dbms_list, entry); + while ((dbms = QSIMPLEQ_FIRST(&s->dbms_list)) != NULL) { + QSIMPLEQ_REMOVE_HEAD(&s->dbms_list, entry); bdrv_dirty_bitmap_set_busy(dbms->bitmap, false); bdrv_unref(dbms->bs); g_free(dbms); @@ -267,7 +275,8 @@ static void dirty_bitmap_do_save_cleanup(void) } /* Called with iothread lock taken. */ -static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name) +static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs, + const char *bs_name) { BdrvDirtyBitmap *bitmap; SaveBitmapState *dbms; @@ -322,25 +331,24 @@ static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name) dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT; } - QSIMPLEQ_INSERT_TAIL(&dirty_bitmap_mig_state.dbms_list, - dbms, entry); + QSIMPLEQ_INSERT_TAIL(&s->dbms_list, dbms, entry); } return 0; } /* Called with iothread lock taken. */ -static int init_dirty_bitmap_migration(void) +static int init_dirty_bitmap_migration(DBMSaveState *s) { BlockDriverState *bs; SaveBitmapState *dbms; GHashTable *handled_by_blk = g_hash_table_new(NULL, NULL); BlockBackend *blk; - dirty_bitmap_mig_state.bulk_completed = false; - dirty_bitmap_mig_state.prev_bs = NULL; - dirty_bitmap_mig_state.prev_bitmap = NULL; - dirty_bitmap_mig_state.no_bitmaps = false; + s->bulk_completed = false; + s->prev_bs = NULL; + s->prev_bitmap = NULL; + s->no_bitmaps = false; /* * Use blockdevice name for direct (or filtered) children of named block @@ -369,7 +377,7 @@ static int init_dirty_bitmap_migration(void) } if (bs && bs->drv && !bs->drv->is_filter) { - if (add_bitmaps_to_list(bs, name)) { + if (add_bitmaps_to_list(s, bs, name)) { goto fail; } g_hash_table_add(handled_by_blk, bs); @@ -381,18 +389,18 @@ static int init_dirty_bitmap_migration(void) continue; } - if (add_bitmaps_to_list(bs, bdrv_get_node_name(bs))) { + if (add_bitmaps_to_list(s, bs, bdrv_get_node_name(bs))) { goto fail; } } /* unset migration flags here, to not roll back it */ - QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) { + QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) { bdrv_dirty_bitmap_skip_store(dbms->bitmap, true); } - if (QSIMPLEQ_EMPTY(&dirty_bitmap_mig_state.dbms_list)) { - dirty_bitmap_mig_state.no_bitmaps = true; + if (QSIMPLEQ_EMPTY(&s->dbms_list)) { + s->no_bitmaps = true; } g_hash_table_destroy(handled_by_blk); @@ -401,18 +409,19 @@ static int init_dirty_bitmap_migration(void) fail: g_hash_table_destroy(handled_by_blk); - dirty_bitmap_do_save_cleanup(); + dirty_bitmap_do_save_cleanup(s); return -1; } /* Called with no lock taken. */ -static void bulk_phase_send_chunk(QEMUFile *f, SaveBitmapState *dbms) +static void bulk_phase_send_chunk(QEMUFile *f, DBMSaveState *s, + SaveBitmapState *dbms) { uint32_t nr_sectors = MIN(dbms->total_sectors - dbms->cur_sector, dbms->sectors_per_chunk); - send_bitmap_bits(f, dbms, dbms->cur_sector, nr_sectors); + send_bitmap_bits(f, s, dbms, dbms->cur_sector, nr_sectors); dbms->cur_sector += nr_sectors; if (dbms->cur_sector >= dbms->total_sectors) { @@ -421,61 +430,66 @@ static void bulk_phase_send_chunk(QEMUFile *f, SaveBitmapState *dbms) } /* Called with no lock taken. */ -static void bulk_phase(QEMUFile *f, bool limit) +static void bulk_phase(QEMUFile *f, DBMSaveState *s, bool limit) { SaveBitmapState *dbms; - QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) { + QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) { while (!dbms->bulk_completed) { - bulk_phase_send_chunk(f, dbms); + bulk_phase_send_chunk(f, s, dbms); if (limit && qemu_file_rate_limit(f)) { return; } } } - dirty_bitmap_mig_state.bulk_completed = true; + s->bulk_completed = true; } /* for SaveVMHandlers */ static void dirty_bitmap_save_cleanup(void *opaque) { - dirty_bitmap_do_save_cleanup(); + DBMSaveState *s = &((DBMState *)opaque)->save; + + dirty_bitmap_do_save_cleanup(s); } static int dirty_bitmap_save_iterate(QEMUFile *f, void *opaque) { + DBMSaveState *s = &((DBMState *)opaque)->save; + trace_dirty_bitmap_save_iterate(migration_in_postcopy()); - if (migration_in_postcopy() && !dirty_bitmap_mig_state.bulk_completed) { - bulk_phase(f, true); + if (migration_in_postcopy() && !s->bulk_completed) { + bulk_phase(f, s, true); } qemu_put_bitmap_flags(f, DIRTY_BITMAP_MIG_FLAG_EOS); - return dirty_bitmap_mig_state.bulk_completed; + return s->bulk_completed; } /* Called with iothread lock taken. */ static int dirty_bitmap_save_complete(QEMUFile *f, void *opaque) { + DBMSaveState *s = &((DBMState *)opaque)->save; SaveBitmapState *dbms; trace_dirty_bitmap_save_complete_enter(); - if (!dirty_bitmap_mig_state.bulk_completed) { - bulk_phase(f, false); + if (!s->bulk_completed) { + bulk_phase(f, s, false); } - QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) { - send_bitmap_complete(f, dbms); + QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) { + send_bitmap_complete(f, s, dbms); } qemu_put_bitmap_flags(f, DIRTY_BITMAP_MIG_FLAG_EOS); trace_dirty_bitmap_save_complete_finish(); - dirty_bitmap_do_save_cleanup(); + dirty_bitmap_save_cleanup(opaque); return 0; } @@ -485,12 +499,13 @@ static void dirty_bitmap_save_pending(QEMUFile *f, void *opaque, uint64_t *res_compatible, uint64_t *res_postcopy_only) { + DBMSaveState *s = &((DBMState *)opaque)->save; SaveBitmapState *dbms; uint64_t pending = 0; qemu_mutex_lock_iothread(); - QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) { + QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) { uint64_t gran = bdrv_dirty_bitmap_granularity(dbms->bitmap); uint64_t sectors = dbms->bulk_completed ? 0 : dbms->total_sectors - dbms->cur_sector; @@ -549,7 +564,7 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s) b->bs = s->bs; b->bitmap = s->bitmap; b->migrated = false; - enabled_bitmaps = g_slist_prepend(enabled_bitmaps, b); + s->enabled_bitmaps = g_slist_prepend(s->enabled_bitmaps, b); } return 0; @@ -557,11 +572,12 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s) void dirty_bitmap_mig_before_vm_start(void) { + DBMLoadState *s = &dbm_state.load; GSList *item; - qemu_mutex_lock(&finish_lock); + qemu_mutex_lock(&s->finish_lock); - for (item = enabled_bitmaps; item; item = g_slist_next(item)) { + for (item = s->enabled_bitmaps; item; item = g_slist_next(item)) { LoadBitmapState *b = item->data; if (b->migrated) { @@ -573,10 +589,10 @@ void dirty_bitmap_mig_before_vm_start(void) g_free(b); } - g_slist_free(enabled_bitmaps); - enabled_bitmaps = NULL; + g_slist_free(s->enabled_bitmaps); + s->enabled_bitmaps = NULL; - qemu_mutex_unlock(&finish_lock); + qemu_mutex_unlock(&s->finish_lock); } static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) @@ -585,9 +601,9 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) trace_dirty_bitmap_load_complete(); bdrv_dirty_bitmap_deserialize_finish(s->bitmap); - qemu_mutex_lock(&finish_lock); + qemu_mutex_lock(&s->finish_lock); - for (item = enabled_bitmaps; item; item = g_slist_next(item)) { + for (item = s->enabled_bitmaps; item; item = g_slist_next(item)) { LoadBitmapState *b = item->data; if (b->bitmap == s->bitmap) { @@ -598,7 +614,7 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) if (bdrv_dirty_bitmap_has_successor(s->bitmap)) { bdrv_dirty_bitmap_lock(s->bitmap); - if (enabled_bitmaps == NULL) { + if (s->enabled_bitmaps == NULL) { /* in postcopy */ bdrv_reclaim_dirty_bitmap_locked(s->bitmap, &error_abort); bdrv_enable_dirty_bitmap_locked(s->bitmap); @@ -617,7 +633,7 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) bdrv_dirty_bitmap_unlock(s->bitmap); } - qemu_mutex_unlock(&finish_lock); + qemu_mutex_unlock(&s->finish_lock); } static int dirty_bitmap_load_bits(QEMUFile *f, DBMLoadState *s) @@ -714,7 +730,7 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s) static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) { - static DBMLoadState s; + DBMLoadState *s = &((DBMState *)opaque)->load; int ret = 0; trace_dirty_bitmap_load_enter(); @@ -724,17 +740,17 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) } do { - ret = dirty_bitmap_load_header(f, &s); + ret = dirty_bitmap_load_header(f, s); if (ret < 0) { return ret; } - if (s.flags & DIRTY_BITMAP_MIG_FLAG_START) { - ret = dirty_bitmap_load_start(f, &s); - } else if (s.flags & DIRTY_BITMAP_MIG_FLAG_COMPLETE) { - dirty_bitmap_load_complete(f, &s); - } else if (s.flags & DIRTY_BITMAP_MIG_FLAG_BITS) { - ret = dirty_bitmap_load_bits(f, &s); + if (s->flags & DIRTY_BITMAP_MIG_FLAG_START) { + ret = dirty_bitmap_load_start(f, s); + } else if (s->flags & DIRTY_BITMAP_MIG_FLAG_COMPLETE) { + dirty_bitmap_load_complete(f, s); + } else if (s->flags & DIRTY_BITMAP_MIG_FLAG_BITS) { + ret = dirty_bitmap_load_bits(f, s); } if (!ret) { @@ -744,7 +760,7 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) if (ret) { return ret; } - } while (!(s.flags & DIRTY_BITMAP_MIG_FLAG_EOS)); + } while (!(s->flags & DIRTY_BITMAP_MIG_FLAG_EOS)); trace_dirty_bitmap_load_success(); return 0; @@ -752,13 +768,14 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque) { + DBMSaveState *s = &((DBMState *)opaque)->save; SaveBitmapState *dbms = NULL; - if (init_dirty_bitmap_migration() < 0) { + if (init_dirty_bitmap_migration(s) < 0) { return -1; } - QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) { - send_bitmap_start(f, dbms); + QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) { + send_bitmap_start(f, s, dbms); } qemu_put_bitmap_flags(f, DIRTY_BITMAP_MIG_FLAG_EOS); @@ -767,7 +784,9 @@ static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque) static bool dirty_bitmap_is_active(void *opaque) { - return migrate_dirty_bitmaps() && !dirty_bitmap_mig_state.no_bitmaps; + DBMSaveState *s = &((DBMState *)opaque)->save; + + return migrate_dirty_bitmaps() && !s->no_bitmaps; } static bool dirty_bitmap_is_active_iterate(void *opaque) @@ -795,10 +814,10 @@ static SaveVMHandlers savevm_dirty_bitmap_handlers = { void dirty_bitmap_mig_init(void) { - QSIMPLEQ_INIT(&dirty_bitmap_mig_state.dbms_list); - qemu_mutex_init(&finish_lock); + QSIMPLEQ_INIT(&dbm_state.save.dbms_list); + qemu_mutex_init(&dbm_state.load.finish_lock); register_savevm_live("dirty-bitmap", 0, 1, &savevm_dirty_bitmap_handlers, - &dirty_bitmap_mig_state); + &dbm_state); } From 8949121644b756b58d6546d86c9a49f18a0e5153 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:27 +0300 Subject: [PATCH 2531/2595] migration/block-dirty-bitmap: rename finish_lock to just lock finish_lock is bad name, as lock used not only on process end. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200727194236.19551-13-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 9b39e7aa2b..9194807b54 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -143,7 +143,7 @@ typedef struct DBMLoadState { BdrvDirtyBitmap *bitmap; GSList *enabled_bitmaps; - QemuMutex finish_lock; + QemuMutex lock; /* protect enabled_bitmaps */ } DBMLoadState; typedef struct DBMState { @@ -575,7 +575,7 @@ void dirty_bitmap_mig_before_vm_start(void) DBMLoadState *s = &dbm_state.load; GSList *item; - qemu_mutex_lock(&s->finish_lock); + qemu_mutex_lock(&s->lock); for (item = s->enabled_bitmaps; item; item = g_slist_next(item)) { LoadBitmapState *b = item->data; @@ -592,7 +592,7 @@ void dirty_bitmap_mig_before_vm_start(void) g_slist_free(s->enabled_bitmaps); s->enabled_bitmaps = NULL; - qemu_mutex_unlock(&s->finish_lock); + qemu_mutex_unlock(&s->lock); } static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) @@ -601,7 +601,7 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) trace_dirty_bitmap_load_complete(); bdrv_dirty_bitmap_deserialize_finish(s->bitmap); - qemu_mutex_lock(&s->finish_lock); + qemu_mutex_lock(&s->lock); for (item = s->enabled_bitmaps; item; item = g_slist_next(item)) { LoadBitmapState *b = item->data; @@ -633,7 +633,7 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) bdrv_dirty_bitmap_unlock(s->bitmap); } - qemu_mutex_unlock(&s->finish_lock); + qemu_mutex_unlock(&s->lock); } static int dirty_bitmap_load_bits(QEMUFile *f, DBMLoadState *s) @@ -815,7 +815,7 @@ static SaveVMHandlers savevm_dirty_bitmap_handlers = { void dirty_bitmap_mig_init(void) { QSIMPLEQ_INIT(&dbm_state.save.dbms_list); - qemu_mutex_init(&dbm_state.load.finish_lock); + qemu_mutex_init(&dbm_state.load.lock); register_savevm_live("dirty-bitmap", 0, 1, &savevm_dirty_bitmap_handlers, From f3045b9a828e99221083a4ad9905b9d7cdd4df2f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:28 +0300 Subject: [PATCH 2532/2595] migration/block-dirty-bitmap: simplify dirty_bitmap_load_complete bdrv_enable_dirty_bitmap_locked() call does nothing, as if we are in postcopy, bitmap successor must be enabled, and reclaim operation will enable the bitmap. So, actually we need just call _reclaim_ in both if branches, and making differences only to add an assertion seems not really good. The logic becomes simple: on load complete we do reclaim and that's all. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200727194236.19551-14-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 9194807b54..405a259296 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -603,6 +603,10 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) qemu_mutex_lock(&s->lock); + if (bdrv_dirty_bitmap_has_successor(s->bitmap)) { + bdrv_reclaim_dirty_bitmap(s->bitmap, &error_abort); + } + for (item = s->enabled_bitmaps; item; item = g_slist_next(item)) { LoadBitmapState *b = item->data; @@ -612,27 +616,6 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) } } - if (bdrv_dirty_bitmap_has_successor(s->bitmap)) { - bdrv_dirty_bitmap_lock(s->bitmap); - if (s->enabled_bitmaps == NULL) { - /* in postcopy */ - bdrv_reclaim_dirty_bitmap_locked(s->bitmap, &error_abort); - bdrv_enable_dirty_bitmap_locked(s->bitmap); - } else { - /* target not started, successor must be empty */ - int64_t count = bdrv_get_dirty_count(s->bitmap); - BdrvDirtyBitmap *ret = bdrv_reclaim_dirty_bitmap_locked(s->bitmap, - NULL); - /* bdrv_reclaim_dirty_bitmap can fail only on no successor (it - * must be) or on merge fail, but merge can't fail when second - * bitmap is empty - */ - assert(ret == s->bitmap && - count == bdrv_get_dirty_count(s->bitmap)); - } - bdrv_dirty_bitmap_unlock(s->bitmap); - } - qemu_mutex_unlock(&s->lock); } From 0a47190a009614598dc5ae3d9d25138575184520 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:29 +0300 Subject: [PATCH 2533/2595] migration/block-dirty-bitmap: keep bitmap state for all bitmaps Keep bitmap state for disabled bitmaps too. Keep the state until the end of the process. It's needed for the following commit to implement bitmap postcopy canceling. To clean-up the new list the following logic is used: We need two events to consider bitmap migration finished: 1. chunk with DIRTY_BITMAP_MIG_FLAG_COMPLETE flag should be received 2. dirty_bitmap_mig_before_vm_start should be called These two events may come in any order, so we understand which one is last, and on the last of them we remove bitmap migration state from the list. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200727194236.19551-15-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 68 ++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 405a259296..eb4ffeac4d 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -132,6 +132,7 @@ typedef struct LoadBitmapState { BlockDriverState *bs; BdrvDirtyBitmap *bitmap; bool migrated; + bool enabled; } LoadBitmapState; /* State of the dirty bitmap migration (DBM) during load process */ @@ -142,8 +143,10 @@ typedef struct DBMLoadState { BlockDriverState *bs; BdrvDirtyBitmap *bitmap; - GSList *enabled_bitmaps; - QemuMutex lock; /* protect enabled_bitmaps */ + bool before_vm_start_handled; /* set in dirty_bitmap_mig_before_vm_start */ + + GSList *bitmaps; + QemuMutex lock; /* protect bitmaps */ } DBMLoadState; typedef struct DBMState { @@ -526,6 +529,7 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s) Error *local_err = NULL; uint32_t granularity = qemu_get_be32(f); uint8_t flags = qemu_get_byte(f); + LoadBitmapState *b; if (s->bitmap) { error_report("Bitmap with the same name ('%s') already exists on " @@ -552,45 +556,59 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s) bdrv_disable_dirty_bitmap(s->bitmap); if (flags & DIRTY_BITMAP_MIG_START_FLAG_ENABLED) { - LoadBitmapState *b; - bdrv_dirty_bitmap_create_successor(s->bitmap, &local_err); if (local_err) { error_report_err(local_err); return -EINVAL; } - - b = g_new(LoadBitmapState, 1); - b->bs = s->bs; - b->bitmap = s->bitmap; - b->migrated = false; - s->enabled_bitmaps = g_slist_prepend(s->enabled_bitmaps, b); } + b = g_new(LoadBitmapState, 1); + b->bs = s->bs; + b->bitmap = s->bitmap; + b->migrated = false; + b->enabled = flags & DIRTY_BITMAP_MIG_START_FLAG_ENABLED; + + s->bitmaps = g_slist_prepend(s->bitmaps, b); + return 0; } -void dirty_bitmap_mig_before_vm_start(void) +/* + * before_vm_start_handle_item + * + * g_slist_foreach helper + * + * item is LoadBitmapState* + * opaque is DBMLoadState* + */ +static void before_vm_start_handle_item(void *item, void *opaque) { - DBMLoadState *s = &dbm_state.load; - GSList *item; - - qemu_mutex_lock(&s->lock); - - for (item = s->enabled_bitmaps; item; item = g_slist_next(item)) { - LoadBitmapState *b = item->data; + DBMLoadState *s = opaque; + LoadBitmapState *b = item; + if (b->enabled) { if (b->migrated) { bdrv_enable_dirty_bitmap(b->bitmap); } else { bdrv_dirty_bitmap_enable_successor(b->bitmap); } - - g_free(b); } - g_slist_free(s->enabled_bitmaps); - s->enabled_bitmaps = NULL; + if (b->migrated) { + s->bitmaps = g_slist_remove(s->bitmaps, b); + g_free(b); + } +} + +void dirty_bitmap_mig_before_vm_start(void) +{ + DBMLoadState *s = &dbm_state.load; + qemu_mutex_lock(&s->lock); + + assert(!s->before_vm_start_handled); + g_slist_foreach(s->bitmaps, before_vm_start_handle_item, s); + s->before_vm_start_handled = true; qemu_mutex_unlock(&s->lock); } @@ -607,11 +625,15 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) bdrv_reclaim_dirty_bitmap(s->bitmap, &error_abort); } - for (item = s->enabled_bitmaps; item; item = g_slist_next(item)) { + for (item = s->bitmaps; item; item = g_slist_next(item)) { LoadBitmapState *b = item->data; if (b->bitmap == s->bitmap) { b->migrated = true; + if (s->before_vm_start_handled) { + s->bitmaps = g_slist_remove(s->bitmaps, b); + g_free(b); + } break; } } From b91f33b81df7439ac504f4737c3e529ec2bf0525 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:30 +0300 Subject: [PATCH 2534/2595] migration/block-dirty-bitmap: relax error handling in incoming part Bitmaps data is not critical, and we should not fail the migration (or use postcopy recovering) because of dirty-bitmaps migration failure. Instead we should just lose unfinished bitmaps. Still we have to report io stream violation errors, as they affect the whole migration stream. While touching this, tighten code that was previously blindly calling malloc on a size read from the migration stream, as a corrupted stream (perhaps from a malicious user) should not be able to convince us to allocate an inordinate amount of memory. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200727194236.19551-16-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake [eblake: typo fixes, enhance commit message] Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 162 +++++++++++++++++++++++++-------- 1 file changed, 126 insertions(+), 36 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index eb4ffeac4d..f91015a4f8 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -145,6 +145,15 @@ typedef struct DBMLoadState { bool before_vm_start_handled; /* set in dirty_bitmap_mig_before_vm_start */ + /* + * cancelled + * Incoming migration is cancelled for some reason. That means that we + * still should read our chunks from migration stream, to not affect other + * migration objects (like RAM), but just ignore them and do not touch any + * bitmaps or nodes. + */ + bool cancelled; + GSList *bitmaps; QemuMutex lock; /* protect bitmaps */ } DBMLoadState; @@ -531,6 +540,10 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s) uint8_t flags = qemu_get_byte(f); LoadBitmapState *b; + if (s->cancelled) { + return 0; + } + if (s->bitmap) { error_report("Bitmap with the same name ('%s') already exists on " "destination", bdrv_dirty_bitmap_name(s->bitmap)); @@ -613,13 +626,47 @@ void dirty_bitmap_mig_before_vm_start(void) qemu_mutex_unlock(&s->lock); } +static void cancel_incoming_locked(DBMLoadState *s) +{ + GSList *item; + + if (s->cancelled) { + return; + } + + s->cancelled = true; + s->bs = NULL; + s->bitmap = NULL; + + /* Drop all unfinished bitmaps */ + for (item = s->bitmaps; item; item = g_slist_next(item)) { + LoadBitmapState *b = item->data; + + /* + * Bitmap must be unfinished, as finished bitmaps should already be + * removed from the list. + */ + assert(!s->before_vm_start_handled || !b->migrated); + if (bdrv_dirty_bitmap_has_successor(b->bitmap)) { + bdrv_reclaim_dirty_bitmap(b->bitmap, &error_abort); + } + bdrv_release_dirty_bitmap(b->bitmap); + } + + g_slist_free_full(s->bitmaps, g_free); + s->bitmaps = NULL; +} + static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) { GSList *item; trace_dirty_bitmap_load_complete(); - bdrv_dirty_bitmap_deserialize_finish(s->bitmap); - qemu_mutex_lock(&s->lock); + if (s->cancelled) { + return; + } + + bdrv_dirty_bitmap_deserialize_finish(s->bitmap); if (bdrv_dirty_bitmap_has_successor(s->bitmap)) { bdrv_reclaim_dirty_bitmap(s->bitmap, &error_abort); @@ -637,8 +684,6 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) break; } } - - qemu_mutex_unlock(&s->lock); } static int dirty_bitmap_load_bits(QEMUFile *f, DBMLoadState *s) @@ -650,15 +695,46 @@ static int dirty_bitmap_load_bits(QEMUFile *f, DBMLoadState *s) if (s->flags & DIRTY_BITMAP_MIG_FLAG_ZEROES) { trace_dirty_bitmap_load_bits_zeroes(); - bdrv_dirty_bitmap_deserialize_zeroes(s->bitmap, first_byte, nr_bytes, - false); + if (!s->cancelled) { + bdrv_dirty_bitmap_deserialize_zeroes(s->bitmap, first_byte, + nr_bytes, false); + } } else { size_t ret; - uint8_t *buf; + g_autofree uint8_t *buf = NULL; uint64_t buf_size = qemu_get_be64(f); - uint64_t needed_size = - bdrv_dirty_bitmap_serialization_size(s->bitmap, - first_byte, nr_bytes); + uint64_t needed_size; + + /* + * The actual check for buf_size is done a bit later. We can't do it in + * cancelled mode as we don't have the bitmap to check the constraints + * (so, we allocate a buffer and read prior to the check). On the other + * hand, we shouldn't blindly g_malloc the number from the stream. + * Actually one chunk should not be larger than CHUNK_SIZE. Let's allow + * a bit larger (which means that bitmap migration will fail anyway and + * the whole migration will most probably fail soon due to broken + * stream). + */ + if (buf_size > 10 * CHUNK_SIZE) { + error_report("Bitmap migration stream buffer allocation request " + "is too large"); + return -EIO; + } + + buf = g_malloc(buf_size); + ret = qemu_get_buffer(f, buf, buf_size); + if (ret != buf_size) { + error_report("Failed to read bitmap bits"); + return -EIO; + } + + if (s->cancelled) { + return 0; + } + + needed_size = bdrv_dirty_bitmap_serialization_size(s->bitmap, + first_byte, + nr_bytes); if (needed_size > buf_size || buf_size > QEMU_ALIGN_UP(needed_size, 4 * sizeof(long)) @@ -667,20 +743,12 @@ static int dirty_bitmap_load_bits(QEMUFile *f, DBMLoadState *s) error_report("Migrated bitmap granularity doesn't " "match the destination bitmap '%s' granularity", bdrv_dirty_bitmap_name(s->bitmap)); - return -EINVAL; - } - - buf = g_malloc(buf_size); - ret = qemu_get_buffer(f, buf, buf_size); - if (ret != buf_size) { - error_report("Failed to read bitmap bits"); - g_free(buf); - return -EIO; + cancel_incoming_locked(s); + return 0; } bdrv_dirty_bitmap_deserialize_part(s->bitmap, buf, first_byte, nr_bytes, false); - g_free(buf); } return 0; @@ -700,14 +768,16 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s) error_report("Unable to read node name string"); return -EINVAL; } - s->bs = bdrv_lookup_bs(s->node_name, s->node_name, &local_err); - if (!s->bs) { - error_report_err(local_err); - return -EINVAL; + if (!s->cancelled) { + s->bs = bdrv_lookup_bs(s->node_name, s->node_name, &local_err); + if (!s->bs) { + error_report_err(local_err); + cancel_incoming_locked(s); + } } - } else if (!s->bs && !nothing) { + } else if (!s->bs && !nothing && !s->cancelled) { error_report("Error: block device name is not set"); - return -EINVAL; + cancel_incoming_locked(s); } if (s->flags & DIRTY_BITMAP_MIG_FLAG_BITMAP_NAME) { @@ -715,24 +785,38 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s) error_report("Unable to read bitmap name string"); return -EINVAL; } - s->bitmap = bdrv_find_dirty_bitmap(s->bs, s->bitmap_name); + if (!s->cancelled) { + s->bitmap = bdrv_find_dirty_bitmap(s->bs, s->bitmap_name); - /* bitmap may be NULL here, it wouldn't be an error if it is the - * first occurrence of the bitmap */ - if (!s->bitmap && !(s->flags & DIRTY_BITMAP_MIG_FLAG_START)) { - error_report("Error: unknown dirty bitmap " - "'%s' for block device '%s'", - s->bitmap_name, s->node_name); - return -EINVAL; + /* + * bitmap may be NULL here, it wouldn't be an error if it is the + * first occurrence of the bitmap + */ + if (!s->bitmap && !(s->flags & DIRTY_BITMAP_MIG_FLAG_START)) { + error_report("Error: unknown dirty bitmap " + "'%s' for block device '%s'", + s->bitmap_name, s->node_name); + cancel_incoming_locked(s); + } } - } else if (!s->bitmap && !nothing) { + } else if (!s->bitmap && !nothing && !s->cancelled) { error_report("Error: block device name is not set"); - return -EINVAL; + cancel_incoming_locked(s); } return 0; } +/* + * dirty_bitmap_load + * + * Load sequence of dirty bitmap chunks. Return error only on fatal io stream + * violations. On other errors just cancel bitmaps incoming migration and return + * 0. + * + * Note, than when incoming bitmap migration is canceled, we still must read all + * our chunks (and just ignore them), to not affect other migration objects. + */ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) { DBMLoadState *s = &((DBMState *)opaque)->load; @@ -741,12 +825,17 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) trace_dirty_bitmap_load_enter(); if (version_id != 1) { + QEMU_LOCK_GUARD(&s->lock); + cancel_incoming_locked(s); return -EINVAL; } do { + QEMU_LOCK_GUARD(&s->lock); + ret = dirty_bitmap_load_header(f, s); if (ret < 0) { + cancel_incoming_locked(s); return ret; } @@ -763,6 +852,7 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) } if (ret) { + cancel_incoming_locked(s); return ret; } } while (!(s->flags & DIRTY_BITMAP_MIG_FLAG_EOS)); From 1499ab096950364d634418e7aefb562694d6c953 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:31 +0300 Subject: [PATCH 2535/2595] migration/block-dirty-bitmap: cancel migration on shutdown If target is turned off prior to postcopy finished, target crashes because busy bitmaps are found at shutdown. Canceling incoming migration helps, as it removes all unfinished (and therefore busy) bitmaps. Similarly on source we crash in bdrv_close_all which asserts that all bdrv states are removed, because bdrv states involved into dirty bitmap migration are referenced by it. So, we need to cancel outgoing migration as well. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200727194236.19551-17-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 16 ++++++++++++++++ migration/migration.c | 13 +++++++++++++ migration/migration.h | 2 ++ 3 files changed, 31 insertions(+) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index f91015a4f8..1f675b792f 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -657,6 +657,22 @@ static void cancel_incoming_locked(DBMLoadState *s) s->bitmaps = NULL; } +void dirty_bitmap_mig_cancel_outgoing(void) +{ + dirty_bitmap_do_save_cleanup(&dbm_state.save); +} + +void dirty_bitmap_mig_cancel_incoming(void) +{ + DBMLoadState *s = &dbm_state.load; + + qemu_mutex_lock(&s->lock); + + cancel_incoming_locked(s); + + qemu_mutex_unlock(&s->lock); +} + static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s) { GSList *item; diff --git a/migration/migration.c b/migration/migration.c index 1c61428988..8fe36339db 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -188,6 +188,19 @@ void migration_shutdown(void) */ migrate_fd_cancel(current_migration); object_unref(OBJECT(current_migration)); + + /* + * Cancel outgoing migration of dirty bitmaps. It should + * at least unref used block nodes. + */ + dirty_bitmap_mig_cancel_outgoing(); + + /* + * Cancel incoming migration of dirty bitmaps. Dirty bitmaps + * are non-critical data, and their loss never considered as + * something serious. + */ + dirty_bitmap_mig_cancel_incoming(); } /* For outgoing */ diff --git a/migration/migration.h b/migration/migration.h index ab20c756f5..6c6a931d0d 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -335,6 +335,8 @@ void migrate_send_rp_recv_bitmap(MigrationIncomingState *mis, void migrate_send_rp_resume_ack(MigrationIncomingState *mis, uint32_t value); void dirty_bitmap_mig_before_vm_start(void); +void dirty_bitmap_mig_cancel_outgoing(void); +void dirty_bitmap_mig_cancel_incoming(void); void migrate_add_address(SocketAddress *address); int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque); From ee64722514fabcad2430982ade86180208f5be4f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:32 +0300 Subject: [PATCH 2536/2595] migration/savevm: don't worry if bitmap migration postcopy failed First, if only bitmaps postcopy is enabled (and not ram postcopy) postcopy_pause_incoming crashes on an assertion assert(mis->to_src_file). And anyway, bitmaps postcopy is not prepared to be somehow recovered. The original idea instead is that if bitmaps postcopy failed, we just lose some bitmaps, which is not critical. So, on failure we just need to remove unfinished bitmaps and guest should continue execution on destination. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Andrey Shinkevich Reviewed-by: Eric Blake Message-Id: <20200727194236.19551-18-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- migration/savevm.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/migration/savevm.c b/migration/savevm.c index 45c9dd9d8a..a843d202b5 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1813,6 +1813,9 @@ static void *postcopy_ram_listen_thread(void *opaque) MigrationIncomingState *mis = migration_incoming_get_current(); QEMUFile *f = mis->from_src_file; int load_res; + MigrationState *migr = migrate_get_current(); + + object_ref(OBJECT(migr)); migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE, MIGRATION_STATUS_POSTCOPY_ACTIVE); @@ -1839,11 +1842,24 @@ static void *postcopy_ram_listen_thread(void *opaque) trace_postcopy_ram_listen_thread_exit(); if (load_res < 0) { - error_report("%s: loadvm failed: %d", __func__, load_res); qemu_file_set_error(f, load_res); - migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE, - MIGRATION_STATUS_FAILED); - } else { + dirty_bitmap_mig_cancel_incoming(); + if (postcopy_state_get() == POSTCOPY_INCOMING_RUNNING && + !migrate_postcopy_ram() && migrate_dirty_bitmaps()) + { + error_report("%s: loadvm failed during postcopy: %d. All states " + "are migrated except dirty bitmaps. Some dirty " + "bitmaps may be lost, and present migrated dirty " + "bitmaps are correctly migrated and valid.", + __func__, load_res); + load_res = 0; /* prevent further exit() */ + } else { + error_report("%s: loadvm failed: %d", __func__, load_res); + migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE, + MIGRATION_STATUS_FAILED); + } + } + if (load_res >= 0) { /* * This looks good, but it's possible that the device loading in the * main thread hasn't finished yet, and so we might not be in 'RUN' @@ -1879,6 +1895,8 @@ static void *postcopy_ram_listen_thread(void *opaque) mis->have_listen_thread = false; postcopy_state_set(POSTCOPY_INCOMING_END); + object_unref(OBJECT(migr)); + return NULL; } @@ -2437,6 +2455,8 @@ static bool postcopy_pause_incoming(MigrationIncomingState *mis) { trace_postcopy_pause_incoming(); + assert(migrate_postcopy_ram()); + /* Clear the triggered bit to allow one recovery */ mis->postcopy_recover_triggered = false; @@ -2521,15 +2541,22 @@ out: if (ret < 0) { qemu_file_set_error(f, ret); + /* Cancel bitmaps incoming regardless of recovery */ + dirty_bitmap_mig_cancel_incoming(); + /* * If we are during an active postcopy, then we pause instead * of bail out to at least keep the VM's dirty data. Note * that POSTCOPY_INCOMING_LISTENING stage is still not enough, * during which we're still receiving device states and we * still haven't yet started the VM on destination. + * + * Only RAM postcopy supports recovery. Still, if RAM postcopy is + * enabled, canceled bitmaps postcopy will not affect RAM postcopy + * recovering. */ if (postcopy_state_get() == POSTCOPY_INCOMING_RUNNING && - postcopy_pause_incoming(mis)) { + migrate_postcopy_ram() && postcopy_pause_incoming(mis)) { /* Reset f to point to the newly created channel */ f = mis->from_src_file; goto retry; From 48f43820cd39f566536f0a5acc328c181f03f0d0 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:33 +0300 Subject: [PATCH 2537/2595] qemu-iotests/199: prepare for new test-cases addition Move future common part to start_postcopy() method. Move checking number of bitmaps to check_bitmap(). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200727194236.19551-19-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/199 | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199 index d8532e49da..355c0b2885 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/199 @@ -29,6 +29,8 @@ disk_b = os.path.join(iotests.test_dir, 'disk_b') size = '256G' fifo = os.path.join(iotests.test_dir, 'mig_fifo') +granularity = 512 +nb_bitmaps = 15 GiB = 1024 * 1024 * 1024 @@ -61,6 +63,15 @@ def event_dist(e1, e2): return event_seconds(e2) - event_seconds(e1) +def check_bitmaps(vm, count): + result = vm.qmp('query-block') + + if count == 0: + assert 'dirty-bitmaps' not in result['return'][0] + else: + assert len(result['return'][0]['dirty-bitmaps']) == count + + class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): def tearDown(self): if debug: @@ -101,10 +112,8 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): self.vm_a_events = [] self.vm_b_events = [] - def test_postcopy(self): - granularity = 512 - nb_bitmaps = 15 - + def start_postcopy(self): + """ Run migration until RESUME event on target. Return this event. """ for i in range(nb_bitmaps): result = self.vm_a.qmp('block-dirty-bitmap-add', node='drive0', name='bitmap{}'.format(i), @@ -119,10 +128,10 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', node='drive0', name='bitmap0') - discards1_sha256 = result['return']['sha256'] + self.discards1_sha256 = result['return']['sha256'] # Check, that updating the bitmap by discards works - assert discards1_sha256 != empty_sha256 + assert self.discards1_sha256 != empty_sha256 # We want to calculate resulting sha256. Do it in bitmap0, so, disable # other bitmaps @@ -135,7 +144,7 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', node='drive0', name='bitmap0') - all_discards_sha256 = result['return']['sha256'] + self.all_discards_sha256 = result['return']['sha256'] # Now, enable some bitmaps, to be updated during migration for i in range(2, nb_bitmaps, 2): @@ -160,6 +169,10 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): event_resume = self.vm_b.event_wait('RESUME') self.vm_b_events.append(event_resume) + return event_resume + + def test_postcopy_success(self): + event_resume = self.start_postcopy() # enabled bitmaps should be updated apply_discards(self.vm_b, discards2) @@ -180,18 +193,15 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): print('downtime:', downtime) print('postcopy_time:', postcopy_time) - # Assert that bitmap migration is finished (check that successor bitmap - # is removed) - result = self.vm_b.qmp('query-block') - assert len(result['return'][0]['dirty-bitmaps']) == nb_bitmaps + check_bitmaps(self.vm_b, nb_bitmaps) # Check content of migrated bitmaps. Still, don't waste time checking # every bitmap for i in range(0, nb_bitmaps, 5): result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256', node='drive0', name='bitmap{}'.format(i)) - sha256 = discards1_sha256 if i % 2 else all_discards_sha256 - self.assert_qmp(result, 'return/sha256', sha256) + sha = self.discards1_sha256 if i % 2 else self.all_discards_sha256 + self.assert_qmp(result, 'return/sha256', sha) if __name__ == '__main__': From d4c6fcc01b59016e49adf3b12e23e65df212eba2 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:34 +0300 Subject: [PATCH 2538/2595] qemu-iotests/199: check persistent bitmaps Check that persistent bitmaps are not stored on source and that bitmaps are persistent on destination. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200727194236.19551-20-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/199 | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199 index 355c0b2885..5fd34f0fcd 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/199 @@ -117,7 +117,8 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): for i in range(nb_bitmaps): result = self.vm_a.qmp('block-dirty-bitmap-add', node='drive0', name='bitmap{}'.format(i), - granularity=granularity) + granularity=granularity, + persistent=True) self.assert_qmp(result, 'return', {}) result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', @@ -193,6 +194,19 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): print('downtime:', downtime) print('postcopy_time:', postcopy_time) + # check that there are no bitmaps stored on source + self.vm_a_events += self.vm_a.get_qmp_events() + self.vm_a.shutdown() + self.vm_a.launch() + check_bitmaps(self.vm_a, 0) + + # check that bitmaps are migrated and persistence works + check_bitmaps(self.vm_b, nb_bitmaps) + self.vm_b.shutdown() + # recreate vm_b, so there is no incoming option, which prevents + # loading bitmaps from disk + self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b) + self.vm_b.launch() check_bitmaps(self.vm_b, nb_bitmaps) # Check content of migrated bitmaps. Still, don't waste time checking From 845b2204c969c90949d5b90765d754a7ca25dc56 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:35 +0300 Subject: [PATCH 2539/2595] qemu-iotests/199: add early shutdown case to bitmaps postcopy Previous patches fixed two crashes which may occur on shutdown prior to bitmaps postcopy finished. Check that it works now. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Tested-by: Eric Blake Message-Id: <20200727194236.19551-21-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/199 | 24 ++++++++++++++++++++++++ tests/qemu-iotests/199.out | 4 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199 index 5fd34f0fcd..140930b2b1 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/199 @@ -217,6 +217,30 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): sha = self.discards1_sha256 if i % 2 else self.all_discards_sha256 self.assert_qmp(result, 'return/sha256', sha) + def test_early_shutdown_destination(self): + self.start_postcopy() + + self.vm_b_events += self.vm_b.get_qmp_events() + self.vm_b.shutdown() + # recreate vm_b, so there is no incoming option, which prevents + # loading bitmaps from disk + self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b) + self.vm_b.launch() + check_bitmaps(self.vm_b, 0) + + # Bitmaps will be lost if we just shutdown the vm, as they are marked + # to skip storing to disk when prepared for migration. And that's + # correct, as actual data may be modified in target vm, so we play + # safe. + # Still, this mark would be taken away if we do 'cont', and bitmaps + # become persistent again. (see iotest 169 for such behavior case) + result = self.vm_a.qmp('query-status') + assert not result['return']['running'] + self.vm_a_events += self.vm_a.get_qmp_events() + self.vm_a.shutdown() + self.vm_a.launch() + check_bitmaps(self.vm_a, 0) + if __name__ == '__main__': iotests.main(supported_fmts=['qcow2']) diff --git a/tests/qemu-iotests/199.out b/tests/qemu-iotests/199.out index ae1213e6f8..fbc63e62f8 100644 --- a/tests/qemu-iotests/199.out +++ b/tests/qemu-iotests/199.out @@ -1,5 +1,5 @@ -. +.. ---------------------------------------------------------------------- -Ran 1 tests +Ran 2 tests OK From 058a08a658ebe152526ea41093679cdb0004abb3 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 22:42:36 +0300 Subject: [PATCH 2540/2595] qemu-iotests/199: add source-killed case to bitmaps postcopy Previous patches fixes behavior of bitmaps migration, so that errors are handled by just removing unfinished bitmaps, and not fail or try to recover postcopy migration. Add corresponding test. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Tested-by: Eric Blake Message-Id: <20200727194236.19551-22-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/199 | 15 +++++++++++++++ tests/qemu-iotests/199.out | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199 index 140930b2b1..58fad872a1 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/199 @@ -241,6 +241,21 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): self.vm_a.launch() check_bitmaps(self.vm_a, 0) + def test_early_kill_source(self): + self.start_postcopy() + + self.vm_a_events = self.vm_a.get_qmp_events() + self.vm_a.kill() + + self.vm_a.launch() + + match = {'data': {'status': 'completed'}} + e_complete = self.vm_b.event_wait('MIGRATION', match=match) + self.vm_b_events.append(e_complete) + + check_bitmaps(self.vm_a, 0) + check_bitmaps(self.vm_b, 0) + if __name__ == '__main__': iotests.main(supported_fmts=['qcow2']) diff --git a/tests/qemu-iotests/199.out b/tests/qemu-iotests/199.out index fbc63e62f8..8d7e996700 100644 --- a/tests/qemu-iotests/199.out +++ b/tests/qemu-iotests/199.out @@ -1,5 +1,5 @@ -.. +... ---------------------------------------------------------------------- -Ran 2 tests +Ran 3 tests OK From fbd1c1b6426019ab4410f9d01eaa1a8c6394491f Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 27 Jul 2020 14:51:17 -0500 Subject: [PATCH 2541/2595] iotests: Adjust which migration tests are quick A quick run of './check -qcow2 -g migration' shows that test 169 is NOT quick, but meanwhile several other tests ARE quick. Let's adjust the test designations accordingly. Signed-off-by: Eric Blake Message-Id: <20200727195117.132151-1-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- tests/qemu-iotests/group | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 1d0252e1f0..806044642c 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -112,7 +112,7 @@ 088 rw quick 089 rw auto quick 090 rw auto quick -091 rw migration +091 rw migration quick 092 rw quick 093 throttle 094 rw quick @@ -186,7 +186,7 @@ 162 quick 163 rw 165 rw quick -169 rw quick migration +169 rw migration 170 rw auto quick 171 rw quick 172 auto @@ -197,9 +197,9 @@ 177 rw auto quick 178 img 179 rw auto quick -181 rw auto migration +181 rw auto migration quick 182 rw quick -183 rw migration +183 rw migration quick 184 rw auto quick 185 rw 186 rw auto @@ -216,9 +216,9 @@ 198 rw 199 rw migration 200 rw -201 rw migration +201 rw migration quick 202 rw quick -203 rw auto migration +203 rw auto migration quick 204 rw quick 205 rw quick 206 rw From 37931e006f05cb768b78dcc47453b13f76ea43c5 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 27 Jul 2020 15:32:06 -0500 Subject: [PATCH 2542/2595] migration: Fix typos in bitmap migration comments Noticed while reviewing the file for newer patches. Fixes: b35ebdf076 Signed-off-by: Eric Blake Message-Id: <20200727203206.134996-1-eblake@redhat.com> --- migration/block-dirty-bitmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 1f675b792f..784330ebe1 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -97,7 +97,7 @@ #define DIRTY_BITMAP_MIG_START_FLAG_ENABLED 0x01 #define DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT 0x02 -/* 0x04 was "AUTOLOAD" flags on elder versions, no it is ignored */ +/* 0x04 was "AUTOLOAD" flags on older versions, now it is ignored */ #define DIRTY_BITMAP_MIG_START_FLAG_RESERVED_MASK 0xf8 /* State of one bitmap during save process */ @@ -180,7 +180,7 @@ static uint32_t qemu_get_bitmap_flags(QEMUFile *f) static void qemu_put_bitmap_flags(QEMUFile *f, uint32_t flags) { - /* The code currently do not send flags more than one byte */ + /* The code currently does not send flags as more than one byte */ assert(!(flags & (0xffffff00 | DIRTY_BITMAP_MIG_EXTRA_FLAGS))); qemu_put_byte(f, flags); From 3aaebc0cce4a4963f331f45643e17266646411e6 Mon Sep 17 00:00:00 2001 From: Basil Salman Date: Thu, 30 Apr 2020 15:11:40 +0300 Subject: [PATCH 2543/2595] qga-win: fix "guest-get-fsinfo" wrong filesystem type This patch handles the case where unmounted volumes exist, where in that case GetVolumePathNamesForVolumeName returns empty path, GetVolumeInformation will use the current working directory instead. This patch fixes the issue by opening a handle to the volumes, and using GetVolumeInformationByHandleW instead. Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1746667 Signed-off-by: Basil Salman Signed-off-by: Basil Salman *fix crash when guest_build_fsinfo() sets errp multiple times *make new error message more distinct from existing ones Signed-off-by: Michael Roth --- qga/commands-win32.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index aaa71f147b..15c9d7944b 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -958,11 +958,13 @@ static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp) { DWORD info_size; char mnt, *mnt_point; + wchar_t wfs_name[32]; char fs_name[32]; - char vol_info[MAX_PATH+1]; + wchar_t vol_info[MAX_PATH + 1]; size_t len; uint64_t i64FreeBytesToCaller, i64TotalBytes, i64FreeBytes; GuestFilesystemInfo *fs = NULL; + HANDLE hLocalDiskHandle = NULL; GetVolumePathNamesForVolumeName(guid, (LPCH)&mnt, 0, &info_size); if (GetLastError() != ERROR_MORE_DATA) { @@ -977,18 +979,27 @@ static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp) goto free; } + hLocalDiskHandle = CreateFile(guid, 0 , 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (INVALID_HANDLE_VALUE == hLocalDiskHandle) { + error_setg_win32(errp, GetLastError(), "failed to get handle for volume"); + goto free; + } + len = strlen(mnt_point); mnt_point[len] = '\\'; mnt_point[len+1] = 0; - if (!GetVolumeInformation(mnt_point, vol_info, sizeof(vol_info), NULL, NULL, - NULL, (LPSTR)&fs_name, sizeof(fs_name))) { + + if (!GetVolumeInformationByHandleW(hLocalDiskHandle, vol_info, + sizeof(vol_info), NULL, NULL, NULL, + (LPWSTR) & wfs_name, sizeof(wfs_name))) { if (GetLastError() != ERROR_NOT_READY) { error_setg_win32(errp, GetLastError(), "failed to get volume info"); } goto free; } - fs_name[sizeof(fs_name) - 1] = 0; fs = g_malloc(sizeof(*fs)); fs->name = g_strdup(guid); fs->has_total_bytes = false; @@ -1007,9 +1018,11 @@ static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp) fs->has_used_bytes = true; } } + wcstombs(fs_name, wfs_name, sizeof(wfs_name)); fs->type = g_strdup(fs_name); fs->disk = build_guest_disk_info(guid, errp); free: + CloseHandle(hLocalDiskHandle); g_free(mnt_point); return fs; } @@ -1027,8 +1040,12 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp) } do { - GuestFilesystemInfo *info = build_guest_fsinfo(guid, errp); - if (info == NULL) { + Error *local_err = NULL; + GuestFilesystemInfo *info = build_guest_fsinfo(guid, &local_err); + if (local_err) { + g_debug("failed to get filesystem info, ignoring error: %s", + error_get_pretty(local_err)); + error_free(local_err); continue; } new = g_malloc(sizeof(*ret)); From ba620541d0db7e3433babbd97c0413a371e6fb4a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 22 Jul 2020 06:40:25 +0200 Subject: [PATCH 2544/2595] qga/qapi-schema: Document -1 for invalid PCI address fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "guest-get-fsinfo" could also be used for non-PCI devices in the future. And the code in GuestPCIAddress() in qga/commands-win32.c seems to be using "-1" for fields that it can not determine already. Thus let's properly document "-1" as value for invalid PCI address fields. Reviewed-by: Daniel P. Berrangé Signed-off-by: Thomas Huth Signed-off-by: Michael Roth --- qga/qapi-schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 4be9aad48e..408a662ea5 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -846,7 +846,7 @@ ## # @GuestDiskAddress: # -# @pci-controller: controller's PCI address +# @pci-controller: controller's PCI address (fields are set to -1 if invalid) # @bus-type: bus type # @bus: bus id # @target: target id From a48aaf882b100b30111b5c7c75e1d9e83fe76cfd Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Mon, 27 Jul 2020 17:38:07 +0300 Subject: [PATCH 2545/2595] virtio-pci: fix wrong index in virtio_pci_queue_enabled We should use the index passed by the caller instead of the queue_sel when checking the enablement of a specific virtqueue. This is reported in https://bugzilla.redhat.com/show_bug.cgi?id=1702608 Fixes: f19bcdfedd53 ("virtio-pci: implement queue_enabled method") Signed-off-by: Yuri Benditovich Signed-off-by: Jason Wang --- hw/virtio/virtio-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 4ad3ad81a2..ccdf54e81c 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1113,7 +1113,7 @@ static bool virtio_pci_queue_enabled(DeviceState *d, int n) VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { - return proxy->vqs[vdev->queue_sel].enabled; + return proxy->vqs[n].enabled; } return virtio_queue_enabled_legacy(vdev, n); From c546ecf27da1114d0274abe600cc6bde6584e659 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 25 Jul 2020 08:13:17 +0800 Subject: [PATCH 2546/2595] virtio-net: check the existence of peer before accessing vDPA config We try to check whether a peer is VDPA in order to get config from there - with no peer, this leads to a NULL pointer dereference. Add a check before trying to access the peer type. No peer means not VDPA. Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend") Cc: Cindy Lu Tested-by: Cornelia Huck Reviewed-by: Cornelia Huck Signed-off-by: Jason Wang --- hw/net/virtio-net.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 4895af1cbe..a1fe9e9285 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -125,6 +125,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) { VirtIONet *n = VIRTIO_NET(vdev); struct virtio_net_config netcfg; + NetClientState *nc = qemu_get_queue(n->nic); int ret = 0; memset(&netcfg, 0 , sizeof(struct virtio_net_config)); @@ -142,13 +143,16 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) VIRTIO_NET_RSS_SUPPORTED_HASHES); memcpy(config, &netcfg, n->config_size); - NetClientState *nc = qemu_get_queue(n->nic); - if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { + /* + * Is this VDPA? No peer means not VDPA: there's no way to + * disconnect/reconnect a VDPA peer. + */ + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg, - n->config_size); - if (ret != -1) { - memcpy(config, &netcfg, n->config_size); - } + n->config_size); + if (ret != -1) { + memcpy(config, &netcfg, n->config_size); + } } } @@ -156,6 +160,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) { VirtIONet *n = VIRTIO_NET(vdev); struct virtio_net_config netcfg = {}; + NetClientState *nc = qemu_get_queue(n->nic); memcpy(&netcfg, config, n->config_size); @@ -166,11 +171,14 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); } - NetClientState *nc = qemu_get_queue(n->nic); - if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { - vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg, - 0, n->config_size, - VHOST_SET_CONFIG_TYPE_MASTER); + /* + * Is this VDPA? No peer means not VDPA: there's no way to + * disconnect/reconnect a VDPA peer. + */ + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { + vhost_net_set_config(get_vhost_net(nc->peer), + (uint8_t *)&netcfg, 0, n->config_size, + VHOST_SET_CONFIG_TYPE_MASTER); } } From 22dc8663d9fc7baa22100544c600b6285a63c7a3 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 22 Jul 2020 16:57:46 +0800 Subject: [PATCH 2547/2595] net: forbid the reentrant RX The memory API allows DMA into NIC's MMIO area. This means the NIC's RX routine must be reentrant. Instead of auditing all the NIC, we can simply detect the reentrancy and return early. The queue->delivering is set and cleared by qemu_net_queue_deliver() for other queue helpers to know whether the delivering in on going (NIC's receive is being called). We can check it and return early in qemu_net_queue_flush() to forbid reentrant RX. Signed-off-by: Jason Wang --- net/queue.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/queue.c b/net/queue.c index 0164727e39..19e32c80fd 100644 --- a/net/queue.c +++ b/net/queue.c @@ -250,6 +250,9 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from) bool qemu_net_queue_flush(NetQueue *queue) { + if (queue->delivering) + return false; + while (!QTAILQ_EMPTY(&queue->packets)) { NetPacket *packet; int ret; From 134b7dec6ec2d90616d7986afb3b3b7ca7a4c383 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 28 Jul 2020 14:08:04 +0200 Subject: [PATCH 2548/2595] block: Fix bdrv_aligned_p*v() for qiov_offset != 0 Since these functions take a @qiov_offset, they must always take it into account when working with @qiov. There are a couple of places where they do not, but they should. Fixes: 65cd4424b9df03bb5195351c33e04cbbecc0705c ("block/io: bdrv_aligned_preadv: use and support qiov_offset") Fixes: 28c4da28695bdbe04b336b2c9c463876cc3aaa6d ("block/io: bdrv_aligned_pwritev: use and support qiov_offset") Reported-by: Claudio Fontana Reported-by: Bruce Rogers Cc: qemu-stable@nongnu.org Signed-off-by: Max Reitz Message-Id: <20200728120806.265916-2-mreitz@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Tested-by: Claudio Fontana Tested-by: Bruce Rogers --- block/io.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/block/io.c b/block/io.c index b6564e34c5..ad3a51ed53 100644 --- a/block/io.c +++ b/block/io.c @@ -1524,12 +1524,13 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child, assert(num); ret = bdrv_driver_preadv(bs, offset + bytes - bytes_remaining, - num, qiov, bytes - bytes_remaining, 0); + num, qiov, + qiov_offset + bytes - bytes_remaining, 0); max_bytes -= num; } else { num = bytes_remaining; - ret = qemu_iovec_memset(qiov, bytes - bytes_remaining, 0, - bytes_remaining); + ret = qemu_iovec_memset(qiov, qiov_offset + bytes - bytes_remaining, + 0, bytes_remaining); } if (ret < 0) { goto out; @@ -2032,7 +2033,8 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, } ret = bdrv_driver_pwritev(bs, offset + bytes - bytes_remaining, - num, qiov, bytes - bytes_remaining, + num, qiov, + qiov_offset + bytes - bytes_remaining, local_flags); if (ret < 0) { break; From ae159450e161b3e1e2c5b815d19632abbbbcd1a1 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 28 Jul 2020 14:08:05 +0200 Subject: [PATCH 2549/2595] iotests/028: Add test for cross-base-EOF reads Signed-off-by: Max Reitz Message-Id: <20200728120806.265916-3-mreitz@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Tested-by: Vladimir Sementsov-Ogievskiy Tested-by: Claudio Fontana --- tests/qemu-iotests/028 | 19 +++++++++++++++++++ tests/qemu-iotests/028.out | 11 +++++++++++ 2 files changed, 30 insertions(+) diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028 index 5d043cef92..6dd3ae09a3 100755 --- a/tests/qemu-iotests/028 +++ b/tests/qemu-iotests/028 @@ -142,6 +142,25 @@ TEST_IMG="${TEST_IMG}.copy" io_zero readv $(( offset + 32 * 1024 )) 512 1024 32 _check_test_img +echo +echo '=== Reading across backing EOF in one operation ===' +echo + +# Use a cluster boundary as the base end here +base_size=$((3 * 1024 * 1024 * 1024)) + +TEST_IMG="$TEST_IMG.base" _make_test_img $base_size +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $image_size + +# Write 16 times 42 at the end of the base image +$QEMU_IO -c "write -P 42 $((base_size - 16)) 16" "$TEST_IMG.base" \ + | _filter_qemu_io + +# Read 32 bytes across the base EOF from the top; +# should be 16 times 0x2a, then 16 times 0x00 +$QEMU_IO -c "read -v $((base_size - 16)) 32" "$TEST_IMG" \ + | _filter_qemu_io + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out index 12f82c6a6c..5a68de5c46 100644 --- a/tests/qemu-iotests/028.out +++ b/tests/qemu-iotests/028.out @@ -730,4 +730,15 @@ read 512/512 bytes at offset 3221257728 read 512/512 bytes at offset 3221258752 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. + +=== Reading across backing EOF in one operation === + +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=3221225472 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294968832 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +wrote 16/16 bytes at offset 3221225456 +16 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +bffffff0: 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a ................ +c0000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +read 32/32 bytes at offset 3221225456 +32 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done From afac471b71da92d91cc56fb64c0719b8a4a2d96b Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 28 Jul 2020 15:11:34 +0200 Subject: [PATCH 2550/2595] iotests/197: Fix for non-qcow2 formats While 197 is very much a qcow2 test, and it looks like the partial cluster case at the end (introduced in b0ddcbbb36a66a6) is specifically a qcow2 case, the whole test scripts actually marks itself to work with generic formats (and generic protocols, even). Said partial cluster case happened to work with non-qcow2 formats as well (mostly by accident), but 1855536256 broke that, because it sets the compat option, which does not work for non-qcow2 formats. So go the whole way and force IMGFMT=qcow2 and IMGPROTO=file, as done in other places in this test. Fixes: 1855536256eb0a5708b04b85f744de69559ea323 ("iotests/197: Fix for compat=0.10") Reported-by: Thomas Huth Signed-off-by: Max Reitz Message-Id: <20200728131134.902519-1-mreitz@redhat.com> Reviewed-by: Eric Blake --- tests/qemu-iotests/197 | 8 +++++--- tests/qemu-iotests/197.out | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 index 121959a09c..a161c89816 100755 --- a/tests/qemu-iotests/197 +++ b/tests/qemu-iotests/197 @@ -114,9 +114,11 @@ echo # Force compat=1.1, because writing zeroes on a v2 image without a # backing file would just result in an unallocated cluster -_make_test_img -o compat=1.1 1024 -$QEMU_IO -f $IMGFMT -C -c 'read 0 1024' "$TEST_IMG" | _filter_qemu_io -$QEMU_IO -f $IMGFMT -c map "$TEST_IMG" +# (Also, note that this is really a pure qcow2 test.) +IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \ + _make_test_img --no-opts -o compat=1.1 1024 +$QEMU_IO -f qcow2 -C -c 'read 0 1024' "$TEST_WRAP" | _filter_qemu_io +$QEMU_IO -f qcow2 -c map "$TEST_WRAP" _check_test_img # success, all done diff --git a/tests/qemu-iotests/197.out b/tests/qemu-iotests/197.out index 7ca46be6e4..ad414c3b0e 100644 --- a/tests/qemu-iotests/197.out +++ b/tests/qemu-iotests/197.out @@ -26,7 +26,7 @@ Images are identical. === Partial final cluster === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1024 +Formatting 'TEST_DIR/t.wrap.IMGFMT', fmt=IMGFMT size=1024 read 1024/1024 bytes at offset 0 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) From 890cbccb089db9e646cc1baea3be9dc060e3917b Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 22 Jul 2020 16:22:31 -0500 Subject: [PATCH 2551/2595] nbd: Fix large trim/zero requests Although qemu as NBD client limits requests to <2G, the NBD protocol allows clients to send requests almost all the way up to 4G. But because our block layer is not yet 64-bit clean, we accidentally wrap such requests into a negative size, and fail with EIO instead of performing the intended operation. The bug is visible in modern systems with something as simple as: $ qemu-img create -f qcow2 /tmp/image.img 5G $ sudo qemu-nbd --connect=/dev/nbd0 /tmp/image.img $ sudo blkdiscard /dev/nbd0 or with user-space only: $ truncate --size=3G file $ qemu-nbd -f raw file $ nbdsh -u nbd://localhost:10809 -c 'h.trim(3*1024*1024*1024,0)' Although both blk_co_pdiscard and blk_pwrite_zeroes currently return 0 on success, this is also a good time to fix our code to a more robust paradigm that treats all non-negative values as success. Alas, our iotests do not currently make it easy to add external dependencies on blkdiscard or nbdsh, so we have to rely on manual testing for now. This patch can be reverted when we later improve the overall block layer to be 64-bit clean, but for now, a minimal fix was deemed less risky prior to release. CC: qemu-stable@nongnu.org Fixes: 1f4d6d18ed Fixes: 1c6c4bb7f0 Fixes: https://github.com/systemd/systemd/issues/16242 Signed-off-by: Eric Blake Message-Id: <20200722212231.535072-1-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy [eblake: rework success tests to use >=0] --- nbd/server.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index 4752a6c8bc..c5d71cff10 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -2378,8 +2378,17 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, if (request->flags & NBD_CMD_FLAG_FAST_ZERO) { flags |= BDRV_REQ_NO_FALLBACK; } - ret = blk_pwrite_zeroes(exp->blk, request->from + exp->dev_offset, - request->len, flags); + ret = 0; + /* FIXME simplify this when blk_pwrite_zeroes switches to 64-bit */ + while (ret >= 0 && request->len) { + int align = client->check_align ?: 1; + int len = MIN(request->len, QEMU_ALIGN_DOWN(BDRV_REQUEST_MAX_BYTES, + align)); + ret = blk_pwrite_zeroes(exp->blk, request->from + exp->dev_offset, + len, flags); + request->len -= len; + request->from += len; + } return nbd_send_generic_reply(client, request->handle, ret, "writing to file failed", errp); @@ -2393,9 +2402,18 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, "flush failed", errp); case NBD_CMD_TRIM: - ret = blk_co_pdiscard(exp->blk, request->from + exp->dev_offset, - request->len); - if (ret == 0 && request->flags & NBD_CMD_FLAG_FUA) { + ret = 0; + /* FIXME simplify this when blk_co_pdiscard switches to 64-bit */ + while (ret >= 0 && request->len) { + int align = client->check_align ?: 1; + int len = MIN(request->len, QEMU_ALIGN_DOWN(BDRV_REQUEST_MAX_BYTES, + align)); + ret = blk_co_pdiscard(exp->blk, request->from + exp->dev_offset, + len); + request->len -= len; + request->from += len; + } + if (ret >= 0 && request->flags & NBD_CMD_FLAG_FUA) { ret = blk_co_flush(exp->blk); } return nbd_send_generic_reply(client, request->handle, ret, From 297641d43ccf18274e18da841f69bdb256a60ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sun, 26 Jul 2020 19:30:23 +0400 Subject: [PATCH 2552/2595] test-char: abort on serial test error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are having issues debugging and bisecting this issue that happen mostly on patchew. Let's make it abort where it failed to gather some new informations. Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Marc-André Lureau --- tests/test-char.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-char.c b/tests/test-char.c index 614bdac2df..d35cc839bc 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -1200,7 +1200,7 @@ static void char_serial_test(void) /* test tty alias */ qemu_opt_set(opts, "backend", "tty", &error_abort); - chr = qemu_chr_new_from_opts(opts, NULL, NULL); + chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); g_assert_nonnull(chr); object_unparent(OBJECT(chr)); From 9c15f57891af7c2cb3baf2d66a1b1f3f87a665ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sun, 26 Jul 2020 19:41:00 +0400 Subject: [PATCH 2553/2595] slirp: update to latest stable-4.2 branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dr. David Alan Gilbert (1): ip_stripoptions use memmove Jindrich Novy (4): Fix possible infinite loops and use-after-free Use secure string copy to avoid overflow Be sure to initialize sockaddr structure Check lseek() for failure Marc-André Lureau (2): util: do not silently truncate Merge branch 'stable-4.2' into 'stable-4.2' Philippe Mathieu-Daudé (3): Fix win32 builds by using the SLIRP_PACKED definition Fix constness warnings Remove unnecessary break Ralf Haferkamp (2): Drop bogus IPv6 messages Fix MTU check Signed-off-by: Marc-André Lureau --- slirp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slirp b/slirp index 2faae0f778..ce94eba204 160000 --- a/slirp +++ b/slirp @@ -1 +1 @@ -Subproject commit 2faae0f778f818fadc873308f983289df697eb93 +Subproject commit ce94eba2042d52a0ba3d9e252ebce86715e94275 From a2b333c01880f56056d50c238834d62e32001e54 Mon Sep 17 00:00:00 2001 From: Nir Soffer Date: Tue, 28 Jul 2020 00:58:43 +0300 Subject: [PATCH 2554/2595] block: nbd: Fix convert qcow2 compressed to nbd When converting to qcow2 compressed format, the last step is a special zero length compressed write, ending in a call to bdrv_co_truncate(). This call always fails for the nbd driver since it does not implement bdrv_co_truncate(). For block devices, which have the same limits, the call succeeds since the file driver implements bdrv_co_truncate(). If the caller asked to truncate to the same or smaller size with exact=false, the truncate succeeds. Implement the same logic for nbd. Example failing without this change: In one shell start qemu-nbd: $ truncate -s 1g test.tar $ qemu-nbd --socket=/tmp/nbd.sock --persistent --format=raw --offset 1536 test.tar In another shell convert an image to qcow2 compressed via NBD: $ echo "disk data" > disk.raw $ truncate -s 1g disk.raw $ qemu-img convert -f raw -O qcow2 -c disk1.raw nbd+unix:///?socket=/tmp/nbd.sock; echo $? 1 qemu-img failed, but the conversion was successful: $ qemu-img info nbd+unix:///?socket=/tmp/nbd.sock image: nbd+unix://?socket=/tmp/nbd.sock file format: qcow2 virtual size: 1 GiB (1073741824 bytes) ... $ qemu-img check nbd+unix:///?socket=/tmp/nbd.sock No errors were found on the image. 1/16384 = 0.01% allocated, 100.00% fragmented, 100.00% compressed clusters Image end offset: 393216 $ qemu-img compare disk.raw nbd+unix:///?socket=/tmp/nbd.sock Images are identical. Fixes: https://bugzilla.redhat.com/1860627 Signed-off-by: Nir Soffer Message-Id: <20200727215846.395443-2-nsoffer@redhat.com> Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy [eblake: typo fixes] Signed-off-by: Eric Blake --- block/nbd.c | 30 ++++++++++++++++++++++++++++++ qemu-io-cmds.c | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/block/nbd.c b/block/nbd.c index 65a4f56924..8934bcb479 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1966,6 +1966,33 @@ static void nbd_close(BlockDriverState *bs) nbd_clear_bdrvstate(s); } +/* + * NBD cannot truncate, but if the caller asks to truncate to the same size, or + * to a smaller size with exact=false, there is no reason to fail the + * operation. + * + * Preallocation mode is ignored since it does not seems useful to fail when + * we never change anything. + */ +static int coroutine_fn nbd_co_truncate(BlockDriverState *bs, int64_t offset, + bool exact, PreallocMode prealloc, + BdrvRequestFlags flags, Error **errp) +{ + BDRVNBDState *s = bs->opaque; + + if (offset != s->info.size && exact) { + error_setg(errp, "Cannot resize NBD nodes"); + return -ENOTSUP; + } + + if (offset > s->info.size) { + error_setg(errp, "Cannot grow NBD nodes"); + return -EINVAL; + } + + return 0; +} + static int64_t nbd_getlength(BlockDriverState *bs) { BDRVNBDState *s = bs->opaque; @@ -2045,6 +2072,7 @@ static BlockDriver bdrv_nbd = { .bdrv_co_flush_to_os = nbd_co_flush, .bdrv_co_pdiscard = nbd_client_co_pdiscard, .bdrv_refresh_limits = nbd_refresh_limits, + .bdrv_co_truncate = nbd_co_truncate, .bdrv_getlength = nbd_getlength, .bdrv_detach_aio_context = nbd_client_detach_aio_context, .bdrv_attach_aio_context = nbd_client_attach_aio_context, @@ -2072,6 +2100,7 @@ static BlockDriver bdrv_nbd_tcp = { .bdrv_co_flush_to_os = nbd_co_flush, .bdrv_co_pdiscard = nbd_client_co_pdiscard, .bdrv_refresh_limits = nbd_refresh_limits, + .bdrv_co_truncate = nbd_co_truncate, .bdrv_getlength = nbd_getlength, .bdrv_detach_aio_context = nbd_client_detach_aio_context, .bdrv_attach_aio_context = nbd_client_attach_aio_context, @@ -2099,6 +2128,7 @@ static BlockDriver bdrv_nbd_unix = { .bdrv_co_flush_to_os = nbd_co_flush, .bdrv_co_pdiscard = nbd_client_co_pdiscard, .bdrv_refresh_limits = nbd_refresh_limits, + .bdrv_co_truncate = nbd_co_truncate, .bdrv_getlength = nbd_getlength, .bdrv_detach_aio_context = nbd_client_detach_aio_context, .bdrv_attach_aio_context = nbd_client_attach_aio_context, diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 851f07e8f8..baeae86d8c 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -1715,7 +1715,7 @@ static int truncate_f(BlockBackend *blk, int argc, char **argv) * exact=true. It is better to err on the "emit more errors" side * than to be overly permissive. */ - ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, 0, &local_err); + ret = blk_truncate(blk, offset, false, PREALLOC_MODE_OFF, 0, &local_err); if (ret < 0) { error_report_err(local_err); return ret; From b7719bcad2e92bab5aae3166fa9011f127e6ee49 Mon Sep 17 00:00:00 2001 From: Nir Soffer Date: Tue, 28 Jul 2020 00:58:44 +0300 Subject: [PATCH 2555/2595] iotests: Make qemu_nbd_popen() a contextmanager Instead of duplicating the code to wait until the server is ready and remember to terminate the server and wait for it, make it possible to use like this: with qemu_nbd_popen('-k', sock, image): # Access image via qemu-nbd socket... Only test 264 used this helper, but I had to modify the output since it did not consistently when starting and stopping qemu-nbd. Signed-off-by: Nir Soffer Message-Id: <20200727215846.395443-3-nsoffer@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Eric Blake --- tests/qemu-iotests/264 | 72 +++++++++++++---------------------- tests/qemu-iotests/264.out | 2 + tests/qemu-iotests/iotests.py | 28 +++++++++++++- 3 files changed, 54 insertions(+), 48 deletions(-) diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264 index 304a7443d7..666f164ed8 100755 --- a/tests/qemu-iotests/264 +++ b/tests/qemu-iotests/264 @@ -36,48 +36,32 @@ wait_step = 0.2 qemu_img_create('-f', iotests.imgfmt, disk_a, str(size)) qemu_img_create('-f', iotests.imgfmt, disk_b, str(size)) -srv = qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk_b) -# Wait for NBD server availability -t = 0 -ok = False -while t < wait_limit: - ok = qemu_io_silent_check('-f', 'raw', '-c', 'read 0 512', nbd_uri) - if ok: - break - time.sleep(wait_step) - t += wait_step +with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk_b): + vm = iotests.VM().add_drive(disk_a) + vm.launch() + vm.hmp_qemu_io('drive0', 'write 0 {}'.format(size)) -assert ok + vm.qmp_log('blockdev-add', filters=[iotests.filter_qmp_testfiles], + **{'node_name': 'backup0', + 'driver': 'raw', + 'file': {'driver': 'nbd', + 'server': {'type': 'unix', 'path': nbd_sock}, + 'reconnect-delay': 10}}) + vm.qmp_log('blockdev-backup', device='drive0', sync='full', target='backup0', + speed=(1 * 1024 * 1024)) -vm = iotests.VM().add_drive(disk_a) -vm.launch() -vm.hmp_qemu_io('drive0', 'write 0 {}'.format(size)) + # Wait for some progress + t = 0 + while t < wait_limit: + jobs = vm.qmp('query-block-jobs')['return'] + if jobs and jobs[0]['offset'] > 0: + break + time.sleep(wait_step) + t += wait_step -vm.qmp_log('blockdev-add', filters=[iotests.filter_qmp_testfiles], - **{'node_name': 'backup0', - 'driver': 'raw', - 'file': {'driver': 'nbd', - 'server': {'type': 'unix', 'path': nbd_sock}, - 'reconnect-delay': 10}}) -vm.qmp_log('blockdev-backup', device='drive0', sync='full', target='backup0', - speed=(1 * 1024 * 1024)) - -# Wait for some progress -t = 0 -while t < wait_limit: - jobs = vm.qmp('query-block-jobs')['return'] if jobs and jobs[0]['offset'] > 0: - break - time.sleep(wait_step) - t += wait_step - -if jobs and jobs[0]['offset'] > 0: - log('Backup job is started') - -log('Kill NBD server') -srv.kill() -srv.wait() + log('Backup job is started') jobs = vm.qmp('query-block-jobs')['return'] if jobs and jobs[0]['offset'] < jobs[0]['len']: @@ -88,12 +72,8 @@ vm.qmp_log('block-job-set-speed', device='drive0', speed=0) # Emulate server down time for 1 second time.sleep(1) -log('Start NBD server') -srv = qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk_b) - -e = vm.event_wait('BLOCK_JOB_COMPLETED') -log('Backup completed: {}'.format(e['data']['offset'])) - -vm.qmp_log('blockdev-del', node_name='backup0') -srv.kill() -vm.shutdown() +with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk_b): + e = vm.event_wait('BLOCK_JOB_COMPLETED') + log('Backup completed: {}'.format(e['data']['offset'])) + vm.qmp_log('blockdev-del', node_name='backup0') + vm.shutdown() diff --git a/tests/qemu-iotests/264.out b/tests/qemu-iotests/264.out index 3000944b09..c45b1e81ef 100644 --- a/tests/qemu-iotests/264.out +++ b/tests/qemu-iotests/264.out @@ -1,3 +1,4 @@ +Start NBD server {"execute": "blockdev-add", "arguments": {"driver": "raw", "file": {"driver": "nbd", "reconnect-delay": 10, "server": {"path": "TEST_DIR/PID-nbd-sock", "type": "unix"}}, "node-name": "backup0"}} {"return": {}} {"execute": "blockdev-backup", "arguments": {"device": "drive0", "speed": 1048576, "sync": "full", "target": "backup0"}} @@ -11,3 +12,4 @@ Start NBD server Backup completed: 5242880 {"execute": "blockdev-del", "arguments": {"node-name": "backup0"}} {"return": {}} +Kill NBD server diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 3590ed78a0..8f79668435 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -28,10 +28,13 @@ import signal import struct import subprocess import sys +import time from typing import (Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, TypeVar) import unittest +from contextlib import contextmanager + # pylint: disable=import-error, wrong-import-position sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu import qtest @@ -270,9 +273,30 @@ def qemu_nbd_early_pipe(*args): return subp.returncode, output if subp.returncode else '' +@contextmanager def qemu_nbd_popen(*args): - '''Run qemu-nbd in daemon mode and return the parent's exit code''' - return subprocess.Popen(qemu_nbd_args + ['--persistent'] + list(args)) + '''Context manager running qemu-nbd within the context''' + pid_file = file_path("pid") + + cmd = list(qemu_nbd_args) + cmd.extend(('--persistent', '--pid-file', pid_file)) + cmd.extend(args) + + log('Start NBD server') + p = subprocess.Popen(cmd) + try: + while not os.path.exists(pid_file): + if p.poll() is not None: + raise RuntimeError( + "qemu-nbd terminated with exit code {}: {}" + .format(p.returncode, ' '.join(cmd))) + + time.sleep(0.01) + yield + finally: + log('Kill NBD server') + p.kill() + p.wait() def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt): '''Return True if two image files are identical''' From 4b914b01cdb95fe5722cb70826db7f0a262e8d2a Mon Sep 17 00:00:00 2001 From: Nir Soffer Date: Tue, 28 Jul 2020 00:58:45 +0300 Subject: [PATCH 2556/2595] iotests: Add more qemu_img helpers Add 2 helpers for measuring and checking images: - qemu_img_measure() - qemu_img_check() Both use --output-json and parse the returned json to make easy to use in other tests. I'm going to use them in a new test, and I hope they will be useful in may other tests. Signed-off-by: Nir Soffer Message-Id: <20200727215846.395443-4-nsoffer@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Eric Blake --- tests/qemu-iotests/iotests.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 8f79668435..717b5b652c 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -141,6 +141,12 @@ def qemu_img_create(*args): return qemu_img(*args) +def qemu_img_measure(*args): + return json.loads(qemu_img_pipe("measure", "--output", "json", *args)) + +def qemu_img_check(*args): + return json.loads(qemu_img_pipe("check", "--output", "json", *args)) + def qemu_img_verbose(*args): '''Run qemu-img without suppressing its output and return the exit code''' exitcode = subprocess.call(qemu_img_args + list(args)) From 03a970bb6ffe17a3ae77d54d4127330cf9a73587 Mon Sep 17 00:00:00 2001 From: Nir Soffer Date: Tue, 28 Jul 2020 00:58:46 +0300 Subject: [PATCH 2557/2595] iotests: Test convert to qcow2 compressed to NBD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add test for "qemu-img convert -O qcow2 -c" to NBD target. The tests     create a OVA file and write compressed qcow2 disk content directly into the OVA file via qemu-nbd. Signed-off-by: Nir Soffer Message-Id: <20200727215846.395443-5-nsoffer@redhat.com> Tested-by: Eric Blake Reviewed-by: Eric Blake Signed-off-by: Eric Blake --- tests/qemu-iotests/302 | 127 +++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/302.out | 31 +++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 159 insertions(+) create mode 100755 tests/qemu-iotests/302 create mode 100644 tests/qemu-iotests/302.out diff --git a/tests/qemu-iotests/302 b/tests/qemu-iotests/302 new file mode 100755 index 0000000000..a8506bda15 --- /dev/null +++ b/tests/qemu-iotests/302 @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +# +# Tests converting qcow2 compressed to NBD +# +# Copyright (c) 2020 Nir Soffer +# +# 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 . +# +# owner=nirsof@gmail.com + +import io +import tarfile + +import iotests + +from iotests import ( + file_path, + qemu_img, + qemu_img_check, + qemu_img_create, + qemu_img_log, + qemu_img_measure, + qemu_io, + qemu_nbd_popen, +) + +iotests.script_initialize(supported_fmts=["qcow2"]) + +# Create source disk. Using qcow2 to enable strict comparing later, and +# avoid issues with random filesystem on CI environment. +src_disk = file_path("disk.qcow2") +qemu_img_create("-f", iotests.imgfmt, src_disk, "1g") +qemu_io("-f", iotests.imgfmt, "-c", "write 1m 64k", src_disk) + +# The use case is writing qcow2 image directly into an ova file, which +# is a tar file with specific layout. This is tricky since we don't know the +# size of the image before compressing, so we have to do: +# 1. Add an ovf file. +# 2. Find the offset of the next member data. +# 3. Make room for image data, allocating for the worst case. +# 4. Write compressed image data into the tar. +# 5. Add a tar entry with the actual image size. +# 6. Shrink the tar to the actual size, aligned to 512 bytes. + +tar_file = file_path("test.ova") + +with tarfile.open(tar_file, "w") as tar: + + # 1. Add an ovf file. + + ovf_data = b"" + ovf = tarfile.TarInfo("vm.ovf") + ovf.size = len(ovf_data) + tar.addfile(ovf, io.BytesIO(ovf_data)) + + # 2. Find the offset of the next member data. + + offset = tar.fileobj.tell() + 512 + + # 3. Make room for image data, allocating for the worst case. + + measure = qemu_img_measure("-O", "qcow2", src_disk) + tar.fileobj.truncate(offset + measure["required"]) + + # 4. Write compressed image data into the tar. + + nbd_sock = file_path("nbd-sock", base_dir=iotests.sock_dir) + nbd_uri = "nbd+unix:///exp?socket=" + nbd_sock + + # Use raw format to allow creating qcow2 directly into tar file. + with qemu_nbd_popen( + "--socket", nbd_sock, + "--export-name", "exp", + "--format", "raw", + "--offset", str(offset), + tar_file): + + iotests.log("=== Target image info ===") + qemu_img_log("info", nbd_uri) + + qemu_img( + "convert", + "-f", iotests.imgfmt, + "-O", "qcow2", + "-c", + src_disk, + nbd_uri) + + iotests.log("=== Converted image info ===") + qemu_img_log("info", nbd_uri) + + iotests.log("=== Converted image check ===") + qemu_img_log("check", nbd_uri) + + iotests.log("=== Comparing to source disk ===") + qemu_img_log("compare", src_disk, nbd_uri) + + actual_size = qemu_img_check(nbd_uri)["image-end-offset"] + + # 5. Add a tar entry with the actual image size. + + disk = tarfile.TarInfo("disk") + disk.size = actual_size + tar.addfile(disk) + + # 6. Shrink the tar to the actual size, aligned to 512 bytes. + + tar_size = offset + (disk.size + 511) & ~511 + tar.fileobj.seek(tar_size) + tar.fileobj.truncate(tar_size) + +with tarfile.open(tar_file) as tar: + members = [{"name": m.name, "size": m.size, "offset": m.offset_data} + for m in tar] + iotests.log("=== OVA file contents ===") + iotests.log(members) diff --git a/tests/qemu-iotests/302.out b/tests/qemu-iotests/302.out new file mode 100644 index 0000000000..e37d3a1030 --- /dev/null +++ b/tests/qemu-iotests/302.out @@ -0,0 +1,31 @@ +Start NBD server +=== Target image info === +image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock +file format: raw +virtual size: 448 KiB (458752 bytes) +disk size: unavailable + +=== Converted image info === +image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock +file format: qcow2 +virtual size: 1 GiB (1073741824 bytes) +disk size: unavailable +cluster_size: 65536 +Format specific information: + compat: 1.1 + compression type: zlib + lazy refcounts: false + refcount bits: 16 + corrupt: false + +=== Converted image check === +No errors were found on the image. +1/16384 = 0.01% allocated, 100.00% fragmented, 100.00% compressed clusters +Image end offset: 393216 + +=== Comparing to source disk === +Images are identical. + +Kill NBD server +=== OVA file contents === +[{"name": "vm.ovf", "offset": 512, "size": 6}, {"name": "disk", "offset": 1536, "size": 393216}] diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 1d0252e1f0..1e1cb27bc8 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -308,3 +308,4 @@ 297 meta 299 auto quick 301 backing quick +302 quick From fa35591b9cb9a7fd0af2d8c2d8848abba30d3c69 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 21:47:47 +0300 Subject: [PATCH 2558/2595] block/nbd: split nbd_establish_connection out of nbd_client_connect We are going to implement non-blocking version of nbd_establish_connection, which for a while will be used only for nbd_reconnect_attempt, not for nbd_open, so we need to call it separately. Refactor nbd_reconnect_attempt in a way which makes next commit simpler. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200727184751.15704-2-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake Signed-off-by: Eric Blake --- block/nbd.c | 60 +++++++++++++++++++++++++++------------------- block/trace-events | 4 ++-- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index 8934bcb479..3558c173e3 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -93,7 +93,10 @@ typedef struct BDRVNBDState { char *x_dirty_bitmap; } BDRVNBDState; -static int nbd_client_connect(BlockDriverState *bs, Error **errp); +static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr, + Error **errp); +static int nbd_client_handshake(BlockDriverState *bs, QIOChannelSocket *sioc, + Error **errp); static void nbd_clear_bdrvstate(BDRVNBDState *s) { @@ -241,7 +244,9 @@ static bool nbd_client_connecting_wait(BDRVNBDState *s) static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s) { + int ret; Error *local_err = NULL; + QIOChannelSocket *sioc; if (!nbd_client_connecting(s)) { return; @@ -280,19 +285,25 @@ static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s) s->ioc = NULL; } - s->connect_status = nbd_client_connect(s->bs, &local_err); + sioc = nbd_establish_connection(s->saddr, &local_err); + if (!sioc) { + ret = -ECONNREFUSED; + goto out; + } + + ret = nbd_client_handshake(s->bs, sioc, &local_err); + +out: + s->connect_status = ret; error_free(s->connect_err); s->connect_err = NULL; error_propagate(&s->connect_err, local_err); - if (s->connect_status < 0) { - /* failed attempt */ - return; + if (ret >= 0) { + /* successfully connected */ + s->state = NBD_CLIENT_CONNECTED; + qemu_co_queue_restart_all(&s->free_sema); } - - /* successfully connected */ - s->state = NBD_CLIENT_CONNECTED; - qemu_co_queue_restart_all(&s->free_sema); } static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s) @@ -1425,24 +1436,15 @@ static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr, return sioc; } -static int nbd_client_connect(BlockDriverState *bs, Error **errp) +/* nbd_client_handshake takes ownership on sioc. On failure it is unref'ed. */ +static int nbd_client_handshake(BlockDriverState *bs, QIOChannelSocket *sioc, + Error **errp) { BDRVNBDState *s = (BDRVNBDState *)bs->opaque; AioContext *aio_context = bdrv_get_aio_context(bs); int ret; - /* - * establish TCP connection, return error if it fails - * TODO: Configurable retry-until-timeout behaviour. - */ - QIOChannelSocket *sioc = nbd_establish_connection(s->saddr, errp); - - if (!sioc) { - return -ECONNREFUSED; - } - - /* NBD handshake */ - trace_nbd_client_connect(s->export); + trace_nbd_client_handshake(s->export); qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL); qio_channel_attach_aio_context(QIO_CHANNEL(sioc), aio_context); @@ -1489,7 +1491,7 @@ static int nbd_client_connect(BlockDriverState *bs, Error **errp) object_ref(OBJECT(s->ioc)); } - trace_nbd_client_connect_success(s->export); + trace_nbd_client_handshake_success(s->export); return 0; @@ -1894,6 +1896,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, { int ret; BDRVNBDState *s = (BDRVNBDState *)bs->opaque; + QIOChannelSocket *sioc; ret = nbd_process_options(bs, options, errp); if (ret < 0) { @@ -1904,7 +1907,16 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, qemu_co_mutex_init(&s->send_mutex); qemu_co_queue_init(&s->free_sema); - ret = nbd_client_connect(bs, errp); + /* + * establish TCP connection, return error if it fails + * TODO: Configurable retry-until-timeout behaviour. + */ + sioc = nbd_establish_connection(s->saddr, errp); + if (!sioc) { + return -ECONNREFUSED; + } + + ret = nbd_client_handshake(bs, sioc, errp); if (ret < 0) { nbd_clear_bdrvstate(s); return ret; diff --git a/block/trace-events b/block/trace-events index d3533ca896..9158335061 100644 --- a/block/trace-events +++ b/block/trace-events @@ -168,8 +168,8 @@ nbd_parse_blockstatus_compliance(const char *err) "ignoring extra data from non- nbd_structured_read_compliance(const char *type) "server sent non-compliant unaligned read %s chunk" nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s" nbd_co_request_fail(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s" -nbd_client_connect(const char *export_name) "export '%s'" -nbd_client_connect_success(const char *export_name) "export '%s'" +nbd_client_handshake(const char *export_name) "export '%s'" +nbd_client_handshake_success(const char *export_name) "export '%s'" # ssh.c ssh_restart_coroutine(void *co) "co=%p" From dd1ec1a4afe190e030edfa052d95c9e6e065438c Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 21:47:48 +0300 Subject: [PATCH 2559/2595] block/nbd: allow drain during reconnect attempt It should be safe to reenter qio_channel_yield() on io/channel read/write path, so it's safe to reduce in_flight and allow attaching new aio context. And no problem to allow drain itself: connection attempt is not a guest request. Moreover, if remote server is down, we can hang in negotiation, blocking drain section and provoking a dead lock. How to reproduce the dead lock: 1. Create nbd-fault-injector.conf with the following contents: [inject-error "mega1"] event=data io=readwrite when=before 2. In one terminal run nbd-fault-injector in a loop, like this: n=1; while true; do echo $n; ((n++)); ./nbd-fault-injector.py 127.0.0.1:10000 nbd-fault-injector.conf; done 3. In another terminal run qemu-io in a loop, like this: n=1; while true; do echo $n; ((n++)); ./qemu-io -c 'read 0 512' nbd://127.0.0.1:10000; done After some time, qemu-io will hang trying to drain, for example, like this: #3 aio_poll (ctx=0x55f006bdd890, blocking=true) at util/aio-posix.c:600 #4 bdrv_do_drained_begin (bs=0x55f006bea710, recursive=false, parent=0x0, ignore_bds_parents=false, poll=true) at block/io.c:427 #5 bdrv_drained_begin (bs=0x55f006bea710) at block/io.c:433 #6 blk_drain (blk=0x55f006befc80) at block/block-backend.c:1710 #7 blk_unref (blk=0x55f006befc80) at block/block-backend.c:498 #8 bdrv_open_inherit (filename=0x7fffba1563bc "nbd+tcp://127.0.0.1:10000", reference=0x0, options=0x55f006be86d0, flags=24578, parent=0x0, child_class=0x0, child_role=0, errp=0x7fffba154620) at block.c:3491 #9 bdrv_open (filename=0x7fffba1563bc "nbd+tcp://127.0.0.1:10000", reference=0x0, options=0x0, flags=16386, errp=0x7fffba154620) at block.c:3513 #10 blk_new_open (filename=0x7fffba1563bc "nbd+tcp://127.0.0.1:10000", reference=0x0, options=0x0, flags=16386, errp=0x7fffba154620) at block/block-backend.c:421 And connection_co stack like this: #0 qemu_coroutine_switch (from_=0x55f006bf2650, to_=0x7fe96e07d918, action=COROUTINE_YIELD) at util/coroutine-ucontext.c:302 #1 qemu_coroutine_yield () at util/qemu-coroutine.c:193 #2 qio_channel_yield (ioc=0x55f006bb3c20, condition=G_IO_IN) at io/channel.c:472 #3 qio_channel_readv_all_eof (ioc=0x55f006bb3c20, iov=0x7fe96d729bf0, niov=1, errp=0x7fe96d729eb0) at io/channel.c:110 #4 qio_channel_readv_all (ioc=0x55f006bb3c20, iov=0x7fe96d729bf0, niov=1, errp=0x7fe96d729eb0) at io/channel.c:143 #5 qio_channel_read_all (ioc=0x55f006bb3c20, buf=0x7fe96d729d28 "\300.\366\004\360U", buflen=8, errp=0x7fe96d729eb0) at io/channel.c:247 #6 nbd_read (ioc=0x55f006bb3c20, buffer=0x7fe96d729d28, size=8, desc=0x55f004f69644 "initial magic", errp=0x7fe96d729eb0) at /work/src/qemu/master/include/block/nbd.h:365 #7 nbd_read64 (ioc=0x55f006bb3c20, val=0x7fe96d729d28, desc=0x55f004f69644 "initial magic", errp=0x7fe96d729eb0) at /work/src/qemu/master/include/block/nbd.h:391 #8 nbd_start_negotiate (aio_context=0x55f006bdd890, ioc=0x55f006bb3c20, tlscreds=0x0, hostname=0x0, outioc=0x55f006bf19f8, structured_reply=true, zeroes=0x7fe96d729dca, errp=0x7fe96d729eb0) at nbd/client.c:904 #9 nbd_receive_negotiate (aio_context=0x55f006bdd890, ioc=0x55f006bb3c20, tlscreds=0x0, hostname=0x0, outioc=0x55f006bf19f8, info=0x55f006bf1a00, errp=0x7fe96d729eb0) at nbd/client.c:1032 #10 nbd_client_connect (bs=0x55f006bea710, errp=0x7fe96d729eb0) at block/nbd.c:1460 #11 nbd_reconnect_attempt (s=0x55f006bf19f0) at block/nbd.c:287 #12 nbd_co_reconnect_loop (s=0x55f006bf19f0) at block/nbd.c:309 #13 nbd_connection_entry (opaque=0x55f006bf19f0) at block/nbd.c:360 #14 coroutine_trampoline (i0=113190480, i1=22000) at util/coroutine-ucontext.c:173 Note, that the hang may be triggered by another bug, so the whole case is fixed only together with commit "block/nbd: on shutdown terminate connection attempt". Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200727184751.15704-3-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake Signed-off-by: Eric Blake --- block/nbd.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/block/nbd.c b/block/nbd.c index 3558c173e3..ee9ab7512b 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -291,8 +291,22 @@ static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s) goto out; } + bdrv_dec_in_flight(s->bs); + ret = nbd_client_handshake(s->bs, sioc, &local_err); + if (s->drained) { + s->wait_drained_end = true; + while (s->drained) { + /* + * We may be entered once from nbd_client_attach_aio_context_bh + * and then from nbd_client_co_drain_end. So here is a loop. + */ + qemu_coroutine_yield(); + } + } + bdrv_inc_in_flight(s->bs); + out: s->connect_status = ret; error_free(s->connect_err); From fbeb3e63b34a1af4a968031de1c82e5edf20bf6c Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 21:47:49 +0300 Subject: [PATCH 2560/2595] block/nbd: on shutdown terminate connection attempt On shutdown nbd driver may be in a connecting state. We should shutdown it as well, otherwise we may hang in nbd_teardown_connection, waiting for conneciton_co to finish in BDRV_POLL_WHILE(bs, s->connection_co) loop if remote server is down. How to reproduce the dead lock: 1. Create nbd-fault-injector.conf with the following contents: [inject-error "mega1"] event=data io=readwrite when=before 2. In one terminal run nbd-fault-injector in a loop, like this: n=1; while true; do echo $n; ((n++)); ./nbd-fault-injector.py 127.0.0.1:10000 nbd-fault-injector.conf; done 3. In another terminal run qemu-io in a loop, like this: n=1; while true; do echo $n; ((n++)); ./qemu-io -c 'read 0 512' nbd://127.0.0.1:10000; done After some time, qemu-io will hang. Note, that this hang may be triggered by another bug, so the whole case is fixed only together with commit "block/nbd: allow drain during reconnect attempt". Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200727184751.15704-4-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- block/nbd.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index ee9ab7512b..620c97be6b 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -209,11 +209,15 @@ static void nbd_teardown_connection(BlockDriverState *bs) { BDRVNBDState *s = (BDRVNBDState *)bs->opaque; - if (s->state == NBD_CLIENT_CONNECTED) { + if (s->ioc) { /* finish any pending coroutines */ - assert(s->ioc); qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); + } else if (s->sioc) { + /* abort negotiation */ + qio_channel_shutdown(QIO_CHANNEL(s->sioc), QIO_CHANNEL_SHUTDOWN_BOTH, + NULL); } + s->state = NBD_CLIENT_QUIT; if (s->connection_co) { if (s->connection_co_sleep_ns_state) { @@ -1459,6 +1463,9 @@ static int nbd_client_handshake(BlockDriverState *bs, QIOChannelSocket *sioc, int ret; trace_nbd_client_handshake(s->export); + + s->sioc = sioc; + qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL); qio_channel_attach_aio_context(QIO_CHANNEL(sioc), aio_context); @@ -1473,6 +1480,7 @@ static int nbd_client_handshake(BlockDriverState *bs, QIOChannelSocket *sioc, g_free(s->info.name); if (ret < 0) { object_unref(OBJECT(sioc)); + s->sioc = NULL; return ret; } if (s->x_dirty_bitmap && !s->info.base_allocation) { @@ -1498,8 +1506,6 @@ static int nbd_client_handshake(BlockDriverState *bs, QIOChannelSocket *sioc, } } - s->sioc = sioc; - if (!s->ioc) { s->ioc = QIO_CHANNEL(sioc); object_ref(OBJECT(s->ioc)); @@ -1520,6 +1526,7 @@ static int nbd_client_handshake(BlockDriverState *bs, QIOChannelSocket *sioc, nbd_send_request(s->ioc ?: QIO_CHANNEL(sioc), &request); object_unref(OBJECT(sioc)); + s->sioc = NULL; return ret; } From 12c75e20a269ac917f4a76936d7142264e522233 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 27 Jul 2020 21:47:50 +0300 Subject: [PATCH 2561/2595] block/nbd: nbd_co_reconnect_loop(): don't sleep if drained We try to go to wakeable sleep, so that, if drain begins it will break the sleep. But what if nbd_client_co_drain_begin() already called and s->drained is already true? We'll go to sleep, and drain will have to wait for the whole timeout. Let's improve it. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200727184751.15704-5-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- block/nbd.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index 620c97be6b..7bb881fef4 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -341,8 +341,6 @@ static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s) qemu_co_queue_restart_all(&s->free_sema); } - qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, timeout, - &s->connection_co_sleep_ns_state); if (s->drained) { bdrv_dec_in_flight(s->bs); s->wait_drained_end = true; @@ -354,9 +352,12 @@ static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s) qemu_coroutine_yield(); } bdrv_inc_in_flight(s->bs); - } - if (timeout < max_timeout) { - timeout *= 2; + } else { + qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, timeout, + &s->connection_co_sleep_ns_state); + if (timeout < max_timeout) { + timeout *= 2; + } } nbd_reconnect_attempt(s); From 5772f2b1fc5d00e7e04e01fa28e9081d6550440a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 28 Jul 2020 21:51:03 +0100 Subject: [PATCH 2562/2595] Update version for v5.1.0-rc2 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 023d5c9cfb..388c02aef2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.91 +5.0.92 From 1b7157be3a8c4300fc8044d40f4b2e64a152a1b4 Mon Sep 17 00:00:00 2001 From: Josh DuBois Date: Thu, 23 Jul 2020 00:33:59 -0500 Subject: [PATCH 2563/2595] trace/simple: Allow enabling simple traces from command line The simple trace backend is enabled / disabled with a call to st_set_trace_file_enabled(). When initializing tracing from the command-line, this must be enabled on startup. (Prior to db25d56c014aa1a9, command-line initialization of simple trace worked because every call to st_set_trace_file enabled tracing.) Fixes: db25d56c014aa1a96319c663e0a60346a223b31e Signed-off-by: Josh DuBois Message-id: 20200723053359.256928-1-josh@joshdubois.com Signed-off-by: Stefan Hajnoczi --- trace/control.c | 1 + 1 file changed, 1 insertion(+) diff --git a/trace/control.c b/trace/control.c index 2ffe000818..6558b5c906 100644 --- a/trace/control.c +++ b/trace/control.c @@ -225,6 +225,7 @@ void trace_init_file(const char *file) { #ifdef CONFIG_TRACE_SIMPLE st_set_trace_file(file); + st_set_trace_file_enabled(true); #elif defined CONFIG_TRACE_LOG /* * If both the simple and the log backends are enabled, "--trace file" From 148d25e0f6ad1dc3bd6aace092d65262d4217ec6 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 30 Jul 2020 15:01:56 +0200 Subject: [PATCH 2564/2595] s390x/s390-virtio-ccw: fix off-by-one in loadparm getter As pointed out by Peter, g_memdup(ms->loadparm, sizeof(ms->loadparm) + 1) reads one past of the end of ms->loadparm, so g_memdup() can not be used here. Let's use g_strndup instead! Fixes: d6645483285f ("s390x/s390-virtio-ccw: fix loadparm property getter") Fixes: Coverity CID 1431058 Reported-by: Peter Maydell Signed-off-by: Halil Pasic Reviewed-by: David Hildenbrand Reviewed-by: Peter Maydell Message-Id: <20200730130156.35063-1-pasic@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 403d30e13b..e72c61d2ea 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -701,12 +701,9 @@ bool hpage_1m_allowed(void) static char *machine_get_loadparm(Object *obj, Error **errp) { S390CcwMachineState *ms = S390_CCW_MACHINE(obj); - char *loadparm_str; /* make a NUL-terminated string */ - loadparm_str = g_memdup(ms->loadparm, sizeof(ms->loadparm) + 1); - loadparm_str[sizeof(ms->loadparm)] = 0; - return loadparm_str; + return g_strndup((char *) ms->loadparm, sizeof(ms->loadparm)); } static void machine_set_loadparm(Object *obj, const char *val, Error **errp) From 000822441e34916991f7c03217dc24f38be49e50 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 29 Jul 2020 16:39:26 +0100 Subject: [PATCH 2565/2595] tracetool: carefully define SDT_USE_VARIADIC The dtrace backend defines SDT_USE_VARIADIC as a workaround for a conflict with a LTTng UST header file, which requires SDT_USE_VARIADIC to be defined. LTTng UST breaks if included after generated dtrace headers because SDT_USE_VARIADIC will already be defined: #ifdef LTTNG_UST_HAVE_SDT_INTEGRATION #define SDT_USE_VARIADIC <-- error, it's already defined #include Be more careful when defining SDT_USE_VARIADIC. This fixes the build when both the dtrace and ust tracers are enabled at the same time. Fixes: 27e08bab94f7c6ebe0b75938c98c394c969e3fd8 ("tracetool: work around ust include conflict") Signed-off-by: Stefan Hajnoczi Message-id: 20200729153926.127083-1-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/backend/dtrace.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py index b7fe4c1b50..fc0c8fc52f 100644 --- a/scripts/tracetool/backend/dtrace.py +++ b/scripts/tracetool/backend/dtrace.py @@ -44,11 +44,15 @@ def generate_h_begin(events, group): # require SDT_USE_VARIADIC to be defined. If dtrace includes # first without defining SDT_USE_VARIADIC then ust breaks because the # STAP_PROBEV() macro is not defined. + out('#ifndef SDT_USE_VARIADIC') out('#define SDT_USE_VARIADIC 1') + out('#endif') out('#include "%s"' % header, '') + out('#undef SDT_USE_VARIADIC') + # SystemTap defines __ENABLED() but other DTrace # implementations might not. for e in events: From 1f42e246995a99890f6af4e42329f184ee14b0e7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 3 Aug 2020 07:00:58 +0200 Subject: [PATCH 2566/2595] seabios: update to master snapshot seabios master branch got a few bugfixes, so update to a newer snapshot to pick them up for 5.1-rc3. shortlog ======== Kevin O'Connor (2): vgabios: Fix preserve memory flag in handle_1000 ldnoexec: Add script to remove ET_EXEC flag from intermediate build objects Paul Menzel (1): nvme: Increase `nvme_cmd_readwrite()` message log level from 3 to 5 Stefan Reiter (1): virtio-scsi: fix boot prio detection by using correct lun Signed-off-by: Gerd Hoffmann --- pc-bios/bios-256k.bin | Bin 262144 -> 262144 bytes pc-bios/bios.bin | Bin 131072 -> 131072 bytes pc-bios/vgabios-ati.bin | Bin 39424 -> 39424 bytes pc-bios/vgabios-bochs-display.bin | Bin 28672 -> 28672 bytes pc-bios/vgabios-cirrus.bin | Bin 38912 -> 38912 bytes pc-bios/vgabios-qxl.bin | Bin 39424 -> 39424 bytes pc-bios/vgabios-ramfb.bin | Bin 28672 -> 28672 bytes pc-bios/vgabios-stdvga.bin | Bin 39424 -> 39424 bytes pc-bios/vgabios-virtio.bin | Bin 39424 -> 39424 bytes pc-bios/vgabios-vmware.bin | Bin 39424 -> 39424 bytes pc-bios/vgabios.bin | Bin 38912 -> 38912 bytes roms/seabios | 2 +- 12 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin index 25b69cafba592be74bcb122570ac3cae5fd3dff3..8fd42903cdb950228613e06c228b7f8004a1381a 100644 GIT binary patch delta 8409 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 delta 8497 zcmaJ`dtA-;|9`*U-ASi%q9}^PH+NB%RYa-WLz??t%oyWDQYzYN$e(YR!i)AKVm0a5xWTd4D4u4Y;9X&gMx_p_8>M5mJ3P#A1Lgz+IsI02<4}2N3%jm@tr-cRaCpAQhMa z%m>~C%7Gt&_l6KV19&G8`vMr2NNhBa3QPt(lZctcjXtz0CwwTeNWeLTm_Lv)m)J(& z1aJYU1{wh8G>ik?fmk2~m=9zDg}^?bVIJnqCuV$|*!#di-~?a+&H!aV1<-o|v2Y-A z0d-~3=)?j`06mZefIk5*C~XF?3-}zk4>X4obAYEnG?Y0Vco(2n#1er9z!^#nYE3z8COUh8 z0%*8@Ah9vP>%b{scn}zGN9WKVU4d6xayt1r7tB z0N(*m0N>t_7BC8U3n=QHgNf*T0u!P>*aR31i~?$bwtaD9;4u&%4vhn|faSni-~-@v z1hF50HZZ%MKngGu&;wSW?JLAy19kxxKpRQy8=x7?Gb{%`?*UJuh!saeJh0D6zy@G9 z;0_b*1*`^k04^}suD~lmG%yZGiX~*V=Q-tXQfNwNiTF+ZoQ8rm95aeB$ZXV6gdW2 zrHfwqES2_f3RdP%q%IzGS=l;^R^lARa}FJGX)b3j?YP1{szsr4{&n)=K2&$PcLTKi6iO*3^mV8=L=$OF-T1^H`o@e^q^sOaQ1f)|J z@DrC#-}~6d!<(@2dCX{KO%{EZQxu&MiX zaDN7YRXXdQ3HJ;d#+^@zlnjccC1QI94fpWJu_h-|kiV$Qpusq-`%1DxGPNtIHzebq zN$Y*(JyhSPI6BT1XZt`J$1-WEgI@CFzw`_dvWk-FnOJIXlyj@71yPN-l0^flO!#C& z_Ii<-O~uq80#{QHsBGA3y2PE|5p8nlO_;MOhu$Hr_(v|8G3R(Lji)7wM;^UJnqMUw zD@PH_FVkzSp~AF=7E`=qm8W&=1nXJ<57s0Qjp$->J>TWO9cHqsor zAYAh)(dWW$n91)@quMT&n5{*Fn3hk+aj5TF8b&jescUHzY)c$mPkM3}AtpN0Nx#dB zrCAC|)sG=&xL~XIFAfA(1x6>E8)KbVqs>+lDEJ1-Zhl7!HeTm$4$_JZ8z|AO1_W~t zZ*hGCb@vZE;l-NLH5Q+C8m1OQ>m`y>94G?K)R7j7STo#kp)kqDQ>il3eu6h<7SKK# zp|sybX`GHKYYVAfl9z6!2UMoa+eXW!&)(WjPst)~yiJi*r1%O-Cz>MG@1P4*p^Vu{ zM~Nx~-$j{_TJ|nF18u*$o7OpmxBZ*v!t=B0MAdFO1i#3Ahg!Kn1Y$3}ON}D3gf@~Y zJ}sdE^rdj#M>D8e%-u&}coO^Q^O)z3{=Z%gBOIUFf@u_&9myJ&7Gu-Mn2=$2dt&u2 zC9+%Tk|p;1n;ye--+qs3sXr%j()HxSvw>~~bE zU@(;&Rk|Law~0=O@`DtDMYj)93e8a>577vsBqjeaEhT8S@rcxHyhuDoL1^Y4gNf`G z=3}sp2BqN`Y|USKTfK|jz11ThLnNQVp0w5zV&w@s+)8@A+He-+c%9aerPDHu8AZ%V zdYz2Q{*yF{VCRocA;uU*Cj|;Hid_l?pgE~fFEl?XILs)9Szud5;$sU4Xpsv{GPz7~!fx>QlMm7xI_?!kcx8Gp>hc;Vryy)}=y+YB-)Gx^2$+Zl} zl~jmTm#Dp)?3?{6MDZm^HAzH%1=9={Q@*04|Ar0a&{wpRYdta56yq#^Bi!Y05IZF% zRnf2>((KD?xOy5^UgC`h2r|Ulh!~w_X%4R3kv^}hcX!)tl`e=BRpd|J;+HB)?vV-*wRvz7^-g2|A3%9SkBQ{*6K+-DvuTq+`t8~d?i)eWrejF&KU8hAd z>Rr4}85~?C-k|ofoqvP+gRYd^Ks2OCapzmghubW;2_<@pYd0yz^?_rf*40qxH6^W@ z9ua0ty+vc_x;S!+;t?$#+@gLUcKaTI&nU9Kr_FfstijQ}#cMUR2zl(&8j2xT8NP}w z!u?0AzAPsFXkWJFN18|}qW(uL^A@Xa(*p8Ve!fl4@}T-VG}YmiUYlWSGVW`w?qcFk zQ~(ZZe?q{wh{Zos8=?Cd=h^#H(Omo)X~QBOJDQMMT8O7jwbZ(0>J%7mMuE*{p6qO> zcdoxxY!Q}P__0NKTuTXrR63xJo)Nh#QT6n-3^G3VD3H?*(X)XnV4Ht5P&CCVy?>V} zIaK-ZK0FM9xBWqFop4Iq$J7ok_3C39%-IgH`Y|MTM_hbNvyr008X==xv8Ivw^^q~c zG^AJMkp4E?$4$lS@o4tjD2Z1*%JqHD4~ZkwkddbGW6Tk`axBIuerZH%2v*iVq0WQ= zapWoPtcs^kVVu>A3GqI-_(Tpd1SAf{u zMGk3rJ!~cEcGmI2lgkMV@kL)<9C0D^` zoR$wqvsug2&^*%eszCeJEo9|oVGx=6bP_gtao!z2zG;vS=}VV9bnJ$pIP|Q!5QIh2 z)VdEC>vC?ro$R2Lnr$`Bhft#&*kl^C&_|b}Wp?yUFZk4$2aLh4EvKz#3E` zPW9o{ZqoEkF&o9szC6TD+PcZlD9ZctgywQY{;PD^D15{D@&G*uno}37(IA={)U6vC zv!7X{6o>OmMB&Pkew-s!E6bwzVxnZ_b~GR6grMIumhXV?RK{}n&V1$GAihbuM|K=k zjimQkJpafUg~qy}FhgYg#$nu_Xouo6f*&SYuau4Cna-3YqQ*kB50r+n+$`(5tP~i` zmtyXCuAmSNO6AGEb}Rib2zrgvAzpb|&nP*m{1%dvGHoL7i!>~@PU43<_-K^j2^wWw zyjrmulPl|;3}4yIaiOT~`h%QcN)b~g^UlG0W?{5Z?bu6BGBuW~?e*PE4aPEkCyf%9 zV2T%eCi8#}i&w*sb1X@ai+aExQ)R65u~u(~!ETbo3~^&J@7hoMIznFp7}K}ZD5G$G zYJ9;oZVJ??tuwLei8U`)BPE+u2W?hiS~EPPi~du1ht6kuVg||pjgjL83_R6&gRoHN zZpzX*qrNV{QuRHNH-!g8?QMtkkKl8GvO=)*mMmOpjp?#1)mneu3BEkAi&_B2>$YRK zRL%*jQj5gbQ+RjkEBI92vH$jLticY@@_n3mISY^F<`kV4DYK7iAM?j4T6MZFE|#M6 z&#%(EVJulpo63X35*OKQ>eZw85fhm#n_bk2kT#gD90X=fS&Ui11&qj2BMAef!Ft9XKyntwJefKLl>c!O z?;a4`b+w|YNxtQ{KTkq;tWns>GD()g9$4aou`brQm$XL{Mane(5A8+!9nxD{$G#l0 zip|q_D{YBmq>FXR%aKA+I*o^F=e-zN_HraeJe ziibJZk8y|*kzSvWmbXfq>y&;MLLMlRXF!+bD;a8Tr&1Kn%<3#RUGHkMX_S_wQt`0v z386A@*>!5ElzT7e0z#Sk(Y+>HUW_cIq%QT%DqZeC%d#I<1(R^@fvH`aOOsBMK5+y? z8l?=zDt+Oy+$aG@i#s#;0CE-`XYvm8gGiXkqmnt|ks?)#>c+#w3=|q;y zIIJG-Cz*S(VWA}bAUtRBkg(*Pb~9WF)3sK3*e!go9NzDN6-M15gthk>O&cITU6{|;bfkfp^=pX8uNL*H(AF_^&+h05gj2*`q|nc%U0 zajBdhR%OO8e0ntmQR$XCcu1ep&X^NcRbbSqa`IdZq*WSq&QejMO^t>cO&YipZD#WT zzww?nTi(FbA>#(=J3`)9C7a)iq}jY%t6yYTa=fnCPZn~s3&J#;M+L5XVmJC`R;ksx z5uv!~NrWwF2ct#JY~InU8)lgDgI}}L+6kXI{G#`wM!8Cp|6>z&Zcqm)_vY|o8OaON zcp!BXhh*a=K2PJ@{hGiSj35%qaoqgqzt!)AejYzSZX$R-ZyoU4TR7V9Pkcjpd0%f_ zQ4J8u^Ld27lbg+!W;mn62S+wq?}N)}<8iqS;+^?C+docPT)YlxBE5q{u$A(9?Ug>S zb5wUtBgMi6ydUb+k_CJ{DWdxud<6}ZO;>U04b)2YV(CKu3LO_8F60ZTPPAUcb*M6; zW%DmFQ#P4m?IILcLxr-4hazd#EaJ5u)K*+r!7ro2+?m0<?}IDE<506vw@)%S3Q?fa<^%-*$AO)dF-( zs=C(k9I0l@j>9n3fpRRq(hwszV|tBaS8R$m(m^&`)EV8o=xg#PNy9EveK0-0Y~@36 zC?tnYYcMhAk0x93Gm*cNcbI6ZlKbi0HD}iz#CN{u4tz+?J)Or`f_bvHq29axtXinr zZO0Qkos^^RU^J|3v}Su*Qm1Mc>{<(hmAbL02sY}Sw=?1S9mK#)9_Z7-K35H}2hNob z)oo&7CJzZ|$b|tuH}}bR9Y%JO?6himA#ZUwlaHlrL92LMnkj;0Geq=X1vl)3wU5rZ z>pj5Ftsw}GZs@osfU)KnFKCt7Er87d;O z5b!#S31~DD8K{n2b5?^NXw%%`N!?TK?p}MwfAYVMr=A8m& zf{L>jC*kbzj(&>d13a!qQMgE4T8+9aOYj`N5k>Fj93G|p;98Sy!*1O*@P(yjx%6Fe zD~FFr8@CF=Z8ToD3--Jm7z7F?WylZ|f&P`+1VfWYx&ZBp91j7_c+)6@O-iqOvCTbEm= z_lV~DSL#}zVlu>B7B|;G#Rmj8;1!^s7+~OWyfjLDwVDSwHB-M5|1$8&@*TNlvx_B^ZUpf;9H)G1TCpZ>ravxi!=P`p8mDt+hLxI%!nC&m?*y` zqEP(A(txSz!uxg~Psry9{*AB0Fgn94&7+;I$um%F6{4I_&x(Edd>TzxoYwMcqC`=% zj_;@2V*Ps5M~w(C7H`Z|H`gNiyyk3nQ!iDbm*`zL6E=o4E6rB5f`-1V6xGA%=f=pD zOg~mV-XIM&W2i-5L7i8RIOF&#>yE<8k}ioI$3h*UCF{XWshouZI20~+-YHfjns}F% z5qL12vwveX-RM$|;h%-U#D{e#t^+3#@&z!=mj6iaYI`N&jRJ;`_3$BKO1mvN{zg8@F)aqsGL_7VuwY!{HrVhiSsnXih@f3}xv>4`- zo|u+rd(cL>74T60c!UTm;96Op72s<`vY1!EyZR^&4$^RoUxwip`C@MY@6o3gWMnPf zbMZWtLvbS>9P}ShHy~2cCLTifM8{2Br(2c)=V#uyVL%^QZrj86 zWK6EVgM*gJRcFK-n|Qa$*Y7mh5)J3I^_SKAsN`fF_#a5NRQiE606%bsj70mv-PM2N zw&19H*v+UZy6(#cSYt7vAYK=*hGR-8QX#Yc2PGv)Bh+B=`zG$Eoh8?lr{&*FmqkXt zJi3Kwvl-Pxxfrt<-v?B&ZZisikHyi=yc>d1^=5paxF8;H=6$=#&jIzJRPJ-tP|gfj zZT*Afhn*Fzmb&+EAwT;p^EBC86W;R27xJ+Ya)ESi=`$v+PWm@`&=73;017MnpUR#K z^?S+7D8vJCWD9TYVPWhUTntwDtPsIIU$ozXW|kPdg%1m|SDl`aRsK!=(gHJM&I}(R zVsV=K=(hM^3z9^&xUhxybPboZz2cc%d_}b1%6rhaV&qnQ7ReUJw(@YqquQ;=U3Z1c zHr~xwPPf;z_02w#+gakp;BCCC=HzK8^(cPucPmxhFIH{iGlG`aJa_JtGz452^9+{W97z4m>Rtv*na)m|@Vw~&w6rJaLtQ$Go-J&}2#+YKVA2p_?M#nK|) zOOzDxsUbbGy;wL93yc6J0lP9C_yYYZC1g8)9NbdMM1F^m;Xz&l>~A4I5qpX&itQBF sOeK?|(KODgf!F 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 delta 13642 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 BO<@24 diff --git a/pc-bios/vgabios-ati.bin b/pc-bios/vgabios-ati.bin index d034f6d254722ea47a706ffa08bcc9a73fa0847f..3dbfe53e5c88c9e62534ee54cea648e829b66c4e 100644 GIT binary patch delta 141 zcmV;80CN9;v;u&%0tZ#9P3ikpcCiP!NCAA4!AS0t(McX6W`p<#eg|j9LmVLM6=s9@ z1`m|MW=Up);qhjJ!9Qn+OB}QBN%#Q)*t6(M?*ajMv)E300|7ykQ&K+xwX>5_Y5@VR vlm1g00lbqLR9*o9vv^c40Rcs`r&X~-4>&DnWI1CvF*0OiVKp&1lV_Qk2y!{d delta 140 zcmV;70CWFXr? diff --git a/pc-bios/vgabios-bochs-display.bin b/pc-bios/vgabios-bochs-display.bin index 1ced8400f4dd3667063b2b0cb7aee7a00c188fc8..ca4c3db2db79d1cbc6deeec7835c34be02966975 100644 GIT binary patch delta 155 zcmV;M0A&Aw-~oW(0S8s8IO+F1Hn9h}Gy!~*!8D!$c#~i?Ta(>29wKIg_y>LmXU0Pu zAnO%ogZKsyl)+|6W`p7JW`n^$XNXH2v->qt0Rh;vPB$R}0YQ^+IX?llv#>c!0T!+U z003r**ih(u=j)bcxr9Oh0A{+plMy>!0RXdbJ2C+QMYE$kQ8EuWEoWpoV>mG~WMpAA JF*%b1Z~aS9JR$%9 delta 154 zcmV;L0A>Gx-~oW(0S8s8IO+F1U9ktbGy#2+!8D!$d6Qr@TOot^2Yv@<#zPz+>lJ2$ z_y!M@!e&ZlgW~aKgTg;&h*KPsx-}oO`!!Ml0ok)oHz5K6LX&VgKLNJ0usKTs7Ow*U z0A`8UQ0RN->y~D@ghBuSX1cwT5j$Q10kd#BG64Zbv!gswG7mH@XE-=vVlZPdH8nCd IW0M1K{TVGgnE(I) diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index b3af3771bd8feae2c2de6ca593bd56b21057d742..b8ee1fe0ff050f34b3565c15e3fd569a4a804609 100644 GIT binary patch delta 143 zcmV;A0C4|+umXUv0tZ#9OzG@VC9wyLLjin~ltb#1phO-bW`p<#eg|j9LmVLM6=s9@ z1`m|MW=Up);qhjJ!9Qn+OB}PlMEC&#*t54r?*ajMv!_XU0|7y^Ax&NZ0kyM$PHF)G xu9NFe8UehM22frB0JCLKG64ZavzSrzL=QMEXJk2JI59G0WMMTiIkTIVWdX5lI2r%| delta 142 zcmV;90CE3-umXUv0tZ#9OzG@VOtA-yLjir0ltbzvgZKx22WQ4Z93blzW`p{+0Rcv{m{IgZ4>T=jI5=TqFk>+_H8M40vzwM>0f;y^kpKVy diff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin index 3fac6dc13765b26029c9ae9bbb50c62e30e8257d..9829cd1dec0d92e902a391c3c3d41c0a4642cb66 100644 GIT binary patch delta 163 zcmZqJ!ql*Zi9K|c@5^tYy&KuLcreyX-sACZ@)=J#rL^WB>~-wv$DCypUW)=bZ2VIW zrg^3{Km3^1e9%6<7B@ed&aGs`+~9 zFr;T=jI5=Tq QFk>+_H8M40v$L2@0Yq#->Hq)$ diff --git a/pc-bios/vgabios-ramfb.bin b/pc-bios/vgabios-ramfb.bin index 1ca4f68a6e5e38e4c61cc216bb70b1047e835054..12dcb8e82305948dd3fb4cead4211f4978fbf514 100644 GIT binary patch delta 176 zcmV;h08jsb-~oW(0S8s8IO)PY3X=gu7qK2~H358+j5VGCc#|tOTa&0Z9wKIg_y>Lm zXU0PuAnO%ogZKsyl)+|6W`p7JW`n^$XNXH2v&J@30Rh;v88{&V0YQ^HIzIumvwJ#A z0T!+U003r**ih&>=j)bcxrjpm0A{+pliWLA0RXc*JTd_RMYC=_ZZae|EoWpoV>mG~ eWMpAAF*z-8a%Ez5X>4>Zab<0FE^l&Y00IO!jX+%h delta 175 zcmV;g08syc-~oW(0S8s8IO)PYF_QsA7qK2~H35B-j5VGCd6O$PTOot^2Yv@<#zPz+ z>lJ2$_y!M@!e&ZlgW~aKgTg;&h*KPsg*G3v#x_y`0ok(|I3WT7LX$f>KLNJ0dpb)2 z7Ow*U0A`8UQ0O`5>y~D@h(iDXX1cwT+&f+Y0kbmXZ*pe<0t5vXKhyvK diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin index a146eead00e87d25ebeab1300623c7155e806283..68fe2fe820d3e4782f2455e39de7b324f32e63cf 100644 GIT binary patch delta 163 zcmZqJ!ql*Zi9K|c@5^tY~-wv$DCypUW)=bZ2VIW zrg^3{Km3^1e9%6<7B@ed&aGs`+~9 zFr;T=jI5=Tq QFk>+_H8M40v$L2@0XLpN)Bpeg diff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin index 49981a4334cdd3d1a101b24c469dd47da1940bfd..60ce81d37c3a6b0fb8d368f2d4c738db0378f427 100644 GIT binary patch delta 163 zcmZqJ!ql*Zi9K|c@5^tYg&WzocreyX-sACZ@)=J#rL^WB>~-wv$DCypUW)=bZ2VIW zrg^3{Km3^1e9%6<7B@ed&aGs`+~9 zFr;T=jI5=Tq QFk>+_H8M40v$L2@0W=^$&Hw-a diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin index 2f8935bf1f4a9977b69ab99a886b9a5f1e6eee03..b75a3517d11a731276087f1d57cd9fbd9e6cd6e8 100644 GIT binary patch delta 163 zcmZqJ!ql*Zi9K|c@5^tYA{*JacreyX-sACZ@)=J#rL^WB>~-wv$DCypUW)=bZ2VIW zrg^3{Km3^1e9%6<7B@ed&aGs`+~9 zFr;Aa@ delta 162 zcmV;T0A2rpv;u&%0tZ#9P3iVkJFy3}NCAD5yh!dLgZKx22WQ4Z93blzW`pT=jI5=Tq QFk>+_H8M40v$L2@0sZhmaR2}S diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index d371983ab9f8dcaad1e0441bf547d0e32dda5cd7..410436fbdf9093badab3b01c8478d40f9278349b 100644 GIT binary patch delta 166 zcmZqJz|^pTi9K|c&&z`$S(6###5c-ixHHyFZg+n-dAf(3Qd;v5_B!_TW6m-PuSJ0z zHvTCG(>&9fAAU@0K4_ob;VrXytH%#U#v7a0dA(<1tk^uyw~Cq3ak6BfJ>%BRk%3u^ zGV7Qb7}7d#1iWy*12RYG&e0001v!X}Cqi2!DU;tFPi$^mD9dmI3H1Axwev$aV0 z0Rh>wu1fC$0eQ2YO?m?XLX#O$KLNJ0Sy5^M9Ipca0A`8UQ0PP4XU0Pu66vb}X1O$3 u003sXy_4TkUI78KK2t6M0Y Date: Wed, 29 Jul 2020 20:10:19 +0100 Subject: [PATCH 2567/2595] qapi/machine.json: Fix missing newline in doc comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 176d2cda0dee9f4 we added the @die-id field to the CpuInstanceProperties struct, but in the process accidentally removed the newline between the doc-comment lines for @core-id and @thread-id. Put the newline back in; this fixes a misformatting in the generated HTML QMP reference manual. Signed-off-by: Peter Maydell Message-Id: <20200729191019.19168-1-peter.maydell@linaro.org> Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster --- qapi/machine.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qapi/machine.json b/qapi/machine.json index f59144023c..daede5ab14 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -825,7 +825,8 @@ # @node-id: NUMA node ID the CPU belongs to # @socket-id: socket number within node/board the CPU belongs to # @die-id: die number within node/board the CPU belongs to (Since 4.1) -# @core-id: core number within die the CPU belongs to# @thread-id: thread number within core the CPU belongs to +# @core-id: core number within die the CPU belongs to +# @thread-id: thread number within core the CPU belongs to # # Note: currently there are 5 properties that could be present # but management should be prepared to pass through other From fbeed197611bda439968e68a42d8efadb2e60f81 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 30 Jul 2020 11:16:56 +0200 Subject: [PATCH 2568/2595] qapi: Delete unwanted indentation of top-level expressions Signed-off-by: Markus Armbruster Message-Id: <20200730091656.2633334-1-armbru@redhat.com> Reviewed-by: Eric Blake [One more line de-indented] --- qapi/block-core.json | 26 +++++++++++++------------- qapi/ui.json | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index ab7bf3c612..49edb4fdae 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1847,9 +1847,9 @@ # # Since: 4.0 ## - { 'enum': 'BlockPermission', - 'data': [ 'consistent-read', 'write', 'write-unchanged', 'resize', - 'graph-mod' ] } +{ 'enum': 'BlockPermission', + 'data': [ 'consistent-read', 'write', 'write-unchanged', 'resize', + 'graph-mod' ] } ## # @XDbgBlockGraphEdge: # @@ -2155,8 +2155,8 @@ # <- { "return": {} } # ## - { 'command': 'block-dirty-bitmap-enable', - 'data': 'BlockDirtyBitmap' } +{ 'command': 'block-dirty-bitmap-enable', + 'data': 'BlockDirtyBitmap' } ## # @block-dirty-bitmap-disable: @@ -2176,8 +2176,8 @@ # <- { "return": {} } # ## - { 'command': 'block-dirty-bitmap-disable', - 'data': 'BlockDirtyBitmap' } +{ 'command': 'block-dirty-bitmap-disable', + 'data': 'BlockDirtyBitmap' } ## # @block-dirty-bitmap-merge: @@ -2208,8 +2208,8 @@ # <- { "return": {} } # ## - { 'command': 'block-dirty-bitmap-merge', - 'data': 'BlockDirtyBitmapMerge' } +{ 'command': 'block-dirty-bitmap-merge', + 'data': 'BlockDirtyBitmapMerge' } ## # @BlockDirtyBitmapSha256: @@ -2220,8 +2220,8 @@ # # Since: 2.10 ## - { 'struct': 'BlockDirtyBitmapSha256', - 'data': {'sha256': 'str'} } +{ 'struct': 'BlockDirtyBitmapSha256', + 'data': {'sha256': 'str'} } ## # @x-debug-block-dirty-bitmap-sha256: @@ -2235,8 +2235,8 @@ # # Since: 2.10 ## - { 'command': 'x-debug-block-dirty-bitmap-sha256', - 'data': 'BlockDirtyBitmap', 'returns': 'BlockDirtyBitmapSha256' } +{ 'command': 'x-debug-block-dirty-bitmap-sha256', + 'data': 'BlockDirtyBitmap', 'returns': 'BlockDirtyBitmapSha256' } ## # @blockdev-mirror: diff --git a/qapi/ui.json b/qapi/ui.json index e16e98a060..1568cfeaad 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1081,8 +1081,8 @@ # Since: 3.0 # ## - { 'enum' : 'DisplayGLMode', - 'data' : [ 'off', 'on', 'core', 'es' ] } +{ 'enum' : 'DisplayGLMode', + 'data' : [ 'off', 'on', 'core', 'es' ] } ## # @DisplayCurses: From f7160f32186b4ae1e1327e3bd05060fffec8f9ae Mon Sep 17 00:00:00 2001 From: Andrea Bolognani Date: Wed, 29 Jul 2020 20:50:24 +0200 Subject: [PATCH 2569/2595] schemas: Add vim modeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The various schemas included in QEMU use a JSON-based format which is, however, strictly speaking not valid JSON. As a consequence, when vim tries to apply syntax highlight rules for JSON (as guessed from the file name), the result is an unreadable mess which mostly consist of red markers pointing out supposed errors in, well, pretty much everything. Using Python syntax highlighting produces much better results, and in fact these files already start with specially-formatted comments that instruct Emacs to process them as if they were Python files. This commit adds the equivalent special comments for vim. Signed-off-by: Andrea Bolognani Message-Id: <20200729185024.121766-1-abologna@redhat.com> Reviewed-by: Daniel P. Berrangé Reviewed-by: John Snow Signed-off-by: Markus Armbruster --- docs/interop/firmware.json | 1 + docs/interop/vhost-user.json | 1 + qapi/authz.json | 1 + qapi/block-core.json | 1 + qapi/block.json | 1 + qapi/char.json | 1 + qapi/common.json | 1 + qapi/control.json | 1 + qapi/crypto.json | 1 + qapi/dump.json | 1 + qapi/error.json | 1 + qapi/introspect.json | 1 + qapi/job.json | 1 + qapi/machine-target.json | 1 + qapi/machine.json | 1 + qapi/migration.json | 1 + qapi/misc-target.json | 1 + qapi/misc.json | 1 + qapi/net.json | 1 + qapi/qapi-schema.json | 1 + qapi/qdev.json | 1 + qapi/qom.json | 1 + qapi/rdma.json | 1 + qapi/rocker.json | 1 + qapi/run-state.json | 1 + qapi/sockets.json | 1 + qapi/tpm.json | 1 + qapi/transaction.json | 1 + qapi/ui.json | 1 + qga/qapi-schema.json | 1 + storage-daemon/qapi/qapi-schema.json | 1 + tests/qapi-schema/doc-good.json | 2 ++ tests/qapi-schema/include/sub-module.json | 1 + tests/qapi-schema/qapi-schema-test.json | 1 + tests/qapi-schema/sub-sub-module.json | 1 + 35 files changed, 36 insertions(+) diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json index 240f565397..989f10b626 100644 --- a/docs/interop/firmware.json +++ b/docs/interop/firmware.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # # Copyright (C) 2018 Red Hat, Inc. # diff --git a/docs/interop/vhost-user.json b/docs/interop/vhost-user.json index ef8ac5941f..feb5fe58ca 100644 --- a/docs/interop/vhost-user.json +++ b/docs/interop/vhost-user.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # # Copyright (C) 2018 Red Hat, Inc. # diff --git a/qapi/authz.json b/qapi/authz.json index 1c836a3abd..f3e9745426 100644 --- a/qapi/authz.json +++ b/qapi/authz.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # # QAPI authz definitions diff --git a/qapi/block-core.json b/qapi/block-core.json index 49edb4fdae..197bdc1c36 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python ## # == Block core (VM unrelated) diff --git a/qapi/block.json b/qapi/block.json index 2ddbfa8306..c54a393cf3 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python ## # = Block devices diff --git a/qapi/char.json b/qapi/char.json index daceb20f84..8aeedf96b2 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qapi/common.json b/qapi/common.json index 7b9cbcd97b..716712d4b3 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python ## # = Common data types diff --git a/qapi/control.json b/qapi/control.json index 6b816bb61f..de51e9916c 100644 --- a/qapi/control.json +++ b/qapi/control.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qapi/crypto.json b/qapi/crypto.json index 5a68e0db25..bb7930d332 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qapi/dump.json b/qapi/dump.json index a1eed7b15c..f7c4267e3f 100644 --- a/qapi/dump.json +++ b/qapi/dump.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # # This work is licensed under the terms of the GNU GPL, version 2 or later. # See the COPYING file in the top-level directory. diff --git a/qapi/error.json b/qapi/error.json index 3fad08f506..94a6502de9 100644 --- a/qapi/error.json +++ b/qapi/error.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python ## # = QMP errors diff --git a/qapi/introspect.json b/qapi/introspect.json index b1aabd4cfd..944bb87a20 100644 --- a/qapi/introspect.json +++ b/qapi/introspect.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # # Copyright (C) 2015 Red Hat, Inc. # diff --git a/qapi/job.json b/qapi/job.json index c48a0c3e34..280c2f76f1 100644 --- a/qapi/job.json +++ b/qapi/job.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python ## # == Background jobs diff --git a/qapi/machine-target.json b/qapi/machine-target.json index f2c82949d8..698850cc78 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # # This work is licensed under the terms of the GNU GPL, version 2 or later. # See the COPYING file in the top-level directory. diff --git a/qapi/machine.json b/qapi/machine.json index daede5ab14..481b1f07ec 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # # This work is licensed under the terms of the GNU GPL, version 2 or later. # See the COPYING file in the top-level directory. diff --git a/qapi/migration.json b/qapi/migration.json index d5000558c6..ea53b23dca 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qapi/misc-target.json b/qapi/misc-target.json index dee3b45930..1e561fa97b 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qapi/misc.json b/qapi/misc.json index 149c925246..9d32820dc1 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qapi/net.json b/qapi/net.json index 558d520a2f..ddb113e5e5 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index 43b0ba0dea..f03ff91ceb 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python ## # = Introduction # diff --git a/qapi/qdev.json b/qapi/qdev.json index f4ed9735c4..13254529bf 100644 --- a/qapi/qdev.json +++ b/qapi/qdev.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # # This work is licensed under the terms of the GNU GPL, version 2 or later. # See the COPYING file in the top-level directory. diff --git a/qapi/qom.json b/qapi/qom.json index 8abe998962..0b0b92944b 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # # This work is licensed under the terms of the GNU GPL, version 2 or later. # See the COPYING file in the top-level directory. diff --git a/qapi/rdma.json b/qapi/rdma.json index b58105b1b6..a1d2175a8b 100644 --- a/qapi/rdma.json +++ b/qapi/rdma.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qapi/rocker.json b/qapi/rocker.json index 52597db491..b48e49a89b 100644 --- a/qapi/rocker.json +++ b/qapi/rocker.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python ## # = Rocker switch device diff --git a/qapi/run-state.json b/qapi/run-state.json index 2e22907740..7cc9f96a5b 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qapi/sockets.json b/qapi/sockets.json index cbd6ef35d0..c0c640a5b0 100644 --- a/qapi/sockets.json +++ b/qapi/sockets.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python ## # = Socket data types diff --git a/qapi/tpm.json b/qapi/tpm.json index dc1f081739..6a10c9ed8d 100644 --- a/qapi/tpm.json +++ b/qapi/tpm.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qapi/transaction.json b/qapi/transaction.json index b6c11158f0..15ddebdbc3 100644 --- a/qapi/transaction.json +++ b/qapi/transaction.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qapi/ui.json b/qapi/ui.json index 1568cfeaad..9d6721037f 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # ## diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 408a662ea5..b1e9ed836d 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -1,4 +1,5 @@ # *-*- Mode: Python -*-* +# vim: filetype=python ## # diff --git a/storage-daemon/qapi/qapi-schema.json b/storage-daemon/qapi/qapi-schema.json index 14f4f8fe61..6100d1f0c9 100644 --- a/storage-daemon/qapi/qapi-schema.json +++ b/storage-daemon/qapi/qapi-schema.json @@ -1,4 +1,5 @@ # -*- Mode: Python -*- +# vim: filetype=python # Note that modules are shared with the QEMU main schema under the assumption # that the storage daemon schema is a subset of the main schema. For the shared diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json index ddd89d1233..9da72a1f55 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -1,4 +1,6 @@ # -*- Mode: Python -*- +# vim: filetype=python +# # Positive QAPI doc comment tests { 'pragma': { 'doc-required': true } } diff --git a/tests/qapi-schema/include/sub-module.json b/tests/qapi-schema/include/sub-module.json index afdb267228..b9f7b9bb56 100644 --- a/tests/qapi-schema/include/sub-module.json +++ b/tests/qapi-schema/include/sub-module.json @@ -1,4 +1,5 @@ # *-*- Mode: Python -*-* +# vim: filetype=python # Sub-module of ../qapi-schema-test.json diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 6b1f05afa7..3a9f2cbb33 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -1,4 +1,5 @@ # *-*- Mode: Python -*-* +# vim: filetype=python # This file is a stress test of supported qapi constructs that must # parse and compile correctly. diff --git a/tests/qapi-schema/sub-sub-module.json b/tests/qapi-schema/sub-sub-module.json index 524ef9b83f..94f36ec0b1 100644 --- a/tests/qapi-schema/sub-sub-module.json +++ b/tests/qapi-schema/sub-sub-module.json @@ -1,4 +1,5 @@ # *-*- Mode: Python -*-* +# vim: filetype=python # Sub-module of sub-module include/sub-module.json of qapi-schema-test.json From fe16c7ddf82b25e54cb76936a4cdf6bf9327ece5 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Thu, 30 Jul 2020 14:02:33 +0200 Subject: [PATCH 2570/2595] qcow2: Release read-only bitmaps when inactivated During migration, we release all bitmaps after storing them on disk, as long as they are (1) stored on disk, (2) not read-only, and (3) consistent. (2) seems arbitrary, though. The reason we do not release them is because we do not write them, as there is no need to; and then we just forget about all bitmaps that we have not written to the file. However, read-only persistent bitmaps are still in the file and in sync with their in-memory representation, so we may as well release them just like any R/W bitmap that we have updated. It leads to actual problems, too: After migration, letting the source continue may result in an error if there were any bitmaps on read-only nodes (such as backing images), because those have not been released by bdrv_inactive_all(), but bdrv_invalidate_cache_all() attempts to reload them (which fails, because they are still present in memory). Signed-off-by: Max Reitz Message-Id: <20200730120234.49288-2-mreitz@redhat.com> Tested-by: Peter Krempa Reviewed-by: Eric Blake Signed-off-by: Eric Blake --- block/qcow2-bitmap.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 1f38806ca6..8c34b2aef7 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -1562,11 +1562,22 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Qcow2Bitmap *bm; if (!bdrv_dirty_bitmap_get_persistence(bitmap) || - bdrv_dirty_bitmap_readonly(bitmap) || bdrv_dirty_bitmap_inconsistent(bitmap)) { continue; } + if (bdrv_dirty_bitmap_readonly(bitmap)) { + /* + * Store the bitmap in the associated Qcow2Bitmap so it + * can be released later + */ + bm = find_bitmap_by_name(bm_list, name); + if (bm) { + bm->dirty_bitmap = bitmap; + } + continue; + } + need_write = true; if (check_constraints_on_bitmap(bs, name, granularity, errp) < 0) { @@ -1618,7 +1629,9 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, /* allocate clusters and store bitmaps */ QSIMPLEQ_FOREACH(bm, bm_list, entry) { - if (bm->dirty_bitmap == NULL) { + BdrvDirtyBitmap *bitmap = bm->dirty_bitmap; + + if (bitmap == NULL || bdrv_dirty_bitmap_readonly(bitmap)) { continue; } @@ -1641,6 +1654,7 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, g_free(tb); } +success: if (release_stored) { QSIMPLEQ_FOREACH(bm, bm_list, entry) { if (bm->dirty_bitmap == NULL) { @@ -1651,13 +1665,14 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, } } -success: bitmap_list_free(bm_list); return; fail: QSIMPLEQ_FOREACH(bm, bm_list, entry) { - if (bm->dirty_bitmap == NULL || bm->table.offset == 0) { + if (bm->dirty_bitmap == NULL || bm->table.offset == 0 || + bdrv_dirty_bitmap_readonly(bm->dirty_bitmap)) + { continue; } From edadc99a2ee90daeaaf4fba21d623ec8efe7c8e6 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Thu, 30 Jul 2020 14:02:34 +0200 Subject: [PATCH 2571/2595] iotests/169: Test source cont with backing bmap Test migrating from a VM with a persistent bitmap in the backing chain, and then continuing that VM after the migration Signed-off-by: Max Reitz Message-Id: <20200730120234.49288-3-mreitz@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Eric Blake --- tests/qemu-iotests/169 | 64 +++++++++++++++++++++++++++++++++++++- tests/qemu-iotests/169.out | 4 +-- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/169 index 2c5a132aa3..40afb15299 100755 --- a/tests/qemu-iotests/169 +++ b/tests/qemu-iotests/169 @@ -24,11 +24,12 @@ import time import itertools import operator import re -from iotests import qemu_img +from iotests import qemu_img, qemu_img_create, Timeout disk_a = os.path.join(iotests.test_dir, 'disk_a') disk_b = os.path.join(iotests.test_dir, 'disk_b') +base_a = os.path.join(iotests.test_dir, 'base_a') size = '1M' mig_file = os.path.join(iotests.test_dir, 'mig_file') mig_cmd = 'exec: cat > ' + mig_file @@ -234,6 +235,67 @@ for cmb in list(itertools.product((True, False), repeat=2)): inject_test_case(TestDirtyBitmapMigration, name, 'do_test_migration_resume_source', *list(cmb)) + +class TestDirtyBitmapBackingMigration(iotests.QMPTestCase): + def setUp(self): + qemu_img_create('-f', iotests.imgfmt, base_a, size) + qemu_img_create('-f', iotests.imgfmt, '-F', iotests.imgfmt, + '-b', base_a, disk_a, size) + + for f in (disk_a, base_a): + qemu_img('bitmap', '--add', f, 'bmap0') + + blockdev = { + 'node-name': 'node0', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': disk_a + }, + 'backing': { + 'node-name': 'node0-base', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': base_a + } + } + } + + self.vm = iotests.VM() + self.vm.launch() + + result = self.vm.qmp('blockdev-add', **blockdev) + self.assert_qmp(result, 'return', {}) + + # Check that the bitmaps are there + for node in self.vm.qmp('query-named-block-nodes', flat=True)['return']: + if 'node0' in node['node-name']: + self.assert_qmp(node, 'dirty-bitmaps[0]/name', 'bmap0') + + caps = [{'capability': 'events', 'state': True}] + result = self.vm.qmp('migrate-set-capabilities', capabilities=caps) + self.assert_qmp(result, 'return', {}) + + def tearDown(self): + self.vm.shutdown() + for f in (disk_a, base_a): + os.remove(f) + + def test_cont_on_source(self): + """ + Continue the source after migration. + """ + result = self.vm.qmp('migrate', uri=f'exec: cat > /dev/null') + self.assert_qmp(result, 'return', {}) + + with Timeout(10, 'Migration timeout'): + self.vm.wait_migration('postmigrate') + + result = self.vm.qmp('cont') + self.assert_qmp(result, 'return', {}) + + if __name__ == '__main__': iotests.main(supported_fmts=['qcow2'], supported_protocols=['file']) diff --git a/tests/qemu-iotests/169.out b/tests/qemu-iotests/169.out index 5c26d15c0d..cafb8161f7 100644 --- a/tests/qemu-iotests/169.out +++ b/tests/qemu-iotests/169.out @@ -1,5 +1,5 @@ -.................................... +..................................... ---------------------------------------------------------------------- -Ran 36 tests +Ran 37 tests OK From e7e5a9595ab1136845c444141830fca0d2746a73 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 3 Aug 2020 17:55:03 +0100 Subject: [PATCH 2572/2595] hw/arm/netduino2, netduinoplus2: Set system_clock_scale The netduino2 and netduinoplus2 boards forgot to set the system_clock_scale global, which meant that if guest code used the systick timer in "use the processor clock" mode it would hang because time never advances. Set the global to match the documented CPU clock speed of these boards. Judging by the data sheet this is slightly simplistic because the SoC allows configuration of the SYSCLK source and frequency via the RCC (reset and clock control) module, but we don't model that. Fixes: https://bugs.launchpad.net/qemu/+bug/1876187 Signed-off-by: Peter Maydell Reviewed-by: Alistair Francis Message-id: 20200727162617.26227-1-peter.maydell@linaro.org --- hw/arm/netduino2.c | 10 ++++++++++ hw/arm/netduinoplus2.c | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c index 79e19392b5..8f10334144 100644 --- a/hw/arm/netduino2.c +++ b/hw/arm/netduino2.c @@ -30,10 +30,20 @@ #include "hw/arm/stm32f205_soc.h" #include "hw/arm/boot.h" +/* Main SYSCLK frequency in Hz (120MHz) */ +#define SYSCLK_FRQ 120000000ULL + static void netduino2_init(MachineState *machine) { DeviceState *dev; + /* + * TODO: ideally we would model the SoC RCC and let it handle + * system_clock_scale, including its ability to define different + * possible SYSCLK sources. + */ + system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ; + dev = qdev_new(TYPE_STM32F205_SOC); qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3")); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); diff --git a/hw/arm/netduinoplus2.c b/hw/arm/netduinoplus2.c index 958d21dd9f..68abd3ec69 100644 --- a/hw/arm/netduinoplus2.c +++ b/hw/arm/netduinoplus2.c @@ -30,10 +30,20 @@ #include "hw/arm/stm32f405_soc.h" #include "hw/arm/boot.h" +/* Main SYSCLK frequency in Hz (168MHz) */ +#define SYSCLK_FRQ 168000000ULL + static void netduinoplus2_init(MachineState *machine) { DeviceState *dev; + /* + * TODO: ideally we would model the SoC RCC and let it handle + * system_clock_scale, including its ability to define different + * possible SYSCLK sources. + */ + system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ; + dev = qdev_new(TYPE_STM32F405_SOC); qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4")); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); From faf7c6de34fb8eaa566726cc658ba5ad81fb32af Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 3 Aug 2020 17:55:03 +0100 Subject: [PATCH 2573/2595] include/hw/irq.h: New function qemu_irq_is_connected() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mostly devices don't need to care whether one of their output qemu_irq lines is connected, because functions like qemu_set_irq() silently do nothing if there is nothing on the other end. However sometimes a device might want to implement default behaviour for the case where the machine hasn't wired the line up to anywhere. Provide a function qemu_irq_is_connected() that devices can use for this purpose. (The test is trivial but encapsulating it in a function makes it easier to see where we're doing it in case we need to change the implementation later.) Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200728103744.6909-2-peter.maydell@linaro.org --- include/hw/irq.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/hw/irq.h b/include/hw/irq.h index 24ba0ece11..dc7abf199e 100644 --- a/include/hw/irq.h +++ b/include/hw/irq.h @@ -55,4 +55,22 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2); on an existing vector of qemu_irq. */ void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n); +/** + * qemu_irq_is_connected: Return true if IRQ line is wired up + * + * If a qemu_irq has a device on the other (receiving) end of it, + * return true; otherwise return false. + * + * Usually device models don't need to care whether the machine model + * has wired up their outbound qemu_irq lines, because functions like + * qemu_set_irq() silently do nothing if there is nothing on the other + * end of the line. However occasionally a device model will want to + * provide default behaviour if its output is left floating, and + * it can use this function to identify when that is the case. + */ +static inline bool qemu_irq_is_connected(qemu_irq irq) +{ + return irq != NULL; +} + #endif From 9e60d759d38d1faae1d85de2c53411e635be3cf2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 3 Aug 2020 17:55:03 +0100 Subject: [PATCH 2574/2595] hw/intc/armv7m_nvic: Provide default "reset the system" behaviour for SYSRESETREQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NVIC provides an outbound qemu_irq "SYSRESETREQ" which it signals when the guest sets the SYSRESETREQ bit in the AIRCR register. This matches the hardware design (where the CPU has a signal of this name and it is up to the SoC to connect that up to an actual reset mechanism), but in QEMU it mostly results in duplicated code in SoC objects and bugs where SoC model implementors forget to wire up the SYSRESETREQ line. Provide a default behaviour for the case where SYSRESETREQ is not actually connected to anything: use qemu_system_reset_request() to perform a system reset. This will allow us to remove the implementations of SYSRESETREQ handling from the boards where that's exactly what it does, and also fixes the bugs in the board models which forgot to wire up the signal: * microbit * mps2-an385 * mps2-an505 * mps2-an511 * mps2-an521 * musca-a * musca-b1 * netduino * netduinoplus2 We still allow the board to wire up the signal if it needs to, in case we need to model more complicated reset controller logic or to model buggy SoC hardware which forgot to wire up the line itself. But defaulting to "reset the system" is more often going to be correct than defaulting to "do nothing". Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200728103744.6909-3-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 17 ++++++++++++++++- include/hw/arm/armv7m.h | 4 +++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 3c4b6e6d70..277a98b87b 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -19,6 +19,7 @@ #include "hw/intc/armv7m_nvic.h" #include "hw/irq.h" #include "hw/qdev-properties.h" +#include "sysemu/runstate.h" #include "target/arm/cpu.h" #include "exec/exec-all.h" #include "exec/memop.h" @@ -64,6 +65,20 @@ static const uint8_t nvic_id[] = { 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 }; +static void signal_sysresetreq(NVICState *s) +{ + if (qemu_irq_is_connected(s->sysresetreq)) { + qemu_irq_pulse(s->sysresetreq); + } else { + /* + * Default behaviour if the SoC doesn't need to wire up + * SYSRESETREQ (eg to a system reset controller of some kind): + * perform a system reset via the usual QEMU API. + */ + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } +} + static int nvic_pending_prio(NVICState *s) { /* return the group priority of the current pending interrupt, @@ -1524,7 +1539,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, if (value & R_V7M_AIRCR_SYSRESETREQ_MASK) { if (attrs.secure || !(cpu->env.v7m.aircr & R_V7M_AIRCR_SYSRESETREQS_MASK)) { - qemu_irq_pulse(s->sysresetreq); + signal_sysresetreq(s); } } if (value & R_V7M_AIRCR_VECTCLRACTIVE_MASK) { diff --git a/include/hw/arm/armv7m.h b/include/hw/arm/armv7m.h index d2c74d3872..a30e3c6471 100644 --- a/include/hw/arm/armv7m.h +++ b/include/hw/arm/armv7m.h @@ -35,7 +35,9 @@ typedef struct { /* ARMv7M container object. * + Unnamed GPIO input lines: external IRQ lines for the NVIC - * + Named GPIO output SYSRESETREQ: signalled for guest AIRCR.SYSRESETREQ + * + Named GPIO output SYSRESETREQ: signalled for guest AIRCR.SYSRESETREQ. + * If this GPIO is not wired up then the NVIC will default to performing + * a qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET). * + Property "cpu-type": CPU type to instantiate * + Property "num-irq": number of external IRQ lines * + Property "memory": MemoryRegion defining the physical address space From fc6bb6e67e2f2b81de765a1c1ad5956de625ab19 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 3 Aug 2020 17:55:03 +0100 Subject: [PATCH 2575/2595] msf2-soc, stellaris: Don't wire up SYSRESETREQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MSF2 SoC model and the Stellaris board code both wire SYSRESETREQ up to a function that just invokes qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); This is now the default action that the NVIC does if the line is not connected, so we can delete the handling code. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200728103744.6909-4-peter.maydell@linaro.org --- hw/arm/msf2-soc.c | 11 ----------- hw/arm/stellaris.c | 12 ------------ 2 files changed, 23 deletions(-) diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index 33ea7df342..d2c29e82d1 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -30,7 +30,6 @@ #include "hw/irq.h" #include "hw/arm/msf2-soc.h" #include "hw/misc/unimp.h" -#include "sysemu/runstate.h" #include "sysemu/sysemu.h" #define MSF2_TIMER_BASE 0x40004000 @@ -59,13 +58,6 @@ static const int spi_irq[MSF2_NUM_SPIS] = { 2, 3 }; static const int uart_irq[MSF2_NUM_UARTS] = { 10, 11 }; static const int timer_irq[MSF2_NUM_TIMERS] = { 14, 15 }; -static void do_sys_reset(void *opaque, int n, int level) -{ - if (level) { - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - } -} - static void m2sxxx_soc_initfn(Object *obj) { MSF2State *s = MSF2_SOC(obj); @@ -130,9 +122,6 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) return; } - qdev_connect_gpio_out_named(DEVICE(&s->armv7m.nvic), "SYSRESETREQ", 0, - qemu_allocate_irq(&do_sys_reset, NULL, 0)); - system_clock_scale = NANOSECONDS_PER_SECOND / s->m3clk; for (i = 0; i < MSF2_NUM_UARTS; i++) { diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 28eb15c76c..5f9d080180 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -18,7 +18,6 @@ #include "hw/boards.h" #include "qemu/log.h" #include "exec/address-spaces.h" -#include "sysemu/runstate.h" #include "sysemu/sysemu.h" #include "hw/arm/armv7m.h" #include "hw/char/pl011.h" @@ -1206,14 +1205,6 @@ static void stellaris_adc_init(Object *obj) qdev_init_gpio_in(dev, stellaris_adc_trigger, 1); } -static -void do_sys_reset(void *opaque, int n, int level) -{ - if (level) { - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - } -} - /* Board init. */ static stellaris_board_info stellaris_boards[] = { { "LM3S811EVB", @@ -1317,9 +1308,6 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) /* This will exit with an error if the user passed us a bad cpu_type */ sysbus_realize_and_unref(SYS_BUS_DEVICE(nvic), &error_fatal); - qdev_connect_gpio_out_named(nvic, "SYSRESETREQ", 0, - qemu_allocate_irq(&do_sys_reset, NULL, 0)); - if (board->dc1 & (1 << 16)) { dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000, qdev_get_gpio_in(nvic, 14), From 8796fe40dd30cd9ffd3c958906471715c923b341 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 3 Aug 2020 17:55:03 +0100 Subject: [PATCH 2576/2595] target/arm: Fix AddPAC error indication The definition of top_bit used in this function is one higher than that used in the Arm ARM psuedo-code, which put the error indication at top_bit - 1 at the wrong place, which meant that it wasn't visible to Auth. Fixing the definition of top_bit requires more changes, because its most common use is for the count of bits in top_bit:bot_bit, which would then need to be computed as top_bit - bot_bit + 1. For now, prefer the minimal fix to the error indication alone. Fixes: 63ff0ca94cb Reported-by: Derrick McKee Signed-off-by: Richard Henderson Message-id: 20200728195706.11087-1-richard.henderson@linaro.org Reviewed-by: Peter Maydell [PMM: added comment about the divergence from the pseudocode] Signed-off-by: Peter Maydell --- target/arm/pauth_helper.c | 6 +++++- tests/tcg/aarch64/Makefile.target | 2 +- tests/tcg/aarch64/pauth-5.c | 33 +++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/tcg/aarch64/pauth-5.c diff --git a/target/arm/pauth_helper.c b/target/arm/pauth_helper.c index b909630317..6dbab03768 100644 --- a/target/arm/pauth_helper.c +++ b/target/arm/pauth_helper.c @@ -300,7 +300,11 @@ static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t modifier, */ test = sextract64(ptr, bot_bit, top_bit - bot_bit); if (test != 0 && test != -1) { - pac ^= MAKE_64BIT_MASK(top_bit - 1, 1); + /* + * Note that our top_bit is one greater than the pseudocode's + * version, hence "- 2" here. + */ + pac ^= MAKE_64BIT_MASK(top_bit - 2, 1); } /* diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index b617f2ac7e..e7249915e7 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -19,7 +19,7 @@ run-fcvt: fcvt # Pauth Tests ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_3),) -AARCH64_TESTS += pauth-1 pauth-2 pauth-4 +AARCH64_TESTS += pauth-1 pauth-2 pauth-4 pauth-5 pauth-%: CFLAGS += -march=armv8.3-a run-pauth-%: QEMU_OPTS += -cpu max run-plugin-pauth-%: QEMU_OPTS += -cpu max diff --git a/tests/tcg/aarch64/pauth-5.c b/tests/tcg/aarch64/pauth-5.c new file mode 100644 index 0000000000..67c257918b --- /dev/null +++ b/tests/tcg/aarch64/pauth-5.c @@ -0,0 +1,33 @@ +#include + +static int x; + +int main() +{ + int *p0 = &x, *p1, *p2, *p3; + unsigned long salt = 0; + + /* + * With TBI enabled and a 48-bit VA, there are 7 bits of auth, and so + * a 1/128 chance of auth = pac(ptr,key,salt) producing zero. + * Find a salt that creates auth != 0. + */ + do { + salt++; + asm("pacda %0, %1" : "=r"(p1) : "r"(salt), "0"(p0)); + } while (p0 == p1); + + /* + * This pac must fail, because the input pointer bears an encryption, + * and so is not properly extended within bits [55:47]. This will + * toggle bit 54 in the output... + */ + asm("pacda %0, %1" : "=r"(p2) : "r"(salt), "0"(p1)); + + /* ... so that the aut must fail, setting bit 53 in the output ... */ + asm("autda %0, %1" : "=r"(p3) : "r"(salt), "0"(p2)); + + /* ... which means this equality must not hold. */ + assert(p3 != p0); + return 0; +} From 88a90e3de6ae99cbcfcc04c862c51f241fdf685f Mon Sep 17 00:00:00 2001 From: Kaige Li Date: Mon, 3 Aug 2020 17:55:04 +0100 Subject: [PATCH 2577/2595] target/arm: Avoid maybe-uninitialized warning with gcc 4.9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC version 4.9.4 isn't clever enough to figure out that all execution paths in disas_ldst() that use 'fn' will have initialized it first, and so it warns: /home/LiKaige/qemu/target/arm/translate-a64.c: In function ‘disas_ldst’: /home/LiKaige/qemu/target/arm/translate-a64.c:3392:5: error: ‘fn’ may be used uninitialized in this function [-Werror=maybe-uninitialized] fn(cpu_reg(s, rt), clean_addr, tcg_rs, get_mem_index(s), ^ /home/LiKaige/qemu/target/arm/translate-a64.c:3318:22: note: ‘fn’ was declared here AtomicThreeOpFn *fn; ^ Make it happy by initializing the variable to NULL. Signed-off-by: Kaige Li Message-id: 1596110248-7366-2-git-send-email-likaige@loongson.cn Reviewed-by: Peter Maydell [PMM: Clean up commit message and note which gcc version this was] Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 8c0764957c..c98dfb17a8 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -3315,7 +3315,7 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn, bool r = extract32(insn, 22, 1); bool a = extract32(insn, 23, 1); TCGv_i64 tcg_rs, clean_addr; - AtomicThreeOpFn *fn; + AtomicThreeOpFn *fn = NULL; if (is_vector || !dc_isar_feature(aa64_atomics, s)) { unallocated_encoding(s); From ce4f70e81ed23c93ff39234672aff33114532640 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 27 Jul 2020 20:34:58 +0100 Subject: [PATCH 2578/2595] hw/arm/nrf51_soc: Set system_clock_scale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nrf51 SoC model wasn't setting the system_clock_scale global.which meant that if guest code used the systick timer in "use the processor clock" mode it would hang because time never advances. Set the global to match the documented CPU clock speed for this SoC. This SoC in fact doesn't have a SysTick timer (which is the only thing currently that cares about the system_clock_scale), because it's a configurable option in the Cortex-M0. However our Cortex-M0 and thus our nrf51 and our micro:bit board do provide a SysTick, so we ought to provide a functional one rather than a broken one. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200727193458.31250-1-peter.maydell@linaro.org --- hw/arm/nrf51_soc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index 45e6cc97d7..e15981e019 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -32,6 +32,9 @@ #define BASE_TO_IRQ(base) ((base >> 12) & 0x1F) +/* HCLK (the main CPU clock) on this SoC is always 16MHz */ +#define HCLK_FRQ 16000000 + static uint64_t clock_read(void *opaque, hwaddr addr, unsigned int size) { qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n", @@ -65,6 +68,8 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) return; } + system_clock_scale = NANOSECONDS_PER_SECOND / HCLK_FRQ; + object_property_set_link(OBJECT(&s->cpu), "memory", OBJECT(&s->container), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpu), errp)) { From 13557fd392890cbd985bceba7f717e01efd674b8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 27 Jul 2020 16:45:50 +0100 Subject: [PATCH 2579/2595] hw/timer/imx_epit: Avoid assertion when CR.SWR is written MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The imx_epit device has a software-controllable reset triggered by setting the SWR bit in the CR register. An error in commit cc2722ec83ad9 means that we will end up assert()ing if the guest does this, because the code in imx_epit_write() starts ptimer transactions, and then imx_epit_reset() also starts ptimer transactions, triggering "ptimer_transaction_begin: Assertion `!s->in_transaction' failed". The cleanest way to avoid this double-transaction is to move the start-transaction for the CR write handling down below the check of the SWR bit. Fixes: https://bugs.launchpad.net/qemu/+bug/1880424 Fixes: cc2722ec83ad944505fe Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200727154550.3409-1-peter.maydell@linaro.org --- hw/timer/imx_epit.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index baf6338e1a..ebd58254d1 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -199,15 +199,22 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, switch (offset >> 2) { case 0: /* CR */ - ptimer_transaction_begin(s->timer_cmp); - ptimer_transaction_begin(s->timer_reload); oldcr = s->cr; s->cr = value & 0x03ffffff; if (s->cr & CR_SWR) { /* handle the reset */ imx_epit_reset(DEVICE(s)); - } else { + /* + * TODO: could we 'break' here? following operations appear + * to duplicate the work imx_epit_reset() already did. + */ + } + + ptimer_transaction_begin(s->timer_cmp); + ptimer_transaction_begin(s->timer_reload); + + if (!(s->cr & CR_SWR)) { imx_epit_set_freq(s); } From f81cddfe8abe7d7e2220e611ee69d2cdf34eb789 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Fri, 31 Jul 2020 07:06:04 +0200 Subject: [PATCH 2580/2595] colo-compare: Remove superfluous NULL-pointer checks for s->iothread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit s->iothread is checked for NULL on object creation in colo_compare_complete, so it's guaranteed not to be NULL. This resolves a false alert from Coverity (CID 1429969). Signed-off-by: Lukas Straub Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Li Qiang Reviewed-by: Zhang Chen Signed-off-by: Jason Wang --- net/colo-compare.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/net/colo-compare.c b/net/colo-compare.c index cc15f23dea..2c20de1537 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -1442,9 +1442,7 @@ static void colo_compare_finalize(Object *obj) qemu_chr_fe_deinit(&s->chr_notify_dev, false); } - if (s->iothread) { - colo_compare_timer_del(s); - } + colo_compare_timer_del(s); qemu_bh_delete(s->event_bh); @@ -1470,9 +1468,7 @@ static void colo_compare_finalize(Object *obj) g_hash_table_destroy(s->connection_track_table); } - if (s->iothread) { - object_unref(OBJECT(s->iothread)); - } + object_unref(OBJECT(s->iothread)); g_free(s->pri_indev); g_free(s->sec_indev); From 035e69b063835a5fd23cacabd63690a3d84532a8 Mon Sep 17 00:00:00 2001 From: Mauro Matteo Cascella Date: Sat, 1 Aug 2020 18:42:38 +0200 Subject: [PATCH 2581/2595] hw/net/net_tx_pkt: fix assertion failure in net_tx_pkt_add_raw_fragment() An assertion failure issue was found in the code that processes network packets while adding data fragments into the packet context. It could be abused by a malicious guest to abort the QEMU process on the host. This patch replaces the affected assert() with a conditional statement, returning false if the current data fragment exceeds max_raw_frags. Reported-by: Alexander Bulekov Reported-by: Ziming Zhang Reviewed-by: Dmitry Fleytman Signed-off-by: Mauro Matteo Cascella Signed-off-by: Jason Wang --- hw/net/net_tx_pkt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index 9560e4a49e..da262edc3e 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -379,7 +379,10 @@ bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, hwaddr mapped_len = 0; struct iovec *ventry; assert(pkt); - assert(pkt->max_raw_frags > pkt->raw_frags); + + if (pkt->raw_frags >= pkt->max_raw_frags) { + return false; + } if (!len) { return true; From 8e0ef068942e4152f0d23e76ca1f5e35dc4456f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 4 Aug 2020 09:49:30 +0200 Subject: [PATCH 2582/2595] accel/xen: Fix xen_enabled() behavior on target-agnostic objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_XEN is generated by configure and stored in "config-target.h", which is (obviously) only include for target-specific objects. This is a problem for target-agnostic objects as CONFIG_XEN is never defined and xen_enabled() is always inlined as 'false'. Fix by following the KVM schema, defining CONFIG_XEN_IS_POSSIBLE when we don't know to force the call of the non-inlined function, returning the xen_allowed boolean. Fixes: da278d58a092 ("accel: Move Xen accelerator code under accel/xen/") Reported-by: Paul Durrant Suggested-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Paul Durrant Reviewed-by: Anthony PERARD Message-Id: <20200804074930.13104-2-philmd@redhat.com> Signed-off-by: Anthony PERARD --- accel/stubs/xen-stub.c | 2 ++ accel/xen/xen-all.c | 7 +------ include/sysemu/xen.h | 18 ++++++++++++++---- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/accel/stubs/xen-stub.c b/accel/stubs/xen-stub.c index dcca4e678a..8ae658acff 100644 --- a/accel/stubs/xen-stub.c +++ b/accel/stubs/xen-stub.c @@ -9,6 +9,8 @@ #include "hw/xen/xen.h" #include "qapi/qapi-commands-misc.h" +bool xen_allowed; + void xenstore_store_pv_console_info(int i, Chardev *chr) { } diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c index 0c24d4b191..60b971d0a8 100644 --- a/accel/xen/xen-all.c +++ b/accel/xen/xen-all.c @@ -32,12 +32,7 @@ do { } while (0) #endif -static bool xen_allowed; - -bool xen_enabled(void) -{ - return xen_allowed; -} +bool xen_allowed; xc_interface *xen_xc; xenforeignmemory_handle *xen_fmem; diff --git a/include/sysemu/xen.h b/include/sysemu/xen.h index 1ca292715e..2c2c429ea8 100644 --- a/include/sysemu/xen.h +++ b/include/sysemu/xen.h @@ -8,9 +8,19 @@ #ifndef SYSEMU_XEN_H #define SYSEMU_XEN_H -#ifdef CONFIG_XEN +#ifdef NEED_CPU_H +# ifdef CONFIG_XEN +# define CONFIG_XEN_IS_POSSIBLE +# endif +#else +# define CONFIG_XEN_IS_POSSIBLE +#endif -bool xen_enabled(void); +#ifdef CONFIG_XEN_IS_POSSIBLE + +extern bool xen_allowed; + +#define xen_enabled() (xen_allowed) #ifndef CONFIG_USER_ONLY void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length); @@ -18,7 +28,7 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, struct MemoryRegion *mr, Error **errp); #endif -#else /* !CONFIG_XEN */ +#else /* !CONFIG_XEN_IS_POSSIBLE */ #define xen_enabled() 0 #ifndef CONFIG_USER_ONLY @@ -33,6 +43,6 @@ static inline void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, } #endif -#endif /* CONFIG_XEN */ +#endif /* CONFIG_XEN_IS_POSSIBLE */ #endif From ffdfca6fac7e87faf4d0815e5cbc31c4a53f7a3a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 3 Aug 2020 13:57:08 -0700 Subject: [PATCH 2583/2595] docs/devel: Document decodetree no-overlap groups When support for this feature went in, the update to the documentation was forgotten. Fixes: 067e8b0f45d6 Reported-by: Peter Maydell Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20200803205708.315829-1-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/devel/decodetree.rst | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/docs/devel/decodetree.rst b/docs/devel/decodetree.rst index ce7f52308f..74f66bf46e 100644 --- a/docs/devel/decodetree.rst +++ b/docs/devel/decodetree.rst @@ -173,18 +173,25 @@ Pattern Groups Syntax:: - group := '{' ( pat_def | group )+ '}' + group := overlap_group | no_overlap_group + overlap_group := '{' ( pat_def | group )+ '}' + no_overlap_group := '[' ( pat_def | group )+ ']' -A *group* begins with a lone open-brace, with all subsequent lines -indented two spaces, and ending with a lone close-brace. Groups -may be nested, increasing the required indentation of the lines -within the nested group to two spaces per nesting level. +A *group* begins with a lone open-brace or open-bracket, with all +subsequent lines indented two spaces, and ending with a lone +close-brace or close-bracket. Groups may be nested, increasing the +required indentation of the lines within the nested group to two +spaces per nesting level. -Unlike ungrouped patterns, grouped patterns are allowed to overlap. -Conflicts are resolved by selecting the patterns in order. If all -of the fixedbits for a pattern match, its translate function will -be called. If the translate function returns false, then subsequent -patterns within the group will be matched. +Patterns within overlap groups are allowed to overlap. Conflicts are +resolved by selecting the patterns in order. If all of the fixedbits +for a pattern match, its translate function will be called. If the +translate function returns false, then subsequent patterns within the +group will be matched. + +Patterns within no-overlap groups are not allowed to overlap, just +the same as ungrouped patterns. Thus no-overlap groups are intended +to be nested inside overlap groups. The following example from PA-RISC shows specialization of the *or* instruction:: @@ -200,7 +207,7 @@ instruction:: When the *cf* field is zero, the instruction has no side effects, and may be specialized. When the *rt* field is zero, the output is discarded and so the instruction has no effect. When the *rt2* -field is zero, the operation is ``reg[rt] | 0`` and so encodes +field is zero, the operation is ``reg[r1] | 0`` and so encodes the canonical register copy operation. The output from the generator might look like:: From d250bb19ced3b702c7c37731855f6876d0cc7995 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Mon, 3 Aug 2020 17:28:49 -0700 Subject: [PATCH 2584/2595] target/arm: Fix decode of LDRA[AB] instructions These instructions use zero as the discriminator, not SP. Signed-off-by: Peter Collingbourne Message-id: 20200804002849.30268-1-pcc@google.com Reviewed-by: Richard Henderson Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index c98dfb17a8..534c3ff5f3 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -3429,9 +3429,11 @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn, if (s->pauth_active) { if (use_key_a) { - gen_helper_autda(dirty_addr, cpu_env, dirty_addr, cpu_X[31]); + gen_helper_autda(dirty_addr, cpu_env, dirty_addr, + new_tmp_a64_zero(s)); } else { - gen_helper_autdb(dirty_addr, cpu_env, dirty_addr, cpu_X[31]); + gen_helper_autdb(dirty_addr, cpu_env, dirty_addr, + new_tmp_a64_zero(s)); } } From facc68516a7ee6d4992dc47b42b47c600b20b21d Mon Sep 17 00:00:00 2001 From: Bruce Rogers Date: Thu, 30 Jul 2020 07:05:19 -0600 Subject: [PATCH 2585/2595] virtio-mem: Correct format specifier mismatch for RISC-V This likely affects other, less popular host architectures as well. Less common host architectures under linux get QEMU_VMALLOC_ALIGN (from which VIRTIO_MEM_MIN_BLOCK_SIZE is derived) define to a variable of type uintptr, which isn't compatible with the format specifier used to print a user message. Since this particular usage of the underlying data seems unique to this file, the simple fix is to just cast QEMU_VMALLOC_ALIGN to uint32_t, which corresponds to the format specifier used. Signed-off-by: Bruce Rogers Message-Id: <20200730130519.168475-1-brogers@suse.com> Acked-by: David Hildenbrand Reviewed-by: Stefano Garzarella Reviewed-by: Pankaj Gupta --- hw/virtio/virtio-mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index c12e9f79b0..7740fc613f 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -36,7 +36,7 @@ * Use QEMU_VMALLOC_ALIGN, so no THP will have to be split when unplugging * memory (e.g., 2MB on x86_64). */ -#define VIRTIO_MEM_MIN_BLOCK_SIZE QEMU_VMALLOC_ALIGN +#define VIRTIO_MEM_MIN_BLOCK_SIZE ((uint32_t)QEMU_VMALLOC_ALIGN) /* * Size the usable region bigger than the requested size if possible. Esp. * Linux guests will only add (aligned) memory blocks in case they fully From 1caac1c0e4d5bdcf18c88ee184453b8ccfdaaee3 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 15 Jul 2020 06:35:01 +0200 Subject: [PATCH 2586/2595] tests/docker: Add python3-venv and netcat to the debian-amd64 container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without python3-venv, I get the following message when trying to run the acceptance tests within the debian container: The virtual environment was not created successfully because ensurepip is not available. On Debian/Ubuntu systems, you need to install the python3-venv package using the following command. apt-get install python3-venv You may need to use sudo with that command. After installing the python3-venv package, recreate your virtual environment. Let's do it as the message suggests. And while we're at it, also add netcat here since it is required for some of the acceptance tests. Message-Id: <20200730141326.8260-2-thuth@redhat.com> Reviewed-by: Alex Bennée Signed-off-by: Thomas Huth --- tests/docker/dockerfiles/debian-amd64.docker | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker index 8fdfd6a6b0..d2500dcff1 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -20,7 +20,9 @@ RUN apt update && \ librdmacm-dev \ libsasl2-dev \ libsnappy-dev \ - libvte-dev + libvte-dev \ + netcat-openbsd \ + python3-venv # virgl RUN apt update && \ From 4d6862ffc74622c34324537549b8ea19e7854ed5 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 23 Jul 2020 08:36:04 +0200 Subject: [PATCH 2587/2595] tests/acceptance: Disable the rx sash and arm cubieboard replay test on Gitlab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These tests always time out on Gitlab, not sure what's happening here. Let's disable them until somebody has enough spare time to debug the issues. Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Cleber Rosa Message-Id: <20200730141326.8260-3-thuth@redhat.com> Reviewed-by: Alex Bennée Signed-off-by: Thomas Huth --- tests/acceptance/machine_rx_gdbsim.py | 4 ++++ tests/acceptance/replay_kernel.py | 1 + 2 files changed, 5 insertions(+) diff --git a/tests/acceptance/machine_rx_gdbsim.py b/tests/acceptance/machine_rx_gdbsim.py index bff63e421d..0c72506028 100644 --- a/tests/acceptance/machine_rx_gdbsim.py +++ b/tests/acceptance/machine_rx_gdbsim.py @@ -8,6 +8,9 @@ # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. +import os + +from avocado import skipIf from avocado_qemu import Test from avocado_qemu import exec_command_and_wait_for_pattern from avocado_qemu import wait_for_console_pattern @@ -42,6 +45,7 @@ class RxGdbSimMachine(Test): # FIXME limit baudrate on chardev, else we type too fast #exec_command_and_wait_for_pattern(self, 'version', gcc_version) + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_linux_sash(self): """ Boots a Linux kernel and checks that the console is operational. diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py index 62d2db8c64..b79fc8daf8 100644 --- a/tests/acceptance/replay_kernel.py +++ b/tests/acceptance/replay_kernel.py @@ -126,6 +126,7 @@ class ReplayKernel(LinuxKernelTest): self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1) + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_arm_cubieboard_initrd(self): """ :avocado: tags=arch:arm From 699616db6465b01580d5ddea18887a562206d928 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 14 Jul 2020 17:35:45 +0200 Subject: [PATCH 2588/2595] gitlab-ci.yml: Add build-system-debian and build-system-centos jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were missing the two new targets avr-softmmu and rx-softmmu in the gitlab-CI so far, and did not add some of the "other endianess" targets like sh4eb-softmmu yet. Since the current build-system-* jobs run already for a very long time, let's do not add these missing targets there, but introduce two new additional build jobs, one running with Debian and one running with CentOS, and add the new targets there. Also move some targets from the old build-system-* jobs to these new targets, to distribute the load and reduce the runtime of the CI. Message-Id: <20200730141326.8260-4-thuth@redhat.com> Reviewed-by: Alex Bennée Signed-off-by: Thomas Huth --- .gitlab-ci.yml | 92 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 17 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 362e5ee755..e96bcd50f8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,68 +53,126 @@ include: - python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat - du -chs $HOME/avocado/data/cache -build-system-ubuntu-main: +build-system-ubuntu: <<: *native_build_job_definition variables: IMAGE: ubuntu2004 - TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu lm32-softmmu - moxie-softmmu microblazeel-softmmu mips64el-softmmu m68k-softmmu ppc-softmmu - riscv64-softmmu sparc-softmmu + TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu + moxie-softmmu microblazeel-softmmu mips64el-softmmu MAKE_CHECK_ARGS: check-build artifacts: paths: - build -check-system-ubuntu-main: +check-system-ubuntu: <<: *native_test_job_definition needs: - - job: build-system-ubuntu-main + - job: build-system-ubuntu artifacts: true variables: IMAGE: ubuntu2004 MAKE_CHECK_ARGS: check -acceptance-system-ubuntu-main: +acceptance-system-ubuntu: <<: *native_test_job_definition needs: - - job: build-system-ubuntu-main + - job: build-system-ubuntu artifacts: true variables: IMAGE: ubuntu2004 MAKE_CHECK_ARGS: check-acceptance <<: *post_acceptance -build-system-fedora-alt: +build-system-debian: <<: *native_build_job_definition variables: - IMAGE: fedora - TARGETS: tricore-softmmu unicore32-softmmu microblaze-softmmu mips-softmmu - riscv32-softmmu s390x-softmmu sh4-softmmu sparc64-softmmu x86_64-softmmu - xtensa-softmmu nios2-softmmu or1k-softmmu + IMAGE: debian-amd64 + TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu + riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu MAKE_CHECK_ARGS: check-build artifacts: paths: - build -check-system-fedora-alt: +check-system-debian: <<: *native_test_job_definition needs: - - job: build-system-fedora-alt + - job: build-system-debian + artifacts: true + variables: + IMAGE: debian-amd64 + MAKE_CHECK_ARGS: check + +acceptance-system-debian: + <<: *native_test_job_definition + needs: + - job: build-system-debian + artifacts: true + variables: + IMAGE: debian-amd64 + MAKE_CHECK_ARGS: check-acceptance + <<: *post_acceptance + +build-system-fedora: + <<: *native_build_job_definition + variables: + IMAGE: fedora + TARGETS: tricore-softmmu unicore32-softmmu microblaze-softmmu mips-softmmu + xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu + MAKE_CHECK_ARGS: check-build + artifacts: + paths: + - build + +check-system-fedora: + <<: *native_test_job_definition + needs: + - job: build-system-fedora artifacts: true variables: IMAGE: fedora MAKE_CHECK_ARGS: check -acceptance-system-fedora-alt: +acceptance-system-fedora: <<: *native_test_job_definition needs: - - job: build-system-fedora-alt + - job: build-system-fedora artifacts: true variables: IMAGE: fedora MAKE_CHECK_ARGS: check-acceptance <<: *post_acceptance +build-system-centos: + <<: *native_build_job_definition + variables: + IMAGE: centos8 + TARGETS: ppc64-softmmu lm32-softmmu or1k-softmmu s390x-softmmu + x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu + MAKE_CHECK_ARGS: check-build + artifacts: + paths: + - build + +check-system-centos: + <<: *native_test_job_definition + needs: + - job: build-system-centos + artifacts: true + variables: + IMAGE: centos8 + MAKE_CHECK_ARGS: check + +acceptance-system-centos: + <<: *native_test_job_definition + needs: + - job: build-system-centos + artifacts: true + variables: + IMAGE: centos8 + MAKE_CHECK_ARGS: check-acceptance + <<: *post_acceptance + build-disabled: <<: *native_build_job_definition variables: From 5896c5395476ca30caad6ddd48d4b9dca2c63c00 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 30 Jul 2020 10:35:48 +0200 Subject: [PATCH 2589/2595] gitlab-ci: Fix Avocado cache usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 6957fd98dc ("gitlab: add avocado asset caching") we tried to save the Avocado cache (as in commit c1073e44b4 with Travis-CI) however it doesn't work as expected. For some reason Avocado uses /root/avocado_cache/ which we can not select later. Manually generate a Avocado config to force the use of the current job's directory. This patch is based on an earlier version from Philippe Mathieu-Daudé. Message-Id: <20200730141326.8260-5-thuth@redhat.com> Reviewed-by: Alex Bennée Signed-off-by: Thomas Huth --- .gitlab-ci.yml | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e96bcd50f8..9820066379 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,11 +47,24 @@ include: - find . -type f -exec touch {} + - make $MAKE_CHECK_ARGS -.post_acceptance_template: &post_acceptance +.acceptance_template: &acceptance_definition + cache: + key: "${CI_JOB_NAME}-cache" + paths: + - ${CI_PROJECT_DIR}/avocado-cache + policy: pull-push + before_script: + - mkdir -p ~/.config/avocado + - echo "[datadir.paths]" > ~/.config/avocado/avocado.conf + - echo "cache_dirs = ['${CI_PROJECT_DIR}/avocado-cache']" + >> ~/.config/avocado/avocado.conf + - if [ -d ${CI_PROJECT_DIR}/avocado-cache ]; then + du -chs ${CI_PROJECT_DIR}/avocado-cache ; + fi after_script: - cd build - python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat - - du -chs $HOME/avocado/data/cache + - du -chs ${CI_PROJECT_DIR}/avocado-cache build-system-ubuntu: <<: *native_build_job_definition @@ -81,7 +94,7 @@ acceptance-system-ubuntu: variables: IMAGE: ubuntu2004 MAKE_CHECK_ARGS: check-acceptance - <<: *post_acceptance + <<: *acceptance_definition build-system-debian: <<: *native_build_job_definition @@ -111,7 +124,7 @@ acceptance-system-debian: variables: IMAGE: debian-amd64 MAKE_CHECK_ARGS: check-acceptance - <<: *post_acceptance + <<: *acceptance_definition build-system-fedora: <<: *native_build_job_definition @@ -141,7 +154,7 @@ acceptance-system-fedora: variables: IMAGE: fedora MAKE_CHECK_ARGS: check-acceptance - <<: *post_acceptance + <<: *acceptance_definition build-system-centos: <<: *native_build_job_definition @@ -171,7 +184,7 @@ acceptance-system-centos: variables: IMAGE: centos8 MAKE_CHECK_ARGS: check-acceptance - <<: *post_acceptance + <<: *acceptance_definition build-disabled: <<: *native_build_job_definition From 35c7f5254b608c0694b11fc9f0d2c1a4ffb216b4 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 3 Aug 2020 19:54:36 +0200 Subject: [PATCH 2590/2595] target/riscv/vector_helper: Fix build on 32-bit big endian hosts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code currently fails to compile on 32-bit big endian hosts: target/riscv/vector_helper.c: In function 'vext_clear': target/riscv/vector_helper.c:154:16: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] memset((void *)((uintptr_t)tail & ~(7ULL)), 0, part1); ^ target/riscv/vector_helper.c:155:16: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] memset((void *)(((uintptr_t)tail + 8) & ~(7ULL)), 0, part2); ^ cc1: all warnings being treated as errors We should not use "long long" (i.e. 64-bit) values here to avoid the problem. Switch to our QEMU_ALIGN_PTR_DOWN/UP macros instead. Fixes: 751538d5da ("add vector stride load and store instructions") Suggested-by: Philippe Mathieu-Daudé Message-Id: <20200804170055.2851-3-thuth@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- target/riscv/vector_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 39f44d1029..793af99067 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -151,8 +151,8 @@ static void vext_clear(void *tail, uint32_t cnt, uint32_t tot) if (cnt % 8) { part1 = 8 - (cnt % 8); part2 = tot - cnt - part1; - memset((void *)((uintptr_t)tail & ~(7ULL)), 0, part1); - memset((void *)(((uintptr_t)tail + 8) & ~(7ULL)), 0, part2); + memset(QEMU_ALIGN_PTR_DOWN(tail, 8), 0, part1); + memset(QEMU_ALIGN_PTR_UP(tail, 8), 0, part2); } else { memset(tail, 0, part2); } From d2a71d7474d4649eabe554994a3fcba75244cce3 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 3 Aug 2020 21:14:57 +0200 Subject: [PATCH 2591/2595] Get rid of the libqemustub.a remainders libqemustub.a has been removed in commit ebedb37c8d ("Makefile: Remove libqemustub.a"). Some remainders have been missed. Remove them now. Message-Id: <20200804170055.2851-8-thuth@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- Makefile | 2 +- scripts/coverity-scan/run-coverity-scan | 3 --- tests/test-util-sockets.c | 3 ++- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index c2120d8d48..13dd708c4a 100644 --- a/Makefile +++ b/Makefile @@ -726,7 +726,7 @@ virtiofsd$(EXESUF): $(virtiofsd-obj-y) libvhost-user.a $(COMMON_LDADDS) $(call LINK, $^) endif -vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a libqemustub.a +vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a $(call LINK, $^) ifdef CONFIG_VHOST_USER_INPUT diff --git a/scripts/coverity-scan/run-coverity-scan b/scripts/coverity-scan/run-coverity-scan index 03a791dec9..6eefb4b558 100755 --- a/scripts/coverity-scan/run-coverity-scan +++ b/scripts/coverity-scan/run-coverity-scan @@ -403,9 +403,6 @@ echo "Configuring..." --enable-mpath --enable-libxml2 --enable-glusterfs \ --enable-virtfs --enable-zstd -echo "Making libqemustub.a..." -make libqemustub.a - echo "Running cov-build..." rm -rf cov-int mkdir cov-int diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c index 2ca1e99f17..261dc48c03 100644 --- a/tests/test-util-sockets.c +++ b/tests/test-util-sockets.c @@ -64,7 +64,8 @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) return dup(mon_fd); } -/* Syms in libqemustub.a are discarded at .o file granularity. +/* + * Syms of stubs in libqemuutil.a are discarded at .o file granularity. * To replace monitor_get_fd() we must ensure everything in * stubs/monitor.c is defined, to make sure monitor.o is discarded * otherwise we get duplicate syms at link time. From 348fcc4f7ace1718006e646078d88c8cd8c1d97e Mon Sep 17 00:00:00 2001 From: Tuguoyi Date: Wed, 5 Aug 2020 09:22:58 +0000 Subject: [PATCH 2592/2595] qcow2-cluster: Fix integer left shift error in qcow2_alloc_cluster_link_l2() When calculating the offset, the result of left shift operation will be promoted to type int64 automatically because the left operand of + operator is uint64_t. but the result after integer promotion may be produce an error value for us and trigger the following asserting error. For example, consider i=0x2000, cluster_bits=18, the result of left shift operation will be 0x80000000. Cause argument i is of signed integer type, the result is automatically promoted to 0xffffffff80000000 which is not we expected The way to trigger the assertion error: qemu-img create -f qcow2 -o preallocation=full,cluster_size=256k tmpdisk 10G This patch fix it by casting @i to uint64_t before doing left shift operation Signed-off-by: Guoyi Tu Reviewed-by: Eric Blake Reviewed-by: Kevin Wolf Reviewed-by: Alberto Garcia Message-id: 81ba90fe0c014f269621c283269b42ad@h3c.com Signed-off-by: Peter Maydell --- block/qcow2-cluster.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index a677ba9f5c..550850b264 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -980,7 +980,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m) assert(l2_index + m->nb_clusters <= s->l2_slice_size); for (i = 0; i < m->nb_clusters; i++) { - uint64_t offset = cluster_offset + (i << s->cluster_bits); + uint64_t offset = cluster_offset + ((uint64_t)i << s->cluster_bits); /* if two concurrent writes happen to the same unallocated cluster * each write allocates separate cluster and writes data concurrently. * The first one to complete updates l2 table with pointer to its From a65dabf71a9f9b949d556b1b57fd72595df92398 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 4 Aug 2020 20:39:03 +0100 Subject: [PATCH 2593/2595] target/arm: Fix Rt/Rt2 in ESR_ELx for copro traps from AArch32 to 64 When a coprocessor instruction in an AArch32 guest traps to AArch32 Hyp mode, the syndrome register (HSR) includes Rt and Rt2 fields which are simply copies of the Rt and Rt2 fields from the trapped instruction. However, if the instruction is trapped from AArch32 to an AArch64 higher exception level, the Rt and Rt2 fields in the syndrome register (ESR_ELx) must be the AArch64 view of the register. This makes a difference if the AArch32 guest was in a mode other than User or System and it was using r13 or r14, or if it was in FIQ mode and using r8-r14. We don't know at translate time which AArch32 CPU mode we are in, so we leave the values we generate in our prototype syndrome register value at translate time as the raw Rt/Rt2 from the instruction, and instead correct them to the AArch64 view when we find we need to take an exception from AArch32 to AArch64 with one of these syndrome values. Fixes: https://bugs.launchpad.net/qemu/+bug/1879587 Reported-by: Julien Freche Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell Message-id: 20200804193903.31240-1-peter.maydell@linaro.org --- target/arm/helper.c | 92 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 8ef0fb478f..455c92b891 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9581,6 +9581,66 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs) take_aarch32_exception(env, new_mode, mask, offset, addr); } +static int aarch64_regnum(CPUARMState *env, int aarch32_reg) +{ + /* + * Return the register number of the AArch64 view of the AArch32 + * register @aarch32_reg. The CPUARMState CPSR is assumed to still + * be that of the AArch32 mode the exception came from. + */ + int mode = env->uncached_cpsr & CPSR_M; + + switch (aarch32_reg) { + case 0 ... 7: + return aarch32_reg; + case 8 ... 12: + return mode == ARM_CPU_MODE_FIQ ? aarch32_reg + 16 : aarch32_reg; + case 13: + switch (mode) { + case ARM_CPU_MODE_USR: + case ARM_CPU_MODE_SYS: + return 13; + case ARM_CPU_MODE_HYP: + return 15; + case ARM_CPU_MODE_IRQ: + return 17; + case ARM_CPU_MODE_SVC: + return 19; + case ARM_CPU_MODE_ABT: + return 21; + case ARM_CPU_MODE_UND: + return 23; + case ARM_CPU_MODE_FIQ: + return 29; + default: + g_assert_not_reached(); + } + case 14: + switch (mode) { + case ARM_CPU_MODE_USR: + case ARM_CPU_MODE_SYS: + case ARM_CPU_MODE_HYP: + return 14; + case ARM_CPU_MODE_IRQ: + return 16; + case ARM_CPU_MODE_SVC: + return 18; + case ARM_CPU_MODE_ABT: + return 20; + case ARM_CPU_MODE_UND: + return 22; + case ARM_CPU_MODE_FIQ: + return 30; + default: + g_assert_not_reached(); + } + case 15: + return 31; + default: + g_assert_not_reached(); + } +} + /* Handle exception entry to a target EL which is using AArch64 */ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) { @@ -9591,6 +9651,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) unsigned int new_mode = aarch64_pstate_mode(new_el, true); unsigned int old_mode; unsigned int cur_el = arm_current_el(env); + int rt; /* * Note that new_el can never be 0. If cur_el is 0, then @@ -9645,7 +9706,8 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) case EXCP_HVC: case EXCP_HYP_TRAP: case EXCP_SMC: - if (syn_get_ec(env->exception.syndrome) == EC_ADVSIMDFPACCESSTRAP) { + switch (syn_get_ec(env->exception.syndrome)) { + case EC_ADVSIMDFPACCESSTRAP: /* * QEMU internal FP/SIMD syndromes from AArch32 include the * TA and coproc fields which are only exposed if the exception @@ -9653,6 +9715,34 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) * AArch64 format syndrome. */ env->exception.syndrome &= ~MAKE_64BIT_MASK(0, 20); + break; + case EC_CP14RTTRAP: + case EC_CP15RTTRAP: + case EC_CP14DTTRAP: + /* + * For a trap on AArch32 MRC/MCR/LDC/STC the Rt field is currently + * the raw register field from the insn; when taking this to + * AArch64 we must convert it to the AArch64 view of the register + * number. Notice that we read a 4-bit AArch32 register number and + * write back a 5-bit AArch64 one. + */ + rt = extract32(env->exception.syndrome, 5, 4); + rt = aarch64_regnum(env, rt); + env->exception.syndrome = deposit32(env->exception.syndrome, + 5, 5, rt); + break; + case EC_CP15RRTTRAP: + case EC_CP14RRTTRAP: + /* Similarly for MRRC/MCRR traps for Rt and Rt2 fields */ + rt = extract32(env->exception.syndrome, 5, 4); + rt = aarch64_regnum(env, rt); + env->exception.syndrome = deposit32(env->exception.syndrome, + 5, 5, rt); + rt = extract32(env->exception.syndrome, 10, 4); + rt = aarch64_regnum(env, rt); + env->exception.syndrome = deposit32(env->exception.syndrome, + 10, 5, rt); + break; } env->cp15.esr_el[new_el] = env->exception.syndrome; break; From e1d322c40524d2c544d1fcd37b267d106d16d328 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 5 Aug 2020 17:37:17 +0100 Subject: [PATCH 2594/2595] Update version for v5.1.0-rc3 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 388c02aef2..c4550df997 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.92 +5.0.93 From d0ed6a69d399ae193959225cdeaa9382746c91cc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 11 Aug 2020 17:07:03 +0100 Subject: [PATCH 2595/2595] Update version for v5.1.0 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c4550df997..831446cbd2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.93 +5.1.0

    dj7iDS5ss848A51sxWJAEvgkva|W}WJ9 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 PhU2kWI4OO{V}1V(KVp+Z diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index 99420eb815a1675df80e837630a4284ce5c4e1eb..26d631ea64c501927c417cf4c5352808dbb1f7ca 100644 GIT binary patch delta 34578 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 delta 34350 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 H=C}U?$-s(; diff --git a/roms/openbios b/roms/openbios index 7e5b89e429..4704d9eba6 160000 --- a/roms/openbios +++ b/roms/openbios @@ -1 +1 @@ -Subproject commit 7e5b89e4295063d8eba55b9c8ce8bc681c2d129a +Subproject commit 4704d9eba6d8017dc694c077ca4205ffd8becad8 From 4f0aff00f964721f8a5917240abbf23d9918069b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 17 May 2020 09:21:30 -0700 Subject: [PATCH 0624/2595] hw/arm/fsl-imx25: Wire up watchdog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this commit, the watchdog on imx25-pdk is fully operational, including pretimeout support. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Guenter Roeck Message-id: 20200517162135.110364-4-linux@roeck-us.net Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx25.c | 10 ++++++++++ include/hw/arm/fsl-imx25.h | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 3d05dc8538..8a5eb140f5 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -359,6 +359,7 @@ config FSL_IMX25 select IMX select IMX_FEC select IMX_I2C + select WDT_IMX2 select DS1338 config FSL_IMX31 diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index 6f1a82ce3d..cdaa79c26b 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -87,6 +87,7 @@ static void fsl_imx25_init(Object *obj) TYPE_CHIPIDEA); } + sysbus_init_child_obj(obj, "wdt", &s->wdt, sizeof(s->wdt), TYPE_IMX2_WDT); } static void fsl_imx25_realize(DeviceState *dev, Error **errp) @@ -302,6 +303,15 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) usb_table[i].irq)); } + /* Watchdog */ + object_property_set_bool(OBJECT(&s->wdt), true, "pretimeout-support", + &error_abort); + object_property_set_bool(OBJECT(&s->wdt), true, "realized", &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, FSL_IMX25_WDT_ADDR); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt), 0, + qdev_get_gpio_in(DEVICE(&s->avic), + FSL_IMX25_WDT_IRQ)); + /* initialize 2 x 16 KB ROM */ memory_region_init_rom(&s->rom[0], OBJECT(dev), "imx25.rom0", FSL_IMX25_ROM0_SIZE, &err); diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h index 5e196bbf05..9e228dacea 100644 --- a/include/hw/arm/fsl-imx25.h +++ b/include/hw/arm/fsl-imx25.h @@ -29,6 +29,7 @@ #include "hw/gpio/imx_gpio.h" #include "hw/sd/sdhci.h" #include "hw/usb/chipidea.h" +#include "hw/watchdog/wdt_imx2.h" #include "exec/memory.h" #include "target/arm/cpu.h" @@ -60,6 +61,7 @@ typedef struct FslIMX25State { IMXGPIOState gpio[FSL_IMX25_NUM_GPIOS]; SDHCIState esdhc[FSL_IMX25_NUM_ESDHCS]; ChipideaState usb[FSL_IMX25_NUM_USBS]; + IMX2WdtState wdt; MemoryRegion rom[2]; MemoryRegion iram; MemoryRegion iram_alias; @@ -229,6 +231,8 @@ typedef struct FslIMX25State { #define FSL_IMX25_GPIO1_SIZE 0x4000 #define FSL_IMX25_GPIO2_ADDR 0x53FD0000 #define FSL_IMX25_GPIO2_SIZE 0x4000 +#define FSL_IMX25_WDT_ADDR 0x53FDC000 +#define FSL_IMX25_WDT_SIZE 0x4000 #define FSL_IMX25_USB1_ADDR 0x53FF4000 #define FSL_IMX25_USB1_SIZE 0x0200 #define FSL_IMX25_USB2_ADDR 0x53FF4400 @@ -268,5 +272,6 @@ typedef struct FslIMX25State { #define FSL_IMX25_ESDHC2_IRQ 8 #define FSL_IMX25_USB1_IRQ 37 #define FSL_IMX25_USB2_IRQ 35 +#define FSL_IMX25_WDT_IRQ 55 #endif /* FSL_IMX25_H */ From b9e521dda3e6f8246d9ca3285ca372462e94c6d1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 17 May 2020 09:21:31 -0700 Subject: [PATCH 0625/2595] hw/arm/fsl-imx31: Wire up watchdog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this patch, the watchdog on i.MX31 emulations is fully operational. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Guenter Roeck Message-id: 20200517162135.110364-5-linux@roeck-us.net Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx31.c | 6 ++++++ include/hw/arm/fsl-imx31.h | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 8a5eb140f5..9afa6eee79 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -367,6 +367,7 @@ config FSL_IMX31 select SERIAL select IMX select IMX_I2C + select WDT_IMX2 select LAN9118 config FSL_IMX6 diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index 8472d2e911..1e7959863d 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -63,6 +63,8 @@ static void fsl_imx31_init(Object *obj) sysbus_init_child_obj(obj, "gpio[*]", &s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO); } + + sysbus_init_child_obj(obj, "wdt", &s->wdt, sizeof(s->wdt), TYPE_IMX2_WDT); } static void fsl_imx31_realize(DeviceState *dev, Error **errp) @@ -205,6 +207,10 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) gpio_table[i].irq)); } + /* Watchdog */ + object_property_set_bool(OBJECT(&s->wdt), true, "realized", &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, FSL_IMX31_WDT_ADDR); + /* On a real system, the first 16k is a `secure boot rom' */ memory_region_init_rom(&s->secure_rom, OBJECT(dev), "imx31.secure_rom", FSL_IMX31_SECURE_ROM_SIZE, &err); diff --git a/include/hw/arm/fsl-imx31.h b/include/hw/arm/fsl-imx31.h index ac5ca9826a..dd8561b309 100644 --- a/include/hw/arm/fsl-imx31.h +++ b/include/hw/arm/fsl-imx31.h @@ -25,6 +25,7 @@ #include "hw/timer/imx_epit.h" #include "hw/i2c/imx_i2c.h" #include "hw/gpio/imx_gpio.h" +#include "hw/watchdog/wdt_imx2.h" #include "exec/memory.h" #include "target/arm/cpu.h" @@ -49,6 +50,7 @@ typedef struct FslIMX31State { IMXEPITState epit[FSL_IMX31_NUM_EPITS]; IMXI2CState i2c[FSL_IMX31_NUM_I2CS]; IMXGPIOState gpio[FSL_IMX31_NUM_GPIOS]; + IMX2WdtState wdt; MemoryRegion secure_rom; MemoryRegion rom; MemoryRegion iram; @@ -87,6 +89,8 @@ typedef struct FslIMX31State { #define FSL_IMX31_GPIO1_SIZE 0x4000 #define FSL_IMX31_GPIO2_ADDR 0x53FD0000 #define FSL_IMX31_GPIO2_SIZE 0x4000 +#define FSL_IMX31_WDT_ADDR 0x53FDC000 +#define FSL_IMX31_WDT_SIZE 0x4000 #define FSL_IMX31_AVIC_ADDR 0x68000000 #define FSL_IMX31_AVIC_SIZE 0x100 #define FSL_IMX31_SDRAM0_ADDR 0x80000000 From bd8045a7044acd78ea5102404a9c16403933ce01 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 17 May 2020 09:21:32 -0700 Subject: [PATCH 0626/2595] hw/arm/fsl-imx6: Connect watchdog interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this patch applied, the watchdog in the sabrelite emulation is fully operational, including pretimeout support. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Guenter Roeck Message-id: 20200517162135.110364-6-linux@roeck-us.net Signed-off-by: Peter Maydell --- hw/arm/fsl-imx6.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 13f1bf23a6..f58c85aa8c 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -433,11 +433,20 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) FSL_IMX6_WDOG1_ADDR, FSL_IMX6_WDOG2_ADDR, }; + static const int FSL_IMX6_WDOGn_IRQ[FSL_IMX6_NUM_WDTS] = { + FSL_IMX6_WDOG1_IRQ, + FSL_IMX6_WDOG2_IRQ, + }; + object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support", + &error_abort); object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX6_WDOGn_ADDR[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0, + qdev_get_gpio_in(DEVICE(&s->a9mpcore), + FSL_IMX6_WDOGn_IRQ[i])); } /* ROM memory */ From 5671e960e2d8ea83405fe408b6b613f20985f87e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 17 May 2020 09:21:33 -0700 Subject: [PATCH 0627/2595] hw/arm/fsl-imx6ul: Connect watchdog interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this commit, the watchdog on mcimx6ul-evk is fully operational, including pretimeout support. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Guenter Roeck Message-id: 20200517162135.110364-7-linux@roeck-us.net Signed-off-by: Peter Maydell --- hw/arm/fsl-imx6ul.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index 56dfd7cecc..3ecb212da6 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -531,12 +531,22 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_WDOG2_ADDR, FSL_IMX6UL_WDOG3_ADDR, }; + static const int FSL_IMX6UL_WDOGn_IRQ[FSL_IMX6UL_NUM_WDTS] = { + FSL_IMX6UL_WDOG1_IRQ, + FSL_IMX6UL_WDOG2_IRQ, + FSL_IMX6UL_WDOG3_IRQ, + }; + object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support", + &error_abort); object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX6UL_WDOGn_ADDR[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0, + qdev_get_gpio_in(DEVICE(&s->a7mpcore), + FSL_IMX6UL_WDOGn_IRQ[i])); } /* From 72465e1ebaa6c850dbc099c6bb301d548bfea92b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 17 May 2020 09:21:34 -0700 Subject: [PATCH 0628/2595] hw/arm/fsl-imx7: Instantiate various unimplemented devices Instantiating PWM, CAN, CAAM, and OCOTP devices is necessary to avoid crashes when booting mainline Linux. Reviewed-by: Peter Maydell Signed-off-by: Guenter Roeck Message-id: 20200517162135.110364-8-linux@roeck-us.net Signed-off-by: Peter Maydell --- hw/arm/fsl-imx7.c | 24 ++++++++++++++++++++++++ include/hw/arm/fsl-imx7.h | 16 ++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index 119b281a50..d6cf7c48ce 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -459,6 +459,30 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) */ create_unimplemented_device("sdma", FSL_IMX7_SDMA_ADDR, FSL_IMX7_SDMA_SIZE); + /* + * CAAM + */ + create_unimplemented_device("caam", FSL_IMX7_CAAM_ADDR, FSL_IMX7_CAAM_SIZE); + + /* + * PWM + */ + create_unimplemented_device("pwm1", FSL_IMX7_PWM1_ADDR, FSL_IMX7_PWMn_SIZE); + create_unimplemented_device("pwm2", FSL_IMX7_PWM2_ADDR, FSL_IMX7_PWMn_SIZE); + create_unimplemented_device("pwm3", FSL_IMX7_PWM3_ADDR, FSL_IMX7_PWMn_SIZE); + create_unimplemented_device("pwm4", FSL_IMX7_PWM4_ADDR, FSL_IMX7_PWMn_SIZE); + + /* + * CAN + */ + create_unimplemented_device("can1", FSL_IMX7_CAN1_ADDR, FSL_IMX7_CANn_SIZE); + create_unimplemented_device("can2", FSL_IMX7_CAN2_ADDR, FSL_IMX7_CANn_SIZE); + + /* + * OCOTP + */ + create_unimplemented_device("ocotp", FSL_IMX7_OCOTP_ADDR, + FSL_IMX7_OCOTP_SIZE); object_property_set_bool(OBJECT(&s->gpr), true, "realized", &error_abort); diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index 3a0041c4c2..47826da2b7 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -113,6 +113,9 @@ enum FslIMX7MemoryMap { FSL_IMX7_IOMUXC_GPR_ADDR = 0x30340000, FSL_IMX7_IOMUXCn_SIZE = 0x1000, + FSL_IMX7_OCOTP_ADDR = 0x30350000, + FSL_IMX7_OCOTP_SIZE = 0x10000, + FSL_IMX7_ANALOG_ADDR = 0x30360000, FSL_IMX7_SNVS_ADDR = 0x30370000, FSL_IMX7_CCM_ADDR = 0x30380000, @@ -124,11 +127,24 @@ enum FslIMX7MemoryMap { FSL_IMX7_ADC2_ADDR = 0x30620000, FSL_IMX7_ADCn_SIZE = 0x1000, + FSL_IMX7_PWM1_ADDR = 0x30660000, + FSL_IMX7_PWM2_ADDR = 0x30670000, + FSL_IMX7_PWM3_ADDR = 0x30680000, + FSL_IMX7_PWM4_ADDR = 0x30690000, + FSL_IMX7_PWMn_SIZE = 0x10000, + FSL_IMX7_PCIE_PHY_ADDR = 0x306D0000, FSL_IMX7_PCIE_PHY_SIZE = 0x10000, FSL_IMX7_GPC_ADDR = 0x303A0000, + FSL_IMX7_CAAM_ADDR = 0x30900000, + FSL_IMX7_CAAM_SIZE = 0x40000, + + FSL_IMX7_CAN1_ADDR = 0x30A00000, + FSL_IMX7_CAN2_ADDR = 0x30A10000, + FSL_IMX7_CANn_SIZE = 0x10000, + FSL_IMX7_I2C1_ADDR = 0x30A20000, FSL_IMX7_I2C2_ADDR = 0x30A30000, FSL_IMX7_I2C3_ADDR = 0x30A40000, From c4947e64efcd8abeb6fde4bcd983f7f022c0e9f5 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 17 May 2020 09:21:35 -0700 Subject: [PATCH 0629/2595] hw/arm/fsl-imx7: Connect watchdog interrupts i.MX7 supports watchdog pretimeout interupts. With this commit, the watchdog in mcimx7d-sabre is fully operational, including pretimeout support. Reviewed-by: Peter Maydell Signed-off-by: Guenter Roeck Message-id: 20200517162135.110364-9-linux@roeck-us.net Signed-off-by: Peter Maydell --- hw/arm/fsl-imx7.c | 11 +++++++++++ include/hw/arm/fsl-imx7.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index d6cf7c48ce..89c3b64c06 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -447,11 +447,22 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_WDOG3_ADDR, FSL_IMX7_WDOG4_ADDR, }; + static const int FSL_IMX7_WDOGn_IRQ[FSL_IMX7_NUM_WDTS] = { + FSL_IMX7_WDOG1_IRQ, + FSL_IMX7_WDOG2_IRQ, + FSL_IMX7_WDOG3_IRQ, + FSL_IMX7_WDOG4_IRQ, + }; + object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support", + &error_abort); object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX7_WDOGn_ADDR[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0, + qdev_get_gpio_in(DEVICE(&s->a7mpcore), + FSL_IMX7_WDOGn_IRQ[i])); } /* diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index 47826da2b7..da977f9ffb 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -228,6 +228,11 @@ enum FslIMX7IRQs { FSL_IMX7_USB2_IRQ = 42, FSL_IMX7_USB3_IRQ = 40, + FSL_IMX7_WDOG1_IRQ = 78, + FSL_IMX7_WDOG2_IRQ = 79, + FSL_IMX7_WDOG3_IRQ = 10, + FSL_IMX7_WDOG4_IRQ = 109, + FSL_IMX7_PCI_INTA_IRQ = 125, FSL_IMX7_PCI_INTB_IRQ = 124, FSL_IMX7_PCI_INTC_IRQ = 123, From 9904625f1b54190bc6d9c098c2e0d969e67014cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 May 2020 16:03:06 +0200 Subject: [PATCH 0630/2595] hw/arm/integratorcp: Replace hw_error() by qemu_log_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw_error() calls exit(). This a bit overkill when we can log the accesses as unimplemented or guest error. When fuzzing the devices, we don't want the whole process to exit. Replace some hw_error() calls by qemu_log_mask(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200518140309.5220-2-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/integratorcp.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index 6d69010d06..5fb54e5aa7 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -20,6 +20,7 @@ #include "exec/address-spaces.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" +#include "qemu/log.h" #include "qemu/error-report.h" #include "hw/char/pl011.h" #include "hw/hw.h" @@ -144,8 +145,9 @@ static uint64_t integratorcm_read(void *opaque, hwaddr offset, /* ??? Voltage control unimplemented. */ return 0; default: - hw_error("integratorcm_read: Unimplemented offset 0x%x\n", - (int)offset); + qemu_log_mask(LOG_UNIMP, + "%s: Unimplemented offset 0x%" HWADDR_PRIX "\n", + __func__, offset); return 0; } } @@ -252,8 +254,9 @@ static void integratorcm_write(void *opaque, hwaddr offset, /* ??? Voltage control unimplemented. */ break; default: - hw_error("integratorcm_write: Unimplemented offset 0x%x\n", - (int)offset); + qemu_log_mask(LOG_UNIMP, + "%s: Unimplemented offset 0x%" HWADDR_PRIX "\n", + __func__, offset); break; } } @@ -394,7 +397,8 @@ static uint64_t icp_pic_read(void *opaque, hwaddr offset, case 5: /* INT_SOFTCLR */ case 11: /* FRQ_ENABLECLR */ default: - printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); return 0; } } @@ -430,7 +434,8 @@ static void icp_pic_write(void *opaque, hwaddr offset, case 8: /* FRQ_STATUS */ case 9: /* FRQ_RAWSTAT */ default: - printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); return; } icp_pic_update(s); @@ -504,7 +509,8 @@ static uint64_t icp_control_read(void *opaque, hwaddr offset, case 3: /* CP_DECODE */ return 0x11; default: - hw_error("icp_control_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); return 0; } } @@ -524,7 +530,8 @@ static void icp_control_write(void *opaque, hwaddr offset, /* Nothing interesting implemented yet. */ break; default: - hw_error("icp_control_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); } } From 5a0001ec7e0a446b6da86da8ca03211aab0fcd08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 May 2020 16:03:07 +0200 Subject: [PATCH 0631/2595] hw/arm/pxa2xx: Replace hw_error() by qemu_log_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw_error() calls exit(). This a bit overkill when we can log the accesses as unimplemented or guest error. When fuzzing the devices, we don't want the whole process to exit. Replace some hw_error() calls by qemu_log_mask(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200518140309.5220-3-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/pxa2xx_gpio.c | 7 ++++--- hw/display/pxa2xx_lcd.c | 8 +++++--- hw/dma/pxa2xx_dma.c | 14 +++++++++----- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c index f8df3cc227..a01db54a51 100644 --- a/hw/arm/pxa2xx_gpio.c +++ b/hw/arm/pxa2xx_gpio.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "hw/hw.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" @@ -199,7 +198,8 @@ static uint64_t pxa2xx_gpio_read(void *opaque, hwaddr offset, return s->status[bank]; default: - hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); } return 0; @@ -252,7 +252,8 @@ static void pxa2xx_gpio_write(void *opaque, hwaddr offset, break; default: - hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); } } diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c index 464e93161a..d5f2e82a4e 100644 --- a/hw/display/pxa2xx_lcd.c +++ b/hw/display/pxa2xx_lcd.c @@ -11,7 +11,7 @@ */ #include "qemu/osdep.h" -#include "hw/hw.h" +#include "qemu/log.h" #include "hw/irq.h" #include "migration/vmstate.h" #include "ui/console.h" @@ -407,7 +407,8 @@ static uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset, default: fail: - hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); } return 0; @@ -562,7 +563,8 @@ static void pxa2xx_lcdc_write(void *opaque, hwaddr offset, default: fail: - hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); } } diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c index 88ed4b6ff1..8a2eeb32bc 100644 --- a/hw/dma/pxa2xx_dma.c +++ b/hw/dma/pxa2xx_dma.c @@ -9,6 +9,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "hw/hw.h" #include "hw/irq.h" #include "hw/qdev-properties.h" @@ -268,7 +269,8 @@ static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset, unsigned int channel; if (size != 4) { - hw_error("%s: Bad access width\n", __func__); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad access width %u\n", + __func__, size); return 5; } @@ -315,8 +317,8 @@ static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset, return s->chan[channel].cmd; } } - - hw_error("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); return 7; } @@ -327,7 +329,8 @@ static void pxa2xx_dma_write(void *opaque, hwaddr offset, unsigned int channel; if (size != 4) { - hw_error("%s: Bad access width\n", __func__); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad access width %u\n", + __func__, size); return; } @@ -420,7 +423,8 @@ static void pxa2xx_dma_write(void *opaque, hwaddr offset, break; } fail: - hw_error("%s: Bad offset " TARGET_FMT_plx "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); } } From 492edf3e3038760aa6b7eb6a9bfdb648d4fa9b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 May 2020 16:03:08 +0200 Subject: [PATCH 0632/2595] hw/char/xilinx_uartlite: Replace hw_error() by qemu_log_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw_error() calls exit(). This a bit overkill when we can log the accesses as unimplemented or guest error. When fuzzing the devices, we don't want the whole process to exit. Replace some hw_error() calls by qemu_log_mask(). Reviewed-by: Edgar E. Iglesias Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200518140309.5220-4-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/char/xilinx_uartlite.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c index c6512285d7..ae4ccd00c7 100644 --- a/hw/char/xilinx_uartlite.c +++ b/hw/char/xilinx_uartlite.c @@ -23,7 +23,7 @@ */ #include "qemu/osdep.h" -#include "hw/hw.h" +#include "qemu/log.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" @@ -135,7 +135,8 @@ uart_write(void *opaque, hwaddr addr, switch (addr) { case R_STATUS: - hw_error("write to UART STATUS?\n"); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write to UART STATUS\n", + __func__); break; case R_CTRL: From a50fe66846d1d02065265f1e54c2b0007f8cb609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 May 2020 16:03:09 +0200 Subject: [PATCH 0633/2595] hw/timer/exynos4210_mct: Replace hw_error() by qemu_log_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw_error() calls exit(). This a bit overkill when we can log the accesses as unimplemented or guest error. When fuzzing the devices, we don't want the whole process to exit. Replace some hw_error() calls by qemu_log_mask(). Per the datasheet "Exynos 4412 RISC Microprocessor Rev 1.00" Chapter 25 "Multi Core Timer (MCT)" figure 1 and table 4, the default value on the APB bus is 0. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200518140309.5220-5-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/timer/exynos4210_mct.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index 570cf7075b..29a4b10676 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -54,7 +54,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" -#include "hw/hw.h" #include "hw/sysbus.h" #include "migration/vmstate.h" #include "qemu/timer.h" @@ -62,7 +61,6 @@ #include "hw/ptimer.h" #include "hw/arm/exynos4210.h" -#include "hw/hw.h" #include "hw/irq.h" //#define DEBUG_MCT @@ -1062,7 +1060,7 @@ static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset, int index; int shift; uint64_t count; - uint32_t value; + uint32_t value = 0; int lt_i; switch (offset) { @@ -1158,8 +1156,8 @@ static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset, break; default: - hw_error("exynos4210.mct: bad read offset " - TARGET_FMT_plx "\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); break; } return value; @@ -1484,8 +1482,8 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, break; default: - hw_error("exynos4210.mct: bad write offset " - TARGET_FMT_plx "\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); break; } } From faf58e53695be8eedc47b6232d581d37461d0f6e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 19 May 2020 10:51:43 +0200 Subject: [PATCH 0634/2595] ARM: PL061: Introduce N_GPIOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a definition for the number of GPIO lines controlled by a PL061 instance, and use it instead of the hardcoded magic value 8. Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Geert Uytterhoeven Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200519085143.1376-1-geert+renesas@glider.be Signed-off-by: Peter Maydell --- hw/gpio/pl061.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c index 2a828260bd..6d3c36bc16 100644 --- a/hw/gpio/pl061.c +++ b/hw/gpio/pl061.c @@ -36,6 +36,8 @@ static const uint8_t pl061_id_luminary[12] = #define TYPE_PL061 "pl061" #define PL061(obj) OBJECT_CHECK(PL061State, (obj), TYPE_PL061) +#define N_GPIOS 8 + typedef struct PL061State { SysBusDevice parent_obj; @@ -62,7 +64,7 @@ typedef struct PL061State { uint32_t cr; uint32_t amsel; qemu_irq irq; - qemu_irq out[8]; + qemu_irq out[N_GPIOS]; const unsigned char *id; uint32_t rsvd_start; /* reserved area: [rsvd_start, 0xfcc] */ } PL061State; @@ -112,7 +114,7 @@ static void pl061_update(PL061State *s) changed = s->old_out_data ^ out; if (changed) { s->old_out_data = out; - for (i = 0; i < 8; i++) { + for (i = 0; i < N_GPIOS; i++) { mask = 1 << i; if (changed & mask) { DPRINTF("Set output %d = %d\n", i, (out & mask) != 0); @@ -125,7 +127,7 @@ static void pl061_update(PL061State *s) changed = (s->old_in_data ^ s->data) & ~s->dir; if (changed) { s->old_in_data = s->data; - for (i = 0; i < 8; i++) { + for (i = 0; i < N_GPIOS; i++) { mask = 1 << i; if (changed & mask) { DPRINTF("Changed input %d = %d\n", i, (s->data & mask) != 0); @@ -364,8 +366,8 @@ static void pl061_init(Object *obj) memory_region_init_io(&s->iomem, obj, &pl061_ops, s, "pl061", 0x1000); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); - qdev_init_gpio_in(dev, pl061_set_irq, 8); - qdev_init_gpio_out(dev, s->out, 8); + qdev_init_gpio_in(dev, pl061_set_irq, N_GPIOS); + qdev_init_gpio_out(dev, s->out, N_GPIOS); } static void pl061_class_init(ObjectClass *klass, void *data) From 5c27392dd08bd8534893abf25ef501f1bd8680fe Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 May 2020 14:24:52 -0700 Subject: [PATCH 0635/2595] target/arm: Use tcg_gen_gvec_mov for clear_vec_high MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 8-byte store for the end a !is_q operation can be merged with the other stores. Use a no-op vector move to trigger the expand_clr portion of tcg_gen_gvec_mov. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20200519212453.28494-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 991e451644..4f6edb2892 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -496,14 +496,8 @@ static void clear_vec_high(DisasContext *s, bool is_q, int rd) unsigned ofs = fp_reg_offset(s, rd, MO_64); unsigned vsz = vec_full_reg_size(s); - if (!is_q) { - TCGv_i64 tcg_zero = tcg_const_i64(0); - tcg_gen_st_i64(tcg_zero, cpu_env, ofs + 8); - tcg_temp_free_i64(tcg_zero); - } - if (vsz > 16) { - tcg_gen_gvec_dup_imm(MO_64, ofs + 16, vsz - 16, vsz - 16, 0); - } + /* Nop move, with side effect of clearing the tail. */ + tcg_gen_gvec_mov(MO_64, ofs, ofs, is_q ? 16 : 8, vsz); } void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v) From e1f778596ebfa8782276f4dd4651f2b285d734ff Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 May 2020 14:24:53 -0700 Subject: [PATCH 0636/2595] target/arm: Use clear_vec_high more effectively MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not explicitly store zero to the NEON high part when we can pass !is_q to clear_vec_high. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20200519212453.28494-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 53 +++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 4f6edb2892..874f3eb4f9 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -900,11 +900,10 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size) { /* This always zero-extends and writes to a full 128 bit wide vector */ TCGv_i64 tmplo = tcg_temp_new_i64(); - TCGv_i64 tmphi; + TCGv_i64 tmphi = NULL; if (size < 4) { MemOp memop = s->be_data + size; - tmphi = tcg_const_i64(0); tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop); } else { bool be = s->be_data == MO_BE; @@ -922,12 +921,13 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size) } tcg_gen_st_i64(tmplo, cpu_env, fp_reg_offset(s, destidx, MO_64)); - tcg_gen_st_i64(tmphi, cpu_env, fp_reg_hi_offset(s, destidx)); - tcg_temp_free_i64(tmplo); - tcg_temp_free_i64(tmphi); - clear_vec_high(s, true, destidx); + if (tmphi) { + tcg_gen_st_i64(tmphi, cpu_env, fp_reg_hi_offset(s, destidx)); + tcg_temp_free_i64(tmphi); + } + clear_vec_high(s, tmphi != NULL, destidx); } /* @@ -6934,7 +6934,6 @@ static void disas_simd_ext(DisasContext *s, uint32_t insn) read_vec_element(s, tcg_resh, rm, 0, MO_64); do_ext64(s, tcg_resh, tcg_resl, pos); } - tcg_gen_movi_i64(tcg_resh, 0); } else { TCGv_i64 tcg_hh; typedef struct { @@ -6964,9 +6963,11 @@ static void disas_simd_ext(DisasContext *s, uint32_t insn) write_vec_element(s, tcg_resl, rd, 0, MO_64); tcg_temp_free_i64(tcg_resl); - write_vec_element(s, tcg_resh, rd, 1, MO_64); + if (is_q) { + write_vec_element(s, tcg_resh, rd, 1, MO_64); + } tcg_temp_free_i64(tcg_resh); - clear_vec_high(s, true, rd); + clear_vec_high(s, is_q, rd); } /* TBL/TBX @@ -7003,17 +7004,21 @@ static void disas_simd_tb(DisasContext *s, uint32_t insn) * the input. */ tcg_resl = tcg_temp_new_i64(); - tcg_resh = tcg_temp_new_i64(); + tcg_resh = NULL; if (is_tblx) { read_vec_element(s, tcg_resl, rd, 0, MO_64); } else { tcg_gen_movi_i64(tcg_resl, 0); } - if (is_tblx && is_q) { - read_vec_element(s, tcg_resh, rd, 1, MO_64); - } else { - tcg_gen_movi_i64(tcg_resh, 0); + + if (is_q) { + tcg_resh = tcg_temp_new_i64(); + if (is_tblx) { + read_vec_element(s, tcg_resh, rd, 1, MO_64); + } else { + tcg_gen_movi_i64(tcg_resh, 0); + } } tcg_idx = tcg_temp_new_i64(); @@ -7033,9 +7038,12 @@ static void disas_simd_tb(DisasContext *s, uint32_t insn) write_vec_element(s, tcg_resl, rd, 0, MO_64); tcg_temp_free_i64(tcg_resl); - write_vec_element(s, tcg_resh, rd, 1, MO_64); - tcg_temp_free_i64(tcg_resh); - clear_vec_high(s, true, rd); + + if (is_q) { + write_vec_element(s, tcg_resh, rd, 1, MO_64); + tcg_temp_free_i64(tcg_resh); + } + clear_vec_high(s, is_q, rd); } /* ZIP/UZP/TRN @@ -7072,7 +7080,7 @@ static void disas_simd_zip_trn(DisasContext *s, uint32_t insn) } tcg_resl = tcg_const_i64(0); - tcg_resh = tcg_const_i64(0); + tcg_resh = is_q ? tcg_const_i64(0) : NULL; tcg_res = tcg_temp_new_i64(); for (i = 0; i < elements; i++) { @@ -7123,9 +7131,12 @@ static void disas_simd_zip_trn(DisasContext *s, uint32_t insn) write_vec_element(s, tcg_resl, rd, 0, MO_64); tcg_temp_free_i64(tcg_resl); - write_vec_element(s, tcg_resh, rd, 1, MO_64); - tcg_temp_free_i64(tcg_resh); - clear_vec_high(s, true, rd); + + if (is_q) { + write_vec_element(s, tcg_resh, rd, 1, MO_64); + tcg_temp_free_i64(tcg_resh); + } + clear_vec_high(s, is_q, rd); } /* From 268b1b3dfbb92a9348406f728a33f39e3d8dcd8a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 18 May 2020 15:28:01 +0100 Subject: [PATCH 0637/2595] target/arm: Allow user-mode code to write CPSR.E via MSR Using the MSR instruction to write to CPSR.E is deprecated, but it is required to work from any mode including unprivileged code. We were incorrectly forbidding usermode code from writing it because CPSR_USER did not include the CPSR_E bit. We use CPSR_USER in only three places: * as the mask of what to allow userspace MSR to write to CPSR * when deciding what bits a linux-user signal-return should be able to write from the sigcontext structure * in target_user_copy_regs() when we set up the initial registers for the linux-user process In the first two cases not being able to update CPSR.E is a bug, and in the third case it doesn't matter because CPSR.E is always 0 there. So we can fix both bugs by adding CPSR_E to CPSR_USER. Because the cpsr_write() in restore_sigcontext() is now changing a CPSR bit which is cached in hflags, we need to add an arm_rebuild_hflags() call there; the callsite in target_user_copy_regs() was already rebuilding hflags for other reasons. (The recommended way to change CPSR.E is to use the 'SETEND' instruction, which we do correctly allow from usermode code.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200518142801.20503-1-peter.maydell@linaro.org --- linux-user/arm/signal.c | 1 + target/arm/cpu.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c index d96fc27ce1..8020c80acb 100644 --- a/linux-user/arm/signal.c +++ b/linux-user/arm/signal.c @@ -546,6 +546,7 @@ restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc) #ifdef TARGET_CONFIG_CPU_32 __get_user(cpsr, &sc->arm_cpsr); cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr); + arm_rebuild_hflags(env); #endif err |= !valid_user_regs(env); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 5d995368d4..677584e5da 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1230,7 +1230,7 @@ void pmu_init(ARMCPU *cpu); #define CACHED_CPSR_BITS (CPSR_T | CPSR_AIF | CPSR_GE | CPSR_IT | CPSR_Q \ | CPSR_NZCV) /* Bits writable in user mode. */ -#define CPSR_USER (CPSR_NZCV | CPSR_Q | CPSR_GE) +#define CPSR_USER (CPSR_NZCV | CPSR_Q | CPSR_GE | CPSR_E) /* Execution state bits. MRS read as zero, MSR writes ignored. */ #define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J | CPSR_IL) From 45e2813964b135a11e0fb6371d2c5f48d901929e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 11 May 2020 14:11:17 +0100 Subject: [PATCH 0638/2595] linux-user/arm: Reset CPSR_E when entering a signal handler This fixes signal handlers running with the wrong endianness if the interrupted code used SETEND to dynamically switch endianness. Signed-off-by: Amanieu d'Antras Reviewed-by: Peter Maydell Message-id: 20200511131117.2486486-1-amanieu@gmail.com Signed-off-by: Peter Maydell --- linux-user/arm/signal.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c index 8020c80acb..698985a647 100644 --- a/linux-user/arm/signal.c +++ b/linux-user/arm/signal.c @@ -244,6 +244,11 @@ setup_return(CPUARMState *env, struct target_sigaction *ka, } else { cpsr &= ~CPSR_T; } + if (env->cp15.sctlr_el[1] & SCTLR_E0E) { + cpsr |= CPSR_E; + } else { + cpsr &= ~CPSR_E; + } if (ka->sa_flags & TARGET_SA_RESTORER) { if (is_fdpic) { @@ -287,7 +292,8 @@ setup_return(CPUARMState *env, struct target_sigaction *ka, env->regs[13] = frame_addr; env->regs[14] = retcode; env->regs[15] = handler & (thumb ? ~1 : ~3); - cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr); + cpsr_write(env, cpsr, CPSR_IT | CPSR_T | CPSR_E, CPSRWriteByInstr); + arm_rebuild_hflags(env); return 0; } From fafe7229272f39500c14845bc7ea60a8504a5a20 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 18 May 2020 15:30:14 +0100 Subject: [PATCH 0639/2595] linux-user/arm/signal.c: Drop TARGET_CONFIG_CPU_32 The Arm signal-handling code has some parts ifdeffed with a TARGET_CONFIG_CPU_32, which is always defined. This is a leftover from when this code's structure was based on the Linux kernel signal handling code, where it was intended to support 26-bit Arm CPUs. The kernel dropped its CONFIG_CPU_32 in kernel commit 4da8b8208eded0ba21e3 in 2009. QEMU has never had 26-bit CPU support and is unlikely to ever add it; we certainly aren't going to support 26-bit Linux binaries via linux-user mode. The ifdef is just unhelpful noise, so remove it entirely. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200518143014.20689-1-peter.maydell@linaro.org --- linux-user/arm/signal.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c index 698985a647..f21d1535e4 100644 --- a/linux-user/arm/signal.c +++ b/linux-user/arm/signal.c @@ -126,8 +126,6 @@ struct rt_sigframe_v2 abi_ulong retcode[4]; }; -#define TARGET_CONFIG_CPU_32 1 - /* * For ARM syscalls, we encode the syscall number into the instruction. */ @@ -187,9 +185,7 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ __put_user(env->regs[13], &sc->arm_sp); __put_user(env->regs[14], &sc->arm_lr); __put_user(env->regs[15], &sc->arm_pc); -#ifdef TARGET_CONFIG_CPU_32 __put_user(cpsr_read(env), &sc->arm_cpsr); -#endif __put_user(/* current->thread.trap_no */ 0, &sc->trap_no); __put_user(/* current->thread.error_code */ 0, &sc->error_code); @@ -549,11 +545,9 @@ restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc) __get_user(env->regs[13], &sc->arm_sp); __get_user(env->regs[14], &sc->arm_lr); __get_user(env->regs[15], &sc->arm_pc); -#ifdef TARGET_CONFIG_CPU_32 __get_user(cpsr, &sc->arm_cpsr); cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr); arm_rebuild_hflags(env); -#endif err |= !valid_user_regs(env); From d23048c05cf0a1b9d72b6937a087cb5ed0e14e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 4 May 2019 18:52:40 +0200 Subject: [PATCH 0640/2595] hw/block/pflash_cfi01: Removed an unused timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'CFI02' NOR flash was introduced in commit 29133e9a0fff, with timing modelled. One year later, the CFI01 model was introduced (commit 05ee37ebf630) based on the CFI02 model. As noted in the header, "It does not support timings". 12 years later, we never had to model the device timings. Time to remove the unused timer, we can still add it back if required. Suggested-by: Laszlo Ersek Reviewed-by: Wei Yang Reviewed-by: Laszlo Ersek Reviewed-by: Alistair Francis Tested-by: Laszlo Ersek [Laszlo Ersek: Regression tested EDK2 OVMF IA32X64, ArmVirtQemu Aarch64 https://lists.gnu.org/archive/html/qemu-devel/2019-07/msg04373.html] Message-Id: <20190716221555.11145-2-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi01.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 8e8887253d..d67f84d655 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -42,7 +42,6 @@ #include "hw/qdev-properties.h" #include "sysemu/block-backend.h" #include "qapi/error.h" -#include "qemu/timer.h" #include "qemu/bitops.h" #include "qemu/error-report.h" #include "qemu/host-utils.h" @@ -91,7 +90,6 @@ struct PFlashCFI01 { uint8_t cfi_table[0x52]; uint64_t counter; unsigned int writeblock_size; - QEMUTimer *timer; MemoryRegion mem; char *name; void *storage; @@ -115,18 +113,6 @@ static const VMStateDescription vmstate_pflash = { } }; -static void pflash_timer (void *opaque) -{ - PFlashCFI01 *pfl = opaque; - - trace_pflash_timer_expired(pfl->cmd); - /* Reset flash */ - pfl->status ^= 0x80; - memory_region_rom_device_set_romd(&pfl->mem, true); - pfl->wcycle = 0; - pfl->cmd = 0; -} - /* Perform a CFI query based on the bank width of the flash. * If this code is called we know we have a device_width set for * this flash. @@ -775,7 +761,6 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) pfl->max_device_width = pfl->device_width; } - pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl); pfl->wcycle = 0; pfl->cmd = 0; pfl->status = 0x80; /* WSM ready */ From aba53a12bd56902e874b168b07c2ecd7a99e7878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jul 2019 19:06:56 +0200 Subject: [PATCH 0641/2595] hw/block/pflash_cfi01: Document use of non-CFI compliant command '0x00' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The command 0x00 is used by this model since its origin (commit 05ee37ebf630). In this commit the command is described with a amusing '/* ??? */' comment, probably meaning 'FIXME'. switch (cmd) { case 0x00: /* ??? */ ... This comment survived 12 years because the 0x00 value is indeed not specified by the CFI open standard (as of this commit). The 'cmd' field is transfered during migration. To keep the migration feature working with older QEMU version, we have to take a lot of care with migrated field. We figured out it is too late to remove a non-specified value from this model (this would make migration review very complex). It is however not too late to improve the documentation. Add few comments to remember this is a special value related to QEMU, and we won't find information about it on the CFI spec. Reviewed-by: Alistair Francis Message-Id: <20190716221555.11145-3-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi01.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index d67f84d655..3cd483d26a 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -278,9 +278,13 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, /* This should never happen : reset state & treat it as a read */ DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); pfl->wcycle = 0; - pfl->cmd = 0; + /* + * The command 0x00 is not assigned by the CFI open standard, + * but QEMU historically uses it for the READ_ARRAY command (0xff). + */ + pfl->cmd = 0x00; /* fall through to read code */ - case 0x00: + case 0x00: /* This model reset value for READ_ARRAY (not CFI compliant) */ /* Flash area read */ ret = pflash_data_read(pfl, offset, width, be); break; @@ -449,7 +453,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, case 0: /* read mode */ switch (cmd) { - case 0x00: /* ??? */ + case 0x00: /* This model reset value for READ_ARRAY (not CFI) */ goto reset_flash; case 0x10: /* Single Byte Program */ case 0x40: /* Single Byte Program */ @@ -646,7 +650,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, trace_pflash_reset(); memory_region_rom_device_set_romd(&pfl->mem, true); pfl->wcycle = 0; - pfl->cmd = 0; + pfl->cmd = 0x00; /* This model reset value for READ_ARRAY (not CFI) */ } @@ -762,7 +766,11 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) } pfl->wcycle = 0; - pfl->cmd = 0; + /* + * The command 0x00 is not assigned by the CFI open standard, + * but QEMU historically uses it for the READ_ARRAY command (0xff). + */ + pfl->cmd = 0x00; pfl->status = 0x80; /* WSM ready */ /* Hardcoded CFI table */ /* Standard "QRY" string */ From 3072182dc177886edabbdc548b4640bb32d82269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jul 2019 19:11:57 +0200 Subject: [PATCH 0642/2595] hw/block/pflash_cfi01: Rename 'reset_flash' label as 'mode_read_array' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the 'reset_flash' as 'mode_read_array' to make explicit we do not reset the device, we simply set its internal state machine in the READ_ARRAY mode. We do not reset the status register error bits, as a device reset would do. Reviewed-by: John Snow Reviewed-by: Alistair Francis Message-Id: <20190716221555.11145-5-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi01.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 3cd483d26a..2ca173aa46 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -454,7 +454,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, /* read mode */ switch (cmd) { case 0x00: /* This model reset value for READ_ARRAY (not CFI) */ - goto reset_flash; + goto mode_read_array; case 0x10: /* Single Byte Program */ case 0x40: /* Single Byte Program */ DPRINTF("%s: Single Byte Program\n", __func__); @@ -477,7 +477,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, case 0x50: /* Clear status bits */ DPRINTF("%s: Clear status bits\n", __func__); pfl->status = 0x0; - goto reset_flash; + goto mode_read_array; case 0x60: /* Block (un)lock */ DPRINTF("%s: Block unlock\n", __func__); break; @@ -502,10 +502,10 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, break; case 0xf0: /* Probe for AMD flash */ DPRINTF("%s: Probe for AMD flash\n", __func__); - goto reset_flash; - case 0xff: /* Read array mode */ + goto mode_read_array; + case 0xff: /* Read Array */ DPRINTF("%s: Read array mode\n", __func__); - goto reset_flash; + goto mode_read_array; default: goto error_flash; } @@ -531,8 +531,8 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, if (cmd == 0xd0) { /* confirm */ pfl->wcycle = 0; pfl->status |= 0x80; - } else if (cmd == 0xff) { /* read array mode */ - goto reset_flash; + } else if (cmd == 0xff) { /* Read Array */ + goto mode_read_array; } else goto error_flash; @@ -558,16 +558,16 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, } else if (cmd == 0x01) { pfl->wcycle = 0; pfl->status |= 0x80; - } else if (cmd == 0xff) { - goto reset_flash; + } else if (cmd == 0xff) { /* Read Array */ + goto mode_read_array; } else { DPRINTF("%s: Unknown (un)locking command\n", __func__); - goto reset_flash; + goto mode_read_array; } break; case 0x98: - if (cmd == 0xff) { - goto reset_flash; + if (cmd == 0xff) { /* Read Array */ + goto mode_read_array; } else { DPRINTF("%s: leaving query mode\n", __func__); } @@ -627,7 +627,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, " the data is already written to storage!\n" "Flash device reset into READ mode.\n", __func__); - goto reset_flash; + goto mode_read_array; } break; default: @@ -637,7 +637,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, default: /* Should never happen */ DPRINTF("%s: invalid write state\n", __func__); - goto reset_flash; + goto mode_read_array; } return; @@ -646,7 +646,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)" "\n", __func__, offset, pfl->wcycle, pfl->cmd, value); - reset_flash: + mode_read_array: trace_pflash_reset(); memory_region_rom_device_set_romd(&pfl->mem, true); pfl->wcycle = 0; From 1857b9db49770590483be44eb90993c42b2a5a99 Mon Sep 17 00:00:00 2001 From: Mansour Ahmadi Date: Tue, 7 Apr 2020 20:35:52 -0400 Subject: [PATCH 0643/2595] hw/block/pflash: Check return value of blk_pwrite() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When updating the PFLASH file contents, we should check for a possible failure of blk_pwrite(). Similar to commit 3a688294e. Reported-by: Coverity (CID 1357678 CHECKED_RETURN) Signed-off-by: Mansour Ahmadi Message-Id: <20200408003552.58095-1-mansourweb@gmail.com> [PMD: Add missing "qemu/error-report.h" include and TODO comment] Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi01.c | 8 +++++++- hw/block/pflash_cfi02.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 2ca173aa46..11922c0f96 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -42,6 +42,7 @@ #include "hw/qdev-properties.h" #include "sysemu/block-backend.h" #include "qapi/error.h" +#include "qemu/error-report.h" #include "qemu/bitops.h" #include "qemu/error-report.h" #include "qemu/host-utils.h" @@ -389,13 +390,18 @@ static void pflash_update(PFlashCFI01 *pfl, int offset, int size) { int offset_end; + int ret; if (pfl->blk) { offset_end = offset + size; /* widen to sector boundaries */ offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE); offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE); - blk_pwrite(pfl->blk, offset, pfl->storage + offset, + ret = blk_pwrite(pfl->blk, offset, pfl->storage + offset, offset_end - offset, 0); + if (ret < 0) { + /* TODO set error bit in status */ + error_report("Could not update PFLASH: %s", strerror(-ret)); + } } } diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index c277b0309d..ac7e34ecbf 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -37,6 +37,7 @@ #include "hw/block/flash.h" #include "hw/qdev-properties.h" #include "qapi/error.h" +#include "qemu/error-report.h" #include "qemu/bitmap.h" #include "qemu/timer.h" #include "sysemu/block-backend.h" @@ -393,13 +394,18 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width) static void pflash_update(PFlashCFI02 *pfl, int offset, int size) { int offset_end; + int ret; if (pfl->blk) { offset_end = offset + size; /* widen to sector boundaries */ offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE); offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE); - blk_pwrite(pfl->blk, offset, pfl->storage + offset, + ret = blk_pwrite(pfl->blk, offset, pfl->storage + offset, offset_end - offset, 0); + if (ret < 0) { + /* TODO set error bit in status */ + error_report("Could not update PFLASH: %s", strerror(-ret)); + } } } From 03556ea920b23c466ce7c1283199033de33ee671 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Mon, 25 May 2020 10:38:03 +0200 Subject: [PATCH 0644/2595] 9pfs: include linux/limits.h for XATTR_SIZE_MAX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit linux/limits.h should be included for the XATTR_SIZE_MAX definition used by v9fs_xattrcreate. Fixes: 3b79ef2cf488 ("9pfs: limit xattr size in xattrcreate") Signed-off-by: Dan Robertson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Christian Schoenebeck Message-Id: <20200515203015.7090-2-dan@dlrobertson.com> Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index a2a14b5979..68c2df7333 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -28,6 +28,7 @@ #include "sysemu/qtest.h" #include "qemu/xxhash.h" #include +#include int open_fd_hw; int total_open_fd; From ed463454efd0ac3042ff772bfe1b1d846dc281a5 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 25 May 2020 10:38:03 +0200 Subject: [PATCH 0645/2595] 9p: Lock directory streams with a CoMutex Locking was introduced in QEMU 2.7 to address the deprecation of readdir_r(3) in glibc 2.24. It turns out that the frontend code is the worst place to handle a critical section with a pthread mutex: the code runs in a coroutine on behalf of the QEMU mainloop and then yields control, waiting for the fsdev backend to process the request in a worker thread. If the client resends another readdir request for the same fid before the previous one finally unlocked the mutex, we're deadlocked. This never bit us because the linux client serializes readdir requests for the same fid, but it is quite easy to demonstrate with a custom client. A good solution could be to narrow the critical section in the worker thread code and to return a copy of the dirent to the frontend, but this causes quite some changes in both 9p.c and codir.c. So, instead of that, in order for people to easily backport the fix to older QEMU versions, let's simply use a CoMutex since all the users for this sit in coroutines. Fixes: 7cde47d4a89d ("9p: add locking to V9fsDir") Reviewed-by: Christian Schoenebeck Message-Id: <158981894794.109297.3530035833368944254.stgit@bahia.lan> Signed-off-by: Greg Kurz --- hw/9pfs/9p.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index dd1c6cb8d2..3ab580764c 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -197,22 +197,22 @@ typedef struct V9fsXattr typedef struct V9fsDir { DIR *stream; - QemuMutex readdir_mutex; + CoMutex readdir_mutex; } V9fsDir; static inline void v9fs_readdir_lock(V9fsDir *dir) { - qemu_mutex_lock(&dir->readdir_mutex); + qemu_co_mutex_lock(&dir->readdir_mutex); } static inline void v9fs_readdir_unlock(V9fsDir *dir) { - qemu_mutex_unlock(&dir->readdir_mutex); + qemu_co_mutex_unlock(&dir->readdir_mutex); } static inline void v9fs_readdir_init(V9fsDir *dir) { - qemu_mutex_init(&dir->readdir_mutex); + qemu_co_mutex_init(&dir->readdir_mutex); } /* From 369ff955a8497988d079c4e3fa1e93c2570c1c69 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Fri, 15 May 2020 01:36:08 +0530 Subject: [PATCH 0646/2595] es1370: check total frame count against current frame A guest user may set channel frame count via es1370_write() such that, in es1370_transfer_audio(), total frame count 'size' is lesser than the number of frames that are processed 'cnt'. int cnt = d->frame_cnt >> 16; int size = d->frame_cnt & 0xffff; if (size < cnt), it results in incorrect calculations leading to OOB access issue(s). Add check to avoid it. Reported-by: Ren Ding Reported-by: Hanqing Zhao Signed-off-by: Prasad J Pandit Message-id: 20200514200608.1744203-1-ppandit@redhat.com Signed-off-by: Gerd Hoffmann --- hw/audio/es1370.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index 89c4dabcd4..5f8a83ff56 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -643,6 +643,9 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, int csc_bytes = (csc + 1) << d->shift; int cnt = d->frame_cnt >> 16; int size = d->frame_cnt & 0xffff; + if (size < cnt) { + return; + } int left = ((size - cnt + 1) << 2) + d->leftover; int transferred = 0; int temp = MIN (max, MIN (left, csc_bytes)); @@ -651,7 +654,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, addr += (cnt << 2) + d->leftover; if (index == ADC_CHANNEL) { - while (temp) { + while (temp > 0) { int acquired, to_copy; to_copy = MIN ((size_t) temp, sizeof (tmpbuf)); @@ -669,7 +672,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, else { SWVoiceOut *voice = s->dac_voice[index]; - while (temp) { + while (temp > 0) { int copied, to_copy; to_copy = MIN ((size_t) temp, sizeof (tmpbuf)); From 2f097e1964dc25a5633a54cae15ff068e9473196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 5 May 2020 12:07:50 +0200 Subject: [PATCH 0647/2595] hw/audio/gus: Use AUDIO_HOST_ENDIANNESS definition from 'audio/audio.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the generic AUDIO_HOST_ENDIANNESS definition instead of a custom one. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200505100750.27332-1-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/audio/gus.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/hw/audio/gus.c b/hw/audio/gus.c index eb4a803fb5..c8df2bde6b 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -41,12 +41,6 @@ #define ldebug(...) #endif -#ifdef HOST_WORDS_BIGENDIAN -#define GUS_ENDIANNESS 1 -#else -#define GUS_ENDIANNESS 0 -#endif - #define TYPE_GUS "gus" #define GUS(obj) OBJECT_CHECK (GUSState, (obj), TYPE_GUS) @@ -256,7 +250,7 @@ static void gus_realizefn (DeviceState *dev, Error **errp) as.freq = s->freq; as.nchannels = 2; as.fmt = AUDIO_FORMAT_S16; - as.endianness = GUS_ENDIANNESS; + as.endianness = AUDIO_HOST_ENDIANNESS; s->voice = AUD_open_out ( &s->card, From 2e44570321056feaa045a51d5e3e8585cea627d0 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Wed, 29 Apr 2020 15:53:58 +1000 Subject: [PATCH 0648/2595] audio/jack: add JACK client audiodev This commit adds a new audiodev backend to allow QEMU to use JACK as both an audio sink and source. Signed-off-by: Geoffrey McRae Message-Id: <20200512101603.E3DB73A038E@moya.office.hostfission.com> Signed-off-by: Gerd Hoffmann --- audio/Makefile.objs | 5 + audio/audio.c | 1 + audio/audio_template.h | 2 + audio/jackaudio.c | 667 +++++++++++++++++++++++++++++++++++++++++ configure | 17 ++ qapi/audio.json | 56 +++- 6 files changed, 746 insertions(+), 2 deletions(-) create mode 100644 audio/jackaudio.c diff --git a/audio/Makefile.objs b/audio/Makefile.objs index d7490a379f..b4a4c11f31 100644 --- a/audio/Makefile.objs +++ b/audio/Makefile.objs @@ -28,3 +28,8 @@ common-obj-$(CONFIG_AUDIO_SDL) += sdl.mo sdl.mo-objs = sdlaudio.o sdl.mo-cflags := $(SDL_CFLAGS) sdl.mo-libs := $(SDL_LIBS) + +# jack module +common-obj-$(CONFIG_AUDIO_JACK) += jack.mo +jack.mo-objs = jackaudio.o +jack.mo-libs := $(JACK_LIBS) diff --git a/audio/audio.c b/audio/audio.c index 7a9e680355..95d9fb16ca 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1969,6 +1969,7 @@ void audio_create_pdos(Audiodev *dev) CASE(ALSA, alsa, Alsa); CASE(COREAUDIO, coreaudio, Coreaudio); CASE(DSOUND, dsound, ); + CASE(JACK, jack, Jack); CASE(OSS, oss, Oss); CASE(PA, pa, Pa); CASE(SDL, sdl, ); diff --git a/audio/audio_template.h b/audio/audio_template.h index 7013d3041f..8dd48ce14e 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -330,6 +330,8 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev) dev->u.coreaudio.TYPE); case AUDIODEV_DRIVER_DSOUND: return dev->u.dsound.TYPE; + case AUDIODEV_DRIVER_JACK: + return qapi_AudiodevJackPerDirectionOptions_base(dev->u.jack.TYPE); case AUDIODEV_DRIVER_OSS: return qapi_AudiodevOssPerDirectionOptions_base(dev->u.oss.TYPE); case AUDIODEV_DRIVER_PA: diff --git a/audio/jackaudio.c b/audio/jackaudio.c new file mode 100644 index 0000000000..722ddb1dfe --- /dev/null +++ b/audio/jackaudio.c @@ -0,0 +1,667 @@ +/* + * QEMU JACK Audio Connection Kit Client + * + * Copyright (c) 2020 Geoffrey McRae (gnif) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/atomic.h" +#include "qemu-common.h" +#include "audio.h" + +#define AUDIO_CAP "jack" +#include "audio_int.h" + +#include +#include + +struct QJack; + +typedef enum QJackState { + QJACK_STATE_DISCONNECTED, + QJACK_STATE_STOPPED, + QJACK_STATE_RUNNING, + QJACK_STATE_SHUTDOWN +} +QJackState; + +typedef struct QJackBuffer { + int channels; + int frames; + uint32_t used; + int rptr, wptr; + float **data; +} +QJackBuffer; + +typedef struct QJackClient { + AudiodevJackPerDirectionOptions *opt; + + bool out; + bool finished; + bool connect_ports; + int packets; + + QJackState state; + jack_client_t *client; + jack_nframes_t freq; + + struct QJack *j; + int nchannels; + int buffersize; + jack_port_t **port; + QJackBuffer fifo; +} +QJackClient; + +typedef struct QJackOut { + HWVoiceOut hw; + QJackClient c; +} +QJackOut; + +typedef struct QJackIn { + HWVoiceIn hw; + QJackClient c; +} +QJackIn; + +static int qjack_client_init(QJackClient *c); +static void qjack_client_connect_ports(QJackClient *c); +static void qjack_client_fini(QJackClient *c); + +static void qjack_buffer_create(QJackBuffer *buffer, int channels, int frames) +{ + buffer->channels = channels; + buffer->frames = frames; + buffer->used = 0; + buffer->rptr = 0; + buffer->wptr = 0; + buffer->data = g_malloc(channels * sizeof(float *)); + for (int i = 0; i < channels; ++i) { + buffer->data[i] = g_malloc(frames * sizeof(float)); + } +} + +static void qjack_buffer_clear(QJackBuffer *buffer) +{ + assert(buffer->data); + atomic_store_release(&buffer->used, 0); + buffer->rptr = 0; + buffer->wptr = 0; +} + +static void qjack_buffer_free(QJackBuffer *buffer) +{ + if (!buffer->data) { + return; + } + + for (int i = 0; i < buffer->channels; ++i) { + g_free(buffer->data[i]); + } + + g_free(buffer->data); + buffer->data = NULL; +} + +/* write PCM interleaved */ +static int qjack_buffer_write(QJackBuffer *buffer, float *data, int size) +{ + assert(buffer->data); + const int samples = size / sizeof(float); + int frames = samples / buffer->channels; + const int avail = buffer->frames - atomic_load_acquire(&buffer->used); + + if (frames > avail) { + frames = avail; + } + + int copy = frames; + int wptr = buffer->wptr; + + while (copy) { + + for (int c = 0; c < buffer->channels; ++c) { + buffer->data[c][wptr] = *data++; + } + + if (++wptr == buffer->frames) { + wptr = 0; + } + + --copy; + } + + buffer->wptr = wptr; + + atomic_add(&buffer->used, frames); + return frames * buffer->channels * sizeof(float); +}; + +/* write PCM linear */ +static int qjack_buffer_write_l(QJackBuffer *buffer, float **dest, int frames) +{ + assert(buffer->data); + const int avail = buffer->frames - atomic_load_acquire(&buffer->used); + int wptr = buffer->wptr; + + if (frames > avail) { + frames = avail; + } + + int right = buffer->frames - wptr; + if (right > frames) { + right = frames; + } + + const int left = frames - right; + for (int c = 0; c < buffer->channels; ++c) { + memcpy(buffer->data[c] + wptr, dest[c] , right * sizeof(float)); + memcpy(buffer->data[c] , dest[c] + right, left * sizeof(float)); + } + + wptr += frames; + if (wptr >= buffer->frames) { + wptr -= buffer->frames; + } + buffer->wptr = wptr; + + atomic_add(&buffer->used, frames); + return frames; +} + +/* read PCM interleaved */ +static int qjack_buffer_read(QJackBuffer *buffer, float *dest, int size) +{ + assert(buffer->data); + const int samples = size / sizeof(float); + int frames = samples / buffer->channels; + const int avail = atomic_load_acquire(&buffer->used); + + if (frames > avail) { + frames = avail; + } + + int copy = frames; + int rptr = buffer->rptr; + + while (copy) { + + for (int c = 0; c < buffer->channels; ++c) { + *dest++ = buffer->data[c][rptr]; + } + + if (++rptr == buffer->frames) { + rptr = 0; + } + + --copy; + } + + buffer->rptr = rptr; + + atomic_sub(&buffer->used, frames); + return frames * buffer->channels * sizeof(float); +} + +/* read PCM linear */ +static int qjack_buffer_read_l(QJackBuffer *buffer, float **dest, int frames) +{ + assert(buffer->data); + int copy = frames; + const int used = atomic_load_acquire(&buffer->used); + int rptr = buffer->rptr; + + if (copy > used) { + copy = used; + } + + int right = buffer->frames - rptr; + if (right > copy) { + right = copy; + } + + const int left = copy - right; + for (int c = 0; c < buffer->channels; ++c) { + memcpy(dest[c] , buffer->data[c] + rptr, right * sizeof(float)); + memcpy(dest[c] + right, buffer->data[c] , left * sizeof(float)); + } + + rptr += copy; + if (rptr >= buffer->frames) { + rptr -= buffer->frames; + } + buffer->rptr = rptr; + + atomic_sub(&buffer->used, copy); + return copy; +} + +static int qjack_process(jack_nframes_t nframes, void *arg) +{ + QJackClient *c = (QJackClient *)arg; + + if (c->state != QJACK_STATE_RUNNING) { + return 0; + } + + /* get the buffers for the ports */ + float *buffers[c->nchannels]; + for (int i = 0; i < c->nchannels; ++i) { + buffers[i] = jack_port_get_buffer(c->port[i], nframes); + } + + if (c->out) { + qjack_buffer_read_l(&c->fifo, buffers, nframes); + } else { + qjack_buffer_write_l(&c->fifo, buffers, nframes); + } + + return 0; +} + +static void qjack_port_registration(jack_port_id_t port, int reg, void *arg) +{ + if (reg) { + QJackClient *c = (QJackClient *)arg; + c->connect_ports = true; + } +} + +static int qjack_xrun(void *arg) +{ + QJackClient *c = (QJackClient *)arg; + if (c->state != QJACK_STATE_RUNNING) { + return 0; + } + + qjack_buffer_clear(&c->fifo); + return 0; +} + +static void qjack_shutdown(void *arg) +{ + QJackClient *c = (QJackClient *)arg; + c->state = QJACK_STATE_SHUTDOWN; +} + +static void qjack_client_recover(QJackClient *c) +{ + if (c->state == QJACK_STATE_SHUTDOWN) { + qjack_client_fini(c); + } + + /* packets is used simply to throttle this */ + if (c->state == QJACK_STATE_DISCONNECTED && + c->packets % 100 == 0) { + + /* if not finished then attempt to recover */ + if (!c->finished) { + dolog("attempting to reconnect to server\n"); + qjack_client_init(c); + } + } +} + +static size_t qjack_write(HWVoiceOut *hw, void *buf, size_t len) +{ + QJackOut *jo = (QJackOut *)hw; + ++jo->c.packets; + + if (jo->c.state != QJACK_STATE_RUNNING) { + qjack_client_recover(&jo->c); + return len; + } + + qjack_client_connect_ports(&jo->c); + return qjack_buffer_write(&jo->c.fifo, buf, len); +} + +static size_t qjack_read(HWVoiceIn *hw, void *buf, size_t len) +{ + QJackIn *ji = (QJackIn *)hw; + ++ji->c.packets; + + if (ji->c.state != QJACK_STATE_RUNNING) { + qjack_client_recover(&ji->c); + return len; + } + + qjack_client_connect_ports(&ji->c); + return qjack_buffer_read(&ji->c.fifo, buf, len); +} + +static void qjack_client_connect_ports(QJackClient *c) +{ + if (!c->connect_ports || !c->opt->connect_ports) { + return; + } + + c->connect_ports = false; + const char **ports; + ports = jack_get_ports(c->client, c->opt->connect_ports, NULL, + c->out ? JackPortIsInput : JackPortIsOutput); + + if (!ports) { + return; + } + + for (int i = 0; i < c->nchannels && ports[i]; ++i) { + const char *p = jack_port_name(c->port[i]); + if (jack_port_connected_to(c->port[i], ports[i])) { + continue; + } + + if (c->out) { + dolog("connect %s -> %s\n", p, ports[i]); + jack_connect(c->client, p, ports[i]); + } else { + dolog("connect %s -> %s\n", ports[i], p); + jack_connect(c->client, ports[i], p); + } + } +} + +static int qjack_client_init(QJackClient *c) +{ + jack_status_t status; + char client_name[jack_client_name_size()]; + jack_options_t options = JackNullOption; + + c->finished = false; + c->connect_ports = true; + + snprintf(client_name, sizeof(client_name), "%s-%s", + c->out ? "out" : "in", + c->opt->client_name ? c->opt->client_name : qemu_get_vm_name()); + + if (c->opt->exact_name) { + options |= JackUseExactName; + } + + if (!c->opt->start_server) { + options |= JackNoStartServer; + } + + if (c->opt->server_name) { + options |= JackServerName; + } + + c->client = jack_client_open(client_name, options, &status, + c->opt->server_name); + + if (c->client == NULL) { + dolog("jack_client_open failed: status = 0x%2.0x\n", status); + if (status & JackServerFailed) { + dolog("unable to connect to JACK server\n"); + } + return -1; + } + + c->freq = jack_get_sample_rate(c->client); + + if (status & JackServerStarted) { + dolog("JACK server started\n"); + } + + if (status & JackNameNotUnique) { + dolog("JACK unique name assigned %s\n", + jack_get_client_name(c->client)); + } + + jack_set_process_callback(c->client, qjack_process , c); + jack_set_port_registration_callback(c->client, qjack_port_registration, c); + jack_set_xrun_callback(c->client, qjack_xrun, c); + jack_on_shutdown(c->client, qjack_shutdown, c); + + /* + * ensure the buffersize is no smaller then 512 samples, some (all?) qemu + * virtual devices do not work correctly otherwise + */ + if (c->buffersize < 512) { + c->buffersize = 512; + } + + /* create a 2 period buffer */ + qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 2); + + /* allocate and register the ports */ + c->port = g_malloc(sizeof(jack_port_t *) * c->nchannels); + for (int i = 0; i < c->nchannels; ++i) { + + char port_name[16]; + snprintf( + port_name, + sizeof(port_name), + c->out ? "output %d" : "input %d", + i); + + c->port[i] = jack_port_register( + c->client, + port_name, + JACK_DEFAULT_AUDIO_TYPE, + c->out ? JackPortIsOutput : JackPortIsInput, + 0); + } + + /* activate the session */ + jack_activate(c->client); + c->buffersize = jack_get_buffer_size(c->client); + + qjack_client_connect_ports(c); + c->state = QJACK_STATE_RUNNING; + return 0; +} + +static int qjack_init_out(HWVoiceOut *hw, struct audsettings *as, + void *drv_opaque) +{ + QJackOut *jo = (QJackOut *)hw; + Audiodev *dev = (Audiodev *)drv_opaque; + + if (jo->c.state != QJACK_STATE_DISCONNECTED) { + return 0; + } + + jo->c.out = true; + jo->c.nchannels = as->nchannels; + jo->c.opt = dev->u.jack.out; + int ret = qjack_client_init(&jo->c); + if (ret != 0) { + return ret; + } + + /* report the buffer size to qemu */ + hw->samples = jo->c.buffersize; + + /* report the audio format we support */ + struct audsettings os = { + .freq = jo->c.freq, + .nchannels = jo->c.nchannels, + .fmt = AUDIO_FORMAT_F32, + .endianness = 0 + }; + audio_pcm_init_info(&hw->info, &os); + + dolog("JACK output configured for %dHz (%d samples)\n", + jo->c.freq, jo->c.buffersize); + + return 0; +} + +static int qjack_init_in(HWVoiceIn *hw, struct audsettings *as, + void *drv_opaque) +{ + QJackIn *ji = (QJackIn *)hw; + Audiodev *dev = (Audiodev *)drv_opaque; + + if (ji->c.state != QJACK_STATE_DISCONNECTED) { + return 0; + } + + ji->c.out = false; + ji->c.nchannels = as->nchannels; + ji->c.opt = dev->u.jack.in; + int ret = qjack_client_init(&ji->c); + if (ret != 0) { + return ret; + } + + /* report the buffer size to qemu */ + hw->samples = ji->c.buffersize; + + /* report the audio format we support */ + struct audsettings is = { + .freq = ji->c.freq, + .nchannels = ji->c.nchannels, + .fmt = AUDIO_FORMAT_F32, + .endianness = 0 + }; + audio_pcm_init_info(&hw->info, &is); + + dolog("JACK input configured for %dHz (%d samples)\n", + ji->c.freq, ji->c.buffersize); + + return 0; +} + +static void qjack_client_fini(QJackClient *c) +{ + switch (c->state) { + case QJACK_STATE_RUNNING: + /* fallthrough */ + + case QJACK_STATE_STOPPED: + for (int i = 0; i < c->nchannels; ++i) { + jack_port_unregister(c->client, c->port[i]); + } + jack_deactivate(c->client); + /* fallthrough */ + + case QJACK_STATE_SHUTDOWN: + jack_client_close(c->client); + /* fallthrough */ + + case QJACK_STATE_DISCONNECTED: + break; + } + + qjack_buffer_free(&c->fifo); + g_free(c->port); + + c->state = QJACK_STATE_DISCONNECTED; +} + +static void qjack_fini_out(HWVoiceOut *hw) +{ + QJackOut *jo = (QJackOut *)hw; + jo->c.finished = true; + qjack_client_fini(&jo->c); +} + +static void qjack_fini_in(HWVoiceIn *hw) +{ + QJackIn *ji = (QJackIn *)hw; + ji->c.finished = true; + qjack_client_fini(&ji->c); +} + +static void qjack_enable_out(HWVoiceOut *hw, bool enable) +{ +} + +static void qjack_enable_in(HWVoiceIn *hw, bool enable) +{ +} + +static int qjack_thread_creator(jack_native_thread_t *thread, + const pthread_attr_t *attr, void *(*function)(void *), void *arg) +{ + int ret = pthread_create(thread, attr, function, arg); + if (ret != 0) { + return ret; + } + + /* set the name of the thread */ + pthread_setname_np(*thread, "jack-client"); + + return ret; +} + +static void *qjack_init(Audiodev *dev) +{ + assert(dev->driver == AUDIODEV_DRIVER_JACK); + + dev->u.jack.has_in = false; + + return dev; +} + +static void qjack_fini(void *opaque) +{ +} + +static struct audio_pcm_ops jack_pcm_ops = { + .init_out = qjack_init_out, + .fini_out = qjack_fini_out, + .write = qjack_write, + .run_buffer_out = audio_generic_run_buffer_out, + .enable_out = qjack_enable_out, + + .init_in = qjack_init_in, + .fini_in = qjack_fini_in, + .read = qjack_read, + .enable_in = qjack_enable_in +}; + +static struct audio_driver jack_driver = { + .name = "jack", + .descr = "JACK Audio Connection Kit Client", + .init = qjack_init, + .fini = qjack_fini, + .pcm_ops = &jack_pcm_ops, + .can_be_default = 1, + .max_voices_out = INT_MAX, + .max_voices_in = INT_MAX, + .voice_size_out = sizeof(QJackOut), + .voice_size_in = sizeof(QJackIn) +}; + +static void qjack_error(const char *msg) +{ + dolog("E: %s\n", msg); +} + +static void qjack_info(const char *msg) +{ + dolog("I: %s\n", msg); +} + +static void register_audio_jack(void) +{ + audio_driver_register(&jack_driver); + jack_set_thread_creator(qjack_thread_creator); + jack_set_error_function(qjack_error); + jack_set_info_function(qjack_info); +} +type_init(register_audio_jack); diff --git a/configure b/configure index 2fc05c4465..b969dee675 100755 --- a/configure +++ b/configure @@ -3629,6 +3629,22 @@ for drv in $audio_drv_list; do oss_libs="$oss_lib" ;; + jack | try-jack) + if $pkg_config jack --exists; then + jack_libs=$($pkg_config jack --libs) + if test "$drv" = "try-jack"; then + audio_drv_list=$(echo "$audio_drv_list" | sed -e 's/try-jack/jack/') + fi + else + if test "$drv" = "try-jack"; then + audio_drv_list=$(echo "$audio_drv_list" | sed -e 's/try-jack//') + else + error_exit "$drv check failed" \ + "Make sure to have the $drv libs and headers installed." + fi + fi + ;; + *) echo "$audio_possible_drivers" | grep -q "\<$drv\>" || { error_exit "Unknown driver '$drv' selected" \ @@ -6904,6 +6920,7 @@ echo "PULSE_LIBS=$pulse_libs" >> $config_host_mak echo "COREAUDIO_LIBS=$coreaudio_libs" >> $config_host_mak echo "DSOUND_LIBS=$dsound_libs" >> $config_host_mak echo "OSS_LIBS=$oss_libs" >> $config_host_mak +echo "JACK_LIBS=$jack_libs" >> $config_host_mak if test "$audio_win_int" = "yes" ; then echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak fi diff --git a/qapi/audio.json b/qapi/audio.json index c31251f45b..f62bd0d7f6 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -152,6 +152,55 @@ '*out': 'AudiodevPerDirectionOptions', '*latency': 'uint32' } } +## +# @AudiodevJackPerDirectionOptions: +# +# Options of the JACK backend that are used for both playback and +# recording. +# +# @server-name: select from among several possible concurrent server instances +# (default: environment variable $JACK_DEFAULT_SERVER if set, else "default") +# +# @client-name: the client name to use. The server will modify this name to +# create a unique variant, if needed unless @exact-name is true (default: the +# guest's name) +# +# @connect-ports: if set, a regular expression of JACK client port name(s) to +# monitor for and automatically connect to +# +# @start-server: start a jack server process if one is not already present +# (default: false) +# +# @exact-name: use the exact name requested otherwise JACK automatically +# generates a unique one, if needed (default: false) +# +# Since: 5.1 +## +{ 'struct': 'AudiodevJackPerDirectionOptions', + 'base': 'AudiodevPerDirectionOptions', + 'data': { + '*server-name': 'str', + '*client-name': 'str', + '*connect-ports': 'str', + '*start-server': 'bool', + '*exact-name': 'bool' } } + +## +# @AudiodevJackOptions: +# +# Options of the JACK audio backend. +# +# @in: options of the capture stream +# +# @out: options of the playback stream +# +# Since: 5.1 +## +{ 'struct': 'AudiodevJackOptions', + 'data': { + '*in': 'AudiodevJackPerDirectionOptions', + '*out': 'AudiodevJackPerDirectionOptions' } } + ## # @AudiodevOssPerDirectionOptions: # @@ -297,11 +346,13 @@ # # An enumeration of possible audio backend drivers. # +# @jack: JACK audio backend (since 5.1) +# # Since: 4.0 ## { 'enum': 'AudiodevDriver', - 'data': [ 'none', 'alsa', 'coreaudio', 'dsound', 'oss', 'pa', 'sdl', - 'spice', 'wav' ] } + 'data': [ 'none', 'alsa', 'coreaudio', 'dsound', 'jack', 'oss', 'pa', + 'sdl', 'spice', 'wav' ] } ## # @Audiodev: @@ -327,6 +378,7 @@ 'alsa': 'AudiodevAlsaOptions', 'coreaudio': 'AudiodevCoreaudioOptions', 'dsound': 'AudiodevDsoundOptions', + 'jack': 'AudiodevJackOptions', 'oss': 'AudiodevOssOptions', 'pa': 'AudiodevPaOptions', 'sdl': 'AudiodevGenericOptions', From cf45183b718f02b1369e18c795dc51bc1821245d Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Thu, 21 May 2020 12:26:25 -0700 Subject: [PATCH 0649/2595] Revert "9p: init_in_iov_from_pdu can truncate the size" This reverts commit 16724a173049ac29c7b5ade741da93a0f46edff7. It causes https://bugs.launchpad.net/bugs/1877688. Signed-off-by: Stefano Stabellini Reviewed-by: Christian Schoenebeck Message-Id: <20200521192627.15259-1-sstabellini@kernel.org> Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 33 +++++++++++---------------------- hw/9pfs/9p.h | 2 +- hw/9pfs/virtio-9p-device.c | 11 ++++------- hw/9pfs/xen-9p-backend.c | 15 ++++++--------- 4 files changed, 22 insertions(+), 39 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 68c2df7333..45a788f6e6 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -2103,29 +2103,22 @@ out_nofid: * with qemu_iovec_destroy(). */ static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu, - size_t skip, size_t *size, + size_t skip, size_t size, bool is_write) { QEMUIOVector elem; struct iovec *iov; unsigned int niov; - size_t alloc_size = *size + skip; if (is_write) { - pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov, alloc_size); + pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov, size + skip); } else { - pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, &alloc_size); - } - - if (alloc_size < skip) { - *size = 0; - } else { - *size = alloc_size - skip; + pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size + skip); } qemu_iovec_init_external(&elem, iov, niov); qemu_iovec_init(qiov, niov); - qemu_iovec_concat(qiov, &elem, skip, *size); + qemu_iovec_concat(qiov, &elem, skip, size); } static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, @@ -2133,14 +2126,15 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, { ssize_t err; size_t offset = 7; - size_t read_count; + uint64_t read_count; QEMUIOVector qiov_full; if (fidp->fs.xattr.len < off) { read_count = 0; - } else if (fidp->fs.xattr.len - off < max_count) { - read_count = fidp->fs.xattr.len - off; } else { + read_count = fidp->fs.xattr.len - off; + } + if (read_count > max_count) { read_count = max_count; } err = pdu_marshal(pdu, offset, "d", read_count); @@ -2149,7 +2143,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, } offset += err; - v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, &read_count, false); + v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, read_count, false); err = v9fs_pack(qiov_full.iov, qiov_full.niov, 0, ((char *)fidp->fs.xattr.value) + off, read_count); @@ -2278,11 +2272,9 @@ static void coroutine_fn v9fs_read(void *opaque) QEMUIOVector qiov_full; QEMUIOVector qiov; int32_t len; - size_t size = max_count; - v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, &size, false); + v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false); qemu_iovec_init(&qiov, qiov_full.niov); - max_count = size; do { qemu_iovec_reset(&qiov); qemu_iovec_concat(&qiov, &qiov_full, count, qiov_full.size - count); @@ -2533,7 +2525,6 @@ static void coroutine_fn v9fs_write(void *opaque) int32_t len = 0; int32_t total = 0; size_t offset = 7; - size_t size; V9fsFidState *fidp; V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; @@ -2546,9 +2537,7 @@ static void coroutine_fn v9fs_write(void *opaque) return; } offset += err; - size = count; - v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, &size, true); - count = size; + v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true); trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov); fidp = get_fid(pdu, fid); diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 3ab580764c..ee2271663c 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -436,7 +436,7 @@ struct V9fsTransport { ssize_t (*pdu_vunmarshal)(V9fsPDU *pdu, size_t offset, const char *fmt, va_list ap); void (*init_in_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov, - unsigned int *pniov, size_t *size); + unsigned int *pniov, size_t size); void (*init_out_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov, unsigned int *pniov, size_t size); void (*push_and_notify)(V9fsPDU *pdu); diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index e5b44977c7..36f3aa9352 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -147,22 +147,19 @@ static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset, } static void virtio_init_in_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, - unsigned int *pniov, size_t *size) + unsigned int *pniov, size_t size) { V9fsState *s = pdu->s; V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); VirtQueueElement *elem = v->elems[pdu->idx]; size_t buf_size = iov_size(elem->in_sg, elem->in_num); - if (buf_size < P9_IOHDRSZ) { + if (buf_size < size) { VirtIODevice *vdev = VIRTIO_DEVICE(v); virtio_error(vdev, - "VirtFS reply type %d needs %zu bytes, buffer has %zu, less than minimum", - pdu->id + 1, *size, buf_size); - } - if (buf_size < *size) { - *size = buf_size; + "VirtFS reply type %d needs %zu bytes, buffer has %zu", + pdu->id + 1, size, buf_size); } *piov = elem->in_sg; diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index f04caabfe5..fc197f6c8a 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -188,7 +188,7 @@ static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu, static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, unsigned int *pniov, - size_t *size) + size_t size) { Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state); Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings]; @@ -198,19 +198,16 @@ static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu, g_free(ring->sg); ring->sg = g_new0(struct iovec, 2); - xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, *size); + xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size); buf_size = iov_size(ring->sg, num); - if (buf_size < P9_IOHDRSZ) { - xen_pv_printf(&xen_9pfs->xendev, 0, "Xen 9pfs reply type %d needs " - "%zu bytes, buffer has %zu, less than minimum\n", - pdu->id + 1, *size, buf_size); + if (buf_size < size) { + xen_pv_printf(&xen_9pfs->xendev, 0, "Xen 9pfs request type %d" + "needs %zu bytes, buffer has %zu\n", pdu->id, size, + buf_size); xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing); xen_9pfs_disconnect(&xen_9pfs->xendev); } - if (buf_size < *size) { - *size = buf_size; - } *piov = ring->sg; *pniov = num; From a4c4d462729466c4756bac8a0a8d77eb63b21ef7 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Thu, 21 May 2020 12:26:26 -0700 Subject: [PATCH 0650/2595] xen/9pfs: yield when there isn't enough room on the ring Instead of truncating replies, which is problematic, wait until the client reads more data and frees bytes on the reply ring. Do that by calling qemu_coroutine_yield(). The corresponding qemu_coroutine_enter_if_inactive() is called from xen_9pfs_bh upon receiving the next notification from the client. We need to be careful to avoid races in case xen_9pfs_bh and the coroutine are both active at the same time. In xen_9pfs_bh, wait until either the critical section is over (ring->co == NULL) or until the coroutine becomes inactive (qemu_coroutine_yield() was called) before continuing. Then, simply wake up the coroutine if it is inactive. Signed-off-by: Stefano Stabellini Reviewed-by: Christian Schoenebeck Message-Id: <20200521192627.15259-2-sstabellini@kernel.org> Signed-off-by: Greg Kurz --- hw/9pfs/xen-9p-backend.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index fc197f6c8a..3c84c86ab8 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -37,6 +37,7 @@ typedef struct Xen9pfsRing { struct iovec *sg; QEMUBH *bh; + Coroutine *co; /* local copies, so that we can read/write PDU data directly from * the ring */ @@ -198,16 +199,20 @@ static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu, g_free(ring->sg); ring->sg = g_new0(struct iovec, 2); - xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size); + ring->co = qemu_coroutine_self(); + /* make sure other threads see ring->co changes before continuing */ + smp_wmb(); +again: + xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size); buf_size = iov_size(ring->sg, num); if (buf_size < size) { - xen_pv_printf(&xen_9pfs->xendev, 0, "Xen 9pfs request type %d" - "needs %zu bytes, buffer has %zu\n", pdu->id, size, - buf_size); - xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing); - xen_9pfs_disconnect(&xen_9pfs->xendev); + qemu_coroutine_yield(); + goto again; } + ring->co = NULL; + /* make sure other threads see ring->co changes before continuing */ + smp_wmb(); *piov = ring->sg; *pniov = num; @@ -292,6 +297,20 @@ static int xen_9pfs_receive(Xen9pfsRing *ring) static void xen_9pfs_bh(void *opaque) { Xen9pfsRing *ring = opaque; + bool wait; + +again: + wait = ring->co != NULL && qemu_coroutine_entered(ring->co); + /* paired with the smb_wmb barriers in xen_9pfs_init_in_iov_from_pdu */ + smp_rmb(); + if (wait) { + cpu_relax(); + goto again; + } + + if (ring->co != NULL) { + qemu_coroutine_enter_if_inactive(ring->co); + } xen_9pfs_receive(ring); } From 84af75577cceb195b044e2d5ba6d940206b169ca Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Thu, 21 May 2020 12:26:27 -0700 Subject: [PATCH 0651/2595] xen/9pfs: increase max ring order to 9 The max order allowed by the protocol is 9. Increase the max order supported by QEMU to 9 to increase performance. Signed-off-by: Stefano Stabellini Reviewed-by: Christian Schoenebeck Message-Id: <20200521192627.15259-3-sstabellini@kernel.org> Signed-off-by: Greg Kurz --- hw/9pfs/xen-9p-backend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index 3c84c86ab8..a969fcc54c 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -21,7 +21,7 @@ #define VERSIONS "1" #define MAX_RINGS 8 -#define MAX_RING_ORDER 8 +#define MAX_RING_ORDER 9 typedef struct Xen9pfsRing { struct Xen9pfsDev *priv; From 9c61fcc89a70256c19047d251aa44f666f06089c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Sat, 23 May 2020 22:17:12 +0200 Subject: [PATCH 0652/2595] audio/mixeng: fix clang 10+ warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code in CONV_NATURAL_FLOAT() and CLIP_NATURAL_FLOAT() seems to use the constant 2^31-0.5 to convert float to integer and back. But the float type lacks the required precision and the constant used for the conversion is 2^31. This is equiva- lent to a [-1.f, 1.f] <-> [INT32_MIN, INT32_MAX + 1] mapping. This patch explicitly writes down the used constant. The compiler generated code doesn't change. The constant 2^31 has an exact float representation and the clang 10 compiler stops complaining about an implicit int to float conversion with a changed value. A few notes: - The conversion of 1.f to INT32_MAX + 1 doesn't overflow. The type of the destination variable is int64_t. - At a later stage one of the clip_* functions in audio/mixeng_template.h limits INT32_MAX + 1 to the integer range. - The clip_natural_float_* functions in audio/mixeng.c convert INT32_MAX and INT32_MAX + 1 to 1.f. Buglink: https://bugs.launchpad.net/bugs/1878627 Signed-off-by: Volker Rümelin Message-id: 20200523201712.23908-1-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann --- audio/mixeng.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/audio/mixeng.c b/audio/mixeng.c index 739a500449..924dcb858a 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -271,11 +271,12 @@ f_sample *mixeng_clip[2][2][2][3] = { #define CONV_NATURAL_FLOAT(x) (x) #define CLIP_NATURAL_FLOAT(x) (x) #else -static const float float_scale = UINT_MAX / 2.f; +/* macros to map [-1.f, 1.f] <-> [INT32_MIN, INT32_MAX + 1] */ +static const float float_scale = (int64_t)INT32_MAX + 1; #define CONV_NATURAL_FLOAT(x) ((x) * float_scale) #ifdef RECIPROCAL -static const float float_scale_reciprocal = 2.f / UINT_MAX; +static const float float_scale_reciprocal = 1.f / ((int64_t)INT32_MAX + 1); #define CLIP_NATURAL_FLOAT(x) ((x) * float_scale_reciprocal) #else #define CLIP_NATURAL_FLOAT(x) ((x) / float_scale) From cbaf25d1f59ee13fc7542a06ea70784f2e000c04 Mon Sep 17 00:00:00 2001 From: Bruce Rogers Date: Thu, 21 May 2020 11:29:31 -0600 Subject: [PATCH 0653/2595] audio: fix wavcapture segfault MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 571a8c522e caused the HMP wavcapture command to segfault when processing audio data in audio_pcm_sw_write(), where a NULL sw->hw->pcm_ops is dereferenced. This fix checks that the pointer is valid before dereferincing it. A similar fix is also made in the parallel function audio_pcm_sw_read(). Fixes: 571a8c522e (audio: split ctl_* functions into enable_* and volume_*) Signed-off-by: Bruce Rogers Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200521172931.121903-1-brogers@suse.com Signed-off-by: Gerd Hoffmann --- audio/audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 95d9fb16ca..ce8c6dec5f 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -649,7 +649,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size) total += isamp; } - if (!hw->pcm_ops->volume_in) { + if (hw->pcm_ops && !hw->pcm_ops->volume_in) { mixeng_volume (sw->buf, ret, &sw->vol); } @@ -736,7 +736,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size) if (swlim) { sw->conv (sw->buf, buf, swlim); - if (!sw->hw->pcm_ops->volume_out) { + if (sw->hw->pcm_ops && !sw->hw->pcm_ops->volume_out) { mixeng_volume (sw->buf, swlim, &sw->vol); } } From e709d2ac47e71a879294f20e3fb994b7aea55226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 5 May 2020 15:25:57 +0200 Subject: [PATCH 0654/2595] audio: Let audio_sample_to_uint64() use const samples argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The samples are the input to convert to u64. As we should not modify them, mark the argument const. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200505132603.8575-2-f4bug@amsat.org> Signed-off-by: Gerd Hoffmann --- audio/audio.h | 2 +- audio/mixeng.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/audio/audio.h b/audio/audio.h index 0db3c7dd5e..f27a12298f 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -163,7 +163,7 @@ int wav_start_capture(AudioState *state, CaptureState *s, const char *path, bool audio_is_cleaning_up(void); void audio_cleanup(void); -void audio_sample_to_uint64(void *samples, int pos, +void audio_sample_to_uint64(const void *samples, int pos, uint64_t *left, uint64_t *right); void audio_sample_from_uint64(void *samples, int pos, uint64_t left, uint64_t right); diff --git a/audio/mixeng.c b/audio/mixeng.c index 924dcb858a..f27deb165b 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -339,10 +339,10 @@ f_sample *mixeng_clip_float[2] = { clip_natural_float_from_stereo, }; -void audio_sample_to_uint64(void *samples, int pos, +void audio_sample_to_uint64(const void *samples, int pos, uint64_t *left, uint64_t *right) { - struct st_sample *sample = samples; + const struct st_sample *sample = samples; sample += pos; #ifdef FLOAT_MIXENG error_report( From 57a878ed4f76a3a6b06dd8fa7df846adad6633ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 5 May 2020 15:25:58 +0200 Subject: [PATCH 0655/2595] audio: Let capture_callback handler use const buffer argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The buffer is the captured input to pass to backends. As we should not modify it, mark the argument const. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200505132603.8575-3-f4bug@amsat.org> Signed-off-by: Gerd Hoffmann --- audio/audio.h | 2 +- audio/wavcapture.c | 2 +- ui/vnc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/audio/audio.h b/audio/audio.h index f27a12298f..b883ebfb1f 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -60,7 +60,7 @@ typedef enum { struct audio_capture_ops { void (*notify) (void *opaque, audcnotification_e cmd); - void (*capture) (void *opaque, void *buf, int size); + void (*capture) (void *opaque, const void *buf, int size); void (*destroy) (void *opaque); }; diff --git a/audio/wavcapture.c b/audio/wavcapture.c index 8d7ce2eda1..17e87ed6f4 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -71,7 +71,7 @@ static void wav_destroy (void *opaque) g_free (wav->path); } -static void wav_capture (void *opaque, void *buf, int size) +static void wav_capture(void *opaque, const void *buf, int size) { WAVState *wav = opaque; diff --git a/ui/vnc.c b/ui/vnc.c index 1d7138a3a0..12a12714e1 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1177,7 +1177,7 @@ static void audio_capture_destroy(void *opaque) { } -static void audio_capture(void *opaque, void *buf, int size) +static void audio_capture(void *opaque, const void *buf, int size) { VncState *vs = opaque; From b3b8a1fea6ed5004bbad2f70833caee70402bf02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 15 May 2020 10:42:09 +0200 Subject: [PATCH 0656/2595] hw/mips/mips_fulong2e: Remove unused 'audio/audio.h' include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Fuloong machine never had to use "audio/audio.h", remove it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Huacai Chen Message-id: 20200515084209.9419-1-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/mips/mips_fulong2e.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index ef02d54b33..05b9efa516 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -33,7 +33,6 @@ #include "hw/mips/mips.h" #include "hw/mips/cpudevs.h" #include "hw/pci/pci.h" -#include "audio/audio.h" #include "qemu/log.h" #include "hw/loader.h" #include "hw/ide/pci.h" From 97eeef8aeeac1c5fb64f6785bbcef2e57f7c62ce Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 8 Apr 2020 17:16:20 +0800 Subject: [PATCH 0657/2595] MAINTAINERS: Add Huacai Chen as fuloong2e co-maintainer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I submitted the MIPS/fuloong2e support about ten years ago, and after that I became a MIPS kernel developer. Last year, Philippe Mathieu- Daudé asked me that whether I can be a reviewer of MIPS/fuloong2e, and I promised that I will do some QEMU work in the next year (i.e., 2020 and later). I think now (and also in future) I can have some spare time, so I can finally do some real work on QEMU/MIPS. And if possible, I hope I can be a co-maintainer of MIPS/fuloong2e. Cc: Jiaxun Yang Signed-off-by: Huacai Chen Message-Id: <1586337380-25217-3-git-send-email-chenhc@lemote.com> [PMD: Added Jiaxun Yang as reviewer] Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Message-Id: <20200510210128.18343-2-f4bug@amsat.org> --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3690f313c3..8f597aae12 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1082,8 +1082,10 @@ S: Obsolete F: hw/mips/mips_r4k.c Fulong 2E +M: Huacai Chen M: Philippe Mathieu-Daudé M: Aleksandar Markovic +R: Jiaxun Yang S: Odd Fixes F: hw/mips/mips_fulong2e.c F: hw/isa/vt82c686.c From abc82de356f636d70ac36e202c989a5e978dbae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 3 Feb 2019 22:37:26 +0100 Subject: [PATCH 0658/2595] hw/pci-host: Use CONFIG_PCI_BONITO to select the Bonito North Bridge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ease the kconfig selection by introducing CONFIG_PCI_BONITO to select the Bonito North Bridge. Reviewed-by: Aleksandar Markovic Signed-off-by: Philippe Mathieu-Daudé Message-id: <20200510210128.18343-6-f4bug@amsat.org> Reviewed-by: Huacai Chen Signed-off-by: Philippe Mathieu-Daudé --- hw/mips/Kconfig | 1 + hw/pci-host/Kconfig | 4 ++++ hw/pci-host/Makefile.objs | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index 2c2adbc42a..2240504dff 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -43,6 +43,7 @@ config JAZZ config FULONG bool + select PCI_BONITO config MIPS_CPS bool diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 9642c77e98..8db41edc7e 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -55,3 +55,7 @@ config PCI_EXPRESS_DESIGNWARE bool select PCI_EXPRESS select MSI_NONBROKEN + +config PCI_BONITO + select PCI + bool diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs index 8c87e8494d..e422e0aca0 100644 --- a/hw/pci-host/Makefile.objs +++ b/hw/pci-host/Makefile.objs @@ -12,7 +12,7 @@ common-obj-$(CONFIG_PPCE500_PCI) += ppce500.o common-obj-$(CONFIG_VERSATILE_PCI) += versatile.o common-obj-$(CONFIG_PCI_SABRE) += sabre.o -common-obj-$(CONFIG_FULONG) += bonito.o +common-obj-$(CONFIG_PCI_BONITO) += bonito.o common-obj-$(CONFIG_PCI_I440FX) += i440fx.o common-obj-$(CONFIG_XEN_IGD_PASSTHROUGH) += xen_igd_pt.o common-obj-$(CONFIG_PCI_EXPRESS_Q35) += q35.o From 3d14264cceb005e6b2131082bfa202c701e7ffb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 10 May 2020 21:34:11 +0200 Subject: [PATCH 0659/2595] hw/pci-host/bonito: Fix DPRINTF() format strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Huacai Chen Message-id: <20200510210128.18343-7-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/pci-host/bonito.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index f212796044..b874468ea6 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -239,7 +239,7 @@ static void bonito_writel(void *opaque, hwaddr addr, saddr = addr >> 2; - DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x\n", + DPRINTF("bonito_writel "TARGET_FMT_plx" val %lx saddr %x\n", addr, val, saddr); switch (saddr) { case BONITO_BONPONCFG: @@ -327,7 +327,7 @@ static void bonito_pciconf_writel(void *opaque, hwaddr addr, PCIBonitoState *s = opaque; PCIDevice *d = PCI_DEVICE(s); - DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x\n", addr, val); + DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %lx\n", addr, val); d->config_write(d, addr, val, 4); } @@ -474,7 +474,7 @@ static void bonito_spciconf_write(void *opaque, hwaddr addr, uint64_t val, uint32_t pciaddr; uint16_t status; - DPRINTF("bonito_spciconf_write "TARGET_FMT_plx" size %d val %x\n", + DPRINTF("bonito_spciconf_write "TARGET_FMT_plx" size %d val %lx\n", addr, size, val); pciaddr = bonito_sbridge_pciaddr(s, addr); From 86313bdc85a3ebc4817ffb29edd1c108c50afbe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 10 May 2020 19:25:18 +0200 Subject: [PATCH 0660/2595] hw/pci-host/bonito: Map peripheral using physical address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Peripherals are mapped at physical address on busses. Only CPU/IOMMU can use virtual addresses. Reviewed-by: Aleksandar Markovic Message-id: <20200510210128.18343-8-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/pci-host/bonito.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index b874468ea6..b90e5a636d 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -647,12 +647,12 @@ static void bonito_realize(PCIDevice *dev, Error **errp) memory_region_init_io(&s->iomem_ldma, OBJECT(s), &bonito_ldma_ops, s, "ldma", 0x100); sysbus_init_mmio(sysbus, &s->iomem_ldma); - sysbus_mmio_map(sysbus, 3, 0xbfe00200); + sysbus_mmio_map(sysbus, 3, 0x1fe00200); memory_region_init_io(&s->iomem_cop, OBJECT(s), &bonito_cop_ops, s, "cop", 0x100); sysbus_init_mmio(sysbus, &s->iomem_cop); - sysbus_mmio_map(sysbus, 4, 0xbfe00300); + sysbus_mmio_map(sysbus, 4, 0x1fe00300); /* Map PCI IO Space 0x1fd0 0000 - 0x1fd1 0000 */ memory_region_init_alias(&s->bonito_pciio, OBJECT(s), "isa_mmio", From 25cca0a9b789244f89b24ed628b0dd6b0a169acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 10 May 2020 19:26:36 +0200 Subject: [PATCH 0661/2595] hw/pci-host/bonito: Map all the Bonito64 I/O range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To ease following guest accesses to the Bonito64 chipset, map its I/O range as UnimplementedDevice. We can now see the accesses to unimplemented peripheral using the '-d unimp' command line option. Reviewed-by: Aleksandar Markovic Message-id: <20200510210128.18343-9-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/pci-host/Kconfig | 1 + hw/pci-host/bonito.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 8db41edc7e..036a61877a 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -58,4 +58,5 @@ config PCI_EXPRESS_DESIGNWARE config PCI_BONITO select PCI + select UNIMP bool diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index b90e5a636d..f09bb1c6a8 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -48,6 +48,7 @@ #include "sysemu/reset.h" #include "sysemu/runstate.h" #include "exec/address-spaces.h" +#include "hw/misc/unimp.h" /* #define DEBUG_BONITO */ @@ -644,6 +645,8 @@ static void bonito_realize(PCIDevice *dev, Error **errp) sysbus_init_mmio(sysbus, &phb->data_mem); sysbus_mmio_map(sysbus, 2, BONITO_SPCICONFIG_BASE); + create_unimplemented_device("bonito", BONITO_REG_BASE, BONITO_REG_SIZE); + memory_region_init_io(&s->iomem_ldma, OBJECT(s), &bonito_ldma_ops, s, "ldma", 0x100); sysbus_init_mmio(sysbus, &s->iomem_ldma); From a0b544c1c95df240629964636479fc113086d57b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 10 May 2020 21:42:11 +0200 Subject: [PATCH 0662/2595] hw/pci-host/bonito: Map the different PCI ranges more detailed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Better describe the Bonito64 MEM HI/LO and I/O PCI ranges, add more PCI regions as unimplemented. Reviewed-by: Aleksandar Markovic Message-id: <20200526104726.11273-7-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/pci-host/bonito.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index f09bb1c6a8..52015cc2a7 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -39,6 +39,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qemu/error-report.h" #include "hw/pci/pci.h" #include "hw/irq.h" @@ -82,7 +83,7 @@ #define BONITO_PCILO1_BASE 0x14000000 #define BONITO_PCILO2_BASE 0x18000000 #define BONITO_PCIHI_BASE 0x20000000 -#define BONITO_PCIHI_SIZE 0x20000000 +#define BONITO_PCIHI_SIZE 0x60000000 #define BONITO_PCIHI_TOP (BONITO_PCIHI_BASE + BONITO_PCIHI_SIZE - 1) #define BONITO_PCIIO_BASE 0x1fd00000 #define BONITO_PCIIO_BASE_VA 0xbfd00000 @@ -605,14 +606,26 @@ static void bonito_pcihost_realize(DeviceState *dev, Error **errp) { PCIHostState *phb = PCI_HOST_BRIDGE(dev); BonitoState *bs = BONITO_PCI_HOST_BRIDGE(dev); + MemoryRegion *pcimem_lo_alias = g_new(MemoryRegion, 3); - memory_region_init(&bs->pci_mem, OBJECT(dev), "pci.mem", BONITO_PCILO_SIZE); + memory_region_init(&bs->pci_mem, OBJECT(dev), "pci.mem", BONITO_PCIHI_SIZE); phb->bus = pci_register_root_bus(dev, "pci", pci_bonito_set_irq, pci_bonito_map_irq, dev, &bs->pci_mem, get_system_io(), 0x28, 32, TYPE_PCI_BUS); - memory_region_add_subregion(get_system_memory(), BONITO_PCILO_BASE, - &bs->pci_mem); + + for (size_t i = 0; i < 3; i++) { + char *name = g_strdup_printf("pci.lomem%zu", i); + + memory_region_init_alias(&pcimem_lo_alias[i], NULL, name, + &bs->pci_mem, i * 64 * MiB, 64 * MiB); + memory_region_add_subregion(get_system_memory(), + BONITO_PCILO_BASE + i * 64 * MiB, + &pcimem_lo_alias[i]); + g_free(name); + } + + create_unimplemented_device("pci.io", BONITO_PCIIO_BASE, 1 * MiB); } static void bonito_realize(PCIDevice *dev, Error **errp) @@ -620,6 +633,8 @@ static void bonito_realize(PCIDevice *dev, Error **errp) PCIBonitoState *s = PCI_BONITO(dev); SysBusDevice *sysbus = SYS_BUS_DEVICE(s->pcihost); PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); + BonitoState *bs = BONITO_PCI_HOST_BRIDGE(s->pcihost); + MemoryRegion *pcimem_alias = g_new(MemoryRegion, 1); /* * Bonito North Bridge, built on FPGA, @@ -652,6 +667,7 @@ static void bonito_realize(PCIDevice *dev, Error **errp) sysbus_init_mmio(sysbus, &s->iomem_ldma); sysbus_mmio_map(sysbus, 3, 0x1fe00200); + /* PCI copier */ memory_region_init_io(&s->iomem_cop, OBJECT(s), &bonito_cop_ops, s, "cop", 0x100); sysbus_init_mmio(sysbus, &s->iomem_cop); @@ -669,6 +685,14 @@ static void bonito_realize(PCIDevice *dev, Error **errp) sysbus_init_mmio(sysbus, &s->bonito_localio); sysbus_mmio_map(sysbus, 6, BONITO_DEV_BASE); + memory_region_init_alias(pcimem_alias, NULL, "pci.mem.alias", + &bs->pci_mem, 0, BONITO_PCIHI_SIZE); + memory_region_add_subregion(get_system_memory(), + BONITO_PCIHI_BASE, pcimem_alias); + create_unimplemented_device("PCI_2", + (hwaddr)BONITO_PCIHI_BASE + BONITO_PCIHI_SIZE, + 2 * GiB); + /* set the default value of north bridge pci config */ pci_set_word(dev->config + PCI_COMMAND, 0x0000); pci_set_word(dev->config + PCI_STATUS, 0x0000); From 7a296990af3ae3a63e5397c9c1a9f26981815c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 10 May 2020 21:46:43 +0200 Subject: [PATCH 0663/2595] hw/pci-host/bonito: Better describe the I/O CS regions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Better describe the I/O CS regions, add the ROMCS region. Reviewed-by: Aleksandar Markovic Message-id: <20200510210128.18343-11-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/pci-host/bonito.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 52015cc2a7..20f2797a73 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -673,6 +673,8 @@ static void bonito_realize(PCIDevice *dev, Error **errp) sysbus_init_mmio(sysbus, &s->iomem_cop); sysbus_mmio_map(sysbus, 4, 0x1fe00300); + create_unimplemented_device("ROMCS", BONITO_FLASH_BASE, 60 * MiB); + /* Map PCI IO Space 0x1fd0 0000 - 0x1fd1 0000 */ memory_region_init_alias(&s->bonito_pciio, OBJECT(s), "isa_mmio", get_system_io(), 0, BONITO_PCIIO_SIZE); @@ -680,10 +682,17 @@ static void bonito_realize(PCIDevice *dev, Error **errp) sysbus_mmio_map(sysbus, 5, BONITO_PCIIO_BASE); /* add pci local io mapping */ - memory_region_init_alias(&s->bonito_localio, OBJECT(s), "isa_mmio", - get_system_io(), 0, BONITO_DEV_SIZE); + + memory_region_init_alias(&s->bonito_localio, OBJECT(s), "IOCS[0]", + get_system_io(), 0, 256 * KiB); sysbus_init_mmio(sysbus, &s->bonito_localio); sysbus_mmio_map(sysbus, 6, BONITO_DEV_BASE); + create_unimplemented_device("IOCS[1]", BONITO_DEV_BASE + 1 * 256 * KiB, + 256 * KiB); + create_unimplemented_device("IOCS[2]", BONITO_DEV_BASE + 2 * 256 * KiB, + 256 * KiB); + create_unimplemented_device("IOCS[3]", BONITO_DEV_BASE + 3 * 256 * KiB, + 256 * KiB); memory_region_init_alias(pcimem_alias, NULL, "pci.mem.alias", &bs->pci_mem, 0, BONITO_PCIHI_SIZE); From 1f8a6c8b3c3a9c6ea0b215a764a1c4f1d6141078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 10 May 2020 21:36:37 +0200 Subject: [PATCH 0664/2595] hw/pci-host/bonito: Set the Config register reset value with FIELD_DP32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Describe some bits of the Config registers fields with the registerfields API. Use the FIELD_DP32() macro to set the BONGENCFG register bits at reset. Reviewed-by: Aleksandar Markovic Message-id: <20200510210128.18343-12-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/pci-host/bonito.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 20f2797a73..d0201ce59e 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -50,6 +50,7 @@ #include "sysemu/runstate.h" #include "exec/address-spaces.h" #include "hw/misc/unimp.h" +#include "hw/registerfields.h" /* #define DEBUG_BONITO */ @@ -112,8 +113,19 @@ /* Power on register */ #define BONITO_BONPONCFG (0x00 >> 2) /* 0x100 */ + +/* PCI configuration register */ #define BONITO_BONGENCFG_OFFSET 0x4 #define BONITO_BONGENCFG (BONITO_BONGENCFG_OFFSET >> 2) /*0x104 */ +REG32(BONGENCFG, 0x104) +FIELD(BONGENCFG, DEBUGMODE, 0, 1) +FIELD(BONGENCFG, SNOOP, 1, 1) +FIELD(BONGENCFG, CPUSELFRESET, 2, 1) +FIELD(BONGENCFG, BYTESWAP, 6, 1) +FIELD(BONGENCFG, UNCACHED, 7, 1) +FIELD(BONGENCFG, PREFETCH, 8, 1) +FIELD(BONGENCFG, WRITEBEHIND, 9, 1) +FIELD(BONGENCFG, PCIQUEUE, 12, 1) /* 2. IO & IDE configuration */ #define BONITO_IODEVCFG (0x08 >> 2) /* 0x108 */ @@ -577,11 +589,18 @@ static int pci_bonito_map_irq(PCIDevice *pci_dev, int irq_num) static void bonito_reset(void *opaque) { PCIBonitoState *s = opaque; + uint32_t val = 0; /* set the default value of north bridge registers */ s->regs[BONITO_BONPONCFG] = 0xc40; - s->regs[BONITO_BONGENCFG] = 0x1384; + val = FIELD_DP32(val, BONGENCFG, PCIQUEUE, 1); + val = FIELD_DP32(val, BONGENCFG, WRITEBEHIND, 1); + val = FIELD_DP32(val, BONGENCFG, PREFETCH, 1); + val = FIELD_DP32(val, BONGENCFG, UNCACHED, 1); + val = FIELD_DP32(val, BONGENCFG, CPUSELFRESET, 1); + s->regs[BONITO_BONGENCFG] = val; + s->regs[BONITO_IODEVCFG] = 0x2bff8010; s->regs[BONITO_SDCFG] = 0x255e0091; From 3e5fe8dd1fcb6aa3acd3e5b719bd0b9e69ddee6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 26 Apr 2020 12:19:16 +0200 Subject: [PATCH 0665/2595] hw/mips/fuloong2e: Move code and update a comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the RAM-related call closer to the RAM creation block, rename the ROM comment. Reviewed-by: Huacai Chen Message-id: <20200510210128.18343-4-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/mips/mips_fulong2e.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 05b9efa516..6996f5e3d1 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -315,12 +315,11 @@ static void mips_fulong2e_init(MachineState *machine) error_report("Invalid RAM size, should be 256MB"); exit(EXIT_FAILURE); } + memory_region_add_subregion(address_space_mem, 0, machine->ram); - /* allocate RAM */ + /* Boot ROM */ memory_region_init_rom(bios, NULL, "fulong2e.bios", BIOS_SIZE, &error_fatal); - - memory_region_add_subregion(address_space_mem, 0, machine->ram); memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios); /* From c3a09ff68ddffd1efd57612706484aa386826518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 26 Apr 2020 12:16:37 +0200 Subject: [PATCH 0666/2595] hw/mips/fuloong2e: Fix typo in Fuloong machine name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We always miswrote the Fuloong machine... Fix its name. Add an machine alias to the previous name for backward compatibility. Suggested-by: Aleksandar Markovic Reviewed-by: Aleksandar Markovic Message-id: <20200526104726.11273-11-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 4 +-- default-configs/mips64el-softmmu.mak | 2 +- docs/system/deprecated.rst | 5 +++ docs/system/target-mips.rst | 2 +- hw/isa/vt82c686.c | 2 +- hw/mips/Kconfig | 2 +- hw/mips/Makefile.objs | 2 +- hw/mips/{mips_fulong2e.c => fuloong2e.c} | 41 ++++++++++++------------ hw/pci-host/bonito.c | 8 ++--- tests/qtest/endianness-test.c | 2 +- 10 files changed, 38 insertions(+), 32 deletions(-) rename hw/mips/{mips_fulong2e.c => fuloong2e.c} (91%) diff --git a/MAINTAINERS b/MAINTAINERS index 8f597aae12..8136a0e56c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1081,13 +1081,13 @@ R: Aleksandar Rikalo S: Obsolete F: hw/mips/mips_r4k.c -Fulong 2E +Fuloong 2E M: Huacai Chen M: Philippe Mathieu-Daudé M: Aleksandar Markovic R: Jiaxun Yang S: Odd Fixes -F: hw/mips/mips_fulong2e.c +F: hw/mips/fuloong2e.c F: hw/isa/vt82c686.c F: hw/pci-host/bonito.c F: include/hw/isa/vt82c686.h diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak index 8b0c9b1e15..9f8a3ef156 100644 --- a/default-configs/mips64el-softmmu.mak +++ b/default-configs/mips64el-softmmu.mak @@ -2,7 +2,7 @@ include mips-softmmu-common.mak CONFIG_IDE_VIA=y -CONFIG_FULONG=y +CONFIG_FULOONG=y CONFIG_ATI_VGA=y CONFIG_RTL8139_PCI=y CONFIG_JAZZ=y diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 3142fac386..f0061f94aa 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -368,6 +368,11 @@ mips ``r4k`` platform (since 5.0) This machine type is very old and unmaintained. Users should use the ``malta`` machine type instead. +mips ``fulong2e`` machine (since 5.1) +''''''''''''''''''''''''''''''''''''' + +This machine has been renamed ``fuloong2e``. + ``pc-1.0``, ``pc-1.1``, ``pc-1.2`` and ``pc-1.3`` (since 5.0) ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/system/target-mips.rst b/docs/system/target-mips.rst index 2736fd0509..cd2a931edf 100644 --- a/docs/system/target-mips.rst +++ b/docs/system/target-mips.rst @@ -74,7 +74,7 @@ The MIPS Magnum R4000 emulation supports: - G364 framebuffer -The Fulong 2E emulation supports: +The Fuloong 2E emulation supports: - Loongson 2E CPU diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index d9b51fce8d..fac4e56b7d 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -503,7 +503,7 @@ static void via_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_via; /* * Reason: part of VIA VT82C686 southbridge, needs to be wired up, - * e.g. by mips_fulong2e_init() + * e.g. by mips_fuloong2e_init() */ dc->user_creatable = false; } diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index 2240504dff..67d39c56a4 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -41,7 +41,7 @@ config JAZZ select DS1225Y select JAZZ_LED -config FULONG +config FULOONG bool select PCI_BONITO diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs index 525809af07..8ab41edc3f 100644 --- a/hw/mips/Makefile.objs +++ b/hw/mips/Makefile.objs @@ -3,6 +3,6 @@ obj-$(CONFIG_R4K) += mips_r4k.o obj-$(CONFIG_MALTA) += gt64xxx_pci.o mips_malta.o obj-$(CONFIG_MIPSSIM) += mips_mipssim.o obj-$(CONFIG_JAZZ) += mips_jazz.o -obj-$(CONFIG_FULONG) += mips_fulong2e.o +obj-$(CONFIG_FULOONG) += fuloong2e.o obj-$(CONFIG_MIPS_CPS) += cps.o obj-$(CONFIG_MIPS_BOSTON) += boston.o diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/fuloong2e.c similarity index 91% rename from hw/mips/mips_fulong2e.c rename to hw/mips/fuloong2e.c index 6996f5e3d1..f583c44b79 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/fuloong2e.c @@ -1,5 +1,5 @@ /* - * QEMU fulong 2e mini pc support + * QEMU fuloong 2e mini pc support * * Copyright (c) 2008 yajin (yajin@vm-kernel.org) * Copyright (c) 2009 chenming (chenming@rdc.faw.com.cn) @@ -11,8 +11,8 @@ */ /* - * Fulong 2e mini pc is based on ICT/ST Loongson 2e CPU (MIPS III like, 800MHz) - * http://www.linux-mips.org/wiki/Fulong + * Fuloong 2e mini pc is based on ICT/ST Loongson 2e CPU (MIPS III like, 800MHz) + * https://www.linux-mips.org/wiki/Fuloong_2E * * Loongson 2e user manual: * http://www.loongsondeveloper.com/doc/Loongson2EUserGuide.pdf @@ -45,13 +45,13 @@ #include "sysemu/reset.h" #include "qemu/error-report.h" -#define DEBUG_FULONG2E_INIT +#define DEBUG_FULOONG2E_INIT #define ENVP_ADDR 0x80002000l #define ENVP_NB_ENTRIES 16 #define ENVP_ENTRY_SIZE 256 -/* fulong 2e has a 512k flash: Winbond W39L040AP70Z */ +/* Fuloong 2e has a 512k flash: Winbond W39L040AP70Z */ #define BIOS_SIZE (512 * KiB) #define MAX_IDE_BUS 2 @@ -68,12 +68,12 @@ * 2, use "Bonito2edev" to replace "dir_corresponding_to_your_target_hardware" * in the "Compile Guide". */ -#define FULONG_BIOSNAME "pmon_fulong2e.bin" +#define FULOONG_BIOSNAME "pmon_2e.bin" -/* PCI SLOT in fulong 2e */ -#define FULONG2E_VIA_SLOT 5 -#define FULONG2E_ATI_SLOT 6 -#define FULONG2E_RTL8139_SLOT 7 +/* PCI SLOT in Fuloong 2e */ +#define FULOONG2E_VIA_SLOT 5 +#define FULOONG2E_ATI_SLOT 6 +#define FULOONG2E_RTL8139_SLOT 7 static struct _loaderparams { int ram_size; @@ -278,7 +278,7 @@ static void network_init(PCIBus *pci_bus) const char *default_devaddr = NULL; if (i == 0 && (!nd->model || strcmp(nd->model, "rtl8139") == 0)) { - /* The fulong board has a RTL8139 card using PCI SLOT 7 */ + /* The Fuloong board has a RTL8139 card using PCI SLOT 7 */ default_devaddr = "07"; } @@ -286,7 +286,7 @@ static void network_init(PCIBus *pci_bus) } } -static void mips_fulong2e_init(MachineState *machine) +static void mips_fuloong2e_init(MachineState *machine) { const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; @@ -318,7 +318,7 @@ static void mips_fulong2e_init(MachineState *machine) memory_region_add_subregion(address_space_mem, 0, machine->ram); /* Boot ROM */ - memory_region_init_rom(bios, NULL, "fulong2e.bios", BIOS_SIZE, + memory_region_init_rom(bios, NULL, "fuloong2e.bios", BIOS_SIZE, &error_fatal); memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios); @@ -336,7 +336,7 @@ static void mips_fulong2e_init(MachineState *machine) write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry); } else { if (bios_name == NULL) { - bios_name = FULONG_BIOSNAME; + bios_name = FULOONG_BIOSNAME; } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); if (filename) { @@ -362,7 +362,7 @@ static void mips_fulong2e_init(MachineState *machine) pci_bus = bonito_init((qemu_irq *)&(env->irq[2])); /* South bridge -> IP5 */ - vt82c686b_southbridge_init(pci_bus, FULONG2E_VIA_SLOT, env->irq[5], + vt82c686b_southbridge_init(pci_bus, FULOONG2E_VIA_SLOT, env->irq[5], &smbus, &isa_bus); /* GPU */ @@ -383,14 +383,15 @@ static void mips_fulong2e_init(MachineState *machine) network_init(pci_bus); } -static void mips_fulong2e_machine_init(MachineClass *mc) +static void mips_fuloong2e_machine_init(MachineClass *mc) { - mc->desc = "Fulong 2e mini pc"; - mc->init = mips_fulong2e_init; + mc->desc = "Fuloong 2e mini pc"; + mc->alias = "fulong2e"; /* Incorrect name used up to QEMU 4.2 */ + mc->init = mips_fuloong2e_init; mc->block_default_type = IF_IDE; mc->default_cpu_type = MIPS_CPU_TYPE_NAME("Loongson-2E"); mc->default_ram_size = 256 * MiB; - mc->default_ram_id = "fulong2e.ram"; + mc->default_ram_id = "fuloong2e.ram"; } -DEFINE_MACHINE("fulong2e", mips_fulong2e_machine_init) +DEFINE_MACHINE("fuloong2e", mips_fuloong2e_machine_init) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index d0201ce59e..f9697dcc43 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -11,7 +11,7 @@ */ /* - * fulong 2e mini pc has a bonito north bridge. + * fuloong 2e mini pc has a bonito north bridge. */ /* @@ -573,11 +573,11 @@ static int pci_bonito_map_irq(PCIDevice *pci_dev, int irq_num) slot = (pci_dev->devfn >> 3); switch (slot) { - case 5: /* FULONG2E_VIA_SLOT, SouthBridge, IDE, USB, ACPI, AC97, MC97 */ + case 5: /* FULOONG2E_VIA_SLOT, SouthBridge, IDE, USB, ACPI, AC97, MC97 */ return irq_num % 4 + BONITO_IRQ_BASE; - case 6: /* FULONG2E_ATI_SLOT, VGA */ + case 6: /* FULOONG2E_ATI_SLOT, VGA */ return 4 + BONITO_IRQ_BASE; - case 7: /* FULONG2E_RTL_SLOT, RTL8139 */ + case 7: /* FULOONG2E_RTL_SLOT, RTL8139 */ return 5 + BONITO_IRQ_BASE; case 8 ... 12: /* PCI slot 1 to 4 */ return (slot - 8 + irq_num) + 6 + BONITO_IRQ_BASE; diff --git a/tests/qtest/endianness-test.c b/tests/qtest/endianness-test.c index 2798802c63..cc088ac01a 100644 --- a/tests/qtest/endianness-test.c +++ b/tests/qtest/endianness-test.c @@ -33,7 +33,7 @@ static const TestCase test_cases[] = { { "mips64", "pica61", 0x90000000, .bswap = true }, { "mips64", "mips", 0x14000000, .bswap = true }, { "mips64", "malta", 0x10000000, .bswap = true }, - { "mips64el", "fulong2e", 0x1fd00000 }, + { "mips64el", "fuloong2e", 0x1fd00000 }, { "ppc", "g3beige", 0xfe000000, .bswap = true, .superio = "i82378" }, { "ppc", "40p", 0x80000000, .bswap = true }, { "ppc", "bamboo", 0xe8000000, .bswap = true, .superio = "i82378" }, From 5298722edad2d40baac9c2326c6d492ad2b0211a Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:20 +0200 Subject: [PATCH 0667/2595] hw/mips: Rename malta/mipssim/r4k/jazz files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Machine file names should not have prefix "mips_". Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Aleksandar Markovic Message-id: <20200518200920.17344-22-aleksandar.qemu.devel@gmail.com> [PMD: Fixed Fuloong line conflict due to rebase] Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 8 ++++---- hw/mips/Makefile.objs | 8 ++++---- hw/mips/{mips_jazz.c => jazz.c} | 0 hw/mips/{mips_malta.c => malta.c} | 0 hw/mips/{mips_mipssim.c => mipssim.c} | 0 hw/mips/{mips_r4k.c => r4k.c} | 0 6 files changed, 8 insertions(+), 8 deletions(-) rename hw/mips/{mips_jazz.c => jazz.c} (100%) rename hw/mips/{mips_malta.c => malta.c} (100%) rename hw/mips/{mips_mipssim.c => mipssim.c} (100%) rename hw/mips/{mips_r4k.c => r4k.c} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 8136a0e56c..f46ab150dc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1050,7 +1050,7 @@ Jazz M: Hervé Poussineau R: Aleksandar Rikalo S: Maintained -F: hw/mips/mips_jazz.c +F: hw/mips/jazz.c F: hw/display/jazz_led.c F: hw/dma/rc4030.c @@ -1061,7 +1061,7 @@ R: Aurelien Jarno S: Maintained F: hw/isa/piix4.c F: hw/acpi/piix4.c -F: hw/mips/mips_malta.c +F: hw/mips/malta.c F: hw/mips/gt64xxx_pci.c F: include/hw/southbridge/piix.h F: tests/acceptance/linux_ssh_mips_malta.py @@ -1071,7 +1071,7 @@ Mipssim M: Aleksandar Markovic R: Aleksandar Rikalo S: Odd Fixes -F: hw/mips/mips_mipssim.c +F: hw/mips/mipssim.c F: hw/net/mipsnet.c R4000 @@ -1079,7 +1079,7 @@ M: Aleksandar Markovic R: Aurelien Jarno R: Aleksandar Rikalo S: Obsolete -F: hw/mips/mips_r4k.c +F: hw/mips/r4k.c Fuloong 2E M: Huacai Chen diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs index 8ab41edc3f..739e2b7b40 100644 --- a/hw/mips/Makefile.objs +++ b/hw/mips/Makefile.objs @@ -1,8 +1,8 @@ obj-y += addr.o mips_int.o -obj-$(CONFIG_R4K) += mips_r4k.o -obj-$(CONFIG_MALTA) += gt64xxx_pci.o mips_malta.o -obj-$(CONFIG_MIPSSIM) += mips_mipssim.o -obj-$(CONFIG_JAZZ) += mips_jazz.o +obj-$(CONFIG_R4K) += r4k.o +obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o +obj-$(CONFIG_MIPSSIM) += mipssim.o +obj-$(CONFIG_JAZZ) += jazz.o obj-$(CONFIG_FULOONG) += fuloong2e.o obj-$(CONFIG_MIPS_CPS) += cps.o obj-$(CONFIG_MIPS_BOSTON) += boston.o diff --git a/hw/mips/mips_jazz.c b/hw/mips/jazz.c similarity index 100% rename from hw/mips/mips_jazz.c rename to hw/mips/jazz.c diff --git a/hw/mips/mips_malta.c b/hw/mips/malta.c similarity index 100% rename from hw/mips/mips_malta.c rename to hw/mips/malta.c diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mipssim.c similarity index 100% rename from hw/mips/mips_mipssim.c rename to hw/mips/mipssim.c diff --git a/hw/mips/mips_r4k.c b/hw/mips/r4k.c similarity index 100% rename from hw/mips/mips_r4k.c rename to hw/mips/r4k.c From c707f06fb1d9b09e5d442e72f6f3dcd021671a90 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:19 +0200 Subject: [PATCH 0668/2595] hw/mips/malta: Add some logging for bad register offset cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Log the cases where a guest attempts read or write using bad register offset. Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Aleksandar Markovic Message-id: <20200518200920.17344-21-aleksandar.qemu.devel@gmail.com> [PMD: Replaced TARGET_FMT_lx by HWADDR_PRIX] Signed-off-by: Philippe Mathieu-Daudé --- hw/mips/malta.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index e4c4de1b4e..b673a3a248 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -427,10 +427,9 @@ static uint64_t malta_fpga_read(void *opaque, hwaddr addr, break; default: -#if 0 - printf("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n", - addr); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "malta_fpga_read: Bad register addr 0x%"HWADDR_PRIX"\n", + addr); break; } return val; @@ -515,10 +514,9 @@ static void malta_fpga_write(void *opaque, hwaddr addr, break; default: -#if 0 - printf("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n", - addr); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "malta_fpga_write: Bad register addr 0x%"HWADDR_PRIX"\n", + addr); break; } } From 56b92eeeac8074501858e15b7658ec6099456f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 29 Apr 2020 10:21:05 +0200 Subject: [PATCH 0669/2595] hw/mips/mips_int: De-duplicate KVM interrupt delivery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor duplicated code in a single place. Reviewed-by: Thomas Huth Message-Id: <20200429082916.10669-2-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/mips/mips_int.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c index 796730b11d..4a1bf846da 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -47,17 +47,12 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) if (level) { env->CP0_Cause |= 1 << (irq + CP0Ca_IP); - - if (kvm_enabled() && irq == 2) { - kvm_mips_set_interrupt(cpu, irq, level); - } - } else { env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP)); + } - if (kvm_enabled() && irq == 2) { - kvm_mips_set_interrupt(cpu, irq, level); - } + if (kvm_enabled() && irq == 2) { + kvm_mips_set_interrupt(cpu, irq, level); } if (env->CP0_Cause & CP0Ca_IP_mask) { From 97d8974620053db5754af808583de70380f73a10 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:16 +0200 Subject: [PATCH 0670/2595] MAINTAINERS: Change Aleksandar Rikalo's email address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aleksandar Rikalo wants to use a different email address from now on. Reviewed-by: Aleksandar Rikalo Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Aleksandar Markovic Message-id: <20200518200920.17344-18-aleksandar.qemu.devel@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- .mailmap | 3 ++- MAINTAINERS | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.mailmap b/.mailmap index 6412067bde..e3628c7a66 100644 --- a/.mailmap +++ b/.mailmap @@ -42,7 +42,8 @@ Justin Terry (VM) Justin Terry (VM) via Qemu-devel Aleksandar Markovic Aleksandar Markovic -Aleksandar Rikalo +Aleksandar Rikalo +Aleksandar Rikalo Anthony Liguori Anthony Liguori James Hogan Leif Lindholm diff --git a/MAINTAINERS b/MAINTAINERS index f46ab150dc..a209b5d8ce 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -213,7 +213,7 @@ F: disas/microblaze.c MIPS TCG CPUs M: Aleksandar Markovic R: Aurelien Jarno -R: Aleksandar Rikalo +R: Aleksandar Rikalo S: Maintained F: target/mips/ F: default-configs/*mips* @@ -1048,7 +1048,7 @@ MIPS Machines ------------- Jazz M: Hervé Poussineau -R: Aleksandar Rikalo +R: Aleksandar Rikalo S: Maintained F: hw/mips/jazz.c F: hw/display/jazz_led.c @@ -1069,7 +1069,7 @@ F: tests/acceptance/machine_mips_malta.py Mipssim M: Aleksandar Markovic -R: Aleksandar Rikalo +R: Aleksandar Rikalo S: Odd Fixes F: hw/mips/mipssim.c F: hw/net/mipsnet.c @@ -1077,7 +1077,7 @@ F: hw/net/mipsnet.c R4000 M: Aleksandar Markovic R: Aurelien Jarno -R: Aleksandar Rikalo +R: Aleksandar Rikalo S: Obsolete F: hw/mips/r4k.c @@ -1094,7 +1094,7 @@ F: include/hw/isa/vt82c686.h Boston M: Paul Burton -R: Aleksandar Rikalo +R: Aleksandar Rikalo S: Maintained F: hw/core/loader-fit.c F: hw/mips/boston.c @@ -2608,7 +2608,7 @@ F: disas/i386.c MIPS TCG target M: Aleksandar Markovic R: Aurelien Jarno -R: Aleksandar Rikalo +R: Aleksandar Rikalo S: Maintained F: tcg/mips/ From fe837714f3462e02e856d441ea6e9a6a0aad4695 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 7 May 2020 21:48:24 +1000 Subject: [PATCH 0671/2595] ppc/pnv: Fix NMI system reset SRR1 value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit a77fed5bd926 ("ppc/pnv: Add support for NMI interface") got the SRR1 setting wrong for sresets that hit outside of power-save states. Fix this, better documenting the source for the bit definitions. Fixes: 01b552b05b0f ("ppc/pnv: Add support for NMI interface") Cc: Cédric Le Goater Cc: David Gibson Signed-off-by: Nicholas Piggin Message-Id: <20200507114824.788942-1-npiggin@gmail.com> Reviewed-by: Cédric Le Goater [dwg: Fixed up some tab indentation] Signed-off-by: David Gibson --- hw/ppc/pnv.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index da637822f9..f48a61d6d1 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1984,12 +1984,26 @@ static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg) cpu_synchronize_state(cs); ppc_cpu_do_system_reset(cs); - /* - * SRR1[42:45] is set to 0100 which the ISA defines as implementation - * dependent. POWER processors use this for xscom triggered interrupts, - * which come from the BMC or NMI IPIs. - */ - env->spr[SPR_SRR1] |= PPC_BIT(43); + if (env->spr[SPR_SRR1] & PPC_BITMASK(46, 47)) { + /* + * Power-save wakeups, as indicated by non-zero SRR1[46:47] put the + * wakeup reason in SRR1[42:45], system reset is indicated with 0b0100 + * (PPC_BIT(43)). + */ + if (!(env->spr[SPR_SRR1] & PPC_BIT(43))) { + warn_report("ppc_cpu_do_system_reset does not set system reset wakeup reason"); + env->spr[SPR_SRR1] |= PPC_BIT(43); + } + } else { + /* + * For non-powersave system resets, SRR1[42:45] are defined to be + * implementation-dependent. The POWER9 User Manual specifies that + * an external (SCOM driven, which may come from a BMC nmi command or + * another CPU requesting a NMI IPI) system reset exception should be + * 0b0010 (PPC_BIT(44)). + */ + env->spr[SPR_SRR1] |= PPC_BIT(44); + } } static void pnv_nmi(NMIState *n, int cpu_index, Error **errp) From 0bbf14a0954322e72bb1845bc0b0fd55fd531d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 7 May 2020 09:38:55 +0200 Subject: [PATCH 0672/2595] ppc/spapr: add a POWER10 CPU model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cédric Le Goater Message-Id: <20200507073855.2485680-1-clg@kaod.org> Signed-off-by: David Gibson --- hw/ppc/spapr_cpu_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index e1f76c74f3..9c8c1b14cf 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -407,6 +407,7 @@ static const TypeInfo spapr_cpu_core_type_infos[] = { DEFINE_SPAPR_CPU_CORE_TYPE("power8nvl_v1.0"), DEFINE_SPAPR_CPU_CORE_TYPE("power9_v1.0"), DEFINE_SPAPR_CPU_CORE_TYPE("power9_v2.0"), + DEFINE_SPAPR_CPU_CORE_TYPE("power10_v1.0"), #ifdef CONFIG_KVM DEFINE_SPAPR_CPU_CORE_TYPE("host"), #endif From ececb880d61a3b7e255f873ba66388877218c036 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 7 May 2020 18:11:23 +0200 Subject: [PATCH 0673/2595] target/ppc: Untabify excp_helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some tabs crept in with a recent change. Fixes: 6dc6b557913f "target/ppc: Improve syscall exception logging" Signed-off-by: Greg Kurz Message-Id: <158886788307.1560068.14096740175576278978.stgit@bahia.lan> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: David Gibson --- target/ppc/excp_helper.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index f052979664..ace8620026 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -70,16 +70,16 @@ static inline void dump_syscall(CPUPPCState *env) static inline void dump_hcall(CPUPPCState *env) { qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64 - " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 - " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64 - " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64 + " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 + " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64 + " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64 " nip=" TARGET_FMT_lx "\n", ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4), - ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6), - ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8), - ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10), - ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12), - env->nip); + ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6), + ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8), + ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10), + ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12), + env->nip); } static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, From 3c89b8d6ac5b8728cd7620f9885bd953edd18a11 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 7 May 2020 21:53:28 +1000 Subject: [PATCH 0674/2595] target/ppc: Add support for scv and rfscv instructions POWER9 adds scv and rfscv instructions and the system call vectored interrupt. Linux does not support this instruction yet but it has been tested with a modified kernel that runs on real hardware. Signed-off-by: Nicholas Piggin Message-Id: <20200507115328.789175-1-npiggin@gmail.com> [dwg: Corrected an overlong line] Signed-off-by: David Gibson --- linux-user/ppc/cpu_loop.c | 1 + target/ppc/cpu.h | 7 ++- target/ppc/excp_helper.c | 98 ++++++++++++++++++++++++--------- target/ppc/helper.h | 1 + target/ppc/translate.c | 53 +++++++++++++++++- target/ppc/translate_init.inc.c | 3 +- 6 files changed, 133 insertions(+), 30 deletions(-) diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c index 5b27f8603e..df71e15a25 100644 --- a/linux-user/ppc/cpu_loop.c +++ b/linux-user/ppc/cpu_loop.c @@ -267,6 +267,7 @@ void cpu_loop(CPUPPCState *env) queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_SYSCALL: /* System call exception */ + case POWERPC_EXCP_SYSCALL_VECTORED: cpu_abort(cs, "Syscall exception while in user mode. " "Aborting\n"); break; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 7db7882f52..c1005b04a0 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -127,8 +127,9 @@ enum { POWERPC_EXCP_SDOOR_HV = 100, /* ISA 3.00 additions */ POWERPC_EXCP_HVIRT = 101, + POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception */ /* EOL */ - POWERPC_EXCP_NB = 102, + POWERPC_EXCP_NB = 103, /* QEMU exceptions: used internally during code translation */ POWERPC_EXCP_STOP = 0x200, /* stop translation */ POWERPC_EXCP_BRANCH = 0x201, /* branch instruction */ @@ -478,6 +479,7 @@ typedef struct ppc_v3_pate_t { /* Facility Status and Control (FSCR) bits */ #define FSCR_EBB (63 - 56) /* Event-Based Branch Facility */ #define FSCR_TAR (63 - 55) /* Target Address Register */ +#define FSCR_SCV (63 - 51) /* System call vectored */ /* Interrupt cause mask and position in FSCR. HFSCR has the same format */ #define FSCR_IC_MASK (0xFFULL) #define FSCR_IC_POS (63 - 7) @@ -487,6 +489,7 @@ typedef struct ppc_v3_pate_t { #define FSCR_IC_TM 5 #define FSCR_IC_EBB 7 #define FSCR_IC_TAR 8 +#define FSCR_IC_SCV 12 /* Exception state register bits definition */ #define ESR_PIL PPC_BIT(36) /* Illegal Instruction */ @@ -554,6 +557,8 @@ enum { POWERPC_FLAG_VSX = 0x00080000, /* Has Transaction Memory (ISA 2.07) */ POWERPC_FLAG_TM = 0x00100000, + /* Has SCV (ISA 3.00) */ + POWERPC_FLAG_SCV = 0x00200000, }; /*****************************************************************************/ diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index ace8620026..14d3902982 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -67,6 +67,18 @@ static inline void dump_syscall(CPUPPCState *env) ppc_dump_gpr(env, 8), env->nip); } +static inline void dump_syscall_vectored(CPUPPCState *env) +{ + qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 + " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64 + " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64 + " nip=" TARGET_FMT_lx "\n", + ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), + ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), + ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7), + ppc_dump_gpr(env, 8), env->nip); +} + static inline void dump_hcall(CPUPPCState *env) { qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64 @@ -185,7 +197,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; target_ulong msr, new_msr, vector; - int srr0, srr1, asrr0, asrr1, lev, ail; + int srr0, srr1, asrr0, asrr1, lev = -1, ail; bool lpes0; qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx @@ -421,6 +433,13 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) new_msr |= (target_ulong)MSR_HVB; } break; + case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */ + lev = env->error_code; + dump_syscall_vectored(env); + env->nip += 4; + new_msr |= env->msr & ((target_ulong)1 << MSR_EE); + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + break; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ case POWERPC_EXCP_DECR: /* Decrementer exception */ @@ -724,12 +743,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) break; } - /* Save PC */ - env->spr[srr0] = env->nip; - - /* Save MSR */ - env->spr[srr1] = msr; - /* Sanity check */ if (!(env->msr_mask & MSR_HVB)) { if (new_msr & MSR_HVB) { @@ -742,14 +755,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } } - /* If any alternate SRR register are defined, duplicate saved values */ - if (asrr0 != -1) { - env->spr[asrr0] = env->spr[srr0]; - } - if (asrr1 != -1) { - env->spr[asrr1] = env->spr[srr1]; - } - /* * Sort out endianness of interrupt, this differs depending on the * CPU, the HV mode, etc... @@ -784,14 +789,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } #endif - /* Jump to handler */ - vector = env->excp_vectors[excp]; - if (vector == (target_ulong)-1ULL) { - cpu_abort(cs, "Raised an exception without defined vector %d\n", - excp); - } - vector |= env->excp_prefix; - /* * AIL only works if there is no HV transition and we are running * with translations enabled @@ -800,10 +797,21 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { ail = 0; } - /* Handle AIL */ - if (ail) { - new_msr |= (1 << MSR_IR) | (1 << MSR_DR); - vector |= ppc_excp_vector_offset(cs, ail); + + vector = env->excp_vectors[excp]; + if (vector == (target_ulong)-1ULL) { + cpu_abort(cs, "Raised an exception without defined vector %d\n", + excp); + } + + vector |= env->excp_prefix; + + /* If any alternate SRR register are defined, duplicate saved values */ + if (asrr0 != -1) { + env->spr[asrr0] = env->nip; + } + if (asrr1 != -1) { + env->spr[asrr1] = msr; } #if defined(TARGET_PPC64) @@ -823,6 +831,37 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } #endif + if (excp != POWERPC_EXCP_SYSCALL_VECTORED) { + /* Save PC */ + env->spr[srr0] = env->nip; + + /* Save MSR */ + env->spr[srr1] = msr; + + /* Handle AIL */ + if (ail) { + new_msr |= (1 << MSR_IR) | (1 << MSR_DR); + vector |= ppc_excp_vector_offset(cs, ail); + } + +#if defined(TARGET_PPC64) + } else { + /* scv AIL is a little different */ + if (ail) { + new_msr |= (1 << MSR_IR) | (1 << MSR_DR); + } + if (ail == AIL_C000_0000_0000_4000) { + vector |= 0xc000000000003000ull; + } else { + vector |= 0x0000000000017000ull; + } + vector += lev * 0x20; + + env->lr = env->nip; + env->ctr = msr; +#endif + } + powerpc_set_excp_state(cpu, vector, new_msr); } @@ -1160,6 +1199,11 @@ void helper_rfid(CPUPPCState *env) do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]); } +void helper_rfscv(CPUPPCState *env) +{ + do_rfi(env, env->lr, env->ctr); +} + void helper_hrfid(CPUPPCState *env) { do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); diff --git a/target/ppc/helper.h b/target/ppc/helper.h index a95c010391..2dfa1c6942 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -15,6 +15,7 @@ DEF_HELPER_1(rfmci, void, env) #if defined(TARGET_PPC64) DEF_HELPER_2(pminsn, void, env, i32) DEF_HELPER_1(rfid, void, env) +DEF_HELPER_1(rfscv, void, env) DEF_HELPER_1(hrfid, void, env) DEF_HELPER_2(store_lpcr, void, env, tl) DEF_HELPER_2(store_pcr, void, env, tl) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 338529879f..4ce3d664b5 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -173,6 +173,7 @@ struct DisasContext { bool vsx_enabled; bool spe_enabled; bool tm_enabled; + bool scv_enabled; bool gtse; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; @@ -4030,6 +4031,24 @@ static void gen_rfid(DisasContext *ctx) #endif } +#if !defined(CONFIG_USER_ONLY) +static void gen_rfscv(DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY) + GEN_PRIV; +#else + /* Restore CPU state */ + CHK_SV; + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } + gen_update_cfar(ctx, ctx->base.pc_next - 4); + gen_helper_rfscv(cpu_env); + gen_sync_exception(ctx); +#endif +} +#endif + static void gen_hrfid(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) @@ -4048,6 +4067,7 @@ static void gen_hrfid(DisasContext *ctx) #define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER #else #define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL +#define POWERPC_SYSCALL_VECTORED POWERPC_EXCP_SYSCALL_VECTORED #endif static void gen_sc(DisasContext *ctx) { @@ -4057,6 +4077,23 @@ static void gen_sc(DisasContext *ctx) gen_exception_err(ctx, POWERPC_SYSCALL, lev); } +#if defined(TARGET_PPC64) +#if !defined(CONFIG_USER_ONLY) +static void gen_scv(DisasContext *ctx) +{ + uint32_t lev; + + if (unlikely(!ctx->scv_enabled)) { + gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_SCV); + return; + } + + lev = (ctx->opcode >> 5) & 0x7F; + gen_exception_err(ctx, POWERPC_SYSCALL_VECTORED, lev); +} +#endif +#endif + /*** Trap ***/ /* Check for unconditional traps (always or never) */ @@ -7049,6 +7086,12 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER), GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW), #if defined(TARGET_PPC64) GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B), +#if !defined(CONFIG_USER_ONLY) +/* Top bit of opc2 corresponds with low bit of LEV, so use two handlers */ +GEN_HANDLER_E(scv, 0x11, 0x10, 0xFF, 0x03FFF01E, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(scv, 0x11, 0x00, 0xFF, 0x03FFF01E, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(rfscv, 0x13, 0x12, 0x02, 0x03FF8001, PPC_NONE, PPC2_ISA300), +#endif GEN_HANDLER_E(stop, 0x13, 0x12, 0x0b, 0x03FFF801, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(doze, 0x13, 0x12, 0x0c, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206), GEN_HANDLER_E(nap, 0x13, 0x12, 0x0d, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206), @@ -7056,7 +7099,9 @@ GEN_HANDLER_E(sleep, 0x13, 0x12, 0x0e, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206), GEN_HANDLER_E(rvwinkle, 0x13, 0x12, 0x0f, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206), GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H), #endif -GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW), +/* Top bit of opc2 corresponds with low bit of LEV, so use two handlers */ +GEN_HANDLER(sc, 0x11, 0x11, 0xFF, 0x03FFF01D, PPC_FLOW), +GEN_HANDLER(sc, 0x11, 0x01, 0xFF, 0x03FFF01D, PPC_FLOW), GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW), GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW), #if defined(TARGET_PPC64) @@ -7835,6 +7880,12 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) } else { ctx->vsx_enabled = false; } + if ((env->flags & POWERPC_FLAG_SCV) + && (env->spr[SPR_FSCR] & (1ull << FSCR_SCV))) { + ctx->scv_enabled = true; + } else { + ctx->scv_enabled = false; + } #if defined(TARGET_PPC64) if ((env->flags & POWERPC_FLAG_TM) && msr_tm) { ctx->tm_enabled = !!msr_tm; diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index d8adc1bd49..38cb773ab4 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -3382,6 +3382,7 @@ static void init_excp_POWER9(CPUPPCState *env) #if !defined(CONFIG_USER_ONLY) env->excp_vectors[POWERPC_EXCP_HVIRT] = 0x00000EA0; + env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00000000; #endif } @@ -9030,7 +9031,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | - POWERPC_FLAG_VSX | POWERPC_FLAG_TM; + POWERPC_FLAG_VSX | POWERPC_FLAG_TM | POWERPC_FLAG_SCV; pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; From 0911a60c76b8598f1863c6951b2b690059465153 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Mon, 11 May 2020 17:02:02 -0300 Subject: [PATCH 0675/2595] ppc/spapr: Add hotremovable flag on DIMM LMBs on drmem_v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On reboot, all memory that was previously added using object_add and device_add is placed in this DIMM area. The new SPAPR_LMB_FLAGS_HOTREMOVABLE flag helps Linux to put this memory in the correct memory zone, so no unmovable allocations are made there, allowing the object to be easily hot-removed by device_del and object_del. This new flag was accepted in Power Architecture documentation. Signed-off-by: Leonardo Bras Reviewed-by: Bharata B Rao Message-Id: <20200511200201.58537-1-leobras.c@gmail.com> [dwg: Fixed syntax error spotted by Cédric Le Goater] Signed-off-by: David Gibson --- hw/ppc/pnv.c | 8 ++++---- hw/ppc/spapr.c | 3 ++- include/hw/ppc/spapr.h | 1 + target/ppc/cpu.h | 21 +++++++++++++++++++++ target/ppc/excp_helper.c | 16 ++++++++-------- 5 files changed, 36 insertions(+), 13 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index f48a61d6d1..806a5d9a8d 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1984,15 +1984,15 @@ static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg) cpu_synchronize_state(cs); ppc_cpu_do_system_reset(cs); - if (env->spr[SPR_SRR1] & PPC_BITMASK(46, 47)) { + if (env->spr[SPR_SRR1] & SRR1_WAKESTATE) { /* * Power-save wakeups, as indicated by non-zero SRR1[46:47] put the * wakeup reason in SRR1[42:45], system reset is indicated with 0b0100 * (PPC_BIT(43)). */ - if (!(env->spr[SPR_SRR1] & PPC_BIT(43))) { + if (!(env->spr[SPR_SRR1] & SRR1_WAKERESET)) { warn_report("ppc_cpu_do_system_reset does not set system reset wakeup reason"); - env->spr[SPR_SRR1] |= PPC_BIT(43); + env->spr[SPR_SRR1] |= SRR1_WAKERESET; } } else { /* @@ -2002,7 +2002,7 @@ static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg) * another CPU requesting a NMI IPI) system reset exception should be * 0b0010 (PPC_BIT(44)). */ - env->spr[SPR_SRR1] |= PPC_BIT(44); + env->spr[SPR_SRR1] |= SRR1_WAKESCOM; } } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 9b358fcc60..3b1a5ed865 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -445,7 +445,8 @@ static int spapr_dt_dynamic_memory_v2(SpaprMachineState *spapr, void *fdt, g_assert(drc); elem = spapr_get_drconf_cell(size / lmb_size, addr, spapr_drc_index(drc), node, - SPAPR_LMB_FLAGS_ASSIGNED); + (SPAPR_LMB_FLAGS_ASSIGNED | + SPAPR_LMB_FLAGS_HOTREMOVABLE)); QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry); nr_entries++; cur_addr = addr + size; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index d2533e7264..c421410e3f 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -886,6 +886,7 @@ int spapr_rtc_import_offset(SpaprRtcState *rtc, int64_t legacy_offset); #define SPAPR_LMB_FLAGS_ASSIGNED 0x00000008 #define SPAPR_LMB_FLAGS_DRC_INVALID 0x00000020 #define SPAPR_LMB_FLAGS_RESERVED 0x00000080 +#define SPAPR_LMB_FLAGS_HOTREMOVABLE 0x00000100 void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg); diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index c1005b04a0..1988b436cb 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -476,6 +476,27 @@ typedef struct ppc_v3_pate_t { #define SRR1_PROTFAULT DSISR_PROTFAULT #define SRR1_IAMR DSISR_AMR +/* SRR1[42:45] wakeup fields for System Reset Interrupt */ + +#define SRR1_WAKEMASK 0x003c0000 /* reason for wakeup */ + +#define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */ +#define SRR1_WAKEHVI 0x00240000 /* Hypervisor Virt. Interrupt (P9) */ +#define SRR1_WAKEEE 0x00200000 /* External interrupt */ +#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ +#define SRR1_WAKEDBELL 0x00140000 /* Privileged doorbell */ +#define SRR1_WAKERESET 0x00100000 /* System reset */ +#define SRR1_WAKEHDBELL 0x000c0000 /* Hypervisor doorbell */ +#define SRR1_WAKESCOM 0x00080000 /* SCOM not in power-saving mode */ + +/* SRR1[46:47] power-saving exit mode */ + +#define SRR1_WAKESTATE 0x00030000 /* Powersave exit mask */ + +#define SRR1_WS_HVLOSS 0x00030000 /* HV resources not maintained */ +#define SRR1_WS_GPRLOSS 0x00020000 /* GPRs not maintained */ +#define SRR1_WS_NOLOSS 0x00010000 /* All resources maintained */ + /* Facility Status and Control (FSCR) bits */ #define FSCR_EBB (63 - 56) /* Event-Based Branch Facility */ #define FSCR_TAR (63 - 55) /* Target Address Register */ diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 14d3902982..a988ba15f4 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -101,7 +101,7 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, env->resume_as_sreset = false; /* Pretend to be returning from doze always as we don't lose state */ - *msr |= (0x1ull << (63 - 47)); + *msr |= SRR1_WS_NOLOSS; /* Machine checks are sent normally */ if (excp == POWERPC_EXCP_MCHECK) { @@ -109,25 +109,25 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, } switch (excp) { case POWERPC_EXCP_RESET: - *msr |= 0x4ull << (63 - 45); + *msr |= SRR1_WAKERESET; break; case POWERPC_EXCP_EXTERNAL: - *msr |= 0x8ull << (63 - 45); + *msr |= SRR1_WAKEEE; break; case POWERPC_EXCP_DECR: - *msr |= 0x6ull << (63 - 45); + *msr |= SRR1_WAKEDEC; break; case POWERPC_EXCP_SDOOR: - *msr |= 0x5ull << (63 - 45); + *msr |= SRR1_WAKEDBELL; break; case POWERPC_EXCP_SDOOR_HV: - *msr |= 0x3ull << (63 - 45); + *msr |= SRR1_WAKEHDBELL; break; case POWERPC_EXCP_HV_MAINT: - *msr |= 0xaull << (63 - 45); + *msr |= SRR1_WAKEHMI; break; case POWERPC_EXCP_HVIRT: - *msr |= 0x9ull << (63 - 45); + *msr |= SRR1_WAKEHVI; break; default: cpu_abort(cs, "Unsupported exception %d in Power Save mode\n", From 6fc009603c64a35f30c7f1047ca38d4f1ff753c7 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 14 May 2020 00:56:48 +0200 Subject: [PATCH 0676/2595] target/ppc: Pass const pointer to ppc_radix64_get_prot_amr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This doesn't require write access to the CPU structure. Signed-off-by: Greg Kurz Message-Id: <158941060817.240484.14621015211317485106.stgit@bahia.lan> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/mmu-radix64.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/ppc/mmu-radix64.h b/target/ppc/mmu-radix64.h index 96228546aa..f28c5794d0 100644 --- a/target/ppc/mmu-radix64.h +++ b/target/ppc/mmu-radix64.h @@ -55,9 +55,9 @@ static inline int ppc_radix64_get_prot_eaa(uint64_t pte) (pte & R_PTE_EAA_X ? PAGE_EXEC : 0); } -static inline int ppc_radix64_get_prot_amr(PowerPCCPU *cpu) +static inline int ppc_radix64_get_prot_amr(const PowerPCCPU *cpu) { - CPUPPCState *env = &cpu->env; + const CPUPPCState *env = &cpu->env; int amr = env->spr[SPR_AMR] >> 62; /* We only care about key0 AMR63:62 */ int iamr = env->spr[SPR_IAMR] >> 62; /* We only care about key0 IAMR63:62 */ From 1830422611806abba07694605e933a566d634eec Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 14 May 2020 00:56:54 +0200 Subject: [PATCH 0677/2595] target/ppc: Pass const pointer to ppc_radix64_get_fully_qualified_addr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This doesn't require write access to the CPU registers. Signed-off-by: Greg Kurz Message-Id: <158941061434.240484.10700096396035994133.stgit@bahia.lan> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 1404e53dec..c76879f65b 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -28,7 +28,8 @@ #include "mmu-radix64.h" #include "mmu-book3s-v3.h" -static bool ppc_radix64_get_fully_qualified_addr(CPUPPCState *env, vaddr eaddr, +static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env, + vaddr eaddr, uint64_t *lpid, uint64_t *pid) { if (msr_hv) { /* MSR[HV] -> Hypervisor/bare metal */ From 7caee782e996988d5d178ed0838e73781f608ae1 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 14 May 2020 00:57:00 +0200 Subject: [PATCH 0678/2595] target/ppc: Don't initialize some local variables in ppc_radix64_xlate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is the job of the ppc_radix64_get_fully_qualified_addr() function which is called at the beginning of ppc_radix64_xlate() to set both lpid *and* pid. It doesn't buy us anything to initialize them first. Worse, a bug in ppc_radix64_get_fully_qualified_addr(), eg. failing to set either lpid or pid, would be undetectable by static analysis tools like coverity. Some recent versions of gcc (eg. gcc-9.3.1-2.fc30) may still think that lpid or pid is used uninitialized though, so this also adds default cases in the switch statements to make it clear this cannot happen. Signed-off-by: Greg Kurz Message-Id: <158941062048.240484.9693581559252337111.stgit@bahia.lan> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index c76879f65b..07f956c986 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -50,6 +50,8 @@ static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env, *lpid = 0; *pid = 0; break; + default: + g_assert_not_reached(); } } else { /* !MSR[HV] -> Guest */ switch (eaddr & R_EADDR_QUADRANT) { @@ -64,6 +66,8 @@ static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env, *lpid = env->spr[SPR_LPIDR]; *pid = 0; /* pid set to 0 -> addresses guest operating system */ break; + default: + g_assert_not_reached(); } } @@ -433,7 +437,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, bool cause_excp) { CPUPPCState *env = &cpu->env; - uint64_t lpid = 0, pid = 0; + uint64_t lpid, pid; ppc_v3_pate_t pate; int psize, prot; hwaddr g_raddr; From b577031cf21e367583616e9f1ab530ee755c726d Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 14 May 2020 00:57:07 +0200 Subject: [PATCH 0679/2595] target/ppc: Add missing braces in ppc_radix64_partition_scoped_xlate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per CODING_STYLE. Fixes: d04ea940c597 "target/ppc: Add support for Radix partition-scoped translation" Signed-off-by: Greg Kurz Message-Id: <158941062665.240484.2663106458734800894.stgit@bahia.lan> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 07f956c986..fb7dfe25ba 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -286,8 +286,9 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx, pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size, &pte, &fault_cause, &pte_addr) || ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, h_prot, true)) { - if (pde_addr) /* address being translated was that of a guest pde */ + if (pde_addr) { /* address being translated was that of a guest pde */ fault_cause |= DSISR_PRTABLE_FAULT; + } if (cause_excp) { ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause); } From 31efae9958a8a085d248a74a9448048bac5d6e68 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 14 May 2020 00:57:13 +0200 Subject: [PATCH 0680/2595] target/ppc: Fix arguments to ppc_radix64_partition_scoped_xlate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The last two arguments have the bool type. Also, we shouldn't raise an exception when using gdbstub. This was found while reading the code. Since it only affects the powernv machine, I didn't dig further to find an actual bug. Fixes: d04ea940c597 "target/ppc: Add support for Radix partition-scoped translation" Signed-off-by: Greg Kurz Message-Id: <158941063281.240484.9114539141307005992.stgit@bahia.lan> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index fb7dfe25ba..7ce37cb778 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -339,7 +339,8 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, */ ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr, pate, &h_raddr, &h_prot, - &h_page_size, 1, 1); + &h_page_size, true, + cause_excp); if (ret) { return ret; } @@ -378,7 +379,8 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, do { ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr, pate, &h_raddr, &h_prot, - &h_page_size, 1, 1); + &h_page_size, true, + cause_excp); if (ret) { return ret; } From e606a5580131855ce79f1f585e91ac0b6dd805ae Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 14 May 2020 00:57:19 +0200 Subject: [PATCH 0681/2595] target/ppc: Don't update radix PTE R/C bits with gdbstub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gdbstub shouldn't silently change guest visible state when doing address translation. Since the R/C bits can only be updated when handling a MMU fault, let's reuse the cause_excp flag and rename it to guest_visible. While here drop a not very useful comment. This was found while reading the code. I could verify that this affects both powernv and pseries, but I failed to observe any actual bug. Fixes: d04ea940c597 "target/ppc: Add support for Radix partition-scoped translation" Signed-off-by: Greg Kurz Message-Id: <158941063899.240484.2778628492106387793.stgit@bahia.lan> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 7ce37cb778..0d3922537c 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -274,7 +274,7 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx, ppc_v3_pate_t pate, hwaddr *h_raddr, int *h_prot, int *h_page_size, bool pde_addr, - bool cause_excp) + bool guest_visible) { int fault_cause = 0; hwaddr pte_addr; @@ -289,14 +289,15 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx, if (pde_addr) { /* address being translated was that of a guest pde */ fault_cause |= DSISR_PRTABLE_FAULT; } - if (cause_excp) { + if (guest_visible) { ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause); } return 1; } - /* Update Reference and Change Bits */ - ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot); + if (guest_visible) { + ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot); + } return 0; } @@ -305,7 +306,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, vaddr eaddr, uint64_t pid, ppc_v3_pate_t pate, hwaddr *g_raddr, int *g_prot, int *g_page_size, - bool cause_excp) + bool guest_visible) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; @@ -319,7 +320,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12); if (offset >= size) { /* offset exceeds size of the process table */ - if (cause_excp) { + if (guest_visible) { ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); } return 1; @@ -340,7 +341,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr, pate, &h_raddr, &h_prot, &h_page_size, true, - cause_excp); + guest_visible); if (ret) { return ret; } @@ -360,7 +361,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, &fault_cause, &pte_addr); if (ret) { /* No valid PTE */ - if (cause_excp) { + if (guest_visible) { ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); } return ret; @@ -380,7 +381,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr, pate, &h_raddr, &h_prot, &h_page_size, true, - cause_excp); + guest_visible); if (ret) { return ret; } @@ -389,7 +390,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, &nls, g_page_size, &pte, &fault_cause); if (ret) { /* No valid pte */ - if (cause_excp) { + if (guest_visible) { ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); } return ret; @@ -406,13 +407,15 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, if (ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) { /* Access denied due to protection */ - if (cause_excp) { + if (guest_visible) { ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); } return 1; } - ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot); + if (guest_visible) { + ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot); + } return 0; } @@ -437,7 +440,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, bool relocation, hwaddr *raddr, int *psizep, int *protp, - bool cause_excp) + bool guest_visible) { CPUPPCState *env = &cpu->env; uint64_t lpid, pid; @@ -447,7 +450,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, /* Virtual Mode Access - get the fully qualified address */ if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) { - if (cause_excp) { + if (guest_visible) { ppc_radix64_raise_segi(cpu, rwx, eaddr); } return 1; @@ -460,13 +463,13 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, vhc->get_pate(cpu->vhyp, &pate); } else { if (!ppc64_v3_get_pate(cpu, lpid, &pate)) { - if (cause_excp) { + if (guest_visible) { ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); } return 1; } if (!validate_pate(cpu, lpid, &pate)) { - if (cause_excp) { + if (guest_visible) { ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG); } return 1; @@ -487,7 +490,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, if (relocation) { int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid, pate, &g_raddr, &prot, - &psize, cause_excp); + &psize, guest_visible); if (ret) { return ret; } @@ -510,7 +513,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr, pate, raddr, &prot, &psize, - 0, cause_excp); + 0, guest_visible); if (ret) { return ret; } From a1cf0c7ce54942f9a45ac6026faffb9814b502b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 25 May 2020 05:39:10 +0200 Subject: [PATCH 0682/2595] hw/pci-bridge/dec: Remove dead debug code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove debug code never used since added in commit e1c6bbabee30. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200525033910.26166-1-f4bug@amsat.org> Signed-off-by: David Gibson --- hw/pci-bridge/dec.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c index 3ae2f788a4..952bc71122 100644 --- a/hw/pci-bridge/dec.c +++ b/hw/pci-bridge/dec.c @@ -32,16 +32,6 @@ #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_bus.h" -/* debug DEC */ -//#define DEBUG_DEC - -#ifdef DEBUG_DEC -#define DEC_DPRINTF(fmt, ...) \ - do { printf("DEC: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DEC_DPRINTF(fmt, ...) -#endif - #define DEC_21154(obj) OBJECT_CHECK(DECState, (obj), TYPE_DEC_21154) typedef struct DECState { From 1521735c2a6df9396ae232fe077af9def85eef91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 24 May 2020 18:51:26 +0200 Subject: [PATCH 0683/2595] hw/nvram/mac_nvram: Convert debug printf()s to trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert NVR_DPRINTF() to trace events and remove ifdef'ry. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200524165126.13920-1-f4bug@amsat.org> Reviewed-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/nvram/mac_nvram.c | 17 +++-------------- hw/nvram/trace-events | 4 ++++ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c index ff5db03e6b..beec1c4e4d 100644 --- a/hw/nvram/mac_nvram.c +++ b/hw/nvram/mac_nvram.c @@ -30,18 +30,9 @@ #include "migration/vmstate.h" #include "qemu/cutils.h" #include "qemu/module.h" +#include "trace.h" #include -/* debug NVR */ -//#define DEBUG_NVR - -#ifdef DEBUG_NVR -#define NVR_DPRINTF(fmt, ...) \ - do { printf("NVR: " fmt , ## __VA_ARGS__); } while (0) -#else -#define NVR_DPRINTF(fmt, ...) -#endif - #define DEF_SYSTEM_SIZE 0xc10 /* macio style NVRAM device */ @@ -51,9 +42,8 @@ static void macio_nvram_writeb(void *opaque, hwaddr addr, MacIONVRAMState *s = opaque; addr = (addr >> s->it_shift) & (s->size - 1); + trace_macio_nvram_write(addr, value); s->data[addr] = value; - NVR_DPRINTF("writeb addr %04" HWADDR_PRIx " val %" PRIx64 "\n", - addr, value); } static uint64_t macio_nvram_readb(void *opaque, hwaddr addr, @@ -64,8 +54,7 @@ static uint64_t macio_nvram_readb(void *opaque, hwaddr addr, addr = (addr >> s->it_shift) & (s->size - 1); value = s->data[addr]; - NVR_DPRINTF("readb addr %04" HWADDR_PRIx " val %" PRIx32 "\n", - addr, value); + trace_macio_nvram_read(addr, value); return value; } diff --git a/hw/nvram/trace-events b/hw/nvram/trace-events index 0dea9260ce..e023193295 100644 --- a/hw/nvram/trace-events +++ b/hw/nvram/trace-events @@ -13,3 +13,7 @@ fw_cfg_add_string(uint16_t key_value, const char *key_name, const char *value) " fw_cfg_add_i16(uint16_t key_value, const char *key_name, uint16_t value) "key 0x%04" PRIx16 " '%s', value 0x%" PRIx16 fw_cfg_add_i32(uint16_t key_value, const char *key_name, uint32_t value) "key 0x%04" PRIx16 " '%s', value 0x%" PRIx32 fw_cfg_add_i64(uint16_t key_value, const char *key_name, uint64_t value) "key 0x%04" PRIx16 " '%s', value 0x%" PRIx64 + +# mac_nvram.c +macio_nvram_read(uint32_t addr, uint8_t val) "read addr=0x%04"PRIx32" val=0x%02x" +macio_nvram_write(uint32_t addr, uint8_t val) "write addr=0x%04"PRIx32" val=0x%02x" From 47e112c4dd8ca0bd4d7872f8bf1a97183915069f Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 26 May 2020 18:20:37 +0200 Subject: [PATCH 0684/2595] target/ppc: Fix argument to ppc_radix64_partition_scoped_xlate() again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The penultimate argument of function ppc_radix64_partition_scoped_xlate() has the bool type. Fixes: d04ea940c597 "target/ppc: Add support for Radix partition-scoped translation" Signed-off-by: Greg Kurz Message-Id: <159051003729.407106.10610703877543955831.stgit@bahia.lan> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: David Gibson --- target/ppc/mmu-radix64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 0d3922537c..c60bf31357 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -513,7 +513,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr, pate, raddr, &prot, &psize, - 0, guest_visible); + false, guest_visible); if (ret) { return ret; } From 9c7c0407028355ca83349b8a60fddfad46f2ebd8 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 1 May 2020 02:54:49 -0300 Subject: [PATCH 0685/2595] vfio/nvlink: Remove exec permission to avoid SELinux AVCs If SELinux is setup without 'execmem' permission for qemu, all mmap with (PROT_WRITE | PROT_EXEC) will fail and print a warning in SELinux log. If "nvlink2-mr" memory allocation fails (fist diff), it will cause guest NUMA nodes to not be correctly configured (V100 memory will not be visible for guest, nor its NUMA nodes). Not having 'execmem' permission is intesting for virtual machines to avoid buffer-overflow based attacks, and it's adopted in distros like RHEL. So, removing the PROT_EXEC flag seems the right thing to do. Browsing some other code that mmaps memory for usage with memory_region_init_ram_device_ptr, I could notice it's usual to not have PROT_EXEC (only PROT_READ | PROT_WRITE), so it should be no problem around this. Signed-off-by: Leonardo Bras Message-Id: <20200501055448.286518-1-leobras.c@gmail.com> Acked-by: Alex Williamson Signed-off-by: David Gibson --- hw/vfio/pci-quirks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index 3bd05fed12..f2155ddb1d 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1620,7 +1620,7 @@ int vfio_pci_nvidia_v100_ram_init(VFIOPCIDevice *vdev, Error **errp) } cap = (void *) hdr; - p = mmap(NULL, nv2reg->size, PROT_READ | PROT_WRITE | PROT_EXEC, + p = mmap(NULL, nv2reg->size, PROT_READ | PROT_WRITE, MAP_SHARED, vdev->vbasedev.fd, nv2reg->offset); if (p == MAP_FAILED) { ret = -errno; @@ -1680,7 +1680,7 @@ int vfio_pci_nvlink2_init(VFIOPCIDevice *vdev, Error **errp) /* Some NVLink bridges may not have assigned ATSD */ if (atsdreg->size) { - p = mmap(NULL, atsdreg->size, PROT_READ | PROT_WRITE | PROT_EXEC, + p = mmap(NULL, atsdreg->size, PROT_READ | PROT_WRITE, MAP_SHARED, vdev->vbasedev.fd, atsdreg->offset); if (p == MAP_FAILED) { ret = -errno; From 75de4efa00d2e3df5abfd6b35fc5b04e98443dd2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 12:18:59 +0200 Subject: [PATCH 0686/2595] nvdimm: Plug memory leak in uuid property setter nvdimm_set_uuid() leaks memory on qemu_uuid_parse() failure. Fix that. Fixes: 6c5627bb24dcd68c997857a8b671617333b1289f Cc: Xiao Guangrong Cc: Shivaprasad G Bhat Signed-off-by: Markus Armbruster Message-Id: <20200505101908.6207-2-armbru@redhat.com> Tested-by: Shivaprasad G Bhat Reviewed-by: Shivaprasad G Bhat --- hw/mem/nvdimm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index c5adedcc69..76f66e0b19 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -97,7 +97,6 @@ static void nvdimm_set_uuid(Object *obj, Visitor *v, const char *name, if (qemu_uuid_parse(value, &nvdimm->uuid) != 0) { error_setg(errp, "Property '%s.%s' has invalid value", object_get_typename(obj), name); - goto out; } g_free(value); From 56f9dde414053410857d0083e92e5b1b45cf33dc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 12:19:00 +0200 Subject: [PATCH 0687/2595] xen: Fix and improve handling of device_add usb-host errors usbback_portid_add() leaks the error when qdev_device_add() fails. Fix that. While there, use the error to improve the error message. The qemu_opts_from_qdict() similarly leaks on failure. But any failure there is a programming error. Pass &error_abort. Fixes: 816ac92ef769f9ffc534e49a1bb6177bddce7aa2 Cc: Stefano Stabellini Cc: Anthony Perard Cc: Paul Durrant Cc: Gerd Hoffmann Cc: xen-devel@lists.xenproject.org Signed-off-by: Markus Armbruster Message-Id: <20200505101908.6207-3-armbru@redhat.com> Acked-by: Paul Durrant --- hw/usb/xen-usb.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c index 961190d0f7..4d266d7bb4 100644 --- a/hw/usb/xen-usb.c +++ b/hw/usb/xen-usb.c @@ -30,6 +30,7 @@ #include "hw/usb.h" #include "hw/xen/xen-legacy-backend.h" #include "monitor/qdev.h" +#include "qapi/error.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" @@ -755,13 +756,16 @@ static void usbback_portid_add(struct usbback_info *usbif, unsigned port, qdict_put_int(qdict, "port", port); qdict_put_int(qdict, "hostbus", atoi(busid)); qdict_put_str(qdict, "hostport", portname); - opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err); - if (local_err) { - goto err; - } + opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, + &error_abort); usbif->ports[port - 1].dev = USB_DEVICE(qdev_device_add(opts, &local_err)); if (!usbif->ports[port - 1].dev) { - goto err; + qobject_unref(qdict); + xen_pv_printf(&usbif->xendev, 0, + "device %s could not be opened: %s\n", + busid, error_get_pretty(local_err)); + error_free(local_err); + return; } qobject_unref(qdict); speed = usbif->ports[port - 1].dev->speed; @@ -793,11 +797,6 @@ static void usbback_portid_add(struct usbback_info *usbif, unsigned port, usbback_hotplug_enq(usbif, port); TR_BUS(&usbif->xendev, "port %d attached\n", port); - return; - -err: - qobject_unref(qdict); - xen_pv_printf(&usbif->xendev, 0, "device %s could not be opened\n", busid); } static void usbback_process_port(struct usbback_info *usbif, unsigned port) From 5e959d2e6e698af86a7064ead87ebe47706d99c7 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 12:19:01 +0200 Subject: [PATCH 0688/2595] s390x/cpumodel: Fix harmless misuse of visit_check_struct() Commit e47970f51d "s390x/cpumodel: Fix query-cpu-model-FOO error API violations" neglected to change visit_check_struct()'s Error ** argument along with the others. If visit_check_struct() failed, we'd take the success path. Fortunately, it can't fail here: qobject_input_check_struct() checks we consumed the whole dictionary, and to get here, we did. Fix it anyway. Cc: David Hildenbrand Cc: Cornelia Huck Signed-off-by: Markus Armbruster Reviewed-by: David Hildenbrand Reviewed-by: Cornelia Huck Message-Id: <20200505101908.6207-4-armbru@redhat.com> --- target/s390x/cpu_models.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 8efe6ed514..2fa609bffe 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -524,7 +524,7 @@ static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info, } } if (!err) { - visit_check_struct(visitor, errp); + visit_check_struct(visitor, &err); } visit_end_struct(visitor, NULL); visit_free(visitor); From d01127584e70f9242d3dd9bf4c0bdc1980254713 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 12:19:02 +0200 Subject: [PATCH 0689/2595] tests/migration: Tighten error checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit migrate_get_socket_address() neglects to check visit_type_SocketAddressList() failure. This smells like a leak, but it actually will crash dereferencing @addrs. Pass &error_abort to remove the code smell. Signed-off-by: Markus Armbruster Message-Id: <20200505101908.6207-5-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- tests/qtest/migration-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 2568c9529c..dc3490c9fa 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "libqtest.h" +#include "qapi/error.h" #include "qapi/qmp/qdict.h" #include "qemu/module.h" #include "qemu/option.h" @@ -301,7 +302,6 @@ static char *migrate_get_socket_address(QTestState *who, const char *parameter) { QDict *rsp; char *result; - Error *local_err = NULL; SocketAddressList *addrs; Visitor *iv = NULL; QObject *object; @@ -310,7 +310,7 @@ static char *migrate_get_socket_address(QTestState *who, const char *parameter) object = qdict_get(rsp, parameter); iv = qobject_input_visitor_new(object); - visit_type_SocketAddressList(iv, NULL, &addrs, &local_err); + visit_type_SocketAddressList(iv, NULL, &addrs, &error_abort); visit_free(iv); /* we are only using a single address */ From 5217f1887a8041c51495fbd5d3f767d96a242000 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 12:19:03 +0200 Subject: [PATCH 0690/2595] error: Use error_reportf_err() where appropriate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace error_report("...: %s", ..., error_get_pretty(err)); by error_reportf_err(err, "...: ", ...); One of the replaced messages lacked a colon. Add it. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200505101908.6207-6-armbru@redhat.com> --- chardev/char-socket.c | 5 +++-- hw/sd/pxa2xx_mmci.c | 4 ++-- hw/sd/sd.c | 4 ++-- hw/usb/dev-mtp.c | 9 +++++---- qemu-nbd.c | 7 +++---- scsi/qemu-pr-helper.c | 4 ++-- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index e77699db48..db253d4024 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -138,8 +138,9 @@ static void check_report_connect_error(Chardev *chr, SocketChardev *s = SOCKET_CHARDEV(chr); if (!s->connect_err_reported) { - error_report("Unable to connect character device %s: %s", - chr->label, error_get_pretty(err)); + error_reportf_err(err, + "Unable to connect character device %s: ", + chr->label); s->connect_err_reported = true; } qemu_chr_socket_restart_timer(chr); diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index 8f9ab0ec16..f9c50ddda5 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -497,12 +497,12 @@ PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &err); if (err) { - error_report("failed to init SD card: %s", error_get_pretty(err)); + error_reportf_err(err, "failed to init SD card: "); return NULL; } object_property_set_bool(OBJECT(carddev), true, "realized", &err); if (err) { - error_report("failed to init SD card: %s", error_get_pretty(err)); + error_reportf_err(err, "failed to init SD card: "); return NULL; } diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 71a9af09ab..3c06a0ac6d 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -703,13 +703,13 @@ SDState *sd_init(BlockBackend *blk, bool is_spi) dev = DEVICE(obj); qdev_prop_set_drive(dev, "drive", blk, &err); if (err) { - error_report("sd_init failed: %s", error_get_pretty(err)); + error_reportf_err(err, "sd_init failed: "); return NULL; } qdev_prop_set_bit(dev, "spi", is_spi); object_property_set_bool(obj, true, "realized", &err); if (err) { - error_report("sd_init failed: %s", error_get_pretty(err)); + error_reportf_err(err, "sd_init failed: "); return NULL; } diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 20717f026b..168428156b 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -631,8 +631,9 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o) int64_t id = qemu_file_monitor_add_watch(s->file_monitor, o->path, NULL, file_monitor_event, s, &err); if (id == -1) { - error_report("usb-mtp: failed to add watch for %s: %s", o->path, - error_get_pretty(err)); + error_reportf_err(err, + "usb-mtp: failed to add watch for %s: ", + o->path); error_free(err); } else { trace_usb_mtp_file_monitor_event(s->dev.addr, o->path, @@ -1276,8 +1277,8 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) s->file_monitor = qemu_file_monitor_new(&err); if (err) { - error_report("usb-mtp: file monitoring init failed: %s", - error_get_pretty(err)); + error_reportf_err(err, + "usb-mtp: file monitoring init failed: "); error_free(err); } else { QTAILQ_INIT(&s->events); diff --git a/qemu-nbd.c b/qemu-nbd.c index 306e44fb0a..d2657b8db5 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -856,8 +856,7 @@ int main(int argc, char **argv) } tlscreds = nbd_get_tls_creds(tlscredsid, list, &local_err); if (local_err) { - error_report("Failed to get TLS creds %s", - error_get_pretty(local_err)); + error_reportf_err(local_err, "Failed to get TLS creds: "); exit(EXIT_FAILURE); } } else { @@ -983,8 +982,8 @@ int main(int argc, char **argv) &local_err); if (sioc == NULL) { object_unref(OBJECT(server)); - error_report("Failed to use socket activation: %s", - error_get_pretty(local_err)); + error_reportf_err(local_err, + "Failed to use socket activation: "); exit(EXIT_FAILURE); } qio_net_listener_add(server, sioc); diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index 181ed4a186..57ad830d54 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -1030,8 +1030,8 @@ int main(int argc, char **argv) server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD, &local_err); if (server_ioc == NULL) { - error_report("Failed to use socket activation: %s", - error_get_pretty(local_err)); + error_reportf_err(local_err, + "Failed to use socket activation: "); exit(EXIT_FAILURE); } } From a729f9bc843a11230d6e7b460b2115e6a55a0f7e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 12:19:04 +0200 Subject: [PATCH 0691/2595] mips/malta: Fix create_cps() error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second create_cps() is wrong that way. The last calls treats an error as fatal. Do that for the prior ones, too. Fixes: bff384a4fbd5d0e86939092e74e766ef0f5f592c Cc: Aleksandar Markovic Cc: "Philippe Mathieu-Daudé" Cc: Aurelien Jarno Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20200505101908.6207-7-armbru@redhat.com> Reviewed-by: Aleksandar Markovic --- hw/mips/mips_malta.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index e4c4de1b4e..17bf41616b 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -1185,17 +1185,14 @@ static void create_cpu_without_cps(MachineState *ms, static void create_cps(MachineState *ms, MaltaState *s, qemu_irq *cbus_irq, qemu_irq *i8259_irq) { - Error *err = NULL; - sysbus_init_child_obj(OBJECT(s), "cps", OBJECT(&s->cps), sizeof(s->cps), TYPE_MIPS_CPS); - object_property_set_str(OBJECT(&s->cps), ms->cpu_type, "cpu-type", &err); - object_property_set_int(OBJECT(&s->cps), ms->smp.cpus, "num-vp", &err); - object_property_set_bool(OBJECT(&s->cps), true, "realized", &err); - if (err != NULL) { - error_report("%s", error_get_pretty(err)); - exit(1); - } + object_property_set_str(OBJECT(&s->cps), ms->cpu_type, "cpu-type", + &error_fatal); + object_property_set_int(OBJECT(&s->cps), ms->smp.cpus, "num-vp", + &error_fatal); + object_property_set_bool(OBJECT(&s->cps), true, "realized", + &error_fatal); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1); From 932d3a65c8bfe0c260d3564afc082c41febdd882 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 12:19:05 +0200 Subject: [PATCH 0692/2595] mips/boston: Fix boston_mach_init() error handling The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. boston_mach_init() is wrong that way. The last calls treats an error as fatal. Do that for the prior ones, too. Fixes: df1d8a1f29f567567b9d20be685a4241282e7005 Cc: Paul Burton Cc: Aleksandar Rikalo Signed-off-by: Markus Armbruster Message-Id: <20200505101908.6207-8-armbru@redhat.com> Reviewed-by: Aleksandar Markovic --- hw/mips/boston.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/hw/mips/boston.c b/hw/mips/boston.c index 98ecd25e8e..2832dfa6ae 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -458,14 +458,11 @@ static void boston_mach_init(MachineState *machine) sysbus_init_child_obj(OBJECT(machine), "cps", OBJECT(&s->cps), sizeof(s->cps), TYPE_MIPS_CPS); object_property_set_str(OBJECT(&s->cps), machine->cpu_type, "cpu-type", - &err); - object_property_set_int(OBJECT(&s->cps), machine->smp.cpus, "num-vp", &err); - object_property_set_bool(OBJECT(&s->cps), true, "realized", &err); - - if (err != NULL) { - error_report("%s", error_get_pretty(err)); - exit(1); - } + &error_fatal); + object_property_set_int(OBJECT(&s->cps), machine->smp.cpus, "num-vp", + &error_fatal); + object_property_set_bool(OBJECT(&s->cps), true, "realized", + &error_fatal); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1); From 3e1df4cc46678b155c9d721c73ab6e310d7dd546 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 12:19:06 +0200 Subject: [PATCH 0693/2595] mips/boston: Plug memory leak in boston_mach_init() Fixes: df1d8a1f29f567567b9d20be685a4241282e7005 Cc: Paul Burton Cc: Aleksandar Rikalo Signed-off-by: Markus Armbruster Message-Id: <20200505101908.6207-9-armbru@redhat.com> Reviewed-by: Aleksandar Markovic --- hw/mips/boston.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/mips/boston.c b/hw/mips/boston.c index 2832dfa6ae..a896056be1 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -426,7 +426,6 @@ static void boston_mach_init(MachineState *machine) { DeviceState *dev; BostonState *s; - Error *err = NULL; MemoryRegion *flash, *ddr_low_alias, *lcd, *platreg; MemoryRegion *sys_mem = get_system_memory(); XilinxPCIEHost *pcie2; @@ -467,7 +466,8 @@ static void boston_mach_init(MachineState *machine) sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1); flash = g_new(MemoryRegion, 1); - memory_region_init_rom(flash, NULL, "boston.flash", 128 * MiB, &err); + memory_region_init_rom(flash, NULL, "boston.flash", 128 * MiB, + &error_fatal); memory_region_add_subregion_overlap(sys_mem, 0x18000000, flash, 0); memory_region_add_subregion_overlap(sys_mem, 0x80000000, machine->ram, 0); From 3b914406cf3cfb4ac48388c1ea15036b333b7a79 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 12:19:07 +0200 Subject: [PATCH 0694/2595] arm/sabrelite: Consistently use &error_fatal in sabrelite_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Peter Maydell Cc: Jean-Christophe Dubois Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200505101908.6207-10-armbru@redhat.com> [Straightforward conflict with resolved d2623129a7 "qom: Drop parameter @errp of object_property_add() & friends"] --- hw/arm/sabrelite.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index 6f0e233d77..96cb30aa3c 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -41,7 +41,6 @@ static void sabrelite_reset_secondary(ARMCPU *cpu, static void sabrelite_init(MachineState *machine) { FslIMX6State *s; - Error *err = NULL; /* Check the amount of memory is compatible with the SOC */ if (machine->ram_size > FSL_IMX6_MMDC_SIZE) { @@ -52,11 +51,7 @@ static void sabrelite_init(MachineState *machine) s = FSL_IMX6(object_new(TYPE_FSL_IMX6)); object_property_add_child(OBJECT(machine), "soc", OBJECT(s)); - object_property_set_bool(OBJECT(s), true, "realized", &err); - if (err != NULL) { - error_report("%s", error_get_pretty(err)); - exit(1); - } + object_property_set_bool(OBJECT(s), true, "realized", &error_fatal); memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR, machine->ram); From 49e2fa85ff04a9be89ed15f922c7d8dae2be9e74 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 May 2020 12:19:08 +0200 Subject: [PATCH 0695/2595] i386: Fix x86_cpu_load_model() error API violation The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. x86_cpu_load_model() is wrong that way. Harmless, because its @errp is always &error_abort. To fix, cut out the @errp middleman. Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Markus Armbruster Message-Id: <20200505101908.6207-11-armbru@redhat.com> --- target/i386/cpu.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 7a4a8e3847..3733d9a279 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5078,7 +5078,7 @@ static void x86_cpu_apply_version_props(X86CPU *cpu, X86CPUModel *model) /* Load data from X86CPUDefinition into a X86CPU object */ -static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model, Error **errp) +static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) { X86CPUDefinition *def = model->cpudef; CPUX86State *env = &cpu->env; @@ -5092,13 +5092,19 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model, Error **errp) */ /* CPU models only set _minimum_ values for level/xlevel: */ - object_property_set_uint(OBJECT(cpu), def->level, "min-level", errp); - object_property_set_uint(OBJECT(cpu), def->xlevel, "min-xlevel", errp); + object_property_set_uint(OBJECT(cpu), def->level, "min-level", + &error_abort); + object_property_set_uint(OBJECT(cpu), def->xlevel, "min-xlevel", + &error_abort); - object_property_set_int(OBJECT(cpu), def->family, "family", errp); - object_property_set_int(OBJECT(cpu), def->model, "model", errp); - object_property_set_int(OBJECT(cpu), def->stepping, "stepping", errp); - object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp); + object_property_set_int(OBJECT(cpu), def->family, "family", + &error_abort); + object_property_set_int(OBJECT(cpu), def->model, "model", + &error_abort); + object_property_set_int(OBJECT(cpu), def->stepping, "stepping", + &error_abort); + object_property_set_str(OBJECT(cpu), def->model_id, "model-id", + &error_abort); for (w = 0; w < FEATURE_WORDS; w++) { env->features[w] = def->features[w]; } @@ -5135,7 +5141,8 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model, Error **errp) vendor = host_vendor; } - object_property_set_str(OBJECT(cpu), vendor, "vendor", errp); + object_property_set_str(OBJECT(cpu), vendor, "vendor", + &error_abort); x86_cpu_apply_version_props(cpu, model); } @@ -6975,7 +6982,7 @@ static void x86_cpu_initfn(Object *obj) object_property_add_alias(obj, "sse4_2", obj, "sse4.2"); if (xcc->model) { - x86_cpu_load_model(cpu, xcc->model, &error_abort); + x86_cpu_load_model(cpu, xcc->model); } } From 3df437c737984069fbc12fd0d2e0f2f2c5ba5d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 19 May 2020 09:22:48 -0400 Subject: [PATCH 0696/2595] configure: add alternate binary for genisoimage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not all distros ship genisoimage which is a Debian fork from the original cdrtools. As the options are pretty much the same support it as a fallback binary. Signed-off-by: Alex Bennée Signed-off-by: Robert Foley Message-Id: <20200519132259.405-2-robert.foley@linaro.org> --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index b969dee675..af2ba83f0e 100755 --- a/configure +++ b/configure @@ -941,7 +941,7 @@ done # Check for ancillary tools used in testing genisoimage= -for binary in genisoimage +for binary in genisoimage mkisofs do if has $binary then From 92fecad3d3ed3cbfd0a6b4408bb80920de803dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 19 May 2020 09:22:49 -0400 Subject: [PATCH 0697/2595] tests/vm: pass --genisoimage to basevm script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we have an alternative to genisoimage we really need to tell the script about it as well so it can use it. It will still default to genisoimage in case it is run outside our build machinery. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Robert Foley Message-Id: <20200519132259.405-3-robert.foley@linaro.org> --- tests/vm/Makefile.include | 1 + tests/vm/basevm.py | 16 ++++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include index 1bf9693d19..74ab522c55 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -56,6 +56,7 @@ $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \ $(call quiet-command, \ $(PYTHON) $< \ $(if $(V)$(DEBUG), --debug) \ + $(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \ --image "$@" \ --force \ --build-image $@, \ diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 756ccf7aca..a2d4054d72 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -61,8 +61,9 @@ class BaseVM(object): # 4 is arbitrary, but greater than 2, # since we found we need to wait more than twice as long. tcg_ssh_timeout_multiplier = 4 - def __init__(self, debug=False, vcpus=None): + def __init__(self, debug=False, vcpus=None, genisoimage=None): self._guest = None + self._genisoimage = genisoimage self._tmpdir = os.path.realpath(tempfile.mkdtemp(prefix="vm-test-", suffix=".tmp", dir=".")) @@ -381,12 +382,12 @@ class BaseVM(object): udata.writelines(["apt:\n", " proxy: %s" % proxy]) udata.close() - subprocess.check_call(["genisoimage", "-output", "cloud-init.iso", + subprocess.check_call([self._genisoimage, "-output", "cloud-init.iso", "-volid", "cidata", "-joliet", "-rock", "user-data", "meta-data"], - cwd=cidir, - stdin=self._devnull, stdout=self._stdout, - stderr=self._stdout) + cwd=cidir, + stdin=self._devnull, stdout=self._stdout, + stderr=self._stdout) return os.path.join(cidir, "cloud-init.iso") @@ -424,6 +425,8 @@ def parse_args(vmcls): help="Interactively run command") parser.add_option("--snapshot", "-s", action="store_true", help="run tests with a snapshot") + parser.add_option("--genisoimage", default="genisoimage", + help="iso imaging tool") parser.disable_interspersed_args() return parser.parse_args() @@ -435,7 +438,8 @@ def main(vmcls): return 1 logging.basicConfig(level=(logging.DEBUG if args.debug else logging.WARN)) - vm = vmcls(debug=args.debug, vcpus=args.jobs) + vm = vmcls(debug=args.debug, vcpus=args.jobs, + genisoimage=args.genisoimage) if args.build_image: if os.path.exists(args.image) and not args.force: sys.stderr.writelines(["Image file exists: %s\n" % args.image, From 6f83cf88f02a98e857b6cadd4b4e27401b901bba Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 20 May 2020 15:05:29 +0100 Subject: [PATCH 0698/2595] travis.yml: Use clang++ in the Clang tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our configure script does not look for clang++ automatically, so we should use --cxx=clang++ to make sure that we test our C++ code with Clang, too. And while we're at it, also use --host-cc=clang here to avoid that we use the normal "cc" as host C compiler. Signed-off-by: Thomas Huth Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200518083316.25065-1-thuth@redhat.com> Message-Id: <20200520140541.30256-4-alex.bennee@linaro.org> --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1ec8a7b465..564be50a3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -205,14 +205,15 @@ jobs: # Test with Clang for compile portability (Travis uses clang-5.0) - name: "Clang (user)" env: - - CONFIG="--disable-system" + - CONFIG="--disable-system --host-cc=clang --cxx=clang++" - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default" compiler: clang - name: "Clang (main-softmmu)" env: - - CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS} " + - CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS} + --host-cc=clang --cxx=clang++" - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-sanitize" compiler: clang before_script: @@ -222,7 +223,8 @@ jobs: - name: "Clang (other-softmmu)" env: - - CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}" + - CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS} + --host-cc=clang --cxx=clang++" - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default" compiler: clang From be9bc1b73a12f1ebfb2ce2f9edfacc5d1304561a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 20 May 2020 15:05:30 +0100 Subject: [PATCH 0699/2595] tests/tcg: fix invocation of the memory record/replay tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm not sure when this broke but we should use EXTRA_RUNS for "virtual" tests which are not generated from the binary names. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200520140541.30256-5-alex.bennee@linaro.org> --- tests/tcg/aarch64/Makefile.softmmu-target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target index 71f72cfbe3..1057a8ac49 100644 --- a/tests/tcg/aarch64/Makefile.softmmu-target +++ b/tests/tcg/aarch64/Makefile.softmmu-target @@ -61,7 +61,7 @@ run-memory-replay: memory-replay run-memory-record $(QEMU_OPTS) memory, \ "$< on $(TARGET_NAME)") -EXTRA_TESTS+=memory-record memory-replay +EXTRA_RUNS+=run-memory-replay ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_3),) pauth-3: CFLAGS += -march=armv8.3-a From 91fa8b64cbef14855dc3bd24702416313dea6481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 20 May 2020 15:05:31 +0100 Subject: [PATCH 0700/2595] tests/fp: enable extf80_le_quite tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These have been fixed now so we no longer need a special version of the le_quiet rule to skip the test. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200520140541.30256-6-alex.bennee@linaro.org> --- tests/Makefile.include | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 03a74b60f6..e6d87fcbf0 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -741,13 +741,6 @@ check-softfloat-%: $(FP_TEST_BIN) SF_COMPARE_OPS=eq eq_signaling le le_quiet lt_quiet SF_COMPARE_RULES=$(patsubst %,check-softfloat-%, $(SF_COMPARE_OPS)) -# FIXME: extF80_le_quiet (broken) -check-softfloat-le_quiet: $(FP_TEST_BIN) - $(call test-softfloat, \ - f16_le_quiet f32_le_quiet f64_le_quiet \ - f128_le_quiet, \ - le_quiet) - # FIXME: extF80_lt_quiet (broken) check-softfloat-lt_quiet: $(FP_TEST_BIN) $(call test-softfloat, \ From 8281a157c5d01c08e1d684bf7a28c3e2bebf1a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 20 May 2020 15:05:32 +0100 Subject: [PATCH 0701/2595] tests/fp: split and audit the conversion tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the float conversion tests into separate groups and audit the tests to check what is still broken. I was able to enable a bunch of tests that had been missed before: all the float to float conversions ui32_to_extF80 ui64_to_extF80 extF80_to_ui32 extF80_to_ui32_r_minMag extF80_to_ui64 extF80_to_ui64_r_minMag Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200520140541.30256-7-alex.bennee@linaro.org> --- tests/Makefile.include | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index e6d87fcbf0..a00ccc94b8 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -687,11 +687,26 @@ test-softfloat = $(call quiet-command, \ (cat $2.out && exit 1;), \ "FLOAT TEST", $2) -# Conversion Routines: +# Conversion Routines: Float to Float +# FIXME: f32_to_f128 (broken), f64_to_f128 (broken) +# FIXME: f128_to_f32(broken), f128_to_f64 (broken) +# FIXME: f128_to_extF80 (broken) +check-softfloat-conv-f2f: $(FP_TEST_BIN) + $(call test-softfloat, \ + f16_to_f32 f16_to_f64 \ + f16_to_extF80 f16_to_f128 \ + f32_to_f16 f32_to_f64 \ + f32_to_extF80 \ + f64_to_f16 f64_to_f32 \ + extF80_to_f16 extF80_to_f32 \ + extF80_to_f64 extF80_to_f128 \ + f128_to_f16, \ + float-to-float) + +# Conversion Routines: Int and Uint to Float # FIXME: i32_to_extF80 (broken), i64_to_extF80 (broken) -# ui32_to_f128 (not implemented), extF80_roundToInt (broken) -# -check-softfloat-conv: $(FP_TEST_BIN) +# ui32_to_f128 (not implemented) +check-softfloat-conv-to-float: $(FP_TEST_BIN) $(call test-softfloat, \ i32_to_f16 i64_to_f16 \ i32_to_f32 i64_to_f32 \ @@ -701,7 +716,12 @@ check-softfloat-conv: $(FP_TEST_BIN) ui32_to_f16 ui64_to_f16 \ ui32_to_f32 ui64_to_f32 \ ui32_to_f64 ui64_to_f64 \ + ui32_to_extF80 ui64_to_extF80 \ ui64_to_f128, uint-to-float) + +# Conversion Routines: Float to integers +# FIXME: extF80_roundToInt (broken) +check-softfloat-conv-to-int: $(FP_TEST_BIN) $(call test-softfloat, \ f16_to_i32 f16_to_i32_r_minMag \ f32_to_i32 f32_to_i32_r_minMag \ @@ -718,10 +738,12 @@ check-softfloat-conv: $(FP_TEST_BIN) f16_to_ui32 f16_to_ui32_r_minMag \ f32_to_ui32 f32_to_ui32_r_minMag \ f64_to_ui32 f64_to_ui32_r_minMag \ + extF80_to_ui32 extF80_to_ui32_r_minMag \ f128_to_ui32 f128_to_ui32_r_minMag \ f16_to_ui64 f16_to_ui64_r_minMag \ f32_to_ui64 f32_to_ui64_r_minMag \ f64_to_ui64 f64_to_ui64_r_minMag \ + extF80_to_ui64 extF80_to_ui64_r_minMag \ f128_to_ui64 f128_to_ui64_r_minMag, \ float-to-uint) $(call test-softfloat, \ @@ -729,9 +751,14 @@ check-softfloat-conv: $(FP_TEST_BIN) f64_roundToInt f128_roundToInt, \ round-to-integer) +.PHONY: check-softfloat-conv +check-softfloat-conv: check-softfloat-conv-f2f +check-softfloat-conv: check-softfloat-conv-to-float +check-softfloat-conv: check-softfloat-conv-to-int + # Generic rule for all float operations # -# Some patterns are overidden due to broken or missing tests. +# Some patterns are overridden due to broken or missing tests. # Hopefully these can be removed over time. check-softfloat-%: $(FP_TEST_BIN) From 8ec6f3315118ef75d37e9433dc8faa8383130fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 20 May 2020 15:05:33 +0100 Subject: [PATCH 0702/2595] tests/tcg: better detect confused gdb which can't connect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While we may gamely give the right information it can still confuse the wide range of GDBs out there. For example ppc64abi32-linux-user reports: warning: Selected architecture powerpc:common is not compatible with reported target architecture powerpc:common64 warning: Architecture rejected target-supplied description but still connects. Add a test for a 0 pc and exit early if that is the case. This may actually be a bug we need to fix? Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200520140541.30256-8-alex.bennee@linaro.org> --- tests/tcg/multiarch/gdbstub/sha1.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/tcg/multiarch/gdbstub/sha1.py b/tests/tcg/multiarch/gdbstub/sha1.py index 734553b98b..2bfde49633 100644 --- a/tests/tcg/multiarch/gdbstub/sha1.py +++ b/tests/tcg/multiarch/gdbstub/sha1.py @@ -65,6 +65,10 @@ except (gdb.error, AttributeError): print("SKIPPING (not connected)", file=sys.stderr) exit(0) +if gdb.parse_and_eval('$pc') == 0: + print("SKIP: PC not set") + exit(0) + try: # These are not very useful in scripts gdb.execute("set pagination off") From 086f269cf4eb0d759d7f716dcd239e6d310bb955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 20 May 2020 15:05:35 +0100 Subject: [PATCH 0703/2595] tests/docker: add debian11 base image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We won't use this for building QEMU but we do need newer GCC's and binutils for building some of our test cases. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200520140541.30256-10-alex.bennee@linaro.org> --- tests/docker/Makefile.include | 2 +- tests/docker/dockerfiles/debian11.docker | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/docker/dockerfiles/debian11.docker diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 43a8678688..3596b58930 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -7,7 +7,7 @@ HOST_ARCH = $(if $(ARCH),$(ARCH),$(shell uname -m)) DOCKER_SUFFIX := .docker DOCKER_FILES_DIR := $(SRC_PATH)/tests/docker/dockerfiles # we don't run tests on intermediate images (used as base by another image) -DOCKER_PARTIAL_IMAGES := debian9 debian10 +DOCKER_PARTIAL_IMAGES := debian9 debian10 debian11 DOCKER_PARTIAL_IMAGES += debian9-mxe debian-bootstrap DOCKER_IMAGES := $(sort $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker)))) DOCKER_TARGETS := $(patsubst %,docker-image-%,$(DOCKER_IMAGES)) diff --git a/tests/docker/dockerfiles/debian11.docker b/tests/docker/dockerfiles/debian11.docker new file mode 100644 index 0000000000..5adfd62d55 --- /dev/null +++ b/tests/docker/dockerfiles/debian11.docker @@ -0,0 +1,18 @@ +# +# Docker multiarch cross-compiler target +# +# This docker target uses the current development version of Debian as +# a base for cross compilers for building test binaries. We won't +# attempt to build QEMU on it yet given it is still in development. +# +# On its own you can't build much but the docker-foo-cross targets +# build on top of the base debian image. +# +FROM debian:bullseye-slim + +# 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 From c729a99d27018b8d619544b18926b234b010b733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 20 May 2020 15:05:36 +0100 Subject: [PATCH 0704/2595] tests/docker: use a gcc-10 based image for arm64 tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As we enable newer features that we want to test on arm64 targets we need newer compilers. Split off a new debian-arm64-test-cross image which we can use to build these new tests. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200520140541.30256-11-alex.bennee@linaro.org> --- tests/docker/Makefile.include | 2 ++ .../dockerfiles/debian-arm64-test-cross.docker | 13 +++++++++++++ tests/tcg/configure.sh | 4 ++-- 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/docker/dockerfiles/debian-arm64-test-cross.docker diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 3596b58930..ed46bd98eb 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -131,9 +131,11 @@ docker-image-travis: NOUSER=1 # Specialist build images, sometimes very limited tools docker-image-tricore-cross: docker-image-debian9 +docker-image-debian-arm64-test-cross: docker-image-debian11 # These images may be good enough for building tests but not for test builds DOCKER_PARTIAL_IMAGES += debian-alpha-cross +DOCKER_PARTIAL_IMAGES += debian-arm64-test-cross DOCKER_PARTIAL_IMAGES += debian-hppa-cross DOCKER_PARTIAL_IMAGES += debian-m68k-cross debian-mips64-cross DOCKER_PARTIAL_IMAGES += debian-powerpc-cross debian-ppc64-cross diff --git a/tests/docker/dockerfiles/debian-arm64-test-cross.docker b/tests/docker/dockerfiles/debian-arm64-test-cross.docker new file mode 100644 index 0000000000..a44e76d942 --- /dev/null +++ b/tests/docker/dockerfiles/debian-arm64-test-cross.docker @@ -0,0 +1,13 @@ +# +# Docker arm64 cross-compiler target (tests only) +# +# This docker target builds on the debian Bullseye base image. +# +FROM qemu:debian11 + +# Add the foreign architecture we want and install dependencies +RUN dpkg --add-architecture arm64 +RUN apt update && \ + DEBIAN_FRONTEND=noninteractive eatmydata \ + apt install -y --no-install-recommends \ + crossbuild-essential-arm64 gcc-10-aarch64-linux-gnu diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh index eaaaff6233..2326f97856 100755 --- a/tests/tcg/configure.sh +++ b/tests/tcg/configure.sh @@ -97,8 +97,8 @@ for target in $target_list; do case $target in aarch64-*) # We don't have any bigendian build tools so we only use this for AArch64 - container_image=debian-arm64-cross - container_cross_cc=aarch64-linux-gnu-gcc + container_image=debian-arm64-test-cross + container_cross_cc=aarch64-linux-gnu-gcc-10 ;; alpha-*) container_image=debian-alpha-cross From 716386e397fabbbf9915d49f8bc79673fd2831bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 20 May 2020 15:05:38 +0100 Subject: [PATCH 0705/2595] cpus-common: ensure auto-assigned cpu_indexes don't clash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Basing the cpu_index on the number of currently allocated vCPUs fails when vCPUs aren't removed in a LIFO manner. This is especially true when we are allocating a cpu_index for each guest thread in linux-user where there is no ordering constraint on their allocation and de-allocation. [I've dropped the assert which is there to guard against out-of-order removal as this should probably be caught higher up the stack. Maybe we could just ifdef CONFIG_SOFTTMU it?] Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Acked-by: Igor Mammedow Cc: Nikolay Igotti Cc: Paolo Bonzini Cc: Eduardo Habkost Message-Id: <20200520140541.30256-13-alex.bennee@linaro.org> --- cpus-common.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cpus-common.c b/cpus-common.c index 55d5df8923..70a9d12981 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -61,13 +61,15 @@ static bool cpu_index_auto_assigned; static int cpu_get_free_index(void) { CPUState *some_cpu; - int cpu_index = 0; + int max_cpu_index = 0; cpu_index_auto_assigned = true; CPU_FOREACH(some_cpu) { - cpu_index++; + if (some_cpu->cpu_index >= max_cpu_index) { + max_cpu_index = some_cpu->cpu_index + 1; + } } - return cpu_index; + return max_cpu_index; } void cpu_list_add(CPUState *cpu) @@ -90,8 +92,6 @@ void cpu_list_remove(CPUState *cpu) return; } - assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus))); - QTAILQ_REMOVE_RCU(&cpus, cpu, node); cpu->cpu_index = UNASSIGNED_CPU_INDEX; } From 1f81ce90e31ef338ee53a0cea02344237bc470cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 20 May 2020 15:05:39 +0100 Subject: [PATCH 0706/2595] linux-user: properly "unrealize" vCPU object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We shouldn't be messing around with the CPU list in linux-user save for the very special case of do_fork(). When threads end we need to properly follow QOM object lifetime handling and allow the eventual cpu_common_unrealizefn to both remove the CPU and ensure any clean-up actions are taken place, for example calling plugin exit hooks. There is still a race condition to avoid so use the linux-user specific clone_lock instead of the cpu_list_lock to avoid it. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Cc: Nikolay Igotti Cc: Paolo Bonzini Cc: Daniel P. Berrange Cc: Eduardo Habkost Cc: Markus Armbruster Message-Id: <20200520140541.30256-14-alex.bennee@linaro.org> --- linux-user/syscall.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 05f03919ff..7f6700c54e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7635,30 +7635,33 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, return -TARGET_ERESTARTSYS; } - cpu_list_lock(); + pthread_mutex_lock(&clone_lock); if (CPU_NEXT(first_cpu)) { - TaskState *ts; + TaskState *ts = cpu->opaque; - /* Remove the CPU from the list. */ - QTAILQ_REMOVE_RCU(&cpus, cpu, node); + object_property_set_bool(OBJECT(cpu), false, "realized", NULL); + object_unref(OBJECT(cpu)); + /* + * At this point the CPU should be unrealized and removed + * from cpu lists. We can clean-up the rest of the thread + * data without the lock held. + */ - cpu_list_unlock(); + pthread_mutex_unlock(&clone_lock); - ts = cpu->opaque; if (ts->child_tidptr) { put_user_u32(0, ts->child_tidptr); do_sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX, NULL, NULL, 0); } thread_cpu = NULL; - object_unref(OBJECT(cpu)); g_free(ts); rcu_unregister_thread(); pthread_exit(NULL); } - cpu_list_unlock(); + pthread_mutex_unlock(&clone_lock); preexit_cleanup(cpu_env, arg1); _exit(arg1); return 0; /* avoid warning */ From 919bfbf5d6569b63a374332292cf3d2355a6d6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 20 May 2020 15:05:40 +0100 Subject: [PATCH 0707/2595] tests/tcg: add new threadcount test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on the original testcase by Nikolay Igotti. Message-ID: Signed-off-by: Nikolay Igotti Signed-off-by: Alex Bennée Message-Id: <20200520140541.30256-15-alex.bennee@linaro.org> --- tests/tcg/multiarch/Makefile.target | 2 + tests/tcg/multiarch/threadcount.c | 64 +++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 tests/tcg/multiarch/threadcount.c diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index 51fb75ecfd..cb49cc9ccb 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -28,6 +28,8 @@ run-float_%: float_% testthread: LDFLAGS+=-lpthread +threadcount: LDFLAGS+=-lpthread + # We define the runner for test-mmap after the individual # architectures have defined their supported pages sizes. If no # additional page sizes are defined we only run the default test. diff --git a/tests/tcg/multiarch/threadcount.c b/tests/tcg/multiarch/threadcount.c new file mode 100644 index 0000000000..545a1c8146 --- /dev/null +++ b/tests/tcg/multiarch/threadcount.c @@ -0,0 +1,64 @@ +/* + * Thread Exerciser + * + * Unlike testthread which is mainly concerned about testing thread + * semantics this test is used to exercise the thread creation and + * accounting. A version of this test found a problem with clashing + * cpu_indexes which caused a break in plugin handling. + * + * Based on the original test case by Nikolay Igotti. + * + * Copyright (c) 2020 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include +#include +#include + +int max_threads = 10; + +typedef struct { + int delay; +} ThreadArg; + +static void *thread_fn(void* varg) +{ + ThreadArg *arg = varg; + usleep(arg->delay); + free(arg); + return NULL; +} + +int main(int argc, char **argv) +{ + int i; + pthread_t *threads; + + if (argc > 1) { + max_threads = atoi(argv[1]); + } + threads = calloc(sizeof(pthread_t), max_threads); + + for (i = 0; i < max_threads; i++) { + ThreadArg *arg = calloc(sizeof(ThreadArg), 1); + arg->delay = i * 100; + pthread_create(threads + i, NULL, thread_fn, arg); + } + + printf("Created %d threads\n", max_threads); + + /* sleep until roughly half the threads have "finished" */ + usleep(max_threads * 50); + + for (i = 0; i < max_threads; i++) { + pthread_join(threads[i], NULL); + } + + printf("Done\n"); + + return 0; +} From 6eb9dbf6a744f07b437e07e5f590625ebb7ab4cc Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sat, 2 May 2020 21:46:42 +0200 Subject: [PATCH 0708/2595] linux-user, alpha: fix oldumount syscall When we try to bootstrap debian/lenny for alpha, it fails because it cannot umount /.root directory: ... Setting up initscripts (2.86.ds1-61) ... umount: /.root: Function not implemented dpkg: error processing initscripts (--configure): subprocess post-installation script returned error exit status 1 dpkg: sysvinit: dependency problems, but configuring anyway as you request: sysvinit depends on initscripts; however: Package initscripts is not configured yet. This is because, when we switched from syscall_nr.h to syscall.tbl, the syscall #321 has been renamed from umount to oldumount and syscall.c has not been updated to manage the new name. oldumount has been introduced in linux 2.1.116pre1 by: 7d32756b2 ("Import 2.1.116pre1") ... * We now support a flag for forced unmount like the other 'big iron' * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD ... Fixes: 6116aea994 ("linux-user, alpha: add syscall table generation support") Signed-off-by: Laurent Vivier Message-Id: <20200502194642.32823-1-laurent@vivier.eu> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 05f03919ff..e89b815ce9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8028,8 +8028,13 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, } } return ret; -#ifdef TARGET_NR_umount +#if defined(TARGET_NR_umount) || defined(TARGET_NR_oldumount) +#if defined(TARGET_NR_umount) case TARGET_NR_umount: +#endif +#if defined(TARGET_NR_oldumount) + case TARGET_NR_oldumount: +#endif if (!(p = lock_user_string(arg1))) return -TARGET_EFAULT; ret = get_errno(umount(p)); From 538fabcb46b956b65247b4e8cf701b63a58b70cc Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 25 Apr 2020 00:00:33 +0200 Subject: [PATCH 0709/2595] linux-user: return target error codes for socket() and prctl() Return target error codes instead of host error codes. Signed-off-by: Helge Deller Reviewed-by: Laurent Vivier Message-Id: <20200424220033.GA28140@ls3530.fritz.box> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e89b815ce9..fd5c4f1d73 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2987,7 +2987,7 @@ static abi_long do_socket(int domain, int type, int protocol) #endif protocol == NETLINK_KOBJECT_UEVENT || protocol == NETLINK_AUDIT)) { - return -EPFNOSUPPORT; + return -TARGET_EPFNOSUPPORT; } if (domain == AF_PACKET || @@ -5856,7 +5856,7 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) { - return -ENOSYS; + return -TARGET_ENOSYS; } #else abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) From 5932a46c8a419db4a6402ac8ae42953b4d4fef1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 10 May 2020 22:34:57 +0200 Subject: [PATCH 0710/2595] hw/registerfields: Prefix local variables with underscore in macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One can name a local variable holding a value as 'v', but it currently clashes with the registerfields macros. To save others to debug the same mistake, prefix the macro's local variables with an underscore. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200510203457.10546-1-f4bug@amsat.org Message-Id: <20200510203457.10546-1-f4bug@amsat.org> Signed-off-by: Alistair Francis --- include/hw/registerfields.h | 40 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/include/hw/registerfields.h b/include/hw/registerfields.h index 0407edb7ec..93fa4a84c2 100644 --- a/include/hw/registerfields.h +++ b/include/hw/registerfields.h @@ -66,35 +66,35 @@ #define FIELD_DP8(storage, reg, field, val) ({ \ struct { \ unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \ - } v = { .v = val }; \ - uint8_t d; \ - d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ - R_ ## reg ## _ ## field ## _LENGTH, v.v); \ - d; }) + } _v = { .v = val }; \ + uint8_t _d; \ + _d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ + R_ ## reg ## _ ## field ## _LENGTH, _v.v); \ + _d; }) #define FIELD_DP16(storage, reg, field, val) ({ \ struct { \ unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \ - } v = { .v = val }; \ - uint16_t d; \ - d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ - R_ ## reg ## _ ## field ## _LENGTH, v.v); \ - d; }) + } _v = { .v = val }; \ + uint16_t _d; \ + _d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ + R_ ## reg ## _ ## field ## _LENGTH, _v.v); \ + _d; }) #define FIELD_DP32(storage, reg, field, val) ({ \ struct { \ unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \ - } v = { .v = val }; \ - uint32_t d; \ - d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ - R_ ## reg ## _ ## field ## _LENGTH, v.v); \ - d; }) + } _v = { .v = val }; \ + uint32_t _d; \ + _d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ + R_ ## reg ## _ ## field ## _LENGTH, _v.v); \ + _d; }) #define FIELD_DP64(storage, reg, field, val) ({ \ struct { \ unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \ - } v = { .v = val }; \ - uint64_t d; \ - d = deposit64((storage), R_ ## reg ## _ ## field ## _SHIFT, \ - R_ ## reg ## _ ## field ## _LENGTH, v.v); \ - d; }) + } _v = { .v = val }; \ + uint64_t _d; \ + _d = deposit64((storage), R_ ## reg ## _ ## field ## _SHIFT, \ + R_ ## reg ## _ ## field ## _LENGTH, _v.v); \ + _d; }) /* Deposit a field to array of registers. */ #define ARRAY_FIELD_DP32(regs, reg, field, val) \ From a932eec49d9ec106c7952314ad1adc28f0986076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 21 May 2020 14:57:48 +0100 Subject: [PATCH 0711/2595] linux-user: limit check to HOST_LONG_BITS < TARGET_ABI_BITS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Newer clangs rightly spot that you can never exceed the full address space of 64 bit hosts with: linux-user/elfload.c:2076:41: error: result of comparison 'unsigned long' > 18446744073709551615 is always false [-Werror,-Wtautological-type-limit-compare] 4685 if ((guest_hiaddr - guest_base) > ~(uintptr_t)0) { 4686 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~ 4687 1 error generated. So lets limit the check to 32 bit hosts only. Fixes: ee94743034bf Reported-by: Thomas Huth Signed-off-by: Alex Bennée Message-Id: <20200525131823.715-8-thuth@redhat.com> [thuth: Use HOST_LONG_BITS < TARGET_ABI_BITS instead of HOST_LONG_BITS == 32] Signed-off-by: Thomas Huth --- linux-user/elfload.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 01a9323a63..ebc663ea0b 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2073,12 +2073,14 @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr, exit(EXIT_FAILURE); } } else { +#if HOST_LONG_BITS < TARGET_ABI_BITS if ((guest_hiaddr - guest_base) > ~(uintptr_t)0) { error_report("%s: requires more virtual address space " "than the host can provide (0x%" PRIx64 ")", image_name, (uint64_t)guest_hiaddr - guest_base); exit(EXIT_FAILURE); } +#endif } /* From d1d3ba2b23c06aab2f7e0511f08f450a3b96ca61 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 10 Feb 2020 16:41:04 +0100 Subject: [PATCH 0712/2595] MAINTAINERS: Add Philippe, Alex and Wainer to the Gitlab-CI section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initially, I was the only one who was using Gitlab while most developers had their git trees still on other systems, but that has changed nowadays. There is now much more interest in the Gitlab-CI today, so it would be good to have more than only one maintainer / reviewer for the gitlab-ci.yml file. Alex, Wainer and Philippe kindly offered their help here, so let's add them to the corresponding section in the MAINTAINERS file now. Message-Id: <20200210155115.9371-1-thuth@redhat.com> Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daude Reviewed-by: Wainer dos Santos Moschetta Signed-off-by: Thomas Huth --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a209b5d8ce..71a0438843 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2901,6 +2901,9 @@ W: https://cirrus-ci.com/github/qemu/qemu GitLab Continuous Integration M: Thomas Huth +M: Philippe Mathieu-Daudé +M: Alex Bennée +R: Wainer dos Santos Moschetta S: Maintained F: .gitlab-ci.yml From f3ea07c70debad6b8f6c084ad0e0c9ff27b3e73c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 15 May 2020 18:30:27 +0200 Subject: [PATCH 0713/2595] gitlab-ci: Remove flex/bison packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU does not use flex/bison packages. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200515163029.12917-4-philmd@redhat.com> Message-Id: <20200525131823.715-3-thuth@redhat.com> Reviewed-by: Alex Bennée Signed-off-by: Thomas Huth --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b889fb96b6..994774250f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,7 +4,7 @@ include: before_script: - apt-get update -qq - - apt-get install -y -qq flex bison libglib2.0-dev libpixman-1-dev genisoimage + - apt-get install -y -qq libglib2.0-dev libpixman-1-dev genisoimage build-system1: script: From 65ea4e65df15682f058b3ef61c8d8fc278ddc0d3 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Thu, 12 Mar 2020 15:36:14 -0400 Subject: [PATCH 0714/2595] GitLab CI: avoid calling before_scripts on unintended jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At this point it seems that all jobs depend on those steps, with maybe the EDK2 jobs as exceptions. The jobs that will be added later will not want those scripts to be run, so let's move these steps to the appropriate jobs, while still trying to avoid repetition. Signed-off-by: Cleber Rosa Message-Id: <20200525131823.715-4-thuth@redhat.com> Reviewed-by: Alex Bennée [thuth: Rebased to current master branch, use separate template] Signed-off-by: Thomas Huth --- .gitlab-ci.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 994774250f..bc6aee6aba 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,11 +2,13 @@ include: - local: '/.gitlab-ci-edk2.yml' - local: '/.gitlab-ci-opensbi.yml' -before_script: - - apt-get update -qq - - apt-get install -y -qq libglib2.0-dev libpixman-1-dev genisoimage +.update_apt_template: &before_script_apt + before_script: + - apt-get update -qq + - apt-get install -y -qq libglib2.0-dev libpixman-1-dev genisoimage build-system1: + <<: *before_script_apt script: - apt-get install -y -qq libgtk-3-dev libvte-dev nettle-dev libcacard-dev libusb-dev libvde-dev libspice-protocol-dev libgl1-mesa-dev libvdeplug-dev @@ -19,6 +21,7 @@ build-system1: - make -j2 check build-system2: + <<: *before_script_apt script: - apt-get install -y -qq libsdl2-dev libgcrypt-dev libbrlapi-dev libaio-dev libfdt-dev liblzo2-dev librdmacm-dev libibverbs-dev libibumad-dev @@ -32,6 +35,7 @@ build-system2: - make -j2 check build-disabled: + <<: *before_script_apt script: - mkdir build - cd build @@ -46,6 +50,7 @@ build-disabled: - make -j2 check-qtest SPEED=slow build-tcg-disabled: + <<: *before_script_apt script: - apt-get install -y -qq clang libgtk-3-dev libusb-dev - mkdir build @@ -64,6 +69,7 @@ build-tcg-disabled: 260 261 262 263 264 270 272 273 277 279 build-user: + <<: *before_script_apt script: - mkdir build - cd build @@ -73,6 +79,7 @@ build-user: - make run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user build-clang: + <<: *before_script_apt script: - apt-get install -y -qq clang libsdl2-dev libattr1-dev libcap-ng-dev xfslibs-dev libiscsi-dev libnfs-dev libseccomp-dev gnutls-dev librbd-dev @@ -85,6 +92,7 @@ build-clang: - make -j2 check build-tci: + <<: *before_script_apt script: - TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64" - mkdir build From 922febe2af0a636636d3b0fd4309f26072cfd2cc Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 20 May 2020 09:45:58 +0200 Subject: [PATCH 0715/2595] gitlab-ci: Move edk2 and opensbi YAML files to .gitlab-ci.d folder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have a dedicated folder for the gitlab-ci - so there is no need to clutter the top directory with these .yml files. Message-Id: <20200525131823.715-5-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Signed-off-by: Thomas Huth --- .gitlab-ci-edk2.yml => .gitlab-ci.d/edk2.yml | 0 .gitlab-ci-opensbi.yml => .gitlab-ci.d/opensbi.yml | 0 .gitlab-ci.yml | 4 ++-- MAINTAINERS | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename .gitlab-ci-edk2.yml => .gitlab-ci.d/edk2.yml (100%) rename .gitlab-ci-opensbi.yml => .gitlab-ci.d/opensbi.yml (100%) diff --git a/.gitlab-ci-edk2.yml b/.gitlab-ci.d/edk2.yml similarity index 100% rename from .gitlab-ci-edk2.yml rename to .gitlab-ci.d/edk2.yml diff --git a/.gitlab-ci-opensbi.yml b/.gitlab-ci.d/opensbi.yml similarity index 100% rename from .gitlab-ci-opensbi.yml rename to .gitlab-ci.d/opensbi.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bc6aee6aba..5208d93ff8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,6 @@ include: - - local: '/.gitlab-ci-edk2.yml' - - local: '/.gitlab-ci-opensbi.yml' + - local: '/.gitlab-ci.d/edk2.yml' + - local: '/.gitlab-ci.d/opensbi.yml' .update_apt_template: &before_script_apt before_script: diff --git a/MAINTAINERS b/MAINTAINERS index 71a0438843..0944d9c731 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2542,7 +2542,7 @@ F: roms/edk2 F: roms/edk2-* F: tests/data/uefi-boot-images/ F: tests/uefi-test-tools/ -F: .gitlab-ci-edk2.yml +F: .gitlab-ci.d/edk2.yml F: .gitlab-ci.d/edk2/ Usermode Emulation From b5d621ff4a7d86e82a58104d5706bda2b4238626 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 20 May 2020 10:38:37 +0200 Subject: [PATCH 0716/2595] gitlab-ci: Do not use the standard container images from gitlab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently all pipelines of the gitlab CI are failing, except for the "build-user" pipeline. There is an issue with the default container image (likely Debian stable) where they imported something bad in one of the system headers: /usr/include/linux/swab.h: In function '__swab': /builds/huth/qemu/include/qemu/bitops.h:20:34: error: "sizeof" is not defined, evaluates to 0 [-Werror=undef] #define BITS_PER_LONG (sizeof (unsigned long) * BITS_PER_BYTE) We could maybe work-around this issue or wait for the default containers to get fixed, but considering that we use Ubuntu (and thus Debian-style) CI in Travis already to a very large extent, we should consider to use some RPM-based distros in our gitlab CI instead. Thus let's change the failing pipelines to use Fedora and CentOS (and also one Ubuntu 19.10, since 20.04 is broken, too) now. Message-Id: <20200525131823.715-6-thuth@redhat.com> Acked-by: Alex Bennée Signed-off-by: Thomas Huth --- .gitlab-ci.yml | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5208d93ff8..559ec2ab4d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,9 +5,17 @@ include: .update_apt_template: &before_script_apt before_script: - apt-get update -qq - - apt-get install -y -qq libglib2.0-dev libpixman-1-dev genisoimage + - apt-get install -y -qq git gcc libglib2.0-dev libpixman-1-dev make + genisoimage + +.update_dnf_template: &before_script_dnf + before_script: + - dnf update -y + - dnf install -y bzip2 diffutils gcc git genisoimage findutils glib2-devel + make python3 perl-podlators perl-Test-Harness pixman-devel zlib-devel build-system1: + image: ubuntu:19.10 <<: *before_script_apt script: - apt-get install -y -qq libgtk-3-dev libvte-dev nettle-dev libcacard-dev @@ -21,11 +29,12 @@ build-system1: - make -j2 check build-system2: - <<: *before_script_apt + image: fedora:latest + <<: *before_script_dnf script: - - apt-get install -y -qq libsdl2-dev libgcrypt-dev libbrlapi-dev libaio-dev - libfdt-dev liblzo2-dev librdmacm-dev libibverbs-dev libibumad-dev - libzstd-dev + - yum install -y SDL2-devel libgcrypt-devel brlapi-devel libaio-devel + libfdt-devel lzo-devel librdmacm-devel libibverbs-devel libibumad-devel + libzstd-devel - mkdir build - cd build - ../configure --enable-werror --target-list="tricore-softmmu unicore32-softmmu @@ -35,7 +44,8 @@ build-system2: - make -j2 check build-disabled: - <<: *before_script_apt + image: fedora:latest + <<: *before_script_dnf script: - mkdir build - cd build @@ -50,9 +60,10 @@ build-disabled: - make -j2 check-qtest SPEED=slow build-tcg-disabled: - <<: *before_script_apt + image: centos:8 + <<: *before_script_dnf script: - - apt-get install -y -qq clang libgtk-3-dev libusb-dev + - dnf install -y clang gtk3-devel libusbx-devel libgcrypt-devel - mkdir build - cd build - ../configure --cc=clang --enable-werror --disable-tcg --audio-drv-list="" @@ -79,10 +90,11 @@ build-user: - make run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user build-clang: - <<: *before_script_apt + image: fedora:latest + <<: *before_script_dnf script: - - apt-get install -y -qq clang libsdl2-dev libattr1-dev libcap-ng-dev - xfslibs-dev libiscsi-dev libnfs-dev libseccomp-dev gnutls-dev librbd-dev + - yum install -y clang SDL2-devel libattr-devel libcap-ng-devel xfsprogs-devel + libiscsi-devel libnfs-devel libseccomp-devel gnutls-devel librbd-devel - mkdir build - cd build - ../configure --cc=clang --cxx=clang++ --enable-werror @@ -92,7 +104,8 @@ build-clang: - make -j2 check build-tci: - <<: *before_script_apt + image: centos:8 + <<: *before_script_dnf script: - TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64" - mkdir build From 0016afa250d251a1b3fbc90c6d618e7f00e02f14 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 21 May 2020 06:50:10 +0200 Subject: [PATCH 0717/2595] gitlab-ci: Determine the number of jobs dynamically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some people might want to run the gitlab CI pipelines in an environment where multiple CPUs are available to the runners, so let's rather get the number for "-j" from the "nproc" program (increased by 1 to compensate for jobs that wait for I/O) instead of hard-coding it. Message-Id: <20200525131823.715-7-thuth@redhat.com> Reviewed-by: Alex Bennée Signed-off-by: Thomas Huth --- .gitlab-ci.yml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 559ec2ab4d..349c77aa58 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,12 +7,14 @@ include: - apt-get update -qq - apt-get install -y -qq git gcc libglib2.0-dev libpixman-1-dev make genisoimage + - JOBS=$(expr $(nproc) + 1) .update_dnf_template: &before_script_dnf before_script: - dnf update -y - dnf install -y bzip2 diffutils gcc git genisoimage findutils glib2-devel make python3 perl-podlators perl-Test-Harness pixman-devel zlib-devel + - JOBS=$(expr $(nproc) + 1) build-system1: image: ubuntu:19.10 @@ -25,8 +27,8 @@ build-system1: - ../configure --enable-werror --target-list="aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu lm32-softmmu moxie-softmmu microblazeel-softmmu mips64el-softmmu m68k-softmmu ppc-softmmu riscv64-softmmu sparc-softmmu" - - make -j2 - - make -j2 check + - make -j"$JOBS" + - make -j"$JOBS" check build-system2: image: fedora:latest @@ -40,8 +42,8 @@ build-system2: - ../configure --enable-werror --target-list="tricore-softmmu unicore32-softmmu microblaze-softmmu mips-softmmu riscv32-softmmu s390x-softmmu sh4-softmmu sparc64-softmmu x86_64-softmmu xtensa-softmmu nios2-softmmu or1k-softmmu" - - make -j2 - - make -j2 check + - make -j"$JOBS" + - make -j"$JOBS" check build-disabled: image: fedora:latest @@ -56,8 +58,8 @@ build-disabled: --disable-qom-cast-debug --disable-spice --disable-vhost-vsock --disable-vhost-net --disable-vhost-crypto --disable-vhost-user --target-list="i386-softmmu ppc64-softmmu mips64-softmmu i386-linux-user" - - make -j2 - - make -j2 check-qtest SPEED=slow + - make -j"$JOBS" + - make -j"$JOBS" check-qtest SPEED=slow build-tcg-disabled: image: centos:8 @@ -67,7 +69,7 @@ build-tcg-disabled: - mkdir build - cd build - ../configure --cc=clang --enable-werror --disable-tcg --audio-drv-list="" - - make -j2 + - make -j"$JOBS" - make check-unit - make check-qapi-schema - cd tests/qemu-iotests/ @@ -86,7 +88,7 @@ build-user: - cd build - ../configure --enable-werror --disable-system --disable-guest-agent --disable-capstone --disable-slirp --disable-fdt - - make -j2 + - make -j"$JOBS" - make run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user build-clang: @@ -100,8 +102,8 @@ build-clang: - ../configure --cc=clang --cxx=clang++ --enable-werror --target-list="alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu ppc-softmmu s390x-softmmu x86_64-softmmu arm-linux-user" - - make -j2 - - make -j2 check + - make -j"$JOBS" + - make -j"$JOBS" check build-tci: image: centos:8 @@ -112,7 +114,7 @@ build-tci: - cd build - ../configure --enable-tcg-interpreter --target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)" - - make -j2 + - make -j"$JOBS" - make run-tcg-tests-x86_64-softmmu - make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test - for tg in $TARGETS ; do From edcbea008d7943633911c2d385fd0c94bb84403c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:39 +0200 Subject: [PATCH 0718/2595] hw/display/edid: Add missing 'qdev-properties.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When trying to consume the DEFINE_EDID_PROPERTIES() macro by including "hw/display/edid.h", we get this build failure: include/hw/display/edid.h:24:5: error: implicit declaration of function ‘DEFINE_PROP_UINT32’ [-Werror=implicit-function-declaration] 24 | DEFINE_PROP_UINT32("xres", _state, _edid_info.prefx, 0), \ | ^~~~~~~~~~~~~~~~~~ Headers should be self-contained, and one shouldn't have to dig to find the missing headers. In this case "hw/qdev-properties.h" is missing. Add it. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-2-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- include/hw/display/edid.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/hw/display/edid.h b/include/hw/display/edid.h index ff99dc0a05..23371ee82c 100644 --- a/include/hw/display/edid.h +++ b/include/hw/display/edid.h @@ -2,6 +2,7 @@ #define EDID_H #include "qom/object.h" +#include "hw/qdev-properties.h" typedef struct qemu_edid_info { const char *vendor; /* http://www.uefi.org/pnp_id_list */ From 85664cf0a4bf91764fb55154feed5797be32a30a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:40 +0200 Subject: [PATCH 0719/2595] hw/display/cg3: Convert debug printf()s to trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert DPRINTF() to trace events and remove ifdef'ry. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-3-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/cg3.c | 14 ++++---------- hw/display/trace-events | 4 ++++ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/hw/display/cg3.c b/hw/display/cg3.c index f7f1c199ce..7cbe6e56ff 100644 --- a/hw/display/cg3.c +++ b/hw/display/cg3.c @@ -35,6 +35,7 @@ #include "hw/qdev-properties.h" #include "qemu/log.h" #include "qemu/module.h" +#include "trace.h" /* Change to 1 to enable debugging */ #define DEBUG_CG3 0 @@ -63,12 +64,6 @@ #define CG3_VRAM_SIZE 0x100000 #define CG3_VRAM_OFFSET 0x800000 -#define DPRINTF(fmt, ...) do { \ - if (DEBUG_CG3) { \ - printf("CG3: " fmt , ## __VA_ARGS__); \ - } \ -} while (0) - #define TYPE_CG3 "cgthree" #define CG3(obj) OBJECT_CHECK(CG3State, (obj), TYPE_CG3) @@ -195,7 +190,8 @@ static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size) val = 0; break; } - DPRINTF("read %02x from reg %" HWADDR_PRIx "\n", val, addr); + trace_cg3_read(addr, val, size); + return val; } @@ -206,9 +202,7 @@ static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val, uint8_t regval; int i; - DPRINTF("write %" PRIx64 " to reg %" HWADDR_PRIx " size %d\n", - val, addr, size); - + trace_cg3_write(addr, val, size); switch (addr) { case CG3_REG_BT458_ADDR: s->dac_index = val; diff --git a/hw/display/trace-events b/hw/display/trace-events index e6e22bef88..47b2b168ae 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -151,3 +151,7 @@ artist_vram_write(unsigned int size, uint64_t addr, uint64_t val) "%u 0x%"PRIx64 artist_fill_window(unsigned int start_x, unsigned int start_y, unsigned int width, unsigned int height, uint32_t op, uint32_t ctlpln) "start=%ux%u length=%ux%u op=0x%08x ctlpln=0x%08x" artist_block_move(unsigned int start_x, unsigned int start_y, unsigned int dest_x, unsigned int dest_y, unsigned int width, unsigned int height) "source %ux%u -> dest %ux%u size %ux%u" artist_draw_line(unsigned int start_x, unsigned int start_y, unsigned int end_x, unsigned int end_y) "%ux%u %ux%u" + +# cg3.c +cg3_read(uint32_t addr, uint32_t val, unsigned size) "read addr:0x%06"PRIx32" val:0x%08"PRIx32" size:%u" +cg3_write(uint32_t addr, uint32_t val, unsigned size) "write addr:0x%06"PRIx32" val:0x%08"PRIx32" size:%u" From bee61ca2b9a9e6f9445bf37f6474f704c5fd07cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:41 +0200 Subject: [PATCH 0720/2595] hw/display/cirrus_vga: Convert debug printf() to trace event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-4-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/cirrus_vga.c | 4 +--- hw/display/trace-events | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 1f29731ffe..33ccdde000 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -1512,9 +1512,7 @@ static int cirrus_vga_read_gr(CirrusVGAState * s, unsigned reg_index) static void cirrus_vga_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) { -#if defined(DEBUG_BITBLT) && 0 - printf("gr%02x: %02x\n", reg_index, reg_value); -#endif + trace_vga_cirrus_write_gr(reg_index, reg_value); switch (reg_index) { case 0x00: // Standard VGA, BGCOLOR 0x000000ff s->vga.gr[reg_index] = reg_value & gr_mask[reg_index]; diff --git a/hw/display/trace-events b/hw/display/trace-events index 47b2b168ae..c3043e4ced 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -133,6 +133,7 @@ vga_vbe_write(uint32_t index, uint32_t val) "index 0x%x, val 0x%x" vga_cirrus_read_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x" vga_cirrus_write_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x" vga_cirrus_write_blt(uint32_t offset, uint32_t val) "offset 0x%x, val 0x%x" +vga_cirrus_write_gr(uint8_t index, uint8_t val) "GR addr 0x%02x, val 0x%02x" # sii9022.c sii9022_read_reg(uint8_t addr, uint8_t val) "addr 0x%02x, val 0x%02x" From bb6e9e940769d18ca1de24a729fddba611bbd751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:42 +0200 Subject: [PATCH 0721/2595] hw/display/cirrus_vga: Use qemu_log_mask(UNIMP) instead of debug printf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace some debug printf() calls by qemu_log_mask(LOG_UNIMP), and add a new one in cirrus_linear_bitblt_read(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-5-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/cirrus_vga.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 33ccdde000..f9f837b850 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -35,6 +35,7 @@ #include "qemu/osdep.h" #include "qemu/module.h" #include "qemu/units.h" +#include "qemu/log.h" #include "sysemu/reset.h" #include "qapi/error.h" #include "trace.h" @@ -905,9 +906,8 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s) static int cirrus_bitblt_videotocpu(CirrusVGAState * s) { /* XXX */ -#ifdef DEBUG_BITBLT - printf("cirrus: bitblt (video to cpu) is not implemented yet\n"); -#endif + qemu_log_mask(LOG_UNIMP, + "cirrus: bitblt (video to cpu) is not implemented\n"); return 0; } @@ -989,9 +989,8 @@ static void cirrus_bitblt_start(CirrusVGAState * s) cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) { -#ifdef DEBUG_BITBLT - printf("cirrus: bitblt - memory-to-memory copy is requested\n"); -#endif + qemu_log_mask(LOG_UNIMP, + "cirrus: bitblt - memory-to-memory copy requested\n"); goto bitblt_ignore; } @@ -2412,6 +2411,9 @@ static uint64_t cirrus_linear_bitblt_read(void *opaque, /* XXX handle bitblt */ (void)s; + qemu_log_mask(LOG_UNIMP, + "cirrus: linear bitblt is not implemented\n"); + return 0xff; } From 2b55f4d3504a9f347380599358a9a171ecbb6869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:43 +0200 Subject: [PATCH 0722/2595] hw/display/cirrus_vga: Use qemu_log_mask(ERROR) instead of debug printf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace some debug printf() calls by qemu_log_mask(LOG_GUEST_ERROR). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-6-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/cirrus_vga.c | 77 ++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 44 deletions(-) diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index f9f837b850..76e2dc5bb6 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -978,9 +978,8 @@ static void cirrus_bitblt_start(CirrusVGAState * s) s->cirrus_blt_pixelwidth = 4; break; default: -#ifdef DEBUG_BITBLT - printf("cirrus: bitblt - pixel width is unknown\n"); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: bitblt - pixel width is unknown\n"); goto bitblt_ignore; } s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK; @@ -1037,7 +1036,9 @@ static void cirrus_bitblt_start(CirrusVGAState * s) } else { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { if (s->cirrus_blt_pixelwidth > 2) { - printf("src transparent without colorexpand must be 8bpp or 16bpp\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: src transparent without colorexpand " + "must be 8bpp or 16bpp\n"); goto bitblt_ignore; } if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { @@ -1135,10 +1136,9 @@ static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s) ret = 16; break; /* XGA HiColor */ default: -#ifdef DEBUG_CIRRUS - printf("cirrus: invalid DAC value %x in 16bpp\n", - (s->cirrus_hidden_dac_data & 0xf)); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: invalid DAC value 0x%x in 16bpp\n", + (s->cirrus_hidden_dac_data & 0xf)); ret = 15; /* XXX */ break; } @@ -1307,11 +1307,9 @@ static int cirrus_vga_read_sr(CirrusVGAState * s) #endif return s->vga.sr[s->vga.sr_index]; default: -#ifdef DEBUG_CIRRUS - printf("cirrus: inport sr_index %02x\n", s->vga.sr_index); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: inport sr_index 0x%02x\n", s->vga.sr_index); return 0xff; - break; } } @@ -1400,10 +1398,9 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val) cirrus_update_memory_access(s); break; default: -#ifdef DEBUG_CIRRUS - printf("cirrus: outport sr_index %02x, sr_value %02x\n", - s->vga.sr_index, val); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: outport sr_index 0x%02x, sr_value 0x%02x\n", + s->vga.sr_index, val); break; } } @@ -1501,9 +1498,8 @@ static int cirrus_vga_read_gr(CirrusVGAState * s, unsigned reg_index) if (reg_index < 0x3a) { return s->vga.gr[reg_index]; } else { -#ifdef DEBUG_CIRRUS - printf("cirrus: inport gr_index %02x\n", reg_index); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: inport gr_index 0x%02x\n", reg_index); return 0xff; } } @@ -1590,10 +1586,9 @@ cirrus_vga_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) cirrus_write_bitblt(s, reg_value); break; default: -#ifdef DEBUG_CIRRUS - printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index, - reg_value); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: outport gr_index 0x%02x, gr_value 0x%02x\n", + reg_index, reg_value); break; } } @@ -1648,9 +1643,8 @@ static int cirrus_vga_read_cr(CirrusVGAState * s, unsigned reg_index) return s->vga.ar_index & 0x3f; break; default: -#ifdef DEBUG_CIRRUS - printf("cirrus: inport cr_index %02x\n", reg_index); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: inport cr_index 0x%02x\n", reg_index); return 0xff; } } @@ -1721,10 +1715,9 @@ static void cirrus_vga_write_cr(CirrusVGAState * s, int reg_value) break; case 0x25: // Part Status default: -#ifdef DEBUG_CIRRUS - printf("cirrus: outport cr_index %02x, cr_value %02x\n", - s->vga.cr_index, reg_value); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: outport cr_index 0x%02x, cr_value 0x%02x\n", + s->vga.cr_index, reg_value); break; } } @@ -1834,9 +1827,8 @@ static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address) value = cirrus_vga_read_gr(s, 0x31); break; default: -#ifdef DEBUG_CIRRUS - printf("cirrus: mmio read - address 0x%04x\n", address); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: mmio read - address 0x%04x\n", address); break; } @@ -1946,10 +1938,9 @@ static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address, cirrus_vga_write_gr(s, 0x31, value); break; default: -#ifdef DEBUG_CIRRUS - printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n", - address, value); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n", + address, value); break; } } @@ -2047,9 +2038,8 @@ static uint64_t cirrus_vga_mem_read(void *opaque, } } else { val = 0xff; -#ifdef DEBUG_CIRRUS - printf("cirrus: mem_readb " TARGET_FMT_plx "\n", addr); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: mem_readb 0x" TARGET_FMT_plx "\n", addr); } return val; } @@ -2112,10 +2102,9 @@ static void cirrus_vga_mem_write(void *opaque, cirrus_mmio_blt_write(s, addr & 0xff, mem_value); } } else { -#ifdef DEBUG_CIRRUS - printf("cirrus: mem_writeb " TARGET_FMT_plx " value 0x%02" PRIu64 "\n", addr, - mem_value); -#endif + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: mem_writeb 0x" TARGET_FMT_plx " " + "value 0x%02" PRIu64 "\n", addr, mem_value); } } From 615277217490317193882101b5270d9147a6d465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:44 +0200 Subject: [PATCH 0723/2595] hw/display/cirrus_vga: Convert debug printf() to trace event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the final bit of DEBUG_BITBLT to a tracepoint. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-7-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/cirrus_vga.c | 24 ++++++++++-------------- hw/display/trace-events | 1 + 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 76e2dc5bb6..92c197cdde 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -53,7 +53,6 @@ */ //#define DEBUG_CIRRUS -//#define DEBUG_BITBLT /*************************************** * @@ -950,19 +949,16 @@ static void cirrus_bitblt_start(CirrusVGAState * s) s->cirrus_blt_dstaddr &= s->cirrus_addr_mask; s->cirrus_blt_srcaddr &= s->cirrus_addr_mask; -#ifdef DEBUG_BITBLT - printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n", - blt_rop, - s->cirrus_blt_mode, - s->cirrus_blt_modeext, - s->cirrus_blt_width, - s->cirrus_blt_height, - s->cirrus_blt_dstpitch, - s->cirrus_blt_srcpitch, - s->cirrus_blt_dstaddr, - s->cirrus_blt_srcaddr, - s->vga.gr[0x2f]); -#endif + trace_vga_cirrus_bitblt_start(blt_rop, + s->cirrus_blt_mode, + s->cirrus_blt_modeext, + s->cirrus_blt_width, + s->cirrus_blt_height, + s->cirrus_blt_dstpitch, + s->cirrus_blt_srcpitch, + s->cirrus_blt_dstaddr, + s->cirrus_blt_srcaddr, + s->vga.gr[0x2f]); switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { case CIRRUS_BLTMODE_PIXELWIDTH8: diff --git a/hw/display/trace-events b/hw/display/trace-events index c3043e4ced..bb089a5f5e 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -134,6 +134,7 @@ vga_cirrus_read_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x" vga_cirrus_write_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x" vga_cirrus_write_blt(uint32_t offset, uint32_t val) "offset 0x%x, val 0x%x" vga_cirrus_write_gr(uint8_t index, uint8_t val) "GR addr 0x%02x, val 0x%02x" +vga_cirrus_bitblt_start(uint8_t blt_rop, uint8_t blt_mode, uint8_t blt_modeext, int blt_width, int blt_height, int blt_dstpitch, int blt_srcpitch, uint32_t blt_dstaddr, uint32_t blt_srcaddr, uint8_t gr_val) "rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08"PRIx32" saddr=0x%08"PRIx32" writemask=0x%02x" # sii9022.c sii9022_read_reg(uint8_t addr, uint8_t val) "addr 0x%02x, val 0x%02x" From 91e7fd3ae5a6fcd270f8d38fd5771033a806abce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:45 +0200 Subject: [PATCH 0724/2595] hw/display/dpcd: Fix memory region size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The memory region size is 512K. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-8-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/dpcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/display/dpcd.c b/hw/display/dpcd.c index 170545c605..0c1b7b35fb 100644 --- a/hw/display/dpcd.c +++ b/hw/display/dpcd.c @@ -1,5 +1,5 @@ /* - * dpcd.c + * Xilinx Display Port Control Data * * Copyright (C) 2015 : GreenSocs Ltd * http://www.greensocs.com/ , email: info@greensocs.com @@ -137,7 +137,7 @@ static void dpcd_init(Object *obj) { DPCDState *s = DPCD(obj); - memory_region_init_io(&s->iomem, obj, &aux_ops, s, TYPE_DPCD, 0x7FFFF); + memory_region_init_io(&s->iomem, obj, &aux_ops, s, TYPE_DPCD, 0x80000); aux_init_mmio(AUX_SLAVE(obj), &s->iomem); } From eeb1168032a1f6dfc7eb5897c3bf4e53fdc28b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:46 +0200 Subject: [PATCH 0725/2595] hw/display/dpcd: Convert debug printf()s to trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert DPRINTF() to trace events and remove ifdef'ry. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-9-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/dpcd.c | 16 +++------------- hw/display/trace-events | 4 ++++ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/hw/display/dpcd.c b/hw/display/dpcd.c index 0c1b7b35fb..64463654a1 100644 --- a/hw/display/dpcd.c +++ b/hw/display/dpcd.c @@ -32,16 +32,7 @@ #include "hw/misc/auxbus.h" #include "migration/vmstate.h" #include "hw/display/dpcd.h" - -#ifndef DEBUG_DPCD -#define DEBUG_DPCD 0 -#endif - -#define DPRINTF(fmt, ...) do { \ - if (DEBUG_DPCD) { \ - qemu_log("dpcd: " fmt, ## __VA_ARGS__); \ - } \ -} while (0) +#include "trace.h" #define DPCD_READABLE_AREA 0x600 @@ -70,8 +61,8 @@ static uint64_t dpcd_read(void *opaque, hwaddr offset, unsigned size) offset); ret = 0; } + trace_dpcd_read(offset, ret); - DPRINTF("read 0x%" PRIX8 " @0x%" HWADDR_PRIX "\n", ret, offset); return ret; } @@ -80,8 +71,7 @@ static void dpcd_write(void *opaque, hwaddr offset, uint64_t value, { DPCDState *e = DPCD(opaque); - DPRINTF("write 0x%" PRIX8 " @0x%" HWADDR_PRIX "\n", (uint8_t)value, offset); - + trace_dpcd_write(offset, value); if (offset < DPCD_READABLE_AREA) { e->dpcd_info[offset] = value; } else { diff --git a/hw/display/trace-events b/hw/display/trace-events index bb089a5f5e..72d4c9812c 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -157,3 +157,7 @@ artist_draw_line(unsigned int start_x, unsigned int start_y, unsigned int end_x, # cg3.c cg3_read(uint32_t addr, uint32_t val, unsigned size) "read addr:0x%06"PRIx32" val:0x%08"PRIx32" size:%u" cg3_write(uint32_t addr, uint32_t val, unsigned size) "write addr:0x%06"PRIx32" val:0x%08"PRIx32" size:%u" + +# dpcd.c +dpcd_read(uint32_t addr, uint8_t val) "read addr:0x%"PRIx32" val:0x%02x" +dpcd_write(uint32_t addr, uint8_t val) "write addr:0x%"PRIx32" val:0x%02x" From 7bbdf0f8922ab0fc6f805851f6bb1a9d271414f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:47 +0200 Subject: [PATCH 0726/2595] hw/display/xlnx_dp: Replace disabled DPRINTF() by error_report() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DPRINTF() calls are disabled by default, so when unexpected data is used, the whole process abort without information. Display a bit of information with error_report() before crashing. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-10-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/xlnx_dp.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 3e5fb44e06..8d940cd8d1 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1,5 +1,5 @@ /* - * xlnx_dp.c + * Xilinx Display Port * * Copyright (C) 2015 : GreenSocs Ltd * http://www.greensocs.com/ , email: info@greensocs.com @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/module.h" #include "hw/display/xlnx_dp.h" @@ -465,7 +466,7 @@ static uint8_t xlnx_dp_aux_pop_tx_fifo(XlnxDPState *s) uint8_t ret; if (fifo8_is_empty(&s->tx_fifo)) { - DPRINTF("tx_fifo underflow..\n"); + error_report("%s: TX_FIFO underflow", __func__); abort(); } ret = fifo8_pop(&s->tx_fifo); @@ -525,6 +526,7 @@ static void xlnx_dp_aux_set_command(XlnxDPState *s, uint32_t value) qemu_log_mask(LOG_UNIMP, "xlnx_dp: Write i2c status not implemented\n"); break; default: + error_report("%s: invalid command: %u", __func__, cmd); abort(); } @@ -631,8 +633,8 @@ static void xlnx_dp_change_graphic_fmt(XlnxDPState *s) s->g_plane.format = PIXMAN_b8g8r8; break; default: - DPRINTF("error: unsupported graphic format %u.\n", - s->avbufm_registers[AV_BUF_FORMAT] & DP_GRAPHIC_MASK); + error_report("%s: unsupported graphic format %u", __func__, + s->avbufm_registers[AV_BUF_FORMAT] & DP_GRAPHIC_MASK); abort(); } @@ -647,8 +649,8 @@ static void xlnx_dp_change_graphic_fmt(XlnxDPState *s) s->v_plane.format = PIXMAN_x8b8g8r8; break; default: - DPRINTF("error: unsupported video format %u.\n", - s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK); + error_report("%s: unsupported video format %u", __func__, + s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK); abort(); } From aa0fd16d00efd56acdf7def10f769615038e2375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:48 +0200 Subject: [PATCH 0727/2595] hw/display/vmware_vga: Replace printf() calls by qemu_log_mask(ERROR) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid flooding stdio by converting printf() calls to qemu_log_mask(GUEST_ERROR), which are disabled by default. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-11-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/vmware_vga.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 58ea82e3e5..5c0fc49d9d 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -26,6 +26,7 @@ #include "qemu/module.h" #include "qemu/units.h" #include "qapi/error.h" +#include "qemu/log.h" #include "hw/loader.h" #include "trace.h" #include "ui/vnc.h" @@ -953,7 +954,8 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) ret = s->scratch[s->index - SVGA_SCRATCH_BASE]; break; } - printf("%s: Bad register %02x\n", __func__, s->index); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad register %02x\n", __func__, s->index); ret = 0; break; } @@ -1002,7 +1004,8 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) s->new_width = value; s->invalidated = 1; } else { - printf("%s: Bad width: %i\n", __func__, value); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad width: %i\n", __func__, value); } break; @@ -1011,13 +1014,15 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) s->new_height = value; s->invalidated = 1; } else { - printf("%s: Bad height: %i\n", __func__, value); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad height: %i\n", __func__, value); } break; case SVGA_REG_BITS_PER_PIXEL: if (value != 32) { - printf("%s: Bad bits per pixel: %i bits\n", __func__, value); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad bits per pixel: %i bits\n", __func__, value); s->config = 0; s->invalidated = 1; } @@ -1082,7 +1087,8 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) s->scratch[s->index - SVGA_SCRATCH_BASE] = value; break; } - printf("%s: Bad register %02x\n", __func__, s->index); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad register %02x\n", __func__, s->index); } } From becce5e90ace3f4d16ff31f12835bf416ba702a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:49 +0200 Subject: [PATCH 0728/2595] hw/display/vmware_vga: Let the PCI device own its I/O MemoryRegion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid the orphan I/O memory region being added in the /unattached QOM container, register the PCI device as its owner. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200526062252.19852-12-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/vmware_vga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 5c0fc49d9d..2579f6b218 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -1306,7 +1306,7 @@ static void pci_vmsvga_realize(PCIDevice *dev, Error **errp) dev->config[PCI_LATENCY_TIMER] = 0x40; dev->config[PCI_INTERRUPT_LINE] = 0xff; /* End */ - memory_region_init_io(&s->io_bar, NULL, &vmsvga_io_ops, &s->chip, + memory_region_init_io(&s->io_bar, OBJECT(dev), &vmsvga_io_ops, &s->chip, "vmsvga-io", 0x10); memory_region_set_flush_coalesced(&s->io_bar); pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar); From b3caeaf2c863bbf0e57c789d2ee6923f7d3bfe4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:50 +0200 Subject: [PATCH 0729/2595] hw/display/exynos4210_fimd: Use qemu_log_mask(GUEST_ERROR) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace DPRINT_ERROR() by qemu_log_mask(GUEST_ERROR). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-13-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/exynos4210_fimd.c | 46 +++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index 1c0266ce9f..4b7286b7c9 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -31,6 +31,7 @@ #include "ui/pixel_ops.h" #include "qemu/bswap.h" #include "qemu/module.h" +#include "qemu/log.h" /* Debug messages configuration */ #define EXYNOS4210_FIMD_DEBUG 0 @@ -39,20 +40,15 @@ #if EXYNOS4210_FIMD_DEBUG == 0 #define DPRINT_L1(fmt, args...) do { } while (0) #define DPRINT_L2(fmt, args...) do { } while (0) - #define DPRINT_ERROR(fmt, args...) do { } while (0) #elif EXYNOS4210_FIMD_DEBUG == 1 #define DPRINT_L1(fmt, args...) \ do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0) #define DPRINT_L2(fmt, args...) do { } while (0) - #define DPRINT_ERROR(fmt, args...) \ - do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0) #else #define DPRINT_L1(fmt, args...) \ do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0) #define DPRINT_L2(fmt, args...) \ do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0) - #define DPRINT_ERROR(fmt, args...) \ - do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0) #endif #if EXYNOS4210_FIMD_MODE_TRACE == 0 @@ -1108,7 +1104,7 @@ static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w) case FIMD_WINCON_BUF2_STAT: return 2; default: - DPRINT_ERROR("Non-existent buffer index\n"); + qemu_log_mask(LOG_GUEST_ERROR, "FIMD: Non-existent buffer index\n"); return 0; } } @@ -1160,20 +1156,24 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win) if (int128_get64(w->mem_section.size) != w->fb_len || !memory_region_is_ram(w->mem_section.mr)) { - DPRINT_ERROR("Failed to find window %u framebuffer region\n", win); + qemu_log_mask(LOG_GUEST_ERROR, + "FIMD: Failed to find window %u framebuffer region\n", + win); goto error_return; } w->host_fb_addr = cpu_physical_memory_map(fb_start_addr, &fb_mapped_len, false); if (!w->host_fb_addr) { - DPRINT_ERROR("Failed to map window %u framebuffer\n", win); + qemu_log_mask(LOG_GUEST_ERROR, + "FIMD: Failed to map window %u framebuffer\n", win); goto error_return; } if (fb_mapped_len != w->fb_len) { - DPRINT_ERROR("Window %u mapped framebuffer length is less then " - "expected\n", win); + qemu_log_mask(LOG_GUEST_ERROR, + "FIMD: Window %u mapped framebuffer length is less than " + "expected\n", win); cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0); goto error_return; } @@ -1490,7 +1490,9 @@ static void exynos4210_fimd_write(void *opaque, hwaddr offset, break; case 3: if (w != 1 && w != 2) { - DPRINT_ERROR("Bad write offset 0x%08x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "FIMD: Bad write offset 0x%08"HWADDR_PRIx"\n", + offset); return; } s->window[w].osdsize = val; @@ -1624,7 +1626,9 @@ static void exynos4210_fimd_write(void *opaque, hwaddr offset, break; case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2: if (offset & 0x0004) { - DPRINT_ERROR("bad write offset 0x%08x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n", + offset); break; } w = (offset - FIMD_VIDW0ADD0_B2) >> 3; @@ -1638,14 +1642,18 @@ static void exynos4210_fimd_write(void *opaque, hwaddr offset, break; case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END: if (offset & 0x0004) { - DPRINT_ERROR("bad write offset 0x%08x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n", + offset); break; } s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start = val; break; case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END: if (offset & 0x0004) { - DPRINT_ERROR("bad write offset 0x%08x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n", + offset); break; } s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end = val; @@ -1665,7 +1673,8 @@ static void exynos4210_fimd_write(void *opaque, hwaddr offset, s->window[w].palette[i] = val; break; default: - DPRINT_ERROR("bad write offset 0x%08x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n", offset); break; } } @@ -1715,7 +1724,9 @@ static uint64_t exynos4210_fimd_read(void *opaque, hwaddr offset, break; case 3: if (w != 1 && w != 2) { - DPRINT_ERROR("bad read offset 0x%08x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "FIMD: bad read offset 0x%08"HWADDR_PRIx"\n", + offset); return 0xBAADBAAD; } ret = s->window[w].osdsize; @@ -1809,7 +1820,8 @@ static uint64_t exynos4210_fimd_read(void *opaque, hwaddr offset, return s->window[w].palette[i]; } - DPRINT_ERROR("bad read offset 0x%08x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "FIMD: bad read offset 0x%08"HWADDR_PRIx"\n", offset); return 0xBAADBAAD; } From 00a946a3cb2568033f8f5c1a7769c5239a429c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:51 +0200 Subject: [PATCH 0730/2595] hw/display/omap_dss: Replace fprintf() call by qemu_log_mask(LOG_UNIMP) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace fprintf() call by qemu_log_mask(LOG_UNIMP), which is disabled by default. This avoid flooding the terminal when fuzzing the device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-14-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/omap_dss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/display/omap_dss.c b/hw/display/omap_dss.c index 32dc0d6aa7..21fde58a26 100644 --- a/hw/display/omap_dss.c +++ b/hw/display/omap_dss.c @@ -619,7 +619,7 @@ static void omap_rfbi_transfer_start(struct omap_dss_s *s) if (s->rfbi.control & (1 << 1)) { /* BYPASS */ /* TODO: in non-Bypass mode we probably need to just assert the * DRQ and wait for DMA to write the pixels. */ - fprintf(stderr, "%s: Bypass mode unimplemented\n", __func__); + qemu_log_mask(LOG_UNIMP, "%s: Bypass mode unimplemented\n", __func__); return; } From b3a7e2416fb867d047723da251b8960228dcc9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 08:22:52 +0200 Subject: [PATCH 0731/2595] hw/display/pxa2xx_lcd: Replace printf() call by qemu_log_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace printf() calls by qemu_log_mask(UNIMP), which is disabled by default. This avoid flooding the terminal when fuzzing the device. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20200526062252.19852-15-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/pxa2xx_lcd.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c index d5f2e82a4e..ff90104b80 100644 --- a/hw/display/pxa2xx_lcd.c +++ b/hw/display/pxa2xx_lcd.c @@ -426,9 +426,10 @@ static void pxa2xx_lcdc_write(void *opaque, hwaddr offset, if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB)) s->status[0] |= LCSR0_QD; - if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT)) - printf("%s: internal frame buffer unsupported\n", __func__); - + if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT)) { + qemu_log_mask(LOG_UNIMP, + "%s: internal frame buffer unsupported\n", __func__); + } if ((s->control[3] & LCCR3_API) && (value & LCCR0_ENB) && !(value & LCCR0_LCDT)) s->status[0] |= LCSR0_ABC; @@ -462,9 +463,9 @@ static void pxa2xx_lcdc_write(void *opaque, hwaddr offset, break; case OVL1C1: - if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN)) - printf("%s: Overlay 1 not supported\n", __func__); - + if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN)) { + qemu_log_mask(LOG_UNIMP, "%s: Overlay 1 not supported\n", __func__); + } s->ovl1c[0] = value & 0x80ffffff; s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS); break; @@ -474,9 +475,9 @@ static void pxa2xx_lcdc_write(void *opaque, hwaddr offset, break; case OVL2C1: - if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN)) - printf("%s: Overlay 2 not supported\n", __func__); - + if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN)) { + qemu_log_mask(LOG_UNIMP, "%s: Overlay 2 not supported\n", __func__); + } s->ovl2c[0] = value & 0x80ffffff; s->dma_ch[2].up = !!(value & OVLC1_EN); s->dma_ch[3].up = !!(value & OVLC1_EN); @@ -488,9 +489,10 @@ static void pxa2xx_lcdc_write(void *opaque, hwaddr offset, break; case CCR: - if (!(s->ccr & CCR_CEN) && (value & CCR_CEN)) - printf("%s: Hardware cursor unimplemented\n", __func__); - + if (!(s->ccr & CCR_CEN) && (value & CCR_CEN)) { + qemu_log_mask(LOG_UNIMP, + "%s: Hardware cursor unimplemented\n", __func__); + } s->ccr = value & 0x81ffffe7; s->dma_ch[5].up = !!(value & CCR_CEN); break; From e29da77e5fddf6480e3a0e80b63d703edaec751b Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 21 May 2020 21:39:44 +0200 Subject: [PATCH 0732/2595] sm501: Convert printf + abort to qemu_log_mask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some places already use qemu_log_mask() to log unimplemented features or errors but some others have printf() then abort(). Convert these to qemu_log_mask() and avoid aborting to prevent guests to easily cause denial of service. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-id: 305af87f59d81e92f2aaff09eb8a3603b8baa322.1590089984.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 57 ++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index acc692531a..bd3ccfe311 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -727,8 +727,8 @@ static void sm501_2d_operation(SM501State *s) int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); if (addressing != 0x0) { - printf("%s: only XY addressing is supported.\n", __func__); - abort(); + qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n"); + return; } if (rop_mode == 0) { @@ -754,8 +754,8 @@ static void sm501_2d_operation(SM501State *s) if ((s->twoD_source_base & 0x08000000) || (s->twoD_destination_base & 0x08000000)) { - printf("%s: only local memory is supported.\n", __func__); - abort(); + qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n"); + return; } switch (operation) { @@ -823,9 +823,9 @@ static void sm501_2d_operation(SM501State *s) break; default: - printf("non-implemented SM501 2D operation. %d\n", operation); - abort(); - break; + qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n", + operation); + return; } if (dst_base >= get_fb_addr(s, crt) && @@ -892,9 +892,8 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr, break; default: - printf("sm501 system config : not implemented register read." - " addr=%x\n", (int)addr); - abort(); + qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config" + "register read. addr=%" HWADDR_PRIx "\n", addr); } return ret; @@ -948,15 +947,15 @@ static void sm501_system_config_write(void *opaque, hwaddr addr, break; case SM501_ENDIAN_CONTROL: if (value & 0x00000001) { - printf("sm501 system config : big endian mode not implemented.\n"); - abort(); + qemu_log_mask(LOG_UNIMP, "sm501: system config big endian mode not" + " implemented.\n"); } break; default: - printf("sm501 system config : not implemented register write." - " addr=%x, val=%x\n", (int)addr, (uint32_t)value); - abort(); + qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config" + "register write. addr=%" HWADDR_PRIx + ", val=%" PRIx64 "\n", addr, value); } } @@ -1207,9 +1206,8 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr, break; default: - printf("sm501 disp ctrl : not implemented register read." - " addr=%x\n", (int)addr); - abort(); + qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register " + "read. addr=%" HWADDR_PRIx "\n", addr); } return ret; @@ -1345,9 +1343,9 @@ static void sm501_disp_ctrl_write(void *opaque, hwaddr addr, break; default: - printf("sm501 disp ctrl : not implemented register write." - " addr=%x, val=%x\n", (int)addr, (unsigned)value); - abort(); + qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register " + "write. addr=%" HWADDR_PRIx + ", val=%" PRIx64 "\n", addr, value); } } @@ -1433,9 +1431,8 @@ static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr, ret = 0; /* Should return interrupt status */ break; default: - printf("sm501 disp ctrl : not implemented register read." - " addr=%x\n", (int)addr); - abort(); + qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register " + "read. addr=%" HWADDR_PRIx "\n", addr); } return ret; @@ -1520,9 +1517,9 @@ static void sm501_2d_engine_write(void *opaque, hwaddr addr, /* ignored, writing 0 should clear interrupt status */ break; default: - printf("sm501 2d engine : not implemented register write." - " addr=%x, val=%x\n", (int)addr, (unsigned)value); - abort(); + qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2d engine register " + "write. addr=%" HWADDR_PRIx + ", val=%" PRIx64 "\n", addr, value); } } @@ -1670,9 +1667,9 @@ static void sm501_update_display(void *opaque) draw_line = draw_line32_funcs[dst_depth_index]; break; default: - printf("sm501 update display : invalid control register value.\n"); - abort(); - break; + qemu_log_mask(LOG_GUEST_ERROR, "sm501: update display" + "invalid control register value.\n"); + return; } /* set up to draw hardware cursor */ From 6f8183b5dc5b309378687830a25e85ea8fb860ea Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 21 May 2020 21:39:44 +0200 Subject: [PATCH 0733/2595] sm501: Shorten long variable names in sm501_2d_operation This increases readability and cleans up some confusing naming. Signed-off-by: BALATON Zoltan Message-id: b9b67b94c46e945252a73c77dfd117132c63c4fb.1590089984.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index bd3ccfe311..f42d05e1e4 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -700,17 +700,16 @@ static inline void hwc_invalidate(SM501State *s, int crt) static void sm501_2d_operation(SM501State *s) { /* obtain operation parameters */ - int operation = (s->twoD_control >> 16) & 0x1f; + int cmd = (s->twoD_control >> 16) & 0x1F; int rtl = s->twoD_control & 0x8000000; int src_x = (s->twoD_source >> 16) & 0x01FFF; int src_y = s->twoD_source & 0xFFFF; int dst_x = (s->twoD_destination >> 16) & 0x01FFF; int dst_y = s->twoD_destination & 0xFFFF; - int operation_width = (s->twoD_dimension >> 16) & 0x1FFF; - int operation_height = s->twoD_dimension & 0xFFFF; + int width = (s->twoD_dimension >> 16) & 0x1FFF; + int height = s->twoD_dimension & 0xFFFF; uint32_t color = s->twoD_foreground; - int format_flags = (s->twoD_stretch >> 20) & 0x3; - int addressing = (s->twoD_stretch >> 16) & 0xF; + int format = (s->twoD_stretch >> 20) & 0x3; int rop_mode = (s->twoD_control >> 15) & 0x1; /* 1 for rop2, else rop3 */ /* 1 if rop2 source is the pattern, otherwise the source is the bitmap */ int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1; @@ -721,12 +720,12 @@ static void sm501_2d_operation(SM501State *s) /* get frame buffer info */ uint8_t *src = s->local_mem + src_base; uint8_t *dst = s->local_mem + dst_base; - int src_width = s->twoD_pitch & 0x1FFF; - int dst_width = (s->twoD_pitch >> 16) & 0x1FFF; + int src_pitch = s->twoD_pitch & 0x1FFF; + int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); - if (addressing != 0x0) { + if ((s->twoD_stretch >> 16) & 0xF) { qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n"); return; } @@ -758,20 +757,20 @@ static void sm501_2d_operation(SM501State *s) return; } - switch (operation) { + switch (cmd) { case 0x00: /* copy area */ #define COPY_AREA(_bpp, _pixel_type, rtl) { \ int y, x, index_d, index_s; \ - for (y = 0; y < operation_height; y++) { \ - for (x = 0; x < operation_width; x++) { \ + for (y = 0; y < height; y++) { \ + for (x = 0; x < width; x++) { \ _pixel_type val; \ \ if (rtl) { \ - index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \ - index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \ + index_s = ((src_y - y) * src_pitch + src_x - x) * _bpp; \ + index_d = ((dst_y - y) * dst_pitch + dst_x - x) * _bpp; \ } else { \ - index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \ - index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \ + index_s = ((src_y + y) * src_pitch + src_x + x) * _bpp; \ + index_d = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ } \ if (rop_mode == 1 && rop == 5) { \ /* Invert dest */ \ @@ -783,7 +782,7 @@ static void sm501_2d_operation(SM501State *s) } \ } \ } - switch (format_flags) { + switch (format) { case 0: COPY_AREA(1, uint8_t, rtl); break; @@ -799,15 +798,15 @@ static void sm501_2d_operation(SM501State *s) case 0x01: /* fill rectangle */ #define FILL_RECT(_bpp, _pixel_type) { \ int y, x; \ - for (y = 0; y < operation_height; y++) { \ - for (x = 0; x < operation_width; x++) { \ - int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \ + for (y = 0; y < height; y++) { \ + for (x = 0; x < width; x++) { \ + int index = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ *(_pixel_type *)&dst[index] = (_pixel_type)color; \ } \ } \ } - switch (format_flags) { + switch (format) { case 0: FILL_RECT(1, uint8_t); break; @@ -824,14 +823,14 @@ static void sm501_2d_operation(SM501State *s) default: qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n", - operation); + cmd); return; } if (dst_base >= get_fb_addr(s, crt) && dst_base <= get_fb_addr(s, crt) + fb_len) { - int dst_len = MIN(fb_len, ((dst_y + operation_height - 1) * dst_width + - dst_x + operation_width) * (1 << format_flags)); + int dst_len = MIN(fb_len, ((dst_y + height - 1) * dst_pitch + + dst_x + width) * (1 << format)); if (dst_len) { memory_region_set_dirty(&s->local_mem_region, dst_base, dst_len); } From 2824809b7f8f03ddc6e2b7e33e78c06022424298 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 21 May 2020 21:39:44 +0200 Subject: [PATCH 0734/2595] sm501: Use BIT(x) macro to shorten constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-id: 124bf5de8d7cf503b32b377d0445029a76bfbd49.1590089984.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index f42d05e1e4..97660090bb 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -701,7 +701,7 @@ static void sm501_2d_operation(SM501State *s) { /* obtain operation parameters */ int cmd = (s->twoD_control >> 16) & 0x1F; - int rtl = s->twoD_control & 0x8000000; + int rtl = s->twoD_control & BIT(27); int src_x = (s->twoD_source >> 16) & 0x01FFF; int src_y = s->twoD_source & 0xFFFF; int dst_x = (s->twoD_destination >> 16) & 0x01FFF; @@ -751,8 +751,7 @@ static void sm501_2d_operation(SM501State *s) } } - if ((s->twoD_source_base & 0x08000000) || - (s->twoD_destination_base & 0x08000000)) { + if (s->twoD_source_base & BIT(27) || s->twoD_destination_base & BIT(27)) { qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n"); return; } From 3d0b096298b5579a7fa0753ad90968b27bc65372 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 21 May 2020 21:39:44 +0200 Subject: [PATCH 0735/2595] sm501: Clean up local variables in sm501_2d_operation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make variables local to the block they are used in to make it clearer which operation they are needed for. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-id: ae59f8138afe7f6a5a4a82539d0f61496a906b06.1590089984.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 97660090bb..5ed57703d8 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -699,28 +699,19 @@ static inline void hwc_invalidate(SM501State *s, int crt) static void sm501_2d_operation(SM501State *s) { - /* obtain operation parameters */ int cmd = (s->twoD_control >> 16) & 0x1F; int rtl = s->twoD_control & BIT(27); - int src_x = (s->twoD_source >> 16) & 0x01FFF; - int src_y = s->twoD_source & 0xFFFF; - int dst_x = (s->twoD_destination >> 16) & 0x01FFF; - int dst_y = s->twoD_destination & 0xFFFF; - int width = (s->twoD_dimension >> 16) & 0x1FFF; - int height = s->twoD_dimension & 0xFFFF; - uint32_t color = s->twoD_foreground; int format = (s->twoD_stretch >> 20) & 0x3; int rop_mode = (s->twoD_control >> 15) & 0x1; /* 1 for rop2, else rop3 */ /* 1 if rop2 source is the pattern, otherwise the source is the bitmap */ int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1; int rop = s->twoD_control & 0xFF; - uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; + int dst_x = (s->twoD_destination >> 16) & 0x01FFF; + int dst_y = s->twoD_destination & 0xFFFF; + int width = (s->twoD_dimension >> 16) & 0x1FFF; + int height = s->twoD_dimension & 0xFFFF; uint32_t dst_base = s->twoD_destination_base & 0x03FFFFFF; - - /* get frame buffer info */ - uint8_t *src = s->local_mem + src_base; uint8_t *dst = s->local_mem + dst_base; - int src_pitch = s->twoD_pitch & 0x1FFF; int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); @@ -758,6 +749,13 @@ static void sm501_2d_operation(SM501State *s) switch (cmd) { case 0x00: /* copy area */ + { + int src_x = (s->twoD_source >> 16) & 0x01FFF; + int src_y = s->twoD_source & 0xFFFF; + uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; + uint8_t *src = s->local_mem + src_base; + int src_pitch = s->twoD_pitch & 0x1FFF; + #define COPY_AREA(_bpp, _pixel_type, rtl) { \ int y, x, index_d, index_s; \ for (y = 0; y < height; y++) { \ @@ -793,8 +791,11 @@ static void sm501_2d_operation(SM501State *s) break; } break; - + } case 0x01: /* fill rectangle */ + { + uint32_t color = s->twoD_foreground; + #define FILL_RECT(_bpp, _pixel_type) { \ int y, x; \ for (y = 0; y < height; y++) { \ @@ -819,7 +820,7 @@ static void sm501_2d_operation(SM501State *s) break; } break; - + } default: qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n", cmd); From b15a22bbcbe6a78dc3d88fe3134985e4cdd87de4 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 21 May 2020 21:39:44 +0200 Subject: [PATCH 0736/2595] sm501: Replace hand written implementation with pixman where possible Besides being faster this should also prevent malicious guests to abuse 2D engine to overwrite data or cause a crash. Signed-off-by: BALATON Zoltan Message-id: 58666389b6cae256e4e972a32c05cf8aa51bffc0.1590089984.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 211 ++++++++++++++++++++++++++------------------- 1 file changed, 121 insertions(+), 90 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 5ed57703d8..8bf4d111f4 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -706,13 +706,12 @@ static void sm501_2d_operation(SM501State *s) /* 1 if rop2 source is the pattern, otherwise the source is the bitmap */ int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1; int rop = s->twoD_control & 0xFF; - int dst_x = (s->twoD_destination >> 16) & 0x01FFF; - int dst_y = s->twoD_destination & 0xFFFF; - int width = (s->twoD_dimension >> 16) & 0x1FFF; - int height = s->twoD_dimension & 0xFFFF; + unsigned int dst_x = (s->twoD_destination >> 16) & 0x01FFF; + unsigned int dst_y = s->twoD_destination & 0xFFFF; + unsigned int width = (s->twoD_dimension >> 16) & 0x1FFF; + unsigned int height = s->twoD_dimension & 0xFFFF; uint32_t dst_base = s->twoD_destination_base & 0x03FFFFFF; - uint8_t *dst = s->local_mem + dst_base; - int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; + unsigned int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); @@ -721,104 +720,136 @@ static void sm501_2d_operation(SM501State *s) return; } - if (rop_mode == 0) { - if (rop != 0xcc) { - /* Anything other than plain copies are not supported */ - qemu_log_mask(LOG_UNIMP, "sm501: rop3 mode with rop %x is not " - "supported.\n", rop); - } - } else { - if (rop2_source_is_pattern && rop != 0x5) { - /* For pattern source, we support only inverse dest */ - qemu_log_mask(LOG_UNIMP, "sm501: rop2 source being the pattern and " - "rop %x is not supported.\n", rop); - } else { - if (rop != 0x5 && rop != 0xc) { - /* Anything other than plain copies or inverse dest is not - * supported */ - qemu_log_mask(LOG_UNIMP, "sm501: rop mode %x is not " - "supported.\n", rop); - } - } - } - if (s->twoD_source_base & BIT(27) || s->twoD_destination_base & BIT(27)) { qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n"); return; } - switch (cmd) { - case 0x00: /* copy area */ - { - int src_x = (s->twoD_source >> 16) & 0x01FFF; - int src_y = s->twoD_source & 0xFFFF; - uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; - uint8_t *src = s->local_mem + src_base; - int src_pitch = s->twoD_pitch & 0x1FFF; - -#define COPY_AREA(_bpp, _pixel_type, rtl) { \ - int y, x, index_d, index_s; \ - for (y = 0; y < height; y++) { \ - for (x = 0; x < width; x++) { \ - _pixel_type val; \ - \ - if (rtl) { \ - index_s = ((src_y - y) * src_pitch + src_x - x) * _bpp; \ - index_d = ((dst_y - y) * dst_pitch + dst_x - x) * _bpp; \ - } else { \ - index_s = ((src_y + y) * src_pitch + src_x + x) * _bpp; \ - index_d = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ - } \ - if (rop_mode == 1 && rop == 5) { \ - /* Invert dest */ \ - val = ~*(_pixel_type *)&dst[index_d]; \ - } else { \ - val = *(_pixel_type *)&src[index_s]; \ - } \ - *(_pixel_type *)&dst[index_d] = val; \ - } \ - } \ + if (!dst_pitch) { + qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero dest pitch.\n"); + return; } - switch (format) { - case 0: - COPY_AREA(1, uint8_t, rtl); - break; - case 1: - COPY_AREA(2, uint16_t, rtl); - break; - case 2: - COPY_AREA(4, uint32_t, rtl); - break; + + if (!width || !height) { + qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero size 2D op.\n"); + return; + } + + if (rtl) { + dst_x -= width - 1; + dst_y -= height - 1; + } + + if (dst_base >= get_local_mem_size(s) || dst_base + + (dst_x + width + (dst_y + height) * (dst_pitch + width)) * + (1 << format) >= get_local_mem_size(s)) { + qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op dest is outside vram.\n"); + return; + } + + switch (cmd) { + case 0: /* BitBlt */ + { + unsigned int src_x = (s->twoD_source >> 16) & 0x01FFF; + unsigned int src_y = s->twoD_source & 0xFFFF; + uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; + unsigned int src_pitch = s->twoD_pitch & 0x1FFF; + + if (!src_pitch) { + qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero src pitch.\n"); + return; + } + + if (rtl) { + src_x -= width - 1; + src_y -= height - 1; + } + + if (src_base >= get_local_mem_size(s) || src_base + + (src_x + width + (src_y + height) * (src_pitch + width)) * + (1 << format) >= get_local_mem_size(s)) { + qemu_log_mask(LOG_GUEST_ERROR, + "sm501: 2D op src is outside vram.\n"); + return; + } + + if ((rop_mode && rop == 0x5) || (!rop_mode && rop == 0x55)) { + /* Invert dest, is there a way to do this with pixman? */ + unsigned int x, y, i; + uint8_t *d = s->local_mem + dst_base; + + for (y = 0; y < height; y++) { + i = (dst_x + (dst_y + y) * dst_pitch) * (1 << format); + for (x = 0; x < width; x++, i += (1 << format)) { + switch (format) { + case 0: + d[i] = ~d[i]; + break; + case 1: + *(uint16_t *)&d[i] = ~*(uint16_t *)&d[i]; + break; + case 2: + *(uint32_t *)&d[i] = ~*(uint32_t *)&d[i]; + break; + } + } + } + } else { + /* Do copy src for unimplemented ops, better than unpainted area */ + if ((rop_mode && (rop != 0xc || rop2_source_is_pattern)) || + (!rop_mode && rop != 0xcc)) { + qemu_log_mask(LOG_UNIMP, + "sm501: rop%d op %x%s not implemented\n", + (rop_mode ? 2 : 3), rop, + (rop2_source_is_pattern ? + " with pattern source" : "")); + } + /* Check for overlaps, this could be made more exact */ + uint32_t sb, se, db, de; + sb = src_base + src_x + src_y * (width + src_pitch); + se = sb + width + height * (width + src_pitch); + db = dst_base + dst_x + dst_y * (width + dst_pitch); + de = db + width + height * (width + dst_pitch); + if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) { + /* regions may overlap: copy via temporary */ + int llb = width * (1 << format); + int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t)); + uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) * + height); + pixman_blt((uint32_t *)&s->local_mem[src_base], tmp, + src_pitch * (1 << format) / sizeof(uint32_t), + tmp_stride, 8 * (1 << format), 8 * (1 << format), + src_x, src_y, 0, 0, width, height); + pixman_blt(tmp, (uint32_t *)&s->local_mem[dst_base], + tmp_stride, + dst_pitch * (1 << format) / sizeof(uint32_t), + 8 * (1 << format), 8 * (1 << format), + 0, 0, dst_x, dst_y, width, height); + g_free(tmp); + } else { + pixman_blt((uint32_t *)&s->local_mem[src_base], + (uint32_t *)&s->local_mem[dst_base], + src_pitch * (1 << format) / sizeof(uint32_t), + dst_pitch * (1 << format) / sizeof(uint32_t), + 8 * (1 << format), 8 * (1 << format), + src_x, src_y, dst_x, dst_y, width, height); + } } break; } - case 0x01: /* fill rectangle */ + case 1: /* Rectangle Fill */ { uint32_t color = s->twoD_foreground; -#define FILL_RECT(_bpp, _pixel_type) { \ - int y, x; \ - for (y = 0; y < height; y++) { \ - for (x = 0; x < width; x++) { \ - int index = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ - *(_pixel_type *)&dst[index] = (_pixel_type)color; \ - } \ - } \ - } - - switch (format) { - case 0: - FILL_RECT(1, uint8_t); - break; - case 1: - color = cpu_to_le16(color); - FILL_RECT(2, uint16_t); - break; - case 2: + if (format == 2) { color = cpu_to_le32(color); - FILL_RECT(4, uint32_t); - break; + } else if (format == 1) { + color = cpu_to_le16(color); } + + pixman_fill((uint32_t *)&s->local_mem[dst_base], + dst_pitch * (1 << format) / sizeof(uint32_t), + 8 * (1 << format), dst_x, dst_y, width, height, color); break; } default: From fa70c2871f011f1ca6763a21a291f2ced1f121d2 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 21 May 2020 21:39:44 +0200 Subject: [PATCH 0737/2595] sm501: Optimize small overlapping blits AmigaOS tends to do a lot of small blits (even 1 pixel). Avoid malloc overhead by keeping around a buffer for this and only alloc when blitting larger areas. Signed-off-by: BALATON Zoltan Message-id: 7946852258d528497e85f465327fc90b5c3b59fb.1590089984.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 8bf4d111f4..e7a9f77de7 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -750,6 +750,7 @@ static void sm501_2d_operation(SM501State *s) switch (cmd) { case 0: /* BitBlt */ { + static uint32_t tmp_buf[16384]; unsigned int src_x = (s->twoD_source >> 16) & 0x01FFF; unsigned int src_y = s->twoD_source & 0xFFFF; uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; @@ -812,10 +813,14 @@ static void sm501_2d_operation(SM501State *s) de = db + width + height * (width + dst_pitch); if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) { /* regions may overlap: copy via temporary */ - int llb = width * (1 << format); + int free_buf = 0, llb = width * (1 << format); int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t)); - uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) * - height); + uint32_t *tmp = tmp_buf; + + if (tmp_stride * sizeof(uint32_t) * height > sizeof(tmp_buf)) { + tmp = g_malloc(tmp_stride * sizeof(uint32_t) * height); + free_buf = 1; + } pixman_blt((uint32_t *)&s->local_mem[src_base], tmp, src_pitch * (1 << format) / sizeof(uint32_t), tmp_stride, 8 * (1 << format), 8 * (1 << format), @@ -825,7 +830,9 @@ static void sm501_2d_operation(SM501State *s) dst_pitch * (1 << format) / sizeof(uint32_t), 8 * (1 << format), 8 * (1 << format), 0, 0, dst_x, dst_y, width, height); - g_free(tmp); + if (free_buf) { + g_free(tmp); + } } else { pixman_blt((uint32_t *)&s->local_mem[src_base], (uint32_t *)&s->local_mem[dst_base], From fa0013a1bc5f6011a1017e0e655740403e5555d9 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 21 May 2020 21:39:44 +0200 Subject: [PATCH 0738/2595] sm501: Remove obsolete changelog and todo comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also update copyright year for latest changes Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-id: 1392cad2ad1315a5a50409970e0af061821462e6.1590089984.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index e7a9f77de7..edd8d24a76 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -2,7 +2,7 @@ * QEMU SM501 Device * * Copyright (c) 2008 Shin-ichiro KAWASAKI - * Copyright (c) 2016 BALATON Zoltan + * Copyright (c) 2016-2020 BALATON Zoltan * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -40,23 +40,6 @@ #include "ui/pixel_ops.h" #include "qemu/bswap.h" -/* - * Status: 2010/05/07 - * - Minimum implementation for Linux console : mmio regs and CRT layer. - * - 2D graphics acceleration partially supported : only fill rectangle. - * - * Status: 2016/12/04 - * - Misc fixes: endianness, hardware cursor - * - Panel support - * - * TODO: - * - Touch panel support - * - USB support - * - UART support - * - More 2D graphics engine support - * - Performance tuning - */ - /*#define DEBUG_SM501*/ /*#define DEBUG_BITBLT*/ From 38908bbc65bcabf110dcc87a84c518e3e6d9a183 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 22 May 2020 01:06:43 +0300 Subject: [PATCH 0739/2595] migration: refactor init_dirty_bitmap_migration Split out handling one bs, it is needed for the following commit, which will handle BlockBackends separately. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200521220648.3255-2-vsementsov@virtuozzo.com> [eblake: shorter subject line] Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 89 +++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 7eafface61..7e93718086 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -268,57 +268,66 @@ static void dirty_bitmap_mig_cleanup(void) } /* Called with iothread lock taken. */ -static int init_dirty_bitmap_migration(void) +static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name) { - BlockDriverState *bs; BdrvDirtyBitmap *bitmap; DirtyBitmapMigBitmapState *dbms; Error *local_err = NULL; + FOR_EACH_DIRTY_BITMAP(bs, bitmap) { + if (!bdrv_dirty_bitmap_name(bitmap)) { + continue; + } + + if (!bs_name || strcmp(bs_name, "") == 0) { + error_report("Found bitmap '%s' in unnamed node %p. It can't " + "be migrated", bdrv_dirty_bitmap_name(bitmap), bs); + return -1; + } + + if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, &local_err)) { + error_report_err(local_err); + return -1; + } + + bdrv_ref(bs); + bdrv_dirty_bitmap_set_busy(bitmap, true); + + dbms = g_new0(DirtyBitmapMigBitmapState, 1); + dbms->bs = bs; + dbms->node_name = bs_name; + dbms->bitmap = bitmap; + dbms->total_sectors = bdrv_nb_sectors(bs); + dbms->sectors_per_chunk = CHUNK_SIZE * 8 * + bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS; + if (bdrv_dirty_bitmap_enabled(bitmap)) { + dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_ENABLED; + } + if (bdrv_dirty_bitmap_get_persistence(bitmap)) { + dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT; + } + + QSIMPLEQ_INSERT_TAIL(&dirty_bitmap_mig_state.dbms_list, + dbms, entry); + } + + return 0; +} + +/* Called with iothread lock taken. */ +static int init_dirty_bitmap_migration(void) +{ + BlockDriverState *bs; + DirtyBitmapMigBitmapState *dbms; + dirty_bitmap_mig_state.bulk_completed = false; dirty_bitmap_mig_state.prev_bs = NULL; dirty_bitmap_mig_state.prev_bitmap = NULL; dirty_bitmap_mig_state.no_bitmaps = false; for (bs = bdrv_next_all_states(NULL); bs; bs = bdrv_next_all_states(bs)) { - const char *name = bdrv_get_device_or_node_name(bs); - - FOR_EACH_DIRTY_BITMAP(bs, bitmap) { - if (!bdrv_dirty_bitmap_name(bitmap)) { - continue; - } - - if (!name || strcmp(name, "") == 0) { - error_report("Found bitmap '%s' in unnamed node %p. It can't " - "be migrated", bdrv_dirty_bitmap_name(bitmap), bs); - goto fail; - } - - if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, - &local_err)) { - error_report_err(local_err); - goto fail; - } - - bdrv_ref(bs); - bdrv_dirty_bitmap_set_busy(bitmap, true); - - dbms = g_new0(DirtyBitmapMigBitmapState, 1); - dbms->bs = bs; - dbms->node_name = name; - dbms->bitmap = bitmap; - dbms->total_sectors = bdrv_nb_sectors(bs); - dbms->sectors_per_chunk = CHUNK_SIZE * 8 * - bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS; - if (bdrv_dirty_bitmap_enabled(bitmap)) { - dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_ENABLED; - } - if (bdrv_dirty_bitmap_get_persistence(bitmap)) { - dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT; - } - - QSIMPLEQ_INSERT_TAIL(&dirty_bitmap_mig_state.dbms_list, - dbms, entry); + if (add_bitmaps_to_list(bs, bdrv_get_device_or_node_name(bs))) { + goto fail; } } From 7ae89a0de945616fcde5947cec5aecb8dce07d81 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 22 May 2020 01:06:44 +0300 Subject: [PATCH 0740/2595] block/dirty-bitmap: add bdrv_has_named_bitmaps helper To be used for bitmap migration in further commit. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Reviewed-by: Eric Blake Message-Id: <20200521220648.3255-3-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- block/dirty-bitmap.c | 13 +++++++++++++ include/block/dirty-bitmap.h | 1 + 2 files changed, 14 insertions(+) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index f9bfc77985..c01319b188 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -818,6 +818,19 @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs) return false; } +bool bdrv_has_named_bitmaps(BlockDriverState *bs) +{ + BdrvDirtyBitmap *bm; + + QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) { + if (bdrv_dirty_bitmap_name(bm)) { + return true; + } + } + + return false; +} + /* Called with BQL taken. */ void bdrv_dirty_bitmap_set_persistence(BdrvDirtyBitmap *bitmap, bool persistent) { diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index 5a8d52e4de..36e8da4fc2 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -95,6 +95,7 @@ int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap); void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes); bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap); bool bdrv_has_readonly_bitmaps(BlockDriverState *bs); +bool bdrv_has_named_bitmaps(BlockDriverState *bs); bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap); bool bdrv_dirty_bitmap_get_persistence(BdrvDirtyBitmap *bitmap); bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap); From 107cfb72541c70030caa9a21578edd73127cf2b4 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 22 May 2020 01:06:45 +0300 Subject: [PATCH 0741/2595] migration: fix bitmaps pre-blockdev migration with mirror job Important thing for bitmap migration is to select destination block node to obtain the migrated bitmap. Prepatch, on source we use bdrv_get_device_or_node_name() to identify the node, and on target we do bdrv_lookup_bs. bdrv_get_device_or_node_name() returns blk name only for direct children of blk. So, bitmaps of direct children of blks are migrated by blk name and others - by node name. Old libvirt is unprepared to bitmap migration by node-name, node-names are mostly auto-generated. So actually only migration by blk name works for it. Newer libvirt will use new interface (which will be added soon) to specify node-mapping for bitmaps migration explicitly. Still, let's improve the current behavior a bit. Now, consider classic libvirt migrations assisted by mirror block job: mirror block job inserts filter, so our source is not a direct child of blk, and bitmaps are migrated by node-names. And this just doesn't work with auto-generated node names. Let's fix it by using blk-name even if some implicit filters are inserted. Note2: we, of course, can't skip filters and use blk name to migrate bitmaps in filtered node by blk name for this blk if these filters have named bitmaps which should be migrated. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1652424 Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200521220648.3255-4-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake [eblake: comment typo fix, shorter subject line] Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 45 +++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 7e93718086..69ddf289dd 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -319,14 +319,54 @@ static int init_dirty_bitmap_migration(void) { BlockDriverState *bs; DirtyBitmapMigBitmapState *dbms; + GHashTable *handled_by_blk = g_hash_table_new(NULL, NULL); + BlockBackend *blk; dirty_bitmap_mig_state.bulk_completed = false; dirty_bitmap_mig_state.prev_bs = NULL; dirty_bitmap_mig_state.prev_bitmap = NULL; dirty_bitmap_mig_state.no_bitmaps = false; + /* + * Use blockdevice name for direct (or filtered) children of named block + * backends. + */ + for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { + const char *name = blk_name(blk); + + if (!name || strcmp(name, "") == 0) { + continue; + } + + bs = blk_bs(blk); + + /* Skip filters without bitmaps */ + while (bs && bs->drv && bs->drv->is_filter && + !bdrv_has_named_bitmaps(bs)) + { + if (bs->backing) { + bs = bs->backing->bs; + } else if (bs->file) { + bs = bs->file->bs; + } else { + bs = NULL; + } + } + + if (bs && bs->drv && !bs->drv->is_filter) { + if (add_bitmaps_to_list(bs, name)) { + goto fail; + } + g_hash_table_add(handled_by_blk, bs); + } + } + for (bs = bdrv_next_all_states(NULL); bs; bs = bdrv_next_all_states(bs)) { - if (add_bitmaps_to_list(bs, bdrv_get_device_or_node_name(bs))) { + if (g_hash_table_contains(handled_by_blk, bs)) { + continue; + } + + if (add_bitmaps_to_list(bs, bdrv_get_node_name(bs))) { goto fail; } } @@ -340,9 +380,12 @@ static int init_dirty_bitmap_migration(void) dirty_bitmap_mig_state.no_bitmaps = true; } + g_hash_table_destroy(handled_by_blk); + return 0; fail: + g_hash_table_destroy(handled_by_blk); dirty_bitmap_mig_cleanup(); return -1; From ae00aa2398476824f0eca80461da215e7cdc1c3b Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 22 May 2020 01:06:46 +0300 Subject: [PATCH 0742/2595] iotests: 194: test also migration of dirty bitmap Test that dirty bitmap migration works when we deal with mirror. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20200521220648.3255-5-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/194 | 14 ++++++++++---- tests/qemu-iotests/194.out | 6 ++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/qemu-iotests/194 b/tests/qemu-iotests/194 index 8b1f720af4..3fad7c6c1a 100755 --- a/tests/qemu-iotests/194 +++ b/tests/qemu-iotests/194 @@ -42,6 +42,8 @@ with iotests.FilePath('source.img') as source_img_path, \ .add_incoming('unix:{0}'.format(migration_sock_path)) .launch()) + source_vm.qmp_log('block-dirty-bitmap-add', node='drive0', name='bitmap0') + iotests.log('Launching NBD server on destination...') iotests.log(dest_vm.qmp('nbd-server-start', addr={'type': 'unix', 'data': {'path': nbd_sock_path}})) iotests.log(dest_vm.qmp('nbd-server-add', device='drive0', writable=True)) @@ -61,12 +63,14 @@ with iotests.FilePath('source.img') as source_img_path, \ filters=[iotests.filter_qmp_event]) iotests.log('Starting migration...') - source_vm.qmp('migrate-set-capabilities', - capabilities=[{'capability': 'events', 'state': True}]) - dest_vm.qmp('migrate-set-capabilities', - capabilities=[{'capability': 'events', 'state': True}]) + capabilities = [{'capability': 'events', 'state': True}, + {'capability': 'dirty-bitmaps', 'state': True}] + source_vm.qmp('migrate-set-capabilities', capabilities=capabilities) + dest_vm.qmp('migrate-set-capabilities', capabilities=capabilities) iotests.log(source_vm.qmp('migrate', uri='unix:{0}'.format(migration_sock_path))) + source_vm.qmp_log('migrate-start-postcopy') + while True: event1 = source_vm.event_wait('MIGRATION') iotests.log(event1, filters=[iotests.filter_qmp_event]) @@ -82,3 +86,5 @@ with iotests.FilePath('source.img') as source_img_path, \ iotests.log('Stopping the NBD server on destination...') iotests.log(dest_vm.qmp('nbd-server-stop')) break + + iotests.log(source_vm.qmp('query-block')['return'][0]['dirty-bitmaps']) diff --git a/tests/qemu-iotests/194.out b/tests/qemu-iotests/194.out index 71857853fb..dd60dcc14f 100644 --- a/tests/qemu-iotests/194.out +++ b/tests/qemu-iotests/194.out @@ -1,4 +1,6 @@ Launching VMs... +{"execute": "block-dirty-bitmap-add", "arguments": {"name": "bitmap0", "node": "drive0"}} +{"return": {}} Launching NBD server on destination... {"return": {}} {"return": {}} @@ -8,11 +10,15 @@ Waiting for `drive-mirror` to complete... {"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} Starting migration... {"return": {}} +{"execute": "migrate-start-postcopy", "arguments": {}} +{"return": {}} {"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"status": "postcopy-active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} Gracefully ending the `drive-mirror` job on source... {"return": {}} {"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} Stopping the NBD server on destination... {"return": {}} +[{"busy": false, "count": 0, "granularity": 65536, "name": "bitmap0", "persistent": false, "recording": true, "status": "active"}] From 82640edb88faacad90ff19f6fced37f9c8025e48 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 22 May 2020 01:06:47 +0300 Subject: [PATCH 0743/2595] migration: add_bitmaps_to_list: check disk name once Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Reviewed-by: Eric Blake Message-Id: <20200521220648.3255-6-vsementsov@virtuozzo.com> [eblake: shorter subject line] Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 69ddf289dd..7be1644b33 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -274,17 +274,22 @@ static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name) DirtyBitmapMigBitmapState *dbms; Error *local_err = NULL; + bitmap = bdrv_dirty_bitmap_first(bs); + if (!bitmap) { + return 0; + } + + if (!bs_name || strcmp(bs_name, "") == 0) { + error_report("Bitmap '%s' in unnamed node can't be migrated", + bdrv_dirty_bitmap_name(bitmap)); + return -1; + } + FOR_EACH_DIRTY_BITMAP(bs, bitmap) { if (!bdrv_dirty_bitmap_name(bitmap)) { continue; } - if (!bs_name || strcmp(bs_name, "") == 0) { - error_report("Found bitmap '%s' in unnamed node %p. It can't " - "be migrated", bdrv_dirty_bitmap_name(bitmap), bs); - return -1; - } - if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, &local_err)) { error_report_err(local_err); return -1; From 4ff5cc121b089d8b16fa3da1e44feababcd1f815 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 22 May 2020 01:06:48 +0300 Subject: [PATCH 0744/2595] migration: forbid bitmap migration by generated node-name It actually never worked with libvirt, as auto-generated names are different on source and destination. It's unsafe and useless to migrate by auto-generated node-names, so let's forbid it. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Reviewed-by: Eric Blake Message-Id: <20200521220648.3255-7-vsementsov@virtuozzo.com> [eblake: shorter subject line] Signed-off-by: Eric Blake --- migration/block-dirty-bitmap.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 7be1644b33..47bc0f650c 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -285,6 +285,13 @@ static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name) return -1; } + if (bs_name[0] == '#') { + error_report("Bitmap '%s' in a node with auto-generated " + "name '%s' can't be migrated", + bdrv_dirty_bitmap_name(bitmap), bs_name); + return -1; + } + FOR_EACH_DIRTY_BITMAP(bs, bitmap) { if (!bdrv_dirty_bitmap_name(bitmap)) { continue; From ca01b7a641527052e3e8961845b40b81706ce5f9 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 21 May 2020 14:21:33 -0500 Subject: [PATCH 0745/2595] iotests: Fix test 178 A recent change to qemu-img changed expected error message output, but 178 takes long enough to execute that it does not get run by 'make check' or './check -g quick'. Fixes: 43d589b074 Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200521192137.1120211-2-eblake@redhat.com> --- tests/qemu-iotests/178.out.qcow2 | 2 +- tests/qemu-iotests/178.out.raw | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2 index f59bf4b2fb..4b69524c80 100644 --- a/tests/qemu-iotests/178.out.qcow2 +++ b/tests/qemu-iotests/178.out.qcow2 @@ -13,7 +13,7 @@ qemu-img: Invalid option list: , qemu-img: Invalid parameter 'snapshot.foo' qemu-img: Failed in parsing snapshot param 'snapshot.foo' qemu-img: --output must be used with human or json as argument. -qemu-img: Image size must be less than 8 EiB! +qemu-img: Invalid image size specified. Must be between 0 and 9223372036854775807. qemu-img: Unknown file format 'foo' == Size calculation for a new file (human) == diff --git a/tests/qemu-iotests/178.out.raw b/tests/qemu-iotests/178.out.raw index 404ca908d8..20e17da115 100644 --- a/tests/qemu-iotests/178.out.raw +++ b/tests/qemu-iotests/178.out.raw @@ -13,7 +13,7 @@ qemu-img: Invalid option list: , qemu-img: Invalid parameter 'snapshot.foo' qemu-img: Failed in parsing snapshot param 'snapshot.foo' qemu-img: --output must be used with human or json as argument. -qemu-img: Image size must be less than 8 EiB! +qemu-img: Invalid image size specified. Must be between 0 and 9223372036854775807. qemu-img: Unknown file format 'foo' == Size calculation for a new file (human) == From 5d72c68b49769c927e90b78af6d90f6a384b26ac Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 21 May 2020 14:21:34 -0500 Subject: [PATCH 0746/2595] qcow2: Expose bitmaps' size during measure It's useful to know how much space can be occupied by qcow2 persistent bitmaps, even though such metadata is unrelated to the guest-visible data. Report this value as an additional QMP field, present when measuring an existing image and output format that both support bitmaps. Update iotest 178 and 190 to updated output, as well as new coverage in 190 demonstrating non-zero values made possible with the recently-added qemu-img bitmap command (see 3b51ab4b). The new 'bitmaps size:' field is displayed automatically as part of 'qemu-img measure' any time it is present in QMP (that is, any time both the source image being measured and destination format support bitmaps, even if the measurement is 0 because there are no bitmaps present). If the field is absent, it means that no bitmaps can be copied (source, destination, or both lack bitmaps, including when measuring based on size rather than on a source image). This behavior is compatible with an upcoming patch adding 'qemu-img convert --bitmaps': that command will fail in the same situations where this patch omits the field. The addition of a new field demonstrates why we should always zero-initialize qapi C structs; while the qcow2 driver still fully populates all fields, the raw and crypto drivers had to be tweaked to avoid uninitialized data. Consideration was also given towards having a 'qemu-img measure --bitmaps' which errors out when bitmaps are not possible, and otherwise sums the bitmaps into the existing allocation totals rather than displaying as a separate field, as a potential convenience factor. But this was ultimately decided to be more complexity than necessary when the QMP interface was sufficient enough with bitmaps remaining a separate field. See also: https://bugzilla.redhat.com/1779904 Reported-by: Nir Soffer Signed-off-by: Eric Blake Message-Id: <20200521192137.1120211-3-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- block/crypto.c | 2 +- block/qcow2-bitmap.c | 36 ++++++++++++++++++++++++ block/qcow2.c | 14 ++++++++-- block/qcow2.h | 2 ++ block/raw-format.c | 2 +- docs/tools/qemu-img.rst | 7 +++++ qapi/block-core.json | 16 +++++++---- qemu-img.c | 3 ++ tests/qemu-iotests/178.out.qcow2 | 16 +++++++++++ tests/qemu-iotests/190 | 47 ++++++++++++++++++++++++++++++-- tests/qemu-iotests/190.out | 27 +++++++++++++++++- 11 files changed, 159 insertions(+), 13 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index b216e12c31..973b57b3eb 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -552,7 +552,7 @@ static BlockMeasureInfo *block_crypto_measure(QemuOpts *opts, * Unallocated blocks are still encrypted so allocation status makes no * difference to the file size. */ - info = g_new(BlockMeasureInfo, 1); + info = g_new0(BlockMeasureInfo, 1); info->fully_allocated = luks_payload_size + size; info->required = luks_payload_size + size; return info; diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 1cf6d2ab77..7bf12502da 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -1755,3 +1755,39 @@ bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs) return s->qcow_version >= 3; } + +/* + * Compute the space required for bitmaps in @bs. + * + * The computation is based as if copying to a new image with the + * given @cluster_size, which may differ from the cluster size in @bs. + */ +uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs, + uint32_t cluster_size) +{ + uint64_t bitmaps_size = 0; + BdrvDirtyBitmap *bm; + size_t bitmap_dir_size = 0; + + FOR_EACH_DIRTY_BITMAP(bs, bm) { + if (bdrv_dirty_bitmap_get_persistence(bm)) { + const char *name = bdrv_dirty_bitmap_name(bm); + uint32_t granularity = bdrv_dirty_bitmap_granularity(bm); + uint64_t bmbytes = + get_bitmap_bytes_needed(bdrv_dirty_bitmap_size(bm), + granularity); + uint64_t bmclusters = DIV_ROUND_UP(bmbytes, cluster_size); + + /* Assume the entire bitmap is allocated */ + bitmaps_size += bmclusters * cluster_size; + /* Also reserve space for the bitmap table entries */ + bitmaps_size += ROUND_UP(bmclusters * sizeof(uint64_t), + cluster_size); + /* And space for contribution to bitmap directory size */ + bitmap_dir_size += calc_dir_entry_size(strlen(name), 0); + } + } + bitmaps_size += ROUND_UP(bitmap_dir_size, cluster_size); + + return bitmaps_size; +} diff --git a/block/qcow2.c b/block/qcow2.c index dfab8d2f6c..0cd2e6757e 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -4953,16 +4953,24 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs, required = virtual_size; } - info = g_new(BlockMeasureInfo, 1); + info = g_new0(BlockMeasureInfo, 1); info->fully_allocated = qcow2_calc_prealloc_size(virtual_size, cluster_size, ctz32(refcount_bits)) + luks_payload_size; - /* Remove data clusters that are not required. This overestimates the + /* + * Remove data clusters that are not required. This overestimates the * required size because metadata needed for the fully allocated file is - * still counted. + * still counted. Show bitmaps only if both source and destination + * would support them. */ info->required = info->fully_allocated - virtual_size + required; + info->has_bitmaps = version >= 3 && in_bs && + bdrv_supports_persistent_dirty_bitmap(in_bs); + if (info->has_bitmaps) { + info->bitmaps = qcow2_get_persistent_dirty_bitmap_size(in_bs, + cluster_size); + } return info; err: diff --git a/block/qcow2.h b/block/qcow2.h index 402e8acb1c..7ce2c23bdb 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -783,6 +783,8 @@ int qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, Error **errp); bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs); +uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs, + uint32_t cluster_size); ssize_t coroutine_fn qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size, diff --git a/block/raw-format.c b/block/raw-format.c index 018441bddf..233d019ca3 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -359,7 +359,7 @@ static BlockMeasureInfo *raw_measure(QemuOpts *opts, BlockDriverState *in_bs, BDRV_SECTOR_SIZE); } - info = g_new(BlockMeasureInfo, 1); + info = g_new0(BlockMeasureInfo, 1); info->required = required; /* Unallocated sectors count towards the file size in raw images */ diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index 38d464ea3f..320cb52b9f 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -616,6 +616,7 @@ Command description: required size: 524288 fully allocated size: 1074069504 + bitmaps size: 0 The ``required size`` is the file size of the new image. It may be smaller than the virtual disk size if the image format supports compact representation. @@ -625,6 +626,12 @@ Command description: occupy with the exception of internal snapshots, dirty bitmaps, vmstate data, and other advanced image format features. + The ``bitmaps size`` is the additional size required in order to + copy bitmaps from a source image in addition to the guest-visible + data; the line is omitted if either source or destination lacks + bitmap support, or 0 if bitmaps are supported but there is nothing + to copy. + .. option:: snapshot [--object OBJECTDEF] [--image-opts] [-U] [-q] [-l | -a SNAPSHOT | -c SNAPSHOT | -d SNAPSHOT] FILENAME List, apply, create or delete snapshots in image *FILENAME*. diff --git a/qapi/block-core.json b/qapi/block-core.json index 6fbacddab2..0e1c6a59f2 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -636,18 +636,24 @@ # efficiently so file size may be smaller than virtual disk size. # # The values are upper bounds that are guaranteed to fit the new image file. -# Subsequent modification, such as internal snapshot or bitmap creation, may -# require additional space and is not covered here. +# Subsequent modification, such as internal snapshot or further bitmap +# creation, may require additional space and is not covered here. # -# @required: Size required for a new image file, in bytes. +# @required: Size required for a new image file, in bytes, when copying just +# allocated guest-visible contents. # # @fully-allocated: Image file size, in bytes, once data has been written -# to all sectors. +# to all sectors, when copying just guest-visible contents. +# +# @bitmaps: Additional size required if all the top-level bitmap metadata +# in the source image were to be copied to the destination, +# present only when source and destination both support +# persistent bitmaps. (since 5.1) # # Since: 2.10 ## { 'struct': 'BlockMeasureInfo', - 'data': {'required': 'int', 'fully-allocated': 'int'} } + 'data': {'required': 'int', 'fully-allocated': 'int', '*bitmaps': 'int'} } ## # @query-block: diff --git a/qemu-img.c b/qemu-img.c index 2d30682f12..b2311bd3f6 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -5302,6 +5302,9 @@ static int img_measure(int argc, char **argv) if (output_format == OFORMAT_HUMAN) { printf("required size: %" PRIu64 "\n", info->required); printf("fully allocated size: %" PRIu64 "\n", info->fully_allocated); + if (info->has_bitmaps) { + printf("bitmaps size: %" PRIu64 "\n", info->bitmaps); + } } else { dump_json_block_measure_info(info); } diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2 index 4b69524c80..c7997760fd 100644 --- a/tests/qemu-iotests/178.out.qcow2 +++ b/tests/qemu-iotests/178.out.qcow2 @@ -37,6 +37,7 @@ qemu-img: The image size is too large (try using a larger cluster size) Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0 required size: 196608 fully allocated size: 196608 +bitmaps size: 0 converted image file size in bytes: 196608 @@ -45,6 +46,7 @@ converted image file size in bytes: 196608 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 required size: 393216 fully allocated size: 1074135040 +bitmaps size: 0 wrote 512/512 bytes at offset 512 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 65536/65536 bytes at offset 65536 @@ -53,6 +55,7 @@ wrote 64512/64512 bytes at offset 134217728 63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) required size: 589824 fully allocated size: 1074135040 +bitmaps size: 0 converted image file size in bytes: 524288 @@ -60,6 +63,7 @@ converted image file size in bytes: 524288 required size: 524288 fully allocated size: 1074135040 +bitmaps size: 0 converted image file size in bytes: 458752 @@ -67,16 +71,19 @@ converted image file size in bytes: 458752 required size: 1074135040 fully allocated size: 1074135040 +bitmaps size: 0 == qcow2 input image and LUKS encryption == required size: 2686976 fully allocated size: 1076232192 +bitmaps size: 0 == qcow2 input image and preallocation (human) == required size: 1074135040 fully allocated size: 1074135040 +bitmaps size: 0 converted image file size in bytes: 1074135040 @@ -87,6 +94,7 @@ wrote 8388608/8388608 bytes at offset 0 8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) required size: 8716288 fully allocated size: 8716288 +bitmaps size: 0 converted image file size in bytes: 8716288 @@ -173,6 +181,7 @@ qemu-img: The image size is too large (try using a larger cluster size) Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0 { + "bitmaps": 0, "required": 196608, "fully-allocated": 196608 } @@ -183,6 +192,7 @@ converted image file size in bytes: 196608 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 { + "bitmaps": 0, "required": 393216, "fully-allocated": 1074135040 } @@ -193,6 +203,7 @@ wrote 65536/65536 bytes at offset 65536 wrote 64512/64512 bytes at offset 134217728 63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { + "bitmaps": 0, "required": 589824, "fully-allocated": 1074135040 } @@ -202,6 +213,7 @@ converted image file size in bytes: 524288 == qcow2 input image with internal snapshot (json) == { + "bitmaps": 0, "required": 524288, "fully-allocated": 1074135040 } @@ -211,6 +223,7 @@ converted image file size in bytes: 458752 == qcow2 input image and a backing file (json) == { + "bitmaps": 0, "required": 1074135040, "fully-allocated": 1074135040 } @@ -218,6 +231,7 @@ converted image file size in bytes: 458752 == qcow2 input image and LUKS encryption == { + "bitmaps": 0, "required": 2686976, "fully-allocated": 1076232192 } @@ -225,6 +239,7 @@ converted image file size in bytes: 458752 == qcow2 input image and preallocation (json) == { + "bitmaps": 0, "required": 1074135040, "fully-allocated": 1074135040 } @@ -237,6 +252,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608 wrote 8388608/8388608 bytes at offset 0 8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) { + "bitmaps": 0, "required": 8716288, "fully-allocated": 8716288 } diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190 index 6d41650438..fe630918e9 100755 --- a/tests/qemu-iotests/190 +++ b/tests/qemu-iotests/190 @@ -2,7 +2,7 @@ # # qemu-img measure sub-command tests on huge qcow2 files # -# Copyright (C) 2017 Red Hat, Inc. +# Copyright (C) 2017-2020 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 @@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file -echo "== Huge file ==" +echo "== Huge file without bitmaps ==" echo _make_test_img -o 'cluster_size=2M' 2T @@ -51,6 +51,49 @@ $QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG" $QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG" $QEMU_IMG measure -O qcow2 -o cluster_size=2M -f qcow2 "$TEST_IMG" +echo +echo "== Huge file with bitmaps ==" +echo + +$QEMU_IMG bitmap --add --granularity 512 -f qcow2 "$TEST_IMG" b1 +$QEMU_IMG bitmap --add -g 2M -f qcow2 "$TEST_IMG" b2 + +# No bitmap without a source +$QEMU_IMG measure -O qcow2 --size 10M +# No bitmap output, since raw does not support it +$QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG" +# No bitmap output, since no bitmaps on raw source. Munge required size, as +# some filesystems store the qcow2 file with less sparseness than others +$QEMU_IMG measure -O qcow2 -f raw "$TEST_IMG" | + sed '/^required size:/ s/[0-9][0-9]*/SIZE/' +# No bitmap output, since v2 does not support it +$QEMU_IMG measure -O qcow2 -o compat=0.10 -f qcow2 "$TEST_IMG" + +# Compute expected output: bitmap clusters + bitmap tables + bitmaps directory +echo +val2T=$((2*1024*1024*1024*1024)) +cluster=$((64*1024)) +b1clusters=$(( (val2T/512/8 + cluster - 1) / cluster )) +b2clusters=$(( (val2T/2/1024/1024/8 + cluster - 1) / cluster )) +echo expected bitmap $((b1clusters * cluster + + (b1clusters * 8 + cluster - 1) / cluster * cluster + + b2clusters * cluster + + (b2clusters * 8 + cluster - 1) / cluster * cluster + + cluster)) +$QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG" + +# Compute expected output: bitmap clusters + bitmap tables + bitmaps directory +echo +cluster=$((2*1024*1024)) +b1clusters=$(( (val2T/512/8 + cluster - 1) / cluster )) +b2clusters=$(( (val2T/2/1024/1024/8 + cluster - 1) / cluster )) +echo expected bitmap $((b1clusters * cluster + + (b1clusters * 8 + cluster - 1) / cluster * cluster + + b2clusters * cluster + + (b2clusters * 8 + cluster - 1) / cluster * cluster + + cluster)) +$QEMU_IMG measure --output=json -O qcow2 -o cluster_size=2M -f qcow2 "$TEST_IMG" + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/190.out b/tests/qemu-iotests/190.out index d001942002..ed9d8214eb 100644 --- a/tests/qemu-iotests/190.out +++ b/tests/qemu-iotests/190.out @@ -1,11 +1,36 @@ QA output created by 190 -== Huge file == +== Huge file without bitmaps == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2199023255552 required size: 2199023255552 fully allocated size: 2199023255552 required size: 335806464 fully allocated size: 2199359062016 +bitmaps size: 0 required size: 18874368 fully allocated size: 2199042129920 +bitmaps size: 0 + +== Huge file with bitmaps == + +required size: 327680 +fully allocated size: 10813440 +required size: 2199023255552 +fully allocated size: 2199023255552 +required size: SIZE +fully allocated size: 17170432 +required size: 335806464 +fully allocated size: 2199359062016 + +expected bitmap 537198592 +required size: 335806464 +fully allocated size: 2199359062016 +bitmaps size: 537198592 + +expected bitmap 545259520 +{ + "bitmaps": 545259520, + "required": 18874368, + "fully-allocated": 2199042129920 +} *** done From 6c729dd832207d7347ecb074912f538e2942f269 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 21 May 2020 14:21:35 -0500 Subject: [PATCH 0747/2595] qemu-img: Factor out code for merging bitmaps The next patch will add another client that wants to merge dirty bitmaps; it will be easier to refactor the code to construct the QAPI struct correctly into a helper function. Signed-off-by: Eric Blake Message-Id: <20200521192137.1120211-4-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- qemu-img.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index b2311bd3f6..0778d8f566 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1638,6 +1638,24 @@ out4: return ret; } +/* Convenience wrapper around qmp_block_dirty_bitmap_merge */ +static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_name, + const char *src_node, const char *src_name, + Error **errp) +{ + BlockDirtyBitmapMergeSource *merge_src; + BlockDirtyBitmapMergeSourceList *list; + + merge_src = g_new0(BlockDirtyBitmapMergeSource, 1); + merge_src->type = QTYPE_QDICT; + merge_src->u.external.node = g_strdup(src_node); + merge_src->u.external.name = g_strdup(src_name); + list = g_new0(BlockDirtyBitmapMergeSourceList, 1); + list->value = merge_src; + qmp_block_dirty_bitmap_merge(dst_node, dst_name, list, errp); + qapi_free_BlockDirtyBitmapMergeSourceList(list); +} + enum ImgConvertBlockStatus { BLK_DATA, BLK_ZERO, @@ -4714,21 +4732,11 @@ static int img_bitmap(int argc, char **argv) qmp_block_dirty_bitmap_disable(bs->node_name, bitmap, &err); op = "disable"; break; - case BITMAP_MERGE: { - BlockDirtyBitmapMergeSource *merge_src; - BlockDirtyBitmapMergeSourceList *list; - - merge_src = g_new0(BlockDirtyBitmapMergeSource, 1); - merge_src->type = QTYPE_QDICT; - merge_src->u.external.node = g_strdup(src_bs->node_name); - merge_src->u.external.name = g_strdup(act->src); - list = g_new0(BlockDirtyBitmapMergeSourceList, 1); - list->value = merge_src; - qmp_block_dirty_bitmap_merge(bs->node_name, bitmap, list, &err); - qapi_free_BlockDirtyBitmapMergeSourceList(list); + case BITMAP_MERGE: + do_dirty_bitmap_merge(bs->node_name, bitmap, src_bs->node_name, + act->src, &err); op = "merge"; break; - } default: g_assert_not_reached(); } From 15e39ad95078d528dfb9a75417453cab60332b77 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 21 May 2020 14:21:36 -0500 Subject: [PATCH 0748/2595] qemu-img: Add convert --bitmaps option Make it easier to copy all the persistent bitmaps of (the top layer of) a source image along with its guest-visible contents, by adding a boolean flag for use with qemu-img convert. This is basically shorthand, as the same effect could be accomplished with a series of 'qemu-img bitmap --add' and 'qemu-img bitmap --merge -b source' commands, or by their corresponding QMP commands. Note that this command will fail in the same scenarios where 'qemu-img measure' omits a 'bitmaps size:' line, namely, when either the source or the destination lacks persistent bitmap support altogether. See also https://bugzilla.redhat.com/show_bug.cgi?id=1779893 While touching this, clean up a couple coding issues spotted in the same function: an extra blank line, and merging back-to-back 'if (!skip_create)' blocks. Signed-off-by: Eric Blake Message-Id: <20200521192137.1120211-5-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- docs/tools/qemu-img.rst | 6 +++- qemu-img-cmds.hx | 4 +-- qemu-img.c | 70 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index 320cb52b9f..69cd9a3037 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -162,6 +162,10 @@ Parameters to convert subcommand: .. program:: qemu-img-convert +.. option:: --bitmaps + + Additionally copy all persistent bitmaps from the top layer of the source + .. option:: -n Skip the creation of the target volume @@ -397,7 +401,7 @@ Command description: 4 Error on reading data -.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME +.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM* to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index a87d3cb264..10b910b67c 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -46,9 +46,9 @@ SRST ERST DEF("convert", img_convert, - "convert [--object objectdef] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename") + "convert [--object objectdef] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename") SRST -.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME +.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME ERST DEF("create", img_create, diff --git a/qemu-img.c b/qemu-img.c index 0778d8f566..d7e846e607 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -78,6 +78,7 @@ enum { OPTION_ENABLE = 272, OPTION_DISABLE = 273, OPTION_MERGE = 274, + OPTION_BITMAPS = 275, }; typedef enum OutputFormat { @@ -191,6 +192,7 @@ static void QEMU_NORETURN help(void) " hiding corruption that has already occurred.\n" "\n" "Parameters to convert subcommand:\n" + " '--bitmaps' copies all top-level persistent bitmaps to destination\n" " '-m' specifies how many coroutines work in parallel during the convert\n" " process (defaults to 8)\n" " '-W' allow to write to the target out of order rather than sequential\n" @@ -2139,6 +2141,39 @@ static int convert_do_copy(ImgConvertState *s) return s->ret; } +static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst) +{ + BdrvDirtyBitmap *bm; + Error *err = NULL; + + FOR_EACH_DIRTY_BITMAP(src, bm) { + const char *name; + + if (!bdrv_dirty_bitmap_get_persistence(bm)) { + continue; + } + name = bdrv_dirty_bitmap_name(bm); + qmp_block_dirty_bitmap_add(dst->node_name, name, + true, bdrv_dirty_bitmap_granularity(bm), + true, true, + true, !bdrv_dirty_bitmap_enabled(bm), + &err); + if (err) { + error_reportf_err(err, "Failed to create bitmap %s: ", name); + return -1; + } + + do_dirty_bitmap_merge(dst->node_name, name, src->node_name, name, + &err); + if (err) { + error_reportf_err(err, "Failed to populate bitmap %s: ", name); + return -1; + } + } + + return 0; +} + #define MAX_BUF_SECTORS 32768 static int img_convert(int argc, char **argv) @@ -2160,6 +2195,7 @@ static int img_convert(int argc, char **argv) int64_t ret = -EINVAL; bool force_share = false; bool explict_min_sparse = false; + bool bitmaps = false; ImgConvertState s = (ImgConvertState) { /* Need at least 4k of zeros for sparse detection */ @@ -2179,6 +2215,7 @@ static int img_convert(int argc, char **argv) {"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS}, {"salvage", no_argument, 0, OPTION_SALVAGE}, {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO}, + {"bitmaps", no_argument, 0, OPTION_BITMAPS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU", @@ -2304,6 +2341,9 @@ static int img_convert(int argc, char **argv) */ s.has_zero_init = true; break; + case OPTION_BITMAPS: + bitmaps = true; + break; } } @@ -2365,7 +2405,6 @@ static int img_convert(int argc, char **argv) goto fail_getopt; } - /* ret is still -EINVAL until here */ ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough); if (ret < 0) { @@ -2525,6 +2564,20 @@ static int img_convert(int argc, char **argv) } } + /* Determine if bitmaps need copying */ + if (bitmaps) { + if (s.src_num > 1) { + error_report("Copying bitmaps only possible with single source"); + ret = -1; + goto out; + } + if (!bdrv_supports_persistent_dirty_bitmap(blk_bs(s.src[0]))) { + error_report("Source lacks bitmap support"); + ret = -1; + goto out; + } + } + /* * The later open call will need any decryption secrets, and * bdrv_create() will purge "opts", so extract them now before @@ -2533,9 +2586,7 @@ static int img_convert(int argc, char **argv) if (!skip_create) { open_opts = qdict_new(); qemu_opt_foreach(opts, img_add_key_secrets, open_opts, &error_abort); - } - if (!skip_create) { /* Create the new image */ ret = bdrv_create(drv, out_filename, opts, &local_err); if (ret < 0) { @@ -2573,6 +2624,13 @@ static int img_convert(int argc, char **argv) } out_bs = blk_bs(s.target); + if (bitmaps && !bdrv_supports_persistent_dirty_bitmap(out_bs)) { + error_report("Format driver '%s' does not support bitmaps", + out_bs->drv->format_name); + ret = -1; + goto out; + } + if (s.compressed && !block_driver_can_compress(out_bs->drv)) { error_report("Compression not supported for this file format"); ret = -1; @@ -2632,6 +2690,12 @@ static int img_convert(int argc, char **argv) } ret = convert_do_copy(&s); + + /* Now copy the bitmaps */ + if (bitmaps && ret == 0) { + ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs); + } + out: if (!ret) { qemu_progress_print(100, 0); From cf2d1203dcfc2bf964453d83a2302231ce77f2dc Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 21 May 2020 14:21:37 -0500 Subject: [PATCH 0749/2595] iotests: Add test 291 to for qemu-img bitmap coverage Add a new test covering the 'qemu-img bitmap' subcommand, as well as 'qemu-img convert --bitmaps', both added in recent patches. Signed-off-by: Eric Blake Reviewed-by: Max Reitz Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200521192137.1120211-6-eblake@redhat.com> --- tests/qemu-iotests/291 | 112 +++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/291.out | 80 ++++++++++++++++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 193 insertions(+) create mode 100755 tests/qemu-iotests/291 create mode 100644 tests/qemu-iotests/291.out diff --git a/tests/qemu-iotests/291 b/tests/qemu-iotests/291 new file mode 100755 index 0000000000..3ca83b9cd1 --- /dev/null +++ b/tests/qemu-iotests/291 @@ -0,0 +1,112 @@ +#!/usr/bin/env bash +# +# Test qemu-img bitmap handling +# +# Copyright (C) 2018-2020 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 . +# + +seq="$(basename $0)" +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + nbd_server_stop +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.nbd + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux +_require_command QEMU_NBD + +echo +echo "=== Initial image setup ===" +echo + +# Create backing image with one bitmap +TEST_IMG="$TEST_IMG.base" _make_test_img 10M +$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG.base" b0 +$QEMU_IO -c 'w 3M 1M' -f $IMGFMT "$TEST_IMG.base" | _filter_qemu_io + +# Create initial image and populate two bitmaps: one active, one inactive. +ORIG_IMG=$TEST_IMG +TEST_IMG=$TEST_IMG.orig +_make_test_img -b "$ORIG_IMG.base" -F $IMGFMT 10M +$QEMU_IO -c 'w 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io +$QEMU_IMG bitmap --add -g 512k -f $IMGFMT "$TEST_IMG" b1 +$QEMU_IMG bitmap --add --disable -f $IMGFMT "$TEST_IMG" b2 +$QEMU_IO -c 'w 3M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io +$QEMU_IMG bitmap --clear -f $IMGFMT "$TEST_IMG" b1 +$QEMU_IO -c 'w 1M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io +$QEMU_IMG bitmap --disable -f $IMGFMT "$TEST_IMG" b1 +$QEMU_IMG bitmap --enable -f $IMGFMT "$TEST_IMG" b2 +$QEMU_IO -c 'w 2M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io + +echo +echo "=== Bitmap preservation not possible to non-qcow2 ===" +echo + +TEST_IMG=$ORIG_IMG +$QEMU_IMG convert --bitmaps -O raw "$TEST_IMG.orig" "$TEST_IMG" && + echo "unexpected success" + +echo +echo "=== Convert with bitmap preservation ===" +echo + +# Only bitmaps from the active layer are copied +$QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG.orig" "$TEST_IMG" +$QEMU_IMG info "$TEST_IMG" | _filter_img_info --format-specific +# But we can also merge in bitmaps from other layers. This test is a bit +# contrived to cover more code paths, in reality, you could merge directly +# into b0 without going through tmp +$QEMU_IMG bitmap --add --disable -f $IMGFMT "$TEST_IMG" b0 +$QEMU_IMG bitmap --add --merge b0 -b "$TEST_IMG.base" -F $IMGFMT \ + -f $IMGFMT "$TEST_IMG" tmp +$QEMU_IMG bitmap --merge tmp -f $IMGFMT "$TEST_IMG" b0 +$QEMU_IMG bitmap --remove --image-opts \ + driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG" tmp +$QEMU_IMG info "$TEST_IMG" | _filter_img_info --format-specific + +echo +echo "=== Check bitmap contents ===" +echo + +# x-dirty-bitmap is a hack for reading bitmaps; it abuses block status to +# report "data":false for portions of the bitmap which are set +IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket" +nbd_server_start_unix_socket -r -f qcow2 -B b0 "$TEST_IMG" +$QEMU_IMG map --output=json --image-opts \ + "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b0" | _filter_qemu_img_map +nbd_server_start_unix_socket -r -f qcow2 -B b1 "$TEST_IMG" +$QEMU_IMG map --output=json --image-opts \ + "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b1" | _filter_qemu_img_map +nbd_server_start_unix_socket -r -f qcow2 -B b2 "$TEST_IMG" +$QEMU_IMG map --output=json --image-opts \ + "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map + +# success, all done +echo '*** done' +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out new file mode 100644 index 0000000000..8c62017567 --- /dev/null +++ b/tests/qemu-iotests/291.out @@ -0,0 +1,80 @@ +QA output created by 291 + +=== Initial image setup === + +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=10485760 +wrote 1048576/1048576 bytes at offset 3145728 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=10485760 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1048576/1048576 bytes at offset 3145728 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1048576/1048576 bytes at offset 2097152 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +=== Bitmap preservation not possible to non-qcow2 === + +qemu-img: Format driver 'raw' does not support bitmaps + +=== Convert with bitmap preservation === + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 10 MiB (10485760 bytes) +disk size: 4.39 MiB +Format specific information: + compat: 1.1 + compression type: zlib + lazy refcounts: false + bitmaps: + [0]: + flags: + name: b1 + granularity: 524288 + [1]: + flags: + [0]: auto + name: b2 + granularity: 65536 + refcount bits: 16 + corrupt: false +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 10 MiB (10485760 bytes) +disk size: 4.48 MiB +Format specific information: + compat: 1.1 + compression type: zlib + lazy refcounts: false + bitmaps: + [0]: + flags: + name: b1 + granularity: 524288 + [1]: + flags: + [0]: auto + name: b2 + granularity: 65536 + [2]: + flags: + name: b0 + granularity: 65536 + refcount bits: 16 + corrupt: false + +=== Check bitmap contents === + +[{ "start": 0, "length": 3145728, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 3145728, "length": 1048576, "depth": 0, "zero": false, "data": false}, +{ "start": 4194304, "length": 6291456, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": false}, +{ "start": 2097152, "length": 8388608, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 1048576, "depth": 0, "zero": false, "data": false}, +{ "start": 3145728, "length": 7340032, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 445c26f8d2..d886fa0cb3 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -299,5 +299,6 @@ 288 quick 289 rw quick 290 rw auto quick +291 rw quick 292 rw auto quick 297 meta From ccff1ae4df08ad79d055ad255fd578786f17a313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 11:40:51 +0200 Subject: [PATCH 0750/2595] hw/m68k/mcf5206: Reduce m5206_mbar_read/write() offset arg to 16-bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All calls to m5206_mbar_read/m5206_mbar_write are used with 'offset = hwaddr & 0x3ff', so we are sure the offset fits in 16-bit. Suggested-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200526094052.1723-2-f4bug@amsat.org> Signed-off-by: Thomas Huth --- hw/m68k/mcf5206.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c index b155dd8170..187291e1f6 100644 --- a/hw/m68k/mcf5206.c +++ b/hw/m68k/mcf5206.c @@ -273,7 +273,7 @@ static void m5206_mbar_reset(m5206_mbar_state *s) } static uint64_t m5206_mbar_read(m5206_mbar_state *s, - uint64_t offset, unsigned size) + uint16_t offset, unsigned size) { if (offset >= 0x100 && offset < 0x120) { return m5206_timer_read(s->timer[0], offset - 0x100); @@ -306,11 +306,11 @@ static uint64_t m5206_mbar_read(m5206_mbar_state *s, case 0x170: return s->uivr[0]; case 0x1b0: return s->uivr[1]; } - hw_error("Bad MBAR read offset 0x%x", (int)offset); + hw_error("Bad MBAR read offset 0x%"PRIx16, offset); return 0; } -static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, +static void m5206_mbar_write(m5206_mbar_state *s, uint16_t offset, uint64_t value, unsigned size) { if (offset >= 0x100 && offset < 0x120) { @@ -360,7 +360,7 @@ static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, s->uivr[1] = value; break; default: - hw_error("Bad MBAR write offset 0x%x", (int)offset); + hw_error("Bad MBAR write offset 0x%"PRIx16, offset); break; } } From b809667808b1f742a85d6cce0d77800be20bcaa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 11:40:52 +0200 Subject: [PATCH 0751/2595] hw/m68k/mcf52xx: Replace hw_error() by qemu_log_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw_error() calls exit(). This a bit overkill when we can log the accesses as unimplemented or guest error. When fuzzing the devices, we don't want the whole process to exit. Replace some hw_error() calls by qemu_log_mask(). Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200526094052.1723-3-f4bug@amsat.org> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- hw/m68k/mcf5206.c | 10 +++++++--- hw/m68k/mcf5208.c | 16 ++++++++++------ hw/m68k/mcf_intc.c | 10 +++++++--- hw/net/mcf_fec.c | 9 ++++++--- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c index 187291e1f6..a2fef04f8e 100644 --- a/hw/m68k/mcf5206.c +++ b/hw/m68k/mcf5206.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qemu/log.h" #include "cpu.h" #include "hw/hw.h" #include "hw/irq.h" @@ -225,7 +226,8 @@ static void m5206_mbar_update(m5206_mbar_state *s) break; default: /* Unknown vector. */ - error_report("Unhandled vector for IRQ %d", irq); + qemu_log_mask(LOG_UNIMP, "%s: Unhandled vector for IRQ %d\n", + __func__, irq); vector = 0xf; break; } @@ -306,7 +308,8 @@ static uint64_t m5206_mbar_read(m5206_mbar_state *s, case 0x170: return s->uivr[0]; case 0x1b0: return s->uivr[1]; } - hw_error("Bad MBAR read offset 0x%"PRIx16, offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad MBAR offset 0x%"PRIx16"\n", + __func__, offset); return 0; } @@ -360,7 +363,8 @@ static void m5206_mbar_write(m5206_mbar_state *s, uint16_t offset, s->uivr[1] = value; break; default: - hw_error("Bad MBAR write offset 0x%"PRIx16, offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad MBAR offset 0x%"PRIx16"\n", + __func__, offset); break; } } diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index b84c152ce3..2ab9701ad6 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -9,10 +9,10 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qemu/error-report.h" +#include "qemu/log.h" #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" -#include "hw/hw.h" #include "hw/irq.h" #include "hw/m68k/mcf.h" #include "hw/m68k/mcf_fec.h" @@ -111,8 +111,9 @@ static void m5208_timer_write(void *opaque, hwaddr offset, case 4: break; default: - hw_error("m5208_timer_write: Bad offset 0x%x\n", (int)offset); - break; + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, offset); + return; } m5208_timer_update(s); } @@ -136,7 +137,8 @@ static uint64_t m5208_timer_read(void *opaque, hwaddr addr, case 4: return ptimer_get_count(s->timer); default: - hw_error("m5208_timer_read: Bad offset 0x%x\n", (int)addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, addr); return 0; } } @@ -164,7 +166,8 @@ static uint64_t m5208_sys_read(void *opaque, hwaddr addr, return 0; default: - hw_error("m5208_sys_read: Bad offset 0x%x\n", (int)addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, addr); return 0; } } @@ -172,7 +175,8 @@ static uint64_t m5208_sys_read(void *opaque, hwaddr addr, static void m5208_sys_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - hw_error("m5208_sys_write: Bad offset 0x%x\n", (int)addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", + __func__, addr); } static const MemoryRegionOps m5208_sys_ops = { diff --git a/hw/m68k/mcf_intc.c b/hw/m68k/mcf_intc.c index d9e03a06ab..bc20742d9a 100644 --- a/hw/m68k/mcf_intc.c +++ b/hw/m68k/mcf_intc.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qemu/module.h" +#include "qemu/log.h" #include "cpu.h" #include "hw/hw.h" #include "hw/irq.h" @@ -80,7 +81,9 @@ static uint64_t mcf_intc_read(void *opaque, hwaddr addr, case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: /* LnIACK */ - hw_error("mcf_intc_read: LnIACK not implemented\n"); + qemu_log_mask(LOG_UNIMP, "%s: LnIACK not implemented (offset 0x%02x)\n", + __func__, offset); + /* fallthru */ default: return 0; } @@ -127,8 +130,9 @@ static void mcf_intc_write(void *opaque, hwaddr addr, } break; default: - hw_error("mcf_intc_write: Bad write offset %d\n", offset); - break; + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%02x\n", + __func__, offset); + return; } mcf_intc_update(s); } diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index 9327ac8a30..281345862c 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -7,7 +7,7 @@ */ #include "qemu/osdep.h" -#include "hw/hw.h" +#include "qemu/log.h" #include "hw/irq.h" #include "net/net.h" #include "qemu/module.h" @@ -392,7 +392,8 @@ static uint64_t mcf_fec_read(void *opaque, hwaddr addr, case 0x188: return s->emrbr; case 0x200 ... 0x2e0: return s->mib[(addr & 0x1ff) / 4]; default: - hw_error("mcf_fec_read: Bad address 0x%x\n", (int)addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address 0x%" HWADDR_PRIX "\n", + __func__, addr); return 0; } } @@ -492,7 +493,9 @@ static void mcf_fec_write(void *opaque, hwaddr addr, s->mib[(addr & 0x1ff) / 4] = value; break; default: - hw_error("mcf_fec_write Bad address 0x%x\n", (int)addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address 0x%" HWADDR_PRIX "\n", + __func__, addr); + return; } mcf_fec_update(s); } From 6acc5c046905183d38e2f44fb0fe69001939d969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 12 May 2020 12:32:33 +0200 Subject: [PATCH 0752/2595] scripts/qemugdb: Remove shebang header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These scripts are loaded as plugin by GDB (and they don't have any __main__ entry point). Remove the shebang header. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Alex Bennée Reviewed-by: John Snow Reviewed-by: Kevin Wolf Message-Id: <20200512103238.7078-2-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- scripts/qemugdb/__init__.py | 3 +-- scripts/qemugdb/aio.py | 3 +-- scripts/qemugdb/coroutine.py | 3 +-- scripts/qemugdb/mtree.py | 4 +--- scripts/qemugdb/tcg.py | 1 - scripts/qemugdb/timers.py | 1 - 6 files changed, 4 insertions(+), 11 deletions(-) diff --git a/scripts/qemugdb/__init__.py b/scripts/qemugdb/__init__.py index 969f552b26..da8ff612e5 100644 --- a/scripts/qemugdb/__init__.py +++ b/scripts/qemugdb/__init__.py @@ -1,5 +1,4 @@ -#!/usr/bin/python - +# # GDB debugging support # # Copyright (c) 2015 Linaro Ltd diff --git a/scripts/qemugdb/aio.py b/scripts/qemugdb/aio.py index 2ba00c4444..d7c1ba0c28 100644 --- a/scripts/qemugdb/aio.py +++ b/scripts/qemugdb/aio.py @@ -1,5 +1,4 @@ -#!/usr/bin/python - +# # GDB debugging support: aio/iohandler debug # # Copyright (c) 2015 Red Hat, Inc. diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py index 41e079d0e2..db61389022 100644 --- a/scripts/qemugdb/coroutine.py +++ b/scripts/qemugdb/coroutine.py @@ -1,5 +1,4 @@ -#!/usr/bin/python - +# # GDB debugging support # # Copyright 2012 Red Hat, Inc. and/or its affiliates diff --git a/scripts/qemugdb/mtree.py b/scripts/qemugdb/mtree.py index 3030a60d3f..8fe42c3c12 100644 --- a/scripts/qemugdb/mtree.py +++ b/scripts/qemugdb/mtree.py @@ -1,5 +1,4 @@ -#!/usr/bin/python - +# # GDB debugging support # # Copyright 2012 Red Hat, Inc. and/or its affiliates @@ -84,4 +83,3 @@ class MtreeCommand(gdb.Command): while not isnull(subregion): self.print_item(subregion, addr, level) subregion = subregion['subregions_link']['tqe_next'] - diff --git a/scripts/qemugdb/tcg.py b/scripts/qemugdb/tcg.py index 18880fc9a7..16c03c06a9 100644 --- a/scripts/qemugdb/tcg.py +++ b/scripts/qemugdb/tcg.py @@ -1,4 +1,3 @@ -#!/usr/bin/python # -*- coding: utf-8 -*- # # GDB debugging support, TCG status diff --git a/scripts/qemugdb/timers.py b/scripts/qemugdb/timers.py index f0e132d27a..46537b27cf 100644 --- a/scripts/qemugdb/timers.py +++ b/scripts/qemugdb/timers.py @@ -1,4 +1,3 @@ -#!/usr/bin/python # -*- coding: utf-8 -*- # GDB debugging support # From 806c200ef47db61078320b58e4aafaaa5a5cdecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 12 May 2020 12:32:34 +0200 Subject: [PATCH 0753/2595] scripts/qemu-gdb: Use Python 3 interpreter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: John Snow Reviewed-by: Kevin Wolf Message-Id: <20200512103238.7078-3-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- scripts/qemu-gdb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/qemu-gdb.py b/scripts/qemu-gdb.py index f2a305c42e..e0bfa7b5a4 100644 --- a/scripts/qemu-gdb.py +++ b/scripts/qemu-gdb.py @@ -1,5 +1,5 @@ -#!/usr/bin/python - +#!/usr/bin/env python3 +# # GDB debugging support # # Copyright 2012 Red Hat, Inc. and/or its affiliates From 06d4c71f4869386abf97f45f61c21e9dc449943f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 12 May 2020 12:32:35 +0200 Subject: [PATCH 0754/2595] scripts/qmp: Use Python 3 interpreter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: John Snow Reviewed-by: Kevin Wolf Message-Id: <20200512103238.7078-4-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- scripts/qmp/qom-get | 2 +- scripts/qmp/qom-list | 2 +- scripts/qmp/qom-set | 2 +- scripts/qmp/qom-tree | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/qmp/qom-get b/scripts/qmp/qom-get index 007b4cd442..7c5ede91bb 100755 --- a/scripts/qmp/qom-get +++ b/scripts/qmp/qom-get @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 ## # QEMU Object Model test tools # diff --git a/scripts/qmp/qom-list b/scripts/qmp/qom-list index 03bda3446b..bb68fd65d4 100755 --- a/scripts/qmp/qom-list +++ b/scripts/qmp/qom-list @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 ## # QEMU Object Model test tools # diff --git a/scripts/qmp/qom-set b/scripts/qmp/qom-set index c37fe78b00..19881d85e9 100755 --- a/scripts/qmp/qom-set +++ b/scripts/qmp/qom-set @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 ## # QEMU Object Model test tools # diff --git a/scripts/qmp/qom-tree b/scripts/qmp/qom-tree index 1c8acf61e7..fa91147a03 100755 --- a/scripts/qmp/qom-tree +++ b/scripts/qmp/qom-tree @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 ## # QEMU Object Model test tools # From e57a707a82a0ddc07615e048ef72cf8553c3a4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 12 May 2020 12:32:36 +0200 Subject: [PATCH 0755/2595] scripts/kvm/vmxcap: Use Python 3 interpreter and add pseudo-main() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Acked-by: Paolo Bonzini Reviewed-by: John Snow Reviewed-by: Kevin Wolf Message-Id: <20200512103238.7078-5-philmd@redhat.com> --- scripts/kvm/vmxcap | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap index 971ed0e721..6fe66d5f57 100755 --- a/scripts/kvm/vmxcap +++ b/scripts/kvm/vmxcap @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # tool for querying VMX capabilities # @@ -275,5 +275,6 @@ controls = [ ), ] -for c in controls: - c.show() +if __name__ == '__main__': + for c in controls: + c.show() From 5aa628045d4cf1c258c92ce7e525bb8d4b2e072d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 12 May 2020 12:32:37 +0200 Subject: [PATCH 0756/2595] scripts/modules/module_block: Use Python 3 interpreter & add pseudo-main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: John Snow Reviewed-by: Kevin Wolf Message-Id: <20200512103238.7078-6-philmd@redhat.com> --- scripts/modules/module_block.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/scripts/modules/module_block.py b/scripts/modules/module_block.py index f23191fac1..1109df827d 100644 --- a/scripts/modules/module_block.py +++ b/scripts/modules/module_block.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Module information generator # @@ -80,19 +80,20 @@ def print_bottom(fheader): #endif ''') -# First argument: output file -# All other arguments: modules source files (.c) -output_file = sys.argv[1] -with open(output_file, 'w') as fheader: - print_top(fheader) +if __name__ == '__main__': + # First argument: output file + # All other arguments: modules source files (.c) + output_file = sys.argv[1] + with open(output_file, 'w') as fheader: + print_top(fheader) - for filename in sys.argv[2:]: - if os.path.isfile(filename): - process_file(fheader, filename) - else: - print("File " + filename + " does not exist.", file=sys.stderr) - sys.exit(1) + for filename in sys.argv[2:]: + if os.path.isfile(filename): + process_file(fheader, filename) + else: + print("File " + filename + " does not exist.", file=sys.stderr) + sys.exit(1) - print_bottom(fheader) + print_bottom(fheader) -sys.exit(0) + sys.exit(0) From c7b942d7f84ef54f266921bf7668d43f1f2c7c79 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 28 May 2020 18:21:26 -0400 Subject: [PATCH 0757/2595] scripts/qmp: Fix shebang and imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's more wrong with these scripts; They are in various stages of disrepair. That's beyond the scope of this current patchset. This just mechanically corrects the imports and the shebangs, as part of ensuring that the python/qemu/lib refactoring didn't break anything needlessly. Signed-off-by: John Snow Message-Id: <20200528222129.23826-2-jsnow@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- scripts/qmp/qmp | 4 +++- scripts/qmp/qom-fuse | 4 +++- scripts/qmp/qom-get | 4 +++- scripts/qmp/qom-list | 4 +++- scripts/qmp/qom-set | 4 +++- scripts/qmp/qom-tree | 4 +++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/scripts/qmp/qmp b/scripts/qmp/qmp index 0625fc2aba..8e52e4a54d 100755 --- a/scripts/qmp/qmp +++ b/scripts/qmp/qmp @@ -11,7 +11,9 @@ # See the COPYING file in the top-level directory. import sys, os -from qmp import QEMUMonitorProtocol + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) +from qemu.qmp import QEMUMonitorProtocol def print_response(rsp, prefix=[]): if type(rsp) == list: diff --git a/scripts/qmp/qom-fuse b/scripts/qmp/qom-fuse index 6bada2c33d..5fa6b3bf64 100755 --- a/scripts/qmp/qom-fuse +++ b/scripts/qmp/qom-fuse @@ -15,7 +15,9 @@ import fuse, stat from fuse import Fuse import os, posix from errno import * -from qmp import QEMUMonitorProtocol + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) +from qemu.qmp import QEMUMonitorProtocol fuse.fuse_python_api = (0, 2) diff --git a/scripts/qmp/qom-get b/scripts/qmp/qom-get index 7c5ede91bb..666df71832 100755 --- a/scripts/qmp/qom-get +++ b/scripts/qmp/qom-get @@ -13,7 +13,9 @@ import sys import os -from qmp import QEMUMonitorProtocol + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) +from qemu.qmp import QEMUMonitorProtocol cmd, args = sys.argv[0], sys.argv[1:] socket_path = None diff --git a/scripts/qmp/qom-list b/scripts/qmp/qom-list index bb68fd65d4..5074fd939f 100755 --- a/scripts/qmp/qom-list +++ b/scripts/qmp/qom-list @@ -13,7 +13,9 @@ import sys import os -from qmp import QEMUMonitorProtocol + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) +from qemu.qmp import QEMUMonitorProtocol cmd, args = sys.argv[0], sys.argv[1:] socket_path = None diff --git a/scripts/qmp/qom-set b/scripts/qmp/qom-set index 19881d85e9..240a78187f 100755 --- a/scripts/qmp/qom-set +++ b/scripts/qmp/qom-set @@ -13,7 +13,9 @@ import sys import os -from qmp import QEMUMonitorProtocol + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) +from qemu.qmp import QEMUMonitorProtocol cmd, args = sys.argv[0], sys.argv[1:] socket_path = None diff --git a/scripts/qmp/qom-tree b/scripts/qmp/qom-tree index fa91147a03..25b0781323 100755 --- a/scripts/qmp/qom-tree +++ b/scripts/qmp/qom-tree @@ -15,7 +15,9 @@ import sys import os -from qmp import QEMUMonitorProtocol + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) +from qemu.qmp import QEMUMonitorProtocol cmd, args = sys.argv[0], sys.argv[1:] socket_path = None From 2d110c11497ac52d5ce9f4b116463cdb8c3f4ad5 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 13 May 2020 23:52:30 -0400 Subject: [PATCH 0758/2595] python: remove more instances of sys.version_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We guarantee 3.5+ everywhere; remove more dead checks. In general, try to avoid using version checks and instead prefer to attempt behavior when possible. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200514035230.25756-1-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- scripts/analyze-migration.py | 5 ----- scripts/decodetree.py | 25 +++++++++--------------- scripts/qmp/qmp-shell | 3 --- tests/docker/docker.py | 5 +++-- tests/qemu-iotests/nbd-fault-injector.py | 5 +---- 5 files changed, 13 insertions(+), 30 deletions(-) diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index 96a31d3974..95838cbff3 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -25,11 +25,6 @@ import struct import sys -MIN_PYTHON = (3, 2) -if sys.version_info < MIN_PYTHON: - sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON) - - def mkdir_p(path): try: os.makedirs(path) diff --git a/scripts/decodetree.py b/scripts/decodetree.py index 46ab917807..f9d204aa36 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -75,13 +75,6 @@ def output(*args): output_fd.write(a) -if sys.version_info >= (3, 4): - re_fullmatch = re.fullmatch -else: - def re_fullmatch(pat, str): - return re.match('^' + pat + '$', str) - - def output_autogen(): output('/* This file is autogenerated by scripts/decodetree.py. */\n\n') @@ -428,18 +421,18 @@ def parse_field(lineno, name, toks): width = 0 func = None for t in toks: - if re_fullmatch('!function=' + re_ident, t): + if re.fullmatch('!function=' + re_ident, t): if func: error(lineno, 'duplicate function') func = t.split('=') func = func[1] continue - if re_fullmatch('[0-9]+:s[0-9]+', t): + if re.fullmatch('[0-9]+:s[0-9]+', t): # Signed field extract subtoks = t.split(':s') sign = True - elif re_fullmatch('[0-9]+:[0-9]+', t): + elif re.fullmatch('[0-9]+:[0-9]+', t): # Unsigned field extract subtoks = t.split(':') sign = False @@ -488,11 +481,11 @@ def parse_arguments(lineno, name, toks): flds = [] extern = False for t in toks: - if re_fullmatch('!extern', t): + if re.fullmatch('!extern', t): extern = True anyextern = True continue - if not re_fullmatch(re_ident, t): + if not re.fullmatch(re_ident, t): error(lineno, 'invalid argument set token "{0}"'.format(t)) if t in flds: error(lineno, 'duplicate argument "{0}"'.format(t)) @@ -621,13 +614,13 @@ def parse_generic(lineno, is_format, name, toks): continue # 'Foo=%Bar' imports a field with a different name. - if re_fullmatch(re_ident + '=%' + re_ident, t): + if re.fullmatch(re_ident + '=%' + re_ident, t): (fname, iname) = t.split('=%') flds = add_field_byname(lineno, flds, fname, iname) continue # 'Foo=number' sets an argument field to a constant value - if re_fullmatch(re_ident + '=[+-]?[0-9]+', t): + if re.fullmatch(re_ident + '=[+-]?[0-9]+', t): (fname, value) = t.split('=') value = int(value) flds = add_field(lineno, flds, fname, ConstField(value)) @@ -635,7 +628,7 @@ def parse_generic(lineno, is_format, name, toks): # Pattern of 0s, 1s, dots and dashes indicate required zeros, # required ones, or dont-cares. - if re_fullmatch('[01.-]+', t): + if re.fullmatch('[01.-]+', t): shift = len(t) fms = t.replace('0', '1') fms = fms.replace('.', '0') @@ -652,7 +645,7 @@ def parse_generic(lineno, is_format, name, toks): fixedmask = (fixedmask << shift) | fms undefmask = (undefmask << shift) | ubm # Otherwise, fieldname:fieldwidth - elif re_fullmatch(re_ident + ':s?[0-9]+', t): + elif re.fullmatch(re_ident + ':s?[0-9]+', t): (fname, flen) = t.split(':') sign = False if flen[0] == 's': diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell index a01d31de1e..c5eef06f3f 100755 --- a/scripts/qmp/qmp-shell +++ b/scripts/qmp/qmp-shell @@ -77,9 +77,6 @@ import re sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu import qmp -if sys.version_info[0] == 2: - input = raw_input - class QMPCompleter(list): def complete(self, text, state): for cmd in self: diff --git a/tests/docker/docker.py b/tests/docker/docker.py index d8268c1111..5a9735db78 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -258,12 +258,13 @@ class Docker(object): return self._do_kill_instances(True) def _output(self, cmd, **kwargs): - if sys.version_info[1] >= 6: + try: return subprocess.check_output(self._command + cmd, stderr=subprocess.STDOUT, encoding='utf-8', **kwargs) - else: + except TypeError: + # 'encoding' argument was added in 3.6+ return subprocess.check_output(self._command + cmd, stderr=subprocess.STDOUT, **kwargs).decode('utf-8') diff --git a/tests/qemu-iotests/nbd-fault-injector.py b/tests/qemu-iotests/nbd-fault-injector.py index 588d62aebf..78f42c4214 100755 --- a/tests/qemu-iotests/nbd-fault-injector.py +++ b/tests/qemu-iotests/nbd-fault-injector.py @@ -47,10 +47,7 @@ import sys import socket import struct import collections -if sys.version_info.major >= 3: - import configparser -else: - import ConfigParser as configparser +import configparser FAKE_DISK_SIZE = 8 * 1024 * 1024 * 1024 # 8 GB From e0e925a61141552bca7277d06516ad78258423da Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 17 Feb 2020 18:02:42 +0300 Subject: [PATCH 0759/2595] python/qemu/machine: add kill() method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add method to hard-kill vm, without any quit commands. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200217150246.29180-19-vsementsov@virtuozzo.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index b9a98e2c86..d2f531f1b4 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -342,7 +342,7 @@ class QEMUMachine(object): self._load_io_log() self._post_shutdown() - def shutdown(self, has_quit=False): + def shutdown(self, has_quit=False, hard=False): """ Terminate the VM and clean up """ @@ -354,7 +354,9 @@ class QEMUMachine(object): self._console_socket = None if self.is_running(): - if self._qmp: + if hard: + self._popen.kill() + elif self._qmp: try: if not has_quit: self._qmp.cmd('quit') @@ -368,7 +370,8 @@ class QEMUMachine(object): self._post_shutdown() exitcode = self.exitcode() - if exitcode is not None and exitcode < 0: + if exitcode is not None and exitcode < 0 and \ + not (exitcode == -9 and hard): msg = 'qemu received signal %i: %s' if self._qemu_full_args: command = ' '.join(self._qemu_full_args) @@ -378,6 +381,9 @@ class QEMUMachine(object): self._launched = False + def kill(self): + self.shutdown(hard=True) + def set_qmp_monitor(self, enabled=True): """ Set the QMP monitor. From 053774bdecf60c0500d66a05e02e48ff24ab23cf Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 14 May 2020 01:53:52 -0400 Subject: [PATCH 0760/2595] python/qemu/machine: remove logging configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Python 3.5 and above do not print a warning when logging is not configured. As a library, it's best practice to leave logging configuration to the client executable. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200514055403.18902-22-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index d2f531f1b4..41554de533 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -119,9 +119,6 @@ class QEMUMachine(object): self._console_socket = None self._remove_files = [] - # just in case logging wasn't configured by the main script: - logging.basicConfig() - def __enter__(self): return self From 9b8ccd6d5b81f10436764bf7e334e087f3918d12 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 28 May 2020 18:21:28 -0400 Subject: [PATCH 0761/2595] python/qemu: delint and add pylintrc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bring our these files up to speed with pylint 2.5.0. Add a pylintrc file to formalize which pylint subset we are targeting. The similarity ignore is there to suppress similarity reports across imports, which for typing constants, are going to trigger this report erroneously. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200528222129.23826-4-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 6 ++--- python/qemu/pylintrc | 58 ++++++++++++++++++++++++++++++++++++++++++ python/qemu/qtest.py | 42 +++++++++++++++++++----------- 3 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 python/qemu/pylintrc diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 41554de533..8e4ecd1837 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -58,7 +58,7 @@ class MonitorResponseError(qmp.QMPError): self.reply = reply -class QEMUMachine(object): +class QEMUMachine: """ A QEMU VM @@ -239,7 +239,7 @@ class QEMUMachine(object): 'chardev=mon,mode=control']) if self._machine is not None: args.extend(['-machine', self._machine]) - for i in range(self._console_index): + for _ in range(self._console_index): args.extend(['-serial', 'null']) if self._console_set: self._console_address = os.path.join(self._sock_dir, @@ -374,7 +374,7 @@ class QEMUMachine(object): command = ' '.join(self._qemu_full_args) else: command = '' - LOG.warning(msg, -exitcode, command) + LOG.warning(msg, -int(exitcode), command) self._launched = False diff --git a/python/qemu/pylintrc b/python/qemu/pylintrc new file mode 100644 index 0000000000..5d6ae7367d --- /dev/null +++ b/python/qemu/pylintrc @@ -0,0 +1,58 @@ +[MASTER] + +[MESSAGES CONTROL] + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=too-many-arguments, + too-many-instance-attributes, + too-many-public-methods, + +[REPORTS] + +[REFACTORING] + +[MISCELLANEOUS] + +[LOGGING] + +[BASIC] + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + ex, + Run, + _, + fd, + +[VARIABLES] + +[STRING] + +[SPELLING] + +[FORMAT] + +[SIMILARITIES] + +# Ignore imports when computing similarities. +ignore-imports=yes + +[TYPECHECK] + +[CLASSES] + +[IMPORTS] + +[DESIGN] + +[EXCEPTIONS] diff --git a/python/qemu/qtest.py b/python/qemu/qtest.py index d24ad04256..53d814c064 100644 --- a/python/qemu/qtest.py +++ b/python/qemu/qtest.py @@ -1,5 +1,11 @@ -# QEMU qtest library -# +""" +QEMU qtest library + +qtest offers the QEMUQtestProtocol and QEMUQTestMachine classes, which +offer a connection to QEMU's qtest protocol socket, and a qtest-enabled +subclass of QEMUMachine, respectively. +""" + # Copyright (C) 2015 Red Hat Inc. # # Authors: @@ -17,19 +23,21 @@ import os from .machine import QEMUMachine -class QEMUQtestProtocol(object): - def __init__(self, address, server=False): - """ - Create a QEMUQtestProtocol object. +class QEMUQtestProtocol: + """ + QEMUQtestProtocol implements a connection to a qtest socket. - @param address: QEMU address, can be either a unix socket path (string) - or a tuple in the form ( address, port ) for a TCP - connection - @param server: server mode, listens on the socket (bool) - @raise socket.error on socket connection errors - @note No connection is established, this is done by the connect() or - accept() methods - """ + :param address: QEMU address, can be either a unix socket path (string) + or a tuple in the form ( address, port ) for a TCP + connection + :param server: server mode, listens on the socket (bool) + :raise socket.error: on socket connection errors + + .. note:: + No conection is estabalished by __init__(), this is done + by the connect() or accept() methods. + """ + def __init__(self, address, server=False): self._address = address self._sock = self._get_sock() self._sockfile = None @@ -73,15 +81,19 @@ class QEMUQtestProtocol(object): return resp def close(self): + """Close this socket.""" self._sock.close() self._sockfile.close() def settimeout(self, timeout): + """Set a timeout, in seconds.""" self._sock.settimeout(timeout) class QEMUQtestMachine(QEMUMachine): - '''A QEMU VM''' + """ + A QEMU VM, with a qtest socket available. + """ def __init__(self, binary, args=None, name=None, test_dir="/var/tmp", socket_scm_helper=None, sock_dir=None): From 8dfac2edb2146d87b25543c70e25723f3d4dbd60 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 28 May 2020 18:21:29 -0400 Subject: [PATCH 0762/2595] python/qemu: delint; add flake8 config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mostly, ignore the "no bare except" rule, because flake8 is not contextual and cannot determine if we re-raise. Pylint can, though, so always prefer pylint for that. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200528222129.23826-5-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/.flake8 | 2 ++ python/qemu/accel.py | 9 ++++++--- python/qemu/machine.py | 13 +++++++++---- python/qemu/qmp.py | 4 ++-- 4 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 python/qemu/.flake8 diff --git a/python/qemu/.flake8 b/python/qemu/.flake8 new file mode 100644 index 0000000000..45d8146f3f --- /dev/null +++ b/python/qemu/.flake8 @@ -0,0 +1,2 @@ +[flake8] +extend-ignore = E722 # Pylint handles this, but smarter. \ No newline at end of file diff --git a/python/qemu/accel.py b/python/qemu/accel.py index 36ae85791e..7fabe62920 100644 --- a/python/qemu/accel.py +++ b/python/qemu/accel.py @@ -23,11 +23,12 @@ LOG = logging.getLogger(__name__) # Mapping host architecture to any additional architectures it can # support which often includes its 32 bit cousin. ADDITIONAL_ARCHES = { - "x86_64" : "i386", - "aarch64" : "armhf", - "ppc64le" : "ppc64", + "x86_64": "i386", + "aarch64": "armhf", + "ppc64le": "ppc64", } + def list_accel(qemu_bin): """ List accelerators enabled in the QEMU binary. @@ -47,6 +48,7 @@ def list_accel(qemu_bin): # Skip the first line which is the header. return [acc.strip() for acc in out.splitlines()[1:]] + def kvm_available(target_arch=None, qemu_bin=None): """ Check if KVM is available using the following heuristic: @@ -69,6 +71,7 @@ def kvm_available(target_arch=None, qemu_bin=None): return False return True + def tcg_available(qemu_bin): """ Check if TCG is available. diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 8e4ecd1837..187790ce9e 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -29,6 +29,7 @@ from . import qmp LOG = logging.getLogger(__name__) + class QEMUMachineError(Exception): """ Exception called when an error in QEMUMachine happens. @@ -62,7 +63,8 @@ class QEMUMachine: """ A QEMU VM - Use this object as a context manager to ensure the QEMU process terminates:: + Use this object as a context manager to ensure + the QEMU process terminates:: with VM(binary) as vm: ... @@ -185,8 +187,10 @@ class QEMUMachine: fd_param.append(str(fd)) devnull = open(os.path.devnull, 'rb') - proc = subprocess.Popen(fd_param, stdin=devnull, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, close_fds=False) + proc = subprocess.Popen( + fd_param, stdin=devnull, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, close_fds=False + ) output = proc.communicate()[0] if output: LOG.debug(output) @@ -485,7 +489,8 @@ class QEMUMachine: def events_wait(self, events, timeout=60.0): """ - events_wait waits for and returns a named event from QMP with a timeout. + events_wait waits for and returns a named event + from QMP with a timeout. events: a sequence of (name, match_criteria) tuples. The match criteria are optional and may be None. diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index d6c9b2f4b1..6ae7693965 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -168,8 +168,8 @@ class QEMUMonitorProtocol: @param timeout: timeout in seconds (nonnegative float number, or None). The value passed will set the behavior of the - underneath QMP socket as described in [1]. Default value - is set to 15.0. + underneath QMP socket as described in [1]. + Default value is set to 15.0. @return QMP greeting dict @raise OSError on socket connection errors @raise QMPConnectError if the greeting is not received From 3797dbcbb7bf1dffdd74ef84b5b21ed9c825e171 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 14 May 2020 01:53:42 -0400 Subject: [PATCH 0763/2595] python/qemu: remove Python2 style super() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the Python3 style instead. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200514055403.18902-12-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 2 +- python/qemu/qtest.py | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 187790ce9e..95a20a17f9 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -55,7 +55,7 @@ class MonitorResponseError(qmp.QMPError): desc = reply["error"]["desc"] except KeyError: desc = reply - super(MonitorResponseError, self).__init__(desc) + super().__init__(desc) self.reply = reply diff --git a/python/qemu/qtest.py b/python/qemu/qtest.py index 53d814c064..7943487c2b 100644 --- a/python/qemu/qtest.py +++ b/python/qemu/qtest.py @@ -101,29 +101,28 @@ class QEMUQtestMachine(QEMUMachine): name = "qemu-%d" % os.getpid() if sock_dir is None: sock_dir = test_dir - super(QEMUQtestMachine, - self).__init__(binary, args, name=name, test_dir=test_dir, - socket_scm_helper=socket_scm_helper, - sock_dir=sock_dir) + super().__init__(binary, args, name=name, test_dir=test_dir, + socket_scm_helper=socket_scm_helper, + sock_dir=sock_dir) self._qtest = None self._qtest_path = os.path.join(sock_dir, name + "-qtest.sock") def _base_args(self): - args = super(QEMUQtestMachine, self)._base_args() + args = super()._base_args() args.extend(['-qtest', 'unix:path=' + self._qtest_path, '-accel', 'qtest']) return args def _pre_launch(self): - super(QEMUQtestMachine, self)._pre_launch() + super()._pre_launch() self._qtest = QEMUQtestProtocol(self._qtest_path, server=True) def _post_launch(self): - super(QEMUQtestMachine, self)._post_launch() + super()._post_launch() self._qtest.accept() def _post_shutdown(self): - super(QEMUQtestMachine, self)._post_shutdown() + super()._post_shutdown() self._remove_if_exists(self._qtest_path) def qtest(self, cmd): From 0add048fbd9992151e4c592977df9cff8558ca60 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 14 May 2020 01:53:43 -0400 Subject: [PATCH 0764/2595] python/qemu: fix socket.makefile() typing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: A bug in typeshed (https://github.com/python/typeshed/issues/3977) misinterprets the type of makefile(). Work around this by explicitly stating that we are opening a text-mode file. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200514055403.18902-13-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/qmp.py | 10 +++++++--- python/qemu/qtest.py | 12 ++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index 6ae7693965..73d49050ed 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -11,6 +11,10 @@ import json import errno import socket import logging +from typing import ( + Optional, + TextIO, +) class QMPError(Exception): @@ -61,7 +65,7 @@ class QEMUMonitorProtocol: self.__events = [] self.__address = address self.__sock = self.__get_sock() - self.__sockfile = None + self.__sockfile: Optional[TextIO] = None self._nickname = nickname if self._nickname: self.logger = logging.getLogger('QMP').getChild(self._nickname) @@ -157,7 +161,7 @@ class QEMUMonitorProtocol: @raise QMPCapabilitiesError if fails to negotiate capabilities """ self.__sock.connect(self.__address) - self.__sockfile = self.__sock.makefile() + self.__sockfile = self.__sock.makefile(mode='r') if negotiate: return self.__negotiate_capabilities() return None @@ -180,7 +184,7 @@ class QEMUMonitorProtocol: """ self.__sock.settimeout(timeout) self.__sock, _ = self.__sock.accept() - self.__sockfile = self.__sock.makefile() + self.__sockfile = self.__sock.makefile(mode='r') return self.__negotiate_capabilities() def cmd_obj(self, qmp_cmd): diff --git a/python/qemu/qtest.py b/python/qemu/qtest.py index 7943487c2b..4c88590eb0 100644 --- a/python/qemu/qtest.py +++ b/python/qemu/qtest.py @@ -19,6 +19,7 @@ subclass of QEMUMachine, respectively. import socket import os +from typing import Optional, TextIO from .machine import QEMUMachine @@ -40,7 +41,7 @@ class QEMUQtestProtocol: def __init__(self, address, server=False): self._address = address self._sock = self._get_sock() - self._sockfile = None + self._sockfile: Optional[TextIO] = None if server: self._sock.bind(self._address) self._sock.listen(1) @@ -59,7 +60,7 @@ class QEMUQtestProtocol: @raise socket.error on socket connection errors """ self._sock.connect(self._address) - self._sockfile = self._sock.makefile() + self._sockfile = self._sock.makefile(mode='r') def accept(self): """ @@ -68,7 +69,7 @@ class QEMUQtestProtocol: @raise socket.error on socket connection errors """ self._sock, _ = self._sock.accept() - self._sockfile = self._sock.makefile() + self._sockfile = self._sock.makefile(mode='r') def cmd(self, qtest_cmd): """ @@ -76,6 +77,7 @@ class QEMUQtestProtocol: @param qtest_cmd: qtest command text to be sent """ + assert self._sockfile is not None self._sock.sendall((qtest_cmd + "\n").encode('utf-8')) resp = self._sockfile.readline() return resp @@ -83,7 +85,9 @@ class QEMUQtestProtocol: def close(self): """Close this socket.""" self._sock.close() - self._sockfile.close() + if self._sockfile: + self._sockfile.close() + self._sockfile = None def settimeout(self, timeout): """Set a timeout, in seconds.""" From 1dda0404d8afeb0ed45fbeae85e380e1ff57da35 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 14 May 2020 01:53:44 -0400 Subject: [PATCH 0765/2595] python/qemu: Adjust traceback typing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mypy considers it incorrect to use `bool` to statically return false, because it will assume that it could conceivably return True, and gives different analysis in that case. Use a None return to achieve the same effect, but make mypy happy. Note: Pylint considers function signatures as code that might trip the duplicate-code checker. I'd rather not disable this as it does not trigger often in practice, so I'm disabling it as a one-off and filed a change request; see https://github.com/PyCQA/pylint/issues/3619 Signed-off-by: John Snow Acked-by: Philippe Mathieu-Daudé Message-Id: <20200514055403.18902-14-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/machine.py | 8 ++++++-- python/qemu/qmp.py | 10 ++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 95a20a17f9..041c615052 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -24,6 +24,8 @@ import subprocess import shutil import socket import tempfile +from typing import Optional, Type +from types import TracebackType from . import qmp @@ -124,9 +126,11 @@ class QEMUMachine: def __enter__(self): return self - def __exit__(self, exc_type, exc_val, exc_tb): + def __exit__(self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType]) -> None: self.shutdown() - return False def add_monitor_null(self): """ diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index 73d49050ed..b91c9d5c1c 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -14,7 +14,9 @@ import logging from typing import ( Optional, TextIO, + Type, ) +from types import TracebackType class QMPError(Exception): @@ -146,10 +148,14 @@ class QEMUMonitorProtocol: # Implement context manager enter function. return self - def __exit__(self, exc_type, exc_value, exc_traceback): + def __exit__(self, + # pylint: disable=duplicate-code + # see https://github.com/PyCQA/pylint/issues/3619 + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType]) -> None: # Implement context manager exit function. self.close() - return False def connect(self, negotiate=True): """ From 7af67d694e289ab116c7abeca8a5bd752fbd46d7 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 14 May 2020 01:53:45 -0400 Subject: [PATCH 0766/2595] python/qemu/qmp: use True/False for non/blocking modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The type system doesn't want integers. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200514055403.18902-15-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/qmp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index b91c9d5c1c..a634c4e26c 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -120,14 +120,14 @@ class QEMUMonitorProtocol: """ # Check for new events regardless and pull them into the cache: - self.__sock.setblocking(0) + self.__sock.setblocking(False) try: self.__json_read() except OSError as err: if err.errno == errno.EAGAIN: # No data available pass - self.__sock.setblocking(1) + self.__sock.setblocking(True) # Wait for new events, if needed. # if wait is 0.0, this means "no wait" and is also implicitly false. From de210ec53c842fa67aa10110a7a351d64f91c487 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 14 May 2020 01:53:51 -0400 Subject: [PATCH 0767/2595] python/qemu/qmp: assert sockfile is not None MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In truth, if you don't do this, you'll just get a TypeError exception. Now, you'll get an AssertionError. Is this tangibly better? No. Does mypy complain less? Yes. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200514055403.18902-21-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/qmp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index a634c4e26c..e64b6b5faa 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -94,6 +94,7 @@ class QEMUMonitorProtocol: raise QMPCapabilitiesError def __json_read(self, only_event=False): + assert self.__sockfile is not None while True: data = self.__sockfile.readline() if not data: From c95dddce4910c9cd5315b942180b03ca4e48a6a6 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 14 May 2020 01:54:00 -0400 Subject: [PATCH 0768/2595] python/qemu/qtest: Check before accessing _qtest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It can be None; so add assertions or exceptions where appropriate to guard the access accordingly. Signed-off-by: John Snow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200514055403.18902-30-jsnow@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- python/qemu/qtest.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/python/qemu/qtest.py b/python/qemu/qtest.py index 4c88590eb0..888c8bd2f6 100644 --- a/python/qemu/qtest.py +++ b/python/qemu/qtest.py @@ -121,7 +121,8 @@ class QEMUQtestMachine(QEMUMachine): super()._pre_launch() self._qtest = QEMUQtestProtocol(self._qtest_path, server=True) - def _post_launch(self): + def _post_launch(self) -> None: + assert self._qtest is not None super()._post_launch() self._qtest.accept() @@ -129,6 +130,13 @@ class QEMUQtestMachine(QEMUMachine): super()._post_shutdown() self._remove_if_exists(self._qtest_path) - def qtest(self, cmd): - '''Send a qtest command to guest''' + def qtest(self, cmd: str) -> str: + """ + Send a qtest command to the guest. + + :param cmd: qtest command to send + :return: qtest server response + """ + if self._qtest is None: + raise RuntimeError("qtest socket not available") return self._qtest.cmd(cmd) From d5326a24378dbf228b5ea842945eff34ed9543a0 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Fri, 29 May 2020 16:34:50 -0400 Subject: [PATCH 0769/2595] tests/vm: Pass --debug through for vm-boot-ssh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helps debug issues that occur during the boot sequence. Signed-off-by: Robert Foley Reviewed-by: Peter Puhov Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20200529203458.1038-5-robert.foley@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- tests/vm/Makefile.include | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include index 74ab522c55..80f7f6bdee 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -91,6 +91,7 @@ vm-boot-ssh-%: $(IMAGES_DIR)/%.img $(call quiet-command, \ $(PYTHON) $(SRC_PATH)/tests/vm/$* \ $(if $(J),--jobs $(J)) \ + $(if $(V)$(DEBUG), --debug) \ --image "$<" \ --interactive \ false, \ From e56c45047bd5bbcfdc36e3f4ed8b439c5d5c989a Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Fri, 29 May 2020 16:34:51 -0400 Subject: [PATCH 0770/2595] tests/vm: Add ability to select QEMU from current build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a new special variable QEMU_LOCAL=1, which will indicate to take the QEMU binary from the current build. Signed-off-by: Robert Foley Reviewed-by: Peter Puhov Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20200529203458.1038-6-robert.foley@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- tests/vm/Makefile.include | 4 ++++ tests/vm/basevm.py | 28 +++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include index 80f7f6bdee..a253aba457 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -41,6 +41,7 @@ endif @echo " J=[0..9]* - Override the -jN parameter for make commands" @echo " DEBUG=1 - Enable verbose output on host and interactive debugging" @echo " V=1 - Enable verbose ouput on host and guest commands" + @echo " QEMU_LOCAL=1 - Use QEMU binary local to this build." @echo " QEMU=/path/to/qemu - Change path to QEMU binary" @echo " QEMU_IMG=/path/to/qemu-img - Change path to qemu-img tool" @@ -57,6 +58,7 @@ $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \ $(PYTHON) $< \ $(if $(V)$(DEBUG), --debug) \ $(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \ + $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ --image "$@" \ --force \ --build-image $@, \ @@ -71,6 +73,7 @@ vm-build-%: $(IMAGES_DIR)/%.img $(if $(DEBUG), --interactive) \ $(if $(J),--jobs $(J)) \ $(if $(V),--verbose) \ + $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ --image "$<" \ $(if $(BUILD_TARGET),--build-target $(BUILD_TARGET)) \ --snapshot \ @@ -92,6 +95,7 @@ vm-boot-ssh-%: $(IMAGES_DIR)/%.img $(PYTHON) $(SRC_PATH)/tests/vm/$* \ $(if $(J),--jobs $(J)) \ $(if $(V)$(DEBUG), --debug) \ + $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \ --image "$<" \ --interactive \ false, \ diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index a2d4054d72..5a3ce42281 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -61,9 +61,11 @@ class BaseVM(object): # 4 is arbitrary, but greater than 2, # since we found we need to wait more than twice as long. tcg_ssh_timeout_multiplier = 4 - def __init__(self, debug=False, vcpus=None, genisoimage=None): + def __init__(self, debug=False, vcpus=None, genisoimage=None, + build_path=None): self._guest = None self._genisoimage = genisoimage + self._build_path = build_path self._tmpdir = os.path.realpath(tempfile.mkdtemp(prefix="vm-test-", suffix=".tmp", dir=".")) @@ -184,15 +186,15 @@ class BaseVM(object): "-device", "virtio-blk,drive=drive0,bootindex=0"] args += self._data_args + extra_args logging.debug("QEMU args: %s", " ".join(args)) - qemu_bin = os.environ.get("QEMU", "qemu-system-" + self.arch) - guest = QEMUMachine(binary=qemu_bin, args=args) + qemu_path = get_qemu_path(self.arch, self._build_path) + guest = QEMUMachine(binary=qemu_path, args=args) guest.set_machine('pc') guest.set_console() try: guest.launch() except: logging.error("Failed to launch QEMU, command line:") - logging.error(" ".join([qemu_bin] + args)) + logging.error(" ".join([qemu_path] + args)) logging.error("Log:") logging.error(guest.get_log()) logging.error("QEMU version >= 2.10 is required") @@ -391,6 +393,19 @@ class BaseVM(object): return os.path.join(cidir, "cloud-init.iso") +def get_qemu_path(arch, build_path=None): + """Fetch the path to the qemu binary.""" + # If QEMU environment variable set, it takes precedence + if "QEMU" in os.environ: + qemu_path = os.environ["QEMU"] + elif build_path: + qemu_path = os.path.join(build_path, arch + "-softmmu") + qemu_path = os.path.join(qemu_path, "qemu-system-" + arch) + else: + # Default is to use system path for qemu. + qemu_path = "qemu-system-" + arch + return qemu_path + def parse_args(vmcls): def get_default_jobs(): @@ -421,6 +436,9 @@ def parse_args(vmcls): help="build QEMU from source in guest") parser.add_option("--build-target", help="QEMU build target", default="check") + parser.add_option("--build-path", default=None, + help="Path of build directory, "\ + "for using build tree QEMU binary. ") parser.add_option("--interactive", "-I", action="store_true", help="Interactively run command") parser.add_option("--snapshot", "-s", action="store_true", @@ -439,7 +457,7 @@ def main(vmcls): logging.basicConfig(level=(logging.DEBUG if args.debug else logging.WARN)) vm = vmcls(debug=args.debug, vcpus=args.jobs, - genisoimage=args.genisoimage) + genisoimage=args.genisoimage, build_path=args.build_path) if args.build_image: if os.path.exists(args.image) and not args.force: sys.stderr.writelines(["Image file exists: %s\n" % args.image, From 6ee982c9abc42e726f9e783ba67bbb7676a9f9b4 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Fri, 29 May 2020 16:34:52 -0400 Subject: [PATCH 0771/2595] tests/vm: allow wait_ssh() to specify command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows for waiting for completion of arbitrary commands. Signed-off-by: Robert Foley Reviewed-by: Peter Puhov Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20200529203458.1038-7-robert.foley@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- tests/vm/basevm.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 5a3ce42281..a80b616a08 100644 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -320,24 +320,24 @@ class BaseVM(object): def print_step(self, text): sys.stderr.write("### %s ...\n" % text) - def wait_ssh(self, wait_root=False, seconds=300): + def wait_ssh(self, wait_root=False, seconds=300, cmd="exit 0"): # Allow more time for VM to boot under TCG. if not kvm_available(self.arch): seconds *= self.tcg_ssh_timeout_multiplier starttime = datetime.datetime.now() endtime = starttime + datetime.timedelta(seconds=seconds) - guest_up = False + cmd_success = False while datetime.datetime.now() < endtime: - if wait_root and self.ssh_root("exit 0") == 0: - guest_up = True + if wait_root and self.ssh_root(cmd) == 0: + cmd_success = True break - elif self.ssh("exit 0") == 0: - guest_up = True + elif self.ssh(cmd) == 0: + cmd_success = True break seconds = (endtime - datetime.datetime.now()).total_seconds() logging.debug("%ds before timeout", seconds) time.sleep(1) - if not guest_up: + if not cmd_success: raise Exception("Timeout while waiting for guest ssh") def shutdown(self): From 83389e22c5aa48877b9e4f903ae4ec49a442df2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 12 May 2020 12:32:38 +0200 Subject: [PATCH 0772/2595] tests/migration/guestperf: Use Python 3 interpreter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: John Snow Reviewed-by: Kevin Wolf Message-Id: <20200512103238.7078-7-philmd@redhat.com> --- tests/migration/guestperf-batch.py | 2 +- tests/migration/guestperf-plot.py | 2 +- tests/migration/guestperf.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/migration/guestperf-batch.py b/tests/migration/guestperf-batch.py index cb150ce804..f1e900908d 100755 --- a/tests/migration/guestperf-batch.py +++ b/tests/migration/guestperf-batch.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Migration test batch comparison invokation # diff --git a/tests/migration/guestperf-plot.py b/tests/migration/guestperf-plot.py index d70bb7a557..907151011a 100755 --- a/tests/migration/guestperf-plot.py +++ b/tests/migration/guestperf-plot.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Migration test graph plotting command # diff --git a/tests/migration/guestperf.py b/tests/migration/guestperf.py index 99b027e8ba..ba1c4bc4ca 100755 --- a/tests/migration/guestperf.py +++ b/tests/migration/guestperf.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Migration test direct invokation command # From 2c9120a223e666d7171e965b8f8bbcd72620f566 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 28 May 2020 12:24:04 +0100 Subject: [PATCH 0773/2595] tests/acceptance/migration.py: Wait for both sides MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the source finishes migration the destination will still be receiving the data sent by the source, so it might not have quite finished yet, so won't quite have reached 'completed'. This lead to occasional asserts in the next few checks. After the source has finished, check the destination as well. (We can't just switch to checking the destination, because it doesn't give a status until it has started receiving the migration). Reported-by: Alex Bennée Signed-off-by: Dr. David Alan Gilbert Tested-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200528112404.121972-1-dgilbert@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/migration.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index 0365289cda..792639cb69 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -35,6 +35,10 @@ class Migration(Test): timeout=self.timeout, step=0.1, args=(src_vm,)) + wait.wait_for(self.migration_finished, + timeout=self.timeout, + step=0.1, + args=(dst_vm,)) self.assertEqual(src_vm.command('query-migrate')['status'], 'completed') self.assertEqual(dst_vm.command('query-migrate')['status'], 'completed') self.assertEqual(dst_vm.command('query-status')['status'], 'running') From a5ba86d423c2b071894d86c60487f2317c7ffb60 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 29 May 2020 10:04:39 +0300 Subject: [PATCH 0774/2595] tests/acceptance: allow console interaction with specific VMs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Console interaction in avocado scripts was possible only with single default VM. This patch modifies the function parameters to allow passing a specific VM as a parameter to interact with it. Signed-off-by: Pavel Dovgalyuk Reviewed-by: Willian Rampazzo Reviewed-by: Alex Bennée Tested-by: Philippe Mathieu-Daudé Message-Id: <159073587933.20809.5122618715976660635.stgit@pasha-ThinkPad-X280> Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/avocado_qemu/__init__.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index 59e7b4f763..77d1c1d9ff 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -69,13 +69,15 @@ def pick_default_qemu_bin(arch=None): def _console_interaction(test, success_message, failure_message, - send_string, keep_sending=False): + send_string, keep_sending=False, vm=None): assert not keep_sending or send_string - console = test.vm.console_socket.makefile() + if vm is None: + vm = test.vm + console = vm.console_socket.makefile() console_logger = logging.getLogger('console') while True: if send_string: - test.vm.console_socket.sendall(send_string.encode()) + vm.console_socket.sendall(send_string.encode()) if not keep_sending: send_string = None # send only once msg = console.readline().strip() @@ -115,7 +117,8 @@ def interrupt_interactive_console_until_pattern(test, success_message, _console_interaction(test, success_message, failure_message, interrupt_string, True) -def wait_for_console_pattern(test, success_message, failure_message=None): +def wait_for_console_pattern(test, success_message, failure_message=None, + vm=None): """ Waits for messages to appear on the console, while logging the content @@ -125,7 +128,7 @@ def wait_for_console_pattern(test, success_message, failure_message=None): :param success_message: if this message appears, test succeeds :param failure_message: if this message appears, test fails """ - _console_interaction(test, success_message, failure_message, None) + _console_interaction(test, success_message, failure_message, None, vm=vm) def exec_command_and_wait_for_pattern(test, command, success_message, failure_message=None): From 12121c496fcc609e23033c4a36399b54f98bcd56 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 29 May 2020 10:04:44 +0300 Subject: [PATCH 0775/2595] tests/acceptance: refactor boot_linux_console test to allow code reuse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch splits code in BootLinuxConsole class into two different classes to allow reusing it by record/replay tests. Signed-off-by: Pavel Dovgalyuk Reviewed-by: Alex Bennée Tested-by: Philippe Mathieu-Daudé Message-Id: <159073588490.20809.13942096070255577558.stgit@pasha-ThinkPad-X280> Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/boot_linux_console.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index c6b06a1a13..12725d4529 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -28,19 +28,13 @@ try: except CmdNotFoundError: P7ZIP_AVAILABLE = False -class BootLinuxConsole(Test): - """ - Boots a Linux kernel and checks that the console is operational and the - kernel command line is properly passed from QEMU to the kernel - """ - - timeout = 90 - +class LinuxKernelTest(Test): KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' - def wait_for_console_pattern(self, success_message): + def wait_for_console_pattern(self, success_message, vm=None): wait_for_console_pattern(self, success_message, - failure_message='Kernel panic - not syncing') + failure_message='Kernel panic - not syncing', + vm=vm) def extract_from_deb(self, deb, path): """ @@ -79,6 +73,13 @@ class BootLinuxConsole(Test): os.chdir(cwd) return os.path.normpath(os.path.join(self.workdir, path)) +class BootLinuxConsole(LinuxKernelTest): + """ + Boots a Linux kernel and checks that the console is operational and the + kernel command line is properly passed from QEMU to the kernel + """ + timeout = 90 + def test_x86_64_pc(self): """ :avocado: tags=arch:x86_64 From 1c80c87c8c2489e4318c93c844aa29bc1d014146 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 29 May 2020 10:05:31 +0300 Subject: [PATCH 0776/2595] tests/acceptance: refactor boot_linux to allow code reuse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch moves image downloading functions to the separate class to allow reusing them from record/replay tests. Signed-off-by: Pavel Dovgalyuk Tested-by: Philippe Mathieu-Daudé Message-Id: <159073593167.20809.17582679291556188984.stgit@pasha-ThinkPad-X280> Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/boot_linux.py | 49 ++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/tests/acceptance/boot_linux.py b/tests/acceptance/boot_linux.py index 075a386300..3aa57e88b0 100644 --- a/tests/acceptance/boot_linux.py +++ b/tests/acceptance/boot_linux.py @@ -26,22 +26,8 @@ KVM_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "KVM" TCG_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "TCG" -class BootLinux(Test): - """ - Boots a Linux system, checking for a successful initialization - """ - - timeout = 900 - chksum = None - - def setUp(self): - super(BootLinux, self).setUp() - self.vm.add_args('-smp', '2') - self.vm.add_args('-m', '1024') - self.prepare_boot() - self.prepare_cloudinit() - - def prepare_boot(self): +class BootLinuxBase(Test): + def download_boot(self): self.log.debug('Looking for and selecting a qemu-img binary to be ' 'used to create the bootable snapshot image') # If qemu-img has been built, use it, otherwise the system wide one @@ -60,17 +46,17 @@ class BootLinux(Test): if image_arch == 'ppc64': image_arch = 'ppc64le' try: - self.boot = vmimage.get( + boot = vmimage.get( 'fedora', arch=image_arch, version='31', checksum=self.chksum, algorithm='sha256', cache_dir=self.cache_dirs[0], snapshot_dir=self.workdir) - self.vm.add_args('-drive', 'file=%s' % self.boot.path) except: self.cancel('Failed to download/prepare boot image') + return boot.path - def prepare_cloudinit(self): + def download_cloudinit(self): self.log.info('Preparing cloudinit image') try: cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso') @@ -81,9 +67,32 @@ class BootLinux(Test): # QEMU's hard coded usermode router address phone_home_host='10.0.2.2', phone_home_port=self.phone_home_port) - self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso) except Exception: self.cancel('Failed to prepared cloudinit image') + return cloudinit_iso + +class BootLinux(BootLinuxBase): + """ + Boots a Linux system, checking for a successful initialization + """ + + timeout = 900 + chksum = None + + def setUp(self): + super(BootLinux, self).setUp() + self.vm.add_args('-smp', '2') + self.vm.add_args('-m', '1024') + self.prepare_boot() + self.prepare_cloudinit() + + def prepare_boot(self): + path = self.download_boot() + self.vm.add_args('-drive', 'file=%s' % path) + + def prepare_cloudinit(self): + cloudinit_iso = self.download_cloudinit() + self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso) def launch_and_wait(self): self.vm.set_console() From 9865f39db06d6c7c634d06684981861035412a48 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Tue, 5 May 2020 18:24:51 +0800 Subject: [PATCH 0777/2595] tests/Makefile: Fix description of "make check" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The description of "make check" is out-of-date, so fix it by adding block and softfloat. Reviewed-by: Claudio Fontana Signed-off-by: Huacai Chen Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: <1588674291-6486-1-git-send-email-chenhc@lemote.com> --- tests/Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index a00ccc94b8..6e3d6370df 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -4,7 +4,7 @@ check-help: @echo "Regression testing targets:" @echo - @echo " $(MAKE) check Run unit, qapi-schema, qtest and decodetree" + @echo " $(MAKE) check Run block, qapi-schema, unit, softfloat, qtest and decodetree tests" @echo @echo " $(MAKE) check-qtest-TARGET Run qtest tests for given target" @echo " $(MAKE) check-qtest Run qtest tests" From aa2953fd169c98c6ef44feb9c7e44eaad7f2808b Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sun, 3 May 2020 18:20:15 +0800 Subject: [PATCH 0778/2595] configure: Add KVM target support for MIPS64 Preparing for Loongson-3 virtualization, add KVM target support for MIPS64 in configure script. Signed-off-by: Huacai Chen Co-developed-by: Jiaxun Yang Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: <1588501221-1205-2-git-send-email-chenhc@lemote.com> --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index af2ba83f0e..f087d2bcd1 100755 --- a/configure +++ b/configure @@ -198,7 +198,7 @@ supported_kvm_target() { arm:arm | aarch64:aarch64 | \ i386:i386 | i386:x86_64 | i386:x32 | \ x86_64:i386 | x86_64:x86_64 | x86_64:x32 | \ - mips:mips | mipsel:mips | \ + mips:mips | mipsel:mips | mips64:mips | mips64el:mips | \ ppc:ppc | ppc64:ppc | ppc:ppc64 | ppc64:ppc64 | ppc64:ppc64le | \ s390x:s390x) return 0 From c3173a35bc2a759dbfac4e76e9a7695b1d44e97a Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sun, 3 May 2020 18:20:17 +0800 Subject: [PATCH 0779/2595] hw/mips: Add CPU IRQ3 delivery for KVM Currently, KVM/MIPS only deliver I/O interrupt via IP2, this patch add IP3 delivery as well, because Loongson-3 based machine use both IRQ2 (CPU's IP2) and IRQ3 (CPU's IP3). Signed-off-by: Huacai Chen Co-developed-by: Jiaxun Yang Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: <1588501221-1205-4-git-send-email-chenhc@lemote.com> --- hw/mips/mips_int.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c index 4a1bf846da..0f9c6f07c1 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -51,7 +51,7 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP)); } - if (kvm_enabled() && irq == 2) { + if (kvm_enabled() && (irq == 2 || irq == 3)) { kvm_mips_set_interrupt(cpu, irq, level); } From 7e0896b0e134f5023107d8b4454c020ba51f2d42 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sun, 3 May 2020 18:20:19 +0800 Subject: [PATCH 0780/2595] target/mips: Add more CP0 register for save/restore Add more CP0 register for save/restore, including: EBase, XContext, PageGrain, PWBase, PWSize, PWField, PWCtl, Config*, KScratch1~KScratch6. Signed-off-by: Huacai Chen Co-developed-by: Jiaxun Yang Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: <1588501221-1205-6-git-send-email-chenhc@lemote.com> --- target/mips/kvm.c | 212 ++++++++++++++++++++++++++++++++++++++++++ target/mips/machine.c | 6 +- 2 files changed, 216 insertions(+), 2 deletions(-) diff --git a/target/mips/kvm.c b/target/mips/kvm.c index de3e26ef1f..96cfa10cf2 100644 --- a/target/mips/kvm.c +++ b/target/mips/kvm.c @@ -245,10 +245,16 @@ int kvm_mips_set_ipi_interrupt(MIPSCPU *cpu, int irq, int level) (KVM_REG_MIPS_CP0 | KVM_REG_SIZE_U64 | (8 * (_R) + (_S))) #define KVM_REG_MIPS_CP0_INDEX MIPS_CP0_32(0, 0) +#define KVM_REG_MIPS_CP0_RANDOM MIPS_CP0_32(1, 0) #define KVM_REG_MIPS_CP0_CONTEXT MIPS_CP0_64(4, 0) #define KVM_REG_MIPS_CP0_USERLOCAL MIPS_CP0_64(4, 2) #define KVM_REG_MIPS_CP0_PAGEMASK MIPS_CP0_32(5, 0) +#define KVM_REG_MIPS_CP0_PAGEGRAIN MIPS_CP0_32(5, 1) +#define KVM_REG_MIPS_CP0_PWBASE MIPS_CP0_64(5, 5) +#define KVM_REG_MIPS_CP0_PWFIELD MIPS_CP0_64(5, 6) +#define KVM_REG_MIPS_CP0_PWSIZE MIPS_CP0_64(5, 7) #define KVM_REG_MIPS_CP0_WIRED MIPS_CP0_32(6, 0) +#define KVM_REG_MIPS_CP0_PWCTL MIPS_CP0_32(6, 6) #define KVM_REG_MIPS_CP0_HWRENA MIPS_CP0_32(7, 0) #define KVM_REG_MIPS_CP0_BADVADDR MIPS_CP0_64(8, 0) #define KVM_REG_MIPS_CP0_COUNT MIPS_CP0_32(9, 0) @@ -258,13 +264,22 @@ int kvm_mips_set_ipi_interrupt(MIPSCPU *cpu, int irq, int level) #define KVM_REG_MIPS_CP0_CAUSE MIPS_CP0_32(13, 0) #define KVM_REG_MIPS_CP0_EPC MIPS_CP0_64(14, 0) #define KVM_REG_MIPS_CP0_PRID MIPS_CP0_32(15, 0) +#define KVM_REG_MIPS_CP0_EBASE MIPS_CP0_64(15, 1) #define KVM_REG_MIPS_CP0_CONFIG MIPS_CP0_32(16, 0) #define KVM_REG_MIPS_CP0_CONFIG1 MIPS_CP0_32(16, 1) #define KVM_REG_MIPS_CP0_CONFIG2 MIPS_CP0_32(16, 2) #define KVM_REG_MIPS_CP0_CONFIG3 MIPS_CP0_32(16, 3) #define KVM_REG_MIPS_CP0_CONFIG4 MIPS_CP0_32(16, 4) #define KVM_REG_MIPS_CP0_CONFIG5 MIPS_CP0_32(16, 5) +#define KVM_REG_MIPS_CP0_CONFIG6 MIPS_CP0_32(16, 6) +#define KVM_REG_MIPS_CP0_XCONTEXT MIPS_CP0_64(20, 0) #define KVM_REG_MIPS_CP0_ERROREPC MIPS_CP0_64(30, 0) +#define KVM_REG_MIPS_CP0_KSCRATCH1 MIPS_CP0_64(31, 2) +#define KVM_REG_MIPS_CP0_KSCRATCH2 MIPS_CP0_64(31, 3) +#define KVM_REG_MIPS_CP0_KSCRATCH3 MIPS_CP0_64(31, 4) +#define KVM_REG_MIPS_CP0_KSCRATCH4 MIPS_CP0_64(31, 5) +#define KVM_REG_MIPS_CP0_KSCRATCH5 MIPS_CP0_64(31, 6) +#define KVM_REG_MIPS_CP0_KSCRATCH6 MIPS_CP0_64(31, 7) static inline int kvm_mips_put_one_reg(CPUState *cs, uint64_t reg_id, int32_t *addr) @@ -394,6 +409,29 @@ static inline int kvm_mips_get_one_ureg64(CPUState *cs, uint64_t reg_id, (1U << CP0C5_UFE) | \ (1U << CP0C5_FRE) | \ (1U << CP0C5_UFR)) +#define KVM_REG_MIPS_CP0_CONFIG6_MASK ((1U << CP0C6_BPPASS) | \ + (0x3fU << CP0C6_KPOS) | \ + (1U << CP0C6_KE) | \ + (1U << CP0C6_VTLBONLY) | \ + (1U << CP0C6_LASX) | \ + (1U << CP0C6_SSEN) | \ + (1U << CP0C6_DISDRTIME) | \ + (1U << CP0C6_PIXNUEN) | \ + (1U << CP0C6_SCRAND) | \ + (1U << CP0C6_LLEXCEN) | \ + (1U << CP0C6_DISVC) | \ + (1U << CP0C6_VCLRU) | \ + (1U << CP0C6_DCLRU) | \ + (1U << CP0C6_PIXUEN) | \ + (1U << CP0C6_DISBLKLYEN) | \ + (1U << CP0C6_UMEMUALEN) | \ + (1U << CP0C6_SFBEN) | \ + (1U << CP0C6_FLTINT) | \ + (1U << CP0C6_VLTINT) | \ + (1U << CP0C6_DISBTB) | \ + (3U << CP0C6_STPREFCTL) | \ + (1U << CP0C6_INSTPREF) | \ + (1U << CP0C6_DATAPREF)) static inline int kvm_mips_change_one_reg(CPUState *cs, uint64_t reg_id, int32_t *addr, int32_t mask) @@ -729,6 +767,11 @@ static int kvm_mips_put_cp0_registers(CPUState *cs, int level) DPRINTF("%s: Failed to put CP0_INDEX (%d)\n", __func__, err); ret = err; } + err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_RANDOM, &env->CP0_Random); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_RANDOM (%d)\n", __func__, err); + ret = err; + } err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_CONTEXT, &env->CP0_Context); if (err < 0) { @@ -747,11 +790,40 @@ static int kvm_mips_put_cp0_registers(CPUState *cs, int level) DPRINTF("%s: Failed to put CP0_PAGEMASK (%d)\n", __func__, err); ret = err; } + err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_PAGEGRAIN, + &env->CP0_PageGrain); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_PAGEGRAIN (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_PWBASE, + &env->CP0_PWBase); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_PWBASE (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_PWFIELD, + &env->CP0_PWField); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_PWField (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_PWSIZE, + &env->CP0_PWSize); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_PWSIZE (%d)\n", __func__, err); + ret = err; + } err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_WIRED, &env->CP0_Wired); if (err < 0) { DPRINTF("%s: Failed to put CP0_WIRED (%d)\n", __func__, err); ret = err; } + err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_PWCTL, &env->CP0_PWCtl); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_PWCTL (%d)\n", __func__, err); + ret = err; + } err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_HWRENA, &env->CP0_HWREna); if (err < 0) { DPRINTF("%s: Failed to put CP0_HWRENA (%d)\n", __func__, err); @@ -799,6 +871,11 @@ static int kvm_mips_put_cp0_registers(CPUState *cs, int level) DPRINTF("%s: Failed to put CP0_PRID (%d)\n", __func__, err); ret = err; } + err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_EBASE, &env->CP0_EBase); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_EBASE (%d)\n", __func__, err); + ret = err; + } err = kvm_mips_change_one_reg(cs, KVM_REG_MIPS_CP0_CONFIG, &env->CP0_Config0, KVM_REG_MIPS_CP0_CONFIG_MASK); @@ -841,12 +918,61 @@ static int kvm_mips_put_cp0_registers(CPUState *cs, int level) DPRINTF("%s: Failed to change CP0_CONFIG5 (%d)\n", __func__, err); ret = err; } + err = kvm_mips_change_one_reg(cs, KVM_REG_MIPS_CP0_CONFIG6, + &env->CP0_Config6, + KVM_REG_MIPS_CP0_CONFIG6_MASK); + if (err < 0) { + DPRINTF("%s: Failed to change CP0_CONFIG6 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_XCONTEXT, + &env->CP0_XContext); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_XCONTEXT (%d)\n", __func__, err); + ret = err; + } err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_ERROREPC, &env->CP0_ErrorEPC); if (err < 0) { DPRINTF("%s: Failed to put CP0_ERROREPC (%d)\n", __func__, err); ret = err; } + err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH1, + &env->CP0_KScratch[0]); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_KSCRATCH1 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH2, + &env->CP0_KScratch[1]); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_KSCRATCH2 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH3, + &env->CP0_KScratch[2]); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_KSCRATCH3 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH4, + &env->CP0_KScratch[3]); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_KSCRATCH4 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH5, + &env->CP0_KScratch[4]); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_KSCRATCH5 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH6, + &env->CP0_KScratch[5]); + if (err < 0) { + DPRINTF("%s: Failed to put CP0_KSCRATCH6 (%d)\n", __func__, err); + ret = err; + } return ret; } @@ -862,6 +988,11 @@ static int kvm_mips_get_cp0_registers(CPUState *cs) DPRINTF("%s: Failed to get CP0_INDEX (%d)\n", __func__, err); ret = err; } + err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_RANDOM, &env->CP0_Random); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_RANDOM (%d)\n", __func__, err); + ret = err; + } err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_CONTEXT, &env->CP0_Context); if (err < 0) { @@ -880,11 +1011,40 @@ static int kvm_mips_get_cp0_registers(CPUState *cs) DPRINTF("%s: Failed to get CP0_PAGEMASK (%d)\n", __func__, err); ret = err; } + err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_PAGEGRAIN, + &env->CP0_PageGrain); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_PAGEGRAIN (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_PWBASE, + &env->CP0_PWBase); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_PWBASE (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_PWFIELD, + &env->CP0_PWField); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_PWFIELD (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_PWSIZE, + &env->CP0_PWSize); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_PWSIZE (%d)\n", __func__, err); + ret = err; + } err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_WIRED, &env->CP0_Wired); if (err < 0) { DPRINTF("%s: Failed to get CP0_WIRED (%d)\n", __func__, err); ret = err; } + err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_PWCTL, &env->CP0_PWCtl); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_PWCtl (%d)\n", __func__, err); + ret = err; + } err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_HWRENA, &env->CP0_HWREna); if (err < 0) { DPRINTF("%s: Failed to get CP0_HWRENA (%d)\n", __func__, err); @@ -932,6 +1092,11 @@ static int kvm_mips_get_cp0_registers(CPUState *cs) DPRINTF("%s: Failed to get CP0_PRID (%d)\n", __func__, err); ret = err; } + err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_EBASE, &env->CP0_EBase); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_EBASE (%d)\n", __func__, err); + ret = err; + } err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_CONFIG, &env->CP0_Config0); if (err < 0) { DPRINTF("%s: Failed to get CP0_CONFIG (%d)\n", __func__, err); @@ -962,12 +1127,59 @@ static int kvm_mips_get_cp0_registers(CPUState *cs) DPRINTF("%s: Failed to get CP0_CONFIG5 (%d)\n", __func__, err); ret = err; } + err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_CONFIG6, &env->CP0_Config6); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_CONFIG6 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_XCONTEXT, + &env->CP0_XContext); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_XCONTEXT (%d)\n", __func__, err); + ret = err; + } err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_ERROREPC, &env->CP0_ErrorEPC); if (err < 0) { DPRINTF("%s: Failed to get CP0_ERROREPC (%d)\n", __func__, err); ret = err; } + err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH1, + &env->CP0_KScratch[0]); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_KSCRATCH1 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH2, + &env->CP0_KScratch[1]); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_KSCRATCH2 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH3, + &env->CP0_KScratch[2]); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_KSCRATCH3 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH4, + &env->CP0_KScratch[3]); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_KSCRATCH4 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH5, + &env->CP0_KScratch[4]); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_KSCRATCH5 (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH6, + &env->CP0_KScratch[5]); + if (err < 0) { + DPRINTF("%s: Failed to get CP0_KSCRATCH6 (%d)\n", __func__, err); + ret = err; + } return ret; } diff --git a/target/mips/machine.c b/target/mips/machine.c index 8d5b18bea2..5b23e3e912 100644 --- a/target/mips/machine.c +++ b/target/mips/machine.c @@ -212,8 +212,8 @@ const VMStateDescription vmstate_tlb = { const VMStateDescription vmstate_mips_cpu = { .name = "cpu", - .version_id = 19, - .minimum_version_id = 19, + .version_id = 20, + .minimum_version_id = 20, .post_load = cpu_post_load, .fields = (VMStateField[]) { /* Active TC */ @@ -289,6 +289,8 @@ const VMStateDescription vmstate_mips_cpu = { VMSTATE_INT32(env.CP0_Config1, MIPSCPU), VMSTATE_INT32(env.CP0_Config2, MIPSCPU), VMSTATE_INT32(env.CP0_Config3, MIPSCPU), + VMSTATE_INT32(env.CP0_Config4, MIPSCPU), + VMSTATE_INT32(env.CP0_Config5, MIPSCPU), VMSTATE_INT32(env.CP0_Config6, MIPSCPU), VMSTATE_INT32(env.CP0_Config7, MIPSCPU), VMSTATE_UINT64(env.CP0_LLAddr, MIPSCPU), From ee3863b9d414f0b4a59a88f2a79b496a99d4f6dd Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 8 Apr 2020 17:16:18 +0800 Subject: [PATCH 0781/2595] target/mips: Support variable page size Traditionally, MIPS use 4KB page size, but Loongson prefer 16KB page size in system emulator. So, let's define TARGET_PAGE_BITS_VARY and TARGET_PAGE_BITS_MIN to support variable page size. Cc: Jiaxun Yang Signed-off-by: Huacai Chen Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: <1586337380-25217-1-git-send-email-chenhc@lemote.com> --- target/mips/cpu-param.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/mips/cpu-param.h b/target/mips/cpu-param.h index 308660d29d..9c4a6ea45e 100644 --- a/target/mips/cpu-param.h +++ b/target/mips/cpu-param.h @@ -23,7 +23,12 @@ # define TARGET_VIRT_ADDR_SPACE_BITS 32 #endif #endif +#ifdef CONFIG_USER_ONLY #define TARGET_PAGE_BITS 12 +#else +#define TARGET_PAGE_BITS_VARY +#define TARGET_PAGE_BITS_MIN 12 +#endif #define NB_MMU_MODES 4 #endif From a08d60bc6c2b6469368fff3d38dd5ddd16dd36be Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 8 Apr 2020 17:16:19 +0800 Subject: [PATCH 0782/2595] hw/mips: fuloong2e: Set preferred page size to 16KB Loongson processor prefers 16KB page size in system emulator, so let's define mc->minimum_page_bits to 14. Cc: Jiaxun Yang Signed-off-by: Huacai Chen Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: <1586337380-25217-2-git-send-email-chenhc@lemote.com> --- hw/mips/fuloong2e.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index f583c44b79..7a65166cf0 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -392,6 +392,7 @@ static void mips_fuloong2e_machine_init(MachineClass *mc) mc->default_cpu_type = MIPS_CPU_TYPE_NAME("Loongson-2E"); mc->default_ram_size = 256 * MiB; mc->default_ram_id = "fuloong2e.ram"; + mc->minimum_page_bits = 14; } DEFINE_MACHINE("fuloong2e", mips_fuloong2e_machine_init) From a564c318fe4e5bdc17029ced343fb13173fbd2c9 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Fri, 29 May 2020 09:21:44 +0200 Subject: [PATCH 0783/2595] target/tricore: Don't save pc in generate_qemu_excp EXCP_DEBUG is the only user. If we encounter a jump in tricore-gdb it's target was overwritten by generate_qemu_excp() and we would never leave. Signed-off-by: Bastian Koppelmann Message-Id: <20200529072148.284037-2-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 609d75ae8a..65a33e5ad8 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -3264,7 +3264,6 @@ static void generate_trap(DisasContext *ctx, int class, int tin) static void generate_qemu_excp(DisasContext *ctx, int excp) { TCGv_i32 tmp = tcg_const_i32(excp); - gen_save_pc(ctx->base.pc_next); gen_helper_qemu_excp(cpu_env, tmp); ctx->base.is_jmp = DISAS_NORETURN; tcg_temp_free(tmp); From 44ee3bafb6711180e77dd071beb04fae70b1cb65 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Fri, 29 May 2020 09:21:45 +0200 Subject: [PATCH 0784/2595] target/tricore: Move translate feature check to ctx this allows us to remove the references to env from ctx. This also fixes a segfault that was due to the unititalized ctx->env ptr. Reported-by: Andreas Konopik Signed-off-by: Bastian Koppelmann Message-Id: <20200529072148.284037-3-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 60 +++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 65a33e5ad8..608f72d384 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -66,14 +66,19 @@ static const char *regnames_d[] = { typedef struct DisasContext { DisasContextBase base; - CPUTriCoreState *env; target_ulong pc_succ_insn; uint32_t opcode; /* Routine used to access memory */ int mem_idx; uint32_t hflags, saved_hflags; + uint64_t features; } DisasContext; +static int has_feature(DisasContext *ctx, int feature) +{ + return (ctx->features & (1ULL << feature)) != 0; +} + enum { MODE_LL = 0, MODE_LU = 1, @@ -370,7 +375,7 @@ static void gen_swapmsk(DisasContext *ctx, int reg, TCGv ea) These makros also specify in which ISA version the csfr was introduced. */ #define R(ADDRESS, REG, FEATURE) \ case ADDRESS: \ - if (tricore_feature(ctx->env, FEATURE)) { \ + if (has_feature(ctx, FEATURE)) { \ tcg_gen_ld_tl(ret, cpu_env, offsetof(CPUTriCoreState, REG)); \ } \ break; @@ -395,7 +400,7 @@ static inline void gen_mfcr(DisasContext *ctx, TCGv ret, int32_t offset) since no execption occurs */ #define A(ADDRESS, REG, FEATURE) R(ADDRESS, REG, FEATURE) \ case ADDRESS: \ - if (tricore_feature(ctx->env, FEATURE)) { \ + if (has_feature(ctx, FEATURE)) { \ tcg_gen_st_tl(r1, cpu_env, offsetof(CPUTriCoreState, REG)); \ } \ break; @@ -3158,7 +3163,7 @@ gen_dvinit_b(DisasContext *ctx, TCGv rl, TCGv rh, TCGv r1, TCGv r2) { TCGv_i64 ret = tcg_temp_new_i64(); - if (!tricore_feature(ctx->env, TRICORE_FEATURE_131)) { + if (!has_feature(ctx, TRICORE_FEATURE_131)) { gen_helper_dvinit_b_13(ret, cpu_env, r1, r2); } else { gen_helper_dvinit_b_131(ret, cpu_env, r1, r2); @@ -3173,7 +3178,7 @@ gen_dvinit_h(DisasContext *ctx, TCGv rl, TCGv rh, TCGv r1, TCGv r2) { TCGv_i64 ret = tcg_temp_new_i64(); - if (!tricore_feature(ctx->env, TRICORE_FEATURE_131)) { + if (!has_feature(ctx, TRICORE_FEATURE_131)) { gen_helper_dvinit_h_13(ret, cpu_env, r1, r2); } else { gen_helper_dvinit_h_131(ret, cpu_env, r1, r2); @@ -3655,7 +3660,7 @@ static void decode_src_opc(DisasContext *ctx, int op1) tcg_gen_movi_tl(cpu_gpr_a[r1], const4); break; case OPC1_16_SRC_MOV_E: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { tcg_gen_movi_tl(cpu_gpr_d[r1], const4); tcg_gen_sari_tl(cpu_gpr_d[r1+1], cpu_gpr_d[r1], 31); } else { @@ -4106,7 +4111,7 @@ static void decode_16Bit_opc(DisasContext *ctx) break; case OPC1_16_SBC_JEQ2: case OPC1_16_SBC_JNE2: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { address = MASK_OP_SBC_DISP4(ctx->opcode); const16 = MASK_OP_SBC_CONST4_SEXT(ctx->opcode); gen_compute_branch(ctx, op1, 0, 0, const16, address); @@ -4124,7 +4129,7 @@ static void decode_16Bit_opc(DisasContext *ctx) /* SBR-format */ case OPC1_16_SBR_JEQ2: case OPC1_16_SBR_JNE2: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { r1 = MASK_OP_SBR_S2(ctx->opcode); address = MASK_OP_SBR_DISP4(ctx->opcode); gen_compute_branch(ctx, op1, r1, 0, 0, address); @@ -4704,13 +4709,13 @@ static void decode_bo_addrmode_post_pre_base(DisasContext *ctx) break; case OPC2_32_BO_CACHEI_WI_SHORTOFF: case OPC2_32_BO_CACHEI_W_SHORTOFF: - if (!tricore_feature(ctx->env, TRICORE_FEATURE_131)) { + if (!has_feature(ctx, TRICORE_FEATURE_131)) { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC2_32_BO_CACHEI_W_POSTINC: case OPC2_32_BO_CACHEI_WI_POSTINC: - if (tricore_feature(ctx->env, TRICORE_FEATURE_131)) { + if (has_feature(ctx, TRICORE_FEATURE_131)) { tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); @@ -4718,7 +4723,7 @@ static void decode_bo_addrmode_post_pre_base(DisasContext *ctx) break; case OPC2_32_BO_CACHEI_W_PREINC: case OPC2_32_BO_CACHEI_WI_PREINC: - if (tricore_feature(ctx->env, TRICORE_FEATURE_131)) { + if (has_feature(ctx, TRICORE_FEATURE_131)) { tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); @@ -5372,7 +5377,7 @@ static void decode_bol_opc(DisasContext *ctx, int32_t op1) tcg_gen_addi_tl(cpu_gpr_a[r1], cpu_gpr_a[r2], address); break; case OPC1_32_BOL_ST_A_LONGOFF: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { gen_offset_st(ctx, cpu_gpr_a[r1], cpu_gpr_a[r2], address, MO_LEUL); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); @@ -5382,42 +5387,42 @@ static void decode_bol_opc(DisasContext *ctx, int32_t op1) gen_offset_st(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LEUL); break; case OPC1_32_BOL_LD_B_LONGOFF: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_SB); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_BOL_LD_BU_LONGOFF: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_UB); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_BOL_LD_H_LONGOFF: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LESW); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_BOL_LD_HU_LONGOFF: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LEUW); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_BOL_ST_B_LONGOFF: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { gen_offset_st(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_SB); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_BOL_ST_H_LONGOFF: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { gen_offset_st(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LESW); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); @@ -6022,7 +6027,7 @@ static void decode_rlc_opc(DisasContext *ctx, tcg_gen_movi_tl(cpu_gpr_d[r2], const16); break; case OPC1_32_RLC_MOV_64: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { CHECK_REG_PAIR(r2); tcg_gen_movi_tl(cpu_gpr_d[r2], const16); tcg_gen_movi_tl(cpu_gpr_d[r2+1], const16 >> 15); @@ -6248,7 +6253,7 @@ static void decode_rr_accumulator(DisasContext *ctx) tcg_gen_mov_tl(cpu_gpr_d[r3], cpu_gpr_d[r2]); break; case OPC2_32_RR_MOV_64: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { temp = tcg_temp_new(); CHECK_REG_PAIR(r3); @@ -6262,7 +6267,7 @@ static void decode_rr_accumulator(DisasContext *ctx) } break; case OPC2_32_RR_MOVS_64: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { CHECK_REG_PAIR(r3); tcg_gen_mov_tl(cpu_gpr_d[r3], cpu_gpr_d[r2]); tcg_gen_sari_tl(cpu_gpr_d[r3 + 1], cpu_gpr_d[r2], 31); @@ -6602,7 +6607,7 @@ static void decode_rr_divide(DisasContext *ctx) tcg_gen_shri_tl(temp3, cpu_gpr_d[r1], 8); /* reset av */ tcg_gen_movi_tl(cpu_PSW_AV, 0); - if (!tricore_feature(ctx->env, TRICORE_FEATURE_131)) { + if (!has_feature(ctx, TRICORE_FEATURE_131)) { /* overflow = (abs(D[r3+1]) >= abs(D[r2])) */ tcg_gen_abs_tl(temp, temp3); tcg_gen_abs_tl(temp2, cpu_gpr_d[r2]); @@ -6635,7 +6640,7 @@ static void decode_rr_divide(DisasContext *ctx) tcg_gen_shri_tl(temp3, cpu_gpr_d[r1], 16); /* reset av */ tcg_gen_movi_tl(cpu_PSW_AV, 0); - if (!tricore_feature(ctx->env, TRICORE_FEATURE_131)) { + if (!has_feature(ctx, TRICORE_FEATURE_131)) { /* overflow = (abs(D[r3+1]) >= abs(D[r2])) */ tcg_gen_abs_tl(temp, temp3); tcg_gen_abs_tl(temp2, cpu_gpr_d[r2]); @@ -6698,14 +6703,14 @@ static void decode_rr_divide(DisasContext *ctx) gen_unpack(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]); break; case OPC2_32_RR_CRC32: - if (tricore_feature(ctx->env, TRICORE_FEATURE_161)) { + if (has_feature(ctx, TRICORE_FEATURE_161)) { gen_helper_crc32(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC2_32_RR_DIV: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { GEN_HELPER_RR(divide, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2]); } else { @@ -6713,7 +6718,7 @@ static void decode_rr_divide(DisasContext *ctx) } break; case OPC2_32_RR_DIV_U: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { GEN_HELPER_RR(divide_u, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2]); } else { @@ -8411,7 +8416,7 @@ static void decode_sys_interrupts(DisasContext *ctx) gen_helper_svlcx(cpu_env); break; case OPC2_32_SYS_RESTORE: - if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) { + if (has_feature(ctx, TRICORE_FEATURE_16)) { if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM || (ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_UM1) { tcg_gen_deposit_tl(cpu_ICR, cpu_ICR, cpu_gpr_d[r1], 8, 1); @@ -8792,6 +8797,7 @@ static void tricore_tr_init_disas_context(DisasContextBase *dcbase, CPUTriCoreState *env = cs->env_ptr; ctx->mem_idx = cpu_mmu_index(env, false); ctx->hflags = (uint32_t)ctx->base.tb->flags; + ctx->features = env->features; } static void tricore_tr_tb_start(DisasContextBase *db, CPUState *cpu) From 1ed8739a9ab38f97f901f0988d266b2981627f1b Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Fri, 29 May 2020 09:21:46 +0200 Subject: [PATCH 0785/2595] target/tricore: Raise EXCP_DEBUG in gen_goto_tb() for singlestep this is needed for remote gdb connections. Signed-off-by: Bastian Koppelmann Message-Id: <20200529072148.284037-4-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 608f72d384..7752630ac1 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -3238,6 +3238,14 @@ static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) #endif } +static void generate_qemu_excp(DisasContext *ctx, int excp) +{ + TCGv_i32 tmp = tcg_const_i32(excp); + gen_helper_qemu_excp(cpu_env, tmp); + ctx->base.is_jmp = DISAS_NORETURN; + tcg_temp_free(tmp); +} + static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { if (use_goto_tb(ctx, dest)) { @@ -3247,7 +3255,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) } else { gen_save_pc(dest); if (ctx->base.singlestep_enabled) { - /* raise exception debug */ + generate_qemu_excp(ctx, EXCP_DEBUG); } tcg_gen_exit_tb(NULL, 0); } @@ -3266,14 +3274,6 @@ static void generate_trap(DisasContext *ctx, int class, int tin) tcg_temp_free(tintemp); } -static void generate_qemu_excp(DisasContext *ctx, int excp) -{ - TCGv_i32 tmp = tcg_const_i32(excp); - gen_helper_qemu_excp(cpu_env, tmp); - ctx->base.is_jmp = DISAS_NORETURN; - tcg_temp_free(tmp); -} - static inline void gen_branch_cond(DisasContext *ctx, TCGCond cond, TCGv r1, TCGv r2, int16_t address) { From e00a56dbc3c278c36855fd0b72adc72c8bcf0cf5 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Fri, 29 May 2020 09:21:47 +0200 Subject: [PATCH 0786/2595] target/tricore: Implement tricore_cpu_get_phys_page_debug this also removes tricore_cpu_get_phys_page_attrs_debug() as it was a temporary fix from b190f477e29c7cd03a8fee49c96d27f160e3f5b0. Signed-off-by: Bastian Koppelmann Message-Id: <20200529072148.284037-5-kbastian@mail.uni-paderborn.de> --- target/tricore/cpu.c | 10 +--------- target/tricore/helper.c | 13 +++++++++++++ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 743b404a95..c8c1e9e7d5 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -23,14 +23,6 @@ #include "exec/exec-all.h" #include "qemu/error-report.h" -static hwaddr tricore_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr, - MemTxAttrs *attrs) -{ - error_report("function cpu_get_phys_page_attrs_debug not " - "implemented, aborting"); - return -1; -} - static inline void set_feature(CPUTriCoreState *env, int feature) { env->features |= 1ULL << feature; @@ -161,7 +153,7 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data) cc->dump_state = tricore_cpu_dump_state; cc->set_pc = tricore_cpu_set_pc; cc->synchronize_from_tb = tricore_cpu_synchronize_from_tb; - cc->get_phys_page_attrs_debug = tricore_cpu_get_phys_page_attrs_debug; + cc->get_phys_page_debug = tricore_cpu_get_phys_page_debug; cc->tcg_initialize = tricore_tcg_init; cc->tlb_fill = tricore_cpu_tlb_fill; } diff --git a/target/tricore/helper.c b/target/tricore/helper.c index d5db7b2c03..7715293263 100644 --- a/target/tricore/helper.c +++ b/target/tricore/helper.c @@ -42,6 +42,19 @@ static int get_physical_address(CPUTriCoreState *env, hwaddr *physical, return ret; } + +hwaddr tricore_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + TriCoreCPU *cpu = TRICORE_CPU(cs); + hwaddr phys_addr; + int prot; + int mmu_idx = cpu_mmu_index(&cpu->env, false); + + if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx)) { + return -1; + } + return phys_addr; +} #endif /* TODO: Add exeption support*/ From d127de3baa64d1cabc8e1994e658688abb577ba9 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Fri, 29 May 2020 09:21:48 +0200 Subject: [PATCH 0787/2595] target/tricore: Implement gdbstub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acked-by: Alex Bennée Signed-off-by: Bastian Koppelmann Message-Id: <20200529072148.284037-6-kbastian@mail.uni-paderborn.de> --- target/tricore/Makefile.objs | 2 +- target/tricore/cpu.c | 10 +++ target/tricore/cpu.h | 2 + target/tricore/gdbstub.c | 139 +++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 target/tricore/gdbstub.c diff --git a/target/tricore/Makefile.objs b/target/tricore/Makefile.objs index 7a05670718..281b55f08d 100644 --- a/target/tricore/Makefile.objs +++ b/target/tricore/Makefile.objs @@ -1 +1 @@ -obj-y += translate.o helper.o cpu.o op_helper.o fpu_helper.o +obj-y += translate.o helper.o cpu.o op_helper.o fpu_helper.o gdbstub.o diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index c8c1e9e7d5..2f2e5b029f 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -28,6 +28,11 @@ static inline void set_feature(CPUTriCoreState *env, int feature) env->features |= 1ULL << feature; } +static gchar *tricore_gdb_arch_name(CPUState *cs) +{ + return g_strdup("tricore"); +} + static void tricore_cpu_set_pc(CPUState *cs, vaddr value) { TriCoreCPU *cpu = TRICORE_CPU(cs); @@ -150,6 +155,11 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data) cc->class_by_name = tricore_cpu_class_by_name; cc->has_work = tricore_cpu_has_work; + cc->gdb_read_register = tricore_cpu_gdb_read_register; + cc->gdb_write_register = tricore_cpu_gdb_write_register; + cc->gdb_num_core_regs = 44; + cc->gdb_arch_name = tricore_gdb_arch_name; + cc->dump_state = tricore_cpu_dump_state; cc->set_pc = tricore_cpu_set_pc; cc->synchronize_from_tb = tricore_cpu_synchronize_from_tb; diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h index 8c014fad07..b82349d1b1 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -353,6 +353,8 @@ enum { uint32_t psw_read(CPUTriCoreState *env); void psw_write(CPUTriCoreState *env, uint32_t val); +int tricore_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n); +int tricore_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n); void fpu_set_state(CPUTriCoreState *env); diff --git a/target/tricore/gdbstub.c b/target/tricore/gdbstub.c new file mode 100644 index 0000000000..0f4e612a04 --- /dev/null +++ b/target/tricore/gdbstub.c @@ -0,0 +1,139 @@ +/* + * TriCore gdb server stub + * + * Copyright (c) 2019 Bastian Koppelmann, Paderborn University + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + + +#define LCX_REGNUM 32 +#define FCX_REGNUM 33 +#define PCXI_REGNUM 34 +#define TRICORE_PSW_REGNUM 35 +#define TRICORE_PC_REGNUM 36 +#define ICR_REGNUM 37 +#define ISP_REGNUM 38 +#define BTV_REGNUM 39 +#define BIV_REGNUM 40 +#define SYSCON_REGNUM 41 +#define PMUCON0_REGNUM 42 +#define DMUCON_REGNUM 43 + +static uint32_t tricore_cpu_gdb_read_csfr(CPUTriCoreState *env, int n) +{ + switch (n) { + case LCX_REGNUM: + return env->LCX; + case FCX_REGNUM: + return env->FCX; + case PCXI_REGNUM: + return env->PCXI; + case TRICORE_PSW_REGNUM: + return psw_read(env); + case TRICORE_PC_REGNUM: + return env->PC; + case ICR_REGNUM: + return env->ICR; + case ISP_REGNUM: + return env->ISP; + case BTV_REGNUM: + return env->BTV; + case BIV_REGNUM: + return env->BIV; + case SYSCON_REGNUM: + return env->SYSCON; + case PMUCON0_REGNUM: + return 0; /* PMUCON0 */ + case DMUCON_REGNUM: + return 0; /* DMUCON0 */ + default: + return 0; + } +} + +static void tricore_cpu_gdb_write_csfr(CPUTriCoreState *env, int n, + uint32_t val) +{ + switch (n) { + case LCX_REGNUM: + env->LCX = val; + break; + case FCX_REGNUM: + env->FCX = val; + break; + case PCXI_REGNUM: + env->PCXI = val; + break; + case TRICORE_PSW_REGNUM: + psw_write(env, val); + break; + case TRICORE_PC_REGNUM: + env->PC = val; + break; + case ICR_REGNUM: + env->ICR = val; + break; + case ISP_REGNUM: + env->ISP = val; + break; + case BTV_REGNUM: + env->BTV = val; + break; + case BIV_REGNUM: + env->BIV = val; + break; + case SYSCON_REGNUM: + env->SYSCON = val; + break; + } +} + + +int tricore_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) +{ + TriCoreCPU *cpu = TRICORE_CPU(cs); + CPUTriCoreState *env = &cpu->env; + + if (n < 16) { /* data registers */ + return gdb_get_reg32(mem_buf, env->gpr_d[n]); + } else if (n < 32) { /* address registers */ + return gdb_get_reg32(mem_buf, env->gpr_a[n - 16]); + } else { /* csfr */ + return gdb_get_reg32(mem_buf, tricore_cpu_gdb_read_csfr(env, n)); + } + return 0; +} + +int tricore_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + TriCoreCPU *cpu = TRICORE_CPU(cs); + CPUTriCoreState *env = &cpu->env; + uint32_t tmp; + + tmp = ldl_p(mem_buf); + + if (n < 16) { /* data registers */ + env->gpr_d[n] = tmp; + } else if (n < 32) { /* address registers */ + env->gpr_d[n - 16] = tmp; + } else { + tricore_cpu_gdb_write_csfr(env, n, tmp); + } + return 4; +} From 3b59ee722726d023f4a56d711aef362ab9ba777e Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Fri, 8 May 2020 06:07:54 -0400 Subject: [PATCH 0788/2595] migration/rdma: fix potential nullptr access in rdma_start_incoming_migration 'rdma' is NULL when taking the first error branch in rdma_start_incoming_migration. And it will cause a null pointer access in label 'err'. Fix that. Fixes: 59c59c67ee6b0327ae932deb303caa47919aeb1e Signed-off-by: Pan Nengyuan Message-Id: <20200508100755.7875-2-pannengyuan@huawei.com> Reviewed-by: Juan Quintela Signed-off-by: Dr. David Alan Gilbert Note this is CID 1428762 --- migration/rdma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/migration/rdma.c b/migration/rdma.c index 967fda5b0c..72e8b1c95b 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -4056,7 +4056,9 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) return; err: error_propagate(errp, local_err); - g_free(rdma->host); + if (rdma) { + g_free(rdma->host); + } g_free(rdma); g_free(rdma_return_path); } From 2f0c285aaac5fdc4c5c2f8e03fa8c11e679c50c4 Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Fri, 8 May 2020 06:07:55 -0400 Subject: [PATCH 0789/2595] migration/rdma: cleanup rdma context before g_free to avoid memleaks When error happen in initializing 'rdma_return_path', we should cleanup rdma context before g_free(rdma) to avoid some memleaks. This patch fix that. Reported-by: Euler Robot Signed-off-by: Pan Nengyuan Message-Id: <20200508100755.7875-3-pannengyuan@huawei.com> Reviewed-by: Juan Quintela Signed-off-by: Dr. David Alan Gilbert --- migration/rdma.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 72e8b1c95b..ec45d33ba3 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -4094,20 +4094,20 @@ void rdma_start_outgoing_migration(void *opaque, rdma_return_path = qemu_rdma_data_init(host_port, errp); if (rdma_return_path == NULL) { - goto err; + goto return_path_err; } ret = qemu_rdma_source_init(rdma_return_path, s->enabled_capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp); if (ret) { - goto err; + goto return_path_err; } ret = qemu_rdma_connect(rdma_return_path, errp); if (ret) { - goto err; + goto return_path_err; } rdma->return_path = rdma_return_path; @@ -4120,6 +4120,8 @@ void rdma_start_outgoing_migration(void *opaque, s->to_dst_file = qemu_fopen_rdma(rdma, "wb"); migrate_fd_connect(s, NULL); return; +return_path_err: + qemu_rdma_cleanup(rdma); err: g_free(rdma); g_free(rdma_return_path); From 89cf4fe34f4afa671a2ab5d9430021ea12106274 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 20 May 2020 16:11:07 +0100 Subject: [PATCH 0790/2595] hmp: Implement qom-get HMP command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This started off as Andreas Färber's implementation from March 2015, but after feedback from Paolo and Markus it morphed into using the json output which handles structs reasonably. Use with qom-list to find the members of an object. (qemu) qom-get /backend/console[0]/device/vga.rom[0] size 65536 (qemu) qom-get /machine smm "auto" (qemu) qom-get /machine rtc-time { "tm_year": 120, "tm_sec": 51, "tm_hour": 9, "tm_min": 50, "tm_mon": 4, "tm_mday": 20 } (qemu) qom-get /machine frob Error: Property '.frob' not found Signed-off-by: Dr. David Alan Gilbert Message-Id: <20200520151108.160598-2-dgilbert@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Markus Armbruster Signed-off-by: Dr. David Alan Gilbert --- hmp-commands.hx | 14 ++++++++++++++ include/monitor/hmp.h | 1 + qom/qom-hmp-cmds.c | 18 ++++++++++++++++++ tests/qtest/test-hmp.c | 1 + 4 files changed, 34 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index 7f0f3974ad..250ddae54d 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1790,6 +1790,20 @@ SRST Print QOM properties of object at location *path* ERST + { + .name = "qom-get", + .args_type = "path:s,property:s", + .params = "path property", + .help = "print QOM property", + .cmd = hmp_qom_get, + .flags = "p", + }, + +SRST +``qom-get`` *path* *property* + Print QOM property *property* of object at location *path* +ERST + { .name = "qom-set", .args_type = "path:s,property:s,value:s", diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index e33ca5a911..c986cfd28b 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -96,6 +96,7 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict); void hmp_info_numa(Monitor *mon, const QDict *qdict); void hmp_info_memory_devices(Monitor *mon, const QDict *qdict); void hmp_qom_list(Monitor *mon, const QDict *qdict); +void hmp_qom_get(Monitor *mon, const QDict *qdict); void hmp_qom_set(Monitor *mon, const QDict *qdict); void hmp_info_qom_tree(Monitor *mon, const QDict *dict); void object_add_completion(ReadLineState *rs, int nb_args, const char *str); diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index cd08233a4c..a8b0a080c7 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -12,6 +12,8 @@ #include "qapi/error.h" #include "qapi/qapi-commands-qom.h" #include "qapi/qmp/qdict.h" +#include "qapi/qmp/qjson.h" +#include "qapi/qmp/qstring.h" #include "qom/object.h" void hmp_qom_list(Monitor *mon, const QDict *qdict) @@ -62,6 +64,22 @@ void hmp_qom_set(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } +void hmp_qom_get(Monitor *mon, const QDict *qdict) +{ + const char *path = qdict_get_str(qdict, "path"); + const char *property = qdict_get_str(qdict, "property"); + Error *err = NULL; + QObject *obj = qmp_qom_get(path, property, &err); + + if (err == NULL) { + QString *str = qobject_to_json_pretty(obj); + monitor_printf(mon, "%s\n", qstring_get_str(str)); + qobject_unref(str); + } + + hmp_handle_error(mon, err); +} + typedef struct QOMCompositionState { Monitor *mon; int indent; diff --git a/tests/qtest/test-hmp.c b/tests/qtest/test-hmp.c index f8aa5f92c5..b8b1271b9e 100644 --- a/tests/qtest/test-hmp.c +++ b/tests/qtest/test-hmp.c @@ -61,6 +61,7 @@ static const char *hmp_cmds[] = { "p $pc + 8", "qom-list /", "qom-set /machine initrd test", + "qom-get /machine initrd", "screendump /dev/null", "sendkey x", "singlestep on", From 7d2ef6dcc1cf87e7506487051eda010b479f5d0e Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 20 May 2020 16:11:08 +0100 Subject: [PATCH 0791/2595] hmp: Simplify qom-set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify qom_set by making it use qmp_qom_set and the JSON parser. (qemu) qom-get /machine smm "auto" (qemu) qom-set /machine smm "auto" Signed-off-by: Dr. David Alan Gilbert Message-Id: <20200520151108.160598-3-dgilbert@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Markus Armbruster Signed-off-by: Dr. David Alan Gilbert With 's'->'S' type change suggested by Paolo and Markus --- hmp-commands.hx | 2 +- qom/qom-hmp-cmds.c | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 250ddae54d..28256209b5 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1806,7 +1806,7 @@ ERST { .name = "qom-set", - .args_type = "path:s,property:s,value:s", + .args_type = "path:s,property:s,value:S", .params = "path property value", .help = "set QOM property", .cmd = hmp_qom_set, diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index a8b0a080c7..f704b6949a 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -48,19 +48,13 @@ void hmp_qom_set(Monitor *mon, const QDict *qdict) const char *property = qdict_get_str(qdict, "property"); const char *value = qdict_get_str(qdict, "value"); Error *err = NULL; - bool ambiguous = false; - Object *obj; + QObject *obj; - obj = object_resolve_path(path, &ambiguous); - if (obj == NULL) { - error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", path); - } else { - if (ambiguous) { - monitor_printf(mon, "Warning: Path '%s' is ambiguous\n", path); - } - object_property_parse(obj, value, property, &err); + obj = qobject_from_json(value, &err); + if (err == NULL) { + qmp_qom_set(path, property, obj, &err); } + hmp_handle_error(mon, err); } From 93bb3d8d4cdadf90f714b8ab71b4caa16092f38c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 14 May 2020 16:07:36 +0200 Subject: [PATCH 0792/2595] virtiofsd: remove symlink fallbacks Path lookup in the kernel has special rules for looking up magic symlinks under /proc. If a filesystem operation is instructed to follow symlinks (e.g. via AT_SYMLINK_FOLLOW or lack of AT_SYMLINK_NOFOLLOW), and the final component is such a proc symlink, then the target of the magic symlink is used for the operation, even if the target itself is a symlink. I.e. path lookup is always terminated after following a final magic symlink. I was erronously assuming that in the above case the target symlink would also be followed, and so workarounds were added for a couple of operations to handle the symlink case. Since the symlink can be handled simply by following the proc symlink, these workardouds are not needed. Also remove the "norace" option, which disabled the workarounds. Commit bdfd66788349 ("virtiofsd: Fix xattr operations") already dealt with the same issue for xattr operations. Signed-off-by: Miklos Szeredi Message-Id: <20200514140736.20561-1-mszeredi@redhat.com> Acked-by: Vivek Goyal Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/passthrough_ll.c | 175 ++----------------------------- 1 file changed, 6 insertions(+), 169 deletions(-) diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index 3ba1d90984..2ce7c96085 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -140,7 +140,6 @@ enum { struct lo_data { pthread_mutex_t mutex; int debug; - int norace; int writeback; int flock; int posix_lock; @@ -176,7 +175,6 @@ static const struct fuse_opt lo_opts[] = { { "cache=none", offsetof(struct lo_data, cache), CACHE_NONE }, { "cache=auto", offsetof(struct lo_data, cache), CACHE_AUTO }, { "cache=always", offsetof(struct lo_data, cache), CACHE_ALWAYS }, - { "norace", offsetof(struct lo_data, norace), 1 }, { "readdirplus", offsetof(struct lo_data, readdirplus_set), 1 }, { "no_readdirplus", offsetof(struct lo_data, readdirplus_clear), 1 }, FUSE_OPT_END @@ -592,136 +590,6 @@ static void lo_getattr(fuse_req_t req, fuse_ino_t ino, fuse_reply_attr(req, &buf, lo->timeout); } -/* - * Increments parent->nlookup and caller must release refcount using - * lo_inode_put(&parent). - */ -static int lo_parent_and_name(struct lo_data *lo, struct lo_inode *inode, - char path[PATH_MAX], struct lo_inode **parent) -{ - char procname[64]; - char *last; - struct stat stat; - struct lo_inode *p; - int retries = 2; - int res; - -retry: - sprintf(procname, "%i", inode->fd); - - res = readlinkat(lo->proc_self_fd, procname, path, PATH_MAX); - if (res < 0) { - fuse_log(FUSE_LOG_WARNING, "%s: readlink failed: %m\n", __func__); - goto fail_noretry; - } - - if (res >= PATH_MAX) { - fuse_log(FUSE_LOG_WARNING, "%s: readlink overflowed\n", __func__); - goto fail_noretry; - } - path[res] = '\0'; - - last = strrchr(path, '/'); - if (last == NULL) { - /* Shouldn't happen */ - fuse_log( - FUSE_LOG_WARNING, - "%s: INTERNAL ERROR: bad path read from proc\n", __func__); - goto fail_noretry; - } - if (last == path) { - p = &lo->root; - pthread_mutex_lock(&lo->mutex); - p->nlookup++; - g_atomic_int_inc(&p->refcount); - pthread_mutex_unlock(&lo->mutex); - } else { - *last = '\0'; - res = fstatat(AT_FDCWD, last == path ? "/" : path, &stat, 0); - if (res == -1) { - if (!retries) { - fuse_log(FUSE_LOG_WARNING, - "%s: failed to stat parent: %m\n", __func__); - } - goto fail; - } - p = lo_find(lo, &stat); - if (p == NULL) { - if (!retries) { - fuse_log(FUSE_LOG_WARNING, - "%s: failed to find parent\n", __func__); - } - goto fail; - } - } - last++; - res = fstatat(p->fd, last, &stat, AT_SYMLINK_NOFOLLOW); - if (res == -1) { - if (!retries) { - fuse_log(FUSE_LOG_WARNING, - "%s: failed to stat last\n", __func__); - } - goto fail_unref; - } - if (stat.st_dev != inode->key.dev || stat.st_ino != inode->key.ino) { - if (!retries) { - fuse_log(FUSE_LOG_WARNING, - "%s: failed to match last\n", __func__); - } - goto fail_unref; - } - *parent = p; - memmove(path, last, strlen(last) + 1); - - return 0; - -fail_unref: - unref_inode_lolocked(lo, p, 1); - lo_inode_put(lo, &p); -fail: - if (retries) { - retries--; - goto retry; - } -fail_noretry: - errno = EIO; - return -1; -} - -static int utimensat_empty(struct lo_data *lo, struct lo_inode *inode, - const struct timespec *tv) -{ - int res; - struct lo_inode *parent; - char path[PATH_MAX]; - - if (S_ISLNK(inode->filetype)) { - res = utimensat(inode->fd, "", tv, AT_EMPTY_PATH); - if (res == -1 && errno == EINVAL) { - /* Sorry, no race free way to set times on symlink. */ - if (lo->norace) { - errno = EPERM; - } else { - goto fallback; - } - } - return res; - } - sprintf(path, "%i", inode->fd); - - return utimensat(lo->proc_self_fd, path, tv, 0); - -fallback: - res = lo_parent_and_name(lo, inode, path, &parent); - if (res != -1) { - res = utimensat(parent->fd, path, tv, AT_SYMLINK_NOFOLLOW); - unref_inode_lolocked(lo, parent, 1); - lo_inode_put(lo, &parent); - } - - return res; -} - static int lo_fi_fd(fuse_req_t req, struct fuse_file_info *fi) { struct lo_data *lo = lo_data(req); @@ -828,7 +696,8 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, if (fi) { res = futimens(fd, tv); } else { - res = utimensat_empty(lo, inode, tv); + sprintf(procname, "%i", inode->fd); + res = utimensat(lo->proc_self_fd, procname, tv, 0); } if (res == -1) { goto out_err; @@ -1129,41 +998,6 @@ static void lo_symlink(fuse_req_t req, const char *link, fuse_ino_t parent, lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link); } -static int linkat_empty_nofollow(struct lo_data *lo, struct lo_inode *inode, - int dfd, const char *name) -{ - int res; - struct lo_inode *parent; - char path[PATH_MAX]; - - if (S_ISLNK(inode->filetype)) { - res = linkat(inode->fd, "", dfd, name, AT_EMPTY_PATH); - if (res == -1 && (errno == ENOENT || errno == EINVAL)) { - /* Sorry, no race free way to hard-link a symlink. */ - if (lo->norace) { - errno = EPERM; - } else { - goto fallback; - } - } - return res; - } - - sprintf(path, "%i", inode->fd); - - return linkat(lo->proc_self_fd, path, dfd, name, AT_SYMLINK_FOLLOW); - -fallback: - res = lo_parent_and_name(lo, inode, path, &parent); - if (res != -1) { - res = linkat(parent->fd, path, dfd, name, 0); - unref_inode_lolocked(lo, parent, 1); - lo_inode_put(lo, &parent); - } - - return res; -} - static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent, const char *name) { @@ -1172,6 +1006,7 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent, struct lo_inode *parent_inode; struct lo_inode *inode; struct fuse_entry_param e; + char procname[64]; int saverr; if (!is_safe_path_component(name)) { @@ -1190,7 +1025,9 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent, e.attr_timeout = lo->timeout; e.entry_timeout = lo->timeout; - res = linkat_empty_nofollow(lo, inode, parent_inode->fd, name); + sprintf(procname, "%i", inode->fd); + res = linkat(lo->proc_self_fd, procname, parent_inode->fd, name, + AT_SYMLINK_FOLLOW); if (res == -1) { goto out_err; } From e0d138aa9b3a4c72fe8bca735686132fdea646b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 30 May 2020 18:55:12 +0200 Subject: [PATCH 0793/2595] migration/vmstate: Remove unnecessary MemoryRegion forward declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "migration/vmstate.h" only uses pointer to MemoryRegion, which is already forward declared in "qemu/typedefs.h". Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200530165512.15225-1-f4bug@amsat.org> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- include/migration/vmstate.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 30667631bc..eafa39f560 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -1199,7 +1199,6 @@ static inline int vmstate_register(VMStateIf *obj, int instance_id, void vmstate_unregister(VMStateIf *obj, const VMStateDescription *vmsd, void *opaque); -struct MemoryRegion; void vmstate_register_ram(struct MemoryRegion *memory, DeviceState *dev); void vmstate_unregister_ram(struct MemoryRegion *memory, DeviceState *dev); void vmstate_register_ram_global(struct MemoryRegion *memory); From bb70b66ed7a5600a63437fb6d64dedb44f670e58 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Mon, 11 May 2020 13:10:44 +0200 Subject: [PATCH 0794/2595] migration/colo.c: Use event instead of semaphore If multiple packets miscompare in a short timeframe, the semaphore value will be increased multiple times. This causes multiple checkpoints even if one would be sufficient. Fix this by using a event instead of a semaphore for triggering checkpoints. Now, checkpoint requests will be ignored until the checkpoint event is sent to colo-compare (which releases the miscompared packets). Benchmark results (iperf3): Client-to-server tcp: without patch: ~66 Mbit/s with patch: ~61 Mbit/s Server-to-client tcp: without patch: ~702 Kbit/s with patch: ~16 Mbit/s Signed-off-by: Lukas Straub Message-Id: Reviewed-by: zhanghailiang Signed-off-by: Dr. David Alan Gilbert --- migration/colo.c | 9 +++++---- migration/migration.h | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/migration/colo.c b/migration/colo.c index d015d4f84e..fe0d6e93e5 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -436,6 +436,7 @@ static int colo_do_checkpoint_transaction(MigrationState *s, goto out; } + qemu_event_reset(&s->colo_checkpoint_event); colo_notify_compares_event(NULL, COLO_EVENT_CHECKPOINT, &local_err); if (local_err) { goto out; @@ -589,7 +590,7 @@ static void colo_process_checkpoint(MigrationState *s) goto out; } - qemu_sem_wait(&s->colo_checkpoint_sem); + qemu_event_wait(&s->colo_checkpoint_event); if (s->state != MIGRATION_STATUS_COLO) { goto out; @@ -637,7 +638,7 @@ out: colo_compare_unregister_notifier(&packets_compare_notifier); timer_del(s->colo_delay_timer); timer_free(s->colo_delay_timer); - qemu_sem_destroy(&s->colo_checkpoint_sem); + qemu_event_destroy(&s->colo_checkpoint_event); /* * Must be called after failover BH is completed, @@ -654,7 +655,7 @@ void colo_checkpoint_notify(void *opaque) MigrationState *s = opaque; int64_t next_notify_time; - qemu_sem_post(&s->colo_checkpoint_sem); + qemu_event_set(&s->colo_checkpoint_event); s->colo_checkpoint_time = qemu_clock_get_ms(QEMU_CLOCK_HOST); next_notify_time = s->colo_checkpoint_time + s->parameters.x_checkpoint_delay; @@ -664,7 +665,7 @@ void colo_checkpoint_notify(void *opaque) void migrate_start_colo_process(MigrationState *s) { qemu_mutex_unlock_iothread(); - qemu_sem_init(&s->colo_checkpoint_sem, 0); + qemu_event_init(&s->colo_checkpoint_event, false); s->colo_delay_timer = timer_new_ms(QEMU_CLOCK_HOST, colo_checkpoint_notify, s); diff --git a/migration/migration.h b/migration/migration.h index 507284e563..f617960522 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -215,8 +215,8 @@ struct MigrationState /* The semaphore is used to notify COLO thread that failover is finished */ QemuSemaphore colo_exit_sem; - /* The semaphore is used to notify COLO thread to do checkpoint */ - QemuSemaphore colo_checkpoint_sem; + /* The event is used to notify COLO thread to do checkpoint */ + QemuEvent colo_checkpoint_event; int64_t colo_checkpoint_time; QEMUTimer *colo_delay_timer; From 786d8b8e38b134f99556e08047e016563b7063f9 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Mon, 11 May 2020 13:10:48 +0200 Subject: [PATCH 0795/2595] migration/colo.c: Use cpu_synchronize_all_states() cpu_synchronize_all_pre_loadvm() marks all vcpus as dirty, so the registers are loaded from CPUState before we continue running the vm. However if we failover during checkpoint, CPUState is not initialized and the registers are loaded with garbage. This causes guest hangs and crashes. Fix this by using cpu_synchronize_all_states(), which initializes CPUState from the current cpu registers additionally to marking the vcpus as dirty. Signed-off-by: Lukas Straub Message-Id: <9675031ce557b73ebd10e7bd20ebbf57f30b177c.1589193382.git.lukasstraub2@web.de> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- migration/colo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/colo.c b/migration/colo.c index fe0d6e93e5..d00b3b9d6b 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -705,7 +705,7 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis, } qemu_mutex_lock_iothread(); - cpu_synchronize_all_pre_loadvm(); + cpu_synchronize_all_states(); ret = qemu_loadvm_state_main(mis->from_src_file, mis); qemu_mutex_unlock_iothread(); From 24fa16f8cc374935458672b027829180ea4b4460 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Mon, 11 May 2020 13:10:51 +0200 Subject: [PATCH 0796/2595] migration/colo.c: Flush ram cache only after receiving device state If we suceed in receiving ram state, but fail receiving the device state, there will be a mismatch between the two. Fix this by flushing the ram cache only after the vmstate has been received. Signed-off-by: Lukas Straub Message-Id: <3289d007d494cb0e2f05b1cf4ae6a78d300fede3.1589193382.git.lukasstraub2@web.de> Reviewed-by: zhanghailiang Signed-off-by: Dr. David Alan Gilbert --- migration/colo.c | 1 + migration/ram.c | 5 +---- migration/ram.h | 1 + 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/migration/colo.c b/migration/colo.c index d00b3b9d6b..4105999634 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -748,6 +748,7 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis, qemu_mutex_lock_iothread(); vmstate_loading = true; + colo_flush_ram_cache(); ret = qemu_load_device_state(fb); if (ret < 0) { error_setg(errp, "COLO: load device state failed"); diff --git a/migration/ram.c b/migration/ram.c index 859f835f1a..41cc530d9d 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3360,7 +3360,7 @@ static bool postcopy_is_running(void) * Flush content of RAM cache into SVM's memory. * Only flush the pages that be dirtied by PVM or SVM or both. */ -static void colo_flush_ram_cache(void) +void colo_flush_ram_cache(void) { RAMBlock *block = NULL; void *dst_host; @@ -3632,9 +3632,6 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) } trace_ram_load_complete(ret, seq_iter); - if (!ret && migration_incoming_in_colo_state()) { - colo_flush_ram_cache(); - } return ret; } diff --git a/migration/ram.h b/migration/ram.h index 5ceaff7cb4..2eeaacfa13 100644 --- a/migration/ram.h +++ b/migration/ram.h @@ -65,6 +65,7 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *rb); /* ram cache */ int colo_init_ram_cache(void); +void colo_flush_ram_cache(void); void colo_release_ram_cache(void); void colo_incoming_start_dirty_log(void); From 92c932de6c4a2b25826201e9d0740207136953c6 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Mon, 11 May 2020 13:10:55 +0200 Subject: [PATCH 0797/2595] migration/colo.c: Relaunch failover even if there was an error If vmstate_loading is true, secondary_vm_do_failover will set failover status to FAILOVER_STATUS_RELAUNCH and return success without initiating failover. However, if there is an error during the vmstate_loading section, failover isn't relaunched. Instead we then wait for failover on colo_incoming_sem. Fix this by relaunching failover even if there was an error. Also, to make this work properly, set vmstate_loading to false when returning during the vmstate_loading section. Signed-off-by: Lukas Straub Message-Id: Reviewed-by: zhanghailiang Signed-off-by: Dr. David Alan Gilbert --- migration/colo.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/migration/colo.c b/migration/colo.c index 4105999634..59639f519f 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -752,6 +752,7 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis, ret = qemu_load_device_state(fb); if (ret < 0) { error_setg(errp, "COLO: load device state failed"); + vmstate_loading = false; qemu_mutex_unlock_iothread(); return; } @@ -760,6 +761,7 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis, replication_get_error_all(&local_err); if (local_err) { error_propagate(errp, local_err); + vmstate_loading = false; qemu_mutex_unlock_iothread(); return; } @@ -768,6 +770,7 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis, replication_do_checkpoint_all(&local_err); if (local_err) { error_propagate(errp, local_err); + vmstate_loading = false; qemu_mutex_unlock_iothread(); return; } @@ -779,6 +782,7 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis, if (local_err) { error_propagate(errp, local_err); + vmstate_loading = false; qemu_mutex_unlock_iothread(); return; } @@ -789,9 +793,6 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis, qemu_mutex_unlock_iothread(); if (failover_get_state() == FAILOVER_STATUS_RELAUNCH) { - failover_set_state(FAILOVER_STATUS_RELAUNCH, - FAILOVER_STATUS_NONE); - failover_request_active(NULL); return; } @@ -890,6 +891,14 @@ void *colo_process_incoming_thread(void *opaque) error_report_err(local_err); break; } + + if (failover_get_state() == FAILOVER_STATUS_RELAUNCH) { + failover_set_state(FAILOVER_STATUS_RELAUNCH, + FAILOVER_STATUS_NONE); + failover_request_active(NULL); + break; + } + if (failover_get_state() != FAILOVER_STATUS_NONE) { error_report("failover request"); break; @@ -897,8 +906,6 @@ void *colo_process_incoming_thread(void *opaque) } out: - vmstate_loading = false; - /* * There are only two reasons we can get here, some error happened * or the user triggered failover. From 4fa8ed25b8dc996d92c60fb6b63752593be5f3a4 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Mon, 11 May 2020 13:11:01 +0200 Subject: [PATCH 0798/2595] migration/colo.c: Move colo_notify_compares_event to the right place If the secondary has to failover during checkpointing, it still is in the old state (i.e. different state than primary). Thus we can't expose the primary state until after the checkpoint is sent. This fixes sporadic connection reset of client connections during failover. Signed-off-by: Lukas Straub Message-Id: Reviewed-by: zhanghailiang Signed-off-by: Dr. David Alan Gilbert --- migration/colo.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/migration/colo.c b/migration/colo.c index 59639f519f..ea7d1e9d4e 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -436,12 +436,6 @@ static int colo_do_checkpoint_transaction(MigrationState *s, goto out; } - qemu_event_reset(&s->colo_checkpoint_event); - colo_notify_compares_event(NULL, COLO_EVENT_CHECKPOINT, &local_err); - if (local_err) { - goto out; - } - /* Disable block migration */ migrate_set_block_enabled(false, &local_err); if (local_err) { @@ -503,6 +497,12 @@ static int colo_do_checkpoint_transaction(MigrationState *s, goto out; } + qemu_event_reset(&s->colo_checkpoint_event); + colo_notify_compares_event(NULL, COLO_EVENT_CHECKPOINT, &local_err); + if (local_err) { + goto out; + } + colo_receive_check_message(s->rp_state.from_dst_file, COLO_MESSAGE_VMSTATE_LOADED, &local_err); if (local_err) { From 773861274ad75a62c7ecf70ecc8e4ba31ed62190 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Wed, 20 May 2020 22:42:32 +0200 Subject: [PATCH 0799/2595] migration/migration.c: Fix hang in ram_save_host_page migration_rate_limit will erroneously ratelimit a shutdown socket, which causes the migration thread to hang in ram_save_host_page if the socket is shutdown. Fix this by explicitly testing if the socket has errors or was shutdown in migration_rate_limit. Signed-off-by: Lukas Straub Message-Id: Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/migration/migration.c b/migration/migration.c index 0bb042a0f7..b63ad91d34 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3361,6 +3361,10 @@ bool migration_rate_limit(void) bool urgent = false; migration_update_counters(s, now); if (qemu_file_rate_limit(s->to_dst_file)) { + + if (qemu_file_get_error(s->to_dst_file)) { + return false; + } /* * Wait for a delay to do rate limiting OR * something urgent to post the semaphore. From 6a0e8bb4956c34328f4624e20bd3a6c2b1d90adc Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 31 May 2020 13:02:31 +0200 Subject: [PATCH 0800/2595] target/m68k: implement fmove.l #,FPCR The immediate value mode was ignored and instruction execution ends to an invalid access mode. This was found running 'R' that set FPSR to 0 at startup with a 'fmove.l #0,FPSR' in qemu-system-m68k emulation and triggers a kernel crash: [ 56.640000] *** ADDRESS ERROR *** FORMAT=2 [ 56.640000] Current process id is 728 [ 56.640000] BAD KERNEL TRAP: 00000000 [ 56.640000] Modules linked in: sg evdev mac_hid ip_tables x_tables sha1_generic hmac ipv6 nf_defrag_ipv6 autofs4 ext4 crc16 mbcache jbd2 crc32c_generic sd_mod t10_pi crc_t10dif crct10dif_generic crct10dif_common sr_mod cdrom mac_esp macsonic esp_scsi [ 56.640000] PC: [<00016a2c>] X_UNSUPP+0x2c/0x3c [ 56.640000] SR: 2004 SP: 3eb5e68c a2: c02e239a [ 56.640000] d0: 00000040 d1: 00000002 d2: 8002adec d3: 8002ad50 [ 56.640000] d4: 8002c768 d5: 0000000d a0: ffffffc2 a1: ffffffc1 [ 56.640000] Process R (pid: 728, task=a3dfda5d) [ 56.640000] Frame format=2 instr addr=00000000 [ 56.650000] Stack from 3a4d9f30: [ 56.650000] 41000000 00000002 00000002 ffffffc2 ffffffc1 1fff0000 80000000 00000000 [ 56.650000] 3fbf0000 80000000 00000000 00000000 20000000 00000000 7fff0000 ffffffff [ 56.650000] ffffffff 00000000 00050008 00000000 8000067c c02c2000 efffee20 000002d8 [ 56.650000] 00002a28 3a4d9f98 00000002 00000014 fffffffe 8002c768 00000002 00000041 [ 56.650000] 00000002 c041fc58 c0743758 ffffffff 00000000 0008c075 00002b24 00000012 [ 56.650000] 000007d0 00000024 00000002 c05bef04 c05bef04 0000005e 00000077 c28aca70 [ 56.650000] Call Trace: [<00050008>] copy_overflow+0x10/0x28 [ 56.650000] [<00002a28>] buserr+0x20/0x28 [ 56.650000] [<0008c075>] bpf_check+0x57f/0x1cfa [ 56.650000] [<00002b24>] syscall+0x8/0xc [ 56.650000] [<0000c019>] dn_sched_init+0x75/0x88 [ 56.650000] Code: 1017 0200 00f0 0c00 0040 66ff 0000 05ac 8800 0000 0000 f23c 9000 0000 0000 222e ff84 082e 0005 ff1c 6600 000a 0281 [ 56.650000] Disabling lock debugging due to kernel taint ... Reported-by: John Paul Adrian Glaubitz Signed-off-by: Laurent Vivier Tested-by: John Paul Adrian Glaubitz Reviewed-by: Richard Henderson Message-Id: <20200531110231.620711-1-laurent@vivier.eu> Signed-off-by: Laurent Vivier --- target/m68k/translate.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 0f80888203..c093f6c683 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4936,6 +4936,20 @@ static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s, gen_store_fcr(s, AREG(insn, 0), mask); } return; + case 7: /* Immediate */ + if (REG(insn, 0) == 4) { + if (is_write || + (mask != M68K_FPIAR && mask != M68K_FPSR && + mask != M68K_FPCR)) { + gen_exception(s, s->base.pc_next, EXCP_ILLEGAL); + return; + } + tmp = tcg_const_i32(read_im32(env, s)); + gen_store_fcr(s, tmp, mask); + tcg_temp_free(tmp); + return; + } + break; default: break; } From 250b1da35d579f42319af234f36207902ca4baa4 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 31 May 2020 15:19:51 +0200 Subject: [PATCH 0801/2595] target/m68k: implement opcode fetoxm1 Example provided in the launchpad bug fails with: qemu: uncaught target signal 4 (Illegal instruction) - core dumped Illegal instruction (core dumped) It appears fetoxm1 is not implemented: IN: expm1f 0x800005cc: fetoxm1x %fp2,%fp0 Disassembler disagrees with translator over instruction decoding Please report this to qemu-devel@nongnu.org (gdb) x/2hx 0x800005cc 0x800005cc: 0xf200 0x0808 This patch adds the instruction. Bug: https://bugs.launchpad.net/qemu/+bug/1881450 Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20200531131951.631902-1-laurent@vivier.eu> Signed-off-by: Laurent Vivier --- target/m68k/fpu_helper.c | 5 +++++ target/m68k/helper.h | 1 + target/m68k/translate.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index 36e6c704d1..9acf60dfd4 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -641,6 +641,11 @@ void HELPER(fatanh)(CPUM68KState *env, FPReg *res, FPReg *val) res->d = floatx80_atanh(val->d, &env->fp_status); } +void HELPER(fetoxm1)(CPUM68KState *env, FPReg *res, FPReg *val) +{ + res->d = floatx80_etoxm1(val->d, &env->fp_status); +} + void HELPER(ftanh)(CPUM68KState *env, FPReg *res, FPReg *val) { res->d = floatx80_tanh(val->d, &env->fp_status); diff --git a/target/m68k/helper.h b/target/m68k/helper.h index feee7be626..77808497a9 100644 --- a/target/m68k/helper.h +++ b/target/m68k/helper.h @@ -83,6 +83,7 @@ DEF_HELPER_3(fatan, void, env, fp, fp) DEF_HELPER_3(fasin, void, env, fp, fp) DEF_HELPER_3(facos, void, env, fp, fp) DEF_HELPER_3(fatanh, void, env, fp, fp) +DEF_HELPER_3(fetoxm1, void, env, fp, fp) DEF_HELPER_3(ftanh, void, env, fp, fp) DEF_HELPER_3(fsinh, void, env, fp, fp) DEF_HELPER_3(fcosh, void, env, fp, fp) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index c093f6c683..3fc67aa452 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -5160,6 +5160,9 @@ DISAS_INSN(fpu) case 0x06: /* flognp1 */ gen_helper_flognp1(cpu_env, cpu_dest, cpu_src); break; + case 0x08: /* fetoxm1 */ + gen_helper_fetoxm1(cpu_env, cpu_dest, cpu_src); + break; case 0x09: /* ftanh */ gen_helper_ftanh(cpu_env, cpu_dest, cpu_src); break; From b0f7e7444c03da17e41bf327c8aea590104a28ab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 19 Apr 2020 18:01:52 -0700 Subject: [PATCH 0802/2595] tcg: Implement gvec support for rotate by immediate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No host backend support yet, but the interfaces for rotli are in place. Canonicalize immediate rotate to the left, based on a survey of architectures, but provide both left and right shift interfaces to the translators. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- accel/tcg/tcg-runtime-gvec.c | 48 +++++++++++++++++++++++++ accel/tcg/tcg-runtime.h | 5 +++ include/tcg/tcg-op-gvec.h | 6 ++++ include/tcg/tcg-op.h | 2 ++ include/tcg/tcg-opc.h | 1 + include/tcg/tcg.h | 1 + tcg/README | 3 +- tcg/aarch64/tcg-target.h | 1 + tcg/i386/tcg-target.h | 1 + tcg/ppc/tcg-target.h | 1 + tcg/tcg-op-gvec.c | 68 ++++++++++++++++++++++++++++++++++++ tcg/tcg-op-vec.c | 12 +++++++ tcg/tcg.c | 2 ++ 13 files changed, 150 insertions(+), 1 deletion(-) diff --git a/accel/tcg/tcg-runtime-gvec.c b/accel/tcg/tcg-runtime-gvec.c index ca449702e6..34b1030365 100644 --- a/accel/tcg/tcg-runtime-gvec.c +++ b/accel/tcg/tcg-runtime-gvec.c @@ -716,6 +716,54 @@ void HELPER(gvec_sar64i)(void *d, void *a, uint32_t desc) clear_high(d, oprsz, desc); } +void HELPER(gvec_rotl8i)(void *d, void *a, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + int shift = simd_data(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint8_t)) { + *(uint8_t *)(d + i) = rol8(*(uint8_t *)(a + i), shift); + } + clear_high(d, oprsz, desc); +} + +void HELPER(gvec_rotl16i)(void *d, void *a, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + int shift = simd_data(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint16_t)) { + *(uint16_t *)(d + i) = rol16(*(uint16_t *)(a + i), shift); + } + clear_high(d, oprsz, desc); +} + +void HELPER(gvec_rotl32i)(void *d, void *a, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + int shift = simd_data(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint32_t)) { + *(uint32_t *)(d + i) = rol32(*(uint32_t *)(a + i), shift); + } + clear_high(d, oprsz, desc); +} + +void HELPER(gvec_rotl64i)(void *d, void *a, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + int shift = simd_data(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint64_t)) { + *(uint64_t *)(d + i) = rol64(*(uint64_t *)(a + i), shift); + } + clear_high(d, oprsz, desc); +} + void HELPER(gvec_shl8v)(void *d, void *a, void *b, uint32_t desc) { intptr_t oprsz = simd_oprsz(desc); diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index 4fa61b49b4..cf10c8361e 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -259,6 +259,11 @@ DEF_HELPER_FLAGS_3(gvec_sar16i, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(gvec_sar32i, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(gvec_sar64i, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_rotl8i, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_rotl16i, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_rotl32i, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_rotl64i, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + DEF_HELPER_FLAGS_4(gvec_shl8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_shl16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_shl32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/include/tcg/tcg-op-gvec.h b/include/tcg/tcg-op-gvec.h index cea6497341..1afc3ebf03 100644 --- a/include/tcg/tcg-op-gvec.h +++ b/include/tcg/tcg-op-gvec.h @@ -334,6 +334,10 @@ void tcg_gen_gvec_shri(unsigned vece, uint32_t dofs, uint32_t aofs, int64_t shift, uint32_t oprsz, uint32_t maxsz); void tcg_gen_gvec_sari(unsigned vece, uint32_t dofs, uint32_t aofs, int64_t shift, uint32_t oprsz, uint32_t maxsz); +void tcg_gen_gvec_rotli(unsigned vece, uint32_t dofs, uint32_t aofs, + int64_t shift, uint32_t oprsz, uint32_t maxsz); +void tcg_gen_gvec_rotri(unsigned vece, uint32_t dofs, uint32_t aofs, + int64_t shift, uint32_t oprsz, uint32_t maxsz); void tcg_gen_gvec_shls(unsigned vece, uint32_t dofs, uint32_t aofs, TCGv_i32 shift, uint32_t oprsz, uint32_t maxsz); @@ -388,5 +392,7 @@ void tcg_gen_vec_shr8i_i64(TCGv_i64 d, TCGv_i64 a, int64_t); void tcg_gen_vec_shr16i_i64(TCGv_i64 d, TCGv_i64 a, int64_t); void tcg_gen_vec_sar8i_i64(TCGv_i64 d, TCGv_i64 a, int64_t); void tcg_gen_vec_sar16i_i64(TCGv_i64 d, TCGv_i64 a, int64_t); +void tcg_gen_vec_rotl8i_i64(TCGv_i64 d, TCGv_i64 a, int64_t c); +void tcg_gen_vec_rotl16i_i64(TCGv_i64 d, TCGv_i64 a, int64_t c); #endif diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index e3399d6a5e..848d91ce74 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -999,6 +999,8 @@ void tcg_gen_umax_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b); void tcg_gen_shli_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i); void tcg_gen_shri_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i); void tcg_gen_sari_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i); +void tcg_gen_rotli_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i); +void tcg_gen_rotri_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i); void tcg_gen_shls_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s); void tcg_gen_shrs_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s); diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 9288a04946..a6ab4a147f 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -248,6 +248,7 @@ DEF(not_vec, 1, 1, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_not_vec)) DEF(shli_vec, 1, 1, 1, IMPLVEC | IMPL(TCG_TARGET_HAS_shi_vec)) DEF(shri_vec, 1, 1, 1, IMPLVEC | IMPL(TCG_TARGET_HAS_shi_vec)) DEF(sari_vec, 1, 1, 1, IMPLVEC | IMPL(TCG_TARGET_HAS_shi_vec)) +DEF(rotli_vec, 1, 1, 1, IMPLVEC | IMPL(TCG_TARGET_HAS_roti_vec)) DEF(shls_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shs_vec)) DEF(shrs_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shs_vec)) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index c48bd76b0a..56bedbd03b 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -182,6 +182,7 @@ typedef uint64_t TCGRegSet; #define TCG_TARGET_HAS_not_vec 0 #define TCG_TARGET_HAS_andc_vec 0 #define TCG_TARGET_HAS_orc_vec 0 +#define TCG_TARGET_HAS_roti_vec 0 #define TCG_TARGET_HAS_shi_vec 0 #define TCG_TARGET_HAS_shs_vec 0 #define TCG_TARGET_HAS_shv_vec 0 diff --git a/tcg/README b/tcg/README index bfa2e4ed24..1e3e4654f4 100644 --- a/tcg/README +++ b/tcg/README @@ -605,10 +605,11 @@ E.g. VECL=1 -> 64 << 1 -> v128, and VECE=2 -> 1 << 2 -> i32. * shri_vec v0, v1, i2 * sari_vec v0, v1, i2 +* rotli_vec v0, v1, i2 * shrs_vec v0, v1, s2 * sars_vec v0, v1, s2 - Similarly for logical and arithmetic right shift. + Similarly for logical and arithmetic right shift, and left rotate. * shlv_vec v0, v1, v2 diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index ca214f6909..225a597f84 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -133,6 +133,7 @@ typedef enum { #define TCG_TARGET_HAS_not_vec 1 #define TCG_TARGET_HAS_neg_vec 1 #define TCG_TARGET_HAS_abs_vec 1 +#define TCG_TARGET_HAS_roti_vec 0 #define TCG_TARGET_HAS_shi_vec 1 #define TCG_TARGET_HAS_shs_vec 0 #define TCG_TARGET_HAS_shv_vec 1 diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index bfb3f5f6e9..23aabde992 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -183,6 +183,7 @@ extern bool have_avx2; #define TCG_TARGET_HAS_not_vec 0 #define TCG_TARGET_HAS_neg_vec 0 #define TCG_TARGET_HAS_abs_vec 1 +#define TCG_TARGET_HAS_roti_vec 0 #define TCG_TARGET_HAS_shi_vec 1 #define TCG_TARGET_HAS_shs_vec 1 #define TCG_TARGET_HAS_shv_vec have_avx2 diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 4fa21f0e71..e57b891aa5 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -161,6 +161,7 @@ extern bool have_vsx; #define TCG_TARGET_HAS_not_vec 1 #define TCG_TARGET_HAS_neg_vec have_isa_3_00 #define TCG_TARGET_HAS_abs_vec 0 +#define TCG_TARGET_HAS_roti_vec 0 #define TCG_TARGET_HAS_shi_vec 0 #define TCG_TARGET_HAS_shs_vec 0 #define TCG_TARGET_HAS_shv_vec 1 diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 049a55e700..25300b1577 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -2694,6 +2694,74 @@ void tcg_gen_gvec_sari(unsigned vece, uint32_t dofs, uint32_t aofs, } } +void tcg_gen_vec_rotl8i_i64(TCGv_i64 d, TCGv_i64 a, int64_t c) +{ + uint64_t mask = dup_const(MO_8, 0xff << c); + + tcg_gen_shli_i64(d, a, c); + tcg_gen_shri_i64(a, a, 8 - c); + tcg_gen_andi_i64(d, d, mask); + tcg_gen_andi_i64(a, a, ~mask); + tcg_gen_or_i64(d, d, a); +} + +void tcg_gen_vec_rotl16i_i64(TCGv_i64 d, TCGv_i64 a, int64_t c) +{ + uint64_t mask = dup_const(MO_16, 0xffff << c); + + tcg_gen_shli_i64(d, a, c); + tcg_gen_shri_i64(a, a, 16 - c); + tcg_gen_andi_i64(d, d, mask); + tcg_gen_andi_i64(a, a, ~mask); + tcg_gen_or_i64(d, d, a); +} + +void tcg_gen_gvec_rotli(unsigned vece, uint32_t dofs, uint32_t aofs, + int64_t shift, uint32_t oprsz, uint32_t maxsz) +{ + static const TCGOpcode vecop_list[] = { INDEX_op_rotli_vec, 0 }; + static const GVecGen2i g[4] = { + { .fni8 = tcg_gen_vec_rotl8i_i64, + .fniv = tcg_gen_rotli_vec, + .fno = gen_helper_gvec_rotl8i, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fni8 = tcg_gen_vec_rotl16i_i64, + .fniv = tcg_gen_rotli_vec, + .fno = gen_helper_gvec_rotl16i, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = tcg_gen_rotli_i32, + .fniv = tcg_gen_rotli_vec, + .fno = gen_helper_gvec_rotl32i, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = tcg_gen_rotli_i64, + .fniv = tcg_gen_rotli_vec, + .fno = gen_helper_gvec_rotl64i, + .opt_opc = vecop_list, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .vece = MO_64 }, + }; + + tcg_debug_assert(vece <= MO_64); + tcg_debug_assert(shift >= 0 && shift < (8 << vece)); + if (shift == 0) { + tcg_gen_gvec_mov(vece, dofs, aofs, oprsz, maxsz); + } else { + tcg_gen_gvec_2i(dofs, aofs, oprsz, maxsz, shift, &g[vece]); + } +} + +void tcg_gen_gvec_rotri(unsigned vece, uint32_t dofs, uint32_t aofs, + int64_t shift, uint32_t oprsz, uint32_t maxsz) +{ + tcg_debug_assert(vece <= MO_64); + tcg_debug_assert(shift >= 0 && shift < (8 << vece)); + tcg_gen_gvec_rotli(vece, dofs, aofs, -shift & ((8 << vece) - 1), + oprsz, maxsz); +} + /* * Specialized generation vector shifts by a non-constant scalar. */ diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c index b6937e8d64..660ad9be88 100644 --- a/tcg/tcg-op-vec.c +++ b/tcg/tcg-op-vec.c @@ -545,6 +545,18 @@ void tcg_gen_sari_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i) do_shifti(INDEX_op_sari_vec, vece, r, a, i); } +void tcg_gen_rotli_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i) +{ + do_shifti(INDEX_op_rotli_vec, vece, r, a, i); +} + +void tcg_gen_rotri_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i) +{ + int bits = 8 << vece; + tcg_debug_assert(i >= 0 && i < bits); + do_shifti(INDEX_op_rotli_vec, vece, r, a, -i & (bits - 1)); +} + void tcg_gen_cmp_vec(TCGCond cond, unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) { diff --git a/tcg/tcg.c b/tcg/tcg.c index a2268d9db0..73a3a4fb9e 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1661,6 +1661,8 @@ bool tcg_op_supported(TCGOpcode op) case INDEX_op_shrv_vec: case INDEX_op_sarv_vec: return have_vec && TCG_TARGET_HAS_shv_vec; + case INDEX_op_rotli_vec: + return have_vec && TCG_TARGET_HAS_roti_vec; case INDEX_op_ssadd_vec: case INDEX_op_usadd_vec: case INDEX_op_sssub_vec: From 5d0ceda902915e3f0e21c39d142c92c4e97c3ebb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 19 Apr 2020 19:47:59 -0700 Subject: [PATCH 0803/2595] tcg: Implement gvec support for rotate by vector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No host backend support yet, but the interfaces for rotlv and rotrv are in place. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- v3: Drop the generic expansion from rot to shift; we can do better for each backend, and then this code becomes unused. --- accel/tcg/tcg-runtime-gvec.c | 96 +++++++++++++++++++++++++++ accel/tcg/tcg-runtime.h | 10 +++ include/tcg/tcg-op-gvec.h | 4 ++ include/tcg/tcg-op.h | 2 + include/tcg/tcg-opc.h | 2 + include/tcg/tcg.h | 1 + tcg/README | 4 +- tcg/aarch64/tcg-target.h | 1 + tcg/i386/tcg-target.h | 1 + tcg/ppc/tcg-target.h | 1 + tcg/tcg-op-gvec.c | 122 +++++++++++++++++++++++++++++++++++ tcg/tcg-op-vec.c | 10 +++ tcg/tcg.c | 3 + 13 files changed, 256 insertions(+), 1 deletion(-) diff --git a/accel/tcg/tcg-runtime-gvec.c b/accel/tcg/tcg-runtime-gvec.c index 34b1030365..521da4a813 100644 --- a/accel/tcg/tcg-runtime-gvec.c +++ b/accel/tcg/tcg-runtime-gvec.c @@ -908,6 +908,102 @@ void HELPER(gvec_sar64v)(void *d, void *a, void *b, uint32_t desc) clear_high(d, oprsz, desc); } +void HELPER(gvec_rotl8v)(void *d, void *a, void *b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint8_t)) { + uint8_t sh = *(uint8_t *)(b + i) & 7; + *(uint8_t *)(d + i) = rol8(*(uint8_t *)(a + i), sh); + } + clear_high(d, oprsz, desc); +} + +void HELPER(gvec_rotl16v)(void *d, void *a, void *b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint16_t)) { + uint8_t sh = *(uint16_t *)(b + i) & 15; + *(uint16_t *)(d + i) = rol16(*(uint16_t *)(a + i), sh); + } + clear_high(d, oprsz, desc); +} + +void HELPER(gvec_rotl32v)(void *d, void *a, void *b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint32_t)) { + uint8_t sh = *(uint32_t *)(b + i) & 31; + *(uint32_t *)(d + i) = rol32(*(uint32_t *)(a + i), sh); + } + clear_high(d, oprsz, desc); +} + +void HELPER(gvec_rotl64v)(void *d, void *a, void *b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint64_t)) { + uint8_t sh = *(uint64_t *)(b + i) & 63; + *(uint64_t *)(d + i) = rol64(*(uint64_t *)(a + i), sh); + } + clear_high(d, oprsz, desc); +} + +void HELPER(gvec_rotr8v)(void *d, void *a, void *b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint8_t)) { + uint8_t sh = *(uint8_t *)(b + i) & 7; + *(uint8_t *)(d + i) = ror8(*(uint8_t *)(a + i), sh); + } + clear_high(d, oprsz, desc); +} + +void HELPER(gvec_rotr16v)(void *d, void *a, void *b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint16_t)) { + uint8_t sh = *(uint16_t *)(b + i) & 15; + *(uint16_t *)(d + i) = ror16(*(uint16_t *)(a + i), sh); + } + clear_high(d, oprsz, desc); +} + +void HELPER(gvec_rotr32v)(void *d, void *a, void *b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint32_t)) { + uint8_t sh = *(uint32_t *)(b + i) & 31; + *(uint32_t *)(d + i) = ror32(*(uint32_t *)(a + i), sh); + } + clear_high(d, oprsz, desc); +} + +void HELPER(gvec_rotr64v)(void *d, void *a, void *b, uint32_t desc) +{ + intptr_t oprsz = simd_oprsz(desc); + intptr_t i; + + for (i = 0; i < oprsz; i += sizeof(uint64_t)) { + uint8_t sh = *(uint64_t *)(b + i) & 63; + *(uint64_t *)(d + i) = ror64(*(uint64_t *)(a + i), sh); + } + clear_high(d, oprsz, desc); +} + #define DO_CMP1(NAME, TYPE, OP) \ void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) \ { \ diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index cf10c8361e..4eda24e63a 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -279,6 +279,16 @@ DEF_HELPER_FLAGS_4(gvec_sar16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_sar32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_sar64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_rotl8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_rotl16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_rotl32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_rotl64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_rotr8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_rotr16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_rotr32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_rotr64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + DEF_HELPER_FLAGS_4(gvec_eq8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_eq16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_eq32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/include/tcg/tcg-op-gvec.h b/include/tcg/tcg-op-gvec.h index 1afc3ebf03..2d768f1160 100644 --- a/include/tcg/tcg-op-gvec.h +++ b/include/tcg/tcg-op-gvec.h @@ -356,6 +356,10 @@ void tcg_gen_gvec_shrv(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t oprsz, uint32_t maxsz); void tcg_gen_gvec_sarv(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t oprsz, uint32_t maxsz); +void tcg_gen_gvec_rotlv(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz); +void tcg_gen_gvec_rotrv(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz); void tcg_gen_gvec_cmp(TCGCond cond, unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t bofs, diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index 848d91ce74..5523ee7810 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -1009,6 +1009,8 @@ void tcg_gen_sars_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s); void tcg_gen_shlv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s); void tcg_gen_shrv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s); void tcg_gen_sarv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s); +void tcg_gen_rotlv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s); +void tcg_gen_rotrv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s); void tcg_gen_cmp_vec(TCGCond cond, unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b); diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index a6ab4a147f..69f98d6523 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -257,6 +257,8 @@ DEF(sars_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shs_vec)) DEF(shlv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shv_vec)) DEF(shrv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shv_vec)) DEF(sarv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shv_vec)) +DEF(rotlv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_rotv_vec)) +DEF(rotrv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_rotv_vec)) DEF(cmp_vec, 1, 2, 1, IMPLVEC) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 56bedbd03b..b2cb30305c 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -183,6 +183,7 @@ typedef uint64_t TCGRegSet; #define TCG_TARGET_HAS_andc_vec 0 #define TCG_TARGET_HAS_orc_vec 0 #define TCG_TARGET_HAS_roti_vec 0 +#define TCG_TARGET_HAS_rotv_vec 0 #define TCG_TARGET_HAS_shi_vec 0 #define TCG_TARGET_HAS_shs_vec 0 #define TCG_TARGET_HAS_shv_vec 0 diff --git a/tcg/README b/tcg/README index 1e3e4654f4..a64f67809b 100644 --- a/tcg/README +++ b/tcg/README @@ -621,8 +621,10 @@ E.g. VECL=1 -> 64 << 1 -> v128, and VECE=2 -> 1 << 2 -> i32. * shrv_vec v0, v1, v2 * sarv_vec v0, v1, v2 +* rotlv_vec v0, v1, v2 +* rotrv_vec v0, v1, v2 - Similarly for logical and arithmetic right shift. + Similarly for logical and arithmetic right shift, and rotates. * cmp_vec v0, v1, v2, cond diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index 225a597f84..a5477bbc07 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -134,6 +134,7 @@ typedef enum { #define TCG_TARGET_HAS_neg_vec 1 #define TCG_TARGET_HAS_abs_vec 1 #define TCG_TARGET_HAS_roti_vec 0 +#define TCG_TARGET_HAS_rotv_vec 0 #define TCG_TARGET_HAS_shi_vec 1 #define TCG_TARGET_HAS_shs_vec 0 #define TCG_TARGET_HAS_shv_vec 1 diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 23aabde992..4c806c97db 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -184,6 +184,7 @@ extern bool have_avx2; #define TCG_TARGET_HAS_neg_vec 0 #define TCG_TARGET_HAS_abs_vec 1 #define TCG_TARGET_HAS_roti_vec 0 +#define TCG_TARGET_HAS_rotv_vec 0 #define TCG_TARGET_HAS_shi_vec 1 #define TCG_TARGET_HAS_shs_vec 1 #define TCG_TARGET_HAS_shv_vec have_avx2 diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index e57b891aa5..7993422526 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -162,6 +162,7 @@ extern bool have_vsx; #define TCG_TARGET_HAS_neg_vec have_isa_3_00 #define TCG_TARGET_HAS_abs_vec 0 #define TCG_TARGET_HAS_roti_vec 0 +#define TCG_TARGET_HAS_rotv_vec 0 #define TCG_TARGET_HAS_shi_vec 0 #define TCG_TARGET_HAS_shs_vec 0 #define TCG_TARGET_HAS_shv_vec 1 diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 25300b1577..2b71725883 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -3171,6 +3171,128 @@ void tcg_gen_gvec_sarv(unsigned vece, uint32_t dofs, uint32_t aofs, tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g[vece]); } +/* + * Similarly for rotates. + */ + +static void tcg_gen_rotlv_mod_vec(unsigned vece, TCGv_vec d, + TCGv_vec a, TCGv_vec b) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + + tcg_gen_dupi_vec(vece, t, (8 << vece) - 1); + tcg_gen_and_vec(vece, t, t, b); + tcg_gen_rotlv_vec(vece, d, a, t); + tcg_temp_free_vec(t); +} + +static void tcg_gen_rotl_mod_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i32 t = tcg_temp_new_i32(); + + tcg_gen_andi_i32(t, b, 31); + tcg_gen_rotl_i32(d, a, t); + tcg_temp_free_i32(t); +} + +static void tcg_gen_rotl_mod_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_andi_i64(t, b, 63); + tcg_gen_rotl_i64(d, a, t); + tcg_temp_free_i64(t); +} + +void tcg_gen_gvec_rotlv(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz) +{ + static const TCGOpcode vecop_list[] = { INDEX_op_rotlv_vec, 0 }; + static const GVecGen3 g[4] = { + { .fniv = tcg_gen_rotlv_mod_vec, + .fno = gen_helper_gvec_rotl8v, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fniv = tcg_gen_rotlv_mod_vec, + .fno = gen_helper_gvec_rotl16v, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = tcg_gen_rotl_mod_i32, + .fniv = tcg_gen_rotlv_mod_vec, + .fno = gen_helper_gvec_rotl32v, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = tcg_gen_rotl_mod_i64, + .fniv = tcg_gen_rotlv_mod_vec, + .fno = gen_helper_gvec_rotl64v, + .opt_opc = vecop_list, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .vece = MO_64 }, + }; + + tcg_debug_assert(vece <= MO_64); + tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g[vece]); +} + +static void tcg_gen_rotrv_mod_vec(unsigned vece, TCGv_vec d, + TCGv_vec a, TCGv_vec b) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + + tcg_gen_dupi_vec(vece, t, (8 << vece) - 1); + tcg_gen_and_vec(vece, t, t, b); + tcg_gen_rotrv_vec(vece, d, a, t); + tcg_temp_free_vec(t); +} + +static void tcg_gen_rotr_mod_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i32 t = tcg_temp_new_i32(); + + tcg_gen_andi_i32(t, b, 31); + tcg_gen_rotr_i32(d, a, t); + tcg_temp_free_i32(t); +} + +static void tcg_gen_rotr_mod_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_andi_i64(t, b, 63); + tcg_gen_rotr_i64(d, a, t); + tcg_temp_free_i64(t); +} + +void tcg_gen_gvec_rotrv(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz) +{ + static const TCGOpcode vecop_list[] = { INDEX_op_rotrv_vec, 0 }; + static const GVecGen3 g[4] = { + { .fniv = tcg_gen_rotrv_mod_vec, + .fno = gen_helper_gvec_rotr8v, + .opt_opc = vecop_list, + .vece = MO_8 }, + { .fniv = tcg_gen_rotrv_mod_vec, + .fno = gen_helper_gvec_rotr16v, + .opt_opc = vecop_list, + .vece = MO_16 }, + { .fni4 = tcg_gen_rotr_mod_i32, + .fniv = tcg_gen_rotrv_mod_vec, + .fno = gen_helper_gvec_rotr32v, + .opt_opc = vecop_list, + .vece = MO_32 }, + { .fni8 = tcg_gen_rotr_mod_i64, + .fniv = tcg_gen_rotrv_mod_vec, + .fno = gen_helper_gvec_rotr64v, + .opt_opc = vecop_list, + .prefer_i64 = TCG_TARGET_REG_BITS == 64, + .vece = MO_64 }, + }; + + tcg_debug_assert(vece <= MO_64); + tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g[vece]); +} + /* Expand OPSZ bytes worth of three-operand operations using i32 elements. */ static void expand_cmp_i32(uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t oprsz, TCGCond cond) diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c index 660ad9be88..488f9bd27b 100644 --- a/tcg/tcg-op-vec.c +++ b/tcg/tcg-op-vec.c @@ -696,6 +696,16 @@ void tcg_gen_sarv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) do_op3_nofail(vece, r, a, b, INDEX_op_sarv_vec); } +void tcg_gen_rotlv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) +{ + do_op3_nofail(vece, r, a, b, INDEX_op_rotlv_vec); +} + +void tcg_gen_rotrv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) +{ + do_op3_nofail(vece, r, a, b, INDEX_op_rotrv_vec); +} + static void do_shifts(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s, TCGOpcode opc_s, TCGOpcode opc_v) { diff --git a/tcg/tcg.c b/tcg/tcg.c index 73a3a4fb9e..bd6ffab79b 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1663,6 +1663,9 @@ bool tcg_op_supported(TCGOpcode op) return have_vec && TCG_TARGET_HAS_shv_vec; case INDEX_op_rotli_vec: return have_vec && TCG_TARGET_HAS_roti_vec; + case INDEX_op_rotlv_vec: + case INDEX_op_rotrv_vec: + return have_vec && TCG_TARGET_HAS_rotv_vec; case INDEX_op_ssadd_vec: case INDEX_op_usadd_vec: case INDEX_op_sssub_vec: From 3d5bb2ea5cc9ed54f65a6929a6e6baa01cabd98b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Apr 2020 07:56:36 -0700 Subject: [PATCH 0804/2595] tcg: Remove expansion to shift by vector from do_shifts We do not reflect this expansion in tcg_can_emit_vecop_list, so it is unused and unusable. However, we actually perform the same expansion in do_gvec_shifts, so it is also unneeded. Signed-off-by: Richard Henderson --- tcg/tcg-op-vec.c | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c index 488f9bd27b..fb1250fee6 100644 --- a/tcg/tcg-op-vec.c +++ b/tcg/tcg-op-vec.c @@ -707,7 +707,7 @@ void tcg_gen_rotrv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) } static void do_shifts(unsigned vece, TCGv_vec r, TCGv_vec a, - TCGv_i32 s, TCGOpcode opc_s, TCGOpcode opc_v) + TCGv_i32 s, TCGOpcode opc) { TCGTemp *rt = tcgv_vec_temp(r); TCGTemp *at = tcgv_vec_temp(a); @@ -716,48 +716,35 @@ static void do_shifts(unsigned vece, TCGv_vec r, TCGv_vec a, TCGArg ai = temp_arg(at); TCGArg si = temp_arg(st); TCGType type = rt->base_type; - const TCGOpcode *hold_list; int can; tcg_debug_assert(at->base_type >= type); - tcg_assert_listed_vecop(opc_s); - hold_list = tcg_swap_vecop_list(NULL); - - can = tcg_can_emit_vec_op(opc_s, type, vece); + tcg_assert_listed_vecop(opc); + can = tcg_can_emit_vec_op(opc, type, vece); if (can > 0) { - vec_gen_3(opc_s, type, vece, ri, ai, si); + vec_gen_3(opc, type, vece, ri, ai, si); } else if (can < 0) { - tcg_expand_vec_op(opc_s, type, vece, ri, ai, si); + const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL); + tcg_expand_vec_op(opc, type, vece, ri, ai, si); + tcg_swap_vecop_list(hold_list); } else { - TCGv_vec vec_s = tcg_temp_new_vec(type); - - if (vece == MO_64) { - TCGv_i64 s64 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(s64, s); - tcg_gen_dup_i64_vec(MO_64, vec_s, s64); - tcg_temp_free_i64(s64); - } else { - tcg_gen_dup_i32_vec(vece, vec_s, s); - } - do_op3_nofail(vece, r, a, vec_s, opc_v); - tcg_temp_free_vec(vec_s); + g_assert_not_reached(); } - tcg_swap_vecop_list(hold_list); } void tcg_gen_shls_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 b) { - do_shifts(vece, r, a, b, INDEX_op_shls_vec, INDEX_op_shlv_vec); + do_shifts(vece, r, a, b, INDEX_op_shls_vec); } void tcg_gen_shrs_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 b) { - do_shifts(vece, r, a, b, INDEX_op_shrs_vec, INDEX_op_shrv_vec); + do_shifts(vece, r, a, b, INDEX_op_shrs_vec); } void tcg_gen_sars_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 b) { - do_shifts(vece, r, a, b, INDEX_op_sars_vec, INDEX_op_sarv_vec); + do_shifts(vece, r, a, b, INDEX_op_sars_vec); } void tcg_gen_bitsel_vec(unsigned vece, TCGv_vec r, TCGv_vec a, From 23850a74afb641102325b4b7f74071d929fc4594 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Apr 2020 08:22:44 -0700 Subject: [PATCH 0805/2595] tcg: Implement gvec support for rotate by scalar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No host backend support yet, but the interfaces for rotls are in place. Only implement left-rotate for now, as the only known use of vector rotate by scalar is s390x, so any right-rotate would be unused and untestable. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- include/tcg/tcg-op-gvec.h | 2 ++ include/tcg/tcg-op.h | 1 + include/tcg/tcg-opc.h | 1 + include/tcg/tcg.h | 1 + tcg/aarch64/tcg-target.h | 1 + tcg/i386/tcg-target.h | 1 + tcg/ppc/tcg-target.h | 1 + tcg/tcg-op-gvec.c | 22 ++++++++++++++++++++++ tcg/tcg-op-vec.c | 5 +++++ tcg/tcg.c | 2 ++ 10 files changed, 37 insertions(+) diff --git a/include/tcg/tcg-op-gvec.h b/include/tcg/tcg-op-gvec.h index 2d768f1160..c69a7de984 100644 --- a/include/tcg/tcg-op-gvec.h +++ b/include/tcg/tcg-op-gvec.h @@ -345,6 +345,8 @@ void tcg_gen_gvec_shrs(unsigned vece, uint32_t dofs, uint32_t aofs, TCGv_i32 shift, uint32_t oprsz, uint32_t maxsz); void tcg_gen_gvec_sars(unsigned vece, uint32_t dofs, uint32_t aofs, TCGv_i32 shift, uint32_t oprsz, uint32_t maxsz); +void tcg_gen_gvec_rotls(unsigned vece, uint32_t dofs, uint32_t aofs, + TCGv_i32 shift, uint32_t oprsz, uint32_t maxsz); /* * Perform vector shift by vector element, modulo the element size. diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index 5523ee7810..5abf17fecc 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -1005,6 +1005,7 @@ void tcg_gen_rotri_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i); void tcg_gen_shls_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s); void tcg_gen_shrs_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s); void tcg_gen_sars_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s); +void tcg_gen_rotls_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s); void tcg_gen_shlv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s); void tcg_gen_shrv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s); diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 69f98d6523..e3929b80d2 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -253,6 +253,7 @@ DEF(rotli_vec, 1, 1, 1, IMPLVEC | IMPL(TCG_TARGET_HAS_roti_vec)) DEF(shls_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shs_vec)) DEF(shrs_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shs_vec)) DEF(sars_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shs_vec)) +DEF(rotls_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_rots_vec)) DEF(shlv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shv_vec)) DEF(shrv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shv_vec)) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index b2cb30305c..380014ed80 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -183,6 +183,7 @@ typedef uint64_t TCGRegSet; #define TCG_TARGET_HAS_andc_vec 0 #define TCG_TARGET_HAS_orc_vec 0 #define TCG_TARGET_HAS_roti_vec 0 +#define TCG_TARGET_HAS_rots_vec 0 #define TCG_TARGET_HAS_rotv_vec 0 #define TCG_TARGET_HAS_shi_vec 0 #define TCG_TARGET_HAS_shs_vec 0 diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index a5477bbc07..9bc2a5ecbe 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -134,6 +134,7 @@ typedef enum { #define TCG_TARGET_HAS_neg_vec 1 #define TCG_TARGET_HAS_abs_vec 1 #define TCG_TARGET_HAS_roti_vec 0 +#define TCG_TARGET_HAS_rots_vec 0 #define TCG_TARGET_HAS_rotv_vec 0 #define TCG_TARGET_HAS_shi_vec 1 #define TCG_TARGET_HAS_shs_vec 0 diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 4c806c97db..99ac1e3958 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -184,6 +184,7 @@ extern bool have_avx2; #define TCG_TARGET_HAS_neg_vec 0 #define TCG_TARGET_HAS_abs_vec 1 #define TCG_TARGET_HAS_roti_vec 0 +#define TCG_TARGET_HAS_rots_vec 0 #define TCG_TARGET_HAS_rotv_vec 0 #define TCG_TARGET_HAS_shi_vec 1 #define TCG_TARGET_HAS_shs_vec 1 diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 7993422526..4a17aebc5a 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -162,6 +162,7 @@ extern bool have_vsx; #define TCG_TARGET_HAS_neg_vec have_isa_3_00 #define TCG_TARGET_HAS_abs_vec 0 #define TCG_TARGET_HAS_roti_vec 0 +#define TCG_TARGET_HAS_rots_vec 0 #define TCG_TARGET_HAS_rotv_vec 0 #define TCG_TARGET_HAS_shi_vec 0 #define TCG_TARGET_HAS_shs_vec 0 diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 2b71725883..3707c0effb 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -2976,6 +2976,28 @@ void tcg_gen_gvec_sars(unsigned vece, uint32_t dofs, uint32_t aofs, do_gvec_shifts(vece, dofs, aofs, shift, oprsz, maxsz, &g); } +void tcg_gen_gvec_rotls(unsigned vece, uint32_t dofs, uint32_t aofs, + TCGv_i32 shift, uint32_t oprsz, uint32_t maxsz) +{ + static const GVecGen2sh g = { + .fni4 = tcg_gen_rotl_i32, + .fni8 = tcg_gen_rotl_i64, + .fniv_s = tcg_gen_rotls_vec, + .fniv_v = tcg_gen_rotlv_vec, + .fno = { + gen_helper_gvec_rotl8i, + gen_helper_gvec_rotl16i, + gen_helper_gvec_rotl32i, + gen_helper_gvec_rotl64i, + }, + .s_list = { INDEX_op_rotls_vec, 0 }, + .v_list = { INDEX_op_rotlv_vec, 0 }, + }; + + tcg_debug_assert(vece <= MO_64); + do_gvec_shifts(vece, dofs, aofs, shift, oprsz, maxsz, &g); +} + /* * Expand D = A << (B % element bits) * diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c index fb1250fee6..f784517d84 100644 --- a/tcg/tcg-op-vec.c +++ b/tcg/tcg-op-vec.c @@ -747,6 +747,11 @@ void tcg_gen_sars_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 b) do_shifts(vece, r, a, b, INDEX_op_sars_vec); } +void tcg_gen_rotls_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s) +{ + do_shifts(vece, r, a, s, INDEX_op_rotls_vec); +} + void tcg_gen_bitsel_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b, TCGv_vec c) { diff --git a/tcg/tcg.c b/tcg/tcg.c index bd6ffab79b..97558ec068 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1663,6 +1663,8 @@ bool tcg_op_supported(TCGOpcode op) return have_vec && TCG_TARGET_HAS_shv_vec; case INDEX_op_rotli_vec: return have_vec && TCG_TARGET_HAS_roti_vec; + case INDEX_op_rotls_vec: + return have_vec && TCG_TARGET_HAS_rots_vec; case INDEX_op_rotlv_vec: case INDEX_op_rotrv_vec: return have_vec && TCG_TARGET_HAS_rotv_vec; From 885b1706df6f0211a22e120fac910fb3abf3e733 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 19 Apr 2020 19:14:51 -0700 Subject: [PATCH 0806/2595] tcg/i386: Implement INDEX_op_rotl{i,s,v}_vec For immediates, we must continue the special casing of 8-bit elements. The other element sizes and shift types are trivially implemented with shifts. Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.inc.c | 116 ++++++++++++++++++++++++++++++++------ 1 file changed, 100 insertions(+), 16 deletions(-) diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c index ec083bddcf..ae0228238b 100644 --- a/tcg/i386/tcg-target.inc.c +++ b/tcg/i386/tcg-target.inc.c @@ -3233,6 +3233,7 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) case INDEX_op_shls_vec: case INDEX_op_shrs_vec: case INDEX_op_sars_vec: + case INDEX_op_rotls_vec: case INDEX_op_cmp_vec: case INDEX_op_x86_shufps_vec: case INDEX_op_x86_blend_vec: @@ -3271,6 +3272,7 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece) case INDEX_op_xor_vec: case INDEX_op_andc_vec: return 1; + case INDEX_op_rotli_vec: case INDEX_op_cmp_vec: case INDEX_op_cmpsel_vec: return -1; @@ -3297,12 +3299,17 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece) return vece >= MO_16; case INDEX_op_sars_vec: return vece >= MO_16 && vece <= MO_32; + case INDEX_op_rotls_vec: + return vece >= MO_16 ? -1 : 0; case INDEX_op_shlv_vec: case INDEX_op_shrv_vec: return have_avx2 && vece >= MO_32; case INDEX_op_sarv_vec: return have_avx2 && vece == MO_32; + case INDEX_op_rotlv_vec: + case INDEX_op_rotrv_vec: + return have_avx2 && vece >= MO_32 ? -1 : 0; case INDEX_op_mul_vec: if (vece == MO_8) { @@ -3331,7 +3338,7 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece) } } -static void expand_vec_shi(TCGType type, unsigned vece, bool shr, +static void expand_vec_shi(TCGType type, unsigned vece, TCGOpcode opc, TCGv_vec v0, TCGv_vec v1, TCGArg imm) { TCGv_vec t1, t2; @@ -3341,26 +3348,31 @@ static void expand_vec_shi(TCGType type, unsigned vece, bool shr, t1 = tcg_temp_new_vec(type); t2 = tcg_temp_new_vec(type); - /* Unpack to W, shift, and repack. Tricky bits: - (1) Use punpck*bw x,x to produce DDCCBBAA, - i.e. duplicate in other half of the 16-bit lane. - (2) For right-shift, add 8 so that the high half of - the lane becomes zero. For left-shift, we must - shift up and down again. - (3) Step 2 leaves high half zero such that PACKUSWB - (pack with unsigned saturation) does not modify - the quantity. */ + /* + * Unpack to W, shift, and repack. Tricky bits: + * (1) Use punpck*bw x,x to produce DDCCBBAA, + * i.e. duplicate in other half of the 16-bit lane. + * (2) For right-shift, add 8 so that the high half of the lane + * becomes zero. For left-shift, and left-rotate, we must + * shift up and down again. + * (3) Step 2 leaves high half zero such that PACKUSWB + * (pack with unsigned saturation) does not modify + * the quantity. + */ vec_gen_3(INDEX_op_x86_punpckl_vec, type, MO_8, tcgv_vec_arg(t1), tcgv_vec_arg(v1), tcgv_vec_arg(v1)); vec_gen_3(INDEX_op_x86_punpckh_vec, type, MO_8, tcgv_vec_arg(t2), tcgv_vec_arg(v1), tcgv_vec_arg(v1)); - if (shr) { - tcg_gen_shri_vec(MO_16, t1, t1, imm + 8); - tcg_gen_shri_vec(MO_16, t2, t2, imm + 8); + if (opc != INDEX_op_rotli_vec) { + imm += 8; + } + if (opc == INDEX_op_shri_vec) { + tcg_gen_shri_vec(MO_16, t1, t1, imm); + tcg_gen_shri_vec(MO_16, t2, t2, imm); } else { - tcg_gen_shli_vec(MO_16, t1, t1, imm + 8); - tcg_gen_shli_vec(MO_16, t2, t2, imm + 8); + tcg_gen_shli_vec(MO_16, t1, t1, imm); + tcg_gen_shli_vec(MO_16, t2, t2, imm); tcg_gen_shri_vec(MO_16, t1, t1, 8); tcg_gen_shri_vec(MO_16, t2, t2, 8); } @@ -3427,6 +3439,61 @@ static void expand_vec_sari(TCGType type, unsigned vece, } } +static void expand_vec_rotli(TCGType type, unsigned vece, + TCGv_vec v0, TCGv_vec v1, TCGArg imm) +{ + TCGv_vec t; + + if (vece == MO_8) { + expand_vec_shi(type, vece, INDEX_op_rotli_vec, v0, v1, imm); + return; + } + + t = tcg_temp_new_vec(type); + tcg_gen_shli_vec(vece, t, v1, imm); + tcg_gen_shri_vec(vece, v0, v1, (8 << vece) - imm); + tcg_gen_or_vec(vece, v0, v0, t); + tcg_temp_free_vec(t); +} + +static void expand_vec_rotls(TCGType type, unsigned vece, + TCGv_vec v0, TCGv_vec v1, TCGv_i32 lsh) +{ + TCGv_i32 rsh; + TCGv_vec t; + + tcg_debug_assert(vece != MO_8); + + t = tcg_temp_new_vec(type); + rsh = tcg_temp_new_i32(); + + tcg_gen_neg_i32(rsh, lsh); + tcg_gen_andi_i32(rsh, rsh, (8 << vece) - 1); + tcg_gen_shls_vec(vece, t, v1, lsh); + tcg_gen_shrs_vec(vece, v0, v1, rsh); + tcg_gen_or_vec(vece, v0, v0, t); + tcg_temp_free_vec(t); + tcg_temp_free_i32(rsh); +} + +static void expand_vec_rotv(TCGType type, unsigned vece, TCGv_vec v0, + TCGv_vec v1, TCGv_vec sh, bool right) +{ + TCGv_vec t = tcg_temp_new_vec(type); + + tcg_gen_dupi_vec(vece, t, 8 << vece); + tcg_gen_sub_vec(vece, t, t, sh); + if (right) { + tcg_gen_shlv_vec(vece, t, v1, t); + tcg_gen_shrv_vec(vece, v0, v1, sh); + } else { + tcg_gen_shrv_vec(vece, t, v1, t); + tcg_gen_shlv_vec(vece, v0, v1, sh); + } + tcg_gen_or_vec(vece, v0, v0, t); + tcg_temp_free_vec(t); +} + static void expand_vec_mul(TCGType type, unsigned vece, TCGv_vec v0, TCGv_vec v1, TCGv_vec v2) { @@ -3636,13 +3703,30 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece, switch (opc) { case INDEX_op_shli_vec: case INDEX_op_shri_vec: - expand_vec_shi(type, vece, opc == INDEX_op_shri_vec, v0, v1, a2); + expand_vec_shi(type, vece, opc, v0, v1, a2); break; case INDEX_op_sari_vec: expand_vec_sari(type, vece, v0, v1, a2); break; + case INDEX_op_rotli_vec: + expand_vec_rotli(type, vece, v0, v1, a2); + break; + + case INDEX_op_rotls_vec: + expand_vec_rotls(type, vece, v0, v1, temp_tcgv_i32(arg_temp(a2))); + break; + + case INDEX_op_rotlv_vec: + v2 = temp_tcgv_vec(arg_temp(a2)); + expand_vec_rotv(type, vece, v0, v1, v2, false); + break; + case INDEX_op_rotrv_vec: + v2 = temp_tcgv_vec(arg_temp(a2)); + expand_vec_rotv(type, vece, v0, v1, v2, true); + break; + case INDEX_op_mul_vec: v2 = temp_tcgv_vec(arg_temp(a2)); expand_vec_mul(type, vece, v0, v1, v2); From 7cff8988fade36f20659aad80f2f763ff054ef48 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Apr 2020 04:03:09 +0000 Subject: [PATCH 0807/2595] tcg/aarch64: Implement INDEX_op_rotl{i,v}_vec For immediate rotate , we can implement this in two instructions, using SLI. For variable rotate, the oddness of aarch64 right-shift- as-negative-left-shift means a backend-specific expansion works best. Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.inc.c | 53 ++++++++++++++++++++++++++++++++++-- tcg/aarch64/tcg-target.opc.h | 1 + 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/tcg/aarch64/tcg-target.inc.c b/tcg/aarch64/tcg-target.inc.c index 843fd0ca69..760b0e742d 100644 --- a/tcg/aarch64/tcg-target.inc.c +++ b/tcg/aarch64/tcg-target.inc.c @@ -557,6 +557,7 @@ typedef enum { I3614_SSHR = 0x0f000400, I3614_SSRA = 0x0f001400, I3614_SHL = 0x0f005400, + I3614_SLI = 0x2f005400, I3614_USHR = 0x2f000400, I3614_USRA = 0x2f001400, @@ -2411,6 +2412,9 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, case INDEX_op_sari_vec: tcg_out_insn(s, 3614, SSHR, is_q, a0, a1, (16 << vece) - a2); break; + case INDEX_op_aa64_sli_vec: + tcg_out_insn(s, 3614, SLI, is_q, a0, a2, args[3] + (8 << vece)); + break; case INDEX_op_shlv_vec: tcg_out_insn(s, 3616, USHL, is_q, vece, a0, a1, a2); break; @@ -2498,8 +2502,11 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece) case INDEX_op_shlv_vec: case INDEX_op_bitsel_vec: return 1; + case INDEX_op_rotli_vec: case INDEX_op_shrv_vec: case INDEX_op_sarv_vec: + case INDEX_op_rotlv_vec: + case INDEX_op_rotrv_vec: return -1; case INDEX_op_mul_vec: case INDEX_op_smax_vec: @@ -2517,14 +2524,24 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece, TCGArg a0, ...) { va_list va; - TCGv_vec v0, v1, v2, t1; + TCGv_vec v0, v1, v2, t1, t2; + TCGArg a2; va_start(va, a0); v0 = temp_tcgv_vec(arg_temp(a0)); v1 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg))); - v2 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg))); + a2 = va_arg(va, TCGArg); + v2 = temp_tcgv_vec(arg_temp(a2)); switch (opc) { + case INDEX_op_rotli_vec: + t1 = tcg_temp_new_vec(type); + tcg_gen_shri_vec(vece, t1, v1, -a2 & ((8 << vece) - 1)); + vec_gen_4(INDEX_op_aa64_sli_vec, type, vece, + tcgv_vec_arg(v0), tcgv_vec_arg(t1), tcgv_vec_arg(v1), a2); + tcg_temp_free_vec(t1); + break; + case INDEX_op_shrv_vec: case INDEX_op_sarv_vec: /* Right shifts are negative left shifts for AArch64. */ @@ -2537,6 +2554,35 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece, tcg_temp_free_vec(t1); break; + case INDEX_op_rotlv_vec: + t1 = tcg_temp_new_vec(type); + tcg_gen_dupi_vec(vece, t1, 8 << vece); + tcg_gen_sub_vec(vece, t1, v2, t1); + /* Right shifts are negative left shifts for AArch64. */ + vec_gen_3(INDEX_op_shlv_vec, type, vece, tcgv_vec_arg(t1), + tcgv_vec_arg(v1), tcgv_vec_arg(t1)); + vec_gen_3(INDEX_op_shlv_vec, type, vece, tcgv_vec_arg(v0), + tcgv_vec_arg(v1), tcgv_vec_arg(v2)); + tcg_gen_or_vec(vece, v0, v0, t1); + tcg_temp_free_vec(t1); + break; + + case INDEX_op_rotrv_vec: + t1 = tcg_temp_new_vec(type); + t2 = tcg_temp_new_vec(type); + tcg_gen_neg_vec(vece, t1, v2); + tcg_gen_dupi_vec(vece, t2, 8 << vece); + tcg_gen_add_vec(vece, t2, t1, t2); + /* Right shifts are negative left shifts for AArch64. */ + vec_gen_3(INDEX_op_shlv_vec, type, vece, tcgv_vec_arg(t1), + tcgv_vec_arg(v1), tcgv_vec_arg(t1)); + vec_gen_3(INDEX_op_shlv_vec, type, vece, tcgv_vec_arg(t2), + tcgv_vec_arg(v1), tcgv_vec_arg(t2)); + tcg_gen_or_vec(vece, v0, t1, t2); + tcg_temp_free_vec(t1); + tcg_temp_free_vec(t2); + break; + default: g_assert_not_reached(); } @@ -2557,6 +2603,7 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) static const TCGTargetOpDef lZ_l = { .args_ct_str = { "lZ", "l" } }; static const TCGTargetOpDef r_r_r = { .args_ct_str = { "r", "r", "r" } }; static const TCGTargetOpDef w_w_w = { .args_ct_str = { "w", "w", "w" } }; + static const TCGTargetOpDef w_0_w = { .args_ct_str = { "w", "0", "w" } }; static const TCGTargetOpDef w_w_wO = { .args_ct_str = { "w", "w", "wO" } }; static const TCGTargetOpDef w_w_wN = { .args_ct_str = { "w", "w", "wN" } }; static const TCGTargetOpDef w_w_wZ = { .args_ct_str = { "w", "w", "wZ" } }; @@ -2751,6 +2798,8 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) return &w_w_wZ; case INDEX_op_bitsel_vec: return &w_w_w_w; + case INDEX_op_aa64_sli_vec: + return &w_0_w; default: return NULL; diff --git a/tcg/aarch64/tcg-target.opc.h b/tcg/aarch64/tcg-target.opc.h index 26bfd9c460..bce30accd9 100644 --- a/tcg/aarch64/tcg-target.opc.h +++ b/tcg/aarch64/tcg-target.opc.h @@ -12,3 +12,4 @@ */ DEF(aa64_sshl_vec, 1, 2, 0, IMPLVEC) +DEF(aa64_sli_vec, 1, 2, 1, IMPLVEC) From ab87a66fa276b61f1d6adbc9271988e42bdf4c1e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Apr 2020 03:46:12 +0000 Subject: [PATCH 0808/2595] tcg/ppc: Implement INDEX_op_rot[lr]v_vec We already had support for rotlv, using a target-specific opcode; convert to use the generic opcode. Handle rotrv via simple negation. Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.h | 2 +- tcg/ppc/tcg-target.inc.c | 23 +++++++++++++++++++---- tcg/ppc/tcg-target.opc.h | 1 - 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 4a17aebc5a..be5b2901c3 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -163,7 +163,7 @@ extern bool have_vsx; #define TCG_TARGET_HAS_abs_vec 0 #define TCG_TARGET_HAS_roti_vec 0 #define TCG_TARGET_HAS_rots_vec 0 -#define TCG_TARGET_HAS_rotv_vec 0 +#define TCG_TARGET_HAS_rotv_vec 1 #define TCG_TARGET_HAS_shi_vec 0 #define TCG_TARGET_HAS_shs_vec 0 #define TCG_TARGET_HAS_shv_vec 1 diff --git a/tcg/ppc/tcg-target.inc.c b/tcg/ppc/tcg-target.inc.c index ee1f9227c1..7da67086c6 100644 --- a/tcg/ppc/tcg-target.inc.c +++ b/tcg/ppc/tcg-target.inc.c @@ -2995,6 +2995,7 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece) case INDEX_op_shlv_vec: case INDEX_op_shrv_vec: case INDEX_op_sarv_vec: + case INDEX_op_rotlv_vec: return vece <= MO_32 || have_isa_2_07; case INDEX_op_ssadd_vec: case INDEX_op_sssub_vec: @@ -3005,6 +3006,7 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece) case INDEX_op_shli_vec: case INDEX_op_shri_vec: case INDEX_op_sari_vec: + case INDEX_op_rotli_vec: return vece <= MO_32 || have_isa_2_07 ? -1 : 0; case INDEX_op_neg_vec: return vece >= MO_32 && have_isa_3_00; @@ -3019,6 +3021,8 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece) return 0; case INDEX_op_bitsel_vec: return have_vsx; + case INDEX_op_rotrv_vec: + return -1; default: return 0; } @@ -3301,7 +3305,7 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, case INDEX_op_ppc_pkum_vec: insn = pkum_op[vece]; break; - case INDEX_op_ppc_rotl_vec: + case INDEX_op_rotlv_vec: insn = rotl_op[vece]; break; case INDEX_op_ppc_msum_vec: @@ -3409,7 +3413,7 @@ static void expand_vec_mul(TCGType type, unsigned vece, TCGv_vec v0, t3 = tcg_temp_new_vec(type); t4 = tcg_temp_new_vec(type); tcg_gen_dupi_vec(MO_8, t4, -16); - vec_gen_3(INDEX_op_ppc_rotl_vec, type, MO_32, tcgv_vec_arg(t1), + vec_gen_3(INDEX_op_rotlv_vec, type, MO_32, tcgv_vec_arg(t1), tcgv_vec_arg(v2), tcgv_vec_arg(t4)); vec_gen_3(INDEX_op_ppc_mulou_vec, type, MO_16, tcgv_vec_arg(t2), tcgv_vec_arg(v1), tcgv_vec_arg(v2)); @@ -3434,7 +3438,7 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece, TCGArg a0, ...) { va_list va; - TCGv_vec v0, v1, v2; + TCGv_vec v0, v1, v2, t0; TCGArg a2; va_start(va, a0); @@ -3452,6 +3456,9 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece, case INDEX_op_sari_vec: expand_vec_shi(type, vece, v0, v1, a2, INDEX_op_sarv_vec); break; + case INDEX_op_rotli_vec: + expand_vec_shi(type, vece, v0, v1, a2, INDEX_op_rotlv_vec); + break; case INDEX_op_cmp_vec: v2 = temp_tcgv_vec(arg_temp(a2)); expand_vec_cmp(type, vece, v0, v1, v2, va_arg(va, TCGArg)); @@ -3460,6 +3467,13 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece, v2 = temp_tcgv_vec(arg_temp(a2)); expand_vec_mul(type, vece, v0, v1, v2); break; + case INDEX_op_rotlv_vec: + v2 = temp_tcgv_vec(arg_temp(a2)); + t0 = tcg_temp_new_vec(type); + tcg_gen_neg_vec(vece, t0, v2); + tcg_gen_rotlv_vec(vece, v0, v1, t0); + tcg_temp_free_vec(t0); + break; default: g_assert_not_reached(); } @@ -3664,12 +3678,13 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) case INDEX_op_shlv_vec: case INDEX_op_shrv_vec: case INDEX_op_sarv_vec: + case INDEX_op_rotlv_vec: + case INDEX_op_rotrv_vec: case INDEX_op_ppc_mrgh_vec: case INDEX_op_ppc_mrgl_vec: case INDEX_op_ppc_muleu_vec: case INDEX_op_ppc_mulou_vec: case INDEX_op_ppc_pkum_vec: - case INDEX_op_ppc_rotl_vec: case INDEX_op_dup2_vec: return &v_v_v; case INDEX_op_not_vec: diff --git a/tcg/ppc/tcg-target.opc.h b/tcg/ppc/tcg-target.opc.h index 1373f77e82..db514403c3 100644 --- a/tcg/ppc/tcg-target.opc.h +++ b/tcg/ppc/tcg-target.opc.h @@ -30,4 +30,3 @@ DEF(ppc_msum_vec, 1, 3, 0, IMPLVEC) DEF(ppc_muleu_vec, 1, 2, 0, IMPLVEC) DEF(ppc_mulou_vec, 1, 2, 0, IMPLVEC) DEF(ppc_pkum_vec, 1, 2, 0, IMPLVEC) -DEF(ppc_rotl_vec, 1, 2, 0, IMPLVEC) From 3e114acc9136dd7300324673a6e589ecc51f28cc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 19 Apr 2020 21:54:56 -0700 Subject: [PATCH 0809/2595] target/ppc: Use tcg_gen_gvec_rotlv Acked-by: David Gibson Signed-off-by: Richard Henderson --- target/ppc/helper.h | 4 ---- target/ppc/int_helper.c | 17 ----------------- target/ppc/translate/vmx-impl.inc.c | 8 ++++---- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 2dfa1c6942..90166cbabd 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -214,10 +214,6 @@ DEF_HELPER_3(vsubuqm, void, avr, avr, avr) DEF_HELPER_4(vsubecuq, void, avr, avr, avr, avr) DEF_HELPER_4(vsubeuqm, void, avr, avr, avr, avr) DEF_HELPER_3(vsubcuq, void, avr, avr, avr) -DEF_HELPER_3(vrlb, void, avr, avr, avr) -DEF_HELPER_3(vrlh, void, avr, avr, avr) -DEF_HELPER_3(vrlw, void, avr, avr, avr) -DEF_HELPER_3(vrld, void, avr, avr, avr) DEF_HELPER_4(vsldoi, void, avr, avr, avr, i32) DEF_HELPER_3(vextractub, void, avr, avr, i32) DEF_HELPER_3(vextractuh, void, avr, avr, i32) diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index be53cd6f68..d8bd3c234a 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -1348,23 +1348,6 @@ VRFI(p, float_round_up) VRFI(z, float_round_to_zero) #undef VRFI -#define VROTATE(suffix, element, mask) \ - void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - unsigned int shift = b->element[i] & mask; \ - r->element[i] = (a->element[i] << shift) | \ - (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \ - } \ - } -VROTATE(b, u8, 0x7) -VROTATE(h, u16, 0xF) -VROTATE(w, u32, 0x1F) -VROTATE(d, u64, 0x3F) -#undef VROTATE - void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) { int i; diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c index 403ed3a01c..de2fd136ff 100644 --- a/target/ppc/translate/vmx-impl.inc.c +++ b/target/ppc/translate/vmx-impl.inc.c @@ -900,13 +900,13 @@ GEN_VXFORM3(vsubeuqm, 31, 0); GEN_VXFORM3(vsubecuq, 31, 0); GEN_VXFORM_DUAL(vsubeuqm, PPC_NONE, PPC2_ALTIVEC_207, \ vsubecuq, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM(vrlb, 2, 0); -GEN_VXFORM(vrlh, 2, 1); -GEN_VXFORM(vrlw, 2, 2); +GEN_VXFORM_V(vrlb, MO_8, tcg_gen_gvec_rotlv, 2, 0); +GEN_VXFORM_V(vrlh, MO_16, tcg_gen_gvec_rotlv, 2, 1); +GEN_VXFORM_V(vrlw, MO_32, tcg_gen_gvec_rotlv, 2, 2); GEN_VXFORM(vrlwmi, 2, 2); GEN_VXFORM_DUAL(vrlw, PPC_ALTIVEC, PPC_NONE, \ vrlwmi, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vrld, 2, 3); +GEN_VXFORM_V(vrld, MO_64, tcg_gen_gvec_rotlv, 2, 3); GEN_VXFORM(vrldmi, 2, 3); GEN_VXFORM_DUAL(vrld, PPC_NONE, PPC2_ALTIVEC_207, \ vrldmi, PPC_NONE, PPC2_ISA300) From cea94ba36d858166fdf749f9894573449c3dafa6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Apr 2020 09:50:54 -0700 Subject: [PATCH 0810/2595] target/s390x: Use tcg_gen_gvec_rotl{i,s,v} Merge VERLL and VERLLV into op_vesv and op_ves, alongside all of the other vector shift operations. Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- target/s390x/helper.h | 4 -- target/s390x/insn-data.def | 4 +- target/s390x/translate_vx.inc.c | 66 +++++---------------------------- target/s390x/vec_int_helper.c | 31 ---------------- 4 files changed, 11 insertions(+), 94 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index b5813c2ac2..b7887b552b 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -198,10 +198,6 @@ DEF_HELPER_FLAGS_4(gvec_vmlo16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_4(gvec_vmlo32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_3(gvec_vpopct8, TCG_CALL_NO_RWG, void, ptr, cptr, i32) DEF_HELPER_FLAGS_3(gvec_vpopct16, TCG_CALL_NO_RWG, void, ptr, cptr, i32) -DEF_HELPER_FLAGS_4(gvec_verllv8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) -DEF_HELPER_FLAGS_4(gvec_verllv16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) -DEF_HELPER_FLAGS_4(gvec_verll8, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32) -DEF_HELPER_FLAGS_4(gvec_verll16, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32) DEF_HELPER_FLAGS_4(gvec_verim8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_4(gvec_verim16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32) DEF_HELPER_FLAGS_4(gvec_vsl, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 2bc77f0871..91ddaedd84 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -1147,8 +1147,8 @@ /* VECTOR POPULATION COUNT */ F(0xe750, VPOPCT, VRR_a, V, 0, 0, 0, 0, vpopct, 0, IF_VEC) /* VECTOR ELEMENT ROTATE LEFT LOGICAL */ - F(0xe773, VERLLV, VRR_c, V, 0, 0, 0, 0, verllv, 0, IF_VEC) - F(0xe733, VERLL, VRS_a, V, la2, 0, 0, 0, verll, 0, IF_VEC) + F(0xe773, VERLLV, VRR_c, V, 0, 0, 0, 0, vesv, 0, IF_VEC) + F(0xe733, VERLL, VRS_a, V, la2, 0, 0, 0, ves, 0, IF_VEC) /* VECTOR ELEMENT ROTATE AND INSERT UNDER MASK */ F(0xe772, VERIM, VRI_d, V, 0, 0, 0, 0, verim, 0, IF_VEC) /* VECTOR ELEMENT SHIFT LEFT */ diff --git a/target/s390x/translate_vx.inc.c b/target/s390x/translate_vx.inc.c index 12347f8a03..eb767f5288 100644 --- a/target/s390x/translate_vx.inc.c +++ b/target/s390x/translate_vx.inc.c @@ -1825,63 +1825,6 @@ static DisasJumpType op_vpopct(DisasContext *s, DisasOps *o) return DISAS_NEXT; } -static void gen_rll_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - - tcg_gen_andi_i32(t0, b, 31); - tcg_gen_rotl_i32(d, a, t0); - tcg_temp_free_i32(t0); -} - -static void gen_rll_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) -{ - TCGv_i64 t0 = tcg_temp_new_i64(); - - tcg_gen_andi_i64(t0, b, 63); - tcg_gen_rotl_i64(d, a, t0); - tcg_temp_free_i64(t0); -} - -static DisasJumpType op_verllv(DisasContext *s, DisasOps *o) -{ - const uint8_t es = get_field(s, m4); - static const GVecGen3 g[4] = { - { .fno = gen_helper_gvec_verllv8, }, - { .fno = gen_helper_gvec_verllv16, }, - { .fni4 = gen_rll_i32, }, - { .fni8 = gen_rll_i64, }, - }; - - if (es > ES_64) { - gen_program_exception(s, PGM_SPECIFICATION); - return DISAS_NORETURN; - } - - gen_gvec_3(get_field(s, v1), get_field(s, v2), - get_field(s, v3), &g[es]); - return DISAS_NEXT; -} - -static DisasJumpType op_verll(DisasContext *s, DisasOps *o) -{ - const uint8_t es = get_field(s, m4); - static const GVecGen2s g[4] = { - { .fno = gen_helper_gvec_verll8, }, - { .fno = gen_helper_gvec_verll16, }, - { .fni4 = gen_rll_i32, }, - { .fni8 = gen_rll_i64, }, - }; - - if (es > ES_64) { - gen_program_exception(s, PGM_SPECIFICATION); - return DISAS_NORETURN; - } - gen_gvec_2s(get_field(s, v1), get_field(s, v3), o->addr1, - &g[es]); - return DISAS_NEXT; -} - static void gen_rim_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, int32_t c) { TCGv_i32 t = tcg_temp_new_i32(); @@ -1946,6 +1889,9 @@ static DisasJumpType op_vesv(DisasContext *s, DisasOps *o) case 0x70: gen_gvec_fn_3(shlv, es, v1, v2, v3); break; + case 0x73: + gen_gvec_fn_3(rotlv, es, v1, v2, v3); + break; case 0x7a: gen_gvec_fn_3(sarv, es, v1, v2, v3); break; @@ -1977,6 +1923,9 @@ static DisasJumpType op_ves(DisasContext *s, DisasOps *o) case 0x30: gen_gvec_fn_2i(shli, es, v1, v3, d2); break; + case 0x33: + gen_gvec_fn_2i(rotli, es, v1, v3, d2); + break; case 0x3a: gen_gvec_fn_2i(sari, es, v1, v3, d2); break; @@ -1994,6 +1943,9 @@ static DisasJumpType op_ves(DisasContext *s, DisasOps *o) case 0x30: gen_gvec_fn_2s(shls, es, v1, v3, shift); break; + case 0x33: + gen_gvec_fn_2s(rotls, es, v1, v3, shift); + break; case 0x3a: gen_gvec_fn_2s(sars, es, v1, v3, shift); break; diff --git a/target/s390x/vec_int_helper.c b/target/s390x/vec_int_helper.c index 0d6bc13dd6..5561b3ed90 100644 --- a/target/s390x/vec_int_helper.c +++ b/target/s390x/vec_int_helper.c @@ -515,37 +515,6 @@ void HELPER(gvec_vpopct##BITS)(void *v1, const void *v2, uint32_t desc) \ DEF_VPOPCT(8) DEF_VPOPCT(16) -#define DEF_VERLLV(BITS) \ -void HELPER(gvec_verllv##BITS)(void *v1, const void *v2, const void *v3, \ - uint32_t desc) \ -{ \ - int i; \ - \ - for (i = 0; i < (128 / BITS); i++) { \ - const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \ - const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i); \ - \ - s390_vec_write_element##BITS(v1, i, rol##BITS(a, b)); \ - } \ -} -DEF_VERLLV(8) -DEF_VERLLV(16) - -#define DEF_VERLL(BITS) \ -void HELPER(gvec_verll##BITS)(void *v1, const void *v2, uint64_t count, \ - uint32_t desc) \ -{ \ - int i; \ - \ - for (i = 0; i < (128 / BITS); i++) { \ - const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \ - \ - s390_vec_write_element##BITS(v1, i, rol##BITS(a, count)); \ - } \ -} -DEF_VERLL(8) -DEF_VERLL(16) - #define DEF_VERIM(BITS) \ void HELPER(gvec_verim##BITS)(void *v1, const void *v2, const void *v3, \ uint32_t desc) \ From 61f15c487fc2aea14f6b0e52c459ae8b7d252a65 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Apr 2020 12:27:53 -0700 Subject: [PATCH 0811/2595] tcg: Improve move ops in liveness_pass_2 If the output of the move is dead, then the last use is in the store. If we propagate the input to the store, then we can remove the move opcode entirely. Signed-off-by: Richard Henderson --- tcg/tcg.c | 78 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index 97558ec068..1aa6cb47f2 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2982,34 +2982,68 @@ static bool liveness_pass_2(TCGContext *s) } /* Outputs become available. */ - for (i = 0; i < nb_oargs; i++) { - arg_ts = arg_temp(op->args[i]); + if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { + arg_ts = arg_temp(op->args[0]); dir_ts = arg_ts->state_ptr; - if (!dir_ts) { - continue; + if (dir_ts) { + op->args[0] = temp_arg(dir_ts); + changes = true; + + /* The output is now live and modified. */ + arg_ts->state = 0; + + if (NEED_SYNC_ARG(0)) { + TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 + ? INDEX_op_st_i32 + : INDEX_op_st_i64); + TCGOp *sop = tcg_op_insert_after(s, op, sopc); + TCGTemp *out_ts = dir_ts; + + if (IS_DEAD_ARG(0)) { + out_ts = arg_temp(op->args[1]); + arg_ts->state = TS_DEAD; + tcg_op_remove(s, op); + } else { + arg_ts->state = TS_MEM; + } + + sop->args[0] = temp_arg(out_ts); + sop->args[1] = temp_arg(arg_ts->mem_base); + sop->args[2] = arg_ts->mem_offset; + } else { + tcg_debug_assert(!IS_DEAD_ARG(0)); + } } - op->args[i] = temp_arg(dir_ts); - changes = true; + } else { + for (i = 0; i < nb_oargs; i++) { + arg_ts = arg_temp(op->args[i]); + dir_ts = arg_ts->state_ptr; + if (!dir_ts) { + continue; + } + op->args[i] = temp_arg(dir_ts); + changes = true; - /* The output is now live and modified. */ - arg_ts->state = 0; + /* The output is now live and modified. */ + arg_ts->state = 0; - /* Sync outputs upon their last write. */ - if (NEED_SYNC_ARG(i)) { - TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 - ? INDEX_op_st_i32 - : INDEX_op_st_i64); - TCGOp *sop = tcg_op_insert_after(s, op, sopc); + /* Sync outputs upon their last write. */ + if (NEED_SYNC_ARG(i)) { + TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 + ? INDEX_op_st_i32 + : INDEX_op_st_i64); + TCGOp *sop = tcg_op_insert_after(s, op, sopc); - sop->args[0] = temp_arg(dir_ts); - sop->args[1] = temp_arg(arg_ts->mem_base); - sop->args[2] = arg_ts->mem_offset; + sop->args[0] = temp_arg(dir_ts); + sop->args[1] = temp_arg(arg_ts->mem_base); + sop->args[2] = arg_ts->mem_offset; - arg_ts->state = TS_MEM; - } - /* Drop outputs that are dead. */ - if (IS_DEAD_ARG(i)) { - arg_ts->state = TS_DEAD; + arg_ts->state = TS_MEM; + } + /* Drop outputs that are dead. */ + if (IS_DEAD_ARG(i)) { + arg_ts->state = TS_DEAD; + } } } } From 853d9a4be8c281547797249dd0d329d807fc7fd7 Mon Sep 17 00:00:00 2001 From: Nick Hudson Date: Sat, 16 May 2020 16:41:47 +0100 Subject: [PATCH 0812/2595] accel/tcg: Adjust cpu_signal_handler for NetBSD/arm Fix building on NetBSD/arm by extracting the FSR value from the correct siginfo_t field. Reviewed-by: Richard Henderson Signed-off-by: Nick Hudson Message-Id: <20200516154147.24842-1-skrll@netbsd.org> Signed-off-by: Richard Henderson --- accel/tcg/user-exec.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 52359949df..bc391eb454 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -517,6 +517,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, #if defined(__NetBSD__) #include +#include #endif int cpu_signal_handler(int host_signum, void *pinfo, @@ -525,10 +526,12 @@ int cpu_signal_handler(int host_signum, void *pinfo, siginfo_t *info = pinfo; #if defined(__NetBSD__) ucontext_t *uc = puc; + siginfo_t *si = pinfo; #else ucontext_t *uc = puc; #endif unsigned long pc; + uint32_t fsr; int is_write; #if defined(__NetBSD__) @@ -539,10 +542,17 @@ int cpu_signal_handler(int host_signum, void *pinfo, pc = uc->uc_mcontext.arm_pc; #endif - /* error_code is the FSR value, in which bit 11 is WnR (assuming a v6 or - * later processor; on v5 we will always report this as a read). +#ifdef __NetBSD__ + fsr = si->si_trap; +#else + fsr = uc->uc_mcontext.error_code; +#endif + /* + * In the FSR, bit 11 is WnR, assuming a v6 or + * later processor. On v5 we will always report + * this as a read, which will fail later. */ - is_write = extract32(uc->uc_mcontext.error_code, 11, 1); + is_write = extract32(fsr, 11, 1); return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask); } From 71b04329c4f7d5824a289ca5225e1883a278cf3b Mon Sep 17 00:00:00 2001 From: Nick Hudson Date: Sun, 17 May 2020 11:15:29 +0100 Subject: [PATCH 0813/2595] accel/tcg: Provide a NetBSD specific aarch64 cpu_signal_handler Fix qemu build on NetBSD/evbarm-aarch64 by providing a NetBSD specific cpu_signal_handler. Reviewed-by: Richard Henderson Signed-off-by: Nick Hudson Message-Id: <20200517101529.5367-1-skrll@netbsd.org> Signed-off-by: Richard Henderson --- accel/tcg/user-exec.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index bc391eb454..d8b027f8c1 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -558,6 +558,32 @@ int cpu_signal_handler(int host_signum, void *pinfo, #elif defined(__aarch64__) +#if defined(__NetBSD__) + +#include +#include + +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) +{ + ucontext_t *uc = puc; + siginfo_t *si = pinfo; + unsigned long pc; + int is_write; + uint32_t esr; + + pc = uc->uc_mcontext.__gregs[_REG_PC]; + esr = si->si_trap; + + /* + * siginfo_t::si_trap is the ESR value, for data aborts ESR.EC + * is 0b10010x: then bit 6 is the WnR bit + */ + is_write = extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1; + return handle_cpu_signal(pc, si, is_write, &uc->uc_sigmask); +} + +#else + #ifndef ESR_MAGIC /* Pre-3.16 kernel headers don't have these, so provide fallback definitions */ #define ESR_MAGIC 0x45535201 @@ -620,6 +646,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc) } return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask); } +#endif #elif defined(__s390__) From ac5f7246d74eecb1da1e5561d933a3c139c71c78 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 1 May 2020 08:50:54 -0700 Subject: [PATCH 0814/2595] riscv: Suppress the error report for QEMU testing with riscv_find_firmware() We only ship plain binary bios images in the QEMU source. With Spike machine that uses ELF images as the default bios, running QEMU test will complain hence let's suppress the error report for QEMU testing. Signed-off-by: Bin Meng Reviewed-by: Anup Patel Message-Id: <1588348254-7241-6-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 726300a171..da5817d438 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -88,9 +88,17 @@ char *riscv_find_firmware(const char *firmware_filename) filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware_filename); if (filename == NULL) { - error_report("Unable to load the RISC-V firmware \"%s\"", - firmware_filename); - exit(1); + if (!qtest_enabled()) { + /* + * We only ship plain binary bios images in the QEMU source. + * With Spike machine that uses ELF images as the default bios, + * running QEMU test will complain hence let's suppress the error + * report for QEMU testing. + */ + error_report("Unable to load the RISC-V firmware \"%s\"", + firmware_filename); + exit(1); + } } return filename; From 087a42467405de45674f76da6a72406764cde6a6 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 1 May 2020 05:19:05 -0700 Subject: [PATCH 0815/2595] riscv: Change the default behavior if no -bios option is specified Per QEMU deprecated doc, QEMU 4.1 introduced support for the -bios option in QEMU for RISC-V for the virt machine and sifive_u machine. The default behavior has been that QEMU does not automatically load any firmware if no -bios option is included. Now 2 releases passed, it's time to change the default behavior to load the default OpenSBI firmware automatically. The firmware is included with the QEMU release and no user interaction is required. All a user needs to do is specify the kernel they want to boot with the -kernel option. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1588335545-649-1-git-send-email-bmeng.cn@gmail.com Message-Id: <1588335545-649-1-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index da5817d438..adb421b91b 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -41,34 +41,11 @@ void riscv_find_and_load_firmware(MachineState *machine, { char *firmware_filename = NULL; - if (!machine->firmware) { + if ((!machine->firmware) || (!strcmp(machine->firmware, "default"))) { /* - * The user didn't specify -bios. - * At the moment we default to loading nothing when this hapens. - * In the future this defaul will change to loading the prebuilt - * OpenSBI firmware. Let's warn the user and then continue. - */ - if (!qtest_enabled()) { - warn_report("No -bios option specified. Not loading a firmware."); - warn_report("This default will change in a future QEMU release. " \ - "Please use the -bios option to avoid breakages when "\ - "this happens."); - warn_report("See QEMU's deprecation documentation for details."); - } - return; - } - - if (!strcmp(machine->firmware, "default")) { - /* - * The user has specified "-bios default". That means we are going to - * load the OpenSBI binary included in the QEMU source. - * - * We can't load the binary by default as it will break existing users - * as users are already loading their own firmware. - * - * Let's try to get everyone to specify the -bios option at all times, - * so then in the future we can make "-bios default" the default option - * if no -bios option is set without breaking anything. + * The user didn't specify -bios, or has specified "-bios default". + * That means we are going to load the OpenSBI binary included in + * the QEMU source. */ firmware_filename = riscv_find_firmware(default_machine_firmware); } else if (strcmp(machine->firmware, "none")) { From 139177b1d4d69e2a31db12ee5bdee7ef9bfe51dc Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 21 May 2020 07:42:26 -0700 Subject: [PATCH 0816/2595] hw/riscv: sifive_u: Remove the riscv_ prefix of the soc* functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To keep consistency with the machine* functions, remove the riscv_ prefix of the soc* functions. Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 1590072147-13035-1-git-send-email-bmeng.cn@gmail.com Message-Id: <1590072147-13035-1-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 4299bdf480..f9fef2be91 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -481,7 +481,7 @@ static void sifive_u_machine_init_register_types(void) type_init(sifive_u_machine_init_register_types) -static void riscv_sifive_u_soc_init(Object *obj) +static void sifive_u_soc_instance_init(Object *obj) { MachineState *ms = MACHINE(qdev_get_machine()); SiFiveUSoCState *s = RISCV_U_SOC(obj); @@ -520,7 +520,7 @@ static void riscv_sifive_u_soc_init(Object *obj) TYPE_CADENCE_GEM); } -static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) +static void sifive_u_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); SiFiveUSoCState *s = RISCV_U_SOC(dev); @@ -635,32 +635,32 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size); } -static Property riscv_sifive_u_soc_props[] = { +static Property sifive_u_soc_props[] = { DEFINE_PROP_UINT32("serial", SiFiveUSoCState, serial, OTP_SERIAL), DEFINE_PROP_END_OF_LIST() }; -static void riscv_sifive_u_soc_class_init(ObjectClass *oc, void *data) +static void sifive_u_soc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); - device_class_set_props(dc, riscv_sifive_u_soc_props); - dc->realize = riscv_sifive_u_soc_realize; + device_class_set_props(dc, sifive_u_soc_props); + dc->realize = sifive_u_soc_realize; /* Reason: Uses serial_hds in realize function, thus can't be used twice */ dc->user_creatable = false; } -static const TypeInfo riscv_sifive_u_soc_type_info = { +static const TypeInfo sifive_u_soc_type_info = { .name = TYPE_RISCV_U_SOC, .parent = TYPE_DEVICE, .instance_size = sizeof(SiFiveUSoCState), - .instance_init = riscv_sifive_u_soc_init, - .class_init = riscv_sifive_u_soc_class_init, + .instance_init = sifive_u_soc_instance_init, + .class_init = sifive_u_soc_class_init, }; -static void riscv_sifive_u_soc_register_types(void) +static void sifive_u_soc_register_types(void) { - type_register_static(&riscv_sifive_u_soc_type_info); + type_register_static(&sifive_u_soc_type_info); } -type_init(riscv_sifive_u_soc_register_types) +type_init(sifive_u_soc_register_types) From b2a3a071f76d45c7ac2b8a1640153d3cc8259ca3 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 21 May 2020 07:42:27 -0700 Subject: [PATCH 0817/2595] hw/riscv: virt: Remove the riscv_ prefix of the machine* functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the riscv_ prefix of the machine* functions. Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 1590072147-13035-2-git-send-email-bmeng.cn@gmail.com Message-Id: <1590072147-13035-2-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 7ce28895bc..4e4c494a70 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -471,7 +471,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, return dev; } -static void riscv_virt_board_init(MachineState *machine) +static void virt_machine_init(MachineState *machine) { const struct MemmapEntry *memmap = virt_memmap; RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); @@ -632,32 +632,32 @@ static void riscv_virt_board_init(MachineState *machine) g_free(plic_hart_config); } -static void riscv_virt_machine_instance_init(Object *obj) +static void virt_machine_instance_init(Object *obj) { } -static void riscv_virt_machine_class_init(ObjectClass *oc, void *data) +static void virt_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); mc->desc = "RISC-V VirtIO board"; - mc->init = riscv_virt_board_init; + mc->init = virt_machine_init; mc->max_cpus = 8; mc->default_cpu_type = VIRT_CPU; mc->pci_allow_0_address = true; } -static const TypeInfo riscv_virt_machine_typeinfo = { +static const TypeInfo virt_machine_typeinfo = { .name = MACHINE_TYPE_NAME("virt"), .parent = TYPE_MACHINE, - .class_init = riscv_virt_machine_class_init, - .instance_init = riscv_virt_machine_instance_init, + .class_init = virt_machine_class_init, + .instance_init = virt_machine_instance_init, .instance_size = sizeof(RISCVVirtState), }; -static void riscv_virt_machine_init_register_types(void) +static void virt_machine_init_register_types(void) { - type_register_static(&riscv_virt_machine_typeinfo); + type_register_static(&virt_machine_typeinfo); } -type_init(riscv_virt_machine_init_register_types) +type_init(virt_machine_init_register_types) From 26cd0362dd43a32fc9a917f5c00b20e9dafa93be Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 5 May 2020 13:07:24 -0700 Subject: [PATCH 0818/2595] hw/riscv: spike: Remove deprecated ISA specific machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ISA specific Spike machines have been deprecated in QEMU since 4.1, let's finally remove them. Signed-off-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bin Meng Reviewed-by: Thomas Huth --- docs/system/deprecated.rst | 17 +-- hw/riscv/spike.c | 217 ------------------------------------- include/hw/riscv/spike.h | 6 +- 3 files changed, 12 insertions(+), 228 deletions(-) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index f0061f94aa..50927bad74 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -379,13 +379,6 @@ This machine has been renamed ``fuloong2e``. These machine types are very old and likely can not be used for live migration from old QEMU versions anymore. A newer machine type should be used instead. -``spike_v1.9.1`` and ``spike_v1.10`` (since 4.1) -'''''''''''''''''''''''''''''''''''''''''''''''' - -The version specific Spike machines have been deprecated in favour of the -generic ``spike`` machine. If you need to specify an older version of the RISC-V -spec you can use the ``-cpu rv64gcsu,priv_spec=v1.9.1`` command line argument. - Device options -------------- @@ -493,6 +486,16 @@ The ``hub_id`` parameter of ``hostfwd_add`` / ``hostfwd_remove`` (removed in 5.0 The ``[hub_id name]`` parameter tuple of the 'hostfwd_add' and 'hostfwd_remove' HMP commands has been replaced by ``netdev_id``. +System emulator machines +------------------------ + +``spike_v1.9.1`` and ``spike_v1.10`` (removed in 5.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The version specific Spike machines have been removed in favour of the +generic ``spike`` machine. If you need to specify an older version of the RISC-V +spec you can use the ``-cpu rv64gcsu,priv_spec=v1.10.0`` command line argument. + Related binaries ---------------- diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index d0c4843712..7bbbdb5036 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -257,221 +257,6 @@ static void spike_board_init(MachineState *machine) false); } -static void spike_v1_10_0_board_init(MachineState *machine) -{ - const struct MemmapEntry *memmap = spike_memmap; - - SpikeState *s = g_new0(SpikeState, 1); - MemoryRegion *system_memory = get_system_memory(); - MemoryRegion *main_mem = g_new(MemoryRegion, 1); - MemoryRegion *mask_rom = g_new(MemoryRegion, 1); - int i; - unsigned int smp_cpus = machine->smp.cpus; - - if (!qtest_enabled()) { - info_report("The Spike v1.10.0 machine has been deprecated. " - "Please use the generic spike machine and specify the ISA " - "versions using -cpu."); - } - - /* Initialize SOC */ - object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), - TYPE_RISCV_HART_ARRAY, &error_abort, NULL); - object_property_set_str(OBJECT(&s->soc), SPIKE_V1_10_0_CPU, "cpu-type", - &error_abort); - object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts", - &error_abort); - object_property_set_bool(OBJECT(&s->soc), true, "realized", - &error_abort); - - /* register system main memory (actual RAM) */ - memory_region_init_ram(main_mem, NULL, "riscv.spike.ram", - machine->ram_size, &error_fatal); - memory_region_add_subregion(system_memory, memmap[SPIKE_DRAM].base, - main_mem); - - /* create device tree */ - create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline); - - /* boot rom */ - memory_region_init_rom(mask_rom, NULL, "riscv.spike.mrom", - memmap[SPIKE_MROM].size, &error_fatal); - memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base, - mask_rom); - - if (machine->kernel_filename) { - riscv_load_kernel(machine->kernel_filename, htif_symbol_callback); - } - - /* reset vector */ - uint32_t reset_vec[8] = { - 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ - 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */ - 0xf1402573, /* csrr a0, mhartid */ -#if defined(TARGET_RISCV32) - 0x0182a283, /* lw t0, 24(t0) */ -#elif defined(TARGET_RISCV64) - 0x0182b283, /* ld t0, 24(t0) */ -#endif - 0x00028067, /* jr t0 */ - 0x00000000, - memmap[SPIKE_DRAM].base, /* start: .dword DRAM_BASE */ - 0x00000000, - /* dtb: */ - }; - - /* copy in the reset vector in little_endian byte order */ - for (i = 0; i < sizeof(reset_vec) >> 2; i++) { - reset_vec[i] = cpu_to_le32(reset_vec[i]); - } - rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), - memmap[SPIKE_MROM].base, &address_space_memory); - - /* copy in the device tree */ - if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) > - memmap[SPIKE_MROM].size - sizeof(reset_vec)) { - error_report("not enough space to store device-tree"); - exit(1); - } - qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt)); - rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt), - memmap[SPIKE_MROM].base + sizeof(reset_vec), - &address_space_memory); - - /* initialize HTIF using symbols found in load_kernel */ - htif_mm_init(system_memory, mask_rom, &s->soc.harts[0].env, serial_hd(0)); - - /* Core Local Interruptor (timer and IPI) */ - sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size, - smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, - false); -} - -static void spike_v1_09_1_board_init(MachineState *machine) -{ - const struct MemmapEntry *memmap = spike_memmap; - - SpikeState *s = g_new0(SpikeState, 1); - MemoryRegion *system_memory = get_system_memory(); - MemoryRegion *main_mem = g_new(MemoryRegion, 1); - MemoryRegion *mask_rom = g_new(MemoryRegion, 1); - int i; - unsigned int smp_cpus = machine->smp.cpus; - - if (!qtest_enabled()) { - info_report("The Spike v1.09.1 machine has been deprecated. " - "Please use the generic spike machine and specify the ISA " - "versions using -cpu."); - } - - /* Initialize SOC */ - object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), - TYPE_RISCV_HART_ARRAY, &error_abort, NULL); - object_property_set_str(OBJECT(&s->soc), SPIKE_V1_09_1_CPU, "cpu-type", - &error_abort); - object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts", - &error_abort); - object_property_set_bool(OBJECT(&s->soc), true, "realized", - &error_abort); - - /* register system main memory (actual RAM) */ - memory_region_init_ram(main_mem, NULL, "riscv.spike.ram", - machine->ram_size, &error_fatal); - memory_region_add_subregion(system_memory, memmap[SPIKE_DRAM].base, - main_mem); - - /* boot rom */ - memory_region_init_rom(mask_rom, NULL, "riscv.spike.mrom", - memmap[SPIKE_MROM].size, &error_fatal); - memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base, - mask_rom); - - if (machine->kernel_filename) { - riscv_load_kernel(machine->kernel_filename, htif_symbol_callback); - } - - /* reset vector */ - uint32_t reset_vec[8] = { - 0x297 + memmap[SPIKE_DRAM].base - memmap[SPIKE_MROM].base, /* lui */ - 0x00028067, /* jump to DRAM_BASE */ - 0x00000000, /* reserved */ - memmap[SPIKE_MROM].base + sizeof(reset_vec), /* config string pointer */ - 0, 0, 0, 0 /* trap vector */ - }; - - /* part one of config string - before memory size specified */ - const char *config_string_tmpl = - "platform {\n" - " vendor ucb;\n" - " arch spike;\n" - "};\n" - "rtc {\n" - " addr 0x%" PRIx64 "x;\n" - "};\n" - "ram {\n" - " 0 {\n" - " addr 0x%" PRIx64 "x;\n" - " size 0x%" PRIx64 "x;\n" - " };\n" - "};\n" - "core {\n" - " 0" " {\n" - " " "0 {\n" - " isa %s;\n" - " timecmp 0x%" PRIx64 "x;\n" - " ipi 0x%" PRIx64 "x;\n" - " };\n" - " };\n" - "};\n"; - - /* build config string with supplied memory size */ - char *isa = riscv_isa_string(&s->soc.harts[0]); - char *config_string = g_strdup_printf(config_string_tmpl, - (uint64_t)memmap[SPIKE_CLINT].base + SIFIVE_TIME_BASE, - (uint64_t)memmap[SPIKE_DRAM].base, - (uint64_t)ram_size, isa, - (uint64_t)memmap[SPIKE_CLINT].base + SIFIVE_TIMECMP_BASE, - (uint64_t)memmap[SPIKE_CLINT].base + SIFIVE_SIP_BASE); - g_free(isa); - size_t config_string_len = strlen(config_string); - - /* copy in the reset vector in little_endian byte order */ - for (i = 0; i < sizeof(reset_vec) >> 2; i++) { - reset_vec[i] = cpu_to_le32(reset_vec[i]); - } - rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), - memmap[SPIKE_MROM].base, &address_space_memory); - - /* copy in the config string */ - rom_add_blob_fixed_as("mrom.reset", config_string, config_string_len, - memmap[SPIKE_MROM].base + sizeof(reset_vec), - &address_space_memory); - - /* initialize HTIF using symbols found in load_kernel */ - htif_mm_init(system_memory, mask_rom, &s->soc.harts[0].env, serial_hd(0)); - - /* Core Local Interruptor (timer and IPI) */ - sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size, - smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, - false); - - g_free(config_string); -} - -static void spike_v1_09_1_machine_init(MachineClass *mc) -{ - mc->desc = "RISC-V Spike Board (Privileged ISA v1.9.1)"; - mc->init = spike_v1_09_1_board_init; - mc->max_cpus = 1; -} - -static void spike_v1_10_0_machine_init(MachineClass *mc) -{ - mc->desc = "RISC-V Spike Board (Privileged ISA v1.10)"; - mc->init = spike_v1_10_0_board_init; - mc->max_cpus = 1; -} - static void spike_machine_init(MachineClass *mc) { mc->desc = "RISC-V Spike Board"; @@ -481,6 +266,4 @@ static void spike_machine_init(MachineClass *mc) mc->default_cpu_type = SPIKE_V1_10_0_CPU; } -DEFINE_MACHINE("spike_v1.9.1", spike_v1_09_1_machine_init) -DEFINE_MACHINE("spike_v1.10", spike_v1_10_0_machine_init) DEFINE_MACHINE("spike", spike_machine_init) diff --git a/include/hw/riscv/spike.h b/include/hw/riscv/spike.h index dc770421bc..1cd72b85d6 100644 --- a/include/hw/riscv/spike.h +++ b/include/hw/riscv/spike.h @@ -39,11 +39,9 @@ enum { }; #if defined(TARGET_RISCV32) -#define SPIKE_V1_09_1_CPU TYPE_RISCV_CPU_RV32GCSU_V1_09_1 -#define SPIKE_V1_10_0_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0 +#define SPIKE_V1_10_0_CPU TYPE_RISCV_CPU_BASE32 #elif defined(TARGET_RISCV64) -#define SPIKE_V1_09_1_CPU TYPE_RISCV_CPU_RV64GCSU_V1_09_1 -#define SPIKE_V1_10_0_CPU TYPE_RISCV_CPU_RV64GCSU_V1_10_0 +#define SPIKE_V1_10_0_CPU TYPE_RISCV_CPU_BASE64 #endif #endif From 65a117da6ec5f0226952368d544cfb5c2a1dcead Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 6 May 2020 13:03:25 -0700 Subject: [PATCH 0819/2595] target/riscv: Remove the deprecated CPUs Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- docs/system/deprecated.rst | 33 ++++++++++++++++++--------------- target/riscv/cpu.c | 28 ---------------------------- target/riscv/cpu.h | 7 ------- tests/qtest/machine-none-test.c | 4 ++-- 4 files changed, 20 insertions(+), 52 deletions(-) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 50927bad74..bb14de9848 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -314,21 +314,6 @@ should be used instead of the 1.09.1 version. System emulator CPUS -------------------- -RISC-V ISA CPUs (since 4.1) -''''''''''''''''''''''''''' - -The RISC-V cpus with the ISA version in the CPU name have been depcreated. The -four CPUs are: ``rv32gcsu-v1.9.1``, ``rv32gcsu-v1.10.0``, ``rv64gcsu-v1.9.1`` and -``rv64gcsu-v1.10.0``. Instead the version can be specified via the CPU ``priv_spec`` -option when using the ``rv32`` or ``rv64`` CPUs. - -RISC-V ISA CPUs (since 4.1) -''''''''''''''''''''''''''' - -The RISC-V no MMU cpus have been depcreated. The two CPUs: ``rv32imacu-nommu`` and -``rv64imacu-nommu`` should no longer be used. Instead the MMU status can be specified -via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs. - ``compat`` property of server class POWER CPUs (since 5.0) '''''''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -486,6 +471,24 @@ The ``hub_id`` parameter of ``hostfwd_add`` / ``hostfwd_remove`` (removed in 5.0 The ``[hub_id name]`` parameter tuple of the 'hostfwd_add' and 'hostfwd_remove' HMP commands has been replaced by ``netdev_id``. +System emulator CPUS +-------------------- + +RISC-V ISA Specific CPUs (removed in 5.1) +''''''''''''''''''''''''''''''''''''''''' + +The RISC-V cpus with the ISA version in the CPU name have been removed. The +four CPUs are: ``rv32gcsu-v1.9.1``, ``rv32gcsu-v1.10.0``, ``rv64gcsu-v1.9.1`` and +``rv64gcsu-v1.10.0``. Instead the version can be specified via the CPU ``priv_spec`` +option when using the ``rv32`` or ``rv64`` CPUs. + +RISC-V no MMU CPUs (removed in 5.1) +''''''''''''''''''''''''''''''''''' + +The RISC-V no MMU cpus have been removed. The two CPUs: ``rv32imacu-nommu`` and +``rv64imacu-nommu`` can no longer be used. Instead the MMU status can be specified +via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs. + System emulator machines ------------------------ diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 059d71f2c7..112f2e3a2f 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -135,16 +135,6 @@ static void riscv_base32_cpu_init(Object *obj) set_misa(env, 0); } -static void rv32gcsu_priv1_09_1_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); - set_priv_version(env, PRIV_VERSION_1_09_1); - set_resetvec(env, DEFAULT_RSTVEC); - set_feature(env, RISCV_FEATURE_MMU); - set_feature(env, RISCV_FEATURE_PMP); -} - static void rv32gcsu_priv1_10_0_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -182,16 +172,6 @@ static void riscv_base64_cpu_init(Object *obj) set_misa(env, 0); } -static void rv64gcsu_priv1_09_1_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); - set_priv_version(env, PRIV_VERSION_1_09_1); - set_resetvec(env, DEFAULT_RSTVEC); - set_feature(env, RISCV_FEATURE_MMU); - set_feature(env, RISCV_FEATURE_PMP); -} - static void rv64gcsu_priv1_10_0_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -621,18 +601,10 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32imafcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init), - /* Depreacted */ - DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init) #elif defined(TARGET_RISCV64) DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base64_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init), - /* Deprecated */ - DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU, rv64imacu_nommu_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init) #endif }; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index d0e7f5b9c5..76b98d7a33 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -40,13 +40,6 @@ #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") #define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34") #define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54") -/* Deprecated */ -#define TYPE_RISCV_CPU_RV32IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv32imacu-nommu") -#define TYPE_RISCV_CPU_RV32GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.9.1") -#define TYPE_RISCV_CPU_RV32GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.10.0") -#define TYPE_RISCV_CPU_RV64IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv64imacu-nommu") -#define TYPE_RISCV_CPU_RV64GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.9.1") -#define TYPE_RISCV_CPU_RV64GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.10.0") #define RV32 ((target_ulong)1 << (TARGET_LONG_BITS - 2)) #define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2)) diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c index 8bb54a6360..10d8ec26a9 100644 --- a/tests/qtest/machine-none-test.c +++ b/tests/qtest/machine-none-test.c @@ -54,8 +54,8 @@ static struct arch2cpu cpus_map[] = { { "xtensa", "dc233c" }, { "xtensaeb", "fsf" }, { "hppa", "hppa" }, - { "riscv64", "rv64gcsu-v1.10.0" }, - { "riscv32", "rv32gcsu-v1.9.1" }, + { "riscv64", "rv64" }, + { "riscv32", "rv32" }, { "rx", "rx62n" }, }; From 1a9540d1f1a9c5022d9273d0244e5809679dd33b Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 5 May 2020 13:04:50 -0700 Subject: [PATCH 0820/2595] target/riscv: Drop support for ISA spec version 1.09.1 The RISC-V ISA spec version 1.09.1 has been deprecated in QEMU since 4.1. It's not commonly used so let's remove support for it. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- docs/system/deprecated.rst | 20 +-- target/riscv/cpu.c | 2 - target/riscv/cpu.h | 1 - target/riscv/cpu_helper.c | 82 ++++------ target/riscv/csr.c | 140 ++++-------------- .../riscv/insn_trans/trans_privileged.inc.c | 18 +-- target/riscv/monitor.c | 5 - target/riscv/op_helper.c | 17 +-- 8 files changed, 74 insertions(+), 211 deletions(-) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index bb14de9848..d177609cbc 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -301,16 +301,6 @@ The ``acl_show``, ``acl_reset``, ``acl_policy``, ``acl_add``, and ``acl_remove`` commands are deprecated with no replacement. Authorization for VNC should be performed using the pluggable QAuthZ objects. -Guest Emulator ISAs -------------------- - -RISC-V ISA privledge specification version 1.09.1 (since 4.1) -''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -The RISC-V ISA privledge specification version 1.09.1 has been deprecated. -QEMU supports both the newer version 1.10.0 and the ratified version 1.11.0, these -should be used instead of the 1.09.1 version. - System emulator CPUS -------------------- @@ -471,6 +461,16 @@ The ``hub_id`` parameter of ``hostfwd_add`` / ``hostfwd_remove`` (removed in 5.0 The ``[hub_id name]`` parameter tuple of the 'hostfwd_add' and 'hostfwd_remove' HMP commands has been replaced by ``netdev_id``. +Guest Emulator ISAs +------------------- + +RISC-V ISA privledge specification version 1.09.1 (removed in 5.1) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The RISC-V ISA privledge specification version 1.09.1 has been removed. +QEMU supports both the newer version 1.10.0 and the ratified version 1.11.0, these +should be used instead of the 1.09.1 version. + System emulator CPUS -------------------- diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 112f2e3a2f..eeb91f8513 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -368,8 +368,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) priv_version = PRIV_VERSION_1_11_0; } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) { priv_version = PRIV_VERSION_1_10_0; - } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.9.1")) { - priv_version = PRIV_VERSION_1_09_1; } else { error_setg(errp, "Unsupported privilege spec version '%s'", diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 76b98d7a33..c022539012 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -73,7 +73,6 @@ enum { RISCV_FEATURE_MISA }; -#define PRIV_VERSION_1_09_1 0x00010901 #define PRIV_VERSION_1_10_0 0x00011000 #define PRIV_VERSION_1_11_0 0x00011100 diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index bc80aa87cf..62fe1ecc8f 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -364,57 +364,36 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, mxr = get_field(env->vsstatus, MSTATUS_MXR); } - if (env->priv_ver >= PRIV_VERSION_1_10_0) { - if (first_stage == true) { - if (use_background) { - base = (hwaddr)get_field(env->vsatp, SATP_PPN) << PGSHIFT; - vm = get_field(env->vsatp, SATP_MODE); - } else { - base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; - vm = get_field(env->satp, SATP_MODE); - } - widened = 0; + if (first_stage == true) { + if (use_background) { + base = (hwaddr)get_field(env->vsatp, SATP_PPN) << PGSHIFT; + vm = get_field(env->vsatp, SATP_MODE); } else { - base = (hwaddr)get_field(env->hgatp, HGATP_PPN) << PGSHIFT; - vm = get_field(env->hgatp, HGATP_MODE); - widened = 2; + base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; + vm = get_field(env->satp, SATP_MODE); } - sum = get_field(env->mstatus, MSTATUS_SUM); - switch (vm) { - case VM_1_10_SV32: - levels = 2; ptidxbits = 10; ptesize = 4; break; - case VM_1_10_SV39: - levels = 3; ptidxbits = 9; ptesize = 8; break; - case VM_1_10_SV48: - levels = 4; ptidxbits = 9; ptesize = 8; break; - case VM_1_10_SV57: - levels = 5; ptidxbits = 9; ptesize = 8; break; - case VM_1_10_MBARE: - *physical = addr; - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - return TRANSLATE_SUCCESS; - default: - g_assert_not_reached(); - } - } else { widened = 0; - base = (hwaddr)(env->sptbr) << PGSHIFT; - sum = !get_field(env->mstatus, MSTATUS_PUM); - vm = get_field(env->mstatus, MSTATUS_VM); - switch (vm) { - case VM_1_09_SV32: - levels = 2; ptidxbits = 10; ptesize = 4; break; - case VM_1_09_SV39: - levels = 3; ptidxbits = 9; ptesize = 8; break; - case VM_1_09_SV48: - levels = 4; ptidxbits = 9; ptesize = 8; break; - case VM_1_09_MBARE: - *physical = addr; - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - return TRANSLATE_SUCCESS; - default: - g_assert_not_reached(); - } + } else { + base = (hwaddr)get_field(env->hgatp, HGATP_PPN) << PGSHIFT; + vm = get_field(env->hgatp, HGATP_MODE); + widened = 2; + } + sum = get_field(env->mstatus, MSTATUS_SUM); + switch (vm) { + case VM_1_10_SV32: + levels = 2; ptidxbits = 10; ptesize = 4; break; + case VM_1_10_SV39: + levels = 3; ptidxbits = 9; ptesize = 8; break; + case VM_1_10_SV48: + levels = 4; ptidxbits = 9; ptesize = 8; break; + case VM_1_10_SV57: + levels = 5; ptidxbits = 9; ptesize = 8; break; + case VM_1_10_MBARE: + *physical = addr; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return TRANSLATE_SUCCESS; + default: + g_assert_not_reached(); } CPUState *cs = env_cpu(env); @@ -588,7 +567,6 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address, int page_fault_exceptions; if (first_stage) { page_fault_exceptions = - (env->priv_ver >= PRIV_VERSION_1_10_0) && get_field(env->satp, SATP_MODE) != VM_1_10_MBARE && !pmp_violation; } else { @@ -941,8 +919,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) } s = env->mstatus; - s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ? - get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv)); + s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE)); s = set_field(s, MSTATUS_SPP, env->priv); s = set_field(s, MSTATUS_SIE, 0); env->mstatus = s; @@ -979,8 +956,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) } s = env->mstatus; - s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ? - get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv)); + s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE)); s = set_field(s, MSTATUS_MPP, env->priv); s = set_field(s, MSTATUS_MIE, 0); env->mstatus = s; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 11d184cd16..383be0a955 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -58,31 +58,11 @@ static int ctr(CPURISCVState *env, int csrno) #if !defined(CONFIG_USER_ONLY) CPUState *cs = env_cpu(env); RISCVCPU *cpu = RISCV_CPU(cs); - uint32_t ctr_en = ~0u; if (!cpu->cfg.ext_counters) { /* The Counters extensions is not enabled */ return -1; } - - /* - * The counters are always enabled at run time on newer priv specs, as the - * CSR has changed from controlling that the counters can be read to - * controlling that the counters increment. - */ - if (env->priv_ver > PRIV_VERSION_1_09_1) { - return 0; - } - - if (env->priv < PRV_M) { - ctr_en &= env->mcounteren; - } - if (env->priv < PRV_S) { - ctr_en &= env->scounteren; - } - if (!(ctr_en & (1u << (csrno & 31)))) { - return -1; - } #endif return 0; } @@ -293,9 +273,6 @@ static const target_ulong delegable_excps = (1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) | (1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) | (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT)); -static const target_ulong sstatus_v1_9_mask = SSTATUS_SIE | SSTATUS_SPIE | - SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | - SSTATUS_SUM | SSTATUS_SD; static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD; @@ -304,20 +281,11 @@ static const target_ulong hip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; static const target_ulong vsip_writable_mask = MIP_VSSIP; #if defined(TARGET_RISCV32) -static const char valid_vm_1_09[16] = { - [VM_1_09_MBARE] = 1, - [VM_1_09_SV32] = 1, -}; static const char valid_vm_1_10[16] = { [VM_1_10_MBARE] = 1, [VM_1_10_SV32] = 1 }; #elif defined(TARGET_RISCV64) -static const char valid_vm_1_09[16] = { - [VM_1_09_MBARE] = 1, - [VM_1_09_SV39] = 1, - [VM_1_09_SV48] = 1, -}; static const char valid_vm_1_10[16] = { [VM_1_10_MBARE] = 1, [VM_1_10_SV39] = 1, @@ -347,8 +315,7 @@ static int read_mstatus(CPURISCVState *env, int csrno, target_ulong *val) static int validate_vm(CPURISCVState *env, target_ulong vm) { - return (env->priv_ver >= PRIV_VERSION_1_10_0) ? - valid_vm_1_10[vm & 0xf] : valid_vm_1_09[vm & 0xf]; + return valid_vm_1_10[vm & 0xf]; } static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) @@ -358,34 +325,21 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) int dirty; /* flush tlb on mstatus fields that affect VM */ - if (env->priv_ver <= PRIV_VERSION_1_09_1) { - if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | - MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_VM)) { - tlb_flush(env_cpu(env)); - } - mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE | - MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM | - MSTATUS_MPP | MSTATUS_MXR | - (validate_vm(env, get_field(val, MSTATUS_VM)) ? - MSTATUS_VM : 0); + if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV | + MSTATUS_MPRV | MSTATUS_SUM)) { + tlb_flush(env_cpu(env)); } - if (env->priv_ver >= PRIV_VERSION_1_10_0) { - if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV | - MSTATUS_MPRV | MSTATUS_SUM)) { - tlb_flush(env_cpu(env)); - } - mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE | - MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM | - MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR | - MSTATUS_TW; + mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE | + MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM | + MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR | + MSTATUS_TW; #if defined(TARGET_RISCV64) - /* - * RV32: MPV and MTL are not in mstatus. The current plan is to - * add them to mstatush. For now, we just don't support it. - */ - mask |= MSTATUS_MTL | MSTATUS_MPV; + /* + * RV32: MPV and MTL are not in mstatus. The current plan is to + * add them to mstatush. For now, we just don't support it. + */ + mask |= MSTATUS_MTL | MSTATUS_MPV; #endif - } mstatus = (mstatus & ~mask) | (val & mask); @@ -534,18 +488,12 @@ static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val) static int read_mcounteren(CPURISCVState *env, int csrno, target_ulong *val) { - if (env->priv_ver < PRIV_VERSION_1_10_0) { - return -1; - } *val = env->mcounteren; return 0; } static int write_mcounteren(CPURISCVState *env, int csrno, target_ulong val) { - if (env->priv_ver < PRIV_VERSION_1_10_0) { - return -1; - } env->mcounteren = val; return 0; } @@ -553,8 +501,7 @@ static int write_mcounteren(CPURISCVState *env, int csrno, target_ulong val) /* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */ static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val) { - if (env->priv_ver > PRIV_VERSION_1_09_1 - && env->priv_ver < PRIV_VERSION_1_11_0) { + if (env->priv_ver < PRIV_VERSION_1_11_0) { return -1; } *val = env->mcounteren; @@ -564,32 +511,13 @@ static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val) /* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */ static int write_mscounteren(CPURISCVState *env, int csrno, target_ulong val) { - if (env->priv_ver > PRIV_VERSION_1_09_1 - && env->priv_ver < PRIV_VERSION_1_11_0) { + if (env->priv_ver < PRIV_VERSION_1_11_0) { return -1; } env->mcounteren = val; return 0; } -static int read_mucounteren(CPURISCVState *env, int csrno, target_ulong *val) -{ - if (env->priv_ver > PRIV_VERSION_1_09_1) { - return -1; - } - *val = env->scounteren; - return 0; -} - -static int write_mucounteren(CPURISCVState *env, int csrno, target_ulong val) -{ - if (env->priv_ver > PRIV_VERSION_1_09_1) { - return -1; - } - env->scounteren = val; - return 0; -} - /* Machine Trap Handling */ static int read_mscratch(CPURISCVState *env, int csrno, target_ulong *val) { @@ -663,16 +591,14 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, /* Supervisor Trap Setup */ static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val) { - target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ? - sstatus_v1_10_mask : sstatus_v1_9_mask); + target_ulong mask = (sstatus_v1_10_mask); *val = env->mstatus & mask; return 0; } static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val) { - target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ? - sstatus_v1_10_mask : sstatus_v1_9_mask); + target_ulong mask = (sstatus_v1_10_mask); target_ulong newval = (env->mstatus & ~mask) | (val & mask); return write_mstatus(env, CSR_MSTATUS, newval); } @@ -722,18 +648,12 @@ static int write_stvec(CPURISCVState *env, int csrno, target_ulong val) static int read_scounteren(CPURISCVState *env, int csrno, target_ulong *val) { - if (env->priv_ver < PRIV_VERSION_1_10_0) { - return -1; - } *val = env->scounteren; return 0; } static int write_scounteren(CPURISCVState *env, int csrno, target_ulong val) { - if (env->priv_ver < PRIV_VERSION_1_10_0) { - return -1; - } env->scounteren = val; return 0; } @@ -812,15 +732,15 @@ static int read_satp(CPURISCVState *env, int csrno, target_ulong *val) { if (!riscv_feature(env, RISCV_FEATURE_MMU)) { *val = 0; - } else if (env->priv_ver >= PRIV_VERSION_1_10_0) { - if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { - return -1; - } else { - *val = env->satp; - } - } else { - *val = env->sptbr; + return 0; } + + if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { + return -1; + } else { + *val = env->satp; + } + return 0; } @@ -829,13 +749,7 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) if (!riscv_feature(env, RISCV_FEATURE_MMU)) { return 0; } - if (env->priv_ver <= PRIV_VERSION_1_09_1 && (val ^ env->sptbr)) { - tlb_flush(env_cpu(env)); - env->sptbr = val & (((target_ulong) - 1 << (TARGET_PHYS_ADDR_SPACE_BITS - PGSHIFT)) - 1); - } - if (env->priv_ver >= PRIV_VERSION_1_10_0 && - validate_vm(env, get_field(val, SATP_MODE)) && + if (validate_vm(env, get_field(val, SATP_MODE)) && ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN))) { if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { @@ -1313,8 +1227,6 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MSTATUSH] = { any, read_mstatush, write_mstatush }, #endif - /* Legacy Counter Setup (priv v1.9.1) */ - [CSR_MUCOUNTEREN] = { any, read_mucounteren, write_mucounteren }, [CSR_MSCOUNTEREN] = { any, read_mscounteren, write_mscounteren }, /* Machine Trap Handling */ diff --git a/target/riscv/insn_trans/trans_privileged.inc.c b/target/riscv/insn_trans/trans_privileged.inc.c index 76c2fad71c..5f26e0f5ea 100644 --- a/target/riscv/insn_trans/trans_privileged.inc.c +++ b/target/riscv/insn_trans/trans_privileged.inc.c @@ -85,30 +85,21 @@ static bool trans_wfi(DisasContext *ctx, arg_wfi *a) static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a) { #ifndef CONFIG_USER_ONLY - if (ctx->priv_ver >= PRIV_VERSION_1_10_0) { - gen_helper_tlb_flush(cpu_env); - return true; - } + gen_helper_tlb_flush(cpu_env); + return true; #endif return false; } static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a) { -#ifndef CONFIG_USER_ONLY - if (ctx->priv_ver <= PRIV_VERSION_1_09_1) { - gen_helper_tlb_flush(cpu_env); - return true; - } -#endif return false; } static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) { #ifndef CONFIG_USER_ONLY - if (ctx->priv_ver >= PRIV_VERSION_1_10_0 && - has_ext(ctx, RVH)) { + if (has_ext(ctx, RVH)) { /* Hpervisor extensions exist */ /* * if (env->priv == PRV_M || @@ -127,8 +118,7 @@ static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) static bool trans_hfence_bvma(DisasContext *ctx, arg_sfence_vma *a) { #ifndef CONFIG_USER_ONLY - if (ctx->priv_ver >= PRIV_VERSION_1_10_0 && - has_ext(ctx, RVH)) { + if (has_ext(ctx, RVH)) { /* Hpervisor extensions exist */ /* * if (env->priv == PRV_M || diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c index d725a7a36e..b569f08387 100644 --- a/target/riscv/monitor.c +++ b/target/riscv/monitor.c @@ -215,11 +215,6 @@ void hmp_info_mem(Monitor *mon, const QDict *qdict) return; } - if (env->priv_ver < PRIV_VERSION_1_10_0) { - monitor_printf(mon, "Privileged mode < 1.10 unsupported\n"); - return; - } - if (!(env->satp & SATP_MODE)) { monitor_printf(mon, "No translation or protection\n"); return; diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index c6412f680c..b0c49efc4a 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -84,8 +84,7 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb) riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC()); } - if (env->priv_ver >= PRIV_VERSION_1_10_0 && - get_field(env->mstatus, MSTATUS_TSR) && !(env->priv >= PRV_M)) { + if (get_field(env->mstatus, MSTATUS_TSR) && !(env->priv >= PRV_M)) { riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); } @@ -119,10 +118,8 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb) } else { prev_priv = get_field(mstatus, MSTATUS_SPP); - mstatus = set_field(mstatus, - env->priv_ver >= PRIV_VERSION_1_10_0 ? - MSTATUS_SIE : MSTATUS_UIE << prev_priv, - get_field(mstatus, MSTATUS_SPIE)); + mstatus = set_field(mstatus, MSTATUS_SIE, + get_field(mstatus, MSTATUS_SPIE)); mstatus = set_field(mstatus, MSTATUS_SPIE, 1); mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U); env->mstatus = mstatus; @@ -147,10 +144,8 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb) target_ulong mstatus = env->mstatus; target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP); target_ulong prev_virt = MSTATUS_MPV_ISSET(env); - mstatus = set_field(mstatus, - env->priv_ver >= PRIV_VERSION_1_10_0 ? - MSTATUS_MIE : MSTATUS_UIE << prev_priv, - get_field(mstatus, MSTATUS_MPIE)); + mstatus = set_field(mstatus, MSTATUS_MIE, + get_field(mstatus, MSTATUS_MPIE)); mstatus = set_field(mstatus, MSTATUS_MPIE, 1); mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U); #ifdef TARGET_RISCV32 @@ -177,7 +172,6 @@ void helper_wfi(CPURISCVState *env) CPUState *cs = env_cpu(env); if ((env->priv == PRV_S && - env->priv_ver >= PRIV_VERSION_1_10_0 && get_field(env->mstatus, MSTATUS_TW)) || riscv_cpu_virt_enabled(env)) { riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); @@ -193,7 +187,6 @@ void helper_tlb_flush(CPURISCVState *env) CPUState *cs = env_cpu(env); if (!(env->priv >= PRV_S) || (env->priv == PRV_S && - env->priv_ver >= PRIV_VERSION_1_10_0 && get_field(env->mstatus, MSTATUS_TVM))) { riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); } else { From f33559a427134ff1ae49982bdca8d10f81837204 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 28 May 2020 10:55:13 -0700 Subject: [PATCH 0821/2595] docs: deprecated: Update the -bios documentation Update the -bios deprecation documentation to describe the new behaviour. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- docs/system/deprecated.rst | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index d177609cbc..544ece0a45 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -138,25 +138,23 @@ the backing storage specified with ``-mem-path`` can actually provide the guest RAM configured with ``-m`` and QEMU will fail to start up if RAM allocation is unsuccessful. -RISC-V ``-bios`` (since 4.1) +RISC-V ``-bios`` (since 5.1) '''''''''''''''''''''''''''' QEMU 4.1 introduced support for the -bios option in QEMU for RISC-V for the -RISC-V virt machine and sifive_u machine. +RISC-V virt machine and sifive_u machine. QEMU 4.1 had no changes to the +default behaviour to avoid breakages. -QEMU 4.1 has no changes to the default behaviour to avoid breakages. This -default will change in a future QEMU release, so please prepare now. All users -of the virt or sifive_u machine must change their command line usage. +QEMU 5.1 changes the default behaviour from ``-bios none`` to ``-bios default``. -QEMU 4.1 has three options, please migrate to one of these three: - 1. ``-bios none`` - This is the current default behavior if no -bios option - is included. QEMU will not automatically load any firmware. It is up +QEMU 5.1 has three options: + 1. ``-bios default`` - This is the current default behavior if no -bios option + is included. This option will load the default OpenSBI firmware automatically. + The firmware is included with the QEMU release and no user interaction is + required. All a user needs to do is specify the kernel they want to boot + with the -kernel option + 2. ``-bios none`` - QEMU will not automatically load any firmware. It is up to the user to load all the images they need. - 2. ``-bios default`` - In a future QEMU release this will become the default - behaviour if no -bios option is specified. This option will load the - default OpenSBI firmware automatically. The firmware is included with - the QEMU release and no user interaction is required. All a user needs - to do is specify the kernel they want to boot with the -kernel option 3. ``-bios `` - Tells QEMU to load the specified file as the firmwrae. ``-tb-size`` option (since 5.0) From 0869490b1cc4d917ac4eb3a02cac7d71149def91 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 13 May 2020 10:37:08 -0700 Subject: [PATCH 0822/2595] riscv: sifive_e: Manually define the machine Signed-off-by: Alistair Francis Reviewed-by: Palmer Dabbelt --- hw/riscv/sifive_e.c | 41 +++++++++++++++++++++++++++---------- include/hw/riscv/sifive_e.h | 4 ++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index b53109521e..472a98970b 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -79,7 +79,7 @@ static void riscv_sifive_e_init(MachineState *machine) { const struct MemmapEntry *memmap = sifive_e_memmap; - SiFiveEState *s = g_new0(SiFiveEState, 1); + SiFiveEState *s = RISCV_E_MACHINE(machine); MemoryRegion *sys_mem = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); int i; @@ -115,6 +115,35 @@ static void riscv_sifive_e_init(MachineState *machine) } } +static void sifive_e_machine_instance_init(Object *obj) +{ +} + +static void sifive_e_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "RISC-V Board compatible with SiFive E SDK"; + mc->init = riscv_sifive_e_init; + mc->max_cpus = 1; + mc->default_cpu_type = SIFIVE_E_CPU; +} + +static const TypeInfo sifive_e_machine_typeinfo = { + .name = MACHINE_TYPE_NAME("sifive_e"), + .parent = TYPE_MACHINE, + .class_init = sifive_e_machine_class_init, + .instance_init = sifive_e_machine_instance_init, + .instance_size = sizeof(SiFiveEState), +}; + +static void sifive_e_machine_init_register_types(void) +{ + type_register_static(&sifive_e_machine_typeinfo); +} + +type_init(sifive_e_machine_init_register_types) + static void riscv_sifive_e_soc_init(Object *obj) { MachineState *ms = MACHINE(qdev_get_machine()); @@ -214,16 +243,6 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) &s->xip_mem); } -static void riscv_sifive_e_machine_init(MachineClass *mc) -{ - mc->desc = "RISC-V Board compatible with SiFive E SDK"; - mc->init = riscv_sifive_e_init; - mc->max_cpus = 1; - mc->default_cpu_type = SIFIVE_E_CPU; -} - -DEFINE_MACHINE("sifive_e", riscv_sifive_e_machine_init) - static void riscv_sifive_e_soc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h index 25ce7aa9d5..414992119e 100644 --- a/include/hw/riscv/sifive_e.h +++ b/include/hw/riscv/sifive_e.h @@ -47,6 +47,10 @@ typedef struct SiFiveEState { SiFiveESoCState soc; } SiFiveEState; +#define TYPE_RISCV_E_MACHINE MACHINE_TYPE_NAME("sifive_e") +#define RISCV_E_MACHINE(obj) \ + OBJECT_CHECK(SiFiveEState, (obj), TYPE_RISCV_E_MACHINE) + enum { SIFIVE_E_DEBUG, SIFIVE_E_MROM, From 757e99b1ebfa8bc2823ba686ab56bb9941b2f238 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 23 Apr 2020 14:09:37 -0700 Subject: [PATCH 0823/2595] riscv/boot: Add a missing header include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the functions declared in this header use the symbol_fn_t typedef itself declared in "hw/loader.h", we need to include it here to make the header file self-contained. Signed-off-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bin Meng --- include/hw/riscv/boot.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index 474a940ad5..9daa98da08 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -21,6 +21,7 @@ #define RISCV_BOOT_H #include "exec/cpu-defs.h" +#include "hw/loader.h" void riscv_find_and_load_firmware(MachineState *machine, const char *default_machine_firmware, From f92d46ad07064d7b45ebb5f0e983af9b29af2ced Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 19 May 2020 11:04:12 -0700 Subject: [PATCH 0824/2595] target/riscv: Don't overwrite the reset vector The reset vector is set in the init function don't set it again in realize. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- target/riscv/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index eeb91f8513..55a180edf9 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -133,6 +133,7 @@ static void riscv_base32_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ set_misa(env, 0); + set_resetvec(env, DEFAULT_RSTVEC); } static void rv32gcsu_priv1_10_0_cpu_init(Object *obj) @@ -170,6 +171,7 @@ static void riscv_base64_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ set_misa(env, 0); + set_resetvec(env, DEFAULT_RSTVEC); } static void rv64gcsu_priv1_10_0_cpu_init(Object *obj) @@ -377,7 +379,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } set_priv_version(env, priv_version); - set_resetvec(env, DEFAULT_RSTVEC); if (cpu->cfg.mmu) { set_feature(env, RISCV_FEATURE_MMU); From 8be6971b73da45e8ee9f8decd136ff054b5230ac Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 26 May 2020 16:06:02 -0700 Subject: [PATCH 0825/2595] target/riscv: Disable the MMU correctly Previously if we didn't enable the MMU it would be enabled in the realize() function anyway. Let's ensure that if we don't want the MMU we disable it. We also don't need to enable the MMU as it will be enabled in realize() by default. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- target/riscv/cpu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 55a180edf9..e1c9a2de58 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -142,7 +142,6 @@ static void rv32gcsu_priv1_10_0_cpu_init(Object *obj) set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); - set_feature(env, RISCV_FEATURE_MMU); set_feature(env, RISCV_FEATURE_PMP); } @@ -153,6 +152,7 @@ static void rv32imacu_nommu_cpu_init(Object *obj) set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); set_feature(env, RISCV_FEATURE_PMP); + qdev_prop_set_bit(DEVICE(obj), "mmu", false); } static void rv32imafcu_nommu_cpu_init(Object *obj) @@ -162,6 +162,7 @@ static void rv32imafcu_nommu_cpu_init(Object *obj) set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); set_feature(env, RISCV_FEATURE_PMP); + qdev_prop_set_bit(DEVICE(obj), "mmu", false); } #elif defined(TARGET_RISCV64) @@ -180,7 +181,6 @@ static void rv64gcsu_priv1_10_0_cpu_init(Object *obj) set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); - set_feature(env, RISCV_FEATURE_MMU); set_feature(env, RISCV_FEATURE_PMP); } @@ -191,6 +191,7 @@ static void rv64imacu_nommu_cpu_init(Object *obj) set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); set_feature(env, RISCV_FEATURE_PMP); + qdev_prop_set_bit(DEVICE(obj), "mmu", false); } #endif From ff832b77aa8ab454e092fb73b61821e56218e8a5 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 28 May 2020 11:04:15 -0700 Subject: [PATCH 0826/2595] target/riscv: Don't set PMP feature in the cpu init The PMP is enabled by default via the "pmp" property so there is no need for us to set it in the init function. As all CPUs have PMP support just remove the set_feature() call in the CPU init functions. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- target/riscv/cpu.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index e1c9a2de58..54829217dc 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -142,7 +142,6 @@ static void rv32gcsu_priv1_10_0_cpu_init(Object *obj) set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); - set_feature(env, RISCV_FEATURE_PMP); } static void rv32imacu_nommu_cpu_init(Object *obj) @@ -151,7 +150,6 @@ static void rv32imacu_nommu_cpu_init(Object *obj) set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); - set_feature(env, RISCV_FEATURE_PMP); qdev_prop_set_bit(DEVICE(obj), "mmu", false); } @@ -161,7 +159,6 @@ static void rv32imafcu_nommu_cpu_init(Object *obj) set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); - set_feature(env, RISCV_FEATURE_PMP); qdev_prop_set_bit(DEVICE(obj), "mmu", false); } @@ -181,7 +178,6 @@ static void rv64gcsu_priv1_10_0_cpu_init(Object *obj) set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); - set_feature(env, RISCV_FEATURE_PMP); } static void rv64imacu_nommu_cpu_init(Object *obj) @@ -190,7 +186,6 @@ static void rv64imacu_nommu_cpu_init(Object *obj) set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); - set_feature(env, RISCV_FEATURE_PMP); qdev_prop_set_bit(DEVICE(obj), "mmu", false); } From 36b80ad99f7ea4979a4c5fc6e4072619b405e3b0 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 23 Apr 2020 10:50:09 -0700 Subject: [PATCH 0827/2595] target/riscv: Add the lowRISC Ibex CPU Ibex is a small and efficient, 32-bit, in-order RISC-V core with a 2-stage pipeline that implements the RV32IMC instruction set architecture. For more details on lowRISC see here: https://github.com/lowRISC/ibex Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Reviewed-by: LIU Zhiwei --- target/riscv/cpu.c | 10 ++++++++++ target/riscv/cpu.h | 1 + 2 files changed, 11 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 54829217dc..9007a25656 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -144,6 +144,15 @@ static void rv32gcsu_priv1_10_0_cpu_init(Object *obj) set_resetvec(env, DEFAULT_RSTVEC); } +static void rv32imcu_nommu_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + set_misa(env, RV32 | RVI | RVM | RVC | RVU); + set_priv_version(env, PRIV_VERSION_1_10_0); + set_resetvec(env, 0x8090); + qdev_prop_set_bit(DEVICE(obj), "mmu", false); +} + static void rv32imacu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -593,6 +602,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), #if defined(TARGET_RISCV32) DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base32_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32imcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32imafcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index c022539012..80569f0d44 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -35,6 +35,7 @@ #define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any") #define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32") #define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64") +#define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex") #define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") #define TYPE_RISCV_CPU_SIFIVE_E34 RISCV_CPU_TYPE_NAME("sifive-e34") #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") From fe0fe4735e798578097758781166cc221319b93d Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 23 Apr 2020 11:30:50 -0700 Subject: [PATCH 0828/2595] riscv: Initial commit of OpenTitan machine This adds a barebone OpenTitan machine to QEMU. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- MAINTAINERS | 9 ++ default-configs/riscv32-softmmu.mak | 1 + default-configs/riscv64-softmmu.mak | 11 +- hw/riscv/Kconfig | 5 + hw/riscv/Makefile.objs | 1 + hw/riscv/opentitan.c | 184 ++++++++++++++++++++++++++++ include/hw/riscv/opentitan.h | 68 ++++++++++ 7 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 hw/riscv/opentitan.c create mode 100644 include/hw/riscv/opentitan.h diff --git a/MAINTAINERS b/MAINTAINERS index 0944d9c731..3e7d9cb0a5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1238,6 +1238,15 @@ F: pc-bios/canyonlands.dt[sb] F: pc-bios/u-boot-sam460ex-20100605.bin F: roms/u-boot-sam460ex +RISC-V Machines +--------------- +OpenTitan +M: Alistair Francis +L: qemu-riscv@nongnu.org +S: Supported +F: hw/riscv/opentitan.c +F: include/hw/riscv/opentitan.h + SH4 Machines ------------ R2D diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak index 1ae077ed87..94a236c9c2 100644 --- a/default-configs/riscv32-softmmu.mak +++ b/default-configs/riscv32-softmmu.mak @@ -10,3 +10,4 @@ CONFIG_SPIKE=y CONFIG_SIFIVE_E=y CONFIG_SIFIVE_U=y CONFIG_RISCV_VIRT=y +CONFIG_OPENTITAN=y diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak index 235c6f473f..aaf6d735bb 100644 --- a/default-configs/riscv64-softmmu.mak +++ b/default-configs/riscv64-softmmu.mak @@ -1,3 +1,12 @@ # Default configuration for riscv64-softmmu -include riscv32-softmmu.mak +# Uncomment the following lines to disable these optional devices: +# +#CONFIG_PCI_DEVICES=n + +# Boards: +# +CONFIG_SPIKE=y +CONFIG_SIFIVE_E=y +CONFIG_SIFIVE_U=y +CONFIG_RISCV_VIRT=y diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index ff9fbe958a..94d19571f7 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -27,6 +27,11 @@ config SPIKE select HTIF select SIFIVE +config OPENTITAN + bool + select HART + select UNIMP + config RISCV_VIRT bool imply PCI_DEVICES diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs index fc3c6dd7c8..57cc708f5d 100644 --- a/hw/riscv/Makefile.objs +++ b/hw/riscv/Makefile.objs @@ -1,6 +1,7 @@ obj-y += boot.o obj-$(CONFIG_SPIKE) += riscv_htif.o obj-$(CONFIG_HART) += riscv_hart.o +obj-$(CONFIG_OPENTITAN) += opentitan.o obj-$(CONFIG_SIFIVE_E) += sifive_e.o obj-$(CONFIG_SIFIVE_E) += sifive_e_prci.o obj-$(CONFIG_SIFIVE) += sifive_clint.o diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c new file mode 100644 index 0000000000..b4fb836466 --- /dev/null +++ b/hw/riscv/opentitan.c @@ -0,0 +1,184 @@ +/* + * QEMU RISC-V Board Compatible with OpenTitan FPGA platform + * + * Copyright (c) 2020 Western Digital + * + * Provides a board compatible with the OpenTitan FPGA platform: + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#include "qemu/osdep.h" +#include "hw/riscv/opentitan.h" +#include "qapi/error.h" +#include "hw/boards.h" +#include "hw/misc/unimp.h" +#include "hw/riscv/boot.h" +#include "exec/address-spaces.h" + +static const struct MemmapEntry { + hwaddr base; + hwaddr size; +} ibex_memmap[] = { + [IBEX_ROM] = { 0x00008000, 0xc000 }, + [IBEX_RAM] = { 0x10000000, 0x10000 }, + [IBEX_FLASH] = { 0x20000000, 0x80000 }, + [IBEX_UART] = { 0x40000000, 0x10000 }, + [IBEX_GPIO] = { 0x40010000, 0x10000 }, + [IBEX_SPI] = { 0x40020000, 0x10000 }, + [IBEX_FLASH_CTRL] = { 0x40030000, 0x10000 }, + [IBEX_PINMUX] = { 0x40070000, 0x10000 }, + [IBEX_RV_TIMER] = { 0x40080000, 0x10000 }, + [IBEX_PLIC] = { 0x40090000, 0x10000 }, + [IBEX_PWRMGR] = { 0x400A0000, 0x10000 }, + [IBEX_RSTMGR] = { 0x400B0000, 0x10000 }, + [IBEX_CLKMGR] = { 0x400C0000, 0x10000 }, + [IBEX_AES] = { 0x40110000, 0x10000 }, + [IBEX_HMAC] = { 0x40120000, 0x10000 }, + [IBEX_ALERT_HANDLER] = { 0x40130000, 0x10000 }, + [IBEX_NMI_GEN] = { 0x40140000, 0x10000 }, + [IBEX_USBDEV] = { 0x40150000, 0x10000 }, + [IBEX_PADCTRL] = { 0x40160000, 0x10000 } +}; + +static void riscv_opentitan_init(MachineState *machine) +{ + const struct MemmapEntry *memmap = ibex_memmap; + OpenTitanState *s = g_new0(OpenTitanState, 1); + MemoryRegion *sys_mem = get_system_memory(); + MemoryRegion *main_mem = g_new(MemoryRegion, 1); + + /* Initialize SoC */ + object_initialize_child(OBJECT(machine), "soc", &s->soc, + sizeof(s->soc), TYPE_RISCV_IBEX_SOC, + &error_abort, NULL); + object_property_set_bool(OBJECT(&s->soc), true, "realized", + &error_abort); + + memory_region_init_ram(main_mem, NULL, "riscv.lowrisc.ibex.ram", + memmap[IBEX_RAM].size, &error_fatal); + memory_region_add_subregion(sys_mem, + memmap[IBEX_RAM].base, main_mem); + + + if (machine->firmware) { + riscv_load_firmware(machine->firmware, memmap[IBEX_RAM].base, NULL); + } + + if (machine->kernel_filename) { + riscv_load_kernel(machine->kernel_filename, NULL); + } +} + +static void riscv_opentitan_machine_init(MachineClass *mc) +{ + mc->desc = "RISC-V Board compatible with OpenTitan"; + mc->init = riscv_opentitan_init; + mc->max_cpus = 1; + mc->default_cpu_type = TYPE_RISCV_CPU_IBEX; +} + +DEFINE_MACHINE("opentitan", riscv_opentitan_machine_init) + +static void riscv_lowrisc_ibex_soc_init(Object *obj) +{ + LowRISCIbexSoCState *s = RISCV_IBEX_SOC(obj); + + object_initialize_child(obj, "cpus", &s->cpus, + sizeof(s->cpus), TYPE_RISCV_HART_ARRAY, + &error_abort, NULL); +} + +static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) +{ + const struct MemmapEntry *memmap = ibex_memmap; + MachineState *ms = MACHINE(qdev_get_machine()); + LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc); + MemoryRegion *sys_mem = get_system_memory(); + + object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type", + &error_abort); + object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts", + &error_abort); + object_property_set_bool(OBJECT(&s->cpus), true, "realized", + &error_abort); + + /* Boot ROM */ + memory_region_init_rom(&s->rom, OBJECT(dev_soc), "riscv.lowrisc.ibex.rom", + memmap[IBEX_ROM].size, &error_fatal); + memory_region_add_subregion(sys_mem, + memmap[IBEX_ROM].base, &s->rom); + + /* Flash memory */ + memory_region_init_rom(&s->flash_mem, OBJECT(dev_soc), "riscv.lowrisc.ibex.flash", + memmap[IBEX_FLASH].size, &error_fatal); + memory_region_add_subregion(sys_mem, memmap[IBEX_FLASH].base, + &s->flash_mem); + + create_unimplemented_device("riscv.lowrisc.ibex.uart", + memmap[IBEX_UART].base, memmap[IBEX_UART].size); + create_unimplemented_device("riscv.lowrisc.ibex.gpio", + memmap[IBEX_GPIO].base, memmap[IBEX_GPIO].size); + create_unimplemented_device("riscv.lowrisc.ibex.spi", + memmap[IBEX_SPI].base, memmap[IBEX_SPI].size); + create_unimplemented_device("riscv.lowrisc.ibex.flash_ctrl", + memmap[IBEX_FLASH_CTRL].base, memmap[IBEX_FLASH_CTRL].size); + create_unimplemented_device("riscv.lowrisc.ibex.rv_timer", + memmap[IBEX_RV_TIMER].base, memmap[IBEX_RV_TIMER].size); + create_unimplemented_device("riscv.lowrisc.ibex.pwrmgr", + memmap[IBEX_PWRMGR].base, memmap[IBEX_PWRMGR].size); + create_unimplemented_device("riscv.lowrisc.ibex.rstmgr", + memmap[IBEX_RSTMGR].base, memmap[IBEX_RSTMGR].size); + create_unimplemented_device("riscv.lowrisc.ibex.clkmgr", + memmap[IBEX_CLKMGR].base, memmap[IBEX_CLKMGR].size); + create_unimplemented_device("riscv.lowrisc.ibex.aes", + memmap[IBEX_AES].base, memmap[IBEX_AES].size); + create_unimplemented_device("riscv.lowrisc.ibex.hmac", + memmap[IBEX_HMAC].base, memmap[IBEX_HMAC].size); + create_unimplemented_device("riscv.lowrisc.ibex.plic", + memmap[IBEX_PLIC].base, memmap[IBEX_PLIC].size); + create_unimplemented_device("riscv.lowrisc.ibex.pinmux", + memmap[IBEX_PINMUX].base, memmap[IBEX_PINMUX].size); + create_unimplemented_device("riscv.lowrisc.ibex.alert_handler", + memmap[IBEX_ALERT_HANDLER].base, memmap[IBEX_ALERT_HANDLER].size); + create_unimplemented_device("riscv.lowrisc.ibex.nmi_gen", + memmap[IBEX_NMI_GEN].base, memmap[IBEX_NMI_GEN].size); + create_unimplemented_device("riscv.lowrisc.ibex.usbdev", + memmap[IBEX_USBDEV].base, memmap[IBEX_USBDEV].size); + create_unimplemented_device("riscv.lowrisc.ibex.padctrl", + memmap[IBEX_PADCTRL].base, memmap[IBEX_PADCTRL].size); +} + +static void riscv_lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = riscv_lowrisc_ibex_soc_realize; + /* Reason: Uses serial_hds in realize function, thus can't be used twice */ + dc->user_creatable = false; +} + +static const TypeInfo riscv_lowrisc_ibex_soc_type_info = { + .name = TYPE_RISCV_IBEX_SOC, + .parent = TYPE_DEVICE, + .instance_size = sizeof(LowRISCIbexSoCState), + .instance_init = riscv_lowrisc_ibex_soc_init, + .class_init = riscv_lowrisc_ibex_soc_class_init, +}; + +static void riscv_lowrisc_ibex_soc_register_types(void) +{ + type_register_static(&riscv_lowrisc_ibex_soc_type_info); +} + +type_init(riscv_lowrisc_ibex_soc_register_types) diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h new file mode 100644 index 0000000000..a4b6499444 --- /dev/null +++ b/include/hw/riscv/opentitan.h @@ -0,0 +1,68 @@ +/* + * QEMU RISC-V Board Compatible with OpenTitan FPGA platform + * + * Copyright (c) 2020 Western Digital + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#ifndef HW_OPENTITAN_H +#define HW_OPENTITAN_H + +#include "hw/riscv/riscv_hart.h" + +#define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc" +#define RISCV_IBEX_SOC(obj) \ + OBJECT_CHECK(LowRISCIbexSoCState, (obj), TYPE_RISCV_IBEX_SOC) + +typedef struct LowRISCIbexSoCState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + RISCVHartArrayState cpus; + MemoryRegion flash_mem; + MemoryRegion rom; +} LowRISCIbexSoCState; + +typedef struct OpenTitanState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + LowRISCIbexSoCState soc; +} OpenTitanState; + +enum { + IBEX_ROM, + IBEX_RAM, + IBEX_FLASH, + IBEX_UART, + IBEX_GPIO, + IBEX_SPI, + IBEX_FLASH_CTRL, + IBEX_RV_TIMER, + IBEX_AES, + IBEX_HMAC, + IBEX_PLIC, + IBEX_PWRMGR, + IBEX_RSTMGR, + IBEX_CLKMGR, + IBEX_PINMUX, + IBEX_ALERT_HANDLER, + IBEX_NMI_GEN, + IBEX_USBDEV, + IBEX_PADCTRL, +}; + +#endif From a98610c429d52db0937c1e48659428929835c455 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Thu, 4 Jun 2020 14:38:30 +0530 Subject: [PATCH 0829/2595] ati-vga: check mm_index before recursive call (CVE-2020-13800) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While accessing VGA registers via ati_mm_read/write routines, a guest may set 's->regs.mm_index' such that it leads to infinite recursion. Check mm_index value to avoid such recursion. Log an error message for wrong values. Reported-by: Ren Ding Reported-by: Hanqing Zhao Reported-by: Yi Ren Message-id: 20200604090830.33885-1-ppandit@redhat.com Suggested-by: BALATON Zoltan Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Prasad J Pandit Signed-off-by: Gerd Hoffmann --- hw/display/ati.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/display/ati.c b/hw/display/ati.c index 065f197678..67604e68de 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -285,8 +285,11 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) if (idx <= s->vga.vram_size - size) { val = ldn_le_p(s->vga.vram_ptr + idx, size); } - } else { + } else if (s->regs.mm_index > MM_DATA + 3) { val = ati_mm_read(s, s->regs.mm_index + addr - MM_DATA, size); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "ati_mm_read: mm_index too small: %u\n", s->regs.mm_index); } break; case BIOS_0_SCRATCH ... BUS_CNTL - 1: @@ -520,8 +523,11 @@ static void ati_mm_write(void *opaque, hwaddr addr, if (idx <= s->vga.vram_size - size) { stn_le_p(s->vga.vram_ptr + idx, size, data); } - } else { + } else if (s->regs.mm_index > MM_DATA + 3) { ati_mm_write(s, s->regs.mm_index + addr - MM_DATA, data, size); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "ati_mm_write: mm_index too small: %u\n", s->regs.mm_index); } break; case BIOS_0_SCRATCH ... BUS_CNTL - 1: From ae3887e6f08c0031b669d4613987ee51df8f1769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 29 May 2020 18:54:36 +0200 Subject: [PATCH 0830/2595] hw/display/cirrus_vga: Fix code mis-indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While replacing fprintf() by qemu_log_mask() in commit 2b55f4d3504, we incorrectly used a 'tab = 4 spaces' alignment, leading to misindented new code. Fix now. Reported-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200529165436.23573-1-f4bug@amsat.org Signed-off-by: Gerd Hoffmann --- hw/display/cirrus_vga.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 92c197cdde..212d6f5e61 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -1032,9 +1032,9 @@ static void cirrus_bitblt_start(CirrusVGAState * s) } else { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { if (s->cirrus_blt_pixelwidth > 2) { - qemu_log_mask(LOG_GUEST_ERROR, - "cirrus: src transparent without colorexpand " - "must be 8bpp or 16bpp\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "cirrus: src transparent without colorexpand " + "must be 8bpp or 16bpp\n"); goto bitblt_ignore; } if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { From b4e44c9944e19c8bfc7fbf0c4a6a5e48f3ba3dc0 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 19 May 2020 15:30:41 +0200 Subject: [PATCH 0831/2595] io_uring: retry io_uring_submit() if it fails with errno=EINTR As recently documented [1], io_uring_enter(2) syscall can return an error (errno=EINTR) if the operation was interrupted by a delivery of a signal before it could complete. This should happen when IORING_ENTER_GETEVENTS flag is used, for example during io_uring_submit_and_wait() or during io_uring_submit() when IORING_SETUP_IOPOLL is enabled. We shouldn't have this problem for now, but it's better to prevent it. [1] https://github.com/axboe/liburing/commit/344355ec6619de8f4e64584c9736530b5346e4f4 Signed-off-by: Stefano Garzarella Message-id: 20200519133041.112138-1-sgarzare@redhat.com Signed-off-by: Stefan Hajnoczi --- block/io_uring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/io_uring.c b/block/io_uring.c index a3142ca989..9765681f7c 100644 --- a/block/io_uring.c +++ b/block/io_uring.c @@ -231,7 +231,7 @@ static int ioq_submit(LuringState *s) trace_luring_io_uring_submit(s, ret); /* Prevent infinite loop if submission is refused */ if (ret <= 0) { - if (ret == -EAGAIN) { + if (ret == -EAGAIN || ret == -EINTR) { continue; } break; From 769335ecb1e8fd9c4317bdff7cfd0f84af7ab2f9 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 19 May 2020 15:49:42 +0200 Subject: [PATCH 0832/2595] io_uring: use io_uring_cq_ready() to check for ready cqes In qemu_luring_poll_cb() we are not using the cqe peeked from the CQ ring. We are using io_uring_peek_cqe() only to see if there are cqes ready, so we can replace it with io_uring_cq_ready(). Signed-off-by: Stefano Garzarella Message-id: 20200519134942.118178-1-sgarzare@redhat.com Signed-off-by: Stefan Hajnoczi --- block/io_uring.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/block/io_uring.c b/block/io_uring.c index 9765681f7c..037af09471 100644 --- a/block/io_uring.c +++ b/block/io_uring.c @@ -277,13 +277,10 @@ static void qemu_luring_completion_cb(void *opaque) static bool qemu_luring_poll_cb(void *opaque) { LuringState *s = opaque; - struct io_uring_cqe *cqes; - if (io_uring_peek_cqe(&s->ring, &cqes) == 0) { - if (cqes) { - luring_process_completions_and_submit(s); - return true; - } + if (io_uring_cq_ready(&s->ring)) { + luring_process_completions_and_submit(s); + return true; } return false; From 7a071a96d3ef48095892c1d1075c0181c8940058 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Mon, 11 May 2020 23:01:30 -0400 Subject: [PATCH 0833/2595] fuzz: add datadir for oss-fuzz compatability This allows us to keep pc-bios in executable_dir/pc-bios, rather than executable_dir/../pc-bios, which is incompatible with oss-fuzz' file structure. Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny Message-id: 20200512030133.29896-2-alxndr@bu.edu Signed-off-by: Stefan Hajnoczi --- include/sysemu/sysemu.h | 2 ++ softmmu/vl.c | 2 +- tests/qtest/fuzz/fuzz.c | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 26c0c802d1..3efccdba7e 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -15,6 +15,8 @@ extern const char *qemu_name; extern QemuUUID qemu_uuid; extern bool qemu_uuid_set; +void qemu_add_data_dir(const char *path); + void qemu_add_exit_notifier(Notifier *notify); void qemu_remove_exit_notifier(Notifier *notify); diff --git a/softmmu/vl.c b/softmmu/vl.c index ae5451bc23..05d1a4cb6b 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1993,7 +1993,7 @@ char *qemu_find_file(int type, const char *name) return NULL; } -static void qemu_add_data_dir(const char *path) +void qemu_add_data_dir(const char *path) { int i; diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index f5c923852e..33365c3782 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -137,6 +137,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) { char *target_name; + char *dir; /* Initialize qgraph and modules */ qos_graph_init(); @@ -147,6 +148,20 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) target_name = strstr(**argv, "-target-"); if (target_name) { /* The binary name specifies the target */ target_name += strlen("-target-"); + /* + * With oss-fuzz, the executable is kept in the root of a directory (we + * cannot assume the path). All data (including bios binaries) must be + * in the same dir, or a subdir. Thus, we cannot place the pc-bios so + * that it would be in exec_dir/../pc-bios. + * As a workaround, oss-fuzz allows us to use argv[0] to get the + * location of the executable. Using this we add exec_dir/pc-bios to + * the datadirs. + */ + dir = g_build_filename(g_path_get_dirname(**argv), "pc-bios", NULL); + if (g_file_test(dir, G_FILE_TEST_IS_DIR)) { + qemu_add_data_dir(dir); + } + g_free(dir); } else if (*argc > 1) { /* The target is specified as an argument */ target_name = (*argv)[1]; if (!strstr(target_name, "--fuzz-target=")) { From 6851803a467238ed39408e35b5f2063c1370b156 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Mon, 11 May 2020 23:01:31 -0400 Subject: [PATCH 0834/2595] fuzz: fix typo in i440fx-qtest-reboot arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200512030133.29896-3-alxndr@bu.edu Signed-off-by: Stefan Hajnoczi --- tests/qtest/fuzz/i440fx_fuzz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/fuzz/i440fx_fuzz.c b/tests/qtest/fuzz/i440fx_fuzz.c index bcd6769b4c..775b3041ba 100644 --- a/tests/qtest/fuzz/i440fx_fuzz.c +++ b/tests/qtest/fuzz/i440fx_fuzz.c @@ -156,7 +156,7 @@ static void i440fx_fuzz_qos_fork(QTestState *s, } static const char *i440fx_qtest_argv = TARGET_NAME " -machine accel=qtest" - "-m 0 -display none"; + " -m 0 -display none"; static const char *i440fx_argv(FuzzTarget *t) { return i440fx_qtest_argv; From 3b113229c5d5477d34f54fce0a3e8781090c93b6 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Mon, 11 May 2020 23:01:32 -0400 Subject: [PATCH 0835/2595] fuzz: add mangled object name to linker script Previously, we relied on "FuzzerTracePC*(.bss*)" to place libfuzzer's fuzzer::TPC object into our contiguous shared-memory region. This does not work for some libfuzzer builds, so this addition identifies the region by its mangled name: *(.bss._ZN6fuzzer3TPCE); Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny Message-id: 20200512030133.29896-4-alxndr@bu.edu Signed-off-by: Stefan Hajnoczi --- tests/qtest/fuzz/fork_fuzz.ld | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/qtest/fuzz/fork_fuzz.ld b/tests/qtest/fuzz/fork_fuzz.ld index e086bba873..bfb667ed06 100644 --- a/tests/qtest/fuzz/fork_fuzz.ld +++ b/tests/qtest/fuzz/fork_fuzz.ld @@ -28,6 +28,11 @@ SECTIONS /* Internal Libfuzzer TracePC object which contains the ValueProfileMap */ FuzzerTracePC*(.bss*); + /* + * In case the above line fails, explicitly specify the (mangled) name of + * the object we care about + */ + *(.bss._ZN6fuzzer3TPCE); } .data.fuzz_end : ALIGN(4K) { From dfd5ddb5680511a2aa5576d8ed01ff214cc0fc03 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Mon, 11 May 2020 23:01:33 -0400 Subject: [PATCH 0836/2595] fuzz: run the main-loop in fork-server process Without this, the time since the last main-loop keeps increasing, as the fuzzer runs. The forked children need to handle all the "past-due" timers, slowing them down, over time. With this change, the parent/fork-server process runs the main-loop, while waiting on the child, ensuring that the timer events do not pile up, over time. Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny Message-id: 20200512030133.29896-5-alxndr@bu.edu Signed-off-by: Stefan Hajnoczi --- tests/qtest/fuzz/i440fx_fuzz.c | 1 + tests/qtest/fuzz/virtio_net_fuzz.c | 2 ++ tests/qtest/fuzz/virtio_scsi_fuzz.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/tests/qtest/fuzz/i440fx_fuzz.c b/tests/qtest/fuzz/i440fx_fuzz.c index 775b3041ba..e2f31e56f9 100644 --- a/tests/qtest/fuzz/i440fx_fuzz.c +++ b/tests/qtest/fuzz/i440fx_fuzz.c @@ -151,6 +151,7 @@ static void i440fx_fuzz_qos_fork(QTestState *s, i440fx_fuzz_qos(s, Data, Size); _Exit(0); } else { + flush_events(s); wait(NULL); } } diff --git a/tests/qtest/fuzz/virtio_net_fuzz.c b/tests/qtest/fuzz/virtio_net_fuzz.c index d08a47e278..a33bd73067 100644 --- a/tests/qtest/fuzz/virtio_net_fuzz.c +++ b/tests/qtest/fuzz/virtio_net_fuzz.c @@ -122,6 +122,7 @@ static void virtio_net_fork_fuzz(QTestState *s, flush_events(s); _Exit(0); } else { + flush_events(s); wait(NULL); } } @@ -134,6 +135,7 @@ static void virtio_net_fork_fuzz_check_used(QTestState *s, flush_events(s); _Exit(0); } else { + flush_events(s); wait(NULL); } } diff --git a/tests/qtest/fuzz/virtio_scsi_fuzz.c b/tests/qtest/fuzz/virtio_scsi_fuzz.c index 3b95247f12..51dce491ab 100644 --- a/tests/qtest/fuzz/virtio_scsi_fuzz.c +++ b/tests/qtest/fuzz/virtio_scsi_fuzz.c @@ -145,6 +145,7 @@ static void virtio_scsi_fork_fuzz(QTestState *s, flush_events(s); _Exit(0); } else { + flush_events(s); wait(NULL); } } @@ -164,6 +165,7 @@ static void virtio_scsi_with_flag_fuzz(QTestState *s, } _Exit(0); } else { + flush_events(s); wait(NULL); } } From 4dfe59d187d9b218efca8d89c0c2fac1298d8712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 8 May 2020 08:24:53 +0200 Subject: [PATCH 0837/2595] memory: Rename memory_region_do_writeback -> memory_region_writeback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We usually use '_do_' for internal functions. Rename memory_region_do_writeback() as memory_region_writeback(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Reviewed-by: Richard Henderson Acked-by: Paolo Bonzini Message-id: 20200508062456.23344-2-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- include/exec/memory.h | 4 ++-- memory.c | 2 +- target/arm/helper.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index e000bd2f97..1b7cfdd5b6 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1474,14 +1474,14 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr); void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp); /** - * memory_region_do_writeback: Trigger cache writeback or msync for + * memory_region_writeback: Trigger cache writeback or msync for * selected address range * * @mr: the memory region to be updated * @addr: the initial address of the range to be written back * @size: the size of the range to be written back */ -void memory_region_do_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size); +void memory_region_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size); /** * memory_region_set_log: Turn dirty logging on or off for a region. diff --git a/memory.c b/memory.c index fd6f3d6aca..bb84334e1e 100644 --- a/memory.c +++ b/memory.c @@ -2198,7 +2198,7 @@ void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp } -void memory_region_do_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size) +void memory_region_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size) { /* * Might be extended case needed to cover diff --git a/target/arm/helper.c b/target/arm/helper.c index a92ae55672..972a766730 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6813,7 +6813,7 @@ static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque, mr = memory_region_from_host(haddr, &offset); if (mr) { - memory_region_do_writeback(mr, offset, dline_size); + memory_region_writeback(mr, offset, dline_size); } } } From 9ecc996a3d39bdbf64a488936f97a9496b74ebd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 8 May 2020 08:24:54 +0200 Subject: [PATCH 0838/2595] memory: Extract memory_region_msync() from memory_region_writeback() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Paolo Bonzini Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Reviewed-by: Richard Henderson Acked-by: Paolo Bonzini Message-id: 20200508062456.23344-3-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- include/exec/memory.h | 13 ++++++++++++- memory.c | 10 ++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 1b7cfdd5b6..3e00cdbbfa 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1473,8 +1473,19 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr); */ void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp); + /** - * memory_region_writeback: Trigger cache writeback or msync for + * memory_region_msync: Synchronize selected address range of + * a memory mapped region + * + * @mr: the memory region to be msync + * @addr: the initial address of the range to be sync + * @size: the size of the range to be sync + */ +void memory_region_msync(MemoryRegion *mr, hwaddr addr, hwaddr size); + +/** + * memory_region_writeback: Trigger cache writeback for * selected address range * * @mr: the memory region to be updated diff --git a/memory.c b/memory.c index bb84334e1e..93febe4759 100644 --- a/memory.c +++ b/memory.c @@ -2197,6 +2197,12 @@ void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp qemu_ram_resize(mr->ram_block, newsize, errp); } +void memory_region_msync(MemoryRegion *mr, hwaddr addr, hwaddr size) +{ + if (mr->ram_block) { + qemu_ram_writeback(mr->ram_block, addr, size); + } +} void memory_region_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size) { @@ -2204,8 +2210,8 @@ void memory_region_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size) * Might be extended case needed to cover * different types of memory regions */ - if (mr->ram_block && mr->dirty_log_mask) { - qemu_ram_writeback(mr->ram_block, addr, size); + if (mr->dirty_log_mask) { + memory_region_msync(mr, addr, size); } } From bc2a2364b8050632a3b3de07f30d88b7f0734845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 8 May 2020 08:24:55 +0200 Subject: [PATCH 0839/2595] hw/block: Let the NVMe emulated device be target-agnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now than the non-target specific memory_region_msync() function is available, use it to make this device target-agnostic. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Reviewed-by: Richard Henderson Acked-by: Paolo Bonzini Message-id: 20200508062456.23344-4-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/Makefile.objs | 2 +- hw/block/nvme.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs index 47960b5f0d..8855c22656 100644 --- a/hw/block/Makefile.objs +++ b/hw/block/Makefile.objs @@ -13,6 +13,6 @@ common-obj-$(CONFIG_SH4) += tc58128.o obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o -obj-$(CONFIG_NVME_PCI) += nvme.o +common-obj-$(CONFIG_NVME_PCI) += nvme.o obj-y += dataplane/ diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 2f3100e56c..a21eeca2fb 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -46,8 +46,7 @@ #include "qapi/visitor.h" #include "sysemu/hostmem.h" #include "sysemu/block-backend.h" -#include "exec/ram_addr.h" - +#include "exec/memory.h" #include "qemu/log.h" #include "qemu/module.h" #include "qemu/cutils.h" @@ -1207,8 +1206,7 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) */ if (addr == 0xE08 && (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) { - qemu_ram_writeback(n->pmrdev->mr.ram_block, - 0, n->pmrdev->size); + memory_region_msync(&n->pmrdev->mr, 0, n->pmrdev->size); } memcpy(&val, ptr + addr, size); } else { From ab7e41e6679224e5ad8da6d70ed7e645a5a482ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 8 May 2020 08:24:56 +0200 Subject: [PATCH 0840/2595] exec: Rename qemu_ram_writeback() as qemu_ram_msync() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename qemu_ram_writeback() as qemu_ram_msync() to better match what it does. Suggested-by: Stefan Hajnoczi Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Reviewed-by: Richard Henderson Acked-by: Paolo Bonzini Message-id: 20200508062456.23344-5-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- exec.c | 2 +- include/exec/ram_addr.h | 4 ++-- memory.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/exec.c b/exec.c index 5162f0d12f..3d4c94a9dc 100644 --- a/exec.c +++ b/exec.c @@ -2127,7 +2127,7 @@ int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp) * Otherwise no-op. * @Note: this is supposed to be a synchronous op. */ -void qemu_ram_writeback(RAMBlock *block, ram_addr_t start, ram_addr_t length) +void qemu_ram_msync(RAMBlock *block, ram_addr_t start, ram_addr_t length) { /* The requested range should fit in within the block range */ g_assert((start + length) <= block->used_length); diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 5e59a3d8d7..b295f6a784 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -136,12 +136,12 @@ void qemu_ram_free(RAMBlock *block); int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp); -void qemu_ram_writeback(RAMBlock *block, ram_addr_t start, ram_addr_t length); +void qemu_ram_msync(RAMBlock *block, ram_addr_t start, ram_addr_t length); /* Clear whole block of mem */ static inline void qemu_ram_block_writeback(RAMBlock *block) { - qemu_ram_writeback(block, 0, block->used_length); + qemu_ram_msync(block, 0, block->used_length); } #define DIRTY_CLIENTS_ALL ((1 << DIRTY_MEMORY_NUM) - 1) diff --git a/memory.c b/memory.c index 93febe4759..91ceaf9fcf 100644 --- a/memory.c +++ b/memory.c @@ -2200,7 +2200,7 @@ void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp void memory_region_msync(MemoryRegion *mr, hwaddr addr, hwaddr size) { if (mr->ram_block) { - qemu_ram_writeback(mr->ram_block, addr, size); + qemu_ram_msync(mr->ram_block, addr, size); } } From 7d2410cea154bf915fb30179ebda3b17ac36e70e Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 20 May 2020 17:49:01 +0300 Subject: [PATCH 0841/2595] block: Factor out bdrv_run_co() We have a few bdrv_*() functions that can either spawn a new coroutine and wait for it with BDRV_POLL_WHILE() or use a fastpath if they are alreeady running in a coroutine. All of them duplicate basically the same code. Factor the common code into a new function bdrv_run_co(). Signed-off-by: Kevin Wolf Signed-off-by: Vladimir Sementsov-Ogievskiy Message-id: 20200520144901.16589-1-vsementsov@virtuozzo.com [Factor out bdrv_run_co_entry too] Signed-off-by: Stefan Hajnoczi --- block/io.c | 193 ++++++++++++++++++++--------------------------------- 1 file changed, 72 insertions(+), 121 deletions(-) diff --git a/block/io.c b/block/io.c index 121ce17a49..df8f2a98d4 100644 --- a/block/io.c +++ b/block/io.c @@ -35,8 +35,6 @@ #include "qemu/main-loop.h" #include "sysemu/replay.h" -#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ - /* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */ #define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS) @@ -891,29 +889,63 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset, return 0; } +typedef int coroutine_fn BdrvRequestEntry(void *opaque); +typedef struct BdrvRunCo { + BdrvRequestEntry *entry; + void *opaque; + int ret; + bool done; + Coroutine *co; /* Coroutine, running bdrv_run_co_entry, for debugging */ +} BdrvRunCo; + +static void coroutine_fn bdrv_run_co_entry(void *opaque) +{ + BdrvRunCo *arg = opaque; + + arg->ret = arg->entry(arg->opaque); + arg->done = true; + aio_wait_kick(); +} + +static int bdrv_run_co(BlockDriverState *bs, BdrvRequestEntry *entry, + void *opaque) +{ + if (qemu_in_coroutine()) { + /* Fast-path if already in coroutine context */ + return entry(opaque); + } else { + BdrvRunCo s = { .entry = entry, .opaque = opaque }; + + s.co = qemu_coroutine_create(bdrv_run_co_entry, &s); + bdrv_coroutine_enter(bs, s.co); + + BDRV_POLL_WHILE(bs, !s.done); + + return s.ret; + } +} + typedef struct RwCo { BdrvChild *child; int64_t offset; QEMUIOVector *qiov; bool is_write; - int ret; BdrvRequestFlags flags; } RwCo; -static void coroutine_fn bdrv_rw_co_entry(void *opaque) +static int coroutine_fn bdrv_rw_co_entry(void *opaque) { RwCo *rwco = opaque; if (!rwco->is_write) { - rwco->ret = bdrv_co_preadv(rwco->child, rwco->offset, - rwco->qiov->size, rwco->qiov, - rwco->flags); + return bdrv_co_preadv(rwco->child, rwco->offset, + rwco->qiov->size, rwco->qiov, + rwco->flags); } else { - rwco->ret = bdrv_co_pwritev(rwco->child, rwco->offset, - rwco->qiov->size, rwco->qiov, - rwco->flags); + return bdrv_co_pwritev(rwco->child, rwco->offset, + rwco->qiov->size, rwco->qiov, + rwco->flags); } - aio_wait_kick(); } /* @@ -923,25 +955,15 @@ static int bdrv_prwv_co(BdrvChild *child, int64_t offset, QEMUIOVector *qiov, bool is_write, BdrvRequestFlags flags) { - Coroutine *co; RwCo rwco = { .child = child, .offset = offset, .qiov = qiov, .is_write = is_write, - .ret = NOT_DONE, .flags = flags, }; - if (qemu_in_coroutine()) { - /* Fast-path if already in coroutine context */ - bdrv_rw_co_entry(&rwco); - } else { - co = qemu_coroutine_create(bdrv_rw_co_entry, &rwco); - bdrv_coroutine_enter(child->bs, co); - BDRV_POLL_WHILE(child->bs, rwco.ret == NOT_DONE); - } - return rwco.ret; + return bdrv_run_co(child->bs, bdrv_rw_co_entry, &rwco); } int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, @@ -2229,8 +2251,6 @@ typedef struct BdrvCoBlockStatusData { int64_t *pnum; int64_t *map; BlockDriverState **file; - int ret; - bool done; } BdrvCoBlockStatusData; int coroutine_fn bdrv_co_block_status_from_file(BlockDriverState *bs, @@ -2484,16 +2504,14 @@ static int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs, } /* Coroutine wrapper for bdrv_block_status_above() */ -static void coroutine_fn bdrv_block_status_above_co_entry(void *opaque) +static int coroutine_fn bdrv_block_status_above_co_entry(void *opaque) { BdrvCoBlockStatusData *data = opaque; - data->ret = bdrv_co_block_status_above(data->bs, data->base, - data->want_zero, - data->offset, data->bytes, - data->pnum, data->map, data->file); - data->done = true; - aio_wait_kick(); + return bdrv_co_block_status_above(data->bs, data->base, + data->want_zero, + data->offset, data->bytes, + data->pnum, data->map, data->file); } /* @@ -2508,7 +2526,6 @@ static int bdrv_common_block_status_above(BlockDriverState *bs, int64_t *map, BlockDriverState **file) { - Coroutine *co; BdrvCoBlockStatusData data = { .bs = bs, .base = base, @@ -2518,18 +2535,9 @@ static int bdrv_common_block_status_above(BlockDriverState *bs, .pnum = pnum, .map = map, .file = file, - .done = false, }; - if (qemu_in_coroutine()) { - /* Fast-path if already in coroutine context */ - bdrv_block_status_above_co_entry(&data); - } else { - co = qemu_coroutine_create(bdrv_block_status_above_co_entry, &data); - bdrv_coroutine_enter(bs, co); - BDRV_POLL_WHILE(bs, !data.done); - } - return data.ret; + return bdrv_run_co(bs, bdrv_block_status_above_co_entry, &data); } int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, @@ -2630,7 +2638,6 @@ typedef struct BdrvVmstateCo { QEMUIOVector *qiov; int64_t pos; bool is_read; - int ret; } BdrvVmstateCo; static int coroutine_fn @@ -2658,33 +2665,25 @@ bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos, return ret; } -static void coroutine_fn bdrv_co_rw_vmstate_entry(void *opaque) +static int coroutine_fn bdrv_co_rw_vmstate_entry(void *opaque) { BdrvVmstateCo *co = opaque; - co->ret = bdrv_co_rw_vmstate(co->bs, co->qiov, co->pos, co->is_read); - aio_wait_kick(); + + return bdrv_co_rw_vmstate(co->bs, co->qiov, co->pos, co->is_read); } static inline int bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos, bool is_read) { - if (qemu_in_coroutine()) { - return bdrv_co_rw_vmstate(bs, qiov, pos, is_read); - } else { - BdrvVmstateCo data = { - .bs = bs, - .qiov = qiov, - .pos = pos, - .is_read = is_read, - .ret = -EINPROGRESS, - }; - Coroutine *co = qemu_coroutine_create(bdrv_co_rw_vmstate_entry, &data); + BdrvVmstateCo data = { + .bs = bs, + .qiov = qiov, + .pos = pos, + .is_read = is_read, + }; - bdrv_coroutine_enter(bs, co); - BDRV_POLL_WHILE(bs, data.ret == -EINPROGRESS); - return data.ret; - } + return bdrv_run_co(bs, bdrv_co_rw_vmstate_entry, &data); } int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf, @@ -2762,18 +2761,9 @@ void bdrv_aio_cancel_async(BlockAIOCB *acb) /**************************************************************/ /* Coroutine block device emulation */ -typedef struct FlushCo { - BlockDriverState *bs; - int ret; -} FlushCo; - - -static void coroutine_fn bdrv_flush_co_entry(void *opaque) +static int coroutine_fn bdrv_flush_co_entry(void *opaque) { - FlushCo *rwco = opaque; - - rwco->ret = bdrv_co_flush(rwco->bs); - aio_wait_kick(); + return bdrv_co_flush(opaque); } int coroutine_fn bdrv_co_flush(BlockDriverState *bs) @@ -2890,36 +2880,20 @@ early_exit: int bdrv_flush(BlockDriverState *bs) { - Coroutine *co; - FlushCo flush_co = { - .bs = bs, - .ret = NOT_DONE, - }; - - if (qemu_in_coroutine()) { - /* Fast-path if already in coroutine context */ - bdrv_flush_co_entry(&flush_co); - } else { - co = qemu_coroutine_create(bdrv_flush_co_entry, &flush_co); - bdrv_coroutine_enter(bs, co); - BDRV_POLL_WHILE(bs, flush_co.ret == NOT_DONE); - } - - return flush_co.ret; + return bdrv_run_co(bs, bdrv_flush_co_entry, bs); } typedef struct DiscardCo { BdrvChild *child; int64_t offset; int64_t bytes; - int ret; } DiscardCo; -static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque) + +static int coroutine_fn bdrv_pdiscard_co_entry(void *opaque) { DiscardCo *rwco = opaque; - rwco->ret = bdrv_co_pdiscard(rwco->child, rwco->offset, rwco->bytes); - aio_wait_kick(); + return bdrv_co_pdiscard(rwco->child, rwco->offset, rwco->bytes); } int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, @@ -3038,24 +3012,13 @@ out: int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes) { - Coroutine *co; DiscardCo rwco = { .child = child, .offset = offset, .bytes = bytes, - .ret = NOT_DONE, }; - if (qemu_in_coroutine()) { - /* Fast-path if already in coroutine context */ - bdrv_pdiscard_co_entry(&rwco); - } else { - co = qemu_coroutine_create(bdrv_pdiscard_co_entry, &rwco); - bdrv_coroutine_enter(child->bs, co); - BDRV_POLL_WHILE(child->bs, rwco.ret == NOT_DONE); - } - - return rwco.ret; + return bdrv_run_co(child->bs, bdrv_pdiscard_co_entry, &rwco); } int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf) @@ -3463,21 +3426,19 @@ typedef struct TruncateCo { PreallocMode prealloc; BdrvRequestFlags flags; Error **errp; - int ret; } TruncateCo; -static void coroutine_fn bdrv_truncate_co_entry(void *opaque) +static int coroutine_fn bdrv_truncate_co_entry(void *opaque) { TruncateCo *tco = opaque; - tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact, - tco->prealloc, tco->flags, tco->errp); - aio_wait_kick(); + + return bdrv_co_truncate(tco->child, tco->offset, tco->exact, + tco->prealloc, tco->flags, tco->errp); } int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) { - Coroutine *co; TruncateCo tco = { .child = child, .offset = offset, @@ -3485,17 +3446,7 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, .prealloc = prealloc, .flags = flags, .errp = errp, - .ret = NOT_DONE, }; - if (qemu_in_coroutine()) { - /* Fast-path if already in coroutine context */ - bdrv_truncate_co_entry(&tco); - } else { - co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco); - bdrv_coroutine_enter(child->bs, co); - BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE); - } - - return tco.ret; + return bdrv_run_co(child->bs, bdrv_truncate_co_entry, &tco); } From f555638c0ef9e9eb47677879fff7ca6f4b04df66 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 29 Apr 2020 03:42:01 -0400 Subject: [PATCH 0842/2595] s390x/kvm: help valgrind in several places MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need some little help in the code to reduce the valgrind noise. This patch does this with some designated initializers for the cpu model features and subfunctions. Signed-off-by: Christian Borntraeger Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: David Hildenbrand Message-Id: <20200429074201.100924-1-borntraeger@de.ibm.com> Signed-off-by: Cornelia Huck --- target/s390x/kvm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 69881a0da0..f2f75d2a57 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -2165,7 +2165,7 @@ int kvm_arch_msi_data_to_gsi(uint32_t data) static int query_cpu_subfunc(S390FeatBitmap features) { - struct kvm_s390_vm_cpu_subfunc prop; + struct kvm_s390_vm_cpu_subfunc prop = {}; struct kvm_device_attr attr = { .group = KVM_S390_VM_CPU_MODEL, .attr = KVM_S390_VM_CPU_MACHINE_SUBFUNC, @@ -2292,7 +2292,7 @@ static int kvm_to_feat[][2] = { static int query_cpu_feat(S390FeatBitmap features) { - struct kvm_s390_vm_cpu_feat prop; + struct kvm_s390_vm_cpu_feat prop = {}; struct kvm_device_attr attr = { .group = KVM_S390_VM_CPU_MODEL, .attr = KVM_S390_VM_CPU_MACHINE_FEAT, From 9a4325976264e2fac9a77cfabd774bd725c07027 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 5 May 2020 08:41:59 -0400 Subject: [PATCH 0843/2595] s390x: pv: Fix KVM_PV_PREP_RESET command wrapper name s390_pv_perf_clear_reset() is not a very helpful name since that function needs to be called for a normal and a clear reset via diag308. Let's instead name it s390_pv_prep_reset() which reflects the purpose of the function a bit better. Signed-off-by: Janosch Frank Reviewed-by: David Hildenbrand Message-Id: <20200505124159.24099-1-frankja@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/pv.c | 2 +- hw/s390x/s390-virtio-ccw.c | 2 +- include/hw/s390x/pv.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c index f11868e865..ab3a2482aa 100644 --- a/hw/s390x/pv.c +++ b/hw/s390x/pv.c @@ -88,7 +88,7 @@ int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) return s390_pv_cmd(KVM_PV_UNPACK, &args); } -void s390_pv_perf_clear_reset(void) +void s390_pv_prep_reset(void) { s390_pv_cmd_exit(KVM_PV_PREP_RESET, NULL); } diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 67ae2e02ff..60b16fef77 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -401,7 +401,7 @@ static void s390_pv_prepare_reset(S390CcwMachineState *ms) s390_cpu_set_state(S390_CPU_STATE_STOPPED, S390_CPU(cs)); } s390_pv_unshare(); - s390_pv_perf_clear_reset(); + s390_pv_prep_reset(); } static void s390_machine_reset(MachineState *machine) diff --git a/include/hw/s390x/pv.h b/include/hw/s390x/pv.h index 522ca6a04e..aee758bc2d 100644 --- a/include/hw/s390x/pv.h +++ b/include/hw/s390x/pv.h @@ -39,7 +39,7 @@ int s390_pv_vm_enable(void); void s390_pv_vm_disable(void); int s390_pv_set_sec_parms(uint64_t origin, uint64_t length); int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak); -void s390_pv_perf_clear_reset(void); +void s390_pv_prep_reset(void); int s390_pv_verify(void); void s390_pv_unshare(void); void s390_pv_inject_reset_error(CPUState *cs); @@ -49,7 +49,7 @@ static inline int s390_pv_vm_enable(void) { return 0; } static inline void s390_pv_vm_disable(void) {} static inline int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) { return 0; } static inline int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) { return 0; } -static inline void s390_pv_perf_clear_reset(void) {} +static inline void s390_pv_prep_reset(void) {} static inline int s390_pv_verify(void) { return 0; } static inline void s390_pv_unshare(void) {} static inline void s390_pv_inject_reset_error(CPUState *cs) {}; From f31270d4ebc8251ff03e808d0eb6cd6e3bbc1b99 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 4 May 2020 16:26:19 +0200 Subject: [PATCH 0844/2595] docs/s390x: document the virtual css Add some hints about "devno" rules. Message-Id: <20200515151518.83950-2-cohuck@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- docs/system/s390x/css.rst | 86 ++++++++++++++++++++++++++++++++++++ docs/system/target-s390x.rst | 1 + 2 files changed, 87 insertions(+) create mode 100644 docs/system/s390x/css.rst diff --git a/docs/system/s390x/css.rst b/docs/system/s390x/css.rst new file mode 100644 index 0000000000..3b40161184 --- /dev/null +++ b/docs/system/s390x/css.rst @@ -0,0 +1,86 @@ +The virtual channel subsystem +============================= + +QEMU implements a virtual channel subsystem with subchannels, (mostly +functionless) channel paths, and channel devices (virtio-ccw, 3270, and +devices passed via vfio-ccw). It supports multiple subchannel sets (MSS) and +multiple channel subsystems extended (MCSS-E). + +All channel devices support the ``devno`` property, which takes a parameter +in the form ``..``. + +The default channel subsystem image id (````) is ``0xfe``. Devices in +there will show up in channel subsystem image ``0`` to guests that do not +enable MCSS-E. Note that devices with a different cssid will not be visible +if the guest OS does not enable MCSS-E (which is true for all supported guest +operating systems today). + +Supported values for the subchannel set id (````) range from ``0-3``. +Devices with a ssid that is not ``0`` will not be visible if the guest OS +does not enable MSS (any Linux version that supports virtio also enables MSS). +Any device may be put into any subchannel set, there is no restriction by +device type. + +The device number can range from ``0-0xffff``. + +If the ``devno`` property is not specified for a device, QEMU will choose the +next free device number in subchannel set 0, skipping to the next subchannel +set if no more device numbers are free. + +QEMU places a device at the first free subchannel in the specified subchannel +set. If a device is hotunplugged and later replugged, it may appear at a +different subchannel. (This is similar to how z/VM works.) + + +Examples +-------- + +* a virtio-net device, cssid/ssid/devno automatically assigned:: + + -device virtio-net-ccw + + In a Linux guest (without default devices and no other devices specified + prior to this one), this will show up as ``0.0.0000`` under subchannel + ``0.0.0000``. + + The auto-assigned-properties in QEMU (as seen via e.g. ``info qtree``) + would be ``dev_id = "fe.0.0000"`` and ``subch_id = "fe.0.0000"``. + +* a virtio-rng device in subchannel set ``0``:: + + -device virtio-rng-ccw,devno=fe.0.0042 + + If added to the same Linux guest as above, it would show up as ``0.0.0042`` + under subchannel ``0.0.0001``. + + The properties for the device would be ``dev_id = "fe.0.0042"`` and + ``subch_id = "fe.0.0001"``. + +* a virtio-gpu device in subchannel set ``2``:: + + -device virtio-gpu-ccw,devno=fe.2.1111 + + If added to the same Linux guest as above, it would show up as ``0.2.1111`` + under subchannel ``0.2.0000``. + + The properties for the device would be ``dev_id = "fe.2.1111"`` and + ``subch_id = "fe.2.0000"``. + +* a virtio-mouse device in a non-standard channel subsystem image:: + + -device virtio-mouse-ccw,devno=2.0.2222 + + This would not show up in a standard Linux guest. + + The properties for the device would be ``dev_id = "2.0.2222"`` and + ``subch_id = "2.0.0000"``. + +* a virtio-keyboard device in another non-standard channel subsystem image:: + + -device virtio-keyboard-ccw,devno=0.0.1234 + + This would not show up in a standard Linux guest, either, as ``0`` is not + the standard channel subsystem image id. + + The properties for the device would be ``dev_id = "0.0.1234"`` and + ``subch_id = "0.0.0000"``. diff --git a/docs/system/target-s390x.rst b/docs/system/target-s390x.rst index 7d76ae97b4..37ca032d98 100644 --- a/docs/system/target-s390x.rst +++ b/docs/system/target-s390x.rst @@ -23,6 +23,7 @@ or vfio-ap is also available. .. toctree:: s390x/vfio-ap + s390x/css Architectural features ====================== From 61a3d5eded4af9e4cc8d779672891eba8d94879c Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 30 Apr 2020 13:35:43 +0200 Subject: [PATCH 0845/2595] docs/s390x: document 3270 Add some basic info how to use 3270 devices. Message-Id: <20200515151518.83950-3-cohuck@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- docs/system/s390x/3270.rst | 32 ++++++++++++++++++++++++++++++++ docs/system/target-s390x.rst | 1 + 2 files changed, 33 insertions(+) create mode 100644 docs/system/s390x/3270.rst diff --git a/docs/system/s390x/3270.rst b/docs/system/s390x/3270.rst new file mode 100644 index 0000000000..1774cdcadf --- /dev/null +++ b/docs/system/s390x/3270.rst @@ -0,0 +1,32 @@ +3270 devices +============ + +QEMU supports connecting an external 3270 terminal emulator (such as +``x3270``) to make a single 3270 device available to a guest. Note that this +supports basic features only. + +To provide a 3270 device to a guest, create a ``x-terminal3270`` linked to +a ``tn3270`` chardev. The guest will see a 3270 channel device. In order +to actually be able to use it, attach the ``x3270`` emulator to the chardev. + +Example configuration +--------------------- + +* Add a ``tn3270`` chardev and a ``x-terminal3270`` to the QEMU command line:: + + -chardev socket,id=char_0,host=0.0.0.0,port=2300,nowait,server,tn3270 + -device x-terminal3270,chardev=char_0,devno=fe.0.000a,id=terminal_0 + +* Start the guest. In the guest, use ``chccwdev -e 0.0.000a`` to enable + the device. + +* On the host, start the ``x3270`` emulator:: + + x3270 :2300 + +* In the guest, locate the 3270 device node under ``/dev/3270/`` (say, + ``tty1``) and start a getty on it:: + + systemctl start serial-getty@3270-tty1.service + +This should get you an addtional tty for logging into the guest. diff --git a/docs/system/target-s390x.rst b/docs/system/target-s390x.rst index 37ca032d98..2592a05303 100644 --- a/docs/system/target-s390x.rst +++ b/docs/system/target-s390x.rst @@ -24,6 +24,7 @@ or vfio-ap is also available. .. toctree:: s390x/vfio-ap s390x/css + s390x/3270 Architectural features ====================== From 24e58a7b1d411627e326144030a20dcf0093fed0 Mon Sep 17 00:00:00 2001 From: Jared Rossi Date: Tue, 12 May 2020 14:15:35 -0400 Subject: [PATCH 0846/2595] vfio-ccw: allow non-prefetch ORBs Remove the explicit prefetch check when using vfio-ccw devices. This check does not trigger in practice as all Linux channel programs are intended to use prefetch. Newer Linux kernel versions do not require to force the PFCH flag with vfio-ccw devices anymore. Signed-off-by: Jared Rossi Reviewed-by: Eric Farman Message-Id: <20200512181535.18630-2-jrossi@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/vfio/ccw.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index c8624943c1..63406184d2 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -74,16 +74,9 @@ static IOInstEnding vfio_ccw_handle_request(SubchDev *sch) struct ccw_io_region *region = vcdev->io_region; int ret; - if (!(sch->orb.ctrl0 & ORB_CTRL0_MASK_PFCH)) { - if (!(vcdev->force_orb_pfch)) { - warn_once_pfch(vcdev, sch, "requires PFCH flag set"); - sch_gen_unit_exception(sch); - css_inject_io_interrupt(sch); - return IOINST_CC_EXPECTED; - } else { - sch->orb.ctrl0 |= ORB_CTRL0_MASK_PFCH; - warn_once_pfch(vcdev, sch, "PFCH flag forced"); - } + if (!(sch->orb.ctrl0 & ORB_CTRL0_MASK_PFCH) && vcdev->force_orb_pfch) { + sch->orb.ctrl0 |= ORB_CTRL0_MASK_PFCH; + warn_once_pfch(vcdev, sch, "PFCH flag forced"); } QEMU_BUILD_BUG_ON(sizeof(region->orb_area) != sizeof(ORB)); From 8e75b8351143ca40eb66ef775291003558ea4ce0 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 30 Apr 2020 14:23:48 +0200 Subject: [PATCH 0847/2595] docs/s390x: document vfio-ccw Add a basic example for passing a dasd via vfio-ccw. Message-Id: <20200518075522.97643-1-cohuck@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- docs/system/s390x/vfio-ccw.rst | 77 ++++++++++++++++++++++++++++++++++ docs/system/target-s390x.rst | 1 + 2 files changed, 78 insertions(+) create mode 100644 docs/system/s390x/vfio-ccw.rst diff --git a/docs/system/s390x/vfio-ccw.rst b/docs/system/s390x/vfio-ccw.rst new file mode 100644 index 0000000000..8f65442c0f --- /dev/null +++ b/docs/system/s390x/vfio-ccw.rst @@ -0,0 +1,77 @@ +Subchannel passthrough via vfio-ccw +=================================== + +vfio-ccw (based upon the mediated vfio device infrastructure) allows to +make certain I/O subchannels and their devices available to a guest. The +host will not interact with those subchannels/devices any more. + +Note that while vfio-ccw should work with most non-QDIO devices, only ECKD +DASDs have really been tested. + +Example configuration +--------------------- + +Step 1: configure the host device +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As every mdev is identified by a uuid, the first step is to obtain one:: + + [root@host ~]# uuidgen + 7e270a25-e163-4922-af60-757fc8ed48c6 + +Note: it is recommended to use the ``mdevctl`` tool for actually configuring +the host device. + +To define the same device as configured below to be started +automatically, use + +:: + + [root@host ~]# driverctl -b css set-override 0.0.0313 vfio_ccw + [root@host ~]# mdevctl define -u 7e270a25-e163-4922-af60-757fc8ed48c6 \ + -p 0.0.0313 -t vfio-ccw_io -a + +If using ``mdevctl`` is not possible or wanted, follow the manual procedure +below. + +* Locate the subchannel for the device (in this example, ``0.0.2b09``):: + + [root@host ~]# lscss | grep 0.0.2b09 | awk '{print $2}' + 0.0.0313 + +* Unbind the subchannel (in this example, ``0.0.0313``) from the standard + I/O subchannel driver and bind it to the vfio-ccw driver:: + + [root@host ~]# echo 0.0.0313 > /sys/bus/css/devices/0.0.0313/driver/unbind + [root@host ~]# echo 0.0.0313 > /sys/bus/css/drivers/vfio_ccw/bind + +* Create the mediated device (identified by the uuid):: + + [root@host ~]# echo "7e270a25-e163-4922-af60-757fc8ed48c6" > \ + /sys/bus/css/devices/0.0.0313/mdev_supported_types/vfio_ccw-io/create + +Step 2: configure QEMU +~~~~~~~~~~~~~~~~~~~~~~ + +* Reference the created mediated device and (optionally) pick a device id to + be presented in the guest (here, ``fe.0.1234``, which will end up visible + in the guest as ``0.0.1234``:: + + -device vfio-ccw,devno=fe.0.1234,sysfsdev=\ + /sys/bus/mdev/devices/7e270a25-e163-4922-af60-757fc8ed48c6 + +* Start the guest. The device (here, ``0.0.1234``) should now be usable:: + + [root@guest ~]# lscss -d 0.0.1234 + Device Subchan. DevType CU Type Use PIM PAM POM CHPID + ---------------------------------------------------------------------- + 0.0.1234 0.0.0007 3390/0e 3990/e9 f0 f0 ff 1a2a3a0a 00000000 + [root@guest ~]# chccwdev -e 0.0.1234 + Setting device 0.0.1234 online + Done + [root@guest ~]# dmesg -t + (...) + dasd-eckd 0.0.1234: A channel path to the device has become operational + dasd-eckd 0.0.1234: New DASD 3390/0E (CU 3990/01) with 10017 cylinders, 15 heads, 224 sectors + dasd-eckd 0.0.1234: DASD with 4 KB/block, 7212240 KB total size, 48 KB/track, compatible disk layout + dasda:VOL1/ 0X2B09: dasda1 diff --git a/docs/system/target-s390x.rst b/docs/system/target-s390x.rst index 2592a05303..644e404ef9 100644 --- a/docs/system/target-s390x.rst +++ b/docs/system/target-s390x.rst @@ -25,6 +25,7 @@ or vfio-ap is also available. s390x/vfio-ap s390x/css s390x/3270 + s390x/vfio-ccw Architectural features ====================== From cdb509a40b8f0d83a37d887572a790a7773745c7 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 25 May 2020 17:58:55 +0200 Subject: [PATCH 0848/2595] MAINTAINERS: add Thomas as additional s390x maintainer ...because two people are better than one. Signed-off-by: Cornelia Huck Acked-by: Thomas Huth Cc: Thomas Huth Message-Id: <20200525155855.225564-1-cohuck@redhat.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3e7d9cb0a5..6e7890ce82 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -85,6 +85,7 @@ Architecture support -------------------- S390 general architecture support M: Cornelia Huck +M: Thomas Huth S: Supported F: default-configs/s390x-softmmu.mak F: gdb-xml/s390*.xml From d64c1bd6ca0323e9e5e848c6a8193dc12ab1273e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 19:24:25 +0200 Subject: [PATCH 0849/2595] target/s390x: Only compile decode_basedisp() on system-mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The decode_basedisp*() methods are only used in ioinst.c, which is only build in system-mode emulation. I/O instructions are privileged, and other S instructions are decoded elsewhere. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cornelia Huck Message-Id: <20200526172427.17460-6-f4bug@amsat.org> Signed-off-by: Cornelia Huck --- target/s390x/internal.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/s390x/internal.h b/target/s390x/internal.h index 8c95c734db..c1678dc6bc 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -204,6 +204,8 @@ enum cc_op { CC_OP_MAX }; +#ifndef CONFIG_USER_ONLY + static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb, uint8_t *ar) { @@ -225,6 +227,8 @@ static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb, /* Base/displacement are at the same locations. */ #define decode_basedisp_rs decode_basedisp_s +#endif /* CONFIG_USER_ONLY */ + /* arch_dump.c */ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, int cpuid, void *opaque); From 8c4b4e37636219bc913205314fa44d27df687d9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 19:24:26 +0200 Subject: [PATCH 0850/2595] target/s390x/helper: Clean ifdef'ry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All this code is guarded checking CONFIG_USER_ONLY definition. Drop the duplicated checks. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: David Hildenbrand Reviewed-by: Cornelia Huck Message-Id: <20200526172427.17460-7-f4bug@amsat.org> Signed-off-by: Cornelia Huck --- target/s390x/helper.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 09f60406aa..9257d388ba 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -42,9 +42,6 @@ void s390x_cpu_timer(void *opaque) { cpu_inject_cpu_timer((S390CPU *) opaque); } -#endif - -#ifndef CONFIG_USER_ONLY hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr) { @@ -98,14 +95,12 @@ void s390_handle_wait(S390CPU *cpu) CPUState *cs = CPU(cpu); if (s390_cpu_halt(cpu) == 0) { -#ifndef CONFIG_USER_ONLY if (is_special_wait_psw(cpu->env.psw.addr)) { qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); } else { cpu->env.crash_reason = S390_CRASH_REASON_DISABLED_WAIT; qemu_system_guest_panicked(cpu_get_crash_info(cs)); } -#endif } } From c44d26a2347177f9bcd558a7c429396b373bb68e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 19:24:27 +0200 Subject: [PATCH 0851/2595] target/s390x: Restrict system-mode declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As these declarations are restricted to !CONFIG_USER_ONLY in helper.c, only declare them when system-mode emulation is used. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cornelia Huck Message-Id: <20200526172427.17460-8-f4bug@amsat.org> Signed-off-by: Cornelia Huck --- target/s390x/internal.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target/s390x/internal.h b/target/s390x/internal.h index c1678dc6bc..b1e0ebf67f 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -236,9 +236,11 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, /* cc_helper.c */ const char *cc_name(enum cc_op cc_op); -void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr); +#ifndef CONFIG_USER_ONLY +void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); +#endif /* CONFIG_USER_ONLY */ /* cpu.c */ @@ -303,18 +305,18 @@ void s390_cpu_gdb_init(CPUState *cs); /* helper.c */ void s390_cpu_dump_state(CPUState *cpu, FILE *f, int flags); -hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr); +void do_restart_interrupt(CPUS390XState *env); +#ifndef CONFIG_USER_ONLY uint64_t get_psw_mask(CPUS390XState *env); void s390_cpu_recompute_watchpoints(CPUState *cs); void s390x_tod_timer(void *opaque); void s390x_cpu_timer(void *opaque); -void do_restart_interrupt(CPUS390XState *env); void s390_handle_wait(S390CPU *cpu); +hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr); #define S390_STORE_STATUS_DEF_ADDR offsetof(LowCore, floating_pt_save_area) int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch); int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len); -#ifndef CONFIG_USER_ONLY LowCore *cpu_map_lowcore(CPUS390XState *env); void cpu_unmap_lowcore(LowCore *lowcore); #endif /* CONFIG_USER_ONLY */ From 9c49c83e4b23d31676633a1189faa6e70b489c01 Mon Sep 17 00:00:00 2001 From: Eden Mikitas Date: Tue, 2 Jun 2020 13:44:34 +0100 Subject: [PATCH 0852/2595] hw/ssi/imx_spi: changed while statement to prevent underflow The while statement in question only checked if tx_burst is not 0. tx_burst is a signed int, which is assigned the value put by the guest driver in ECSPI_CONREG. The burst length can be anywhere between 1 and 4096, and since tx_burst is always decremented by 8 it could possibly underflow, causing an infinite loop. Signed-off-by: Eden Mikitas Reviewed-by: Alistair Francis Signed-off-by: Peter Maydell --- hw/ssi/imx_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c index 2dd9a631e1..6fef5c7958 100644 --- a/hw/ssi/imx_spi.c +++ b/hw/ssi/imx_spi.c @@ -182,7 +182,7 @@ static void imx_spi_flush_txfifo(IMXSPIState *s) rx = 0; - while (tx_burst) { + while (tx_burst > 0) { uint8_t byte = tx & 0xff; DPRINTF("writing 0x%02x\n", (uint32_t)byte); From 6d686145c86c9712db1547f66bebb7131979c61b Mon Sep 17 00:00:00 2001 From: Eden Mikitas Date: Tue, 2 Jun 2020 13:44:34 +0100 Subject: [PATCH 0853/2595] hw/ssi/imx_spi: Removed unnecessary cast of rx data received from slave When inserting the value retrieved (rx) from the spi slave, rx is pushed to rx_fifo after being cast to uint8_t. rx_fifo is a fifo32, and the rx register the driver uses is also 32 bit. This zeroes the 24 most significant bits of rx. This proved problematic with devices that expect to use the whole 32 bits of the rx register. Signed-off-by: Eden Mikitas Reviewed-by: Alistair Francis Signed-off-by: Peter Maydell --- hw/ssi/imx_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c index 6fef5c7958..43b2f14dd2 100644 --- a/hw/ssi/imx_spi.c +++ b/hw/ssi/imx_spi.c @@ -206,7 +206,7 @@ static void imx_spi_flush_txfifo(IMXSPIState *s) if (fifo32_is_full(&s->rx_fifo)) { s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RO; } else { - fifo32_push(&s->rx_fifo, (uint8_t)rx); + fifo32_push(&s->rx_fifo, rx); } if (s->burst_length <= 0) { From 3a37f23979ac8179dd297b45cd23020a610002ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 2 Jun 2020 13:44:34 +0100 Subject: [PATCH 0854/2595] hw/input/pxa2xx_keypad: Replace hw_error() by qemu_log_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw_error() calls exit(). This a bit overkill when we can log the accesses as unimplemented or guest error. When fuzzing the devices, we don't want the whole process to exit. Replace some hw_error() calls by qemu_log_mask() (missed in commit 5a0001ec7e). Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200525114123.21317-2-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/input/pxa2xx_keypad.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/input/pxa2xx_keypad.c b/hw/input/pxa2xx_keypad.c index 31862a7d16..62aa6f6b15 100644 --- a/hw/input/pxa2xx_keypad.c +++ b/hw/input/pxa2xx_keypad.c @@ -12,7 +12,7 @@ */ #include "qemu/osdep.h" -#include "hw/hw.h" +#include "qemu/log.h" #include "hw/irq.h" #include "migration/vmstate.h" #include "hw/arm/pxa.h" @@ -233,7 +233,9 @@ static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset, return s->kpkdi; break; default: - hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, offset); } return 0; @@ -280,7 +282,9 @@ static void pxa2xx_keypad_write(void *opaque, hwaddr offset, break; default: - hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, offset); } } From fc417e5b5784eec92163ad36140ab029c6661b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 2 Jun 2020 13:44:35 +0100 Subject: [PATCH 0855/2595] hw/arm/pxa2xx: Replace printf() call by qemu_log_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace printf() calls by qemu_log_mask(), which is disabled by default. This avoid flooding the terminal when fuzzing the device. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200525114123.21317-3-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/pxa2xx.c | 66 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 336c9bad4a..e649f8930c 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -26,6 +26,7 @@ #include "sysemu/blockdev.h" #include "sysemu/qtest.h" #include "qemu/cutils.h" +#include "qemu/log.h" static struct { hwaddr io_base; @@ -112,7 +113,9 @@ static uint64_t pxa2xx_pm_read(void *opaque, hwaddr addr, return s->pm_regs[addr >> 2]; default: fail: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } return 0; @@ -143,8 +146,9 @@ static void pxa2xx_pm_write(void *opaque, hwaddr addr, s->pm_regs[addr >> 2] = value; break; } - - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } } @@ -185,7 +189,9 @@ static uint64_t pxa2xx_cm_read(void *opaque, hwaddr addr, return s->cm_regs[CCCR >> 2] | (3 << 28); default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } return 0; @@ -210,7 +216,9 @@ static void pxa2xx_cm_write(void *opaque, hwaddr addr, break; default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } } @@ -415,7 +423,9 @@ static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr, return s->mm_regs[addr >> 2]; /* fall through */ default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } return 0; @@ -434,7 +444,9 @@ static void pxa2xx_mm_write(void *opaque, hwaddr addr, } default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } } @@ -641,7 +653,9 @@ static uint64_t pxa2xx_ssp_read(void *opaque, hwaddr addr, case SSACD: return s->ssacd; default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } return 0; @@ -733,7 +747,9 @@ static void pxa2xx_ssp_write(void *opaque, hwaddr addr, break; default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } } @@ -995,7 +1011,9 @@ static uint64_t pxa2xx_rtc_read(void *opaque, hwaddr addr, else return s->last_swcr; default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } return 0; @@ -1101,7 +1119,9 @@ static void pxa2xx_rtc_write(void *opaque, hwaddr addr, break; default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, addr); } } @@ -1354,7 +1374,9 @@ static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr, s->ibmr = 0; return s->ibmr; default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } return 0; @@ -1427,7 +1449,9 @@ static void pxa2xx_i2c_write(void *opaque, hwaddr addr, break; default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, addr); } } @@ -1628,7 +1652,9 @@ static uint64_t pxa2xx_i2s_read(void *opaque, hwaddr addr, } return 0; default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } return 0; @@ -1685,7 +1711,9 @@ static void pxa2xx_i2s_write(void *opaque, hwaddr addr, } break; default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, addr); } } @@ -1870,7 +1898,9 @@ static uint64_t pxa2xx_fir_read(void *opaque, hwaddr addr, case ICFOR: return s->rx_len; default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, addr); break; } return 0; @@ -1922,7 +1952,9 @@ static void pxa2xx_fir_write(void *opaque, hwaddr addr, case ICFOR: break; default: - printf("%s: Bad register " REG_FMT "\n", __func__, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, addr); } } From a04b68e1d4c4f0cd5cd7542697b1b230b84532f5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 May 2020 14:28:26 -0700 Subject: [PATCH 0856/2595] target/arm: Convert aes and sm4 to gvec helpers With this conversion, we will be able to use the same helpers with sve. In particular, pass 3 vector parameters for the 3-operand operations; for advsimd the destination register is also an input. This also fixes a bug in which we failed to clear the high bits of the SVE register after an AdvSIMD operation. Signed-off-by: Richard Henderson Message-id: 20200514212831.31248-2-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/crypto_helper.c | 72 +++++++++++++++++++++++++++----------- target/arm/helper.h | 6 ++-- target/arm/translate-a64.c | 55 ++++++++++++++++++----------- target/arm/translate.c | 27 +++++++------- target/arm/vec_helper.c | 12 +------ target/arm/vec_internal.h | 33 +++++++++++++++++ 6 files changed, 138 insertions(+), 67 deletions(-) create mode 100644 target/arm/vec_internal.h diff --git a/target/arm/crypto_helper.c b/target/arm/crypto_helper.c index f800266727..6bd5a3d2d0 100644 --- a/target/arm/crypto_helper.c +++ b/target/arm/crypto_helper.c @@ -13,7 +13,9 @@ #include "cpu.h" #include "exec/helper-proto.h" +#include "tcg/tcg-gvec-desc.h" #include "crypto/aes.h" +#include "vec_internal.h" union CRYPTO_STATE { uint8_t bytes[16]; @@ -29,18 +31,15 @@ union CRYPTO_STATE { #define CR_ST_WORD(state, i) (state.words[i]) #endif -void HELPER(crypto_aese)(void *vd, void *vm, uint32_t decrypt) +static void do_crypto_aese(uint64_t *rd, uint64_t *rn, + uint64_t *rm, bool decrypt) { static uint8_t const * const sbox[2] = { AES_sbox, AES_isbox }; static uint8_t const * const shift[2] = { AES_shifts, AES_ishifts }; - uint64_t *rd = vd; - uint64_t *rm = vm; union CRYPTO_STATE rk = { .l = { rm[0], rm[1] } }; - union CRYPTO_STATE st = { .l = { rd[0], rd[1] } }; + union CRYPTO_STATE st = { .l = { rn[0], rn[1] } }; int i; - assert(decrypt < 2); - /* xor state vector with round key */ rk.l[0] ^= st.l[0]; rk.l[1] ^= st.l[1]; @@ -54,7 +53,18 @@ void HELPER(crypto_aese)(void *vd, void *vm, uint32_t decrypt) rd[1] = st.l[1]; } -void HELPER(crypto_aesmc)(void *vd, void *vm, uint32_t decrypt) +void HELPER(crypto_aese)(void *vd, void *vn, void *vm, uint32_t desc) +{ + intptr_t i, opr_sz = simd_oprsz(desc); + bool decrypt = simd_data(desc); + + for (i = 0; i < opr_sz; i += 16) { + do_crypto_aese(vd + i, vn + i, vm + i, decrypt); + } + clear_tail(vd, opr_sz, simd_maxsz(desc)); +} + +static void do_crypto_aesmc(uint64_t *rd, uint64_t *rm, bool decrypt) { static uint32_t const mc[][256] = { { /* MixColumns lookup table */ @@ -190,13 +200,9 @@ void HELPER(crypto_aesmc)(void *vd, void *vm, uint32_t decrypt) 0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d, } }; - uint64_t *rd = vd; - uint64_t *rm = vm; union CRYPTO_STATE st = { .l = { rm[0], rm[1] } }; int i; - assert(decrypt < 2); - for (i = 0; i < 16; i += 4) { CR_ST_WORD(st, i >> 2) = mc[decrypt][CR_ST_BYTE(st, i)] ^ @@ -209,6 +215,17 @@ void HELPER(crypto_aesmc)(void *vd, void *vm, uint32_t decrypt) rd[1] = st.l[1]; } +void HELPER(crypto_aesmc)(void *vd, void *vm, uint32_t desc) +{ + intptr_t i, opr_sz = simd_oprsz(desc); + bool decrypt = simd_data(desc); + + for (i = 0; i < opr_sz; i += 16) { + do_crypto_aesmc(vd + i, vm + i, decrypt); + } + clear_tail(vd, opr_sz, simd_maxsz(desc)); +} + /* * SHA-1 logical functions */ @@ -638,12 +655,10 @@ static uint8_t const sm4_sbox[] = { 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48, }; -void HELPER(crypto_sm4e)(void *vd, void *vn) +static void do_crypto_sm4e(uint64_t *rd, uint64_t *rn, uint64_t *rm) { - uint64_t *rd = vd; - uint64_t *rn = vn; - union CRYPTO_STATE d = { .l = { rd[0], rd[1] } }; - union CRYPTO_STATE n = { .l = { rn[0], rn[1] } }; + union CRYPTO_STATE d = { .l = { rn[0], rn[1] } }; + union CRYPTO_STATE n = { .l = { rm[0], rm[1] } }; uint32_t t, i; for (i = 0; i < 4; i++) { @@ -665,11 +680,18 @@ void HELPER(crypto_sm4e)(void *vd, void *vn) rd[1] = d.l[1]; } -void HELPER(crypto_sm4ekey)(void *vd, void *vn, void* vm) +void HELPER(crypto_sm4e)(void *vd, void *vn, void *vm, uint32_t desc) +{ + intptr_t i, opr_sz = simd_oprsz(desc); + + for (i = 0; i < opr_sz; i += 16) { + do_crypto_sm4e(vd + i, vn + i, vm + i); + } + clear_tail(vd, opr_sz, simd_maxsz(desc)); +} + +static void do_crypto_sm4ekey(uint64_t *rd, uint64_t *rn, uint64_t *rm) { - uint64_t *rd = vd; - uint64_t *rn = vn; - uint64_t *rm = vm; union CRYPTO_STATE d; union CRYPTO_STATE n = { .l = { rn[0], rn[1] } }; union CRYPTO_STATE m = { .l = { rm[0], rm[1] } }; @@ -693,3 +715,13 @@ void HELPER(crypto_sm4ekey)(void *vd, void *vn, void* vm) rd[0] = d.l[0]; rd[1] = d.l[1]; } + +void HELPER(crypto_sm4ekey)(void *vd, void *vn, void* vm, uint32_t desc) +{ + intptr_t i, opr_sz = simd_oprsz(desc); + + for (i = 0; i < opr_sz; i += 16) { + do_crypto_sm4ekey(vd + i, vn + i, vm + i); + } + clear_tail(vd, opr_sz, simd_maxsz(desc)); +} diff --git a/target/arm/helper.h b/target/arm/helper.h index 49336dc432..42759f82aa 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -510,7 +510,7 @@ DEF_HELPER_FLAGS_2(neon_qzip8, TCG_CALL_NO_RWG, void, ptr, ptr) DEF_HELPER_FLAGS_2(neon_qzip16, TCG_CALL_NO_RWG, void, ptr, ptr) DEF_HELPER_FLAGS_2(neon_qzip32, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_3(crypto_aese, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_aese, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_3(crypto_aesmc, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_4(crypto_sha1_3reg, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) @@ -531,8 +531,8 @@ DEF_HELPER_FLAGS_5(crypto_sm3tt, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32, i32) DEF_HELPER_FLAGS_3(crypto_sm3partw1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) DEF_HELPER_FLAGS_3(crypto_sm3partw2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) -DEF_HELPER_FLAGS_2(crypto_sm4e, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_3(crypto_sm4ekey, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) +DEF_HELPER_FLAGS_4(crypto_sm4e, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sm4ekey, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 874f3eb4f9..b3f4223006 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -571,6 +571,15 @@ static void gen_gvec_fn4(DisasContext *s, bool is_q, int rd, int rn, int rm, is_q ? 16 : 8, vec_full_reg_size(s)); } +/* Expand a 2-operand operation using an out-of-line helper. */ +static void gen_gvec_op2_ool(DisasContext *s, bool is_q, int rd, + int rn, int data, gen_helper_gvec_2 *fn) +{ + tcg_gen_gvec_2_ool(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + is_q ? 16 : 8, vec_full_reg_size(s), data, fn); +} + /* Expand a 3-operand operation using an out-of-line helper. */ static void gen_gvec_op3_ool(DisasContext *s, bool is_q, int rd, int rn, int rm, int data, gen_helper_gvec_3 *fn) @@ -13403,9 +13412,8 @@ static void disas_crypto_aes(DisasContext *s, uint32_t insn) int rn = extract32(insn, 5, 5); int rd = extract32(insn, 0, 5); int decrypt; - TCGv_ptr tcg_rd_ptr, tcg_rn_ptr; - TCGv_i32 tcg_decrypt; - CryptoThreeOpIntFn *genfn; + gen_helper_gvec_2 *genfn2 = NULL; + gen_helper_gvec_3 *genfn3 = NULL; if (!dc_isar_feature(aa64_aes, s) || size != 0) { unallocated_encoding(s); @@ -13415,19 +13423,19 @@ static void disas_crypto_aes(DisasContext *s, uint32_t insn) switch (opcode) { case 0x4: /* AESE */ decrypt = 0; - genfn = gen_helper_crypto_aese; + genfn3 = gen_helper_crypto_aese; break; case 0x6: /* AESMC */ decrypt = 0; - genfn = gen_helper_crypto_aesmc; + genfn2 = gen_helper_crypto_aesmc; break; case 0x5: /* AESD */ decrypt = 1; - genfn = gen_helper_crypto_aese; + genfn3 = gen_helper_crypto_aese; break; case 0x7: /* AESIMC */ decrypt = 1; - genfn = gen_helper_crypto_aesmc; + genfn2 = gen_helper_crypto_aesmc; break; default: unallocated_encoding(s); @@ -13437,16 +13445,11 @@ static void disas_crypto_aes(DisasContext *s, uint32_t insn) if (!fp_access_check(s)) { return; } - - tcg_rd_ptr = vec_full_reg_ptr(s, rd); - tcg_rn_ptr = vec_full_reg_ptr(s, rn); - tcg_decrypt = tcg_const_i32(decrypt); - - genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_decrypt); - - tcg_temp_free_ptr(tcg_rd_ptr); - tcg_temp_free_ptr(tcg_rn_ptr); - tcg_temp_free_i32(tcg_decrypt); + if (genfn2) { + gen_gvec_op2_ool(s, true, rd, rn, decrypt, genfn2); + } else { + gen_gvec_op3_ool(s, true, rd, rd, rn, decrypt, genfn3); + } } /* Crypto three-reg SHA @@ -13595,7 +13598,8 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) int rn = extract32(insn, 5, 5); int rd = extract32(insn, 0, 5); bool feature; - CryptoThreeOpFn *genfn; + CryptoThreeOpFn *genfn = NULL; + gen_helper_gvec_3 *oolfn = NULL; if (o == 0) { switch (opcode) { @@ -13630,7 +13634,7 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) break; case 2: /* SM4EKEY */ feature = dc_isar_feature(aa64_sm4, s); - genfn = gen_helper_crypto_sm4ekey; + oolfn = gen_helper_crypto_sm4ekey; break; default: unallocated_encoding(s); @@ -13647,6 +13651,11 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) return; } + if (oolfn) { + gen_gvec_op3_ool(s, true, rd, rn, rm, 0, oolfn); + return; + } + if (genfn) { TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr; @@ -13699,6 +13708,7 @@ static void disas_crypto_two_reg_sha512(DisasContext *s, uint32_t insn) TCGv_ptr tcg_rd_ptr, tcg_rn_ptr; bool feature; CryptoTwoOpFn *genfn; + gen_helper_gvec_3 *oolfn = NULL; switch (opcode) { case 0: /* SHA512SU0 */ @@ -13707,7 +13717,7 @@ static void disas_crypto_two_reg_sha512(DisasContext *s, uint32_t insn) break; case 1: /* SM4E */ feature = dc_isar_feature(aa64_sm4, s); - genfn = gen_helper_crypto_sm4e; + oolfn = gen_helper_crypto_sm4e; break; default: unallocated_encoding(s); @@ -13723,6 +13733,11 @@ static void disas_crypto_two_reg_sha512(DisasContext *s, uint32_t insn) return; } + if (oolfn) { + gen_gvec_op3_ool(s, true, rd, rd, rn, 0, oolfn); + return; + } + tcg_rd_ptr = vec_full_reg_ptr(s, rd); tcg_rn_ptr = vec_full_reg_ptr(s, rn); diff --git a/target/arm/translate.c b/target/arm/translate.c index c8296116d4..74c1b5be42 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -6350,22 +6350,23 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if (!dc_isar_feature(aa32_aes, s) || ((rm | rd) & 1)) { return 1; } - ptr1 = vfp_reg_ptr(true, rd); - ptr2 = vfp_reg_ptr(true, rm); - - /* Bit 6 is the lowest opcode bit; it distinguishes between - * encryption (AESE/AESMC) and decryption (AESD/AESIMC) - */ - tmp3 = tcg_const_i32(extract32(insn, 6, 1)); - + /* + * Bit 6 is the lowest opcode bit; it distinguishes + * between encryption (AESE/AESMC) and decryption + * (AESD/AESIMC). + */ if (op == NEON_2RM_AESE) { - gen_helper_crypto_aese(ptr1, ptr2, tmp3); + tcg_gen_gvec_3_ool(vfp_reg_offset(true, rd), + vfp_reg_offset(true, rd), + vfp_reg_offset(true, rm), + 16, 16, extract32(insn, 6, 1), + gen_helper_crypto_aese); } else { - gen_helper_crypto_aesmc(ptr1, ptr2, tmp3); + tcg_gen_gvec_2_ool(vfp_reg_offset(true, rd), + vfp_reg_offset(true, rm), + 16, 16, extract32(insn, 6, 1), + gen_helper_crypto_aesmc); } - tcg_temp_free_ptr(ptr1); - tcg_temp_free_ptr(ptr2); - tcg_temp_free_i32(tmp3); break; case NEON_2RM_SHA1H: if (!dc_isar_feature(aa32_sha1, s) || ((rm | rd) & 1)) { diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index 50a499299f..7d76412ee0 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -22,7 +22,7 @@ #include "exec/helper-proto.h" #include "tcg/tcg-gvec-desc.h" #include "fpu/softfloat.h" - +#include "vec_internal.h" /* Note that vector data is stored in host-endian 64-bit chunks, so addressing units smaller than that needs a host-endian fixup. */ @@ -36,16 +36,6 @@ #define H4(x) (x) #endif -static void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz) -{ - uint64_t *d = vd + opr_sz; - uintptr_t i; - - for (i = opr_sz; i < max_sz; i += 8) { - *d++ = 0; - } -} - /* Signed saturating rounding doubling multiply-accumulate high half, 16-bit */ static int16_t inl_qrdmlah_s16(int16_t src1, int16_t src2, int16_t src3, uint32_t *sat) diff --git a/target/arm/vec_internal.h b/target/arm/vec_internal.h new file mode 100644 index 0000000000..00a8277765 --- /dev/null +++ b/target/arm/vec_internal.h @@ -0,0 +1,33 @@ +/* + * ARM AdvSIMD / SVE Vector Helpers + * + * Copyright (c) 2020 Linaro + * + * 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 . + */ + +#ifndef TARGET_ARM_VEC_INTERNALS_H +#define TARGET_ARM_VEC_INTERNALS_H + +static inline void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz) +{ + uint64_t *d = vd + opr_sz; + uintptr_t i; + + for (i = opr_sz; i < max_sz; i += 8) { + *d++ = 0; + } +} + +#endif /* TARGET_ARM_VEC_INTERNALS_H */ From 1738860d7e60dec5dbeba17f8b44d31aae3accac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 May 2020 14:28:27 -0700 Subject: [PATCH 0857/2595] target/arm: Convert rax1 to gvec helpers With this conversion, we will be able to use the same helpers with sve. This also fixes a bug in which we failed to clear the high bits of the SVE register after an AdvSIMD operation. Signed-off-by: Richard Henderson Message-id: 20200514212831.31248-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/crypto_helper.c | 11 +++++++ target/arm/helper.h | 2 ++ target/arm/translate-a64.c | 59 ++++++++++++++++++++------------------ target/arm/translate-a64.h | 3 ++ 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/target/arm/crypto_helper.c b/target/arm/crypto_helper.c index 6bd5a3d2d0..372d8350e4 100644 --- a/target/arm/crypto_helper.c +++ b/target/arm/crypto_helper.c @@ -725,3 +725,14 @@ void HELPER(crypto_sm4ekey)(void *vd, void *vn, void* vm, uint32_t desc) } clear_tail(vd, opr_sz, simd_maxsz(desc)); } + +void HELPER(crypto_rax1)(void *vd, void *vn, void *vm, uint32_t desc) +{ + intptr_t i, opr_sz = simd_oprsz(desc); + uint64_t *d = vd, *n = vn, *m = vm; + + for (i = 0; i < opr_sz / 8; ++i) { + d[i] = n[i] ^ rol64(m[i], 1); + } + clear_tail(vd, opr_sz, simd_maxsz(desc)); +} diff --git a/target/arm/helper.h b/target/arm/helper.h index 42759f82aa..6c4eb9befb 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -534,6 +534,8 @@ DEF_HELPER_FLAGS_3(crypto_sm3partw2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) DEF_HELPER_FLAGS_4(crypto_sm4e, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(crypto_sm4ekey, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_rax1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index b3f4223006..45c797f8fc 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -13584,6 +13584,32 @@ static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(tcg_rn_ptr); } +static void gen_rax1_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m) +{ + tcg_gen_rotli_i64(d, m, 1); + tcg_gen_xor_i64(d, d, n); +} + +static void gen_rax1_vec(unsigned vece, TCGv_vec d, TCGv_vec n, TCGv_vec m) +{ + tcg_gen_rotli_vec(vece, d, m, 1); + tcg_gen_xor_vec(vece, d, d, n); +} + +void gen_gvec_rax1(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz) +{ + static const TCGOpcode vecop_list[] = { INDEX_op_rotli_vec, 0 }; + static const GVecGen3 op = { + .fni8 = gen_rax1_i64, + .fniv = gen_rax1_vec, + .opt_opc = vecop_list, + .fno = gen_helper_crypto_rax1, + .vece = MO_64, + }; + tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &op); +} + /* Crypto three-reg SHA512 * 31 21 20 16 15 14 13 12 11 10 9 5 4 0 * +-----------------------+------+---+---+-----+--------+------+------+ @@ -13600,6 +13626,7 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) bool feature; CryptoThreeOpFn *genfn = NULL; gen_helper_gvec_3 *oolfn = NULL; + GVecGen3Fn *gvecfn = NULL; if (o == 0) { switch (opcode) { @@ -13617,7 +13644,7 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) break; case 3: /* RAX1 */ feature = dc_isar_feature(aa64_sha3, s); - genfn = NULL; + gvecfn = gen_gvec_rax1; break; default: g_assert_not_reached(); @@ -13653,10 +13680,9 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) if (oolfn) { gen_gvec_op3_ool(s, true, rd, rn, rm, 0, oolfn); - return; - } - - if (genfn) { + } else if (gvecfn) { + gen_gvec_fn3(s, true, rd, rn, rm, gvecfn, MO_64); + } else { TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr; tcg_rd_ptr = vec_full_reg_ptr(s, rd); @@ -13668,29 +13694,6 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(tcg_rd_ptr); tcg_temp_free_ptr(tcg_rn_ptr); tcg_temp_free_ptr(tcg_rm_ptr); - } else { - TCGv_i64 tcg_op1, tcg_op2, tcg_res[2]; - int pass; - - tcg_op1 = tcg_temp_new_i64(); - tcg_op2 = tcg_temp_new_i64(); - tcg_res[0] = tcg_temp_new_i64(); - tcg_res[1] = tcg_temp_new_i64(); - - for (pass = 0; pass < 2; pass++) { - read_vec_element(s, tcg_op1, rn, pass, MO_64); - read_vec_element(s, tcg_op2, rm, pass, MO_64); - - tcg_gen_rotli_i64(tcg_res[pass], tcg_op2, 1); - tcg_gen_xor_i64(tcg_res[pass], tcg_res[pass], tcg_op1); - } - write_vec_element(s, tcg_res[0], rd, 0, MO_64); - write_vec_element(s, tcg_res[1], rd, 1, MO_64); - - tcg_temp_free_i64(tcg_op1); - tcg_temp_free_i64(tcg_op2); - tcg_temp_free_i64(tcg_res[0]); - tcg_temp_free_i64(tcg_res[1]); } } diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index f02fbb63a4..da0f59a2ce 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -115,4 +115,7 @@ static inline int vec_full_reg_size(DisasContext *s) bool disas_sve(DisasContext *, uint32_t); +void gen_gvec_rax1(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); + #endif /* TARGET_ARM_TRANSLATE_A64_H */ From aaffebd6d3135b8aed7e61932af53b004d261579 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 May 2020 14:28:28 -0700 Subject: [PATCH 0858/2595] target/arm: Convert sha512 and sm3 to gvec helpers Do not yet convert the helpers to loop over opr_sz, but the descriptor allows the vector tail to be cleared. Which fixes an existing bug vs SVE. Signed-off-by: Richard Henderson Message-id: 20200514212831.31248-4-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/crypto_helper.c | 37 +++++++++++++++++++++++----- target/arm/helper.h | 15 +++++++----- target/arm/translate-a64.c | 50 ++++++++++++-------------------------- 3 files changed, 55 insertions(+), 47 deletions(-) diff --git a/target/arm/crypto_helper.c b/target/arm/crypto_helper.c index 372d8350e4..637e4c00bb 100644 --- a/target/arm/crypto_helper.c +++ b/target/arm/crypto_helper.c @@ -31,6 +31,19 @@ union CRYPTO_STATE { #define CR_ST_WORD(state, i) (state.words[i]) #endif +/* + * The caller has not been converted to full gvec, and so only + * modifies the low 16 bytes of the vector register. + */ +static void clear_tail_16(void *vd, uint32_t desc) +{ + int opr_sz = simd_oprsz(desc); + int max_sz = simd_maxsz(desc); + + assert(opr_sz == 16); + clear_tail(vd, opr_sz, max_sz); +} + static void do_crypto_aese(uint64_t *rd, uint64_t *rn, uint64_t *rm, bool decrypt) { @@ -470,7 +483,7 @@ static uint64_t s1_512(uint64_t x) return ror64(x, 19) ^ ror64(x, 61) ^ (x >> 6); } -void HELPER(crypto_sha512h)(void *vd, void *vn, void *vm) +void HELPER(crypto_sha512h)(void *vd, void *vn, void *vm, uint32_t desc) { uint64_t *rd = vd; uint64_t *rn = vn; @@ -483,9 +496,11 @@ void HELPER(crypto_sha512h)(void *vd, void *vn, void *vm) rd[0] = d0; rd[1] = d1; + + clear_tail_16(vd, desc); } -void HELPER(crypto_sha512h2)(void *vd, void *vn, void *vm) +void HELPER(crypto_sha512h2)(void *vd, void *vn, void *vm, uint32_t desc) { uint64_t *rd = vd; uint64_t *rn = vn; @@ -498,9 +513,11 @@ void HELPER(crypto_sha512h2)(void *vd, void *vn, void *vm) rd[0] = d0; rd[1] = d1; + + clear_tail_16(vd, desc); } -void HELPER(crypto_sha512su0)(void *vd, void *vn) +void HELPER(crypto_sha512su0)(void *vd, void *vn, uint32_t desc) { uint64_t *rd = vd; uint64_t *rn = vn; @@ -512,9 +529,11 @@ void HELPER(crypto_sha512su0)(void *vd, void *vn) rd[0] = d0; rd[1] = d1; + + clear_tail_16(vd, desc); } -void HELPER(crypto_sha512su1)(void *vd, void *vn, void *vm) +void HELPER(crypto_sha512su1)(void *vd, void *vn, void *vm, uint32_t desc) { uint64_t *rd = vd; uint64_t *rn = vn; @@ -522,9 +541,11 @@ void HELPER(crypto_sha512su1)(void *vd, void *vn, void *vm) rd[0] += s1_512(rn[0]) + rm[0]; rd[1] += s1_512(rn[1]) + rm[1]; + + clear_tail_16(vd, desc); } -void HELPER(crypto_sm3partw1)(void *vd, void *vn, void *vm) +void HELPER(crypto_sm3partw1)(void *vd, void *vn, void *vm, uint32_t desc) { uint64_t *rd = vd; uint64_t *rn = vn; @@ -548,9 +569,11 @@ void HELPER(crypto_sm3partw1)(void *vd, void *vn, void *vm) rd[0] = d.l[0]; rd[1] = d.l[1]; + + clear_tail_16(vd, desc); } -void HELPER(crypto_sm3partw2)(void *vd, void *vn, void *vm) +void HELPER(crypto_sm3partw2)(void *vd, void *vn, void *vm, uint32_t desc) { uint64_t *rd = vd; uint64_t *rn = vn; @@ -568,6 +591,8 @@ void HELPER(crypto_sm3partw2)(void *vd, void *vn, void *vm) rd[0] = d.l[0]; rd[1] = d.l[1]; + + clear_tail_16(vd, desc); } void HELPER(crypto_sm3tt)(void *vd, void *vn, void *vm, uint32_t imm2, diff --git a/target/arm/helper.h b/target/arm/helper.h index 6c4eb9befb..784dc29ce2 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -522,14 +522,17 @@ DEF_HELPER_FLAGS_3(crypto_sha256h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) DEF_HELPER_FLAGS_2(crypto_sha256su0, TCG_CALL_NO_RWG, void, ptr, ptr) DEF_HELPER_FLAGS_3(crypto_sha256su1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) -DEF_HELPER_FLAGS_3(crypto_sha512h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) -DEF_HELPER_FLAGS_3(crypto_sha512h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) -DEF_HELPER_FLAGS_2(crypto_sha512su0, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_3(crypto_sha512su1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) +DEF_HELPER_FLAGS_4(crypto_sha512h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha512h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(crypto_sha512su0, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha512su1, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(crypto_sm3tt, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32, i32) -DEF_HELPER_FLAGS_3(crypto_sm3partw1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) -DEF_HELPER_FLAGS_3(crypto_sm3partw2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) +DEF_HELPER_FLAGS_4(crypto_sm3partw1, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sm3partw2, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(crypto_sm4e, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(crypto_sm4ekey, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 45c797f8fc..2d24cfbe2f 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -13624,7 +13624,6 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) int rn = extract32(insn, 5, 5); int rd = extract32(insn, 0, 5); bool feature; - CryptoThreeOpFn *genfn = NULL; gen_helper_gvec_3 *oolfn = NULL; GVecGen3Fn *gvecfn = NULL; @@ -13632,15 +13631,15 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) switch (opcode) { case 0: /* SHA512H */ feature = dc_isar_feature(aa64_sha512, s); - genfn = gen_helper_crypto_sha512h; + oolfn = gen_helper_crypto_sha512h; break; case 1: /* SHA512H2 */ feature = dc_isar_feature(aa64_sha512, s); - genfn = gen_helper_crypto_sha512h2; + oolfn = gen_helper_crypto_sha512h2; break; case 2: /* SHA512SU1 */ feature = dc_isar_feature(aa64_sha512, s); - genfn = gen_helper_crypto_sha512su1; + oolfn = gen_helper_crypto_sha512su1; break; case 3: /* RAX1 */ feature = dc_isar_feature(aa64_sha3, s); @@ -13653,11 +13652,11 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) switch (opcode) { case 0: /* SM3PARTW1 */ feature = dc_isar_feature(aa64_sm3, s); - genfn = gen_helper_crypto_sm3partw1; + oolfn = gen_helper_crypto_sm3partw1; break; case 1: /* SM3PARTW2 */ feature = dc_isar_feature(aa64_sm3, s); - genfn = gen_helper_crypto_sm3partw2; + oolfn = gen_helper_crypto_sm3partw2; break; case 2: /* SM4EKEY */ feature = dc_isar_feature(aa64_sm4, s); @@ -13680,20 +13679,8 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) if (oolfn) { gen_gvec_op3_ool(s, true, rd, rn, rm, 0, oolfn); - } else if (gvecfn) { - gen_gvec_fn3(s, true, rd, rn, rm, gvecfn, MO_64); } else { - TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr; - - tcg_rd_ptr = vec_full_reg_ptr(s, rd); - tcg_rn_ptr = vec_full_reg_ptr(s, rn); - tcg_rm_ptr = vec_full_reg_ptr(s, rm); - - genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr); - - tcg_temp_free_ptr(tcg_rd_ptr); - tcg_temp_free_ptr(tcg_rn_ptr); - tcg_temp_free_ptr(tcg_rm_ptr); + gen_gvec_fn3(s, true, rd, rn, rm, gvecfn, MO_64); } } @@ -13708,19 +13695,14 @@ static void disas_crypto_two_reg_sha512(DisasContext *s, uint32_t insn) int opcode = extract32(insn, 10, 2); int rn = extract32(insn, 5, 5); int rd = extract32(insn, 0, 5); - TCGv_ptr tcg_rd_ptr, tcg_rn_ptr; bool feature; - CryptoTwoOpFn *genfn; - gen_helper_gvec_3 *oolfn = NULL; switch (opcode) { case 0: /* SHA512SU0 */ feature = dc_isar_feature(aa64_sha512, s); - genfn = gen_helper_crypto_sha512su0; break; case 1: /* SM4E */ feature = dc_isar_feature(aa64_sm4, s); - oolfn = gen_helper_crypto_sm4e; break; default: unallocated_encoding(s); @@ -13736,18 +13718,16 @@ static void disas_crypto_two_reg_sha512(DisasContext *s, uint32_t insn) return; } - if (oolfn) { - gen_gvec_op3_ool(s, true, rd, rd, rn, 0, oolfn); - return; + switch (opcode) { + case 0: /* SHA512SU0 */ + gen_gvec_op2_ool(s, true, rd, rn, 0, gen_helper_crypto_sha512su0); + break; + case 1: /* SM4E */ + gen_gvec_op3_ool(s, true, rd, rd, rn, 0, gen_helper_crypto_sm4e); + break; + default: + g_assert_not_reached(); } - - tcg_rd_ptr = vec_full_reg_ptr(s, rd); - tcg_rn_ptr = vec_full_reg_ptr(s, rn); - - genfn(tcg_rd_ptr, tcg_rn_ptr); - - tcg_temp_free_ptr(tcg_rd_ptr); - tcg_temp_free_ptr(tcg_rn_ptr); } /* Crypto four-register From effa992f153f5e7ab97ab843b565690748c5b402 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 May 2020 14:28:29 -0700 Subject: [PATCH 0859/2595] target/arm: Convert sha1 and sha256 to gvec helpers Do not yet convert the helpers to loop over opr_sz, but the descriptor allows the vector tail to be cleared. Which fixes an existing bug vs SVE. Signed-off-by: Richard Henderson Message-id: 20200514212831.31248-5-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/crypto_helper.c | 24 +++++-- target/arm/helper.h | 12 ++-- target/arm/neon-dp.decode | 12 ++-- target/arm/translate-a64.c | 34 ++++----- target/arm/translate-neon.inc.c | 124 +++++--------------------------- target/arm/translate.c | 24 ++----- 6 files changed, 67 insertions(+), 163 deletions(-) diff --git a/target/arm/crypto_helper.c b/target/arm/crypto_helper.c index 637e4c00bb..7124745c32 100644 --- a/target/arm/crypto_helper.c +++ b/target/arm/crypto_helper.c @@ -303,7 +303,7 @@ void HELPER(crypto_sha1_3reg)(void *vd, void *vn, void *vm, uint32_t op) rd[1] = d.l[1]; } -void HELPER(crypto_sha1h)(void *vd, void *vm) +void HELPER(crypto_sha1h)(void *vd, void *vm, uint32_t desc) { uint64_t *rd = vd; uint64_t *rm = vm; @@ -314,9 +314,11 @@ void HELPER(crypto_sha1h)(void *vd, void *vm) rd[0] = m.l[0]; rd[1] = m.l[1]; + + clear_tail_16(vd, desc); } -void HELPER(crypto_sha1su1)(void *vd, void *vm) +void HELPER(crypto_sha1su1)(void *vd, void *vm, uint32_t desc) { uint64_t *rd = vd; uint64_t *rm = vm; @@ -330,6 +332,8 @@ void HELPER(crypto_sha1su1)(void *vd, void *vm) rd[0] = d.l[0]; rd[1] = d.l[1]; + + clear_tail_16(vd, desc); } /* @@ -357,7 +361,7 @@ static uint32_t s1(uint32_t x) return ror32(x, 17) ^ ror32(x, 19) ^ (x >> 10); } -void HELPER(crypto_sha256h)(void *vd, void *vn, void *vm) +void HELPER(crypto_sha256h)(void *vd, void *vn, void *vm, uint32_t desc) { uint64_t *rd = vd; uint64_t *rn = vn; @@ -388,9 +392,11 @@ void HELPER(crypto_sha256h)(void *vd, void *vn, void *vm) rd[0] = d.l[0]; rd[1] = d.l[1]; + + clear_tail_16(vd, desc); } -void HELPER(crypto_sha256h2)(void *vd, void *vn, void *vm) +void HELPER(crypto_sha256h2)(void *vd, void *vn, void *vm, uint32_t desc) { uint64_t *rd = vd; uint64_t *rn = vn; @@ -413,9 +419,11 @@ void HELPER(crypto_sha256h2)(void *vd, void *vn, void *vm) rd[0] = d.l[0]; rd[1] = d.l[1]; + + clear_tail_16(vd, desc); } -void HELPER(crypto_sha256su0)(void *vd, void *vm) +void HELPER(crypto_sha256su0)(void *vd, void *vm, uint32_t desc) { uint64_t *rd = vd; uint64_t *rm = vm; @@ -429,9 +437,11 @@ void HELPER(crypto_sha256su0)(void *vd, void *vm) rd[0] = d.l[0]; rd[1] = d.l[1]; + + clear_tail_16(vd, desc); } -void HELPER(crypto_sha256su1)(void *vd, void *vn, void *vm) +void HELPER(crypto_sha256su1)(void *vd, void *vn, void *vm, uint32_t desc) { uint64_t *rd = vd; uint64_t *rn = vn; @@ -447,6 +457,8 @@ void HELPER(crypto_sha256su1)(void *vd, void *vn, void *vm) rd[0] = d.l[0]; rd[1] = d.l[1]; + + clear_tail_16(vd, desc); } /* diff --git a/target/arm/helper.h b/target/arm/helper.h index 784dc29ce2..cee23adbfc 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -514,13 +514,13 @@ DEF_HELPER_FLAGS_4(crypto_aese, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_3(crypto_aesmc, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_4(crypto_sha1_3reg, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_2(crypto_sha1h, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_2(crypto_sha1su1, TCG_CALL_NO_RWG, void, ptr, ptr) +DEF_HELPER_FLAGS_3(crypto_sha1h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(crypto_sha1su1, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(crypto_sha256h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) -DEF_HELPER_FLAGS_3(crypto_sha256h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) -DEF_HELPER_FLAGS_2(crypto_sha256su0, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_3(crypto_sha256su1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) +DEF_HELPER_FLAGS_4(crypto_sha256h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha256h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(crypto_sha256su0, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha256su1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(crypto_sha512h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(crypto_sha512h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 8beb1db768..5b2fc65d72 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -165,14 +165,14 @@ VPADD_3s 1111 001 0 0 . .. .... .... 1011 . . . 1 .... @3same_q0 VQRDMLAH_3s 1111 001 1 0 . .. .... .... 1011 ... 1 .... @3same +@3same_crypto .... .... .... .... .... .... .... .... \ + &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp size=0 q=1 + SHA1_3s 1111 001 0 0 . optype:2 .... .... 1100 . 1 . 0 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp -SHA256H_3s 1111 001 1 0 . 00 .... .... 1100 . 1 . 0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp -SHA256H2_3s 1111 001 1 0 . 01 .... .... 1100 . 1 . 0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp -SHA256SU1_3s 1111 001 1 0 . 10 .... .... 1100 . 1 . 0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp +SHA256H_3s 1111 001 1 0 . 00 .... .... 1100 . 1 . 0 .... @3same_crypto +SHA256H2_3s 1111 001 1 0 . 01 .... .... 1100 . 1 . 0 .... @3same_crypto +SHA256SU1_3s 1111 001 1 0 . 10 .... .... 1100 . 1 . 0 .... @3same_crypto VFMA_fp_3s 1111 001 0 0 . 0 . .... .... 1100 ... 1 .... @3same_fp VFMS_fp_3s 1111 001 0 0 . 1 . .... .... 1100 ... 1 .... @3same_fp diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 2d24cfbe2f..5a4f8196bd 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -13465,8 +13465,7 @@ static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn) int rm = extract32(insn, 16, 5); int rn = extract32(insn, 5, 5); int rd = extract32(insn, 0, 5); - CryptoThreeOpFn *genfn; - TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr; + gen_helper_gvec_3 *genfn; bool feature; if (size != 0) { @@ -13508,23 +13507,22 @@ static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn) return; } - tcg_rd_ptr = vec_full_reg_ptr(s, rd); - tcg_rn_ptr = vec_full_reg_ptr(s, rn); - tcg_rm_ptr = vec_full_reg_ptr(s, rm); - if (genfn) { - genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr); + gen_gvec_op3_ool(s, true, rd, rn, rm, 0, genfn); } else { TCGv_i32 tcg_opcode = tcg_const_i32(opcode); + TCGv_ptr tcg_rd_ptr = vec_full_reg_ptr(s, rd); + TCGv_ptr tcg_rn_ptr = vec_full_reg_ptr(s, rn); + TCGv_ptr tcg_rm_ptr = vec_full_reg_ptr(s, rm); gen_helper_crypto_sha1_3reg(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr, tcg_opcode); - tcg_temp_free_i32(tcg_opcode); - } - tcg_temp_free_ptr(tcg_rd_ptr); - tcg_temp_free_ptr(tcg_rn_ptr); - tcg_temp_free_ptr(tcg_rm_ptr); + tcg_temp_free_i32(tcg_opcode); + tcg_temp_free_ptr(tcg_rd_ptr); + tcg_temp_free_ptr(tcg_rn_ptr); + tcg_temp_free_ptr(tcg_rm_ptr); + } } /* Crypto two-reg SHA @@ -13539,9 +13537,8 @@ static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn) int opcode = extract32(insn, 12, 5); int rn = extract32(insn, 5, 5); int rd = extract32(insn, 0, 5); - CryptoTwoOpFn *genfn; + gen_helper_gvec_2 *genfn; bool feature; - TCGv_ptr tcg_rd_ptr, tcg_rn_ptr; if (size != 0) { unallocated_encoding(s); @@ -13574,14 +13571,7 @@ static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn) if (!fp_access_check(s)) { return; } - - tcg_rd_ptr = vec_full_reg_ptr(s, rd); - tcg_rn_ptr = vec_full_reg_ptr(s, rn); - - genfn(tcg_rd_ptr, tcg_rn_ptr); - - tcg_temp_free_ptr(tcg_rd_ptr); - tcg_temp_free_ptr(tcg_rn_ptr); + gen_gvec_op2_ool(s, true, rd, rn, 0, genfn); } static void gen_rax1_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m) diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 3fe65a0b08..205877ca48 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -661,12 +661,14 @@ DO_3SAME_CMP(VCGE_S, TCG_COND_GE) DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) DO_3SAME_CMP(VCEQ, TCG_COND_EQ) -static void gen_VMUL_p_3s(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, - uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) -{ - tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, - 0, gen_helper_gvec_pmul_b); -} +#define WRAP_OOL_FN(WRAPNAME, FUNC) \ + static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, \ + uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) \ + { \ + tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \ + } + +WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b) static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) { @@ -728,107 +730,19 @@ static bool trans_SHA1_3s(DisasContext *s, arg_SHA1_3s *a) return true; } -static bool trans_SHA256H_3s(DisasContext *s, arg_SHA256H_3s *a) -{ - TCGv_ptr ptr1, ptr2, ptr3; - - if (!arm_dc_feature(s, ARM_FEATURE_NEON) || - !dc_isar_feature(aa32_sha2, s)) { - return false; +#define DO_SHA2(NAME, FUNC) \ + WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ + static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ + { \ + if (!dc_isar_feature(aa32_sha2, s)) { \ + return false; \ + } \ + return do_3same(s, a, gen_##NAME##_3s); \ } - /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { - return false; - } - - if ((a->vn | a->vm | a->vd) & 1) { - return false; - } - - if (!vfp_access_check(s)) { - return true; - } - - ptr1 = vfp_reg_ptr(true, a->vd); - ptr2 = vfp_reg_ptr(true, a->vn); - ptr3 = vfp_reg_ptr(true, a->vm); - gen_helper_crypto_sha256h(ptr1, ptr2, ptr3); - tcg_temp_free_ptr(ptr1); - tcg_temp_free_ptr(ptr2); - tcg_temp_free_ptr(ptr3); - - return true; -} - -static bool trans_SHA256H2_3s(DisasContext *s, arg_SHA256H2_3s *a) -{ - TCGv_ptr ptr1, ptr2, ptr3; - - if (!arm_dc_feature(s, ARM_FEATURE_NEON) || - !dc_isar_feature(aa32_sha2, s)) { - return false; - } - - /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { - return false; - } - - if ((a->vn | a->vm | a->vd) & 1) { - return false; - } - - if (!vfp_access_check(s)) { - return true; - } - - ptr1 = vfp_reg_ptr(true, a->vd); - ptr2 = vfp_reg_ptr(true, a->vn); - ptr3 = vfp_reg_ptr(true, a->vm); - gen_helper_crypto_sha256h2(ptr1, ptr2, ptr3); - tcg_temp_free_ptr(ptr1); - tcg_temp_free_ptr(ptr2); - tcg_temp_free_ptr(ptr3); - - return true; -} - -static bool trans_SHA256SU1_3s(DisasContext *s, arg_SHA256SU1_3s *a) -{ - TCGv_ptr ptr1, ptr2, ptr3; - - if (!arm_dc_feature(s, ARM_FEATURE_NEON) || - !dc_isar_feature(aa32_sha2, s)) { - return false; - } - - /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { - return false; - } - - if ((a->vn | a->vm | a->vd) & 1) { - return false; - } - - if (!vfp_access_check(s)) { - return true; - } - - ptr1 = vfp_reg_ptr(true, a->vd); - ptr2 = vfp_reg_ptr(true, a->vn); - ptr3 = vfp_reg_ptr(true, a->vm); - gen_helper_crypto_sha256su1(ptr1, ptr2, ptr3); - tcg_temp_free_ptr(ptr1); - tcg_temp_free_ptr(ptr2); - tcg_temp_free_ptr(ptr3); - - return true; -} +DO_SHA2(SHA256H, gen_helper_crypto_sha256h) +DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2) +DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1) #define DO_3SAME_64(INSN, FUNC) \ static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ diff --git a/target/arm/translate.c b/target/arm/translate.c index 74c1b5be42..c61180ea61 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5257,7 +5257,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int vec_size; uint32_t imm; TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5; - TCGv_ptr ptr1, ptr2; + TCGv_ptr ptr1; TCGv_i64 tmp64; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { @@ -6372,13 +6372,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if (!dc_isar_feature(aa32_sha1, s) || ((rm | rd) & 1)) { return 1; } - ptr1 = vfp_reg_ptr(true, rd); - ptr2 = vfp_reg_ptr(true, rm); - - gen_helper_crypto_sha1h(ptr1, ptr2); - - tcg_temp_free_ptr(ptr1); - tcg_temp_free_ptr(ptr2); + tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0, + gen_helper_crypto_sha1h); break; case NEON_2RM_SHA1SU1: if ((rm | rd) & 1) { @@ -6392,17 +6387,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } else if (!dc_isar_feature(aa32_sha1, s)) { return 1; } - ptr1 = vfp_reg_ptr(true, rd); - ptr2 = vfp_reg_ptr(true, rm); - if (q) { - gen_helper_crypto_sha256su0(ptr1, ptr2); - } else { - gen_helper_crypto_sha1su1(ptr1, ptr2); - } - tcg_temp_free_ptr(ptr1); - tcg_temp_free_ptr(ptr2); + tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0, + q ? gen_helper_crypto_sha256su0 + : gen_helper_crypto_sha1su1); break; - case NEON_2RM_VMVN: tcg_gen_gvec_not(0, rd_ofs, rm_ofs, vec_size, vec_size); break; From afc8b7d32668547308bdd654a63cf5228936e0ba Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 May 2020 14:28:30 -0700 Subject: [PATCH 0860/2595] target/arm: Split helper_crypto_sha1_3reg Rather than passing an opcode to a helper, fully decode the operation at translate time. Use clear_tail_16 to zap the balance of the SVE register with the AdvSIMD write. Signed-off-by: Richard Henderson Message-id: 20200514212831.31248-6-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/crypto_helper.c | 99 +++++++++++++++++++++------------ target/arm/helper.h | 5 +- target/arm/neon-dp.decode | 6 +- target/arm/translate-a64.c | 29 ++++------ target/arm/translate-neon.inc.c | 46 ++++----------- 5 files changed, 93 insertions(+), 92 deletions(-) diff --git a/target/arm/crypto_helper.c b/target/arm/crypto_helper.c index 7124745c32..636683d0f1 100644 --- a/target/arm/crypto_helper.c +++ b/target/arm/crypto_helper.c @@ -24,11 +24,11 @@ union CRYPTO_STATE { }; #ifdef HOST_WORDS_BIGENDIAN -#define CR_ST_BYTE(state, i) (state.bytes[(15 - (i)) ^ 8]) -#define CR_ST_WORD(state, i) (state.words[(3 - (i)) ^ 2]) +#define CR_ST_BYTE(state, i) ((state).bytes[(15 - (i)) ^ 8]) +#define CR_ST_WORD(state, i) ((state).words[(3 - (i)) ^ 2]) #else -#define CR_ST_BYTE(state, i) (state.bytes[i]) -#define CR_ST_WORD(state, i) (state.words[i]) +#define CR_ST_BYTE(state, i) ((state).bytes[i]) +#define CR_ST_WORD(state, i) ((state).words[i]) #endif /* @@ -258,49 +258,74 @@ static uint32_t maj(uint32_t x, uint32_t y, uint32_t z) return (x & y) | ((x | y) & z); } -void HELPER(crypto_sha1_3reg)(void *vd, void *vn, void *vm, uint32_t op) +void HELPER(crypto_sha1su0)(void *vd, void *vn, void *vm, uint32_t desc) +{ + uint64_t *d = vd, *n = vn, *m = vm; + uint64_t d0, d1; + + d0 = d[1] ^ d[0] ^ m[0]; + d1 = n[0] ^ d[1] ^ m[1]; + d[0] = d0; + d[1] = d1; + + clear_tail_16(vd, desc); +} + +static inline void crypto_sha1_3reg(uint64_t *rd, uint64_t *rn, + uint64_t *rm, uint32_t desc, + uint32_t (*fn)(union CRYPTO_STATE *d)) { - uint64_t *rd = vd; - uint64_t *rn = vn; - uint64_t *rm = vm; union CRYPTO_STATE d = { .l = { rd[0], rd[1] } }; union CRYPTO_STATE n = { .l = { rn[0], rn[1] } }; union CRYPTO_STATE m = { .l = { rm[0], rm[1] } }; + int i; - if (op == 3) { /* sha1su0 */ - d.l[0] ^= d.l[1] ^ m.l[0]; - d.l[1] ^= n.l[0] ^ m.l[1]; - } else { - int i; + for (i = 0; i < 4; i++) { + uint32_t t = fn(&d); - for (i = 0; i < 4; i++) { - uint32_t t; + t += rol32(CR_ST_WORD(d, 0), 5) + CR_ST_WORD(n, 0) + + CR_ST_WORD(m, i); - switch (op) { - case 0: /* sha1c */ - t = cho(CR_ST_WORD(d, 1), CR_ST_WORD(d, 2), CR_ST_WORD(d, 3)); - break; - case 1: /* sha1p */ - t = par(CR_ST_WORD(d, 1), CR_ST_WORD(d, 2), CR_ST_WORD(d, 3)); - break; - case 2: /* sha1m */ - t = maj(CR_ST_WORD(d, 1), CR_ST_WORD(d, 2), CR_ST_WORD(d, 3)); - break; - default: - g_assert_not_reached(); - } - t += rol32(CR_ST_WORD(d, 0), 5) + CR_ST_WORD(n, 0) - + CR_ST_WORD(m, i); - - CR_ST_WORD(n, 0) = CR_ST_WORD(d, 3); - CR_ST_WORD(d, 3) = CR_ST_WORD(d, 2); - CR_ST_WORD(d, 2) = ror32(CR_ST_WORD(d, 1), 2); - CR_ST_WORD(d, 1) = CR_ST_WORD(d, 0); - CR_ST_WORD(d, 0) = t; - } + CR_ST_WORD(n, 0) = CR_ST_WORD(d, 3); + CR_ST_WORD(d, 3) = CR_ST_WORD(d, 2); + CR_ST_WORD(d, 2) = ror32(CR_ST_WORD(d, 1), 2); + CR_ST_WORD(d, 1) = CR_ST_WORD(d, 0); + CR_ST_WORD(d, 0) = t; } rd[0] = d.l[0]; rd[1] = d.l[1]; + + clear_tail_16(rd, desc); +} + +static uint32_t do_sha1c(union CRYPTO_STATE *d) +{ + return cho(CR_ST_WORD(*d, 1), CR_ST_WORD(*d, 2), CR_ST_WORD(*d, 3)); +} + +void HELPER(crypto_sha1c)(void *vd, void *vn, void *vm, uint32_t desc) +{ + crypto_sha1_3reg(vd, vn, vm, desc, do_sha1c); +} + +static uint32_t do_sha1p(union CRYPTO_STATE *d) +{ + return par(CR_ST_WORD(*d, 1), CR_ST_WORD(*d, 2), CR_ST_WORD(*d, 3)); +} + +void HELPER(crypto_sha1p)(void *vd, void *vn, void *vm, uint32_t desc) +{ + crypto_sha1_3reg(vd, vn, vm, desc, do_sha1p); +} + +static uint32_t do_sha1m(union CRYPTO_STATE *d) +{ + return maj(CR_ST_WORD(*d, 1), CR_ST_WORD(*d, 2), CR_ST_WORD(*d, 3)); +} + +void HELPER(crypto_sha1m)(void *vd, void *vn, void *vm, uint32_t desc) +{ + crypto_sha1_3reg(vd, vn, vm, desc, do_sha1m); } void HELPER(crypto_sha1h)(void *vd, void *vm, uint32_t desc) diff --git a/target/arm/helper.h b/target/arm/helper.h index cee23adbfc..13475ecf81 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -513,7 +513,10 @@ DEF_HELPER_FLAGS_2(neon_qzip32, TCG_CALL_NO_RWG, void, ptr, ptr) DEF_HELPER_FLAGS_4(crypto_aese, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_3(crypto_aesmc, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sha1_3reg, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha1su0, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha1c, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha1p, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha1m, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_3(crypto_sha1h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(crypto_sha1su1, TCG_CALL_NO_RWG, void, ptr, ptr, i32) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 5b2fc65d72..8af7c53d8b 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -168,8 +168,10 @@ VQRDMLAH_3s 1111 001 1 0 . .. .... .... 1011 ... 1 .... @3same @3same_crypto .... .... .... .... .... .... .... .... \ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp size=0 q=1 -SHA1_3s 1111 001 0 0 . optype:2 .... .... 1100 . 1 . 0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp +SHA1C_3s 1111 001 0 0 . 00 .... .... 1100 . 1 . 0 .... @3same_crypto +SHA1P_3s 1111 001 0 0 . 01 .... .... 1100 . 1 . 0 .... @3same_crypto +SHA1M_3s 1111 001 0 0 . 10 .... .... 1100 . 1 . 0 .... @3same_crypto +SHA1SU0_3s 1111 001 0 0 . 11 .... .... 1100 . 1 . 0 .... @3same_crypto SHA256H_3s 1111 001 1 0 . 00 .... .... 1100 . 1 . 0 .... @3same_crypto SHA256H2_3s 1111 001 1 0 . 01 .... .... 1100 . 1 . 0 .... @3same_crypto SHA256SU1_3s 1111 001 1 0 . 10 .... .... 1100 . 1 . 0 .... @3same_crypto diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 5a4f8196bd..3f28888cd2 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -13475,10 +13475,19 @@ static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn) switch (opcode) { case 0: /* SHA1C */ + genfn = gen_helper_crypto_sha1c; + feature = dc_isar_feature(aa64_sha1, s); + break; case 1: /* SHA1P */ + genfn = gen_helper_crypto_sha1p; + feature = dc_isar_feature(aa64_sha1, s); + break; case 2: /* SHA1M */ + genfn = gen_helper_crypto_sha1m; + feature = dc_isar_feature(aa64_sha1, s); + break; case 3: /* SHA1SU0 */ - genfn = NULL; + genfn = gen_helper_crypto_sha1su0; feature = dc_isar_feature(aa64_sha1, s); break; case 4: /* SHA256H */ @@ -13506,23 +13515,7 @@ static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn) if (!fp_access_check(s)) { return; } - - if (genfn) { - gen_gvec_op3_ool(s, true, rd, rn, rm, 0, genfn); - } else { - TCGv_i32 tcg_opcode = tcg_const_i32(opcode); - TCGv_ptr tcg_rd_ptr = vec_full_reg_ptr(s, rd); - TCGv_ptr tcg_rn_ptr = vec_full_reg_ptr(s, rn); - TCGv_ptr tcg_rm_ptr = vec_full_reg_ptr(s, rm); - - gen_helper_crypto_sha1_3reg(tcg_rd_ptr, tcg_rn_ptr, - tcg_rm_ptr, tcg_opcode); - - tcg_temp_free_i32(tcg_opcode); - tcg_temp_free_ptr(tcg_rd_ptr); - tcg_temp_free_ptr(tcg_rn_ptr); - tcg_temp_free_ptr(tcg_rm_ptr); - } + gen_gvec_op3_ool(s, true, rd, rn, rm, 0, genfn); } /* Crypto two-reg SHA diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 205877ca48..7b19753c8c 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -693,42 +693,20 @@ static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc) DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc) -static bool trans_SHA1_3s(DisasContext *s, arg_SHA1_3s *a) -{ - TCGv_ptr ptr1, ptr2, ptr3; - TCGv_i32 tmp; - - if (!arm_dc_feature(s, ARM_FEATURE_NEON) || - !dc_isar_feature(aa32_sha1, s)) { - return false; +#define DO_SHA1(NAME, FUNC) \ + WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ + static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ + { \ + if (!dc_isar_feature(aa32_sha1, s)) { \ + return false; \ + } \ + return do_3same(s, a, gen_##NAME##_3s); \ } - /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { - return false; - } - - if ((a->vn | a->vm | a->vd) & 1) { - return false; - } - - if (!vfp_access_check(s)) { - return true; - } - - ptr1 = vfp_reg_ptr(true, a->vd); - ptr2 = vfp_reg_ptr(true, a->vn); - ptr3 = vfp_reg_ptr(true, a->vm); - tmp = tcg_const_i32(a->optype); - gen_helper_crypto_sha1_3reg(ptr1, ptr2, ptr3, tmp); - tcg_temp_free_i32(tmp); - tcg_temp_free_ptr(ptr1); - tcg_temp_free_ptr(ptr2); - tcg_temp_free_ptr(ptr3); - - return true; -} +DO_SHA1(SHA1C, gen_helper_crypto_sha1c) +DO_SHA1(SHA1P, gen_helper_crypto_sha1p) +DO_SHA1(SHA1M, gen_helper_crypto_sha1m) +DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0) #define DO_SHA2(NAME, FUNC) \ WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ From 43fa36c96c24349145497adc1b451f9caf74e344 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 May 2020 14:28:31 -0700 Subject: [PATCH 0861/2595] target/arm: Split helper_crypto_sm3tt Rather than passing an opcode to a helper, fully decode the operation at translate time. Use clear_tail_16 to zap the balance of the SVE register with the AdvSIMD write. Signed-off-by: Richard Henderson Message-id: 20200514212831.31248-7-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/crypto_helper.c | 24 ++++++++++++++++++------ target/arm/helper.h | 5 ++++- target/arm/translate-a64.c | 21 +++++---------------- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/target/arm/crypto_helper.c b/target/arm/crypto_helper.c index 636683d0f1..c76806dc8d 100644 --- a/target/arm/crypto_helper.c +++ b/target/arm/crypto_helper.c @@ -632,15 +632,14 @@ void HELPER(crypto_sm3partw2)(void *vd, void *vn, void *vm, uint32_t desc) clear_tail_16(vd, desc); } -void HELPER(crypto_sm3tt)(void *vd, void *vn, void *vm, uint32_t imm2, - uint32_t opcode) +static inline void QEMU_ALWAYS_INLINE +crypto_sm3tt(uint64_t *rd, uint64_t *rn, uint64_t *rm, + uint32_t desc, uint32_t opcode) { - uint64_t *rd = vd; - uint64_t *rn = vn; - uint64_t *rm = vm; union CRYPTO_STATE d = { .l = { rd[0], rd[1] } }; union CRYPTO_STATE n = { .l = { rn[0], rn[1] } }; union CRYPTO_STATE m = { .l = { rm[0], rm[1] } }; + uint32_t imm2 = simd_data(desc); uint32_t t; assert(imm2 < 4); @@ -655,7 +654,7 @@ void HELPER(crypto_sm3tt)(void *vd, void *vn, void *vm, uint32_t imm2, /* SM3TT2B */ t = cho(CR_ST_WORD(d, 3), CR_ST_WORD(d, 2), CR_ST_WORD(d, 1)); } else { - g_assert_not_reached(); + qemu_build_not_reached(); } t += CR_ST_WORD(d, 0) + CR_ST_WORD(m, imm2); @@ -680,8 +679,21 @@ void HELPER(crypto_sm3tt)(void *vd, void *vn, void *vm, uint32_t imm2, rd[0] = d.l[0]; rd[1] = d.l[1]; + + clear_tail_16(rd, desc); } +#define DO_SM3TT(NAME, OPCODE) \ + void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \ + { crypto_sm3tt(vd, vn, vm, desc, OPCODE); } + +DO_SM3TT(crypto_sm3tt1a, 0) +DO_SM3TT(crypto_sm3tt1b, 1) +DO_SM3TT(crypto_sm3tt2a, 2) +DO_SM3TT(crypto_sm3tt2b, 3) + +#undef DO_SM3TT + static uint8_t const sm4_sbox[] = { 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, diff --git a/target/arm/helper.h b/target/arm/helper.h index 13475ecf81..2a20c8174c 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -531,7 +531,10 @@ DEF_HELPER_FLAGS_3(crypto_sha512su0, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_4(crypto_sha512su1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(crypto_sm3tt, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32, i32) +DEF_HELPER_FLAGS_4(crypto_sm3tt1a, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sm3tt1b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sm3tt2a, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sm3tt2b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(crypto_sm3partw1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(crypto_sm3partw2, TCG_CALL_NO_RWG, diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 3f28888cd2..a0e72ad694 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -13866,13 +13866,15 @@ static void disas_crypto_xar(DisasContext *s, uint32_t insn) */ static void disas_crypto_three_reg_imm2(DisasContext *s, uint32_t insn) { + static gen_helper_gvec_3 * const fns[4] = { + gen_helper_crypto_sm3tt1a, gen_helper_crypto_sm3tt1b, + gen_helper_crypto_sm3tt2a, gen_helper_crypto_sm3tt2b, + }; int opcode = extract32(insn, 10, 2); int imm2 = extract32(insn, 12, 2); int rm = extract32(insn, 16, 5); int rn = extract32(insn, 5, 5); int rd = extract32(insn, 0, 5); - TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr; - TCGv_i32 tcg_imm2, tcg_opcode; if (!dc_isar_feature(aa64_sm3, s)) { unallocated_encoding(s); @@ -13883,20 +13885,7 @@ static void disas_crypto_three_reg_imm2(DisasContext *s, uint32_t insn) return; } - tcg_rd_ptr = vec_full_reg_ptr(s, rd); - tcg_rn_ptr = vec_full_reg_ptr(s, rn); - tcg_rm_ptr = vec_full_reg_ptr(s, rm); - tcg_imm2 = tcg_const_i32(imm2); - tcg_opcode = tcg_const_i32(opcode); - - gen_helper_crypto_sm3tt(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr, tcg_imm2, - tcg_opcode); - - tcg_temp_free_ptr(tcg_rd_ptr); - tcg_temp_free_ptr(tcg_rn_ptr); - tcg_temp_free_ptr(tcg_rm_ptr); - tcg_temp_free_i32(tcg_imm2); - tcg_temp_free_i32(tcg_opcode); + gen_gvec_op3_ool(s, true, rd, rn, rm, imm2, fns[opcode]); } /* C3.6 Data processing - SIMD, inc Crypto From d04bf49c9ee8fa3e8f2961462a9f053c3faa8548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 3 Jun 2020 07:59:15 +0200 Subject: [PATCH 0862/2595] hw/adc/stm32f2xx_adc: Correct memory region size and access size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ADC region size is 256B, split as: - [0x00 - 0x4f] defined - [0x50 - 0xff] reserved All registers are 32-bit (thus when the datasheet mentions the last defined register is 0x4c, it means its address range is 0x4c .. 0x4f. This model implementation is also 32-bit. Set MemoryRegionOps 'impl' fields. See: 'RM0033 Reference manual Rev 8', Table 10.13.18 "ADC register map". Reported-by: Seth Kintigh Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200603055915.17678-1-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/adc/stm32f2xx_adc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/adc/stm32f2xx_adc.c b/hw/adc/stm32f2xx_adc.c index 4f9d485ecf..01a0b14e69 100644 --- a/hw/adc/stm32f2xx_adc.c +++ b/hw/adc/stm32f2xx_adc.c @@ -246,6 +246,8 @@ static const MemoryRegionOps stm32f2xx_adc_ops = { .read = stm32f2xx_adc_read, .write = stm32f2xx_adc_write, .endianness = DEVICE_NATIVE_ENDIAN, + .impl.min_access_size = 4, + .impl.max_access_size = 4, }; static const VMStateDescription vmstate_stm32f2xx_adc = { @@ -278,7 +280,7 @@ static void stm32f2xx_adc_init(Object *obj) sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); memory_region_init_io(&s->mmio, obj, &stm32f2xx_adc_ops, s, - TYPE_STM32F2XX_ADC, 0xFF); + TYPE_STM32F2XX_ADC, 0x100); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); } From 27dfbafaa78c3937122954cb0706e4e203812c56 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 25 May 2020 16:12:37 +0200 Subject: [PATCH 0863/2595] tests/acceptance: Add a boot test for the xlnx-versal-virt machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As described by Edgar here: https://www.mail-archive.com/qemu-devel@nongnu.org/msg605124.html we can use the Ubuntu kernel for testing the xlnx-versal-virt machine. So let's add a boot test for this now. Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Message-id: 20200525141237.15243-1-thuth@redhat.com Signed-off-by: Peter Maydell --- tests/acceptance/boot_linux_console.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 12725d4529..bbbbd30e48 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -308,6 +308,32 @@ class BootLinuxConsole(LinuxKernelTest): console_pattern = 'Kernel command line: %s' % kernel_command_line self.wait_for_console_pattern(console_pattern) + def test_aarch64_xlnx_versal_virt(self): + """ + :avocado: tags=arch:aarch64 + :avocado: tags=machine:xlnx-versal-virt + :avocado: tags=device:pl011 + :avocado: tags=device:arm_gicv3 + """ + kernel_url = ('http://ports.ubuntu.com/ubuntu-ports/dists/' + 'bionic-updates/main/installer-arm64/current/images/' + 'netboot/ubuntu-installer/arm64/linux') + kernel_hash = '5bfc54cf7ed8157d93f6e5b0241e727b6dc22c50' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + initrd_url = ('http://ports.ubuntu.com/ubuntu-ports/dists/' + 'bionic-updates/main/installer-arm64/current/images/' + 'netboot/ubuntu-installer/arm64/initrd.gz') + initrd_hash = 'd385d3e88d53e2004c5d43cbe668b458a094f772' + initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash) + + self.vm.set_console() + self.vm.add_args('-m', '2G', + '-kernel', kernel_path, + '-initrd', initrd_path) + self.vm.launch() + self.wait_for_console_pattern('Checked W+X mappings: passed') + def test_arm_virt(self): """ :avocado: tags=arch:arm From 7a1e049a707149b306b7b65c66d504d251c0a4b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 2 Jun 2020 15:50:50 +0200 Subject: [PATCH 0864/2595] docs/system: Document Aspeed boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200602135050.593692-1-clg@kaod.org Signed-off-by: Peter Maydell --- docs/system/arm/aspeed.rst | 85 ++++++++++++++++++++++++++++++++++++++ docs/system/target-arm.rst | 1 + 2 files changed, 86 insertions(+) create mode 100644 docs/system/arm/aspeed.rst diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst new file mode 100644 index 0000000000..45f891eb3c --- /dev/null +++ b/docs/system/arm/aspeed.rst @@ -0,0 +1,85 @@ +Aspeed family boards (``*-bmc``, ``ast2500-evb``, ``ast2600-evb``) +================================================================== + +The QEMU Aspeed machines model BMCs of various OpenPOWER systems and +Aspeed evaluation boards. They are based on different releases of the +Aspeed SoC : the AST2400 integrating an ARM926EJ-S CPU (400MHz), the +AST2500 with an ARM1176JZS CPU (800MHz) and more recently the AST2600 +with dual cores ARM Cortex A7 CPUs (1.2GHz). + +The SoC comes with RAM, Gigabit ethernet, USB, SD/MMC, USB, SPI, I2C, +etc. + +AST2400 SoC based machines : + +- ``palmetto-bmc`` OpenPOWER Palmetto POWER8 BMC + +AST2500 SoC based machines : + +- ``ast2500-evb`` Aspeed AST2500 Evaluation board +- ``romulus-bmc`` OpenPOWER Romulus POWER9 BMC +- ``witherspoon-bmc`` OpenPOWER Witherspoon POWER9 BMC +- ``sonorapass-bmc`` OCP SonoraPass BMC +- ``swift-bmc`` OpenPOWER Swift BMC POWER9 + +AST2600 SoC based machines : + +- ``ast2600-evb`` Aspeed AST2600 Evaluation board (Cortex A7) +- ``tacoma-bmc`` OpenPOWER Witherspoon POWER9 AST2600 BMC + +Supported devices +----------------- + + * SMP (for the AST2600 Cortex-A7) + * Interrupt Controller (VIC) + * Timer Controller + * RTC Controller + * I2C Controller + * System Control Unit (SCU) + * SRAM mapping + * X-DMA Controller (basic interface) + * Static Memory Controller (SMC or FMC) - Only SPI Flash support + * SPI Memory Controller + * USB 2.0 Controller + * SD/MMC storage controllers + * SDRAM controller (dummy interface for basic settings and training) + * Watchdog Controller + * GPIO Controller (Master only) + * UART + * Ethernet controllers + + +Missing devices +--------------- + + * Coprocessor support + * ADC (out of tree implementation) + * PWM and Fan Controller + * LPC Bus Controller + * Slave GPIO Controller + * Super I/O Controller + * Hash/Crypto Engine + * PCI-Express 1 Controller + * Graphic Display Controller + * PECI Controller + * MCTP Controller + * Mailbox Controller + * Virtual UART + * eSPI Controller + * I3C Controller + +Boot options +------------ + +The Aspeed machines can be started using the -kernel option to load a +Linux kernel or from a firmare image which can be downloaded from the +OpenPOWER jenkins : + + https://openpower.xyz/ + +The image should be attached as an MTD drive. Run : + +.. code-block:: bash + + $ qemu-system-arm -M romulus-bmc -nic user \ + -drive file=flash-romulus,format=raw,if=mtd -nographic diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index dce384cb0e..1bd477a293 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -81,6 +81,7 @@ undocumented; you can get a complete list by running arm/realview arm/versatile arm/vexpress + arm/aspeed arm/musicpal arm/nseries arm/orangepi From 3d46938bbbd7cea47ab9b994c0438aea3d10d98f Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Wed, 20 May 2020 16:53:43 -0700 Subject: [PATCH 0865/2595] raspi: add BCM2835 SOC MPHI emulation Add BCM2835 SOC MPHI (Message-based Parallel Host Interface) emulation. It is very basic, only providing the FIQ interrupt needed to allow the dwc-otg USB host controller driver in the Raspbian kernel to function. Signed-off-by: Paul Zimmerman Acked-by: Philippe Mathieu-Daude Reviewed-by: Peter Maydell Message-id: 20200520235349.21215-2-pauldzim@gmail.com Signed-off-by: Peter Maydell --- hw/arm/bcm2835_peripherals.c | 17 +++ hw/misc/Makefile.objs | 1 + hw/misc/bcm2835_mphi.c | 191 +++++++++++++++++++++++++++ include/hw/arm/bcm2835_peripherals.h | 2 + include/hw/misc/bcm2835_mphi.h | 44 ++++++ 5 files changed, 255 insertions(+) create mode 100644 hw/misc/bcm2835_mphi.c create mode 100644 include/hw/misc/bcm2835_mphi.h diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index f1bcc14f55..b3e0495040 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -125,6 +125,10 @@ static void bcm2835_peripherals_init(Object *obj) OBJECT(&s->sdhci.sdbus)); object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhost", OBJECT(&s->sdhost.sdbus)); + + /* Mphi */ + sysbus_init_child_obj(obj, "mphi", &s->mphi, sizeof(s->mphi), + TYPE_BCM2835_MPHI); } static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) @@ -360,6 +364,19 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus"); + /* Mphi */ + object_property_set_bool(OBJECT(&s->mphi), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, MPHI_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mphi), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->mphi), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, + INTERRUPT_HOSTPORT)); + create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40); create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000); create_unimp(s, &s->a2w, "bcm2835-a2w", A2W_OFFSET, 0x1000); diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index b25181b711..60a9d80b74 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -56,6 +56,7 @@ common-obj-$(CONFIG_OMAP) += omap_l4.o common-obj-$(CONFIG_OMAP) += omap_sdrc.o common-obj-$(CONFIG_OMAP) += omap_tap.o common-obj-$(CONFIG_RASPI) += bcm2835_mbox.o +common-obj-$(CONFIG_RASPI) += bcm2835_mphi.o common-obj-$(CONFIG_RASPI) += bcm2835_property.o common-obj-$(CONFIG_RASPI) += bcm2835_rng.o common-obj-$(CONFIG_RASPI) += bcm2835_thermal.o diff --git a/hw/misc/bcm2835_mphi.c b/hw/misc/bcm2835_mphi.c new file mode 100644 index 0000000000..0428e10ba5 --- /dev/null +++ b/hw/misc/bcm2835_mphi.c @@ -0,0 +1,191 @@ +/* + * BCM2835 SOC MPHI emulation + * + * Very basic emulation, only providing the FIQ interrupt needed to + * allow the dwc-otg USB host controller driver in the Raspbian kernel + * to function. + * + * Copyright (c) 2020 Paul Zimmerman + * + * 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. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/misc/bcm2835_mphi.h" +#include "migration/vmstate.h" +#include "qemu/error-report.h" +#include "qemu/log.h" +#include "qemu/main-loop.h" + +static inline void mphi_raise_irq(BCM2835MphiState *s) +{ + qemu_set_irq(s->irq, 1); +} + +static inline void mphi_lower_irq(BCM2835MphiState *s) +{ + qemu_set_irq(s->irq, 0); +} + +static uint64_t mphi_reg_read(void *ptr, hwaddr addr, unsigned size) +{ + BCM2835MphiState *s = ptr; + uint32_t val = 0; + + switch (addr) { + case 0x28: /* outdda */ + val = s->outdda; + break; + case 0x2c: /* outddb */ + val = s->outddb; + break; + case 0x4c: /* ctrl */ + val = s->ctrl; + val |= 1 << 17; + break; + case 0x50: /* intstat */ + val = s->intstat; + break; + case 0x1f0: /* swirq_set */ + val = s->swirq; + break; + case 0x1f4: /* swirq_clr */ + val = s->swirq; + break; + default: + qemu_log_mask(LOG_UNIMP, "read from unknown register"); + break; + } + + return val; +} + +static void mphi_reg_write(void *ptr, hwaddr addr, uint64_t val, unsigned size) +{ + BCM2835MphiState *s = ptr; + int do_irq = 0; + + switch (addr) { + case 0x28: /* outdda */ + s->outdda = val; + break; + case 0x2c: /* outddb */ + s->outddb = val; + if (val & (1 << 29)) { + do_irq = 1; + } + break; + case 0x4c: /* ctrl */ + s->ctrl = val; + if (val & (1 << 16)) { + do_irq = -1; + } + break; + case 0x50: /* intstat */ + s->intstat = val; + if (val & ((1 << 16) | (1 << 29))) { + do_irq = -1; + } + break; + case 0x1f0: /* swirq_set */ + s->swirq |= val; + do_irq = 1; + break; + case 0x1f4: /* swirq_clr */ + s->swirq &= ~val; + do_irq = -1; + break; + default: + qemu_log_mask(LOG_UNIMP, "write to unknown register"); + return; + } + + if (do_irq > 0) { + mphi_raise_irq(s); + } else if (do_irq < 0) { + mphi_lower_irq(s); + } +} + +static const MemoryRegionOps mphi_mmio_ops = { + .read = mphi_reg_read, + .write = mphi_reg_write, + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void mphi_reset(DeviceState *dev) +{ + BCM2835MphiState *s = BCM2835_MPHI(dev); + + s->outdda = 0; + s->outddb = 0; + s->ctrl = 0; + s->intstat = 0; + s->swirq = 0; +} + +static void mphi_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + BCM2835MphiState *s = BCM2835_MPHI(dev); + + sysbus_init_irq(sbd, &s->irq); +} + +static void mphi_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + BCM2835MphiState *s = BCM2835_MPHI(obj); + + memory_region_init_io(&s->iomem, obj, &mphi_mmio_ops, s, "mphi", MPHI_MMIO_SIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +const VMStateDescription vmstate_mphi_state = { + .name = "mphi", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(outdda, BCM2835MphiState), + VMSTATE_UINT32(outddb, BCM2835MphiState), + VMSTATE_UINT32(ctrl, BCM2835MphiState), + VMSTATE_UINT32(intstat, BCM2835MphiState), + VMSTATE_UINT32(swirq, BCM2835MphiState), + VMSTATE_END_OF_LIST() + } +}; + +static void mphi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = mphi_realize; + dc->reset = mphi_reset; + dc->vmsd = &vmstate_mphi_state; +} + +static const TypeInfo bcm2835_mphi_type_info = { + .name = TYPE_BCM2835_MPHI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835MphiState), + .instance_init = mphi_init, + .class_init = mphi_class_init, +}; + +static void bcm2835_mphi_register_types(void) +{ + type_register_static(&bcm2835_mphi_type_info); +} + +type_init(bcm2835_mphi_register_types) diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h index 2e8655a7c2..7a7a8f6141 100644 --- a/include/hw/arm/bcm2835_peripherals.h +++ b/include/hw/arm/bcm2835_peripherals.h @@ -21,6 +21,7 @@ #include "hw/misc/bcm2835_property.h" #include "hw/misc/bcm2835_rng.h" #include "hw/misc/bcm2835_mbox.h" +#include "hw/misc/bcm2835_mphi.h" #include "hw/misc/bcm2835_thermal.h" #include "hw/sd/sdhci.h" #include "hw/sd/bcm2835_sdhost.h" @@ -42,6 +43,7 @@ typedef struct BCM2835PeripheralState { qemu_irq irq, fiq; BCM2835SystemTimerState systmr; + BCM2835MphiState mphi; UnimplementedDeviceState armtmr; UnimplementedDeviceState cprman; UnimplementedDeviceState a2w; diff --git a/include/hw/misc/bcm2835_mphi.h b/include/hw/misc/bcm2835_mphi.h new file mode 100644 index 0000000000..e084314d0f --- /dev/null +++ b/include/hw/misc/bcm2835_mphi.h @@ -0,0 +1,44 @@ +/* + * BCM2835 SOC MPHI state definitions + * + * Copyright (c) 2020 Paul Zimmerman + * + * 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. + */ + +#ifndef HW_MISC_BCM2835_MPHI_H +#define HW_MISC_BCM2835_MPHI_H + +#include "hw/irq.h" +#include "hw/sysbus.h" + +#define MPHI_MMIO_SIZE 0x1000 + +typedef struct BCM2835MphiState BCM2835MphiState; + +struct BCM2835MphiState { + SysBusDevice parent_obj; + qemu_irq irq; + MemoryRegion iomem; + + uint32_t outdda; + uint32_t outddb; + uint32_t ctrl; + uint32_t intstat; + uint32_t swirq; +}; + +#define TYPE_BCM2835_MPHI "bcm2835-mphi" + +#define BCM2835_MPHI(obj) \ + OBJECT_CHECK(BCM2835MphiState, (obj), TYPE_BCM2835_MPHI) + +#endif From 3f5b312a3f9faf2e20a700be70d921e26220a0fe Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Wed, 20 May 2020 16:53:44 -0700 Subject: [PATCH 0866/2595] dwc-hsotg (dwc2) USB host controller register definitions Import the dwc-hsotg (dwc2) register definitions file from the Linux kernel. This is a copy of drivers/usb/dwc2/hw.h from the mainline Linux kernel, the only changes being to the header, and two instances of 'u32' changed to 'uint32_t' to allow it to compile. Checkpatch throws a boatload of errors due to the tab indentation, but I would rather import it as-is than reformat it. Signed-off-by: Paul Zimmerman Message-id: 20200520235349.21215-3-pauldzim@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- include/hw/usb/dwc2-regs.h | 899 +++++++++++++++++++++++++++++++++++++ 1 file changed, 899 insertions(+) create mode 100644 include/hw/usb/dwc2-regs.h diff --git a/include/hw/usb/dwc2-regs.h b/include/hw/usb/dwc2-regs.h new file mode 100644 index 0000000000..40af23a0ba --- /dev/null +++ b/include/hw/usb/dwc2-regs.h @@ -0,0 +1,899 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Imported from the Linux kernel file drivers/usb/dwc2/hw.h, commit + * a89bae709b3492b478480a2c9734e7e9393b279c ("usb: dwc2: Move + * UTMI_PHY_DATA defines closer") + * + * hw.h - DesignWare HS OTG Controller hardware definitions + * + * Copyright 2004-2013 Synopsys, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DWC2_HW_H__ +#define __DWC2_HW_H__ + +#define HSOTG_REG(x) (x) + +#define GOTGCTL HSOTG_REG(0x000) +#define GOTGCTL_CHIRPEN BIT(27) +#define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22) +#define GOTGCTL_MULT_VALID_BC_SHIFT 22 +#define GOTGCTL_OTGVER BIT(20) +#define GOTGCTL_BSESVLD BIT(19) +#define GOTGCTL_ASESVLD BIT(18) +#define GOTGCTL_DBNC_SHORT BIT(17) +#define GOTGCTL_CONID_B BIT(16) +#define GOTGCTL_DBNCE_FLTR_BYPASS BIT(15) +#define GOTGCTL_DEVHNPEN BIT(11) +#define GOTGCTL_HSTSETHNPEN BIT(10) +#define GOTGCTL_HNPREQ BIT(9) +#define GOTGCTL_HSTNEGSCS BIT(8) +#define GOTGCTL_SESREQ BIT(1) +#define GOTGCTL_SESREQSCS BIT(0) + +#define GOTGINT HSOTG_REG(0x004) +#define GOTGINT_DBNCE_DONE BIT(19) +#define GOTGINT_A_DEV_TOUT_CHG BIT(18) +#define GOTGINT_HST_NEG_DET BIT(17) +#define GOTGINT_HST_NEG_SUC_STS_CHNG BIT(9) +#define GOTGINT_SES_REQ_SUC_STS_CHNG BIT(8) +#define GOTGINT_SES_END_DET BIT(2) + +#define GAHBCFG HSOTG_REG(0x008) +#define GAHBCFG_AHB_SINGLE BIT(23) +#define GAHBCFG_NOTI_ALL_DMA_WRIT BIT(22) +#define GAHBCFG_REM_MEM_SUPP BIT(21) +#define GAHBCFG_P_TXF_EMP_LVL BIT(8) +#define GAHBCFG_NP_TXF_EMP_LVL BIT(7) +#define GAHBCFG_DMA_EN BIT(5) +#define GAHBCFG_HBSTLEN_MASK (0xf << 1) +#define GAHBCFG_HBSTLEN_SHIFT 1 +#define GAHBCFG_HBSTLEN_SINGLE 0 +#define GAHBCFG_HBSTLEN_INCR 1 +#define GAHBCFG_HBSTLEN_INCR4 3 +#define GAHBCFG_HBSTLEN_INCR8 5 +#define GAHBCFG_HBSTLEN_INCR16 7 +#define GAHBCFG_GLBL_INTR_EN BIT(0) +#define GAHBCFG_CTRL_MASK (GAHBCFG_P_TXF_EMP_LVL | \ + GAHBCFG_NP_TXF_EMP_LVL | \ + GAHBCFG_DMA_EN | \ + GAHBCFG_GLBL_INTR_EN) + +#define GUSBCFG HSOTG_REG(0x00C) +#define GUSBCFG_FORCEDEVMODE BIT(30) +#define GUSBCFG_FORCEHOSTMODE BIT(29) +#define GUSBCFG_TXENDDELAY BIT(28) +#define GUSBCFG_ICTRAFFICPULLREMOVE BIT(27) +#define GUSBCFG_ICUSBCAP BIT(26) +#define GUSBCFG_ULPI_INT_PROT_DIS BIT(25) +#define GUSBCFG_INDICATORPASSTHROUGH BIT(24) +#define GUSBCFG_INDICATORCOMPLEMENT BIT(23) +#define GUSBCFG_TERMSELDLPULSE BIT(22) +#define GUSBCFG_ULPI_INT_VBUS_IND BIT(21) +#define GUSBCFG_ULPI_EXT_VBUS_DRV BIT(20) +#define GUSBCFG_ULPI_CLK_SUSP_M BIT(19) +#define GUSBCFG_ULPI_AUTO_RES BIT(18) +#define GUSBCFG_ULPI_FS_LS BIT(17) +#define GUSBCFG_OTG_UTMI_FS_SEL BIT(16) +#define GUSBCFG_PHY_LP_CLK_SEL BIT(15) +#define GUSBCFG_USBTRDTIM_MASK (0xf << 10) +#define GUSBCFG_USBTRDTIM_SHIFT 10 +#define GUSBCFG_HNPCAP BIT(9) +#define GUSBCFG_SRPCAP BIT(8) +#define GUSBCFG_DDRSEL BIT(7) +#define GUSBCFG_PHYSEL BIT(6) +#define GUSBCFG_FSINTF BIT(5) +#define GUSBCFG_ULPI_UTMI_SEL BIT(4) +#define GUSBCFG_PHYIF16 BIT(3) +#define GUSBCFG_PHYIF8 (0 << 3) +#define GUSBCFG_TOUTCAL_MASK (0x7 << 0) +#define GUSBCFG_TOUTCAL_SHIFT 0 +#define GUSBCFG_TOUTCAL_LIMIT 0x7 +#define GUSBCFG_TOUTCAL(_x) ((_x) << 0) + +#define GRSTCTL HSOTG_REG(0x010) +#define GRSTCTL_AHBIDLE BIT(31) +#define GRSTCTL_DMAREQ BIT(30) +#define GRSTCTL_TXFNUM_MASK (0x1f << 6) +#define GRSTCTL_TXFNUM_SHIFT 6 +#define GRSTCTL_TXFNUM_LIMIT 0x1f +#define GRSTCTL_TXFNUM(_x) ((_x) << 6) +#define GRSTCTL_TXFFLSH BIT(5) +#define GRSTCTL_RXFFLSH BIT(4) +#define GRSTCTL_IN_TKNQ_FLSH BIT(3) +#define GRSTCTL_FRMCNTRRST BIT(2) +#define GRSTCTL_HSFTRST BIT(1) +#define GRSTCTL_CSFTRST BIT(0) + +#define GINTSTS HSOTG_REG(0x014) +#define GINTMSK HSOTG_REG(0x018) +#define GINTSTS_WKUPINT BIT(31) +#define GINTSTS_SESSREQINT BIT(30) +#define GINTSTS_DISCONNINT BIT(29) +#define GINTSTS_CONIDSTSCHNG BIT(28) +#define GINTSTS_LPMTRANRCVD BIT(27) +#define GINTSTS_PTXFEMP BIT(26) +#define GINTSTS_HCHINT BIT(25) +#define GINTSTS_PRTINT BIT(24) +#define GINTSTS_RESETDET BIT(23) +#define GINTSTS_FET_SUSP BIT(22) +#define GINTSTS_INCOMPL_IP BIT(21) +#define GINTSTS_INCOMPL_SOOUT BIT(21) +#define GINTSTS_INCOMPL_SOIN BIT(20) +#define GINTSTS_OEPINT BIT(19) +#define GINTSTS_IEPINT BIT(18) +#define GINTSTS_EPMIS BIT(17) +#define GINTSTS_RESTOREDONE BIT(16) +#define GINTSTS_EOPF BIT(15) +#define GINTSTS_ISOUTDROP BIT(14) +#define GINTSTS_ENUMDONE BIT(13) +#define GINTSTS_USBRST BIT(12) +#define GINTSTS_USBSUSP BIT(11) +#define GINTSTS_ERLYSUSP BIT(10) +#define GINTSTS_I2CINT BIT(9) +#define GINTSTS_ULPI_CK_INT BIT(8) +#define GINTSTS_GOUTNAKEFF BIT(7) +#define GINTSTS_GINNAKEFF BIT(6) +#define GINTSTS_NPTXFEMP BIT(5) +#define GINTSTS_RXFLVL BIT(4) +#define GINTSTS_SOF BIT(3) +#define GINTSTS_OTGINT BIT(2) +#define GINTSTS_MODEMIS BIT(1) +#define GINTSTS_CURMODE_HOST BIT(0) + +#define GRXSTSR HSOTG_REG(0x01C) +#define GRXSTSP HSOTG_REG(0x020) +#define GRXSTS_FN_MASK (0x7f << 25) +#define GRXSTS_FN_SHIFT 25 +#define GRXSTS_PKTSTS_MASK (0xf << 17) +#define GRXSTS_PKTSTS_SHIFT 17 +#define GRXSTS_PKTSTS_GLOBALOUTNAK 1 +#define GRXSTS_PKTSTS_OUTRX 2 +#define GRXSTS_PKTSTS_HCHIN 2 +#define GRXSTS_PKTSTS_OUTDONE 3 +#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3 +#define GRXSTS_PKTSTS_SETUPDONE 4 +#define GRXSTS_PKTSTS_DATATOGGLEERR 5 +#define GRXSTS_PKTSTS_SETUPRX 6 +#define GRXSTS_PKTSTS_HCHHALTED 7 +#define GRXSTS_HCHNUM_MASK (0xf << 0) +#define GRXSTS_HCHNUM_SHIFT 0 +#define GRXSTS_DPID_MASK (0x3 << 15) +#define GRXSTS_DPID_SHIFT 15 +#define GRXSTS_BYTECNT_MASK (0x7ff << 4) +#define GRXSTS_BYTECNT_SHIFT 4 +#define GRXSTS_EPNUM_MASK (0xf << 0) +#define GRXSTS_EPNUM_SHIFT 0 + +#define GRXFSIZ HSOTG_REG(0x024) +#define GRXFSIZ_DEPTH_MASK (0xffff << 0) +#define GRXFSIZ_DEPTH_SHIFT 0 + +#define GNPTXFSIZ HSOTG_REG(0x028) +/* Use FIFOSIZE_* constants to access this register */ + +#define GNPTXSTS HSOTG_REG(0x02C) +#define GNPTXSTS_NP_TXQ_TOP_MASK (0x7f << 24) +#define GNPTXSTS_NP_TXQ_TOP_SHIFT 24 +#define GNPTXSTS_NP_TXQ_SPC_AVAIL_MASK (0xff << 16) +#define GNPTXSTS_NP_TXQ_SPC_AVAIL_SHIFT 16 +#define GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(_v) (((_v) >> 16) & 0xff) +#define GNPTXSTS_NP_TXF_SPC_AVAIL_MASK (0xffff << 0) +#define GNPTXSTS_NP_TXF_SPC_AVAIL_SHIFT 0 +#define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v) (((_v) >> 0) & 0xffff) + +#define GI2CCTL HSOTG_REG(0x0030) +#define GI2CCTL_BSYDNE BIT(31) +#define GI2CCTL_RW BIT(30) +#define GI2CCTL_I2CDATSE0 BIT(28) +#define GI2CCTL_I2CDEVADDR_MASK (0x3 << 26) +#define GI2CCTL_I2CDEVADDR_SHIFT 26 +#define GI2CCTL_I2CSUSPCTL BIT(25) +#define GI2CCTL_ACK BIT(24) +#define GI2CCTL_I2CEN BIT(23) +#define GI2CCTL_ADDR_MASK (0x7f << 16) +#define GI2CCTL_ADDR_SHIFT 16 +#define GI2CCTL_REGADDR_MASK (0xff << 8) +#define GI2CCTL_REGADDR_SHIFT 8 +#define GI2CCTL_RWDATA_MASK (0xff << 0) +#define GI2CCTL_RWDATA_SHIFT 0 + +#define GPVNDCTL HSOTG_REG(0x0034) +#define GGPIO HSOTG_REG(0x0038) +#define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16) + +#define GUID HSOTG_REG(0x003c) +#define GSNPSID HSOTG_REG(0x0040) +#define GHWCFG1 HSOTG_REG(0x0044) +#define GSNPSID_ID_MASK GENMASK(31, 16) + +#define GHWCFG2 HSOTG_REG(0x0048) +#define GHWCFG2_OTG_ENABLE_IC_USB BIT(31) +#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK (0x1f << 26) +#define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT 26 +#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK (0x3 << 24) +#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT 24 +#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK (0x3 << 22) +#define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT 22 +#define GHWCFG2_MULTI_PROC_INT BIT(20) +#define GHWCFG2_DYNAMIC_FIFO BIT(19) +#define GHWCFG2_PERIO_EP_SUPPORTED BIT(18) +#define GHWCFG2_NUM_HOST_CHAN_MASK (0xf << 14) +#define GHWCFG2_NUM_HOST_CHAN_SHIFT 14 +#define GHWCFG2_NUM_DEV_EP_MASK (0xf << 10) +#define GHWCFG2_NUM_DEV_EP_SHIFT 10 +#define GHWCFG2_FS_PHY_TYPE_MASK (0x3 << 8) +#define GHWCFG2_FS_PHY_TYPE_SHIFT 8 +#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED 0 +#define GHWCFG2_FS_PHY_TYPE_DEDICATED 1 +#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI 2 +#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI 3 +#define GHWCFG2_HS_PHY_TYPE_MASK (0x3 << 6) +#define GHWCFG2_HS_PHY_TYPE_SHIFT 6 +#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 +#define GHWCFG2_HS_PHY_TYPE_UTMI 1 +#define GHWCFG2_HS_PHY_TYPE_ULPI 2 +#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 +#define GHWCFG2_POINT2POINT BIT(5) +#define GHWCFG2_ARCHITECTURE_MASK (0x3 << 3) +#define GHWCFG2_ARCHITECTURE_SHIFT 3 +#define GHWCFG2_SLAVE_ONLY_ARCH 0 +#define GHWCFG2_EXT_DMA_ARCH 1 +#define GHWCFG2_INT_DMA_ARCH 2 +#define GHWCFG2_OP_MODE_MASK (0x7 << 0) +#define GHWCFG2_OP_MODE_SHIFT 0 +#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE 0 +#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE 1 +#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE 2 +#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 +#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 +#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 +#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 +#define GHWCFG2_OP_MODE_UNDEFINED 7 + +#define GHWCFG3 HSOTG_REG(0x004c) +#define GHWCFG3_DFIFO_DEPTH_MASK (0xffff << 16) +#define GHWCFG3_DFIFO_DEPTH_SHIFT 16 +#define GHWCFG3_OTG_LPM_EN BIT(15) +#define GHWCFG3_BC_SUPPORT BIT(14) +#define GHWCFG3_OTG_ENABLE_HSIC BIT(13) +#define GHWCFG3_ADP_SUPP BIT(12) +#define GHWCFG3_SYNCH_RESET_TYPE BIT(11) +#define GHWCFG3_OPTIONAL_FEATURES BIT(10) +#define GHWCFG3_VENDOR_CTRL_IF BIT(9) +#define GHWCFG3_I2C BIT(8) +#define GHWCFG3_OTG_FUNC BIT(7) +#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK (0x7 << 4) +#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT 4 +#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK (0xf << 0) +#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT 0 + +#define GHWCFG4 HSOTG_REG(0x0050) +#define GHWCFG4_DESC_DMA_DYN BIT(31) +#define GHWCFG4_DESC_DMA BIT(30) +#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26) +#define GHWCFG4_NUM_IN_EPS_SHIFT 26 +#define GHWCFG4_DED_FIFO_EN BIT(25) +#define GHWCFG4_DED_FIFO_SHIFT 25 +#define GHWCFG4_SESSION_END_FILT_EN BIT(24) +#define GHWCFG4_B_VALID_FILT_EN BIT(23) +#define GHWCFG4_A_VALID_FILT_EN BIT(22) +#define GHWCFG4_VBUS_VALID_FILT_EN BIT(21) +#define GHWCFG4_IDDIG_FILT_EN BIT(20) +#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK (0xf << 16) +#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14) +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 +#define GHWCFG4_ACG_SUPPORTED BIT(12) +#define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11) +#define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10) +#define GHWCFG4_XHIBER BIT(7) +#define GHWCFG4_HIBER BIT(6) +#define GHWCFG4_MIN_AHB_FREQ BIT(5) +#define GHWCFG4_POWER_OPTIMIZ BIT(4) +#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK (0xf << 0) +#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT 0 + +#define GLPMCFG HSOTG_REG(0x0054) +#define GLPMCFG_INVSELHSIC BIT(31) +#define GLPMCFG_HSICCON BIT(30) +#define GLPMCFG_RSTRSLPSTS BIT(29) +#define GLPMCFG_ENBESL BIT(28) +#define GLPMCFG_LPM_RETRYCNT_STS_MASK (0x7 << 25) +#define GLPMCFG_LPM_RETRYCNT_STS_SHIFT 25 +#define GLPMCFG_SNDLPM BIT(24) +#define GLPMCFG_RETRY_CNT_MASK (0x7 << 21) +#define GLPMCFG_RETRY_CNT_SHIFT 21 +#define GLPMCFG_LPM_REJECT_CTRL_CONTROL BIT(21) +#define GLPMCFG_LPM_ACCEPT_CTRL_ISOC BIT(22) +#define GLPMCFG_LPM_CHNL_INDX_MASK (0xf << 17) +#define GLPMCFG_LPM_CHNL_INDX_SHIFT 17 +#define GLPMCFG_L1RESUMEOK BIT(16) +#define GLPMCFG_SLPSTS BIT(15) +#define GLPMCFG_COREL1RES_MASK (0x3 << 13) +#define GLPMCFG_COREL1RES_SHIFT 13 +#define GLPMCFG_HIRD_THRES_MASK (0x1f << 8) +#define GLPMCFG_HIRD_THRES_SHIFT 8 +#define GLPMCFG_HIRD_THRES_EN (0x10 << 8) +#define GLPMCFG_ENBLSLPM BIT(7) +#define GLPMCFG_BREMOTEWAKE BIT(6) +#define GLPMCFG_HIRD_MASK (0xf << 2) +#define GLPMCFG_HIRD_SHIFT 2 +#define GLPMCFG_APPL1RES BIT(1) +#define GLPMCFG_LPMCAP BIT(0) + +#define GPWRDN HSOTG_REG(0x0058) +#define GPWRDN_MULT_VAL_ID_BC_MASK (0x1f << 24) +#define GPWRDN_MULT_VAL_ID_BC_SHIFT 24 +#define GPWRDN_ADP_INT BIT(23) +#define GPWRDN_BSESSVLD BIT(22) +#define GPWRDN_IDSTS BIT(21) +#define GPWRDN_LINESTATE_MASK (0x3 << 19) +#define GPWRDN_LINESTATE_SHIFT 19 +#define GPWRDN_STS_CHGINT_MSK BIT(18) +#define GPWRDN_STS_CHGINT BIT(17) +#define GPWRDN_SRP_DET_MSK BIT(16) +#define GPWRDN_SRP_DET BIT(15) +#define GPWRDN_CONNECT_DET_MSK BIT(14) +#define GPWRDN_CONNECT_DET BIT(13) +#define GPWRDN_DISCONN_DET_MSK BIT(12) +#define GPWRDN_DISCONN_DET BIT(11) +#define GPWRDN_RST_DET_MSK BIT(10) +#define GPWRDN_RST_DET BIT(9) +#define GPWRDN_LNSTSCHG_MSK BIT(8) +#define GPWRDN_LNSTSCHG BIT(7) +#define GPWRDN_DIS_VBUS BIT(6) +#define GPWRDN_PWRDNSWTCH BIT(5) +#define GPWRDN_PWRDNRSTN BIT(4) +#define GPWRDN_PWRDNCLMP BIT(3) +#define GPWRDN_RESTORE BIT(2) +#define GPWRDN_PMUACTV BIT(1) +#define GPWRDN_PMUINTSEL BIT(0) + +#define GDFIFOCFG HSOTG_REG(0x005c) +#define GDFIFOCFG_EPINFOBASE_MASK (0xffff << 16) +#define GDFIFOCFG_EPINFOBASE_SHIFT 16 +#define GDFIFOCFG_GDFIFOCFG_MASK (0xffff << 0) +#define GDFIFOCFG_GDFIFOCFG_SHIFT 0 + +#define ADPCTL HSOTG_REG(0x0060) +#define ADPCTL_AR_MASK (0x3 << 27) +#define ADPCTL_AR_SHIFT 27 +#define ADPCTL_ADP_TMOUT_INT_MSK BIT(26) +#define ADPCTL_ADP_SNS_INT_MSK BIT(25) +#define ADPCTL_ADP_PRB_INT_MSK BIT(24) +#define ADPCTL_ADP_TMOUT_INT BIT(23) +#define ADPCTL_ADP_SNS_INT BIT(22) +#define ADPCTL_ADP_PRB_INT BIT(21) +#define ADPCTL_ADPENA BIT(20) +#define ADPCTL_ADPRES BIT(19) +#define ADPCTL_ENASNS BIT(18) +#define ADPCTL_ENAPRB BIT(17) +#define ADPCTL_RTIM_MASK (0x7ff << 6) +#define ADPCTL_RTIM_SHIFT 6 +#define ADPCTL_PRB_PER_MASK (0x3 << 4) +#define ADPCTL_PRB_PER_SHIFT 4 +#define ADPCTL_PRB_DELTA_MASK (0x3 << 2) +#define ADPCTL_PRB_DELTA_SHIFT 2 +#define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0) +#define ADPCTL_PRB_DSCHRG_SHIFT 0 + +#define GREFCLK HSOTG_REG(0x0064) +#define GREFCLK_REFCLKPER_MASK (0x1ffff << 15) +#define GREFCLK_REFCLKPER_SHIFT 15 +#define GREFCLK_REF_CLK_MODE BIT(14) +#define GREFCLK_SOF_CNT_WKUP_ALERT_MASK (0x3ff) +#define GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT 0 + +#define GINTMSK2 HSOTG_REG(0x0068) +#define GINTMSK2_WKUP_ALERT_INT_MSK BIT(0) + +#define GINTSTS2 HSOTG_REG(0x006c) +#define GINTSTS2_WKUP_ALERT_INT BIT(0) + +#define HPTXFSIZ HSOTG_REG(0x100) +/* Use FIFOSIZE_* constants to access this register */ + +#define DPTXFSIZN(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4)) +/* Use FIFOSIZE_* constants to access this register */ + +/* These apply to the GNPTXFSIZ, HPTXFSIZ and DPTXFSIZN registers */ +#define FIFOSIZE_DEPTH_MASK (0xffff << 16) +#define FIFOSIZE_DEPTH_SHIFT 16 +#define FIFOSIZE_STARTADDR_MASK (0xffff << 0) +#define FIFOSIZE_STARTADDR_SHIFT 0 +#define FIFOSIZE_DEPTH_GET(_x) (((_x) >> 16) & 0xffff) + +/* Device mode registers */ + +#define DCFG HSOTG_REG(0x800) +#define DCFG_DESCDMA_EN BIT(23) +#define DCFG_EPMISCNT_MASK (0x1f << 18) +#define DCFG_EPMISCNT_SHIFT 18 +#define DCFG_EPMISCNT_LIMIT 0x1f +#define DCFG_EPMISCNT(_x) ((_x) << 18) +#define DCFG_IPG_ISOC_SUPPORDED BIT(17) +#define DCFG_PERFRINT_MASK (0x3 << 11) +#define DCFG_PERFRINT_SHIFT 11 +#define DCFG_PERFRINT_LIMIT 0x3 +#define DCFG_PERFRINT(_x) ((_x) << 11) +#define DCFG_DEVADDR_MASK (0x7f << 4) +#define DCFG_DEVADDR_SHIFT 4 +#define DCFG_DEVADDR_LIMIT 0x7f +#define DCFG_DEVADDR(_x) ((_x) << 4) +#define DCFG_NZ_STS_OUT_HSHK BIT(2) +#define DCFG_DEVSPD_MASK (0x3 << 0) +#define DCFG_DEVSPD_SHIFT 0 +#define DCFG_DEVSPD_HS 0 +#define DCFG_DEVSPD_FS 1 +#define DCFG_DEVSPD_LS 2 +#define DCFG_DEVSPD_FS48 3 + +#define DCTL HSOTG_REG(0x804) +#define DCTL_SERVICE_INTERVAL_SUPPORTED BIT(19) +#define DCTL_PWRONPRGDONE BIT(11) +#define DCTL_CGOUTNAK BIT(10) +#define DCTL_SGOUTNAK BIT(9) +#define DCTL_CGNPINNAK BIT(8) +#define DCTL_SGNPINNAK BIT(7) +#define DCTL_TSTCTL_MASK (0x7 << 4) +#define DCTL_TSTCTL_SHIFT 4 +#define DCTL_GOUTNAKSTS BIT(3) +#define DCTL_GNPINNAKSTS BIT(2) +#define DCTL_SFTDISCON BIT(1) +#define DCTL_RMTWKUPSIG BIT(0) + +#define DSTS HSOTG_REG(0x808) +#define DSTS_SOFFN_MASK (0x3fff << 8) +#define DSTS_SOFFN_SHIFT 8 +#define DSTS_SOFFN_LIMIT 0x3fff +#define DSTS_SOFFN(_x) ((_x) << 8) +#define DSTS_ERRATICERR BIT(3) +#define DSTS_ENUMSPD_MASK (0x3 << 1) +#define DSTS_ENUMSPD_SHIFT 1 +#define DSTS_ENUMSPD_HS 0 +#define DSTS_ENUMSPD_FS 1 +#define DSTS_ENUMSPD_LS 2 +#define DSTS_ENUMSPD_FS48 3 +#define DSTS_SUSPSTS BIT(0) + +#define DIEPMSK HSOTG_REG(0x810) +#define DIEPMSK_NAKMSK BIT(13) +#define DIEPMSK_BNAININTRMSK BIT(9) +#define DIEPMSK_TXFIFOUNDRNMSK BIT(8) +#define DIEPMSK_TXFIFOEMPTY BIT(7) +#define DIEPMSK_INEPNAKEFFMSK BIT(6) +#define DIEPMSK_INTKNEPMISMSK BIT(5) +#define DIEPMSK_INTKNTXFEMPMSK BIT(4) +#define DIEPMSK_TIMEOUTMSK BIT(3) +#define DIEPMSK_AHBERRMSK BIT(2) +#define DIEPMSK_EPDISBLDMSK BIT(1) +#define DIEPMSK_XFERCOMPLMSK BIT(0) + +#define DOEPMSK HSOTG_REG(0x814) +#define DOEPMSK_BNAMSK BIT(9) +#define DOEPMSK_BACK2BACKSETUP BIT(6) +#define DOEPMSK_STSPHSERCVDMSK BIT(5) +#define DOEPMSK_OUTTKNEPDISMSK BIT(4) +#define DOEPMSK_SETUPMSK BIT(3) +#define DOEPMSK_AHBERRMSK BIT(2) +#define DOEPMSK_EPDISBLDMSK BIT(1) +#define DOEPMSK_XFERCOMPLMSK BIT(0) + +#define DAINT HSOTG_REG(0x818) +#define DAINTMSK HSOTG_REG(0x81C) +#define DAINT_OUTEP_SHIFT 16 +#define DAINT_OUTEP(_x) (1 << ((_x) + 16)) +#define DAINT_INEP(_x) (1 << (_x)) + +#define DTKNQR1 HSOTG_REG(0x820) +#define DTKNQR2 HSOTG_REG(0x824) +#define DTKNQR3 HSOTG_REG(0x830) +#define DTKNQR4 HSOTG_REG(0x834) +#define DIEPEMPMSK HSOTG_REG(0x834) + +#define DVBUSDIS HSOTG_REG(0x828) +#define DVBUSPULSE HSOTG_REG(0x82C) + +#define DIEPCTL0 HSOTG_REG(0x900) +#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20)) + +#define DOEPCTL0 HSOTG_REG(0xB00) +#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20)) + +/* EP0 specialness: + * bits[29..28] - reserved (no SetD0PID, SetD1PID) + * bits[25..22] - should always be zero, this isn't a periodic endpoint + * bits[10..0] - MPS setting different for EP0 + */ +#define D0EPCTL_MPS_MASK (0x3 << 0) +#define D0EPCTL_MPS_SHIFT 0 +#define D0EPCTL_MPS_64 0 +#define D0EPCTL_MPS_32 1 +#define D0EPCTL_MPS_16 2 +#define D0EPCTL_MPS_8 3 + +#define DXEPCTL_EPENA BIT(31) +#define DXEPCTL_EPDIS BIT(30) +#define DXEPCTL_SETD1PID BIT(29) +#define DXEPCTL_SETODDFR BIT(29) +#define DXEPCTL_SETD0PID BIT(28) +#define DXEPCTL_SETEVENFR BIT(28) +#define DXEPCTL_SNAK BIT(27) +#define DXEPCTL_CNAK BIT(26) +#define DXEPCTL_TXFNUM_MASK (0xf << 22) +#define DXEPCTL_TXFNUM_SHIFT 22 +#define DXEPCTL_TXFNUM_LIMIT 0xf +#define DXEPCTL_TXFNUM(_x) ((_x) << 22) +#define DXEPCTL_STALL BIT(21) +#define DXEPCTL_SNP BIT(20) +#define DXEPCTL_EPTYPE_MASK (0x3 << 18) +#define DXEPCTL_EPTYPE_CONTROL (0x0 << 18) +#define DXEPCTL_EPTYPE_ISO (0x1 << 18) +#define DXEPCTL_EPTYPE_BULK (0x2 << 18) +#define DXEPCTL_EPTYPE_INTERRUPT (0x3 << 18) + +#define DXEPCTL_NAKSTS BIT(17) +#define DXEPCTL_DPID BIT(16) +#define DXEPCTL_EOFRNUM BIT(16) +#define DXEPCTL_USBACTEP BIT(15) +#define DXEPCTL_NEXTEP_MASK (0xf << 11) +#define DXEPCTL_NEXTEP_SHIFT 11 +#define DXEPCTL_NEXTEP_LIMIT 0xf +#define DXEPCTL_NEXTEP(_x) ((_x) << 11) +#define DXEPCTL_MPS_MASK (0x7ff << 0) +#define DXEPCTL_MPS_SHIFT 0 +#define DXEPCTL_MPS_LIMIT 0x7ff +#define DXEPCTL_MPS(_x) ((_x) << 0) + +#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20)) +#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20)) +#define DXEPINT_SETUP_RCVD BIT(15) +#define DXEPINT_NYETINTRPT BIT(14) +#define DXEPINT_NAKINTRPT BIT(13) +#define DXEPINT_BBLEERRINTRPT BIT(12) +#define DXEPINT_PKTDRPSTS BIT(11) +#define DXEPINT_BNAINTR BIT(9) +#define DXEPINT_TXFIFOUNDRN BIT(8) +#define DXEPINT_OUTPKTERR BIT(8) +#define DXEPINT_TXFEMP BIT(7) +#define DXEPINT_INEPNAKEFF BIT(6) +#define DXEPINT_BACK2BACKSETUP BIT(6) +#define DXEPINT_INTKNEPMIS BIT(5) +#define DXEPINT_STSPHSERCVD BIT(5) +#define DXEPINT_INTKNTXFEMP BIT(4) +#define DXEPINT_OUTTKNEPDIS BIT(4) +#define DXEPINT_TIMEOUT BIT(3) +#define DXEPINT_SETUP BIT(3) +#define DXEPINT_AHBERR BIT(2) +#define DXEPINT_EPDISBLD BIT(1) +#define DXEPINT_XFERCOMPL BIT(0) + +#define DIEPTSIZ0 HSOTG_REG(0x910) +#define DIEPTSIZ0_PKTCNT_MASK (0x3 << 19) +#define DIEPTSIZ0_PKTCNT_SHIFT 19 +#define DIEPTSIZ0_PKTCNT_LIMIT 0x3 +#define DIEPTSIZ0_PKTCNT(_x) ((_x) << 19) +#define DIEPTSIZ0_XFERSIZE_MASK (0x7f << 0) +#define DIEPTSIZ0_XFERSIZE_SHIFT 0 +#define DIEPTSIZ0_XFERSIZE_LIMIT 0x7f +#define DIEPTSIZ0_XFERSIZE(_x) ((_x) << 0) + +#define DOEPTSIZ0 HSOTG_REG(0xB10) +#define DOEPTSIZ0_SUPCNT_MASK (0x3 << 29) +#define DOEPTSIZ0_SUPCNT_SHIFT 29 +#define DOEPTSIZ0_SUPCNT_LIMIT 0x3 +#define DOEPTSIZ0_SUPCNT(_x) ((_x) << 29) +#define DOEPTSIZ0_PKTCNT BIT(19) +#define DOEPTSIZ0_XFERSIZE_MASK (0x7f << 0) +#define DOEPTSIZ0_XFERSIZE_SHIFT 0 + +#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20)) +#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20)) +#define DXEPTSIZ_MC_MASK (0x3 << 29) +#define DXEPTSIZ_MC_SHIFT 29 +#define DXEPTSIZ_MC_LIMIT 0x3 +#define DXEPTSIZ_MC(_x) ((_x) << 29) +#define DXEPTSIZ_PKTCNT_MASK (0x3ff << 19) +#define DXEPTSIZ_PKTCNT_SHIFT 19 +#define DXEPTSIZ_PKTCNT_LIMIT 0x3ff +#define DXEPTSIZ_PKTCNT_GET(_v) (((_v) >> 19) & 0x3ff) +#define DXEPTSIZ_PKTCNT(_x) ((_x) << 19) +#define DXEPTSIZ_XFERSIZE_MASK (0x7ffff << 0) +#define DXEPTSIZ_XFERSIZE_SHIFT 0 +#define DXEPTSIZ_XFERSIZE_LIMIT 0x7ffff +#define DXEPTSIZ_XFERSIZE_GET(_v) (((_v) >> 0) & 0x7ffff) +#define DXEPTSIZ_XFERSIZE(_x) ((_x) << 0) + +#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20)) +#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20)) + +#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20)) + +#define PCGCTL HSOTG_REG(0x0e00) +#define PCGCTL_IF_DEV_MODE BIT(31) +#define PCGCTL_P2HD_PRT_SPD_MASK (0x3 << 29) +#define PCGCTL_P2HD_PRT_SPD_SHIFT 29 +#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3 << 27) +#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27 +#define PCGCTL_MAC_DEV_ADDR_MASK (0x7f << 20) +#define PCGCTL_MAC_DEV_ADDR_SHIFT 20 +#define PCGCTL_MAX_TERMSEL BIT(19) +#define PCGCTL_MAX_XCVRSELECT_MASK (0x3 << 17) +#define PCGCTL_MAX_XCVRSELECT_SHIFT 17 +#define PCGCTL_PORT_POWER BIT(16) +#define PCGCTL_PRT_CLK_SEL_MASK (0x3 << 14) +#define PCGCTL_PRT_CLK_SEL_SHIFT 14 +#define PCGCTL_ESS_REG_RESTORED BIT(13) +#define PCGCTL_EXTND_HIBER_SWITCH BIT(12) +#define PCGCTL_EXTND_HIBER_PWRCLMP BIT(11) +#define PCGCTL_ENBL_EXTND_HIBER BIT(10) +#define PCGCTL_RESTOREMODE BIT(9) +#define PCGCTL_RESETAFTSUSP BIT(8) +#define PCGCTL_DEEP_SLEEP BIT(7) +#define PCGCTL_PHY_IN_SLEEP BIT(6) +#define PCGCTL_ENBL_SLEEP_GATING BIT(5) +#define PCGCTL_RSTPDWNMODULE BIT(3) +#define PCGCTL_PWRCLMP BIT(2) +#define PCGCTL_GATEHCLK BIT(1) +#define PCGCTL_STOPPCLK BIT(0) + +#define PCGCCTL1 HSOTG_REG(0xe04) +#define PCGCCTL1_TIMER (0x3 << 1) +#define PCGCCTL1_GATEEN BIT(0) + +#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000)) + +/* Host Mode Registers */ + +#define HCFG HSOTG_REG(0x0400) +#define HCFG_MODECHTIMEN BIT(31) +#define HCFG_PERSCHEDENA BIT(26) +#define HCFG_FRLISTEN_MASK (0x3 << 24) +#define HCFG_FRLISTEN_SHIFT 24 +#define HCFG_FRLISTEN_8 (0 << 24) +#define FRLISTEN_8_SIZE 8 +#define HCFG_FRLISTEN_16 BIT(24) +#define FRLISTEN_16_SIZE 16 +#define HCFG_FRLISTEN_32 (2 << 24) +#define FRLISTEN_32_SIZE 32 +#define HCFG_FRLISTEN_64 (3 << 24) +#define FRLISTEN_64_SIZE 64 +#define HCFG_DESCDMA BIT(23) +#define HCFG_RESVALID_MASK (0xff << 8) +#define HCFG_RESVALID_SHIFT 8 +#define HCFG_ENA32KHZ BIT(7) +#define HCFG_FSLSSUPP BIT(2) +#define HCFG_FSLSPCLKSEL_MASK (0x3 << 0) +#define HCFG_FSLSPCLKSEL_SHIFT 0 +#define HCFG_FSLSPCLKSEL_30_60_MHZ 0 +#define HCFG_FSLSPCLKSEL_48_MHZ 1 +#define HCFG_FSLSPCLKSEL_6_MHZ 2 + +#define HFIR HSOTG_REG(0x0404) +#define HFIR_FRINT_MASK (0xffff << 0) +#define HFIR_FRINT_SHIFT 0 +#define HFIR_RLDCTRL BIT(16) + +#define HFNUM HSOTG_REG(0x0408) +#define HFNUM_FRREM_MASK (0xffff << 16) +#define HFNUM_FRREM_SHIFT 16 +#define HFNUM_FRNUM_MASK (0xffff << 0) +#define HFNUM_FRNUM_SHIFT 0 +#define HFNUM_MAX_FRNUM 0x3fff + +#define HPTXSTS HSOTG_REG(0x0410) +#define TXSTS_QTOP_ODD BIT(31) +#define TXSTS_QTOP_CHNEP_MASK (0xf << 27) +#define TXSTS_QTOP_CHNEP_SHIFT 27 +#define TXSTS_QTOP_TOKEN_MASK (0x3 << 25) +#define TXSTS_QTOP_TOKEN_SHIFT 25 +#define TXSTS_QTOP_TERMINATE BIT(24) +#define TXSTS_QSPCAVAIL_MASK (0xff << 16) +#define TXSTS_QSPCAVAIL_SHIFT 16 +#define TXSTS_FSPCAVAIL_MASK (0xffff << 0) +#define TXSTS_FSPCAVAIL_SHIFT 0 + +#define HAINT HSOTG_REG(0x0414) +#define HAINTMSK HSOTG_REG(0x0418) +#define HFLBADDR HSOTG_REG(0x041c) + +#define HPRT0 HSOTG_REG(0x0440) +#define HPRT0_SPD_MASK (0x3 << 17) +#define HPRT0_SPD_SHIFT 17 +#define HPRT0_SPD_HIGH_SPEED 0 +#define HPRT0_SPD_FULL_SPEED 1 +#define HPRT0_SPD_LOW_SPEED 2 +#define HPRT0_TSTCTL_MASK (0xf << 13) +#define HPRT0_TSTCTL_SHIFT 13 +#define HPRT0_PWR BIT(12) +#define HPRT0_LNSTS_MASK (0x3 << 10) +#define HPRT0_LNSTS_SHIFT 10 +#define HPRT0_RST BIT(8) +#define HPRT0_SUSP BIT(7) +#define HPRT0_RES BIT(6) +#define HPRT0_OVRCURRCHG BIT(5) +#define HPRT0_OVRCURRACT BIT(4) +#define HPRT0_ENACHG BIT(3) +#define HPRT0_ENA BIT(2) +#define HPRT0_CONNDET BIT(1) +#define HPRT0_CONNSTS BIT(0) + +#define HCCHAR(_ch) HSOTG_REG(0x0500 + 0x20 * (_ch)) +#define HCCHAR_CHENA BIT(31) +#define HCCHAR_CHDIS BIT(30) +#define HCCHAR_ODDFRM BIT(29) +#define HCCHAR_DEVADDR_MASK (0x7f << 22) +#define HCCHAR_DEVADDR_SHIFT 22 +#define HCCHAR_MULTICNT_MASK (0x3 << 20) +#define HCCHAR_MULTICNT_SHIFT 20 +#define HCCHAR_EPTYPE_MASK (0x3 << 18) +#define HCCHAR_EPTYPE_SHIFT 18 +#define HCCHAR_LSPDDEV BIT(17) +#define HCCHAR_EPDIR BIT(15) +#define HCCHAR_EPNUM_MASK (0xf << 11) +#define HCCHAR_EPNUM_SHIFT 11 +#define HCCHAR_MPS_MASK (0x7ff << 0) +#define HCCHAR_MPS_SHIFT 0 + +#define HCSPLT(_ch) HSOTG_REG(0x0504 + 0x20 * (_ch)) +#define HCSPLT_SPLTENA BIT(31) +#define HCSPLT_COMPSPLT BIT(16) +#define HCSPLT_XACTPOS_MASK (0x3 << 14) +#define HCSPLT_XACTPOS_SHIFT 14 +#define HCSPLT_XACTPOS_MID 0 +#define HCSPLT_XACTPOS_END 1 +#define HCSPLT_XACTPOS_BEGIN 2 +#define HCSPLT_XACTPOS_ALL 3 +#define HCSPLT_HUBADDR_MASK (0x7f << 7) +#define HCSPLT_HUBADDR_SHIFT 7 +#define HCSPLT_PRTADDR_MASK (0x7f << 0) +#define HCSPLT_PRTADDR_SHIFT 0 + +#define HCINT(_ch) HSOTG_REG(0x0508 + 0x20 * (_ch)) +#define HCINTMSK(_ch) HSOTG_REG(0x050c + 0x20 * (_ch)) +#define HCINTMSK_RESERVED14_31 (0x3ffff << 14) +#define HCINTMSK_FRM_LIST_ROLL BIT(13) +#define HCINTMSK_XCS_XACT BIT(12) +#define HCINTMSK_BNA BIT(11) +#define HCINTMSK_DATATGLERR BIT(10) +#define HCINTMSK_FRMOVRUN BIT(9) +#define HCINTMSK_BBLERR BIT(8) +#define HCINTMSK_XACTERR BIT(7) +#define HCINTMSK_NYET BIT(6) +#define HCINTMSK_ACK BIT(5) +#define HCINTMSK_NAK BIT(4) +#define HCINTMSK_STALL BIT(3) +#define HCINTMSK_AHBERR BIT(2) +#define HCINTMSK_CHHLTD BIT(1) +#define HCINTMSK_XFERCOMPL BIT(0) + +#define HCTSIZ(_ch) HSOTG_REG(0x0510 + 0x20 * (_ch)) +#define TSIZ_DOPNG BIT(31) +#define TSIZ_SC_MC_PID_MASK (0x3 << 29) +#define TSIZ_SC_MC_PID_SHIFT 29 +#define TSIZ_SC_MC_PID_DATA0 0 +#define TSIZ_SC_MC_PID_DATA2 1 +#define TSIZ_SC_MC_PID_DATA1 2 +#define TSIZ_SC_MC_PID_MDATA 3 +#define TSIZ_SC_MC_PID_SETUP 3 +#define TSIZ_PKTCNT_MASK (0x3ff << 19) +#define TSIZ_PKTCNT_SHIFT 19 +#define TSIZ_NTD_MASK (0xff << 8) +#define TSIZ_NTD_SHIFT 8 +#define TSIZ_SCHINFO_MASK (0xff << 0) +#define TSIZ_SCHINFO_SHIFT 0 +#define TSIZ_XFERSIZE_MASK (0x7ffff << 0) +#define TSIZ_XFERSIZE_SHIFT 0 + +#define HCDMA(_ch) HSOTG_REG(0x0514 + 0x20 * (_ch)) + +#define HCDMAB(_ch) HSOTG_REG(0x051c + 0x20 * (_ch)) + +#define HCFIFO(_ch) HSOTG_REG(0x1000 + 0x1000 * (_ch)) + +/** + * struct dwc2_dma_desc - DMA descriptor structure, + * used for both host and gadget modes + * + * @status: DMA descriptor status quadlet + * @buf: DMA descriptor data buffer pointer + * + * DMA Descriptor structure contains two quadlets: + * Status quadlet and Data buffer pointer. + */ +struct dwc2_dma_desc { + uint32_t status; + uint32_t buf; +} __packed; + +/* Host Mode DMA descriptor status quadlet */ + +#define HOST_DMA_A BIT(31) +#define HOST_DMA_STS_MASK (0x3 << 28) +#define HOST_DMA_STS_SHIFT 28 +#define HOST_DMA_STS_PKTERR BIT(28) +#define HOST_DMA_EOL BIT(26) +#define HOST_DMA_IOC BIT(25) +#define HOST_DMA_SUP BIT(24) +#define HOST_DMA_ALT_QTD BIT(23) +#define HOST_DMA_QTD_OFFSET_MASK (0x3f << 17) +#define HOST_DMA_QTD_OFFSET_SHIFT 17 +#define HOST_DMA_ISOC_NBYTES_MASK (0xfff << 0) +#define HOST_DMA_ISOC_NBYTES_SHIFT 0 +#define HOST_DMA_NBYTES_MASK (0x1ffff << 0) +#define HOST_DMA_NBYTES_SHIFT 0 +#define HOST_DMA_NBYTES_LIMIT 131071 + +/* Device Mode DMA descriptor status quadlet */ + +#define DEV_DMA_BUFF_STS_MASK (0x3 << 30) +#define DEV_DMA_BUFF_STS_SHIFT 30 +#define DEV_DMA_BUFF_STS_HREADY 0 +#define DEV_DMA_BUFF_STS_DMABUSY 1 +#define DEV_DMA_BUFF_STS_DMADONE 2 +#define DEV_DMA_BUFF_STS_HBUSY 3 +#define DEV_DMA_STS_MASK (0x3 << 28) +#define DEV_DMA_STS_SHIFT 28 +#define DEV_DMA_STS_SUCC 0 +#define DEV_DMA_STS_BUFF_FLUSH 1 +#define DEV_DMA_STS_BUFF_ERR 3 +#define DEV_DMA_L BIT(27) +#define DEV_DMA_SHORT BIT(26) +#define DEV_DMA_IOC BIT(25) +#define DEV_DMA_SR BIT(24) +#define DEV_DMA_MTRF BIT(23) +#define DEV_DMA_ISOC_PID_MASK (0x3 << 23) +#define DEV_DMA_ISOC_PID_SHIFT 23 +#define DEV_DMA_ISOC_PID_DATA0 0 +#define DEV_DMA_ISOC_PID_DATA2 1 +#define DEV_DMA_ISOC_PID_DATA1 2 +#define DEV_DMA_ISOC_PID_MDATA 3 +#define DEV_DMA_ISOC_FRNUM_MASK (0x7ff << 12) +#define DEV_DMA_ISOC_FRNUM_SHIFT 12 +#define DEV_DMA_ISOC_TX_NBYTES_MASK (0xfff << 0) +#define DEV_DMA_ISOC_TX_NBYTES_LIMIT 0xfff +#define DEV_DMA_ISOC_RX_NBYTES_MASK (0x7ff << 0) +#define DEV_DMA_ISOC_RX_NBYTES_LIMIT 0x7ff +#define DEV_DMA_ISOC_NBYTES_SHIFT 0 +#define DEV_DMA_NBYTES_MASK (0xffff << 0) +#define DEV_DMA_NBYTES_SHIFT 0 +#define DEV_DMA_NBYTES_LIMIT 0xffff + +#define MAX_DMA_DESC_NUM_GENERIC 64 +#define MAX_DMA_DESC_NUM_HS_ISOC 256 + +#endif /* __DWC2_HW_H__ */ From 104a010f24f7ae9d16ff67bce66c309a4a070915 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Wed, 20 May 2020 16:53:45 -0700 Subject: [PATCH 0867/2595] dwc-hsotg (dwc2) USB host controller state definitions Add the dwc-hsotg (dwc2) USB host controller state definitions. Mostly based on hw/usb/hcd-ehci.h. Signed-off-by: Paul Zimmerman Message-id: 20200520235349.21215-4-pauldzim@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/usb/hcd-dwc2.h | 190 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 hw/usb/hcd-dwc2.h diff --git a/hw/usb/hcd-dwc2.h b/hw/usb/hcd-dwc2.h new file mode 100644 index 0000000000..4ba809a07b --- /dev/null +++ b/hw/usb/hcd-dwc2.h @@ -0,0 +1,190 @@ +/* + * dwc-hsotg (dwc2) USB host controller state definitions + * + * Based on hw/usb/hcd-ehci.h + * + * Copyright (c) 2020 Paul Zimmerman + * + * 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. + */ + +#ifndef HW_USB_DWC2_H +#define HW_USB_DWC2_H + +#include "qemu/timer.h" +#include "hw/irq.h" +#include "hw/sysbus.h" +#include "hw/usb.h" +#include "sysemu/dma.h" + +#define DWC2_MMIO_SIZE 0x11000 + +#define DWC2_NB_CHAN 8 /* Number of host channels */ +#define DWC2_MAX_XFER_SIZE 65536 /* Max transfer size expected in HCTSIZ */ + +typedef struct DWC2Packet DWC2Packet; +typedef struct DWC2State DWC2State; +typedef struct DWC2Class DWC2Class; + +enum async_state { + DWC2_ASYNC_NONE = 0, + DWC2_ASYNC_INITIALIZED, + DWC2_ASYNC_INFLIGHT, + DWC2_ASYNC_FINISHED, +}; + +struct DWC2Packet { + USBPacket packet; + uint32_t devadr; + uint32_t epnum; + uint32_t epdir; + uint32_t mps; + uint32_t pid; + uint32_t index; + uint32_t pcnt; + uint32_t len; + int32_t async; + bool small; + bool needs_service; +}; + +struct DWC2State { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + USBBus bus; + qemu_irq irq; + MemoryRegion *dma_mr; + AddressSpace dma_as; + MemoryRegion container; + MemoryRegion hsotg; + MemoryRegion fifos; + + union { +#define DWC2_GLBREG_SIZE 0x70 + uint32_t glbreg[DWC2_GLBREG_SIZE / sizeof(uint32_t)]; + struct { + uint32_t gotgctl; /* 00 */ + uint32_t gotgint; /* 04 */ + uint32_t gahbcfg; /* 08 */ + uint32_t gusbcfg; /* 0c */ + uint32_t grstctl; /* 10 */ + uint32_t gintsts; /* 14 */ + uint32_t gintmsk; /* 18 */ + uint32_t grxstsr; /* 1c */ + uint32_t grxstsp; /* 20 */ + uint32_t grxfsiz; /* 24 */ + uint32_t gnptxfsiz; /* 28 */ + uint32_t gnptxsts; /* 2c */ + uint32_t gi2cctl; /* 30 */ + uint32_t gpvndctl; /* 34 */ + uint32_t ggpio; /* 38 */ + uint32_t guid; /* 3c */ + uint32_t gsnpsid; /* 40 */ + uint32_t ghwcfg1; /* 44 */ + uint32_t ghwcfg2; /* 48 */ + uint32_t ghwcfg3; /* 4c */ + uint32_t ghwcfg4; /* 50 */ + uint32_t glpmcfg; /* 54 */ + uint32_t gpwrdn; /* 58 */ + uint32_t gdfifocfg; /* 5c */ + uint32_t gadpctl; /* 60 */ + uint32_t grefclk; /* 64 */ + uint32_t gintmsk2; /* 68 */ + uint32_t gintsts2; /* 6c */ + }; + }; + + union { +#define DWC2_FSZREG_SIZE 0x04 + uint32_t fszreg[DWC2_FSZREG_SIZE / sizeof(uint32_t)]; + struct { + uint32_t hptxfsiz; /* 100 */ + }; + }; + + union { +#define DWC2_HREG0_SIZE 0x44 + uint32_t hreg0[DWC2_HREG0_SIZE / sizeof(uint32_t)]; + struct { + uint32_t hcfg; /* 400 */ + uint32_t hfir; /* 404 */ + uint32_t hfnum; /* 408 */ + uint32_t rsvd0; /* 40c */ + uint32_t hptxsts; /* 410 */ + uint32_t haint; /* 414 */ + uint32_t haintmsk; /* 418 */ + uint32_t hflbaddr; /* 41c */ + uint32_t rsvd1[8]; /* 420-43c */ + uint32_t hprt0; /* 440 */ + }; + }; + +#define DWC2_HREG1_SIZE (0x20 * DWC2_NB_CHAN) + uint32_t hreg1[DWC2_HREG1_SIZE / sizeof(uint32_t)]; + +#define hcchar(_ch) hreg1[((_ch) << 3) + 0] /* 500, 520, ... */ +#define hcsplt(_ch) hreg1[((_ch) << 3) + 1] /* 504, 524, ... */ +#define hcint(_ch) hreg1[((_ch) << 3) + 2] /* 508, 528, ... */ +#define hcintmsk(_ch) hreg1[((_ch) << 3) + 3] /* 50c, 52c, ... */ +#define hctsiz(_ch) hreg1[((_ch) << 3) + 4] /* 510, 530, ... */ +#define hcdma(_ch) hreg1[((_ch) << 3) + 5] /* 514, 534, ... */ +#define hcdmab(_ch) hreg1[((_ch) << 3) + 7] /* 51c, 53c, ... */ + + union { +#define DWC2_PCGREG_SIZE 0x08 + uint32_t pcgreg[DWC2_PCGREG_SIZE / sizeof(uint32_t)]; + struct { + uint32_t pcgctl; /* e00 */ + uint32_t pcgcctl1; /* e04 */ + }; + }; + + /* TODO - implement FIFO registers for slave mode */ +#define DWC2_HFIFO_SIZE (0x1000 * DWC2_NB_CHAN) + + /* + * Internal state + */ + QEMUTimer *eof_timer; + QEMUTimer *frame_timer; + QEMUBH *async_bh; + int64_t sof_time; + int64_t usb_frame_time; + int64_t usb_bit_time; + uint32_t usb_version; + uint16_t frame_number; + uint16_t fi; + uint16_t next_chan; + bool working; + USBPort uport; + DWC2Packet packet[DWC2_NB_CHAN]; /* one packet per chan */ + uint8_t usb_buf[DWC2_NB_CHAN][DWC2_MAX_XFER_SIZE]; /* one buffer per chan */ +}; + +struct DWC2Class { + /*< private >*/ + SysBusDeviceClass parent_class; + ResettablePhases parent_phases; + + /*< public >*/ +}; + +#define TYPE_DWC2_USB "dwc2-usb" +#define DWC2_USB(obj) \ + OBJECT_CHECK(DWC2State, (obj), TYPE_DWC2_USB) +#define DWC2_CLASS(klass) \ + OBJECT_CLASS_CHECK(DWC2Class, (klass), TYPE_DWC2_USB) +#define DWC2_GET_CLASS(obj) \ + OBJECT_GET_CLASS(DWC2Class, (obj), TYPE_DWC2_USB) + +#endif From 153ef1662c35ba3d3bbcedefe8dc24cfa4e8c33d Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Wed, 20 May 2020 16:53:46 -0700 Subject: [PATCH 0868/2595] dwc-hsotg (dwc2) USB host controller emulation Add the dwc-hsotg (dwc2) USB host controller emulation code. Based on hw/usb/hcd-ehci.c and hw/usb/hcd-ohci.c. Note that to use this with the dwc-otg driver in the Raspbian kernel, you must pass the option "dwc_otg.fiq_fsm_enable=0" on the kernel command line. Emulation of slave mode and of descriptor-DMA mode has not been implemented yet. These modes are seldom used. I have used some on-line sources of information while developing this emulation, including: http://www.capital-micro.com/PDF/CME-M7_Family_User_Guide_EN.pdf which has a pretty complete description of the controller starting on page 370. https://sourceforge.net/p/wive-ng/wive-ng-mt/ci/master/tree/docs/DataSheets/RT3050_5x_V2.0_081408_0902.pdf which has a description of the controller registers starting on page 130. Thanks to Felippe Mathieu-Daude for providing a cleaner method of implementing the memory regions for the controller registers. Signed-off-by: Paul Zimmerman Message-id: 20200520235349.21215-5-pauldzim@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/usb/Kconfig | 5 + hw/usb/Makefile.objs | 1 + hw/usb/hcd-dwc2.c | 1417 ++++++++++++++++++++++++++++++++++++++++++ hw/usb/trace-events | 50 ++ 4 files changed, 1473 insertions(+) create mode 100644 hw/usb/hcd-dwc2.c diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig index 464348ba14..d4d8c37c28 100644 --- a/hw/usb/Kconfig +++ b/hw/usb/Kconfig @@ -46,6 +46,11 @@ config USB_MUSB bool select USB +config USB_DWC2 + bool + default y + select USB + config TUSB6010 bool select USB_MUSB diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 66835e5bf7..fa5c3fa1b8 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -12,6 +12,7 @@ common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci-sysbus.o common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o common-obj-$(CONFIG_USB_XHCI_NEC) += hcd-xhci-nec.o common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o +common-obj-$(CONFIG_USB_DWC2) += hcd-dwc2.o common-obj-$(CONFIG_TUSB6010) += tusb6010.o common-obj-$(CONFIG_IMX) += chipidea.o diff --git a/hw/usb/hcd-dwc2.c b/hw/usb/hcd-dwc2.c new file mode 100644 index 0000000000..72cbd051f3 --- /dev/null +++ b/hw/usb/hcd-dwc2.c @@ -0,0 +1,1417 @@ +/* + * dwc-hsotg (dwc2) USB host controller emulation + * + * Based on hw/usb/hcd-ehci.c and hw/usb/hcd-ohci.c + * + * Note that to use this emulation with the dwc-otg driver in the + * Raspbian kernel, you must pass the option "dwc_otg.fiq_fsm_enable=0" + * on the kernel command line. + * + * Some useful documentation used to develop this emulation can be + * found online (as of April 2020) at: + * + * http://www.capital-micro.com/PDF/CME-M7_Family_User_Guide_EN.pdf + * which has a pretty complete description of the controller starting + * on page 370. + * + * https://sourceforge.net/p/wive-ng/wive-ng-mt/ci/master/tree/docs/DataSheets/RT3050_5x_V2.0_081408_0902.pdf + * which has a description of the controller registers starting on + * page 130. + * + * Copyright (c) 2020 Paul Zimmerman + * + * 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. + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "hw/usb/dwc2-regs.h" +#include "hw/usb/hcd-dwc2.h" +#include "migration/vmstate.h" +#include "trace.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qemu/main-loop.h" +#include "hw/qdev-properties.h" + +#define USB_HZ_FS 12000000 +#define USB_HZ_HS 96000000 +#define USB_FRMINTVL 12000 + +/* nifty macros from Arnon's EHCI version */ +#define get_field(data, field) \ + (((data) & field##_MASK) >> field##_SHIFT) + +#define set_field(data, newval, field) do { \ + uint32_t val = *(data); \ + val &= ~field##_MASK; \ + val |= ((newval) << field##_SHIFT) & field##_MASK; \ + *(data) = val; \ +} while (0) + +#define get_bit(data, bitmask) \ + (!!((data) & (bitmask))) + +/* update irq line */ +static inline void dwc2_update_irq(DWC2State *s) +{ + static int oldlevel; + int level = 0; + + if ((s->gintsts & s->gintmsk) && (s->gahbcfg & GAHBCFG_GLBL_INTR_EN)) { + level = 1; + } + if (level != oldlevel) { + oldlevel = level; + trace_usb_dwc2_update_irq(level); + qemu_set_irq(s->irq, level); + } +} + +/* flag interrupt condition */ +static inline void dwc2_raise_global_irq(DWC2State *s, uint32_t intr) +{ + if (!(s->gintsts & intr)) { + s->gintsts |= intr; + trace_usb_dwc2_raise_global_irq(intr); + dwc2_update_irq(s); + } +} + +static inline void dwc2_lower_global_irq(DWC2State *s, uint32_t intr) +{ + if (s->gintsts & intr) { + s->gintsts &= ~intr; + trace_usb_dwc2_lower_global_irq(intr); + dwc2_update_irq(s); + } +} + +static inline void dwc2_raise_host_irq(DWC2State *s, uint32_t host_intr) +{ + if (!(s->haint & host_intr)) { + s->haint |= host_intr; + s->haint &= 0xffff; + trace_usb_dwc2_raise_host_irq(host_intr); + if (s->haint & s->haintmsk) { + dwc2_raise_global_irq(s, GINTSTS_HCHINT); + } + } +} + +static inline void dwc2_lower_host_irq(DWC2State *s, uint32_t host_intr) +{ + if (s->haint & host_intr) { + s->haint &= ~host_intr; + trace_usb_dwc2_lower_host_irq(host_intr); + if (!(s->haint & s->haintmsk)) { + dwc2_lower_global_irq(s, GINTSTS_HCHINT); + } + } +} + +static inline void dwc2_update_hc_irq(DWC2State *s, int index) +{ + uint32_t host_intr = 1 << (index >> 3); + + if (s->hreg1[index + 2] & s->hreg1[index + 3]) { + dwc2_raise_host_irq(s, host_intr); + } else { + dwc2_lower_host_irq(s, host_intr); + } +} + +/* set a timer for EOF */ +static void dwc2_eof_timer(DWC2State *s) +{ + timer_mod(s->eof_timer, s->sof_time + s->usb_frame_time); +} + +/* Set a timer for EOF and generate SOF event */ +static void dwc2_sof(DWC2State *s) +{ + s->sof_time += s->usb_frame_time; + trace_usb_dwc2_sof(s->sof_time); + dwc2_eof_timer(s); + dwc2_raise_global_irq(s, GINTSTS_SOF); +} + +/* Do frame processing on frame boundary */ +static void dwc2_frame_boundary(void *opaque) +{ + DWC2State *s = opaque; + int64_t now; + uint16_t frcnt; + + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + /* Frame boundary, so do EOF stuff here */ + + /* Increment frame number */ + frcnt = (uint16_t)((now - s->sof_time) / s->fi); + s->frame_number = (s->frame_number + frcnt) & 0xffff; + s->hfnum = s->frame_number & HFNUM_MAX_FRNUM; + + /* Do SOF stuff here */ + dwc2_sof(s); +} + +/* Start sending SOF tokens on the USB bus */ +static void dwc2_bus_start(DWC2State *s) +{ + trace_usb_dwc2_bus_start(); + s->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + dwc2_eof_timer(s); +} + +/* Stop sending SOF tokens on the USB bus */ +static void dwc2_bus_stop(DWC2State *s) +{ + trace_usb_dwc2_bus_stop(); + timer_del(s->eof_timer); +} + +static USBDevice *dwc2_find_device(DWC2State *s, uint8_t addr) +{ + USBDevice *dev; + + trace_usb_dwc2_find_device(addr); + + if (!(s->hprt0 & HPRT0_ENA)) { + trace_usb_dwc2_port_disabled(0); + } else { + dev = usb_find_device(&s->uport, addr); + if (dev != NULL) { + trace_usb_dwc2_device_found(0); + return dev; + } + } + + trace_usb_dwc2_device_not_found(); + return NULL; +} + +static const char *pstatus[] = { + "USB_RET_SUCCESS", "USB_RET_NODEV", "USB_RET_NAK", "USB_RET_STALL", + "USB_RET_BABBLE", "USB_RET_IOERROR", "USB_RET_ASYNC", + "USB_RET_ADD_TO_QUEUE", "USB_RET_REMOVE_FROM_QUEUE" +}; + +static uint32_t pintr[] = { + HCINTMSK_XFERCOMPL, HCINTMSK_XACTERR, HCINTMSK_NAK, HCINTMSK_STALL, + HCINTMSK_BBLERR, HCINTMSK_XACTERR, HCINTMSK_XACTERR, HCINTMSK_XACTERR, + HCINTMSK_XACTERR +}; + +static const char *types[] = { + "Ctrl", "Isoc", "Bulk", "Intr" +}; + +static const char *dirs[] = { + "Out", "In" +}; + +static void dwc2_handle_packet(DWC2State *s, uint32_t devadr, USBDevice *dev, + USBEndpoint *ep, uint32_t index, bool send) +{ + DWC2Packet *p; + uint32_t hcchar = s->hreg1[index]; + uint32_t hctsiz = s->hreg1[index + 4]; + uint32_t hcdma = s->hreg1[index + 5]; + uint32_t chan, epnum, epdir, eptype, mps, pid, pcnt, len, tlen, intr = 0; + uint32_t tpcnt, stsidx, actual = 0; + bool do_intr = false, done = false; + + epnum = get_field(hcchar, HCCHAR_EPNUM); + epdir = get_bit(hcchar, HCCHAR_EPDIR); + eptype = get_field(hcchar, HCCHAR_EPTYPE); + mps = get_field(hcchar, HCCHAR_MPS); + pid = get_field(hctsiz, TSIZ_SC_MC_PID); + pcnt = get_field(hctsiz, TSIZ_PKTCNT); + len = get_field(hctsiz, TSIZ_XFERSIZE); + assert(len <= DWC2_MAX_XFER_SIZE); + chan = index >> 3; + p = &s->packet[chan]; + + trace_usb_dwc2_handle_packet(chan, dev, &p->packet, epnum, types[eptype], + dirs[epdir], mps, len, pcnt); + + if (eptype == USB_ENDPOINT_XFER_CONTROL && pid == TSIZ_SC_MC_PID_SETUP) { + pid = USB_TOKEN_SETUP; + } else { + pid = epdir ? USB_TOKEN_IN : USB_TOKEN_OUT; + } + + if (send) { + tlen = len; + if (p->small) { + if (tlen > mps) { + tlen = mps; + } + } + + if (pid != USB_TOKEN_IN) { + trace_usb_dwc2_memory_read(hcdma, tlen); + if (dma_memory_read(&s->dma_as, hcdma, + s->usb_buf[chan], tlen) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_read failed\n", + __func__); + } + } + + usb_packet_init(&p->packet); + usb_packet_setup(&p->packet, pid, ep, 0, hcdma, + pid != USB_TOKEN_IN, true); + usb_packet_addbuf(&p->packet, s->usb_buf[chan], tlen); + p->async = DWC2_ASYNC_NONE; + usb_handle_packet(dev, &p->packet); + } else { + tlen = p->len; + } + + stsidx = -p->packet.status; + assert(stsidx < sizeof(pstatus) / sizeof(*pstatus)); + actual = p->packet.actual_length; + trace_usb_dwc2_packet_status(pstatus[stsidx], actual); + +babble: + if (p->packet.status != USB_RET_SUCCESS && + p->packet.status != USB_RET_NAK && + p->packet.status != USB_RET_STALL && + p->packet.status != USB_RET_ASYNC) { + trace_usb_dwc2_packet_error(pstatus[stsidx]); + } + + if (p->packet.status == USB_RET_ASYNC) { + trace_usb_dwc2_async_packet(&p->packet, chan, dev, epnum, + dirs[epdir], tlen); + usb_device_flush_ep_queue(dev, ep); + assert(p->async != DWC2_ASYNC_INFLIGHT); + p->devadr = devadr; + p->epnum = epnum; + p->epdir = epdir; + p->mps = mps; + p->pid = pid; + p->index = index; + p->pcnt = pcnt; + p->len = tlen; + p->async = DWC2_ASYNC_INFLIGHT; + p->needs_service = false; + return; + } + + if (p->packet.status == USB_RET_SUCCESS) { + if (actual > tlen) { + p->packet.status = USB_RET_BABBLE; + goto babble; + } + + if (pid == USB_TOKEN_IN) { + trace_usb_dwc2_memory_write(hcdma, actual); + if (dma_memory_write(&s->dma_as, hcdma, s->usb_buf[chan], + actual) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_write failed\n", + __func__); + } + } + + tpcnt = actual / mps; + if (actual % mps) { + tpcnt++; + if (pid == USB_TOKEN_IN) { + done = true; + } + } + + pcnt -= tpcnt < pcnt ? tpcnt : pcnt; + set_field(&hctsiz, pcnt, TSIZ_PKTCNT); + len -= actual < len ? actual : len; + set_field(&hctsiz, len, TSIZ_XFERSIZE); + s->hreg1[index + 4] = hctsiz; + hcdma += actual; + s->hreg1[index + 5] = hcdma; + + if (!pcnt || len == 0 || actual == 0) { + done = true; + } + } else { + intr |= pintr[stsidx]; + if (p->packet.status == USB_RET_NAK && + (eptype == USB_ENDPOINT_XFER_CONTROL || + eptype == USB_ENDPOINT_XFER_BULK)) { + /* + * for ctrl/bulk, automatically retry on NAK, + * but send the interrupt anyway + */ + intr &= ~HCINTMSK_RESERVED14_31; + s->hreg1[index + 2] |= intr; + do_intr = true; + } else { + intr |= HCINTMSK_CHHLTD; + done = true; + } + } + + usb_packet_cleanup(&p->packet); + + if (done) { + hcchar &= ~HCCHAR_CHENA; + s->hreg1[index] = hcchar; + if (!(intr & HCINTMSK_CHHLTD)) { + intr |= HCINTMSK_CHHLTD | HCINTMSK_XFERCOMPL; + } + intr &= ~HCINTMSK_RESERVED14_31; + s->hreg1[index + 2] |= intr; + p->needs_service = false; + trace_usb_dwc2_packet_done(pstatus[stsidx], actual, len, pcnt); + dwc2_update_hc_irq(s, index); + return; + } + + p->devadr = devadr; + p->epnum = epnum; + p->epdir = epdir; + p->mps = mps; + p->pid = pid; + p->index = index; + p->pcnt = pcnt; + p->len = len; + p->needs_service = true; + trace_usb_dwc2_packet_next(pstatus[stsidx], len, pcnt); + if (do_intr) { + dwc2_update_hc_irq(s, index); + } +} + +/* Attach or detach a device on root hub */ + +static const char *speeds[] = { + "low", "full", "high" +}; + +static void dwc2_attach(USBPort *port) +{ + DWC2State *s = port->opaque; + int hispd = 0; + + trace_usb_dwc2_attach(port); + assert(port->index == 0); + + if (!port->dev || !port->dev->attached) { + return; + } + + assert(port->dev->speed <= USB_SPEED_HIGH); + trace_usb_dwc2_attach_speed(speeds[port->dev->speed]); + s->hprt0 &= ~HPRT0_SPD_MASK; + + switch (port->dev->speed) { + case USB_SPEED_LOW: + s->hprt0 |= HPRT0_SPD_LOW_SPEED << HPRT0_SPD_SHIFT; + break; + case USB_SPEED_FULL: + s->hprt0 |= HPRT0_SPD_FULL_SPEED << HPRT0_SPD_SHIFT; + break; + case USB_SPEED_HIGH: + s->hprt0 |= HPRT0_SPD_HIGH_SPEED << HPRT0_SPD_SHIFT; + hispd = 1; + break; + } + + if (hispd) { + s->usb_frame_time = NANOSECONDS_PER_SECOND / 8000; /* 125000 */ + if (NANOSECONDS_PER_SECOND >= USB_HZ_HS) { + s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_HS; /* 10.4 */ + } else { + s->usb_bit_time = 1; + } + } else { + s->usb_frame_time = NANOSECONDS_PER_SECOND / 1000; /* 1000000 */ + if (NANOSECONDS_PER_SECOND >= USB_HZ_FS) { + s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_FS; /* 83.3 */ + } else { + s->usb_bit_time = 1; + } + } + + s->fi = USB_FRMINTVL - 1; + s->hprt0 |= HPRT0_CONNDET | HPRT0_CONNSTS; + + dwc2_bus_start(s); + dwc2_raise_global_irq(s, GINTSTS_PRTINT); +} + +static void dwc2_detach(USBPort *port) +{ + DWC2State *s = port->opaque; + + trace_usb_dwc2_detach(port); + assert(port->index == 0); + + dwc2_bus_stop(s); + + s->hprt0 &= ~(HPRT0_SPD_MASK | HPRT0_SUSP | HPRT0_ENA | HPRT0_CONNSTS); + s->hprt0 |= HPRT0_CONNDET | HPRT0_ENACHG; + + dwc2_raise_global_irq(s, GINTSTS_PRTINT); +} + +static void dwc2_child_detach(USBPort *port, USBDevice *child) +{ + trace_usb_dwc2_child_detach(port, child); + assert(port->index == 0); +} + +static void dwc2_wakeup(USBPort *port) +{ + DWC2State *s = port->opaque; + + trace_usb_dwc2_wakeup(port); + assert(port->index == 0); + + if (s->hprt0 & HPRT0_SUSP) { + s->hprt0 |= HPRT0_RES; + dwc2_raise_global_irq(s, GINTSTS_PRTINT); + } + + qemu_bh_schedule(s->async_bh); +} + +static void dwc2_async_packet_complete(USBPort *port, USBPacket *packet) +{ + DWC2State *s = port->opaque; + DWC2Packet *p; + USBDevice *dev; + USBEndpoint *ep; + + assert(port->index == 0); + p = container_of(packet, DWC2Packet, packet); + dev = dwc2_find_device(s, p->devadr); + ep = usb_ep_get(dev, p->pid, p->epnum); + trace_usb_dwc2_async_packet_complete(port, packet, p->index >> 3, dev, + p->epnum, dirs[p->epdir], p->len); + assert(p->async == DWC2_ASYNC_INFLIGHT); + + if (packet->status == USB_RET_REMOVE_FROM_QUEUE) { + usb_cancel_packet(packet); + usb_packet_cleanup(packet); + return; + } + + dwc2_handle_packet(s, p->devadr, dev, ep, p->index, false); + + p->async = DWC2_ASYNC_FINISHED; + qemu_bh_schedule(s->async_bh); +} + +static USBPortOps dwc2_port_ops = { + .attach = dwc2_attach, + .detach = dwc2_detach, + .child_detach = dwc2_child_detach, + .wakeup = dwc2_wakeup, + .complete = dwc2_async_packet_complete, +}; + +static uint32_t dwc2_get_frame_remaining(DWC2State *s) +{ + uint32_t fr = 0; + int64_t tks; + + tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->sof_time; + if (tks < 0) { + tks = 0; + } + + /* avoid muldiv if possible */ + if (tks >= s->usb_frame_time) { + goto out; + } + if (tks < s->usb_bit_time) { + fr = s->fi; + goto out; + } + + /* tks = number of ns since SOF, divided by 83 (fs) or 10 (hs) */ + tks = tks / s->usb_bit_time; + if (tks >= (int64_t)s->fi) { + goto out; + } + + /* remaining = frame interval minus tks */ + fr = (uint32_t)((int64_t)s->fi - tks); + +out: + return fr; +} + +static void dwc2_work_bh(void *opaque) +{ + DWC2State *s = opaque; + DWC2Packet *p; + USBDevice *dev; + USBEndpoint *ep; + int64_t t_now, expire_time; + int chan; + bool found = false; + + trace_usb_dwc2_work_bh(); + if (s->working) { + return; + } + s->working = true; + + t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + chan = s->next_chan; + + do { + p = &s->packet[chan]; + if (p->needs_service) { + dev = dwc2_find_device(s, p->devadr); + ep = usb_ep_get(dev, p->pid, p->epnum); + trace_usb_dwc2_work_bh_service(s->next_chan, chan, dev, p->epnum); + dwc2_handle_packet(s, p->devadr, dev, ep, p->index, true); + found = true; + } + if (++chan == DWC2_NB_CHAN) { + chan = 0; + } + if (found) { + s->next_chan = chan; + trace_usb_dwc2_work_bh_next(chan); + } + } while (chan != s->next_chan); + + if (found) { + expire_time = t_now + NANOSECONDS_PER_SECOND / 4000; + timer_mod(s->frame_timer, expire_time); + } + s->working = false; +} + +static void dwc2_enable_chan(DWC2State *s, uint32_t index) +{ + USBDevice *dev; + USBEndpoint *ep; + uint32_t hcchar; + uint32_t hctsiz; + uint32_t devadr, epnum, epdir, eptype, pid, len; + DWC2Packet *p; + + assert((index >> 3) < DWC2_NB_CHAN); + p = &s->packet[index >> 3]; + hcchar = s->hreg1[index]; + hctsiz = s->hreg1[index + 4]; + devadr = get_field(hcchar, HCCHAR_DEVADDR); + epnum = get_field(hcchar, HCCHAR_EPNUM); + epdir = get_bit(hcchar, HCCHAR_EPDIR); + eptype = get_field(hcchar, HCCHAR_EPTYPE); + pid = get_field(hctsiz, TSIZ_SC_MC_PID); + len = get_field(hctsiz, TSIZ_XFERSIZE); + + dev = dwc2_find_device(s, devadr); + + trace_usb_dwc2_enable_chan(index >> 3, dev, &p->packet, epnum); + if (dev == NULL) { + return; + } + + if (eptype == USB_ENDPOINT_XFER_CONTROL && pid == TSIZ_SC_MC_PID_SETUP) { + pid = USB_TOKEN_SETUP; + } else { + pid = epdir ? USB_TOKEN_IN : USB_TOKEN_OUT; + } + + ep = usb_ep_get(dev, pid, epnum); + + /* + * Hack: Networking doesn't like us delivering large transfers, it kind + * of works but the latency is horrible. So if the transfer is <= the mtu + * size, we take that as a hint that this might be a network transfer, + * and do the transfer packet-by-packet. + */ + if (len > 1536) { + p->small = false; + } else { + p->small = true; + } + + dwc2_handle_packet(s, devadr, dev, ep, index, true); + qemu_bh_schedule(s->async_bh); +} + +static const char *glbregnm[] = { + "GOTGCTL ", "GOTGINT ", "GAHBCFG ", "GUSBCFG ", "GRSTCTL ", + "GINTSTS ", "GINTMSK ", "GRXSTSR ", "GRXSTSP ", "GRXFSIZ ", + "GNPTXFSIZ", "GNPTXSTS ", "GI2CCTL ", "GPVNDCTL ", "GGPIO ", + "GUID ", "GSNPSID ", "GHWCFG1 ", "GHWCFG2 ", "GHWCFG3 ", + "GHWCFG4 ", "GLPMCFG ", "GPWRDN ", "GDFIFOCFG", "GADPCTL ", + "GREFCLK ", "GINTMSK2 ", "GINTSTS2 " +}; + +static uint64_t dwc2_glbreg_read(void *ptr, hwaddr addr, int index, + unsigned size) +{ + DWC2State *s = ptr; + uint32_t val; + + assert(addr <= GINTSTS2); + val = s->glbreg[index]; + + switch (addr) { + case GRSTCTL: + /* clear any self-clearing bits that were set */ + val &= ~(GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH | GRSTCTL_IN_TKNQ_FLSH | + GRSTCTL_FRMCNTRRST | GRSTCTL_HSFTRST | GRSTCTL_CSFTRST); + s->glbreg[index] = val; + break; + default: + break; + } + + trace_usb_dwc2_glbreg_read(addr, glbregnm[index], val); + return val; +} + +static void dwc2_glbreg_write(void *ptr, hwaddr addr, int index, uint64_t val, + unsigned size) +{ + DWC2State *s = ptr; + uint64_t orig = val; + uint32_t *mmio; + uint32_t old; + int iflg = 0; + + assert(addr <= GINTSTS2); + mmio = &s->glbreg[index]; + old = *mmio; + + switch (addr) { + case GOTGCTL: + /* don't allow setting of read-only bits */ + val &= ~(GOTGCTL_MULT_VALID_BC_MASK | GOTGCTL_BSESVLD | + GOTGCTL_ASESVLD | GOTGCTL_DBNC_SHORT | GOTGCTL_CONID_B | + GOTGCTL_HSTNEGSCS | GOTGCTL_SESREQSCS); + /* don't allow clearing of read-only bits */ + val |= old & (GOTGCTL_MULT_VALID_BC_MASK | GOTGCTL_BSESVLD | + GOTGCTL_ASESVLD | GOTGCTL_DBNC_SHORT | GOTGCTL_CONID_B | + GOTGCTL_HSTNEGSCS | GOTGCTL_SESREQSCS); + break; + case GAHBCFG: + if ((val & GAHBCFG_GLBL_INTR_EN) && !(old & GAHBCFG_GLBL_INTR_EN)) { + iflg = 1; + } + break; + case GRSTCTL: + val |= GRSTCTL_AHBIDLE; + val &= ~GRSTCTL_DMAREQ; + if (!(old & GRSTCTL_TXFFLSH) && (val & GRSTCTL_TXFFLSH)) { + /* TODO - TX fifo flush */ + qemu_log_mask(LOG_UNIMP, "Tx FIFO flush not implemented\n"); + } + if (!(old & GRSTCTL_RXFFLSH) && (val & GRSTCTL_RXFFLSH)) { + /* TODO - RX fifo flush */ + qemu_log_mask(LOG_UNIMP, "Rx FIFO flush not implemented\n"); + } + if (!(old & GRSTCTL_IN_TKNQ_FLSH) && (val & GRSTCTL_IN_TKNQ_FLSH)) { + /* TODO - device IN token queue flush */ + qemu_log_mask(LOG_UNIMP, "Token queue flush not implemented\n"); + } + if (!(old & GRSTCTL_FRMCNTRRST) && (val & GRSTCTL_FRMCNTRRST)) { + /* TODO - host frame counter reset */ + qemu_log_mask(LOG_UNIMP, "Frame counter reset not implemented\n"); + } + if (!(old & GRSTCTL_HSFTRST) && (val & GRSTCTL_HSFTRST)) { + /* TODO - host soft reset */ + qemu_log_mask(LOG_UNIMP, "Host soft reset not implemented\n"); + } + if (!(old & GRSTCTL_CSFTRST) && (val & GRSTCTL_CSFTRST)) { + /* TODO - core soft reset */ + qemu_log_mask(LOG_UNIMP, "Core soft reset not implemented\n"); + } + /* don't allow clearing of self-clearing bits */ + val |= old & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH | + GRSTCTL_IN_TKNQ_FLSH | GRSTCTL_FRMCNTRRST | + GRSTCTL_HSFTRST | GRSTCTL_CSFTRST); + break; + case GINTSTS: + /* clear the write-1-to-clear bits */ + val |= ~old; + val = ~val; + /* don't allow clearing of read-only bits */ + val |= old & (GINTSTS_PTXFEMP | GINTSTS_HCHINT | GINTSTS_PRTINT | + GINTSTS_OEPINT | GINTSTS_IEPINT | GINTSTS_GOUTNAKEFF | + GINTSTS_GINNAKEFF | GINTSTS_NPTXFEMP | GINTSTS_RXFLVL | + GINTSTS_OTGINT | GINTSTS_CURMODE_HOST); + iflg = 1; + break; + case GINTMSK: + iflg = 1; + break; + default: + break; + } + + trace_usb_dwc2_glbreg_write(addr, glbregnm[index], orig, old, val); + *mmio = val; + + if (iflg) { + dwc2_update_irq(s); + } +} + +static uint64_t dwc2_fszreg_read(void *ptr, hwaddr addr, int index, + unsigned size) +{ + DWC2State *s = ptr; + uint32_t val; + + assert(addr == HPTXFSIZ); + val = s->fszreg[index]; + + trace_usb_dwc2_fszreg_read(addr, val); + return val; +} + +static void dwc2_fszreg_write(void *ptr, hwaddr addr, int index, uint64_t val, + unsigned size) +{ + DWC2State *s = ptr; + uint64_t orig = val; + uint32_t *mmio; + uint32_t old; + + assert(addr == HPTXFSIZ); + mmio = &s->fszreg[index]; + old = *mmio; + + trace_usb_dwc2_fszreg_write(addr, orig, old, val); + *mmio = val; +} + +static const char *hreg0nm[] = { + "HCFG ", "HFIR ", "HFNUM ", " ", "HPTXSTS ", + "HAINT ", "HAINTMSK ", "HFLBADDR ", " ", " ", + " ", " ", " ", " ", " ", + " ", "HPRT0 " +}; + +static uint64_t dwc2_hreg0_read(void *ptr, hwaddr addr, int index, + unsigned size) +{ + DWC2State *s = ptr; + uint32_t val; + + assert(addr >= HCFG && addr <= HPRT0); + val = s->hreg0[index]; + + switch (addr) { + case HFNUM: + val = (dwc2_get_frame_remaining(s) << HFNUM_FRREM_SHIFT) | + (s->hfnum << HFNUM_FRNUM_SHIFT); + break; + default: + break; + } + + trace_usb_dwc2_hreg0_read(addr, hreg0nm[index], val); + return val; +} + +static void dwc2_hreg0_write(void *ptr, hwaddr addr, int index, uint64_t val, + unsigned size) +{ + DWC2State *s = ptr; + USBDevice *dev = s->uport.dev; + uint64_t orig = val; + uint32_t *mmio; + uint32_t tval, told, old; + int prst = 0; + int iflg = 0; + + assert(addr >= HCFG && addr <= HPRT0); + mmio = &s->hreg0[index]; + old = *mmio; + + switch (addr) { + case HFIR: + break; + case HFNUM: + case HPTXSTS: + case HAINT: + qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read-only register\n", + __func__); + return; + case HAINTMSK: + val &= 0xffff; + break; + case HPRT0: + /* don't allow clearing of read-only bits */ + val |= old & (HPRT0_SPD_MASK | HPRT0_LNSTS_MASK | HPRT0_OVRCURRACT | + HPRT0_CONNSTS); + /* don't allow clearing of self-clearing bits */ + val |= old & (HPRT0_SUSP | HPRT0_RES); + /* don't allow setting of self-setting bits */ + if (!(old & HPRT0_ENA) && (val & HPRT0_ENA)) { + val &= ~HPRT0_ENA; + } + /* clear the write-1-to-clear bits */ + tval = val & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA | + HPRT0_CONNDET); + told = old & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA | + HPRT0_CONNDET); + tval |= ~told; + tval = ~tval; + tval &= (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA | + HPRT0_CONNDET); + val &= ~(HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA | + HPRT0_CONNDET); + val |= tval; + if (!(val & HPRT0_RST) && (old & HPRT0_RST)) { + if (dev && dev->attached) { + val |= HPRT0_ENA | HPRT0_ENACHG; + prst = 1; + } + } + if (val & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_CONNDET)) { + iflg = 1; + } else { + iflg = -1; + } + break; + default: + break; + } + + if (prst) { + trace_usb_dwc2_hreg0_write(addr, hreg0nm[index], orig, old, + val & ~HPRT0_CONNDET); + trace_usb_dwc2_hreg0_action("call usb_port_reset"); + usb_port_reset(&s->uport); + val &= ~HPRT0_CONNDET; + } else { + trace_usb_dwc2_hreg0_write(addr, hreg0nm[index], orig, old, val); + } + + *mmio = val; + + if (iflg > 0) { + trace_usb_dwc2_hreg0_action("enable PRTINT"); + dwc2_raise_global_irq(s, GINTSTS_PRTINT); + } else if (iflg < 0) { + trace_usb_dwc2_hreg0_action("disable PRTINT"); + dwc2_lower_global_irq(s, GINTSTS_PRTINT); + } +} + +static const char *hreg1nm[] = { + "HCCHAR ", "HCSPLT ", "HCINT ", "HCINTMSK", "HCTSIZ ", "HCDMA ", + " ", "HCDMAB " +}; + +static uint64_t dwc2_hreg1_read(void *ptr, hwaddr addr, int index, + unsigned size) +{ + DWC2State *s = ptr; + uint32_t val; + + assert(addr >= HCCHAR(0) && addr <= HCDMAB(DWC2_NB_CHAN - 1)); + val = s->hreg1[index]; + + trace_usb_dwc2_hreg1_read(addr, hreg1nm[index & 7], addr >> 5, val); + return val; +} + +static void dwc2_hreg1_write(void *ptr, hwaddr addr, int index, uint64_t val, + unsigned size) +{ + DWC2State *s = ptr; + uint64_t orig = val; + uint32_t *mmio; + uint32_t old; + int iflg = 0; + int enflg = 0; + int disflg = 0; + + assert(addr >= HCCHAR(0) && addr <= HCDMAB(DWC2_NB_CHAN - 1)); + mmio = &s->hreg1[index]; + old = *mmio; + + switch (HSOTG_REG(0x500) + (addr & 0x1c)) { + case HCCHAR(0): + if ((val & HCCHAR_CHDIS) && !(old & HCCHAR_CHDIS)) { + val &= ~(HCCHAR_CHENA | HCCHAR_CHDIS); + disflg = 1; + } else { + val |= old & HCCHAR_CHDIS; + if ((val & HCCHAR_CHENA) && !(old & HCCHAR_CHENA)) { + val &= ~HCCHAR_CHDIS; + enflg = 1; + } else { + val |= old & HCCHAR_CHENA; + } + } + break; + case HCINT(0): + /* clear the write-1-to-clear bits */ + val |= ~old; + val = ~val; + val &= ~HCINTMSK_RESERVED14_31; + iflg = 1; + break; + case HCINTMSK(0): + val &= ~HCINTMSK_RESERVED14_31; + iflg = 1; + break; + case HCDMAB(0): + qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read-only register\n", + __func__); + return; + default: + break; + } + + trace_usb_dwc2_hreg1_write(addr, hreg1nm[index & 7], index >> 3, orig, + old, val); + *mmio = val; + + if (disflg) { + /* set ChHltd in HCINT */ + s->hreg1[(index & ~7) + 2] |= HCINTMSK_CHHLTD; + iflg = 1; + } + + if (enflg) { + dwc2_enable_chan(s, index & ~7); + } + + if (iflg) { + dwc2_update_hc_irq(s, index & ~7); + } +} + +static const char *pcgregnm[] = { + "PCGCTL ", "PCGCCTL1 " +}; + +static uint64_t dwc2_pcgreg_read(void *ptr, hwaddr addr, int index, + unsigned size) +{ + DWC2State *s = ptr; + uint32_t val; + + assert(addr >= PCGCTL && addr <= PCGCCTL1); + val = s->pcgreg[index]; + + trace_usb_dwc2_pcgreg_read(addr, pcgregnm[index], val); + return val; +} + +static void dwc2_pcgreg_write(void *ptr, hwaddr addr, int index, + uint64_t val, unsigned size) +{ + DWC2State *s = ptr; + uint64_t orig = val; + uint32_t *mmio; + uint32_t old; + + assert(addr >= PCGCTL && addr <= PCGCCTL1); + mmio = &s->pcgreg[index]; + old = *mmio; + + trace_usb_dwc2_pcgreg_write(addr, pcgregnm[index], orig, old, val); + *mmio = val; +} + +static uint64_t dwc2_hsotg_read(void *ptr, hwaddr addr, unsigned size) +{ + uint64_t val; + + switch (addr) { + case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc): + val = dwc2_glbreg_read(ptr, addr, (addr - HSOTG_REG(0x000)) >> 2, size); + break; + case HSOTG_REG(0x100): + val = dwc2_fszreg_read(ptr, addr, (addr - HSOTG_REG(0x100)) >> 2, size); + break; + case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc): + /* Gadget-mode registers, just return 0 for now */ + val = 0; + break; + case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc): + val = dwc2_hreg0_read(ptr, addr, (addr - HSOTG_REG(0x400)) >> 2, size); + break; + case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc): + val = dwc2_hreg1_read(ptr, addr, (addr - HSOTG_REG(0x500)) >> 2, size); + break; + case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc): + /* Gadget-mode registers, just return 0 for now */ + val = 0; + break; + case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc): + val = dwc2_pcgreg_read(ptr, addr, (addr - HSOTG_REG(0xe00)) >> 2, size); + break; + default: + g_assert_not_reached(); + } + + return val; +} + +static void dwc2_hsotg_write(void *ptr, hwaddr addr, uint64_t val, + unsigned size) +{ + switch (addr) { + case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc): + dwc2_glbreg_write(ptr, addr, (addr - HSOTG_REG(0x000)) >> 2, val, size); + break; + case HSOTG_REG(0x100): + dwc2_fszreg_write(ptr, addr, (addr - HSOTG_REG(0x100)) >> 2, val, size); + break; + case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc): + /* Gadget-mode registers, do nothing for now */ + break; + case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc): + dwc2_hreg0_write(ptr, addr, (addr - HSOTG_REG(0x400)) >> 2, val, size); + break; + case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc): + dwc2_hreg1_write(ptr, addr, (addr - HSOTG_REG(0x500)) >> 2, val, size); + break; + case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc): + /* Gadget-mode registers, do nothing for now */ + break; + case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc): + dwc2_pcgreg_write(ptr, addr, (addr - HSOTG_REG(0xe00)) >> 2, val, size); + break; + default: + g_assert_not_reached(); + } +} + +static const MemoryRegionOps dwc2_mmio_hsotg_ops = { + .read = dwc2_hsotg_read, + .write = dwc2_hsotg_write, + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t dwc2_hreg2_read(void *ptr, hwaddr addr, unsigned size) +{ + /* TODO - implement FIFOs to support slave mode */ + trace_usb_dwc2_hreg2_read(addr, addr >> 12, 0); + qemu_log_mask(LOG_UNIMP, "FIFO read not implemented\n"); + return 0; +} + +static void dwc2_hreg2_write(void *ptr, hwaddr addr, uint64_t val, + unsigned size) +{ + uint64_t orig = val; + + /* TODO - implement FIFOs to support slave mode */ + trace_usb_dwc2_hreg2_write(addr, addr >> 12, orig, 0, val); + qemu_log_mask(LOG_UNIMP, "FIFO write not implemented\n"); +} + +static const MemoryRegionOps dwc2_mmio_hreg2_ops = { + .read = dwc2_hreg2_read, + .write = dwc2_hreg2_write, + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void dwc2_wakeup_endpoint(USBBus *bus, USBEndpoint *ep, + unsigned int stream) +{ + DWC2State *s = container_of(bus, DWC2State, bus); + + trace_usb_dwc2_wakeup_endpoint(ep, stream); + + /* TODO - do something here? */ + qemu_bh_schedule(s->async_bh); +} + +static USBBusOps dwc2_bus_ops = { + .wakeup_endpoint = dwc2_wakeup_endpoint, +}; + +static void dwc2_work_timer(void *opaque) +{ + DWC2State *s = opaque; + + trace_usb_dwc2_work_timer(); + qemu_bh_schedule(s->async_bh); +} + +static void dwc2_reset_enter(Object *obj, ResetType type) +{ + DWC2Class *c = DWC2_GET_CLASS(obj); + DWC2State *s = DWC2_USB(obj); + int i; + + trace_usb_dwc2_reset_enter(); + + if (c->parent_phases.enter) { + c->parent_phases.enter(obj, type); + } + + timer_del(s->frame_timer); + qemu_bh_cancel(s->async_bh); + + if (s->uport.dev && s->uport.dev->attached) { + usb_detach(&s->uport); + } + + dwc2_bus_stop(s); + + s->gotgctl = GOTGCTL_BSESVLD | GOTGCTL_ASESVLD | GOTGCTL_CONID_B; + s->gotgint = 0; + s->gahbcfg = 0; + s->gusbcfg = 5 << GUSBCFG_USBTRDTIM_SHIFT; + s->grstctl = GRSTCTL_AHBIDLE; + s->gintsts = GINTSTS_CONIDSTSCHNG | GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP | + GINTSTS_CURMODE_HOST; + s->gintmsk = 0; + s->grxstsr = 0; + s->grxstsp = 0; + s->grxfsiz = 1024; + s->gnptxfsiz = 1024 << FIFOSIZE_DEPTH_SHIFT; + s->gnptxsts = (4 << FIFOSIZE_DEPTH_SHIFT) | 1024; + s->gi2cctl = GI2CCTL_I2CDATSE0 | GI2CCTL_ACK; + s->gpvndctl = 0; + s->ggpio = 0; + s->guid = 0; + s->gsnpsid = 0x4f54294a; + s->ghwcfg1 = 0; + s->ghwcfg2 = (8 << GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT) | + (4 << GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT) | + (4 << GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT) | + GHWCFG2_DYNAMIC_FIFO | + GHWCFG2_PERIO_EP_SUPPORTED | + ((DWC2_NB_CHAN - 1) << GHWCFG2_NUM_HOST_CHAN_SHIFT) | + (GHWCFG2_INT_DMA_ARCH << GHWCFG2_ARCHITECTURE_SHIFT) | + (GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST << GHWCFG2_OP_MODE_SHIFT); + s->ghwcfg3 = (4096 << GHWCFG3_DFIFO_DEPTH_SHIFT) | + (4 << GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT) | + (4 << GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT); + s->ghwcfg4 = 0; + s->glpmcfg = 0; + s->gpwrdn = GPWRDN_PWRDNRSTN; + s->gdfifocfg = 0; + s->gadpctl = 0; + s->grefclk = 0; + s->gintmsk2 = 0; + s->gintsts2 = 0; + + s->hptxfsiz = 500 << FIFOSIZE_DEPTH_SHIFT; + + s->hcfg = 2 << HCFG_RESVALID_SHIFT; + s->hfir = 60000; + s->hfnum = 0x3fff; + s->hptxsts = (16 << TXSTS_QSPCAVAIL_SHIFT) | 32768; + s->haint = 0; + s->haintmsk = 0; + s->hprt0 = 0; + + memset(s->hreg1, 0, sizeof(s->hreg1)); + memset(s->pcgreg, 0, sizeof(s->pcgreg)); + + s->sof_time = 0; + s->frame_number = 0; + s->fi = USB_FRMINTVL - 1; + s->next_chan = 0; + s->working = false; + + for (i = 0; i < DWC2_NB_CHAN; i++) { + s->packet[i].needs_service = false; + } +} + +static void dwc2_reset_hold(Object *obj) +{ + DWC2Class *c = DWC2_GET_CLASS(obj); + DWC2State *s = DWC2_USB(obj); + + trace_usb_dwc2_reset_hold(); + + if (c->parent_phases.hold) { + c->parent_phases.hold(obj); + } + + dwc2_update_irq(s); +} + +static void dwc2_reset_exit(Object *obj) +{ + DWC2Class *c = DWC2_GET_CLASS(obj); + DWC2State *s = DWC2_USB(obj); + + trace_usb_dwc2_reset_exit(); + + if (c->parent_phases.exit) { + c->parent_phases.exit(obj); + } + + s->hprt0 = HPRT0_PWR; + if (s->uport.dev && s->uport.dev->attached) { + usb_attach(&s->uport); + usb_device_reset(s->uport.dev); + } +} + +static void dwc2_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + DWC2State *s = DWC2_USB(dev); + Object *obj; + Error *err = NULL; + + obj = object_property_get_link(OBJECT(dev), "dma-mr", &err); + if (err) { + error_setg(errp, "dwc2: required dma-mr link not found: %s", + error_get_pretty(err)); + return; + } + assert(obj != NULL); + + s->dma_mr = MEMORY_REGION(obj); + address_space_init(&s->dma_as, s->dma_mr, "dwc2"); + + usb_bus_new(&s->bus, sizeof(s->bus), &dwc2_bus_ops, dev); + usb_register_port(&s->bus, &s->uport, s, 0, &dwc2_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL | + (s->usb_version == 2 ? USB_SPEED_MASK_HIGH : 0)); + s->uport.dev = 0; + + s->usb_frame_time = NANOSECONDS_PER_SECOND / 1000; /* 1000000 */ + if (NANOSECONDS_PER_SECOND >= USB_HZ_FS) { + s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_FS; /* 83.3 */ + } else { + s->usb_bit_time = 1; + } + + s->fi = USB_FRMINTVL - 1; + s->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, dwc2_frame_boundary, s); + s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, dwc2_work_timer, s); + s->async_bh = qemu_bh_new(dwc2_work_bh, s); + + sysbus_init_irq(sbd, &s->irq); +} + +static void dwc2_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DWC2State *s = DWC2_USB(obj); + + memory_region_init(&s->container, obj, "dwc2", DWC2_MMIO_SIZE); + sysbus_init_mmio(sbd, &s->container); + + memory_region_init_io(&s->hsotg, obj, &dwc2_mmio_hsotg_ops, s, + "dwc2-io", 4 * KiB); + memory_region_add_subregion(&s->container, 0x0000, &s->hsotg); + + memory_region_init_io(&s->fifos, obj, &dwc2_mmio_hreg2_ops, s, + "dwc2-fifo", 64 * KiB); + memory_region_add_subregion(&s->container, 0x1000, &s->fifos); +} + +static const VMStateDescription vmstate_dwc2_state_packet = { + .name = "dwc2/packet", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(devadr, DWC2Packet), + VMSTATE_UINT32(epnum, DWC2Packet), + VMSTATE_UINT32(epdir, DWC2Packet), + VMSTATE_UINT32(mps, DWC2Packet), + VMSTATE_UINT32(pid, DWC2Packet), + VMSTATE_UINT32(index, DWC2Packet), + VMSTATE_UINT32(pcnt, DWC2Packet), + VMSTATE_UINT32(len, DWC2Packet), + VMSTATE_INT32(async, DWC2Packet), + VMSTATE_BOOL(small, DWC2Packet), + VMSTATE_BOOL(needs_service, DWC2Packet), + VMSTATE_END_OF_LIST() + }, +}; + +const VMStateDescription vmstate_dwc2_state = { + .name = "dwc2", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(glbreg, DWC2State, + DWC2_GLBREG_SIZE / sizeof(uint32_t)), + VMSTATE_UINT32_ARRAY(fszreg, DWC2State, + DWC2_FSZREG_SIZE / sizeof(uint32_t)), + VMSTATE_UINT32_ARRAY(hreg0, DWC2State, + DWC2_HREG0_SIZE / sizeof(uint32_t)), + VMSTATE_UINT32_ARRAY(hreg1, DWC2State, + DWC2_HREG1_SIZE / sizeof(uint32_t)), + VMSTATE_UINT32_ARRAY(pcgreg, DWC2State, + DWC2_PCGREG_SIZE / sizeof(uint32_t)), + + VMSTATE_TIMER_PTR(eof_timer, DWC2State), + VMSTATE_TIMER_PTR(frame_timer, DWC2State), + VMSTATE_INT64(sof_time, DWC2State), + VMSTATE_INT64(usb_frame_time, DWC2State), + VMSTATE_INT64(usb_bit_time, DWC2State), + VMSTATE_UINT32(usb_version, DWC2State), + VMSTATE_UINT16(frame_number, DWC2State), + VMSTATE_UINT16(fi, DWC2State), + VMSTATE_UINT16(next_chan, DWC2State), + VMSTATE_BOOL(working, DWC2State), + + VMSTATE_STRUCT_ARRAY(packet, DWC2State, DWC2_NB_CHAN, 1, + vmstate_dwc2_state_packet, DWC2Packet), + VMSTATE_UINT8_2DARRAY(usb_buf, DWC2State, DWC2_NB_CHAN, + DWC2_MAX_XFER_SIZE), + + VMSTATE_END_OF_LIST() + } +}; + +static Property dwc2_usb_properties[] = { + DEFINE_PROP_UINT32("usb_version", DWC2State, usb_version, 2), + DEFINE_PROP_END_OF_LIST(), +}; + +static void dwc2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + DWC2Class *c = DWC2_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + dc->realize = dwc2_realize; + dc->vmsd = &vmstate_dwc2_state; + set_bit(DEVICE_CATEGORY_USB, dc->categories); + device_class_set_props(dc, dwc2_usb_properties); + resettable_class_set_parent_phases(rc, dwc2_reset_enter, dwc2_reset_hold, + dwc2_reset_exit, &c->parent_phases); +} + +static const TypeInfo dwc2_usb_type_info = { + .name = TYPE_DWC2_USB, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(DWC2State), + .instance_init = dwc2_init, + .class_size = sizeof(DWC2Class), + .class_init = dwc2_class_init, +}; + +static void dwc2_usb_register_types(void) +{ + type_register_static(&dwc2_usb_type_info); +} + +type_init(dwc2_usb_register_types) diff --git a/hw/usb/trace-events b/hw/usb/trace-events index 1c24d82c09..5817ce4421 100644 --- a/hw/usb/trace-events +++ b/hw/usb/trace-events @@ -176,6 +176,56 @@ usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d" usb_xhci_unimplemented(const char *item, int nr) "%s (0x%x)" usb_xhci_enforced_limit(const char *item) "%s" +# hcd-dwc2.c +usb_dwc2_update_irq(uint32_t level) "level=%d" +usb_dwc2_raise_global_irq(uint32_t intr) "0x%08x" +usb_dwc2_lower_global_irq(uint32_t intr) "0x%08x" +usb_dwc2_raise_host_irq(uint32_t intr) "0x%04x" +usb_dwc2_lower_host_irq(uint32_t intr) "0x%04x" +usb_dwc2_sof(int64_t next) "next SOF %" PRId64 +usb_dwc2_bus_start(void) "start SOFs" +usb_dwc2_bus_stop(void) "stop SOFs" +usb_dwc2_find_device(uint8_t addr) "%d" +usb_dwc2_port_disabled(uint32_t pnum) "port %d disabled" +usb_dwc2_device_found(uint32_t pnum) "device found on port %d" +usb_dwc2_device_not_found(void) "device not found" +usb_dwc2_handle_packet(uint32_t chan, void *dev, void *pkt, uint32_t ep, const char *type, const char *dir, uint32_t mps, uint32_t len, uint32_t pcnt) "ch %d dev %p pkt %p ep %d type %s dir %s mps %d len %d pcnt %d" +usb_dwc2_memory_read(uint32_t addr, uint32_t len) "addr %d len %d" +usb_dwc2_packet_status(const char *status, uint32_t len) "status %s len %d" +usb_dwc2_packet_error(const char *status) "ERROR %s" +usb_dwc2_async_packet(void *pkt, uint32_t chan, void *dev, uint32_t ep, const char *dir, uint32_t len) "pkt %p ch %d dev %p ep %d %s len %d" +usb_dwc2_memory_write(uint32_t addr, uint32_t len) "addr %d len %d" +usb_dwc2_packet_done(const char *status, uint32_t actual, uint32_t len, uint32_t pcnt) "status %s actual %d len %d pcnt %d" +usb_dwc2_packet_next(const char *status, uint32_t len, uint32_t pcnt) "status %s len %d pcnt %d" +usb_dwc2_attach(void *port) "port %p" +usb_dwc2_attach_speed(const char *speed) "%s-speed device attached" +usb_dwc2_detach(void *port) "port %p" +usb_dwc2_child_detach(void *port, void *child) "port %p child %p" +usb_dwc2_wakeup(void *port) "port %p" +usb_dwc2_async_packet_complete(void *port, void *pkt, uint32_t chan, void *dev, uint32_t ep, const char *dir, uint32_t len) "port %p packet %p ch %d dev %p ep %d %s len %d" +usb_dwc2_work_bh(void) "" +usb_dwc2_work_bh_service(uint32_t first, uint32_t current, void *dev, uint32_t ep) "first %d servicing %d dev %p ep %d" +usb_dwc2_work_bh_next(uint32_t chan) "next %d" +usb_dwc2_enable_chan(uint32_t chan, void *dev, void *pkt, uint32_t ep) "ch %d dev %p pkt %p ep %d" +usb_dwc2_glbreg_read(uint64_t addr, const char *reg, uint32_t val) " 0x%04" PRIx64 " %s val 0x%08x" +usb_dwc2_glbreg_write(uint64_t addr, const char *reg, uint64_t val, uint32_t old, uint64_t result) "0x%04" PRIx64 " %s val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64 +usb_dwc2_fszreg_read(uint64_t addr, uint32_t val) " 0x%04" PRIx64 " HPTXFSIZ val 0x%08x" +usb_dwc2_fszreg_write(uint64_t addr, uint64_t val, uint32_t old, uint64_t result) "0x%04" PRIx64 " HPTXFSIZ val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64 +usb_dwc2_hreg0_read(uint64_t addr, const char *reg, uint32_t val) " 0x%04" PRIx64 " %s val 0x%08x" +usb_dwc2_hreg0_write(uint64_t addr, const char *reg, uint64_t val, uint32_t old, uint64_t result) " 0x%04" PRIx64 " %s val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64 +usb_dwc2_hreg1_read(uint64_t addr, const char *reg, uint64_t chan, uint32_t val) " 0x%04" PRIx64 " %s%" PRId64 " val 0x%08x" +usb_dwc2_hreg1_write(uint64_t addr, const char *reg, uint64_t chan, uint64_t val, uint32_t old, uint64_t result) " 0x%04" PRIx64 " %s%" PRId64 " val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64 +usb_dwc2_pcgreg_read(uint64_t addr, const char *reg, uint32_t val) " 0x%04" PRIx64 " %s val 0x%08x" +usb_dwc2_pcgreg_write(uint64_t addr, const char *reg, uint64_t val, uint32_t old, uint64_t result) "0x%04" PRIx64 " %s val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64 +usb_dwc2_hreg2_read(uint64_t addr, uint64_t fifo, uint32_t val) " 0x%04" PRIx64 " FIFO%" PRId64 " val 0x%08x" +usb_dwc2_hreg2_write(uint64_t addr, uint64_t fifo, uint64_t val, uint32_t old, uint64_t result) " 0x%04" PRIx64 " FIFO%" PRId64 " val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64 +usb_dwc2_hreg0_action(const char *s) "%s" +usb_dwc2_wakeup_endpoint(void *ep, uint32_t stream) "endp %p stream %d" +usb_dwc2_work_timer(void) "" +usb_dwc2_reset_enter(void) "=== RESET enter ===" +usb_dwc2_reset_hold(void) "=== RESET hold ===" +usb_dwc2_reset_exit(void) "=== RESET exit ===" + # desc.c usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d" usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d" From 7ad3d51ebb8a522ffcad391c4bef281245739dde Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Wed, 20 May 2020 16:53:47 -0700 Subject: [PATCH 0869/2595] usb: add short-packet handling to usb-storage driver The dwc-hsotg (dwc2) USB host depends on a short packet to indicate the end of an IN transfer. The usb-storage driver currently doesn't provide this, so fix it. I have tested this change rather extensively using a PC emulation with xhci, ehci, and uhci controllers, and have not observed any regressions. Signed-off-by: Paul Zimmerman Message-id: 20200520235349.21215-6-pauldzim@gmail.com Signed-off-by: Peter Maydell --- hw/usb/dev-storage.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 4eba47538d..a5204b6f2a 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -229,6 +229,9 @@ static void usb_msd_copy_data(MSDState *s, USBPacket *p) usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len); s->scsi_len -= len; s->scsi_off += len; + if (len > s->data_len) { + len = s->data_len; + } s->data_len -= len; if (s->scsi_len == 0 || s->data_len == 0) { scsi_req_continue(s->req); @@ -303,6 +306,9 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r if (s->data_len) { int len = (p->iov.size - p->actual_length); usb_packet_skip(p, len); + if (len > s->data_len) { + len = s->data_len; + } s->data_len -= len; } if (s->data_len == 0) { @@ -469,6 +475,9 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) int len = p->iov.size - p->actual_length; if (len) { usb_packet_skip(p, len); + if (len > s->data_len) { + len = s->data_len; + } s->data_len -= len; if (s->data_len == 0) { s->mode = USB_MSDM_CSW; @@ -528,13 +537,17 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) int len = p->iov.size - p->actual_length; if (len) { usb_packet_skip(p, len); + if (len > s->data_len) { + len = s->data_len; + } s->data_len -= len; if (s->data_len == 0) { s->mode = USB_MSDM_CSW; } } } - if (p->actual_length < p->iov.size) { + if (p->actual_length < p->iov.size && (p->short_not_ok || + s->scsi_len >= p->ep->max_packet_size)) { DPRINTF("Deferring packet %p [wait data-in]\n", p); s->packet = p; p->status = USB_RET_ASYNC; From 60bf734e647f8a6e243766929813358c9fcd4335 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Wed, 20 May 2020 16:53:48 -0700 Subject: [PATCH 0870/2595] wire in the dwc-hsotg (dwc2) USB host controller emulation Wire the dwc-hsotg (dwc2) emulation into Qemu Signed-off-by: Paul Zimmerman Reviewed-by: Philippe Mathieu-Daude Message-id: 20200520235349.21215-7-pauldzim@gmail.com Signed-off-by: Peter Maydell --- hw/arm/bcm2835_peripherals.c | 21 ++++++++++++++++++++- include/hw/arm/bcm2835_peripherals.h | 3 ++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index b3e0495040..cca5b5ad04 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -129,6 +129,13 @@ static void bcm2835_peripherals_init(Object *obj) /* Mphi */ sysbus_init_child_obj(obj, "mphi", &s->mphi, sizeof(s->mphi), TYPE_BCM2835_MPHI); + + /* DWC2 */ + sysbus_init_child_obj(obj, "dwc2", &s->dwc2, sizeof(s->dwc2), + TYPE_DWC2_USB); + + object_property_add_const_link(OBJECT(&s->dwc2), "dma-mr", + OBJECT(&s->gpu_bus_mr)); } static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) @@ -377,6 +384,19 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, INTERRUPT_HOSTPORT)); + /* DWC2 */ + object_property_set_bool(OBJECT(&s->dwc2), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, USB_OTG_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dwc2), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->dwc2), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, + INTERRUPT_USB)); + create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40); create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000); create_unimp(s, &s->a2w, "bcm2835-a2w", A2W_OFFSET, 0x1000); @@ -390,7 +410,6 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) create_unimp(s, &s->otp, "bcm2835-otp", OTP_OFFSET, 0x80); create_unimp(s, &s->dbus, "bcm2835-dbus", DBUS_OFFSET, 0x8000); create_unimp(s, &s->ave0, "bcm2835-ave0", AVE0_OFFSET, 0x8000); - create_unimp(s, &s->dwc2, "dwc-usb2", USB_OTG_OFFSET, 0x1000); create_unimp(s, &s->sdramc, "bcm2835-sdramc", SDRAMC_OFFSET, 0x100); } diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h index 7a7a8f6141..48a0ad1633 100644 --- a/include/hw/arm/bcm2835_peripherals.h +++ b/include/hw/arm/bcm2835_peripherals.h @@ -27,6 +27,7 @@ #include "hw/sd/bcm2835_sdhost.h" #include "hw/gpio/bcm2835_gpio.h" #include "hw/timer/bcm2835_systmr.h" +#include "hw/usb/hcd-dwc2.h" #include "hw/misc/unimp.h" #define TYPE_BCM2835_PERIPHERALS "bcm2835-peripherals" @@ -67,7 +68,7 @@ typedef struct BCM2835PeripheralState { UnimplementedDeviceState ave0; UnimplementedDeviceState bscsl; UnimplementedDeviceState smi; - UnimplementedDeviceState dwc2; + DWC2State dwc2; UnimplementedDeviceState sdramc; } BCM2835PeripheralState; From d02ded087030d2b5b5906b127d616acb2a6d1483 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Wed, 20 May 2020 16:53:49 -0700 Subject: [PATCH 0871/2595] raspi2 acceptance test: add test for dwc-hsotg (dwc2) USB host Add a check for functional dwc-hsotg (dwc2) USB host emulation to the Raspi 2 acceptance test Signed-off-by: Paul Zimmerman Reviewed-by: Philippe Mathieu-Daude Message-id: 20200520235349.21215-8-pauldzim@gmail.com Signed-off-by: Peter Maydell --- tests/acceptance/boot_linux_console.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index bbbbd30e48..3f3aa0c854 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -405,13 +405,18 @@ class BootLinuxConsole(LinuxKernelTest): self.vm.set_console() kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + - serial_kernel_cmdline[uart_id]) + serial_kernel_cmdline[uart_id] + + ' root=/dev/mmcblk0p2 rootwait ' + + 'dwc_otg.fiq_fsm_enable=0') self.vm.add_args('-kernel', kernel_path, '-dtb', dtb_path, - '-append', kernel_command_line) + '-append', kernel_command_line, + '-device', 'usb-kbd') self.vm.launch() console_pattern = 'Kernel command line: %s' % kernel_command_line self.wait_for_console_pattern(console_pattern) + console_pattern = 'Product: QEMU USB Keyboard' + self.wait_for_console_pattern(console_pattern) def test_arm_raspi2_uart0(self): """ From d3c8c736f8b4bdd02831076286b1788232f46ced Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 May 2020 15:55:12 +0100 Subject: [PATCH 0872/2595] target/arm: Convert Neon VSHL and VSLI 2-reg-shift insn to decodetree Convert the VSHL and VSLI insns from the Neon 2-registers-and-a-shift group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200522145520.6778-2-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 25 ++++++++++++++++++++++ target/arm/translate-neon.inc.c | 38 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 18 +++++++--------- 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 8af7c53d8b..fcce2edacd 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -201,3 +201,28 @@ VRECPS_fp_3s 1111 001 0 0 . 0 . .... .... 1111 ... 1 .... @3same_fp VRSQRTS_fp_3s 1111 001 0 0 . 1 . .... .... 1111 ... 1 .... @3same_fp VMAXNM_fp_3s 1111 001 1 0 . 0 . .... .... 1111 ... 1 .... @3same_fp VMINNM_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 1 .... @3same_fp + +###################################################################### +# 2-reg-and-shift grouping: +# 1111 001 U 1 D immH:3 immL:3 Vd:4 opc:4 L Q M 1 Vm:4 +###################################################################### +&2reg_shift vm vd q shift size + +@2reg_shl_d .... ... . . . shift:6 .... .... 1 q:1 . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=3 +@2reg_shl_s .... ... . . . 1 shift:5 .... .... 0 q:1 . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=2 +@2reg_shl_h .... ... . . . 01 shift:4 .... .... 0 q:1 . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=1 +@2reg_shl_b .... ... . . . 001 shift:3 .... .... 0 q:1 . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=0 + +VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_d +VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_s +VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_h +VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_b + +VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_d +VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_s +VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_h +VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_b diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 7b19753c8c..7f05323fdf 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1202,3 +1202,41 @@ static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn) DO_3S_FP_PAIR(VPADD, gen_helper_vfp_adds) DO_3S_FP_PAIR(VPMAX, gen_helper_vfp_maxs) DO_3S_FP_PAIR(VPMIN, gen_helper_vfp_mins) + +static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) +{ + /* Handle a 2-reg-shift insn which can be vectorized. */ + int vec_size = a->q ? 16 : 8; + int rd_ofs = neon_reg_offset(a->vd, 0); + int rm_ofs = neon_reg_offset(a->vm, 0); + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vm | a->vd) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size); + return true; +} + +#define DO_2SH(INSN, FUNC) \ + static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ + { \ + return do_vector_2sh(s, a, FUNC); \ + } \ + +DO_2SH(VSHL, tcg_gen_gvec_shli) +DO_2SH(VSLI, gen_gvec_sli) diff --git a/target/arm/translate.c b/target/arm/translate.c index c61180ea61..41fef49dbe 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5294,6 +5294,14 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if ((insn & 0x00380080) != 0) { /* Two registers and shift. */ op = (insn >> 8) & 0xf; + + switch (op) { + case 5: /* VSHL, VSLI */ + return 1; /* handled by decodetree */ + default: + break; + } + if (insn & (1 << 7)) { /* 64-bit shift. */ if (op > 7) { @@ -5387,16 +5395,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) gen_gvec_sri(size, rd_ofs, rm_ofs, shift, vec_size, vec_size); return 0; - - case 5: /* VSHL, VSLI */ - if (u) { /* VSLI */ - gen_gvec_sli(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } else { /* VSHL */ - tcg_gen_gvec_shli(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } - return 0; } if (size == 3) { From 66432d6b8294e3508218b360acfdf7c244eea993 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 May 2020 15:55:13 +0100 Subject: [PATCH 0873/2595] target/arm: Convert Neon VSHR 2-reg-shift insns to decodetree Convert the VSHR 2-reg-shift insns to decodetree. Note that unlike the legacy decoder, we present the right shift amount to the trans_ function as a positive integer. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200522145520.6778-3-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 25 ++++++++++++++++++++ target/arm/translate-neon.inc.c | 41 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 21 +---------------- 3 files changed, 67 insertions(+), 20 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index fcce2edacd..1b877cc68f 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -208,6 +208,21 @@ VMINNM_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 1 .... @3same_fp ###################################################################### &2reg_shift vm vd q shift size +# Right shifts are encoded as N - shift, where N is the element size in bits. +%neon_rshift_i6 16:6 !function=rsub_64 +%neon_rshift_i5 16:5 !function=rsub_32 +%neon_rshift_i4 16:4 !function=rsub_16 +%neon_rshift_i3 16:3 !function=rsub_8 + +@2reg_shr_d .... ... . . . ...... .... .... 1 q:1 . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=3 shift=%neon_rshift_i6 +@2reg_shr_s .... ... . . . 1 ..... .... .... 0 q:1 . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=2 shift=%neon_rshift_i5 +@2reg_shr_h .... ... . . . 01 .... .... .... 0 q:1 . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=1 shift=%neon_rshift_i4 +@2reg_shr_b .... ... . . . 001 ... .... .... 0 q:1 . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=0 shift=%neon_rshift_i3 + @2reg_shl_d .... ... . . . shift:6 .... .... 1 q:1 . . .... \ &2reg_shift vm=%vm_dp vd=%vd_dp size=3 @2reg_shl_s .... ... . . . 1 shift:5 .... .... 0 q:1 . . .... \ @@ -217,6 +232,16 @@ VMINNM_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 1 .... @3same_fp @2reg_shl_b .... ... . . . 001 shift:3 .... .... 0 q:1 . . .... \ &2reg_shift vm=%vm_dp vd=%vd_dp size=0 +VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_d +VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_s +VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_h +VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_b + +VSHR_U_2sh 1111 001 1 1 . ...... .... 0000 . . . 1 .... @2reg_shr_d +VSHR_U_2sh 1111 001 1 1 . ...... .... 0000 . . . 1 .... @2reg_shr_s +VSHR_U_2sh 1111 001 1 1 . ...... .... 0000 . . . 1 .... @2reg_shr_h +VSHR_U_2sh 1111 001 1 1 . ...... .... 0000 . . . 1 .... @2reg_shr_b + VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_d VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_s VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_h diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 7f05323fdf..8693b9aa99 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -31,6 +31,24 @@ static inline int plus1(DisasContext *s, int x) return x + 1; } +static inline int rsub_64(DisasContext *s, int x) +{ + return 64 - x; +} + +static inline int rsub_32(DisasContext *s, int x) +{ + return 32 - x; +} +static inline int rsub_16(DisasContext *s, int x) +{ + return 16 - x; +} +static inline int rsub_8(DisasContext *s, int x) +{ + return 8 - x; +} + /* Include the generated Neon decoder */ #include "decode-neon-dp.inc.c" #include "decode-neon-ls.inc.c" @@ -1240,3 +1258,26 @@ static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) DO_2SH(VSHL, tcg_gen_gvec_shli) DO_2SH(VSLI, gen_gvec_sli) + +static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a) +{ + /* Signed shift out of range results in all-sign-bits */ + a->shift = MIN(a->shift, (8 << a->size) - 1); + return do_vector_2sh(s, a, tcg_gen_gvec_sari); +} + +static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, + int64_t shift, uint32_t oprsz, uint32_t maxsz) +{ + tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0); +} + +static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a) +{ + /* Shift out of range is architecturally valid and results in zero. */ + if (a->shift >= (8 << a->size)) { + return do_vector_2sh(s, a, gen_zero_rd_2sh); + } else { + return do_vector_2sh(s, a, tcg_gen_gvec_shri); + } +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 41fef49dbe..4acc94e3cb 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5296,6 +5296,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) op = (insn >> 8) & 0xf; switch (op) { + case 0: /* VSHR */ case 5: /* VSHL, VSLI */ return 1; /* handled by decodetree */ default: @@ -5330,26 +5331,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } switch (op) { - case 0: /* VSHR */ - /* Right shift comes here negative. */ - shift = -shift; - /* Shifts larger than the element size are architecturally - * valid. Unsigned results in all zeros; signed results - * in all sign bits. - */ - if (!u) { - tcg_gen_gvec_sari(size, rd_ofs, rm_ofs, - MIN(shift, (8 << size) - 1), - vec_size, vec_size); - } else if (shift >= 8 << size) { - tcg_gen_gvec_dup_imm(MO_8, rd_ofs, vec_size, - vec_size, 0); - } else { - tcg_gen_gvec_shri(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } - return 0; - case 1: /* VSRA */ /* Right shift comes here negative. */ shift = -shift; From 434f71ef96d69dbf57d6bb3883a15d2d0b32dea8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 May 2020 15:55:14 +0100 Subject: [PATCH 0874/2595] target/arm: Convert Neon VSRA, VSRI, VRSHR, VRSRA 2-reg-shift insns to decodetree Convert the VSRA, VSRI, VRSHR, VRSRA 2-reg-shift insns to decodetree. (These are the last instructions in the group that are vectorized; the rest all require looping over each element.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200522145520.6778-4-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 35 ++++++++++++++++++++++ target/arm/translate-neon.inc.c | 7 +++++ target/arm/translate.c | 52 +++------------------------------ 3 files changed, 46 insertions(+), 48 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 1b877cc68f..659cf13930 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -242,6 +242,41 @@ VSHR_U_2sh 1111 001 1 1 . ...... .... 0000 . . . 1 .... @2reg_shr_s VSHR_U_2sh 1111 001 1 1 . ...... .... 0000 . . . 1 .... @2reg_shr_h VSHR_U_2sh 1111 001 1 1 . ...... .... 0000 . . . 1 .... @2reg_shr_b +VSRA_S_2sh 1111 001 0 1 . ...... .... 0001 . . . 1 .... @2reg_shr_d +VSRA_S_2sh 1111 001 0 1 . ...... .... 0001 . . . 1 .... @2reg_shr_s +VSRA_S_2sh 1111 001 0 1 . ...... .... 0001 . . . 1 .... @2reg_shr_h +VSRA_S_2sh 1111 001 0 1 . ...... .... 0001 . . . 1 .... @2reg_shr_b + +VSRA_U_2sh 1111 001 1 1 . ...... .... 0001 . . . 1 .... @2reg_shr_d +VSRA_U_2sh 1111 001 1 1 . ...... .... 0001 . . . 1 .... @2reg_shr_s +VSRA_U_2sh 1111 001 1 1 . ...... .... 0001 . . . 1 .... @2reg_shr_h +VSRA_U_2sh 1111 001 1 1 . ...... .... 0001 . . . 1 .... @2reg_shr_b + +VRSHR_S_2sh 1111 001 0 1 . ...... .... 0010 . . . 1 .... @2reg_shr_d +VRSHR_S_2sh 1111 001 0 1 . ...... .... 0010 . . . 1 .... @2reg_shr_s +VRSHR_S_2sh 1111 001 0 1 . ...... .... 0010 . . . 1 .... @2reg_shr_h +VRSHR_S_2sh 1111 001 0 1 . ...... .... 0010 . . . 1 .... @2reg_shr_b + +VRSHR_U_2sh 1111 001 1 1 . ...... .... 0010 . . . 1 .... @2reg_shr_d +VRSHR_U_2sh 1111 001 1 1 . ...... .... 0010 . . . 1 .... @2reg_shr_s +VRSHR_U_2sh 1111 001 1 1 . ...... .... 0010 . . . 1 .... @2reg_shr_h +VRSHR_U_2sh 1111 001 1 1 . ...... .... 0010 . . . 1 .... @2reg_shr_b + +VRSRA_S_2sh 1111 001 0 1 . ...... .... 0011 . . . 1 .... @2reg_shr_d +VRSRA_S_2sh 1111 001 0 1 . ...... .... 0011 . . . 1 .... @2reg_shr_s +VRSRA_S_2sh 1111 001 0 1 . ...... .... 0011 . . . 1 .... @2reg_shr_h +VRSRA_S_2sh 1111 001 0 1 . ...... .... 0011 . . . 1 .... @2reg_shr_b + +VRSRA_U_2sh 1111 001 1 1 . ...... .... 0011 . . . 1 .... @2reg_shr_d +VRSRA_U_2sh 1111 001 1 1 . ...... .... 0011 . . . 1 .... @2reg_shr_s +VRSRA_U_2sh 1111 001 1 1 . ...... .... 0011 . . . 1 .... @2reg_shr_h +VRSRA_U_2sh 1111 001 1 1 . ...... .... 0011 . . . 1 .... @2reg_shr_b + +VSRI_2sh 1111 001 1 1 . ...... .... 0100 . . . 1 .... @2reg_shr_d +VSRI_2sh 1111 001 1 1 . ...... .... 0100 . . . 1 .... @2reg_shr_s +VSRI_2sh 1111 001 1 1 . ...... .... 0100 . . . 1 .... @2reg_shr_h +VSRI_2sh 1111 001 1 1 . ...... .... 0100 . . . 1 .... @2reg_shr_b + VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_d VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_s VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_h diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 8693b9aa99..2868800059 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1258,6 +1258,13 @@ static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) DO_2SH(VSHL, tcg_gen_gvec_shli) DO_2SH(VSLI, gen_gvec_sli) +DO_2SH(VSRI, gen_gvec_sri) +DO_2SH(VSRA_S, gen_gvec_ssra) +DO_2SH(VSRA_U, gen_gvec_usra) +DO_2SH(VRSHR_S, gen_gvec_srshr) +DO_2SH(VRSHR_U, gen_gvec_urshr) +DO_2SH(VRSRA_S, gen_gvec_srsra) +DO_2SH(VRSRA_U, gen_gvec_ursra) static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a) { diff --git a/target/arm/translate.c b/target/arm/translate.c index 4acc94e3cb..2d08c64483 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5297,6 +5297,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) switch (op) { case 0: /* VSHR */ + case 1: /* VSRA */ + case 2: /* VRSHR */ + case 3: /* VRSRA */ + case 4: /* VSRI */ case 5: /* VSHL, VSLI */ return 1; /* handled by decodetree */ default: @@ -5330,54 +5334,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) shift = shift - (1 << (size + 3)); } - switch (op) { - case 1: /* VSRA */ - /* Right shift comes here negative. */ - shift = -shift; - if (u) { - gen_gvec_usra(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } else { - gen_gvec_ssra(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } - return 0; - - case 2: /* VRSHR */ - /* Right shift comes here negative. */ - shift = -shift; - if (u) { - gen_gvec_urshr(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } else { - gen_gvec_srshr(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } - return 0; - - case 3: /* VRSRA */ - /* Right shift comes here negative. */ - shift = -shift; - if (u) { - gen_gvec_ursra(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } else { - gen_gvec_srsra(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } - return 0; - - case 4: /* VSRI */ - if (!u) { - return 1; - } - /* Right shift comes here negative. */ - shift = -shift; - gen_gvec_sri(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - return 0; - } - if (size == 3) { count = q + 1; } else { From 37bfce81b10450071193c8495a07f182ec652e2a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 May 2020 15:55:15 +0100 Subject: [PATCH 0875/2595] target/arm: Convert VQSHLU, VQSHL 2-reg-shift insns to decodetree Convert the VQSHLU and QVSHL 2-reg-shift insns to decodetree. These are the last of the simple shift-by-immediate insns. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200522145520.6778-5-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 15 +++++ target/arm/translate-neon.inc.c | 108 +++++++++++++++++++++++++++++++ target/arm/translate.c | 110 +------------------------------- 3 files changed, 126 insertions(+), 107 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 659cf13930..66c41a53e5 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -286,3 +286,18 @@ VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_d VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_s VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_h VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_b + +VQSHLU_64_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_d +VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_s +VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_h +VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_b + +VQSHL_S_64_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d +VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_s +VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_h +VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_b + +VQSHL_U_64_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d +VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_s +VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_h +VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_b diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 2868800059..baa985b16c 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1288,3 +1288,111 @@ static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a) return do_vector_2sh(s, a, tcg_gen_gvec_shri); } } + +static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, + NeonGenTwo64OpEnvFn *fn) +{ + /* + * 2-reg-and-shift operations, size == 3 case, where the + * function needs to be passed cpu_env. + */ + TCGv_i64 constimm; + int pass; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vm | a->vd) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + /* + * To avoid excessive duplication of ops we implement shift + * by immediate using the variable shift operations. + */ + constimm = tcg_const_i64(dup_const(a->size, a->shift)); + + for (pass = 0; pass < a->q + 1; pass++) { + TCGv_i64 tmp = tcg_temp_new_i64(); + + neon_load_reg64(tmp, a->vm + pass); + fn(tmp, cpu_env, tmp, constimm); + neon_store_reg64(tmp, a->vd + pass); + } + tcg_temp_free_i64(constimm); + return true; +} + +static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, + NeonGenTwoOpEnvFn *fn) +{ + /* + * 2-reg-and-shift operations, size < 3 case, where the + * helper needs to be passed cpu_env. + */ + TCGv_i32 constimm; + int pass; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vm | a->vd) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + /* + * To avoid excessive duplication of ops we implement shift + * by immediate using the variable shift operations. + */ + constimm = tcg_const_i32(dup_const(a->size, a->shift)); + + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + TCGv_i32 tmp = neon_load_reg(a->vm, pass); + fn(tmp, cpu_env, tmp, constimm); + neon_store_reg(a->vd, pass, tmp); + } + tcg_temp_free_i32(constimm); + return true; +} + +#define DO_2SHIFT_ENV(INSN, FUNC) \ + static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \ + { \ + return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64); \ + } \ + static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ + { \ + static NeonGenTwoOpEnvFn * const fns[] = { \ + gen_helper_neon_##FUNC##8, \ + gen_helper_neon_##FUNC##16, \ + gen_helper_neon_##FUNC##32, \ + }; \ + assert(a->size < ARRAY_SIZE(fns)); \ + return do_2shift_env_32(s, a, fns[a->size]); \ + } + +DO_2SHIFT_ENV(VQSHLU, qshlu_s) +DO_2SHIFT_ENV(VQSHL_U, qshl_u) +DO_2SHIFT_ENV(VQSHL_S, qshl_s) diff --git a/target/arm/translate.c b/target/arm/translate.c index 2d08c64483..c32a16085c 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3011,29 +3011,6 @@ static inline void gen_neon_rsb(int size, TCGv_i32 t0, TCGv_i32 t1) } } -#define GEN_NEON_INTEGER_OP_ENV(name) do { \ - switch ((size << 1) | u) { \ - case 0: \ - gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \ - break; \ - case 1: \ - gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \ - break; \ - case 2: \ - gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \ - break; \ - case 3: \ - gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \ - break; \ - case 4: \ - gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \ - break; \ - case 5: \ - gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \ - break; \ - default: return 1; \ - }} while (0) - static TCGv_i32 neon_load_scratch(int scratch) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -5252,7 +5229,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int size; int shift; int pass; - int count; int u; int vec_size; uint32_t imm; @@ -5302,6 +5278,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case 3: /* VRSRA */ case 4: /* VSRI */ case 5: /* VSHL, VSLI */ + case 6: /* VQSHLU */ + case 7: /* VQSHL */ return 1; /* handled by decodetree */ default: break; @@ -5319,89 +5297,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) size--; } shift = (insn >> 16) & ((1 << (3 + size)) - 1); - if (op < 8) { - /* Shift by immediate: - VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */ - if (q && ((rd | rm) & 1)) { - return 1; - } - if (!u && (op == 4 || op == 6)) { - return 1; - } - /* Right shifts are encoded as N - shift, where N is the - element size in bits. */ - if (op <= 4) { - shift = shift - (1 << (size + 3)); - } - - if (size == 3) { - count = q + 1; - } else { - count = q ? 4: 2; - } - - /* To avoid excessive duplication of ops we implement shift - * by immediate using the variable shift operations. - */ - imm = dup_const(size, shift); - - for (pass = 0; pass < count; pass++) { - if (size == 3) { - neon_load_reg64(cpu_V0, rm + pass); - tcg_gen_movi_i64(cpu_V1, imm); - switch (op) { - case 6: /* VQSHLU */ - gen_helper_neon_qshlu_s64(cpu_V0, cpu_env, - cpu_V0, cpu_V1); - break; - case 7: /* VQSHL */ - if (u) { - gen_helper_neon_qshl_u64(cpu_V0, cpu_env, - cpu_V0, cpu_V1); - } else { - gen_helper_neon_qshl_s64(cpu_V0, cpu_env, - cpu_V0, cpu_V1); - } - break; - default: - g_assert_not_reached(); - } - neon_store_reg64(cpu_V0, rd + pass); - } else { /* size < 3 */ - /* Operands in T0 and T1. */ - tmp = neon_load_reg(rm, pass); - tmp2 = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp2, imm); - switch (op) { - case 6: /* VQSHLU */ - switch (size) { - case 0: - gen_helper_neon_qshlu_s8(tmp, cpu_env, - tmp, tmp2); - break; - case 1: - gen_helper_neon_qshlu_s16(tmp, cpu_env, - tmp, tmp2); - break; - case 2: - gen_helper_neon_qshlu_s32(tmp, cpu_env, - tmp, tmp2); - break; - default: - abort(); - } - break; - case 7: /* VQSHL */ - GEN_NEON_INTEGER_OP_ENV(qshl); - break; - default: - g_assert_not_reached(); - } - tcg_temp_free_i32(tmp2); - neon_store_reg(rd, pass, tmp); - } - } /* for pass */ - } else if (op < 10) { + if (op < 10) { /* Shift by immediate and narrow: VSHRN, VRSHRN, VQSHRN, VQRSHRN. */ int input_unsigned = (op == 8) ? !u : u; From 712182d340e33c2ce86143f25fb2f04ae23d90de Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 May 2020 15:55:16 +0100 Subject: [PATCH 0876/2595] target/arm: Convert Neon narrowing shifts with op==8 to decodetree Convert the Neon narrowing shifts where op==8 to decodetree: * VSHRN * VRSHRN * VQSHRUN * VQRSHRUN Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200522145520.6778-6-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 27 ++++++ target/arm/translate-neon.inc.c | 167 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 1 + 3 files changed, 195 insertions(+) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 66c41a53e5..8161995aee 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -232,6 +232,17 @@ VMINNM_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 1 .... @3same_fp @2reg_shl_b .... ... . . . 001 shift:3 .... .... 0 q:1 . . .... \ &2reg_shift vm=%vm_dp vd=%vd_dp size=0 +# Narrowing right shifts: here the Q bit is part of the opcode decode +@2reg_shrn_d .... ... . . . 1 ..... .... .... 0 . . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=3 q=0 \ + shift=%neon_rshift_i5 +@2reg_shrn_s .... ... . . . 01 .... .... .... 0 . . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=2 q=0 \ + shift=%neon_rshift_i4 +@2reg_shrn_h .... ... . . . 001 ... .... .... 0 . . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=1 q=0 \ + shift=%neon_rshift_i3 + VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_d VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_s VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_h @@ -301,3 +312,19 @@ VQSHL_U_64_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_s VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_h VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_b + +VSHRN_64_2sh 1111 001 0 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_d +VSHRN_32_2sh 1111 001 0 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_s +VSHRN_16_2sh 1111 001 0 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_h + +VRSHRN_64_2sh 1111 001 0 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_d +VRSHRN_32_2sh 1111 001 0 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_s +VRSHRN_16_2sh 1111 001 0 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_h + +VQSHRUN_64_2sh 1111 001 1 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_d +VQSHRUN_32_2sh 1111 001 1 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_s +VQSHRUN_16_2sh 1111 001 1 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_h + +VQRSHRUN_64_2sh 1111 001 1 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_d +VQRSHRUN_32_2sh 1111 001 1 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_s +VQRSHRUN_16_2sh 1111 001 1 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_h diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index baa985b16c..fe3fb7f62f 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1396,3 +1396,170 @@ static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, DO_2SHIFT_ENV(VQSHLU, qshlu_s) DO_2SHIFT_ENV(VQSHL_U, qshl_u) DO_2SHIFT_ENV(VQSHL_S, qshl_s) + +static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, + NeonGenTwo64OpFn *shiftfn, + NeonGenNarrowEnvFn *narrowfn) +{ + /* 2-reg-and-shift narrowing-shift operations, size == 3 case */ + TCGv_i64 constimm, rm1, rm2; + TCGv_i32 rd; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (a->vm & 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + /* + * This is always a right shift, and the shiftfn is always a + * left-shift helper, which thus needs the negated shift count. + */ + constimm = tcg_const_i64(-a->shift); + rm1 = tcg_temp_new_i64(); + rm2 = tcg_temp_new_i64(); + + /* Load both inputs first to avoid potential overwrite if rm == rd */ + neon_load_reg64(rm1, a->vm); + neon_load_reg64(rm2, a->vm + 1); + + shiftfn(rm1, rm1, constimm); + rd = tcg_temp_new_i32(); + narrowfn(rd, cpu_env, rm1); + neon_store_reg(a->vd, 0, rd); + + shiftfn(rm2, rm2, constimm); + rd = tcg_temp_new_i32(); + narrowfn(rd, cpu_env, rm2); + neon_store_reg(a->vd, 1, rd); + + tcg_temp_free_i64(rm1); + tcg_temp_free_i64(rm2); + tcg_temp_free_i64(constimm); + + return true; +} + +static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, + NeonGenTwoOpFn *shiftfn, + NeonGenNarrowEnvFn *narrowfn) +{ + /* 2-reg-and-shift narrowing-shift operations, size < 3 case */ + TCGv_i32 constimm, rm1, rm2, rm3, rm4; + TCGv_i64 rtmp; + uint32_t imm; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (a->vm & 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + /* + * This is always a right shift, and the shiftfn is always a + * left-shift helper, which thus needs the negated shift count + * duplicated into each lane of the immediate value. + */ + if (a->size == 1) { + imm = (uint16_t)(-a->shift); + imm |= imm << 16; + } else { + /* size == 2 */ + imm = -a->shift; + } + constimm = tcg_const_i32(imm); + + /* Load all inputs first to avoid potential overwrite */ + rm1 = neon_load_reg(a->vm, 0); + rm2 = neon_load_reg(a->vm, 1); + rm3 = neon_load_reg(a->vm + 1, 0); + rm4 = neon_load_reg(a->vm + 1, 1); + rtmp = tcg_temp_new_i64(); + + shiftfn(rm1, rm1, constimm); + shiftfn(rm2, rm2, constimm); + + tcg_gen_concat_i32_i64(rtmp, rm1, rm2); + tcg_temp_free_i32(rm2); + + narrowfn(rm1, cpu_env, rtmp); + neon_store_reg(a->vd, 0, rm1); + + shiftfn(rm3, rm3, constimm); + shiftfn(rm4, rm4, constimm); + tcg_temp_free_i32(constimm); + + tcg_gen_concat_i32_i64(rtmp, rm3, rm4); + tcg_temp_free_i32(rm4); + + narrowfn(rm3, cpu_env, rtmp); + tcg_temp_free_i64(rtmp); + neon_store_reg(a->vd, 1, rm3); + return true; +} + +#define DO_2SN_64(INSN, FUNC, NARROWFUNC) \ + static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ + { \ + return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC); \ + } +#define DO_2SN_32(INSN, FUNC, NARROWFUNC) \ + static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ + { \ + return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC); \ + } + +static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) +{ + tcg_gen_extrl_i64_i32(dest, src); +} + +static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) +{ + gen_helper_neon_narrow_u16(dest, src); +} + +static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) +{ + gen_helper_neon_narrow_u8(dest, src); +} + +DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32) +DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16) +DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8) + +DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32) +DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16) +DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8) + +DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32) +DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16) +DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8) + +DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32) +DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16) +DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8) diff --git a/target/arm/translate.c b/target/arm/translate.c index c32a16085c..11330b9296 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5280,6 +5280,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case 5: /* VSHL, VSLI */ case 6: /* VQSHLU */ case 7: /* VQSHL */ + case 8: /* VSHRN, VRSHRN, VQSHRUN, VQRSHRUN */ return 1; /* handled by decodetree */ default: break; From b4a3a77bb7a0dff1cc5673fe3be467d9e3635d44 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 May 2020 15:55:17 +0100 Subject: [PATCH 0877/2595] target/arm: Convert Neon narrowing shifts with op==9 to decodetree Convert the remaining Neon narrowing shifts to decodetree: * VQSHRN * VQRSHRN Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200522145520.6778-7-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 20 ++++++ target/arm/translate-neon.inc.c | 15 +++++ target/arm/translate.c | 110 +------------------------------- 3 files changed, 37 insertions(+), 108 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 8161995aee..79d0bfdd70 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -328,3 +328,23 @@ VQSHRUN_16_2sh 1111 001 1 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_h VQRSHRUN_64_2sh 1111 001 1 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_d VQRSHRUN_32_2sh 1111 001 1 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_s VQRSHRUN_16_2sh 1111 001 1 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_h + +# VQSHRN with signed input +VQSHRN_S64_2sh 1111 001 0 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_d +VQSHRN_S32_2sh 1111 001 0 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_s +VQSHRN_S16_2sh 1111 001 0 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_h + +# VQRSHRN with signed input +VQRSHRN_S64_2sh 1111 001 0 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_d +VQRSHRN_S32_2sh 1111 001 0 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_s +VQRSHRN_S16_2sh 1111 001 0 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_h + +# VQSHRN with unsigned input +VQSHRN_U64_2sh 1111 001 1 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_d +VQSHRN_U32_2sh 1111 001 1 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_s +VQSHRN_U16_2sh 1111 001 1 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_h + +# VQRSHRN with unsigned input +VQRSHRN_U64_2sh 1111 001 1 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_d +VQRSHRN_U32_2sh 1111 001 1 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_s +VQRSHRN_U16_2sh 1111 001 1 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_h diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index fe3fb7f62f..562470ca08 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1563,3 +1563,18 @@ DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8) DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32) DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16) DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8) +DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32) +DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16) +DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8) + +DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32) +DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16) +DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8) + +DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32) +DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16) +DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8) + +DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32) +DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16) +DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8) diff --git a/target/arm/translate.c b/target/arm/translate.c index 11330b9296..883c1a29c7 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3201,40 +3201,6 @@ static inline void gen_neon_unarrow_sats(int size, TCGv_i32 dest, TCGv_i64 src) } } -static inline void gen_neon_shift_narrow(int size, TCGv_i32 var, TCGv_i32 shift, - int q, int u) -{ - if (q) { - if (u) { - switch (size) { - case 1: gen_helper_neon_rshl_u16(var, var, shift); break; - case 2: gen_helper_neon_rshl_u32(var, var, shift); break; - default: abort(); - } - } else { - switch (size) { - case 1: gen_helper_neon_rshl_s16(var, var, shift); break; - case 2: gen_helper_neon_rshl_s32(var, var, shift); break; - default: abort(); - } - } - } else { - if (u) { - switch (size) { - case 1: gen_helper_neon_shl_u16(var, var, shift); break; - case 2: gen_ushl_i32(var, var, shift); break; - default: abort(); - } - } else { - switch (size) { - case 1: gen_helper_neon_shl_s16(var, var, shift); break; - case 2: gen_sshl_i32(var, var, shift); break; - default: abort(); - } - } - } -} - static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u) { if (u) { @@ -5281,6 +5247,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case 6: /* VQSHLU */ case 7: /* VQSHL */ case 8: /* VSHRN, VRSHRN, VQSHRUN, VQRSHRUN */ + case 9: /* VQSHRN, VQRSHRN */ return 1; /* handled by decodetree */ default: break; @@ -5298,80 +5265,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) size--; } shift = (insn >> 16) & ((1 << (3 + size)) - 1); - if (op < 10) { - /* Shift by immediate and narrow: - VSHRN, VRSHRN, VQSHRN, VQRSHRN. */ - int input_unsigned = (op == 8) ? !u : u; - if (rm & 1) { - return 1; - } - shift = shift - (1 << (size + 3)); - size++; - if (size == 3) { - tmp64 = tcg_const_i64(shift); - neon_load_reg64(cpu_V0, rm); - neon_load_reg64(cpu_V1, rm + 1); - for (pass = 0; pass < 2; pass++) { - TCGv_i64 in; - if (pass == 0) { - in = cpu_V0; - } else { - in = cpu_V1; - } - if (q) { - if (input_unsigned) { - gen_helper_neon_rshl_u64(cpu_V0, in, tmp64); - } else { - gen_helper_neon_rshl_s64(cpu_V0, in, tmp64); - } - } else { - if (input_unsigned) { - gen_ushl_i64(cpu_V0, in, tmp64); - } else { - gen_sshl_i64(cpu_V0, in, tmp64); - } - } - tmp = tcg_temp_new_i32(); - gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0); - neon_store_reg(rd, pass, tmp); - } /* for pass */ - tcg_temp_free_i64(tmp64); - } else { - if (size == 1) { - imm = (uint16_t)shift; - imm |= imm << 16; - } else { - /* size == 2 */ - imm = (uint32_t)shift; - } - tmp2 = tcg_const_i32(imm); - tmp4 = neon_load_reg(rm + 1, 0); - tmp5 = neon_load_reg(rm + 1, 1); - for (pass = 0; pass < 2; pass++) { - if (pass == 0) { - tmp = neon_load_reg(rm, 0); - } else { - tmp = tmp4; - } - gen_neon_shift_narrow(size, tmp, tmp2, q, - input_unsigned); - if (pass == 0) { - tmp3 = neon_load_reg(rm, 1); - } else { - tmp3 = tmp5; - } - gen_neon_shift_narrow(size, tmp3, tmp2, q, - input_unsigned); - tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp3); - tmp = tcg_temp_new_i32(); - gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0); - neon_store_reg(rd, pass, tmp); - } /* for pass */ - tcg_temp_free_i32(tmp2); - } - } else if (op == 10) { + if (op == 10) { /* VSHLL, VMOVL */ if (q || (rd & 1)) { return 1; From 968bf842742a5ffbb0041cb31089e61a9f7a833d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 May 2020 15:55:18 +0100 Subject: [PATCH 0878/2595] target/arm: Convert Neon VSHLL, VMOVL to decodetree Convert the VSHLL and VMOVL insns from the 2-reg-shift group to decodetree. Since the loop always has two passes, we unroll it to avoid the awkward reassignment of one TCGv to another. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200522145520.6778-8-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 16 +++++++ target/arm/translate-neon.inc.c | 81 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 46 +------------------ 3 files changed, 99 insertions(+), 44 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 79d0bfdd70..3dde699e97 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -243,6 +243,14 @@ VMINNM_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 1 .... @3same_fp &2reg_shift vm=%vm_dp vd=%vd_dp size=1 q=0 \ shift=%neon_rshift_i3 +# Long left shifts: again Q is part of opcode decode +@2reg_shll_s .... ... . . . 1 shift:5 .... .... 0 . . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=2 q=0 +@2reg_shll_h .... ... . . . 01 shift:4 .... .... 0 . . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=1 q=0 +@2reg_shll_b .... ... . . . 001 shift:3 .... .... 0 . . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=0 q=0 + VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_d VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_s VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_h @@ -348,3 +356,11 @@ VQSHRN_U16_2sh 1111 001 1 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_h VQRSHRN_U64_2sh 1111 001 1 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_d VQRSHRN_U32_2sh 1111 001 1 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_s VQRSHRN_U16_2sh 1111 001 1 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_h + +VSHLL_S_2sh 1111 001 0 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_s +VSHLL_S_2sh 1111 001 0 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_h +VSHLL_S_2sh 1111 001 0 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_b + +VSHLL_U_2sh 1111 001 1 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_s +VSHLL_U_2sh 1111 001 1 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_h +VSHLL_U_2sh 1111 001 1 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_b diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 562470ca08..3d566044f3 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1578,3 +1578,84 @@ DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8) DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32) DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16) DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8) + +static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, + NeonGenWidenFn *widenfn, bool u) +{ + TCGv_i64 tmp; + TCGv_i32 rm0, rm1; + uint64_t widen_mask = 0; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (a->vd & 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + /* + * This is a widen-and-shift operation. The shift is always less + * than the width of the source type, so after widening the input + * vector we can simply shift the whole 64-bit widened register, + * and then clear the potential overflow bits resulting from left + * bits of the narrow input appearing as right bits of the left + * neighbour narrow input. Calculate a mask of bits to clear. + */ + if ((a->shift != 0) && (a->size < 2 || u)) { + int esize = 8 << a->size; + widen_mask = MAKE_64BIT_MASK(0, esize); + widen_mask >>= esize - a->shift; + widen_mask = dup_const(a->size + 1, widen_mask); + } + + rm0 = neon_load_reg(a->vm, 0); + rm1 = neon_load_reg(a->vm, 1); + tmp = tcg_temp_new_i64(); + + widenfn(tmp, rm0); + if (a->shift != 0) { + tcg_gen_shli_i64(tmp, tmp, a->shift); + tcg_gen_andi_i64(tmp, tmp, ~widen_mask); + } + neon_store_reg64(tmp, a->vd); + + widenfn(tmp, rm1); + if (a->shift != 0) { + tcg_gen_shli_i64(tmp, tmp, a->shift); + tcg_gen_andi_i64(tmp, tmp, ~widen_mask); + } + neon_store_reg64(tmp, a->vd + 1); + tcg_temp_free_i64(tmp); + return true; +} + +static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a) +{ + NeonGenWidenFn *widenfn[] = { + gen_helper_neon_widen_s8, + gen_helper_neon_widen_s16, + tcg_gen_ext_i32_i64, + }; + return do_vshll_2sh(s, a, widenfn[a->size], false); +} + +static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) +{ + NeonGenWidenFn *widenfn[] = { + gen_helper_neon_widen_u8, + gen_helper_neon_widen_u16, + tcg_gen_extu_i32_i64, + }; + return do_vshll_2sh(s, a, widenfn[a->size], true); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 883c1a29c7..a9f52049e7 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5248,6 +5248,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case 7: /* VQSHL */ case 8: /* VSHRN, VRSHRN, VQSHRUN, VQRSHRUN */ case 9: /* VQSHRN, VQRSHRN */ + case 10: /* VSHLL, including VMOVL */ return 1; /* handled by decodetree */ default: break; @@ -5265,50 +5266,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) size--; } shift = (insn >> 16) & ((1 << (3 + size)) - 1); - if (op == 10) { - /* VSHLL, VMOVL */ - if (q || (rd & 1)) { - return 1; - } - tmp = neon_load_reg(rm, 0); - tmp2 = neon_load_reg(rm, 1); - for (pass = 0; pass < 2; pass++) { - if (pass == 1) - tmp = tmp2; - - gen_neon_widen(cpu_V0, tmp, size, u); - - if (shift != 0) { - /* The shift is less than the width of the source - type, so we can just shift the whole register. */ - tcg_gen_shli_i64(cpu_V0, cpu_V0, shift); - /* Widen the result of shift: we need to clear - * the potential overflow bits resulting from - * left bits of the narrow input appearing as - * right bits of left the neighbour narrow - * input. */ - if (size < 2 || !u) { - uint64_t imm64; - if (size == 0) { - imm = (0xffu >> (8 - shift)); - imm |= imm << 16; - } else if (size == 1) { - imm = 0xffff >> (16 - shift); - } else { - /* size == 2 */ - imm = 0xffffffff >> (32 - shift); - } - if (size < 2) { - imm64 = imm | (((uint64_t)imm) << 32); - } else { - imm64 = imm; - } - tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64); - } - } - neon_store_reg64(cpu_V0, rd + pass); - } - } else if (op >= 14) { + if (op >= 14) { /* VCVT fixed-point. */ TCGv_ptr fpst; TCGv_i32 shiftv; From 3da26f11711caeaa18318b6afa14dfb81d7650ab Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 May 2020 15:55:19 +0100 Subject: [PATCH 0879/2595] target/arm: Convert VCVT fixed-point ops to decodetree Convert the VCVT fixed-point conversion operations in the Neon 2-regs-and-shift group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200522145520.6778-9-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 11 +++++ target/arm/translate-neon.inc.c | 49 +++++++++++++++++++++ target/arm/translate.c | 75 +-------------------------------- 3 files changed, 62 insertions(+), 73 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 3dde699e97..47a5c90b5d 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -251,6 +251,10 @@ VMINNM_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 1 .... @3same_fp @2reg_shll_b .... ... . . . 001 shift:3 .... .... 0 . . . .... \ &2reg_shift vm=%vm_dp vd=%vd_dp size=0 q=0 +# We use size=0 for fp32 and size=1 for fp16 to match the 3-same encodings. +@2reg_vcvt .... ... . . . 1 ..... .... .... . q:1 . . .... \ + &2reg_shift vm=%vm_dp vd=%vd_dp size=0 shift=%neon_rshift_i5 + VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_d VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_s VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_h @@ -364,3 +368,10 @@ VSHLL_S_2sh 1111 001 0 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_b VSHLL_U_2sh 1111 001 1 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_s VSHLL_U_2sh 1111 001 1 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_h VSHLL_U_2sh 1111 001 1 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_b + +# VCVT fixed<->float conversions +# TODO: FP16 fixed<->float conversions are opc==0b1100 and 0b1101 +VCVT_SF_2sh 1111 001 0 1 . ...... .... 1110 0 . . 1 .... @2reg_vcvt +VCVT_UF_2sh 1111 001 1 1 . ...... .... 1110 0 . . 1 .... @2reg_vcvt +VCVT_FS_2sh 1111 001 0 1 . ...... .... 1111 0 . . 1 .... @2reg_vcvt +VCVT_FU_2sh 1111 001 1 1 . ...... .... 1111 0 . . 1 .... @2reg_vcvt diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 3d566044f3..2a445c7589 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1659,3 +1659,52 @@ static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) }; return do_vshll_2sh(s, a, widenfn[a->size], true); } + +static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, + NeonGenTwoSingleOPFn *fn) +{ + /* FP operations in 2-reg-and-shift group */ + TCGv_i32 tmp, shiftv; + TCGv_ptr fpstatus; + int pass; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vm | a->vd) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fpstatus = get_fpstatus_ptr(1); + shiftv = tcg_const_i32(a->shift); + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + tmp = neon_load_reg(a->vm, pass); + fn(tmp, tmp, shiftv, fpstatus); + neon_store_reg(a->vd, pass, tmp); + } + tcg_temp_free_ptr(fpstatus); + tcg_temp_free_i32(shiftv); + return true; +} + +#define DO_FP_2SH(INSN, FUNC) \ + static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ + { \ + return do_fp_2sh(s, a, FUNC); \ + } + +DO_FP_2SH(VCVT_SF, gen_helper_vfp_sltos) +DO_FP_2SH(VCVT_UF, gen_helper_vfp_ultos) +DO_FP_2SH(VCVT_FS, gen_helper_vfp_tosls_round_to_zero) +DO_FP_2SH(VCVT_FU, gen_helper_vfp_touls_round_to_zero) diff --git a/target/arm/translate.c b/target/arm/translate.c index a9f52049e7..166349ee20 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5193,7 +5193,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int q; int rd, rn, rm, rd_ofs, rn_ofs, rm_ofs; int size; - int shift; int pass; int u; int vec_size; @@ -5234,78 +5233,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 1; } else if (insn & (1 << 4)) { if ((insn & 0x00380080) != 0) { - /* Two registers and shift. */ - op = (insn >> 8) & 0xf; - - switch (op) { - case 0: /* VSHR */ - case 1: /* VSRA */ - case 2: /* VRSHR */ - case 3: /* VRSRA */ - case 4: /* VSRI */ - case 5: /* VSHL, VSLI */ - case 6: /* VQSHLU */ - case 7: /* VQSHL */ - case 8: /* VSHRN, VRSHRN, VQSHRUN, VQRSHRUN */ - case 9: /* VQSHRN, VQRSHRN */ - case 10: /* VSHLL, including VMOVL */ - return 1; /* handled by decodetree */ - default: - break; - } - - if (insn & (1 << 7)) { - /* 64-bit shift. */ - if (op > 7) { - return 1; - } - size = 3; - } else { - size = 2; - while ((insn & (1 << (size + 19))) == 0) - size--; - } - shift = (insn >> 16) & ((1 << (3 + size)) - 1); - if (op >= 14) { - /* VCVT fixed-point. */ - TCGv_ptr fpst; - TCGv_i32 shiftv; - VFPGenFixPointFn *fn; - - if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) { - return 1; - } - - if (!(op & 1)) { - if (u) { - fn = gen_helper_vfp_ultos; - } else { - fn = gen_helper_vfp_sltos; - } - } else { - if (u) { - fn = gen_helper_vfp_touls_round_to_zero; - } else { - fn = gen_helper_vfp_tosls_round_to_zero; - } - } - - /* We have already masked out the must-be-1 top bit of imm6, - * hence this 32-shift where the ARM ARM has 64-imm6. - */ - shift = 32 - shift; - fpst = get_fpstatus_ptr(1); - shiftv = tcg_const_i32(shift); - for (pass = 0; pass < (q ? 4 : 2); pass++) { - TCGv_i32 tmpf = neon_load_reg(rm, pass); - fn(tmpf, tmpf, shiftv, fpst); - neon_store_reg(rd, pass, tmpf); - } - tcg_temp_free_ptr(fpst); - tcg_temp_free_i32(shiftv); - } else { - return 1; - } + /* Two registers and shift: handled by decodetree */ + return 1; } else { /* (insn & 0x00380080) == 0 */ int invert, reg_ofs, vec_size; From 2c35a39eda0b16c2ed85c94cec204bf5efb97812 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 May 2020 15:55:20 +0100 Subject: [PATCH 0880/2595] target/arm: Convert Neon one-register-and-immediate insns to decodetree Convert the insns in the one-register-and-immediate group to decodetree. In the new decode, our asimd_imm_const() function returns a 64-bit value rather than a 32-bit one, which means we don't need to treat cmode=14 op=1 as a special case in the decoder (it is the only encoding where the two halves of the 64-bit value are different). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200522145520.6778-10-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 22 ++++++ target/arm/translate-neon.inc.c | 118 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 101 +-------------------------- 3 files changed, 142 insertions(+), 99 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 47a5c90b5d..bd1b0e13f7 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -375,3 +375,25 @@ VCVT_SF_2sh 1111 001 0 1 . ...... .... 1110 0 . . 1 .... @2reg_vcvt VCVT_UF_2sh 1111 001 1 1 . ...... .... 1110 0 . . 1 .... @2reg_vcvt VCVT_FS_2sh 1111 001 0 1 . ...... .... 1111 0 . . 1 .... @2reg_vcvt VCVT_FU_2sh 1111 001 1 1 . ...... .... 1111 0 . . 1 .... @2reg_vcvt + +###################################################################### +# 1-reg-and-modified-immediate grouping: +# 1111 001 i 1 D 000 imm:3 Vd:4 cmode:4 0 Q op 1 Vm:4 +###################################################################### + +&1reg_imm vd q imm cmode op + +%asimd_imm_value 24:1 16:3 0:4 + +@1reg_imm .... ... . . . ... ... .... .... . q:1 . . .... \ + &1reg_imm imm=%asimd_imm_value vd=%vd_dp + +# The cmode/op bits here decode VORR/VBIC/VMOV/VMNV, but +# not in a way we can conveniently represent in decodetree without +# a lot of repetition: +# VORR: op=0, (cmode & 1) && cmode < 12 +# VBIC: op=1, (cmode & 1) && cmode < 12 +# VMOV: everything else +# So we have a single decode line and check the cmode/op in the +# trans function. +Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 2a445c7589..664d361260 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1708,3 +1708,121 @@ DO_FP_2SH(VCVT_SF, gen_helper_vfp_sltos) DO_FP_2SH(VCVT_UF, gen_helper_vfp_ultos) DO_FP_2SH(VCVT_FS, gen_helper_vfp_tosls_round_to_zero) DO_FP_2SH(VCVT_FU, gen_helper_vfp_touls_round_to_zero) + +static uint64_t asimd_imm_const(uint32_t imm, int cmode, int op) +{ + /* + * Expand the encoded constant. + * Note that cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE. + * We choose to not special-case this and will behave as if a + * valid constant encoding of 0 had been given. + * cmode = 15 op = 1 must UNDEF; we assume decode has handled that. + */ + switch (cmode) { + case 0: case 1: + /* no-op */ + break; + case 2: case 3: + imm <<= 8; + break; + case 4: case 5: + imm <<= 16; + break; + case 6: case 7: + imm <<= 24; + break; + case 8: case 9: + imm |= imm << 16; + break; + case 10: case 11: + imm = (imm << 8) | (imm << 24); + break; + case 12: + imm = (imm << 8) | 0xff; + break; + case 13: + imm = (imm << 16) | 0xffff; + break; + case 14: + if (op) { + /* + * This is the only case where the top and bottom 32 bits + * of the encoded constant differ. + */ + uint64_t imm64 = 0; + int n; + + for (n = 0; n < 8; n++) { + if (imm & (1 << n)) { + imm64 |= (0xffULL << (n * 8)); + } + } + return imm64; + } + imm |= (imm << 8) | (imm << 16) | (imm << 24); + break; + case 15: + imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) + | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); + break; + } + if (op) { + imm = ~imm; + } + return dup_const(MO_32, imm); +} + +static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a, + GVecGen2iFn *fn) +{ + uint64_t imm; + int reg_ofs, vec_size; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + return false; + } + + if (a->vd & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + reg_ofs = neon_reg_offset(a->vd, 0); + vec_size = a->q ? 16 : 8; + imm = asimd_imm_const(a->imm, a->cmode, a->op); + + fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size); + return true; +} + +static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs, + int64_t c, uint32_t oprsz, uint32_t maxsz) +{ + tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c); +} + +static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a) +{ + /* Handle decode of cmode/op here between VORR/VBIC/VMOV */ + GVecGen2iFn *fn; + + if ((a->cmode & 1) && a->cmode < 12) { + /* for op=1, the imm will be inverted, so BIC becomes AND. */ + fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori; + } else { + /* There is one unallocated cmode/op combination in this space */ + if (a->cmode == 15 && a->op == 1) { + return false; + } + fn = gen_VMOV_1r; + } + return do_1reg_imm(s, a, fn); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 166349ee20..bcdfec34d2 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5232,105 +5232,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) /* Three register same length: handled by decodetree */ return 1; } else if (insn & (1 << 4)) { - if ((insn & 0x00380080) != 0) { - /* Two registers and shift: handled by decodetree */ - return 1; - } else { /* (insn & 0x00380080) == 0 */ - int invert, reg_ofs, vec_size; - - if (q && (rd & 1)) { - return 1; - } - - op = (insn >> 8) & 0xf; - /* One register and immediate. */ - imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf); - invert = (insn & (1 << 5)) != 0; - /* Note that op = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE. - * We choose to not special-case this and will behave as if a - * valid constant encoding of 0 had been given. - */ - switch (op) { - case 0: case 1: - /* no-op */ - break; - case 2: case 3: - imm <<= 8; - break; - case 4: case 5: - imm <<= 16; - break; - case 6: case 7: - imm <<= 24; - break; - case 8: case 9: - imm |= imm << 16; - break; - case 10: case 11: - imm = (imm << 8) | (imm << 24); - break; - case 12: - imm = (imm << 8) | 0xff; - break; - case 13: - imm = (imm << 16) | 0xffff; - break; - case 14: - imm |= (imm << 8) | (imm << 16) | (imm << 24); - if (invert) { - imm = ~imm; - } - break; - case 15: - if (invert) { - return 1; - } - imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) - | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); - break; - } - if (invert) { - imm = ~imm; - } - - reg_ofs = neon_reg_offset(rd, 0); - vec_size = q ? 16 : 8; - - if (op & 1 && op < 12) { - if (invert) { - /* The immediate value has already been inverted, - * so BIC becomes AND. - */ - tcg_gen_gvec_andi(MO_32, reg_ofs, reg_ofs, imm, - vec_size, vec_size); - } else { - tcg_gen_gvec_ori(MO_32, reg_ofs, reg_ofs, imm, - vec_size, vec_size); - } - } else { - /* VMOV, VMVN. */ - if (op == 14 && invert) { - TCGv_i64 t64 = tcg_temp_new_i64(); - - for (pass = 0; pass <= q; ++pass) { - uint64_t val = 0; - int n; - - for (n = 0; n < 8; n++) { - if (imm & (1 << (n + pass * 8))) { - val |= 0xffull << (n * 8); - } - } - tcg_gen_movi_i64(t64, val); - neon_store_reg64(t64, rd + pass); - } - tcg_temp_free_i64(t64); - } else { - tcg_gen_gvec_dup_imm(MO_32, reg_ofs, vec_size, - vec_size, imm); - } - } - } + /* Two registers and shift or reg and imm: handled by decodetree */ + return 1; } else { /* (insn & 0x00800010 == 0x00800000) */ if (size != 3) { op = (insn >> 8) & 0xf; From 93a5661dc5aca5c8c4eaa4b75f36707199a78f0e Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 24 Apr 2020 23:06:48 +0200 Subject: [PATCH 0881/2595] linux-user: Add support for /proc/cpuinfo on hppa platform Provide our own /proc/cpuinfo file for the hppa (parisc) platform. Signed-off-by: Helge Deller Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-Id: <20200424210648.GA26715@ls3530.fritz.box> [lv: s/an/our/ and add TARGET_HPPA to guard is_proc()] Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index fd5c4f1d73..9ac3af20c1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7378,7 +7378,7 @@ static int is_proc_myself(const char *filename, const char *entry) } #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) || \ - defined(TARGET_SPARC) || defined(TARGET_M68K) + defined(TARGET_SPARC) || defined(TARGET_M68K) || defined(TARGET_HPPA) static int is_proc(const char *filename, const char *entry) { return strcmp(filename, entry) == 0; @@ -7438,6 +7438,18 @@ static int open_cpuinfo(void *cpu_env, int fd) } #endif +#if defined(TARGET_HPPA) +static int open_cpuinfo(void *cpu_env, int fd) +{ + dprintf(fd, "cpu family\t: PA-RISC 1.1e\n"); + dprintf(fd, "cpu\t\t: PA7300LC (PCX-L2)\n"); + dprintf(fd, "capabilities\t: os32\n"); + dprintf(fd, "model\t\t: 9000/778/B160L\n"); + dprintf(fd, "model name\t: Merlin L2 160 QEMU (9000/778/B160L)\n"); + return 0; +} +#endif + #if defined(TARGET_M68K) static int open_hardware(void *cpu_env, int fd) { @@ -7462,7 +7474,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) { "/proc/net/route", open_net_route, is_proc }, #endif -#if defined(TARGET_SPARC) +#if defined(TARGET_SPARC) || defined(TARGET_HPPA) { "/proc/cpuinfo", open_cpuinfo, is_proc }, #endif #if defined(TARGET_M68K) From fd568660b7ae9b9e45cbb616acc91ae4c065c32d Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Thu, 16 Apr 2020 18:59:57 +0100 Subject: [PATCH 0882/2595] linux-user/strace.list: fix epoll_create{,1} -strace output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix syscall name and parameters priinter. Before the change: ``` $ alpha-linux-user/qemu-alpha -strace -L /usr/alpha-unknown-linux-gnu/ /tmp/a ... 1274697 %s(%d)(2097152,274903156744,274903156760,274905840712,274877908880,274903235616) = 3 1274697 exit_group(0) ``` After the change: ``` $ alpha-linux-user/qemu-alpha -strace -L /usr/alpha-unknown-linux-gnu/ /tmp/a ... 1273719 epoll_create1(2097152) = 3 1273719 exit_group(0) ``` Fixes: 9cbc0578cb6 ("Improve output of various syscalls") Signed-off-by: Sergei Trofimovich CC: Riku Voipio CC: Laurent Vivier Cc: qemu-stable@nongnu.org Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200416175957.1274882-1-slyfox@gentoo.org> Signed-off-by: Laurent Vivier --- linux-user/strace.list | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/strace.list b/linux-user/strace.list index d49a1e92a8..9281c0a758 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -125,10 +125,10 @@ { TARGET_NR_dup3, "dup3" , "%s(%d,%d,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_epoll_create -{ TARGET_NR_epoll_create, "%s(%d)", NULL, NULL, NULL }, +{ TARGET_NR_epoll_create, "epoll_create", "%s(%d)", NULL, NULL }, #endif #ifdef TARGET_NR_epoll_create1 -{ TARGET_NR_epoll_create1, "%s(%d)", NULL, NULL, NULL }, +{ TARGET_NR_epoll_create1, "epoll_create1", "%s(%d)", NULL, NULL }, #endif #ifdef TARGET_NR_epoll_ctl { TARGET_NR_epoll_ctl, "epoll_ctl" , NULL, NULL, NULL }, From 257a7e212d5e518ac53bd6a02a3157cf4594c8b3 Mon Sep 17 00:00:00 2001 From: Jonathan Marler Date: Sat, 2 May 2020 10:12:25 -0600 Subject: [PATCH 0883/2595] linux-user/mmap.c: fix integer underflow in target_mremap Fixes: https://bugs.launchpad.net/bugs/1876373 This code path in mmap occurs when a page size is decreased with mremap. When a section of pages is shrunk, qemu calls mmap_reserve on the pages that were released. However, it has the diff operation reversed, subtracting the larger old_size from the smaller new_size. Instead, it should be subtracting the smaller new_size from the larger old_size. You can also see in the previous line of the change that this mmap_reserve call only occurs when old_size > new_size. Bug: https://bugs.launchpad.net/qemu/+bug/1876373 Signed-off-by: Jonathan Marler Reviewded-by: Laurent Vivier Message-Id: <20200502161225.14346-1-johnnymarler@gmail.com> Signed-off-by: Laurent Vivier --- linux-user/mmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index e378033797..caab62909e 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -708,7 +708,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, if (prot == 0) { host_addr = mremap(g2h(old_addr), old_size, new_size, flags); if (host_addr != MAP_FAILED && reserved_va && old_size > new_size) { - mmap_reserve(old_addr + old_size, new_size - old_size); + mmap_reserve(old_addr + old_size, old_size - new_size); } } else { errno = ENOMEM; From 2d92c6827ca01cb4086212a95d9c1b454c252268 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Mon, 25 May 2020 09:59:28 +0200 Subject: [PATCH 0884/2595] linux-user: implement OFD locks Signed-off-by: Andreas Schwab Reviewed-by: Laurent Vivier Message-Id: Signed-off-by: Laurent Vivier --- linux-user/generic/fcntl.h | 4 ++++ linux-user/syscall.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/linux-user/generic/fcntl.h b/linux-user/generic/fcntl.h index 9f727d4df2..c85c5b9fed 100644 --- a/linux-user/generic/fcntl.h +++ b/linux-user/generic/fcntl.h @@ -99,6 +99,10 @@ #define TARGET_F_SETLKW64 14 #endif +#define TARGET_F_OFD_GETLK 36 +#define TARGET_F_OFD_SETLK 37 +#define TARGET_F_OFD_SETLKW 38 + #ifndef TARGET_F_SETOWN_EX #define TARGET_F_SETOWN_EX 15 #define TARGET_F_GETOWN_EX 16 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9ac3af20c1..2d8125fa53 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6098,6 +6098,9 @@ static int target_to_host_fcntl_cmd(int cmd) case TARGET_F_SETFD: case TARGET_F_GETFL: case TARGET_F_SETFL: + case TARGET_F_OFD_GETLK: + case TARGET_F_OFD_SETLK: + case TARGET_F_OFD_SETLKW: ret = cmd; break; case TARGET_F_GETLK: @@ -6383,6 +6386,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) break; case TARGET_F_GETLK64: + case TARGET_F_OFD_GETLK: ret = copy_from_user_flock64(&fl64, arg); if (ret) { return ret; @@ -6394,6 +6398,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) break; case TARGET_F_SETLK64: case TARGET_F_SETLKW64: + case TARGET_F_OFD_SETLK: + case TARGET_F_OFD_SETLKW: ret = copy_from_user_flock64(&fl64, arg); if (ret) { return ret; From 57159bb239bb3517348415b7cd23dd45fb7b100f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:24:58 +0200 Subject: [PATCH 0885/2595] Makefile: Only build virtiofsd if system-mode is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not build the virtiofsd helper when configured with --disable-system. Reviewed-by: Richard Henderson Acked-by: Dr. David Alan Gilbert Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-2-philmd@redhat.com> Signed-off-by: Laurent Vivier --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 40e4f7677b..d1af126ea1 100644 --- a/Makefile +++ b/Makefile @@ -345,7 +345,7 @@ HELPERS-y += vhost-user-gpu$(EXESUF) vhost-user-json-y += contrib/vhost-user-gpu/50-qemu-gpu.json endif -ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy) +ifeq ($(CONFIG_SOFTMMU)$(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyyy) HELPERS-y += virtiofsd$(EXESUF) vhost-user-json-y += tools/virtiofsd/50-qemu-virtiofsd.json endif From 1cf295be5de93e984ea6f52f151141f5126537f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:24:59 +0200 Subject: [PATCH 0886/2595] configure: Avoid building TCG when not needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid building TCG when building only tools: ./configure --enable-tools --disable-system --disable-user This saves us from running the soft-float tests enabled since commit 76170102508. Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-3-philmd@redhat.com> Signed-off-by: Laurent Vivier --- configure | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure b/configure index b969dee675..fccc56bd4d 100755 --- a/configure +++ b/configure @@ -1663,6 +1663,10 @@ if [ "$ARCH" = "unknown" ]; then linux_user="no" fi +if [ "$bsd_user" = "no" -a "$linux_user" = "no" -a "$softmmu" = "no" ] ; then + tcg="no" +fi + default_target_list="" mak_wilds="" From ca6db4691345dee059aa5b7eb6152f005a8eb120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:25:00 +0200 Subject: [PATCH 0887/2595] tests/Makefile: Only display TCG-related tests when TCG is available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-4-philmd@redhat.com> Signed-off-by: Laurent Vivier --- tests/Makefile.include | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Makefile.include b/tests/Makefile.include index 03a74b60f6..6bc3d1096b 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -12,8 +12,10 @@ check-help: @echo " $(MAKE) check-speed Run qobject speed tests" @echo " $(MAKE) check-qapi-schema Run QAPI schema tests" @echo " $(MAKE) check-block Run block tests" +ifeq ($(CONFIG_TCG),y) @echo " $(MAKE) check-tcg Run TCG tests" @echo " $(MAKE) check-softfloat Run FPU emulation tests" +endif @echo " $(MAKE) check-acceptance Run all acceptance (functional) tests" @echo @echo " $(MAKE) check-report.tap Generates an aggregated TAP test report" From 37914f603f37949f6f13df0eee31bbef0e144d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:25:01 +0200 Subject: [PATCH 0888/2595] tests/Makefile: Restrict some softmmu-only tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the next commit we are going to remove some objects from the util-obj-y variable (objects which are not used by user-mode, when configured with --disable-system). Then some system-mode tests are going to fail, due to the missing objects: $ make check-unit -k LINK tests/test-iov /usr/bin/ld: tests/test-iov.o: in function `iov_from_buf': include/qemu/iov.h:49: undefined reference to `iov_from_buf_full' make: *** [rules.mak:124: tests/test-iov] Error 1 LINK tests/test-timed-average /usr/bin/ld: tests/test-timed-average.o: in function `account': tests/test-timed-average.c:27: undefined reference to `timed_average_account' make: *** [rules.mak:124: tests/test-timed-average] Error 1 LINK tests/test-util-filemonitor /usr/bin/ld: tests/test-util-filemonitor.o: in function `qemu_file_monitor_test_event_loop': tests/test-util-filemonitor.c:83: undefined reference to `main_loop_wait' make: *** [rules.mak:124: tests/test-util-filemonitor] Error 1 LINK tests/test-util-sockets /usr/bin/ld: tests/test-util-sockets.o: in function `test_socket_fd_pass_name_good': tests/test-util-sockets.c:91: undefined reference to `socket_connect' make: *** [rules.mak:124: tests/test-util-sockets] Error 1 LINK tests/test-base64 /usr/bin/ld: tests/test-base64.o: in function `test_base64_good': tests/test-base64.c:35: undefined reference to `qbase64_decode' collect2: error: ld returned 1 exit status make: *** [rules.mak:124: tests/test-base64] Error 1 LINK tests/test-bufferiszero /usr/bin/ld: tests/test-bufferiszero.o: in function `test_1': tests/test-bufferiszero.c:31: undefined reference to `buffer_is_zero' make: *** [rules.mak:124: tests/test-bufferiszero] Error 1 make: Target 'check-unit' not remade because of errors. Instead, restrict these tests to system-mode, by using the $(CONFIG_SOFTMMU) variable. Reviewed-by: Richard Henderson Tested-by: Richard Henderson Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-5-philmd@redhat.com> Signed-off-by: Laurent Vivier --- tests/Makefile.include | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 6bc3d1096b..0cb58aad26 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -66,14 +66,14 @@ check-unit-y += tests/check-qlit$(EXESUF) check-unit-y += tests/test-qobject-output-visitor$(EXESUF) check-unit-y += tests/test-clone-visitor$(EXESUF) check-unit-y += tests/test-qobject-input-visitor$(EXESUF) -check-unit-y += tests/test-qmp-cmds$(EXESUF) +check-unit-$(CONFIG_SOFTMMU) += tests/test-qmp-cmds$(EXESUF) check-unit-y += tests/test-string-input-visitor$(EXESUF) check-unit-y += tests/test-string-output-visitor$(EXESUF) check-unit-y += tests/test-qmp-event$(EXESUF) check-unit-y += tests/test-opts-visitor$(EXESUF) check-unit-$(CONFIG_BLOCK) += tests/test-coroutine$(EXESUF) check-unit-y += tests/test-visitor-serialization$(EXESUF) -check-unit-y += tests/test-iov$(EXESUF) +check-unit-$(CONFIG_SOFTMMU) += tests/test-iov$(EXESUF) check-unit-y += tests/test-bitmap$(EXESUF) check-unit-$(CONFIG_BLOCK) += tests/test-aio$(EXESUF) check-unit-$(CONFIG_BLOCK) += tests/test-aio-multithread$(EXESUF) @@ -108,7 +108,7 @@ check-unit-y += tests/test-qht$(EXESUF) check-unit-y += tests/test-qht-par$(EXESUF) check-unit-y += tests/test-bitops$(EXESUF) check-unit-y += tests/test-bitcnt$(EXESUF) -check-unit-y += tests/test-qdev-global-props$(EXESUF) +check-unit-$(CONFIG_SOFTMMU) += tests/test-qdev-global-props$(EXESUF) check-unit-y += tests/check-qom-interface$(EXESUF) check-unit-y += tests/check-qom-proplist$(EXESUF) check-unit-y += tests/test-qemu-opts$(EXESUF) @@ -126,9 +126,9 @@ check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_GNUTLS)) += tests/test-crypto-tl ifneq (,$(findstring qemu-ga,$(TOOLS))) check-unit-$(call land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF) endif -check-unit-y += tests/test-timed-average$(EXESUF) -check-unit-$(CONFIG_INOTIFY1) += tests/test-util-filemonitor$(EXESUF) -check-unit-y += tests/test-util-sockets$(EXESUF) +check-unit-$(CONFIG_SOFTMMU) += tests/test-timed-average$(EXESUF) +check-unit-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_INOTIFY1)) += tests/test-util-filemonitor$(EXESUF) +check-unit-$(CONFIG_SOFTMMU) += tests/test-util-sockets$(EXESUF) check-unit-$(CONFIG_BLOCK) += tests/test-authz-simple$(EXESUF) check-unit-$(CONFIG_BLOCK) += tests/test-authz-list$(EXESUF) check-unit-$(CONFIG_BLOCK) += tests/test-authz-listfile$(EXESUF) @@ -139,7 +139,7 @@ check-unit-$(CONFIG_BLOCK) += tests/test-io-channel-file$(EXESUF) check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_GNUTLS)) += tests/test-io-channel-tls$(EXESUF) check-unit-$(CONFIG_BLOCK) += tests/test-io-channel-command$(EXESUF) check-unit-$(CONFIG_BLOCK) += tests/test-io-channel-buffer$(EXESUF) -check-unit-y += tests/test-base64$(EXESUF) +check-unit-$(CONFIG_SOFTMMU) += tests/test-base64$(EXESUF) check-unit-$(call land,$(CONFIG_BLOCK),$(if $(CONFIG_NETTLE),y,$(CONFIG_GCRYPT))) += tests/test-crypto-pbkdf$(EXESUF) check-unit-$(CONFIG_BLOCK) += tests/test-crypto-ivgen$(EXESUF) check-unit-$(CONFIG_BLOCK) += tests/test-crypto-afsplit$(EXESUF) @@ -147,7 +147,7 @@ check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_QEMU_PRIVATE_XTS)) += tests/test check-unit-$(CONFIG_BLOCK) += tests/test-crypto-block$(EXESUF) check-unit-y += tests/test-logging$(EXESUF) check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_REPLICATION)) += tests/test-replication$(EXESUF) -check-unit-y += tests/test-bufferiszero$(EXESUF) +check-unit-$(CONFIG_SOFTMMU) += tests/test-bufferiszero$(EXESUF) check-unit-y += tests/test-uuid$(EXESUF) check-unit-y += tests/ptimer-test$(EXESUF) check-unit-y += tests/test-qapi-util$(EXESUF) From e4d6d41ce23e0dfb4aa992e00c578d127fad061c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:25:02 +0200 Subject: [PATCH 0889/2595] util/Makefile: Reduce the user-mode object list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These objects are not required when configured with --disable-system. Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-6-philmd@redhat.com> Signed-off-by: Laurent Vivier --- util/Makefile.objs | 59 +++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/util/Makefile.objs b/util/Makefile.objs index fe339c2636..cc5e37177a 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -1,8 +1,4 @@ util-obj-y = osdep.o cutils.o unicode.o qemu-timer-common.o -util-obj-y += bufferiszero.o -util-obj-y += lockcnt.o -util-obj-y += aiocb.o async.o aio-wait.o thread-pool.o qemu-timer.o -util-obj-y += main-loop.o util-obj-$(call lnot,$(CONFIG_ATOMIC64)) += atomic64.o util-obj-$(CONFIG_POSIX) += aio-posix.o util-obj-$(CONFIG_POSIX) += fdmon-poll.o @@ -21,31 +17,20 @@ util-obj-$(CONFIG_WIN32) += oslib-win32.o util-obj-$(CONFIG_WIN32) += qemu-thread-win32.o util-obj-y += envlist.o path.o module.o util-obj-y += host-utils.o -util-obj-y += bitmap.o bitops.o hbitmap.o +util-obj-y += bitmap.o bitops.o util-obj-y += fifo8.o -util-obj-y += nvdimm-utils.o util-obj-y += cacheinfo.o util-obj-y += error.o qemu-error.o util-obj-y += qemu-print.o util-obj-y += id.o -util-obj-y += iov.o qemu-config.o qemu-sockets.o uri.o notify.o +util-obj-y += qemu-config.o notify.o util-obj-y += qemu-option.o qemu-progress.o util-obj-y += keyval.o -util-obj-y += hexdump.o util-obj-y += crc32c.o util-obj-y += uuid.o -util-obj-y += throttle.o util-obj-y += getauxval.o -util-obj-y += readline.o util-obj-y += rcu.o util-obj-$(CONFIG_MEMBARRIER) += sys_membarrier.o -util-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o -util-obj-y += qemu-coroutine-sleep.o -util-obj-y += qemu-co-shared-resource.o -util-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o -util-obj-y += buffer.o -util-obj-y += timed-average.o -util-obj-y += base64.o util-obj-y += log.o util-obj-y += pagesize.o util-obj-y += qdist.o @@ -54,13 +39,45 @@ util-obj-y += qsp.o util-obj-y += range.o util-obj-y += stats64.o util-obj-y += systemd.o -util-obj-y += iova-tree.o -util-obj-$(CONFIG_INOTIFY1) += filemonitor-inotify.o -util-obj-$(call lnot,$(CONFIG_INOTIFY1)) += filemonitor-stub.o -util-obj-$(CONFIG_LINUX) += vfio-helpers.o util-obj-$(CONFIG_POSIX) += drm.o util-obj-y += guest-random.o util-obj-$(CONFIG_GIO) += dbus.o dbus.o-cflags = $(GIO_CFLAGS) dbus.o-libs = $(GIO_LIBS) util-obj-$(CONFIG_USER_ONLY) += selfmap.o + +####################################################################### +# code used by both qemu system emulation and qemu-img + +ifeq ($(call lor,$(CONFIG_SOFTMMU),$(CONFIG_TOOLS)),y) + +util-obj-y += aio-wait.o +util-obj-y += aiocb.o +util-obj-y += async.o +util-obj-y += base64.o +util-obj-y += buffer.o +util-obj-y += bufferiszero.o +util-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o +util-obj-y += hexdump.o +util-obj-y += lockcnt.o +util-obj-y += iov.o +util-obj-y += iova-tree.o +util-obj-y += hbitmap.o +util-obj-y += main-loop.o +util-obj-y += nvdimm-utils.o +util-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o +util-obj-y += qemu-coroutine-sleep.o +util-obj-y += qemu-co-shared-resource.o +util-obj-y += qemu-sockets.o +util-obj-y += qemu-timer.o +util-obj-y += thread-pool.o +util-obj-y += throttle.o +util-obj-y += timed-average.o +util-obj-y += uri.o + +util-obj-$(CONFIG_LINUX) += vfio-helpers.o +util-obj-$(CONFIG_INOTIFY1) += filemonitor-inotify.o +util-obj-$(call lnot,$(CONFIG_INOTIFY1)) += filemonitor-stub.o +util-obj-$(CONFIG_BLOCK) += readline.o + +endif # CONFIG_SOFTMMU || CONFIG_TOOLS From dc70f80fb276c7ca83261bca7850c4c401c3f892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:25:03 +0200 Subject: [PATCH 0890/2595] stubs/Makefile: Reduce the user-mode object list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These stubs are not required when configured with --disable-system. Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-7-philmd@redhat.com> Signed-off-by: Laurent Vivier --- stubs/Makefile.objs | 52 ++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 6a9e3135e8..f54125de31 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -1,47 +1,55 @@ -stub-obj-y += arch_type.o -stub-obj-y += bdrv-next-monitor-owned.o stub-obj-y += blk-commit-all.o -stub-obj-y += blockdev-close-all-bdrv-states.o -stub-obj-y += clock-warp.o stub-obj-y += cpu-get-clock.o stub-obj-y += cpu-get-icount.o stub-obj-y += dump.o stub-obj-y += error-printf.o stub-obj-y += fdset.o stub-obj-y += gdbstub.o -stub-obj-y += get-vm-name.o -stub-obj-y += iothread.o stub-obj-y += iothread-lock.o stub-obj-y += is-daemonized.o stub-obj-$(CONFIG_LINUX_AIO) += linux-aio.o stub-obj-$(CONFIG_LINUX_IO_URING) += io_uring.o -stub-obj-y += machine-init-done.o -stub-obj-y += migr-blocker.o -stub-obj-y += change-state-handler.o -stub-obj-y += monitor.o stub-obj-y += monitor-core.o stub-obj-y += notify-event.o +stub-obj-y += qmp_memory_device.o stub-obj-y += qtest.o +stub-obj-y += ramfb.o stub-obj-y += replay.o -stub-obj-y += replay-user.o stub-obj-y += runstate-check.o +stub-obj-$(CONFIG_SOFTMMU) += semihost.o stub-obj-y += set-fd-handler.o +stub-obj-y += vmgenid.o stub-obj-y += sysbus.o stub-obj-y += tpm.o stub-obj-y += trace-control.o -stub-obj-y += uuid.o -stub-obj-y += vm-stop.o stub-obj-y += vmstate.o stub-obj-y += win32-kbd-hook.o + +####################################################################### +# code used by both qemu system emulation and qemu-img + +ifeq ($(call lor,$(CONFIG_SOFTMMU),$(CONFIG_TOOLS)),y) + +stub-obj-y += arch_type.o +stub-obj-y += bdrv-next-monitor-owned.o +stub-obj-y += blockdev-close-all-bdrv-states.o +stub-obj-y += change-state-handler.o +stub-obj-y += clock-warp.o stub-obj-y += fd-register.o -stub-obj-y += qmp_memory_device.o -stub-obj-y += target-monitor-defs.o -stub-obj-y += target-get-monitor-def.o -stub-obj-y += vmgenid.o -stub-obj-y += xen-common.o -stub-obj-y += xen-hvm.o +stub-obj-y += fw_cfg.o +stub-obj-y += get-vm-name.o +stub-obj-y += iothread.o +stub-obj-y += machine-init-done.o +stub-obj-y += migr-blocker.o +stub-obj-y += monitor.o stub-obj-y += pci-host-piix.o stub-obj-y += ram-block.o -stub-obj-y += ramfb.o -stub-obj-y += fw_cfg.o -stub-obj-$(CONFIG_SOFTMMU) += semihost.o +stub-obj-y += replay-user.o +stub-obj-y += target-get-monitor-def.o +stub-obj-y += target-monitor-defs.o +stub-obj-y += uuid.o +stub-obj-y += vm-stop.o +stub-obj-y += xen-common.o +stub-obj-y += xen-hvm.o + +endif # CONFIG_SOFTMMU || CONFIG_TOOLS From 0c4e99317a7a95a80de17a83a6271c97e524f380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:25:04 +0200 Subject: [PATCH 0891/2595] target/riscv/cpu: Restrict CPU migration to system-mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-8-philmd@redhat.com> Signed-off-by: Laurent Vivier --- target/riscv/cpu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 059d71f2c7..6c78337858 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -485,10 +485,12 @@ static void riscv_cpu_init(Object *obj) cpu_set_cpustate_pointers(cpu); } +#ifndef CONFIG_USER_ONLY static const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", .unmigratable = 1, }; +#endif static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("i", RISCVCPU, cfg.ext_i, true), @@ -544,13 +546,13 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) cc->do_transaction_failed = riscv_cpu_do_transaction_failed; cc->do_unaligned_access = riscv_cpu_do_unaligned_access; cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug; + /* For now, mark unmigratable: */ + cc->vmsd = &vmstate_riscv_cpu; #endif #ifdef CONFIG_TCG cc->tcg_initialize = riscv_translate_init; cc->tlb_fill = riscv_cpu_tlb_fill; #endif - /* For now, mark unmigratable: */ - cc->vmsd = &vmstate_riscv_cpu; device_class_set_props(dc, riscv_cpu_properties); } From 3e07593aecccef9f5d877bb8a27a400d8431ea3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:25:05 +0200 Subject: [PATCH 0892/2595] exec: Assert CPU migration is not used on user-only build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-9-philmd@redhat.com> Signed-off-by: Laurent Vivier --- exec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 5162f0d12f..6dfd314469 100644 --- a/exec.c +++ b/exec.c @@ -946,7 +946,9 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp) qemu_plugin_vcpu_init_hook(cpu); -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_USER_ONLY + assert(cc->vmsd == NULL); +#else /* !CONFIG_USER_ONLY */ if (qdev_get_vmsd(DEVICE(cpu)) == NULL) { vmstate_register(NULL, cpu->cpu_index, &vmstate_cpu_common, cpu); } From 32f5b7e5169c885f09cb20f194db9ba4aab448ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:25:06 +0200 Subject: [PATCH 0893/2595] arch_init: Remove unused 'qapi-commands-misc.h' include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit ffaee83bcb2 moved qmp_query_target but forgot to remove this include. Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-10-philmd@redhat.com> Signed-off-by: Laurent Vivier --- arch_init.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch_init.c b/arch_init.c index d9eb0ec1dd..8afea4748b 100644 --- a/arch_init.c +++ b/arch_init.c @@ -27,7 +27,6 @@ #include "sysemu/arch_init.h" #include "hw/pci/pci.h" #include "hw/audio/soundhw.h" -#include "qapi/qapi-commands-misc.h" #include "qapi/error.h" #include "qemu/config-file.h" #include "qemu/error-report.h" From b75c99008075eb817461dcd272b6ba8cd7ae210f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:25:07 +0200 Subject: [PATCH 0894/2595] target/i386: Restrict CpuClass::get_crash_info() to system-mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-11-philmd@redhat.com> Signed-off-by: Laurent Vivier --- target/i386/cpu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 7a4a8e3847..dd31c1de5f 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6843,6 +6843,7 @@ static void x86_cpu_register_feature_bit_props(X86CPU *cpu, x86_cpu_register_bit_prop(cpu, name, w, bitnr); } +#if !defined(CONFIG_USER_ONLY) static GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); @@ -6886,6 +6887,7 @@ static void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, errp); qapi_free_GuestPanicInformation(panic_info); } +#endif /* !CONFIG_USER_ONLY */ static void x86_cpu_initfn(Object *obj) { @@ -6932,8 +6934,10 @@ static void x86_cpu_initfn(Object *obj) x86_cpu_get_unavailable_features, NULL, NULL, NULL); +#if !defined(CONFIG_USER_ONLY) object_property_add(obj, "crash-information", "GuestPanicInformation", x86_cpu_get_crash_info_qom, NULL, NULL, NULL); +#endif for (w = 0; w < FEATURE_WORDS; w++) { int bitnr; @@ -7245,7 +7249,6 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->cpu_exec_interrupt = x86_cpu_exec_interrupt; #endif cc->dump_state = x86_cpu_dump_state; - cc->get_crash_info = x86_cpu_get_crash_info; cc->set_pc = x86_cpu_set_pc; cc->synchronize_from_tb = x86_cpu_synchronize_from_tb; cc->gdb_read_register = x86_cpu_gdb_read_register; @@ -7256,6 +7259,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->asidx_from_attrs = x86_asidx_from_attrs; cc->get_memory_mapping = x86_cpu_get_memory_mapping; cc->get_phys_page_attrs_debug = x86_cpu_get_phys_page_attrs_debug; + cc->get_crash_info = x86_cpu_get_crash_info; 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; From 6b4bf66e336cbaa6e77f950ea95bdc50f8d5eace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:25:08 +0200 Subject: [PATCH 0895/2595] target/s390x: Restrict CpuClass::get_crash_info() to system-mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Reviewed-by: Cornelia Huck Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-12-philmd@redhat.com> Signed-off-by: Laurent Vivier --- target/s390x/cpu.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index ca50b70451..08eb674d22 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -247,6 +247,7 @@ out: error_propagate(errp, err); } +#if !defined(CONFIG_USER_ONLY) static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs) { GuestPanicInformation *panic_info; @@ -256,11 +257,7 @@ static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs) panic_info = g_malloc0(sizeof(GuestPanicInformation)); panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390; -#if !defined(CONFIG_USER_ONLY) panic_info->u.s390.core = cpu->env.core_id; -#else - panic_info->u.s390.core = 0; /* sane default for non system emulation */ -#endif panic_info->u.s390.psw_mask = cpu->env.psw.mask; panic_info->u.s390.psw_addr = cpu->env.psw.addr; panic_info->u.s390.reason = cpu->env.crash_reason; @@ -286,6 +283,7 @@ static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v, errp); qapi_free_GuestPanicInformation(panic_info); } +#endif static void s390_cpu_initfn(Object *obj) { @@ -295,16 +293,16 @@ static void s390_cpu_initfn(Object *obj) cpu_set_cpustate_pointers(cpu); cs->halted = 1; cs->exception_index = EXCP_HLT; +#if !defined(CONFIG_USER_ONLY) object_property_add(obj, "crash-information", "GuestPanicInformation", s390_cpu_get_crash_info_qom, NULL, NULL, NULL); - s390_cpu_model_register_props(obj); -#if !defined(CONFIG_USER_ONLY) cpu->env.tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu); cpu->env.cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu); s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); #endif + s390_cpu_model_register_props(obj); } static void s390_cpu_finalize(Object *obj) @@ -488,13 +486,13 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) cc->do_interrupt = s390_cpu_do_interrupt; #endif cc->dump_state = s390_cpu_dump_state; - cc->get_crash_info = s390_cpu_get_crash_info; cc->set_pc = s390_cpu_set_pc; cc->gdb_read_register = s390_cpu_gdb_read_register; cc->gdb_write_register = s390_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_debug = s390_cpu_get_phys_page_debug; cc->vmsd = &vmstate_s390_cpu; + cc->get_crash_info = s390_cpu_get_crash_info; cc->write_elf64_note = s390_cpu_write_elf64_note; #ifdef CONFIG_TCG cc->cpu_exec_interrupt = s390_cpu_exec_interrupt; From cfe35d4889cebac0417fcb2d68e33e109b5fd484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:25:09 +0200 Subject: [PATCH 0896/2595] hw/core: Restrict CpuClass::get_crash_info() to system-mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200522172510.25784-13-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/core/cpu.c | 2 ++ include/hw/core/cpu.h | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/core/cpu.c b/hw/core/cpu.c index 5284d384fb..f31ec48ee6 100644 --- a/hw/core/cpu.c +++ b/hw/core/cpu.c @@ -209,6 +209,7 @@ static bool cpu_common_exec_interrupt(CPUState *cpu, int int_req) return false; } +#if !defined(CONFIG_USER_ONLY) GuestPanicInformation *cpu_get_crash_info(CPUState *cpu) { CPUClass *cc = CPU_GET_CLASS(cpu); @@ -219,6 +220,7 @@ GuestPanicInformation *cpu_get_crash_info(CPUState *cpu) } return res; } +#endif void cpu_dump_state(CPUState *cpu, FILE *f, int flags) { diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 07f7698155..497600c49e 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -490,6 +490,8 @@ bool cpu_paging_enabled(const CPUState *cpu); void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, Error **errp); +#if !defined(CONFIG_USER_ONLY) + /** * cpu_write_elf64_note: * @f: pointer to a function that writes memory to a file @@ -539,6 +541,8 @@ int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, */ GuestPanicInformation *cpu_get_crash_info(CPUState *cpu); +#endif /* !CONFIG_USER_ONLY */ + /** * CPUDumpFlags: * @CPU_DUMP_CODE: @@ -632,7 +636,8 @@ static inline int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs) } return ret; } -#endif + +#endif /* CONFIG_USER_ONLY */ /** * cpu_list_add: From 95722b27845b972250a7d4f93b693b01e2a0c3a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 22 May 2020 19:25:10 +0200 Subject: [PATCH 0897/2595] stubs: Restrict ui/win32-kbd-hook to system-mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Makefile.objs, the ui/ directory is restricted to system-mode: 43 ifeq ($(CONFIG_SOFTMMU),y) ... 65 common-obj-y += ui/ 66 common-obj-m += ui/ ... 82 endif # CONFIG_SOFTMMU Restrict the ui/ stub added in commit 2df9f5718df to only build it for system-mode emulation. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200522172510.25784-14-philmd@redhat.com> Signed-off-by: Laurent Vivier --- stubs/Makefile.objs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index f54125de31..c1e43ac68f 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -23,7 +23,7 @@ stub-obj-y += sysbus.o stub-obj-y += tpm.o stub-obj-y += trace-control.o stub-obj-y += vmstate.o -stub-obj-y += win32-kbd-hook.o +stub-obj-$(CONFIG_SOFTMMU) += win32-kbd-hook.o ####################################################################### # code used by both qemu system emulation and qemu-img From 02324a475c7df4223d63d631d0cead61f0efeb03 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 5 Jun 2020 16:49:16 +0100 Subject: [PATCH 0898/2595] qemu-plugin.h: add missing include to define size_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Emilio G. Cota Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200524202427.951784-1-cota@braap.org> Message-Id: <20200605154929.26910-2-alex.bennee@linaro.org> --- include/qemu/qemu-plugin.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index 89ed579f55..bab8b0d4b3 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -12,6 +12,7 @@ #include #include +#include /* * For best performance, build the plugin with -fvisibility=hidden so that From a6703e65ecfe3a57f122abdf1f8353fb60927a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 5 Jun 2020 16:49:17 +0100 Subject: [PATCH 0899/2595] scripts/clean-includes: Mark 'qemu/qemu-plugin.h' as special header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "qemu/qemu-plugin.h" isn't meant to be include by QEMU codebase, but by 3rd party plugins that QEMU can use. These plugins can be built out of QEMU and don't include "qemu/osdep.h". Mark "qemu/qemu-plugin.h" as a special header that doesn't need to be cleaned for "qemu/osdep.h". Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Emilio G. Cota Signed-off-by: Alex Bennée Message-Id: <20200524215654.13256-1-f4bug@amsat.org> Message-Id: <20200605154929.26910-3-alex.bennee@linaro.org> --- scripts/clean-includes | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/clean-includes b/scripts/clean-includes index dd938daa3e..795b3bea31 100755 --- a/scripts/clean-includes +++ b/scripts/clean-includes @@ -123,6 +123,7 @@ for f in "$@"; do ;; *include/qemu/osdep.h | \ *include/qemu/compiler.h | \ + *include/qemu/qemu-plugin.h | \ *include/glib-compat.h | \ *include/sysemu/os-posix.h | \ *include/sysemu/os-win32.h | \ From 4e62bfa9ee54d071c656d12057b7d293ca22d423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 5 Jun 2020 16:49:18 +0100 Subject: [PATCH 0900/2595] tests/plugin: correctly honour io_count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200605154929.26910-4-alex.bennee@linaro.org> --- tests/plugin/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/plugin/mem.c b/tests/plugin/mem.c index 878abf09d1..4725bd851d 100644 --- a/tests/plugin/mem.c +++ b/tests/plugin/mem.c @@ -28,7 +28,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) g_string_printf(out, "mem accesses: %" PRIu64 "\n", mem_count); if (do_haddr) { - g_string_append_printf(out, "io accesses: %" PRIu64 "\n", mem_count); + g_string_append_printf(out, "io accesses: %" PRIu64 "\n", io_count); } qemu_plugin_outs(out->str); } From 2e886a242cf540d716d431a55071a717d562eb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 5 Jun 2020 16:49:19 +0100 Subject: [PATCH 0901/2595] exec: flush the whole TLB if a watchpoint crosses a page boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no particular reason why you can't have a watchpoint in TCG that covers a large chunk of the address space. We could be clever about it but these cases are pretty rare and we can assume the user will expect a little performance degradation. NB: In my testing gdb will silently squash a watchpoint like: watch (char[0x7fffffffff]) *0x0 to a 4 byte watchpoint. Practically it will limit the maximum size based on max-value-size. However given enough of a tweak the sky is the limit. Reported-by: Alexander Bulekov Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200605154929.26910-5-alex.bennee@linaro.org> --- exec.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index be4be2df3a..a0bf9d61c8 100644 --- a/exec.c +++ b/exec.c @@ -1038,6 +1038,7 @@ int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len, int flags, CPUWatchpoint **watchpoint) { CPUWatchpoint *wp; + vaddr in_page; /* forbid ranges which are empty or run off the end of the address space */ if (len == 0 || (addr + len - 1) < addr) { @@ -1058,7 +1059,12 @@ int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len, QTAILQ_INSERT_TAIL(&cpu->watchpoints, wp, entry); } - tlb_flush_page(cpu, addr); + in_page = -(addr | TARGET_PAGE_MASK); + if (len <= in_page) { + tlb_flush_page(cpu, addr); + } else { + tlb_flush(cpu); + } if (watchpoint) *watchpoint = wp; From 1de8e4c4dcf2af8e1c7d95f1d3c42d0c35b96295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 5 Jun 2020 16:49:20 +0100 Subject: [PATCH 0902/2595] .travis.yml: allow failure for unreliable hosts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They will still run but they won't get in the way of the result. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20200605154929.26910-6-alex.bennee@linaro.org> --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 564be50a3c..ec6367af1f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -429,6 +429,7 @@ jobs: env: - TEST_CMD="make check check-tcg V=1" - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS}" + - UNRELIABLE=true - name: "[ppc64] GCC check-tcg" arch: ppc64le @@ -493,6 +494,7 @@ jobs: env: - TEST_CMD="make check check-tcg V=1" - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user" + - UNRELIABLE=true script: - ( cd ${SRC_DIR} ; git submodule update --init roms/SLOF ) - BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$? @@ -535,6 +537,7 @@ jobs: - TEST_CMD="make check-unit" - CONFIG="--disable-containers --disable-tcg --enable-kvm --disable-tools --host-cc=clang --cxx=clang++" + - UNRELIABLE=true # Release builds # The make-release script expect a QEMU version, so our tag must start with a 'v'. @@ -556,3 +559,5 @@ jobs: - mkdir -p release-build && cd release-build - ../configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; } - make install + allow_failures: + - env: UNRELIABLE=true From 12d43b5ae916809aad9ccf8aa2a0a06260527340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 5 Jun 2020 16:49:21 +0100 Subject: [PATCH 0903/2595] .shippable: temporaily disable some cross builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These currently fail due to Debian bug #960271 as the linux-libc-library has a user-space build breaking symbol in it. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20200605154929.26910-7-alex.bennee@linaro.org> --- .shippable.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.shippable.yml b/.shippable.yml index 2cce7b5689..10cf219bff 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -5,8 +5,8 @@ env: global: - LC_ALL=C matrix: - - IMAGE=debian-amd64 - TARGET_LIST=x86_64-softmmu,x86_64-linux-user + # - IMAGE=debian-amd64 + # TARGET_LIST=x86_64-softmmu,x86_64-linux-user - IMAGE=debian-win32-cross TARGET_LIST=arm-softmmu,i386-softmmu,lm32-softmmu - IMAGE=debian-win64-cross @@ -19,10 +19,10 @@ env: TARGET_LIST=aarch64-softmmu,aarch64-linux-user - IMAGE=debian-s390x-cross TARGET_LIST=s390x-softmmu,s390x-linux-user - - IMAGE=debian-mips-cross - TARGET_LIST=mips-softmmu,mipsel-linux-user - - IMAGE=debian-mips64el-cross - TARGET_LIST=mips64el-softmmu,mips64el-linux-user + # - IMAGE=debian-mips-cross + # TARGET_LIST=mips-softmmu,mipsel-linux-user + # - IMAGE=debian-mips64el-cross + # TARGET_LIST=mips64el-softmmu,mips64el-linux-user - IMAGE=debian-ppc64el-cross TARGET_LIST=ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user build: From e035e6ffed3e3943920c93b19ca1d92444add4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 5 Jun 2020 16:49:23 +0100 Subject: [PATCH 0904/2595] tests/docker: fix pre-requisite for debian-tricore-cross MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Bastian Koppelmann Signed-off-by: Alex Bennée Message-Id: <20200605154929.26910-9-alex.bennee@linaro.org> --- tests/docker/Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index ed46bd98eb..981b7fcf2a 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -130,7 +130,7 @@ docker-image-debian-sparc64-cross: docker-image-debian10 docker-image-travis: NOUSER=1 # Specialist build images, sometimes very limited tools -docker-image-tricore-cross: docker-image-debian9 +docker-image-debian-tricore-cross: docker-image-debian9 docker-image-debian-arm64-test-cross: docker-image-debian11 # These images may be good enough for building tests but not for test builds From a97098844b9e4d2d1c3a24f66b8e2c7f97b3a795 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 5 Jun 2020 16:49:24 +0100 Subject: [PATCH 0905/2595] docker: update Ubuntu to 20.04 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paolo Bonzini Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200604231716.11354-1-pbonzini@redhat.com> Message-Id: <20200605154929.26910-10-alex.bennee@linaro.org> --- tests/docker/dockerfiles/ubuntu.docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker index eeb3b22bf2..43872417de 100644 --- a/tests/docker/dockerfiles/ubuntu.docker +++ b/tests/docker/dockerfiles/ubuntu.docker @@ -9,7 +9,7 @@ # system won't pick up that it has changed. # -FROM ubuntu:19.04 +FROM ubuntu:20.04 ENV PACKAGES flex bison \ ccache \ clang \ From 083b9bd7a1c526d57ec17b23dd6eca414e808886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 5 Jun 2020 16:49:25 +0100 Subject: [PATCH 0906/2595] hw/virtio/vhost: re-factor vhost-section and allow DIRTY_MEMORY_CODE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The purpose of vhost_section is to identify RAM regions that need to be made available to a vhost client. However when running under TCG all RAM sections have DIRTY_MEMORY_CODE set which leads to problems down the line. Re-factor the code so: - steps are clearer to follow - reason for rejection is recorded in the trace point - we allow DIRTY_MEMORY_CODE We expand the comment to explain that kernel based vhost has specific support for migration tracking. Signed-off-by: Alex Bennée Tested-by: Fabiano Rosas Cc: Michael S. Tsirkin Cc: Dr. David Alan Gilbert Cc: Stefan Hajnoczi Message-Id: <20200605154929.26910-11-alex.bennee@linaro.org> --- hw/virtio/trace-events | 3 ++- hw/virtio/vhost.c | 55 ++++++++++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index e83500bee9..6427a0047d 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -5,7 +5,8 @@ vhost_commit(bool started, bool changed) "Started: %d Changed: %d" vhost_region_add_section(const char *name, uint64_t gpa, uint64_t size, uint64_t host) "%s: 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64 vhost_region_add_section_merge(const char *name, uint64_t new_size, uint64_t gpa, uint64_t owr) "%s: size: 0x%"PRIx64 " gpa: 0x%"PRIx64 " owr: 0x%"PRIx64 vhost_region_add_section_aligned(const char *name, uint64_t gpa, uint64_t size, uint64_t host) "%s: 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64 -vhost_section(const char *name, int r) "%s:%d" +vhost_section(const char *name) "%s" +vhost_reject_section(const char *name, int d) "%s:%d" vhost_iotlb_miss(void *dev, int step) "%p step %d" # vhost-user.c diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index aff98a0ede..e3e2181290 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -27,6 +27,7 @@ #include "migration/blocker.h" #include "migration/qemu-file-types.h" #include "sysemu/dma.h" +#include "sysemu/tcg.h" #include "trace.h" /* enabled until disconnected backend stabilizes */ @@ -403,26 +404,50 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev, return r; } +/* + * vhost_section: identify sections needed for vhost access + * + * We only care about RAM sections here (where virtqueue and guest + * internals accessed by virtio might live). If we find one we still + * allow the backend to potentially filter it out of our list. + */ static bool vhost_section(struct vhost_dev *dev, MemoryRegionSection *section) { - bool result; - bool log_dirty = memory_region_get_dirty_log_mask(section->mr) & - ~(1 << DIRTY_MEMORY_MIGRATION); - result = memory_region_is_ram(section->mr) && - !memory_region_is_rom(section->mr); + MemoryRegion *mr = section->mr; - /* Vhost doesn't handle any block which is doing dirty-tracking other - * than migration; this typically fires on VGA areas. - */ - result &= !log_dirty; + if (memory_region_is_ram(mr) && !memory_region_is_rom(mr)) { + uint8_t dirty_mask = memory_region_get_dirty_log_mask(mr); + uint8_t handled_dirty; - if (result && dev->vhost_ops->vhost_backend_mem_section_filter) { - result &= - dev->vhost_ops->vhost_backend_mem_section_filter(dev, section); + /* + * Kernel based vhost doesn't handle any block which is doing + * dirty-tracking other than migration for which it has + * specific logging support. However for TCG the kernel never + * gets involved anyway so we can also ignore it's + * self-modiying code detection flags. However a vhost-user + * client could still confuse a TCG guest if it re-writes + * executable memory that has already been translated. + */ + handled_dirty = (1 << DIRTY_MEMORY_MIGRATION) | + (1 << DIRTY_MEMORY_CODE); + + if (dirty_mask & ~handled_dirty) { + trace_vhost_reject_section(mr->name, 1); + return false; + } + + if (dev->vhost_ops->vhost_backend_mem_section_filter && + !dev->vhost_ops->vhost_backend_mem_section_filter(dev, section)) { + trace_vhost_reject_section(mr->name, 2); + return false; + } + + trace_vhost_section(mr->name); + return true; + } else { + trace_vhost_reject_section(mr->name, 3); + return false; } - - trace_vhost_section(section->mr->name, result); - return result; } static void vhost_begin(MemoryListener *listener) From ad592e37dfccf730378a44c5fa79acb603a7678d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 5 Jun 2020 16:49:26 +0100 Subject: [PATCH 0907/2595] linux-user: provide fallback pgd_find_hole for bare chroots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running QEMU out of a chroot environment we may not have access to /proc/self/maps. As there is no other "official" way to introspect our memory map we need to fall back to the original technique of repeatedly trying to mmap an address range until we find one that works. Fortunately it's not quite as ugly as the original code given we already re-factored the complications of dealing with the ARM_COMMPAGE. We do make an attempt to skip over brk() which is about the only concrete piece of information we have about the address map at this moment. Fixes: ee9474303 Reported-by: Peter Maydell Signed-off-by: Alex Bennée Message-Id: <20200605154929.26910-12-alex.bennee@linaro.org> --- linux-user/elfload.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index ebc663ea0b..475d243f3b 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2101,6 +2101,50 @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr, } } +/** + * pgd_find_hole_fallback: potential mmap address + * @guest_size: size of available space + * @brk: location of break + * @align: memory alignment + * + * This is a fallback method for finding a hole in the host address + * space if we don't have the benefit of being able to access + * /proc/self/map. It can potentially take a very long time as we can + * only dumbly iterate up the host address space seeing if the + * allocation would work. + */ +static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk, long align) +{ + uintptr_t base; + + /* Start (aligned) at the bottom and work our way up */ + base = ROUND_UP(mmap_min_addr, align); + + while (true) { + uintptr_t align_start, end; + align_start = ROUND_UP(base, align); + end = align_start + guest_size; + + /* if brk is anywhere in the range give ourselves some room to grow. */ + if (align_start <= brk && brk < end) { + base = brk + (16 * MiB); + continue; + } else if (align_start + guest_size < align_start) { + /* we have run out of space */ + return -1; + } else { + int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE | MAP_FIXED; + void * mmap_start = mmap((void *) align_start, guest_size, + PROT_NONE, flags, -1, 0); + if (mmap_start != MAP_FAILED) { + munmap((void *) align_start, guest_size); + return (uintptr_t) mmap_start; + } + base += qemu_host_page_size; + } + } +} + /* Return value for guest_base, or -1 if no hole found. */ static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size, long align) @@ -2116,6 +2160,10 @@ static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size, /* Read brk after we've read the maps, which will malloc. */ brk = (uintptr_t)sbrk(0); + if (!maps) { + return pgd_find_hole_fallback(guest_size, brk, align); + } + /* The first hole is before the first map entry. */ this_start = mmap_min_addr; From 5c3e87f345ac93de9260f12c408d2afd87a6ab3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 5 Jun 2020 16:49:27 +0100 Subject: [PATCH 0908/2595] linux-user: deal with address wrap for ARM_COMMPAGE on 32 bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We rely on the pointer to wrap when accessing the high address of the COMMPAGE so it lands somewhere reasonable. However on 32 bit hosts we cannot afford just to map the entire 4gb address range. The old mmap trial and error code handled this by just checking we could map both the guest_base and the computed COMMPAGE address. We can't just manipulate loadaddr to get what we want so we introduce an offset which pgb_find_hole can apply when looking for a gap for guest_base that ensures there is space left to map the COMMPAGE afterwards. This is arguably a little inefficient for the one 32 bit value (kuser_helper_version) we need to keep there given all the actual code entries are picked up during the translation phase. Fixes: ee94743034b Bug: https://bugs.launchpad.net/qemu/+bug/1880225 Cc: Bug 1880225 <1880225@bugs.launchpad.net> Signed-off-by: Alex Bennée Tested-by: Aleksandar Markovic Cc: Richard Henderson Cc: Peter Maydell Message-Id: <20200605154929.26910-13-alex.bennee@linaro.org> --- linux-user/elfload.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 475d243f3b..b5cb21384a 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -389,7 +389,7 @@ static bool init_guest_commpage(void) { void *want = g2h(ARM_COMMPAGE & -qemu_host_page_size); void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); if (addr == MAP_FAILED) { perror("Allocating guest commpage"); @@ -2113,7 +2113,8 @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr, * only dumbly iterate up the host address space seeing if the * allocation would work. */ -static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk, long align) +static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk, + long align, uintptr_t offset) { uintptr_t base; @@ -2123,7 +2124,7 @@ static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk, lon while (true) { uintptr_t align_start, end; align_start = ROUND_UP(base, align); - end = align_start + guest_size; + end = align_start + guest_size + offset; /* if brk is anywhere in the range give ourselves some room to grow. */ if (align_start <= brk && brk < end) { @@ -2138,7 +2139,7 @@ static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk, lon PROT_NONE, flags, -1, 0); if (mmap_start != MAP_FAILED) { munmap((void *) align_start, guest_size); - return (uintptr_t) mmap_start; + return (uintptr_t) mmap_start + offset; } base += qemu_host_page_size; } @@ -2147,7 +2148,7 @@ static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk, lon /* Return value for guest_base, or -1 if no hole found. */ static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size, - long align) + long align, uintptr_t offset) { GSList *maps, *iter; uintptr_t this_start, this_end, next_start, brk; @@ -2161,7 +2162,7 @@ static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size, brk = (uintptr_t)sbrk(0); if (!maps) { - return pgd_find_hole_fallback(guest_size, brk, align); + return pgd_find_hole_fallback(guest_size, brk, align, offset); } /* The first hole is before the first map entry. */ @@ -2173,7 +2174,7 @@ static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size, this_end = ((MapInfo *)iter->data)->start; next_start = ((MapInfo *)iter->data)->end; - align_start = ROUND_UP(this_start, align); + align_start = ROUND_UP(this_start + offset, align); /* Skip holes that are too small. */ if (align_start >= this_end) { @@ -2223,6 +2224,7 @@ static void pgb_static(const char *image_name, abi_ulong orig_loaddr, { uintptr_t loaddr = orig_loaddr; uintptr_t hiaddr = orig_hiaddr; + uintptr_t offset = 0; uintptr_t addr; if (hiaddr != orig_hiaddr) { @@ -2236,18 +2238,19 @@ static void pgb_static(const char *image_name, abi_ulong orig_loaddr, if (ARM_COMMPAGE) { /* * Extend the allocation to include the commpage. - * For a 64-bit host, this is just 4GiB; for a 32-bit host, - * the address arithmetic will wrap around, but the difference - * will produce the correct allocation size. + * For a 64-bit host, this is just 4GiB; for a 32-bit host we + * need to ensure there is space bellow the guest_base so we + * can map the commpage in the place needed when the address + * arithmetic wraps around. */ if (sizeof(uintptr_t) == 8 || loaddr >= 0x80000000u) { - hiaddr = (uintptr_t)4 << 30; + hiaddr = (uintptr_t) 4 << 30; } else { - loaddr = ARM_COMMPAGE & -align; + offset = -(ARM_COMMPAGE & -align); } } - addr = pgb_find_hole(loaddr, hiaddr - loaddr, align); + addr = pgb_find_hole(loaddr, hiaddr - loaddr, align, offset); if (addr == -1) { /* * If ARM_COMMPAGE, there *might* be a non-consecutive allocation @@ -2282,7 +2285,7 @@ static void pgb_dynamic(const char *image_name, long align) * just above that, and maximises the positive guest addresses. */ commpage = ARM_COMMPAGE & -align; - addr = pgb_find_hole(commpage, -commpage, align); + addr = pgb_find_hole(commpage, -commpage, align, 0); assert(addr != -1); guest_base = addr; } From b6771210b5bba543628b8eeacfea9f994372f880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 5 Jun 2020 16:49:28 +0100 Subject: [PATCH 0909/2595] tests/tcg: add simple commpage test case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The COMMPAGE are a number of kernel provided user-space routines for 32 bit ARM systems. Add a basic series of smoke tests to ensure it is working as it should. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200605154929.26910-14-alex.bennee@linaro.org> --- tests/tcg/arm/Makefile.target | 2 ++ tests/tcg/arm/commpage.c | 61 +++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 tests/tcg/arm/commpage.c diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target index 11c39c601e..3da09a38be 100644 --- a/tests/tcg/arm/Makefile.target +++ b/tests/tcg/arm/Makefile.target @@ -68,6 +68,8 @@ run-semiconsole-arm: semiconsole-arm run-plugin-semiconsole-arm-with-%: $(call skip-test, $<, "MANUAL ONLY") +ARM_TESTS += commpage + TESTS += $(ARM_TESTS) # On ARM Linux only supports 4k pages diff --git a/tests/tcg/arm/commpage.c b/tests/tcg/arm/commpage.c new file mode 100644 index 0000000000..c76e70cb8b --- /dev/null +++ b/tests/tcg/arm/commpage.c @@ -0,0 +1,61 @@ +/* + * Verify the COMMPAGE emulation + * + * The ARM commpage is a set of user space helper functions provided + * by the kernel in an effort to ease portability of user space code + * between different CPUs with potentially different capabilities. It + * is a 32 bit invention and similar to the vdso segment in many ways. + * + * The ABI is documented in the Linux kernel: + * Documentation/arm/kernel_userspace_helpers.rst + * + * Copyright (c) 2020 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include + +#define ARM_COMMPAGE (0xffff0f00u) +#define ARM_KUSER_VERSION (*(int32_t *)(ARM_COMMPAGE + 0xfc)) +typedef void * (get_tls_fn)(void); +#define ARM_KUSER_GET_TLS (*(get_tls_fn *)(ARM_COMMPAGE + 0xe0)) +typedef int (cmpxchg_fn)(int oldval, int newval, volatile int *ptr); +#define ARM_KUSER_CMPXCHG (*(cmpxchg_fn *)(ARM_COMMPAGE + 0xc0)) +typedef void (dmb_fn)(void); +#define ARM_KUSER_DMB (*(dmb_fn *)(ARM_COMMPAGE + 0xa0)) +typedef int (cmpxchg64_fn)(const int64_t *oldval, + const int64_t *newval, + volatile int64_t *ptr); +#define ARM_KUSER_CMPXCHG64 (*(cmpxchg64_fn *)(ARM_COMMPAGE + 0x60)) + +#define fail_unless(x) \ + do { \ + if (!(x)) { \ + fprintf(stderr, "FAILED at %s:%d\n", __FILE__, __LINE__); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) + + +int main(int argc, char *argv[argc]) +{ + void *kuser_tls; + int val = 1; + const int64_t oldval = 1, newval = 2; + int64_t val64 = 1; + + fail_unless(ARM_KUSER_VERSION == 0x5); + kuser_tls = ARM_KUSER_GET_TLS(); + printf("TLS = %p\n", kuser_tls); + fail_unless(kuser_tls != 0); + fail_unless(ARM_KUSER_CMPXCHG(1, 2, &val) == 0); + printf("val = %d\n", val); + /* this is a crash test, not checking an actual barrier occurs */ + ARM_KUSER_DMB(); + fail_unless(ARM_KUSER_CMPXCHG64(&oldval, &newval, &val64) == 0); + printf("val64 = %lld\n", val64); + return 0; +} From 8ef618859c379fdce81c91bc93e0574e36ea76ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 5 Jun 2020 16:49:29 +0100 Subject: [PATCH 0910/2595] linux-user: detect overflow of MAP_FIXED mmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relaxing the restrictions on 64 bit guests leads to the user being able to attempt to map right at the edge of addressable memory. This in turn lead to address overflow tripping the assert in page_set_flags when the end address wrapped around. Detect the wrap earlier and correctly -ENOMEM the guest (in the reported case LTP mmap15). Fixes: 7d8cbbabcb Signed-off-by: Alex Bennée Reported-by: Laurent Vivier Message-Id: <20200605154929.26910-15-alex.bennee@linaro.org> --- linux-user/mmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index caab62909e..0019447892 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -467,7 +467,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, * It can fail only on 64-bit host with 32-bit target. * On any other target/host host mmap() handles this error correctly. */ - if (!guest_range_valid(start, len)) { + if (end < start || !guest_range_valid(start, len)) { errno = ENOMEM; goto fail; } From c6dd82e8a6348096cf7c66a9c1b8a5815aa4ff91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 15 May 2020 18:30:25 +0200 Subject: [PATCH 0911/2595] tests/docker: Remove flex/bison packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU does not use flex/bison packages. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Claudio Fontana Signed-off-by: Alex Bennée Message-Id: <20200515163029.12917-2-philmd@redhat.com> --- tests/docker/dockerfiles/centos7.docker | 2 -- tests/docker/dockerfiles/centos8.docker | 2 -- tests/docker/dockerfiles/debian-xtensa-cross.docker | 2 -- tests/docker/dockerfiles/debian10.docker | 2 -- tests/docker/dockerfiles/debian9.docker | 2 -- tests/docker/dockerfiles/fedora.docker | 2 -- tests/docker/dockerfiles/ubuntu.docker | 2 +- tests/docker/dockerfiles/ubuntu1804.docker | 2 +- 8 files changed, 2 insertions(+), 14 deletions(-) diff --git a/tests/docker/dockerfiles/centos7.docker b/tests/docker/dockerfiles/centos7.docker index 9a2a2e515d..e197acdc3c 100644 --- a/tests/docker/dockerfiles/centos7.docker +++ b/tests/docker/dockerfiles/centos7.docker @@ -5,13 +5,11 @@ RUN yum -y update # Please keep this list sorted alphabetically ENV PACKAGES \ - bison \ bzip2 \ bzip2-devel \ ccache \ csnappy-devel \ dbus-daemon \ - flex \ gcc-c++ \ gcc \ gettext \ diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index bfa0d33c9c..9852c5b9ee 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -3,11 +3,9 @@ FROM centos:8.1.1911 RUN dnf -y update ENV PACKAGES \ SDL-devel \ - bison \ bzip2 \ bzip2-devel \ dbus-daemon \ - flex \ gcc \ gcc-c++ \ gettext \ diff --git a/tests/docker/dockerfiles/debian-xtensa-cross.docker b/tests/docker/dockerfiles/debian-xtensa-cross.docker index e6f93f65ee..beb73f46ba 100644 --- a/tests/docker/dockerfiles/debian-xtensa-cross.docker +++ b/tests/docker/dockerfiles/debian-xtensa-cross.docker @@ -11,11 +11,9 @@ 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 \ curl \ - flex \ gettext \ git \ python3-minimal diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker index 0769700a41..bcdff04ddf 100644 --- a/tests/docker/dockerfiles/debian10.docker +++ b/tests/docker/dockerfiles/debian10.docker @@ -18,12 +18,10 @@ RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ apt install -y --no-install-recommends \ bc \ - bison \ build-essential \ ca-certificates \ clang \ dbus \ - flex \ gdb-multiarch \ gettext \ git \ diff --git a/tests/docker/dockerfiles/debian9.docker b/tests/docker/dockerfiles/debian9.docker index 08cc970feb..0f0ebe530a 100644 --- a/tests/docker/dockerfiles/debian9.docker +++ b/tests/docker/dockerfiles/debian9.docker @@ -18,11 +18,9 @@ RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ apt install -y --no-install-recommends \ bc \ - bison \ build-essential \ ca-certificates \ clang \ - flex \ gdb-multiarch \ gettext \ git \ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 179575ecaa..92b6e11c8a 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -3,7 +3,6 @@ FROM fedora:30 # Please keep this list sorted alphabetically ENV PACKAGES \ bc \ - bison \ brlapi-devel \ bzip2 \ bzip2-devel \ @@ -13,7 +12,6 @@ ENV PACKAGES \ dbus-daemon \ device-mapper-multipath-devel \ findutils \ - flex \ gcc \ gcc-c++ \ gettext \ diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker index 43872417de..161806e6b8 100644 --- a/tests/docker/dockerfiles/ubuntu.docker +++ b/tests/docker/dockerfiles/ubuntu.docker @@ -10,7 +10,7 @@ # FROM ubuntu:20.04 -ENV PACKAGES flex bison \ +ENV PACKAGES \ ccache \ clang \ dbus \ diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker index f66b06f4cf..a10ea2850b 100644 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ b/tests/docker/dockerfiles/ubuntu1804.docker @@ -1,5 +1,5 @@ FROM ubuntu:18.04 -ENV PACKAGES flex bison \ +ENV PACKAGES \ ccache \ clang \ gcc \ From e661e9580cb78b04bc2b843cee8ed23fbef1f311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 15 May 2020 18:30:26 +0200 Subject: [PATCH 0912/2595] tests/vm: Remove flex/bison packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU does not use flex/bison packages. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Claudio Fontana Signed-off-by: Alex Bennée Message-Id: <20200515163029.12917-3-philmd@redhat.com> --- tests/vm/fedora | 1 - tests/vm/freebsd | 1 - tests/vm/netbsd | 1 - tests/vm/openbsd | 1 - tests/vm/ubuntu.i386 | 2 +- 5 files changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/vm/fedora b/tests/vm/fedora index bd9c6cf295..a9195670f4 100755 --- a/tests/vm/fedora +++ b/tests/vm/fedora @@ -32,7 +32,6 @@ class FedoraVM(basevm.BaseVM): pkgs = [ # tools 'git-core', - 'flex', 'bison', 'gcc', 'binutils', 'make', # perl diff --git a/tests/vm/freebsd b/tests/vm/freebsd index 298967fe9c..f87db2b126 100755 --- a/tests/vm/freebsd +++ b/tests/vm/freebsd @@ -38,7 +38,6 @@ class FreeBSDVM(basevm.BaseVM): "bash", "gmake", "gsed", - "flex", "bison", # libs: crypto "gnutls", diff --git a/tests/vm/netbsd b/tests/vm/netbsd index b10c9d429d..cdac502dad 100755 --- a/tests/vm/netbsd +++ b/tests/vm/netbsd @@ -36,7 +36,6 @@ class NetBSDVM(basevm.BaseVM): "bash", "gmake", "gsed", - "flex", "bison", # libs: crypto "gnutls", diff --git a/tests/vm/openbsd b/tests/vm/openbsd index 0b705f4945..13e7f9a6d5 100755 --- a/tests/vm/openbsd +++ b/tests/vm/openbsd @@ -35,7 +35,6 @@ class OpenBSDVM(basevm.BaseVM): "bash", "gmake", "gsed", - "bison", # libs: usb "libusb1", diff --git a/tests/vm/ubuntu.i386 b/tests/vm/ubuntu.i386 index 1570775335..24527cc78c 100755 --- a/tests/vm/ubuntu.i386 +++ b/tests/vm/ubuntu.i386 @@ -52,7 +52,7 @@ class UbuntuX86VM(basevm.BaseVM): self.ssh_root_check("sed -ie s/^#\ deb-src/deb-src/g /etc/apt/sources.list") self.ssh_root_check("apt-get update") self.ssh_root_check("apt-get build-dep -y qemu") - self.ssh_root_check("apt-get install -y libfdt-dev flex bison language-pack-en") + self.ssh_root_check("apt-get install -y libfdt-dev language-pack-en") self.ssh_root("poweroff") self.wait() os.rename(img_tmp, img) From 48ba32e62210fde35c1d0dc6164233bcc8bb331d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 15 May 2020 18:30:28 +0200 Subject: [PATCH 0913/2595] cirrus-ci: Remove flex/bison packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU does not use flex/bison packages. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Li-Wen Hsu Signed-off-by: Alex Bennée Message-Id: <20200515163029.12917-5-philmd@redhat.com> --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index de0727cb09..ce7850a320 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -7,7 +7,7 @@ freebsd_12_task: cpu: 8 memory: 8G install_script: ASSUME_ALWAYS_YES=yes pkg bootstrap -f ; pkg install -y - bash bison curl cyrus-sasl git glib gmake gnutls gsed + bash curl cyrus-sasl git glib gmake gnutls gsed nettle perl5 pixman pkgconf png usbredir script: - mkdir build From a5b04ccd742f6c58a1d305530d9e07ad9731b8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 15 May 2020 18:30:29 +0200 Subject: [PATCH 0914/2595] scripts/coverity-scan: Remove flex/bison packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU does not use flex/bison packages. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Claudio Fontana Signed-off-by: Alex Bennée Message-Id: <20200515163029.12917-6-philmd@redhat.com> --- scripts/coverity-scan/coverity-scan.docker | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/coverity-scan/coverity-scan.docker b/scripts/coverity-scan/coverity-scan.docker index a4f64d1283..ad4d64c0f8 100644 --- a/scripts/coverity-scan/coverity-scan.docker +++ b/scripts/coverity-scan/coverity-scan.docker @@ -19,7 +19,6 @@ FROM fedora:30 ENV PACKAGES \ alsa-lib-devel \ bc \ - bison \ brlapi-devel \ bzip2 \ bzip2-devel \ @@ -30,7 +29,6 @@ ENV PACKAGES \ dbus-daemon \ device-mapper-multipath-devel \ findutils \ - flex \ gcc \ gcc-c++ \ gettext \ From 2fd51b19c9ee73b0a1f07dcebd753a00f4fa4b26 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 15 May 2020 14:48:54 -0700 Subject: [PATCH 0915/2595] decodetree: Tidy error_with_file Use proper varargs to print the arguments. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- scripts/decodetree.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/scripts/decodetree.py b/scripts/decodetree.py index f9d204aa36..b559db3086 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -51,23 +51,27 @@ def error_with_file(file, lineno, *args): global output_file global output_fd + prefix = '' + if file: + prefix += '{0}:'.format(file) if lineno: - r = '{0}:{1}: error:'.format(file, lineno) - elif input_file: - r = '{0}: error:'.format(file) - else: - r = 'error:' - for a in args: - r += ' ' + str(a) - r += '\n' - sys.stderr.write(r) + prefix += '{0}:'.format(lineno) + if prefix: + prefix += ' ' + print(prefix, end='error: ', file=sys.stderr) + print(*args, file=sys.stderr) + if output_file and output_fd: output_fd.close() os.remove(output_file) exit(1) +# end error_with_file + def error(lineno, *args): - error_with_file(input_file, lineno, args) + error_with_file(input_file, lineno, *args) +# end error + def output(*args): global output_fd From 040145c4f8dad9391031203315b5ae4bae8dde1a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 16 May 2020 10:50:43 -0700 Subject: [PATCH 0916/2595] decodetree: Rename MultiPattern to IncMultiPattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Name the current node for "inclusive" multi-pattern, in preparation for adding a node for "exclusive" multi-pattern. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- scripts/decodetree.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/decodetree.py b/scripts/decodetree.py index b559db3086..7af6b3056d 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -371,7 +371,7 @@ class Pattern(General): # end Pattern -class MultiPattern(General): +class IncMultiPattern(General): """Class representing an overlapping set of instruction patterns""" def __init__(self, lineno, pats, fixb, fixm, udfm, w): @@ -410,7 +410,7 @@ class MultiPattern(General): output(ind, '}\n') else: p.output_code(i, extracted, p.fixedbits, p.fixedmask) -#end MultiPattern +#end IncMultiPattern def parse_field(lineno, name, toks): @@ -751,8 +751,8 @@ def parse_generic(lineno, is_format, name, toks): .format(allbits ^ insnmask)) # end parse_general -def build_multi_pattern(lineno, pats): - """Validate the Patterns going into a MultiPattern.""" +def build_incmulti_pattern(lineno, pats): + """Validate the Patterns going into a IncMultiPattern.""" global patterns global insnmask @@ -792,9 +792,9 @@ def build_multi_pattern(lineno, pats): else: repeat = False - mp = MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask, width) + mp = IncMultiPattern(lineno, pats, fixedbits, fixedmask, undefmask, width) patterns.append(mp) -# end build_multi_pattern +# end build_incmulti_pattern def parse_file(f): """Parse all of the patterns within a file""" @@ -860,7 +860,7 @@ def parse_file(f): error(start_lineno, 'indentation ', indent, ' != ', nesting) pats = patterns patterns = saved_pats.pop() - build_multi_pattern(lineno, pats) + build_incmulti_pattern(lineno, pats) toks = [] continue From df63044d02bf79241257bafe282d966c86933b68 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 16 May 2020 11:19:45 -0700 Subject: [PATCH 0917/2595] decodetree: Split out MultiPattern from IncMultiPattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- scripts/decodetree.py | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/scripts/decodetree.py b/scripts/decodetree.py index 7af6b3056d..ea313bcdea 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -371,7 +371,32 @@ class Pattern(General): # end Pattern -class IncMultiPattern(General): +class MultiPattern(General): + """Class representing a set of instruction patterns""" + + def __init__(self, lineno, pats): + self.file = input_file + self.lineno = lineno + self.pats = pats + self.base = None + self.fixedbits = 0 + self.fixedmask = 0 + self.undefmask = 0 + self.width = None + + def __str__(self): + r = 'group' + if self.fixedbits is not None: + r += ' ' + str_match_bits(self.fixedbits, self.fixedmask) + return r + + def output_decl(self): + for p in self.pats: + p.output_decl() +# end MultiPattern + + +class IncMultiPattern(MultiPattern): """Class representing an overlapping set of instruction patterns""" def __init__(self, lineno, pats, fixb, fixm, udfm, w): @@ -384,16 +409,6 @@ class IncMultiPattern(General): self.undefmask = udfm self.width = w - def __str__(self): - r = "{" - for p in self.pats: - r = r + ' ' + str(p) - return r + "}" - - def output_decl(self): - for p in self.pats: - p.output_decl() - def output_code(self, i, extracted, outerbits, outermask): global translate_prefix ind = str_indent(i) From b44b3449a08818f0eb25b93faaf535e9c9a85e50 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 16 May 2020 13:15:02 -0700 Subject: [PATCH 0918/2595] decodetree: Allow group covering the entire insn space This is an edge case for sure, but the logic that disallowed this case was faulty. Further, a few fixes scattered about can allow this to work. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- scripts/decodetree.py | 14 +++++++++++--- ...est1.decode => succ_pattern_group_nest2.decode} | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) rename tests/decode/{err_pattern_group_nest1.decode => succ_pattern_group_nest2.decode} (85%) diff --git a/scripts/decodetree.py b/scripts/decodetree.py index ea313bcdea..3307c74c30 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -124,6 +124,7 @@ def is_pow2(x): def ctz(x): """Return the number of times 2 factors into X.""" + assert x != 0 r = 0 while ((x >> r) & 1) == 0: r += 1 @@ -131,6 +132,8 @@ def ctz(x): def is_contiguous(bits): + if bits == 0: + return -1 shift = ctz(bits) if is_pow2((bits >> shift) + 1): return shift @@ -793,9 +796,8 @@ def build_incmulti_pattern(lineno, pats): error(lineno, 'width mismatch in patterns within braces') repeat = True - while repeat: - if fixedmask == 0: - error(lineno, 'no overlap in patterns within braces') + fixedbits = 0 + while repeat and fixedmask != 0: fixedbits = None for p in pats: thisbits = p.fixedbits & fixedmask @@ -978,6 +980,12 @@ def build_tree(pats, outerbits, outermask): innermask &= i.fixedmask if innermask == 0: + # Edge condition: One pattern covers the entire insnmask + if len(pats) == 1: + t = Tree(outermask, innermask) + t.subs.append((0, pats[0])) + return t + text = 'overlapping patterns:' for p in pats: text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p) diff --git a/tests/decode/err_pattern_group_nest1.decode b/tests/decode/succ_pattern_group_nest2.decode similarity index 85% rename from tests/decode/err_pattern_group_nest1.decode rename to tests/decode/succ_pattern_group_nest2.decode index 92e971c3c5..8d5ab4b2d3 100644 --- a/tests/decode/err_pattern_group_nest1.decode +++ b/tests/decode/succ_pattern_group_nest2.decode @@ -6,7 +6,7 @@ %sub3 16:8 %sub4 24:8 -# Groups with no overlap are supposed to fail +# Group with complete overlap of the two patterns { top 00000000 00000000 00000000 00000000 sub4 ........ ........ ........ ........ %sub1 %sub2 %sub3 %sub4 From 08561fc1283568d9892033f98651010a18d8f108 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 17 May 2020 10:14:11 -0700 Subject: [PATCH 0919/2595] decodetree: Move semantic propagation into classes Create ExcMultiPattern to hold an set of non-overlapping patterns. The body of build_tree, prop_format become member functions on this class. Add minimal member functions to Pattern and MultiPattern to allow recusion through the tree. Move the bulk of build_incmulti_pattern to prop_masks and prop_width in MultiPattern, since we will need this for both kinds of containers. Only perform prop_width for variablewidth. Remove global patterns variable, and pass down container object into parse_file from main. No functional change in all of this. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- scripts/decodetree.py | 464 +++++++++++++++++++++++------------------- 1 file changed, 253 insertions(+), 211 deletions(-) diff --git a/scripts/decodetree.py b/scripts/decodetree.py index 3307c74c30..0ba01e049c 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -31,7 +31,6 @@ variablewidth = False fields = {} arguments = {} formats = {} -patterns = [] allpatterns = [] anyextern = False @@ -371,16 +370,27 @@ class Pattern(General): output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n') output(ind, 'if (', translate_prefix, '_', self.name, '(ctx, &u.f_', arg, ')) return true;\n') + + # Normal patterns do not have children. + def build_tree(self): + return + def prop_masks(self): + return + def prop_format(self): + return + def prop_width(self): + return + # end Pattern class MultiPattern(General): """Class representing a set of instruction patterns""" - def __init__(self, lineno, pats): + def __init__(self, lineno): self.file = input_file self.lineno = lineno - self.pats = pats + self.pats = [] self.base = None self.fixedbits = 0 self.fixedmask = 0 @@ -396,22 +406,63 @@ class MultiPattern(General): def output_decl(self): for p in self.pats: p.output_decl() + + def prop_masks(self): + global insnmask + + fixedmask = insnmask + undefmask = insnmask + + # Collect fixedmask/undefmask for all of the children. + for p in self.pats: + p.prop_masks() + fixedmask &= p.fixedmask + undefmask &= p.undefmask + + # Widen fixedmask until all fixedbits match + repeat = True + fixedbits = 0 + while repeat and fixedmask != 0: + fixedbits = None + for p in self.pats: + thisbits = p.fixedbits & fixedmask + if fixedbits is None: + fixedbits = thisbits + elif fixedbits != thisbits: + fixedmask &= ~(fixedbits ^ thisbits) + break + else: + repeat = False + + self.fixedbits = fixedbits + self.fixedmask = fixedmask + self.undefmask = undefmask + + def build_tree(self): + for p in self.pats: + p.build_tree() + + def prop_format(self): + for p in self.pats: + p.build_tree() + + def prop_width(self): + width = None + for p in self.pats: + p.prop_width() + if width is None: + width = p.width + elif width != p.width: + error_with_file(self.file, self.lineno, + 'width mismatch in patterns within braces') + self.width = width + # end MultiPattern class IncMultiPattern(MultiPattern): """Class representing an overlapping set of instruction patterns""" - def __init__(self, lineno, pats, fixb, fixm, udfm, w): - self.file = input_file - self.lineno = lineno - self.pats = pats - self.base = None - self.fixedbits = fixb - self.fixedmask = fixm - self.undefmask = udfm - self.width = w - def output_code(self, i, extracted, outerbits, outermask): global translate_prefix ind = str_indent(i) @@ -431,6 +482,153 @@ class IncMultiPattern(MultiPattern): #end IncMultiPattern +class Tree: + """Class representing a node in a decode tree""" + + def __init__(self, fm, tm): + self.fixedmask = fm + self.thismask = tm + self.subs = [] + self.base = None + + def str1(self, i): + ind = str_indent(i) + r = '{0}{1:08x}'.format(ind, self.fixedmask) + if self.format: + r += ' ' + self.format.name + r += ' [\n' + for (b, s) in self.subs: + r += '{0} {1:08x}:\n'.format(ind, b) + r += s.str1(i + 4) + '\n' + r += ind + ']' + return r + + def __str__(self): + return self.str1(0) + + def output_code(self, i, extracted, outerbits, outermask): + ind = str_indent(i) + + # If we identified all nodes below have the same format, + # extract the fields now. + if not extracted and self.base: + output(ind, self.base.extract_name(), + '(ctx, &u.f_', self.base.base.name, ', insn);\n') + extracted = True + + # Attempt to aid the compiler in producing compact switch statements. + # If the bits in the mask are contiguous, extract them. + sh = is_contiguous(self.thismask) + if sh > 0: + # Propagate SH down into the local functions. + def str_switch(b, sh=sh): + return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh) + + def str_case(b, sh=sh): + return '0x{0:x}'.format(b >> sh) + else: + def str_switch(b): + return 'insn & 0x{0:08x}'.format(b) + + def str_case(b): + return '0x{0:08x}'.format(b) + + output(ind, 'switch (', str_switch(self.thismask), ') {\n') + for b, s in sorted(self.subs): + assert (self.thismask & ~s.fixedmask) == 0 + innermask = outermask | self.thismask + innerbits = outerbits | b + output(ind, 'case ', str_case(b), ':\n') + output(ind, ' /* ', + str_match_bits(innerbits, innermask), ' */\n') + s.output_code(i + 4, extracted, innerbits, innermask) + output(ind, ' return false;\n') + output(ind, '}\n') +# end Tree + + +class ExcMultiPattern(MultiPattern): + """Class representing a non-overlapping set of instruction patterns""" + + def output_code(self, i, extracted, outerbits, outermask): + # Defer everything to our decomposed Tree node + self.tree.output_code(i, extracted, outerbits, outermask) + + @staticmethod + def __build_tree(pats, outerbits, outermask): + # Find the intersection of all remaining fixedmask. + innermask = ~outermask & insnmask + for i in pats: + innermask &= i.fixedmask + + if innermask == 0: + # Edge condition: One pattern covers the entire insnmask + if len(pats) == 1: + t = Tree(outermask, innermask) + t.subs.append((0, pats[0])) + return t + + text = 'overlapping patterns:' + for p in pats: + text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p) + error_with_file(pats[0].file, pats[0].lineno, text) + + fullmask = outermask | innermask + + # Sort each element of pats into the bin selected by the mask. + bins = {} + for i in pats: + fb = i.fixedbits & innermask + if fb in bins: + bins[fb].append(i) + else: + bins[fb] = [i] + + # We must recurse if any bin has more than one element or if + # the single element in the bin has not been fully matched. + t = Tree(fullmask, innermask) + + for b, l in bins.items(): + s = l[0] + if len(l) > 1 or s.fixedmask & ~fullmask != 0: + s = ExcMultiPattern.__build_tree(l, b | outerbits, fullmask) + t.subs.append((b, s)) + + return t + + def build_tree(self): + super().prop_format() + self.tree = self.__build_tree(self.pats, self.fixedbits, + self.fixedmask) + + @staticmethod + def __prop_format(tree): + """Propagate Format objects into the decode tree""" + + # Depth first search. + for (b, s) in tree.subs: + if isinstance(s, Tree): + ExcMultiPattern.__prop_format(s) + + # If all entries in SUBS have the same format, then + # propagate that into the tree. + f = None + for (b, s) in tree.subs: + if f is None: + f = s.base + if f is None: + return + if f is not s.base: + return + tree.base = f + + def prop_format(self): + super().prop_format() + self.__prop_format(self.tree) + +# end ExcMultiPattern + + def parse_field(lineno, name, toks): """Parse one instruction field from TOKS at LINENO""" global fields @@ -587,18 +785,19 @@ def infer_format(arg, fieldmask, flds, width): # end infer_format -def parse_generic(lineno, is_format, name, toks): +def parse_generic(lineno, parent_pat, name, toks): """Parse one instruction format from TOKS at LINENO""" global fields global arguments global formats - global patterns global allpatterns global re_ident global insnwidth global insnmask global variablewidth + is_format = parent_pat is None + fixedmask = 0 fixedbits = 0 undefmask = 0 @@ -749,7 +948,7 @@ def parse_generic(lineno, is_format, name, toks): error(lineno, 'field {0} not initialized'.format(f)) pat = Pattern(name, lineno, fmt, fixedbits, fixedmask, undefmask, fieldmask, flds, width) - patterns.append(pat) + parent_pat.pats.append(pat) allpatterns.append(pat) # Validate the masks that we have assembled. @@ -769,61 +968,16 @@ def parse_generic(lineno, is_format, name, toks): .format(allbits ^ insnmask)) # end parse_general -def build_incmulti_pattern(lineno, pats): - """Validate the Patterns going into a IncMultiPattern.""" - global patterns - global insnmask - if len(pats) < 2: - error(lineno, 'less than two patterns within braces') - - fixedmask = insnmask - undefmask = insnmask - - # Collect fixed/undefmask for all of the children. - # Move the defining lineno back to that of the first child. - for p in pats: - fixedmask &= p.fixedmask - undefmask &= p.undefmask - if p.lineno < lineno: - lineno = p.lineno - - width = None - for p in pats: - if width is None: - width = p.width - elif width != p.width: - error(lineno, 'width mismatch in patterns within braces') - - repeat = True - fixedbits = 0 - while repeat and fixedmask != 0: - fixedbits = None - for p in pats: - thisbits = p.fixedbits & fixedmask - if fixedbits is None: - fixedbits = thisbits - elif fixedbits != thisbits: - fixedmask &= ~(fixedbits ^ thisbits) - break - else: - repeat = False - - mp = IncMultiPattern(lineno, pats, fixedbits, fixedmask, undefmask, width) - patterns.append(mp) -# end build_incmulti_pattern - -def parse_file(f): +def parse_file(f, parent_pat): """Parse all of the patterns within a file""" - global patterns - # Read all of the lines of the file. Concatenate lines # ending in backslash; discard empty lines and comments. toks = [] lineno = 0 nesting = 0 - saved_pats = [] + nesting_pats = [] for line in f: lineno += 1 @@ -868,16 +1022,20 @@ def parse_file(f): # End nesting? if name == '}': - if nesting == 0: - error(start_lineno, 'mismatched close brace') if len(toks) != 0: error(start_lineno, 'extra tokens after close brace') + if len(parent_pat.pats) < 2: + error(lineno, 'less than two patterns within braces') + + try: + parent_pat = nesting_pats.pop() + except: + error(lineno, 'mismatched close brace') + nesting -= 2 if indent != nesting: - error(start_lineno, 'indentation ', indent, ' != ', nesting) - pats = patterns - patterns = saved_pats.pop() - build_incmulti_pattern(lineno, pats) + error(lineno, 'indentation ', indent, ' != ', nesting) + toks = [] continue @@ -889,8 +1047,12 @@ def parse_file(f): if name == '{': if len(toks) != 0: error(start_lineno, 'extra tokens after open brace') - saved_pats.append(patterns) - patterns = [] + + nested_pat = IncMultiPattern(start_lineno) + parent_pat.pats.append(nested_pat) + nesting_pats.append(parent_pat) + parent_pat = nested_pat + nesting += 2 toks = [] continue @@ -901,121 +1063,13 @@ def parse_file(f): elif name[0] == '&': parse_arguments(start_lineno, name[1:], toks) elif name[0] == '@': - parse_generic(start_lineno, True, name[1:], toks) + parse_generic(start_lineno, None, name[1:], toks) else: - parse_generic(start_lineno, False, name, toks) + parse_generic(start_lineno, parent_pat, name, toks) toks = [] # end parse_file -class Tree: - """Class representing a node in a decode tree""" - - def __init__(self, fm, tm): - self.fixedmask = fm - self.thismask = tm - self.subs = [] - self.base = None - - def str1(self, i): - ind = str_indent(i) - r = '{0}{1:08x}'.format(ind, self.fixedmask) - if self.format: - r += ' ' + self.format.name - r += ' [\n' - for (b, s) in self.subs: - r += '{0} {1:08x}:\n'.format(ind, b) - r += s.str1(i + 4) + '\n' - r += ind + ']' - return r - - def __str__(self): - return self.str1(0) - - def output_code(self, i, extracted, outerbits, outermask): - ind = str_indent(i) - - # If we identified all nodes below have the same format, - # extract the fields now. - if not extracted and self.base: - output(ind, self.base.extract_name(), - '(ctx, &u.f_', self.base.base.name, ', insn);\n') - extracted = True - - # Attempt to aid the compiler in producing compact switch statements. - # If the bits in the mask are contiguous, extract them. - sh = is_contiguous(self.thismask) - if sh > 0: - # Propagate SH down into the local functions. - def str_switch(b, sh=sh): - return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh) - - def str_case(b, sh=sh): - return '0x{0:x}'.format(b >> sh) - else: - def str_switch(b): - return 'insn & 0x{0:08x}'.format(b) - - def str_case(b): - return '0x{0:08x}'.format(b) - - output(ind, 'switch (', str_switch(self.thismask), ') {\n') - for b, s in sorted(self.subs): - assert (self.thismask & ~s.fixedmask) == 0 - innermask = outermask | self.thismask - innerbits = outerbits | b - output(ind, 'case ', str_case(b), ':\n') - output(ind, ' /* ', - str_match_bits(innerbits, innermask), ' */\n') - s.output_code(i + 4, extracted, innerbits, innermask) - output(ind, ' return false;\n') - output(ind, '}\n') -# end Tree - - -def build_tree(pats, outerbits, outermask): - # Find the intersection of all remaining fixedmask. - innermask = ~outermask & insnmask - for i in pats: - innermask &= i.fixedmask - - if innermask == 0: - # Edge condition: One pattern covers the entire insnmask - if len(pats) == 1: - t = Tree(outermask, innermask) - t.subs.append((0, pats[0])) - return t - - text = 'overlapping patterns:' - for p in pats: - text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p) - error_with_file(pats[0].file, pats[0].lineno, text) - - fullmask = outermask | innermask - - # Sort each element of pats into the bin selected by the mask. - bins = {} - for i in pats: - fb = i.fixedbits & innermask - if fb in bins: - bins[fb].append(i) - else: - bins[fb] = [i] - - # We must recurse if any bin has more than one element or if - # the single element in the bin has not been fully matched. - t = Tree(fullmask, innermask) - - for b, l in bins.items(): - s = l[0] - if len(l) > 1 or s.fixedmask & ~fullmask != 0: - s = build_tree(l, b | outerbits, fullmask) - t.subs.append((b, s)) - - return t -# end build_tree - - class SizeTree: """Class representing a node in a size decode tree""" @@ -1157,28 +1211,6 @@ def build_size_tree(pats, width, outerbits, outermask): # end build_size_tree -def prop_format(tree): - """Propagate Format objects into the decode tree""" - - # Depth first search. - for (b, s) in tree.subs: - if isinstance(s, Tree): - prop_format(s) - - # If all entries in SUBS have the same format, then - # propagate that into the tree. - f = None - for (b, s) in tree.subs: - if f is None: - f = s.base - if f is None: - return - if f is not s.base: - return - tree.base = f -# end prop_format - - def prop_size(tree): """Propagate minimum widths up the decode size tree""" @@ -1199,7 +1231,6 @@ def prop_size(tree): def main(): global arguments global formats - global patterns global allpatterns global translate_scope global translate_prefix @@ -1246,18 +1277,29 @@ def main(): if len(args) < 1: error(0, 'missing input file') + + toppat = ExcMultiPattern(0) + for filename in args: input_file = filename f = open(filename, 'r') - parse_file(f) + parse_file(f, toppat) f.close() - if variablewidth: - stree = build_size_tree(patterns, 8, 0, 0) - prop_size(stree) + # We do not want to compute masks for toppat, because those masks + # are used as a starting point for build_tree. For toppat, we must + # insist that decode begins from naught. + for i in toppat.pats: + i.prop_masks() - dtree = build_tree(patterns, 0, 0) - prop_format(dtree) + toppat.build_tree() + toppat.prop_format() + + if variablewidth: + for i in toppat.pats: + i.prop_width() + stree = build_size_tree(toppat.pats, 8, 0, 0) + prop_size(stree) if output_file: output_fd = open(output_file, 'w') @@ -1316,7 +1358,7 @@ def main(): f = arguments[n] output(i4, i4, f.struct_name(), ' f_', f.name, ';\n') output(i4, '} u;\n\n') - dtree.output_code(4, False, 0, 0) + toppat.output_code(4, False, 0, 0) output(i4, 'return false;\n') output('}\n') From 067e8b0f45d650ced89a638577b85443f3333480 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 18 May 2020 08:45:32 -0700 Subject: [PATCH 0920/2595] decodetree: Implement non-overlapping groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Intended to be nested within overlapping groups. Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Suggested-by: Peter Maydell Signed-off-by: Richard Henderson --- scripts/decodetree.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/scripts/decodetree.py b/scripts/decodetree.py index 0ba01e049c..7e3b1d1399 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -1021,16 +1021,20 @@ def parse_file(f, parent_pat): del toks[0] # End nesting? - if name == '}': + if name == '}' or name == ']': if len(toks) != 0: error(start_lineno, 'extra tokens after close brace') if len(parent_pat.pats) < 2: error(lineno, 'less than two patterns within braces') + # Make sure { } and [ ] nest properly. + if (name == '}') != isinstance(parent_pat, IncMultiPattern): + error(lineno, 'mismatched close brace') + try: parent_pat = nesting_pats.pop() except: - error(lineno, 'mismatched close brace') + error(lineno, 'extra close brace') nesting -= 2 if indent != nesting: @@ -1044,11 +1048,14 @@ def parse_file(f, parent_pat): error(start_lineno, 'indentation ', indent, ' != ', nesting) # Start nesting? - if name == '{': + if name == '{' or name == '[': if len(toks) != 0: error(start_lineno, 'extra tokens after open brace') - nested_pat = IncMultiPattern(start_lineno) + if name == '{': + nested_pat = IncMultiPattern(start_lineno) + else: + nested_pat = ExcMultiPattern(start_lineno) parent_pat.pats.append(nested_pat) nesting_pats.append(parent_pat) parent_pat = nested_pat @@ -1067,6 +1074,9 @@ def parse_file(f, parent_pat): else: parse_generic(start_lineno, parent_pat, name, toks) toks = [] + + if nesting != 0: + error(lineno, 'missing close brace') # end parse_file From 33c0f25bfd7af2848d078afe2876dcb0d5a1c6d3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 2 Jun 2020 16:13:28 -0700 Subject: [PATCH 0921/2595] tests/decode: Test non-overlapping groups Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tests/decode/err_pattern_group_nest1.decode | 14 ++++++++++++++ tests/decode/err_pattern_group_nest2.decode | 6 ++++++ tests/decode/err_pattern_group_nest3.decode | 14 ++++++++++++++ tests/decode/succ_pattern_group_nest3.decode | 11 +++++++++++ 4 files changed, 45 insertions(+) create mode 100644 tests/decode/err_pattern_group_nest1.decode create mode 100644 tests/decode/err_pattern_group_nest2.decode create mode 100644 tests/decode/err_pattern_group_nest3.decode create mode 100644 tests/decode/succ_pattern_group_nest3.decode diff --git a/tests/decode/err_pattern_group_nest1.decode b/tests/decode/err_pattern_group_nest1.decode new file mode 100644 index 0000000000..7d09891a1c --- /dev/null +++ b/tests/decode/err_pattern_group_nest1.decode @@ -0,0 +1,14 @@ +# This work is licensed under the terms of the GNU LGPL, version 2 or later. +# See the COPYING.LIB file in the top-level directory. + +%sub1 0:8 +%sub2 8:8 + +# Make sure braces are matched +{ + top 00000000 00000000 00000000 00000000 + [ + sub1 00000000 00000000 00000000 ........ %sub1 + sub2 00000000 00000000 ........ ........ %sub1 %sub2 + } +} diff --git a/tests/decode/err_pattern_group_nest2.decode b/tests/decode/err_pattern_group_nest2.decode new file mode 100644 index 0000000000..c172239e9b --- /dev/null +++ b/tests/decode/err_pattern_group_nest2.decode @@ -0,0 +1,6 @@ +# This work is licensed under the terms of the GNU LGPL, version 2 or later. +# See the COPYING.LIB file in the top-level directory. + +# Make sure braces are matched +{ + [ diff --git a/tests/decode/err_pattern_group_nest3.decode b/tests/decode/err_pattern_group_nest3.decode new file mode 100644 index 0000000000..b085d01410 --- /dev/null +++ b/tests/decode/err_pattern_group_nest3.decode @@ -0,0 +1,14 @@ +# This work is licensed under the terms of the GNU LGPL, version 2 or later. +# See the COPYING.LIB file in the top-level directory. + +%sub1 0:8 +%sub2 8:8 + +# The exclusive group should error for overlap. +{ + top 00000000 00000000 00000000 00000000 + [ + sub1 00000000 00000000 00000000 ........ %sub1 + sub2 00000000 00000000 ........ ........ %sub1 %sub2 + ] +} diff --git a/tests/decode/succ_pattern_group_nest3.decode b/tests/decode/succ_pattern_group_nest3.decode new file mode 100644 index 0000000000..156249f090 --- /dev/null +++ b/tests/decode/succ_pattern_group_nest3.decode @@ -0,0 +1,11 @@ +# This work is licensed under the terms of the GNU LGPL, version 2 or later. +# See the COPYING.LIB file in the top-level directory. + +{ + [ + sub1 00000000 a:8 b:8 c:8 + sub2 00000001 a:8 b:8 c:8 + sub3 00000010 a:8 b:8 c:8 + ] + sub4 000000 d:2 a:8 b:8 c:8 +} From 077f0f3dade3dcb38f43cc728fa26c4f6affcdd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Oct 2018 22:27:22 +0200 Subject: [PATCH 0922/2595] hw/sparc/sun4m: Use UnimplementedDevice for I/O devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These devices are not slots on a bus, but real I/O devices that we do not implement. As the ISDN ROM would be a ROMD device, also model it as UnimplementedDevice. Reviewed-by: Artyom Tarasenko Message-Id: <20200510152840.13558-2-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/sparc/Kconfig | 1 + hw/sparc/sun4m.c | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/sparc/Kconfig b/hw/sparc/Kconfig index 22aff2f5b7..91805afab6 100644 --- a/hw/sparc/Kconfig +++ b/hw/sparc/Kconfig @@ -5,6 +5,7 @@ config SUN4M select CS4231 select ECCMEMCTL select EMPTY_SLOT + select UNIMP select ESCC select ESP select FDC diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 8dda3f7292..fa3dd7775f 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -47,6 +47,7 @@ #include "hw/nvram/fw_cfg.h" #include "hw/char/escc.h" #include "hw/empty_slot.h" +#include "hw/misc/unimp.h" #include "hw/irq.h" #include "hw/loader.h" #include "elf.h" @@ -968,7 +969,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, } if (hwdef->sx_base) { - empty_slot_init(hwdef->sx_base, 0x2000); + create_unimplemented_device("SUNW,sx", hwdef->sx_base, 0x2000); } nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 1968, 8); @@ -1031,14 +1032,16 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, if (hwdef->dbri_base) { /* ISDN chip with attached CS4215 audio codec */ /* prom space */ - empty_slot_init(hwdef->dbri_base+0x1000, 0x30); + create_unimplemented_device("SUNW,DBRI.prom", + hwdef->dbri_base + 0x1000, 0x30); /* reg space */ - empty_slot_init(hwdef->dbri_base+0x10000, 0x100); + create_unimplemented_device("SUNW,DBRI", + hwdef->dbri_base + 0x10000, 0x100); } if (hwdef->bpp_base) { /* parallel port */ - empty_slot_init(hwdef->bpp_base, 0x20); + create_unimplemented_device("SUNW,bpp", hwdef->bpp_base, 0x20); } initrd_size = 0; From 6c339493c8dbb709c98f471144eebf74c4cca1ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 24 Jun 2019 17:20:37 +0200 Subject: [PATCH 0923/2595] hw/misc/empty_slot: Lower address space priority MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Empty slots model RAZ/WI access on a bus. Since we can still (hot) plug devices on the bus, lower the slot priority, so device added later is accessed first. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Artyom Tarasenko Message-Id: <20200510152840.13558-3-f4bug@amsat.org> --- hw/core/empty_slot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/core/empty_slot.c b/hw/core/empty_slot.c index 3ba450e1ca..5ab426e965 100644 --- a/hw/core/empty_slot.c +++ b/hw/core/empty_slot.c @@ -67,7 +67,7 @@ void empty_slot_init(hwaddr addr, uint64_t slot_size) qdev_init_nofail(dev); - sysbus_mmio_map(s, 0, addr); + sysbus_mmio_map_overlap(s, 0, addr, -10000); } } From 4bbadef0e3da3f455374e83cb9249c2afe497b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 24 Jun 2019 17:19:22 +0200 Subject: [PATCH 0924/2595] hw/misc/empty_slot: Convert 'size' field as qdev property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Acked-by: Artyom Tarasenko Message-Id: <20200510152840.13558-4-f4bug@amsat.org> --- hw/core/empty_slot.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hw/core/empty_slot.c b/hw/core/empty_slot.c index 5ab426e965..0df086fe98 100644 --- a/hw/core/empty_slot.c +++ b/hw/core/empty_slot.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "qemu/module.h" +#include "hw/qdev-properties.h" #include "hw/empty_slot.h" //#define DEBUG_EMPTY_SLOT @@ -57,17 +58,13 @@ void empty_slot_init(hwaddr addr, uint64_t slot_size) if (slot_size > 0) { /* Only empty slots larger than 0 byte need handling. */ DeviceState *dev; - SysBusDevice *s; - EmptySlot *e; dev = qdev_create(NULL, TYPE_EMPTY_SLOT); - s = SYS_BUS_DEVICE(dev); - e = EMPTY_SLOT(dev); - e->size = slot_size; + qdev_prop_set_uint64(dev, "size", slot_size); qdev_init_nofail(dev); - sysbus_mmio_map_overlap(s, 0, addr, -10000); + sysbus_mmio_map_overlap(SYS_BUS_DEVICE(dev), 0, addr, -10000); } } @@ -80,11 +77,17 @@ static void empty_slot_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); } +static Property empty_slot_properties[] = { + DEFINE_PROP_UINT64("size", EmptySlot, size, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void empty_slot_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = empty_slot_realize; + device_class_set_props(dc, empty_slot_properties); } static const TypeInfo empty_slot_info = { From 07ddf5cbe2e9499cc2d238e5c864ac3f5bdd25ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 24 Jun 2019 17:23:31 +0200 Subject: [PATCH 0925/2595] hw/misc/empty_slot: Add a 'name' qdev property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a 'name' qdev property so when multiple slots are accessed, we can notice which one is accessed. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Artyom Tarasenko Message-Id: <20200510152840.13558-5-f4bug@amsat.org> --- hw/core/empty_slot.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/core/empty_slot.c b/hw/core/empty_slot.c index 0df086fe98..576b276c4b 100644 --- a/hw/core/empty_slot.c +++ b/hw/core/empty_slot.c @@ -31,6 +31,7 @@ typedef struct EmptySlot { SysBusDevice parent_obj; MemoryRegion iomem; + char *name; uint64_t size; } EmptySlot; @@ -72,13 +73,17 @@ static void empty_slot_realize(DeviceState *dev, Error **errp) { EmptySlot *s = EMPTY_SLOT(dev); + if (s->name == NULL) { + s->name = g_strdup("empty-slot"); + } memory_region_init_io(&s->iomem, OBJECT(s), &empty_slot_ops, s, - "empty-slot", s->size); + s->name, s->size); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); } static Property empty_slot_properties[] = { DEFINE_PROP_UINT64("size", EmptySlot, size, 0), + DEFINE_PROP_STRING("name", EmptySlot, name), DEFINE_PROP_END_OF_LIST(), }; From c0e43084dd63daf63e8f7f5a866f2861a5e8d630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 24 Jun 2019 17:23:48 +0200 Subject: [PATCH 0926/2595] hw/misc/empty_slot: Convert debug printf() to trace event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Acked-by: Artyom Tarasenko Message-Id: <20200510152840.13558-6-f4bug@amsat.org> --- hw/core/empty_slot.c | 19 ++++++++----------- hw/core/trace-events | 4 ++++ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/hw/core/empty_slot.c b/hw/core/empty_slot.c index 576b276c4b..d28f7f99c9 100644 --- a/hw/core/empty_slot.c +++ b/hw/core/empty_slot.c @@ -14,15 +14,7 @@ #include "qemu/module.h" #include "hw/qdev-properties.h" #include "hw/empty_slot.h" - -//#define DEBUG_EMPTY_SLOT - -#ifdef DEBUG_EMPTY_SLOT -#define DPRINTF(fmt, ...) \ - do { printf("empty_slot: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif +#include "trace.h" #define TYPE_EMPTY_SLOT "empty_slot" #define EMPTY_SLOT(obj) OBJECT_CHECK(EmptySlot, (obj), TYPE_EMPTY_SLOT) @@ -38,14 +30,19 @@ typedef struct EmptySlot { static uint64_t empty_slot_read(void *opaque, hwaddr addr, unsigned size) { - DPRINTF("read from " TARGET_FMT_plx "\n", addr); + EmptySlot *s = EMPTY_SLOT(opaque); + + trace_empty_slot_write(addr, size << 1, 0, size, s->name); + return 0; } static void empty_slot_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - DPRINTF("write 0x%x to " TARGET_FMT_plx "\n", (unsigned)val, addr); + EmptySlot *s = EMPTY_SLOT(opaque); + + trace_empty_slot_write(addr, size << 1, val, size, s->name); } static const MemoryRegionOps empty_slot_ops = { diff --git a/hw/core/trace-events b/hw/core/trace-events index 1ac60ede6b..bbb68fb6f0 100644 --- a/hw/core/trace-events +++ b/hw/core/trace-events @@ -34,3 +34,7 @@ clock_disconnect(const char *clk) "'%s'" clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', ns=%"PRIu64"->%"PRIu64 clock_propagate(const char *clk) "'%s'" clock_update(const char *clk, const char *src, uint64_t val, int cb) "'%s', src='%s', ns=%"PRIu64", cb=%d" + +# empty_slot.c +empty_slot_read(uint64_t addr, unsigned width, uint64_t value, unsigned size, const char *name) "rd addr:0x%04"PRIx64" data:0x%0*"PRIx64" size %u [%s]" +empty_slot_write(uint64_t addr, unsigned width, uint64_t value, unsigned size, const char *name) "wr addr:0x%04"PRIx64" data:0x%0*"PRIx64" size %u [%s]" From 6007523a80bc5100c22a1caf642a9e8a3ea7bd15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 24 Jun 2019 17:17:32 +0200 Subject: [PATCH 0927/2595] hw/misc/empty_slot: Move the 'hw/misc' and cover in MAINTAINERS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an entry for the 'empty_slot' device. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Artyom Tarasenko Message-Id: <20200510152840.13558-7-f4bug@amsat.org> --- MAINTAINERS | 7 +++++++ hw/core/Makefile.objs | 1 - hw/core/trace-events | 4 ---- hw/mips/malta.c | 2 +- hw/misc/Makefile.objs | 1 + hw/{core => misc}/empty_slot.c | 4 ++-- hw/misc/trace-events | 4 ++++ hw/sparc/sun4m.c | 2 +- include/hw/empty_slot.h | 9 --------- include/hw/misc/empty_slot.h | 19 +++++++++++++++++++ 10 files changed, 35 insertions(+), 18 deletions(-) rename hw/{core => misc}/empty_slot.c (96%) delete mode 100644 include/hw/empty_slot.h create mode 100644 include/hw/misc/empty_slot.h diff --git a/MAINTAINERS b/MAINTAINERS index 6e7890ce82..3abe3faa4e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1864,6 +1864,13 @@ S: Maintained F: include/hw/misc/unimp.h F: hw/misc/unimp.c +Empty slot +M: Artyom Tarasenko +R: Philippe Mathieu-Daudé +S: Maintained +F: include/hw/misc/empty_slot.h +F: hw/misc/empty_slot.c + Standard VGA M: Gerd Hoffmann S: Maintained diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 1d540ed6e7..d8fee8effe 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -24,7 +24,6 @@ common-obj-$(CONFIG_SOFTMMU) += numa.o common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o -common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o common-obj-$(CONFIG_XILINX_AXI) += stream.o common-obj-$(CONFIG_PTIMER) += ptimer.o common-obj-$(CONFIG_FITLOADER) += loader-fit.o diff --git a/hw/core/trace-events b/hw/core/trace-events index bbb68fb6f0..1ac60ede6b 100644 --- a/hw/core/trace-events +++ b/hw/core/trace-events @@ -34,7 +34,3 @@ clock_disconnect(const char *clk) "'%s'" clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', ns=%"PRIu64"->%"PRIu64 clock_propagate(const char *clk) "'%s'" clock_update(const char *clk, const char *src, uint64_t val, int cb) "'%s', src='%s', ns=%"PRIu64", cb=%d" - -# empty_slot.c -empty_slot_read(uint64_t addr, unsigned width, uint64_t value, unsigned size, const char *name) "rd addr:0x%04"PRIx64" data:0x%0*"PRIx64" size %u [%s]" -empty_slot_write(uint64_t addr, unsigned width, uint64_t value, unsigned size, const char *name) "wr addr:0x%04"PRIx64" data:0x%0*"PRIx64" size %u [%s]" diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 636c95d1fe..c973c76b2a 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -52,7 +52,7 @@ #include "sysemu/runstate.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "hw/empty_slot.h" +#include "hw/misc/empty_slot.h" #include "sysemu/kvm.h" #include "hw/semihosting/semihost.h" #include "hw/mips/cps.h" diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 60a9d80b74..5aaca8a039 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -10,6 +10,7 @@ common-obj-$(CONFIG_EDU) += edu.o common-obj-$(CONFIG_PCA9552) += pca9552.o common-obj-$(CONFIG_UNIMP) += unimp.o +common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o common-obj-$(CONFIG_FW_CFG_DMA) += vmcoreinfo.o # ARM devices diff --git a/hw/core/empty_slot.c b/hw/misc/empty_slot.c similarity index 96% rename from hw/core/empty_slot.c rename to hw/misc/empty_slot.c index d28f7f99c9..54be085189 100644 --- a/hw/core/empty_slot.c +++ b/hw/misc/empty_slot.c @@ -11,9 +11,8 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" -#include "qemu/module.h" #include "hw/qdev-properties.h" -#include "hw/empty_slot.h" +#include "hw/misc/empty_slot.h" #include "trace.h" #define TYPE_EMPTY_SLOT "empty_slot" @@ -90,6 +89,7 @@ static void empty_slot_class_init(ObjectClass *klass, void *data) dc->realize = empty_slot_realize; device_class_set_props(dc, empty_slot_properties); + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo empty_slot_info = { diff --git a/hw/misc/trace-events b/hw/misc/trace-events index a5862b2bed..0cb4c64ae7 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -39,6 +39,10 @@ ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 0x%08x" ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = 0x%02x" ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= 0x%02x" +# empty_slot.c +empty_slot_read(uint64_t addr, unsigned width, uint64_t value, unsigned size, const char *name) "rd addr:0x%04"PRIx64" data:0x%0*"PRIx64" size %u [%s]" +empty_slot_write(uint64_t addr, unsigned width, uint64_t value, unsigned size, const char *name) "wr addr:0x%04"PRIx64" data:0x%0*"PRIx64" size %u [%s]" + # slavio_misc.c slavio_misc_update_irq_raise(void) "Raise IRQ" slavio_misc_update_irq_lower(void) "Lower IRQ" diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index fa3dd7775f..a16e667bee 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -46,7 +46,7 @@ #include "hw/nvram/chrp_nvram.h" #include "hw/nvram/fw_cfg.h" #include "hw/char/escc.h" -#include "hw/empty_slot.h" +#include "hw/misc/empty_slot.h" #include "hw/misc/unimp.h" #include "hw/irq.h" #include "hw/loader.h" diff --git a/include/hw/empty_slot.h b/include/hw/empty_slot.h deleted file mode 100644 index cb9a221aa6..0000000000 --- a/include/hw/empty_slot.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef HW_EMPTY_SLOT_H -#define HW_EMPTY_SLOT_H - -#include "exec/hwaddr.h" - -/* empty_slot.c */ -void empty_slot_init(hwaddr addr, uint64_t slot_size); - -#endif diff --git a/include/hw/misc/empty_slot.h b/include/hw/misc/empty_slot.h new file mode 100644 index 0000000000..b023bc2d91 --- /dev/null +++ b/include/hw/misc/empty_slot.h @@ -0,0 +1,19 @@ +/* + * QEMU Empty Slot + * + * The empty_slot device emulates known to a bus but not connected devices. + * + * Copyright (c) 2010 Artyom Tarasenko + * + * This code is licensed under the GNU GPL v2 or (at your option) any later + * version. + */ + +#ifndef HW_EMPTY_SLOT_H +#define HW_EMPTY_SLOT_H + +#include "exec/hwaddr.h" + +void empty_slot_init(hwaddr addr, uint64_t slot_size); + +#endif From 28c78fe818257eb1229448ac672e9f350b37437d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 24 Jun 2019 18:55:47 +0200 Subject: [PATCH 0928/2595] hw/misc/empty_slot: Name the slots when created MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Directly set the slot name when creating the device, to display the device name in trace events. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Artyom Tarasenko Message-Id: <20200510152840.13558-8-f4bug@amsat.org> --- hw/mips/malta.c | 2 +- hw/misc/empty_slot.c | 2 +- hw/sparc/sun4m.c | 10 +++++++--- include/hw/misc/empty_slot.h | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index c973c76b2a..62063b2305 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -1241,7 +1241,7 @@ void mips_malta_init(MachineState *machine) * exception when accessing invalid memory. Create an empty slot to * emulate this feature. */ - empty_slot_init(0, 0x20000000); + empty_slot_init("GT64120", 0, 0x20000000); qdev_init_nofail(dev); diff --git a/hw/misc/empty_slot.c b/hw/misc/empty_slot.c index 54be085189..b568ae202b 100644 --- a/hw/misc/empty_slot.c +++ b/hw/misc/empty_slot.c @@ -50,7 +50,7 @@ static const MemoryRegionOps empty_slot_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -void empty_slot_init(hwaddr addr, uint64_t slot_size) +void empty_slot_init(const char *name, hwaddr addr, uint64_t slot_size) { if (slot_size > 0) { /* Only empty slots larger than 0 byte need handling. */ diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index a16e667bee..249f7ba7ea 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -884,7 +884,8 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, /* models without ECC don't trap when missing ram is accessed */ if (!hwdef->ecc_base) { - empty_slot_init(machine->ram_size, hwdef->max_mem - machine->ram_size); + empty_slot_init("ecc", machine->ram_size, + hwdef->max_mem - machine->ram_size); } prom_init(hwdef->slavio_base, bios_name); @@ -915,7 +916,8 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, Software shouldn't use aliased addresses, neither should it crash when does. Using empty_slot instead of aliasing can help with debugging such accesses */ - empty_slot_init(hwdef->iommu_pad_base,hwdef->iommu_pad_len); + empty_slot_init("iommu.alias", + hwdef->iommu_pad_base, hwdef->iommu_pad_len); } sparc32_dma_init(hwdef->dma_base, @@ -964,7 +966,9 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, for (i = 0; i < MAX_VSIMMS; i++) { /* vsimm registers probed by OBP */ if (hwdef->vsimm[i].reg_base) { - empty_slot_init(hwdef->vsimm[i].reg_base, 0x2000); + char *name = g_strdup_printf("vsimm[%d]", i); + empty_slot_init(name, hwdef->vsimm[i].reg_base, 0x2000); + g_free(name); } } diff --git a/include/hw/misc/empty_slot.h b/include/hw/misc/empty_slot.h index b023bc2d91..dec56e56ae 100644 --- a/include/hw/misc/empty_slot.h +++ b/include/hw/misc/empty_slot.h @@ -14,6 +14,6 @@ #include "exec/hwaddr.h" -void empty_slot_init(hwaddr addr, uint64_t slot_size); +void empty_slot_init(const char *name, hwaddr addr, uint64_t slot_size); #endif From acd2a001e0a1658b90c912f7aaf7beb1e341b1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 1 Dec 2019 21:35:24 +0100 Subject: [PATCH 0929/2595] hw/sparc/leon3: Map the UART device unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The UART is present on the chipset regardless there is a character device connected to it. Map it unconditionally. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Artyom Tarasenko Reviewed-by: KONRAD Frederic Message-Id: <20200608172144.20461-2-f4bug@amsat.org> --- hw/sparc/leon3.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index 8f024dab7b..cc55117dec 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -339,16 +339,14 @@ static void leon3_generic_hw_init(MachineState *machine) 0, LEON3_TIMER_IRQ, GRLIB_APBIO_AREA); /* Allocate uart */ - if (serial_hd(0)) { - dev = qdev_create(NULL, TYPE_GRLIB_APB_UART); - qdev_prop_set_chr(dev, "chrdev", serial_hd(0)); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_UART_OFFSET); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irqs[LEON3_UART_IRQ]); - grlib_apb_pnp_add_entry(apb_pnp, LEON3_UART_OFFSET, 0xFFF, - GRLIB_VENDOR_GAISLER, GRLIB_APBUART_DEV, 1, - LEON3_UART_IRQ, GRLIB_APBIO_AREA); - } + dev = qdev_create(NULL, TYPE_GRLIB_APB_UART); + qdev_prop_set_chr(dev, "chrdev", serial_hd(0)); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_UART_OFFSET); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irqs[LEON3_UART_IRQ]); + grlib_apb_pnp_add_entry(apb_pnp, LEON3_UART_OFFSET, 0xFFF, + GRLIB_VENDOR_GAISLER, GRLIB_APBUART_DEV, 1, + LEON3_UART_IRQ, GRLIB_APBIO_AREA); } static void leon3_generic_machine_init(MachineClass *mc) From bec6e07afde3bffb52f1a9d26a90ccbdfff13690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 1 Dec 2019 21:35:24 +0100 Subject: [PATCH 0930/2595] hw/sparc64/niagara: Map the UART device unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The UART is present on the machine regardless there is a character device connected to it. Map it unconditionally. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Artyom Tarasenko Message-Id: <20200608172144.20461-4-f4bug@amsat.org> --- hw/sparc64/niagara.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c index ab5ef8c5b3..148a26890e 100644 --- a/hw/sparc64/niagara.c +++ b/hw/sparc64/niagara.c @@ -152,10 +152,8 @@ static void niagara_init(MachineState *machine) exit(1); } } - if (serial_hd(0)) { - serial_mm_init(sysmem, NIAGARA_UART_BASE, 0, NULL, 115200, - serial_hd(0), DEVICE_BIG_ENDIAN); - } + serial_mm_init(sysmem, NIAGARA_UART_BASE, 0, NULL, + 115200, serial_hd(0), DEVICE_BIG_ENDIAN); create_unimplemented_device("sun4v-iob", NIAGARA_IOBBASE, NIAGARA_IOBSIZE); sun4v_rtc_init(NIAGARA_RTC_BASE); } From aceeb71306b41ab0ad2eb82d15a2beb6d8ea0e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 8 Jun 2020 19:14:37 +0200 Subject: [PATCH 0931/2595] hw/sparc64/niagara: Remove duplicated NIAGARA_UART_BASE definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NIAGARA_UART_BASE is already defined few lines earlier. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Artyom Tarasenko Message-Id: <20200608172144.20461-3-f4bug@amsat.org> --- hw/sparc64/niagara.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c index 148a26890e..a87d55f6bb 100644 --- a/hw/sparc64/niagara.c +++ b/hw/sparc64/niagara.c @@ -68,7 +68,6 @@ typedef struct NiagaraBoardState { #define NIAGARA_VDISK_BASE 0x1f40000000ULL #define NIAGARA_RTC_BASE 0xfff0c1fff8ULL -#define NIAGARA_UART_BASE 0x1f10000000ULL /* Firmware layout * From bb15013ef34617eb1344f5276292cadd326c21b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 31 Mar 2020 11:56:22 +0200 Subject: [PATCH 0932/2595] hw/misc/grlib_ahb_apb_pnp: Avoid crash when writing to AHB PnP registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similarly to commit 158b659451 with the APB PnP registers, guests can crash QEMU when writting to the AHB PnP registers: $ echo 'writeb 0xfffff042 69' | qemu-system-sparc -M leon3_generic -S -bios /etc/magic -qtest stdio [I 1571938309.932255] OPENED [R +0.063474] writeb 0xfffff042 69 Segmentation fault (core dumped) (gdb) bt #0 0x0000000000000000 in () #1 0x0000562999110df4 in memory_region_write_with_attrs_accessor (mr=mr@entry=0x56299aa28ea0, addr=66, value=value@entry=0x7fff6abe13b8, size=size@entry=1, shift=, mask=mask@entry=255, attrs=...) at memory.c:503 #2 0x000056299911095e in access_with_adjusted_size (addr=addr@entry=66, value=value@entry=0x7fff6abe13b8, size=size@entry=1, access_size_min=, access_size_max=, access_fn=access_fn@entry= 0x562999110d70 , mr=0x56299aa28ea0, attrs=...) at memory.c:539 #3 0x0000562999114fba in memory_region_dispatch_write (mr=mr@entry=0x56299aa28ea0, addr=66, data=, op=, attrs=attrs@entry=...) at memory.c:1482 #4 0x00005629990c0860 in flatview_write_continue (fv=fv@entry=0x56299aa7d8a0, addr=addr@entry=4294963266, attrs=..., ptr=ptr@entry=0x7fff6abe1540, len=len@entry=1, addr1=, l=, mr=0x56299aa28ea0) at include/qemu/host-utils.h:164 #5 0x00005629990c0a76 in flatview_write (fv=0x56299aa7d8a0, addr=4294963266, attrs=..., buf=0x7fff6abe1540, len=1) at exec.c:3165 #6 0x00005629990c4c1b in address_space_write (as=, addr=, attrs=..., attrs@entry=..., buf=buf@entry=0x7fff6abe1540, len=len@entry=1) at exec.c:3256 #7 0x000056299910f807 in qtest_process_command (chr=chr@entry=0x5629995ee920 , words=words@entry=0x56299acfcfa0) at qtest.c:437 Instead of crashing, log the access as unimplemented. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: KONRAD Frederic Message-Id: <20200331105048.27989-3-f4bug@amsat.org> --- hw/misc/grlib_ahb_apb_pnp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/misc/grlib_ahb_apb_pnp.c b/hw/misc/grlib_ahb_apb_pnp.c index e230e25363..72a8764776 100644 --- a/hw/misc/grlib_ahb_apb_pnp.c +++ b/hw/misc/grlib_ahb_apb_pnp.c @@ -136,8 +136,15 @@ static uint64_t grlib_ahb_pnp_read(void *opaque, hwaddr offset, unsigned size) return ahb_pnp->regs[offset >> 2]; } +static void grlib_ahb_pnp_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); +} + static const MemoryRegionOps grlib_ahb_pnp_ops = { .read = grlib_ahb_pnp_read, + .write = grlib_ahb_pnp_write, .endianness = DEVICE_BIG_ENDIAN, }; From 1a5a5570889df9cdd42dd85223e03a5f35025a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 31 Mar 2020 11:59:49 +0200 Subject: [PATCH 0933/2595] hw/misc/grlib_ahb_apb_pnp: Fix AHB PnP 8-bit accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Plug & Play region of the AHB/APB bridge can be accessed by various word size, however the implementation is clearly restricted to 32-bit: static uint64_t grlib_ahb_pnp_read(void *opaque, hwaddr offset, unsigned size) { AHBPnp *ahb_pnp = GRLIB_AHB_PNP(opaque); return ahb_pnp->regs[offset >> 2]; } Similarly to commit 0fbe394a64 with the APB PnP registers, set the MemoryRegionOps::impl min/max fields to 32-bit, so memory.c::access_with_adjusted_size() can adjust when the access is not 32-bit. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: KONRAD Frederic Message-Id: <20200331105048.27989-4-f4bug@amsat.org> --- hw/misc/grlib_ahb_apb_pnp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/misc/grlib_ahb_apb_pnp.c b/hw/misc/grlib_ahb_apb_pnp.c index 72a8764776..d22ed00206 100644 --- a/hw/misc/grlib_ahb_apb_pnp.c +++ b/hw/misc/grlib_ahb_apb_pnp.c @@ -146,6 +146,10 @@ static const MemoryRegionOps grlib_ahb_pnp_ops = { .read = grlib_ahb_pnp_read, .write = grlib_ahb_pnp_write, .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, }; static void grlib_ahb_pnp_realize(DeviceState *dev, Error **errp) From d15188ddcffe0239295f48756bab31e76d88007a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 31 Mar 2020 12:02:47 +0200 Subject: [PATCH 0934/2595] hw/misc/grlib_ahb_apb_pnp: Add trace events on read accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: KONRAD Frederic Message-Id: <20200331105048.27989-5-f4bug@amsat.org> --- hw/misc/grlib_ahb_apb_pnp.c | 13 +++++++++++-- hw/misc/trace-events | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/misc/grlib_ahb_apb_pnp.c b/hw/misc/grlib_ahb_apb_pnp.c index d22ed00206..43e001c3c7 100644 --- a/hw/misc/grlib_ahb_apb_pnp.c +++ b/hw/misc/grlib_ahb_apb_pnp.c @@ -25,6 +25,7 @@ #include "qemu/log.h" #include "hw/sysbus.h" #include "hw/misc/grlib_ahb_apb_pnp.h" +#include "trace.h" #define GRLIB_PNP_VENDOR_SHIFT (24) #define GRLIB_PNP_VENDOR_SIZE (8) @@ -132,8 +133,12 @@ void grlib_ahb_pnp_add_entry(AHBPnp *dev, uint32_t address, uint32_t mask, static uint64_t grlib_ahb_pnp_read(void *opaque, hwaddr offset, unsigned size) { AHBPnp *ahb_pnp = GRLIB_AHB_PNP(opaque); + uint32_t val; - return ahb_pnp->regs[offset >> 2]; + val = ahb_pnp->regs[offset >> 2]; + trace_grlib_ahb_pnp_read(offset, val); + + return val; } static void grlib_ahb_pnp_write(void *opaque, hwaddr addr, @@ -239,8 +244,12 @@ void grlib_apb_pnp_add_entry(APBPnp *dev, uint32_t address, uint32_t mask, static uint64_t grlib_apb_pnp_read(void *opaque, hwaddr offset, unsigned size) { APBPnp *apb_pnp = GRLIB_APB_PNP(opaque); + uint32_t val; - return apb_pnp->regs[offset >> 2]; + val = apb_pnp->regs[offset >> 2]; + trace_grlib_apb_pnp_read(offset, val); + + return val; } static void grlib_apb_pnp_write(void *opaque, hwaddr addr, diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 0cb4c64ae7..5561746866 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -202,3 +202,7 @@ via1_rtc_cmd_pram_read(int addr, int value) "addr=%u value=0x%02x" via1_rtc_cmd_pram_write(int addr, int value) "addr=%u value=0x%02x" via1_rtc_cmd_pram_sect_read(int sector, int offset, int addr, int value) "sector=%u offset=%u addr=%d value=0x%02x" via1_rtc_cmd_pram_sect_write(int sector, int offset, int addr, int value) "sector=%u offset=%u addr=%d value=0x%02x" + +# grlib_ahb_apb_pnp.c +grlib_ahb_pnp_read(uint64_t addr, uint32_t value) "AHB PnP read addr:0x%03"PRIx64" data:0x%08x" +grlib_apb_pnp_read(uint64_t addr, uint32_t value) "APB PnP read addr:0x%03"PRIx64" data:0x%08x" From 8e071cd40143d86e987b3616a63ccf1275750530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 31 Mar 2020 11:38:01 +0200 Subject: [PATCH 0935/2595] hw/timer/grlib_gptimer: Display frequency in decimal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: KONRAD Frederic Message-Id: <20200331105048.27989-6-f4bug@amsat.org> --- hw/timer/trace-events | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/timer/trace-events b/hw/timer/trace-events index 80ea197594..866c9f546a 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -19,7 +19,7 @@ slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address 0x%"PRIx64 grlib_gptimer_enable(int id, uint32_t count) "timer:%d set count 0x%x and run" grlib_gptimer_disabled(int id, uint32_t config) "timer:%d Timer disable config 0x%x" grlib_gptimer_restart(int id, uint32_t reload) "timer:%d reload val: 0x%x" -grlib_gptimer_set_scaler(uint32_t scaler, uint32_t freq) "scaler:0x%x freq: 0x%x" +grlib_gptimer_set_scaler(uint32_t scaler, uint32_t freq) "scaler:0x%x freq:%uHz" grlib_gptimer_hit(int id) "timer:%d HIT" grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x" grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x" From 304c1c8aa5e948ea11aa64acca0e485a185cedc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 31 Mar 2020 11:38:15 +0200 Subject: [PATCH 0936/2595] target/sparc/int32_helper: Remove DEBUG_PCALL definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We define DEBUG_PCALL since b884fc5e (2012-10-06). 7.5 years later it is safe to assume we can remove it :) Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: KONRAD Frederic Message-Id: <20200331105048.27989-7-f4bug@amsat.org> --- target/sparc/int32_helper.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target/sparc/int32_helper.c b/target/sparc/int32_helper.c index 813b47dbb2..c56dd3df18 100644 --- a/target/sparc/int32_helper.c +++ b/target/sparc/int32_helper.c @@ -23,9 +23,7 @@ #include "exec/log.h" #include "sysemu/runstate.h" -#define DEBUG_PCALL -#ifdef DEBUG_PCALL static const char * const excp_names[0x80] = { [TT_TFAULT] = "Instruction Access Fault", [TT_ILL_INSN] = "Illegal Instruction", @@ -58,7 +56,6 @@ static const char * const excp_names[0x80] = { [TT_DIV_ZERO] = "Division By Zero", [TT_NCP_INSN] = "Coprocessor Disabled", }; -#endif void sparc_cpu_do_interrupt(CPUState *cs) { @@ -71,7 +68,6 @@ void sparc_cpu_do_interrupt(CPUState *cs) cpu_get_psr(env); } -#ifdef DEBUG_PCALL if (qemu_loglevel_mask(CPU_LOG_INT)) { static int count; const char *name; @@ -104,7 +100,6 @@ void sparc_cpu_do_interrupt(CPUState *cs) #endif count++; } -#endif #if !defined(CONFIG_USER_ONLY) if (env->psret == 0) { if (cs->exception_index == 0x80 && From 86e8c353f705f14f2f2fd7a6195cefa431aa24d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 31 Mar 2020 11:49:11 +0200 Subject: [PATCH 0937/2595] target/sparc/int32_helper: Extract and use excp_name_str() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve exception error report: Before: qemu: fatal: Trap 0x06 while interrupts disabled, Error state After: qemu: fatal: Trap 0x06 (Window Underflow) while interrupts disabled, Error state Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: KONRAD Frederic Message-Id: <20200331105048.27989-8-f4bug@amsat.org> --- target/sparc/int32_helper.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/target/sparc/int32_helper.c b/target/sparc/int32_helper.c index c56dd3df18..9a71e1abd8 100644 --- a/target/sparc/int32_helper.c +++ b/target/sparc/int32_helper.c @@ -57,6 +57,14 @@ static const char * const excp_names[0x80] = { [TT_NCP_INSN] = "Coprocessor Disabled", }; +static const char *excp_name_str(int32_t exception_index) +{ + if (exception_index < 0 || exception_index >= ARRAY_SIZE(excp_names)) { + return "Unknown"; + } + return excp_names[exception_index]; +} + void sparc_cpu_do_interrupt(CPUState *cs) { SPARCCPU *cpu = SPARC_CPU(cs); @@ -77,10 +85,7 @@ void sparc_cpu_do_interrupt(CPUState *cs) } else if (intno >= 0x80) { name = "Trap Instruction"; } else { - name = excp_names[intno]; - if (!name) { - name = "Unknown"; - } + name = excp_name_str(intno); } qemu_log("%6d: %s (v=%02x)\n", count, name, intno); @@ -106,8 +111,9 @@ void sparc_cpu_do_interrupt(CPUState *cs) env->def.features & CPU_FEATURE_TA0_SHUTDOWN) { qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); } else { - cpu_abort(cs, "Trap 0x%02x while interrupts disabled, Error state", - cs->exception_index); + cpu_abort(cs, "Trap 0x%02x (%s) while interrupts disabled, " + "Error state", + cs->exception_index, excp_name_str(cs->exception_index)); } return; } From 191f90cbea08122b48107f1f9116106fbf3bdfac Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 14 May 2020 11:14:39 -0400 Subject: [PATCH 0938/2595] msix: allow qword MSI-X table accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCI spec says: For all accesses to MSI-X Table and MSI-X PBA fields, software must use aligned full DWORD or aligned full QWORD transactions; otherwise, the result is undefined. However, since MSI-X was converted to use memory API, QEMU started blocking qword transactions, only allowing DWORD ones. Guests do not seem to use QWORD accesses, but let's be spec compliant. Fixes: 95524ae8dc8f ("msix: convert to memory API") Signed-off-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé --- hw/pci/msix.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/pci/msix.c b/hw/pci/msix.c index 29187898f2..e6a5559038 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -199,6 +199,9 @@ static const MemoryRegionOps msix_table_mmio_ops = { .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { .max_access_size = 4, }, }; @@ -227,6 +230,9 @@ static const MemoryRegionOps msix_pba_mmio_ops = { .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { .max_access_size = 4, }, }; From acc5c98ddd8f85d41fd22e57cf289aeaa34f160a Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Fri, 5 Jun 2020 18:09:09 -0600 Subject: [PATCH 0939/2595] diffs-allowed: add the SRAT AML to diffs-allowed In anticipation of a change to the SRAT generation in qemu, add the AML file to diffs-allowed. Signed-off-by: Vishal Verma Message-Id: <20200606000911.9896-2-vishal.l.verma@intel.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..e8f2766a63 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,4 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/SRAT.dimmpxm", +"tests/data/acpi/q35/SRAT.dimmpxm", +"tests/data/acpi/virt/SRAT.memhp", From c3b0cf6e7dbc48ecf84ace4224f220fa9baa85b6 Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Fri, 5 Jun 2020 18:09:10 -0600 Subject: [PATCH 0940/2595] hw/acpi/nvdimm: add a helper to augment SRAT generation NVDIMMs can belong to their own proximity domains, as described by the NFIT. In such cases, the SRAT needs to have Memory Affinity structures in the SRAT for these NVDIMMs, otherwise Linux doesn't populate node data structures properly during NUMA initialization. See the following for an example failure case. https://lore.kernel.org/linux-nvdimm/20200416225438.15208-1-vishal.l.verma@intel.com/ Introduce a new helper, nvdimm_build_srat(), and call it for both the i386 and arm versions of 'build_srat()' to augment the SRAT with memory affinity information for NVDIMMs. The relevant command line options to exercise this are below. Nodes 0-1 contain CPUs and regular memory, and nodes 2-3 are the NVDIMM address space. -object memory-backend-ram,id=mem0,size=2048M -numa node,nodeid=0,memdev=mem0, -numa cpu,node-id=0,socket-id=0 -object memory-backend-ram,id=mem1,size=2048M -numa node,nodeid=1,memdev=mem1, -numa cpu,node-id=1,socket-id=1 -numa node,nodeid=2, -object memory-backend-file,id=nvmem0,share,mem-path=nvdimm-0,size=16384M,align=1G -device nvdimm,memdev=nvmem0,id=nv0,label-size=2M,node=2 -numa node,nodeid=3, -object memory-backend-file,id=nvmem1,share,mem-path=nvdimm-1,size=16384M,align=1G -device nvdimm,memdev=nvmem1,id=nv1,label-size=2M,node=3 Cc: Jingqi Liu Cc: Michael S. Tsirkin Reviewed-by: Jingqi Liu Reviewed-by: Igor Mammedov Signed-off-by: Vishal Verma Message-Id: <20200606000911.9896-3-vishal.l.verma@intel.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/nvdimm.c | 23 +++++++++++++++++++++++ hw/arm/virt-acpi-build.c | 4 ++++ hw/i386/acpi-build.c | 5 +++++ include/hw/mem/nvdimm.h | 1 + 4 files changed, 33 insertions(+) diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index 9316d12b70..8f7cc16add 100644 --- a/hw/acpi/nvdimm.c +++ b/hw/acpi/nvdimm.c @@ -28,6 +28,7 @@ #include "qemu/osdep.h" #include "qemu/uuid.h" +#include "qapi/error.h" #include "hw/acpi/acpi.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/bios-linker-loader.h" @@ -1334,6 +1335,28 @@ static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data, free_aml_allocator(); } +void nvdimm_build_srat(GArray *table_data) +{ + GSList *device_list = nvdimm_get_device_list(); + + for (; device_list; device_list = device_list->next) { + AcpiSratMemoryAffinity *numamem = NULL; + DeviceState *dev = device_list->data; + Object *obj = OBJECT(dev); + uint64_t addr, size; + int node; + + node = object_property_get_int(obj, PC_DIMM_NODE_PROP, &error_abort); + addr = object_property_get_uint(obj, PC_DIMM_ADDR_PROP, &error_abort); + size = object_property_get_uint(obj, PC_DIMM_SIZE_PROP, &error_abort); + + numamem = acpi_data_push(table_data, sizeof *numamem); + build_srat_memory(numamem, addr, size, node, + MEM_AFFINITY_ENABLED | MEM_AFFINITY_NON_VOLATILE); + } + g_slist_free(device_list); +} + void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data, BIOSLinker *linker, NVDIMMState *state, uint32_t ram_slots) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 1b0a584c7b..2cbccd5fe2 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -539,6 +539,10 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) } } + if (ms->nvdimms_state->is_enabled) { + nvdimm_build_srat(table_data); + } + if (ms->device_memory) { numamem = acpi_data_push(table_data, sizeof *numamem); build_srat_memory(numamem, ms->device_memory->base, diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 2e15f6848e..d996525e2c 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2428,6 +2428,11 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) MEM_AFFINITY_ENABLED); } } + + if (machine->nvdimms_state->is_enabled) { + nvdimm_build_srat(table_data); + } + slots = (table_data->len - numa_start) / sizeof *numamem; for (; slots < pcms->numa_nodes + 2; slots++) { numamem = acpi_data_push(table_data, sizeof *numamem); diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h index a3c08955e8..b67a1aedf6 100644 --- a/include/hw/mem/nvdimm.h +++ b/include/hw/mem/nvdimm.h @@ -155,6 +155,7 @@ typedef struct NVDIMMState NVDIMMState; void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io, struct AcpiGenericAddress dsm_io, FWCfgState *fw_cfg, Object *owner); +void nvdimm_build_srat(GArray *table_data); void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data, BIOSLinker *linker, NVDIMMState *state, uint32_t ram_slots); From cdcb6395dca7a67c26a2277d93df3a82e9a4d1fa Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Tue, 2 Jun 2020 10:52:14 +0200 Subject: [PATCH 0941/2595] mailmap: Change email address of Filip Bozuta Filip Bozuta wants to use his new email address for his future work in QEMU. CC: Filip Bozuta Signed-off-by: Aleksandar Markovic Reviewed-by: Filip Bozuta Message-Id: <20200602085215.12585-2-aleksandar.qemu.devel@gmail.com> --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index e3628c7a66..9f2a3a55f9 100644 --- a/.mailmap +++ b/.mailmap @@ -45,6 +45,7 @@ Aleksandar Markovic Aleksandar Rikalo Aleksandar Rikalo Anthony Liguori Anthony Liguori +Filip Bozuta James Hogan Leif Lindholm Paul Burton From f364a8d026fb35af97cb4775ffe02de2fd64764b Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Tue, 2 Jun 2020 10:52:15 +0200 Subject: [PATCH 0942/2595] mailmap: Change email address of Stefan Brankovic Stefan Brankovic wants to use his new email address for his future work in QEMU. CC: Stefan Brankovic Signed-off-by: Aleksandar Markovic Reviewed-by: Stefan Brankovic Message-Id: <20200602085215.12585-3-aleksandar.qemu.devel@gmail.com> --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 9f2a3a55f9..84f36592ba 100644 --- a/.mailmap +++ b/.mailmap @@ -52,6 +52,7 @@ Paul Burton Paul Burton Paul Burton Philippe Mathieu-Daudé +Stefan Brankovic Yongbok Kim # Also list preferred name forms where people have changed their From 1ace099f2acb952eaaef0ba7725879949a7e4406 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:00 +0200 Subject: [PATCH 0943/2595] target/mips: fpu: Demacro ADD. This is just a cosmetic change to enable tools like gcov, gdb, callgrind, etc. to better display involved source code. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-2-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index 5287c86c61..984f3f4dfb 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1208,12 +1208,48 @@ uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ return ((uint64_t)wth2 << 32) | wt2; \ } -FLOAT_BINOP(add) FLOAT_BINOP(sub) FLOAT_BINOP(mul) FLOAT_BINOP(div) #undef FLOAT_BINOP +uint64_t helper_float_add_d(CPUMIPSState *env, + uint64_t fdt0, uint64_t fdt1) +{ + uint64_t dt2; + + dt2 = float64_add(fdt0, fdt1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return dt2; +} + +uint32_t helper_float_add_s(CPUMIPSState *env, + uint32_t fst0, uint32_t fst1) +{ + uint32_t wt2; + + wt2 = float32_sub(fst0, fst1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return wt2; +} + +uint64_t helper_float_add_ps(CPUMIPSState *env, + uint64_t fdt0, uint64_t fdt1) +{ + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fstl1 = fdt1 & 0XFFFFFFFF; + uint32_t fsth1 = fdt1 >> 32; + uint32_t wtl2; + uint32_t wth2; + + wtl2 = float32_add(fstl0, fstl1, &env->active_fpu.fp_status); + wth2 = float32_add(fsth0, fsth1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return ((uint64_t)wth2 << 32) | wtl2; +} + + /* MIPS specific binary operations */ uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) { From 92ebdd7fa4f48e09f0da3973fe3136131cfee94f Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:01 +0200 Subject: [PATCH 0944/2595] target/mips: fpu: Demacro SUB. This is just a cosmetic change to enable tools like gcov, gdb, callgrind, etc. to better display involved source code. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-3-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index 984f3f4dfb..715a872cae 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1208,7 +1208,6 @@ uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ return ((uint64_t)wth2 << 32) | wt2; \ } -FLOAT_BINOP(sub) FLOAT_BINOP(mul) FLOAT_BINOP(div) #undef FLOAT_BINOP @@ -1249,6 +1248,42 @@ uint64_t helper_float_add_ps(CPUMIPSState *env, return ((uint64_t)wth2 << 32) | wtl2; } +uint64_t helper_float_sub_d(CPUMIPSState *env, + uint64_t fdt0, uint64_t fdt1) +{ + uint64_t dt2; + + dt2 = float64_sub(fdt0, fdt1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return dt2; +} + +uint32_t helper_float_sub_s(CPUMIPSState *env, + uint32_t fst0, uint32_t fst1) +{ + uint32_t wt2; + + wt2 = float32_sub(fst0, fst1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return wt2; +} + +uint64_t helper_float_sub_ps(CPUMIPSState *env, + uint64_t fdt0, uint64_t fdt1) +{ + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fstl1 = fdt1 & 0XFFFFFFFF; + uint32_t fsth1 = fdt1 >> 32; + uint32_t wtl2; + uint32_t wth2; + + wtl2 = float32_sub(fstl0, fstl1, &env->active_fpu.fp_status); + wth2 = float32_sub(fsth0, fsth1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return ((uint64_t)wth2 << 32) | wtl2; +} + /* MIPS specific binary operations */ uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) From 11811198efdcf423e787272b13751fd899fdfb03 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:02 +0200 Subject: [PATCH 0945/2595] target/mips: fpu: Demacro MUL. This is just a cosmetic change to enable tools like gcov, gdb, callgrind, etc. to better display involved source code. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-4-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index 715a872cae..449e945166 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1208,7 +1208,6 @@ uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ return ((uint64_t)wth2 << 32) | wt2; \ } -FLOAT_BINOP(mul) FLOAT_BINOP(div) #undef FLOAT_BINOP @@ -1284,6 +1283,42 @@ uint64_t helper_float_sub_ps(CPUMIPSState *env, return ((uint64_t)wth2 << 32) | wtl2; } +uint64_t helper_float_mul_d(CPUMIPSState *env, + uint64_t fdt0, uint64_t fdt1) +{ + uint64_t dt2; + + dt2 = float64_mul(fdt0, fdt1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return dt2; +} + +uint32_t helper_float_mul_s(CPUMIPSState *env, + uint32_t fst0, uint32_t fst1) +{ + uint32_t wt2; + + wt2 = float32_mul(fst0, fst1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return wt2; +} + +uint64_t helper_float_mul_ps(CPUMIPSState *env, + uint64_t fdt0, uint64_t fdt1) +{ + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fstl1 = fdt1 & 0XFFFFFFFF; + uint32_t fsth1 = fdt1 >> 32; + uint32_t wtl2; + uint32_t wth2; + + wtl2 = float32_mul(fstl0, fstl1, &env->active_fpu.fp_status); + wth2 = float32_mul(fsth0, fsth1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return ((uint64_t)wth2 << 32) | wtl2; +} + /* MIPS specific binary operations */ uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) From bcca8c4b1a044e8ef4ad2c88cbde217e1a38baeb Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:03 +0200 Subject: [PATCH 0946/2595] target/mips: fpu: Demacro DIV. This is just a cosmetic change to enable tools like gcov, gdb, callgrind, etc. to better display involved source code. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-5-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index 449e945166..2759c9989d 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1208,7 +1208,6 @@ uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ return ((uint64_t)wth2 << 32) | wt2; \ } -FLOAT_BINOP(div) #undef FLOAT_BINOP uint64_t helper_float_add_d(CPUMIPSState *env, @@ -1319,6 +1318,42 @@ uint64_t helper_float_mul_ps(CPUMIPSState *env, return ((uint64_t)wth2 << 32) | wtl2; } +uint64_t helper_float_div_d(CPUMIPSState *env, + uint64_t fdt0, uint64_t fdt1) +{ + uint64_t dt2; + + dt2 = float64_div(fdt0, fdt1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return dt2; +} + +uint32_t helper_float_div_s(CPUMIPSState *env, + uint32_t fst0, uint32_t fst1) +{ + uint32_t wt2; + + wt2 = float32_div(fst0, fst1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return wt2; +} + +uint64_t helper_float_div_ps(CPUMIPSState *env, + uint64_t fdt0, uint64_t fdt1) +{ + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fstl1 = fdt1 & 0XFFFFFFFF; + uint32_t fsth1 = fdt1 >> 32; + uint32_t wtl2; + uint32_t wth2; + + wtl2 = float32_div(fstl0, fstl1, &env->active_fpu.fp_status); + wth2 = float32_div(fsth0, fsth1, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return ((uint64_t)wth2 << 32) | wtl2; +} + /* MIPS specific binary operations */ uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) From 8248c9c5b2983464945fc0fa077e0c51c4d3f97c Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:04 +0200 Subject: [PATCH 0947/2595] target/mips: fpu: Remove now unused macro FLOAT_BINOP After demacroing ., this macro is not needed anymore. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-6-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index 2759c9989d..a3a39681f8 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1170,45 +1170,6 @@ FLOAT_CLASS(class_d, 64) #undef FLOAT_CLASS /* binary operations */ -#define FLOAT_BINOP(name) \ -uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \ - uint64_t fdt0, uint64_t fdt1) \ -{ \ - uint64_t dt2; \ - \ - dt2 = float64_ ## name(fdt0, fdt1, &env->active_fpu.fp_status);\ - update_fcr31(env, GETPC()); \ - return dt2; \ -} \ - \ -uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \ - uint32_t fst0, uint32_t fst1) \ -{ \ - uint32_t wt2; \ - \ - wt2 = float32_ ## name(fst0, fst1, &env->active_fpu.fp_status);\ - update_fcr31(env, GETPC()); \ - return wt2; \ -} \ - \ -uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ - uint64_t fdt0, \ - uint64_t fdt1) \ -{ \ - uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ - uint32_t fsth0 = fdt0 >> 32; \ - uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ - uint32_t fsth1 = fdt1 >> 32; \ - uint32_t wt2; \ - uint32_t wth2; \ - \ - wt2 = float32_ ## name(fst0, fst1, &env->active_fpu.fp_status); \ - wth2 = float32_ ## name(fsth0, fsth1, &env->active_fpu.fp_status); \ - update_fcr31(env, GETPC()); \ - return ((uint64_t)wth2 << 32) | wt2; \ -} - -#undef FLOAT_BINOP uint64_t helper_float_add_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1) From 16734cc1da678e906c6d472dbbba8ac80bdf2f06 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:05 +0200 Subject: [PATCH 0948/2595] target/mips: fpu: Demacro MADD. This is just a cosmetic change to enable tools like gcov, gdb, callgrind, etc. to better display involved source code. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-7-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 41 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index a3a39681f8..c070081cbc 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1495,12 +1495,51 @@ uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ update_fcr31(env, GETPC()); \ return ((uint64_t)fsth0 << 32) | fst0; \ } -FLOAT_FMA(madd, 0) FLOAT_FMA(msub, float_muladd_negate_c) FLOAT_FMA(nmadd, float_muladd_negate_result) FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c) #undef FLOAT_FMA +uint64_t helper_float_madd_d(CPUMIPSState *env, uint64_t fst0, + uint64_t fst1, uint64_t fst2) +{ + fst0 = float64_mul(fst0, fst1, &env->active_fpu.fp_status); + fst0 = float64_add(fst0, fst2, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fst0; +} + +uint32_t helper_float_madd_s(CPUMIPSState *env, uint32_t fst0, + uint32_t fst1, uint32_t fst2) +{ + fst0 = float32_mul(fst0, fst1, &env->active_fpu.fp_status); + fst0 = float32_add(fst0, fst2, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fst0; +} + +uint64_t helper_float_madd_ps(CPUMIPSState *env, uint64_t fdt0, + uint64_t fdt1, uint64_t fdt2) +{ + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fstl1 = fdt1 & 0XFFFFFFFF; + uint32_t fsth1 = fdt1 >> 32; + uint32_t fstl2 = fdt2 & 0XFFFFFFFF; + uint32_t fsth2 = fdt2 >> 32; + + fstl0 = float32_mul(fstl0, fstl1, &env->active_fpu.fp_status); + fstl0 = float32_add(fstl0, fstl2, &env->active_fpu.fp_status); + fsth0 = float32_mul(fsth0, fsth1, &env->active_fpu.fp_status); + fsth0 = float32_add(fsth0, fsth2, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return ((uint64_t)fsth0 << 32) | fstl0; +} + + #define FLOAT_FMADDSUB(name, bits, muladd_arg) \ uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \ uint ## bits ## _t fs, \ From faec75244c6878d62d1474b9462b552a829d7f3d Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:06 +0200 Subject: [PATCH 0949/2595] target/mips: fpu: Demacro MSUB. This is just a cosmetic change to enable tools like gcov, gdb, callgrind, etc. to better display involved source code. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-8-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index c070081cbc..e37fc4075d 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1495,7 +1495,6 @@ uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ update_fcr31(env, GETPC()); \ return ((uint64_t)fsth0 << 32) | fst0; \ } -FLOAT_FMA(msub, float_muladd_negate_c) FLOAT_FMA(nmadd, float_muladd_negate_result) FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c) #undef FLOAT_FMA @@ -1539,6 +1538,45 @@ uint64_t helper_float_madd_ps(CPUMIPSState *env, uint64_t fdt0, return ((uint64_t)fsth0 << 32) | fstl0; } +uint64_t helper_float_msub_d(CPUMIPSState *env, uint64_t fst0, + uint64_t fst1, uint64_t fst2) +{ + fst0 = float64_mul(fst0, fst1, &env->active_fpu.fp_status); + fst0 = float64_sub(fst0, fst2, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fst0; +} + +uint32_t helper_float_msub_s(CPUMIPSState *env, uint32_t fst0, + uint32_t fst1, uint32_t fst2) +{ + fst0 = float32_mul(fst0, fst1, &env->active_fpu.fp_status); + fst0 = float32_sub(fst0, fst2, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fst0; +} + +uint64_t helper_float_msub_ps(CPUMIPSState *env, uint64_t fdt0, + uint64_t fdt1, uint64_t fdt2) +{ + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fstl1 = fdt1 & 0XFFFFFFFF; + uint32_t fsth1 = fdt1 >> 32; + uint32_t fstl2 = fdt2 & 0XFFFFFFFF; + uint32_t fsth2 = fdt2 >> 32; + + fstl0 = float32_mul(fstl0, fstl1, &env->active_fpu.fp_status); + fstl0 = float32_sub(fstl0, fstl2, &env->active_fpu.fp_status); + fsth0 = float32_mul(fsth0, fsth1, &env->active_fpu.fp_status); + fsth0 = float32_sub(fsth0, fsth2, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return ((uint64_t)fsth0 << 32) | fstl0; +} + #define FLOAT_FMADDSUB(name, bits, muladd_arg) \ uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \ From 0278586d603dec01bbd8eddc48c1c063db070cf1 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:07 +0200 Subject: [PATCH 0950/2595] target/mips: fpu: Demacro NMADD. This is just a cosmetic change to enable tools like gcov, gdb, callgrind, etc. to better display involved source code. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-9-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 44 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index e37fc4075d..d4c065f281 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1495,7 +1495,6 @@ uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ update_fcr31(env, GETPC()); \ return ((uint64_t)fsth0 << 32) | fst0; \ } -FLOAT_FMA(nmadd, float_muladd_negate_result) FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c) #undef FLOAT_FMA @@ -1577,6 +1576,49 @@ uint64_t helper_float_msub_ps(CPUMIPSState *env, uint64_t fdt0, return ((uint64_t)fsth0 << 32) | fstl0; } +uint64_t helper_float_nmadd_d(CPUMIPSState *env, uint64_t fst0, + uint64_t fst1, uint64_t fst2) +{ + fst0 = float64_mul(fst0, fst1, &env->active_fpu.fp_status); + fst0 = float64_add(fst0, fst2, &env->active_fpu.fp_status); + fst0 = float64_chs(fst0); + + update_fcr31(env, GETPC()); + return fst0; +} + +uint32_t helper_float_nmadd_s(CPUMIPSState *env, uint32_t fst0, + uint32_t fst1, uint32_t fst2) +{ + fst0 = float32_mul(fst0, fst1, &env->active_fpu.fp_status); + fst0 = float32_add(fst0, fst2, &env->active_fpu.fp_status); + fst0 = float32_chs(fst0); + + update_fcr31(env, GETPC()); + return fst0; +} + +uint64_t helper_float_nmadd_ps(CPUMIPSState *env, uint64_t fdt0, + uint64_t fdt1, uint64_t fdt2) +{ + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fstl1 = fdt1 & 0XFFFFFFFF; + uint32_t fsth1 = fdt1 >> 32; + uint32_t fstl2 = fdt2 & 0XFFFFFFFF; + uint32_t fsth2 = fdt2 >> 32; + + fstl0 = float32_mul(fstl0, fstl1, &env->active_fpu.fp_status); + fstl0 = float32_add(fstl0, fstl2, &env->active_fpu.fp_status); + fstl0 = float32_chs(fstl0); + fsth0 = float32_mul(fsth0, fsth1, &env->active_fpu.fp_status); + fsth0 = float32_add(fsth0, fsth2, &env->active_fpu.fp_status); + fsth0 = float32_chs(fsth0); + + update_fcr31(env, GETPC()); + return ((uint64_t)fsth0 << 32) | fstl0; +} + #define FLOAT_FMADDSUB(name, bits, muladd_arg) \ uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \ From 5c591e22592c2751a2e48c3b22f2c8df264fe789 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:08 +0200 Subject: [PATCH 0951/2595] target/mips: fpu: Demacro NMSUB. This is just a cosmetic change to enable tools like gcov, gdb, callgrind, etc. to better display involved source code. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-10-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 44 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index d4c065f281..927bac24ac 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1495,7 +1495,6 @@ uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ update_fcr31(env, GETPC()); \ return ((uint64_t)fsth0 << 32) | fst0; \ } -FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c) #undef FLOAT_FMA uint64_t helper_float_madd_d(CPUMIPSState *env, uint64_t fst0, @@ -1619,6 +1618,49 @@ uint64_t helper_float_nmadd_ps(CPUMIPSState *env, uint64_t fdt0, return ((uint64_t)fsth0 << 32) | fstl0; } +uint64_t helper_float_nmsub_d(CPUMIPSState *env, uint64_t fst0, + uint64_t fst1, uint64_t fst2) +{ + fst0 = float64_mul(fst0, fst1, &env->active_fpu.fp_status); + fst0 = float64_sub(fst0, fst2, &env->active_fpu.fp_status); + fst0 = float64_chs(fst0); + + update_fcr31(env, GETPC()); + return fst0; +} + +uint32_t helper_float_nmsub_s(CPUMIPSState *env, uint32_t fst0, + uint32_t fst1, uint32_t fst2) +{ + fst0 = float32_mul(fst0, fst1, &env->active_fpu.fp_status); + fst0 = float32_sub(fst0, fst2, &env->active_fpu.fp_status); + fst0 = float32_chs(fst0); + + update_fcr31(env, GETPC()); + return fst0; +} + +uint64_t helper_float_nmsub_ps(CPUMIPSState *env, uint64_t fdt0, + uint64_t fdt1, uint64_t fdt2) +{ + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; + uint32_t fstl1 = fdt1 & 0XFFFFFFFF; + uint32_t fsth1 = fdt1 >> 32; + uint32_t fstl2 = fdt2 & 0XFFFFFFFF; + uint32_t fsth2 = fdt2 >> 32; + + fstl0 = float32_mul(fstl0, fstl1, &env->active_fpu.fp_status); + fstl0 = float32_sub(fstl0, fstl2, &env->active_fpu.fp_status); + fstl0 = float32_chs(fstl0); + fsth0 = float32_mul(fsth0, fsth1, &env->active_fpu.fp_status); + fsth0 = float32_sub(fsth0, fsth2, &env->active_fpu.fp_status); + fsth0 = float32_chs(fsth0); + + update_fcr31(env, GETPC()); + return ((uint64_t)fsth0 << 32) | fstl0; +} + #define FLOAT_FMADDSUB(name, bits, muladd_arg) \ uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \ From 32574f1d1ce2879971e747ab7917b5d28e56d90c Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:09 +0200 Subject: [PATCH 0952/2595] target/mips: fpu: Remove now unused UNFUSED_FMA and FLOAT_FMA macros After demacroing ., these macros are not needed anymore. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-11-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 50 ---------------------------------------- 1 file changed, 50 deletions(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index 927bac24ac..e8e50e4bc0 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1446,56 +1446,6 @@ FLOAT_MINMAX(mina_d, 64, minnummag) #undef FLOAT_MINMAX /* ternary operations */ -#define UNFUSED_FMA(prefix, a, b, c, flags) \ -{ \ - a = prefix##_mul(a, b, &env->active_fpu.fp_status); \ - if ((flags) & float_muladd_negate_c) { \ - a = prefix##_sub(a, c, &env->active_fpu.fp_status); \ - } else { \ - a = prefix##_add(a, c, &env->active_fpu.fp_status); \ - } \ - if ((flags) & float_muladd_negate_result) { \ - a = prefix##_chs(a); \ - } \ -} - -/* FMA based operations */ -#define FLOAT_FMA(name, type) \ -uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \ - uint64_t fdt0, uint64_t fdt1, \ - uint64_t fdt2) \ -{ \ - UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \ - update_fcr31(env, GETPC()); \ - return fdt0; \ -} \ - \ -uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \ - uint32_t fst0, uint32_t fst1, \ - uint32_t fst2) \ -{ \ - UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ - update_fcr31(env, GETPC()); \ - return fst0; \ -} \ - \ -uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ - uint64_t fdt0, uint64_t fdt1, \ - uint64_t fdt2) \ -{ \ - uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ - uint32_t fsth0 = fdt0 >> 32; \ - uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ - uint32_t fsth1 = fdt1 >> 32; \ - uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ - uint32_t fsth2 = fdt2 >> 32; \ - \ - UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ - UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \ - update_fcr31(env, GETPC()); \ - return ((uint64_t)fsth0 << 32) | fst0; \ -} -#undef FLOAT_FMA uint64_t helper_float_madd_d(CPUMIPSState *env, uint64_t fst0, uint64_t fst1, uint64_t fst2) From 0bd99ac77cb6717ae7bc51c033c4833efcc7b315 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:10 +0200 Subject: [PATCH 0953/2595] target/mips: fpu: Demacro CLASS. This is just a cosmetic change to enable tools like gcov, gdb, callgrind, etc. to better display involved source code. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-12-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 70 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index e8e50e4bc0..b3903f5357 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1165,10 +1165,76 @@ uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \ return float_ ## name(arg, &env->active_fpu.fp_status); \ } -FLOAT_CLASS(class_s, 32) -FLOAT_CLASS(class_d, 64) #undef FLOAT_CLASS +uint64_t float_class_d(uint64_t arg, float_status *status) +{ + if (float64_is_signaling_nan(arg, status)) { + return FLOAT_CLASS_SIGNALING_NAN; + } else if (float64_is_quiet_nan(arg, status)) { + return FLOAT_CLASS_QUIET_NAN; + } else if (float64_is_neg(arg)) { + if (float64_is_infinity(arg)) { + return FLOAT_CLASS_NEGATIVE_INFINITY; + } else if (float64_is_zero(arg)) { + return FLOAT_CLASS_NEGATIVE_ZERO; + } else if (float64_is_zero_or_denormal(arg)) { + return FLOAT_CLASS_NEGATIVE_SUBNORMAL; + } else { + return FLOAT_CLASS_NEGATIVE_NORMAL; + } + } else { + if (float64_is_infinity(arg)) { + return FLOAT_CLASS_POSITIVE_INFINITY; + } else if (float64_is_zero(arg)) { + return FLOAT_CLASS_POSITIVE_ZERO; + } else if (float64_is_zero_or_denormal(arg)) { + return FLOAT_CLASS_POSITIVE_SUBNORMAL; + } else { + return FLOAT_CLASS_POSITIVE_NORMAL; + } + } +} + +uint64_t helper_float_class_d(CPUMIPSState *env, uint64_t arg) +{ + return float_class_d(arg, &env->active_fpu.fp_status); +} + +uint32_t float_class_s(uint32_t arg, float_status *status) +{ + if (float32_is_signaling_nan(arg, status)) { + return FLOAT_CLASS_SIGNALING_NAN; + } else if (float32_is_quiet_nan(arg, status)) { + return FLOAT_CLASS_QUIET_NAN; + } else if (float32_is_neg(arg)) { + if (float32_is_infinity(arg)) { + return FLOAT_CLASS_NEGATIVE_INFINITY; + } else if (float32_is_zero(arg)) { + return FLOAT_CLASS_NEGATIVE_ZERO; + } else if (float32_is_zero_or_denormal(arg)) { + return FLOAT_CLASS_NEGATIVE_SUBNORMAL; + } else { + return FLOAT_CLASS_NEGATIVE_NORMAL; + } + } else { + if (float32_is_infinity(arg)) { + return FLOAT_CLASS_POSITIVE_INFINITY; + } else if (float32_is_zero(arg)) { + return FLOAT_CLASS_POSITIVE_ZERO; + } else if (float32_is_zero_or_denormal(arg)) { + return FLOAT_CLASS_POSITIVE_SUBNORMAL; + } else { + return FLOAT_CLASS_POSITIVE_NORMAL; + } + } +} + +uint32_t helper_float_class_s(CPUMIPSState *env, uint32_t arg) +{ + return float_class_s(arg, &env->active_fpu.fp_status); +} + /* binary operations */ uint64_t helper_float_add_d(CPUMIPSState *env, From 6971a1b970cb9663cc067a61f0db3e95400f3e38 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:11 +0200 Subject: [PATCH 0954/2595] target/mips: fpu: Remove now unused FLOAT_CLASS macro After demacroing CLASS., this macro is not needed anymore. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-13-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index b3903f5357..e227e53f70 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1128,45 +1128,6 @@ FLOAT_RINT(rint_d, 64) #define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100 #define FLOAT_CLASS_POSITIVE_ZERO 0x200 -#define FLOAT_CLASS(name, bits) \ -uint ## bits ## _t float_ ## name(uint ## bits ## _t arg, \ - float_status *status) \ -{ \ - if (float ## bits ## _is_signaling_nan(arg, status)) { \ - return FLOAT_CLASS_SIGNALING_NAN; \ - } else if (float ## bits ## _is_quiet_nan(arg, status)) { \ - return FLOAT_CLASS_QUIET_NAN; \ - } else if (float ## bits ## _is_neg(arg)) { \ - if (float ## bits ## _is_infinity(arg)) { \ - return FLOAT_CLASS_NEGATIVE_INFINITY; \ - } else if (float ## bits ## _is_zero(arg)) { \ - return FLOAT_CLASS_NEGATIVE_ZERO; \ - } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ - return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \ - } else { \ - return FLOAT_CLASS_NEGATIVE_NORMAL; \ - } \ - } else { \ - if (float ## bits ## _is_infinity(arg)) { \ - return FLOAT_CLASS_POSITIVE_INFINITY; \ - } else if (float ## bits ## _is_zero(arg)) { \ - return FLOAT_CLASS_POSITIVE_ZERO; \ - } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ - return FLOAT_CLASS_POSITIVE_SUBNORMAL; \ - } else { \ - return FLOAT_CLASS_POSITIVE_NORMAL; \ - } \ - } \ -} \ - \ -uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \ - uint ## bits ## _t arg) \ -{ \ - return float_ ## name(arg, &env->active_fpu.fp_status); \ -} - -#undef FLOAT_CLASS - uint64_t float_class_d(uint64_t arg, float_status *status) { if (float64_is_signaling_nan(arg, status)) { From 728e424690c64787722bbfb3cc5d9a4088a58d8b Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:12 +0200 Subject: [PATCH 0955/2595] target/mips: fpu: Demacro RINT. This is just a cosmetic change to enable tools like gcov, gdb, callgrind, etc. to better display involved source code. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-14-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index e227e53f70..dae1331f23 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1113,10 +1113,26 @@ uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \ return fdret; \ } -FLOAT_RINT(rint_s, 32) -FLOAT_RINT(rint_d, 64) #undef FLOAT_RINT +uint64_t helper_float_rint_d(CPUMIPSState *env, uint64_t fs) +{ + uint64_t fdret; + + fdret = float64_round_to_int(fs, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return fdret; +} + +uint32_t helper_float_rint_s(CPUMIPSState *env, uint32_t fs) +{ + uint32_t fdret; + + fdret = float32_round_to_int(fs, &env->active_fpu.fp_status); + update_fcr31(env, GETPC()); + return fdret; +} + #define FLOAT_CLASS_SIGNALING_NAN 0x001 #define FLOAT_CLASS_QUIET_NAN 0x002 #define FLOAT_CLASS_NEGATIVE_INFINITY 0x004 From bdbe48db40d058d5a82097fe4f29fd0168ecce9e Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:13 +0200 Subject: [PATCH 0956/2595] target/mips: fpu: Remove now unused FLOAT_RINT macro After demacroing RINT., this macro is not needed anymore. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-15-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index dae1331f23..56ba49104e 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1102,19 +1102,6 @@ uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0) return ((uint64_t)fsth2 << 32) | fst2; } -#define FLOAT_RINT(name, bits) \ -uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \ - uint ## bits ## _t fs) \ -{ \ - uint ## bits ## _t fdret; \ - \ - fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \ - update_fcr31(env, GETPC()); \ - return fdret; \ -} - -#undef FLOAT_RINT - uint64_t helper_float_rint_d(CPUMIPSState *env, uint64_t fs) { uint64_t fdret; From 485cd2e4ce35f24428bd1783ad31325acc67b350 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:14 +0200 Subject: [PATCH 0957/2595] target/mips: fpu: Name better paired-single variables Use consistently 'l' and 'h' for low and high halves. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-16-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 62 ++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index 56ba49104e..dbb8ca5692 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -1059,14 +1059,14 @@ uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0) uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0) { - uint32_t fst2; + uint32_t fstl2; uint32_t fsth2; - fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, - &env->active_fpu.fp_status); + fstl2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, + &env->active_fpu.fp_status); fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status); update_fcr31(env, GETPC()); - return ((uint64_t)fsth2 << 32) | fst2; + return ((uint64_t)fsth2 << 32) | fstl2; } uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0) @@ -1091,15 +1091,15 @@ uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0) uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0) { - uint32_t fst2; + uint32_t fstl2; uint32_t fsth2; - fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); + fstl2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status); - fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status); + fstl2 = float32_div(float32_one, fstl2, &env->active_fpu.fp_status); fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status); update_fcr31(env, GETPC()); - return ((uint64_t)fsth2 << 32) | fst2; + return ((uint64_t)fsth2 << 32) | fstl2; } uint64_t helper_float_rint_d(CPUMIPSState *env, uint64_t fs) @@ -1367,19 +1367,19 @@ uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2) uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) { - uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; uint32_t fsth0 = fdt0 >> 32; - uint32_t fst2 = fdt2 & 0XFFFFFFFF; + uint32_t fstl2 = fdt2 & 0XFFFFFFFF; uint32_t fsth2 = fdt2 >> 32; - fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); + fstl2 = float32_mul(fstl0, fstl2, &env->active_fpu.fp_status); fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status); - fst2 = float32_chs(float32_sub(fst2, float32_one, + fstl2 = float32_chs(float32_sub(fstl2, float32_one, &env->active_fpu.fp_status)); fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status)); update_fcr31(env, GETPC()); - return ((uint64_t)fsth2 << 32) | fst2; + return ((uint64_t)fsth2 << 32) | fstl2; } uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) @@ -1404,51 +1404,51 @@ uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2) uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) { - uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; uint32_t fsth0 = fdt0 >> 32; - uint32_t fst2 = fdt2 & 0XFFFFFFFF; + uint32_t fstl2 = fdt2 & 0XFFFFFFFF; uint32_t fsth2 = fdt2 >> 32; - fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); + fstl2 = float32_mul(fstl0, fstl2, &env->active_fpu.fp_status); fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status); - fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status); + fstl2 = float32_sub(fstl2, float32_one, &env->active_fpu.fp_status); fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status); - fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, + fstl2 = float32_chs(float32_div(fstl2, FLOAT_TWO32, &env->active_fpu.fp_status)); fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status)); update_fcr31(env, GETPC()); - return ((uint64_t)fsth2 << 32) | fst2; + return ((uint64_t)fsth2 << 32) | fstl2; } uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1) { - uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; uint32_t fsth0 = fdt0 >> 32; - uint32_t fst1 = fdt1 & 0XFFFFFFFF; + uint32_t fstl1 = fdt1 & 0XFFFFFFFF; uint32_t fsth1 = fdt1 >> 32; - uint32_t fst2; + uint32_t fstl2; uint32_t fsth2; - fst2 = float32_add(fst0, fsth0, &env->active_fpu.fp_status); - fsth2 = float32_add(fst1, fsth1, &env->active_fpu.fp_status); + fstl2 = float32_add(fstl0, fsth0, &env->active_fpu.fp_status); + fsth2 = float32_add(fstl1, fsth1, &env->active_fpu.fp_status); update_fcr31(env, GETPC()); - return ((uint64_t)fsth2 << 32) | fst2; + return ((uint64_t)fsth2 << 32) | fstl2; } uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1) { - uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fstl0 = fdt0 & 0XFFFFFFFF; uint32_t fsth0 = fdt0 >> 32; - uint32_t fst1 = fdt1 & 0XFFFFFFFF; + uint32_t fstl1 = fdt1 & 0XFFFFFFFF; uint32_t fsth1 = fdt1 >> 32; - uint32_t fst2; + uint32_t fstl2; uint32_t fsth2; - fst2 = float32_mul(fst0, fsth0, &env->active_fpu.fp_status); - fsth2 = float32_mul(fst1, fsth1, &env->active_fpu.fp_status); + fstl2 = float32_mul(fstl0, fsth0, &env->active_fpu.fp_status); + fsth2 = float32_mul(fstl1, fsth1, &env->active_fpu.fp_status); update_fcr31(env, GETPC()); - return ((uint64_t)fsth2 << 32) | fst2; + return ((uint64_t)fsth2 << 32) | fstl2; } #define FLOAT_MINMAX(name, bits, minmaxfunc) \ From 9579f7816855757c747f9428a8e53d0fe0a0e9b7 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 18 May 2020 22:09:15 +0200 Subject: [PATCH 0958/2595] target/mips: fpu: Refactor conversion from ieee to mips exception flags The original coversion function is used for regular and MSA floating point instructions handling. Since there are some nuanced differences between regular and MSA floating point exception handling, provide two instances of the conversion function, rather than just a single common one. Inline both instances of this function instances for the sake of performance. Improve variable naming in surrounding code for clarity. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200518200920.17344-17-aleksandar.qemu.devel@gmail.com> --- target/mips/fpu_helper.c | 55 +++++++++++++++------------- target/mips/internal.h | 1 - target/mips/msa_helper.c | 77 +++++++++++++++++++++++++++------------- 3 files changed, 82 insertions(+), 51 deletions(-) diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index dbb8ca5692..7a3a61cab3 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -189,43 +189,48 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) } } -int ieee_ex_to_mips(int xcpt) +static inline int ieee_to_mips_xcpt(int ieee_xcpt) { - int ret = 0; - if (xcpt) { - if (xcpt & float_flag_invalid) { - ret |= FP_INVALID; - } - if (xcpt & float_flag_overflow) { - ret |= FP_OVERFLOW; - } - if (xcpt & float_flag_underflow) { - ret |= FP_UNDERFLOW; - } - if (xcpt & float_flag_divbyzero) { - ret |= FP_DIV0; - } - if (xcpt & float_flag_inexact) { - ret |= FP_INEXACT; - } + int mips_xcpt = 0; + + if (ieee_xcpt & float_flag_invalid) { + mips_xcpt |= FP_INVALID; } - return ret; + if (ieee_xcpt & float_flag_overflow) { + mips_xcpt |= FP_OVERFLOW; + } + if (ieee_xcpt & float_flag_underflow) { + mips_xcpt |= FP_UNDERFLOW; + } + if (ieee_xcpt & float_flag_divbyzero) { + mips_xcpt |= FP_DIV0; + } + if (ieee_xcpt & float_flag_inexact) { + mips_xcpt |= FP_INEXACT; + } + + return mips_xcpt; } static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc) { - int tmp = ieee_ex_to_mips(get_float_exception_flags( - &env->active_fpu.fp_status)); + int ieee_exception_flags = get_float_exception_flags( + &env->active_fpu.fp_status); + int mips_exception_flags = 0; - SET_FP_CAUSE(env->active_fpu.fcr31, tmp); + if (ieee_exception_flags) { + mips_exception_flags = ieee_to_mips_xcpt(ieee_exception_flags); + } - if (tmp) { + SET_FP_CAUSE(env->active_fpu.fcr31, mips_exception_flags); + + if (mips_exception_flags) { set_float_exception_flags(0, &env->active_fpu.fp_status); - if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) { + if (GET_FP_ENABLE(env->active_fpu.fcr31) & mips_exception_flags) { do_raise_exception(env, EXCP_FPE, pc); } else { - UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp); + UPDATE_FP_FLAGS(env->active_fpu.fcr31, mips_exception_flags); } } } diff --git a/target/mips/internal.h b/target/mips/internal.h index 1bf274b3ef..684356e309 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -224,7 +224,6 @@ uint32_t float_class_s(uint32_t arg, float_status *fst); uint64_t float_class_d(uint64_t arg, float_status *fst); extern unsigned int ieee_rm[]; -int ieee_ex_to_mips(int xcpt); void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask); static inline void restore_rounding_mode(CPUMIPSState *env) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 3c7012c0b8..c3b271934a 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -5419,54 +5419,81 @@ static inline void check_msacsr_cause(CPUMIPSState *env, uintptr_t retaddr) #define CLEAR_IS_INEXACT 2 #define RECIPROCAL_INEXACT 4 + +static inline int ieee_to_mips_xcpt_msa(int ieee_xcpt) +{ + int mips_xcpt = 0; + + if (ieee_xcpt & float_flag_invalid) { + mips_xcpt |= FP_INVALID; + } + if (ieee_xcpt & float_flag_overflow) { + mips_xcpt |= FP_OVERFLOW; + } + if (ieee_xcpt & float_flag_underflow) { + mips_xcpt |= FP_UNDERFLOW; + } + if (ieee_xcpt & float_flag_divbyzero) { + mips_xcpt |= FP_DIV0; + } + if (ieee_xcpt & float_flag_inexact) { + mips_xcpt |= FP_INEXACT; + } + + return mips_xcpt; +} + static inline int update_msacsr(CPUMIPSState *env, int action, int denormal) { - int ieee_ex; - - int c; + int ieee_exception_flags; + int mips_exception_flags = 0; int cause; int enable; - ieee_ex = get_float_exception_flags(&env->active_tc.msa_fp_status); + ieee_exception_flags = get_float_exception_flags( + &env->active_tc.msa_fp_status); /* QEMU softfloat does not signal all underflow cases */ if (denormal) { - ieee_ex |= float_flag_underflow; + ieee_exception_flags |= float_flag_underflow; + } + if (ieee_exception_flags) { + mips_exception_flags = ieee_to_mips_xcpt_msa(ieee_exception_flags); } - - c = ieee_ex_to_mips(ieee_ex); enable = GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED; /* Set Inexact (I) when flushing inputs to zero */ - if ((ieee_ex & float_flag_input_denormal) && + if ((ieee_exception_flags & float_flag_input_denormal) && (env->active_tc.msacsr & MSACSR_FS_MASK) != 0) { if (action & CLEAR_IS_INEXACT) { - c &= ~FP_INEXACT; + mips_exception_flags &= ~FP_INEXACT; } else { - c |= FP_INEXACT; + mips_exception_flags |= FP_INEXACT; } } /* Set Inexact (I) and Underflow (U) when flushing outputs to zero */ - if ((ieee_ex & float_flag_output_denormal) && + if ((ieee_exception_flags & float_flag_output_denormal) && (env->active_tc.msacsr & MSACSR_FS_MASK) != 0) { - c |= FP_INEXACT; + mips_exception_flags |= FP_INEXACT; if (action & CLEAR_FS_UNDERFLOW) { - c &= ~FP_UNDERFLOW; + mips_exception_flags &= ~FP_UNDERFLOW; } else { - c |= FP_UNDERFLOW; + mips_exception_flags |= FP_UNDERFLOW; } } /* Set Inexact (I) when Overflow (O) is not enabled */ - if ((c & FP_OVERFLOW) != 0 && (enable & FP_OVERFLOW) == 0) { - c |= FP_INEXACT; + if ((mips_exception_flags & FP_OVERFLOW) != 0 && + (enable & FP_OVERFLOW) == 0) { + mips_exception_flags |= FP_INEXACT; } /* Clear Exact Underflow when Underflow (U) is not enabled */ - if ((c & FP_UNDERFLOW) != 0 && (enable & FP_UNDERFLOW) == 0 && - (c & FP_INEXACT) == 0) { - c &= ~FP_UNDERFLOW; + if ((mips_exception_flags & FP_UNDERFLOW) != 0 && + (enable & FP_UNDERFLOW) == 0 && + (mips_exception_flags & FP_INEXACT) == 0) { + mips_exception_flags &= ~FP_UNDERFLOW; } /* @@ -5474,11 +5501,11 @@ static inline int update_msacsr(CPUMIPSState *env, int action, int denormal) * divide by zero */ if ((action & RECIPROCAL_INEXACT) && - (c & (FP_INVALID | FP_DIV0)) == 0) { - c = FP_INEXACT; + (mips_exception_flags & (FP_INVALID | FP_DIV0)) == 0) { + mips_exception_flags = FP_INEXACT; } - cause = c & enable; /* all current enabled exceptions */ + cause = mips_exception_flags & enable; /* all current enabled exceptions */ if (cause == 0) { /* @@ -5486,7 +5513,7 @@ static inline int update_msacsr(CPUMIPSState *env, int action, int denormal) * with all current exceptions */ SET_FP_CAUSE(env->active_tc.msacsr, - (GET_FP_CAUSE(env->active_tc.msacsr) | c)); + (GET_FP_CAUSE(env->active_tc.msacsr) | mips_exception_flags)); } else { /* Current exceptions are enabled */ if ((env->active_tc.msacsr & MSACSR_NX_MASK) == 0) { @@ -5495,11 +5522,11 @@ static inline int update_msacsr(CPUMIPSState *env, int action, int denormal) * with all enabled exceptions */ SET_FP_CAUSE(env->active_tc.msacsr, - (GET_FP_CAUSE(env->active_tc.msacsr) | c)); + (GET_FP_CAUSE(env->active_tc.msacsr) | mips_exception_flags)); } } - return c; + return mips_exception_flags; } static inline int get_enabled_exceptions(const CPUMIPSState *env, int c) From af868995e1b7641577300d1342ede452ef0c5565 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Tue, 2 Jun 2020 10:39:15 +0800 Subject: [PATCH 0959/2595] target/mips: Add Loongson-3 CPU definition Loongson-3 CPU family include Loongson-3A R1/R2/R3/R4 and Loongson-3B R1/R2. Loongson-3A R1 is the oldest and its ISA is the smallest, while Loongson-3A R4 is the newest and its ISA is almost the superset of all others. To reduce complexity, we just define two CPU types: 1) "Loongson-3A1000" CPU which is corresponding to Loongson-3A R1. It is suitable for TCG because Loongson-3A R1 has fewest ASE. 2) "Loongson-3A4000" CPU which is corresponding to Loongson-3A R4. It is suitable for KVM because Loongson-3A R4 has the VZ ASE. Loongson-3A has CONFIG6 and CONFIG7, so add their bit-fields as well. [AM: Rearranged insn_flags, added comments, renamed lmi_helper.c, improved commit message, fixed checkpatch warnings] Signed-off-by: Huacai Chen Co-developed-by: Jiaxun Yang Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: <1591065557-9174-3-git-send-email-chenhc@lemote.com> --- target/mips/Makefile.objs | 2 +- target/mips/cpu.h | 32 +++++++- target/mips/internal.h | 2 + target/mips/{lmi_helper.c => lmmi_helper.c} | 0 target/mips/mips-defs.h | 45 ++++++----- target/mips/translate.c | 2 + target/mips/translate_init.inc.c | 86 +++++++++++++++++++++ 7 files changed, 146 insertions(+), 23 deletions(-) rename target/mips/{lmi_helper.c => lmmi_helper.c} (100%) diff --git a/target/mips/Makefile.objs b/target/mips/Makefile.objs index 91eb691833..b820b3b7bc 100644 --- a/target/mips/Makefile.objs +++ b/target/mips/Makefile.objs @@ -1,6 +1,6 @@ obj-y += translate.o cpu.o gdbstub.o helper.o obj-y += op_helper.o cp0_helper.o fpu_helper.o -obj-y += dsp_helper.o lmi_helper.o msa_helper.o +obj-y += dsp_helper.o lmmi_helper.o msa_helper.o obj-$(CONFIG_SOFTMMU) += mips-semi.o obj-$(CONFIG_SOFTMMU) += machine.o cp0_timer.o obj-$(CONFIG_KVM) += kvm.o diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 94d01ea798..7cf7f5239f 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -198,8 +198,8 @@ typedef struct mips_def_t mips_def_t; * 3 Config3 WatchLo3 WatchHi * 4 Config4 WatchLo4 WatchHi * 5 Config5 WatchLo5 WatchHi - * 6 WatchLo6 WatchHi - * 7 WatchLo7 WatchHi + * 6 Config6 WatchLo6 WatchHi + * 7 Config7 WatchLo7 WatchHi * * * Register 20 Register 21 Register 22 Register 23 @@ -940,7 +940,35 @@ struct CPUMIPSState { #define CP0C5_UFR 2 #define CP0C5_NFExists 0 int32_t CP0_Config6; + int32_t CP0_Config6_rw_bitmask; +#define CP0C6_BPPASS 31 +#define CP0C6_KPOS 24 +#define CP0C6_KE 23 +#define CP0C6_VTLBONLY 22 +#define CP0C6_LASX 21 +#define CP0C6_SSEN 20 +#define CP0C6_DISDRTIME 19 +#define CP0C6_PIXNUEN 18 +#define CP0C6_SCRAND 17 +#define CP0C6_LLEXCEN 16 +#define CP0C6_DISVC 15 +#define CP0C6_VCLRU 14 +#define CP0C6_DCLRU 13 +#define CP0C6_PIXUEN 12 +#define CP0C6_DISBLKLYEN 11 +#define CP0C6_UMEMUALEN 10 +#define CP0C6_SFBEN 8 +#define CP0C6_FLTINT 7 +#define CP0C6_VLTINT 6 +#define CP0C6_DISBTB 5 +#define CP0C6_STPREFCTL 2 +#define CP0C6_INSTPREF 1 +#define CP0C6_DATAPREF 0 int32_t CP0_Config7; + int64_t CP0_Config7_rw_bitmask; +#define CP0C7_NAPCGEN 2 +#define CP0C7_UNIMUEN 1 +#define CP0C7_VFPUCGEN 0 uint64_t CP0_LLAddr; uint64_t CP0_MAAR[MIPS_MAAR_MAX]; int32_t CP0_MAARI; diff --git a/target/mips/internal.h b/target/mips/internal.h index 684356e309..7f159a9230 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -36,7 +36,9 @@ struct mips_def_t { int32_t CP0_Config5; int32_t CP0_Config5_rw_bitmask; int32_t CP0_Config6; + int32_t CP0_Config6_rw_bitmask; int32_t CP0_Config7; + int32_t CP0_Config7_rw_bitmask; target_ulong CP0_LLAddr_rw_bitmask; int CP0_LLAddr_shift; int32_t SYNCI_Step; diff --git a/target/mips/lmi_helper.c b/target/mips/lmmi_helper.c similarity index 100% rename from target/mips/lmi_helper.c rename to target/mips/lmmi_helper.c diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h index a831bb4384..0c129106c8 100644 --- a/target/mips/mips-defs.h +++ b/target/mips/mips-defs.h @@ -15,7 +15,7 @@ * ------------------------------------------------ */ /* - * bits 0-31: MIPS base instruction sets + * bits 0-23: MIPS base instruction sets */ #define ISA_MIPS1 0x0000000000000001ULL #define ISA_MIPS2 0x0000000000000002ULL @@ -34,30 +34,33 @@ #define ISA_MIPS64R6 0x0000000000004000ULL #define ISA_NANOMIPS32 0x0000000000008000ULL /* - * bits 32-47: MIPS ASEs + * bits 24-39: MIPS ASEs */ -#define ASE_MIPS16 0x0000000100000000ULL -#define ASE_MIPS3D 0x0000000200000000ULL -#define ASE_MDMX 0x0000000400000000ULL -#define ASE_DSP 0x0000000800000000ULL -#define ASE_DSP_R2 0x0000001000000000ULL -#define ASE_DSP_R3 0x0000002000000000ULL -#define ASE_MT 0x0000004000000000ULL -#define ASE_SMARTMIPS 0x0000008000000000ULL -#define ASE_MICROMIPS 0x0000010000000000ULL -#define ASE_MSA 0x0000020000000000ULL +#define ASE_MIPS16 0x0000000001000000ULL +#define ASE_MIPS3D 0x0000000002000000ULL +#define ASE_MDMX 0x0000000004000000ULL +#define ASE_DSP 0x0000000008000000ULL +#define ASE_DSP_R2 0x0000000010000000ULL +#define ASE_DSP_R3 0x0000000020000000ULL +#define ASE_MT 0x0000000040000000ULL +#define ASE_SMARTMIPS 0x0000000080000000ULL +#define ASE_MICROMIPS 0x0000000100000000ULL +#define ASE_MSA 0x0000000200000000ULL /* - * bits 48-55: vendor-specific base instruction sets + * bits 40-51: vendor-specific base instruction sets */ -#define INSN_LOONGSON2E 0x0001000000000000ULL -#define INSN_LOONGSON2F 0x0002000000000000ULL -#define INSN_VR54XX 0x0004000000000000ULL -#define INSN_R5900 0x0008000000000000ULL +#define INSN_VR54XX 0x0000010000000000ULL +#define INSN_R5900 0x0000020000000000ULL +#define INSN_LOONGSON2E 0x0000040000000000ULL +#define INSN_LOONGSON2F 0x0000080000000000ULL +#define INSN_LOONGSON3A 0x0000100000000000ULL /* - * bits 56-63: vendor-specific ASEs + * bits 52-63: vendor-specific ASEs */ -#define ASE_MMI 0x0100000000000000ULL -#define ASE_MXU 0x0200000000000000ULL +#define ASE_MMI 0x0010000000000000ULL +#define ASE_MXU 0x0020000000000000ULL +#define ASE_LMMI 0x0040000000000000ULL +#define ASE_LEXT 0x0080000000000000ULL /* MIPS CPU defines. */ #define CPU_MIPS1 (ISA_MIPS1) @@ -94,6 +97,8 @@ /* Wave Computing: "nanoMIPS" */ #define CPU_NANOMIPS32 (CPU_MIPS32R6 | ISA_NANOMIPS32) +#define CPU_LOONGSON3A (CPU_MIPS64R2 | INSN_LOONGSON3A) + /* * Strictly follow the architecture standard: * - Disallow "special" instruction handling for PMON/SPIM. diff --git a/target/mips/translate.c b/target/mips/translate.c index 25b595a17d..2caf4cba5a 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -31206,7 +31206,9 @@ void cpu_state_reset(CPUMIPSState *env) env->CP0_Config5 = env->cpu_model->CP0_Config5; env->CP0_Config5_rw_bitmask = env->cpu_model->CP0_Config5_rw_bitmask; env->CP0_Config6 = env->cpu_model->CP0_Config6; + env->CP0_Config6_rw_bitmask = env->cpu_model->CP0_Config6_rw_bitmask; env->CP0_Config7 = env->cpu_model->CP0_Config7; + env->CP0_Config7_rw_bitmask = env->cpu_model->CP0_Config7_rw_bitmask; env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask << env->cpu_model->CP0_LLAddr_shift; env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift; diff --git a/target/mips/translate_init.inc.c b/target/mips/translate_init.inc.c index 6d145a905a..ffae10d4c4 100644 --- a/target/mips/translate_init.inc.c +++ b/target/mips/translate_init.inc.c @@ -801,6 +801,92 @@ const mips_def_t mips_defs[] = .insn_flags = CPU_LOONGSON2F, .mmu_type = MMU_TYPE_R4000, }, + { + .name = "Loongson-3A1000", + .CP0_PRid = 0x6305, + /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */ + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) | + (3 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) | + (3 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2 | (7 << CP0C2_SS) | (4 << CP0C2_SL) | + (3 << CP0C2_SA), + .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA), + .CP0_LLAddr_rw_bitmask = 0, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x74D8FFFF, + .CP0_PageGrain = (1 << CP0PG_ELPA), + .CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA), + .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV) | (0x1 << FCR0_F64) | + (0x1 << FCR0_PS) | (0x1 << FCR0_L) | (0x1 << FCR0_W) | + (0x1 << FCR0_D) | (0x1 << FCR0_S), + .CP1_fcr31 = 0, + .CP1_fcr31_rw_bitmask = 0xFF83FFFF, + .SEGBITS = 42, + .PABITS = 48, + .insn_flags = CPU_LOONGSON3A, + .mmu_type = MMU_TYPE_R4000, + }, + { + .name = "Loongson-3A4000", + .CP0_PRid = 0x14C000, + /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */ + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) | + (2 << CP0C1_IS) | (5 << CP0C1_IL) | (3 << CP0C1_IA) | + (2 << CP0C1_DS) | (5 << CP0C1_DL) | (3 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2 | (5 << CP0C2_SS) | (5 << CP0C2_SL) | + (15 << CP0C2_SA), + .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP) | + (1 << CP0C3_BP) | (1 << CP0C3_BI) | (1 << CP0C3_ULRI) | + (1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt), + .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (2 << CP0C4_IE) | + (1 << CP0C4_AE) | (0x1c << CP0C4_KScrExist), + .CP0_Config4_rw_bitmask = 0, + .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_CRCP) | (1 << CP0C5_NFExists), + .CP0_Config5_rw_bitmask = (1 << CP0C5_K) | (1 << CP0C5_CV) | + (1 << CP0C5_MSAEn) | (1 << CP0C5_UFE) | + (1 << CP0C5_FRE) | (1 << CP0C5_SBRI), + .CP0_Config6 = (1 << CP0C6_VCLRU) | (1 << CP0C6_DCLRU) | + (1 << CP0C6_SFBEN) | (1 << CP0C6_VLTINT) | + (1 << CP0C6_INSTPREF) | (1 << CP0C6_DATAPREF), + .CP0_Config6_rw_bitmask = (1 << CP0C6_BPPASS) | (0x3f << CP0C6_KPOS) | + (1 << CP0C6_KE) | (1 << CP0C6_VTLBONLY) | + (1 << CP0C6_LASX) | (1 << CP0C6_SSEN) | + (1 << CP0C6_DISDRTIME) | (1 << CP0C6_PIXNUEN) | + (1 << CP0C6_SCRAND) | (1 << CP0C6_LLEXCEN) | + (1 << CP0C6_DISVC) | (1 << CP0C6_VCLRU) | + (1 << CP0C6_DCLRU) | (1 << CP0C6_PIXUEN) | + (1 << CP0C6_DISBLKLYEN) | (1 << CP0C6_UMEMUALEN) | + (1 << CP0C6_SFBEN) | (1 << CP0C6_FLTINT) | + (1 << CP0C6_VLTINT) | (1 << CP0C6_DISBTB) | + (3 << CP0C6_STPREFCTL) | (1 << CP0C6_INSTPREF) | + (1 << CP0C6_DATAPREF), + .CP0_Config7 = 0, + .CP0_Config7_rw_bitmask = (1 << CP0C7_NAPCGEN) | (1 << CP0C7_UNIMUEN) | + (1 << CP0C7_VFPUCGEN), + .CP0_LLAddr_rw_bitmask = 1, + .SYNCI_Step = 16, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x7DDBFFFF, + .CP0_PageGrain = (1 << CP0PG_ELPA), + .CP0_PageGrain_rw_bitmask = (1U << CP0PG_RIE) | (1 << CP0PG_XIE) | + (1 << CP0PG_ELPA) | (1 << CP0PG_IEC), + .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV) | (0x1 << FCR0_F64) | + (0x1 << FCR0_PS) | (0x1 << FCR0_L) | (0x1 << FCR0_W) | + (0x1 << FCR0_D) | (0x1 << FCR0_S), + .CP1_fcr31 = 0, + .CP1_fcr31_rw_bitmask = 0xFF83FFFF, + .SEGBITS = 48, + .PABITS = 48, + .insn_flags = CPU_LOONGSON3A, + .mmu_type = MMU_TYPE_R4000, + }, { /* A generic CPU providing MIPS64 DSP R2 ASE features. FIXME: Eventually this should be replaced by a real CPU model. */ From 6db06115d246ea6d24755657a98c185ed2a50210 Mon Sep 17 00:00:00 2001 From: Andrea Oliveri Date: Sat, 25 Apr 2020 20:20:04 +0200 Subject: [PATCH 0960/2595] target/mips: Enable hardware page table walker and CMGCR features for P5600 Enable hardware page table walker and CMGCR features for P5600 that supports both. Signed-off-by: Andrea Oliveri Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: --- target/mips/translate_init.inc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target/mips/translate_init.inc.c b/target/mips/translate_init.inc.c index ffae10d4c4..637caccd89 100644 --- a/target/mips/translate_init.inc.c +++ b/target/mips/translate_init.inc.c @@ -366,7 +366,7 @@ const mips_def_t mips_defs[] = }, { /* FIXME: - * Config3: CMGCR, PW, VZ, CTXTC, CDMM, TL + * Config3: VZ, CTXTC, CDMM, TL * Config4: MMUExtDef * Config5: MRP * FIR(FCR0): Has2008 @@ -380,10 +380,11 @@ const mips_def_t mips_defs[] = (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) | (1 << CP0C1_PC) | (1 << CP0C1_FP), .CP0_Config2 = MIPS_CONFIG2, - .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP) | + .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | + (1 << CP0C3_CMGCR) | (1 << CP0C3_MSAP) | (1 << CP0C3_BP) | (1 << CP0C3_BI) | (1 << CP0C3_SC) | - (1 << CP0C3_ULRI) | (1 << CP0C3_RXI) | (1 << CP0C3_LPA) | - (1 << CP0C3_VInt), + (1 << CP0C3_PW) | (1 << CP0C3_ULRI) | (1 << CP0C3_RXI) | + (1 << CP0C3_LPA) | (1 << CP0C3_VInt), .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (2 << CP0C4_IE) | (0x1c << CP0C4_KScrExist), .CP0_Config4_rw_bitmask = 0, From fe079aa13d6f77f9d7323b58ab24448e73ae6a93 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 8 Jun 2020 10:41:49 -0700 Subject: [PATCH 0961/2595] decodetree: Drop check for less than 2 patterns in a group While it makes little sense for the end product to have a group containing only a single pattern, avoiding this case within an incremental patch set is troublesome. Because this is expected to be a transient condition, do not bother "optimizing" this case, e.g. by folding away the group. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- scripts/decodetree.py | 2 -- tests/decode/succ_pattern_group_nest4.decode | 13 +++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/decode/succ_pattern_group_nest4.decode diff --git a/scripts/decodetree.py b/scripts/decodetree.py index 7e3b1d1399..530d41ca62 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -1024,8 +1024,6 @@ def parse_file(f, parent_pat): if name == '}' or name == ']': if len(toks) != 0: error(start_lineno, 'extra tokens after close brace') - if len(parent_pat.pats) < 2: - error(lineno, 'less than two patterns within braces') # Make sure { } and [ ] nest properly. if (name == '}') != isinstance(parent_pat, IncMultiPattern): diff --git a/tests/decode/succ_pattern_group_nest4.decode b/tests/decode/succ_pattern_group_nest4.decode new file mode 100644 index 0000000000..dc54a1d285 --- /dev/null +++ b/tests/decode/succ_pattern_group_nest4.decode @@ -0,0 +1,13 @@ +# This work is licensed under the terms of the GNU LGPL, version 2 or later. +# See the COPYING.LIB file in the top-level directory. + +# Verify deeper nesting, and a single element in the groups. +{ + [ + { + [ + sub1 00000000 a:8 b:8 c:8 + ] + } + ] +} From d6084fba47bb9aef79775c1102d4b647eb58c365 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 18 May 2020 09:25:10 -0700 Subject: [PATCH 0962/2595] target/arm: Use a non-overlapping group for misc control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The miscellaneous control instructions are mutually exclusive within the t32 decode sub-group. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/arm/t32.decode | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/t32.decode b/target/arm/t32.decode index c63082fc9c..c21a988f97 100644 --- a/target/arm/t32.decode +++ b/target/arm/t32.decode @@ -312,13 +312,13 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm &cps # Miscellaneous control - { + [ CLREX 1111 0011 1011 1111 1000 1111 0010 1111 DSB 1111 0011 1011 1111 1000 1111 0100 ---- DMB 1111 0011 1011 1111 1000 1111 0101 ---- ISB 1111 0011 1011 1111 1000 1111 0110 ---- SB 1111 0011 1011 1111 1000 1111 0111 0000 - } + ] # Note that the v7m insn overlaps both the normal and banked insn. { From 705f7f2fce25e774e19f6853cd92ebaf909958f3 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 7 May 2020 17:37:58 -0400 Subject: [PATCH 0963/2595] Fix parameter type in vhost migration log path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ‘enable’ parameter to the vhost_migration_log() function is given as an int, but "true"/"false" values are passed in wherever it is invoked. Inside the function itself it is only ever compared with bool values. Therefore the parameter value itself should be changed to bool. Signed-off-by: Raphael Norwitz Reviewed-by: Eric Blake Message-Id: Signed-off-by: Laurent Vivier --- hw/virtio/vhost.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index aff98a0ede..aa06a36919 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -809,12 +809,12 @@ err_features: return r; } -static int vhost_migration_log(MemoryListener *listener, int enable) +static int vhost_migration_log(MemoryListener *listener, bool enable) { struct vhost_dev *dev = container_of(listener, struct vhost_dev, memory_listener); int r; - if (!!enable == dev->log_enabled) { + if (enable == dev->log_enabled) { return 0; } if (!dev->started) { From 8a49b30034da8c5440f425a94e7fb12425f35283 Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Fri, 5 Jun 2020 18:09:11 -0600 Subject: [PATCH 0964/2595] tests/acpi: update expected SRAT files Update expected SRAT files for the change to account for NVDIMM NUMA nodes in the SRAT. AML diffs: tests/data/acpi/pc/SRAT.dimmpxm: Message-Id: <20200606000911.9896-4-vishal.l.verma@intel.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/pc/SRAT.dimmpxm | Bin 392 -> 392 bytes tests/data/acpi/q35/SRAT.dimmpxm | Bin 392 -> 392 bytes tests/data/acpi/virt/SRAT.memhp | Bin 186 -> 226 bytes tests/qtest/bios-tables-test-allowed-diff.h | 3 --- 4 files changed, 3 deletions(-) diff --git a/tests/data/acpi/pc/SRAT.dimmpxm b/tests/data/acpi/pc/SRAT.dimmpxm index f5c0267ea24bb404b6b4e687390140378fbdc3f1..5a13c61b9041c6045c29643bf93a111fb1c0c76a 100644 GIT binary patch delta 51 scmeBR?qKE$4ss0XU}Rum%-G0fz$nec00kUCF%aN@Pz(&LlS3Je0lmQmhyVZp delta 51 icmeBR?qKE$4ss0XU}RumY}m+Uz$ndt8%z#mGzI{_tp$hx diff --git a/tests/data/acpi/q35/SRAT.dimmpxm b/tests/data/acpi/q35/SRAT.dimmpxm index f5c0267ea24bb404b6b4e687390140378fbdc3f1..5a13c61b9041c6045c29643bf93a111fb1c0c76a 100644 GIT binary patch delta 51 scmeBR?qKE$4ss0XU}Rum%-G0fz$nec00kUCF%aN@Pz(&LlS3Je0lmQmhyVZp delta 51 icmeBR?qKE$4ss0XU}RumY}m+Uz$ndt8%z#mGzI{_tp$hx diff --git a/tests/data/acpi/virt/SRAT.memhp b/tests/data/acpi/virt/SRAT.memhp index 1b57db2072e7f7e2085c4a427aa31c7383851b71..9a35adb40c6f7cd822e5af37abba8aad033617cb 100644 GIT binary patch delta 43 rcmdnR_=u4!ILI;N5d#AQbIe4p$wD1K76@=aC Date: Fri, 15 May 2020 17:04:06 +0200 Subject: [PATCH 0965/2595] qtest: allow DSDT acpi table changes Signed-off-by: Gerd Hoffmann Message-Id: <20200515150421.25479-2-kraxel@redhat.com> --- tests/qtest/bios-tables-test-allowed-diff.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..6a052c5044 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,18 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT", +"tests/data/acpi/pc/DSDT.acpihmat", +"tests/data/acpi/pc/DSDT.bridge", +"tests/data/acpi/pc/DSDT.cphp", +"tests/data/acpi/pc/DSDT.dimmpxm", +"tests/data/acpi/pc/DSDT.ipmikcs", +"tests/data/acpi/pc/DSDT.memhp", +"tests/data/acpi/pc/DSDT.numamem", +"tests/data/acpi/q35/DSDT", +"tests/data/acpi/q35/DSDT.acpihmat", +"tests/data/acpi/q35/DSDT.bridge", +"tests/data/acpi/q35/DSDT.cphp", +"tests/data/acpi/q35/DSDT.dimmpxm", +"tests/data/acpi/q35/DSDT.ipmibt", +"tests/data/acpi/q35/DSDT.memhp", +"tests/data/acpi/q35/DSDT.mmio64", +"tests/data/acpi/q35/DSDT.numamem", From df9b9b42cd2375a4eb785702899699a020ca2597 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 15 May 2020 17:04:07 +0200 Subject: [PATCH 0966/2595] acpi: move aml builder code for rtc device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200515150421.25479-3-kraxel@redhat.com> --- hw/i386/acpi-build.c | 17 ----------------- hw/rtc/mc146818rtc.c | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index d996525e2c..df5417c75f 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1137,22 +1137,6 @@ static Aml *build_fdc_device_aml(ISADevice *fdc) return dev; } -static Aml *build_rtc_device_aml(void) -{ - Aml *dev; - Aml *crs; - - dev = aml_device("RTC"); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0B00"))); - crs = aml_resource_template(); - aml_append(crs, aml_io(AML_DECODE16, 0x0070, 0x0070, 0x10, 0x02)); - aml_append(crs, aml_irq_no_flags(8)); - aml_append(crs, aml_io(AML_DECODE16, 0x0072, 0x0072, 0x02, 0x06)); - aml_append(dev, aml_name_decl("_CRS", crs)); - - return dev; -} - static Aml *build_kbd_device_aml(void) { Aml *dev; @@ -1278,7 +1262,6 @@ static void build_isa_devices_aml(Aml *table) Aml *scope = aml_scope("_SB.PCI0.ISA"); Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous); - aml_append(scope, build_rtc_device_aml()); aml_append(scope, build_kbd_device_aml()); aml_append(scope, build_mouse_device_aml()); if (fdc) { diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 9c30cbdcd7..fe05a4488e 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -27,6 +27,7 @@ #include "qemu/cutils.h" #include "qemu/module.h" #include "qemu/bcd.h" +#include "hw/acpi/aml-build.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "qemu/timer.h" @@ -1007,13 +1008,34 @@ static void rtc_resetdev(DeviceState *d) } } +static void rtc_build_aml(ISADevice *isadev, Aml *scope) +{ + Aml *dev; + Aml *crs; + + crs = aml_resource_template(); + aml_append(crs, aml_io(AML_DECODE16, RTC_ISA_BASE, RTC_ISA_BASE, + 0x10, 0x02)); + aml_append(crs, aml_irq_no_flags(RTC_ISA_IRQ)); + aml_append(crs, aml_io(AML_DECODE16, RTC_ISA_BASE + 2, RTC_ISA_BASE + 2, + 0x02, 0x06)); + + dev = aml_device("RTC"); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0B00"))); + aml_append(dev, aml_name_decl("_CRS", crs)); + + aml_append(scope, dev); +} + static void rtc_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); dc->realize = rtc_realizefn; dc->reset = rtc_resetdev; dc->vmsd = &vmstate_rtc; + isa->build_aml = rtc_build_aml; device_class_set_props(dc, mc146818rtc_properties); } From f592b94f3cbd5325bcf5142509b60cb6ab252770 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 15 May 2020 17:04:08 +0200 Subject: [PATCH 0967/2595] acpi: rtc: use a single crs range Use a single io range for _CRS instead of two, following what real hardware does. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Message-Id: <20200515150421.25479-4-kraxel@redhat.com> --- hw/rtc/mc146818rtc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index fe05a4488e..1e9fa0f33f 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -1013,12 +1013,14 @@ static void rtc_build_aml(ISADevice *isadev, Aml *scope) Aml *dev; Aml *crs; + /* + * Reserving 8 io ports here, following what physical hardware + * does, even though qemu only responds to the first two ports. + */ crs = aml_resource_template(); aml_append(crs, aml_io(AML_DECODE16, RTC_ISA_BASE, RTC_ISA_BASE, - 0x10, 0x02)); + 0x01, 0x08)); aml_append(crs, aml_irq_no_flags(RTC_ISA_IRQ)); - aml_append(crs, aml_io(AML_DECODE16, RTC_ISA_BASE + 2, RTC_ISA_BASE + 2, - 0x02, 0x06)); dev = aml_device("RTC"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0B00"))); From 4b8e369b91deff3ae7d8ae1067d336a66464f472 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 15 May 2020 17:04:09 +0200 Subject: [PATCH 0968/2595] acpi: serial: don't use _STA method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The _STA method dates back to the days where we had a static DSDT. The device is listed in the DSDT table unconditionally and the _STA method checks a bit in the isa bridge pci config space to figure whenever a given is isa device is present or not, then evaluates to 0x0f (present) or 0x00 (absent). These days the DSDT is generated by qemu anyway, so if a device is not present we can simply drop it from the DSDT instead. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200515150421.25479-5-kraxel@redhat.com> --- hw/i386/acpi-build.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index df5417c75f..cb22cb0fe6 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1208,50 +1208,34 @@ static Aml *build_lpt_device_aml(void) return dev; } -static Aml *build_com_device_aml(uint8_t uid) +static void build_com_device_aml(Aml *scope, uint8_t uid) { Aml *dev; Aml *crs; - Aml *method; - Aml *if_ctx; - Aml *else_ctx; - Aml *zero = aml_int(0); - Aml *is_present = aml_local(0); - const char *enabled_field = "CAEN"; uint8_t irq = 4; uint16_t io_port = 0x03F8; assert(uid == 1 || uid == 2); if (uid == 2) { - enabled_field = "CBEN"; irq = 3; io_port = 0x02F8; } + if (!memory_region_present(get_system_io(), io_port)) { + return; + } dev = aml_device("COM%d", uid); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0501"))); aml_append(dev, aml_name_decl("_UID", aml_int(uid))); - method = aml_method("_STA", 0, AML_NOTSERIALIZED); - aml_append(method, aml_store(aml_name("%s", enabled_field), is_present)); - if_ctx = aml_if(aml_equal(is_present, zero)); - { - aml_append(if_ctx, aml_return(aml_int(0x00))); - } - aml_append(method, if_ctx); - else_ctx = aml_else(); - { - aml_append(else_ctx, aml_return(aml_int(0x0f))); - } - aml_append(method, else_ctx); - aml_append(dev, method); + aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); crs = aml_resource_template(); aml_append(crs, aml_io(AML_DECODE16, io_port, io_port, 0x00, 0x08)); aml_append(crs, aml_irq_no_flags(irq)); aml_append(dev, aml_name_decl("_CRS", crs)); - return dev; + aml_append(scope, dev); } static void build_isa_devices_aml(Aml *table) @@ -1268,8 +1252,8 @@ static void build_isa_devices_aml(Aml *table) aml_append(scope, build_fdc_device_aml(fdc)); } aml_append(scope, build_lpt_device_aml()); - aml_append(scope, build_com_device_aml(1)); - aml_append(scope, build_com_device_aml(2)); + build_com_device_aml(scope, 1); + build_com_device_aml(scope, 2); if (ambiguous) { error_report("Multiple ISA busses, unable to define IPMI ACPI data"); From dcdbfaafe90a5e6e172368b2aa5500a9ca192e49 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 15 May 2020 17:04:10 +0200 Subject: [PATCH 0969/2595] acpi: move aml builder code for serial device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code uses the isa_serial_io array to figure what the device uid is. Side effect is that acpi antries are not limited to port 1+2 any more, we'll also get entries for ports 3+4. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200515150421.25479-6-kraxel@redhat.com> --- hw/char/serial-isa.c | 22 ++++++++++++++++++++++ hw/i386/acpi-build.c | 32 -------------------------------- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index f9b6eed783..165e320e65 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -27,6 +27,7 @@ #include "qapi/error.h" #include "qemu/module.h" #include "sysemu/sysemu.h" +#include "hw/acpi/aml-build.h" #include "hw/char/serial.h" #include "hw/isa/isa.h" #include "hw/qdev-properties.h" @@ -81,6 +82,25 @@ static void serial_isa_realizefn(DeviceState *dev, Error **errp) isa_register_ioport(isadev, &s->io, isa->iobase); } +static void serial_isa_build_aml(ISADevice *isadev, Aml *scope) +{ + ISASerialState *isa = ISA_SERIAL(isadev); + Aml *dev; + Aml *crs; + + crs = aml_resource_template(); + aml_append(crs, aml_io(AML_DECODE16, isa->iobase, isa->iobase, 0x00, 0x08)); + aml_append(crs, aml_irq_no_flags(isa->isairq)); + + dev = aml_device("COM%d", isa->index + 1); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0501"))); + aml_append(dev, aml_name_decl("_UID", aml_int(isa->index + 1))); + aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); + aml_append(dev, aml_name_decl("_CRS", crs)); + + aml_append(scope, dev); +} + static const VMStateDescription vmstate_isa_serial = { .name = "serial", .version_id = 3, @@ -103,9 +123,11 @@ static Property serial_isa_properties[] = { static void serial_isa_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); dc->realize = serial_isa_realizefn; dc->vmsd = &vmstate_isa_serial; + isa->build_aml = serial_isa_build_aml; device_class_set_props(dc, serial_isa_properties); set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index cb22cb0fe6..6de25f6484 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1208,36 +1208,6 @@ static Aml *build_lpt_device_aml(void) return dev; } -static void build_com_device_aml(Aml *scope, uint8_t uid) -{ - Aml *dev; - Aml *crs; - uint8_t irq = 4; - uint16_t io_port = 0x03F8; - - assert(uid == 1 || uid == 2); - if (uid == 2) { - irq = 3; - io_port = 0x02F8; - } - if (!memory_region_present(get_system_io(), io_port)) { - return; - } - - dev = aml_device("COM%d", uid); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0501"))); - aml_append(dev, aml_name_decl("_UID", aml_int(uid))); - - aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); - - crs = aml_resource_template(); - aml_append(crs, aml_io(AML_DECODE16, io_port, io_port, 0x00, 0x08)); - aml_append(crs, aml_irq_no_flags(irq)); - aml_append(dev, aml_name_decl("_CRS", crs)); - - aml_append(scope, dev); -} - static void build_isa_devices_aml(Aml *table) { ISADevice *fdc = pc_find_fdc0(); @@ -1252,8 +1222,6 @@ static void build_isa_devices_aml(Aml *table) aml_append(scope, build_fdc_device_aml(fdc)); } aml_append(scope, build_lpt_device_aml()); - build_com_device_aml(scope, 1); - build_com_device_aml(scope, 2); if (ambiguous) { error_report("Multiple ISA busses, unable to define IPMI ACPI data"); From 3e824d38256364f983be8717214fef709bc90e31 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 15 May 2020 17:04:11 +0200 Subject: [PATCH 0970/2595] acpi: parallel: don't use _STA method The _STA method dates back to the days where we had a static DSDT. The device is listed in the DSDT table unconditionally and the _STA method checks a bit in the isa bridge pci config space to figure whenever a given is isa device is present or not, then evaluates to 0x0f (present) or 0x00 (absent). These days the DSDT is generated by qemu anyway, so if a device is not present we can simply drop it from the DSDT instead. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Message-Id: <20200515150421.25479-7-kraxel@redhat.com> --- hw/i386/acpi-build.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 6de25f6484..2cafad03e2 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1173,39 +1173,26 @@ static Aml *build_mouse_device_aml(void) return dev; } -static Aml *build_lpt_device_aml(void) +static void build_lpt_device_aml(Aml *scope) { Aml *dev; Aml *crs; - Aml *method; - Aml *if_ctx; - Aml *else_ctx; - Aml *zero = aml_int(0); - Aml *is_present = aml_local(0); + + if (!memory_region_present(get_system_io(), 0x0378)) { + return; + } dev = aml_device("LPT"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0400"))); - method = aml_method("_STA", 0, AML_NOTSERIALIZED); - aml_append(method, aml_store(aml_name("LPEN"), is_present)); - if_ctx = aml_if(aml_equal(is_present, zero)); - { - aml_append(if_ctx, aml_return(aml_int(0x00))); - } - aml_append(method, if_ctx); - else_ctx = aml_else(); - { - aml_append(else_ctx, aml_return(aml_int(0x0f))); - } - aml_append(method, else_ctx); - aml_append(dev, method); + aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); crs = aml_resource_template(); aml_append(crs, aml_io(AML_DECODE16, 0x0378, 0x0378, 0x08, 0x08)); aml_append(crs, aml_irq_no_flags(7)); aml_append(dev, aml_name_decl("_CRS", crs)); - return dev; + aml_append(scope, dev); } static void build_isa_devices_aml(Aml *table) @@ -1221,7 +1208,7 @@ static void build_isa_devices_aml(Aml *table) if (fdc) { aml_append(scope, build_fdc_device_aml(fdc)); } - aml_append(scope, build_lpt_device_aml()); + build_lpt_device_aml(scope); if (ambiguous) { error_report("Multiple ISA busses, unable to define IPMI ACPI data"); From ed003c8c7743b846b1bf3f87cb88baf090da44e6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 15 May 2020 17:04:12 +0200 Subject: [PATCH 0971/2595] acpi: move aml builder code for parallel device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also adds support for multiple LPT devices. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200515150421.25479-8-kraxel@redhat.com> --- hw/char/parallel.c | 22 ++++++++++++++++++++++ hw/i386/acpi-build.c | 23 ----------------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/hw/char/parallel.c b/hw/char/parallel.c index 8dd67d1375..c0f34bf924 100644 --- a/hw/char/parallel.c +++ b/hw/char/parallel.c @@ -28,6 +28,7 @@ #include "qemu/module.h" #include "chardev/char-parallel.h" #include "chardev/char-fe.h" +#include "hw/acpi/aml-build.h" #include "hw/irq.h" #include "hw/isa/isa.h" #include "hw/qdev-properties.h" @@ -568,6 +569,25 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp) s, "parallel"); } +static void parallel_isa_build_aml(ISADevice *isadev, Aml *scope) +{ + ISAParallelState *isa = ISA_PARALLEL(isadev); + Aml *dev; + Aml *crs; + + crs = aml_resource_template(); + aml_append(crs, aml_io(AML_DECODE16, isa->iobase, isa->iobase, 0x08, 0x08)); + aml_append(crs, aml_irq_no_flags(isa->isairq)); + + dev = aml_device("LPT%d", isa->index + 1); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0400"))); + aml_append(dev, aml_name_decl("_UID", aml_int(isa->index + 1))); + aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); + aml_append(dev, aml_name_decl("_CRS", crs)); + + aml_append(scope, dev); +} + /* Memory mapped interface */ static uint64_t parallel_mm_readfn(void *opaque, hwaddr addr, unsigned size) { @@ -624,9 +644,11 @@ static Property parallel_isa_properties[] = { static void parallel_isa_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); dc->realize = parallel_isa_realizefn; dc->vmsd = &vmstate_parallel_isa; + isa->build_aml = parallel_isa_build_aml; device_class_set_props(dc, parallel_isa_properties); set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 2cafad03e2..58fe505fb6 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1173,28 +1173,6 @@ static Aml *build_mouse_device_aml(void) return dev; } -static void build_lpt_device_aml(Aml *scope) -{ - Aml *dev; - Aml *crs; - - if (!memory_region_present(get_system_io(), 0x0378)) { - return; - } - - dev = aml_device("LPT"); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0400"))); - - aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); - - crs = aml_resource_template(); - aml_append(crs, aml_io(AML_DECODE16, 0x0378, 0x0378, 0x08, 0x08)); - aml_append(crs, aml_irq_no_flags(7)); - aml_append(dev, aml_name_decl("_CRS", crs)); - - aml_append(scope, dev); -} - static void build_isa_devices_aml(Aml *table) { ISADevice *fdc = pc_find_fdc0(); @@ -1208,7 +1186,6 @@ static void build_isa_devices_aml(Aml *table) if (fdc) { aml_append(scope, build_fdc_device_aml(fdc)); } - build_lpt_device_aml(scope); if (ambiguous) { error_report("Multiple ISA busses, unable to define IPMI ACPI data"); From bab16ab33012cdae36246d2994b4a5ed9ac441f0 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 9 Jun 2020 11:16:14 -0400 Subject: [PATCH 0972/2595] tests/acpi: update DSDT expected files Update DSDT after CRS changes and _STA methods dropped. Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/pc/DSDT | Bin 5125 -> 5014 bytes tests/data/acpi/pc/DSDT.acpihmat | Bin 6449 -> 6338 bytes tests/data/acpi/pc/DSDT.bridge | Bin 6984 -> 6873 bytes tests/data/acpi/pc/DSDT.cphp | Bin 5588 -> 5477 bytes tests/data/acpi/pc/DSDT.dimmpxm | Bin 6778 -> 6667 bytes tests/data/acpi/pc/DSDT.ipmikcs | Bin 5197 -> 5086 bytes tests/data/acpi/pc/DSDT.memhp | Bin 6484 -> 6373 bytes tests/data/acpi/pc/DSDT.numamem | Bin 5131 -> 5020 bytes tests/data/acpi/q35/DSDT | Bin 7863 -> 7752 bytes tests/data/acpi/q35/DSDT.acpihmat | Bin 9187 -> 9076 bytes tests/data/acpi/q35/DSDT.bridge | Bin 7880 -> 7769 bytes tests/data/acpi/q35/DSDT.cphp | Bin 8326 -> 8215 bytes tests/data/acpi/q35/DSDT.dimmpxm | Bin 9516 -> 9405 bytes tests/data/acpi/q35/DSDT.ipmibt | Bin 7938 -> 7827 bytes tests/data/acpi/q35/DSDT.memhp | Bin 9222 -> 9111 bytes tests/data/acpi/q35/DSDT.mmio64 | Bin 8993 -> 8882 bytes tests/data/acpi/q35/DSDT.numamem | Bin 7869 -> 7758 bytes tests/qtest/bios-tables-test-allowed-diff.h | 17 ----------------- 18 files changed, 17 deletions(-) diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT index ad4b2d46cc7865e8bafcca2e4e888a03cc5483b5..384a82dbb3cb0e9f47db6f4d08945631c2b72b56 100644 GIT binary patch delta 164 zcmZqGn5NF<66_K(O_+g!v27z)FQb5;xIS}yuv2`1v!{V)uw(q>Ym5)2jC=w@3_0RG zJY9GkFR(Ch#D{viFml8Phd55Y%On+UYPPMU;J z0)_$x0VX8|Mt8;{h9U+gwn~P{%NZZm+xY~9#B;=Zc)IX7USMGmk%$itabzg)32^mG zSim+pfnf>5LY5_5{2cMlLBWCoT)gg#70eaP92`mw43!MgO|C4?{=SAV16Ub3;zK=M z7-7aZJK{Fx2lEeR1|JS30kAo4Aajh+%;5sM9^xKnCp-o*{a|9?P~u?NEX>?2004S} BL(TvI diff --git a/tests/data/acpi/pc/DSDT.acpihmat b/tests/data/acpi/pc/DSDT.acpihmat index eff7aadfabe431c3ac2d28e0c6721eb6e322af66..47ddfdb027b06dc2daa46be711c3f4640ce68320 100644 GIT binary patch delta 164 zcmdmJbjXm)CDXE}*eV$&FK2vMZ|4&b63-Fu;pxKTc!7mML?S*o#F3%EC&1M& zVFBCZ1coIH3t5(M@pHsG2L%fXaPhh`RxnpEb8sj%FjO)`H@UJn`}-Qg3}9vCh!6F2 zVT2ju?13KkUL;&o^I!Tf`n nfkR1vp^_oGNi`_MIUZ&tH_%A9vI2$z21X7g2FA@z%*Vt5d=n{- delta 282 zcmcab|o6X5EX zuz+oH0>cu9g)B?B_&MU8gMtMGxOm+eE0`;oIXILW7%CZ}n_O9({e2B#2Cy=6#D{vi zFv5&+cEoMW59S}t3_cu60$_98K;{^snZpHiJ;XiEPIwGr`oYA&p~S(kS(y2lH~`2b BMNI$z diff --git a/tests/data/acpi/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp index f3572358510f3fbb3d966047274f7aa7835e7bef..54f481faf1e336c0bbf5e774cd67220fe06e951b 100644 GIT binary patch delta 164 zcmcbj{Zxy~CD>tYEHS=HO6jV5nq>ZgORD_V+b}8NkZO5g+R5 z!U!|Q*%7xfKbU_oGx%^Q34qOU1DRulW)2t7^$_Ym5)2jC=w@3_0RG zJY9GkFR(Ch#D{viFml8Phd55Y%On+UYPPMU;J z0)_$x0VX8|Mt8;{h9U+gwn~P{%NZZm+xY~9#B;=Zc)IX7USMGmk%$itabzg)32^mG zSim+pfnf>5LY5_5{2cMlLBWCoT)gg#70eaP92`mw43!MgO|C4?{=SAV16Ub3;zK=M z7-7aZJK{Fx2lEeR1|JS30kAo4Aajh+%;5sM9^xKnCp-o*{a|9?P~u?NEX@2v3;^?H BMW_G( diff --git a/tests/data/acpi/pc/DSDT.ipmikcs b/tests/data/acpi/pc/DSDT.ipmikcs index 469d13e1f6b873bb9cfa0b3af32d1a3bc58e8f77..57b78358744a5bb13639ccddb887be2721240807 100644 GIT binary patch delta 172 zcmX@BaZjDgCDjc!oU$9>gmGB5g#1lIQcGUHE!Nn_l delta 259 zcmcboepZ9aCDCqao0w!UPgOYWqs!OV5j&1XHNsqV8{6ACf%SA=Xj2I4^I~! z#|zvH9P!RU!GaQ8qV9|Z3tJCJk%$it zabzg)32^mGSim+pfnf>5LY5_yUolDPy0SR?`x?SbXJzDw5A}3mgz0d0MAae3EamD3 t(qV+AgNq5S#R)|V7eBb|o6X5EX zuz+oH0>cu9g)B?B_&MU8gMtMGxOm+eE0`;oIXILW7%CZ}n_O9({e2B#2Cy=6#D{vi zFv5&+cEoMW59S}t3_cu60$_98K;{^snZpHiJ;XiEPIwGr`oYA&p~S(kS(y2fC;*9S BMH&DA diff --git a/tests/data/acpi/pc/DSDT.numamem b/tests/data/acpi/pc/DSDT.numamem index 9a747f6f08f61c73b891d8f91db01521e635f811..f194bc639482eb839a875d493857526f85f1a9e0 100644 GIT binary patch delta 164 zcmeCyn4`|+66_K(N0@Ym5)2jC=w@3_0RG zJY9GkFR(Ch#D{viFml8Phd55Y%On+Ub|o6X5EX zuz+oH0>cu9g)B?B_&MU8gMtMGxOm+eE0`;oIXILW7%CZ}n_O9({e2B#2Cy=6#D{vi zFv5&+cEoMW59S}t3_cu60$_98K;{^snZpHiJ;XiEPIwGr`oYA&p~S(kS(v#~002NJ BM34Xg diff --git a/tests/data/acpi/q35/DSDT b/tests/data/acpi/q35/DSDT index 9fa4d5a405c2bcd9313b13894917622bf156013e..6a5e4dd85a7d9a95f7ad0fb95e6a4fa7a8d91adb 100644 GIT binary patch delta 164 zcmdmPd%}jxCDXE}*eV$&Yca*u+xY~9#B;=Zc)IX7USMGmk%$itabzg)32^mG zSim+pfnf>5LY5_5{2cMlLBWCoT)gg#70eaP92`mw43!MgO|C4?{=SAV16Ub3;zK=M z7-7aZJK{Fx2lEeR1|JS30kAo4Aajh+%;5sM9^xKnCp-o*{a|9?P~u?NEX-^w4FJ*) BL!JNt diff --git a/tests/data/acpi/q35/DSDT.acpihmat b/tests/data/acpi/q35/DSDT.acpihmat index 2d834a854ccddc17afd0bc4b4a9e0886feff8e65..c1dd7773f3386a946fcb4a9a3bf9ad3a33ddbbe9 100644 GIT binary patch delta 164 zcmaFt{>6>UCDXE}*eV$&Yca*u+xY~9#B;=Zc)IX7USMGmk%$itabzg)32^mG zSim+pfnf>5LY5_5{2cMlLBWCoT)gg#70eaP92`mw43!MgO|C4?{=SAV16Ub3;zK=M z7-7aZJK{Fx2lEeR1|JS30kAo4Aajh+%;5sM9^xKnCp-o*{a|9?P~u?NEXzdmz(uv2`1v!{V)uw(q>NTxU`BcFf}LymY4 zPZu7?3oHyA@u8kBj2!X7A&!&pGD(FSIs5y?REWIH4xP delta 282 zcmcaXE}*eV$&Yca*u+xY~9#B;=Zc)IX7USMGmk%$itabzg)32^mG zSim+pfnf>5LY5_5{2cMlLBWCoT)gg#70eaP92`mw43!MgO|C4?{=SAV16Ub3;zK=M z7-7aZJK{Fx2lEeR1|JS30kAo4Aajh+%;5sM9^xKnCp-o*{a|9?P~u?NEX?dC4FIJi BLxKPR diff --git a/tests/data/acpi/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp index c59c19ff46b9bb4fa3e06e9ffbcbeba308a80cd0..74e86176e5fec46e660c567acf8fbcf08a14bdfb 100644 GIT binary patch delta 164 zcmZp3obJHo66_KpuE4;+=(~|ifJwlcU!OTX*eO21+0(!?*fD-`BvYJ}kxxK~AxFH2 zrwfnc1r`R5_)t$5MvnO45XZ@PnWVyvoc(>_(yTxUxHK0(N4#@Tu%G}JuRG%p<{!)q n97+NVl?>5MszD*n@h~H~fkwiW6)+SqFmfm{Fm7&QW|0K|t9T`# delta 282 zcmbR4(B{bH66_Mvroh0!_--SY0F$tnm_BoSuv2`1v!{V)uw#65lkVh?Od=8zT%zub z1q=lY0!&H_jP8s@3`Gn~Y?Ta?wV2}S?R)}4;yL0yJY9GkFR(C(NW=$+I5HIY1i1Po zEMS|Qz_5g2AXE}*eV$&Yca*u+xY~9#B;=Zc)IX7USMGmk%$itabzg)32^mG zSim+pfnf>5LY5_5{2cMlLBWCoT)gg#70eaP92`mw43!MgO|C4?{=SAV16Ub3;zK=M z7-7aZJK{Fx2lEeR1|JS30kAo4Aajh+%;5sM9^xKnCp-o*{a|9?P~u?NEX=%05de>t BL)!oV diff --git a/tests/data/acpi/q35/DSDT.ipmibt b/tests/data/acpi/q35/DSDT.ipmibt index 3910e9b767808962b46501da51945229359e3d1d..38723daef80421ea528b2ad2d411e7357df43956 100644 GIT binary patch delta 172 zcmZp&n{3PF66_K(S&o5$kz*s50F!{5h(2?Cuv2`1v!{V)uw(q>NT#^SZOooB(M?7^ z0U?GQ@gANoJdPJw7&ziXJzW?%;)6pRC*Ng~iZpWe_k~Nd0wv(mT>KpI&OyO~0$jZA uj6axvFf(u{2{2SLL^r7hg*eB+c9V`qY67j(y zjtm7p0j_=t3)m(nFf3tM$g*VeTP7)8R~Bb~UqhJbtc)D-p`I>`Fdfd0s5%sxrCi)V rI*ibCa52HPIH73a;)l3bfQ#3i@dwinCI${A4u;7sOum~Fn2n_Y$^<{r diff --git a/tests/data/acpi/q35/DSDT.memhp b/tests/data/acpi/q35/DSDT.memhp index 8461e984c965da916d828884f6629422e83e429c..98328d1c4197ab19a71de7f3f18e2985f4910f45 100644 GIT binary patch delta 164 zcmZqknC{Ny66_K(U73M_@z_Q#0VV-&etqWnV5j&1XHNsqV8{5$kxX$?Mm_-{h8*!8 zo-RC&7g!iL;zK=M7&+pDLmVgHWs(Xva`yLyOS1wc;L=?D9P!RU!GZ!@yzY!Yn13)c na3~2dR5C<2sRo5O$HR=|1{w)hR=`lez{sJ*z__`IxkUj0OPVJw delta 282 zcmbR4-sZvO66_MfrozC$n6{BifJxX(OrJSE*eO21+0(!?*fBo3Nq6!`CJ_kU;J z0)_$x0VX8|Mt8;{h9U+gwn~P{T1;{Ec0K_i@f`6Uo-RC&7g!iXB;tcZ92p9H0$lwP z7O+iDU|7PikYx!MKS#WCP_Uo?7q2^G1#<;62ZvGvLnT9WlPim}zpo+809Hnh_)t$5 zMwl_qj<}8a!Tf`n!G}Xh0BnvM$Q&aybGU%6hq%Yt36DWcKbROelsFhR3p2MU006lR BLhJwl diff --git a/tests/data/acpi/q35/DSDT.mmio64 b/tests/data/acpi/q35/DSDT.mmio64 index fc0cc096baf8aedc0a526978ff796025d7380453..5916c0e9ce0a9607c6230f9dfebe2c1be70b2495 100644 GIT binary patch delta 164 zcmZ4Jw#k*tCDXVQ;;W5 delta 282 zcmdnwy3mcwCDzdmz(uv2`1v!{V)uw(q>NTxU`BcFf}LymY4 zPZu7?3oHyA@u8kBj2!X7A&!&pGD(FSIs5yXE}*eV$&Yca*u+xY~9#B;=Zc)IX7USMGmk%$itabzg)32^mG zSim+pfnf>5LY5_5{2cMlLBWCoT)gg#70eaP92`mw43!MgO|C4?{=SAV16Ub3;zK=M z7-7aZJK{Fx2lEeR1|JS30kAo4Aajh+%;5sM9^xKnCp-o*{a|9?P~u?NEX-^z4FHR! BLtp>^ diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 6a052c5044..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,18 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/pc/DSDT", -"tests/data/acpi/pc/DSDT.acpihmat", -"tests/data/acpi/pc/DSDT.bridge", -"tests/data/acpi/pc/DSDT.cphp", -"tests/data/acpi/pc/DSDT.dimmpxm", -"tests/data/acpi/pc/DSDT.ipmikcs", -"tests/data/acpi/pc/DSDT.memhp", -"tests/data/acpi/pc/DSDT.numamem", -"tests/data/acpi/q35/DSDT", -"tests/data/acpi/q35/DSDT.acpihmat", -"tests/data/acpi/q35/DSDT.bridge", -"tests/data/acpi/q35/DSDT.cphp", -"tests/data/acpi/q35/DSDT.dimmpxm", -"tests/data/acpi/q35/DSDT.ipmibt", -"tests/data/acpi/q35/DSDT.memhp", -"tests/data/acpi/q35/DSDT.mmio64", -"tests/data/acpi/q35/DSDT.numamem", From 7e7c1b84ca11c36a4269baa6538a47dbdf2ee758 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Fri, 29 May 2020 15:28:40 -0400 Subject: [PATCH 0973/2595] acpi: tpm: Do not build TCPA table for TPM 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not build a TCPA table for TPM 2 anymore but create the log area when building the TPM2 table. The TCPA table is only needed for TPM 1.2. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau Reviewed-by: Eric Auger Reviewed-by: Igor Mammedov Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 58fe505fb6..d05d010f77 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2216,6 +2216,10 @@ build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) tpm2_ptr->log_area_minimum_length = cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE); + acpi_data_push(tcpalog, le32_to_cpu(tpm2_ptr->log_area_minimum_length)); + bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1, + false); + /* log area start address to be filled by Guest linker */ bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, log_addr_offset, log_addr_size, @@ -2752,10 +2756,10 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) build_hpet(tables_blob, tables->linker); } if (misc.tpm_version != TPM_VERSION_UNSPEC) { - acpi_add_table(table_offsets, tables_blob); - build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog); - - if (misc.tpm_version == TPM_VERSION_2_0) { + if (misc.tpm_version == TPM_VERSION_1_2) { + acpi_add_table(table_offsets, tables_blob); + build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog); + } else { /* TPM_VERSION_2_0 */ acpi_add_table(table_offsets, tables_blob); build_tpm2(tables_blob, tables->linker, tables->tcpalog); } From 04b778610af51987309055440b1ff16b50db5646 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 1 Jun 2020 11:57:34 +0200 Subject: [PATCH 0974/2595] acpi: Convert build_tpm2() to build_append* API In preparation of its move to the generic acpi code, let's convert build_tpm2() to use build_append API. This latter now is prefered in place of direct ACPI struct field settings with manual endianness conversion. Signed-off-by: Eric Auger Message-Id: <20200601095737.32671-2-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index d05d010f77..8d93a2d339 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2197,30 +2197,40 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) static void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) { - Acpi20TPM2 *tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr); + Acpi20TPM2 *tpm2_ptr = acpi_data_push(table_data, sizeof(AcpiTableHeader)); unsigned log_addr_size = sizeof(tpm2_ptr->log_area_start_address); unsigned log_addr_offset = (char *)&tpm2_ptr->log_area_start_address - table_data->data; + uint8_t start_method_params[12] = {}; - tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT); + /* platform class */ + build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2); + /* reserved */ + build_append_int_noprefix(table_data, 0, 2); if (TPM_IS_TIS_ISA(tpm_find())) { - tpm2_ptr->control_area_address = cpu_to_le64(0); - tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); + /* address of control area */ + build_append_int_noprefix(table_data, 0, 8); + /* start method */ + build_append_int_noprefix(table_data, TPM2_START_METHOD_MMIO, 4); } else if (TPM_IS_CRB(tpm_find())) { - tpm2_ptr->control_area_address = cpu_to_le64(TPM_CRB_ADDR_CTRL); - tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_CRB); + build_append_int_noprefix(table_data, TPM_CRB_ADDR_CTRL, 8); + build_append_int_noprefix(table_data, TPM2_START_METHOD_CRB, 4); } else { g_warn_if_reached(); } - tpm2_ptr->log_area_minimum_length = - cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE); + /* platform specific parameters */ + g_array_append_vals(table_data, &start_method_params, 12); - acpi_data_push(tcpalog, le32_to_cpu(tpm2_ptr->log_area_minimum_length)); + /* log area minimum length */ + build_append_int_noprefix(table_data, TPM_LOG_AREA_MINIMUM_SIZE, 4); + + acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE); bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1, false); /* log area start address to be filled by Guest linker */ + build_append_int_noprefix(table_data, 0, 8); bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, log_addr_offset, log_addr_size, ACPI_BUILD_TPMLOG_FILE, 0); From 4338416064303aad7929a247770f2ed4d9652966 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 1 Jun 2020 11:57:35 +0200 Subject: [PATCH 0975/2595] acpi: Move build_tpm2() in the generic part We plan to build the TPM2 table on ARM too. In order to reuse the generation code, let's move build_tpm2() to aml-build.c. No change in the implementation. Signed-off-by: Eric Auger Message-Id: <20200601095737.32671-3-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/aml-build.c | 44 +++++++++++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 44 ------------------------------------- include/hw/acpi/aml-build.h | 2 ++ 3 files changed, 46 insertions(+), 44 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 3681ec6e3d..b37052c1b4 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -26,6 +26,7 @@ #include "qemu/bitops.h" #include "sysemu/numa.h" #include "hw/boards.h" +#include "hw/acpi/tpm.h" static GArray *build_alloc_array(void) { @@ -1877,6 +1878,49 @@ build_hdr: "FACP", tbl->len - fadt_start, f->rev, oem_id, oem_table_id); } +void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) +{ + Acpi20TPM2 *tpm2_ptr = acpi_data_push(table_data, sizeof(AcpiTableHeader)); + unsigned log_addr_size = sizeof(tpm2_ptr->log_area_start_address); + unsigned log_addr_offset = + (char *)&tpm2_ptr->log_area_start_address - table_data->data; + uint8_t start_method_params[12] = {}; + + /* platform class */ + build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2); + /* reserved */ + build_append_int_noprefix(table_data, 0, 2); + if (TPM_IS_TIS_ISA(tpm_find())) { + /* address of control area */ + build_append_int_noprefix(table_data, 0, 8); + /* start method */ + build_append_int_noprefix(table_data, TPM2_START_METHOD_MMIO, 4); + } else if (TPM_IS_CRB(tpm_find())) { + build_append_int_noprefix(table_data, TPM_CRB_ADDR_CTRL, 8); + build_append_int_noprefix(table_data, TPM2_START_METHOD_CRB, 4); + } else { + g_warn_if_reached(); + } + + /* platform specific parameters */ + g_array_append_vals(table_data, &start_method_params, 12); + + /* log area minimum length */ + build_append_int_noprefix(table_data, TPM_LOG_AREA_MINIMUM_SIZE, 4); + + acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE); + bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1, + false); + + /* log area start address to be filled by Guest linker */ + build_append_int_noprefix(table_data, 0, 8); + bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, + log_addr_offset, log_addr_size, + ACPI_BUILD_TPMLOG_FILE, 0); + build_header(linker, table_data, + (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL); +} + /* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors */ static Aml *aml_serial_bus_device(uint8_t serial_bus_type, uint8_t flags, uint16_t type_flags, diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 8d93a2d339..1ecb68f45f 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2194,50 +2194,6 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) (void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL, NULL); } -static void -build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) -{ - Acpi20TPM2 *tpm2_ptr = acpi_data_push(table_data, sizeof(AcpiTableHeader)); - unsigned log_addr_size = sizeof(tpm2_ptr->log_area_start_address); - unsigned log_addr_offset = - (char *)&tpm2_ptr->log_area_start_address - table_data->data; - uint8_t start_method_params[12] = {}; - - /* platform class */ - build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2); - /* reserved */ - build_append_int_noprefix(table_data, 0, 2); - if (TPM_IS_TIS_ISA(tpm_find())) { - /* address of control area */ - build_append_int_noprefix(table_data, 0, 8); - /* start method */ - build_append_int_noprefix(table_data, TPM2_START_METHOD_MMIO, 4); - } else if (TPM_IS_CRB(tpm_find())) { - build_append_int_noprefix(table_data, TPM_CRB_ADDR_CTRL, 8); - build_append_int_noprefix(table_data, TPM2_START_METHOD_CRB, 4); - } else { - g_warn_if_reached(); - } - - /* platform specific parameters */ - g_array_append_vals(table_data, &start_method_params, 12); - - /* log area minimum length */ - build_append_int_noprefix(table_data, TPM_LOG_AREA_MINIMUM_SIZE, 4); - - acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE); - bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1, - false); - - /* log area start address to be filled by Guest linker */ - build_append_int_noprefix(table_data, 0, 8); - bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, - log_addr_offset, log_addr_size, - ACPI_BUILD_TPMLOG_FILE, 0); - build_header(linker, table_data, - (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL); -} - #define HOLE_640K_START (640 * KiB) #define HOLE_640K_END (1 * MiB) diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index ed7c89309e..d27da03d64 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -437,4 +437,6 @@ void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms); void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, const char *oem_id, const char *oem_table_id); + +void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog); #endif From 80bde69353924d99e2a7f5ac6be0ab4cf489d33c Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 1 Jun 2020 11:57:36 +0200 Subject: [PATCH 0976/2595] arm/acpi: TPM2 ACPI table support Add a TPM2 ACPI table if a TPM2.0 sysbus device has been dynamically instantiated. Signed-off-by: Eric Auger Message-Id: <20200601095737.32671-4-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/aml-build.c | 5 +++-- hw/arm/virt-acpi-build.c | 7 +++++++ include/sysemu/tpm.h | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index b37052c1b4..d24e9e6c3a 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1885,17 +1885,18 @@ void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) unsigned log_addr_offset = (char *)&tpm2_ptr->log_area_start_address - table_data->data; uint8_t start_method_params[12] = {}; + TPMIf *tpmif = tpm_find(); /* platform class */ build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2); /* reserved */ build_append_int_noprefix(table_data, 0, 2); - if (TPM_IS_TIS_ISA(tpm_find())) { + if (TPM_IS_TIS_ISA(tpmif) || TPM_IS_TIS_SYSBUS(tpmif)) { /* address of control area */ build_append_int_noprefix(table_data, 0, 8); /* start method */ build_append_int_noprefix(table_data, TPM2_START_METHOD_MMIO, 4); - } else if (TPM_IS_CRB(tpm_find())) { + } else if (TPM_IS_CRB(tpmif)) { build_append_int_noprefix(table_data, TPM_CRB_ADDR_CTRL, 8); build_append_int_noprefix(table_data, TPM2_START_METHOD_CRB, 4); } else { diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 2cbccd5fe2..ca31f70f7f 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -41,12 +41,14 @@ #include "hw/acpi/pci.h" #include "hw/acpi/memory_hotplug.h" #include "hw/acpi/generic_event_device.h" +#include "hw/acpi/tpm.h" #include "hw/pci/pcie_host.h" #include "hw/pci/pci.h" #include "hw/arm/virt.h" #include "hw/mem/nvdimm.h" #include "sysemu/numa.h" #include "sysemu/reset.h" +#include "sysemu/tpm.h" #include "kvm_arm.h" #include "migration/vmstate.h" #include "hw/acpi/ghes.h" @@ -848,6 +850,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) build_iort(tables_blob, tables->linker, vms); } + if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) { + acpi_add_table(table_offsets, tables_blob); + build_tpm2(tables_blob, tables->linker, tables->tcpalog); + } + /* XSDT is pointed to by RSDP */ xsdt = tables_blob->len; build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL); diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index f37851b1aa..03fb25941c 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -50,6 +50,8 @@ typedef struct TPMIfClass { #define TPM_IS_TIS_ISA(chr) \ object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_ISA) +#define TPM_IS_TIS_SYSBUS(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_SYSBUS) #define TPM_IS_CRB(chr) \ object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB) #define TPM_IS_SPAPR(chr) \ From 0561dfac082becdd9e89110249a27b309b62aa9f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 18 May 2020 09:43:52 +0200 Subject: [PATCH 0977/2595] net: Do not include a newline in the id of -nic devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The '\n' sneaked in by accident here, an "id" string should really not contain a newline character at the end. Fixes: 78cd6f7bf6b ('net: Add a new convenience option "--nic" ...') Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200518074352.23125-1-thuth@redhat.com> Signed-off-by: Laurent Vivier --- net/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/net.c b/net/net.c index 38778e831d..cbeeeadff8 100644 --- a/net/net.c +++ b/net/net.c @@ -1506,7 +1506,7 @@ static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp) /* Create an ID if the user did not specify one */ nd_id = g_strdup(qemu_opts_id(opts)); if (!nd_id) { - nd_id = g_strdup_printf("__org.qemu.nic%i\n", idx); + nd_id = g_strdup_printf("__org.qemu.nic%i", idx); qemu_opts_set_id(opts, nd_id); } From 449fd1fc0041facd8c9bef0c7eb8d63fd0418a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 May 2020 12:39:20 +0200 Subject: [PATCH 0978/2595] .mailmap: Update Fred Konrad email address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update Fred Konrad email address to avoid emails bouncing. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: KONRAD Frederic Message-Id: <20200518103920.10699-1-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index e3628c7a66..d6bd1b2fec 100644 --- a/.mailmap +++ b/.mailmap @@ -45,6 +45,7 @@ Aleksandar Markovic Aleksandar Rikalo Aleksandar Rikalo Anthony Liguori Anthony Liguori +Frederic Konrad James Hogan Leif Lindholm Paul Burton From 3b34ee6780f5ebf4c641a7522288b9e7e4e123d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 24 May 2020 18:45:03 +0200 Subject: [PATCH 0979/2595] hw/unicore32/puv3: Use qemu_log_mask(ERROR) instead of debug printf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace some debug printf() calls by qemu_log_mask(LOG_GUEST_ERROR). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20200524164503.11944-1-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/dma/puv3_dma.c | 9 +++++++-- hw/gpio/puv3_gpio.c | 15 +++++++++++---- hw/intc/puv3_intc.c | 9 +++++++-- hw/misc/puv3_pm.c | 9 +++++++-- hw/timer/puv3_ost.c | 9 +++++++-- hw/unicore32/puv3.c | 2 -- 6 files changed, 39 insertions(+), 14 deletions(-) diff --git a/hw/dma/puv3_dma.c b/hw/dma/puv3_dma.c index 5488d388a9..7fa979180f 100644 --- a/hw/dma/puv3_dma.c +++ b/hw/dma/puv3_dma.c @@ -15,6 +15,7 @@ #undef DEBUG_PUV3 #include "hw/unicore32/puv3.h" #include "qemu/module.h" +#include "qemu/log.h" #define PUV3_DMA_CH_NR (6) #define PUV3_DMA_CH_MASK (0xff) @@ -43,7 +44,9 @@ static uint64_t puv3_dma_read(void *opaque, hwaddr offset, ret = s->reg_CFG[PUV3_DMA_CH(offset)]; break; default: - DPRINTF("Bad offset 0x%x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, offset); } DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); @@ -62,7 +65,9 @@ static void puv3_dma_write(void *opaque, hwaddr offset, s->reg_CFG[PUV3_DMA_CH(offset)] = value; break; default: - DPRINTF("Bad offset 0x%x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, offset); } DPRINTF("offset 0x%x, value 0x%x\n", offset, value); } diff --git a/hw/gpio/puv3_gpio.c b/hw/gpio/puv3_gpio.c index d19e342514..7362b6715f 100644 --- a/hw/gpio/puv3_gpio.c +++ b/hw/gpio/puv3_gpio.c @@ -15,6 +15,7 @@ #undef DEBUG_PUV3 #include "hw/unicore32/puv3.h" #include "qemu/module.h" +#include "qemu/log.h" #define TYPE_PUV3_GPIO "puv3_gpio" #define PUV3_GPIO(obj) OBJECT_CHECK(PUV3GPIOState, (obj), TYPE_PUV3_GPIO) @@ -47,7 +48,9 @@ static uint64_t puv3_gpio_read(void *opaque, hwaddr offset, ret = s->reg_GPIR; break; default: - DPRINTF("Bad offset 0x%x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, offset); } DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); @@ -68,14 +71,16 @@ static void puv3_gpio_write(void *opaque, hwaddr offset, if (s->reg_GPDR & value) { s->reg_GPLR |= value; } else { - DPRINTF("Write gpio input port error!"); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Write gpio input port\n", + __func__); } break; case 0x0c: if (s->reg_GPDR & value) { s->reg_GPLR &= ~value; } else { - DPRINTF("Write gpio input port error!"); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Write gpio input port\n", + __func__); } break; case 0x10: /* GRER */ @@ -86,7 +91,9 @@ static void puv3_gpio_write(void *opaque, hwaddr offset, s->reg_GPIR = value; break; default: - DPRINTF("Bad offset 0x%x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, offset); } } diff --git a/hw/intc/puv3_intc.c b/hw/intc/puv3_intc.c index e018955ce8..090d4839d1 100644 --- a/hw/intc/puv3_intc.c +++ b/hw/intc/puv3_intc.c @@ -16,6 +16,7 @@ #undef DEBUG_PUV3 #include "hw/unicore32/puv3.h" #include "qemu/module.h" +#include "qemu/log.h" #define TYPE_PUV3_INTC "puv3_intc" #define PUV3_INTC(obj) OBJECT_CHECK(PUV3INTCState, (obj), TYPE_PUV3_INTC) @@ -68,7 +69,9 @@ static uint64_t puv3_intc_read(void *opaque, hwaddr offset, ret = s->reg_ICPR; /* the same value with ICPR */ break; default: - DPRINTF("Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, offset); } DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); return ret; @@ -88,7 +91,9 @@ static void puv3_intc_write(void *opaque, hwaddr offset, s->reg_ICMR = value; break; default: - DPRINTF("Bad offset 0x%x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, offset); return; } puv3_intc_update(s); diff --git a/hw/misc/puv3_pm.c b/hw/misc/puv3_pm.c index c213500d9c..8989d363cd 100644 --- a/hw/misc/puv3_pm.c +++ b/hw/misc/puv3_pm.c @@ -15,6 +15,7 @@ #undef DEBUG_PUV3 #include "hw/unicore32/puv3.h" #include "qemu/module.h" +#include "qemu/log.h" #define TYPE_PUV3_PM "puv3_pm" #define PUV3_PM(obj) OBJECT_CHECK(PUV3PMState, (obj), TYPE_PUV3_PM) @@ -73,7 +74,9 @@ static uint64_t puv3_pm_read(void *opaque, hwaddr offset, ret = 0x7; break; default: - DPRINTF("Bad offset 0x%x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, offset); } DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); @@ -105,7 +108,9 @@ static void puv3_pm_write(void *opaque, hwaddr offset, case 0x38: break; default: - DPRINTF("Bad offset 0x%x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, offset); } DPRINTF("offset 0x%x, value 0x%x\n", offset, value); } diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c index 697519593b..f76b0bb1ca 100644 --- a/hw/timer/puv3_ost.c +++ b/hw/timer/puv3_ost.c @@ -14,6 +14,7 @@ #include "hw/irq.h" #include "hw/ptimer.h" #include "qemu/module.h" +#include "qemu/log.h" #undef DEBUG_PUV3 #include "hw/unicore32/puv3.h" @@ -52,7 +53,9 @@ static uint64_t puv3_ost_read(void *opaque, hwaddr offset, ret = s->reg_OIER; break; default: - DPRINTF("Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad read offset 0x%"HWADDR_PRIx"\n", + __func__, offset); } DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); return ret; @@ -88,7 +91,9 @@ static void puv3_ost_write(void *opaque, hwaddr offset, s->reg_OIER = value; break; default: - DPRINTF("Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad write offset 0x%"HWADDR_PRIx"\n", + __func__, offset); } } diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c index 7f9c0238fe..eacacb4249 100644 --- a/hw/unicore32/puv3.c +++ b/hw/unicore32/puv3.c @@ -16,8 +16,6 @@ #include "hw/boards.h" #include "hw/loader.h" #include "sysemu/qtest.h" - -#undef DEBUG_PUV3 #include "hw/unicore32/puv3.h" #include "hw/input/i8042.h" #include "hw/irq.h" From 18cdeb72bb9ad7a574be68175e72068ced70e443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 24 May 2020 18:48:06 +0200 Subject: [PATCH 0980/2595] hw/isa/apm: Convert debug printf()s to trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert APM_DPRINTF() to trace events and remove ifdef'ry. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200524164806.12658-1-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/isa/apm.c | 15 +++++---------- hw/isa/trace-events | 4 ++++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/hw/isa/apm.c b/hw/isa/apm.c index 6300b1ba7a..bce266b957 100644 --- a/hw/isa/apm.c +++ b/hw/isa/apm.c @@ -24,14 +24,8 @@ #include "hw/isa/apm.h" #include "hw/pci/pci.h" #include "migration/vmstate.h" +#include "trace.h" -//#define DEBUG - -#ifdef DEBUG -# define APM_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) -#else -# define APM_DPRINTF(format, ...) do { } while (0) -#endif /* fixed I/O location */ #define APM_STS_IOPORT 0xb3 @@ -41,8 +35,8 @@ static void apm_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, { APMState *apm = opaque; addr &= 1; - APM_DPRINTF("apm_ioport_writeb addr=0x%" HWADDR_PRIx - " val=0x%02" PRIx64 "\n", addr, val); + + trace_apm_io_write(addr, val); if (addr == 0) { apm->apmc = val; @@ -65,7 +59,8 @@ static uint64_t apm_ioport_readb(void *opaque, hwaddr addr, unsigned size) } else { val = apm->apms; } - APM_DPRINTF("apm_ioport_readb addr=0x%" HWADDR_PRIx " val=0x%02x\n", addr, val); + trace_apm_io_read(addr, val); + return val; } diff --git a/hw/isa/trace-events b/hw/isa/trace-events index 202f8938e7..3544c6213c 100644 --- a/hw/isa/trace-events +++ b/hw/isa/trace-events @@ -9,3 +9,7 @@ superio_create_ide(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, # pc87312.c pc87312_io_read(uint32_t addr, uint32_t val) "read addr=0x%x val=0x%x" pc87312_io_write(uint32_t addr, uint32_t val) "write addr=0x%x val=0x%x" + +# apm.c +apm_io_read(uint8_t addr, uint8_t val) "read addr=0x%x val=0x%02x" +apm_io_write(uint8_t addr, uint8_t val) "write addr=0x%x val=0x%02x" From d263425bce8620d608410e68e492adb7ef072465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 6 Jun 2020 09:02:16 +0200 Subject: [PATCH 0981/2595] hw/misc/auxbus: Use qemu_log_mask(UNIMP) instead of debug printf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace a deprecated DPRINTF() call by qemu_log_mask(LOG_UNIMP). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Message-Id: <20200606070216.30952-1-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/misc/auxbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index f8e7b97971..06aabf20c5 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -196,7 +196,7 @@ AUXReply aux_request(AUXBus *bus, AUXCommand cmd, uint32_t address, } break; default: - DPRINTF("Not implemented!\n"); + qemu_log_mask(LOG_UNIMP, "AUX cmd=%u not implemented\n", cmd); return AUX_NACK; } From 547f8f6452579506fbde2f0a1aa5fc0469dc45a3 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 29 May 2020 09:45:27 -0500 Subject: [PATCH 0982/2595] qemu-img: Fix doc typo for 'bitmap' subcommand Prefer a consistent naming for the --merge argument. Fixes: 3b51ab4bf Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200529144527.1943527-1-eblake@redhat.com> Signed-off-by: Laurent Vivier --- docs/tools/qemu-img.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index 69cd9a3037..7f0737488a 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -300,7 +300,7 @@ Command description: ``--disable`` to change *BITMAP* to stop recording future edits. - ``--merge`` to merge the contents of *SOURCE_BITMAP* into *BITMAP*. + ``--merge`` to merge the contents of the *SOURCE* bitmap into *BITMAP*. Additional options include ``-g`` which sets a non-default *GRANULARITY* for ``--add``, and ``-b`` and ``-F`` which select an From 7df9f0283905c25d9c317f782cde9f52bb1916ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 16:29:23 +0200 Subject: [PATCH 0983/2595] hw/arm/aspeed: Correct DRAM container region size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit memory_region_set_size() handle the 16 Exabytes limit by special-casing the UINT64_MAX value. This is not a problem for the 32-bit maximum, 4 GiB. By using the UINT32_MAX value, the aspeed-ram-container MemoryRegion ends up missing 1 byte: $ qemu-system-arm -M ast2600-evb -S -monitor stdio (qemu) info mtree address-space: aspeed.fmc-ast2600-dma-dram 0000000080000000-000000017ffffffe (prio 0, i/o): aspeed-ram-container 0000000080000000-00000000bfffffff (prio 0, ram): ram 00000000c0000000-ffffffffffffffff (prio 0, i/o): max_ram Fix by using the correct value. We now have: address-space: aspeed.fmc-ast2600-dma-dram 0000000080000000-000000017fffffff (prio 0, i/o): aspeed-ram-container 0000000080000000-00000000bfffffff (prio 0, ram): ram 00000000c0000000-ffffffffffffffff (prio 0, i/o): max_ram Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Reviewed-by: Richard Henderson Message-Id: <20200601142930.29408-2-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/arm/aspeed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 2c23297edf..62344ac6a3 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -262,7 +262,7 @@ static void aspeed_machine_init(MachineState *machine) bmc = g_new0(AspeedBoardState, 1); memory_region_init(&bmc->ram_container, NULL, "aspeed-ram-container", - UINT32_MAX); + 4 * GiB); memory_region_add_subregion(&bmc->ram_container, 0, machine->ram); object_initialize_child(OBJECT(machine), "soc", &bmc->soc, From 94c1253e3e55d82806d00a94cbbde209738ed1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 16:29:28 +0200 Subject: [PATCH 0984/2595] hw/hppa/dino: Use the IEC binary prefix definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IEC binary prefixes ease code review: the unit is explicit. Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200601142930.29408-7-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/hppa/dino.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 2b1b38c58a..7290f23962 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -542,7 +542,7 @@ PCIBus *dino_init(MemoryRegion *addr_space, &s->parent_obj.data_mem); /* Dino PCI bus memory. */ - memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 1ull << 32); + memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 4 * GiB); b = pci_register_root_bus(dev, "pci", dino_set_irq, dino_pci_map_irq, s, &s->pci_mem, get_system_io(), @@ -561,7 +561,7 @@ PCIBus *dino_init(MemoryRegion *addr_space, } /* Set up PCI view of memory: Bus master address space. */ - memory_region_init(&s->bm, OBJECT(s), "bm-dino", 1ull << 32); + memory_region_init(&s->bm, OBJECT(s), "bm-dino", 4 * GiB); memory_region_init_alias(&s->bm_ram_alias, OBJECT(s), "bm-system", addr_space, 0, 0xf0000000 + DINO_MEM_CHUNK_SIZE); From 039a93b02f37a23f49e4b1d0c4a075829a9d49d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 16:29:29 +0200 Subject: [PATCH 0985/2595] hw/i386/xen/xen-hvm: Use the IEC binary prefix definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IEC binary prefixes ease code review: the unit is explicit. Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Paul Durrant Reviewed-by: Richard Henderson Message-Id: <20200601142930.29408-8-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/i386/xen/xen-hvm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index 82ece6b9e7..94fe5d65e9 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -9,6 +9,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "cpu.h" #include "hw/pci/pci.h" @@ -230,7 +231,7 @@ static void xen_ram_init(PCMachineState *pcms, * Xen does not allocate the memory continuously, it keeps a * hole of the size computed above or passed in. */ - block_len = (1ULL << 32) + x86ms->above_4g_mem_size; + block_len = (4 * GiB) + x86ms->above_4g_mem_size; } memory_region_init_ram(&ram_memory, NULL, "xen.ram", block_len, &error_fatal); From 3fb79344bd41bed9e2975dab49d7d1c8fde9a37a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 16:29:30 +0200 Subject: [PATCH 0986/2595] target/i386/cpu: Use the IEC binary prefix definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IEC binary prefixes ease code review: the unit is explicit. Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200601142930.29408-9-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- target/i386/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ba05da3f2e..02065e35d4 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6159,7 +6159,7 @@ static void x86_cpu_machine_done(Notifier *n, void *unused) if (smram) { cpu->smram = g_new(MemoryRegion, 1); memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram", - smram, 0, 1ull << 32); + smram, 0, 4 * GiB); memory_region_set_enabled(cpu->smram, true); memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->smram, 1); } From c421f81826386687ace2066c81ef661e81a8d0a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 3 Jun 2020 14:37:52 +0200 Subject: [PATCH 0987/2595] target/unicore32: Remove unused headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200603123754.19059-2-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- target/unicore32/helper.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/target/unicore32/helper.c b/target/unicore32/helper.c index 7d538e2144..53292ae311 100644 --- a/target/unicore32/helper.c +++ b/target/unicore32/helper.c @@ -12,9 +12,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/exec-all.h" -#include "exec/gdbstub.h" #include "exec/helper-proto.h" -#include "qemu/host-utils.h" #ifndef CONFIG_USER_ONLY #include "ui/console.h" #endif From 7a7b66323435c998c63797e33bb5403bc31e2570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 3 Jun 2020 14:37:53 +0200 Subject: [PATCH 0988/2595] target/unicore32: Replace DPRINTF() by qemu_log_mask(GUEST_ERROR) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace disabled DPRINTF() by qemu_log_mask(GUEST_ERROR). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200603123754.19059-3-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- target/unicore32/helper.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/target/unicore32/helper.c b/target/unicore32/helper.c index 53292ae311..00371a7da6 100644 --- a/target/unicore32/helper.c +++ b/target/unicore32/helper.c @@ -10,6 +10,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" @@ -106,8 +107,9 @@ void helper_cp0_set(CPUUniCore32State *env, uint32_t val, uint32_t creg, } return; unrecognized: - DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n", - creg, cop); + qemu_log_mask(LOG_GUEST_ERROR, + "Wrong register (%d) or wrong operation (%d) in cp0_set!\n", + creg, cop); } uint32_t helper_cp0_get(CPUUniCore32State *env, uint32_t creg, uint32_t cop) @@ -153,8 +155,9 @@ uint32_t helper_cp0_get(CPUUniCore32State *env, uint32_t creg, uint32_t cop) } break; } - DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n", - creg, cop); + qemu_log_mask(LOG_GUEST_ERROR, + "Wrong register (%d) or wrong operation (%d) in cp0_set!\n", + creg, cop); return 0; } From c7a856b42e403e2b86c8ed026a3cd31e0a04973d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 3 Jun 2020 14:37:54 +0200 Subject: [PATCH 0989/2595] target/unicore32: Prefer qemu_semihosting_log_out() over curses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the common API for semihosting logging. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200603123754.19059-4-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- default-configs/unicore32-softmmu.mak | 1 + target/unicore32/helper.c | 57 +++------------------------ 2 files changed, 6 insertions(+), 52 deletions(-) diff --git a/default-configs/unicore32-softmmu.mak b/default-configs/unicore32-softmmu.mak index 0bfce48c6d..899288e3d7 100644 --- a/default-configs/unicore32-softmmu.mak +++ b/default-configs/unicore32-softmmu.mak @@ -3,3 +3,4 @@ # Boards: # CONFIG_PUV3=y +CONFIG_SEMIHOSTING=y diff --git a/target/unicore32/helper.c b/target/unicore32/helper.c index 00371a7da6..54c26871fe 100644 --- a/target/unicore32/helper.c +++ b/target/unicore32/helper.c @@ -14,9 +14,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" -#ifndef CONFIG_USER_ONLY -#include "ui/console.h" -#endif +#include "hw/semihosting/console.h" #undef DEBUG_UC32 @@ -161,58 +159,13 @@ uint32_t helper_cp0_get(CPUUniCore32State *env, uint32_t creg, uint32_t cop) return 0; } -#ifdef CONFIG_CURSES - -/* KEY_EVENT is defined in wincon.h and in curses.h. Avoid redefinition. */ -#undef KEY_EVENT -#include -#undef KEY_EVENT - -/* - * FIXME: - * 1. curses windows will be blank when switching back - * 2. backspace is not handled yet - */ -static void putc_on_screen(unsigned char ch) +void helper_cp1_putc(target_ulong regval) { - static WINDOW *localwin; - static int init; + const char c = regval; - if (!init) { - /* Assume 80 * 30 screen to minimize the implementation */ - localwin = newwin(30, 80, 0, 0); - scrollok(localwin, TRUE); - init = TRUE; - } - - if (isprint(ch)) { - wprintw(localwin, "%c", ch); - } else { - switch (ch) { - case '\n': - wprintw(localwin, "%c", ch); - break; - case '\r': - /* If '\r' is put before '\n', the curses window will destroy the - * last print line. And meanwhile, '\n' implifies '\r' inside. */ - break; - default: /* Not handled, so just print it hex code */ - wprintw(localwin, "-- 0x%x --", ch); - } - } - - wrefresh(localwin); + qemu_semihosting_log_out(&c, sizeof(c)); } -#else -#define putc_on_screen(c) do { } while (0) -#endif - -void helper_cp1_putc(target_ulong x) -{ - putc_on_screen((unsigned char)x); /* Output to screen */ - DPRINTF("%c", x); /* Output to stdout */ -} -#endif +#endif /* !CONFIG_USER_ONLY */ bool uc32_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { From 266345a867c290d6664c008b3bb3945395eca821 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 9 Jun 2020 14:54:05 +0200 Subject: [PATCH 0990/2595] test/tpm-emu: include sockets and channel headers in tpm-emu header Include sockets and channel headers to that the header is self-contained. Signed-off-by: Eric Auger Reviewed-by: Stefan Berger Message-Id: <20200609125409.24179-2-eric.auger@redhat.com> --- tests/qtest/tpm-emu.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/qtest/tpm-emu.h b/tests/qtest/tpm-emu.h index a4f1d64226..73f3bed0c4 100644 --- a/tests/qtest/tpm-emu.h +++ b/tests/qtest/tpm-emu.h @@ -16,6 +16,9 @@ #define TPM_RC_FAILURE 0x101 #define TPM2_ST_NO_SESSIONS 0x8001 +#include "qemu/sockets.h" +#include "io/channel.h" + struct tpm_hdr { uint16_t tag; uint32_t len; From 6d6d1a23fc2ed42ab6ac76e289000474def8ff0c Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 9 Jun 2020 14:54:06 +0200 Subject: [PATCH 0991/2595] tests/acpi: Add void tables for Q35/TPM-TIS bios-tables-test Add placeholders for TPM and DSDT reference tables for Q35 TPM-TIS tests and ignore them for the time being. Signed-off-by: Eric Auger Reviewed-by: Stefan Berger Reviewed-by: Igor Mammedov Message-Id: <20200609125409.24179-3-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/q35/DSDT.tis | 0 tests/data/acpi/q35/TPM2.tis | 0 tests/qtest/bios-tables-test-allowed-diff.h | 2 ++ 3 files changed, 2 insertions(+) create mode 100644 tests/data/acpi/q35/DSDT.tis create mode 100644 tests/data/acpi/q35/TPM2.tis diff --git a/tests/data/acpi/q35/DSDT.tis b/tests/data/acpi/q35/DSDT.tis new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/acpi/q35/TPM2.tis b/tests/data/acpi/q35/TPM2.tis new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..a2a45d1d31 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,3 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/q35/DSDT.tis", +"tests/data/acpi/q35/TPM2.tis", From c7504b9f32f2ee6ddcb2b0d69219046b3fa48c2d Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 9 Jun 2020 14:54:07 +0200 Subject: [PATCH 0992/2595] tests: tpm-emu: Remove assert on TPM2_ST_NO_SESSIONS bios-tables-test executes SeaBIOS. Indeed FW is needed to fetch tables from QEMU and put them into the guest RAM. Also the FW patches cross table pointers. At some point, SeaBIOS ends up calling the TPM2_CC_HierarchyControl command with TPM2_ST_SESSIONS tag, most probably steming from tpm_set_failure/tpm20_hierarchycontrol SeaBIOS call path. This causes an assert() in the qtest tpm emulation code. As the goal here is not to boot SeaBIOS completely but just let it grab the ACPI tables and consolidate them, let's just remove the assert(). Signed-off-by: Eric Auger Message-Id: <20200609125409.24179-4-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/tpm-emu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/qtest/tpm-emu.c b/tests/qtest/tpm-emu.c index c43ac4aef8..298d0eec74 100644 --- a/tests/qtest/tpm-emu.c +++ b/tests/qtest/tpm-emu.c @@ -49,7 +49,6 @@ static void *tpm_emu_tpm_thread(void *data) s->tpm_msg->tag = be16_to_cpu(s->tpm_msg->tag); s->tpm_msg->len = be32_to_cpu(s->tpm_msg->len); g_assert_cmpint(s->tpm_msg->len, >=, minhlen); - g_assert_cmpint(s->tpm_msg->tag, ==, TPM2_ST_NO_SESSIONS); s->tpm_msg = g_realloc(s->tpm_msg, s->tpm_msg->len); qio_channel_read(ioc, (char *)&s->tpm_msg->code, From 5da7c35e25a4cba351602774e30cb59173af3c73 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 9 Jun 2020 14:54:08 +0200 Subject: [PATCH 0993/2595] bios-tables-test: Add Q35/TPM-TIS test Test tables specific to the TPM-TIS instantiation. The TPM2 is added in the framework. Also the DSDT is updated with the TPM. The new function should be be usable for CRB as well, later one. Signed-off-by: Eric Auger Message-Id: <20200609125409.24179-5-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/Makefile.include | 1 + tests/qtest/bios-tables-test.c | 58 ++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/tests/qtest/Makefile.include b/tests/qtest/Makefile.include index 9e5a51d033..5023fa413d 100644 --- a/tests/qtest/Makefile.include +++ b/tests/qtest/Makefile.include @@ -262,6 +262,7 @@ tests/qtest/hd-geo-test$(EXESUF): tests/qtest/hd-geo-test.o $(libqos-obj-y) tests/qtest/boot-order-test$(EXESUF): tests/qtest/boot-order-test.o $(libqos-obj-y) tests/qtest/boot-serial-test$(EXESUF): tests/qtest/boot-serial-test.o $(libqos-obj-y) tests/qtest/bios-tables-test$(EXESUF): tests/qtest/bios-tables-test.o \ + tests/qtest/tpm-emu.o $(test-io-obj-y) \ tests/qtest/boot-sector.o tests/qtest/acpi-utils.o $(libqos-obj-y) tests/qtest/pxe-test$(EXESUF): tests/qtest/pxe-test.o tests/qtest/boot-sector.o $(libqos-obj-y) tests/qtest/microbit-test$(EXESUF): tests/qtest/microbit-test.o diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index c9843829b3..53f104a9c5 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -57,6 +57,9 @@ #include "qemu/bitmap.h" #include "acpi-utils.h" #include "boot-sector.h" +#include "tpm-emu.h" +#include "hw/acpi/tpm.h" + #define MACHINE_PC "pc" #define MACHINE_Q35 "q35" @@ -874,6 +877,60 @@ static void test_acpi_piix4_tcg_numamem(void) free_test_data(&data); } +uint64_t tpm_tis_base_addr; + +static void test_acpi_tcg_tpm(const char *machine, const char *tpm_if, + uint64_t base) +{ + gchar *tmp_dir_name = g_strdup_printf("qemu-test_acpi_%s_tcg_%s.XXXXXX", + machine, tpm_if); + char *tmp_path = g_dir_make_tmp(tmp_dir_name, NULL); + TestState test; + test_data data; + GThread *thread; + char *args, *variant = g_strdup_printf(".%s", tpm_if); + + tpm_tis_base_addr = base; + + module_call_init(MODULE_INIT_QOM); + + test.addr = g_new0(SocketAddress, 1); + test.addr->type = SOCKET_ADDRESS_TYPE_UNIX; + test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL); + g_mutex_init(&test.data_mutex); + g_cond_init(&test.data_cond); + test.data_cond_signal = false; + + thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test); + tpm_emu_test_wait_cond(&test); + + memset(&data, 0, sizeof(data)); + data.machine = machine; + data.variant = variant; + + args = g_strdup_printf( + " -chardev socket,id=chr,path=%s" + " -tpmdev emulator,id=dev,chardev=chr" + " -device tpm-%s,tpmdev=dev", + test.addr->u.q_unix.path, tpm_if); + + test_acpi_one(args, &data); + + g_thread_join(thread); + g_unlink(test.addr->u.q_unix.path); + qapi_free_SocketAddress(test.addr); + g_rmdir(tmp_path); + g_free(variant); + g_free(tmp_path); + g_free(tmp_dir_name); + free_test_data(&data); +} + +static void test_acpi_q35_tcg_tpm_tis(void) +{ + test_acpi_tcg_tpm("q35", "tis", 0xFED40000); +} + static void test_acpi_tcg_dimm_pxm(const char *machine) { test_data data; @@ -1037,6 +1094,7 @@ int main(int argc, char *argv[]) return ret; } + qtest_add_func("acpi/q35/tpm-tis", test_acpi_q35_tcg_tpm_tis); qtest_add_func("acpi/piix4", test_acpi_piix4_tcg); qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge); qtest_add_func("acpi/q35", test_acpi_q35_tcg); From cae98d8c86b7c76eae1c389ff7b9bd98143f656d Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 9 Jun 2020 14:54:09 +0200 Subject: [PATCH 0994/2595] bios-tables-test: Generate reference tables for Q35/TPM-TIS TPM2, DSDT tables were generated using tests/data/acpi/rebuild-expected-aml.sh Signed-off-by: Eric Auger Reviewed-by: Stefan Berger Message-Id: <20200609125409.24179-6-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/q35/DSDT.tis | Bin 0 -> 8357 bytes tests/data/acpi/q35/TPM2.tis | Bin 0 -> 76 bytes tests/qtest/bios-tables-test-allowed-diff.h | 2 -- 3 files changed, 2 deletions(-) diff --git a/tests/data/acpi/q35/DSDT.tis b/tests/data/acpi/q35/DSDT.tis index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..56b6fb0c3298517d080e38fea05a748b9f1dba54 100644 GIT binary patch literal 8357 zcmb7JON=AM8Lskc+U@pC+vC|cthEqD1O%QLASe+DcDG-d@l21~y9B(Edp3~F?nc4_ zR)VaMW(JAJN{IpnluINpa-v+KTyhV}IR_3affVJCYouHfMXYjI=liQ%yH&PFVtr`$ zU;TamUtjg(>#p)czw_H7WBd=5ZLbj)D?bc8A8nj5M*H;dHWL?Fci*qndpr|M@a{oI z>|;~03Xl1f^L75~z37uDdi~vq@AlcHPu-6%?e^b(FS^7CbnQ~#wrR)RuzO*p*FE&? zz-yMQUZd$d<UnZ6ZuQE3n_0c{O`jJw7kb;Fm$-42dH(aO!>#0CFSl&F-PYgM zzdC#7xlf*dz5Lm;U;O08RXYK|8vZT(ulH#aU61Uu(a`;HaGAeFba8BTxcuQj9F}b^ z9qC8Za?_DblxlT!)ood_uT`rNR6DA#96dzeFdmJd(_#)|pWn%_MEAg@c=p`9Df!3Z3Z1bCQ#LweMqPkpsLI(SGTxV!DchS#@$$YBCaY@weI1Q8x`Ma#8WrJne$#cvl)Ec_As&XeL z=ik7(cDBynh`$lHtaJM!^BNT0m1{6GAn3$HCAwX_~-pSirinmz-csG@1Nqz4ceU`zwz3BK9j(SWSd(XRVMd2_G>Kf zP`e#NP**`5L4)P931>XUeI;>|h*$tF%432Ds0xXR`~n*jOkgJwF%>k%1QSrfL`Y2Z zMquNDsd_+{g2*bMamfT!g~U`O4YSXVTD_6ifw8N~Y>OLS1Ld z(3uiU1x=Yc5$ZY@44n&x&IMB^LS3h2=(G%-mZ=k=t`j$_HqvQBXWG<>P}gZ2I&DLz zZR$j*>&zHBGltHLsS}~D6AumTd^(0s$JB{X*O@hRW(}QLQzt@Q=c1u=(a^bQ>O`pP zTrzYn89J9tod|WEuA$R4bh@Tagu2e0p)+Ub%$Yh7>N@j=&b*;BZ|X#->s&T;E*mu}HkhYP zCPJNg#$cW?m}g8TLY?`5!F<4AK43Bt>dXfPQ@PB8f~lVI4@#zba3dt9a+0$~&9g?$ zvt~_%vZe(CEo%l^51V%l6#FPVF;E03D}y)!RTKs)al(=~;}WPGGbW)bB&L!E1C>~1 zpc<46R6+%l3=|=HqYPAHClS?DUP}flp?3`wA-XQGFi?q|M8s5sO9m>Tf=LF7Q0at$ zN~~bQKs6{CsDuh887M-f69y`=f(ZlFpk$yDDwt%T2$fD4sKg2;3{-=Xfl8=gl7S*r zI$@v^E0{1)4N3+op@K;Uicsl$|V8TE(C>f}P z3MLsSLZuT1DzSnI1J$5ppb{#WWS|I@P8g`f3MLFxgOY(ts9=(TB2+qIpb{&XFi;Ij z1}dR~Nd}5g>4bqwtYE@GH7FUVgbF4ZC_<$Z1}d?F2?N!jWS|l%m}H;`l};F_#0n-1 zRD+U%N~mCxfg)5oVW1K#m@rTcN(L&Sf=LF7Q0at$N~~bQKs6{CsDuh887M-f69y`= zf(ZlFpk$yDDwt%T2$fD4sKg2;3{-=Xfl8=gl7S*rI$@v^E0{1)4N3+op@K;Uicsl< zfg;ij6p?PA2z3KRs2Qlngn?>IGEj|42C6Y(pc)efsxiqxH6|IT#)N@tOco$ zWS|-o2C6Y(pc<15RAZ8XYD^d?B6W6QponnB#9)$vBE)G>Au-k1!axzJv4w#mQe#U7 zicpO$87M-Z6;AbFp={_3#K-E0K1gq-=&#&8_|6k?`bwqGcA6OAL3^hR$K9#W#-ojI zF-%kJRB69Pn>uY8R$;lh6L$D8ecj&Q!+b<~WM>LbHg~*s8h~~ww`gbHPq8%33*m$M z2DRBqY@7Y-d-f8eJ#?atNs7${yd#v=H@$urnaMwuq1S!gk1S>`nSW<*9vAy)soDa|BV5!EZ`pI*IEm|wlpJ#3M7Z>qW-yN~joR^Aiky{Yov5#_x}d4IY*W^BH;dS5H= zi}LORWXweodQzCKmHenk2DqdZ)oKkqI_ejeB+4n4U|vNqinjoE6b~g z2VN_1yUWQpv#pR4w>F}mAlTNmo>D<%W?D$gHs$gva>j+L9ljH6tX5!_d!^L}3+CjS-s;kt- z%?WSHdcpZ(1Gt`vuJo~Fnxe}-?x{d?l)(SY;KIALMus%?ynG^PK69}^A{S6 zUg&LEN6FyPr{&Bb;^=yxO((?&59^5;LE=ncxTfJ4eBPhw8PI(m-P}kF8?&jz`JA81 zj?d--9J%HTZKb{Ku;Uyhbnf|@=`0lYFVE4{w`0?-1idodh#{EUyYAc1&{c(-4?kR> zxU#GfU0=8cTjfqJV_OWL`t%Z5Si}-tCqrV`-sLNW)3|)=LA6&ct>FZT6(qWp>8!d1 zIwEem$wggynz^l@A@%svgZ##G6 zELLF{`_H?0I>_VnVmThuizWSHOdJuftq860c>G6kfU(~jM?M>m|9nRt`Rsc)9=(@M zwow9b$53zlD8`B%4&S=N0(xj+l`a9fa*;C|Yz3t<&$r(99os8h_|*cT(AmjouIar9;QG1cn|YBBRr~caFxC4u;A96 zJvKqFa-VsD7*UjIvYMVxMIh!0)Ca@Nkx5$c5(Rnu8q015${Ln{!SnA z+AS;se;?rZa0Lt1eQJM?dcqlc)mj@qG`NgJs(GC=+HVnL9hU%M)`u4OiIE)x_==tE z)7S`r1P8O=)Cl#eNuU>w>?6J`MR)BOfnDmH)@$l5`XyT+lPfJJk<>DijzpeOF3#ET qDLIV)>O|jO{_C~cug=sjeDUvFKN_aRFvfX&xQszm{D@BGi2Wba Date: Wed, 20 May 2020 12:04:37 +0200 Subject: [PATCH 0995/2595] virtio-balloon: fix free page hinting without an iothread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case we don't have an iothread, we mark the feature as abscent but still add the queue. 'free_page_bh' remains set to NULL. qemu-system-i386 \ -M microvm \ -nographic \ -device virtio-balloon-device,free-page-hint=true \ -nographic \ -display none \ -monitor none \ -serial none \ -qtest stdio Doing a "write 0xc0000e30 0x24 0x030000000300000003000000030000000300000003000000030000000300000003000000" We will trigger a SEGFAULT. Let's move the check and bail out. While at it, move the static initializations to instance_init(). free_page_report_status and block_iothread are implicitly set to the right values (0/false) already, so drop the initialization. Reviewed-by: Alexander Duyck Reviewed-by: Philippe Mathieu-Daudé Fixes: c13c4153f76d ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT") Reported-by: Alexander Bulekov Cc: qemu-stable@nongnu.org Cc: Wei Wang Cc: Michael S. Tsirkin Cc: Philippe Mathieu-Daudé Cc: Alexander Duyck Signed-off-by: David Hildenbrand Message-Id: <20200520100439.19872-2-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 065cd450f1..7ff6a7aa7c 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -789,6 +789,13 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) return; } + if (virtio_has_feature(s->host_features, VIRTIO_BALLOON_F_FREE_PAGE_HINT) && + !s->iothread) { + error_setg(errp, "'free-page-hint' requires 'iothread' to be set"); + virtio_cleanup(vdev); + return; + } + s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output); s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output); s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats); @@ -797,24 +804,11 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) VIRTIO_BALLOON_F_FREE_PAGE_HINT)) { s->free_page_vq = virtio_add_queue(vdev, VIRTQUEUE_MAX_SIZE, virtio_balloon_handle_free_page_vq); - s->free_page_report_status = FREE_PAGE_REPORT_S_STOP; - s->free_page_report_cmd_id = - VIRTIO_BALLOON_FREE_PAGE_REPORT_CMD_ID_MIN; - s->free_page_report_notify.notify = - virtio_balloon_free_page_report_notify; precopy_add_notifier(&s->free_page_report_notify); - if (s->iothread) { - object_ref(OBJECT(s->iothread)); - s->free_page_bh = aio_bh_new(iothread_get_aio_context(s->iothread), - virtio_ballloon_get_free_page_hints, s); - qemu_mutex_init(&s->free_page_lock); - qemu_cond_init(&s->free_page_cond); - s->block_iothread = false; - } else { - /* Simply disable this feature if the iothread wasn't created. */ - s->host_features &= ~(1 << VIRTIO_BALLOON_F_FREE_PAGE_HINT); - virtio_error(vdev, "iothread is missing"); - } + + object_ref(OBJECT(s->iothread)); + s->free_page_bh = aio_bh_new(iothread_get_aio_context(s->iothread), + virtio_ballloon_get_free_page_hints, s); } reset_stats(s); } @@ -892,6 +886,11 @@ static void virtio_balloon_instance_init(Object *obj) { VirtIOBalloon *s = VIRTIO_BALLOON(obj); + qemu_mutex_init(&s->free_page_lock); + qemu_cond_init(&s->free_page_cond); + s->free_page_report_cmd_id = VIRTIO_BALLOON_FREE_PAGE_REPORT_CMD_ID_MIN; + s->free_page_report_notify.notify = virtio_balloon_free_page_report_notify; + object_property_add(obj, "guest-stats", "guest statistics", balloon_stats_get_all, NULL, NULL, s); From 49b01711b8eb3796c6904c7f85d2431572cfe54f Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 20 May 2020 12:04:38 +0200 Subject: [PATCH 0996/2595] virtio-balloon: fix free page hinting check on unrealize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Checking against guest features is wrong. We allocated data structures based on host features. We can rely on "free_page_bh" as an indicator whether to un-do stuff instead. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alexander Duyck Fixes: c13c4153f76d ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT") Cc: qemu-stable@nongnu.org Cc: Wei Wang Cc: Michael S. Tsirkin Cc: Philippe Mathieu-Daudé Cc: Alexander Duyck Signed-off-by: David Hildenbrand Message-Id: <20200520100439.19872-3-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 7ff6a7aa7c..32e9fe3f64 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -818,7 +818,7 @@ static void virtio_balloon_device_unrealize(DeviceState *dev) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBalloon *s = VIRTIO_BALLOON(dev); - if (virtio_balloon_free_page_support(s)) { + if (s->free_page_bh) { qemu_bh_delete(s->free_page_bh); virtio_balloon_free_page_stop(s); precopy_remove_notifier(&s->free_page_report_notify); From 105aef9c9479786d27c1c45c9b0b1fa03dc46be3 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 20 May 2020 12:04:39 +0200 Subject: [PATCH 0997/2595] virtio-balloon: unref the iothread when unrealizing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We took a reference when realizing, so let's drop that reference when unrealizing. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alexander Duyck Fixes: c13c4153f76d ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT") Cc: qemu-stable@nongnu.org Cc: Wei Wang Cc: Alexander Duyck Cc: Michael S. Tsirkin Cc: Philippe Mathieu-Daudé Signed-off-by: David Hildenbrand Message-Id: <20200520100439.19872-4-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 32e9fe3f64..cff8eab6a1 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -820,6 +820,7 @@ static void virtio_balloon_device_unrealize(DeviceState *dev) if (s->free_page_bh) { qemu_bh_delete(s->free_page_bh); + object_unref(OBJECT(s->iothread)); virtio_balloon_free_page_stop(s); precopy_remove_notifier(&s->free_page_report_notify); } From 7483cbbaf8204de330b7362339a4a070b114b425 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 26 May 2020 21:14:00 -0700 Subject: [PATCH 0998/2595] virtio-balloon: Implement support for page poison reporting feature We need to make certain to advertise support for page poison reporting if we want to actually get data on if the guest will be poisoning pages. Add a value for reporting the poison value being used if page poisoning is enabled in the guest. With this we can determine if we will need to skip free page reporting when it is enabled in the future. The value currently has no impact on existing balloon interfaces. In the case of existing balloon interfaces the onus is on the guest driver to reapply whatever poison is in place. When we add free page reporting the poison value is used to determine if we can perform in-place page reporting. The expectation is that a reported page will already contain the value specified by the poison, and the reporting of the page should not change that value. Acked-by: David Hildenbrand Signed-off-by: Alexander Duyck Message-Id: <20200527041400.12700.33251.stgit@localhost.localdomain> --- hw/core/machine.c | 4 +++- hw/virtio/virtio-balloon.c | 29 +++++++++++++++++++++++++++++ include/hw/virtio/virtio-balloon.h | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index bb3a7b18b1..9eca7d8c9b 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -28,7 +28,9 @@ #include "hw/mem/nvdimm.h" #include "migration/vmstate.h" -GlobalProperty hw_compat_5_0[] = {}; +GlobalProperty hw_compat_5_0[] = { + { "virtio-balloon-device", "page-poison", "false" }, +}; const size_t hw_compat_5_0_len = G_N_ELEMENTS(hw_compat_5_0); GlobalProperty hw_compat_4_2[] = { diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index cff8eab6a1..31d3c88482 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -634,6 +634,7 @@ static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data) config.num_pages = cpu_to_le32(dev->num_pages); config.actual = cpu_to_le32(dev->actual); + config.poison_val = cpu_to_le32(dev->poison_val); if (dev->free_page_report_status == FREE_PAGE_REPORT_S_REQUESTED) { config.free_page_report_cmd_id = @@ -683,6 +684,14 @@ static ram_addr_t get_current_ram_size(void) return size; } +static bool virtio_balloon_page_poison_support(void *opaque) +{ + VirtIOBalloon *s = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(s); + + return virtio_vdev_has_feature(vdev, VIRTIO_BALLOON_F_PAGE_POISON); +} + static void virtio_balloon_set_config(VirtIODevice *vdev, const uint8_t *config_data) { @@ -697,6 +706,10 @@ static void virtio_balloon_set_config(VirtIODevice *vdev, qapi_event_send_balloon_change(vm_ram_size - ((ram_addr_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT)); } + dev->poison_val = 0; + if (virtio_balloon_page_poison_support(dev)) { + dev->poison_val = le32_to_cpu(config.poison_val); + } trace_virtio_balloon_set_config(dev->actual, oldactual); } @@ -755,6 +768,17 @@ static const VMStateDescription vmstate_virtio_balloon_free_page_report = { } }; +static const VMStateDescription vmstate_virtio_balloon_page_poison = { + .name = "vitio-balloon-device/page-poison", + .version_id = 1, + .minimum_version_id = 1, + .needed = virtio_balloon_page_poison_support, + .fields = (VMStateField[]) { + VMSTATE_UINT32(poison_val, VirtIOBalloon), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_virtio_balloon_device = { .name = "virtio-balloon-device", .version_id = 1, @@ -767,6 +791,7 @@ static const VMStateDescription vmstate_virtio_balloon_device = { }, .subsections = (const VMStateDescription * []) { &vmstate_virtio_balloon_free_page_report, + &vmstate_virtio_balloon_page_poison, NULL } }; @@ -849,6 +874,8 @@ static void virtio_balloon_device_reset(VirtIODevice *vdev) g_free(s->stats_vq_elem); s->stats_vq_elem = NULL; } + + s->poison_val = 0; } static void virtio_balloon_set_status(VirtIODevice *vdev, uint8_t status) @@ -916,6 +943,8 @@ static Property virtio_balloon_properties[] = { VIRTIO_BALLOON_F_DEFLATE_ON_OOM, false), DEFINE_PROP_BIT("free-page-hint", VirtIOBalloon, host_features, VIRTIO_BALLOON_F_FREE_PAGE_HINT, false), + DEFINE_PROP_BIT("page-poison", VirtIOBalloon, host_features, + VIRTIO_BALLOON_F_PAGE_POISON, true), /* QEMU 4.0 accidentally changed the config size even when free-page-hint * is disabled, resulting in QEMU 3.1 migration incompatibility. This * property retains this quirk for QEMU 4.1 machine types. diff --git a/include/hw/virtio/virtio-balloon.h b/include/hw/virtio/virtio-balloon.h index d1c968d237..7fe78e5c14 100644 --- a/include/hw/virtio/virtio-balloon.h +++ b/include/hw/virtio/virtio-balloon.h @@ -70,6 +70,7 @@ typedef struct VirtIOBalloon { uint32_t host_features; bool qemu_4_0_config_size; + uint32_t poison_val; } VirtIOBalloon; #endif From 91b867191ddf73c64f51ca2ddb489b922ed4058e Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 26 May 2020 21:14:07 -0700 Subject: [PATCH 0999/2595] virtio-balloon: Provide an interface for free page reporting Add support for free page reporting. The idea is to function very similar to how the balloon works in that we basically end up madvising the page as not being used. However we don't really need to bother with any deflate type logic since the page will be faulted back into the guest when it is read or written to. This provides a new way of letting the guest proactively report free pages to the hypervisor, so the hypervisor can reuse them. In contrast to inflate/deflate that is triggered via the hypervisor explicitly. Acked-by: David Hildenbrand Signed-off-by: Alexander Duyck Message-Id: <20200527041407.12700.73735.stgit@localhost.localdomain> --- hw/virtio/virtio-balloon.c | 72 ++++++++++++++++++++++++++++++ include/hw/virtio/virtio-balloon.h | 2 +- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 31d3c88482..10507b2a43 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -321,6 +321,67 @@ static void balloon_stats_set_poll_interval(Object *obj, Visitor *v, balloon_stats_change_timer(s, 0); } +static void virtio_balloon_handle_report(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOBalloon *dev = VIRTIO_BALLOON(vdev); + VirtQueueElement *elem; + + while ((elem = virtqueue_pop(vq, sizeof(VirtQueueElement)))) { + unsigned int i; + + /* + * When we discard the page it has the effect of removing the page + * from the hypervisor itself and causing it to be zeroed when it + * is returned to us. So we must not discard the page if it is + * accessible by another device or process, or if the guest is + * expecting it to retain a non-zero value. + */ + if (qemu_balloon_is_inhibited() || dev->poison_val) { + goto skip_element; + } + + for (i = 0; i < elem->in_num; i++) { + void *addr = elem->in_sg[i].iov_base; + size_t size = elem->in_sg[i].iov_len; + ram_addr_t ram_offset; + RAMBlock *rb; + + /* + * There is no need to check the memory section to see if + * it is ram/readonly/romd like there is for handle_output + * below. If the region is not meant to be written to then + * address_space_map will have allocated a bounce buffer + * and it will be freed in address_space_unmap and trigger + * and unassigned_mem_write before failing to copy over the + * buffer. If more than one bad descriptor is provided it + * will return NULL after the first bounce buffer and fail + * to map any resources. + */ + rb = qemu_ram_block_from_host(addr, false, &ram_offset); + if (!rb) { + trace_virtio_balloon_bad_addr(elem->in_addr[i]); + continue; + } + + /* + * For now we will simply ignore unaligned memory regions, or + * regions that overrun the end of the RAMBlock. + */ + if (!QEMU_IS_ALIGNED(ram_offset | size, qemu_ram_pagesize(rb)) || + (ram_offset + size) > qemu_ram_get_used_length(rb)) { + continue; + } + + ram_block_discard_range(rb, ram_offset, size); + } + +skip_element: + virtqueue_push(vq, elem, 0); + virtio_notify(vdev, vq); + g_free(elem); + } +} + static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) { VirtIOBalloon *s = VIRTIO_BALLOON(vdev); @@ -835,6 +896,12 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) s->free_page_bh = aio_bh_new(iothread_get_aio_context(s->iothread), virtio_ballloon_get_free_page_hints, s); } + + if (virtio_has_feature(s->host_features, VIRTIO_BALLOON_F_REPORTING)) { + s->reporting_vq = virtio_add_queue(vdev, 32, + virtio_balloon_handle_report); + } + reset_stats(s); } @@ -858,6 +925,9 @@ static void virtio_balloon_device_unrealize(DeviceState *dev) if (s->free_page_vq) { virtio_delete_queue(s->free_page_vq); } + if (s->reporting_vq) { + virtio_delete_queue(s->reporting_vq); + } virtio_cleanup(vdev); } @@ -945,6 +1015,8 @@ static Property virtio_balloon_properties[] = { VIRTIO_BALLOON_F_FREE_PAGE_HINT, false), DEFINE_PROP_BIT("page-poison", VirtIOBalloon, host_features, VIRTIO_BALLOON_F_PAGE_POISON, true), + DEFINE_PROP_BIT("free-page-reporting", VirtIOBalloon, host_features, + VIRTIO_BALLOON_F_REPORTING, false), /* QEMU 4.0 accidentally changed the config size even when free-page-hint * is disabled, resulting in QEMU 3.1 migration incompatibility. This * property retains this quirk for QEMU 4.1 machine types. diff --git a/include/hw/virtio/virtio-balloon.h b/include/hw/virtio/virtio-balloon.h index 7fe78e5c14..d49fef00ce 100644 --- a/include/hw/virtio/virtio-balloon.h +++ b/include/hw/virtio/virtio-balloon.h @@ -42,7 +42,7 @@ enum virtio_balloon_free_page_report_status { typedef struct VirtIOBalloon { VirtIODevice parent_obj; - VirtQueue *ivq, *dvq, *svq, *free_page_vq; + VirtQueue *ivq, *dvq, *svq, *free_page_vq, *reporting_vq; uint32_t free_page_report_status; uint32_t num_pages; uint32_t actual; From b963ea19f896e34e21275ff69fa4565948f703c8 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Sun, 7 Jun 2020 07:20:22 +0200 Subject: [PATCH 1000/2595] MAINTAINERS: Fix the classification of bios-tables-test-allowed-diff.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The file tests/qtest/bios-tables-test-allowed-diff.h is currently only assigned to the qtest section according MAINTAINERS. However, this file normally only gets updated when the ACPI tables changed - something the qtest maintainers don't have much clue of. Thus this file should rather be assigned to the ACPI maintainers instead. Signed-off-by: Thomas Huth Message-Id: <20200607052022.12222-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 6e7890ce82..0c5ed09ad5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1531,7 +1531,7 @@ F: hw/acpi/* F: hw/smbios/* F: hw/i386/acpi-build.[hc] F: hw/arm/virt-acpi-build.c -F: tests/qtest/bios-tables-test.c +F: tests/qtest/bios-tables-test* F: tests/qtest/acpi-utils.[hc] F: tests/data/acpi/ @@ -2321,6 +2321,7 @@ S: Maintained F: qtest.c F: accel/qtest.c F: tests/qtest/ +X: tests/qtest/bios-tables-test-allowed-diff.h Device Fuzzing M: Alexander Bulekov From 0dabc0f6544f2c0310546f6d6cf3b68979580a9c Mon Sep 17 00:00:00 2001 From: Julia Suvorova Date: Thu, 4 Jun 2020 14:59:46 +0200 Subject: [PATCH 1001/2595] hw/pci/pcie: Move hot plug capability check to pre_plug callback Check for hot plug capability earlier to avoid removing devices attached during the initialization process. Run qemu with an unattached drive: -drive file=$FILE,if=none,id=drive0 \ -device pcie-root-port,id=rp0,slot=3,bus=pcie.0,hotplug=off Hotplug a block device: device_add virtio-blk-pci,id=blk0,drive=drive0,bus=rp0 If hotplug fails on plug_cb, drive0 will be deleted. Fixes: 0501e1aa1d32a6 ("hw/pci/pcie: Forbid hot-plug if it's disabled on the slot") Acked-by: Igor Mammedov Signed-off-by: Julia Suvorova Message-Id: <20200604125947.881210-1-jusual@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index f50e10b8fb..5b9c022d91 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -407,6 +407,17 @@ static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev, void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { + PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev); + uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap; + uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP); + + /* Check if hot-plug is disabled on the slot */ + if (dev->hotplugged && (sltcap & PCI_EXP_SLTCAP_HPC) == 0) { + error_setg(errp, "Hot-plug failed: unsupported by the port device '%s'", + DEVICE(hotplug_pdev)->id); + return; + } + pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, errp); } @@ -415,7 +426,6 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, { PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev); uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap; - uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP); PCIDevice *pci_dev = PCI_DEVICE(dev); /* Don't send event when device is enabled during qemu machine creation: @@ -431,13 +441,6 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, return; } - /* Check if hot-plug is disabled on the slot */ - if ((sltcap & PCI_EXP_SLTCAP_HPC) == 0) { - error_setg(errp, "Hot-plug failed: unsupported by the port device '%s'", - DEVICE(hotplug_pdev)->id); - return; - } - /* To enable multifunction hot-plug, we just ensure the function * 0 added last. When function 0 is added, we set the sltsta and * inform OS via event notification. From f7d6a635fa3b7797f9d072e280f065bf3cfcd24d Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Thu, 4 Jun 2020 17:05:25 +0530 Subject: [PATCH 1002/2595] pci: assert configuration access is within bounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While accessing PCI configuration bytes, assert that 'address + len' is within PCI configuration space. Generally it is within bounds. This is more of a defensive assert, in case a buggy device was to send 'address' which may go out of bounds. Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Prasad J Pandit Message-Id: <20200604113525.58898-1-ppandit@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 70c66965f5..7bf2ae6d92 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1381,6 +1381,8 @@ uint32_t pci_default_read_config(PCIDevice *d, { uint32_t val = 0; + assert(address + len <= pci_config_size(d)); + if (pci_is_express_downstream_port(d) && ranges_overlap(address, len, d->exp.exp_cap + PCI_EXP_LNKSTA, 2)) { pcie_sync_bridge_lnk(d); @@ -1394,6 +1396,8 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int int i, was_irq_disabled = pci_irq_disabled(d); uint32_t val = val_in; + assert(addr + l <= pci_config_size(d)); + for (i = 0; i < l; val >>= 8, ++i) { uint8_t wmask = d->wmask[addr + i]; uint8_t w1cmask = d->w1cmask[addr + i]; From ea2fe4dfe4e5d32e69ae749a3b9f287aaf8b898e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 16:29:24 +0200 Subject: [PATCH 1003/2595] hw/pci-host/prep: Correct RAVEN bus bridge memory region size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit memory_region_set_size() handle the 16 Exabytes limit by special-casing the UINT64_MAX value. This is not a problem for the 32-bit maximum, 4 GiB. By using the UINT32_MAX value, the bm-raven MemoryRegion ends up missing 1 byte: $ qemu-system-ppc -M prep -S -monitor stdio -usb memory-region: bm-raven 0000000000000000-00000000fffffffe (prio 0, i/o): bm-raven 0000000000000000-000000003effffff (prio 0, i/o): alias bm-pci-memory @pci-memory 0000000000000000-000000003effffff 0000000080000000-00000000ffffffff (prio 0, i/o): alias bm-system @system 0000000000000000-000000007fffffff Fix by using the correct value. We now have: memory-region: bm-raven 0000000000000000-00000000ffffffff (prio 0, i/o): bm-raven 0000000000000000-000000003effffff (prio 0, i/o): alias bm-pci-memory @pci-memory 0000000000000000-000000003effffff 0000000080000000-00000000ffffffff (prio 0, i/o): alias bm-system @system 0000000000000000-000000007fffffff Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200601142930.29408-3-f4bug@amsat.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Richard Henderson --- hw/pci-host/prep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c index 1a02e9a670..88e2fc66a9 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -294,7 +294,7 @@ static void raven_pcihost_initfn(Object *obj) &s->pci_memory, &s->pci_io, 0, TYPE_PCI_BUS); /* Bus master address space */ - memory_region_init(&s->bm, obj, "bm-raven", UINT32_MAX); + memory_region_init(&s->bm, obj, "bm-raven", 4 * GiB); memory_region_init_alias(&s->bm_pci_memory_alias, obj, "bm-pci-memory", &s->pci_memory, 0, memory_region_size(&s->pci_memory)); From 2dc48da25547bf82dee81f4e60766509b28e736e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 16:29:25 +0200 Subject: [PATCH 1004/2595] hw/pci/pci_bridge: Correct pci_bridge_io memory region size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit memory_region_set_size() handle the 16 Exabytes limit by special-casing the UINT64_MAX value. This is not a problem for the 32-bit maximum, 4 GiB. By using the UINT32_MAX value, the pci_bridge_io MemoryRegion ends up missing 1 byte: (qemu) info mtree memory-region: pci_bridge_io 0000000000000000-00000000fffffffe (prio 0, i/o): pci_bridge_io 0000000000000060-0000000000000060 (prio 0, i/o): i8042-data 0000000000000064-0000000000000064 (prio 0, i/o): i8042-cmd 00000000000001ce-00000000000001d1 (prio 0, i/o): vbe 0000000000000378-000000000000037f (prio 0, i/o): parallel 00000000000003b4-00000000000003b5 (prio 0, i/o): vga ... Fix by using the correct value. We now have: memory-region: pci_bridge_io 0000000000000000-00000000ffffffff (prio 0, i/o): pci_bridge_io 0000000000000060-0000000000000060 (prio 0, i/o): i8042-data 0000000000000064-0000000000000064 (prio 0, i/o): i8042-cmd ... Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200601142930.29408-4-f4bug@amsat.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Richard Henderson --- hw/pci/pci_bridge.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 97967d12eb..3ba3203f72 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -30,6 +30,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_bus.h" #include "qemu/module.h" @@ -381,7 +382,7 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename) memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", UINT64_MAX); sec_bus->address_space_io = &br->address_space_io; memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io", - UINT32_MAX); + 4 * GiB); br->windows = pci_bridge_region_init(br); QLIST_INIT(&sec_bus->child); QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); From 37e7211cae59d090eafdf26fb2b21ca41df7aed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 16:29:26 +0200 Subject: [PATCH 1005/2595] hw/pci/pci_bridge: Use the IEC binary prefix definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IEC binary prefixes ease code review: the unit is explicit. Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200601142930.29408-5-f4bug@amsat.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Richard Henderson --- hw/pci/pci_bridge.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 3ba3203f72..3789c17edc 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -423,14 +423,14 @@ int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, } if (res_reserve.mem_non_pref != (uint64_t)-1 && - res_reserve.mem_non_pref >= (1ULL << 32)) { + res_reserve.mem_non_pref >= 4 * GiB) { error_setg(errp, "PCI resource reserve cap: mem-reserve must be less than 4G"); return -EINVAL; } if (res_reserve.mem_pref_32 != (uint64_t)-1 && - res_reserve.mem_pref_32 >= (1ULL << 32)) { + res_reserve.mem_pref_32 >= 4 * GiB) { error_setg(errp, "PCI resource reserve cap: pref32-reserve must be less than 4G"); return -EINVAL; From 51eae1e7e427ef9efc7c10c52b33575fe685add3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 16:29:27 +0200 Subject: [PATCH 1006/2595] hw/pci-host: Use the IEC binary prefix definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IEC binary prefixes ease code review: the unit is explicit. Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200601142930.29408-6-f4bug@amsat.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Richard Henderson --- hw/pci-host/i440fx.c | 3 ++- hw/pci-host/q35.c | 2 +- hw/pci-host/versatile.c | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c index 0adbd77553..aefb416c8f 100644 --- a/hw/pci-host/i440fx.c +++ b/hw/pci-host/i440fx.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qemu/range.h" #include "hw/i386/pc.h" #include "hw/pci/pci.h" @@ -301,7 +302,7 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, memory_region_set_enabled(&f->smram_region, true); /* smram, as seen by SMM CPUs */ - memory_region_init(&f->smram, OBJECT(d), "smram", 1ull << 32); + memory_region_init(&f->smram, OBJECT(d), "smram", 4 * GiB); memory_region_set_enabled(&f->smram, true); memory_region_init_alias(&f->low_smram, OBJECT(d), "smram-low", f->ram_memory, 0xa0000, 0x20000); diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 352aeecfa7..b788f17b2c 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -589,7 +589,7 @@ static void mch_realize(PCIDevice *d, Error **errp) memory_region_set_enabled(&mch->open_high_smram, false); /* smram, as seen by SMM CPUs */ - memory_region_init(&mch->smram, OBJECT(mch), "smram", 1ull << 32); + memory_region_init(&mch->smram, OBJECT(mch), "smram", 4 * GiB); memory_region_set_enabled(&mch->smram, true); memory_region_init_alias(&mch->low_smram, OBJECT(mch), "smram-low", mch->ram_memory, MCH_HOST_BRIDGE_SMRAM_C_BASE, diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c index cfb9a78ea6..8ddfb8772a 100644 --- a/hw/pci-host/versatile.c +++ b/hw/pci-host/versatile.c @@ -8,6 +8,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "hw/sysbus.h" #include "migration/vmstate.h" #include "hw/irq.h" @@ -399,8 +400,8 @@ static void pci_vpb_realize(DeviceState *dev, Error **errp) pci_map_irq_fn mapfn; int i; - memory_region_init(&s->pci_io_space, OBJECT(s), "pci_io", 1ULL << 32); - memory_region_init(&s->pci_mem_space, OBJECT(s), "pci_mem", 1ULL << 32); + memory_region_init(&s->pci_io_space, OBJECT(s), "pci_io", 4 * GiB); + memory_region_init(&s->pci_mem_space, OBJECT(s), "pci_mem", 4 * GiB); pci_root_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), dev, "pci", &s->pci_mem_space, &s->pci_io_space, From 271094474b65de1ad7aaf729938de3d9b9d0d36f Mon Sep 17 00:00:00 2001 From: Dima Stepanov Date: Thu, 28 May 2020 12:11:18 +0300 Subject: [PATCH 1007/2595] char-socket: return -1 in case of disconnect during tcp_chr_write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During testing of the vhost-user-blk reconnect functionality the qemu SIGSEGV was triggered: start qemu as: x86_64-softmmu/qemu-system-x86_64 -m 1024M -M q35 \ -object memory-backend-file,id=ram-node0,size=1024M,mem-path=/dev/shm/qemu,share=on \ -numa node,cpus=0,memdev=ram-node0 \ -chardev socket,id=chardev0,path=./vhost.sock,noserver,reconnect=1 \ -device vhost-user-blk-pci,chardev=chardev0,num-queues=4 --enable-kvm start vhost-user-blk daemon: ./vhost-user-blk -s ./vhost.sock -b test-img.raw If vhost-user-blk will be killed during the vhost initialization process, for instance after getting VHOST_SET_VRING_CALL command, then QEMU will fail with the following backtrace: Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault. 0x00005555559272bb in vhost_user_read (dev=0x7fffef2d53e0, msg=0x7fffffffd5b0) at ./hw/virtio/vhost-user.c:260 260 CharBackend *chr = u->user->chr; #0 0x00005555559272bb in vhost_user_read (dev=0x7fffef2d53e0, msg=0x7fffffffd5b0) at ./hw/virtio/vhost-user.c:260 #1 0x000055555592acb8 in vhost_user_get_config (dev=0x7fffef2d53e0, config=0x7fffef2d5394 "", config_len=60) at ./hw/virtio/vhost-user.c:1645 #2 0x0000555555925525 in vhost_dev_get_config (hdev=0x7fffef2d53e0, config=0x7fffef2d5394 "", config_len=60) at ./hw/virtio/vhost.c:1490 #3 0x00005555558cc46b in vhost_user_blk_device_realize (dev=0x7fffef2d51a0, errp=0x7fffffffd8f0) at ./hw/block/vhost-user-blk.c:429 #4 0x0000555555920090 in virtio_device_realize (dev=0x7fffef2d51a0, errp=0x7fffffffd948) at ./hw/virtio/virtio.c:3615 #5 0x0000555555a9779c in device_set_realized (obj=0x7fffef2d51a0, value=true, errp=0x7fffffffdb88) at ./hw/core/qdev.c:891 ... The problem is that vhost_user_write doesn't get an error after disconnect and try to call vhost_user_read(). The tcp_chr_write() routine should return -1 in case of disconnect. Indicate the EIO error if this routine is called in the disconnected state. Signed-off-by: Dima Stepanov Reviewed-by: Marc-André Lureau Message-Id: Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- chardev/char-socket.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index db253d4024..18e762643b 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -175,15 +175,16 @@ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len) if (ret < 0 && errno != EAGAIN) { if (tcp_chr_read_poll(chr) <= 0) { + /* Perform disconnect and return error. */ tcp_chr_disconnect_locked(chr); - return len; } /* else let the read handler finish it properly */ } return ret; } else { - /* XXX: indicate an error ? */ - return len; + /* Indicate an error. */ + errno = EIO; + return -1; } } From 4bcad76f4c390f798198a9a93fbaa1a20d06b73e Mon Sep 17 00:00:00 2001 From: Dima Stepanov Date: Thu, 28 May 2020 12:11:19 +0300 Subject: [PATCH 1008/2595] vhost-user-blk: delay vhost_user_blk_disconnect A socket write during vhost-user communication may trigger a disconnect event, calling vhost_user_blk_disconnect() and clearing all the vhost_dev structures holding data that vhost-user functions expect to remain valid to roll back initialization correctly. Delay the cleanup to keep vhost_dev structure valid. There are two possible states to handle: 1. RUN_STATE_PRELAUNCH: skip bh oneshot call and perform disconnect in the caller routine. 2. RUN_STATE_RUNNING: delay by using bh BH changes are based on the similar changes for the vhost-user-net device: commit e7c83a885f865128ae3cf1946f8cb538b63cbfba "vhost-user: delay vhost_user_stop" Signed-off-by: Dima Stepanov Message-Id: <69b73b94dcd066065595266c852810e0863a0895.1590396396.git.dimastep@yandex-team.ru> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Signed-off-by: Li Feng Reviewed-by: Raphael Norwitz --- hw/block/vhost-user-blk.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 9d8c0b3909..76838e76d3 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -349,6 +349,19 @@ static void vhost_user_blk_disconnect(DeviceState *dev) vhost_dev_cleanup(&s->dev); } +static void vhost_user_blk_event(void *opaque, QEMUChrEvent event); + +static void vhost_user_blk_chr_closed_bh(void *opaque) +{ + DeviceState *dev = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserBlk *s = VHOST_USER_BLK(vdev); + + vhost_user_blk_disconnect(dev); + qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, + NULL, opaque, NULL, true); +} + static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) { DeviceState *dev = opaque; @@ -363,7 +376,30 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) } break; case CHR_EVENT_CLOSED: - vhost_user_blk_disconnect(dev); + /* + * A close event may happen during a read/write, but vhost + * code assumes the vhost_dev remains setup, so delay the + * stop & clear. There are two possible paths to hit this + * disconnect event: + * 1. When VM is in the RUN_STATE_PRELAUNCH state. The + * vhost_user_blk_device_realize() is a caller. + * 2. In tha main loop phase after VM start. + * + * For p2 the disconnect event will be delayed. We can't + * do the same for p1, because we are not running the loop + * at this moment. So just skip this step and perform + * disconnect in the caller function. + * + * TODO: maybe it is a good idea to make the same fix + * for other vhost-user devices. + */ + if (runstate_is_running()) { + AioContext *ctx = qemu_get_current_aio_context(); + + qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL, NULL, + NULL, NULL, false); + aio_bh_schedule_oneshot(ctx, vhost_user_blk_chr_closed_bh, opaque); + } break; case CHR_EVENT_BREAK: case CHR_EVENT_MUX_IN: From ece99091c2d0aeb23734289a50ef2ff4e0a08929 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 21 May 2020 05:00:26 +0000 Subject: [PATCH 1009/2595] Add helper to populate vhost-user message regions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When setting vhost-user memory tables, memory region descriptors must be copied from the vhost_dev struct to the vhost-user message. To avoid duplicating code in setting the memory tables, we should use a helper to populate this field. This change adds this helper. Signed-off-by: Raphael Norwitz Message-Id: <1588533678-23450-2-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marc-André Lureau --- hw/virtio/vhost-user.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index ec21e8fbe8..2e0552dd74 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -407,6 +407,15 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, return 0; } +static void vhost_user_fill_msg_region(VhostUserMemoryRegion *dst, + struct vhost_memory_region *src) +{ + assert(src != NULL && dst != NULL); + dst->userspace_addr = src->userspace_addr; + dst->memory_size = src->memory_size; + dst->guest_phys_addr = src->guest_phys_addr; +} + static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, struct vhost_dev *dev, VhostUserMsg *msg, @@ -417,6 +426,7 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, ram_addr_t offset; MemoryRegion *mr; struct vhost_memory_region *reg; + VhostUserMemoryRegion region_buffer; msg->hdr.request = VHOST_USER_SET_MEM_TABLE; @@ -441,12 +451,8 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, error_report("Failed preparing vhost-user memory table msg"); return -1; } - msg->payload.memory.regions[*fd_num].userspace_addr = - reg->userspace_addr; - msg->payload.memory.regions[*fd_num].memory_size = - reg->memory_size; - msg->payload.memory.regions[*fd_num].guest_phys_addr = - reg->guest_phys_addr; + vhost_user_fill_msg_region(®ion_buffer, reg); + msg->payload.memory.regions[*fd_num] = region_buffer; msg->payload.memory.regions[*fd_num].mmap_offset = offset; fds[(*fd_num)++] = fd; } else if (track_ramblocks) { From 23374a84c5f08e20ec2506a6322330d51f9134c5 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 21 May 2020 05:00:29 +0000 Subject: [PATCH 1010/2595] Add vhost-user helper to get MemoryRegion data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When setting the memory tables, qemu uses a memory region's userspace address to look up the region's MemoryRegion struct. Among other things, the MemoryRegion contains the region's offset and associated file descriptor, all of which need to be sent to the backend. With VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS, this logic will be needed in multiple places, so before feature support is added it should be moved to a helper function. This helper is also used to simplify the vhost_user_can_merge() function. Signed-off-by: Raphael Norwitz Message-Id: <1588533678-23450-3-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marc-André Lureau --- hw/virtio/vhost-user.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 2e0552dd74..442b0d650a 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -407,6 +407,18 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, return 0; } +static MemoryRegion *vhost_user_get_mr_data(uint64_t addr, ram_addr_t *offset, + int *fd) +{ + MemoryRegion *mr; + + assert((uintptr_t)addr == addr); + mr = memory_region_from_host((void *)(uintptr_t)addr, offset); + *fd = memory_region_get_fd(mr); + + return mr; +} + static void vhost_user_fill_msg_region(VhostUserMemoryRegion *dst, struct vhost_memory_region *src) { @@ -433,10 +445,7 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, for (i = 0; i < dev->mem->nregions; ++i) { reg = dev->mem->regions + i; - assert((uintptr_t)reg->userspace_addr == reg->userspace_addr); - mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr, - &offset); - fd = memory_region_get_fd(mr); + mr = vhost_user_get_mr_data(reg->userspace_addr, &offset, &fd); if (fd > 0) { if (track_ramblocks) { assert(*fd_num < VHOST_MEMORY_MAX_NREGIONS); @@ -1551,13 +1560,9 @@ static bool vhost_user_can_merge(struct vhost_dev *dev, { ram_addr_t offset; int mfd, rfd; - MemoryRegion *mr; - mr = memory_region_from_host((void *)(uintptr_t)start1, &offset); - mfd = memory_region_get_fd(mr); - - mr = memory_region_from_host((void *)(uintptr_t)start2, &offset); - rfd = memory_region_get_fd(mr); + (void)vhost_user_get_mr_data(start1, &offset, &mfd); + (void)vhost_user_get_mr_data(start2, &offset, &rfd); return mfd == rfd; } From 1d74594065a387c03b962a2c5cf77efa394ff82d Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 29 May 2020 09:45:27 -0500 Subject: [PATCH 1011/2595] qemu-img: Fix doc typo for 'bitmap' subcommand Prefer a consistent naming for the --merge argument. Fixes: 3b51ab4bf Signed-off-by: Eric Blake Message-Id: <20200529144527.1943527-1-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- docs/tools/qemu-img.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index 69cd9a3037..7f0737488a 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -300,7 +300,7 @@ Command description: ``--disable`` to change *BITMAP* to stop recording future edits. - ``--merge`` to merge the contents of *SOURCE_BITMAP* into *BITMAP*. + ``--merge`` to merge the contents of the *SOURCE* bitmap into *BITMAP*. Additional options include ``-g`` which sets a non-default *GRANULARITY* for ``--add``, and ``-b`` and ``-F`` which select an From 02756054e1e4e662e2fbdb283754a4a32e9bbd91 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:17:54 +0300 Subject: [PATCH 1012/2595] qcow2.py: python style fixes Fix flake8 complaints. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200606081806.23897-2-vsementsov@virtuozzo.com> Tested-by: Eric Blake Reviewed-by: Eric Blake [eblake: commit message improved] Signed-off-by: Eric Blake --- tests/qemu-iotests/qcow2.py | 95 ++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 39 deletions(-) diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py index 94a07b2f6f..d99f4ee3e8 100755 --- a/tests/qemu-iotests/qcow2.py +++ b/tests/qemu-iotests/qcow2.py @@ -4,6 +4,7 @@ import sys import struct import string + class QcowHeaderExtension: def __init__(self, magic, length, data): @@ -11,14 +12,15 @@ class QcowHeaderExtension: padding = 8 - (length % 8) data += b"\0" * padding - self.magic = magic + self.magic = magic self.length = length - self.data = data + self.data = data @classmethod def create(cls, magic, data): return QcowHeaderExtension(magic, len(data), data) + class QcowHeader: uint32_t = 'I' @@ -26,27 +28,27 @@ class QcowHeader: fields = [ # Version 2 header fields - [ uint32_t, '%#x', 'magic' ], - [ uint32_t, '%d', 'version' ], - [ uint64_t, '%#x', 'backing_file_offset' ], - [ uint32_t, '%#x', 'backing_file_size' ], - [ uint32_t, '%d', 'cluster_bits' ], - [ uint64_t, '%d', 'size' ], - [ uint32_t, '%d', 'crypt_method' ], - [ uint32_t, '%d', 'l1_size' ], - [ uint64_t, '%#x', 'l1_table_offset' ], - [ uint64_t, '%#x', 'refcount_table_offset' ], - [ uint32_t, '%d', 'refcount_table_clusters' ], - [ uint32_t, '%d', 'nb_snapshots' ], - [ uint64_t, '%#x', 'snapshot_offset' ], + [uint32_t, '%#x', 'magic'], + [uint32_t, '%d', 'version'], + [uint64_t, '%#x', 'backing_file_offset'], + [uint32_t, '%#x', 'backing_file_size'], + [uint32_t, '%d', 'cluster_bits'], + [uint64_t, '%d', 'size'], + [uint32_t, '%d', 'crypt_method'], + [uint32_t, '%d', 'l1_size'], + [uint64_t, '%#x', 'l1_table_offset'], + [uint64_t, '%#x', 'refcount_table_offset'], + [uint32_t, '%d', 'refcount_table_clusters'], + [uint32_t, '%d', 'nb_snapshots'], + [uint64_t, '%#x', 'snapshot_offset'], # Version 3 header fields - [ uint64_t, 'mask', 'incompatible_features' ], - [ uint64_t, 'mask', 'compatible_features' ], - [ uint64_t, 'mask', 'autoclear_features' ], - [ uint32_t, '%d', 'refcount_order' ], - [ uint32_t, '%d', 'header_length' ], - ]; + [uint64_t, 'mask', 'incompatible_features'], + [uint64_t, 'mask', 'compatible_features'], + [uint64_t, 'mask', 'autoclear_features'], + [uint32_t, '%d', 'refcount_order'], + [uint32_t, '%d', 'header_length'], + ] fmt = '>' + ''.join(field[0] for field in fields) @@ -59,7 +61,7 @@ class QcowHeader: header = struct.unpack(QcowHeader.fmt, buf) self.__dict__ = dict((field[2], header[i]) - for i, field in enumerate(QcowHeader.fields)) + for i, field in enumerate(QcowHeader.fields)) self.set_defaults() self.cluster_size = 1 << self.cluster_bits @@ -96,7 +98,8 @@ class QcowHeader: else: padded = (length + 7) & ~7 data = fd.read(padded) - self.extensions.append(QcowHeaderExtension(magic, length, data)) + self.extensions.append(QcowHeaderExtension(magic, length, + data)) def update_extensions(self, fd): @@ -108,14 +111,13 @@ class QcowHeader: fd.write(buf) fd.write(ex.data) - if self.backing_file != None: + if self.backing_file is not None: self.backing_file_offset = fd.tell() fd.write(self.backing_file) if fd.tell() > self.cluster_size: raise Exception("I think I just broke the image...") - def update(self, fd): header_bytes = self.header_length @@ -163,19 +165,21 @@ def cmd_dump_header(fd): h.dump() h.dump_extensions() + def cmd_dump_header_exts(fd): h = QcowHeader(fd) h.dump_extensions() + def cmd_set_header(fd, name, value): try: value = int(value, 0) - except: + except ValueError: print("'%s' is not a valid number" % value) sys.exit(1) fields = (field[2] for field in QcowHeader.fields) - if not name in fields: + if name not in fields: print("'%s' is not a known header field" % name) sys.exit(1) @@ -183,25 +187,29 @@ def cmd_set_header(fd, name, value): h.__dict__[name] = value h.update(fd) + def cmd_add_header_ext(fd, magic, data): try: magic = int(magic, 0) - except: + except ValueError: print("'%s' is not a valid magic number" % magic) sys.exit(1) h = QcowHeader(fd) - h.extensions.append(QcowHeaderExtension.create(magic, data.encode('ascii'))) + h.extensions.append(QcowHeaderExtension.create(magic, + data.encode('ascii'))) h.update(fd) + def cmd_add_header_ext_stdio(fd, magic): data = sys.stdin.read() cmd_add_header_ext(fd, magic, data) + def cmd_del_header_ext(fd, magic): try: magic = int(magic, 0) - except: + except ValueError: print("'%s' is not a valid magic number" % magic) sys.exit(1) @@ -219,12 +227,13 @@ def cmd_del_header_ext(fd, magic): h.update(fd) + def cmd_set_feature_bit(fd, group, bit): try: bit = int(bit, 0) if bit < 0 or bit >= 64: raise ValueError - except: + except ValueError: print("'%s' is not a valid bit number in range [0, 64)" % bit) sys.exit(1) @@ -236,21 +245,27 @@ def cmd_set_feature_bit(fd, group, bit): elif group == 'autoclear': h.autoclear_features |= 1 << bit else: - print("'%s' is not a valid group, try 'incompatible', 'compatible', or 'autoclear'" % group) + print("'%s' is not a valid group, try " + "'incompatible', 'compatible', or 'autoclear'" % group) sys.exit(1) h.update(fd) + cmds = [ - [ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ], - [ 'dump-header-exts', cmd_dump_header_exts, 0, 'Dump image header extensions' ], - [ 'set-header', cmd_set_header, 2, 'Set a field in the header'], - [ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ], - [ 'add-header-ext-stdio', cmd_add_header_ext_stdio, 1, 'Add a header extension, data from stdin' ], - [ 'del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension' ], - [ 'set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'], + ['dump-header', cmd_dump_header, 0, + 'Dump image header and header extensions'], + ['dump-header-exts', cmd_dump_header_exts, 0, + 'Dump image header extensions'], + ['set-header', cmd_set_header, 2, 'Set a field in the header'], + ['add-header-ext', cmd_add_header_ext, 2, 'Add a header extension'], + ['add-header-ext-stdio', cmd_add_header_ext_stdio, 1, + 'Add a header extension, data from stdin'], + ['del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension'], + ['set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'], ] + def main(filename, cmd, args): fd = open(filename, "r+b") try: @@ -267,6 +282,7 @@ def main(filename, cmd, args): finally: fd.close() + def usage(): print("Usage: %s [, ...]" % sys.argv[0]) print("") @@ -274,6 +290,7 @@ def usage(): for name, handler, num_args, desc in cmds: print(" %-20s - %s" % (name, desc)) + if __name__ == '__main__': if len(sys.argv) < 3: usage() From 16306a7b39fd63cf6e2e0cdf35a1834a5294235a Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:17:55 +0300 Subject: [PATCH 1013/2595] qcow2.py: add licensing blurb Add classic heading, which is missing here. Keep copyright place empty, prior authors may add a line later. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200606081806.23897-3-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake [eblake: tweak commit message] Signed-off-by: Eric Blake --- tests/qemu-iotests/qcow2.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py index d99f4ee3e8..2da434a013 100755 --- a/tests/qemu-iotests/qcow2.py +++ b/tests/qemu-iotests/qcow2.py @@ -1,4 +1,20 @@ #!/usr/bin/env python3 +# +# Manipulations with qcow2 image +# +# 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 . +# import sys import struct From d5262c712488674fba74a749e81894e098226bfa Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:17:56 +0300 Subject: [PATCH 1014/2595] qcow2.py: move qcow2 format classes to separate module We are going to enhance qcow2 format parsing by adding more structure classes. Let's split format parsing from utility code. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200606081806.23897-4-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake Signed-off-by: Eric Blake --- tests/qemu-iotests/qcow2.py | 160 +------------------------- tests/qemu-iotests/qcow2_format.py | 173 +++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 156 deletions(-) create mode 100644 tests/qemu-iotests/qcow2_format.py diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py index 2da434a013..e968869ea6 100755 --- a/tests/qemu-iotests/qcow2.py +++ b/tests/qemu-iotests/qcow2.py @@ -17,163 +17,11 @@ # import sys -import struct -import string - -class QcowHeaderExtension: - - def __init__(self, magic, length, data): - if length % 8 != 0: - padding = 8 - (length % 8) - data += b"\0" * padding - - self.magic = magic - self.length = length - self.data = data - - @classmethod - def create(cls, magic, data): - return QcowHeaderExtension(magic, len(data), data) - - -class QcowHeader: - - uint32_t = 'I' - uint64_t = 'Q' - - fields = [ - # Version 2 header fields - [uint32_t, '%#x', 'magic'], - [uint32_t, '%d', 'version'], - [uint64_t, '%#x', 'backing_file_offset'], - [uint32_t, '%#x', 'backing_file_size'], - [uint32_t, '%d', 'cluster_bits'], - [uint64_t, '%d', 'size'], - [uint32_t, '%d', 'crypt_method'], - [uint32_t, '%d', 'l1_size'], - [uint64_t, '%#x', 'l1_table_offset'], - [uint64_t, '%#x', 'refcount_table_offset'], - [uint32_t, '%d', 'refcount_table_clusters'], - [uint32_t, '%d', 'nb_snapshots'], - [uint64_t, '%#x', 'snapshot_offset'], - - # Version 3 header fields - [uint64_t, 'mask', 'incompatible_features'], - [uint64_t, 'mask', 'compatible_features'], - [uint64_t, 'mask', 'autoclear_features'], - [uint32_t, '%d', 'refcount_order'], - [uint32_t, '%d', 'header_length'], - ] - - fmt = '>' + ''.join(field[0] for field in fields) - - def __init__(self, fd): - - buf_size = struct.calcsize(QcowHeader.fmt) - - fd.seek(0) - buf = fd.read(buf_size) - - header = struct.unpack(QcowHeader.fmt, buf) - self.__dict__ = dict((field[2], header[i]) - for i, field in enumerate(QcowHeader.fields)) - - self.set_defaults() - self.cluster_size = 1 << self.cluster_bits - - fd.seek(self.header_length) - self.load_extensions(fd) - - if self.backing_file_offset: - fd.seek(self.backing_file_offset) - self.backing_file = fd.read(self.backing_file_size) - else: - self.backing_file = None - - def set_defaults(self): - if self.version == 2: - self.incompatible_features = 0 - self.compatible_features = 0 - self.autoclear_features = 0 - self.refcount_order = 4 - self.header_length = 72 - - def load_extensions(self, fd): - self.extensions = [] - - if self.backing_file_offset != 0: - end = min(self.cluster_size, self.backing_file_offset) - else: - end = self.cluster_size - - while fd.tell() < end: - (magic, length) = struct.unpack('>II', fd.read(8)) - if magic == 0: - break - else: - padded = (length + 7) & ~7 - data = fd.read(padded) - self.extensions.append(QcowHeaderExtension(magic, length, - data)) - - def update_extensions(self, fd): - - fd.seek(self.header_length) - extensions = self.extensions - extensions.append(QcowHeaderExtension(0, 0, b"")) - for ex in extensions: - buf = struct.pack('>II', ex.magic, ex.length) - fd.write(buf) - fd.write(ex.data) - - if self.backing_file is not None: - self.backing_file_offset = fd.tell() - fd.write(self.backing_file) - - if fd.tell() > self.cluster_size: - raise Exception("I think I just broke the image...") - - def update(self, fd): - header_bytes = self.header_length - - self.update_extensions(fd) - - fd.seek(0) - header = tuple(self.__dict__[f] for t, p, f in QcowHeader.fields) - buf = struct.pack(QcowHeader.fmt, *header) - buf = buf[0:header_bytes-1] - fd.write(buf) - - def dump(self): - for f in QcowHeader.fields: - value = self.__dict__[f[2]] - if f[1] == 'mask': - bits = [] - for bit in range(64): - if value & (1 << bit): - bits.append(bit) - value_str = str(bits) - else: - value_str = f[1] % value - - print("%-25s" % f[2], value_str) - print("") - - def dump_extensions(self): - for ex in self.extensions: - - data = ex.data[:ex.length] - if all(c in string.printable.encode('ascii') for c in data): - data = "'%s'" % data.decode('ascii') - else: - data = "" - - print("Header extension:") - print("%-25s %#x" % ("magic", ex.magic)) - print("%-25s %d" % ("length", ex.length)) - print("%-25s %s" % ("data", data)) - print("") +from qcow2_format import ( + QcowHeader, + QcowHeaderExtension +) def cmd_dump_header(fd): diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py new file mode 100644 index 0000000000..0e517c1bbc --- /dev/null +++ b/tests/qemu-iotests/qcow2_format.py @@ -0,0 +1,173 @@ +# Library for manipulations with qcow2 image +# +# 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 . +# + +import struct +import string + + +class QcowHeaderExtension: + + def __init__(self, magic, length, data): + if length % 8 != 0: + padding = 8 - (length % 8) + data += b"\0" * padding + + self.magic = magic + self.length = length + self.data = data + + @classmethod + def create(cls, magic, data): + return QcowHeaderExtension(magic, len(data), data) + + +class QcowHeader: + + uint32_t = 'I' + uint64_t = 'Q' + + fields = [ + # Version 2 header fields + [uint32_t, '%#x', 'magic'], + [uint32_t, '%d', 'version'], + [uint64_t, '%#x', 'backing_file_offset'], + [uint32_t, '%#x', 'backing_file_size'], + [uint32_t, '%d', 'cluster_bits'], + [uint64_t, '%d', 'size'], + [uint32_t, '%d', 'crypt_method'], + [uint32_t, '%d', 'l1_size'], + [uint64_t, '%#x', 'l1_table_offset'], + [uint64_t, '%#x', 'refcount_table_offset'], + [uint32_t, '%d', 'refcount_table_clusters'], + [uint32_t, '%d', 'nb_snapshots'], + [uint64_t, '%#x', 'snapshot_offset'], + + # Version 3 header fields + [uint64_t, 'mask', 'incompatible_features'], + [uint64_t, 'mask', 'compatible_features'], + [uint64_t, 'mask', 'autoclear_features'], + [uint32_t, '%d', 'refcount_order'], + [uint32_t, '%d', 'header_length'], + ] + + fmt = '>' + ''.join(field[0] for field in fields) + + def __init__(self, fd): + + buf_size = struct.calcsize(QcowHeader.fmt) + + fd.seek(0) + buf = fd.read(buf_size) + + header = struct.unpack(QcowHeader.fmt, buf) + self.__dict__ = dict((field[2], header[i]) + for i, field in enumerate(QcowHeader.fields)) + + self.set_defaults() + self.cluster_size = 1 << self.cluster_bits + + fd.seek(self.header_length) + self.load_extensions(fd) + + if self.backing_file_offset: + fd.seek(self.backing_file_offset) + self.backing_file = fd.read(self.backing_file_size) + else: + self.backing_file = None + + def set_defaults(self): + if self.version == 2: + self.incompatible_features = 0 + self.compatible_features = 0 + self.autoclear_features = 0 + self.refcount_order = 4 + self.header_length = 72 + + def load_extensions(self, fd): + self.extensions = [] + + if self.backing_file_offset != 0: + end = min(self.cluster_size, self.backing_file_offset) + else: + end = self.cluster_size + + while fd.tell() < end: + (magic, length) = struct.unpack('>II', fd.read(8)) + if magic == 0: + break + else: + padded = (length + 7) & ~7 + data = fd.read(padded) + self.extensions.append(QcowHeaderExtension(magic, length, + data)) + + def update_extensions(self, fd): + + fd.seek(self.header_length) + extensions = self.extensions + extensions.append(QcowHeaderExtension(0, 0, b"")) + for ex in extensions: + buf = struct.pack('>II', ex.magic, ex.length) + fd.write(buf) + fd.write(ex.data) + + if self.backing_file is not None: + self.backing_file_offset = fd.tell() + fd.write(self.backing_file) + + if fd.tell() > self.cluster_size: + raise Exception("I think I just broke the image...") + + def update(self, fd): + header_bytes = self.header_length + + self.update_extensions(fd) + + fd.seek(0) + header = tuple(self.__dict__[f] for t, p, f in QcowHeader.fields) + buf = struct.pack(QcowHeader.fmt, *header) + buf = buf[0:header_bytes-1] + fd.write(buf) + + def dump(self): + for f in QcowHeader.fields: + value = self.__dict__[f[2]] + if f[1] == 'mask': + bits = [] + for bit in range(64): + if value & (1 << bit): + bits.append(bit) + value_str = str(bits) + else: + value_str = f[1] % value + + print("%-25s" % f[2], value_str) + print("") + + def dump_extensions(self): + for ex in self.extensions: + + data = ex.data[:ex.length] + if all(c in string.printable.encode('ascii') for c in data): + data = "'%s'" % data.decode('ascii') + else: + data = "" + + print("Header extension:") + print("%-25s %#x" % ("magic", ex.magic)) + print("%-25s %d" % ("length", ex.length)) + print("%-25s %s" % ("data", data)) + print("") From eeafed5f6e76a98d3b640f003b96b1490d2281b1 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:17:57 +0300 Subject: [PATCH 1015/2595] qcow2_format.py: drop new line printing at end of dump() This will simplify further conversion. To compensate, print this empty line directly in cmd_dump_header(). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200606081806.23897-5-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/qcow2.py | 1 + tests/qemu-iotests/qcow2_format.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py index e968869ea6..8c187e9a72 100755 --- a/tests/qemu-iotests/qcow2.py +++ b/tests/qemu-iotests/qcow2.py @@ -27,6 +27,7 @@ from qcow2_format import ( def cmd_dump_header(fd): h = QcowHeader(fd) h.dump() + print() h.dump_extensions() diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index 0e517c1bbc..2b6c9612ae 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -155,7 +155,6 @@ class QcowHeader: value_str = f[1] % value print("%-25s" % f[2], value_str) - print("") def dump_extensions(self): for ex in self.extensions: From b2f1415444af944a087a72ed0e55f971a78a2371 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:17:58 +0300 Subject: [PATCH 1016/2595] qcow2_format.py: use tuples instead of lists for fields No need in lists: it's a constant variable. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200606081806.23897-6-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/qcow2_format.py | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index 2b6c9612ae..e2f08ed691 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -39,29 +39,29 @@ class QcowHeader: uint32_t = 'I' uint64_t = 'Q' - fields = [ + fields = ( # Version 2 header fields - [uint32_t, '%#x', 'magic'], - [uint32_t, '%d', 'version'], - [uint64_t, '%#x', 'backing_file_offset'], - [uint32_t, '%#x', 'backing_file_size'], - [uint32_t, '%d', 'cluster_bits'], - [uint64_t, '%d', 'size'], - [uint32_t, '%d', 'crypt_method'], - [uint32_t, '%d', 'l1_size'], - [uint64_t, '%#x', 'l1_table_offset'], - [uint64_t, '%#x', 'refcount_table_offset'], - [uint32_t, '%d', 'refcount_table_clusters'], - [uint32_t, '%d', 'nb_snapshots'], - [uint64_t, '%#x', 'snapshot_offset'], + (uint32_t, '%#x', 'magic'), + (uint32_t, '%d', 'version'), + (uint64_t, '%#x', 'backing_file_offset'), + (uint32_t, '%#x', 'backing_file_size'), + (uint32_t, '%d', 'cluster_bits'), + (uint64_t, '%d', 'size'), + (uint32_t, '%d', 'crypt_method'), + (uint32_t, '%d', 'l1_size'), + (uint64_t, '%#x', 'l1_table_offset'), + (uint64_t, '%#x', 'refcount_table_offset'), + (uint32_t, '%d', 'refcount_table_clusters'), + (uint32_t, '%d', 'nb_snapshots'), + (uint64_t, '%#x', 'snapshot_offset'), # Version 3 header fields - [uint64_t, 'mask', 'incompatible_features'], - [uint64_t, 'mask', 'compatible_features'], - [uint64_t, 'mask', 'autoclear_features'], - [uint32_t, '%d', 'refcount_order'], - [uint32_t, '%d', 'header_length'], - ] + (uint64_t, 'mask', 'incompatible_features'), + (uint64_t, 'mask', 'compatible_features'), + (uint64_t, 'mask', 'autoclear_features'), + (uint32_t, '%d', 'refcount_order'), + (uint32_t, '%d', 'header_length'), + ) fmt = '>' + ''.join(field[0] for field in fields) From 621ca4988a20733eca43148396f910373e02d571 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:17:59 +0300 Subject: [PATCH 1017/2595] qcow2_format.py: use modern string formatting Use .format and f-strings instead of old %style. Also, the file uses both '' and "" quotes, for consistency let's use '', except for cases when we need '' inside the string (use "" to avoid extra escaping). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200606081806.23897-7-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/qcow2_format.py | 54 +++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index e2f08ed691..da66df3408 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -23,7 +23,7 @@ class QcowHeaderExtension: def __init__(self, magic, length, data): if length % 8 != 0: padding = 8 - (length % 8) - data += b"\0" * padding + data += b'\0' * padding self.magic = magic self.length = length @@ -41,26 +41,26 @@ class QcowHeader: fields = ( # Version 2 header fields - (uint32_t, '%#x', 'magic'), - (uint32_t, '%d', 'version'), - (uint64_t, '%#x', 'backing_file_offset'), - (uint32_t, '%#x', 'backing_file_size'), - (uint32_t, '%d', 'cluster_bits'), - (uint64_t, '%d', 'size'), - (uint32_t, '%d', 'crypt_method'), - (uint32_t, '%d', 'l1_size'), - (uint64_t, '%#x', 'l1_table_offset'), - (uint64_t, '%#x', 'refcount_table_offset'), - (uint32_t, '%d', 'refcount_table_clusters'), - (uint32_t, '%d', 'nb_snapshots'), - (uint64_t, '%#x', 'snapshot_offset'), + (uint32_t, '{:#x}', 'magic'), + (uint32_t, '{}', 'version'), + (uint64_t, '{:#x}', 'backing_file_offset'), + (uint32_t, '{:#x}', 'backing_file_size'), + (uint32_t, '{}', 'cluster_bits'), + (uint64_t, '{}', 'size'), + (uint32_t, '{}', 'crypt_method'), + (uint32_t, '{}', 'l1_size'), + (uint64_t, '{:#x}', 'l1_table_offset'), + (uint64_t, '{:#x}', 'refcount_table_offset'), + (uint32_t, '{}', 'refcount_table_clusters'), + (uint32_t, '{}', 'nb_snapshots'), + (uint64_t, '{:#x}', 'snapshot_offset'), # Version 3 header fields (uint64_t, 'mask', 'incompatible_features'), (uint64_t, 'mask', 'compatible_features'), (uint64_t, 'mask', 'autoclear_features'), - (uint32_t, '%d', 'refcount_order'), - (uint32_t, '%d', 'header_length'), + (uint32_t, '{}', 'refcount_order'), + (uint32_t, '{}', 'header_length'), ) fmt = '>' + ''.join(field[0] for field in fields) @@ -118,7 +118,7 @@ class QcowHeader: fd.seek(self.header_length) extensions = self.extensions - extensions.append(QcowHeaderExtension(0, 0, b"")) + extensions.append(QcowHeaderExtension(0, 0, b'')) for ex in extensions: buf = struct.pack('>II', ex.magic, ex.length) fd.write(buf) @@ -129,7 +129,7 @@ class QcowHeader: fd.write(self.backing_file) if fd.tell() > self.cluster_size: - raise Exception("I think I just broke the image...") + raise Exception('I think I just broke the image...') def update(self, fd): header_bytes = self.header_length @@ -152,21 +152,21 @@ class QcowHeader: bits.append(bit) value_str = str(bits) else: - value_str = f[1] % value + value_str = f[1].format(value) - print("%-25s" % f[2], value_str) + print(f'{f[2]:<25} {value_str}') def dump_extensions(self): for ex in self.extensions: data = ex.data[:ex.length] if all(c in string.printable.encode('ascii') for c in data): - data = "'%s'" % data.decode('ascii') + data = f"'{ data.decode('ascii') }'" else: - data = "" + data = '' - print("Header extension:") - print("%-25s %#x" % ("magic", ex.magic)) - print("%-25s %d" % ("length", ex.length)) - print("%-25s %s" % ("data", data)) - print("") + print('Header extension:') + print(f'{"magic":<25} {ex.magic:#x}') + print(f'{"length":<25} {ex.length}') + print(f'{"data":<25} {data}') + print() From 5432a0db528cde9f58d6a843105a66c79b523a73 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:18:00 +0300 Subject: [PATCH 1018/2595] qcow2_format.py: use strings to specify c-type of struct fields We are going to move field-parsing to super-class, this will be simpler with simple string specifiers instead of variables. For some reason, python doesn't allow the definition of ctypes variable in the class alongside fields: it would not be available then for use by the 'for' operator. Don't worry: ctypes will be moved to metaclass soon. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200606081806.23897-8-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/qcow2_format.py | 50 +++++++++++++++++------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index da66df3408..28f2bfa63b 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -34,36 +34,42 @@ class QcowHeaderExtension: return QcowHeaderExtension(magic, len(data), data) -class QcowHeader: +# Mapping from c types to python struct format +ctypes = { + 'u8': 'B', + 'u16': 'H', + 'u32': 'I', + 'u64': 'Q' +} - uint32_t = 'I' - uint64_t = 'Q' + +class QcowHeader: fields = ( # Version 2 header fields - (uint32_t, '{:#x}', 'magic'), - (uint32_t, '{}', 'version'), - (uint64_t, '{:#x}', 'backing_file_offset'), - (uint32_t, '{:#x}', 'backing_file_size'), - (uint32_t, '{}', 'cluster_bits'), - (uint64_t, '{}', 'size'), - (uint32_t, '{}', 'crypt_method'), - (uint32_t, '{}', 'l1_size'), - (uint64_t, '{:#x}', 'l1_table_offset'), - (uint64_t, '{:#x}', 'refcount_table_offset'), - (uint32_t, '{}', 'refcount_table_clusters'), - (uint32_t, '{}', 'nb_snapshots'), - (uint64_t, '{:#x}', 'snapshot_offset'), + ('u32', '{:#x}', 'magic'), + ('u32', '{}', 'version'), + ('u64', '{:#x}', 'backing_file_offset'), + ('u32', '{:#x}', 'backing_file_size'), + ('u32', '{}', 'cluster_bits'), + ('u64', '{}', 'size'), + ('u32', '{}', 'crypt_method'), + ('u32', '{}', 'l1_size'), + ('u64', '{:#x}', 'l1_table_offset'), + ('u64', '{:#x}', 'refcount_table_offset'), + ('u32', '{}', 'refcount_table_clusters'), + ('u32', '{}', 'nb_snapshots'), + ('u64', '{:#x}', 'snapshot_offset'), # Version 3 header fields - (uint64_t, 'mask', 'incompatible_features'), - (uint64_t, 'mask', 'compatible_features'), - (uint64_t, 'mask', 'autoclear_features'), - (uint32_t, '{}', 'refcount_order'), - (uint32_t, '{}', 'header_length'), + ('u64', 'mask', 'incompatible_features'), + ('u64', 'mask', 'compatible_features'), + ('u64', 'mask', 'autoclear_features'), + ('u32', '{}', 'refcount_order'), + ('u32', '{}', 'header_length'), ) - fmt = '>' + ''.join(field[0] for field in fields) + fmt = '>' + ''.join(ctypes[f[0]] for f in fields) def __init__(self, fd): From 0903e3b3714df385931e4ff844e4aff713aa2411 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:18:01 +0300 Subject: [PATCH 1019/2595] qcow2_format.py: separate generic functionality of structure classes We are going to introduce more Qcow2 structure types, defined like QcowHeader. Move generic functionality into base class to be reused for further structure classes. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200606081806.23897-9-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/qcow2_format.py | 101 +++++++++++++++++++---------- 1 file changed, 66 insertions(+), 35 deletions(-) diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index 28f2bfa63b..898d388b8a 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -1,5 +1,7 @@ # Library for manipulations with qcow2 image # +# Copyright (c) 2020 Virtuozzo International GmbH. +# # 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 @@ -18,6 +20,68 @@ import struct import string +class Qcow2StructMeta(type): + + # Mapping from c types to python struct format + ctypes = { + 'u8': 'B', + 'u16': 'H', + 'u32': 'I', + 'u64': 'Q' + } + + def __init__(self, name, bases, attrs): + if 'fields' in attrs: + self.fmt = '>' + ''.join(self.ctypes[f[0]] for f in self.fields) + + +class Qcow2Struct(metaclass=Qcow2StructMeta): + + """Qcow2Struct: base class for qcow2 data structures + + Successors should define fields class variable, which is: list of tuples, + each of three elements: + - c-type (one of 'u8', 'u16', 'u32', 'u64') + - format (format_spec to use with .format() when dump or 'mask' to dump + bitmasks) + - field name + """ + + def __init__(self, fd=None, offset=None, data=None): + """ + Two variants: + 1. Specify data. fd and offset must be None. + 2. Specify fd and offset, data must be None. offset may be omitted + in this case, than current position of fd is used. + """ + if data is None: + assert fd is not None + buf_size = struct.calcsize(self.fmt) + if offset is not None: + fd.seek(offset) + data = fd.read(buf_size) + else: + assert fd is None and offset is None + + values = struct.unpack(self.fmt, data) + self.__dict__ = dict((field[2], values[i]) + for i, field in enumerate(self.fields)) + + def dump(self): + for f in self.fields: + value = self.__dict__[f[2]] + if f[1] == 'mask': + bits = [] + for bit in range(64): + if value & (1 << bit): + bits.append(bit) + value_str = str(bits) + else: + value_str = f[1].format(value) + + print('{:<25} {}'.format(f[2], value_str)) + + class QcowHeaderExtension: def __init__(self, magic, length, data): @@ -34,16 +98,7 @@ class QcowHeaderExtension: return QcowHeaderExtension(magic, len(data), data) -# Mapping from c types to python struct format -ctypes = { - 'u8': 'B', - 'u16': 'H', - 'u32': 'I', - 'u64': 'Q' -} - - -class QcowHeader: +class QcowHeader(Qcow2Struct): fields = ( # Version 2 header fields @@ -69,18 +124,8 @@ class QcowHeader: ('u32', '{}', 'header_length'), ) - fmt = '>' + ''.join(ctypes[f[0]] for f in fields) - def __init__(self, fd): - - buf_size = struct.calcsize(QcowHeader.fmt) - - fd.seek(0) - buf = fd.read(buf_size) - - header = struct.unpack(QcowHeader.fmt, buf) - self.__dict__ = dict((field[2], header[i]) - for i, field in enumerate(QcowHeader.fields)) + super().__init__(fd=fd, offset=0) self.set_defaults() self.cluster_size = 1 << self.cluster_bits @@ -148,20 +193,6 @@ class QcowHeader: buf = buf[0:header_bytes-1] fd.write(buf) - def dump(self): - for f in QcowHeader.fields: - value = self.__dict__[f[2]] - if f[1] == 'mask': - bits = [] - for bit in range(64): - if value & (1 << bit): - bits.append(bit) - value_str = str(bits) - else: - value_str = f[1].format(value) - - print(f'{f[2]:<25} {value_str}') - def dump_extensions(self): for ex in self.extensions: From 860543f055654017cdb5b25ed06c2bc91b72af70 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:18:02 +0300 Subject: [PATCH 1020/2595] qcow2_format.py: add field-formatting class Allow formatter class in structure definition instead of hacking with 'mask'. This will simplify further introduction of new formatters. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200606081806.23897-10-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/qcow2_format.py | 35 +++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index 898d388b8a..74a82f9263 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -20,6 +20,25 @@ import struct import string +class Qcow2Field: + + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + + +class Flags64(Qcow2Field): + + def __str__(self): + bits = [] + for bit in range(64): + if self.value & (1 << bit): + bits.append(bit) + return str(bits) + + class Qcow2StructMeta(type): # Mapping from c types to python struct format @@ -70,14 +89,10 @@ class Qcow2Struct(metaclass=Qcow2StructMeta): def dump(self): for f in self.fields: value = self.__dict__[f[2]] - if f[1] == 'mask': - bits = [] - for bit in range(64): - if value & (1 << bit): - bits.append(bit) - value_str = str(bits) - else: + if isinstance(f[1], str): value_str = f[1].format(value) + else: + value_str = str(f[1](value)) print('{:<25} {}'.format(f[2], value_str)) @@ -117,9 +132,9 @@ class QcowHeader(Qcow2Struct): ('u64', '{:#x}', 'snapshot_offset'), # Version 3 header fields - ('u64', 'mask', 'incompatible_features'), - ('u64', 'mask', 'compatible_features'), - ('u64', 'mask', 'autoclear_features'), + ('u64', Flags64, 'incompatible_features'), + ('u64', Flags64, 'compatible_features'), + ('u64', Flags64, 'autoclear_features'), ('u32', '{}', 'refcount_order'), ('u32', '{}', 'header_length'), ) From 0931fcc7beb1c2461f094e16720a979e749085e9 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:18:03 +0300 Subject: [PATCH 1021/2595] qcow2_format.py: QcowHeaderExtension: add dump method Obviously, for-loop body in dump_extensions should be the dump method of extension. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200606081806.23897-11-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/qcow2_format.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index 74a82f9263..d4ad5431b2 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -108,6 +108,17 @@ class QcowHeaderExtension: self.length = length self.data = data + def dump(self): + data = self.data[:self.length] + if all(c in string.printable.encode('ascii') for c in data): + data = f"'{ data.decode('ascii') }'" + else: + data = '' + + print(f'{"magic":<25} {self.magic:#x}') + print(f'{"length":<25} {self.length}') + print(f'{"data":<25} {data}') + @classmethod def create(cls, magic, data): return QcowHeaderExtension(magic, len(data), data) @@ -210,15 +221,6 @@ class QcowHeader(Qcow2Struct): def dump_extensions(self): for ex in self.extensions: - - data = ex.data[:ex.length] - if all(c in string.printable.encode('ascii') for c in data): - data = f"'{ data.decode('ascii') }'" - else: - data = '' - print('Header extension:') - print(f'{"magic":<25} {ex.magic:#x}') - print(f'{"length":<25} {ex.length}') - print(f'{"data":<25} {data}') + ex.dump() print() From a9e750e1ce0bfcca1ff51c71e66eb4b0f66061a8 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:18:04 +0300 Subject: [PATCH 1022/2595] qcow2_format: refactor QcowHeaderExtension as a subclass of Qcow2Struct Only two fields we can parse by generic code, but that is better than nothing. Keep further refactoring of variable-length fields for another day. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200606081806.23897-12-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/qcow2_format.py | 53 +++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index d4ad5431b2..32371e42da 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -97,16 +97,41 @@ class Qcow2Struct(metaclass=Qcow2StructMeta): print('{:<25} {}'.format(f[2], value_str)) -class QcowHeaderExtension: +class QcowHeaderExtension(Qcow2Struct): - def __init__(self, magic, length, data): - if length % 8 != 0: - padding = 8 - (length % 8) - data += b'\0' * padding + fields = ( + ('u32', '{:#x}', 'magic'), + ('u32', '{}', 'length') + # length bytes of data follows + # then padding to next multiply of 8 + ) - self.magic = magic - self.length = length - self.data = data + def __init__(self, magic=None, length=None, data=None, fd=None): + """ + Support both loading from fd and creation from user data. + For fd-based creation current position in a file will be used to read + the data. + + This should be somehow refactored and functionality should be moved to + superclass (to allow creation of any qcow2 struct), but then, fields + of variable length (data here) should be supported in base class + somehow. So, it's a TODO. We'll see how to properly refactor this when + we have more qcow2 structures. + """ + if fd is None: + assert all(v is not None for v in (magic, length, data)) + self.magic = magic + self.length = length + if length % 8 != 0: + padding = 8 - (length % 8) + data += b'\0' * padding + self.data = data + else: + assert all(v is None for v in (magic, length, data)) + super().__init__(fd=fd) + padded = (self.length + 7) & ~7 + self.data = fd.read(padded) + assert self.data is not None def dump(self): data = self.data[:self.length] @@ -115,8 +140,7 @@ class QcowHeaderExtension: else: data = '' - print(f'{"magic":<25} {self.magic:#x}') - print(f'{"length":<25} {self.length}') + super().dump() print(f'{"data":<25} {data}') @classmethod @@ -182,14 +206,11 @@ class QcowHeader(Qcow2Struct): end = self.cluster_size while fd.tell() < end: - (magic, length) = struct.unpack('>II', fd.read(8)) - if magic == 0: + ext = QcowHeaderExtension(fd=fd) + if ext.magic == 0: break else: - padded = (length + 7) & ~7 - data = fd.read(padded) - self.extensions.append(QcowHeaderExtension(magic, length, - data)) + self.extensions.append(ext) def update_extensions(self, fd): From aef87784f93b9e7e07ea7b2ee9dee4c257c1881f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:18:05 +0300 Subject: [PATCH 1023/2595] qcow2: QcowHeaderExtension print names for extension magics Suggested-by: Andrey Shinkevich Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200606081806.23897-13-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake Signed-off-by: Eric Blake --- tests/qemu-iotests/031.out | 22 +++++++++++----------- tests/qemu-iotests/036.out | 4 ++-- tests/qemu-iotests/061.out | 14 +++++++------- tests/qemu-iotests/qcow2_format.py | 17 ++++++++++++++++- 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out index 5a4beda6a2..4b21d6a9ba 100644 --- a/tests/qemu-iotests/031.out +++ b/tests/qemu-iotests/031.out @@ -25,7 +25,7 @@ refcount_order 4 header_length 72 Header extension: -magic 0x12345678 +magic 0x12345678 () length 31 data 'This is a test header extension' @@ -53,7 +53,7 @@ refcount_order 4 header_length 72 Header extension: -magic 0x12345678 +magic 0x12345678 () length 31 data 'This is a test header extension' @@ -81,12 +81,12 @@ refcount_order 4 header_length 72 Header extension: -magic 0xe2792aca +magic 0xe2792aca (Backing format) length 11 data 'host_device' Header extension: -magic 0x12345678 +magic 0x12345678 () length 31 data 'This is a test header extension' @@ -116,12 +116,12 @@ refcount_order 4 header_length 112 Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data Header extension: -magic 0x12345678 +magic 0x12345678 () length 31 data 'This is a test header extension' @@ -149,12 +149,12 @@ refcount_order 4 header_length 112 Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data Header extension: -magic 0x12345678 +magic 0x12345678 () length 31 data 'This is a test header extension' @@ -182,17 +182,17 @@ refcount_order 4 header_length 112 Header extension: -magic 0xe2792aca +magic 0xe2792aca (Backing format) length 11 data 'host_device' Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data Header extension: -magic 0x12345678 +magic 0x12345678 () length 31 data 'This is a test header extension' diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out index e409acf60e..a9bed828e5 100644 --- a/tests/qemu-iotests/036.out +++ b/tests/qemu-iotests/036.out @@ -25,7 +25,7 @@ incompatible_features [] compatible_features [] autoclear_features [63] Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data @@ -37,7 +37,7 @@ incompatible_features [] compatible_features [] autoclear_features [] Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index a51ad1b5ba..2f03cf045c 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -25,7 +25,7 @@ refcount_order 4 header_length 112 Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data @@ -83,7 +83,7 @@ refcount_order 4 header_length 112 Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data @@ -139,7 +139,7 @@ refcount_order 4 header_length 112 Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data @@ -194,7 +194,7 @@ refcount_order 4 header_length 112 Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data @@ -263,7 +263,7 @@ refcount_order 4 header_length 112 Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data @@ -325,7 +325,7 @@ refcount_order 4 header_length 112 Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data @@ -354,7 +354,7 @@ refcount_order 4 header_length 112 Header extension: -magic 0x6803f857 +magic 0x6803f857 (Feature table) length 336 data diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index 32371e42da..40b5bf467b 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -39,6 +39,12 @@ class Flags64(Qcow2Field): return str(bits) +class Enum(Qcow2Field): + + def __str__(self): + return f'{self.value:#x} ({self.mapping.get(self.value, "")})' + + class Qcow2StructMeta(type): # Mapping from c types to python struct format @@ -99,8 +105,17 @@ class Qcow2Struct(metaclass=Qcow2StructMeta): class QcowHeaderExtension(Qcow2Struct): + class Magic(Enum): + mapping = { + 0xe2792aca: 'Backing format', + 0x6803f857: 'Feature table', + 0x0537be77: 'Crypto header', + 0x23852875: 'Bitmaps', + 0x44415441: 'Data file' + } + fields = ( - ('u32', '{:#x}', 'magic'), + ('u32', Magic, 'magic'), ('u32', '{}', 'length') # length bytes of data follows # then padding to next multiply of 8 From 820c6bee534ec3bd61c7d14d7040ec917cc25ab2 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 6 Jun 2020 11:18:06 +0300 Subject: [PATCH 1024/2595] qcow2_format.py: dump bitmaps header extension Add class for bitmap extension and dump its fields. Further work is to dump bitmap directory. Test new functionality inside 291 iotest. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Andrey Shinkevich Message-Id: <20200606081806.23897-14-vsementsov@virtuozzo.com> [eblake: fix iotest output] Signed-off-by: Eric Blake --- tests/qemu-iotests/291 | 4 +++ tests/qemu-iotests/291.out | 33 +++++++++++++++++++++++ tests/qemu-iotests/qcow2_format.py | 42 +++++++++++++++++++++++------- 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/tests/qemu-iotests/291 b/tests/qemu-iotests/291 index 3ca83b9cd1..e0cffc7cb1 100755 --- a/tests/qemu-iotests/291 +++ b/tests/qemu-iotests/291 @@ -62,6 +62,8 @@ $QEMU_IO -c 'w 1M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io $QEMU_IMG bitmap --disable -f $IMGFMT "$TEST_IMG" b1 $QEMU_IMG bitmap --enable -f $IMGFMT "$TEST_IMG" b2 $QEMU_IO -c 'w 2M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io +echo "Check resulting qcow2 header extensions:" +$PYTHON qcow2.py "$TEST_IMG" dump-header-exts echo echo "=== Bitmap preservation not possible to non-qcow2 ===" @@ -88,6 +90,8 @@ $QEMU_IMG bitmap --merge tmp -f $IMGFMT "$TEST_IMG" b0 $QEMU_IMG bitmap --remove --image-opts \ driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG" tmp $QEMU_IMG info "$TEST_IMG" | _filter_img_info --format-specific +echo "Check resulting qcow2 header extensions:" +$PYTHON qcow2.py "$TEST_IMG" dump-header-exts echo echo "=== Check bitmap contents ===" diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out index 8c62017567..ccfcdc5e35 100644 --- a/tests/qemu-iotests/291.out +++ b/tests/qemu-iotests/291.out @@ -14,6 +14,25 @@ wrote 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1048576/1048576 bytes at offset 2097152 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Check resulting qcow2 header extensions: +Header extension: +magic 0xe2792aca (Backing format) +length 5 +data 'qcow2' + +Header extension: +magic 0x6803f857 (Feature table) +length 336 +data + +Header extension: +magic 0x23852875 (Bitmaps) +length 24 +nb_bitmaps 2 +reserved32 0 +bitmap_directory_size 0x40 +bitmap_directory_offset 0x510000 + === Bitmap preservation not possible to non-qcow2 === @@ -65,6 +84,20 @@ Format specific information: granularity: 65536 refcount bits: 16 corrupt: false +Check resulting qcow2 header extensions: +Header extension: +magic 0x6803f857 (Feature table) +length 336 +data + +Header extension: +magic 0x23852875 (Bitmaps) +length 24 +nb_bitmaps 3 +reserved32 0 +bitmap_directory_size 0x60 +bitmap_directory_offset 0x520000 + === Check bitmap contents === diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index 40b5bf467b..0f65fd161d 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -103,6 +103,19 @@ class Qcow2Struct(metaclass=Qcow2StructMeta): print('{:<25} {}'.format(f[2], value_str)) +class Qcow2BitmapExt(Qcow2Struct): + + fields = ( + ('u32', '{}', 'nb_bitmaps'), + ('u32', '{}', 'reserved32'), + ('u64', '{:#x}', 'bitmap_directory_size'), + ('u64', '{:#x}', 'bitmap_directory_offset') + ) + + +QCOW2_EXT_MAGIC_BITMAPS = 0x23852875 + + class QcowHeaderExtension(Qcow2Struct): class Magic(Enum): @@ -110,7 +123,7 @@ class QcowHeaderExtension(Qcow2Struct): 0xe2792aca: 'Backing format', 0x6803f857: 'Feature table', 0x0537be77: 'Crypto header', - 0x23852875: 'Bitmaps', + QCOW2_EXT_MAGIC_BITMAPS: 'Bitmaps', 0x44415441: 'Data file' } @@ -130,8 +143,11 @@ class QcowHeaderExtension(Qcow2Struct): This should be somehow refactored and functionality should be moved to superclass (to allow creation of any qcow2 struct), but then, fields of variable length (data here) should be supported in base class - somehow. So, it's a TODO. We'll see how to properly refactor this when - we have more qcow2 structures. + somehow. Note also, that we probably want to parse different + extensions. Should they be subclasses of this class, or how to do it + better? Should it be something like QAPI union with discriminator field + (magic here). So, it's a TODO. We'll see how to properly refactor this + when we have more qcow2 structures. """ if fd is None: assert all(v is not None for v in (magic, length, data)) @@ -148,15 +164,23 @@ class QcowHeaderExtension(Qcow2Struct): self.data = fd.read(padded) assert self.data is not None - def dump(self): - data = self.data[:self.length] - if all(c in string.printable.encode('ascii') for c in data): - data = f"'{ data.decode('ascii') }'" + if self.magic == QCOW2_EXT_MAGIC_BITMAPS: + self.obj = Qcow2BitmapExt(data=self.data) else: - data = '' + self.obj = None + def dump(self): super().dump() - print(f'{"data":<25} {data}') + + if self.obj is None: + data = self.data[:self.length] + if all(c in string.printable.encode('ascii') for c in data): + data = f"'{ data.decode('ascii') }'" + else: + data = '' + print(f'{"data":<25} {data}') + else: + self.obj.dump() @classmethod def create(cls, magic, data): From adf92f4645ba46726368735916fed763d3e5a09b Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 8 Jun 2020 14:56:29 -0500 Subject: [PATCH 1025/2595] iotests: Fix 291 across more file systems Depending on the granularity of holes and amount of metadata consumed by a file, the 'disk size:' number of 'qemu-img info' is not reliable. Adjust our test to use a different set of filters to avoid spurious failures. Reported-by: Kevin Wolf Fixes: cf2d1203dc Signed-off-by: Eric Blake Message-Id: <20200608195629.3299649-1-eblake@redhat.com> Acked-by: Kevin Wolf [eblake: fix merge conflict] Signed-off-by: Eric Blake --- tests/qemu-iotests/291 | 4 ++-- tests/qemu-iotests/291.out | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/qemu-iotests/291 b/tests/qemu-iotests/291 index e0cffc7cb1..404f8521f7 100755 --- a/tests/qemu-iotests/291 +++ b/tests/qemu-iotests/291 @@ -79,7 +79,7 @@ echo # Only bitmaps from the active layer are copied $QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG.orig" "$TEST_IMG" -$QEMU_IMG info "$TEST_IMG" | _filter_img_info --format-specific +_img_info --format-specific # But we can also merge in bitmaps from other layers. This test is a bit # contrived to cover more code paths, in reality, you could merge directly # into b0 without going through tmp @@ -89,7 +89,7 @@ $QEMU_IMG bitmap --add --merge b0 -b "$TEST_IMG.base" -F $IMGFMT \ $QEMU_IMG bitmap --merge tmp -f $IMGFMT "$TEST_IMG" b0 $QEMU_IMG bitmap --remove --image-opts \ driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG" tmp -$QEMU_IMG info "$TEST_IMG" | _filter_img_info --format-specific +_img_info --format-specific echo "Check resulting qcow2 header extensions:" $PYTHON qcow2.py "$TEST_IMG" dump-header-exts diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out index ccfcdc5e35..08bfaaaa6b 100644 --- a/tests/qemu-iotests/291.out +++ b/tests/qemu-iotests/291.out @@ -43,7 +43,7 @@ qemu-img: Format driver 'raw' does not support bitmaps image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 10 MiB (10485760 bytes) -disk size: 4.39 MiB +cluster_size: 65536 Format specific information: compat: 1.1 compression type: zlib @@ -63,7 +63,7 @@ Format specific information: image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 10 MiB (10485760 bytes) -disk size: 4.48 MiB +cluster_size: 65536 Format specific information: compat: 1.1 compression type: zlib From 93d487807bf8fb9a5867d1a0a77d7afbc26e6c5c Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 4 Jun 2020 11:33:41 +0300 Subject: [PATCH 1026/2595] iotests: 194: wait for migration completion on target too It is possible, that shutdown on target occurs earlier than migration finish. In this case we crash in bdrv_release_dirty_bitmap_locked() on assertion "assert(!bdrv_dirty_bitmap_busy(bitmap));" as we do have busy bitmap, as bitmap migration is ongoing. We'll fix bitmap migration to gracefully cancel on early shutdown soon. Now let's fix iotest 194 to wait migration completion before shutdown. Note that in this test dest_vm.shutdown() is called implicitly, as vms used as context-providers, see __exit__() method of QEMUMachine class. Actually, not waiting migration finish is a wrong thing, but the test started to crash after commit ae00aa239847682 "iotests: 194: test also migration of dirty bitmap", which added dirty bitmaps here. So, Fixes: tag won't hurt. Fixes: ae00aa2398476824f0eca80461da215e7cdc1c3b Reported-by: Thomas Huth Signed-off-by: Vladimir Sementsov-Ogievskiy Tested-by: Thomas Huth Reviewed-by: Eric Blake [eblake: grammar tweak] Message-Id: <20200604083341.26978-1-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- tests/qemu-iotests/194 | 10 ++++++++++ tests/qemu-iotests/194.out | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/tests/qemu-iotests/194 b/tests/qemu-iotests/194 index 3fad7c6c1a..da7c4265ec 100755 --- a/tests/qemu-iotests/194 +++ b/tests/qemu-iotests/194 @@ -87,4 +87,14 @@ with iotests.FilePath('source.img') as source_img_path, \ iotests.log(dest_vm.qmp('nbd-server-stop')) break + iotests.log('Wait for migration completion on target...') + migr_events = (('MIGRATION', {'data': {'status': 'completed'}}), + ('MIGRATION', {'data': {'status': 'failed'}})) + event = dest_vm.events_wait(migr_events) + iotests.log(event, filters=[iotests.filter_qmp_event]) + + iotests.log('Check bitmaps on source:') iotests.log(source_vm.qmp('query-block')['return'][0]['dirty-bitmaps']) + + iotests.log('Check bitmaps on target:') + iotests.log(dest_vm.qmp('query-block')['return'][0]['dirty-bitmaps']) diff --git a/tests/qemu-iotests/194.out b/tests/qemu-iotests/194.out index dd60dcc14f..a51bdb2d4f 100644 --- a/tests/qemu-iotests/194.out +++ b/tests/qemu-iotests/194.out @@ -21,4 +21,9 @@ Gracefully ending the `drive-mirror` job on source... {"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} Stopping the NBD server on destination... {"return": {}} +Wait for migration completion on target... +{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +Check bitmaps on source: +[{"busy": false, "count": 0, "granularity": 65536, "name": "bitmap0", "persistent": false, "recording": true, "status": "active"}] +Check bitmaps on target: [{"busy": false, "count": 0, "granularity": 65536, "name": "bitmap0", "persistent": false, "recording": true, "status": "active"}] From 1db889c71f37d5bad411b2ef83a69739d9d598f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 8 Jun 2020 18:06:11 +0200 Subject: [PATCH 1027/2595] hw/openrisc/openrisc_sim: Add assertion to silence GCC warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling with GCC 10 (Fedora 32) using CFLAGS=-O2 we get: CC or1k-softmmu/hw/openrisc/openrisc_sim.o hw/openrisc/openrisc_sim.c: In function ‘openrisc_sim_init’: hw/openrisc/openrisc_sim.c:87:42: error: ‘cpu_irqs[0]’ may be used uninitialized in this function [-Werror=maybe-uninitialized] 87 | sysbus_connect_irq(s, i, cpu_irqs[i][irq_pin]); | ~~~~~~~~^~~ While humans can tell smp_cpus will always be in the [1, 2] range, (openrisc_sim_machine_init sets mc->max_cpus = 2), the compiler can't. Add an assertion to give the compiler a hint there's no use of uninitialized data. Buglink: https://bugs.launchpad.net/qemu/+bug/1874073 Reported-by: Martin Liška Suggested-by: Peter Maydell Reviewed-by: Thomas Huth Tested-by: Eric Blake Reviewed-by: Eric Blake Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Acked-by: Stafford Horne Message-Id: <20200608160611.16966-1-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/openrisc/openrisc_sim.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index d08ce61811..02f5259e5e 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -134,6 +134,7 @@ static void openrisc_sim_init(MachineState *machine) int n; unsigned int smp_cpus = machine->smp.cpus; + assert(smp_cpus >= 1 && smp_cpus <= 2); for (n = 0; n < smp_cpus; n++) { cpu = OPENRISC_CPU(cpu_create(machine->cpu_type)); if (cpu == NULL) { From fe18e6eecdd45d3dff0c8968cbb07c5e02fbe4c8 Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Mon, 18 May 2020 15:02:38 +0200 Subject: [PATCH 1028/2595] semihosting: remove the pthread include which seems unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This have been introduced by: 8de702cb677c8381fb702cae252d6b69aa4c653b It doesn't seem to be used so remove it. Signed-off-by: KONRAD Frederic Reviewed-by: Philippe Mathieu-Daudé Acked-by: Alex Bennée Message-Id: <1589806958-23511-1-git-send-email-frederic.konrad@adacore.com> Signed-off-by: Laurent Vivier --- hw/semihosting/console.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/semihosting/console.c b/hw/semihosting/console.c index 6346bd7f50..22e7827824 100644 --- a/hw/semihosting/console.c +++ b/hw/semihosting/console.c @@ -23,7 +23,6 @@ #include "exec/exec-all.h" #include "qemu/log.h" #include "chardev/char.h" -#include #include "chardev/char-fe.h" #include "sysemu/sysemu.h" #include "qemu/main-loop.h" From dfae62845961556935c6b8ccbb4285d4688c42b4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2020 10:17:08 -0400 Subject: [PATCH 1029/2595] docker.py/build: support -t and -f arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docker.py command line is subtly different from docker and podman's, in that the tag and Dockerfile are passed via positional arguments. Remove this gratuitous difference and just parse -f and -t. -f was previously used by --extra-files, only keep the long option. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- tests/docker/Makefile.include | 2 +- tests/docker/docker.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index ed46bd98eb..f32a95b488 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -55,7 +55,7 @@ docker-image-%: $(DOCKER_FILES_DIR)/%.docker else docker-image-%: $(DOCKER_FILES_DIR)/%.docker $(call quiet-command,\ - $(DOCKER_SCRIPT) build qemu:$* $< \ + $(DOCKER_SCRIPT) build -t qemu:$* -f $< \ $(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \ $(if $(NOUSER),,--add-current-user) \ $(if $(EXTRA_FILES),--extra-files $(EXTRA_FILES))\ diff --git a/tests/docker/docker.py b/tests/docker/docker.py index 5a9735db78..d96ccc9b19 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -392,16 +392,16 @@ class BuildCommand(SubCommand): help="""Specify a binary that will be copied to the container together with all its dependent libraries""") - parser.add_argument("--extra-files", "-f", nargs='*', + parser.add_argument("--extra-files", nargs='*', help="""Specify files that will be copied in the Docker image, fulfilling the ADD directive from the Dockerfile""") parser.add_argument("--add-current-user", "-u", dest="user", action="store_true", help="Add the current user to image's passwd") - parser.add_argument("tag", + parser.add_argument("-t", dest="tag", help="Image Tag") - parser.add_argument("dockerfile", + parser.add_argument("-f", dest="dockerfile", help="Dockerfile name") def run(self, args, argv): From af509738f8e4400c26d321abeac924efb04fbfa0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2020 12:19:43 -0400 Subject: [PATCH 1030/2595] docker.py/build: support binary files in --extra-files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read the --extra-files in binary mode to avoid encoding errors. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- tests/docker/docker.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/docker/docker.py b/tests/docker/docker.py index d96ccc9b19..e630aae108 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -56,15 +56,19 @@ class EngineEnum(enum.IntEnum): USE_ENGINE = EngineEnum.AUTO +def _bytes_checksum(bytes): + """Calculate a digest string unique to the text content""" + return hashlib.sha1(bytes).hexdigest() + def _text_checksum(text): """Calculate a digest string unique to the text content""" - return hashlib.sha1(text.encode('utf-8')).hexdigest() + return _bytes_checksum(text.encode('utf-8')) def _read_dockerfile(path): return open(path, 'rt', encoding='utf-8').read() def _file_checksum(filename): - return _text_checksum(_read_dockerfile(filename)) + return _bytes_checksum(open(filename, 'rb').read()) def _guess_engine_command(): From 6ed4075c3c06b35cbd8316f2121073c600fcc089 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2020 10:21:18 -0400 Subject: [PATCH 1031/2595] run-coverity-scan: get Coverity token and email from special git config section Support a [coverity] section in .git/config. It can be used to retrieve the token and also, if it is different from user.email, the username of the submitter. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/run-coverity-scan | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/scripts/coverity-scan/run-coverity-scan b/scripts/coverity-scan/run-coverity-scan index 2e067ef5cf..990f75138d 100755 --- a/scripts/coverity-scan/run-coverity-scan +++ b/scripts/coverity-scan/run-coverity-scan @@ -41,9 +41,10 @@ # is intended mainly for internal use by the Docker support # # User-specifiable environment variables: -# COVERITY_TOKEN -- Coverity token +# COVERITY_TOKEN -- Coverity token (default: looks at your +# coverity.token config) # COVERITY_EMAIL -- the email address to use for uploads (default: -# looks at your git user.email config) +# looks at your git coverity.email or user.email config) # COVERITY_BUILD_CMD -- make command (default: 'make -jN' where N is # number of CPUs as determined by 'nproc') # COVERITY_TOOL_BASE -- set to directory to put coverity tools @@ -58,11 +59,11 @@ check_upload_permissions() { # with status 1 if the check failed (usually a bad token); # will exit the script with status 0 if the check indicated that we # can't upload yet (ie we are at quota) - # Assumes that PROJTOKEN, PROJNAME and DRYRUN have been initialized. + # Assumes that COVERITY_TOKEN, PROJNAME and DRYRUN have been initialized. echo "Checking upload permissions..." - if ! up_perm="$(wget https://scan.coverity.com/api/upload_permitted --post-data "token=$PROJTOKEN&project=$PROJNAME" -q -O -)"; then + if ! up_perm="$(wget https://scan.coverity.com/api/upload_permitted --post-data "token=$COVERITY_TOKEN&project=$PROJNAME" -q -O -)"; then echo "Coverity Scan API access denied: bad token?" exit 1 fi @@ -94,20 +95,20 @@ check_upload_permissions() { update_coverity_tools () { # Check for whether we need to download the Coverity tools # (either because we don't have a copy, or because it's out of date) - # Assumes that COVERITY_TOOL_BASE, PROJTOKEN and PROJNAME are set. + # Assumes that COVERITY_TOOL_BASE, COVERITY_TOKEN and PROJNAME are set. mkdir -p "$COVERITY_TOOL_BASE" cd "$COVERITY_TOOL_BASE" echo "Checking for new version of coverity build tools..." - wget https://scan.coverity.com/download/linux64 --post-data "token=$PROJTOKEN&project=$PROJNAME&md5=1" -O coverity_tool.md5.new + wget https://scan.coverity.com/download/linux64 --post-data "token=$COVERITY_TOKEN&project=$PROJNAME&md5=1" -O coverity_tool.md5.new if ! cmp -s coverity_tool.md5 coverity_tool.md5.new; then # out of date md5 or no md5: download new build tool # blow away the old build tool echo "Downloading coverity build tools..." rm -rf coverity_tool coverity_tool.tgz - wget https://scan.coverity.com/download/linux64 --post-data "token=$PROJTOKEN&project=$PROJNAME" -O coverity_tool.tgz + wget https://scan.coverity.com/download/linux64 --post-data "token=$COVERITY_TOKEN&project=$PROJNAME" -O coverity_tool.tgz if ! (cat coverity_tool.md5.new; echo " coverity_tool.tgz") | md5sum -c --status; then echo "Downloaded tarball didn't match md5sum!" exit 1 @@ -205,6 +206,9 @@ while [ "$#" -ge 1 ]; do esac done +if [ -z "$COVERITY_TOKEN" ]; then + COVERITY_TOKEN="$(git config coverity.token)" +fi if [ -z "$COVERITY_TOKEN" ]; then echo "COVERITY_TOKEN environment variable not set" exit 1 @@ -225,7 +229,6 @@ if [ -z "$SRCDIR" ]; then SRCDIR="$PWD" fi -PROJTOKEN="$COVERITY_TOKEN" PROJNAME=QEMU TARBALL=cov-int.tar.xz @@ -268,6 +271,9 @@ if [ -z "$DESCRIPTION" ]; then DESCRIPTION="$(git rev-parse HEAD)" fi +if [ -z "$COVERITY_EMAIL" ]; then + COVERITY_EMAIL="$(git config coverity.email)" +fi if [ -z "$COVERITY_EMAIL" ]; then COVERITY_EMAIL="$(git config user.email)" fi @@ -393,7 +399,7 @@ if [ "$DRYRUN" = yes ]; then exit 0 fi -curl --form token="$PROJTOKEN" --form email="$COVERITY_EMAIL" \ +curl --form token="$COVERITY_TOKEN" --form email="$COVERITY_EMAIL" \ --form file=@"$TARBALL" --form version="$VERSION" \ --form description="$DESCRIPTION" \ https://scan.coverity.com/builds?project="$PROJNAME" From 726590594071a458643a00160aa659dd5f663b72 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2020 10:38:57 -0400 Subject: [PATCH 1032/2595] run-coverity-scan: use docker.py Our trusted docker wrapper allows run-coverity-scan to run with both docker and podman. For the "run" phase this is transparent; for the "build" phase however scripts are replaced with a bind mount (-v). This is not an issue because the secret option is meant for secrets stored globally in the system and bind mounts are a valid substitute for secrets that are known to whoever builds the container. Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/coverity-scan.docker | 2 +- scripts/coverity-scan/run-coverity-scan | 32 ++++++++++++++-------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/scripts/coverity-scan/coverity-scan.docker b/scripts/coverity-scan/coverity-scan.docker index a4f64d1283..6f0460b66c 100644 --- a/scripts/coverity-scan/coverity-scan.docker +++ b/scripts/coverity-scan/coverity-scan.docker @@ -128,4 +128,4 @@ RUN rpm -q $PACKAGES | sort > /packages.txt ENV PATH $PATH:/usr/libexec/python3-sphinx/ ENV COVERITY_TOOL_BASE=/coverity-tools COPY run-coverity-scan run-coverity-scan -RUN --mount=type=secret,id=coverity.token,required ./run-coverity-scan --update-tools-only --tokenfile /run/secrets/coverity.token +RUN ./run-coverity-scan --update-tools-only --tokenfile /work/token diff --git a/scripts/coverity-scan/run-coverity-scan b/scripts/coverity-scan/run-coverity-scan index 990f75138d..e926623b3b 100755 --- a/scripts/coverity-scan/run-coverity-scan +++ b/scripts/coverity-scan/run-coverity-scan @@ -29,7 +29,9 @@ # Command line options: # --dry-run : run the tools, but don't actually do the upload -# --docker : create and work inside a docker container +# --docker : create and work inside a container +# --docker-engine : specify the container engine to use (docker/podman/auto); +# implies --docker # --update-tools-only : update the cached copy of the tools, but don't run them # --tokenfile : file to read Coverity token from # --version ver : specify version being analyzed (default: ask git) @@ -197,6 +199,17 @@ while [ "$#" -ge 1 ]; do ;; --docker) DOCKER=yes + DOCKER_ENGINE=auto + shift + ;; + --docker-engine) + shift + if [ $# -eq 0 ]; then + echo "--docker-engine needs an argument" + exit 1 + fi + DOCKER=yes + DOCKER_ENGINE="$1" shift ;; *) @@ -283,9 +296,8 @@ if [ "$DOCKER" = yes ]; then # build docker container including the coverity-scan tools # Put the Coverity token into a temporary file that only # we have read access to, and then pass it to docker build - # using --secret. This requires at least Docker 18.09. - # Mostly what we are trying to do here is ensure we don't leak - # the token into the Docker image. + # using a volume. A volume is enough for the token not to + # leak into the Docker image. umask 077 SECRETDIR=$(mktemp -d) if [ -z "$SECRETDIR" ]; then @@ -300,12 +312,10 @@ if [ "$DOCKER" = yes ]; then # TODO: This re-downloads the tools every time, rather than # caching and reusing the image produced with the downloaded tools. # Not sure why. - # TODO: how do you get 'docker build' to print the output of the - # commands it is running to its stdout? This would be useful for debug. - DOCKER_BUILDKIT=1 docker build -t coverity-scanner \ - --secret id=coverity.token,src="$SECRET" \ - -f scripts/coverity-scan/coverity-scan.docker \ - scripts/coverity-scan + tests/docker/docker.py --engine ${DOCKER_ENGINE} build \ + -t coverity-scanner -f scripts/coverity-scan/coverity-scan.docker \ + -v "$SECRETDIR:/work" \ + --extra-files scripts/coverity-scan/run-coverity-scan echo "Archiving sources to be analyzed..." ./scripts/archive-source.sh "$SECRETDIR/qemu-sources.tgz" if [ "$DRYRUN" = yes ]; then @@ -323,7 +333,7 @@ if [ "$DOCKER" = yes ]; then # Arrange for this docker run to get access to the sources with -v. # We pass through all the configuration from the outer script to the inner. export COVERITY_EMAIL COVERITY_BUILD_CMD - docker run -it --env COVERITY_EMAIL --env COVERITY_BUILD_CMD \ + tests/docker/docker.py run -it --env COVERITY_EMAIL --env COVERITY_BUILD_CMD \ -v "$SECRETDIR:/work" coverity-scanner \ ./run-coverity-scan --version "$VERSION" \ --description "$DESCRIPTION" $DRYRUNARG --tokenfile /work/token \ From b99b007905f06042435ebc6fbcbe66ee34a7b596 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2020 11:37:55 -0400 Subject: [PATCH 1033/2595] run-coverity-scan: add --no-update-tools option Provide a quick way to skip building the container while we figure out how to get caching right. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/run-coverity-scan | 37 +++++++++++++++---------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/scripts/coverity-scan/run-coverity-scan b/scripts/coverity-scan/run-coverity-scan index e926623b3b..bc9e12670b 100755 --- a/scripts/coverity-scan/run-coverity-scan +++ b/scripts/coverity-scan/run-coverity-scan @@ -33,6 +33,7 @@ # --docker-engine : specify the container engine to use (docker/podman/auto); # implies --docker # --update-tools-only : update the cached copy of the tools, but don't run them +# --no-update-tools : do not update the cached copy of the tools # --tokenfile : file to read Coverity token from # --version ver : specify version being analyzed (default: ask git) # --description desc : specify description of this version (default: ask git) @@ -130,7 +131,7 @@ update_coverity_tools () { # Check user-provided environment variables and arguments DRYRUN=no -UPDATE_ONLY=no +UPDATE=yes DOCKER=no while [ "$#" -ge 1 ]; do @@ -139,9 +140,13 @@ while [ "$#" -ge 1 ]; do shift DRYRUN=yes ;; + --no-update-tools) + shift + UPDATE=no + ;; --update-tools-only) shift - UPDATE_ONLY=yes + UPDATE=only ;; --version) shift @@ -245,12 +250,12 @@ fi PROJNAME=QEMU TARBALL=cov-int.tar.xz -if [ "$UPDATE_ONLY" = yes ] && [ "$DOCKER" = yes ]; then +if [ "$UPDATE" = only ] && [ "$DOCKER" = yes ]; then echo "Combining --docker and --update-only is not supported" exit 1 fi -if [ "$UPDATE_ONLY" = yes ]; then +if [ "$UPDATE" = only ]; then # Just do the tools update; we don't need to check whether # we are in a source tree or have upload rights for this, # so do it before some of the command line and source tree checks. @@ -293,7 +298,6 @@ fi # Run ourselves inside docker if that's what the user wants if [ "$DOCKER" = yes ]; then - # build docker container including the coverity-scan tools # Put the Coverity token into a temporary file that only # we have read access to, and then pass it to docker build # using a volume. A volume is enough for the token not to @@ -308,14 +312,17 @@ if [ "$DOCKER" = yes ]; then echo "Created temporary directory $SECRETDIR" SECRET="$SECRETDIR/token" echo "$COVERITY_TOKEN" > "$SECRET" - echo "Building docker container..." - # TODO: This re-downloads the tools every time, rather than - # caching and reusing the image produced with the downloaded tools. - # Not sure why. - tests/docker/docker.py --engine ${DOCKER_ENGINE} build \ - -t coverity-scanner -f scripts/coverity-scan/coverity-scan.docker \ - -v "$SECRETDIR:/work" \ - --extra-files scripts/coverity-scan/run-coverity-scan + if [ "$UPDATE" != no ]; then + # build docker container including the coverity-scan tools + echo "Building docker container..." + # TODO: This re-downloads the tools every time, rather than + # caching and reusing the image produced with the downloaded tools. + # Not sure why. + tests/docker/docker.py --engine ${DOCKER_ENGINE} build \ + -t coverity-scanner -f scripts/coverity-scan/coverity-scan.docker \ + -v "$SECRETDIR:/work" \ + --extra-files scripts/coverity-scan/run-coverity-scan + fi echo "Archiving sources to be analyzed..." ./scripts/archive-source.sh "$SECRETDIR/qemu-sources.tgz" if [ "$DRYRUN" = yes ]; then @@ -350,7 +357,9 @@ fi check_upload_permissions -update_coverity_tools +if [ "$UPDATE" != no ]; then + update_coverity_tools +fi TOOLBIN="$(cd "$COVERITY_TOOL_BASE" && echo $PWD/coverity_tool/cov-analysis-*/bin)" From 3077453cf965c999ae0aaab46c566edf74f8e0b4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2020 11:43:14 -0400 Subject: [PATCH 1034/2595] run-coverity-scan: use --no-update-tools in docker run Tools are already updated via the docker build. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/run-coverity-scan | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/coverity-scan/run-coverity-scan b/scripts/coverity-scan/run-coverity-scan index bc9e12670b..6bb38b4f48 100755 --- a/scripts/coverity-scan/run-coverity-scan +++ b/scripts/coverity-scan/run-coverity-scan @@ -325,17 +325,16 @@ if [ "$DOCKER" = yes ]; then fi echo "Archiving sources to be analyzed..." ./scripts/archive-source.sh "$SECRETDIR/qemu-sources.tgz" + ARGS="--no-update-tools" if [ "$DRYRUN" = yes ]; then - DRYRUNARG=--dry-run + ARGS="$ARGS --dry-run" fi echo "Running scanner..." # If we need to capture the output tarball, get the inner run to # save it to the secrets directory so we can copy it out before the # directory is cleaned up. if [ ! -z "$RESULTSTARBALL" ]; then - RTARGS="--results-tarball /work/cov-int.tar.xz" - else - RTARGS="" + ARGS="$ARGS --results-tarball /work/cov-int.tar.xz" fi # Arrange for this docker run to get access to the sources with -v. # We pass through all the configuration from the outer script to the inner. @@ -343,8 +342,8 @@ if [ "$DOCKER" = yes ]; then tests/docker/docker.py run -it --env COVERITY_EMAIL --env COVERITY_BUILD_CMD \ -v "$SECRETDIR:/work" coverity-scanner \ ./run-coverity-scan --version "$VERSION" \ - --description "$DESCRIPTION" $DRYRUNARG --tokenfile /work/token \ - --srcdir /qemu --src-tarball /work/qemu-sources.tgz $RTARGS + --description "$DESCRIPTION" $ARGS --tokenfile /work/token \ + --srcdir /qemu --src-tarball /work/qemu-sources.tgz if [ ! -z "$RESULTSTARBALL" ]; then echo "Copying results tarball to $RESULTSTARBALL..." cp "$SECRETDIR/cov-int.tar.xz" "$RESULTSTARBALL" From 2e90470e90d660ed03321ba677fba2d5208bc6e4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2020 11:49:40 -0400 Subject: [PATCH 1035/2595] run-coverity-scan: download tools outside the container This lets us look at coverity_tool.md5 across executions of run-coverity-scan and skip the download. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/coverity-scan.docker | 3 +- scripts/coverity-scan/run-coverity-scan | 42 +++++++++++----------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/scripts/coverity-scan/coverity-scan.docker b/scripts/coverity-scan/coverity-scan.docker index 6f0460b66c..efcf63224d 100644 --- a/scripts/coverity-scan/coverity-scan.docker +++ b/scripts/coverity-scan/coverity-scan.docker @@ -127,5 +127,6 @@ RUN dnf install -y $PACKAGES RUN rpm -q $PACKAGES | sort > /packages.txt ENV PATH $PATH:/usr/libexec/python3-sphinx/ ENV COVERITY_TOOL_BASE=/coverity-tools +COPY coverity_tool.tgz coverity_tool.tgz +RUN mkdir -p /coverity-tools/coverity_tool && cd /coverity-tools/coverity_tool && tar xf /coverity_tool.tgz COPY run-coverity-scan run-coverity-scan -RUN ./run-coverity-scan --update-tools-only --tokenfile /work/token diff --git a/scripts/coverity-scan/run-coverity-scan b/scripts/coverity-scan/run-coverity-scan index 6bb38b4f48..8bff952bf5 100755 --- a/scripts/coverity-scan/run-coverity-scan +++ b/scripts/coverity-scan/run-coverity-scan @@ -116,15 +116,17 @@ update_coverity_tools () { echo "Downloaded tarball didn't match md5sum!" exit 1 fi - # extract the new one, keeping it corralled in a 'coverity_tool' directory - echo "Unpacking coverity build tools..." - mkdir -p coverity_tool - cd coverity_tool - tar xf ../coverity_tool.tgz - cd .. - mv coverity_tool.md5.new coverity_tool.md5 - fi + if [ "$DOCKER" != yes ]; then + # extract the new one, keeping it corralled in a 'coverity_tool' directory + echo "Unpacking coverity build tools..." + mkdir -p coverity_tool + cd coverity_tool + tar xf ../coverity_tool.tgz + cd .. + mv coverity_tool.md5.new coverity_tool.md5 + fi + fi rm -f coverity_tool.md5.new } @@ -296,6 +298,14 @@ if [ -z "$COVERITY_EMAIL" ]; then COVERITY_EMAIL="$(git config user.email)" fi +# Otherwise, continue with the full build and upload process. + +check_upload_permissions + +if [ "$UPDATE" != no ]; then + update_coverity_tools +fi + # Run ourselves inside docker if that's what the user wants if [ "$DOCKER" = yes ]; then # Put the Coverity token into a temporary file that only @@ -315,13 +325,13 @@ if [ "$DOCKER" = yes ]; then if [ "$UPDATE" != no ]; then # build docker container including the coverity-scan tools echo "Building docker container..." - # TODO: This re-downloads the tools every time, rather than - # caching and reusing the image produced with the downloaded tools. + # TODO: This re-unpacks the tools every time, rather than caching + # and reusing the image produced by the COPY of the .tgz file. # Not sure why. tests/docker/docker.py --engine ${DOCKER_ENGINE} build \ -t coverity-scanner -f scripts/coverity-scan/coverity-scan.docker \ - -v "$SECRETDIR:/work" \ - --extra-files scripts/coverity-scan/run-coverity-scan + --extra-files scripts/coverity-scan/run-coverity-scan \ + "$COVERITY_TOOL_BASE"/coverity_tool.tgz fi echo "Archiving sources to be analyzed..." ./scripts/archive-source.sh "$SECRETDIR/qemu-sources.tgz" @@ -352,14 +362,6 @@ if [ "$DOCKER" = yes ]; then exit 0 fi -# Otherwise, continue with the full build and upload process. - -check_upload_permissions - -if [ "$UPDATE" != no ]; then - update_coverity_tools -fi - TOOLBIN="$(cd "$COVERITY_TOOL_BASE" && echo $PWD/coverity_tool/cov-analysis-*/bin)" if ! test -x "$TOOLBIN/cov-build"; then From fbb84f074174aa3bb6fde4a63b569a1f7e64f264 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2020 10:38:57 -0400 Subject: [PATCH 1036/2595] run-coverity-scan: support --update-tools-only --docker Just build the container when run-coverity-scan is invoked with --update-tools-only --docker. This requires moving the "docker build" logic into the update_coverity_tools function. The only snag is that --update-tools-only --docker requires access to the dockerfile. For now just report an error for --src-tarball, and "docker build" will fail if not in a source tree. Another possibility could be to host our container images on a public registry, and use "FROM qemu:fedora" to make the Dockerfile small enough that it can be included directly in the run-coverity-scan script. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/run-coverity-scan | 39 +++++++++++++++---------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/scripts/coverity-scan/run-coverity-scan b/scripts/coverity-scan/run-coverity-scan index 8bff952bf5..03a791dec9 100755 --- a/scripts/coverity-scan/run-coverity-scan +++ b/scripts/coverity-scan/run-coverity-scan @@ -95,6 +95,18 @@ check_upload_permissions() { } +build_docker_image() { + # build docker container including the coverity-scan tools + echo "Building docker container..." + # TODO: This re-unpacks the tools every time, rather than caching + # and reusing the image produced by the COPY of the .tgz file. + # Not sure why. + tests/docker/docker.py --engine ${DOCKER_ENGINE} build \ + -t coverity-scanner -f scripts/coverity-scan/coverity-scan.docker \ + --extra-files scripts/coverity-scan/run-coverity-scan \ + "$COVERITY_TOOL_BASE"/coverity_tool.tgz +} + update_coverity_tools () { # Check for whether we need to download the Coverity tools # (either because we don't have a copy, or because it's out of date) @@ -128,6 +140,11 @@ update_coverity_tools () { fi fi rm -f coverity_tool.md5.new + cd "$SRCDIR" + + if [ "$DOCKER" = yes ]; then + build_docker_image + fi } @@ -252,15 +269,16 @@ fi PROJNAME=QEMU TARBALL=cov-int.tar.xz -if [ "$UPDATE" = only ] && [ "$DOCKER" = yes ]; then - echo "Combining --docker and --update-only is not supported" - exit 1 -fi - if [ "$UPDATE" = only ]; then # Just do the tools update; we don't need to check whether # we are in a source tree or have upload rights for this, # so do it before some of the command line and source tree checks. + + if [ "$DOCKER" = yes ] && [ ! -z "$SRCTARBALL" ]; then + echo --update-tools-only --docker is incompatible with --src-tarball. + exit 1 + fi + update_coverity_tools exit 0 fi @@ -322,17 +340,6 @@ if [ "$DOCKER" = yes ]; then echo "Created temporary directory $SECRETDIR" SECRET="$SECRETDIR/token" echo "$COVERITY_TOKEN" > "$SECRET" - if [ "$UPDATE" != no ]; then - # build docker container including the coverity-scan tools - echo "Building docker container..." - # TODO: This re-unpacks the tools every time, rather than caching - # and reusing the image produced by the COPY of the .tgz file. - # Not sure why. - tests/docker/docker.py --engine ${DOCKER_ENGINE} build \ - -t coverity-scanner -f scripts/coverity-scan/coverity-scan.docker \ - --extra-files scripts/coverity-scan/run-coverity-scan \ - "$COVERITY_TOOL_BASE"/coverity_tool.tgz - fi echo "Archiving sources to be analyzed..." ./scripts/archive-source.sh "$SECRETDIR/qemu-sources.tgz" ARGS="--no-update-tools" From 59d55a16edfac087248dc60dd9525bdfcc057bb1 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 11 May 2020 10:11:02 -0400 Subject: [PATCH 1037/2595] vl.c: run preconfig loop before creating default RAM backend Default RAM backend depends on numa_uses_legacy_mem(), which is infulenced by -numa options on CLI or set-numa-node QMP command at preconfig time. If QEMU is started with '-preconfig' without -numa, it will lead to creating default RAM backend even if later set-numa-node is used to assing RAM to NUMA nodes using 'memdev' NUMA option. That at best will waste RAM object created by default and with next patch adding a check to prevent usage of conflicting '-M memory-backend' and '-numa memdev' options, it will make QEMU error out if user tries to configure NUMA at preconfig time with memdev option, making set-numa-node unusable. To fix issue, move preconfig loop before default RAM backend is created, so that numa_uses_legacy_mem() would take into account effects of set-numa-node commands executed at preconfig time. Signed-off-by: Igor Mammedov Message-Id: <20200511141103.43768-2-imammedo@redhat.com> Signed-off-by: Paolo Bonzini --- softmmu/vl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index 05d1a4cb6b..055472da66 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -4334,12 +4334,13 @@ void qemu_init(int argc, char **argv, char **envp) parse_numa_opts(current_machine); + /* do monitor/qmp handling at preconfig state if requested */ + qemu_main_loop(); + if (machine_class->default_ram_id && current_machine->ram_size && numa_uses_legacy_mem() && !current_machine->ram_memdev_id) { create_default_memdev(current_machine, mem_path); } - /* do monitor/qmp handling at preconfig state if requested */ - qemu_main_loop(); audio_init_audiodevs(); From ea81f98bce48fc424960ca180fe2ccad0427bfc7 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 11 May 2020 10:11:03 -0400 Subject: [PATCH 1038/2595] numa: prevent usage of -M memory-backend and -numa memdev at the same time Options -M memory-backend and -numa memdev are mutually exclusive, and if used together, it might lead to a crash in the worst case. For example when the same backend is used with these options together: -m 4G \ -object memory-backend-ram,id=mem0,size=4G \ -M pc,memory-backend=mem0 \ -numa node,memdev=mem0 QEMU will abort with: exec.c:2006: qemu_ram_set_idstr: Assertion `!new_block->idstr[0]' failed. and following backtrace: abort () qemu_ram_set_idstr () vmstate_register_ram () vmstate_register_ram_global () machine_consume_memdev () numa_init_memdev_container () numa_complete_configuration () machine_run_board_init () add a check to error out in case the user tries to use both options at the same time. Signed-off-by: Igor Mammedov Message-Id: <20200511141103.43768-3-imammedo@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/numa.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/core/numa.c b/hw/core/numa.c index 316bc50d75..5f81900f88 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -757,6 +757,11 @@ void numa_complete_configuration(MachineState *ms) } if (!numa_uses_legacy_mem() && mc->default_ram_id) { + if (ms->ram_memdev_id) { + error_report("'-machine memory-backend' and '-numa memdev'" + " properties are mutually exclusive"); + exit(1); + } ms->ram = g_new(MemoryRegion, 1); memory_region_init(ms->ram, OBJECT(ms), mc->default_ram_id, ram_size); From b8164e68e5f91325821d413fec84b9a0956e95bb Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 19 May 2020 13:43:20 +0300 Subject: [PATCH 1039/2595] icount: fix shift=auto for record/replay This patch fixes shift=auto when record/replay is enabled. Now user does not need to guess the best shift value. Signed-off-by: Pavel Dovgalyuk -- v2: moved icount_time_shift to vmstate subsection Message-Id: <158988500050.15192.692077802469400393.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- cpus.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cpus.c b/cpus.c index 5670c96bcf..7ce0d569b3 100644 --- a/cpus.c +++ b/cpus.c @@ -379,7 +379,8 @@ static void icount_adjust(void) seqlock_write_lock(&timers_state.vm_clock_seqlock, &timers_state.vm_clock_lock); - cur_time = cpu_get_clock_locked(); + cur_time = REPLAY_CLOCK_LOCKED(REPLAY_CLOCK_VIRTUAL_RT, + cpu_get_clock_locked()); cur_icount = cpu_get_icount_locked(); delta = cur_icount - cur_time; @@ -647,6 +648,11 @@ static bool adjust_timers_state_needed(void *opaque) return s->icount_rt_timer != NULL; } +static bool shift_state_needed(void *opaque) +{ + return use_icount == 2; +} + /* * Subsection for warp timer migration is optional, because may not be created */ @@ -674,6 +680,17 @@ static const VMStateDescription icount_vmstate_adjust_timers = { } }; +static const VMStateDescription icount_vmstate_shift = { + .name = "timer/icount/shift", + .version_id = 1, + .minimum_version_id = 1, + .needed = shift_state_needed, + .fields = (VMStateField[]) { + VMSTATE_INT16(icount_time_shift, TimersState), + VMSTATE_END_OF_LIST() + } +}; + /* * This is a subsection for icount migration. */ @@ -690,6 +707,7 @@ static const VMStateDescription icount_vmstate_timers = { .subsections = (const VMStateDescription*[]) { &icount_vmstate_warp_timer, &icount_vmstate_adjust_timers, + &icount_vmstate_shift, NULL } }; From 4a39181db284167111ff1b27bffe7599543e930f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 4 Apr 2020 17:33:40 +0200 Subject: [PATCH 1040/2595] qom/object: Fix object_child_foreach_recursive() return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When recursing, the return value of do_object_child_foreach() is not taken into account. Cc: Peter Crosthwaite Fixes: d714b8de7747 ("qom: Add recursive version of object_child_for_each") Signed-off-by: Cédric Le Goater Reviewed-by: Marc-André Lureau Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200404153340.164861-1-clg@kaod.org> Signed-off-by: Paolo Bonzini --- qom/object.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qom/object.c b/qom/object.c index d0be42c8d6..484465f1c8 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1051,7 +1051,10 @@ static int do_object_child_foreach(Object *obj, break; } if (recurse) { - do_object_child_foreach(child, fn, opaque, true); + ret = do_object_child_foreach(child, fn, opaque, true); + if (ret != 0) { + break; + } } } } From ce8540fde2cb535923a52a012f57b418eea85e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 17 May 2020 13:01:47 +0200 Subject: [PATCH 1041/2595] target/i386: Fix OUTL debug output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix OUTL instructions incorrectly displayed as OUTW. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200517110147.26026-1-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- target/i386/misc_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/misc_helper.c b/target/i386/misc_helper.c index 7d61221024..b6b1d41b14 100644 --- a/target/i386/misc_helper.c +++ b/target/i386/misc_helper.c @@ -70,7 +70,7 @@ target_ulong helper_inw(CPUX86State *env, uint32_t port) void helper_outl(CPUX86State *env, uint32_t port, uint32_t data) { #ifdef CONFIG_USER_ONLY - fprintf(stderr, "outw: port=0x%04x, data=%08x\n", port, data); + fprintf(stderr, "outl: port=0x%04x, data=%08x\n", port, data); #else address_space_stl(&address_space_io, port, data, cpu_get_mem_attrs(env), NULL); From ca27b5eb7cdd112ed465bd757358af4c06e135ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 13:56:54 +0200 Subject: [PATCH 1042/2595] qom/object: Move Object typedef to 'qemu/typedefs.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use the Object type all over the place. Forward declare it in "qemu/typedefs.h". Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200504115656.6045-2-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/block/vhost-user-blk.c | 1 - hw/pci-host/pam.c | 1 - hw/scsi/vhost-user-scsi.c | 1 - include/hw/display/edid.h | 3 --- include/qemu/typedefs.h | 1 + include/qom/object.h | 2 -- include/qom/qom-qobject.h | 2 -- include/sysemu/sysemu.h | 1 - stubs/qmp_memory_device.c | 1 - 9 files changed, 1 insertion(+), 12 deletions(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 9d8c0b3909..98941019a2 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -20,7 +20,6 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/cutils.h" -#include "qom/object.h" #include "hw/qdev-core.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost.h" diff --git a/hw/pci-host/pam.c b/hw/pci-host/pam.c index 45c4333cd3..a496205783 100644 --- a/hw/pci-host/pam.c +++ b/hw/pci-host/pam.c @@ -28,7 +28,6 @@ */ #include "qemu/osdep.h" -#include "qom/object.h" #include "hw/pci-host/pam.h" void init_pam(DeviceState *dev, MemoryRegion *ram_memory, diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index cbb5d97599..f2e524438a 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "qom/object.h" #include "hw/fw-path-provider.h" #include "hw/qdev-core.h" #include "hw/qdev-properties.h" diff --git a/include/hw/display/edid.h b/include/hw/display/edid.h index 23371ee82c..5b1de57f24 100644 --- a/include/hw/display/edid.h +++ b/include/hw/display/edid.h @@ -1,9 +1,6 @@ #ifndef EDID_H #define EDID_H -#include "qom/object.h" -#include "hw/qdev-properties.h" - typedef struct qemu_edid_info { const char *vendor; /* http://www.uefi.org/pnp_id_list */ const char *name; diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index ecf3cde26c..de68d51d52 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -76,6 +76,7 @@ typedef struct NetFilterState NetFilterState; typedef struct NICInfo NICInfo; typedef struct NodeInfo NodeInfo; typedef struct NumaNodeMem NumaNodeMem; +typedef struct Object Object; typedef struct ObjectClass ObjectClass; typedef struct PCIBridge PCIBridge; typedef struct PCIBus PCIBus; diff --git a/include/qom/object.h b/include/qom/object.h index fd453dc8d6..c7c97ead60 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -20,8 +20,6 @@ struct TypeImpl; typedef struct TypeImpl *Type; -typedef struct Object Object; - typedef struct TypeInfo TypeInfo; typedef struct InterfaceClass InterfaceClass; diff --git a/include/qom/qom-qobject.h b/include/qom/qom-qobject.h index 77cd717e3f..82136e6e80 100644 --- a/include/qom/qom-qobject.h +++ b/include/qom/qom-qobject.h @@ -13,8 +13,6 @@ #ifndef QEMU_QOM_QOBJECT_H #define QEMU_QOM_QOBJECT_H -#include "qom/object.h" - /* * object_property_get_qobject: * @obj: the object diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 3efccdba7e..4b6a5c459c 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -5,7 +5,6 @@ #include "qemu/timer.h" #include "qemu/notify.h" #include "qemu/uuid.h" -#include "qom/object.h" /* vl.c */ diff --git a/stubs/qmp_memory_device.c b/stubs/qmp_memory_device.c index 85ff8f2d7e..e75cac62dc 100644 --- a/stubs/qmp_memory_device.c +++ b/stubs/qmp_memory_device.c @@ -1,5 +1,4 @@ #include "qemu/osdep.h" -#include "qom/object.h" #include "hw/mem/memory-device.h" MemoryDeviceInfoList *qmp_memory_device_list(void) From 78f8d4975c5d035e2e2447e6e499629b96142db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 13:56:55 +0200 Subject: [PATCH 1043/2595] io/task: Move 'qom/object.h' header to source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need "qom/object.h" to call object_ref()/object_unref(), and to test the TYPE_DUMMY. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200504115656.6045-3-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- include/io/task.h | 2 -- io/task.c | 1 + tests/test-io-task.c | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/io/task.h b/include/io/task.h index 1abbfb8b65..6818dfedd0 100644 --- a/include/io/task.h +++ b/include/io/task.h @@ -21,8 +21,6 @@ #ifndef QIO_TASK_H #define QIO_TASK_H -#include "qom/object.h" - typedef struct QIOTask QIOTask; typedef void (*QIOTaskFunc)(QIOTask *task, diff --git a/io/task.c b/io/task.c index 1ae7b86488..53c0bed686 100644 --- a/io/task.c +++ b/io/task.c @@ -22,6 +22,7 @@ #include "io/task.h" #include "qapi/error.h" #include "qemu/thread.h" +#include "qom/object.h" #include "trace.h" struct QIOTaskThreadData { diff --git a/tests/test-io-task.c b/tests/test-io-task.c index aa8b653bfa..c8a3813d49 100644 --- a/tests/test-io-task.c +++ b/tests/test-io-task.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" +#include "qom/object.h" #include "io/task.h" #include "qapi/error.h" #include "qemu/module.h" From fdbff6bd145c1e27520cfe206f04cc664fbb2b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 12:43:45 +0200 Subject: [PATCH 1044/2595] Makefile: Let the 'help' target list the helper targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit List the name of the helper targets when calling 'make help', along with the tool targets: $ make help [...] Helper targets: fsdev/virtfs-proxy-helper - Build virtfs-proxy-helper scsi/qemu-pr-helper - Build qemu-pr-helper qemu-bridge-helper - Build qemu-bridge-helper vhost-user-gpu - Build vhost-user-gpu virtiofsd - Build virtiofsd Tools targets: qemu-ga - Build qemu-ga tool qemu-keymap - Build qemu-keymap tool elf2dmp - Build elf2dmp tool ivshmem-client - Build ivshmem-client tool ivshmem-server - Build ivshmem-server tool qemu-nbd - Build qemu-nbd tool qemu-storage-daemon - Build qemu-storage-daemon tool qemu-img - Build qemu-img tool qemu-io - Build qemu-io tool qemu-edid - Build qemu-edid tool Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- Makefile | 9 +++++++-- configure | 5 +++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index d1af126ea1..ed0ed93b2d 100644 --- a/Makefile +++ b/Makefile @@ -336,9 +336,9 @@ $(call set-vpath, $(SRC_PATH)) LIBS+=-lz $(LIBS_TOOLS) vhost-user-json-y = -HELPERS-y = +HELPERS-y = $(HELPERS) -HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) = qemu-bridge-helper$(EXESUF) +HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) += qemu-bridge-helper$(EXESUF) ifeq ($(CONFIG_LINUX)$(CONFIG_VIRGL)$(CONFIG_GBM)$(CONFIG_TOOLS),yyyy) HELPERS-y += vhost-user-gpu$(EXESUF) @@ -1258,6 +1258,11 @@ endif $(call print-help-run,$(t)/fuzz,Build fuzzer for $(t)); \ ))) \ echo '') + @$(if $(HELPERS-y), \ + echo 'Helper targets:'; \ + $(foreach t, $(HELPERS-y), \ + $(call print-help-run,$(t),Build $(shell basename $(t)));) \ + echo '') @$(if $(TOOLS), \ echo 'Tools targets:'; \ $(foreach t, $(TOOLS), \ diff --git a/configure b/configure index 597e909b53..53a6dd0297 100755 --- a/configure +++ b/configure @@ -6394,7 +6394,7 @@ if test "$softmmu" = yes ; then if test "$linux" = yes; then if test "$virtfs" != no && test "$cap_ng" = yes && test "$attr" = yes ; then virtfs=yes - tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)" + helpers="$helpers fsdev/virtfs-proxy-helper\$(EXESUF)" else if test "$virtfs" = yes; then error_exit "VirtFS requires libcap-ng devel and libattr devel" @@ -6409,7 +6409,7 @@ if test "$softmmu" = yes ; then fi mpath=no fi - tools="$tools scsi/qemu-pr-helper\$(EXESUF)" + helpers="$helpers scsi/qemu-pr-helper\$(EXESUF)" else if test "$virtfs" = yes; then error_exit "VirtFS is supported only on Linux" @@ -7651,6 +7651,7 @@ else QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/\$(ARCH) $QEMU_INCLUDES" fi +echo "HELPERS=$helpers" >> $config_host_mak echo "TOOLS=$tools" >> $config_host_mak echo "ROMS=$roms" >> $config_host_mak echo "MAKE=$make" >> $config_host_mak From d42cd96100724bc9fbac18cc17c5f5f9b9b2f181 Mon Sep 17 00:00:00 2001 From: Jon Doron Date: Fri, 24 Apr 2020 15:34:39 +0300 Subject: [PATCH 1045/2595] hyperv: expose API to determine if synic is enabled Signed-off-by: Jon Doron Message-Id: <20200424123444.3481728-2-arilou@gmail.com> Signed-off-by: Paolo Bonzini --- hw/hyperv/hyperv.c | 8 ++++++++ include/hw/hyperv/hyperv.h | 1 + 2 files changed, 9 insertions(+) diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index 4b11f7a76b..a3933c34c6 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -38,6 +38,13 @@ typedef struct SynICState { #define TYPE_SYNIC "hyperv-synic" #define SYNIC(obj) OBJECT_CHECK(SynICState, (obj), TYPE_SYNIC) +static bool synic_enabled; + +bool hyperv_is_synic_enabled(void) +{ + return synic_enabled; +} + static SynICState *get_synic(CPUState *cs) { return SYNIC(object_resolve_path_component(OBJECT(cs), "synic")); @@ -134,6 +141,7 @@ void hyperv_synic_add(CPUState *cs) object_property_add_child(OBJECT(cs), "synic", obj); object_unref(obj); object_property_set_bool(obj, true, "realized", &error_abort); + synic_enabled = true; } void hyperv_synic_reset(CPUState *cs) diff --git a/include/hw/hyperv/hyperv.h b/include/hw/hyperv/hyperv.h index 597381cb01..a63ee0003c 100644 --- a/include/hw/hyperv/hyperv.h +++ b/include/hw/hyperv/hyperv.h @@ -79,5 +79,6 @@ void hyperv_synic_add(CPUState *cs); void hyperv_synic_reset(CPUState *cs); void hyperv_synic_update(CPUState *cs, bool enable, hwaddr msg_page_addr, hwaddr event_page_addr); +bool hyperv_is_synic_enabled(void); #endif From 973b1fbd862c848dde7f710ba1b9ca340235e75f Mon Sep 17 00:00:00 2001 From: Jon Doron Date: Fri, 24 Apr 2020 15:34:40 +0300 Subject: [PATCH 1046/2595] vmbus: add vmbus protocol definitions Add a header with data structures and constants used in Hyper-V VMBus hypervisor <-> guest interactions. Based on the respective stuff from Linux kernel. Signed-off-by: Roman Kagan Signed-off-by: Maciej S. Szmigiero Signed-off-by: Jon Doron Message-Id: <20200424123444.3481728-3-arilou@gmail.com> Signed-off-by: Paolo Bonzini --- include/hw/hyperv/vmbus-proto.h | 222 ++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 include/hw/hyperv/vmbus-proto.h diff --git a/include/hw/hyperv/vmbus-proto.h b/include/hw/hyperv/vmbus-proto.h new file mode 100644 index 0000000000..4628d3b323 --- /dev/null +++ b/include/hw/hyperv/vmbus-proto.h @@ -0,0 +1,222 @@ +/* + * QEMU Hyper-V VMBus support + * + * Copyright (c) 2017-2018 Virtuozzo International GmbH. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_HYPERV_VMBUS_PROTO_H +#define HW_HYPERV_VMBUS_PROTO_H + +#define VMBUS_VERSION_WS2008 ((0 << 16) | (13)) +#define VMBUS_VERSION_WIN7 ((1 << 16) | (1)) +#define VMBUS_VERSION_WIN8 ((2 << 16) | (4)) +#define VMBUS_VERSION_WIN8_1 ((3 << 16) | (0)) +#define VMBUS_VERSION_WIN10 ((4 << 16) | (0)) +#define VMBUS_VERSION_INVAL -1 +#define VMBUS_VERSION_CURRENT VMBUS_VERSION_WIN10 + +#define VMBUS_MESSAGE_CONNECTION_ID 1 +#define VMBUS_EVENT_CONNECTION_ID 2 +#define VMBUS_MONITOR_CONNECTION_ID 3 +#define VMBUS_SINT 2 + +#define VMBUS_MSG_INVALID 0 +#define VMBUS_MSG_OFFERCHANNEL 1 +#define VMBUS_MSG_RESCIND_CHANNELOFFER 2 +#define VMBUS_MSG_REQUESTOFFERS 3 +#define VMBUS_MSG_ALLOFFERS_DELIVERED 4 +#define VMBUS_MSG_OPENCHANNEL 5 +#define VMBUS_MSG_OPENCHANNEL_RESULT 6 +#define VMBUS_MSG_CLOSECHANNEL 7 +#define VMBUS_MSG_GPADL_HEADER 8 +#define VMBUS_MSG_GPADL_BODY 9 +#define VMBUS_MSG_GPADL_CREATED 10 +#define VMBUS_MSG_GPADL_TEARDOWN 11 +#define VMBUS_MSG_GPADL_TORNDOWN 12 +#define VMBUS_MSG_RELID_RELEASED 13 +#define VMBUS_MSG_INITIATE_CONTACT 14 +#define VMBUS_MSG_VERSION_RESPONSE 15 +#define VMBUS_MSG_UNLOAD 16 +#define VMBUS_MSG_UNLOAD_RESPONSE 17 +#define VMBUS_MSG_COUNT 18 + +#define VMBUS_MESSAGE_SIZE_ALIGN sizeof(uint64_t) + +#define VMBUS_PACKET_INVALID 0x0 +#define VMBUS_PACKET_SYNCH 0x1 +#define VMBUS_PACKET_ADD_XFER_PAGESET 0x2 +#define VMBUS_PACKET_RM_XFER_PAGESET 0x3 +#define VMBUS_PACKET_ESTABLISH_GPADL 0x4 +#define VMBUS_PACKET_TEARDOWN_GPADL 0x5 +#define VMBUS_PACKET_DATA_INBAND 0x6 +#define VMBUS_PACKET_DATA_USING_XFER_PAGES 0x7 +#define VMBUS_PACKET_DATA_USING_GPADL 0x8 +#define VMBUS_PACKET_DATA_USING_GPA_DIRECT 0x9 +#define VMBUS_PACKET_CANCEL_REQUEST 0xa +#define VMBUS_PACKET_COMP 0xb +#define VMBUS_PACKET_DATA_USING_ADDITIONAL_PKT 0xc +#define VMBUS_PACKET_ADDITIONAL_DATA 0xd + +#define VMBUS_CHANNEL_USER_DATA_SIZE 120 + +#define VMBUS_OFFER_MONITOR_ALLOCATED 0x1 +#define VMBUS_OFFER_INTERRUPT_DEDICATED 0x1 + +#define VMBUS_RING_BUFFER_FEAT_PENDING_SZ (1ul << 0) + +#define VMBUS_CHANNEL_ENUMERATE_DEVICE_INTERFACE 0x1 +#define VMBUS_CHANNEL_SERVER_SUPPORTS_TRANSFER_PAGES 0x2 +#define VMBUS_CHANNEL_SERVER_SUPPORTS_GPADLS 0x4 +#define VMBUS_CHANNEL_NAMED_PIPE_MODE 0x10 +#define VMBUS_CHANNEL_LOOPBACK_OFFER 0x100 +#define VMBUS_CHANNEL_PARENT_OFFER 0x200 +#define VMBUS_CHANNEL_REQUEST_MONITORED_NOTIFICATION 0x400 +#define VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER 0x2000 + +#define VMBUS_PACKET_FLAG_REQUEST_COMPLETION 1 + +typedef struct vmbus_message_header { + uint32_t message_type; + uint32_t _padding; +} vmbus_message_header; + +typedef struct vmbus_message_initiate_contact { + vmbus_message_header header; + uint32_t version_requested; + uint32_t target_vcpu; + uint64_t interrupt_page; + uint64_t monitor_page1; + uint64_t monitor_page2; +} vmbus_message_initiate_contact; + +typedef struct vmbus_message_version_response { + vmbus_message_header header; + uint8_t version_supported; + uint8_t status; +} vmbus_message_version_response; + +typedef struct vmbus_message_offer_channel { + vmbus_message_header header; + uint8_t type_uuid[16]; + uint8_t instance_uuid[16]; + uint64_t _reserved1; + uint64_t _reserved2; + uint16_t channel_flags; + uint16_t mmio_size_mb; + uint8_t user_data[VMBUS_CHANNEL_USER_DATA_SIZE]; + uint16_t sub_channel_index; + uint16_t _reserved3; + uint32_t child_relid; + uint8_t monitor_id; + uint8_t monitor_flags; + uint16_t interrupt_flags; + uint32_t connection_id; +} vmbus_message_offer_channel; + +typedef struct vmbus_message_rescind_channel_offer { + vmbus_message_header header; + uint32_t child_relid; +} vmbus_message_rescind_channel_offer; + +typedef struct vmbus_gpa_range { + uint32_t byte_count; + uint32_t byte_offset; + uint64_t pfn_array[]; +} vmbus_gpa_range; + +typedef struct vmbus_message_gpadl_header { + vmbus_message_header header; + uint32_t child_relid; + uint32_t gpadl_id; + uint16_t range_buflen; + uint16_t rangecount; + vmbus_gpa_range range[]; +} QEMU_PACKED vmbus_message_gpadl_header; + +typedef struct vmbus_message_gpadl_body { + vmbus_message_header header; + uint32_t message_number; + uint32_t gpadl_id; + uint64_t pfn_array[]; +} vmbus_message_gpadl_body; + +typedef struct vmbus_message_gpadl_created { + vmbus_message_header header; + uint32_t child_relid; + uint32_t gpadl_id; + uint32_t status; +} vmbus_message_gpadl_created; + +typedef struct vmbus_message_gpadl_teardown { + vmbus_message_header header; + uint32_t child_relid; + uint32_t gpadl_id; +} vmbus_message_gpadl_teardown; + +typedef struct vmbus_message_gpadl_torndown { + vmbus_message_header header; + uint32_t gpadl_id; +} vmbus_message_gpadl_torndown; + +typedef struct vmbus_message_open_channel { + vmbus_message_header header; + uint32_t child_relid; + uint32_t open_id; + uint32_t ring_buffer_gpadl_id; + uint32_t target_vp; + uint32_t ring_buffer_offset; + uint8_t user_data[VMBUS_CHANNEL_USER_DATA_SIZE]; +} vmbus_message_open_channel; + +typedef struct vmbus_message_open_result { + vmbus_message_header header; + uint32_t child_relid; + uint32_t open_id; + uint32_t status; +} vmbus_message_open_result; + +typedef struct vmbus_message_close_channel { + vmbus_message_header header; + uint32_t child_relid; +} vmbus_message_close_channel; + +typedef struct vmbus_ring_buffer { + uint32_t write_index; + uint32_t read_index; + uint32_t interrupt_mask; + uint32_t pending_send_sz; + uint32_t _reserved1[12]; + uint32_t feature_bits; +} vmbus_ring_buffer; + +typedef struct vmbus_packet_hdr { + uint16_t type; + uint16_t offset_qwords; + uint16_t len_qwords; + uint16_t flags; + uint64_t transaction_id; +} vmbus_packet_hdr; + +typedef struct vmbus_pkt_gpa_direct { + uint32_t _reserved; + uint32_t rangecount; + vmbus_gpa_range range[]; +} vmbus_pkt_gpa_direct; + +typedef struct vmbus_xferpg_range { + uint32_t byte_count; + uint32_t byte_offset; +} vmbus_xferpg_range; + +typedef struct vmbus_pkt_xferpg { + uint16_t buffer_id; + uint8_t sender_owns_set; + uint8_t _reserved; + uint32_t rangecount; + vmbus_xferpg_range range[]; +} vmbus_pkt_xferpg; + +#endif From 0d71f7082d7aeec8d9767e32dbf7dd86b94b8260 Mon Sep 17 00:00:00 2001 From: Jon Doron Date: Fri, 24 Apr 2020 15:34:41 +0300 Subject: [PATCH 1047/2595] vmbus: vmbus implementation Add the VMBus infrastructure -- bus, devices, root bridge, vmbus state machine, vmbus channel interactions, etc. VMBus is a collection of technologies. At its lowest layer, it's a message passing and signaling mechanism, allowing efficient passing of messages to and from guest VMs. A layer higher, it's a mechanism for defining channels of communication, where each channel is tagged with a type (which implies a protocol) and a instance ID. A layer higher than that, it's a bus driver, serving as the basis of device enumeration within a VM, where a channel can optionally be exposed as a paravirtual device. When a server-side (paravirtual back-end) component wishes to offer a channel to a guest VM, it does so by specifying a channel type, a mode, and an instance ID. VMBus then exposes this in the guest. More information about VMBus can be found in the file vmbuskernelmodeclientlibapi.h in Microsoft's WDK. TODO: - split into smaller palatable pieces - more comments - check and handle corner cases Kudos to Evgeny Yakovlev (formerly eyakovlev@virtuozzo.com) and Andrey Smetatin (formerly asmetanin@virtuozzo.com) for research and prototyping. Signed-off-by: Roman Kagan Signed-off-by: Maciej S. Szmigiero Signed-off-by: Jon Doron Message-Id: <20200424123444.3481728-4-arilou@gmail.com> Signed-off-by: Paolo Bonzini --- Makefile.objs | 1 + hw/hyperv/Kconfig | 5 + hw/hyperv/Makefile.objs | 1 + hw/hyperv/trace-events | 18 + hw/hyperv/vmbus.c | 2672 ++++++++++++++++++++++++++++++ include/hw/hyperv/vmbus-bridge.h | 32 + include/hw/hyperv/vmbus.h | 227 +++ 7 files changed, 2956 insertions(+) create mode 100644 hw/hyperv/trace-events create mode 100644 hw/hyperv/vmbus.c create mode 100644 include/hw/hyperv/vmbus-bridge.h create mode 100644 include/hw/hyperv/vmbus.h diff --git a/Makefile.objs b/Makefile.objs index 99774cfd25..c09d95dfe3 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -150,6 +150,7 @@ trace-events-subdirs += hw/block/dataplane trace-events-subdirs += hw/char trace-events-subdirs += hw/dma trace-events-subdirs += hw/hppa +trace-events-subdirs += hw/hyperv trace-events-subdirs += hw/i2c trace-events-subdirs += hw/i386 trace-events-subdirs += hw/i386/xen diff --git a/hw/hyperv/Kconfig b/hw/hyperv/Kconfig index a1fa8ff9be..3fbfe41c9e 100644 --- a/hw/hyperv/Kconfig +++ b/hw/hyperv/Kconfig @@ -6,3 +6,8 @@ config HYPERV_TESTDEV bool default y if TEST_DEVICES depends on HYPERV + +config VMBUS + bool + default y + depends on HYPERV diff --git a/hw/hyperv/Makefile.objs b/hw/hyperv/Makefile.objs index edaca2f763..5b614e040c 100644 --- a/hw/hyperv/Makefile.objs +++ b/hw/hyperv/Makefile.objs @@ -1,2 +1,3 @@ obj-y += hyperv.o obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o +obj-$(CONFIG_VMBUS) += vmbus.o diff --git a/hw/hyperv/trace-events b/hw/hyperv/trace-events new file mode 100644 index 0000000000..ba5bd62d61 --- /dev/null +++ b/hw/hyperv/trace-events @@ -0,0 +1,18 @@ +# vmbus +vmbus_recv_message(uint32_t type, uint32_t size) "type %d size %d" +vmbus_signal_event(void) "" +vmbus_channel_notify_guest(uint32_t chan_id) "channel #%d" +vmbus_post_msg(uint32_t type, uint32_t size) "type %d size %d" +vmbus_msg_cb(int status) "message status %d" +vmbus_process_incoming_message(uint32_t message_type) "type %d" +vmbus_initiate_contact(uint16_t major, uint16_t minor, uint32_t vcpu, uint64_t monitor_page1, uint64_t monitor_page2, uint64_t interrupt_page) "version %d.%d target vp %d mon pages 0x%"PRIx64",0x%"PRIx64" int page 0x%"PRIx64 +vmbus_send_offer(uint32_t chan_id, void *dev) "channel #%d dev %p" +vmbus_terminate_offers(void) "" +vmbus_gpadl_header(uint32_t gpadl_id, uint16_t num_gfns) "gpadl #%d gfns %d" +vmbus_gpadl_body(uint32_t gpadl_id) "gpadl #%d" +vmbus_gpadl_created(uint32_t gpadl_id) "gpadl #%d" +vmbus_gpadl_teardown(uint32_t gpadl_id) "gpadl #%d" +vmbus_gpadl_torndown(uint32_t gpadl_id) "gpadl #%d" +vmbus_open_channel(uint32_t chan_id, uint32_t gpadl_id, uint32_t target_vp) "channel #%d gpadl #%d target vp %d" +vmbus_channel_open(uint32_t chan_id, uint32_t status) "channel #%d status %d" +vmbus_close_channel(uint32_t chan_id) "channel #%d" diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c new file mode 100644 index 0000000000..802bbc8c96 --- /dev/null +++ b/hw/hyperv/vmbus.c @@ -0,0 +1,2672 @@ +/* + * QEMU Hyper-V VMBus + * + * Copyright (c) 2017-2018 Virtuozzo International GmbH. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qemu/main-loop.h" +#include "qapi/error.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/hyperv/hyperv.h" +#include "hw/hyperv/vmbus.h" +#include "hw/hyperv/vmbus-bridge.h" +#include "hw/sysbus.h" +#include "cpu.h" +#include "trace.h" + +#define TYPE_VMBUS "vmbus" +#define VMBUS(obj) OBJECT_CHECK(VMBus, (obj), TYPE_VMBUS) + +enum { + VMGPADL_INIT, + VMGPADL_ALIVE, + VMGPADL_TEARINGDOWN, + VMGPADL_TORNDOWN, +}; + +struct VMBusGpadl { + /* GPADL id */ + uint32_t id; + /* associated channel id (rudimentary?) */ + uint32_t child_relid; + + /* number of pages in the GPADL as declared in GPADL_HEADER message */ + uint32_t num_gfns; + /* + * Due to limited message size, GPADL may not fit fully in a single + * GPADL_HEADER message, and is further popluated using GPADL_BODY + * messages. @seen_gfns is the number of pages seen so far; once it + * reaches @num_gfns, the GPADL is ready to use. + */ + uint32_t seen_gfns; + /* array of GFNs (of size @num_gfns once allocated) */ + uint64_t *gfns; + + uint8_t state; + + QTAILQ_ENTRY(VMBusGpadl) link; + VMBus *vmbus; + unsigned refcount; +}; + +/* + * Wrap sequential read from / write to GPADL. + */ +typedef struct GpadlIter { + VMBusGpadl *gpadl; + AddressSpace *as; + DMADirection dir; + /* offset into GPADL where the next i/o will be performed */ + uint32_t off; + /* + * Cached mapping of the currently accessed page, up to page boundary. + * Updated lazily on i/o. + * Note: MemoryRegionCache can not be used here because pages in the GPADL + * are non-contiguous and may belong to different memory regions. + */ + void *map; + /* offset after last i/o (i.e. not affected by seek) */ + uint32_t last_off; + /* + * Indicator that the iterator is active and may have a cached mapping. + * Allows to enforce bracketing of all i/o (which may create cached + * mappings) and thus exclude mapping leaks. + */ + bool active; +} GpadlIter; + +/* + * Ring buffer. There are two of them, sitting in the same GPADL, for each + * channel. + * Each ring buffer consists of a set of pages, with the first page containing + * the ring buffer header, and the remaining pages being for data packets. + */ +typedef struct VMBusRingBufCommon { + AddressSpace *as; + /* GPA of the ring buffer header */ + dma_addr_t rb_addr; + /* start and length of the ring buffer data area within GPADL */ + uint32_t base; + uint32_t len; + + GpadlIter iter; +} VMBusRingBufCommon; + +typedef struct VMBusSendRingBuf { + VMBusRingBufCommon common; + /* current write index, to be committed at the end of send */ + uint32_t wr_idx; + /* write index at the start of send */ + uint32_t last_wr_idx; + /* space to be requested from the guest */ + uint32_t wanted; + /* space reserved for planned sends */ + uint32_t reserved; + /* last seen read index */ + uint32_t last_seen_rd_idx; +} VMBusSendRingBuf; + +typedef struct VMBusRecvRingBuf { + VMBusRingBufCommon common; + /* current read index, to be committed at the end of receive */ + uint32_t rd_idx; + /* read index at the start of receive */ + uint32_t last_rd_idx; + /* last seen write index */ + uint32_t last_seen_wr_idx; +} VMBusRecvRingBuf; + + +enum { + VMOFFER_INIT, + VMOFFER_SENDING, + VMOFFER_SENT, +}; + +enum { + VMCHAN_INIT, + VMCHAN_OPENING, + VMCHAN_OPEN, +}; + +struct VMBusChannel { + VMBusDevice *dev; + + /* channel id */ + uint32_t id; + /* + * subchannel index within the device; subchannel #0 is "primary" and + * always exists + */ + uint16_t subchan_idx; + uint32_t open_id; + /* VP_INDEX of the vCPU to notify with (synthetic) interrupts */ + uint32_t target_vp; + /* GPADL id to use for the ring buffers */ + uint32_t ringbuf_gpadl; + /* start (in pages) of the send ring buffer within @ringbuf_gpadl */ + uint32_t ringbuf_send_offset; + + uint8_t offer_state; + uint8_t state; + bool is_open; + + /* main device worker; copied from the device class */ + VMBusChannelNotifyCb notify_cb; + /* + * guest->host notifications, either sent directly or dispatched via + * interrupt page (older VMBus) + */ + EventNotifier notifier; + + VMBus *vmbus; + /* + * SINT route to signal with host->guest notifications; may be shared with + * the main VMBus SINT route + */ + HvSintRoute *notify_route; + VMBusGpadl *gpadl; + + VMBusSendRingBuf send_ringbuf; + VMBusRecvRingBuf recv_ringbuf; + + QTAILQ_ENTRY(VMBusChannel) link; +}; + +/* + * Hyper-V spec mandates that every message port has 16 buffers, which means + * that the guest can post up to this many messages without blocking. + * Therefore a queue for incoming messages has to be provided. + * For outgoing (i.e. host->guest) messages there's no queue; the VMBus just + * doesn't transition to a new state until the message is known to have been + * successfully delivered to the respective SynIC message slot. + */ +#define HV_MSG_QUEUE_LEN 16 + +/* Hyper-V devices never use channel #0. Must be something special. */ +#define VMBUS_FIRST_CHANID 1 +/* Each channel occupies one bit within a single event page sint slot. */ +#define VMBUS_CHANID_COUNT (HV_EVENT_FLAGS_COUNT - VMBUS_FIRST_CHANID) +/* Leave a few connection numbers for other purposes. */ +#define VMBUS_CHAN_CONNECTION_OFFSET 16 + +/* + * Since the success or failure of sending a message is reported + * asynchronously, the VMBus state machine has effectively two entry points: + * vmbus_run and vmbus_msg_cb (the latter is called when the host->guest + * message delivery status becomes known). Both are run as oneshot BHs on the + * main aio context, ensuring serialization. + */ +enum { + VMBUS_LISTEN, + VMBUS_HANDSHAKE, + VMBUS_OFFER, + VMBUS_CREATE_GPADL, + VMBUS_TEARDOWN_GPADL, + VMBUS_OPEN_CHANNEL, + VMBUS_UNLOAD, + VMBUS_STATE_MAX +}; + +struct VMBus { + BusState parent; + + uint8_t state; + /* protection against recursive aio_poll (see vmbus_run) */ + bool in_progress; + /* whether there's a message being delivered to the guest */ + bool msg_in_progress; + uint32_t version; + /* VP_INDEX of the vCPU to send messages and interrupts to */ + uint32_t target_vp; + HvSintRoute *sint_route; + /* + * interrupt page for older protocol versions; newer ones use SynIC event + * flags directly + */ + hwaddr int_page_gpa; + + DECLARE_BITMAP(chanid_bitmap, VMBUS_CHANID_COUNT); + + /* incoming message queue */ + struct hyperv_post_message_input rx_queue[HV_MSG_QUEUE_LEN]; + uint8_t rx_queue_head; + uint8_t rx_queue_size; + QemuMutex rx_queue_lock; + + QTAILQ_HEAD(, VMBusGpadl) gpadl_list; + QTAILQ_HEAD(, VMBusChannel) channel_list; + + /* + * guest->host notifications for older VMBus, to be dispatched via + * interrupt page + */ + EventNotifier notifier; +}; + +static bool gpadl_full(VMBusGpadl *gpadl) +{ + return gpadl->seen_gfns == gpadl->num_gfns; +} + +static VMBusGpadl *create_gpadl(VMBus *vmbus, uint32_t id, + uint32_t child_relid, uint32_t num_gfns) +{ + VMBusGpadl *gpadl = g_new0(VMBusGpadl, 1); + + gpadl->id = id; + gpadl->child_relid = child_relid; + gpadl->num_gfns = num_gfns; + gpadl->gfns = g_new(uint64_t, num_gfns); + QTAILQ_INSERT_HEAD(&vmbus->gpadl_list, gpadl, link); + gpadl->vmbus = vmbus; + gpadl->refcount = 1; + return gpadl; +} + +static void free_gpadl(VMBusGpadl *gpadl) +{ + QTAILQ_REMOVE(&gpadl->vmbus->gpadl_list, gpadl, link); + g_free(gpadl->gfns); + g_free(gpadl); +} + +static VMBusGpadl *find_gpadl(VMBus *vmbus, uint32_t gpadl_id) +{ + VMBusGpadl *gpadl; + QTAILQ_FOREACH(gpadl, &vmbus->gpadl_list, link) { + if (gpadl->id == gpadl_id) { + return gpadl; + } + } + return NULL; +} + +VMBusGpadl *vmbus_get_gpadl(VMBusChannel *chan, uint32_t gpadl_id) +{ + VMBusGpadl *gpadl = find_gpadl(chan->vmbus, gpadl_id); + if (!gpadl || !gpadl_full(gpadl)) { + return NULL; + } + gpadl->refcount++; + return gpadl; +} + +void vmbus_put_gpadl(VMBusGpadl *gpadl) +{ + if (!gpadl) { + return; + } + if (--gpadl->refcount) { + return; + } + free_gpadl(gpadl); +} + +uint32_t vmbus_gpadl_len(VMBusGpadl *gpadl) +{ + return gpadl->num_gfns * TARGET_PAGE_SIZE; +} + +static void gpadl_iter_init(GpadlIter *iter, VMBusGpadl *gpadl, + AddressSpace *as, DMADirection dir) +{ + iter->gpadl = gpadl; + iter->as = as; + iter->dir = dir; + iter->active = false; +} + +static inline void gpadl_iter_cache_unmap(GpadlIter *iter) +{ + uint32_t map_start_in_page = (uintptr_t)iter->map & ~TARGET_PAGE_MASK; + uint32_t io_end_in_page = ((iter->last_off - 1) & ~TARGET_PAGE_MASK) + 1; + + /* mapping is only done to do non-zero amount of i/o */ + assert(iter->last_off > 0); + assert(map_start_in_page < io_end_in_page); + + dma_memory_unmap(iter->as, iter->map, TARGET_PAGE_SIZE - map_start_in_page, + iter->dir, io_end_in_page - map_start_in_page); +} + +/* + * Copy exactly @len bytes between the GPADL pointed to by @iter and @buf. + * The direction of the copy is determined by @iter->dir. + * The caller must ensure the operation overflows neither @buf nor the GPADL + * (there's an assert for the latter). + * Reuse the currently mapped page in the GPADL if possible. + */ +static ssize_t gpadl_iter_io(GpadlIter *iter, void *buf, uint32_t len) +{ + ssize_t ret = len; + + assert(iter->active); + + while (len) { + uint32_t off_in_page = iter->off & ~TARGET_PAGE_MASK; + uint32_t pgleft = TARGET_PAGE_SIZE - off_in_page; + uint32_t cplen = MIN(pgleft, len); + void *p; + + /* try to reuse the cached mapping */ + if (iter->map) { + uint32_t map_start_in_page = + (uintptr_t)iter->map & ~TARGET_PAGE_MASK; + uint32_t off_base = iter->off & ~TARGET_PAGE_MASK; + uint32_t mapped_base = (iter->last_off - 1) & ~TARGET_PAGE_MASK; + if (off_base != mapped_base || off_in_page < map_start_in_page) { + gpadl_iter_cache_unmap(iter); + iter->map = NULL; + } + } + + if (!iter->map) { + dma_addr_t maddr; + dma_addr_t mlen = pgleft; + uint32_t idx = iter->off >> TARGET_PAGE_BITS; + assert(idx < iter->gpadl->num_gfns); + + maddr = (iter->gpadl->gfns[idx] << TARGET_PAGE_BITS) | off_in_page; + + iter->map = dma_memory_map(iter->as, maddr, &mlen, iter->dir); + if (mlen != pgleft) { + dma_memory_unmap(iter->as, iter->map, mlen, iter->dir, 0); + iter->map = NULL; + return -EFAULT; + } + } + + p = (void *)(((uintptr_t)iter->map & TARGET_PAGE_MASK) | off_in_page); + if (iter->dir == DMA_DIRECTION_FROM_DEVICE) { + memcpy(p, buf, cplen); + } else { + memcpy(buf, p, cplen); + } + + buf += cplen; + len -= cplen; + iter->off += cplen; + iter->last_off = iter->off; + } + + return ret; +} + +/* + * Position the iterator @iter at new offset @new_off. + * If this results in the cached mapping being unusable with the new offset, + * unmap it. + */ +static inline void gpadl_iter_seek(GpadlIter *iter, uint32_t new_off) +{ + assert(iter->active); + iter->off = new_off; +} + +/* + * Start a series of i/o on the GPADL. + * After this i/o and seek operations on @iter become legal. + */ +static inline void gpadl_iter_start_io(GpadlIter *iter) +{ + assert(!iter->active); + /* mapping is cached lazily on i/o */ + iter->map = NULL; + iter->active = true; +} + +/* + * End the eariler started series of i/o on the GPADL and release the cached + * mapping if any. + */ +static inline void gpadl_iter_end_io(GpadlIter *iter) +{ + assert(iter->active); + + if (iter->map) { + gpadl_iter_cache_unmap(iter); + } + + iter->active = false; +} + +static void vmbus_resched(VMBus *vmbus); +static void vmbus_msg_cb(void *data, int status); + +ssize_t vmbus_iov_to_gpadl(VMBusChannel *chan, VMBusGpadl *gpadl, uint32_t off, + const struct iovec *iov, size_t iov_cnt) +{ + GpadlIter iter; + size_t i; + ssize_t ret = 0; + + gpadl_iter_init(&iter, gpadl, chan->dev->dma_as, + DMA_DIRECTION_FROM_DEVICE); + gpadl_iter_start_io(&iter); + gpadl_iter_seek(&iter, off); + for (i = 0; i < iov_cnt; i++) { + ret = gpadl_iter_io(&iter, iov[i].iov_base, iov[i].iov_len); + if (ret < 0) { + goto out; + } + } +out: + gpadl_iter_end_io(&iter); + return ret; +} + +int vmbus_map_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov, + unsigned iov_cnt, size_t len, size_t off) +{ + int ret_cnt = 0, ret; + unsigned i; + QEMUSGList *sgl = &req->sgl; + ScatterGatherEntry *sg = sgl->sg; + + for (i = 0; i < sgl->nsg; i++) { + if (sg[i].len > off) { + break; + } + off -= sg[i].len; + } + for (; len && i < sgl->nsg; i++) { + dma_addr_t mlen = MIN(sg[i].len - off, len); + dma_addr_t addr = sg[i].base + off; + len -= mlen; + off = 0; + + for (; mlen; ret_cnt++) { + dma_addr_t l = mlen; + dma_addr_t a = addr; + + if (ret_cnt == iov_cnt) { + ret = -ENOBUFS; + goto err; + } + + iov[ret_cnt].iov_base = dma_memory_map(sgl->as, a, &l, dir); + if (!l) { + ret = -EFAULT; + goto err; + } + iov[ret_cnt].iov_len = l; + addr += l; + mlen -= l; + } + } + + return ret_cnt; +err: + vmbus_unmap_sgl(req, dir, iov, ret_cnt, 0); + return ret; +} + +void vmbus_unmap_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov, + unsigned iov_cnt, size_t accessed) +{ + QEMUSGList *sgl = &req->sgl; + unsigned i; + + for (i = 0; i < iov_cnt; i++) { + size_t acsd = MIN(accessed, iov[i].iov_len); + dma_memory_unmap(sgl->as, iov[i].iov_base, iov[i].iov_len, dir, acsd); + accessed -= acsd; + } +} + +static const VMStateDescription vmstate_gpadl = { + .name = "vmbus/gpadl", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(id, VMBusGpadl), + VMSTATE_UINT32(child_relid, VMBusGpadl), + VMSTATE_UINT32(num_gfns, VMBusGpadl), + VMSTATE_UINT32(seen_gfns, VMBusGpadl), + VMSTATE_VARRAY_UINT32_ALLOC(gfns, VMBusGpadl, num_gfns, 0, + vmstate_info_uint64, uint64_t), + VMSTATE_UINT8(state, VMBusGpadl), + VMSTATE_END_OF_LIST() + } +}; + +/* + * Wrap the index into a ring buffer of @len bytes. + * @idx is assumed not to exceed twice the size of the ringbuffer, so only + * single wraparound is considered. + */ +static inline uint32_t rb_idx_wrap(uint32_t idx, uint32_t len) +{ + if (idx >= len) { + idx -= len; + } + return idx; +} + +/* + * Circular difference between two indices into a ring buffer of @len bytes. + * @allow_catchup - whether @idx1 may catch up @idx2; e.g. read index may catch + * up write index but not vice versa. + */ +static inline uint32_t rb_idx_delta(uint32_t idx1, uint32_t idx2, uint32_t len, + bool allow_catchup) +{ + return rb_idx_wrap(idx2 + len - idx1 - !allow_catchup, len); +} + +static vmbus_ring_buffer *ringbuf_map_hdr(VMBusRingBufCommon *ringbuf) +{ + vmbus_ring_buffer *rb; + dma_addr_t mlen = sizeof(*rb); + + rb = dma_memory_map(ringbuf->as, ringbuf->rb_addr, &mlen, + DMA_DIRECTION_FROM_DEVICE); + if (mlen != sizeof(*rb)) { + dma_memory_unmap(ringbuf->as, rb, mlen, + DMA_DIRECTION_FROM_DEVICE, 0); + return NULL; + } + return rb; +} + +static void ringbuf_unmap_hdr(VMBusRingBufCommon *ringbuf, + vmbus_ring_buffer *rb, bool dirty) +{ + assert(rb); + + dma_memory_unmap(ringbuf->as, rb, sizeof(*rb), DMA_DIRECTION_FROM_DEVICE, + dirty ? sizeof(*rb) : 0); +} + +static void ringbuf_init_common(VMBusRingBufCommon *ringbuf, VMBusGpadl *gpadl, + AddressSpace *as, DMADirection dir, + uint32_t begin, uint32_t end) +{ + ringbuf->as = as; + ringbuf->rb_addr = gpadl->gfns[begin] << TARGET_PAGE_BITS; + ringbuf->base = (begin + 1) << TARGET_PAGE_BITS; + ringbuf->len = (end - begin - 1) << TARGET_PAGE_BITS; + gpadl_iter_init(&ringbuf->iter, gpadl, as, dir); +} + +static int ringbufs_init(VMBusChannel *chan) +{ + vmbus_ring_buffer *rb; + VMBusSendRingBuf *send_ringbuf = &chan->send_ringbuf; + VMBusRecvRingBuf *recv_ringbuf = &chan->recv_ringbuf; + + if (chan->ringbuf_send_offset <= 1 || + chan->gpadl->num_gfns <= chan->ringbuf_send_offset + 1) { + return -EINVAL; + } + + ringbuf_init_common(&recv_ringbuf->common, chan->gpadl, chan->dev->dma_as, + DMA_DIRECTION_TO_DEVICE, 0, chan->ringbuf_send_offset); + ringbuf_init_common(&send_ringbuf->common, chan->gpadl, chan->dev->dma_as, + DMA_DIRECTION_FROM_DEVICE, chan->ringbuf_send_offset, + chan->gpadl->num_gfns); + send_ringbuf->wanted = 0; + send_ringbuf->reserved = 0; + + rb = ringbuf_map_hdr(&recv_ringbuf->common); + if (!rb) { + return -EFAULT; + } + recv_ringbuf->rd_idx = recv_ringbuf->last_rd_idx = rb->read_index; + ringbuf_unmap_hdr(&recv_ringbuf->common, rb, false); + + rb = ringbuf_map_hdr(&send_ringbuf->common); + if (!rb) { + return -EFAULT; + } + send_ringbuf->wr_idx = send_ringbuf->last_wr_idx = rb->write_index; + send_ringbuf->last_seen_rd_idx = rb->read_index; + rb->feature_bits |= VMBUS_RING_BUFFER_FEAT_PENDING_SZ; + ringbuf_unmap_hdr(&send_ringbuf->common, rb, true); + + if (recv_ringbuf->rd_idx >= recv_ringbuf->common.len || + send_ringbuf->wr_idx >= send_ringbuf->common.len) { + return -EOVERFLOW; + } + + return 0; +} + +/* + * Perform io between the GPADL-backed ringbuffer @ringbuf and @buf, wrapping + * around if needed. + * @len is assumed not to exceed the size of the ringbuffer, so only single + * wraparound is considered. + */ +static ssize_t ringbuf_io(VMBusRingBufCommon *ringbuf, void *buf, uint32_t len) +{ + ssize_t ret1 = 0, ret2 = 0; + uint32_t remain = ringbuf->len + ringbuf->base - ringbuf->iter.off; + + if (len >= remain) { + ret1 = gpadl_iter_io(&ringbuf->iter, buf, remain); + if (ret1 < 0) { + return ret1; + } + gpadl_iter_seek(&ringbuf->iter, ringbuf->base); + buf += remain; + len -= remain; + } + ret2 = gpadl_iter_io(&ringbuf->iter, buf, len); + if (ret2 < 0) { + return ret2; + } + return ret1 + ret2; +} + +/* + * Position the circular iterator within @ringbuf to offset @new_off, wrapping + * around if needed. + * @new_off is assumed not to exceed twice the size of the ringbuffer, so only + * single wraparound is considered. + */ +static inline void ringbuf_seek(VMBusRingBufCommon *ringbuf, uint32_t new_off) +{ + gpadl_iter_seek(&ringbuf->iter, + ringbuf->base + rb_idx_wrap(new_off, ringbuf->len)); +} + +static inline uint32_t ringbuf_tell(VMBusRingBufCommon *ringbuf) +{ + return ringbuf->iter.off - ringbuf->base; +} + +static inline void ringbuf_start_io(VMBusRingBufCommon *ringbuf) +{ + gpadl_iter_start_io(&ringbuf->iter); +} + +static inline void ringbuf_end_io(VMBusRingBufCommon *ringbuf) +{ + gpadl_iter_end_io(&ringbuf->iter); +} + +VMBusDevice *vmbus_channel_device(VMBusChannel *chan) +{ + return chan->dev; +} + +VMBusChannel *vmbus_device_channel(VMBusDevice *dev, uint32_t chan_idx) +{ + if (chan_idx >= dev->num_channels) { + return NULL; + } + return &dev->channels[chan_idx]; +} + +uint32_t vmbus_channel_idx(VMBusChannel *chan) +{ + return chan - chan->dev->channels; +} + +void vmbus_channel_notify_host(VMBusChannel *chan) +{ + event_notifier_set(&chan->notifier); +} + +bool vmbus_channel_is_open(VMBusChannel *chan) +{ + return chan->is_open; +} + +/* + * Notify the guest side about the data to work on in the channel ring buffer. + * The notification is done by signaling a dedicated per-channel SynIC event + * flag (more recent guests) or setting a bit in the interrupt page and firing + * the VMBus SINT (older guests). + */ +static int vmbus_channel_notify_guest(VMBusChannel *chan) +{ + int res = 0; + unsigned long *int_map, mask; + unsigned idx; + hwaddr addr = chan->vmbus->int_page_gpa; + hwaddr len = TARGET_PAGE_SIZE / 2, dirty = 0; + + trace_vmbus_channel_notify_guest(chan->id); + + if (!addr) { + return hyperv_set_event_flag(chan->notify_route, chan->id); + } + + int_map = cpu_physical_memory_map(addr, &len, 1); + if (len != TARGET_PAGE_SIZE / 2) { + res = -ENXIO; + goto unmap; + } + + idx = BIT_WORD(chan->id); + mask = BIT_MASK(chan->id); + if ((atomic_fetch_or(&int_map[idx], mask) & mask) != mask) { + res = hyperv_sint_route_set_sint(chan->notify_route); + dirty = len; + } + +unmap: + cpu_physical_memory_unmap(int_map, len, 1, dirty); + return res; +} + +#define VMBUS_PKT_TRAILER sizeof(uint64_t) + +static uint32_t vmbus_pkt_hdr_set_offsets(vmbus_packet_hdr *hdr, + uint32_t desclen, uint32_t msglen) +{ + hdr->offset_qwords = sizeof(*hdr) / sizeof(uint64_t) + + DIV_ROUND_UP(desclen, sizeof(uint64_t)); + hdr->len_qwords = hdr->offset_qwords + + DIV_ROUND_UP(msglen, sizeof(uint64_t)); + return hdr->len_qwords * sizeof(uint64_t) + VMBUS_PKT_TRAILER; +} + +/* + * Simplified ring buffer operation with paired barriers annotations in the + * producer and consumer loops: + * + * producer * consumer + * ~~~~~~~~ * ~~~~~~~~ + * write pending_send_sz * read write_index + * smp_mb [A] * smp_mb [C] + * read read_index * read packet + * smp_mb [B] * read/write out-of-band data + * read/write out-of-band data * smp_mb [B] + * write packet * write read_index + * smp_mb [C] * smp_mb [A] + * write write_index * read pending_send_sz + * smp_wmb [D] * smp_rmb [D] + * write pending_send_sz * read write_index + * ... * ... + */ + +static inline uint32_t ringbuf_send_avail(VMBusSendRingBuf *ringbuf) +{ + /* don't trust guest data */ + if (ringbuf->last_seen_rd_idx >= ringbuf->common.len) { + return 0; + } + return rb_idx_delta(ringbuf->wr_idx, ringbuf->last_seen_rd_idx, + ringbuf->common.len, false); +} + +static ssize_t ringbuf_send_update_idx(VMBusChannel *chan) +{ + VMBusSendRingBuf *ringbuf = &chan->send_ringbuf; + vmbus_ring_buffer *rb; + uint32_t written; + + written = rb_idx_delta(ringbuf->last_wr_idx, ringbuf->wr_idx, + ringbuf->common.len, true); + if (!written) { + return 0; + } + + rb = ringbuf_map_hdr(&ringbuf->common); + if (!rb) { + return -EFAULT; + } + + ringbuf->reserved -= written; + + /* prevent reorder with the data operation and packet write */ + smp_mb(); /* barrier pair [C] */ + rb->write_index = ringbuf->wr_idx; + + /* + * If the producer earlier indicated that it wants to be notified when the + * consumer frees certain amount of space in the ring buffer, that amount + * is reduced by the size of the completed write. + */ + if (ringbuf->wanted) { + /* otherwise reservation would fail */ + assert(ringbuf->wanted < written); + ringbuf->wanted -= written; + /* prevent reorder with write_index write */ + smp_wmb(); /* barrier pair [D] */ + rb->pending_send_sz = ringbuf->wanted; + } + + /* prevent reorder with write_index or pending_send_sz write */ + smp_mb(); /* barrier pair [A] */ + ringbuf->last_seen_rd_idx = rb->read_index; + + /* + * The consumer may have missed the reduction of pending_send_sz and skip + * notification, so re-check the blocking condition, and, if it's no longer + * true, ensure processing another iteration by simulating consumer's + * notification. + */ + if (ringbuf_send_avail(ringbuf) >= ringbuf->wanted) { + vmbus_channel_notify_host(chan); + } + + /* skip notification by consumer's request */ + if (rb->interrupt_mask) { + goto out; + } + + /* + * The consumer hasn't caught up with the producer's previous state so it's + * not blocked. + * (last_seen_rd_idx comes from the guest but it's safe to use w/o + * validation here as it only affects notification.) + */ + if (rb_idx_delta(ringbuf->last_seen_rd_idx, ringbuf->wr_idx, + ringbuf->common.len, true) > written) { + goto out; + } + + vmbus_channel_notify_guest(chan); +out: + ringbuf_unmap_hdr(&ringbuf->common, rb, true); + ringbuf->last_wr_idx = ringbuf->wr_idx; + return written; +} + +int vmbus_channel_reserve(VMBusChannel *chan, + uint32_t desclen, uint32_t msglen) +{ + VMBusSendRingBuf *ringbuf = &chan->send_ringbuf; + vmbus_ring_buffer *rb = NULL; + vmbus_packet_hdr hdr; + uint32_t needed = ringbuf->reserved + + vmbus_pkt_hdr_set_offsets(&hdr, desclen, msglen); + + /* avoid touching the guest memory if possible */ + if (likely(needed <= ringbuf_send_avail(ringbuf))) { + goto success; + } + + rb = ringbuf_map_hdr(&ringbuf->common); + if (!rb) { + return -EFAULT; + } + + /* fetch read index from guest memory and try again */ + ringbuf->last_seen_rd_idx = rb->read_index; + + if (likely(needed <= ringbuf_send_avail(ringbuf))) { + goto success; + } + + rb->pending_send_sz = needed; + + /* + * The consumer may have made progress and freed up some space before + * seeing updated pending_send_sz, so re-read read_index (preventing + * reorder with the pending_send_sz write) and try again. + */ + smp_mb(); /* barrier pair [A] */ + ringbuf->last_seen_rd_idx = rb->read_index; + + if (needed > ringbuf_send_avail(ringbuf)) { + goto out; + } + +success: + ringbuf->reserved = needed; + needed = 0; + + /* clear pending_send_sz if it was set */ + if (ringbuf->wanted) { + if (!rb) { + rb = ringbuf_map_hdr(&ringbuf->common); + if (!rb) { + /* failure to clear pending_send_sz is non-fatal */ + goto out; + } + } + + rb->pending_send_sz = 0; + } + + /* prevent reorder of the following data operation with read_index read */ + smp_mb(); /* barrier pair [B] */ + +out: + if (rb) { + ringbuf_unmap_hdr(&ringbuf->common, rb, ringbuf->wanted == needed); + } + ringbuf->wanted = needed; + return needed ? -ENOSPC : 0; +} + +ssize_t vmbus_channel_send(VMBusChannel *chan, uint16_t pkt_type, + void *desc, uint32_t desclen, + void *msg, uint32_t msglen, + bool need_comp, uint64_t transaction_id) +{ + ssize_t ret = 0; + vmbus_packet_hdr hdr; + uint32_t totlen; + VMBusSendRingBuf *ringbuf = &chan->send_ringbuf; + + if (!vmbus_channel_is_open(chan)) { + return -EINVAL; + } + + totlen = vmbus_pkt_hdr_set_offsets(&hdr, desclen, msglen); + hdr.type = pkt_type; + hdr.flags = need_comp ? VMBUS_PACKET_FLAG_REQUEST_COMPLETION : 0; + hdr.transaction_id = transaction_id; + + assert(totlen <= ringbuf->reserved); + + ringbuf_start_io(&ringbuf->common); + ringbuf_seek(&ringbuf->common, ringbuf->wr_idx); + ret = ringbuf_io(&ringbuf->common, &hdr, sizeof(hdr)); + if (ret < 0) { + goto out; + } + if (desclen) { + assert(desc); + ret = ringbuf_io(&ringbuf->common, desc, desclen); + if (ret < 0) { + goto out; + } + ringbuf_seek(&ringbuf->common, + ringbuf->wr_idx + hdr.offset_qwords * sizeof(uint64_t)); + } + ret = ringbuf_io(&ringbuf->common, msg, msglen); + if (ret < 0) { + goto out; + } + ringbuf_seek(&ringbuf->common, ringbuf->wr_idx + totlen); + ringbuf->wr_idx = ringbuf_tell(&ringbuf->common); + ret = 0; +out: + ringbuf_end_io(&ringbuf->common); + if (ret) { + return ret; + } + return ringbuf_send_update_idx(chan); +} + +ssize_t vmbus_channel_send_completion(VMBusChanReq *req, + void *msg, uint32_t msglen) +{ + assert(req->need_comp); + return vmbus_channel_send(req->chan, VMBUS_PACKET_COMP, NULL, 0, + msg, msglen, false, req->transaction_id); +} + +static int sgl_from_gpa_ranges(QEMUSGList *sgl, VMBusDevice *dev, + VMBusRingBufCommon *ringbuf, uint32_t len) +{ + int ret; + vmbus_pkt_gpa_direct hdr; + hwaddr curaddr = 0; + hwaddr curlen = 0; + int num; + + if (len < sizeof(hdr)) { + return -EIO; + } + ret = ringbuf_io(ringbuf, &hdr, sizeof(hdr)); + if (ret < 0) { + return ret; + } + len -= sizeof(hdr); + + num = (len - hdr.rangecount * sizeof(vmbus_gpa_range)) / sizeof(uint64_t); + if (num < 0) { + return -EIO; + } + qemu_sglist_init(sgl, DEVICE(dev), num, ringbuf->as); + + for (; hdr.rangecount; hdr.rangecount--) { + vmbus_gpa_range range; + + if (len < sizeof(range)) { + goto eio; + } + ret = ringbuf_io(ringbuf, &range, sizeof(range)); + if (ret < 0) { + goto err; + } + len -= sizeof(range); + + if (range.byte_offset & TARGET_PAGE_MASK) { + goto eio; + } + + for (; range.byte_count; range.byte_offset = 0) { + uint64_t paddr; + uint32_t plen = MIN(range.byte_count, + TARGET_PAGE_SIZE - range.byte_offset); + + if (len < sizeof(uint64_t)) { + goto eio; + } + ret = ringbuf_io(ringbuf, &paddr, sizeof(paddr)); + if (ret < 0) { + goto err; + } + len -= sizeof(uint64_t); + paddr <<= TARGET_PAGE_BITS; + paddr |= range.byte_offset; + range.byte_count -= plen; + + if (curaddr + curlen == paddr) { + /* consecutive fragments - join */ + curlen += plen; + } else { + if (curlen) { + qemu_sglist_add(sgl, curaddr, curlen); + } + + curaddr = paddr; + curlen = plen; + } + } + } + + if (curlen) { + qemu_sglist_add(sgl, curaddr, curlen); + } + + return 0; +eio: + ret = -EIO; +err: + qemu_sglist_destroy(sgl); + return ret; +} + +static VMBusChanReq *vmbus_alloc_req(VMBusChannel *chan, + uint32_t size, uint16_t pkt_type, + uint32_t msglen, uint64_t transaction_id, + bool need_comp) +{ + VMBusChanReq *req; + uint32_t msgoff = QEMU_ALIGN_UP(size, __alignof__(*req->msg)); + uint32_t totlen = msgoff + msglen; + + req = g_malloc0(totlen); + req->chan = chan; + req->pkt_type = pkt_type; + req->msg = (void *)req + msgoff; + req->msglen = msglen; + req->transaction_id = transaction_id; + req->need_comp = need_comp; + return req; +} + +int vmbus_channel_recv_start(VMBusChannel *chan) +{ + VMBusRecvRingBuf *ringbuf = &chan->recv_ringbuf; + vmbus_ring_buffer *rb; + + rb = ringbuf_map_hdr(&ringbuf->common); + if (!rb) { + return -EFAULT; + } + ringbuf->last_seen_wr_idx = rb->write_index; + ringbuf_unmap_hdr(&ringbuf->common, rb, false); + + if (ringbuf->last_seen_wr_idx >= ringbuf->common.len) { + return -EOVERFLOW; + } + + /* prevent reorder of the following data operation with write_index read */ + smp_mb(); /* barrier pair [C] */ + return 0; +} + +void *vmbus_channel_recv_peek(VMBusChannel *chan, uint32_t size) +{ + VMBusRecvRingBuf *ringbuf = &chan->recv_ringbuf; + vmbus_packet_hdr hdr = {}; + VMBusChanReq *req; + uint32_t avail; + uint32_t totlen, pktlen, msglen, msgoff, desclen; + + assert(size >= sizeof(*req)); + + /* safe as last_seen_wr_idx is validated in vmbus_channel_recv_start */ + avail = rb_idx_delta(ringbuf->rd_idx, ringbuf->last_seen_wr_idx, + ringbuf->common.len, true); + if (avail < sizeof(hdr)) { + return NULL; + } + + ringbuf_seek(&ringbuf->common, ringbuf->rd_idx); + if (ringbuf_io(&ringbuf->common, &hdr, sizeof(hdr)) < 0) { + return NULL; + } + + pktlen = hdr.len_qwords * sizeof(uint64_t); + totlen = pktlen + VMBUS_PKT_TRAILER; + if (totlen > avail) { + return NULL; + } + + msgoff = hdr.offset_qwords * sizeof(uint64_t); + if (msgoff > pktlen || msgoff < sizeof(hdr)) { + error_report("%s: malformed packet: %u %u", __func__, msgoff, pktlen); + return NULL; + } + + msglen = pktlen - msgoff; + + req = vmbus_alloc_req(chan, size, hdr.type, msglen, hdr.transaction_id, + hdr.flags & VMBUS_PACKET_FLAG_REQUEST_COMPLETION); + + switch (hdr.type) { + case VMBUS_PACKET_DATA_USING_GPA_DIRECT: + desclen = msgoff - sizeof(hdr); + if (sgl_from_gpa_ranges(&req->sgl, chan->dev, &ringbuf->common, + desclen) < 0) { + error_report("%s: failed to convert GPA ranges to SGL", __func__); + goto free_req; + } + break; + case VMBUS_PACKET_DATA_INBAND: + case VMBUS_PACKET_COMP: + break; + default: + error_report("%s: unexpected msg type: %x", __func__, hdr.type); + goto free_req; + } + + ringbuf_seek(&ringbuf->common, ringbuf->rd_idx + msgoff); + if (ringbuf_io(&ringbuf->common, req->msg, msglen) < 0) { + goto free_req; + } + ringbuf_seek(&ringbuf->common, ringbuf->rd_idx + totlen); + + return req; +free_req: + vmbus_free_req(req); + return NULL; +} + +void vmbus_channel_recv_pop(VMBusChannel *chan) +{ + VMBusRecvRingBuf *ringbuf = &chan->recv_ringbuf; + ringbuf->rd_idx = ringbuf_tell(&ringbuf->common); +} + +ssize_t vmbus_channel_recv_done(VMBusChannel *chan) +{ + VMBusRecvRingBuf *ringbuf = &chan->recv_ringbuf; + vmbus_ring_buffer *rb; + uint32_t read; + + read = rb_idx_delta(ringbuf->last_rd_idx, ringbuf->rd_idx, + ringbuf->common.len, true); + if (!read) { + return 0; + } + + rb = ringbuf_map_hdr(&ringbuf->common); + if (!rb) { + return -EFAULT; + } + + /* prevent reorder with the data operation and packet read */ + smp_mb(); /* barrier pair [B] */ + rb->read_index = ringbuf->rd_idx; + + /* prevent reorder of the following pending_send_sz read */ + smp_mb(); /* barrier pair [A] */ + + if (rb->interrupt_mask) { + goto out; + } + + if (rb->feature_bits & VMBUS_RING_BUFFER_FEAT_PENDING_SZ) { + uint32_t wr_idx, wr_avail; + uint32_t wanted = rb->pending_send_sz; + + if (!wanted) { + goto out; + } + + /* prevent reorder with pending_send_sz read */ + smp_rmb(); /* barrier pair [D] */ + wr_idx = rb->write_index; + + wr_avail = rb_idx_delta(wr_idx, ringbuf->rd_idx, ringbuf->common.len, + true); + + /* the producer wasn't blocked on the consumer state */ + if (wr_avail >= read + wanted) { + goto out; + } + /* there's not enough space for the producer to make progress */ + if (wr_avail < wanted) { + goto out; + } + } + + vmbus_channel_notify_guest(chan); +out: + ringbuf_unmap_hdr(&ringbuf->common, rb, true); + ringbuf->last_rd_idx = ringbuf->rd_idx; + return read; +} + +void vmbus_free_req(void *req) +{ + VMBusChanReq *r = req; + + if (!req) { + return; + } + + if (r->sgl.dev) { + qemu_sglist_destroy(&r->sgl); + } + g_free(req); +} + +static void channel_event_cb(EventNotifier *e) +{ + VMBusChannel *chan = container_of(e, VMBusChannel, notifier); + if (event_notifier_test_and_clear(e)) { + /* + * All receives are supposed to happen within the device worker, so + * bracket it with ringbuf_start/end_io on the receive ringbuffer, and + * potentially reuse the cached mapping throughout the worker. + * Can't do this for sends as they may happen outside the device + * worker. + */ + VMBusRecvRingBuf *ringbuf = &chan->recv_ringbuf; + ringbuf_start_io(&ringbuf->common); + chan->notify_cb(chan); + ringbuf_end_io(&ringbuf->common); + + } +} + +static int alloc_chan_id(VMBus *vmbus) +{ + int ret; + + ret = find_next_zero_bit(vmbus->chanid_bitmap, VMBUS_CHANID_COUNT, 0); + if (ret == VMBUS_CHANID_COUNT) { + return -ENOMEM; + } + return ret + VMBUS_FIRST_CHANID; +} + +static int register_chan_id(VMBusChannel *chan) +{ + return test_and_set_bit(chan->id - VMBUS_FIRST_CHANID, + chan->vmbus->chanid_bitmap) ? -EEXIST : 0; +} + +static void unregister_chan_id(VMBusChannel *chan) +{ + clear_bit(chan->id - VMBUS_FIRST_CHANID, chan->vmbus->chanid_bitmap); +} + +static uint32_t chan_connection_id(VMBusChannel *chan) +{ + return VMBUS_CHAN_CONNECTION_OFFSET + chan->id; +} + +static void init_channel(VMBus *vmbus, VMBusDevice *dev, VMBusDeviceClass *vdc, + VMBusChannel *chan, uint16_t idx, Error **errp) +{ + int res; + + chan->dev = dev; + chan->notify_cb = vdc->chan_notify_cb; + chan->subchan_idx = idx; + chan->vmbus = vmbus; + + res = alloc_chan_id(vmbus); + if (res < 0) { + error_setg(errp, "no spare channel id"); + return; + } + chan->id = res; + register_chan_id(chan); + + /* + * The guest drivers depend on the device subchannels (idx #1+) to be + * offered after the primary channel (idx #0) of that device. To ensure + * that, record the channels on the channel list in the order they appear + * within the device. + */ + QTAILQ_INSERT_TAIL(&vmbus->channel_list, chan, link); +} + +static void deinit_channel(VMBusChannel *chan) +{ + assert(chan->state == VMCHAN_INIT); + QTAILQ_REMOVE(&chan->vmbus->channel_list, chan, link); + unregister_chan_id(chan); +} + +static void create_channels(VMBus *vmbus, VMBusDevice *dev, Error **errp) +{ + uint16_t i; + VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(dev); + Error *err = NULL; + + dev->num_channels = vdc->num_channels ? vdc->num_channels(dev) : 1; + if (dev->num_channels < 1) { + error_setg(&err, "invalid #channels: %u", dev->num_channels); + goto error_out; + } + + dev->channels = g_new0(VMBusChannel, dev->num_channels); + for (i = 0; i < dev->num_channels; i++) { + init_channel(vmbus, dev, vdc, &dev->channels[i], i, &err); + if (err) { + goto err_init; + } + } + + return; + +err_init: + while (i--) { + deinit_channel(&dev->channels[i]); + } +error_out: + error_propagate(errp, err); +} + +static void free_channels(VMBusDevice *dev) +{ + uint16_t i; + for (i = 0; i < dev->num_channels; i++) { + deinit_channel(&dev->channels[i]); + } + g_free(dev->channels); +} + +static HvSintRoute *make_sint_route(VMBus *vmbus, uint32_t vp_index) +{ + VMBusChannel *chan; + + if (vp_index == vmbus->target_vp) { + hyperv_sint_route_ref(vmbus->sint_route); + return vmbus->sint_route; + } + + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + if (chan->target_vp == vp_index && vmbus_channel_is_open(chan)) { + hyperv_sint_route_ref(chan->notify_route); + return chan->notify_route; + } + } + + return hyperv_sint_route_new(vp_index, VMBUS_SINT, NULL, NULL); +} + +static void open_channel(VMBusChannel *chan) +{ + VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(chan->dev); + + chan->gpadl = vmbus_get_gpadl(chan, chan->ringbuf_gpadl); + if (!chan->gpadl) { + return; + } + + if (ringbufs_init(chan)) { + goto put_gpadl; + } + + if (event_notifier_init(&chan->notifier, 0)) { + goto put_gpadl; + } + + event_notifier_set_handler(&chan->notifier, channel_event_cb); + + if (hyperv_set_event_flag_handler(chan_connection_id(chan), + &chan->notifier)) { + goto cleanup_notifier; + } + + chan->notify_route = make_sint_route(chan->vmbus, chan->target_vp); + if (!chan->notify_route) { + goto clear_event_flag_handler; + } + + if (vdc->open_channel && vdc->open_channel(chan)) { + goto unref_sint_route; + } + + chan->is_open = true; + return; + +unref_sint_route: + hyperv_sint_route_unref(chan->notify_route); +clear_event_flag_handler: + hyperv_set_event_flag_handler(chan_connection_id(chan), NULL); +cleanup_notifier: + event_notifier_set_handler(&chan->notifier, NULL); + event_notifier_cleanup(&chan->notifier); +put_gpadl: + vmbus_put_gpadl(chan->gpadl); +} + +static void close_channel(VMBusChannel *chan) +{ + VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(chan->dev); + + if (!chan->is_open) { + return; + } + + if (vdc->close_channel) { + vdc->close_channel(chan); + } + + hyperv_sint_route_unref(chan->notify_route); + hyperv_set_event_flag_handler(chan_connection_id(chan), NULL); + event_notifier_set_handler(&chan->notifier, NULL); + event_notifier_cleanup(&chan->notifier); + vmbus_put_gpadl(chan->gpadl); + chan->is_open = false; +} + +static int channel_post_load(void *opaque, int version_id) +{ + VMBusChannel *chan = opaque; + + return register_chan_id(chan); +} + +static const VMStateDescription vmstate_channel = { + .name = "vmbus/channel", + .version_id = 0, + .minimum_version_id = 0, + .post_load = channel_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(id, VMBusChannel), + VMSTATE_UINT16(subchan_idx, VMBusChannel), + VMSTATE_UINT32(open_id, VMBusChannel), + VMSTATE_UINT32(target_vp, VMBusChannel), + VMSTATE_UINT32(ringbuf_gpadl, VMBusChannel), + VMSTATE_UINT32(ringbuf_send_offset, VMBusChannel), + VMSTATE_UINT8(offer_state, VMBusChannel), + VMSTATE_UINT8(state, VMBusChannel), + VMSTATE_END_OF_LIST() + } +}; + +static VMBusChannel *find_channel(VMBus *vmbus, uint32_t id) +{ + VMBusChannel *chan; + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + if (chan->id == id) { + return chan; + } + } + return NULL; +} + +static int enqueue_incoming_message(VMBus *vmbus, + const struct hyperv_post_message_input *msg) +{ + int ret = 0; + uint8_t idx, prev_size; + + qemu_mutex_lock(&vmbus->rx_queue_lock); + + if (vmbus->rx_queue_size == HV_MSG_QUEUE_LEN) { + ret = -ENOBUFS; + goto out; + } + + prev_size = vmbus->rx_queue_size; + idx = (vmbus->rx_queue_head + vmbus->rx_queue_size) % HV_MSG_QUEUE_LEN; + memcpy(&vmbus->rx_queue[idx], msg, sizeof(*msg)); + vmbus->rx_queue_size++; + + /* only need to resched if the queue was empty before */ + if (!prev_size) { + vmbus_resched(vmbus); + } +out: + qemu_mutex_unlock(&vmbus->rx_queue_lock); + return ret; +} + +static uint16_t vmbus_recv_message(const struct hyperv_post_message_input *msg, + void *data) +{ + VMBus *vmbus = data; + struct vmbus_message_header *vmbus_msg; + + if (msg->message_type != HV_MESSAGE_VMBUS) { + return HV_STATUS_INVALID_HYPERCALL_INPUT; + } + + if (msg->payload_size < sizeof(struct vmbus_message_header)) { + return HV_STATUS_INVALID_HYPERCALL_INPUT; + } + + vmbus_msg = (struct vmbus_message_header *)msg->payload; + + trace_vmbus_recv_message(vmbus_msg->message_type, msg->payload_size); + + if (vmbus_msg->message_type == VMBUS_MSG_INVALID || + vmbus_msg->message_type >= VMBUS_MSG_COUNT) { + error_report("vmbus: unknown message type %#x", + vmbus_msg->message_type); + return HV_STATUS_INVALID_HYPERCALL_INPUT; + } + + if (enqueue_incoming_message(vmbus, msg)) { + return HV_STATUS_INSUFFICIENT_BUFFERS; + } + return HV_STATUS_SUCCESS; +} + +static bool vmbus_initialized(VMBus *vmbus) +{ + return vmbus->version > 0 && vmbus->version <= VMBUS_VERSION_CURRENT; +} + +static void vmbus_reset_all(VMBus *vmbus) +{ + qbus_reset_all(BUS(vmbus)); +} + +static void post_msg(VMBus *vmbus, void *msgdata, uint32_t msglen) +{ + int ret; + struct hyperv_message msg = { + .header.message_type = HV_MESSAGE_VMBUS, + }; + + assert(!vmbus->msg_in_progress); + assert(msglen <= sizeof(msg.payload)); + assert(msglen >= sizeof(struct vmbus_message_header)); + + vmbus->msg_in_progress = true; + + trace_vmbus_post_msg(((struct vmbus_message_header *)msgdata)->message_type, + msglen); + + memcpy(msg.payload, msgdata, msglen); + msg.header.payload_size = ROUND_UP(msglen, VMBUS_MESSAGE_SIZE_ALIGN); + + ret = hyperv_post_msg(vmbus->sint_route, &msg); + if (ret == 0 || ret == -EAGAIN) { + return; + } + + error_report("message delivery fatal failure: %d; aborting vmbus", ret); + vmbus_reset_all(vmbus); +} + +static int vmbus_init(VMBus *vmbus) +{ + if (vmbus->target_vp != (uint32_t)-1) { + vmbus->sint_route = hyperv_sint_route_new(vmbus->target_vp, VMBUS_SINT, + vmbus_msg_cb, vmbus); + if (!vmbus->sint_route) { + error_report("failed to set up SINT route"); + return -ENOMEM; + } + } + return 0; +} + +static void vmbus_deinit(VMBus *vmbus) +{ + VMBusGpadl *gpadl, *tmp_gpadl; + VMBusChannel *chan; + + QTAILQ_FOREACH_SAFE(gpadl, &vmbus->gpadl_list, link, tmp_gpadl) { + if (gpadl->state == VMGPADL_TORNDOWN) { + continue; + } + vmbus_put_gpadl(gpadl); + } + + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + chan->offer_state = VMOFFER_INIT; + } + + hyperv_sint_route_unref(vmbus->sint_route); + vmbus->sint_route = NULL; + vmbus->int_page_gpa = 0; + vmbus->target_vp = (uint32_t)-1; + vmbus->version = 0; + vmbus->state = VMBUS_LISTEN; + vmbus->msg_in_progress = false; +} + +static void handle_initiate_contact(VMBus *vmbus, + vmbus_message_initiate_contact *msg, + uint32_t msglen) +{ + if (msglen < sizeof(*msg)) { + return; + } + + trace_vmbus_initiate_contact(msg->version_requested >> 16, + msg->version_requested & 0xffff, + msg->target_vcpu, msg->monitor_page1, + msg->monitor_page2, msg->interrupt_page); + + /* + * Reset vmbus on INITIATE_CONTACT regardless of its previous state. + * Useful, in particular, with vmbus-aware BIOS which can't shut vmbus down + * before handing over to OS loader. + */ + vmbus_reset_all(vmbus); + + vmbus->target_vp = msg->target_vcpu; + vmbus->version = msg->version_requested; + if (vmbus->version < VMBUS_VERSION_WIN8) { + /* linux passes interrupt page even when it doesn't need it */ + vmbus->int_page_gpa = msg->interrupt_page; + } + vmbus->state = VMBUS_HANDSHAKE; + + if (vmbus_init(vmbus)) { + error_report("failed to init vmbus; aborting"); + vmbus_deinit(vmbus); + return; + } +} + +static void send_handshake(VMBus *vmbus) +{ + struct vmbus_message_version_response msg = { + .header.message_type = VMBUS_MSG_VERSION_RESPONSE, + .version_supported = vmbus_initialized(vmbus), + }; + + post_msg(vmbus, &msg, sizeof(msg)); +} + +static void handle_request_offers(VMBus *vmbus, void *msgdata, uint32_t msglen) +{ + VMBusChannel *chan; + + if (!vmbus_initialized(vmbus)) { + return; + } + + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + if (chan->offer_state == VMOFFER_INIT) { + chan->offer_state = VMOFFER_SENDING; + break; + } + } + + vmbus->state = VMBUS_OFFER; +} + +static void send_offer(VMBus *vmbus) +{ + VMBusChannel *chan; + struct vmbus_message_header alloffers_msg = { + .message_type = VMBUS_MSG_ALLOFFERS_DELIVERED, + }; + + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + if (chan->offer_state == VMOFFER_SENDING) { + VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(chan->dev); + /* Hyper-V wants LE GUIDs */ + QemuUUID classid = qemu_uuid_bswap(vdc->classid); + QemuUUID instanceid = qemu_uuid_bswap(chan->dev->instanceid); + struct vmbus_message_offer_channel msg = { + .header.message_type = VMBUS_MSG_OFFERCHANNEL, + .child_relid = chan->id, + .connection_id = chan_connection_id(chan), + .channel_flags = vdc->channel_flags, + .mmio_size_mb = vdc->mmio_size_mb, + .sub_channel_index = vmbus_channel_idx(chan), + .interrupt_flags = VMBUS_OFFER_INTERRUPT_DEDICATED, + }; + + memcpy(msg.type_uuid, &classid, sizeof(classid)); + memcpy(msg.instance_uuid, &instanceid, sizeof(instanceid)); + + trace_vmbus_send_offer(chan->id, chan->dev); + + post_msg(vmbus, &msg, sizeof(msg)); + return; + } + } + + /* no more offers, send terminator message */ + trace_vmbus_terminate_offers(); + post_msg(vmbus, &alloffers_msg, sizeof(alloffers_msg)); +} + +static bool complete_offer(VMBus *vmbus) +{ + VMBusChannel *chan; + + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + if (chan->offer_state == VMOFFER_SENDING) { + chan->offer_state = VMOFFER_SENT; + goto next_offer; + } + } + /* + * no transitioning channels found so this is completing the terminator + * message, and vmbus can move to the next state + */ + return true; + +next_offer: + /* try to mark another channel for offering */ + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + if (chan->offer_state == VMOFFER_INIT) { + chan->offer_state = VMOFFER_SENDING; + break; + } + } + /* + * if an offer has been sent there are more offers or the terminator yet to + * send, so no state transition for vmbus + */ + return false; +} + + +static void handle_gpadl_header(VMBus *vmbus, vmbus_message_gpadl_header *msg, + uint32_t msglen) +{ + VMBusGpadl *gpadl; + uint32_t num_gfns, i; + + /* must include at least one gpa range */ + if (msglen < sizeof(*msg) + sizeof(msg->range[0]) || + !vmbus_initialized(vmbus)) { + return; + } + + num_gfns = (msg->range_buflen - msg->rangecount * sizeof(msg->range[0])) / + sizeof(msg->range[0].pfn_array[0]); + + trace_vmbus_gpadl_header(msg->gpadl_id, num_gfns); + + /* + * In theory the GPADL_HEADER message can define a GPADL with multiple GPA + * ranges each with arbitrary size and alignment. However in practice only + * single-range page-aligned GPADLs have been observed so just ignore + * anything else and simplify things greatly. + */ + if (msg->rangecount != 1 || msg->range[0].byte_offset || + (msg->range[0].byte_count != (num_gfns << TARGET_PAGE_BITS))) { + return; + } + + /* ignore requests to create already existing GPADLs */ + if (find_gpadl(vmbus, msg->gpadl_id)) { + return; + } + + gpadl = create_gpadl(vmbus, msg->gpadl_id, msg->child_relid, num_gfns); + + for (i = 0; i < num_gfns && + (void *)&msg->range[0].pfn_array[i + 1] <= (void *)msg + msglen; + i++) { + gpadl->gfns[gpadl->seen_gfns++] = msg->range[0].pfn_array[i]; + } + + if (gpadl_full(gpadl)) { + vmbus->state = VMBUS_CREATE_GPADL; + } +} + +static void handle_gpadl_body(VMBus *vmbus, vmbus_message_gpadl_body *msg, + uint32_t msglen) +{ + VMBusGpadl *gpadl; + uint32_t num_gfns_left, i; + + if (msglen < sizeof(*msg) || !vmbus_initialized(vmbus)) { + return; + } + + trace_vmbus_gpadl_body(msg->gpadl_id); + + gpadl = find_gpadl(vmbus, msg->gpadl_id); + if (!gpadl) { + return; + } + + num_gfns_left = gpadl->num_gfns - gpadl->seen_gfns; + assert(num_gfns_left); + + for (i = 0; i < num_gfns_left && + (void *)&msg->pfn_array[i + 1] <= (void *)msg + msglen; i++) { + gpadl->gfns[gpadl->seen_gfns++] = msg->pfn_array[i]; + } + + if (gpadl_full(gpadl)) { + vmbus->state = VMBUS_CREATE_GPADL; + } +} + +static void send_create_gpadl(VMBus *vmbus) +{ + VMBusGpadl *gpadl; + + QTAILQ_FOREACH(gpadl, &vmbus->gpadl_list, link) { + if (gpadl_full(gpadl) && gpadl->state == VMGPADL_INIT) { + struct vmbus_message_gpadl_created msg = { + .header.message_type = VMBUS_MSG_GPADL_CREATED, + .gpadl_id = gpadl->id, + .child_relid = gpadl->child_relid, + }; + + trace_vmbus_gpadl_created(gpadl->id); + post_msg(vmbus, &msg, sizeof(msg)); + return; + } + } + + assert(false); +} + +static bool complete_create_gpadl(VMBus *vmbus) +{ + VMBusGpadl *gpadl; + + QTAILQ_FOREACH(gpadl, &vmbus->gpadl_list, link) { + if (gpadl_full(gpadl) && gpadl->state == VMGPADL_INIT) { + gpadl->state = VMGPADL_ALIVE; + + return true; + } + } + + assert(false); + return false; +} + +static void handle_gpadl_teardown(VMBus *vmbus, + vmbus_message_gpadl_teardown *msg, + uint32_t msglen) +{ + VMBusGpadl *gpadl; + + if (msglen < sizeof(*msg) || !vmbus_initialized(vmbus)) { + return; + } + + trace_vmbus_gpadl_teardown(msg->gpadl_id); + + gpadl = find_gpadl(vmbus, msg->gpadl_id); + if (!gpadl || gpadl->state == VMGPADL_TORNDOWN) { + return; + } + + gpadl->state = VMGPADL_TEARINGDOWN; + vmbus->state = VMBUS_TEARDOWN_GPADL; +} + +static void send_teardown_gpadl(VMBus *vmbus) +{ + VMBusGpadl *gpadl; + + QTAILQ_FOREACH(gpadl, &vmbus->gpadl_list, link) { + if (gpadl->state == VMGPADL_TEARINGDOWN) { + struct vmbus_message_gpadl_torndown msg = { + .header.message_type = VMBUS_MSG_GPADL_TORNDOWN, + .gpadl_id = gpadl->id, + }; + + trace_vmbus_gpadl_torndown(gpadl->id); + post_msg(vmbus, &msg, sizeof(msg)); + return; + } + } + + assert(false); +} + +static bool complete_teardown_gpadl(VMBus *vmbus) +{ + VMBusGpadl *gpadl; + + QTAILQ_FOREACH(gpadl, &vmbus->gpadl_list, link) { + if (gpadl->state == VMGPADL_TEARINGDOWN) { + gpadl->state = VMGPADL_TORNDOWN; + vmbus_put_gpadl(gpadl); + return true; + } + } + + assert(false); + return false; +} + +static void handle_open_channel(VMBus *vmbus, vmbus_message_open_channel *msg, + uint32_t msglen) +{ + VMBusChannel *chan; + + if (msglen < sizeof(*msg) || !vmbus_initialized(vmbus)) { + return; + } + + trace_vmbus_open_channel(msg->child_relid, msg->ring_buffer_gpadl_id, + msg->target_vp); + chan = find_channel(vmbus, msg->child_relid); + if (!chan || chan->state != VMCHAN_INIT) { + return; + } + + chan->ringbuf_gpadl = msg->ring_buffer_gpadl_id; + chan->ringbuf_send_offset = msg->ring_buffer_offset; + chan->target_vp = msg->target_vp; + chan->open_id = msg->open_id; + + open_channel(chan); + + chan->state = VMCHAN_OPENING; + vmbus->state = VMBUS_OPEN_CHANNEL; +} + +static void send_open_channel(VMBus *vmbus) +{ + VMBusChannel *chan; + + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + if (chan->state == VMCHAN_OPENING) { + struct vmbus_message_open_result msg = { + .header.message_type = VMBUS_MSG_OPENCHANNEL_RESULT, + .child_relid = chan->id, + .open_id = chan->open_id, + .status = !vmbus_channel_is_open(chan), + }; + + trace_vmbus_channel_open(chan->id, msg.status); + post_msg(vmbus, &msg, sizeof(msg)); + return; + } + } + + assert(false); +} + +static bool complete_open_channel(VMBus *vmbus) +{ + VMBusChannel *chan; + + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + if (chan->state == VMCHAN_OPENING) { + if (vmbus_channel_is_open(chan)) { + chan->state = VMCHAN_OPEN; + /* + * simulate guest notification of ringbuffer space made + * available, for the channel protocols where the host + * initiates the communication + */ + vmbus_channel_notify_host(chan); + } else { + chan->state = VMCHAN_INIT; + } + return true; + } + } + + assert(false); + return false; +} + +static void vdev_reset_on_close(VMBusDevice *vdev) +{ + uint16_t i; + + for (i = 0; i < vdev->num_channels; i++) { + if (vmbus_channel_is_open(&vdev->channels[i])) { + return; + } + } + + /* all channels closed -- reset device */ + qdev_reset_all(DEVICE(vdev)); +} + +static void handle_close_channel(VMBus *vmbus, vmbus_message_close_channel *msg, + uint32_t msglen) +{ + VMBusChannel *chan; + + if (msglen < sizeof(*msg) || !vmbus_initialized(vmbus)) { + return; + } + + trace_vmbus_close_channel(msg->child_relid); + + chan = find_channel(vmbus, msg->child_relid); + if (!chan) { + return; + } + + close_channel(chan); + chan->state = VMCHAN_INIT; + + vdev_reset_on_close(chan->dev); +} + +static void handle_unload(VMBus *vmbus, void *msg, uint32_t msglen) +{ + vmbus->state = VMBUS_UNLOAD; +} + +static void send_unload(VMBus *vmbus) +{ + vmbus_message_header msg = { + .message_type = VMBUS_MSG_UNLOAD_RESPONSE, + }; + + qemu_mutex_lock(&vmbus->rx_queue_lock); + vmbus->rx_queue_size = 0; + qemu_mutex_unlock(&vmbus->rx_queue_lock); + + post_msg(vmbus, &msg, sizeof(msg)); + return; +} + +static bool complete_unload(VMBus *vmbus) +{ + vmbus_reset_all(vmbus); + return true; +} + +static void process_message(VMBus *vmbus) +{ + struct hyperv_post_message_input *hv_msg; + struct vmbus_message_header *msg; + void *msgdata; + uint32_t msglen; + + qemu_mutex_lock(&vmbus->rx_queue_lock); + + if (!vmbus->rx_queue_size) { + goto unlock; + } + + hv_msg = &vmbus->rx_queue[vmbus->rx_queue_head]; + msglen = hv_msg->payload_size; + if (msglen < sizeof(*msg)) { + goto out; + } + msgdata = hv_msg->payload; + msg = (struct vmbus_message_header *)msgdata; + + trace_vmbus_process_incoming_message(msg->message_type); + + switch (msg->message_type) { + case VMBUS_MSG_INITIATE_CONTACT: + handle_initiate_contact(vmbus, msgdata, msglen); + break; + case VMBUS_MSG_REQUESTOFFERS: + handle_request_offers(vmbus, msgdata, msglen); + break; + case VMBUS_MSG_GPADL_HEADER: + handle_gpadl_header(vmbus, msgdata, msglen); + break; + case VMBUS_MSG_GPADL_BODY: + handle_gpadl_body(vmbus, msgdata, msglen); + break; + case VMBUS_MSG_GPADL_TEARDOWN: + handle_gpadl_teardown(vmbus, msgdata, msglen); + break; + case VMBUS_MSG_OPENCHANNEL: + handle_open_channel(vmbus, msgdata, msglen); + break; + case VMBUS_MSG_CLOSECHANNEL: + handle_close_channel(vmbus, msgdata, msglen); + break; + case VMBUS_MSG_UNLOAD: + handle_unload(vmbus, msgdata, msglen); + break; + default: + error_report("unknown message type %#x", msg->message_type); + break; + } + +out: + vmbus->rx_queue_size--; + vmbus->rx_queue_head++; + vmbus->rx_queue_head %= HV_MSG_QUEUE_LEN; + + vmbus_resched(vmbus); +unlock: + qemu_mutex_unlock(&vmbus->rx_queue_lock); +} + +static const struct { + void (*run)(VMBus *vmbus); + bool (*complete)(VMBus *vmbus); +} state_runner[] = { + [VMBUS_LISTEN] = {process_message, NULL}, + [VMBUS_HANDSHAKE] = {send_handshake, NULL}, + [VMBUS_OFFER] = {send_offer, complete_offer}, + [VMBUS_CREATE_GPADL] = {send_create_gpadl, complete_create_gpadl}, + [VMBUS_TEARDOWN_GPADL] = {send_teardown_gpadl, complete_teardown_gpadl}, + [VMBUS_OPEN_CHANNEL] = {send_open_channel, complete_open_channel}, + [VMBUS_UNLOAD] = {send_unload, complete_unload}, +}; + +static void vmbus_do_run(VMBus *vmbus) +{ + if (vmbus->msg_in_progress) { + return; + } + + assert(vmbus->state < VMBUS_STATE_MAX); + assert(state_runner[vmbus->state].run); + state_runner[vmbus->state].run(vmbus); +} + +static void vmbus_run(void *opaque) +{ + VMBus *vmbus = opaque; + + /* make sure no recursion happens (e.g. due to recursive aio_poll()) */ + if (vmbus->in_progress) { + return; + } + + vmbus->in_progress = true; + /* + * FIXME: if vmbus_resched() is called from within vmbus_do_run(), it + * should go *after* the code that can result in aio_poll; otherwise + * reschedules can be missed. No idea how to enforce that. + */ + vmbus_do_run(vmbus); + vmbus->in_progress = false; +} + +static void vmbus_msg_cb(void *data, int status) +{ + VMBus *vmbus = data; + bool (*complete)(VMBus *vmbus); + + assert(vmbus->msg_in_progress); + + trace_vmbus_msg_cb(status); + + if (status == -EAGAIN) { + goto out; + } + if (status) { + error_report("message delivery fatal failure: %d; aborting vmbus", + status); + vmbus_reset_all(vmbus); + return; + } + + assert(vmbus->state < VMBUS_STATE_MAX); + complete = state_runner[vmbus->state].complete; + if (!complete || complete(vmbus)) { + vmbus->state = VMBUS_LISTEN; + } +out: + vmbus->msg_in_progress = false; + vmbus_resched(vmbus); +} + +static void vmbus_resched(VMBus *vmbus) +{ + aio_bh_schedule_oneshot(qemu_get_aio_context(), vmbus_run, vmbus); +} + +static void vmbus_signal_event(EventNotifier *e) +{ + VMBusChannel *chan; + VMBus *vmbus = container_of(e, VMBus, notifier); + unsigned long *int_map; + hwaddr addr, len; + bool is_dirty = false; + + if (!event_notifier_test_and_clear(e)) { + return; + } + + trace_vmbus_signal_event(); + + if (!vmbus->int_page_gpa) { + return; + } + + addr = vmbus->int_page_gpa + TARGET_PAGE_SIZE / 2; + len = TARGET_PAGE_SIZE / 2; + int_map = cpu_physical_memory_map(addr, &len, 1); + if (len != TARGET_PAGE_SIZE / 2) { + goto unmap; + } + + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + if (bitmap_test_and_clear_atomic(int_map, chan->id, 1)) { + if (!vmbus_channel_is_open(chan)) { + continue; + } + vmbus_channel_notify_host(chan); + is_dirty = true; + } + } + +unmap: + cpu_physical_memory_unmap(int_map, len, 1, is_dirty); +} + +static void vmbus_dev_realize(DeviceState *dev, Error **errp) +{ + VMBusDevice *vdev = VMBUS_DEVICE(dev); + VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(vdev); + VMBus *vmbus = VMBUS(qdev_get_parent_bus(dev)); + BusChild *child; + Error *err = NULL; + char idstr[UUID_FMT_LEN + 1]; + + assert(!qemu_uuid_is_null(&vdev->instanceid)); + + /* Check for instance id collision for this class id */ + QTAILQ_FOREACH(child, &BUS(vmbus)->children, sibling) { + VMBusDevice *child_dev = VMBUS_DEVICE(child->child); + + if (child_dev == vdev) { + continue; + } + + if (qemu_uuid_is_equal(&child_dev->instanceid, &vdev->instanceid)) { + qemu_uuid_unparse(&vdev->instanceid, idstr); + error_setg(&err, "duplicate vmbus device instance id %s", idstr); + goto error_out; + } + } + + vdev->dma_as = &address_space_memory; + + create_channels(vmbus, vdev, &err); + if (err) { + goto error_out; + } + + if (vdc->vmdev_realize) { + vdc->vmdev_realize(vdev, &err); + if (err) { + goto err_vdc_realize; + } + } + return; + +err_vdc_realize: + free_channels(vdev); +error_out: + error_propagate(errp, err); +} + +static void vmbus_dev_reset(DeviceState *dev) +{ + uint16_t i; + VMBusDevice *vdev = VMBUS_DEVICE(dev); + VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(vdev); + + if (vdev->channels) { + for (i = 0; i < vdev->num_channels; i++) { + VMBusChannel *chan = &vdev->channels[i]; + close_channel(chan); + chan->state = VMCHAN_INIT; + } + } + + if (vdc->vmdev_reset) { + vdc->vmdev_reset(vdev); + } +} + +static void vmbus_dev_unrealize(DeviceState *dev) +{ + VMBusDevice *vdev = VMBUS_DEVICE(dev); + VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(vdev); + + if (vdc->vmdev_unrealize) { + vdc->vmdev_unrealize(vdev); + } + free_channels(vdev); +} + +static void vmbus_dev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *kdev = DEVICE_CLASS(klass); + kdev->bus_type = TYPE_VMBUS; + kdev->realize = vmbus_dev_realize; + kdev->unrealize = vmbus_dev_unrealize; + kdev->reset = vmbus_dev_reset; +} + +static Property vmbus_dev_instanceid = + DEFINE_PROP_UUID("instanceid", VMBusDevice, instanceid); + +static void vmbus_dev_instance_init(Object *obj) +{ + VMBusDevice *vdev = VMBUS_DEVICE(obj); + VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(vdev); + + if (!qemu_uuid_is_null(&vdc->instanceid)) { + /* Class wants to only have a single instance with a fixed UUID */ + vdev->instanceid = vdc->instanceid; + } else { + qdev_property_add_static(DEVICE(vdev), &vmbus_dev_instanceid); + } +} + +const VMStateDescription vmstate_vmbus_dev = { + .name = TYPE_VMBUS_DEVICE, + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(instanceid.data, VMBusDevice, 16), + VMSTATE_UINT16(num_channels, VMBusDevice), + VMSTATE_STRUCT_VARRAY_POINTER_UINT16(channels, VMBusDevice, + num_channels, vmstate_channel, + VMBusChannel), + VMSTATE_END_OF_LIST() + } +}; + +/* vmbus generic device base */ +static const TypeInfo vmbus_dev_type_info = { + .name = TYPE_VMBUS_DEVICE, + .parent = TYPE_DEVICE, + .abstract = true, + .instance_size = sizeof(VMBusDevice), + .class_size = sizeof(VMBusDeviceClass), + .class_init = vmbus_dev_class_init, + .instance_init = vmbus_dev_instance_init, +}; + +static void vmbus_realize(BusState *bus, Error **errp) +{ + int ret = 0; + Error *local_err = NULL; + VMBus *vmbus = VMBUS(bus); + + qemu_mutex_init(&vmbus->rx_queue_lock); + + QTAILQ_INIT(&vmbus->gpadl_list); + QTAILQ_INIT(&vmbus->channel_list); + + ret = hyperv_set_msg_handler(VMBUS_MESSAGE_CONNECTION_ID, + vmbus_recv_message, vmbus); + if (ret != 0) { + error_setg(&local_err, "hyperv set message handler failed: %d", ret); + goto error_out; + } + + ret = event_notifier_init(&vmbus->notifier, 0); + if (ret != 0) { + error_setg(&local_err, "event notifier failed to init with %d", ret); + goto remove_msg_handler; + } + + event_notifier_set_handler(&vmbus->notifier, vmbus_signal_event); + ret = hyperv_set_event_flag_handler(VMBUS_EVENT_CONNECTION_ID, + &vmbus->notifier); + if (ret != 0) { + error_setg(&local_err, "hyperv set event handler failed with %d", ret); + goto clear_event_notifier; + } + + return; + +clear_event_notifier: + event_notifier_cleanup(&vmbus->notifier); +remove_msg_handler: + hyperv_set_msg_handler(VMBUS_MESSAGE_CONNECTION_ID, NULL, NULL); +error_out: + qemu_mutex_destroy(&vmbus->rx_queue_lock); + error_propagate(errp, local_err); +} + +static void vmbus_unrealize(BusState *bus) +{ + VMBus *vmbus = VMBUS(bus); + + hyperv_set_msg_handler(VMBUS_MESSAGE_CONNECTION_ID, NULL, NULL); + hyperv_set_event_flag_handler(VMBUS_EVENT_CONNECTION_ID, NULL); + event_notifier_cleanup(&vmbus->notifier); + + qemu_mutex_destroy(&vmbus->rx_queue_lock); +} + +static void vmbus_reset(BusState *bus) +{ + vmbus_deinit(VMBUS(bus)); +} + +static char *vmbus_get_dev_path(DeviceState *dev) +{ + BusState *bus = qdev_get_parent_bus(dev); + return qdev_get_dev_path(bus->parent); +} + +static char *vmbus_get_fw_dev_path(DeviceState *dev) +{ + VMBusDevice *vdev = VMBUS_DEVICE(dev); + char uuid[UUID_FMT_LEN + 1]; + + qemu_uuid_unparse(&vdev->instanceid, uuid); + return g_strdup_printf("%s@%s", qdev_fw_name(dev), uuid); +} + +static void vmbus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->get_dev_path = vmbus_get_dev_path; + k->get_fw_dev_path = vmbus_get_fw_dev_path; + k->realize = vmbus_realize; + k->unrealize = vmbus_unrealize; + k->reset = vmbus_reset; +} + +static int vmbus_pre_load(void *opaque) +{ + VMBusChannel *chan; + VMBus *vmbus = VMBUS(opaque); + + /* + * channel IDs allocated by the source will come in the migration stream + * for each channel, so clean up the ones allocated at realize + */ + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + unregister_chan_id(chan); + } + + return 0; +} +static int vmbus_post_load(void *opaque, int version_id) +{ + int ret; + VMBus *vmbus = VMBUS(opaque); + VMBusGpadl *gpadl; + VMBusChannel *chan; + + ret = vmbus_init(vmbus); + if (ret) { + return ret; + } + + QTAILQ_FOREACH(gpadl, &vmbus->gpadl_list, link) { + gpadl->vmbus = vmbus; + gpadl->refcount = 1; + } + + /* + * reopening channels depends on initialized vmbus so it's done here + * instead of channel_post_load() + */ + QTAILQ_FOREACH(chan, &vmbus->channel_list, link) { + + if (chan->state == VMCHAN_OPENING || chan->state == VMCHAN_OPEN) { + open_channel(chan); + } + + if (chan->state != VMCHAN_OPEN) { + continue; + } + + if (!vmbus_channel_is_open(chan)) { + /* reopen failed, abort loading */ + return -1; + } + + /* resume processing on the guest side if it missed the notification */ + hyperv_sint_route_set_sint(chan->notify_route); + /* ditto on the host side */ + vmbus_channel_notify_host(chan); + } + + vmbus_resched(vmbus); + return 0; +} + +static const VMStateDescription vmstate_post_message_input = { + .name = "vmbus/hyperv_post_message_input", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + /* + * skip connection_id and message_type as they are validated before + * queueing and ignored on dequeueing + */ + VMSTATE_UINT32(payload_size, struct hyperv_post_message_input), + VMSTATE_UINT8_ARRAY(payload, struct hyperv_post_message_input, + HV_MESSAGE_PAYLOAD_SIZE), + VMSTATE_END_OF_LIST() + } +}; + +static bool vmbus_rx_queue_needed(void *opaque) +{ + VMBus *vmbus = VMBUS(opaque); + return vmbus->rx_queue_size; +} + +static const VMStateDescription vmstate_rx_queue = { + .name = "vmbus/rx_queue", + .version_id = 0, + .minimum_version_id = 0, + .needed = vmbus_rx_queue_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT8(rx_queue_head, VMBus), + VMSTATE_UINT8(rx_queue_size, VMBus), + VMSTATE_STRUCT_ARRAY(rx_queue, VMBus, + HV_MSG_QUEUE_LEN, 0, + vmstate_post_message_input, + struct hyperv_post_message_input), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_vmbus = { + .name = TYPE_VMBUS, + .version_id = 0, + .minimum_version_id = 0, + .pre_load = vmbus_pre_load, + .post_load = vmbus_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(state, VMBus), + VMSTATE_UINT32(version, VMBus), + VMSTATE_UINT32(target_vp, VMBus), + VMSTATE_UINT64(int_page_gpa, VMBus), + VMSTATE_QTAILQ_V(gpadl_list, VMBus, 0, + vmstate_gpadl, VMBusGpadl, link), + VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &vmstate_rx_queue, + NULL + } +}; + +static const TypeInfo vmbus_type_info = { + .name = TYPE_VMBUS, + .parent = TYPE_BUS, + .instance_size = sizeof(VMBus), + .class_init = vmbus_class_init, +}; + +static void vmbus_bridge_realize(DeviceState *dev, Error **errp) +{ + VMBusBridge *bridge = VMBUS_BRIDGE(dev); + + /* + * here there's at least one vmbus bridge that is being realized, so + * vmbus_bridge_find can only return NULL if it's not unique + */ + if (!vmbus_bridge_find()) { + error_setg(errp, "there can be at most one %s in the system", + TYPE_VMBUS_BRIDGE); + return; + } + + if (!hyperv_is_synic_enabled()) { + error_report("VMBus requires usable Hyper-V SynIC and VP_INDEX"); + return; + } + + bridge->bus = VMBUS(qbus_create(TYPE_VMBUS, dev, "vmbus")); +} + +static char *vmbus_bridge_ofw_unit_address(const SysBusDevice *dev) +{ + /* there can be only one VMBus */ + return g_strdup("0"); +} + +static const VMStateDescription vmstate_vmbus_bridge = { + .name = TYPE_VMBUS_BRIDGE, + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_POINTER(bus, VMBusBridge, vmstate_vmbus, VMBus), + VMSTATE_END_OF_LIST() + }, +}; + +static void vmbus_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + SysBusDeviceClass *sk = SYS_BUS_DEVICE_CLASS(klass); + + k->realize = vmbus_bridge_realize; + k->fw_name = "vmbus"; + sk->explicit_ofw_unit_address = vmbus_bridge_ofw_unit_address; + set_bit(DEVICE_CATEGORY_BRIDGE, k->categories); + k->vmsd = &vmstate_vmbus_bridge; + /* override SysBusDevice's default */ + k->user_creatable = true; +} + +static const TypeInfo vmbus_bridge_type_info = { + .name = TYPE_VMBUS_BRIDGE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(VMBusBridge), + .class_init = vmbus_bridge_class_init, +}; + +static void vmbus_register_types(void) +{ + type_register_static(&vmbus_bridge_type_info); + type_register_static(&vmbus_dev_type_info); + type_register_static(&vmbus_type_info); +} + +type_init(vmbus_register_types) diff --git a/include/hw/hyperv/vmbus-bridge.h b/include/hw/hyperv/vmbus-bridge.h new file mode 100644 index 0000000000..9cc8f780de --- /dev/null +++ b/include/hw/hyperv/vmbus-bridge.h @@ -0,0 +1,32 @@ +/* + * QEMU Hyper-V VMBus root bridge + * + * Copyright (c) 2017-2018 Virtuozzo International GmbH. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_HYPERV_VMBUS_BRIDGE_H +#define HW_HYPERV_VMBUS_BRIDGE_H + +#include "hw/sysbus.h" + +#define TYPE_VMBUS_BRIDGE "vmbus-bridge" + +typedef struct VMBus VMBus; + +typedef struct VMBusBridge { + SysBusDevice parent_obj; + + VMBus *bus; +} VMBusBridge; + +#define VMBUS_BRIDGE(obj) OBJECT_CHECK(VMBusBridge, (obj), TYPE_VMBUS_BRIDGE) + +static inline VMBusBridge *vmbus_bridge_find(void) +{ + return VMBUS_BRIDGE(object_resolve_path_type("", TYPE_VMBUS_BRIDGE, NULL)); +} + +#endif diff --git a/include/hw/hyperv/vmbus.h b/include/hw/hyperv/vmbus.h new file mode 100644 index 0000000000..99b647e1d6 --- /dev/null +++ b/include/hw/hyperv/vmbus.h @@ -0,0 +1,227 @@ +/* + * QEMU Hyper-V VMBus + * + * Copyright (c) 2017-2018 Virtuozzo International GmbH. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_HYPERV_VMBUS_H +#define HW_HYPERV_VMBUS_H + +#include "sysemu/sysemu.h" +#include "sysemu/dma.h" +#include "hw/qdev-core.h" +#include "migration/vmstate.h" +#include "hw/hyperv/vmbus-proto.h" +#include "qemu/uuid.h" + +#define TYPE_VMBUS_DEVICE "vmbus-dev" + +#define VMBUS_DEVICE(obj) \ + OBJECT_CHECK(VMBusDevice, (obj), TYPE_VMBUS_DEVICE) +#define VMBUS_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(VMBusDeviceClass, (klass), TYPE_VMBUS_DEVICE) +#define VMBUS_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VMBusDeviceClass, (obj), TYPE_VMBUS_DEVICE) + +/* + * Object wrapping a GPADL -- GPA Descriptor List -- an array of guest physical + * pages, to be used for various buffers shared between the host and the guest. + */ +typedef struct VMBusGpadl VMBusGpadl; +/* + * VMBus channel -- a pair of ring buffers for either direction, placed within + * one GPADL, and the associated notification means. + */ +typedef struct VMBusChannel VMBusChannel; +/* + * Base class for VMBus devices. Includes one or more channels. Identified by + * class GUID and instance GUID. + */ +typedef struct VMBusDevice VMBusDevice; + +typedef void(*VMBusChannelNotifyCb)(struct VMBusChannel *chan); + +typedef struct VMBusDeviceClass { + DeviceClass parent; + + QemuUUID classid; + QemuUUID instanceid; /* Fixed UUID for singleton devices */ + uint16_t channel_flags; + uint16_t mmio_size_mb; + + /* Extentions to standard device callbacks */ + void (*vmdev_realize)(VMBusDevice *vdev, Error **errp); + void (*vmdev_unrealize)(VMBusDevice *vdev); + void (*vmdev_reset)(VMBusDevice *vdev); + /* + * Calculate the number of channels based on the device properties. Called + * at realize time. + **/ + uint16_t (*num_channels)(VMBusDevice *vdev); + /* + * Device-specific actions to complete the otherwise successful process of + * opening a channel. + * Return 0 on success, -errno on failure. + */ + int (*open_channel)(VMBusChannel *chan); + /* + * Device-specific actions to perform before closing a channel. + */ + void (*close_channel)(VMBusChannel *chan); + /* + * Main device worker; invoked in response to notifications from either + * side, when there's work to do with the data in the channel ring buffers. + */ + VMBusChannelNotifyCb chan_notify_cb; +} VMBusDeviceClass; + +struct VMBusDevice { + DeviceState parent; + QemuUUID instanceid; + uint16_t num_channels; + VMBusChannel *channels; + AddressSpace *dma_as; +}; + +extern const VMStateDescription vmstate_vmbus_dev; + +/* + * A unit of work parsed out of a message in the receive (i.e. guest->host) + * ring buffer of a channel. It's supposed to be subclassed (through + * embedding) by the specific devices. + */ +typedef struct VMBusChanReq { + VMBusChannel *chan; + uint16_t pkt_type; + uint32_t msglen; + void *msg; + uint64_t transaction_id; + bool need_comp; + QEMUSGList sgl; +} VMBusChanReq; + +VMBusDevice *vmbus_channel_device(VMBusChannel *chan); +VMBusChannel *vmbus_device_channel(VMBusDevice *dev, uint32_t chan_idx); +uint32_t vmbus_channel_idx(VMBusChannel *chan); +bool vmbus_channel_is_open(VMBusChannel *chan); + +/* + * Notify (on guest's behalf) the host side of the channel that there's data in + * the ringbuffer to process. + */ +void vmbus_channel_notify_host(VMBusChannel *chan); + +/* + * Reserve space for a packet in the send (i.e. host->guest) ringbuffer. If + * there isn't enough room, indicate that to the guest, to be notified when it + * becomes available. + * Return 0 on success, negative errno on failure. + * The ringbuffer indices are NOT updated, the requested space indicator may. + */ +int vmbus_channel_reserve(VMBusChannel *chan, + uint32_t desclen, uint32_t msglen); + +/* + * Send a packet to the guest. The space for the packet MUST be reserved + * first. + * Return total number of bytes placed in the send ringbuffer on success, + * negative errno on failure. + * The ringbuffer indices are updated on success, and the guest is signaled if + * needed. + */ +ssize_t vmbus_channel_send(VMBusChannel *chan, uint16_t pkt_type, + void *desc, uint32_t desclen, + void *msg, uint32_t msglen, + bool need_comp, uint64_t transaction_id); + +/* + * Prepare to fetch a batch of packets from the receive ring buffer. + * Return 0 on success, negative errno on failure. + */ +int vmbus_channel_recv_start(VMBusChannel *chan); + +/* + * Shortcut for a common case of sending a simple completion packet with no + * auxiliary descriptors. + */ +ssize_t vmbus_channel_send_completion(VMBusChanReq *req, + void *msg, uint32_t msglen); + +/* + * Peek at the receive (i.e. guest->host) ring buffer and extract a unit of + * work (a device-specific subclass of VMBusChanReq) from a packet if there's + * one. + * Return an allocated buffer, containing the request of @size with filled + * VMBusChanReq at the beginning, followed by the message payload, or NULL on + * failure. + * The ringbuffer indices are NOT updated, nor is the private copy of the read + * index. + */ +void *vmbus_channel_recv_peek(VMBusChannel *chan, uint32_t size); + +/* + * Update the private copy of the read index once the preceding peek is deemed + * successful. + * The ringbuffer indices are NOT updated. + */ +void vmbus_channel_recv_pop(VMBusChannel *chan); + +/* + * Propagate the private copy of the read index into the receive ring buffer, + * and thus complete the reception of a series of packets. Notify guest if + * needed. + * Return the number of bytes popped off the receive ring buffer by the + * preceding recv_peek/recv_pop calls on success, negative errno on failure. + */ +ssize_t vmbus_channel_recv_done(VMBusChannel *chan); + +/* + * Free the request allocated by vmbus_channel_recv_peek, together with its + * fields. + */ +void vmbus_free_req(void *req); + +/* + * Find and reference a GPADL by @gpadl_id. + * If not found return NULL. + */ +VMBusGpadl *vmbus_get_gpadl(VMBusChannel *chan, uint32_t gpadl_id); + +/* + * Unreference @gpadl. If the reference count drops to zero, free it. + * @gpadl may be NULL, in which case nothing is done. + */ +void vmbus_put_gpadl(VMBusGpadl *gpadl); + +/* + * Calculate total length in bytes of @gpadl. + * @gpadl must be valid. + */ +uint32_t vmbus_gpadl_len(VMBusGpadl *gpadl); + +/* + * Copy data from @iov to @gpadl at offset @off. + * Return the number of bytes copied, or a negative status on failure. + */ +ssize_t vmbus_iov_to_gpadl(VMBusChannel *chan, VMBusGpadl *gpadl, uint32_t off, + const struct iovec *iov, size_t iov_cnt); + +/* + * Map SGList contained in the request @req, at offset @off and no more than + * @len bytes, for io in direction @dir, and populate @iov with the mapped + * iovecs. + * Return the number of iovecs mapped, or negative status on failure. + */ +int vmbus_map_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov, + unsigned iov_cnt, size_t len, size_t off); + +/* + * Unmap *iov mapped with vmbus_map_sgl, marking the number of bytes @accessed. + */ +void vmbus_unmap_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov, + unsigned iov_cnt, size_t accessed); + +#endif From cab78e7cb298c247c1749125001362a586c45c1f Mon Sep 17 00:00:00 2001 From: Jon Doron Date: Fri, 24 Apr 2020 15:34:42 +0300 Subject: [PATCH 1048/2595] i386:pc: whitelist dynamic vmbus-bridge As vmbus-bridge is derived from sysbus device, it has to be whitelisted to be allowed to be created with -device. Signed-off-by: Roman Kagan Signed-off-by: Maciej S. Szmigiero Signed-off-by: Jon Doron Message-Id: <20200424123444.3481728-5-arilou@gmail.com> Signed-off-by: Paolo Bonzini --- hw/i386/pc_piix.c | 2 ++ hw/i386/pc_q35.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index f66e1d73ce..2613d25bda 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -60,6 +60,7 @@ #include "migration/global_state.h" #include "migration/misc.h" #include "sysemu/numa.h" +#include "hw/hyperv/vmbus-bridge.h" #include "hw/mem/nvdimm.h" #include "hw/i386/acpi-build.h" @@ -419,6 +420,7 @@ static void pc_i440fx_machine_options(MachineClass *m) m->default_machine_opts = "firmware=bios-256k.bin"; m->default_display = "std"; machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE); + machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE); } static void pc_i440fx_5_1_machine_options(MachineClass *m) diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 4ba8ac8774..688d57ddf3 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -53,6 +53,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/numa.h" +#include "hw/hyperv/vmbus-bridge.h" #include "hw/mem/nvdimm.h" #include "hw/i386/acpi-build.h" @@ -348,6 +349,7 @@ static void pc_q35_machine_options(MachineClass *m) machine_class_allow_dynamic_sysbus_dev(m, TYPE_AMD_IOMMU_DEVICE); machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE); machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE); + machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE); m->max_cpus = 288; } From 6775d15de18268718c2f971c2b2d255c76ff2240 Mon Sep 17 00:00:00 2001 From: Jon Doron Date: Fri, 24 Apr 2020 15:34:43 +0300 Subject: [PATCH 1049/2595] i386: Hyper-V VMBus ACPI DSDT entry Guest OS uses ACPI to discover VMBus presence. Add a corresponding entry to DSDT in case VMBus has been enabled. Experimentally Windows guests were found to require this entry to include two IRQ resources. They seem to never be used but they still have to be there. Make IRQ numbers user-configurable via corresponding properties; use 7 and 13 by default. Signed-off-by: Evgeny Yakovlev Signed-off-by: Roman Kagan Signed-off-by: Maciej S. Szmigiero Signed-off-by: Jon Doron Message-Id: <20200424123444.3481728-6-arilou@gmail.com> Signed-off-by: Paolo Bonzini --- hw/hyperv/vmbus.c | 7 ++++++ hw/i386/acpi-build.c | 43 ++++++++++++++++++++++++++++++++ include/hw/hyperv/vmbus-bridge.h | 3 +++ 3 files changed, 53 insertions(+) diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index 802bbc8c96..2acb2185e8 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -2641,6 +2641,12 @@ static const VMStateDescription vmstate_vmbus_bridge = { }, }; +static Property vmbus_bridge_props[] = { + DEFINE_PROP_UINT8("irq0", VMBusBridge, irq0, 7), + DEFINE_PROP_UINT8("irq1", VMBusBridge, irq1, 13), + DEFINE_PROP_END_OF_LIST() +}; + static void vmbus_bridge_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); @@ -2651,6 +2657,7 @@ static void vmbus_bridge_class_init(ObjectClass *klass, void *data) sk->explicit_ofw_unit_address = vmbus_bridge_ofw_unit_address; set_bit(DEVICE_CATEGORY_BRIDGE, k->categories); k->vmsd = &vmstate_vmbus_bridge; + device_class_set_props(k, vmbus_bridge_props); /* override SysBusDevice's default */ k->user_creatable = true; } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 2e15f6848e..dcdfbd8906 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -50,6 +50,7 @@ #include "hw/mem/nvdimm.h" #include "sysemu/numa.h" #include "sysemu/reset.h" +#include "hw/hyperv/vmbus-bridge.h" /* Supported chipsets: */ #include "hw/southbridge/piix.h" @@ -1270,9 +1271,47 @@ static Aml *build_com_device_aml(uint8_t uid) return dev; } +static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge) +{ + Aml *dev; + Aml *method; + Aml *crs; + + dev = aml_device("VMBS"); + aml_append(dev, aml_name_decl("STA", aml_int(0xF))); + aml_append(dev, aml_name_decl("_HID", aml_string("VMBus"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0x0))); + aml_append(dev, aml_name_decl("_DDN", aml_string("VMBUS"))); + + method = aml_method("_DIS", 0, AML_NOTSERIALIZED); + aml_append(method, aml_store(aml_and(aml_name("STA"), aml_int(0xD), NULL), + aml_name("STA"))); + aml_append(dev, method); + + method = aml_method("_PS0", 0, AML_NOTSERIALIZED); + aml_append(method, aml_store(aml_or(aml_name("STA"), aml_int(0xF), NULL), + aml_name("STA"))); + aml_append(dev, method); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_name("STA"))); + aml_append(dev, method); + + aml_append(dev, aml_name_decl("_PS3", aml_int(0x0))); + + crs = aml_resource_template(); + aml_append(crs, aml_irq_no_flags(vmbus_bridge->irq0)); + /* FIXME: newer HyperV gets by with only one IRQ */ + aml_append(crs, aml_irq_no_flags(vmbus_bridge->irq1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + + return dev; +} + static void build_isa_devices_aml(Aml *table) { ISADevice *fdc = pc_find_fdc0(); + VMBusBridge *vmbus_bridge = vmbus_bridge_find(); bool ambiguous; Aml *scope = aml_scope("_SB.PCI0.ISA"); @@ -1297,6 +1336,10 @@ static void build_isa_devices_aml(Aml *table) isa_build_aml(ISA_BUS(obj), scope); } + if (vmbus_bridge) { + aml_append(scope, build_vmbus_device_aml(vmbus_bridge)); + } + aml_append(table, scope); } diff --git a/include/hw/hyperv/vmbus-bridge.h b/include/hw/hyperv/vmbus-bridge.h index 9cc8f780de..c0a06d832c 100644 --- a/include/hw/hyperv/vmbus-bridge.h +++ b/include/hw/hyperv/vmbus-bridge.h @@ -19,6 +19,9 @@ typedef struct VMBus VMBus; typedef struct VMBusBridge { SysBusDevice parent_obj; + uint8_t irq0; + uint8_t irq1; + VMBus *bus; } VMBusBridge; From 4dd8a7064b8a6527f99a62be11a5124e65cae270 Mon Sep 17 00:00:00 2001 From: Jon Doron Date: Fri, 24 Apr 2020 15:34:44 +0300 Subject: [PATCH 1050/2595] vmbus: add infrastructure to save/load vmbus requests This can be allow to include controller-specific data while saving/loading in-flight scsi requests of the vmbus scsi controller. Signed-off-by: Roman Kagan Signed-off-by: Maciej S. Szmigiero Signed-off-by: Jon Doron Message-Id: <20200424123444.3481728-7-arilou@gmail.com> Signed-off-by: Paolo Bonzini --- hw/hyperv/vmbus.c | 99 +++++++++++++++++++++++++++++++++++++++ include/hw/hyperv/vmbus.h | 3 ++ 2 files changed, 102 insertions(+) diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index 2acb2185e8..f371240176 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -1272,6 +1272,105 @@ void vmbus_free_req(void *req) g_free(req); } +static const VMStateDescription vmstate_sgent = { + .name = "vmbus/sgentry", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT64(base, ScatterGatherEntry), + VMSTATE_UINT64(len, ScatterGatherEntry), + VMSTATE_END_OF_LIST() + } +}; + +typedef struct VMBusChanReqSave { + uint16_t chan_idx; + uint16_t pkt_type; + uint32_t msglen; + void *msg; + uint64_t transaction_id; + bool need_comp; + uint32_t num; + ScatterGatherEntry *sgl; +} VMBusChanReqSave; + +static const VMStateDescription vmstate_vmbus_chan_req = { + .name = "vmbus/vmbus_chan_req", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT16(chan_idx, VMBusChanReqSave), + VMSTATE_UINT16(pkt_type, VMBusChanReqSave), + VMSTATE_UINT32(msglen, VMBusChanReqSave), + VMSTATE_VBUFFER_ALLOC_UINT32(msg, VMBusChanReqSave, 0, NULL, msglen), + VMSTATE_UINT64(transaction_id, VMBusChanReqSave), + VMSTATE_BOOL(need_comp, VMBusChanReqSave), + VMSTATE_UINT32(num, VMBusChanReqSave), + VMSTATE_STRUCT_VARRAY_POINTER_UINT32(sgl, VMBusChanReqSave, num, + vmstate_sgent, ScatterGatherEntry), + VMSTATE_END_OF_LIST() + } +}; + +void vmbus_save_req(QEMUFile *f, VMBusChanReq *req) +{ + VMBusChanReqSave req_save; + + req_save.chan_idx = req->chan->subchan_idx; + req_save.pkt_type = req->pkt_type; + req_save.msglen = req->msglen; + req_save.msg = req->msg; + req_save.transaction_id = req->transaction_id; + req_save.need_comp = req->need_comp; + req_save.num = req->sgl.nsg; + req_save.sgl = g_memdup(req->sgl.sg, + req_save.num * sizeof(ScatterGatherEntry)); + + vmstate_save_state(f, &vmstate_vmbus_chan_req, &req_save, NULL); + + g_free(req_save.sgl); +} + +void *vmbus_load_req(QEMUFile *f, VMBusDevice *dev, uint32_t size) +{ + VMBusChanReqSave req_save; + VMBusChanReq *req = NULL; + VMBusChannel *chan = NULL; + uint32_t i; + + vmstate_load_state(f, &vmstate_vmbus_chan_req, &req_save, 0); + + if (req_save.chan_idx >= dev->num_channels) { + error_report("%s: %u(chan_idx) > %u(num_channels)", __func__, + req_save.chan_idx, dev->num_channels); + goto out; + } + chan = &dev->channels[req_save.chan_idx]; + + if (vmbus_channel_reserve(chan, 0, req_save.msglen)) { + goto out; + } + + req = vmbus_alloc_req(chan, size, req_save.pkt_type, req_save.msglen, + req_save.transaction_id, req_save.need_comp); + if (req_save.msglen) { + memcpy(req->msg, req_save.msg, req_save.msglen); + } + + for (i = 0; i < req_save.num; i++) { + qemu_sglist_add(&req->sgl, req_save.sgl[i].base, req_save.sgl[i].len); + } + +out: + if (req_save.msglen) { + g_free(req_save.msg); + } + if (req_save.num) { + g_free(req_save.sgl); + } + return req; +} + static void channel_event_cb(EventNotifier *e) { VMBusChannel *chan = container_of(e, VMBusChannel, notifier); diff --git a/include/hw/hyperv/vmbus.h b/include/hw/hyperv/vmbus.h index 99b647e1d6..40e8417eec 100644 --- a/include/hw/hyperv/vmbus.h +++ b/include/hw/hyperv/vmbus.h @@ -224,4 +224,7 @@ int vmbus_map_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov, void vmbus_unmap_sgl(VMBusChanReq *req, DMADirection dir, struct iovec *iov, unsigned iov_cnt, size_t accessed); +void vmbus_save_req(QEMUFile *f, VMBusChanReq *req); +void *vmbus_load_req(QEMUFile *f, VMBusDevice *dev, uint32_t size); + #endif From cac9edfc4dad2a7d2ad7e23e0de4edc41801e346 Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Fri, 17 Apr 2020 16:55:13 -0500 Subject: [PATCH 1051/2595] target/i386: Fix the CPUID leaf CPUID_Fn80000008 CPUID leaf CPUID_Fn80000008_ECX provides information about the number of threads supported by the processor. It was found that the field ApicIdSize(bits 15-12) was not set correctly. ApicIdSize is defined as the number of bits required to represent all the ApicId values within a package. Valid Values: Value Description 3h-0h Reserved. 4h up to 16 threads. 5h up to 32 threads. 6h up to 64 threads. 7h up to 128 threads. Fh-8h Reserved. Fix the bit appropriately. This came up during following thread. https://lore.kernel.org/qemu-devel/158643709116.17430.15995069125716778943.malonedeb@wampee.canonical.com/#t Refer the Processor Programming Reference (PPR) for AMD Family 17h Model 01h, Revision B1 Processors. The documentation is available from the bugzilla Link below. Link: https://bugzilla.kernel.org/show_bug.cgi?id=206537 Reported-by: Philipp Eppelt <1871842@bugs.launchpad.net> Signed-off-by: Babu Moger Message-Id: <20200417215345.64800.73351.stgit@localhost.localdomain> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ba05da3f2e..25a8f6b1ad 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5837,11 +5837,20 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *eax = cpu->phys_bits; } *ebx = env->features[FEAT_8000_0008_EBX]; - *ecx = 0; - *edx = 0; if (cs->nr_cores * cs->nr_threads > 1) { - *ecx |= (cs->nr_cores * cs->nr_threads) - 1; + /* + * Bits 15:12 is "The number of bits in the initial + * Core::X86::Apic::ApicId[ApicId] value that indicate + * thread ID within a package". This is already stored at + * CPUX86State::pkg_offset. + * Bits 7:0 is "The number of threads in the package is NC+1" + */ + *ecx = (env->pkg_offset << 12) | + ((cs->nr_cores * cs->nr_threads) - 1); + } else { + *ecx = 0; } + *edx = 0; break; case 0x8000000A: if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) { From 2dfbea1a872727fb747ca6adf2390e09956cdc6e Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 2 Apr 2020 00:52:53 +0200 Subject: [PATCH 1052/2595] target/i386: fix phadd* with identical destination and source register Detected by asm test suite failures in dav1d (https://code.videolan.org/videolan/dav1d). Can be reproduced by `qemu-x86_64 -cpu core2duo ./tests/checkasm --test=mc_8bpc 1659890620`. Signed-off-by: Janne Grunau Message-Id: <20200401225253.30745-1-j@jannau.net> Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/ops_sse.h | 53 +++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h index 4658768de2..01d6017412 100644 --- a/target/i386/ops_sse.h +++ b/target/i386/ops_sse.h @@ -1435,34 +1435,47 @@ void glue(helper_pshufb, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) void glue(helper_phaddw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - d->W(0) = (int16_t)d->W(0) + (int16_t)d->W(1); - d->W(1) = (int16_t)d->W(2) + (int16_t)d->W(3); - XMM_ONLY(d->W(2) = (int16_t)d->W(4) + (int16_t)d->W(5)); - XMM_ONLY(d->W(3) = (int16_t)d->W(6) + (int16_t)d->W(7)); - d->W((2 << SHIFT) + 0) = (int16_t)s->W(0) + (int16_t)s->W(1); - d->W((2 << SHIFT) + 1) = (int16_t)s->W(2) + (int16_t)s->W(3); - XMM_ONLY(d->W(6) = (int16_t)s->W(4) + (int16_t)s->W(5)); - XMM_ONLY(d->W(7) = (int16_t)s->W(6) + (int16_t)s->W(7)); + + Reg r; + + r.W(0) = (int16_t)d->W(0) + (int16_t)d->W(1); + r.W(1) = (int16_t)d->W(2) + (int16_t)d->W(3); + XMM_ONLY(r.W(2) = (int16_t)d->W(4) + (int16_t)d->W(5)); + XMM_ONLY(r.W(3) = (int16_t)d->W(6) + (int16_t)d->W(7)); + r.W((2 << SHIFT) + 0) = (int16_t)s->W(0) + (int16_t)s->W(1); + r.W((2 << SHIFT) + 1) = (int16_t)s->W(2) + (int16_t)s->W(3); + XMM_ONLY(r.W(6) = (int16_t)s->W(4) + (int16_t)s->W(5)); + XMM_ONLY(r.W(7) = (int16_t)s->W(6) + (int16_t)s->W(7)); + + *d = r; } void glue(helper_phaddd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - d->L(0) = (int32_t)d->L(0) + (int32_t)d->L(1); - XMM_ONLY(d->L(1) = (int32_t)d->L(2) + (int32_t)d->L(3)); - d->L((1 << SHIFT) + 0) = (int32_t)s->L(0) + (int32_t)s->L(1); - XMM_ONLY(d->L(3) = (int32_t)s->L(2) + (int32_t)s->L(3)); + Reg r; + + r.L(0) = (int32_t)d->L(0) + (int32_t)d->L(1); + XMM_ONLY(r.L(1) = (int32_t)d->L(2) + (int32_t)d->L(3)); + r.L((1 << SHIFT) + 0) = (int32_t)s->L(0) + (int32_t)s->L(1); + XMM_ONLY(r.L(3) = (int32_t)s->L(2) + (int32_t)s->L(3)); + + *d = r; } void glue(helper_phaddsw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - d->W(0) = satsw((int16_t)d->W(0) + (int16_t)d->W(1)); - d->W(1) = satsw((int16_t)d->W(2) + (int16_t)d->W(3)); - XMM_ONLY(d->W(2) = satsw((int16_t)d->W(4) + (int16_t)d->W(5))); - XMM_ONLY(d->W(3) = satsw((int16_t)d->W(6) + (int16_t)d->W(7))); - d->W((2 << SHIFT) + 0) = satsw((int16_t)s->W(0) + (int16_t)s->W(1)); - d->W((2 << SHIFT) + 1) = satsw((int16_t)s->W(2) + (int16_t)s->W(3)); - XMM_ONLY(d->W(6) = satsw((int16_t)s->W(4) + (int16_t)s->W(5))); - XMM_ONLY(d->W(7) = satsw((int16_t)s->W(6) + (int16_t)s->W(7))); + Reg r; + + r.W(0) = satsw((int16_t)d->W(0) + (int16_t)d->W(1)); + r.W(1) = satsw((int16_t)d->W(2) + (int16_t)d->W(3)); + XMM_ONLY(r.W(2) = satsw((int16_t)d->W(4) + (int16_t)d->W(5))); + XMM_ONLY(r.W(3) = satsw((int16_t)d->W(6) + (int16_t)d->W(7))); + r.W((2 << SHIFT) + 0) = satsw((int16_t)s->W(0) + (int16_t)s->W(1)); + r.W((2 << SHIFT) + 1) = satsw((int16_t)s->W(2) + (int16_t)s->W(3)); + XMM_ONLY(r.W(6) = satsw((int16_t)s->W(4) + (int16_t)s->W(5))); + XMM_ONLY(r.W(7) = satsw((int16_t)s->W(6) + (int16_t)s->W(7))); + + *d = r; } void glue(helper_pmaddubsw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) From 29282253b79fcb917d154d37a491c17b390f258b Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:16 +0200 Subject: [PATCH 1053/2595] hw/i386/vmport: Add reference to VMware open-vm-tools This official VMware open-source project can be used as reference to understand how guest code interacts with VMPort virtual device. Thus, providing understanding on how device is expected to behave. Signed-off-by: Liran Alon Message-Id: <20200312165431.82118-2-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/i386/vmport.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 1aaaab691a..fc0074608e 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -21,6 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + +/* + * Guest code that interacts with this virtual device can be found + * in VMware open-vm-tools open-source project: + * https://github.com/vmware/open-vm-tools + */ + #include "qemu/osdep.h" #include "hw/isa/isa.h" #include "sysemu/hw_accel.h" From c9ab24cef8ab680e3d24d7332599b2b857bd107b Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:17 +0200 Subject: [PATCH 1054/2595] hw/i386/vmport: Add device properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change. This is done as a preparation for the following patches that will introduce several device properties. Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200312165431.82118-3-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/i386/vmport.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index fc0074608e..5985167dcf 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -30,6 +30,7 @@ #include "qemu/osdep.h" #include "hw/isa/isa.h" +#include "hw/qdev-properties.h" #include "sysemu/hw_accel.h" #include "qemu/log.h" #include "vmport.h" @@ -140,6 +141,10 @@ static void vmport_realizefn(DeviceState *dev, Error **errp) vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL); } +static Property vmport_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + static void vmport_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -147,6 +152,7 @@ static void vmport_class_initfn(ObjectClass *klass, void *data) dc->realize = vmport_realizefn; /* Reason: realize sets global port_state */ dc->user_creatable = false; + device_class_set_props(dc, vmport_properties); } static const TypeInfo vmport_info = { From b889212973dabee119a1ab21326a27fc51b88d6d Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:18 +0200 Subject: [PATCH 1055/2595] hw/i386/vmport: Propagate IOPort read to vCPU EAX register vmport_ioport_read() returns the value that should propagate to vCPU EAX register when guest reads VMPort IOPort (i.e. By x86 IN instruction). However, because vmport_ioport_read() calls cpu_synchronize_state(), the returned value gets overridden by the value in QEMU vCPU EAX register. i.e. cpu->env.regs[R_EAX]. To fix this issue, change vmport_ioport_read() to explicitly override cpu->env.regs[R_EAX] with the value it wish to propagate to vCPU EAX register. Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Message-Id: <20200312165431.82118-4-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 1 + hw/i386/vmport.c | 32 +++++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index bb3a7b18b1..83f0fe5c91 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -43,6 +43,7 @@ GlobalProperty hw_compat_4_2[] = { { "qxl", "revision", "4" }, { "qxl-vga", "revision", "4" }, { "fw_cfg", "acpi-mr-restore", "false" }, + { "vmport", "x-read-set-eax", "off" }, }; const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2); diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 5985167dcf..3bb420a245 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -43,6 +43,11 @@ #define VMPORT_ENTRIES 0x2c #define VMPORT_MAGIC 0x564D5868 +/* Compatibility flags for migration */ +#define VMPORT_COMPAT_READ_SET_EAX_BIT 0 +#define VMPORT_COMPAT_READ_SET_EAX \ + (1 << VMPORT_COMPAT_READ_SET_EAX_BIT) + #define VMPORT(obj) OBJECT_CHECK(VMPortState, (obj), TYPE_VMPORT) typedef struct VMPortState { @@ -51,6 +56,8 @@ typedef struct VMPortState { MemoryRegion io; VMPortReadFunc *func[VMPORT_ENTRIES]; void *opaque[VMPORT_ENTRIES]; + + uint32_t compat_flags; } VMPortState; static VMPortState *port_state; @@ -80,17 +87,33 @@ static uint64_t vmport_ioport_read(void *opaque, hwaddr addr, eax = env->regs[R_EAX]; if (eax != VMPORT_MAGIC) { - return eax; + goto out; } command = env->regs[R_ECX]; trace_vmport_command(command); if (command >= VMPORT_ENTRIES || !s->func[command]) { qemu_log_mask(LOG_UNIMP, "vmport: unknown command %x\n", command); - return eax; + goto out; } - return s->func[command](s->opaque[command], addr); + eax = s->func[command](s->opaque[command], addr); + +out: + /* + * The call above to cpu_synchronize_state() gets vCPU registers values + * to QEMU but also cause QEMU to write QEMU vCPU registers values to + * vCPU implementation (e.g. Accelerator such as KVM) just before + * resuming guest. + * + * Therefore, in order to make IOPort return value propagate to + * guest EAX, we need to explicitly update QEMU EAX register value. + */ + if (s->compat_flags & VMPORT_COMPAT_READ_SET_EAX) { + cpu->env.regs[R_EAX] = eax; + } + + return eax; } static void vmport_ioport_write(void *opaque, hwaddr addr, @@ -142,6 +165,9 @@ static void vmport_realizefn(DeviceState *dev, Error **errp) } static Property vmport_properties[] = { + /* Used to enforce compatibility for migration */ + DEFINE_PROP_BIT("x-read-set-eax", VMPortState, compat_flags, + VMPORT_COMPAT_READ_SET_EAX_BIT, true), DEFINE_PROP_END_OF_LIST(), }; From 0342ee761ef27a0def476dab3e284f924b3c801e Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:19 +0200 Subject: [PATCH 1056/2595] hw/i386/vmport: Set EAX to -1 on failed and unsupported commands This is used as a signal for VMware Tools to know if a command it attempted to invoke, failed or is unsupported. As a result, VMware Tools will either report failure to user or fallback to another backdoor command in attempt to perform some operation. A few examples: * open-vm-tools TimeSyncReadHost() function fallbacks to CMD_GETTIMEFULL command when CMD_GETTIMEFULL_WITH_LAG fails/unsupported. * open-vm-tools Hostinfo_NestingSupported() function verifies EAX != -1 to check for success. * open-vm-tools Hostinfo_VCPUInfoBackdoor() functions checks if reserved-bit is set to indicate command is unimplemented. Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Message-Id: <20200312165431.82118-5-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 1 + hw/i386/vmport.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 83f0fe5c91..fc209d711b 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -44,6 +44,7 @@ GlobalProperty hw_compat_4_2[] = { { "qxl-vga", "revision", "4" }, { "fw_cfg", "acpi-mr-restore", "false" }, { "vmport", "x-read-set-eax", "off" }, + { "vmport", "x-signal-unsupported-cmd", "off" }, }; const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2); diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 3bb420a245..730b61fcaa 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -44,9 +44,12 @@ #define VMPORT_MAGIC 0x564D5868 /* Compatibility flags for migration */ -#define VMPORT_COMPAT_READ_SET_EAX_BIT 0 -#define VMPORT_COMPAT_READ_SET_EAX \ +#define VMPORT_COMPAT_READ_SET_EAX_BIT 0 +#define VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD_BIT 1 +#define VMPORT_COMPAT_READ_SET_EAX \ (1 << VMPORT_COMPAT_READ_SET_EAX_BIT) +#define VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD \ + (1 << VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD_BIT) #define VMPORT(obj) OBJECT_CHECK(VMPortState, (obj), TYPE_VMPORT) @@ -87,17 +90,23 @@ static uint64_t vmport_ioport_read(void *opaque, hwaddr addr, eax = env->regs[R_EAX]; if (eax != VMPORT_MAGIC) { - goto out; + goto err; } command = env->regs[R_ECX]; trace_vmport_command(command); if (command >= VMPORT_ENTRIES || !s->func[command]) { qemu_log_mask(LOG_UNIMP, "vmport: unknown command %x\n", command); - goto out; + goto err; } eax = s->func[command](s->opaque[command], addr); + goto out; + +err: + if (s->compat_flags & VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD) { + eax = UINT32_MAX; + } out: /* @@ -168,6 +177,8 @@ static Property vmport_properties[] = { /* Used to enforce compatibility for migration */ DEFINE_PROP_BIT("x-read-set-eax", VMPortState, compat_flags, VMPORT_COMPAT_READ_SET_EAX_BIT, true), + DEFINE_PROP_BIT("x-signal-unsupported-cmd", VMPortState, compat_flags, + VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD_BIT, true), DEFINE_PROP_END_OF_LIST(), }; From 2fd2f799f874a4d4156c4c7287c92cfbbae5bdb2 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:20 +0200 Subject: [PATCH 1057/2595] hw/i386/vmport: Introduce vmware-vmx-version property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vmware-vmx-version is a number returned from CMD_GETVERSION which specifies to guest VMware Tools the the host VMX version. If the host reports a number that is different than what the guest VMware Tools expects, it may force guest to upgrade VMware Tools. (See comment above VERSION_MAGIC and VmCheck_IsVirtualWorld() function in open-vm-tools open-source code). For better readability and allow maintaining compatability for guests which may expect different vmware-vmx-version, make vmware-vmx-version a VMPort object property. This would allow user to control it's value via "-global vmport.vmware-vmx-version=X". Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200312165431.82118-6-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/i386/vmport.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 730b61fcaa..dfebaf5b73 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -60,6 +60,8 @@ typedef struct VMPortState { VMPortReadFunc *func[VMPORT_ENTRIES]; void *opaque[VMPORT_ENTRIES]; + uint32_t vmware_vmx_version; + uint32_t compat_flags; } VMPortState; @@ -138,7 +140,7 @@ static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr) X86CPU *cpu = X86_CPU(current_cpu); cpu->env.regs[R_EBX] = VMPORT_MAGIC; - return 6; + return port_state->vmware_vmx_version; } static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) @@ -179,6 +181,11 @@ static Property vmport_properties[] = { VMPORT_COMPAT_READ_SET_EAX_BIT, true), DEFINE_PROP_BIT("x-signal-unsupported-cmd", VMPortState, compat_flags, VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD_BIT, true), + + /* Default value taken from open-vm-tools code VERSION_MAGIC definition */ + DEFINE_PROP_UINT32("vmware-vmx-version", VMPortState, + vmware_vmx_version, 6), + DEFINE_PROP_END_OF_LIST(), }; From f8bdc550370f9a652a00db891f9b7640d83c0c43 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:21 +0200 Subject: [PATCH 1058/2595] hw/i386/vmport: Report vmware-vmx-type in CMD_GETVERSION As can be seen from VmCheck_GetVersion() in open-vm-tools code, CMD_GETVERSION should return vmware-vmx-type in ECX register. Default is to fake host as VMware ESX server. But user can control this value by "-global vmport.vmware-vmx-type=X". Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Message-Id: <20200312165431.82118-7-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 1 + hw/i386/vmport.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index fc209d711b..9a07e9333a 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -45,6 +45,7 @@ GlobalProperty hw_compat_4_2[] = { { "fw_cfg", "acpi-mr-restore", "false" }, { "vmport", "x-read-set-eax", "off" }, { "vmport", "x-signal-unsupported-cmd", "off" }, + { "vmport", "x-report-vmx-type", "off" }, }; const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2); diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index dfebaf5b73..dabb443367 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -46,10 +46,13 @@ /* Compatibility flags for migration */ #define VMPORT_COMPAT_READ_SET_EAX_BIT 0 #define VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD_BIT 1 +#define VMPORT_COMPAT_REPORT_VMX_TYPE_BIT 2 #define VMPORT_COMPAT_READ_SET_EAX \ (1 << VMPORT_COMPAT_READ_SET_EAX_BIT) #define VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD \ (1 << VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD_BIT) +#define VMPORT_COMPAT_REPORT_VMX_TYPE \ + (1 << VMPORT_COMPAT_REPORT_VMX_TYPE_BIT) #define VMPORT(obj) OBJECT_CHECK(VMPortState, (obj), TYPE_VMPORT) @@ -61,6 +64,7 @@ typedef struct VMPortState { void *opaque[VMPORT_ENTRIES]; uint32_t vmware_vmx_version; + uint8_t vmware_vmx_type; uint32_t compat_flags; } VMPortState; @@ -140,6 +144,9 @@ static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr) X86CPU *cpu = X86_CPU(current_cpu); cpu->env.regs[R_EBX] = VMPORT_MAGIC; + if (port_state->compat_flags & VMPORT_COMPAT_REPORT_VMX_TYPE) { + cpu->env.regs[R_ECX] = port_state->vmware_vmx_type; + } return port_state->vmware_vmx_version; } @@ -181,10 +188,30 @@ static Property vmport_properties[] = { VMPORT_COMPAT_READ_SET_EAX_BIT, true), DEFINE_PROP_BIT("x-signal-unsupported-cmd", VMPortState, compat_flags, VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD_BIT, true), + DEFINE_PROP_BIT("x-report-vmx-type", VMPortState, compat_flags, + VMPORT_COMPAT_REPORT_VMX_TYPE_BIT, true), /* Default value taken from open-vm-tools code VERSION_MAGIC definition */ DEFINE_PROP_UINT32("vmware-vmx-version", VMPortState, vmware_vmx_version, 6), + /* + * Value determines which VMware product type host report itself to guest. + * + * Most guests are fine with exposing host as VMware ESX server. + * Some legacy/proprietary guests hard-code a given type. + * + * For a complete list of values, refer to enum VMXType at open-vm-tools + * project (Defined at lib/include/vm_vmx_type.h). + * + * Reasonable options: + * 0 - Unset + * 1 - VMware Express (deprecated) + * 2 - VMware ESX Server + * 3 - VMware Server (Deprecated) + * 4 - VMware Workstation + * 5 - ACE 1.x (Deprecated) + */ + DEFINE_PROP_UINT8("vmware-vmx-type", VMPortState, vmware_vmx_type, 2), DEFINE_PROP_END_OF_LIST(), }; From d8f23d619c495bc64977c00e92f3af4ff2c54046 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:22 +0200 Subject: [PATCH 1059/2595] hw/i386/vmport: Introduce vmport.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change. This is mere refactoring. Suggested-by: Michael S. Tsirkin Signed-off-by: Liran Alon Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200312165431.82118-8-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/i386/pc.c | 2 +- hw/i386/vmmouse.c | 2 +- hw/i386/vmport.c | 2 +- hw/i386/vmport.h | 34 ---------------------------------- include/hw/i386/vmport.h | 16 ++++++++++++++++ 5 files changed, 19 insertions(+), 37 deletions(-) delete mode 100644 hw/i386/vmport.h create mode 100644 include/hw/i386/vmport.h diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 2128f3d6fe..b9961b1035 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -31,6 +31,7 @@ #include "hw/i386/apic.h" #include "hw/i386/topology.h" #include "hw/i386/fw_cfg.h" +#include "hw/i386/vmport.h" #include "sysemu/cpus.h" #include "hw/block/fdc.h" #include "hw/ide.h" @@ -91,7 +92,6 @@ #include "qapi/qmp/qerror.h" #include "config-devices.h" #include "e820_memory_layout.h" -#include "vmport.h" #include "fw_cfg.h" #include "trace.h" diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c index b3aef41327..b73f076753 100644 --- a/hw/i386/vmmouse.c +++ b/hw/i386/vmmouse.c @@ -25,10 +25,10 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "ui/console.h" +#include "hw/i386/vmport.h" #include "hw/input/i8042.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "vmport.h" #include "cpu.h" /* debug only vmmouse */ diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index dabb443367..e6d169566d 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -30,10 +30,10 @@ #include "qemu/osdep.h" #include "hw/isa/isa.h" +#include "hw/i386/vmport.h" #include "hw/qdev-properties.h" #include "sysemu/hw_accel.h" #include "qemu/log.h" -#include "vmport.h" #include "cpu.h" #include "trace.h" diff --git a/hw/i386/vmport.h b/hw/i386/vmport.h deleted file mode 100644 index 47eda7a22b..0000000000 --- a/hw/i386/vmport.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * QEMU VMPort emulation - * - * Copyright (C) 2007 Hervé Poussineau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef HW_I386_VMPORT_H -#define HW_I386_VMPORT_H - -#define TYPE_VMPORT "vmport" - -typedef uint32_t (VMPortReadFunc)(void *opaque, uint32_t address); - -void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque); - -#endif diff --git a/include/hw/i386/vmport.h b/include/hw/i386/vmport.h new file mode 100644 index 0000000000..efbe3e0e3f --- /dev/null +++ b/include/hw/i386/vmport.h @@ -0,0 +1,16 @@ +#ifndef HW_VMPORT_H +#define HW_VMPORT_H + +#include "hw/isa/isa.h" + +#define TYPE_VMPORT "vmport" +typedef uint32_t (VMPortReadFunc)(void *opaque, uint32_t address); + +static inline void vmport_init(ISABus *bus) +{ + isa_create_simple(bus, TYPE_VMPORT); +} + +void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque); + +#endif From dcd938f032d3cca5d33d9faaca591b498d40debe Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:23 +0200 Subject: [PATCH 1060/2595] hw/i386/vmport: Define enum for all commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change. Defining an enum for all VMPort commands have the following advantages: * It gets rid of the error-prone requirement to update VMPORT_ENTRIES when new VMPort commands are added to QEMU. * It makes it clear to know by looking at one place at the source, what are all the VMPort commands supported by QEMU. Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200312165431.82118-9-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/i386/vmmouse.c | 18 ++++++------------ hw/i386/vmport.c | 11 ++--------- include/hw/i386/vmport.h | 11 ++++++++++- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c index b73f076753..ba5c987bd2 100644 --- a/hw/i386/vmmouse.c +++ b/hw/i386/vmmouse.c @@ -34,12 +34,6 @@ /* debug only vmmouse */ //#define DEBUG_VMMOUSE -/* VMMouse Commands */ -#define VMMOUSE_GETVERSION 10 -#define VMMOUSE_DATA 39 -#define VMMOUSE_STATUS 40 -#define VMMOUSE_COMMAND 41 - #define VMMOUSE_READ_ID 0x45414552 #define VMMOUSE_DISABLE 0x000000f5 #define VMMOUSE_REQUEST_RELATIVE 0x4c455252 @@ -217,10 +211,10 @@ static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr) command = data[2] & 0xFFFF; switch (command) { - case VMMOUSE_STATUS: + case VMPORT_CMD_VMMOUSE_STATUS: data[0] = vmmouse_get_status(s); break; - case VMMOUSE_COMMAND: + case VMPORT_CMD_VMMOUSE_COMMAND: switch (data[1]) { case VMMOUSE_DISABLE: vmmouse_disable(s); @@ -239,7 +233,7 @@ static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr) break; } break; - case VMMOUSE_DATA: + case VMPORT_CMD_VMMOUSE_DATA: vmmouse_data(s, data, data[1]); break; default: @@ -296,9 +290,9 @@ static void vmmouse_realizefn(DeviceState *dev, Error **errp) return; } - vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s); - vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s); - vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s); + vmport_register(VMPORT_CMD_VMMOUSE_STATUS, vmmouse_ioport_read, s); + vmport_register(VMPORT_CMD_VMMOUSE_COMMAND, vmmouse_ioport_read, s); + vmport_register(VMPORT_CMD_VMMOUSE_DATA, vmmouse_ioport_read, s); } static Property vmmouse_properties[] = { diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index e6d169566d..359cdef1e0 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -37,10 +37,6 @@ #include "cpu.h" #include "trace.h" -#define VMPORT_CMD_GETVERSION 0x0a -#define VMPORT_CMD_GETRAMSIZE 0x14 - -#define VMPORT_ENTRIES 0x2c #define VMPORT_MAGIC 0x564D5868 /* Compatibility flags for migration */ @@ -71,12 +67,9 @@ typedef struct VMPortState { static VMPortState *port_state; -void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque) +void vmport_register(VMPortCommand command, VMPortReadFunc *func, void *opaque) { - if (command >= VMPORT_ENTRIES) { - return; - } - + assert(command < VMPORT_ENTRIES); trace_vmport_register(command, func, opaque); port_state->func[command] = func; port_state->opaque[command] = opaque; diff --git a/include/hw/i386/vmport.h b/include/hw/i386/vmport.h index efbe3e0e3f..bbe2c58bf9 100644 --- a/include/hw/i386/vmport.h +++ b/include/hw/i386/vmport.h @@ -6,11 +6,20 @@ #define TYPE_VMPORT "vmport" typedef uint32_t (VMPortReadFunc)(void *opaque, uint32_t address); +typedef enum { + VMPORT_CMD_GETVERSION = 10, + VMPORT_CMD_GETRAMSIZE = 20, + VMPORT_CMD_VMMOUSE_DATA = 39, + VMPORT_CMD_VMMOUSE_STATUS = 40, + VMPORT_CMD_VMMOUSE_COMMAND = 41, + VMPORT_ENTRIES +} VMPortCommand; + static inline void vmport_init(ISABus *bus) { isa_create_simple(bus, TYPE_VMPORT); } -void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque); +void vmport_register(VMPortCommand command, VMPortReadFunc *func, void *opaque); #endif From aaacf1c15a225ffeb1ff066b78e211594b3a5053 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:24 +0200 Subject: [PATCH 1061/2595] hw/i386/vmport: Add support for CMD_GETBIOSUUID This is VMware documented functionallity that some guests rely on. Returns the BIOS UUID of the current virtual machine. Note that we also introduce a new compatability flag "x-cmds-v2" to make sure to expose new VMPort commands only to new machine-types. This flag will also be used by the following patches that will introduce additional VMPort commands. Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Message-Id: <20200312165431.82118-10-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 1 + hw/i386/vmport.c | 22 ++++++++++++++++++++++ include/hw/i386/vmport.h | 1 + 3 files changed, 24 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index 9a07e9333a..5460e62294 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -46,6 +46,7 @@ GlobalProperty hw_compat_4_2[] = { { "vmport", "x-read-set-eax", "off" }, { "vmport", "x-signal-unsupported-cmd", "off" }, { "vmport", "x-report-vmx-type", "off" }, + { "vmport", "x-cmds-v2", "off" }, }; const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2); diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 359cdef1e0..8006ff91d4 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -32,6 +32,7 @@ #include "hw/isa/isa.h" #include "hw/i386/vmport.h" #include "hw/qdev-properties.h" +#include "sysemu/sysemu.h" #include "sysemu/hw_accel.h" #include "qemu/log.h" #include "cpu.h" @@ -43,12 +44,15 @@ #define VMPORT_COMPAT_READ_SET_EAX_BIT 0 #define VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD_BIT 1 #define VMPORT_COMPAT_REPORT_VMX_TYPE_BIT 2 +#define VMPORT_COMPAT_CMDS_V2_BIT 3 #define VMPORT_COMPAT_READ_SET_EAX \ (1 << VMPORT_COMPAT_READ_SET_EAX_BIT) #define VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD \ (1 << VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD_BIT) #define VMPORT_COMPAT_REPORT_VMX_TYPE \ (1 << VMPORT_COMPAT_REPORT_VMX_TYPE_BIT) +#define VMPORT_COMPAT_CMDS_V2 \ + (1 << VMPORT_COMPAT_CMDS_V2_BIT) #define VMPORT(obj) OBJECT_CHECK(VMPortState, (obj), TYPE_VMPORT) @@ -143,6 +147,18 @@ static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr) return port_state->vmware_vmx_version; } +static uint32_t vmport_cmd_get_bios_uuid(void *opaque, uint32_t addr) +{ + X86CPU *cpu = X86_CPU(current_cpu); + uint32_t *uuid_parts = (uint32_t *)(qemu_uuid.data); + + cpu->env.regs[R_EAX] = le32_to_cpu(uuid_parts[0]); + cpu->env.regs[R_EBX] = le32_to_cpu(uuid_parts[1]); + cpu->env.regs[R_ECX] = le32_to_cpu(uuid_parts[2]); + cpu->env.regs[R_EDX] = le32_to_cpu(uuid_parts[3]); + return cpu->env.regs[R_EAX]; +} + static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) { X86CPU *cpu = X86_CPU(current_cpu); @@ -170,9 +186,13 @@ static void vmport_realizefn(DeviceState *dev, Error **errp) isa_register_ioport(isadev, &s->io, 0x5658); port_state = s; + /* Register some generic port commands */ vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, NULL); vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL); + if (s->compat_flags & VMPORT_COMPAT_CMDS_V2) { + vmport_register(VMPORT_CMD_GETBIOSUUID, vmport_cmd_get_bios_uuid, NULL); + } } static Property vmport_properties[] = { @@ -183,6 +203,8 @@ static Property vmport_properties[] = { VMPORT_COMPAT_SIGNAL_UNSUPPORTED_CMD_BIT, true), DEFINE_PROP_BIT("x-report-vmx-type", VMPortState, compat_flags, VMPORT_COMPAT_REPORT_VMX_TYPE_BIT, true), + DEFINE_PROP_BIT("x-cmds-v2", VMPortState, compat_flags, + VMPORT_COMPAT_CMDS_V2_BIT, true), /* Default value taken from open-vm-tools code VERSION_MAGIC definition */ DEFINE_PROP_UINT32("vmware-vmx-version", VMPortState, diff --git a/include/hw/i386/vmport.h b/include/hw/i386/vmport.h index bbe2c58bf9..7f566ccc02 100644 --- a/include/hw/i386/vmport.h +++ b/include/hw/i386/vmport.h @@ -8,6 +8,7 @@ typedef uint32_t (VMPortReadFunc)(void *opaque, uint32_t address); typedef enum { VMPORT_CMD_GETVERSION = 10, + VMPORT_CMD_GETBIOSUUID = 19, VMPORT_CMD_GETRAMSIZE = 20, VMPORT_CMD_VMMOUSE_DATA = 39, VMPORT_CMD_VMMOUSE_STATUS = 40, From acacd3550ba1b2379d5a14a00f7dad4820a015b4 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:27 +0200 Subject: [PATCH 1062/2595] hw/i386/vmport: Add support for CMD_GET_VCPU_INFO Command currently returns that it is unimplemented by setting the reserved-bit in it's return value. Following patches will return various useful vCPU information to guest. Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Message-Id: <20200312165431.82118-13-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/i386/vmport.c | 14 ++++++++++++++ include/hw/i386/vmport.h | 1 + 2 files changed, 15 insertions(+) diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 8006ff91d4..942a0e94e3 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -54,6 +54,13 @@ #define VMPORT_COMPAT_CMDS_V2 \ (1 << VMPORT_COMPAT_CMDS_V2_BIT) +/* vCPU features reported by CMD_GET_VCPU_INFO */ +#define VCPU_INFO_SLC64_BIT 0 +#define VCPU_INFO_SYNC_VTSCS_BIT 1 +#define VCPU_INFO_HV_REPLAY_OK_BIT 2 +#define VCPU_INFO_LEGACY_X2APIC_BIT 3 +#define VCPU_INFO_RESERVED_BIT 31 + #define VMPORT(obj) OBJECT_CHECK(VMPortState, (obj), TYPE_VMPORT) typedef struct VMPortState { @@ -167,6 +174,11 @@ static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) return ram_size; } +static uint32_t vmport_cmd_get_vcpu_info(void *opaque, uint32_t addr) +{ + return 1 << VCPU_INFO_RESERVED_BIT; +} + static const MemoryRegionOps vmport_ops = { .read = vmport_ioport_read, .write = vmport_ioport_write, @@ -192,6 +204,8 @@ static void vmport_realizefn(DeviceState *dev, Error **errp) vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL); if (s->compat_flags & VMPORT_COMPAT_CMDS_V2) { vmport_register(VMPORT_CMD_GETBIOSUUID, vmport_cmd_get_bios_uuid, NULL); + vmport_register(VMPORT_CMD_GET_VCPU_INFO, vmport_cmd_get_vcpu_info, + NULL); } } diff --git a/include/hw/i386/vmport.h b/include/hw/i386/vmport.h index 7f566ccc02..7656432358 100644 --- a/include/hw/i386/vmport.h +++ b/include/hw/i386/vmport.h @@ -13,6 +13,7 @@ typedef enum { VMPORT_CMD_VMMOUSE_DATA = 39, VMPORT_CMD_VMMOUSE_STATUS = 40, VMPORT_CMD_VMMOUSE_COMMAND = 41, + VMPORT_CMD_GET_VCPU_INFO = 68, VMPORT_ENTRIES } VMPortCommand; From 7f9114b77c285016cb5ac28604b9923cbac43ddf Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:28 +0200 Subject: [PATCH 1063/2595] hw/i386/vmport: Allow x2apic without IR Signal to guest that hypervisor supports x2apic without VT-d/IOMMU Interrupt-Remapping support. This allows guest to use x2apic in case all APIC IDs fits in 8-bit (i.e. Max APIC ID < 255). See Linux kernel commit 4cca6ea04d31 ("x86/apic: Allow x2apic without IR on VMware platform") and Linux try_to_enable_x2apic() function. Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Message-Id: <20200312165431.82118-14-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/i386/vmport.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 942a0e94e3..21d4ff048a 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -176,7 +176,14 @@ static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) static uint32_t vmport_cmd_get_vcpu_info(void *opaque, uint32_t addr) { - return 1 << VCPU_INFO_RESERVED_BIT; + X86CPU *cpu = X86_CPU(current_cpu); + uint32_t ret = 0; + + if (cpu->env.features[FEAT_1_ECX] & CPUID_EXT_X2APIC) { + ret |= 1 << VCPU_INFO_LEGACY_X2APIC_BIT; + } + + return ret; } static const MemoryRegionOps vmport_ops = { From 73b994f6d74ec00a1d78daf4145096ff9f0e2982 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:29 +0200 Subject: [PATCH 1064/2595] i386/cpu: Store LAPIC bus frequency in CPU structure No functional change. This information will be used by following patches. Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Message-Id: <20200312165431.82118-15-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 1 + target/i386/kvm.c | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 408392dbf6..00d1f4f013 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1584,6 +1584,7 @@ typedef struct CPUX86State { bool tsc_valid; int64_t tsc_khz; int64_t user_tsc_khz; /* for sanity check only */ + uint64_t apic_bus_freq; #if defined(CONFIG_KVM) || defined(CONFIG_HVF) void *xsave_buf; #endif diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 34f838728d..95bbeb424b 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -59,6 +59,10 @@ do { } while (0) #endif +/* From arch/x86/kvm/lapic.h */ +#define KVM_APIC_BUS_CYCLE_NS 1 +#define KVM_APIC_BUS_FREQUENCY (1000000000ULL / KVM_APIC_BUS_CYCLE_NS) + #define MSR_KVM_WALL_CLOCK 0x11 #define MSR_KVM_SYSTEM_TIME 0x12 @@ -1469,6 +1473,8 @@ int kvm_arch_init_vcpu(CPUState *cs) } } + env->apic_bus_freq = KVM_APIC_BUS_FREQUENCY; + /* Paravirtualization CPUIDs */ r = hyperv_handle_properties(cs, cpuid_data.entries); if (r < 0) { @@ -1773,9 +1779,7 @@ int kvm_arch_init_vcpu(CPUState *cs) c = &cpuid_data.entries[cpuid_i++]; c->function = KVM_CPUID_SIGNATURE | 0x10; c->eax = env->tsc_khz; - /* LAPIC resolution of 1ns (freq: 1GHz) is hardcoded in KVM's - * APIC_BUS_CYCLE_NS */ - c->ebx = 1000000; + c->ebx = env->apic_bus_freq / 1000; /* Hz to KHz */ c->ecx = c->edx = 0; c = cpuid_find_entry(&cpuid_data.cpuid, kvm_base, 0); From d6048bfd12e24a0980ba2040cfaa2b101df3fa16 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:30 +0200 Subject: [PATCH 1065/2595] hw/i386/vmport: Add support for CMD_GETHZ This command returns to guest information on LAPIC bus frequency and TSC frequency. One can see how this interface is used by Linux vmware_platform_setup() introduced in Linux commit 88b094fb8d4f ("x86: Hypervisor detection and get tsc_freq from hypervisor"). Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Message-Id: <20200312165431.82118-16-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/i386/vmport.c | 19 +++++++++++++++++++ include/hw/i386/vmport.h | 1 + 2 files changed, 20 insertions(+) diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 21d4ff048a..309cfd105b 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -174,6 +174,24 @@ static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) return ram_size; } +static uint32_t vmport_cmd_get_hz(void *opaque, uint32_t addr) +{ + X86CPU *cpu = X86_CPU(current_cpu); + + if (cpu->env.tsc_khz && cpu->env.apic_bus_freq) { + uint64_t tsc_freq = (uint64_t)cpu->env.tsc_khz * 1000; + + cpu->env.regs[R_ECX] = cpu->env.apic_bus_freq; + cpu->env.regs[R_EBX] = (uint32_t)(tsc_freq >> 32); + cpu->env.regs[R_EAX] = (uint32_t)tsc_freq; + } else { + /* Signal cmd as not supported */ + cpu->env.regs[R_EBX] = UINT32_MAX; + } + + return cpu->env.regs[R_EAX]; +} + static uint32_t vmport_cmd_get_vcpu_info(void *opaque, uint32_t addr) { X86CPU *cpu = X86_CPU(current_cpu); @@ -211,6 +229,7 @@ static void vmport_realizefn(DeviceState *dev, Error **errp) vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL); if (s->compat_flags & VMPORT_COMPAT_CMDS_V2) { vmport_register(VMPORT_CMD_GETBIOSUUID, vmport_cmd_get_bios_uuid, NULL); + vmport_register(VMPORT_CMD_GETHZ, vmport_cmd_get_hz, NULL); vmport_register(VMPORT_CMD_GET_VCPU_INFO, vmport_cmd_get_vcpu_info, NULL); } diff --git a/include/hw/i386/vmport.h b/include/hw/i386/vmport.h index 7656432358..c380b9c1f0 100644 --- a/include/hw/i386/vmport.h +++ b/include/hw/i386/vmport.h @@ -13,6 +13,7 @@ typedef enum { VMPORT_CMD_VMMOUSE_DATA = 39, VMPORT_CMD_VMMOUSE_STATUS = 40, VMPORT_CMD_VMMOUSE_COMMAND = 41, + VMPORT_CMD_GETHZ = 45, VMPORT_CMD_GET_VCPU_INFO = 68, VMPORT_ENTRIES } VMPortCommand; From 23accdf162dcccb9fec9585a64ad01a87b13da5c Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 12 Mar 2020 18:54:31 +0200 Subject: [PATCH 1066/2595] hw/i386/vmport: Assert vmport initialized before registering commands vmport_register() is also called from other modules such as vmmouse. Therefore, these modules rely that vmport is realized before those call sites. If this is violated, vmport_register() will NULL-deref. To make such issues easier to debug, assert in vmport_register() that vmport is already realized. Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Message-Id: <20200312165431.82118-17-liran.alon@oracle.com> Signed-off-by: Paolo Bonzini --- hw/i386/vmport.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 309cfd105b..79ef25d223 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -81,6 +81,8 @@ static VMPortState *port_state; void vmport_register(VMPortCommand command, VMPortReadFunc *func, void *opaque) { assert(command < VMPORT_ENTRIES); + assert(port_state); + trace_vmport_register(command, func, opaque); port_state->func[command] = func; port_state->opaque[command] = opaque; From da278d58a092bfcc4e36f1e274229c1468dea731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 8 May 2020 12:02:22 +0200 Subject: [PATCH 1067/2595] accel: Move Xen accelerator code under accel/xen/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code is not related to hardware emulation. Move it under accel/ with the other hypervisors. Reviewed-by: Paul Durrant Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200508100222.7112-1-philmd@redhat.com> Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 ++ accel/Makefile.objs | 1 + accel/xen/Makefile.objs | 1 + hw/xen/xen-common.c => accel/xen/xen-all.c | 8 +++++ hw/acpi/piix4.c | 2 +- hw/i386/pc.c | 1 + hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 1 + hw/i386/xen/xen-hvm.c | 1 + hw/i386/xen/xen_platform.c | 1 + hw/isa/piix3.c | 1 + hw/pci/msix.c | 1 + hw/xen/Makefile.objs | 2 +- include/exec/ram_addr.h | 2 +- include/hw/xen/xen.h | 11 ------- include/sysemu/xen.h | 38 ++++++++++++++++++++++ migration/savevm.c | 2 +- softmmu/vl.c | 2 +- stubs/xen-hvm.c | 9 ----- target/i386/cpu.c | 2 +- 20 files changed, 63 insertions(+), 26 deletions(-) create mode 100644 accel/xen/Makefile.objs rename hw/xen/xen-common.c => accel/xen/xen-all.c (98%) create mode 100644 include/sysemu/xen.h diff --git a/MAINTAINERS b/MAINTAINERS index 3abe3faa4e..abe4d7ef8a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -440,6 +440,7 @@ M: Paul Durrant L: xen-devel@lists.xenproject.org S: Supported F: */xen* +F: accel/xen/* F: hw/9pfs/xen-9p* F: hw/char/xen_console.c F: hw/display/xenfb.c @@ -453,6 +454,7 @@ F: hw/i386/xen/ F: hw/pci-host/xen_igd_pt.c F: include/hw/block/dataplane/xen* F: include/hw/xen/ +F: include/sysemu/xen.h F: include/sysemu/xen-mapcache.h Guest CPU Cores (HAXM) diff --git a/accel/Makefile.objs b/accel/Makefile.objs index 17e5ac6061..ff72f0d030 100644 --- a/accel/Makefile.objs +++ b/accel/Makefile.objs @@ -2,4 +2,5 @@ common-obj-$(CONFIG_SOFTMMU) += accel.o obj-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_POSIX)) += qtest.o obj-$(CONFIG_KVM) += kvm/ obj-$(CONFIG_TCG) += tcg/ +obj-$(CONFIG_XEN) += xen/ obj-y += stubs/ diff --git a/accel/xen/Makefile.objs b/accel/xen/Makefile.objs new file mode 100644 index 0000000000..7482cfb436 --- /dev/null +++ b/accel/xen/Makefile.objs @@ -0,0 +1 @@ +obj-y += xen-all.o diff --git a/hw/xen/xen-common.c b/accel/xen/xen-all.c similarity index 98% rename from hw/xen/xen-common.c rename to accel/xen/xen-all.c index 70564cc952..f3edc65ec9 100644 --- a/hw/xen/xen-common.c +++ b/accel/xen/xen-all.c @@ -16,6 +16,7 @@ #include "hw/xen/xen_pt.h" #include "chardev/char.h" #include "sysemu/accel.h" +#include "sysemu/xen.h" #include "sysemu/runstate.h" #include "migration/misc.h" #include "migration/global_state.h" @@ -31,6 +32,13 @@ do { } while (0) #endif +static bool xen_allowed; + +bool xen_enabled(void) +{ + return xen_allowed; +} + xc_interface *xen_xc; xenforeignmemory_handle *xen_fmem; xendevicemodel_handle *xen_dmod; diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 85c199b30d..e27f57195a 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -30,6 +30,7 @@ #include "hw/acpi/acpi.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" +#include "sysemu/xen.h" #include "qapi/error.h" #include "qemu/range.h" #include "exec/address-spaces.h" @@ -41,7 +42,6 @@ #include "hw/mem/nvdimm.h" #include "hw/acpi/memory_hotplug.h" #include "hw/acpi/acpi_dev_interface.h" -#include "hw/xen/xen.h" #include "migration/vmstate.h" #include "hw/core/cpu.h" #include "trace.h" diff --git a/hw/i386/pc.c b/hw/i386/pc.c index b9961b1035..143ac1c354 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -57,6 +57,7 @@ #include "sysemu/tcg.h" #include "sysemu/numa.h" #include "sysemu/kvm.h" +#include "sysemu/xen.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 2613d25bda..eea964e72b 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -53,6 +53,7 @@ #include "cpu.h" #include "qapi/error.h" #include "qemu/error-report.h" +#include "sysemu/xen.h" #ifdef CONFIG_XEN #include #include "hw/xen/xen_pt.h" diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 688d57ddf3..fa9ef449d1 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -36,6 +36,7 @@ #include "hw/rtc/mc146818rtc.h" #include "hw/xen/xen.h" #include "sysemu/kvm.h" +#include "sysemu/xen.h" #include "hw/kvm/clock.h" #include "hw/pci-host/q35.h" #include "hw/qdev-properties.h" diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index 82ece6b9e7..041303a2fa 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -28,6 +28,7 @@ #include "qemu/range.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" +#include "sysemu/xen.h" #include "sysemu/xen-mapcache.h" #include "trace.h" #include "exec/address-spaces.h" diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index 0f7b05e5e1..a1492fdecd 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -33,6 +33,7 @@ #include "hw/xen/xen-legacy-backend.h" #include "trace.h" #include "exec/address-spaces.h" +#include "sysemu/xen.h" #include "sysemu/block-backend.h" #include "qemu/error-report.h" #include "qemu/module.h" diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index fd1c78879f..1a5267e19f 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -28,6 +28,7 @@ #include "hw/irq.h" #include "hw/isa/isa.h" #include "hw/xen/xen.h" +#include "sysemu/xen.h" #include "sysemu/sysemu.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" diff --git a/hw/pci/msix.c b/hw/pci/msix.c index 29187898f2..2c7ead7667 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -19,6 +19,7 @@ #include "hw/pci/msix.h" #include "hw/pci/pci.h" #include "hw/xen/xen.h" +#include "sysemu/xen.h" #include "migration/qemu-file-types.h" #include "migration/vmstate.h" #include "qemu/range.h" diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index 84df60a928..340b2c5096 100644 --- a/hw/xen/Makefile.objs +++ b/hw/xen/Makefile.objs @@ -1,5 +1,5 @@ # xen backend driver support -common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-common.o xen-bus.o xen-bus-helper.o xen-backend.o +common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-bus.o xen-bus-helper.o xen-backend.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index b295f6a784..7b5c24e928 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -21,7 +21,7 @@ #ifndef CONFIG_USER_ONLY #include "cpu.h" -#include "hw/xen/xen.h" +#include "sysemu/xen.h" #include "sysemu/tcg.h" #include "exec/ramlist.h" #include "exec/ramblock.h" diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index 5ac1c6dc55..771dd447f2 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -20,13 +20,6 @@ extern uint32_t xen_domid; extern enum xen_mode xen_mode; extern bool xen_domid_restrict; -extern bool xen_allowed; - -static inline bool xen_enabled(void) -{ - return xen_allowed; -} - int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num); void xen_piix3_set_irq(void *opaque, int irq_num, int level); void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len); @@ -39,10 +32,6 @@ void xenstore_store_pv_console_info(int i, struct Chardev *chr); void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory); -void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, - struct MemoryRegion *mr, Error **errp); -void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length); - void xen_register_framebuffer(struct MemoryRegion *mr); #endif /* QEMU_HW_XEN_H */ diff --git a/include/sysemu/xen.h b/include/sysemu/xen.h new file mode 100644 index 0000000000..1ca292715e --- /dev/null +++ b/include/sysemu/xen.h @@ -0,0 +1,38 @@ +/* + * QEMU Xen support + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef SYSEMU_XEN_H +#define SYSEMU_XEN_H + +#ifdef CONFIG_XEN + +bool xen_enabled(void); + +#ifndef CONFIG_USER_ONLY +void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length); +void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, + struct MemoryRegion *mr, Error **errp); +#endif + +#else /* !CONFIG_XEN */ + +#define xen_enabled() 0 +#ifndef CONFIG_USER_ONLY +static inline void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length) +{ + /* nothing */ +} +static inline void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, + MemoryRegion *mr, Error **errp) +{ + g_assert_not_reached(); +} +#endif + +#endif /* CONFIG_XEN */ + +#endif diff --git a/migration/savevm.c b/migration/savevm.c index c00a6807d9..b979ea6e7f 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -28,7 +28,6 @@ #include "qemu/osdep.h" #include "hw/boards.h" -#include "hw/xen/xen.h" #include "net/net.h" #include "migration.h" #include "migration/snapshot.h" @@ -59,6 +58,7 @@ #include "sysemu/replay.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" +#include "sysemu/xen.h" #include "qjson.h" #include "migration/colo.h" #include "qemu/bitmap.h" diff --git a/softmmu/vl.c b/softmmu/vl.c index 055472da66..f669c06ede 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -36,6 +36,7 @@ #include "sysemu/runstate.h" #include "sysemu/seccomp.h" #include "sysemu/tcg.h" +#include "sysemu/xen.h" #include "qemu/error-report.h" #include "qemu/sockets.h" @@ -178,7 +179,6 @@ static NotifierList exit_notifiers = static NotifierList machine_init_done_notifiers = NOTIFIER_LIST_INITIALIZER(machine_init_done_notifiers); -bool xen_allowed; uint32_t xen_domid; enum xen_mode xen_mode = XEN_EMULATE; bool xen_domid_restrict; diff --git a/stubs/xen-hvm.c b/stubs/xen-hvm.c index b7d53b5e2f..6954a5b696 100644 --- a/stubs/xen-hvm.c +++ b/stubs/xen-hvm.c @@ -35,11 +35,6 @@ int xen_is_pirq_msi(uint32_t msi_data) return 0; } -void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr, - Error **errp) -{ -} - qemu_irq *xen_interrupt_controller_init(void) { return NULL; @@ -49,10 +44,6 @@ void xen_register_framebuffer(MemoryRegion *mr) { } -void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length) -{ -} - void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory) { } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 25a8f6b1ad..b5705cda86 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -29,6 +29,7 @@ #include "sysemu/reset.h" #include "sysemu/hvf.h" #include "sysemu/cpus.h" +#include "sysemu/xen.h" #include "kvm_i386.h" #include "sev_i386.h" @@ -54,7 +55,6 @@ #include "hw/i386/topology.h" #ifndef CONFIG_USER_ONLY #include "exec/address-spaces.h" -#include "hw/xen/xen.h" #include "hw/i386/apic_internal.h" #include "hw/boards.h" #endif From ad195c8ff562365b3e5b43e800d6acd84cb22e99 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 May 2020 10:32:35 +0900 Subject: [PATCH 1068/2595] qom: remove index from object_resolve_abs_path() You can advance 'parts' to track the current path fragment. The 'index' parameter is unneeded. Signed-off-by: Masahiro Yamada Message-Id: <20200510013235.954906-1-masahiroy@kernel.org> Signed-off-by: Paolo Bonzini --- qom/object.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/qom/object.c b/qom/object.c index 484465f1c8..ea16680051 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1956,26 +1956,25 @@ Object *object_resolve_path_component(Object *parent, const char *part) } static Object *object_resolve_abs_path(Object *parent, - char **parts, - const char *typename, - int index) + char **parts, + const char *typename) { Object *child; - if (parts[index] == NULL) { + if (*parts == NULL) { return object_dynamic_cast(parent, typename); } - if (strcmp(parts[index], "") == 0) { - return object_resolve_abs_path(parent, parts, typename, index + 1); + if (strcmp(*parts, "") == 0) { + return object_resolve_abs_path(parent, parts + 1, typename); } - child = object_resolve_path_component(parent, parts[index]); + child = object_resolve_path_component(parent, *parts); if (!child) { return NULL; } - return object_resolve_abs_path(child, parts, typename, index + 1); + return object_resolve_abs_path(child, parts + 1, typename); } static Object *object_resolve_partial_path(Object *parent, @@ -1987,7 +1986,7 @@ static Object *object_resolve_partial_path(Object *parent, GHashTableIter iter; ObjectProperty *prop; - obj = object_resolve_abs_path(parent, parts, typename, 0); + obj = object_resolve_abs_path(parent, parts, typename); g_hash_table_iter_init(&iter, parent->properties); while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { @@ -2032,7 +2031,7 @@ Object *object_resolve_path_type(const char *path, const char *typename, *ambiguousp = ambiguous; } } else { - obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); + obj = object_resolve_abs_path(object_get_root(), parts + 1, typename); } g_strfreev(parts); From e5a0cc5e44c0344a3b8e284feeeffe43debca995 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 13 May 2020 02:26:15 +0900 Subject: [PATCH 1069/2595] qom/object: factor out the initialization of hash table of properties Properties are not related to the initialization of interfaces. The initialization of the hash table can be moved after the if-block, and unified. Signed-off-by: Masahiro Yamada Message-Id: <20200512172615.2291999-1-masahiroy@kernel.org> Signed-off-by: Paolo Bonzini --- qom/object.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/qom/object.c b/qom/object.c index ea16680051..a4094a6bb5 100644 --- a/qom/object.c +++ b/qom/object.c @@ -316,8 +316,6 @@ static void type_initialize(TypeImpl *ti) g_assert(parent->instance_size <= ti->instance_size); memcpy(ti->class, parent->class, parent->class_size); ti->class->interfaces = NULL; - ti->class->properties = g_hash_table_new_full( - g_str_hash, g_str_equal, NULL, object_property_free); for (e = parent->class->interfaces; e; e = e->next) { InterfaceClass *iface = e->data; @@ -347,11 +345,11 @@ static void type_initialize(TypeImpl *ti) type_initialize_interface(ti, t, t); } - } else { - ti->class->properties = g_hash_table_new_full( - g_str_hash, g_str_equal, NULL, object_property_free); } + ti->class->properties = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + object_property_free); + ti->class->type = ti; while (parent) { From 3d91293ed2c023b016d845b68ee184ee0f435227 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 13 May 2020 03:25:01 +0900 Subject: [PATCH 1070/2595] qom/object: simplify type_initialize_interface() iface_impl->class is the same as new_iface. Make it more readable. Signed-off-by: Masahiro Yamada Message-Id: <20200512182501.2300530-1-masahiroy@kernel.org> Signed-off-by: Paolo Bonzini --- qom/object.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qom/object.c b/qom/object.c index a4094a6bb5..bc39ad4b99 100644 --- a/qom/object.c +++ b/qom/object.c @@ -262,8 +262,7 @@ static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type, new_iface->concrete_class = ti->class; new_iface->interface_type = interface_type; - ti->class->interfaces = g_slist_append(ti->class->interfaces, - iface_impl->class); + ti->class->interfaces = g_slist_append(ti->class->interfaces, new_iface); } static void object_property_free(gpointer data) From e27a959581759d4f6df45993ba940ec1f769ea68 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 13 May 2020 02:31:04 +0900 Subject: [PATCH 1071/2595] qom/object: pass (Object *) to object_initialize_with_type() object_new_with_type() already passes (Object *) pointer. Avoid casting back and forth. Signed-off-by: Masahiro Yamada Message-Id: <20200512173104.2293073-1-masahiroy@kernel.org> Signed-off-by: Paolo Bonzini --- qom/object.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/qom/object.c b/qom/object.c index bc39ad4b99..b0ed560fd8 100644 --- a/qom/object.c +++ b/qom/object.c @@ -494,10 +494,8 @@ static void object_class_property_init_all(Object *obj) } } -static void object_initialize_with_type(void *data, size_t size, TypeImpl *type) +static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type) { - Object *obj = data; - type_initialize(type); g_assert(type->instance_size >= sizeof(Object)); From c5e18709585c6f2a3464f89434b0040ce5164d9d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 13 May 2020 12:36:00 +0900 Subject: [PATCH 1072/2595] qom/container: remove .instance_size initializer from container_info You can omit .instance_size if it is the same as that of the parent. .class_size = sizeof(ObjectClass) ... is omitted here, so removing .instance_size is more consistent. Signed-off-by: Masahiro Yamada Message-Id: <20200513033600.2709646-1-masahiroy@kernel.org> Signed-off-by: Paolo Bonzini --- qom/container.c | 1 - 1 file changed, 1 deletion(-) diff --git a/qom/container.c b/qom/container.c index 14e7ae485b..455e8410c6 100644 --- a/qom/container.c +++ b/qom/container.c @@ -16,7 +16,6 @@ static const TypeInfo container_info = { .name = "container", - .instance_size = sizeof(Object), .parent = TYPE_OBJECT, }; From 6c1ddc36d8ddcb21e905dfdecfb9f2e4d4fd8acc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 15 May 2020 06:22:31 +0200 Subject: [PATCH 1073/2595] cpus: Fix botched configure_icount() error API violation fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before recent commit abc9bf69a66, configure_icount() returned early when option "shift" was absent: succeed when option "align" was also absent, else fail. Since then, it still errors out when only "align" is present, but continues when both are absent. Crashes when examining the value of "shift" further. Reproducer: -icount "". Revert this erroneous part of the commit. Fixes: abc9bf69a66a11499a801ff545b8fe7adbb3a04c Fixes: Coverity CID 1428754 Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200515042231.18201-1-armbru@redhat.com> Signed-off-by: Paolo Bonzini --- cpus.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cpus.c b/cpus.c index 7ce0d569b3..34fc203808 100644 --- a/cpus.c +++ b/cpus.c @@ -821,8 +821,10 @@ void configure_icount(QemuOpts *opts, Error **errp) bool align = qemu_opt_get_bool(opts, "align", false); long time_shift = -1; - if (!option && qemu_opt_get(opts, "align")) { - error_setg(errp, "Please specify shift option when using align"); + if (!option) { + if (qemu_opt_get(opts, "align") != NULL) { + error_setg(errp, "Please specify shift option when using align"); + } return; } From 34a0950605855870017bbe4d96110bf06a075982 Mon Sep 17 00:00:00 2001 From: WangBowen Date: Sat, 9 May 2020 11:59:52 +0800 Subject: [PATCH 1074/2595] hax: Dynamic allocate vcpu state structure Dynamic allocating vcpu state structure according to smp value to be more precise and safe. Previously it will alloccate array of fixed size HAX_MAX_VCPU. This is achieved by using g_new0 to dynamic allocate the array. The allocated size is obtained from smp.max_cpus in MachineState. Also, the size is compared with HAX_MAX_VCPU when creating the vm. The reason for choosing dynamic array over linked list is because the status is visited by index all the time. This will lead to QEMU checking whether the smp value is larger than the HAX_MAX_VCPU when creating vm, if larger, the process will terminate, otherwise it will allocate array of size smp to store the status. V2: Check max_cpus before open vm. (Philippe) Signed-off-by: WangBowen Signed-off-by: Colin Xu Message-Id: <20200509035952.187615-1-colin.xu@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/hax-all.c | 25 +++++++++++++++++++------ target/i386/hax-i386.h | 5 +++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/target/i386/hax-all.c b/target/i386/hax-all.c index f9c83fff25..c93bb23a44 100644 --- a/target/i386/hax-all.c +++ b/target/i386/hax-all.c @@ -232,10 +232,10 @@ int hax_init_vcpu(CPUState *cpu) return ret; } -struct hax_vm *hax_vm_create(struct hax_state *hax) +struct hax_vm *hax_vm_create(struct hax_state *hax, int max_cpus) { struct hax_vm *vm; - int vm_id = 0, ret; + int vm_id = 0, ret, i; if (hax_invalid_fd(hax->fd)) { return NULL; @@ -245,6 +245,11 @@ struct hax_vm *hax_vm_create(struct hax_state *hax) return hax->vm; } + if (max_cpus > HAX_MAX_VCPU) { + fprintf(stderr, "Maximum VCPU number QEMU supported is %d\n", HAX_MAX_VCPU); + return NULL; + } + vm = g_new0(struct hax_vm, 1); ret = hax_host_create_vm(hax, &vm_id); @@ -259,6 +264,12 @@ struct hax_vm *hax_vm_create(struct hax_state *hax) goto error; } + vm->numvcpus = max_cpus; + vm->vcpus = g_new0(struct hax_vcpu_state *, vm->numvcpus); + for (i = 0; i < vm->numvcpus; i++) { + vm->vcpus[i] = NULL; + } + hax->vm = vm; return vm; @@ -272,12 +283,14 @@ int hax_vm_destroy(struct hax_vm *vm) { int i; - for (i = 0; i < HAX_MAX_VCPU; i++) + for (i = 0; i < vm->numvcpus; i++) if (vm->vcpus[i]) { fprintf(stderr, "VCPU should be cleaned before vm clean\n"); return -1; } hax_close_fd(vm->fd); + vm->numvcpus = 0; + g_free(vm->vcpus); g_free(vm); hax_global.vm = NULL; return 0; @@ -292,7 +305,7 @@ static void hax_handle_interrupt(CPUState *cpu, int mask) } } -static int hax_init(ram_addr_t ram_size) +static int hax_init(ram_addr_t ram_size, int max_cpus) { struct hax_state *hax = NULL; struct hax_qemu_version qversion; @@ -324,7 +337,7 @@ static int hax_init(ram_addr_t ram_size) goto error; } - hax->vm = hax_vm_create(hax); + hax->vm = hax_vm_create(hax, max_cpus); if (!hax->vm) { fprintf(stderr, "Failed to create HAX VM\n"); ret = -EINVAL; @@ -352,7 +365,7 @@ static int hax_init(ram_addr_t ram_size) static int hax_accel_init(MachineState *ms) { - int ret = hax_init(ms->ram_size); + int ret = hax_init(ms->ram_size, (int)ms->smp.max_cpus); if (ret && (ret != -ENOSPC)) { fprintf(stderr, "No accelerator found.\n"); diff --git a/target/i386/hax-i386.h b/target/i386/hax-i386.h index 54e9d8b057..7d988f81da 100644 --- a/target/i386/hax-i386.h +++ b/target/i386/hax-i386.h @@ -47,7 +47,8 @@ struct hax_state { struct hax_vm { hax_fd fd; int id; - struct hax_vcpu_state *vcpus[HAX_MAX_VCPU]; + int numvcpus; + struct hax_vcpu_state **vcpus; }; #ifdef NEED_CPU_H @@ -58,7 +59,7 @@ int valid_hax_tunnel_size(uint16_t size); /* Host specific functions */ int hax_mod_version(struct hax_state *hax, struct hax_module_version *version); int hax_inject_interrupt(CPUArchState *env, int vector); -struct hax_vm *hax_vm_create(struct hax_state *hax); +struct hax_vm *hax_vm_create(struct hax_state *hax, int max_cpus); int hax_vcpu_run(struct hax_vcpu_state *vcpu); int hax_vcpu_create(int id); int hax_sync_vcpu_state(CPUArchState *env, struct vcpu_state_t *state, From 2a6931425890a9a2822e62f60724a9edbb93ba10 Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Wed, 13 May 2020 09:26:30 -0400 Subject: [PATCH 1075/2595] i386/kvm: fix a use-after-free when vcpu plug/unplug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we hotplug vcpus, cpu_update_state is added to vm_change_state_head in kvm_arch_init_vcpu(). But it forgot to delete in kvm_arch_destroy_vcpu() after unplug. Then it will cause a use-after-free access. This patch delete it in kvm_arch_destroy_vcpu() to fix that. Reproducer: virsh setvcpus vm1 4 --live virsh setvcpus vm1 2 --live virsh suspend vm1 virsh resume vm1 The UAF stack: ==qemu-system-x86_64==28233==ERROR: AddressSanitizer: heap-use-after-free on address 0x62e00002e798 at pc 0x5573c6917d9e bp 0x7fff07139e50 sp 0x7fff07139e40 WRITE of size 1 at 0x62e00002e798 thread T0 #0 0x5573c6917d9d in cpu_update_state /mnt/sdb/qemu/target/i386/kvm.c:742 #1 0x5573c699121a in vm_state_notify /mnt/sdb/qemu/vl.c:1290 #2 0x5573c636287e in vm_prepare_start /mnt/sdb/qemu/cpus.c:2144 #3 0x5573c6362927 in vm_start /mnt/sdb/qemu/cpus.c:2150 #4 0x5573c71e8304 in qmp_cont /mnt/sdb/qemu/monitor/qmp-cmds.c:173 #5 0x5573c727cb1e in qmp_marshal_cont qapi/qapi-commands-misc.c:835 #6 0x5573c7694c7a in do_qmp_dispatch /mnt/sdb/qemu/qapi/qmp-dispatch.c:132 #7 0x5573c7694c7a in qmp_dispatch /mnt/sdb/qemu/qapi/qmp-dispatch.c:175 #8 0x5573c71d9110 in monitor_qmp_dispatch /mnt/sdb/qemu/monitor/qmp.c:145 #9 0x5573c71dad4f in monitor_qmp_bh_dispatcher /mnt/sdb/qemu/monitor/qmp.c:234 Reported-by: Euler Robot Signed-off-by: Pan Nengyuan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200513132630.13412-1-pannengyuan@huawei.com> Reviewed-by: Igor Mammedov Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 1 + target/i386/kvm.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 00d1f4f013..37572bd437 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1634,6 +1634,7 @@ struct X86CPU { CPUNegativeOffsetState neg; CPUX86State env; + VMChangeStateEntry *vmsentry; uint64_t ucode_rev; diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 95bbeb424b..ef2e0a81dd 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -1741,7 +1741,7 @@ int kvm_arch_init_vcpu(CPUState *cs) } } - qemu_add_vm_change_state_handler(cpu_update_state, env); + cpu->vmsentry = qemu_add_vm_change_state_handler(cpu_update_state, env); c = cpuid_find_entry(&cpuid_data.cpuid, 1, 0); if (c) { @@ -1852,6 +1852,8 @@ int kvm_arch_destroy_vcpu(CPUState *cs) env->nested_state = NULL; } + qemu_del_vm_change_state_handler(cpu->vmsentry); + return 0; } From f50ab86a2620bd7e8507af865b164655ee921661 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Thu, 14 May 2020 00:55:38 +0530 Subject: [PATCH 1076/2595] megasas: use unsigned type for reply_queue_head and check index A guest user may set 'reply_queue_head' field of MegasasState to a negative value. Later in 'megasas_lookup_frame' it is used to index into s->frames[] array. Use unsigned type to avoid OOB access issue. Also check that 'index' value stays within s->frames[] bounds through the while() loop in 'megasas_lookup_frame' to avoid OOB access. Reported-by: Ren Ding Reported-by: Hanqing Zhao Reported-by: Alexander Bulekov Signed-off-by: Prasad J Pandit Acked-by: Alexander Bulekov Message-Id: <20200513192540.1583887-2-ppandit@redhat.com> Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index af18c88b65..6ce598cd69 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -112,7 +112,7 @@ typedef struct MegasasState { uint64_t reply_queue_pa; void *reply_queue; int reply_queue_len; - int reply_queue_head; + uint16_t reply_queue_head; int reply_queue_tail; uint64_t consumer_pa; uint64_t producer_pa; @@ -445,7 +445,7 @@ static MegasasCmd *megasas_lookup_frame(MegasasState *s, index = s->reply_queue_head; - while (num < s->fw_cmds) { + while (num < s->fw_cmds && index < MEGASAS_MAX_FRAMES) { if (s->frames[index].pa && s->frames[index].pa == frame) { cmd = &s->frames[index]; break; From fd6918556736ecce8b10acd581ba134ffb62d9f9 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Thu, 14 May 2020 00:55:39 +0530 Subject: [PATCH 1077/2595] megasas: avoid NULL pointer dereference While in megasas_handle_frame(), megasas_enqueue_frame() may set a NULL frame into MegasasCmd object for a given 'frame_addr' address. Add check to avoid a NULL pointer dereference issue. Reported-by: Alexander Bulekov Fixes: https://bugs.launchpad.net/qemu/+bug/1878259 Signed-off-by: Prasad J Pandit Acked-by: Alexander Bulekov Reviewed-by: Darren Kenny Message-Id: <20200513192540.1583887-3-ppandit@redhat.com> Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 6ce598cd69..b531d88a9b 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -504,7 +504,7 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s, cmd->pa = frame; /* Map all possible frames */ cmd->frame = pci_dma_map(pcid, frame, &frame_size_p, 0); - if (frame_size_p != frame_size) { + if (!cmd->frame || frame_size_p != frame_size) { trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame); if (cmd->frame) { megasas_unmap_frame(s, cmd); From 2b151297e44655e45c18f57ae0232780ee4ad45a Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Thu, 14 May 2020 00:55:40 +0530 Subject: [PATCH 1078/2595] megasas: use unsigned type for positive numeric fields Use unsigned type for the MegasasState fields which hold positive numeric values. Signed-off-by: Prasad J Pandit Reviewed-by: Darren Kenny Message-Id: <20200513192540.1583887-4-ppandit@redhat.com> Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index b531d88a9b..634af0bbb8 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -86,34 +86,34 @@ typedef struct MegasasState { MemoryRegion queue_io; uint32_t frame_hi; - int fw_state; + uint32_t fw_state; uint32_t fw_sge; uint32_t fw_cmds; uint32_t flags; - int fw_luns; - int intr_mask; - int doorbell; - int busy; - int diag; - int adp_reset; + uint32_t fw_luns; + uint32_t intr_mask; + uint32_t doorbell; + uint32_t busy; + uint32_t diag; + uint32_t adp_reset; OnOffAuto msi; OnOffAuto msix; MegasasCmd *event_cmd; - int event_locale; + uint16_t event_locale; int event_class; - int event_count; - int shutdown_event; - int boot_event; + uint32_t event_count; + uint32_t shutdown_event; + uint32_t boot_event; uint64_t sas_addr; char *hba_serial; uint64_t reply_queue_pa; void *reply_queue; - int reply_queue_len; + uint16_t reply_queue_len; uint16_t reply_queue_head; - int reply_queue_tail; + uint16_t reply_queue_tail; uint64_t consumer_pa; uint64_t producer_pa; @@ -2259,9 +2259,9 @@ static const VMStateDescription vmstate_megasas_gen1 = { VMSTATE_PCI_DEVICE(parent_obj, MegasasState), VMSTATE_MSIX(parent_obj, MegasasState), - VMSTATE_INT32(fw_state, MegasasState), - VMSTATE_INT32(intr_mask, MegasasState), - VMSTATE_INT32(doorbell, MegasasState), + VMSTATE_UINT32(fw_state, MegasasState), + VMSTATE_UINT32(intr_mask, MegasasState), + VMSTATE_UINT32(doorbell, MegasasState), VMSTATE_UINT64(reply_queue_pa, MegasasState), VMSTATE_UINT64(consumer_pa, MegasasState), VMSTATE_UINT64(producer_pa, MegasasState), @@ -2278,9 +2278,9 @@ static const VMStateDescription vmstate_megasas_gen2 = { VMSTATE_PCI_DEVICE(parent_obj, MegasasState), VMSTATE_MSIX(parent_obj, MegasasState), - VMSTATE_INT32(fw_state, MegasasState), - VMSTATE_INT32(intr_mask, MegasasState), - VMSTATE_INT32(doorbell, MegasasState), + VMSTATE_UINT32(fw_state, MegasasState), + VMSTATE_UINT32(intr_mask, MegasasState), + VMSTATE_UINT32(doorbell, MegasasState), VMSTATE_UINT64(reply_queue_pa, MegasasState), VMSTATE_UINT64(consumer_pa, MegasasState), VMSTATE_UINT64(producer_pa, MegasasState), From c415f2c58296d86e9abb7e4a133111acf7031da3 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 7 May 2020 00:43:30 +0000 Subject: [PATCH 1079/2595] target/i386: implement special cases for fxtract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The implementation of the fxtract instruction treats all nonzero operands as normal numbers, so yielding incorrect results for invalid formats, infinities, NaNs and subnormal and pseudo-denormal operands. Implement appropriate handling of all those cases. Signed-off-by: Joseph Myers Acked-by: Alex Bennée Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 25 +++++- tests/tcg/i386/test-i386-fxtract.c | 120 +++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/i386/test-i386-fxtract.c diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index b34fa784eb..568bd3b359 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -767,10 +767,33 @@ void helper_fxtract(CPUX86State *env) &env->fp_status); fpush(env); ST0 = temp.d; + } else if (floatx80_invalid_encoding(ST0)) { + float_raise(float_flag_invalid, &env->fp_status); + ST0 = floatx80_default_nan(&env->fp_status); + fpush(env); + ST0 = ST1; + } else if (floatx80_is_any_nan(ST0)) { + if (floatx80_is_signaling_nan(ST0, &env->fp_status)) { + float_raise(float_flag_invalid, &env->fp_status); + ST0 = floatx80_silence_nan(ST0, &env->fp_status); + } + fpush(env); + ST0 = ST1; + } else if (floatx80_is_infinity(ST0)) { + fpush(env); + ST0 = ST1; + ST1 = floatx80_infinity; } else { int expdif; - expdif = EXPD(temp) - EXPBIAS; + if (EXPD(temp) == 0) { + int shift = clz64(temp.l.lower); + temp.l.lower <<= shift; + expdif = 1 - EXPBIAS - shift; + float_raise(float_flag_input_denormal, &env->fp_status); + } else { + expdif = EXPD(temp) - EXPBIAS; + } /* DP exponent bias */ ST0 = int32_to_floatx80(expdif, &env->fp_status); fpush(env); diff --git a/tests/tcg/i386/test-i386-fxtract.c b/tests/tcg/i386/test-i386-fxtract.c new file mode 100644 index 0000000000..64fd93d333 --- /dev/null +++ b/tests/tcg/i386/test-i386-fxtract.c @@ -0,0 +1,120 @@ +/* Test fxtract instruction. */ + +#include +#include + +union u { + struct { uint64_t sig; uint16_t sign_exp; } s; + long double ld; +}; + +volatile union u ld_pseudo_m16382 = { .s = { UINT64_C(1) << 63, 0 } }; +volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; +volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; +volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; +volatile union u ld_invalid_4 = { .s = { (UINT64_C(1) << 63) - 1, 0x7fff } }; + +volatile long double ld_sig, ld_exp; + +int isnan_ld(long double x) +{ + union u tmp = { .ld = x }; + return ((tmp.s.sign_exp & 0x7fff) == 0x7fff && + (tmp.s.sig >> 63) != 0 && + (tmp.s.sig << 1) != 0); +} + +int issignaling_ld(long double x) +{ + union u tmp = { .ld = x }; + return isnan_ld(x) && (tmp.s.sig & UINT64_C(0x4000000000000000)) == 0; +} + +int main(void) +{ + int ret = 0; + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : "0" (2.5L)); + if (ld_sig != 1.25L || ld_exp != 1.0L) { + printf("FAIL: fxtract 2.5\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : "0" (0.0L)); + if (ld_sig != 0.0L || __builtin_copysignl(1.0L, ld_sig) != 1.0L || + ld_exp != -__builtin_infl()) { + printf("FAIL: fxtract 0.0\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : "0" (-0.0L)); + if (ld_sig != -0.0L || __builtin_copysignl(1.0L, ld_sig) != -1.0L || + ld_exp != -__builtin_infl()) { + printf("FAIL: fxtract -0.0\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : + "0" (__builtin_infl())); + if (ld_sig != __builtin_infl() || ld_exp != __builtin_infl()) { + printf("FAIL: fxtract inf\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : + "0" (-__builtin_infl())); + if (ld_sig != -__builtin_infl() || ld_exp != __builtin_infl()) { + printf("FAIL: fxtract -inf\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : + "0" (__builtin_nanl(""))); + if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || + !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { + printf("FAIL: fxtract qnan\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : + "0" (__builtin_nansl(""))); + if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || + !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { + printf("FAIL: fxtract snan\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : + "0" (0x1p-16445L)); + if (ld_sig != 1.0L || ld_exp != -16445.0L) { + printf("FAIL: fxtract subnormal\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : + "0" (ld_pseudo_m16382.ld)); + if (ld_sig != 1.0L || ld_exp != -16382.0L) { + printf("FAIL: fxtract pseudo\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : + "0" (ld_invalid_1.ld)); + if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || + !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { + printf("FAIL: fxtract invalid 1\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : + "0" (ld_invalid_2.ld)); + if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || + !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { + printf("FAIL: fxtract invalid 2\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : + "0" (ld_invalid_3.ld)); + if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || + !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { + printf("FAIL: fxtract invalid 3\n"); + ret = 1; + } + __asm__ volatile ("fxtract" : "=t" (ld_sig), "=u" (ld_exp) : + "0" (ld_invalid_4.ld)); + if (!isnan_ld(ld_sig) || issignaling_ld(ld_sig) || + !isnan_ld(ld_exp) || issignaling_ld(ld_exp)) { + printf("FAIL: fxtract invalid 4\n"); + ret = 1; + } + return ret; +} From 0d48b436327955c69e2eb53f88aba9aa1e0dbaa0 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 7 May 2020 00:44:14 +0000 Subject: [PATCH 1080/2595] target/i386: fix fscale handling of signaling NaN The implementation of the fscale instruction returns a NaN exponent unchanged. Fix it to return a quiet NaN when the provided exponent is a signaling NaN. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 4 ++++ tests/tcg/i386/test-i386-fscale.c | 37 +++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/tcg/i386/test-i386-fscale.c diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 568bd3b359..0671de6952 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -970,6 +970,10 @@ void helper_fscale(CPUX86State *env) { if (floatx80_is_any_nan(ST1)) { ST0 = ST1; + if (floatx80_is_signaling_nan(ST0, &env->fp_status)) { + float_raise(float_flag_invalid, &env->fp_status); + ST0 = floatx80_silence_nan(ST0, &env->fp_status); + } } else { int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status); ST0 = floatx80_scalbn(ST0, n, &env->fp_status); diff --git a/tests/tcg/i386/test-i386-fscale.c b/tests/tcg/i386/test-i386-fscale.c new file mode 100644 index 0000000000..aecac5125f --- /dev/null +++ b/tests/tcg/i386/test-i386-fscale.c @@ -0,0 +1,37 @@ +/* Test fscale instruction. */ + +#include +#include + +union u { + struct { uint64_t sig; uint16_t sign_exp; } s; + long double ld; +}; + +volatile long double ld_res; + +int isnan_ld(long double x) +{ + union u tmp = { .ld = x }; + return ((tmp.s.sign_exp & 0x7fff) == 0x7fff && + (tmp.s.sig >> 63) != 0 && + (tmp.s.sig << 1) != 0); +} + +int issignaling_ld(long double x) +{ + union u tmp = { .ld = x }; + return isnan_ld(x) && (tmp.s.sig & UINT64_C(0x4000000000000000)) == 0; +} + +int main(void) +{ + int ret = 0; + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (2.5L), "u" (__builtin_nansl(""))); + if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { + printf("FAIL: fscale snan\n"); + ret = 1; + } + return ret; +} From b40eec96b26028b68c3594fbf34b6d6f029df26a Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 7 May 2020 00:44:57 +0000 Subject: [PATCH 1081/2595] target/i386: fix fscale handling of invalid exponent encodings The fscale implementation does not check for invalid encodings in the exponent operand, thus treating them like INT_MIN (the value returned for invalid encodings by floatx80_to_int32_round_to_zero). Fix it to treat them similarly to signaling NaN exponents, thus generating a quiet NaN result. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 5 ++++- tests/tcg/i386/test-i386-fscale.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 0671de6952..10ff90370e 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -968,7 +968,10 @@ void helper_frndint(CPUX86State *env) void helper_fscale(CPUX86State *env) { - if (floatx80_is_any_nan(ST1)) { + if (floatx80_invalid_encoding(ST1)) { + float_raise(float_flag_invalid, &env->fp_status); + ST0 = floatx80_default_nan(&env->fp_status); + } else if (floatx80_is_any_nan(ST1)) { ST0 = ST1; if (floatx80_is_signaling_nan(ST0, &env->fp_status)) { float_raise(float_flag_invalid, &env->fp_status); diff --git a/tests/tcg/i386/test-i386-fscale.c b/tests/tcg/i386/test-i386-fscale.c index aecac5125f..b65a055d0a 100644 --- a/tests/tcg/i386/test-i386-fscale.c +++ b/tests/tcg/i386/test-i386-fscale.c @@ -8,6 +8,11 @@ union u { long double ld; }; +volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; +volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; +volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; +volatile union u ld_invalid_4 = { .s = { (UINT64_C(1) << 63) - 1, 0x7fff } }; + volatile long double ld_res; int isnan_ld(long double x) @@ -33,5 +38,29 @@ int main(void) printf("FAIL: fscale snan\n"); ret = 1; } + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (2.5L), "u" (ld_invalid_1.ld)); + if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { + printf("FAIL: fscale invalid 1\n"); + ret = 1; + } + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (2.5L), "u" (ld_invalid_2.ld)); + if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { + printf("FAIL: fscale invalid 2\n"); + ret = 1; + } + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (2.5L), "u" (ld_invalid_3.ld)); + if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { + printf("FAIL: fscale invalid 3\n"); + ret = 1; + } + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (2.5L), "u" (ld_invalid_4.ld)); + if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { + printf("FAIL: fscale invalid 4\n"); + ret = 1; + } return ret; } From c1c5fb8f9067c830e36830c2b82c0ec146c03d7b Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 7 May 2020 00:45:38 +0000 Subject: [PATCH 1082/2595] target/i386: fix fscale handling of infinite exponents The fscale implementation passes infinite exponents through to generic code that rounds the exponent to a 32-bit integer before using floatx80_scalbn. In round-to-nearest mode, and ignoring exceptions, this works in many cases. But it fails to handle the special cases of scaling 0 by a +Inf exponent or an infinity by a -Inf exponent, which should produce a NaN, and because it produces an inexact result for finite nonzero numbers being scaled, the result is sometimes incorrect in other rounding modes. Add appropriate handling of infinite exponents to produce a NaN or an appropriately signed exact zero or infinity as a result. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 22 ++++++++++++++++++++++ tests/tcg/i386/test-i386-fscale.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 10ff90370e..72d1e77eb0 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -977,6 +977,28 @@ void helper_fscale(CPUX86State *env) float_raise(float_flag_invalid, &env->fp_status); ST0 = floatx80_silence_nan(ST0, &env->fp_status); } + } else if (floatx80_is_infinity(ST1) && + !floatx80_invalid_encoding(ST0) && + !floatx80_is_any_nan(ST0)) { + if (floatx80_is_neg(ST1)) { + if (floatx80_is_infinity(ST0)) { + float_raise(float_flag_invalid, &env->fp_status); + ST0 = floatx80_default_nan(&env->fp_status); + } else { + ST0 = (floatx80_is_neg(ST0) ? + floatx80_chs(floatx80_zero) : + floatx80_zero); + } + } else { + if (floatx80_is_zero(ST0)) { + float_raise(float_flag_invalid, &env->fp_status); + ST0 = floatx80_default_nan(&env->fp_status); + } else { + ST0 = (floatx80_is_neg(ST0) ? + floatx80_chs(floatx80_infinity) : + floatx80_infinity); + } + } } else { int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status); ST0 = floatx80_scalbn(ST0, n, &env->fp_status); diff --git a/tests/tcg/i386/test-i386-fscale.c b/tests/tcg/i386/test-i386-fscale.c index b65a055d0a..b953e7c563 100644 --- a/tests/tcg/i386/test-i386-fscale.c +++ b/tests/tcg/i386/test-i386-fscale.c @@ -31,6 +31,7 @@ int issignaling_ld(long double x) int main(void) { + short cw; int ret = 0; __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (2.5L), "u" (__builtin_nansl(""))); @@ -62,5 +63,33 @@ int main(void) printf("FAIL: fscale invalid 4\n"); ret = 1; } + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (0.0L), "u" (__builtin_infl())); + if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { + printf("FAIL: fscale 0 up inf\n"); + ret = 1; + } + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (__builtin_infl()), "u" (-__builtin_infl())); + if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { + printf("FAIL: fscale inf down inf\n"); + ret = 1; + } + /* Set round-downward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x400; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (1.0L), "u" (__builtin_infl())); + if (ld_res != __builtin_infl()) { + printf("FAIL: fscale finite up inf\n"); + ret = 1; + } + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (-1.0L), "u" (-__builtin_infl())); + if (ld_res != -0.0L || __builtin_copysignl(1.0L, ld_res) != -1.0L) { + printf("FAIL: fscale finite down inf\n"); + ret = 1; + } return ret; } From c535d68755576bfa33be7aef7bd294a601f776e0 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 7 May 2020 00:46:28 +0000 Subject: [PATCH 1083/2595] target/i386: fix fscale handling of rounding precision The fscale implementation uses floatx80_scalbn for the final scaling operation. floatx80_scalbn ends up rounding the result using the dynamic rounding precision configured for the FPU. But only a limited set of x87 floating-point instructions are supposed to respect the dynamic rounding precision, and fscale is not in that set. Fix the implementation to save and restore the rounding precision around the call to floatx80_scalbn. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 3 +++ tests/tcg/i386/test-i386-fscale.c | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 72d1e77eb0..4d14c1ca24 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -1001,7 +1001,10 @@ void helper_fscale(CPUX86State *env) } } else { int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status); + signed char save = env->fp_status.floatx80_rounding_precision; + env->fp_status.floatx80_rounding_precision = 80; ST0 = floatx80_scalbn(ST0, n, &env->fp_status); + env->fp_status.floatx80_rounding_precision = save; } } diff --git a/tests/tcg/i386/test-i386-fscale.c b/tests/tcg/i386/test-i386-fscale.c index b953e7c563..d23b3cfeec 100644 --- a/tests/tcg/i386/test-i386-fscale.c +++ b/tests/tcg/i386/test-i386-fscale.c @@ -8,6 +8,8 @@ union u { long double ld; }; +volatile long double ld_third = 1.0L / 3.0L; +volatile long double ld_four_thirds = 4.0L / 3.0L; volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; @@ -91,5 +93,16 @@ int main(void) printf("FAIL: fscale finite down inf\n"); ret = 1; } + /* Set round-to-nearest with single-precision rounding. */ + cw = cw & ~0xf00; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (ld_third), "u" (2.0L)); + cw = cw | 0x300; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + if (ld_res != ld_four_thirds) { + printf("FAIL: fscale single-precision\n"); + ret = 1; + } return ret; } From 38df19fad71abe8823f8b416f672be95c2ac8d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 May 2020 17:53:02 +0200 Subject: [PATCH 1084/2595] exec: Let address_space_read/write_cached() propagate MemTxResult MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both address_space_read_cached_slow() and address_space_write_cached_slow() return a MemTxResult type. Do not discard it, return it to the caller. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- exec.c | 16 ++++++++-------- include/exec/memory.h | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/exec.c b/exec.c index be4be2df3a..0e197e53c2 100644 --- a/exec.c +++ b/exec.c @@ -3718,7 +3718,7 @@ static inline MemoryRegion *address_space_translate_cached( /* Called from RCU critical section. address_space_read_cached uses this * out of line function when the target is an MMIO or IOMMU region. */ -void +MemTxResult address_space_read_cached_slow(MemoryRegionCache *cache, hwaddr addr, void *buf, hwaddr len) { @@ -3728,15 +3728,15 @@ address_space_read_cached_slow(MemoryRegionCache *cache, hwaddr addr, l = len; mr = address_space_translate_cached(cache, addr, &addr1, &l, false, MEMTXATTRS_UNSPECIFIED); - flatview_read_continue(cache->fv, - addr, MEMTXATTRS_UNSPECIFIED, buf, len, - addr1, l, mr); + return flatview_read_continue(cache->fv, + addr, MEMTXATTRS_UNSPECIFIED, buf, len, + addr1, l, mr); } /* Called from RCU critical section. address_space_write_cached uses this * out of line function when the target is an MMIO or IOMMU region. */ -void +MemTxResult address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr, const void *buf, hwaddr len) { @@ -3746,9 +3746,9 @@ address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr, l = len; mr = address_space_translate_cached(cache, addr, &addr1, &l, true, MEMTXATTRS_UNSPECIFIED); - flatview_write_continue(cache->fv, - addr, MEMTXATTRS_UNSPECIFIED, buf, len, - addr1, l, mr); + return flatview_write_continue(cache->fv, + addr, MEMTXATTRS_UNSPECIFIED, buf, len, + addr1, l, mr); } #define ARG1_DECL MemoryRegionCache *cache diff --git a/include/exec/memory.h b/include/exec/memory.h index 3e00cdbbfa..48df5abe13 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -2354,10 +2354,11 @@ void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr); /* Internal functions, part of the implementation of address_space_read_cached * and address_space_write_cached. */ -void address_space_read_cached_slow(MemoryRegionCache *cache, - hwaddr addr, void *buf, hwaddr len); -void address_space_write_cached_slow(MemoryRegionCache *cache, - hwaddr addr, const void *buf, hwaddr len); +MemTxResult address_space_read_cached_slow(MemoryRegionCache *cache, + hwaddr addr, void *buf, hwaddr len); +MemTxResult address_space_write_cached_slow(MemoryRegionCache *cache, + hwaddr addr, const void *buf, + hwaddr len); static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) { @@ -2422,15 +2423,16 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr, * @buf: buffer with the data transferred * @len: length of the data transferred */ -static inline void +static inline MemTxResult address_space_read_cached(MemoryRegionCache *cache, hwaddr addr, void *buf, hwaddr len) { assert(addr < cache->len && len <= cache->len - addr); if (likely(cache->ptr)) { memcpy(buf, cache->ptr + addr, len); + return MEMTX_OK; } else { - address_space_read_cached_slow(cache, addr, buf, len); + return address_space_read_cached_slow(cache, addr, buf, len); } } @@ -2442,15 +2444,16 @@ address_space_read_cached(MemoryRegionCache *cache, hwaddr addr, * @buf: buffer with the data transferred * @len: length of the data transferred */ -static inline void +static inline MemTxResult address_space_write_cached(MemoryRegionCache *cache, hwaddr addr, const void *buf, hwaddr len) { assert(addr < cache->len && len <= cache->len - addr); if (likely(cache->ptr)) { memcpy(cache->ptr + addr, buf, len); + return MEMTX_OK; } else { - address_space_write_cached_slow(cache, addr, buf, len); + return address_space_write_cached_slow(cache, addr, buf, len); } } From ddfc8b96eec648f35f0f054bd3f0a05df6cd34fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 May 2020 17:53:03 +0200 Subject: [PATCH 1085/2595] exec: Propagate cpu_memory_rw_debug() error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not ignore the MemTxResult error type returned by the address_space_rw() API. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- exec.c | 12 ++++++++---- include/exec/cpu-all.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/exec.c b/exec.c index 0e197e53c2..9cbde85d8c 100644 --- a/exec.c +++ b/exec.c @@ -3771,6 +3771,7 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, while (len > 0) { int asidx; MemTxAttrs attrs; + MemTxResult res; page = addr & TARGET_PAGE_MASK; phys_addr = cpu_get_phys_page_attrs_debug(cpu, page, &attrs); @@ -3783,11 +3784,14 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, l = len; phys_addr += (addr & ~TARGET_PAGE_MASK); if (is_write) { - address_space_write_rom(cpu->cpu_ases[asidx].as, phys_addr, - attrs, buf, l); + res = address_space_write_rom(cpu->cpu_ases[asidx].as, phys_addr, + attrs, buf, l); } else { - address_space_read(cpu->cpu_ases[asidx].as, phys_addr, attrs, buf, - l); + res = address_space_read(cpu->cpu_ases[asidx].as, phys_addr, + attrs, buf, l); + } + if (res != MEMTX_OK) { + return -1; } len -= l; buf += l; diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index d14374bdd4..fb4e8a8e29 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -413,6 +413,7 @@ void dump_exec_info(void); void dump_opcount_info(void); #endif /* !CONFIG_USER_ONLY */ +/* Returns: 0 on success, -1 on error */ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, void *ptr, target_ulong len, bool is_write); From 6766ba506eb62110b8299d25718565a03220d012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 May 2020 17:53:04 +0200 Subject: [PATCH 1086/2595] disas: Let disas::read_memory() handler return EIO on error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both cpu_memory_rw_debug() and address_space_read() return an error on failed transaction. Check the returned value, and return EIO in case of error. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- disas.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/disas.c b/disas.c index 45285d3f63..c1397d3933 100644 --- a/disas.c +++ b/disas.c @@ -39,9 +39,11 @@ target_read_memory (bfd_vma memaddr, struct disassemble_info *info) { CPUDebug *s = container_of(info, CPUDebug, info); + int r; - cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0); - return 0; + r = cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0); + + return r ? EIO : 0; } /* Print an error message. We can assume that this is in response to @@ -718,10 +720,11 @@ physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length, struct disassemble_info *info) { CPUDebug *s = container_of(info, CPUDebug, info); + MemTxResult res; - address_space_read(s->cpu->as, memaddr, MEMTXATTRS_UNSPECIFIED, - myaddr, length); - return 0; + res = address_space_read(s->cpu->as, memaddr, MEMTXATTRS_UNSPECIFIED, + myaddr, length); + return res == MEMTX_OK ? 0 : EIO; } /* Disassembler for the monitor. */ From 5579b524b0d2e4b310157c0b7985d35c24238120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 May 2020 17:53:05 +0200 Subject: [PATCH 1087/2595] hw/elf_ops: Do not ignore write failures when loading ELF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not ignore the MemTxResult error type returned by address_space_write(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefano Garzarella Signed-off-by: Paolo Bonzini --- include/hw/elf_ops.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index 398a4a2c85..6fdff3dced 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -553,9 +553,14 @@ static int glue(load_elf, SZ)(const char *name, int fd, rom_add_elf_program(label, mapped_file, data, file_size, mem_size, addr, as); } else { - address_space_write(as ? as : &address_space_memory, - addr, MEMTXATTRS_UNSPECIFIED, - data, file_size); + MemTxResult res; + + res = address_space_write(as ? as : &address_space_memory, + addr, MEMTXATTRS_UNSPECIFIED, + data, file_size); + if (res != MEMTX_OK) { + goto fail; + } } } From 80b4008c805ebcfd4c0d302ac31c1689e34571e0 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Wed, 13 May 2020 23:49:27 +0000 Subject: [PATCH 1088/2595] target/i386: fix floating-point load-constant rounding The implementations of the fldl2t, fldl2e, fldpi, fldlg2 and fldln2 instructions load fixed constants independent of the rounding mode. Fix them to load a value correctly rounded for the current rounding mode (but always rounded to 64-bit precision independent of the precision control, and without setting "inexact") as specified. Signed-off-by: Joseph Myers Reviewed-by: Richard Henderson Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 54 +++++++- tests/tcg/i386/test-i386-fldcst.c | 199 ++++++++++++++++++++++++++++++ 2 files changed, 248 insertions(+), 5 deletions(-) create mode 100644 tests/tcg/i386/test-i386-fldcst.c diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 4d14c1ca24..f0b9cb5de8 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -59,8 +59,13 @@ #define FPUC_EM 0x3f #define floatx80_lg2 make_floatx80(0x3ffd, 0x9a209a84fbcff799LL) +#define floatx80_lg2_d make_floatx80(0x3ffd, 0x9a209a84fbcff798LL) #define floatx80_l2e make_floatx80(0x3fff, 0xb8aa3b295c17f0bcLL) +#define floatx80_l2e_d make_floatx80(0x3fff, 0xb8aa3b295c17f0bbLL) #define floatx80_l2t make_floatx80(0x4000, 0xd49a784bcd1b8afeLL) +#define floatx80_l2t_u make_floatx80(0x4000, 0xd49a784bcd1b8affLL) +#define floatx80_ln2_d make_floatx80(0x3ffe, 0xb17217f7d1cf79abLL) +#define floatx80_pi_d make_floatx80(0x4000, 0xc90fdaa22168c234LL) #if !defined(CONFIG_USER_ONLY) static qemu_irq ferr_irq; @@ -544,27 +549,66 @@ void helper_fld1_ST0(CPUX86State *env) void helper_fldl2t_ST0(CPUX86State *env) { - ST0 = floatx80_l2t; + switch (env->fpuc & FPU_RC_MASK) { + case FPU_RC_UP: + ST0 = floatx80_l2t_u; + break; + default: + ST0 = floatx80_l2t; + break; + } } void helper_fldl2e_ST0(CPUX86State *env) { - ST0 = floatx80_l2e; + switch (env->fpuc & FPU_RC_MASK) { + case FPU_RC_DOWN: + case FPU_RC_CHOP: + ST0 = floatx80_l2e_d; + break; + default: + ST0 = floatx80_l2e; + break; + } } void helper_fldpi_ST0(CPUX86State *env) { - ST0 = floatx80_pi; + switch (env->fpuc & FPU_RC_MASK) { + case FPU_RC_DOWN: + case FPU_RC_CHOP: + ST0 = floatx80_pi_d; + break; + default: + ST0 = floatx80_pi; + break; + } } void helper_fldlg2_ST0(CPUX86State *env) { - ST0 = floatx80_lg2; + switch (env->fpuc & FPU_RC_MASK) { + case FPU_RC_DOWN: + case FPU_RC_CHOP: + ST0 = floatx80_lg2_d; + break; + default: + ST0 = floatx80_lg2; + break; + } } void helper_fldln2_ST0(CPUX86State *env) { - ST0 = floatx80_ln2; + switch (env->fpuc & FPU_RC_MASK) { + case FPU_RC_DOWN: + case FPU_RC_CHOP: + ST0 = floatx80_ln2_d; + break; + default: + ST0 = floatx80_ln2; + break; + } } void helper_fldz_ST0(CPUX86State *env) diff --git a/tests/tcg/i386/test-i386-fldcst.c b/tests/tcg/i386/test-i386-fldcst.c new file mode 100644 index 0000000000..e635432ccf --- /dev/null +++ b/tests/tcg/i386/test-i386-fldcst.c @@ -0,0 +1,199 @@ +/* Test instructions loading floating-point constants. */ + +#include +#include + +volatile long double ld_res; + +int main(void) +{ + short cw; + int ret = 0; + + /* Round to nearest. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x000; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldl2t" : "=t" (ld_res)); + if (ld_res != 0x3.5269e12f346e2bf8p+0L) { + printf("FAIL: fldl2t N\n"); + ret = 1; + } + /* Round downward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x400; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldl2t" : "=t" (ld_res)); + if (ld_res != 0x3.5269e12f346e2bf8p+0L) { + printf("FAIL: fldl2t D\n"); + ret = 1; + } + /* Round toward zero. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0xc00; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldl2t" : "=t" (ld_res)); + if (ld_res != 0x3.5269e12f346e2bf8p+0L) { + printf("FAIL: fldl2t Z\n"); + ret = 1; + } + /* Round upward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x800; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldl2t" : "=t" (ld_res)); + if (ld_res != 0x3.5269e12f346e2bfcp+0L) { + printf("FAIL: fldl2t U\n"); + ret = 1; + } + + /* Round to nearest. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x000; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldl2e" : "=t" (ld_res)); + if (ld_res != 0x1.71547652b82fe178p+0L) { + printf("FAIL: fldl2e N\n"); + ret = 1; + } + /* Round downward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x400; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldl2e" : "=t" (ld_res)); + if (ld_res != 0x1.71547652b82fe176p+0L) { + printf("FAIL: fldl2e D\n"); + ret = 1; + } + /* Round toward zero. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0xc00; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldl2e" : "=t" (ld_res)); + if (ld_res != 0x1.71547652b82fe176p+0L) { + printf("FAIL: fldl2e Z\n"); + ret = 1; + } + /* Round upward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x800; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldl2e" : "=t" (ld_res)); + if (ld_res != 0x1.71547652b82fe178p+0L) { + printf("FAIL: fldl2e U\n"); + ret = 1; + } + + /* Round to nearest. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x000; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldpi" : "=t" (ld_res)); + if (ld_res != 0x3.243f6a8885a308d4p+0L) { + printf("FAIL: fldpi N\n"); + ret = 1; + } + /* Round downward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x400; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldpi" : "=t" (ld_res)); + if (ld_res != 0x3.243f6a8885a308dp+0L) { + printf("FAIL: fldpi D\n"); + ret = 1; + } + /* Round toward zero. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0xc00; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldpi" : "=t" (ld_res)); + if (ld_res != 0x3.243f6a8885a308dp+0L) { + printf("FAIL: fldpi Z\n"); + ret = 1; + } + /* Round upward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x800; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldpi" : "=t" (ld_res)); + if (ld_res != 0x3.243f6a8885a308d4p+0L) { + printf("FAIL: fldpi U\n"); + ret = 1; + } + + /* Round to nearest. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x000; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldlg2" : "=t" (ld_res)); + if (ld_res != 0x4.d104d427de7fbcc8p-4L) { + printf("FAIL: fldlg2 N\n"); + ret = 1; + } + /* Round downward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x400; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldlg2" : "=t" (ld_res)); + if (ld_res != 0x4.d104d427de7fbccp-4L) { + printf("FAIL: fldlg2 D\n"); + ret = 1; + } + /* Round toward zero. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0xc00; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldlg2" : "=t" (ld_res)); + if (ld_res != 0x4.d104d427de7fbccp-4L) { + printf("FAIL: fldlg2 Z\n"); + ret = 1; + } + /* Round upward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x800; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldlg2" : "=t" (ld_res)); + if (ld_res != 0x4.d104d427de7fbcc8p-4L) { + printf("FAIL: fldlg2 U\n"); + ret = 1; + } + + /* Round to nearest. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x000; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldln2" : "=t" (ld_res)); + if (ld_res != 0xb.17217f7d1cf79acp-4L) { + printf("FAIL: fldln2 N\n"); + ret = 1; + } + /* Round downward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x400; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldln2" : "=t" (ld_res)); + if (ld_res != 0xb.17217f7d1cf79abp-4L) { + printf("FAIL: fldln2 D\n"); + ret = 1; + } + /* Round toward zero. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0xc00; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldln2" : "=t" (ld_res)); + if (ld_res != 0xb.17217f7d1cf79abp-4L) { + printf("FAIL: fldln2 Z\n"); + ret = 1; + } + /* Round upward. */ + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xc00) | 0x800; + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("fldln2" : "=t" (ld_res)); + if (ld_res != 0xb.17217f7d1cf79acp-4L) { + printf("FAIL: fldln2 U\n"); + ret = 1; + } + + return ret; +} From 34b9cc076ff423023a779a04a9f7cd7c17372cbf Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Wed, 13 May 2020 23:50:19 +0000 Subject: [PATCH 1089/2595] target/i386: fix fxam handling of invalid encodings The fxam implementation does not check for invalid encodings, instead treating them like NaN or normal numbers depending on the exponent. Fix it to check that the high bit of the significand is set before treating an encoding as NaN or normal, thus resulting in correct handling (all of C0, C2 and C3 cleared) for invalid encodings. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 4 +- tests/tcg/i386/test-i386-fxam.c | 143 ++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 tests/tcg/i386/test-i386-fxam.c diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index f0b9cb5de8..185493db8e 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -1099,7 +1099,7 @@ void helper_fxam_ST0(CPUX86State *env) if (expdif == MAXEXPD) { if (MANTD(temp) == 0x8000000000000000ULL) { env->fpus |= 0x500; /* Infinity */ - } else { + } else if (MANTD(temp) & 0x8000000000000000ULL) { env->fpus |= 0x100; /* NaN */ } } else if (expdif == 0) { @@ -1108,7 +1108,7 @@ void helper_fxam_ST0(CPUX86State *env) } else { env->fpus |= 0x4400; /* Denormal */ } - } else { + } else if (MANTD(temp) & 0x8000000000000000ULL) { env->fpus |= 0x400; } } diff --git a/tests/tcg/i386/test-i386-fxam.c b/tests/tcg/i386/test-i386-fxam.c new file mode 100644 index 0000000000..ddd76ca42d --- /dev/null +++ b/tests/tcg/i386/test-i386-fxam.c @@ -0,0 +1,143 @@ +/* Test fxam instruction. */ + +#include +#include + +union u { + struct { uint64_t sig; uint16_t sign_exp; } s; + long double ld; +}; + +volatile union u ld_pseudo_m16382 = { .s = { UINT64_C(1) << 63, 0 } }; +volatile union u ld_pseudo_nm16382 = { .s = { UINT64_C(1) << 63, 0x8000 } }; +volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; +volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; +volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; +volatile union u ld_invalid_4 = { .s = { (UINT64_C(1) << 63) - 1, 0x7fff } }; +volatile union u ld_invalid_n1 = { .s = { 1, 0x8123 } }; +volatile union u ld_invalid_n2 = { .s = { 0, 0x8123 } }; +volatile union u ld_invalid_n3 = { .s = { 0, 0xffff } }; +volatile union u ld_invalid_n4 = { .s = { (UINT64_C(1) << 63) - 1, 0xffff } }; + +#define C0 (1 << 8) +#define C1 (1 << 9) +#define C2 (1 << 10) +#define C3 (1 << 14) +#define FLAGS (C0 | C1 | C2 | C3) + +int main(void) +{ + short sw; + int ret = 0; + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (0.0L)); + if ((sw & FLAGS) != C3) { + printf("FAIL: +0\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-0.0L)); + if ((sw & FLAGS) != (C3 | C1)) { + printf("FAIL: -0\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (1.0L)); + if ((sw & FLAGS) != C2) { + printf("FAIL: +normal\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-1.0L)); + if ((sw & FLAGS) != (C2 | C1)) { + printf("FAIL: -normal\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (__builtin_infl())); + if ((sw & FLAGS) != (C2 | C0)) { + printf("FAIL: +inf\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-__builtin_infl())); + if ((sw & FLAGS) != (C2 | C1 | C0)) { + printf("FAIL: -inf\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (__builtin_nanl(""))); + if ((sw & FLAGS) != C0) { + printf("FAIL: +nan\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-__builtin_nanl(""))); + if ((sw & FLAGS) != (C1 | C0)) { + printf("FAIL: -nan\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (__builtin_nansl(""))); + if ((sw & FLAGS) != C0) { + printf("FAIL: +snan\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-__builtin_nansl(""))); + if ((sw & FLAGS) != (C1 | C0)) { + printf("FAIL: -snan\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (0x1p-16445L)); + if ((sw & FLAGS) != (C3 | C2)) { + printf("FAIL: +denormal\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (-0x1p-16445L)); + if ((sw & FLAGS) != (C3 | C2 | C1)) { + printf("FAIL: -denormal\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_pseudo_m16382.ld)); + if ((sw & FLAGS) != (C3 | C2)) { + printf("FAIL: +pseudo-denormal\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_pseudo_nm16382.ld)); + if ((sw & FLAGS) != (C3 | C2 | C1)) { + printf("FAIL: -pseudo-denormal\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_1.ld)); + if ((sw & FLAGS) != 0) { + printf("FAIL: +invalid 1\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_n1.ld)); + if ((sw & FLAGS) != C1) { + printf("FAIL: -invalid 1\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_2.ld)); + if ((sw & FLAGS) != 0) { + printf("FAIL: +invalid 2\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_n2.ld)); + if ((sw & FLAGS) != C1) { + printf("FAIL: -invalid 2\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_3.ld)); + if ((sw & FLAGS) != 0) { + printf("FAIL: +invalid 3\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_n3.ld)); + if ((sw & FLAGS) != C1) { + printf("FAIL: -invalid 3\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_4.ld)); + if ((sw & FLAGS) != 0) { + printf("FAIL: +invalid 4\n"); + ret = 1; + } + __asm__ volatile ("fxam\nfnstsw" : "=a" (sw) : "t" (ld_invalid_n4.ld)); + if ((sw & FLAGS) != C1) { + printf("FAIL: -invalid 4\n"); + ret = 1; + } + return ret; +} From 18c53e1e73197a24f9f4b66b1276eb9868db5bf0 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Wed, 13 May 2020 23:51:09 +0000 Subject: [PATCH 1090/2595] target/i386: fix fbstp handling of negative zero The fbstp implementation stores +0 when the rounded result should be -0 because it compares an integer value with 0 to determine the sign. Fix this by checking the sign bit of the operand instead. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 5 ++++- tests/tcg/i386/test-i386-fbstp.c | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/i386/test-i386-fbstp.c diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 185493db8e..f0a57099ca 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -726,11 +726,14 @@ void helper_fbst_ST0(CPUX86State *env, target_ulong ptr) int v; target_ulong mem_ref, mem_end; int64_t val; + CPU_LDoubleU temp; + + temp.d = ST0; val = floatx80_to_int64(ST0, &env->fp_status); mem_ref = ptr; mem_end = mem_ref + 9; - if (val < 0) { + if (SIGND(temp)) { cpu_stb_data_ra(env, mem_end, 0x80, GETPC()); val = -val; } else { diff --git a/tests/tcg/i386/test-i386-fbstp.c b/tests/tcg/i386/test-i386-fbstp.c new file mode 100644 index 0000000000..d368949188 --- /dev/null +++ b/tests/tcg/i386/test-i386-fbstp.c @@ -0,0 +1,25 @@ +/* Test fbstp instruction. */ + +#include +#include + +int main(void) +{ + int ret = 0; + unsigned char out[10]; + memset(out, 0xfe, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-0.0L) : "st"); + out[9] &= 0x80; + if (memcmp(out, "\0\0\0\0\0\0\0\0\0\x80", sizeof out) != 0) { + printf("FAIL: fbstp -0\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-0.1L) : "st"); + out[9] &= 0x80; + if (memcmp(out, "\0\0\0\0\0\0\0\0\0\x80", sizeof out) != 0) { + printf("FAIL: fbstp -0.1\n"); + ret = 1; + } + return ret; +} From 374ff4d0a3c2cce2bc6e4ba8a77eaba55c165252 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Wed, 13 May 2020 23:51:42 +0000 Subject: [PATCH 1091/2595] target/i386: fix fbstp handling of out-of-range values The fbstp implementation fails to check for out-of-range and invalid values, instead just taking the result of conversion to int64_t and storing its sign and low 18 decimal digits. Fix this by checking for an out-of-range result (invalid conversions always result in INT64_MAX or INT64_MIN from the softfloat code, which are large enough to be considered as out-of-range by this code) and storing the packed BCD indefinite encoding in that case. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 10 +++ tests/tcg/i386/test-i386-fbstp.c | 115 +++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index f0a57099ca..41f6f391ca 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -732,6 +732,16 @@ void helper_fbst_ST0(CPUX86State *env, target_ulong ptr) val = floatx80_to_int64(ST0, &env->fp_status); mem_ref = ptr; + if (val >= 1000000000000000000LL || val <= -1000000000000000000LL) { + float_raise(float_flag_invalid, &env->fp_status); + while (mem_ref < ptr + 7) { + cpu_stb_data_ra(env, mem_ref++, 0, GETPC()); + } + cpu_stb_data_ra(env, mem_ref++, 0xc0, GETPC()); + cpu_stb_data_ra(env, mem_ref++, 0xff, GETPC()); + cpu_stb_data_ra(env, mem_ref++, 0xff, GETPC()); + return; + } mem_end = mem_ref + 9; if (SIGND(temp)) { cpu_stb_data_ra(env, mem_end, 0x80, GETPC()); diff --git a/tests/tcg/i386/test-i386-fbstp.c b/tests/tcg/i386/test-i386-fbstp.c index d368949188..73bf56b9dc 100644 --- a/tests/tcg/i386/test-i386-fbstp.c +++ b/tests/tcg/i386/test-i386-fbstp.c @@ -1,8 +1,19 @@ /* Test fbstp instruction. */ +#include #include #include +union u { + struct { uint64_t sig; uint16_t sign_exp; } s; + long double ld; +}; + +volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; +volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; +volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; +volatile union u ld_invalid_4 = { .s = { (UINT64_C(1) << 63) - 1, 0x7fff } }; + int main(void) { int ret = 0; @@ -21,5 +32,109 @@ int main(void) printf("FAIL: fbstp -0.1\n"); ret = 1; } + memset(out, 0x1f, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-987654321987654321.0L) : + "st"); + out[9] &= 0x80; + if (memcmp(out, "\x21\x43\x65\x87\x19\x32\x54\x76\x98\x80", + sizeof out) != 0) { + printf("FAIL: fbstp -987654321987654321\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (999999999999999999.5L) : + "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp 999999999999999999.5\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (1000000000000000000.0L) : + "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp 1000000000000000000\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (1e30L) : "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp 1e30\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-999999999999999999.5L) : + "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp -999999999999999999.5\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-1000000000000000000.0L) : + "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp -1000000000000000000\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-1e30L) : "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp -1e30\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (__builtin_infl()) : "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp inf\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-__builtin_infl()) : + "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp -inf\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (__builtin_nanl("")) : + "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp nan\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-__builtin_nanl("")) : + "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp -nan\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_invalid_1.ld) : + "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp invalid 1\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_invalid_2.ld) : + "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp invalid 2\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_invalid_3.ld) : + "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp invalid 3\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_invalid_4.ld) : + "st"); + if (memcmp(out, "\0\0\0\0\0\0\0\xc0\xff\xff", sizeof out) != 0) { + printf("FAIL: fbstp invalid 4\n"); + ret = 1; + } return ret; } From c8af85b10c818709755f5dc8061c69920611fd4c Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 15 May 2020 21:20:25 +0000 Subject: [PATCH 1092/2595] target/i386: fix fisttpl, fisttpll handling of out-of-range values The fist / fistt family of instructions should all store the most negative integer in the destination format when the rounded / truncated integer result is out of range or the input is an invalid encoding, infinity or NaN. The fisttpl and fisttpll implementations (32-bit and 64-bit results, truncate towards zero) failed to do this, producing the most positive integer in some cases instead. Fix this by copying the code used to handle this issue for fistpl and fistpll, adjusted to use the _round_to_zero functions for the actual conversion (but without any other changes to that code). Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 28 ++++++++- tests/tcg/i386/test-i386-fisttp.c | 100 ++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 tests/tcg/i386/test-i386-fisttp.c diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 41f6f391ca..9c93f385b1 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -338,12 +338,36 @@ int32_t helper_fistt_ST0(CPUX86State *env) int32_t helper_fisttl_ST0(CPUX86State *env) { - return floatx80_to_int32_round_to_zero(ST0, &env->fp_status); + int32_t val; + signed char old_exp_flags; + + old_exp_flags = get_float_exception_flags(&env->fp_status); + set_float_exception_flags(0, &env->fp_status); + + val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) { + val = 0x80000000; + } + set_float_exception_flags(get_float_exception_flags(&env->fp_status) + | old_exp_flags, &env->fp_status); + return val; } int64_t helper_fisttll_ST0(CPUX86State *env) { - return floatx80_to_int64_round_to_zero(ST0, &env->fp_status); + int64_t val; + signed char old_exp_flags; + + old_exp_flags = get_float_exception_flags(&env->fp_status); + set_float_exception_flags(0, &env->fp_status); + + val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) { + val = 0x8000000000000000ULL; + } + set_float_exception_flags(get_float_exception_flags(&env->fp_status) + | old_exp_flags, &env->fp_status); + return val; } void helper_fldt_ST0(CPUX86State *env, target_ulong ptr) diff --git a/tests/tcg/i386/test-i386-fisttp.c b/tests/tcg/i386/test-i386-fisttp.c new file mode 100644 index 0000000000..16af59a774 --- /dev/null +++ b/tests/tcg/i386/test-i386-fisttp.c @@ -0,0 +1,100 @@ +/* Test fisttpl and fisttpll instructions. */ + +#include +#include +#include + +union u { + struct { uint64_t sig; uint16_t sign_exp; } s; + long double ld; +}; + +volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; + +int main(void) +{ + int ret = 0; + int32_t res_32; + int64_t res_64; + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (0x1p100L) : "st"); + if (res_32 != INT32_MIN) { + printf("FAIL: fisttpl 0x1p100\n"); + ret = 1; + } + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (-0x1p100L) : "st"); + if (res_32 != INT32_MIN) { + printf("FAIL: fisttpl -0x1p100\n"); + ret = 1; + } + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (__builtin_infl()) : + "st"); + if (res_32 != INT32_MIN) { + printf("FAIL: fisttpl inf\n"); + ret = 1; + } + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (-__builtin_infl()) : + "st"); + if (res_32 != INT32_MIN) { + printf("FAIL: fisttpl -inf\n"); + ret = 1; + } + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (__builtin_nanl("")) : + "st"); + if (res_32 != INT32_MIN) { + printf("FAIL: fisttpl nan\n"); + ret = 1; + } + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : + "t" (-__builtin_nanl("")) : "st"); + if (res_32 != INT32_MIN) { + printf("FAIL: fisttpl -nan\n"); + ret = 1; + } + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (ld_invalid_1.ld) : + "st"); + if (res_32 != INT32_MIN) { + printf("FAIL: fisttpl invalid\n"); + ret = 1; + } + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (0x1p100L) : "st"); + if (res_64 != INT64_MIN) { + printf("FAIL: fisttpll 0x1p100\n"); + ret = 1; + } + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (-0x1p100L) : "st"); + if (res_64 != INT64_MIN) { + printf("FAIL: fisttpll -0x1p100\n"); + ret = 1; + } + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (__builtin_infl()) : + "st"); + if (res_64 != INT64_MIN) { + printf("FAIL: fisttpll inf\n"); + ret = 1; + } + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (-__builtin_infl()) : + "st"); + if (res_64 != INT64_MIN) { + printf("FAIL: fisttpll -inf\n"); + ret = 1; + } + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : + "t" (__builtin_nanl("")) : "st"); + if (res_64 != INT64_MIN) { + printf("FAIL: fisttpll nan\n"); + ret = 1; + } + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : + "t" (-__builtin_nanl("")) : "st"); + if (res_64 != INT64_MIN) { + printf("FAIL: fisttpll -nan\n"); + ret = 1; + } + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (ld_invalid_1.ld) : + "st"); + if (res_64 != INT64_MIN) { + printf("FAIL: fisttpll invalid\n"); + ret = 1; + } + return ret; +} From c781a2cc423155079acf45e5ce79e6635f109fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 18 May 2020 12:31:13 +0200 Subject: [PATCH 1093/2595] hw/i386/vmport: Allow QTest use without crashing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trying libFuzzer on the vmport device, we get: AddressSanitizer:DEADLYSIGNAL ================================================================= ==29476==ERROR: AddressSanitizer: SEGV on unknown address 0x000000008840 (pc 0x56448bec4d79 bp 0x7ffeec9741b0 sp 0x7ffeec9740e0 T0) ==29476==The signal is caused by a READ memory access. #0 0x56448bec4d78 in vmport_ioport_read (qemu-fuzz-i386+0x1260d78) #1 0x56448bb5f175 in memory_region_read_accessor (qemu-fuzz-i386+0xefb175) #2 0x56448bb30c13 in access_with_adjusted_size (qemu-fuzz-i386+0xeccc13) #3 0x56448bb2ea27 in memory_region_dispatch_read1 (qemu-fuzz-i386+0xecaa27) #4 0x56448bb2e443 in memory_region_dispatch_read (qemu-fuzz-i386+0xeca443) #5 0x56448b961ab1 in flatview_read_continue (qemu-fuzz-i386+0xcfdab1) #6 0x56448b96336d in flatview_read (qemu-fuzz-i386+0xcff36d) #7 0x56448b962ec4 in address_space_read_full (qemu-fuzz-i386+0xcfeec4) This is easily reproducible using: $ echo inb 0x5658 | qemu-system-i386 -M isapc,accel=qtest -qtest stdio [I 1589796572.009763] OPENED [R +0.008069] inb 0x5658 Segmentation fault (core dumped) $ coredumpctl gdb -q Program terminated with signal SIGSEGV, Segmentation fault. #0 0x00005605b54d0f21 in vmport_ioport_read (opaque=0x5605b7531ce0, addr=0, size=4) at hw/i386/vmport.c:77 77 eax = env->regs[R_EAX]; (gdb) p cpu $1 = (X86CPU *) 0x0 (gdb) bt #0 0x00005605b54d0f21 in vmport_ioport_read (opaque=0x5605b7531ce0, addr=0, size=4) at hw/i386/vmport.c:77 #1 0x00005605b53db114 in memory_region_read_accessor (mr=0x5605b7531d80, addr=0, value=0x7ffc9d261a30, size=4, shift=0, mask=4294967295, attrs=...) at memory.c:434 #2 0x00005605b53db5d4 in access_with_adjusted_size (addr=0, value=0x7ffc9d261a30, size=1, access_size_min=4, access_size_max=4, access_fn= 0x5605b53db0d2 , mr=0x5605b7531d80, attrs=...) at memory.c:544 #3 0x00005605b53de156 in memory_region_dispatch_read1 (mr=0x5605b7531d80, addr=0, pval=0x7ffc9d261a30, size=1, attrs=...) at memory.c:1396 #4 0x00005605b53de228 in memory_region_dispatch_read (mr=0x5605b7531d80, addr=0, pval=0x7ffc9d261a30, op=MO_8, attrs=...) at memory.c:1424 #5 0x00005605b537c80a in flatview_read_continue (fv=0x5605b7650290, addr=22104, attrs=..., ptr=0x7ffc9d261b4b, len=1, addr1=0, l=1, mr=0x5605b7531d80) at exec.c:3200 #6 0x00005605b537c95d in flatview_read (fv=0x5605b7650290, addr=22104, attrs=..., buf=0x7ffc9d261b4b, len=1) at exec.c:3239 #7 0x00005605b537c9e6 in address_space_read_full (as=0x5605b5f74ac0 , addr=22104, attrs=..., buf=0x7ffc9d261b4b, len=1) at exec.c:3252 #8 0x00005605b53d5a5d in address_space_read (len=1, buf=0x7ffc9d261b4b, attrs=..., addr=22104, as=0x5605b5f74ac0 ) at include/exec/memory.h:2401 #9 0x00005605b53d5a5d in cpu_inb (addr=22104) at ioport.c:88 X86CPU is NULL because QTest accelerator does not use CPU. Fix by returning default values when QTest accelerator is used. Reported-by: Clang AddressSanitizer Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- hw/i386/vmport.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 79ef25d223..89bda9108e 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -34,6 +34,7 @@ #include "hw/qdev-properties.h" #include "sysemu/sysemu.h" #include "sysemu/hw_accel.h" +#include "sysemu/qtest.h" #include "qemu/log.h" #include "cpu.h" #include "trace.h" @@ -94,10 +95,14 @@ static uint64_t vmport_ioport_read(void *opaque, hwaddr addr, VMPortState *s = opaque; CPUState *cs = current_cpu; X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; + CPUX86State *env; unsigned char command; uint32_t eax; + if (qtest_enabled()) { + return -1; + } + env = &cpu->env; cpu_synchronize_state(cs); eax = env->regs[R_EAX]; @@ -142,6 +147,9 @@ static void vmport_ioport_write(void *opaque, hwaddr addr, { X86CPU *cpu = X86_CPU(current_cpu); + if (qtest_enabled()) { + return; + } cpu->env.regs[R_EAX] = vmport_ioport_read(opaque, addr, 4); } @@ -149,6 +157,9 @@ static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr) { X86CPU *cpu = X86_CPU(current_cpu); + if (qtest_enabled()) { + return -1; + } cpu->env.regs[R_EBX] = VMPORT_MAGIC; if (port_state->compat_flags & VMPORT_COMPAT_REPORT_VMX_TYPE) { cpu->env.regs[R_ECX] = port_state->vmware_vmx_type; @@ -172,6 +183,9 @@ static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) { X86CPU *cpu = X86_CPU(current_cpu); + if (qtest_enabled()) { + return -1; + } cpu->env.regs[R_EBX] = 0x1177; return ram_size; } From 353f98c9ad52ff4b8cfe553c90be04f747a14c98 Mon Sep 17 00:00:00 2001 From: Cathy Zhang Date: Mon, 13 Apr 2020 14:52:38 +0800 Subject: [PATCH 1094/2595] x86/cpu: Enable AVX512_VP2INTERSECT cpu feature AVX512_VP2INTERSECT compute vector pair intersection to a pair of mask registers, which is introduced with intel Tiger Lake, defining as CPUID.(EAX=7,ECX=0):EDX[bit 08]. Refer to the following release spec: https://software.intel.com/sites/default/files/managed/c5/15/\ architecture-instruction-set-extensions-programming-reference.pdf Signed-off-by: Cathy Zhang Message-Id: <1586760758-13638-1-git-send-email-cathy.zhang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 +- target/i386/cpu.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index b5705cda86..e89d9fa894 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -985,7 +985,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .feat_names = { NULL, NULL, "avx512-4vnniw", "avx512-4fmaps", NULL, NULL, NULL, NULL, - NULL, NULL, "md-clear", NULL, + "avx512-vp2intersect", NULL, "md-clear", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* pconfig */, NULL, NULL, NULL, NULL, NULL, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 37572bd437..100476ee89 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -772,6 +772,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Multiply Accumulation Single Precision */ #define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) +/* AVX512 Vector Pair Intersection to a Pair of Mask Registers */ +#define CPUID_7_0_EDX_AVX512_VP2INTERSECT (1U << 8) /* Speculation Control */ #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Single Thread Indirect Branch Predictors */ From 97a3757616ca27840c7ce1d088d8f1d2e5753738 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 18 Mar 2020 10:52:01 -0400 Subject: [PATCH 1095/2595] vfio/pci: Use kvm_irqchip_add_irqfd_notifier_gsi() for irqfds VFIO is currently the only one left that is not using the generic function (kvm_irqchip_add_irqfd_notifier_gsi()) to register irqfds. Let VFIO use the common framework too. Follow up patches will introduce extra features for kvm irqfd, so that VFIO can easily leverage that after the switch. Reviewed-by: Eric Auger Reviewed-by: Cornelia Huck Reviewed-by: Alex Williamson Acked-by: Alex Williamson Signed-off-by: Peter Xu Message-Id: <20200318145204.74483-3-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- hw/vfio/pci.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 342dd6b912..6838bcc4b3 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -115,11 +115,7 @@ static void vfio_intx_eoi(VFIODevice *vbasedev) static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp) { #ifdef CONFIG_KVM - struct kvm_irqfd irqfd = { - .fd = event_notifier_get_fd(&vdev->intx.interrupt), - .gsi = vdev->intx.route.irq, - .flags = KVM_IRQFD_FLAG_RESAMPLE, - }; + int irq_fd = event_notifier_get_fd(&vdev->intx.interrupt); Error *err = NULL; if (vdev->no_kvm_intx || !kvm_irqfds_enabled() || @@ -129,7 +125,7 @@ static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp) } /* Get to a known interrupt state */ - qemu_set_fd_handler(irqfd.fd, NULL, NULL, vdev); + qemu_set_fd_handler(irq_fd, NULL, NULL, vdev); vfio_mask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); vdev->intx.pending = false; pci_irq_deassert(&vdev->pdev); @@ -140,17 +136,18 @@ static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp) goto fail; } - /* KVM triggers it, VFIO listens for it */ - irqfd.resamplefd = event_notifier_get_fd(&vdev->intx.unmask); - - if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) { + if (kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, + &vdev->intx.interrupt, + &vdev->intx.unmask, + vdev->intx.route.irq)) { error_setg_errno(errp, errno, "failed to setup resample irqfd"); goto fail_irqfd; } if (vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX, 0, VFIO_IRQ_SET_ACTION_UNMASK, - irqfd.resamplefd, &err)) { + event_notifier_get_fd(&vdev->intx.unmask), + &err)) { error_propagate(errp, err); goto fail_vfio; } @@ -165,12 +162,12 @@ static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp) return; fail_vfio: - irqfd.flags = KVM_IRQFD_FLAG_DEASSIGN; - kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd); + kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, &vdev->intx.interrupt, + vdev->intx.route.irq); fail_irqfd: event_notifier_cleanup(&vdev->intx.unmask); fail: - qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev); + qemu_set_fd_handler(irq_fd, vfio_intx_interrupt, NULL, vdev); vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); #endif } @@ -178,12 +175,6 @@ fail: static void vfio_intx_disable_kvm(VFIOPCIDevice *vdev) { #ifdef CONFIG_KVM - struct kvm_irqfd irqfd = { - .fd = event_notifier_get_fd(&vdev->intx.interrupt), - .gsi = vdev->intx.route.irq, - .flags = KVM_IRQFD_FLAG_DEASSIGN, - }; - if (!vdev->intx.kvm_accel) { return; } @@ -197,7 +188,8 @@ static void vfio_intx_disable_kvm(VFIOPCIDevice *vdev) pci_irq_deassert(&vdev->pdev); /* Tell KVM to stop listening for an INTx irqfd */ - if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) { + if (kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, &vdev->intx.interrupt, + vdev->intx.route.irq)) { error_report("vfio: Error: Failed to disable INTx irqfd: %m"); } @@ -205,7 +197,8 @@ static void vfio_intx_disable_kvm(VFIOPCIDevice *vdev) event_notifier_cleanup(&vdev->intx.unmask); /* QEMU starts listening for interrupt events. */ - qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev); + qemu_set_fd_handler(event_notifier_get_fd(&vdev->intx.interrupt), + vfio_intx_interrupt, NULL, vdev); vdev->intx.kvm_accel = false; From ff66ba87ba1c43c10bc77138281bbdbd8bddaaba Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 18 Mar 2020 10:52:02 -0400 Subject: [PATCH 1096/2595] KVM: Pass EventNotifier into kvm_irqchip_assign_irqfd So that kvm_irqchip_assign_irqfd() can have access to the EventNotifiers, especially the resample event. It is needed in follow up patch to cache and kick resamplefds from QEMU. Reviewed-by: Eric Auger Reviewed-by: Alex Williamson Signed-off-by: Peter Xu Message-Id: <20200318145204.74483-4-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- accel/kvm/kvm-all.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index d06cc04079..b048c10af9 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -1662,9 +1662,13 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg, return kvm_update_routing_entry(s, &kroute); } -static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int rfd, int virq, +static int kvm_irqchip_assign_irqfd(KVMState *s, EventNotifier *event, + EventNotifier *resample, int virq, bool assign) { + int fd = event_notifier_get_fd(event); + int rfd = resample ? event_notifier_get_fd(resample) : -1; + struct kvm_irqfd irqfd = { .fd = fd, .gsi = virq, @@ -1769,7 +1773,9 @@ int kvm_irqchip_add_hv_sint_route(KVMState *s, uint32_t vcpu, uint32_t sint) return -ENOSYS; } -static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign) +static int kvm_irqchip_assign_irqfd(KVMState *s, EventNotifier *event, + EventNotifier *resample, int virq, + bool assign) { abort(); } @@ -1783,15 +1789,13 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg) int kvm_irqchip_add_irqfd_notifier_gsi(KVMState *s, EventNotifier *n, EventNotifier *rn, int virq) { - return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n), - rn ? event_notifier_get_fd(rn) : -1, virq, true); + return kvm_irqchip_assign_irqfd(s, n, rn, virq, true); } int kvm_irqchip_remove_irqfd_notifier_gsi(KVMState *s, EventNotifier *n, int virq) { - return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n), -1, virq, - false); + return kvm_irqchip_assign_irqfd(s, n, NULL, virq, false); } int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, From c82d9d43ed5d1a7021890d788193fdbeae1011c8 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 18 Mar 2020 10:52:03 -0400 Subject: [PATCH 1097/2595] KVM: Kick resamplefd for split kernel irqchip This is majorly only for X86 because that's the only one that supports split irqchip for now. When the irqchip is split, we face a dilemma that KVM irqfd will be enabled, however the slow irqchip is still running in the userspace. It means that the resamplefd in the kernel irqfds won't take any effect and it will miss to ack INTx interrupts on EOIs. One example is split irqchip with VFIO INTx, which will break if we use the VFIO INTx fast path. This patch can potentially supports the VFIO fast path again for INTx, that the IRQ delivery will still use the fast path, while we don't need to trap MMIOs in QEMU for the device to emulate the EIOs (see the callers of vfio_eoi() hook). However the EOI of the INTx will still need to be done from the userspace by caching all the resamplefds in QEMU and kick properly for IOAPIC EOI broadcast. This is tricky because in this case the userspace ioapic irr & remote-irr will be bypassed. However such a change will greatly boost performance for assigned devices using INTx irqs (TCP_RR boosts 46% after this patch applied). When the userspace is responsible for the resamplefd kickup, don't register it on the kvm_irqfd anymore, because on newer kernels (after commit 654f1f13ea56, 5.2+) the KVM_IRQFD will fail if with both split irqchip and resamplefd. This will make sure that the fast path will work for all supported kernels. https://patchwork.kernel.org/patch/10738541/#22609933 Suggested-by: Paolo Bonzini Signed-off-by: Peter Xu Message-Id: <20200318145204.74483-5-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- accel/kvm/kvm-all.c | 79 ++++++++++++++++++++++++++++++++++++++++-- accel/kvm/trace-events | 1 + hw/intc/ioapic.c | 19 ++++++++++ include/sysemu/kvm.h | 4 +++ 4 files changed, 101 insertions(+), 2 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index b048c10af9..f24d7da783 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -160,9 +160,59 @@ static const KVMCapabilityInfo kvm_required_capabilites[] = { static NotifierList kvm_irqchip_change_notifiers = NOTIFIER_LIST_INITIALIZER(kvm_irqchip_change_notifiers); +struct KVMResampleFd { + int gsi; + EventNotifier *resample_event; + QLIST_ENTRY(KVMResampleFd) node; +}; +typedef struct KVMResampleFd KVMResampleFd; + +/* + * Only used with split irqchip where we need to do the resample fd + * kick for the kernel from userspace. + */ +static QLIST_HEAD(, KVMResampleFd) kvm_resample_fd_list = + QLIST_HEAD_INITIALIZER(kvm_resample_fd_list); + #define kvm_slots_lock(kml) qemu_mutex_lock(&(kml)->slots_lock) #define kvm_slots_unlock(kml) qemu_mutex_unlock(&(kml)->slots_lock) +static inline void kvm_resample_fd_remove(int gsi) +{ + KVMResampleFd *rfd; + + QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) { + if (rfd->gsi == gsi) { + QLIST_REMOVE(rfd, node); + g_free(rfd); + break; + } + } +} + +static inline void kvm_resample_fd_insert(int gsi, EventNotifier *event) +{ + KVMResampleFd *rfd = g_new0(KVMResampleFd, 1); + + rfd->gsi = gsi; + rfd->resample_event = event; + + QLIST_INSERT_HEAD(&kvm_resample_fd_list, rfd, node); +} + +void kvm_resample_fd_notify(int gsi) +{ + KVMResampleFd *rfd; + + QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) { + if (rfd->gsi == gsi) { + event_notifier_set(rfd->resample_event); + trace_kvm_resample_fd_notify(gsi); + return; + } + } +} + int kvm_get_max_memslots(void) { KVMState *s = KVM_STATE(current_accel()); @@ -1676,8 +1726,33 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, EventNotifier *event, }; if (rfd != -1) { - irqfd.flags |= KVM_IRQFD_FLAG_RESAMPLE; - irqfd.resamplefd = rfd; + assert(assign); + if (kvm_irqchip_is_split()) { + /* + * When the slow irqchip (e.g. IOAPIC) is in the + * userspace, KVM kernel resamplefd will not work because + * the EOI of the interrupt will be delivered to userspace + * instead, so the KVM kernel resamplefd kick will be + * skipped. The userspace here mimics what the kernel + * provides with resamplefd, remember the resamplefd and + * kick it when we receive EOI of this IRQ. + * + * This is hackery because IOAPIC is mostly bypassed + * (except EOI broadcasts) when irqfd is used. However + * this can bring much performance back for split irqchip + * with INTx IRQs (for VFIO, this gives 93% perf of the + * full fast path, which is 46% perf boost comparing to + * the INTx slow path). + */ + kvm_resample_fd_insert(virq, resample); + } else { + irqfd.flags |= KVM_IRQFD_FLAG_RESAMPLE; + irqfd.resamplefd = rfd; + } + } else if (!assign) { + if (kvm_irqchip_is_split()) { + kvm_resample_fd_remove(virq); + } } if (!kvm_irqfds_enabled()) { diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events index 4fb6e59d19..a68eb66534 100644 --- a/accel/kvm/trace-events +++ b/accel/kvm/trace-events @@ -16,4 +16,5 @@ kvm_set_ioeventfd_mmio(int fd, uint64_t addr, uint32_t val, bool assign, uint32_ kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%x val=0x%x assign: %d size: %d match: %d" kvm_set_user_memory(uint32_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d" kvm_clear_dirty_log(uint32_t slot, uint64_t start, uint32_t size) "slot#%"PRId32" start 0x%"PRIx64" size 0x%"PRIx32 +kvm_resample_fd_notify(int gsi) "gsi %d" diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index ffe30dc457..bca71b5934 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -241,6 +241,25 @@ void ioapic_eoi_broadcast(int vector) continue; } +#ifdef CONFIG_KVM + /* + * When IOAPIC is in the userspace while APIC is still in + * the kernel (i.e., split irqchip), we have a trick to + * kick the resamplefd logic for registered irqfds from + * userspace to deactivate the IRQ. When that happens, it + * means the irq bypassed userspace IOAPIC (so the irr and + * remote-irr of the table entry should be bypassed too + * even if interrupt come). Still kick the resamplefds if + * they're bound to the IRQ, to make sure to EOI the + * interrupt for the hardware correctly. + * + * Note: We still need to go through the irr & remote-irr + * operations below because we don't know whether there're + * emulated devices that are using/sharing the same IRQ. + */ + kvm_resample_fd_notify(n); +#endif + if (!(entry & IOAPIC_LVT_REMOTE_IRR)) { continue; } diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 3b2250471c..b4174d941c 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -554,4 +554,8 @@ int kvm_set_one_reg(CPUState *cs, uint64_t id, void *source); int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target); struct ppc_radix_page_info *kvm_get_radix_page_info(void); int kvm_get_max_memslots(void); + +/* Notify resamplefd for EOI of specific interrupts. */ +void kvm_resample_fd_notify(int gsi); + #endif From 4d1d4602488fd5f3c0f0601feac4289b474add37 Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Sun, 19 Apr 2020 15:21:40 +0530 Subject: [PATCH 1098/2595] chardev/char-socket: Properly make qio connections non blocking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In tcp_chr_sync_read function, there is a possibility of socket disconnection during blocking read, then tcp_chr_hup function would clean up the qio channel pointers(i.e ioc, sioc). Signed-off-by: Sai Pavan Boddu Message-Id: <1587289900-29485-1-git-send-email-sai.pavan.boddu@xilinx.com> Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- chardev/char-socket.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index db253d4024..dd3d3ed8d6 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -550,7 +550,9 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len) qio_channel_set_blocking(s->ioc, true, NULL); size = tcp_chr_recv(chr, (void *) buf, len); - qio_channel_set_blocking(s->ioc, false, NULL); + if (s->state != TCP_CHARDEV_STATE_DISCONNECTED) { + qio_channel_set_blocking(s->ioc, false, NULL); + } if (size == 0) { /* connection closed */ tcp_chr_disconnect(chr); From bbad173c7478269d2f4f67c81bafb1711f3cc815 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 16 Apr 2020 21:33:03 +0200 Subject: [PATCH 1099/2595] tests: machine-none-test: Enable MicroBlaze testing Enable MicroBlaze testing. Signed-off-by: Edgar E. Iglesias Message-Id: <20200416193303.23674-2-edgar.iglesias@gmail.com> Signed-off-by: Paolo Bonzini --- tests/qtest/machine-none-test.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c index 10d8ec26a9..8b7abea8af 100644 --- a/tests/qtest/machine-none-test.c +++ b/tests/qtest/machine-none-test.c @@ -33,8 +33,8 @@ static struct arch2cpu cpus_map[] = { { "cris", "crisv32" }, { "lm32", "lm32-full" }, { "m68k", "m5206" }, - /* FIXME: { "microblaze", "any" }, doesn't work with -M none -cpu any */ - /* FIXME: { "microblazeel", "any" }, doesn't work with -M none -cpu any */ + { "microblaze", "any" }, + { "microblazeel", "any" }, { "mips", "4Kc" }, { "mipsel", "I7200" }, { "mips64", "20Kc" }, @@ -79,10 +79,8 @@ static void test_machine_cpu_cli(void) QTestState *qts; if (!cpu_model) { - if (!(!strcmp(arch, "microblaze") || !strcmp(arch, "microblazeel"))) { - fprintf(stderr, "WARNING: cpu name for target '%s' isn't defined," - " add it to cpus_map\n", arch); - } + fprintf(stderr, "WARNING: cpu name for target '%s' isn't defined," + " add it to cpus_map\n", arch); return; /* TODO: die here to force all targets have a test */ } qts = qtest_initf("-machine none -cpu '%s'", cpu_model); From 2356ff8500f3aec43070fcfa61a624ec36a8c6b4 Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Fri, 17 Apr 2020 23:28:45 -0500 Subject: [PATCH 1100/2595] hw/i386/amd_iommu: Fix the reserved bits definition of IOMMU commands Many reserved bits of amd_iommu commands are defined incorrectly in QEMU. Because of it, QEMU incorrectly injects lots of illegal commands into guest VM's IOMMU event log. Signed-off-by: Wei Huang Message-Id: <20200418042845.596457-1-wei.huang2@amd.com> Signed-off-by: Paolo Bonzini --- hw/i386/amd_iommu.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index fd75cae024..4346060e62 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -370,7 +370,7 @@ static void amdvi_completion_wait(AMDVIState *s, uint64_t *cmd) hwaddr addr = cpu_to_le64(extract64(cmd[0], 3, 49)) << 3; uint64_t data = cpu_to_le64(cmd[1]); - if (extract64(cmd[0], 51, 8)) { + if (extract64(cmd[0], 52, 8)) { amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), s->cmdbuf + s->cmdbuf_head); } @@ -395,7 +395,7 @@ static void amdvi_inval_devtab_entry(AMDVIState *s, uint64_t *cmd) uint16_t devid = cpu_to_le16((uint16_t)extract64(cmd[0], 0, 16)); /* This command should invalidate internal caches of which there isn't */ - if (extract64(cmd[0], 15, 16) || cmd[1]) { + if (extract64(cmd[0], 16, 44) || cmd[1]) { amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), s->cmdbuf + s->cmdbuf_head); } @@ -405,9 +405,9 @@ static void amdvi_inval_devtab_entry(AMDVIState *s, uint64_t *cmd) static void amdvi_complete_ppr(AMDVIState *s, uint64_t *cmd) { - if (extract64(cmd[0], 15, 16) || extract64(cmd[0], 19, 8) || + if (extract64(cmd[0], 16, 16) || extract64(cmd[0], 52, 8) || extract64(cmd[1], 0, 2) || extract64(cmd[1], 3, 29) - || extract64(cmd[1], 47, 16)) { + || extract64(cmd[1], 48, 16)) { amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), s->cmdbuf + s->cmdbuf_head); } @@ -438,8 +438,8 @@ static void amdvi_inval_pages(AMDVIState *s, uint64_t *cmd) { uint16_t domid = cpu_to_le16((uint16_t)extract64(cmd[0], 32, 16)); - if (extract64(cmd[0], 20, 12) || extract64(cmd[0], 16, 12) || - extract64(cmd[0], 3, 10)) { + if (extract64(cmd[0], 20, 12) || extract64(cmd[0], 48, 12) || + extract64(cmd[1], 3, 9)) { amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), s->cmdbuf + s->cmdbuf_head); } @@ -451,7 +451,7 @@ static void amdvi_inval_pages(AMDVIState *s, uint64_t *cmd) static void amdvi_prefetch_pages(AMDVIState *s, uint64_t *cmd) { - if (extract64(cmd[0], 16, 8) || extract64(cmd[0], 20, 8) || + if (extract64(cmd[0], 16, 8) || extract64(cmd[0], 52, 8) || extract64(cmd[1], 1, 1) || extract64(cmd[1], 3, 1) || extract64(cmd[1], 5, 7)) { amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), @@ -463,7 +463,7 @@ static void amdvi_prefetch_pages(AMDVIState *s, uint64_t *cmd) static void amdvi_inval_inttable(AMDVIState *s, uint64_t *cmd) { - if (extract64(cmd[0], 16, 16) || cmd[1]) { + if (extract64(cmd[0], 16, 44) || cmd[1]) { amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), s->cmdbuf + s->cmdbuf_head); return; @@ -479,7 +479,8 @@ static void iommu_inval_iotlb(AMDVIState *s, uint64_t *cmd) { uint16_t devid = extract64(cmd[0], 0, 16); - if (extract64(cmd[1], 1, 1) || extract64(cmd[1], 3, 9)) { + if (extract64(cmd[1], 1, 1) || extract64(cmd[1], 3, 1) || + extract64(cmd[1], 6, 6)) { amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), s->cmdbuf + s->cmdbuf_head); return; From ddf63df736257f9151d5e0fc3c6fddcb97f29cab Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Thu, 30 Apr 2020 12:13:49 +0300 Subject: [PATCH 1101/2595] replay: implement fair mutex In record/replay icount mode main loop thread and vCPU thread do not perform simultaneously. They take replay mutex to synchronize the actions. Sometimes vCPU thread waits for locking the mutex for very long time, because main loop releases the mutex and takes it back again. Standard qemu mutex do not provide the ordering capabilities. This patch adds a "queue" for replay mutex. Therefore thread ordering becomes more "fair". Threads are executed in the same order as they are trying to take the mutex. Signed-off-by: Pavel Dovgalyuk Message-Id: <158823802979.28101.9340462887738957616.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- replay/replay-internal.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/replay/replay-internal.c b/replay/replay-internal.c index eba8246aae..2e8a3e947a 100644 --- a/replay/replay-internal.c +++ b/replay/replay-internal.c @@ -22,6 +22,9 @@ It also protects replay events queue which stores events to be written or read to the log. */ static QemuMutex lock; +/* Condition and queue for fair ordering of mutex lock requests. */ +static QemuCond mutex_cond; +static unsigned long mutex_head, mutex_tail; /* File for replay writing */ static bool write_error; @@ -197,9 +200,10 @@ static __thread bool replay_locked; void replay_mutex_init(void) { qemu_mutex_init(&lock); + qemu_cond_init(&mutex_cond); /* Hold the mutex while we start-up */ - qemu_mutex_lock(&lock); replay_locked = true; + ++mutex_tail; } bool replay_mutex_locked(void) @@ -211,10 +215,16 @@ bool replay_mutex_locked(void) void replay_mutex_lock(void) { if (replay_mode != REPLAY_MODE_NONE) { + unsigned long id; g_assert(!qemu_mutex_iothread_locked()); g_assert(!replay_mutex_locked()); qemu_mutex_lock(&lock); + id = mutex_tail++; + while (id != mutex_head) { + qemu_cond_wait(&mutex_cond, &lock); + } replay_locked = true; + qemu_mutex_unlock(&lock); } } @@ -222,7 +232,10 @@ void replay_mutex_unlock(void) { if (replay_mode != REPLAY_MODE_NONE) { g_assert(replay_mutex_locked()); + qemu_mutex_lock(&lock); + ++mutex_head; replay_locked = false; + qemu_cond_broadcast(&mutex_cond); qemu_mutex_unlock(&lock); } } From 20c8fa2ec74fe32a42008c177ed9c48031356705 Mon Sep 17 00:00:00 2001 From: Julio Faracco Date: Mon, 23 Mar 2020 17:05:38 -0300 Subject: [PATCH 1102/2595] i386: Remove unused define's from hax and hvf Commit acb9f95a removed boundary checks for ID and VCPU ID. After that, the max definitions of that boundaries are not required anymore. This commit is only a code cleanup. Signed-off-by: Julio Faracco Message-Id: <20200323200538.202164-1-jcfaracco@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/hax-i386.h | 2 -- target/i386/hvf/hvf-i386.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/target/i386/hax-i386.h b/target/i386/hax-i386.h index 7d988f81da..ec28708185 100644 --- a/target/i386/hax-i386.h +++ b/target/i386/hax-i386.h @@ -41,8 +41,6 @@ struct hax_state { }; #define HAX_MAX_VCPU 0x10 -#define MAX_VM_ID 0x40 -#define MAX_VCPU_ID 0x40 struct hax_vm { hax_fd fd; diff --git a/target/i386/hvf/hvf-i386.h b/target/i386/hvf/hvf-i386.h index 15ee4835cf..fbe4a350c5 100644 --- a/target/i386/hvf/hvf-i386.h +++ b/target/i386/hvf/hvf-i386.h @@ -21,8 +21,6 @@ #include "x86.h" #define HVF_MAX_VCPU 0x10 -#define MAX_VM_ID 0x40 -#define MAX_VCPU_ID 0x40 extern struct hvf_state hvf_global; From ea39f9b643959d759b8643b4c11c4cbb3683d0ff Mon Sep 17 00:00:00 2001 From: Like Xu Date: Fri, 29 May 2020 15:43:47 +0800 Subject: [PATCH 1103/2595] target/i386: define a new MSR based feature word - FEAT_PERF_CAPABILITIES The Perfmon and Debug Capability MSR named IA32_PERF_CAPABILITIES is a feature-enumerating MSR, which only enumerates the feature full-width write (via bit 13) by now which indicates the processor supports IA32_A_PMCx interface for updating bits 32 and above of IA32_PMCx. The existence of MSR IA32_PERF_CAPABILITIES is enumerated by CPUID.1:ECX[15]. Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Cc: Marcelo Tosatti Cc: qemu-devel@nongnu.org Signed-off-by: Like Xu Message-Id: <20200529074347.124619-5-like.xu@linux.intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 23 +++++++++++++++++++++++ target/i386/cpu.h | 3 +++ target/i386/kvm.c | 20 ++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index e89d9fa894..2d3b8d5dea 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1139,6 +1139,22 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .index = MSR_IA32_CORE_CAPABILITY, }, }, + [FEAT_PERF_CAPABILITIES] = { + .type = MSR_FEATURE_WORD, + .feat_names = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, "full-width-write", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .msr = { + .index = MSR_IA32_PERF_CAPABILITIES, + }, + }, [FEAT_VMX_PROCBASED_CTLS] = { .type = MSR_FEATURE_WORD, @@ -1316,6 +1332,10 @@ static FeatureDep feature_dependencies[] = { .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_CORE_CAPABILITY }, .to = { FEAT_CORE_CAPABILITY, ~0ull }, }, + { + .from = { FEAT_1_ECX, CPUID_EXT_PDCM }, + .to = { FEAT_PERF_CAPABILITIES, ~0ull }, + }, { .from = { FEAT_1_ECX, CPUID_EXT_VMX }, .to = { FEAT_VMX_PROCBASED_CTLS, ~0ull }, @@ -5488,6 +5508,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ebx |= (cs->nr_cores * cs->nr_threads) << 16; *edx |= CPUID_HT; } + if (!cpu->enable_pmu) { + *ecx &= ~CPUID_EXT_PDCM; + } break; case 2: /* cache info: needed for Pentium Pro compatibility */ diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 100476ee89..c2b8bdcbde 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -356,6 +356,8 @@ typedef enum X86Seg { #define MSR_IA32_ARCH_CAPABILITIES 0x10a #define ARCH_CAP_TSX_CTRL_MSR (1<<7) +#define MSR_IA32_PERF_CAPABILITIES 0x345 + #define MSR_IA32_TSX_CTRL 0x122 #define MSR_IA32_TSCDEADLINE 0x6e0 @@ -529,6 +531,7 @@ typedef enum FeatureWord { FEAT_XSAVE_COMP_HI, /* CPUID[EAX=0xd,ECX=0].EDX */ FEAT_ARCH_CAPABILITIES, FEAT_CORE_CAPABILITY, + FEAT_PERF_CAPABILITIES, FEAT_VMX_PROCBASED_CTLS, FEAT_VMX_SECONDARY_CTLS, FEAT_VMX_PINBASED_CTLS, diff --git a/target/i386/kvm.c b/target/i386/kvm.c index ef2e0a81dd..b3c13cb898 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -110,6 +110,7 @@ static bool has_msr_core_capabs; static bool has_msr_vmx_vmfunc; static bool has_msr_ucode_rev; static bool has_msr_vmx_procbased_ctls2; +static bool has_msr_perf_capabs; static uint32_t has_architectural_pmu_version; static uint32_t num_architectural_pmu_gp_counters; @@ -2033,6 +2034,9 @@ static int kvm_get_supported_msrs(KVMState *s) case MSR_IA32_CORE_CAPABILITY: has_msr_core_capabs = true; break; + case MSR_IA32_PERF_CAPABILITIES: + has_msr_perf_capabs = true; + break; case MSR_IA32_VMX_VMFUNC: has_msr_vmx_vmfunc = true; break; @@ -2649,6 +2653,18 @@ static void kvm_msr_entry_add_vmx(X86CPU *cpu, FeatureWordArray f) VMCS12_MAX_FIELD_INDEX << 1); } +static void kvm_msr_entry_add_perf(X86CPU *cpu, FeatureWordArray f) +{ + uint64_t kvm_perf_cap = + kvm_arch_get_supported_msr_feature(kvm_state, + MSR_IA32_PERF_CAPABILITIES); + + if (kvm_perf_cap) { + kvm_msr_entry_add(cpu, MSR_IA32_PERF_CAPABILITIES, + kvm_perf_cap & f[FEAT_PERF_CAPABILITIES]); + } +} + static int kvm_buf_set_msrs(X86CPU *cpu) { int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); @@ -2681,6 +2697,10 @@ static void kvm_init_msrs(X86CPU *cpu) env->features[FEAT_CORE_CAPABILITY]); } + if (has_msr_perf_capabs && cpu->enable_pmu) { + kvm_msr_entry_add_perf(cpu, env->features); + } + if (has_msr_ucode_rev) { kvm_msr_entry_add(cpu, MSR_IA32_UCODE_REV, cpu->ucode_rev); } From 9548a891738424a09eae9ef6e3826ef930cdd598 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 26 May 2020 08:25:26 +0100 Subject: [PATCH 1104/2595] util/oslib: Returns the real thread identifier on FreeBSD and NetBSD getpid is good enough in a mono thread context, however thr_self/_lwp_self reflects the real current thread identifier from a given process. Signed-off-by: David Carlier Signed-off-by: Paolo Bonzini Signed-off-by: David Carlier --- util/oslib-posix.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 062236a1ab..916f1be224 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -48,11 +48,13 @@ #ifdef __FreeBSD__ #include #include +#include #include #endif #ifdef __NetBSD__ #include +#include #endif #include "qemu/mmap-alloc.h" @@ -84,6 +86,13 @@ int qemu_get_thread_id(void) { #if defined(__linux__) return syscall(SYS_gettid); +#elif defined(__FreeBSD__) + /* thread id is up to INT_MAX */ + long tid; + thr_self(&tid); + return (int)tid; +#elif defined(__NetBSD__) + return _lwp_self(); #else return getpid(); #endif From 2261d3939fd40267029e790a9970f0e6c2ecfdea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 29 May 2020 14:53:25 +0200 Subject: [PATCH 1105/2595] memory: Make 'info mtree' not display disabled regions by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We might have many disabled memory regions, making the 'info mtree' output too verbose to be useful. Remove the disabled regions in the default output, but allow the monitor user to display them using the '-D' option. Before: (qemu) info mtree memory-region: system 0000000000000000-ffffffffffffffff (prio 0, i/o): system 0000000000000000-0000000007ffffff (prio 0, ram): alias ram-below-4g @pc.ram 0000000000000000-0000000007ffffff 0000000000000000-ffffffffffffffff (prio -1, i/o): pci 00000000000a0000-00000000000bffff (prio 1, i/o): vga-lowmem 00000000000c0000-00000000000dffff (prio 1, rom): pc.rom 00000000000e0000-00000000000fffff (prio 1, rom): alias isa-bios @pc.bios 0000000000020000-000000000003ffff 00000000fffc0000-00000000ffffffff (prio 0, rom): pc.bios 00000000000a0000-00000000000bffff (prio 1, i/o): alias smram-region @pci 00000000000a0000-00000000000bffff 00000000000c0000-00000000000c3fff (prio 1, ram): alias pam-ram @pc.ram 00000000000c0000-00000000000c3fff [disabled] 00000000000c0000-00000000000c3fff (prio 1, ram): alias pam-pci @pc.ram 00000000000c0000-00000000000c3fff [disabled] 00000000000c0000-00000000000c3fff (prio 1, ram): alias pam-rom @pc.ram 00000000000c0000-00000000000c3fff [disabled] 00000000000c0000-00000000000c3fff (prio 1, i/o): alias pam-pci @pci 00000000000c0000-00000000000c3fff 00000000000c4000-00000000000c7fff (prio 1, ram): alias pam-ram @pc.ram 00000000000c4000-00000000000c7fff [disabled] 00000000000c4000-00000000000c7fff (prio 1, ram): alias pam-pci @pc.ram 00000000000c4000-00000000000c7fff [disabled] 00000000000c4000-00000000000c7fff (prio 1, ram): alias pam-rom @pc.ram 00000000000c4000-00000000000c7fff [disabled] 00000000000c4000-00000000000c7fff (prio 1, i/o): alias pam-pci @pci 00000000000c4000-00000000000c7fff 00000000000c8000-00000000000cbfff (prio 1, ram): alias pam-ram @pc.ram 00000000000c8000-00000000000cbfff [disabled] 00000000000c8000-00000000000cbfff (prio 1, ram): alias pam-pci @pc.ram 00000000000c8000-00000000000cbfff [disabled] 00000000000c8000-00000000000cbfff (prio 1, ram): alias pam-rom @pc.ram 00000000000c8000-00000000000cbfff [disabled] 00000000000c8000-00000000000cbfff (prio 1, i/o): alias pam-pci @pci 00000000000c8000-00000000000cbfff 00000000000cc000-00000000000cffff (prio 1, ram): alias pam-ram @pc.ram 00000000000cc000-00000000000cffff [disabled] 00000000000cc000-00000000000cffff (prio 1, ram): alias pam-pci @pc.ram 00000000000cc000-00000000000cffff [disabled] 00000000000cc000-00000000000cffff (prio 1, ram): alias pam-rom @pc.ram 00000000000cc000-00000000000cffff [disabled] 00000000000cc000-00000000000cffff (prio 1, i/o): alias pam-pci @pci 00000000000cc000-00000000000cffff 00000000000d0000-00000000000d3fff (prio 1, ram): alias pam-ram @pc.ram 00000000000d0000-00000000000d3fff [disabled] 00000000000d0000-00000000000d3fff (prio 1, ram): alias pam-pci @pc.ram 00000000000d0000-00000000000d3fff [disabled] 00000000000d0000-00000000000d3fff (prio 1, ram): alias pam-rom @pc.ram 00000000000d0000-00000000000d3fff [disabled] 00000000000d0000-00000000000d3fff (prio 1, i/o): alias pam-pci @pci 00000000000d0000-00000000000d3fff 00000000000d4000-00000000000d7fff (prio 1, ram): alias pam-ram @pc.ram 00000000000d4000-00000000000d7fff [disabled] 00000000000d4000-00000000000d7fff (prio 1, ram): alias pam-pci @pc.ram 00000000000d4000-00000000000d7fff [disabled] 00000000000d4000-00000000000d7fff (prio 1, ram): alias pam-rom @pc.ram 00000000000d4000-00000000000d7fff [disabled] 00000000000d4000-00000000000d7fff (prio 1, i/o): alias pam-pci @pci 00000000000d4000-00000000000d7fff 00000000000d8000-00000000000dbfff (prio 1, ram): alias pam-ram @pc.ram 00000000000d8000-00000000000dbfff [disabled] 00000000000d8000-00000000000dbfff (prio 1, ram): alias pam-pci @pc.ram 00000000000d8000-00000000000dbfff [disabled] 00000000000d8000-00000000000dbfff (prio 1, ram): alias pam-rom @pc.ram 00000000000d8000-00000000000dbfff [disabled] 00000000000d8000-00000000000dbfff (prio 1, i/o): alias pam-pci @pci 00000000000d8000-00000000000dbfff 00000000000dc000-00000000000dffff (prio 1, ram): alias pam-ram @pc.ram 00000000000dc000-00000000000dffff [disabled] 00000000000dc000-00000000000dffff (prio 1, ram): alias pam-pci @pc.ram 00000000000dc000-00000000000dffff [disabled] 00000000000dc000-00000000000dffff (prio 1, ram): alias pam-rom @pc.ram 00000000000dc000-00000000000dffff [disabled] 00000000000dc000-00000000000dffff (prio 1, i/o): alias pam-pci @pci 00000000000dc000-00000000000dffff 00000000000e0000-00000000000e3fff (prio 1, ram): alias pam-ram @pc.ram 00000000000e0000-00000000000e3fff [disabled] 00000000000e0000-00000000000e3fff (prio 1, ram): alias pam-pci @pc.ram 00000000000e0000-00000000000e3fff [disabled] 00000000000e0000-00000000000e3fff (prio 1, ram): alias pam-rom @pc.ram 00000000000e0000-00000000000e3fff [disabled] 00000000000e0000-00000000000e3fff (prio 1, i/o): alias pam-pci @pci 00000000000e0000-00000000000e3fff 00000000000e4000-00000000000e7fff (prio 1, ram): alias pam-ram @pc.ram 00000000000e4000-00000000000e7fff [disabled] 00000000000e4000-00000000000e7fff (prio 1, ram): alias pam-pci @pc.ram 00000000000e4000-00000000000e7fff [disabled] 00000000000e4000-00000000000e7fff (prio 1, ram): alias pam-rom @pc.ram 00000000000e4000-00000000000e7fff [disabled] 00000000000e4000-00000000000e7fff (prio 1, i/o): alias pam-pci @pci 00000000000e4000-00000000000e7fff 00000000000e8000-00000000000ebfff (prio 1, ram): alias pam-ram @pc.ram 00000000000e8000-00000000000ebfff [disabled] 00000000000e8000-00000000000ebfff (prio 1, ram): alias pam-pci @pc.ram 00000000000e8000-00000000000ebfff [disabled] 00000000000e8000-00000000000ebfff (prio 1, ram): alias pam-rom @pc.ram 00000000000e8000-00000000000ebfff [disabled] 00000000000e8000-00000000000ebfff (prio 1, i/o): alias pam-pci @pci 00000000000e8000-00000000000ebfff 00000000000ec000-00000000000effff (prio 1, ram): alias pam-ram @pc.ram 00000000000ec000-00000000000effff [disabled] 00000000000ec000-00000000000effff (prio 1, ram): alias pam-pci @pc.ram 00000000000ec000-00000000000effff [disabled] 00000000000ec000-00000000000effff (prio 1, ram): alias pam-rom @pc.ram 00000000000ec000-00000000000effff [disabled] 00000000000ec000-00000000000effff (prio 1, i/o): alias pam-pci @pci 00000000000ec000-00000000000effff 00000000000f0000-00000000000fffff (prio 1, ram): alias pam-ram @pc.ram 00000000000f0000-00000000000fffff [disabled] 00000000000f0000-00000000000fffff (prio 1, ram): alias pam-pci @pc.ram 00000000000f0000-00000000000fffff [disabled] 00000000000f0000-00000000000fffff (prio 1, ram): alias pam-rom @pc.ram 00000000000f0000-00000000000fffff [disabled] 00000000000f0000-00000000000fffff (prio 1, i/o): alias pam-pci @pci 00000000000f0000-00000000000fffff 00000000fec00000-00000000fec00fff (prio 0, i/o): ioapic 00000000fed00000-00000000fed003ff (prio 0, i/o): hpet 00000000fee00000-00000000feefffff (prio 4096, i/o): apic-msi After: (qemu) info mtree memory-region: system 0000000000000000-ffffffffffffffff (prio 0, i/o): system 0000000000000000-0000000007ffffff (prio 0, ram): alias ram-below-4g @pc.ram 0000000000000000-0000000007ffffff 0000000000000000-ffffffffffffffff (prio -1, i/o): pci 00000000000a0000-00000000000bffff (prio 1, i/o): vga-lowmem 00000000000c0000-00000000000dffff (prio 1, rom): pc.rom 00000000000e0000-00000000000fffff (prio 1, rom): alias isa-bios @pc.bios 0000000000020000-000000000003ffff 00000000fffc0000-00000000ffffffff (prio 0, rom): pc.bios 00000000000a0000-00000000000bffff (prio 1, i/o): alias smram-region @pci 00000000000a0000-00000000000bffff 00000000000c0000-00000000000c3fff (prio 1, i/o): alias pam-pci @pci 00000000000c0000-00000000000c3fff 00000000000c4000-00000000000c7fff (prio 1, i/o): alias pam-pci @pci 00000000000c4000-00000000000c7fff 00000000000c8000-00000000000cbfff (prio 1, i/o): alias pam-pci @pci 00000000000c8000-00000000000cbfff 00000000000cc000-00000000000cffff (prio 1, i/o): alias pam-pci @pci 00000000000cc000-00000000000cffff 00000000000d0000-00000000000d3fff (prio 1, i/o): alias pam-pci @pci 00000000000d0000-00000000000d3fff 00000000000d4000-00000000000d7fff (prio 1, i/o): alias pam-pci @pci 00000000000d4000-00000000000d7fff 00000000000d8000-00000000000dbfff (prio 1, i/o): alias pam-pci @pci 00000000000d8000-00000000000dbfff 00000000000dc000-00000000000dffff (prio 1, i/o): alias pam-pci @pci 00000000000dc000-00000000000dffff 00000000000e0000-00000000000e3fff (prio 1, i/o): alias pam-pci @pci 00000000000e0000-00000000000e3fff 00000000000e4000-00000000000e7fff (prio 1, i/o): alias pam-pci @pci 00000000000e4000-00000000000e7fff 00000000000e8000-00000000000ebfff (prio 1, i/o): alias pam-pci @pci 00000000000e8000-00000000000ebfff 00000000000ec000-00000000000effff (prio 1, i/o): alias pam-pci @pci 00000000000ec000-00000000000effff 00000000000f0000-00000000000fffff (prio 1, i/o): alias pam-pci @pci 00000000000f0000-00000000000fffff 00000000fec00000-00000000fec00fff (prio 0, i/o): ioapic 00000000fed00000-00000000fed003ff (prio 0, i/o): hpet 00000000fee00000-00000000feefffff (prio 4096, i/o): apic-msi The old behavior is preserved using 'info mtree -D'. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- hmp-commands-info.hx | 7 ++-- include/exec/memory.h | 2 +- memory.c | 75 +++++++++++++++++++++++-------------------- monitor/misc.c | 3 +- 4 files changed, 48 insertions(+), 39 deletions(-) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index ca5198438d..30209e3903 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -254,11 +254,12 @@ ERST { .name = "mtree", - .args_type = "flatview:-f,dispatch_tree:-d,owner:-o", - .params = "[-f][-d][-o]", + .args_type = "flatview:-f,dispatch_tree:-d,owner:-o,disabled:-D", + .params = "[-f][-d][-o][-D]", .help = "show memory tree (-f: dump flat view for address spaces;" "-d: dump dispatch tree, valid with -f only);" - "-o: dump region owners/parents", + "-o: dump region owners/parents;" + "-D: dump disabled regions", .cmd = hmp_info_mtree, }, diff --git a/include/exec/memory.h b/include/exec/memory.h index 48df5abe13..bd7fdd6081 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1984,7 +1984,7 @@ void memory_global_dirty_log_start(void); */ void memory_global_dirty_log_stop(void); -void mtree_info(bool flatview, bool dispatch_tree, bool owner); +void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled); /** * memory_region_dispatch_read: perform a read directly to the specified diff --git a/memory.c b/memory.c index 91ceaf9fcf..2f15a4b250 100644 --- a/memory.c +++ b/memory.c @@ -2882,7 +2882,7 @@ static void mtree_print_mr_owner(const MemoryRegion *mr) static void mtree_print_mr(const MemoryRegion *mr, unsigned int level, hwaddr base, MemoryRegionListHead *alias_print_queue, - bool owner) + bool owner, bool display_disabled) { MemoryRegionList *new_ml, *ml, *next_ml; MemoryRegionListHead submr_print_queue; @@ -2894,10 +2894,6 @@ static void mtree_print_mr(const MemoryRegion *mr, unsigned int level, return; } - for (i = 0; i < level; i++) { - qemu_printf(MTREE_INDENT); - } - cur_start = base + mr->addr; cur_end = cur_start + MR_SIZE(mr->size); @@ -2926,35 +2922,46 @@ static void mtree_print_mr(const MemoryRegion *mr, unsigned int level, ml->mr = mr->alias; QTAILQ_INSERT_TAIL(alias_print_queue, ml, mrqueue); } - qemu_printf(TARGET_FMT_plx "-" TARGET_FMT_plx - " (prio %d, %s%s): alias %s @%s " TARGET_FMT_plx - "-" TARGET_FMT_plx "%s", - cur_start, cur_end, - mr->priority, - mr->nonvolatile ? "nv-" : "", - memory_region_type((MemoryRegion *)mr), - memory_region_name(mr), - memory_region_name(mr->alias), - mr->alias_offset, - mr->alias_offset + MR_SIZE(mr->size), - mr->enabled ? "" : " [disabled]"); - if (owner) { - mtree_print_mr_owner(mr); + if (mr->enabled || display_disabled) { + for (i = 0; i < level; i++) { + qemu_printf(MTREE_INDENT); + } + qemu_printf(TARGET_FMT_plx "-" TARGET_FMT_plx + " (prio %d, %s%s): alias %s @%s " TARGET_FMT_plx + "-" TARGET_FMT_plx "%s", + cur_start, cur_end, + mr->priority, + mr->nonvolatile ? "nv-" : "", + memory_region_type((MemoryRegion *)mr), + memory_region_name(mr), + memory_region_name(mr->alias), + mr->alias_offset, + mr->alias_offset + MR_SIZE(mr->size), + mr->enabled ? "" : " [disabled]"); + if (owner) { + mtree_print_mr_owner(mr); + } + qemu_printf("\n"); } } else { - qemu_printf(TARGET_FMT_plx "-" TARGET_FMT_plx - " (prio %d, %s%s): %s%s", - cur_start, cur_end, - mr->priority, - mr->nonvolatile ? "nv-" : "", - memory_region_type((MemoryRegion *)mr), - memory_region_name(mr), - mr->enabled ? "" : " [disabled]"); - if (owner) { - mtree_print_mr_owner(mr); + if (mr->enabled || display_disabled) { + for (i = 0; i < level; i++) { + qemu_printf(MTREE_INDENT); + } + qemu_printf(TARGET_FMT_plx "-" TARGET_FMT_plx + " (prio %d, %s%s): %s%s", + cur_start, cur_end, + mr->priority, + mr->nonvolatile ? "nv-" : "", + memory_region_type((MemoryRegion *)mr), + memory_region_name(mr), + mr->enabled ? "" : " [disabled]"); + if (owner) { + mtree_print_mr_owner(mr); + } + qemu_printf("\n"); } } - qemu_printf("\n"); QTAILQ_INIT(&submr_print_queue); @@ -2977,7 +2984,7 @@ static void mtree_print_mr(const MemoryRegion *mr, unsigned int level, QTAILQ_FOREACH(ml, &submr_print_queue, mrqueue) { mtree_print_mr(ml->mr, level + 1, cur_start, - alias_print_queue, owner); + alias_print_queue, owner, display_disabled); } QTAILQ_FOREACH_SAFE(ml, &submr_print_queue, mrqueue, next_ml) { @@ -3088,7 +3095,7 @@ static gboolean mtree_info_flatview_free(gpointer key, gpointer value, return true; } -void mtree_info(bool flatview, bool dispatch_tree, bool owner) +void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled) { MemoryRegionListHead ml_head; MemoryRegionList *ml, *ml2; @@ -3136,14 +3143,14 @@ void mtree_info(bool flatview, bool dispatch_tree, bool owner) QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { qemu_printf("address-space: %s\n", as->name); - mtree_print_mr(as->root, 1, 0, &ml_head, owner); + mtree_print_mr(as->root, 1, 0, &ml_head, owner, disabled); qemu_printf("\n"); } /* print aliased regions */ QTAILQ_FOREACH(ml, &ml_head, mrqueue) { qemu_printf("memory-region: %s\n", memory_region_name(ml->mr)); - mtree_print_mr(ml->mr, 1, 0, &ml_head, owner); + mtree_print_mr(ml->mr, 1, 0, &ml_head, owner, disabled); qemu_printf("\n"); } diff --git a/monitor/misc.c b/monitor/misc.c index f5207cd242..89bb970b00 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -957,8 +957,9 @@ static void hmp_info_mtree(Monitor *mon, const QDict *qdict) bool flatview = qdict_get_try_bool(qdict, "flatview", false); bool dispatch_tree = qdict_get_try_bool(qdict, "dispatch_tree", false); bool owner = qdict_get_try_bool(qdict, "owner", false); + bool disabled = qdict_get_try_bool(qdict, "disabled", false); - mtree_info(flatview, dispatch_tree, owner); + mtree_info(flatview, dispatch_tree, owner, disabled); } #ifdef CONFIG_PROFILER From c08790f48b2f41ef26d491fd4d460b74c06cefe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 11:38:08 +0200 Subject: [PATCH 1106/2595] qemu/thread: Mark qemu_thread_exit() with 'noreturn' attribute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After upgrading to Ubuntu 20.04 LTS, GCC 9.3 complains: util/qemu-thread-posix.c: In function ‘qemu_thread_exit’: util/qemu-thread-posix.c:577:6: error: function might be candidate for attribute ‘noreturn’ [-Werror=suggest-attribute=noreturn] 577 | void qemu_thread_exit(void *retval) | ^~~~~~~~~~~~~~~~ Fix by marking the qemu_thread_exit function with QEMU_NORETURN to set the 'noreturn' attribute. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- include/qemu/thread.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/qemu/thread.h b/include/qemu/thread.h index d22848138e..06c058fb58 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -177,7 +177,7 @@ void qemu_thread_create(QemuThread *thread, const char *name, void *qemu_thread_join(QemuThread *thread); void qemu_thread_get_self(QemuThread *thread); bool qemu_thread_is_self(QemuThread *thread); -void qemu_thread_exit(void *retval); +void qemu_thread_exit(void *retval) QEMU_NORETURN; void qemu_thread_naming(bool enable); struct Notifier; From f2dfe54c74f768a5bf78c9e5918918727f9d9459 Mon Sep 17 00:00:00 2001 From: Leonid Bloch Date: Mon, 25 May 2020 01:12:04 +0300 Subject: [PATCH 1107/2595] configure: Do not ignore malloc value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not checking the value of malloc will cause a warning with GCC 10.1, which may result in configuration failure, with the following line in config.log: config-temp/qemu-conf.c:2:18: error: ignoring return value of ‘malloc’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result] 2 | int main(void) { malloc(1); return 0; } | ^~~~~~~~~ Signed-off-by: Leonid Bloch Message-Id: <20200524221204.9791-1-lb.workbox@gmail.com> Signed-off-by: Paolo Bonzini --- configure | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 53a6dd0297..dbc16b5656 100755 --- a/configure +++ b/configure @@ -4587,7 +4587,13 @@ fi if test "$tcmalloc" = "yes" ; then cat > $TMPC << EOF #include -int main(void) { malloc(1); return 0; } +int main(void) { + void *tmp = malloc(1); + if (tmp != NULL) { + return 0; + } + return 1; +} EOF if compile_prog "" "-ltcmalloc" ; then @@ -4603,7 +4609,13 @@ fi if test "$jemalloc" = "yes" ; then cat > $TMPC << EOF #include -int main(void) { malloc(1); return 0; } +int main(void) { + void *tmp = malloc(1); + if (tmp != NULL) { + return 0; + } + return 1; +} EOF if compile_prog "" "-ljemalloc" ; then @@ -6164,7 +6176,9 @@ if test "$sanitizers" = "yes" ; then #include int main(void) { void *tmp = malloc(10); - return *(int *)(tmp + 2); + if (tmp != NULL) { + return *(int *)(tmp + 2); + } } EOF if compile_prog "$CPU_CFLAGS -Werror -fsanitize=undefined" ""; then From 77f55eac6c433e23e82a1b88b2d74f385c4c7d82 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Tue, 26 May 2020 16:47:43 +0530 Subject: [PATCH 1108/2595] exec: set map length to zero when returning NULL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When mapping physical memory into host's virtual address space, 'address_space_map' may return NULL if BounceBuffer is in_use. Set and return '*plen = 0' to avoid later NULL pointer dereference. Reported-by: Alexander Bulekov Fixes: https://bugs.launchpad.net/qemu/+bug/1878259 Suggested-by: Paolo Bonzini Suggested-by: Peter Maydell Signed-off-by: Prasad J Pandit Message-Id: <20200526111743.428367-1-ppandit@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- exec.c | 1 + include/exec/memory.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 9cbde85d8c..778263f1c6 100644 --- a/exec.c +++ b/exec.c @@ -3540,6 +3540,7 @@ void *address_space_map(AddressSpace *as, if (!memory_access_is_direct(mr, is_write)) { if (atomic_xchg(&bounce.in_use, true)) { + *plen = 0; return NULL; } /* Avoid unbounded allocations */ diff --git a/include/exec/memory.h b/include/exec/memory.h index bd7fdd6081..af8ca7824e 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -2314,7 +2314,8 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, hwaddr len, /* address_space_map: map a physical memory region into a host virtual address * * May map a subset of the requested range, given by and returned in @plen. - * May return %NULL if resources needed to perform the mapping are exhausted. + * May return %NULL and set *@plen to zero(0), if resources needed to perform + * the mapping are exhausted. * Use only for reads OR writes - not for read-modify-write operations. * Use cpu_register_map_client() to know when retrying the map operation is * likely to succeed. From 975af797f1e04e4d1b1a12f1731141d3770fdbce Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 15 May 2020 21:21:24 +0000 Subject: [PATCH 1109/2595] target/i386: fix IEEE x87 floating-point exception raising Most x87 instruction implementations fail to raise the expected IEEE floating-point exceptions because they do nothing to convert the exception state from the softfloat machinery into the exception flags in the x87 status word. There is special-case handling of division to raise the divide-by-zero exception, but that handling is itself buggy: it raises the exception in inappropriate cases (inf / 0 and nan / 0, which should not raise any exceptions, and 0 / 0, which should raise "invalid" instead). Fix this by converting the floating-point exceptions raised during an operation by the softfloat machinery into exceptions in the x87 status word (passing through the existing fpu_set_exception function for handling related to trapping exceptions). There are special cases where some functions convert to integer internally but exceptions from that conversion are not always correct exceptions for the instruction to raise. There might be scope for some simplification if the softfloat exception state either could always be assumed to be in sync with the state in the status word, or could always be ignored at the start of each instruction and just set to 0 then; I haven't looked into that in detail, and it might run into interactions with the various ways the emulation does not yet handle trapping exceptions properly. I think the approach taken here, of saving the softfloat state, setting exceptions there to 0 and then merging the old exceptions back in after carrying out the operation, is conservatively safe. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 126 +++- tests/tcg/i386/test-i386-fp-exceptions.c | 831 +++++++++++++++++++++++ 2 files changed, 926 insertions(+), 31 deletions(-) create mode 100644 tests/tcg/i386/test-i386-fp-exceptions.c diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 9c93f385b1..8ef5b463ea 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -161,12 +161,32 @@ static void fpu_set_exception(CPUX86State *env, int mask) } } +static inline uint8_t save_exception_flags(CPUX86State *env) +{ + uint8_t old_flags = get_float_exception_flags(&env->fp_status); + set_float_exception_flags(0, &env->fp_status); + return old_flags; +} + +static void merge_exception_flags(CPUX86State *env, uint8_t old_flags) +{ + uint8_t new_flags = get_float_exception_flags(&env->fp_status); + float_raise(old_flags, &env->fp_status); + fpu_set_exception(env, + ((new_flags & float_flag_invalid ? FPUS_IE : 0) | + (new_flags & float_flag_divbyzero ? FPUS_ZE : 0) | + (new_flags & float_flag_overflow ? FPUS_OE : 0) | + (new_flags & float_flag_underflow ? FPUS_UE : 0) | + (new_flags & float_flag_inexact ? FPUS_PE : 0) | + (new_flags & float_flag_input_denormal ? FPUS_DE : 0))); +} + static inline floatx80 helper_fdiv(CPUX86State *env, floatx80 a, floatx80 b) { - if (floatx80_is_zero(b)) { - fpu_set_exception(env, FPUS_ZE); - } - return floatx80_div(a, b, &env->fp_status); + uint8_t old_flags = save_exception_flags(env); + floatx80 ret = floatx80_div(a, b, &env->fp_status); + merge_exception_flags(env, old_flags); + return ret; } static void fpu_raise_exception(CPUX86State *env, uintptr_t retaddr) @@ -183,6 +203,7 @@ static void fpu_raise_exception(CPUX86State *env, uintptr_t retaddr) void helper_flds_FT0(CPUX86State *env, uint32_t val) { + uint8_t old_flags = save_exception_flags(env); union { float32 f; uint32_t i; @@ -190,10 +211,12 @@ void helper_flds_FT0(CPUX86State *env, uint32_t val) u.i = val; FT0 = float32_to_floatx80(u.f, &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fldl_FT0(CPUX86State *env, uint64_t val) { + uint8_t old_flags = save_exception_flags(env); union { float64 f; uint64_t i; @@ -201,6 +224,7 @@ void helper_fldl_FT0(CPUX86State *env, uint64_t val) u.i = val; FT0 = float64_to_floatx80(u.f, &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fildl_FT0(CPUX86State *env, int32_t val) @@ -210,6 +234,7 @@ void helper_fildl_FT0(CPUX86State *env, int32_t val) void helper_flds_ST0(CPUX86State *env, uint32_t val) { + uint8_t old_flags = save_exception_flags(env); int new_fpstt; union { float32 f; @@ -221,10 +246,12 @@ void helper_flds_ST0(CPUX86State *env, uint32_t val) env->fpregs[new_fpstt].d = float32_to_floatx80(u.f, &env->fp_status); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ + merge_exception_flags(env, old_flags); } void helper_fldl_ST0(CPUX86State *env, uint64_t val) { + uint8_t old_flags = save_exception_flags(env); int new_fpstt; union { float64 f; @@ -236,6 +263,7 @@ void helper_fldl_ST0(CPUX86State *env, uint64_t val) env->fpregs[new_fpstt].d = float64_to_floatx80(u.f, &env->fp_status); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ + merge_exception_flags(env, old_flags); } void helper_fildl_ST0(CPUX86State *env, int32_t val) @@ -260,113 +288,107 @@ void helper_fildll_ST0(CPUX86State *env, int64_t val) uint32_t helper_fsts_ST0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); union { float32 f; uint32_t i; } u; u.f = floatx80_to_float32(ST0, &env->fp_status); + merge_exception_flags(env, old_flags); return u.i; } uint64_t helper_fstl_ST0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); union { float64 f; uint64_t i; } u; u.f = floatx80_to_float64(ST0, &env->fp_status); + merge_exception_flags(env, old_flags); return u.i; } int32_t helper_fist_ST0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); int32_t val; val = floatx80_to_int32(ST0, &env->fp_status); if (val != (int16_t)val) { + set_float_exception_flags(float_flag_invalid, &env->fp_status); val = -32768; } + merge_exception_flags(env, old_flags); return val; } int32_t helper_fistl_ST0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); int32_t val; - signed char old_exp_flags; - - old_exp_flags = get_float_exception_flags(&env->fp_status); - set_float_exception_flags(0, &env->fp_status); val = floatx80_to_int32(ST0, &env->fp_status); if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) { val = 0x80000000; } - set_float_exception_flags(get_float_exception_flags(&env->fp_status) - | old_exp_flags, &env->fp_status); + merge_exception_flags(env, old_flags); return val; } int64_t helper_fistll_ST0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); int64_t val; - signed char old_exp_flags; - - old_exp_flags = get_float_exception_flags(&env->fp_status); - set_float_exception_flags(0, &env->fp_status); val = floatx80_to_int64(ST0, &env->fp_status); if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) { val = 0x8000000000000000ULL; } - set_float_exception_flags(get_float_exception_flags(&env->fp_status) - | old_exp_flags, &env->fp_status); + merge_exception_flags(env, old_flags); return val; } int32_t helper_fistt_ST0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); int32_t val; val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status); if (val != (int16_t)val) { + set_float_exception_flags(float_flag_invalid, &env->fp_status); val = -32768; } + merge_exception_flags(env, old_flags); return val; } int32_t helper_fisttl_ST0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); int32_t val; - signed char old_exp_flags; - - old_exp_flags = get_float_exception_flags(&env->fp_status); - set_float_exception_flags(0, &env->fp_status); val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status); if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) { val = 0x80000000; } - set_float_exception_flags(get_float_exception_flags(&env->fp_status) - | old_exp_flags, &env->fp_status); + merge_exception_flags(env, old_flags); return val; } int64_t helper_fisttll_ST0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); int64_t val; - signed char old_exp_flags; - - old_exp_flags = get_float_exception_flags(&env->fp_status); - set_float_exception_flags(0, &env->fp_status); val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status); if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) { val = 0x8000000000000000ULL; } - set_float_exception_flags(get_float_exception_flags(&env->fp_status) - | old_exp_flags, &env->fp_status); + merge_exception_flags(env, old_flags); return val; } @@ -449,24 +471,29 @@ static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500}; void helper_fcom_ST0_FT0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); FloatRelation ret; ret = floatx80_compare(ST0, FT0, &env->fp_status); env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1]; + merge_exception_flags(env, old_flags); } void helper_fucom_ST0_FT0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); FloatRelation ret; ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status); env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1]; + merge_exception_flags(env, old_flags); } static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; void helper_fcomi_ST0_FT0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); int eflags; FloatRelation ret; @@ -474,10 +501,12 @@ void helper_fcomi_ST0_FT0(CPUX86State *env) eflags = cpu_cc_compute_all(env, CC_OP); eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; CC_SRC = eflags; + merge_exception_flags(env, old_flags); } void helper_fucomi_ST0_FT0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); int eflags; FloatRelation ret; @@ -485,26 +514,35 @@ void helper_fucomi_ST0_FT0(CPUX86State *env) eflags = cpu_cc_compute_all(env, CC_OP); eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; CC_SRC = eflags; + merge_exception_flags(env, old_flags); } void helper_fadd_ST0_FT0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); ST0 = floatx80_add(ST0, FT0, &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fmul_ST0_FT0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); ST0 = floatx80_mul(ST0, FT0, &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fsub_ST0_FT0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); ST0 = floatx80_sub(ST0, FT0, &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fsubr_ST0_FT0(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); ST0 = floatx80_sub(FT0, ST0, &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fdiv_ST0_FT0(CPUX86State *env) @@ -521,22 +559,30 @@ void helper_fdivr_ST0_FT0(CPUX86State *env) void helper_fadd_STN_ST0(CPUX86State *env, int st_index) { + uint8_t old_flags = save_exception_flags(env); ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fmul_STN_ST0(CPUX86State *env, int st_index) { + uint8_t old_flags = save_exception_flags(env); ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fsub_STN_ST0(CPUX86State *env, int st_index) { + uint8_t old_flags = save_exception_flags(env); ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fsubr_STN_ST0(CPUX86State *env, int st_index) { + uint8_t old_flags = save_exception_flags(env); ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fdiv_STN_ST0(CPUX86State *env, int st_index) @@ -747,6 +793,7 @@ void helper_fbld_ST0(CPUX86State *env, target_ulong ptr) void helper_fbst_ST0(CPUX86State *env, target_ulong ptr) { + uint8_t old_flags = save_exception_flags(env); int v; target_ulong mem_ref, mem_end; int64_t val; @@ -757,13 +804,14 @@ void helper_fbst_ST0(CPUX86State *env, target_ulong ptr) val = floatx80_to_int64(ST0, &env->fp_status); mem_ref = ptr; if (val >= 1000000000000000000LL || val <= -1000000000000000000LL) { - float_raise(float_flag_invalid, &env->fp_status); + set_float_exception_flags(float_flag_invalid, &env->fp_status); while (mem_ref < ptr + 7) { cpu_stb_data_ra(env, mem_ref++, 0, GETPC()); } cpu_stb_data_ra(env, mem_ref++, 0xc0, GETPC()); cpu_stb_data_ra(env, mem_ref++, 0xff, GETPC()); cpu_stb_data_ra(env, mem_ref++, 0xff, GETPC()); + merge_exception_flags(env, old_flags); return; } mem_end = mem_ref + 9; @@ -785,6 +833,7 @@ void helper_fbst_ST0(CPUX86State *env, target_ulong ptr) while (mem_ref < mem_end) { cpu_stb_data_ra(env, mem_ref++, 0, GETPC()); } + merge_exception_flags(env, old_flags); } void helper_f2xm1(CPUX86State *env) @@ -838,6 +887,7 @@ void helper_fpatan(CPUX86State *env) void helper_fxtract(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); CPU_LDoubleU temp; temp.d = ST0; @@ -881,6 +931,7 @@ void helper_fxtract(CPUX86State *env) BIASEXPONENT(temp); ST0 = temp.d; } + merge_exception_flags(env, old_flags); } void helper_fprem1(CPUX86State *env) @@ -1020,11 +1071,13 @@ void helper_fyl2xp1(CPUX86State *env) void helper_fsqrt(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); if (floatx80_is_neg(ST0)) { env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */ env->fpus |= 0x400; } ST0 = floatx80_sqrt(ST0, &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fsincos(CPUX86State *env) @@ -1044,15 +1097,21 @@ void helper_fsincos(CPUX86State *env) void helper_frndint(CPUX86State *env) { + uint8_t old_flags = save_exception_flags(env); ST0 = floatx80_round_to_int(ST0, &env->fp_status); + merge_exception_flags(env, old_flags); } void helper_fscale(CPUX86State *env) { - if (floatx80_invalid_encoding(ST1)) { + uint8_t old_flags = save_exception_flags(env); + if (floatx80_invalid_encoding(ST1) || floatx80_invalid_encoding(ST0)) { float_raise(float_flag_invalid, &env->fp_status); ST0 = floatx80_default_nan(&env->fp_status); } else if (floatx80_is_any_nan(ST1)) { + if (floatx80_is_signaling_nan(ST0, &env->fp_status)) { + float_raise(float_flag_invalid, &env->fp_status); + } ST0 = ST1; if (floatx80_is_signaling_nan(ST0, &env->fp_status)) { float_raise(float_flag_invalid, &env->fp_status); @@ -1081,12 +1140,17 @@ void helper_fscale(CPUX86State *env) } } } else { - int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status); + int n; signed char save = env->fp_status.floatx80_rounding_precision; + uint8_t save_flags = get_float_exception_flags(&env->fp_status); + set_float_exception_flags(0, &env->fp_status); + n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status); + set_float_exception_flags(save_flags, &env->fp_status); env->fp_status.floatx80_rounding_precision = 80; ST0 = floatx80_scalbn(ST0, n, &env->fp_status); env->fp_status.floatx80_rounding_precision = save; } + merge_exception_flags(env, old_flags); } void helper_fsin(CPUX86State *env) diff --git a/tests/tcg/i386/test-i386-fp-exceptions.c b/tests/tcg/i386/test-i386-fp-exceptions.c new file mode 100644 index 0000000000..dfb7117c17 --- /dev/null +++ b/tests/tcg/i386/test-i386-fp-exceptions.c @@ -0,0 +1,831 @@ +/* Test floating-point exceptions. */ + +#include +#include +#include + +union u { + struct { uint64_t sig; uint16_t sign_exp; } s; + long double ld; +}; + +volatile float f_res; +volatile double d_res; +volatile long double ld_res; +volatile long double ld_res2; + +volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; +volatile float f_snan = __builtin_nansf(""); +volatile double d_snan = __builtin_nans(""); +volatile long double ld_third = 1.0L / 3.0L; +volatile long double ld_snan = __builtin_nansl(""); +volatile long double ld_nan = __builtin_nanl(""); +volatile long double ld_inf = __builtin_infl(); +volatile long double ld_ninf = -__builtin_infl(); +volatile long double ld_one = 1.0L; +volatile long double ld_zero = 0.0L; +volatile long double ld_nzero = -0.0L; +volatile long double ld_min = LDBL_MIN; +volatile long double ld_max = LDBL_MAX; +volatile long double ld_nmax = -LDBL_MAX; + +#define IE (1 << 0) +#define ZE (1 << 2) +#define OE (1 << 3) +#define UE (1 << 4) +#define PE (1 << 5) +#define EXC (IE | ZE | OE | UE | PE) + +int main(void) +{ + short sw; + unsigned char out[10]; + int ret = 0; + int16_t res_16; + int32_t res_32; + int64_t res_64; + + __asm__ volatile ("fnclex"); + ld_res = f_snan; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: widen float snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = d_snan; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: widen double snan\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + f_res = ld_min; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (UE | PE)) { + printf("FAIL: narrow float underflow\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + d_res = ld_min; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (UE | PE)) { + printf("FAIL: narrow double underflow\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + f_res = ld_max; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (OE | PE)) { + printf("FAIL: narrow float overflow\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + d_res = ld_max; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (OE | PE)) { + printf("FAIL: narrow double overflow\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + f_res = ld_third; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: narrow float inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + d_res = ld_third; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: narrow double inexact\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + f_res = ld_snan; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: narrow float snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + d_res = ld_snan; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: narrow double snan\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + f_res = ld_invalid_1.ld; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: narrow float invalid\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + d_res = ld_invalid_1.ld; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: narrow double invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("frndint" : "=t" (ld_res) : "0" (ld_min)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: frndint min\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("frndint" : "=t" (ld_res) : "0" (ld_snan)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: frndint snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("frndint" : "=t" (ld_res) : "0" (ld_invalid_1.ld)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: frndint invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("fcom" : : "t" (ld_nan), "u" (ld_zero)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fcom nan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fucom" : : "t" (ld_nan), "u" (ld_zero)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != 0) { + printf("FAIL: fucom nan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fucom" : : "t" (ld_snan), "u" (ld_zero)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fucom snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fucom" : : "t" (1.0L), "u" (ld_invalid_1.ld)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fucom invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + ld_res = ld_max + ld_max; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (OE | PE)) { + printf("FAIL: add overflow\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_max + ld_min; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: add inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_inf + ld_ninf; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: add inf -inf\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_snan + ld_third; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: add snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_third + ld_invalid_1.ld; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: add invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + ld_res = ld_max - ld_nmax; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (OE | PE)) { + printf("FAIL: sub overflow\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_max - ld_min; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: sub inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_inf - ld_inf; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: sub inf inf\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_snan - ld_third; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: sub snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_third - ld_invalid_1.ld; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: sub invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + ld_res = ld_max * ld_max; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (OE | PE)) { + printf("FAIL: mul overflow\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_third * ld_third; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: mul inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_min * ld_min; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (UE | PE)) { + printf("FAIL: mul underflow\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_inf * ld_zero; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: mul inf 0\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_snan * ld_third; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: mul snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_third * ld_invalid_1.ld; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: mul invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + ld_res = ld_max / ld_min; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (OE | PE)) { + printf("FAIL: div overflow\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_one / ld_third; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: div inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_min / ld_max; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (UE | PE)) { + printf("FAIL: div underflow\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_one / ld_zero; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != ZE) { + printf("FAIL: div 1 0\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_inf / ld_zero; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != 0) { + printf("FAIL: div inf 0\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_nan / ld_zero; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != 0) { + printf("FAIL: div nan 0\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_zero / ld_zero; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: div 0 0\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_inf / ld_inf; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: div inf inf\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_snan / ld_third; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: div snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + ld_res = ld_third / ld_invalid_1.ld; + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: div invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_max)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: fsqrt inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_nmax)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fsqrt -max\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_ninf)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fsqrt -inf\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_snan)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fsqrt snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_invalid_1.ld)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fsqrt invalid\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (ld_nzero)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != 0) { + printf("FAIL: fsqrt -0\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fsqrt" : "=t" (ld_res) : "0" (-__builtin_nanl(""))); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != 0) { + printf("FAIL: fsqrt -nan\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistp %0" : "=m" (res_16) : "t" (1.5L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: fistp inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistp %0" : "=m" (res_16) : "t" (32767.5L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistp 32767.5\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistp %0" : "=m" (res_16) : "t" (-32768.51L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistp -32768.51\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistp %0" : "=m" (res_16) : "t" (ld_nan) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistp nan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistp %0" : "=m" (res_16) : "t" (ld_invalid_1.ld) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistp invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistpl %0" : "=m" (res_32) : "t" (1.5L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: fistpl inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistpl %0" : "=m" (res_32) : "t" (2147483647.5L) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistpl 2147483647.5\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistpl %0" : "=m" (res_32) : "t" (-2147483648.51L) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistpl -2147483648.51\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistpl %0" : "=m" (res_32) : "t" (ld_nan) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistpl nan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistpl %0" : "=m" (res_32) : "t" (ld_invalid_1.ld) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistpl invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistpll %0" : "=m" (res_64) : "t" (1.5L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: fistpll inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistpll %0" : "=m" (res_64) : "t" (0x1p63) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistpll 0x1p63\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistpll %0" : "=m" (res_64) : "t" (-0x1.1p63L) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistpll -0x1.1p63\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistpll %0" : "=m" (res_64) : "t" (ld_nan) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistpll nan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fistpll %0" : "=m" (res_64) : "t" (ld_invalid_1.ld) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fistpll invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (1.5L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: fisttp inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (32768.0L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttp 32768\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (32768.5L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttp 32768.5\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (-32769.0L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttp -32769\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (-32769.5L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttp -32769.5\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (ld_nan) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttp nan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttp %0" : "=m" (res_16) : "t" (ld_invalid_1.ld) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttp invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (1.5L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: fisttpl inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (2147483648.0L) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttpl 2147483648\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (-2147483649.0L) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttpl -2147483649\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (ld_nan) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttpl nan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttpl %0" : "=m" (res_32) : "t" (ld_invalid_1.ld) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttpl invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (1.5L) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: fisttpll inexact\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (0x1p63) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttpll 0x1p63\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (-0x1.1p63L) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttpll -0x1.1p63\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (ld_nan) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttpll nan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fisttpll %0" : "=m" (res_64) : "t" (ld_invalid_1.ld) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fisttpll invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : + "0" (ld_zero)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != ZE) { + printf("FAIL: fxtract 0\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : + "0" (ld_nzero)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != ZE) { + printf("FAIL: fxtract -0\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : + "0" (ld_inf)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != 0) { + printf("FAIL: fxtract inf\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : + "0" (ld_nan)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != 0) { + printf("FAIL: fxtract nan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : + "0" (ld_snan)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fxtract snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fxtract" : "=t" (ld_res), "=u" (ld_res2) : + "0" (ld_invalid_1.ld)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fxtract invalid\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_min), "u" (ld_max)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (OE | PE)) { + printf("FAIL: fscale overflow\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_max), "u" (ld_nmax)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != (UE | PE)) { + printf("FAIL: fscale underflow\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_zero), "u" (ld_inf)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fscale 0 inf\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_inf), "u" (ld_ninf)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fscale inf -inf\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_one), "u" (ld_snan)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fscale 1 snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fscale" : "=t" (ld_res) : "0" (ld_snan), "u" (ld_nan)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fscale snan nan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (ld_invalid_1.ld), "u" (ld_one)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fscale invalid 1\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fscale" : "=t" (ld_res) : + "0" (ld_invalid_1.ld), "u" (ld_nan)); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fscale invalid nan\n"); + ret = 1; + } + + __asm__ volatile ("fnclex"); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (1.5L) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != PE) { + printf("FAIL: fbstp 1.5\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (999999999999999999.5L) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fbstp 999999999999999999.5\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-1000000000000000000.0L) : + "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fbstp -1000000000000000000\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_inf) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fbstp inf\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_nan) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fbstp nan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_snan) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fbstp snan\n"); + ret = 1; + } + __asm__ volatile ("fnclex"); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (ld_invalid_1.ld) : "st"); + __asm__ volatile ("fnstsw" : "=a" (sw)); + if ((sw & EXC) != IE) { + printf("FAIL: fbstp invalid\n"); + ret = 1; + } + + return ret; +} From 5c4fe018c025740fef4a0a4421e8162db0c3eefd Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 8 Jun 2020 13:26:37 -0500 Subject: [PATCH 1110/2595] nbd/server: Avoid long error message assertions CVE-2020-10761 Ever since commit 36683283 (v2.8), the server code asserts that error strings sent to the client are well-formed per the protocol by not exceeding the maximum string length of 4096. At the time the server first started sending error messages, the assertion could not be triggered, because messages were completely under our control. However, over the years, we have added latent scenarios where a client could trigger the server to attempt an error message that would include the client's information if it passed other checks first: - requesting NBD_OPT_INFO/GO on an export name that is not present (commit 0cfae925 in v2.12 echoes the name) - requesting NBD_OPT_LIST/SET_META_CONTEXT on an export name that is not present (commit e7b1948d in v2.12 echoes the name) At the time, those were still safe because we flagged names larger than 256 bytes with a different message; but that changed in commit 93676c88 (v4.2) when we raised the name limit to 4096 to match the NBD string limit. (That commit also failed to change the magic number 4096 in nbd_negotiate_send_rep_err to the just-introduced named constant.) So with that commit, long client names appended to server text can now trigger the assertion, and thus be used as a denial of service attack against a server. As a mitigating factor, if the server requires TLS, the client cannot trigger the problematic paths unless it first supplies TLS credentials, and such trusted clients are less likely to try to intentionally crash the server. We may later want to further sanitize the user-supplied strings we place into our error messages, such as scrubbing out control characters, but that is less important to the CVE fix, so it can be a later patch to the new nbd_sanitize_name. Consideration was given to changing the assertion in nbd_negotiate_send_rep_verr to instead merely log a server error and truncate the message, to avoid leaving a latent path that could trigger a future CVE DoS on any new error message. However, this merely complicates the code for something that is already (correctly) flagging coding errors, and now that we are aware of the long message pitfall, we are less likely to introduce such errors in the future, which would make such error handling dead code. Reported-by: Xueqiang Wei CC: qemu-stable@nongnu.org Fixes: https://bugzilla.redhat.com/1843684 CVE-2020-10761 Fixes: 93676c88d7 Signed-off-by: Eric Blake Message-Id: <20200610163741.3745251-2-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- nbd/server.c | 23 ++++++++++++++++++++--- tests/qemu-iotests/143 | 4 ++++ tests/qemu-iotests/143.out | 2 ++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index 02b1ed0801..20754e9ebc 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -217,7 +217,7 @@ nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type, msg = g_strdup_vprintf(fmt, va); len = strlen(msg); - assert(len < 4096); + assert(len < NBD_MAX_STRING_SIZE); trace_nbd_negotiate_send_rep_err(msg); ret = nbd_negotiate_send_rep_len(client, type, len, errp); if (ret < 0) { @@ -231,6 +231,19 @@ nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type, return 0; } +/* + * Return a malloc'd copy of @name suitable for use in an error reply. + */ +static char * +nbd_sanitize_name(const char *name) +{ + if (strnlen(name, 80) < 80) { + return g_strdup(name); + } + /* XXX Should we also try to sanitize any control characters? */ + return g_strdup_printf("%.80s...", name); +} + /* Send an error reply. * Return -errno on error, 0 on success. */ static int GCC_FMT_ATTR(4, 5) @@ -595,9 +608,11 @@ static int nbd_negotiate_handle_info(NBDClient *client, Error **errp) exp = nbd_export_find(name); if (!exp) { + g_autofree char *sane_name = nbd_sanitize_name(name); + return nbd_negotiate_send_rep_err(client, NBD_REP_ERR_UNKNOWN, errp, "export '%s' not present", - name); + sane_name); } /* Don't bother sending NBD_INFO_NAME unless client requested it */ @@ -995,8 +1010,10 @@ static int nbd_negotiate_meta_queries(NBDClient *client, meta->exp = nbd_export_find(export_name); if (meta->exp == NULL) { + g_autofree char *sane_name = nbd_sanitize_name(export_name); + return nbd_opt_drop(client, NBD_REP_ERR_UNKNOWN, errp, - "export '%s' not present", export_name); + "export '%s' not present", sane_name); } ret = nbd_opt_read(client, &nb_queries, sizeof(nb_queries), errp); diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143 index f649b36195..d2349903b1 100755 --- a/tests/qemu-iotests/143 +++ b/tests/qemu-iotests/143 @@ -58,6 +58,10 @@ _send_qemu_cmd $QEMU_HANDLE \ $QEMU_IO_PROG -f raw -c quit \ "nbd+unix:///no_such_export?socket=$SOCK_DIR/nbd" 2>&1 \ | _filter_qemu_io | _filter_nbd +# Likewise, with longest possible name permitted in NBD protocol +$QEMU_IO_PROG -f raw -c quit \ + "nbd+unix:///$(printf %4096d 1 | tr ' ' a)?socket=$SOCK_DIR/nbd" 2>&1 \ + | _filter_qemu_io | _filter_nbd | sed 's/aaaa*aa/aa--aa/' _send_qemu_cmd $QEMU_HANDLE \ "{ 'execute': 'quit' }" \ diff --git a/tests/qemu-iotests/143.out b/tests/qemu-iotests/143.out index 1f4001c601..fc9c0a761f 100644 --- a/tests/qemu-iotests/143.out +++ b/tests/qemu-iotests/143.out @@ -5,6 +5,8 @@ QA output created by 143 {"return": {}} qemu-io: can't open device nbd+unix:///no_such_export?socket=SOCK_DIR/nbd: Requested export not available server reported: export 'no_such_export' not present +qemu-io: can't open device nbd+unix:///aa--aa1?socket=SOCK_DIR/nbd: Requested export not available +server reported: export 'aa--aa...' not present { 'execute': 'quit' } {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} From 5c86bdf1208916ece0b87e1151c9b48ee54faa3e Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 8 Jun 2020 13:26:38 -0500 Subject: [PATCH 1111/2595] block: Call attention to truncation of long NBD exports Commit 93676c88 relaxed our NBD client code to request export names up to the NBD protocol maximum of 4096 bytes without NUL terminator, even though the block layer can't store anything longer than 4096 bytes including NUL terminator for display to the user. Since this means there are some export names where we have to truncate things, we can at least try to make the truncation a bit more obvious for the user. Note that in spite of the truncated display name, we can still communicate with an NBD server using such a long export name; this was deemed nicer than refusing to even connect to such a server (since the server may not be under our control, and since determining our actual length limits gets tricky when nbd://host:port/export and nbd+unix:///export?socket=/path are themselves variable-length expansions beyond the export name but count towards the block layer name length). Reported-by: Xueqiang Wei Fixes: https://bugzilla.redhat.com/1843684 Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200610163741.3745251-3-eblake@redhat.com> --- block.c | 7 +++++-- block/nbd.c | 21 +++++++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/block.c b/block.c index 8416376c9b..6dbcb7e083 100644 --- a/block.c +++ b/block.c @@ -6809,8 +6809,11 @@ void bdrv_refresh_filename(BlockDriverState *bs) pstrcpy(bs->filename, sizeof(bs->filename), bs->exact_filename); } else { QString *json = qobject_to_json(QOBJECT(bs->full_open_options)); - snprintf(bs->filename, sizeof(bs->filename), "json:%s", - qstring_get_str(json)); + if (snprintf(bs->filename, sizeof(bs->filename), "json:%s", + qstring_get_str(json)) >= sizeof(bs->filename)) { + /* Give user a hint if we truncated things. */ + strcpy(bs->filename + sizeof(bs->filename) - 4, "..."); + } qobject_unref(json); } } diff --git a/block/nbd.c b/block/nbd.c index 4ac23c8f62..eed160c5cd 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1984,6 +1984,7 @@ static void nbd_refresh_filename(BlockDriverState *bs) { BDRVNBDState *s = bs->opaque; const char *host = NULL, *port = NULL, *path = NULL; + size_t len = 0; if (s->saddr->type == SOCKET_ADDRESS_TYPE_INET) { const InetSocketAddress *inet = &s->saddr->u.inet; @@ -1996,17 +1997,21 @@ static void nbd_refresh_filename(BlockDriverState *bs) } /* else can't represent as pseudo-filename */ if (path && s->export) { - snprintf(bs->exact_filename, sizeof(bs->exact_filename), - "nbd+unix:///%s?socket=%s", s->export, path); + len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), + "nbd+unix:///%s?socket=%s", s->export, path); } else if (path && !s->export) { - snprintf(bs->exact_filename, sizeof(bs->exact_filename), - "nbd+unix://?socket=%s", path); + len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), + "nbd+unix://?socket=%s", path); } else if (host && s->export) { - snprintf(bs->exact_filename, sizeof(bs->exact_filename), - "nbd://%s:%s/%s", host, port, s->export); + len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), + "nbd://%s:%s/%s", host, port, s->export); } else if (host && !s->export) { - snprintf(bs->exact_filename, sizeof(bs->exact_filename), - "nbd://%s:%s", host, port); + len = snprintf(bs->exact_filename, sizeof(bs->exact_filename), + "nbd://%s:%s", host, port); + } + if (len > sizeof(bs->exact_filename)) { + /* Name is too long to represent exactly, so leave it empty. */ + bs->exact_filename[0] = '\0'; } } From ee7932b0bba2062a0fad1e70d576ef13c4906c83 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Thu, 11 Jun 2020 11:36:39 -0600 Subject: [PATCH 1112/2595] hw/vfio: Add VMD Passthrough Quirk The VMD endpoint provides a real PCIe domain to the guest, including bridges and endpoints. Because the VMD domain is enumerated by the guest kernel, the guest kernel will assign Guest Physical Addresses to the downstream endpoint BARs and bridge windows. When the guest kernel performs MMIO to VMD sub-devices, MMU will translate from the guest address space to the physical address space. Because the bridges have been programmed with guest addresses, the bridges will reject the transaction containing physical addresses. VMD device 28C0 natively assists passthrough by providing the Host Physical Address in shadow registers accessible to the guest for bridge window assignment. The shadow registers are valid if bit 1 is set in VMD VMLOCK config register 0x70. In order to support existing VMDs, this quirk provides the shadow registers in a vendor-specific PCI capability to the vfio-passthrough device for all VMD device ids which don't natively assist with passthrough. The Linux VMD driver is updated to check for this new vendor-specific capability. Signed-off-by: Jon Derrick Signed-off-by: Alex Williamson --- hw/vfio/pci-quirks.c | 84 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index f2155ddb1d..a1e615c54e 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1567,18 +1567,6 @@ static int vfio_add_nv_gpudirect_cap(VFIOPCIDevice *vdev, Error **errp) return 0; } -int vfio_add_virt_caps(VFIOPCIDevice *vdev, Error **errp) -{ - int ret; - - ret = vfio_add_nv_gpudirect_cap(vdev, errp); - if (ret) { - return ret; - } - - return 0; -} - static void vfio_pci_nvlink2_get_tgt(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -1709,3 +1697,75 @@ free_exit: return ret; } + +/* + * The VMD endpoint provides a real PCIe domain to the guest and the guest + * kernel performs enumeration of the VMD sub-device domain. Guest transactions + * to VMD sub-devices go through MMU translation from guest addresses to + * physical addresses. When MMIO goes to an endpoint after being translated to + * physical addresses, the bridge rejects the transaction because the window + * has been programmed with guest addresses. + * + * VMD can use the Host Physical Address in order to correctly program the + * bridge windows in its PCIe domain. VMD device 28C0 has HPA shadow registers + * located at offset 0x2000 in MEMBAR2 (BAR 4). This quirk provides the HPA + * shadow registers in a vendor-specific capability register for devices + * without native support. The position of 0xE8-0xFF is in the reserved range + * of the VMD device capability space following the Power Management + * Capability. + */ +#define VMD_SHADOW_CAP_VER 1 +#define VMD_SHADOW_CAP_LEN 24 +static int vfio_add_vmd_shadow_cap(VFIOPCIDevice *vdev, Error **errp) +{ + uint8_t membar_phys[16]; + int ret, pos = 0xE8; + + if (!(vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, 0x201D) || + vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, 0x467F) || + vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, 0x4C3D) || + vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, 0x9A0B))) { + return 0; + } + + ret = pread(vdev->vbasedev.fd, membar_phys, 16, + vdev->config_offset + PCI_BASE_ADDRESS_2); + if (ret != 16) { + error_report("VMD %s cannot read MEMBARs (%d)", + vdev->vbasedev.name, ret); + return -EFAULT; + } + + ret = pci_add_capability(&vdev->pdev, PCI_CAP_ID_VNDR, pos, + VMD_SHADOW_CAP_LEN, errp); + if (ret < 0) { + error_prepend(errp, "Failed to add VMD MEMBAR Shadow cap: "); + return ret; + } + + memset(vdev->emulated_config_bits + pos, 0xFF, VMD_SHADOW_CAP_LEN); + pos += PCI_CAP_FLAGS; + pci_set_byte(vdev->pdev.config + pos++, VMD_SHADOW_CAP_LEN); + pci_set_byte(vdev->pdev.config + pos++, VMD_SHADOW_CAP_VER); + pci_set_long(vdev->pdev.config + pos, 0x53484457); /* SHDW */ + memcpy(vdev->pdev.config + pos + 4, membar_phys, 16); + + return 0; +} + +int vfio_add_virt_caps(VFIOPCIDevice *vdev, Error **errp) +{ + int ret; + + ret = vfio_add_nv_gpudirect_cap(vdev, errp); + if (ret) { + return ret; + } + + ret = vfio_add_vmd_shadow_cap(vdev, errp); + if (ret) { + return ret; + } + + return 0; +} From 643a4eacef87a318cf71800a4fb2ae1f78c4b245 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 11 Jun 2020 11:36:40 -0600 Subject: [PATCH 1113/2595] hw/vfio/pci-quirks: Fix broken legacy IGD passthrough MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The #ifdef CONFIG_VFIO_IGD in pci-quirks.c is not working since the required header config-devices.h is not included, so that the legacy IGD passthrough is currently broken. Let's include the right header to fix this issue. Buglink: https://bugs.launchpad.net/qemu/+bug/1882784 Fixes: 29d62771c81d ("hw/vfio: Move the IGD quirk code to a separate file") Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Williamson --- hw/vfio/pci-quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index a1e615c54e..d304c81148 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -11,6 +11,7 @@ */ #include "qemu/osdep.h" +#include "config-devices.h" #include "exec/memop.h" #include "qemu/units.h" #include "qemu/error-report.h" From 6b0eff1a4ea47c835a7d8bee88c05c47ada37495 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 21 May 2020 05:00:32 +0000 Subject: [PATCH 1114/2595] Add VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change introduces a new feature to the vhost-user protocol allowing a backend device to specify the maximum number of ram slots it supports. At this point, the value returned by the backend will be capped at the maximum number of ram slots which can be supported by vhost-user, which is currently set to 8 because of underlying protocol limitations. The returned value will be stored inside the VhostUserState struct so that on device reconnect we can verify that the ram slot limitation has not decreased since the last time the device connected. Signed-off-by: Raphael Norwitz Signed-off-by: Peter Turschmid Message-Id: <1588533678-23450-4-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marc-André Lureau --- docs/interop/vhost-user.rst | 16 +++++++++++ hw/virtio/vhost-user.c | 49 ++++++++++++++++++++++++++++++++-- include/hw/virtio/vhost-user.h | 1 + 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 3b1b6602c7..b3cf5c3cb5 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -815,6 +815,7 @@ Protocol features #define VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD 12 #define VHOST_USER_PROTOCOL_F_RESET_DEVICE 13 #define VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS 14 + #define VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS 15 Master message types -------------------- @@ -1263,6 +1264,21 @@ Master message types The state.num field is currently reserved and must be set to 0. +``VHOST_USER_GET_MAX_MEM_SLOTS`` + :id: 36 + :equivalent ioctl: N/A + :slave payload: u64 + + When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol + feature has been successfully negotiated, this message is submitted + by master to the slave. The slave should return the message with a + u64 payload containing the maximum number of memory slots for + QEMU to expose to the guest. At this point, the value returned + by the backend will be capped at the maximum number of ram slots + which can be supported by vhost-user. Currently that limit is set + at VHOST_USER_MAX_RAM_SLOTS = 8 because of underlying protocol + limitations. + Slave message types ------------------- diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 442b0d650a..754ad885cf 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -59,6 +59,8 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12, VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13, + /* Feature 14 reserved for VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS. */ + VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, VHOST_USER_PROTOCOL_F_MAX }; @@ -100,6 +102,8 @@ typedef enum VhostUserRequest { VHOST_USER_SET_INFLIGHT_FD = 32, VHOST_USER_GPU_SET_SOCKET = 33, VHOST_USER_RESET_DEVICE = 34, + /* Message number 35 reserved for VHOST_USER_VRING_KICK. */ + VHOST_USER_GET_MAX_MEM_SLOTS = 36, VHOST_USER_MAX } VhostUserRequest; @@ -895,6 +899,23 @@ static int vhost_user_set_owner(struct vhost_dev *dev) return 0; } +static int vhost_user_get_max_memslots(struct vhost_dev *dev, + uint64_t *max_memslots) +{ + uint64_t backend_max_memslots; + int err; + + err = vhost_user_get_u64(dev, VHOST_USER_GET_MAX_MEM_SLOTS, + &backend_max_memslots); + if (err < 0) { + return err; + } + + *max_memslots = backend_max_memslots; + + return 0; +} + static int vhost_user_reset_device(struct vhost_dev *dev) { VhostUserMsg msg = { @@ -1392,7 +1413,7 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier, static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque) { - uint64_t features, protocol_features; + uint64_t features, protocol_features, ram_slots; struct vhost_user *u; int err; @@ -1454,6 +1475,27 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque) "slave-req protocol features."); return -1; } + + /* get max memory regions if backend supports configurable RAM slots */ + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS)) { + u->user->memory_slots = VHOST_MEMORY_MAX_NREGIONS; + } else { + err = vhost_user_get_max_memslots(dev, &ram_slots); + if (err < 0) { + return err; + } + + if (ram_slots < u->user->memory_slots) { + error_report("The backend specified a max ram slots limit " + "of %" PRIu64", when the prior validated limit was %d. " + "This limit should never decrease.", ram_slots, + u->user->memory_slots); + return -1; + } + + u->user->memory_slots = MIN(ram_slots, VHOST_MEMORY_MAX_NREGIONS); + } } if (dev->migration_blocker == NULL && @@ -1519,7 +1561,9 @@ static int vhost_user_get_vq_index(struct vhost_dev *dev, int idx) static int vhost_user_memslots_limit(struct vhost_dev *dev) { - return VHOST_MEMORY_MAX_NREGIONS; + struct vhost_user *u = dev->opaque; + + return u->user->memory_slots; } static bool vhost_user_requires_shm_log(struct vhost_dev *dev) @@ -1904,6 +1948,7 @@ bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) return false; } user->chr = chr; + user->memory_slots = 0; return true; } diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index 811e325f42..a9abca3288 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -20,6 +20,7 @@ typedef struct VhostUserHostNotifier { typedef struct VhostUserState { CharBackend *chr; VhostUserHostNotifier notifier[VIRTIO_QUEUE_MAX]; + int memory_slots; } VhostUserState; bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp); From f1aeb14b0809e313c74244d838645ed25e85ea63 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 21 May 2020 05:00:35 +0000 Subject: [PATCH 1115/2595] Transmit vhost-user memory regions individually MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this change, when the VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS protocol feature has been negotiated, Qemu no longer sends the backend all the memory regions in a single message. Rather, when the memory tables are set or updated, a series of VHOST_USER_ADD_MEM_REG and VHOST_USER_REM_MEM_REG messages are sent to transmit the regions to map and/or unmap instead of sending send all the regions in one fixed size VHOST_USER_SET_MEM_TABLE message. The vhost_user struct maintains a shadow state of the VM’s memory regions. When the memory tables are modified, the vhost_user_set_mem_table() function compares the new device memory state to the shadow state and only sends regions which need to be unmapped or mapped in. The regions which must be unmapped are sent first, followed by the new regions to be mapped in. After all the messages have been sent, the shadow state is set to the current virtual device state. Existing backends which do not support VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS are unaffected. Signed-off-by: Raphael Norwitz Signed-off-by: Swapnil Ingle Signed-off-by: Peter Turschmid Suggested-by: Mike Cui Message-Id: <1588533678-23450-5-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Marc-André Lureau --- docs/interop/vhost-user.rst | 33 ++- hw/virtio/vhost-user.c | 516 ++++++++++++++++++++++++++++++------ 2 files changed, 472 insertions(+), 77 deletions(-) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index b3cf5c3cb5..037eefab0e 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -1276,8 +1276,37 @@ Master message types QEMU to expose to the guest. At this point, the value returned by the backend will be capped at the maximum number of ram slots which can be supported by vhost-user. Currently that limit is set - at VHOST_USER_MAX_RAM_SLOTS = 8 because of underlying protocol - limitations. + at VHOST_USER_MAX_RAM_SLOTS = 8. + +``VHOST_USER_ADD_MEM_REG`` + :id: 37 + :equivalent ioctl: N/A + :slave payload: memory region + + When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol + feature has been successfully negotiated, this message is submitted + by the master to the slave. The message payload contains a memory + region descriptor struct, describing a region of guest memory which + the slave device must map in. When the + ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has + been successfully negotiated, along with the + ``VHOST_USER_REM_MEM_REG`` message, this message is used to set and + update the memory tables of the slave device. + +``VHOST_USER_REM_MEM_REG`` + :id: 38 + :equivalent ioctl: N/A + :slave payload: memory region + + When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol + feature has been successfully negotiated, this message is submitted + by the master to the slave. The message payload contains a memory + region descriptor struct, describing a region of guest memory which + the slave device must unmap. When the + ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has + been successfully negotiated, along with the + ``VHOST_USER_ADD_MEM_REG`` message, this message is used to set and + update the memory tables of the slave device. Slave message types ------------------- diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 754ad885cf..3640f017a2 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -104,6 +104,8 @@ typedef enum VhostUserRequest { VHOST_USER_RESET_DEVICE = 34, /* Message number 35 reserved for VHOST_USER_VRING_KICK. */ VHOST_USER_GET_MAX_MEM_SLOTS = 36, + VHOST_USER_ADD_MEM_REG = 37, + VHOST_USER_REM_MEM_REG = 38, VHOST_USER_MAX } VhostUserRequest; @@ -128,6 +130,11 @@ typedef struct VhostUserMemory { VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; } VhostUserMemory; +typedef struct VhostUserMemRegMsg { + uint32_t padding; + VhostUserMemoryRegion region; +} VhostUserMemRegMsg; + typedef struct VhostUserLog { uint64_t mmap_size; uint64_t mmap_offset; @@ -186,6 +193,7 @@ typedef union { struct vhost_vring_state state; struct vhost_vring_addr addr; VhostUserMemory memory; + VhostUserMemRegMsg mem_reg; VhostUserLog log; struct vhost_iotlb_msg iotlb; VhostUserConfig config; @@ -226,6 +234,16 @@ struct vhost_user { /* True once we've entered postcopy_listen */ bool postcopy_listen; + + /* Our current regions */ + int num_shadow_regions; + struct vhost_memory_region shadow_regions[VHOST_MEMORY_MAX_NREGIONS]; +}; + +struct scrub_regions { + struct vhost_memory_region *region; + int reg_idx; + int fd_idx; }; static bool ioeventfd_enabled(void) @@ -489,8 +507,332 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, return 1; } +static inline bool reg_equal(struct vhost_memory_region *shadow_reg, + struct vhost_memory_region *vdev_reg) +{ + return shadow_reg->guest_phys_addr == vdev_reg->guest_phys_addr && + shadow_reg->userspace_addr == vdev_reg->userspace_addr && + shadow_reg->memory_size == vdev_reg->memory_size; +} + +static void scrub_shadow_regions(struct vhost_dev *dev, + struct scrub_regions *add_reg, + int *nr_add_reg, + struct scrub_regions *rem_reg, + int *nr_rem_reg, uint64_t *shadow_pcb, + bool track_ramblocks) +{ + struct vhost_user *u = dev->opaque; + bool found[VHOST_MEMORY_MAX_NREGIONS] = {}; + struct vhost_memory_region *reg, *shadow_reg; + int i, j, fd, add_idx = 0, rm_idx = 0, fd_num = 0; + ram_addr_t offset; + MemoryRegion *mr; + bool matching; + + /* + * Find memory regions present in our shadow state which are not in + * the device's current memory state. + * + * Mark regions in both the shadow and device state as "found". + */ + for (i = 0; i < u->num_shadow_regions; i++) { + shadow_reg = &u->shadow_regions[i]; + matching = false; + + for (j = 0; j < dev->mem->nregions; j++) { + reg = &dev->mem->regions[j]; + + mr = vhost_user_get_mr_data(reg->userspace_addr, &offset, &fd); + + if (reg_equal(shadow_reg, reg)) { + matching = true; + found[j] = true; + if (track_ramblocks) { + /* + * Reset postcopy client bases, region_rb, and + * region_rb_offset in case regions are removed. + */ + if (fd > 0) { + u->region_rb_offset[j] = offset; + u->region_rb[j] = mr->ram_block; + shadow_pcb[j] = u->postcopy_client_bases[i]; + } else { + u->region_rb_offset[j] = 0; + u->region_rb[j] = NULL; + } + } + break; + } + } + + /* + * If the region was not found in the current device memory state + * create an entry for it in the removed list. + */ + if (!matching) { + rem_reg[rm_idx].region = shadow_reg; + rem_reg[rm_idx++].reg_idx = i; + } + } + + /* + * For regions not marked "found", create entries in the added list. + * + * Note their indexes in the device memory state and the indexes of their + * file descriptors. + */ + for (i = 0; i < dev->mem->nregions; i++) { + reg = &dev->mem->regions[i]; + mr = vhost_user_get_mr_data(reg->userspace_addr, &offset, &fd); + if (fd > 0) { + ++fd_num; + } + + /* + * If the region was in both the shadow and device state we don't + * need to send a VHOST_USER_ADD_MEM_REG message for it. + */ + if (found[i]) { + continue; + } + + add_reg[add_idx].region = reg; + add_reg[add_idx].reg_idx = i; + add_reg[add_idx++].fd_idx = fd_num; + } + *nr_rem_reg = rm_idx; + *nr_add_reg = add_idx; + + return; +} + +static int send_remove_regions(struct vhost_dev *dev, + struct scrub_regions *remove_reg, + int nr_rem_reg, VhostUserMsg *msg, + bool reply_supported) +{ + struct vhost_user *u = dev->opaque; + struct vhost_memory_region *shadow_reg; + int i, fd, shadow_reg_idx, ret; + ram_addr_t offset; + VhostUserMemoryRegion region_buffer; + + /* + * The regions in remove_reg appear in the same order they do in the + * shadow table. Therefore we can minimize memory copies by iterating + * through remove_reg backwards. + */ + for (i = nr_rem_reg - 1; i >= 0; i--) { + shadow_reg = remove_reg[i].region; + shadow_reg_idx = remove_reg[i].reg_idx; + + vhost_user_get_mr_data(shadow_reg->userspace_addr, &offset, &fd); + + if (fd > 0) { + msg->hdr.request = VHOST_USER_REM_MEM_REG; + vhost_user_fill_msg_region(®ion_buffer, shadow_reg); + msg->payload.mem_reg.region = region_buffer; + + if (vhost_user_write(dev, msg, &fd, 1) < 0) { + return -1; + } + + if (reply_supported) { + ret = process_message_reply(dev, msg); + if (ret) { + return ret; + } + } + } + + /* + * At this point we know the backend has unmapped the region. It is now + * safe to remove it from the shadow table. + */ + memmove(&u->shadow_regions[shadow_reg_idx], + &u->shadow_regions[shadow_reg_idx + 1], + sizeof(struct vhost_memory_region) * + (u->num_shadow_regions - shadow_reg_idx)); + u->num_shadow_regions--; + } + + return 0; +} + +static int send_add_regions(struct vhost_dev *dev, + struct scrub_regions *add_reg, int nr_add_reg, + VhostUserMsg *msg, uint64_t *shadow_pcb, + bool reply_supported, bool track_ramblocks) +{ + struct vhost_user *u = dev->opaque; + int i, fd, ret, reg_idx, reg_fd_idx; + struct vhost_memory_region *reg; + MemoryRegion *mr; + ram_addr_t offset; + VhostUserMsg msg_reply; + VhostUserMemoryRegion region_buffer; + + for (i = 0; i < nr_add_reg; i++) { + reg = add_reg[i].region; + reg_idx = add_reg[i].reg_idx; + reg_fd_idx = add_reg[i].fd_idx; + + mr = vhost_user_get_mr_data(reg->userspace_addr, &offset, &fd); + + if (fd > 0) { + if (track_ramblocks) { + trace_vhost_user_set_mem_table_withfd(reg_fd_idx, mr->name, + reg->memory_size, + reg->guest_phys_addr, + reg->userspace_addr, + offset); + u->region_rb_offset[reg_idx] = offset; + u->region_rb[reg_idx] = mr->ram_block; + } + msg->hdr.request = VHOST_USER_ADD_MEM_REG; + vhost_user_fill_msg_region(®ion_buffer, reg); + msg->payload.mem_reg.region = region_buffer; + msg->payload.mem_reg.region.mmap_offset = offset; + + if (vhost_user_write(dev, msg, &fd, 1) < 0) { + return -1; + } + + if (track_ramblocks) { + uint64_t reply_gpa; + + if (vhost_user_read(dev, &msg_reply) < 0) { + return -1; + } + + reply_gpa = msg_reply.payload.mem_reg.region.guest_phys_addr; + + if (msg_reply.hdr.request != VHOST_USER_ADD_MEM_REG) { + error_report("%s: Received unexpected msg type." + "Expected %d received %d", __func__, + VHOST_USER_ADD_MEM_REG, + msg_reply.hdr.request); + return -1; + } + + /* + * We're using the same structure, just reusing one of the + * fields, so it should be the same size. + */ + if (msg_reply.hdr.size != msg->hdr.size) { + error_report("%s: Unexpected size for postcopy reply " + "%d vs %d", __func__, msg_reply.hdr.size, + msg->hdr.size); + return -1; + } + + /* Get the postcopy client base from the backend's reply. */ + if (reply_gpa == dev->mem->regions[reg_idx].guest_phys_addr) { + shadow_pcb[reg_idx] = + msg_reply.payload.mem_reg.region.userspace_addr; + trace_vhost_user_set_mem_table_postcopy( + msg_reply.payload.mem_reg.region.userspace_addr, + msg->payload.mem_reg.region.userspace_addr, + reg_fd_idx, reg_idx); + } else { + error_report("%s: invalid postcopy reply for region. " + "Got guest physical address %" PRIX64 ", expected " + "%" PRIX64, __func__, reply_gpa, + dev->mem->regions[reg_idx].guest_phys_addr); + return -1; + } + } else if (reply_supported) { + ret = process_message_reply(dev, msg); + if (ret) { + return ret; + } + } + } else if (track_ramblocks) { + u->region_rb_offset[reg_idx] = 0; + u->region_rb[reg_idx] = NULL; + } + + /* + * At this point, we know the backend has mapped in the new + * region, if the region has a valid file descriptor. + * + * The region should now be added to the shadow table. + */ + u->shadow_regions[u->num_shadow_regions].guest_phys_addr = + reg->guest_phys_addr; + u->shadow_regions[u->num_shadow_regions].userspace_addr = + reg->userspace_addr; + u->shadow_regions[u->num_shadow_regions].memory_size = + reg->memory_size; + u->num_shadow_regions++; + } + + return 0; +} + +static int vhost_user_add_remove_regions(struct vhost_dev *dev, + VhostUserMsg *msg, + bool reply_supported, + bool track_ramblocks) +{ + struct vhost_user *u = dev->opaque; + struct scrub_regions add_reg[VHOST_MEMORY_MAX_NREGIONS]; + struct scrub_regions rem_reg[VHOST_MEMORY_MAX_NREGIONS]; + uint64_t shadow_pcb[VHOST_MEMORY_MAX_NREGIONS] = {}; + int nr_add_reg, nr_rem_reg; + + msg->hdr.size = sizeof(msg->payload.mem_reg.padding) + + sizeof(VhostUserMemoryRegion); + + /* Find the regions which need to be removed or added. */ + scrub_shadow_regions(dev, add_reg, &nr_add_reg, rem_reg, &nr_rem_reg, + shadow_pcb, track_ramblocks); + + if (nr_rem_reg && send_remove_regions(dev, rem_reg, nr_rem_reg, msg, + reply_supported) < 0) + { + goto err; + } + + if (nr_add_reg && send_add_regions(dev, add_reg, nr_add_reg, msg, + shadow_pcb, reply_supported, track_ramblocks) < 0) + { + goto err; + } + + if (track_ramblocks) { + memcpy(u->postcopy_client_bases, shadow_pcb, + sizeof(uint64_t) * VHOST_MEMORY_MAX_NREGIONS); + /* + * Now we've registered this with the postcopy code, we ack to the + * client, because now we're in the position to be able to deal with + * any faults it generates. + */ + /* TODO: Use this for failure cases as well with a bad value. */ + msg->hdr.size = sizeof(msg->payload.u64); + msg->payload.u64 = 0; /* OK */ + + if (vhost_user_write(dev, msg, NULL, 0) < 0) { + return -1; + } + } + + return 0; + +err: + if (track_ramblocks) { + memcpy(u->postcopy_client_bases, shadow_pcb, + sizeof(uint64_t) * VHOST_MEMORY_MAX_NREGIONS); + } + + return -1; +} + static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, - struct vhost_memory *mem) + struct vhost_memory *mem, + bool reply_supported, + bool config_mem_slots) { struct vhost_user *u = dev->opaque; int fds[VHOST_MEMORY_MAX_NREGIONS]; @@ -513,71 +855,84 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, u->region_rb_len = dev->mem->nregions; } - if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, + if (config_mem_slots) { + if (vhost_user_add_remove_regions(dev, &msg, reply_supported, true) < 0) { - return -1; - } - - if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { - return -1; - } - - if (vhost_user_read(dev, &msg_reply) < 0) { - return -1; - } - - if (msg_reply.hdr.request != VHOST_USER_SET_MEM_TABLE) { - error_report("%s: Received unexpected msg type." - "Expected %d received %d", __func__, - VHOST_USER_SET_MEM_TABLE, msg_reply.hdr.request); - return -1; - } - /* We're using the same structure, just reusing one of the - * fields, so it should be the same size. - */ - if (msg_reply.hdr.size != msg.hdr.size) { - error_report("%s: Unexpected size for postcopy reply " - "%d vs %d", __func__, msg_reply.hdr.size, msg.hdr.size); - return -1; - } - - memset(u->postcopy_client_bases, 0, - sizeof(uint64_t) * VHOST_MEMORY_MAX_NREGIONS); - - /* They're in the same order as the regions that were sent - * but some of the regions were skipped (above) if they - * didn't have fd's - */ - for (msg_i = 0, region_i = 0; - region_i < dev->mem->nregions; - region_i++) { - if (msg_i < fd_num && - msg_reply.payload.memory.regions[msg_i].guest_phys_addr == - dev->mem->regions[region_i].guest_phys_addr) { - u->postcopy_client_bases[region_i] = - msg_reply.payload.memory.regions[msg_i].userspace_addr; - trace_vhost_user_set_mem_table_postcopy( - msg_reply.payload.memory.regions[msg_i].userspace_addr, - msg.payload.memory.regions[msg_i].userspace_addr, - msg_i, region_i); - msg_i++; + return -1; + } + } else { + if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, + true) < 0) { + return -1; + } + + if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { + return -1; + } + + if (vhost_user_read(dev, &msg_reply) < 0) { + return -1; + } + + if (msg_reply.hdr.request != VHOST_USER_SET_MEM_TABLE) { + error_report("%s: Received unexpected msg type." + "Expected %d received %d", __func__, + VHOST_USER_SET_MEM_TABLE, msg_reply.hdr.request); + return -1; + } + + /* + * We're using the same structure, just reusing one of the + * fields, so it should be the same size. + */ + if (msg_reply.hdr.size != msg.hdr.size) { + error_report("%s: Unexpected size for postcopy reply " + "%d vs %d", __func__, msg_reply.hdr.size, + msg.hdr.size); + return -1; + } + + memset(u->postcopy_client_bases, 0, + sizeof(uint64_t) * VHOST_MEMORY_MAX_NREGIONS); + + /* + * They're in the same order as the regions that were sent + * but some of the regions were skipped (above) if they + * didn't have fd's + */ + for (msg_i = 0, region_i = 0; + region_i < dev->mem->nregions; + region_i++) { + if (msg_i < fd_num && + msg_reply.payload.memory.regions[msg_i].guest_phys_addr == + dev->mem->regions[region_i].guest_phys_addr) { + u->postcopy_client_bases[region_i] = + msg_reply.payload.memory.regions[msg_i].userspace_addr; + trace_vhost_user_set_mem_table_postcopy( + msg_reply.payload.memory.regions[msg_i].userspace_addr, + msg.payload.memory.regions[msg_i].userspace_addr, + msg_i, region_i); + msg_i++; + } + } + if (msg_i != fd_num) { + error_report("%s: postcopy reply not fully consumed " + "%d vs %zd", + __func__, msg_i, fd_num); + return -1; + } + + /* + * Now we've registered this with the postcopy code, we ack to the + * client, because now we're in the position to be able to deal + * with any faults it generates. + */ + /* TODO: Use this for failure cases as well with a bad value. */ + msg.hdr.size = sizeof(msg.payload.u64); + msg.payload.u64 = 0; /* OK */ + if (vhost_user_write(dev, &msg, NULL, 0) < 0) { + return -1; } - } - if (msg_i != fd_num) { - error_report("%s: postcopy reply not fully consumed " - "%d vs %zd", - __func__, msg_i, fd_num); - return -1; - } - /* Now we've registered this with the postcopy code, we ack to the client, - * because now we're in the position to be able to deal with any faults - * it generates. - */ - /* TODO: Use this for failure cases as well with a bad value */ - msg.hdr.size = sizeof(msg.payload.u64); - msg.payload.u64 = 0; /* OK */ - if (vhost_user_write(dev, &msg, NULL, 0) < 0) { - return -1; } return 0; @@ -592,12 +947,17 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, bool do_postcopy = u->postcopy_listen && u->postcopy_fd.handler; bool reply_supported = virtio_has_feature(dev->protocol_features, VHOST_USER_PROTOCOL_F_REPLY_ACK); + bool config_mem_slots = + virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS); if (do_postcopy) { - /* Postcopy has enough differences that it's best done in it's own + /* + * Postcopy has enough differences that it's best done in it's own * version */ - return vhost_user_set_mem_table_postcopy(dev, mem); + return vhost_user_set_mem_table_postcopy(dev, mem, reply_supported, + config_mem_slots); } VhostUserMsg msg = { @@ -608,17 +968,23 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; } - if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, + if (config_mem_slots) { + if (vhost_user_add_remove_regions(dev, &msg, reply_supported, false) < 0) { - return -1; - } + return -1; + } + } else { + if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, + false) < 0) { + return -1; + } + if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { + return -1; + } - if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { - return -1; - } - - if (reply_supported) { - return process_message_reply(dev, &msg); + if (reply_supported) { + return process_message_reply(dev, &msg); + } } return 0; From 27598393a23215cfbf92ad550b9541675b0b8f2b Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 21 May 2020 05:00:40 +0000 Subject: [PATCH 1116/2595] Lift max memory slots limit imposed by vhost-user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Historically, sending all memory regions to vhost-user backends in a single message imposed a limitation on the number of times memory could be hot-added to a VM with a vhost-user device. Now that backends which support the VHOST_USER_PROTOCOL_F_CONFIGURE_SLOTS send memory regions individually, we no longer need to impose this limitation on devices which support this feature. With this change, VMs with a vhost-user device which supports the VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS can support a configurable number of memory slots, up to the maximum allowed by the target platform. Existing backends which do not support VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS are unaffected. Signed-off-by: Raphael Norwitz Signed-off-by: Peter Turschmid Suggested-by: Mike Cui Message-Id: <1588533678-23450-6-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marc-André Lureau --- docs/interop/vhost-user.rst | 7 ++--- hw/virtio/vhost-user.c | 56 ++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index 037eefab0e..688b7c6900 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -1273,10 +1273,9 @@ Master message types feature has been successfully negotiated, this message is submitted by master to the slave. The slave should return the message with a u64 payload containing the maximum number of memory slots for - QEMU to expose to the guest. At this point, the value returned - by the backend will be capped at the maximum number of ram slots - which can be supported by vhost-user. Currently that limit is set - at VHOST_USER_MAX_RAM_SLOTS = 8. + QEMU to expose to the guest. The value returned by the backend + will be capped at the maximum number of ram slots which can be + supported by the target platform. ``VHOST_USER_ADD_MEM_REG`` :id: 37 diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 3640f017a2..4d6cd4e58a 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -35,10 +35,28 @@ #include #endif -#define VHOST_MEMORY_MAX_NREGIONS 8 +#define VHOST_MEMORY_BASELINE_NREGIONS 8 #define VHOST_USER_F_PROTOCOL_FEATURES 30 #define VHOST_USER_SLAVE_MAX_FDS 8 +/* + * Set maximum number of RAM slots supported to + * the maximum number supported by the target + * hardware plaform. + */ +#if defined(TARGET_X86) || defined(TARGET_X86_64) || \ + defined(TARGET_ARM) || defined(TARGET_ARM_64) +#include "hw/acpi/acpi.h" +#define VHOST_USER_MAX_RAM_SLOTS ACPI_MAX_RAM_SLOTS + +#elif defined(TARGET_PPC) || defined(TARGET_PPC_64) +#include "hw/ppc/spapr.h" +#define VHOST_USER_MAX_RAM_SLOTS SPAPR_MAX_RAM_SLOTS + +#else +#define VHOST_USER_MAX_RAM_SLOTS 512 +#endif + /* * Maximum size of virtio device config space */ @@ -127,7 +145,7 @@ typedef struct VhostUserMemoryRegion { typedef struct VhostUserMemory { uint32_t nregions; uint32_t padding; - VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; + VhostUserMemoryRegion regions[VHOST_MEMORY_BASELINE_NREGIONS]; } VhostUserMemory; typedef struct VhostUserMemRegMsg { @@ -222,7 +240,7 @@ struct vhost_user { int slave_fd; NotifierWithReturn postcopy_notifier; struct PostCopyFD postcopy_fd; - uint64_t postcopy_client_bases[VHOST_MEMORY_MAX_NREGIONS]; + uint64_t postcopy_client_bases[VHOST_USER_MAX_RAM_SLOTS]; /* Length of the region_rb and region_rb_offset arrays */ size_t region_rb_len; /* RAMBlock associated with a given region */ @@ -237,7 +255,7 @@ struct vhost_user { /* Our current regions */ int num_shadow_regions; - struct vhost_memory_region shadow_regions[VHOST_MEMORY_MAX_NREGIONS]; + struct vhost_memory_region shadow_regions[VHOST_USER_MAX_RAM_SLOTS]; }; struct scrub_regions { @@ -392,7 +410,7 @@ int vhost_user_gpu_set_socket(struct vhost_dev *dev, int fd) static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, struct vhost_log *log) { - int fds[VHOST_MEMORY_MAX_NREGIONS]; + int fds[VHOST_USER_MAX_RAM_SLOTS]; size_t fd_num = 0; bool shmfd = virtio_has_feature(dev->protocol_features, VHOST_USER_PROTOCOL_F_LOG_SHMFD); @@ -470,7 +488,7 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, mr = vhost_user_get_mr_data(reg->userspace_addr, &offset, &fd); if (fd > 0) { if (track_ramblocks) { - assert(*fd_num < VHOST_MEMORY_MAX_NREGIONS); + assert(*fd_num < VHOST_MEMORY_BASELINE_NREGIONS); trace_vhost_user_set_mem_table_withfd(*fd_num, mr->name, reg->memory_size, reg->guest_phys_addr, @@ -478,7 +496,7 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, offset); u->region_rb_offset[i] = offset; u->region_rb[i] = mr->ram_block; - } else if (*fd_num == VHOST_MEMORY_MAX_NREGIONS) { + } else if (*fd_num == VHOST_MEMORY_BASELINE_NREGIONS) { error_report("Failed preparing vhost-user memory table msg"); return -1; } @@ -523,7 +541,7 @@ static void scrub_shadow_regions(struct vhost_dev *dev, bool track_ramblocks) { struct vhost_user *u = dev->opaque; - bool found[VHOST_MEMORY_MAX_NREGIONS] = {}; + bool found[VHOST_USER_MAX_RAM_SLOTS] = {}; struct vhost_memory_region *reg, *shadow_reg; int i, j, fd, add_idx = 0, rm_idx = 0, fd_num = 0; ram_addr_t offset; @@ -777,9 +795,9 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev, bool track_ramblocks) { struct vhost_user *u = dev->opaque; - struct scrub_regions add_reg[VHOST_MEMORY_MAX_NREGIONS]; - struct scrub_regions rem_reg[VHOST_MEMORY_MAX_NREGIONS]; - uint64_t shadow_pcb[VHOST_MEMORY_MAX_NREGIONS] = {}; + struct scrub_regions add_reg[VHOST_USER_MAX_RAM_SLOTS]; + struct scrub_regions rem_reg[VHOST_USER_MAX_RAM_SLOTS]; + uint64_t shadow_pcb[VHOST_USER_MAX_RAM_SLOTS] = {}; int nr_add_reg, nr_rem_reg; msg->hdr.size = sizeof(msg->payload.mem_reg.padding) + @@ -803,7 +821,7 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev, if (track_ramblocks) { memcpy(u->postcopy_client_bases, shadow_pcb, - sizeof(uint64_t) * VHOST_MEMORY_MAX_NREGIONS); + sizeof(uint64_t) * VHOST_USER_MAX_RAM_SLOTS); /* * Now we've registered this with the postcopy code, we ack to the * client, because now we're in the position to be able to deal with @@ -823,7 +841,7 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev, err: if (track_ramblocks) { memcpy(u->postcopy_client_bases, shadow_pcb, - sizeof(uint64_t) * VHOST_MEMORY_MAX_NREGIONS); + sizeof(uint64_t) * VHOST_USER_MAX_RAM_SLOTS); } return -1; @@ -835,7 +853,7 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, bool config_mem_slots) { struct vhost_user *u = dev->opaque; - int fds[VHOST_MEMORY_MAX_NREGIONS]; + int fds[VHOST_MEMORY_BASELINE_NREGIONS]; size_t fd_num = 0; VhostUserMsg msg_reply; int region_i, msg_i; @@ -893,7 +911,7 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, } memset(u->postcopy_client_bases, 0, - sizeof(uint64_t) * VHOST_MEMORY_MAX_NREGIONS); + sizeof(uint64_t) * VHOST_USER_MAX_RAM_SLOTS); /* * They're in the same order as the regions that were sent @@ -942,7 +960,7 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, struct vhost_memory *mem) { struct vhost_user *u = dev->opaque; - int fds[VHOST_MEMORY_MAX_NREGIONS]; + int fds[VHOST_MEMORY_BASELINE_NREGIONS]; size_t fd_num = 0; bool do_postcopy = u->postcopy_listen && u->postcopy_fd.handler; bool reply_supported = virtio_has_feature(dev->protocol_features, @@ -1149,7 +1167,7 @@ static int vhost_set_vring_file(struct vhost_dev *dev, VhostUserRequest request, struct vhost_vring_file *file) { - int fds[VHOST_MEMORY_MAX_NREGIONS]; + int fds[VHOST_USER_MAX_RAM_SLOTS]; size_t fd_num = 0; VhostUserMsg msg = { .hdr.request = request, @@ -1845,7 +1863,7 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque) /* get max memory regions if backend supports configurable RAM slots */ if (!virtio_has_feature(dev->protocol_features, VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS)) { - u->user->memory_slots = VHOST_MEMORY_MAX_NREGIONS; + u->user->memory_slots = VHOST_MEMORY_BASELINE_NREGIONS; } else { err = vhost_user_get_max_memslots(dev, &ram_slots); if (err < 0) { @@ -1860,7 +1878,7 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque) return -1; } - u->user->memory_slots = MIN(ram_slots, VHOST_MEMORY_MAX_NREGIONS); + u->user->memory_slots = MIN(ram_slots, VHOST_USER_MAX_RAM_SLOTS); } } From 08fccf8f077397b47c740d4850cdeedc947f21ac Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 21 May 2020 05:00:47 +0000 Subject: [PATCH 1117/2595] Refactor out libvhost-user fault generation logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In libvhost-user, the incoming postcopy migration path for setting the backend's memory tables has become convolued. In particular, moving the logic which starts generating faults, having received the final ACK from qemu can be moved to a separate function. This simplifies the code substantially. This logic will also be needed by the postcopy path once the VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS feature is supported. Signed-off-by: Raphael Norwitz Message-Id: <1588533678-23450-7-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marc-André Lureau --- contrib/libvhost-user/libvhost-user.c | 147 ++++++++++++++------------ 1 file changed, 79 insertions(+), 68 deletions(-) diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index 3bca996c62..cccfa22209 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -583,6 +583,84 @@ map_ring(VuDev *dev, VuVirtq *vq) return !(vq->vring.desc && vq->vring.used && vq->vring.avail); } +static bool +generate_faults(VuDev *dev) { + int i; + for (i = 0; i < dev->nregions; i++) { + VuDevRegion *dev_region = &dev->regions[i]; + int ret; +#ifdef UFFDIO_REGISTER + /* + * We should already have an open ufd. Mark each memory + * range as ufd. + * Discard any mapping we have here; note I can't use MADV_REMOVE + * or fallocate to make the hole since I don't want to lose + * data that's already arrived in the shared process. + * TODO: How to do hugepage + */ + ret = madvise((void *)(uintptr_t)dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, + MADV_DONTNEED); + if (ret) { + fprintf(stderr, + "%s: Failed to madvise(DONTNEED) region %d: %s\n", + __func__, i, strerror(errno)); + } + /* + * Turn off transparent hugepages so we dont get lose wakeups + * in neighbouring pages. + * TODO: Turn this backon later. + */ + ret = madvise((void *)(uintptr_t)dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, + MADV_NOHUGEPAGE); + if (ret) { + /* + * Note: This can happen legally on kernels that are configured + * without madvise'able hugepages + */ + fprintf(stderr, + "%s: Failed to madvise(NOHUGEPAGE) region %d: %s\n", + __func__, i, strerror(errno)); + } + struct uffdio_register reg_struct; + reg_struct.range.start = (uintptr_t)dev_region->mmap_addr; + reg_struct.range.len = dev_region->size + dev_region->mmap_offset; + reg_struct.mode = UFFDIO_REGISTER_MODE_MISSING; + + if (ioctl(dev->postcopy_ufd, UFFDIO_REGISTER, ®_struct)) { + vu_panic(dev, "%s: Failed to userfault region %d " + "@%p + size:%zx offset: %zx: (ufd=%d)%s\n", + __func__, i, + dev_region->mmap_addr, + dev_region->size, dev_region->mmap_offset, + dev->postcopy_ufd, strerror(errno)); + return false; + } + if (!(reg_struct.ioctls & ((__u64)1 << _UFFDIO_COPY))) { + vu_panic(dev, "%s Region (%d) doesn't support COPY", + __func__, i); + return false; + } + DPRINT("%s: region %d: Registered userfault for %" + PRIx64 " + %" PRIx64 "\n", __func__, i, + (uint64_t)reg_struct.range.start, + (uint64_t)reg_struct.range.len); + /* Now it's registered we can let the client at it */ + if (mprotect((void *)(uintptr_t)dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, + PROT_READ | PROT_WRITE)) { + vu_panic(dev, "failed to mprotect region %d for postcopy (%s)", + i, strerror(errno)); + return false; + } + /* TODO: Stash 'zero' support flags somewhere */ +#endif + } + + return true; +} + static bool vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg) { @@ -655,74 +733,7 @@ vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg) } /* OK, now we can go and register the memory and generate faults */ - for (i = 0; i < dev->nregions; i++) { - VuDevRegion *dev_region = &dev->regions[i]; - int ret; -#ifdef UFFDIO_REGISTER - /* We should already have an open ufd. Mark each memory - * range as ufd. - * Discard any mapping we have here; note I can't use MADV_REMOVE - * or fallocate to make the hole since I don't want to lose - * data that's already arrived in the shared process. - * TODO: How to do hugepage - */ - ret = madvise((void *)(uintptr_t)dev_region->mmap_addr, - dev_region->size + dev_region->mmap_offset, - MADV_DONTNEED); - if (ret) { - fprintf(stderr, - "%s: Failed to madvise(DONTNEED) region %d: %s\n", - __func__, i, strerror(errno)); - } - /* Turn off transparent hugepages so we dont get lose wakeups - * in neighbouring pages. - * TODO: Turn this backon later. - */ - ret = madvise((void *)(uintptr_t)dev_region->mmap_addr, - dev_region->size + dev_region->mmap_offset, - MADV_NOHUGEPAGE); - if (ret) { - /* Note: This can happen legally on kernels that are configured - * without madvise'able hugepages - */ - fprintf(stderr, - "%s: Failed to madvise(NOHUGEPAGE) region %d: %s\n", - __func__, i, strerror(errno)); - } - struct uffdio_register reg_struct; - reg_struct.range.start = (uintptr_t)dev_region->mmap_addr; - reg_struct.range.len = dev_region->size + dev_region->mmap_offset; - reg_struct.mode = UFFDIO_REGISTER_MODE_MISSING; - - if (ioctl(dev->postcopy_ufd, UFFDIO_REGISTER, ®_struct)) { - vu_panic(dev, "%s: Failed to userfault region %d " - "@%p + size:%zx offset: %zx: (ufd=%d)%s\n", - __func__, i, - dev_region->mmap_addr, - dev_region->size, dev_region->mmap_offset, - dev->postcopy_ufd, strerror(errno)); - return false; - } - if (!(reg_struct.ioctls & ((__u64)1 << _UFFDIO_COPY))) { - vu_panic(dev, "%s Region (%d) doesn't support COPY", - __func__, i); - return false; - } - DPRINT("%s: region %d: Registered userfault for %" - PRIx64 " + %" PRIx64 "\n", __func__, i, - (uint64_t)reg_struct.range.start, - (uint64_t)reg_struct.range.len); - /* Now it's registered we can let the client at it */ - if (mprotect((void *)(uintptr_t)dev_region->mmap_addr, - dev_region->size + dev_region->mmap_offset, - PROT_READ | PROT_WRITE)) { - vu_panic(dev, "failed to mprotect region %d for postcopy (%s)", - i, strerror(errno)); - return false; - } - /* TODO: Stash 'zero' support flags somewhere */ -#endif - } + (void)generate_faults(dev); return false; } From 6fb2e173d20c9bbb5466183d33a3ad7dcd0375fa Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 21 May 2020 05:00:50 +0000 Subject: [PATCH 1118/2595] Support ram slot configuration in libvhost-user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VHOST_USER_GET_MAX_MEM_SLOTS message allows a vhost-user backend to specify a maximum number of ram slots it is willing to support. This change adds support for libvhost-user to process this message. For now the backend will reply with 8 as the maximum number of regions supported. libvhost-user does not yet support the vhost-user protocol feature VHOST_USER_PROTOCOL_F_CONFIGIRE_MEM_SLOTS, so qemu should never send the VHOST_USER_GET_MAX_MEM_SLOTS message. Therefore this new functionality is not currently used. Signed-off-by: Raphael Norwitz Message-Id: <1588533678-23450-8-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marc-André Lureau --- contrib/libvhost-user/libvhost-user.c | 19 +++++++++++++++++++ contrib/libvhost-user/libvhost-user.h | 1 + 2 files changed, 20 insertions(+) diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index cccfa22209..9f039b707e 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -137,6 +137,7 @@ vu_request_to_string(unsigned int req) REQ(VHOST_USER_SET_INFLIGHT_FD), REQ(VHOST_USER_GPU_SET_SOCKET), REQ(VHOST_USER_VRING_KICK), + REQ(VHOST_USER_GET_MAX_MEM_SLOTS), REQ(VHOST_USER_MAX), }; #undef REQ @@ -1565,6 +1566,22 @@ vu_handle_vring_kick(VuDev *dev, VhostUserMsg *vmsg) return false; } +static bool vu_handle_get_max_memslots(VuDev *dev, VhostUserMsg *vmsg) +{ + vmsg->flags = VHOST_USER_REPLY_MASK | VHOST_USER_VERSION; + vmsg->size = sizeof(vmsg->payload.u64); + vmsg->payload.u64 = VHOST_MEMORY_MAX_NREGIONS; + vmsg->fd_num = 0; + + if (!vu_message_write(dev, dev->sock, vmsg)) { + vu_panic(dev, "Failed to send max ram slots: %s\n", strerror(errno)); + } + + DPRINT("u64: 0x%016"PRIx64"\n", (uint64_t) VHOST_MEMORY_MAX_NREGIONS); + + return false; +} + static bool vu_process_message(VuDev *dev, VhostUserMsg *vmsg) { @@ -1649,6 +1666,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg) return vu_set_inflight_fd(dev, vmsg); case VHOST_USER_VRING_KICK: return vu_handle_vring_kick(dev, vmsg); + case VHOST_USER_GET_MAX_MEM_SLOTS: + return vu_handle_get_max_memslots(dev, vmsg); default: vmsg_close_fds(vmsg); vu_panic(dev, "Unhandled request: %d", vmsg->request); diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h index f30394fab6..88ef40d26a 100644 --- a/contrib/libvhost-user/libvhost-user.h +++ b/contrib/libvhost-user/libvhost-user.h @@ -97,6 +97,7 @@ typedef enum VhostUserRequest { VHOST_USER_SET_INFLIGHT_FD = 32, VHOST_USER_GPU_SET_SOCKET = 33, VHOST_USER_VRING_KICK = 35, + VHOST_USER_GET_MAX_MEM_SLOTS = 36, VHOST_USER_MAX } VhostUserRequest; From ec94c8e621de96c50c2d381c8c9ec94f5beec7c1 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 21 May 2020 05:00:52 +0000 Subject: [PATCH 1119/2595] Support adding individual regions in libvhost-user When the VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS is enabled, qemu will transmit memory regions to a backend individually using the new message VHOST_USER_ADD_MEM_REG. With this change vhost-user backends built with libvhost-user can now map in new memory regions when VHOST_USER_ADD_MEM_REG messages are received. Qemu only sends VHOST_USER_ADD_MEM_REG messages when the VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS feature is negotiated, and since it is not yet supported in libvhost-user, this new functionality is not yet used. Signed-off-by: Raphael Norwitz Message-Id: <1588533678-23450-9-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- contrib/libvhost-user/libvhost-user.c | 103 ++++++++++++++++++++++++++ contrib/libvhost-user/libvhost-user.h | 7 ++ 2 files changed, 110 insertions(+) diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index 9f039b707e..d8ee7a23a3 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -138,6 +138,7 @@ vu_request_to_string(unsigned int req) REQ(VHOST_USER_GPU_SET_SOCKET), REQ(VHOST_USER_VRING_KICK), REQ(VHOST_USER_GET_MAX_MEM_SLOTS), + REQ(VHOST_USER_ADD_MEM_REG), REQ(VHOST_USER_MAX), }; #undef REQ @@ -662,6 +663,106 @@ generate_faults(VuDev *dev) { return true; } +static bool +vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { + int i; + bool track_ramblocks = dev->postcopy_listening; + VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m; + VuDevRegion *dev_region = &dev->regions[dev->nregions]; + void *mmap_addr; + + /* + * If we are in postcopy mode and we receive a u64 payload with a 0 value + * we know all the postcopy client bases have been recieved, and we + * should start generating faults. + */ + if (track_ramblocks && + vmsg->size == sizeof(vmsg->payload.u64) && + vmsg->payload.u64 == 0) { + (void)generate_faults(dev); + return false; + } + + DPRINT("Adding region: %d\n", dev->nregions); + DPRINT(" guest_phys_addr: 0x%016"PRIx64"\n", + msg_region->guest_phys_addr); + DPRINT(" memory_size: 0x%016"PRIx64"\n", + msg_region->memory_size); + DPRINT(" userspace_addr 0x%016"PRIx64"\n", + msg_region->userspace_addr); + DPRINT(" mmap_offset 0x%016"PRIx64"\n", + msg_region->mmap_offset); + + dev_region->gpa = msg_region->guest_phys_addr; + dev_region->size = msg_region->memory_size; + dev_region->qva = msg_region->userspace_addr; + dev_region->mmap_offset = msg_region->mmap_offset; + + /* + * We don't use offset argument of mmap() since the + * mapped address has to be page aligned, and we use huge + * pages. + */ + if (track_ramblocks) { + /* + * In postcopy we're using PROT_NONE here to catch anyone + * accessing it before we userfault. + */ + mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset, + PROT_NONE, MAP_SHARED, + vmsg->fds[0], 0); + } else { + mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset, + PROT_READ | PROT_WRITE, MAP_SHARED, vmsg->fds[0], + 0); + } + + if (mmap_addr == MAP_FAILED) { + vu_panic(dev, "region mmap error: %s", strerror(errno)); + } else { + dev_region->mmap_addr = (uint64_t)(uintptr_t)mmap_addr; + DPRINT(" mmap_addr: 0x%016"PRIx64"\n", + dev_region->mmap_addr); + } + + close(vmsg->fds[0]); + + if (track_ramblocks) { + /* + * Return the address to QEMU so that it can translate the ufd + * fault addresses back. + */ + msg_region->userspace_addr = (uintptr_t)(mmap_addr + + dev_region->mmap_offset); + + /* Send the message back to qemu with the addresses filled in. */ + vmsg->fd_num = 0; + if (!vu_send_reply(dev, dev->sock, vmsg)) { + vu_panic(dev, "failed to respond to add-mem-region for postcopy"); + return false; + } + + DPRINT("Successfully added new region in postcopy\n"); + dev->nregions++; + return false; + + } else { + for (i = 0; i < dev->max_queues; i++) { + if (dev->vq[i].vring.desc) { + if (map_ring(dev, &dev->vq[i])) { + vu_panic(dev, "remapping queue %d for new memory region", + i); + } + } + } + + DPRINT("Successfully added new region\n"); + dev->nregions++; + vmsg_set_reply_u64(vmsg, 0); + return true; + } +} + static bool vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg) { @@ -1668,6 +1769,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg) return vu_handle_vring_kick(dev, vmsg); case VHOST_USER_GET_MAX_MEM_SLOTS: return vu_handle_get_max_memslots(dev, vmsg); + case VHOST_USER_ADD_MEM_REG: + return vu_add_mem_reg(dev, vmsg); default: vmsg_close_fds(vmsg); vu_panic(dev, "Unhandled request: %d", vmsg->request); diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h index 88ef40d26a..60ef7fd13e 100644 --- a/contrib/libvhost-user/libvhost-user.h +++ b/contrib/libvhost-user/libvhost-user.h @@ -98,6 +98,7 @@ typedef enum VhostUserRequest { VHOST_USER_GPU_SET_SOCKET = 33, VHOST_USER_VRING_KICK = 35, VHOST_USER_GET_MAX_MEM_SLOTS = 36, + VHOST_USER_ADD_MEM_REG = 37, VHOST_USER_MAX } VhostUserRequest; @@ -124,6 +125,11 @@ typedef struct VhostUserMemory { VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; } VhostUserMemory; +typedef struct VhostUserMemRegMsg { + uint32_t padding; + VhostUserMemoryRegion region; +} VhostUserMemRegMsg; + typedef struct VhostUserLog { uint64_t mmap_size; uint64_t mmap_offset; @@ -176,6 +182,7 @@ typedef struct VhostUserMsg { struct vhost_vring_state state; struct vhost_vring_addr addr; VhostUserMemory memory; + VhostUserMemRegMsg memreg; VhostUserLog log; VhostUserConfig config; VhostUserVringArea area; From 875b9fd97b34dae796d61330804b094ca7b1b403 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 21 May 2020 05:00:56 +0000 Subject: [PATCH 1120/2595] Support individual region unmap in libvhost-user When the VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS protocol feature is enabled, on memory hot-unplug qemu will transmit memory regions to remove individually using the new message VHOST_USER_REM_MEM_REG message. With this change, vhost-user backends build with libvhost-user can now unmap individual memory regions when receiving the VHOST_USER_REM_MEM_REG message. Qemu only sends VHOST_USER_REM_MEM_REG messages when the VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS feature is negotiated, and support for that feature has not yet been added in libvhost-user, this new functionality is not yet used. Signed-off-by: Raphael Norwitz Message-Id: <1588533678-23450-10-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- contrib/libvhost-user/libvhost-user.c | 63 +++++++++++++++++++++++++++ contrib/libvhost-user/libvhost-user.h | 1 + 2 files changed, 64 insertions(+) diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index d8ee7a23a3..386449b697 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -139,6 +139,7 @@ vu_request_to_string(unsigned int req) REQ(VHOST_USER_VRING_KICK), REQ(VHOST_USER_GET_MAX_MEM_SLOTS), REQ(VHOST_USER_ADD_MEM_REG), + REQ(VHOST_USER_REM_MEM_REG), REQ(VHOST_USER_MAX), }; #undef REQ @@ -763,6 +764,66 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { } } +static inline bool reg_equal(VuDevRegion *vudev_reg, + VhostUserMemoryRegion *msg_reg) +{ + if (vudev_reg->gpa == msg_reg->guest_phys_addr && + vudev_reg->qva == msg_reg->userspace_addr && + vudev_reg->size == msg_reg->memory_size) { + return true; + } + + return false; +} + +static bool +vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { + int i, j; + bool found = false; + VuDevRegion shadow_regions[VHOST_MEMORY_MAX_NREGIONS] = {}; + VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m; + + DPRINT("Removing region:\n"); + DPRINT(" guest_phys_addr: 0x%016"PRIx64"\n", + msg_region->guest_phys_addr); + DPRINT(" memory_size: 0x%016"PRIx64"\n", + msg_region->memory_size); + DPRINT(" userspace_addr 0x%016"PRIx64"\n", + msg_region->userspace_addr); + DPRINT(" mmap_offset 0x%016"PRIx64"\n", + msg_region->mmap_offset); + + for (i = 0, j = 0; i < dev->nregions; i++) { + if (!reg_equal(&dev->regions[i], msg_region)) { + shadow_regions[j].gpa = dev->regions[i].gpa; + shadow_regions[j].size = dev->regions[i].size; + shadow_regions[j].qva = dev->regions[i].qva; + shadow_regions[j].mmap_offset = dev->regions[i].mmap_offset; + j++; + } else { + found = true; + VuDevRegion *r = &dev->regions[i]; + void *m = (void *) (uintptr_t) r->mmap_addr; + + if (m) { + munmap(m, r->size + r->mmap_offset); + } + } + } + + if (found) { + memcpy(dev->regions, shadow_regions, + sizeof(VuDevRegion) * VHOST_MEMORY_MAX_NREGIONS); + DPRINT("Successfully removed a region\n"); + dev->nregions--; + vmsg_set_reply_u64(vmsg, 0); + } else { + vu_panic(dev, "Specified region not found\n"); + } + + return true; +} + static bool vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg) { @@ -1771,6 +1832,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg) return vu_handle_get_max_memslots(dev, vmsg); case VHOST_USER_ADD_MEM_REG: return vu_add_mem_reg(dev, vmsg); + case VHOST_USER_REM_MEM_REG: + return vu_rem_mem_reg(dev, vmsg); default: vmsg_close_fds(vmsg); vu_panic(dev, "Unhandled request: %d", vmsg->request); diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h index 60ef7fd13e..f8439713a8 100644 --- a/contrib/libvhost-user/libvhost-user.h +++ b/contrib/libvhost-user/libvhost-user.h @@ -99,6 +99,7 @@ typedef enum VhostUserRequest { VHOST_USER_VRING_KICK = 35, VHOST_USER_GET_MAX_MEM_SLOTS = 36, VHOST_USER_ADD_MEM_REG = 37, + VHOST_USER_REM_MEM_REG = 38, VHOST_USER_MAX } VhostUserRequest; From b650d5f4b1cd3f9f8c4fdb319838c5c1e0695e41 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 21 May 2020 05:00:59 +0000 Subject: [PATCH 1121/2595] Lift max ram slots limit in libvhost-user Historically, VMs with vhost-user devices could hot-add memory a maximum of 8 times. Now that the VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS protocol feature has been added, VMs with vhost-user backends which support this new feature can support a configurable number of ram slots up to the maximum supported by the target platform. This change adds VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS support for backends built with libvhost-user, and increases the number of supported ram slots from 8 to 32. Memory hot-add, hot-remove and postcopy migration were tested with the vhost-user-bridge sample. Signed-off-by: Raphael Norwitz Message-Id: <1588533678-23450-11-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- contrib/libvhost-user/libvhost-user.c | 17 +++++++++-------- contrib/libvhost-user/libvhost-user.h | 15 +++++++++++---- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index 386449b697..b1e607298c 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -269,7 +269,7 @@ have_userfault(void) static bool vu_message_read(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) { - char control[CMSG_SPACE(VHOST_MEMORY_MAX_NREGIONS * sizeof(int))] = { }; + char control[CMSG_SPACE(VHOST_MEMORY_BASELINE_NREGIONS * sizeof(int))] = {}; struct iovec iov = { .iov_base = (char *)vmsg, .iov_len = VHOST_USER_HDR_SIZE, @@ -340,7 +340,7 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) { int rc; uint8_t *p = (uint8_t *)vmsg; - char control[CMSG_SPACE(VHOST_MEMORY_MAX_NREGIONS * sizeof(int))] = { }; + char control[CMSG_SPACE(VHOST_MEMORY_BASELINE_NREGIONS * sizeof(int))] = {}; struct iovec iov = { .iov_base = (char *)vmsg, .iov_len = VHOST_USER_HDR_SIZE, @@ -353,7 +353,7 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) struct cmsghdr *cmsg; memset(control, 0, sizeof(control)); - assert(vmsg->fd_num <= VHOST_MEMORY_MAX_NREGIONS); + assert(vmsg->fd_num <= VHOST_MEMORY_BASELINE_NREGIONS); if (vmsg->fd_num > 0) { size_t fdsize = vmsg->fd_num * sizeof(int); msg.msg_controllen = CMSG_SPACE(fdsize); @@ -780,7 +780,7 @@ static bool vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { int i, j; bool found = false; - VuDevRegion shadow_regions[VHOST_MEMORY_MAX_NREGIONS] = {}; + VuDevRegion shadow_regions[VHOST_USER_MAX_RAM_SLOTS] = {}; VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m; DPRINT("Removing region:\n"); @@ -813,7 +813,7 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { if (found) { memcpy(dev->regions, shadow_regions, - sizeof(VuDevRegion) * VHOST_MEMORY_MAX_NREGIONS); + sizeof(VuDevRegion) * VHOST_USER_MAX_RAM_SLOTS); DPRINT("Successfully removed a region\n"); dev->nregions--; vmsg_set_reply_u64(vmsg, 0); @@ -1394,7 +1394,8 @@ vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg) 1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ | 1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER | 1ULL << VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD | - 1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK; + 1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK | + 1ULL << VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS; if (have_userfault()) { features |= 1ULL << VHOST_USER_PROTOCOL_F_PAGEFAULT; @@ -1732,14 +1733,14 @@ static bool vu_handle_get_max_memslots(VuDev *dev, VhostUserMsg *vmsg) { vmsg->flags = VHOST_USER_REPLY_MASK | VHOST_USER_VERSION; vmsg->size = sizeof(vmsg->payload.u64); - vmsg->payload.u64 = VHOST_MEMORY_MAX_NREGIONS; + vmsg->payload.u64 = VHOST_USER_MAX_RAM_SLOTS; vmsg->fd_num = 0; if (!vu_message_write(dev, dev->sock, vmsg)) { vu_panic(dev, "Failed to send max ram slots: %s\n", strerror(errno)); } - DPRINT("u64: 0x%016"PRIx64"\n", (uint64_t) VHOST_MEMORY_MAX_NREGIONS); + DPRINT("u64: 0x%016"PRIx64"\n", (uint64_t) VHOST_USER_MAX_RAM_SLOTS); return false; } diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h index f8439713a8..844c37c648 100644 --- a/contrib/libvhost-user/libvhost-user.h +++ b/contrib/libvhost-user/libvhost-user.h @@ -28,7 +28,13 @@ #define VIRTQUEUE_MAX_SIZE 1024 -#define VHOST_MEMORY_MAX_NREGIONS 8 +#define VHOST_MEMORY_BASELINE_NREGIONS 8 + +/* + * Set a reasonable maximum number of ram slots, which will be supported by + * any architecture. + */ +#define VHOST_USER_MAX_RAM_SLOTS 32 typedef enum VhostSetConfigType { VHOST_SET_CONFIG_TYPE_MASTER = 0, @@ -55,6 +61,7 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12, VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14, + VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, VHOST_USER_PROTOCOL_F_MAX }; @@ -123,7 +130,7 @@ typedef struct VhostUserMemoryRegion { typedef struct VhostUserMemory { uint32_t nregions; uint32_t padding; - VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; + VhostUserMemoryRegion regions[VHOST_MEMORY_BASELINE_NREGIONS]; } VhostUserMemory; typedef struct VhostUserMemRegMsg { @@ -190,7 +197,7 @@ typedef struct VhostUserMsg { VhostUserInflight inflight; } payload; - int fds[VHOST_MEMORY_MAX_NREGIONS]; + int fds[VHOST_MEMORY_BASELINE_NREGIONS]; int fd_num; uint8_t *data; } VU_PACKED VhostUserMsg; @@ -368,7 +375,7 @@ typedef struct VuDevInflightInfo { struct VuDev { int sock; uint32_t nregions; - VuDevRegion regions[VHOST_MEMORY_MAX_NREGIONS]; + VuDevRegion regions[VHOST_USER_MAX_RAM_SLOTS]; VuVirtq *vq; VuDevInflightInfo inflight_info; int log_call_fd; From a9a5c473d25d83bcdad27d97e5fb451950ee894a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 29 May 2020 17:13:38 +0100 Subject: [PATCH 1122/2595] libvhost-user: advertise vring features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libvhost-user implements several vring features without advertising them. There is no way for the vhost-user master to detect support for these features. Things more or less work today because QEMU assumes the vhost-user backend always implements certain feature bits like VIRTIO_RING_F_EVENT_IDX. This is not documented anywhere. This patch explicitly advertises features implemented in libvhost-user so that the vhost-user master does not need to make undocumented assumptions. Feature bits that libvhost-user now advertises can be removed from vhost-user-blk.c. Devices should not be responsible for advertising vring feature bits, that is libvhost-user's job. Cc: Marc-André Lureau Cc: Jason Wang Cc: Michael S. Tsirkin Signed-off-by: Stefan Hajnoczi Message-Id: <20200529161338.456017-1-stefanha@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marc-André Lureau --- contrib/libvhost-user/libvhost-user.c | 10 ++++++++++ contrib/vhost-user-blk/vhost-user-blk.c | 4 +--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index b1e607298c..d315db1396 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -498,6 +498,16 @@ static bool vu_get_features_exec(VuDev *dev, VhostUserMsg *vmsg) { vmsg->payload.u64 = + /* + * The following VIRTIO feature bits are supported by our virtqueue + * implementation: + */ + 1ULL << VIRTIO_F_NOTIFY_ON_EMPTY | + 1ULL << VIRTIO_RING_F_INDIRECT_DESC | + 1ULL << VIRTIO_RING_F_EVENT_IDX | + 1ULL << VIRTIO_F_VERSION_1 | + + /* vhost-user feature bits */ 1ULL << VHOST_F_LOG_ALL | 1ULL << VHOST_USER_F_PROTOCOL_FEATURES; diff --git a/contrib/vhost-user-blk/vhost-user-blk.c b/contrib/vhost-user-blk/vhost-user-blk.c index 6fd91c7e99..25eccd02b5 100644 --- a/contrib/vhost-user-blk/vhost-user-blk.c +++ b/contrib/vhost-user-blk/vhost-user-blk.c @@ -382,9 +382,7 @@ vub_get_features(VuDev *dev) 1ull << VIRTIO_BLK_F_DISCARD | 1ull << VIRTIO_BLK_F_WRITE_ZEROES | #endif - 1ull << VIRTIO_BLK_F_CONFIG_WCE | - 1ull << VIRTIO_F_VERSION_1 | - 1ull << VHOST_USER_F_PROTOCOL_FEATURES; + 1ull << VIRTIO_BLK_F_CONFIG_WCE; if (vdev_blk->enable_ro) { features |= 1ull << VIRTIO_BLK_F_RO; From 00823980b296c80a3ff7b448df20c48897cd62e9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 27 May 2020 17:31:52 +0200 Subject: [PATCH 1123/2595] hw/pci: Fix crash when running QEMU with "-nic model=rocker" QEMU currently aborts when being started with "-nic model=rocker" or with "-net nic,model=rocker". This happens because the "rocker" device is not a normal NIC but a switch, which has different properties. Thus we should only consider real NIC devices for "-nic" and "-net". These devices can be identified by the "netdev" property, so check for this property before adding the device to the list. Reported-by: Michael Tokarev Fixes: 52310c3fa7dc854d ("net: allow using any PCI NICs in -net or -nic") Signed-off-by: Thomas Huth Message-Id: <20200527153152.9211-1-thuth@redhat.com> Reviewed-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 7bf2ae6d92..1b88a32cf7 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1891,7 +1891,18 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, if (test_bit(DEVICE_CATEGORY_NETWORK, dc->categories) && dc->user_creatable) { const char *name = object_class_get_name(list->data); - g_ptr_array_add(pci_nic_models, (gpointer)name); + /* + * A network device might also be something else than a NIC, see + * e.g. the "rocker" device. Thus we have to look for the "netdev" + * property, too. Unfortunately, some devices like virtio-net only + * create this property during instance_init, so we have to create + * a temporary instance here to be able to check it. + */ + Object *obj = object_new_with_class(OBJECT_CLASS(dc)); + if (object_property_find(obj, "netdev", NULL)) { + g_ptr_array_add(pci_nic_models, (gpointer)name); + } + object_unref(obj); } next = list->next; g_slist_free_1(list); From c6136ec0c6fea0db638de08720018fd4bc777787 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Fri, 22 May 2020 14:25:10 +0200 Subject: [PATCH 1124/2595] vhost-vsock: add vhost-vsock-common abstraction This patch prepares the introduction of vhost-user-vsock, moving the common code usable for both vhost-vsock and vhost-user-vsock devices, in the new vhost-vsock-common parent class. While moving the code, fixed checkpatch warnings about block comments. Signed-off-by: Stefano Garzarella Message-Id: <20200522122512.87413-2-sgarzare@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 2 +- hw/virtio/vhost-vsock-common.c | 258 ++++++++++++++++++++++ hw/virtio/vhost-vsock.c | 283 ++++--------------------- include/hw/virtio/vhost-vsock-common.h | 47 ++++ include/hw/virtio/vhost-vsock.h | 11 +- 5 files changed, 350 insertions(+), 251 deletions(-) create mode 100644 hw/virtio/vhost-vsock-common.c create mode 100644 include/hw/virtio/vhost-vsock-common.h diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 4e4d39a0a4..b1eeb44eac 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -17,7 +17,7 @@ obj-$(CONFIG_VIRTIO_PMEM) += virtio-pmem.o common-obj-$(call land,$(CONFIG_VIRTIO_PMEM),$(CONFIG_VIRTIO_PCI)) += virtio-pmem-pci.o obj-$(call land,$(CONFIG_VHOST_USER_FS),$(CONFIG_VIRTIO_PCI)) += vhost-user-fs-pci.o obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o -obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o +obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-common.o vhost-vsock.o ifeq ($(CONFIG_VIRTIO_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c new file mode 100644 index 0000000000..5b2ebf3496 --- /dev/null +++ b/hw/virtio/vhost-vsock-common.c @@ -0,0 +1,258 @@ +/* + * Parent class for vhost-vsock devices + * + * Copyright 2015-2020 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" +#include "standard-headers/linux/virtio_vsock.h" +#include "qapi/error.h" +#include "hw/virtio/virtio-access.h" +#include "qemu/error-report.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/vhost-vsock.h" +#include "qemu/iov.h" +#include "monitor/monitor.h" + +int vhost_vsock_common_start(VirtIODevice *vdev) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int ret; + int i; + + if (!k->set_guest_notifiers) { + error_report("binding does not support guest notifiers"); + return -ENOSYS; + } + + ret = vhost_dev_enable_notifiers(&vvc->vhost_dev, vdev); + if (ret < 0) { + error_report("Error enabling host notifiers: %d", -ret); + return ret; + } + + ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, true); + if (ret < 0) { + error_report("Error binding guest notifier: %d", -ret); + goto err_host_notifiers; + } + + vvc->vhost_dev.acked_features = vdev->guest_features; + ret = vhost_dev_start(&vvc->vhost_dev, vdev); + if (ret < 0) { + error_report("Error starting vhost: %d", -ret); + goto err_guest_notifiers; + } + + /* + * guest_notifier_mask/pending not used yet, so just unmask + * everything here. virtio-pci will do the right thing by + * enabling/disabling irqfd. + */ + for (i = 0; i < vvc->vhost_dev.nvqs; i++) { + vhost_virtqueue_mask(&vvc->vhost_dev, vdev, i, false); + } + + return 0; + +err_guest_notifiers: + k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false); +err_host_notifiers: + vhost_dev_disable_notifiers(&vvc->vhost_dev, vdev); + return ret; +} + +void vhost_vsock_common_stop(VirtIODevice *vdev) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int ret; + + if (!k->set_guest_notifiers) { + return; + } + + vhost_dev_stop(&vvc->vhost_dev, vdev); + + ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false); + if (ret < 0) { + error_report("vhost guest notifier cleanup failed: %d", ret); + return; + } + + vhost_dev_disable_notifiers(&vvc->vhost_dev, vdev); +} + + +static void vhost_vsock_common_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + /* Do nothing */ +} + +static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, + bool mask) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + + vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); +} + +static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, + int idx) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + + return vhost_virtqueue_pending(&vvc->vhost_dev, idx); +} + +static void vhost_vsock_common_send_transport_reset(VHostVSockCommon *vvc) +{ + VirtQueueElement *elem; + VirtQueue *vq = vvc->event_vq; + struct virtio_vsock_event event = { + .id = cpu_to_le32(VIRTIO_VSOCK_EVENT_TRANSPORT_RESET), + }; + + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + error_report("vhost-vsock missed transport reset event"); + return; + } + + if (elem->out_num) { + error_report("invalid vhost-vsock event virtqueue element with " + "out buffers"); + goto out; + } + + if (iov_from_buf(elem->in_sg, elem->in_num, 0, + &event, sizeof(event)) != sizeof(event)) { + error_report("vhost-vsock event virtqueue element is too short"); + goto out; + } + + virtqueue_push(vq, elem, sizeof(event)); + virtio_notify(VIRTIO_DEVICE(vvc), vq); + +out: + g_free(elem); +} + +static void vhost_vsock_common_post_load_timer_cleanup(VHostVSockCommon *vvc) +{ + if (!vvc->post_load_timer) { + return; + } + + timer_del(vvc->post_load_timer); + timer_free(vvc->post_load_timer); + vvc->post_load_timer = NULL; +} + +static void vhost_vsock_common_post_load_timer_cb(void *opaque) +{ + VHostVSockCommon *vvc = opaque; + + vhost_vsock_common_post_load_timer_cleanup(vvc); + vhost_vsock_common_send_transport_reset(vvc); +} + +int vhost_vsock_common_pre_save(void *opaque) +{ + VHostVSockCommon *vvc = opaque; + + /* + * At this point, backend must be stopped, otherwise + * it might keep writing to memory. + */ + assert(!vvc->vhost_dev.started); + + return 0; +} + +int vhost_vsock_common_post_load(void *opaque, int version_id) +{ + VHostVSockCommon *vvc = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(vvc); + + if (virtio_queue_get_addr(vdev, 2)) { + /* + * Defer transport reset event to a vm clock timer so that virtqueue + * changes happen after migration has completed. + */ + assert(!vvc->post_load_timer); + vvc->post_load_timer = + timer_new_ns(QEMU_CLOCK_VIRTUAL, + vhost_vsock_common_post_load_timer_cb, + vvc); + timer_mod(vvc->post_load_timer, 1); + } + return 0; +} + +void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + + virtio_init(vdev, name, VIRTIO_ID_VSOCK, + sizeof(struct virtio_vsock_config)); + + /* Receive and transmit queues belong to vhost */ + vvc->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, + vhost_vsock_common_handle_output); + vvc->trans_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, + vhost_vsock_common_handle_output); + + /* The event queue belongs to QEMU */ + vvc->event_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, + vhost_vsock_common_handle_output); + + vvc->vhost_dev.nvqs = ARRAY_SIZE(vvc->vhost_vqs); + vvc->vhost_dev.vqs = vvc->vhost_vqs; + + vvc->post_load_timer = NULL; +} + +void vhost_vsock_common_unrealize(VirtIODevice *vdev) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + + vhost_vsock_common_post_load_timer_cleanup(vvc); + + virtio_delete_queue(vvc->recv_vq); + virtio_delete_queue(vvc->trans_vq); + virtio_delete_queue(vvc->event_vq); + virtio_cleanup(vdev); +} + +static void vhost_vsock_common_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + vdc->guest_notifier_mask = vhost_vsock_common_guest_notifier_mask; + vdc->guest_notifier_pending = vhost_vsock_common_guest_notifier_pending; +} + +static const TypeInfo vhost_vsock_common_info = { + .name = TYPE_VHOST_VSOCK_COMMON, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VHostVSockCommon), + .class_init = vhost_vsock_common_class_init, + .abstract = true, +}; + +static void vhost_vsock_common_register_types(void) +{ + type_register_static(&vhost_vsock_common_info); +} + +type_init(vhost_vsock_common_register_types) diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index 4a228f5168..c8f0699b4f 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -12,24 +12,14 @@ */ #include "qemu/osdep.h" -#include #include "standard-headers/linux/virtio_vsock.h" #include "qapi/error.h" -#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost-vsock.h" -#include "qemu/iov.h" -#include "qemu/module.h" #include "monitor/monitor.h" -enum { - VHOST_VSOCK_SAVEVM_VERSION = 0, - - VHOST_VSOCK_QUEUE_SIZE = 128, -}; - static void vhost_vsock_get_config(VirtIODevice *vdev, uint8_t *config) { VHostVSock *vsock = VHOST_VSOCK(vdev); @@ -39,16 +29,18 @@ static void vhost_vsock_get_config(VirtIODevice *vdev, uint8_t *config) memcpy(config, &vsockcfg, sizeof(vsockcfg)); } -static int vhost_vsock_set_guest_cid(VHostVSock *vsock) +static int vhost_vsock_set_guest_cid(VirtIODevice *vdev) { - const VhostOps *vhost_ops = vsock->vhost_dev.vhost_ops; + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + VHostVSock *vsock = VHOST_VSOCK(vdev); + const VhostOps *vhost_ops = vvc->vhost_dev.vhost_ops; int ret; if (!vhost_ops->vhost_vsock_set_guest_cid) { return -ENOSYS; } - ret = vhost_ops->vhost_vsock_set_guest_cid(&vsock->vhost_dev, + ret = vhost_ops->vhost_vsock_set_guest_cid(&vvc->vhost_dev, vsock->conf.guest_cid); if (ret < 0) { return -errno; @@ -56,123 +48,58 @@ static int vhost_vsock_set_guest_cid(VHostVSock *vsock) return 0; } -static int vhost_vsock_set_running(VHostVSock *vsock, int start) +static int vhost_vsock_set_running(VirtIODevice *vdev, int start) { - const VhostOps *vhost_ops = vsock->vhost_dev.vhost_ops; + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + const VhostOps *vhost_ops = vvc->vhost_dev.vhost_ops; int ret; if (!vhost_ops->vhost_vsock_set_running) { return -ENOSYS; } - ret = vhost_ops->vhost_vsock_set_running(&vsock->vhost_dev, start); + ret = vhost_ops->vhost_vsock_set_running(&vvc->vhost_dev, start); if (ret < 0) { return -errno; } return 0; } -static void vhost_vsock_start(VirtIODevice *vdev) -{ - VHostVSock *vsock = VHOST_VSOCK(vdev); - BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); - VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); - int ret; - int i; - - if (!k->set_guest_notifiers) { - error_report("binding does not support guest notifiers"); - return; - } - - ret = vhost_dev_enable_notifiers(&vsock->vhost_dev, vdev); - if (ret < 0) { - error_report("Error enabling host notifiers: %d", -ret); - return; - } - - ret = k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, true); - if (ret < 0) { - error_report("Error binding guest notifier: %d", -ret); - goto err_host_notifiers; - } - - vsock->vhost_dev.acked_features = vdev->guest_features; - ret = vhost_dev_start(&vsock->vhost_dev, vdev); - if (ret < 0) { - error_report("Error starting vhost: %d", -ret); - goto err_guest_notifiers; - } - - ret = vhost_vsock_set_running(vsock, 1); - if (ret < 0) { - error_report("Error starting vhost vsock: %d", -ret); - goto err_dev_start; - } - - /* guest_notifier_mask/pending not used yet, so just unmask - * everything here. virtio-pci will do the right thing by - * enabling/disabling irqfd. - */ - for (i = 0; i < vsock->vhost_dev.nvqs; i++) { - vhost_virtqueue_mask(&vsock->vhost_dev, vdev, i, false); - } - - return; - -err_dev_start: - vhost_dev_stop(&vsock->vhost_dev, vdev); -err_guest_notifiers: - k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, false); -err_host_notifiers: - vhost_dev_disable_notifiers(&vsock->vhost_dev, vdev); -} - -static void vhost_vsock_stop(VirtIODevice *vdev) -{ - VHostVSock *vsock = VHOST_VSOCK(vdev); - BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); - VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); - int ret; - - if (!k->set_guest_notifiers) { - return; - } - - ret = vhost_vsock_set_running(vsock, 0); - if (ret < 0) { - error_report("vhost vsock set running failed: %d", ret); - return; - } - - vhost_dev_stop(&vsock->vhost_dev, vdev); - - ret = k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, false); - if (ret < 0) { - error_report("vhost guest notifier cleanup failed: %d", ret); - return; - } - - vhost_dev_disable_notifiers(&vsock->vhost_dev, vdev); -} static void vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status) { - VHostVSock *vsock = VHOST_VSOCK(vdev); + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; + int ret; if (!vdev->vm_running) { should_start = false; } - if (vsock->vhost_dev.started == should_start) { + if (vvc->vhost_dev.started == should_start) { return; } if (should_start) { - vhost_vsock_start(vdev); + ret = vhost_vsock_common_start(vdev); + if (ret < 0) { + return; + } + + ret = vhost_vsock_set_running(vdev, 1); + if (ret < 0) { + vhost_vsock_common_stop(vdev); + error_report("Error starting vhost vsock: %d", -ret); + return; + } } else { - vhost_vsock_stop(vdev); + ret = vhost_vsock_set_running(vdev, 0); + if (ret < 0) { + error_report("vhost vsock set running failed: %d", ret); + return; + } + + vhost_vsock_common_stop(vdev); } } @@ -184,108 +111,6 @@ static uint64_t vhost_vsock_get_features(VirtIODevice *vdev, return requested_features; } -static void vhost_vsock_handle_output(VirtIODevice *vdev, VirtQueue *vq) -{ - /* Do nothing */ -} - -static void vhost_vsock_guest_notifier_mask(VirtIODevice *vdev, int idx, - bool mask) -{ - VHostVSock *vsock = VHOST_VSOCK(vdev); - - vhost_virtqueue_mask(&vsock->vhost_dev, vdev, idx, mask); -} - -static bool vhost_vsock_guest_notifier_pending(VirtIODevice *vdev, int idx) -{ - VHostVSock *vsock = VHOST_VSOCK(vdev); - - return vhost_virtqueue_pending(&vsock->vhost_dev, idx); -} - -static void vhost_vsock_send_transport_reset(VHostVSock *vsock) -{ - VirtQueueElement *elem; - VirtQueue *vq = vsock->event_vq; - struct virtio_vsock_event event = { - .id = cpu_to_le32(VIRTIO_VSOCK_EVENT_TRANSPORT_RESET), - }; - - elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); - if (!elem) { - error_report("vhost-vsock missed transport reset event"); - return; - } - - if (elem->out_num) { - error_report("invalid vhost-vsock event virtqueue element with " - "out buffers"); - goto out; - } - - if (iov_from_buf(elem->in_sg, elem->in_num, 0, - &event, sizeof(event)) != sizeof(event)) { - error_report("vhost-vsock event virtqueue element is too short"); - goto out; - } - - virtqueue_push(vq, elem, sizeof(event)); - virtio_notify(VIRTIO_DEVICE(vsock), vq); - -out: - g_free(elem); -} - -static void vhost_vsock_post_load_timer_cleanup(VHostVSock *vsock) -{ - if (!vsock->post_load_timer) { - return; - } - - timer_del(vsock->post_load_timer); - timer_free(vsock->post_load_timer); - vsock->post_load_timer = NULL; -} - -static void vhost_vsock_post_load_timer_cb(void *opaque) -{ - VHostVSock *vsock = opaque; - - vhost_vsock_post_load_timer_cleanup(vsock); - vhost_vsock_send_transport_reset(vsock); -} - -static int vhost_vsock_pre_save(void *opaque) -{ - VHostVSock *vsock = opaque; - - /* At this point, backend must be stopped, otherwise - * it might keep writing to memory. */ - assert(!vsock->vhost_dev.started); - - return 0; -} - -static int vhost_vsock_post_load(void *opaque, int version_id) -{ - VHostVSock *vsock = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(vsock); - - if (virtio_queue_get_addr(vdev, 2)) { - /* Defer transport reset event to a vm clock timer so that virtqueue - * changes happen after migration has completed. - */ - assert(!vsock->post_load_timer); - vsock->post_load_timer = - timer_new_ns(QEMU_CLOCK_VIRTUAL, - vhost_vsock_post_load_timer_cb, - vsock); - timer_mod(vsock->post_load_timer, 1); - } - return 0; -} - static const VMStateDescription vmstate_virtio_vhost_vsock = { .name = "virtio-vhost_vsock", .minimum_version_id = VHOST_VSOCK_SAVEVM_VERSION, @@ -294,12 +119,13 @@ static const VMStateDescription vmstate_virtio_vhost_vsock = { VMSTATE_VIRTIO_DEVICE, VMSTATE_END_OF_LIST() }, - .pre_save = vhost_vsock_pre_save, - .post_load = vhost_vsock_post_load, + .pre_save = vhost_vsock_common_pre_save, + .post_load = vhost_vsock_common_post_load, }; static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostVSock *vsock = VHOST_VSOCK(dev); int vhostfd; @@ -331,46 +157,29 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) } } - virtio_init(vdev, "vhost-vsock", VIRTIO_ID_VSOCK, - sizeof(struct virtio_vsock_config)); + vhost_vsock_common_realize(vdev, "vhost-vsock"); - /* Receive and transmit queues belong to vhost */ - vsock->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, - vhost_vsock_handle_output); - vsock->trans_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, - vhost_vsock_handle_output); - - /* The event queue belongs to QEMU */ - vsock->event_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, - vhost_vsock_handle_output); - - vsock->vhost_dev.nvqs = ARRAY_SIZE(vsock->vhost_vqs); - vsock->vhost_dev.vqs = vsock->vhost_vqs; - ret = vhost_dev_init(&vsock->vhost_dev, (void *)(uintptr_t)vhostfd, + ret = vhost_dev_init(&vvc->vhost_dev, (void *)(uintptr_t)vhostfd, VHOST_BACKEND_TYPE_KERNEL, 0); if (ret < 0) { error_setg_errno(errp, -ret, "vhost-vsock: vhost_dev_init failed"); goto err_virtio; } - ret = vhost_vsock_set_guest_cid(vsock); + ret = vhost_vsock_set_guest_cid(vdev); if (ret < 0) { error_setg_errno(errp, -ret, "vhost-vsock: unable to set guest cid"); goto err_vhost_dev; } - vsock->post_load_timer = NULL; return; err_vhost_dev: - vhost_dev_cleanup(&vsock->vhost_dev); + vhost_dev_cleanup(&vvc->vhost_dev); /* vhost_dev_cleanup() closes the vhostfd passed to vhost_dev_init() */ vhostfd = -1; err_virtio: - virtio_delete_queue(vsock->recv_vq); - virtio_delete_queue(vsock->trans_vq); - virtio_delete_queue(vsock->event_vq); - virtio_cleanup(vdev); + vhost_vsock_common_unrealize(vdev); if (vhostfd >= 0) { close(vhostfd); } @@ -379,19 +188,14 @@ err_virtio: static void vhost_vsock_device_unrealize(DeviceState *dev) { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev); - VHostVSock *vsock = VHOST_VSOCK(dev); - - vhost_vsock_post_load_timer_cleanup(vsock); /* This will stop vhost backend if appropriate. */ vhost_vsock_set_status(vdev, 0); - vhost_dev_cleanup(&vsock->vhost_dev); - virtio_delete_queue(vsock->recv_vq); - virtio_delete_queue(vsock->trans_vq); - virtio_delete_queue(vsock->event_vq); - virtio_cleanup(vdev); + vhost_dev_cleanup(&vvc->vhost_dev); + vhost_vsock_common_unrealize(vdev); } static Property vhost_vsock_properties[] = { @@ -407,19 +211,16 @@ static void vhost_vsock_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, vhost_vsock_properties); dc->vmsd = &vmstate_virtio_vhost_vsock; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); vdc->realize = vhost_vsock_device_realize; vdc->unrealize = vhost_vsock_device_unrealize; vdc->get_features = vhost_vsock_get_features; vdc->get_config = vhost_vsock_get_config; vdc->set_status = vhost_vsock_set_status; - vdc->guest_notifier_mask = vhost_vsock_guest_notifier_mask; - vdc->guest_notifier_pending = vhost_vsock_guest_notifier_pending; } static const TypeInfo vhost_vsock_info = { .name = TYPE_VHOST_VSOCK, - .parent = TYPE_VIRTIO_DEVICE, + .parent = TYPE_VHOST_VSOCK_COMMON, .instance_size = sizeof(VHostVSock), .class_init = vhost_vsock_class_init, }; diff --git a/include/hw/virtio/vhost-vsock-common.h b/include/hw/virtio/vhost-vsock-common.h new file mode 100644 index 0000000000..f8b4aaae00 --- /dev/null +++ b/include/hw/virtio/vhost-vsock-common.h @@ -0,0 +1,47 @@ +/* + * Parent class for vhost-vsock devices + * + * Copyright 2015-2020 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#ifndef _QEMU_VHOST_VSOCK_COMMON_H +#define _QEMU_VHOST_VSOCK_COMMON_H + +#include "hw/virtio/virtio.h" +#include "hw/virtio/vhost.h" + +#define TYPE_VHOST_VSOCK_COMMON "vhost-vsock-common" +#define VHOST_VSOCK_COMMON(obj) \ + OBJECT_CHECK(VHostVSockCommon, (obj), TYPE_VHOST_VSOCK_COMMON) + +enum { + VHOST_VSOCK_SAVEVM_VERSION = 0, + + VHOST_VSOCK_QUEUE_SIZE = 128, +}; + +typedef struct { + VirtIODevice parent; + + struct vhost_virtqueue vhost_vqs[2]; + struct vhost_dev vhost_dev; + + VirtQueue *event_vq; + VirtQueue *recv_vq; + VirtQueue *trans_vq; + + QEMUTimer *post_load_timer; +} VHostVSockCommon; + +int vhost_vsock_common_start(VirtIODevice *vdev); +void vhost_vsock_common_stop(VirtIODevice *vdev); +int vhost_vsock_common_pre_save(void *opaque); +int vhost_vsock_common_post_load(void *opaque, int version_id); +void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name); +void vhost_vsock_common_unrealize(VirtIODevice *vdev); + +#endif /* _QEMU_VHOST_VSOCK_COMMON_H */ diff --git a/include/hw/virtio/vhost-vsock.h b/include/hw/virtio/vhost-vsock.h index bc5a988ee5..8cbb7b90f9 100644 --- a/include/hw/virtio/vhost-vsock.h +++ b/include/hw/virtio/vhost-vsock.h @@ -14,8 +14,7 @@ #ifndef QEMU_VHOST_VSOCK_H #define QEMU_VHOST_VSOCK_H -#include "hw/virtio/virtio.h" -#include "hw/virtio/vhost.h" +#include "hw/virtio/vhost-vsock-common.h" #define TYPE_VHOST_VSOCK "vhost-vsock-device" #define VHOST_VSOCK(obj) \ @@ -28,14 +27,8 @@ typedef struct { typedef struct { /*< private >*/ - VirtIODevice parent; + VHostVSockCommon parent; VHostVSockConf conf; - struct vhost_virtqueue vhost_vqs[2]; - struct vhost_dev vhost_dev; - VirtQueue *event_vq; - VirtQueue *recv_vq; - VirtQueue *trans_vq; - QEMUTimer *post_load_timer; /*< public >*/ } VHostVSock; From 5fe97d8829e8bc2a297474df20cd3ac12eebdbba Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Fri, 22 May 2020 14:25:11 +0200 Subject: [PATCH 1125/2595] virtio: add vhost-user-vsock base device This patch introduces a vhost-user device for vsock, using the vhost-vsock-common parent class. The vhost-user-vsock device can be used to implement the virtio-vsock device emulation in user-space. Signed-off-by: Stefano Garzarella Message-Id: <20200522122512.87413-3-sgarzare@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- configure | 3 + hw/virtio/Makefile.objs | 1 + hw/virtio/vhost-user-vsock.c | 181 +++++++++++++++++++++++++++ include/hw/virtio/vhost-user-vsock.h | 36 ++++++ 4 files changed, 221 insertions(+) create mode 100644 hw/virtio/vhost-user-vsock.c create mode 100644 include/hw/virtio/vhost-user-vsock.h diff --git a/configure b/configure index 597e909b53..7c2adf36e5 100755 --- a/configure +++ b/configure @@ -7196,6 +7196,9 @@ if test "$vhost_crypto" = "yes" ; then fi if test "$vhost_vsock" = "yes" ; then echo "CONFIG_VHOST_VSOCK=y" >> $config_host_mak + if test "$vhost_user" = "yes" ; then + echo "CONFIG_VHOST_USER_VSOCK=y" >> $config_host_mak + fi fi if test "$vhost_kernel" = "yes" ; then echo "CONFIG_VHOST_KERNEL=y" >> $config_host_mak diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index b1eeb44eac..dd42daedb1 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -18,6 +18,7 @@ common-obj-$(call land,$(CONFIG_VIRTIO_PMEM),$(CONFIG_VIRTIO_PCI)) += virtio-pme obj-$(call land,$(CONFIG_VHOST_USER_FS),$(CONFIG_VIRTIO_PCI)) += vhost-user-fs-pci.o obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-common.o vhost-vsock.o +obj-$(CONFIG_VHOST_USER_VSOCK) += vhost-vsock-common.o vhost-user-vsock.o ifeq ($(CONFIG_VIRTIO_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o diff --git a/hw/virtio/vhost-user-vsock.c b/hw/virtio/vhost-user-vsock.c new file mode 100644 index 0000000000..3534a39d62 --- /dev/null +++ b/hw/virtio/vhost-user-vsock.c @@ -0,0 +1,181 @@ +/* + * Vhost-user vsock virtio device + * + * Copyright 2020 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/vhost-user-vsock.h" + +static const int user_feature_bits[] = { + VIRTIO_F_VERSION_1, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_F_NOTIFY_ON_EMPTY, + VHOST_INVALID_FEATURE_BIT +}; + +static void vuv_get_config(VirtIODevice *vdev, uint8_t *config) +{ + VHostUserVSock *vsock = VHOST_USER_VSOCK(vdev); + + memcpy(config, &vsock->vsockcfg, sizeof(struct virtio_vsock_config)); +} + +static int vuv_handle_config_change(struct vhost_dev *dev) +{ + VHostUserVSock *vsock = VHOST_USER_VSOCK(dev->vdev); + int ret = vhost_dev_get_config(dev, (uint8_t *)&vsock->vsockcfg, + sizeof(struct virtio_vsock_config)); + if (ret < 0) { + error_report("get config space failed"); + return -1; + } + + virtio_notify_config(dev->vdev); + + return 0; +} + +const VhostDevConfigOps vsock_ops = { + .vhost_dev_config_notifier = vuv_handle_config_change, +}; + +static void vuv_set_status(VirtIODevice *vdev, uint8_t status) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; + + if (!vdev->vm_running) { + should_start = false; + } + + if (vvc->vhost_dev.started == should_start) { + return; + } + + if (should_start) { + int ret = vhost_vsock_common_start(vdev); + if (ret < 0) { + return; + } + } else { + vhost_vsock_common_stop(vdev); + } +} + +static uint64_t vuv_get_features(VirtIODevice *vdev, + uint64_t features, + Error **errp) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + + return vhost_get_features(&vvc->vhost_dev, user_feature_bits, features); +} + +static const VMStateDescription vuv_vmstate = { + .name = "vhost-user-vsock", + .unmigratable = 1, +}; + +static void vuv_device_realize(DeviceState *dev, Error **errp) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserVSock *vsock = VHOST_USER_VSOCK(dev); + int ret; + + if (!vsock->conf.chardev.chr) { + error_setg(errp, "missing chardev"); + return; + } + + if (!vhost_user_init(&vsock->vhost_user, &vsock->conf.chardev, errp)) { + return; + } + + vhost_vsock_common_realize(vdev, "vhost-user-vsock"); + + vhost_dev_set_config_notifier(&vvc->vhost_dev, &vsock_ops); + + ret = vhost_dev_init(&vvc->vhost_dev, &vsock->vhost_user, + VHOST_BACKEND_TYPE_USER, 0); + if (ret < 0) { + error_setg_errno(errp, -ret, "vhost_dev_init failed"); + goto err_virtio; + } + + ret = vhost_dev_get_config(&vvc->vhost_dev, (uint8_t *)&vsock->vsockcfg, + sizeof(struct virtio_vsock_config)); + if (ret < 0) { + error_setg_errno(errp, -ret, "get config space failed"); + goto err_vhost_dev; + } + + return; + +err_vhost_dev: + vhost_dev_cleanup(&vvc->vhost_dev); +err_virtio: + vhost_vsock_common_unrealize(vdev); + vhost_user_cleanup(&vsock->vhost_user); + return; +} + +static void vuv_device_unrealize(DeviceState *dev) +{ + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserVSock *vsock = VHOST_USER_VSOCK(dev); + + /* This will stop vhost backend if appropriate. */ + vuv_set_status(vdev, 0); + + vhost_dev_cleanup(&vvc->vhost_dev); + + vhost_vsock_common_unrealize(vdev); + + vhost_user_cleanup(&vsock->vhost_user); + +} + +static Property vuv_properties[] = { + DEFINE_PROP_CHR("chardev", VHostUserVSock, conf.chardev), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vuv_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + device_class_set_props(dc, vuv_properties); + dc->vmsd = &vuv_vmstate; + vdc->realize = vuv_device_realize; + vdc->unrealize = vuv_device_unrealize; + vdc->get_features = vuv_get_features; + vdc->get_config = vuv_get_config; + vdc->set_status = vuv_set_status; +} + +static const TypeInfo vuv_info = { + .name = TYPE_VHOST_USER_VSOCK, + .parent = TYPE_VHOST_VSOCK_COMMON, + .instance_size = sizeof(VHostUserVSock), + .class_init = vuv_class_init, +}; + +static void vuv_register_types(void) +{ + type_register_static(&vuv_info); +} + +type_init(vuv_register_types) diff --git a/include/hw/virtio/vhost-user-vsock.h b/include/hw/virtio/vhost-user-vsock.h new file mode 100644 index 0000000000..4e128a4b9f --- /dev/null +++ b/include/hw/virtio/vhost-user-vsock.h @@ -0,0 +1,36 @@ +/* + * Vhost-user vsock virtio device + * + * Copyright 2020 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#ifndef _QEMU_VHOST_USER_VSOCK_H +#define _QEMU_VHOST_USER_VSOCK_H + +#include "hw/virtio/vhost-vsock-common.h" +#include "hw/virtio/vhost-user.h" +#include "standard-headers/linux/virtio_vsock.h" + +#define TYPE_VHOST_USER_VSOCK "vhost-user-vsock-device" +#define VHOST_USER_VSOCK(obj) \ + OBJECT_CHECK(VHostUserVSock, (obj), TYPE_VHOST_USER_VSOCK) + +typedef struct { + CharBackend chardev; +} VHostUserVSockConf; + +typedef struct { + /*< private >*/ + VHostVSockCommon parent; + VhostUserState vhost_user; + VHostUserVSockConf conf; + struct virtio_vsock_config vsockcfg; + + /*< public >*/ +} VHostUserVSock; + +#endif /* _QEMU_VHOST_USER_VSOCK_H */ From 9b83bb27477f3fb2c08db32ea2ee9e8f817f0f9d Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Fri, 22 May 2020 14:25:12 +0200 Subject: [PATCH 1126/2595] virtio: add vhost-user-vsock-pci device Add the PCI version of vhost-user-vsock Launch QEMU like this: qemu -chardev socket,path=/tmp/vm.vsock,id=chr0 \ -device vhost-user-vsock-pci,chardev=chr0 Signed-off-by: Stefano Garzarella Message-Id: <20200522122512.87413-4-sgarzare@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/Makefile.objs | 1 + hw/virtio/vhost-user-vsock-pci.c | 84 ++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 hw/virtio/vhost-user-vsock-pci.c diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index dd42daedb1..13e75f171f 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -22,6 +22,7 @@ obj-$(CONFIG_VHOST_USER_VSOCK) += vhost-vsock-common.o vhost-user-vsock.o ifeq ($(CONFIG_VIRTIO_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o +obj-$(CONFIG_VHOST_USER_VSOCK) += vhost-user-vsock-pci.o obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk-pci.o obj-$(CONFIG_VHOST_USER_INPUT) += vhost-user-input-pci.o obj-$(CONFIG_VHOST_USER_SCSI) += vhost-user-scsi-pci.o diff --git a/hw/virtio/vhost-user-vsock-pci.c b/hw/virtio/vhost-user-vsock-pci.c new file mode 100644 index 0000000000..0a6847e6fc --- /dev/null +++ b/hw/virtio/vhost-user-vsock-pci.c @@ -0,0 +1,84 @@ +/* + * Vhost-user vsock PCI Bindings + * + * Copyright 2020 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/vhost-user-vsock.h" + +typedef struct VHostUserVSockPCI VHostUserVSockPCI; + +/* + * vhost-user-vsock-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VHOST_USER_VSOCK_PCI "vhost-user-vsock-pci-base" +#define VHOST_USER_VSOCK_PCI(obj) \ + OBJECT_CHECK(VHostUserVSockPCI, (obj), TYPE_VHOST_USER_VSOCK_PCI) + +struct VHostUserVSockPCI { + VirtIOPCIProxy parent_obj; + VHostUserVSock vdev; +}; + +/* vhost-user-vsock-pci */ + +static Property vhost_user_vsock_pci_properties[] = { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_user_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostUserVSockPCI *dev = VHOST_USER_VSOCK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void vhost_user_vsock_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_user_vsock_pci_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + device_class_set_props(dc, vhost_user_vsock_pci_properties); + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VSOCK; + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; +} + +static void vhost_user_vsock_pci_instance_init(Object *obj) +{ + VHostUserVSockPCI *dev = VHOST_USER_VSOCK_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_VSOCK); +} + +static const VirtioPCIDeviceTypeInfo vhost_user_vsock_pci_info = { + .base_name = TYPE_VHOST_USER_VSOCK_PCI, + .generic_name = "vhost-user-vsock-pci", + .transitional_name = "vhost-user-vsock-pci-transitional", + .non_transitional_name = "vhost-user-vsock-pci-non-transitional", + .instance_size = sizeof(VHostUserVSockPCI), + .instance_init = vhost_user_vsock_pci_instance_init, + .class_init = vhost_user_vsock_pci_class_init, +}; + +static void virtio_pci_vhost_register(void) +{ + virtio_pci_types_register(&vhost_user_vsock_pci_info); +} + +type_init(virtio_pci_vhost_register) From 1dc32f9aeb127d995efd52a29f57460c011780da Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 20 May 2020 15:19:46 +0200 Subject: [PATCH 1127/2595] acpi: make build_madt() more generic. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove PCMachineState dependency from build_madt(). Pass AcpiDeviceIf as separate argument instead of depending on PCMachineState->acpi_dev. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov Message-Id: <20200520132003.9492-6-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 1ecb68f45f..d217fc1fe6 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -366,14 +366,13 @@ void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, } static void -build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms) +build_madt(GArray *table_data, BIOSLinker *linker, + X86MachineState *x86ms, AcpiDeviceIf *adev) { - MachineClass *mc = MACHINE_GET_CLASS(pcms); - X86MachineState *x86ms = X86_MACHINE(pcms); - const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(pcms)); + MachineClass *mc = MACHINE_GET_CLASS(x86ms); + const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); int madt_start = table_data->len; - AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(pcms->acpi_dev); - AcpiDeviceIf *adev = ACPI_DEVICE_IF(pcms->acpi_dev); + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); bool x2apic_mode = false; AcpiMultipleApicTable *madt; @@ -2708,7 +2707,8 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) aml_len += tables_blob->len - fadt; acpi_add_table(table_offsets, tables_blob); - build_madt(tables_blob, tables->linker, pcms); + build_madt(tables_blob, tables->linker, x86ms, + ACPI_DEVICE_IF(pcms->acpi_dev)); vmgenid_dev = find_vmgenid_dev(); if (vmgenid_dev) { From eb66ffabc00a7b062b2c73b9178eb2679328813b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 20 May 2020 15:19:47 +0200 Subject: [PATCH 1128/2595] acpi: create acpi-common.c and move madt code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'll need madt support for microvm. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Message-Id: <20200520132003.9492-7-kraxel@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/Makefile.objs | 1 + hw/i386/acpi-build.c | 126 +--------------------------------- hw/i386/acpi-common.c | 152 ++++++++++++++++++++++++++++++++++++++++++ hw/i386/acpi-common.h | 14 ++++ 4 files changed, 170 insertions(+), 123 deletions(-) create mode 100644 hw/i386/acpi-common.c create mode 100644 hw/i386/acpi-common.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 8ce1b26533..6abc74551a 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -16,4 +16,5 @@ obj-$(CONFIG_VMMOUSE) += vmmouse.o obj-$(CONFIG_PC) += port92.o obj-y += kvmvapic.o +obj-$(CONFIG_ACPI) += acpi-common.o obj-$(CONFIG_PC) += acpi-build.o diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index d217fc1fe6..26c0c8aefa 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -24,6 +24,7 @@ #include "qapi/error.h" #include "qapi/qmp/qnum.h" #include "acpi-build.h" +#include "acpi-common.h" #include "qemu/bitmap.h" #include "qemu/error-report.h" #include "hw/pci/pci.h" @@ -89,9 +90,6 @@ #define ACPI_BUILD_DPRINTF(fmt, ...) #endif -/* Default IOAPIC ID */ -#define ACPI_BUILD_IOAPIC_ID 0x0 - typedef struct AcpiPmInfo { bool s3_disabled; bool s4_disabled; @@ -327,124 +325,6 @@ build_facs(GArray *table_data) facs->length = cpu_to_le32(sizeof(*facs)); } -void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry) -{ - uint32_t apic_id = apic_ids->cpus[uid].arch_id; - - /* ACPI spec says that LAPIC entry for non present - * CPU may be omitted from MADT or it must be marked - * as disabled. However omitting non present CPU from - * MADT breaks hotplug on linux. So possible CPUs - * should be put in MADT but kept disabled. - */ - if (apic_id < 255) { - AcpiMadtProcessorApic *apic = acpi_data_push(entry, sizeof *apic); - - apic->type = ACPI_APIC_PROCESSOR; - apic->length = sizeof(*apic); - apic->processor_id = uid; - apic->local_apic_id = apic_id; - if (apic_ids->cpus[uid].cpu != NULL) { - apic->flags = cpu_to_le32(1); - } else { - apic->flags = cpu_to_le32(0); - } - } else { - AcpiMadtProcessorX2Apic *apic = acpi_data_push(entry, sizeof *apic); - - apic->type = ACPI_APIC_LOCAL_X2APIC; - apic->length = sizeof(*apic); - apic->uid = cpu_to_le32(uid); - apic->x2apic_id = cpu_to_le32(apic_id); - if (apic_ids->cpus[uid].cpu != NULL) { - apic->flags = cpu_to_le32(1); - } else { - apic->flags = cpu_to_le32(0); - } - } -} - -static void -build_madt(GArray *table_data, BIOSLinker *linker, - X86MachineState *x86ms, AcpiDeviceIf *adev) -{ - MachineClass *mc = MACHINE_GET_CLASS(x86ms); - const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); - int madt_start = table_data->len; - AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); - bool x2apic_mode = false; - - AcpiMultipleApicTable *madt; - AcpiMadtIoApic *io_apic; - AcpiMadtIntsrcovr *intsrcovr; - int i; - - madt = acpi_data_push(table_data, sizeof *madt); - madt->local_apic_address = cpu_to_le32(APIC_DEFAULT_ADDRESS); - madt->flags = cpu_to_le32(1); - - for (i = 0; i < apic_ids->len; i++) { - adevc->madt_cpu(adev, i, apic_ids, table_data); - if (apic_ids->cpus[i].arch_id > 254) { - x2apic_mode = true; - } - } - - io_apic = acpi_data_push(table_data, sizeof *io_apic); - io_apic->type = ACPI_APIC_IO; - io_apic->length = sizeof(*io_apic); - io_apic->io_apic_id = ACPI_BUILD_IOAPIC_ID; - io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS); - io_apic->interrupt = cpu_to_le32(0); - - if (x86ms->apic_xrupt_override) { - intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr); - intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE; - intsrcovr->length = sizeof(*intsrcovr); - intsrcovr->source = 0; - intsrcovr->gsi = cpu_to_le32(2); - intsrcovr->flags = cpu_to_le16(0); /* conforms to bus specifications */ - } - for (i = 1; i < 16; i++) { -#define ACPI_BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11)) - if (!(ACPI_BUILD_PCI_IRQS & (1 << i))) { - /* No need for a INT source override structure. */ - continue; - } - intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr); - intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE; - intsrcovr->length = sizeof(*intsrcovr); - intsrcovr->source = i; - intsrcovr->gsi = cpu_to_le32(i); - intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */ - } - - if (x2apic_mode) { - AcpiMadtLocalX2ApicNmi *local_nmi; - - local_nmi = acpi_data_push(table_data, sizeof *local_nmi); - local_nmi->type = ACPI_APIC_LOCAL_X2APIC_NMI; - local_nmi->length = sizeof(*local_nmi); - local_nmi->uid = 0xFFFFFFFF; /* all processors */ - local_nmi->flags = cpu_to_le16(0); - local_nmi->lint = 1; /* ACPI_LINT1 */ - } else { - AcpiMadtLocalNmi *local_nmi; - - local_nmi = acpi_data_push(table_data, sizeof *local_nmi); - local_nmi->type = ACPI_APIC_LOCAL_NMI; - local_nmi->length = sizeof(*local_nmi); - local_nmi->processor_id = 0xff; /* all processors */ - local_nmi->flags = cpu_to_le16(0); - local_nmi->lint = 1; /* ACPI_LINT1 */ - } - - build_header(linker, table_data, - (void *)(table_data->data + madt_start), "APIC", - table_data->len - madt_start, 1, NULL, NULL); -} - static void build_append_pcihp_notify_entry(Aml *method, int slot) { Aml *if_ctx; @@ -2707,8 +2587,8 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) aml_len += tables_blob->len - fadt; acpi_add_table(table_offsets, tables_blob); - build_madt(tables_blob, tables->linker, x86ms, - ACPI_DEVICE_IF(pcms->acpi_dev)); + acpi_build_madt(tables_blob, tables->linker, x86ms, + ACPI_DEVICE_IF(pcms->acpi_dev)); vmgenid_dev = find_vmgenid_dev(); if (vmgenid_dev) { diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c new file mode 100644 index 0000000000..5caca16a0b --- /dev/null +++ b/hw/i386/acpi-common.c @@ -0,0 +1,152 @@ +/* Support for generating ACPI tables and passing them to Guests + * + * Copyright (C) 2008-2010 Kevin O'Connor + * Copyright (C) 2006 Fabrice Bellard + * Copyright (C) 2013 Red Hat Inc + * + * Author: Michael S. Tsirkin + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" + +#include "exec/memory.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/utils.h" +#include "hw/i386/pc.h" +#include "target/i386/cpu.h" + +#include "acpi-build.h" +#include "acpi-common.h" + +void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, + const CPUArchIdList *apic_ids, GArray *entry) +{ + uint32_t apic_id = apic_ids->cpus[uid].arch_id; + + /* ACPI spec says that LAPIC entry for non present + * CPU may be omitted from MADT or it must be marked + * as disabled. However omitting non present CPU from + * MADT breaks hotplug on linux. So possible CPUs + * should be put in MADT but kept disabled. + */ + if (apic_id < 255) { + AcpiMadtProcessorApic *apic = acpi_data_push(entry, sizeof *apic); + + apic->type = ACPI_APIC_PROCESSOR; + apic->length = sizeof(*apic); + apic->processor_id = uid; + apic->local_apic_id = apic_id; + if (apic_ids->cpus[uid].cpu != NULL) { + apic->flags = cpu_to_le32(1); + } else { + apic->flags = cpu_to_le32(0); + } + } else { + AcpiMadtProcessorX2Apic *apic = acpi_data_push(entry, sizeof *apic); + + apic->type = ACPI_APIC_LOCAL_X2APIC; + apic->length = sizeof(*apic); + apic->uid = cpu_to_le32(uid); + apic->x2apic_id = cpu_to_le32(apic_id); + if (apic_ids->cpus[uid].cpu != NULL) { + apic->flags = cpu_to_le32(1); + } else { + apic->flags = cpu_to_le32(0); + } + } +} + +void acpi_build_madt(GArray *table_data, BIOSLinker *linker, + X86MachineState *x86ms, AcpiDeviceIf *adev) +{ + MachineClass *mc = MACHINE_GET_CLASS(x86ms); + const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); + int madt_start = table_data->len; + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); + bool x2apic_mode = false; + + AcpiMultipleApicTable *madt; + AcpiMadtIoApic *io_apic; + AcpiMadtIntsrcovr *intsrcovr; + int i; + + madt = acpi_data_push(table_data, sizeof *madt); + madt->local_apic_address = cpu_to_le32(APIC_DEFAULT_ADDRESS); + madt->flags = cpu_to_le32(1); + + for (i = 0; i < apic_ids->len; i++) { + adevc->madt_cpu(adev, i, apic_ids, table_data); + if (apic_ids->cpus[i].arch_id > 254) { + x2apic_mode = true; + } + } + + io_apic = acpi_data_push(table_data, sizeof *io_apic); + io_apic->type = ACPI_APIC_IO; + io_apic->length = sizeof(*io_apic); + io_apic->io_apic_id = ACPI_BUILD_IOAPIC_ID; + io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS); + io_apic->interrupt = cpu_to_le32(0); + + if (x86ms->apic_xrupt_override) { + intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr); + intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE; + intsrcovr->length = sizeof(*intsrcovr); + intsrcovr->source = 0; + intsrcovr->gsi = cpu_to_le32(2); + intsrcovr->flags = cpu_to_le16(0); /* conforms to bus specifications */ + } + for (i = 1; i < 16; i++) { +#define ACPI_BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11)) + if (!(ACPI_BUILD_PCI_IRQS & (1 << i))) { + /* No need for a INT source override structure. */ + continue; + } + intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr); + intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE; + intsrcovr->length = sizeof(*intsrcovr); + intsrcovr->source = i; + intsrcovr->gsi = cpu_to_le32(i); + intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */ + } + + if (x2apic_mode) { + AcpiMadtLocalX2ApicNmi *local_nmi; + + local_nmi = acpi_data_push(table_data, sizeof *local_nmi); + local_nmi->type = ACPI_APIC_LOCAL_X2APIC_NMI; + local_nmi->length = sizeof(*local_nmi); + local_nmi->uid = 0xFFFFFFFF; /* all processors */ + local_nmi->flags = cpu_to_le16(0); + local_nmi->lint = 1; /* ACPI_LINT1 */ + } else { + AcpiMadtLocalNmi *local_nmi; + + local_nmi = acpi_data_push(table_data, sizeof *local_nmi); + local_nmi->type = ACPI_APIC_LOCAL_NMI; + local_nmi->length = sizeof(*local_nmi); + local_nmi->processor_id = 0xff; /* all processors */ + local_nmi->flags = cpu_to_le16(0); + local_nmi->lint = 1; /* ACPI_LINT1 */ + } + + build_header(linker, table_data, + (void *)(table_data->data + madt_start), "APIC", + table_data->len - madt_start, 1, NULL, NULL); +} + diff --git a/hw/i386/acpi-common.h b/hw/i386/acpi-common.h new file mode 100644 index 0000000000..c30e461f18 --- /dev/null +++ b/hw/i386/acpi-common.h @@ -0,0 +1,14 @@ +#ifndef HW_I386_ACPI_COMMON_H +#define HW_I386_ACPI_COMMON_H +#include "include/hw/acpi/acpi_dev_interface.h" + +#include "include/hw/acpi/bios-linker-loader.h" +#include "include/hw/i386/x86.h" + +/* Default IOAPIC ID */ +#define ACPI_BUILD_IOAPIC_ID 0x0 + +void acpi_build_madt(GArray *table_data, BIOSLinker *linker, + X86MachineState *x86ms, AcpiDeviceIf *adev); + +#endif From 5794d34a13d11e12d9bc53ea4ade997c2ff81c4c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 20 May 2020 15:19:48 +0200 Subject: [PATCH 1129/2595] acpi: madt: skip pci override on pci-less systems. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for microvm. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200520132003.9492-8-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 2 +- hw/i386/acpi-common.c | 26 +++++++++++++++----------- hw/i386/acpi-common.h | 3 ++- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 26c0c8aefa..473cbdfffd 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2588,7 +2588,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) acpi_add_table(table_offsets, tables_blob); acpi_build_madt(tables_blob, tables->linker, x86ms, - ACPI_DEVICE_IF(pcms->acpi_dev)); + ACPI_DEVICE_IF(pcms->acpi_dev), true); vmgenid_dev = find_vmgenid_dev(); if (vmgenid_dev) { diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 5caca16a0b..ab9b00581a 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -72,7 +72,8 @@ void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, } void acpi_build_madt(GArray *table_data, BIOSLinker *linker, - X86MachineState *x86ms, AcpiDeviceIf *adev) + X86MachineState *x86ms, AcpiDeviceIf *adev, + bool has_pci) { MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); @@ -111,18 +112,21 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, intsrcovr->gsi = cpu_to_le32(2); intsrcovr->flags = cpu_to_le16(0); /* conforms to bus specifications */ } - for (i = 1; i < 16; i++) { + + if (has_pci) { + for (i = 1; i < 16; i++) { #define ACPI_BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11)) - if (!(ACPI_BUILD_PCI_IRQS & (1 << i))) { - /* No need for a INT source override structure. */ - continue; + if (!(ACPI_BUILD_PCI_IRQS & (1 << i))) { + /* No need for a INT source override structure. */ + continue; + } + intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr); + intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE; + intsrcovr->length = sizeof(*intsrcovr); + intsrcovr->source = i; + intsrcovr->gsi = cpu_to_le32(i); + intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */ } - intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr); - intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE; - intsrcovr->length = sizeof(*intsrcovr); - intsrcovr->source = i; - intsrcovr->gsi = cpu_to_le32(i); - intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */ } if (x2apic_mode) { diff --git a/hw/i386/acpi-common.h b/hw/i386/acpi-common.h index c30e461f18..9cac18dddf 100644 --- a/hw/i386/acpi-common.h +++ b/hw/i386/acpi-common.h @@ -9,6 +9,7 @@ #define ACPI_BUILD_IOAPIC_ID 0x0 void acpi_build_madt(GArray *table_data, BIOSLinker *linker, - X86MachineState *x86ms, AcpiDeviceIf *adev); + X86MachineState *x86ms, AcpiDeviceIf *adev, + bool has_pci); #endif From c8ed8f57cc558045638512249ffc5f3633f76db1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 20 May 2020 15:19:49 +0200 Subject: [PATCH 1130/2595] acpi: fadt: add hw-reduced sleep register support Add fields to struct AcpiFadtData and update build_fadt() to properly generate sleep register entries. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Message-Id: <20200520132003.9492-9-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/aml-build.c | 4 ++-- include/hw/acpi/acpi-defs.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index d24e9e6c3a..2cb7b991ef 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1866,9 +1866,9 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, } /* SLEEP_CONTROL_REG */ - build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0); + build_append_gas_from_struct(tbl, &f->sleep_ctl); /* SLEEP_STATUS_REG */ - build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0); + build_append_gas_from_struct(tbl, &f->sleep_sts); /* TODO: extra fields need to be added to support revisions above rev5 */ assert(f->rev == 5); diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index c13327fa78..3be9ab5049 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -88,6 +88,8 @@ typedef struct AcpiFadtData { struct AcpiGenericAddress pm_tmr; /* PM_TMR_BLK */ struct AcpiGenericAddress gpe0_blk; /* GPE0_BLK */ struct AcpiGenericAddress reset_reg; /* RESET_REG */ + struct AcpiGenericAddress sleep_ctl; /* SLEEP_CONTROL_REG */ + struct AcpiGenericAddress sleep_sts; /* SLEEP_STATUS_REG */ uint8_t reset_val; /* RESET_VALUE */ uint8_t rev; /* Revision */ uint32_t flags; /* Flags */ From 32905fc95c0a082f4cb28b8076e0160b3c62c7f8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 20 May 2020 15:19:50 +0200 Subject: [PATCH 1131/2595] acpi: ged: rename event memory region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename memory region and callbacks and ops to carry "evt" in the name because a second region will be added shortly. Signed-off-by: Gerd Hoffmann Message-Id: <20200520132003.9492-10-kraxel@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedow Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/generic_event_device.c | 16 ++++++++-------- include/hw/acpi/generic_event_device.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index b1cbdd86b6..1cb34111e5 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -142,7 +142,7 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, } /* Memory read by the GED _EVT AML dynamic method */ -static uint64_t ged_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t ged_evt_read(void *opaque, hwaddr addr, unsigned size) { uint64_t val = 0; GEDState *ged_st = opaque; @@ -161,14 +161,14 @@ static uint64_t ged_read(void *opaque, hwaddr addr, unsigned size) } /* Nothing is expected to be written to the GED memory region */ -static void ged_write(void *opaque, hwaddr addr, uint64_t data, - unsigned int size) +static void ged_evt_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { } -static const MemoryRegionOps ged_ops = { - .read = ged_read, - .write = ged_write, +static const MemoryRegionOps ged_evt_ops = { + .read = ged_evt_read, + .write = ged_evt_write, .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 4, @@ -287,9 +287,9 @@ static void acpi_ged_initfn(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); GEDState *ged_st = &s->ged_state; - memory_region_init_io(&ged_st->io, obj, &ged_ops, ged_st, + memory_region_init_io(&ged_st->evt, obj, &ged_evt_ops, ged_st, TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN); - sysbus_init_mmio(sbd, &ged_st->io); + sysbus_init_mmio(sbd, &ged_st->evt); sysbus_init_irq(sbd, &s->irq); diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h index 83917de024..90a9180db5 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h @@ -86,7 +86,7 @@ #define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4 typedef struct GEDState { - MemoryRegion io; + MemoryRegion evt; uint32_t sel; } GEDState; From 62925fd2b8b778539607b321216cd54897ddb63a Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Thu, 7 May 2020 17:37:58 -0400 Subject: [PATCH 1132/2595] Fix parameter type in vhost migration log path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ‘enable’ parameter to the vhost_migration_log() function is given as an int, but "true"/"false" values are passed in wherever it is invoked. Inside the function itself it is only ever compared with bool values. Therefore the parameter value itself should be changed to bool. Signed-off-by: Raphael Norwitz Message-Id: Reviewed-by: Eric Blake Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index aff98a0ede..aa06a36919 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -809,12 +809,12 @@ err_features: return r; } -static int vhost_migration_log(MemoryListener *listener, int enable) +static int vhost_migration_log(MemoryListener *listener, bool enable) { struct vhost_dev *dev = container_of(listener, struct vhost_dev, memory_listener); int r; - if (!!enable == dev->log_enabled) { + if (enable == dev->log_enabled) { return 0; } if (!dev->started) { From 12fcf49c1a016cc05638b965f4e7b909794bffa2 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 17 Mar 2020 15:59:08 -0400 Subject: [PATCH 1133/2595] pci: Display PCI IRQ pin in "info pci" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes it would be good to be able to read the pin number along with the IRQ number allocated. Since we'll dump the IRQ number, no reason to not dump the pin information. For example, the vfio-pci device will overwrite the pin with the hardware pin number. It would be nice to know the pin number of one assigned device from QMP/HMP. CC: Dr. David Alan Gilbert CC: Alex Williamson CC: Michael S. Tsirkin CC: Marcel Apfelbaum CC: Julia Suvorova CC: Markus Armbruster Signed-off-by: Peter Xu Message-Id: <20200317195908.283800-1-peterx@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé Acked-by: Dr. David Alan Gilbert Acked-by: Markus Armbruster --- hw/pci/pci.c | 1 + monitor/hmp-cmds.c | 3 ++- qapi/misc.json | 6 ++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 1b88a32cf7..a60cf3ae3b 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1776,6 +1776,7 @@ static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, info->regions = qmp_query_pci_regions(dev); info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : ""); + info->irq_pin = dev->config[PCI_INTERRUPT_PIN]; if (dev->config[PCI_INTERRUPT_PIN] != 0) { info->has_irq = true; info->irq = dev->config[PCI_INTERRUPT_LINE]; diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 9c61e769ca..e03adf0d4d 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -688,7 +688,8 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev) } if (dev->has_irq) { - monitor_printf(mon, " IRQ %" PRId64 ".\n", dev->irq); + monitor_printf(mon, " IRQ %" PRId64 ", pin %c\n", + dev->irq, (char)('A' + dev->irq_pin - 1)); } if (dev->has_pci_bridge) { diff --git a/qapi/misc.json b/qapi/misc.json index 99b90ac80b..a5a0beb902 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -403,6 +403,8 @@ # # @irq: if an IRQ is assigned to the device, the IRQ number # +# @irq_pin: the IRQ pin, zero means no IRQ (since 5.1) +# # @qdev_id: the device name of the PCI device # # @pci_bridge: if the device is a PCI bridge, the bridge information @@ -417,8 +419,8 @@ { 'struct': 'PciDeviceInfo', 'data': {'bus': 'int', 'slot': 'int', 'function': 'int', 'class_info': 'PciDeviceClass', 'id': 'PciDeviceId', - '*irq': 'int', 'qdev_id': 'str', '*pci_bridge': 'PciBridgeInfo', - 'regions': ['PciMemoryRegion']} } + '*irq': 'int', 'irq_pin': 'int', 'qdev_id': 'str', + '*pci_bridge': 'PciBridgeInfo', 'regions': ['PciMemoryRegion'] }} ## # @PciInfo: From 10d35e581901c09ee3817ac7cddd296d05291a9d Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 10 Jun 2020 13:43:51 +0800 Subject: [PATCH 1134/2595] virtio-pci: fix queue_enable write Spec said: The driver uses this to selectively prevent the device from executing requests from this virtqueue. 1 - enabled; 0 - disabled. Though write 0 to queue_enable is forbidden by the spec, we should not assume that the value is 1. Fix this by ignore the write value other than 1. Signed-off-by: Jason Wang Message-Id: <20200610054351.15811-1-jasowang@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Stefano Garzarella Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index d028c17c24..7bc8c1c056 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1273,16 +1273,20 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr, virtio_queue_set_vector(vdev, vdev->queue_sel, val); break; case VIRTIO_PCI_COMMON_Q_ENABLE: - virtio_queue_set_num(vdev, vdev->queue_sel, - proxy->vqs[vdev->queue_sel].num); - virtio_queue_set_rings(vdev, vdev->queue_sel, + if (val == 1) { + virtio_queue_set_num(vdev, vdev->queue_sel, + proxy->vqs[vdev->queue_sel].num); + virtio_queue_set_rings(vdev, vdev->queue_sel, ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 | proxy->vqs[vdev->queue_sel].desc[0], ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 | proxy->vqs[vdev->queue_sel].avail[0], ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 | proxy->vqs[vdev->queue_sel].used[0]); - proxy->vqs[vdev->queue_sel].enabled = 1; + proxy->vqs[vdev->queue_sel].enabled = 1; + } else { + virtio_error(vdev, "wrong value for queue_enable %"PRIx64, val); + } break; case VIRTIO_PCI_COMMON_Q_DESCLO: proxy->vqs[vdev->queue_sel].desc[0] = val; From bc921b2711c4e2e8ab99a3045f6c0f134a93b535 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 12 Jun 2020 13:45:23 +0000 Subject: [PATCH 1135/2595] target/i386: correct fix for pcmpxstrx substring search This corrects a bug introduced in my previous fix for SSE4.2 pcmpestri / pcmpestrm / pcmpistri / pcmpistrm substring search, commit ae35eea7e4a9f21dd147406dfbcd0c4c6aaf2a60. That commit fixed a bug that showed up in four GCC tests with one libc implementation. The tests in question generate random inputs to the intrinsics and compare results to a C implementation, but they only test 1024 possible random inputs, and when the tests use the cases of those instructions that work with word rather than byte inputs, it's easy to have problematic cases that show up much less frequently than that. Thus, testing with a different libc implementation, and so a different random number generator, showed up a problem with the previous patch. When investigating the previous test failures, I found the description of these instructions in the Intel manuals (starting from computing a 16x16 or 8x8 set of comparison results) confusing and hard to match up with the more optimized implementation in QEMU, and referred to AMD manuals which described the instructions in a different way. Those AMD descriptions are very explicit that the whole of the string being searched for must be found in the other operand, not running off the end of that operand; they say "If the prototype and the SUT are equal in length, the two strings must be identical for the comparison to be TRUE.". However, that statement is incorrect. In my previous commit message, I noted: The operation in this case is a search for a string (argument d to the helper) in another string (argument s to the helper); if a copy of d at a particular position would run off the end of s, the resulting output bit should be 0 whether or not the strings match in the region where they overlap, but the QEMU implementation was wrongly comparing only up to the point where s ends and counting it as a match if an initial segment of d matched a terminal segment of s. Here, "run off the end of s" means that some byte of d would overlap some byte outside of s; thus, if d has zero length, it is considered to match everywhere, including after the end of s. The description "some byte of d would overlap some byte outside of s" is accurate only when understood to refer to overlapping some byte *within the 16-byte operand* but at or after the zero terminator; it is valid to run over the end of s if the end of s is the end of the 16-byte operand. So the fix in the previous patch for the case of d being empty was correct, but the other part of that patch was not correct (as it never allowed partial matches even at the end of the 16-byte operand). Nor was the code before the previous patch correct for the case of d nonempty, as it would always have allowed partial matches at the end of s. Fix with a partial revert of my previous change, combined with inserting a check for the special case of s having maximum length to determine where it is necessary to check for matches. In the added test, test 1 is for the case of empty strings, which failed before my 2017 patch, test 2 is for the bug introduced by my 2017 patch and test 3 deals with the case where a match of an initial segment at the end of the string is not valid when the string ends before the end of the 16-byte operand (that is, the case that would be broken by a simple revert of the non-empty-string part of my 2017 patch). Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/ops_sse.h | 4 ++-- tests/tcg/i386/Makefile.target | 3 +++ tests/tcg/i386/test-i386-pcmpistri.c | 33 ++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 tests/tcg/i386/test-i386-pcmpistri.c diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h index 01d6017412..14f2b16abd 100644 --- a/target/i386/ops_sse.h +++ b/target/i386/ops_sse.h @@ -2089,10 +2089,10 @@ static inline unsigned pcmpxstrx(CPUX86State *env, Reg *d, Reg *s, res = (2 << upper) - 1; break; } - for (j = valids - validd; j >= 0; j--) { + for (j = valids == upper ? valids : valids - validd; j >= 0; j--) { res <<= 1; v = 1; - for (i = validd; i >= 0; i--) { + for (i = MIN(valids - j, validd); i >= 0; i--) { v &= (pcmp_val(s, ctrl, i + j) == pcmp_val(d, ctrl, i)); } res |= v; diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index 43ee2e181e..53efec0668 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -10,6 +10,9 @@ ALL_X86_TESTS=$(I386_SRCS:.c=) SKIP_I386_TESTS=test-i386-ssse3 X86_64_TESTS:=$(filter test-i386-ssse3, $(ALL_X86_TESTS)) +test-i386-pcmpistri: CFLAGS += -msse4.2 +run-test-i386-pcmpistri: QEMU_OPTS += -cpu max + # # hello-i386 is a barebones app # diff --git a/tests/tcg/i386/test-i386-pcmpistri.c b/tests/tcg/i386/test-i386-pcmpistri.c new file mode 100644 index 0000000000..1e81ae611a --- /dev/null +++ b/tests/tcg/i386/test-i386-pcmpistri.c @@ -0,0 +1,33 @@ +/* Test pcmpistri instruction. */ + +#include +#include + +union u { + __m128i x; + unsigned char uc[16]; +}; + +union u s0 = { .uc = { 0 } }; +union u s1 = { .uc = "abcdefghijklmnop" }; +union u s2 = { .uc = "bcdefghijklmnopa" }; +union u s3 = { .uc = "bcdefghijklmnab" }; + +int +main(void) +{ + int ret = 0; + if (_mm_cmpistri(s0.x, s0.x, 0x4c) != 15) { + printf("FAIL: pcmpistri test 1\n"); + ret = 1; + } + if (_mm_cmpistri(s1.x, s2.x, 0x4c) != 15) { + printf("FAIL: pcmpistri test 2\n"); + ret = 1; + } + if (_mm_cmpistri(s1.x, s3.x, 0x4c) != 16) { + printf("FAIL: pcmpistri test 3\n"); + ret = 1; + } + return ret; +} From 33fb9bfaa4bef35b53affaf17368b439834de5f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 19:24:21 +0200 Subject: [PATCH 1136/2595] sysemu/accel: Restrict machine methods to system-mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restrict init_machine(), setup_post() and has_memory() to system-mode. Reviewed-by: Edgar E. Iglesias Reviewed-by: Cornelia Huck Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Roman Bolshakov Message-Id: <20200526172427.17460-2-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- include/sysemu/accel.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sysemu/accel.h b/include/sysemu/accel.h index 47e5788530..e08b8ab8fa 100644 --- a/include/sysemu/accel.h +++ b/include/sysemu/accel.h @@ -37,10 +37,12 @@ typedef struct AccelClass { /*< public >*/ const char *name; +#ifndef CONFIG_USER_ONLY int (*init_machine)(MachineState *ms); void (*setup_post)(MachineState *ms, AccelState *accel); bool (*has_memory)(MachineState *ms, AddressSpace *as, hwaddr start_addr, hwaddr size); +#endif bool *allowed; /* * Array of global properties that would be applied when specific From ce4049e89344cc019fff75ab0ecc645af27400ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 19:24:22 +0200 Subject: [PATCH 1137/2595] sysemu/tcg: Only declare tcg_allowed when TCG is available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When TCG is not available, the tcg_allowed variable does not exist. Reviewed-by: Edgar E. Iglesias Reviewed-by: Cornelia Huck Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200526172427.17460-3-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- include/sysemu/tcg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sysemu/tcg.h b/include/sysemu/tcg.h index 7d116d2e80..d9d3ca8559 100644 --- a/include/sysemu/tcg.h +++ b/include/sysemu/tcg.h @@ -8,9 +8,9 @@ #ifndef SYSEMU_TCG_H #define SYSEMU_TCG_H -extern bool tcg_allowed; void tcg_exec_init(unsigned long tb_size); #ifdef CONFIG_TCG +extern bool tcg_allowed; #define tcg_enabled() (tcg_allowed) #else #define tcg_enabled() 0 From f291cf54148e5b9e51c55b9056e4be546492a9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 19:24:23 +0200 Subject: [PATCH 1138/2595] sysemu/hvf: Only declare hvf_allowed when HVF is available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When HVF is not available, the hvf_allowed variable does not exist. Reviewed-by: Edgar E. Iglesias Reviewed-by: Cornelia Huck Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Roman Bolshakov Message-Id: <20200526172427.17460-4-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- include/sysemu/hvf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index d211e808e9..fe95743124 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -18,7 +18,6 @@ #include "exec/memory.h" #include "sysemu/accel.h" -extern bool hvf_allowed; #ifdef CONFIG_HVF #include #include @@ -26,11 +25,12 @@ extern bool hvf_allowed; #include "target/i386/cpu.h" uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, int reg); +extern bool hvf_allowed; #define hvf_enabled() (hvf_allowed) -#else +#else /* !CONFIG_HVF */ #define hvf_enabled() 0 #define hvf_get_supported_cpuid(func, idx, reg) 0 -#endif +#endif /* !CONFIG_HVF */ /* hvf_slot flags */ #define HVF_SLOT_LOG (1 << 0) From e89aac1acdc62c09313c20ea1706554d9c3b9162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 26 May 2020 19:24:24 +0200 Subject: [PATCH 1139/2595] target/ppc: Restrict PPCVirtualHypervisorClass to system-mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code related to PPC Virtual Hypervisor is pointless in user-mode. Acked-by: David Gibson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200526172427.17460-5-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- target/ppc/cpu.h | 4 ++-- target/ppc/kvm_ppc.h | 22 +++++++++++----------- target/ppc/translate_init.inc.c | 4 ++++ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 1988b436cb..e7d382ac10 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1202,6 +1202,7 @@ PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr); PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr); PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc); +#ifndef CONFIG_USER_ONLY struct PPCVirtualHypervisorClass { InterfaceClass parent; void (*hypercall)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu); @@ -1215,10 +1216,8 @@ struct PPCVirtualHypervisorClass { void (*hpte_set_r)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte1); void (*get_pate)(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry); target_ulong (*encode_hpt_for_kvm_pr)(PPCVirtualHypervisor *vhyp); -#ifndef CONFIG_USER_ONLY void (*cpu_exec_enter)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu); void (*cpu_exec_exit)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu); -#endif }; #define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor" @@ -1230,6 +1229,7 @@ struct PPCVirtualHypervisorClass { #define PPC_VIRTUAL_HYPERVISOR_GET_CLASS(obj) \ OBJECT_GET_CLASS(PPCVirtualHypervisorClass, (obj), \ TYPE_PPC_VIRTUAL_HYPERVISOR) +#endif /* CONFIG_USER_ONLY */ void ppc_cpu_do_interrupt(CPUState *cpu); bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req); diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index fcaf745516..701c0c262b 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -280,6 +280,17 @@ static inline bool kvmppc_has_cap_spapr_vfio(void) return false; } +static inline void kvmppc_read_hptes(ppc_hash_pte64_t *hptes, + hwaddr ptex, int n) +{ + abort(); +} + +static inline void kvmppc_write_hpte(hwaddr ptex, uint64_t pte0, uint64_t pte1) +{ + abort(); +} + #endif /* !CONFIG_USER_ONLY */ static inline bool kvmppc_has_cap_epr(void) @@ -310,17 +321,6 @@ static inline int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, abort(); } -static inline void kvmppc_read_hptes(ppc_hash_pte64_t *hptes, - hwaddr ptex, int n) -{ - abort(); -} - -static inline void kvmppc_write_hpte(hwaddr ptex, uint64_t pte0, uint64_t pte1) -{ - abort(); -} - static inline bool kvmppc_has_cap_fixup_hcalls(void) { abort(); diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index 38cb773ab4..a40888411c 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -10942,16 +10942,20 @@ static const TypeInfo ppc_cpu_type_info = { .class_init = ppc_cpu_class_init, }; +#ifndef CONFIG_USER_ONLY static const TypeInfo ppc_vhyp_type_info = { .name = TYPE_PPC_VIRTUAL_HYPERVISOR, .parent = TYPE_INTERFACE, .class_size = sizeof(PPCVirtualHypervisorClass), }; +#endif static void ppc_cpu_register_types(void) { type_register_static(&ppc_cpu_type_info); +#ifndef CONFIG_USER_ONLY type_register_static(&ppc_vhyp_type_info); +#endif } type_init(ppc_cpu_register_types) From 24115348bd8a8a1206646b81990e451ee841c8e5 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:46 +0300 Subject: [PATCH 1140/2595] i386: hvf: Move HVFState definition into hvf "sysemu/hvf.h" is intended for inclusion in generic code. However it also contains several hvf definitions and declarations, including HVFState that are used only inside "hvf.c". "hvf-i386.h" would be more appropriate place to define HVFState as it's only included by "hvf.c" and "x86_task.c". Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-2-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- include/sysemu/hvf.h | 37 ------------------------------------- target/i386/hvf/hvf-i386.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index fe95743124..644bdfc722 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -15,8 +15,6 @@ #include "cpu.h" #include "qemu/bitops.h" -#include "exec/memory.h" -#include "sysemu/accel.h" #ifdef CONFIG_HVF #include @@ -32,41 +30,6 @@ extern bool hvf_allowed; #define hvf_get_supported_cpuid(func, idx, reg) 0 #endif /* !CONFIG_HVF */ -/* hvf_slot flags */ -#define HVF_SLOT_LOG (1 << 0) - -typedef struct hvf_slot { - uint64_t start; - uint64_t size; - uint8_t *mem; - int slot_id; - uint32_t flags; - MemoryRegion *region; -} hvf_slot; - -typedef struct hvf_vcpu_caps { - uint64_t vmx_cap_pinbased; - uint64_t vmx_cap_procbased; - uint64_t vmx_cap_procbased2; - uint64_t vmx_cap_entry; - uint64_t vmx_cap_exit; - uint64_t vmx_cap_preemption_timer; -} hvf_vcpu_caps; - -typedef struct HVFState { - AccelState parent; - hvf_slot slots[32]; - int num_slots; - - hvf_vcpu_caps *hvf_caps; -} HVFState; -extern HVFState *hvf_state; - -void hvf_set_phys_mem(MemoryRegionSection *, bool); -void hvf_handle_io(CPUArchState *, uint16_t, void *, - int, int, int); -hvf_slot *hvf_find_overlap_slot(uint64_t, uint64_t); - /* Disable HVF if |disable| is 1, otherwise, enable it iff it is supported by * the host CPU. Use hvf_enabled() after this to get the result. */ void hvf_disable(int disable); diff --git a/target/i386/hvf/hvf-i386.h b/target/i386/hvf/hvf-i386.h index fbe4a350c5..ef20c73eca 100644 --- a/target/i386/hvf/hvf-i386.h +++ b/target/i386/hvf/hvf-i386.h @@ -16,6 +16,7 @@ #ifndef HVF_I386_H #define HVF_I386_H +#include "sysemu/accel.h" #include "sysemu/hvf.h" #include "cpu.h" #include "x86.h" @@ -35,6 +36,40 @@ struct hvf_state { uint64_t mem_quota; }; +/* hvf_slot flags */ +#define HVF_SLOT_LOG (1 << 0) + +typedef struct hvf_slot { + uint64_t start; + uint64_t size; + uint8_t *mem; + int slot_id; + uint32_t flags; + MemoryRegion *region; +} hvf_slot; + +typedef struct hvf_vcpu_caps { + uint64_t vmx_cap_pinbased; + uint64_t vmx_cap_procbased; + uint64_t vmx_cap_procbased2; + uint64_t vmx_cap_entry; + uint64_t vmx_cap_exit; + uint64_t vmx_cap_preemption_timer; +} hvf_vcpu_caps; + +typedef struct HVFState { + AccelState parent; + hvf_slot slots[32]; + int num_slots; + + hvf_vcpu_caps *hvf_caps; +} HVFState; +extern HVFState *hvf_state; + +void hvf_set_phys_mem(MemoryRegionSection *, bool); +void hvf_handle_io(CPUArchState *, uint16_t, void *, int, int, int); +hvf_slot *hvf_find_overlap_slot(uint64_t, uint64_t); + #ifdef NEED_CPU_H /* Functions exported to host specific mode */ From 583ae161b1d7ba8832260d1cca022afce7dcf957 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:47 +0300 Subject: [PATCH 1141/2595] i386: hvf: Drop useless declarations in sysemu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They're either declared elsewhere or have no use. While at it, rename _hvf_cpu_synchronize_post_init() to do_hvf_cpu_synchronize_post_init(). Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-3-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini Reviewed-by: Philippe Mathieu-Daudé --- include/sysemu/hvf.h | 22 ---------------------- target/i386/hvf/hvf.c | 7 ++++--- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index 644bdfc722..2af32e505e 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -30,35 +30,13 @@ extern bool hvf_allowed; #define hvf_get_supported_cpuid(func, idx, reg) 0 #endif /* !CONFIG_HVF */ -/* Disable HVF if |disable| is 1, otherwise, enable it iff it is supported by - * the host CPU. Use hvf_enabled() after this to get the result. */ -void hvf_disable(int disable); - -/* Returns non-0 if the host CPU supports the VMX "unrestricted guest" feature - * which allows the virtual CPU to directly run in "real mode". If true, this - * allows QEMU to run several vCPU threads in parallel (see cpus.c). Otherwise, - * only a a single TCG thread can run, and it will call HVF to run the current - * instructions, except in case of "real mode" (paging disabled, typically at - * boot time), or MMIO operations. */ - -int hvf_sync_vcpus(void); - int hvf_init_vcpu(CPUState *); int hvf_vcpu_exec(CPUState *); -int hvf_smp_cpu_exec(CPUState *); void hvf_cpu_synchronize_state(CPUState *); void hvf_cpu_synchronize_post_reset(CPUState *); void hvf_cpu_synchronize_post_init(CPUState *); -void _hvf_cpu_synchronize_post_init(CPUState *, run_on_cpu_data); - void hvf_vcpu_destroy(CPUState *); -void hvf_raise_event(CPUState *); -/* void hvf_reset_vcpu_state(void *opaque); */ void hvf_reset_vcpu(CPUState *); -void vmx_update_tpr(CPUState *); -void update_apic_tpr(CPUState *); -int hvf_put_registers(CPUState *); -void vmx_clear_int_window_exiting(CPUState *cpu); #define TYPE_HVF_ACCEL ACCEL_CLASS_NAME("hvf") diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index d72543dc31..9ccdb7e7c7 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -251,7 +251,7 @@ void vmx_update_tpr(CPUState *cpu) } } -void update_apic_tpr(CPUState *cpu) +static void update_apic_tpr(CPUState *cpu) { X86CPU *x86_cpu = X86_CPU(cpu); int tpr = rreg(cpu->hvf_fd, HV_X86_TPR) >> 4; @@ -312,7 +312,8 @@ void hvf_cpu_synchronize_post_reset(CPUState *cpu_state) run_on_cpu(cpu_state, do_hvf_cpu_synchronize_post_reset, RUN_ON_CPU_NULL); } -void _hvf_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) +static void do_hvf_cpu_synchronize_post_init(CPUState *cpu, + run_on_cpu_data arg) { CPUState *cpu_state = cpu; hvf_put_registers(cpu_state); @@ -321,7 +322,7 @@ void _hvf_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) void hvf_cpu_synchronize_post_init(CPUState *cpu_state) { - run_on_cpu(cpu_state, _hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL); + run_on_cpu(cpu_state, do_hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL); } static bool ept_emulation_fault(hvf_slot *slot, uint64_t gpa, uint64_t ept_qual) From 8598135dd6df2b2ad2ce10f68d9eae3e9e26da6d Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:48 +0300 Subject: [PATCH 1142/2595] i386: hvf: Clean stray includes in sysemu They have no use. Signed-off-by: Roman Bolshakov Reviewed-by: Claudio Fontana Message-Id: <20200528193758.51454-4-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- include/sysemu/hvf.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index 2af32e505e..5214ed5202 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -13,14 +13,7 @@ #ifndef HVF_H #define HVF_H -#include "cpu.h" -#include "qemu/bitops.h" - #ifdef CONFIG_HVF -#include -#include -#include -#include "target/i386/cpu.h" uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, int reg); extern bool hvf_allowed; From 6345d7e2aeb6f7bbaa9c1e7e94e21fccf9453c70 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:49 +0300 Subject: [PATCH 1143/2595] i386: hvf: Drop unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-5-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini Reviewed-by: Philippe Mathieu-Daudé --- target/i386/hvf/x86.h | 1 - 1 file changed, 1 deletion(-) diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index c95d5b2116..56fcde13c6 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -293,7 +293,6 @@ typedef struct lazy_flags { /* Definition of hvf_x86_state is here */ struct HVFX86EmulatorState { - int interruptable; uint64_t fetch_rip; uint64_t rip; struct x86_register regs[16]; From 81ae3d0216587bf868486244f038072e07ee4e9d Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:50 +0300 Subject: [PATCH 1144/2595] i386: hvf: Use ins_len to advance IP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no need to read VMCS twice, instruction length is already available in ins_len. Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-6-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini Reviewed-by: Philippe Mathieu-Daudé --- target/i386/hvf/hvf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 9ccdb7e7c7..8ff1d25521 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -871,7 +871,7 @@ int hvf_vcpu_exec(CPUState *cpu) } else { simulate_wrmsr(cpu); } - RIP(env) += rvmcs(cpu->hvf_fd, VMCS_EXIT_INSTRUCTION_LENGTH); + RIP(env) += ins_len; store_regs(cpu); break; } From 5d32173fc30e5b08e196f7ffd993ddc8335a203e Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:51 +0300 Subject: [PATCH 1145/2595] i386: hvf: Use IP from CPUX86State MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop and replace rip field from HVFX86EmulatorState in favor of eip from common CPUX86State. Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-7-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini Reviewed-by: Philippe Mathieu-Daudé --- target/i386/hvf/hvf.c | 6 +-- target/i386/hvf/x86.h | 3 -- target/i386/hvf/x86_decode.c | 6 +-- target/i386/hvf/x86_emu.c | 86 ++++++++++++++++++------------------ target/i386/hvf/x86_task.c | 4 +- 5 files changed, 51 insertions(+), 54 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 8ff1d25521..45ae55dd27 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -797,7 +797,7 @@ int hvf_vcpu_exec(CPUState *cpu) } else { RAX(env) = (uint64_t)val; } - RIP(env) += ins_len; + env->eip += ins_len; store_regs(cpu); break; } else if (!string && !in) { @@ -871,7 +871,7 @@ int hvf_vcpu_exec(CPUState *cpu) } else { simulate_wrmsr(cpu); } - RIP(env) += ins_len; + env->eip += ins_len; store_regs(cpu); break; } @@ -907,7 +907,7 @@ int hvf_vcpu_exec(CPUState *cpu) error_report("Unrecognized CR %d", cr); abort(); } - RIP(env) += ins_len; + env->eip += ins_len; store_regs(cpu); break; } diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index 56fcde13c6..e3ab7c5137 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -294,7 +294,6 @@ typedef struct lazy_flags { /* Definition of hvf_x86_state is here */ struct HVFX86EmulatorState { uint64_t fetch_rip; - uint64_t rip; struct x86_register regs[16]; struct x86_reg_flags rflags; struct lazy_flags lflags; @@ -302,8 +301,6 @@ struct HVFX86EmulatorState { }; /* useful register access macros */ -#define RIP(cpu) (cpu->hvf_emul->rip) -#define EIP(cpu) ((uint32_t)cpu->hvf_emul->rip) #define RFLAGS(cpu) (cpu->hvf_emul->rflags.rflags) #define EFLAGS(cpu) (cpu->hvf_emul->rflags.eflags) diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index 77c346605f..a590088f54 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -75,7 +75,7 @@ static inline uint64_t decode_bytes(CPUX86State *env, struct x86_decode *decode, VM_PANIC_EX("%s invalid size %d\n", __func__, size); break; } - target_ulong va = linear_rip(env_cpu(env), RIP(env)) + decode->len; + target_ulong va = linear_rip(env_cpu(env), env->eip) + decode->len; vmx_read_mem(env_cpu(env), &val, va, size); decode->len += size; @@ -1771,7 +1771,7 @@ void calc_modrm_operand32(CPUX86State *env, struct x86_decode *decode, ptr += get_sib_val(env, decode, &seg); } else if (!decode->modrm.mod && 5 == decode->modrm.rm) { if (x86_is_long_mode(env_cpu(env))) { - ptr += RIP(env) + decode->len; + ptr += env->eip + decode->len; } else { ptr = decode->displacement; } @@ -1807,7 +1807,7 @@ void calc_modrm_operand64(CPUX86State *env, struct x86_decode *decode, if (4 == rm) { ptr = get_sib_val(env, decode, &seg) + offset; } else if (0 == mod && 5 == rm) { - ptr = RIP(env) + decode->len + (int32_t) offset; + ptr = env->eip + decode->len + (int32_t) offset; } else { ptr = get_reg_val(env, src, decode->rex.rex, decode->rex.b, 8) + (int64_t) offset; diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 92ab815f5d..0efd9f9928 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -267,49 +267,49 @@ static void exec_mov(struct CPUX86State *env, struct x86_decode *decode) write_val_ext(env, decode->op[0].ptr, decode->op[1].val, decode->operand_size); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_add(struct CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_or(struct CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, |, SET_FLAGS_OSZAPC_LOGIC, true); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_adc(struct CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, +get_CF(env)+, SET_FLAGS_OSZAPC_ADD, true); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_sbb(struct CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, -get_CF(env)-, SET_FLAGS_OSZAPC_SUB, true); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_and(struct CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, true); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_sub(struct CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, true); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_xor(struct CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, ^, SET_FLAGS_OSZAPC_LOGIC, true); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_neg(struct CPUX86State *env, struct x86_decode *decode) @@ -332,13 +332,13 @@ static void exec_neg(struct CPUX86State *env, struct x86_decode *decode) } /*lflags_to_rflags(env);*/ - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_cmp(struct CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_inc(struct CPUX86State *env, struct x86_decode *decode) @@ -348,7 +348,7 @@ static void exec_inc(struct CPUX86State *env, struct x86_decode *decode) EXEC_2OP_FLAGS_CMD(env, decode, +1+, SET_FLAGS_OSZAP_ADD, true); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_dec(struct CPUX86State *env, struct x86_decode *decode) @@ -357,13 +357,13 @@ static void exec_dec(struct CPUX86State *env, struct x86_decode *decode) decode->op[1].val = 0; EXEC_2OP_FLAGS_CMD(env, decode, -1-, SET_FLAGS_OSZAP_SUB, true); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_tst(struct CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, false); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_not(struct CPUX86State *env, struct x86_decode *decode) @@ -372,7 +372,7 @@ static void exec_not(struct CPUX86State *env, struct x86_decode *decode) write_val_ext(env, decode->op[0].ptr, ~decode->op[0].val, decode->operand_size); - RIP(env) += decode->len; + env->eip += decode->len; } void exec_movzx(struct CPUX86State *env, struct x86_decode *decode) @@ -392,7 +392,7 @@ void exec_movzx(struct CPUX86State *env, struct x86_decode *decode) decode->op[1].val = read_val_ext(env, decode->op[1].ptr, src_op_size); write_val_ext(env, decode->op[0].ptr, decode->op[1].val, op_size); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_out(struct CPUX86State *env, struct x86_decode *decode) @@ -416,7 +416,7 @@ static void exec_out(struct CPUX86State *env, struct x86_decode *decode) VM_PANIC("Bad out opcode\n"); break; } - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_in(struct CPUX86State *env, struct x86_decode *decode) @@ -452,7 +452,7 @@ static void exec_in(struct CPUX86State *env, struct x86_decode *decode) break; } - RIP(env) += decode->len; + env->eip += decode->len; } static inline void string_increment_reg(struct CPUX86State *env, int reg, @@ -505,7 +505,7 @@ static void exec_ins(struct CPUX86State *env, struct x86_decode *decode) exec_ins_single(env, decode); } - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_outs_single(struct CPUX86State *env, struct x86_decode *decode) @@ -528,7 +528,7 @@ static void exec_outs(struct CPUX86State *env, struct x86_decode *decode) exec_outs_single(env, decode); } - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_movs_single(struct CPUX86State *env, struct x86_decode *decode) @@ -556,7 +556,7 @@ static void exec_movs(struct CPUX86State *env, struct x86_decode *decode) exec_movs_single(env, decode); } - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_cmps_single(struct CPUX86State *env, struct x86_decode *decode) @@ -586,7 +586,7 @@ static void exec_cmps(struct CPUX86State *env, struct x86_decode *decode) } else { exec_cmps_single(env, decode); } - RIP(env) += decode->len; + env->eip += decode->len; } @@ -612,7 +612,7 @@ static void exec_stos(struct CPUX86State *env, struct x86_decode *decode) exec_stos_single(env, decode); } - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_scas_single(struct CPUX86State *env, struct x86_decode *decode) @@ -638,7 +638,7 @@ static void exec_scas(struct CPUX86State *env, struct x86_decode *decode) exec_scas_single(env, decode); } - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_lods_single(struct CPUX86State *env, struct x86_decode *decode) @@ -661,7 +661,7 @@ static void exec_lods(struct CPUX86State *env, struct x86_decode *decode) exec_lods_single(env, decode); } - RIP(env) += decode->len; + env->eip += decode->len; } void simulate_rdmsr(struct CPUState *cpu) @@ -758,7 +758,7 @@ void simulate_rdmsr(struct CPUState *cpu) static void exec_rdmsr(struct CPUX86State *env, struct x86_decode *decode) { simulate_rdmsr(env_cpu(env)); - RIP(env) += decode->len; + env->eip += decode->len; } void simulate_wrmsr(struct CPUState *cpu) @@ -853,7 +853,7 @@ void simulate_wrmsr(struct CPUState *cpu) static void exec_wrmsr(struct CPUX86State *env, struct x86_decode *decode) { simulate_wrmsr(env_cpu(env)); - RIP(env) += decode->len; + env->eip += decode->len; } /* @@ -909,25 +909,25 @@ static void do_bt(struct CPUX86State *env, struct x86_decode *decode, int flag) static void exec_bt(struct CPUX86State *env, struct x86_decode *decode) { do_bt(env, decode, 0); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_btc(struct CPUX86State *env, struct x86_decode *decode) { do_bt(env, decode, 1); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_btr(struct CPUX86State *env, struct x86_decode *decode) { do_bt(env, decode, 3); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_bts(struct CPUX86State *env, struct x86_decode *decode) { do_bt(env, decode, 2); - RIP(env) += decode->len; + env->eip += decode->len; } void exec_shl(struct CPUX86State *env, struct x86_decode *decode) @@ -991,7 +991,7 @@ void exec_shl(struct CPUX86State *env, struct x86_decode *decode) exit: /* lflags_to_rflags(env); */ - RIP(env) += decode->len; + env->eip += decode->len; } void exec_movsx(CPUX86State *env, struct x86_decode *decode) @@ -1014,7 +1014,7 @@ void exec_movsx(CPUX86State *env, struct x86_decode *decode) write_val_ext(env, decode->op[0].ptr, decode->op[1].val, op_size); - RIP(env) += decode->len; + env->eip += decode->len; } void exec_ror(struct CPUX86State *env, struct x86_decode *decode) @@ -1092,7 +1092,7 @@ void exec_ror(struct CPUX86State *env, struct x86_decode *decode) break; } } - RIP(env) += decode->len; + env->eip += decode->len; } void exec_rol(struct CPUX86State *env, struct x86_decode *decode) @@ -1173,7 +1173,7 @@ void exec_rol(struct CPUX86State *env, struct x86_decode *decode) break; } } - RIP(env) += decode->len; + env->eip += decode->len; } @@ -1259,7 +1259,7 @@ void exec_rcl(struct CPUX86State *env, struct x86_decode *decode) break; } } - RIP(env) += decode->len; + env->eip += decode->len; } void exec_rcr(struct CPUX86State *env, struct x86_decode *decode) @@ -1334,7 +1334,7 @@ void exec_rcr(struct CPUX86State *env, struct x86_decode *decode) break; } } - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_xchg(struct CPUX86State *env, struct x86_decode *decode) @@ -1346,7 +1346,7 @@ static void exec_xchg(struct CPUX86State *env, struct x86_decode *decode) write_val_ext(env, decode->op[1].ptr, decode->op[0].val, decode->operand_size); - RIP(env) += decode->len; + env->eip += decode->len; } static void exec_xadd(struct CPUX86State *env, struct x86_decode *decode) @@ -1355,7 +1355,7 @@ static void exec_xadd(struct CPUX86State *env, struct x86_decode *decode) write_val_ext(env, decode->op[1].ptr, decode->op[0].val, decode->operand_size); - RIP(env) += decode->len; + env->eip += decode->len; } static struct cmd_handler { @@ -1434,7 +1434,7 @@ void load_regs(struct CPUState *cpu) RFLAGS(env) = rreg(cpu->hvf_fd, HV_X86_RFLAGS); rflags_to_lflags(env); - RIP(env) = rreg(cpu->hvf_fd, HV_X86_RIP); + env->eip = rreg(cpu->hvf_fd, HV_X86_RIP); } void store_regs(struct CPUState *cpu) @@ -1457,20 +1457,20 @@ void store_regs(struct CPUState *cpu) lflags_to_rflags(env); wreg(cpu->hvf_fd, HV_X86_RFLAGS, RFLAGS(env)); - macvm_set_rip(cpu, RIP(env)); + macvm_set_rip(cpu, env->eip); } bool exec_instruction(struct CPUX86State *env, struct x86_decode *ins) { /*if (hvf_vcpu_id(cpu)) - printf("%d, %llx: exec_instruction %s\n", hvf_vcpu_id(cpu), RIP(cpu), + printf("%d, %llx: exec_instruction %s\n", hvf_vcpu_id(cpu), env->eip, decode_cmd_to_string(ins->cmd));*/ if (!_cmd_handler[ins->cmd].handler) { - printf("Unimplemented handler (%llx) for %d (%x %x) \n", RIP(env), + printf("Unimplemented handler (%llx) for %d (%x %x) \n", env->eip, ins->cmd, ins->opcode[0], ins->opcode_len > 1 ? ins->opcode[1] : 0); - RIP(env) += ins->len; + env->eip += ins->len; return true; } diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c index 1daac6cc2b..834baec3ea 100644 --- a/target/i386/hvf/x86_task.c +++ b/target/i386/hvf/x86_task.c @@ -38,7 +38,7 @@ static void save_state_to_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) CPUX86State *env = &x86_cpu->env; /* CR3 and ldt selector are not saved intentionally */ - tss->eip = EIP(env); + tss->eip = (uint32_t)env->eip; tss->eflags = EFLAGS(env); tss->eax = EAX(env); tss->ecx = ECX(env); @@ -64,7 +64,7 @@ static void load_state_from_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) wvmcs(cpu->hvf_fd, VMCS_GUEST_CR3, tss->cr3); - RIP(env) = tss->eip; + env->eip = tss->eip; EFLAGS(env) = tss->eflags | 2; /* General purpose registers */ From 2d5f696cb7b7a024f2a1bd4a8c6aed7a1d5532b4 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:52 +0300 Subject: [PATCH 1146/2595] i386: hvf: Drop fetch_rip from HVFX86EmulatorState The field is used to print address of instructions that have no parser in decode_invalid(). RIP from VMCS is saved into fetch_rip before decoding starts but it's also saved into env->eip in load_regs(). Therefore env->eip can be used instead of fetch_rip. While at it, correct address printed in decode_invalid(). It prints an address before the unknown instruction. Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-8-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 6 ------ target/i386/hvf/x86.h | 1 - target/i386/hvf/x86_decode.c | 3 +-- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 45ae55dd27..416a6fae7c 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -767,8 +767,6 @@ int hvf_vcpu_exec(CPUState *cpu) struct x86_decode decode; load_regs(cpu); - env->hvf_emul->fetch_rip = rip; - decode_instruction(env, &decode); exec_instruction(env, &decode); store_regs(cpu); @@ -809,8 +807,6 @@ int hvf_vcpu_exec(CPUState *cpu) struct x86_decode decode; load_regs(cpu); - env->hvf_emul->fetch_rip = rip; - decode_instruction(env, &decode); assert(ins_len == decode.len); exec_instruction(env, &decode); @@ -915,8 +911,6 @@ int hvf_vcpu_exec(CPUState *cpu) struct x86_decode decode; load_regs(cpu); - env->hvf_emul->fetch_rip = rip; - decode_instruction(env, &decode); exec_instruction(env, &decode); store_regs(cpu); diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index e3ab7c5137..411e4b6599 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -293,7 +293,6 @@ typedef struct lazy_flags { /* Definition of hvf_x86_state is here */ struct HVFX86EmulatorState { - uint64_t fetch_rip; struct x86_register regs[16]; struct x86_reg_flags rflags; struct lazy_flags lflags; diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index a590088f54..d881542181 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -29,8 +29,7 @@ static void decode_invalid(CPUX86State *env, struct x86_decode *decode) { - printf("%llx: failed to decode instruction ", env->hvf_emul->fetch_rip - - decode->len); + printf("%llx: failed to decode instruction ", env->eip); for (int i = 0; i < decode->opcode_len; i++) { printf("%x ", decode->opcode[i]); } From 967f4da2afb2ece8b2b054bc8af23389e028fdcc Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:53 +0300 Subject: [PATCH 1147/2595] i386: hvf: Drop rflags from HVFX86EmulatorState HVFX86EmulatorState carries it's own copy of x86 flags. It can be dropped in favor of eflags in generic CPUX86State. Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-9-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 5 ++--- target/i386/hvf/x86.c | 2 +- target/i386/hvf/x86.h | 42 ------------------------------------- target/i386/hvf/x86_emu.c | 6 +++--- target/i386/hvf/x86_flags.c | 24 ++++++++++----------- target/i386/hvf/x86_task.c | 6 +++--- target/i386/hvf/x86hvf.c | 6 +++--- 7 files changed, 24 insertions(+), 67 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 416a6fae7c..4cee496d71 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -723,8 +723,7 @@ int hvf_vcpu_exec(CPUState *cpu) hvf_store_events(cpu, ins_len, idtvec_info); rip = rreg(cpu->hvf_fd, HV_X86_RIP); - RFLAGS(env) = rreg(cpu->hvf_fd, HV_X86_RFLAGS); - env->eflags = RFLAGS(env); + env->eflags = rreg(cpu->hvf_fd, HV_X86_RFLAGS); qemu_mutex_lock_iothread(); @@ -736,7 +735,7 @@ int hvf_vcpu_exec(CPUState *cpu) case EXIT_REASON_HLT: { macvm_set_rip(cpu, rip + ins_len); if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) && - (EFLAGS(env) & IF_MASK)) + (env->eflags & IF_MASK)) && !(cpu->interrupt_request & CPU_INTERRUPT_NMI) && !(idtvec_info & VMCS_IDT_VEC_VALID)) { cpu->halted = 1; diff --git a/target/i386/hvf/x86.c b/target/i386/hvf/x86.c index 3afcedc7fc..7ebb5b45bd 100644 --- a/target/i386/hvf/x86.c +++ b/target/i386/hvf/x86.c @@ -131,7 +131,7 @@ bool x86_is_v8086(struct CPUState *cpu) { X86CPU *x86_cpu = X86_CPU(cpu); CPUX86State *env = &x86_cpu->env; - return x86_is_protected(cpu) && (RFLAGS(env) & RFLAGS_VM); + return x86_is_protected(cpu) && (env->eflags & RFLAGS_VM); } bool x86_is_long_mode(struct CPUState *cpu) diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index 411e4b6599..e309b8f203 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -62,44 +62,6 @@ typedef enum x86_rflags { RFLAGS_ID = (1L << 21), } x86_rflags; -/* rflags register */ -typedef struct x86_reg_flags { - union { - struct { - uint64_t rflags; - }; - struct { - uint32_t eflags; - uint32_t hi32_unused1; - }; - struct { - uint32_t cf:1; - uint32_t unused1:1; - uint32_t pf:1; - uint32_t unused2:1; - uint32_t af:1; - uint32_t unused3:1; - uint32_t zf:1; - uint32_t sf:1; - uint32_t tf:1; - uint32_t ief:1; - uint32_t df:1; - uint32_t of:1; - uint32_t iopl:2; - uint32_t nt:1; - uint32_t unused4:1; - uint32_t rf:1; - uint32_t vm:1; - uint32_t ac:1; - uint32_t vif:1; - uint32_t vip:1; - uint32_t id:1; - uint32_t unused5:10; - uint32_t hi32_unused2; - }; - }; -} __attribute__ ((__packed__)) x86_reg_flags; - typedef enum x86_reg_cr0 { CR0_PE = (1L << 0), CR0_MP = (1L << 1), @@ -294,15 +256,11 @@ typedef struct lazy_flags { /* Definition of hvf_x86_state is here */ struct HVFX86EmulatorState { struct x86_register regs[16]; - struct x86_reg_flags rflags; struct lazy_flags lflags; uint8_t mmio_buf[4096]; }; /* useful register access macros */ -#define RFLAGS(cpu) (cpu->hvf_emul->rflags.rflags) -#define EFLAGS(cpu) (cpu->hvf_emul->rflags.eflags) - #define RRX(cpu, reg) (cpu->hvf_emul->regs[reg].rrx) #define RAX(cpu) RRX(cpu, R_EAX) #define RCX(cpu) RRX(cpu, R_ECX) diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 0efd9f9928..04fac64e72 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -459,7 +459,7 @@ static inline void string_increment_reg(struct CPUX86State *env, int reg, struct x86_decode *decode) { target_ulong val = read_reg(env, reg, decode->addressing_size); - if (env->hvf_emul->rflags.df) { + if (env->eflags & DF_MASK) { val -= decode->operand_size; } else { val += decode->operand_size; @@ -1432,7 +1432,7 @@ void load_regs(struct CPUState *cpu) RRX(env, i) = rreg(cpu->hvf_fd, HV_X86_RAX + i); } - RFLAGS(env) = rreg(cpu->hvf_fd, HV_X86_RFLAGS); + env->eflags = rreg(cpu->hvf_fd, HV_X86_RFLAGS); rflags_to_lflags(env); env->eip = rreg(cpu->hvf_fd, HV_X86_RIP); } @@ -1456,7 +1456,7 @@ void store_regs(struct CPUState *cpu) } lflags_to_rflags(env); - wreg(cpu->hvf_fd, HV_X86_RFLAGS, RFLAGS(env)); + wreg(cpu->hvf_fd, HV_X86_RFLAGS, env->eflags); macvm_set_rip(cpu, env->eip); } diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index ee6d33f861..1152cd7234 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -295,21 +295,21 @@ void set_SF(CPUX86State *env, bool val) void lflags_to_rflags(CPUX86State *env) { - env->hvf_emul->rflags.cf = get_CF(env); - env->hvf_emul->rflags.pf = get_PF(env); - env->hvf_emul->rflags.af = get_AF(env); - env->hvf_emul->rflags.zf = get_ZF(env); - env->hvf_emul->rflags.sf = get_SF(env); - env->hvf_emul->rflags.of = get_OF(env); + env->eflags |= get_CF(env) ? CC_C : 0; + env->eflags |= get_PF(env) ? CC_P : 0; + env->eflags |= get_AF(env) ? CC_A : 0; + env->eflags |= get_ZF(env) ? CC_Z : 0; + env->eflags |= get_SF(env) ? CC_S : 0; + env->eflags |= get_OF(env) ? CC_O : 0; } void rflags_to_lflags(CPUX86State *env) { env->hvf_emul->lflags.auxbits = env->hvf_emul->lflags.result = 0; - set_OF(env, env->hvf_emul->rflags.of); - set_SF(env, env->hvf_emul->rflags.sf); - set_ZF(env, env->hvf_emul->rflags.zf); - set_AF(env, env->hvf_emul->rflags.af); - set_PF(env, env->hvf_emul->rflags.pf); - set_CF(env, env->hvf_emul->rflags.cf); + set_OF(env, env->eflags & CC_O); + set_SF(env, env->eflags & CC_S); + set_ZF(env, env->eflags & CC_Z); + set_AF(env, env->eflags & CC_A); + set_PF(env, env->eflags & CC_P); + set_CF(env, env->eflags & CC_C); } diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c index 834baec3ea..6ea8508946 100644 --- a/target/i386/hvf/x86_task.c +++ b/target/i386/hvf/x86_task.c @@ -39,7 +39,7 @@ static void save_state_to_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) /* CR3 and ldt selector are not saved intentionally */ tss->eip = (uint32_t)env->eip; - tss->eflags = EFLAGS(env); + tss->eflags = (uint32_t)env->eflags; tss->eax = EAX(env); tss->ecx = ECX(env); tss->edx = EDX(env); @@ -65,7 +65,7 @@ static void load_state_from_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) wvmcs(cpu->hvf_fd, VMCS_GUEST_CR3, tss->cr3); env->eip = tss->eip; - EFLAGS(env) = tss->eflags | 2; + env->eflags = tss->eflags | 2; /* General purpose registers */ RAX(env) = tss->eax; @@ -158,7 +158,7 @@ void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int rea } if (reason == TSR_IRET) - EFLAGS(env) &= ~RFLAGS_NT; + env->eflags &= ~RFLAGS_NT; if (reason != TSR_CALL && reason != TSR_IDT_GATE) old_tss_sel.sel = 0xffff; diff --git a/target/i386/hvf/x86hvf.c b/target/i386/hvf/x86hvf.c index edefe5319a..5cbcb32ab6 100644 --- a/target/i386/hvf/x86hvf.c +++ b/target/i386/hvf/x86hvf.c @@ -412,7 +412,7 @@ bool hvf_inject_interrupts(CPUState *cpu_state) if (!(env->hflags & HF_INHIBIT_IRQ_MASK) && (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) && - (EFLAGS(env) & IF_MASK) && !(info & VMCS_INTR_VALID)) { + (env->eflags & IF_MASK) && !(info & VMCS_INTR_VALID)) { int line = cpu_get_pic_interrupt(&x86cpu->env); cpu_state->interrupt_request &= ~CPU_INTERRUPT_HARD; if (line >= 0) { @@ -432,7 +432,7 @@ int hvf_process_events(CPUState *cpu_state) X86CPU *cpu = X86_CPU(cpu_state); CPUX86State *env = &cpu->env; - EFLAGS(env) = rreg(cpu_state->hvf_fd, HV_X86_RFLAGS); + env->eflags = rreg(cpu_state->hvf_fd, HV_X86_RFLAGS); if (cpu_state->interrupt_request & CPU_INTERRUPT_INIT) { hvf_cpu_synchronize_state(cpu_state); @@ -444,7 +444,7 @@ int hvf_process_events(CPUState *cpu_state) apic_poll_irq(cpu->apic_state); } if (((cpu_state->interrupt_request & CPU_INTERRUPT_HARD) && - (EFLAGS(env) & IF_MASK)) || + (env->eflags & IF_MASK)) || (cpu_state->interrupt_request & CPU_INTERRUPT_NMI)) { cpu_state->halted = 0; } From ea48ae91210eae3cb7d3576d2dc8152529d5f962 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:54 +0300 Subject: [PATCH 1148/2595] i386: hvf: Drop copy of RFLAGS defines Use the ones provided in target/i386/cpu.h instead. Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-10-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86.c | 2 +- target/i386/hvf/x86.h | 20 -------------------- target/i386/hvf/x86_decode.c | 16 +++++++--------- target/i386/hvf/x86_task.c | 2 +- 4 files changed, 9 insertions(+), 31 deletions(-) diff --git a/target/i386/hvf/x86.c b/target/i386/hvf/x86.c index 7ebb5b45bd..fdb11c8db9 100644 --- a/target/i386/hvf/x86.c +++ b/target/i386/hvf/x86.c @@ -131,7 +131,7 @@ bool x86_is_v8086(struct CPUState *cpu) { X86CPU *x86_cpu = X86_CPU(cpu); CPUX86State *env = &x86_cpu->env; - return x86_is_protected(cpu) && (env->eflags & RFLAGS_VM); + return x86_is_protected(cpu) && (env->eflags & VM_MASK); } bool x86_is_long_mode(struct CPUState *cpu) diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index e309b8f203..f0d03faff9 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -42,26 +42,6 @@ typedef struct x86_register { }; } __attribute__ ((__packed__)) x86_register; -typedef enum x86_rflags { - RFLAGS_CF = (1L << 0), - RFLAGS_PF = (1L << 2), - RFLAGS_AF = (1L << 4), - RFLAGS_ZF = (1L << 6), - RFLAGS_SF = (1L << 7), - RFLAGS_TF = (1L << 8), - RFLAGS_IF = (1L << 9), - RFLAGS_DF = (1L << 10), - RFLAGS_OF = (1L << 11), - RFLAGS_IOPL = (3L << 12), - RFLAGS_NT = (1L << 14), - RFLAGS_RF = (1L << 16), - RFLAGS_VM = (1L << 17), - RFLAGS_AC = (1L << 18), - RFLAGS_VIF = (1L << 19), - RFLAGS_VIP = (1L << 20), - RFLAGS_ID = (1L << 21), -} x86_rflags; - typedef enum x86_reg_cr0 { CR0_PE = (1L << 0), CR0_MP = (1L << 1), diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index d881542181..34c5e3006c 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -697,15 +697,13 @@ static void decode_db_4(CPUX86State *env, struct x86_decode *decode) #define RFLAGS_MASK_NONE 0 -#define RFLAGS_MASK_OSZAPC (RFLAGS_OF | RFLAGS_SF | RFLAGS_ZF | RFLAGS_AF | \ - RFLAGS_PF | RFLAGS_CF) -#define RFLAGS_MASK_LAHF (RFLAGS_SF | RFLAGS_ZF | RFLAGS_AF | RFLAGS_PF | \ - RFLAGS_CF) -#define RFLAGS_MASK_CF (RFLAGS_CF) -#define RFLAGS_MASK_IF (RFLAGS_IF) -#define RFLAGS_MASK_TF (RFLAGS_TF) -#define RFLAGS_MASK_DF (RFLAGS_DF) -#define RFLAGS_MASK_ZF (RFLAGS_ZF) +#define RFLAGS_MASK_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C) +#define RFLAGS_MASK_LAHF (CC_S | CC_Z | CC_A | CC_P | CC_C) +#define RFLAGS_MASK_CF (CC_C) +#define RFLAGS_MASK_IF (IF_MASK) +#define RFLAGS_MASK_TF (TF_MASK) +#define RFLAGS_MASK_DF (DF_MASK) +#define RFLAGS_MASK_ZF (CC_Z) struct decode_tbl _1op_inst[] = { {0x0, X86_DECODE_CMD_ADD, 1, true, decode_modrm_rm, decode_modrm_reg, NULL, diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c index 6ea8508946..6f04478b3a 100644 --- a/target/i386/hvf/x86_task.c +++ b/target/i386/hvf/x86_task.c @@ -158,7 +158,7 @@ void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int rea } if (reason == TSR_IRET) - env->eflags &= ~RFLAGS_NT; + env->eflags &= ~NT_MASK; if (reason != TSR_CALL && reason != TSR_IDT_GATE) old_tss_sel.sel = 0xffff; From 167c6aef67dcf4f2d1c417db057ad95f84030180 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:55 +0300 Subject: [PATCH 1149/2595] i386: hvf: Drop regs in HVFX86EmulatorState HVFX86EmulatorState carries it's own copy of x86 registers. It can be dropped in favor of regs in generic CPUX86State. Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-11-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86.h | 13 +++++++------ target/i386/hvf/x86_emu.c | 18 +++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index f0d03faff9..6048b5cc74 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -235,13 +235,14 @@ typedef struct lazy_flags { /* Definition of hvf_x86_state is here */ struct HVFX86EmulatorState { - struct x86_register regs[16]; struct lazy_flags lflags; uint8_t mmio_buf[4096]; }; /* useful register access macros */ -#define RRX(cpu, reg) (cpu->hvf_emul->regs[reg].rrx) +#define x86_reg(cpu, reg) ((x86_register *) &cpu->regs[reg]) + +#define RRX(cpu, reg) (x86_reg(cpu, reg)->rrx) #define RAX(cpu) RRX(cpu, R_EAX) #define RCX(cpu) RRX(cpu, R_ECX) #define RDX(cpu) RRX(cpu, R_EDX) @@ -259,7 +260,7 @@ struct HVFX86EmulatorState { #define R14(cpu) RRX(cpu, R_R14) #define R15(cpu) RRX(cpu, R_R15) -#define ERX(cpu, reg) (cpu->hvf_emul->regs[reg].erx) +#define ERX(cpu, reg) (x86_reg(cpu, reg)->erx) #define EAX(cpu) ERX(cpu, R_EAX) #define ECX(cpu) ERX(cpu, R_ECX) #define EDX(cpu) ERX(cpu, R_EDX) @@ -269,7 +270,7 @@ struct HVFX86EmulatorState { #define ESI(cpu) ERX(cpu, R_ESI) #define EDI(cpu) ERX(cpu, R_EDI) -#define RX(cpu, reg) (cpu->hvf_emul->regs[reg].rx) +#define RX(cpu, reg) (x86_reg(cpu, reg)->rx) #define AX(cpu) RX(cpu, R_EAX) #define CX(cpu) RX(cpu, R_ECX) #define DX(cpu) RX(cpu, R_EDX) @@ -279,13 +280,13 @@ struct HVFX86EmulatorState { #define SI(cpu) RX(cpu, R_ESI) #define DI(cpu) RX(cpu, R_EDI) -#define RL(cpu, reg) (cpu->hvf_emul->regs[reg].lx) +#define RL(cpu, reg) (x86_reg(cpu, reg)->lx) #define AL(cpu) RL(cpu, R_EAX) #define CL(cpu) RL(cpu, R_ECX) #define DL(cpu) RL(cpu, R_EDX) #define BL(cpu) RL(cpu, R_EBX) -#define RH(cpu, reg) (cpu->hvf_emul->regs[reg].hx) +#define RH(cpu, reg) (x86_reg(cpu, reg)->hx) #define AH(cpu) RH(cpu, R_EAX) #define CH(cpu) RH(cpu, R_ECX) #define DH(cpu) RH(cpu, R_EDX) diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 04fac64e72..1ad2c30e16 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -95,13 +95,13 @@ target_ulong read_reg(CPUX86State *env, int reg, int size) { switch (size) { case 1: - return env->hvf_emul->regs[reg].lx; + return x86_reg(env, reg)->lx; case 2: - return env->hvf_emul->regs[reg].rx; + return x86_reg(env, reg)->rx; case 4: - return env->hvf_emul->regs[reg].erx; + return x86_reg(env, reg)->erx; case 8: - return env->hvf_emul->regs[reg].rrx; + return x86_reg(env, reg)->rrx; default: abort(); } @@ -112,16 +112,16 @@ void write_reg(CPUX86State *env, int reg, target_ulong val, int size) { switch (size) { case 1: - env->hvf_emul->regs[reg].lx = val; + x86_reg(env, reg)->lx = val; break; case 2: - env->hvf_emul->regs[reg].rx = val; + x86_reg(env, reg)->rx = val; break; case 4: - env->hvf_emul->regs[reg].rrx = (uint32_t)val; + x86_reg(env, reg)->rrx = (uint32_t)val; break; case 8: - env->hvf_emul->regs[reg].rrx = val; + x86_reg(env, reg)->rrx = val; break; default: abort(); @@ -173,7 +173,7 @@ void write_val_to_reg(target_ulong reg_ptr, target_ulong val, int size) static bool is_host_reg(struct CPUX86State *env, target_ulong ptr) { - return (ptr - (target_ulong)&env->hvf_emul->regs[0]) < sizeof(env->hvf_emul->regs); + return (ptr - (target_ulong)&env->regs[0]) < sizeof(env->regs); } void write_val_ext(struct CPUX86State *env, target_ulong ptr, target_ulong val, int size) From 577f02b89049c4a466973ae2785c6928e00798c8 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:56 +0300 Subject: [PATCH 1150/2595] i386: hvf: Move lazy_flags into CPUX86State The lazy flags are still needed for instruction decoder. Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-12-r.bolshakov@yadro.com> [Move struct to target/i386/cpu.h - Paolo] Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 6 ++++ target/i386/hvf/x86.h | 6 ---- target/i386/hvf/x86_flags.c | 57 ++++++++++++++++++------------------- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index c2b8bdcbde..f742ba933f 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1366,6 +1366,11 @@ typedef struct CPUCaches { CPUCacheInfo *l3_cache; } CPUCaches; +typedef struct HVFX86LazyFlags { + target_ulong result; + target_ulong auxbits; +} HVFX86LazyFlags; + typedef struct CPUX86State { /* standard registers */ target_ulong regs[CPU_NB_REGS]; @@ -1597,6 +1602,7 @@ typedef struct CPUX86State { struct kvm_nested_state *nested_state; #endif #if defined(CONFIG_HVF) + HVFX86LazyFlags hvf_lflags; HVFX86EmulatorState *hvf_emul; #endif diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index 6048b5cc74..2363616c07 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -228,14 +228,8 @@ typedef struct x68_segment_selector { }; } __attribute__ ((__packed__)) x68_segment_selector; -typedef struct lazy_flags { - target_ulong result; - target_ulong auxbits; -} lazy_flags; - /* Definition of hvf_x86_state is here */ struct HVFX86EmulatorState { - struct lazy_flags lflags; uint8_t mmio_buf[4096]; }; diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index 1152cd7234..5ca4f41f5c 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -63,7 +63,7 @@ #define SET_FLAGS_OSZAPC_SIZE(size, lf_carries, lf_result) { \ target_ulong temp = ((lf_carries) & (LF_MASK_AF)) | \ (((lf_carries) >> (size - 2)) << LF_BIT_PO); \ - env->hvf_emul->lflags.result = (target_ulong)(int##size##_t)(lf_result); \ + env->hvf_lflags.result = (target_ulong)(int##size##_t)(lf_result); \ if ((size) == 32) { \ temp = ((lf_carries) & ~(LF_MASK_PDB | LF_MASK_SD)); \ } else if ((size) == 16) { \ @@ -73,7 +73,7 @@ } else { \ VM_PANIC("unimplemented"); \ } \ - env->hvf_emul->lflags.auxbits = (target_ulong)(uint32_t)temp; \ + env->hvf_lflags.auxbits = (target_ulong)(uint32_t)temp; \ } /* carries, result */ @@ -100,10 +100,10 @@ } else { \ VM_PANIC("unimplemented"); \ } \ - env->hvf_emul->lflags.result = (target_ulong)(int##size##_t)(lf_result); \ - target_ulong delta_c = (env->hvf_emul->lflags.auxbits ^ temp) & LF_MASK_CF; \ + env->hvf_lflags.result = (target_ulong)(int##size##_t)(lf_result); \ + target_ulong delta_c = (env->hvf_lflags.auxbits ^ temp) & LF_MASK_CF; \ delta_c ^= (delta_c >> 1); \ - env->hvf_emul->lflags.auxbits = (target_ulong)(uint32_t)(temp ^ delta_c); \ + env->hvf_lflags.auxbits = (target_ulong)(uint32_t)(temp ^ delta_c); \ } /* carries, result */ @@ -117,9 +117,8 @@ void SET_FLAGS_OxxxxC(CPUX86State *env, uint32_t new_of, uint32_t new_cf) { uint32_t temp_po = new_of ^ new_cf; - env->hvf_emul->lflags.auxbits &= ~(LF_MASK_PO | LF_MASK_CF); - env->hvf_emul->lflags.auxbits |= (temp_po << LF_BIT_PO) | - (new_cf << LF_BIT_CF); + env->hvf_lflags.auxbits &= ~(LF_MASK_PO | LF_MASK_CF); + env->hvf_lflags.auxbits |= (temp_po << LF_BIT_PO) | (new_cf << LF_BIT_CF); } void SET_FLAGS_OSZAPC_SUB32(CPUX86State *env, uint32_t v1, uint32_t v2, @@ -215,27 +214,27 @@ void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t v1, uint8_t v2, bool get_PF(CPUX86State *env) { - uint32_t temp = (255 & env->hvf_emul->lflags.result); - temp = temp ^ (255 & (env->hvf_emul->lflags.auxbits >> LF_BIT_PDB)); + uint32_t temp = (255 & env->hvf_lflags.result); + temp = temp ^ (255 & (env->hvf_lflags.auxbits >> LF_BIT_PDB)); temp = (temp ^ (temp >> 4)) & 0x0F; return (0x9669U >> temp) & 1; } void set_PF(CPUX86State *env, bool val) { - uint32_t temp = (255 & env->hvf_emul->lflags.result) ^ (!val); - env->hvf_emul->lflags.auxbits &= ~(LF_MASK_PDB); - env->hvf_emul->lflags.auxbits |= (temp << LF_BIT_PDB); + uint32_t temp = (255 & env->hvf_lflags.result) ^ (!val); + env->hvf_lflags.auxbits &= ~(LF_MASK_PDB); + env->hvf_lflags.auxbits |= (temp << LF_BIT_PDB); } bool get_OF(CPUX86State *env) { - return ((env->hvf_emul->lflags.auxbits + (1U << LF_BIT_PO)) >> LF_BIT_CF) & 1; + return ((env->hvf_lflags.auxbits + (1U << LF_BIT_PO)) >> LF_BIT_CF) & 1; } bool get_CF(CPUX86State *env) { - return (env->hvf_emul->lflags.auxbits >> LF_BIT_CF) & 1; + return (env->hvf_lflags.auxbits >> LF_BIT_CF) & 1; } void set_OF(CPUX86State *env, bool val) @@ -252,45 +251,45 @@ void set_CF(CPUX86State *env, bool val) bool get_AF(CPUX86State *env) { - return (env->hvf_emul->lflags.auxbits >> LF_BIT_AF) & 1; + return (env->hvf_lflags.auxbits >> LF_BIT_AF) & 1; } void set_AF(CPUX86State *env, bool val) { - env->hvf_emul->lflags.auxbits &= ~(LF_MASK_AF); - env->hvf_emul->lflags.auxbits |= val << LF_BIT_AF; + env->hvf_lflags.auxbits &= ~(LF_MASK_AF); + env->hvf_lflags.auxbits |= val << LF_BIT_AF; } bool get_ZF(CPUX86State *env) { - return !env->hvf_emul->lflags.result; + return !env->hvf_lflags.result; } void set_ZF(CPUX86State *env, bool val) { if (val) { - env->hvf_emul->lflags.auxbits ^= - (((env->hvf_emul->lflags.result >> LF_SIGN_BIT) & 1) << LF_BIT_SD); + env->hvf_lflags.auxbits ^= + (((env->hvf_lflags.result >> LF_SIGN_BIT) & 1) << LF_BIT_SD); /* merge the parity bits into the Parity Delta Byte */ - uint32_t temp_pdb = (255 & env->hvf_emul->lflags.result); - env->hvf_emul->lflags.auxbits ^= (temp_pdb << LF_BIT_PDB); + uint32_t temp_pdb = (255 & env->hvf_lflags.result); + env->hvf_lflags.auxbits ^= (temp_pdb << LF_BIT_PDB); /* now zero the .result value */ - env->hvf_emul->lflags.result = 0; + env->hvf_lflags.result = 0; } else { - env->hvf_emul->lflags.result |= (1 << 8); + env->hvf_lflags.result |= (1 << 8); } } bool get_SF(CPUX86State *env) { - return ((env->hvf_emul->lflags.result >> LF_SIGN_BIT) ^ - (env->hvf_emul->lflags.auxbits >> LF_BIT_SD)) & 1; + return ((env->hvf_lflags.result >> LF_SIGN_BIT) ^ + (env->hvf_lflags.auxbits >> LF_BIT_SD)) & 1; } void set_SF(CPUX86State *env, bool val) { bool temp_sf = get_SF(env); - env->hvf_emul->lflags.auxbits ^= (temp_sf ^ val) << LF_BIT_SD; + env->hvf_lflags.auxbits ^= (temp_sf ^ val) << LF_BIT_SD; } void lflags_to_rflags(CPUX86State *env) @@ -305,7 +304,7 @@ void lflags_to_rflags(CPUX86State *env) void rflags_to_lflags(CPUX86State *env) { - env->hvf_emul->lflags.auxbits = env->hvf_emul->lflags.result = 0; + env->hvf_lflags.auxbits = env->hvf_lflags.result = 0; set_OF(env, env->eflags & CC_O); set_SF(env, env->eflags & CC_S); set_ZF(env, env->eflags & CC_Z); From fe76b09c5b600310639af7ec614fb1303c773e5f Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:57 +0300 Subject: [PATCH 1151/2595] i386: hvf: Move mmio_buf into CPUX86State There's no similar field in CPUX86State, but it's needed for MMIO traps. Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-13-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 1 + target/i386/hvf/hvf.c | 5 +++++ target/i386/hvf/x86.h | 1 - target/i386/hvf/x86_emu.c | 12 ++++++------ 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index f742ba933f..25a2f4c0c3 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1603,6 +1603,7 @@ typedef struct CPUX86State { #endif #if defined(CONFIG_HVF) HVFX86LazyFlags hvf_lflags; + void *hvf_mmio_buf; HVFX86EmulatorState *hvf_emul; #endif diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 4cee496d71..57696c46c7 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -533,7 +533,11 @@ void hvf_reset_vcpu(CPUState *cpu) { void hvf_vcpu_destroy(CPUState *cpu) { + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + hv_return_t ret = hv_vcpu_destroy((hv_vcpuid_t)cpu->hvf_fd); + g_free(env->hvf_mmio_buf); assert_hvf_ok(ret); } @@ -563,6 +567,7 @@ int hvf_init_vcpu(CPUState *cpu) init_decoder(); hvf_state->hvf_caps = g_new0(struct hvf_vcpu_caps, 1); + env->hvf_mmio_buf = g_new(char, 4096); env->hvf_emul = g_new0(HVFX86EmulatorState, 1); r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf_fd, HV_VCPU_DEFAULT); diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index 2363616c07..483fcea762 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -230,7 +230,6 @@ typedef struct x68_segment_selector { /* Definition of hvf_x86_state is here */ struct HVFX86EmulatorState { - uint8_t mmio_buf[4096]; }; /* useful register access macros */ diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 1ad2c30e16..d3e289ed87 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -187,8 +187,8 @@ void write_val_ext(struct CPUX86State *env, target_ulong ptr, target_ulong val, uint8_t *read_mmio(struct CPUX86State *env, target_ulong ptr, int bytes) { - vmx_read_mem(env_cpu(env), env->hvf_emul->mmio_buf, ptr, bytes); - return env->hvf_emul->mmio_buf; + vmx_read_mem(env_cpu(env), env->hvf_mmio_buf, ptr, bytes); + return env->hvf_mmio_buf; } @@ -489,9 +489,9 @@ static void exec_ins_single(struct CPUX86State *env, struct x86_decode *decode) target_ulong addr = linear_addr_size(env_cpu(env), RDI(env), decode->addressing_size, R_ES); - hvf_handle_io(env_cpu(env), DX(env), env->hvf_emul->mmio_buf, 0, + hvf_handle_io(env_cpu(env), DX(env), env->hvf_mmio_buf, 0, decode->operand_size, 1); - vmx_write_mem(env_cpu(env), addr, env->hvf_emul->mmio_buf, + vmx_write_mem(env_cpu(env), addr, env->hvf_mmio_buf, decode->operand_size); string_increment_reg(env, R_EDI, decode); @@ -512,9 +512,9 @@ static void exec_outs_single(struct CPUX86State *env, struct x86_decode *decode) { target_ulong addr = decode_linear_addr(env, decode, RSI(env), R_DS); - vmx_read_mem(env_cpu(env), env->hvf_emul->mmio_buf, addr, + vmx_read_mem(env_cpu(env), env->hvf_mmio_buf, addr, decode->operand_size); - hvf_handle_io(env_cpu(env), DX(env), env->hvf_emul->mmio_buf, 1, + hvf_handle_io(env_cpu(env), DX(env), env->hvf_mmio_buf, 1, decode->operand_size, 1); string_increment_reg(env, R_ESI, decode); From e77cb0bb204c18c04a8290e03181510bbbfc683a Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 28 May 2020 22:37:58 +0300 Subject: [PATCH 1152/2595] i386: hvf: Drop HVFX86EmulatorState Signed-off-by: Roman Bolshakov Message-Id: <20200528193758.51454-14-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- include/qemu/typedefs.h | 1 - target/i386/cpu.h | 1 - target/i386/hvf/hvf.c | 1 - target/i386/hvf/x86.h | 4 ---- 4 files changed, 7 deletions(-) diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index de68d51d52..ce4a78b687 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -51,7 +51,6 @@ typedef struct FWCfgIoState FWCfgIoState; typedef struct FWCfgMemState FWCfgMemState; typedef struct FWCfgState FWCfgState; typedef struct HostMemoryBackend HostMemoryBackend; -typedef struct HVFX86EmulatorState HVFX86EmulatorState; typedef struct I2CBus I2CBus; typedef struct I2SCodec I2SCodec; typedef struct IOMMUMemoryRegion IOMMUMemoryRegion; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 25a2f4c0c3..7d77efd9e4 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1604,7 +1604,6 @@ typedef struct CPUX86State { #if defined(CONFIG_HVF) HVFX86LazyFlags hvf_lflags; void *hvf_mmio_buf; - HVFX86EmulatorState *hvf_emul; #endif uint64_t mcg_cap; diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 57696c46c7..be016b951a 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -568,7 +568,6 @@ int hvf_init_vcpu(CPUState *cpu) hvf_state->hvf_caps = g_new0(struct hvf_vcpu_caps, 1); env->hvf_mmio_buf = g_new(char, 4096); - env->hvf_emul = g_new0(HVFX86EmulatorState, 1); r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf_fd, HV_VCPU_DEFAULT); cpu->vcpu_dirty = 1; diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index 483fcea762..bacade7b65 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -228,10 +228,6 @@ typedef struct x68_segment_selector { }; } __attribute__ ((__packed__)) x68_segment_selector; -/* Definition of hvf_x86_state is here */ -struct HVFX86EmulatorState { -}; - /* useful register access macros */ #define x86_reg(cpu, reg) ((x86_register *) &cpu->regs[reg]) From acd0c9416d4846afc541605ee0e75ca163773e6c Mon Sep 17 00:00:00 2001 From: Anthony PERARD Date: Wed, 3 Jun 2020 17:04:42 +0100 Subject: [PATCH 1153/2595] xen: fix build without pci passthrough MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Xen PCI passthrough support may not be available and thus the global variable "has_igd_gfx_passthru" might be compiled out. Common code should not access it in that case. Unfortunately, we can't use CONFIG_XEN_PCI_PASSTHROUGH directly in xen-common.c so this patch instead move access to the has_igd_gfx_passthru variable via function and those functions are also implemented as stubs. The stubs will be used when QEMU is built without passthrough support. Now, when one will want to enable igd-passthru via the -machine property, they will get an error message if QEMU is built without passthrough support. Fixes: 46472d82322d0 ('xen: convert "-machine igd-passthru" to an accelerator property') Reported-by: Roger Pau Monné Signed-off-by: Anthony PERARD Message-Id: <20200603160442.3151170-1-anthony.perard@citrix.com> Signed-off-by: Paolo Bonzini --- accel/xen/xen-all.c | 4 ++-- hw/Makefile.objs | 2 +- hw/i386/pc_piix.c | 2 +- hw/xen/Makefile.objs | 3 ++- hw/xen/xen_pt.c | 12 +++++++++++- hw/xen/xen_pt.h | 6 ++++-- hw/xen/xen_pt_stub.c | 22 ++++++++++++++++++++++ 7 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 hw/xen/xen_pt_stub.c diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c index f3edc65ec9..0c24d4b191 100644 --- a/accel/xen/xen-all.c +++ b/accel/xen/xen-all.c @@ -137,12 +137,12 @@ static void xen_change_state_handler(void *opaque, int running, static bool xen_get_igd_gfx_passthru(Object *obj, Error **errp) { - return has_igd_gfx_passthru; + return xen_igd_gfx_pt_enabled(); } static void xen_set_igd_gfx_passthru(Object *obj, bool value, Error **errp) { - has_igd_gfx_passthru = value; + xen_igd_gfx_pt_set(value, errp); } static void xen_setup_post(MachineState *ms, AccelState *accel) diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 660e2b4373..4cbe5e4e57 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -35,7 +35,7 @@ devices-dirs-y += usb/ devices-dirs-$(CONFIG_VFIO) += vfio/ devices-dirs-y += virtio/ devices-dirs-y += watchdog/ -devices-dirs-y += xen/ +devices-dirs-$(CONFIG_XEN) += xen/ devices-dirs-$(CONFIG_MEM_DEVICE) += mem/ devices-dirs-$(CONFIG_NUBUS) += nubus/ devices-dirs-y += semihosting/ diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index eea964e72b..054d3aa9f7 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -377,7 +377,7 @@ static void pc_init_isa(MachineState *machine) #ifdef CONFIG_XEN static void pc_xen_hvm_init_pci(MachineState *machine) { - const char *pci_type = has_igd_gfx_passthru ? + const char *pci_type = xen_igd_gfx_pt_enabled() ? TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE : TYPE_I440FX_PCI_DEVICE; pc_init1(machine, diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index 340b2c5096..3fc715e595 100644 --- a/hw/xen/Makefile.objs +++ b/hw/xen/Makefile.objs @@ -1,6 +1,7 @@ # xen backend driver support -common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-bus.o xen-bus-helper.o xen-backend.o +common-obj-y += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-bus.o xen-bus-helper.o xen-backend.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt_load_rom.o +obj-$(call $(lnot, $(CONFIG_XEN_PCI_PASSTHROUGH))) += xen_pt_stub.o diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 81d5ad8da7..ab84443d5e 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -65,7 +65,17 @@ #include "qemu/range.h" #include "exec/address-spaces.h" -bool has_igd_gfx_passthru; +static bool has_igd_gfx_passthru; + +bool xen_igd_gfx_pt_enabled(void) +{ + return has_igd_gfx_passthru; +} + +void xen_igd_gfx_pt_set(bool value, Error **errp) +{ + has_igd_gfx_passthru = value; +} #define XEN_PT_NR_IRQS (256) static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0}; diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index 179775db7b..6e9cec95f3 100644 --- a/hw/xen/xen_pt.h +++ b/hw/xen/xen_pt.h @@ -5,6 +5,9 @@ #include "hw/pci/pci.h" #include "xen-host-pci-device.h" +bool xen_igd_gfx_pt_enabled(void); +void xen_igd_gfx_pt_set(bool value, Error **errp); + void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3); #define XEN_PT_ERR(d, _f, _a...) xen_pt_log(d, "%s: Error: "_f, __func__, ##_a) @@ -322,10 +325,9 @@ extern void *pci_assign_dev_load_option_rom(PCIDevice *dev, unsigned int domain, unsigned int bus, unsigned int slot, unsigned int function); -extern bool has_igd_gfx_passthru; static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev) { - return (has_igd_gfx_passthru + return (xen_igd_gfx_pt_enabled() && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA)); } int xen_pt_register_vga_regions(XenHostPCIDevice *dev); diff --git a/hw/xen/xen_pt_stub.c b/hw/xen/xen_pt_stub.c new file mode 100644 index 0000000000..2d8cac8d54 --- /dev/null +++ b/hw/xen/xen_pt_stub.c @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020 Citrix Systems UK Ltd. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/xen/xen_pt.h" +#include "qapi/error.h" + +bool xen_igd_gfx_pt_enabled(void) +{ + return false; +} + +void xen_igd_gfx_pt_set(bool value, Error **errp) +{ + if (value) { + error_setg(errp, "Xen PCI passthrough support not built in"); + } +} From b5b9b1ad4648b625cee25ef5c4cac2a7588d9c04 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 4 Jun 2020 16:42:11 +1000 Subject: [PATCH 1154/2595] target/i386: sev: Remove unused QSevGuestInfoClass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This structure is nothing but an empty wrapper around the parent class, which by QOM conventions means we don't need it at all. Signed-off-by: David Gibson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200604064219.436242-2-david@gibson.dropbear.id.au> Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 1 - target/i386/sev_i386.h | 5 ----- 2 files changed, 6 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index 51cdbe5496..2312510cf2 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -287,7 +287,6 @@ static const TypeInfo qsev_guest_info = { .name = TYPE_QSEV_GUEST_INFO, .instance_size = sizeof(QSevGuestInfo), .instance_finalize = qsev_guest_finalize, - .class_size = sizeof(QSevGuestInfoClass), .class_init = qsev_guest_class_init, .instance_init = qsev_guest_init, .interfaces = (InterfaceInfo[]) { diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h index 8ada9d385d..4f193642ac 100644 --- a/target/i386/sev_i386.h +++ b/target/i386/sev_i386.h @@ -41,7 +41,6 @@ extern char *sev_get_launch_measurement(void); extern SevCapability *sev_get_capabilities(void); typedef struct QSevGuestInfo QSevGuestInfo; -typedef struct QSevGuestInfoClass QSevGuestInfoClass; /** * QSevGuestInfo: @@ -64,10 +63,6 @@ struct QSevGuestInfo { uint32_t reduced_phys_bits; }; -struct QSevGuestInfoClass { - ObjectClass parent_class; -}; - struct SEVState { QSevGuestInfo *sev_info; uint8_t api_major; From a86ab19d4a955ab5c7e9df56801c9c580a009148 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 4 Jun 2020 16:42:12 +1000 Subject: [PATCH 1155/2595] target/i386: sev: Move local structure definitions into .c file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neither QSevGuestInfo nor SEVState (not to be confused with SevState) is used anywhere outside target/i386/sev.c, so they might as well live in there rather than in a (somewhat) exposed header. Signed-off-by: David Gibson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200604064219.436242-3-david@gibson.dropbear.id.au> Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 44 ++++++++++++++++++++++++++++++++++++++++++ target/i386/sev_i386.h | 44 ------------------------------------------ 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index 2312510cf2..53def5f41a 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -29,6 +29,50 @@ #include "trace.h" #include "migration/blocker.h" +#define TYPE_QSEV_GUEST_INFO "sev-guest" +#define QSEV_GUEST_INFO(obj) \ + OBJECT_CHECK(QSevGuestInfo, (obj), TYPE_QSEV_GUEST_INFO) + +typedef struct QSevGuestInfo QSevGuestInfo; + +/** + * QSevGuestInfo: + * + * The QSevGuestInfo object is used for creating a SEV guest. + * + * # $QEMU \ + * -object sev-guest,id=sev0 \ + * -machine ...,memory-encryption=sev0 + */ +struct QSevGuestInfo { + Object parent_obj; + + char *sev_device; + uint32_t policy; + uint32_t handle; + char *dh_cert_file; + char *session_file; + uint32_t cbitpos; + uint32_t reduced_phys_bits; +}; + +struct SEVState { + QSevGuestInfo *sev_info; + uint8_t api_major; + uint8_t api_minor; + uint8_t build_id; + uint32_t policy; + uint64_t me_mask; + uint32_t cbitpos; + uint32_t reduced_phys_bits; + uint32_t handle; + int sev_fd; + SevState state; + gchar *measurement; +}; + +typedef struct SEVState SEVState; + #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ #define DEFAULT_SEV_DEVICE "/dev/sev" diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h index 4f193642ac..8eb7de1bef 100644 --- a/target/i386/sev_i386.h +++ b/target/i386/sev_i386.h @@ -28,10 +28,6 @@ #define SEV_POLICY_DOMAIN 0x10 #define SEV_POLICY_SEV 0x20 -#define TYPE_QSEV_GUEST_INFO "sev-guest" -#define QSEV_GUEST_INFO(obj) \ - OBJECT_CHECK(QSevGuestInfo, (obj), TYPE_QSEV_GUEST_INFO) - extern bool sev_enabled(void); extern uint64_t sev_get_me_mask(void); extern SevInfo *sev_get_info(void); @@ -40,44 +36,4 @@ extern uint32_t sev_get_reduced_phys_bits(void); extern char *sev_get_launch_measurement(void); extern SevCapability *sev_get_capabilities(void); -typedef struct QSevGuestInfo QSevGuestInfo; - -/** - * QSevGuestInfo: - * - * The QSevGuestInfo object is used for creating a SEV guest. - * - * # $QEMU \ - * -object sev-guest,id=sev0 \ - * -machine ...,memory-encryption=sev0 - */ -struct QSevGuestInfo { - Object parent_obj; - - char *sev_device; - uint32_t policy; - uint32_t handle; - char *dh_cert_file; - char *session_file; - uint32_t cbitpos; - uint32_t reduced_phys_bits; -}; - -struct SEVState { - QSevGuestInfo *sev_info; - uint8_t api_major; - uint8_t api_minor; - uint8_t build_id; - uint32_t policy; - uint64_t me_mask; - uint32_t cbitpos; - uint32_t reduced_phys_bits; - uint32_t handle; - int sev_fd; - SevState state; - gchar *measurement; -}; - -typedef struct SEVState SEVState; - #endif From d2d8a1984d7954f10f878dd8b9f6f01069c20d33 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 4 Jun 2020 16:42:13 +1000 Subject: [PATCH 1156/2595] target/i386: sev: Rename QSevGuestInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the moment this is a purely passive object which is just a container for information used elsewhere, hence the name. I'm going to change that though, so as a preliminary rename it to SevGuestState. That name risks confusion with both SEVState and SevState, but I'll be working on that in following patches. Signed-off-by: David Gibson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200604064219.436242-4-david@gibson.dropbear.id.au> Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 87 ++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index 53def5f41a..b6ed719fb5 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -29,22 +29,23 @@ #include "trace.h" #include "migration/blocker.h" -#define TYPE_QSEV_GUEST_INFO "sev-guest" -#define QSEV_GUEST_INFO(obj) \ - OBJECT_CHECK(QSevGuestInfo, (obj), TYPE_QSEV_GUEST_INFO) +#define TYPE_SEV_GUEST "sev-guest" +#define SEV_GUEST(obj) \ + OBJECT_CHECK(SevGuestState, (obj), TYPE_SEV_GUEST) -typedef struct QSevGuestInfo QSevGuestInfo; +typedef struct SevGuestState SevGuestState; /** - * QSevGuestInfo: + * SevGuestState: * - * The QSevGuestInfo object is used for creating a SEV guest. + * The SevGuestState object is used for creating and managing a SEV + * guest. * * # $QEMU \ * -object sev-guest,id=sev0 \ * -machine ...,memory-encryption=sev0 */ -struct QSevGuestInfo { +struct SevGuestState { Object parent_obj; char *sev_device; @@ -57,7 +58,7 @@ struct QSevGuestInfo { }; struct SEVState { - QSevGuestInfo *sev_info; + SevGuestState *sev_info; uint8_t api_major; uint8_t api_minor; uint8_t build_id; @@ -235,82 +236,82 @@ static struct RAMBlockNotifier sev_ram_notifier = { }; static void -qsev_guest_finalize(Object *obj) +sev_guest_finalize(Object *obj) { } static char * -qsev_guest_get_session_file(Object *obj, Error **errp) +sev_guest_get_session_file(Object *obj, Error **errp) { - QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + SevGuestState *s = SEV_GUEST(obj); return s->session_file ? g_strdup(s->session_file) : NULL; } static void -qsev_guest_set_session_file(Object *obj, const char *value, Error **errp) +sev_guest_set_session_file(Object *obj, const char *value, Error **errp) { - QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + SevGuestState *s = SEV_GUEST(obj); s->session_file = g_strdup(value); } static char * -qsev_guest_get_dh_cert_file(Object *obj, Error **errp) +sev_guest_get_dh_cert_file(Object *obj, Error **errp) { - QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + SevGuestState *s = SEV_GUEST(obj); return g_strdup(s->dh_cert_file); } static void -qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp) +sev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp) { - QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + SevGuestState *s = SEV_GUEST(obj); s->dh_cert_file = g_strdup(value); } static char * -qsev_guest_get_sev_device(Object *obj, Error **errp) +sev_guest_get_sev_device(Object *obj, Error **errp) { - QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + SevGuestState *sev = SEV_GUEST(obj); return g_strdup(sev->sev_device); } static void -qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp) +sev_guest_set_sev_device(Object *obj, const char *value, Error **errp) { - QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + SevGuestState *sev = SEV_GUEST(obj); sev->sev_device = g_strdup(value); } static void -qsev_guest_class_init(ObjectClass *oc, void *data) +sev_guest_class_init(ObjectClass *oc, void *data) { object_class_property_add_str(oc, "sev-device", - qsev_guest_get_sev_device, - qsev_guest_set_sev_device); + sev_guest_get_sev_device, + sev_guest_set_sev_device); object_class_property_set_description(oc, "sev-device", "SEV device to use"); object_class_property_add_str(oc, "dh-cert-file", - qsev_guest_get_dh_cert_file, - qsev_guest_set_dh_cert_file); + sev_guest_get_dh_cert_file, + sev_guest_set_dh_cert_file); object_class_property_set_description(oc, "dh-cert-file", "guest owners DH certificate (encoded with base64)"); object_class_property_add_str(oc, "session-file", - qsev_guest_get_session_file, - qsev_guest_set_session_file); + sev_guest_get_session_file, + sev_guest_set_session_file); object_class_property_set_description(oc, "session-file", "guest owners session parameters (encoded with base64)"); } static void -qsev_guest_init(Object *obj) +sev_guest_instance_init(Object *obj) { - QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + SevGuestState *sev = SEV_GUEST(obj); sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE); sev->policy = DEFAULT_GUEST_POLICY; @@ -326,32 +327,32 @@ qsev_guest_init(Object *obj) } /* sev guest info */ -static const TypeInfo qsev_guest_info = { +static const TypeInfo sev_guest_info = { .parent = TYPE_OBJECT, - .name = TYPE_QSEV_GUEST_INFO, - .instance_size = sizeof(QSevGuestInfo), - .instance_finalize = qsev_guest_finalize, - .class_init = qsev_guest_class_init, - .instance_init = qsev_guest_init, + .name = TYPE_SEV_GUEST, + .instance_size = sizeof(SevGuestState), + .instance_finalize = sev_guest_finalize, + .class_init = sev_guest_class_init, + .instance_init = sev_guest_instance_init, .interfaces = (InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } }; -static QSevGuestInfo * +static SevGuestState * lookup_sev_guest_info(const char *id) { Object *obj; - QSevGuestInfo *info; + SevGuestState *info; obj = object_resolve_path_component(object_get_objects_root(), id); if (!obj) { return NULL; } - info = (QSevGuestInfo *) - object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO); + info = (SevGuestState *) + object_dynamic_cast(obj, TYPE_SEV_GUEST); if (!info) { return NULL; } @@ -510,7 +511,7 @@ sev_launch_start(SEVState *s) gsize sz; int ret = 1; int fw_error, rc; - QSevGuestInfo *sev = s->sev_info; + SevGuestState *sev = s->sev_info; struct kvm_sev_launch_start *start; guchar *session = NULL, *dh_cert = NULL; @@ -696,7 +697,7 @@ sev_guest_init(const char *id) s->sev_info = lookup_sev_guest_info(id); if (!s->sev_info) { error_report("%s: '%s' is not a valid '%s' object", - __func__, id, TYPE_QSEV_GUEST_INFO); + __func__, id, TYPE_SEV_GUEST); goto err; } @@ -786,7 +787,7 @@ sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len) static void sev_register_types(void) { - type_register_static(&qsev_guest_info); + type_register_static(&sev_guest_info); } type_init(sev_register_types); From 75a877e3b14a8575fd6bc99d193f7fcc03eee94b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 4 Jun 2020 16:42:14 +1000 Subject: [PATCH 1157/2595] target/i386: sev: Embed SEVState in SevGuestState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently SevGuestState contains only configuration information. For runtime state another non-QOM struct SEVState is allocated separately. Simplify things by instead embedding the SEVState structure in SevGuestState. Signed-off-by: David Gibson Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200604064219.436242-5-david@gibson.dropbear.id.au> Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 68 +++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index b6ed719fb5..b4ab9720d6 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -35,30 +35,7 @@ typedef struct SevGuestState SevGuestState; -/** - * SevGuestState: - * - * The SevGuestState object is used for creating and managing a SEV - * guest. - * - * # $QEMU \ - * -object sev-guest,id=sev0 \ - * -machine ...,memory-encryption=sev0 - */ -struct SevGuestState { - Object parent_obj; - - char *sev_device; - uint32_t policy; - uint32_t handle; - char *dh_cert_file; - char *session_file; - uint32_t cbitpos; - uint32_t reduced_phys_bits; -}; - struct SEVState { - SevGuestState *sev_info; uint8_t api_major; uint8_t api_minor; uint8_t build_id; @@ -74,6 +51,32 @@ struct SEVState { typedef struct SEVState SEVState; +/** + * SevGuestState: + * + * The SevGuestState object is used for creating and managing a SEV + * guest. + * + * # $QEMU \ + * -object sev-guest,id=sev0 \ + * -machine ...,memory-encryption=sev0 + */ +struct SevGuestState { + Object parent_obj; + + /* configuration parameters */ + char *sev_device; + uint32_t policy; + uint32_t handle; + char *dh_cert_file; + char *session_file; + uint32_t cbitpos; + uint32_t reduced_phys_bits; + + /* runtime state */ + SEVState state; +}; + #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ #define DEFAULT_SEV_DEVICE "/dev/sev" @@ -506,12 +509,12 @@ sev_read_file_base64(const char *filename, guchar **data, gsize *len) } static int -sev_launch_start(SEVState *s) +sev_launch_start(SevGuestState *sev) { + SEVState *s = &sev->state; gsize sz; int ret = 1; int fw_error, rc; - SevGuestState *sev = s->sev_info; struct kvm_sev_launch_start *start; guchar *session = NULL, *dh_cert = NULL; @@ -686,6 +689,7 @@ sev_vm_state_change(void *opaque, int running, RunState state) void * sev_guest_init(const char *id) { + SevGuestState *sev; SEVState *s; char *devname; int ret, fw_error; @@ -693,27 +697,27 @@ sev_guest_init(const char *id) uint32_t host_cbitpos; struct sev_user_data_status status = {}; - sev_state = s = g_new0(SEVState, 1); - s->sev_info = lookup_sev_guest_info(id); - if (!s->sev_info) { + sev = lookup_sev_guest_info(id); + if (!sev) { error_report("%s: '%s' is not a valid '%s' object", __func__, id, TYPE_SEV_GUEST); goto err; } + sev_state = s = &sev->state; s->state = SEV_STATE_UNINIT; host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL); host_cbitpos = ebx & 0x3f; - s->cbitpos = object_property_get_int(OBJECT(s->sev_info), "cbitpos", NULL); + s->cbitpos = object_property_get_int(OBJECT(sev), "cbitpos", NULL); if (host_cbitpos != s->cbitpos) { error_report("%s: cbitpos check failed, host '%d' requested '%d'", __func__, host_cbitpos, s->cbitpos); goto err; } - s->reduced_phys_bits = object_property_get_int(OBJECT(s->sev_info), + s->reduced_phys_bits = object_property_get_int(OBJECT(sev), "reduced-phys-bits", NULL); if (s->reduced_phys_bits < 1) { error_report("%s: reduced_phys_bits check failed, it should be >=1," @@ -723,7 +727,7 @@ sev_guest_init(const char *id) s->me_mask = ~(1UL << s->cbitpos); - devname = object_property_get_str(OBJECT(s->sev_info), "sev-device", NULL); + devname = object_property_get_str(OBJECT(sev), "sev-device", NULL); s->sev_fd = open(devname, O_RDWR); if (s->sev_fd < 0) { error_report("%s: Failed to open %s '%s'", __func__, @@ -754,7 +758,7 @@ sev_guest_init(const char *id) goto err; } - ret = sev_launch_start(s); + ret = sev_launch_start(sev); if (ret) { error_report("%s: failed to create encryption context", __func__); goto err; From 8673dee354271a4f30f68059bfbbbea3d21e1a73 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 4 Jun 2020 16:42:15 +1000 Subject: [PATCH 1158/2595] target/i386: sev: Partial cleanup to sev_state global MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SEV code uses a pretty ugly global to access its internal state. Now that SEVState is embedded in SevGuestState, we can avoid accessing it via the global in some cases. In the remaining cases use a new global referencing the containing SevGuestState which will simplify some future transformations. Signed-off-by: David Gibson Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200604064219.436242-6-david@gibson.dropbear.id.au> Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 92 ++++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index b4ab9720d6..9e8ab7b056 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -80,7 +80,7 @@ struct SevGuestState { #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ #define DEFAULT_SEV_DEVICE "/dev/sev" -static SEVState *sev_state; +static SevGuestState *sev_guest; static Error *sev_mig_blocker; static const char *const sev_fw_errlist[] = { @@ -159,21 +159,21 @@ fw_error_to_str(int code) } static bool -sev_check_state(SevState state) +sev_check_state(const SevGuestState *sev, SevState state) { - assert(sev_state); - return sev_state->state == state ? true : false; + assert(sev); + return sev->state.state == state ? true : false; } static void -sev_set_guest_state(SevState new_state) +sev_set_guest_state(SevGuestState *sev, SevState new_state) { assert(new_state < SEV_STATE__MAX); - assert(sev_state); + assert(sev); - trace_kvm_sev_change_state(SevState_str(sev_state->state), + trace_kvm_sev_change_state(SevState_str(sev->state.state), SevState_str(new_state)); - sev_state->state = new_state; + sev->state.state = new_state; } static void @@ -366,25 +366,25 @@ lookup_sev_guest_info(const char *id) bool sev_enabled(void) { - return sev_state ? true : false; + return !!sev_guest; } uint64_t sev_get_me_mask(void) { - return sev_state ? sev_state->me_mask : ~0; + return sev_guest ? sev_guest->state.me_mask : ~0; } uint32_t sev_get_cbit_position(void) { - return sev_state ? sev_state->cbitpos : 0; + return sev_guest ? sev_guest->state.cbitpos : 0; } uint32_t sev_get_reduced_phys_bits(void) { - return sev_state ? sev_state->reduced_phys_bits : 0; + return sev_guest ? sev_guest->state.reduced_phys_bits : 0; } SevInfo * @@ -393,15 +393,15 @@ sev_get_info(void) SevInfo *info; info = g_new0(SevInfo, 1); - info->enabled = sev_state ? true : false; + info->enabled = sev_enabled(); if (info->enabled) { - info->api_major = sev_state->api_major; - info->api_minor = sev_state->api_minor; - info->build_id = sev_state->build_id; - info->policy = sev_state->policy; - info->state = sev_state->state; - info->handle = sev_state->handle; + info->api_major = sev_guest->state.api_major; + info->api_minor = sev_guest->state.api_minor; + info->build_id = sev_guest->state.build_id; + info->policy = sev_guest->state.policy; + info->state = sev_guest->state.state; + info->handle = sev_guest->state.handle; } return info; @@ -550,7 +550,7 @@ sev_launch_start(SevGuestState *sev) object_property_set_int(OBJECT(sev), start->handle, "handle", &error_abort); - sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE); + sev_set_guest_state(sev, SEV_STATE_LAUNCH_UPDATE); s->handle = start->handle; s->policy = start->policy; ret = 0; @@ -563,7 +563,7 @@ out: } static int -sev_launch_update_data(uint8_t *addr, uint64_t len) +sev_launch_update_data(SevGuestState *sev, uint8_t *addr, uint64_t len) { int ret, fw_error; struct kvm_sev_launch_update_data update; @@ -575,7 +575,7 @@ sev_launch_update_data(uint8_t *addr, uint64_t len) update.uaddr = (__u64)(unsigned long)addr; update.len = len; trace_kvm_sev_launch_update_data(addr, len); - ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA, + ret = sev_ioctl(sev->state.sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA, &update, &fw_error); if (ret) { error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'", @@ -588,19 +588,20 @@ sev_launch_update_data(uint8_t *addr, uint64_t len) static void sev_launch_get_measure(Notifier *notifier, void *unused) { + SevGuestState *sev = sev_guest; int ret, error; guchar *data; - SEVState *s = sev_state; + SEVState *s = &sev->state; struct kvm_sev_launch_measure *measurement; - if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) { + if (!sev_check_state(sev, SEV_STATE_LAUNCH_UPDATE)) { return; } measurement = g_new0(struct kvm_sev_launch_measure, 1); /* query the measurement blob length */ - ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE, + ret = sev_ioctl(sev->state.sev_fd, KVM_SEV_LAUNCH_MEASURE, measurement, &error); if (!measurement->len) { error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'", @@ -612,7 +613,7 @@ sev_launch_get_measure(Notifier *notifier, void *unused) measurement->uaddr = (unsigned long)data; /* get the measurement blob */ - ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE, + ret = sev_ioctl(sev->state.sev_fd, KVM_SEV_LAUNCH_MEASURE, measurement, &error); if (ret) { error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'", @@ -620,7 +621,7 @@ sev_launch_get_measure(Notifier *notifier, void *unused) goto free_data; } - sev_set_guest_state(SEV_STATE_LAUNCH_SECRET); + sev_set_guest_state(sev, SEV_STATE_LAUNCH_SECRET); /* encode the measurement value and emit the event */ s->measurement = g_base64_encode(data, measurement->len); @@ -635,9 +636,9 @@ free_measurement: char * sev_get_launch_measurement(void) { - if (sev_state && - sev_state->state >= SEV_STATE_LAUNCH_SECRET) { - return g_strdup(sev_state->measurement); + if (sev_guest && + sev_guest->state.state >= SEV_STATE_LAUNCH_SECRET) { + return g_strdup(sev_guest->state.measurement); } return NULL; @@ -648,20 +649,21 @@ static Notifier sev_machine_done_notify = { }; static void -sev_launch_finish(SEVState *s) +sev_launch_finish(SevGuestState *sev) { + SEVState *s = &sev->state; int ret, error; Error *local_err = NULL; trace_kvm_sev_launch_finish(); - ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error); + ret = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error); if (ret) { error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'", __func__, ret, error, fw_error_to_str(error)); exit(1); } - sev_set_guest_state(SEV_STATE_RUNNING); + sev_set_guest_state(sev, SEV_STATE_RUNNING); /* add migration blocker */ error_setg(&sev_mig_blocker, @@ -677,11 +679,11 @@ sev_launch_finish(SEVState *s) static void sev_vm_state_change(void *opaque, int running, RunState state) { - SEVState *s = opaque; + SevGuestState *sev = opaque; if (running) { - if (!sev_check_state(SEV_STATE_RUNNING)) { - sev_launch_finish(s); + if (!sev_check_state(sev, SEV_STATE_RUNNING)) { + sev_launch_finish(sev); } } } @@ -704,7 +706,8 @@ sev_guest_init(const char *id) goto err; } - sev_state = s = &sev->state; + sev_guest = sev; + s = &sev->state; s->state = SEV_STATE_UNINIT; host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL); @@ -766,23 +769,24 @@ sev_guest_init(const char *id) ram_block_notifier_add(&sev_ram_notifier); qemu_add_machine_init_done_notifier(&sev_machine_done_notify); - qemu_add_vm_change_state_handler(sev_vm_state_change, s); + qemu_add_vm_change_state_handler(sev_vm_state_change, sev); - return s; + return sev; err: - g_free(sev_state); - sev_state = NULL; + sev_guest = NULL; return NULL; } int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len) { - assert(handle); + SevGuestState *sev = handle; + + assert(sev); /* if SEV is in update state then encrypt the data else do nothing */ - if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) { - return sev_launch_update_data(ptr, len); + if (sev_check_state(sev, SEV_STATE_LAUNCH_UPDATE)) { + return sev_launch_update_data(sev, ptr, len); } return 0; From a06d2bad053f5f95871c0b429acc2c64c74a92b3 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 4 Jun 2020 16:42:16 +1000 Subject: [PATCH 1159/2595] target/i386: sev: Remove redundant cbitpos and reduced_phys_bits fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SEVState structure has cbitpos and reduced_phys_bits fields which are simply copied from the SevGuestState structure and never changed. Now that SEVState is embedded in SevGuestState we can just access the original copy directly. Signed-off-by: David Gibson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200604064219.436242-7-david@gibson.dropbear.id.au> Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index 9e8ab7b056..d25af37136 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -41,8 +41,6 @@ struct SEVState { uint8_t build_id; uint32_t policy; uint64_t me_mask; - uint32_t cbitpos; - uint32_t reduced_phys_bits; uint32_t handle; int sev_fd; SevState state; @@ -378,13 +376,13 @@ sev_get_me_mask(void) uint32_t sev_get_cbit_position(void) { - return sev_guest ? sev_guest->state.cbitpos : 0; + return sev_guest ? sev_guest->cbitpos : 0; } uint32_t sev_get_reduced_phys_bits(void) { - return sev_guest ? sev_guest->state.reduced_phys_bits : 0; + return sev_guest ? sev_guest->reduced_phys_bits : 0; } SevInfo * @@ -713,22 +711,19 @@ sev_guest_init(const char *id) host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL); host_cbitpos = ebx & 0x3f; - s->cbitpos = object_property_get_int(OBJECT(sev), "cbitpos", NULL); - if (host_cbitpos != s->cbitpos) { + if (host_cbitpos != sev->cbitpos) { error_report("%s: cbitpos check failed, host '%d' requested '%d'", - __func__, host_cbitpos, s->cbitpos); + __func__, host_cbitpos, sev->cbitpos); goto err; } - s->reduced_phys_bits = object_property_get_int(OBJECT(sev), - "reduced-phys-bits", NULL); - if (s->reduced_phys_bits < 1) { + if (sev->reduced_phys_bits < 1) { error_report("%s: reduced_phys_bits check failed, it should be >=1," - " requested '%d'", __func__, s->reduced_phys_bits); + " requested '%d'", __func__, sev->reduced_phys_bits); goto err; } - s->me_mask = ~(1UL << s->cbitpos); + s->me_mask = ~(1UL << sev->cbitpos); devname = object_property_get_str(OBJECT(sev), "sev-device", NULL); s->sev_fd = open(devname, O_RDWR); From 0bd1527774fc17985f47df41b95f31b00b162129 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 4 Jun 2020 16:42:17 +1000 Subject: [PATCH 1160/2595] target/i386: sev: Remove redundant policy field SEVState::policy is set from the final value of the policy field in the parameter structure for the KVM_SEV_LAUNCH_START ioctl(). But, AFAICT that ioctl() won't ever change it from the original supplied value which comes from SevGuestState::policy. So, remove this field and just use SevGuestState::policy directly. Signed-off-by: David Gibson Reviewed-by: Richard Henderson Message-Id: <20200604064219.436242-8-david@gibson.dropbear.id.au> Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index d25af37136..4b261beaa7 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -39,7 +39,6 @@ struct SEVState { uint8_t api_major; uint8_t api_minor; uint8_t build_id; - uint32_t policy; uint64_t me_mask; uint32_t handle; int sev_fd; @@ -397,7 +396,7 @@ sev_get_info(void) info->api_major = sev_guest->state.api_major; info->api_minor = sev_guest->state.api_minor; info->build_id = sev_guest->state.build_id; - info->policy = sev_guest->state.policy; + info->policy = sev_guest->policy; info->state = sev_guest->state.state; info->handle = sev_guest->state.handle; } @@ -520,8 +519,7 @@ sev_launch_start(SevGuestState *sev) start->handle = object_property_get_int(OBJECT(sev), "handle", &error_abort); - start->policy = object_property_get_int(OBJECT(sev), "policy", - &error_abort); + start->policy = sev->policy; if (sev->session_file) { if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) { goto out; @@ -550,7 +548,6 @@ sev_launch_start(SevGuestState *sev) &error_abort); sev_set_guest_state(sev, SEV_STATE_LAUNCH_UPDATE); s->handle = start->handle; - s->policy = start->policy; ret = 0; out: From cf504cd67b26ded2e25eb8f33b5ebec031b31def Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 4 Jun 2020 16:42:18 +1000 Subject: [PATCH 1161/2595] target/i386: sev: Remove redundant handle field The user can explicitly specify a handle via the "handle" property wired to SevGuestState::handle. That gets passed to the KVM_SEV_LAUNCH_START ioctl() which may update it, the final value being copied back to both SevGuestState::handle and SEVState::handle. AFAICT, nothing will be looking SEVState::handle before it and SevGuestState::handle have been updated from the ioctl(). So, remove the field and just use SevGuestState::handle directly. Signed-off-by: David Gibson Reviewed-by: Richard Henderson Message-Id: <20200604064219.436242-9-david@gibson.dropbear.id.au> Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index 4b261beaa7..24e2dea9b8 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -40,7 +40,6 @@ struct SEVState { uint8_t api_minor; uint8_t build_id; uint64_t me_mask; - uint32_t handle; int sev_fd; SevState state; gchar *measurement; @@ -64,13 +63,13 @@ struct SevGuestState { /* configuration parameters */ char *sev_device; uint32_t policy; - uint32_t handle; char *dh_cert_file; char *session_file; uint32_t cbitpos; uint32_t reduced_phys_bits; /* runtime state */ + uint32_t handle; SEVState state; }; @@ -398,7 +397,7 @@ sev_get_info(void) info->build_id = sev_guest->state.build_id; info->policy = sev_guest->policy; info->state = sev_guest->state.state; - info->handle = sev_guest->state.handle; + info->handle = sev_guest->handle; } return info; @@ -517,8 +516,7 @@ sev_launch_start(SevGuestState *sev) start = g_new0(struct kvm_sev_launch_start, 1); - start->handle = object_property_get_int(OBJECT(sev), "handle", - &error_abort); + start->handle = sev->handle; start->policy = sev->policy; if (sev->session_file) { if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) { @@ -544,10 +542,8 @@ sev_launch_start(SevGuestState *sev) goto out; } - object_property_set_int(OBJECT(sev), start->handle, "handle", - &error_abort); sev_set_guest_state(sev, SEV_STATE_LAUNCH_UPDATE); - s->handle = start->handle; + sev->handle = start->handle; ret = 0; out: From 421522eb534d82040bc8e405ed3a28d94d17f24e Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 4 Jun 2020 16:42:19 +1000 Subject: [PATCH 1162/2595] target/i386: sev: Unify SEVState and SevGuestState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SEVState is contained with SevGuestState. We've now fixed redundancies and name conflicts, so there's no real point to the nested structure. Just move all the fields of SEVState into SevGuestState. This eliminates the SEVState structure, which as a bonus removes the confusion with the SevState enum. Signed-off-by: David Gibson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200604064219.436242-10-david@gibson.dropbear.id.au> Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 79 ++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 45 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index 24e2dea9b8..d273174ad3 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -35,18 +35,6 @@ typedef struct SevGuestState SevGuestState; -struct SEVState { - uint8_t api_major; - uint8_t api_minor; - uint8_t build_id; - uint64_t me_mask; - int sev_fd; - SevState state; - gchar *measurement; -}; - -typedef struct SEVState SEVState; - /** * SevGuestState: * @@ -70,7 +58,13 @@ struct SevGuestState { /* runtime state */ uint32_t handle; - SEVState state; + uint8_t api_major; + uint8_t api_minor; + uint8_t build_id; + uint64_t me_mask; + int sev_fd; + SevState state; + gchar *measurement; }; #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ @@ -158,7 +152,7 @@ static bool sev_check_state(const SevGuestState *sev, SevState state) { assert(sev); - return sev->state.state == state ? true : false; + return sev->state == state ? true : false; } static void @@ -167,9 +161,9 @@ sev_set_guest_state(SevGuestState *sev, SevState new_state) assert(new_state < SEV_STATE__MAX); assert(sev); - trace_kvm_sev_change_state(SevState_str(sev->state.state), + trace_kvm_sev_change_state(SevState_str(sev->state), SevState_str(new_state)); - sev->state.state = new_state; + sev->state = new_state; } static void @@ -368,7 +362,7 @@ sev_enabled(void) uint64_t sev_get_me_mask(void) { - return sev_guest ? sev_guest->state.me_mask : ~0; + return sev_guest ? sev_guest->me_mask : ~0; } uint32_t @@ -392,11 +386,11 @@ sev_get_info(void) info->enabled = sev_enabled(); if (info->enabled) { - info->api_major = sev_guest->state.api_major; - info->api_minor = sev_guest->state.api_minor; - info->build_id = sev_guest->state.build_id; + info->api_major = sev_guest->api_major; + info->api_minor = sev_guest->api_minor; + info->build_id = sev_guest->build_id; info->policy = sev_guest->policy; - info->state = sev_guest->state.state; + info->state = sev_guest->state; info->handle = sev_guest->handle; } @@ -507,7 +501,6 @@ sev_read_file_base64(const char *filename, guchar **data, gsize *len) static int sev_launch_start(SevGuestState *sev) { - SEVState *s = &sev->state; gsize sz; int ret = 1; int fw_error, rc; @@ -535,7 +528,7 @@ sev_launch_start(SevGuestState *sev) } trace_kvm_sev_launch_start(start->policy, session, dh_cert); - rc = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error); + rc = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error); if (rc < 0) { error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'", __func__, ret, fw_error, fw_error_to_str(fw_error)); @@ -566,7 +559,7 @@ sev_launch_update_data(SevGuestState *sev, uint8_t *addr, uint64_t len) update.uaddr = (__u64)(unsigned long)addr; update.len = len; trace_kvm_sev_launch_update_data(addr, len); - ret = sev_ioctl(sev->state.sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA, + ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA, &update, &fw_error); if (ret) { error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'", @@ -582,7 +575,6 @@ sev_launch_get_measure(Notifier *notifier, void *unused) SevGuestState *sev = sev_guest; int ret, error; guchar *data; - SEVState *s = &sev->state; struct kvm_sev_launch_measure *measurement; if (!sev_check_state(sev, SEV_STATE_LAUNCH_UPDATE)) { @@ -592,7 +584,7 @@ sev_launch_get_measure(Notifier *notifier, void *unused) measurement = g_new0(struct kvm_sev_launch_measure, 1); /* query the measurement blob length */ - ret = sev_ioctl(sev->state.sev_fd, KVM_SEV_LAUNCH_MEASURE, + ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_MEASURE, measurement, &error); if (!measurement->len) { error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'", @@ -604,7 +596,7 @@ sev_launch_get_measure(Notifier *notifier, void *unused) measurement->uaddr = (unsigned long)data; /* get the measurement blob */ - ret = sev_ioctl(sev->state.sev_fd, KVM_SEV_LAUNCH_MEASURE, + ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_MEASURE, measurement, &error); if (ret) { error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'", @@ -615,8 +607,8 @@ sev_launch_get_measure(Notifier *notifier, void *unused) sev_set_guest_state(sev, SEV_STATE_LAUNCH_SECRET); /* encode the measurement value and emit the event */ - s->measurement = g_base64_encode(data, measurement->len); - trace_kvm_sev_launch_measurement(s->measurement); + sev->measurement = g_base64_encode(data, measurement->len); + trace_kvm_sev_launch_measurement(sev->measurement); free_data: g_free(data); @@ -628,8 +620,8 @@ char * sev_get_launch_measurement(void) { if (sev_guest && - sev_guest->state.state >= SEV_STATE_LAUNCH_SECRET) { - return g_strdup(sev_guest->state.measurement); + sev_guest->state >= SEV_STATE_LAUNCH_SECRET) { + return g_strdup(sev_guest->measurement); } return NULL; @@ -642,12 +634,11 @@ static Notifier sev_machine_done_notify = { static void sev_launch_finish(SevGuestState *sev) { - SEVState *s = &sev->state; int ret, error; Error *local_err = NULL; trace_kvm_sev_launch_finish(); - ret = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error); + ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error); if (ret) { error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'", __func__, ret, error, fw_error_to_str(error)); @@ -683,7 +674,6 @@ void * sev_guest_init(const char *id) { SevGuestState *sev; - SEVState *s; char *devname; int ret, fw_error; uint32_t ebx; @@ -698,8 +688,7 @@ sev_guest_init(const char *id) } sev_guest = sev; - s = &sev->state; - s->state = SEV_STATE_UNINIT; + sev->state = SEV_STATE_UNINIT; host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL); host_cbitpos = ebx & 0x3f; @@ -716,20 +705,20 @@ sev_guest_init(const char *id) goto err; } - s->me_mask = ~(1UL << sev->cbitpos); + sev->me_mask = ~(1UL << sev->cbitpos); devname = object_property_get_str(OBJECT(sev), "sev-device", NULL); - s->sev_fd = open(devname, O_RDWR); - if (s->sev_fd < 0) { + sev->sev_fd = open(devname, O_RDWR); + if (sev->sev_fd < 0) { error_report("%s: Failed to open %s '%s'", __func__, devname, strerror(errno)); } g_free(devname); - if (s->sev_fd < 0) { + if (sev->sev_fd < 0) { goto err; } - ret = sev_platform_ioctl(s->sev_fd, SEV_PLATFORM_STATUS, &status, + ret = sev_platform_ioctl(sev->sev_fd, SEV_PLATFORM_STATUS, &status, &fw_error); if (ret) { error_report("%s: failed to get platform status ret=%d " @@ -737,12 +726,12 @@ sev_guest_init(const char *id) fw_error_to_str(fw_error)); goto err; } - s->build_id = status.build; - s->api_major = status.api_major; - s->api_minor = status.api_minor; + sev->build_id = status.build; + sev->api_major = status.api_major; + sev->api_minor = status.api_minor; trace_kvm_sev_init(); - ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, &fw_error); + ret = sev_ioctl(sev->sev_fd, KVM_SEV_INIT, NULL, &fw_error); if (ret) { error_report("%s: failed to initialize ret=%d fw_error=%d '%s'", __func__, ret, fw_error, fw_error_to_str(fw_error)); From 2046811c66afd54358355242fa23b987b7445440 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 2 Jun 2020 01:36:17 -0400 Subject: [PATCH 1163/2595] checkpatch: reversed logic with acpi test checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Logic reversed: allowed list should just be ignored. Instead we only take that into account :( Fixes: e11b06a880ca ("checkpatch: ignore allowed diff list") Signed-off-by: Michael S. Tsirkin Message-Id: <20200602053614.54745-1-mst@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Eric Auger Tested-by: Eric Auger Signed-off-by: Paolo Bonzini --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 0ba213e9f2..2d2e922d89 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1267,7 +1267,7 @@ sub checkfilename { # files and when changing tests. if ($name =~ m#^tests/data/acpi/# and not $name =~ m#^\.sh$#) { $$acpi_testexpected = $name; - } elsif ($name =~ m#^tests/qtest/bios-tables-test-allowed-diff.h$#) { + } elsif ($name !~ m#^tests/qtest/bios-tables-test-allowed-diff.h$#) { $$acpi_nontestexpected = $name; } if (defined $$acpi_testexpected and defined $$acpi_nontestexpected) { From e1bc61989264a37aeffefa1fb3cf100db259b35b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 16:15:34 +0200 Subject: [PATCH 1164/2595] exec/memory: Remove unused MemoryRegionMmio type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 62a0db942dec ('memory: Remove old_mmio accessors') this structure is unused. Remove it. Suggested-by: Peter Maydell Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200601141536.15192-2-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index af8ca7824e..7207025bd4 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -50,12 +50,6 @@ extern bool global_dirty_log; typedef struct MemoryRegionOps MemoryRegionOps; -typedef struct MemoryRegionMmio MemoryRegionMmio; - -struct MemoryRegionMmio { - CPUReadMemoryFunc *read[3]; - CPUWriteMemoryFunc *write[3]; -}; typedef struct IOMMUTLBEntry IOMMUTLBEntry; From 2c89d91195c4c7a118d2ae3518c31ca77a0583cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 16:15:35 +0200 Subject: [PATCH 1165/2595] hw/usb: Move device-specific declarations to new 'hcd-musb.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the declarations for the MUSB-HDRC USB2.0 OTG compliant core into a separate header. Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200601141536.15192-3-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/usb/hcd-musb.c | 1 + hw/usb/tusb6010.c | 1 + include/hw/usb.h | 30 ------------------------- include/hw/usb/hcd-musb.h | 46 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 30 deletions(-) create mode 100644 include/hw/usb/hcd-musb.h diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c index c29fbef6fc..5ab13feb3a 100644 --- a/hw/usb/hcd-musb.c +++ b/hw/usb/hcd-musb.c @@ -23,6 +23,7 @@ #include "qemu/osdep.h" #include "qemu/timer.h" #include "hw/usb.h" +#include "hw/usb/hcd-musb.h" #include "hw/irq.h" #include "hw/hw.h" diff --git a/hw/usb/tusb6010.c b/hw/usb/tusb6010.c index 17580876c6..27eb28d3e4 100644 --- a/hw/usb/tusb6010.c +++ b/hw/usb/tusb6010.c @@ -23,6 +23,7 @@ #include "qemu/module.h" #include "qemu/timer.h" #include "hw/usb.h" +#include "hw/usb/hcd-musb.h" #include "hw/arm/omap.h" #include "hw/hw.h" #include "hw/irq.h" diff --git a/include/hw/usb.h b/include/hw/usb.h index 1cf1cd9584..e2128c7c45 100644 --- a/include/hw/usb.h +++ b/include/hw/usb.h @@ -474,36 +474,6 @@ bool usb_host_dev_is_scsi_storage(USBDevice *usbdev); #define VM_USB_HUB_SIZE 8 -/* hw/usb/hdc-musb.c */ - -enum musb_irq_source_e { - musb_irq_suspend = 0, - musb_irq_resume, - musb_irq_rst_babble, - musb_irq_sof, - musb_irq_connect, - musb_irq_disconnect, - musb_irq_vbus_request, - musb_irq_vbus_error, - musb_irq_rx, - musb_irq_tx, - musb_set_vbus, - musb_set_session, - /* Add new interrupts here */ - musb_irq_max, /* total number of interrupts defined */ -}; - -typedef struct MUSBState MUSBState; - -extern CPUReadMemoryFunc * const musb_read[]; -extern CPUWriteMemoryFunc * const musb_write[]; - -MUSBState *musb_init(DeviceState *parent_device, int gpio_base); -void musb_reset(MUSBState *s); -uint32_t musb_core_intr_get(MUSBState *s); -void musb_core_intr_clear(MUSBState *s, uint32_t mask); -void musb_set_size(MUSBState *s, int epnum, int size, int is_tx); - /* usb-bus.c */ #define TYPE_USB_BUS "usb-bus" diff --git a/include/hw/usb/hcd-musb.h b/include/hw/usb/hcd-musb.h new file mode 100644 index 0000000000..26b50132ff --- /dev/null +++ b/include/hw/usb/hcd-musb.h @@ -0,0 +1,46 @@ +/* + * "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics, + * USB2.0 OTG compliant core used in various chips. + * + * Only host-mode and non-DMA accesses are currently supported. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_USB_MUSB_H +#define HW_USB_MUSB_H + +#include "exec/cpu-common.h" + +enum musb_irq_source_e { + musb_irq_suspend = 0, + musb_irq_resume, + musb_irq_rst_babble, + musb_irq_sof, + musb_irq_connect, + musb_irq_disconnect, + musb_irq_vbus_request, + musb_irq_vbus_error, + musb_irq_rx, + musb_irq_tx, + musb_set_vbus, + musb_set_session, + /* Add new interrupts here */ + musb_irq_max /* total number of interrupts defined */ +}; + +extern CPUReadMemoryFunc * const musb_read[]; +extern CPUWriteMemoryFunc * const musb_write[]; + +typedef struct MUSBState MUSBState; + +MUSBState *musb_init(DeviceState *parent_device, int gpio_base); +void musb_reset(MUSBState *s); +uint32_t musb_core_intr_get(MUSBState *s); +void musb_core_intr_clear(MUSBState *s, uint32_t mask); +void musb_set_size(MUSBState *s, int epnum, int size, int is_tx); + +#endif From efb22b2f98975785aa594e5a198d4c2e13a5d2d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 1 Jun 2020 16:15:36 +0200 Subject: [PATCH 1166/2595] exec/cpu-common: Move MUSB specific typedefs to 'hw/usb/hcd-musb.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CPUReadMemoryFunc/CPUWriteMemoryFunc typedefs are legacy remnant from before the conversion to MemoryRegions. Since they are now only used in tusb6010.c and hcd-musb.c, move them to "hw/usb/musb.h" and rename them appropriately. Suggested-by: Peter Maydell Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200601141536.15192-4-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/usb/hcd-musb.c | 4 ++-- include/exec/cpu-common.h | 3 --- include/hw/usb/hcd-musb.h | 9 +++++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c index 5ab13feb3a..85f5ff5bd4 100644 --- a/hw/usb/hcd-musb.c +++ b/hw/usb/hcd-musb.c @@ -1540,13 +1540,13 @@ static void musb_writew(void *opaque, hwaddr addr, uint32_t value) }; } -CPUReadMemoryFunc * const musb_read[] = { +MUSBReadFunc * const musb_read[] = { musb_readb, musb_readh, musb_readw, }; -CPUWriteMemoryFunc * const musb_write[] = { +MUSBWriteFunc * const musb_write[] = { musb_writeb, musb_writeh, musb_writew, diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index b47e5630e7..d5e285d2b5 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -43,9 +43,6 @@ extern ram_addr_t ram_size; /* memory API */ -typedef void CPUWriteMemoryFunc(void *opaque, hwaddr addr, uint32_t value); -typedef uint32_t CPUReadMemoryFunc(void *opaque, hwaddr addr); - void qemu_ram_remap(ram_addr_t addr, ram_addr_t length); /* This should not be used by devices. */ ram_addr_t qemu_ram_addr_from_host(void *ptr); diff --git a/include/hw/usb/hcd-musb.h b/include/hw/usb/hcd-musb.h index 26b50132ff..c874b9f292 100644 --- a/include/hw/usb/hcd-musb.h +++ b/include/hw/usb/hcd-musb.h @@ -13,8 +13,6 @@ #ifndef HW_USB_MUSB_H #define HW_USB_MUSB_H -#include "exec/cpu-common.h" - enum musb_irq_source_e { musb_irq_suspend = 0, musb_irq_resume, @@ -32,8 +30,11 @@ enum musb_irq_source_e { musb_irq_max /* total number of interrupts defined */ }; -extern CPUReadMemoryFunc * const musb_read[]; -extern CPUWriteMemoryFunc * const musb_write[]; +/* TODO convert hcd-musb to QOM/qdev and remove MUSBReadFunc/MUSBWriteFunc */ +typedef void MUSBWriteFunc(void *opaque, hwaddr addr, uint32_t value); +typedef uint32_t MUSBReadFunc(void *opaque, hwaddr addr); +extern MUSBReadFunc * const musb_read[]; +extern MUSBWriteFunc * const musb_write[]; typedef struct MUSBState MUSBState; From ed5d7ff34a8cfafd8efe2aab4eeaf9bf789870e3 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 22 May 2020 09:45:54 +0300 Subject: [PATCH 1167/2595] replay: fix replay shutdown for console mode When QEMU is used without any graphical window, QEMU execution is terminated with the signal (e.g., Ctrl-C). Signal processing in QEMU does not include qemu_system_shutdown_request call. That is why shutdown event is not recorded by record/replay in this case. This patch adds shutdown event to the end of the record log. Now every replay will shutdown the machine at the end. Signed-off-by: Pavel Dovgalyuk Message-Id: <159012995470.27967.18129611453659045726.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- replay/replay.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/replay/replay.c b/replay/replay.c index 706c7b4f4b..7d93746c73 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -366,6 +366,11 @@ void replay_finish(void) /* finalize the file */ if (replay_file) { if (replay_mode == REPLAY_MODE_RECORD) { + /* + * Can't do it in the signal handler, therefore + * add shutdown event here for the case of Ctrl-C. + */ + replay_shutdown_request(SHUTDOWN_CAUSE_HOST_SIGNAL); /* write end event */ replay_put_event(EVENT_END); From 234b74966390894046dfef6157ecc49c39fdce20 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 10 Jun 2020 12:14:21 -0400 Subject: [PATCH 1168/2595] stubs: move Xen stubs to accel/ Keep them close to the other accelerator-dependent stubs, so as to remove stubs that are not needed by tools. Signed-off-by: Paolo Bonzini --- accel/stubs/Makefile.objs | 1 + stubs/xen-hvm.c => accel/stubs/xen-stub.c | 14 +++++++------- stubs/Makefile.objs | 2 -- stubs/xen-common.c | 13 ------------- 4 files changed, 8 insertions(+), 22 deletions(-) rename stubs/xen-hvm.c => accel/stubs/xen-stub.c (74%) delete mode 100644 stubs/xen-common.c diff --git a/accel/stubs/Makefile.objs b/accel/stubs/Makefile.objs index 3894caf95d..bbd14e71fb 100644 --- a/accel/stubs/Makefile.objs +++ b/accel/stubs/Makefile.objs @@ -3,3 +3,4 @@ obj-$(call lnot,$(CONFIG_HVF)) += hvf-stub.o obj-$(call lnot,$(CONFIG_WHPX)) += whpx-stub.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o +obj-$(call lnot,$(CONFIG_XEN)) += xen-stub.o diff --git a/stubs/xen-hvm.c b/accel/stubs/xen-stub.c similarity index 74% rename from stubs/xen-hvm.c rename to accel/stubs/xen-stub.c index 6954a5b696..dcca4e678a 100644 --- a/stubs/xen-hvm.c +++ b/accel/stubs/xen-stub.c @@ -1,18 +1,18 @@ /* - * Copyright (C) 2010 Citrix Ltd. + * Copyright (C) 2014 Citrix Systems UK Ltd. * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" #include "hw/xen/xen.h" -#include "exec/memory.h" #include "qapi/qapi-commands-misc.h" +void xenstore_store_pv_console_info(int i, Chardev *chr) +{ +} + int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) { return -1; diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index c1e43ac68f..28e48171d1 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -49,7 +49,5 @@ stub-obj-y += target-get-monitor-def.o stub-obj-y += target-monitor-defs.o stub-obj-y += uuid.o stub-obj-y += vm-stop.o -stub-obj-y += xen-common.o -stub-obj-y += xen-hvm.o endif # CONFIG_SOFTMMU || CONFIG_TOOLS diff --git a/stubs/xen-common.c b/stubs/xen-common.c deleted file mode 100644 index f5efcae362..0000000000 --- a/stubs/xen-common.c +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (C) 2014 Citrix Systems UK Ltd. - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/xen/xen.h" - -void xenstore_store_pv_console_info(int i, Chardev *chr) -{ -} From 3575b0aea983ad57804c9af739ed8ff7bc168393 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 11 Jun 2020 19:24:45 +0200 Subject: [PATCH 1169/2595] target/i386: Remove obsolete TODO file The last real change to this file is from 2012, so it is very likely that this file is completely out-of-date and ignored today. Let's simply remove it to avoid confusion if someone finds it by accident. Signed-off-by: Thomas Huth Message-Id: <20200611172445.5177-1-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- target/i386/TODO | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 target/i386/TODO diff --git a/target/i386/TODO b/target/i386/TODO deleted file mode 100644 index a8d69cf87f..0000000000 --- a/target/i386/TODO +++ /dev/null @@ -1,31 +0,0 @@ -Correctness issues: - -- some eflags manipulation incorrectly reset the bit 0x2. -- SVM: test, cpu save/restore, SMM save/restore. -- x86_64: lcall/ljmp intel/amd differences ? -- better code fetch (different exception handling + CS.limit support) -- user/kernel PUSHL/POPL in helper.c -- add missing cpuid tests -- return UD exception if LOCK prefix incorrectly used -- test ldt limit < 7 ? -- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret) -- full support of segment limit/rights -- full x87 exception support -- improve x87 bit exactness (use bochs code ?) -- DRx register support -- CR0.AC emulation -- SSE alignment checks - -Optimizations/Features: - -- add SVM nested paging support -- add VMX support -- add AVX support -- add SSE5 support -- fxsave/fxrstor AMD extensions -- improve monitor/mwait support -- faster EFLAGS update: consider SZAP, C, O can be updated separately - with a bit field in CC_OP and more state variables. -- evaluate x87 stack pointer statically -- find a way to avoid translating several time the same TB if CR0.TS - is set or not. From b767d2578da4a46ff5e353f14da6364b97df1020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 20 May 2020 15:20:23 +0200 Subject: [PATCH 1170/2595] crypto: add "none" random provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case of not using random-number needing feature, it makes sense to skip RNG init too. This is especially helpful when QEMU is sandboxed in Stubdomain under Xen, where there is very little entropy so initial getrandom() call delays the startup several seconds. In that setup, no random bytes are needed at all. Signed-off-by: Marek Marczykowski-Górecki Signed-off-by: Daniel P. Berrangé --- configure | 11 +++++++++++ crypto/Makefile.objs | 3 ++- crypto/random-none.c | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 crypto/random-none.c diff --git a/configure b/configure index bb7fd12612..997284e094 100755 --- a/configure +++ b/configure @@ -509,6 +509,7 @@ libpmem="" default_devices="yes" plugins="no" fuzzing="no" +rng_none="no" supported_cpu="no" supported_os="no" @@ -1601,6 +1602,10 @@ for opt do ;; --gdb=*) gdb_bin="$optarg" ;; + --enable-rng-none) rng_none=yes + ;; + --disable-rng-none) rng_none=no + ;; *) echo "ERROR: unknown option $opt" echo "Try '$0 --help' for more information" @@ -1898,6 +1903,7 @@ disabled with --disable-FEATURE, default is enabled if available: debug-mutex mutex debugging support libpmem libpmem support xkbcommon xkbcommon support + rng-none dummy RNG, avoid using /dev/(u)random and getrandom() NOTE: The object files are built at the place where configure is launched EOF @@ -6767,6 +6773,7 @@ echo "default devices $default_devices" echo "plugin support $plugins" echo "fuzzing support $fuzzing" echo "gdb $gdb_bin" +echo "rng-none $rng_none" if test "$supported_cpu" = "no"; then echo @@ -7744,6 +7751,10 @@ if test "$edk2_blobs" = "yes" ; then echo "DECOMPRESS_EDK2_BLOBS=y" >> $config_host_mak fi +if test "$rng_none" = "yes"; then + echo "CONFIG_RNG_NONE=y" >> $config_host_mak +fi + # use included Linux headers if test "$linux" = "yes" ; then mkdir -p linux-headers diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs index c2a371b0b4..cdee92b4e5 100644 --- a/crypto/Makefile.objs +++ b/crypto/Makefile.objs @@ -35,5 +35,6 @@ crypto-obj-y += block-luks.o util-obj-$(CONFIG_GCRYPT) += random-gcrypt.o util-obj-$(if $(CONFIG_GCRYPT),n,$(CONFIG_GNUTLS)) += random-gnutls.o -util-obj-$(if $(CONFIG_GCRYPT),n,$(if $(CONFIG_GNUTLS),n,y)) += random-platform.o +util-obj-$(if $(CONFIG_GCRYPT),n,$(if $(CONFIG_GNUTLS),n,$(CONFIG_RNG_NONE))) += random-none.o +util-obj-$(if $(CONFIG_GCRYPT),n,$(if $(CONFIG_GNUTLS),n,$(if $(CONFIG_RNG_NONE),n,y))) += random-platform.o util-obj-y += aes.o init.o diff --git a/crypto/random-none.c b/crypto/random-none.c new file mode 100644 index 0000000000..102f8a4dce --- /dev/null +++ b/crypto/random-none.c @@ -0,0 +1,38 @@ +/* + * QEMU Crypto "none" random number provider + * + * Copyright (c) 2020 Marek Marczykowski-Górecki + * + * + * 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.1 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 . + * + */ + +#include "qemu/osdep.h" + +#include "crypto/random.h" +#include "qapi/error.h" + +int qcrypto_random_init(Error **errp) +{ + return 0; +} + +int qcrypto_random_bytes(void *buf, + size_t buflen, + Error **errp) +{ + error_setg(errp, "Random bytes not available with \"none\" rng"); + return -1; +} From 4862bd3cd2052f1b48e4d08b1820e70a255c4859 Mon Sep 17 00:00:00 2001 From: Alexey Krasikov Date: Mon, 25 May 2020 14:16:53 +0300 Subject: [PATCH 1171/2595] crypto/secret: move main logic from 'secret' to 'secret_common'. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create base class 'common secret'. Move common data and logic from 'secret' to 'common_secret' class. This allowed adding abstraction layer for easier adding new 'secret' objects in future. Convert 'secret' class to child from basic 'secret_common' with 'data' and 'file' properties. Signed-off-by: Alexey Krasikov Signed-off-by: Daniel P. Berrangé --- crypto/Makefile.objs | 1 + crypto/secret.c | 347 +--------------------------- crypto/secret_common.c | 403 +++++++++++++++++++++++++++++++++ include/crypto/secret.h | 20 +- include/crypto/secret_common.h | 68 ++++++ 5 files changed, 482 insertions(+), 357 deletions(-) create mode 100644 crypto/secret_common.c create mode 100644 include/crypto/secret_common.h diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs index cdee92b4e5..110dec1b87 100644 --- a/crypto/Makefile.objs +++ b/crypto/Makefile.objs @@ -18,6 +18,7 @@ crypto-obj-y += tlscredsanon.o crypto-obj-y += tlscredspsk.o crypto-obj-y += tlscredsx509.o crypto-obj-y += tlssession.o +crypto-obj-y += secret_common.o crypto-obj-y += secret.o crypto-obj-y += pbkdf.o crypto-obj-$(CONFIG_NETTLE) += pbkdf-nettle.o diff --git a/crypto/secret.c b/crypto/secret.c index 3107aecb47..3447e2f64b 100644 --- a/crypto/secret.c +++ b/crypto/secret.c @@ -20,16 +20,14 @@ #include "qemu/osdep.h" #include "crypto/secret.h" -#include "crypto/cipher.h" #include "qapi/error.h" #include "qom/object_interfaces.h" -#include "qemu/base64.h" #include "qemu/module.h" #include "trace.h" static void -qcrypto_secret_load_data(QCryptoSecret *secret, +qcrypto_secret_load_data(QCryptoSecretCommon *sec_common, uint8_t **output, size_t *outputlen, Error **errp) @@ -38,6 +36,8 @@ qcrypto_secret_load_data(QCryptoSecret *secret, size_t length = 0; GError *gerr = NULL; + QCryptoSecret *secret = QCRYPTO_SECRET(sec_common); + *output = NULL; *outputlen = 0; @@ -65,198 +65,6 @@ qcrypto_secret_load_data(QCryptoSecret *secret, } -static void qcrypto_secret_decrypt(QCryptoSecret *secret, - const uint8_t *input, - size_t inputlen, - uint8_t **output, - size_t *outputlen, - Error **errp) -{ - g_autofree uint8_t *key = NULL; - g_autofree uint8_t *ciphertext = NULL; - g_autofree uint8_t *iv = NULL; - size_t keylen, ciphertextlen, ivlen; - g_autoptr(QCryptoCipher) aes = NULL; - g_autofree uint8_t *plaintext = NULL; - - *output = NULL; - *outputlen = 0; - - if (qcrypto_secret_lookup(secret->keyid, - &key, &keylen, - errp) < 0) { - return; - } - - if (keylen != 32) { - error_setg(errp, "Key should be 32 bytes in length"); - return; - } - - if (!secret->iv) { - error_setg(errp, "IV is required to decrypt secret"); - return; - } - - iv = qbase64_decode(secret->iv, -1, &ivlen, errp); - if (!iv) { - return; - } - if (ivlen != 16) { - error_setg(errp, "IV should be 16 bytes in length not %zu", - ivlen); - return; - } - - aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256, - QCRYPTO_CIPHER_MODE_CBC, - key, keylen, - errp); - if (!aes) { - return; - } - - if (qcrypto_cipher_setiv(aes, iv, ivlen, errp) < 0) { - return; - } - - if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { - ciphertext = qbase64_decode((const gchar*)input, - inputlen, - &ciphertextlen, - errp); - if (!ciphertext) { - return; - } - plaintext = g_new0(uint8_t, ciphertextlen + 1); - } else { - ciphertextlen = inputlen; - plaintext = g_new0(uint8_t, inputlen + 1); - } - if (qcrypto_cipher_decrypt(aes, - ciphertext ? ciphertext : input, - plaintext, - ciphertextlen, - errp) < 0) { - return; - } - - if (plaintext[ciphertextlen - 1] > 16 || - plaintext[ciphertextlen - 1] > ciphertextlen) { - error_setg(errp, "Incorrect number of padding bytes (%d) " - "found on decrypted data", - (int)plaintext[ciphertextlen - 1]); - return; - } - - /* Even though plaintext may contain arbitrary NUL - * ensure it is explicitly NUL terminated. - */ - ciphertextlen -= plaintext[ciphertextlen - 1]; - plaintext[ciphertextlen] = '\0'; - - *output = g_steal_pointer(&plaintext); - *outputlen = ciphertextlen; -} - - -static void qcrypto_secret_decode(const uint8_t *input, - size_t inputlen, - uint8_t **output, - size_t *outputlen, - Error **errp) -{ - *output = qbase64_decode((const gchar*)input, - inputlen, - outputlen, - errp); -} - - -static void -qcrypto_secret_prop_set_loaded(Object *obj, - bool value, - Error **errp) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - - if (value) { - Error *local_err = NULL; - uint8_t *input = NULL; - size_t inputlen = 0; - uint8_t *output = NULL; - size_t outputlen = 0; - - qcrypto_secret_load_data(secret, &input, &inputlen, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - if (secret->keyid) { - qcrypto_secret_decrypt(secret, input, inputlen, - &output, &outputlen, &local_err); - g_free(input); - if (local_err) { - error_propagate(errp, local_err); - return; - } - input = output; - inputlen = outputlen; - } else { - if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { - qcrypto_secret_decode(input, inputlen, - &output, &outputlen, &local_err); - g_free(input); - if (local_err) { - error_propagate(errp, local_err); - return; - } - input = output; - inputlen = outputlen; - } - } - - secret->rawdata = input; - secret->rawlen = inputlen; - } else { - g_free(secret->rawdata); - secret->rawdata = NULL; - secret->rawlen = 0; - } -} - - -static bool -qcrypto_secret_prop_get_loaded(Object *obj, - Error **errp G_GNUC_UNUSED) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - return secret->rawdata != NULL; -} - - -static void -qcrypto_secret_prop_set_format(Object *obj, - int value, - Error **errp G_GNUC_UNUSED) -{ - QCryptoSecret *creds = QCRYPTO_SECRET(obj); - - creds->format = value; -} - - -static int -qcrypto_secret_prop_get_format(Object *obj, - Error **errp G_GNUC_UNUSED) -{ - QCryptoSecret *creds = QCRYPTO_SECRET(obj); - - return creds->format; -} - - static void qcrypto_secret_prop_set_data(Object *obj, const char *value, @@ -299,48 +107,6 @@ qcrypto_secret_prop_get_file(Object *obj, } -static void -qcrypto_secret_prop_set_iv(Object *obj, - const char *value, - Error **errp) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - - g_free(secret->iv); - secret->iv = g_strdup(value); -} - - -static char * -qcrypto_secret_prop_get_iv(Object *obj, - Error **errp) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - return g_strdup(secret->iv); -} - - -static void -qcrypto_secret_prop_set_keyid(Object *obj, - const char *value, - Error **errp) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - - g_free(secret->keyid); - secret->keyid = g_strdup(value); -} - - -static char * -qcrypto_secret_prop_get_keyid(Object *obj, - Error **errp) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - return g_strdup(secret->keyid); -} - - static void qcrypto_secret_complete(UserCreatable *uc, Error **errp) { @@ -353,129 +119,30 @@ qcrypto_secret_finalize(Object *obj) { QCryptoSecret *secret = QCRYPTO_SECRET(obj); - g_free(secret->iv); g_free(secret->file); - g_free(secret->keyid); - g_free(secret->rawdata); g_free(secret->data); } static void qcrypto_secret_class_init(ObjectClass *oc, void *data) { - UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + QCryptoSecretCommonClass *sic = QCRYPTO_SECRET_COMMON_CLASS(oc); + sic->load_data = qcrypto_secret_load_data; + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); ucc->complete = qcrypto_secret_complete; - object_class_property_add_bool(oc, "loaded", - qcrypto_secret_prop_get_loaded, - qcrypto_secret_prop_set_loaded); - object_class_property_add_enum(oc, "format", - "QCryptoSecretFormat", - &QCryptoSecretFormat_lookup, - qcrypto_secret_prop_get_format, - qcrypto_secret_prop_set_format); object_class_property_add_str(oc, "data", qcrypto_secret_prop_get_data, qcrypto_secret_prop_set_data); object_class_property_add_str(oc, "file", qcrypto_secret_prop_get_file, qcrypto_secret_prop_set_file); - object_class_property_add_str(oc, "keyid", - qcrypto_secret_prop_get_keyid, - qcrypto_secret_prop_set_keyid); - object_class_property_add_str(oc, "iv", - qcrypto_secret_prop_get_iv, - qcrypto_secret_prop_set_iv); -} - - -int qcrypto_secret_lookup(const char *secretid, - uint8_t **data, - size_t *datalen, - Error **errp) -{ - Object *obj; - QCryptoSecret *secret; - - obj = object_resolve_path_component( - object_get_objects_root(), secretid); - if (!obj) { - error_setg(errp, "No secret with id '%s'", secretid); - return -1; - } - - secret = (QCryptoSecret *) - object_dynamic_cast(obj, - TYPE_QCRYPTO_SECRET); - if (!secret) { - error_setg(errp, "Object with id '%s' is not a secret", - secretid); - return -1; - } - - if (!secret->rawdata) { - error_setg(errp, "Secret with id '%s' has no data", - secretid); - return -1; - } - - *data = g_new0(uint8_t, secret->rawlen + 1); - memcpy(*data, secret->rawdata, secret->rawlen); - (*data)[secret->rawlen] = '\0'; - *datalen = secret->rawlen; - - return 0; -} - - -char *qcrypto_secret_lookup_as_utf8(const char *secretid, - Error **errp) -{ - uint8_t *data; - size_t datalen; - - if (qcrypto_secret_lookup(secretid, - &data, - &datalen, - errp) < 0) { - return NULL; - } - - if (!g_utf8_validate((const gchar*)data, datalen, NULL)) { - error_setg(errp, - "Data from secret %s is not valid UTF-8", - secretid); - g_free(data); - return NULL; - } - - return (char *)data; -} - - -char *qcrypto_secret_lookup_as_base64(const char *secretid, - Error **errp) -{ - uint8_t *data; - size_t datalen; - char *ret; - - if (qcrypto_secret_lookup(secretid, - &data, - &datalen, - errp) < 0) { - return NULL; - } - - ret = g_base64_encode(data, datalen); - g_free(data); - return ret; } static const TypeInfo qcrypto_secret_info = { - .parent = TYPE_OBJECT, + .parent = TYPE_QCRYPTO_SECRET_COMMON, .name = TYPE_QCRYPTO_SECRET, .instance_size = sizeof(QCryptoSecret), .instance_finalize = qcrypto_secret_finalize, diff --git a/crypto/secret_common.c b/crypto/secret_common.c new file mode 100644 index 0000000000..b03d530867 --- /dev/null +++ b/crypto/secret_common.c @@ -0,0 +1,403 @@ +/* + * QEMU crypto secret support + * + * Copyright (c) 2015 Red Hat, Inc. + * + * 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.1 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 . + * + */ + +#include "qemu/osdep.h" +#include "crypto/secret_common.h" +#include "crypto/cipher.h" +#include "qapi/error.h" +#include "qom/object_interfaces.h" +#include "qemu/base64.h" +#include "qemu/module.h" +#include "trace.h" + + +static void qcrypto_secret_decrypt(QCryptoSecretCommon *secret, + const uint8_t *input, + size_t inputlen, + uint8_t **output, + size_t *outputlen, + Error **errp) +{ + g_autofree uint8_t *iv = NULL; + g_autofree uint8_t *key = NULL; + g_autofree uint8_t *ciphertext = NULL; + size_t keylen, ciphertextlen, ivlen; + g_autoptr(QCryptoCipher) aes = NULL; + g_autofree uint8_t *plaintext = NULL; + + *output = NULL; + *outputlen = 0; + + if (qcrypto_secret_lookup(secret->keyid, + &key, &keylen, + errp) < 0) { + return; + } + + if (keylen != 32) { + error_setg(errp, "Key should be 32 bytes in length"); + return; + } + + if (!secret->iv) { + error_setg(errp, "IV is required to decrypt secret"); + return; + } + + iv = qbase64_decode(secret->iv, -1, &ivlen, errp); + if (!iv) { + return; + } + if (ivlen != 16) { + error_setg(errp, "IV should be 16 bytes in length not %zu", + ivlen); + return; + } + + aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256, + QCRYPTO_CIPHER_MODE_CBC, + key, keylen, + errp); + if (!aes) { + return; + } + + if (qcrypto_cipher_setiv(aes, iv, ivlen, errp) < 0) { + return; + } + + if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { + ciphertext = qbase64_decode((const gchar *)input, + inputlen, + &ciphertextlen, + errp); + if (!ciphertext) { + return; + } + plaintext = g_new0(uint8_t, ciphertextlen + 1); + } else { + ciphertextlen = inputlen; + plaintext = g_new0(uint8_t, inputlen + 1); + } + if (qcrypto_cipher_decrypt(aes, + ciphertext ? ciphertext : input, + plaintext, + ciphertextlen, + errp) < 0) { + return; + } + + if (plaintext[ciphertextlen - 1] > 16 || + plaintext[ciphertextlen - 1] > ciphertextlen) { + error_setg(errp, "Incorrect number of padding bytes (%d) " + "found on decrypted data", + (int)plaintext[ciphertextlen - 1]); + return; + } + + /* + * Even though plaintext may contain arbitrary NUL + * ensure it is explicitly NUL terminated. + */ + ciphertextlen -= plaintext[ciphertextlen - 1]; + plaintext[ciphertextlen] = '\0'; + + *output = g_steal_pointer(&plaintext); + *outputlen = ciphertextlen; +} + + +static void qcrypto_secret_decode(const uint8_t *input, + size_t inputlen, + uint8_t **output, + size_t *outputlen, + Error **errp) +{ + *output = qbase64_decode((const gchar *)input, + inputlen, + outputlen, + errp); +} + + +static void +qcrypto_secret_prop_set_loaded(Object *obj, + bool value, + Error **errp) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + QCryptoSecretCommonClass *sec_class + = QCRYPTO_SECRET_COMMON_GET_CLASS(obj); + + if (value) { + Error *local_err = NULL; + uint8_t *input = NULL; + size_t inputlen = 0; + uint8_t *output = NULL; + size_t outputlen = 0; + + if (sec_class->load_data) { + sec_class->load_data(secret, &input, &inputlen, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } else { + error_setg(errp, "%s provides no 'load_data' method'", + object_get_typename(obj)); + return; + } + + if (secret->keyid) { + qcrypto_secret_decrypt(secret, input, inputlen, + &output, &outputlen, &local_err); + g_free(input); + if (local_err) { + error_propagate(errp, local_err); + return; + } + input = output; + inputlen = outputlen; + } else { + if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { + qcrypto_secret_decode(input, inputlen, + &output, &outputlen, &local_err); + g_free(input); + if (local_err) { + error_propagate(errp, local_err); + return; + } + input = output; + inputlen = outputlen; + } + } + + secret->rawdata = input; + secret->rawlen = inputlen; + } else { + g_free(secret->rawdata); + secret->rawlen = 0; + } +} + + +static bool +qcrypto_secret_prop_get_loaded(Object *obj, + Error **errp G_GNUC_UNUSED) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + return secret->rawdata != NULL; +} + + +static void +qcrypto_secret_prop_set_format(Object *obj, + int value, + Error **errp G_GNUC_UNUSED) +{ + QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj); + creds->format = value; +} + + +static int +qcrypto_secret_prop_get_format(Object *obj, + Error **errp G_GNUC_UNUSED) +{ + QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj); + return creds->format; +} + + +static void +qcrypto_secret_prop_set_iv(Object *obj, + const char *value, + Error **errp) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + + g_free(secret->iv); + secret->iv = g_strdup(value); +} + + +static char * +qcrypto_secret_prop_get_iv(Object *obj, + Error **errp) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + return g_strdup(secret->iv); +} + + +static void +qcrypto_secret_prop_set_keyid(Object *obj, + const char *value, + Error **errp) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + + g_free(secret->keyid); + secret->keyid = g_strdup(value); +} + + +static char * +qcrypto_secret_prop_get_keyid(Object *obj, + Error **errp) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + return g_strdup(secret->keyid); +} + + +static void +qcrypto_secret_finalize(Object *obj) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + + g_free(secret->iv); + g_free(secret->keyid); + g_free(secret->rawdata); +} + +static void +qcrypto_secret_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add_bool(oc, "loaded", + qcrypto_secret_prop_get_loaded, + qcrypto_secret_prop_set_loaded); + object_class_property_add_enum(oc, "format", + "QCryptoSecretFormat", + &QCryptoSecretFormat_lookup, + qcrypto_secret_prop_get_format, + qcrypto_secret_prop_set_format); + object_class_property_add_str(oc, "keyid", + qcrypto_secret_prop_get_keyid, + qcrypto_secret_prop_set_keyid); + object_class_property_add_str(oc, "iv", + qcrypto_secret_prop_get_iv, + qcrypto_secret_prop_set_iv); +} + + +int qcrypto_secret_lookup(const char *secretid, + uint8_t **data, + size_t *datalen, + Error **errp) +{ + Object *obj; + QCryptoSecretCommon *secret; + + obj = object_resolve_path_component( + object_get_objects_root(), secretid); + if (!obj) { + error_setg(errp, "No secret with id '%s'", secretid); + return -1; + } + + secret = (QCryptoSecretCommon *) + object_dynamic_cast(obj, + TYPE_QCRYPTO_SECRET_COMMON); + if (!secret) { + error_setg(errp, "Object with id '%s' is not a secret", + secretid); + return -1; + } + + if (!secret->rawdata) { + error_setg(errp, "Secret with id '%s' has no data", + secretid); + return -1; + } + + *data = g_new0(uint8_t, secret->rawlen + 1); + memcpy(*data, secret->rawdata, secret->rawlen); + (*data)[secret->rawlen] = '\0'; + *datalen = secret->rawlen; + + return 0; +} + + +char *qcrypto_secret_lookup_as_utf8(const char *secretid, + Error **errp) +{ + uint8_t *data; + size_t datalen; + + if (qcrypto_secret_lookup(secretid, + &data, + &datalen, + errp) < 0) { + return NULL; + } + + if (!g_utf8_validate((const gchar *)data, datalen, NULL)) { + error_setg(errp, + "Data from secret %s is not valid UTF-8", + secretid); + g_free(data); + return NULL; + } + + return (char *)data; +} + + +char *qcrypto_secret_lookup_as_base64(const char *secretid, + Error **errp) +{ + uint8_t *data; + size_t datalen; + char *ret; + + if (qcrypto_secret_lookup(secretid, + &data, + &datalen, + errp) < 0) { + return NULL; + } + + ret = g_base64_encode(data, datalen); + g_free(data); + return ret; +} + + +static const TypeInfo qcrypto_secret_info = { + .parent = TYPE_OBJECT, + .name = TYPE_QCRYPTO_SECRET_COMMON, + .instance_size = sizeof(QCryptoSecretCommon), + .instance_finalize = qcrypto_secret_finalize, + .class_size = sizeof(QCryptoSecretCommonClass), + .class_init = qcrypto_secret_class_init, + .abstract = true, +}; + + +static void +qcrypto_secret_register_types(void) +{ + type_register_static(&qcrypto_secret_info); +} + + +type_init(qcrypto_secret_register_types); diff --git a/include/crypto/secret.h b/include/crypto/secret.h index 5e07e29bae..2deb461d2f 100644 --- a/include/crypto/secret.h +++ b/include/crypto/secret.h @@ -23,6 +23,7 @@ #include "qapi/qapi-types-crypto.h" #include "qom/object.h" +#include "crypto/secret_common.h" #define TYPE_QCRYPTO_SECRET "secret" #define QCRYPTO_SECRET(obj) \ @@ -119,29 +120,14 @@ typedef struct QCryptoSecretClass QCryptoSecretClass; */ struct QCryptoSecret { - Object parent_obj; - uint8_t *rawdata; - size_t rawlen; - QCryptoSecretFormat format; + QCryptoSecretCommon parent_obj; char *data; char *file; - char *keyid; - char *iv; }; struct QCryptoSecretClass { - ObjectClass parent_class; + QCryptoSecretCommonClass parent_class; }; - -extern int qcrypto_secret_lookup(const char *secretid, - uint8_t **data, - size_t *datalen, - Error **errp); -extern char *qcrypto_secret_lookup_as_utf8(const char *secretid, - Error **errp); -extern char *qcrypto_secret_lookup_as_base64(const char *secretid, - Error **errp); - #endif /* QCRYPTO_SECRET_H */ diff --git a/include/crypto/secret_common.h b/include/crypto/secret_common.h new file mode 100644 index 0000000000..980c02ab71 --- /dev/null +++ b/include/crypto/secret_common.h @@ -0,0 +1,68 @@ +/* + * QEMU crypto secret support + * + * Copyright (c) 2015 Red Hat, Inc. + * + * 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.1 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 . + * + */ + +#ifndef QCRYPTO_SECRET_COMMON_H +#define QCRYPTO_SECRET_COMMON_H + +#include "qapi/qapi-types-crypto.h" +#include "qom/object.h" + +#define TYPE_QCRYPTO_SECRET_COMMON "secret_common" +#define QCRYPTO_SECRET_COMMON(obj) \ + OBJECT_CHECK(QCryptoSecretCommon, (obj), TYPE_QCRYPTO_SECRET_COMMON) +#define QCRYPTO_SECRET_COMMON_CLASS(class) \ + OBJECT_CLASS_CHECK(QCryptoSecretCommonClass, \ + (class), TYPE_QCRYPTO_SECRET_COMMON) +#define QCRYPTO_SECRET_COMMON_GET_CLASS(obj) \ + OBJECT_GET_CLASS(QCryptoSecretCommonClass, \ + (obj), TYPE_QCRYPTO_SECRET_COMMON) + +typedef struct QCryptoSecretCommon QCryptoSecretCommon; +typedef struct QCryptoSecretCommonClass QCryptoSecretCommonClass; + +struct QCryptoSecretCommon { + Object parent_obj; + uint8_t *rawdata; + size_t rawlen; + QCryptoSecretFormat format; + char *keyid; + char *iv; +}; + + +struct QCryptoSecretCommonClass { + ObjectClass parent_class; + void (*load_data)(QCryptoSecretCommon *secret, + uint8_t **output, + size_t *outputlen, + Error **errp); +}; + + +extern int qcrypto_secret_lookup(const char *secretid, + uint8_t **data, + size_t *datalen, + Error **errp); +extern char *qcrypto_secret_lookup_as_utf8(const char *secretid, + Error **errp); +extern char *qcrypto_secret_lookup_as_base64(const char *secretid, + Error **errp); + +#endif /* QCRYPTO_SECRET_COMMON_H */ From 54e7aac0562452e4fcab65ca5001d030eef2de15 Mon Sep 17 00:00:00 2001 From: Alexey Krasikov Date: Mon, 25 May 2020 14:19:12 +0300 Subject: [PATCH 1172/2595] crypto/linux_keyring: add 'secret_keyring' secret object. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the ability for the secret object to obtain secret data from the Linux in-kernel key managment and retention facility, as an extra option to the existing ones: reading from a file or passing directly as a string. The secret is identified by the key serial number. The upper layers need to instantiate the key and make sure the QEMU process has access permissions to read it. Signed-off-by: Alexey Krasikov - Fixed up detection logic default behaviour in configure Signed-off-by: Daniel P. Berrangé --- configure | 45 ++++++++++ crypto/Makefile.objs | 1 + crypto/secret_keyring.c | 148 ++++++++++++++++++++++++++++++++ include/crypto/secret_keyring.h | 52 +++++++++++ 4 files changed, 246 insertions(+) create mode 100644 crypto/secret_keyring.c create mode 100644 include/crypto/secret_keyring.h diff --git a/configure b/configure index 997284e094..3fbb61905a 100755 --- a/configure +++ b/configure @@ -510,6 +510,7 @@ default_devices="yes" plugins="no" fuzzing="no" rng_none="no" +secret_keyring="" supported_cpu="no" supported_os="no" @@ -1606,6 +1607,10 @@ for opt do ;; --disable-rng-none) rng_none=no ;; + --enable-keyring) secret_keyring="yes" + ;; + --disable-keyring) secret_keyring="no" + ;; *) echo "ERROR: unknown option $opt" echo "Try '$0 --help' for more information" @@ -6290,6 +6295,41 @@ case "$slirp" in ;; esac +########################################## +# check for usable __NR_keyctl syscall + +if test "$linux" = "yes" ; then + + have_keyring=no + cat > $TMPC << EOF +#include +#include +#include +#include +int main(void) { + return syscall(__NR_keyctl, KEYCTL_READ, 0, NULL, NULL, 0); +} +EOF + if compile_prog "" "" ; then + have_keyring=yes + fi +fi +if test "$secret_keyring" != "no" +then + if test "$have_keyring" == "yes" + then + secret_keyring=yes + else + if test "$secret_keyring" = "yes" + then + error_exit "syscall __NR_keyctl requested, \ +but not implemented on your system" + else + secret_keyring=no + fi + fi +fi + ########################################## # End of CC checks @@ -6774,6 +6814,7 @@ echo "plugin support $plugins" echo "fuzzing support $fuzzing" echo "gdb $gdb_bin" echo "rng-none $rng_none" +echo "Linux keyring $secret_keyring" if test "$supported_cpu" = "no"; then echo @@ -7659,6 +7700,10 @@ if test -n "$gdb_bin" ; then echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak fi +if test "$secret_keyring" = "yes" ; then + echo "CONFIG_SECRET_KEYRING=y" >> $config_host_mak +fi + if test "$tcg_interpreter" = "yes"; then QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES" elif test "$ARCH" = "sparc64" ; then diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs index 110dec1b87..707c02ad37 100644 --- a/crypto/Makefile.objs +++ b/crypto/Makefile.objs @@ -20,6 +20,7 @@ crypto-obj-y += tlscredsx509.o crypto-obj-y += tlssession.o crypto-obj-y += secret_common.o crypto-obj-y += secret.o +crypto-obj-$(CONFIG_SECRET_KEYRING) += secret_keyring.o crypto-obj-y += pbkdf.o crypto-obj-$(CONFIG_NETTLE) += pbkdf-nettle.o crypto-obj-$(if $(CONFIG_NETTLE),n,$(CONFIG_GCRYPT)) += pbkdf-gcrypt.o diff --git a/crypto/secret_keyring.c b/crypto/secret_keyring.c new file mode 100644 index 0000000000..4f132d6370 --- /dev/null +++ b/crypto/secret_keyring.c @@ -0,0 +1,148 @@ +/* + * QEMU crypto secret support + * + * Copyright 2020 Yandex N.V. + * + * 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.1 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 . + * + */ + +#include "qemu/osdep.h" +#include +#include +#include "qapi/error.h" +#include "qom/object_interfaces.h" +#include "trace.h" +#include "crypto/secret_keyring.h" + + +static inline +long keyctl_read(int32_t key, uint8_t *buffer, size_t buflen) +{ + return syscall(__NR_keyctl, KEYCTL_READ, key, buffer, buflen, 0); +} + + +static void +qcrypto_secret_keyring_load_data(QCryptoSecretCommon *sec_common, + uint8_t **output, + size_t *outputlen, + Error **errp) +{ + QCryptoSecretKeyring *secret = QCRYPTO_SECRET_KEYRING(sec_common); + uint8_t *buffer = NULL; + long retcode; + + *output = NULL; + *outputlen = 0; + + if (!secret->serial) { + error_setg(errp, "'serial' parameter must be provided"); + return; + } + + retcode = keyctl_read(secret->serial, NULL, 0); + if (retcode <= 0) { + goto keyctl_error; + } + + buffer = g_new0(uint8_t, retcode); + + retcode = keyctl_read(secret->serial, buffer, retcode); + if (retcode < 0) { + g_free(buffer); + goto keyctl_error; + } + + *outputlen = retcode; + *output = buffer; + return; + +keyctl_error: + error_setg_errno(errp, errno, + "Unable to read serial key %08x", + secret->serial); +} + + +static void +qcrypto_secret_prop_set_key(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + QCryptoSecretKeyring *secret = QCRYPTO_SECRET_KEYRING(obj); + int32_t value; + visit_type_int32(v, name, &value, errp); + if (!value) { + error_setg(errp, "'serial' should not be equal to 0"); + } + secret->serial = value; +} + + +static void +qcrypto_secret_prop_get_key(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + QCryptoSecretKeyring *secret = QCRYPTO_SECRET_KEYRING(obj); + int32_t value = secret->serial; + visit_type_int32(v, name, &value, errp); +} + + +static void +qcrypto_secret_keyring_complete(UserCreatable *uc, Error **errp) +{ + object_property_set_bool(OBJECT(uc), true, "loaded", errp); +} + + +static void +qcrypto_secret_keyring_class_init(ObjectClass *oc, void *data) +{ + QCryptoSecretCommonClass *sic = QCRYPTO_SECRET_COMMON_CLASS(oc); + sic->load_data = qcrypto_secret_keyring_load_data; + + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + ucc->complete = qcrypto_secret_keyring_complete; + + object_class_property_add(oc, "serial", "int32_t", + qcrypto_secret_prop_get_key, + qcrypto_secret_prop_set_key, + NULL, NULL); +} + + +static const TypeInfo qcrypto_secret_info = { + .parent = TYPE_QCRYPTO_SECRET_COMMON, + .name = TYPE_QCRYPTO_SECRET_KEYRING, + .instance_size = sizeof(QCryptoSecretKeyring), + .class_size = sizeof(QCryptoSecretKeyringClass), + .class_init = qcrypto_secret_keyring_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + + +static void +qcrypto_secret_register_types(void) +{ + type_register_static(&qcrypto_secret_info); +} + + +type_init(qcrypto_secret_register_types); diff --git a/include/crypto/secret_keyring.h b/include/crypto/secret_keyring.h new file mode 100644 index 0000000000..9f371ad251 --- /dev/null +++ b/include/crypto/secret_keyring.h @@ -0,0 +1,52 @@ +/* + * QEMU crypto secret support + * + * Copyright 2020 Yandex N.V. + * + * 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.1 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 . + * + */ + +#ifndef QCRYPTO_SECRET_KEYRING_H +#define QCRYPTO_SECRET_KEYRING_H + +#include "qapi/qapi-types-crypto.h" +#include "qom/object.h" +#include "crypto/secret_common.h" + +#define TYPE_QCRYPTO_SECRET_KEYRING "secret_keyring" +#define QCRYPTO_SECRET_KEYRING(obj) \ + OBJECT_CHECK(QCryptoSecretKeyring, (obj), \ + TYPE_QCRYPTO_SECRET_KEYRING) +#define QCRYPTO_SECRET_KEYRING_CLASS(class) \ + OBJECT_CLASS_CHECK(QCryptoSecretKeyringClass, \ + (class), TYPE_QCRYPTO_SECRET_KEYRING) +#define QCRYPTO_SECRET_KEYRING_GET_CLASS(class) \ + OBJECT_GET_CLASS(QCryptoSecretKeyringClass, \ + (class), TYPE_QCRYPTO_SECRET_KEYRING) + +typedef struct QCryptoSecretKeyring QCryptoSecretKeyring; +typedef struct QCryptoSecretKeyringClass QCryptoSecretKeyringClass; + +typedef struct QCryptoSecretKeyring { + QCryptoSecretCommon parent; + int32_t serial; +} QCryptoSecretKeyring; + + +typedef struct QCryptoSecretKeyringClass { + QCryptoSecretCommonClass parent; +} QCryptoSecretKeyringClass; + +#endif /* QCRYPTO_SECRET_KEYRING_H */ From 92500362210268faf4ae81644a66a7616d6bde1d Mon Sep 17 00:00:00 2001 From: Alexey Krasikov Date: Mon, 25 May 2020 14:19:13 +0300 Subject: [PATCH 1173/2595] test-crypto-secret: add 'secret_keyring' object tests. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests: test_secret_keyring_good; test_secret_keyring_revoked_key; test_secret_keyring_expired_key; test_secret_keyring_bad_serial_key; test_secret_keyring_bad_key_access_right; Added tests require libkeyutils. The absence of this library is not critical, because these tests will be skipped in this case. Signed-off-by: Alexey Krasikov Signed-off-by: Daniel P. Berrangé --- configure | 24 ++++++ tests/Makefile.include | 4 + tests/test-crypto-secret.c | 158 +++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+) diff --git a/configure b/configure index 3fbb61905a..07202acb9e 100755 --- a/configure +++ b/configure @@ -6330,6 +6330,27 @@ but not implemented on your system" fi fi +########################################## +# check for usable keyutils.h + +if test "$linux" = "yes" ; then + + have_keyutils=no + cat > $TMPC << EOF +#include +#include +#include +#include +#include +int main(void) { + return request_key("user", NULL, NULL, 0); +} +EOF + if compile_prog "" "-lkeyutils"; then + have_keyutils=yes + fi +fi + ########################################## # End of CC checks @@ -7702,6 +7723,9 @@ fi if test "$secret_keyring" = "yes" ; then echo "CONFIG_SECRET_KEYRING=y" >> $config_host_mak + if test "$have_keyutils" = "yes" ; then + echo "CONFIG_TEST_SECRET_KEYRING=y" >> $config_host_mak + fi fi if test "$tcg_interpreter" = "yes"; then diff --git a/tests/Makefile.include b/tests/Makefile.include index c2397de8ed..5607c7290d 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -540,6 +540,10 @@ tests/benchmark-crypto-cipher$(EXESUF): tests/benchmark-crypto-cipher.o $(test-c tests/test-crypto-secret$(EXESUF): tests/test-crypto-secret.o $(test-crypto-obj-y) tests/test-crypto-xts$(EXESUF): tests/test-crypto-xts.o $(test-crypto-obj-y) +ifeq ($(CONFIG_TEST_SECRET_KEYRING),y) +tests/test-crypto-secret.o-libs := -lkeyutils +endif + tests/crypto-tls-x509-helpers.o-cflags := $(TASN1_CFLAGS) tests/crypto-tls-x509-helpers.o-libs := $(TASN1_LIBS) tests/pkix_asn1_tab.o-cflags := $(TASN1_CFLAGS) diff --git a/tests/test-crypto-secret.c b/tests/test-crypto-secret.c index 13fc6c4c75..603a093f10 100644 --- a/tests/test-crypto-secret.c +++ b/tests/test-crypto-secret.c @@ -24,6 +24,10 @@ #include "crypto/secret.h" #include "qapi/error.h" #include "qemu/module.h" +#ifdef CONFIG_TEST_SECRET_KEYRING +#include "crypto/secret_keyring.h" +#include +#endif static void test_secret_direct(void) { @@ -124,6 +128,147 @@ static void test_secret_indirect_emptyfile(void) g_free(fname); } +#ifdef CONFIG_TEST_SECRET_KEYRING + +#define DESCRIPTION "qemu_test_secret" +#define PAYLOAD "Test Payload" + + +static void test_secret_keyring_good(void) +{ + char key_str[16]; + Object *sec; + int32_t key = add_key("user", DESCRIPTION, PAYLOAD, + strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING); + + g_assert(key >= 0); + + snprintf(key_str, sizeof(key_str), "0x%08x", key); + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET_KEYRING, + object_get_objects_root(), + "sec0", + &error_abort, + "serial", key_str, + NULL); + + assert(0 <= keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING)); + char *pw = qcrypto_secret_lookup_as_utf8("sec0", + &error_abort); + g_assert_cmpstr(pw, ==, PAYLOAD); + + object_unparent(sec); + g_free(pw); +} + + +static void test_secret_keyring_revoked_key(void) +{ + char key_str[16]; + Object *sec; + int32_t key = add_key("user", DESCRIPTION, PAYLOAD, + strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING); + g_assert(key >= 0); + g_assert_false(keyctl_revoke(key)); + + snprintf(key_str, sizeof(key_str), "0x%08x", key); + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET_KEYRING, + object_get_objects_root(), + "sec0", + NULL, + "serial", key_str, + NULL); + + g_assert(errno == EKEYREVOKED); + g_assert(sec == NULL); + + keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING); +} + + +static void test_secret_keyring_expired_key(void) +{ + char key_str[16]; + Object *sec; + int32_t key = add_key("user", DESCRIPTION, PAYLOAD, + strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING); + g_assert(key >= 0); + g_assert_false(keyctl_set_timeout(key, 1)); + sleep(1); + + snprintf(key_str, sizeof(key_str), "0x%08x", key); + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET_KEYRING, + object_get_objects_root(), + "sec0", + NULL, + "serial", key_str, + NULL); + + g_assert(errno == EKEYEXPIRED); + g_assert(sec == NULL); + + keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING); +} + + +static void test_secret_keyring_bad_serial_key(void) +{ + Object *sec; + + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET_KEYRING, + object_get_objects_root(), + "sec0", + NULL, + "serial", "1", + NULL); + + g_assert(errno == ENOKEY); + g_assert(sec == NULL); +} + +/* + * TODO + * test_secret_keyring_bad_key_access_right() is not working yet. + * We don't know yet if this due a bug in the Linux kernel or + * whether it's normal syscall behavior. + * We've requested information from kernel maintainers. + * See: + * Thread: 'security/keys: remove possessor verify after key permission check' + */ + +static void test_secret_keyring_bad_key_access_right(void) +{ + char key_str[16]; + Object *sec; + + g_test_skip("TODO: Need responce from Linux kernel maintainers"); + return; + + int32_t key = add_key("user", DESCRIPTION, PAYLOAD, + strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING); + g_assert(key >= 0); + g_assert_false(keyctl_setperm(key, KEY_POS_ALL & (~KEY_POS_READ))); + + snprintf(key_str, sizeof(key_str), "0x%08x", key); + + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET_KEYRING, + object_get_objects_root(), + "sec0", + NULL, + "serial", key_str, + NULL); + + g_assert(errno == EACCES); + g_assert(sec == NULL); + + keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING); +} + +#endif /* CONFIG_TEST_SECRET_KEYRING */ static void test_secret_noconv_base64_good(void) { @@ -426,6 +571,19 @@ int main(int argc, char **argv) g_test_add_func("/crypto/secret/indirect/emptyfile", test_secret_indirect_emptyfile); +#ifdef CONFIG_TEST_SECRET_KEYRING + g_test_add_func("/crypto/secret/keyring/good", + test_secret_keyring_good); + g_test_add_func("/crypto/secret/keyring/revoked_key", + test_secret_keyring_revoked_key); + g_test_add_func("/crypto/secret/keyring/expired_key", + test_secret_keyring_expired_key); + g_test_add_func("/crypto/secret/keyring/bad_serial_key", + test_secret_keyring_bad_serial_key); + g_test_add_func("/crypto/secret/keyring/bad_key_access_right", + test_secret_keyring_bad_key_access_right); +#endif /* CONFIG_TEST_SECRET_KEYRING */ + g_test_add_func("/crypto/secret/noconv/base64/good", test_secret_noconv_base64_good); g_test_add_func("/crypto/secret/noconv/base64/bad", From d6cca8e111696fbbd7c233dc53f9c80b6a43359d Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 27 May 2020 10:34:09 +0100 Subject: [PATCH 1174/2595] crypto: Remove use of GCRYPT_VERSION macro. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the gcrypt documentation it's intended that gcry_check_version() is called with the minimum version of gcrypt needed by the program, not the version from the header file that happened to be installed when qemu was compiled. Indeed the gcrypt.h header says that you shouldn't use the GCRYPT_VERSION macro. This causes the following failure: qemu-img: Unable to initialize gcrypt if a slightly older version of libgcrypt is installed with a newer qemu, even though the slightly older version works fine. This can happen with RPM packaging which uses symbol versioning to determine automatically which libgcrypt is required by qemu, which caused the following bug in RHEL 8: https://bugzilla.redhat.com/show_bug.cgi?id=1840485 qemu actually requires libgcrypt >= 1.5.0, so we might put the string "1.5.0" here. However since 1.5.0 was released in 2011, it hardly seems we need to check that. So I replaced GCRYPT_VERSION with NULL. Perhaps in future if we move to requiring a newer version of gcrypt we could put a literal string here. Signed-off-by: Richard W.M. Jones Signed-off-by: Daniel P. Berrangé --- crypto/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/init.c b/crypto/init.c index b305381ec5..ea233b9192 100644 --- a/crypto/init.c +++ b/crypto/init.c @@ -122,7 +122,7 @@ int qcrypto_init(Error **errp) #endif #ifdef CONFIG_GCRYPT - if (!gcry_check_version(GCRYPT_VERSION)) { + if (!gcry_check_version(NULL)) { error_setg(errp, "Unable to initialize gcrypt"); return -1; } From 55b9757c7e58092068d6788114b9e347406ed7f9 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 15 Jun 2020 15:50:51 +0200 Subject: [PATCH 1175/2595] bios-tables-test: Fix "-tpmdev: invalid option" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When configure is run with "--disable-tpm", the bios-tables-test q35/tis test fails with "-tpmdev: invalid option". Skip the test if CONFIG_TPM is unset. Signed-off-by: Eric Auger Reported-by: Philippe Mathieu-Daudé Message-Id: <20200615135051.2213-1-eric.auger@redhat.com> Tested-by: Stefan Berger Fixes: 5da7c35e25 ("bios-tables-test: Add Q35/TPM-TIS test") Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- tests/qtest/bios-tables-test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 53f104a9c5..b482f76c03 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -882,6 +882,7 @@ uint64_t tpm_tis_base_addr; static void test_acpi_tcg_tpm(const char *machine, const char *tpm_if, uint64_t base) { +#ifdef CONFIG_TPM gchar *tmp_dir_name = g_strdup_printf("qemu-test_acpi_%s_tcg_%s.XXXXXX", machine, tpm_if); char *tmp_path = g_dir_make_tmp(tmp_dir_name, NULL); @@ -924,6 +925,9 @@ static void test_acpi_tcg_tpm(const char *machine, const char *tpm_if, g_free(tmp_path); g_free(tmp_dir_name); free_test_data(&data); +#else + g_test_skip("TPM disabled"); +#endif } static void test_acpi_q35_tcg_tpm_tis(void) From d92e1b6d5439e04d2b863113ce714709f40fb84e Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Fri, 29 May 2020 18:14:49 -0400 Subject: [PATCH 1176/2595] fuzz: skip QTest serialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QTest server usually parses ASCII commands from clients. Since we fuzz within the QEMU process, skip the QTest serialization and server for most QTest commands. Leave the option to use the ASCII protocol, to generate readable traces for crash reproducers. Inspired-by: Philippe Mathieu-Daudé Signed-off-by: Alexander Bulekov Message-Id: <20200529221450.26673-2-alxndr@bu.edu> Reviewed-by: Darren Kenny Signed-off-by: Thomas Huth --- tests/qtest/fuzz/Makefile.include | 21 +++ tests/qtest/fuzz/fuzz.c | 13 +- tests/qtest/fuzz/fuzz.h | 3 + tests/qtest/fuzz/qtest_wrappers.c | 252 ++++++++++++++++++++++++++++++ 4 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/fuzz/qtest_wrappers.c diff --git a/tests/qtest/fuzz/Makefile.include b/tests/qtest/fuzz/Makefile.include index f259d866c9..5bde793bf2 100644 --- a/tests/qtest/fuzz/Makefile.include +++ b/tests/qtest/fuzz/Makefile.include @@ -5,6 +5,7 @@ fuzz-obj-y += $(libqos-obj-y) fuzz-obj-y += tests/qtest/fuzz/fuzz.o # Fuzzer skeleton fuzz-obj-y += tests/qtest/fuzz/fork_fuzz.o fuzz-obj-y += tests/qtest/fuzz/qos_fuzz.o +fuzz-obj-y += tests/qtest/fuzz/qtest_wrappers.o # Targets fuzz-obj-$(CONFIG_PCI_I440FX) += tests/qtest/fuzz/i440fx_fuzz.o @@ -16,3 +17,23 @@ FUZZ_CFLAGS += -I$(SRC_PATH)/tests -I$(SRC_PATH)/tests/qtest # Linker Script to force coverage-counters into known regions which we can mark # shared FUZZ_LDFLAGS += -Xlinker -T$(SRC_PATH)/tests/qtest/fuzz/fork_fuzz.ld + +FUZZ_LDFLAGS += -Wl,-wrap,qtest_inb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_inw +FUZZ_LDFLAGS += -Wl,-wrap,qtest_inl +FUZZ_LDFLAGS += -Wl,-wrap,qtest_outb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_outw +FUZZ_LDFLAGS += -Wl,-wrap,qtest_outl +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readw +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readl +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readq +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writeb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writew +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writel +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writeq +FUZZ_LDFLAGS += -Wl,-wrap,qtest_memread +FUZZ_LDFLAGS += -Wl,-wrap,qtest_bufread +FUZZ_LDFLAGS += -Wl,-wrap,qtest_memwrite +FUZZ_LDFLAGS += -Wl,-wrap,qtest_bufwrite +FUZZ_LDFLAGS += -Wl,-wrap,qtest_memset diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 33365c3782..ea630ddb9b 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -91,7 +91,10 @@ static void usage(char *path) printf(" * %s : %s\n", tmp->target->name, tmp->target->description); } - printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n"); + printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n\n" + "Set the environment variable FUZZ_SERIALIZE_QTEST=1 to serialize\n" + "QTest commands into an ASCII protocol. Useful for building crash\n" + "reproducers, but slows down execution.\n"); exit(0); } @@ -138,6 +141,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) char *target_name; char *dir; + bool serialize = false; /* Initialize qgraph and modules */ qos_graph_init(); @@ -172,6 +176,13 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) usage(**argv); } + /* Should we always serialize qtest commands? */ + if (getenv("FUZZ_SERIALIZE_QTEST")) { + serialize = true; + } + + fuzz_qtest_set_serialize(serialize); + /* Identify the fuzz target */ fuzz_target = fuzz_get_target(target_name); if (!fuzz_target) { diff --git a/tests/qtest/fuzz/fuzz.h b/tests/qtest/fuzz/fuzz.h index 03901d414e..72d5710f6c 100644 --- a/tests/qtest/fuzz/fuzz.h +++ b/tests/qtest/fuzz/fuzz.h @@ -82,6 +82,9 @@ typedef struct FuzzTarget { void flush_events(QTestState *); void reboot(QTestState *); +/* Use the QTest ASCII protocol or call address_space API directly?*/ +void fuzz_qtest_set_serialize(bool option); + /* * makes a copy of *target and adds it to the target-list. * i.e. fine to set up target on the caller's stack diff --git a/tests/qtest/fuzz/qtest_wrappers.c b/tests/qtest/fuzz/qtest_wrappers.c new file mode 100644 index 0000000000..713c830cdb --- /dev/null +++ b/tests/qtest/fuzz/qtest_wrappers.c @@ -0,0 +1,252 @@ +/* + * qtest function wrappers + * + * Copyright Red Hat Inc., 2019 + * + * Authors: + * Alexander Bulekov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/ioport.h" + +#include "fuzz.h" + +static bool serialize = true; + +#define WRAP(RET_TYPE, NAME_AND_ARGS)\ + RET_TYPE __wrap_##NAME_AND_ARGS;\ + RET_TYPE __real_##NAME_AND_ARGS; + +WRAP(uint8_t , qtest_inb(QTestState *s, uint16_t addr)) +WRAP(uint16_t , qtest_inw(QTestState *s, uint16_t addr)) +WRAP(uint32_t , qtest_inl(QTestState *s, uint16_t addr)) +WRAP(void , qtest_outb(QTestState *s, uint16_t addr, uint8_t value)) +WRAP(void , qtest_outw(QTestState *s, uint16_t addr, uint16_t value)) +WRAP(void , qtest_outl(QTestState *s, uint16_t addr, uint32_t value)) +WRAP(uint8_t , qtest_readb(QTestState *s, uint64_t addr)) +WRAP(uint16_t , qtest_readw(QTestState *s, uint64_t addr)) +WRAP(uint32_t , qtest_readl(QTestState *s, uint64_t addr)) +WRAP(uint64_t , qtest_readq(QTestState *s, uint64_t addr)) +WRAP(void , qtest_writeb(QTestState *s, uint64_t addr, uint8_t value)) +WRAP(void , qtest_writew(QTestState *s, uint64_t addr, uint16_t value)) +WRAP(void , qtest_writel(QTestState *s, uint64_t addr, uint32_t value)) +WRAP(void , qtest_writeq(QTestState *s, uint64_t addr, uint64_t value)) +WRAP(void , qtest_memread(QTestState *s, uint64_t addr, + void *data, size_t size)) +WRAP(void , qtest_bufread(QTestState *s, uint64_t addr, void *data, + size_t size)) +WRAP(void , qtest_memwrite(QTestState *s, uint64_t addr, const void *data, + size_t size)) +WRAP(void, qtest_bufwrite(QTestState *s, uint64_t addr, + const void *data, size_t size)) +WRAP(void, qtest_memset(QTestState *s, uint64_t addr, + uint8_t patt, size_t size)) + + +uint8_t __wrap_qtest_inb(QTestState *s, uint16_t addr) +{ + if (!serialize) { + return cpu_inb(addr); + } else { + return __real_qtest_inb(s, addr); + } +} + +uint16_t __wrap_qtest_inw(QTestState *s, uint16_t addr) +{ + if (!serialize) { + return cpu_inw(addr); + } else { + return __real_qtest_inw(s, addr); + } +} + +uint32_t __wrap_qtest_inl(QTestState *s, uint16_t addr) +{ + if (!serialize) { + return cpu_inl(addr); + } else { + return __real_qtest_inl(s, addr); + } +} + +void __wrap_qtest_outb(QTestState *s, uint16_t addr, uint8_t value) +{ + if (!serialize) { + cpu_outb(addr, value); + } else { + __real_qtest_outb(s, addr, value); + } +} + +void __wrap_qtest_outw(QTestState *s, uint16_t addr, uint16_t value) +{ + if (!serialize) { + cpu_outw(addr, value); + } else { + __real_qtest_outw(s, addr, value); + } +} + +void __wrap_qtest_outl(QTestState *s, uint16_t addr, uint32_t value) +{ + if (!serialize) { + cpu_outl(addr, value); + } else { + __real_qtest_outl(s, addr, value); + } +} + +uint8_t __wrap_qtest_readb(QTestState *s, uint64_t addr) +{ + uint8_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 1); + return value; + } else { + return __real_qtest_readb(s, addr); + } +} + +uint16_t __wrap_qtest_readw(QTestState *s, uint64_t addr) +{ + uint16_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 2); + return value; + } else { + return __real_qtest_readw(s, addr); + } +} + +uint32_t __wrap_qtest_readl(QTestState *s, uint64_t addr) +{ + uint32_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 4); + return value; + } else { + return __real_qtest_readl(s, addr); + } +} + +uint64_t __wrap_qtest_readq(QTestState *s, uint64_t addr) +{ + uint64_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 8); + return value; + } else { + return __real_qtest_readq(s, addr); + } +} + +void __wrap_qtest_writeb(QTestState *s, uint64_t addr, uint8_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 1); + } else { + __real_qtest_writeb(s, addr, value); + } +} + +void __wrap_qtest_writew(QTestState *s, uint64_t addr, uint16_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 2); + } else { + __real_qtest_writew(s, addr, value); + } +} + +void __wrap_qtest_writel(QTestState *s, uint64_t addr, uint32_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 4); + } else { + __real_qtest_writel(s, addr, value); + } +} + +void __wrap_qtest_writeq(QTestState *s, uint64_t addr, uint64_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 8); + } else { + __real_qtest_writeq(s, addr, value); + } +} + +void __wrap_qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size) +{ + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data, + size); + } else { + __real_qtest_memread(s, addr, data, size); + } +} + +void __wrap_qtest_bufread(QTestState *s, uint64_t addr, void *data, size_t size) +{ + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data, + size); + } else { + __real_qtest_bufread(s, addr, data, size); + } +} + +void __wrap_qtest_memwrite(QTestState *s, uint64_t addr, const void *data, + size_t size) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + data, size); + } else { + __real_qtest_memwrite(s, addr, data, size); + } +} + +void __wrap_qtest_bufwrite(QTestState *s, uint64_t addr, + const void *data, size_t size) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + data, size); + } else { + __real_qtest_bufwrite(s, addr, data, size); + } +} +void __wrap_qtest_memset(QTestState *s, uint64_t addr, + uint8_t patt, size_t size) +{ + void *data; + if (!serialize) { + data = malloc(size); + memset(data, patt, size); + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + data, size); + } else { + __real_qtest_memset(s, addr, patt, size); + } +} + +void fuzz_qtest_set_serialize(bool option) +{ + serialize = option; +} From 8efebd4e0171a6f11f7ac085898d315fcac0e066 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Fri, 29 May 2020 18:14:50 -0400 Subject: [PATCH 1177/2595] fuzz: Add support for logging QTest commands Signed-off-by: Alexander Bulekov Message-Id: <20200529221450.26673-3-alxndr@bu.edu> Reviewed-by: Darren Kenny Signed-off-by: Thomas Huth --- tests/qtest/fuzz/fuzz.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index ea630ddb9b..a44fe479db 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -94,7 +94,9 @@ static void usage(char *path) printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n\n" "Set the environment variable FUZZ_SERIALIZE_QTEST=1 to serialize\n" "QTest commands into an ASCII protocol. Useful for building crash\n" - "reproducers, but slows down execution.\n"); + "reproducers, but slows down execution.\n\n" + "Set the environment variable QTEST_LOG=1 to log all qtest commands" + "\n"); exit(0); } @@ -197,6 +199,11 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) /* Run QEMU's softmmu main with the fuzz-target dependent arguments */ const char *init_cmdline = fuzz_target->get_init_cmdline(fuzz_target); + init_cmdline = g_strdup_printf("%s -qtest /dev/null -qtest-log %s", + init_cmdline, + getenv("QTEST_LOG") ? "/dev/fd/2" + : "/dev/null"); + /* Split the runcmd into an argv and argc */ wordexp_t result; From 211635b3a2e717a09fc7fdb475c93d9ccab125e7 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Fri, 12 Jun 2020 01:51:45 -0400 Subject: [PATCH 1178/2595] fuzz: add oss-fuzz build-script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is neater to keep this in the QEMU repo, since any change that requires an update to the oss-fuzz build configuration, can make the necessary changes in the same series. Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny Message-Id: <20200612055145.12101-1-alxndr@bu.edu> Signed-off-by: Thomas Huth --- MAINTAINERS | 1 + scripts/oss-fuzz/build.sh | 105 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100755 scripts/oss-fuzz/build.sh diff --git a/MAINTAINERS b/MAINTAINERS index a922775e45..9ec50e165d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2339,6 +2339,7 @@ R: Bandan Das R: Stefan Hajnoczi S: Maintained F: tests/qtest/fuzz/ +F: scripts/oss-fuzz/ Register API M: Alistair Francis diff --git a/scripts/oss-fuzz/build.sh b/scripts/oss-fuzz/build.sh new file mode 100755 index 0000000000..f5cee3d67e --- /dev/null +++ b/scripts/oss-fuzz/build.sh @@ -0,0 +1,105 @@ +#!/bin/sh -e +# +# OSS-Fuzz build script. See: +# https://google.github.io/oss-fuzz/getting-started/new-project-guide/#buildsh +# +# The file is consumed by: +# https://github.com/google/oss-fuzz/blob/master/projects/qemu/Dockerfiles +# +# This code is licensed under the GPL version 2 or later. See +# the COPYING file in the top-level directory. +# + +# build project +# e.g. +# ./autogen.sh +# ./configure +# make -j$(nproc) all + +# build fuzzers +# e.g. +# $CXX $CXXFLAGS -std=c++11 -Iinclude \ +# /path/to/name_of_fuzzer.cc -o $OUT/name_of_fuzzer \ +# $LIB_FUZZING_ENGINE /path/to/library.a + +fatal () { + echo "Error : ${*}, exiting." + exit 1 +} + +OSS_FUZZ_BUILD_DIR="./build-oss-fuzz/" + +# There seems to be a bug in clang-11 (used for builds on oss-fuzz) : +# accel/tcg/cputlb.o: In function `load_memop': +# accel/tcg/cputlb.c:1505: undefined reference to `qemu_build_not_reached' +# +# When building with optimization, the compiler is expected to prove that the +# statement cannot be reached, and remove it. For some reason clang-11 doesn't +# remove it, resulting in an unresolved reference to qemu_build_not_reached +# Undefine the __OPTIMIZE__ macro which compiler.h relies on to choose whether +# to " #define qemu_build_not_reached() g_assert_not_reached() " +EXTRA_CFLAGS="$CFLAGS -U __OPTIMIZE__" + +if ! { [ -e "./COPYING" ] && + [ -e "./MAINTAINERS" ] && + [ -e "./Makefile" ] && + [ -e "./docs" ] && + [ -e "./VERSION" ] && + [ -e "./linux-user" ] && + [ -e "./softmmu" ];} ; then + fatal "Please run the script from the top of the QEMU tree" +fi + +mkdir -p $OSS_FUZZ_BUILD_DIR || fatal "mkdir $OSS_FUZZ_BUILD_DIR failed" +cd $OSS_FUZZ_BUILD_DIR || fatal "cd $OSS_FUZZ_BUILD_DIR failed" + + +if [ -z ${LIB_FUZZING_ENGINE+x} ]; then + LIB_FUZZING_ENGINE="-fsanitize=fuzzer" +fi + +if [ -z ${OUT+x} ]; then + DEST_DIR=$(realpath "./DEST_DIR") +else + DEST_DIR=$OUT +fi + +mkdir -p "$DEST_DIR/lib/" # Copy the shared libraries here + +# Build once to get the list of dynamic lib paths, and copy them over +../configure --disable-werror --cc="$CC" --cxx="$CXX" \ + --extra-cflags="$EXTRA_CFLAGS" + +if ! make CONFIG_FUZZ=y CFLAGS="$LIB_FUZZING_ENGINE" "-j$(nproc)" \ + i386-softmmu/fuzz; then + fatal "Build failed. Please specify a compiler with fuzzing support"\ + "using the \$CC and \$CXX environemnt variables, or specify a"\ + "\$LIB_FUZZING_ENGINE compatible with your compiler"\ + "\nFor example: CC=clang CXX=clang++ $0" +fi + +for i in $(ldd ./i386-softmmu/qemu-fuzz-i386 | cut -f3 -d' '); do + cp "$i" "$DEST_DIR/lib/" +done +rm ./i386-softmmu/qemu-fuzz-i386 + +# Build a second time to build the final binary with correct rpath +../configure --bindir="$DEST_DIR" --datadir="$DEST_DIR/data/" --disable-werror \ + --cc="$CC" --cxx="$CXX" --extra-cflags="$EXTRA_CFLAGS" \ + --extra-ldflags="-Wl,-rpath,'\$\$ORIGIN/lib'" +make CONFIG_FUZZ=y CFLAGS="$LIB_FUZZING_ENGINE" "-j$(nproc)" i386-softmmu/fuzz + +# Copy over the datadir +cp -r ../pc-bios/ "$DEST_DIR/pc-bios" + +# Run the fuzzer with no arguments, to print the help-string and get the list +# of available fuzz-targets. Copy over the qemu-fuzz-i386, naming it according +# to each available fuzz target (See 05509c8e6d fuzz: select fuzz target using +# executable name) +for target in $(./i386-softmmu/qemu-fuzz-i386 | awk '$1 ~ /\*/ {print $2}'); +do + cp ./i386-softmmu/qemu-fuzz-i386 "$DEST_DIR/qemu-fuzz-i386-target-$target" +done + +echo "Done. The fuzzers are located in $DEST_DIR" +exit 0 From dc0ad02df963245d2d8aa7437afff6b9e2c55207 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 5 Jun 2020 12:02:42 +0200 Subject: [PATCH 1179/2595] tests/qtest: Fix LGPL information in the file headers It's either "GNU *Library* General Public License version 2" or "GNU Lesser General Public License version *2.1*", but there was no "version 2.0" of the "Lesser" license. So assume that version 2.1 is meant here. Message-Id: <20200605100645.6506-1-thuth@redhat.com> Reviewed-by: Laurent Vivier Reviewed-by: Stefan Hajnoczi Signed-off-by: Thomas Huth --- tests/qtest/e1000e-test.c | 2 +- tests/qtest/fuzz/qos_fuzz.c | 2 +- tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c | 2 +- tests/qtest/libqos/arm-imx25-pdk-machine.c | 2 +- tests/qtest/libqos/arm-n800-machine.c | 2 +- tests/qtest/libqos/arm-raspi2-machine.c | 2 +- tests/qtest/libqos/arm-sabrelite-machine.c | 2 +- tests/qtest/libqos/arm-smdkc210-machine.c | 2 +- tests/qtest/libqos/arm-virt-machine.c | 2 +- tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c | 2 +- tests/qtest/libqos/e1000e.c | 2 +- tests/qtest/libqos/e1000e.h | 2 +- tests/qtest/libqos/ppc64_pseries-machine.c | 2 +- tests/qtest/libqos/qgraph.c | 2 +- tests/qtest/libqos/qgraph.h | 2 +- tests/qtest/libqos/qgraph_internal.h | 2 +- tests/qtest/libqos/qos_external.c | 2 +- tests/qtest/libqos/qos_external.h | 2 +- tests/qtest/libqos/sdhci.c | 2 +- tests/qtest/libqos/sdhci.h | 2 +- tests/qtest/libqos/virtio-9p.c | 2 +- tests/qtest/libqos/virtio-9p.h | 2 +- tests/qtest/libqos/virtio-balloon.c | 2 +- tests/qtest/libqos/virtio-balloon.h | 2 +- tests/qtest/libqos/virtio-blk.c | 2 +- tests/qtest/libqos/virtio-blk.h | 2 +- tests/qtest/libqos/virtio-net.c | 2 +- tests/qtest/libqos/virtio-net.h | 2 +- tests/qtest/libqos/virtio-rng.c | 2 +- tests/qtest/libqos/virtio-rng.h | 2 +- tests/qtest/libqos/virtio-scsi.c | 2 +- tests/qtest/libqos/virtio-scsi.h | 2 +- tests/qtest/libqos/virtio-serial.c | 2 +- tests/qtest/libqos/virtio-serial.h | 2 +- tests/qtest/libqos/x86_64_pc-machine.c | 2 +- tests/qtest/qos-test.c | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/tests/qtest/e1000e-test.c b/tests/qtest/e1000e-test.c index 1a232a663a..fc226fdfeb 100644 --- a/tests/qtest/e1000e-test.c +++ b/tests/qtest/e1000e-test.c @@ -12,7 +12,7 @@ * 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. + * version 2.1 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 diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c index 87eadb0889..0c68f5361f 100644 --- a/tests/qtest/fuzz/qos_fuzz.c +++ b/tests/qtest/fuzz/qos_fuzz.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c b/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c index 1d5de5af00..8f827aeb52 100644 --- a/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c +++ b/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-imx25-pdk-machine.c b/tests/qtest/libqos/arm-imx25-pdk-machine.c index 25066fb8a9..0da3f19c0e 100644 --- a/tests/qtest/libqos/arm-imx25-pdk-machine.c +++ b/tests/qtest/libqos/arm-imx25-pdk-machine.c @@ -7,7 +7,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-n800-machine.c b/tests/qtest/libqos/arm-n800-machine.c index 87279bdb26..35f82070fa 100644 --- a/tests/qtest/libqos/arm-n800-machine.c +++ b/tests/qtest/libqos/arm-n800-machine.c @@ -7,7 +7,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-raspi2-machine.c b/tests/qtest/libqos/arm-raspi2-machine.c index 12a7cb7e4b..8480d80669 100644 --- a/tests/qtest/libqos/arm-raspi2-machine.c +++ b/tests/qtest/libqos/arm-raspi2-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-sabrelite-machine.c b/tests/qtest/libqos/arm-sabrelite-machine.c index e6df43795a..f6e403b538 100644 --- a/tests/qtest/libqos/arm-sabrelite-machine.c +++ b/tests/qtest/libqos/arm-sabrelite-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-smdkc210-machine.c b/tests/qtest/libqos/arm-smdkc210-machine.c index 215b628a7d..eebac7feeb 100644 --- a/tests/qtest/libqos/arm-smdkc210-machine.c +++ b/tests/qtest/libqos/arm-smdkc210-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-virt-machine.c b/tests/qtest/libqos/arm-virt-machine.c index 96ffe3ee5c..9316598f9e 100644 --- a/tests/qtest/libqos/arm-virt-machine.c +++ b/tests/qtest/libqos/arm-virt-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c b/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c index 5bc95f2e73..473acce993 100644 --- a/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c +++ b/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/e1000e.c b/tests/qtest/libqos/e1000e.c index 560e7a2bb2..e2927ed2da 100644 --- a/tests/qtest/libqos/e1000e.c +++ b/tests/qtest/libqos/e1000e.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/e1000e.h b/tests/qtest/libqos/e1000e.h index dc4ab10f58..35183b2875 100644 --- a/tests/qtest/libqos/e1000e.h +++ b/tests/qtest/libqos/e1000e.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/ppc64_pseries-machine.c b/tests/qtest/libqos/ppc64_pseries-machine.c index 867f27a3c8..5d7bd88f2f 100644 --- a/tests/qtest/libqos/ppc64_pseries-machine.c +++ b/tests/qtest/libqos/ppc64_pseries-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/qgraph.c b/tests/qtest/libqos/qgraph.c index ca01de0743..eb0af8ab4a 100644 --- a/tests/qtest/libqos/qgraph.c +++ b/tests/qtest/libqos/qgraph.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/qgraph.h b/tests/qtest/libqos/qgraph.h index 3a25dda4b2..db1244eb59 100644 --- a/tests/qtest/libqos/qgraph.h +++ b/tests/qtest/libqos/qgraph.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/qgraph_internal.h b/tests/qtest/libqos/qgraph_internal.h index f4734c8681..aa3123f0f2 100644 --- a/tests/qtest/libqos/qgraph_internal.h +++ b/tests/qtest/libqos/qgraph_internal.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/qos_external.c b/tests/qtest/libqos/qos_external.c index 9f5180e18d..0dfc05cfb6 100644 --- a/tests/qtest/libqos/qos_external.c +++ b/tests/qtest/libqos/qos_external.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/qos_external.h b/tests/qtest/libqos/qos_external.h index 72d7f91707..56a2f37fde 100644 --- a/tests/qtest/libqos/qos_external.h +++ b/tests/qtest/libqos/qos_external.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/sdhci.c b/tests/qtest/libqos/sdhci.c index 309794bc52..fbf2e36aec 100644 --- a/tests/qtest/libqos/sdhci.c +++ b/tests/qtest/libqos/sdhci.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/sdhci.h b/tests/qtest/libqos/sdhci.h index a88b45ae9d..1acd3096e2 100644 --- a/tests/qtest/libqos/sdhci.h +++ b/tests/qtest/libqos/sdhci.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c index 77dbfb62ad..c87b56132a 100644 --- a/tests/qtest/libqos/virtio-9p.c +++ b/tests/qtest/libqos/virtio-9p.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-9p.h b/tests/qtest/libqos/virtio-9p.h index b54e89b3a1..be9621a5e3 100644 --- a/tests/qtest/libqos/virtio-9p.h +++ b/tests/qtest/libqos/virtio-9p.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-balloon.c b/tests/qtest/libqos/virtio-balloon.c index 42a4c5831e..9745f4a83c 100644 --- a/tests/qtest/libqos/virtio-balloon.c +++ b/tests/qtest/libqos/virtio-balloon.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-balloon.h b/tests/qtest/libqos/virtio-balloon.h index 52661cc87d..5b919303a6 100644 --- a/tests/qtest/libqos/virtio-balloon.h +++ b/tests/qtest/libqos/virtio-balloon.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-blk.c b/tests/qtest/libqos/virtio-blk.c index 726e93c5c1..5fc69401be 100644 --- a/tests/qtest/libqos/virtio-blk.c +++ b/tests/qtest/libqos/virtio-blk.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-blk.h b/tests/qtest/libqos/virtio-blk.h index c05adc659d..5170f13cfe 100644 --- a/tests/qtest/libqos/virtio-blk.h +++ b/tests/qtest/libqos/virtio-blk.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-net.c b/tests/qtest/libqos/virtio-net.c index 710d440c3d..a9e253afe4 100644 --- a/tests/qtest/libqos/virtio-net.c +++ b/tests/qtest/libqos/virtio-net.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-net.h b/tests/qtest/libqos/virtio-net.h index 855c67d00f..b8cbec04af 100644 --- a/tests/qtest/libqos/virtio-net.h +++ b/tests/qtest/libqos/virtio-net.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-rng.c b/tests/qtest/libqos/virtio-rng.c index b86349e2fd..46f8d95b1f 100644 --- a/tests/qtest/libqos/virtio-rng.c +++ b/tests/qtest/libqos/virtio-rng.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-rng.h b/tests/qtest/libqos/virtio-rng.h index 9e192f11f7..9342372efa 100644 --- a/tests/qtest/libqos/virtio-rng.h +++ b/tests/qtest/libqos/virtio-rng.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-scsi.c b/tests/qtest/libqos/virtio-scsi.c index de739bec5f..c8c3598428 100644 --- a/tests/qtest/libqos/virtio-scsi.c +++ b/tests/qtest/libqos/virtio-scsi.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-scsi.h b/tests/qtest/libqos/virtio-scsi.h index 4ca19a6a7a..9e3774d99a 100644 --- a/tests/qtest/libqos/virtio-scsi.h +++ b/tests/qtest/libqos/virtio-scsi.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-serial.c b/tests/qtest/libqos/virtio-serial.c index 3e5b8b82c7..b95654085d 100644 --- a/tests/qtest/libqos/virtio-serial.c +++ b/tests/qtest/libqos/virtio-serial.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-serial.h b/tests/qtest/libqos/virtio-serial.h index 080fa8428d..3328c6cf19 100644 --- a/tests/qtest/libqos/virtio-serial.h +++ b/tests/qtest/libqos/virtio-serial.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/x86_64_pc-machine.c b/tests/qtest/libqos/x86_64_pc-machine.c index 6dfa705217..0edb1c9144 100644 --- a/tests/qtest/libqos/x86_64_pc-machine.c +++ b/tests/qtest/libqos/x86_64_pc-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c index 3062a13557..8fdf87b183 100644 --- a/tests/qtest/qos-test.c +++ b/tests/qtest/qos-test.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of From 8662404650f343fa6598608f02eedd013d614ab1 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 11 Feb 2020 09:59:41 +0100 Subject: [PATCH 1180/2595] tests/acceptance: Add boot tests for sh4 QEMU advent calendar image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we can select the second serial console in the acceptance tests (see commit 746f244d9720 "Allow to use other serial consoles than default"), we can also test the sh4 image from the QEMU advent calendar 2018. Message-Id: <20200515164337.4899-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- .travis.yml | 2 +- tests/acceptance/boot_linux_console.py | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index ec6367af1f..22de1eeea1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -293,7 +293,7 @@ jobs: - name: "GCC check-acceptance" dist: bionic env: - - CONFIG="--enable-tools --target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu" + - CONFIG="--enable-tools --target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sh4-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu" - TEST_CMD="make check-acceptance" - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-acceptance" after_script: diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 3f3aa0c854..3d02519660 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -858,12 +858,12 @@ class BootLinuxConsole(LinuxKernelTest): console_pattern = 'No filesystem could mount root' self.wait_for_console_pattern(console_pattern) - def do_test_advcal_2018(self, day, tar_hash, kernel_name): + def do_test_advcal_2018(self, day, tar_hash, kernel_name, console=0): tar_url = ('https://www.qemu-advent-calendar.org' '/2018/download/day' + day + '.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) - self.vm.set_console() + self.vm.set_console(console_index=console) self.vm.add_args('-kernel', self.workdir + '/day' + day + '/' + kernel_name) self.vm.launch() @@ -937,6 +937,15 @@ class BootLinuxConsole(LinuxKernelTest): self.vm.add_args('-M', 'graphics=off') self.do_test_advcal_2018('15', tar_hash, 'invaders.elf') + def test_sh4_r2d(self): + """ + :avocado: tags=arch:sh4 + :avocado: tags=machine:r2d + """ + tar_hash = 'fe06a4fd8ccbf2e27928d64472939d47829d4c7e' + self.vm.add_args('-append', 'console=ttySC1') + self.do_test_advcal_2018('09', tar_hash, 'zImage', console=1) + def test_sparc_ss20(self): """ :avocado: tags=arch:sparc From 1ef6bfc23144e0ec7c182301d26b114b3610c8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 15 Jun 2020 09:49:19 +0200 Subject: [PATCH 1181/2595] configure: Let SLOF be initialized by ./scripts/git-submodule.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The git-submodule.sh script is called by make and initialize the submodules listed in the GIT_SUBMODULES variable generated by ./configure. SLOF is required for building the s390-ccw firmware on s390x, since it is using the libnet code from SLOF for network booting. Add it to the GIT_SUBMODULES when building the s390-ccw firmware. Reported-by: Mark Cave-Ayland Suggested-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200615074919.12552-1-f4bug@amsat.org> [thuth: Tweaked the commit message a little bit] Signed-off-by: Thomas Huth --- .travis.yml | 1 - configure | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 22de1eeea1..74158f741b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -496,7 +496,6 @@ jobs: - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user" - UNRELIABLE=true script: - - ( cd ${SRC_DIR} ; git submodule update --init roms/SLOF ) - BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$? - | if [ "$BUILD_RC" -eq 0 ] ; then diff --git a/configure b/configure index bb7fd12612..927e4a3d06 100755 --- a/configure +++ b/configure @@ -6533,6 +6533,11 @@ if test "$cpu" = "s390x" ; then write_c_skeleton if compile_prog "-march=z900" ""; then roms="$roms s390-ccw" + # SLOF is required for building the s390-ccw firmware on s390x, + # since it is using the libnet code from SLOF for network booting. + if test -e "${source_path}/.git" ; then + git_submodules="${git_submodules} roms/SLOF" + fi fi fi From 8e2d5831e4b53720d4846aca9eabe3652e7192af Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Sun, 14 Jun 2020 16:00:46 +0800 Subject: [PATCH 1182/2595] target/mips: Legalize Loongson insn flags To match the actual status of Loongson insn, we split flags for LMMI and LEXT from INSN_LOONGSON2F. As Loongson-2F only implemented interger part of LEXT, we'll not enable LEXT for the processor, but instead we're still using INSN_LOONGSON2F as switch flag of these instructions. All multimedia instructions have been moved to LMMI flag. Loongson-2F and Loongson-3A are sharing these instructions. Signed-off-by: Jiaxun Yang Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: <20200614080049.31134-2-jiaxun.yang@flygoat.com> --- target/mips/mips-defs.h | 4 ++-- target/mips/translate.c | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h index 0c129106c8..f1b833f947 100644 --- a/target/mips/mips-defs.h +++ b/target/mips/mips-defs.h @@ -70,7 +70,7 @@ #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_LOONGSON2F (CPU_MIPS3 | INSN_LOONGSON2F | ASE_LMMI) #define CPU_MIPS5 (CPU_MIPS4 | ISA_MIPS5) @@ -97,7 +97,7 @@ /* Wave Computing: "nanoMIPS" */ #define CPU_NANOMIPS32 (CPU_MIPS32R6 | ISA_NANOMIPS32) -#define CPU_LOONGSON3A (CPU_MIPS64R2 | INSN_LOONGSON3A) +#define CPU_LOONGSON3A (CPU_MIPS64R2 | INSN_LOONGSON3A | ASE_LMMI | ASE_LEXT) /* * Strictly follow the architecture standard: diff --git a/target/mips/translate.c b/target/mips/translate.c index 2caf4cba5a..e49f32f6ae 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -1046,7 +1046,7 @@ enum { OPC_BC2NEZ = (0x0D << 21) | OPC_CP2, }; -#define MASK_LMI(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | (op & 0x1F)) +#define MASK_LMMI(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | (op & 0x1F)) enum { OPC_PADDSH = (24 << 21) | (0x00) | OPC_CP2, @@ -3421,7 +3421,8 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, TCGv t0, t1, t2; int mem_idx = ctx->mem_idx; - if (rt == 0 && ctx->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)) { + if (rt == 0 && ctx->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F | + INSN_LOONGSON3A)) { /* * Loongson CPU uses a load to zero register for prefetch. * We emulate it as a NOP. On other CPU we must perform the @@ -5531,7 +5532,7 @@ static void gen_loongson_multimedia(DisasContext *ctx, int rd, int rs, int rt) TCGv_i64 t0, t1; TCGCond cond; - opc = MASK_LMI(ctx->opcode); + opc = MASK_LMMI(ctx->opcode); switch (opc) { case OPC_ADD_CP2: case OPC_SUB_CP2: @@ -27161,7 +27162,7 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) case OPC_MULTU_G_2F: case OPC_MOD_G_2F: case OPC_MODU_G_2F: - check_insn(ctx, INSN_LOONGSON2F); + check_insn(ctx, INSN_LOONGSON2F | ASE_LEXT); gen_loongson_integer(ctx, op1, rd, rs, rt); break; case OPC_CLO: @@ -27194,7 +27195,7 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) case OPC_DDIVU_G_2F: case OPC_DMOD_G_2F: case OPC_DMODU_G_2F: - check_insn(ctx, INSN_LOONGSON2F); + check_insn(ctx, INSN_LOONGSON2F | ASE_LEXT); gen_loongson_integer(ctx, op1, rd, rs, rt); break; #endif @@ -30641,7 +30642,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_CP2: - check_insn(ctx, INSN_LOONGSON2F); + check_insn(ctx, ASE_LMMI); /* Note that these instructions use different fields. */ gen_loongson_multimedia(ctx, sa, rd, rt); break; From 7f4d0651b6dec78975c78301f77fdf68c98036ab Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Sun, 14 Jun 2020 16:00:47 +0800 Subject: [PATCH 1183/2595] target/mips: Add comments for vendor-specific ASEs Abbreviations of vendor-specific ASEs looks very similiar. Add comments to explain the full name and vendors of these flags. Signed-off-by: Jiaxun Yang Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Message-Id: <20200614080049.31134-3-jiaxun.yang@flygoat.com> --- target/mips/mips-defs.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h index f1b833f947..ed6a7a9e54 100644 --- a/target/mips/mips-defs.h +++ b/target/mips/mips-defs.h @@ -57,9 +57,13 @@ /* * bits 52-63: vendor-specific ASEs */ +/* MultiMedia Instructions defined by R5900 */ #define ASE_MMI 0x0010000000000000ULL +/* MIPS eXtension/enhanced Unit defined by Ingenic */ #define ASE_MXU 0x0020000000000000ULL +/* Loongson MultiMedia Instructions */ #define ASE_LMMI 0x0040000000000000ULL +/* Loongson EXTensions */ #define ASE_LEXT 0x0080000000000000ULL /* MIPS CPU defines. */ From 7a7a162addecf3fbbc706645ac94bbfb92f5514b Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:20 +0200 Subject: [PATCH 1184/2595] target/mips: msa: Split helpers for MADDV. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-2-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 6 ++- target/mips/msa_helper.c | 79 ++++++++++++++++++++++++++++++++++++---- target/mips/translate.c | 19 ++++++++-- 3 files changed, 92 insertions(+), 12 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 84fdd9fd27..e479a22559 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -950,6 +950,11 @@ 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_maddv_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_maddv_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_maddv_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_maddv_d, void, env, i32, i32, i32) + DEF_HELPER_4(msa_asub_s_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_asub_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_asub_s_w, void, env, i32, i32, i32) @@ -1069,7 +1074,6 @@ 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) DEF_HELPER_5(msa_subsuu_s_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_dotp_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_dotp_u_df, void, env, i32, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index c3b271934a..3b75bdc6a4 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -2883,7 +2883,77 @@ void helper_msa_mod_u_d(CPUMIPSState *env, * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Int Multiply group helpers here */ +static inline int64_t msa_maddv_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + return dest + arg1 * arg2; +} + +void helper_msa_maddv_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_maddv_df(DF_BYTE, pwt->b[0], pws->b[0], pwt->b[0]); + pwd->b[1] = msa_maddv_df(DF_BYTE, pwt->b[1], pws->b[1], pwt->b[1]); + pwd->b[2] = msa_maddv_df(DF_BYTE, pwt->b[2], pws->b[2], pwt->b[2]); + pwd->b[3] = msa_maddv_df(DF_BYTE, pwt->b[3], pws->b[3], pwt->b[3]); + pwd->b[4] = msa_maddv_df(DF_BYTE, pwt->b[4], pws->b[4], pwt->b[4]); + pwd->b[5] = msa_maddv_df(DF_BYTE, pwt->b[5], pws->b[5], pwt->b[5]); + pwd->b[6] = msa_maddv_df(DF_BYTE, pwt->b[6], pws->b[6], pwt->b[6]); + pwd->b[7] = msa_maddv_df(DF_BYTE, pwt->b[7], pws->b[7], pwt->b[7]); + pwd->b[8] = msa_maddv_df(DF_BYTE, pwt->b[8], pws->b[8], pwt->b[8]); + pwd->b[9] = msa_maddv_df(DF_BYTE, pwt->b[9], pws->b[9], pwt->b[9]); + pwd->b[10] = msa_maddv_df(DF_BYTE, pwt->b[10], pws->b[10], pwt->b[10]); + pwd->b[11] = msa_maddv_df(DF_BYTE, pwt->b[11], pws->b[11], pwt->b[11]); + pwd->b[12] = msa_maddv_df(DF_BYTE, pwt->b[12], pws->b[12], pwt->b[12]); + pwd->b[13] = msa_maddv_df(DF_BYTE, pwt->b[13], pws->b[13], pwt->b[13]); + pwd->b[14] = msa_maddv_df(DF_BYTE, pwt->b[14], pws->b[14], pwt->b[14]); + pwd->b[15] = msa_maddv_df(DF_BYTE, pwt->b[15], pws->b[15], pwt->b[15]); +} + +void helper_msa_maddv_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_maddv_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_maddv_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_maddv_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_maddv_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_maddv_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_maddv_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_maddv_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_maddv_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_maddv_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_maddv_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_maddv_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_maddv_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_maddv_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_maddv_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_maddv_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_maddv_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} /* @@ -4816,12 +4886,6 @@ void helper_msa_sld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_sld_df(df, pwd, pws, env->active_tc.gpr[rt]); } -static inline int64_t msa_maddv_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - return dest + arg1 * arg2; -} - static inline int64_t msa_msubv_df(uint32_t df, int64_t dest, int64_t arg1, int64_t arg2) { @@ -5002,7 +5066,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ } \ } -MSA_TEROP_DF(maddv) MSA_TEROP_DF(msubv) MSA_TEROP_DF(dpadd_s) MSA_TEROP_DF(dpadd_u) diff --git a/target/mips/translate.c b/target/mips/translate.c index e49f32f6ae..4975e57e35 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29058,6 +29058,22 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) break; } break; + case OPC_MADDV_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_maddv_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_maddv_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_maddv_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_maddv_d(cpu_env, twd, tws, twt); + break; + } + break; case OPC_ASUB_S_df: switch (df) { case DF_BYTE: @@ -29284,9 +29300,6 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) case OPC_SUBS_U_df: gen_helper_msa_subs_u_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_MADDV_df: - gen_helper_msa_maddv_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_SPLAT_df: gen_helper_msa_splat_df(cpu_env, tdf, twd, tws, twt); break; From 5f148a023279c735f9b26955e8af8556620fb7ec Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:21 +0200 Subject: [PATCH 1185/2595] target/mips: msa: Split helpers for MSUBV. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-3-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 6 ++- target/mips/msa_helper.c | 79 ++++++++++++++++++++++++++++++++++++---- target/mips/translate.c | 19 ++++++++-- 3 files changed, 93 insertions(+), 11 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index e479a22559..7ca0036807 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -955,6 +955,11 @@ DEF_HELPER_4(msa_maddv_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_maddv_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_maddv_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_msubv_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_msubv_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_msubv_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_msubv_d, void, env, i32, i32, i32) + DEF_HELPER_4(msa_asub_s_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_asub_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_asub_s_w, void, env, i32, i32, i32) @@ -1074,7 +1079,6 @@ 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) DEF_HELPER_5(msa_subsuu_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_msubv_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) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 3b75bdc6a4..2b54de0959 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -2955,6 +2955,78 @@ void helper_msa_maddv_d(CPUMIPSState *env, pwd->d[1] = msa_maddv_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); } +static inline int64_t msa_msubv_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + return dest - arg1 * arg2; +} + +void helper_msa_msubv_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_msubv_df(DF_BYTE, pwt->b[0], pws->b[0], pwt->b[0]); + pwd->b[1] = msa_msubv_df(DF_BYTE, pwt->b[1], pws->b[1], pwt->b[1]); + pwd->b[2] = msa_msubv_df(DF_BYTE, pwt->b[2], pws->b[2], pwt->b[2]); + pwd->b[3] = msa_msubv_df(DF_BYTE, pwt->b[3], pws->b[3], pwt->b[3]); + pwd->b[4] = msa_msubv_df(DF_BYTE, pwt->b[4], pws->b[4], pwt->b[4]); + pwd->b[5] = msa_msubv_df(DF_BYTE, pwt->b[5], pws->b[5], pwt->b[5]); + pwd->b[6] = msa_msubv_df(DF_BYTE, pwt->b[6], pws->b[6], pwt->b[6]); + pwd->b[7] = msa_msubv_df(DF_BYTE, pwt->b[7], pws->b[7], pwt->b[7]); + pwd->b[8] = msa_msubv_df(DF_BYTE, pwt->b[8], pws->b[8], pwt->b[8]); + pwd->b[9] = msa_msubv_df(DF_BYTE, pwt->b[9], pws->b[9], pwt->b[9]); + pwd->b[10] = msa_msubv_df(DF_BYTE, pwt->b[10], pws->b[10], pwt->b[10]); + pwd->b[11] = msa_msubv_df(DF_BYTE, pwt->b[11], pws->b[11], pwt->b[11]); + pwd->b[12] = msa_msubv_df(DF_BYTE, pwt->b[12], pws->b[12], pwt->b[12]); + pwd->b[13] = msa_msubv_df(DF_BYTE, pwt->b[13], pws->b[13], pwt->b[13]); + pwd->b[14] = msa_msubv_df(DF_BYTE, pwt->b[14], pws->b[14], pwt->b[14]); + pwd->b[15] = msa_msubv_df(DF_BYTE, pwt->b[15], pws->b[15], pwt->b[15]); +} + +void helper_msa_msubv_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_msubv_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_msubv_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_msubv_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_msubv_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_msubv_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_msubv_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_msubv_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_msubv_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_msubv_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_msubv_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_msubv_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_msubv_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_msubv_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_msubv_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_msubv_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_msubv_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} + /* * Int Subtract @@ -4886,12 +4958,6 @@ void helper_msa_sld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_sld_df(df, pwd, pws, env->active_tc.gpr[rt]); } -static inline int64_t msa_msubv_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - return dest - arg1 * arg2; -} - static inline int64_t msa_dpadd_s_df(uint32_t df, int64_t dest, int64_t arg1, int64_t arg2) { @@ -5066,7 +5132,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ } \ } -MSA_TEROP_DF(msubv) MSA_TEROP_DF(dpadd_s) MSA_TEROP_DF(dpadd_u) MSA_TEROP_DF(dpsub_s) diff --git a/target/mips/translate.c b/target/mips/translate.c index 4975e57e35..7388a1600c 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29074,6 +29074,22 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) break; } break; + case OPC_MSUBV_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_msubv_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_msubv_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_msubv_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_msubv_d(cpu_env, twd, tws, twt); + break; + } + break; case OPC_ASUB_S_df: switch (df) { case DF_BYTE: @@ -29306,9 +29322,6 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) case OPC_SUBSUS_U_df: gen_helper_msa_subsus_u_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_MSUBV_df: - gen_helper_msa_msubv_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_SUBSUU_S_df: gen_helper_msa_subsuu_s_df(cpu_env, tdf, twd, tws, twt); break; From 9f5840a6a58cd9201567806dd831b6cf0db00195 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:22 +0200 Subject: [PATCH 1186/2595] target/mips: msa: Split helpers for DPADD_S. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-4-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 4 +- target/mips/msa_helper.c | 90 ++++++++++++++++++++++++++++------------ target/mips/translate.c | 12 +++++- 3 files changed, 78 insertions(+), 28 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 7ca0036807..16f2d53ad0 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -1081,7 +1081,9 @@ DEF_HELPER_5(msa_subsuu_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mulv_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) +DEF_HELPER_4(msa_dpadd_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpadd_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpadd_s_d, void, env, i32, i32, i32) DEF_HELPER_5(msa_dpadd_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_dpsub_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_dpsub_u_df, void, env, i32, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 2b54de0959..086b56f58c 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -2224,7 +2224,70 @@ void helper_msa_div_u_d(CPUMIPSState *env, * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Int Dot Product group helpers here */ +#define SIGNED_EXTRACT(e, o, a, df) \ + do { \ + e = SIGNED_EVEN(a, df); \ + o = SIGNED_ODD(a, df); \ + } while (0) + +#define UNSIGNED_EXTRACT(e, o, a, df) \ + do { \ + e = UNSIGNED_EVEN(a, df); \ + o = UNSIGNED_ODD(a, df); \ + } while (0) + +static inline int64_t msa_dpadd_s_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +void helper_msa_dpadd_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_dpadd_s_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dpadd_s_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dpadd_s_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dpadd_s_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dpadd_s_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dpadd_s_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dpadd_s_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dpadd_s_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_dpadd_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_dpadd_s_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dpadd_s_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dpadd_s_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dpadd_s_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_dpadd_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_dpadd_s_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dpadd_s_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} /* @@ -4785,18 +4848,6 @@ static inline int64_t msa_mulv_df(uint32_t df, int64_t arg1, int64_t arg2) return arg1 * arg2; } -#define SIGNED_EXTRACT(e, o, a, df) \ - do { \ - e = SIGNED_EVEN(a, df); \ - o = SIGNED_ODD(a, df); \ - } while (0) - -#define UNSIGNED_EXTRACT(e, o, a, df) \ - do { \ - e = UNSIGNED_EVEN(a, df); \ - o = UNSIGNED_ODD(a, df); \ - } while (0) - static inline int64_t msa_dotp_s_df(uint32_t df, int64_t arg1, int64_t arg2) { int64_t even_arg1; @@ -4958,18 +5009,6 @@ void helper_msa_sld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_sld_df(df, pwd, pws, env->active_tc.gpr[rt]); } -static inline int64_t msa_dpadd_s_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); -} - static inline int64_t msa_dpadd_u_df(uint32_t df, int64_t dest, int64_t arg1, int64_t arg2) { @@ -5132,7 +5171,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ } \ } -MSA_TEROP_DF(dpadd_s) MSA_TEROP_DF(dpadd_u) MSA_TEROP_DF(dpsub_s) MSA_TEROP_DF(dpsub_u) diff --git a/target/mips/translate.c b/target/mips/translate.c index 7388a1600c..47ac4ea91c 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29400,7 +29400,17 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) gen_helper_msa_dotp_u_df(cpu_env, tdf, twd, tws, twt); break; case OPC_DPADD_S_df: - gen_helper_msa_dpadd_s_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dpadd_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dpadd_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dpadd_s_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DPADD_U_df: gen_helper_msa_dpadd_u_df(cpu_env, tdf, twd, tws, twt); From e5e0777e7fe0aa6b70040c7bcf92eecbf9493df4 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:23 +0200 Subject: [PATCH 1187/2595] target/mips: msa: Split helpers for DPADD_U. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-5-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 4 ++- target/mips/msa_helper.c | 67 ++++++++++++++++++++++++++++++++-------- target/mips/translate.c | 12 ++++++- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 16f2d53ad0..155b6bbe3e 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -1084,7 +1084,9 @@ DEF_HELPER_5(msa_dotp_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_4(msa_dpadd_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpadd_s_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpadd_s_d, void, env, i32, i32, i32) -DEF_HELPER_5(msa_dpadd_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_4(msa_dpadd_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpadd_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpadd_u_d, void, env, i32, i32, i32) DEF_HELPER_5(msa_dpsub_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_dpsub_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_sld_df, void, env, i32, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 086b56f58c..9741c94d27 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -2290,6 +2290,60 @@ void helper_msa_dpadd_s_d(CPUMIPSState *env, } +static inline int64_t msa_dpadd_u_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +void helper_msa_dpadd_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_dpadd_u_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dpadd_u_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dpadd_u_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dpadd_u_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dpadd_u_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dpadd_u_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dpadd_u_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dpadd_u_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_dpadd_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_dpadd_u_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dpadd_u_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dpadd_u_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dpadd_u_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_dpadd_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_dpadd_u_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dpadd_u_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} + + /* * Int Max Min * ----------- @@ -5009,18 +5063,6 @@ void helper_msa_sld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_sld_df(df, pwd, pws, env->active_tc.gpr[rt]); } -static inline int64_t msa_dpadd_u_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); -} - static inline int64_t msa_dpsub_s_df(uint32_t df, int64_t dest, int64_t arg1, int64_t arg2) { @@ -5171,7 +5213,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ } \ } -MSA_TEROP_DF(dpadd_u) MSA_TEROP_DF(dpsub_s) MSA_TEROP_DF(dpsub_u) MSA_TEROP_DF(binsl) diff --git a/target/mips/translate.c b/target/mips/translate.c index 47ac4ea91c..0f99768358 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29413,7 +29413,17 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_DPADD_U_df: - gen_helper_msa_dpadd_u_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dpadd_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dpadd_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dpadd_u_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DPSUB_S_df: gen_helper_msa_dpsub_s_df(cpu_env, tdf, twd, tws, twt); From 8ed86716f69fafc39f8ff1032ccc414b5cc76929 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:24 +0200 Subject: [PATCH 1188/2595] target/mips: msa: Split helpers for DPSUB_S. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-6-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 4 ++- target/mips/msa_helper.c | 67 ++++++++++++++++++++++++++++++++-------- target/mips/translate.c | 12 ++++++- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 155b6bbe3e..2de14542cd 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -1087,7 +1087,9 @@ DEF_HELPER_4(msa_dpadd_s_d, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpadd_u_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpadd_u_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpadd_u_d, void, env, i32, i32, i32) -DEF_HELPER_5(msa_dpsub_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_s_d, void, env, i32, i32, i32) DEF_HELPER_5(msa_dpsub_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_sld_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_splat_df, void, env, i32, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 9741c94d27..934f705c1e 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -2344,6 +2344,60 @@ void helper_msa_dpadd_u_d(CPUMIPSState *env, } +static inline int64_t msa_dpsub_s_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); +} + +void helper_msa_dpsub_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_dpsub_s_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dpsub_s_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dpsub_s_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dpsub_s_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dpsub_s_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dpsub_s_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dpsub_s_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dpsub_s_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_dpsub_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_dpsub_s_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dpsub_s_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dpsub_s_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dpsub_s_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_dpsub_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_dpsub_s_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dpsub_s_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} + + /* * Int Max Min * ----------- @@ -5063,18 +5117,6 @@ void helper_msa_sld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_sld_df(df, pwd, pws, env->active_tc.gpr[rt]); } -static inline int64_t msa_dpsub_s_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); -} - static inline int64_t msa_dpsub_u_df(uint32_t df, int64_t dest, int64_t arg1, int64_t arg2) { @@ -5213,7 +5255,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ } \ } -MSA_TEROP_DF(dpsub_s) MSA_TEROP_DF(dpsub_u) MSA_TEROP_DF(binsl) MSA_TEROP_DF(binsr) diff --git a/target/mips/translate.c b/target/mips/translate.c index 0f99768358..caf3adfa25 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29426,7 +29426,17 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_DPSUB_S_df: - gen_helper_msa_dpsub_s_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dpsub_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dpsub_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dpsub_s_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DPSUB_U_df: gen_helper_msa_dpsub_u_df(cpu_env, tdf, twd, tws, twt); From 0c8c76ac8592d768f20be7c0d3bfd2b892ec231a Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:25 +0200 Subject: [PATCH 1189/2595] target/mips: msa: Split helpers for DPSUB_U. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-7-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 4 ++- target/mips/msa_helper.c | 67 ++++++++++++++++++++++++++++++++-------- target/mips/translate.c | 12 ++++++- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 2de14542cd..575f4a524c 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -1090,7 +1090,9 @@ DEF_HELPER_4(msa_dpadd_u_d, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpsub_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpsub_s_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpsub_s_d, void, env, i32, i32, i32) -DEF_HELPER_5(msa_dpsub_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_u_d, void, env, i32, i32, i32) DEF_HELPER_5(msa_sld_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_splat_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_vshf_df, void, env, i32, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 934f705c1e..33d5251a6b 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -2398,6 +2398,60 @@ void helper_msa_dpsub_s_d(CPUMIPSState *env, } +static inline int64_t msa_dpsub_u_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); +} + +void helper_msa_dpsub_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_dpsub_u_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dpsub_u_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dpsub_u_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dpsub_u_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dpsub_u_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dpsub_u_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dpsub_u_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dpsub_u_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_dpsub_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_dpsub_u_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dpsub_u_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dpsub_u_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dpsub_u_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_dpsub_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_dpsub_u_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dpsub_u_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} + + /* * Int Max Min * ----------- @@ -5117,18 +5171,6 @@ void helper_msa_sld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_sld_df(df, pwd, pws, env->active_tc.gpr[rt]); } -static inline int64_t msa_dpsub_u_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); -} - static inline int64_t msa_madd_q_df(uint32_t df, int64_t dest, int64_t arg1, int64_t arg2) { @@ -5255,7 +5297,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ } \ } -MSA_TEROP_DF(dpsub_u) MSA_TEROP_DF(binsl) MSA_TEROP_DF(binsr) MSA_TEROP_DF(madd_q) diff --git a/target/mips/translate.c b/target/mips/translate.c index caf3adfa25..bd6febca9c 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29439,7 +29439,17 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_DPSUB_U_df: - gen_helper_msa_dpsub_u_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dpsub_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dpsub_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dpsub_u_d(cpu_env, twd, tws, twt); + break; + } break; } break; From 165cacb65ce41334cfd1a89e362bfca749f0fdd6 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:26 +0200 Subject: [PATCH 1190/2595] target/mips: msa: Split helpers for DOTP_S. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-8-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 5 ++- target/mips/msa_helper.c | 66 ++++++++++++++++++++++++++++++++-------- target/mips/translate.c | 12 +++++++- 3 files changed, 69 insertions(+), 14 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 575f4a524c..06df3de744 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -1079,7 +1079,10 @@ 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) DEF_HELPER_5(msa_subsuu_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_dotp_s_df, void, env, i32, i32, i32, i32) + +DEF_HELPER_4(msa_dotp_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dotp_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dotp_s_d, void, env, i32, i32, i32) DEF_HELPER_5(msa_dotp_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_4(msa_dpadd_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpadd_s_w, void, env, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 33d5251a6b..201283fdd9 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -2236,6 +2236,60 @@ void helper_msa_div_u_d(CPUMIPSState *env, o = UNSIGNED_ODD(a, df); \ } while (0) + +static inline int64_t msa_dotp_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +void helper_msa_dotp_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_dotp_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dotp_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dotp_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dotp_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dotp_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dotp_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dotp_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dotp_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_dotp_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_dotp_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dotp_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dotp_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dotp_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_dotp_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_dotp_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dotp_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + static inline int64_t msa_dpadd_s_df(uint32_t df, int64_t dest, int64_t arg1, int64_t arg2) { @@ -5010,17 +5064,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_dotp_s_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); -} - static inline int64_t msa_dotp_u_df(uint32_t df, int64_t arg1, int64_t arg2) { int64_t even_arg1; @@ -5155,7 +5198,6 @@ MSA_BINOP_DF(subs_u) MSA_BINOP_DF(subsus_u) MSA_BINOP_DF(subsuu_s) MSA_BINOP_DF(mulv) -MSA_BINOP_DF(dotp_s) MSA_BINOP_DF(dotp_u) MSA_BINOP_DF(mul_q) diff --git a/target/mips/translate.c b/target/mips/translate.c index bd6febca9c..e150454253 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29394,7 +29394,17 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_DOTP_S_df: - gen_helper_msa_dotp_s_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dotp_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dotp_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dotp_s_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DOTP_U_df: gen_helper_msa_dotp_u_df(cpu_env, tdf, twd, tws, twt); From 72c6a6e2c218806f9a0989336e0960aa0d68cf8f Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:27 +0200 Subject: [PATCH 1191/2595] target/mips: msa: Split helpers for DOTP_U. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-9-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 4 ++- target/mips/msa_helper.c | 65 ++++++++++++++++++++++++++++++++-------- target/mips/translate.c | 12 +++++++- 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 06df3de744..05d5533dfb 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -1083,7 +1083,9 @@ DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32) DEF_HELPER_4(msa_dotp_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_dotp_s_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_dotp_s_d, void, env, i32, i32, i32) -DEF_HELPER_5(msa_dotp_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_4(msa_dotp_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dotp_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dotp_u_d, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpadd_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpadd_s_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_dpadd_s_d, void, env, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 201283fdd9..84d0073918 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -2290,6 +2290,59 @@ void helper_msa_dotp_s_d(CPUMIPSState *env, } +static inline int64_t msa_dotp_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +void helper_msa_dotp_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_dotp_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dotp_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dotp_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dotp_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dotp_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dotp_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dotp_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dotp_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_dotp_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_dotp_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dotp_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dotp_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dotp_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_dotp_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_dotp_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dotp_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + static inline int64_t msa_dpadd_s_df(uint32_t df, int64_t dest, int64_t arg1, int64_t arg2) { @@ -5064,17 +5117,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_dotp_u_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); -} - #define CONCATENATE_AND_SLIDE(s, k) \ do { \ for (i = 0; i < s; i++) { \ @@ -5198,7 +5240,6 @@ MSA_BINOP_DF(subs_u) MSA_BINOP_DF(subsus_u) MSA_BINOP_DF(subsuu_s) MSA_BINOP_DF(mulv) -MSA_BINOP_DF(dotp_u) MSA_BINOP_DF(mul_q) MSA_BINOP_DF(mulr_q) diff --git a/target/mips/translate.c b/target/mips/translate.c index e150454253..77e2d95d60 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29407,7 +29407,17 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_DOTP_U_df: - gen_helper_msa_dotp_u_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dotp_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dotp_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dotp_u_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DPADD_S_df: switch (df) { From 534e400141dfff34db060b9af842fb4bc2a69fc4 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:28 +0200 Subject: [PATCH 1192/2595] target/mips: msa: Split helpers for SUBS_S. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-10-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 6 ++- target/mips/msa_helper.c | 90 ++++++++++++++++++++++++++++++++++------ target/mips/translate.c | 15 ++++++- 3 files changed, 97 insertions(+), 14 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 05d5533dfb..a93402a2d3 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -978,6 +978,11 @@ DEF_HELPER_4(msa_hsub_u_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_hsub_u_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_hsub_u_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_s_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_s_d, void, env, i32, i32, i32) + DEF_HELPER_4(msa_ilvev_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_w, void, env, i32, i32, i32) @@ -1074,7 +1079,6 @@ DEF_HELPER_5(msa_srlri_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_subv_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) DEF_HELPER_5(msa_subsuu_s_df, void, env, i32, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 84d0073918..f08beba123 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -3650,6 +3650,84 @@ void helper_msa_hsub_u_d(CPUMIPSState *env, } +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); + int64_t min_int = DF_MIN_INT(df); + if (arg2 > 0) { + return (min_int + arg2 < arg1) ? arg1 - arg2 : min_int; + } else { + return (arg1 < max_int + arg2) ? arg1 - arg2 : max_int; + } +} + +void helper_msa_subs_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_subs_s_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_subs_s_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_subs_s_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_subs_s_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_subs_s_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_subs_s_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_subs_s_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_subs_s_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_subs_s_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_subs_s_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_subs_s_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_subs_s_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_subs_s_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_subs_s_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_subs_s_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_subs_s_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_subs_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_subs_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_subs_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_subs_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_subs_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_subs_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_subs_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_subs_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_subs_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_subs_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_subs_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_subs_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_subs_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_subs_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_subs_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_subs_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_subs_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + /* * Interleave * ---------- @@ -5060,17 +5138,6 @@ MSA_TEROP_IMMU_DF(binsli, binsl) MSA_TEROP_IMMU_DF(binsri, binsr) #undef MSA_TEROP_IMMU_DF -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); - int64_t min_int = DF_MIN_INT(df); - if (arg2 > 0) { - return (min_int + arg2 < arg1) ? arg1 - arg2 : min_int; - } else { - return (arg1 < max_int + arg2) ? arg1 - arg2 : max_int; - } -} - static inline int64_t msa_subs_u_df(uint32_t df, int64_t arg1, int64_t arg2) { uint64_t u_arg1 = UNSIGNED(arg1, df); @@ -5235,7 +5302,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ } MSA_BINOP_DF(subv) -MSA_BINOP_DF(subs_s) MSA_BINOP_DF(subs_u) MSA_BINOP_DF(subsus_u) MSA_BINOP_DF(subsuu_s) diff --git a/target/mips/translate.c b/target/mips/translate.c index 77e2d95d60..f33121a161 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29299,7 +29299,20 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_SUBS_S_df: - gen_helper_msa_subs_s_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_subs_s_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_subs_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_subs_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_subs_s_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_MULV_df: gen_helper_msa_mulv_df(cpu_env, tdf, twd, tws, twt); From 81b53858fed8a316a4715c2f7f92cdfb4a7b4dd8 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:29 +0200 Subject: [PATCH 1193/2595] target/mips: msa: Split helpers for SUBS_U. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-11-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 6 ++- target/mips/msa_helper.c | 82 ++++++++++++++++++++++++++++++++++++---- target/mips/translate.c | 15 +++++++- 3 files changed, 93 insertions(+), 10 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index a93402a2d3..61dc1ed626 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -983,6 +983,11 @@ DEF_HELPER_4(msa_subs_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_subs_s_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_subs_s_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_u_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_u_d, void, env, i32, i32, i32) + DEF_HELPER_4(msa_ilvev_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_w, void, env, i32, i32, i32) @@ -1079,7 +1084,6 @@ DEF_HELPER_5(msa_srlri_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_subv_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) DEF_HELPER_5(msa_subsuu_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index f08beba123..bce32abf77 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -3728,6 +3728,80 @@ void helper_msa_subs_s_d(CPUMIPSState *env, } +static inline int64_t msa_subs_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) ? u_arg1 - u_arg2 : 0; +} + +void helper_msa_subs_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_subs_u_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_subs_u_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_subs_u_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_subs_u_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_subs_u_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_subs_u_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_subs_u_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_subs_u_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_subs_u_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_subs_u_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_subs_u_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_subs_u_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_subs_u_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_subs_u_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_subs_u_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_subs_u_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_subs_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_subs_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_subs_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_subs_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_subs_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_subs_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_subs_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_subs_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_subs_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_subs_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_subs_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_subs_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_subs_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_subs_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_subs_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_subs_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_subs_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + /* * Interleave * ---------- @@ -5138,13 +5212,6 @@ MSA_TEROP_IMMU_DF(binsli, binsl) MSA_TEROP_IMMU_DF(binsri, binsr) #undef MSA_TEROP_IMMU_DF -static inline int64_t msa_subs_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) ? u_arg1 - u_arg2 : 0; -} - static inline int64_t msa_subsus_u_df(uint32_t df, int64_t arg1, int64_t arg2) { uint64_t u_arg1 = UNSIGNED(arg1, df); @@ -5302,7 +5369,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ } MSA_BINOP_DF(subv) -MSA_BINOP_DF(subs_u) MSA_BINOP_DF(subsus_u) MSA_BINOP_DF(subsuu_s) MSA_BINOP_DF(mulv) diff --git a/target/mips/translate.c b/target/mips/translate.c index f33121a161..7671a4909d 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29327,7 +29327,20 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) gen_helper_msa_subv_df(cpu_env, tdf, twd, tws, twt); break; case OPC_SUBS_U_df: - gen_helper_msa_subs_u_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_subs_u_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_subs_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_subs_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_subs_u_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_SPLAT_df: gen_helper_msa_splat_df(cpu_env, tdf, twd, tws, twt); From 55a04640476be28d629bc4db0baca74b737cfe6c Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:30 +0200 Subject: [PATCH 1194/2595] target/mips: msa: Split helpers for SUBSUS_U. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-12-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 6 ++- target/mips/msa_helper.c | 102 ++++++++++++++++++++++++++++++++------- target/mips/translate.c | 15 +++++- 3 files changed, 103 insertions(+), 20 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 61dc1ed626..227ff76ec1 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -988,6 +988,11 @@ DEF_HELPER_4(msa_subs_u_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_subs_u_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_subs_u_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsus_u_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsus_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsus_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsus_u_d, void, env, i32, i32, i32) + DEF_HELPER_4(msa_ilvev_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_w, void, env, i32, i32, i32) @@ -1084,7 +1089,6 @@ DEF_HELPER_5(msa_srlri_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_subv_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_subsus_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_subsuu_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index bce32abf77..f7e5c018ac 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -3802,6 +3802,90 @@ void helper_msa_subs_u_d(CPUMIPSState *env, } +static inline int64_t msa_subsus_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t max_uint = DF_MAX_UINT(df); + if (arg2 >= 0) { + uint64_t u_arg2 = (uint64_t)arg2; + return (u_arg1 > u_arg2) ? + (int64_t)(u_arg1 - u_arg2) : + 0; + } else { + uint64_t u_arg2 = (uint64_t)(-arg2); + return (u_arg1 < max_uint - u_arg2) ? + (int64_t)(u_arg1 + u_arg2) : + (int64_t)max_uint; + } +} + +void helper_msa_subsus_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_subsus_u_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_subsus_u_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_subsus_u_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_subsus_u_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_subsus_u_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_subsus_u_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_subsus_u_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_subsus_u_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_subsus_u_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_subsus_u_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_subsus_u_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_subsus_u_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_subsus_u_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_subsus_u_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_subsus_u_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_subsus_u_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_subsus_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_subsus_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_subsus_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_subsus_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_subsus_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_subsus_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_subsus_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_subsus_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_subsus_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_subsus_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_subsus_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_subsus_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_subsus_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_subsus_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_subsus_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_subsus_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_subsus_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + /* * Interleave * ---------- @@ -5212,23 +5296,6 @@ MSA_TEROP_IMMU_DF(binsli, binsl) MSA_TEROP_IMMU_DF(binsri, binsr) #undef MSA_TEROP_IMMU_DF -static inline int64_t msa_subsus_u_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t max_uint = DF_MAX_UINT(df); - if (arg2 >= 0) { - uint64_t u_arg2 = (uint64_t)arg2; - return (u_arg1 > u_arg2) ? - (int64_t)(u_arg1 - u_arg2) : - 0; - } else { - uint64_t u_arg2 = (uint64_t)(-arg2); - return (u_arg1 < max_uint - u_arg2) ? - (int64_t)(u_arg1 + u_arg2) : - (int64_t)max_uint; - } -} - static inline int64_t msa_subsuu_s_df(uint32_t df, int64_t arg1, int64_t arg2) { uint64_t u_arg1 = UNSIGNED(arg1, df); @@ -5369,7 +5436,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ } MSA_BINOP_DF(subv) -MSA_BINOP_DF(subsus_u) MSA_BINOP_DF(subsuu_s) MSA_BINOP_DF(mulv) diff --git a/target/mips/translate.c b/target/mips/translate.c index 7671a4909d..b273f4d4c3 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29346,7 +29346,20 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) gen_helper_msa_splat_df(cpu_env, tdf, twd, tws, twt); break; case OPC_SUBSUS_U_df: - gen_helper_msa_subsus_u_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_subsus_u_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_subsus_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_subsus_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_subsus_u_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_SUBSUU_S_df: gen_helper_msa_subsuu_s_df(cpu_env, tdf, twd, tws, twt); From cb4ac991f7ac158b13afa50506f8b93b379a9dbd Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:31 +0200 Subject: [PATCH 1195/2595] target/mips: msa: Split helpers for SUBSUU_S. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-13-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 6 ++- target/mips/msa_helper.c | 102 ++++++++++++++++++++++++++++++++------- target/mips/translate.c | 15 +++++- 3 files changed, 103 insertions(+), 20 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 227ff76ec1..4795c97f47 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -993,6 +993,11 @@ DEF_HELPER_4(msa_subsus_u_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_subsus_u_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_subsus_u_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsuu_s_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsuu_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsuu_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsuu_s_d, void, env, i32, i32, i32) + DEF_HELPER_4(msa_ilvev_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_w, void, env, i32, i32, i32) @@ -1089,7 +1094,6 @@ DEF_HELPER_5(msa_srlri_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_subv_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_subsuu_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32) DEF_HELPER_4(msa_dotp_s_h, void, env, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index f7e5c018ac..27a9c36a89 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -3886,6 +3886,90 @@ void helper_msa_subsus_u_d(CPUMIPSState *env, } +static inline int64_t msa_subsuu_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + int64_t max_int = DF_MAX_INT(df); + int64_t min_int = DF_MIN_INT(df); + if (u_arg1 > u_arg2) { + return u_arg1 - u_arg2 < (uint64_t)max_int ? + (int64_t)(u_arg1 - u_arg2) : + max_int; + } else { + return u_arg2 - u_arg1 < (uint64_t)(-min_int) ? + (int64_t)(u_arg1 - u_arg2) : + min_int; + } +} + +void helper_msa_subsuu_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_subsuu_s_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_subsuu_s_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_subsuu_s_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_subsuu_s_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_subsuu_s_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_subsuu_s_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_subsuu_s_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_subsuu_s_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_subsuu_s_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_subsuu_s_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_subsuu_s_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_subsuu_s_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_subsuu_s_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_subsuu_s_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_subsuu_s_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_subsuu_s_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_subsuu_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_subsuu_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_subsuu_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_subsuu_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_subsuu_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_subsuu_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_subsuu_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_subsuu_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_subsuu_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_subsuu_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_subsuu_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_subsuu_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_subsuu_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_subsuu_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_subsuu_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_subsuu_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_subsuu_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + /* * Interleave * ---------- @@ -5296,23 +5380,6 @@ MSA_TEROP_IMMU_DF(binsli, binsl) MSA_TEROP_IMMU_DF(binsri, binsr) #undef MSA_TEROP_IMMU_DF -static inline int64_t msa_subsuu_s_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t u_arg2 = UNSIGNED(arg2, df); - int64_t max_int = DF_MAX_INT(df); - int64_t min_int = DF_MIN_INT(df); - if (u_arg1 > u_arg2) { - return u_arg1 - u_arg2 < (uint64_t)max_int ? - (int64_t)(u_arg1 - u_arg2) : - max_int; - } else { - return u_arg2 - u_arg1 < (uint64_t)(-min_int) ? - (int64_t)(u_arg1 - u_arg2) : - min_int; - } -} - static inline int64_t msa_mulv_df(uint32_t df, int64_t arg1, int64_t arg2) { return arg1 * arg2; @@ -5436,7 +5503,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ } MSA_BINOP_DF(subv) -MSA_BINOP_DF(subsuu_s) MSA_BINOP_DF(mulv) MSA_BINOP_DF(mul_q) diff --git a/target/mips/translate.c b/target/mips/translate.c index b273f4d4c3..6d9ae1de4b 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29362,7 +29362,20 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_SUBSUU_S_df: - gen_helper_msa_subsuu_s_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_subsuu_s_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_subsuu_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_subsuu_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_subsuu_s_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DOTP_S_df: From 83b2e79a80a05b905bbfbe88dd7a29e00e65a5a9 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:32 +0200 Subject: [PATCH 1196/2595] target/mips: msa: Split helpers for SUBV. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-14-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 6 ++- target/mips/msa_helper.c | 81 +++++++++++++++++++++++++++++++++++----- target/mips/translate.c | 15 +++++++- 3 files changed, 91 insertions(+), 11 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 4795c97f47..5d7ba6a847 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -998,6 +998,11 @@ DEF_HELPER_4(msa_subsuu_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_subsuu_s_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_subsuu_s_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subv_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subv_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subv_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subv_d, void, env, i32, i32, i32) + DEF_HELPER_4(msa_ilvev_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_w, void, env, i32, i32, i32) @@ -1093,7 +1098,6 @@ DEF_HELPER_5(msa_srlri_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_subv_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32) DEF_HELPER_4(msa_dotp_s_h, void, env, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 27a9c36a89..d099e00b40 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -3553,9 +3553,6 @@ void helper_msa_asub_u_d(CPUMIPSState *env, } -/* TODO: insert the rest of Int Subtract group helpers here */ - - static inline int64_t msa_hsub_s_df(uint32_t df, int64_t arg1, int64_t arg2) { return SIGNED_ODD(arg1, df) - SIGNED_EVEN(arg2, df); @@ -3970,6 +3967,78 @@ void helper_msa_subsuu_s_d(CPUMIPSState *env, } +static inline int64_t msa_subv_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 - arg2; +} + +void helper_msa_subv_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_subv_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_subv_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_subv_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_subv_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_subv_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_subv_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_subv_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_subv_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_subv_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_subv_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_subv_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_subv_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_subv_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_subv_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_subv_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_subv_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_subv_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_subv_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_subv_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_subv_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_subv_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_subv_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_subv_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_subv_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_subv_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_subv_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_subv_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_subv_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_subv_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_subv_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_subv_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_subv_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_subv_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + /* * Interleave * ---------- @@ -5194,11 +5263,6 @@ void helper_msa_shf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_move_v(pwd, pwx); } -static inline int64_t msa_subv_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - return arg1 - arg2; -} - #define MSA_BINOP_IMM_DF(helper, func) \ void helper_msa_ ## helper ## _df(CPUMIPSState *env, uint32_t df, \ uint32_t wd, uint32_t ws, int32_t u5) \ @@ -5502,7 +5566,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ } \ } -MSA_BINOP_DF(subv) MSA_BINOP_DF(mulv) MSA_BINOP_DF(mul_q) diff --git a/target/mips/translate.c b/target/mips/translate.c index 6d9ae1de4b..9ca17ed02c 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29324,7 +29324,20 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) gen_helper_msa_vshf_df(cpu_env, tdf, twd, tws, twt); break; case OPC_SUBV_df: - gen_helper_msa_subv_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_subv_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_subv_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_subv_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_subv_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_SUBS_U_df: switch (df) { From 0513503480fb00ecfe0eb5d7744eb03744df2b36 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 13 Jun 2020 17:21:33 +0200 Subject: [PATCH 1197/2595] target/mips: msa: Split helpers for MULV. Achieves clearer code and slightly better performance. Reviewed-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Message-Id: <20200613152133.8964-15-aleksandar.qemu.devel@gmail.com> --- target/mips/helper.h | 6 ++- target/mips/msa_helper.c | 79 ++++++++++++++++++++++++++++++++++++---- target/mips/translate.c | 15 +++++++- 3 files changed, 91 insertions(+), 9 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 5d7ba6a847..e97655dc0e 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -960,6 +960,11 @@ DEF_HELPER_4(msa_msubv_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_msubv_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_msubv_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mulv_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mulv_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mulv_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mulv_d, void, env, i32, i32, i32) + DEF_HELPER_4(msa_asub_s_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_asub_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_asub_s_w, void, env, i32, i32, i32) @@ -1098,7 +1103,6 @@ DEF_HELPER_5(msa_srlri_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_mulv_df, void, env, i32, i32, i32, i32) DEF_HELPER_4(msa_dotp_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_dotp_s_w, void, env, i32, i32, i32) diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index d099e00b40..6865addaf6 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -3360,6 +3360,78 @@ void helper_msa_msubv_d(CPUMIPSState *env, } +static inline int64_t msa_mulv_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 * arg2; +} + +void helper_msa_mulv_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_mulv_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_mulv_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_mulv_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_mulv_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_mulv_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_mulv_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_mulv_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_mulv_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_mulv_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_mulv_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_mulv_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_mulv_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_mulv_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_mulv_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_mulv_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_mulv_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_mulv_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_mulv_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_mulv_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_mulv_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_mulv_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_mulv_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_mulv_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_mulv_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_mulv_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_mulv_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_mulv_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_mulv_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_mulv_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_mulv_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_mulv_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_mulv_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_mulv_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + /* * Int Subtract * ------------ @@ -5444,11 +5516,6 @@ MSA_TEROP_IMMU_DF(binsli, binsl) MSA_TEROP_IMMU_DF(binsri, binsr) #undef MSA_TEROP_IMMU_DF -static inline int64_t msa_mulv_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - return arg1 * arg2; -} - #define CONCATENATE_AND_SLIDE(s, k) \ do { \ for (i = 0; i < s; i++) { \ @@ -5566,8 +5633,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ } \ } -MSA_BINOP_DF(mulv) - MSA_BINOP_DF(mul_q) MSA_BINOP_DF(mulr_q) #undef MSA_BINOP_DF diff --git a/target/mips/translate.c b/target/mips/translate.c index 9ca17ed02c..9fad58ea2c 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -29315,7 +29315,20 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_MULV_df: - gen_helper_msa_mulv_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_mulv_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_mulv_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_mulv_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_mulv_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_SLD_df: gen_helper_msa_sld_df(cpu_env, tdf, twd, tws, twt); From a9fb446811595854c0b22e0847a67be68febcc01 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 11 Jun 2020 11:53:16 +0200 Subject: [PATCH 1198/2595] MAINTAINERS: Adjust sh4 maintainership MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch transfers sh4 sections to Yoshinori Sato, who is best positioned in the community to assume sh4 maintainership. He is the maintainer of the related target rx as well, which means that some synergy between the two targets can be expected in future. Further adjustments, reorganizations, and improvements of sh4 sections are left to the future maintainer to be devised and executed, as he deems suitable. Aurelien and Magnus are deleted as maintainers in some sections of the MAINTAINERS file with this patch. However, they will not be deleted from QEMU Hall of Fame, where their names will always remained carved in stone as QEMU pioneers and granddaddies. Reviewed-by: Philippe Mathieu-Daudé Acked-by: Aurelien Jarno Acked-by: Magnus Damm Acked-by: Yoshinori Sato Signed-off-by: Aleksandar Markovic Reviewed-by: Thomas Huth Message-Id: <20200611095316.10133-2-aleksandar.qemu.devel@gmail.com> --- MAINTAINERS | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a922775e45..d59b605db5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -296,7 +296,7 @@ F: tests/tcg/s390x/ L: qemu-s390x@nongnu.org SH4 TCG CPUs -M: Aurelien Jarno +M: Yoshinori Sato S: Odd Fixes F: target/sh4/ F: hw/sh4/ @@ -1253,14 +1253,16 @@ F: include/hw/riscv/opentitan.h SH4 Machines ------------ R2D -M: Magnus Damm +M: Yoshinori Sato +R: Magnus Damm S: Maintained F: hw/sh4/r2d.c F: hw/intc/sh_intc.c F: hw/timer/sh_timer.c Shix -M: Magnus Damm +M: Yoshinori Sato +R: Magnus Damm S: Odd Fixes F: hw/sh4/shix.c From 250bc43a406f7d46e319abe87c19548d4f027828 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Thu, 11 Jun 2020 13:45:23 +0200 Subject: [PATCH 1199/2595] translations: Add Swedish language This patch adds translation of QEMU to Swedish. Signed-off-by: Sebastian Rasmussen Signed-off-by: Aleksandar Markovic Reviewed-by: Aleksandar Markovic Message-Id: <20200611114523.15584-2-aleksandar.qemu.devel@gmail.com> --- po/sv.po | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 po/sv.po diff --git a/po/sv.po b/po/sv.po new file mode 100644 index 0000000000..1e430edd65 --- /dev/null +++ b/po/sv.po @@ -0,0 +1,75 @@ +# Swedish translation of qemu po-file. +# This file is put in the public domain. +# Sebastian Rasmussen , 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: QEMU 2.12.91\n" +"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" +"POT-Creation-Date: 2018-07-18 07:56+0200\n" +"PO-Revision-Date: 2019-08-16 21:19+0200\n" +"Last-Translator: Sebastian Rasmussen \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 2.2.3\n" + +msgid " - Press Ctrl+Alt+G to release grab" +msgstr " - Tryck Ctrl+Alt+G för att sluta fånga" + +msgid " [Paused]" +msgstr " [Pausad]" + +msgid "_Pause" +msgstr "_Paus" + +msgid "_Reset" +msgstr "_Starta om" + +msgid "Power _Down" +msgstr "Stäng _ner" + +msgid "_Quit" +msgstr "_Avsluta" + +msgid "_Fullscreen" +msgstr "_Helskärm" + +msgid "_Copy" +msgstr "_Kopiera" + +msgid "Zoom _In" +msgstr "Zooma _in" + +msgid "Zoom _Out" +msgstr "Zooma _ut" + +msgid "Best _Fit" +msgstr "Anpassad _storlek" + +msgid "Zoom To _Fit" +msgstr "Zooma ti_ll anpassad storlek" + +msgid "Grab On _Hover" +msgstr "Fånga vi_d hovring" + +msgid "_Grab Input" +msgstr "Fån_ga inmatning" + +msgid "Show _Tabs" +msgstr "Visa _flika" + +msgid "Detach Tab" +msgstr "Frigör flik" + +msgid "Show Menubar" +msgstr "Visa menyrad" + +msgid "_Machine" +msgstr "_Maskin" + +msgid "_View" +msgstr "_Visa" From e8512dfa4d320e83b7dd4d994a3e404060c5b49b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 27 May 2020 10:47:53 +0200 Subject: [PATCH 1200/2595] qom: Constify object_get_canonical_path{,_component}()'s parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Eric Blake Signed-off-by: Markus Armbruster Message-Id: <20200527084754.7531-2-armbru@redhat.com> Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé --- include/qom/object.h | 4 ++-- qom/object.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index c7c97ead60..43858162ad 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1404,7 +1404,7 @@ Object *object_get_internal_root(void); * path is the path within the composition tree starting from the root. * %NULL if the object doesn't have a parent (and thus a canonical path). */ -char *object_get_canonical_path_component(Object *obj); +char *object_get_canonical_path_component(const Object *obj); /** * object_get_canonical_path: @@ -1412,7 +1412,7 @@ char *object_get_canonical_path_component(Object *obj); * Returns: The canonical path for a object. This is the path within the * composition tree starting from the root. */ -char *object_get_canonical_path(Object *obj); +char *object_get_canonical_path(const Object *obj); /** * object_resolve_path: diff --git a/qom/object.c b/qom/object.c index b0ed560fd8..d1340ba3d9 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1881,7 +1881,7 @@ object_property_add_const_link(Object *obj, const char *name, NULL, OBJ_PROP_LINK_DIRECT); } -char *object_get_canonical_path_component(Object *obj) +char *object_get_canonical_path_component(const Object *obj) { ObjectProperty *prop = NULL; GHashTableIter iter; @@ -1906,7 +1906,7 @@ char *object_get_canonical_path_component(Object *obj) return NULL; } -char *object_get_canonical_path(Object *obj) +char *object_get_canonical_path(const Object *obj) { Object *root = object_get_root(); char *newpath, *path = NULL; From e8c9e65816f5dbfe18ad3b2be938d0d8192d459a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 27 May 2020 10:47:54 +0200 Subject: [PATCH 1201/2595] qom: Make "info qom-tree" show children sorted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "info qom-tree" prints children in unstable order. This is a pain when diffing output for different versions to find change. Print it sorted. Signed-off-by: Markus Armbruster Message-Id: <20200527084754.7531-3-armbru@redhat.com> Tested-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé --- qom/qom-hmp-cmds.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index f704b6949a..99385b6ad2 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -81,22 +81,25 @@ typedef struct QOMCompositionState { static void print_qom_composition(Monitor *mon, Object *obj, int indent); -static int print_qom_composition_child(Object *obj, void *opaque) +static int qom_composition_compare(const void *a, const void *b, void *ignore) { - QOMCompositionState *s = opaque; + return g_strcmp0(a ? object_get_canonical_path_component(a) : NULL, + b ? object_get_canonical_path_component(b) : NULL); +} - print_qom_composition(s->mon, obj, s->indent); +static int insert_qom_composition_child(Object *obj, void *opaque) +{ + GQueue *children = opaque; + g_queue_insert_sorted(children, obj, qom_composition_compare, NULL); return 0; } static void print_qom_composition(Monitor *mon, Object *obj, int indent) { - QOMCompositionState s = { - .mon = mon, - .indent = indent + 2, - }; char *name; + GQueue children; + Object *child; if (obj == object_get_root()) { name = g_strdup(""); @@ -106,7 +109,12 @@ static void print_qom_composition(Monitor *mon, Object *obj, int indent) monitor_printf(mon, "%*s/%s (%s)\n", indent, "", name, object_get_typename(obj)); g_free(name); - object_child_foreach(obj, print_qom_composition_child, &s); + + g_queue_init(&children); + object_child_foreach(obj, insert_qom_composition_child, &children); + while ((child = g_queue_pop_head(&children))) { + print_qom_composition(mon, child, indent + 2); + } } void hmp_info_qom_tree(Monitor *mon, const QDict *dict) From 2fb1f7d29932db2908bdaad0f03c326e800d5e62 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:16 +0200 Subject: [PATCH 1202/2595] arm/stm32f405: Fix realization of "stm32f2xx-adc" devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit stm32f405_soc_initfn() creates six such devices, but stm32f405_soc_realize() realizes only one. Affects machine netduinoplus2. In theory, a device becomes real only on realize. In practice, the transition from unreal to real is a fuzzy one. The work to make a device real can be spread between realize methods (fine), instance_init methods (wrong), and board code wiring up the device (fine as long as it effectively happens on realize). Depending on what exactly is done where, a device can work even when we neglect to realize it. The five unrealized devices appear to stay unreal: neither MMIO nor IRQ get wired up. Fix stm32f405_soc_realize() to realize and wire up all six. Visible in "info qtree": bus: main-system-bus type System dev: stm32f405-soc, id "" cpu-type = "cortex-m4-arm-cpu" dev: stm32f2xx-adc, id "" gpio-out "sysbus-irq" 1 - mmio ffffffffffffffff/00000000000000ff + mmio 0000000040012000/00000000000000ff dev: stm32f2xx-adc, id "" gpio-out "sysbus-irq" 1 - mmio ffffffffffffffff/00000000000000ff + mmio 0000000040012100/00000000000000ff dev: stm32f2xx-adc, id "" gpio-out "sysbus-irq" 1 - mmio ffffffffffffffff/00000000000000ff + mmio 0000000040012200/00000000000000ff dev: stm32f2xx-adc, id "" gpio-out "sysbus-irq" 1 - mmio ffffffffffffffff/00000000000000ff + mmio 0000000040012300/00000000000000ff dev: stm32f2xx-adc, id "" gpio-out "sysbus-irq" 1 - mmio 0000000040012000/00000000000000ff + mmio 0000000040012400/00000000000000ff dev: stm32f2xx-adc, id "" gpio-out "sysbus-irq" 1 - mmio ffffffffffffffff/00000000000000ff + mmio 0000000040012500/00000000000000ff dev: armv7m, id "" Fixes: 529fc5fd3e18ace8f739afd02dc0953354f39442 Cc: Alistair Francis Cc: Peter Maydell Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200609122339.937862-2-armbru@redhat.com> Reviewed-by: Alistair Francis --- hw/arm/stm32f405_soc.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index 4f10ce6176..c9a530eecf 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -37,7 +37,8 @@ static const uint32_t usart_addr[] = { 0x40011000, 0x40004400, 0x40004800, /* At the moment only Timer 2 to 5 are modelled */ static const uint32_t timer_addr[] = { 0x40000000, 0x40000400, 0x40000800, 0x40000C00 }; -#define ADC_ADDR 0x40012000 +static const uint32_t adc_addr[] = { 0x40012000, 0x40012100, 0x40012200, + 0x40012300, 0x40012400, 0x40012500 }; static const uint32_t spi_addr[] = { 0x40013000, 0x40003800, 0x40003C00, 0x40013400, 0x40015000, 0x40015400 }; #define EXTI_ADDR 0x40013C00 @@ -185,16 +186,18 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) qdev_connect_gpio_out(DEVICE(&s->adc_irqs), 0, qdev_get_gpio_in(armv7m, ADC_IRQ)); - dev = DEVICE(&(s->adc[i])); - object_property_set_bool(OBJECT(&s->adc[i]), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; + for (i = 0; i < STM_NUM_ADCS; i++) { + dev = DEVICE(&(s->adc[i])); + object_property_set_bool(OBJECT(&s->adc[i]), true, "realized", &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, adc_addr[i]); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(DEVICE(&s->adc_irqs), i)); } - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, ADC_ADDR); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(DEVICE(&s->adc_irqs), i)); /* SPI devices */ for (i = 0; i < STM_NUM_SPIS; i++) { From f6a1f93d6a43c6ede9f32de3b4ccb126998f322e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:17 +0200 Subject: [PATCH 1203/2595] display/xlnx_dp: Fix to realize "i2c-ddc" and "aux-to-i2c-bridge" xlnx_dp_init() creates these two devices, but they're never realized. Affects machine xlnx-zcu102. In theory, a device becomes real only on realize. In practice, the transition from unreal to real is a fuzzy one. The work to make a device real can be spread between realize methods (fine), instance_init methods (wrong), and board code wiring up the device (fine as long as it effectively happens on realize). Depending on what exactly is done where, a device can work even when we neglect to realize it. These two appear to work. Nevertheless, it's a clear misuse of the interface. Even when it works today (more or less by chance), it can break tomorrow. Fix by realizing them in xlnx_dp_realize(). Fixes: 58ac482a66de09a7590f705e53fc6a3fb8a055e8 Cc: KONRAD Frederic Cc: Alistair Francis Cc: "Edgar E. Iglesias" Cc: Peter Maydell Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Message-Id: <20200609122339.937862-3-armbru@redhat.com> --- hw/display/xlnx_dp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 8d940cd8d1..5210412e55 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1266,9 +1266,13 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp) DisplaySurface *surface; struct audsettings as; + qdev_init_nofail(DEVICE(s->aux_bus->bridge)); + qdev_init_nofail(DEVICE(s->dpcd)); aux_map_slave(AUX_SLAVE(s->dpcd), 0x0000); + qdev_init_nofail(DEVICE(s->edid)); + s->console = graphic_console_init(dev, 0, &xlnx_dp_gfx_ops, s); surface = qemu_console_surface(s->console); xlnx_dpdma_set_host_data_location(s->dpdma, DP_GRAPHIC_DMA_CHANNEL, From 71e5770b618a2a10d9f92eade0ea0f2c8aaca58d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:18 +0200 Subject: [PATCH 1204/2595] sd/pxa2xx_mmci: Fix to realize "pxa2xx-mmci" device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pxa2xx_mmci_init() creates a "pxa2xx-mmci" device, but neglects to realize it. Affects machines akita, borzoi, connex, mainstone, spitz, terrier, tosa, verdex, and z2. In theory, a device becomes real only on realize. In practice, the transition from unreal to real is a fuzzy one. The work to make a device real can be spread between realize methods (fine), instance_init methods (wrong), and board code wiring up the device (fine as long as it effectively happens on realize). Depending on what exactly is done where, a device can work even when we neglect to realize it. This one appears to work. Nevertheless, it's a clear misuse of the interface. Even when it works today (more or less by chance), it can break tomorrow. Fix by realizing it right away. Visible in "info qom-tree"; here's the change for akita: /machine (akita-machine) [...] /unattached (container) [...] + /device[5] (pxa2xx-mmci) + /pxa2xx-mmci[0] (qemu:memory-region) + /sd-bus (pxa2xx-mmci-bus) [rest of device[*] renumbered...] Fixes: 7a9468c92517e19037bfe2272f64f5dadaf9db15 Cc: Andrzej Zaborowski Cc: Peter Maydell Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200609122339.937862-4-armbru@redhat.com> --- hw/sd/pxa2xx_mmci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index f9c50ddda5..c32df1b8f9 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -492,6 +492,7 @@ PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, sysbus_connect_irq(sbd, 0, irq); qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma); qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma); + qdev_init_nofail(dev); /* Create and plug in the sd card */ carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); From b7f1a0cb7663eca31c8e8f7b247eaf1c9782b104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 9 Jun 2020 14:23:19 +0200 Subject: [PATCH 1205/2595] arm/aspeed: Compute the number of CPUs from the SoC definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit ece09beec457 ("aspeed: introduce a configurable number of CPU per machine") was a convient change during bringup but the Aspeed SoCs have a fixed number of CPUs : one for the AST2400 and AST2500, and two for the AST2600. When the number of CPUs configured with -smp is less than the SoC's fixed number, the "unconfigured" CPUs are left unrealized. This can happen for machines ast2600-evb and tacoma-bmc, where the SoC's fixed number is 2. To get virtual hardware that matches the physical hardware, you have to pass -smp cpus=2 (or its sugared form -smp 2). We normally reject -smp cpus=N when N exceeds the machine's limit. Except we ignore cpus=2 (and only cpus=2) with a warning for machines ast2500-evb, palmetto-bmc, romulus-bmc, sonorapass-bmc, swift-bmc, and witherspoon-bmc. Remove the "num-cpu" property from the SoC state and use the fixed number of CPUs defined in the SoC class instead. Compute the default, min, max number of CPUs of the machine directly from the SoC class definition. Machines ast2600-evb and tacoma-bmc now always get their second CPU as they should. Visible in "info qom-tree"; here's the change for ast2600-evb: /machine (ast2600-evb-machine) /peripheral (container) /peripheral-anon (container) /soc (ast2600-a1) /a7mpcore (a15mpcore_priv) /a15mp-priv-container[0] (qemu:memory-region) /gic (arm_gic) /gic_cpu[0] (qemu:memory-region) /gic_cpu[1] (qemu:memory-region) + /gic_cpu[2] (qemu:memory-region) /gic_dist[0] (qemu:memory-region) /gic_vcpu[0] (qemu:memory-region) /gic_viface[0] (qemu:memory-region) /gic_viface[1] (qemu:memory-region) + /gic_viface[2] (qemu:memory-region) /unnamed-gpio-in[0] (irq) [...] + /unnamed-gpio-in[160] (irq) [same for 161 to 190...] + /unnamed-gpio-in[191] (irq) Also visible in "info qtree"; here's the change for ast2600-evb: bus: main-system-bus type System dev: a15mpcore_priv, id "" gpio-in "" 128 - gpio-out "sysbus-irq" 5 - num-cpu = 1 (0x1) + gpio-out "sysbus-irq" 10 + num-cpu = 2 (0x2) num-irq = 160 (0xa0) mmio 0000000040460000/0000000000008000 dev: arm_gic, id "" - gpio-in "" 160 - num-cpu = 1 (0x1) + gpio-in "" 192 + num-cpu = 2 (0x2) num-irq = 160 (0xa0) revision = 2 (0x2) has-security-extensions = true has-virtualization-extensions = true num-priority-bits = 8 (0x8) mmio ffffffffffffffff/0000000000001000 mmio ffffffffffffffff/0000000000002000 mmio ffffffffffffffff/0000000000001000 mmio ffffffffffffffff/0000000000002000 mmio ffffffffffffffff/0000000000000100 + mmio ffffffffffffffff/0000000000000100 + mmio ffffffffffffffff/0000000000000200 mmio ffffffffffffffff/0000000000000200 The other machines now reject -smp cpus=2 just like -smp cpus=3 and up. Signed-off-by: Cédric Le Goater Reviewed-by: Markus Armbruster [Commit message expanded] Signed-off-by: Markus Armbruster Message-Id: <20200609122339.937862-5-armbru@redhat.com> --- hw/arm/aspeed.c | 29 ++++++++++++++++++++++++----- hw/arm/aspeed_ast2600.c | 20 +++++++------------- hw/arm/aspeed_soc.c | 9 +-------- include/hw/arm/aspeed_soc.h | 1 - 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 62344ac6a3..2e7917da74 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -283,8 +283,6 @@ static void aspeed_machine_init(MachineState *machine) &error_abort); object_property_set_int(OBJECT(&bmc->soc), amc->num_cs, "num-cs", &error_abort); - object_property_set_int(OBJECT(&bmc->soc), machine->smp.cpus, "num-cpus", - &error_abort); object_property_set_link(OBJECT(&bmc->soc), OBJECT(&bmc->ram_container), "dram", &error_abort); if (machine->kernel_filename) { @@ -337,7 +335,7 @@ static void aspeed_machine_init(MachineState *machine) } } - if (machine->kernel_filename && bmc->soc.num_cpus > 1) { + if (machine->kernel_filename && sc->num_cpus > 1) { /* With no u-boot we must set up a boot stub for the secondary CPU */ MemoryRegion *smpboot = g_new(MemoryRegion, 1); memory_region_init_ram(smpboot, OBJECT(bmc), "aspeed.smpboot", @@ -352,7 +350,7 @@ static void aspeed_machine_init(MachineState *machine) aspeed_board_binfo.ram_size = ram_size; aspeed_board_binfo.loader_start = sc->memmap[ASPEED_SDRAM]; - aspeed_board_binfo.nb_cpus = bmc->soc.num_cpus; + aspeed_board_binfo.nb_cpus = sc->num_cpus; if (amc->i2c_init) { amc->i2c_init(bmc); @@ -549,12 +547,17 @@ static void aspeed_machine_class_props_init(ObjectClass *oc) "boot directly from CE0 flash device"); } +static int aspeed_soc_num_cpus(const char *soc_name) +{ + AspeedSoCClass *sc = ASPEED_SOC_CLASS(object_class_by_name(soc_name)); + return sc->num_cpus; +} + static void aspeed_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); mc->init = aspeed_machine_init; - mc->max_cpus = ASPEED_CPUS_NUM; mc->no_floppy = 1; mc->no_cdrom = 1; mc->no_parallel = 1; @@ -576,6 +579,8 @@ static void aspeed_machine_palmetto_class_init(ObjectClass *oc, void *data) amc->num_cs = 1; amc->i2c_init = palmetto_bmc_i2c_init; mc->default_ram_size = 256 * MiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); }; static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, void *data) @@ -591,6 +596,8 @@ static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, void *data) amc->num_cs = 1; amc->i2c_init = ast2500_evb_i2c_init; mc->default_ram_size = 512 * MiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); }; static void aspeed_machine_romulus_class_init(ObjectClass *oc, void *data) @@ -606,6 +613,8 @@ static void aspeed_machine_romulus_class_init(ObjectClass *oc, void *data) amc->num_cs = 2; amc->i2c_init = romulus_bmc_i2c_init; mc->default_ram_size = 512 * MiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); }; static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, void *data) @@ -621,6 +630,8 @@ static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, void *data) amc->num_cs = 2; amc->i2c_init = sonorapass_bmc_i2c_init; mc->default_ram_size = 512 * MiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); }; static void aspeed_machine_swift_class_init(ObjectClass *oc, void *data) @@ -636,6 +647,8 @@ static void aspeed_machine_swift_class_init(ObjectClass *oc, void *data) amc->num_cs = 2; amc->i2c_init = swift_bmc_i2c_init; mc->default_ram_size = 512 * MiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); }; static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data) @@ -651,6 +664,8 @@ static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data) amc->num_cs = 2; amc->i2c_init = witherspoon_bmc_i2c_init; mc->default_ram_size = 512 * MiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); }; static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data) @@ -667,6 +682,8 @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data) amc->num_cs = 1; amc->i2c_init = ast2600_evb_i2c_init; mc->default_ram_size = 1 * GiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); }; static void aspeed_machine_tacoma_class_init(ObjectClass *oc, void *data) @@ -683,6 +700,8 @@ static void aspeed_machine_tacoma_class_init(ObjectClass *oc, void *data) amc->num_cs = 2; amc->i2c_init = witherspoon_bmc_i2c_init; /* Same board layout */ mc->default_ram_size = 1 * GiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); }; static const TypeInfo aspeed_machine_types[] = { diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 71a0acfe26..c6821b3322 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -255,17 +255,11 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) create_unimplemented_device("aspeed.video", sc->memmap[ASPEED_VIDEO], 0x1000); - if (s->num_cpus > sc->num_cpus) { - warn_report("%s: invalid number of CPUs %d, using default %d", - sc->name, s->num_cpus, sc->num_cpus); - s->num_cpus = sc->num_cpus; - } - /* CPU */ - for (i = 0; i < s->num_cpus; i++) { + for (i = 0; i < sc->num_cpus; i++) { object_property_set_int(OBJECT(&s->cpu[i]), QEMU_PSCI_CONDUIT_SMC, "psci-conduit", &error_abort); - if (s->num_cpus > 1) { + if (sc->num_cpus > 1) { object_property_set_int(OBJECT(&s->cpu[i]), ASPEED_A7MPCORE_ADDR, "reset-cbar", &error_abort); @@ -289,7 +283,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* A7MPCORE */ - object_property_set_int(OBJECT(&s->a7mpcore), s->num_cpus, "num-cpu", + object_property_set_int(OBJECT(&s->a7mpcore), sc->num_cpus, "num-cpu", &error_abort); object_property_set_int(OBJECT(&s->a7mpcore), ASPEED_SOC_AST2600_MAX_IRQ + GIC_INTERNAL, @@ -299,18 +293,18 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, ASPEED_A7MPCORE_ADDR); - for (i = 0; i < s->num_cpus; i++) { + for (i = 0; i < sc->num_cpus; i++) { SysBusDevice *sbd = SYS_BUS_DEVICE(&s->a7mpcore); DeviceState *d = DEVICE(qemu_get_cpu(i)); irq = qdev_get_gpio_in(d, ARM_CPU_IRQ); sysbus_connect_irq(sbd, i, irq); irq = qdev_get_gpio_in(d, ARM_CPU_FIQ); - sysbus_connect_irq(sbd, i + s->num_cpus, irq); + sysbus_connect_irq(sbd, i + sc->num_cpus, irq); irq = qdev_get_gpio_in(d, ARM_CPU_VIRQ); - sysbus_connect_irq(sbd, i + 2 * s->num_cpus, irq); + sysbus_connect_irq(sbd, i + 2 * sc->num_cpus, irq); irq = qdev_get_gpio_in(d, ARM_CPU_VFIQ); - sysbus_connect_irq(sbd, i + 3 * s->num_cpus, irq); + sysbus_connect_irq(sbd, i + 3 * sc->num_cpus, irq); } /* SRAM */ diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index cf6b6dd116..e6f4b59134 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -242,14 +242,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) create_unimplemented_device("aspeed.video", sc->memmap[ASPEED_VIDEO], 0x1000); - if (s->num_cpus > sc->num_cpus) { - warn_report("%s: invalid number of CPUs %d, using default %d", - sc->name, s->num_cpus, sc->num_cpus); - s->num_cpus = sc->num_cpus; - } - /* CPU */ - for (i = 0; i < s->num_cpus; i++) { + for (i = 0; i < sc->num_cpus; i++) { object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err); if (err) { error_propagate(errp, err); @@ -460,7 +454,6 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_SDHCI)); } static Property aspeed_soc_properties[] = { - DEFINE_PROP_UINT32("num-cpus", AspeedSoCState, num_cpus, 0), DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 78b9f6ae53..914115f3ef 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -40,7 +40,6 @@ typedef struct AspeedSoCState { /*< public >*/ ARMCPU cpu[ASPEED_CPUS_NUM]; - uint32_t num_cpus; A15MPPrivState a7mpcore; MemoryRegion *dram_mr; MemoryRegion sram; From d3bad7e7c48f8c33b28cd5a472c89a53dfe56f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 9 Jun 2020 14:23:20 +0200 Subject: [PATCH 1206/2595] arm/aspeed: Rework NIC attachment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The number of MACs supported by an Aspeed SoC is defined by "macs_num" under the SoC model, that is two for the AST2400 and AST2500 and four for the AST2600. The model initializes the maximum number of supported MACs but the number of realized devices is capped by the number of network device back-ends defined on the command line. This can leave unrealized devices hanging around in the QOM composition tree. To get virtual hardware that matches the physical hardware, you have to pass exactly as many -nic options as there are MACs, and some of them must be -nic none: * Machines ast2500-evb, palmetto-bmc, romulus-bmc, sonorapass-bmc, swift-bmc, and witherspoon-bmc: two -nic, and the second one must be -nic none. * Machine ast2600-evb: four -nic, the first one must be -nic none. * Machine tacoma-bmc: four nic, the first two and the last one must be -nic none. Modify the machine initialization to define which MACs are attached to a network device back-end using a bit-field property "macs-mask" and let the SoC realize all network devices. The default setting of "macs-mask" is "use MAC0" only, which works for all our AST2400 and AST2500 machines. The AST2600 machines have different configurations. The AST2600 EVB machine activates MAC1, MAC2 and MAC3 and the Tacoma BMC machine activates MAC2. Incompatible CLI change: -nic options now apply to *active* MACs: MAC1, MAC2, MAC3 for ast2600-evb, MAC2 for tacoma-bmc, and MAC0 for all the others. The machines now always get all MACs as they should. Visible in "info qom-tree", here's the change for tacoma-bmc: /machine (tacoma-bmc-machine) /peripheral (container) /peripheral-anon (container) /soc (ast2600-a1) [...] /ftgmac100[0] (ftgmac100) /ftgmac100[0] (qemu:memory-region) /ftgmac100[1] (ftgmac100) + /ftgmac100[0] (qemu:memory-region) /ftgmac100[2] (ftgmac100) + /ftgmac100[0] (qemu:memory-region) /ftgmac100[3] (ftgmac100) + /ftgmac100[0] (qemu:memory-region) [...] /mii[0] (aspeed-mmi) /aspeed-mmi[0] (qemu:memory-region) /mii[1] (aspeed-mmi) + /aspeed-mmi[0] (qemu:memory-region) /mii[2] (aspeed-mmi) + /aspeed-mmi[0] (qemu:memory-region) /mii[3] (aspeed-mmi) + /aspeed-mmi[0] (qemu:memory-region) Also visible in "info qtree"; here's the change for tacoma-bmc: dev: ftgmac100, id "" gpio-out "sysbus-irq" 1 aspeed = true - mac = "52:54:00:12:34:56" - netdev = "hub0port0" + mac = "52:54:00:12:34:57" + netdev = "" mmio 000000001e660000/0000000000002000 dev: ftgmac100, id "" - aspeed = false - mac = "00:00:00:00:00:00" + gpio-out "sysbus-irq" 1 + aspeed = true + mac = "52:54:00:12:34:58" netdev = "" + mmio 000000001e680000/0000000000002000 dev: ftgmac100, id "" - aspeed = false - mac = "00:00:00:00:00:00" - netdev = "" + gpio-out "sysbus-irq" 1 + aspeed = true + mac = "52:54:00:12:34:56" + netdev = "hub0port0" + mmio 000000001e670000/0000000000002000 dev: ftgmac100, id "" - aspeed = false - mac = "00:00:00:00:00:00" + gpio-out "sysbus-irq" 1 + aspeed = true + mac = "52:54:00:12:34:59" netdev = "" + mmio 000000001e690000/0000000000002000 [...] dev: aspeed-mmi, id "" mmio 000000001e650000/0000000000000008 dev: aspeed-mmi, id "" + mmio 000000001e650008/0000000000000008 dev: aspeed-mmi, id "" + mmio 000000001e650010/0000000000000008 dev: aspeed-mmi, id "" + mmio 000000001e650018/0000000000000008 Inactive MACs will have no peer and QEMU may warn the user with : qemu-system-arm: warning: nic ftgmac100.0 has no peer qemu-system-arm: warning: nic ftgmac100.1 has no peer qemu-system-arm: warning: nic ftgmac100.3 has no peer Signed-off-by: Cédric Le Goater Reviewed-by: Markus Armbruster Reviewed-by: Joel Stanley [Commit message expanded] Signed-off-by: Markus Armbruster Message-Id: <20200609122339.937862-6-armbru@redhat.com> --- hw/arm/aspeed.c | 13 +++++++++++++ hw/arm/aspeed_ast2600.c | 3 +-- hw/arm/aspeed_soc.c | 3 +-- include/hw/arm/aspeed.h | 6 ++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 2e7917da74..ad9f772e06 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -258,6 +258,7 @@ static void aspeed_machine_init(MachineState *machine) DriveInfo *drive0 = drive_get(IF_MTD, 0, 0); ram_addr_t max_ram_size; int i; + NICInfo *nd = &nd_table[0]; bmc = g_new0(AspeedBoardState, 1); @@ -277,6 +278,14 @@ static void aspeed_machine_init(MachineState *machine) object_property_set_uint(OBJECT(&bmc->soc), ram_size, "ram-size", &error_fatal); + for (i = 0; i < sc->macs_num; i++) { + if ((amc->macs_mask & (1 << i)) && nd->used) { + qemu_check_nic_model(nd, TYPE_FTGMAC100); + qdev_set_nic_properties(DEVICE(&bmc->soc.ftgmac100[i]), nd); + nd++; + } + } + object_property_set_int(OBJECT(&bmc->soc), amc->hw_strap1, "hw-strap1", &error_abort); object_property_set_int(OBJECT(&bmc->soc), amc->hw_strap2, "hw-strap2", @@ -556,12 +565,14 @@ static int aspeed_soc_num_cpus(const char *soc_name) static void aspeed_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); mc->init = aspeed_machine_init; mc->no_floppy = 1; mc->no_cdrom = 1; mc->no_parallel = 1; mc->default_ram_id = "ram"; + amc->macs_mask = ASPEED_MAC0_ON; aspeed_machine_class_props_init(oc); } @@ -680,6 +691,7 @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data) amc->fmc_model = "w25q512jv"; amc->spi_model = "mx66u51235f"; amc->num_cs = 1; + amc->macs_mask = ASPEED_MAC1_ON | ASPEED_MAC2_ON | ASPEED_MAC3_ON; amc->i2c_init = ast2600_evb_i2c_init; mc->default_ram_size = 1 * GiB; mc->default_cpus = mc->min_cpus = mc->max_cpus = @@ -698,6 +710,7 @@ static void aspeed_machine_tacoma_class_init(ObjectClass *oc, void *data) amc->fmc_model = "mx66l1g45g"; amc->spi_model = "mx66l1g45g"; amc->num_cs = 2; + amc->macs_mask = ASPEED_MAC2_ON; amc->i2c_init = witherspoon_bmc_i2c_init; /* Same board layout */ mc->default_ram_size = 1 * GiB; mc->default_cpus = mc->min_cpus = mc->max_cpus = diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index c6821b3322..b912d19f80 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -461,8 +461,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* Net */ - for (i = 0; i < nb_nics && i < sc->macs_num; i++) { - qdev_set_nic_properties(DEVICE(&s->ftgmac100[i]), &nd_table[i]); + for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", &err); object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "realized", diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index e6f4b59134..3ec1257c14 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -404,8 +404,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } /* Net */ - for (i = 0; i < nb_nics && i < sc->macs_num; i++) { - qdev_set_nic_properties(DEVICE(&s->ftgmac100[i]), &nd_table[i]); + for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", &err); object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "realized", diff --git a/include/hw/arm/aspeed.h b/include/hw/arm/aspeed.h index 18521484b9..95b4daece8 100644 --- a/include/hw/arm/aspeed.h +++ b/include/hw/arm/aspeed.h @@ -23,6 +23,11 @@ typedef struct AspeedMachine { bool mmio_exec; } AspeedMachine; +#define ASPEED_MAC0_ON (1 << 0) +#define ASPEED_MAC1_ON (1 << 1) +#define ASPEED_MAC2_ON (1 << 2) +#define ASPEED_MAC3_ON (1 << 3) + #define ASPEED_MACHINE_CLASS(klass) \ OBJECT_CLASS_CHECK(AspeedMachineClass, (klass), TYPE_ASPEED_MACHINE) #define ASPEED_MACHINE_GET_CLASS(obj) \ @@ -39,6 +44,7 @@ typedef struct AspeedMachineClass { const char *fmc_model; const char *spi_model; uint32_t num_cs; + uint32_t macs_mask; void (*i2c_init)(AspeedBoardState *bmc); } AspeedMachineClass; From 210d18674a34bb43bd05cdd68d24fd03e161ff3d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:21 +0200 Subject: [PATCH 1207/2595] armv7m: Delete unused "ARM,bitband-memory" devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These devices are optional, and enabled by property "enable-bitband". armv7m_instance_init() creates them unconditionally, because the property has not been set then. armv7m_realize() realizes them only when the property is true. Works, although it leaves unrealized devices hanging around in the QOM composition tree. Affects machines microbit, mps2-an505, mps2-an521, musca-a, and musca-b1. Delete the unused devices by making armv7m_realize() unparent them. Visible in "info qom-tree"; here's the change for microbit: /machine (microbit-machine) /microbit.twi (microbit.i2c) /microbit.twi[0] (qemu:memory-region) /nrf51 (nrf51-soc) /armv6m (armv7m) /armv7m-container[0] (qemu:memory-region) - /bitband[0] (ARM,bitband-memory) - /bitband[0] (qemu:memory-region) - /bitband[1] (ARM,bitband-memory) - /bitband[0] (qemu:memory-region) /cpu (cortex-m0-arm-cpu) Cc: Peter Maydell Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Message-Id: <20200609122339.937862-7-armbru@redhat.com> --- hw/arm/armv7m.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 7da57f56d3..f930619f53 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -245,8 +245,8 @@ static void armv7m_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(&s->container, 0xe000e000, sysbus_mmio_get_region(sbd, 0)); - if (s->enable_bitband) { - for (i = 0; i < ARRAY_SIZE(s->bitband); i++) { + for (i = 0; i < ARRAY_SIZE(s->bitband); i++) { + if (s->enable_bitband) { Object *obj = OBJECT(&s->bitband[i]); SysBusDevice *sbd = SYS_BUS_DEVICE(&s->bitband[i]); @@ -265,6 +265,8 @@ static void armv7m_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(&s->container, bitband_output_addr[i], sysbus_mmio_get_region(sbd, 0)); + } else { + object_unparent(OBJECT(&s->bitband[i])); } } } From 6b888ee28c8801b346eb41655b36207a28ce146b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:22 +0200 Subject: [PATCH 1208/2595] auxbus: Fix aux-to-i2c-bridge to be a subtype of aux-slave MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We plug aux-to-i2c-bridge into the aux-bus, even though its DeviceClass member bus_type is null, not TYPE_AUX_BUS. Fix that by deriving it from TYPE_AUX_SLAVE instead of TYPE_DEVICE. Cc: KONRAD Frederic Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200609122339.937862-8-armbru@redhat.com> --- hw/misc/auxbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index 06aabf20c5..80bc3a0777 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -244,7 +244,7 @@ static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge) static const TypeInfo aux_to_i2c_type_info = { .name = TYPE_AUXTOI2C, - .parent = TYPE_DEVICE, + .parent = TYPE_AUX_SLAVE, .class_init = aux_bridge_class_init, .instance_size = sizeof(AUXTOI2CState), .instance_init = aux_bridge_init From 5e769ecf509089c053bb247ae48a360ef8e87d66 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:23 +0200 Subject: [PATCH 1209/2595] mac_via: Fix to realize "mos6522-q800-via*" devices mac_via_realize() creates a "mos6522-q800-via1" and a "mos6522-q800-via2" device, but neglects to realize them. Affects machine q800. In theory, a device becomes real only on realize. In practice, the transition from unreal to real is a fuzzy one. The work to make a device real can be spread between realize methods (fine), instance_init methods (wrong), and board code wiring up the device (fine as long as it effectively happens on realize). Depending on what exactly is done where, a device can work even when we neglect to realize it. These two appear to work. Nevertheless, it's a clear misuse of the interface. Even when it works today (more or less by chance), it can break tomorrow. Fix by realizing them right away. Fixes: 6dca62a0000f95e0b7020aa00d0ca9b2c421f341 Cc: Laurent Vivier Signed-off-by: Markus Armbruster Reviewed-by: Mark Cave-Ayland Message-Id: <20200609122339.937862-9-armbru@redhat.com> Tested-by: Laurent Vivier Acked-by: Laurent Vivier --- hw/misc/mac_via.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index e05623d730..82614c155a 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -890,6 +890,11 @@ static void mac_via_realize(DeviceState *dev, Error **errp) object_property_add_alias(OBJECT(dev), "irq[1]", OBJECT(ms), SYSBUS_DEVICE_GPIO_IRQ "[0]"); + object_property_set_bool(OBJECT(&m->mos6522_via1), true, "realized", + &error_abort); + object_property_set_bool(OBJECT(&m->mos6522_via2), true, "realized", + &error_abort); + /* Pass through mos6522 input IRQs */ qdev_pass_gpios(DEVICE(&m->mos6522_via1), dev, "via1-irq"); qdev_pass_gpios(DEVICE(&m->mos6522_via2), dev, "via2-irq"); From 3d81f594fdcd6c2737a52dcb19552a298f2af9e1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:24 +0200 Subject: [PATCH 1210/2595] macio: Fix to realize "mos6522-cuda" and "mos6522-pmu" devices cuda_init() creates a "mos6522-cuda" device, but it's never realized. Affects machines mac99 with via=cuda (default) and g3beige. pmu_init() creates a "mos6522-pmu" device, but it's never realized. Affects machine mac99 with via=pmu and via=pmu-adb, In theory, a device becomes real only on realize. In practice, the transition from unreal to real is a fuzzy one. The work to make a device real can be spread between realize methods (fine), instance_init methods (wrong), and board code wiring up the device (fine as long as it effectively happens on realize). Depending on what exactly is done where, a device can work even when we neglect to realize it. These two appear to work. Nevertheless, it's a clear misuse of the interface. Even when it works today (more or less by chance), it can break tomorrow. Fix by realizing them in cuda_realize() and pmu_realize(), respectively. Fixes: 6dca62a0000f95e0b7020aa00d0ca9b2c421f341 Cc: Laurent Vivier Signed-off-by: Markus Armbruster Message-Id: <20200609122339.937862-10-armbru@redhat.com> --- hw/misc/macio/cuda.c | 15 ++++++++++----- hw/misc/macio/pmu.c | 15 ++++++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index e0cc0aac5d..3cb10c743c 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -33,6 +33,7 @@ #include "hw/misc/macio/cuda.h" #include "qemu/timer.h" #include "sysemu/runstate.h" +#include "qapi/error.h" #include "qemu/cutils.h" #include "qemu/log.h" #include "qemu/module.h" @@ -522,16 +523,20 @@ static void cuda_reset(DeviceState *dev) static void cuda_realize(DeviceState *dev, Error **errp) { CUDAState *s = CUDA(dev); + Error *err = NULL; SysBusDevice *sbd; - MOS6522State *ms; - DeviceState *d; struct tm tm; + object_property_set_bool(OBJECT(&s->mos6522_cuda), true, "realized", + &err); + if (err) { + error_propagate(errp, err); + return; + } + /* Pass IRQ from 6522 */ - d = DEVICE(&s->mos6522_cuda); - ms = MOS6522(d); sbd = SYS_BUS_DEVICE(s); - sysbus_pass_irq(sbd, SYS_BUS_DEVICE(ms)); + sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->mos6522_cuda)); qemu_get_timedate(&tm, 0); s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index 9a9cd427e1..0895b78b59 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -40,6 +40,7 @@ #include "hw/misc/macio/pmu.h" #include "qemu/timer.h" #include "sysemu/runstate.h" +#include "qapi/error.h" #include "qemu/cutils.h" #include "qemu/log.h" #include "qemu/module.h" @@ -739,16 +740,20 @@ static void pmu_reset(DeviceState *dev) static void pmu_realize(DeviceState *dev, Error **errp) { PMUState *s = VIA_PMU(dev); + Error *err = NULL; SysBusDevice *sbd; - MOS6522State *ms; - DeviceState *d; struct tm tm; + object_property_set_bool(OBJECT(&s->mos6522_pmu), true, "realized", + &err); + if (err) { + error_propagate(errp, err); + return; + } + /* Pass IRQ from 6522 */ - d = DEVICE(&s->mos6522_pmu); - ms = MOS6522(d); sbd = SYS_BUS_DEVICE(s); - sysbus_pass_irq(sbd, SYS_BUS_DEVICE(ms)); + sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->mos6522_pmu)); qemu_get_timedate(&tm, 0); s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; From 33208432f5fdd459c98237872e480ef82f435419 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:25 +0200 Subject: [PATCH 1211/2595] macio: Delete unused "macio-gpio" devices These devices go with the "via-pmu" device, which is controlled by property "has-pmu". macio_newworld_init() creates it unconditionally, because the property has not been set then. macio_newworld_realize() realizes it only when the property is true. Works, although it can leave an unrealized device hanging around in the QOM composition tree. Affects machine mac99 with via=cuda (default). Delete the unused device by making macio_newworld_realize() unparent it. Visible in "info qom-tree": /machine (mac99-machine) [...] /unattached (container) /device[9] (macio-newworld) [...] /escc-legacy-port[8] (qemu:memory-region) /escc-legacy-port[9] (qemu:memory-region) /escc-legacy[0] (qemu:memory-region) - /gpio (macio-gpio) - /gpio[0] (qemu:memory-region) /ide[0] (macio-ide) /ide.0 (IDE) /pmac-ide[0] (qemu:memory-region) Cc: Mark Cave-Ayland Cc: David Gibson Cc: qemu-ppc@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Mark Cave-Ayland Message-Id: <20200609122339.937862-11-armbru@redhat.com> --- hw/misc/macio/macio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 3779865ab2..b3dddf8be7 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -368,6 +368,8 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) memory_region_add_subregion(&s->bar, 0x16000, sysbus_mmio_get_region(sysbus_dev, 0)); } else { + object_unparent(OBJECT(&ns->gpio)); + /* CUDA */ object_initialize_child(OBJECT(s), "cuda", &s->cuda, sizeof(s->cuda), TYPE_CUDA, &error_abort, NULL); From efa0559547e7e2c10dee16a78066176c1ea75e97 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:26 +0200 Subject: [PATCH 1212/2595] pnv/phb4: Delete unused "pnv-phb4-pec-stack" devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The number of stacks is controlled by property "num-stacks". pnv_pec_instance_init() creates the maximum supported number, because the property has not been set then. pnv_pec_realize() realizes only the wanted number. Works, although it can leave unrealized devices hanging around in the QOM composition tree. Affects machine powernv9. Delete the unused devices by making pnv_pec_realize() unparent them. Visible in "info qom-tree": /machine (powernv9-machine) /chip[0] (power9_v2.0-pnv-chip) [...] /pec[0] (pnv-phb4-pec) /stack[0] (pnv-phb4-pec-stack) [...] - /stack[1] (pnv-phb4-pec-stack) - /phb (pnv-phb4) - /pcie-mmcfg-mmio[0] (qemu:memory-region) - /root (pnv-phb4-root-port) - /source (xive-source) - /stack[2] (pnv-phb4-pec-stack) - /phb (pnv-phb4) - /pcie-mmcfg-mmio[0] (qemu:memory-region) - /root (pnv-phb4-root-port) - /source (xive-source) /xscom-pec-0.0-nest[0] (qemu:memory-region) /xscom-pec-0.0-pci[0] (qemu:memory-region) /pec[1] (pnv-phb4-pec) /stack[0] (pnv-phb4-pec-stack) [...] /stack[1] (pnv-phb4-pec-stack) [...] - /stack[2] (pnv-phb4-pec-stack) - /phb (pnv-phb4) - /pcie-mmcfg-mmio[0] (qemu:memory-region) - /root (pnv-phb4-root-port) - /source (xive-source) /xscom-pec-0.1-nest[0] (qemu:memory-region) /xscom-pec-0.1-pci[0] (qemu:memory-region) /pec[2] (pnv-phb4-pec) /stack[0] (pnv-phb4-pec-stack) [...] /stack[1] (pnv-phb4-pec-stack) [...] /stack[2] (pnv-phb4-pec-stack) [...] Cc: Cédric Le Goater Cc: David Gibson Cc: qemu-ppc@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Greg Kurz Reviewed-by: Cédric Le Goater Message-Id: <20200609122339.937862-12-armbru@redhat.com> --- hw/pci-host/pnv_phb4_pec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index 911d147ffd..565345a018 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -397,6 +397,9 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp) return; } } + for (; i < PHB4_PEC_MAX_STACKS; i++) { + object_unparent(OBJECT(&pec->stacks[i])); + } /* Initialize the XSCOM regions for the PEC registers */ snprintf(name, sizeof(name), "xscom-pec-%d.%d-nest", pec->chip_id, From 157ed954e2dc8c2a4230d38058ca7f1fe50902e0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:27 +0200 Subject: [PATCH 1213/2595] MAINTAINERS: Make section PowerNV cover pci-host/pnv* as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Cédric Le Goater Cc: David Gibson Cc: qemu-ppc@nongnu.org Signed-off-by: Markus Armbruster Acked-by: David Gibson Message-Id: <20200609122339.937862-13-armbru@redhat.com> --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a922775e45..de25c82249 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1218,7 +1218,9 @@ S: Maintained F: hw/ppc/pnv* F: hw/intc/pnv* F: hw/intc/xics_pnv.c +F: hw/pci-host/pnv* F: include/hw/ppc/pnv* +F: include/hw/pci-host/pnv* F: pc-bios/skiboot.lid F: tests/qtest/pnv* From b15fe4a018a019707793c178cba05ee5600389f6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:28 +0200 Subject: [PATCH 1214/2595] ppc4xx: Drop redundant device realization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit object_property_set_bool(OBJECT(dev), true, "realized", ...) right after qdev_init_nofail(dev) does nothing, because qdev_init_nofail() already realizes. Drop. Cc: BALATON Zoltan Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: BALATON Zoltan Reviewed-by: Thomas Huth Message-Id: <20200609122339.937862-14-armbru@redhat.com> --- hw/ppc/ppc440_uc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index b30e093cbb..dc318c7aa7 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -1370,12 +1370,10 @@ void ppc460ex_pcie_init(CPUPPCState *env) dev = qdev_create(NULL, TYPE_PPC460EX_PCIE_HOST); qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE0_BASE); qdev_init_nofail(dev); - object_property_set_bool(OBJECT(dev), true, "realized", NULL); ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env); dev = qdev_create(NULL, TYPE_PPC460EX_PCIE_HOST); qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE1_BASE); qdev_init_nofail(dev); - object_property_set_bool(OBJECT(dev), true, "realized", NULL); ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env); } From 514db7710bf59c2c6d3c5046f5b52e54829fcbc0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:29 +0200 Subject: [PATCH 1215/2595] macio: Put "macio-nvram" device on the macio bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macio_oldworld_init() creates a "macio-nvram", sysbus device, but neglects to but it on a bus. Put it on the macio bus. Affects machine g3beige. Visible in "info qtree": bus: macio.0 type macio-bus [...] + dev: macio-nvram, id "" + size = 8192 (0x2000) + it_shift = 4 (0x4) This also makes it a QOM child of macio-oldworld. Visible in "info qom-tree": /machine (g3beige-machine) [...] /unattached (container) [...] /device[6] (macio-oldworld) [...] - /device[7] (macio-nvram) - /macio-nvram[0] (qemu:memory-region) + /nvram (macio-nvram) + /macio-nvram[0] (qemu:memory-region) [rest of device[*] renumbered...] Cc: Mark Cave-Ayland Cc: David Gibson Cc: qemu-ppc@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200609122339.937862-15-armbru@redhat.com> --- hw/misc/macio/macio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index b3dddf8be7..ebc96cc8f6 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -245,7 +245,8 @@ static void macio_oldworld_init(Object *obj) macio_init_child_obj(s, "cuda", &s->cuda, sizeof(s->cuda), TYPE_CUDA); - object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM); + macio_init_child_obj(s, "nvram", &os->nvram, sizeof(os->nvram), + TYPE_MACIO_NVRAM); dev = DEVICE(&os->nvram); qdev_prop_set_uint32(dev, "size", 0x2000); qdev_prop_set_uint32(dev, "it_shift", 4); From 6741a3430b59cfbdb97a2194dcc16a4fedce486d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:30 +0200 Subject: [PATCH 1216/2595] macio: Fix macio-bus to be a subtype of System bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The devices we plug into the macio-bus are all sysbus devices (DeviceClass member bus_type is TYPE_SYSTEM_BUS), but macio-bus does not derive from TYPE_SYSTEM_BUS. Fix that. "info qtree" now shows the devices' mmio ranges, as it should Cc: Mark Cave-Ayland Cc: David Gibson Cc: qemu-ppc@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200609122339.937862-16-armbru@redhat.com> --- hw/misc/macio/macio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index ebc96cc8f6..53a9fd5696 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -492,7 +492,7 @@ static void macio_class_init(ObjectClass *klass, void *data) static const TypeInfo macio_bus_info = { .name = TYPE_MACIO_BUS, - .parent = TYPE_BUS, + .parent = TYPE_SYSTEM_BUS, .instance_size = sizeof(MacIOBusState), }; From 9354eaaf16fdb98651574f131ff66ad974e50bba Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:31 +0200 Subject: [PATCH 1217/2595] ppc/pnv: Put "*-pnv-chip" and "pnv-xive" on the main system bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pnv_init() creates "power10_v1.0-pnv-chip", "power8_v2.0-pnv-chip", "power8e_v2.1-pnv-chip", "power8nvl_v1.0-pnv-chip", or "power9_v2.0-pnv-chip" sysbus devices in a way that leaves them unplugged. pnv_chip_power9_instance_init() creates a "pnv-xive" sysbus device in a way that leaves it unplugged. Create them the common way that puts them into the main system bus. Affects machines powernv8, powernv9, and powernv10. Visible in "info qtree". Here's the change for powernv9: bus: main-system-bus type System + dev: power9_v2.0-pnv-chip, id "" + chip-id = 0 (0x0) + ram-start = 0 (0x0) + ram-size = 1879048192 (0x70000000) + nr-cores = 1 (0x1) + cores-mask = 72057594037927935 (0xffffffffffffff) + nr-threads = 1 (0x1) + num-phbs = 6 (0x6) + mmio 000603fc00000000/0000000400000000 [...] + dev: pnv-xive, id "" + ic-bar = 1692157036462080 (0x6030203100000) + vc-bar = 1689949371891712 (0x6010000000000) + pc-bar = 1690499127705600 (0x6018000000000) + tm-bar = 1692157036986368 (0x6030203180000) Cc: "Cédric Le Goater" Cc: David Gibson Cc: qemu-ppc@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Cédric Le Goater Message-Id: <20200609122339.937862-17-armbru@redhat.com> --- hw/ppc/pnv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 806a5d9a8d..9d1a11adb7 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -818,7 +818,7 @@ static void pnv_init(MachineState *machine) pnv->chips = g_new0(PnvChip *, pnv->num_chips); for (i = 0; i < pnv->num_chips; i++) { char chip_name[32]; - Object *chip = object_new(chip_typename); + Object *chip = OBJECT(qdev_create(NULL, chip_typename)); pnv->chips[i] = PNV_CHIP(chip); @@ -1317,8 +1317,8 @@ static void pnv_chip_power9_instance_init(Object *obj) PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj); int i; - object_initialize_child(obj, "xive", &chip9->xive, sizeof(chip9->xive), - TYPE_PNV_XIVE, &error_abort, NULL); + sysbus_init_child_obj(obj, "xive", &chip9->xive, sizeof(chip9->xive), + TYPE_PNV_XIVE); object_property_add_alias(obj, "xive-fabric", OBJECT(&chip9->xive), "xive-fabric"); From 2f35254aa0403ed527fc8ec379e5f7fdf2184e85 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:32 +0200 Subject: [PATCH 1218/2595] pnv/psi: Correct the pnv-psi* devices not to be sysbus devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pnv_chip_power8_instance_init() creates a "pnv-psi-POWER8" sysbus device in a way that leaves it unplugged. pnv_chip_power9_instance_init() and pnv_chip_power10_instance_init() do the same for "pnv-psi-POWER9" and "pnv-psi-POWER10", respectively. These devices aren't actually sysbus devices. Correct that. Cc: "Cédric Le Goater" Cc: David Gibson Cc: qemu-ppc@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Cédric Le Goater Message-Id: <20200609122339.937862-18-armbru@redhat.com> --- hw/ppc/pnv_psi.c | 2 +- include/hw/ppc/pnv_psi.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index cfd5b7bc25..82f0769465 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -943,7 +943,7 @@ static void pnv_psi_class_init(ObjectClass *klass, void *data) static const TypeInfo pnv_psi_info = { .name = TYPE_PNV_PSI, - .parent = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_DEVICE, .instance_size = sizeof(PnvPsi), .class_init = pnv_psi_class_init, .class_size = sizeof(PnvPsiClass), diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h index f0f5b55197..979fc59f33 100644 --- a/include/hw/ppc/pnv_psi.h +++ b/include/hw/ppc/pnv_psi.h @@ -31,7 +31,7 @@ #define PSIHB_XSCOM_MAX 0x20 typedef struct PnvPsi { - SysBusDevice parent; + DeviceState parent; MemoryRegion regs_mr; uint64_t bar; From 734a5914333ea81e4809699a8539de63a66f0d4c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:33 +0200 Subject: [PATCH 1219/2595] display/sm501 display/ati: Fix to realize "i2c-ddc" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sm501_init() and ati_vga_realize() create an "i2c-ddc" device, but neglect to realize it. Affects machines sam460ex, shix, r2d, and fulong2e. In theory, a device becomes real only on realize. In practice, the transition from unreal to real is a fuzzy one. The work to make a device real can be spread between realize methods (fine), instance_init methods (wrong), and board code wiring up the device (fine as long as it effectively happens on realize). Depending on what exactly is done where, a device can work even when we neglect to realize it. This one appears to work. Nevertheless, it's a clear misuse of the interface. Even when it works today (more or less by chance), it can break tomorrow. Fix by realizing it right away. Visible in "info qom-tree"; here's the change for sam460ex: /machine (sam460ex-machine) [...] /unattached (container) [...] - /device[14] (sii3112) + /device[14] (i2c-ddc) + /device[15] (sii3112) [rest of device[*] renumbered...] Fixes: 4a1f253adb45ac6019971193d5077c4d5d55886a Fixes: c82c7336de58876862e6b4dccbda29e9240fd388 Cc: BALATON Zoltan Cc: qemu-ppc@nongnu.org Cc: Magnus Damm Cc: Philippe Mathieu-Daudé Cc: Aleksandar Markovic Signed-off-by: Markus Armbruster Tested-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200609122339.937862-19-armbru@redhat.com> --- hw/display/ati.c | 2 ++ hw/display/sm501.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hw/display/ati.c b/hw/display/ati.c index 67604e68de..1d9df92b96 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -935,6 +935,8 @@ static void ati_vga_realize(PCIDevice *dev, Error **errp) bitbang_i2c_init(&s->bbi2c, i2cbus); I2CSlave *i2cddc = I2C_SLAVE(qdev_create(BUS(i2cbus), TYPE_I2CDDC)); i2c_set_slave_address(i2cddc, 0x50); + object_property_set_bool(OBJECT(i2cddc), true, "realized", + &error_abort); /* mmio register space */ memory_region_init_io(&s->mm, OBJECT(s), &ati_mm_ops, s, diff --git a/hw/display/sm501.c b/hw/display/sm501.c index edd8d24a76..fa23a78164 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1833,6 +1833,8 @@ static void sm501_init(SM501State *s, DeviceState *dev, /* ddc */ I2CDDCState *ddc = I2CDDC(qdev_create(BUS(s->i2c_bus), TYPE_I2CDDC)); i2c_set_slave_address(I2C_SLAVE(ddc), 0x50); + object_property_set_bool(OBJECT(ddc), true, "realized", + &error_abort); /* mmio */ memory_region_init(&s->mmio_region, OBJECT(dev), "sm501.mmio", MMIO_SIZE); From 75a6ed875ff0a2eb6b2971ae2098ed09963d7329 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:34 +0200 Subject: [PATCH 1220/2595] riscv: Fix to put "riscv.hart_array" devices on sysbus riscv_sifive_e_soc_init(), riscv_sifive_u_soc_init(), spike_board_init(), spike_v1_10_0_board_init(), spike_v1_09_1_board_init(), and riscv_virt_board_init() create "riscv-hart_array" sysbus devices in a way that leaves them unplugged. Create them the common way that puts them into the main system bus. Affects machines sifive_e, sifive_u, spike, spike_v1.10, spike_v1.9.1, and virt. Visible in "info qtree", here's the change for sifive_e: bus: main-system-bus type System + dev: riscv.hart_array, id "" + num-harts = 1 (0x1) + hartid-base = 0 (0x0) + cpu-type = "sifive-e31-riscv-cpu" dev: sifive_soc.gpio, id "" Cc: Palmer Dabbelt Cc: Alistair Francis Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: qemu-riscv@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Alistair Francis Message-Id: <20200609122339.937862-20-armbru@redhat.com> --- hw/riscv/opentitan.c | 5 ++--- hw/riscv/sifive_e.c | 5 ++--- hw/riscv/sifive_u.c | 14 ++++++-------- hw/riscv/spike.c | 4 ++-- hw/riscv/virt.c | 4 ++-- 5 files changed, 14 insertions(+), 18 deletions(-) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index b4fb836466..29887fe363 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -94,9 +94,8 @@ static void riscv_lowrisc_ibex_soc_init(Object *obj) { LowRISCIbexSoCState *s = RISCV_IBEX_SOC(obj); - object_initialize_child(obj, "cpus", &s->cpus, - sizeof(s->cpus), TYPE_RISCV_HART_ARRAY, - &error_abort, NULL); + sysbus_init_child_obj(obj, "cpus", &s->cpus, + sizeof(s->cpus), TYPE_RISCV_HART_ARRAY); } static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 472a98970b..d2e2350a4d 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -149,9 +149,8 @@ static void riscv_sifive_e_soc_init(Object *obj) MachineState *ms = MACHINE(qdev_get_machine()); SiFiveESoCState *s = RISCV_E_SOC(obj); - object_initialize_child(obj, "cpus", &s->cpus, - sizeof(s->cpus), TYPE_RISCV_HART_ARRAY, - &error_abort, NULL); + sysbus_init_child_obj(obj, "cpus", &s->cpus, + sizeof(s->cpus), TYPE_RISCV_HART_ARRAY); object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts", &error_abort); sysbus_init_child_obj(obj, "riscv.sifive.e.gpio0", diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index f9fef2be91..d6c6364596 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -491,10 +491,9 @@ static void sifive_u_soc_instance_init(Object *obj) &error_abort, NULL); qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0); - object_initialize_child(OBJECT(&s->e_cluster), "e-cpus", - &s->e_cpus, sizeof(s->e_cpus), - TYPE_RISCV_HART_ARRAY, &error_abort, - NULL); + sysbus_init_child_obj(OBJECT(&s->e_cluster), "e-cpus", + &s->e_cpus, sizeof(s->e_cpus), + TYPE_RISCV_HART_ARRAY); qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1); qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0); qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type", SIFIVE_E_CPU); @@ -504,10 +503,9 @@ static void sifive_u_soc_instance_init(Object *obj) &error_abort, NULL); qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1); - object_initialize_child(OBJECT(&s->u_cluster), "u-cpus", - &s->u_cpus, sizeof(s->u_cpus), - TYPE_RISCV_HART_ARRAY, &error_abort, - NULL); + sysbus_init_child_obj(OBJECT(&s->u_cluster), "u-cpus", + &s->u_cpus, sizeof(s->u_cpus), + TYPE_RISCV_HART_ARRAY); qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1); qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1); qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", SIFIVE_U_CPU); diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 7bbbdb5036..7d1119dcb6 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -169,8 +169,8 @@ static void spike_board_init(MachineState *machine) unsigned int smp_cpus = machine->smp.cpus; /* Initialize SOC */ - object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), - TYPE_RISCV_HART_ARRAY, &error_abort, NULL); + sysbus_init_child_obj(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), + TYPE_RISCV_HART_ARRAY); object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type", &error_abort); object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts", diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 4e4c494a70..d569b38d1b 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -485,8 +485,8 @@ static void virt_machine_init(MachineState *machine) unsigned int smp_cpus = machine->smp.cpus; /* Initialize SOC */ - object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), - TYPE_RISCV_HART_ARRAY, &error_abort, NULL); + sysbus_init_child_obj(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), + TYPE_RISCV_HART_ARRAY); object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type", &error_abort); object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts", From 589b1be07c060e583d9f758ff0cb10e0f1ff242f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:35 +0200 Subject: [PATCH 1221/2595] riscv: Fix type of SiFive[EU]SocState, member parent_obj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Device "riscv.sifive.e.soc" is a direct subtype of TYPE_DEVICE, but its instance struct SiFiveESoCState's member @parent_obj is SysBusDevice instead of DeviceState. Correct that. Same for "riscv.sifive.u.soc"'s instance struct SiFiveUSoCState. Cc: Palmer Dabbelt Cc: Alistair Francis Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: qemu-riscv@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20200609122339.937862-21-armbru@redhat.com> --- include/hw/riscv/sifive_e.h | 2 +- include/hw/riscv/sifive_u.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h index 414992119e..d386ea9223 100644 --- a/include/hw/riscv/sifive_e.h +++ b/include/hw/riscv/sifive_e.h @@ -29,7 +29,7 @@ typedef struct SiFiveESoCState { /*< private >*/ - SysBusDevice parent_obj; + DeviceState parent_obj; /*< public >*/ RISCVHartArrayState cpus; diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index 16c297ec5f..5f62cf5f85 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -31,7 +31,7 @@ typedef struct SiFiveUSoCState { /*< private >*/ - SysBusDevice parent_obj; + DeviceState parent_obj; /*< public >*/ CPUClusterState e_cluster; From d6b78ac8ecf94f56dbfbecc23fb4365d8772a41a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:36 +0200 Subject: [PATCH 1222/2595] sparc/leon3: Fix to put grlib,* devices on sysbus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit leon3_generic_hw_init() creates a "grlib,ahbpnp" and a "grlib,apbpnp" sysbus device in a way that leaves them unplugged. Create them the common way that puts them into the main system bus. Affects machine leon3_generic. Visible in "info qtree": bus: main-system-bus type System + dev: grlib,ahbpnp, id "" + mmio 00000000fffff000/0000000000001000 + dev: grlib,apbpnp, id "" + mmio 00000000800ff000/0000000000001000 dev: grlib,irqmp, id "" Cc: Fabien Chouteau Cc: KONRAD Frederic Cc: Mark Cave-Ayland Cc: Artyom Tarasenko Signed-off-by: Markus Armbruster Reviewed-by: KONRAD Frederic Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200609122339.937862-22-armbru@redhat.com> Acked-by: Artyom Tarasenko --- hw/sparc/leon3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index cc55117dec..d3ab8c9400 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -213,14 +213,14 @@ static void leon3_generic_hw_init(MachineState *machine) reset_info->sp = LEON3_RAM_OFFSET + ram_size; qemu_register_reset(main_cpu_reset, reset_info); - ahb_pnp = GRLIB_AHB_PNP(object_new(TYPE_GRLIB_AHB_PNP)); + ahb_pnp = GRLIB_AHB_PNP(qdev_create(NULL, TYPE_GRLIB_AHB_PNP)); object_property_set_bool(OBJECT(ahb_pnp), true, "realized", &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(ahb_pnp), 0, LEON3_AHB_PNP_OFFSET); grlib_ahb_pnp_add_entry(ahb_pnp, 0, 0, GRLIB_VENDOR_GAISLER, GRLIB_LEON3_DEV, GRLIB_AHB_MASTER, GRLIB_CPU_AREA); - apb_pnp = GRLIB_APB_PNP(object_new(TYPE_GRLIB_APB_PNP)); + apb_pnp = GRLIB_APB_PNP(qdev_create(NULL, TYPE_GRLIB_APB_PNP)); object_property_set_bool(OBJECT(apb_pnp), true, "realized", &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(apb_pnp), 0, LEON3_APB_PNP_OFFSET); grlib_ahb_pnp_add_entry(ahb_pnp, LEON3_APB_PNP_OFFSET, 0xFFF, From 81cb05732efb36971901c515b007869cc1d3a532 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:37 +0200 Subject: [PATCH 1223/2595] qdev: Assert devices are plugged into a bus that can take them This would have caught some of the bugs I just fixed. Signed-off-by: Markus Armbruster Reviewed-by: Mark Cave-Ayland Message-Id: <20200609122339.937862-23-armbru@redhat.com> --- hw/core/qdev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 9e5538aeae..b5b42b2616 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -97,6 +97,9 @@ static void bus_add_child(BusState *bus, DeviceState *child) void qdev_set_parent_bus(DeviceState *dev, BusState *bus) { BusState *old_parent_bus = dev->parent_bus; + DeviceClass *dc = DEVICE_GET_CLASS(dev); + + assert(dc->bus_type && object_dynamic_cast(OBJECT(bus), dc->bus_type)); if (old_parent_bus) { trace_qdev_update_parent_bus(dev, object_get_typename(OBJECT(dev)), From 007d1dbf72536ec1b847a944832e4de1546af2ac Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:38 +0200 Subject: [PATCH 1224/2595] sd: Hide the qdev-but-not-quite thing created by sd_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 260bc9d8aa "hw/sd/sd.c: QOMify" QOMified only the device itself, not its users. It kept sd_init() around for non-QOMified users. More than four years later, three such users remain: omap1 (machines cheetah, sx1, sx1-v1) and omap2 (machines n800, n810) are not QOMified, and pl181 (machines integratorcp, realview-eb, realview-eb-mpcore, realview-pb-a8 realview-pbx-a9, versatileab, versatilepb, vexpress-a15, vexpress-a9) is not QOMified properly. The issue I presently have with this: an "sd-card" device should plug into an "sd-bus" (its DeviceClass member bus_type says so), but sd_init() leaves it unplugged. This is normally a bug (I just fixed some instances), and I'd like to assert proper pluggedness to prevent regressions. However, the qdev-but-not-quite thing returned by sd_init() would fail the assertion. Meh. Make sd_init() hide it from QOM/qdev. Visible in "info qom-tree", here's the change for cheetah: /machine (cheetah-machine) [...] /unattached (container) [...] /device[5] (serial-mm) /serial (serial) /serial[0] (qemu:memory-region) - /device[6] (sd-card) - /device[7] (omap-gpio) + /device[6] (omap-gpio) [rest of device[*] renumbered...] Cc: "Philippe Mathieu-Daudé" Signed-off-by: Markus Armbruster Message-Id: <20200609122339.937862-24-armbru@redhat.com> --- hw/sd/sd.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 3c06a0ac6d..7070a116ea 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -83,6 +83,10 @@ enum SDCardStates { struct SDState { DeviceState parent_obj; + /* If true, created by sd_init() for a non-qdevified caller */ + /* TODO purge them with fire */ + bool me_no_qdev_me_kill_mammoth_with_rocks; + /* SD Memory Card Registers */ uint32_t ocr; uint8_t scr[8]; @@ -129,6 +133,8 @@ struct SDState { bool cmd_line; }; +static void sd_realize(DeviceState *dev, Error **errp); + static const char *sd_state_name(enum SDCardStates state) { static const char *state_name[] = { @@ -590,7 +596,7 @@ static void sd_cardchange(void *opaque, bool load, Error **errp) { SDState *sd = opaque; DeviceState *dev = DEVICE(sd); - SDBus *sdbus = SD_BUS(qdev_get_parent_bus(dev)); + SDBus *sdbus; bool inserted = sd_get_inserted(sd); bool readonly = sd_get_readonly(sd); @@ -601,19 +607,17 @@ static void sd_cardchange(void *opaque, bool load, Error **errp) trace_sdcard_ejected(); } - /* The IRQ notification is for legacy non-QOM SD controller devices; - * QOMified controllers use the SDBus APIs. - */ - if (sdbus) { - sdbus_set_inserted(sdbus, inserted); - if (inserted) { - sdbus_set_readonly(sdbus, readonly); - } - } else { + if (sd->me_no_qdev_me_kill_mammoth_with_rocks) { qemu_set_irq(sd->inserted_cb, inserted); if (inserted) { qemu_set_irq(sd->readonly_cb, readonly); } + } else { + sdbus = SD_BUS(qdev_get_parent_bus(dev)); + sdbus_set_inserted(sdbus, inserted); + if (inserted) { + sdbus_set_readonly(sdbus, readonly); + } } } @@ -697,6 +701,7 @@ SDState *sd_init(BlockBackend *blk, bool is_spi) { Object *obj; DeviceState *dev; + SDState *sd; Error *err = NULL; obj = object_new(TYPE_SD_CARD); @@ -707,13 +712,24 @@ SDState *sd_init(BlockBackend *blk, bool is_spi) return NULL; } qdev_prop_set_bit(dev, "spi", is_spi); - object_property_set_bool(obj, true, "realized", &err); + + /* + * Realizing the device properly would put it into the QOM + * composition tree even though it is not plugged into an + * appropriate bus. That's a no-no. Hide the device from + * QOM/qdev, and call its qdev realize callback directly. + */ + object_ref(obj); + object_unparent(obj); + sd_realize(dev, &err); if (err) { error_reportf_err(err, "sd_init failed: "); return NULL; } - return SD_CARD(dev); + sd = SD_CARD(dev); + sd->me_no_qdev_me_kill_mammoth_with_rocks = true; + return sd; } void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert) From dfe8c79c44680e34eac2e8abd0d0c885ce01aa55 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 9 Jun 2020 14:23:39 +0200 Subject: [PATCH 1225/2595] qdev: Assert onboard devices all get realized properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This would have caught some of the bugs I just fixed. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200609122339.937862-25-armbru@redhat.com> --- hw/core/qdev.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index b5b42b2616..a68ba674db 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -427,6 +427,19 @@ void qdev_init_nofail(DeviceState *dev) object_unref(OBJECT(dev)); } +static int qdev_assert_realized_properly(Object *obj, void *opaque) +{ + DeviceState *dev = DEVICE(object_dynamic_cast(obj, TYPE_DEVICE)); + DeviceClass *dc; + + if (dev) { + dc = DEVICE_GET_CLASS(dev); + assert(dev->realized); + assert(dev->parent_bus || !dc->bus_type); + } + return 0; +} + void qdev_machine_creation_done(void) { /* @@ -434,6 +447,9 @@ void qdev_machine_creation_done(void) * only create hotpluggable devices */ qdev_hotplug = true; + + object_child_foreach_recursive(object_get_root(), + qdev_assert_realized_properly, NULL); } bool qdev_machine_modified(void) From 30884d1b837fb09f9dba3a770325e228ec2335b4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:31:50 +0200 Subject: [PATCH 1226/2595] qdev: Rename qbus_realize() to qbus_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qbus_realize() does not actually realize. Rename it to qbus_init(). Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-2-armbru@redhat.com> --- hw/core/bus.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/core/bus.c b/hw/core/bus.c index 50924793ac..33a4443217 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -95,7 +95,7 @@ static void bus_reset_child_foreach(Object *obj, ResettableChildCallback cb, } } -static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) +static void qbus_init(BusState *bus, DeviceState *parent, const char *name) { const char *typename = object_get_typename(OBJECT(bus)); BusClass *bc; @@ -151,7 +151,7 @@ void qbus_create_inplace(void *bus, size_t size, const char *typename, DeviceState *parent, const char *name) { object_initialize(bus, size, typename); - qbus_realize(bus, parent, name); + qbus_init(bus, parent, name); } BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) @@ -159,7 +159,7 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam BusState *bus; bus = BUS(object_new(typename)); - qbus_realize(bus, parent, name); + qbus_init(bus, parent, name); return bus; } From 9e1b990c2ee6e1b14f9abdf5ab325ff2cf9d8bd5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:31:51 +0200 Subject: [PATCH 1227/2595] Revert "hw/prep: realize the PCI root bus as part of the prep init" This reverts commit 685f9a3428f625f580af0123aa95f4838d86cac3. Realizing a device automatically realizes its buses, in device_set_realized(). Realizing them in realize methods is redundant, unless the methods themselves require them to be realized early. raven_pcihost_realizefn() doesn't. Drop the redundant bus realization. Cc: Marcel Apfelbaum Cc: Michael S. Tsirkin Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-3-armbru@redhat.com> --- hw/pci-host/prep.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c index 88e2fc66a9..fc01a294a4 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -268,7 +268,6 @@ static void raven_pcihost_realizefn(DeviceState *d, Error **errp) memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->pci_intack); /* TODO Remove once realize propagates to child devices. */ - object_property_set_bool(OBJECT(&s->pci_bus), true, "realized", errp); object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp); } From da9630c57ee386f8beb571ba6bb4a98d546c42ca Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:31:52 +0200 Subject: [PATCH 1228/2595] Revert "hw/versatile: realize the PCI root bus as part of the versatile init" This reverts commit b1af7959a66610669e1a019b9a84f6ed3a7936c6. Realizing a device automatically realizes its buses, in device_set_realized(). Realizing them in realize methods is redundant, unless the methods themselves require them to be realized early. pci_vpb_realize() doesn't. Drop the redundant bus realization. Cc: Marcel Apfelbaum Cc: Michael S. Tsirkin Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-4-armbru@redhat.com> --- hw/pci-host/versatile.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c index 8ddfb8772a..ea7390c6fa 100644 --- a/hw/pci-host/versatile.c +++ b/hw/pci-host/versatile.c @@ -459,7 +459,6 @@ static void pci_vpb_realize(DeviceState *dev, Error **errp) } /* TODO Remove once realize propagates to child devices. */ - object_property_set_bool(OBJECT(&s->pci_bus), true, "realized", errp); object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp); } From 9940b2cfbc05cdffdf6b42227a80cb1e6d2a85c2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:31:53 +0200 Subject: [PATCH 1229/2595] qdev: New qdev_new(), qdev_realize(), etc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We commonly plug devices into their bus right when we create them, like this: dev = qdev_create(bus, type_name); Note that @dev is a weak reference. The reference from @bus to @dev is the only strong one. We realize at some later time, either with object_property_set_bool(OBJECT(dev), true, "realized", errp); or its convenience wrapper qdev_init_nofail(dev); If @dev still has no QOM parent then, realizing makes the /machine/unattached/ orphanage its QOM parent. Note that the device returned by qdev_create() is plugged into a bus, but doesn't have a QOM parent, yet. Until it acquires one, unrealizing the bus will hang in bus_unparent(): while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { DeviceState *dev = kid->child; object_unparent(OBJECT(dev)); } object_unparent() does nothing when its argument has no QOM parent, and the loop spins forever. Device state "no QOM parent, but plugged into bus" is dangerous. Paolo suggested to delay plugging into the bus until realize. We need to plug into the parent bus before we call the device's realize method, in case it uses the parent bus. So the dangerous state still exists, but only within realization, where we can manage it safely. This commit creates infrastructure to do this: dev = qdev_new(type_name); ... qdev_realize_and_unref(dev, bus, errp) Note that @dev becomes a strong reference here. qdev_realize_and_unref() drops it. There is also plain qdev_realize(), which doesn't drop it. The remainder of this series will convert all users to this new interface. Cc: Michael S. Tsirkin Cc: Marcel Apfelbaum Cc: Alistair Francis Cc: Gerd Hoffmann Cc: Mark Cave-Ayland Cc: David Gibson Signed-off-by: Markus Armbruster Acked-by: Gerd Hoffmann Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-5-armbru@redhat.com> --- hw/core/bus.c | 14 +++++++ hw/core/qdev.c | 90 ++++++++++++++++++++++++++++++++++++++++++ include/hw/qdev-core.h | 11 +++++- 3 files changed, 114 insertions(+), 1 deletion(-) diff --git a/hw/core/bus.c b/hw/core/bus.c index 33a4443217..6f6071f5fa 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -164,6 +164,20 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam return bus; } +bool qbus_realize(BusState *bus, Error **errp) +{ + Error *err = NULL; + + object_property_set_bool(OBJECT(bus), true, "realized", &err); + error_propagate(errp, err); + return !err; +} + +void qbus_unrealize(BusState *bus) +{ + object_property_set_bool(OBJECT(bus), false, "realized", &error_abort); +} + static bool bus_get_realized(Object *obj, Error **errp) { BusState *bus = BUS(obj); diff --git a/hw/core/qdev.c b/hw/core/qdev.c index a68ba674db..f2c5cee278 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -176,6 +176,32 @@ DeviceState *qdev_try_create(BusState *bus, const char *type) return dev; } +/* + * Create a device on the heap. + * A type @name must exist. + * This only initializes the device state structure and allows + * properties to be set. The device still needs to be realized. See + * qdev-core.h. + */ +DeviceState *qdev_new(const char *name) +{ + return DEVICE(object_new(name)); +} + +/* + * Try to create a device on the heap. + * This is like qdev_new(), except it returns %NULL when type @name + * does not exist. + */ +DeviceState *qdev_try_new(const char *name) +{ + if (!object_class_by_name(name)) { + return NULL; + } + + return DEVICE(object_new(name)); +} + static QTAILQ_HEAD(, DeviceListener) device_listeners = QTAILQ_HEAD_INITIALIZER(device_listeners); @@ -427,6 +453,66 @@ void qdev_init_nofail(DeviceState *dev) object_unref(OBJECT(dev)); } +/* + * Realize @dev. + * @dev must not be plugged into a bus. + * Plug @dev into @bus if non-null, else into the main system bus. + * This takes a reference to @dev. + * If @dev has no QOM parent, make one up, taking another reference. + * On success, return true. + * On failure, store an error through @errp and return false. + */ +bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) +{ + Error *err = NULL; + + assert(!dev->realized && !dev->parent_bus); + + if (!bus) { + /* + * Assert that the device really is a SysBusDevice before we + * put it onto the sysbus. Non-sysbus devices which aren't + * being put onto a bus should be realized with + * object_property_set_bool(OBJECT(dev), true, "realized", + * errp); + */ + g_assert(object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)); + bus = sysbus_get_default(); + } + + qdev_set_parent_bus(dev, bus); + + object_property_set_bool(OBJECT(dev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } + return !err; +} + +/* + * Realize @dev and drop a reference. + * This is like qdev_realize(), except the caller must hold a + * (private) reference, which is dropped on return regardless of + * success or failure. Intended use: + * dev = qdev_new(); + * [...] + * qdev_realize_and_unref(dev, bus, errp); + * Now @dev can go away without further ado. + */ +bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp) +{ + bool ret; + + ret = qdev_realize(dev, bus, errp); + object_unref(OBJECT(dev)); + return ret; +} + +void qdev_unrealize(DeviceState *dev) +{ + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); +} + static int qdev_assert_realized_properly(Object *obj, void *opaque) { DeviceState *dev = DEVICE(object_dynamic_cast(obj, TYPE_DEVICE)); @@ -1002,6 +1088,10 @@ post_realize_fail: fail: error_propagate(errp, local_err); if (unattached_parent) { + /* + * Beware, this doesn't just revert + * object_property_add_child(), it also runs bus_remove()! + */ object_unparent(OBJECT(dev)); unattached_count--; } diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index b870b27966..fba29308f7 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -57,7 +57,7 @@ typedef void (*BusUnrealize)(BusState *bus); * After successful realization, setting static properties will fail. * * As an interim step, the #DeviceState:realized property can also be - * set with qdev_init_nofail(). + * set with qdev_realize() or qdev_init_nofail(). * In the future, devices will propagate this state change to their children * and along busses they expose. * The point in time will be deferred to machine creation, so that values @@ -322,7 +322,13 @@ compat_props_add(GPtrArray *arr, DeviceState *qdev_create(BusState *bus, const char *name); DeviceState *qdev_try_create(BusState *bus, const char *name); +DeviceState *qdev_new(const char *name); +DeviceState *qdev_try_new(const char *name); void qdev_init_nofail(DeviceState *dev); +bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp); +bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp); +void qdev_unrealize(DeviceState *dev); + void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, int required_for_version); HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev); @@ -411,6 +417,9 @@ typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque); void qbus_create_inplace(void *bus, size_t size, const char *typename, DeviceState *parent, const char *name); BusState *qbus_create(const char *typename, DeviceState *parent, const char *name); +bool qbus_realize(BusState *bus, Error **errp); +void qbus_unrealize(BusState *bus); + /* Returns > 0 if either devfn or busfn skip walk somewhere in cursion, * < 0 if either devfn or busfn terminate walk somewhere in cursion, * 0 otherwise. */ From 4e3a6778b0db1798afd696759cee28575f598ca8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:31:54 +0200 Subject: [PATCH 1230/2595] qdev: Put qdev_new() to use with Coccinelle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's start simple and put qdev_new() to use. Coccinelle script: @ depends on !(file in "hw/core/qdev.c")@ expression type_name; @@ - DEVICE(object_new(type_name)) + qdev_new(type_name) Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-6-armbru@redhat.com> --- hw/block/nand.c | 2 +- hw/misc/auxbus.c | 2 +- qdev-monitor.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/block/nand.c b/hw/block/nand.c index bba89688ba..cdf3429ce6 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -644,7 +644,7 @@ DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id) if (nand_flash_ids[chip_id].size == 0) { hw_error("%s: Unsupported NAND chip ID.\n", __func__); } - dev = DEVICE(object_new(TYPE_NAND)); + dev = qdev_new(TYPE_NAND); qdev_prop_set_uint8(dev, "manufacturer_id", manf_id); qdev_prop_set_uint8(dev, "chip_id", chip_id); if (blk) { diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index 80bc3a0777..c37d235b0e 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -273,7 +273,7 @@ DeviceState *aux_create_slave(AUXBus *bus, const char *type) { DeviceState *dev; - dev = DEVICE(object_new(type)); + dev = qdev_new(type); assert(dev); qdev_set_parent_bus(dev, &bus->qbus); return dev; diff --git a/qdev-monitor.c b/qdev-monitor.c index a4735d3bb1..20cfa7615b 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -652,7 +652,7 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) } /* create device */ - dev = DEVICE(object_new(driver)); + dev = qdev_new(driver); /* Check whether the hotplug is allowed by the machine */ if (qdev_hotplug && !qdev_hotplug_allowed(dev, &err)) { From f1483b466d7b607d45606a4287fea79380b7900d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:31:55 +0200 Subject: [PATCH 1231/2595] qdev: Convert to qbus_realize(), qbus_unrealize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm going to convert device realization to qdev_realize() with the help of Coccinelle. Convert bus realization to qbus_realize() first, to get it out of Coccinelle's way. Readability improves. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-7-armbru@redhat.com> --- hw/core/qdev.c | 10 +++------- hw/pci/pci.c | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index f2c5cee278..b7355fbcd0 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -1024,9 +1024,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) resettable_state_clear(&dev->reset); QLIST_FOREACH(bus, &dev->child_bus, sibling) { - object_property_set_bool(OBJECT(bus), true, "realized", - &local_err); - if (local_err != NULL) { + if (!qbus_realize(bus, errp)) { goto child_realize_fail; } } @@ -1051,8 +1049,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) } else if (!value && dev->realized) { QLIST_FOREACH(bus, &dev->child_bus, sibling) { - object_property_set_bool(OBJECT(bus), false, "realized", - &error_abort); + qbus_unrealize(bus); } if (qdev_get_vmsd(dev)) { vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev); @@ -1070,8 +1067,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) child_realize_fail: QLIST_FOREACH(bus, &dev->child_bus, sibling) { - object_property_set_bool(OBJECT(bus), false, "realized", - &error_abort); + qbus_unrealize(bus); } if (qdev_get_vmsd(dev)) { diff --git a/hw/pci/pci.c b/hw/pci/pci.c index a60cf3ae3b..955eb11a01 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -456,7 +456,7 @@ void pci_root_bus_cleanup(PCIBus *bus) { pci_bus_uninit(bus); /* the caller of the unplug hotplug handler will delete this device */ - object_property_set_bool(OBJECT(bus), false, "realized", &error_abort); + qbus_unrealize(BUS(bus)); } void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, From 981c3dcd948907f1127bc1d85b6e455dce687096 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:31:56 +0200 Subject: [PATCH 1232/2595] qdev: Convert to qdev_unrealize() with Coccinelle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For readability, and consistency with qbus_realize(). Coccinelle script: @ depends on !(file in "hw/core/qdev.c")@ typedef DeviceState; DeviceState *dev; symbol false, error_abort; @@ - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); @ depends on !(file in "hw/core/qdev.c") && !(file in "hw/core/bus.c")@ expression dev; symbol false, error_abort; @@ - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(DEVICE(dev)); Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-8-armbru@redhat.com> --- hw/acpi/pcihp.c | 2 +- hw/char/serial-pci-multi.c | 2 +- hw/char/serial-pci.c | 2 +- hw/core/bus.c | 3 +-- hw/i386/pc.c | 4 ++-- hw/pci/pcie.c | 2 +- hw/pci/shpc.c | 2 +- hw/ppc/spapr.c | 8 ++++---- hw/ppc/spapr_pci.c | 3 +-- hw/s390x/css-bridge.c | 2 +- hw/s390x/s390-pci-bus.c | 4 ++-- 11 files changed, 16 insertions(+), 18 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index d42906ea19..33ea2b76ae 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -266,7 +266,7 @@ void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, { trace_acpi_pci_unplug(PCI_SLOT(PCI_DEVICE(dev)->devfn), acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev)))); - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); } void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev, diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c index 5f9ccfcc93..23d0ebe2cd 100644 --- a/hw/char/serial-pci-multi.c +++ b/hw/char/serial-pci-multi.c @@ -56,7 +56,7 @@ static void multi_serial_pci_exit(PCIDevice *dev) for (i = 0; i < pci->ports; i++) { s = pci->state + i; - object_property_set_bool(OBJECT(s), false, "realized", &error_abort); + qdev_unrealize(DEVICE(s)); memory_region_del_subregion(&pci->iobar, &s->io); g_free(pci->name[i]); } diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index 37818db156..65eacfae0e 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -68,7 +68,7 @@ static void serial_pci_exit(PCIDevice *dev) PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); SerialState *s = &pci->state; - object_property_set_bool(OBJECT(s), false, "realized", &error_abort); + qdev_unrealize(DEVICE(s)); qemu_free_irq(s->irq); } diff --git a/hw/core/bus.c b/hw/core/bus.c index 6f6071f5fa..6cc28b334e 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -200,8 +200,7 @@ static void bus_set_realized(Object *obj, bool value, Error **errp) } else if (!value && bus->realized) { QTAILQ_FOREACH(kid, &bus->children, sibling) { DeviceState *dev = kid->child; - object_property_set_bool(OBJECT(dev), false, "realized", - &error_abort); + qdev_unrealize(dev); } if (bc->unrealize) { bc->unrealize(bus); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 143ac1c354..a5dd6252fa 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1386,7 +1386,7 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev, } pc_dimm_unplug(PC_DIMM(dev), MACHINE(pcms)); - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); out: error_propagate(errp, local_err); } @@ -1494,7 +1494,7 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev, found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL); found_cpu->cpu = NULL; - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); /* decrement the number of CPUs */ x86ms->boot_cpus--; diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 5b9c022d91..086d0dfceb 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -460,7 +460,7 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); } static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque) diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index b76d3d2c9a..99d65d5c4c 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -547,7 +547,7 @@ void shpc_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); } void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev, diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 3b1a5ed865..6a315c0dc8 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3671,7 +3671,7 @@ static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev)); pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev)); - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); spapr_pending_dimm_unplugs_remove(spapr, ds); } @@ -3764,7 +3764,7 @@ static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) assert(core_slot); core_slot->cpu = NULL; - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); } static @@ -4037,7 +4037,7 @@ void spapr_phb_release(DeviceState *dev) static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) { - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); } static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev, @@ -4073,7 +4073,7 @@ static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev { SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); object_unparent(OBJECT(dev)); spapr->tpm_proxy = NULL; } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 83f1453096..329002ac04 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1587,8 +1587,7 @@ static void spapr_pci_unplug(HotplugHandler *plug_handler, return; } - object_property_set_bool(OBJECT(plugged_dev), false, "realized", - &error_abort); + qdev_unrealize(plugged_dev); } static void spapr_pci_unplug_request(HotplugHandler *plug_handler, diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index 3f6aec6b6a..813bfc768a 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -54,7 +54,7 @@ static void ccw_device_unplug(HotplugHandler *hotplug_dev, css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); } static void virtual_css_bus_reset(BusState *qbus) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index c4a4259f0c..7a4bfb7383 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -1003,7 +1003,7 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, pbdev->fh, pbdev->fid); bus = pci_get_bus(pci_dev); devfn = pci_dev->devfn; - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); s390_pci_msix_free(pbdev); s390_pci_iommu_free(s, bus, devfn); @@ -1014,7 +1014,7 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, pbdev->fid = 0; QTAILQ_REMOVE(&s->zpci_devs, pbdev, link); g_hash_table_remove(s->zpci_table, &pbdev->idx); - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); } } From dc3edf8d8a544dbf21e1cb63339e42806470d5d9 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:31:57 +0200 Subject: [PATCH 1233/2595] qdev: Convert to qdev_unrealize() manually MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-9-armbru@redhat.com> --- hw/core/qdev.c | 4 ++-- include/hw/qdev-core.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index b7355fbcd0..4768244f31 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -421,7 +421,7 @@ static void device_reset_child_foreach(Object *obj, ResettableChildCallback cb, void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); + qdev_unrealize(dev); } /* @@ -1183,7 +1183,7 @@ static void device_unparent(Object *obj) BusState *bus; if (dev->realized) { - object_property_set_bool(obj, false, "realized", &error_abort); + qdev_unrealize(dev); } while (dev->num_child_bus) { bus = QLIST_FIRST(&dev->child_bus); diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index fba29308f7..be6f7c4736 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -328,7 +328,6 @@ void qdev_init_nofail(DeviceState *dev); bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp); bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp); void qdev_unrealize(DeviceState *dev); - void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, int required_for_version); HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev); From 3e80f6902c13f6edb6675c0f33edcbbf0163ec32 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:31:58 +0200 Subject: [PATCH 1234/2595] qdev: Convert uses of qdev_create() with Coccinelle This is the transformation explained in the commit before previous. Takes care of just one pattern that needs conversion. More to come in this series. Coccinelle script: @ depends on !(file in "hw/arm/highbank.c")@ expression bus, type_name, dev, expr; @@ - dev = qdev_create(bus, type_name); + dev = qdev_new(type_name); ... when != dev = expr - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, bus, &error_fatal); @@ expression bus, type_name, dev, expr; identifier DOWN; @@ - dev = DOWN(qdev_create(bus, type_name)); + dev = DOWN(qdev_new(type_name)); ... when != dev = expr - qdev_init_nofail(DEVICE(dev)); + qdev_realize_and_unref(DEVICE(dev), bus, &error_fatal); @@ expression bus, type_name, expr; identifier dev; @@ - DeviceState *dev = qdev_create(bus, type_name); + DeviceState *dev = qdev_new(type_name); ... when != dev = expr - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, bus, &error_fatal); @@ expression bus, type_name, dev, expr, errp; symbol true; @@ - dev = qdev_create(bus, type_name); + dev = qdev_new(type_name); ... when != dev = expr - object_property_set_bool(OBJECT(dev), true, "realized", errp); + qdev_realize_and_unref(dev, bus, errp); @@ expression bus, type_name, expr, errp; identifier dev; symbol true; @@ - DeviceState *dev = qdev_create(bus, type_name); + DeviceState *dev = qdev_new(type_name); ... when != dev = expr - object_property_set_bool(OBJECT(dev), true, "realized", errp); + qdev_realize_and_unref(dev, bus, errp); The first rule exempts hw/arm/highbank.c, because it matches along two control flow paths there, with different @type_name. Covered by the next commit's manual conversions. Missing #include "qapi/error.h" added manually. Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-10-armbru@redhat.com> [Conflicts in hw/misc/empty_slot.c and hw/sparc/leon3.c resolved] --- hw/alpha/typhoon.c | 4 +- hw/arm/aspeed.c | 7 +-- hw/arm/cubieboard.c | 4 +- hw/arm/exynos4210.c | 41 +++++++-------- hw/arm/exynos4_boards.c | 4 +- hw/arm/imx25_pdk.c | 5 +- hw/arm/integratorcp.c | 4 +- hw/arm/mcimx6ul-evk.c | 5 +- hw/arm/mcimx7d-sabre.c | 5 +- hw/arm/mps2-tz.c | 4 +- hw/arm/msf2-som.c | 4 +- hw/arm/musicpal.c | 8 +-- hw/arm/netduino2.c | 4 +- hw/arm/netduinoplus2.c | 4 +- hw/arm/nseries.c | 8 +-- hw/arm/omap1.c | 16 +++--- hw/arm/omap2.c | 16 +++--- hw/arm/orangepi.c | 4 +- hw/arm/pxa2xx.c | 8 +-- hw/arm/pxa2xx_gpio.c | 5 +- hw/arm/pxa2xx_pic.c | 5 +- hw/arm/raspi.c | 4 +- hw/arm/realview.c | 20 ++++---- hw/arm/sbsa-ref.c | 20 ++++---- hw/arm/spitz.c | 4 +- hw/arm/stellaris.c | 12 ++--- hw/arm/strongarm.c | 9 ++-- hw/arm/versatilepb.c | 16 +++--- hw/arm/vexpress.c | 16 +++--- hw/arm/virt.c | 32 ++++++------ hw/arm/xilinx_zynq.c | 38 +++++++------- hw/arm/xlnx-versal-virt.c | 9 ++-- hw/arm/xlnx-versal.c | 4 +- hw/arm/xlnx-zcu102.c | 5 +- hw/audio/intel-hda.c | 4 +- hw/block/fdc.c | 12 ++--- hw/block/pflash_cfi01.c | 4 +- hw/block/pflash_cfi02.c | 4 +- hw/char/exynos4210_uart.c | 5 +- hw/char/mcf_uart.c | 5 +- hw/char/spapr_vty.c | 4 +- hw/core/sysbus.c | 4 +- hw/cris/axis_dev88.c | 4 +- hw/display/milkymist-tmu2.c | 4 +- hw/display/sm501.c | 4 +- hw/dma/pxa2xx_dma.c | 8 +-- hw/dma/rc4030.c | 5 +- hw/dma/sparc32_dma.c | 16 +++--- hw/hppa/dino.c | 4 +- hw/hppa/lasi.c | 4 +- hw/hppa/machine.c | 4 +- hw/i2c/core.c | 5 +- hw/i2c/smbus_eeprom.c | 4 +- hw/i386/pc_q35.c | 4 +- hw/i386/x86.c | 6 +-- hw/ide/qdev.c | 4 +- hw/intc/exynos4210_gic.c | 5 +- hw/intc/s390_flic.c | 6 +-- hw/isa/isa-bus.c | 4 +- hw/lm32/lm32.h | 13 ++--- hw/lm32/milkymist-hw.h | 37 +++++++------- hw/m68k/mcf5208.c | 4 +- hw/m68k/mcf_intc.c | 5 +- hw/m68k/next-cube.c | 12 ++--- hw/m68k/q800.c | 36 ++++++------- hw/microblaze/petalogix_ml605_mmu.c | 20 ++++---- hw/microblaze/petalogix_s3adsp1800_mmu.c | 12 ++--- hw/mips/boston.c | 8 +-- hw/mips/gt64xxx_pci.c | 5 +- hw/mips/jazz.c | 16 +++--- hw/mips/malta.c | 4 +- hw/mips/mipssim.c | 8 +-- hw/misc/empty_slot.c | 5 +- hw/net/etraxfs_eth.c | 4 +- hw/net/fsl_etsec/etsec.c | 5 +- hw/net/lan9118.c | 5 +- hw/net/lasi_i82596.c | 5 +- hw/net/smc91c111.c | 5 +- hw/net/spapr_llan.c | 4 +- hw/nios2/10m50_devboard.c | 12 ++--- hw/nvram/fw_cfg.c | 8 +-- hw/openrisc/openrisc_sim.c | 8 +-- hw/pci-bridge/pci_expander_bridge.c | 4 +- hw/pci-host/bonito.c | 5 +- hw/pci-host/i440fx.c | 4 +- hw/pcmcia/pxa2xx.c | 5 +- hw/ppc/e500.c | 32 ++++++------ hw/ppc/mac_newworld.c | 40 +++++++-------- hw/ppc/mac_oldworld.c | 20 ++++---- hw/ppc/pnv.c | 4 +- hw/ppc/ppc440_uc.c | 8 +-- hw/ppc/prep.c | 9 ++-- hw/ppc/sam460ex.c | 4 +- hw/ppc/spapr.c | 8 +-- hw/ppc/spapr_irq.c | 4 +- hw/ppc/spapr_vio.c | 4 +- hw/ppc/virtex_ml507.c | 9 ++-- hw/riscv/sifive_clint.c | 5 +- hw/riscv/sifive_e_prci.c | 5 +- hw/riscv/sifive_plic.c | 5 +- hw/riscv/sifive_test.c | 5 +- hw/riscv/virt.c | 4 +- hw/rtc/m48t59.c | 5 +- hw/rtc/sun4v-rtc.c | 5 +- hw/s390x/ap-bridge.c | 4 +- hw/s390x/css-bridge.c | 4 +- hw/s390x/s390-virtio-ccw.c | 12 ++--- hw/scsi/scsi-bus.c | 4 +- hw/scsi/spapr_vscsi.c | 4 +- hw/sd/milkymist-memcard.c | 4 +- hw/sd/pxa2xx_mmci.c | 8 +-- hw/sd/ssi-sd.c | 4 +- hw/sh4/r2d.c | 12 ++--- hw/sparc/leon3.c | 12 ++--- hw/sparc/sun4m.c | 64 ++++++++++++------------ hw/sparc64/sun4u.c | 24 ++++----- hw/xen/xen-bus.c | 4 +- hw/xen/xen-legacy-backend.c | 4 +- hw/xtensa/virt.c | 4 +- hw/xtensa/xtfpga.c | 8 +-- include/hw/char/cadence_uart.h | 5 +- include/hw/char/cmsdk-apb-uart.h | 4 +- include/hw/char/pl011.h | 9 ++-- include/hw/char/xilinx_uartlite.h | 4 +- include/hw/cris/etraxfs.h | 4 +- include/hw/misc/unimp.h | 5 +- include/hw/timer/cmsdk-apb-timer.h | 4 +- 127 files changed, 581 insertions(+), 552 deletions(-) diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index 1795e2f29d..480d866c77 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -826,7 +826,7 @@ PCIBus *typhoon_init(MemoryRegion *ram, ISABus **isa_bus, qemu_irq *p_rtc_irq, PCIBus *b; int i; - dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE); + dev = qdev_new(TYPE_TYPHOON_PCI_HOST_BRIDGE); s = TYPHOON_PCI_HOST_BRIDGE(dev); phb = PCI_HOST_BRIDGE(dev); @@ -889,7 +889,7 @@ PCIBus *typhoon_init(MemoryRegion *ram, ISABus **isa_bus, qemu_irq *p_rtc_irq, &s->pchip.reg_mem, &s->pchip.reg_io, 0, 64, TYPE_PCI_BUS); phb->bus = b; - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* Host memory as seen from the PCI side, via the IOMMU. */ memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu), diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index ad9f772e06..b08903df33 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -241,13 +241,14 @@ static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo) { DeviceState *card; - card = qdev_create(qdev_get_child_bus(DEVICE(sdhci), "sd-bus"), - TYPE_SD_CARD); + card = qdev_new(TYPE_SD_CARD); if (dinfo) { qdev_prop_set_drive(card, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } - object_property_set_bool(OBJECT(card), true, "realized", &error_fatal); + qdev_realize_and_unref(card, + qdev_get_child_bus(DEVICE(sdhci), "sd-bus"), + &error_fatal); } static void aspeed_machine_init(MachineState *machine) diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index cd1b6d3e19..4bc4f08caf 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -92,9 +92,9 @@ static void cubieboard_init(MachineState *machine) bus = qdev_get_child_bus(DEVICE(a10), "sd-bus"); /* Plug in SD card */ - carddev = qdev_create(bus, TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); + qdev_realize_and_unref(carddev, bus, &error_fatal); memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE, machine->ram); diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index 1f7253ef6f..9ff1a11f80 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -173,7 +173,7 @@ static DeviceState *pl330_create(uint32_t base, qemu_or_irq *orgate, DeviceState *dev; int i; - dev = qdev_create(NULL, "pl330"); + dev = qdev_new("pl330"); qdev_prop_set_uint8(dev, "num_events", nevents); qdev_prop_set_uint8(dev, "num_chnls", 8); qdev_prop_set_uint8(dev, "num_periph_req", nreq); @@ -184,7 +184,7 @@ static DeviceState *pl330_create(uint32_t base, qemu_or_irq *orgate, qdev_prop_set_uint8(dev, "rd_q_dep", 8); qdev_prop_set_uint8(dev, "data_width", width); qdev_prop_set_uint16(dev, "data_buffer_dep", width); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, base); @@ -232,9 +232,9 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) /* IRQ Gate */ for (i = 0; i < EXYNOS4210_NCPUS; i++) { - dev = qdev_create(NULL, "exynos4210.irq_gate"); + dev = qdev_new("exynos4210.irq_gate"); qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* Get IRQ Gate input in gate_irq */ for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) { gate_irq[i][n] = qdev_get_gpio_in(dev, n); @@ -247,9 +247,9 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) } /* Private memory region and Internal GIC */ - dev = qdev_create(NULL, TYPE_A9MPCORE_PRIV); + dev = qdev_new(TYPE_A9MPCORE_PRIV); qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR); for (n = 0; n < EXYNOS4210_NCPUS; n++) { @@ -263,9 +263,9 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL); /* External GIC */ - dev = qdev_create(NULL, "exynos4210.gic"); + dev = qdev_new("exynos4210.gic"); qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); /* Map CPU interface */ sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR); @@ -279,8 +279,8 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) } /* Internal Interrupt Combiner */ - dev = qdev_create(NULL, "exynos4210.combiner"); - qdev_init_nofail(dev); + dev = qdev_new("exynos4210.combiner"); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]); @@ -289,9 +289,9 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR); /* External Interrupt Combiner */ - dev = qdev_create(NULL, "exynos4210.combiner"); + dev = qdev_new("exynos4210.combiner"); qdev_prop_set_uint32(dev, "external", 1); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]); @@ -353,8 +353,8 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) NULL); /* Multi Core Timer */ - dev = qdev_create(NULL, "exynos4210.mct"); - qdev_init_nofail(dev); + dev = qdev_new("exynos4210.mct"); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); for (n = 0; n < 4; n++) { /* Connect global timer interrupts to Combiner gpio_in */ @@ -379,8 +379,8 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)]; } - dev = qdev_create(NULL, "exynos4210.i2c"); - qdev_init_nofail(dev); + dev = qdev_new("exynos4210.i2c"); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_connect_irq(busdev, 0, i2c_irq); sysbus_mmio_map(busdev, 0, addr); @@ -423,9 +423,9 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) * public datasheet which is very similar (implementing * MMC Specification Version 4.0 being the only difference noted) */ - dev = qdev_create(NULL, TYPE_S3C_SDHCI); + dev = qdev_new(TYPE_S3C_SDHCI); qdev_prop_set_uint64(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, EXYNOS4210_SDHCI_ADDR(n)); @@ -433,9 +433,10 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) di = drive_get(IF_SD, 0, n); blk = di ? blk_by_legacy_dinfo(di) : NULL; - carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &error_abort); - qdev_init_nofail(carddev); + qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"), + &error_fatal); } /*** Display controller (FIMD) ***/ diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index 09da52876d..d4fe9c6128 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -81,10 +81,10 @@ static void lan9215_init(uint32_t base, qemu_irq irq) /* This should be a 9215 but the 9118 is close enough */ if (nd_table[0].used) { qemu_check_nic_model(&nd_table[0], "lan9118"); - dev = qdev_create(NULL, TYPE_LAN9118); + dev = qdev_new(TYPE_LAN9118); qdev_set_nic_properties(dev, &nd_table[0]); qdev_prop_set_uint32(dev, "mode_16bit", 1); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index b3ca82bafa..75076f2ea4 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -130,10 +130,9 @@ static void imx25_pdk_init(MachineState *machine) di = drive_get_next(IF_SD); blk = di ? blk_by_legacy_dinfo(di) : NULL; bus = qdev_get_child_bus(DEVICE(&s->soc.esdhc[i]), "sd-bus"); - carddev = qdev_create(bus, TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, - "realized", &error_fatal); + qdev_realize_and_unref(carddev, bus, &error_fatal); } /* diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index 5fb54e5aa7..45698307f1 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -620,9 +620,9 @@ static void integratorcp_init(MachineState *machine) 0, ram_size); memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias); - dev = qdev_create(NULL, TYPE_INTEGRATOR_CM); + dev = qdev_new(TYPE_INTEGRATOR_CM); qdev_prop_set_uint32(dev, "memsz", ram_size >> 20); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000); dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000, diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c index 5b5f23a6d4..769fe6d802 100644 --- a/hw/arm/mcimx6ul-evk.c +++ b/hw/arm/mcimx6ul-evk.c @@ -54,10 +54,9 @@ static void mcimx6ul_evk_init(MachineState *machine) di = drive_get_next(IF_SD); blk = di ? blk_by_legacy_dinfo(di) : NULL; bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus"); - carddev = qdev_create(bus, TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, - "realized", &error_fatal); + qdev_realize_and_unref(carddev, bus, &error_fatal); } if (!qtest_enabled()) { diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c index 3851cd9e3e..645ad5470f 100644 --- a/hw/arm/mcimx7d-sabre.c +++ b/hw/arm/mcimx7d-sabre.c @@ -56,10 +56,9 @@ static void mcimx7d_sabre_init(MachineState *machine) di = drive_get_next(IF_SD); blk = di ? blk_by_legacy_dinfo(di) : NULL; bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus"); - carddev = qdev_create(bus, TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, - "realized", &error_fatal); + qdev_realize_and_unref(carddev, bus, &error_fatal); } if (!qtest_enabled()) { diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 2c43041564..07d11e439f 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -246,9 +246,9 @@ static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque, * except that it doesn't support the checksum-offload feature. */ qemu_check_nic_model(nd, "lan9118"); - mms->lan9118 = qdev_create(NULL, TYPE_LAN9118); + mms->lan9118 = qdev_new(TYPE_LAN9118); qdev_set_nic_properties(mms->lan9118, nd); - qdev_init_nofail(mms->lan9118); + qdev_realize_and_unref(mms->lan9118, NULL, &error_fatal); s = SYS_BUS_DEVICE(mms->lan9118); sysbus_connect_irq(s, 0, get_sse_irq_in(mms, 16)); diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c index dbd35b6def..e398703742 100644 --- a/hw/arm/msf2-som.c +++ b/hw/arm/msf2-som.c @@ -61,7 +61,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine) &error_fatal); memory_region_add_subregion(sysmem, DDR_BASE_ADDRESS, ddr); - dev = qdev_create(NULL, TYPE_MSF2_SOC); + dev = qdev_new(TYPE_MSF2_SOC); qdev_prop_set_string(dev, "part-name", "M2S010"); qdev_prop_set_string(dev, "cpu-type", mc->default_cpu_type); @@ -77,7 +77,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine) qdev_prop_set_uint32(dev, "apb0div", 2); qdev_prop_set_uint32(dev, "apb1div", 2); - object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal); + qdev_realize_and_unref(dev, NULL, &error_fatal); soc = MSF2_SOC(dev); diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 92f33ed87e..d03351e5fa 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -1651,9 +1651,9 @@ static void musicpal_init(MachineState *machine) sysbus_create_simple(TYPE_MV88W8618_FLASHCFG, MP_FLASHCFG_BASE, NULL); qemu_check_nic_model(&nd_table[0], "mv88w8618"); - dev = qdev_create(NULL, TYPE_MV88W8618_ETH); + dev = qdev_new(TYPE_MV88W8618_ETH); qdev_set_nic_properties(dev, &nd_table[0]); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]); @@ -1688,11 +1688,11 @@ static void musicpal_init(MachineState *machine) } wm8750_dev = i2c_create_slave(i2c, TYPE_WM8750, MP_WM_ADDR); - dev = qdev_create(NULL, TYPE_MV88W8618_AUDIO); + dev = qdev_new(TYPE_MV88W8618_AUDIO); s = SYS_BUS_DEVICE(dev); object_property_set_link(OBJECT(dev), OBJECT(wm8750_dev), "wm8750", NULL); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(s, 0, MP_AUDIO_BASE); sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]); diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c index e770d9cac8..6bd8e4e197 100644 --- a/hw/arm/netduino2.c +++ b/hw/arm/netduino2.c @@ -34,9 +34,9 @@ static void netduino2_init(MachineState *machine) { DeviceState *dev; - dev = qdev_create(NULL, TYPE_STM32F205_SOC); + dev = qdev_new(TYPE_STM32F205_SOC); qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3")); - object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal); + qdev_realize_and_unref(dev, NULL, &error_fatal); armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, FLASH_SIZE); diff --git a/hw/arm/netduinoplus2.c b/hw/arm/netduinoplus2.c index e5e247edbe..8d4b3d7c43 100644 --- a/hw/arm/netduinoplus2.c +++ b/hw/arm/netduinoplus2.c @@ -34,9 +34,9 @@ static void netduinoplus2_init(MachineState *machine) { DeviceState *dev; - dev = qdev_create(NULL, TYPE_STM32F405_SOC); + dev = qdev_new(TYPE_STM32F405_SOC); qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4")); - object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal); + qdev_realize_and_unref(dev, NULL, &error_fatal); armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index eae800b5c1..856fa565a4 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -174,7 +174,7 @@ static void n8x0_nand_setup(struct n800_s *s) char *otp_region; DriveInfo *dinfo; - s->nand = qdev_create(NULL, "onenand"); + s->nand = qdev_new("onenand"); qdev_prop_set_uint16(s->nand, "manufacturer_id", NAND_MFR_SAMSUNG); /* Either 0x40 or 0x48 are OK for the device ID */ qdev_prop_set_uint16(s->nand, "device_id", 0x48); @@ -185,7 +185,7 @@ static void n8x0_nand_setup(struct n800_s *s) qdev_prop_set_drive(s->nand, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } - qdev_init_nofail(s->nand); + qdev_realize_and_unref(s->nand, NULL, &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0, qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO)); omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS, @@ -802,9 +802,9 @@ static void n8x0_uart_setup(struct n800_s *s) static void n8x0_usb_setup(struct n800_s *s) { SysBusDevice *dev; - s->usb = qdev_create(NULL, "tusb6010"); + s->usb = qdev_new("tusb6010"); dev = SYS_BUS_DEVICE(s->usb); - qdev_init_nofail(s->usb); + qdev_realize_and_unref(s->usb, NULL, &error_fatal); sysbus_connect_irq(dev, 0, qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO)); /* Using the NOR interface */ diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index 761cc17ea9..c11d6da9d5 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -3887,20 +3887,20 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram, omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s); - s->ih[0] = qdev_create(NULL, "omap-intc"); + s->ih[0] = qdev_new("omap-intc"); qdev_prop_set_uint32(s->ih[0], "size", 0x100); omap_intc_set_iclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "arminth_ck")); - qdev_init_nofail(s->ih[0]); + qdev_realize_and_unref(s->ih[0], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->ih[0]); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); sysbus_connect_irq(busdev, 1, qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); sysbus_mmio_map(busdev, 0, 0xfffecb00); - s->ih[1] = qdev_create(NULL, "omap-intc"); + s->ih[1] = qdev_new("omap-intc"); qdev_prop_set_uint32(s->ih[1], "size", 0x800); omap_intc_set_iclk(OMAP_INTC(s->ih[1]), omap_findclk(s, "arminth_ck")); - qdev_init_nofail(s->ih[1]); + qdev_realize_and_unref(s->ih[1], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->ih[1]); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_15XX_IH2_IRQ)); @@ -4010,10 +4010,10 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram, qdev_get_gpio_in(s->ih[1], OMAP_INT_MPUIO), s->wakeup, omap_findclk(s, "clk32-kHz")); - s->gpio = qdev_create(NULL, "omap-gpio"); + s->gpio = qdev_new("omap-gpio"); qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model); omap_gpio_set_clk(OMAP1_GPIO(s->gpio), omap_findclk(s, "arm_gpio_ck")); - qdev_init_nofail(s->gpio); + qdev_realize_and_unref(s->gpio, NULL, &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(s->gpio), 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1)); sysbus_mmio_map(SYS_BUS_DEVICE(s->gpio), 0, 0xfffce000); @@ -4028,10 +4028,10 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram, s->pwt = omap_pwt_init(system_memory, 0xfffb6000, omap_findclk(s, "armxor_ck")); - s->i2c[0] = qdev_create(NULL, "omap_i2c"); + s->i2c[0] = qdev_new("omap_i2c"); qdev_prop_set_uint8(s->i2c[0], "revision", 0x11); omap_i2c_set_fclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "mpuper_ck")); - qdev_init_nofail(s->i2c[0]); + qdev_realize_and_unref(s->i2c[0], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->i2c[0]); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C)); sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_I2C_TX]); diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index e1c11de5ce..b45ed5c9ec 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -2306,11 +2306,11 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram, s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54); /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */ - s->ih[0] = qdev_create(NULL, "omap2-intc"); + s->ih[0] = qdev_new("omap2-intc"); qdev_prop_set_uint8(s->ih[0], "revision", 0x21); omap_intc_set_fclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "mpu_intc_fclk")); omap_intc_set_iclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "mpu_intc_iclk")); - qdev_init_nofail(s->ih[0]); + qdev_realize_and_unref(s->ih[0], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->ih[0]); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); @@ -2423,11 +2423,11 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram, omap_findclk(s, "clk32-kHz"), omap_findclk(s, "core_l4_iclk")); - s->i2c[0] = qdev_create(NULL, "omap_i2c"); + s->i2c[0] = qdev_new("omap_i2c"); qdev_prop_set_uint8(s->i2c[0], "revision", 0x34); omap_i2c_set_iclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "i2c1.iclk")); omap_i2c_set_fclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "i2c1.fclk")); - qdev_init_nofail(s->i2c[0]); + qdev_realize_and_unref(s->i2c[0], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->i2c[0]); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ)); @@ -2435,11 +2435,11 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram, sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C1_RX]); sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 5), 0)); - s->i2c[1] = qdev_create(NULL, "omap_i2c"); + s->i2c[1] = qdev_new("omap_i2c"); qdev_prop_set_uint8(s->i2c[1], "revision", 0x34); omap_i2c_set_iclk(OMAP_I2C(s->i2c[1]), omap_findclk(s, "i2c2.iclk")); omap_i2c_set_fclk(OMAP_I2C(s->i2c[1]), omap_findclk(s, "i2c2.fclk")); - qdev_init_nofail(s->i2c[1]); + qdev_realize_and_unref(s->i2c[1], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->i2c[1]); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ)); @@ -2447,7 +2447,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram, sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C2_RX]); sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 6), 0)); - s->gpio = qdev_create(NULL, "omap2-gpio"); + s->gpio = qdev_new("omap2-gpio"); qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model); omap2_gpio_set_iclk(OMAP2_GPIO(s->gpio), omap_findclk(s, "gpio_iclk")); omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 0, omap_findclk(s, "gpio1_dbclk")); @@ -2458,7 +2458,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram, omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 4, omap_findclk(s, "gpio5_dbclk")); } - qdev_init_nofail(s->gpio); + qdev_realize_and_unref(s->gpio, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->gpio); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1)); diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c index b291715f27..44a333a6eb 100644 --- a/hw/arm/orangepi.c +++ b/hw/arm/orangepi.c @@ -94,9 +94,9 @@ static void orangepi_init(MachineState *machine) bus = qdev_get_child_bus(DEVICE(h3), "sd-bus"); /* Plug in SD card */ - carddev = qdev_create(bus, TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); + qdev_realize_and_unref(carddev, bus, &error_fatal); /* SDRAM */ memory_region_add_subregion(get_system_memory(), h3->memmap[AW_H3_SDRAM], diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index e649f8930c..e21ba1af3e 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1510,10 +1510,10 @@ PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, PXA2xxI2CState *s; I2CBus *i2cbus; - dev = qdev_create(NULL, TYPE_PXA2XX_I2C); + dev = qdev_new(TYPE_PXA2XX_I2C); qdev_prop_set_uint32(dev, "size", region_size + 1); qdev_prop_set_uint32(dev, "offset", base & region_size); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); i2c_dev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(i2c_dev, 0, base & ~region_size); @@ -2073,9 +2073,9 @@ static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, DeviceState *dev; SysBusDevice *sbd; - dev = qdev_create(NULL, TYPE_PXA2XX_FIR); + dev = qdev_new(TYPE_PXA2XX_FIR); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sbd = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sbd, 0, base); sysbus_connect_irq(sbd, 0, irq); diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c index a01db54a51..27199af43c 100644 --- a/hw/arm/pxa2xx_gpio.c +++ b/hw/arm/pxa2xx_gpio.c @@ -14,6 +14,7 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" #include "hw/arm/pxa.h" +#include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" @@ -269,10 +270,10 @@ DeviceState *pxa2xx_gpio_init(hwaddr base, CPUState *cs = CPU(cpu); DeviceState *dev; - dev = qdev_create(NULL, TYPE_PXA2XX_GPIO); + dev = qdev_new(TYPE_PXA2XX_GPIO); qdev_prop_set_int32(dev, "lines", lines); qdev_prop_set_int32(dev, "ncpu", cs->cpu_index); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index 203d4d28af..4c451cf540 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -9,6 +9,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/module.h" #include "cpu.h" #include "hw/arm/pxa.h" @@ -267,7 +268,7 @@ static int pxa2xx_pic_post_load(void *opaque, int version_id) DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) { - DeviceState *dev = qdev_create(NULL, TYPE_PXA2XX_PIC); + DeviceState *dev = qdev_new(TYPE_PXA2XX_PIC); PXA2xxPICState *s = PXA2XX_PIC(dev); s->cpu = cpu; @@ -279,7 +280,7 @@ DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) s->is_fiq[0] = 0; s->is_fiq[1] = 0; - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); qdev_init_gpio_in(dev, pxa2xx_pic_set_irq, PXA2XX_PIC_SRCS); diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index a2efe0b94d..a8e26a70bb 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -297,9 +297,9 @@ static void raspi_machine_init(MachineState *machine) error_report("No SD bus found in SOC object"); exit(1); } - carddev = qdev_create(bus, TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); + qdev_realize_and_unref(carddev, bus, &error_fatal); vcram_size = object_property_get_uint(OBJECT(&s->soc), "vcram-size", &error_abort); diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 8fcdf75a2b..128146448c 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -161,16 +161,16 @@ static void realview_init(MachineState *machine, } sys_id = is_pb ? 0x01780500 : 0xc1400400; - sysctl = qdev_create(NULL, "realview_sysctl"); + sysctl = qdev_new("realview_sysctl"); qdev_prop_set_uint32(sysctl, "sys_id", sys_id); qdev_prop_set_uint32(sysctl, "proc_id", proc_id); - qdev_init_nofail(sysctl); + qdev_realize_and_unref(sysctl, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); if (is_mpcore) { - dev = qdev_create(NULL, is_pb ? TYPE_A9MPCORE_PRIV : "realview_mpcore"); + dev = qdev_new(is_pb ? TYPE_A9MPCORE_PRIV : "realview_mpcore"); qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, periphbase); for (n = 0; n < smp_cpus; n++) { @@ -188,9 +188,9 @@ static void realview_init(MachineState *machine, pic[n] = qdev_get_gpio_in(dev, n); } - pl041 = qdev_create(NULL, "pl041"); + pl041 = qdev_new("pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_init_nofail(pl041); + qdev_realize_and_unref(pl041, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[19]); @@ -203,10 +203,10 @@ static void realview_init(MachineState *machine, pl011_create(0x1000c000, pic[15], serial_hd(3)); /* DMA controller is optional, apparently. */ - dev = qdev_create(NULL, "pl081"); + dev = qdev_new("pl081"); object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream", &error_fatal); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0x10030000); sysbus_connect_irq(busdev, 0, pic[24]); @@ -239,9 +239,9 @@ static void realview_init(MachineState *machine, sysbus_create_simple("pl031", 0x10017000, pic[10]); if (!is_pb) { - dev = qdev_create(NULL, "realview_pci"); + dev = qdev_new("realview_pci"); busdev = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(busdev, 0, 0x10019000); /* PCI controller registers */ sysbus_mmio_map(busdev, 1, 0x60000000); /* PCI self-config */ sysbus_mmio_map(busdev, 2, 0x61000000); /* PCI config */ diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 6a0221a681..d68c5d87af 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -339,7 +339,7 @@ static void create_gic(SBSAMachineState *sms) gictype = gicv3_class_name(); - sms->gic = qdev_create(NULL, gictype); + sms->gic = qdev_new(gictype); qdev_prop_set_uint32(sms->gic, "revision", 3); qdev_prop_set_uint32(sms->gic, "num-cpu", smp_cpus); /* @@ -356,7 +356,7 @@ static void create_gic(SBSAMachineState *sms) qdev_prop_set_uint32(sms->gic, "len-redist-region-count", 1); qdev_prop_set_uint32(sms->gic, "redist-region-count[0]", redist0_count); - qdev_init_nofail(sms->gic); + qdev_realize_and_unref(sms->gic, NULL, &error_fatal); gicbusdev = SYS_BUS_DEVICE(sms->gic); sysbus_mmio_map(gicbusdev, 0, sbsa_ref_memmap[SBSA_GIC_DIST].base); sysbus_mmio_map(gicbusdev, 1, sbsa_ref_memmap[SBSA_GIC_REDIST].base); @@ -409,11 +409,11 @@ static void create_uart(const SBSAMachineState *sms, int uart, { hwaddr base = sbsa_ref_memmap[uart].base; int irq = sbsa_ref_irqmap[uart]; - DeviceState *dev = qdev_create(NULL, TYPE_PL011); + DeviceState *dev = qdev_new(TYPE_PL011); SysBusDevice *s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); sysbus_connect_irq(s, 0, qdev_get_gpio_in(sms->gic, irq)); @@ -464,9 +464,9 @@ static void create_ahci(const SBSAMachineState *sms) AHCIState *ahci; int i; - dev = qdev_create(NULL, "sysbus-ahci"); + dev = qdev_new("sysbus-ahci"); qdev_prop_set_uint32(dev, "num-ports", NUM_SATA_PORTS); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(sms->gic, irq)); @@ -497,11 +497,11 @@ static void create_smmu(const SBSAMachineState *sms, PCIBus *bus) DeviceState *dev; int i; - dev = qdev_create(NULL, "arm-smmuv3"); + dev = qdev_new("arm-smmuv3"); object_property_set_link(OBJECT(dev), OBJECT(bus), "primary-bus", &error_abort); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); for (i = 0; i < NUM_SMMU_IRQS; i++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, @@ -525,8 +525,8 @@ static void create_pcie(SBSAMachineState *sms) PCIHostState *pci; int i; - dev = qdev_create(NULL, TYPE_GPEX_HOST); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_GPEX_HOST); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* Map ECAM space */ ecam_alias = g_new0(MemoryRegion, 1); diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index c28d9b5ed7..edae6bf8be 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -155,7 +155,7 @@ static void sl_flash_register(PXA2xxState *cpu, int size) { DeviceState *dev; - dev = qdev_create(NULL, TYPE_SL_NAND); + dev = qdev_new(TYPE_SL_NAND); qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG); if (size == FLASH_128M) @@ -163,7 +163,7 @@ static void sl_flash_register(PXA2xxState *cpu, int size) else if (size == FLASH_1024M) qdev_prop_set_uint8(dev, "chip_id", 0xf1); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE); } diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index d136ba1a92..f824cbd498 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -1308,14 +1308,14 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) &error_fatal); memory_region_add_subregion(system_memory, 0x20000000, sram); - nvic = qdev_create(NULL, TYPE_ARMV7M); + nvic = qdev_new(TYPE_ARMV7M); qdev_prop_set_uint32(nvic, "num-irq", NUM_IRQ_LINES); qdev_prop_set_string(nvic, "cpu-type", ms->cpu_type); qdev_prop_set_bit(nvic, "enable-bitband", true); object_property_set_link(OBJECT(nvic), OBJECT(get_system_memory()), "memory", &error_abort); /* This will exit with an error if the user passed us a bad cpu_type */ - qdev_init_nofail(nvic); + qdev_realize_and_unref(nvic, NULL, &error_fatal); qdev_connect_gpio_out_named(nvic, "SYSRESETREQ", 0, qemu_allocate_irq(&do_sys_reset, NULL, 0)); @@ -1347,13 +1347,13 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) if (board->dc1 & (1 << 3)) { /* watchdog present */ - dev = qdev_create(NULL, TYPE_LUMINARY_WATCHDOG); + dev = qdev_new(TYPE_LUMINARY_WATCHDOG); /* system_clock_scale is valid now */ uint32_t mainclk = NANOSECONDS_PER_SECOND / system_clock_scale; qdev_prop_set_uint32(dev, "wdogclk-frq", mainclk); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x40000000u); @@ -1425,9 +1425,9 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) qemu_check_nic_model(&nd_table[0], "stellaris"); - enet = qdev_create(NULL, "stellaris_enet"); + enet = qdev_new("stellaris_enet"); qdev_set_nic_properties(enet, &nd_table[0]); - qdev_init_nofail(enet); + qdev_realize_and_unref(enet, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000); sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, qdev_get_gpio_in(nvic, 42)); } diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index 3010d765bb..108ed8d147 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -42,6 +42,7 @@ #include "chardev/char-serial.h" #include "sysemu/sysemu.h" #include "hw/ssi/ssi.h" +#include "qapi/error.h" #include "qemu/cutils.h" #include "qemu/log.h" @@ -644,8 +645,8 @@ static DeviceState *strongarm_gpio_init(hwaddr base, DeviceState *dev; int i; - dev = qdev_create(NULL, TYPE_STRONGARM_GPIO); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_STRONGARM_GPIO); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); for (i = 0; i < 12; i++) @@ -1626,9 +1627,9 @@ StrongARMState *sa1110_init(const char *cpu_type) s->ppc = sysbus_create_varargs(TYPE_STRONGARM_PPC, 0x90060000, NULL); for (i = 0; sa_serial[i].io_base; i++) { - DeviceState *dev = qdev_create(NULL, TYPE_STRONGARM_UART); + DeviceState *dev = qdev_new(TYPE_STRONGARM_UART); qdev_prop_set_chr(dev, "chardev", serial_hd(i)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, sa_serial[i].io_base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index f3c4a50b19..154fa72f33 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -223,10 +223,10 @@ static void versatile_init(MachineState *machine, int board_id) /* SDRAM at address zero. */ memory_region_add_subregion(sysmem, 0, machine->ram); - sysctl = qdev_create(NULL, "realview_sysctl"); + sysctl = qdev_new("realview_sysctl"); qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004); qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000); - qdev_init_nofail(sysctl); + qdev_realize_and_unref(sysctl, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); dev = sysbus_create_varargs("pl190", 0x10140000, @@ -245,9 +245,9 @@ static void versatile_init(MachineState *machine, int board_id) sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]); sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]); - dev = qdev_create(NULL, "versatile_pci"); + dev = qdev_new("versatile_pci"); busdev = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(busdev, 0, 0x10001000); /* PCI controller regs */ sysbus_mmio_map(busdev, 1, 0x41000000); /* PCI self-config */ sysbus_mmio_map(busdev, 2, 0x42000000); /* PCI config */ @@ -286,10 +286,10 @@ static void versatile_init(MachineState *machine, int board_id) pl011_create(0x101f3000, pic[14], serial_hd(2)); pl011_create(0x10009000, sic[6], serial_hd(3)); - dev = qdev_create(NULL, "pl080"); + dev = qdev_new("pl080"); object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream", &error_fatal); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0x10130000); sysbus_connect_irq(busdev, 0, pic[17]); @@ -319,9 +319,9 @@ static void versatile_init(MachineState *machine, int board_id) i2c_create_slave(i2c, "ds1338", 0x68); /* Add PL041 AACI Interface to the LM4549 codec */ - pl041 = qdev_create(NULL, "pl041"); + pl041 = qdev_new("pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_init_nofail(pl041); + qdev_realize_and_unref(pl041, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 69ee4988f9..ef29e9f5ae 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -236,9 +236,9 @@ static void init_cpus(MachineState *ms, const char *cpu_type, * this must happen after the CPUs are created because a15mpcore_priv * wires itself up to the CPU's generic_timer gpio out lines. */ - dev = qdev_create(NULL, privdev); + dev = qdev_new(privdev); qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, periphbase); @@ -514,7 +514,7 @@ static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt) static PFlashCFI01 *ve_pflash_cfi01_register(hwaddr base, const char *name, DriveInfo *di) { - DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); if (di) { qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di), @@ -532,7 +532,7 @@ static PFlashCFI01 *ve_pflash_cfi01_register(hwaddr base, const char *name, qdev_prop_set_uint16(dev, "id2", 0x00); qdev_prop_set_uint16(dev, "id3", 0x00); qdev_prop_set_string(dev, "name", name); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return PFLASH_CFI01(dev); @@ -593,7 +593,7 @@ static void vexpress_common_init(MachineState *machine) sys_id = 0x1190f500; - sysctl = qdev_create(NULL, "realview_sysctl"); + sysctl = qdev_new("realview_sysctl"); qdev_prop_set_uint32(sysctl, "sys_id", sys_id); qdev_prop_set_uint32(sysctl, "proc_id", daughterboard->proc_id); qdev_prop_set_uint32(sysctl, "len-db-voltage", @@ -610,15 +610,15 @@ static void vexpress_common_init(MachineState *machine) qdev_prop_set_uint32(sysctl, propname, daughterboard->clocks[i]); g_free(propname); } - qdev_init_nofail(sysctl); + qdev_realize_and_unref(sysctl, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]); /* VE_SP810: not modelled */ /* VE_SERIALPCI: not modelled */ - pl041 = qdev_create(NULL, "pl041"); + pl041 = qdev_new("pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_init_nofail(pl041); + qdev_realize_and_unref(pl041, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, map[VE_PL041]); sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[11]); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 37462a6f78..154cd24731 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -572,14 +572,14 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) event |= ACPI_GED_NVDIMM_HOTPLUG_EVT; } - dev = qdev_create(NULL, TYPE_ACPI_GED); + dev = qdev_new(TYPE_ACPI_GED); qdev_prop_set_uint32(dev, "ged-event", event); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); return dev; } @@ -594,11 +594,11 @@ static void create_its(VirtMachineState *vms) return; } - dev = qdev_create(NULL, itsclass); + dev = qdev_new(itsclass); object_property_set_link(OBJECT(dev), OBJECT(vms->gic), "parent-gicv3", &error_abort); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_ITS].base); fdt_add_its_gic_node(vms); @@ -610,11 +610,11 @@ static void create_v2m(VirtMachineState *vms) int irq = vms->irqmap[VIRT_GIC_V2M]; DeviceState *dev; - dev = qdev_create(NULL, "arm-gicv2m"); + dev = qdev_new("arm-gicv2m"); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_V2M].base); qdev_prop_set_uint32(dev, "base-spi", irq); qdev_prop_set_uint32(dev, "num-spi", NUM_GICV2M_SPIS); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); for (i = 0; i < NUM_GICV2M_SPIS; i++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, @@ -636,7 +636,7 @@ static void create_gic(VirtMachineState *vms) gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); - vms->gic = qdev_create(NULL, gictype); + vms->gic = qdev_new(gictype); qdev_prop_set_uint32(vms->gic, "revision", type); qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus); /* Note that the num-irq property counts both internal and external @@ -671,7 +671,7 @@ static void create_gic(VirtMachineState *vms) vms->virt); } } - qdev_init_nofail(vms->gic); + qdev_realize_and_unref(vms->gic, NULL, &error_fatal); gicbusdev = SYS_BUS_DEVICE(vms->gic); sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base); if (type == 3) { @@ -754,11 +754,11 @@ static void create_uart(const VirtMachineState *vms, int uart, int irq = vms->irqmap[uart]; const char compat[] = "arm,pl011\0arm,primecell"; const char clocknames[] = "uartclk\0apb_pclk"; - DeviceState *dev = qdev_create(NULL, TYPE_PL011); + DeviceState *dev = qdev_new(TYPE_PL011); SysBusDevice *s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq)); @@ -1173,11 +1173,11 @@ static void create_smmu(const VirtMachineState *vms, return; } - dev = qdev_create(NULL, "arm-smmuv3"); + dev = qdev_new("arm-smmuv3"); object_property_set_link(OBJECT(dev), OBJECT(bus), "primary-bus", &error_abort); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); for (i = 0; i < NUM_SMMU_IRQS; i++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, @@ -1253,8 +1253,8 @@ static void create_pcie(VirtMachineState *vms) int i, ecam_id; PCIHostState *pci; - dev = qdev_create(NULL, TYPE_GPEX_HOST); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_GPEX_HOST); + qdev_realize_and_unref(dev, NULL, &error_fatal); ecam_id = VIRT_ECAM_ID(vms->highmem_ecam); base_ecam = vms->memmap[ecam_id].base; @@ -1372,11 +1372,11 @@ static void create_platform_bus(VirtMachineState *vms) int i; MemoryRegion *sysmem = get_system_memory(); - dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE); + dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); dev->id = TYPE_PLATFORM_BUS_DEVICE; qdev_prop_set_uint32(dev, "num_irqs", PLATFORM_BUS_NUM_IRQS); qdev_prop_set_uint32(dev, "mmio_size", vms->memmap[VIRT_PLATFORM_BUS].size); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); vms->platform_bus_dev = dev; s = SYS_BUS_DEVICE(dev); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index cb933efb49..5fbd2b2e31 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -114,12 +114,12 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, TYPE_CADENCE_GEM); + dev = qdev_new(TYPE_CADENCE_GEM); if (nd->used) { qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(dev, nd); } - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); @@ -136,11 +136,11 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, int num_busses = is_qspi ? NUM_QSPI_BUSSES : 1; int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES; - dev = qdev_create(NULL, is_qspi ? "xlnx.ps7-qspi" : "xlnx.ps7-spi"); + dev = qdev_new(is_qspi ? "xlnx.ps7-qspi" : "xlnx.ps7-spi"); qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1); qdev_prop_set_uint8(dev, "num-ss-bits", num_ss); qdev_prop_set_uint8(dev, "num-busses", num_busses); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, base_addr); if (is_qspi) { @@ -222,8 +222,8 @@ static void zynq_init(MachineState *machine) 0); /* Create slcr, keep a pointer to connect clocks */ - slcr = qdev_create(NULL, "xilinx,zynq_slcr"); - qdev_init_nofail(slcr); + slcr = qdev_new("xilinx,zynq_slcr"); + qdev_realize_and_unref(slcr, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(slcr), 0, 0xF8000000); /* Create the main clock source, and feed slcr with it */ @@ -234,9 +234,9 @@ static void zynq_init(MachineState *machine) clock_set_hz(zynq_machine->ps_clk, PS_CLK_FREQUENCY); qdev_connect_clock_in(slcr, "ps_clk", zynq_machine->ps_clk); - dev = qdev_create(NULL, TYPE_A9MPCORE_PRIV); + dev = qdev_new(TYPE_A9MPCORE_PRIV); qdev_prop_set_uint32(dev, "num-cpu", 1); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE); sysbus_connect_irq(busdev, 0, @@ -280,27 +280,27 @@ static void zynq_init(MachineState *machine) * - SDIO Specification Version 2.0 * - MMC Specification Version 3.31 */ - dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); + dev = qdev_new(TYPE_SYSBUS_SDHCI); qdev_prop_set_uint8(dev, "sd-spec-version", 2); qdev_prop_set_uint64(dev, "capareg", ZYNQ_SDHCI_CAPABILITIES); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, hci_addr); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[hci_irq - IRQ_OFFSET]); di = drive_get_next(IF_SD); blk = di ? blk_by_legacy_dinfo(di) : NULL; - carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, "realized", - &error_fatal); + qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"), + &error_fatal); } - dev = qdev_create(NULL, TYPE_ZYNQ_XADC); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_ZYNQ_XADC); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[39-IRQ_OFFSET]); - dev = qdev_create(NULL, "pl330"); + dev = qdev_new("pl330"); qdev_prop_set_uint8(dev, "num_chnls", 8); qdev_prop_set_uint8(dev, "num_periph_req", 4); qdev_prop_set_uint8(dev, "num_events", 16); @@ -312,7 +312,7 @@ static void zynq_init(MachineState *machine) qdev_prop_set_uint8(dev, "rd_q_dep", 16); qdev_prop_set_uint16(dev, "data_buffer_dep", 256); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xF8003000); sysbus_connect_irq(busdev, 0, pic[45-IRQ_OFFSET]); /* abort irq line */ @@ -320,8 +320,8 @@ static void zynq_init(MachineState *machine) sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]); } - dev = qdev_create(NULL, "xlnx.ps7-dev-cfg"); - qdev_init_nofail(dev); + dev = qdev_new("xlnx.ps7-dev-cfg"); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_connect_irq(busdev, 0, pic[40 - IRQ_OFFSET]); sysbus_mmio_map(busdev, 0, 0xF8007000); diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 43a71e2eea..fb37b235fe 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -432,9 +432,9 @@ static void create_virtio_regions(VersalVirt *s) qemu_irq pic_irq; pic_irq = qdev_get_gpio_in(DEVICE(&s->soc.fpd.apu.gic), irq); - dev = qdev_create(NULL, "virtio-mmio"); + dev = qdev_new("virtio-mmio"); object_property_add_child(OBJECT(&s->soc), name, OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic_irq); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(&s->soc.mr_ps, base, mr); @@ -463,10 +463,11 @@ static void sd_plugin_card(SDHCIState *sd, DriveInfo *di) BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL; DeviceState *card; - card = qdev_create(qdev_get_child_bus(DEVICE(sd), "sd-bus"), TYPE_SD_CARD); + card = qdev_new(TYPE_SD_CARD); object_property_add_child(OBJECT(sd), "card[*]", OBJECT(card)); qdev_prop_set_drive(card, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(card), true, "realized", &error_fatal); + qdev_realize_and_unref(card, qdev_get_child_bus(DEVICE(sd), "sd-bus"), + &error_fatal); } static void versal_virt_init(MachineState *machine) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 809a31390f..c3d47bb9e9 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -304,13 +304,13 @@ static void versal_unimp_area(Versal *s, const char *name, MemoryRegion *mr, hwaddr base, hwaddr size) { - DeviceState *dev = qdev_create(NULL, TYPE_UNIMPLEMENTED_DEVICE); + DeviceState *dev = qdev_new(TYPE_UNIMPLEMENTED_DEVICE); MemoryRegion *mr_dev; qdev_prop_set_string(dev, "name", name); qdev_prop_set_uint64(dev, "size", size); object_property_add_child(OBJECT(s), name, OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); mr_dev = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(mr, base, mr_dev); diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index b01e575b58..4229b2d936 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -143,10 +143,9 @@ static void xlnx_zcu102_init(MachineState *machine) error_report("No SD bus found for SD card %d", i); exit(1); } - carddev = qdev_create(bus, TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, "realized", - &error_fatal); + qdev_realize_and_unref(carddev, bus, &error_fatal); } for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 4696ae0d9a..f673b8317a 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -1309,8 +1309,8 @@ static int intel_hda_and_codec_init(PCIBus *bus) controller = DEVICE(pci_create_simple(bus, -1, "intel-hda")); hdabus = QLIST_FIRST(&controller->child_bus); - codec = qdev_create(hdabus, "hda-duplex"); - qdev_init_nofail(codec); + codec = qdev_new("hda-duplex"); + qdev_realize_and_unref(codec, hdabus, &error_fatal); return 0; } diff --git a/hw/block/fdc.c b/hw/block/fdc.c index c5fb9d6ece..1feb398875 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2516,7 +2516,7 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, continue; } - dev = qdev_create(&fdctrl->bus.bus, "floppy"); + dev = qdev_new("floppy"); qdev_prop_set_uint32(dev, "unit", i); qdev_prop_set_enum(dev, "drive-type", fdctrl->qdev_for_drives[i].type); @@ -2531,7 +2531,7 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, return; } - object_property_set_bool(OBJECT(dev), true, "realized", &local_err); + qdev_realize_and_unref(dev, &fdctrl->bus.bus, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -2571,7 +2571,7 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, SysBusDevice *sbd; FDCtrlSysBus *sys; - dev = qdev_create(NULL, "sysbus-fdc"); + dev = qdev_new("sysbus-fdc"); sys = SYSBUS_FDC(dev); fdctrl = &sys->state; fdctrl->dma_chann = dma_chann; /* FIXME */ @@ -2583,7 +2583,7 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]), &error_fatal); } - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sbd = SYS_BUS_DEVICE(dev); sysbus_connect_irq(sbd, 0, irq); sysbus_mmio_map(sbd, 0, mmio_base); @@ -2595,12 +2595,12 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, DeviceState *dev; FDCtrlSysBus *sys; - dev = qdev_create(NULL, "SUNW,fdtwo"); + dev = qdev_new("SUNW,fdtwo"); if (fds[0]) { qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(fds[0]), &error_fatal); } - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sys = SYSBUS_FDC(dev); sysbus_connect_irq(SYS_BUS_DEVICE(sys), 0, irq); sysbus_mmio_map(SYS_BUS_DEVICE(sys), 0, io_base); diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 11922c0f96..d2a647d2b8 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -959,7 +959,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, uint16_t id2, uint16_t id3, int be) { - DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); if (blk) { qdev_prop_set_drive(dev, "drive", blk, &error_abort); @@ -974,7 +974,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, qdev_prop_set_uint16(dev, "id2", id2); qdev_prop_set_uint16(dev, "id3", id3); qdev_prop_set_string(dev, "name", name); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return PFLASH_CFI01(dev); diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index ac7e34ecbf..ed9e9eef0c 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -998,7 +998,7 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base, uint16_t unlock_addr1, int be) { - DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI02); + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI02); if (blk) { qdev_prop_set_drive(dev, "drive", blk, &error_abort); @@ -1016,7 +1016,7 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base, qdev_prop_set_uint16(dev, "unlock-addr0", unlock_addr0); qdev_prop_set_uint16(dev, "unlock-addr1", unlock_addr1); qdev_prop_set_string(dev, "name", name); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return PFLASH_CFI02(dev); diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index 96d5180e3e..b86bd7b2e6 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -22,6 +22,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "migration/vmstate.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/module.h" #include "qemu/timer.h" @@ -652,7 +653,7 @@ DeviceState *exynos4210_uart_create(hwaddr addr, DeviceState *dev; SysBusDevice *bus; - dev = qdev_create(NULL, TYPE_EXYNOS4210_UART); + dev = qdev_new(TYPE_EXYNOS4210_UART); qdev_prop_set_chr(dev, "chardev", chr); qdev_prop_set_uint32(dev, "channel", channel); @@ -660,7 +661,7 @@ DeviceState *exynos4210_uart_create(hwaddr addr, qdev_prop_set_uint32(dev, "tx-size", fifo_size); bus = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); if (addr != (hwaddr)-1) { sysbus_mmio_map(bus, 0, addr); } diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c index 97e4bbc31a..2ac0a195f3 100644 --- a/hw/char/mcf_uart.c +++ b/hw/char/mcf_uart.c @@ -10,6 +10,7 @@ #include "hw/irq.h" #include "hw/sysbus.h" #include "qemu/module.h" +#include "qapi/error.h" #include "hw/m68k/mcf.h" #include "hw/qdev-properties.h" #include "chardev/char-fe.h" @@ -343,11 +344,11 @@ void *mcf_uart_init(qemu_irq irq, Chardev *chrdrv) { DeviceState *dev; - dev = qdev_create(NULL, TYPE_MCF_UART); + dev = qdev_new(TYPE_MCF_UART); if (chrdrv) { qdev_prop_set_chr(dev, "chardev", chrdrv); } - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c index ecb94f5673..464a52342a 100644 --- a/hw/char/spapr_vty.c +++ b/hw/char/spapr_vty.c @@ -158,9 +158,9 @@ void spapr_vty_create(SpaprVioBus *bus, Chardev *chardev) { DeviceState *dev; - dev = qdev_create(&bus->bus, "spapr-vty"); + dev = qdev_new("spapr-vty"); qdev_prop_set_chr(dev, "chardev", chardev); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, &bus->bus, &error_fatal); } static Property spapr_vty_properties[] = { diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 08b0311c5f..b5db0d179f 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -230,9 +230,9 @@ DeviceState *sysbus_create_varargs(const char *name, qemu_irq irq; int n; - dev = qdev_create(NULL, name); + dev = qdev_new(name); s = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); if (addr != (hwaddr)-1) { sysbus_mmio_map(s, 0, addr); } diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c index 75e5c993b5..5db667d518 100644 --- a/hw/cris/axis_dev88.c +++ b/hw/cris/axis_dev88.c @@ -289,8 +289,8 @@ void axisdev88_init(MachineState *machine) &gpio_state.iomem); - dev = qdev_create(NULL, "etraxfs,pic"); - qdev_init_nofail(dev); + dev = qdev_new("etraxfs,pic"); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, 0x3001c000); sysbus_connect_irq(s, 0, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_IRQ)); diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c index 513c0d5bab..e54fd85777 100644 --- a/hw/display/milkymist-tmu2.c +++ b/hw/display/milkymist-tmu2.c @@ -543,8 +543,8 @@ DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq) XFree(configs); XCloseDisplay(d); - dev = qdev_create(NULL, TYPE_MILKYMIST_TMU2); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_MILKYMIST_TMU2); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); diff --git a/hw/display/sm501.c b/hw/display/sm501.c index fa23a78164..7ff14fd474 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1969,10 +1969,10 @@ static void sm501_realize_sysbus(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->state.mmio_region); /* bridge to usb host emulation module */ - usb_dev = qdev_create(NULL, "sysbus-ohci"); + usb_dev = qdev_new("sysbus-ohci"); qdev_prop_set_uint32(usb_dev, "num-ports", 2); qdev_prop_set_uint64(usb_dev, "dma-offset", s->base); - qdev_init_nofail(usb_dev); + qdev_realize_and_unref(usb_dev, NULL, &error_fatal); memory_region_add_subregion(&s->state.mmio_region, SM501_USB_HOST, sysbus_mmio_get_region(SYS_BUS_DEVICE(usb_dev), 0)); sysbus_pass_irq(sbd, SYS_BUS_DEVICE(usb_dev)); diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c index 8a2eeb32bc..6b761af701 100644 --- a/hw/dma/pxa2xx_dma.c +++ b/hw/dma/pxa2xx_dma.c @@ -495,9 +495,9 @@ DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq) { DeviceState *dev; - dev = qdev_create(NULL, "pxa2xx-dma"); + dev = qdev_new("pxa2xx-dma"); qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); @@ -509,9 +509,9 @@ DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq) { DeviceState *dev; - dev = qdev_create(NULL, "pxa2xx-dma"); + dev = qdev_new("pxa2xx-dma"); qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index eefbabd758..21c9706bf3 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -28,6 +28,7 @@ #include "hw/mips/mips.h" #include "hw/sysbus.h" #include "migration/vmstate.h" +#include "qapi/error.h" #include "qemu/timer.h" #include "qemu/log.h" #include "qemu/module.h" @@ -744,8 +745,8 @@ DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr) { DeviceState *dev; - dev = qdev_create(NULL, TYPE_RC4030); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_RC4030); + qdev_realize_and_unref(dev, NULL, &error_fatal); *dmas = rc4030_allocate_dmas(dev, 4); *dma_mr = &RC4030(dev)->dma_mr; diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index 84b9c5dc77..77cf41e591 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -301,7 +301,7 @@ static void sparc32_espdma_device_realize(DeviceState *dev, Error **errp) SysBusESPState *sysbus; ESPState *esp; - d = qdev_create(NULL, TYPE_ESP); + d = qdev_new(TYPE_ESP); object_property_add_child(OBJECT(dev), "esp", OBJECT(d)); sysbus = ESP_STATE(d); esp = &sysbus->esp; @@ -310,7 +310,7 @@ static void sparc32_espdma_device_realize(DeviceState *dev, Error **errp) esp->dma_opaque = SPARC32_DMA_DEVICE(dev); sysbus->it_shift = 2; esp->dma_enabled = 1; - qdev_init_nofail(d); + qdev_realize_and_unref(d, NULL, &error_fatal); } static void sparc32_espdma_device_class_init(ObjectClass *klass, void *data) @@ -343,11 +343,11 @@ static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp) qemu_check_nic_model(nd, TYPE_LANCE); - d = qdev_create(NULL, TYPE_LANCE); + d = qdev_new(TYPE_LANCE); object_property_add_child(OBJECT(dev), "lance", OBJECT(d)); qdev_set_nic_properties(d, nd); object_property_set_link(OBJECT(d), OBJECT(dev), "dma", errp); - qdev_init_nofail(d); + qdev_realize_and_unref(d, NULL, &error_fatal); } static void sparc32_ledma_device_class_init(ObjectClass *klass, void *data) @@ -378,10 +378,10 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) return; } - espdma = qdev_create(NULL, TYPE_SPARC32_ESPDMA_DEVICE); + espdma = qdev_new(TYPE_SPARC32_ESPDMA_DEVICE); object_property_set_link(OBJECT(espdma), iommu, "iommu", errp); object_property_add_child(OBJECT(s), "espdma", OBJECT(espdma)); - qdev_init_nofail(espdma); + qdev_realize_and_unref(espdma, NULL, &error_fatal); esp = DEVICE(object_resolve_path_component(OBJECT(espdma), "esp")); sbd = SYS_BUS_DEVICE(esp); @@ -393,10 +393,10 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(&s->dmamem, 0x0, sysbus_mmio_get_region(sbd, 0)); - ledma = qdev_create(NULL, TYPE_SPARC32_LEDMA_DEVICE); + ledma = qdev_new(TYPE_SPARC32_LEDMA_DEVICE); object_property_set_link(OBJECT(ledma), iommu, "iommu", errp); object_property_add_child(OBJECT(s), "ledma", OBJECT(ledma)); - qdev_init_nofail(ledma); + qdev_realize_and_unref(ledma, NULL, &error_fatal); lance = DEVICE(object_resolve_path_component(OBJECT(ledma), "lance")); sbd = SYS_BUS_DEVICE(lance); diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 7290f23962..4152c852dc 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -521,7 +521,7 @@ PCIBus *dino_init(MemoryRegion *addr_space, PCIBus *b; int i; - dev = qdev_create(NULL, TYPE_DINO_PCI_HOST_BRIDGE); + dev = qdev_new(TYPE_DINO_PCI_HOST_BRIDGE); s = DINO_PCI_HOST_BRIDGE(dev); s->iar0 = s->iar1 = CPU_HPA + 3; s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */ @@ -548,7 +548,7 @@ PCIBus *dino_init(MemoryRegion *addr_space, &s->pci_mem, get_system_io(), PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS); s->parent_obj.bus = b; - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* Set up windows into PCI bus memory. */ for (i = 1; i < 31; i++) { diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index d8d03f95c0..4539022c5b 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -300,7 +300,7 @@ DeviceState *lasi_init(MemoryRegion *address_space) DeviceState *dev; LasiState *s; - dev = qdev_create(NULL, TYPE_LASI_CHIP); + dev = qdev_new(TYPE_LASI_CHIP); s = LASI_CHIP(dev); s->iar = CPU_HPA + 3; @@ -309,7 +309,7 @@ DeviceState *lasi_init(MemoryRegion *address_space) s, "lasi", 0x100000); memory_region_add_subregion(address_space, LASI_HPA, &s->this_mem); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* LAN */ if (enable_lasi_lan()) { diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 00dd9f58d6..d828b4fb94 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -124,8 +124,8 @@ static void machine_hppa_init(MachineState *machine) /* Graphics setup. */ if (machine->enable_graphics && vga_interface_type != VGA_NONE) { - dev = qdev_create(NULL, "artist"); - qdev_init_nofail(dev); + dev = qdev_new("artist"); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, LASI_GFX_HPA); sysbus_mmio_map(s, 1, ARTIST_FB_ADDR); diff --git a/hw/i2c/core.c b/hw/i2c/core.c index d413a192ed..1aac457a2a 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -11,6 +11,7 @@ #include "hw/i2c/i2c.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" +#include "qapi/error.h" #include "qemu/module.h" #include "trace.h" @@ -270,9 +271,9 @@ DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr) { DeviceState *dev; - dev = qdev_create(&bus->qbus, name); + dev = qdev_new(name); qdev_prop_set_uint8(dev, "address", addr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, &bus->qbus, &error_fatal); return dev; } diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c index e199fc8678..b7def9eeb8 100644 --- a/hw/i2c/smbus_eeprom.c +++ b/hw/i2c/smbus_eeprom.c @@ -169,11 +169,11 @@ void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf) { DeviceState *dev; - dev = qdev_create((BusState *) smbus, TYPE_SMBUS_EEPROM); + dev = qdev_new(TYPE_SMBUS_EEPROM); qdev_prop_set_uint8(dev, "address", address); /* FIXME: use an array of byte or block backend property? */ SMBUS_EEPROM(dev)->init_data = eeprom_buf; - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, (BusState *)smbus, &error_fatal); } void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index fa9ef449d1..59307d91e2 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -214,7 +214,7 @@ static void pc_q35_init(MachineState *machine) } /* create pci host bus */ - q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE)); + q35_host = Q35_HOST_DEVICE(qdev_new(TYPE_Q35_HOST_DEVICE)); object_property_add_child(qdev_get_machine(), "q35", OBJECT(q35_host)); object_property_set_link(OBJECT(q35_host), OBJECT(ram_memory), @@ -230,7 +230,7 @@ static void pc_q35_init(MachineState *machine) object_property_set_int(OBJECT(q35_host), x86ms->above_4g_mem_size, PCI_HOST_ABOVE_4G_MEM_SIZE, NULL); /* pci */ - qdev_init_nofail(DEVICE(q35_host)); + qdev_realize_and_unref(DEVICE(q35_host), NULL, &error_fatal); phb = PCI_HOST_BRIDGE(q35_host); host_bus = phb->bus; /* create ISA bus */ diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 7a3bc7ab66..85ab52b316 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -345,13 +345,13 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name) assert(parent_name); if (kvm_ioapic_in_kernel()) { - dev = qdev_create(NULL, TYPE_KVM_IOAPIC); + dev = qdev_new(TYPE_KVM_IOAPIC); } else { - dev = qdev_create(NULL, TYPE_IOAPIC); + dev = qdev_new(TYPE_IOAPIC); } object_property_add_child(object_resolve_path(parent_name, NULL), "ioapic", OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); d = SYS_BUS_DEVICE(dev); sysbus_mmio_map(d, 0, IO_APIC_DEFAULT_ADDRESS); diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 06b11583f5..caa88526f5 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -127,11 +127,11 @@ IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive) { DeviceState *dev; - dev = qdev_create(&bus->qbus, drive->media_cd ? "ide-cd" : "ide-hd"); + dev = qdev_new(drive->media_cd ? "ide-cd" : "ide-hd"); qdev_prop_set_uint32(dev, "unit", unit); qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(drive), &error_fatal); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, &bus->qbus, &error_fatal); return DO_UPCAST(IDEDevice, qdev, dev); } diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index 82c8f4192c..a261ab2401 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -23,6 +23,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "migration/vmstate.h" +#include "qapi/error.h" #include "qemu/module.h" #include "hw/irq.h" #include "hw/qdev-properties.h" @@ -296,10 +297,10 @@ static void exynos4210_gic_realize(DeviceState *dev, Error **errp) uint32_t n = s->num_cpu; uint32_t i; - s->gic = qdev_create(NULL, "arm_gic"); + s->gic = qdev_new("arm_gic"); qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ); - qdev_init_nofail(s->gic); + qdev_realize_and_unref(s->gic, NULL, &error_fatal); gicbusdev = SYS_BUS_DEVICE(s->gic); /* Pass through outbound IRQ lines from the GIC */ diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c index baca4d8a2d..b2a247dd15 100644 --- a/hw/intc/s390_flic.c +++ b/hw/intc/s390_flic.c @@ -63,15 +63,15 @@ void s390_flic_init(void) DeviceState *dev; if (kvm_enabled()) { - dev = qdev_create(NULL, TYPE_KVM_S390_FLIC); + dev = qdev_new(TYPE_KVM_S390_FLIC); object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC, OBJECT(dev)); } else { - dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC); + dev = qdev_new(TYPE_QEMU_S390_FLIC); object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC, OBJECT(dev)); } - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); } static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id, diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 1f2189f4d5..1c9d7e19ab 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -61,8 +61,8 @@ ISABus *isa_bus_new(DeviceState *dev, MemoryRegion* address_space, return NULL; } if (!dev) { - dev = qdev_create(NULL, "isabus-bridge"); - qdev_init_nofail(dev); + dev = qdev_new("isabus-bridge"); + qdev_realize_and_unref(dev, NULL, &error_fatal); } isabus = ISA_BUS(qbus_create(TYPE_ISA_BUS, dev, NULL)); diff --git a/hw/lm32/lm32.h b/hw/lm32/lm32.h index 98de07acf2..326238d859 100644 --- a/hw/lm32/lm32.h +++ b/hw/lm32/lm32.h @@ -3,14 +3,15 @@ #include "hw/char/lm32_juart.h" #include "hw/qdev-properties.h" +#include "qapi/error.h" static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq) { DeviceState *dev; SysBusDevice *d; - dev = qdev_create(NULL, "lm32-pic"); - qdev_init_nofail(dev); + dev = qdev_new("lm32-pic"); + qdev_realize_and_unref(dev, NULL, &error_fatal); d = SYS_BUS_DEVICE(dev); sysbus_connect_irq(d, 0, cpu_irq); @@ -21,9 +22,9 @@ static inline DeviceState *lm32_juart_init(Chardev *chr) { DeviceState *dev; - dev = qdev_create(NULL, TYPE_LM32_JUART); + dev = qdev_new(TYPE_LM32_JUART); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); return dev; } @@ -35,10 +36,10 @@ static inline DeviceState *lm32_uart_create(hwaddr addr, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "lm32-uart"); + dev = qdev_new("lm32-uart"); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); return dev; diff --git a/hw/lm32/milkymist-hw.h b/hw/lm32/milkymist-hw.h index 5f63024355..d5f15a30a1 100644 --- a/hw/lm32/milkymist-hw.h +++ b/hw/lm32/milkymist-hw.h @@ -3,6 +3,7 @@ #include "hw/qdev-core.h" #include "net/net.h" +#include "qapi/error.h" static inline DeviceState *milkymist_uart_create(hwaddr base, qemu_irq irq, @@ -10,9 +11,9 @@ static inline DeviceState *milkymist_uart_create(hwaddr base, { DeviceState *dev; - dev = qdev_create(NULL, "milkymist-uart"); + dev = qdev_new("milkymist-uart"); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); @@ -23,8 +24,8 @@ static inline DeviceState *milkymist_hpdmc_create(hwaddr base) { DeviceState *dev; - dev = qdev_create(NULL, "milkymist-hpdmc"); - qdev_init_nofail(dev); + dev = qdev_new("milkymist-hpdmc"); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; @@ -34,8 +35,8 @@ static inline DeviceState *milkymist_memcard_create(hwaddr base) { DeviceState *dev; - dev = qdev_create(NULL, "milkymist-memcard"); - qdev_init_nofail(dev); + dev = qdev_new("milkymist-memcard"); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; @@ -46,10 +47,10 @@ static inline DeviceState *milkymist_vgafb_create(hwaddr base, { DeviceState *dev; - dev = qdev_create(NULL, "milkymist-vgafb"); + dev = qdev_new("milkymist-vgafb"); qdev_prop_set_uint32(dev, "fb_offset", fb_offset); qdev_prop_set_uint32(dev, "fb_mask", fb_mask); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; @@ -62,12 +63,12 @@ static inline DeviceState *milkymist_sysctl_create(hwaddr base, { DeviceState *dev; - dev = qdev_create(NULL, "milkymist-sysctl"); + dev = qdev_new("milkymist-sysctl"); qdev_prop_set_uint32(dev, "frequency", freq_hz); qdev_prop_set_uint32(dev, "systemid", system_id); qdev_prop_set_uint32(dev, "capabilities", capabilities); qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gpio_irq); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, timer0_irq); @@ -81,8 +82,8 @@ static inline DeviceState *milkymist_pfpu_create(hwaddr base, { DeviceState *dev; - dev = qdev_create(NULL, "milkymist-pfpu"); - qdev_init_nofail(dev); + dev = qdev_new("milkymist-pfpu"); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; @@ -94,8 +95,8 @@ static inline DeviceState *milkymist_ac97_create(hwaddr base, { DeviceState *dev; - dev = qdev_create(NULL, "milkymist-ac97"); - qdev_init_nofail(dev); + dev = qdev_new("milkymist-ac97"); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, crrequest_irq); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, crreply_irq); @@ -111,9 +112,9 @@ static inline DeviceState *milkymist_minimac2_create(hwaddr base, DeviceState *dev; qemu_check_nic_model(&nd_table[0], "minimac2"); - dev = qdev_create(NULL, "milkymist-minimac2"); + dev = qdev_new("milkymist-minimac2"); qdev_set_nic_properties(dev, &nd_table[0]); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, buffers_base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq); @@ -128,10 +129,10 @@ static inline DeviceState *milkymist_softusb_create(hwaddr base, { DeviceState *dev; - dev = qdev_create(NULL, "milkymist-softusb"); + dev = qdev_new("milkymist-softusb"); qdev_prop_set_uint32(dev, "pmem_size", pmem_size); qdev_prop_set_uint32(dev, "dmem_size", dmem_size); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, pmem_base); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, dmem_base); diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 2ab9701ad6..666561d716 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -214,9 +214,9 @@ static void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd, hwaddr base, int i; qemu_check_nic_model(nd, TYPE_MCF_FEC_NET); - dev = qdev_create(NULL, TYPE_MCF_FEC_NET); + dev = qdev_new(TYPE_MCF_FEC_NET); qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); for (i = 0; i < FEC_NUM_IRQ; i++) { diff --git a/hw/m68k/mcf_intc.c b/hw/m68k/mcf_intc.c index bc20742d9a..75d6e24719 100644 --- a/hw/m68k/mcf_intc.c +++ b/hw/m68k/mcf_intc.c @@ -7,6 +7,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/module.h" #include "qemu/log.h" #include "cpu.h" @@ -204,8 +205,8 @@ qemu_irq *mcf_intc_init(MemoryRegion *sysmem, DeviceState *dev; mcf_intc_state *s; - dev = qdev_create(NULL, TYPE_MCF_INTC); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_MCF_INTC); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = MCF_INTC(dev); s->cpu = cpu; diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c index 14b99ed25d..e1e16bf9af 100644 --- a/hw/m68k/next-cube.c +++ b/hw/m68k/next-cube.c @@ -839,7 +839,7 @@ static void next_escc_init(M68kCPU *cpu) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, TYPE_ESCC); + dev = qdev_new(TYPE_ESCC); qdev_prop_set_uint32(dev, "disabled", 0); qdev_prop_set_uint32(dev, "frequency", 9600 * 384); qdev_prop_set_uint32(dev, "it_shift", 0); @@ -848,7 +848,7 @@ static void next_escc_init(M68kCPU *cpu) qdev_prop_set_chr(dev, "chrA", serial_hd(0)); qdev_prop_set_uint32(dev, "chnBtype", escc_serial); qdev_prop_set_uint32(dev, "chnAtype", escc_serial); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, ser_irq[0]); @@ -895,8 +895,8 @@ static void next_cube_init(MachineState *machine) memory_region_add_subregion(sysmem, 0x04000000, machine->ram); /* Framebuffer */ - dev = qdev_create(NULL, TYPE_NEXTFB); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_NEXTFB); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0B000000); /* MMIO */ @@ -918,8 +918,8 @@ static void next_cube_init(MachineState *machine) memory_region_add_subregion(sysmem, 0x02100000, scrmem); /* KBD */ - dev = qdev_create(NULL, TYPE_NEXTKBD); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_NEXTKBD); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0200e000); /* Load ROM here */ diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 81749e7ec6..15b7eb719a 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -218,13 +218,13 @@ static void q800_init(MachineState *machine) /* VIA */ - via_dev = qdev_create(NULL, TYPE_MAC_VIA); + via_dev = qdev_new(TYPE_MAC_VIA); dinfo = drive_get(IF_MTD, 0, 0); if (dinfo) { qdev_prop_set_drive(via_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_abort); } - qdev_init_nofail(via_dev); + qdev_realize_and_unref(via_dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(via_dev); sysbus_mmio_map(sysbus, 0, VIA_BASE); qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 0, pic[0]); @@ -232,10 +232,10 @@ static void q800_init(MachineState *machine) adb_bus = qdev_get_child_bus(via_dev, "adb.0"); - dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD); - qdev_init_nofail(dev); - dev = qdev_create(adb_bus, TYPE_ADB_MOUSE); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_ADB_KEYBOARD); + qdev_realize_and_unref(dev, adb_bus, &error_fatal); + dev = qdev_new(TYPE_ADB_MOUSE); + qdev_realize_and_unref(dev, adb_bus, &error_fatal); /* MACSONIC */ @@ -259,13 +259,13 @@ static void q800_init(MachineState *machine) nd_table[0].macaddr.a[1] = 0x00; nd_table[0].macaddr.a[2] = 0x07; - dev = qdev_create(NULL, "dp8393x"); + dev = qdev_new("dp8393x"); qdev_set_nic_properties(dev, &nd_table[0]); qdev_prop_set_uint8(dev, "it_shift", 2); qdev_prop_set_bit(dev, "big_endian", true); object_property_set_link(OBJECT(dev), OBJECT(get_system_memory()), "dma_mr", &error_abort); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sysbus, 0, SONIC_BASE); sysbus_mmio_map(sysbus, 1, SONIC_PROM_BASE); @@ -273,7 +273,7 @@ static void q800_init(MachineState *machine) /* SCC */ - dev = qdev_create(NULL, TYPE_ESCC); + dev = qdev_new(TYPE_ESCC); qdev_prop_set_uint32(dev, "disabled", 0); qdev_prop_set_uint32(dev, "frequency", MAC_CLOCK); qdev_prop_set_uint32(dev, "it_shift", 1); @@ -282,7 +282,7 @@ static void q800_init(MachineState *machine) qdev_prop_set_chr(dev, "chrB", serial_hd(1)); qdev_prop_set_uint32(dev, "chnBtype", 0); qdev_prop_set_uint32(dev, "chnAtype", 0); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); sysbus_connect_irq(sysbus, 0, pic[3]); sysbus_connect_irq(sysbus, 1, pic[3]); @@ -290,7 +290,7 @@ static void q800_init(MachineState *machine) /* SCSI */ - dev = qdev_create(NULL, TYPE_ESP); + dev = qdev_new(TYPE_ESP); sysbus_esp = ESP_STATE(dev); esp = &sysbus_esp->esp; esp->dma_memory_read = NULL; @@ -298,7 +298,7 @@ static void q800_init(MachineState *machine) esp->dma_opaque = NULL; sysbus_esp->it_shift = 4; esp->dma_enabled = 1; - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in_named(via_dev, @@ -314,14 +314,14 @@ static void q800_init(MachineState *machine) /* SWIM floppy controller */ - dev = qdev_create(NULL, TYPE_SWIM); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_SWIM); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SWIM_BASE); /* NuBus */ - dev = qdev_create(NULL, TYPE_MAC_NUBUS_BRIDGE); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_MAC_NUBUS_BRIDGE); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, NUBUS_SUPER_SLOT_BASE); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, NUBUS_SLOT_BASE); @@ -329,11 +329,11 @@ static void q800_init(MachineState *machine) /* framebuffer in nubus slot #9 */ - dev = qdev_create(BUS(nubus), TYPE_NUBUS_MACFB); + dev = qdev_new(TYPE_NUBUS_MACFB); qdev_prop_set_uint32(dev, "width", graphic_width); qdev_prop_set_uint32(dev, "height", graphic_height); qdev_prop_set_uint8(dev, "depth", graphic_depth); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, BUS(nubus), &error_fatal); cs = CPU(cpu); if (linux_boot) { diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index 05a5614a04..2e7a3fa119 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -110,9 +110,9 @@ petalogix_ml605_init(MachineState *machine) 64 * KiB, 2, 0x89, 0x18, 0x0000, 0x0, 0); - dev = qdev_create(NULL, "xlnx.xps-intc"); + dev = qdev_new("xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", 1 << TIMER_IRQ); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(cpu), MB_CPU_IRQ)); @@ -125,17 +125,17 @@ petalogix_ml605_init(MachineState *machine) DEVICE_LITTLE_ENDIAN); /* 2 timers at irq 2 @ 100 Mhz. */ - dev = qdev_create(NULL, "xlnx.xps-timer"); + dev = qdev_new("xlnx.xps-timer"); qdev_prop_set_uint32(dev, "one-timer-only", 0); qdev_prop_set_uint32(dev, "clock-frequency", 100 * 1000000); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]); /* axi ethernet and dma initialization. */ qemu_check_nic_model(&nd_table[0], "xlnx.axi-ethernet"); - eth0 = qdev_create(NULL, "xlnx.axi-ethernet"); - dma = qdev_create(NULL, "xlnx.axi-dma"); + eth0 = qdev_new("xlnx.axi-ethernet"); + dma = qdev_new("xlnx.axi-dma"); /* FIXME: attach to the sysbus instead */ object_property_add_child(qdev_get_machine(), "xilinx-eth", OBJECT(eth0)); @@ -152,7 +152,7 @@ petalogix_ml605_init(MachineState *machine) "axistream-connected", &error_abort); object_property_set_link(OBJECT(eth0), cs, "axistream-control-connected", &error_abort); - qdev_init_nofail(eth0); + qdev_realize_and_unref(eth0, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(eth0), 0, AXIENET_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(eth0), 0, irq[AXIENET_IRQ]); @@ -165,7 +165,7 @@ petalogix_ml605_init(MachineState *machine) "axistream-connected", &error_abort); object_property_set_link(OBJECT(dma), cs, "axistream-control-connected", &error_abort); - qdev_init_nofail(dma); + qdev_realize_and_unref(dma, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dma), 0, AXIDMA_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dma), 0, irq[AXIDMA_IRQ0]); sysbus_connect_irq(SYS_BUS_DEVICE(dma), 1, irq[AXIDMA_IRQ1]); @@ -173,9 +173,9 @@ petalogix_ml605_init(MachineState *machine) { SSIBus *spi; - dev = qdev_create(NULL, "xlnx.xps-spi"); + dev = qdev_new("xlnx.xps-spi"); qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, SPI_BASEADDR); sysbus_connect_irq(busdev, 0, irq[SPI_IRQ]); diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c index 0bb6cdea8d..aecee2f5f3 100644 --- a/hw/microblaze/petalogix_s3adsp1800_mmu.c +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -89,10 +89,10 @@ petalogix_s3adsp1800_init(MachineState *machine) dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, 64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1); - dev = qdev_create(NULL, "xlnx.xps-intc"); + dev = qdev_new("xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", 1 << ETHLITE_IRQ | 1 << UARTLITE_IRQ); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(cpu), MB_CPU_IRQ)); @@ -104,19 +104,19 @@ petalogix_s3adsp1800_init(MachineState *machine) serial_hd(0)); /* 2 timers at irq 2 @ 62 Mhz. */ - dev = qdev_create(NULL, "xlnx.xps-timer"); + dev = qdev_new("xlnx.xps-timer"); qdev_prop_set_uint32(dev, "one-timer-only", 0); qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]); qemu_check_nic_model(&nd_table[0], "xlnx.xps-ethernetlite"); - dev = qdev_create(NULL, "xlnx.xps-ethernetlite"); + dev = qdev_new("xlnx.xps-ethernetlite"); qdev_set_nic_properties(dev, &nd_table[0]); qdev_prop_set_uint32(dev, "tx-ping-pong", 0); qdev_prop_set_uint32(dev, "rx-ping-pong", 0); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ETHLITE_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[ETHLITE_IRQ]); diff --git a/hw/mips/boston.c b/hw/mips/boston.c index a896056be1..a34ccdf616 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -400,7 +400,7 @@ xilinx_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr, DeviceState *dev; MemoryRegion *cfg, *mmio; - dev = qdev_create(NULL, TYPE_XILINX_PCIE_HOST); + dev = qdev_new(TYPE_XILINX_PCIE_HOST); qdev_prop_set_uint32(dev, "bus_nr", bus_nr); qdev_prop_set_uint64(dev, "cfg_base", cfg_base); @@ -409,7 +409,7 @@ xilinx_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr, qdev_prop_set_uint64(dev, "mmio_size", mmio_size); qdev_prop_set_bit(dev, "link_up", link_up); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); cfg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion_overlap(sys_mem, cfg_base, cfg, 0); @@ -441,8 +441,8 @@ static void boston_mach_init(MachineState *machine) exit(1); } - dev = qdev_create(NULL, TYPE_MIPS_BOSTON); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_MIPS_BOSTON); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = BOSTON(dev); s->mach = machine; diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index b2ea13f09d..37750b8037 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/units.h" #include "qemu/log.h" #include "hw/mips/mips.h" @@ -1201,7 +1202,7 @@ PCIBus *gt64120_register(qemu_irq *pic) PCIHostState *phb; DeviceState *dev; - dev = qdev_create(NULL, TYPE_GT64120_PCI_HOST_BRIDGE); + dev = qdev_new(TYPE_GT64120_PCI_HOST_BRIDGE); d = GT64120_PCI_HOST_BRIDGE(dev); phb = PCI_HOST_BRIDGE(dev); memory_region_init(&d->pci0_mem, OBJECT(dev), "pci0-mem", 4 * GiB); @@ -1212,7 +1213,7 @@ PCIBus *gt64120_register(qemu_irq *pic) &d->pci0_mem, get_system_io(), PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); memory_region_init_io(&d->ISD_mem, OBJECT(dev), &isd_mem_ops, d, "isd-mem", 0x1000); diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index afea52b41b..fb975bd1c7 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -255,8 +255,8 @@ static void mips_jazz_init(MachineState *machine, /* Video card */ switch (jazz_model) { case JAZZ_MAGNUM: - dev = qdev_create(NULL, "sysbus-g364"); - qdev_init_nofail(dev); + dev = qdev_new("sysbus-g364"); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sysbus, 0, 0x60080000); sysbus_mmio_map(sysbus, 1, 0x40000000); @@ -287,12 +287,12 @@ static void mips_jazz_init(MachineState *machine, if (strcmp(nd->model, "dp83932") == 0) { qemu_check_nic_model(nd, "dp83932"); - dev = qdev_create(NULL, "dp8393x"); + dev = qdev_new("dp8393x"); qdev_set_nic_properties(dev, nd); qdev_prop_set_uint8(dev, "it_shift", 2); object_property_set_link(OBJECT(dev), OBJECT(rc4030_dma_mr), "dma_mr", &error_abort); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sysbus, 0, 0x80001000); sysbus_mmio_map(sysbus, 1, 0x8000b000); @@ -308,7 +308,7 @@ static void mips_jazz_init(MachineState *machine, } /* SCSI adapter */ - dev = qdev_create(NULL, TYPE_ESP); + dev = qdev_new(TYPE_ESP); sysbus_esp = ESP_STATE(dev); esp = &sysbus_esp->esp; esp->dma_memory_read = rc4030_dma_read; @@ -317,7 +317,7 @@ static void mips_jazz_init(MachineState *machine, sysbus_esp->it_shift = 0; /* XXX for now until rc4030 has been changed to use DMA enable signal */ esp->dma_enabled = 1; - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 5)); @@ -362,8 +362,8 @@ static void mips_jazz_init(MachineState *machine, /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */ /* NVRAM */ - dev = qdev_create(NULL, "ds1225y"); - qdev_init_nofail(dev); + dev = qdev_new("ds1225y"); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sysbus, 0, 0x80009000); diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 62063b2305..cfc236a1da 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -1233,7 +1233,7 @@ void mips_malta_init(MachineState *machine) int fl_idx = 0; int be; - DeviceState *dev = qdev_create(NULL, TYPE_MIPS_MALTA); + DeviceState *dev = qdev_new(TYPE_MIPS_MALTA); MaltaState *s = MIPS_MALTA(dev); /* @@ -1243,7 +1243,7 @@ void mips_malta_init(MachineState *machine) */ empty_slot_init("GT64120", 0, 0x20000000); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* create CPU */ mips_create_cpu(machine, s, &cbus_irq, &i8259_irq); diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c index d220318939..72b1e846af 100644 --- a/hw/mips/mipssim.c +++ b/hw/mips/mipssim.c @@ -129,9 +129,9 @@ static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "mipsnet"); + dev = qdev_new("mipsnet"); qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); @@ -216,11 +216,11 @@ mips_mipssim_init(MachineState *machine) * MIPS CPU INT2, which is interrupt 4. */ if (serial_hd(0)) { - DeviceState *dev = qdev_create(NULL, TYPE_SERIAL_IO); + DeviceState *dev = qdev_new(TYPE_SERIAL_IO); qdev_prop_set_chr(dev, "chardev", serial_hd(0)); qdev_set_legacy_instance_id(dev, 0x3f8, 2); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, env->irq[4]); sysbus_add_io(SYS_BUS_DEVICE(dev), 0x3f8, sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); diff --git a/hw/misc/empty_slot.c b/hw/misc/empty_slot.c index b568ae202b..eb2aec731e 100644 --- a/hw/misc/empty_slot.c +++ b/hw/misc/empty_slot.c @@ -13,6 +13,7 @@ #include "hw/sysbus.h" #include "hw/qdev-properties.h" #include "hw/misc/empty_slot.h" +#include "qapi/error.h" #include "trace.h" #define TYPE_EMPTY_SLOT "empty_slot" @@ -56,10 +57,10 @@ void empty_slot_init(const char *name, hwaddr addr, uint64_t slot_size) /* Only empty slots larger than 0 byte need handling. */ DeviceState *dev; - dev = qdev_create(NULL, TYPE_EMPTY_SLOT); + dev = qdev_new(TYPE_EMPTY_SLOT); qdev_prop_set_uint64(dev, "size", slot_size); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(dev), 0, addr, -10000); } diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c index 27fd069b96..7e98cbda87 100644 --- a/hw/net/etraxfs_eth.c +++ b/hw/net/etraxfs_eth.c @@ -654,7 +654,7 @@ etraxfs_eth_init(NICInfo *nd, hwaddr base, int phyaddr, DeviceState *dev; qemu_check_nic_model(nd, "fseth"); - dev = qdev_create(NULL, "etraxfs-eth"); + dev = qdev_new("etraxfs-eth"); qdev_set_nic_properties(dev, nd); qdev_prop_set_uint32(dev, "phyaddr", phyaddr); @@ -668,7 +668,7 @@ etraxfs_eth_init(NICInfo *nd, hwaddr base, int phyaddr, */ ETRAX_FS_ETH(dev)->dma_out = dma_out; ETRAX_FS_ETH(dev)->dma_in = dma_in; - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index 475f3c887a..d0e9ff57ca 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -33,6 +33,7 @@ #include "hw/qdev-properties.h" #include "etsec.h" #include "registers.h" +#include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" @@ -452,9 +453,9 @@ DeviceState *etsec_create(hwaddr base, { DeviceState *dev; - dev = qdev_create(NULL, "eTSEC"); + dev = qdev_new("eTSEC"); qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq); diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index da7e0bb0e8..81c32c8107 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -20,6 +20,7 @@ #include "hw/net/lan9118.h" #include "hw/ptimer.h" #include "hw/qdev-properties.h" +#include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" /* For crc32 */ @@ -1394,9 +1395,9 @@ void lan9118_init(NICInfo *nd, uint32_t base, qemu_irq irq) SysBusDevice *s; qemu_check_nic_model(nd, "lan9118"); - dev = qdev_create(NULL, TYPE_LAN9118); + dev = qdev_new(TYPE_LAN9118); qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); diff --git a/hw/net/lasi_i82596.c b/hw/net/lasi_i82596.c index 5e0fd69763..1870507727 100644 --- a/hw/net/lasi_i82596.c +++ b/hw/net/lasi_i82596.c @@ -11,6 +11,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/timer.h" #include "hw/sysbus.h" #include "net/eth.h" @@ -126,11 +127,11 @@ SysBusI82596State *lasi_82596_init(MemoryRegion *addr_space, .a = { 0x08, 0x00, 0x09, 0xef, 0x34, 0xf6 } }; qemu_check_nic_model(&nd_table[0], TYPE_LASI_82596); - dev = qdev_create(NULL, TYPE_LASI_82596); + dev = qdev_new(TYPE_LASI_82596); s = SYSBUS_I82596(dev); s->state.irq = lan_irq; qdev_set_nic_properties(dev, &nd_table[0]); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s->state.conf.macaddr = HP_MAC; /* set HP MAC prefix */ /* LASI 82596 ports in main memory. */ diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c index b3240b9335..9b616fe62a 100644 --- a/hw/net/smc91c111.c +++ b/hw/net/smc91c111.c @@ -14,6 +14,7 @@ #include "hw/irq.h" #include "hw/net/smc91c111.h" #include "hw/qdev-properties.h" +#include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" /* For crc32 */ @@ -821,9 +822,9 @@ void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) SysBusDevice *s; qemu_check_nic_model(nd, "smc91c111"); - dev = qdev_create(NULL, TYPE_SMC91C111); + dev = qdev_new(TYPE_SMC91C111); qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 968a1ce78e..4cd02dda01 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -372,11 +372,11 @@ void spapr_vlan_create(SpaprVioBus *bus, NICInfo *nd) { DeviceState *dev; - dev = qdev_create(&bus->bus, "spapr-vlan"); + dev = qdev_new("spapr-vlan"); qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, &bus->bus, &error_fatal); } static int spapr_vlan_devnode(SpaprVioDevice *dev, void *fdt, int node_off) diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c index 4c60a27fb7..3d304d724a 100644 --- a/hw/nios2/10m50_devboard.c +++ b/hw/nios2/10m50_devboard.c @@ -80,9 +80,9 @@ static void nios2_10m50_ghrd_init(MachineState *machine) cpu_irq = nios2_cpu_pic_init(cpu); /* Register: Internal Interrupt Controller (IIC) */ - dev = qdev_create(NULL, "altera,iic"); + dev = qdev_new("altera,iic"); object_property_add_const_link(OBJECT(dev), "cpu", OBJECT(cpu)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]); for (i = 0; i < 32; i++) { irq[i] = qdev_get_gpio_in(dev, i); @@ -93,16 +93,16 @@ static void nios2_10m50_ghrd_init(MachineState *machine) serial_hd(0), DEVICE_NATIVE_ENDIAN); /* Register: Timer sys_clk_timer */ - dev = qdev_create(NULL, "ALTR.timer"); + dev = qdev_new("ALTR.timer"); qdev_prop_set_uint32(dev, "clock-frequency", 75 * 1000000); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xf8001440); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[0]); /* Register: Timer sys_clk_timer_1 */ - dev = qdev_create(NULL, "ALTR.timer"); + dev = qdev_new("ALTR.timer"); qdev_prop_set_uint32(dev, "clock-frequency", 75 * 1000000); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xe0000880); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[5]); diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 8dd50c2c72..fbcaf66002 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -1099,14 +1099,14 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, FWCfgState *s; bool dma_requested = dma_iobase && dma_as; - dev = qdev_create(NULL, TYPE_FW_CFG_IO); + dev = qdev_new(TYPE_FW_CFG_IO); if (!dma_requested) { qdev_prop_set_bit(dev, "dma_enabled", false); } object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sbd = SYS_BUS_DEVICE(dev); ios = FW_CFG_IO(dev); @@ -1138,7 +1138,7 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, FWCfgState *s; bool dma_requested = dma_addr && dma_as; - dev = qdev_create(NULL, TYPE_FW_CFG_MEM); + dev = qdev_new(TYPE_FW_CFG_MEM); qdev_prop_set_uint32(dev, "data_width", data_width); if (!dma_requested) { qdev_prop_set_bit(dev, "dma_enabled", false); @@ -1146,7 +1146,7 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sbd = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sbd, 0, ctl_addr); diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 02f5259e5e..ba1a11442f 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -59,9 +59,9 @@ static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, SysBusDevice *s; int i; - dev = qdev_create(NULL, "open_eth"); + dev = qdev_new("open_eth"); qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); for (i = 0; i < num_cpus; i++) { @@ -78,9 +78,9 @@ static void openrisc_sim_ompic_init(hwaddr base, int num_cpus, SysBusDevice *s; int i; - dev = qdev_create(NULL, "or1k-ompic"); + dev = qdev_new("or1k-ompic"); qdev_prop_set_uint32(dev, "num-cpus", num_cpus); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); for (i = 0; i < num_cpus; i++) { diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 47aaaf8fd1..5da0d21061 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -231,7 +231,7 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) dev_name = dev->qdev.id; } - ds = qdev_create(NULL, TYPE_PXB_HOST); + ds = qdev_new(TYPE_PXB_HOST); if (pcie) { bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_PCIE_BUS); } else { @@ -255,7 +255,7 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) goto err_register_bus; } - qdev_init_nofail(ds); + qdev_realize_and_unref(ds, NULL, &error_fatal); if (bds) { qdev_init_nofail(bds); } diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index f9697dcc43..546ac84cf4 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -40,6 +40,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "hw/pci/pci.h" #include "hw/irq.h" @@ -743,11 +744,11 @@ PCIBus *bonito_init(qemu_irq *pic) PCIBonitoState *s; PCIDevice *d; - dev = qdev_create(NULL, TYPE_BONITO_PCI_HOST_BRIDGE); + dev = qdev_new(TYPE_BONITO_PCI_HOST_BRIDGE); phb = PCI_HOST_BRIDGE(dev); pcihost = BONITO_PCI_HOST_BRIDGE(dev); pcihost->pic = pic; - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); d = pci_create(phb->bus, PCI_DEVFN(0, 0), TYPE_PCI_BONITO); s = PCI_BONITO(d); diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c index aefb416c8f..09c0d2f4e8 100644 --- a/hw/pci-host/i440fx.c +++ b/hw/pci-host/i440fx.c @@ -271,13 +271,13 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, unsigned i; I440FXState *i440fx; - dev = qdev_create(NULL, host_type); + dev = qdev_new(host_type); s = PCI_HOST_BRIDGE(dev); b = pci_root_bus_new(dev, NULL, pci_address_space, address_space_io, 0, TYPE_PCI_BUS); s->bus = b; object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); d = pci_create_simple(b, 0, pci_type); *pi440fx_state = I440FX_PCI_DEVICE(d); diff --git a/hw/pcmcia/pxa2xx.c b/hw/pcmcia/pxa2xx.c index 8667244df4..90f540209d 100644 --- a/hw/pcmcia/pxa2xx.c +++ b/hw/pcmcia/pxa2xx.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "hw/irq.h" #include "hw/sysbus.h" +#include "qapi/error.h" #include "qemu/module.h" #include "hw/pcmcia.h" #include "hw/arm/pxa.h" @@ -147,11 +148,11 @@ PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem, DeviceState *dev; PXA2xxPCMCIAState *s; - dev = qdev_create(NULL, TYPE_PXA2XX_PCMCIA); + dev = qdev_new(TYPE_PXA2XX_PCMCIA); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); s = PXA2XX_PCMCIA(dev); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); return s; } diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 2a0b66a152..06f4a38266 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -743,12 +743,12 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms, unsigned int smp_cpus = machine->smp.cpus; const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); - dev = qdev_create(NULL, TYPE_OPENPIC); + dev = qdev_new(TYPE_OPENPIC); object_property_add_child(OBJECT(machine), "pic", OBJECT(dev)); qdev_prop_set_uint32(dev, "model", pmc->mpic_version); qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); k = 0; @@ -768,10 +768,10 @@ static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc, DeviceState *dev; CPUState *cs; - dev = qdev_create(NULL, TYPE_KVM_OPENPIC); + dev = qdev_new(TYPE_KVM_OPENPIC); qdev_prop_set_uint32(dev, "model", pmc->mpic_version); - object_property_set_bool(OBJECT(dev), true, "realized", &err); + qdev_realize_and_unref(dev, NULL, &err); if (err) { error_propagate(errp, err); object_unparent(OBJECT(dev)); @@ -913,10 +913,10 @@ void ppce500_init(MachineState *machine) /* Register Memory */ memory_region_add_subregion(address_space_mem, 0, machine->ram); - dev = qdev_create(NULL, "e500-ccsr"); + dev = qdev_new("e500-ccsr"); object_property_add_child(qdev_get_machine(), "e500-ccsr", OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); ccsr = CCSR(dev); ccsr_addr_space = &ccsr->ccsr_space; memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base, @@ -937,9 +937,9 @@ void ppce500_init(MachineState *machine) serial_hd(1), DEVICE_BIG_ENDIAN); } /* I2C */ - dev = qdev_create(NULL, "mpc-i2c"); + dev = qdev_new("mpc-i2c"); s = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ)); memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET, sysbus_mmio_get_region(s, 0)); @@ -948,18 +948,18 @@ void ppce500_init(MachineState *machine) /* General Utility device */ - dev = qdev_create(NULL, "mpc8544-guts"); - qdev_init_nofail(dev); + dev = qdev_new("mpc8544-guts"); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET, sysbus_mmio_get_region(s, 0)); /* PCI */ - dev = qdev_create(NULL, "e500-pcihost"); + dev = qdev_new("e500-pcihost"); object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev)); qdev_prop_set_uint32(dev, "first_slot", pmc->pci_first_slot); qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); for (i = 0; i < PCI_NUM_PINS; i++) { sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i])); @@ -985,9 +985,9 @@ void ppce500_init(MachineState *machine) if (pmc->has_mpc8xxx_gpio) { qemu_irq poweroff_irq; - dev = qdev_create(NULL, "mpc8xxx_gpio"); + dev = qdev_new("mpc8xxx_gpio"); s = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ)); memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET, sysbus_mmio_get_region(s, 0)); @@ -999,11 +999,11 @@ void ppce500_init(MachineState *machine) /* Platform Bus Device */ if (pmc->has_platform_bus) { - dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE); + dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); dev->id = TYPE_PLATFORM_BUS_DEVICE; qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs); qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); pms->pbus_dev = PLATFORM_BUS_DEVICE(dev); s = SYS_BUS_DEVICE(pms->pbus_dev); diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 3507f26f6e..69281d7834 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -242,8 +242,8 @@ static void ppc_core99_init(MachineState *machine) } /* UniN init */ - dev = qdev_create(NULL, TYPE_UNI_NORTH); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_UNI_NORTH); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); memory_region_add_subregion(get_system_memory(), 0xf8000000, sysbus_mmio_get_region(s, 0)); @@ -288,9 +288,9 @@ static void ppc_core99_init(MachineState *machine) } } - pic_dev = qdev_create(NULL, TYPE_OPENPIC); + pic_dev = qdev_new(TYPE_OPENPIC); qdev_prop_set_uint32(pic_dev, "model", OPENPIC_MODEL_KEYLARGO); - qdev_init_nofail(pic_dev); + qdev_realize_and_unref(pic_dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(pic_dev); k = 0; for (i = 0; i < smp_cpus; i++) { @@ -303,10 +303,10 @@ static void ppc_core99_init(MachineState *machine) if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) { /* 970 gets a U3 bus */ /* Uninorth AGP bus */ - dev = qdev_create(NULL, TYPE_U3_AGP_HOST_BRIDGE); + dev = qdev_new(TYPE_U3_AGP_HOST_BRIDGE); object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", &error_abort); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); uninorth_pci = U3_AGP_HOST_BRIDGE(dev); s = SYS_BUS_DEVICE(dev); /* PCI hole */ @@ -322,29 +322,29 @@ static void ppc_core99_init(MachineState *machine) } else { /* Use values found on a real PowerMac */ /* Uninorth AGP bus */ - dev = qdev_create(NULL, TYPE_UNI_NORTH_AGP_HOST_BRIDGE); + dev = qdev_new(TYPE_UNI_NORTH_AGP_HOST_BRIDGE); object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", &error_abort); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, 0xf0800000); sysbus_mmio_map(s, 1, 0xf0c00000); /* Uninorth internal bus */ - dev = qdev_create(NULL, TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE); + dev = qdev_new(TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE); object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", &error_abort); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, 0xf4800000); sysbus_mmio_map(s, 1, 0xf4c00000); /* Uninorth main bus */ - dev = qdev_create(NULL, TYPE_UNI_NORTH_PCI_HOST_BRIDGE); + dev = qdev_new(TYPE_UNI_NORTH_PCI_HOST_BRIDGE); qdev_prop_set_uint32(dev, "ofw-addr", 0xf2000000); object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", &error_abort); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); uninorth_pci = UNI_NORTH_PCI_HOST_BRIDGE(dev); s = SYS_BUS_DEVICE(dev); /* PCI hole */ @@ -403,13 +403,13 @@ static void ppc_core99_init(MachineState *machine) } adb_bus = qdev_get_child_bus(dev, "adb.0"); - dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD); + dev = qdev_new(TYPE_ADB_KEYBOARD); qdev_prop_set_bit(dev, "disable-direct-reg3-writes", true); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, adb_bus, &error_fatal); - dev = qdev_create(adb_bus, TYPE_ADB_MOUSE); + dev = qdev_new(TYPE_ADB_MOUSE); qdev_prop_set_bit(dev, "disable-direct-reg3-writes", true); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, adb_bus, &error_fatal); } if (machine->usb) { @@ -441,22 +441,22 @@ static void ppc_core99_init(MachineState *machine) move the NVRAM out of ROM again for KVM */ nvram_addr = 0xFFE00000; } - dev = qdev_create(NULL, TYPE_MACIO_NVRAM); + dev = qdev_new(TYPE_MACIO_NVRAM); qdev_prop_set_uint32(dev, "size", 0x2000); qdev_prop_set_uint32(dev, "it_shift", 1); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, nvram_addr); nvr = MACIO_NVRAM(dev); pmac_format_nvram_partition(nvr, 0x2000); /* No PCI init: the BIOS will do it */ - dev = qdev_create(NULL, TYPE_FW_CFG_MEM); + dev = qdev_new(TYPE_FW_CFG_MEM); fw_cfg = FW_CFG(dev); qdev_prop_set_uint32(dev, "data_width", 1); qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(fw_cfg)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, CFG_ADDR); sysbus_mmio_map(s, 1, CFG_ADDR + 2); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 0b4c1c6373..cfc2eae1d9 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -222,8 +222,8 @@ static void ppc_heathrow_init(MachineState *machine) } /* XXX: we register only 1 output pin for heathrow PIC */ - pic_dev = qdev_create(NULL, TYPE_HEATHROW); - qdev_init_nofail(pic_dev); + pic_dev = qdev_new(TYPE_HEATHROW); + qdev_realize_and_unref(pic_dev, NULL, &error_fatal); /* Connect the heathrow PIC outputs to the 6xx bus */ for (i = 0; i < smp_cpus; i++) { @@ -252,11 +252,11 @@ static void ppc_heathrow_init(MachineState *machine) } /* Grackle PCI host bridge */ - dev = qdev_create(NULL, TYPE_GRACKLE_PCI_HOST_BRIDGE); + dev = qdev_new(TYPE_GRACKLE_PCI_HOST_BRIDGE); qdev_prop_set_uint32(dev, "ofw-addr", 0x80000000); object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", &error_abort); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, GRACKLE_BASE); sysbus_mmio_map(s, 1, GRACKLE_BASE + 0x200000); @@ -295,10 +295,10 @@ static void ppc_heathrow_init(MachineState *machine) dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda")); adb_bus = qdev_get_child_bus(dev, "adb.0"); - dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD); - qdev_init_nofail(dev); - dev = qdev_create(adb_bus, TYPE_ADB_MOUSE); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_ADB_KEYBOARD); + qdev_realize_and_unref(dev, adb_bus, &error_fatal); + dev = qdev_new(TYPE_ADB_MOUSE); + qdev_realize_and_unref(dev, adb_bus, &error_fatal); if (machine_usb(machine)) { pci_create_simple(pci_bus, -1, "pci-ohci"); @@ -309,13 +309,13 @@ static void ppc_heathrow_init(MachineState *machine) /* No PCI init: the BIOS will do it */ - dev = qdev_create(NULL, TYPE_FW_CFG_MEM); + dev = qdev_new(TYPE_FW_CFG_MEM); fw_cfg = FW_CFG(dev); qdev_prop_set_uint32(dev, "data_width", 1); qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(fw_cfg)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, CFG_ADDR); sysbus_mmio_map(s, 1, CFG_ADDR + 2); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 9d1a11adb7..e3b6f0b884 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -729,12 +729,12 @@ static void pnv_init(MachineState *machine) /* * Create our simple PNOR device */ - dev = qdev_create(NULL, TYPE_PNV_PNOR); + dev = qdev_new(TYPE_PNV_PNOR); if (pnor) { qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(pnor), &error_abort); } - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); pnv->pnor = PNV_PNOR(dev); /* load skiboot firmware */ diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index dc318c7aa7..c1cf8d0f46 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -1367,13 +1367,13 @@ void ppc460ex_pcie_init(CPUPPCState *env) { DeviceState *dev; - dev = qdev_create(NULL, TYPE_PPC460EX_PCIE_HOST); + dev = qdev_new(TYPE_PPC460EX_PCIE_HOST); qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE0_BASE); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env); - dev = qdev_create(NULL, TYPE_PPC460EX_PCIE_HOST); + dev = qdev_new(TYPE_PPC460EX_PCIE_HOST); qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE1_BASE); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env); } diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 9266453dd9..c7af0e16c3 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -35,6 +35,7 @@ #include "hw/pci/pci_host.h" #include "hw/ppc/ppc.h" #include "hw/boards.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/log.h" #include "hw/irq.h" @@ -268,7 +269,7 @@ static void ibm_40p_init(MachineState *machine) qemu_register_reset(ppc_prep_reset, cpu); /* PCI host */ - dev = qdev_create(NULL, "raven-pcihost"); + dev = qdev_new("raven-pcihost"); if (!bios_name) { bios_name = "openbios-ppc"; } @@ -276,7 +277,7 @@ static void ibm_40p_init(MachineState *machine) qdev_prop_set_uint32(dev, "elf-machine", PPC_ELF_MACHINE); pcihost = SYS_BUS_DEVICE(dev); object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0")); if (!pci_bus) { error_report("could not create PCI host controller"); @@ -338,13 +339,13 @@ static void ibm_40p_init(MachineState *machine) } /* Prepare firmware configuration for OpenBIOS */ - dev = qdev_create(NULL, TYPE_FW_CFG_MEM); + dev = qdev_new(TYPE_FW_CFG_MEM); fw_cfg = FW_CFG(dev); qdev_prop_set_uint32(dev, "data_width", 1); qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(fw_cfg)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, CFG_ADDR); sysbus_mmio_map(s, 1, CFG_ADDR + 2); diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 42a8c9fb7f..503bd21728 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -370,10 +370,10 @@ static void sam460ex_init(MachineState *machine) /* USB */ sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400, uic[2][29]); - dev = qdev_create(NULL, "sysbus-ohci"); + dev = qdev_new("sysbus-ohci"); qdev_prop_set_string(dev, "masterbus", "usb-bus.0"); qdev_prop_set_uint32(dev, "num-ports", 6); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sbdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sbdev, 0, 0x4bffd0000); sysbus_connect_irq(sbdev, 0, uic[2][30]); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 6a315c0dc8..1228aeb4b0 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1712,7 +1712,7 @@ static void spapr_machine_reset(MachineState *machine) static void spapr_create_nvram(SpaprMachineState *spapr) { - DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram"); + DeviceState *dev = qdev_new("spapr-nvram"); DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0); if (dinfo) { @@ -1720,7 +1720,7 @@ static void spapr_create_nvram(SpaprMachineState *spapr) &error_fatal); } - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, &spapr->vio_bus->bus, &error_fatal); spapr->nvram = (struct SpaprNvram *)dev; } @@ -2640,9 +2640,9 @@ static PCIHostState *spapr_create_default_phb(void) { DeviceState *dev; - dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE); + dev = qdev_new(TYPE_SPAPR_PCI_HOST_BRIDGE); qdev_prop_set_uint32(dev, "index", 0); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); return PCI_HOST_BRIDGE(dev); } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 0c594aa72e..f2ade64e7d 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -325,7 +325,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) DeviceState *dev; int i; - dev = qdev_create(NULL, TYPE_SPAPR_XIVE); + dev = qdev_new(TYPE_SPAPR_XIVE); qdev_prop_set_uint32(dev, "nr-irqs", smc->nr_xirqs + SPAPR_XIRQ_BASE); /* * 8 XIVE END structures per CPU. One for each available @@ -334,7 +334,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3); object_property_set_link(OBJECT(dev), OBJECT(spapr), "xive-fabric", &error_abort); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); spapr->xive = SPAPR_XIVE(dev); diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 0b085eabe4..61558db1bf 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -576,8 +576,8 @@ SpaprVioBus *spapr_vio_bus_init(void) DeviceState *dev; /* Create bridge device */ - dev = qdev_create(NULL, TYPE_SPAPR_VIO_BRIDGE); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_SPAPR_VIO_BRIDGE); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* Create bus on bridge device */ qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index 0dacfcd236..f28a69c0f9 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -36,6 +36,7 @@ #include "sysemu/device_tree.h" #include "hw/loader.h" #include "elf.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/option.h" @@ -228,9 +229,9 @@ static void virtex_init(MachineState *machine) 64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1); cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT]; - dev = qdev_create(NULL, "xlnx.xps-intc"); + dev = qdev_new("xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", 0); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]); for (i = 0; i < 32; i++) { @@ -241,10 +242,10 @@ static void virtex_init(MachineState *machine) 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); /* 2 timers at irq 2 @ 62 Mhz. */ - dev = qdev_create(NULL, "xlnx.xps-timer"); + dev = qdev_new("xlnx.xps-timer"); qdev_prop_set_uint32(dev, "one-timer-only", 0); qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]); diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c index e933d35092..729fce0a58 100644 --- a/hw/riscv/sifive_clint.c +++ b/hw/riscv/sifive_clint.c @@ -20,6 +20,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/module.h" #include "hw/sysbus.h" @@ -245,13 +246,13 @@ DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, uint32_t num_harts, env->timecmp = 0; } - DeviceState *dev = qdev_create(NULL, TYPE_SIFIVE_CLINT); + DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT); qdev_prop_set_uint32(dev, "num-harts", num_harts); qdev_prop_set_uint32(dev, "sip-base", sip_base); qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base); qdev_prop_set_uint32(dev, "time-base", time_base); qdev_prop_set_uint32(dev, "aperture-size", size); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); return dev; } diff --git a/hw/riscv/sifive_e_prci.c b/hw/riscv/sifive_e_prci.c index a1c0d44f18..423af22ecc 100644 --- a/hw/riscv/sifive_e_prci.c +++ b/hw/riscv/sifive_e_prci.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" +#include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" #include "hw/hw.h" @@ -117,8 +118,8 @@ type_init(sifive_e_prci_register_types) */ DeviceState *sifive_e_prci_create(hwaddr addr) { - DeviceState *dev = qdev_create(NULL, TYPE_SIFIVE_E_PRCI); - qdev_init_nofail(dev); + DeviceState *dev = qdev_new(TYPE_SIFIVE_E_PRCI); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); return dev; } diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c index c1e04cbb98..203fec8e48 100644 --- a/hw/riscv/sifive_plic.c +++ b/hw/riscv/sifive_plic.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" #include "qemu/error-report.h" @@ -494,7 +495,7 @@ DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, uint32_t context_base, uint32_t context_stride, uint32_t aperture_size) { - DeviceState *dev = qdev_create(NULL, TYPE_SIFIVE_PLIC); + DeviceState *dev = qdev_new(TYPE_SIFIVE_PLIC); assert(enable_stride == (enable_stride & -enable_stride)); assert(context_stride == (context_stride & -context_stride)); qdev_prop_set_string(dev, "hart-config", hart_config); @@ -507,7 +508,7 @@ DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, qdev_prop_set_uint32(dev, "context-base", context_base); qdev_prop_set_uint32(dev, "context-stride", context_stride); qdev_prop_set_uint32(dev, "aperture-size", aperture_size); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); return dev; } diff --git a/hw/riscv/sifive_test.c b/hw/riscv/sifive_test.c index 339195c6ff..596757f714 100644 --- a/hw/riscv/sifive_test.c +++ b/hw/riscv/sifive_test.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" +#include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" #include "sysemu/runstate.h" @@ -92,8 +93,8 @@ type_init(sifive_test_register_types) */ DeviceState *sifive_test_create(hwaddr addr) { - DeviceState *dev = qdev_create(NULL, TYPE_SIFIVE_TEST); - qdev_init_nofail(dev); + DeviceState *dev = qdev_new(TYPE_SIFIVE_TEST); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); return dev; } diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index d569b38d1b..fa88e9118c 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -443,9 +443,9 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, qemu_irq irq; int i; - dev = qdev_create(NULL, TYPE_GPEX_HOST); + dev = qdev_new(TYPE_GPEX_HOST); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); ecam_alias = g_new0(MemoryRegion, 1); ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); diff --git a/hw/rtc/m48t59.c b/hw/rtc/m48t59.c index 47d48054fd..f6acf416ff 100644 --- a/hw/rtc/m48t59.c +++ b/hw/rtc/m48t59.c @@ -33,6 +33,7 @@ #include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" +#include "qapi/error.h" #include "qemu/bcd.h" #include "qemu/module.h" #include "trace.h" @@ -579,9 +580,9 @@ Nvram *m48t59_init(qemu_irq IRQ, hwaddr mem_base, continue; } - dev = qdev_create(NULL, m48txx_sysbus_info[i].bus_name); + dev = qdev_new(m48txx_sysbus_info[i].bus_name); qdev_prop_set_int32(dev, "base-year", base_year); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, IRQ); if (io_base != 0) { diff --git a/hw/rtc/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c index ada01b5774..ed1c10832f 100644 --- a/hw/rtc/sun4v-rtc.c +++ b/hw/rtc/sun4v-rtc.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" +#include "qapi/error.h" #include "qemu/module.h" #include "qemu/timer.h" #include "hw/rtc/sun4v-rtc.h" @@ -55,10 +56,10 @@ void sun4v_rtc_init(hwaddr addr) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, TYPE_SUN4V_RTC); + dev = qdev_new(TYPE_SUN4V_RTC); s = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(s, 0, addr); } diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c index d0dbd0f1b6..974c97f454 100644 --- a/hw/s390x/ap-bridge.c +++ b/hw/s390x/ap-bridge.c @@ -49,10 +49,10 @@ void s390_init_ap(void) } /* Create bridge device */ - dev = qdev_create(NULL, TYPE_AP_BRIDGE); + dev = qdev_new(TYPE_AP_BRIDGE); object_property_add_child(qdev_get_machine(), TYPE_AP_BRIDGE, OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* Create bus on bridge device */ bus = qbus_create(TYPE_AP_BUS, dev, TYPE_AP_BUS); diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index 813bfc768a..a0dd2da0b8 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -101,10 +101,10 @@ VirtualCssBus *virtual_css_bus_init(void) DeviceState *dev; /* Create bridge device */ - dev = qdev_create(NULL, TYPE_VIRTUAL_CSS_BRIDGE); + dev = qdev_new(TYPE_VIRTUAL_CSS_BRIDGE); object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE, OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* Create bus on bridge device */ bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 60b16fef77..fb68c5a437 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -227,9 +227,9 @@ static void s390_create_virtio_net(BusState *bus, const char *name) qemu_check_nic_model(nd, "virtio"); - dev = qdev_create(bus, name); + dev = qdev_new(name); qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, bus, &error_fatal); } } @@ -237,9 +237,9 @@ static void s390_create_sclpconsole(const char *type, Chardev *chardev) { DeviceState *dev; - dev = qdev_create(sclp_get_event_facility_bus(), type); + dev = qdev_new(type); qdev_prop_set_chr(dev, "chardev", chardev); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, sclp_get_event_facility_bus(), &error_fatal); } static void ccw_init(MachineState *machine) @@ -269,10 +269,10 @@ static void ccw_init(MachineState *machine) machine->initrd_filename, "s390-ccw.img", "s390-netboot.img", true); - dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); + dev = qdev_new(TYPE_S390_PCI_HOST_BRIDGE); object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE, OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* register hypercalls */ virtio_ccw_register_hcalls(); diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 2836f807a0..1a7320c0af 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -261,7 +261,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, driver = "scsi-hd"; } } - dev = qdev_create(&bus->qbus, driver); + dev = qdev_new(driver); name = g_strdup_printf("legacy[%d]", unit); object_property_add_child(OBJECT(bus), name, OBJECT(dev)); g_free(name); @@ -293,7 +293,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, qdev_prop_set_enum(dev, "rerror", rerror); qdev_prop_set_enum(dev, "werror", werror); - object_property_set_bool(OBJECT(dev), true, "realized", &err); + qdev_realize_and_unref(dev, &bus->qbus, &err); if (err != NULL) { error_propagate(errp, err); object_unparent(OBJECT(dev)); diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 923488beb2..d17dc03c73 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -1225,9 +1225,9 @@ void spapr_vscsi_create(SpaprVioBus *bus) { DeviceState *dev; - dev = qdev_create(&bus->bus, "spapr-vscsi"); + dev = qdev_new("spapr-vscsi"); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, &bus->bus, &error_fatal); scsi_bus_legacy_handle_cmdline(&VIO_SPAPR_VSCSI_DEVICE(dev)->bus); } diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index 926e1af475..4cfdf7b64c 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -278,9 +278,9 @@ static void milkymist_memcard_realize(DeviceState *dev, Error **errp) /* FIXME use a qdev drive property instead of drive_get_next() */ dinfo = drive_get_next(IF_SD); blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; - carddev = qdev_create(BUS(&s->sdbus), TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &err); - object_property_set_bool(OBJECT(carddev), true, "realized", &err); + qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err); if (err) { error_setg(errp, "failed to init SD card: %s", error_get_pretty(err)); return; diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index c32df1b8f9..89784407b9 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -485,23 +485,23 @@ PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, PXA2xxMMCIState *s; Error *err = NULL; - dev = qdev_create(NULL, TYPE_PXA2XX_MMCI); + dev = qdev_new(TYPE_PXA2XX_MMCI); s = PXA2XX_MMCI(dev); sbd = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sbd, 0, base); sysbus_connect_irq(sbd, 0, irq); qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma); qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* Create and plug in the sd card */ - carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); qdev_prop_set_drive(carddev, "drive", blk, &err); if (err) { error_reportf_err(err, "failed to init SD card: "); return NULL; } - object_property_set_bool(OBJECT(carddev), true, "realized", &err); + qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"), &err); if (err) { error_reportf_err(err, "failed to init SD card: "); return NULL; diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 829797b597..f98a6f3ae1 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -252,7 +252,7 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) /* Create and plug in the sd card */ /* FIXME use a qdev drive property instead of drive_get_next() */ dinfo = drive_get_next(IF_SD); - carddev = qdev_create(BUS(&s->sdbus), TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD); if (dinfo) { qdev_prop_set_drive(carddev, "drive", blk_by_legacy_dinfo(dinfo), &err); if (err) { @@ -265,7 +265,7 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) goto fail; } - object_property_set_bool(OBJECT(carddev), true, "realized", &err); + qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err); if (err) { goto fail; } diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c index 72bb5285cc..d9592280bc 100644 --- a/hw/sh4/r2d.c +++ b/hw/sh4/r2d.c @@ -257,9 +257,9 @@ static void r2d_init(MachineState *machine) s = sh7750_init(cpu, address_space_mem); irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s)); - dev = qdev_create(NULL, "sh_pci"); + dev = qdev_new("sh_pci"); busdev = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci")); sysbus_mmio_map(busdev, 0, P4ADDR(0x1e200000)); sysbus_mmio_map(busdev, 1, A7ADDR(0x1e200000)); @@ -268,23 +268,23 @@ static void r2d_init(MachineState *machine) sysbus_connect_irq(busdev, 2, irq[PCI_INTC]); sysbus_connect_irq(busdev, 3, irq[PCI_INTD]); - dev = qdev_create(NULL, "sysbus-sm501"); + dev = qdev_new("sysbus-sm501"); busdev = SYS_BUS_DEVICE(dev); qdev_prop_set_uint32(dev, "vram-size", SM501_VRAM_SIZE); qdev_prop_set_uint32(dev, "base", 0x10000000); qdev_prop_set_chr(dev, "chardev", serial_hd(2)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(busdev, 0, 0x10000000); sysbus_mmio_map(busdev, 1, 0x13e00000); sysbus_connect_irq(busdev, 0, irq[SM501]); /* onboard CF (True IDE mode, Master only). */ dinfo = drive_get(IF_IDE, 0, 0); - dev = qdev_create(NULL, "mmio-ide"); + dev = qdev_new("mmio-ide"); busdev = SYS_BUS_DEVICE(dev); sysbus_connect_irq(busdev, 0, irq[CF_IDE]); qdev_prop_set_uint32(dev, "shift", 1); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(busdev, 0, 0x14001000); sysbus_mmio_map(busdev, 1, 0x1400080c); mmio_ide_init_drives(dev, dinfo, NULL); diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index d3ab8c9400..69fb39909d 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -228,12 +228,12 @@ static void leon3_generic_hw_init(MachineState *machine) GRLIB_AHB_SLAVE, GRLIB_AHBMEM_AREA); /* Allocate IRQ manager */ - dev = qdev_create(NULL, TYPE_GRLIB_IRQMP); + dev = qdev_new(TYPE_GRLIB_IRQMP); qdev_init_gpio_in_named_with_opaque(DEVICE(cpu), leon3_set_pil_in, env, "pil", 1); qdev_connect_gpio_out_named(dev, "grlib-irq", 0, qdev_get_gpio_in_named(DEVICE(cpu), "pil", 0)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_IRQMP_OFFSET); env->irq_manager = dev; env->qemu_irq_ack = leon3_irq_manager; @@ -322,11 +322,11 @@ static void leon3_generic_hw_init(MachineState *machine) } /* Allocate timers */ - dev = qdev_create(NULL, TYPE_GRLIB_GPTIMER); + dev = qdev_new(TYPE_GRLIB_GPTIMER); qdev_prop_set_uint32(dev, "nr-timers", LEON3_TIMER_COUNT); qdev_prop_set_uint32(dev, "frequency", CPU_CLK); qdev_prop_set_uint32(dev, "irq-line", LEON3_TIMER_IRQ); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_TIMER_OFFSET); for (i = 0; i < LEON3_TIMER_COUNT; i++) { @@ -339,9 +339,9 @@ static void leon3_generic_hw_init(MachineState *machine) 0, LEON3_TIMER_IRQ, GRLIB_APBIO_AREA); /* Allocate uart */ - dev = qdev_create(NULL, TYPE_GRLIB_APB_UART); + dev = qdev_new(TYPE_GRLIB_APB_UART); qdev_prop_set_chr(dev, "chrdev", serial_hd(0)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_UART_OFFSET); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irqs[LEON3_UART_IRQ]); grlib_apb_pnp_add_entry(apb_pnp, LEON3_UART_OFFSET, 0xFFF, diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 249f7ba7ea..5ebf303de9 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -316,9 +316,9 @@ static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, TYPE_SUN4M_IOMMU); + dev = qdev_new(TYPE_SUN4M_IOMMU); qdev_prop_set_uint32(dev, "version", version); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); sysbus_mmio_map(s, 0, addr); @@ -336,8 +336,8 @@ static void *sparc32_dma_init(hwaddr dma_base, SysBusESPState *esp; SysBusPCNetState *lance; - dma = qdev_create(NULL, TYPE_SPARC32_DMA); - qdev_init_nofail(dma); + dma = qdev_new(TYPE_SPARC32_DMA); + qdev_realize_and_unref(dma, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dma), 0, dma_base); espdma = SPARC32_ESPDMA_DEVICE(object_resolve_path_component( @@ -367,8 +367,8 @@ static DeviceState *slavio_intctl_init(hwaddr addr, SysBusDevice *s; unsigned int i, j; - dev = qdev_create(NULL, "slavio_intctl"); - qdev_init_nofail(dev); + dev = qdev_new("slavio_intctl"); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); @@ -395,9 +395,9 @@ static void slavio_timer_init_all(hwaddr addr, qemu_irq master_irq, SysBusDevice *s; unsigned int i; - dev = qdev_create(NULL, "slavio_timer"); + dev = qdev_new("slavio_timer"); qdev_prop_set_uint32(dev, "num_cpus", num_cpus); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, master_irq); sysbus_mmio_map(s, 0, addr + SYS_TIMER_OFFSET); @@ -433,8 +433,8 @@ static void slavio_misc_init(hwaddr base, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "slavio_misc"); - qdev_init_nofail(dev); + dev = qdev_new("slavio_misc"); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); if (base) { /* 8 bit registers */ @@ -470,9 +470,9 @@ static void ecc_init(hwaddr base, qemu_irq irq, uint32_t version) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "eccmemctl"); + dev = qdev_new("eccmemctl"); qdev_prop_set_uint32(dev, "version", version); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); sysbus_mmio_map(s, 0, base); @@ -486,8 +486,8 @@ static void apc_init(hwaddr power_base, qemu_irq cpu_halt) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "apc"); - qdev_init_nofail(dev); + dev = qdev_new("apc"); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); /* Power management (APC) XXX: not a Slavio device */ sysbus_mmio_map(s, 0, power_base); @@ -500,12 +500,12 @@ static void tcx_init(hwaddr addr, qemu_irq irq, int vram_size, int width, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "SUNW,tcx"); + dev = qdev_new("SUNW,tcx"); qdev_prop_set_uint32(dev, "vram_size", vram_size); qdev_prop_set_uint16(dev, "width", width); qdev_prop_set_uint16(dev, "height", height); qdev_prop_set_uint16(dev, "depth", depth); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); /* 10/ROM : FCode ROM */ @@ -552,12 +552,12 @@ static void cg3_init(hwaddr addr, qemu_irq irq, int vram_size, int width, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "cgthree"); + dev = qdev_new("cgthree"); qdev_prop_set_uint32(dev, "vram-size", vram_size); qdev_prop_set_uint16(dev, "width", width); qdev_prop_set_uint16(dev, "height", height); qdev_prop_set_uint16(dev, "depth", depth); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); /* FCode ROM */ @@ -581,8 +581,8 @@ static void idreg_init(hwaddr addr) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, TYPE_MACIO_ID_REGISTER); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_MACIO_ID_REGISTER); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, addr); @@ -647,8 +647,8 @@ static void afx_init(hwaddr addr) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, TYPE_TCX_AFX); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_TCX_AFX); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, addr); @@ -708,8 +708,8 @@ static void prom_init(hwaddr addr, const char *bios_name) char *filename; int ret; - dev = qdev_create(NULL, TYPE_OPENPROM); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_OPENPROM); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, addr); @@ -877,9 +877,9 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); /* Create and map RAM frontend */ - dev = qdev_create(NULL, "memory"); + dev = qdev_new("memory"); object_property_set_link(OBJECT(dev), ram_memdev, "memdev", &error_fatal); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0); /* models without ECC don't trap when missing ram is accessed */ @@ -982,7 +982,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */ - dev = qdev_create(NULL, TYPE_ESCC); + dev = qdev_new(TYPE_ESCC); qdev_prop_set_uint32(dev, "disabled", !machine->enable_graphics); qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK); qdev_prop_set_uint32(dev, "it_shift", 1); @@ -990,13 +990,13 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, qdev_prop_set_chr(dev, "chrA", NULL); qdev_prop_set_uint32(dev, "chnBtype", escc_mouse); qdev_prop_set_uint32(dev, "chnAtype", escc_kbd); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, slavio_irq[14]); sysbus_connect_irq(s, 1, slavio_irq[14]); sysbus_mmio_map(s, 0, hwdef->ms_kb_base); - dev = qdev_create(NULL, TYPE_ESCC); + dev = qdev_new(TYPE_ESCC); qdev_prop_set_uint32(dev, "disabled", 0); qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK); qdev_prop_set_uint32(dev, "it_shift", 1); @@ -1004,7 +1004,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, qdev_prop_set_chr(dev, "chrA", serial_hd(0)); qdev_prop_set_uint32(dev, "chnBtype", escc_serial); qdev_prop_set_uint32(dev, "chnAtype", escc_serial); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, slavio_irq[15]); @@ -1062,13 +1062,13 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ecc_init(hwdef->ecc_base, slavio_irq[28], hwdef->ecc_version); - dev = qdev_create(NULL, TYPE_FW_CFG_MEM); + dev = qdev_new(TYPE_FW_CFG_MEM); fw_cfg = FW_CFG(dev); qdev_prop_set_uint32(dev, "data_width", 1); qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(fw_cfg)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, CFG_ADDR); sysbus_mmio_map(s, 1, CFG_ADDR + 2); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 3a757ec42e..ade9c22825 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -351,8 +351,8 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) qdev_init_nofail(dev); /* Power */ - dev = qdev_create(NULL, TYPE_SUN4U_POWER); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_SUN4U_POWER); + qdev_realize_and_unref(dev, NULL, &error_fatal); sbd = SYS_BUS_DEVICE(dev); memory_region_add_subregion(pci_address_space_io(pci_dev), 0x7240, sysbus_mmio_get_region(sbd, 0)); @@ -426,8 +426,8 @@ static void prom_init(hwaddr addr, const char *bios_name) char *filename; int ret; - dev = qdev_create(NULL, TYPE_OPENPROM); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_OPENPROM); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, addr); @@ -520,12 +520,12 @@ static void ram_init(hwaddr addr, ram_addr_t RAM_size) RamDevice *d; /* allocate RAM */ - dev = qdev_create(NULL, TYPE_SUN4U_MEMORY); + dev = qdev_new(TYPE_SUN4U_MEMORY); s = SYS_BUS_DEVICE(dev); d = SUN4U_RAM(dev); d->size = RAM_size; - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(s, 0, addr); } @@ -572,8 +572,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem, cpu = sparc64_cpu_devinit(machine->cpu_type, hwdef->prom_addr); /* IOMMU */ - iommu = qdev_create(NULL, TYPE_SUN4U_IOMMU); - qdev_init_nofail(iommu); + iommu = qdev_new(TYPE_SUN4U_IOMMU); + qdev_realize_and_unref(iommu, NULL, &error_fatal); /* set up devices */ ram_init(0, machine->ram_size); @@ -581,12 +581,12 @@ static void sun4uv_init(MemoryRegion *address_space_mem, prom_init(hwdef->prom_addr, bios_name); /* Init sabre (PCI host bridge) */ - sabre = SABRE_DEVICE(qdev_create(NULL, TYPE_SABRE)); + sabre = SABRE_DEVICE(qdev_new(TYPE_SABRE)); qdev_prop_set_uint64(DEVICE(sabre), "special-base", PBM_SPECIAL_BASE); qdev_prop_set_uint64(DEVICE(sabre), "mem-base", PBM_MEM_BASE); object_property_set_link(OBJECT(sabre), OBJECT(iommu), "iommu", &error_abort); - qdev_init_nofail(DEVICE(sabre)); + qdev_realize_and_unref(DEVICE(sabre), NULL, &error_fatal); /* Wire up PCI interrupts to CPU */ for (i = 0; i < IVEC_MAX; i++) { @@ -689,10 +689,10 @@ static void sun4uv_init(MemoryRegion *address_space_mem, graphic_width, graphic_height, graphic_depth, (uint8_t *)&macaddr); - dev = qdev_create(NULL, TYPE_FW_CFG_IO); + dev = qdev_new(TYPE_FW_CFG_IO); qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(ebus), TYPE_FW_CFG, OBJECT(dev)); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); memory_region_add_subregion(pci_address_space_io(ebus), BIOS_CFG_IOPORT, &FW_CFG_IO(dev)->comb_iomem); diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index 32dd4461be..532f73661b 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -1387,9 +1387,9 @@ type_init(xen_register_types) void xen_bus_init(void) { - DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE); + DeviceState *dev = qdev_new(TYPE_XEN_BRIDGE); BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); qbus_set_bus_hotplug_handler(bus, &error_abort); } diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index f9d013811a..1c25373852 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -703,8 +703,8 @@ int xen_be_init(void) xengnttab_close(gnttabdev); } - xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV); - qdev_init_nofail(xen_sysdev); + xen_sysdev = qdev_new(TYPE_XENSYSDEV); + qdev_realize_and_unref(xen_sysdev, NULL, &error_fatal); xen_sysbus = qbus_create(TYPE_XENSYSBUS, xen_sysdev, "xen-sysbus"); qbus_set_bus_hotplug_handler(xen_sysbus, &error_abort); diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c index b22dcf938a..4dbc1a1614 100644 --- a/hw/xtensa/virt.c +++ b/hw/xtensa/virt.c @@ -62,8 +62,8 @@ static void create_pcie(CPUXtensaState *env, int irq_base, hwaddr addr_base) qemu_irq *extints; int i; - dev = qdev_create(NULL, TYPE_GPEX_HOST); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_GPEX_HOST); + qdev_realize_and_unref(dev, NULL, &error_fatal); /* Map only the first size_ecam bytes of ECAM space. */ ecam_alias = g_new0(MemoryRegion, 1); diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index 60ccc74f5f..eab5c8062e 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -148,9 +148,9 @@ static void xtfpga_net_init(MemoryRegion *address_space, SysBusDevice *s; MemoryRegion *ram; - dev = qdev_create(NULL, "open_eth"); + dev = qdev_new("open_eth"); qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); @@ -171,7 +171,7 @@ static PFlashCFI01 *xtfpga_flash_init(MemoryRegion *address_space, DriveInfo *dinfo, int be) { SysBusDevice *s; - DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo), &error_abort); @@ -181,7 +181,7 @@ static PFlashCFI01 *xtfpga_flash_init(MemoryRegion *address_space, qdev_prop_set_uint8(dev, "width", 2); qdev_prop_set_bit(dev, "big-endian", be); qdev_prop_set_string(dev, "name", "xtfpga.io.flash"); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); memory_region_add_subregion(address_space, board->flash->base, sysbus_mmio_get_region(s, 0)); diff --git a/include/hw/char/cadence_uart.h b/include/hw/char/cadence_uart.h index 2a179a572f..af80b6083b 100644 --- a/include/hw/char/cadence_uart.h +++ b/include/hw/char/cadence_uart.h @@ -22,6 +22,7 @@ #include "hw/qdev-properties.h" #include "hw/sysbus.h" #include "chardev/char-fe.h" +#include "qapi/error.h" #include "qemu/timer.h" #define CADENCE_UART_RX_FIFO_SIZE 16 @@ -59,10 +60,10 @@ static inline DeviceState *cadence_uart_create(hwaddr addr, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, TYPE_CADENCE_UART); + dev = qdev_new(TYPE_CADENCE_UART); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); diff --git a/include/hw/char/cmsdk-apb-uart.h b/include/hw/char/cmsdk-apb-uart.h index 3c1b53db4e..a51471ff74 100644 --- a/include/hw/char/cmsdk-apb-uart.h +++ b/include/hw/char/cmsdk-apb-uart.h @@ -62,11 +62,11 @@ static inline DeviceState *cmsdk_apb_uart_create(hwaddr addr, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, TYPE_CMSDK_APB_UART); + dev = qdev_new(TYPE_CMSDK_APB_UART); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); qdev_prop_set_uint32(dev, "pclk-frq", pclk_frq); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, txint); sysbus_connect_irq(s, 1, rxint); diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h index 14187165c6..18e701b65d 100644 --- a/include/hw/char/pl011.h +++ b/include/hw/char/pl011.h @@ -18,6 +18,7 @@ #include "hw/qdev-properties.h" #include "hw/sysbus.h" #include "chardev/char-fe.h" +#include "qapi/error.h" #define TYPE_PL011 "pl011" #define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011) @@ -57,10 +58,10 @@ static inline DeviceState *pl011_create(hwaddr addr, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "pl011"); + dev = qdev_new("pl011"); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); @@ -74,10 +75,10 @@ static inline DeviceState *pl011_luminary_create(hwaddr addr, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "pl011_luminary"); + dev = qdev_new("pl011_luminary"); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); diff --git a/include/hw/char/xilinx_uartlite.h b/include/hw/char/xilinx_uartlite.h index 194e2feafe..007b84575f 100644 --- a/include/hw/char/xilinx_uartlite.h +++ b/include/hw/char/xilinx_uartlite.h @@ -25,10 +25,10 @@ static inline DeviceState *xilinx_uartlite_create(hwaddr addr, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "xlnx.xps-uartlite"); + dev = qdev_new("xlnx.xps-uartlite"); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); diff --git a/include/hw/cris/etraxfs.h b/include/hw/cris/etraxfs.h index 403e7f95e6..19b903facf 100644 --- a/include/hw/cris/etraxfs.h +++ b/include/hw/cris/etraxfs.h @@ -41,10 +41,10 @@ static inline DeviceState *etraxfs_ser_create(hwaddr addr, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "etraxfs,serial"); + dev = qdev_new("etraxfs,serial"); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); return dev; diff --git a/include/hw/misc/unimp.h b/include/hw/misc/unimp.h index 44d87be903..e71ec17e13 100644 --- a/include/hw/misc/unimp.h +++ b/include/hw/misc/unimp.h @@ -10,6 +10,7 @@ #include "hw/qdev-properties.h" #include "hw/sysbus.h" +#include "qapi/error.h" #define TYPE_UNIMPLEMENTED_DEVICE "unimplemented-device" @@ -40,11 +41,11 @@ static inline void create_unimplemented_device(const char *name, hwaddr base, hwaddr size) { - DeviceState *dev = qdev_create(NULL, TYPE_UNIMPLEMENTED_DEVICE); + DeviceState *dev = qdev_new(TYPE_UNIMPLEMENTED_DEVICE); qdev_prop_set_string(dev, "name", name); qdev_prop_set_uint64(dev, "size", size); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(dev), 0, base, -1000); } diff --git a/include/hw/timer/cmsdk-apb-timer.h b/include/hw/timer/cmsdk-apb-timer.h index e93caccc3c..eee175eaa4 100644 --- a/include/hw/timer/cmsdk-apb-timer.h +++ b/include/hw/timer/cmsdk-apb-timer.h @@ -48,10 +48,10 @@ static inline DeviceState *cmsdk_apb_timer_create(hwaddr addr, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, TYPE_CMSDK_APB_TIMER); + dev = qdev_new(TYPE_CMSDK_APB_TIMER); s = SYS_BUS_DEVICE(dev); qdev_prop_set_uint32(dev, "pclk-frq", pclk_frq); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, timerint); return dev; From df70796916ebbafe262a01c1c4dc6d7af805de24 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:31:59 +0200 Subject: [PATCH 1235/2595] qdev: Convert uses of qdev_create() manually Same transformation as in the previous commit. Manual, because convincing Coccinelle to transform these cases is somewhere between not worthwhile and infeasible (at least for me). Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-11-armbru@redhat.com> --- hw/arm/highbank.c | 26 +++++++++++++------------- hw/arm/sbsa-ref.c | 4 ++-- hw/arm/virt.c | 4 ++-- hw/block/xen-block.c | 4 ++-- hw/char/serial.c | 4 ++-- hw/display/ati.c | 5 ++--- hw/display/sm501.c | 5 ++--- hw/display/xlnx_dp.c | 5 +++-- hw/i386/pc.c | 4 ++-- hw/i386/pc_sysfw.c | 4 ++-- hw/pci-bridge/pci_expander_bridge.c | 4 ++-- hw/ppc/pnv.c | 4 ++-- hw/riscv/virt.c | 4 ++-- hw/s390x/s390-pci-bus.c | 4 ++-- hw/sparc/leon3.c | 8 ++++---- hw/usb/bus.c | 8 ++++---- 16 files changed, 48 insertions(+), 49 deletions(-) diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index ac9de9411e..1bed540011 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -311,20 +311,20 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) switch (machine_id) { case CALXEDA_HIGHBANK: - dev = qdev_create(NULL, "l2x0"); - qdev_init_nofail(dev); + dev = qdev_new("l2x0"); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff12000); - dev = qdev_create(NULL, TYPE_A9MPCORE_PRIV); + dev = qdev_new(TYPE_A9MPCORE_PRIV); break; case CALXEDA_MIDWAY: - dev = qdev_create(NULL, TYPE_A15MPCORE_PRIV); + dev = qdev_new(TYPE_A15MPCORE_PRIV); break; } qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE); for (n = 0; n < smp_cpus; n++) { @@ -338,17 +338,17 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) pic[n] = qdev_get_gpio_in(dev, n); } - dev = qdev_create(NULL, "sp804"); + dev = qdev_new("sp804"); qdev_prop_set_uint32(dev, "freq0", 150000000); qdev_prop_set_uint32(dev, "freq1", 150000000); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff34000); sysbus_connect_irq(busdev, 0, pic[18]); pl011_create(0xfff36000, pic[20], serial_hd(0)); - dev = qdev_create(NULL, TYPE_HIGHBANK_REGISTERS); - qdev_init_nofail(dev); + dev = qdev_new(TYPE_HIGHBANK_REGISTERS); + qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff3c000); @@ -363,18 +363,18 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) if (nd_table[0].used) { qemu_check_nic_model(&nd_table[0], "xgmac"); - dev = qdev_create(NULL, "xgmac"); + dev = qdev_new("xgmac"); qdev_set_nic_properties(dev, &nd_table[0]); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff50000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[77]); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[78]); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[79]); qemu_check_nic_model(&nd_table[1], "xgmac"); - dev = qdev_create(NULL, "xgmac"); + dev = qdev_new("xgmac"); qdev_set_nic_properties(dev, &nd_table[1]); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff51000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[80]); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[81]); diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index d68c5d87af..fe24567333 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -211,7 +211,7 @@ static PFlashCFI01 *sbsa_flash_create1(SBSAMachineState *sms, * Create a single flash device. We use the same parameters as * the flash devices on the Versatile Express board. */ - DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); qdev_prop_set_uint64(dev, "sector-length", SBSA_FLASH_SECTOR_SIZE); qdev_prop_set_uint8(dev, "width", 4); @@ -243,7 +243,7 @@ static void sbsa_flash_map1(PFlashCFI01 *flash, assert(QEMU_IS_ALIGNED(size, SBSA_FLASH_SECTOR_SIZE)); assert(size / SBSA_FLASH_SECTOR_SIZE <= UINT32_MAX); qdev_prop_set_uint32(dev, "num-blocks", size / SBSA_FLASH_SECTOR_SIZE); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); memory_region_add_subregion(sysmem, base, sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 154cd24731..ca151435ae 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -948,7 +948,7 @@ static PFlashCFI01 *virt_flash_create1(VirtMachineState *vms, * Create a single flash device. We use the same parameters as * the flash devices on the Versatile Express board. */ - DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE); qdev_prop_set_uint8(dev, "width", 4); @@ -980,7 +980,7 @@ static void virt_flash_map1(PFlashCFI01 *flash, assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE)); assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); memory_region_add_subregion(sysmem, base, sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 570489d6d9..2827c90ac7 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -937,7 +937,7 @@ static void xen_block_device_create(XenBackendInstance *backend, goto fail; } - xendev = XEN_DEVICE(qdev_create(BUS(xenbus), type)); + xendev = XEN_DEVICE(qdev_new(type)); blockdev = XEN_BLOCK_DEVICE(xendev); object_property_set_str(OBJECT(xendev), vdev, "vdev", &local_err); @@ -965,7 +965,7 @@ static void xen_block_device_create(XenBackendInstance *backend, blockdev->iothread = iothread; blockdev->drive = drive; - object_property_set_bool(OBJECT(xendev), true, "realized", &local_err); + qdev_realize_and_unref(DEVICE(xendev), BUS(xenbus), &local_err); if (local_err) { error_propagate_prepend(errp, local_err, "realization of device %s failed: ", diff --git a/hw/char/serial.c b/hw/char/serial.c index 7d74694587..a0cab38fb0 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -1127,7 +1127,7 @@ SerialMM *serial_mm_init(MemoryRegion *address_space, qemu_irq irq, int baudbase, Chardev *chr, enum device_endian end) { - SerialMM *smm = SERIAL_MM(qdev_create(NULL, TYPE_SERIAL_MM)); + SerialMM *smm = SERIAL_MM(qdev_new(TYPE_SERIAL_MM)); MemoryRegion *mr; qdev_prop_set_uint8(DEVICE(smm), "regshift", regshift); @@ -1135,7 +1135,7 @@ SerialMM *serial_mm_init(MemoryRegion *address_space, qdev_prop_set_chr(DEVICE(smm), "chardev", chr); qdev_set_legacy_instance_id(DEVICE(smm), base, 2); qdev_prop_set_uint8(DEVICE(smm), "endianness", end); - qdev_init_nofail(DEVICE(smm)); + qdev_realize_and_unref(DEVICE(smm), NULL, &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, irq); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(smm), 0); diff --git a/hw/display/ati.c b/hw/display/ati.c index 1d9df92b96..7216f7e08f 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -933,10 +933,9 @@ static void ati_vga_realize(PCIDevice *dev, Error **errp) /* ddc, edid */ I2CBus *i2cbus = i2c_init_bus(DEVICE(s), "ati-vga.ddc"); bitbang_i2c_init(&s->bbi2c, i2cbus); - I2CSlave *i2cddc = I2C_SLAVE(qdev_create(BUS(i2cbus), TYPE_I2CDDC)); + I2CSlave *i2cddc = I2C_SLAVE(qdev_new(TYPE_I2CDDC)); i2c_set_slave_address(i2cddc, 0x50); - object_property_set_bool(OBJECT(i2cddc), true, "realized", - &error_abort); + qdev_realize_and_unref(DEVICE(i2cddc), BUS(i2cbus), &error_abort); /* mmio register space */ memory_region_init_io(&s->mm, OBJECT(s), &ati_mm_ops, s, diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 7ff14fd474..3e62eca3de 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1831,10 +1831,9 @@ static void sm501_init(SM501State *s, DeviceState *dev, /* i2c */ s->i2c_bus = i2c_init_bus(dev, "sm501.i2c"); /* ddc */ - I2CDDCState *ddc = I2CDDC(qdev_create(BUS(s->i2c_bus), TYPE_I2CDDC)); + I2CDDCState *ddc = I2CDDC(qdev_new(TYPE_I2CDDC)); i2c_set_slave_address(I2C_SLAVE(ddc), 0x50); - object_property_set_bool(OBJECT(ddc), true, "realized", - &error_abort); + qdev_realize_and_unref(DEVICE(ddc), BUS(s->i2c_bus), &error_abort); /* mmio */ memory_region_init(&s->mmio_region, OBJECT(dev), "sm501.mmio", MMIO_SIZE); diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 5210412e55..6e9793584a 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1252,7 +1252,7 @@ static void xlnx_dp_init(Object *obj) s->dpcd = DPCD(aux_create_slave(s->aux_bus, "dpcd")); object_property_add_child(OBJECT(s), "dpcd", OBJECT(s->dpcd)); - s->edid = I2CDDC(qdev_create(BUS(aux_get_i2c_bus(s->aux_bus)), "i2c-ddc")); + s->edid = I2CDDC(qdev_new("i2c-ddc")); i2c_set_slave_address(I2C_SLAVE(s->edid), 0x50); object_property_add_child(OBJECT(s), "edid", OBJECT(s->edid)); @@ -1271,7 +1271,8 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp) qdev_init_nofail(DEVICE(s->dpcd)); aux_map_slave(AUX_SLAVE(s->dpcd), 0x0000); - qdev_init_nofail(DEVICE(s->edid)); + qdev_realize_and_unref(DEVICE(s->edid), BUS(aux_get_i2c_bus(s->aux_bus)), + &error_fatal); s->console = graphic_console_init(dev, 0, &xlnx_dp_gfx_ops, s); surface = qemu_console_surface(s->console); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index a5dd6252fa..ab2380c01f 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1205,7 +1205,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, * when the HPET wants to take over. Thus we have to disable the latter. */ if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) { - hpet = qdev_try_create(NULL, TYPE_HPET); + hpet = qdev_try_new(TYPE_HPET); if (hpet) { /* For pc-piix-*, hpet's intcap is always IRQ2. For pc-q35-1.7 * and earlier, use IRQ2 for compat. Otherwise, use IRQ16~23, @@ -1216,7 +1216,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, if (!compat) { qdev_prop_set_uint32(hpet, HPET_INTCAP, hpet_irqs); } - qdev_init_nofail(hpet); + qdev_realize_and_unref(hpet, NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(hpet), 0, HPET_BASE); for (i = 0; i < GSI_NUM_PINS; i++) { diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index b8d8ef59eb..2e414d1934 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -85,7 +85,7 @@ static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms, const char *name, const char *alias_prop_name) { - DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); qdev_prop_set_uint64(dev, "sector-length", FLASH_SECTOR_SIZE); qdev_prop_set_uint8(dev, "width", 1); @@ -187,7 +187,7 @@ static void pc_system_flash_map(PCMachineState *pcms, total_size += size; qdev_prop_set_uint32(DEVICE(system_flash), "num-blocks", size / FLASH_SECTOR_SIZE); - qdev_init_nofail(DEVICE(system_flash)); + qdev_realize_and_unref(DEVICE(system_flash), NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(system_flash), 0, 0x100000000ULL - total_size); diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 5da0d21061..3a395ab2f0 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -236,7 +236,7 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_PCIE_BUS); } else { bus = pci_root_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS); - bds = qdev_create(BUS(bus), "pci-bridge"); + bds = qdev_new("pci-bridge"); bds->id = dev_name; qdev_prop_set_uint8(bds, PCI_BRIDGE_DEV_PROP_CHASSIS_NR, pxb->bus_nr); qdev_prop_set_bit(bds, PCI_BRIDGE_DEV_PROP_SHPC, false); @@ -257,7 +257,7 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) qdev_realize_and_unref(ds, NULL, &error_fatal); if (bds) { - qdev_init_nofail(bds); + qdev_realize_and_unref(bds, &bus->qbus, &error_fatal); } pci_word_test_and_set_mask(dev->config + PCI_STATUS, diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index e3b6f0b884..8562af3fe0 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -818,7 +818,7 @@ static void pnv_init(MachineState *machine) pnv->chips = g_new0(PnvChip *, pnv->num_chips); for (i = 0; i < pnv->num_chips; i++) { char chip_name[32]; - Object *chip = OBJECT(qdev_create(NULL, chip_typename)); + Object *chip = OBJECT(qdev_new(chip_typename)); pnv->chips[i] = PNV_CHIP(chip); @@ -850,7 +850,7 @@ static void pnv_init(MachineState *machine) object_property_set_link(chip, OBJECT(pnv), "xive-fabric", &error_abort); } - object_property_set_bool(chip, true, "realized", &error_fatal); + qdev_realize_and_unref(DEVICE(chip), NULL, &error_fatal); } g_free(chip_typename); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index fa88e9118c..4970a085ca 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -80,7 +80,7 @@ static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s, * Create a single flash device. We use the same parameters as * the flash devices on the ARM virt board. */ - DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE); qdev_prop_set_uint8(dev, "width", 4); @@ -114,7 +114,7 @@ static void virt_flash_map1(PFlashCFI01 *flash, assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE)); assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, NULL, &error_fatal); memory_region_add_subregion(sysmem, base, sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 7a4bfb7383..a13978bb37 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -824,7 +824,7 @@ static S390PCIBusDevice *s390_pci_device_new(S390pciState *s, Error *local_err = NULL; DeviceState *dev; - dev = qdev_try_create(BUS(s->bus), TYPE_S390_PCI_DEVICE); + dev = qdev_try_new(TYPE_S390_PCI_DEVICE); if (!dev) { error_setg(errp, "zPCI device could not be created"); return NULL; @@ -837,7 +837,7 @@ static S390PCIBusDevice *s390_pci_device_new(S390pciState *s, "zPCI device could not be created: "); return NULL; } - object_property_set_bool(OBJECT(dev), true, "realized", &local_err); + qdev_realize_and_unref(dev, BUS(s->bus), &local_err); if (local_err) { object_unparent(OBJECT(dev)); error_propagate_prepend(errp, local_err, diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index 69fb39909d..b778a5bf80 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -213,15 +213,15 @@ static void leon3_generic_hw_init(MachineState *machine) reset_info->sp = LEON3_RAM_OFFSET + ram_size; qemu_register_reset(main_cpu_reset, reset_info); - ahb_pnp = GRLIB_AHB_PNP(qdev_create(NULL, TYPE_GRLIB_AHB_PNP)); - object_property_set_bool(OBJECT(ahb_pnp), true, "realized", &error_fatal); + ahb_pnp = GRLIB_AHB_PNP(qdev_new(TYPE_GRLIB_AHB_PNP)); + qdev_realize_and_unref(DEVICE(ahb_pnp), NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(ahb_pnp), 0, LEON3_AHB_PNP_OFFSET); grlib_ahb_pnp_add_entry(ahb_pnp, 0, 0, GRLIB_VENDOR_GAISLER, GRLIB_LEON3_DEV, GRLIB_AHB_MASTER, GRLIB_CPU_AREA); - apb_pnp = GRLIB_APB_PNP(qdev_create(NULL, TYPE_GRLIB_APB_PNP)); - object_property_set_bool(OBJECT(apb_pnp), true, "realized", &error_fatal); + apb_pnp = GRLIB_APB_PNP(qdev_new(TYPE_GRLIB_APB_PNP)); + qdev_realize_and_unref(DEVICE(apb_pnp), NULL, &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(apb_pnp), 0, LEON3_APB_PNP_OFFSET); grlib_ahb_pnp_add_entry(ahb_pnp, LEON3_APB_PNP_OFFSET, 0xFFF, GRLIB_VENDOR_GAISLER, GRLIB_APBMST_DEV, diff --git a/hw/usb/bus.c b/hw/usb/bus.c index fa07df98a2..d28eff1b5c 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -326,21 +326,21 @@ static USBDevice *usb_try_create_simple(USBBus *bus, const char *name, Error **errp) { Error *err = NULL; - USBDevice *dev; + DeviceState *dev; - dev = USB_DEVICE(qdev_try_create(&bus->qbus, name)); + dev = qdev_try_new(name); if (!dev) { error_setg(errp, "Failed to create USB device '%s'", name); return NULL; } - object_property_set_bool(OBJECT(dev), true, "realized", &err); + qdev_realize_and_unref(dev, &bus->qbus, &err); if (err) { error_propagate_prepend(errp, err, "Failed to initialize USB device '%s': ", name); return NULL; } - return dev; + return USB_DEVICE(dev); } USBDevice *usb_create_simple(USBBus *bus, const char *name) From 99ba777e53ebf31bf24e7a52a21fccdd25f95537 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:00 +0200 Subject: [PATCH 1236/2595] qdev: Convert uses of qdev_set_parent_bus() with Coccinelle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In addition to the qdev_create() patterns converted so far, we have a qdev_set_parent_bus() pattern. Mostly when we embed a device in a parent device rather than allocating it on the heap. This pattern also puts devices in the dangerous "no QOM parent, but plugged into bus" state I explained in recent commit "qdev: New qdev_new(), qdev_realize(), etc." Apply same solution: convert to qdev_realize(). Coccinelle script: @@ expression dev, bus, errp; symbol true; @@ - qdev_set_parent_bus(DEVICE(dev), bus); ... - object_property_set_bool(OBJECT(dev), true, "realized", errp); + qdev_realize(DEVICE(dev), bus, errp); @ depends on !(file in "qdev-monitor.c") && !(file in "hw/core/qdev.c")@ expression dev, bus, errp; symbol true; @@ - qdev_set_parent_bus(dev, bus); ... - object_property_set_bool(OBJECT(dev), true, "realized", errp); + qdev_realize(dev, bus, errp); @@ expression dev, bus; symbol true; @@ - qdev_set_parent_bus(DEVICE(dev), bus); ... - qdev_init_nofail(DEVICE(dev)); + qdev_realize(DEVICE(dev), bus, &error_fatal); Unconverted uses of qdev_set_parent_bus() remain. They'll be converted later in this series. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-12-armbru@redhat.com> [Also convert new hw/virtio/vhost-user-vsock-pci.c] --- hw/display/virtio-gpu-pci.c | 3 +-- hw/display/virtio-vga.c | 3 +-- hw/i386/amd_iommu.c | 3 +-- hw/isa/piix4.c | 3 +-- hw/misc/macio/macio.c | 7 ++----- hw/pci-host/designware.c | 3 +-- hw/pci-host/gpex.c | 3 +-- hw/pci-host/pnv_phb3.c | 3 +-- hw/pci-host/pnv_phb4.c | 3 +-- hw/pci-host/q35.c | 3 +-- hw/pci-host/versatile.c | 3 +-- hw/pci-host/xilinx-pcie.c | 3 +-- hw/s390x/vhost-vsock-ccw.c | 3 +-- hw/s390x/virtio-ccw-9p.c | 3 +-- hw/s390x/virtio-ccw-balloon.c | 3 +-- hw/s390x/virtio-ccw-blk.c | 3 +-- hw/s390x/virtio-ccw-crypto.c | 3 +-- hw/s390x/virtio-ccw-gpu.c | 3 +-- hw/s390x/virtio-ccw-input.c | 3 +-- hw/s390x/virtio-ccw-net.c | 3 +-- hw/s390x/virtio-ccw-rng.c | 3 +-- hw/s390x/virtio-ccw-scsi.c | 6 ++---- hw/s390x/virtio-ccw-serial.c | 3 +-- hw/virtio/vhost-scsi-pci.c | 3 +-- hw/virtio/vhost-user-blk-pci.c | 3 +-- hw/virtio/vhost-user-fs-pci.c | 3 +-- hw/virtio/vhost-user-scsi-pci.c | 3 +-- hw/virtio/vhost-user-vsock-pci.c | 3 +-- hw/virtio/vhost-vsock-pci.c | 3 +-- hw/virtio/virtio-9p-pci.c | 3 +-- hw/virtio/virtio-balloon-pci.c | 3 +-- hw/virtio/virtio-blk-pci.c | 3 +-- hw/virtio/virtio-crypto-pci.c | 3 +-- hw/virtio/virtio-input-pci.c | 3 +-- hw/virtio/virtio-iommu-pci.c | 3 +-- hw/virtio/virtio-net-pci.c | 3 +-- hw/virtio/virtio-pmem-pci.c | 3 +-- hw/virtio/virtio-rng-pci.c | 3 +-- hw/virtio/virtio-scsi-pci.c | 3 +-- hw/virtio/virtio-serial-pci.c | 3 +-- hw/xen/xen-legacy-backend.c | 3 +-- 41 files changed, 43 insertions(+), 87 deletions(-) diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index 3d152ff5c8..b532fe8b5f 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -33,9 +33,8 @@ static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) int i; Error *local_error = NULL; - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); virtio_pci_force_virtio_1(vpci_dev); - object_property_set_bool(OBJECT(vdev), true, "realized", &local_error); + qdev_realize(vdev, BUS(&vpci_dev->bus), &local_error); if (local_error) { error_propagate(errp, local_error); diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 95757a6619..68a062ece6 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -137,9 +137,8 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) vpci_dev->common.offset = offset; /* init virtio bits */ - qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus)); virtio_pci_force_virtio_1(vpci_dev); - object_property_set_bool(OBJECT(g), true, "realized", &err); + qdev_realize(DEVICE(g), BUS(&vpci_dev->bus), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 4346060e62..b26d30da57 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1549,8 +1549,7 @@ static void amdvi_realize(DeviceState *dev, Error **errp) /* This device should take care of IOMMU PCI properties */ x86_iommu->type = TYPE_AMD; - qdev_set_parent_bus(DEVICE(&s->pci), &bus->qbus); - object_property_set_bool(OBJECT(&s->pci), true, "realized", errp); + qdev_realize(DEVICE(&s->pci), &bus->qbus, errp); ret = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0, AMDVI_CAPAB_SIZE, errp); if (ret < 0) { diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 9a10fb9b3c..f634bcb2d1 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -182,9 +182,8 @@ static void piix4_realize(PCIDevice *dev, Error **errp) i8257_dma_init(isa_bus, 0); /* RTC */ - qdev_set_parent_bus(DEVICE(&s->rtc), BUS(isa_bus)); qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000); - object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err); + qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 53a9fd5696..216bdc69c0 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -356,9 +356,7 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) object_property_set_link(OBJECT(&s->pmu), OBJECT(sysbus_dev), "gpio", &error_abort); qdev_prop_set_bit(DEVICE(&s->pmu), "has-adb", ns->has_adb); - qdev_set_parent_bus(DEVICE(&s->pmu), BUS(&s->macio_bus)); - - object_property_set_bool(OBJECT(&s->pmu), true, "realized", &err); + qdev_realize(DEVICE(&s->pmu), BUS(&s->macio_bus), &err); if (err) { error_propagate(errp, err); return; @@ -374,11 +372,10 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) /* CUDA */ object_initialize_child(OBJECT(s), "cuda", &s->cuda, sizeof(s->cuda), TYPE_CUDA, &error_abort, NULL); - qdev_set_parent_bus(DEVICE(&s->cuda), BUS(&s->macio_bus)); qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency", s->frequency); - object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err); + qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index dd245516dd..2e97d6b17f 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -688,8 +688,7 @@ static void designware_pcie_host_realize(DeviceState *dev, Error **errp) "pcie-bus-address-space"); pci_setup_iommu(pci->bus, designware_pcie_host_set_iommu, s); - qdev_set_parent_bus(DEVICE(&s->root), BUS(pci->bus)); - qdev_init_nofail(DEVICE(&s->root)); + qdev_realize(DEVICE(&s->root), BUS(pci->bus), &error_fatal); } static const VMStateDescription vmstate_designware_pcie_host = { diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c index 0ca604dc62..3dfb3bf599 100644 --- a/hw/pci-host/gpex.c +++ b/hw/pci-host/gpex.c @@ -98,9 +98,8 @@ static void gpex_host_realize(DeviceState *dev, Error **errp) pci_swizzle_map_irq_fn, s, &s->io_mmio, &s->io_ioport, 0, 4, TYPE_PCIE_BUS); - qdev_set_parent_bus(DEVICE(&s->gpex_root), BUS(pci->bus)); pci_bus_set_route_irq_fn(pci->bus, gpex_route_intx_pin_to_irq); - qdev_init_nofail(DEVICE(&s->gpex_root)); + qdev_realize(DEVICE(&s->gpex_root), BUS(pci->bus), &error_fatal); } static const char *gpex_host_root_bus_path(PCIHostState *host_bridge, diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index 74618fadf0..8dcfe4a2fd 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -1064,8 +1064,7 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) /* Add a single Root port */ qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id); qdev_prop_set_uint16(DEVICE(&phb->root), "slot", phb->phb_id); - qdev_set_parent_bus(DEVICE(&phb->root), BUS(pci->bus)); - qdev_init_nofail(DEVICE(&phb->root)); + qdev_realize(DEVICE(&phb->root), BUS(pci->bus), &error_fatal); } void pnv_phb3_update_regions(PnvPHB3 *phb) diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 23cf093928..e30ae9ad5b 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1210,8 +1210,7 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) /* Add a single Root port */ qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id); qdev_prop_set_uint16(DEVICE(&phb->root), "slot", phb->phb_id); - qdev_set_parent_bus(DEVICE(&phb->root), BUS(pci->bus)); - qdev_init_nofail(DEVICE(&phb->root)); + qdev_realize(DEVICE(&phb->root), BUS(pci->bus), &error_fatal); /* Setup XIVE Source */ if (phb->big_phb) { diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index b788f17b2c..43ed5188cc 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -64,8 +64,7 @@ static void q35_host_realize(DeviceState *dev, Error **errp) s->mch.address_space_io, 0, TYPE_PCIE_BUS); PC_MACHINE(qdev_get_machine())->bus = pci->bus; - qdev_set_parent_bus(DEVICE(&s->mch), BUS(pci->bus)); - qdev_init_nofail(DEVICE(&s->mch)); + qdev_realize(DEVICE(&s->mch), BUS(pci->bus), &error_fatal); } static const char *q35_host_root_bus_path(PCIHostState *host_bridge, diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c index ea7390c6fa..616882a80d 100644 --- a/hw/pci-host/versatile.c +++ b/hw/pci-host/versatile.c @@ -409,7 +409,6 @@ static void pci_vpb_realize(DeviceState *dev, Error **errp) h->bus = &s->pci_bus; object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_VERSATILE_PCI_HOST); - qdev_set_parent_bus(DEVICE(&s->pci_dev), BUS(&s->pci_bus)); for (i = 0; i < 4; i++) { sysbus_init_irq(sbd, &s->irq[i]); @@ -459,7 +458,7 @@ static void pci_vpb_realize(DeviceState *dev, Error **errp) } /* TODO Remove once realize propagates to child devices. */ - object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp); + qdev_realize(DEVICE(&s->pci_dev), BUS(&s->pci_bus), errp); } static void versatile_pci_host_realize(PCIDevice *d, Error **errp) diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c index e06f2b59cf..e4fc8abb6a 100644 --- a/hw/pci-host/xilinx-pcie.c +++ b/hw/pci-host/xilinx-pcie.c @@ -137,8 +137,7 @@ static void xilinx_pcie_host_realize(DeviceState *dev, Error **errp) pci_swizzle_map_irq_fn, s, &s->mmio, &s->io, 0, 4, TYPE_PCIE_BUS); - qdev_set_parent_bus(DEVICE(&s->root), BUS(pci->bus)); - qdev_init_nofail(DEVICE(&s->root)); + qdev_realize(DEVICE(&s->root), BUS(pci->bus), &error_fatal); } static const char *xilinx_pcie_host_root_bus_path(PCIHostState *host_bridge, diff --git a/hw/s390x/vhost-vsock-ccw.c b/hw/s390x/vhost-vsock-ccw.c index 12dee15e11..0822ecca89 100644 --- a/hw/s390x/vhost-vsock-ccw.c +++ b/hw/s390x/vhost-vsock-ccw.c @@ -24,8 +24,7 @@ static void vhost_vsock_ccw_realize(VirtioCcwDevice *ccw_dev, Error **errp) VHostVSockCCWState *dev = VHOST_VSOCK_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); } static void vhost_vsock_ccw_class_init(ObjectClass *klass, void *data) diff --git a/hw/s390x/virtio-ccw-9p.c b/hw/s390x/virtio-ccw-9p.c index 08e1d5d416..88c8884fc5 100644 --- a/hw/s390x/virtio-ccw-9p.c +++ b/hw/s390x/virtio-ccw-9p.c @@ -21,8 +21,7 @@ static void virtio_ccw_9p_realize(VirtioCcwDevice *ccw_dev, Error **errp) V9fsCCWState *dev = VIRTIO_9P_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); } static void virtio_ccw_9p_instance_init(Object *obj) diff --git a/hw/s390x/virtio-ccw-balloon.c b/hw/s390x/virtio-ccw-balloon.c index ef3308ecab..4c7631a433 100644 --- a/hw/s390x/virtio-ccw-balloon.c +++ b/hw/s390x/virtio-ccw-balloon.c @@ -21,8 +21,7 @@ static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp) VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); } static void virtio_ccw_balloon_instance_init(Object *obj) diff --git a/hw/s390x/virtio-ccw-blk.c b/hw/s390x/virtio-ccw-blk.c index 7287932b7e..2294ce1ce4 100644 --- a/hw/s390x/virtio-ccw-blk.c +++ b/hw/s390x/virtio-ccw-blk.c @@ -21,8 +21,7 @@ static void virtio_ccw_blk_realize(VirtioCcwDevice *ccw_dev, Error **errp) VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); } static void virtio_ccw_blk_instance_init(Object *obj) diff --git a/hw/s390x/virtio-ccw-crypto.c b/hw/s390x/virtio-ccw-crypto.c index 1a2690cf9e..ca6753bff3 100644 --- a/hw/s390x/virtio-ccw-crypto.c +++ b/hw/s390x/virtio-ccw-crypto.c @@ -21,8 +21,7 @@ static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) DeviceState *vdev = DEVICE(&dev->vdev); Error *err = NULL; - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); + qdev_realize(vdev, BUS(&ccw_dev->bus), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/s390x/virtio-ccw-gpu.c b/hw/s390x/virtio-ccw-gpu.c index f69e3ff5a0..c301e2586b 100644 --- a/hw/s390x/virtio-ccw-gpu.c +++ b/hw/s390x/virtio-ccw-gpu.c @@ -20,8 +20,7 @@ static void virtio_ccw_gpu_realize(VirtioCcwDevice *ccw_dev, Error **errp) VirtIOGPUCcw *dev = VIRTIO_GPU_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); } static void virtio_ccw_gpu_instance_init(Object *obj) diff --git a/hw/s390x/virtio-ccw-input.c b/hw/s390x/virtio-ccw-input.c index b257dfd467..5601e25dee 100644 --- a/hw/s390x/virtio-ccw-input.c +++ b/hw/s390x/virtio-ccw-input.c @@ -20,8 +20,7 @@ static void virtio_ccw_input_realize(VirtioCcwDevice *ccw_dev, Error **errp) VirtIOInputCcw *dev = VIRTIO_INPUT_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); } static Property virtio_ccw_input_properties[] = { diff --git a/hw/s390x/virtio-ccw-net.c b/hw/s390x/virtio-ccw-net.c index 26c4d873bf..3860d4e6ea 100644 --- a/hw/s390x/virtio-ccw-net.c +++ b/hw/s390x/virtio-ccw-net.c @@ -24,8 +24,7 @@ static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp) virtio_net_set_netclient_name(&dev->vdev, qdev->id, object_get_typename(OBJECT(qdev))); - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); } static void virtio_ccw_net_instance_init(Object *obj) diff --git a/hw/s390x/virtio-ccw-rng.c b/hw/s390x/virtio-ccw-rng.c index d575e30cc6..4077160f49 100644 --- a/hw/s390x/virtio-ccw-rng.c +++ b/hw/s390x/virtio-ccw-rng.c @@ -22,8 +22,7 @@ static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) DeviceState *vdev = DEVICE(&dev->vdev); Error *err = NULL; - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); + qdev_realize(vdev, BUS(&ccw_dev->bus), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/s390x/virtio-ccw-scsi.c b/hw/s390x/virtio-ccw-scsi.c index 3cb3ad669d..6e4beef700 100644 --- a/hw/s390x/virtio-ccw-scsi.c +++ b/hw/s390x/virtio-ccw-scsi.c @@ -33,8 +33,7 @@ static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) g_free(bus_name); } - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); } static void virtio_ccw_scsi_instance_init(Object *obj) @@ -78,8 +77,7 @@ static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); } static void vhost_ccw_scsi_instance_init(Object *obj) diff --git a/hw/s390x/virtio-ccw-serial.c b/hw/s390x/virtio-ccw-serial.c index 1764db2e70..61958228d1 100644 --- a/hw/s390x/virtio-ccw-serial.c +++ b/hw/s390x/virtio-ccw-serial.c @@ -33,8 +33,7 @@ static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp) g_free(bus_name); } - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); } diff --git a/hw/virtio/vhost-scsi-pci.c b/hw/virtio/vhost-scsi-pci.c index 5da6bb6449..095af23f3f 100644 --- a/hw/virtio/vhost-scsi-pci.c +++ b/hw/virtio/vhost-scsi-pci.c @@ -53,8 +53,7 @@ static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) vpci_dev->nvectors = vs->conf.num_queues + 3; } - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/vhost-user-blk-pci.c b/hw/virtio/vhost-user-blk-pci.c index 58d7c31735..4f5d5cbf44 100644 --- a/hw/virtio/vhost-user-blk-pci.c +++ b/hw/virtio/vhost-user-blk-pci.c @@ -58,8 +58,7 @@ static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) vpci_dev->nvectors = dev->vdev.num_queues + 1; } - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void vhost_user_blk_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/vhost-user-fs-pci.c b/hw/virtio/vhost-user-fs-pci.c index ae36f1172d..e11c889d82 100644 --- a/hw/virtio/vhost-user-fs-pci.c +++ b/hw/virtio/vhost-user-fs-pci.c @@ -44,8 +44,7 @@ static void vhost_user_fs_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) vpci_dev->nvectors = dev->vdev.conf.num_request_queues + 2; } - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void vhost_user_fs_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/vhost-user-scsi-pci.c b/hw/virtio/vhost-user-scsi-pci.c index 6f3375fe55..4705cd54e8 100644 --- a/hw/virtio/vhost-user-scsi-pci.c +++ b/hw/virtio/vhost-user-scsi-pci.c @@ -59,8 +59,7 @@ static void vhost_user_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) vpci_dev->nvectors = vs->conf.num_queues + 3; } - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void vhost_user_scsi_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/vhost-user-vsock-pci.c b/hw/virtio/vhost-user-vsock-pci.c index 0a6847e6fc..f4cf95873d 100644 --- a/hw/virtio/vhost-user-vsock-pci.c +++ b/hw/virtio/vhost-user-vsock-pci.c @@ -40,8 +40,7 @@ static void vhost_user_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) VHostUserVSockPCI *dev = VHOST_USER_VSOCK_PCI(vpci_dev); DeviceState *vdev = DEVICE(&dev->vdev); - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void vhost_user_vsock_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/vhost-vsock-pci.c b/hw/virtio/vhost-vsock-pci.c index 01effe3d52..a815278e69 100644 --- a/hw/virtio/vhost-vsock-pci.c +++ b/hw/virtio/vhost-vsock-pci.c @@ -44,8 +44,7 @@ static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) VHostVSockPCI *dev = VHOST_VSOCK_PCI(vpci_dev); DeviceState *vdev = DEVICE(&dev->vdev); - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/virtio-9p-pci.c b/hw/virtio/virtio-9p-pci.c index 6507ce340b..cbcb062faa 100644 --- a/hw/virtio/virtio-9p-pci.c +++ b/hw/virtio/virtio-9p-pci.c @@ -38,8 +38,7 @@ static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev); DeviceState *vdev = DEVICE(&dev->vdev); - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static Property virtio_9p_pci_properties[] = { diff --git a/hw/virtio/virtio-balloon-pci.c b/hw/virtio/virtio-balloon-pci.c index cc25df0a3d..5adc4e5819 100644 --- a/hw/virtio/virtio-balloon-pci.c +++ b/hw/virtio/virtio-balloon-pci.c @@ -48,8 +48,7 @@ static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) vpci_dev->class_code = PCI_CLASS_OTHERS; } - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c index 28838fa958..849cc7dfd8 100644 --- a/hw/virtio/virtio-blk-pci.c +++ b/hw/virtio/virtio-blk-pci.c @@ -55,8 +55,7 @@ static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) vpci_dev->nvectors = dev->vdev.conf.num_queues + 1; } - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c index 0bebe0149d..72be531c95 100644 --- a/hw/virtio/virtio-crypto-pci.c +++ b/hw/virtio/virtio-crypto-pci.c @@ -53,9 +53,8 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) return; } - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); virtio_pci_force_virtio_1(vpci_dev); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); object_property_set_link(OBJECT(vcrypto), OBJECT(vcrypto->vdev.conf.cryptodev), "cryptodev", NULL); diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c index 5a965408df..74651a42ea 100644 --- a/hw/virtio/virtio-input-pci.c +++ b/hw/virtio/virtio-input-pci.c @@ -49,9 +49,8 @@ static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev); DeviceState *vdev = DEVICE(&vinput->vdev); - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); virtio_pci_force_virtio_1(vpci_dev); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void virtio_input_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c index 3dfbf55b47..632533abaf 100644 --- a/hw/virtio/virtio-iommu-pci.c +++ b/hw/virtio/virtio-iommu-pci.c @@ -54,11 +54,10 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) "-no-acpi\n"); return; } - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); object_property_set_link(OBJECT(dev), OBJECT(pci_get_bus(&vpci_dev->pci_dev)), "primary-bus", errp); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void virtio_iommu_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c index ea43040f7b..489b5dbad6 100644 --- a/hw/virtio/virtio-net-pci.c +++ b/hw/virtio/virtio-net-pci.c @@ -52,8 +52,7 @@ static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) virtio_net_set_netclient_name(&dev->vdev, qdev->id, object_get_typename(OBJECT(qdev))); - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void virtio_net_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/virtio-pmem-pci.c b/hw/virtio/virtio-pmem-pci.c index fe2af00fa1..11d0c8ebc6 100644 --- a/hw/virtio/virtio-pmem-pci.c +++ b/hw/virtio/virtio-pmem-pci.c @@ -22,8 +22,7 @@ static void virtio_pmem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) VirtIOPMEMPCI *pmem_pci = VIRTIO_PMEM_PCI(vpci_dev); DeviceState *vdev = DEVICE(&pmem_pci->vdev); - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void virtio_pmem_pci_set_addr(MemoryDeviceState *md, uint64_t addr, diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c index 8aaf54b781..cf1afb47a6 100644 --- a/hw/virtio/virtio-rng-pci.c +++ b/hw/virtio/virtio-rng-pci.c @@ -36,8 +36,7 @@ static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) DeviceState *vdev = DEVICE(&vrng->vdev); Error *err = NULL; - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); + qdev_realize(vdev, BUS(&vpci_dev->bus), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/virtio/virtio-scsi-pci.c b/hw/virtio/virtio-scsi-pci.c index e82e7e5680..c23a134202 100644 --- a/hw/virtio/virtio-scsi-pci.c +++ b/hw/virtio/virtio-scsi-pci.c @@ -64,8 +64,7 @@ static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) g_free(bus_name); } - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/virtio/virtio-serial-pci.c b/hw/virtio/virtio-serial-pci.c index 22ab4d8562..95d25d54da 100644 --- a/hw/virtio/virtio-serial-pci.c +++ b/hw/virtio/virtio-serial-pci.c @@ -65,8 +65,7 @@ static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) g_free(bus_name); } - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } static Property virtio_serial_pci_properties[] = { diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index 1c25373852..ef7c832e2e 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -278,9 +278,8 @@ static struct XenLegacyDevice *xen_be_get_xendev(const char *type, int dom, xendev = g_malloc0(ops->size); object_initialize(&xendev->qdev, ops->size, TYPE_XENBACKEND); OBJECT(xendev)->free = g_free; - qdev_set_parent_bus(DEVICE(xendev), xen_sysbus); qdev_set_id(DEVICE(xendev), g_strdup_printf("xen-%s-%d", type, dev)); - qdev_init_nofail(DEVICE(xendev)); + qdev_realize(DEVICE(xendev), xen_sysbus, &error_fatal); object_unref(OBJECT(xendev)); xendev->type = type; From 68424112284f1553e886f3db7ddada7d8ddcbb6a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:01 +0200 Subject: [PATCH 1237/2595] qdev: Convert uses of qdev_set_parent_bus() manually MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same transformation as in the previous commit. Manual, because convincing Coccinelle to transform these cases is somewhere between not worthwhile and infeasible (at least for me). Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-13-armbru@redhat.com> --- hw/pci-host/prep.c | 3 +-- hw/ppc/pnv.c | 6 ++---- hw/s390x/sclp.c | 10 ++++------ 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c index fc01a294a4..a5550d1221 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -268,7 +268,7 @@ static void raven_pcihost_realizefn(DeviceState *d, Error **errp) memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->pci_intack); /* TODO Remove once realize propagates to child devices. */ - object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp); + qdev_realize(DEVICE(&s->pci_dev), BUS(&s->pci_bus), errp); } static void raven_pcihost_initfn(Object *obj) @@ -308,7 +308,6 @@ static void raven_pcihost_initfn(Object *obj) object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_RAVEN_PCI_DEVICE); pci_dev = DEVICE(&s->pci_dev); - qdev_set_parent_bus(pci_dev, BUS(&s->pci_bus)); object_property_set_int(OBJECT(&s->pci_dev), PCI_DEVFN(0, 0), "addr", NULL); qdev_prop_set_bit(pci_dev, "multifunction", false); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 8562af3fe0..e0588285a2 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1212,12 +1212,11 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(phb), i, "index", &error_fatal); object_property_set_int(OBJECT(phb), chip->chip_id, "chip-id", &error_fatal); - object_property_set_bool(OBJECT(phb), true, "realized", &local_err); + qdev_realize(DEVICE(phb), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; } - qdev_set_parent_bus(DEVICE(phb), sysbus_get_default()); /* Populate the XSCOM address space. */ pnv_xscom_add_subregion(chip, @@ -1422,12 +1421,11 @@ static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp) object_property_set_int(obj, PNV_PHB4_DEVICE_ID, "device-id", &error_fatal); object_property_set_link(obj, OBJECT(stack), "stack", &error_abort); - object_property_set_bool(obj, true, "realized", &local_err); + qdev_realize(DEVICE(obj), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; } - qdev_set_parent_bus(DEVICE(obj), sysbus_get_default()); /* Populate the XSCOM address space. */ pnv_xscom_add_subregion(chip, diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 20aca30ac4..40e27a8cb4 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -333,17 +333,15 @@ static void sclp_realize(DeviceState *dev, Error **errp) uint64_t hw_limit; int ret; - object_property_set_bool(OBJECT(sclp->event_facility), true, "realized", - &err); - if (err) { - goto out; - } /* * qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS. As long * as we can't find a fitting bus via the qom tree, we have to add the * event facility to the sysbus, so e.g. a sclp console can be created. */ - qdev_set_parent_bus(DEVICE(sclp->event_facility), sysbus_get_default()); + qdev_realize(DEVICE(sclp->event_facility), NULL, &err); + if (err) { + goto out; + } ret = s390_set_memory_limit(machine->maxram_size, &hw_limit); if (ret == -E2BIG) { From 7411aa63a5f586329f87cbf318addaef427aa906 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:02 +0200 Subject: [PATCH 1238/2595] pci: New pci_new(), pci_realize_and_unref() etc. I'm converting from qdev_create()/qdev_init_nofail() to qdev_new()/qdev_realize_and_unref(); recent commit "qdev: New qdev_new(), qdev_realize(), etc." explains why. PCI devices use qdev_create() through pci_create() and pci_create_multifunction(). Provide pci_new(), pci_new_multifunction(), and pci_realize_and_unref() for converting PCI devices. Cc: Michael S. Tsirkin Cc: Marcel Apfelbaum Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-14-armbru@redhat.com> Reviewed-by: Michael S. Tsirkin --- hw/pci/pci.c | 21 +++++++++++++++++++++ include/hw/pci/pci.h | 5 +++++ 2 files changed, 26 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 955eb11a01..7e759646cf 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2163,6 +2163,27 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) } } +PCIDevice *pci_new_multifunction(int devfn, bool multifunction, + const char *name) +{ + DeviceState *dev; + + dev = qdev_new(name); + qdev_prop_set_int32(dev, "addr", devfn); + qdev_prop_set_bit(dev, "multifunction", multifunction); + return PCI_DEVICE(dev); +} + +PCIDevice *pci_new(int devfn, const char *name) +{ + return pci_new_multifunction(devfn, false, name); +} + +bool pci_realize_and_unref(PCIDevice *dev, PCIBus *bus, Error **errp) +{ + return qdev_realize_and_unref(&dev->qdev, &bus->qbus, errp); +} + PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name) { diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index cfedf5a995..66f8ba519b 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -712,6 +712,11 @@ pci_get_quad_by_mask(uint8_t *config, uint64_t mask) return (val & mask) >> ctz32(mask); } +PCIDevice *pci_new_multifunction(int devfn, bool multifunction, + const char *name); +PCIDevice *pci_new(int devfn, const char *name); +bool pci_realize_and_unref(PCIDevice *dev, PCIBus *bus, Error **errp); + PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name); PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, From 7d61226158b58f84b832390b13a72d3902f56696 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:03 +0200 Subject: [PATCH 1239/2595] hw/ppc: Eliminate two superfluous QOM casts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-15-armbru@redhat.com> Reviewed-by: Michael S. Tsirkin --- hw/ppc/mac_newworld.c | 4 ++-- hw/ppc/mac_oldworld.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 69281d7834..2d069dcc59 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -122,7 +122,7 @@ static void ppc_core99_init(MachineState *machine) long kernel_size, initrd_size; UNINHostState *uninorth_pci; PCIBus *pci_bus; - NewWorldMacIOState *macio; + PCIDevice *macio; bool has_pmu, has_adb; MACIOIDEState *macio_ide; BusState *adb_bus; @@ -375,7 +375,7 @@ static void ppc_core99_init(MachineState *machine) pci_bus = PCI_HOST_BRIDGE(uninorth_pci)->bus; /* MacIO */ - macio = NEWWORLD_MACIO(pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO)); + macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO); dev = DEVICE(macio); qdev_prop_set_uint64(dev, "frequency", tbfreq); qdev_prop_set_bit(dev, "has-pmu", has_pmu); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index cfc2eae1d9..f73ec5f3a9 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -94,7 +94,7 @@ static void ppc_heathrow_init(MachineState *machine) uint32_t kernel_base, initrd_base, cmdline_base = 0; int32_t kernel_size, initrd_size; PCIBus *pci_bus; - OldWorldMacIOState *macio; + PCIDevice *macio; MACIOIDEState *macio_ide; SysBusDevice *s; DeviceState *dev, *pic_dev; @@ -278,7 +278,7 @@ static void ppc_heathrow_init(MachineState *machine) ide_drive_get(hd, ARRAY_SIZE(hd)); /* MacIO */ - macio = OLDWORLD_MACIO(pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO)); + macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO); dev = DEVICE(macio); qdev_prop_set_uint64(dev, "frequency", tbfreq); object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic", From 9307d06da9d12ede17942dc4f1c7bf8d80b4a3c6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:04 +0200 Subject: [PATCH 1240/2595] pci: Convert uses of pci_create() etc. with Coccinelle Replace dev = pci_create(bus, type_name); ... qdev_init_nofail(dev); by dev = pci_new(type_name); ... pci_realize_and_unref(dev, bus, &error_fatal); and similarly for pci_create_multifunction(). Recent commit "qdev: New qdev_new(), qdev_realize(), etc." explains why. Coccinelle script: @@ expression dev, bus, expr; expression list args; @@ - dev = pci_create(bus, args); + dev = pci_new(args); ... when != dev = expr - qdev_init_nofail(&dev->qdev); + pci_realize_and_unref(dev, bus, &error_fatal); @@ expression dev, bus, expr; expression list args; expression d; @@ - dev = pci_create(bus, args); + dev = pci_new(args); ( d = &dev->qdev; | d = DEVICE(dev); ) ... when != dev = expr - qdev_init_nofail(d); + pci_realize_and_unref(dev, bus, &error_fatal); @@ expression dev, bus, expr; expression list args; @@ - dev = pci_create(bus, args); + dev = pci_new(args); ... when != dev = expr - qdev_init_nofail(DEVICE(dev)); + pci_realize_and_unref(dev, bus, &error_fatal); @@ expression dev, bus, expr; expression list args; @@ - dev = DEVICE(pci_create(bus, args)); + PCIDevice *pci_dev; // TODO move + pci_dev = pci_new(args); + dev = DEVICE(pci_dev); ... when != dev = expr - qdev_init_nofail(dev); + pci_realize_and_unref(pci_dev, bus, &error_fatal); @@ expression dev, bus, expr; expression list args; @@ - dev = pci_create_multifunction(bus, args); + dev = pci_new_multifunction(args); ... when != dev = expr - qdev_init_nofail(&dev->qdev); + pci_realize_and_unref(dev, bus, &error_fatal); @@ expression bus, expr; expression list args; identifier dev; @@ - PCIDevice *dev = pci_create_multifunction(bus, args); + PCIDevice *dev = pci_new_multifunction(args); ... when != dev = expr - qdev_init_nofail(&dev->qdev); + pci_realize_and_unref(dev, bus, &error_fatal); @@ expression dev, bus, expr; expression list args; @@ - dev = pci_create_multifunction(bus, args); + dev = pci_new_multifunction(args); ... when != dev = expr - qdev_init_nofail(DEVICE(dev)); + pci_realize_and_unref(dev, bus, &error_fatal); Missing #include "qapi/error.h" added manually, whitespace changes minimized manually, @pci_dev declarations moved manually. Cc: Michael S. Tsirkin Cc: Marcel Apfelbaum Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-16-armbru@redhat.com> Reviewed-by: Michael S. Tsirkin --- hw/acpi/piix4.c | 6 ++++-- hw/i386/pc_q35.c | 10 +++++----- hw/isa/vt82c686.c | 13 +++++++------ hw/mips/fuloong2e.c | 6 ++++-- hw/pci-bridge/dec.c | 6 +++--- hw/pci-host/bonito.c | 4 ++-- hw/pci-host/sabre.c | 13 +++++++------ hw/pci/pci.c | 8 ++++---- hw/ppc/mac_newworld.c | 4 ++-- hw/ppc/mac_oldworld.c | 4 ++-- hw/sparc64/sun4u.c | 8 ++++---- 11 files changed, 44 insertions(+), 38 deletions(-) diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index e27f57195a..1262abc77a 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -514,10 +514,12 @@ I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, qemu_irq sci_irq, qemu_irq smi_irq, int smm_enabled, DeviceState **piix4_pm) { + PCIDevice *pci_dev; DeviceState *dev; PIIX4PMState *s; - dev = DEVICE(pci_create(bus, devfn, TYPE_PIIX4_PM)); + pci_dev = pci_new(devfn, TYPE_PIIX4_PM); + dev = DEVICE(pci_dev); qdev_prop_set_uint32(dev, "smb_io_base", smb_io_base); if (piix4_pm) { *piix4_pm = dev; @@ -531,7 +533,7 @@ I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, s->use_acpi_pci_hotplug = false; } - qdev_init_nofail(dev); + pci_realize_and_unref(pci_dev, bus, &error_fatal); return s->smb.smbus; } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 59307d91e2..a6b6add2ef 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -100,16 +100,16 @@ static int ehci_create_ich9_with_companions(PCIBus *bus, int slot) return -1; } - ehci = pci_create_multifunction(bus, PCI_DEVFN(slot, 7), true, name); - qdev_init_nofail(&ehci->qdev); + ehci = pci_new_multifunction(PCI_DEVFN(slot, 7), true, name); + pci_realize_and_unref(ehci, bus, &error_fatal); usbbus = QLIST_FIRST(&ehci->qdev.child_bus); for (i = 0; i < 3; i++) { - uhci = pci_create_multifunction(bus, PCI_DEVFN(slot, comp[i].func), - true, comp[i].name); + uhci = pci_new_multifunction(PCI_DEVFN(slot, comp[i].func), true, + comp[i].name); qdev_prop_set_string(&uhci->qdev, "masterbus", usbbus->name); qdev_prop_set_uint32(&uhci->qdev, "firstport", comp[i].port); - qdev_init_nofail(&uhci->qdev); + pci_realize_and_unref(uhci, bus, &error_fatal); } return 0; } diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index fac4e56b7d..18160ca445 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -23,6 +23,7 @@ #include "hw/isa/apm.h" #include "hw/acpi/acpi.h" #include "hw/i2c/pm_smbus.h" +#include "qapi/error.h" #include "qemu/module.h" #include "qemu/timer.h" #include "exec/address-spaces.h" @@ -276,8 +277,8 @@ void vt82c686b_ac97_init(PCIBus *bus, int devfn) { PCIDevice *dev; - dev = pci_create(bus, devfn, TYPE_VT82C686B_AC97_DEVICE); - qdev_init_nofail(&dev->qdev); + dev = pci_new(devfn, TYPE_VT82C686B_AC97_DEVICE); + pci_realize_and_unref(dev, bus, &error_fatal); } static void via_ac97_class_init(ObjectClass *klass, void *data) @@ -320,8 +321,8 @@ void vt82c686b_mc97_init(PCIBus *bus, int devfn) { PCIDevice *dev; - dev = pci_create(bus, devfn, TYPE_VT82C686B_MC97_DEVICE); - qdev_init_nofail(&dev->qdev); + dev = pci_new(devfn, TYPE_VT82C686B_MC97_DEVICE); + pci_realize_and_unref(dev, bus, &error_fatal); } static void via_mc97_class_init(ObjectClass *klass, void *data) @@ -388,12 +389,12 @@ I2CBus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, PCIDevice *dev; VT686PMState *s; - dev = pci_create(bus, devfn, TYPE_VT82C686B_PM_DEVICE); + dev = pci_new(devfn, TYPE_VT82C686B_PM_DEVICE); qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base); s = VT82C686B_PM_DEVICE(dev); - qdev_init_nofail(&dev->qdev); + pci_realize_and_unref(dev, bus, &error_fatal); return s->smb.smbus; } diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index 7a65166cf0..8ca31e5162 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -297,6 +297,7 @@ static void mips_fuloong2e_init(MachineState *machine) long bios_size; uint8_t *spd_data; int64_t kernel_entry; + PCIDevice *pci_dev; PCIBus *pci_bus; ISABus *isa_bus; I2CBus *smbus; @@ -367,10 +368,11 @@ static void mips_fuloong2e_init(MachineState *machine) /* GPU */ if (vga_interface_type != VGA_NONE) { - dev = DEVICE(pci_create(pci_bus, -1, "ati-vga")); + pci_dev = pci_new(-1, "ati-vga"); + dev = DEVICE(pci_dev); qdev_prop_set_uint32(dev, "vgamem_mb", 16); qdev_prop_set_uint16(dev, "x-device-id", 0x5159); - qdev_init_nofail(dev); + pci_realize_and_unref(pci_dev, pci_bus, &error_fatal); } /* Populate SPD eeprom data */ diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c index 952bc71122..677a310b96 100644 --- a/hw/pci-bridge/dec.c +++ b/hw/pci-bridge/dec.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "dec.h" #include "hw/sysbus.h" +#include "qapi/error.h" #include "qemu/module.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" @@ -81,11 +82,10 @@ PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) PCIDevice *dev; PCIBridge *br; - dev = pci_create_multifunction(parent_bus, devfn, false, - "dec-21154-p2p-bridge"); + dev = pci_new_multifunction(devfn, false, "dec-21154-p2p-bridge"); br = PCI_BRIDGE(dev); pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq); - qdev_init_nofail(&dev->qdev); + pci_realize_and_unref(dev, parent_bus, &error_fatal); return pci_bridge_get_sec_bus(br); } diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 546ac84cf4..7bb032f005 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -750,11 +750,11 @@ PCIBus *bonito_init(qemu_irq *pic) pcihost->pic = pic; qdev_realize_and_unref(dev, NULL, &error_fatal); - d = pci_create(phb->bus, PCI_DEVFN(0, 0), TYPE_PCI_BONITO); + d = pci_new(PCI_DEVFN(0, 0), TYPE_PCI_BONITO); s = PCI_BONITO(d); s->pcihost = pcihost; pcihost->pci_dev = s; - qdev_init_nofail(DEVICE(d)); + pci_realize_and_unref(d, phb->bus, &error_fatal); return phb->bus; } diff --git a/hw/pci-host/sabre.c b/hw/pci-host/sabre.c index 475bcb01d7..0cc68585f8 100644 --- a/hw/pci-host/sabre.c +++ b/hw/pci-host/sabre.c @@ -35,6 +35,7 @@ #include "hw/pci-bridge/simba.h" #include "hw/pci-host/sabre.h" #include "exec/address-spaces.h" +#include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" #include "sysemu/runstate.h" @@ -405,17 +406,17 @@ static void sabre_realize(DeviceState *dev, Error **errp) pci_setup_iommu(phb->bus, sabre_pci_dma_iommu, s->iommu); /* APB secondary busses */ - pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, - TYPE_SIMBA_PCI_BRIDGE); + pci_dev = pci_new_multifunction(PCI_DEVFN(1, 0), true, + TYPE_SIMBA_PCI_BRIDGE); s->bridgeB = PCI_BRIDGE(pci_dev); pci_bridge_map_irq(s->bridgeB, "pciB", pci_simbaB_map_irq); - qdev_init_nofail(&pci_dev->qdev); + pci_realize_and_unref(pci_dev, phb->bus, &error_fatal); - pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true, - TYPE_SIMBA_PCI_BRIDGE); + pci_dev = pci_new_multifunction(PCI_DEVFN(1, 1), true, + TYPE_SIMBA_PCI_BRIDGE); s->bridgeA = PCI_BRIDGE(pci_dev); pci_bridge_map_irq(s->bridgeA, "pciA", pci_simbaA_map_irq); - qdev_init_nofail(&pci_dev->qdev); + pci_realize_and_unref(pci_dev, phb->bus, &error_fatal); } static void sabre_init(Object *obj) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 7e759646cf..24f726d4cd 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1953,10 +1953,10 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, exit(1); } - pci_dev = pci_create(bus, devfn, nd->model); + pci_dev = pci_new(devfn, nd->model); dev = &pci_dev->qdev; qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + pci_realize_and_unref(pci_dev, bus, &error_fatal); g_ptr_array_free(pci_nic_models, true); return pci_dev; } @@ -2199,8 +2199,8 @@ PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name) { - PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction, name); - qdev_init_nofail(&dev->qdev); + PCIDevice *dev = pci_new_multifunction(devfn, multifunction, name); + pci_realize_and_unref(dev, bus, &error_fatal); return dev; } diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 2d069dcc59..baa17cdce7 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -375,14 +375,14 @@ static void ppc_core99_init(MachineState *machine) pci_bus = PCI_HOST_BRIDGE(uninorth_pci)->bus; /* MacIO */ - macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO); + macio = pci_new(-1, TYPE_NEWWORLD_MACIO); dev = DEVICE(macio); qdev_prop_set_uint64(dev, "frequency", tbfreq); qdev_prop_set_bit(dev, "has-pmu", has_pmu); qdev_prop_set_bit(dev, "has-adb", has_adb); object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic", &error_abort); - qdev_init_nofail(dev); + pci_realize_and_unref(macio, pci_bus, &error_fatal); /* We only emulate 2 out of 3 IDE controllers for now */ ide_drive_get(hd, ARRAY_SIZE(hd)); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index f73ec5f3a9..903483079e 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -278,12 +278,12 @@ static void ppc_heathrow_init(MachineState *machine) ide_drive_get(hd, ARRAY_SIZE(hd)); /* MacIO */ - macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO); + macio = pci_new(-1, TYPE_OLDWORLD_MACIO); dev = DEVICE(macio); qdev_prop_set_uint64(dev, "frequency", tbfreq); object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic", &error_abort); - qdev_init_nofail(dev); + pci_realize_and_unref(macio, pci_bus, &error_fatal); macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), "ide[0]")); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index ade9c22825..6f29a013ca 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -605,10 +605,10 @@ static void sun4uv_init(MemoryRegion *address_space_mem, pci_busA->slot_reserved_mask = 0xfffffff1; pci_busB->slot_reserved_mask = 0xfffffff0; - ebus = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 0), true, TYPE_EBUS); + ebus = pci_new_multifunction(PCI_DEVFN(1, 0), true, TYPE_EBUS); qdev_prop_set_uint64(DEVICE(ebus), "console-serial-base", hwdef->console_serial_base); - qdev_init_nofail(DEVICE(ebus)); + pci_realize_and_unref(ebus, pci_busA, &error_fatal); /* Wire up "well-known" ISA IRQs to PBM legacy obio IRQs */ qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 7, @@ -661,9 +661,9 @@ static void sun4uv_init(MemoryRegion *address_space_mem, qemu_macaddr_default_if_unset(&macaddr); } - pci_dev = pci_create(pci_busA, PCI_DEVFN(3, 0), "cmd646-ide"); + pci_dev = pci_new(PCI_DEVFN(3, 0), "cmd646-ide"); qdev_prop_set_uint32(&pci_dev->qdev, "secondary", 1); - qdev_init_nofail(&pci_dev->qdev); + pci_realize_and_unref(pci_dev, pci_busA, &error_fatal); pci_ide_create_devs(pci_dev); /* Map NVRAM into I/O (ebus) space */ From db2322469a245eb9d9aa1c98747f6d595cca8f35 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:05 +0200 Subject: [PATCH 1241/2595] pci: Convert uses of pci_create() etc. manually Same transformation as in the previous commit. Manual, because convincing Coccinelle to transform these cases is not worthwhile. Cc: Michael S. Tsirkin Cc: Marcel Apfelbaum Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-17-armbru@redhat.com> Reviewed-by: Michael S. Tsirkin --- hw/sparc64/sun4u.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 6f29a013ca..0b898d6e3d 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -635,24 +635,28 @@ static void sun4uv_init(MemoryRegion *address_space_mem, memset(&macaddr, 0, sizeof(MACAddr)); onboard_nic = false; for (i = 0; i < nb_nics; i++) { + PCIBus *bus; nd = &nd_table[i]; if (!nd->model || strcmp(nd->model, "sunhme") == 0) { if (!onboard_nic) { - pci_dev = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 1), + pci_dev = pci_new_multifunction(PCI_DEVFN(1, 1), true, "sunhme"); + bus = pci_busA; memcpy(&macaddr, &nd->macaddr.a, sizeof(MACAddr)); onboard_nic = true; } else { - pci_dev = pci_create(pci_busB, -1, "sunhme"); + pci_dev = pci_new(-1, "sunhme"); + bus = pci_busB; } } else { - pci_dev = pci_create(pci_busB, -1, nd->model); + pci_dev = pci_new(-1, nd->model); + bus = pci_busB; } dev = &pci_dev->qdev; qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + pci_realize_and_unref(pci_dev, bus, &error_fatal); } /* If we don't have an onboard NIC, grab a default MAC address so that From a9cf5c46c6a6fd965cf12ddb37f44d25e914bf04 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:06 +0200 Subject: [PATCH 1242/2595] pci: pci_create(), pci_create_multifunction() are now unused, drop Cc: Michael S. Tsirkin Cc: Marcel Apfelbaum Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-18-armbru@redhat.com> Reviewed-by: Michael S. Tsirkin --- hw/pci/pci.c | 16 ---------------- include/hw/pci/pci.h | 3 --- 2 files changed, 19 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 24f726d4cd..b22dedc88c 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2184,17 +2184,6 @@ bool pci_realize_and_unref(PCIDevice *dev, PCIBus *bus, Error **errp) return qdev_realize_and_unref(&dev->qdev, &bus->qbus, errp); } -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, - const char *name) -{ - DeviceState *dev; - - dev = qdev_create(&bus->qbus, name); - qdev_prop_set_int32(dev, "addr", devfn); - qdev_prop_set_bit(dev, "multifunction", multifunction); - return PCI_DEVICE(dev); -} - PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name) @@ -2204,11 +2193,6 @@ PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, return dev; } -PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name) -{ - return pci_create_multifunction(bus, devfn, false, name); -} - PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) { return pci_create_simple_multifunction(bus, devfn, false, name); diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 66f8ba519b..a4e9c33416 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -717,12 +717,9 @@ PCIDevice *pci_new_multifunction(int devfn, bool multifunction, PCIDevice *pci_new(int devfn, const char *name); bool pci_realize_and_unref(PCIDevice *dev, PCIBus *bus, Error **errp); -PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, - const char *name); PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name); -PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name); void lsi53c8xx_handle_legacy_cmdline(DeviceState *lsi_dev); From 0fe9d9011971820b2dab27aa49cfb957b91cc3e2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:07 +0200 Subject: [PATCH 1243/2595] isa: New isa_new(), isa_realize_and_unref() etc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm converting from qdev_create()/qdev_init_nofail() to qdev_new()/qdev_realize_and_unref(); recent commit "qdev: New qdev_new(), qdev_realize(), etc." explains why. ISA devices use qdev_create() through isa_create() and isa_try_create(). Provide isa_new(), isa_try_new(), and isa_realize_and_unref() for converting ISA devices. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-19-armbru@redhat.com> --- hw/isa/isa-bus.c | 15 +++++++++++++++ include/hw/isa/isa.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 1c9d7e19ab..e6412d39b4 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -176,6 +176,16 @@ ISADevice *isa_try_create(ISABus *bus, const char *name) return ISA_DEVICE(dev); } +ISADevice *isa_new(const char *name) +{ + return ISA_DEVICE(qdev_new(name)); +} + +ISADevice *isa_try_new(const char *name) +{ + return ISA_DEVICE(qdev_try_new(name)); +} + ISADevice *isa_create_simple(ISABus *bus, const char *name) { ISADevice *dev; @@ -185,6 +195,11 @@ ISADevice *isa_create_simple(ISABus *bus, const char *name) return dev; } +bool isa_realize_and_unref(ISADevice *dev, ISABus *bus, Error **errp) +{ + return qdev_realize_and_unref(&dev->parent_obj, &bus->parent_obj, errp); +} + ISADevice *isa_vga_init(ISABus *bus) { switch (vga_interface_type) { diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index 02c2350274..3b6215fafe 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -105,6 +105,9 @@ MemoryRegion *isa_address_space(ISADevice *dev); MemoryRegion *isa_address_space_io(ISADevice *dev); ISADevice *isa_create(ISABus *bus, const char *name); ISADevice *isa_try_create(ISABus *bus, const char *name); +ISADevice *isa_new(const char *name); +ISADevice *isa_try_new(const char *name); +bool isa_realize_and_unref(ISADevice *dev, ISABus *bus, Error **errp); ISADevice *isa_create_simple(ISABus *bus, const char *name); ISADevice *isa_vga_init(ISABus *bus); From 96927c744f9cd5205f95ef897c35695038dc2896 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:08 +0200 Subject: [PATCH 1244/2595] isa: Convert uses of isa_create() with Coccinelle Replace dev = isa_create(bus, type_name); ... qdev_init_nofail(dev); by dev = isa_new(type_name); ... isa_realize_and_unref(dev, bus, &error_fatal); Recent commit "qdev: New qdev_new(), qdev_realize(), etc." explains why. Coccinelle script: @@ expression dev, bus, expr; expression list args; expression d; @@ - dev = isa_create(bus, args); + dev = isa_new(args); ( d = &dev->qdev; | d = DEVICE(dev); ) ... when != dev = expr - qdev_init_nofail(d); + isa_realize_and_unref(dev, bus, &error_fatal); @@ expression dev, bus, expr; expression list args; @@ - dev = isa_create(bus, args); + dev = isa_new(args); ... when != dev = expr - qdev_init_nofail(DEVICE(dev)); + isa_realize_and_unref(dev, bus, &error_fatal); @@ expression dev, bus, expr; expression list args; @@ - dev = DEVICE(isa_create(bus, args)); + ISADevice *isa_dev; // TODO move + isa_dev = isa_new(args); + dev = DEVICE(isa_dev); ... when != dev = expr - qdev_init_nofail(dev); + isa_realize_and_unref(isa_dev, bus, &error_fatal); Missing #include "qapi/error.h" added manually, whitespace changes minimized manually. Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-20-armbru@redhat.com> --- hw/char/parallel-isa.c | 5 +++-- hw/char/serial-isa.c | 4 ++-- hw/dma/i8257.c | 9 +++++---- hw/ide/isa.c | 5 +++-- hw/intc/i8259_common.c | 5 +++-- hw/isa/isa-bus.c | 4 ++-- hw/isa/isa-superio.c | 20 ++++++++++---------- hw/ppc/prep.c | 26 ++++++++++++++++---------- hw/rtc/m48t59-isa.c | 7 +++++-- hw/rtc/mc146818rtc.c | 4 ++-- hw/sparc64/sun4u.c | 6 ++++-- include/hw/audio/pcspk.h | 5 +++-- include/hw/timer/i8254.h | 9 +++++---- 13 files changed, 63 insertions(+), 46 deletions(-) diff --git a/hw/char/parallel-isa.c b/hw/char/parallel-isa.c index bcc577f61c..1ccbb96e70 100644 --- a/hw/char/parallel-isa.c +++ b/hw/char/parallel-isa.c @@ -14,17 +14,18 @@ #include "hw/isa/isa.h" #include "hw/qdev-properties.h" #include "hw/char/parallel.h" +#include "qapi/error.h" static void parallel_init(ISABus *bus, int index, Chardev *chr) { DeviceState *dev; ISADevice *isadev; - isadev = isa_create(bus, "isa-parallel"); + isadev = isa_new("isa-parallel"); dev = DEVICE(isadev); qdev_prop_set_uint32(dev, "index", index); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + isa_realize_and_unref(isadev, bus, &error_fatal); } void parallel_hds_isa_init(ISABus *bus, int n) diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index 165e320e65..d69aab5714 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -160,11 +160,11 @@ static void serial_isa_init(ISABus *bus, int index, Chardev *chr) DeviceState *dev; ISADevice *isadev; - isadev = isa_create(bus, TYPE_ISA_SERIAL); + isadev = isa_new(TYPE_ISA_SERIAL); dev = DEVICE(isadev); qdev_prop_set_uint32(dev, "index", index); qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); + isa_realize_and_unref(isadev, bus, &error_fatal); } void serial_hds_isa_init(ISABus *bus, int from, int to) diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c index 1b3435ab58..db808029b0 100644 --- a/hw/dma/i8257.c +++ b/hw/dma/i8257.c @@ -27,6 +27,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "hw/dma/i8257.h" +#include "qapi/error.h" #include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/log.h" @@ -638,21 +639,21 @@ void i8257_dma_init(ISABus *bus, bool high_page_enable) ISADevice *isa1, *isa2; DeviceState *d; - isa1 = isa_create(bus, TYPE_I8257); + isa1 = isa_new(TYPE_I8257); d = DEVICE(isa1); qdev_prop_set_int32(d, "base", 0x00); qdev_prop_set_int32(d, "page-base", 0x80); qdev_prop_set_int32(d, "pageh-base", high_page_enable ? 0x480 : -1); qdev_prop_set_int32(d, "dshift", 0); - qdev_init_nofail(d); + isa_realize_and_unref(isa1, bus, &error_fatal); - isa2 = isa_create(bus, TYPE_I8257); + isa2 = isa_new(TYPE_I8257); d = DEVICE(isa2); qdev_prop_set_int32(d, "base", 0xc0); qdev_prop_set_int32(d, "page-base", 0x88); qdev_prop_set_int32(d, "pageh-base", high_page_enable ? 0x488 : -1); qdev_prop_set_int32(d, "dshift", 1); - qdev_init_nofail(d); + isa_realize_and_unref(isa2, bus, &error_fatal); isa_bus_dma(bus, ISADMA(isa1), ISADMA(isa2)); } diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 8395807b08..f28c8fba6c 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -27,6 +27,7 @@ #include "hw/isa/isa.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" +#include "qapi/error.h" #include "qemu/module.h" #include "sysemu/dma.h" @@ -86,12 +87,12 @@ ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq, ISADevice *isadev; ISAIDEState *s; - isadev = isa_create(bus, TYPE_ISA_IDE); + isadev = isa_new(TYPE_ISA_IDE); dev = DEVICE(isadev); qdev_prop_set_uint32(dev, "iobase", iobase); qdev_prop_set_uint32(dev, "iobase2", iobase2); qdev_prop_set_uint32(dev, "irq", isairq); - qdev_init_nofail(dev); + isa_realize_and_unref(isadev, bus, &error_fatal); s = ISA_IDE(dev); if (hd0) { diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c index 99f8f6abd5..d90b40fe4c 100644 --- a/hw/intc/i8259_common.c +++ b/hw/intc/i8259_common.c @@ -29,6 +29,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "monitor/monitor.h" +#include "qapi/error.h" static int irq_level[16]; static uint64_t irq_count[16]; @@ -94,13 +95,13 @@ ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master) DeviceState *dev; ISADevice *isadev; - isadev = isa_create(bus, name); + isadev = isa_new(name); dev = DEVICE(isadev); qdev_prop_set_uint32(dev, "iobase", master ? 0x20 : 0xa0); qdev_prop_set_uint32(dev, "elcr_addr", master ? 0x4d0 : 0x4d1); qdev_prop_set_uint8(dev, "elcr_mask", master ? 0xf8 : 0xde); qdev_prop_set_bit(dev, "master", master); - qdev_init_nofail(dev); + isa_realize_and_unref(isadev, bus, &error_fatal); return isadev; } diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index e6412d39b4..9a95ac3f96 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -190,8 +190,8 @@ ISADevice *isa_create_simple(ISABus *bus, const char *name) { ISADevice *dev; - dev = isa_create(bus, name); - qdev_init_nofail(DEVICE(dev)); + dev = isa_new(name); + isa_realize_and_unref(dev, bus, &error_fatal); return dev; } diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index 3dcdc234a4..d3d58f9f16 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -51,7 +51,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) } else { name = g_strdup_printf("parallel%d", i); } - isa = isa_create(bus, "isa-parallel"); + isa = isa_new("isa-parallel"); d = DEVICE(isa); qdev_prop_set_uint32(d, "index", i); if (k->parallel.get_iobase) { @@ -63,7 +63,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) } qdev_prop_set_chr(d, "chardev", chr); object_property_add_child(OBJECT(dev), name, OBJECT(isa)); - qdev_init_nofail(d); + isa_realize_and_unref(isa, bus, &error_fatal); sio->parallel[i] = isa; trace_superio_create_parallel(i, k->parallel.get_iobase ? @@ -90,7 +90,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) } else { name = g_strdup_printf("serial%d", i); } - isa = isa_create(bus, TYPE_ISA_SERIAL); + isa = isa_new(TYPE_ISA_SERIAL); d = DEVICE(isa); qdev_prop_set_uint32(d, "index", i); if (k->serial.get_iobase) { @@ -102,7 +102,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) } qdev_prop_set_chr(d, "chardev", chr); object_property_add_child(OBJECT(dev), name, OBJECT(isa)); - qdev_init_nofail(d); + isa_realize_and_unref(isa, bus, &error_fatal); sio->serial[i] = isa; trace_superio_create_serial(i, k->serial.get_iobase ? @@ -115,7 +115,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) /* Floppy disc */ if (!k->floppy.is_enabled || k->floppy.is_enabled(sio, 0)) { - isa = isa_create(bus, "isa-fdc"); + isa = isa_new("isa-fdc"); d = DEVICE(isa); if (k->floppy.get_iobase) { qdev_prop_set_uint32(d, "iobase", k->floppy.get_iobase(sio, 0)); @@ -136,7 +136,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) &error_fatal); } object_property_add_child(OBJECT(sio), "isa-fdc", OBJECT(isa)); - qdev_init_nofail(d); + isa_realize_and_unref(isa, bus, &error_fatal); sio->floppy = isa; trace_superio_create_floppy(0, k->floppy.get_iobase ? @@ -146,14 +146,14 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) } /* Keyboard, mouse */ - isa = isa_create(bus, TYPE_I8042); + isa = isa_new(TYPE_I8042); object_property_add_child(OBJECT(sio), TYPE_I8042, OBJECT(isa)); - qdev_init_nofail(DEVICE(isa)); + isa_realize_and_unref(isa, bus, &error_fatal); sio->kbc = isa; /* IDE */ if (k->ide.count && (!k->ide.is_enabled || k->ide.is_enabled(sio, 0))) { - isa = isa_create(bus, "isa-ide"); + isa = isa_new("isa-ide"); d = DEVICE(isa); if (k->ide.get_iobase) { qdev_prop_set_uint32(d, "iobase", k->ide.get_iobase(sio, 0)); @@ -164,7 +164,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) if (k->ide.get_irq) { qdev_prop_set_uint32(d, "irq", k->ide.get_irq(sio, 0)); } - qdev_init_nofail(d); + isa_realize_and_unref(isa, bus, &error_fatal); object_property_add_child(OBJECT(sio), "isa-ide", OBJECT(isa)); sio->ide = isa; trace_superio_create_ide(0, diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index c7af0e16c3..73a40b2cbe 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -244,6 +244,7 @@ static void ibm_40p_init(MachineState *machine) SysBusDevice *pcihost, *s; Nvram *m48t59 = NULL; PCIBus *pci_bus; + ISADevice *isa_dev; ISABus *isa_bus; void *fw_cfg; int i; @@ -292,14 +293,16 @@ static void ibm_40p_init(MachineState *machine) isa_bus = ISA_BUS(qdev_get_child_bus(i82378_dev, "isa.0")); /* Memory controller */ - dev = DEVICE(isa_create(isa_bus, "rs6000-mc")); + isa_dev = isa_new("rs6000-mc"); + dev = DEVICE(isa_dev); qdev_prop_set_uint32(dev, "ram-size", machine->ram_size); - qdev_init_nofail(dev); + isa_realize_and_unref(isa_dev, isa_bus, &error_fatal); /* RTC */ - dev = DEVICE(isa_create(isa_bus, TYPE_MC146818_RTC)); + isa_dev = isa_new(TYPE_MC146818_RTC); + dev = DEVICE(isa_dev); qdev_prop_set_int32(dev, "base_year", 1900); - qdev_init_nofail(dev); + isa_realize_and_unref(isa_dev, isa_bus, &error_fatal); /* initialize CMOS checksums */ cmos_checksum = 0x6aa9; @@ -310,19 +313,22 @@ static void ibm_40p_init(MachineState *machine) if (defaults_enabled()) { m48t59 = NVRAM(isa_create_simple(isa_bus, "isa-m48t59")); - dev = DEVICE(isa_create(isa_bus, "cs4231a")); + isa_dev = isa_new("cs4231a"); + dev = DEVICE(isa_dev); qdev_prop_set_uint32(dev, "iobase", 0x830); qdev_prop_set_uint32(dev, "irq", 10); - qdev_init_nofail(dev); + isa_realize_and_unref(isa_dev, isa_bus, &error_fatal); - dev = DEVICE(isa_create(isa_bus, "pc87312")); + isa_dev = isa_new("pc87312"); + dev = DEVICE(isa_dev); qdev_prop_set_uint32(dev, "config", 12); - qdev_init_nofail(dev); + isa_realize_and_unref(isa_dev, isa_bus, &error_fatal); - dev = DEVICE(isa_create(isa_bus, "prep-systemio")); + isa_dev = isa_new("prep-systemio"); + dev = DEVICE(isa_dev); qdev_prop_set_uint32(dev, "ibm-planar-id", 0xfc); qdev_prop_set_uint32(dev, "equipment", 0xc0); - qdev_init_nofail(dev); + isa_realize_and_unref(isa_dev, isa_bus, &error_fatal); dev = DEVICE(pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "lsi53c810")); diff --git a/hw/rtc/m48t59-isa.c b/hw/rtc/m48t59-isa.c index 131eb5b7d3..50430b7a85 100644 --- a/hw/rtc/m48t59-isa.c +++ b/hw/rtc/m48t59-isa.c @@ -28,6 +28,7 @@ #include "hw/qdev-properties.h" #include "hw/rtc/m48t59.h" #include "m48t59-internal.h" +#include "qapi/error.h" #include "qemu/module.h" #define TYPE_M48TXX_ISA "isa-m48txx" @@ -61,6 +62,7 @@ static M48txxInfo m48txx_isa_info[] = { Nvram *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size, int base_year, int model) { + ISADevice *isa_dev; DeviceState *dev; int i; @@ -70,10 +72,11 @@ Nvram *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size, continue; } - dev = DEVICE(isa_create(bus, m48txx_isa_info[i].bus_name)); + isa_dev = isa_new(m48txx_isa_info[i].bus_name); + dev = DEVICE(isa_dev); qdev_prop_set_uint32(dev, "iobase", io_base); qdev_prop_set_int32(dev, "base-year", base_year); - qdev_init_nofail(dev); + isa_realize_and_unref(isa_dev, bus, &error_fatal); return NVRAM(dev); } diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 1e9fa0f33f..7a38540cb9 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -974,10 +974,10 @@ ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) DeviceState *dev; ISADevice *isadev; - isadev = isa_create(bus, TYPE_MC146818_RTC); + isadev = isa_new(TYPE_MC146818_RTC); dev = DEVICE(isadev); qdev_prop_set_int32(dev, "base_year", base_year); - qdev_init_nofail(dev); + isa_realize_and_unref(isadev, bus, &error_fatal); if (intercept_irq) { qdev_connect_gpio_out(dev, 0, intercept_irq); } else { diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 0b898d6e3d..8470c33f99 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -300,6 +300,7 @@ static void ebus_isa_irq_handler(void *opaque, int n, int level) static void ebus_realize(PCIDevice *pci_dev, Error **errp) { EbusState *s = EBUS(pci_dev); + ISADevice *isa_dev; SysBusDevice *sbd; DeviceState *dev; qemu_irq *isa_irq; @@ -338,7 +339,8 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) for (i = 0; i < MAX_FD; i++) { fd[i] = drive_get(IF_FLOPPY, 0, i); } - dev = DEVICE(isa_create(s->isa_bus, TYPE_ISA_FDC)); + isa_dev = isa_new(TYPE_ISA_FDC); + dev = DEVICE(isa_dev); if (fd[0]) { qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fd[0]), &error_abort); @@ -348,7 +350,7 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) &error_abort); } qdev_prop_set_uint32(dev, "dma", -1); - qdev_init_nofail(dev); + isa_realize_and_unref(isa_dev, s->isa_bus, &error_fatal); /* Power */ dev = qdev_new(TYPE_SUN4U_POWER); diff --git a/include/hw/audio/pcspk.h b/include/hw/audio/pcspk.h index 632cce9f68..7e7f5f49dc 100644 --- a/include/hw/audio/pcspk.h +++ b/include/hw/audio/pcspk.h @@ -27,6 +27,7 @@ #include "hw/isa/isa.h" #include "hw/qdev-properties.h" +#include "qapi/error.h" #define TYPE_PC_SPEAKER "isa-pcspk" @@ -35,11 +36,11 @@ static inline ISADevice *pcspk_init(ISABus *bus, ISADevice *pit) DeviceState *dev; ISADevice *isadev; - isadev = isa_create(bus, TYPE_PC_SPEAKER); + isadev = isa_new(TYPE_PC_SPEAKER); dev = DEVICE(isadev); qdev_prop_set_uint32(dev, "iobase", 0x61); object_property_set_link(OBJECT(dev), OBJECT(pit), "pit", NULL); - qdev_init_nofail(dev); + isa_realize_and_unref(isadev, bus, &error_fatal); return isadev; } diff --git a/include/hw/timer/i8254.h b/include/hw/timer/i8254.h index 45cb42571f..e75b4a5a08 100644 --- a/include/hw/timer/i8254.h +++ b/include/hw/timer/i8254.h @@ -27,6 +27,7 @@ #include "hw/qdev-properties.h" #include "hw/isa/isa.h" +#include "qapi/error.h" #define PIT_FREQ 1193182 @@ -54,10 +55,10 @@ static inline ISADevice *i8254_pit_init(ISABus *bus, int base, int isa_irq, DeviceState *dev; ISADevice *d; - d = isa_create(bus, TYPE_I8254); + d = isa_new(TYPE_I8254); dev = DEVICE(d); qdev_prop_set_uint32(dev, "iobase", base); - qdev_init_nofail(dev); + isa_realize_and_unref(d, bus, &error_fatal); qdev_connect_gpio_out(dev, 0, isa_irq >= 0 ? isa_get_irq(d, isa_irq) : alt_irq); @@ -69,10 +70,10 @@ static inline ISADevice *kvm_pit_init(ISABus *bus, int base) DeviceState *dev; ISADevice *d; - d = isa_create(bus, TYPE_KVM_I8254); + d = isa_new(TYPE_KVM_I8254); dev = DEVICE(d); qdev_prop_set_uint32(dev, "iobase", base); - qdev_init_nofail(dev); + isa_realize_and_unref(d, bus, &error_fatal); return d; } From c23e05614e54e11f54961fbf086193ccb4cf8aa5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:09 +0200 Subject: [PATCH 1245/2595] isa: Convert uses of isa_create(), isa_try_create() manually Same transformation as in the previous commit. Manual, because convincing Coccinelle to transform these cases is not worthwhile. Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-21-armbru@redhat.com> --- hw/block/fdc.c | 4 ++-- hw/i386/pc.c | 4 ++-- hw/ppc/pnv.c | 9 ++++----- include/hw/net/ne2000-isa.h | 5 +++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 1feb398875..a3250f6fdb 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2544,7 +2544,7 @@ ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds) DeviceState *dev; ISADevice *isadev; - isadev = isa_try_create(bus, TYPE_ISA_FDC); + isadev = isa_try_new(TYPE_ISA_FDC); if (!isadev) { return NULL; } @@ -2558,7 +2558,7 @@ ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds) qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]), &error_fatal); } - qdev_init_nofail(dev); + isa_realize_and_unref(isadev, bus, &error_fatal); return isadev; } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index ab2380c01f..30a2b5eb30 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1158,14 +1158,14 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport) i8042 = isa_create_simple(isa_bus, "i8042"); if (!no_vmport) { isa_create_simple(isa_bus, TYPE_VMPORT); - vmmouse = isa_try_create(isa_bus, "vmmouse"); + vmmouse = isa_try_new("vmmouse"); } else { vmmouse = NULL; } if (vmmouse) { object_property_set_link(OBJECT(vmmouse), OBJECT(i8042), "i8042", &error_abort); - qdev_init_nofail(DEVICE(vmmouse)); + isa_realize_and_unref(vmmouse, isa_bus, &error_fatal); } port92 = isa_create_simple(isa_bus, TYPE_PORT92); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index e0588285a2..ffaf12b006 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -694,12 +694,11 @@ static bool pnv_match_cpu(const char *default_type, const char *cpu_type) static void pnv_ipmi_bt_init(ISABus *bus, IPMIBmc *bmc, uint32_t irq) { - Object *obj; + ISADevice *dev = isa_new("isa-ipmi-bt"); - obj = OBJECT(isa_create(bus, "isa-ipmi-bt")); - object_property_set_link(obj, OBJECT(bmc), "bmc", &error_fatal); - object_property_set_int(obj, irq, "irq", &error_fatal); - object_property_set_bool(obj, true, "realized", &error_fatal); + object_property_set_link(OBJECT(dev), OBJECT(bmc), "bmc", &error_fatal); + object_property_set_int(OBJECT(dev), irq, "irq", &error_fatal); + isa_realize_and_unref(dev, bus, &error_fatal); } static void pnv_chip_power10_pic_print_info(PnvChip *chip, Monitor *mon) diff --git a/include/hw/net/ne2000-isa.h b/include/hw/net/ne2000-isa.h index eef17a680d..af59ee0b02 100644 --- a/include/hw/net/ne2000-isa.h +++ b/include/hw/net/ne2000-isa.h @@ -13,6 +13,7 @@ #include "hw/isa/isa.h" #include "hw/qdev-properties.h" #include "net/net.h" +#include "qapi/error.h" #define TYPE_ISA_NE2000 "ne2k_isa" @@ -23,14 +24,14 @@ static inline ISADevice *isa_ne2000_init(ISABus *bus, int base, int irq, qemu_check_nic_model(nd, "ne2k_isa"); - d = isa_try_create(bus, TYPE_ISA_NE2000); + d = isa_try_new(TYPE_ISA_NE2000); if (d) { DeviceState *dev = DEVICE(d); qdev_prop_set_uint32(dev, "iobase", base); qdev_prop_set_uint32(dev, "irq", irq); qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); + isa_realize_and_unref(d, bus, &error_fatal); } return d; } From bd2f053dc5de7b28729a4a23e180de198d59159f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:10 +0200 Subject: [PATCH 1246/2595] isa: isa_create(), isa_try_create() are now unused, drop Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-22-armbru@redhat.com> --- hw/isa/isa-bus.c | 16 ---------------- include/hw/isa/isa.h | 2 -- 2 files changed, 18 deletions(-) diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 9a95ac3f96..630985604d 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -160,22 +160,6 @@ static void isa_device_init(Object *obj) dev->isairq[1] = -1; } -ISADevice *isa_create(ISABus *bus, const char *name) -{ - DeviceState *dev; - - dev = qdev_create(BUS(bus), name); - return ISA_DEVICE(dev); -} - -ISADevice *isa_try_create(ISABus *bus, const char *name) -{ - DeviceState *dev; - - dev = qdev_try_create(BUS(bus), name); - return ISA_DEVICE(dev); -} - ISADevice *isa_new(const char *name) { return ISA_DEVICE(qdev_new(name)); diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index 3b6215fafe..52b61eed88 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -103,8 +103,6 @@ void isa_bus_dma(ISABus *bus, IsaDma *dma8, IsaDma *dma16); IsaDma *isa_get_dma(ISABus *bus, int nchan); MemoryRegion *isa_address_space(ISADevice *dev); MemoryRegion *isa_address_space_io(ISADevice *dev); -ISADevice *isa_create(ISABus *bus, const char *name); -ISADevice *isa_try_create(ISABus *bus, const char *name); ISADevice *isa_new(const char *name); ISADevice *isa_try_new(const char *name); bool isa_realize_and_unref(ISADevice *dev, ISABus *bus, Error **errp); From 7f16c76e83cedeea0e4cec8942c974885a216865 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:11 +0200 Subject: [PATCH 1247/2595] ssi: ssi_auto_connect_slaves() never does anything, drop ssi_auto_connect_slaves(parent, cs_line, bus) iterates over @parent's QOM children @dev of type TYPE_SSI_SLAVE. It puts these on @bus, and sets cs_line[] to qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0). Suspicious: there is no protection against overrunning cs_line[]. Turns out it's safe because ssi_auto_connect_slaves() never finds any such children. Its called by realize methods of some (but not all) devices providing an SSI bus, and gets passed the device. SSI slave devices are always created with ssi_create_slave_no_init(), optionally via ssi_create_slave(). This adds them to their SSI bus. It doesn't set their QOM parent. ssi_create_slave_no_init() is always immediately followed by qdev_init_nofail(), with no QOM parent assigned, so device_set_realized() puts the device into the /machine/unattached/ orphanage. None become QOM children of a device providing an SSI bus. ssi_auto_connect_slaves() was added in commit b4ae3cfa57 "ssi: Add slave autoconnect helper". I can't see which slaves it was supposed to connect back then. Cc: Alistair Francis Signed-off-by: Markus Armbruster Acked-by: Alistair Francis Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-23-armbru@redhat.com> --- hw/ssi/aspeed_smc.c | 1 - hw/ssi/imx_spi.c | 2 -- hw/ssi/mss-spi.c | 1 - hw/ssi/ssi.c | 33 --------------------------------- hw/ssi/xilinx_spi.c | 1 - hw/ssi/xilinx_spips.c | 4 ---- include/hw/ssi/ssi.h | 4 ---- 7 files changed, 46 deletions(-) diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 2edccef2d5..4fab1f5f85 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -1356,7 +1356,6 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) /* Setup cs_lines for slaves */ s->cs_lines = g_new0(qemu_irq, s->num_cs); - ssi_auto_connect_slaves(dev, s->cs_lines, s->spi); for (i = 0; i < s->num_cs; ++i) { sysbus_init_irq(sbd, &s->cs_lines[i]); diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c index 43b2f14dd2..7f703d8328 100644 --- a/hw/ssi/imx_spi.c +++ b/hw/ssi/imx_spi.c @@ -424,8 +424,6 @@ static void imx_spi_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); - ssi_auto_connect_slaves(dev, s->cs_lines, s->bus); - for (i = 0; i < 4; ++i) { sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]); } diff --git a/hw/ssi/mss-spi.c b/hw/ssi/mss-spi.c index 3050fabb69..b2432c5a13 100644 --- a/hw/ssi/mss-spi.c +++ b/hw/ssi/mss-spi.c @@ -376,7 +376,6 @@ static void mss_spi_realize(DeviceState *dev, Error **errp) s->spi = ssi_create_bus(dev, "spi"); sysbus_init_irq(sbd, &s->irq); - ssi_auto_connect_slaves(dev, &s->cs_line, s->spi); sysbus_init_irq(sbd, &s->cs_line); memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s, diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index c6415eb6e3..54106f5ef8 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -142,36 +142,3 @@ static void ssi_slave_register_types(void) } type_init(ssi_slave_register_types) - -typedef struct SSIAutoConnectArg { - qemu_irq **cs_linep; - SSIBus *bus; -} SSIAutoConnectArg; - -static int ssi_auto_connect_slave(Object *child, void *opaque) -{ - SSIAutoConnectArg *arg = opaque; - SSISlave *dev = (SSISlave *)object_dynamic_cast(child, TYPE_SSI_SLAVE); - qemu_irq cs_line; - - if (!dev) { - return 0; - } - - cs_line = qdev_get_gpio_in_named(DEVICE(dev), SSI_GPIO_CS, 0); - qdev_set_parent_bus(DEVICE(dev), BUS(arg->bus)); - **arg->cs_linep = cs_line; - (*arg->cs_linep)++; - return 0; -} - -void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_line, - SSIBus *bus) -{ - SSIAutoConnectArg arg = { - .cs_linep = &cs_line, - .bus = bus - }; - - object_child_foreach(OBJECT(parent), ssi_auto_connect_slave, &arg); -} diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c index eba7ccd46a..80d1488dc7 100644 --- a/hw/ssi/xilinx_spi.c +++ b/hw/ssi/xilinx_spi.c @@ -334,7 +334,6 @@ static void xilinx_spi_realize(DeviceState *dev, Error **errp) sysbus_init_irq(sbd, &s->irq); s->cs_lines = g_new0(qemu_irq, s->num_cs); - ssi_auto_connect_slaves(dev, s->cs_lines, s->spi); for (i = 0; i < s->num_cs; ++i) { sysbus_init_irq(sbd, &s->cs_lines[i]); } diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index e76cf290c8..b9371dbf8d 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -1270,7 +1270,6 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp) XilinxSPIPS *s = XILINX_SPIPS(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); XilinxSPIPSClass *xsc = XILINX_SPIPS_GET_CLASS(s); - qemu_irq *cs; int i; DB_PRINT_L(0, "realized spips\n"); @@ -1297,9 +1296,6 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp) s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses); s->cs_lines_state = g_new0(bool, s->num_cs * s->num_busses); - for (i = 0, cs = s->cs_lines; i < s->num_busses; ++i, cs += s->num_cs) { - ssi_auto_connect_slaves(DEVICE(s), cs, s->spi[i]); - } sysbus_init_irq(sbd, &s->irq); for (i = 0; i < s->num_cs * s->num_busses; ++i) { diff --git a/include/hw/ssi/ssi.h b/include/hw/ssi/ssi.h index 1107cb89ee..1725b13c32 100644 --- a/include/hw/ssi/ssi.h +++ b/include/hw/ssi/ssi.h @@ -86,10 +86,6 @@ SSIBus *ssi_create_bus(DeviceState *parent, const char *name); uint32_t ssi_transfer(SSIBus *bus, uint32_t val); -/* Automatically connect all children nodes a spi controller as slaves */ -void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_lines, - SSIBus *bus); - /* max111x.c */ void max111x_set_input(DeviceState *dev, int line, uint8_t value); From 57d479c9c6c69cd856f77360e116f25e73e40566 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:12 +0200 Subject: [PATCH 1248/2595] ssi: Convert uses of ssi_create_slave_no_init() with Coccinelle Replace dev = ssi_create_slave_no_init(bus, type_name); ... qdev_init_nofail(dev); by dev = qdev_new(type_name); ... qdev_realize_and_unref(dev, bus, &error_fatal); Recent commit "qdev: New qdev_new(), qdev_realize(), etc." explains why. @@ type SSIBus; identifier bus; expression dev, qbus, expr; expression list args; @@ - bus = (SSIBus *)qbus; + bus = qbus; // TODO fix up decl ... - dev = ssi_create_slave_no_init(bus, args); + dev = qdev_new(args); ... when != dev = expr - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, bus, &error_fatal); @@ expression dev, bus, expr; expression list args; @@ - dev = ssi_create_slave_no_init(bus, args); + dev = qdev_new(args); ... when != dev = expr - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, BUS(bus), &error_fatal); Bus declarations fixed up manually. Cc: Alistair Francis Signed-off-by: Markus Armbruster Reviewed-by: Alistair Francis Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-24-armbru@redhat.com> --- hw/arm/aspeed.c | 4 ++-- hw/arm/msf2-som.c | 8 ++++---- hw/arm/sabrelite.c | 4 ++-- hw/arm/xilinx_zynq.c | 4 ++-- hw/arm/xlnx-zcu102.c | 16 ++++++++-------- hw/microblaze/petalogix_ml605_mmu.c | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index b08903df33..2b96244cf5 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -225,12 +225,12 @@ static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, DriveInfo *dinfo = drive_get_next(IF_MTD); qemu_irq cs_line; - fl->flash = ssi_create_slave_no_init(s->spi, flashtype); + fl->flash = qdev_new(flashtype); if (dinfo) { qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo), errp); } - qdev_init_nofail(fl->flash); + qdev_realize_and_unref(fl->flash, BUS(s->spi), &error_fatal); cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0); sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line); diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c index e398703742..ca9cbe1acb 100644 --- a/hw/arm/msf2-som.c +++ b/hw/arm/msf2-som.c @@ -47,7 +47,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine) MachineClass *mc = MACHINE_GET_CLASS(machine); DriveInfo *dinfo = drive_get_next(IF_MTD); qemu_irq cs_line; - SSIBus *spi_bus; + BusState *spi_bus; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ddr = g_new(MemoryRegion, 1); @@ -82,14 +82,14 @@ static void emcraft_sf2_s2s010_init(MachineState *machine) soc = MSF2_SOC(dev); /* Attach SPI flash to SPI0 controller */ - spi_bus = (SSIBus *)qdev_get_child_bus(dev, "spi0"); - spi_flash = ssi_create_slave_no_init(spi_bus, "s25sl12801"); + spi_bus = qdev_get_child_bus(dev, "spi0"); + spi_flash = qdev_new("s25sl12801"); qdev_prop_set_uint8(spi_flash, "spansion-cr2nv", 1); if (dinfo) { qdev_prop_set_drive(spi_flash, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } - qdev_init_nofail(spi_flash); + qdev_realize_and_unref(spi_flash, spi_bus, &error_fatal); cs_line = qdev_get_gpio_in_named(spi_flash, SSI_GPIO_CS, 0); sysbus_connect_irq(SYS_BUS_DEVICE(&soc->spi[0]), 1, cs_line); diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index 96cb30aa3c..33d731549d 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -75,13 +75,13 @@ static void sabrelite_init(MachineState *machine) qemu_irq cs_line; DriveInfo *dinfo = drive_get_next(IF_MTD); - flash_dev = ssi_create_slave_no_init(spi_bus, "sst25vf016b"); + flash_dev = qdev_new("sst25vf016b"); if (dinfo) { qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } - qdev_init_nofail(flash_dev); + qdev_realize_and_unref(flash_dev, BUS(spi_bus), &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 5fbd2b2e31..0e0f0976c4 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -157,12 +157,12 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, for (j = 0; j < num_ss; ++j) { DriveInfo *dinfo = drive_get_next(IF_MTD); - flash_dev = ssi_create_slave_no_init(spi, "n25q128"); + flash_dev = qdev_new("n25q128"); if (dinfo) { qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } - qdev_init_nofail(flash_dev); + qdev_realize_and_unref(flash_dev, BUS(spi), &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line); diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 4229b2d936..77c84b82ab 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -149,21 +149,21 @@ static void xlnx_zcu102_init(MachineState *machine) } for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { - SSIBus *spi_bus; + BusState *spi_bus; DeviceState *flash_dev; qemu_irq cs_line; DriveInfo *dinfo = drive_get_next(IF_MTD); gchar *bus_name = g_strdup_printf("spi%d", i); - spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name); + spi_bus = qdev_get_child_bus(DEVICE(&s->soc), bus_name); g_free(bus_name); - flash_dev = ssi_create_slave_no_init(spi_bus, "sst25wf080"); + flash_dev = qdev_new("sst25wf080"); if (dinfo) { qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } - qdev_init_nofail(flash_dev); + qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); @@ -171,22 +171,22 @@ static void xlnx_zcu102_init(MachineState *machine) } for (i = 0; i < XLNX_ZYNQMP_NUM_QSPI_FLASH; i++) { - SSIBus *spi_bus; + BusState *spi_bus; DeviceState *flash_dev; qemu_irq cs_line; DriveInfo *dinfo = drive_get_next(IF_MTD); int bus = i / XLNX_ZYNQMP_NUM_QSPI_BUS_CS; gchar *bus_name = g_strdup_printf("qspi%d", bus); - spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name); + spi_bus = qdev_get_child_bus(DEVICE(&s->soc), bus_name); g_free(bus_name); - flash_dev = ssi_create_slave_no_init(spi_bus, "n25q512a11"); + flash_dev = qdev_new("n25q512a11"); if (dinfo) { qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } - qdev_init_nofail(flash_dev); + qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index 2e7a3fa119..d4bfa233c9 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -186,12 +186,12 @@ petalogix_ml605_init(MachineState *machine) DriveInfo *dinfo = drive_get_next(IF_MTD); qemu_irq cs_line; - dev = ssi_create_slave_no_init(spi, "n25q128"); + dev = qdev_new("n25q128"); if (dinfo) { qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, BUS(spi), &error_fatal); cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); sysbus_connect_irq(busdev, i+1, cs_line); From 7e272a0001ab7a9f3d2e14e1829bc6f522440eca Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:13 +0200 Subject: [PATCH 1249/2595] ssi: Convert last use of ssi_create_slave_no_init() manually Same transformation as in the previous commit. Manual, because convincing Coccinelle to transform this case is not worthwhile. Cc: Alistair Francis Signed-off-by: Markus Armbruster Acked-by: Alistair Francis Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-25-armbru@redhat.com> --- hw/ssi/ssi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 54106f5ef8..58e7d904db 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -16,6 +16,7 @@ #include "hw/ssi/ssi.h" #include "migration/vmstate.h" #include "qemu/module.h" +#include "qapi/error.h" struct SSIBus { BusState parent_obj; @@ -96,9 +97,9 @@ DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name) DeviceState *ssi_create_slave(SSIBus *bus, const char *name) { - DeviceState *dev = ssi_create_slave_no_init(bus, name); + DeviceState *dev = qdev_new(name); - qdev_init_nofail(dev); + qdev_realize_and_unref(dev, &bus->parent_obj, &error_fatal); return dev; } From 7ce8d8c8d5b4d7492bd493d6f12b68e23c1d864d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:14 +0200 Subject: [PATCH 1250/2595] ssi: ssi_create_slave_no_init() is now unused, drop Cc: Alistair Francis Signed-off-by: Markus Armbruster Reviewed-by: Alistair Francis Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-26-armbru@redhat.com> --- hw/ssi/ssi.c | 5 ----- include/hw/ssi/ssi.h | 1 - 2 files changed, 6 deletions(-) diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 58e7d904db..67b48c31cd 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -90,11 +90,6 @@ static const TypeInfo ssi_slave_info = { .abstract = true, }; -DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name) -{ - return qdev_create(BUS(bus), name); -} - DeviceState *ssi_create_slave(SSIBus *bus, const char *name) { DeviceState *dev = qdev_new(name); diff --git a/include/hw/ssi/ssi.h b/include/hw/ssi/ssi.h index 1725b13c32..93f2b8b0be 100644 --- a/include/hw/ssi/ssi.h +++ b/include/hw/ssi/ssi.h @@ -79,7 +79,6 @@ extern const VMStateDescription vmstate_ssi_slave; } DeviceState *ssi_create_slave(SSIBus *bus, const char *name); -DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name); /* Master interface. */ SSIBus *ssi_create_bus(DeviceState *parent, const char *name); From 32aaaebe5665a75f8be8d76ba3ecfcf87627858b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:15 +0200 Subject: [PATCH 1251/2595] usb: New usb_new(), usb_realize_and_unref() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm converting from qdev_create()/qdev_init_nofail() to qdev_new()/qdev_realize_and_unref(); recent commit "qdev: New qdev_new(), qdev_realize(), etc." explains why. USB devices use qdev_create() through usb_create(). Provide usb_new() and usb_realize_and_unref() for converting USB devices. Cc: Gerd Hoffmann Signed-off-by: Markus Armbruster Reviewed-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-27-armbru@redhat.com> --- hw/usb/bus.c | 10 ++++++++++ include/hw/usb.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/hw/usb/bus.c b/hw/usb/bus.c index d28eff1b5c..6b0d9f9e4d 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -314,6 +314,16 @@ void usb_legacy_register(const char *typename, const char *usbdevice_name, } } +USBDevice *usb_new(const char *name) +{ + return USB_DEVICE(qdev_new(name)); +} + +bool usb_realize_and_unref(USBDevice *dev, USBBus *bus, Error **errp) +{ + return qdev_realize_and_unref(&dev->qdev, &bus->qbus, errp); +} + USBDevice *usb_create(USBBus *bus, const char *name) { DeviceState *dev; diff --git a/include/hw/usb.h b/include/hw/usb.h index e2128c7c45..1cc0ba0fed 100644 --- a/include/hw/usb.h +++ b/include/hw/usb.h @@ -504,6 +504,8 @@ USBBus *usb_bus_find(int busnr); void usb_legacy_register(const char *typename, const char *usbdevice_name, USBDevice *(*usbdevice_init)(USBBus *bus, const char *params)); +USBDevice *usb_new(const char *name); +bool usb_realize_and_unref(USBDevice *dev, USBBus *bus, Error **errp); USBDevice *usb_create(USBBus *bus, const char *name); USBDevice *usb_create_simple(USBBus *bus, const char *name); USBDevice *usbdevice_create(const char *cmdline); From 590ce74a08d5b4fb39ac165a4fb68bd07e6d2b6c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:16 +0200 Subject: [PATCH 1252/2595] usb: Convert uses of usb_create() Replace dev = usb_create(bus, type_name); ... object_property_set_bool(OBJECT(dev), true, "realized", &err); by dev = isa_new(type_name); ... usb_realize_and_unref(dev, bus, &err); Recent commit "qdev: New qdev_new(), qdev_realize(), etc." explains why. Cc: Gerd Hoffmann Signed-off-by: Markus Armbruster Reviewed-by: Gerd Hoffmann Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-28-armbru@redhat.com> --- hw/usb/bus.c | 11 +++++------ hw/usb/dev-serial.c | 4 ++-- include/hw/usb.h | 3 +-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 6b0d9f9e4d..da85b8b005 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -296,14 +296,13 @@ typedef struct LegacyUSBFactory { const char *name; const char *usbdevice_name; - USBDevice *(*usbdevice_init)(USBBus *bus, const char *params); + USBDevice *(*usbdevice_init)(const char *params); } LegacyUSBFactory; static GSList *legacy_usb_factory; void usb_legacy_register(const char *typename, const char *usbdevice_name, - USBDevice *(*usbdevice_init)(USBBus *bus, - const char *params)) + USBDevice *(*usbdevice_init)(const char *params)) { if (usbdevice_name) { LegacyUSBFactory *f = g_malloc0(sizeof(*f)); @@ -710,19 +709,19 @@ USBDevice *usbdevice_create(const char *cmdline) } if (f->usbdevice_init) { - dev = f->usbdevice_init(bus, params); + dev = f->usbdevice_init(params); } else { if (*params) { error_report("usbdevice %s accepts no params", driver); return NULL; } - dev = usb_create(bus, f->name); + dev = usb_new(f->name); } if (!dev) { error_report("Failed to create USB device '%s'", f->name); return NULL; } - object_property_set_bool(OBJECT(dev), true, "realized", &err); + usb_realize_and_unref(dev, bus, &err); if (err) { error_reportf_err(err, "Failed to initialize USB device '%s': ", f->name); diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index d2c03681b7..7e50e3ba47 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -542,7 +542,7 @@ static void usb_serial_realize(USBDevice *dev, Error **errp) s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); } -static USBDevice *usb_braille_init(USBBus *bus, const char *unused) +static USBDevice *usb_braille_init(const char *unused) { USBDevice *dev; Chardev *cdrv; @@ -551,7 +551,7 @@ static USBDevice *usb_braille_init(USBBus *bus, const char *unused) if (!cdrv) return NULL; - dev = usb_create(bus, "usb-braille"); + dev = usb_new("usb-braille"); qdev_prop_set_chr(&dev->qdev, "chardev", cdrv); return dev; } diff --git a/include/hw/usb.h b/include/hw/usb.h index 1cc0ba0fed..dce16c792b 100644 --- a/include/hw/usb.h +++ b/include/hw/usb.h @@ -502,8 +502,7 @@ void usb_bus_new(USBBus *bus, size_t bus_size, void usb_bus_release(USBBus *bus); USBBus *usb_bus_find(int busnr); void usb_legacy_register(const char *typename, const char *usbdevice_name, - USBDevice *(*usbdevice_init)(USBBus *bus, - const char *params)); + USBDevice *(*usbdevice_init)(const char *params)); USBDevice *usb_new(const char *name); bool usb_realize_and_unref(USBDevice *dev, USBBus *bus, Error **errp); USBDevice *usb_create(USBBus *bus, const char *name); From 8cd81a9e551265dc63fe80aa83af773709e48552 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:17 +0200 Subject: [PATCH 1253/2595] usb: usb_create() is now unused, drop Cc: Gerd Hoffmann Signed-off-by: Markus Armbruster Reviewed-by: Gerd Hoffmann Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-29-armbru@redhat.com> --- hw/usb/bus.c | 8 -------- include/hw/usb.h | 1 - 2 files changed, 9 deletions(-) diff --git a/hw/usb/bus.c b/hw/usb/bus.c index da85b8b005..5c4d31614e 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -323,14 +323,6 @@ bool usb_realize_and_unref(USBDevice *dev, USBBus *bus, Error **errp) return qdev_realize_and_unref(&dev->qdev, &bus->qbus, errp); } -USBDevice *usb_create(USBBus *bus, const char *name) -{ - DeviceState *dev; - - dev = qdev_create(&bus->qbus, name); - return USB_DEVICE(dev); -} - static USBDevice *usb_try_create_simple(USBBus *bus, const char *name, Error **errp) { diff --git a/include/hw/usb.h b/include/hw/usb.h index dce16c792b..e29a37635b 100644 --- a/include/hw/usb.h +++ b/include/hw/usb.h @@ -505,7 +505,6 @@ void usb_legacy_register(const char *typename, const char *usbdevice_name, USBDevice *(*usbdevice_init)(const char *params)); USBDevice *usb_new(const char *name); bool usb_realize_and_unref(USBDevice *dev, USBBus *bus, Error **errp); -USBDevice *usb_create(USBBus *bus, const char *name); USBDevice *usb_create_simple(USBBus *bus, const char *name); USBDevice *usbdevice_create(const char *cmdline); void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, From 535770518f85e6e8b912c262492a251053491637 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:18 +0200 Subject: [PATCH 1254/2595] usb: Eliminate usb_try_create_simple() usb_try_create_simple() is qdev_try_new() and qdev_realize_and_unref() with more verbose error messages. Of its two users, one ignores errors, and the other asserts they are impossible. Make them use qdev_try_new() and qdev_realize_and_unref() directly, and eliminate usb_try_create_simple Cc: Gerd Hoffmann Signed-off-by: Markus Armbruster Reviewed-by: Gerd Hoffmann Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-30-armbru@redhat.com> --- hw/usb/bus.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 5c4d31614e..a81aee2051 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -318,35 +318,22 @@ USBDevice *usb_new(const char *name) return USB_DEVICE(qdev_new(name)); } +static USBDevice *usb_try_new(const char *name) +{ + return USB_DEVICE(qdev_try_new(name)); +} + bool usb_realize_and_unref(USBDevice *dev, USBBus *bus, Error **errp) { return qdev_realize_and_unref(&dev->qdev, &bus->qbus, errp); } -static USBDevice *usb_try_create_simple(USBBus *bus, const char *name, - Error **errp) -{ - Error *err = NULL; - DeviceState *dev; - - dev = qdev_try_new(name); - if (!dev) { - error_setg(errp, "Failed to create USB device '%s'", name); - return NULL; - } - qdev_realize_and_unref(dev, &bus->qbus, &err); - if (err) { - error_propagate_prepend(errp, err, - "Failed to initialize USB device '%s': ", - name); - return NULL; - } - return USB_DEVICE(dev); -} - USBDevice *usb_create_simple(USBBus *bus, const char *name) { - return usb_try_create_simple(bus, name, &error_abort); + USBDevice *dev = usb_new(name); + + usb_realize_and_unref(dev, bus, &error_abort); + return dev; } static void usb_fill_port(USBPort *port, void *opaque, int index, @@ -426,6 +413,7 @@ void usb_claim_port(USBDevice *dev, Error **errp) { USBBus *bus = usb_bus_from_device(dev); USBPort *port; + USBDevice *hub; assert(dev->port == NULL); @@ -443,7 +431,10 @@ void usb_claim_port(USBDevice *dev, Error **errp) } else { if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) { /* Create a new hub and chain it on */ - usb_try_create_simple(bus, "usb-hub", NULL); + hub = usb_try_new("usb-hub"); + if (hub) { + usb_realize_and_unref(hub, bus, NULL); + } } if (bus->nfree == 0) { error_setg(errp, "tried to attach usb device %s to a bus " From 2194abd6231b36704b77adfdec2a32d38b7dc848 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:19 +0200 Subject: [PATCH 1255/2595] qdev: qdev_create(), qdev_try_create() are now unused, drop Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-31-armbru@redhat.com> --- hw/core/qdev.c | 48 ------------------------------------------ hw/core/sysbus.c | 1 - include/hw/qdev-core.h | 2 -- migration/migration.c | 2 +- 4 files changed, 1 insertion(+), 52 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 4768244f31..a1fdebb3aa 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -128,54 +128,6 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus) } } -/* Create a new device. This only initializes the device state - structure and allows properties to be set. The device still needs - to be realized. See qdev-core.h. */ -DeviceState *qdev_create(BusState *bus, const char *name) -{ - DeviceState *dev; - - dev = qdev_try_create(bus, name); - if (!dev) { - if (bus) { - error_report("Unknown device '%s' for bus '%s'", name, - object_get_typename(OBJECT(bus))); - } else { - error_report("Unknown device '%s' for default sysbus", name); - } - abort(); - } - - return dev; -} - -DeviceState *qdev_try_create(BusState *bus, const char *type) -{ - DeviceState *dev; - - if (object_class_by_name(type) == NULL) { - return NULL; - } - dev = DEVICE(object_new(type)); - if (!dev) { - return NULL; - } - - if (!bus) { - /* Assert that the device really is a SysBusDevice before - * we put it onto the sysbus. Non-sysbus devices which aren't - * being put onto a bus should be created with object_new(TYPE_FOO), - * not qdev_create(NULL, TYPE_FOO). - */ - g_assert(object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)); - bus = sysbus_get_default(); - } - - qdev_set_parent_bus(dev, bus); - object_unref(OBJECT(dev)); - return dev; -} - /* * Create a device on the heap. * A type @name must exist. diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index b5db0d179f..7ff1b5f2de 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -325,7 +325,6 @@ static const TypeInfo sysbus_device_type_info = { .class_init = sysbus_device_class_init, }; -/* This is a nasty hack to allow passing a NULL bus to qdev_create. */ static BusState *main_system_bus; static void main_system_bus_create(void) diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index be6f7c4736..ef6137b6a8 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -320,8 +320,6 @@ compat_props_add(GPtrArray *arr, /*** Board API. This should go away once we have a machine config file. ***/ -DeviceState *qdev_create(BusState *bus, const char *name); -DeviceState *qdev_try_create(BusState *bus, const char *name); DeviceState *qdev_new(const char *name); DeviceState *qdev_try_new(const char *name); void qdev_init_nofail(DeviceState *dev); diff --git a/migration/migration.c b/migration/migration.c index b63ad91d34..481a590f72 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3778,7 +3778,7 @@ static const TypeInfo migration_type = { .name = TYPE_MIGRATION, /* * NOTE: TYPE_MIGRATION is not really a device, as the object is - * not created using qdev_create(), it is not attached to the qdev + * not created using qdev_new(), it is not attached to the qdev * device tree, and it is never realized. * * TODO: Make this TYPE_OBJECT once QOM provides something like From dbe4070e59ab86f4a25de9cd12ed56f9eb68049b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:20 +0200 Subject: [PATCH 1256/2595] auxbus: Rename aux_init_bus() to aux_bus_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-32-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/display/xlnx_dp.c | 2 +- hw/misc/auxbus.c | 4 ++-- include/hw/misc/auxbus.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 6e9793584a..31d0c5a101 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1244,7 +1244,7 @@ static void xlnx_dp_init(Object *obj) /* * Initialize AUX Bus. */ - s->aux_bus = aux_init_bus(DEVICE(obj), "aux"); + s->aux_bus = aux_bus_init(DEVICE(obj), "aux"); /* * Initialize DPCD and EDID.. diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index c37d235b0e..e93a35dd0a 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -62,7 +62,7 @@ static void aux_bus_class_init(ObjectClass *klass, void *data) k->print_dev = aux_slave_dev_print; } -AUXBus *aux_init_bus(DeviceState *parent, const char *name) +AUXBus *aux_bus_init(DeviceState *parent, const char *name) { AUXBus *bus; Object *auxtoi2c; @@ -225,7 +225,7 @@ static void aux_bridge_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); /* This device is private and is created only once for each - * aux-bus in aux_init_bus(..). So don't allow the user to add one. + * aux-bus in aux_bus_init(..). So don't allow the user to add one. */ dc->user_creatable = false; } diff --git a/include/hw/misc/auxbus.h b/include/hw/misc/auxbus.h index a539a98c4b..5cfd7a9284 100644 --- a/include/hw/misc/auxbus.h +++ b/include/hw/misc/auxbus.h @@ -84,14 +84,14 @@ struct AUXSlave { }; /** - * aux_init_bus: Initialize an AUX bus. + * aux_bus_init: Initialize an AUX bus. * * Returns the new AUX bus created. * * @parent The device where this bus is located. * @name The name of the bus. */ -AUXBus *aux_init_bus(DeviceState *parent, const char *name); +AUXBus *aux_bus_init(DeviceState *parent, const char *name); /* * aux_request: Make a request on the bus. From b7a1b5483ee0179f0e5d31cf43678fa225227614 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:21 +0200 Subject: [PATCH 1257/2595] auxbus: New aux_bus_realize(), pairing with aux_bus_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aux_bus_init() encapsulates the creation of an aux-bus and its aux-to-i2c-bridge device. Create aux_bus_realize() to similarly encapsulate their realization. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-33-armbru@redhat.com> --- hw/display/xlnx_dp.c | 2 +- hw/misc/auxbus.c | 5 +++++ include/hw/misc/auxbus.h | 7 +++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 31d0c5a101..a714cf8a50 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1266,7 +1266,7 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp) DisplaySurface *surface; struct audsettings as; - qdev_init_nofail(DEVICE(s->aux_bus->bridge)); + aux_bus_realize(s->aux_bus); qdev_init_nofail(DEVICE(s->dpcd)); aux_map_slave(AUX_SLAVE(s->dpcd), 0x0000); diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index e93a35dd0a..75b6de1c63 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -81,6 +81,11 @@ AUXBus *aux_bus_init(DeviceState *parent, const char *name) return bus; } +void aux_bus_realize(AUXBus *bus) +{ + qdev_init_nofail(DEVICE(bus->bridge)); +} + void aux_map_slave(AUXSlave *aux_dev, hwaddr addr) { DeviceState *dev = DEVICE(aux_dev); diff --git a/include/hw/misc/auxbus.h b/include/hw/misc/auxbus.h index 5cfd7a9284..0d849d9d89 100644 --- a/include/hw/misc/auxbus.h +++ b/include/hw/misc/auxbus.h @@ -93,6 +93,13 @@ struct AUXSlave { */ AUXBus *aux_bus_init(DeviceState *parent, const char *name); +/** + * aux_bus_realize: Realize an AUX bus. + * + * @bus: The AUX bus. + */ +void aux_bus_realize(AUXBus *bus); + /* * aux_request: Make a request on the bus. * From 2214985408041b54e7f25ce76cd8e6d9e68c4be1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:22 +0200 Subject: [PATCH 1258/2595] auxbus: Convert a use of qdev_set_parent_bus() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert qdev_set_parent_bus()/qdev_init_nofail() to qdev_realize(); recent commit "qdev: New qdev_new(), qdev_realize(), etc." explains why. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-34-armbru@redhat.com> --- hw/display/xlnx_dp.c | 2 +- hw/misc/auxbus.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index a714cf8a50..884d29c8ce 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1268,7 +1268,7 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp) aux_bus_realize(s->aux_bus); - qdev_init_nofail(DEVICE(s->dpcd)); + qdev_realize(DEVICE(s->dpcd), BUS(s->aux_bus), &error_fatal); aux_map_slave(AUX_SLAVE(s->dpcd), 0x0000); qdev_realize_and_unref(DEVICE(s->edid), BUS(aux_get_i2c_bus(s->aux_bus)), diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index 75b6de1c63..5c9c23a336 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -70,7 +70,6 @@ AUXBus *aux_bus_init(DeviceState *parent, const char *name) bus = AUX_BUS(qbus_create(TYPE_AUX_BUS, parent, name)); auxtoi2c = object_new_with_props(TYPE_AUXTOI2C, OBJECT(bus), "i2c", &error_abort, NULL); - qdev_set_parent_bus(DEVICE(auxtoi2c), BUS(bus)); bus->bridge = AUXTOI2C(auxtoi2c); @@ -83,7 +82,7 @@ AUXBus *aux_bus_init(DeviceState *parent, const char *name) void aux_bus_realize(AUXBus *bus) { - qdev_init_nofail(DEVICE(bus->bridge)); + qdev_realize(DEVICE(bus->bridge), BUS(bus), &error_fatal); } void aux_map_slave(AUXSlave *aux_dev, hwaddr addr) @@ -280,7 +279,6 @@ DeviceState *aux_create_slave(AUXBus *bus, const char *type) dev = qdev_new(type); assert(dev); - qdev_set_parent_bus(dev, &bus->qbus); return dev; } From cd9ae806cdad8f1992e0ac9198c114c636693764 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:23 +0200 Subject: [PATCH 1259/2595] auxbus: Eliminate aux_create_slave() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aux_create_slave() has become a trivial wrapper around qdev_new(). There's just one user. Eliminate. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-35-armbru@redhat.com> --- hw/display/xlnx_dp.c | 2 +- hw/misc/auxbus.c | 9 --------- include/hw/misc/auxbus.h | 7 ------- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 884d29c8ce..c56e6ec593 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1249,7 +1249,7 @@ static void xlnx_dp_init(Object *obj) /* * Initialize DPCD and EDID.. */ - s->dpcd = DPCD(aux_create_slave(s->aux_bus, "dpcd")); + s->dpcd = DPCD(qdev_new("dpcd")); object_property_add_child(OBJECT(s), "dpcd", OBJECT(s->dpcd)); s->edid = I2CDDC(qdev_new("i2c-ddc")); diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index 5c9c23a336..da361baa32 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -273,15 +273,6 @@ static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent) memory_region_size(s->mmio)); } -DeviceState *aux_create_slave(AUXBus *bus, const char *type) -{ - DeviceState *dev; - - dev = qdev_new(type); - assert(dev); - return dev; -} - void aux_init_mmio(AUXSlave *aux_slave, MemoryRegion *mmio) { assert(!aux_slave->mmio); diff --git a/include/hw/misc/auxbus.h b/include/hw/misc/auxbus.h index 0d849d9d89..15a8973517 100644 --- a/include/hw/misc/auxbus.h +++ b/include/hw/misc/auxbus.h @@ -131,13 +131,6 @@ I2CBus *aux_get_i2c_bus(AUXBus *bus); */ void aux_init_mmio(AUXSlave *aux_slave, MemoryRegion *mmio); -/* aux_create_slave: Create a new device on an AUX bus - * - * @bus The AUX bus for the new device. - * @name The type of the device to be created. - */ -DeviceState *aux_create_slave(AUXBus *bus, const char *name); - /* aux_map_slave: Map the mmio for an AUX slave on the bus. * * @dev The AUX slave. From 19dc7e977c145cf3683dc5d18d54ef3629e34619 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:24 +0200 Subject: [PATCH 1260/2595] qom: Tidy up a few object_initialize_child() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The callers of object_initialize_child() commonly pass either &child, sizeof(child), or pchild, sizeof(*pchild). Tidy up the few that don't, mostly to keep the next commit simpler. Signed-off-by: Markus Armbruster Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-36-armbru@redhat.com> --- hw/arm/aspeed.c | 2 +- hw/microblaze/xlnx-zynqmp-pmu.c | 3 +-- hw/pci-host/pnv_phb4.c | 2 +- hw/riscv/riscv_hart.c | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 2b96244cf5..ee50476ccb 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -268,7 +268,7 @@ static void aspeed_machine_init(MachineState *machine) memory_region_add_subregion(&bmc->ram_container, 0, machine->ram); object_initialize_child(OBJECT(machine), "soc", &bmc->soc, - (sizeof(bmc->soc)), amc->soc_name, &error_abort, + sizeof(bmc->soc), amc->soc_name, &error_abort, NULL); sc = ASPEED_SOC_GET_CLASS(&bmc->soc); diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index 028f31894d..aa90b9d1be 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -174,8 +174,7 @@ static void xlnx_zynqmp_pmu_init(MachineState *machine) pmu_ram); /* Create the PMU device */ - object_initialize_child(OBJECT(machine), "pmu", pmu, - sizeof(XlnxZynqMPPMUSoCState), + object_initialize_child(OBJECT(machine), "pmu", pmu, sizeof(*pmu), TYPE_XLNX_ZYNQMP_PMU_SOC, &error_abort, NULL); object_property_set_bool(OBJECT(pmu), true, "realized", &error_fatal); diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index e30ae9ad5b..aba710fd1f 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1155,7 +1155,7 @@ static void pnv_phb4_instance_init(Object *obj) QLIST_INIT(&phb->dma_spaces); /* XIVE interrupt source object */ - object_initialize_child(obj, "source", &phb->xsrc, sizeof(XiveSource), + object_initialize_child(obj, "source", &phb->xsrc, sizeof(phb->xsrc), TYPE_XIVE_SOURCE, &error_abort, NULL); /* Root Port */ diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c index 276a9baca0..61e88e2e37 100644 --- a/hw/riscv/riscv_hart.c +++ b/hw/riscv/riscv_hart.c @@ -46,7 +46,7 @@ static void riscv_hart_realize(RISCVHartArrayState *s, int idx, Error *err = NULL; object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], - sizeof(RISCVCPU), cpu_type, + sizeof(s->harts[idx]), cpu_type, &error_abort, NULL); s->harts[idx].env.mhartid = s->hartid_base + idx; qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]); From 9fc7fc4d3909817555ce0af6bcb69dff1606140d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:25 +0200 Subject: [PATCH 1261/2595] qom: Less verbose object_initialize_child() All users of object_initialize_child() pass the obvious child size argument. Almost all pass &error_abort and no properties. Tiresome. Rename object_initialize_child() to object_initialize_child_with_props() to free the name. New convenience wrapper object_initialize_child() automates the size argument, and passes &error_abort and no properties. Rename object_initialize_childv() to object_initialize_child_with_propsv() for consistency. Convert callers with this Coccinelle script: @@ expression parent, propname, type; expression child, size; symbol error_abort; @@ - object_initialize_child(parent, propname, OBJECT(child), size, type, &error_abort, NULL) + object_initialize_child(parent, propname, child, size, type, &error_abort, NULL) @@ expression parent, propname, type; expression child; symbol error_abort; @@ - object_initialize_child(parent, propname, child, sizeof(*child), type, &error_abort, NULL) + object_initialize_child(parent, propname, child, type) @@ expression parent, propname, type; expression child; symbol error_abort; @@ - object_initialize_child(parent, propname, &child, sizeof(child), type, &error_abort, NULL) + object_initialize_child(parent, propname, &child, type) @@ expression parent, propname, type; expression child, size, err; expression list props; @@ - object_initialize_child(parent, propname, child, size, type, err, props) + object_initialize_child_with_props(parent, propname, child, size, type, err, props) Note that Coccinelle chokes on ARMSSE typedef vs. macro in hw/arm/armsse.c. Worked around by temporarily renaming the macro for the spatch run. Signed-off-by: Markus Armbruster Acked-by: Alistair Francis [Rebased: machine opentitan is new (commit fe0fe4735e7)] Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-37-armbru@redhat.com> --- hw/arm/allwinner-a10.c | 5 ++-- hw/arm/allwinner-h3.c | 5 ++-- hw/arm/armsse.c | 26 +++++++------------- hw/arm/aspeed.c | 4 +--- hw/arm/aspeed_ast2600.c | 4 +--- hw/arm/aspeed_soc.c | 4 +--- hw/arm/bcm2836.c | 3 +-- hw/arm/digic.c | 4 +--- hw/arm/exynos4210.c | 3 +-- hw/arm/fsl-imx25.c | 4 +--- hw/arm/fsl-imx31.c | 4 +--- hw/arm/fsl-imx6.c | 5 ++-- hw/arm/fsl-imx6ul.c | 4 ++-- hw/arm/fsl-imx7.c | 5 ++-- hw/arm/imx25_pdk.c | 3 +-- hw/arm/kzm.c | 3 +-- hw/arm/mps2-tz.c | 14 +++++------ hw/arm/musca.c | 14 +++++------ hw/arm/raspi.c | 4 ++-- hw/arm/stm32f405_soc.c | 6 ++--- hw/arm/xlnx-versal.c | 5 ++-- hw/arm/xlnx-zcu102.c | 3 +-- hw/arm/xlnx-zynqmp.c | 16 +++++-------- hw/char/serial-isa.c | 3 +-- hw/char/serial-pci-multi.c | 4 +--- hw/char/serial-pci.c | 3 +-- hw/char/serial.c | 6 ++--- hw/core/sysbus.c | 4 ++-- hw/dma/xilinx_axidma.c | 9 +++---- hw/intc/pnv_xive.c | 6 ++--- hw/intc/spapr_xive.c | 6 ++--- hw/microblaze/xlnx-zynqmp-pmu.c | 7 +++--- hw/misc/macio/macio.c | 10 ++++---- hw/net/xilinx_axienet.c | 9 +++---- hw/pci-host/designware.c | 3 +-- hw/pci-host/gpex.c | 3 +-- hw/pci-host/pnv_phb3.c | 12 ++++------ hw/pci-host/pnv_phb4.c | 6 ++--- hw/pci-host/pnv_phb4_pec.c | 6 ++--- hw/pci-host/q35.c | 3 +-- hw/pci-host/xilinx-pcie.c | 3 +-- hw/ppc/pnv.c | 42 ++++++++++++--------------------- hw/ppc/pnv_psi.c | 6 ++--- hw/ppc/spapr.c | 6 ++--- hw/riscv/opentitan.c | 3 +-- hw/riscv/riscv_hart.c | 4 +--- hw/riscv/sifive_e.c | 4 +--- hw/riscv/sifive_u.c | 12 +++------- hw/virtio/virtio.c | 5 ++-- include/qom/object.h | 30 +++++++++++++++++++---- qom/object.c | 19 +++++++++++---- 51 files changed, 161 insertions(+), 221 deletions(-) diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 6e1329a4a2..49c51463e1 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -41,9 +41,8 @@ static void aw_a10_init(Object *obj) { AwA10State *s = AW_A10(obj); - object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu), - ARM_CPU_TYPE_NAME("cortex-a8"), - &error_abort, NULL); + object_initialize_child(obj, "cpu", &s->cpu, + ARM_CPU_TYPE_NAME("cortex-a8")); sysbus_init_child_obj(obj, "intc", &s->intc, sizeof(s->intc), TYPE_AW_A10_PIC); diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c index f10674da5a..7dc3671155 100644 --- a/hw/arm/allwinner-h3.c +++ b/hw/arm/allwinner-h3.c @@ -194,9 +194,8 @@ static void allwinner_h3_init(Object *obj) s->memmap = allwinner_h3_memmap; for (int i = 0; i < AW_H3_NUM_CPUS; i++) { - object_initialize_child(obj, "cpu[*]", &s->cpus[i], sizeof(s->cpus[i]), - ARM_CPU_TYPE_NAME("cortex-a7"), - &error_abort, NULL); + object_initialize_child(obj, "cpu[*]", &s->cpus[i], + ARM_CPU_TYPE_NAME("cortex-a7")); } sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic), diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 174ca7effc..c903e725f7 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -251,9 +251,7 @@ static void armsse_init(Object *obj) char *name; name = g_strdup_printf("cluster%d", i); - object_initialize_child(obj, name, &s->cluster[i], - sizeof(s->cluster[i]), TYPE_CPU_CLUSTER, - &error_abort, NULL); + object_initialize_child(obj, name, &s->cluster[i], TYPE_CPU_CLUSTER); qdev_prop_set_uint32(DEVICE(&s->cluster[i]), "cluster-id", i); g_free(name); @@ -287,15 +285,13 @@ static void armsse_init(Object *obj) g_free(name); } object_initialize_child(obj, "mpc-irq-orgate", &s->mpc_irq_orgate, - sizeof(s->mpc_irq_orgate), TYPE_OR_IRQ, - &error_abort, NULL); + TYPE_OR_IRQ); for (i = 0; i < IOTS_NUM_EXP_MPC + info->sram_banks; i++) { char *name = g_strdup_printf("mpc-irq-splitter-%d", i); SplitIRQ *splitter = &s->mpc_irq_splitter[i]; - object_initialize_child(obj, name, splitter, sizeof(*splitter), - TYPE_SPLIT_IRQ, &error_abort, NULL); + object_initialize_child(obj, name, splitter, TYPE_SPLIT_IRQ); g_free(name); } sysbus_init_child_obj(obj, "timer0", &s->timer0, sizeof(s->timer0), @@ -375,21 +371,16 @@ static void armsse_init(Object *obj) g_free(name); } } - object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate, - sizeof(s->nmi_orgate), TYPE_OR_IRQ, - &error_abort, NULL); + object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate, TYPE_OR_IRQ); object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate, - sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ, - &error_abort, NULL); + TYPE_OR_IRQ); object_initialize_child(obj, "sec-resp-splitter", &s->sec_resp_splitter, - sizeof(s->sec_resp_splitter), TYPE_SPLIT_IRQ, - &error_abort, NULL); + TYPE_SPLIT_IRQ); for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) { char *name = g_strdup_printf("ppc-irq-splitter-%d", i); SplitIRQ *splitter = &s->ppc_irq_splitter[i]; - object_initialize_child(obj, name, splitter, sizeof(*splitter), - TYPE_SPLIT_IRQ, &error_abort, NULL); + object_initialize_child(obj, name, splitter, TYPE_SPLIT_IRQ); g_free(name); } if (info->num_cpus > 1) { @@ -398,8 +389,7 @@ static void armsse_init(Object *obj) char *name = g_strdup_printf("cpu-irq-splitter%d", i); SplitIRQ *splitter = &s->cpu_irq_splitter[i]; - object_initialize_child(obj, name, splitter, sizeof(*splitter), - TYPE_SPLIT_IRQ, &error_abort, NULL); + object_initialize_child(obj, name, splitter, TYPE_SPLIT_IRQ); g_free(name); } } diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index ee50476ccb..46fe6fecc2 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -267,9 +267,7 @@ static void aspeed_machine_init(MachineState *machine) 4 * GiB); memory_region_add_subregion(&bmc->ram_container, 0, machine->ram); - object_initialize_child(OBJECT(machine), "soc", &bmc->soc, - sizeof(bmc->soc), amc->soc_name, &error_abort, - NULL); + object_initialize_child(OBJECT(machine), "soc", &bmc->soc, amc->soc_name); sc = ASPEED_SOC_GET_CLASS(&bmc->soc); diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index b912d19f80..beb688fd8f 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -127,9 +127,7 @@ static void aspeed_soc_ast2600_init(Object *obj) } for (i = 0; i < sc->num_cpus; i++) { - object_initialize_child(obj, "cpu[*]", OBJECT(&s->cpu[i]), - sizeof(s->cpu[i]), sc->cpu_type, - &error_abort, NULL); + object_initialize_child(obj, "cpu[*]", &s->cpu[i], sc->cpu_type); } snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname); diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 3ec1257c14..18d1763aba 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -142,9 +142,7 @@ static void aspeed_soc_init(Object *obj) } for (i = 0; i < sc->num_cpus; i++) { - object_initialize_child(obj, "cpu[*]", OBJECT(&s->cpu[i]), - sizeof(s->cpu[i]), sc->cpu_type, - &error_abort, NULL); + object_initialize_child(obj, "cpu[*]", &s->cpu[i], sc->cpu_type); } snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname); diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index e51b4e0c43..82cd1d2df8 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -53,8 +53,7 @@ static void bcm2836_init(Object *obj) for (n = 0; n < BCM283X_NCPUS; n++) { object_initialize_child(obj, "cpu[*]", &s->cpu[n].core, - sizeof(s->cpu[n].core), info->cpu_type, - &error_abort, NULL); + info->cpu_type); } sysbus_init_child_obj(obj, "control", &s->control, sizeof(s->control), diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 22434a65a2..6153d5f108 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -36,9 +36,7 @@ static void digic_init(Object *obj) DigicState *s = DIGIC(obj); int i; - object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu), - ARM_CPU_TYPE_NAME("arm946"), - &error_abort, NULL); + object_initialize_child(obj, "cpu", &s->cpu, ARM_CPU_TYPE_NAME("arm946")); for (i = 0; i < DIGIC4_NB_TIMERS; i++) { #define DIGIC_TIMER_NAME_MLEN 11 diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index 9ff1a11f80..86cbd63857 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -482,8 +482,7 @@ static void exynos4210_init(Object *obj) char *name = g_strdup_printf("pl330-irq-orgate%d", i); qemu_or_irq *orgate = &s->pl330_irq_orgate[i]; - object_initialize_child(obj, name, orgate, sizeof(*orgate), - TYPE_OR_IRQ, &error_abort, NULL); + object_initialize_child(obj, name, orgate, TYPE_OR_IRQ); g_free(name); } } diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index cdaa79c26b..d8340e3527 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -38,9 +38,7 @@ static void fsl_imx25_init(Object *obj) FslIMX25State *s = FSL_IMX25(obj); int i; - object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu), - ARM_CPU_TYPE_NAME("arm926"), - &error_abort, NULL); + object_initialize_child(obj, "cpu", &s->cpu, ARM_CPU_TYPE_NAME("arm926")); sysbus_init_child_obj(obj, "avic", &s->avic, sizeof(s->avic), TYPE_IMX_AVIC); diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index 1e7959863d..54eec89701 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -33,9 +33,7 @@ static void fsl_imx31_init(Object *obj) FslIMX31State *s = FSL_IMX31(obj); int i; - object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu), - ARM_CPU_TYPE_NAME("arm1136"), - &error_abort, NULL); + object_initialize_child(obj, "cpu", &s->cpu, ARM_CPU_TYPE_NAME("arm1136")); sysbus_init_child_obj(obj, "avic", &s->avic, sizeof(s->avic), TYPE_IMX_AVIC); diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index f58c85aa8c..88fbba84a4 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -43,9 +43,8 @@ static void fsl_imx6_init(Object *obj) for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX6_NUM_CPUS); i++) { snprintf(name, NAME_SIZE, "cpu%d", i); - object_initialize_child(obj, name, &s->cpu[i], sizeof(s->cpu[i]), - ARM_CPU_TYPE_NAME("cortex-a9"), - &error_abort, NULL); + object_initialize_child(obj, name, &s->cpu[i], + ARM_CPU_TYPE_NAME("cortex-a9")); } sysbus_init_child_obj(obj, "a9mpcore", &s->a9mpcore, sizeof(s->a9mpcore), diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index 3ecb212da6..491f1b7f73 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -34,8 +34,8 @@ static void fsl_imx6ul_init(Object *obj) char name[NAME_SIZE]; int i; - object_initialize_child(obj, "cpu0", &s->cpu, sizeof(s->cpu), - ARM_CPU_TYPE_NAME("cortex-a7"), &error_abort, NULL); + object_initialize_child(obj, "cpu0", &s->cpu, + ARM_CPU_TYPE_NAME("cortex-a7")); /* * A7MPCORE diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index 89c3b64c06..5cf2b7a808 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -38,9 +38,8 @@ static void fsl_imx7_init(Object *obj) for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX7_NUM_CPUS); i++) { snprintf(name, NAME_SIZE, "cpu%d", i); - object_initialize_child(obj, name, &s->cpu[i], sizeof(s->cpu[i]), - ARM_CPU_TYPE_NAME("cortex-a7"), &error_abort, - NULL); + object_initialize_child(obj, name, &s->cpu[i], + ARM_CPU_TYPE_NAME("cortex-a7")); } /* diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 75076f2ea4..69b95711e4 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -73,8 +73,7 @@ static void imx25_pdk_init(MachineState *machine) unsigned int alias_offset; int i; - object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), - TYPE_FSL_IMX25, &error_abort, NULL); + object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_FSL_IMX25); object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c index 34f6bcb491..0275d63079 100644 --- a/hw/arm/kzm.c +++ b/hw/arm/kzm.c @@ -71,8 +71,7 @@ static void kzm_init(MachineState *machine) unsigned int alias_offset; unsigned int i; - object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), - TYPE_FSL_IMX31, &error_abort, NULL); + object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_FSL_IMX31); object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 07d11e439f..8a050228d0 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -414,9 +414,10 @@ static void mps2tz_common_init(MachineState *machine) char *name = g_strdup_printf("mps2-irq-splitter%d", i); SplitIRQ *splitter = &mms->cpu_irq_splitter[i]; - object_initialize_child(OBJECT(machine), name, - splitter, sizeof(*splitter), - TYPE_SPLIT_IRQ, &error_fatal, NULL); + object_initialize_child_with_props(OBJECT(machine), name, + splitter, sizeof(*splitter), + TYPE_SPLIT_IRQ, &error_fatal, + NULL); g_free(name); object_property_set_int(OBJECT(splitter), 2, "num-lines", @@ -436,9 +437,7 @@ static void mps2tz_common_init(MachineState *machine) * lines, one for each of the PPCs we create here, plus one per MSC. */ object_initialize_child(OBJECT(machine), "sec-resp-splitter", - &mms->sec_resp_splitter, - sizeof(mms->sec_resp_splitter), - TYPE_SPLIT_IRQ, &error_abort, NULL); + &mms->sec_resp_splitter, TYPE_SPLIT_IRQ); object_property_set_int(OBJECT(&mms->sec_resp_splitter), ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc), "num-lines", &error_fatal); @@ -472,8 +471,7 @@ static void mps2tz_common_init(MachineState *machine) * Create the OR gate for this. */ object_initialize_child(OBJECT(mms), "uart-irq-orgate", - &mms->uart_irq_orgate, sizeof(mms->uart_irq_orgate), - TYPE_OR_IRQ, &error_abort, NULL); + &mms->uart_irq_orgate, TYPE_OR_IRQ); object_property_set_int(OBJECT(&mms->uart_irq_orgate), 10, "num-lines", &error_fatal); object_property_set_bool(OBJECT(&mms->uart_irq_orgate), true, diff --git a/hw/arm/musca.c b/hw/arm/musca.c index ba99dd1941..cd7df7c191 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -404,9 +404,9 @@ static void musca_init(MachineState *machine) char *name = g_strdup_printf("musca-irq-splitter%d", i); SplitIRQ *splitter = &mms->cpu_irq_splitter[i]; - object_initialize_child(OBJECT(machine), name, - splitter, sizeof(*splitter), - TYPE_SPLIT_IRQ, &error_fatal, NULL); + object_initialize_child_with_props(OBJECT(machine), name, splitter, + sizeof(*splitter), TYPE_SPLIT_IRQ, + &error_fatal, NULL); g_free(name); object_property_set_int(OBJECT(splitter), 2, "num-lines", @@ -424,10 +424,10 @@ static void musca_init(MachineState *machine) * The sec_resp_cfg output from the SSE-200 must be split into multiple * lines, one for each of the PPCs we create here. */ - object_initialize_child(OBJECT(machine), "sec-resp-splitter", - &mms->sec_resp_splitter, - sizeof(mms->sec_resp_splitter), - TYPE_SPLIT_IRQ, &error_fatal, NULL); + object_initialize_child_with_props(OBJECT(machine), "sec-resp-splitter", + &mms->sec_resp_splitter, + sizeof(mms->sec_resp_splitter), + TYPE_SPLIT_IRQ, &error_fatal, NULL); object_property_set_int(OBJECT(&mms->sec_resp_splitter), ARRAY_SIZE(mms->ppc), "num-lines", &error_fatal); diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index a8e26a70bb..78cb995251 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -282,8 +282,8 @@ static void raspi_machine_init(MachineState *machine) machine->ram, 0); /* Setup the SOC */ - object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), - board_soc_type(board_rev), &error_abort, NULL); + object_initialize_child(OBJECT(machine), "soc", &s->soc, + board_soc_type(board_rev)); object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(machine->ram)); object_property_set_int(OBJECT(&s->soc), board_rev, "board-rev", &error_abort); diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index c9a530eecf..33a83bd1d4 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -169,9 +169,9 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) } /* ADC device, the IRQs are ORed together */ - object_initialize_child(OBJECT(s), "adc-orirq", &s->adc_irqs, - sizeof(s->adc_irqs), TYPE_OR_IRQ, - &err, NULL); + object_initialize_child_with_props(OBJECT(s), "adc-orirq", &s->adc_irqs, + sizeof(s->adc_irqs), TYPE_OR_IRQ, &err, + NULL); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index c3d47bb9e9..12e4469cf4 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -32,9 +32,8 @@ static void versal_create_apu_cpus(Versal *s) for (i = 0; i < ARRAY_SIZE(s->fpd.apu.cpu); i++) { Object *obj; - object_initialize_child(OBJECT(s), "apu-cpu[*]", - &s->fpd.apu.cpu[i], sizeof(s->fpd.apu.cpu[i]), - XLNX_VERSAL_ACPU_TYPE, &error_abort, NULL); + object_initialize_child(OBJECT(s), "apu-cpu[*]", &s->fpd.apu.cpu[i], + XLNX_VERSAL_ACPU_TYPE); obj = OBJECT(&s->fpd.apu.cpu[i]); object_property_set_int(obj, s->cfg.psci_conduit, "psci-conduit", &error_abort); diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 77c84b82ab..822e24af65 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -116,8 +116,7 @@ static void xlnx_zcu102_init(MachineState *machine) ram_size); } - object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), - TYPE_XLNX_ZYNQMP, &error_abort, NULL); + object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_XLNX_ZYNQMP); object_property_set_link(OBJECT(&s->soc), OBJECT(machine->ram), "ddr-ram", &error_abort); diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index f08abf60d7..890139d6a2 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -187,17 +187,15 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s, } object_initialize_child(OBJECT(s), "rpu-cluster", &s->rpu_cluster, - sizeof(s->rpu_cluster), TYPE_CPU_CLUSTER, - &error_abort, NULL); + TYPE_CPU_CLUSTER); qdev_prop_set_uint32(DEVICE(&s->rpu_cluster), "cluster-id", 1); for (i = 0; i < num_rpus; i++) { char *name; object_initialize_child(OBJECT(&s->rpu_cluster), "rpu-cpu[*]", - &s->rpu_cpu[i], sizeof(s->rpu_cpu[i]), - ARM_CPU_TYPE_NAME("cortex-r5f"), - &error_abort, NULL); + &s->rpu_cpu[i], + ARM_CPU_TYPE_NAME("cortex-r5f")); name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i])); if (strcmp(name, boot_cpu)) { @@ -230,15 +228,13 @@ static void xlnx_zynqmp_init(Object *obj) int num_apus = MIN(ms->smp.cpus, XLNX_ZYNQMP_NUM_APU_CPUS); object_initialize_child(obj, "apu-cluster", &s->apu_cluster, - sizeof(s->apu_cluster), TYPE_CPU_CLUSTER, - &error_abort, NULL); + TYPE_CPU_CLUSTER); qdev_prop_set_uint32(DEVICE(&s->apu_cluster), "cluster-id", 0); for (i = 0; i < num_apus; i++) { object_initialize_child(OBJECT(&s->apu_cluster), "apu-cpu[*]", - &s->apu_cpu[i], sizeof(s->apu_cpu[i]), - ARM_CPU_TYPE_NAME("cortex-a53"), - &error_abort, NULL); + &s->apu_cpu[i], + ARM_CPU_TYPE_NAME("cortex-a53")); } sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic), diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index d69aab5714..d816dc3d73 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -136,8 +136,7 @@ static void serial_isa_initfn(Object *o) { ISASerialState *self = ISA_SERIAL(o); - object_initialize_child(o, "serial", &self->state, sizeof(self->state), - TYPE_SERIAL, &error_abort, NULL); + object_initialize_child(o, "serial", &self->state, TYPE_SERIAL); } static const TypeInfo serial_isa_info = { diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c index 23d0ebe2cd..1d65d64c4e 100644 --- a/hw/char/serial-pci-multi.c +++ b/hw/char/serial-pci-multi.c @@ -187,9 +187,7 @@ static void multi_serial_init(Object *o) size_t i, nports = multi_serial_get_port_count(PCI_DEVICE_GET_CLASS(dev)); for (i = 0; i < nports; i++) { - object_initialize_child(o, "serial[*]", &pms->state[i], - sizeof(pms->state[i]), - TYPE_SERIAL, &error_abort, NULL); + object_initialize_child(o, "serial[*]", &pms->state[i], TYPE_SERIAL); } } diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index 65eacfae0e..5f5ff10a75 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -108,8 +108,7 @@ static void serial_pci_init(Object *o) { PCISerialState *ps = PCI_SERIAL(o); - object_initialize_child(o, "serial", &ps->state, sizeof(ps->state), - TYPE_SERIAL, &error_abort, NULL); + object_initialize_child(o, "serial", &ps->state, TYPE_SERIAL); } static const TypeInfo serial_pci_info = { diff --git a/hw/char/serial.c b/hw/char/serial.c index a0cab38fb0..57c299e993 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -1014,8 +1014,7 @@ static void serial_io_instance_init(Object *o) { SerialIO *sio = SERIAL_IO(o); - object_initialize_child(o, "serial", &sio->serial, sizeof(sio->serial), - TYPE_SERIAL, &error_abort, NULL); + object_initialize_child(o, "serial", &sio->serial, TYPE_SERIAL); qdev_alias_all_properties(DEVICE(&sio->serial), o); } @@ -1148,8 +1147,7 @@ static void serial_mm_instance_init(Object *o) { SerialMM *smm = SERIAL_MM(o); - object_initialize_child(o, "serial", &smm->serial, sizeof(smm->serial), - TYPE_SERIAL, &error_abort, NULL); + object_initialize_child(o, "serial", &smm->serial, TYPE_SERIAL); qdev_alias_all_properties(DEVICE(&smm->serial), o); } diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 7ff1b5f2de..e8d08d349b 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -348,8 +348,8 @@ BusState *sysbus_get_default(void) void sysbus_init_child_obj(Object *parent, const char *childname, void *child, size_t childsize, const char *childtype) { - object_initialize_child(parent, childname, child, childsize, childtype, - &error_abort, NULL); + object_initialize_child_with_props(parent, childname, child, childsize, + childtype, &error_abort, NULL); qdev_set_parent_bus(DEVICE(child), sysbus_get_default()); } diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 460102b142..6a9df2c4db 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -579,13 +579,10 @@ static void xilinx_axidma_init(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); object_initialize_child(OBJECT(s), "axistream-connected-target", - &s->rx_data_dev, sizeof(s->rx_data_dev), - TYPE_XILINX_AXI_DMA_DATA_STREAM, &error_abort, - NULL); + &s->rx_data_dev, TYPE_XILINX_AXI_DMA_DATA_STREAM); object_initialize_child(OBJECT(s), "axistream-control-connected-target", - &s->rx_control_dev, sizeof(s->rx_control_dev), - TYPE_XILINX_AXI_DMA_CONTROL_STREAM, &error_abort, - NULL); + &s->rx_control_dev, + TYPE_XILINX_AXI_DMA_CONTROL_STREAM); object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, (Object **)&s->dma_mr, qdev_prop_allow_set_link_before_realize, diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index aeda488bd1..892c78069d 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -1796,11 +1796,9 @@ static void pnv_xive_init(Object *obj) PnvXive *xive = PNV_XIVE(obj); object_initialize_child(obj, "ipi_source", &xive->ipi_source, - sizeof(xive->ipi_source), TYPE_XIVE_SOURCE, - &error_abort, NULL); + TYPE_XIVE_SOURCE); object_initialize_child(obj, "end_source", &xive->end_source, - sizeof(xive->end_source), TYPE_XIVE_END_SOURCE, - &error_abort, NULL); + TYPE_XIVE_END_SOURCE); } /* diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 6608d7220a..263cd1253c 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -272,12 +272,10 @@ static void spapr_xive_instance_init(Object *obj) { SpaprXive *xive = SPAPR_XIVE(obj); - object_initialize_child(obj, "source", &xive->source, sizeof(xive->source), - TYPE_XIVE_SOURCE, &error_abort, NULL); + object_initialize_child(obj, "source", &xive->source, TYPE_XIVE_SOURCE); object_initialize_child(obj, "end_source", &xive->end_source, - sizeof(xive->end_source), TYPE_XIVE_END_SOURCE, - &error_abort, NULL); + TYPE_XIVE_END_SOURCE); /* Not connected to the KVM XIVE device */ xive->fd = -1; diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index aa90b9d1be..bd56eccd66 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -61,8 +61,7 @@ static void xlnx_zynqmp_pmu_soc_init(Object *obj) { XlnxZynqMPPMUSoCState *s = XLNX_ZYNQMP_PMU_SOC(obj); - object_initialize_child(obj, "pmu-cpu", &s->cpu, sizeof(s->cpu), - TYPE_MICROBLAZE_CPU, &error_abort, NULL); + object_initialize_child(obj, "pmu-cpu", &s->cpu, TYPE_MICROBLAZE_CPU); sysbus_init_child_obj(obj, "intc", &s->intc, sizeof(s->intc), TYPE_XLNX_PMU_IO_INTC); @@ -174,8 +173,8 @@ static void xlnx_zynqmp_pmu_init(MachineState *machine) pmu_ram); /* Create the PMU device */ - object_initialize_child(OBJECT(machine), "pmu", pmu, sizeof(*pmu), - TYPE_XLNX_ZYNQMP_PMU_SOC, &error_abort, NULL); + object_initialize_child(OBJECT(machine), "pmu", pmu, + TYPE_XLNX_ZYNQMP_PMU_SOC); object_property_set_bool(OBJECT(pmu), true, "realized", &error_fatal); /* Load the kernel */ diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 216bdc69c0..a2698e4a20 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -98,8 +98,8 @@ static void macio_init_child_obj(MacIOState *s, const char *childname, void *child, size_t childsize, const char *childtype) { - object_initialize_child(OBJECT(s), childname, child, childsize, childtype, - &error_abort, NULL); + object_initialize_child_with_props(OBJECT(s), childname, child, childsize, + childtype, &error_abort, NULL); qdev_set_parent_bus(DEVICE(child), BUS(&s->macio_bus)); } @@ -351,8 +351,7 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) object_property_set_bool(OBJECT(&ns->gpio), true, "realized", &err); /* PMU */ - object_initialize_child(OBJECT(s), "pmu", &s->pmu, sizeof(s->pmu), - TYPE_VIA_PMU, &error_abort, NULL); + object_initialize_child(OBJECT(s), "pmu", &s->pmu, TYPE_VIA_PMU); object_property_set_link(OBJECT(&s->pmu), OBJECT(sysbus_dev), "gpio", &error_abort); qdev_prop_set_bit(DEVICE(&s->pmu), "has-adb", ns->has_adb); @@ -370,8 +369,7 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) object_unparent(OBJECT(&ns->gpio)); /* CUDA */ - object_initialize_child(OBJECT(s), "cuda", &s->cuda, sizeof(s->cuda), - TYPE_CUDA, &error_abort, NULL); + object_initialize_child(OBJECT(s), "cuda", &s->cuda, TYPE_CUDA); qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency", s->frequency); diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 44fe04d889..c2f40b8ea9 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -1020,13 +1020,10 @@ static void xilinx_enet_init(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); object_initialize_child(OBJECT(s), "axistream-connected-target", - &s->rx_data_dev, sizeof(s->rx_data_dev), - TYPE_XILINX_AXI_ENET_DATA_STREAM, &error_abort, - NULL); + &s->rx_data_dev, TYPE_XILINX_AXI_ENET_DATA_STREAM); object_initialize_child(OBJECT(s), "axistream-control-connected-target", - &s->rx_control_dev, sizeof(s->rx_control_dev), - TYPE_XILINX_AXI_ENET_CONTROL_STREAM, &error_abort, - NULL); + &s->rx_control_dev, + TYPE_XILINX_AXI_ENET_CONTROL_STREAM); sysbus_init_irq(sbd, &s->irq); memory_region_init_io(&s->iomem, OBJECT(s), &enet_ops, s, "enet", 0x40000); diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index 2e97d6b17f..8492c18991 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -722,8 +722,7 @@ static void designware_pcie_host_init(Object *obj) DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(obj); DesignwarePCIERoot *root = &s->root; - object_initialize_child(obj, "root", root, sizeof(*root), - TYPE_DESIGNWARE_PCIE_ROOT, &error_abort, NULL); + object_initialize_child(obj, "root", root, TYPE_DESIGNWARE_PCIE_ROOT); qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0)); qdev_prop_set_bit(DEVICE(root), "multifunction", false); } diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c index 3dfb3bf599..2bdbe7b456 100644 --- a/hw/pci-host/gpex.c +++ b/hw/pci-host/gpex.c @@ -124,8 +124,7 @@ static void gpex_host_initfn(Object *obj) GPEXHost *s = GPEX_HOST(obj); GPEXRootState *root = &s->gpex_root; - object_initialize_child(obj, "gpex_root", root, sizeof(*root), - TYPE_GPEX_ROOT_DEVICE, &error_abort, NULL); + object_initialize_child(obj, "gpex_root", root, TYPE_GPEX_ROOT_DEVICE); qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0)); qdev_prop_set_bit(DEVICE(root), "multifunction", false); } diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index 8dcfe4a2fd..6e2b0174f6 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -968,23 +968,19 @@ static void pnv_phb3_instance_init(Object *obj) QLIST_INIT(&phb->dma_spaces); /* LSI sources */ - object_initialize_child(obj, "lsi", &phb->lsis, sizeof(phb->lsis), - TYPE_ICS, &error_abort, NULL); + object_initialize_child(obj, "lsi", &phb->lsis, TYPE_ICS); /* Default init ... will be fixed by HW inits */ phb->lsis.offset = 0; /* MSI sources */ - object_initialize_child(obj, "msi", &phb->msis, sizeof(phb->msis), - TYPE_PHB3_MSI, &error_abort, NULL); + object_initialize_child(obj, "msi", &phb->msis, TYPE_PHB3_MSI); /* Power Bus Common Queue */ - object_initialize_child(obj, "pbcq", &phb->pbcq, sizeof(phb->pbcq), - TYPE_PNV_PBCQ, &error_abort, NULL); + object_initialize_child(obj, "pbcq", &phb->pbcq, TYPE_PNV_PBCQ); /* Root Port */ - object_initialize_child(obj, "root", &phb->root, sizeof(phb->root), - TYPE_PNV_PHB3_ROOT_PORT, &error_abort, NULL); + object_initialize_child(obj, "root", &phb->root, TYPE_PNV_PHB3_ROOT_PORT); qdev_prop_set_int32(DEVICE(&phb->root), "addr", PCI_DEVFN(0, 0)); qdev_prop_set_bit(DEVICE(&phb->root), "multifunction", false); } diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index aba710fd1f..368ae9eacd 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1155,12 +1155,10 @@ static void pnv_phb4_instance_init(Object *obj) QLIST_INIT(&phb->dma_spaces); /* XIVE interrupt source object */ - object_initialize_child(obj, "source", &phb->xsrc, sizeof(phb->xsrc), - TYPE_XIVE_SOURCE, &error_abort, NULL); + object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE); /* Root Port */ - object_initialize_child(obj, "root", &phb->root, sizeof(phb->root), - TYPE_PNV_PHB4_ROOT_PORT, &error_abort, NULL); + object_initialize_child(obj, "root", &phb->root, TYPE_PNV_PHB4_ROOT_PORT); qdev_prop_set_int32(DEVICE(&phb->root), "addr", PCI_DEVFN(0, 0)); qdev_prop_set_bit(DEVICE(&phb->root), "multifunction", false); diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index 565345a018..f9b41c5042 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -370,8 +370,7 @@ static void pnv_pec_instance_init(Object *obj) for (i = 0; i < PHB4_PEC_MAX_STACKS; i++) { object_initialize_child(obj, "stack[*]", &pec->stacks[i], - sizeof(pec->stacks[i]), TYPE_PNV_PHB4_PEC_STACK, - &error_abort, NULL); + TYPE_PNV_PHB4_PEC_STACK); } } @@ -522,8 +521,7 @@ static void pnv_pec_stk_instance_init(Object *obj) { PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(obj); - object_initialize_child(obj, "phb", &stack->phb, sizeof(stack->phb), - TYPE_PNV_PHB4, &error_abort, NULL); + object_initialize_child(obj, "phb", &stack->phb, TYPE_PNV_PHB4); } static void pnv_pec_stk_realize(DeviceState *dev, Error **errp) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 43ed5188cc..b67cb9c29f 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -212,8 +212,7 @@ static void q35_host_initfn(Object *obj) memory_region_init_io(&phb->data_mem, obj, &pci_host_data_le_ops, phb, "pci-conf-data", 4); - object_initialize_child(OBJECT(s), "mch", &s->mch, sizeof(s->mch), - TYPE_MCH_PCI_DEVICE, &error_abort, NULL); + object_initialize_child(OBJECT(s), "mch", &s->mch, TYPE_MCH_PCI_DEVICE); qdev_prop_set_int32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0)); qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false); /* mch's object_initialize resets the default value, set it again */ diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c index e4fc8abb6a..3b321421b6 100644 --- a/hw/pci-host/xilinx-pcie.c +++ b/hw/pci-host/xilinx-pcie.c @@ -151,8 +151,7 @@ static void xilinx_pcie_host_init(Object *obj) XilinxPCIEHost *s = XILINX_PCIE_HOST(obj); XilinxPCIERoot *root = &s->root; - object_initialize_child(obj, "root", root, sizeof(*root), - TYPE_XILINX_PCIE_ROOT, &error_abort, NULL); + object_initialize_child(obj, "root", root, TYPE_XILINX_PCIE_ROOT); qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0)); qdev_prop_set_bit(DEVICE(root), "multifunction", false); } diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index ffaf12b006..8cf097ae7c 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1061,22 +1061,16 @@ static void pnv_chip_power8_instance_init(Object *obj) object_property_allow_set_link, OBJ_PROP_LINK_STRONG); - object_initialize_child(obj, "psi", &chip8->psi, sizeof(chip8->psi), - TYPE_PNV8_PSI, &error_abort, NULL); + object_initialize_child(obj, "psi", &chip8->psi, TYPE_PNV8_PSI); - object_initialize_child(obj, "lpc", &chip8->lpc, sizeof(chip8->lpc), - TYPE_PNV8_LPC, &error_abort, NULL); + object_initialize_child(obj, "lpc", &chip8->lpc, TYPE_PNV8_LPC); - object_initialize_child(obj, "occ", &chip8->occ, sizeof(chip8->occ), - TYPE_PNV8_OCC, &error_abort, NULL); + object_initialize_child(obj, "occ", &chip8->occ, TYPE_PNV8_OCC); - object_initialize_child(obj, "homer", &chip8->homer, sizeof(chip8->homer), - TYPE_PNV8_HOMER, &error_abort, NULL); + object_initialize_child(obj, "homer", &chip8->homer, TYPE_PNV8_HOMER); for (i = 0; i < pcc->num_phbs; i++) { - object_initialize_child(obj, "phb[*]", &chip8->phbs[i], - sizeof(chip8->phbs[i]), TYPE_PNV_PHB3, - &error_abort, NULL); + object_initialize_child(obj, "phb[*]", &chip8->phbs[i], TYPE_PNV_PHB3); } /* @@ -1320,22 +1314,17 @@ static void pnv_chip_power9_instance_init(Object *obj) object_property_add_alias(obj, "xive-fabric", OBJECT(&chip9->xive), "xive-fabric"); - object_initialize_child(obj, "psi", &chip9->psi, sizeof(chip9->psi), - TYPE_PNV9_PSI, &error_abort, NULL); + object_initialize_child(obj, "psi", &chip9->psi, TYPE_PNV9_PSI); - object_initialize_child(obj, "lpc", &chip9->lpc, sizeof(chip9->lpc), - TYPE_PNV9_LPC, &error_abort, NULL); + object_initialize_child(obj, "lpc", &chip9->lpc, TYPE_PNV9_LPC); - object_initialize_child(obj, "occ", &chip9->occ, sizeof(chip9->occ), - TYPE_PNV9_OCC, &error_abort, NULL); + object_initialize_child(obj, "occ", &chip9->occ, TYPE_PNV9_OCC); - object_initialize_child(obj, "homer", &chip9->homer, sizeof(chip9->homer), - TYPE_PNV9_HOMER, &error_abort, NULL); + object_initialize_child(obj, "homer", &chip9->homer, TYPE_PNV9_HOMER); for (i = 0; i < PNV9_CHIP_MAX_PEC; i++) { object_initialize_child(obj, "pec[*]", &chip9->pecs[i], - sizeof(chip9->pecs[i]), TYPE_PNV_PHB4_PEC, - &error_abort, NULL); + TYPE_PNV_PHB4_PEC); } /* @@ -1359,8 +1348,9 @@ static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp) int core_id = CPU_CORE(pnv_core)->core_id; snprintf(eq_name, sizeof(eq_name), "eq[%d]", core_id); - object_initialize_child(OBJECT(chip), eq_name, eq, sizeof(*eq), - TYPE_PNV_QUAD, &error_fatal, NULL); + object_initialize_child_with_props(OBJECT(chip), eq_name, eq, + sizeof(*eq), TYPE_PNV_QUAD, + &error_fatal, NULL); object_property_set_int(OBJECT(eq), core_id, "id", &error_fatal); object_property_set_bool(OBJECT(eq), true, "realized", &error_fatal); @@ -1586,10 +1576,8 @@ static void pnv_chip_power10_instance_init(Object *obj) { Pnv10Chip *chip10 = PNV10_CHIP(obj); - object_initialize_child(obj, "psi", &chip10->psi, sizeof(chip10->psi), - TYPE_PNV10_PSI, &error_abort, NULL); - object_initialize_child(obj, "lpc", &chip10->lpc, sizeof(chip10->lpc), - TYPE_PNV10_LPC, &error_abort, NULL); + object_initialize_child(obj, "psi", &chip10->psi, TYPE_PNV10_PSI); + object_initialize_child(obj, "lpc", &chip10->lpc, TYPE_PNV10_LPC); } static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 82f0769465..20e54ad5ac 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -483,8 +483,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, &error_abort, NULL); + object_initialize_child(obj, "ics-psi", &psi8->ics, TYPE_ICS); object_property_add_alias(obj, ICS_PROP_XICS, OBJECT(&psi8->ics), ICS_PROP_XICS); } @@ -836,8 +835,7 @@ static void pnv_psi_power9_instance_init(Object *obj) { Pnv9Psi *psi = PNV9_PSI(obj); - object_initialize_child(obj, "source", &psi->source, sizeof(psi->source), - TYPE_XIVE_SOURCE, &error_abort, NULL); + object_initialize_child(obj, "source", &psi->source, TYPE_XIVE_SOURCE); } static void pnv_psi_power9_realize(DeviceState *dev, Error **errp) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 1228aeb4b0..7ef24ea2a1 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1727,9 +1727,9 @@ static void spapr_create_nvram(SpaprMachineState *spapr) static void spapr_rtc_create(SpaprMachineState *spapr) { - object_initialize_child(OBJECT(spapr), "rtc", - &spapr->rtc, sizeof(spapr->rtc), TYPE_SPAPR_RTC, - &error_fatal, NULL); + object_initialize_child_with_props(OBJECT(spapr), "rtc", &spapr->rtc, + sizeof(spapr->rtc), TYPE_SPAPR_RTC, + &error_fatal, NULL); object_property_set_bool(OBJECT(&spapr->rtc), true, "realized", &error_fatal); object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc), diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 29887fe363..ae4c3ebb8a 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -60,8 +60,7 @@ static void riscv_opentitan_init(MachineState *machine) /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, - sizeof(s->soc), TYPE_RISCV_IBEX_SOC, - &error_abort, NULL); + TYPE_RISCV_IBEX_SOC); object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort); diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c index 61e88e2e37..56c2be5312 100644 --- a/hw/riscv/riscv_hart.c +++ b/hw/riscv/riscv_hart.c @@ -45,9 +45,7 @@ static void riscv_hart_realize(RISCVHartArrayState *s, int idx, { Error *err = NULL; - object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], - sizeof(s->harts[idx]), cpu_type, - &error_abort, NULL); + object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], cpu_type); s->harts[idx].env.mhartid = s->hartid_base + idx; qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]); object_property_set_bool(OBJECT(&s->harts[idx]), true, diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index d2e2350a4d..77742c1a6e 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -85,9 +85,7 @@ static void riscv_sifive_e_init(MachineState *machine) int i; /* Initialize SoC */ - object_initialize_child(OBJECT(machine), "soc", &s->soc, - sizeof(s->soc), TYPE_RISCV_E_SOC, - &error_abort, NULL); + object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_E_SOC); object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort); diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index d6c6364596..3e39301124 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -328,9 +328,7 @@ static void sifive_u_machine_init(MachineState *machine) int i; /* Initialize SoC */ - object_initialize_child(OBJECT(machine), "soc", &s->soc, - sizeof(s->soc), TYPE_RISCV_U_SOC, - &error_abort, NULL); + object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); object_property_set_uint(OBJECT(&s->soc), s->serial, "serial", &error_abort); object_property_set_bool(OBJECT(&s->soc), true, "realized", @@ -486,9 +484,7 @@ static void sifive_u_soc_instance_init(Object *obj) MachineState *ms = MACHINE(qdev_get_machine()); SiFiveUSoCState *s = RISCV_U_SOC(obj); - object_initialize_child(obj, "e-cluster", &s->e_cluster, - sizeof(s->e_cluster), TYPE_CPU_CLUSTER, - &error_abort, NULL); + object_initialize_child(obj, "e-cluster", &s->e_cluster, TYPE_CPU_CLUSTER); qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0); sysbus_init_child_obj(OBJECT(&s->e_cluster), "e-cpus", @@ -498,9 +494,7 @@ static void sifive_u_soc_instance_init(Object *obj) qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0); qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type", SIFIVE_E_CPU); - object_initialize_child(obj, "u-cluster", &s->u_cluster, - sizeof(s->u_cluster), TYPE_CPU_CLUSTER, - &error_abort, NULL); + object_initialize_child(obj, "u-cluster", &s->u_cluster, TYPE_CPU_CLUSTER); qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1); sysbus_init_child_obj(OBJECT(&s->u_cluster), "u-cpus", diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 850fcce5e7..cc9c9dc162 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3230,8 +3230,9 @@ void virtio_instance_init_common(Object *proxy_obj, void *data, { DeviceState *vdev = data; - object_initialize_child(proxy_obj, "virtio-backend", vdev, vdev_size, - vdev_name, &error_abort, NULL); + object_initialize_child_with_props(proxy_obj, "virtio-backend", vdev, + vdev_size, vdev_name, &error_abort, + NULL); qdev_alias_all_properties(vdev, proxy_obj); } diff --git a/include/qom/object.h b/include/qom/object.h index 43858162ad..94a61ccc3f 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -781,7 +781,7 @@ int object_set_propv(Object *obj, void object_initialize(void *obj, size_t size, const char *typename); /** - * object_initialize_child: + * object_initialize_child_with_props: * @parentobj: The parent object to add a property to * @propname: The name of the property * @childobj: A pointer to the memory to be used for the object. @@ -801,12 +801,13 @@ void object_initialize(void *obj, size_t size, const char *typename); * If the object implements the user creatable interface, the object will * be marked complete once all the properties have been processed. */ -void object_initialize_child(Object *parentobj, const char *propname, +void object_initialize_child_with_props(Object *parentobj, + const char *propname, void *childobj, size_t size, const char *type, Error **errp, ...) QEMU_SENTINEL; /** - * object_initialize_childv: + * object_initialize_child_with_propsv: * @parentobj: The parent object to add a property to * @propname: The name of the property * @childobj: A pointer to the memory to be used for the object. @@ -817,10 +818,31 @@ void object_initialize_child(Object *parentobj, const char *propname, * * See object_initialize_child() for documentation. */ -void object_initialize_childv(Object *parentobj, const char *propname, +void object_initialize_child_with_propsv(Object *parentobj, + const char *propname, void *childobj, size_t size, const char *type, Error **errp, va_list vargs); +/** + * object_initialize_child: + * @parent: The parent object to add a property to + * @propname: The name of the property + * @child: A precisely typed pointer to the memory to be used for the + * object. + * @type: The name of the type of the object to instantiate. + * + * This is like + * object_initialize_child_with_props(parent, propname, + * child, sizeof(*child), type, + * &error_abort, NULL) + */ +#define object_initialize_child(parent, propname, child, type) \ + object_initialize_child_internal((parent), (propname), \ + (child), sizeof(*(child)), (type)) +void object_initialize_child_internal(Object *parent, const char *propname, + void *child, size_t size, + const char *type); + /** * object_dynamic_cast: * @obj: The object to cast. diff --git a/qom/object.c b/qom/object.c index d1340ba3d9..6ece96bc2b 100644 --- a/qom/object.c +++ b/qom/object.c @@ -524,19 +524,21 @@ void object_initialize(void *data, size_t size, const char *typename) object_initialize_with_type(data, size, type); } -void object_initialize_child(Object *parentobj, const char *propname, +void object_initialize_child_with_props(Object *parentobj, + const char *propname, void *childobj, size_t size, const char *type, Error **errp, ...) { va_list vargs; va_start(vargs, errp); - object_initialize_childv(parentobj, propname, childobj, size, type, errp, - vargs); + object_initialize_child_with_propsv(parentobj, propname, + childobj, size, type, errp, vargs); va_end(vargs); } -void object_initialize_childv(Object *parentobj, const char *propname, +void object_initialize_child_with_propsv(Object *parentobj, + const char *propname, void *childobj, size_t size, const char *type, Error **errp, va_list vargs) { @@ -577,6 +579,15 @@ out: error_propagate(errp, local_err); } +void object_initialize_child_internal(Object *parent, + const char *propname, + void *child, size_t size, + const char *type) +{ + object_initialize_child_with_props(parent, propname, child, size, type, + &error_abort, NULL); +} + static inline bool object_property_is_child(ObjectProperty *prop) { return strstart(prop->type, "child<", NULL); From f4a0df70a23946011c0e435d66530ff919e73b37 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:26 +0200 Subject: [PATCH 1262/2595] macio: Convert use of qdev_set_parent_bus() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert qdev_set_parent_bus()/realize to qdev_realize(); recent commit "qdev: New qdev_new(), qdev_realize(), etc." explains why. Cc: Mark Cave-Ayland Cc: David Gibson Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-38-armbru@redhat.com> --- hw/misc/macio/macio.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index a2698e4a20..1a07ca2ca5 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -100,7 +100,6 @@ static void macio_init_child_obj(MacIOState *s, const char *childname, { object_initialize_child_with_props(OBJECT(s), childname, child, childsize, childtype, &error_abort, NULL); - qdev_set_parent_bus(DEVICE(child), BUS(&s->macio_bus)); } static void macio_common_realize(PCIDevice *d, Error **errp) @@ -109,7 +108,7 @@ static void macio_common_realize(PCIDevice *d, Error **errp) SysBusDevice *sysbus_dev; Error *err = NULL; - object_property_set_bool(OBJECT(&s->dbdma), true, "realized", &err); + qdev_realize(DEVICE(&s->dbdma), BUS(&s->macio_bus), &err); if (err) { error_propagate(errp, err); return; @@ -125,7 +124,7 @@ static void macio_common_realize(PCIDevice *d, Error **errp) qdev_prop_set_chr(DEVICE(&s->escc), "chrB", serial_hd(1)); qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial); qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial); - object_property_set_bool(OBJECT(&s->escc), true, "realized", &err); + qdev_realize(DEVICE(&s->escc), BUS(&s->macio_bus), &err); if (err) { error_propagate(errp, err); return; @@ -148,7 +147,7 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide, object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma", errp); macio_ide_register_dma(ide); - object_property_set_bool(OBJECT(ide), true, "realized", errp); + qdev_realize(DEVICE(ide), BUS(&s->macio_bus), errp); } static void macio_oldworld_realize(PCIDevice *d, Error **errp) @@ -167,7 +166,7 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp) qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency", s->frequency); - object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err); + qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), &err); if (err) { error_propagate(errp, err); return; @@ -184,7 +183,7 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp) sysbus_connect_irq(sysbus_dev, 1, qdev_get_gpio_in(pic_dev, OLDWORLD_ESCCA_IRQ)); - object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err); + qdev_realize(DEVICE(&os->nvram), BUS(&s->macio_bus), &err); if (err) { error_propagate(errp, err); return; @@ -348,7 +347,7 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) &error_abort); memory_region_add_subregion(&s->bar, 0x50, sysbus_mmio_get_region(sysbus_dev, 0)); - object_property_set_bool(OBJECT(&ns->gpio), true, "realized", &err); + qdev_realize(DEVICE(&ns->gpio), BUS(&s->macio_bus), &err); /* PMU */ object_initialize_child(OBJECT(s), "pmu", &s->pmu, TYPE_VIA_PMU); From 8fb9cfe762e6d5d6d9d2241dc4d25475ecd3e77d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:27 +0200 Subject: [PATCH 1263/2595] macio: Eliminate macio_init_child_obj() macio_init_child_obj() has become a trivial wrapper around object_initialize_child_with_props(). Eliminate it, since the general convenience wrapper object_initialize_child() is just as convenient already. Cc: Mark Cave-Ayland Cc: David Gibson Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-39-armbru@redhat.com> --- hw/misc/macio/macio.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 1a07ca2ca5..8ba7af073c 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -94,14 +94,6 @@ static void macio_bar_setup(MacIOState *s) macio_escc_legacy_setup(s); } -static void macio_init_child_obj(MacIOState *s, const char *childname, - void *child, size_t childsize, - const char *childtype) -{ - object_initialize_child_with_props(OBJECT(s), childname, child, childsize, - childtype, &error_abort, NULL); -} - static void macio_common_realize(PCIDevice *d, Error **errp) { MacIOState *s = MACIO(d); @@ -218,13 +210,12 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp) } } -static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, size_t ide_size, - int index) +static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, int index) { gchar *name = g_strdup_printf("ide[%i]", index); uint32_t addr = 0x1f000 + ((index + 1) * 0x1000); - macio_init_child_obj(s, name, ide, ide_size, TYPE_MACIO_IDE); + object_initialize_child(OBJECT(s), name, ide, TYPE_MACIO_IDE); qdev_prop_set_uint32(DEVICE(ide), "addr", addr); memory_region_add_subregion(&s->bar, addr, &ide->mem); g_free(name); @@ -242,16 +233,15 @@ static void macio_oldworld_init(Object *obj) qdev_prop_allow_set_link_before_realize, 0); - macio_init_child_obj(s, "cuda", &s->cuda, sizeof(s->cuda), TYPE_CUDA); + object_initialize_child(OBJECT(s), "cuda", &s->cuda, TYPE_CUDA); - macio_init_child_obj(s, "nvram", &os->nvram, sizeof(os->nvram), - TYPE_MACIO_NVRAM); + object_initialize_child(OBJECT(s), "nvram", &os->nvram, TYPE_MACIO_NVRAM); dev = DEVICE(&os->nvram); qdev_prop_set_uint32(dev, "size", 0x2000); qdev_prop_set_uint32(dev, "it_shift", 4); for (i = 0; i < 2; i++) { - macio_init_ide(s, &os->ide[i], sizeof(os->ide[i]), i); + macio_init_ide(s, &os->ide[i], i); } } @@ -396,11 +386,10 @@ static void macio_newworld_init(Object *obj) qdev_prop_allow_set_link_before_realize, 0); - macio_init_child_obj(s, "gpio", &ns->gpio, sizeof(ns->gpio), - TYPE_MACIO_GPIO); + object_initialize_child(OBJECT(s), "gpio", &ns->gpio, TYPE_MACIO_GPIO); for (i = 0; i < 2; i++) { - macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i); + macio_init_ide(s, &ns->ide[i], i); } } @@ -413,10 +402,9 @@ static void macio_instance_init(Object *obj) qbus_create_inplace(&s->macio_bus, sizeof(s->macio_bus), TYPE_MACIO_BUS, DEVICE(obj), "macio.0"); - macio_init_child_obj(s, "dbdma", &s->dbdma, sizeof(s->dbdma), - TYPE_MAC_DBDMA); + object_initialize_child(OBJECT(s), "dbdma", &s->dbdma, TYPE_MAC_DBDMA); - macio_init_child_obj(s, "escc", &s->escc, sizeof(s->escc), TYPE_ESCC); + object_initialize_child(OBJECT(s), "escc", &s->escc, TYPE_ESCC); } static const VMStateDescription vmstate_macio_oldworld = { From 9bdee7f4a5b45f0240c9296fe0daacb6c08f247c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:28 +0200 Subject: [PATCH 1264/2595] sysbus: Drop useless OBJECT() in sysbus_init_child_obj() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OBJECT(child) expands to ((Object *)(child)). sysbus_init_child_obj() parameter @child is void *. Pass child instead of OBJECT(child). Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-40-armbru@redhat.com> --- hw/arm/allwinner-a10.c | 4 ++-- hw/arm/aspeed_ast2600.c | 39 +++++++++++++++++---------------------- hw/arm/aspeed_soc.c | 35 +++++++++++++++-------------------- hw/arm/nrf51_soc.c | 2 +- hw/mips/boston.c | 4 ++-- hw/mips/malta.c | 2 +- 6 files changed, 38 insertions(+), 48 deletions(-) diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 49c51463e1..64449416de 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -59,9 +59,9 @@ static void aw_a10_init(Object *obj) int i; for (i = 0; i < AW_A10_NUM_USB; i++) { - sysbus_init_child_obj(obj, "ehci[*]", OBJECT(&s->ehci[i]), + sysbus_init_child_obj(obj, "ehci[*]", &s->ehci[i], sizeof(s->ehci[i]), TYPE_PLATFORM_EHCI); - sysbus_init_child_obj(obj, "ohci[*]", OBJECT(&s->ohci[i]), + sysbus_init_child_obj(obj, "ohci[*]", &s->ohci[i], sizeof(s->ohci[i]), TYPE_SYSBUS_OHCI); } } diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index beb688fd8f..10e92643c1 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -131,8 +131,7 @@ static void aspeed_soc_ast2600_init(Object *obj) } snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname); - sysbus_init_child_obj(obj, "scu", OBJECT(&s->scu), sizeof(s->scu), - typename); + sysbus_init_child_obj(obj, "scu", &s->scu, sizeof(s->scu), typename); qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev); object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), @@ -145,36 +144,33 @@ static void aspeed_soc_ast2600_init(Object *obj) sysbus_init_child_obj(obj, "a7mpcore", &s->a7mpcore, sizeof(s->a7mpcore), TYPE_A15MPCORE_PRIV); - sysbus_init_child_obj(obj, "rtc", OBJECT(&s->rtc), sizeof(s->rtc), + sysbus_init_child_obj(obj, "rtc", &s->rtc, sizeof(s->rtc), TYPE_ASPEED_RTC); snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname); - sysbus_init_child_obj(obj, "timerctrl", OBJECT(&s->timerctrl), + sysbus_init_child_obj(obj, "timerctrl", &s->timerctrl, sizeof(s->timerctrl), typename); snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname); - sysbus_init_child_obj(obj, "i2c", OBJECT(&s->i2c), sizeof(s->i2c), - typename); + sysbus_init_child_obj(obj, "i2c", &s->i2c, sizeof(s->i2c), typename); snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname); - sysbus_init_child_obj(obj, "fmc", OBJECT(&s->fmc), sizeof(s->fmc), - typename); + sysbus_init_child_obj(obj, "fmc", &s->fmc, sizeof(s->fmc), typename); object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs"); for (i = 0; i < sc->spis_num; i++) { snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i + 1, socname); - sysbus_init_child_obj(obj, "spi[*]", OBJECT(&s->spi[i]), + sysbus_init_child_obj(obj, "spi[*]", &s->spi[i], sizeof(s->spi[i]), typename); } for (i = 0; i < sc->ehcis_num; i++) { - sysbus_init_child_obj(obj, "ehci[*]", OBJECT(&s->ehci[i]), + sysbus_init_child_obj(obj, "ehci[*]", &s->ehci[i], sizeof(s->ehci[i]), TYPE_PLATFORM_EHCI); } snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname); - sysbus_init_child_obj(obj, "sdmc", OBJECT(&s->sdmc), sizeof(s->sdmc), - typename); + sysbus_init_child_obj(obj, "sdmc", &s->sdmc, sizeof(s->sdmc), typename); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), "ram-size"); object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc), @@ -182,30 +178,29 @@ static void aspeed_soc_ast2600_init(Object *obj) for (i = 0; i < sc->wdts_num; i++) { snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname); - sysbus_init_child_obj(obj, "wdt[*]", OBJECT(&s->wdt[i]), + sysbus_init_child_obj(obj, "wdt[*]", &s->wdt[i], sizeof(s->wdt[i]), typename); } for (i = 0; i < sc->macs_num; i++) { - sysbus_init_child_obj(obj, "ftgmac100[*]", OBJECT(&s->ftgmac100[i]), + sysbus_init_child_obj(obj, "ftgmac100[*]", &s->ftgmac100[i], sizeof(s->ftgmac100[i]), TYPE_FTGMAC100); sysbus_init_child_obj(obj, "mii[*]", &s->mii[i], sizeof(s->mii[i]), TYPE_ASPEED_MII); } - sysbus_init_child_obj(obj, "xdma", OBJECT(&s->xdma), sizeof(s->xdma), + sysbus_init_child_obj(obj, "xdma", &s->xdma, sizeof(s->xdma), TYPE_ASPEED_XDMA); snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); - sysbus_init_child_obj(obj, "gpio", OBJECT(&s->gpio), sizeof(s->gpio), - typename); + sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio), typename); snprintf(typename, sizeof(typename), "aspeed.gpio-%s-1_8v", socname); - sysbus_init_child_obj(obj, "gpio_1_8v", OBJECT(&s->gpio_1_8v), + sysbus_init_child_obj(obj, "gpio_1_8v", &s->gpio_1_8v, sizeof(s->gpio_1_8v), typename); - sysbus_init_child_obj(obj, "sd-controller", OBJECT(&s->sdhci), + sysbus_init_child_obj(obj, "sd-controller", &s->sdhci, sizeof(s->sdhci), TYPE_ASPEED_SDHCI); object_property_set_int(OBJECT(&s->sdhci), 2, "num-slots", &error_abort); @@ -213,17 +208,17 @@ static void aspeed_soc_ast2600_init(Object *obj) /* Init sd card slot class here so that they're under the correct parent */ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { sysbus_init_child_obj(obj, "sd-controller.sdhci[*]", - OBJECT(&s->sdhci.slots[i]), + &s->sdhci.slots[i], sizeof(s->sdhci.slots[i]), TYPE_SYSBUS_SDHCI); } - sysbus_init_child_obj(obj, "emmc-controller", OBJECT(&s->emmc), + sysbus_init_child_obj(obj, "emmc-controller", &s->emmc, sizeof(s->emmc), TYPE_ASPEED_SDHCI); object_property_set_int(OBJECT(&s->emmc), 1, "num-slots", &error_abort); sysbus_init_child_obj(obj, "emmc-controller.sdhci", - OBJECT(&s->emmc.slots[0]), sizeof(s->emmc.slots[0]), + &s->emmc.slots[0], sizeof(s->emmc.slots[0]), TYPE_SYSBUS_SDHCI); } diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 18d1763aba..5806e5c9b4 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -146,8 +146,7 @@ static void aspeed_soc_init(Object *obj) } snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname); - sysbus_init_child_obj(obj, "scu", OBJECT(&s->scu), sizeof(s->scu), - typename); + sysbus_init_child_obj(obj, "scu", &s->scu, sizeof(s->scu), typename); qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev); object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), @@ -157,39 +156,36 @@ static void aspeed_soc_init(Object *obj) object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu), "hw-prot-key"); - sysbus_init_child_obj(obj, "vic", OBJECT(&s->vic), sizeof(s->vic), + sysbus_init_child_obj(obj, "vic", &s->vic, sizeof(s->vic), TYPE_ASPEED_VIC); - sysbus_init_child_obj(obj, "rtc", OBJECT(&s->rtc), sizeof(s->rtc), + sysbus_init_child_obj(obj, "rtc", &s->rtc, sizeof(s->rtc), TYPE_ASPEED_RTC); snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname); - sysbus_init_child_obj(obj, "timerctrl", OBJECT(&s->timerctrl), + sysbus_init_child_obj(obj, "timerctrl", &s->timerctrl, sizeof(s->timerctrl), typename); snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname); - sysbus_init_child_obj(obj, "i2c", OBJECT(&s->i2c), sizeof(s->i2c), - typename); + sysbus_init_child_obj(obj, "i2c", &s->i2c, sizeof(s->i2c), typename); snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname); - sysbus_init_child_obj(obj, "fmc", OBJECT(&s->fmc), sizeof(s->fmc), - typename); + sysbus_init_child_obj(obj, "fmc", &s->fmc, sizeof(s->fmc), typename); object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs"); for (i = 0; i < sc->spis_num; i++) { snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i + 1, socname); - sysbus_init_child_obj(obj, "spi[*]", OBJECT(&s->spi[i]), + sysbus_init_child_obj(obj, "spi[*]", &s->spi[i], sizeof(s->spi[i]), typename); } for (i = 0; i < sc->ehcis_num; i++) { - sysbus_init_child_obj(obj, "ehci[*]", OBJECT(&s->ehci[i]), + sysbus_init_child_obj(obj, "ehci[*]", &s->ehci[i], sizeof(s->ehci[i]), TYPE_PLATFORM_EHCI); } snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname); - sysbus_init_child_obj(obj, "sdmc", OBJECT(&s->sdmc), sizeof(s->sdmc), - typename); + sysbus_init_child_obj(obj, "sdmc", &s->sdmc, sizeof(s->sdmc), typename); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), "ram-size"); object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc), @@ -197,30 +193,29 @@ static void aspeed_soc_init(Object *obj) for (i = 0; i < sc->wdts_num; i++) { snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname); - sysbus_init_child_obj(obj, "wdt[*]", OBJECT(&s->wdt[i]), + sysbus_init_child_obj(obj, "wdt[*]", &s->wdt[i], sizeof(s->wdt[i]), typename); } for (i = 0; i < sc->macs_num; i++) { - sysbus_init_child_obj(obj, "ftgmac100[*]", OBJECT(&s->ftgmac100[i]), + sysbus_init_child_obj(obj, "ftgmac100[*]", &s->ftgmac100[i], sizeof(s->ftgmac100[i]), TYPE_FTGMAC100); } - sysbus_init_child_obj(obj, "xdma", OBJECT(&s->xdma), sizeof(s->xdma), + sysbus_init_child_obj(obj, "xdma", &s->xdma, sizeof(s->xdma), TYPE_ASPEED_XDMA); snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); - sysbus_init_child_obj(obj, "gpio", OBJECT(&s->gpio), sizeof(s->gpio), - typename); + sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio), typename); - sysbus_init_child_obj(obj, "sdc", OBJECT(&s->sdhci), sizeof(s->sdhci), + sysbus_init_child_obj(obj, "sdc", &s->sdhci, sizeof(s->sdhci), TYPE_ASPEED_SDHCI); object_property_set_int(OBJECT(&s->sdhci), 2, "num-slots", &error_abort); /* Init sd card slot class here so that they're under the correct parent */ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { - sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(&s->sdhci.slots[i]), + sysbus_init_child_obj(obj, "sdhci[*]", &s->sdhci.slots[i], sizeof(s->sdhci.slots[i]), TYPE_SYSBUS_SDHCI); } } diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index fe126581e4..c278827b09 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -189,7 +189,7 @@ static void nrf51_soc_init(Object *obj) memory_region_init(&s->container, obj, "nrf51-container", UINT64_MAX); - sysbus_init_child_obj(OBJECT(s), "armv6m", OBJECT(&s->cpu), sizeof(s->cpu), + sysbus_init_child_obj(OBJECT(s), "armv6m", &s->cpu, sizeof(s->cpu), TYPE_ARMV7M); qdev_prop_set_string(DEVICE(&s->cpu), "cpu-type", ARM_CPU_TYPE_NAME("cortex-m0")); diff --git a/hw/mips/boston.c b/hw/mips/boston.c index a34ccdf616..d90f3a463b 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -454,8 +454,8 @@ static void boston_mach_init(MachineState *machine) is_64b = cpu_supports_isa(machine->cpu_type, ISA_MIPS64); - sysbus_init_child_obj(OBJECT(machine), "cps", OBJECT(&s->cps), - sizeof(s->cps), TYPE_MIPS_CPS); + sysbus_init_child_obj(OBJECT(machine), "cps", &s->cps, sizeof(s->cps), + TYPE_MIPS_CPS); object_property_set_str(OBJECT(&s->cps), machine->cpu_type, "cpu-type", &error_fatal); object_property_set_int(OBJECT(&s->cps), machine->smp.cpus, "num-vp", diff --git a/hw/mips/malta.c b/hw/mips/malta.c index cfc236a1da..755e7ca40d 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -1183,7 +1183,7 @@ static void create_cpu_without_cps(MachineState *ms, static void create_cps(MachineState *ms, MaltaState *s, qemu_irq *cbus_irq, qemu_irq *i8259_irq) { - sysbus_init_child_obj(OBJECT(s), "cps", OBJECT(&s->cps), sizeof(s->cps), + sysbus_init_child_obj(OBJECT(s), "cps", &s->cps, sizeof(s->cps), TYPE_MIPS_CPS); object_property_set_str(OBJECT(&s->cps), ms->cpu_type, "cpu-type", &error_fatal); From b0d09949fe2e0d3ebe806356bf782894f5b8acc5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:29 +0200 Subject: [PATCH 1265/2595] microbit: Tidy up sysbus_init_child_obj() @child argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The callers of sysbus_init_child_obj() commonly pass either &child, sizeof(child), or pchild, sizeof(*pchild). Tidy up two that don't, mostly to keep future commits simpler. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-41-armbru@redhat.com> --- hw/arm/microbit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c index ef213695bd..72fab429c4 100644 --- a/hw/arm/microbit.c +++ b/hw/arm/microbit.c @@ -39,7 +39,7 @@ static void microbit_init(MachineState *machine) Object *soc = OBJECT(&s->nrf51); Object *i2c = OBJECT(&s->i2c); - sysbus_init_child_obj(OBJECT(machine), "nrf51", soc, sizeof(s->nrf51), + sysbus_init_child_obj(OBJECT(machine), "nrf51", &s->nrf51, sizeof(s->nrf51), TYPE_NRF51_SOC); qdev_prop_set_chr(DEVICE(&s->nrf51), "serial0", serial_hd(0)); object_property_set_link(soc, OBJECT(system_memory), "memory", @@ -51,7 +51,7 @@ static void microbit_init(MachineState *machine) * hack until we implement the nRF51 TWI controller properly and the * magnetometer/accelerometer devices. */ - sysbus_init_child_obj(OBJECT(machine), "microbit.twi", i2c, + sysbus_init_child_obj(OBJECT(machine), "microbit.twi", &s->i2c, sizeof(s->i2c), TYPE_MICROBIT_I2C); object_property_set_bool(i2c, true, "realized", &error_fatal); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(i2c), 0); From 8352a5b8ccdaeb3fc1b00550399abc375ae62d8b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:30 +0200 Subject: [PATCH 1266/2595] sysbus: Tidy up sysbus_init_child_obj()'s @childsize arg, part 1 The callers of sysbus_init_child_obj() commonly pass either &child, sizeof(child), or pchild, sizeof(*pchild). Tidy up the few that use sizeof(child_type) instead, mostly to keep future commits simpler. Coccinelle script: @@ expression parent, propname, type; type T; T child; @@ - sysbus_init_child_obj(parent, propname, &child, sizeof(T), type) + sysbus_init_child_obj(parent, propname, &child, sizeof(child), type) @@ expression parent, propname, type; type T; T *child; @@ - sysbus_init_child_obj(parent, propname, child, sizeof(T), type) + sysbus_init_child_obj(parent, propname, child, sizeof(*child), type) Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-42-armbru@redhat.com> --- hw/arm/bcm2835_peripherals.c | 3 +-- hw/arm/mps2-tz.c | 5 ++--- hw/arm/musca.c | 8 +++----- hw/display/sm501.c | 2 +- hw/microblaze/xlnx-zynqmp-pmu.c | 4 ++-- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index cca5b5ad04..188b112c13 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -27,8 +27,7 @@ static void create_unimp(BCM2835PeripheralState *ps, UnimplementedDeviceState *uds, const char *name, hwaddr ofs, hwaddr size) { - sysbus_init_child_obj(OBJECT(ps), name, uds, - sizeof(UnimplementedDeviceState), + sysbus_init_child_obj(OBJECT(ps), name, uds, sizeof(*uds), TYPE_UNIMPLEMENTED_DEVICE); qdev_prop_set_string(DEVICE(uds), "name", name); qdev_prop_set_uint64(DEVICE(uds), "size", size); diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 8a050228d0..ad0bc9365a 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -174,8 +174,7 @@ static MemoryRegion *make_unimp_dev(MPS2TZMachineState *mms, */ UnimplementedDeviceState *uds = opaque; - sysbus_init_child_obj(OBJECT(mms), name, uds, - sizeof(UnimplementedDeviceState), + sysbus_init_child_obj(OBJECT(mms), name, uds, sizeof(*uds), TYPE_UNIMPLEMENTED_DEVICE); qdev_prop_set_string(DEVICE(uds), "name", name); qdev_prop_set_uint64(DEVICE(uds), "size", size); @@ -552,7 +551,7 @@ static void mps2tz_common_init(MachineState *machine) char *gpioname; sysbus_init_child_obj(OBJECT(machine), ppcinfo->name, ppc, - sizeof(TZPPC), TYPE_TZ_PPC); + sizeof(*ppc), TYPE_TZ_PPC); ppcdev = DEVICE(ppc); for (port = 0; port < TZ_NUM_PORTS; port++) { diff --git a/hw/arm/musca.c b/hw/arm/musca.c index cd7df7c191..b7f1c4e128 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -142,8 +142,7 @@ static MemoryRegion *make_unimp_dev(MuscaMachineState *mms, */ UnimplementedDeviceState *uds = opaque; - sysbus_init_child_obj(OBJECT(mms), name, uds, - sizeof(UnimplementedDeviceState), + sysbus_init_child_obj(OBJECT(mms), name, uds, sizeof(*uds), TYPE_UNIMPLEMENTED_DEVICE); qdev_prop_set_string(DEVICE(uds), "name", name); qdev_prop_set_uint64(DEVICE(uds), "size", size); @@ -246,8 +245,7 @@ static MemoryRegion *make_mpc(MuscaMachineState *mms, void *opaque, case MPC_CRYPTOISLAND: /* We don't implement the CryptoIsland yet */ uds = &mms->cryptoisland; - sysbus_init_child_obj(OBJECT(mms), name, uds, - sizeof(UnimplementedDeviceState), + sysbus_init_child_obj(OBJECT(mms), name, uds, sizeof(*uds), TYPE_UNIMPLEMENTED_DEVICE); qdev_prop_set_string(DEVICE(uds), "name", mpcinfo[i].name); qdev_prop_set_uint64(DEVICE(uds), "size", mpcinfo[i].size); @@ -535,7 +533,7 @@ static void musca_init(MachineState *machine) char *gpioname; sysbus_init_child_obj(OBJECT(machine), ppcinfo->name, ppc, - sizeof(TZPPC), TYPE_TZ_PPC); + sizeof(*ppc), TYPE_TZ_PPC); ppcdev = DEVICE(ppc); for (port = 0; port < TZ_NUM_PORTS; port++) { diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 3e62eca3de..ccdbce1a06 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -2023,7 +2023,7 @@ static void sm501_sysbus_init(Object *o) SM501SysBusState *sm501 = SYSBUS_SM501(o); SerialMM *smm = &sm501->serial; - sysbus_init_child_obj(o, "serial", smm, sizeof(SerialMM), TYPE_SERIAL_MM); + sysbus_init_child_obj(o, "serial", smm, sizeof(*smm), TYPE_SERIAL_MM); qdev_set_legacy_instance_id(DEVICE(smm), SM501_UART0, 2); qdev_prop_set_uint8(DEVICE(smm), "regshift", 2); qdev_prop_set_uint8(DEVICE(smm), "endianness", DEVICE_LITTLE_ENDIAN); diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index bd56eccd66..30ad133ec3 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -69,8 +69,8 @@ static void xlnx_zynqmp_pmu_soc_init(Object *obj) /* Create the IPI device */ for (int i = 0; i < XLNX_ZYNQMP_PMU_NUM_IPIS; i++) { char *name = g_strdup_printf("ipi%d", i); - sysbus_init_child_obj(obj, name, &s->ipi[i], - sizeof(XlnxZynqMPIPI), TYPE_XLNX_ZYNQMP_IPI); + sysbus_init_child_obj(obj, name, &s->ipi[i], sizeof(s->ipi[i]), + TYPE_XLNX_ZYNQMP_IPI); g_free(name); } } From 287f43196d1008b1f85d7a33593789381dde2d4b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:31 +0200 Subject: [PATCH 1267/2595] hw/arm/armsse: Pass correct child size to sysbus_init_child_obj() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit armsse_init() initializes s->armv7m[i] for all i. It passes the size of the entire array instead of the array element to sysbus_init_child_obj(). Harmless, but fix it anyway. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-43-armbru@redhat.com> --- hw/arm/armsse.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index c903e725f7..f042145e6e 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -257,7 +257,8 @@ static void armsse_init(Object *obj) name = g_strdup_printf("armv7m%d", i); sysbus_init_child_obj(OBJECT(&s->cluster[i]), name, - &s->armv7m[i], sizeof(s->armv7m), TYPE_ARMV7M); + &s->armv7m[i], sizeof(s->armv7m[i]), + TYPE_ARMV7M); qdev_prop_set_string(DEVICE(&s->armv7m[i]), "cpu-type", ARM_CPU_TYPE_NAME("cortex-m33")); g_free(name); From b45ad78889461fdf9aa98493a9b49612a8e79833 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:32 +0200 Subject: [PATCH 1268/2595] sysbus: Tidy up sysbus_init_child_obj()'s @childsize arg, part 2 The callers of sysbus_init_child_obj() commonly pass either &child, sizeof(child), or pchild, sizeof(*pchild). Tidy up the few that use something else instead, mostly to keep future commits simpler. Coccinelle script: @@ expression parent, propname, type; expression child; type T; T proxy; @@ ( sysbus_init_child_obj(parent, propname, &child, sizeof(child), type) | sysbus_init_child_obj(parent, propname, child, sizeof(*child), type) | - sysbus_init_child_obj(parent, propname, child, sizeof(proxy), type) + sysbus_init_child_obj(parent, propname, child, sizeof(*child), type) ) This script is *unsound*: for each change we need to verify the @childsize argument stays the same. I did. Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-44-armbru@redhat.com> --- hw/arm/mps2-tz.c | 15 +++++++-------- hw/arm/musca.c | 7 +++---- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index ad0bc9365a..90f4449b9d 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -193,7 +193,7 @@ static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque, SysBusDevice *s; DeviceState *orgate_dev = DEVICE(&mms->uart_irq_orgate); - sysbus_init_child_obj(OBJECT(mms), name, uart, sizeof(mms->uart[0]), + sysbus_init_child_obj(OBJECT(mms), name, uart, sizeof(*uart), TYPE_CMSDK_APB_UART); qdev_prop_set_chr(DEVICE(uart), "chardev", serial_hd(i)); qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", SYSCLK_FRQ); @@ -214,8 +214,8 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque, DeviceState *sccdev; MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); - sysbus_init_child_obj(OBJECT(mms), "scc", scc, - sizeof(mms->scc), TYPE_MPS2_SCC); + sysbus_init_child_obj(OBJECT(mms), "scc", scc, sizeof(*scc), + TYPE_MPS2_SCC); sccdev = DEVICE(scc); qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008); @@ -229,8 +229,8 @@ static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque, { MPS2FPGAIO *fpgaio = opaque; - sysbus_init_child_obj(OBJECT(mms), "fpgaio", fpgaio, - sizeof(mms->fpgaio), TYPE_MPS2_FPGAIO); + sysbus_init_child_obj(OBJECT(mms), "fpgaio", fpgaio, sizeof(*fpgaio), + TYPE_MPS2_FPGAIO); object_property_set_bool(OBJECT(fpgaio), true, "realized", &error_fatal); return sysbus_mmio_get_region(SYS_BUS_DEVICE(fpgaio), 0); } @@ -267,7 +267,7 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque, memory_region_init_ram(ssram, NULL, name, ramsize[i], &error_fatal); - sysbus_init_child_obj(OBJECT(mms), mpcname, mpc, sizeof(mms->ssram_mpc[0]), + sysbus_init_child_obj(OBJECT(mms), mpcname, mpc, sizeof(*mpc), TYPE_TZ_MPC); object_property_set_link(OBJECT(mpc), OBJECT(ssram), "downstream", &error_fatal); @@ -363,8 +363,7 @@ static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque, int i = spi - &mms->spi[0]; SysBusDevice *s; - sysbus_init_child_obj(OBJECT(mms), name, spi, sizeof(mms->spi[0]), - TYPE_PL022); + sysbus_init_child_obj(OBJECT(mms), name, spi, sizeof(*spi), TYPE_PL022); object_property_set_bool(OBJECT(spi), true, "realized", &error_fatal); s = SYS_BUS_DEVICE(spi); sysbus_connect_irq(s, 0, get_sse_irq_in(mms, 51 + i)); diff --git a/hw/arm/musca.c b/hw/arm/musca.c index b7f1c4e128..a1a6e887ed 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -256,7 +256,7 @@ static MemoryRegion *make_mpc(MuscaMachineState *mms, void *opaque, g_assert_not_reached(); } - sysbus_init_child_obj(OBJECT(mms), mpcname, mpc, sizeof(mms->mpc[0]), + sysbus_init_child_obj(OBJECT(mms), mpcname, mpc, sizeof(*mpc), TYPE_TZ_MPC); object_property_set_link(OBJECT(mpc), OBJECT(downstream), "downstream", &error_fatal); @@ -279,7 +279,7 @@ static MemoryRegion *make_rtc(MuscaMachineState *mms, void *opaque, { PL031State *rtc = opaque; - sysbus_init_child_obj(OBJECT(mms), name, rtc, sizeof(mms->rtc), TYPE_PL031); + sysbus_init_child_obj(OBJECT(mms), name, rtc, sizeof(*rtc), TYPE_PL031); object_property_set_bool(OBJECT(rtc), true, "realized", &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(rtc), 0, get_sse_irq_in(mms, 39)); return sysbus_mmio_get_region(SYS_BUS_DEVICE(rtc), 0); @@ -293,8 +293,7 @@ static MemoryRegion *make_uart(MuscaMachineState *mms, void *opaque, int irqbase = 7 + i * 6; SysBusDevice *s; - sysbus_init_child_obj(OBJECT(mms), name, uart, sizeof(mms->uart[0]), - TYPE_PL011); + sysbus_init_child_obj(OBJECT(mms), name, uart, sizeof(*uart), TYPE_PL011); qdev_prop_set_chr(DEVICE(uart), "chardev", serial_hd(i)); object_property_set_bool(OBJECT(uart), true, "realized", &error_fatal); s = SYS_BUS_DEVICE(uart); From 496a8525622d4ac5d276f76840dd30eddb73672d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:33 +0200 Subject: [PATCH 1269/2595] sysbus: New sysbus_realize(), sysbus_realize_and_unref() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sysbus devices almost always plug into the main system bus. qdev_create() even has a convenience feature to make that easy: a null bus argument gets replaced by the main system bus. qdev_realize() and qdev_realize_and_unref() do the same. We can do better. Provide convenience wrappers around qdev_realize() and qdev_realize_and_unref() that don't take a @bus argument. They always pass the main system bus. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-45-armbru@redhat.com> --- hw/core/sysbus.c | 14 ++++++++++++-- include/hw/sysbus.h | 4 +++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index e8d08d349b..68b837ac85 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -217,7 +217,7 @@ void sysbus_init_ioports(SysBusDevice *dev, uint32_t ioport, uint32_t size) * from being set to NULL to break the normal init/realize * of some devices. */ -static void sysbus_realize(DeviceState *dev, Error **errp) +static void sysbus_device_realize(DeviceState *dev, Error **errp) { } @@ -250,6 +250,16 @@ DeviceState *sysbus_create_varargs(const char *name, return dev; } +bool sysbus_realize(SysBusDevice *dev, Error **errp) +{ + return qdev_realize(DEVICE(dev), sysbus_get_default(), errp); +} + +bool sysbus_realize_and_unref(SysBusDevice *dev, Error **errp) +{ + return qdev_realize_and_unref(DEVICE(dev), sysbus_get_default(), errp); +} + static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) { SysBusDevice *s = SYS_BUS_DEVICE(dev); @@ -301,7 +311,7 @@ MemoryRegion *sysbus_address_space(SysBusDevice *dev) static void sysbus_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); - k->realize = sysbus_realize; + k->realize = sysbus_device_realize; k->bus_type = TYPE_SYSTEM_BUS; /* * device_add plugs devices into a suitable bus. For "real" buses, diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h index c4a1c0adfa..606095ba35 100644 --- a/include/hw/sysbus.h +++ b/include/hw/sysbus.h @@ -90,6 +90,9 @@ void sysbus_add_io(SysBusDevice *dev, hwaddr addr, MemoryRegion *mem); MemoryRegion *sysbus_address_space(SysBusDevice *dev); +bool sysbus_realize(SysBusDevice *dev, Error **errp); +bool sysbus_realize_and_unref(SysBusDevice *dev, Error **errp); + /** * sysbus_init_child_obj: * @parent: The parent object @@ -121,5 +124,4 @@ static inline DeviceState *sysbus_create_simple(const char *name, return sysbus_create_varargs(name, addr, irq, NULL); } - #endif /* HW_SYSBUS_H */ From 3c6ef471ee67bf5a22a9e0ecfdc45ca7d2393216 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:34 +0200 Subject: [PATCH 1270/2595] sysbus: Convert to sysbus_realize() etc. with Coccinelle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert from qdev_realize(), qdev_realize_and_unref() with null @bus argument to sysbus_realize(), sysbus_realize_and_unref(). Coccinelle script: @@ expression dev, errp; @@ - qdev_realize(DEVICE(dev), NULL, errp); + sysbus_realize(SYS_BUS_DEVICE(dev), errp); @@ expression sysbus_dev, dev, errp; @@ + sysbus_dev = SYS_BUS_DEVICE(dev); - qdev_realize_and_unref(dev, NULL, errp); + sysbus_realize_and_unref(sysbus_dev, errp); - sysbus_dev = SYS_BUS_DEVICE(dev); @@ expression sysbus_dev, dev, errp; expression expr; @@ sysbus_dev = SYS_BUS_DEVICE(dev); ... when != dev = expr; - qdev_realize_and_unref(dev, NULL, errp); + sysbus_realize_and_unref(sysbus_dev, errp); @@ expression dev, errp; @@ - qdev_realize_and_unref(DEVICE(dev), NULL, errp); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp); @@ expression dev, errp; @@ - qdev_realize_and_unref(dev, NULL, errp); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp); Whitespace changes minimized manually. Signed-off-by: Markus Armbruster Acked-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-46-armbru@redhat.com> [Conflicts in hw/misc/empty_slot.c and hw/sparc/leon3.c resolved] --- hw/alpha/typhoon.c | 2 +- hw/arm/exynos4210.c | 18 ++++++------- hw/arm/exynos4_boards.c | 2 +- hw/arm/highbank.c | 12 ++++----- hw/arm/integratorcp.c | 2 +- hw/arm/mps2-tz.c | 2 +- hw/arm/msf2-som.c | 2 +- hw/arm/musicpal.c | 4 +-- hw/arm/netduino2.c | 2 +- hw/arm/netduinoplus2.c | 2 +- hw/arm/nseries.c | 4 +-- hw/arm/omap1.c | 8 +++--- hw/arm/omap2.c | 8 +++--- hw/arm/pxa2xx.c | 4 +-- hw/arm/pxa2xx_gpio.c | 2 +- hw/arm/pxa2xx_pic.c | 2 +- hw/arm/realview.c | 10 ++++---- hw/arm/sbsa-ref.c | 12 ++++----- hw/arm/spitz.c | 2 +- hw/arm/stellaris.c | 6 ++--- hw/arm/strongarm.c | 4 +-- hw/arm/versatilepb.c | 8 +++--- hw/arm/vexpress.c | 8 +++--- hw/arm/virt.c | 18 ++++++------- hw/arm/xilinx_zynq.c | 16 ++++++------ hw/arm/xlnx-versal-virt.c | 2 +- hw/arm/xlnx-versal.c | 2 +- hw/block/fdc.c | 4 +-- hw/block/pflash_cfi01.c | 2 +- hw/block/pflash_cfi02.c | 2 +- hw/char/exynos4210_uart.c | 2 +- hw/char/mcf_uart.c | 2 +- hw/char/serial.c | 2 +- hw/core/sysbus.c | 2 +- hw/cris/axis_dev88.c | 2 +- hw/display/milkymist-tmu2.c | 2 +- hw/display/sm501.c | 2 +- hw/dma/pxa2xx_dma.c | 4 +-- hw/dma/rc4030.c | 2 +- hw/dma/sparc32_dma.c | 8 +++--- hw/hppa/dino.c | 2 +- hw/hppa/lasi.c | 2 +- hw/hppa/machine.c | 2 +- hw/i386/pc.c | 2 +- hw/i386/pc_q35.c | 2 +- hw/i386/pc_sysfw.c | 2 +- hw/i386/x86.c | 2 +- hw/intc/exynos4210_gic.c | 2 +- hw/intc/s390_flic.c | 2 +- hw/isa/isa-bus.c | 2 +- hw/lm32/lm32.h | 6 ++--- hw/lm32/milkymist-hw.h | 18 ++++++------- hw/m68k/mcf5208.c | 2 +- hw/m68k/mcf_intc.c | 2 +- hw/m68k/next-cube.c | 6 ++--- hw/m68k/q800.c | 12 ++++----- hw/microblaze/petalogix_ml605_mmu.c | 10 ++++---- hw/microblaze/petalogix_s3adsp1800_mmu.c | 6 ++--- hw/mips/boston.c | 4 +-- hw/mips/gt64xxx_pci.c | 2 +- hw/mips/jazz.c | 8 +++--- hw/mips/malta.c | 2 +- hw/mips/mipssim.c | 4 +-- hw/misc/empty_slot.c | 2 +- hw/net/etraxfs_eth.c | 2 +- hw/net/fsl_etsec/etsec.c | 2 +- hw/net/lan9118.c | 2 +- hw/net/lasi_i82596.c | 2 +- hw/net/smc91c111.c | 2 +- hw/nios2/10m50_devboard.c | 6 ++--- hw/nvram/fw_cfg.c | 4 +-- hw/openrisc/openrisc_sim.c | 4 +-- hw/pci-bridge/pci_expander_bridge.c | 2 +- hw/pci-host/bonito.c | 2 +- hw/pci-host/i440fx.c | 2 +- hw/pcmcia/pxa2xx.c | 2 +- hw/ppc/e500.c | 16 ++++++------ hw/ppc/mac_newworld.c | 16 ++++++------ hw/ppc/mac_oldworld.c | 6 ++--- hw/ppc/pnv.c | 8 +++--- hw/ppc/ppc440_uc.c | 4 +-- hw/ppc/prep.c | 4 +-- hw/ppc/sam460ex.c | 2 +- hw/ppc/spapr.c | 2 +- hw/ppc/spapr_irq.c | 2 +- hw/ppc/spapr_vio.c | 2 +- hw/ppc/virtex_ml507.c | 4 +-- hw/riscv/sifive_clint.c | 2 +- hw/riscv/sifive_e_prci.c | 2 +- hw/riscv/sifive_plic.c | 2 +- hw/riscv/sifive_test.c | 2 +- hw/riscv/virt.c | 4 +-- hw/rtc/m48t59.c | 2 +- hw/rtc/sun4v-rtc.c | 2 +- hw/s390x/ap-bridge.c | 2 +- hw/s390x/css-bridge.c | 2 +- hw/s390x/s390-virtio-ccw.c | 2 +- hw/s390x/sclp.c | 2 +- hw/sd/pxa2xx_mmci.c | 2 +- hw/sh4/r2d.c | 6 ++--- hw/sparc/leon3.c | 10 ++++---- hw/sparc/sun4m.c | 32 ++++++++++++------------ hw/sparc64/sun4u.c | 12 ++++----- hw/xen/xen-bus.c | 2 +- hw/xen/xen-legacy-backend.c | 2 +- hw/xtensa/virt.c | 2 +- hw/xtensa/xtfpga.c | 4 +-- include/hw/char/cadence_uart.h | 2 +- include/hw/char/cmsdk-apb-uart.h | 2 +- include/hw/char/pl011.h | 4 +-- include/hw/char/xilinx_uartlite.h | 2 +- include/hw/cris/etraxfs.h | 2 +- include/hw/misc/unimp.h | 2 +- include/hw/timer/cmsdk-apb-timer.h | 2 +- 114 files changed, 257 insertions(+), 257 deletions(-) diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index 480d866c77..29d44dfb06 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -889,7 +889,7 @@ PCIBus *typhoon_init(MemoryRegion *ram, ISABus **isa_bus, qemu_irq *p_rtc_irq, &s->pchip.reg_mem, &s->pchip.reg_io, 0, 64, TYPE_PCI_BUS); phb->bus = b; - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Host memory as seen from the PCI side, via the IOMMU. */ memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu), diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index 86cbd63857..2afeb73776 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -184,8 +184,8 @@ static DeviceState *pl330_create(uint32_t base, qemu_or_irq *orgate, qdev_prop_set_uint8(dev, "rd_q_dep", 8); qdev_prop_set_uint8(dev, "data_width", width); qdev_prop_set_uint16(dev, "data_buffer_dep", width); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, base); object_property_set_int(OBJECT(orgate), nevents + 1, "num-lines", @@ -234,7 +234,7 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) for (i = 0; i < EXYNOS4210_NCPUS; i++) { dev = qdev_new("exynos4210.irq_gate"); qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Get IRQ Gate input in gate_irq */ for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) { gate_irq[i][n] = qdev_get_gpio_in(dev, n); @@ -249,8 +249,8 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) /* Private memory region and Internal GIC */ dev = qdev_new(TYPE_A9MPCORE_PRIV); qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR); for (n = 0; n < EXYNOS4210_NCPUS; n++) { sysbus_connect_irq(busdev, n, gate_irq[n][0]); @@ -265,8 +265,8 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) /* External GIC */ dev = qdev_new("exynos4210.gic"); qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); /* Map CPU interface */ sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR); /* Map Distributer interface */ @@ -280,8 +280,8 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) /* Internal Interrupt Combiner */ dev = qdev_new("exynos4210.combiner"); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]); } @@ -291,8 +291,8 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) /* External Interrupt Combiner */ dev = qdev_new("exynos4210.combiner"); qdev_prop_set_uint32(dev, "external", 1); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]); } @@ -354,8 +354,8 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) /* Multi Core Timer */ dev = qdev_new("exynos4210.mct"); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); for (n = 0; n < 4; n++) { /* Connect global timer interrupts to Combiner gpio_in */ sysbus_connect_irq(busdev, n, @@ -380,8 +380,8 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) } dev = qdev_new("exynos4210.i2c"); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, i2c_irq); sysbus_mmio_map(busdev, 0, addr); s->i2c_if[n] = (I2CBus *)qdev_get_child_bus(dev, "i2c"); @@ -425,9 +425,9 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) */ dev = qdev_new(TYPE_S3C_SDHCI); qdev_prop_set_uint64(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, EXYNOS4210_SDHCI_ADDR(n)); sysbus_connect_irq(busdev, 0, s->irq_table[exynos4210_get_irq(29, n)]); diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index d4fe9c6128..326122abff 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -84,8 +84,8 @@ static void lan9215_init(uint32_t base, qemu_irq irq) dev = qdev_new(TYPE_LAN9118); qdev_set_nic_properties(dev, &nd_table[0]); qdev_prop_set_uint32(dev, "mode_16bit", 1); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); } diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 1bed540011..7f279d7f93 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -312,8 +312,8 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) switch (machine_id) { case CALXEDA_HIGHBANK: dev = qdev_new("l2x0"); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, 0xfff12000); dev = qdev_new(TYPE_A9MPCORE_PRIV); @@ -324,8 +324,8 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) } qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE); for (n = 0; n < smp_cpus; n++) { sysbus_connect_irq(busdev, n, cpu_irq[n]); @@ -341,15 +341,15 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) dev = qdev_new("sp804"); qdev_prop_set_uint32(dev, "freq0", 150000000); qdev_prop_set_uint32(dev, "freq1", 150000000); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, 0xfff34000); sysbus_connect_irq(busdev, 0, pic[18]); pl011_create(0xfff36000, pic[20], serial_hd(0)); dev = qdev_new(TYPE_HIGHBANK_REGISTERS); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, 0xfff3c000); sysbus_create_simple("pl061", 0xfff30000, pic[14]); @@ -365,7 +365,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) qemu_check_nic_model(&nd_table[0], "xgmac"); dev = qdev_new("xgmac"); qdev_set_nic_properties(dev, &nd_table[0]); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff50000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[77]); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[78]); @@ -374,7 +374,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) qemu_check_nic_model(&nd_table[1], "xgmac"); dev = qdev_new("xgmac"); qdev_set_nic_properties(dev, &nd_table[1]); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff51000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[80]); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[81]); diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index 45698307f1..a55d2c31e3 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -622,7 +622,7 @@ static void integratorcp_init(MachineState *machine) dev = qdev_new(TYPE_INTEGRATOR_CM); qdev_prop_set_uint32(dev, "memsz", ram_size >> 20); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000); dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000, diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 90f4449b9d..4c49512e0b 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -247,9 +247,9 @@ static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque, qemu_check_nic_model(nd, "lan9118"); mms->lan9118 = qdev_new(TYPE_LAN9118); qdev_set_nic_properties(mms->lan9118, nd); - qdev_realize_and_unref(mms->lan9118, NULL, &error_fatal); s = SYS_BUS_DEVICE(mms->lan9118); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, get_sse_irq_in(mms, 16)); return sysbus_mmio_get_region(s, 0); } diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c index ca9cbe1acb..355966c073 100644 --- a/hw/arm/msf2-som.c +++ b/hw/arm/msf2-som.c @@ -77,7 +77,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine) qdev_prop_set_uint32(dev, "apb0div", 2); qdev_prop_set_uint32(dev, "apb1div", 2); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); soc = MSF2_SOC(dev); diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index d03351e5fa..394a3345bd 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -1653,7 +1653,7 @@ static void musicpal_init(MachineState *machine) qemu_check_nic_model(&nd_table[0], "mv88w8618"); dev = qdev_new(TYPE_MV88W8618_ETH); qdev_set_nic_properties(dev, &nd_table[0]); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]); @@ -1692,7 +1692,7 @@ static void musicpal_init(MachineState *machine) s = SYS_BUS_DEVICE(dev); object_property_set_link(OBJECT(dev), OBJECT(wm8750_dev), "wm8750", NULL); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, MP_AUDIO_BASE); sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]); diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c index 6bd8e4e197..79e19392b5 100644 --- a/hw/arm/netduino2.c +++ b/hw/arm/netduino2.c @@ -36,7 +36,7 @@ static void netduino2_init(MachineState *machine) dev = qdev_new(TYPE_STM32F205_SOC); qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3")); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, FLASH_SIZE); diff --git a/hw/arm/netduinoplus2.c b/hw/arm/netduinoplus2.c index 8d4b3d7c43..958d21dd9f 100644 --- a/hw/arm/netduinoplus2.c +++ b/hw/arm/netduinoplus2.c @@ -36,7 +36,7 @@ static void netduinoplus2_init(MachineState *machine) dev = qdev_new(TYPE_STM32F405_SOC); qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4")); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index 856fa565a4..02678dda2d 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -185,7 +185,7 @@ static void n8x0_nand_setup(struct n800_s *s) qdev_prop_set_drive(s->nand, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } - qdev_realize_and_unref(s->nand, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(s->nand), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0, qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO)); omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS, @@ -804,7 +804,7 @@ static void n8x0_usb_setup(struct n800_s *s) SysBusDevice *dev; s->usb = qdev_new("tusb6010"); dev = SYS_BUS_DEVICE(s->usb); - qdev_realize_and_unref(s->usb, NULL, &error_fatal); + sysbus_realize_and_unref(dev, &error_fatal); sysbus_connect_irq(dev, 0, qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO)); /* Using the NOR interface */ diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index c11d6da9d5..6ba0df6b6d 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -3890,8 +3890,8 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram, s->ih[0] = qdev_new("omap-intc"); qdev_prop_set_uint32(s->ih[0], "size", 0x100); omap_intc_set_iclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "arminth_ck")); - qdev_realize_and_unref(s->ih[0], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->ih[0]); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); sysbus_connect_irq(busdev, 1, @@ -3900,8 +3900,8 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram, s->ih[1] = qdev_new("omap-intc"); qdev_prop_set_uint32(s->ih[1], "size", 0x800); omap_intc_set_iclk(OMAP_INTC(s->ih[1]), omap_findclk(s, "arminth_ck")); - qdev_realize_and_unref(s->ih[1], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->ih[1]); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_15XX_IH2_IRQ)); /* The second interrupt controller's FIQ output is not wired up */ @@ -4013,7 +4013,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram, s->gpio = qdev_new("omap-gpio"); qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model); omap_gpio_set_clk(OMAP1_GPIO(s->gpio), omap_findclk(s, "arm_gpio_ck")); - qdev_realize_and_unref(s->gpio, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(s->gpio), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(s->gpio), 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1)); sysbus_mmio_map(SYS_BUS_DEVICE(s->gpio), 0, 0xfffce000); @@ -4031,8 +4031,8 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram, s->i2c[0] = qdev_new("omap_i2c"); qdev_prop_set_uint8(s->i2c[0], "revision", 0x11); omap_i2c_set_fclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "mpuper_ck")); - qdev_realize_and_unref(s->i2c[0], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->i2c[0]); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C)); sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_I2C_TX]); sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_I2C_RX]); diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index b45ed5c9ec..16d388fc79 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -2310,8 +2310,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram, qdev_prop_set_uint8(s->ih[0], "revision", 0x21); omap_intc_set_fclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "mpu_intc_fclk")); omap_intc_set_iclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "mpu_intc_iclk")); - qdev_realize_and_unref(s->ih[0], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->ih[0]); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); sysbus_connect_irq(busdev, 1, @@ -2427,8 +2427,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram, qdev_prop_set_uint8(s->i2c[0], "revision", 0x34); omap_i2c_set_iclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "i2c1.iclk")); omap_i2c_set_fclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "i2c1.fclk")); - qdev_realize_and_unref(s->i2c[0], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->i2c[0]); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ)); sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C1_TX]); @@ -2439,8 +2439,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram, qdev_prop_set_uint8(s->i2c[1], "revision", 0x34); omap_i2c_set_iclk(OMAP_I2C(s->i2c[1]), omap_findclk(s, "i2c2.iclk")); omap_i2c_set_fclk(OMAP_I2C(s->i2c[1]), omap_findclk(s, "i2c2.fclk")); - qdev_realize_and_unref(s->i2c[1], NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->i2c[1]); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ)); sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C2_TX]); @@ -2458,8 +2458,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram, omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 4, omap_findclk(s, "gpio5_dbclk")); } - qdev_realize_and_unref(s->gpio, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(s->gpio); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1)); sysbus_connect_irq(busdev, 3, diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index e21ba1af3e..f104a33463 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1513,9 +1513,9 @@ PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, dev = qdev_new(TYPE_PXA2XX_I2C); qdev_prop_set_uint32(dev, "size", region_size + 1); qdev_prop_set_uint32(dev, "offset", base & region_size); - qdev_realize_and_unref(dev, NULL, &error_fatal); i2c_dev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(i2c_dev, &error_fatal); sysbus_mmio_map(i2c_dev, 0, base & ~region_size); sysbus_connect_irq(i2c_dev, 0, irq); @@ -2075,8 +2075,8 @@ static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, dev = qdev_new(TYPE_PXA2XX_FIR); qdev_prop_set_chr(dev, "chardev", chr); - qdev_realize_and_unref(dev, NULL, &error_fatal); sbd = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sbd, &error_fatal); sysbus_mmio_map(sbd, 0, base); sysbus_connect_irq(sbd, 0, irq); sysbus_connect_irq(sbd, 1, rx_dma); diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c index 27199af43c..d6d0d0b08e 100644 --- a/hw/arm/pxa2xx_gpio.c +++ b/hw/arm/pxa2xx_gpio.c @@ -273,7 +273,7 @@ DeviceState *pxa2xx_gpio_init(hwaddr base, dev = qdev_new(TYPE_PXA2XX_GPIO); qdev_prop_set_int32(dev, "lines", lines); qdev_prop_set_int32(dev, "ncpu", cs->cpu_index); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index 4c451cf540..105c5e63f2 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -280,7 +280,7 @@ DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) s->is_fiq[0] = 0; s->is_fiq[1] = 0; - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); qdev_init_gpio_in(dev, pxa2xx_pic_set_irq, PXA2XX_PIC_SRCS); diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 128146448c..aee7989037 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -164,14 +164,14 @@ static void realview_init(MachineState *machine, sysctl = qdev_new("realview_sysctl"); qdev_prop_set_uint32(sysctl, "sys_id", sys_id); qdev_prop_set_uint32(sysctl, "proc_id", proc_id); - qdev_realize_and_unref(sysctl, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(sysctl), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); if (is_mpcore) { dev = qdev_new(is_pb ? TYPE_A9MPCORE_PRIV : "realview_mpcore"); qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, periphbase); for (n = 0; n < smp_cpus; n++) { sysbus_connect_irq(busdev, n, cpu_irq[n]); @@ -190,7 +190,7 @@ static void realview_init(MachineState *machine, pl041 = qdev_new("pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_realize_and_unref(pl041, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(pl041), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[19]); @@ -206,8 +206,8 @@ static void realview_init(MachineState *machine, dev = qdev_new("pl081"); object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream", &error_fatal); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, 0x10030000); sysbus_connect_irq(busdev, 0, pic[24]); @@ -241,7 +241,7 @@ static void realview_init(MachineState *machine, if (!is_pb) { dev = qdev_new("realview_pci"); busdev = SYS_BUS_DEVICE(dev); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, 0x10019000); /* PCI controller registers */ sysbus_mmio_map(busdev, 1, 0x60000000); /* PCI self-config */ sysbus_mmio_map(busdev, 2, 0x61000000); /* PCI config */ diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index fe24567333..3fd3536796 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -243,7 +243,7 @@ static void sbsa_flash_map1(PFlashCFI01 *flash, assert(QEMU_IS_ALIGNED(size, SBSA_FLASH_SECTOR_SIZE)); assert(size / SBSA_FLASH_SECTOR_SIZE <= UINT32_MAX); qdev_prop_set_uint32(dev, "num-blocks", size / SBSA_FLASH_SECTOR_SIZE); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); memory_region_add_subregion(sysmem, base, sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), @@ -356,8 +356,8 @@ static void create_gic(SBSAMachineState *sms) qdev_prop_set_uint32(sms->gic, "len-redist-region-count", 1); qdev_prop_set_uint32(sms->gic, "redist-region-count[0]", redist0_count); - qdev_realize_and_unref(sms->gic, NULL, &error_fatal); gicbusdev = SYS_BUS_DEVICE(sms->gic); + sysbus_realize_and_unref(gicbusdev, &error_fatal); sysbus_mmio_map(gicbusdev, 0, sbsa_ref_memmap[SBSA_GIC_DIST].base); sysbus_mmio_map(gicbusdev, 1, sbsa_ref_memmap[SBSA_GIC_REDIST].base); @@ -413,7 +413,7 @@ static void create_uart(const SBSAMachineState *sms, int uart, SysBusDevice *s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); sysbus_connect_irq(s, 0, qdev_get_gpio_in(sms->gic, irq)); @@ -466,7 +466,7 @@ static void create_ahci(const SBSAMachineState *sms) dev = qdev_new("sysbus-ahci"); qdev_prop_set_uint32(dev, "num-ports", NUM_SATA_PORTS); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(sms->gic, irq)); @@ -501,7 +501,7 @@ static void create_smmu(const SBSAMachineState *sms, PCIBus *bus) object_property_set_link(OBJECT(dev), OBJECT(bus), "primary-bus", &error_abort); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); for (i = 0; i < NUM_SMMU_IRQS; i++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, @@ -526,7 +526,7 @@ static void create_pcie(SBSAMachineState *sms) int i; dev = qdev_new(TYPE_GPEX_HOST); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Map ECAM space */ ecam_alias = g_new0(MemoryRegion, 1); diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index edae6bf8be..fc18212e68 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -163,7 +163,7 @@ static void sl_flash_register(PXA2xxState *cpu, int size) else if (size == FLASH_1024M) qdev_prop_set_uint8(dev, "chip_id", 0xf1); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE); } diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index f824cbd498..97ef566c12 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -1315,7 +1315,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) object_property_set_link(OBJECT(nvic), OBJECT(get_system_memory()), "memory", &error_abort); /* This will exit with an error if the user passed us a bad cpu_type */ - qdev_realize_and_unref(nvic, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(nvic), &error_fatal); qdev_connect_gpio_out_named(nvic, "SYSRESETREQ", 0, qemu_allocate_irq(&do_sys_reset, NULL, 0)); @@ -1353,7 +1353,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) uint32_t mainclk = NANOSECONDS_PER_SECOND / system_clock_scale; qdev_prop_set_uint32(dev, "wdogclk-frq", mainclk); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x40000000u); @@ -1427,7 +1427,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) enet = qdev_new("stellaris_enet"); qdev_set_nic_properties(enet, &nd_table[0]); - qdev_realize_and_unref(enet, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(enet), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000); sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, qdev_get_gpio_in(nvic, 42)); } diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index 108ed8d147..2639b9ae55 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -646,7 +646,7 @@ static DeviceState *strongarm_gpio_init(hwaddr base, int i; dev = qdev_new(TYPE_STRONGARM_GPIO); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); for (i = 0; i < 12; i++) @@ -1629,7 +1629,7 @@ StrongARMState *sa1110_init(const char *cpu_type) for (i = 0; sa_serial[i].io_base; i++) { DeviceState *dev = qdev_new(TYPE_STRONGARM_UART); qdev_prop_set_chr(dev, "chardev", serial_hd(i)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, sa_serial[i].io_base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 154fa72f33..29e3bc6bd0 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -226,7 +226,7 @@ static void versatile_init(MachineState *machine, int board_id) sysctl = qdev_new("realview_sysctl"); qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004); qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000); - qdev_realize_and_unref(sysctl, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(sysctl), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); dev = sysbus_create_varargs("pl190", 0x10140000, @@ -247,7 +247,7 @@ static void versatile_init(MachineState *machine, int board_id) dev = qdev_new("versatile_pci"); busdev = SYS_BUS_DEVICE(dev); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, 0x10001000); /* PCI controller regs */ sysbus_mmio_map(busdev, 1, 0x41000000); /* PCI self-config */ sysbus_mmio_map(busdev, 2, 0x42000000); /* PCI config */ @@ -289,8 +289,8 @@ static void versatile_init(MachineState *machine, int board_id) dev = qdev_new("pl080"); object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream", &error_fatal); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, 0x10130000); sysbus_connect_irq(busdev, 0, pic[17]); @@ -321,7 +321,7 @@ static void versatile_init(MachineState *machine, int board_id) /* Add PL041 AACI Interface to the LM4549 codec */ pl041 = qdev_new("pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_realize_and_unref(pl041, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(pl041), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index ef29e9f5ae..bebb0ed5a4 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -238,8 +238,8 @@ static void init_cpus(MachineState *ms, const char *cpu_type, */ dev = qdev_new(privdev); qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, periphbase); /* Interrupts [42:0] are from the motherboard; @@ -532,7 +532,7 @@ static PFlashCFI01 *ve_pflash_cfi01_register(hwaddr base, const char *name, qdev_prop_set_uint16(dev, "id2", 0x00); qdev_prop_set_uint16(dev, "id3", 0x00); qdev_prop_set_string(dev, "name", name); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return PFLASH_CFI01(dev); @@ -610,7 +610,7 @@ static void vexpress_common_init(MachineState *machine) qdev_prop_set_uint32(sysctl, propname, daughterboard->clocks[i]); g_free(propname); } - qdev_realize_and_unref(sysctl, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(sysctl), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]); /* VE_SP810: not modelled */ @@ -618,7 +618,7 @@ static void vexpress_common_init(MachineState *machine) pl041 = qdev_new("pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_realize_and_unref(pl041, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(pl041), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, map[VE_PL041]); sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[11]); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index ca151435ae..c3e80bcbce 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -579,7 +579,7 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); return dev; } @@ -598,7 +598,7 @@ static void create_its(VirtMachineState *vms) object_property_set_link(OBJECT(dev), OBJECT(vms->gic), "parent-gicv3", &error_abort); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_ITS].base); fdt_add_its_gic_node(vms); @@ -614,7 +614,7 @@ static void create_v2m(VirtMachineState *vms) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_V2M].base); qdev_prop_set_uint32(dev, "base-spi", irq); qdev_prop_set_uint32(dev, "num-spi", NUM_GICV2M_SPIS); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); for (i = 0; i < NUM_GICV2M_SPIS; i++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, @@ -671,8 +671,8 @@ static void create_gic(VirtMachineState *vms) vms->virt); } } - qdev_realize_and_unref(vms->gic, NULL, &error_fatal); gicbusdev = SYS_BUS_DEVICE(vms->gic); + sysbus_realize_and_unref(gicbusdev, &error_fatal); sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base); if (type == 3) { sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_REDIST].base); @@ -758,7 +758,7 @@ static void create_uart(const VirtMachineState *vms, int uart, SysBusDevice *s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq)); @@ -980,7 +980,7 @@ static void virt_flash_map1(PFlashCFI01 *flash, assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE)); assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); memory_region_add_subregion(sysmem, base, sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), @@ -1177,7 +1177,7 @@ static void create_smmu(const VirtMachineState *vms, object_property_set_link(OBJECT(dev), OBJECT(bus), "primary-bus", &error_abort); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); for (i = 0; i < NUM_SMMU_IRQS; i++) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, @@ -1254,7 +1254,7 @@ static void create_pcie(VirtMachineState *vms) PCIHostState *pci; dev = qdev_new(TYPE_GPEX_HOST); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); ecam_id = VIRT_ECAM_ID(vms->highmem_ecam); base_ecam = vms->memmap[ecam_id].base; @@ -1376,7 +1376,7 @@ static void create_platform_bus(VirtMachineState *vms) dev->id = TYPE_PLATFORM_BUS_DEVICE; qdev_prop_set_uint32(dev, "num_irqs", PLATFORM_BUS_NUM_IRQS); qdev_prop_set_uint32(dev, "mmio_size", vms->memmap[VIRT_PLATFORM_BUS].size); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); vms->platform_bus_dev = dev; s = SYS_BUS_DEVICE(dev); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 0e0f0976c4..69d62ee24b 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -119,8 +119,8 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(dev, nd); } - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); } @@ -140,8 +140,8 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1); qdev_prop_set_uint8(dev, "num-ss-bits", num_ss); qdev_prop_set_uint8(dev, "num-busses", num_busses); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, base_addr); if (is_qspi) { sysbus_mmio_map(busdev, 1, 0xFC000000); @@ -223,7 +223,7 @@ static void zynq_init(MachineState *machine) /* Create slcr, keep a pointer to connect clocks */ slcr = qdev_new("xilinx,zynq_slcr"); - qdev_realize_and_unref(slcr, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(slcr), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(slcr), 0, 0xF8000000); /* Create the main clock source, and feed slcr with it */ @@ -236,8 +236,8 @@ static void zynq_init(MachineState *machine) dev = qdev_new(TYPE_A9MPCORE_PRIV); qdev_prop_set_uint32(dev, "num-cpu", 1); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ)); @@ -283,7 +283,7 @@ static void zynq_init(MachineState *machine) dev = qdev_new(TYPE_SYSBUS_SDHCI); qdev_prop_set_uint8(dev, "sd-spec-version", 2); qdev_prop_set_uint64(dev, "capareg", ZYNQ_SDHCI_CAPABILITIES); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, hci_addr); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[hci_irq - IRQ_OFFSET]); @@ -296,7 +296,7 @@ static void zynq_init(MachineState *machine) } dev = qdev_new(TYPE_ZYNQ_XADC); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[39-IRQ_OFFSET]); @@ -312,8 +312,8 @@ static void zynq_init(MachineState *machine) qdev_prop_set_uint8(dev, "rd_q_dep", 16); qdev_prop_set_uint16(dev, "data_buffer_dep", 256); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, 0xF8003000); sysbus_connect_irq(busdev, 0, pic[45-IRQ_OFFSET]); /* abort irq line */ for (n = 0; n < ARRAY_SIZE(dma_irqs); ++n) { /* event irqs */ @@ -321,8 +321,8 @@ static void zynq_init(MachineState *machine) } dev = qdev_new("xlnx.ps7-dev-cfg"); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, pic[40 - IRQ_OFFSET]); sysbus_mmio_map(busdev, 0, 0xF8007000); diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index fb37b235fe..3d8431dbcf 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -434,7 +434,7 @@ static void create_virtio_regions(VersalVirt *s) pic_irq = qdev_get_gpio_in(DEVICE(&s->soc.fpd.apu.gic), irq); dev = qdev_new("virtio-mmio"); object_property_add_child(OBJECT(&s->soc), name, OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic_irq); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(&s->soc.mr_ps, base, mr); diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 12e4469cf4..38d6b91d15 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -309,7 +309,7 @@ static void versal_unimp_area(Versal *s, const char *name, qdev_prop_set_string(dev, "name", name); qdev_prop_set_uint64(dev, "size", size); object_property_add_child(OBJECT(s), name, OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); mr_dev = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(mr, base, mr_dev); diff --git a/hw/block/fdc.c b/hw/block/fdc.c index a3250f6fdb..8528b9a3c7 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2583,8 +2583,8 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]), &error_fatal); } - qdev_realize_and_unref(dev, NULL, &error_fatal); sbd = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sbd, &error_fatal); sysbus_connect_irq(sbd, 0, irq); sysbus_mmio_map(sbd, 0, mmio_base); } @@ -2600,7 +2600,7 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(fds[0]), &error_fatal); } - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sys = SYSBUS_FDC(dev); sysbus_connect_irq(SYS_BUS_DEVICE(sys), 0, irq); sysbus_mmio_map(SYS_BUS_DEVICE(sys), 0, io_base); diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index d2a647d2b8..9f0c1d61ca 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -974,7 +974,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, qdev_prop_set_uint16(dev, "id2", id2); qdev_prop_set_uint16(dev, "id3", id3); qdev_prop_set_string(dev, "name", name); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return PFLASH_CFI01(dev); diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index ed9e9eef0c..6eb66e7bb0 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -1016,7 +1016,7 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base, qdev_prop_set_uint16(dev, "unlock-addr0", unlock_addr0); qdev_prop_set_uint16(dev, "unlock-addr1", unlock_addr1); qdev_prop_set_string(dev, "name", name); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return PFLASH_CFI02(dev); diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index b86bd7b2e6..9c8ab3a77d 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -661,7 +661,7 @@ DeviceState *exynos4210_uart_create(hwaddr addr, qdev_prop_set_uint32(dev, "tx-size", fifo_size); bus = SYS_BUS_DEVICE(dev); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(bus, &error_fatal); if (addr != (hwaddr)-1) { sysbus_mmio_map(bus, 0, addr); } diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c index 2ac0a195f3..8d1b7f2bca 100644 --- a/hw/char/mcf_uart.c +++ b/hw/char/mcf_uart.c @@ -348,7 +348,7 @@ void *mcf_uart_init(qemu_irq irq, Chardev *chrdrv) if (chrdrv) { qdev_prop_set_chr(dev, "chardev", chrdrv); } - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); diff --git a/hw/char/serial.c b/hw/char/serial.c index 57c299e993..4582d488d0 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -1134,7 +1134,7 @@ SerialMM *serial_mm_init(MemoryRegion *address_space, qdev_prop_set_chr(DEVICE(smm), "chardev", chr); qdev_set_legacy_instance_id(DEVICE(smm), base, 2); qdev_prop_set_uint8(DEVICE(smm), "endianness", end); - qdev_realize_and_unref(DEVICE(smm), NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(smm), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, irq); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(smm), 0); diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 68b837ac85..1220298e8f 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -232,7 +232,7 @@ DeviceState *sysbus_create_varargs(const char *name, dev = qdev_new(name); s = SYS_BUS_DEVICE(dev); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); if (addr != (hwaddr)-1) { sysbus_mmio_map(s, 0, addr); } diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c index 5db667d518..dab7423c73 100644 --- a/hw/cris/axis_dev88.c +++ b/hw/cris/axis_dev88.c @@ -290,8 +290,8 @@ void axisdev88_init(MachineState *machine) dev = qdev_new("etraxfs,pic"); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, 0x3001c000); sysbus_connect_irq(s, 0, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_IRQ)); sysbus_connect_irq(s, 1, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_NMI)); diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c index e54fd85777..c34ef1a1bf 100644 --- a/hw/display/milkymist-tmu2.c +++ b/hw/display/milkymist-tmu2.c @@ -544,7 +544,7 @@ DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq) XCloseDisplay(d); dev = qdev_new(TYPE_MILKYMIST_TMU2); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); diff --git a/hw/display/sm501.c b/hw/display/sm501.c index ccdbce1a06..80da8575fe 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1971,7 +1971,7 @@ static void sm501_realize_sysbus(DeviceState *dev, Error **errp) usb_dev = qdev_new("sysbus-ohci"); qdev_prop_set_uint32(usb_dev, "num-ports", 2); qdev_prop_set_uint64(usb_dev, "dma-offset", s->base); - qdev_realize_and_unref(usb_dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(usb_dev), &error_fatal); memory_region_add_subregion(&s->state.mmio_region, SM501_USB_HOST, sysbus_mmio_get_region(SYS_BUS_DEVICE(usb_dev), 0)); sysbus_pass_irq(sbd, SYS_BUS_DEVICE(usb_dev)); diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c index 6b761af701..78b2849bcb 100644 --- a/hw/dma/pxa2xx_dma.c +++ b/hw/dma/pxa2xx_dma.c @@ -497,7 +497,7 @@ DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq) dev = qdev_new("pxa2xx-dma"); qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); @@ -511,7 +511,7 @@ DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq) dev = qdev_new("pxa2xx-dma"); qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index 21c9706bf3..7eddc9a776 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -746,7 +746,7 @@ DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr) DeviceState *dev; dev = qdev_new(TYPE_RC4030); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); *dmas = rc4030_allocate_dmas(dev, 4); *dma_mr = &RC4030(dev)->dma_mr; diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index 77cf41e591..f02aca6f40 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -310,7 +310,7 @@ static void sparc32_espdma_device_realize(DeviceState *dev, Error **errp) esp->dma_opaque = SPARC32_DMA_DEVICE(dev); sysbus->it_shift = 2; esp->dma_enabled = 1; - qdev_realize_and_unref(d, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(d), &error_fatal); } static void sparc32_espdma_device_class_init(ObjectClass *klass, void *data) @@ -347,7 +347,7 @@ static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp) object_property_add_child(OBJECT(dev), "lance", OBJECT(d)); qdev_set_nic_properties(d, nd); object_property_set_link(OBJECT(d), OBJECT(dev), "dma", errp); - qdev_realize_and_unref(d, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(d), &error_fatal); } static void sparc32_ledma_device_class_init(ObjectClass *klass, void *data) @@ -381,7 +381,7 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) espdma = qdev_new(TYPE_SPARC32_ESPDMA_DEVICE); object_property_set_link(OBJECT(espdma), iommu, "iommu", errp); object_property_add_child(OBJECT(s), "espdma", OBJECT(espdma)); - qdev_realize_and_unref(espdma, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(espdma), &error_fatal); esp = DEVICE(object_resolve_path_component(OBJECT(espdma), "esp")); sbd = SYS_BUS_DEVICE(esp); @@ -396,7 +396,7 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) ledma = qdev_new(TYPE_SPARC32_LEDMA_DEVICE); object_property_set_link(OBJECT(ledma), iommu, "iommu", errp); object_property_add_child(OBJECT(s), "ledma", OBJECT(ledma)); - qdev_realize_and_unref(ledma, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ledma), &error_fatal); lance = DEVICE(object_resolve_path_component(OBJECT(ledma), "lance")); sbd = SYS_BUS_DEVICE(lance); diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 4152c852dc..7f0c6223a8 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -548,7 +548,7 @@ PCIBus *dino_init(MemoryRegion *addr_space, &s->pci_mem, get_system_io(), PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS); s->parent_obj.bus = b; - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Set up windows into PCI bus memory. */ for (i = 1; i < 31; i++) { diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 4539022c5b..19974034f3 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -309,7 +309,7 @@ DeviceState *lasi_init(MemoryRegion *address_space) s, "lasi", 0x100000); memory_region_add_subregion(address_space, LASI_HPA, &s->this_mem); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* LAN */ if (enable_lasi_lan()) { diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index d828b4fb94..49155537cd 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -125,8 +125,8 @@ static void machine_hppa_init(MachineState *machine) /* Graphics setup. */ if (machine->enable_graphics && vga_interface_type != VGA_NONE) { dev = qdev_new("artist"); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, LASI_GFX_HPA); sysbus_mmio_map(s, 1, ARTIST_FB_ADDR); } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 30a2b5eb30..ec39741c87 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1216,7 +1216,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, if (!compat) { qdev_prop_set_uint32(hpet, HPET_INTCAP, hpet_irqs); } - qdev_realize_and_unref(hpet, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(hpet), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(hpet), 0, HPET_BASE); for (i = 0; i < GSI_NUM_PINS; i++) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index a6b6add2ef..18d2fad9c5 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -230,7 +230,7 @@ static void pc_q35_init(MachineState *machine) object_property_set_int(OBJECT(q35_host), x86ms->above_4g_mem_size, PCI_HOST_ABOVE_4G_MEM_SIZE, NULL); /* pci */ - qdev_realize_and_unref(DEVICE(q35_host), NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(q35_host), &error_fatal); phb = PCI_HOST_BRIDGE(q35_host); host_bus = phb->bus; /* create ISA bus */ diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index 2e414d1934..ec2a3b3e7e 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -187,7 +187,7 @@ static void pc_system_flash_map(PCMachineState *pcms, total_size += size; qdev_prop_set_uint32(DEVICE(system_flash), "num-blocks", size / FLASH_SECTOR_SIZE); - qdev_realize_and_unref(DEVICE(system_flash), NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(system_flash), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(system_flash), 0, 0x100000000ULL - total_size); diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 85ab52b316..9b6ebd92b5 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -351,8 +351,8 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name) } object_property_add_child(object_resolve_path(parent_name, NULL), "ioapic", OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); d = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(d, &error_fatal); sysbus_mmio_map(d, 0, IO_APIC_DEFAULT_ADDRESS); for (i = 0; i < IOAPIC_NUM_PINS; i++) { diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index a261ab2401..0aa3b843a9 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -300,8 +300,8 @@ static void exynos4210_gic_realize(DeviceState *dev, Error **errp) s->gic = qdev_new("arm_gic"); qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ); - qdev_realize_and_unref(s->gic, NULL, &error_fatal); gicbusdev = SYS_BUS_DEVICE(s->gic); + sysbus_realize_and_unref(gicbusdev, &error_fatal); /* Pass through outbound IRQ lines from the GIC */ sysbus_pass_irq(sbd, gicbusdev); diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c index b2a247dd15..aacdb1bbc2 100644 --- a/hw/intc/s390_flic.c +++ b/hw/intc/s390_flic.c @@ -71,7 +71,7 @@ void s390_flic_init(void) object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC, OBJECT(dev)); } - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); } static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id, diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 630985604d..58fde178f9 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -62,7 +62,7 @@ ISABus *isa_bus_new(DeviceState *dev, MemoryRegion* address_space, } if (!dev) { dev = qdev_new("isabus-bridge"); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); } isabus = ISA_BUS(qbus_create(TYPE_ISA_BUS, dev, NULL)); diff --git a/hw/lm32/lm32.h b/hw/lm32/lm32.h index 326238d859..7b4f6255b9 100644 --- a/hw/lm32/lm32.h +++ b/hw/lm32/lm32.h @@ -11,8 +11,8 @@ static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq) SysBusDevice *d; dev = qdev_new("lm32-pic"); - qdev_realize_and_unref(dev, NULL, &error_fatal); d = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(d, &error_fatal); sysbus_connect_irq(d, 0, cpu_irq); return dev; @@ -24,7 +24,7 @@ static inline DeviceState *lm32_juart_init(Chardev *chr) dev = qdev_new(TYPE_LM32_JUART); qdev_prop_set_chr(dev, "chardev", chr); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); return dev; } @@ -39,7 +39,7 @@ static inline DeviceState *lm32_uart_create(hwaddr addr, dev = qdev_new("lm32-uart"); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); return dev; diff --git a/hw/lm32/milkymist-hw.h b/hw/lm32/milkymist-hw.h index d5f15a30a1..05e2c2a5a7 100644 --- a/hw/lm32/milkymist-hw.h +++ b/hw/lm32/milkymist-hw.h @@ -13,7 +13,7 @@ static inline DeviceState *milkymist_uart_create(hwaddr base, dev = qdev_new("milkymist-uart"); qdev_prop_set_chr(dev, "chardev", chr); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); @@ -25,7 +25,7 @@ static inline DeviceState *milkymist_hpdmc_create(hwaddr base) DeviceState *dev; dev = qdev_new("milkymist-hpdmc"); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; @@ -36,7 +36,7 @@ static inline DeviceState *milkymist_memcard_create(hwaddr base) DeviceState *dev; dev = qdev_new("milkymist-memcard"); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; @@ -50,7 +50,7 @@ static inline DeviceState *milkymist_vgafb_create(hwaddr base, dev = qdev_new("milkymist-vgafb"); qdev_prop_set_uint32(dev, "fb_offset", fb_offset); qdev_prop_set_uint32(dev, "fb_mask", fb_mask); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; @@ -68,7 +68,7 @@ static inline DeviceState *milkymist_sysctl_create(hwaddr base, qdev_prop_set_uint32(dev, "systemid", system_id); qdev_prop_set_uint32(dev, "capabilities", capabilities); qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gpio_irq); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, timer0_irq); @@ -83,7 +83,7 @@ static inline DeviceState *milkymist_pfpu_create(hwaddr base, DeviceState *dev; dev = qdev_new("milkymist-pfpu"); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; @@ -96,7 +96,7 @@ static inline DeviceState *milkymist_ac97_create(hwaddr base, DeviceState *dev; dev = qdev_new("milkymist-ac97"); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, crrequest_irq); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, crreply_irq); @@ -114,7 +114,7 @@ static inline DeviceState *milkymist_minimac2_create(hwaddr base, qemu_check_nic_model(&nd_table[0], "minimac2"); dev = qdev_new("milkymist-minimac2"); qdev_set_nic_properties(dev, &nd_table[0]); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, buffers_base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq); @@ -132,7 +132,7 @@ static inline DeviceState *milkymist_softusb_create(hwaddr base, dev = qdev_new("milkymist-softusb"); qdev_prop_set_uint32(dev, "pmem_size", pmem_size); qdev_prop_set_uint32(dev, "dmem_size", dmem_size); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, pmem_base); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, dmem_base); diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 666561d716..d310a98e7b 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -216,9 +216,9 @@ static void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd, hwaddr base, qemu_check_nic_model(nd, TYPE_MCF_FEC_NET); dev = qdev_new(TYPE_MCF_FEC_NET); qdev_set_nic_properties(dev, nd); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); for (i = 0; i < FEC_NUM_IRQ; i++) { sysbus_connect_irq(s, i, irqs[i]); } diff --git a/hw/m68k/mcf_intc.c b/hw/m68k/mcf_intc.c index 75d6e24719..e01e2e111b 100644 --- a/hw/m68k/mcf_intc.c +++ b/hw/m68k/mcf_intc.c @@ -206,7 +206,7 @@ qemu_irq *mcf_intc_init(MemoryRegion *sysmem, mcf_intc_state *s; dev = qdev_new(TYPE_MCF_INTC); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); s = MCF_INTC(dev); s->cpu = cpu; diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c index e1e16bf9af..d3f25cd6d7 100644 --- a/hw/m68k/next-cube.c +++ b/hw/m68k/next-cube.c @@ -848,9 +848,9 @@ static void next_escc_init(M68kCPU *cpu) qdev_prop_set_chr(dev, "chrA", serial_hd(0)); qdev_prop_set_uint32(dev, "chnBtype", escc_serial); qdev_prop_set_uint32(dev, "chnAtype", escc_serial); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, ser_irq[0]); sysbus_connect_irq(s, 1, ser_irq[1]); sysbus_mmio_map(s, 0, 0x2118000); @@ -896,7 +896,7 @@ static void next_cube_init(MachineState *machine) /* Framebuffer */ dev = qdev_new(TYPE_NEXTFB); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0B000000); /* MMIO */ @@ -919,7 +919,7 @@ static void next_cube_init(MachineState *machine) /* KBD */ dev = qdev_new(TYPE_NEXTKBD); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0200e000); /* Load ROM here */ diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 15b7eb719a..503ec54f5d 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -224,8 +224,8 @@ static void q800_init(MachineState *machine) qdev_prop_set_drive(via_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_abort); } - qdev_realize_and_unref(via_dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(via_dev); + sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, VIA_BASE); qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 0, pic[0]); qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 1, pic[1]); @@ -265,8 +265,8 @@ static void q800_init(MachineState *machine) qdev_prop_set_bit(dev, "big_endian", true); object_property_set_link(OBJECT(dev), OBJECT(get_system_memory()), "dma_mr", &error_abort); - qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, SONIC_BASE); sysbus_mmio_map(sysbus, 1, SONIC_PROM_BASE); sysbus_connect_irq(sysbus, 0, pic[2]); @@ -282,8 +282,8 @@ static void q800_init(MachineState *machine) qdev_prop_set_chr(dev, "chrB", serial_hd(1)); qdev_prop_set_uint32(dev, "chnBtype", 0); qdev_prop_set_uint32(dev, "chnAtype", 0); - qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_connect_irq(sysbus, 0, pic[3]); sysbus_connect_irq(sysbus, 1, pic[3]); sysbus_mmio_map(sysbus, 0, SCC_BASE); @@ -298,9 +298,9 @@ static void q800_init(MachineState *machine) esp->dma_opaque = NULL; sysbus_esp->it_shift = 4; esp->dma_enabled = 1; - qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in_named(via_dev, "via2-irq", VIA2_IRQ_SCSI_BIT)); @@ -315,13 +315,13 @@ static void q800_init(MachineState *machine) /* SWIM floppy controller */ dev = qdev_new(TYPE_SWIM); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SWIM_BASE); /* NuBus */ dev = qdev_new(TYPE_MAC_NUBUS_BRIDGE); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, NUBUS_SUPER_SLOT_BASE); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, NUBUS_SLOT_BASE); diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index d4bfa233c9..4d80a691bc 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -112,7 +112,7 @@ petalogix_ml605_init(MachineState *machine) dev = qdev_new("xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", 1 << TIMER_IRQ); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(cpu), MB_CPU_IRQ)); @@ -128,7 +128,7 @@ petalogix_ml605_init(MachineState *machine) dev = qdev_new("xlnx.xps-timer"); qdev_prop_set_uint32(dev, "one-timer-only", 0); qdev_prop_set_uint32(dev, "clock-frequency", 100 * 1000000); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]); @@ -152,7 +152,7 @@ petalogix_ml605_init(MachineState *machine) "axistream-connected", &error_abort); object_property_set_link(OBJECT(eth0), cs, "axistream-control-connected", &error_abort); - qdev_realize_and_unref(eth0, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(eth0), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(eth0), 0, AXIENET_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(eth0), 0, irq[AXIENET_IRQ]); @@ -165,7 +165,7 @@ petalogix_ml605_init(MachineState *machine) "axistream-connected", &error_abort); object_property_set_link(OBJECT(dma), cs, "axistream-control-connected", &error_abort); - qdev_realize_and_unref(dma, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dma), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dma), 0, AXIDMA_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dma), 0, irq[AXIDMA_IRQ0]); sysbus_connect_irq(SYS_BUS_DEVICE(dma), 1, irq[AXIDMA_IRQ1]); @@ -175,8 +175,8 @@ petalogix_ml605_init(MachineState *machine) dev = qdev_new("xlnx.xps-spi"); qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES); - qdev_realize_and_unref(dev, NULL, &error_fatal); busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, SPI_BASEADDR); sysbus_connect_irq(busdev, 0, irq[SPI_IRQ]); diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c index aecee2f5f3..793006a822 100644 --- a/hw/microblaze/petalogix_s3adsp1800_mmu.c +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -92,7 +92,7 @@ petalogix_s3adsp1800_init(MachineState *machine) dev = qdev_new("xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", 1 << ETHLITE_IRQ | 1 << UARTLITE_IRQ); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(cpu), MB_CPU_IRQ)); @@ -107,7 +107,7 @@ petalogix_s3adsp1800_init(MachineState *machine) dev = qdev_new("xlnx.xps-timer"); qdev_prop_set_uint32(dev, "one-timer-only", 0); qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]); @@ -116,7 +116,7 @@ petalogix_s3adsp1800_init(MachineState *machine) qdev_set_nic_properties(dev, &nd_table[0]); qdev_prop_set_uint32(dev, "tx-ping-pong", 0); qdev_prop_set_uint32(dev, "rx-ping-pong", 0); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ETHLITE_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[ETHLITE_IRQ]); diff --git a/hw/mips/boston.c b/hw/mips/boston.c index d90f3a463b..03008b5581 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -409,7 +409,7 @@ xilinx_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr, qdev_prop_set_uint64(dev, "mmio_size", mmio_size); qdev_prop_set_bit(dev, "link_up", link_up); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); cfg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion_overlap(sys_mem, cfg_base, cfg, 0); @@ -442,7 +442,7 @@ static void boston_mach_init(MachineState *machine) } dev = qdev_new(TYPE_MIPS_BOSTON); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); s = BOSTON(dev); s->mach = machine; diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 37750b8037..756ac9ae12 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -1213,7 +1213,7 @@ PCIBus *gt64120_register(qemu_irq *pic) &d->pci0_mem, get_system_io(), PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); memory_region_init_io(&d->ISD_mem, OBJECT(dev), &isd_mem_ops, d, "isd-mem", 0x1000); diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index fb975bd1c7..c3b0da60cc 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -256,8 +256,8 @@ static void mips_jazz_init(MachineState *machine, switch (jazz_model) { case JAZZ_MAGNUM: dev = qdev_new("sysbus-g364"); - qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, 0x60080000); sysbus_mmio_map(sysbus, 1, 0x40000000); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 3)); @@ -292,8 +292,8 @@ static void mips_jazz_init(MachineState *machine, qdev_prop_set_uint8(dev, "it_shift", 2); object_property_set_link(OBJECT(dev), OBJECT(rc4030_dma_mr), "dma_mr", &error_abort); - qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, 0x80001000); sysbus_mmio_map(sysbus, 1, 0x8000b000); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 4)); @@ -317,9 +317,9 @@ static void mips_jazz_init(MachineState *machine, sysbus_esp->it_shift = 0; /* XXX for now until rc4030 has been changed to use DMA enable signal */ esp->dma_enabled = 1; - qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 5)); sysbus_mmio_map(sysbus, 0, 0x80002000); @@ -363,8 +363,8 @@ static void mips_jazz_init(MachineState *machine, /* NVRAM */ dev = qdev_new("ds1225y"); - qdev_realize_and_unref(dev, NULL, &error_fatal); sysbus = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, 0x80009000); /* LED indicator */ diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 755e7ca40d..7df4768170 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -1243,7 +1243,7 @@ void mips_malta_init(MachineState *machine) */ empty_slot_init("GT64120", 0, 0x20000000); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* create CPU */ mips_create_cpu(machine, s, &cbus_irq, &i8259_irq); diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c index 72b1e846af..1b3b762203 100644 --- a/hw/mips/mipssim.c +++ b/hw/mips/mipssim.c @@ -131,9 +131,9 @@ static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd) dev = qdev_new("mipsnet"); qdev_set_nic_properties(dev, nd); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, irq); memory_region_add_subregion(get_system_io(), base, @@ -220,7 +220,7 @@ mips_mipssim_init(MachineState *machine) qdev_prop_set_chr(dev, "chardev", serial_hd(0)); qdev_set_legacy_instance_id(dev, 0x3f8, 2); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, env->irq[4]); sysbus_add_io(SYS_BUS_DEVICE(dev), 0x3f8, sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); diff --git a/hw/misc/empty_slot.c b/hw/misc/empty_slot.c index eb2aec731e..9a011b1c11 100644 --- a/hw/misc/empty_slot.c +++ b/hw/misc/empty_slot.c @@ -60,7 +60,7 @@ void empty_slot_init(const char *name, hwaddr addr, uint64_t slot_size) dev = qdev_new(TYPE_EMPTY_SLOT); qdev_prop_set_uint64(dev, "size", slot_size); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(dev), 0, addr, -10000); } diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c index 7e98cbda87..3408ceacb5 100644 --- a/hw/net/etraxfs_eth.c +++ b/hw/net/etraxfs_eth.c @@ -668,7 +668,7 @@ etraxfs_eth_init(NICInfo *nd, hwaddr base, int phyaddr, */ ETRAX_FS_ETH(dev)->dma_out = dma_out; ETRAX_FS_ETH(dev)->dma_in = dma_in; - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index d0e9ff57ca..7035cf4eb9 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -455,7 +455,7 @@ DeviceState *etsec_create(hwaddr base, dev = qdev_new("eTSEC"); qdev_set_nic_properties(dev, nd); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq); diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 81c32c8107..8e2a432179 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -1397,8 +1397,8 @@ void lan9118_init(NICInfo *nd, uint32_t base, qemu_irq irq) qemu_check_nic_model(nd, "lan9118"); dev = qdev_new(TYPE_LAN9118); qdev_set_nic_properties(dev, nd); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); } diff --git a/hw/net/lasi_i82596.c b/hw/net/lasi_i82596.c index 1870507727..820b63f350 100644 --- a/hw/net/lasi_i82596.c +++ b/hw/net/lasi_i82596.c @@ -131,7 +131,7 @@ SysBusI82596State *lasi_82596_init(MemoryRegion *addr_space, s = SYSBUS_I82596(dev); s->state.irq = lan_irq; qdev_set_nic_properties(dev, &nd_table[0]); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); s->state.conf.macaddr = HP_MAC; /* set HP MAC prefix */ /* LASI 82596 ports in main memory. */ diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c index 9b616fe62a..a347b6a4d5 100644 --- a/hw/net/smc91c111.c +++ b/hw/net/smc91c111.c @@ -824,8 +824,8 @@ void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) qemu_check_nic_model(nd, "smc91c111"); dev = qdev_new(TYPE_SMC91C111); qdev_set_nic_properties(dev, nd); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); } diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c index 3d304d724a..5c13b74306 100644 --- a/hw/nios2/10m50_devboard.c +++ b/hw/nios2/10m50_devboard.c @@ -82,7 +82,7 @@ static void nios2_10m50_ghrd_init(MachineState *machine) /* Register: Internal Interrupt Controller (IIC) */ dev = qdev_new("altera,iic"); object_property_add_const_link(OBJECT(dev), "cpu", OBJECT(cpu)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]); for (i = 0; i < 32; i++) { irq[i] = qdev_get_gpio_in(dev, i); @@ -95,14 +95,14 @@ static void nios2_10m50_ghrd_init(MachineState *machine) /* Register: Timer sys_clk_timer */ dev = qdev_new("ALTR.timer"); qdev_prop_set_uint32(dev, "clock-frequency", 75 * 1000000); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xf8001440); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[0]); /* Register: Timer sys_clk_timer_1 */ dev = qdev_new("ALTR.timer"); qdev_prop_set_uint32(dev, "clock-frequency", 75 * 1000000); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xe0000880); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[5]); diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index fbcaf66002..0408a31f8e 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -1106,9 +1106,9 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); sbd = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sbd, &error_fatal); ios = FW_CFG_IO(dev); sysbus_add_io(sbd, iobase, &ios->comb_iomem); @@ -1146,9 +1146,9 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); sbd = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sbd, &error_fatal); sysbus_mmio_map(sbd, 0, ctl_addr); sysbus_mmio_map(sbd, 1, data_addr); diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index ba1a11442f..d752282e67 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -61,9 +61,9 @@ static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, dev = qdev_new("open_eth"); qdev_set_nic_properties(dev, nd); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); for (i = 0; i < num_cpus; i++) { sysbus_connect_irq(s, 0, cpu_irqs[i][irq_pin]); } @@ -80,9 +80,9 @@ static void openrisc_sim_ompic_init(hwaddr base, int num_cpus, dev = qdev_new("or1k-ompic"); qdev_prop_set_uint32(dev, "num-cpus", num_cpus); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); for (i = 0; i < num_cpus; i++) { sysbus_connect_irq(s, i, cpu_irqs[i][irq_pin]); } diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 3a395ab2f0..22f9fc223b 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -255,7 +255,7 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) goto err_register_bus; } - qdev_realize_and_unref(ds, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), &error_fatal); if (bds) { qdev_realize_and_unref(bds, &bus->qbus, &error_fatal); } diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 7bb032f005..1405b3fc70 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -748,7 +748,7 @@ PCIBus *bonito_init(qemu_irq *pic) phb = PCI_HOST_BRIDGE(dev); pcihost = BONITO_PCI_HOST_BRIDGE(dev); pcihost->pic = pic; - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); d = pci_new(PCI_DEVFN(0, 0), TYPE_PCI_BONITO); s = PCI_BONITO(d); diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c index 09c0d2f4e8..8ed2417f0c 100644 --- a/hw/pci-host/i440fx.c +++ b/hw/pci-host/i440fx.c @@ -277,7 +277,7 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, address_space_io, 0, TYPE_PCI_BUS); s->bus = b; object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); d = pci_create_simple(b, 0, pci_type); *pi440fx_state = I440FX_PCI_DEVICE(d); diff --git a/hw/pcmcia/pxa2xx.c b/hw/pcmcia/pxa2xx.c index 90f540209d..5f4bf22a90 100644 --- a/hw/pcmcia/pxa2xx.c +++ b/hw/pcmcia/pxa2xx.c @@ -152,7 +152,7 @@ PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem, sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); s = PXA2XX_PCMCIA(dev); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); return s; } diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 06f4a38266..51bf95b303 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -748,8 +748,8 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms, qdev_prop_set_uint32(dev, "model", pmc->mpic_version); qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); k = 0; for (i = 0; i < smp_cpus; i++) { @@ -771,7 +771,7 @@ static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc, dev = qdev_new(TYPE_KVM_OPENPIC); qdev_prop_set_uint32(dev, "model", pmc->mpic_version); - qdev_realize_and_unref(dev, NULL, &err); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &err); if (err) { error_propagate(errp, err); object_unparent(OBJECT(dev)); @@ -916,7 +916,7 @@ void ppce500_init(MachineState *machine) dev = qdev_new("e500-ccsr"); object_property_add_child(qdev_get_machine(), "e500-ccsr", OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); ccsr = CCSR(dev); ccsr_addr_space = &ccsr->ccsr_space; memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base, @@ -939,7 +939,7 @@ void ppce500_init(MachineState *machine) /* I2C */ dev = qdev_new("mpc-i2c"); s = SYS_BUS_DEVICE(dev); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ)); memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET, sysbus_mmio_get_region(s, 0)); @@ -949,8 +949,8 @@ void ppce500_init(MachineState *machine) /* General Utility device */ dev = qdev_new("mpc8544-guts"); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET, sysbus_mmio_get_region(s, 0)); @@ -959,8 +959,8 @@ void ppce500_init(MachineState *machine) object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev)); qdev_prop_set_uint32(dev, "first_slot", pmc->pci_first_slot); qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); for (i = 0; i < PCI_NUM_PINS; i++) { sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i])); } @@ -987,7 +987,7 @@ void ppce500_init(MachineState *machine) dev = qdev_new("mpc8xxx_gpio"); s = SYS_BUS_DEVICE(dev); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ)); memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET, sysbus_mmio_get_region(s, 0)); @@ -1003,7 +1003,7 @@ void ppce500_init(MachineState *machine) dev->id = TYPE_PLATFORM_BUS_DEVICE; qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs); qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); pms->pbus_dev = PLATFORM_BUS_DEVICE(dev); s = SYS_BUS_DEVICE(pms->pbus_dev); diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index baa17cdce7..5f3a028e6a 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -243,8 +243,8 @@ static void ppc_core99_init(MachineState *machine) /* UniN init */ dev = qdev_new(TYPE_UNI_NORTH); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); memory_region_add_subregion(get_system_memory(), 0xf8000000, sysbus_mmio_get_region(s, 0)); @@ -290,8 +290,8 @@ static void ppc_core99_init(MachineState *machine) pic_dev = qdev_new(TYPE_OPENPIC); qdev_prop_set_uint32(pic_dev, "model", OPENPIC_MODEL_KEYLARGO); - qdev_realize_and_unref(pic_dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(pic_dev); + sysbus_realize_and_unref(s, &error_fatal); k = 0; for (i = 0; i < smp_cpus; i++) { for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { @@ -306,7 +306,7 @@ static void ppc_core99_init(MachineState *machine) dev = qdev_new(TYPE_U3_AGP_HOST_BRIDGE); object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", &error_abort); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); uninorth_pci = U3_AGP_HOST_BRIDGE(dev); s = SYS_BUS_DEVICE(dev); /* PCI hole */ @@ -325,8 +325,8 @@ static void ppc_core99_init(MachineState *machine) dev = qdev_new(TYPE_UNI_NORTH_AGP_HOST_BRIDGE); object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", &error_abort); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, 0xf0800000); sysbus_mmio_map(s, 1, 0xf0c00000); @@ -334,8 +334,8 @@ static void ppc_core99_init(MachineState *machine) dev = qdev_new(TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE); object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", &error_abort); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, 0xf4800000); sysbus_mmio_map(s, 1, 0xf4c00000); @@ -344,7 +344,7 @@ static void ppc_core99_init(MachineState *machine) qdev_prop_set_uint32(dev, "ofw-addr", 0xf2000000); object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", &error_abort); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); uninorth_pci = UNI_NORTH_PCI_HOST_BRIDGE(dev); s = SYS_BUS_DEVICE(dev); /* PCI hole */ @@ -444,7 +444,7 @@ static void ppc_core99_init(MachineState *machine) dev = qdev_new(TYPE_MACIO_NVRAM); qdev_prop_set_uint32(dev, "size", 0x2000); qdev_prop_set_uint32(dev, "it_shift", 1); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, nvram_addr); nvr = MACIO_NVRAM(dev); pmac_format_nvram_partition(nvr, 0x2000); @@ -456,8 +456,8 @@ static void ppc_core99_init(MachineState *machine) qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(fw_cfg)); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, CFG_ADDR); sysbus_mmio_map(s, 1, CFG_ADDR + 2); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 903483079e..f8c204ead7 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -223,7 +223,7 @@ static void ppc_heathrow_init(MachineState *machine) /* XXX: we register only 1 output pin for heathrow PIC */ pic_dev = qdev_new(TYPE_HEATHROW); - qdev_realize_and_unref(pic_dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(pic_dev), &error_fatal); /* Connect the heathrow PIC outputs to the 6xx bus */ for (i = 0; i < smp_cpus; i++) { @@ -256,8 +256,8 @@ static void ppc_heathrow_init(MachineState *machine) qdev_prop_set_uint32(dev, "ofw-addr", 0x80000000); object_property_set_link(OBJECT(dev), OBJECT(pic_dev), "pic", &error_abort); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, GRACKLE_BASE); sysbus_mmio_map(s, 1, GRACKLE_BASE + 0x200000); /* PCI hole */ @@ -315,8 +315,8 @@ static void ppc_heathrow_init(MachineState *machine) qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(fw_cfg)); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, CFG_ADDR); sysbus_mmio_map(s, 1, CFG_ADDR + 2); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 8cf097ae7c..3eb40ad8f8 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -733,7 +733,7 @@ static void pnv_init(MachineState *machine) qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(pnor), &error_abort); } - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); pnv->pnor = PNV_PNOR(dev); /* load skiboot firmware */ @@ -849,7 +849,7 @@ static void pnv_init(MachineState *machine) object_property_set_link(chip, OBJECT(pnv), "xive-fabric", &error_abort); } - qdev_realize_and_unref(DEVICE(chip), NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(chip), &error_fatal); } g_free(chip_typename); @@ -1205,7 +1205,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(phb), i, "index", &error_fatal); object_property_set_int(OBJECT(phb), chip->chip_id, "chip-id", &error_fatal); - qdev_realize(DEVICE(phb), NULL, &local_err); + sysbus_realize(SYS_BUS_DEVICE(phb), &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1410,7 +1410,7 @@ static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp) object_property_set_int(obj, PNV_PHB4_DEVICE_ID, "device-id", &error_fatal); object_property_set_link(obj, OBJECT(stack), "stack", &error_abort); - qdev_realize(DEVICE(obj), NULL, &local_err); + sysbus_realize(SYS_BUS_DEVICE(obj), &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index c1cf8d0f46..38fc392438 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -1369,11 +1369,11 @@ void ppc460ex_pcie_init(CPUPPCState *env) dev = qdev_new(TYPE_PPC460EX_PCIE_HOST); qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE0_BASE); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env); dev = qdev_new(TYPE_PPC460EX_PCIE_HOST); qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE1_BASE); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env); } diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 73a40b2cbe..4a0cb434a6 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -278,7 +278,7 @@ static void ibm_40p_init(MachineState *machine) qdev_prop_set_uint32(dev, "elf-machine", PPC_ELF_MACHINE); pcihost = SYS_BUS_DEVICE(dev); object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(pcihost, &error_fatal); pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0")); if (!pci_bus) { error_report("could not create PCI host controller"); @@ -351,8 +351,8 @@ static void ibm_40p_init(MachineState *machine) qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(fw_cfg)); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, CFG_ADDR); sysbus_mmio_map(s, 1, CFG_ADDR + 2); diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 503bd21728..1a106a68de 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -373,8 +373,8 @@ static void sam460ex_init(MachineState *machine) dev = qdev_new("sysbus-ohci"); qdev_prop_set_string(dev, "masterbus", "usb-bus.0"); qdev_prop_set_uint32(dev, "num-ports", 6); - qdev_realize_and_unref(dev, NULL, &error_fatal); sbdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sbdev, &error_fatal); sysbus_mmio_map(sbdev, 0, 0x4bffd0000); sysbus_connect_irq(sbdev, 0, uic[2][30]); usb_create_simple(usb_bus_find(-1), "usb-kbd"); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 7ef24ea2a1..c381bb6fb5 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2642,7 +2642,7 @@ static PCIHostState *spapr_create_default_phb(void) dev = qdev_new(TYPE_SPAPR_PCI_HOST_BRIDGE); qdev_prop_set_uint32(dev, "index", 0); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); return PCI_HOST_BRIDGE(dev); } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index f2ade64e7d..79b0e40b66 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -334,7 +334,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3); object_property_set_link(OBJECT(dev), OBJECT(spapr), "xive-fabric", &error_abort); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); spapr->xive = SPAPR_XIVE(dev); diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 61558db1bf..4318ed9638 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -577,7 +577,7 @@ SpaprVioBus *spapr_vio_bus_init(void) /* Create bridge device */ dev = qdev_new(TYPE_SPAPR_VIO_BRIDGE); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Create bus on bridge device */ qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index f28a69c0f9..78c4901be1 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -231,7 +231,7 @@ static void virtex_init(MachineState *machine) cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT]; dev = qdev_new("xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", 0); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]); for (i = 0; i < 32; i++) { @@ -245,7 +245,7 @@ static void virtex_init(MachineState *machine) dev = qdev_new("xlnx.xps-timer"); qdev_prop_set_uint32(dev, "one-timer-only", 0); qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]); diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c index 729fce0a58..b11ffa0edc 100644 --- a/hw/riscv/sifive_clint.c +++ b/hw/riscv/sifive_clint.c @@ -252,7 +252,7 @@ DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, uint32_t num_harts, qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base); qdev_prop_set_uint32(dev, "time-base", time_base); qdev_prop_set_uint32(dev, "aperture-size", size); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); return dev; } diff --git a/hw/riscv/sifive_e_prci.c b/hw/riscv/sifive_e_prci.c index 423af22ecc..17dfa74715 100644 --- a/hw/riscv/sifive_e_prci.c +++ b/hw/riscv/sifive_e_prci.c @@ -119,7 +119,7 @@ type_init(sifive_e_prci_register_types) DeviceState *sifive_e_prci_create(hwaddr addr) { DeviceState *dev = qdev_new(TYPE_SIFIVE_E_PRCI); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); return dev; } diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c index 203fec8e48..4f216c5585 100644 --- a/hw/riscv/sifive_plic.c +++ b/hw/riscv/sifive_plic.c @@ -508,7 +508,7 @@ DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, qdev_prop_set_uint32(dev, "context-base", context_base); qdev_prop_set_uint32(dev, "context-stride", context_stride); qdev_prop_set_uint32(dev, "aperture-size", aperture_size); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); return dev; } diff --git a/hw/riscv/sifive_test.c b/hw/riscv/sifive_test.c index 596757f714..0c78fb2c93 100644 --- a/hw/riscv/sifive_test.c +++ b/hw/riscv/sifive_test.c @@ -94,7 +94,7 @@ type_init(sifive_test_register_types) DeviceState *sifive_test_create(hwaddr addr) { DeviceState *dev = qdev_new(TYPE_SIFIVE_TEST); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); return dev; } diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 4970a085ca..01d50d29bb 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -114,7 +114,7 @@ static void virt_flash_map1(PFlashCFI01 *flash, assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE)); assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); memory_region_add_subregion(sysmem, base, sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), @@ -445,7 +445,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, dev = qdev_new(TYPE_GPEX_HOST); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); ecam_alias = g_new0(MemoryRegion, 1); ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); diff --git a/hw/rtc/m48t59.c b/hw/rtc/m48t59.c index f6acf416ff..b428a06045 100644 --- a/hw/rtc/m48t59.c +++ b/hw/rtc/m48t59.c @@ -582,8 +582,8 @@ Nvram *m48t59_init(qemu_irq IRQ, hwaddr mem_base, dev = qdev_new(m48txx_sysbus_info[i].bus_name); qdev_prop_set_int32(dev, "base-year", base_year); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, IRQ); if (io_base != 0) { memory_region_add_subregion(get_system_io(), io_base, diff --git a/hw/rtc/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c index ed1c10832f..52caea8654 100644 --- a/hw/rtc/sun4v-rtc.c +++ b/hw/rtc/sun4v-rtc.c @@ -59,7 +59,7 @@ void sun4v_rtc_init(hwaddr addr) dev = qdev_new(TYPE_SUN4V_RTC); s = SYS_BUS_DEVICE(dev); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); } diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c index 974c97f454..c4e3188ad6 100644 --- a/hw/s390x/ap-bridge.c +++ b/hw/s390x/ap-bridge.c @@ -52,7 +52,7 @@ void s390_init_ap(void) dev = qdev_new(TYPE_AP_BRIDGE); object_property_add_child(qdev_get_machine(), TYPE_AP_BRIDGE, OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Create bus on bridge device */ bus = qbus_create(TYPE_AP_BUS, dev, TYPE_AP_BUS); diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index a0dd2da0b8..e37a54d3f2 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -104,7 +104,7 @@ VirtualCssBus *virtual_css_bus_init(void) dev = qdev_new(TYPE_VIRTUAL_CSS_BRIDGE); object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE, OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Create bus on bridge device */ bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index fb68c5a437..201f9604fe 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -272,7 +272,7 @@ static void ccw_init(MachineState *machine) dev = qdev_new(TYPE_S390_PCI_HOST_BRIDGE); object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE, OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* register hypercalls */ virtio_ccw_register_hcalls(); diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 40e27a8cb4..b66afb35c8 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -338,7 +338,7 @@ static void sclp_realize(DeviceState *dev, Error **errp) * as we can't find a fitting bus via the qom tree, we have to add the * event facility to the sysbus, so e.g. a sclp console can be created. */ - qdev_realize(DEVICE(sclp->event_facility), NULL, &err); + sysbus_realize(SYS_BUS_DEVICE(sclp->event_facility), &err); if (err) { goto out; } diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index 89784407b9..623be70b26 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -492,7 +492,7 @@ PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, sysbus_connect_irq(sbd, 0, irq); qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma); qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(sbd, &error_fatal); /* Create and plug in the sd card */ carddev = qdev_new(TYPE_SD_CARD); diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c index d9592280bc..443820901d 100644 --- a/hw/sh4/r2d.c +++ b/hw/sh4/r2d.c @@ -259,7 +259,7 @@ static void r2d_init(MachineState *machine) dev = qdev_new("sh_pci"); busdev = SYS_BUS_DEVICE(dev); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(busdev, &error_fatal); pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci")); sysbus_mmio_map(busdev, 0, P4ADDR(0x1e200000)); sysbus_mmio_map(busdev, 1, A7ADDR(0x1e200000)); @@ -273,7 +273,7 @@ static void r2d_init(MachineState *machine) qdev_prop_set_uint32(dev, "vram-size", SM501_VRAM_SIZE); qdev_prop_set_uint32(dev, "base", 0x10000000); qdev_prop_set_chr(dev, "chardev", serial_hd(2)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, 0x10000000); sysbus_mmio_map(busdev, 1, 0x13e00000); sysbus_connect_irq(busdev, 0, irq[SM501]); @@ -284,7 +284,7 @@ static void r2d_init(MachineState *machine) busdev = SYS_BUS_DEVICE(dev); sysbus_connect_irq(busdev, 0, irq[CF_IDE]); qdev_prop_set_uint32(dev, "shift", 1); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, 0x14001000); sysbus_mmio_map(busdev, 1, 0x1400080c); mmio_ide_init_drives(dev, dinfo, NULL); diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index b778a5bf80..d40b7891f6 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -214,14 +214,14 @@ static void leon3_generic_hw_init(MachineState *machine) qemu_register_reset(main_cpu_reset, reset_info); ahb_pnp = GRLIB_AHB_PNP(qdev_new(TYPE_GRLIB_AHB_PNP)); - qdev_realize_and_unref(DEVICE(ahb_pnp), NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ahb_pnp), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(ahb_pnp), 0, LEON3_AHB_PNP_OFFSET); grlib_ahb_pnp_add_entry(ahb_pnp, 0, 0, GRLIB_VENDOR_GAISLER, GRLIB_LEON3_DEV, GRLIB_AHB_MASTER, GRLIB_CPU_AREA); apb_pnp = GRLIB_APB_PNP(qdev_new(TYPE_GRLIB_APB_PNP)); - qdev_realize_and_unref(DEVICE(apb_pnp), NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(apb_pnp), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(apb_pnp), 0, LEON3_APB_PNP_OFFSET); grlib_ahb_pnp_add_entry(ahb_pnp, LEON3_APB_PNP_OFFSET, 0xFFF, GRLIB_VENDOR_GAISLER, GRLIB_APBMST_DEV, @@ -233,7 +233,7 @@ static void leon3_generic_hw_init(MachineState *machine) env, "pil", 1); qdev_connect_gpio_out_named(dev, "grlib-irq", 0, qdev_get_gpio_in_named(DEVICE(cpu), "pil", 0)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_IRQMP_OFFSET); env->irq_manager = dev; env->qemu_irq_ack = leon3_irq_manager; @@ -326,7 +326,7 @@ static void leon3_generic_hw_init(MachineState *machine) qdev_prop_set_uint32(dev, "nr-timers", LEON3_TIMER_COUNT); qdev_prop_set_uint32(dev, "frequency", CPU_CLK); qdev_prop_set_uint32(dev, "irq-line", LEON3_TIMER_IRQ); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_TIMER_OFFSET); for (i = 0; i < LEON3_TIMER_COUNT; i++) { @@ -341,7 +341,7 @@ static void leon3_generic_hw_init(MachineState *machine) /* Allocate uart */ dev = qdev_new(TYPE_GRLIB_APB_UART); qdev_prop_set_chr(dev, "chrdev", serial_hd(0)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_UART_OFFSET); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irqs[LEON3_UART_IRQ]); grlib_apb_pnp_add_entry(apb_pnp, LEON3_UART_OFFSET, 0xFFF, diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 5ebf303de9..ee52b5cbbc 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -318,8 +318,8 @@ static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq) dev = qdev_new(TYPE_SUN4M_IOMMU); qdev_prop_set_uint32(dev, "version", version); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, irq); sysbus_mmio_map(s, 0, addr); @@ -337,7 +337,7 @@ static void *sparc32_dma_init(hwaddr dma_base, SysBusPCNetState *lance; dma = qdev_new(TYPE_SPARC32_DMA); - qdev_realize_and_unref(dma, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dma), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dma), 0, dma_base); espdma = SPARC32_ESPDMA_DEVICE(object_resolve_path_component( @@ -368,9 +368,9 @@ static DeviceState *slavio_intctl_init(hwaddr addr, unsigned int i, j; dev = qdev_new("slavio_intctl"); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); for (i = 0; i < MAX_CPUS; i++) { for (j = 0; j < MAX_PILS; j++) { @@ -397,8 +397,8 @@ static void slavio_timer_init_all(hwaddr addr, qemu_irq master_irq, dev = qdev_new("slavio_timer"); qdev_prop_set_uint32(dev, "num_cpus", num_cpus); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, master_irq); sysbus_mmio_map(s, 0, addr + SYS_TIMER_OFFSET); @@ -434,8 +434,8 @@ static void slavio_misc_init(hwaddr base, SysBusDevice *s; dev = qdev_new("slavio_misc"); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); if (base) { /* 8 bit registers */ /* Slavio control */ @@ -472,8 +472,8 @@ static void ecc_init(hwaddr base, qemu_irq irq, uint32_t version) dev = qdev_new("eccmemctl"); qdev_prop_set_uint32(dev, "version", version); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, irq); sysbus_mmio_map(s, 0, base); if (version == 0) { // SS-600MP only @@ -487,8 +487,8 @@ static void apc_init(hwaddr power_base, qemu_irq cpu_halt) SysBusDevice *s; dev = qdev_new("apc"); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); /* Power management (APC) XXX: not a Slavio device */ sysbus_mmio_map(s, 0, power_base); sysbus_connect_irq(s, 0, cpu_halt); @@ -505,8 +505,8 @@ static void tcx_init(hwaddr addr, qemu_irq irq, int vram_size, int width, qdev_prop_set_uint16(dev, "width", width); qdev_prop_set_uint16(dev, "height", height); qdev_prop_set_uint16(dev, "depth", depth); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); /* 10/ROM : FCode ROM */ sysbus_mmio_map(s, 0, addr); @@ -557,8 +557,8 @@ static void cg3_init(hwaddr addr, qemu_irq irq, int vram_size, int width, qdev_prop_set_uint16(dev, "width", width); qdev_prop_set_uint16(dev, "height", height); qdev_prop_set_uint16(dev, "depth", depth); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); /* FCode ROM */ sysbus_mmio_map(s, 0, addr); @@ -582,8 +582,8 @@ static void idreg_init(hwaddr addr) SysBusDevice *s; dev = qdev_new(TYPE_MACIO_ID_REGISTER); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); address_space_write_rom(&address_space_memory, addr, @@ -648,8 +648,8 @@ static void afx_init(hwaddr addr) SysBusDevice *s; dev = qdev_new(TYPE_TCX_AFX); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); } @@ -709,8 +709,8 @@ static void prom_init(hwaddr addr, const char *bios_name) int ret; dev = qdev_new(TYPE_OPENPROM); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); @@ -879,7 +879,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, /* Create and map RAM frontend */ dev = qdev_new("memory"); object_property_set_link(OBJECT(dev), ram_memdev, "memdev", &error_fatal); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0); /* models without ECC don't trap when missing ram is accessed */ @@ -990,8 +990,8 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, qdev_prop_set_chr(dev, "chrA", NULL); qdev_prop_set_uint32(dev, "chnBtype", escc_mouse); qdev_prop_set_uint32(dev, "chnAtype", escc_kbd); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, slavio_irq[14]); sysbus_connect_irq(s, 1, slavio_irq[14]); sysbus_mmio_map(s, 0, hwdef->ms_kb_base); @@ -1004,9 +1004,9 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, qdev_prop_set_chr(dev, "chrA", serial_hd(0)); qdev_prop_set_uint32(dev, "chnBtype", escc_serial); qdev_prop_set_uint32(dev, "chnAtype", escc_serial); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, slavio_irq[15]); sysbus_connect_irq(s, 1, slavio_irq[15]); sysbus_mmio_map(s, 0, hwdef->serial_base); @@ -1068,8 +1068,8 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, OBJECT(fw_cfg)); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, CFG_ADDR); sysbus_mmio_map(s, 1, CFG_ADDR + 2); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 8470c33f99..97e6d3a025 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -354,8 +354,8 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) /* Power */ dev = qdev_new(TYPE_SUN4U_POWER); - qdev_realize_and_unref(dev, NULL, &error_fatal); sbd = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sbd, &error_fatal); memory_region_add_subregion(pci_address_space_io(pci_dev), 0x7240, sysbus_mmio_get_region(sbd, 0)); @@ -429,8 +429,8 @@ static void prom_init(hwaddr addr, const char *bios_name) int ret; dev = qdev_new(TYPE_OPENPROM); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); @@ -527,7 +527,7 @@ static void ram_init(hwaddr addr, ram_addr_t RAM_size) d = SUN4U_RAM(dev); d->size = RAM_size; - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); } @@ -575,7 +575,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, /* IOMMU */ iommu = qdev_new(TYPE_SUN4U_IOMMU); - qdev_realize_and_unref(iommu, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu), &error_fatal); /* set up devices */ ram_init(0, machine->ram_size); @@ -588,7 +588,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, qdev_prop_set_uint64(DEVICE(sabre), "mem-base", PBM_MEM_BASE); object_property_set_link(OBJECT(sabre), OBJECT(iommu), "iommu", &error_abort); - qdev_realize_and_unref(DEVICE(sabre), NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(sabre), &error_fatal); /* Wire up PCI interrupts to CPU */ for (i = 0; i < IVEC_MAX; i++) { @@ -698,7 +698,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, dev = qdev_new(TYPE_FW_CFG_IO); qdev_prop_set_bit(dev, "dma_enabled", false); object_property_add_child(OBJECT(ebus), TYPE_FW_CFG, OBJECT(dev)); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); memory_region_add_subregion(pci_address_space_io(ebus), BIOS_CFG_IOPORT, &FW_CFG_IO(dev)->comb_iomem); diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index 532f73661b..4b00320f1c 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -1390,6 +1390,6 @@ void xen_bus_init(void) DeviceState *dev = qdev_new(TYPE_XEN_BRIDGE); BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); qbus_set_bus_hotplug_handler(bus, &error_abort); } diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index ef7c832e2e..2335ee2e65 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -703,7 +703,7 @@ int xen_be_init(void) } xen_sysdev = qdev_new(TYPE_XENSYSDEV); - qdev_realize_and_unref(xen_sysdev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(xen_sysdev), &error_fatal); xen_sysbus = qbus_create(TYPE_XENSYSBUS, xen_sysdev, "xen-sysbus"); qbus_set_bus_hotplug_handler(xen_sysbus, &error_abort); diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c index 4dbc1a1614..e47e1de676 100644 --- a/hw/xtensa/virt.c +++ b/hw/xtensa/virt.c @@ -63,7 +63,7 @@ static void create_pcie(CPUXtensaState *env, int irq_base, hwaddr addr_base) int i; dev = qdev_new(TYPE_GPEX_HOST); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); /* Map only the first size_ecam bytes of ECAM space. */ ecam_alias = g_new0(MemoryRegion, 1); diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index eab5c8062e..5d0834c1d9 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -150,9 +150,9 @@ static void xtfpga_net_init(MemoryRegion *address_space, dev = qdev_new("open_eth"); qdev_set_nic_properties(dev, nd); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); sysbus_connect_irq(s, 0, irq); memory_region_add_subregion(address_space, base, sysbus_mmio_get_region(s, 0)); @@ -181,8 +181,8 @@ static PFlashCFI01 *xtfpga_flash_init(MemoryRegion *address_space, qdev_prop_set_uint8(dev, "width", 2); qdev_prop_set_bit(dev, "big-endian", be); qdev_prop_set_string(dev, "name", "xtfpga.io.flash"); - qdev_realize_and_unref(dev, NULL, &error_fatal); s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); memory_region_add_subregion(address_space, board->flash->base, sysbus_mmio_get_region(s, 0)); return PFLASH_CFI01(dev); diff --git a/include/hw/char/cadence_uart.h b/include/hw/char/cadence_uart.h index af80b6083b..ed7b58d31d 100644 --- a/include/hw/char/cadence_uart.h +++ b/include/hw/char/cadence_uart.h @@ -63,7 +63,7 @@ static inline DeviceState *cadence_uart_create(hwaddr addr, dev = qdev_new(TYPE_CADENCE_UART); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); diff --git a/include/hw/char/cmsdk-apb-uart.h b/include/hw/char/cmsdk-apb-uart.h index a51471ff74..bc9069f9fd 100644 --- a/include/hw/char/cmsdk-apb-uart.h +++ b/include/hw/char/cmsdk-apb-uart.h @@ -66,7 +66,7 @@ static inline DeviceState *cmsdk_apb_uart_create(hwaddr addr, s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); qdev_prop_set_uint32(dev, "pclk-frq", pclk_frq); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, txint); sysbus_connect_irq(s, 1, rxint); diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h index 18e701b65d..bed758350f 100644 --- a/include/hw/char/pl011.h +++ b/include/hw/char/pl011.h @@ -61,7 +61,7 @@ static inline DeviceState *pl011_create(hwaddr addr, dev = qdev_new("pl011"); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); @@ -78,7 +78,7 @@ static inline DeviceState *pl011_luminary_create(hwaddr addr, dev = qdev_new("pl011_luminary"); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); diff --git a/include/hw/char/xilinx_uartlite.h b/include/hw/char/xilinx_uartlite.h index 007b84575f..bb32d0fcb3 100644 --- a/include/hw/char/xilinx_uartlite.h +++ b/include/hw/char/xilinx_uartlite.h @@ -28,7 +28,7 @@ static inline DeviceState *xilinx_uartlite_create(hwaddr addr, dev = qdev_new("xlnx.xps-uartlite"); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); diff --git a/include/hw/cris/etraxfs.h b/include/hw/cris/etraxfs.h index 19b903facf..9e99380e0c 100644 --- a/include/hw/cris/etraxfs.h +++ b/include/hw/cris/etraxfs.h @@ -44,7 +44,7 @@ static inline DeviceState *etraxfs_ser_create(hwaddr addr, dev = qdev_new("etraxfs,serial"); s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, irq); return dev; diff --git a/include/hw/misc/unimp.h b/include/hw/misc/unimp.h index e71ec17e13..4c1d13c9bf 100644 --- a/include/hw/misc/unimp.h +++ b/include/hw/misc/unimp.h @@ -45,7 +45,7 @@ static inline void create_unimplemented_device(const char *name, qdev_prop_set_string(dev, "name", name); qdev_prop_set_uint64(dev, "size", size); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(dev), 0, base, -1000); } diff --git a/include/hw/timer/cmsdk-apb-timer.h b/include/hw/timer/cmsdk-apb-timer.h index eee175eaa4..f24bda6a46 100644 --- a/include/hw/timer/cmsdk-apb-timer.h +++ b/include/hw/timer/cmsdk-apb-timer.h @@ -51,7 +51,7 @@ static inline DeviceState *cmsdk_apb_timer_create(hwaddr addr, dev = qdev_new(TYPE_CMSDK_APB_TIMER); s = SYS_BUS_DEVICE(dev); qdev_prop_set_uint32(dev, "pclk-frq", pclk_frq); - qdev_realize_and_unref(dev, NULL, &error_fatal); + sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, addr); sysbus_connect_irq(s, 0, timerint); return dev; From cfe91404c516551de88afbe57433a39dcdacf3c4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:35 +0200 Subject: [PATCH 1271/2595] qdev: Drop qdev_realize() support for null bus The "null @bus means main system bus" convenience feature is no longer used. Drop it. Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-47-armbru@redhat.com> --- hw/core/qdev.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index a1fdebb3aa..78a06db76e 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -408,8 +408,7 @@ void qdev_init_nofail(DeviceState *dev) /* * Realize @dev. * @dev must not be plugged into a bus. - * Plug @dev into @bus if non-null, else into the main system bus. - * This takes a reference to @dev. + * Plug @dev into @bus. This takes a reference to @dev. * If @dev has no QOM parent, make one up, taking another reference. * On success, return true. * On failure, store an error through @errp and return false. @@ -419,18 +418,7 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) Error *err = NULL; assert(!dev->realized && !dev->parent_bus); - - if (!bus) { - /* - * Assert that the device really is a SysBusDevice before we - * put it onto the sysbus. Non-sysbus devices which aren't - * being put onto a bus should be realized with - * object_property_set_bool(OBJECT(dev), true, "realized", - * errp); - */ - g_assert(object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)); - bus = sysbus_get_default(); - } + assert(bus); qdev_set_parent_bus(dev, bus); From 0074fce61fecf40326845fa859119bbdd96df620 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:36 +0200 Subject: [PATCH 1272/2595] sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 1 I'm converting from qdev_set_parent_bus()/realize to qdev_realize(); recent commit "qdev: Convert uses of qdev_set_parent_bus() with Coccinelle" explains why. sysbus_init_child_obj() is a wrapper around object_initialize_child_with_props() and qdev_set_parent_bus(). It passes no properties. Convert sysbus_init_child_obj()/realize to object_initialize_child()/ qdev_realize(). Coccinelle script: @@ expression parent, name, size, type, errp; expression child; symbol true; @@ - sysbus_init_child_obj(parent, name, &child, size, type); + sysbus_init_child_XXX(parent, name, &child, size, type); ... - object_property_set_bool(OBJECT(&child), true, "realized", errp); + sysbus_realize(SYS_BUS_DEVICE(&child), errp); @@ expression parent, name, size, type, errp; expression child; symbol true; @@ - sysbus_init_child_obj(parent, name, child, size, type); + sysbus_init_child_XXX(parent, name, child, size, type); ... - object_property_set_bool(OBJECT(child), true, "realized", errp); + sysbus_realize(SYS_BUS_DEVICE(child), errp); @@ expression parent, name, size, type; expression child; expression dev; expression expr; @@ - sysbus_init_child_obj(parent, name, child, size, type); + sysbus_init_child_XXX(parent, name, child, size, type); ... dev = DEVICE(child); ... when != dev = expr; - qdev_init_nofail(dev); + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); @@ expression parent, propname, type; expression child; @@ - sysbus_init_child_XXX(parent, propname, child, sizeof(*child), type) + object_initialize_child(parent, propname, child, type) @@ expression parent, propname, type; expression child; @@ - sysbus_init_child_XXX(parent, propname, &child, sizeof(child), type) + object_initialize_child(parent, propname, &child, type) Signed-off-by: Markus Armbruster Acked-by: Alistair Francis Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-48-armbru@redhat.com> --- hw/arm/bcm2835_peripherals.c | 5 ++-- hw/arm/exynos4_boards.c | 7 +++-- hw/arm/mps2-tz.c | 50 ++++++++++++++++-------------------- hw/arm/mps2.c | 19 +++++--------- hw/arm/musca.c | 37 ++++++++++++-------------- hw/arm/xlnx-versal-virt.c | 6 ++--- hw/arm/xlnx-versal.c | 36 +++++++++++--------------- hw/intc/armv7m_nvic.c | 8 +++--- hw/mips/boston.c | 6 ++--- hw/mips/cps.c | 20 ++++++--------- hw/mips/malta.c | 6 ++--- hw/misc/mac_via.c | 14 +++++----- hw/riscv/spike.c | 7 +++-- hw/riscv/virt.c | 7 +++-- 14 files changed, 96 insertions(+), 132 deletions(-) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 188b112c13..987e394ec8 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -27,11 +27,10 @@ static void create_unimp(BCM2835PeripheralState *ps, UnimplementedDeviceState *uds, const char *name, hwaddr ofs, hwaddr size) { - sysbus_init_child_obj(OBJECT(ps), name, uds, sizeof(*uds), - TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(OBJECT(ps), name, uds, TYPE_UNIMPLEMENTED_DEVICE); qdev_prop_set_string(DEVICE(uds), "name", name); qdev_prop_set_uint64(DEVICE(uds), "size", size); - object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(uds), &error_fatal); memory_region_add_subregion_overlap(&ps->peri_mr, ofs, sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0), -1000); } diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index 326122abff..56b729141b 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -128,10 +128,9 @@ exynos4_boards_init_common(MachineState *machine, exynos4_boards_init_ram(s, get_system_memory(), exynos4_board_ram_size[board_type]); - sysbus_init_child_obj(OBJECT(machine), "soc", - &s->soc, sizeof(s->soc), TYPE_EXYNOS4210_SOC); - object_property_set_bool(OBJECT(&s->soc), true, "realized", - &error_fatal); + object_initialize_child(OBJECT(machine), "soc", &s->soc, + TYPE_EXYNOS4210_SOC); + sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal); return s; } diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 4c49512e0b..a2b20fff37 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -174,11 +174,10 @@ static MemoryRegion *make_unimp_dev(MPS2TZMachineState *mms, */ UnimplementedDeviceState *uds = opaque; - sysbus_init_child_obj(OBJECT(mms), name, uds, sizeof(*uds), - TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(OBJECT(mms), name, uds, TYPE_UNIMPLEMENTED_DEVICE); qdev_prop_set_string(DEVICE(uds), "name", name); qdev_prop_set_uint64(DEVICE(uds), "size", size); - object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(uds), &error_fatal); return sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0); } @@ -193,11 +192,10 @@ static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque, SysBusDevice *s; DeviceState *orgate_dev = DEVICE(&mms->uart_irq_orgate); - sysbus_init_child_obj(OBJECT(mms), name, uart, sizeof(*uart), - TYPE_CMSDK_APB_UART); + object_initialize_child(OBJECT(mms), name, uart, TYPE_CMSDK_APB_UART); qdev_prop_set_chr(DEVICE(uart), "chardev", serial_hd(i)); qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", SYSCLK_FRQ); - object_property_set_bool(OBJECT(uart), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(uart), &error_fatal); s = SYS_BUS_DEVICE(uart); sysbus_connect_irq(s, 0, get_sse_irq_in(mms, txirqno)); sysbus_connect_irq(s, 1, get_sse_irq_in(mms, rxirqno)); @@ -214,13 +212,12 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque, DeviceState *sccdev; MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); - sysbus_init_child_obj(OBJECT(mms), "scc", scc, sizeof(*scc), - TYPE_MPS2_SCC); + object_initialize_child(OBJECT(mms), "scc", scc, TYPE_MPS2_SCC); sccdev = DEVICE(scc); qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008); qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); - object_property_set_bool(OBJECT(scc), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(scc), &error_fatal); return sysbus_mmio_get_region(SYS_BUS_DEVICE(sccdev), 0); } @@ -229,9 +226,8 @@ static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque, { MPS2FPGAIO *fpgaio = opaque; - sysbus_init_child_obj(OBJECT(mms), "fpgaio", fpgaio, sizeof(*fpgaio), - TYPE_MPS2_FPGAIO); - object_property_set_bool(OBJECT(fpgaio), true, "realized", &error_fatal); + object_initialize_child(OBJECT(mms), "fpgaio", fpgaio, TYPE_MPS2_FPGAIO); + sysbus_realize(SYS_BUS_DEVICE(fpgaio), &error_fatal); return sysbus_mmio_get_region(SYS_BUS_DEVICE(fpgaio), 0); } @@ -267,11 +263,10 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque, memory_region_init_ram(ssram, NULL, name, ramsize[i], &error_fatal); - sysbus_init_child_obj(OBJECT(mms), mpcname, mpc, sizeof(*mpc), - TYPE_TZ_MPC); + object_initialize_child(OBJECT(mms), mpcname, mpc, TYPE_TZ_MPC); object_property_set_link(OBJECT(mpc), OBJECT(ssram), "downstream", &error_fatal); - object_property_set_bool(OBJECT(mpc), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(mpc), &error_fatal); /* Map the upstream end of the MPC into system memory */ upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1); memory_region_add_subregion(get_system_memory(), rambase[i], upstream); @@ -310,13 +305,13 @@ static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque, * the MSC connects to the IoTKit AHB Slave Expansion port, so the * DMA devices can see all devices and memory that the CPU does. */ - sysbus_init_child_obj(OBJECT(mms), mscname, msc, sizeof(*msc), TYPE_TZ_MSC); + object_initialize_child(OBJECT(mms), mscname, msc, TYPE_TZ_MSC); msc_downstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(&mms->iotkit), 0); object_property_set_link(OBJECT(msc), OBJECT(msc_downstream), "downstream", &error_fatal); object_property_set_link(OBJECT(msc), OBJECT(mms), "idau", &error_fatal); - object_property_set_bool(OBJECT(msc), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(msc), &error_fatal); qdev_connect_gpio_out_named(DEVICE(msc), "irq", 0, qdev_get_gpio_in_named(iotkitdev, @@ -333,10 +328,10 @@ static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque, "cfg_sec_resp", 0)); msc_upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(msc), 0); - sysbus_init_child_obj(OBJECT(mms), name, dma, sizeof(*dma), TYPE_PL081); + object_initialize_child(OBJECT(mms), name, dma, TYPE_PL081); object_property_set_link(OBJECT(dma), OBJECT(msc_upstream), "downstream", &error_fatal); - object_property_set_bool(OBJECT(dma), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(dma), &error_fatal); s = SYS_BUS_DEVICE(dma); /* Wire up DMACINTR, DMACINTERR, DMACINTTC */ @@ -363,8 +358,8 @@ static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque, int i = spi - &mms->spi[0]; SysBusDevice *s; - sysbus_init_child_obj(OBJECT(mms), name, spi, sizeof(*spi), TYPE_PL022); - object_property_set_bool(OBJECT(spi), true, "realized", &error_fatal); + object_initialize_child(OBJECT(mms), name, spi, TYPE_PL022); + sysbus_realize(SYS_BUS_DEVICE(spi), &error_fatal); s = SYS_BUS_DEVICE(spi); sysbus_connect_irq(s, 0, get_sse_irq_in(mms, 51 + i)); return sysbus_mmio_get_region(s, 0); @@ -393,15 +388,14 @@ static void mps2tz_common_init(MachineState *machine) exit(EXIT_FAILURE); } - sysbus_init_child_obj(OBJECT(machine), TYPE_IOTKIT, &mms->iotkit, - sizeof(mms->iotkit), mmc->armsse_type); + object_initialize_child(OBJECT(machine), TYPE_IOTKIT, &mms->iotkit, + mmc->armsse_type); iotkitdev = DEVICE(&mms->iotkit); object_property_set_link(OBJECT(&mms->iotkit), OBJECT(system_memory), "memory", &error_abort); qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", MPS2TZ_NUMIRQ); qdev_prop_set_uint32(iotkitdev, "MAINCLK", SYSCLK_FRQ); - object_property_set_bool(OBJECT(&mms->iotkit), true, "realized", - &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&mms->iotkit), &error_fatal); /* * The AN521 needs us to create splitters to feed the IRQ inputs @@ -549,8 +543,8 @@ static void mps2tz_common_init(MachineState *machine) int port; char *gpioname; - sysbus_init_child_obj(OBJECT(machine), ppcinfo->name, ppc, - sizeof(*ppc), TYPE_TZ_PPC); + object_initialize_child(OBJECT(machine), ppcinfo->name, ppc, + TYPE_TZ_PPC); ppcdev = DEVICE(ppc); for (port = 0; port < TZ_NUM_PORTS; port++) { @@ -569,7 +563,7 @@ static void mps2tz_common_init(MachineState *machine) g_free(portname); } - object_property_set_bool(OBJECT(ppc), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(ppc), &error_fatal); for (port = 0; port < TZ_NUM_PORTS; port++) { const PPCPortInfo *pinfo = &ppcinfo->ports[port]; diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index f246213206..735f44c7a3 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -180,8 +180,7 @@ static void mps2_common_init(MachineState *machine) g_assert_not_reached(); } - sysbus_init_child_obj(OBJECT(mms), "armv7m", &mms->armv7m, - sizeof(mms->armv7m), TYPE_ARMV7M); + object_initialize_child(OBJECT(mms), "armv7m", &mms->armv7m, TYPE_ARMV7M); armv7m = DEVICE(&mms->armv7m); switch (mmc->fpga_type) { case FPGA_AN385: @@ -197,8 +196,7 @@ static void mps2_common_init(MachineState *machine) qdev_prop_set_bit(armv7m, "enable-bitband", true); object_property_set_link(OBJECT(&mms->armv7m), OBJECT(system_memory), "memory", &error_abort); - object_property_set_bool(OBJECT(&mms->armv7m), true, "realized", - &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&mms->armv7m), &error_fatal); create_unimplemented_device("zbtsmram mirror", 0x00400000, 0x00400000); create_unimplemented_device("RESERVED 1", 0x00800000, 0x00800000); @@ -305,23 +303,20 @@ static void mps2_common_init(MachineState *machine) cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ); cmsdk_apb_timer_create(0x40001000, qdev_get_gpio_in(armv7m, 9), SYSCLK_FRQ); - sysbus_init_child_obj(OBJECT(mms), "dualtimer", &mms->dualtimer, - sizeof(mms->dualtimer), TYPE_CMSDK_APB_DUALTIMER); + object_initialize_child(OBJECT(mms), "dualtimer", &mms->dualtimer, + TYPE_CMSDK_APB_DUALTIMER); qdev_prop_set_uint32(DEVICE(&mms->dualtimer), "pclk-frq", SYSCLK_FRQ); - object_property_set_bool(OBJECT(&mms->dualtimer), true, "realized", - &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&mms->dualtimer), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0, qdev_get_gpio_in(armv7m, 10)); sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000); - sysbus_init_child_obj(OBJECT(mms), "scc", &mms->scc, - sizeof(mms->scc), TYPE_MPS2_SCC); + object_initialize_child(OBJECT(mms), "scc", &mms->scc, TYPE_MPS2_SCC); sccdev = DEVICE(&mms->scc); qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008); qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); - object_property_set_bool(OBJECT(&mms->scc), true, "realized", - &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&mms->scc), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(sccdev), 0, 0x4002f000); /* In hardware this is a LAN9220; the LAN9118 is software compatible diff --git a/hw/arm/musca.c b/hw/arm/musca.c index a1a6e887ed..d74042356d 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -142,11 +142,10 @@ static MemoryRegion *make_unimp_dev(MuscaMachineState *mms, */ UnimplementedDeviceState *uds = opaque; - sysbus_init_child_obj(OBJECT(mms), name, uds, sizeof(*uds), - TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(OBJECT(mms), name, uds, TYPE_UNIMPLEMENTED_DEVICE); qdev_prop_set_string(DEVICE(uds), "name", name); qdev_prop_set_uint64(DEVICE(uds), "size", size); - object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(uds), &error_fatal); return sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0); } @@ -245,22 +244,21 @@ static MemoryRegion *make_mpc(MuscaMachineState *mms, void *opaque, case MPC_CRYPTOISLAND: /* We don't implement the CryptoIsland yet */ uds = &mms->cryptoisland; - sysbus_init_child_obj(OBJECT(mms), name, uds, sizeof(*uds), - TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(OBJECT(mms), name, uds, + TYPE_UNIMPLEMENTED_DEVICE); qdev_prop_set_string(DEVICE(uds), "name", mpcinfo[i].name); qdev_prop_set_uint64(DEVICE(uds), "size", mpcinfo[i].size); - object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(uds), &error_fatal); downstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0); break; default: g_assert_not_reached(); } - sysbus_init_child_obj(OBJECT(mms), mpcname, mpc, sizeof(*mpc), - TYPE_TZ_MPC); + object_initialize_child(OBJECT(mms), mpcname, mpc, TYPE_TZ_MPC); object_property_set_link(OBJECT(mpc), OBJECT(downstream), "downstream", &error_fatal); - object_property_set_bool(OBJECT(mpc), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(mpc), &error_fatal); /* Map the upstream end of the MPC into system memory */ upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1); memory_region_add_subregion(get_system_memory(), mpcinfo[i].addr, upstream); @@ -279,8 +277,8 @@ static MemoryRegion *make_rtc(MuscaMachineState *mms, void *opaque, { PL031State *rtc = opaque; - sysbus_init_child_obj(OBJECT(mms), name, rtc, sizeof(*rtc), TYPE_PL031); - object_property_set_bool(OBJECT(rtc), true, "realized", &error_fatal); + object_initialize_child(OBJECT(mms), name, rtc, TYPE_PL031); + sysbus_realize(SYS_BUS_DEVICE(rtc), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(rtc), 0, get_sse_irq_in(mms, 39)); return sysbus_mmio_get_region(SYS_BUS_DEVICE(rtc), 0); } @@ -293,9 +291,9 @@ static MemoryRegion *make_uart(MuscaMachineState *mms, void *opaque, int irqbase = 7 + i * 6; SysBusDevice *s; - sysbus_init_child_obj(OBJECT(mms), name, uart, sizeof(*uart), TYPE_PL011); + object_initialize_child(OBJECT(mms), name, uart, TYPE_PL011); qdev_prop_set_chr(DEVICE(uart), "chardev", serial_hd(i)); - object_property_set_bool(OBJECT(uart), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(uart), &error_fatal); s = SYS_BUS_DEVICE(uart); sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqbase + 5)); /* combined */ sysbus_connect_irq(s, 1, get_sse_irq_in(mms, irqbase + 0)); /* RX */ @@ -373,8 +371,8 @@ static void musca_init(MachineState *machine) exit(1); } - sysbus_init_child_obj(OBJECT(machine), "sse-200", &mms->sse, - sizeof(mms->sse), TYPE_SSE200); + object_initialize_child(OBJECT(machine), "sse-200", &mms->sse, + TYPE_SSE200); ssedev = DEVICE(&mms->sse); object_property_set_link(OBJECT(&mms->sse), OBJECT(system_memory), "memory", &error_fatal); @@ -390,8 +388,7 @@ static void musca_init(MachineState *machine) qdev_prop_set_bit(ssedev, "CPU0_FPU", true); qdev_prop_set_bit(ssedev, "CPU0_DSP", true); } - object_property_set_bool(OBJECT(&mms->sse), true, "realized", - &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&mms->sse), &error_fatal); /* * We need to create splitters to feed the IRQ inputs @@ -531,8 +528,8 @@ static void musca_init(MachineState *machine) int port; char *gpioname; - sysbus_init_child_obj(OBJECT(machine), ppcinfo->name, ppc, - sizeof(*ppc), TYPE_TZ_PPC); + object_initialize_child(OBJECT(machine), ppcinfo->name, ppc, + TYPE_TZ_PPC); ppcdev = DEVICE(ppc); for (port = 0; port < TZ_NUM_PORTS; port++) { @@ -551,7 +548,7 @@ static void musca_init(MachineState *machine) g_free(portname); } - object_property_set_bool(OBJECT(ppc), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(ppc), &error_fatal); for (port = 0; port < TZ_NUM_PORTS; port++) { const PPCPortInfo *pinfo = &ppcinfo->ports[port]; diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 3d8431dbcf..5bcca7f95b 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -500,13 +500,13 @@ static void versal_virt_init(MachineState *machine) psci_conduit = QEMU_PSCI_CONDUIT_SMC; } - sysbus_init_child_obj(OBJECT(machine), "xlnx-versal", &s->soc, - sizeof(s->soc), TYPE_XLNX_VERSAL); + object_initialize_child(OBJECT(machine), "xlnx-versal", &s->soc, + TYPE_XLNX_VERSAL); object_property_set_link(OBJECT(&s->soc), OBJECT(machine->ram), "ddr", &error_abort); object_property_set_int(OBJECT(&s->soc), psci_conduit, "psci-conduit", &error_abort); - object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal); fdt_create(s); create_virtio_regions(s); diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 38d6b91d15..a27c315a6b 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -62,9 +62,8 @@ static void versal_create_apu_gic(Versal *s, qemu_irq *pic) int nr_apu_cpus = ARRAY_SIZE(s->fpd.apu.cpu); int i; - sysbus_init_child_obj(OBJECT(s), "apu-gic", - &s->fpd.apu.gic, sizeof(s->fpd.apu.gic), - gicv3_class_name()); + object_initialize_child(OBJECT(s), "apu-gic", &s->fpd.apu.gic, + gicv3_class_name()); gicbusdev = SYS_BUS_DEVICE(&s->fpd.apu.gic); gicdev = DEVICE(&s->fpd.apu.gic); qdev_prop_set_uint32(gicdev, "revision", 3); @@ -74,8 +73,7 @@ static void versal_create_apu_gic(Versal *s, qemu_irq *pic) qdev_prop_set_uint32(gicdev, "redist-region-count[0]", 2); qdev_prop_set_bit(gicdev, "has-security-extensions", true); - object_property_set_bool(OBJECT(&s->fpd.apu.gic), true, "realized", - &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->fpd.apu.gic), &error_fatal); for (i = 0; i < ARRAY_SIZE(addrs); i++) { MemoryRegion *mr; @@ -133,12 +131,11 @@ static void versal_create_uarts(Versal *s, qemu_irq *pic) DeviceState *dev; MemoryRegion *mr; - sysbus_init_child_obj(OBJECT(s), name, - &s->lpd.iou.uart[i], sizeof(s->lpd.iou.uart[i]), - TYPE_PL011); + object_initialize_child(OBJECT(s), name, &s->lpd.iou.uart[i], + TYPE_PL011); dev = DEVICE(&s->lpd.iou.uart[i]); qdev_prop_set_chr(dev, "chardev", serial_hd(i)); - qdev_init_nofail(dev); + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(&s->mr_ps, addrs[i], mr); @@ -160,9 +157,8 @@ static void versal_create_gems(Versal *s, qemu_irq *pic) DeviceState *dev; MemoryRegion *mr; - sysbus_init_child_obj(OBJECT(s), name, - &s->lpd.iou.gem[i], sizeof(s->lpd.iou.gem[i]), - TYPE_CADENCE_GEM); + object_initialize_child(OBJECT(s), name, &s->lpd.iou.gem[i], + TYPE_CADENCE_GEM); dev = DEVICE(&s->lpd.iou.gem[i]); if (nd->used) { qemu_check_nic_model(nd, "cadence_gem"); @@ -174,7 +170,7 @@ static void versal_create_gems(Versal *s, qemu_irq *pic) object_property_set_link(OBJECT(dev), OBJECT(&s->mr_ps), "dma", &error_abort); - qdev_init_nofail(dev); + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(&s->mr_ps, addrs[i], mr); @@ -193,12 +189,11 @@ static void versal_create_admas(Versal *s, qemu_irq *pic) DeviceState *dev; MemoryRegion *mr; - sysbus_init_child_obj(OBJECT(s), name, - &s->lpd.iou.adma[i], sizeof(s->lpd.iou.adma[i]), - TYPE_XLNX_ZDMA); + object_initialize_child(OBJECT(s), name, &s->lpd.iou.adma[i], + TYPE_XLNX_ZDMA); dev = DEVICE(&s->lpd.iou.adma[i]); object_property_set_int(OBJECT(dev), 128, "bus-width", &error_abort); - qdev_init_nofail(dev); + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(&s->mr_ps, @@ -218,9 +213,8 @@ static void versal_create_sds(Versal *s, qemu_irq *pic) DeviceState *dev; MemoryRegion *mr; - sysbus_init_child_obj(OBJECT(s), "sd[*]", - &s->pmc.iou.sd[i], sizeof(s->pmc.iou.sd[i]), - TYPE_SYSBUS_SDHCI); + object_initialize_child(OBJECT(s), "sd[*]", &s->pmc.iou.sd[i], + TYPE_SYSBUS_SDHCI); dev = DEVICE(&s->pmc.iou.sd[i]); object_property_set_uint(OBJECT(dev), @@ -228,7 +222,7 @@ static void versal_create_sds(Versal *s, qemu_irq *pic) object_property_set_uint(OBJECT(dev), SDHCI_CAPABILITIES, "capareg", &error_fatal); object_property_set_uint(OBJECT(dev), UHS_I, "uhs", &error_fatal); - qdev_init_nofail(dev); + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(&s->mr_ps, diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 1ad35e5529..f035079168 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -2655,12 +2655,10 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) * as we didn't know then if the CPU had the security extensions; * so we have to do it here. */ - sysbus_init_child_obj(OBJECT(dev), "systick-reg-s", - &s->systick[M_REG_S], - sizeof(s->systick[M_REG_S]), TYPE_SYSTICK); + object_initialize_child(OBJECT(dev), "systick-reg-s", + &s->systick[M_REG_S], TYPE_SYSTICK); - object_property_set_bool(OBJECT(&s->systick[M_REG_S]), true, - "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_S]), &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/mips/boston.c b/hw/mips/boston.c index 03008b5581..f5d4ac8cd4 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -454,14 +454,12 @@ static void boston_mach_init(MachineState *machine) is_64b = cpu_supports_isa(machine->cpu_type, ISA_MIPS64); - sysbus_init_child_obj(OBJECT(machine), "cps", &s->cps, sizeof(s->cps), - TYPE_MIPS_CPS); + object_initialize_child(OBJECT(machine), "cps", &s->cps, TYPE_MIPS_CPS); object_property_set_str(OBJECT(&s->cps), machine->cpu_type, "cpu-type", &error_fatal); object_property_set_int(OBJECT(&s->cps), machine->smp.cpus, "num-vp", &error_fatal); - object_property_set_bool(OBJECT(&s->cps), true, "realized", - &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->cps), &error_fatal); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1); diff --git a/hw/mips/cps.c b/hw/mips/cps.c index 92b9b1a5f6..cdfab19826 100644 --- a/hw/mips/cps.c +++ b/hw/mips/cps.c @@ -99,8 +99,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) /* Inter-Thread Communication Unit */ if (itu_present) { - sysbus_init_child_obj(OBJECT(dev), "itu", &s->itu, sizeof(s->itu), - TYPE_MIPS_ITU); + object_initialize_child(OBJECT(dev), "itu", &s->itu, TYPE_MIPS_ITU); object_property_set_int(OBJECT(&s->itu), 16, "num-fifo", &err); object_property_set_int(OBJECT(&s->itu), 16, "num-semaphores", &err); object_property_set_bool(OBJECT(&s->itu), saar_present, "saar-present", @@ -108,7 +107,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) if (saar_present) { s->itu.saar = &env->CP0_SAAR; } - object_property_set_bool(OBJECT(&s->itu), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->itu), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -119,11 +118,10 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) } /* Cluster Power Controller */ - sysbus_init_child_obj(OBJECT(dev), "cpc", &s->cpc, sizeof(s->cpc), - TYPE_MIPS_CPC); + object_initialize_child(OBJECT(dev), "cpc", &s->cpc, TYPE_MIPS_CPC); object_property_set_int(OBJECT(&s->cpc), s->num_vp, "num-vp", &err); object_property_set_int(OBJECT(&s->cpc), 1, "vp-start-running", &err); - object_property_set_bool(OBJECT(&s->cpc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->cpc), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -133,11 +131,10 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpc), 0)); /* Global Interrupt Controller */ - sysbus_init_child_obj(OBJECT(dev), "gic", &s->gic, sizeof(s->gic), - TYPE_MIPS_GIC); + object_initialize_child(OBJECT(dev), "gic", &s->gic, TYPE_MIPS_GIC); object_property_set_int(OBJECT(&s->gic), s->num_vp, "num-vp", &err); object_property_set_int(OBJECT(&s->gic), 128, "num-irq", &err); - object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -149,14 +146,13 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) /* Global Configuration Registers */ gcr_base = env->CP0_CMGCRBase << 4; - sysbus_init_child_obj(OBJECT(dev), "gcr", &s->gcr, sizeof(s->gcr), - TYPE_MIPS_GCR); + object_initialize_child(OBJECT(dev), "gcr", &s->gcr, TYPE_MIPS_GCR); object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp", &err); object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev", &err); object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base", &err); object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->gic.mr), "gic", &err); object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc", &err); - object_property_set_bool(OBJECT(&s->gcr), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gcr), &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 7df4768170..d95926a89c 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -1183,14 +1183,12 @@ static void create_cpu_without_cps(MachineState *ms, static void create_cps(MachineState *ms, MaltaState *s, qemu_irq *cbus_irq, qemu_irq *i8259_irq) { - sysbus_init_child_obj(OBJECT(s), "cps", &s->cps, sizeof(s->cps), - TYPE_MIPS_CPS); + object_initialize_child(OBJECT(s), "cps", &s->cps, TYPE_MIPS_CPS); object_property_set_str(OBJECT(&s->cps), ms->cpu_type, "cpu-type", &error_fatal); object_property_set_int(OBJECT(&s->cps), ms->smp.cpus, "num-vp", &error_fatal); - object_property_set_bool(OBJECT(&s->cps), true, "realized", - &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->cps), &error_fatal); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1); diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 82614c155a..9cd313c812 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -876,11 +876,11 @@ static void mac_via_realize(DeviceState *dev, Error **errp) int ret; /* Init VIAs 1 and 2 */ - sysbus_init_child_obj(OBJECT(dev), "via1", &m->mos6522_via1, - sizeof(m->mos6522_via1), TYPE_MOS6522_Q800_VIA1); + object_initialize_child(OBJECT(dev), "via1", &m->mos6522_via1, + TYPE_MOS6522_Q800_VIA1); - sysbus_init_child_obj(OBJECT(dev), "via2", &m->mos6522_via2, - sizeof(m->mos6522_via2), TYPE_MOS6522_Q800_VIA2); + object_initialize_child(OBJECT(dev), "via2", &m->mos6522_via2, + TYPE_MOS6522_Q800_VIA2); /* Pass through mos6522 output IRQs */ ms = MOS6522(&m->mos6522_via1); @@ -890,10 +890,8 @@ static void mac_via_realize(DeviceState *dev, Error **errp) object_property_add_alias(OBJECT(dev), "irq[1]", OBJECT(ms), SYSBUS_DEVICE_GPIO_IRQ "[0]"); - object_property_set_bool(OBJECT(&m->mos6522_via1), true, "realized", - &error_abort); - object_property_set_bool(OBJECT(&m->mos6522_via2), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&m->mos6522_via1), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&m->mos6522_via2), &error_abort); /* Pass through mos6522 input IRQs */ qdev_pass_gpios(DEVICE(&m->mos6522_via1), dev, "via1-irq"); diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 7d1119dcb6..3c87e04fdc 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -169,14 +169,13 @@ static void spike_board_init(MachineState *machine) unsigned int smp_cpus = machine->smp.cpus; /* Initialize SOC */ - sysbus_init_child_obj(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), - TYPE_RISCV_HART_ARRAY); + object_initialize_child(OBJECT(machine), "soc", &s->soc, + TYPE_RISCV_HART_ARRAY); object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type", &error_abort); object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts", &error_abort); - object_property_set_bool(OBJECT(&s->soc), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_abort); /* register system main memory (actual RAM) */ memory_region_init_ram(main_mem, NULL, "riscv.spike.ram", diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 01d50d29bb..616db6f5ac 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -485,14 +485,13 @@ static void virt_machine_init(MachineState *machine) unsigned int smp_cpus = machine->smp.cpus; /* Initialize SOC */ - sysbus_init_child_obj(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), - TYPE_RISCV_HART_ARRAY); + object_initialize_child(OBJECT(machine), "soc", &s->soc, + TYPE_RISCV_HART_ARRAY); object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type", &error_abort); object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts", &error_abort); - object_property_set_bool(OBJECT(&s->soc), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_abort); /* register system main memory (actual RAM) */ memory_region_init_ram(main_mem, NULL, "riscv_virt_board.ram", From db873cc5d1a4aaa67eea87768d504b2f89d88738 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:37 +0200 Subject: [PATCH 1273/2595] sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 2 This is the same transformation as in the previous commit, except sysbus_init_child_obj() and realize are too separated for the commit's Coccinelle script to handle, typically because sysbus_init_child_obj() is in a device's instance_init() method, and the matching realize is in its realize() method. Perhaps a Coccinelle wizard could make it transform that pattern, but I'm just a bungler, and the best I can do is transforming the two separate parts separately: @@ expression errp; expression child; symbol true; @@ - object_property_set_bool(OBJECT(child), true, "realized", errp); + sysbus_realize(SYS_BUS_DEVICE(child), errp); // only correct with a matching sysbus_init_child_obj() transformation! @@ expression errp; expression child; symbol true; @@ - object_property_set_bool(child, true, "realized", errp); + sysbus_realize(SYS_BUS_DEVICE(child), errp); // only correct with a matching sysbus_init_child_obj() transformation! @@ expression child; @@ - qdev_init_nofail(DEVICE(child)); + sysbus_realize(SYS_BUS_DEVICE(child), &error_fatal); // only correct with a matching sysbus_init_child_obj() transformation! @@ expression child; expression dev; @@ dev = DEVICE(child); ... - qdev_init_nofail(dev); + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); // only correct with a matching sysbus_init_child_obj() transformation! @@ expression child; identifier dev; @@ DeviceState *dev = DEVICE(child); ... - qdev_init_nofail(dev); + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); // only correct with a matching sysbus_init_child_obj() transformation! @@ expression parent, name, size, type; expression child; symbol true; @@ - sysbus_init_child_obj(parent, name, child, size, type); + sysbus_init_child_XXX(parent, name, child, size, type); @@ expression parent, propname, type; expression child; @@ - sysbus_init_child_XXX(parent, propname, child, sizeof(*child), type) + object_initialize_child(parent, propname, child, type) @@ expression parent, propname, type; expression child; @@ - sysbus_init_child_XXX(parent, propname, &child, sizeof(child), type) + object_initialize_child(parent, propname, &child, type) This script is *unsound*: we need to manually verify init and realize conversions are properly paired. This commit has only the pairs where object_initialize_child()'s @child and sysbus_realize()'s @dev argument text match exactly within the same source file. Note that Coccinelle chokes on ARMSSE typedef vs. macro in hw/arm/armsse.c. Worked around by temporarily renaming the macro for the spatch run. Signed-off-by: Markus Armbruster Acked-by: Alistair Francis Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-49-armbru@redhat.com> --- hw/arm/allwinner-a10.c | 43 ++++++--------- hw/arm/allwinner-h3.c | 50 +++++++---------- hw/arm/armsse.c | 96 ++++++++++++++------------------ hw/arm/armv7m.c | 4 +- hw/arm/aspeed_ast2600.c | 89 +++++++++++++----------------- hw/arm/aspeed_soc.c | 69 ++++++++++------------- hw/arm/bcm2835_peripherals.c | 75 +++++++++++-------------- hw/arm/bcm2836.c | 11 ++-- hw/arm/digic.c | 10 ++-- hw/arm/fsl-imx25.c | 58 ++++++++----------- hw/arm/fsl-imx31.c | 37 ++++++------- hw/arm/fsl-imx6.c | 69 ++++++++++------------- hw/arm/fsl-imx6ul.c | 98 ++++++++++++--------------------- hw/arm/fsl-imx7.c | 93 +++++++++++-------------------- hw/arm/msf2-soc.c | 25 ++++----- hw/arm/nrf51_soc.c | 30 +++++----- hw/arm/stm32f205_soc.c | 32 +++++------ hw/arm/stm32f405_soc.c | 37 ++++++------- hw/arm/xlnx-zynqmp.c | 60 +++++++++----------- hw/cpu/a15mpcore.c | 5 +- hw/cpu/a9mpcore.c | 23 ++++---- hw/cpu/arm11mpcore.c | 18 +++--- hw/cpu/realview_mpcore.c | 5 +- hw/intc/realview_gic.c | 4 +- hw/microblaze/xlnx-zynqmp-pmu.c | 11 ++-- hw/misc/macio/cuda.c | 8 +-- hw/misc/macio/pmu.c | 8 +-- hw/ppc/pnv.c | 6 +- hw/riscv/opentitan.c | 6 +- hw/riscv/sifive_e.c | 13 ++--- hw/riscv/sifive_u.c | 31 ++++------- 31 files changed, 463 insertions(+), 661 deletions(-) diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 64449416de..e05099c757 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -44,33 +44,28 @@ static void aw_a10_init(Object *obj) object_initialize_child(obj, "cpu", &s->cpu, ARM_CPU_TYPE_NAME("cortex-a8")); - sysbus_init_child_obj(obj, "intc", &s->intc, sizeof(s->intc), - TYPE_AW_A10_PIC); + object_initialize_child(obj, "intc", &s->intc, TYPE_AW_A10_PIC); - sysbus_init_child_obj(obj, "timer", &s->timer, sizeof(s->timer), - TYPE_AW_A10_PIT); + object_initialize_child(obj, "timer", &s->timer, TYPE_AW_A10_PIT); - sysbus_init_child_obj(obj, "emac", &s->emac, sizeof(s->emac), TYPE_AW_EMAC); + object_initialize_child(obj, "emac", &s->emac, TYPE_AW_EMAC); - sysbus_init_child_obj(obj, "sata", &s->sata, sizeof(s->sata), - TYPE_ALLWINNER_AHCI); + object_initialize_child(obj, "sata", &s->sata, TYPE_ALLWINNER_AHCI); if (machine_usb(current_machine)) { int i; for (i = 0; i < AW_A10_NUM_USB; i++) { - sysbus_init_child_obj(obj, "ehci[*]", &s->ehci[i], - sizeof(s->ehci[i]), TYPE_PLATFORM_EHCI); - sysbus_init_child_obj(obj, "ohci[*]", &s->ohci[i], - sizeof(s->ohci[i]), TYPE_SYSBUS_OHCI); + object_initialize_child(obj, "ehci[*]", &s->ehci[i], + TYPE_PLATFORM_EHCI); + object_initialize_child(obj, "ohci[*]", &s->ohci[i], + TYPE_SYSBUS_OHCI); } } - sysbus_init_child_obj(obj, "mmc0", &s->mmc0, sizeof(s->mmc0), - TYPE_AW_SDHOST_SUN4I); + object_initialize_child(obj, "mmc0", &s->mmc0, TYPE_AW_SDHOST_SUN4I); - sysbus_init_child_obj(obj, "rtc", &s->rtc, sizeof(s->rtc), - TYPE_AW_RTC_SUN4I); + object_initialize_child(obj, "rtc", &s->rtc, TYPE_AW_RTC_SUN4I); } static void aw_a10_realize(DeviceState *dev, Error **errp) @@ -85,7 +80,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) return; } - object_property_set_bool(OBJECT(&s->intc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->intc), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -98,7 +93,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); qdev_pass_gpios(DEVICE(&s->intc), dev, NULL); - object_property_set_bool(OBJECT(&s->timer), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->timer), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -122,7 +117,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC); qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); } - object_property_set_bool(OBJECT(&s->emac), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->emac), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -131,7 +126,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(sysbusdev, 0, AW_A10_EMAC_BASE); sysbus_connect_irq(sysbusdev, 0, qdev_get_gpio_in(dev, 55)); - object_property_set_bool(OBJECT(&s->sata), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->sata), &err); if (err) { error_propagate(errp, err); return; @@ -154,8 +149,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) object_property_set_bool(OBJECT(&s->ehci[i]), true, "companion-enable", &error_fatal); - object_property_set_bool(OBJECT(&s->ehci[i]), true, "realized", - &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0, AW_A10_EHCI_BASE + i * 0x8000); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0, @@ -163,8 +157,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) object_property_set_str(OBJECT(&s->ohci[i]), bus, "masterbus", &error_fatal); - object_property_set_bool(OBJECT(&s->ohci[i]), true, "realized", - &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->ohci[i]), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci[i]), 0, AW_A10_OHCI_BASE + i * 0x8000); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci[i]), 0, @@ -173,14 +166,14 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) } /* SD/MMC */ - qdev_init_nofail(DEVICE(&s->mmc0)); + sysbus_realize(SYS_BUS_DEVICE(&s->mmc0), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc0), 0, AW_A10_MMC0_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc0), 0, qdev_get_gpio_in(dev, 32)); object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->mmc0), "sd-bus"); /* RTC */ - qdev_init_nofail(DEVICE(&s->rtc)); + sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &error_fatal); sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->rtc), 0, AW_A10_RTC_BASE, 10); } diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c index 7dc3671155..91d22640e4 100644 --- a/hw/arm/allwinner-h3.c +++ b/hw/arm/allwinner-h3.c @@ -198,45 +198,35 @@ static void allwinner_h3_init(Object *obj) ARM_CPU_TYPE_NAME("cortex-a7")); } - sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic), - TYPE_ARM_GIC); + object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC); - sysbus_init_child_obj(obj, "timer", &s->timer, sizeof(s->timer), - TYPE_AW_A10_PIT); + object_initialize_child(obj, "timer", &s->timer, TYPE_AW_A10_PIT); object_property_add_alias(obj, "clk0-freq", OBJECT(&s->timer), "clk0-freq"); object_property_add_alias(obj, "clk1-freq", OBJECT(&s->timer), "clk1-freq"); - sysbus_init_child_obj(obj, "ccu", &s->ccu, sizeof(s->ccu), - TYPE_AW_H3_CCU); + object_initialize_child(obj, "ccu", &s->ccu, TYPE_AW_H3_CCU); - sysbus_init_child_obj(obj, "sysctrl", &s->sysctrl, sizeof(s->sysctrl), - TYPE_AW_H3_SYSCTRL); + object_initialize_child(obj, "sysctrl", &s->sysctrl, TYPE_AW_H3_SYSCTRL); - sysbus_init_child_obj(obj, "cpucfg", &s->cpucfg, sizeof(s->cpucfg), - TYPE_AW_CPUCFG); + object_initialize_child(obj, "cpucfg", &s->cpucfg, TYPE_AW_CPUCFG); - sysbus_init_child_obj(obj, "sid", &s->sid, sizeof(s->sid), - TYPE_AW_SID); + object_initialize_child(obj, "sid", &s->sid, TYPE_AW_SID); object_property_add_alias(obj, "identifier", OBJECT(&s->sid), "identifier"); - sysbus_init_child_obj(obj, "mmc0", &s->mmc0, sizeof(s->mmc0), - TYPE_AW_SDHOST_SUN5I); + object_initialize_child(obj, "mmc0", &s->mmc0, TYPE_AW_SDHOST_SUN5I); - sysbus_init_child_obj(obj, "emac", &s->emac, sizeof(s->emac), - TYPE_AW_SUN8I_EMAC); + object_initialize_child(obj, "emac", &s->emac, TYPE_AW_SUN8I_EMAC); - sysbus_init_child_obj(obj, "dramc", &s->dramc, sizeof(s->dramc), - TYPE_AW_H3_DRAMC); + object_initialize_child(obj, "dramc", &s->dramc, TYPE_AW_H3_DRAMC); object_property_add_alias(obj, "ram-addr", OBJECT(&s->dramc), "ram-addr"); object_property_add_alias(obj, "ram-size", OBJECT(&s->dramc), "ram-size"); - sysbus_init_child_obj(obj, "rtc", &s->rtc, sizeof(s->rtc), - TYPE_AW_RTC_SUN6I); + object_initialize_child(obj, "rtc", &s->rtc, TYPE_AW_RTC_SUN6I); } static void allwinner_h3_realize(DeviceState *dev, Error **errp) @@ -270,7 +260,7 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", AW_H3_NUM_CPUS); qdev_prop_set_bit(DEVICE(&s->gic), "has-security-extensions", false); qdev_prop_set_bit(DEVICE(&s->gic), "has-virtualization-extensions", true); - qdev_init_nofail(DEVICE(&s->gic)); + sysbus_realize(SYS_BUS_DEVICE(&s->gic), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0, s->memmap[AW_H3_GIC_DIST]); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1, s->memmap[AW_H3_GIC_CPU]); @@ -321,7 +311,7 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) } /* Timer */ - qdev_init_nofail(DEVICE(&s->timer)); + sysbus_realize(SYS_BUS_DEVICE(&s->timer), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->timer), 0, s->memmap[AW_H3_PIT]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer), 0, qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_TIMER0)); @@ -343,23 +333,23 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) &s->sram_c); /* Clock Control Unit */ - qdev_init_nofail(DEVICE(&s->ccu)); + sysbus_realize(SYS_BUS_DEVICE(&s->ccu), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccu), 0, s->memmap[AW_H3_CCU]); /* System Control */ - qdev_init_nofail(DEVICE(&s->sysctrl)); + sysbus_realize(SYS_BUS_DEVICE(&s->sysctrl), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctrl), 0, s->memmap[AW_H3_SYSCTRL]); /* CPU Configuration */ - qdev_init_nofail(DEVICE(&s->cpucfg)); + sysbus_realize(SYS_BUS_DEVICE(&s->cpucfg), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->cpucfg), 0, s->memmap[AW_H3_CPUCFG]); /* Security Identifier */ - qdev_init_nofail(DEVICE(&s->sid)); + sysbus_realize(SYS_BUS_DEVICE(&s->sid), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->sid), 0, s->memmap[AW_H3_SID]); /* SD/MMC */ - qdev_init_nofail(DEVICE(&s->mmc0)); + sysbus_realize(SYS_BUS_DEVICE(&s->mmc0), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc0), 0, s->memmap[AW_H3_MMC0]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc0), 0, qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_MMC0)); @@ -372,7 +362,7 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) qemu_check_nic_model(&nd_table[0], TYPE_AW_SUN8I_EMAC); qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); } - qdev_init_nofail(DEVICE(&s->emac)); + sysbus_realize(SYS_BUS_DEVICE(&s->emac), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->emac), 0, s->memmap[AW_H3_EMAC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->emac), 0, qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_EMAC)); @@ -422,13 +412,13 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) 115200, serial_hd(3), DEVICE_NATIVE_ENDIAN); /* DRAMC */ - qdev_init_nofail(DEVICE(&s->dramc)); + sysbus_realize(SYS_BUS_DEVICE(&s->dramc), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 0, s->memmap[AW_H3_DRAMCOM]); sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 1, s->memmap[AW_H3_DRAMCTL]); sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 2, s->memmap[AW_H3_DRAMPHY]); /* RTC */ - qdev_init_nofail(DEVICE(&s->rtc)); + sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, s->memmap[AW_H3_RTC]); /* Unimplemented devices */ diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index f042145e6e..6571c1ed4c 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -273,16 +273,12 @@ static void armsse_init(Object *obj) } } - sysbus_init_child_obj(obj, "secctl", &s->secctl, sizeof(s->secctl), - TYPE_IOTKIT_SECCTL); - sysbus_init_child_obj(obj, "apb-ppc0", &s->apb_ppc0, sizeof(s->apb_ppc0), - TYPE_TZ_PPC); - sysbus_init_child_obj(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1), - TYPE_TZ_PPC); + object_initialize_child(obj, "secctl", &s->secctl, TYPE_IOTKIT_SECCTL); + object_initialize_child(obj, "apb-ppc0", &s->apb_ppc0, TYPE_TZ_PPC); + object_initialize_child(obj, "apb-ppc1", &s->apb_ppc1, TYPE_TZ_PPC); for (i = 0; i < info->sram_banks; i++) { char *name = g_strdup_printf("mpc%d", i); - sysbus_init_child_obj(obj, name, &s->mpc[i], - sizeof(s->mpc[i]), TYPE_TZ_MPC); + object_initialize_child(obj, name, &s->mpc[i], TYPE_TZ_MPC); g_free(name); } object_initialize_child(obj, "mpc-irq-orgate", &s->mpc_irq_orgate, @@ -295,24 +291,22 @@ static void armsse_init(Object *obj) object_initialize_child(obj, name, splitter, TYPE_SPLIT_IRQ); g_free(name); } - sysbus_init_child_obj(obj, "timer0", &s->timer0, sizeof(s->timer0), - TYPE_CMSDK_APB_TIMER); - sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1), - TYPE_CMSDK_APB_TIMER); - sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer), - TYPE_CMSDK_APB_TIMER); - sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer), - TYPE_CMSDK_APB_DUALTIMER); - sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog, - sizeof(s->s32kwatchdog), TYPE_CMSDK_APB_WATCHDOG); - sysbus_init_child_obj(obj, "nswatchdog", &s->nswatchdog, - sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG); - sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog, - sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG); - sysbus_init_child_obj(obj, "armsse-sysctl", &s->sysctl, - sizeof(s->sysctl), TYPE_IOTKIT_SYSCTL); - sysbus_init_child_obj(obj, "armsse-sysinfo", &s->sysinfo, - sizeof(s->sysinfo), TYPE_IOTKIT_SYSINFO); + object_initialize_child(obj, "timer0", &s->timer0, TYPE_CMSDK_APB_TIMER); + object_initialize_child(obj, "timer1", &s->timer1, TYPE_CMSDK_APB_TIMER); + object_initialize_child(obj, "s32ktimer", &s->s32ktimer, + TYPE_CMSDK_APB_TIMER); + object_initialize_child(obj, "dualtimer", &s->dualtimer, + TYPE_CMSDK_APB_DUALTIMER); + object_initialize_child(obj, "s32kwatchdog", &s->s32kwatchdog, + TYPE_CMSDK_APB_WATCHDOG); + object_initialize_child(obj, "nswatchdog", &s->nswatchdog, + TYPE_CMSDK_APB_WATCHDOG); + object_initialize_child(obj, "swatchdog", &s->swatchdog, + TYPE_CMSDK_APB_WATCHDOG); + object_initialize_child(obj, "armsse-sysctl", &s->sysctl, + TYPE_IOTKIT_SYSCTL); + object_initialize_child(obj, "armsse-sysinfo", &s->sysinfo, + TYPE_IOTKIT_SYSINFO); if (info->has_mhus) { sysbus_init_child_obj(obj, "mhu0", &s->mhu[0], sizeof(s->mhu[0]), TYPE_ARMSSE_MHU); @@ -346,9 +340,8 @@ static void armsse_init(Object *obj) for (i = 0; i < info->num_cpus; i++) { char *name = g_strdup_printf("cachectrl%d", i); - sysbus_init_child_obj(obj, name, &s->cachectrl[i], - sizeof(s->cachectrl[i]), - TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, name, &s->cachectrl[i], + TYPE_UNIMPLEMENTED_DEVICE); g_free(name); } } @@ -356,9 +349,8 @@ static void armsse_init(Object *obj) for (i = 0; i < info->num_cpus; i++) { char *name = g_strdup_printf("cpusecctrl%d", i); - sysbus_init_child_obj(obj, name, &s->cpusecctrl[i], - sizeof(s->cpusecctrl[i]), - TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, name, &s->cpusecctrl[i], + TYPE_UNIMPLEMENTED_DEVICE); g_free(name); } } @@ -366,9 +358,8 @@ static void armsse_init(Object *obj) for (i = 0; i < info->num_cpus; i++) { char *name = g_strdup_printf("cpuid%d", i); - sysbus_init_child_obj(obj, name, &s->cpuid[i], - sizeof(s->cpuid[i]), - TYPE_ARMSSE_CPUID); + object_initialize_child(obj, name, &s->cpuid[i], + TYPE_ARMSSE_CPUID); g_free(name); } } @@ -669,7 +660,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) } /* Security controller */ - object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->secctl), &err); if (err) { error_propagate(errp, err); return; @@ -721,7 +712,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->mpc[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->mpc[i]), &err); if (err) { error_propagate(errp, err); return; @@ -764,7 +755,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) * map its upstream ends to the right place in the container. */ qdev_prop_set_uint32(DEVICE(&s->timer0), "pclk-frq", s->mainclk_frq); - object_property_set_bool(OBJECT(&s->timer0), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->timer0), &err); if (err) { error_propagate(errp, err); return; @@ -779,7 +770,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) } qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq); - object_property_set_bool(OBJECT(&s->timer1), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->timer1), &err); if (err) { error_propagate(errp, err); return; @@ -795,7 +786,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq); - object_property_set_bool(OBJECT(&s->dualtimer), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->dualtimer), &err); if (err) { error_propagate(errp, err); return; @@ -856,7 +847,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) } } - object_property_set_bool(OBJECT(&s->apb_ppc0), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc0), &err); if (err) { error_propagate(errp, err); return; @@ -929,8 +920,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_prop_set_string(DEVICE(&s->cachectrl[i]), "name", name); g_free(name); qdev_prop_set_uint64(DEVICE(&s->cachectrl[i]), "size", 0x1000); - object_property_set_bool(OBJECT(&s->cachectrl[i]), true, - "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->cachectrl[i]), &err); if (err) { error_propagate(errp, err); return; @@ -948,8 +938,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_prop_set_string(DEVICE(&s->cpusecctrl[i]), "name", name); g_free(name); qdev_prop_set_uint64(DEVICE(&s->cpusecctrl[i]), "size", 0x1000); - object_property_set_bool(OBJECT(&s->cpusecctrl[i]), true, - "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->cpusecctrl[i]), &err); if (err) { error_propagate(errp, err); return; @@ -964,8 +953,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) MemoryRegion *mr; qdev_prop_set_uint32(DEVICE(&s->cpuid[i]), "CPUID", i); - object_property_set_bool(OBJECT(&s->cpuid[i]), true, - "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->cpuid[i]), &err); if (err) { error_propagate(errp, err); return; @@ -981,7 +969,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) * 0x4002f000: S32K timer */ qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK); - object_property_set_bool(OBJECT(&s->s32ktimer), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->s32ktimer), &err); if (err) { error_propagate(errp, err); return; @@ -995,7 +983,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) return; } - object_property_set_bool(OBJECT(&s->apb_ppc1), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc1), &err); if (err) { error_propagate(errp, err); return; @@ -1033,7 +1021,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->sysinfo), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->sysinfo), &err); if (err) { error_propagate(errp, err); return; @@ -1049,7 +1037,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) "INITSVTOR0_RST", &err); object_property_set_int(OBJECT(&s->sysctl), s->init_svtor, "INITSVTOR1_RST", &err); - object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->sysctl), &err); if (err) { error_propagate(errp, err); return; @@ -1093,7 +1081,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0)); qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK); - object_property_set_bool(OBJECT(&s->s32kwatchdog), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->s32kwatchdog), &err); if (err) { error_propagate(errp, err); return; @@ -1105,7 +1093,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) /* 0x40080000 .. 0x4008ffff : ARMSSE second Base peripheral region */ qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq); - object_property_set_bool(OBJECT(&s->nswatchdog), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->nswatchdog), &err); if (err) { error_propagate(errp, err); return; @@ -1115,7 +1103,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000); qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq); - object_property_set_bool(OBJECT(&s->swatchdog), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->swatchdog), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index f930619f53..6fd672e7d9 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -136,7 +136,7 @@ static void armv7m_instance_init(Object *obj) memory_region_init(&s->container, obj, "armv7m-container", UINT64_MAX); - sysbus_init_child_obj(obj, "nvnic", &s->nvic, sizeof(s->nvic), TYPE_NVIC); + object_initialize_child(obj, "nvnic", &s->nvic, TYPE_NVIC); object_property_add_alias(obj, "num-irq", OBJECT(&s->nvic), "num-irq"); @@ -223,7 +223,7 @@ static void armv7m_realize(DeviceState *dev, Error **errp) } /* Note that we must realize the NVIC after the CPU */ - object_property_set_bool(OBJECT(&s->nvic), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->nvic), &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 10e92643c1..7c39adb272 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -131,7 +131,7 @@ static void aspeed_soc_ast2600_init(Object *obj) } snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname); - sysbus_init_child_obj(obj, "scu", &s->scu, sizeof(s->scu), typename); + object_initialize_child(obj, "scu", &s->scu, typename); qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev); object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), @@ -141,36 +141,33 @@ static void aspeed_soc_ast2600_init(Object *obj) object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu), "hw-prot-key"); - sysbus_init_child_obj(obj, "a7mpcore", &s->a7mpcore, - sizeof(s->a7mpcore), TYPE_A15MPCORE_PRIV); + object_initialize_child(obj, "a7mpcore", &s->a7mpcore, + TYPE_A15MPCORE_PRIV); - sysbus_init_child_obj(obj, "rtc", &s->rtc, sizeof(s->rtc), - TYPE_ASPEED_RTC); + object_initialize_child(obj, "rtc", &s->rtc, TYPE_ASPEED_RTC); snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname); - sysbus_init_child_obj(obj, "timerctrl", &s->timerctrl, - sizeof(s->timerctrl), typename); + object_initialize_child(obj, "timerctrl", &s->timerctrl, typename); snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname); - sysbus_init_child_obj(obj, "i2c", &s->i2c, sizeof(s->i2c), typename); + object_initialize_child(obj, "i2c", &s->i2c, typename); snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname); - sysbus_init_child_obj(obj, "fmc", &s->fmc, sizeof(s->fmc), typename); + object_initialize_child(obj, "fmc", &s->fmc, typename); object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs"); for (i = 0; i < sc->spis_num; i++) { snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i + 1, socname); - sysbus_init_child_obj(obj, "spi[*]", &s->spi[i], - sizeof(s->spi[i]), typename); + object_initialize_child(obj, "spi[*]", &s->spi[i], typename); } for (i = 0; i < sc->ehcis_num; i++) { - sysbus_init_child_obj(obj, "ehci[*]", &s->ehci[i], - sizeof(s->ehci[i]), TYPE_PLATFORM_EHCI); + object_initialize_child(obj, "ehci[*]", &s->ehci[i], + TYPE_PLATFORM_EHCI); } snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname); - sysbus_init_child_obj(obj, "sdmc", &s->sdmc, sizeof(s->sdmc), typename); + object_initialize_child(obj, "sdmc", &s->sdmc, typename); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), "ram-size"); object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc), @@ -178,30 +175,26 @@ static void aspeed_soc_ast2600_init(Object *obj) for (i = 0; i < sc->wdts_num; i++) { snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname); - sysbus_init_child_obj(obj, "wdt[*]", &s->wdt[i], - sizeof(s->wdt[i]), typename); + object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename); } for (i = 0; i < sc->macs_num; i++) { - sysbus_init_child_obj(obj, "ftgmac100[*]", &s->ftgmac100[i], - sizeof(s->ftgmac100[i]), TYPE_FTGMAC100); + object_initialize_child(obj, "ftgmac100[*]", &s->ftgmac100[i], + TYPE_FTGMAC100); - sysbus_init_child_obj(obj, "mii[*]", &s->mii[i], sizeof(s->mii[i]), - TYPE_ASPEED_MII); + object_initialize_child(obj, "mii[*]", &s->mii[i], TYPE_ASPEED_MII); } - sysbus_init_child_obj(obj, "xdma", &s->xdma, sizeof(s->xdma), - TYPE_ASPEED_XDMA); + object_initialize_child(obj, "xdma", &s->xdma, TYPE_ASPEED_XDMA); snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); - sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio), typename); + object_initialize_child(obj, "gpio", &s->gpio, typename); snprintf(typename, sizeof(typename), "aspeed.gpio-%s-1_8v", socname); - sysbus_init_child_obj(obj, "gpio_1_8v", &s->gpio_1_8v, - sizeof(s->gpio_1_8v), typename); + object_initialize_child(obj, "gpio_1_8v", &s->gpio_1_8v, typename); - sysbus_init_child_obj(obj, "sd-controller", &s->sdhci, - sizeof(s->sdhci), TYPE_ASPEED_SDHCI); + object_initialize_child(obj, "sd-controller", &s->sdhci, + TYPE_ASPEED_SDHCI); object_property_set_int(OBJECT(&s->sdhci), 2, "num-slots", &error_abort); @@ -212,8 +205,8 @@ static void aspeed_soc_ast2600_init(Object *obj) sizeof(s->sdhci.slots[i]), TYPE_SYSBUS_SDHCI); } - sysbus_init_child_obj(obj, "emmc-controller", &s->emmc, - sizeof(s->emmc), TYPE_ASPEED_SDHCI); + object_initialize_child(obj, "emmc-controller", &s->emmc, + TYPE_ASPEED_SDHCI); object_property_set_int(OBJECT(&s->emmc), 1, "num-slots", &error_abort); @@ -282,8 +275,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) ASPEED_SOC_AST2600_MAX_IRQ + GIC_INTERNAL, "num-irq", &error_abort); - object_property_set_bool(OBJECT(&s->a7mpcore), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->a7mpcore), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, ASPEED_A7MPCORE_ADDR); for (i = 0; i < sc->num_cpus; i++) { @@ -311,7 +303,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sc->memmap[ASPEED_SRAM], &s->sram); /* SCU */ - object_property_set_bool(OBJECT(&s->scu), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err); if (err) { error_propagate(errp, err); return; @@ -319,7 +311,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_SCU]); /* RTC */ - object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err); if (err) { error_propagate(errp, err); return; @@ -331,7 +323,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* Timer */ object_property_set_link(OBJECT(&s->timerctrl), OBJECT(&s->scu), "scu", &error_abort); - object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), &err); if (err) { error_propagate(errp, err); return; @@ -356,7 +348,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->i2c), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err); if (err) { error_propagate(errp, err); return; @@ -384,7 +376,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->fmc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->fmc), &err); if (err) { error_propagate(errp, err); return; @@ -404,8 +396,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) return; } object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err); - object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", - &local_err); + sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &local_err); error_propagate(&err, local_err); if (err) { error_propagate(errp, err); @@ -419,7 +410,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* EHCI */ for (i = 0; i < sc->ehcis_num; i++) { - object_property_set_bool(OBJECT(&s->ehci[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &err); if (err) { error_propagate(errp, err); return; @@ -431,7 +422,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* SDMC - SDRAM Memory Controller */ - object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), &err); if (err) { error_propagate(errp, err); return; @@ -444,7 +435,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->wdt[i]), OBJECT(&s->scu), "scu", &error_abort); - object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &err); if (err) { error_propagate(errp, err); return; @@ -457,8 +448,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", &err); - object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "realized", - &local_err); + sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &local_err); error_propagate(&err, local_err); if (err) { error_propagate(errp, err); @@ -471,8 +461,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->mii[i]), OBJECT(&s->ftgmac100[i]), "nic", &error_abort); - object_property_set_bool(OBJECT(&s->mii[i]), true, "realized", - &err); + sysbus_realize(SYS_BUS_DEVICE(&s->mii[i]), &err); if (err) { error_propagate(errp, err); return; @@ -483,7 +472,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* XDMA */ - object_property_set_bool(OBJECT(&s->xdma), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->xdma), &err); if (err) { error_propagate(errp, err); return; @@ -494,7 +483,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_XDMA)); /* GPIO */ - object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); if (err) { error_propagate(errp, err); return; @@ -503,7 +492,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, aspeed_soc_get_irq(s, ASPEED_GPIO)); - object_property_set_bool(OBJECT(&s->gpio_1_8v), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio_1_8v), &err); if (err) { error_propagate(errp, err); return; @@ -514,7 +503,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_GPIO_1_8V)); /* SDHCI */ - object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err); if (err) { error_propagate(errp, err); return; @@ -525,7 +514,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_SDHCI)); /* eMMC */ - object_property_set_bool(OBJECT(&s->emmc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->emmc), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 5806e5c9b4..c40839c1fb 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -146,7 +146,7 @@ static void aspeed_soc_init(Object *obj) } snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname); - sysbus_init_child_obj(obj, "scu", &s->scu, sizeof(s->scu), typename); + object_initialize_child(obj, "scu", &s->scu, typename); qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev); object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), @@ -156,36 +156,32 @@ static void aspeed_soc_init(Object *obj) object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu), "hw-prot-key"); - sysbus_init_child_obj(obj, "vic", &s->vic, sizeof(s->vic), - TYPE_ASPEED_VIC); + object_initialize_child(obj, "vic", &s->vic, TYPE_ASPEED_VIC); - sysbus_init_child_obj(obj, "rtc", &s->rtc, sizeof(s->rtc), - TYPE_ASPEED_RTC); + object_initialize_child(obj, "rtc", &s->rtc, TYPE_ASPEED_RTC); snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname); - sysbus_init_child_obj(obj, "timerctrl", &s->timerctrl, - sizeof(s->timerctrl), typename); + object_initialize_child(obj, "timerctrl", &s->timerctrl, typename); snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname); - sysbus_init_child_obj(obj, "i2c", &s->i2c, sizeof(s->i2c), typename); + object_initialize_child(obj, "i2c", &s->i2c, typename); snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname); - sysbus_init_child_obj(obj, "fmc", &s->fmc, sizeof(s->fmc), typename); + object_initialize_child(obj, "fmc", &s->fmc, typename); object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs"); for (i = 0; i < sc->spis_num; i++) { snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i + 1, socname); - sysbus_init_child_obj(obj, "spi[*]", &s->spi[i], - sizeof(s->spi[i]), typename); + object_initialize_child(obj, "spi[*]", &s->spi[i], typename); } for (i = 0; i < sc->ehcis_num; i++) { - sysbus_init_child_obj(obj, "ehci[*]", &s->ehci[i], - sizeof(s->ehci[i]), TYPE_PLATFORM_EHCI); + object_initialize_child(obj, "ehci[*]", &s->ehci[i], + TYPE_PLATFORM_EHCI); } snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname); - sysbus_init_child_obj(obj, "sdmc", &s->sdmc, sizeof(s->sdmc), typename); + object_initialize_child(obj, "sdmc", &s->sdmc, typename); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), "ram-size"); object_property_add_alias(obj, "max-ram-size", OBJECT(&s->sdmc), @@ -193,23 +189,20 @@ static void aspeed_soc_init(Object *obj) for (i = 0; i < sc->wdts_num; i++) { snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname); - sysbus_init_child_obj(obj, "wdt[*]", &s->wdt[i], - sizeof(s->wdt[i]), typename); + object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename); } for (i = 0; i < sc->macs_num; i++) { - sysbus_init_child_obj(obj, "ftgmac100[*]", &s->ftgmac100[i], - sizeof(s->ftgmac100[i]), TYPE_FTGMAC100); + object_initialize_child(obj, "ftgmac100[*]", &s->ftgmac100[i], + TYPE_FTGMAC100); } - sysbus_init_child_obj(obj, "xdma", &s->xdma, sizeof(s->xdma), - TYPE_ASPEED_XDMA); + object_initialize_child(obj, "xdma", &s->xdma, TYPE_ASPEED_XDMA); snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); - sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio), typename); + object_initialize_child(obj, "gpio", &s->gpio, typename); - sysbus_init_child_obj(obj, "sdc", &s->sdhci, sizeof(s->sdhci), - TYPE_ASPEED_SDHCI); + object_initialize_child(obj, "sdc", &s->sdhci, TYPE_ASPEED_SDHCI); object_property_set_int(OBJECT(&s->sdhci), 2, "num-slots", &error_abort); @@ -255,7 +248,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sc->memmap[ASPEED_SRAM], &s->sram); /* SCU */ - object_property_set_bool(OBJECT(&s->scu), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err); if (err) { error_propagate(errp, err); return; @@ -263,7 +256,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_SCU]); /* VIC */ - object_property_set_bool(OBJECT(&s->vic), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->vic), &err); if (err) { error_propagate(errp, err); return; @@ -275,7 +268,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); /* RTC */ - object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err); if (err) { error_propagate(errp, err); return; @@ -287,7 +280,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* Timer */ object_property_set_link(OBJECT(&s->timerctrl), OBJECT(&s->scu), "scu", &error_abort); - object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), &err); if (err) { error_propagate(errp, err); return; @@ -312,7 +305,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->i2c), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err); if (err) { error_propagate(errp, err); return; @@ -333,7 +326,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->fmc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->fmc), &err); if (err) { error_propagate(errp, err); return; @@ -347,8 +340,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* SPI */ for (i = 0; i < sc->spis_num; i++) { object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err); - object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", - &local_err); + sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &local_err); error_propagate(&err, local_err); if (err) { error_propagate(errp, err); @@ -362,7 +354,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* EHCI */ for (i = 0; i < sc->ehcis_num; i++) { - object_property_set_bool(OBJECT(&s->ehci[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &err); if (err) { error_propagate(errp, err); return; @@ -374,7 +366,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } /* SDMC - SDRAM Memory Controller */ - object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), &err); if (err) { error_propagate(errp, err); return; @@ -387,7 +379,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(&s->wdt[i]), OBJECT(&s->scu), "scu", &error_abort); - object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &err); if (err) { error_propagate(errp, err); return; @@ -400,8 +392,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) for (i = 0; i < sc->macs_num; i++) { object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed", &err); - object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "realized", - &local_err); + sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &local_err); error_propagate(&err, local_err); if (err) { error_propagate(errp, err); @@ -414,7 +405,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } /* XDMA */ - object_property_set_bool(OBJECT(&s->xdma), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->xdma), &err); if (err) { error_propagate(errp, err); return; @@ -425,7 +416,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_XDMA)); /* GPIO */ - object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); if (err) { error_propagate(errp, err); return; @@ -435,7 +426,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_GPIO)); /* SDHCI */ - object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 987e394ec8..1e975d7eec 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -53,37 +53,34 @@ static void bcm2835_peripherals_init(Object *obj) MBOX_CHAN_COUNT << MBOX_AS_CHAN_SHIFT); /* Interrupt Controller */ - sysbus_init_child_obj(obj, "ic", &s->ic, sizeof(s->ic), TYPE_BCM2835_IC); + object_initialize_child(obj, "ic", &s->ic, TYPE_BCM2835_IC); /* SYS Timer */ - sysbus_init_child_obj(obj, "systimer", &s->systmr, sizeof(s->systmr), - TYPE_BCM2835_SYSTIMER); + object_initialize_child(obj, "systimer", &s->systmr, + TYPE_BCM2835_SYSTIMER); /* UART0 */ - sysbus_init_child_obj(obj, "uart0", &s->uart0, sizeof(s->uart0), - TYPE_PL011); + object_initialize_child(obj, "uart0", &s->uart0, TYPE_PL011); /* AUX / UART1 */ - sysbus_init_child_obj(obj, "aux", &s->aux, sizeof(s->aux), - TYPE_BCM2835_AUX); + object_initialize_child(obj, "aux", &s->aux, TYPE_BCM2835_AUX); /* Mailboxes */ - sysbus_init_child_obj(obj, "mbox", &s->mboxes, sizeof(s->mboxes), - TYPE_BCM2835_MBOX); + object_initialize_child(obj, "mbox", &s->mboxes, TYPE_BCM2835_MBOX); object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr", OBJECT(&s->mbox_mr)); /* Framebuffer */ - sysbus_init_child_obj(obj, "fb", &s->fb, sizeof(s->fb), TYPE_BCM2835_FB); + object_initialize_child(obj, "fb", &s->fb, TYPE_BCM2835_FB); object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size"); object_property_add_const_link(OBJECT(&s->fb), "dma-mr", OBJECT(&s->gpu_bus_mr)); /* Property channel */ - sysbus_init_child_obj(obj, "property", &s->property, sizeof(s->property), - TYPE_BCM2835_PROPERTY); + object_initialize_child(obj, "property", &s->property, + TYPE_BCM2835_PROPERTY); object_property_add_alias(obj, "board-rev", OBJECT(&s->property), "board-rev"); @@ -93,31 +90,25 @@ static void bcm2835_peripherals_init(Object *obj) OBJECT(&s->gpu_bus_mr)); /* Random Number Generator */ - sysbus_init_child_obj(obj, "rng", &s->rng, sizeof(s->rng), - TYPE_BCM2835_RNG); + object_initialize_child(obj, "rng", &s->rng, TYPE_BCM2835_RNG); /* Extended Mass Media Controller */ - sysbus_init_child_obj(obj, "sdhci", &s->sdhci, sizeof(s->sdhci), - TYPE_SYSBUS_SDHCI); + object_initialize_child(obj, "sdhci", &s->sdhci, TYPE_SYSBUS_SDHCI); /* SDHOST */ - sysbus_init_child_obj(obj, "sdhost", &s->sdhost, sizeof(s->sdhost), - TYPE_BCM2835_SDHOST); + object_initialize_child(obj, "sdhost", &s->sdhost, TYPE_BCM2835_SDHOST); /* DMA Channels */ - sysbus_init_child_obj(obj, "dma", &s->dma, sizeof(s->dma), - TYPE_BCM2835_DMA); + object_initialize_child(obj, "dma", &s->dma, TYPE_BCM2835_DMA); object_property_add_const_link(OBJECT(&s->dma), "dma-mr", OBJECT(&s->gpu_bus_mr)); /* Thermal */ - sysbus_init_child_obj(obj, "thermal", &s->thermal, sizeof(s->thermal), - TYPE_BCM2835_THERMAL); + object_initialize_child(obj, "thermal", &s->thermal, TYPE_BCM2835_THERMAL); /* GPIO */ - sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio), - TYPE_BCM2835_GPIO); + object_initialize_child(obj, "gpio", &s->gpio, TYPE_BCM2835_GPIO); object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhci", OBJECT(&s->sdhci.sdbus)); @@ -125,12 +116,10 @@ static void bcm2835_peripherals_init(Object *obj) OBJECT(&s->sdhost.sdbus)); /* Mphi */ - sysbus_init_child_obj(obj, "mphi", &s->mphi, sizeof(s->mphi), - TYPE_BCM2835_MPHI); + object_initialize_child(obj, "mphi", &s->mphi, TYPE_BCM2835_MPHI); /* DWC2 */ - sysbus_init_child_obj(obj, "dwc2", &s->dwc2, sizeof(s->dwc2), - TYPE_DWC2_USB); + object_initialize_child(obj, "dwc2", &s->dwc2, TYPE_DWC2_USB); object_property_add_const_link(OBJECT(&s->dwc2), "dma-mr", OBJECT(&s->gpu_bus_mr)); @@ -172,7 +161,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) } /* Interrupt Controller */ - object_property_set_bool(OBJECT(&s->ic), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->ic), &err); if (err) { error_propagate(errp, err); return; @@ -183,7 +172,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic)); /* Sys Timer */ - object_property_set_bool(OBJECT(&s->systmr), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->systmr), &err); if (err) { error_propagate(errp, err); return; @@ -196,7 +185,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) /* UART0 */ qdev_prop_set_chr(DEVICE(&s->uart0), "chardev", serial_hd(0)); - object_property_set_bool(OBJECT(&s->uart0), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->uart0), &err); if (err) { error_propagate(errp, err); return; @@ -211,7 +200,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) /* AUX / UART1 */ qdev_prop_set_chr(DEVICE(&s->aux), "chardev", serial_hd(1)); - object_property_set_bool(OBJECT(&s->aux), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->aux), &err); if (err) { error_propagate(errp, err); return; @@ -224,7 +213,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_AUX)); /* Mailboxes */ - object_property_set_bool(OBJECT(&s->mboxes), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->mboxes), &err); if (err) { error_propagate(errp, err); return; @@ -250,7 +239,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) return; } - object_property_set_bool(OBJECT(&s->fb), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->fb), &err); if (err) { error_propagate(errp, err); return; @@ -262,7 +251,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_FB)); /* Property channel */ - object_property_set_bool(OBJECT(&s->property), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->property), &err); if (err) { error_propagate(errp, err); return; @@ -275,7 +264,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_PROPERTY)); /* Random Number Generator */ - object_property_set_bool(OBJECT(&s->rng), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->rng), &err); if (err) { error_propagate(errp, err); return; @@ -304,7 +293,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) return; } - object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err); if (err) { error_propagate(errp, err); return; @@ -317,7 +306,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_ARASANSDIO)); /* SDHOST */ - object_property_set_bool(OBJECT(&s->sdhost), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->sdhost), &err); if (err) { error_propagate(errp, err); return; @@ -330,7 +319,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_SDIO)); /* DMA Channels */ - object_property_set_bool(OBJECT(&s->dma), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->dma), &err); if (err) { error_propagate(errp, err); return; @@ -349,7 +338,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) } /* THERMAL */ - object_property_set_bool(OBJECT(&s->thermal), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->thermal), &err); if (err) { error_propagate(errp, err); return; @@ -358,7 +347,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->thermal), 0)); /* GPIO */ - object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); if (err) { error_propagate(errp, err); return; @@ -370,7 +359,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus"); /* Mphi */ - object_property_set_bool(OBJECT(&s->mphi), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->mphi), &err); if (err) { error_propagate(errp, err); return; @@ -383,7 +372,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) INTERRUPT_HOSTPORT)); /* DWC2 */ - object_property_set_bool(OBJECT(&s->dwc2), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->dwc2), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index 82cd1d2df8..39a63f2565 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -56,11 +56,10 @@ static void bcm2836_init(Object *obj) info->cpu_type); } - sysbus_init_child_obj(obj, "control", &s->control, sizeof(s->control), - TYPE_BCM2836_CONTROL); + object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL); - sysbus_init_child_obj(obj, "peripherals", &s->peripherals, - sizeof(s->peripherals), TYPE_BCM2835_PERIPHERALS); + object_initialize_child(obj, "peripherals", &s->peripherals, + TYPE_BCM2835_PERIPHERALS); object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals), "board-rev"); object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals), @@ -87,7 +86,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj); - object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), &err); if (err) { error_propagate(errp, err); return; @@ -100,7 +99,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) info->peri_base, 1); /* bcm2836 interrupt controller (and mailboxes, etc.) */ - object_property_set_bool(OBJECT(&s->control), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->control), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 6153d5f108..13acd2cf6e 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -43,12 +43,10 @@ static void digic_init(Object *obj) char name[DIGIC_TIMER_NAME_MLEN]; snprintf(name, DIGIC_TIMER_NAME_MLEN, "timer[%d]", i); - sysbus_init_child_obj(obj, name, &s->timer[i], sizeof(s->timer[i]), - TYPE_DIGIC_TIMER); + object_initialize_child(obj, name, &s->timer[i], TYPE_DIGIC_TIMER); } - sysbus_init_child_obj(obj, "uart", &s->uart, sizeof(s->uart), - TYPE_DIGIC_UART); + object_initialize_child(obj, "uart", &s->uart, TYPE_DIGIC_UART); } static void digic_realize(DeviceState *dev, Error **errp) @@ -71,7 +69,7 @@ static void digic_realize(DeviceState *dev, Error **errp) } for (i = 0; i < DIGIC4_NB_TIMERS; i++) { - object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -82,7 +80,7 @@ static void digic_realize(DeviceState *dev, Error **errp) } qdev_prop_set_chr(DEVICE(&s->uart), "chardev", serial_hd(0)); - object_property_set_bool(OBJECT(&s->uart), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index d8340e3527..d2c4970074 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -40,52 +40,43 @@ static void fsl_imx25_init(Object *obj) object_initialize_child(obj, "cpu", &s->cpu, ARM_CPU_TYPE_NAME("arm926")); - sysbus_init_child_obj(obj, "avic", &s->avic, sizeof(s->avic), - TYPE_IMX_AVIC); + object_initialize_child(obj, "avic", &s->avic, TYPE_IMX_AVIC); - sysbus_init_child_obj(obj, "ccm", &s->ccm, sizeof(s->ccm), TYPE_IMX25_CCM); + object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX25_CCM); for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) { - sysbus_init_child_obj(obj, "uart[*]", &s->uart[i], sizeof(s->uart[i]), - TYPE_IMX_SERIAL); + object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_IMX_SERIAL); } for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) { - sysbus_init_child_obj(obj, "gpt[*]", &s->gpt[i], sizeof(s->gpt[i]), - TYPE_IMX25_GPT); + object_initialize_child(obj, "gpt[*]", &s->gpt[i], TYPE_IMX25_GPT); } for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) { - sysbus_init_child_obj(obj, "epit[*]", &s->epit[i], sizeof(s->epit[i]), - TYPE_IMX_EPIT); + object_initialize_child(obj, "epit[*]", &s->epit[i], TYPE_IMX_EPIT); } - sysbus_init_child_obj(obj, "fec", &s->fec, sizeof(s->fec), TYPE_IMX_FEC); + object_initialize_child(obj, "fec", &s->fec, TYPE_IMX_FEC); - sysbus_init_child_obj(obj, "rngc", &s->rngc, sizeof(s->rngc), - TYPE_IMX_RNGC); + object_initialize_child(obj, "rngc", &s->rngc, TYPE_IMX_RNGC); for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) { - sysbus_init_child_obj(obj, "i2c[*]", &s->i2c[i], sizeof(s->i2c[i]), - TYPE_IMX_I2C); + object_initialize_child(obj, "i2c[*]", &s->i2c[i], TYPE_IMX_I2C); } for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) { - sysbus_init_child_obj(obj, "gpio[*]", &s->gpio[i], sizeof(s->gpio[i]), - TYPE_IMX_GPIO); + object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_IMX_GPIO); } for (i = 0; i < FSL_IMX25_NUM_ESDHCS; i++) { - sysbus_init_child_obj(obj, "sdhc[*]", &s->esdhc[i], sizeof(s->esdhc[i]), - TYPE_IMX_USDHC); + object_initialize_child(obj, "sdhc[*]", &s->esdhc[i], TYPE_IMX_USDHC); } for (i = 0; i < FSL_IMX25_NUM_USBS; i++) { - sysbus_init_child_obj(obj, "usb[*]", &s->usb[i], sizeof(s->usb[i]), - TYPE_CHIPIDEA); + object_initialize_child(obj, "usb[*]", &s->usb[i], TYPE_CHIPIDEA); } - sysbus_init_child_obj(obj, "wdt", &s->wdt, sizeof(s->wdt), TYPE_IMX2_WDT); + object_initialize_child(obj, "wdt", &s->wdt, TYPE_IMX2_WDT); } static void fsl_imx25_realize(DeviceState *dev, Error **errp) @@ -100,7 +91,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) return; } - object_property_set_bool(OBJECT(&s->avic), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->avic), &err); if (err) { error_propagate(errp, err); return; @@ -111,7 +102,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1, qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); - object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err); if (err) { error_propagate(errp, err); return; @@ -133,7 +124,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err); if (err) { error_propagate(errp, err); return; @@ -158,7 +149,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) s->gpt[i].ccm = IMX_CCM(&s->ccm); - object_property_set_bool(OBJECT(&s->gpt[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &err); if (err) { error_propagate(errp, err); return; @@ -181,7 +172,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) s->epit[i].ccm = IMX_CCM(&s->ccm); - object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err); if (err) { error_propagate(errp, err); return; @@ -194,7 +185,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]); - object_property_set_bool(OBJECT(&s->fec), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->fec), &err); if (err) { error_propagate(errp, err); return; @@ -203,7 +194,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->fec), 0, qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_FEC_IRQ)); - object_property_set_bool(OBJECT(&s->rngc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->rngc), &err); if (err) { error_propagate(errp, err); return; @@ -223,7 +214,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) { FSL_IMX25_I2C3_ADDR, FSL_IMX25_I2C3_IRQ } }; - object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err); if (err) { error_propagate(errp, err); return; @@ -246,7 +237,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) { FSL_IMX25_GPIO4_ADDR, FSL_IMX25_GPIO4_IRQ } }; - object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err); if (err) { error_propagate(errp, err); return; @@ -272,7 +263,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) &err); object_property_set_uint(OBJECT(&s->esdhc[i]), IMX25_ESDHC_CAPABILITIES, "capareg", &err); - object_property_set_bool(OBJECT(&s->esdhc[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err); if (err) { error_propagate(errp, err); return; @@ -293,8 +284,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) { FSL_IMX25_USB2_ADDR, FSL_IMX25_USB2_IRQ }, }; - object_property_set_bool(OBJECT(&s->usb[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, usb_table[i].addr); sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i]), 0, qdev_get_gpio_in(DEVICE(&s->avic), @@ -304,7 +294,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) /* Watchdog */ object_property_set_bool(OBJECT(&s->wdt), true, "pretimeout-support", &error_abort); - object_property_set_bool(OBJECT(&s->wdt), true, "realized", &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, FSL_IMX25_WDT_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt), 0, qdev_get_gpio_in(DEVICE(&s->avic), diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index 54eec89701..08236c3230 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -35,34 +35,29 @@ static void fsl_imx31_init(Object *obj) object_initialize_child(obj, "cpu", &s->cpu, ARM_CPU_TYPE_NAME("arm1136")); - sysbus_init_child_obj(obj, "avic", &s->avic, sizeof(s->avic), - TYPE_IMX_AVIC); + object_initialize_child(obj, "avic", &s->avic, TYPE_IMX_AVIC); - sysbus_init_child_obj(obj, "ccm", &s->ccm, sizeof(s->ccm), TYPE_IMX31_CCM); + object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX31_CCM); for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) { - sysbus_init_child_obj(obj, "uart[*]", &s->uart[i], sizeof(s->uart[i]), - TYPE_IMX_SERIAL); + object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_IMX_SERIAL); } - sysbus_init_child_obj(obj, "gpt", &s->gpt, sizeof(s->gpt), TYPE_IMX31_GPT); + object_initialize_child(obj, "gpt", &s->gpt, TYPE_IMX31_GPT); for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) { - sysbus_init_child_obj(obj, "epit[*]", &s->epit[i], sizeof(s->epit[i]), - TYPE_IMX_EPIT); + object_initialize_child(obj, "epit[*]", &s->epit[i], TYPE_IMX_EPIT); } for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) { - sysbus_init_child_obj(obj, "i2c[*]", &s->i2c[i], sizeof(s->i2c[i]), - TYPE_IMX_I2C); + object_initialize_child(obj, "i2c[*]", &s->i2c[i], TYPE_IMX_I2C); } for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) { - sysbus_init_child_obj(obj, "gpio[*]", &s->gpio[i], sizeof(s->gpio[i]), - TYPE_IMX_GPIO); + object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_IMX_GPIO); } - sysbus_init_child_obj(obj, "wdt", &s->wdt, sizeof(s->wdt), TYPE_IMX2_WDT); + object_initialize_child(obj, "wdt", &s->wdt, TYPE_IMX2_WDT); } static void fsl_imx31_realize(DeviceState *dev, Error **errp) @@ -77,7 +72,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) return; } - object_property_set_bool(OBJECT(&s->avic), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->avic), &err); if (err) { error_propagate(errp, err); return; @@ -88,7 +83,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1, qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); - object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err); if (err) { error_propagate(errp, err); return; @@ -107,7 +102,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err); if (err) { error_propagate(errp, err); return; @@ -121,7 +116,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) s->gpt.ccm = IMX_CCM(&s->ccm); - object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpt), &err); if (err) { error_propagate(errp, err); return; @@ -143,7 +138,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) s->epit[i].ccm = IMX_CCM(&s->ccm); - object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err); if (err) { error_propagate(errp, err); return; @@ -167,7 +162,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) }; /* Initialize the I2C */ - object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err); if (err) { error_propagate(errp, err); return; @@ -193,7 +188,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) object_property_set_bool(OBJECT(&s->gpio[i]), false, "has-edge-sel", &error_abort); - object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err); if (err) { error_propagate(errp, err); return; @@ -206,7 +201,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) } /* Watchdog */ - object_property_set_bool(OBJECT(&s->wdt), true, "realized", &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, FSL_IMX31_WDT_ADDR); /* On a real system, the first 16k is a `secure boot rom' */ diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 88fbba84a4..33b1be4000 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -47,69 +47,59 @@ static void fsl_imx6_init(Object *obj) ARM_CPU_TYPE_NAME("cortex-a9")); } - sysbus_init_child_obj(obj, "a9mpcore", &s->a9mpcore, sizeof(s->a9mpcore), - TYPE_A9MPCORE_PRIV); + object_initialize_child(obj, "a9mpcore", &s->a9mpcore, TYPE_A9MPCORE_PRIV); - sysbus_init_child_obj(obj, "ccm", &s->ccm, sizeof(s->ccm), TYPE_IMX6_CCM); + object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX6_CCM); - sysbus_init_child_obj(obj, "src", &s->src, sizeof(s->src), TYPE_IMX6_SRC); + object_initialize_child(obj, "src", &s->src, TYPE_IMX6_SRC); for (i = 0; i < FSL_IMX6_NUM_UARTS; i++) { snprintf(name, NAME_SIZE, "uart%d", i + 1); - sysbus_init_child_obj(obj, name, &s->uart[i], sizeof(s->uart[i]), - TYPE_IMX_SERIAL); + object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); } - sysbus_init_child_obj(obj, "gpt", &s->gpt, sizeof(s->gpt), TYPE_IMX6_GPT); + object_initialize_child(obj, "gpt", &s->gpt, TYPE_IMX6_GPT); for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) { snprintf(name, NAME_SIZE, "epit%d", i + 1); - sysbus_init_child_obj(obj, name, &s->epit[i], sizeof(s->epit[i]), - TYPE_IMX_EPIT); + object_initialize_child(obj, name, &s->epit[i], TYPE_IMX_EPIT); } for (i = 0; i < FSL_IMX6_NUM_I2CS; i++) { snprintf(name, NAME_SIZE, "i2c%d", i + 1); - sysbus_init_child_obj(obj, name, &s->i2c[i], sizeof(s->i2c[i]), - TYPE_IMX_I2C); + object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C); } for (i = 0; i < FSL_IMX6_NUM_GPIOS; i++) { snprintf(name, NAME_SIZE, "gpio%d", i + 1); - sysbus_init_child_obj(obj, name, &s->gpio[i], sizeof(s->gpio[i]), - TYPE_IMX_GPIO); + object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO); } for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) { snprintf(name, NAME_SIZE, "sdhc%d", i + 1); - sysbus_init_child_obj(obj, name, &s->esdhc[i], sizeof(s->esdhc[i]), - TYPE_IMX_USDHC); + object_initialize_child(obj, name, &s->esdhc[i], TYPE_IMX_USDHC); } for (i = 0; i < FSL_IMX6_NUM_USB_PHYS; i++) { snprintf(name, NAME_SIZE, "usbphy%d", i); - sysbus_init_child_obj(obj, name, &s->usbphy[i], sizeof(s->usbphy[i]), - TYPE_IMX_USBPHY); + object_initialize_child(obj, name, &s->usbphy[i], TYPE_IMX_USBPHY); } for (i = 0; i < FSL_IMX6_NUM_USBS; i++) { snprintf(name, NAME_SIZE, "usb%d", i); - sysbus_init_child_obj(obj, name, &s->usb[i], sizeof(s->usb[i]), - TYPE_CHIPIDEA); + object_initialize_child(obj, name, &s->usb[i], TYPE_CHIPIDEA); } for (i = 0; i < FSL_IMX6_NUM_ECSPIS; i++) { snprintf(name, NAME_SIZE, "spi%d", i + 1); - sysbus_init_child_obj(obj, name, &s->spi[i], sizeof(s->spi[i]), - TYPE_IMX_SPI); + object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI); } for (i = 0; i < FSL_IMX6_NUM_WDTS; i++) { snprintf(name, NAME_SIZE, "wdt%d", i); - sysbus_init_child_obj(obj, name, &s->wdt[i], sizeof(s->wdt[i]), - TYPE_IMX2_WDT); + object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT); } - sysbus_init_child_obj(obj, "eth", &s->eth, sizeof(s->eth), TYPE_IMX_ENET); + object_initialize_child(obj, "eth", &s->eth, TYPE_IMX_ENET); } static void fsl_imx6_realize(DeviceState *dev, Error **errp) @@ -154,7 +144,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) FSL_IMX6_MAX_IRQ + GIC_INTERNAL, "num-irq", &error_abort); - object_property_set_bool(OBJECT(&s->a9mpcore), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->a9mpcore), &err); if (err) { error_propagate(errp, err); return; @@ -168,14 +158,14 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ)); } - object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &err); if (err) { error_propagate(errp, err); return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX6_CCM_ADDR); - object_property_set_bool(OBJECT(&s->src), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->src), &err); if (err) { error_propagate(errp, err); return; @@ -197,7 +187,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err); if (err) { error_propagate(errp, err); return; @@ -211,7 +201,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) s->gpt.ccm = IMX_CCM(&s->ccm); - object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpt), &err); if (err) { error_propagate(errp, err); return; @@ -234,7 +224,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) s->epit[i].ccm = IMX_CCM(&s->ccm); - object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &err); if (err) { error_propagate(errp, err); return; @@ -257,7 +247,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) { FSL_IMX6_I2C3_ADDR, FSL_IMX6_I2C3_IRQ } }; - object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &err); if (err) { error_propagate(errp, err); return; @@ -317,7 +307,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-upper-pin-irq", &error_abort); - object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &err); if (err) { error_propagate(errp, err); return; @@ -349,7 +339,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) &err); object_property_set_uint(OBJECT(&s->esdhc[i]), IMX6_ESDHC_CAPABILITIES, "capareg", &err); - object_property_set_bool(OBJECT(&s->esdhc[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err); if (err) { error_propagate(errp, err); return; @@ -362,8 +352,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) /* USB */ for (i = 0; i < FSL_IMX6_NUM_USB_PHYS; i++) { - object_property_set_bool(OBJECT(&s->usbphy[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->usbphy[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usbphy[i]), 0, FSL_IMX6_USBPHY1_ADDR + i * 0x1000); } @@ -375,8 +364,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) FSL_IMX6_USB_HOST3_IRQ, }; - object_property_set_bool(OBJECT(&s->usb[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, FSL_IMX6_USBOH3_USB_ADDR + i * 0x200); sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i]), 0, @@ -398,7 +386,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) }; /* Initialize the SPI */ - object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); if (err) { error_propagate(errp, err); return; @@ -411,7 +399,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) } qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]); - object_property_set_bool(OBJECT(&s->eth), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->eth), &err); if (err) { error_propagate(errp, err); return; @@ -439,8 +427,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support", &error_abort); - object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX6_WDOGn_ADDR[i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0, diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index 491f1b7f73..72142cc2b6 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -40,44 +40,40 @@ static void fsl_imx6ul_init(Object *obj) /* * A7MPCORE */ - sysbus_init_child_obj(obj, "a7mpcore", &s->a7mpcore, sizeof(s->a7mpcore), - TYPE_A15MPCORE_PRIV); + object_initialize_child(obj, "a7mpcore", &s->a7mpcore, + TYPE_A15MPCORE_PRIV); /* * CCM */ - sysbus_init_child_obj(obj, "ccm", &s->ccm, sizeof(s->ccm), TYPE_IMX6UL_CCM); + object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX6UL_CCM); /* * SRC */ - sysbus_init_child_obj(obj, "src", &s->src, sizeof(s->src), TYPE_IMX6_SRC); + object_initialize_child(obj, "src", &s->src, TYPE_IMX6_SRC); /* * GPCv2 */ - sysbus_init_child_obj(obj, "gpcv2", &s->gpcv2, sizeof(s->gpcv2), - TYPE_IMX_GPCV2); + object_initialize_child(obj, "gpcv2", &s->gpcv2, TYPE_IMX_GPCV2); /* * SNVS */ - sysbus_init_child_obj(obj, "snvs", &s->snvs, sizeof(s->snvs), - TYPE_IMX7_SNVS); + object_initialize_child(obj, "snvs", &s->snvs, TYPE_IMX7_SNVS); /* * GPR */ - sysbus_init_child_obj(obj, "gpr", &s->gpr, sizeof(s->gpr), - TYPE_IMX7_GPR); + object_initialize_child(obj, "gpr", &s->gpr, TYPE_IMX7_GPR); /* * GPIOs 1 to 5 */ for (i = 0; i < FSL_IMX6UL_NUM_GPIOS; i++) { snprintf(name, NAME_SIZE, "gpio%d", i); - sysbus_init_child_obj(obj, name, &s->gpio[i], sizeof(s->gpio[i]), - TYPE_IMX_GPIO); + object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO); } /* @@ -85,8 +81,7 @@ static void fsl_imx6ul_init(Object *obj) */ for (i = 0; i < FSL_IMX6UL_NUM_GPTS; i++) { snprintf(name, NAME_SIZE, "gpt%d", i); - sysbus_init_child_obj(obj, name, &s->gpt[i], sizeof(s->gpt[i]), - TYPE_IMX7_GPT); + object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX7_GPT); } /* @@ -94,8 +89,7 @@ static void fsl_imx6ul_init(Object *obj) */ for (i = 0; i < FSL_IMX6UL_NUM_EPITS; i++) { snprintf(name, NAME_SIZE, "epit%d", i + 1); - sysbus_init_child_obj(obj, name, &s->epit[i], sizeof(s->epit[i]), - TYPE_IMX_EPIT); + object_initialize_child(obj, name, &s->epit[i], TYPE_IMX_EPIT); } /* @@ -103,8 +97,7 @@ static void fsl_imx6ul_init(Object *obj) */ for (i = 0; i < FSL_IMX6UL_NUM_ECSPIS; i++) { snprintf(name, NAME_SIZE, "spi%d", i + 1); - sysbus_init_child_obj(obj, name, &s->spi[i], sizeof(s->spi[i]), - TYPE_IMX_SPI); + object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI); } /* @@ -112,8 +105,7 @@ static void fsl_imx6ul_init(Object *obj) */ for (i = 0; i < FSL_IMX6UL_NUM_I2CS; i++) { snprintf(name, NAME_SIZE, "i2c%d", i + 1); - sysbus_init_child_obj(obj, name, &s->i2c[i], sizeof(s->i2c[i]), - TYPE_IMX_I2C); + object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C); } /* @@ -121,8 +113,7 @@ static void fsl_imx6ul_init(Object *obj) */ for (i = 0; i < FSL_IMX6UL_NUM_UARTS; i++) { snprintf(name, NAME_SIZE, "uart%d", i); - sysbus_init_child_obj(obj, name, &s->uart[i], sizeof(s->uart[i]), - TYPE_IMX_SERIAL); + object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); } /* @@ -130,20 +121,17 @@ static void fsl_imx6ul_init(Object *obj) */ for (i = 0; i < FSL_IMX6UL_NUM_ETHS; i++) { snprintf(name, NAME_SIZE, "eth%d", i); - sysbus_init_child_obj(obj, name, &s->eth[i], sizeof(s->eth[i]), - TYPE_IMX_ENET); + object_initialize_child(obj, name, &s->eth[i], TYPE_IMX_ENET); } /* USB */ for (i = 0; i < FSL_IMX6UL_NUM_USB_PHYS; i++) { snprintf(name, NAME_SIZE, "usbphy%d", i); - sysbus_init_child_obj(obj, name, &s->usbphy[i], sizeof(s->usbphy[i]), - TYPE_IMX_USBPHY); + object_initialize_child(obj, name, &s->usbphy[i], TYPE_IMX_USBPHY); } for (i = 0; i < FSL_IMX6UL_NUM_USBS; i++) { snprintf(name, NAME_SIZE, "usb%d", i); - sysbus_init_child_obj(obj, name, &s->usb[i], sizeof(s->usb[i]), - TYPE_CHIPIDEA); + object_initialize_child(obj, name, &s->usb[i], TYPE_CHIPIDEA); } /* @@ -151,8 +139,7 @@ static void fsl_imx6ul_init(Object *obj) */ for (i = 0; i < FSL_IMX6UL_NUM_USDHCS; i++) { snprintf(name, NAME_SIZE, "usdhc%d", i); - sysbus_init_child_obj(obj, name, &s->usdhc[i], sizeof(s->usdhc[i]), - TYPE_IMX_USDHC); + object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); } /* @@ -160,8 +147,7 @@ static void fsl_imx6ul_init(Object *obj) */ for (i = 0; i < FSL_IMX6UL_NUM_WDTS; i++) { snprintf(name, NAME_SIZE, "wdt%d", i); - sysbus_init_child_obj(obj, name, &s->wdt[i], sizeof(s->wdt[i]), - TYPE_IMX2_WDT); + object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT); } } @@ -192,8 +178,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(&s->a7mpcore), FSL_IMX6UL_MAX_IRQ + GIC_INTERNAL, "num-irq", &error_abort); - object_property_set_bool(OBJECT(&s->a7mpcore), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->a7mpcore), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, FSL_IMX6UL_A7MPCORE_ADDR); sbd = SYS_BUS_DEVICE(&s->a7mpcore); @@ -225,8 +210,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) }; s->gpt[i].ccm = IMX_CCM(&s->ccm); - object_property_set_bool(OBJECT(&s->gpt[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, FSL_IMX6UL_GPTn_ADDR[i]); @@ -251,8 +235,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) }; s->epit[i].ccm = IMX_CCM(&s->ccm); - object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->epit[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, FSL_IMX6UL_EPITn_ADDR[i]); @@ -290,8 +273,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_GPIO5_HIGH_IRQ, }; - object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, FSL_IMX6UL_GPIOn_ADDR[i]); @@ -321,20 +303,19 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) /* * CCM */ - object_property_set_bool(OBJECT(&s->ccm), true, "realized", &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX6UL_CCM_ADDR); /* * SRC */ - object_property_set_bool(OBJECT(&s->src), true, "realized", &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->src), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->src), 0, FSL_IMX6UL_SRC_ADDR); /* * GPCv2 */ - object_property_set_bool(OBJECT(&s->gpcv2), true, - "realized", &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->gpcv2), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpcv2), 0, FSL_IMX6UL_GPC_ADDR); /* Initialize all ECSPI */ @@ -354,8 +335,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) }; /* Initialize the SPI */ - object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, FSL_IMX6UL_SPIn_ADDR[i]); @@ -383,8 +363,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_I2C4_IRQ, }; - object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, FSL_IMX6UL_I2Cn_ADDR[i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, @@ -420,8 +399,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, FSL_IMX6UL_UARTn_ADDR[i]); @@ -454,8 +432,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_ETH_NUM_TX_RINGS, "tx-ring-num", &error_abort); qdev_set_nic_properties(DEVICE(&s->eth[i]), &nd_table[i]); - object_property_set_bool(OBJECT(&s->eth[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->eth[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->eth[i]), 0, FSL_IMX6UL_ENETn_ADDR[i]); @@ -471,8 +448,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) /* USB */ for (i = 0; i < FSL_IMX6UL_NUM_USB_PHYS; i++) { - object_property_set_bool(OBJECT(&s->usbphy[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->usbphy[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usbphy[i]), 0, FSL_IMX6UL_USBPHY1_ADDR + i * 0x1000); } @@ -482,8 +458,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_USB1_IRQ, FSL_IMX6UL_USB2_IRQ, }; - object_property_set_bool(OBJECT(&s->usb[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, FSL_IMX6UL_USBO2_USB_ADDR + i * 0x200); sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i]), 0, @@ -505,8 +480,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_USDHC2_IRQ, }; - object_property_set_bool(OBJECT(&s->usdhc[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, FSL_IMX6UL_USDHCn_ADDR[i]); @@ -519,7 +493,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) /* * SNVS */ - object_property_set_bool(OBJECT(&s->snvs), true, "realized", &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->snvs), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0, FSL_IMX6UL_SNVS_HP_ADDR); /* @@ -539,8 +513,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support", &error_abort); - object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX6UL_WDOGn_ADDR[i]); @@ -552,8 +525,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) /* * GPR */ - object_property_set_bool(OBJECT(&s->gpr), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->gpr), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpr), 0, FSL_IMX6UL_IOMUXC_GPR_ADDR); /* diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index 5cf2b7a808..aa7051307d 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -45,16 +45,15 @@ static void fsl_imx7_init(Object *obj) /* * A7MPCORE */ - sysbus_init_child_obj(obj, "a7mpcore", &s->a7mpcore, sizeof(s->a7mpcore), - TYPE_A15MPCORE_PRIV); + object_initialize_child(obj, "a7mpcore", &s->a7mpcore, + TYPE_A15MPCORE_PRIV); /* * GPIOs 1 to 7 */ for (i = 0; i < FSL_IMX7_NUM_GPIOS; i++) { snprintf(name, NAME_SIZE, "gpio%d", i); - sysbus_init_child_obj(obj, name, &s->gpio[i], sizeof(s->gpio[i]), - TYPE_IMX_GPIO); + object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO); } /* @@ -62,38 +61,33 @@ static void fsl_imx7_init(Object *obj) */ for (i = 0; i < FSL_IMX7_NUM_GPTS; i++) { snprintf(name, NAME_SIZE, "gpt%d", i); - sysbus_init_child_obj(obj, name, &s->gpt[i], sizeof(s->gpt[i]), - TYPE_IMX7_GPT); + object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX7_GPT); } /* * CCM */ - sysbus_init_child_obj(obj, "ccm", &s->ccm, sizeof(s->ccm), TYPE_IMX7_CCM); + object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX7_CCM); /* * Analog */ - sysbus_init_child_obj(obj, "analog", &s->analog, sizeof(s->analog), - TYPE_IMX7_ANALOG); + object_initialize_child(obj, "analog", &s->analog, TYPE_IMX7_ANALOG); /* * GPCv2 */ - sysbus_init_child_obj(obj, "gpcv2", &s->gpcv2, sizeof(s->gpcv2), - TYPE_IMX_GPCV2); + object_initialize_child(obj, "gpcv2", &s->gpcv2, TYPE_IMX_GPCV2); for (i = 0; i < FSL_IMX7_NUM_ECSPIS; i++) { snprintf(name, NAME_SIZE, "spi%d", i + 1); - sysbus_init_child_obj(obj, name, &s->spi[i], sizeof(s->spi[i]), - TYPE_IMX_SPI); + object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI); } for (i = 0; i < FSL_IMX7_NUM_I2CS; i++) { snprintf(name, NAME_SIZE, "i2c%d", i + 1); - sysbus_init_child_obj(obj, name, &s->i2c[i], sizeof(s->i2c[i]), - TYPE_IMX_I2C); + object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C); } /* @@ -101,8 +95,7 @@ static void fsl_imx7_init(Object *obj) */ for (i = 0; i < FSL_IMX7_NUM_UARTS; i++) { snprintf(name, NAME_SIZE, "uart%d", i); - sysbus_init_child_obj(obj, name, &s->uart[i], sizeof(s->uart[i]), - TYPE_IMX_SERIAL); + object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); } /* @@ -110,8 +103,7 @@ static void fsl_imx7_init(Object *obj) */ for (i = 0; i < FSL_IMX7_NUM_ETHS; i++) { snprintf(name, NAME_SIZE, "eth%d", i); - sysbus_init_child_obj(obj, name, &s->eth[i], sizeof(s->eth[i]), - TYPE_IMX_ENET); + object_initialize_child(obj, name, &s->eth[i], TYPE_IMX_ENET); } /* @@ -119,37 +111,32 @@ static void fsl_imx7_init(Object *obj) */ for (i = 0; i < FSL_IMX7_NUM_USDHCS; i++) { snprintf(name, NAME_SIZE, "usdhc%d", i); - sysbus_init_child_obj(obj, name, &s->usdhc[i], sizeof(s->usdhc[i]), - TYPE_IMX_USDHC); + object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); } /* * SNVS */ - sysbus_init_child_obj(obj, "snvs", &s->snvs, sizeof(s->snvs), - TYPE_IMX7_SNVS); + object_initialize_child(obj, "snvs", &s->snvs, TYPE_IMX7_SNVS); /* * Watchdog */ for (i = 0; i < FSL_IMX7_NUM_WDTS; i++) { snprintf(name, NAME_SIZE, "wdt%d", i); - sysbus_init_child_obj(obj, name, &s->wdt[i], sizeof(s->wdt[i]), - TYPE_IMX2_WDT); + object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT); } /* * GPR */ - sysbus_init_child_obj(obj, "gpr", &s->gpr, sizeof(s->gpr), TYPE_IMX7_GPR); + object_initialize_child(obj, "gpr", &s->gpr, TYPE_IMX7_GPR); - sysbus_init_child_obj(obj, "pcie", &s->pcie, sizeof(s->pcie), - TYPE_DESIGNWARE_PCIE_HOST); + object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST); for (i = 0; i < FSL_IMX7_NUM_USBS; i++) { snprintf(name, NAME_SIZE, "usb%d", i); - sysbus_init_child_obj(obj, name, &s->usb[i], sizeof(s->usb[i]), - TYPE_CHIPIDEA); + object_initialize_child(obj, name, &s->usb[i], TYPE_CHIPIDEA); } } @@ -199,8 +186,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_MAX_IRQ + GIC_INTERNAL, "num-irq", &error_abort); - object_property_set_bool(OBJECT(&s->a7mpcore), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->a7mpcore), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, FSL_IMX7_A7MPCORE_ADDR); for (i = 0; i < smp_cpus; i++) { @@ -235,8 +221,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) }; s->gpt[i].ccm = IMX_CCM(&s->ccm); - object_property_set_bool(OBJECT(&s->gpt[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, FSL_IMX7_GPTn_ADDR[i]); } @@ -251,8 +236,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_GPIO7_ADDR, }; - object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, FSL_IMX7_GPIOn_ADDR[i]); } @@ -273,21 +257,19 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) /* * CCM */ - object_property_set_bool(OBJECT(&s->ccm), true, "realized", &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->ccm), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX7_CCM_ADDR); /* * Analog */ - object_property_set_bool(OBJECT(&s->analog), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->analog), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->analog), 0, FSL_IMX7_ANALOG_ADDR); /* * GPCv2 */ - object_property_set_bool(OBJECT(&s->gpcv2), true, - "realized", &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->gpcv2), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpcv2), 0, FSL_IMX7_GPC_ADDR); /* Initialize all ECSPI */ @@ -307,8 +289,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) }; /* Initialize the SPI */ - object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, FSL_IMX7_SPIn_ADDR[i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0, @@ -331,8 +312,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_I2C4_IRQ, }; - object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, FSL_IMX7_I2Cn_ADDR[i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, @@ -367,8 +347,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, FSL_IMX7_UARTn_ADDR[i]); @@ -388,8 +367,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) object_property_set_uint(OBJECT(&s->eth[i]), FSL_IMX7_ETH_NUM_TX_RINGS, "tx-ring-num", &error_abort); qdev_set_nic_properties(DEVICE(&s->eth[i]), &nd_table[i]); - object_property_set_bool(OBJECT(&s->eth[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->eth[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->eth[i]), 0, FSL_IMX7_ENETn_ADDR[i]); @@ -415,8 +393,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_USDHC3_IRQ, }; - object_property_set_bool(OBJECT(&s->usdhc[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, FSL_IMX7_USDHCn_ADDR[i]); @@ -428,7 +405,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) /* * SNVS */ - object_property_set_bool(OBJECT(&s->snvs), true, "realized", &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->snvs), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0, FSL_IMX7_SNVS_ADDR); /* @@ -455,8 +432,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support", &error_abort); - object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX7_WDOGn_ADDR[i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0, @@ -494,12 +470,10 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) create_unimplemented_device("ocotp", FSL_IMX7_OCOTP_ADDR, FSL_IMX7_OCOTP_SIZE); - object_property_set_bool(OBJECT(&s->gpr), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->gpr), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpr), 0, FSL_IMX7_GPR_ADDR); - object_property_set_bool(OBJECT(&s->pcie), true, - "realized", &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->pcie), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie), 0, FSL_IMX7_PCIE_REG_ADDR); irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_PCI_INTA_IRQ); @@ -531,8 +505,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_USB3_IRQ, }; - object_property_set_bool(OBJECT(&s->usb[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, FSL_IMX7_USBn_ADDR[i]); diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index f4579e5a08..3235c76194 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -71,22 +71,17 @@ static void m2sxxx_soc_initfn(Object *obj) MSF2State *s = MSF2_SOC(obj); int i; - sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m), - TYPE_ARMV7M); + object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M); - sysbus_init_child_obj(obj, "sysreg", &s->sysreg, sizeof(s->sysreg), - TYPE_MSF2_SYSREG); + object_initialize_child(obj, "sysreg", &s->sysreg, TYPE_MSF2_SYSREG); - sysbus_init_child_obj(obj, "timer", &s->timer, sizeof(s->timer), - TYPE_MSS_TIMER); + object_initialize_child(obj, "timer", &s->timer, TYPE_MSS_TIMER); for (i = 0; i < MSF2_NUM_SPIS; i++) { - sysbus_init_child_obj(obj, "spi[*]", &s->spi[i], sizeof(s->spi[i]), - TYPE_MSS_SPI); + object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_MSS_SPI); } - sysbus_init_child_obj(obj, "emac", &s->emac, sizeof(s->emac), - TYPE_MSS_EMAC); + object_initialize_child(obj, "emac", &s->emac, TYPE_MSS_EMAC); if (nd_table[0].used) { qemu_check_nic_model(&nd_table[0], TYPE_MSS_EMAC); qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); @@ -130,7 +125,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_bit(armv7m, "enable-bitband", true); object_property_set_link(OBJECT(&s->armv7m), OBJECT(get_system_memory()), "memory", &error_abort); - object_property_set_bool(OBJECT(&s->armv7m), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -158,7 +153,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) dev = DEVICE(&s->timer); /* APB0 clock is the timer input clock */ qdev_prop_set_uint32(dev, "clock-frequency", s->m3clk / s->apb0div); - object_property_set_bool(OBJECT(&s->timer), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->timer), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -173,7 +168,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) dev = DEVICE(&s->sysreg); qdev_prop_set_uint32(dev, "apb0divisor", s->apb0div); qdev_prop_set_uint32(dev, "apb1divisor", s->apb1div); - object_property_set_bool(OBJECT(&s->sysreg), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -184,7 +179,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < MSF2_NUM_SPIS; i++) { gchar *bus_name; - object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -204,7 +199,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) dev = DEVICE(&s->emac); object_property_set_link(OBJECT(&s->emac), OBJECT(get_system_memory()), "ahb-bus", &error_abort); - object_property_set_bool(OBJECT(&s->emac), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->emac), &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index c278827b09..5a8961ddbb 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -71,7 +71,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->cpu), &err); if (err) { error_propagate(errp, err); return; @@ -88,7 +88,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) memory_region_add_subregion(&s->container, NRF51_SRAM_BASE, &s->sram); /* UART */ - object_property_set_bool(OBJECT(&s->uart), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err); if (err) { error_propagate(errp, err); return; @@ -100,7 +100,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) BASE_TO_IRQ(NRF51_UART_BASE))); /* RNG */ - object_property_set_bool(OBJECT(&s->rng), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->rng), &err); if (err) { error_propagate(errp, err); return; @@ -120,7 +120,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) return; } - object_property_set_bool(OBJECT(&s->nvm), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->nvm), &err); if (err) { error_propagate(errp, err); return; @@ -136,7 +136,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) memory_region_add_subregion_overlap(&s->container, NRF51_FLASH_BASE, mr, 0); /* GPIO */ - object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); if (err) { error_propagate(errp, err); return; @@ -155,7 +155,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err); if (err) { error_propagate(errp, err); return; @@ -189,27 +189,23 @@ static void nrf51_soc_init(Object *obj) memory_region_init(&s->container, obj, "nrf51-container", UINT64_MAX); - sysbus_init_child_obj(OBJECT(s), "armv6m", &s->cpu, sizeof(s->cpu), - TYPE_ARMV7M); + object_initialize_child(OBJECT(s), "armv6m", &s->cpu, TYPE_ARMV7M); qdev_prop_set_string(DEVICE(&s->cpu), "cpu-type", ARM_CPU_TYPE_NAME("cortex-m0")); qdev_prop_set_uint32(DEVICE(&s->cpu), "num-irq", 32); - sysbus_init_child_obj(obj, "uart", &s->uart, sizeof(s->uart), - TYPE_NRF51_UART); + object_initialize_child(obj, "uart", &s->uart, TYPE_NRF51_UART); object_property_add_alias(obj, "serial0", OBJECT(&s->uart), "chardev"); - sysbus_init_child_obj(obj, "rng", &s->rng, sizeof(s->rng), - TYPE_NRF51_RNG); + object_initialize_child(obj, "rng", &s->rng, TYPE_NRF51_RNG); - sysbus_init_child_obj(obj, "nvm", &s->nvm, sizeof(s->nvm), TYPE_NRF51_NVM); + object_initialize_child(obj, "nvm", &s->nvm, TYPE_NRF51_NVM); - sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio), - TYPE_NRF51_GPIO); + object_initialize_child(obj, "gpio", &s->gpio, TYPE_NRF51_GPIO); for (i = 0; i < NRF51_NUM_TIMERS; i++) { - sysbus_init_child_obj(obj, "timer[*]", &s->timer[i], - sizeof(s->timer[i]), TYPE_NRF51_TIMER); + object_initialize_child(obj, "timer[*]", &s->timer[i], + TYPE_NRF51_TIMER); } } diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index 118c342559..e2c3479702 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -51,32 +51,28 @@ static void stm32f205_soc_initfn(Object *obj) STM32F205State *s = STM32F205_SOC(obj); int i; - sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m), - TYPE_ARMV7M); + object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M); - sysbus_init_child_obj(obj, "syscfg", &s->syscfg, sizeof(s->syscfg), - TYPE_STM32F2XX_SYSCFG); + object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32F2XX_SYSCFG); for (i = 0; i < STM_NUM_USARTS; i++) { - sysbus_init_child_obj(obj, "usart[*]", &s->usart[i], - sizeof(s->usart[i]), TYPE_STM32F2XX_USART); + object_initialize_child(obj, "usart[*]", &s->usart[i], + TYPE_STM32F2XX_USART); } for (i = 0; i < STM_NUM_TIMERS; i++) { - sysbus_init_child_obj(obj, "timer[*]", &s->timer[i], - sizeof(s->timer[i]), TYPE_STM32F2XX_TIMER); + object_initialize_child(obj, "timer[*]", &s->timer[i], + TYPE_STM32F2XX_TIMER); } s->adc_irqs = OR_IRQ(object_new(TYPE_OR_IRQ)); for (i = 0; i < STM_NUM_ADCS; i++) { - sysbus_init_child_obj(obj, "adc[*]", &s->adc[i], sizeof(s->adc[i]), - TYPE_STM32F2XX_ADC); + object_initialize_child(obj, "adc[*]", &s->adc[i], TYPE_STM32F2XX_ADC); } for (i = 0; i < STM_NUM_SPIS; i++) { - sysbus_init_child_obj(obj, "spi[*]", &s->spi[i], sizeof(s->spi[i]), - TYPE_STM32F2XX_SPI); + object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_STM32F2XX_SPI); } } @@ -111,7 +107,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_bit(armv7m, "enable-bitband", true); object_property_set_link(OBJECT(&s->armv7m), OBJECT(get_system_memory()), "memory", &error_abort); - object_property_set_bool(OBJECT(&s->armv7m), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -119,7 +115,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) /* System configuration controller */ dev = DEVICE(&s->syscfg); - object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -132,7 +128,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_USARTS; i++) { dev = DEVICE(&(s->usart[i])); qdev_prop_set_chr(dev, "chardev", serial_hd(i)); - object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -146,7 +142,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_TIMERS; i++) { dev = DEVICE(&(s->timer[i])); qdev_prop_set_uint64(dev, "clock-frequency", 1000000000); - object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -169,7 +165,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_ADCS; i++) { dev = DEVICE(&(s->adc[i])); - object_property_set_bool(OBJECT(&s->adc[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->adc[i]), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -183,7 +179,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) /* SPI 1 and 2 */ for (i = 0; i < STM_NUM_SPIS; i++) { dev = DEVICE(&(s->spi[i])); - object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index 33a83bd1d4..9f7838a4a3 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -57,34 +57,29 @@ static void stm32f405_soc_initfn(Object *obj) STM32F405State *s = STM32F405_SOC(obj); int i; - sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m), - TYPE_ARMV7M); + object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M); - sysbus_init_child_obj(obj, "syscfg", &s->syscfg, sizeof(s->syscfg), - TYPE_STM32F4XX_SYSCFG); + object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32F4XX_SYSCFG); for (i = 0; i < STM_NUM_USARTS; i++) { - sysbus_init_child_obj(obj, "usart[*]", &s->usart[i], - sizeof(s->usart[i]), TYPE_STM32F2XX_USART); + object_initialize_child(obj, "usart[*]", &s->usart[i], + TYPE_STM32F2XX_USART); } for (i = 0; i < STM_NUM_TIMERS; i++) { - sysbus_init_child_obj(obj, "timer[*]", &s->timer[i], - sizeof(s->timer[i]), TYPE_STM32F2XX_TIMER); + object_initialize_child(obj, "timer[*]", &s->timer[i], + TYPE_STM32F2XX_TIMER); } for (i = 0; i < STM_NUM_ADCS; i++) { - sysbus_init_child_obj(obj, "adc[*]", &s->adc[i], sizeof(s->adc[i]), - TYPE_STM32F2XX_ADC); + object_initialize_child(obj, "adc[*]", &s->adc[i], TYPE_STM32F2XX_ADC); } for (i = 0; i < STM_NUM_SPIS; i++) { - sysbus_init_child_obj(obj, "spi[*]", &s->spi[i], sizeof(s->spi[i]), - TYPE_STM32F2XX_SPI); + object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_STM32F2XX_SPI); } - sysbus_init_child_obj(obj, "exti", &s->exti, sizeof(s->exti), - TYPE_STM32F4XX_EXTI); + object_initialize_child(obj, "exti", &s->exti, TYPE_STM32F4XX_EXTI); } static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) @@ -123,7 +118,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) qdev_prop_set_bit(armv7m, "enable-bitband", true); object_property_set_link(OBJECT(&s->armv7m), OBJECT(system_memory), "memory", &error_abort); - object_property_set_bool(OBJECT(&s->armv7m), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -131,7 +126,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) /* System configuration controller */ dev = DEVICE(&s->syscfg); - object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -144,7 +139,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_USARTS; i++) { dev = DEVICE(&(s->usart[i])); qdev_prop_set_chr(dev, "chardev", serial_hd(i)); - object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -158,7 +153,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_TIMERS; i++) { dev = DEVICE(&(s->timer[i])); qdev_prop_set_uint64(dev, "clock-frequency", 1000000000); - object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->timer[i]), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -188,7 +183,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < STM_NUM_ADCS; i++) { dev = DEVICE(&(s->adc[i])); - object_property_set_bool(OBJECT(&s->adc[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->adc[i]), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -202,7 +197,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) /* SPI devices */ for (i = 0; i < STM_NUM_SPIS; i++) { dev = DEVICE(&(s->spi[i])); - object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -214,7 +209,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) /* EXTI device */ dev = DEVICE(&s->exti); - object_property_set_bool(OBJECT(&s->exti), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->exti), &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 890139d6a2..667c11ac8d 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -237,21 +237,18 @@ static void xlnx_zynqmp_init(Object *obj) ARM_CPU_TYPE_NAME("cortex-a53")); } - sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic), - gic_class_name()); + object_initialize_child(obj, "gic", &s->gic, gic_class_name()); for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) { - sysbus_init_child_obj(obj, "gem[*]", &s->gem[i], sizeof(s->gem[i]), - TYPE_CADENCE_GEM); + object_initialize_child(obj, "gem[*]", &s->gem[i], TYPE_CADENCE_GEM); } for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) { - sysbus_init_child_obj(obj, "uart[*]", &s->uart[i], sizeof(s->uart[i]), - TYPE_CADENCE_UART); + object_initialize_child(obj, "uart[*]", &s->uart[i], + TYPE_CADENCE_UART); } - sysbus_init_child_obj(obj, "sata", &s->sata, sizeof(s->sata), - TYPE_SYSBUS_AHCI); + object_initialize_child(obj, "sata", &s->sata, TYPE_SYSBUS_AHCI); for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { sysbus_init_child_obj(obj, "sdhci[*]", &s->sdhci[i], @@ -259,32 +256,25 @@ static void xlnx_zynqmp_init(Object *obj) } for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { - sysbus_init_child_obj(obj, "spi[*]", &s->spi[i], sizeof(s->spi[i]), - TYPE_XILINX_SPIPS); + object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_XILINX_SPIPS); } - sysbus_init_child_obj(obj, "qspi", &s->qspi, sizeof(s->qspi), - TYPE_XLNX_ZYNQMP_QSPIPS); + object_initialize_child(obj, "qspi", &s->qspi, TYPE_XLNX_ZYNQMP_QSPIPS); - sysbus_init_child_obj(obj, "xxxdp", &s->dp, sizeof(s->dp), TYPE_XLNX_DP); + object_initialize_child(obj, "xxxdp", &s->dp, TYPE_XLNX_DP); - sysbus_init_child_obj(obj, "dp-dma", &s->dpdma, sizeof(s->dpdma), - TYPE_XLNX_DPDMA); + object_initialize_child(obj, "dp-dma", &s->dpdma, TYPE_XLNX_DPDMA); - sysbus_init_child_obj(obj, "ipi", &s->ipi, sizeof(s->ipi), - TYPE_XLNX_ZYNQMP_IPI); + object_initialize_child(obj, "ipi", &s->ipi, TYPE_XLNX_ZYNQMP_IPI); - sysbus_init_child_obj(obj, "rtc", &s->rtc, sizeof(s->rtc), - TYPE_XLNX_ZYNQMP_RTC); + object_initialize_child(obj, "rtc", &s->rtc, TYPE_XLNX_ZYNQMP_RTC); for (i = 0; i < XLNX_ZYNQMP_NUM_GDMA_CH; i++) { - sysbus_init_child_obj(obj, "gdma[*]", &s->gdma[i], sizeof(s->gdma[i]), - TYPE_XLNX_ZDMA); + object_initialize_child(obj, "gdma[*]", &s->gdma[i], TYPE_XLNX_ZDMA); } for (i = 0; i < XLNX_ZYNQMP_NUM_ADMA_CH; i++) { - sysbus_init_child_obj(obj, "adma[*]", &s->adma[i], sizeof(s->adma[i]), - TYPE_XLNX_ZDMA); + object_initialize_child(obj, "adma[*]", &s->adma[i], TYPE_XLNX_ZDMA); } } @@ -386,7 +376,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) } } - object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); if (err) { error_propagate(errp, err); return; @@ -482,7 +472,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->gem[i]), 2, "num-priority-queues", &error_abort); - object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), &err); if (err) { error_propagate(errp, err); return; @@ -494,7 +484,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) { qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); - object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), &err); if (err) { error_propagate(errp, err); return; @@ -506,7 +496,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(&s->sata), SATA_NUM_PORTS, "num-ports", &error_abort); - object_property_set_bool(OBJECT(&s->sata), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->sata), &err); if (err) { error_propagate(errp, err); return; @@ -557,7 +547,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { gchar *bus_name; - object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err); if (err) { error_propagate(errp, err); return; @@ -574,7 +564,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) g_free(bus_name); } - object_property_set_bool(OBJECT(&s->qspi), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->qspi), &err); if (err) { error_propagate(errp, err); return; @@ -596,7 +586,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) g_free(target_bus); } - object_property_set_bool(OBJECT(&s->dp), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->dp), &err); if (err) { error_propagate(errp, err); return; @@ -604,7 +594,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->dp), 0, DP_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->dp), 0, gic_spi[DP_IRQ]); - object_property_set_bool(OBJECT(&s->dpdma), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->dpdma), &err); if (err) { error_propagate(errp, err); return; @@ -614,7 +604,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->dpdma), 0, DPDMA_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->dpdma), 0, gic_spi[DPDMA_IRQ]); - object_property_set_bool(OBJECT(&s->ipi), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->ipi), &err); if (err) { error_propagate(errp, err); return; @@ -622,7 +612,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->ipi), 0, IPI_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ipi), 0, gic_spi[IPI_IRQ]); - object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->rtc), &err); if (err) { error_propagate(errp, err); return; @@ -636,7 +626,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->gdma[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gdma[i]), &err); if (err) { error_propagate(errp, err); return; @@ -648,7 +638,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) } for (i = 0; i < XLNX_ZYNQMP_NUM_ADMA_CH; i++) { - object_property_set_bool(OBJECT(&s->adma[i]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->adma[i]), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c index 4f659115b6..e6085f5d44 100644 --- a/hw/cpu/a15mpcore.c +++ b/hw/cpu/a15mpcore.c @@ -42,8 +42,7 @@ static void a15mp_priv_initfn(Object *obj) memory_region_init(&s->container, obj, "a15mp-priv-container", 0x8000); sysbus_init_mmio(sbd, &s->container); - sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic), - gic_class_name()); + object_initialize_child(obj, "gic", &s->gic, gic_class_name()); qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2); } @@ -77,7 +76,7 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp) qdev_prop_set_bit(gicdev, "has-virtualization-extensions", has_el2); } - object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c index b4f6a7e8a5..642363d2f4 100644 --- a/hw/cpu/a9mpcore.c +++ b/hw/cpu/a9mpcore.c @@ -32,18 +32,15 @@ static void a9mp_priv_initfn(Object *obj) memory_region_init(&s->container, obj, "a9mp-priv-container", 0x2000); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->container); - sysbus_init_child_obj(obj, "scu", &s->scu, sizeof(s->scu), TYPE_A9_SCU); + object_initialize_child(obj, "scu", &s->scu, TYPE_A9_SCU); - sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic), TYPE_ARM_GIC); + object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC); - sysbus_init_child_obj(obj, "gtimer", &s->gtimer, sizeof(s->gtimer), - TYPE_A9_GTIMER); + object_initialize_child(obj, "gtimer", &s->gtimer, TYPE_A9_GTIMER); - sysbus_init_child_obj(obj, "mptimer", &s->mptimer, sizeof(s->mptimer), - TYPE_ARM_MPTIMER); + object_initialize_child(obj, "mptimer", &s->mptimer, TYPE_ARM_MPTIMER); - sysbus_init_child_obj(obj, "wdt", &s->wdt, sizeof(s->wdt), - TYPE_ARM_MPTIMER); + object_initialize_child(obj, "wdt", &s->wdt, TYPE_ARM_MPTIMER); } static void a9mp_priv_realize(DeviceState *dev, Error **errp) @@ -60,7 +57,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) scudev = DEVICE(&s->scu); qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu); - object_property_set_bool(OBJECT(&s->scu), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -81,7 +78,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) object_property_get_bool(cpuobj, "has_el3", &error_abort); qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3); - object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -96,7 +93,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) gtimerdev = DEVICE(&s->gtimer); qdev_prop_set_uint32(gtimerdev, "num-cpu", s->num_cpu); - object_property_set_bool(OBJECT(&s->gtimer), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gtimer), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -105,7 +102,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) mptimerdev = DEVICE(&s->mptimer); qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu); - object_property_set_bool(OBJECT(&s->mptimer), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->mptimer), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -114,7 +111,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) wdtdev = DEVICE(&s->wdt); qdev_prop_set_uint32(wdtdev, "num-cpu", s->num_cpu); - object_property_set_bool(OBJECT(&s->wdt), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/cpu/arm11mpcore.c b/hw/cpu/arm11mpcore.c index ab9fadb67c..a2afb992fb 100644 --- a/hw/cpu/arm11mpcore.c +++ b/hw/cpu/arm11mpcore.c @@ -79,7 +79,7 @@ static void mpcore_priv_realize(DeviceState *dev, Error **errp) Error *err = NULL; qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu); - object_property_set_bool(OBJECT(&s->scu), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -91,7 +91,7 @@ static void mpcore_priv_realize(DeviceState *dev, Error **errp) ARM11MPCORE_NUM_GIC_PRIORITY_BITS); - object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -104,14 +104,14 @@ static void mpcore_priv_realize(DeviceState *dev, Error **errp) qdev_init_gpio_in(dev, mpcore_priv_set_irq, s->num_irq - 32); qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu); - object_property_set_bool(OBJECT(&s->mptimer), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->mptimer), &err); if (err != NULL) { error_propagate(errp, err); return; } qdev_prop_set_uint32(wdtimerdev, "num-cpu", s->num_cpu); - object_property_set_bool(OBJECT(&s->wdtimer), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->wdtimer), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -129,17 +129,15 @@ static void mpcore_priv_initfn(Object *obj) "mpcore-priv-container", 0x2000); sysbus_init_mmio(sbd, &s->container); - sysbus_init_child_obj(obj, "scu", &s->scu, sizeof(s->scu), TYPE_ARM11_SCU); + object_initialize_child(obj, "scu", &s->scu, TYPE_ARM11_SCU); - sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic), TYPE_ARM_GIC); + object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC); /* Request the legacy 11MPCore GIC behaviour: */ qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 0); - sysbus_init_child_obj(obj, "mptimer", &s->mptimer, sizeof(s->mptimer), - TYPE_ARM_MPTIMER); + object_initialize_child(obj, "mptimer", &s->mptimer, TYPE_ARM_MPTIMER); - sysbus_init_child_obj(obj, "wdtimer", &s->wdtimer, sizeof(s->wdtimer), - TYPE_ARM_MPTIMER); + object_initialize_child(obj, "wdtimer", &s->wdtimer, TYPE_ARM_MPTIMER); } static Property mpcore_priv_properties[] = { diff --git a/hw/cpu/realview_mpcore.c b/hw/cpu/realview_mpcore.c index cc2767c716..672d0f8a25 100644 --- a/hw/cpu/realview_mpcore.c +++ b/hw/cpu/realview_mpcore.c @@ -70,7 +70,7 @@ static void realview_mpcore_realize(DeviceState *dev, Error **errp) int i; qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu); - object_property_set_bool(OBJECT(&s->priv), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->priv), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -104,8 +104,7 @@ static void mpcore_rirq_init(Object *obj) SysBusDevice *privbusdev; int i; - sysbus_init_child_obj(obj, "a11priv", &s->priv, sizeof(s->priv), - TYPE_ARM11MPCORE_PRIV); + object_initialize_child(obj, "a11priv", &s->priv, TYPE_ARM11MPCORE_PRIV); privbusdev = SYS_BUS_DEVICE(&s->priv); sysbus_init_mmio(sbd, sysbus_mmio_get_region(privbusdev, 0)); diff --git a/hw/intc/realview_gic.c b/hw/intc/realview_gic.c index 73fe8cd815..f11fb5259a 100644 --- a/hw/intc/realview_gic.c +++ b/hw/intc/realview_gic.c @@ -34,7 +34,7 @@ static void realview_gic_realize(DeviceState *dev, Error **errp) int numirq = 96; qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", numirq); - object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -62,7 +62,7 @@ static void realview_gic_init(Object *obj) "realview-gic-container", 0x2000); sysbus_init_mmio(sbd, &s->container); - sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic), TYPE_ARM_GIC); + object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC); qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", 1); } diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index 30ad133ec3..e74b047380 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -63,14 +63,12 @@ static void xlnx_zynqmp_pmu_soc_init(Object *obj) object_initialize_child(obj, "pmu-cpu", &s->cpu, TYPE_MICROBLAZE_CPU); - sysbus_init_child_obj(obj, "intc", &s->intc, sizeof(s->intc), - TYPE_XLNX_PMU_IO_INTC); + object_initialize_child(obj, "intc", &s->intc, TYPE_XLNX_PMU_IO_INTC); /* Create the IPI device */ for (int i = 0; i < XLNX_ZYNQMP_PMU_NUM_IPIS; i++) { char *name = g_strdup_printf("ipi%d", i); - sysbus_init_child_obj(obj, name, &s->ipi[i], sizeof(s->ipi[i]), - TYPE_XLNX_ZYNQMP_IPI); + object_initialize_child(obj, name, &s->ipi[i], TYPE_XLNX_ZYNQMP_IPI); g_free(name); } } @@ -110,7 +108,7 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_uint(OBJECT(&s->intc), 0xffff, "intc-positive", &error_abort); - object_property_set_bool(OBJECT(&s->intc), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->intc), &err); if (err) { error_propagate(errp, err); return; @@ -121,8 +119,7 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) /* Connect the IPI device */ for (int i = 0; i < XLNX_ZYNQMP_PMU_NUM_IPIS; i++) { - object_property_set_bool(OBJECT(&s->ipi[i]), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->ipi[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ipi[i]), 0, ipi_addr[i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ipi[i]), 0, qdev_get_gpio_in(DEVICE(&s->intc), ipi_irq[i])); diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 3cb10c743c..47aa3b0552 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -31,6 +31,7 @@ #include "hw/input/adb.h" #include "hw/misc/mos6522.h" #include "hw/misc/macio/cuda.h" +#include "qapi/error.h" #include "qemu/timer.h" #include "sysemu/runstate.h" #include "qapi/error.h" @@ -527,8 +528,7 @@ static void cuda_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd; struct tm tm; - object_property_set_bool(OBJECT(&s->mos6522_cuda), true, "realized", - &err); + sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_cuda), &err); if (err) { error_propagate(errp, err); return; @@ -554,8 +554,8 @@ static void cuda_init(Object *obj) CUDAState *s = CUDA(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - sysbus_init_child_obj(obj, "mos6522-cuda", &s->mos6522_cuda, - sizeof(s->mos6522_cuda), TYPE_MOS6522_CUDA); + object_initialize_child(obj, "mos6522-cuda", &s->mos6522_cuda, + TYPE_MOS6522_CUDA); memory_region_init_io(&s->mem, obj, &mos6522_cuda_ops, s, "cuda", 0x2000); sysbus_init_mmio(sbd, &s->mem); diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index 0895b78b59..41b626c46c 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -38,6 +38,7 @@ #include "hw/misc/mos6522.h" #include "hw/misc/macio/gpio.h" #include "hw/misc/macio/pmu.h" +#include "qapi/error.h" #include "qemu/timer.h" #include "sysemu/runstate.h" #include "qapi/error.h" @@ -744,8 +745,7 @@ static void pmu_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd; struct tm tm; - object_property_set_bool(OBJECT(&s->mos6522_pmu), true, "realized", - &err); + sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_pmu), &err); if (err) { error_propagate(errp, err); return; @@ -780,8 +780,8 @@ static void pmu_init(Object *obj) qdev_prop_allow_set_link_before_realize, 0); - sysbus_init_child_obj(obj, "mos6522-pmu", &s->mos6522_pmu, - sizeof(s->mos6522_pmu), TYPE_MOS6522_PMU); + object_initialize_child(obj, "mos6522-pmu", &s->mos6522_pmu, + TYPE_MOS6522_PMU); memory_region_init_io(&s->mem, obj, &mos6522_pmu_ops, s, "via-pmu", 0x2000); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 3eb40ad8f8..b64baf71ca 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1309,8 +1309,7 @@ static void pnv_chip_power9_instance_init(Object *obj) PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj); int i; - sysbus_init_child_obj(obj, "xive", &chip9->xive, sizeof(chip9->xive), - TYPE_PNV_XIVE); + object_initialize_child(obj, "xive", &chip9->xive, TYPE_PNV_XIVE); object_property_add_alias(obj, "xive-fabric", OBJECT(&chip9->xive), "xive-fabric"); @@ -1470,8 +1469,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) "tm-bar", &error_fatal); object_property_set_link(OBJECT(&chip9->xive), OBJECT(chip), "chip", &error_abort); - object_property_set_bool(OBJECT(&chip9->xive), true, "realized", - &local_err); + sysbus_realize(SYS_BUS_DEVICE(&chip9->xive), &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index ae4c3ebb8a..bebd3213e1 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -93,8 +93,7 @@ static void riscv_lowrisc_ibex_soc_init(Object *obj) { LowRISCIbexSoCState *s = RISCV_IBEX_SOC(obj); - sysbus_init_child_obj(obj, "cpus", &s->cpus, - sizeof(s->cpus), TYPE_RISCV_HART_ARRAY); + object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); } static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) @@ -108,8 +107,7 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts", &error_abort); - object_property_set_bool(OBJECT(&s->cpus), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); /* Boot ROM */ memory_region_init_rom(&s->rom, OBJECT(dev_soc), "riscv.lowrisc.ibex.rom", diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 77742c1a6e..a9e4482270 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -147,13 +147,11 @@ static void riscv_sifive_e_soc_init(Object *obj) MachineState *ms = MACHINE(qdev_get_machine()); SiFiveESoCState *s = RISCV_E_SOC(obj); - sysbus_init_child_obj(obj, "cpus", &s->cpus, - sizeof(s->cpus), TYPE_RISCV_HART_ARRAY); + object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts", &error_abort); - sysbus_init_child_obj(obj, "riscv.sifive.e.gpio0", - &s->gpio, sizeof(s->gpio), - TYPE_SIFIVE_GPIO); + object_initialize_child(obj, "riscv.sifive.e.gpio0", &s->gpio, + TYPE_SIFIVE_GPIO); } static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) @@ -167,8 +165,7 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type", &error_abort); - object_property_set_bool(OBJECT(&s->cpus), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); /* Mask ROM */ memory_region_init_rom(&s->mask_rom, OBJECT(dev), "riscv.sifive.e.mrom", @@ -197,7 +194,7 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) /* GPIO */ - object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 3e39301124..5b86520b24 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -487,9 +487,8 @@ static void sifive_u_soc_instance_init(Object *obj) object_initialize_child(obj, "e-cluster", &s->e_cluster, TYPE_CPU_CLUSTER); qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0); - sysbus_init_child_obj(OBJECT(&s->e_cluster), "e-cpus", - &s->e_cpus, sizeof(s->e_cpus), - TYPE_RISCV_HART_ARRAY); + object_initialize_child(OBJECT(&s->e_cluster), "e-cpus", &s->e_cpus, + TYPE_RISCV_HART_ARRAY); qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1); qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0); qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type", SIFIVE_E_CPU); @@ -497,19 +496,15 @@ static void sifive_u_soc_instance_init(Object *obj) object_initialize_child(obj, "u-cluster", &s->u_cluster, TYPE_CPU_CLUSTER); qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1); - sysbus_init_child_obj(OBJECT(&s->u_cluster), "u-cpus", - &s->u_cpus, sizeof(s->u_cpus), - TYPE_RISCV_HART_ARRAY); + object_initialize_child(OBJECT(&s->u_cluster), "u-cpus", &s->u_cpus, + TYPE_RISCV_HART_ARRAY); qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1); qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1); qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", SIFIVE_U_CPU); - sysbus_init_child_obj(obj, "prci", &s->prci, sizeof(s->prci), - TYPE_SIFIVE_U_PRCI); - sysbus_init_child_obj(obj, "otp", &s->otp, sizeof(s->otp), - TYPE_SIFIVE_U_OTP); - sysbus_init_child_obj(obj, "gem", &s->gem, sizeof(s->gem), - TYPE_CADENCE_GEM); + object_initialize_child(obj, "prci", &s->prci, TYPE_SIFIVE_U_PRCI); + object_initialize_child(obj, "otp", &s->otp, TYPE_SIFIVE_U_OTP); + object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM); } static void sifive_u_soc_realize(DeviceState *dev, Error **errp) @@ -527,10 +522,8 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) Error *err = NULL; NICInfo *nd = &nd_table[0]; - object_property_set_bool(OBJECT(&s->e_cpus), true, "realized", - &error_abort); - object_property_set_bool(OBJECT(&s->u_cpus), true, "realized", - &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_abort); /* * The cluster must be realized after the RISC-V hart array container, * as the container's CPU object is only created on realize, and the @@ -597,11 +590,11 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) memmap[SIFIVE_U_CLINT].size, ms->smp.cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false); - object_property_set_bool(OBJECT(&s->prci), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->prci), &err); sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base); qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial); - object_property_set_bool(OBJECT(&s->otp), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->otp), &err); sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base); for (i = 0; i < SIFIVE_U_PLIC_NUM_SOURCES; i++) { @@ -614,7 +607,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) } object_property_set_int(OBJECT(&s->gem), GEM_REVISION, "revision", &error_abort); - object_property_set_bool(OBJECT(&s->gem), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gem), &err); if (err) { error_propagate(errp, err); return; From 5a147c8c51d42fcdf5befc2982715b4b407f612e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:38 +0200 Subject: [PATCH 1274/2595] sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 3 These are init/realize pairs produced by the previous commit's Coccinelle script where the argument test doesn't quite match. They need even more careful review. Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-50-armbru@redhat.com> --- hw/arm/armsse.c | 33 +++++++++++++-------------------- hw/arm/armv7m.c | 6 +++--- hw/arm/microbit.c | 12 ++++++------ hw/arm/xlnx-versal.c | 6 +++--- hw/arm/xlnx-zynqmp.c | 6 +++--- hw/cpu/realview_mpcore.c | 5 ++--- hw/display/sm501.c | 4 ++-- hw/intc/armv7m_nvic.c | 7 +++---- 8 files changed, 35 insertions(+), 44 deletions(-) diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 6571c1ed4c..8abe1307a9 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -256,9 +256,8 @@ static void armsse_init(Object *obj) g_free(name); name = g_strdup_printf("armv7m%d", i); - sysbus_init_child_obj(OBJECT(&s->cluster[i]), name, - &s->armv7m[i], sizeof(s->armv7m[i]), - TYPE_ARMV7M); + object_initialize_child(OBJECT(&s->cluster[i]), name, &s->armv7m[i], + TYPE_ARMV7M); qdev_prop_set_string(DEVICE(&s->armv7m[i]), "cpu-type", ARM_CPU_TYPE_NAME("cortex-m33")); g_free(name); @@ -308,31 +307,26 @@ static void armsse_init(Object *obj) object_initialize_child(obj, "armsse-sysinfo", &s->sysinfo, TYPE_IOTKIT_SYSINFO); if (info->has_mhus) { - sysbus_init_child_obj(obj, "mhu0", &s->mhu[0], sizeof(s->mhu[0]), - TYPE_ARMSSE_MHU); - sysbus_init_child_obj(obj, "mhu1", &s->mhu[1], sizeof(s->mhu[1]), - TYPE_ARMSSE_MHU); + object_initialize_child(obj, "mhu0", &s->mhu[0], TYPE_ARMSSE_MHU); + object_initialize_child(obj, "mhu1", &s->mhu[1], TYPE_ARMSSE_MHU); } if (info->has_ppus) { for (i = 0; i < info->num_cpus; i++) { char *name = g_strdup_printf("CPU%dCORE_PPU", i); int ppuidx = CPU0CORE_PPU + i; - sysbus_init_child_obj(obj, name, &s->ppu[ppuidx], - sizeof(s->ppu[ppuidx]), - TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, name, &s->ppu[ppuidx], + TYPE_UNIMPLEMENTED_DEVICE); g_free(name); } - sysbus_init_child_obj(obj, "DBG_PPU", &s->ppu[DBG_PPU], - sizeof(s->ppu[DBG_PPU]), - TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "DBG_PPU", &s->ppu[DBG_PPU], + TYPE_UNIMPLEMENTED_DEVICE); for (i = 0; i < info->sram_banks; i++) { char *name = g_strdup_printf("RAM%d_PPU", i); int ppuidx = RAM0_PPU + i; - sysbus_init_child_obj(obj, name, &s->ppu[ppuidx], - sizeof(s->ppu[ppuidx]), - TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, name, &s->ppu[ppuidx], + TYPE_UNIMPLEMENTED_DEVICE); g_free(name); } } @@ -428,7 +422,7 @@ static void map_ppu(ARMSSE *s, int ppuidx, const char *name, hwaddr addr) qdev_prop_set_string(dev, "name", name); qdev_prop_set_uint64(dev, "size", 0x1000); - qdev_init_nofail(dev); + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ppu[ppuidx]), 0, addr); } @@ -579,7 +573,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(cpuobj, true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(cpuobj), &err); if (err) { error_propagate(errp, err); return; @@ -815,8 +809,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) int cpunum; SysBusDevice *mhu_sbd = SYS_BUS_DEVICE(&s->mhu[i]); - object_property_set_bool(OBJECT(&s->mhu[i]), true, - "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->mhu[i]), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 6fd672e7d9..5cdd0b9b51 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -141,8 +141,8 @@ static void armv7m_instance_init(Object *obj) OBJECT(&s->nvic), "num-irq"); for (i = 0; i < ARRAY_SIZE(s->bitband); i++) { - sysbus_init_child_obj(obj, "bitband[*]", &s->bitband[i], - sizeof(s->bitband[i]), TYPE_BITBAND); + object_initialize_child(obj, "bitband[*]", &s->bitband[i], + TYPE_BITBAND); } } @@ -257,7 +257,7 @@ static void armv7m_realize(DeviceState *dev, Error **errp) } object_property_set_link(obj, OBJECT(s->board_memory), "source-memory", &error_abort); - object_property_set_bool(obj, true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(obj), &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c index 72fab429c4..d20ebd3aad 100644 --- a/hw/arm/microbit.c +++ b/hw/arm/microbit.c @@ -39,21 +39,21 @@ static void microbit_init(MachineState *machine) Object *soc = OBJECT(&s->nrf51); Object *i2c = OBJECT(&s->i2c); - sysbus_init_child_obj(OBJECT(machine), "nrf51", &s->nrf51, sizeof(s->nrf51), - TYPE_NRF51_SOC); + object_initialize_child(OBJECT(machine), "nrf51", &s->nrf51, + TYPE_NRF51_SOC); qdev_prop_set_chr(DEVICE(&s->nrf51), "serial0", serial_hd(0)); object_property_set_link(soc, OBJECT(system_memory), "memory", &error_fatal); - object_property_set_bool(soc, true, "realized", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(soc), &error_fatal); /* * Overlap the TWI stub device into the SoC. This is a microbit-specific * hack until we implement the nRF51 TWI controller properly and the * magnetometer/accelerometer devices. */ - sysbus_init_child_obj(OBJECT(machine), "microbit.twi", &s->i2c, - sizeof(s->i2c), TYPE_MICROBIT_I2C); - object_property_set_bool(i2c, true, "realized", &error_fatal); + object_initialize_child(OBJECT(machine), "microbit.twi", &s->i2c, + TYPE_MICROBIT_I2C); + sysbus_realize(SYS_BUS_DEVICE(i2c), &error_fatal); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(i2c), 0); memory_region_add_subregion_overlap(&s->nrf51.container, NRF51_TWI_BASE, mr, -1); diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index a27c315a6b..20f0121ab0 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -238,10 +238,10 @@ static void versal_create_rtc(Versal *s, qemu_irq *pic) SysBusDevice *sbd; MemoryRegion *mr; - sysbus_init_child_obj(OBJECT(s), "rtc", &s->pmc.rtc, sizeof(s->pmc.rtc), - TYPE_XLNX_ZYNQMP_RTC); + object_initialize_child(OBJECT(s), "rtc", &s->pmc.rtc, + TYPE_XLNX_ZYNQMP_RTC); sbd = SYS_BUS_DEVICE(&s->pmc.rtc); - qdev_init_nofail(DEVICE(sbd)); + sysbus_realize(SYS_BUS_DEVICE(sbd), &error_fatal); mr = sysbus_mmio_get_region(sbd, 0); memory_region_add_subregion(&s->mr_ps, MM_PMC_RTC, mr); diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 667c11ac8d..446b75a7aa 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -251,8 +251,8 @@ static void xlnx_zynqmp_init(Object *obj) object_initialize_child(obj, "sata", &s->sata, TYPE_SYSBUS_AHCI); for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { - sysbus_init_child_obj(obj, "sdhci[*]", &s->sdhci[i], - sizeof(s->sdhci[i]), TYPE_SYSBUS_SDHCI); + object_initialize_child(obj, "sdhci[*]", &s->sdhci[i], + TYPE_SYSBUS_SDHCI); } for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { @@ -530,7 +530,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(sdhci, true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(sdhci), &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/cpu/realview_mpcore.c b/hw/cpu/realview_mpcore.c index 672d0f8a25..d2e426fa45 100644 --- a/hw/cpu/realview_mpcore.c +++ b/hw/cpu/realview_mpcore.c @@ -81,7 +81,7 @@ static void realview_mpcore_realize(DeviceState *dev, Error **errp) } /* ??? IRQ routing is hardcoded to "normal" mode. */ for (n = 0; n < 4; n++) { - object_property_set_bool(OBJECT(&s->gic[n]), true, "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->gic[n]), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -109,8 +109,7 @@ static void mpcore_rirq_init(Object *obj) sysbus_init_mmio(sbd, sysbus_mmio_get_region(privbusdev, 0)); for (i = 0; i < 4; i++) { - sysbus_init_child_obj(obj, "gic[*]", &s->gic[i], sizeof(s->gic[i]), - TYPE_REALVIEW_GIC); + object_initialize_child(obj, "gic[*]", &s->gic[i], TYPE_REALVIEW_GIC); } } diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 80da8575fe..a7fc08c52b 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1977,7 +1977,7 @@ static void sm501_realize_sysbus(DeviceState *dev, Error **errp) sysbus_pass_irq(sbd, SYS_BUS_DEVICE(usb_dev)); /* bridge to serial emulation module */ - qdev_init_nofail(DEVICE(&s->serial)); + sysbus_realize(SYS_BUS_DEVICE(&s->serial), &error_fatal); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->serial), 0); memory_region_add_subregion(&s->state.mmio_region, SM501_UART0, mr); /* TODO : chain irq to IRL */ @@ -2023,7 +2023,7 @@ static void sm501_sysbus_init(Object *o) SM501SysBusState *sm501 = SYSBUS_SM501(o); SerialMM *smm = &sm501->serial; - sysbus_init_child_obj(o, "serial", smm, sizeof(*smm), TYPE_SERIAL_MM); + object_initialize_child(o, "serial", smm, TYPE_SERIAL_MM); qdev_set_legacy_instance_id(DEVICE(smm), SM501_UART0, 2); qdev_prop_set_uint8(DEVICE(smm), "regshift", 2); qdev_prop_set_uint8(DEVICE(smm), "endianness", DEVICE_LITTLE_ENDIAN); diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index f035079168..af9f4c5a85 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -2640,8 +2640,7 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) s->num_prio_bits = arm_feature(&s->cpu->env, ARM_FEATURE_V7) ? 8 : 2; - object_property_set_bool(OBJECT(&s->systick[M_REG_NS]), true, - "realized", &err); + sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), &err); if (err != NULL) { error_propagate(errp, err); return; @@ -2735,8 +2734,8 @@ static void armv7m_nvic_instance_init(Object *obj) NVICState *nvic = NVIC(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - sysbus_init_child_obj(obj, "systick-reg-ns", &nvic->systick[M_REG_NS], - sizeof(nvic->systick[M_REG_NS]), TYPE_SYSTICK); + object_initialize_child(obj, "systick-reg-ns", &nvic->systick[M_REG_NS], + TYPE_SYSTICK); /* We can't initialize the secure systick here, as we don't know * yet if we need it. */ From 7089e0cc468597556bb208ae8e3853499b746ebd Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:39 +0200 Subject: [PATCH 1275/2595] sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 4 This is still the same transformation as in the previous commits, but here the sysbus_init_child_obj() and its matching realize in are in separate files. Fortunately, there's just one realize left to convert. Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-51-armbru@redhat.com> --- hw/arm/aspeed_ast2600.c | 10 ++++------ hw/arm/aspeed_soc.c | 4 ++-- hw/sd/aspeed_sdhci.c | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 7c39adb272..d465743247 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -200,9 +200,8 @@ static void aspeed_soc_ast2600_init(Object *obj) /* Init sd card slot class here so that they're under the correct parent */ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { - sysbus_init_child_obj(obj, "sd-controller.sdhci[*]", - &s->sdhci.slots[i], - sizeof(s->sdhci.slots[i]), TYPE_SYSBUS_SDHCI); + object_initialize_child(obj, "sd-controller.sdhci[*]", + &s->sdhci.slots[i], TYPE_SYSBUS_SDHCI); } object_initialize_child(obj, "emmc-controller", &s->emmc, @@ -210,9 +209,8 @@ static void aspeed_soc_ast2600_init(Object *obj) object_property_set_int(OBJECT(&s->emmc), 1, "num-slots", &error_abort); - sysbus_init_child_obj(obj, "emmc-controller.sdhci", - &s->emmc.slots[0], sizeof(s->emmc.slots[0]), - TYPE_SYSBUS_SDHCI); + object_initialize_child(obj, "emmc-controller.sdhci", &s->emmc.slots[0], + TYPE_SYSBUS_SDHCI); } /* diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index c40839c1fb..d1e48b7a5d 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -208,8 +208,8 @@ static void aspeed_soc_init(Object *obj) /* Init sd card slot class here so that they're under the correct parent */ for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { - sysbus_init_child_obj(obj, "sdhci[*]", &s->sdhci.slots[i], - sizeof(s->sdhci.slots[i]), TYPE_SYSBUS_SDHCI); + object_initialize_child(obj, "sdhci[*]", &s->sdhci.slots[i], + TYPE_SYSBUS_SDHCI); } } diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c index 6a039a1d2f..538d3bad3d 100644 --- a/hw/sd/aspeed_sdhci.c +++ b/hw/sd/aspeed_sdhci.c @@ -145,7 +145,7 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp) return; } - object_property_set_bool(sdhci_slot, true, "realized", &err); + sysbus_realize(sbd_slot, &err); if (err) { error_propagate(errp, err); return; From 034b61d79f30709cf61bafdfe83e3fbbbec9bab4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:40 +0200 Subject: [PATCH 1276/2595] sysbus: sysbus_init_child_obj() is now unused, drop Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-52-armbru@redhat.com> --- hw/core/sysbus.c | 8 -------- include/hw/sysbus.h | 17 ----------------- 2 files changed, 25 deletions(-) diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 1220298e8f..70239b7e7d 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -355,14 +355,6 @@ BusState *sysbus_get_default(void) return main_system_bus; } -void sysbus_init_child_obj(Object *parent, const char *childname, void *child, - size_t childsize, const char *childtype) -{ - object_initialize_child_with_props(parent, childname, child, childsize, - childtype, &error_abort, NULL); - qdev_set_parent_bus(DEVICE(child), sysbus_get_default()); -} - static void sysbus_register_types(void) { type_register_static(&system_bus_info); diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h index 606095ba35..da9f85c58c 100644 --- a/include/hw/sysbus.h +++ b/include/hw/sysbus.h @@ -93,23 +93,6 @@ MemoryRegion *sysbus_address_space(SysBusDevice *dev); bool sysbus_realize(SysBusDevice *dev, Error **errp); bool sysbus_realize_and_unref(SysBusDevice *dev, Error **errp); -/** - * sysbus_init_child_obj: - * @parent: The parent object - * @childname: Used as name of the "child<>" property in the parent - * @child: A pointer to the memory to be used for the object. - * @childsize: The maximum size available at @child for the object. - * @childtype: The name of the type of the object to instantiate. - * - * This function will initialize an object and attach it to the main system - * bus. The memory for the object should have already been allocated. The - * object will then be added as child to the given parent. The returned object - * has a reference count of 1 (for the "child<...>" property from the parent), - * so the object will be finalized automatically when the parent gets removed. - */ -void sysbus_init_child_obj(Object *parent, const char *childname, void *child, - size_t childsize, const char *childtype); - /* Call func for every dynamically created sysbus device in the system */ void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque); From e9a82986c27a1d721d983e4112f8b971374a4e21 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:41 +0200 Subject: [PATCH 1277/2595] microbit: Eliminate two local variables in microbit_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-53-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/arm/microbit.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c index d20ebd3aad..8fe42c9d6a 100644 --- a/hw/arm/microbit.c +++ b/hw/arm/microbit.c @@ -36,15 +36,13 @@ static void microbit_init(MachineState *machine) MicrobitMachineState *s = MICROBIT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mr; - Object *soc = OBJECT(&s->nrf51); - Object *i2c = OBJECT(&s->i2c); object_initialize_child(OBJECT(machine), "nrf51", &s->nrf51, TYPE_NRF51_SOC); qdev_prop_set_chr(DEVICE(&s->nrf51), "serial0", serial_hd(0)); - object_property_set_link(soc, OBJECT(system_memory), "memory", - &error_fatal); - sysbus_realize(SYS_BUS_DEVICE(soc), &error_fatal); + object_property_set_link(OBJECT(&s->nrf51), OBJECT(system_memory), + "memory", &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->nrf51), &error_fatal); /* * Overlap the TWI stub device into the SoC. This is a microbit-specific @@ -53,13 +51,13 @@ static void microbit_init(MachineState *machine) */ object_initialize_child(OBJECT(machine), "microbit.twi", &s->i2c, TYPE_MICROBIT_I2C); - sysbus_realize(SYS_BUS_DEVICE(i2c), &error_fatal); - mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(i2c), 0); + sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &error_fatal); + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->i2c), 0); memory_region_add_subregion_overlap(&s->nrf51.container, NRF51_TWI_BASE, mr, -1); armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, - NRF51_SOC(soc)->flash_size); + s->nrf51.flash_size); } static void microbit_machine_class_init(ObjectClass *oc, void *data) From 1afec9e8ea46f8e54d0ca73b7a58f27af5edc7da Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:42 +0200 Subject: [PATCH 1278/2595] s390x/event-facility: Simplify creation of SCLP event devices init_event_facility() creates the SCLP events bus with two SCLP event devices (sclpquiesce and sclp-cpu-hotplug). It leaves the devices unrealized. A comment explains they will be realized "via the bus". The bus's realize method sclp_events_bus_realize() indeed realizes all unrealized devices on this bus. It carries a TODO comment claiming this "has to be done in common code". No other bus realize method realizes its devices. The common code in question is bus_set_realized(), which has a TODO comment asking for recursive realization. It's been asking for years. The only devices sclp_events_bus_realize() will ever realize are the two init_event_facility() puts there. Simplify as follows: * Make the devices members of the event facility instance struct, just like the bus. object_initialize_child() is simpler than object_property_add_child() and object_unref(). * Realize them in the event facility realize method. This is in line with how such things are done elsewhere. Cc: Cornelia Huck Cc: Halil Pasic Cc: Christian Borntraeger Cc: Richard Henderson Cc: David Hildenbrand Cc: qemu-s390x@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: David Hildenbrand Acked-by: Cornelia Huck Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-54-armbru@redhat.com> --- hw/s390x/event-facility.c | 64 ++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 97a4f0b1f5..164b1fd295 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -39,6 +39,7 @@ typedef struct SCLPEventsBus { struct SCLPEventFacility { SysBusDevice parent_obj; SCLPEventsBus sbus; + SCLPEvent quiesce, cpu_hotplug; /* guest's receive mask */ union { uint32_t receive_mask_pieces[2]; @@ -328,34 +329,9 @@ static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb) #define TYPE_SCLP_EVENTS_BUS "s390-sclp-events-bus" -static void sclp_events_bus_realize(BusState *bus, Error **errp) -{ - Error *err = NULL; - BusChild *kid; - - /* TODO: recursive realization has to be done in common code */ - QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - - object_property_set_bool(OBJECT(dev), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - } -} - -static void sclp_events_bus_class_init(ObjectClass *klass, void *data) -{ - BusClass *bc = BUS_CLASS(klass); - - bc->realize = sclp_events_bus_realize; -} - static const TypeInfo sclp_events_bus_info = { .name = TYPE_SCLP_EVENTS_BUS, .parent = TYPE_BUS, - .class_init = sclp_events_bus_class_init, }; static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code) @@ -443,27 +419,44 @@ static void init_event_facility(Object *obj) { SCLPEventFacility *event_facility = EVENT_FACILITY(obj); DeviceState *sdev = DEVICE(obj); - Object *new; event_facility->mask_length = 4; event_facility->allow_all_mask_sizes = true; object_property_add_bool(obj, "allow_all_mask_sizes", sclp_event_get_allow_all_mask_sizes, sclp_event_set_allow_all_mask_sizes); + /* Spawn a new bus for SCLP events */ qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus), TYPE_SCLP_EVENTS_BUS, sdev, NULL); - new = object_new(TYPE_SCLP_QUIESCE); - object_property_add_child(obj, TYPE_SCLP_QUIESCE, new); - object_unref(new); - qdev_set_parent_bus(DEVICE(new), BUS(&event_facility->sbus)); + object_initialize_child(obj, TYPE_SCLP_QUIESCE, + &event_facility->quiesce, + TYPE_SCLP_QUIESCE); - new = object_new(TYPE_SCLP_CPU_HOTPLUG); - object_property_add_child(obj, TYPE_SCLP_CPU_HOTPLUG, new); - object_unref(new); - qdev_set_parent_bus(DEVICE(new), BUS(&event_facility->sbus)); - /* the facility will automatically realize the devices via the bus */ + object_initialize_child(obj, TYPE_SCLP_CPU_HOTPLUG, + &event_facility->cpu_hotplug, + TYPE_SCLP_CPU_HOTPLUG); +} + +static void realize_event_facility(DeviceState *dev, Error **errp) +{ + SCLPEventFacility *event_facility = EVENT_FACILITY(dev); + Error *local_err = NULL; + + qdev_realize(DEVICE(&event_facility->quiesce), + BUS(&event_facility->sbus), &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + qdev_realize(DEVICE(&event_facility->cpu_hotplug), + BUS(&event_facility->sbus), &local_err); + if (local_err) { + error_propagate(errp, local_err); + qdev_unrealize(DEVICE(&event_facility->quiesce)); + return; + } } static void reset_event_facility(DeviceState *dev) @@ -479,6 +472,7 @@ static void init_event_facility_class(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(sbdc); SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc); + dc->realize = realize_event_facility; dc->reset = reset_event_facility; dc->vmsd = &vmstate_event_facility; set_bit(DEVICE_CATEGORY_MISC, dc->categories); From 510ef98dca5c44039b6f77f9752f62b5a9752c00 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:43 +0200 Subject: [PATCH 1279/2595] qdev: Make qdev_realize() support bus-less devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far, qdev_realize() supports only devices that plug into a bus: argument @bus cannot be null. Extend it to support bus-less devices, too. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-55-armbru@redhat.com> --- hw/core/qdev.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 78a06db76e..50336168f2 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -408,7 +408,7 @@ void qdev_init_nofail(DeviceState *dev) /* * Realize @dev. * @dev must not be plugged into a bus. - * Plug @dev into @bus. This takes a reference to @dev. + * If @bus, plug @dev into @bus. This takes a reference to @dev. * If @dev has no QOM parent, make one up, taking another reference. * On success, return true. * On failure, store an error through @errp and return false. @@ -418,9 +418,12 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) Error *err = NULL; assert(!dev->realized && !dev->parent_bus); - assert(bus); - qdev_set_parent_bus(dev, bus); + if (bus) { + qdev_set_parent_bus(dev, bus); + } else { + assert(!DEVICE_GET_CLASS(dev)->bus_type); + } object_property_set_bool(OBJECT(dev), true, "realized", &err); if (err) { From 464a22c7570d53518da5bd492b70bae1800a6556 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:44 +0200 Subject: [PATCH 1280/2595] qdev: Use qdev_realize() in qdev_device_add() Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-56-armbru@redhat.com> --- qdev-monitor.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qdev-monitor.c b/qdev-monitor.c index 20cfa7615b..22da107484 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -661,9 +661,7 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) goto err_del_dev; } - if (bus) { - qdev_set_parent_bus(dev, bus); - } else if (qdev_hotplug && !qdev_get_machine_hotplug_handler(dev)) { + if (!bus && qdev_hotplug && !qdev_get_machine_hotplug_handler(dev)) { /* No bus, no machine hotplug handler --> device is not hotpluggable */ error_setg(&err, "Device '%s' can not be hotplugged on this machine", driver); @@ -678,7 +676,7 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) } dev->opts = opts; - object_property_set_bool(OBJECT(dev), true, "realized", &err); + qdev_realize(DEVICE(dev), bus, &err); if (err != NULL) { dev->opts = NULL; goto err_del_dev; From ce189ab230bd3472ada876bf7568221342ee6dbb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:45 +0200 Subject: [PATCH 1281/2595] qdev: Convert bus-less devices to qdev_realize() with Coccinelle All remaining conversions to qdev_realize() are for bus-less devices. Coccinelle script: // only correct for bus-less @dev! @@ expression errp; expression dev; @@ - qdev_init_nofail(dev); + qdev_realize(dev, NULL, &error_fatal); @ depends on !(file in "hw/core/qdev.c") && !(file in "hw/core/bus.c")@ expression errp; expression dev; symbol true; @@ - object_property_set_bool(OBJECT(dev), true, "realized", errp); + qdev_realize(DEVICE(dev), NULL, errp); @ depends on !(file in "hw/core/qdev.c") && !(file in "hw/core/bus.c")@ expression errp; expression dev; symbol true; @@ - object_property_set_bool(dev, true, "realized", errp); + qdev_realize(DEVICE(dev), NULL, errp); Note that Coccinelle chokes on ARMSSE typedef vs. macro in hw/arm/armsse.c. Worked around by temporarily renaming the macro for the spatch run. Signed-off-by: Markus Armbruster Acked-by: Alistair Francis Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-57-armbru@redhat.com> --- hw/arm/allwinner-a10.c | 2 +- hw/arm/allwinner-h3.c | 2 +- hw/arm/armsse.c | 20 ++++++--------- hw/arm/armv7m.c | 2 +- hw/arm/aspeed.c | 3 +-- hw/arm/aspeed_ast2600.c | 2 +- hw/arm/aspeed_soc.c | 2 +- hw/arm/bcm2836.c | 3 +-- hw/arm/cubieboard.c | 2 +- hw/arm/digic.c | 2 +- hw/arm/digic_boards.c | 2 +- hw/arm/exynos4210.c | 4 +-- hw/arm/fsl-imx25.c | 2 +- hw/arm/fsl-imx31.c | 2 +- hw/arm/fsl-imx6.c | 2 +- hw/arm/fsl-imx6ul.c | 3 +-- hw/arm/fsl-imx7.c | 2 +- hw/arm/highbank.c | 2 +- hw/arm/imx25_pdk.c | 2 +- hw/arm/integratorcp.c | 2 +- hw/arm/kzm.c | 2 +- hw/arm/mcimx6ul-evk.c | 2 +- hw/arm/mcimx7d-sabre.c | 2 +- hw/arm/mps2-tz.c | 9 +++---- hw/arm/mps2.c | 7 +++--- hw/arm/musca.c | 6 ++--- hw/arm/orangepi.c | 2 +- hw/arm/raspi.c | 2 +- hw/arm/realview.c | 2 +- hw/arm/sabrelite.c | 2 +- hw/arm/sbsa-ref.c | 2 +- hw/arm/stm32f205_soc.c | 2 +- hw/arm/stm32f405_soc.c | 2 +- hw/arm/versatilepb.c | 2 +- hw/arm/vexpress.c | 2 +- hw/arm/virt.c | 2 +- hw/arm/xilinx_zynq.c | 2 +- hw/arm/xlnx-versal.c | 2 +- hw/arm/xlnx-zcu102.c | 2 +- hw/arm/xlnx-zynqmp.c | 10 +++----- hw/block/nand.c | 2 +- hw/char/serial-isa.c | 2 +- hw/char/serial-pci-multi.c | 2 +- hw/char/serial-pci.c | 2 +- hw/char/serial.c | 4 +-- hw/core/cpu.c | 2 +- hw/hyperv/hyperv.c | 2 +- hw/i386/x86.c | 2 +- hw/ide/microdrive.c | 3 ++- hw/intc/pnv_xive.c | 4 +-- hw/intc/spapr_xive.c | 4 +-- hw/intc/xics.c | 2 +- hw/intc/xive.c | 2 +- hw/microblaze/petalogix_ml605_mmu.c | 2 +- hw/microblaze/petalogix_s3adsp1800_mmu.c | 2 +- hw/microblaze/xlnx-zynqmp-pmu.c | 4 +-- hw/pci-host/pnv_phb3.c | 6 ++--- hw/pci-host/pnv_phb4.c | 2 +- hw/pci-host/pnv_phb4_pec.c | 2 +- hw/pci-host/prep.c | 3 +-- hw/ppc/pnv.c | 32 ++++++++++-------------- hw/ppc/pnv_bmc.c | 2 +- hw/ppc/pnv_core.c | 2 +- hw/ppc/pnv_psi.c | 4 +-- hw/ppc/spapr.c | 5 ++-- hw/ppc/spapr_cpu_core.c | 2 +- hw/ppc/spapr_drc.c | 2 +- hw/ppc/spapr_iommu.c | 2 +- hw/ppc/spapr_irq.c | 2 +- hw/riscv/opentitan.c | 3 +-- hw/riscv/riscv_hart.c | 3 +-- hw/riscv/sifive_e.c | 3 +-- hw/riscv/sifive_u.c | 9 +++---- hw/s390x/s390-skeys.c | 2 +- hw/s390x/s390-stattrib.c | 2 +- hw/s390x/s390-virtio-ccw.c | 4 +-- hw/s390x/sclp.c | 2 +- hw/s390x/tod.c | 2 +- target/i386/cpu.c | 3 +-- tests/test-qdev-global-props.c | 9 ++++--- 80 files changed, 124 insertions(+), 152 deletions(-) diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index e05099c757..52e0d83760 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -74,7 +74,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) SysBusDevice *sysbusdev; Error *err = NULL; - object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); + qdev_realize(DEVICE(&s->cpu), NULL, &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c index 91d22640e4..8e09468e86 100644 --- a/hw/arm/allwinner-h3.c +++ b/hw/arm/allwinner-h3.c @@ -250,7 +250,7 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) qdev_prop_set_bit(DEVICE(&s->cpus[i]), "has_el2", true); /* Mark realized */ - qdev_init_nofail(DEVICE(&s->cpus[i])); + qdev_realize(DEVICE(&s->cpus[i]), NULL, &error_fatal); } /* Generic Interrupt Controller */ diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 8abe1307a9..9ddde339ec 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -584,8 +584,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) * CPU must exist and have been parented into the cluster before * the cluster is realized. */ - object_property_set_bool(OBJECT(&s->cluster[i]), - true, "realized", &err); + qdev_realize(DEVICE(&s->cluster[i]), NULL, &err); if (err) { error_propagate(errp, err); return; @@ -621,7 +620,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(splitter, true, "realized", &err); + qdev_realize(DEVICE(splitter), NULL, &err); if (err) { error_propagate(errp, err); return; @@ -677,8 +676,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->sec_resp_splitter), true, - "realized", &err); + qdev_realize(DEVICE(&s->sec_resp_splitter), NULL, &err); if (err) { error_propagate(errp, err); return; @@ -729,8 +727,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->mpc_irq_orgate), true, - "realized", &err); + qdev_realize(DEVICE(&s->mpc_irq_orgate), NULL, &err); if (err) { error_propagate(errp, err); return; @@ -889,8 +886,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->ppc_irq_orgate), true, - "realized", &err); + qdev_realize(DEVICE(&s->ppc_irq_orgate), NULL, &err); if (err) { error_propagate(errp, err); return; @@ -1065,7 +1061,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(&s->nmi_orgate), true, "realized", &err); + qdev_realize(DEVICE(&s->nmi_orgate), NULL, &err); if (err) { error_propagate(errp, err); return; @@ -1113,7 +1109,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(splitter, true, "realized", &err); + qdev_realize(DEVICE(splitter), NULL, &err); if (err) { error_propagate(errp, err); return; @@ -1160,7 +1156,7 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(splitter), true, "realized", &err); + qdev_realize(DEVICE(splitter), NULL, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 5cdd0b9b51..ce83586e03 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -216,7 +216,7 @@ static void armv7m_realize(DeviceState *dev, Error **errp) s->cpu->env.nvic = &s->nvic; s->nvic.cpu = s->cpu; - object_property_set_bool(OBJECT(s->cpu), true, "realized", &err); + qdev_realize(DEVICE(s->cpu), NULL, &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 46fe6fecc2..0ad08a2b4c 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -302,8 +302,7 @@ static void aspeed_machine_init(MachineState *machine) object_property_set_int(OBJECT(&bmc->soc), ASPEED_SCU_PROT_KEY, "hw-prot-key", &error_abort); } - object_property_set_bool(OBJECT(&bmc->soc), true, "realized", - &error_abort); + qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort); memory_region_add_subregion(get_system_memory(), sc->memmap[ASPEED_SDRAM], diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index d465743247..6da687299f 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -259,7 +259,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) * is needed when using -kernel */ - object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err); + qdev_realize(DEVICE(&s->cpu[i]), NULL, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index d1e48b7a5d..810cf9b6cc 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -230,7 +230,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* CPU */ for (i = 0; i < sc->num_cpus; i++) { - object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err); + qdev_realize(DEVICE(&s->cpu[i]), NULL, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index 39a63f2565..ed1793f7b7 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -133,8 +133,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) return; } - object_property_set_bool(OBJECT(&s->cpu[n].core), true, - "realized", &err); + qdev_realize(DEVICE(&s->cpu[n].core), NULL, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 4bc4f08caf..a96c860575 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -80,7 +80,7 @@ static void cubieboard_init(MachineState *machine) exit(1); } - object_property_set_bool(OBJECT(a10), true, "realized", &err); + qdev_realize(DEVICE(a10), NULL, &err); if (err != NULL) { error_reportf_err(err, "Couldn't realize Allwinner A10: "); exit(1); diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 13acd2cf6e..13a83f7430 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -62,7 +62,7 @@ static void digic_realize(DeviceState *dev, Error **errp) return; } - object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); + qdev_realize(DEVICE(&s->cpu), NULL, &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c index 518a63e61d..b6452d918c 100644 --- a/hw/arm/digic_boards.c +++ b/hw/arm/digic_boards.c @@ -62,7 +62,7 @@ static void digic4_board_init(MachineState *machine, DigicBoard *board) exit(EXIT_FAILURE); } - object_property_set_bool(OBJECT(s), true, "realized", &err); + qdev_realize(DEVICE(s), NULL, &err); if (err != NULL) { error_reportf_err(err, "Couldn't realize DIGIC SoC: "); exit(1); diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index 2afeb73776..b888a5c9ab 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -190,7 +190,7 @@ static DeviceState *pl330_create(uint32_t base, qemu_or_irq *orgate, object_property_set_int(OBJECT(orgate), nevents + 1, "num-lines", &error_abort); - object_property_set_bool(OBJECT(orgate), true, "realized", &error_abort); + qdev_realize(DEVICE(orgate), NULL, &error_abort); for (i = 0; i < nevents + 1; i++) { sysbus_connect_irq(busdev, i, qdev_get_gpio_in(DEVICE(orgate), i)); @@ -223,7 +223,7 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) "mp-affinity", &error_abort); object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR, "reset-cbar", &error_abort); - object_property_set_bool(cpuobj, true, "realized", &error_fatal); + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); } /*** IRQs ***/ diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index d2c4970074..fb516bdbac 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -85,7 +85,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) uint8_t i; Error *err = NULL; - object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); + qdev_realize(DEVICE(&s->cpu), NULL, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index 08236c3230..42cca529c3 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -66,7 +66,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) uint16_t i; Error *err = NULL; - object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); + qdev_realize(DEVICE(&s->cpu), NULL, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 33b1be4000..17593485b7 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -130,7 +130,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) "start-powered-off", &error_abort); } - object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err); + qdev_realize(DEVICE(&s->cpu[i]), NULL, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index 72142cc2b6..f8c564033e 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -168,8 +168,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(&s->cpu), QEMU_PSCI_CONDUIT_SMC, "psci-conduit", &error_abort); - object_property_set_bool(OBJECT(&s->cpu), true, - "realized", &error_abort); + qdev_realize(DEVICE(&s->cpu), NULL, &error_abort); /* * A7MPCORE diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index aa7051307d..ca8b5cc358 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -174,7 +174,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) "start-powered-off", &error_abort); } - object_property_set_bool(o, true, "realized", &error_abort); + qdev_realize(DEVICE(o), NULL, &error_abort); } /* diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 7f279d7f93..c7ef48ecde 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -280,7 +280,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) object_property_set_int(cpuobj, MPCORE_PERIPHBASE, "reset-cbar", &error_abort); } - object_property_set_bool(cpuobj, true, "realized", &error_fatal); + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ); cpu_fiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ); cpu_virq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_VIRQ); diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 69b95711e4..af8f7f969c 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -75,7 +75,7 @@ static void imx25_pdk_init(MachineState *machine) object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_FSL_IMX25); - object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); + qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); /* We need to initialize our memory */ if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) { diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index a55d2c31e3..b11a846355 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -607,7 +607,7 @@ static void integratorcp_init(MachineState *machine) object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); } - object_property_set_bool(cpuobj, true, "realized", &error_fatal); + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); cpu = ARM_CPU(cpuobj); diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c index 0275d63079..e3f7d4ead2 100644 --- a/hw/arm/kzm.c +++ b/hw/arm/kzm.c @@ -73,7 +73,7 @@ static void kzm_init(MachineState *machine) object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_FSL_IMX31); - object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); + qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); /* Check the amount of memory is compatible with the SOC */ if (machine->ram_size > (FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE)) { diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c index 769fe6d802..3d1d2e3c04 100644 --- a/hw/arm/mcimx6ul-evk.c +++ b/hw/arm/mcimx6ul-evk.c @@ -40,7 +40,7 @@ static void mcimx6ul_evk_init(MachineState *machine) s = FSL_IMX6UL(object_new(TYPE_FSL_IMX6UL)); object_property_add_child(OBJECT(machine), "soc", OBJECT(s)); - object_property_set_bool(OBJECT(s), true, "realized", &error_fatal); + qdev_realize(DEVICE(s), NULL, &error_fatal); memory_region_add_subregion(get_system_memory(), FSL_IMX6UL_MMDC_ADDR, machine->ram); diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c index 645ad5470f..365f8183bc 100644 --- a/hw/arm/mcimx7d-sabre.c +++ b/hw/arm/mcimx7d-sabre.c @@ -42,7 +42,7 @@ static void mcimx7d_sabre_init(MachineState *machine) s = FSL_IMX7(object_new(TYPE_FSL_IMX7)); object_property_add_child(OBJECT(machine), "soc", OBJECT(s)); - object_property_set_bool(OBJECT(s), true, "realized", &error_fatal); + qdev_realize(DEVICE(s), NULL, &error_fatal); memory_region_add_subregion(get_system_memory(), FSL_IMX7_MMDC_ADDR, machine->ram); diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index a2b20fff37..8155c35418 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -414,8 +414,7 @@ static void mps2tz_common_init(MachineState *machine) object_property_set_int(OBJECT(splitter), 2, "num-lines", &error_fatal); - object_property_set_bool(OBJECT(splitter), true, "realized", - &error_fatal); + qdev_realize(DEVICE(splitter), NULL, &error_fatal); qdev_connect_gpio_out(DEVICE(splitter), 0, qdev_get_gpio_in_named(DEVICE(&mms->iotkit), "EXP_IRQ", i)); @@ -433,8 +432,7 @@ static void mps2tz_common_init(MachineState *machine) object_property_set_int(OBJECT(&mms->sec_resp_splitter), ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc), "num-lines", &error_fatal); - object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true, - "realized", &error_fatal); + qdev_realize(DEVICE(&mms->sec_resp_splitter), NULL, &error_fatal); dev_splitter = DEVICE(&mms->sec_resp_splitter); qdev_connect_gpio_out_named(iotkitdev, "sec_resp_cfg", 0, qdev_get_gpio_in(dev_splitter, 0)); @@ -466,8 +464,7 @@ static void mps2tz_common_init(MachineState *machine) &mms->uart_irq_orgate, TYPE_OR_IRQ); object_property_set_int(OBJECT(&mms->uart_irq_orgate), 10, "num-lines", &error_fatal); - object_property_set_bool(OBJECT(&mms->uart_irq_orgate), true, - "realized", &error_fatal); + qdev_realize(DEVICE(&mms->uart_irq_orgate), NULL, &error_fatal); qdev_connect_gpio_out(DEVICE(&mms->uart_irq_orgate), 0, get_sse_irq_in(mms, 15)); diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index 735f44c7a3..daa55f730b 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -229,7 +229,7 @@ static void mps2_common_init(MachineState *machine) orgate = object_new(TYPE_OR_IRQ); object_property_set_int(orgate, 6, "num-lines", &error_fatal); - object_property_set_bool(orgate, true, "realized", &error_fatal); + qdev_realize(DEVICE(orgate), NULL, &error_fatal); orgate_dev = DEVICE(orgate); qdev_connect_gpio_out(orgate_dev, 0, qdev_get_gpio_in(armv7m, 12)); @@ -266,7 +266,7 @@ static void mps2_common_init(MachineState *machine) orgate = object_new(TYPE_OR_IRQ); object_property_set_int(orgate, 10, "num-lines", &error_fatal); - object_property_set_bool(orgate, true, "realized", &error_fatal); + qdev_realize(DEVICE(orgate), NULL, &error_fatal); orgate_dev = DEVICE(orgate); qdev_connect_gpio_out(orgate_dev, 0, qdev_get_gpio_in(armv7m, 12)); @@ -281,8 +281,7 @@ static void mps2_common_init(MachineState *machine) txrx_orgate = object_new(TYPE_OR_IRQ); object_property_set_int(txrx_orgate, 2, "num-lines", &error_fatal); - object_property_set_bool(txrx_orgate, true, "realized", - &error_fatal); + qdev_realize(DEVICE(txrx_orgate), NULL, &error_fatal); txrx_orgate_dev = DEVICE(txrx_orgate); qdev_connect_gpio_out(txrx_orgate_dev, 0, qdev_get_gpio_in(armv7m, uart_txrx_irqno[i])); diff --git a/hw/arm/musca.c b/hw/arm/musca.c index d74042356d..34376328fc 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -405,8 +405,7 @@ static void musca_init(MachineState *machine) object_property_set_int(OBJECT(splitter), 2, "num-lines", &error_fatal); - object_property_set_bool(OBJECT(splitter), true, "realized", - &error_fatal); + qdev_realize(DEVICE(splitter), NULL, &error_fatal); qdev_connect_gpio_out(DEVICE(splitter), 0, qdev_get_gpio_in_named(ssedev, "EXP_IRQ", i)); qdev_connect_gpio_out(DEVICE(splitter), 1, @@ -425,8 +424,7 @@ static void musca_init(MachineState *machine) object_property_set_int(OBJECT(&mms->sec_resp_splitter), ARRAY_SIZE(mms->ppc), "num-lines", &error_fatal); - object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true, - "realized", &error_fatal); + qdev_realize(DEVICE(&mms->sec_resp_splitter), NULL, &error_fatal); dev_splitter = DEVICE(&mms->sec_resp_splitter); qdev_connect_gpio_out_named(ssedev, "sec_resp_cfg", 0, qdev_get_gpio_in(dev_splitter, 0)); diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c index 44a333a6eb..678c93033e 100644 --- a/hw/arm/orangepi.c +++ b/hw/arm/orangepi.c @@ -86,7 +86,7 @@ static void orangepi_init(MachineState *machine) &error_abort); /* Mark H3 object realized */ - object_property_set_bool(OBJECT(h3), true, "realized", &error_abort); + qdev_realize(DEVICE(h3), NULL, &error_abort); /* Retrieve SD bus */ di = drive_get_next(IF_SD); diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 78cb995251..380978fc27 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -287,7 +287,7 @@ static void raspi_machine_init(MachineState *machine) object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(machine->ram)); object_property_set_int(OBJECT(&s->soc), board_rev, "board-rev", &error_abort); - object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort); + qdev_realize(DEVICE(&s->soc), NULL, &error_abort); /* Create and plug in the SD cards */ di = drive_get_next(IF_SD); diff --git a/hw/arm/realview.c b/hw/arm/realview.c index aee7989037..f3c00fe00c 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -114,7 +114,7 @@ static void realview_init(MachineState *machine, &error_fatal); } - object_property_set_bool(cpuobj, true, "realized", &error_fatal); + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpuobj), ARM_CPU_IRQ); } diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index 33d731549d..a27e5baf60 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -51,7 +51,7 @@ static void sabrelite_init(MachineState *machine) s = FSL_IMX6(object_new(TYPE_FSL_IMX6)); object_property_add_child(OBJECT(machine), "soc", OBJECT(s)); - object_property_set_bool(OBJECT(s), true, "realized", &error_fatal); + qdev_realize(DEVICE(s), NULL, &error_fatal); memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR, machine->ram); diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 3fd3536796..e40c868a82 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -680,7 +680,7 @@ static void sbsa_ref_init(MachineState *machine) object_property_set_link(cpuobj, OBJECT(secure_sysmem), "secure-memory", &error_abort); - object_property_set_bool(cpuobj, true, "realized", &error_fatal); + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); object_unref(cpuobj); } diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index e2c3479702..19487544f0 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -155,7 +155,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) /* ADC 1 to 3 */ object_property_set_int(OBJECT(s->adc_irqs), STM_NUM_ADCS, "num-lines", &err); - object_property_set_bool(OBJECT(s->adc_irqs), true, "realized", &err); + qdev_realize(DEVICE(s->adc_irqs), NULL, &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index 9f7838a4a3..c12d9f999d 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -173,7 +173,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) } object_property_set_int(OBJECT(&s->adc_irqs), STM_NUM_ADCS, "num-lines", &err); - object_property_set_bool(OBJECT(&s->adc_irqs), true, "realized", &err); + qdev_realize(DEVICE(&s->adc_irqs), NULL, &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 29e3bc6bd0..2ebdcbd8ac 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -215,7 +215,7 @@ static void versatile_init(MachineState *machine, int board_id) object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); } - object_property_set_bool(cpuobj, true, "realized", &error_fatal); + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); cpu = ARM_CPU(cpuobj); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index bebb0ed5a4..7ca5d523a4 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -229,7 +229,7 @@ static void init_cpus(MachineState *ms, const char *cpu_type, object_property_set_int(cpuobj, periphbase, "reset-cbar", &error_abort); } - object_property_set_bool(cpuobj, true, "realized", &error_fatal); + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); } /* Create the private peripheral devices (including the GIC); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index c3e80bcbce..caceb1e4a0 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1819,7 +1819,7 @@ static void machvirt_init(MachineState *machine) "secure-memory", &error_abort); } - object_property_set_bool(cpuobj, true, "realized", &error_fatal); + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); object_unref(cpuobj); } fdt_add_timer_nodes(vms); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 69d62ee24b..4247c4dbd8 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -202,7 +202,7 @@ static void zynq_init(MachineState *machine) &error_fatal); object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar", &error_fatal); - object_property_set_bool(OBJECT(cpu), true, "realized", &error_fatal); + qdev_realize(DEVICE(cpu), NULL, &error_fatal); /* DDR remapped to address zero. */ memory_region_add_subregion(address_space_mem, 0, machine->ram); diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 20f0121ab0..fed9d07ca2 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -47,7 +47,7 @@ static void versal_create_apu_cpus(Versal *s) "core-count", &error_abort); object_property_set_link(obj, OBJECT(&s->fpd.apu.mr), "memory", &error_abort); - object_property_set_bool(obj, true, "realized", &error_fatal); + qdev_realize(DEVICE(obj), NULL, &error_fatal); } } diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 822e24af65..b920bcee94 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -125,7 +125,7 @@ static void xlnx_zcu102_init(MachineState *machine) object_property_set_bool(OBJECT(&s->soc), s->virt, "virtualization", &error_fatal); - object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); + qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); /* Create and plug in the SD cards */ for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 446b75a7aa..1de9d4a89d 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -209,15 +209,14 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s, object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs", &error_abort); - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized", - &err); + qdev_realize(DEVICE(&s->rpu_cpu[i]), NULL, &err); if (err) { error_propagate(errp, err); return; } } - qdev_init_nofail(DEVICE(&s->rpu_cluster)); + qdev_realize(DEVICE(&s->rpu_cluster), NULL, &error_fatal); } static void xlnx_zynqmp_init(Object *obj) @@ -341,7 +340,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) qdev_prop_set_bit(DEVICE(&s->gic), "has-virtualization-extensions", s->virt); - qdev_init_nofail(DEVICE(&s->apu_cluster)); + qdev_realize(DEVICE(&s->apu_cluster), NULL, &error_fatal); /* Realize APUs before realizing the GIC. KVM requires this. */ for (i = 0; i < num_apus; i++) { @@ -368,8 +367,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) "reset-cbar", &error_abort); object_property_set_int(OBJECT(&s->apu_cpu[i]), num_apus, "core-count", &error_abort); - object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized", - &err); + qdev_realize(DEVICE(&s->apu_cpu[i]), NULL, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/block/nand.c b/hw/block/nand.c index cdf3429ce6..7e25681d59 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -651,7 +651,7 @@ DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id) qdev_prop_set_drive(dev, "drive", blk, &error_fatal); } - qdev_init_nofail(dev); + qdev_realize(dev, NULL, &error_fatal); return dev; } diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index d816dc3d73..b4c65949cd 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -75,7 +75,7 @@ static void serial_isa_realizefn(DeviceState *dev, Error **errp) index++; isa_init_irq(isadev, &s->irq, isa->isairq); - object_property_set_bool(OBJECT(s), true, "realized", errp); + qdev_realize(DEVICE(s), NULL, errp); qdev_set_legacy_instance_id(dev, isa->iobase, 3); memory_region_init_io(&s->io, OBJECT(isa), &serial_io_ops, s, "serial", 8); diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c index 1d65d64c4e..56f915e7c9 100644 --- a/hw/char/serial-pci-multi.c +++ b/hw/char/serial-pci-multi.c @@ -106,7 +106,7 @@ static void multi_serial_pci_realize(PCIDevice *dev, Error **errp) for (i = 0; i < nports; i++) { s = pci->state + i; - object_property_set_bool(OBJECT(s), true, "realized", &err); + qdev_realize(DEVICE(s), NULL, &err); if (err != NULL) { error_propagate(errp, err); multi_serial_pci_exit(dev); diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index 5f5ff10a75..298f3adba7 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -49,7 +49,7 @@ static void serial_pci_realize(PCIDevice *dev, Error **errp) SerialState *s = &pci->state; Error *err = NULL; - object_property_set_bool(OBJECT(s), true, "realized", &err); + qdev_realize(DEVICE(s), NULL, &err); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/char/serial.c b/hw/char/serial.c index 4582d488d0..9eebcb27e7 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -991,7 +991,7 @@ static void serial_io_realize(DeviceState *dev, Error **errp) SerialState *s = &sio->serial; Error *local_err = NULL; - object_property_set_bool(OBJECT(s), true, "realized", &local_err); + qdev_realize(DEVICE(s), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1098,7 +1098,7 @@ static void serial_mm_realize(DeviceState *dev, Error **errp) SerialState *s = &smm->serial; Error *local_err = NULL; - object_property_set_bool(OBJECT(s), true, "realized", &local_err); + qdev_realize(DEVICE(s), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/core/cpu.c b/hw/core/cpu.c index f31ec48ee6..4d5438b70e 100644 --- a/hw/core/cpu.c +++ b/hw/core/cpu.c @@ -59,7 +59,7 @@ CPUState *cpu_create(const char *typename) { Error *err = NULL; CPUState *cpu = CPU(object_new(typename)); - object_property_set_bool(OBJECT(cpu), true, "realized", &err); + qdev_realize(DEVICE(cpu), NULL, &err); if (err != NULL) { error_report_err(err); object_unref(OBJECT(cpu)); diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index a3933c34c6..844d00776d 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -140,7 +140,7 @@ void hyperv_synic_add(CPUState *cs) synic->cs = cs; object_property_add_child(OBJECT(cs), "synic", obj); object_unref(obj); - object_property_set_bool(obj, true, "realized", &error_abort); + qdev_realize(DEVICE(obj), NULL, &error_abort); synic_enabled = true; } diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 9b6ebd92b5..bb31935f70 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -124,7 +124,7 @@ void x86_cpu_new(X86MachineState *x86ms, int64_t apic_id, Error **errp) cpu = object_new(MACHINE(x86ms)->cpu_type); object_property_set_uint(cpu, apic_id, "apic-id", &local_err); - object_property_set_bool(cpu, true, "realized", &local_err); + qdev_realize(DEVICE(cpu), NULL, &local_err); object_unref(cpu); error_propagate(errp, local_err); diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 6b30e36ed8..c4cc0a84eb 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "hw/pcmcia.h" #include "migration/vmstate.h" +#include "qapi/error.h" #include "qemu/module.h" #include "sysemu/dma.h" @@ -560,7 +561,7 @@ PCMCIACardState *dscm1xxxx_init(DriveInfo *dinfo) MicroDriveState *md; md = MICRODRIVE(object_new(TYPE_DSCM1XXXX)); - qdev_init_nofail(DEVICE(md)); + qdev_realize(DEVICE(md), NULL, &error_fatal); if (dinfo != NULL) { ide_create_drive(&md->bus, 0, dinfo); diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index 892c78069d..85ba0b4655 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -1833,7 +1833,7 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp) &error_fatal); object_property_set_link(OBJECT(xsrc), OBJECT(xive), "xive", &error_abort); - object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err); + qdev_realize(DEVICE(xsrc), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1843,7 +1843,7 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp) &error_fatal); object_property_set_link(OBJECT(end_xsrc), OBJECT(xive), "xive", &error_abort); - object_property_set_bool(OBJECT(end_xsrc), true, "realized", &local_err); + qdev_realize(DEVICE(end_xsrc), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 263cd1253c..b7fc8dde7a 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -312,7 +312,7 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) &error_fatal); object_property_set_link(OBJECT(xsrc), OBJECT(xive), "xive", &error_abort); - object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err); + qdev_realize(DEVICE(xsrc), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -326,7 +326,7 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) &error_fatal); object_property_set_link(OBJECT(end_xsrc), OBJECT(xive), "xive", &error_abort); - object_property_set_bool(OBJECT(end_xsrc), true, "realized", &local_err); + qdev_realize(DEVICE(end_xsrc), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/intc/xics.c b/hw/intc/xics.c index d5032c8f8a..d365eeca66 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -384,7 +384,7 @@ Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp) object_unref(obj); object_property_set_link(obj, OBJECT(xi), ICP_PROP_XICS, &error_abort); object_property_set_link(obj, cpu, ICP_PROP_CPU, &error_abort); - object_property_set_bool(obj, true, "realized", &local_err); + qdev_realize(DEVICE(obj), NULL, &local_err); if (local_err) { object_unparent(obj); error_propagate(errp, local_err); diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 8f2b4050cb..2c30dc53d8 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -765,7 +765,7 @@ Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp) object_unref(obj); object_property_set_link(obj, cpu, "cpu", &error_abort); object_property_set_link(obj, OBJECT(xptr), "presenter", &error_abort); - object_property_set_bool(obj, true, "realized", &local_err); + qdev_realize(DEVICE(obj), NULL, &local_err); if (local_err) { goto error; } diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index 4d80a691bc..23420028f5 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -91,7 +91,7 @@ petalogix_ml605_init(MachineState *machine) object_property_set_bool(OBJECT(cpu), true, "dcache-writeback", &error_abort); object_property_set_bool(OBJECT(cpu), true, "endianness", &error_abort); - object_property_set_bool(OBJECT(cpu), true, "realized", &error_abort); + qdev_realize(DEVICE(cpu), NULL, &error_abort); /* Attach emulated BRAM through the LMB. */ memory_region_init_ram(phys_lmb_bram, NULL, "petalogix_ml605.lmb_bram", diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c index 793006a822..a43c980fc9 100644 --- a/hw/microblaze/petalogix_s3adsp1800_mmu.c +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -71,7 +71,7 @@ petalogix_s3adsp1800_init(MachineState *machine) cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU)); object_property_set_str(OBJECT(cpu), "7.10.d", "version", &error_abort); - object_property_set_bool(OBJECT(cpu), true, "realized", &error_abort); + qdev_realize(DEVICE(cpu), NULL, &error_abort); /* Attach emulated BRAM through the LMB. */ memory_region_init_ram(phys_lmb_bram, NULL, diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index e74b047380..abebc7e2ef 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -96,7 +96,7 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) object_property_set_str(OBJECT(&s->cpu), "8.40.b", "version", &error_abort); object_property_set_uint(OBJECT(&s->cpu), 0, "pvr", &error_abort); - object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); + qdev_realize(DEVICE(&s->cpu), NULL, &err); if (err) { error_propagate(errp, err); return; @@ -172,7 +172,7 @@ static void xlnx_zynqmp_pmu_init(MachineState *machine) /* Create the PMU device */ object_initialize_child(OBJECT(machine), "pmu", pmu, TYPE_XLNX_ZYNQMP_PMU_SOC); - object_property_set_bool(OBJECT(pmu), true, "realized", &error_fatal); + qdev_realize(DEVICE(pmu), NULL, &error_fatal); /* Load the kernel */ microblaze_load_kernel(&pmu->cpu, XLNX_ZYNQMP_PMU_RAM_ADDR, diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index 6e2b0174f6..3ec904a55f 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -1003,7 +1003,7 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&phb->lsis), PNV_PHB3_NUM_LSI, "nr-irqs", &error_abort); - object_property_set_bool(OBJECT(&phb->lsis), true, "realized", &local_err); + qdev_realize(DEVICE(&phb->lsis), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1022,7 +1022,7 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) &error_abort); object_property_set_int(OBJECT(&phb->msis), PHB3_MAX_MSI, "nr-irqs", &error_abort); - object_property_set_bool(OBJECT(&phb->msis), true, "realized", &local_err); + qdev_realize(DEVICE(&phb->msis), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1031,7 +1031,7 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) /* Power Bus Common Queue */ object_property_set_link(OBJECT(&phb->pbcq), OBJECT(phb), "phb", &error_abort); - object_property_set_bool(OBJECT(&phb->pbcq), true, "realized", &local_err); + qdev_realize(DEVICE(&phb->pbcq), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 368ae9eacd..10716d759d 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1218,7 +1218,7 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) } object_property_set_int(OBJECT(xsrc), nr_irqs, "nr-irqs", &error_fatal); object_property_set_link(OBJECT(xsrc), OBJECT(phb), "xive", &error_fatal); - object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err); + qdev_realize(DEVICE(xsrc), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index f9b41c5042..2d634c838e 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -390,7 +390,7 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp) object_property_set_int(stk_obj, i, "stack-no", &error_abort); object_property_set_link(stk_obj, OBJECT(pec), "pec", &error_abort); - object_property_set_bool(stk_obj, true, "realized", &local_err); + qdev_realize(DEVICE(stk_obj), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c index a5550d1221..367e408b91 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -238,8 +238,7 @@ static void raven_pcihost_realizefn(DeviceState *d, Error **errp) s->or_irq = OR_IRQ(object_new(TYPE_OR_IRQ)); object_property_set_int(OBJECT(s->or_irq), PCI_NUM_PINS, "num-lines", &error_fatal); - object_property_set_bool(OBJECT(s->or_irq), true, "realized", - &error_fatal); + qdev_realize(DEVICE(s->or_irq), NULL, &error_fatal); sysbus_init_irq(dev, &s->or_irq->out_irq); for (i = 0; i < PCI_NUM_PINS; i++) { diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index b64baf71ca..80b4afd211 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1138,7 +1138,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) "bar", &error_fatal); object_property_set_link(OBJECT(&chip8->psi), OBJECT(chip8->xics), ICS_PROP_XICS, &error_abort); - object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err); + qdev_realize(DEVICE(&chip8->psi), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1149,8 +1149,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) /* Create LPC controller */ object_property_set_link(OBJECT(&chip8->lpc), OBJECT(&chip8->psi), "psi", &error_abort); - object_property_set_bool(OBJECT(&chip8->lpc), true, "realized", - &error_fatal); + qdev_realize(DEVICE(&chip8->lpc), NULL, &error_fatal); pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs); chip->dt_isa_nodename = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x", @@ -1170,7 +1169,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) /* Create the simplified OCC model */ object_property_set_link(OBJECT(&chip8->occ), OBJECT(&chip8->psi), "psi", &error_abort); - object_property_set_bool(OBJECT(&chip8->occ), true, "realized", &local_err); + qdev_realize(DEVICE(&chip8->occ), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1184,8 +1183,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) /* HOMER */ object_property_set_link(OBJECT(&chip8->homer), OBJECT(chip), "chip", &error_abort); - object_property_set_bool(OBJECT(&chip8->homer), true, "realized", - &local_err); + qdev_realize(DEVICE(&chip8->homer), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1352,7 +1350,7 @@ static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp) &error_fatal, NULL); object_property_set_int(OBJECT(eq), core_id, "id", &error_fatal); - object_property_set_bool(OBJECT(eq), true, "realized", &error_fatal); + qdev_realize(DEVICE(eq), NULL, &error_fatal); pnv_xscom_add_subregion(chip, PNV9_XSCOM_EQ_BASE(eq->id), &eq->xscom_regs); @@ -1384,7 +1382,7 @@ static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp) &error_fatal); object_property_set_link(OBJECT(pec), OBJECT(get_system_memory()), "system-memory", &error_abort); - object_property_set_bool(OBJECT(pec), true, "realized", &local_err); + qdev_realize(DEVICE(pec), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1480,7 +1478,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* Processor Service Interface (PSI) Host Bridge */ object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip), "bar", &error_fatal); - object_property_set_bool(OBJECT(&chip9->psi), true, "realized", &local_err); + qdev_realize(DEVICE(&chip9->psi), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1491,7 +1489,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* LPC */ object_property_set_link(OBJECT(&chip9->lpc), OBJECT(&chip9->psi), "psi", &error_abort); - object_property_set_bool(OBJECT(&chip9->lpc), true, "realized", &local_err); + qdev_realize(DEVICE(&chip9->lpc), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1505,7 +1503,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* Create the simplified OCC model */ object_property_set_link(OBJECT(&chip9->occ), OBJECT(&chip9->psi), "psi", &error_abort); - object_property_set_bool(OBJECT(&chip9->occ), true, "realized", &local_err); + qdev_realize(DEVICE(&chip9->occ), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1519,8 +1517,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* HOMER */ object_property_set_link(OBJECT(&chip9->homer), OBJECT(chip), "chip", &error_abort); - object_property_set_bool(OBJECT(&chip9->homer), true, "realized", - &local_err); + qdev_realize(DEVICE(&chip9->homer), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1602,8 +1599,7 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) /* Processor Service Interface (PSI) Host Bridge */ object_property_set_int(OBJECT(&chip10->psi), PNV10_PSIHB_BASE(chip), "bar", &error_fatal); - object_property_set_bool(OBJECT(&chip10->psi), true, "realized", - &local_err); + qdev_realize(DEVICE(&chip10->psi), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1614,8 +1610,7 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) /* LPC */ object_property_set_link(OBJECT(&chip10->lpc), OBJECT(&chip10->psi), "psi", &error_abort); - object_property_set_bool(OBJECT(&chip10->lpc), true, "realized", - &local_err); + qdev_realize(DEVICE(&chip10->lpc), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1734,8 +1729,7 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp) "hrmor", &error_fatal); object_property_set_link(OBJECT(pnv_core), OBJECT(chip), "chip", &error_abort); - object_property_set_bool(OBJECT(pnv_core), true, "realized", - &error_fatal); + qdev_realize(DEVICE(pnv_core), NULL, &error_fatal); /* Each core has an XSCOM MMIO region */ xscom_core_base = pcc->xscom_core_base(chip, core_hwid); diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c index 5f86453b6a..2e1a03daa4 100644 --- a/hw/ppc/pnv_bmc.c +++ b/hw/ppc/pnv_bmc.c @@ -235,7 +235,7 @@ IPMIBmc *pnv_bmc_create(PnvPnor *pnor) obj = object_new(TYPE_IPMI_BMC_SIMULATOR); object_ref(OBJECT(pnor)); object_property_add_const_link(obj, "pnor", OBJECT(pnor)); - object_property_set_bool(obj, true, "realized", &error_fatal); + qdev_realize(DEVICE(obj), NULL, &error_fatal); /* Install the HIOMAP protocol handlers to access the PNOR */ ipmi_sim_register_netfn(IPMI_BMC_SIMULATOR(obj), IPMI_NETFN_OEM, diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 96a446f001..c986c16db1 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -173,7 +173,7 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp) Error *local_err = NULL; PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip); - object_property_set_bool(OBJECT(cpu), true, "realized", &local_err); + qdev_realize(DEVICE(cpu), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 20e54ad5ac..75b8ae9703 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -510,7 +510,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - object_property_set_bool(OBJECT(ics), true, "realized", &err); + qdev_realize(DEVICE(ics), NULL, &err); if (err) { error_propagate(errp, err); return; @@ -851,7 +851,7 @@ static void pnv_psi_power9_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(xsrc), PSIHB9_NUM_IRQS, "nr-irqs", &error_fatal); object_property_set_link(OBJECT(xsrc), OBJECT(psi), "xive", &error_abort); - object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err); + qdev_realize(DEVICE(xsrc), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c381bb6fb5..8d630baa5d 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1730,8 +1730,7 @@ static void spapr_rtc_create(SpaprMachineState *spapr) object_initialize_child_with_props(OBJECT(spapr), "rtc", &spapr->rtc, sizeof(spapr->rtc), TYPE_SPAPR_RTC, &error_fatal, NULL); - object_property_set_bool(OBJECT(&spapr->rtc), true, "realized", - &error_fatal); + qdev_realize(DEVICE(&spapr->rtc), NULL, &error_fatal); object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc), "date"); } @@ -2629,7 +2628,7 @@ static void spapr_init_cpus(SpaprMachineState *spapr) &error_fatal); object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID, &error_fatal); - object_property_set_bool(core, true, "realized", &error_fatal); + qdev_realize(DEVICE(core), NULL, &error_fatal); object_unref(core); } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 9c8c1b14cf..26ad566f42 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -239,7 +239,7 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, CPUState *cs = CPU(cpu); Error *local_err = NULL; - object_property_set_bool(OBJECT(cpu), true, "realized", &local_err); + qdev_realize(DEVICE(cpu), NULL, &local_err); if (local_err) { goto error; } diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index b958f8acb5..2689104295 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -567,7 +567,7 @@ SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type, spapr_drc_index(drc)); object_property_add_child(owner, prop_name, OBJECT(drc)); object_unref(OBJECT(drc)); - object_property_set_bool(OBJECT(drc), true, "realized", NULL); + qdev_realize(DEVICE(drc), NULL, NULL); g_free(prop_name); return drc; diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 7e1d6d59ac..0fecabc135 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -369,7 +369,7 @@ SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn) g_free(tmp); object_unref(OBJECT(tcet)); - object_property_set_bool(OBJECT(tcet), true, "realized", NULL); + qdev_realize(DEVICE(tcet), NULL, NULL); return tcet; } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 79b0e40b66..897bf98587 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -311,7 +311,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) object_property_set_link(obj, OBJECT(spapr), ICS_PROP_XICS, &error_abort); object_property_set_int(obj, smc->nr_xirqs, "nr-irqs", &error_abort); - object_property_set_bool(obj, true, "realized", &local_err); + qdev_realize(DEVICE(obj), NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index bebd3213e1..f6776da8e9 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -61,8 +61,7 @@ static void riscv_opentitan_init(MachineState *machine) /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_IBEX_SOC); - object_property_set_bool(OBJECT(&s->soc), true, "realized", - &error_abort); + qdev_realize(DEVICE(&s->soc), NULL, &error_abort); memory_region_init_ram(main_mem, NULL, "riscv.lowrisc.ibex.ram", memmap[IBEX_RAM].size, &error_fatal); diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c index 56c2be5312..e26c382259 100644 --- a/hw/riscv/riscv_hart.c +++ b/hw/riscv/riscv_hart.c @@ -48,8 +48,7 @@ static void riscv_hart_realize(RISCVHartArrayState *s, int idx, object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], cpu_type); s->harts[idx].env.mhartid = s->hartid_base + idx; qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]); - object_property_set_bool(OBJECT(&s->harts[idx]), true, - "realized", &err); + qdev_realize(DEVICE(&s->harts[idx]), NULL, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index a9e4482270..1c17d02cf0 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -86,8 +86,7 @@ static void riscv_sifive_e_init(MachineState *machine) /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_E_SOC); - object_property_set_bool(OBJECT(&s->soc), true, "realized", - &error_abort); + qdev_realize(DEVICE(&s->soc), NULL, &error_abort); /* Data Tightly Integrated Memory */ memory_region_init_ram(main_mem, NULL, "riscv.sifive.e.ram", diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 5b86520b24..ea197ab64f 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -331,8 +331,7 @@ static void sifive_u_machine_init(MachineState *machine) object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); object_property_set_uint(OBJECT(&s->soc), s->serial, "serial", &error_abort); - object_property_set_bool(OBJECT(&s->soc), true, "realized", - &error_abort); + qdev_realize(DEVICE(&s->soc), NULL, &error_abort); /* register RAM */ memory_region_init_ram(main_mem, NULL, "riscv.sifive.u.ram", @@ -530,10 +529,8 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) * CPU must exist and have been parented into the cluster before the * cluster is realized. */ - object_property_set_bool(OBJECT(&s->e_cluster), true, "realized", - &error_abort); - object_property_set_bool(OBJECT(&s->u_cluster), true, "realized", - &error_abort); + qdev_realize(DEVICE(&s->e_cluster), NULL, &error_abort); + qdev_realize(DEVICE(&s->u_cluster), NULL, &error_abort); /* boot rom */ memory_region_init_rom(mask_rom, OBJECT(dev), "riscv.sifive.u.mrom", diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index d304b85640..1e036cc602 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -48,7 +48,7 @@ void s390_skeys_init(void) obj); object_unref(obj); - qdev_init_nofail(DEVICE(obj)); + qdev_realize(DEVICE(obj), NULL, &error_fatal); } static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn, diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index 6d1e587527..0144b9021c 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -50,7 +50,7 @@ void s390_stattrib_init(void) obj); object_unref(obj); - qdev_init_nofail(DEVICE(obj)); + qdev_realize(DEVICE(obj), NULL, &error_fatal); } /* Console commands: */ diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 201f9604fe..b111406d56 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -75,7 +75,7 @@ static S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, if (err != NULL) { goto out; } - object_property_set_bool(OBJECT(cpu), true, "realized", &err); + qdev_realize(DEVICE(cpu), NULL, &err); out: object_unref(OBJECT(cpu)); @@ -210,7 +210,7 @@ static void s390_init_ipl_dev(const char *kernel_filename, object_property_add_child(qdev_get_machine(), TYPE_S390_IPL, new); object_unref(new); - qdev_init_nofail(dev); + qdev_realize(dev, NULL, &error_fatal); } static void s390_create_virtio_net(BusState *bus, const char *name) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index b66afb35c8..d39f6d7785 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -322,7 +322,7 @@ void s390_sclp_init(void) object_property_add_child(qdev_get_machine(), TYPE_SCLP, new); object_unref(new); - qdev_init_nofail(DEVICE(new)); + qdev_realize(DEVICE(new), NULL, &error_fatal); } static void sclp_realize(DeviceState *dev, Error **errp) diff --git a/hw/s390x/tod.c b/hw/s390x/tod.c index 7324e37b5e..3c2979175e 100644 --- a/hw/s390x/tod.c +++ b/hw/s390x/tod.c @@ -29,7 +29,7 @@ void s390_init_tod(void) object_property_add_child(qdev_get_machine(), TYPE_S390_TOD, obj); object_unref(obj); - qdev_init_nofail(DEVICE(obj)); + qdev_realize(DEVICE(obj), NULL, &error_fatal); } S390TODState *s390_get_todstate(void) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 4fe97f9b41..b1b311baa2 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6167,8 +6167,7 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) if (cpu->apic_state == NULL) { return; } - object_property_set_bool(OBJECT(cpu->apic_state), true, "realized", - errp); + qdev_realize(DEVICE(cpu->apic_state), NULL, errp); /* Map APIC MMIO area */ apic = APIC_COMMON(cpu->apic_state); diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c index 42d3dd7030..1e6b0f33ff 100644 --- a/tests/test-qdev-global-props.c +++ b/tests/test-qdev-global-props.c @@ -26,6 +26,7 @@ #include "hw/qdev-properties.h" #include "qom/object.h" +#include "qapi/error.h" #include "qapi/visitor.h" @@ -76,7 +77,7 @@ static void test_static_prop_subprocess(void) MyType *mt; mt = STATIC_TYPE(object_new(TYPE_STATIC_PROPS)); - qdev_init_nofail(DEVICE(mt)); + qdev_realize(DEVICE(mt), NULL, &error_fatal); g_assert_cmpuint(mt->prop1, ==, PROP_DEFAULT); } @@ -111,7 +112,7 @@ static void test_static_globalprop_subprocess(void) register_global_properties(props); mt = STATIC_TYPE(object_new(TYPE_STATIC_PROPS)); - qdev_init_nofail(DEVICE(mt)); + qdev_realize(DEVICE(mt), NULL, &error_fatal); g_assert_cmpuint(mt->prop1, ==, 200); g_assert_cmpuint(mt->prop2, ==, PROP_DEFAULT); @@ -229,7 +230,7 @@ static void test_dynamic_globalprop_subprocess(void) register_global_properties(props); mt = DYNAMIC_TYPE(object_new(TYPE_DYNAMIC_PROPS)); - qdev_init_nofail(DEVICE(mt)); + qdev_realize(DEVICE(mt), NULL, &error_fatal); g_assert_cmpuint(mt->prop1, ==, 101); g_assert_cmpuint(mt->prop2, ==, 102); @@ -272,7 +273,7 @@ static void test_subclass_global_props(void) register_global_properties(props); mt = STATIC_TYPE(object_new(TYPE_SUBCLASS)); - qdev_init_nofail(DEVICE(mt)); + qdev_realize(DEVICE(mt), NULL, &error_fatal); g_assert_cmpuint(mt->prop1, ==, 102); g_assert_cmpuint(mt->prop2, ==, 104); From c835fac3f074f85c6d61bcc77c509816fdf27080 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:46 +0200 Subject: [PATCH 1282/2595] qdev: qdev_init_nofail() is now unused, drop Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-58-armbru@redhat.com> --- hw/core/qdev.c | 29 ----------------------------- include/hw/qdev-core.h | 3 +-- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 50336168f2..2131c7f951 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -376,35 +376,6 @@ void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, qdev_unrealize(dev); } -/* - * Realize @dev. - * Device properties should be set before calling this function. IRQs - * and MMIO regions should be connected/mapped after calling this - * function. - * On failure, report an error with error_report() and terminate the - * program. This is okay during machine creation. Don't use for - * hotplug, because there callers need to recover from failure. - * Exception: if you know the device's init() callback can't fail, - * then qdev_init_nofail() can't fail either, and is therefore usable - * even then. But relying on the device implementation that way is - * somewhat unclean, and best avoided. - */ -void qdev_init_nofail(DeviceState *dev) -{ - Error *err = NULL; - - assert(!dev->realized); - - object_ref(OBJECT(dev)); - object_property_set_bool(OBJECT(dev), true, "realized", &err); - if (err) { - error_reportf_err(err, "Initialization of device %s failed: ", - object_get_typename(OBJECT(dev))); - exit(1); - } - object_unref(OBJECT(dev)); -} - /* * Realize @dev. * @dev must not be plugged into a bus. diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index ef6137b6a8..7dc10be46f 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -57,7 +57,7 @@ typedef void (*BusUnrealize)(BusState *bus); * After successful realization, setting static properties will fail. * * As an interim step, the #DeviceState:realized property can also be - * set with qdev_realize() or qdev_init_nofail(). + * set with qdev_realize(). * In the future, devices will propagate this state change to their children * and along busses they expose. * The point in time will be deferred to machine creation, so that values @@ -322,7 +322,6 @@ compat_props_add(GPtrArray *arr, DeviceState *qdev_new(const char *name); DeviceState *qdev_try_new(const char *name); -void qdev_init_nofail(DeviceState *dev); bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp); bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp); void qdev_unrealize(DeviceState *dev); From b77b5b3dc7a4730d804090d359c57d33573cf85a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 10 Jun 2020 07:32:47 +0200 Subject: [PATCH 1283/2595] MAINTAINERS: Make section QOM cover hw/core/*bus.c as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paolo Bonzini Message-Id: <20200610053247.1583243-59-armbru@redhat.com> --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index de25c82249..b69edc2d2f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2298,6 +2298,8 @@ R: Eduardo Habkost S: Supported F: docs/qdev-device-use.txt F: hw/core/qdev* +F: hw/core/bus.c +F: hw/core/sysbus.c F: include/hw/qdev* F: include/monitor/qdev.h F: include/qom/ From 9593a3988c3e788790aa107d778386b09f456a6d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:25 +0100 Subject: [PATCH 1284/2595] target/arm: Fix missing temp frees in do_vshll_2sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The widenfn() in do_vshll_2sh() does not free the input 32-bit TCGv, so we need to do this in the calling code. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé --- target/arm/translate-neon.inc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 664d361260..299a61f067 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1624,6 +1624,7 @@ static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, tmp = tcg_temp_new_i64(); widenfn(tmp, rm0); + tcg_temp_free_i32(rm0); if (a->shift != 0) { tcg_gen_shli_i64(tmp, tmp, a->shift); tcg_gen_andi_i64(tmp, tmp, ~widen_mask); @@ -1631,6 +1632,7 @@ static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, neon_store_reg64(tmp, a->vd); widenfn(tmp, rm1); + tcg_temp_free_i32(rm1); if (a->shift != 0) { tcg_gen_shli_i64(tmp, tmp, a->shift); tcg_gen_andi_i64(tmp, tmp, ~widen_mask); From b28be09570d0827969b62b8f82b0f720a9915427 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:25 +0100 Subject: [PATCH 1285/2595] target/arm: Convert Neon 3-reg-diff prewidening ops to decodetree Convert the "pre-widening" insns VADDL, VSUBL, VADDW and VSUBW in the Neon 3-registers-different-lengths group to decodetree. These insns work by widening one or both inputs to double their size, performing an add or subtract at the doubled size and then storing the double-size result. As usual, rather than copying the loop of the original decoder (which needs awkward code to avoid problems when source and destination registers overlap) we just unroll the two passes. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 43 +++++++++++++ target/arm/translate-neon.inc.c | 104 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 16 ++--- 3 files changed, 151 insertions(+), 12 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index bd1b0e13f7..144a527ee6 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -397,3 +397,46 @@ VCVT_FU_2sh 1111 001 1 1 . ...... .... 1111 0 . . 1 .... @2reg_vcvt # So we have a single decode line and check the cmode/op in the # trans function. Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm + +###################################################################### +# Within the "two registers, or three registers of different lengths" +# grouping ([23,4]=0b10), bits [21:20] are either part of the opcode +# decode: 0b11 for VEXT, two-reg-misc, VTBL, and duplicate-scalar; +# or they are a size field for the three-reg-different-lengths and +# two-reg-and-scalar insn groups (where size cannot be 0b11). This +# is slightly awkward for decodetree: we handle it with this +# non-exclusive group which contains within it two exclusive groups: +# one for the size=0b11 patterns, and one for the size-not-0b11 +# patterns. This allows us to check that none of the insns within +# each subgroup accidentally overlap each other. Note that all the +# trans functions for the size-not-0b11 patterns must check and +# return false for size==3. +###################################################################### +{ + # 0b11 subgroup will go here + + # Subgroup for size != 0b11 + [ + ################################################################## + # 3-reg-different-length grouping: + # 1111 001 U 1 D sz!=11 Vn:4 Vd:4 opc:4 N 0 M 0 Vm:4 + ################################################################## + + &3diff vm vn vd size + + @3diff .... ... . . . size:2 .... .... .... . . . . .... \ + &3diff vm=%vm_dp vn=%vn_dp vd=%vd_dp + + VADDL_S_3d 1111 001 0 1 . .. .... .... 0000 . 0 . 0 .... @3diff + VADDL_U_3d 1111 001 1 1 . .. .... .... 0000 . 0 . 0 .... @3diff + + VADDW_S_3d 1111 001 0 1 . .. .... .... 0001 . 0 . 0 .... @3diff + VADDW_U_3d 1111 001 1 1 . .. .... .... 0001 . 0 . 0 .... @3diff + + VSUBL_S_3d 1111 001 0 1 . .. .... .... 0010 . 0 . 0 .... @3diff + VSUBL_U_3d 1111 001 1 1 . .. .... .... 0010 . 0 . 0 .... @3diff + + VSUBW_S_3d 1111 001 0 1 . .. .... .... 0011 . 0 . 0 .... @3diff + VSUBW_U_3d 1111 001 1 1 . .. .... .... 0011 . 0 . 0 .... @3diff + ] +} diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 299a61f067..9b9d411107 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1828,3 +1828,107 @@ static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a) } return do_1reg_imm(s, a, fn); } + +static bool do_prewiden_3d(DisasContext *s, arg_3diff *a, + NeonGenWidenFn *widenfn, + NeonGenTwo64OpFn *opfn, + bool src1_wide) +{ + /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */ + TCGv_i64 rn0_64, rn1_64, rm_64; + TCGv_i32 rm; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if (!widenfn || !opfn) { + /* size == 3 case, which is an entirely different insn group */ + return false; + } + + if ((a->vd & 1) || (src1_wide && (a->vn & 1))) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + rn0_64 = tcg_temp_new_i64(); + rn1_64 = tcg_temp_new_i64(); + rm_64 = tcg_temp_new_i64(); + + if (src1_wide) { + neon_load_reg64(rn0_64, a->vn); + } else { + TCGv_i32 tmp = neon_load_reg(a->vn, 0); + widenfn(rn0_64, tmp); + tcg_temp_free_i32(tmp); + } + rm = neon_load_reg(a->vm, 0); + + widenfn(rm_64, rm); + tcg_temp_free_i32(rm); + opfn(rn0_64, rn0_64, rm_64); + + /* + * Load second pass inputs before storing the first pass result, to + * avoid incorrect results if a narrow input overlaps with the result. + */ + if (src1_wide) { + neon_load_reg64(rn1_64, a->vn + 1); + } else { + TCGv_i32 tmp = neon_load_reg(a->vn, 1); + widenfn(rn1_64, tmp); + tcg_temp_free_i32(tmp); + } + rm = neon_load_reg(a->vm, 1); + + neon_store_reg64(rn0_64, a->vd); + + widenfn(rm_64, rm); + tcg_temp_free_i32(rm); + opfn(rn1_64, rn1_64, rm_64); + neon_store_reg64(rn1_64, a->vd + 1); + + tcg_temp_free_i64(rn0_64); + tcg_temp_free_i64(rn1_64); + tcg_temp_free_i64(rm_64); + + return true; +} + +#define DO_PREWIDEN(INSN, S, EXT, OP, SRC1WIDE) \ + static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ + { \ + static NeonGenWidenFn * const widenfn[] = { \ + gen_helper_neon_widen_##S##8, \ + gen_helper_neon_widen_##S##16, \ + tcg_gen_##EXT##_i32_i64, \ + NULL, \ + }; \ + static NeonGenTwo64OpFn * const addfn[] = { \ + gen_helper_neon_##OP##l_u16, \ + gen_helper_neon_##OP##l_u32, \ + tcg_gen_##OP##_i64, \ + NULL, \ + }; \ + return do_prewiden_3d(s, a, widenfn[a->size], \ + addfn[a->size], SRC1WIDE); \ + } + +DO_PREWIDEN(VADDL_S, s, ext, add, false) +DO_PREWIDEN(VADDL_U, u, extu, add, false) +DO_PREWIDEN(VSUBL_S, s, ext, sub, false) +DO_PREWIDEN(VSUBL_U, u, extu, sub, false) +DO_PREWIDEN(VADDW_S, s, ext, add, true) +DO_PREWIDEN(VADDW_U, u, extu, add, true) +DO_PREWIDEN(VSUBW_S, s, ext, sub, true) +DO_PREWIDEN(VSUBW_U, u, extu, sub, true) diff --git a/target/arm/translate.c b/target/arm/translate.c index bcdfec34d2..9376534441 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5241,7 +5241,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) /* Three registers of different lengths. */ int src1_wide; int src2_wide; - int prewiden; /* undefreq: bit 0 : UNDEF if size == 0 * bit 1 : UNDEF if size == 1 * bit 2 : UNDEF if size == 2 @@ -5251,10 +5250,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int undefreq; /* prewiden, src1_wide, src2_wide, undefreq */ static const int neon_3reg_wide[16][4] = { - {1, 0, 0, 0}, /* VADDL */ - {1, 1, 0, 0}, /* VADDW */ - {1, 0, 0, 0}, /* VSUBL */ - {1, 1, 0, 0}, /* VSUBW */ + {0, 0, 0, 7}, /* VADDL: handled by decodetree */ + {0, 0, 0, 7}, /* VADDW: handled by decodetree */ + {0, 0, 0, 7}, /* VSUBL: handled by decodetree */ + {0, 0, 0, 7}, /* VSUBW: handled by decodetree */ {0, 1, 1, 0}, /* VADDHN */ {0, 0, 0, 0}, /* VABAL */ {0, 1, 1, 0}, /* VSUBHN */ @@ -5269,7 +5268,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) {0, 0, 0, 7}, /* Reserved: always UNDEF */ }; - prewiden = neon_3reg_wide[op][0]; src1_wide = neon_3reg_wide[op][1]; src2_wide = neon_3reg_wide[op][2]; undefreq = neon_3reg_wide[op][3]; @@ -5322,9 +5320,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } else { tmp = neon_load_reg(rn, pass); } - if (prewiden) { - gen_neon_widen(cpu_V0, tmp, size, u); - } } if (src2_wide) { neon_load_reg64(cpu_V1, rm + pass); @@ -5335,9 +5330,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } else { tmp2 = neon_load_reg(rm, pass); } - if (prewiden) { - gen_neon_widen(cpu_V1, tmp2, size, u); - } } switch (op) { case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */ From 0fa1ab0302badabc3581aefcbb2f189ef52c4985 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:25 +0100 Subject: [PATCH 1286/2595] target/arm: Convert Neon 3-reg-diff narrowing ops to decodetree Convert the narrow-to-high-half insns VADDHN, VSUBHN, VRADDHN, VRSUBHN in the Neon 3-registers-different-lengths group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 6 +++ target/arm/translate-neon.inc.c | 87 +++++++++++++++++++++++++++++++ target/arm/translate.c | 91 ++++----------------------------- 3 files changed, 104 insertions(+), 80 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 144a527ee6..a2234dfa4f 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -438,5 +438,11 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VSUBW_S_3d 1111 001 0 1 . .. .... .... 0011 . 0 . 0 .... @3diff VSUBW_U_3d 1111 001 1 1 . .. .... .... 0011 . 0 . 0 .... @3diff + + VADDHN_3d 1111 001 0 1 . .. .... .... 0100 . 0 . 0 .... @3diff + VRADDHN_3d 1111 001 1 1 . .. .... .... 0100 . 0 . 0 .... @3diff + + VSUBHN_3d 1111 001 0 1 . .. .... .... 0110 . 0 . 0 .... @3diff + VRSUBHN_3d 1111 001 1 1 . .. .... .... 0110 . 0 . 0 .... @3diff ] } diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 9b9d411107..0c3965802a 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1932,3 +1932,90 @@ DO_PREWIDEN(VADDW_S, s, ext, add, true) DO_PREWIDEN(VADDW_U, u, extu, add, true) DO_PREWIDEN(VSUBW_S, s, ext, sub, true) DO_PREWIDEN(VSUBW_U, u, extu, sub, true) + +static bool do_narrow_3d(DisasContext *s, arg_3diff *a, + NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn) +{ + /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */ + TCGv_i64 rn_64, rm_64; + TCGv_i32 rd0, rd1; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if (!opfn || !narrowfn) { + /* size == 3 case, which is an entirely different insn group */ + return false; + } + + if ((a->vn | a->vm) & 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + rn_64 = tcg_temp_new_i64(); + rm_64 = tcg_temp_new_i64(); + rd0 = tcg_temp_new_i32(); + rd1 = tcg_temp_new_i32(); + + neon_load_reg64(rn_64, a->vn); + neon_load_reg64(rm_64, a->vm); + + opfn(rn_64, rn_64, rm_64); + + narrowfn(rd0, rn_64); + + neon_load_reg64(rn_64, a->vn + 1); + neon_load_reg64(rm_64, a->vm + 1); + + opfn(rn_64, rn_64, rm_64); + + narrowfn(rd1, rn_64); + + neon_store_reg(a->vd, 0, rd0); + neon_store_reg(a->vd, 1, rd1); + + tcg_temp_free_i64(rn_64); + tcg_temp_free_i64(rm_64); + + return true; +} + +#define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP) \ + static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ + { \ + static NeonGenTwo64OpFn * const addfn[] = { \ + gen_helper_neon_##OP##l_u16, \ + gen_helper_neon_##OP##l_u32, \ + tcg_gen_##OP##_i64, \ + NULL, \ + }; \ + static NeonGenNarrowFn * const narrowfn[] = { \ + gen_helper_neon_##NARROWTYPE##_high_u8, \ + gen_helper_neon_##NARROWTYPE##_high_u16, \ + EXTOP, \ + NULL, \ + }; \ + return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]); \ + } + +static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn) +{ + tcg_gen_addi_i64(rn, rn, 1u << 31); + tcg_gen_extrh_i64_i32(rd, rn); +} + +DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32) +DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32) +DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32) +DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32) diff --git a/target/arm/translate.c b/target/arm/translate.c index 9376534441..3fe39cd4f4 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3231,16 +3231,6 @@ static inline void gen_neon_addl(int size) } } -static inline void gen_neon_subl(int size) -{ - switch (size) { - case 0: gen_helper_neon_subl_u16(CPU_V001); break; - case 1: gen_helper_neon_subl_u32(CPU_V001); break; - case 2: tcg_gen_sub_i64(CPU_V001); break; - default: abort(); - } -} - static inline void gen_neon_negl(TCGv_i64 var, int size) { switch (size) { @@ -5239,8 +5229,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) op = (insn >> 8) & 0xf; if ((insn & (1 << 6)) == 0) { /* Three registers of different lengths. */ - int src1_wide; - int src2_wide; /* undefreq: bit 0 : UNDEF if size == 0 * bit 1 : UNDEF if size == 1 * bit 2 : UNDEF if size == 2 @@ -5254,9 +5242,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) {0, 0, 0, 7}, /* VADDW: handled by decodetree */ {0, 0, 0, 7}, /* VSUBL: handled by decodetree */ {0, 0, 0, 7}, /* VSUBW: handled by decodetree */ - {0, 1, 1, 0}, /* VADDHN */ + {0, 0, 0, 7}, /* VADDHN: handled by decodetree */ {0, 0, 0, 0}, /* VABAL */ - {0, 1, 1, 0}, /* VSUBHN */ + {0, 0, 0, 7}, /* VSUBHN: handled by decodetree */ {0, 0, 0, 0}, /* VABDL */ {0, 0, 0, 0}, /* VMLAL */ {0, 0, 0, 9}, /* VQDMLAL */ @@ -5268,17 +5256,13 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) {0, 0, 0, 7}, /* Reserved: always UNDEF */ }; - src1_wide = neon_3reg_wide[op][1]; - src2_wide = neon_3reg_wide[op][2]; undefreq = neon_3reg_wide[op][3]; if ((undefreq & (1 << size)) || ((undefreq & 8) && u)) { return 1; } - if ((src1_wide && (rn & 1)) || - (src2_wide && (rm & 1)) || - (!src2_wide && (rd & 1))) { + if (rd & 1) { return 1; } @@ -5302,42 +5286,26 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) /* Avoid overlapping operands. Wide source operands are always aligned so will never overlap with wide destinations in problematic ways. */ - if (rd == rm && !src2_wide) { + if (rd == rm) { tmp = neon_load_reg(rm, 1); neon_store_scratch(2, tmp); - } else if (rd == rn && !src1_wide) { + } else if (rd == rn) { tmp = neon_load_reg(rn, 1); neon_store_scratch(2, tmp); } tmp3 = NULL; for (pass = 0; pass < 2; pass++) { - if (src1_wide) { - neon_load_reg64(cpu_V0, rn + pass); - tmp = NULL; + if (pass == 1 && rd == rn) { + tmp = neon_load_scratch(2); } else { - if (pass == 1 && rd == rn) { - tmp = neon_load_scratch(2); - } else { - tmp = neon_load_reg(rn, pass); - } + tmp = neon_load_reg(rn, pass); } - if (src2_wide) { - neon_load_reg64(cpu_V1, rm + pass); - tmp2 = NULL; + if (pass == 1 && rd == rm) { + tmp2 = neon_load_scratch(2); } else { - if (pass == 1 && rd == rm) { - tmp2 = neon_load_scratch(2); - } else { - tmp2 = neon_load_reg(rm, pass); - } + tmp2 = neon_load_reg(rm, pass); } switch (op) { - case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */ - gen_neon_addl(size); - break; - case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHN, VRSUBHN */ - gen_neon_subl(size); - break; case 5: case 7: /* VABAL, VABDL */ switch ((size << 1) | u) { case 0: @@ -5395,43 +5363,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) abort(); } neon_store_reg64(cpu_V0, rd + pass); - } else if (op == 4 || op == 6) { - /* Narrowing operation. */ - tmp = tcg_temp_new_i32(); - if (!u) { - switch (size) { - case 0: - gen_helper_neon_narrow_high_u8(tmp, cpu_V0); - break; - case 1: - gen_helper_neon_narrow_high_u16(tmp, cpu_V0); - break; - case 2: - tcg_gen_extrh_i64_i32(tmp, cpu_V0); - break; - default: abort(); - } - } else { - switch (size) { - case 0: - gen_helper_neon_narrow_round_high_u8(tmp, cpu_V0); - break; - case 1: - gen_helper_neon_narrow_round_high_u16(tmp, cpu_V0); - break; - case 2: - tcg_gen_addi_i64(cpu_V0, cpu_V0, 1u << 31); - tcg_gen_extrh_i64_i32(tmp, cpu_V0); - break; - default: abort(); - } - } - if (pass == 0) { - tmp3 = tmp; - } else { - neon_store_reg(rd, 0, tmp3); - neon_store_reg(rd, 1, tmp); - } } else { /* Write back the result. */ neon_store_reg64(cpu_V0, rd + pass); From f5b28401200ec95ba89552df3ecdcdc342f6b90b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:25 +0100 Subject: [PATCH 1287/2595] target/arm: Convert Neon 3-reg-diff VABAL, VABDL to decodetree Convert the Neon 3-reg-diff insns VABAL and VABDL to decodetree. Like almost all the remaining insns in this group, these are a combination of a two-input operation which returns a double width result and then a possible accumulation of that double width result into the destination. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 6 ++ target/arm/translate-neon.inc.c | 132 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 31 +------- target/arm/translate.h | 1 + 4 files changed, 142 insertions(+), 28 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index a2234dfa4f..4f0aaaf6bb 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -442,7 +442,13 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VADDHN_3d 1111 001 0 1 . .. .... .... 0100 . 0 . 0 .... @3diff VRADDHN_3d 1111 001 1 1 . .. .... .... 0100 . 0 . 0 .... @3diff + VABAL_S_3d 1111 001 0 1 . .. .... .... 0101 . 0 . 0 .... @3diff + VABAL_U_3d 1111 001 1 1 . .. .... .... 0101 . 0 . 0 .... @3diff + VSUBHN_3d 1111 001 0 1 . .. .... .... 0110 . 0 . 0 .... @3diff VRSUBHN_3d 1111 001 1 1 . .. .... .... 0110 . 0 . 0 .... @3diff + + VABDL_S_3d 1111 001 0 1 . .. .... .... 0111 . 0 . 0 .... @3diff + VABDL_U_3d 1111 001 1 1 . .. .... .... 0111 . 0 . 0 .... @3diff ] } diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 0c3965802a..bea9360ce3 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2019,3 +2019,135 @@ DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32) DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32) DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32) DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32) + +static bool do_long_3d(DisasContext *s, arg_3diff *a, + NeonGenTwoOpWidenFn *opfn, + NeonGenTwo64OpFn *accfn) +{ + /* + * 3-regs different lengths, long operations. + * These perform an operation on two inputs that returns a double-width + * result, and then possibly perform an accumulation operation of + * that result into the double-width destination. + */ + TCGv_i64 rd0, rd1, tmp; + TCGv_i32 rn, rm; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if (!opfn) { + /* size == 3 case, which is an entirely different insn group */ + return false; + } + + if (a->vd & 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + rd0 = tcg_temp_new_i64(); + rd1 = tcg_temp_new_i64(); + + rn = neon_load_reg(a->vn, 0); + rm = neon_load_reg(a->vm, 0); + opfn(rd0, rn, rm); + tcg_temp_free_i32(rn); + tcg_temp_free_i32(rm); + + rn = neon_load_reg(a->vn, 1); + rm = neon_load_reg(a->vm, 1); + opfn(rd1, rn, rm); + tcg_temp_free_i32(rn); + tcg_temp_free_i32(rm); + + /* Don't store results until after all loads: they might overlap */ + if (accfn) { + tmp = tcg_temp_new_i64(); + neon_load_reg64(tmp, a->vd); + accfn(tmp, tmp, rd0); + neon_store_reg64(tmp, a->vd); + neon_load_reg64(tmp, a->vd + 1); + accfn(tmp, tmp, rd1); + neon_store_reg64(tmp, a->vd + 1); + tcg_temp_free_i64(tmp); + } else { + neon_store_reg64(rd0, a->vd); + neon_store_reg64(rd1, a->vd + 1); + } + + tcg_temp_free_i64(rd0); + tcg_temp_free_i64(rd1); + + return true; +} + +static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + gen_helper_neon_abdl_s16, + gen_helper_neon_abdl_s32, + gen_helper_neon_abdl_s64, + NULL, + }; + + return do_long_3d(s, a, opfn[a->size], NULL); +} + +static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + gen_helper_neon_abdl_u16, + gen_helper_neon_abdl_u32, + gen_helper_neon_abdl_u64, + NULL, + }; + + return do_long_3d(s, a, opfn[a->size], NULL); +} + +static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + gen_helper_neon_abdl_s16, + gen_helper_neon_abdl_s32, + gen_helper_neon_abdl_s64, + NULL, + }; + static NeonGenTwo64OpFn * const addfn[] = { + gen_helper_neon_addl_u16, + gen_helper_neon_addl_u32, + tcg_gen_add_i64, + NULL, + }; + + return do_long_3d(s, a, opfn[a->size], addfn[a->size]); +} + +static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + gen_helper_neon_abdl_u16, + gen_helper_neon_abdl_u32, + gen_helper_neon_abdl_u64, + NULL, + }; + static NeonGenTwo64OpFn * const addfn[] = { + gen_helper_neon_addl_u16, + gen_helper_neon_addl_u32, + tcg_gen_add_i64, + NULL, + }; + + return do_long_3d(s, a, opfn[a->size], addfn[a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 3fe39cd4f4..37fe9d46e0 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5243,9 +5243,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) {0, 0, 0, 7}, /* VSUBL: handled by decodetree */ {0, 0, 0, 7}, /* VSUBW: handled by decodetree */ {0, 0, 0, 7}, /* VADDHN: handled by decodetree */ - {0, 0, 0, 0}, /* VABAL */ + {0, 0, 0, 7}, /* VABAL */ {0, 0, 0, 7}, /* VSUBHN: handled by decodetree */ - {0, 0, 0, 0}, /* VABDL */ + {0, 0, 0, 7}, /* VABDL */ {0, 0, 0, 0}, /* VMLAL */ {0, 0, 0, 9}, /* VQDMLAL */ {0, 0, 0, 0}, /* VMLSL */ @@ -5306,31 +5306,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp2 = neon_load_reg(rm, pass); } switch (op) { - case 5: case 7: /* VABAL, VABDL */ - switch ((size << 1) | u) { - case 0: - gen_helper_neon_abdl_s16(cpu_V0, tmp, tmp2); - break; - case 1: - gen_helper_neon_abdl_u16(cpu_V0, tmp, tmp2); - break; - case 2: - gen_helper_neon_abdl_s32(cpu_V0, tmp, tmp2); - break; - case 3: - gen_helper_neon_abdl_u32(cpu_V0, tmp, tmp2); - break; - case 4: - gen_helper_neon_abdl_s64(cpu_V0, tmp, tmp2); - break; - case 5: - gen_helper_neon_abdl_u64(cpu_V0, tmp, tmp2); - break; - default: abort(); - } - tcg_temp_free_i32(tmp2); - tcg_temp_free_i32(tmp); - break; case 8: case 9: case 10: case 11: case 12: case 13: /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */ gen_neon_mull(cpu_V0, tmp, tmp2, size, u); @@ -5349,7 +5324,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case 10: /* VMLSL */ gen_neon_negl(cpu_V0, size); /* Fall through */ - case 5: case 8: /* VABAL, VMLAL */ + case 8: /* VABAL, VMLAL */ gen_neon_addl(size); break; case 9: case 11: /* VQDMLAL, VQDMLSL */ diff --git a/target/arm/translate.h b/target/arm/translate.h index c937dfe9bf..62ed5c4780 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -371,6 +371,7 @@ typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64); typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64); typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32); +typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32); typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64); From 3a1d9eb07b767a7592abca642af80906f9eab0ed Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:26 +0100 Subject: [PATCH 1288/2595] target/arm: Convert Neon 3-reg-diff long multiplies Convert the Neon 3-reg-diff insns VMULL, VMLAL and VMLSL; these perform a 32x32->64 multiply with possible accumulate. Note that for VMLSL we do the accumulate directly with a subtraction rather than doing a negate-then-add as the old code did. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 9 +++++ target/arm/translate-neon.inc.c | 71 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 21 +++------- 3 files changed, 86 insertions(+), 15 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 4f0aaaf6bb..1da492df14 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -450,5 +450,14 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VABDL_S_3d 1111 001 0 1 . .. .... .... 0111 . 0 . 0 .... @3diff VABDL_U_3d 1111 001 1 1 . .. .... .... 0111 . 0 . 0 .... @3diff + + VMLAL_S_3d 1111 001 0 1 . .. .... .... 1000 . 0 . 0 .... @3diff + VMLAL_U_3d 1111 001 1 1 . .. .... .... 1000 . 0 . 0 .... @3diff + + VMLSL_S_3d 1111 001 0 1 . .. .... .... 1010 . 0 . 0 .... @3diff + VMLSL_U_3d 1111 001 1 1 . .. .... .... 1010 . 0 . 0 .... @3diff + + VMULL_S_3d 1111 001 0 1 . .. .... .... 1100 . 0 . 0 .... @3diff + VMULL_U_3d 1111 001 1 1 . .. .... .... 1100 . 0 . 0 .... @3diff ] } diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index bea9360ce3..c435f0685d 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2151,3 +2151,74 @@ static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a) return do_long_3d(s, a, opfn[a->size], addfn[a->size]); } + +static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) +{ + TCGv_i32 lo = tcg_temp_new_i32(); + TCGv_i32 hi = tcg_temp_new_i32(); + + tcg_gen_muls2_i32(lo, hi, rn, rm); + tcg_gen_concat_i32_i64(rd, lo, hi); + + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); +} + +static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) +{ + TCGv_i32 lo = tcg_temp_new_i32(); + TCGv_i32 hi = tcg_temp_new_i32(); + + tcg_gen_mulu2_i32(lo, hi, rn, rm); + tcg_gen_concat_i32_i64(rd, lo, hi); + + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); +} + +static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + gen_helper_neon_mull_s8, + gen_helper_neon_mull_s16, + gen_mull_s32, + NULL, + }; + + return do_long_3d(s, a, opfn[a->size], NULL); +} + +static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + gen_helper_neon_mull_u8, + gen_helper_neon_mull_u16, + gen_mull_u32, + NULL, + }; + + return do_long_3d(s, a, opfn[a->size], NULL); +} + +#define DO_VMLAL(INSN,MULL,ACC) \ + static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ + { \ + static NeonGenTwoOpWidenFn * const opfn[] = { \ + gen_helper_neon_##MULL##8, \ + gen_helper_neon_##MULL##16, \ + gen_##MULL##32, \ + NULL, \ + }; \ + static NeonGenTwo64OpFn * const accfn[] = { \ + gen_helper_neon_##ACC##l_u16, \ + gen_helper_neon_##ACC##l_u32, \ + tcg_gen_##ACC##_i64, \ + NULL, \ + }; \ + return do_long_3d(s, a, opfn[a->size], accfn[a->size]); \ + } + +DO_VMLAL(VMLAL_S,mull_s,add) +DO_VMLAL(VMLAL_U,mull_u,add) +DO_VMLAL(VMLSL_S,mull_s,sub) +DO_VMLAL(VMLSL_U,mull_u,sub) diff --git a/target/arm/translate.c b/target/arm/translate.c index 37fe9d46e0..a2c47d19f2 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5246,11 +5246,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) {0, 0, 0, 7}, /* VABAL */ {0, 0, 0, 7}, /* VSUBHN: handled by decodetree */ {0, 0, 0, 7}, /* VABDL */ - {0, 0, 0, 0}, /* VMLAL */ + {0, 0, 0, 7}, /* VMLAL */ {0, 0, 0, 9}, /* VQDMLAL */ - {0, 0, 0, 0}, /* VMLSL */ + {0, 0, 0, 7}, /* VMLSL */ {0, 0, 0, 9}, /* VQDMLSL */ - {0, 0, 0, 0}, /* Integer VMULL */ + {0, 0, 0, 7}, /* Integer VMULL */ {0, 0, 0, 9}, /* VQDMULL */ {0, 0, 0, 0xa}, /* Polynomial VMULL */ {0, 0, 0, 7}, /* Reserved: always UNDEF */ @@ -5306,8 +5306,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp2 = neon_load_reg(rm, pass); } switch (op) { - case 8: case 9: case 10: case 11: case 12: case 13: - /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */ + case 9: case 11: case 13: + /* VQDMLAL, VQDMLSL, VQDMULL */ gen_neon_mull(cpu_V0, tmp, tmp2, size, u); break; default: /* 15 is RESERVED: caught earlier */ @@ -5317,16 +5317,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) /* VQDMULL */ gen_neon_addl_saturate(cpu_V0, cpu_V0, size); neon_store_reg64(cpu_V0, rd + pass); - } else if (op == 5 || (op >= 8 && op <= 11)) { + } else { /* Accumulate. */ neon_load_reg64(cpu_V1, rd + pass); switch (op) { - case 10: /* VMLSL */ - gen_neon_negl(cpu_V0, size); - /* Fall through */ - case 8: /* VABAL, VMLAL */ - gen_neon_addl(size); - break; case 9: case 11: /* VQDMLAL, VQDMLSL */ gen_neon_addl_saturate(cpu_V0, cpu_V0, size); if (op == 11) { @@ -5338,9 +5332,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) abort(); } neon_store_reg64(cpu_V0, rd + pass); - } else { - /* Write back the result. */ - neon_store_reg64(cpu_V0, rd + pass); } } } else { From 9546ca5998d3cbd98a81b2d46a2e92a11b0f78a4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:26 +0100 Subject: [PATCH 1289/2595] target/arm: Convert Neon 3-reg-diff saturating doubling multiplies Convert the Neon 3-reg-diff insns VQDMULL, VQDMLAL and VQDMLSL: these are all saturating doubling long multiplies with a possible accumulate step. These are the last insns in the group which use the pass-over-each elements loop, so we can delete that code. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 6 +++ target/arm/translate-neon.inc.c | 82 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 59 ++---------------------- 3 files changed, 92 insertions(+), 55 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 1da492df14..65ea30d3ed 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -454,10 +454,16 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VMLAL_S_3d 1111 001 0 1 . .. .... .... 1000 . 0 . 0 .... @3diff VMLAL_U_3d 1111 001 1 1 . .. .... .... 1000 . 0 . 0 .... @3diff + VQDMLAL_3d 1111 001 0 1 . .. .... .... 1001 . 0 . 0 .... @3diff + VMLSL_S_3d 1111 001 0 1 . .. .... .... 1010 . 0 . 0 .... @3diff VMLSL_U_3d 1111 001 1 1 . .. .... .... 1010 . 0 . 0 .... @3diff + VQDMLSL_3d 1111 001 0 1 . .. .... .... 1011 . 0 . 0 .... @3diff + VMULL_S_3d 1111 001 0 1 . .. .... .... 1100 . 0 . 0 .... @3diff VMULL_U_3d 1111 001 1 1 . .. .... .... 1100 . 0 . 0 .... @3diff + + VQDMULL_3d 1111 001 0 1 . .. .... .... 1101 . 0 . 0 .... @3diff ] } diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index c435f0685d..083e3af8c5 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2222,3 +2222,85 @@ DO_VMLAL(VMLAL_S,mull_s,add) DO_VMLAL(VMLAL_U,mull_u,add) DO_VMLAL(VMLSL_S,mull_s,sub) DO_VMLAL(VMLSL_U,mull_u,sub) + +static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) +{ + gen_helper_neon_mull_s16(rd, rn, rm); + gen_helper_neon_addl_saturate_s32(rd, cpu_env, rd, rd); +} + +static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) +{ + gen_mull_s32(rd, rn, rm); + gen_helper_neon_addl_saturate_s64(rd, cpu_env, rd, rd); +} + +static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + NULL, + gen_VQDMULL_16, + gen_VQDMULL_32, + NULL, + }; + + return do_long_3d(s, a, opfn[a->size], NULL); +} + +static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) +{ + gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); +} + +static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) +{ + gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); +} + +static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + NULL, + gen_VQDMULL_16, + gen_VQDMULL_32, + NULL, + }; + static NeonGenTwo64OpFn * const accfn[] = { + NULL, + gen_VQDMLAL_acc_16, + gen_VQDMLAL_acc_32, + NULL, + }; + + return do_long_3d(s, a, opfn[a->size], accfn[a->size]); +} + +static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) +{ + gen_helper_neon_negl_u32(rm, rm); + gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); +} + +static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) +{ + tcg_gen_neg_i64(rm, rm); + gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); +} + +static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + NULL, + gen_VQDMULL_16, + gen_VQDMULL_32, + NULL, + }; + static NeonGenTwo64OpFn * const accfn[] = { + NULL, + gen_VQDMLSL_acc_16, + gen_VQDMLSL_acc_32, + NULL, + }; + + return do_long_3d(s, a, opfn[a->size], accfn[a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index a2c47d19f2..88e91845c0 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5247,11 +5247,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) {0, 0, 0, 7}, /* VSUBHN: handled by decodetree */ {0, 0, 0, 7}, /* VABDL */ {0, 0, 0, 7}, /* VMLAL */ - {0, 0, 0, 9}, /* VQDMLAL */ + {0, 0, 0, 7}, /* VQDMLAL */ {0, 0, 0, 7}, /* VMLSL */ - {0, 0, 0, 9}, /* VQDMLSL */ + {0, 0, 0, 7}, /* VQDMLSL */ {0, 0, 0, 7}, /* Integer VMULL */ - {0, 0, 0, 9}, /* VQDMULL */ + {0, 0, 0, 7}, /* VQDMULL */ {0, 0, 0, 0xa}, /* Polynomial VMULL */ {0, 0, 0, 7}, /* Reserved: always UNDEF */ }; @@ -5282,58 +5282,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } return 0; } - - /* Avoid overlapping operands. Wide source operands are - always aligned so will never overlap with wide - destinations in problematic ways. */ - if (rd == rm) { - tmp = neon_load_reg(rm, 1); - neon_store_scratch(2, tmp); - } else if (rd == rn) { - tmp = neon_load_reg(rn, 1); - neon_store_scratch(2, tmp); - } - tmp3 = NULL; - for (pass = 0; pass < 2; pass++) { - if (pass == 1 && rd == rn) { - tmp = neon_load_scratch(2); - } else { - tmp = neon_load_reg(rn, pass); - } - if (pass == 1 && rd == rm) { - tmp2 = neon_load_scratch(2); - } else { - tmp2 = neon_load_reg(rm, pass); - } - switch (op) { - case 9: case 11: case 13: - /* VQDMLAL, VQDMLSL, VQDMULL */ - gen_neon_mull(cpu_V0, tmp, tmp2, size, u); - break; - default: /* 15 is RESERVED: caught earlier */ - abort(); - } - if (op == 13) { - /* VQDMULL */ - gen_neon_addl_saturate(cpu_V0, cpu_V0, size); - neon_store_reg64(cpu_V0, rd + pass); - } else { - /* Accumulate. */ - neon_load_reg64(cpu_V1, rd + pass); - switch (op) { - case 9: case 11: /* VQDMLAL, VQDMLSL */ - gen_neon_addl_saturate(cpu_V0, cpu_V0, size); - if (op == 11) { - gen_neon_negl(cpu_V0, size); - } - gen_neon_addl_saturate(cpu_V0, cpu_V1, size); - break; - default: - abort(); - } - neon_store_reg64(cpu_V0, rd + pass); - } - } + abort(); /* all others handled by decodetree */ } else { /* Two registers and a scalar. NB that for ops of this form * the ARM ARM labels bit 24 as Q, but it is in our variable From 18fb58d588898550919392277787979ee7d0d84e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:26 +0100 Subject: [PATCH 1290/2595] target/arm: Convert Neon 3-reg-diff polynomial VMULL Convert the Neon 3-reg-diff insn polynomial VMULL. This is the last insn in this group to be converted. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 2 ++ target/arm/translate-neon.inc.c | 43 +++++++++++++++++++++++ target/arm/translate.c | 60 ++------------------------------- 3 files changed, 48 insertions(+), 57 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 65ea30d3ed..ed49726abf 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -465,5 +465,7 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VMULL_U_3d 1111 001 1 1 . .. .... .... 1100 . 0 . 0 .... @3diff VQDMULL_3d 1111 001 0 1 . .. .... .... 1101 . 0 . 0 .... @3diff + + VMULL_P_3d 1111 001 0 1 . .. .... .... 1110 . 0 . 0 .... @3diff ] } diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 083e3af8c5..c2cc10913f 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2304,3 +2304,46 @@ static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a) return do_long_3d(s, a, opfn[a->size], accfn[a->size]); } + +static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a) +{ + gen_helper_gvec_3 *fn_gvec; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if (a->vd & 1) { + return false; + } + + switch (a->size) { + case 0: + fn_gvec = gen_helper_neon_pmull_h; + break; + case 2: + if (!dc_isar_feature(aa32_pmull, s)) { + return false; + } + fn_gvec = gen_helper_gvec_pmull_q; + break; + default: + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + tcg_gen_gvec_3_ool(neon_reg_offset(a->vd, 0), + neon_reg_offset(a->vn, 0), + neon_reg_offset(a->vm, 0), + 16, 16, 0, fn_gvec); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 88e91845c0..f459fad864 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5181,7 +5181,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) { int op; int q; - int rd, rn, rm, rd_ofs, rn_ofs, rm_ofs; + int rd, rn, rm, rd_ofs, rm_ofs; int size; int pass; int u; @@ -5215,7 +5215,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) size = (insn >> 20) & 3; vec_size = q ? 16 : 8; rd_ofs = neon_reg_offset(rd, 0); - rn_ofs = neon_reg_offset(rn, 0); rm_ofs = neon_reg_offset(rm, 0); if ((insn & (1 << 23)) == 0) { @@ -5228,61 +5227,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if (size != 3) { op = (insn >> 8) & 0xf; if ((insn & (1 << 6)) == 0) { - /* Three registers of different lengths. */ - /* undefreq: bit 0 : UNDEF if size == 0 - * bit 1 : UNDEF if size == 1 - * bit 2 : UNDEF if size == 2 - * bit 3 : UNDEF if U == 1 - * Note that [2:0] set implies 'always UNDEF' - */ - int undefreq; - /* prewiden, src1_wide, src2_wide, undefreq */ - static const int neon_3reg_wide[16][4] = { - {0, 0, 0, 7}, /* VADDL: handled by decodetree */ - {0, 0, 0, 7}, /* VADDW: handled by decodetree */ - {0, 0, 0, 7}, /* VSUBL: handled by decodetree */ - {0, 0, 0, 7}, /* VSUBW: handled by decodetree */ - {0, 0, 0, 7}, /* VADDHN: handled by decodetree */ - {0, 0, 0, 7}, /* VABAL */ - {0, 0, 0, 7}, /* VSUBHN: handled by decodetree */ - {0, 0, 0, 7}, /* VABDL */ - {0, 0, 0, 7}, /* VMLAL */ - {0, 0, 0, 7}, /* VQDMLAL */ - {0, 0, 0, 7}, /* VMLSL */ - {0, 0, 0, 7}, /* VQDMLSL */ - {0, 0, 0, 7}, /* Integer VMULL */ - {0, 0, 0, 7}, /* VQDMULL */ - {0, 0, 0, 0xa}, /* Polynomial VMULL */ - {0, 0, 0, 7}, /* Reserved: always UNDEF */ - }; - - undefreq = neon_3reg_wide[op][3]; - - if ((undefreq & (1 << size)) || - ((undefreq & 8) && u)) { - return 1; - } - if (rd & 1) { - return 1; - } - - /* Handle polynomial VMULL in a single pass. */ - if (op == 14) { - if (size == 0) { - /* VMULL.P8 */ - tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, 16, 16, - 0, gen_helper_neon_pmull_h); - } else { - /* VMULL.P64 */ - if (!dc_isar_feature(aa32_pmull, s)) { - return 1; - } - tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, 16, 16, - 0, gen_helper_gvec_pmull_q); - } - return 0; - } - abort(); /* all others handled by decodetree */ + /* Three registers of different lengths: handled by decodetree */ + return 1; } else { /* Two registers and a scalar. NB that for ops of this form * the ARM ARM labels bit 24 as Q, but it is in our variable From 448f0e5f3ecfbd089b934e5e3aa0ccd1f51a6174 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:26 +0100 Subject: [PATCH 1291/2595] target/arm: Add 'static' and 'const' annotations to VSHLL function arrays Mark the arrays of function pointers in trans_VSHLL_S_2sh() and trans_VSHLL_U_2sh() as both 'static' and 'const'. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/translate-neon.inc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index c2cc10913f..7c4888a80c 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1644,7 +1644,7 @@ static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a) { - NeonGenWidenFn *widenfn[] = { + static NeonGenWidenFn * const widenfn[] = { gen_helper_neon_widen_s8, gen_helper_neon_widen_s16, tcg_gen_ext_i32_i64, @@ -1654,7 +1654,7 @@ static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a) static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) { - NeonGenWidenFn *widenfn[] = { + static NeonGenWidenFn * const widenfn[] = { gen_helper_neon_widen_u8, gen_helper_neon_widen_u16, tcg_gen_extu_i32_i64, From a4f67e180def790ff0bbb33fc93bb6e80382f041 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:26 +0100 Subject: [PATCH 1292/2595] target/arm: Add missing TCG temp free in do_2shift_env_64() In commit 37bfce81b10450071 we accidentally introduced a leak of a TCG temporary in do_2shift_env_64(); free it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/translate-neon.inc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 7c4888a80c..f2c241a87e 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1329,6 +1329,7 @@ static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, neon_load_reg64(tmp, a->vm + pass); fn(tmp, cpu_env, tmp, constimm); neon_store_reg64(tmp, a->vd + pass); + tcg_temp_free_i64(tmp); } tcg_temp_free_i64(constimm); return true; From 96fc80f5f186decd1a649f6c04252faceb057ad2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:27 +0100 Subject: [PATCH 1293/2595] target/arm: Convert Neon 2-reg-scalar integer multiplies to decodetree Convert the VMLA, VMLS and VMUL insns in the Neon "2 registers and a scalar" group to decodetree. These are 32x32->32 operations where one of the inputs is the scalar, followed by a possible accumulate operation of the 32-bit result. The refactoring removes some of the oddities of the old decoder: * operands to the operation and accumulation were often reversed (taking advantage of the fact that most of these ops are commutative); the new code follows the pseudocode order * the Q bit in the insn was in a local variable 'u'; in the new code it is decoded into a->q Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 15 ++++ target/arm/translate-neon.inc.c | 133 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 77 ++---------------- 3 files changed, 154 insertions(+), 71 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index ed49726abf..983747b785 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -467,5 +467,20 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VQDMULL_3d 1111 001 0 1 . .. .... .... 1101 . 0 . 0 .... @3diff VMULL_P_3d 1111 001 0 1 . .. .... .... 1110 . 0 . 0 .... @3diff + + ################################################################## + # 2-regs-plus-scalar grouping: + # 1111 001 Q 1 D sz!=11 Vn:4 Vd:4 opc:4 N 1 M 0 Vm:4 + ################################################################## + &2scalar vm vn vd size q + + @2scalar .... ... q:1 . . size:2 .... .... .... . . . . .... \ + &2scalar vm=%vm_dp vn=%vn_dp vd=%vd_dp + + VMLA_2sc 1111 001 . 1 . .. .... .... 0000 . 1 . 0 .... @2scalar + + VMLS_2sc 1111 001 . 1 . .. .... .... 0100 . 1 . 0 .... @2scalar + + VMUL_2sc 1111 001 . 1 . .. .... .... 1000 . 1 . 0 .... @2scalar ] } diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index f2c241a87e..478a0dd5c1 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2348,3 +2348,136 @@ static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a) 16, 16, 0, fn_gvec); return true; } + +static void gen_neon_dup_low16(TCGv_i32 var) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_ext16u_i32(var, var); + tcg_gen_shli_i32(tmp, var, 16); + tcg_gen_or_i32(var, var, tmp); + tcg_temp_free_i32(tmp); +} + +static void gen_neon_dup_high16(TCGv_i32 var) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_andi_i32(var, var, 0xffff0000); + tcg_gen_shri_i32(tmp, var, 16); + tcg_gen_or_i32(var, var, tmp); + tcg_temp_free_i32(tmp); +} + +static inline TCGv_i32 neon_get_scalar(int size, int reg) +{ + TCGv_i32 tmp; + if (size == 1) { + tmp = neon_load_reg(reg & 7, reg >> 4); + if (reg & 8) { + gen_neon_dup_high16(tmp); + } else { + gen_neon_dup_low16(tmp); + } + } else { + tmp = neon_load_reg(reg & 15, reg >> 4); + } + return tmp; +} + +static bool do_2scalar(DisasContext *s, arg_2scalar *a, + NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn) +{ + /* + * Two registers and a scalar: perform an operation between + * the input elements and the scalar, and then possibly + * perform an accumulation operation of that result into the + * destination. + */ + TCGv_i32 scalar; + int pass; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if (!opfn) { + /* Bad size (including size == 3, which is a different insn group) */ + return false; + } + + if (a->q && ((a->vd | a->vn) & 1)) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + scalar = neon_get_scalar(a->size, a->vm); + + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + TCGv_i32 tmp = neon_load_reg(a->vn, pass); + opfn(tmp, tmp, scalar); + if (accfn) { + TCGv_i32 rd = neon_load_reg(a->vd, pass); + accfn(tmp, rd, tmp); + tcg_temp_free_i32(rd); + } + neon_store_reg(a->vd, pass, tmp); + } + tcg_temp_free_i32(scalar); + return true; +} + +static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpFn * const opfn[] = { + NULL, + gen_helper_neon_mul_u16, + tcg_gen_mul_i32, + NULL, + }; + + return do_2scalar(s, a, opfn[a->size], NULL); +} + +static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpFn * const opfn[] = { + NULL, + gen_helper_neon_mul_u16, + tcg_gen_mul_i32, + NULL, + }; + static NeonGenTwoOpFn * const accfn[] = { + NULL, + gen_helper_neon_add_u16, + tcg_gen_add_i32, + NULL, + }; + + return do_2scalar(s, a, opfn[a->size], accfn[a->size]); +} + +static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpFn * const opfn[] = { + NULL, + gen_helper_neon_mul_u16, + tcg_gen_mul_i32, + NULL, + }; + static NeonGenTwoOpFn * const accfn[] = { + NULL, + gen_helper_neon_sub_u16, + tcg_gen_sub_i32, + NULL, + }; + + return do_2scalar(s, a, opfn[a->size], accfn[a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index f459fad864..e9cc237ef8 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2624,24 +2624,6 @@ static int disas_dsp_insn(DisasContext *s, uint32_t insn) #define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7) #define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5) -static void gen_neon_dup_low16(TCGv_i32 var) -{ - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_ext16u_i32(var, var); - tcg_gen_shli_i32(tmp, var, 16); - tcg_gen_or_i32(var, var, tmp); - tcg_temp_free_i32(tmp); -} - -static void gen_neon_dup_high16(TCGv_i32 var) -{ - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(var, var, 0xffff0000); - tcg_gen_shri_i32(tmp, var, 16); - tcg_gen_or_i32(var, var, tmp); - tcg_temp_free_i32(tmp); -} - static inline bool use_goto_tb(DisasContext *s, target_ulong dest) { #ifndef CONFIG_USER_ONLY @@ -2991,26 +2973,6 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc) #define CPU_V001 cpu_V0, cpu_V0, cpu_V1 -static inline void gen_neon_add(int size, TCGv_i32 t0, TCGv_i32 t1) -{ - switch (size) { - case 0: gen_helper_neon_add_u8(t0, t0, t1); break; - case 1: gen_helper_neon_add_u16(t0, t0, t1); break; - case 2: tcg_gen_add_i32(t0, t0, t1); break; - default: abort(); - } -} - -static inline void gen_neon_rsb(int size, TCGv_i32 t0, TCGv_i32 t1) -{ - switch (size) { - case 0: gen_helper_neon_sub_u8(t0, t1, t0); break; - case 1: gen_helper_neon_sub_u16(t0, t1, t0); break; - case 2: tcg_gen_sub_i32(t0, t1, t0); break; - default: return; - } -} - static TCGv_i32 neon_load_scratch(int scratch) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -3024,22 +2986,6 @@ static void neon_store_scratch(int scratch, TCGv_i32 var) tcg_temp_free_i32(var); } -static inline TCGv_i32 neon_get_scalar(int size, int reg) -{ - TCGv_i32 tmp; - if (size == 1) { - tmp = neon_load_reg(reg & 7, reg >> 4); - if (reg & 8) { - gen_neon_dup_high16(tmp); - } else { - gen_neon_dup_low16(tmp); - } - } else { - tmp = neon_load_reg(reg & 15, reg >> 4); - } - return tmp; -} - static int gen_neon_unzip(int rd, int rm, int size, int q) { TCGv_ptr pd, pm; @@ -5238,6 +5184,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 1; } switch (op) { + case 0: /* Integer VMLA scalar */ + case 4: /* Integer VMLS scalar */ + case 8: /* Integer VMUL scalar */ + return 1; /* handled by decodetree */ + case 1: /* Float VMLA scalar */ case 5: /* Floating point VMLS scalar */ case 9: /* Floating point VMUL scalar */ @@ -5245,9 +5196,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 1; } /* fall through */ - case 0: /* Integer VMLA scalar */ - case 4: /* Integer VMLS scalar */ - case 8: /* Integer VMUL scalar */ case 12: /* VQDMULH scalar */ case 13: /* VQRDMULH scalar */ if (u && ((rd | rn) & 1)) { @@ -5270,26 +5218,16 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } else { gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); } - } else if (op & 1) { + } else { TCGv_ptr fpstatus = get_fpstatus_ptr(1); gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus); tcg_temp_free_ptr(fpstatus); - } else { - switch (size) { - case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; - case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; - case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; - default: abort(); - } } tcg_temp_free_i32(tmp2); if (op < 8) { /* Accumulate. */ tmp2 = neon_load_reg(rd, pass); switch (op) { - case 0: - gen_neon_add(size, tmp, tmp2); - break; case 1: { TCGv_ptr fpstatus = get_fpstatus_ptr(1); @@ -5297,9 +5235,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(fpstatus); break; } - case 4: - gen_neon_rsb(size, tmp, tmp2); - break; case 5: { TCGv_ptr fpstatus = get_fpstatus_ptr(1); From 85ac9aef9a5418de3168df569e21258e853840a2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:27 +0100 Subject: [PATCH 1294/2595] target/arm: Convert Neon 2-reg-scalar float multiplies to decodetree Convert the float versions of VMLA, VMLS and VMUL in the Neon 2-reg-scalar group to decodetree. Signed-off-by: Peter Maydell --- As noted in the comment on the WRAP_FP_FN macro, we could have had a do_2scalar_fp() function, but for 3 insns it seemed simpler to just do the wrapping to get hold of the fpstatus ptr. (These are the only fp insns in the group.) Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 3 ++ target/arm/translate-neon.inc.c | 65 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 37 ++----------------- 3 files changed, 71 insertions(+), 34 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 983747b785..cc2ee9641d 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -478,9 +478,12 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm &2scalar vm=%vm_dp vn=%vn_dp vd=%vd_dp VMLA_2sc 1111 001 . 1 . .. .... .... 0000 . 1 . 0 .... @2scalar + VMLA_F_2sc 1111 001 . 1 . .. .... .... 0001 . 1 . 0 .... @2scalar VMLS_2sc 1111 001 . 1 . .. .... .... 0100 . 1 . 0 .... @2scalar + VMLS_F_2sc 1111 001 . 1 . .. .... .... 0101 . 1 . 0 .... @2scalar VMUL_2sc 1111 001 . 1 . .. .... .... 1000 . 1 . 0 .... @2scalar + VMUL_F_2sc 1111 001 . 1 . .. .... .... 1001 . 1 . 0 .... @2scalar ] } diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 478a0dd5c1..a5c7d60bda 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2481,3 +2481,68 @@ static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a) return do_2scalar(s, a, opfn[a->size], accfn[a->size]); } + +/* + * Rather than have a float-specific version of do_2scalar just for + * three insns, we wrap a NeonGenTwoSingleOpFn to turn it into + * a NeonGenTwoOpFn. + */ +#define WRAP_FP_FN(WRAPNAME, FUNC) \ + static void WRAPNAME(TCGv_i32 rd, TCGv_i32 rn, TCGv_i32 rm) \ + { \ + TCGv_ptr fpstatus = get_fpstatus_ptr(1); \ + FUNC(rd, rn, rm, fpstatus); \ + tcg_temp_free_ptr(fpstatus); \ + } + +WRAP_FP_FN(gen_VMUL_F_mul, gen_helper_vfp_muls) +WRAP_FP_FN(gen_VMUL_F_add, gen_helper_vfp_adds) +WRAP_FP_FN(gen_VMUL_F_sub, gen_helper_vfp_subs) + +static bool trans_VMUL_F_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpFn * const opfn[] = { + NULL, + NULL, /* TODO: fp16 support */ + gen_VMUL_F_mul, + NULL, + }; + + return do_2scalar(s, a, opfn[a->size], NULL); +} + +static bool trans_VMLA_F_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpFn * const opfn[] = { + NULL, + NULL, /* TODO: fp16 support */ + gen_VMUL_F_mul, + NULL, + }; + static NeonGenTwoOpFn * const accfn[] = { + NULL, + NULL, /* TODO: fp16 support */ + gen_VMUL_F_add, + NULL, + }; + + return do_2scalar(s, a, opfn[a->size], accfn[a->size]); +} + +static bool trans_VMLS_F_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpFn * const opfn[] = { + NULL, + NULL, /* TODO: fp16 support */ + gen_VMUL_F_mul, + NULL, + }; + static NeonGenTwoOpFn * const accfn[] = { + NULL, + NULL, /* TODO: fp16 support */ + gen_VMUL_F_sub, + NULL, + }; + + return do_2scalar(s, a, opfn[a->size], accfn[a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index e9cc237ef8..e4a6a38c78 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5187,15 +5187,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case 0: /* Integer VMLA scalar */ case 4: /* Integer VMLS scalar */ case 8: /* Integer VMUL scalar */ - return 1; /* handled by decodetree */ - case 1: /* Float VMLA scalar */ case 5: /* Floating point VMLS scalar */ case 9: /* Floating point VMUL scalar */ - if (size == 1) { - return 1; - } - /* fall through */ + return 1; /* handled by decodetree */ + case 12: /* VQDMULH scalar */ case 13: /* VQRDMULH scalar */ if (u && ((rd | rn) & 1)) { @@ -5212,41 +5208,14 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } else { gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); } - } else if (op == 13) { + } else { if (size == 1) { gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); } else { gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); } - } else { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus); - tcg_temp_free_ptr(fpstatus); } tcg_temp_free_i32(tmp2); - if (op < 8) { - /* Accumulate. */ - tmp2 = neon_load_reg(rd, pass); - switch (op) { - case 1: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case 5: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - default: - abort(); - } - tcg_temp_free_i32(tmp2); - } neon_store_reg(rd, pass, tmp); } break; From b2fc7be972b94872f6a6dd32d9bda1b88ddbcaad Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:27 +0100 Subject: [PATCH 1295/2595] target/arm: Convert Neon 2-reg-scalar VQDMULH, VQRDMULH to decodetree Convert the VQDMULH and VQRDMULH insns in the 2-reg-scalar group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 3 +++ target/arm/translate-neon.inc.c | 29 +++++++++++++++++++++++ target/arm/translate.c | 42 ++------------------------------- 3 files changed, 34 insertions(+), 40 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index cc2ee9641d..105cf2b2db 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -485,5 +485,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VMUL_2sc 1111 001 . 1 . .. .... .... 1000 . 1 . 0 .... @2scalar VMUL_F_2sc 1111 001 . 1 . .. .... .... 1001 . 1 . 0 .... @2scalar + + VQDMULH_2sc 1111 001 . 1 . .. .... .... 1100 . 1 . 0 .... @2scalar + VQRDMULH_2sc 1111 001 . 1 . .. .... .... 1101 . 1 . 0 .... @2scalar ] } diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index a5c7d60bda..6301016d5c 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2546,3 +2546,32 @@ static bool trans_VMLS_F_2sc(DisasContext *s, arg_2scalar *a) return do_2scalar(s, a, opfn[a->size], accfn[a->size]); } + +WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16) +WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32) +WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16) +WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32) + +static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpFn * const opfn[] = { + NULL, + gen_VQDMULH_16, + gen_VQDMULH_32, + NULL, + }; + + return do_2scalar(s, a, opfn[a->size], NULL); +} + +static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpFn * const opfn[] = { + NULL, + gen_VQRDMULH_16, + gen_VQRDMULH_32, + NULL, + }; + + return do_2scalar(s, a, opfn[a->size], NULL); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index e4a6a38c78..5d0e00f92e 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2973,19 +2973,6 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc) #define CPU_V001 cpu_V0, cpu_V0, cpu_V1 -static TCGv_i32 neon_load_scratch(int scratch) -{ - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch])); - return tmp; -} - -static void neon_store_scratch(int scratch, TCGv_i32 var) -{ - tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch])); - tcg_temp_free_i32(var); -} - static int gen_neon_unzip(int rd, int rm, int size, int q) { TCGv_ptr pd, pm; @@ -5190,35 +5177,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case 1: /* Float VMLA scalar */ case 5: /* Floating point VMLS scalar */ case 9: /* Floating point VMUL scalar */ - return 1; /* handled by decodetree */ - case 12: /* VQDMULH scalar */ case 13: /* VQRDMULH scalar */ - if (u && ((rd | rn) & 1)) { - return 1; - } - tmp = neon_get_scalar(size, rm); - neon_store_scratch(0, tmp); - for (pass = 0; pass < (u ? 4 : 2); pass++) { - tmp = neon_load_scratch(0); - tmp2 = neon_load_reg(rn, pass); - if (op == 12) { - if (size == 1) { - gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2); - } else { - gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); - } - } else { - if (size == 1) { - gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); - } else { - gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); - } - } - tcg_temp_free_i32(tmp2); - neon_store_reg(rd, pass, tmp); - } - break; + return 1; /* handled by decodetree */ + case 3: /* VQDMLAL scalar */ case 7: /* VQDMLSL scalar */ case 11: /* VQDMULL scalar */ From aa318f5b9b4ab3b6744b5305dd8ae9b96676f20e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:27 +0100 Subject: [PATCH 1296/2595] target/arm: Convert Neon 2-reg-scalar VQRDMLAH, VQRDMLSH to decodetree Convert the VQRDMLAH and VQRDMLSH insns in the 2-reg-scalar group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 3 ++ target/arm/translate-neon.inc.c | 74 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 38 +---------------- 3 files changed, 79 insertions(+), 36 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 105cf2b2db..7b069abe62 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -488,5 +488,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VQDMULH_2sc 1111 001 . 1 . .. .... .... 1100 . 1 . 0 .... @2scalar VQRDMULH_2sc 1111 001 . 1 . .. .... .... 1101 . 1 . 0 .... @2scalar + + VQRDMLAH_2sc 1111 001 . 1 . .. .... .... 1110 . 1 . 0 .... @2scalar + VQRDMLSH_2sc 1111 001 . 1 . .. .... .... 1111 . 1 . 0 .... @2scalar ] } diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 6301016d5c..59a075f154 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2575,3 +2575,77 @@ static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a) return do_2scalar(s, a, opfn[a->size], NULL); } + +static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a, + NeonGenThreeOpEnvFn *opfn) +{ + /* + * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn + * performs a kind of fused op-then-accumulate using a helper + * function that takes all of rd, rn and the scalar at once. + */ + TCGv_i32 scalar; + int pass; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + if (!dc_isar_feature(aa32_rdm, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if (!opfn) { + /* Bad size (including size == 3, which is a different insn group) */ + return false; + } + + if (a->q && ((a->vd | a->vn) & 1)) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + scalar = neon_get_scalar(a->size, a->vm); + + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + TCGv_i32 rn = neon_load_reg(a->vn, pass); + TCGv_i32 rd = neon_load_reg(a->vd, pass); + opfn(rd, cpu_env, rn, scalar, rd); + tcg_temp_free_i32(rn); + neon_store_reg(a->vd, pass, rd); + } + tcg_temp_free_i32(scalar); + + return true; +} + +static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenThreeOpEnvFn *opfn[] = { + NULL, + gen_helper_neon_qrdmlah_s16, + gen_helper_neon_qrdmlah_s32, + NULL, + }; + return do_vqrdmlah_2sc(s, a, opfn[a->size]); +} + +static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenThreeOpEnvFn *opfn[] = { + NULL, + gen_helper_neon_qrdmlsh_s16, + gen_helper_neon_qrdmlsh_s32, + NULL, + }; + return do_vqrdmlah_2sc(s, a, opfn[a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 5d0e00f92e..f0db029f66 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5179,6 +5179,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case 9: /* Floating point VMUL scalar */ case 12: /* VQDMULH scalar */ case 13: /* VQRDMULH scalar */ + case 14: /* VQRDMLAH scalar */ + case 15: /* VQRDMLSH scalar */ return 1; /* handled by decodetree */ case 3: /* VQDMLAL scalar */ @@ -5238,42 +5240,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) neon_store_reg64(cpu_V0, rd + pass); } break; - case 14: /* VQRDMLAH scalar */ - case 15: /* VQRDMLSH scalar */ - { - NeonGenThreeOpEnvFn *fn; - - if (!dc_isar_feature(aa32_rdm, s)) { - return 1; - } - if (u && ((rd | rn) & 1)) { - return 1; - } - if (op == 14) { - if (size == 1) { - fn = gen_helper_neon_qrdmlah_s16; - } else { - fn = gen_helper_neon_qrdmlah_s32; - } - } else { - if (size == 1) { - fn = gen_helper_neon_qrdmlsh_s16; - } else { - fn = gen_helper_neon_qrdmlsh_s32; - } - } - - tmp2 = neon_get_scalar(size, rm); - for (pass = 0; pass < (u ? 4 : 2); pass++) { - tmp = neon_load_reg(rn, pass); - tmp3 = neon_load_reg(rd, pass); - fn(tmp, cpu_env, tmp, tmp2, tmp3); - tcg_temp_free_i32(tmp3); - neon_store_reg(rd, pass, tmp); - } - tcg_temp_free_i32(tmp2); - } - break; default: g_assert_not_reached(); } From 77e576a9281825fc170f3b3af83f47e110549b5c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:28 +0100 Subject: [PATCH 1297/2595] target/arm: Convert Neon 2-reg-scalar long multiplies to decodetree Convert the Neon 2-reg-scalar long multiplies to decodetree. These are the last instructions in the group. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 18 ++++ target/arm/translate-neon.inc.c | 163 ++++++++++++++++++++++++++++ target/arm/translate.c | 182 ++------------------------------ 3 files changed, 187 insertions(+), 176 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 7b069abe62..9ff182f56d 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -476,16 +476,34 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm @2scalar .... ... q:1 . . size:2 .... .... .... . . . . .... \ &2scalar vm=%vm_dp vn=%vn_dp vd=%vd_dp + # For the 'long' ops the Q bit is part of insn decode + @2scalar_q0 .... ... . . . size:2 .... .... .... . . . . .... \ + &2scalar vm=%vm_dp vn=%vn_dp vd=%vd_dp q=0 VMLA_2sc 1111 001 . 1 . .. .... .... 0000 . 1 . 0 .... @2scalar VMLA_F_2sc 1111 001 . 1 . .. .... .... 0001 . 1 . 0 .... @2scalar + VMLAL_S_2sc 1111 001 0 1 . .. .... .... 0010 . 1 . 0 .... @2scalar_q0 + VMLAL_U_2sc 1111 001 1 1 . .. .... .... 0010 . 1 . 0 .... @2scalar_q0 + + VQDMLAL_2sc 1111 001 0 1 . .. .... .... 0011 . 1 . 0 .... @2scalar_q0 + VMLS_2sc 1111 001 . 1 . .. .... .... 0100 . 1 . 0 .... @2scalar VMLS_F_2sc 1111 001 . 1 . .. .... .... 0101 . 1 . 0 .... @2scalar + VMLSL_S_2sc 1111 001 0 1 . .. .... .... 0110 . 1 . 0 .... @2scalar_q0 + VMLSL_U_2sc 1111 001 1 1 . .. .... .... 0110 . 1 . 0 .... @2scalar_q0 + + VQDMLSL_2sc 1111 001 0 1 . .. .... .... 0111 . 1 . 0 .... @2scalar_q0 + VMUL_2sc 1111 001 . 1 . .. .... .... 1000 . 1 . 0 .... @2scalar VMUL_F_2sc 1111 001 . 1 . .. .... .... 1001 . 1 . 0 .... @2scalar + VMULL_S_2sc 1111 001 0 1 . .. .... .... 1010 . 1 . 0 .... @2scalar_q0 + VMULL_U_2sc 1111 001 1 1 . .. .... .... 1010 . 1 . 0 .... @2scalar_q0 + + VQDMULL_2sc 1111 001 0 1 . .. .... .... 1011 . 1 . 0 .... @2scalar_q0 + VQDMULH_2sc 1111 001 . 1 . .. .... .... 1100 . 1 . 0 .... @2scalar VQRDMULH_2sc 1111 001 . 1 . .. .... .... 1101 . 1 . 0 .... @2scalar diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 59a075f154..48a0dee150 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2649,3 +2649,166 @@ static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a) }; return do_vqrdmlah_2sc(s, a, opfn[a->size]); } + +static bool do_2scalar_long(DisasContext *s, arg_2scalar *a, + NeonGenTwoOpWidenFn *opfn, + NeonGenTwo64OpFn *accfn) +{ + /* + * Two registers and a scalar, long operations: perform an + * operation on the input elements and the scalar which produces + * a double-width result, and then possibly perform an accumulation + * operation of that result into the destination. + */ + TCGv_i32 scalar, rn; + TCGv_i64 rn0_64, rn1_64; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if (!opfn) { + /* Bad size (including size == 3, which is a different insn group) */ + return false; + } + + if (a->vd & 1) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + scalar = neon_get_scalar(a->size, a->vm); + + /* Load all inputs before writing any outputs, in case of overlap */ + rn = neon_load_reg(a->vn, 0); + rn0_64 = tcg_temp_new_i64(); + opfn(rn0_64, rn, scalar); + tcg_temp_free_i32(rn); + + rn = neon_load_reg(a->vn, 1); + rn1_64 = tcg_temp_new_i64(); + opfn(rn1_64, rn, scalar); + tcg_temp_free_i32(rn); + tcg_temp_free_i32(scalar); + + if (accfn) { + TCGv_i64 t64 = tcg_temp_new_i64(); + neon_load_reg64(t64, a->vd); + accfn(t64, t64, rn0_64); + neon_store_reg64(t64, a->vd); + neon_load_reg64(t64, a->vd + 1); + accfn(t64, t64, rn1_64); + neon_store_reg64(t64, a->vd + 1); + tcg_temp_free_i64(t64); + } else { + neon_store_reg64(rn0_64, a->vd); + neon_store_reg64(rn1_64, a->vd + 1); + } + tcg_temp_free_i64(rn0_64); + tcg_temp_free_i64(rn1_64); + return true; +} + +static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + NULL, + gen_helper_neon_mull_s16, + gen_mull_s32, + NULL, + }; + + return do_2scalar_long(s, a, opfn[a->size], NULL); +} + +static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + NULL, + gen_helper_neon_mull_u16, + gen_mull_u32, + NULL, + }; + + return do_2scalar_long(s, a, opfn[a->size], NULL); +} + +#define DO_VMLAL_2SC(INSN, MULL, ACC) \ + static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a) \ + { \ + static NeonGenTwoOpWidenFn * const opfn[] = { \ + NULL, \ + gen_helper_neon_##MULL##16, \ + gen_##MULL##32, \ + NULL, \ + }; \ + static NeonGenTwo64OpFn * const accfn[] = { \ + NULL, \ + gen_helper_neon_##ACC##l_u32, \ + tcg_gen_##ACC##_i64, \ + NULL, \ + }; \ + return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); \ + } + +DO_VMLAL_2SC(VMLAL_S, mull_s, add) +DO_VMLAL_2SC(VMLAL_U, mull_u, add) +DO_VMLAL_2SC(VMLSL_S, mull_s, sub) +DO_VMLAL_2SC(VMLSL_U, mull_u, sub) + +static bool trans_VQDMULL_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + NULL, + gen_VQDMULL_16, + gen_VQDMULL_32, + NULL, + }; + + return do_2scalar_long(s, a, opfn[a->size], NULL); +} + +static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + NULL, + gen_VQDMULL_16, + gen_VQDMULL_32, + NULL, + }; + static NeonGenTwo64OpFn * const accfn[] = { + NULL, + gen_VQDMLAL_acc_16, + gen_VQDMLAL_acc_32, + NULL, + }; + + return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); +} + +static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + NULL, + gen_VQDMULL_16, + gen_VQDMULL_32, + NULL, + }; + static NeonGenTwo64OpFn * const accfn[] = { + NULL, + gen_VQDMLSL_acc_16, + gen_VQDMLSL_acc_32, + NULL, + }; + + return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index f0db029f66..4d39bbf035 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -377,43 +377,6 @@ static void gen_revsh(TCGv_i32 dest, TCGv_i32 var) tcg_gen_ext16s_i32(dest, var); } -/* 32x32->64 multiply. Marks inputs as dead. */ -static TCGv_i64 gen_mulu_i64_i32(TCGv_i32 a, TCGv_i32 b) -{ - TCGv_i32 lo = tcg_temp_new_i32(); - TCGv_i32 hi = tcg_temp_new_i32(); - TCGv_i64 ret; - - tcg_gen_mulu2_i32(lo, hi, a, b); - tcg_temp_free_i32(a); - tcg_temp_free_i32(b); - - ret = tcg_temp_new_i64(); - tcg_gen_concat_i32_i64(ret, lo, hi); - tcg_temp_free_i32(lo); - tcg_temp_free_i32(hi); - - return ret; -} - -static TCGv_i64 gen_muls_i64_i32(TCGv_i32 a, TCGv_i32 b) -{ - TCGv_i32 lo = tcg_temp_new_i32(); - TCGv_i32 hi = tcg_temp_new_i32(); - TCGv_i64 ret; - - tcg_gen_muls2_i32(lo, hi, a, b); - tcg_temp_free_i32(a); - tcg_temp_free_i32(b); - - ret = tcg_temp_new_i64(); - tcg_gen_concat_i32_i64(ret, lo, hi); - tcg_temp_free_i32(lo); - tcg_temp_free_i32(hi); - - return ret; -} - /* Swap low and high halfwords. */ static void gen_swap_half(TCGv_i32 var) { @@ -3164,58 +3127,6 @@ static inline void gen_neon_addl(int size) } } -static inline void gen_neon_negl(TCGv_i64 var, int size) -{ - switch (size) { - case 0: gen_helper_neon_negl_u16(var, var); break; - case 1: gen_helper_neon_negl_u32(var, var); break; - case 2: - tcg_gen_neg_i64(var, var); - break; - default: abort(); - } -} - -static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size) -{ - switch (size) { - case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break; - case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break; - default: abort(); - } -} - -static inline void gen_neon_mull(TCGv_i64 dest, TCGv_i32 a, TCGv_i32 b, - int size, int u) -{ - TCGv_i64 tmp; - - switch ((size << 1) | u) { - case 0: gen_helper_neon_mull_s8(dest, a, b); break; - case 1: gen_helper_neon_mull_u8(dest, a, b); break; - case 2: gen_helper_neon_mull_s16(dest, a, b); break; - case 3: gen_helper_neon_mull_u16(dest, a, b); break; - case 4: - tmp = gen_muls_i64_i32(a, b); - tcg_gen_mov_i64(dest, tmp); - tcg_temp_free_i64(tmp); - break; - case 5: - tmp = gen_mulu_i64_i32(a, b); - tcg_gen_mov_i64(dest, tmp); - tcg_temp_free_i64(tmp); - break; - default: abort(); - } - - /* gen_helper_neon_mull_[su]{8|16} do not free their parameters. - Don't forget to clean them now. */ - if (size < 2) { - tcg_temp_free_i32(a); - tcg_temp_free_i32(b); - } -} - static void gen_neon_narrow_op(int op, int u, int size, TCGv_i32 dest, TCGv_i64 src) { @@ -5120,7 +5031,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int u; int vec_size; uint32_t imm; - TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5; + TCGv_i32 tmp, tmp2, tmp3, tmp5; TCGv_ptr ptr1; TCGv_i64 tmp64; @@ -5158,92 +5069,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 1; } else { /* (insn & 0x00800010 == 0x00800000) */ if (size != 3) { - op = (insn >> 8) & 0xf; - if ((insn & (1 << 6)) == 0) { - /* Three registers of different lengths: handled by decodetree */ - return 1; - } else { - /* Two registers and a scalar. NB that for ops of this form - * the ARM ARM labels bit 24 as Q, but it is in our variable - * 'u', not 'q'. - */ - if (size == 0) { - return 1; - } - switch (op) { - case 0: /* Integer VMLA scalar */ - case 4: /* Integer VMLS scalar */ - case 8: /* Integer VMUL scalar */ - case 1: /* Float VMLA scalar */ - case 5: /* Floating point VMLS scalar */ - case 9: /* Floating point VMUL scalar */ - case 12: /* VQDMULH scalar */ - case 13: /* VQRDMULH scalar */ - case 14: /* VQRDMLAH scalar */ - case 15: /* VQRDMLSH scalar */ - return 1; /* handled by decodetree */ - - case 3: /* VQDMLAL scalar */ - case 7: /* VQDMLSL scalar */ - case 11: /* VQDMULL scalar */ - if (u == 1) { - return 1; - } - /* fall through */ - case 2: /* VMLAL sclar */ - case 6: /* VMLSL scalar */ - case 10: /* VMULL scalar */ - if (rd & 1) { - return 1; - } - tmp2 = neon_get_scalar(size, rm); - /* We need a copy of tmp2 because gen_neon_mull - * deletes it during pass 0. */ - tmp4 = tcg_temp_new_i32(); - tcg_gen_mov_i32(tmp4, tmp2); - tmp3 = neon_load_reg(rn, 1); - - for (pass = 0; pass < 2; pass++) { - if (pass == 0) { - tmp = neon_load_reg(rn, 0); - } else { - tmp = tmp3; - tmp2 = tmp4; - } - gen_neon_mull(cpu_V0, tmp, tmp2, size, u); - if (op != 11) { - neon_load_reg64(cpu_V1, rd + pass); - } - switch (op) { - case 6: - gen_neon_negl(cpu_V0, size); - /* Fall through */ - case 2: - gen_neon_addl(size); - break; - case 3: case 7: - gen_neon_addl_saturate(cpu_V0, cpu_V0, size); - if (op == 7) { - gen_neon_negl(cpu_V0, size); - } - gen_neon_addl_saturate(cpu_V0, cpu_V1, size); - break; - case 10: - /* no-op */ - break; - case 11: - gen_neon_addl_saturate(cpu_V0, cpu_V0, size); - break; - default: - abort(); - } - neon_store_reg64(cpu_V0, rd + pass); - } - break; - default: - g_assert_not_reached(); - } - } + /* + * Three registers of different lengths, or two registers and + * a scalar: handled by decodetree + */ + return 1; } else { /* size == 3 */ if (!u) { /* Extract. */ From 0aad761fb0aed40c99039eacac470cbd03d07019 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:28 +0100 Subject: [PATCH 1298/2595] target/arm: Convert Neon VEXT to decodetree Convert the Neon VEXT insn to decodetree. Rather than keeping the old implementation which used fixed temporaries cpu_V0 and cpu_V1 and did the extraction with by-hand shift and logic ops, we use the TCG extract2 insn. We don't need to special case 0 or 8 immediates any more as the optimizer is smart enough to throw away the dead code. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 8 +++- target/arm/translate-neon.inc.c | 76 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 58 +------------------------ 3 files changed, 85 insertions(+), 57 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 9ff182f56d..26d6022016 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -413,7 +413,13 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm # return false for size==3. ###################################################################### { - # 0b11 subgroup will go here + [ + ################################################################## + # Miscellaneous size=0b11 insns + ################################################################## + VEXT 1111 001 0 1 . 11 .... .... imm:4 . q:1 . 0 .... \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp + ] # Subgroup for size != 0b11 [ diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 48a0dee150..84bc2b239c 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2812,3 +2812,79 @@ static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a) return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); } + +static bool trans_VEXT(DisasContext *s, arg_VEXT *a) +{ + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if ((a->vn | a->vm | a->vd) & a->q) { + return false; + } + + if (a->imm > 7 && !a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + if (!a->q) { + /* Extract 64 bits from */ + TCGv_i64 left, right, dest; + + left = tcg_temp_new_i64(); + right = tcg_temp_new_i64(); + dest = tcg_temp_new_i64(); + + neon_load_reg64(right, a->vn); + neon_load_reg64(left, a->vm); + tcg_gen_extract2_i64(dest, right, left, a->imm * 8); + neon_store_reg64(dest, a->vd); + + tcg_temp_free_i64(left); + tcg_temp_free_i64(right); + tcg_temp_free_i64(dest); + } else { + /* Extract 128 bits from */ + TCGv_i64 left, middle, right, destleft, destright; + + left = tcg_temp_new_i64(); + middle = tcg_temp_new_i64(); + right = tcg_temp_new_i64(); + destleft = tcg_temp_new_i64(); + destright = tcg_temp_new_i64(); + + if (a->imm < 8) { + neon_load_reg64(right, a->vn); + neon_load_reg64(middle, a->vn + 1); + tcg_gen_extract2_i64(destright, right, middle, a->imm * 8); + neon_load_reg64(left, a->vm); + tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8); + } else { + neon_load_reg64(right, a->vn + 1); + neon_load_reg64(middle, a->vm); + tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8); + neon_load_reg64(left, a->vm + 1); + tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8); + } + + neon_store_reg64(destright, a->vd); + neon_store_reg64(destleft, a->vd + 1); + + tcg_temp_free_i64(destright); + tcg_temp_free_i64(destleft); + tcg_temp_free_i64(right); + tcg_temp_free_i64(middle); + tcg_temp_free_i64(left); + } + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 4d39bbf035..a0822dba5e 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5030,10 +5030,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int pass; int u; int vec_size; - uint32_t imm; TCGv_i32 tmp, tmp2, tmp3, tmp5; TCGv_ptr ptr1; - TCGv_i64 tmp64; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { return 1; @@ -5076,60 +5074,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) return 1; } else { /* size == 3 */ if (!u) { - /* Extract. */ - imm = (insn >> 8) & 0xf; - - if (imm > 7 && !q) - return 1; - - if (q && ((rd | rn | rm) & 1)) { - return 1; - } - - if (imm == 0) { - neon_load_reg64(cpu_V0, rn); - if (q) { - neon_load_reg64(cpu_V1, rn + 1); - } - } else if (imm == 8) { - neon_load_reg64(cpu_V0, rn + 1); - if (q) { - neon_load_reg64(cpu_V1, rm); - } - } else if (q) { - tmp64 = tcg_temp_new_i64(); - if (imm < 8) { - neon_load_reg64(cpu_V0, rn); - neon_load_reg64(tmp64, rn + 1); - } else { - neon_load_reg64(cpu_V0, rn + 1); - neon_load_reg64(tmp64, rm); - } - tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8); - tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8)); - tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1); - if (imm < 8) { - neon_load_reg64(cpu_V1, rm); - } else { - neon_load_reg64(cpu_V1, rm + 1); - imm -= 8; - } - tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8)); - tcg_gen_shri_i64(tmp64, tmp64, imm * 8); - tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64); - tcg_temp_free_i64(tmp64); - } else { - /* BUGFIX */ - neon_load_reg64(cpu_V0, rn); - tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8); - neon_load_reg64(cpu_V1, rm); - tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8)); - tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1); - } - neon_store_reg64(cpu_V0, rd); - if (q) { - neon_store_reg64(cpu_V1, rd + 1); - } + /* Extract: handled by decodetree */ + return 1; } else if ((insn & (1 << 11)) == 0) { /* Two register misc. */ op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf); From 54e96c744b70a5d19f14b212a579dd3be8fcaad9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:28 +0100 Subject: [PATCH 1299/2595] target/arm: Convert Neon VTBL, VTBX to decodetree Convert the Neon VTBL, VTBX instructions to decodetree. The actual implementation of the insn is copied across to the new trans function unchanged except for renaming 'tmp5' to 'tmp4'. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 3 ++ target/arm/translate-neon.inc.c | 56 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 41 +++--------------------- 3 files changed, 63 insertions(+), 37 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 26d6022016..91bc770dfb 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -419,6 +419,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm ################################################################## VEXT 1111 001 0 1 . 11 .... .... imm:4 . q:1 . 0 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp + + VTBL 1111 001 1 1 . 11 .... .... 10 len:2 . op:1 . 0 .... \ + vm=%vm_dp vn=%vn_dp vd=%vd_dp ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 84bc2b239c..da0e5dbc6f 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2888,3 +2888,59 @@ static bool trans_VEXT(DisasContext *s, arg_VEXT *a) } return true; } + +static bool trans_VTBL(DisasContext *s, arg_VTBL *a) +{ + int n; + TCGv_i32 tmp, tmp2, tmp3, tmp4; + TCGv_ptr ptr1; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + n = a->len + 1; + if ((a->vn + n) > 32) { + /* + * This is UNPREDICTABLE; we choose to UNDEF to avoid the + * helper function running off the end of the register file. + */ + return false; + } + n <<= 3; + if (a->op) { + tmp = neon_load_reg(a->vd, 0); + } else { + tmp = tcg_temp_new_i32(); + tcg_gen_movi_i32(tmp, 0); + } + tmp2 = neon_load_reg(a->vm, 0); + ptr1 = vfp_reg_ptr(true, a->vn); + tmp4 = tcg_const_i32(n); + gen_helper_neon_tbl(tmp2, tmp2, tmp, ptr1, tmp4); + tcg_temp_free_i32(tmp); + if (a->op) { + tmp = neon_load_reg(a->vd, 1); + } else { + tmp = tcg_temp_new_i32(); + tcg_gen_movi_i32(tmp, 0); + } + tmp3 = neon_load_reg(a->vm, 1); + gen_helper_neon_tbl(tmp3, tmp3, tmp, ptr1, tmp4); + tcg_temp_free_i32(tmp4); + tcg_temp_free_ptr(ptr1); + neon_store_reg(a->vd, 0, tmp2); + neon_store_reg(a->vd, 1, tmp3); + tcg_temp_free_i32(tmp); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index a0822dba5e..0c6425928f 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5025,13 +5025,12 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) { int op; int q; - int rd, rn, rm, rd_ofs, rm_ofs; + int rd, rm, rd_ofs, rm_ofs; int size; int pass; int u; int vec_size; - TCGv_i32 tmp, tmp2, tmp3, tmp5; - TCGv_ptr ptr1; + TCGv_i32 tmp, tmp2, tmp3; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { return 1; @@ -5052,7 +5051,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) q = (insn & (1 << 6)) != 0; u = (insn >> 24) & 1; VFP_DREG_D(rd, insn); - VFP_DREG_N(rn, insn); VFP_DREG_M(rm, insn); size = (insn >> 20) & 3; vec_size = q ? 16 : 8; @@ -5577,39 +5575,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) break; } } else if ((insn & (1 << 10)) == 0) { - /* VTBL, VTBX. */ - int n = ((insn >> 8) & 3) + 1; - if ((rn + n) > 32) { - /* This is UNPREDICTABLE; we choose to UNDEF to avoid the - * helper function running off the end of the register file. - */ - return 1; - } - n <<= 3; - if (insn & (1 << 6)) { - tmp = neon_load_reg(rd, 0); - } else { - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, 0); - } - tmp2 = neon_load_reg(rm, 0); - ptr1 = vfp_reg_ptr(true, rn); - tmp5 = tcg_const_i32(n); - gen_helper_neon_tbl(tmp2, tmp2, tmp, ptr1, tmp5); - tcg_temp_free_i32(tmp); - if (insn & (1 << 6)) { - tmp = neon_load_reg(rd, 1); - } else { - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, 0); - } - tmp3 = neon_load_reg(rm, 1); - gen_helper_neon_tbl(tmp3, tmp3, tmp, ptr1, tmp5); - tcg_temp_free_i32(tmp5); - tcg_temp_free_ptr(ptr1); - neon_store_reg(rd, 0, tmp2); - neon_store_reg(rd, 1, tmp3); - tcg_temp_free_i32(tmp); + /* VTBL, VTBX: handled by decodetree */ + return 1; } else if ((insn & 0x380) == 0) { /* VDUP */ int element; From 9aaa23c2ae18e6fb9a291b81baf91341db76dfa0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 10:32:28 +0100 Subject: [PATCH 1300/2595] target/arm: Convert Neon VDUP (scalar) to decodetree Convert the Neon VDUP (scalar) insn to decodetree. (Note that we can't call this just "VDUP" as we used that already in vfp.decode for the "VDUP (general purpose register" insn.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/neon-dp.decode | 7 +++++++ target/arm/translate-neon.inc.c | 26 ++++++++++++++++++++++++++ target/arm/translate.c | 25 +------------------------ 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 91bc770dfb..6d890b2161 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -422,6 +422,13 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VTBL 1111 001 1 1 . 11 .... .... 10 len:2 . op:1 . 0 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp + + VDUP_scalar 1111 001 1 1 . 11 index:3 1 .... 11 000 q:1 . 0 .... \ + vm=%vm_dp vd=%vd_dp size=0 + VDUP_scalar 1111 001 1 1 . 11 index:2 10 .... 11 000 q:1 . 0 .... \ + vm=%vm_dp vd=%vd_dp size=1 + VDUP_scalar 1111 001 1 1 . 11 index:1 100 .... 11 000 q:1 . 0 .... \ + vm=%vm_dp vd=%vd_dp size=2 ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index da0e5dbc6f..a5aa56bbde 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2944,3 +2944,29 @@ static bool trans_VTBL(DisasContext *s, arg_VTBL *a) tcg_temp_free_i32(tmp); return true; } + +static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) +{ + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (a->vd & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + tcg_gen_gvec_dup_mem(a->size, neon_reg_offset(a->vd, 0), + neon_element_offset(a->vm, a->index, a->size), + a->q ? 16 : 8, a->q ? 16 : 8); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 0c6425928f..6d18892ade 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5574,31 +5574,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } break; } - } else if ((insn & (1 << 10)) == 0) { - /* VTBL, VTBX: handled by decodetree */ - return 1; - } else if ((insn & 0x380) == 0) { - /* VDUP */ - int element; - MemOp size; - - if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) { - return 1; - } - if (insn & (1 << 16)) { - size = MO_8; - element = (insn >> 17) & 7; - } else if (insn & (1 << 17)) { - size = MO_16; - element = (insn >> 18) & 3; - } else { - size = MO_32; - element = (insn >> 19) & 1; - } - tcg_gen_gvec_dup_mem(size, neon_reg_offset(rd, 0), - neon_element_offset(rm, element, size), - q ? 16 : 8, q ? 16 : 8); } else { + /* VTBL, VTBX, VDUP: handled by decodetree */ return 1; } } From 3d26d7d69066f37b994d3a5eb7601311de2dd659 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Tue, 16 Jun 2020 10:32:28 +0100 Subject: [PATCH 1301/2595] hw/misc/imx6ul_ccm: Implement non writable bits in CCM registers Some bits of the CCM registers are non writable. This was left undone in the initial commit (all bits of registers were writable). This patch adds the required code to protect the non writable bits. Signed-off-by: Jean-Christophe Dubois Message-id: 20200608133508.550046-1-jcd@tribudubois.net Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/misc/imx6ul_ccm.c | 76 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/hw/misc/imx6ul_ccm.c b/hw/misc/imx6ul_ccm.c index a2fc1d0364..5e0661dacf 100644 --- a/hw/misc/imx6ul_ccm.c +++ b/hw/misc/imx6ul_ccm.c @@ -19,6 +19,62 @@ #include "trace.h" +static const uint32_t ccm_mask[CCM_MAX] = { + [CCM_CCR] = 0xf01fef80, + [CCM_CCDR] = 0xfffeffff, + [CCM_CSR] = 0xffffffff, + [CCM_CCSR] = 0xfffffef2, + [CCM_CACRR] = 0xfffffff8, + [CCM_CBCDR] = 0xc1f8e000, + [CCM_CBCMR] = 0xfc03cfff, + [CCM_CSCMR1] = 0x80700000, + [CCM_CSCMR2] = 0xe01ff003, + [CCM_CSCDR1] = 0xfe00c780, + [CCM_CS1CDR] = 0xfe00fe00, + [CCM_CS2CDR] = 0xf8007000, + [CCM_CDCDR] = 0xf00fffff, + [CCM_CHSCCDR] = 0xfffc01ff, + [CCM_CSCDR2] = 0xfe0001ff, + [CCM_CSCDR3] = 0xffffc1ff, + [CCM_CDHIPR] = 0xffffffff, + [CCM_CTOR] = 0x00000000, + [CCM_CLPCR] = 0xf39ff01c, + [CCM_CISR] = 0xfb85ffbe, + [CCM_CIMR] = 0xfb85ffbf, + [CCM_CCOSR] = 0xfe00fe00, + [CCM_CGPR] = 0xfffc3fea, + [CCM_CCGR0] = 0x00000000, + [CCM_CCGR1] = 0x00000000, + [CCM_CCGR2] = 0x00000000, + [CCM_CCGR3] = 0x00000000, + [CCM_CCGR4] = 0x00000000, + [CCM_CCGR5] = 0x00000000, + [CCM_CCGR6] = 0x00000000, + [CCM_CMEOR] = 0xafffff1f, +}; + +static const uint32_t analog_mask[CCM_ANALOG_MAX] = { + [CCM_ANALOG_PLL_ARM] = 0xfff60f80, + [CCM_ANALOG_PLL_USB1] = 0xfffe0fbc, + [CCM_ANALOG_PLL_USB2] = 0xfffe0fbc, + [CCM_ANALOG_PLL_SYS] = 0xfffa0ffe, + [CCM_ANALOG_PLL_SYS_SS] = 0x00000000, + [CCM_ANALOG_PLL_SYS_NUM] = 0xc0000000, + [CCM_ANALOG_PLL_SYS_DENOM] = 0xc0000000, + [CCM_ANALOG_PLL_AUDIO] = 0xffe20f80, + [CCM_ANALOG_PLL_AUDIO_NUM] = 0xc0000000, + [CCM_ANALOG_PLL_AUDIO_DENOM] = 0xc0000000, + [CCM_ANALOG_PLL_VIDEO] = 0xffe20f80, + [CCM_ANALOG_PLL_VIDEO_NUM] = 0xc0000000, + [CCM_ANALOG_PLL_VIDEO_DENOM] = 0xc0000000, + [CCM_ANALOG_PLL_ENET] = 0xffc20ff0, + [CCM_ANALOG_PFD_480] = 0x40404040, + [CCM_ANALOG_PFD_528] = 0x40404040, + [PMU_MISC0] = 0x01fe8306, + [PMU_MISC1] = 0x07fcede0, + [PMU_MISC2] = 0x005f5f5f, +}; + static const char *imx6ul_ccm_reg_name(uint32_t reg) { static char unknown[20]; @@ -596,11 +652,8 @@ static void imx6ul_ccm_write(void *opaque, hwaddr offset, uint64_t value, trace_ccm_write_reg(imx6ul_ccm_reg_name(index), (uint32_t)value); - /* - * We will do a better implementation later. In particular some bits - * cannot be written to. - */ - s->ccm[index] = (uint32_t)value; + s->ccm[index] = (s->ccm[index] & ccm_mask[index]) | + ((uint32_t)value & ~ccm_mask[index]); } static uint64_t imx6ul_analog_read(void *opaque, hwaddr offset, unsigned size) @@ -737,7 +790,7 @@ static void imx6ul_analog_write(void *opaque, hwaddr offset, uint64_t value, * the REG_NAME register. So we change the value of the * REG_NAME register, setting bits passed in the value. */ - s->analog[index - 1] |= value; + s->analog[index - 1] |= (value & ~analog_mask[index - 1]); break; case CCM_ANALOG_PLL_ARM_CLR: case CCM_ANALOG_PLL_USB1_CLR: @@ -762,7 +815,7 @@ static void imx6ul_analog_write(void *opaque, hwaddr offset, uint64_t value, * the REG_NAME register. So we change the value of the * REG_NAME register, unsetting bits passed in the value. */ - s->analog[index - 2] &= ~value; + s->analog[index - 2] &= ~(value & ~analog_mask[index - 2]); break; case CCM_ANALOG_PLL_ARM_TOG: case CCM_ANALOG_PLL_USB1_TOG: @@ -787,14 +840,11 @@ static void imx6ul_analog_write(void *opaque, hwaddr offset, uint64_t value, * the REG_NAME register. So we change the value of the * REG_NAME register, toggling bits passed in the value. */ - s->analog[index - 3] ^= value; + s->analog[index - 3] ^= (value & ~analog_mask[index - 3]); break; default: - /* - * We will do a better implementation later. In particular some bits - * cannot be written to. - */ - s->analog[index] = value; + s->analog[index] = (s->analog[index] & analog_mask[index]) | + (value & ~analog_mask[index]); break; } } From d7a64d0063d15bf2ee574f18e4f3fe82f57a32ca Mon Sep 17 00:00:00 2001 From: Erik Smit Date: Tue, 16 Jun 2020 10:32:29 +0100 Subject: [PATCH 1302/2595] Implement configurable descriptor size in ftgmac100 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hardware supports configurable descriptor sizes, configured in the DBLAC register. Most drivers use the default 4 word descriptor, which is currently hardcoded, but Aspeed SDK configures 8 words to store extra data. Signed-off-by: Erik Smit Reviewed-by: Cédric Le Goater [PMM: removed unnecessary parens] Signed-off-by: Peter Maydell --- hw/net/ftgmac100.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 25ebee7ec2..043ba61b86 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -79,6 +79,16 @@ #define FTGMAC100_APTC_TXPOLL_CNT(x) (((x) >> 8) & 0xf) #define FTGMAC100_APTC_TXPOLL_TIME_SEL (1 << 12) +/* + * DMA burst length and arbitration control register + */ +#define FTGMAC100_DBLAC_RXBURST_SIZE(x) (((x) >> 8) & 0x3) +#define FTGMAC100_DBLAC_TXBURST_SIZE(x) (((x) >> 10) & 0x3) +#define FTGMAC100_DBLAC_RXDES_SIZE(x) ((((x) >> 12) & 0xf) * 8) +#define FTGMAC100_DBLAC_TXDES_SIZE(x) ((((x) >> 16) & 0xf) * 8) +#define FTGMAC100_DBLAC_IFG_CNT(x) (((x) >> 20) & 0x7) +#define FTGMAC100_DBLAC_IFG_INC (1 << 23) + /* * PHY control register */ @@ -553,7 +563,7 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring, if (bd.des0 & s->txdes0_edotr) { addr = tx_ring; } else { - addr += sizeof(FTGMAC100Desc); + addr += FTGMAC100_DBLAC_TXDES_SIZE(s->dblac); } } @@ -800,6 +810,18 @@ static void ftgmac100_write(void *opaque, hwaddr addr, s->phydata = value & 0xffff; break; case FTGMAC100_DBLAC: /* DMA Burst Length and Arbitration Control */ + if (FTGMAC100_DBLAC_TXDES_SIZE(s->dblac) < sizeof(FTGMAC100Desc)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: transmit descriptor too small : %d bytes\n", + __func__, FTGMAC100_DBLAC_TXDES_SIZE(s->dblac)); + break; + } + if (FTGMAC100_DBLAC_RXDES_SIZE(s->dblac) < sizeof(FTGMAC100Desc)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: receive descriptor too small : %d bytes\n", + __func__, FTGMAC100_DBLAC_RXDES_SIZE(s->dblac)); + break; + } s->dblac = value; break; case FTGMAC100_REVR: /* Feature Register */ @@ -982,7 +1004,7 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf, if (bd.des0 & s->rxdes0_edorr) { addr = s->rx_ring; } else { - addr += sizeof(FTGMAC100Desc); + addr += FTGMAC100_DBLAC_RXDES_SIZE(s->dblac); } } s->rx_descriptor = addr; From 9e6f8d8aab3afe6d704054e3fd850bcba5aa20f7 Mon Sep 17 00:00:00 2001 From: fangying Date: Tue, 16 Jun 2020 10:32:29 +0100 Subject: [PATCH 1303/2595] target/arm/cpu: adjust virtual time for all KVM arm cpus Virtual time adjustment was implemented for virt-5.0 machine type, but the cpu property was enabled only for host-passthrough and max cpu model. Let's add it for any KVM arm cpu which has the generic timer feature enabled. Signed-off-by: Ying Fang Reviewed-by: Andrew Jones Message-id: 20200608121243.2076-1-fangying1@huawei.com [PMM: minor commit message tweak, removed inaccurate suggested-by tag] Signed-off-by: Peter Maydell --- target/arm/cpu.c | 6 ++++-- target/arm/cpu64.c | 1 - target/arm/kvm.c | 21 +++++++++++---------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 32bec156f2..5b7a36b5d7 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1245,6 +1245,10 @@ void arm_cpu_post_init(Object *obj) if (arm_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER)) { qdev_property_add_static(DEVICE(cpu), &arm_cpu_gt_cntfrq_property); } + + if (kvm_enabled()) { + kvm_arm_add_vcpu_properties(obj); + } } static void arm_cpu_finalizefn(Object *obj) @@ -2029,7 +2033,6 @@ static void arm_max_initfn(Object *obj) if (kvm_enabled()) { kvm_arm_set_cpu_features_from_host(cpu); - kvm_arm_add_vcpu_properties(obj); } else { cortex_a15_initfn(obj); @@ -2183,7 +2186,6 @@ static void arm_host_initfn(Object *obj) if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { aarch64_add_sve_properties(obj); } - kvm_arm_add_vcpu_properties(obj); arm_cpu_post_init(obj); } diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index cbc5c3868f..778cecc2e6 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -592,7 +592,6 @@ static void aarch64_max_initfn(Object *obj) if (kvm_enabled()) { kvm_arm_set_cpu_features_from_host(cpu); - kvm_arm_add_vcpu_properties(obj); } else { uint64_t t; uint32_t u; diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 4bdbe6dcac..eef3bbd1cc 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -194,17 +194,18 @@ static void kvm_no_adjvtime_set(Object *obj, bool value, Error **errp) /* KVM VCPU properties should be prefixed with "kvm-". */ void kvm_arm_add_vcpu_properties(Object *obj) { - if (!kvm_enabled()) { - return; - } + ARMCPU *cpu = ARM_CPU(obj); + CPUARMState *env = &cpu->env; - ARM_CPU(obj)->kvm_adjvtime = true; - object_property_add_bool(obj, "kvm-no-adjvtime", kvm_no_adjvtime_get, - kvm_no_adjvtime_set); - object_property_set_description(obj, "kvm-no-adjvtime", - "Set on to disable the adjustment of " - "the virtual counter. VM stopped time " - "will be counted."); + if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) { + cpu->kvm_adjvtime = true; + object_property_add_bool(obj, "kvm-no-adjvtime", kvm_no_adjvtime_get, + kvm_no_adjvtime_set); + object_property_set_description(obj, "kvm-no-adjvtime", + "Set on to disable the adjustment of " + "the virtual counter. VM stopped time " + "will be counted."); + } } bool kvm_arm_pmu_supported(CPUState *cpu) From 8095508a9d8af3d83365becf45ef2a58ba3d488a Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Tue, 16 Jun 2020 10:32:29 +0100 Subject: [PATCH 1304/2595] hw/net/imx_fec: Convert debug fprintf() to trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-Christophe Dubois Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Fixed 32-bit format string using PRIx32/PRIx64] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 106 +++++++++++++++++++------------------------- hw/net/trace-events | 18 ++++++++ 2 files changed, 63 insertions(+), 61 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 7adcc9df65..eefedc252d 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -31,34 +31,11 @@ #include "qemu/module.h" #include "net/checksum.h" #include "net/eth.h" +#include "trace.h" /* For crc32 */ #include -#ifndef DEBUG_IMX_FEC -#define DEBUG_IMX_FEC 0 -#endif - -#define FEC_PRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX_FEC) { \ - fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_FEC, \ - __func__, ##args); \ - } \ - } while (0) - -#ifndef DEBUG_IMX_PHY -#define DEBUG_IMX_PHY 0 -#endif - -#define PHY_PRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX_PHY) { \ - fprintf(stderr, "[%s.phy]%s: " fmt , TYPE_IMX_FEC, \ - __func__, ##args); \ - } \ - } while (0) - #define IMX_MAX_DESC 1024 static const char *imx_default_reg_name(IMXFECState *s, uint32_t index) @@ -262,43 +239,45 @@ static void imx_eth_update(IMXFECState *s); * For now we don't handle any GPIO/interrupt line, so the OS will * have to poll for the PHY status. */ -static void phy_update_irq(IMXFECState *s) +static void imx_phy_update_irq(IMXFECState *s) { imx_eth_update(s); } -static void phy_update_link(IMXFECState *s) +static void imx_phy_update_link(IMXFECState *s) { /* Autonegotiation status mirrors link status. */ if (qemu_get_queue(s->nic)->link_down) { - PHY_PRINTF("link is down\n"); + trace_imx_phy_update_link("down"); s->phy_status &= ~0x0024; s->phy_int |= PHY_INT_DOWN; } else { - PHY_PRINTF("link is up\n"); + trace_imx_phy_update_link("up"); s->phy_status |= 0x0024; s->phy_int |= PHY_INT_ENERGYON; s->phy_int |= PHY_INT_AUTONEG_COMPLETE; } - phy_update_irq(s); + imx_phy_update_irq(s); } static void imx_eth_set_link(NetClientState *nc) { - phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc))); + imx_phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc))); } -static void phy_reset(IMXFECState *s) +static void imx_phy_reset(IMXFECState *s) { + trace_imx_phy_reset(); + s->phy_status = 0x7809; s->phy_control = 0x3000; s->phy_advertise = 0x01e1; s->phy_int_mask = 0; s->phy_int = 0; - phy_update_link(s); + imx_phy_update_link(s); } -static uint32_t do_phy_read(IMXFECState *s, int reg) +static uint32_t imx_phy_read(IMXFECState *s, int reg) { uint32_t val; @@ -332,7 +311,7 @@ static uint32_t do_phy_read(IMXFECState *s, int reg) case 29: /* Interrupt source. */ val = s->phy_int; s->phy_int = 0; - phy_update_irq(s); + imx_phy_update_irq(s); break; case 30: /* Interrupt mask */ val = s->phy_int_mask; @@ -352,14 +331,14 @@ static uint32_t do_phy_read(IMXFECState *s, int reg) break; } - PHY_PRINTF("read 0x%04x @ %d\n", val, reg); + trace_imx_phy_read(val, reg); return val; } -static void do_phy_write(IMXFECState *s, int reg, uint32_t val) +static void imx_phy_write(IMXFECState *s, int reg, uint32_t val) { - PHY_PRINTF("write 0x%04x @ %d\n", val, reg); + trace_imx_phy_write(val, reg); if (reg > 31) { /* we only advertise one phy */ @@ -369,7 +348,7 @@ static void do_phy_write(IMXFECState *s, int reg, uint32_t val) switch (reg) { case 0: /* Basic Control */ if (val & 0x8000) { - phy_reset(s); + imx_phy_reset(s); } else { s->phy_control = val & 0x7980; /* Complete autonegotiation immediately. */ @@ -383,7 +362,7 @@ static void do_phy_write(IMXFECState *s, int reg, uint32_t val) break; case 30: /* Interrupt mask */ s->phy_int_mask = val & 0xff; - phy_update_irq(s); + imx_phy_update_irq(s); break; case 17: case 18: @@ -402,6 +381,8 @@ static void do_phy_write(IMXFECState *s, int reg, uint32_t val) static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr) { dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd)); + + trace_imx_fec_read_bd(addr, bd->flags, bd->length, bd->data); } static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr) @@ -412,6 +393,9 @@ static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr) static void imx_enet_read_bd(IMXENETBufDesc *bd, dma_addr_t addr) { dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd)); + + trace_imx_enet_read_bd(addr, bd->flags, bd->length, bd->data, + bd->option, bd->status); } static void imx_enet_write_bd(IMXENETBufDesc *bd, dma_addr_t addr) @@ -471,11 +455,11 @@ static void imx_fec_do_tx(IMXFECState *s) int len; imx_fec_read_bd(&bd, addr); - FEC_PRINTF("tx_bd %x flags %04x len %d data %08x\n", - addr, bd.flags, bd.length, bd.data); if ((bd.flags & ENET_BD_R) == 0) { + /* Run out of descriptors to transmit. */ - FEC_PRINTF("tx_bd ran out of descriptors to transmit\n"); + trace_imx_eth_tx_bd_busy(); + break; } len = bd.length; @@ -552,11 +536,11 @@ static void imx_enet_do_tx(IMXFECState *s, uint32_t index) int len; imx_enet_read_bd(&bd, addr); - FEC_PRINTF("tx_bd %x flags %04x len %d data %08x option %04x " - "status %04x\n", addr, bd.flags, bd.length, bd.data, - bd.option, bd.status); if ((bd.flags & ENET_BD_R) == 0) { /* Run out of descriptors to transmit. */ + + trace_imx_eth_tx_bd_busy(); + break; } len = bd.length; @@ -633,7 +617,7 @@ static void imx_eth_enable_rx(IMXFECState *s, bool flush) s->regs[ENET_RDAR] = (bd.flags & ENET_BD_E) ? ENET_RDAR_RDAR : 0; if (!s->regs[ENET_RDAR]) { - FEC_PRINTF("RX buffer full\n"); + trace_imx_eth_rx_bd_full(); } else if (flush) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } @@ -676,7 +660,7 @@ static void imx_eth_reset(DeviceState *d) memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor)); /* We also reset the PHY */ - phy_reset(s); + imx_phy_reset(s); } static uint32_t imx_default_read(IMXFECState *s, uint32_t index) @@ -774,8 +758,7 @@ static uint64_t imx_eth_read(void *opaque, hwaddr offset, unsigned size) break; } - FEC_PRINTF("reg[%s] => 0x%" PRIx32 "\n", imx_eth_reg_name(s, index), - value); + trace_imx_eth_read(index, imx_eth_reg_name(s, index), value); return value; } @@ -884,8 +867,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, const bool single_tx_ring = !imx_eth_is_multi_tx_ring(s); uint32_t index = offset >> 2; - FEC_PRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_eth_reg_name(s, index), - (uint32_t)value); + trace_imx_eth_write(index, imx_eth_reg_name(s, index), value); switch (index) { case ENET_EIR: @@ -940,12 +922,12 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, if (extract32(value, 29, 1)) { /* This is a read operation */ s->regs[ENET_MMFR] = deposit32(s->regs[ENET_MMFR], 0, 16, - do_phy_read(s, + imx_phy_read(s, extract32(value, 18, 10))); } else { /* This a write operation */ - do_phy_write(s, extract32(value, 18, 10), extract32(value, 0, 16)); + imx_phy_write(s, extract32(value, 18, 10), extract32(value, 0, 16)); } /* raise the interrupt as the PHY operation is done */ s->regs[ENET_EIR] |= ENET_INT_MII; @@ -1053,8 +1035,6 @@ static bool imx_eth_can_receive(NetClientState *nc) { IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); - FEC_PRINTF("\n"); - return !!s->regs[ENET_RDAR]; } @@ -1071,7 +1051,7 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, unsigned int buf_len; size_t size = len; - FEC_PRINTF("len %d\n", (int)size); + trace_imx_fec_receive(size); if (!s->regs[ENET_RDAR]) { qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Unexpected packet\n", @@ -1113,7 +1093,7 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, bd.length = buf_len; size -= buf_len; - FEC_PRINTF("rx_bd 0x%x length %d\n", addr, bd.length); + trace_imx_fec_receive_len(addr, bd.length); /* The last 4 bytes are the CRC. */ if (size < 4) { @@ -1131,7 +1111,9 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, if (size == 0) { /* Last buffer in frame. */ bd.flags |= flags | ENET_BD_L; - FEC_PRINTF("rx frame flags %04x\n", bd.flags); + + trace_imx_fec_receive_last(bd.flags); + s->regs[ENET_EIR] |= ENET_INT_RXF; } else { s->regs[ENET_EIR] |= ENET_INT_RXB; @@ -1164,7 +1146,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, size_t size = len; bool shift16 = s->regs[ENET_RACC] & ENET_RACC_SHIFT16; - FEC_PRINTF("len %d\n", (int)size); + trace_imx_enet_receive(size); if (!s->regs[ENET_RDAR]) { qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Unexpected packet\n", @@ -1210,7 +1192,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, bd.length = buf_len; size -= buf_len; - FEC_PRINTF("rx_bd 0x%x length %d\n", addr, bd.length); + trace_imx_enet_receive_len(addr, bd.length); /* The last 4 bytes are the CRC. */ if (size < 4) { @@ -1246,7 +1228,9 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, if (size == 0) { /* Last buffer in frame. */ bd.flags |= flags | ENET_BD_L; - FEC_PRINTF("rx frame flags %04x\n", bd.flags); + + trace_imx_enet_receive_last(bd.flags); + /* Indicate that we've updated the last buffer descriptor. */ bd.last_buffer = ENET_BD_BDU; if (bd.option & ENET_BD_RX_INT) { diff --git a/hw/net/trace-events b/hw/net/trace-events index e18f883cfd..26700dad99 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -408,3 +408,21 @@ i82596_receive_packet(size_t sz) "len=%zu" i82596_new_mac(const char *id_with_mac) "New MAC for: %s" i82596_set_multicast(uint16_t count) "Added %d multicast entries" i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION" + +# imx_fec.c +imx_phy_read(uint32_t val, int reg) "0x%04"PRIx32" <= reg[%d]" +imx_phy_write(uint32_t val, int reg) "0x%04"PRIx32" => reg[%d]" +imx_phy_update_link(const char *s) "%s" +imx_phy_reset(void) "" +imx_fec_read_bd(uint64_t addr, int flags, int len, int data) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x" +imx_enet_read_bd(uint64_t addr, int flags, int len, int data, int options, int status) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x option 0x%04x status 0x%04x" +imx_eth_tx_bd_busy(void) "tx_bd ran out of descriptors to transmit" +imx_eth_rx_bd_full(void) "RX buffer is full" +imx_eth_read(int reg, const char *reg_name, uint32_t value) "reg[%d:%s] => 0x%08"PRIx32 +imx_eth_write(int reg, const char *reg_name, uint64_t value) "reg[%d:%s] <= 0x%08"PRIx64 +imx_fec_receive(size_t size) "len %zu" +imx_fec_receive_len(uint64_t addr, int len) "rx_bd 0x%"PRIx64" length %d" +imx_fec_receive_last(int last) "rx frame flags 0x%04x" +imx_enet_receive(size_t size) "len %zu" +imx_enet_receive_len(uint64_t addr, int len) "rx_bd 0x%"PRIx64" length %d" +imx_enet_receive_last(int last) "rx frame flags 0x%04x" From 3b2d81766fd9c957a9fcfe997ff3d692e9981c98 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 16 Jun 2020 10:32:29 +0100 Subject: [PATCH 1305/2595] sd: sdhci: Implement basic vendor specific register support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Linux kernel's IMX code now uses vendor specific commands. This results in endless warnings when booting the Linux kernel. sdhci-esdhc-imx 2194000.usdhc: esdhc_wait_for_card_clock_gate_off: card clock still not gate off in 100us!. Implement support for the vendor specific command implemented in IMX hardware to be able to avoid this warning. Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Guenter Roeck Message-id: 20200603145258.195920-2-linux@roeck-us.net Signed-off-by: Peter Maydell --- hw/sd/sdhci-internal.h | 5 +++++ hw/sd/sdhci.c | 18 +++++++++++++++++- include/hw/sd/sdhci.h | 5 +++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index e7c8a523b5..e8c753d6d1 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -75,6 +75,7 @@ #define SDHC_CMD_INHIBIT 0x00000001 #define SDHC_DATA_INHIBIT 0x00000002 #define SDHC_DAT_LINE_ACTIVE 0x00000004 +#define SDHC_IMX_CLOCK_GATE_OFF 0x00000080 #define SDHC_DOING_WRITE 0x00000100 #define SDHC_DOING_READ 0x00000200 #define SDHC_SPACE_AVAILABLE 0x00000400 @@ -289,7 +290,10 @@ extern const VMStateDescription sdhci_vmstate; #define ESDHC_MIX_CTRL 0x48 + #define ESDHC_VENDOR_SPEC 0xc0 +#define ESDHC_IMX_FRC_SDCLK_ON (1 << 8) + #define ESDHC_DLL_CTRL 0x60 #define ESDHC_TUNING_CTRL 0xcc @@ -326,6 +330,7 @@ extern const VMStateDescription sdhci_vmstate; #define DEFINE_SDHCI_COMMON_PROPERTIES(_state) \ DEFINE_PROP_UINT8("sd-spec-version", _state, sd_spec_version, 2), \ DEFINE_PROP_UINT8("uhs", _state, uhs_mode, UHS_NOT_SUPPORTED), \ + DEFINE_PROP_UINT8("vendor", _state, vendor, SDHCI_VENDOR_NONE), \ \ /* Capabilities registers provide information on supported * features of this specific host controller implementation */ \ diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 1b75d7bab9..eb2be6529e 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1569,11 +1569,13 @@ static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size) } break; + case ESDHC_VENDOR_SPEC: + ret = s->vendor_spec; + break; case ESDHC_DLL_CTRL: case ESDHC_TUNE_CTRL_STATUS: case ESDHC_UNDOCUMENTED_REG27: case ESDHC_TUNING_CTRL: - case ESDHC_VENDOR_SPEC: case ESDHC_MIX_CTRL: case ESDHC_WTMK_LVL: ret = 0; @@ -1596,7 +1598,21 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) case ESDHC_UNDOCUMENTED_REG27: case ESDHC_TUNING_CTRL: case ESDHC_WTMK_LVL: + break; + case ESDHC_VENDOR_SPEC: + s->vendor_spec = value; + switch (s->vendor) { + case SDHCI_VENDOR_IMX: + if (value & ESDHC_IMX_FRC_SDCLK_ON) { + s->prnsts &= ~SDHC_IMX_CLOCK_GATE_OFF; + } else { + s->prnsts |= SDHC_IMX_CLOCK_GATE_OFF; + } + break; + default: + break; + } break; case SDHC_HOSTCTL: diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h index c6868c9699..5d9275f3d6 100644 --- a/include/hw/sd/sdhci.h +++ b/include/hw/sd/sdhci.h @@ -74,6 +74,7 @@ typedef struct SDHCIState { uint16_t acmd12errsts; /* Auto CMD12 error status register */ uint16_t hostctl2; /* Host Control 2 */ uint64_t admasysaddr; /* ADMA System Address Register */ + uint16_t vendor_spec; /* Vendor specific register */ /* Read-only registers */ uint64_t capareg; /* Capabilities Register */ @@ -96,8 +97,12 @@ typedef struct SDHCIState { uint32_t quirks; uint8_t sd_spec_version; uint8_t uhs_mode; + uint8_t vendor; /* For vendor specific functionality */ } SDHCIState; +#define SDHCI_VENDOR_NONE 0 +#define SDHCI_VENDOR_IMX 1 + /* * Controller does not provide transfer-complete interrupt when not * busy. From 64b397417a26509bcdff44ab94356a35c7901c79 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 16 Jun 2020 10:32:29 +0100 Subject: [PATCH 1306/2595] hw: arm: Set vendor property for IMX SDHCI emulations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set vendor property to IMX to enable IMX specific functionality in sdhci code. Tested-by: Philippe Mathieu-Daudé Signed-off-by: Guenter Roeck Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200603145258.195920-3-linux@roeck-us.net Signed-off-by: Peter Maydell --- hw/arm/fsl-imx25.c | 6 ++++++ hw/arm/fsl-imx6.c | 6 ++++++ hw/arm/fsl-imx6ul.c | 2 ++ hw/arm/fsl-imx7.c | 2 ++ 4 files changed, 16 insertions(+) diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index cdaa79c26b..a853ffcc00 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -274,6 +274,12 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) &err); object_property_set_uint(OBJECT(&s->esdhc[i]), IMX25_ESDHC_CAPABILITIES, "capareg", &err); + object_property_set_uint(OBJECT(&s->esdhc[i]), SDHCI_VENDOR_IMX, + "vendor", &err); + if (err) { + error_propagate(errp, err); + return; + } object_property_set_bool(OBJECT(&s->esdhc[i]), true, "realized", &err); if (err) { error_propagate(errp, err); diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index f58c85aa8c..29677cfd59 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -350,6 +350,12 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) &err); object_property_set_uint(OBJECT(&s->esdhc[i]), IMX6_ESDHC_CAPABILITIES, "capareg", &err); + object_property_set_uint(OBJECT(&s->esdhc[i]), SDHCI_VENDOR_IMX, + "vendor", &err); + if (err) { + error_propagate(errp, err); + return; + } object_property_set_bool(OBJECT(&s->esdhc[i]), true, "realized", &err); if (err) { error_propagate(errp, err); diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index 3ecb212da6..ce1462927c 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -505,6 +505,8 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_USDHC2_IRQ, }; + object_property_set_uint(OBJECT(&s->usdhc[i]), SDHCI_VENDOR_IMX, + "vendor", &error_abort); object_property_set_bool(OBJECT(&s->usdhc[i]), true, "realized", &error_abort); diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index 89c3b64c06..dbf16b2814 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -416,6 +416,8 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_USDHC3_IRQ, }; + object_property_set_uint(OBJECT(&s->usdhc[i]), SDHCI_VENDOR_IMX, + "vendor", &error_abort); object_property_set_bool(OBJECT(&s->usdhc[i]), true, "realized", &error_abort); From 7ec1edde9eba46964cd2e8fca2c004b2021e79f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 12 Jun 2020 20:02:20 +0100 Subject: [PATCH 1307/2595] tests/docker: bump fedora to 32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should be keeping this up to date as Fedora goes out of support quite quickly. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200612190237.30436-2-alex.bennee@linaro.org> --- tests/docker/dockerfiles/fedora.docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 92b6e11c8a..798ddd2c3e 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -1,4 +1,4 @@ -FROM fedora:30 +FROM fedora:32 # Please keep this list sorted alphabetically ENV PACKAGES \ From 67953a379ea5497e7cffda14b9362c673845abbb Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Fri, 12 Jun 2020 20:02:21 +0100 Subject: [PATCH 1308/2595] Makefile: dtc: update, build the libfdt target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dtc submodule update, now call the libfdt target from the new dtc Makefile, which has been changed to not require bison, flex, etc. This removes warnings during the build. scripts/ symlink and tests directory creation are not necessary, and neither is calling the clean rule explicitly. Signed-off-by: Claudio Fontana Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200518160319.18861-2-cfontana@suse.de> Message-Id: <20200612190237.30436-3-alex.bennee@linaro.org> --- Makefile | 10 +++++----- configure | 1 - dtc | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index ed0ed93b2d..895410fbf9 100644 --- a/Makefile +++ b/Makefile @@ -526,13 +526,14 @@ $(SOFTMMU_FUZZ_RULES): $(edk2-decompressed) $(TARGET_DIRS_RULES): $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" $(notdir $@),) -DTC_MAKE_ARGS=-I$(SRC_PATH)/dtc VPATH=$(SRC_PATH)/dtc -C dtc V="$(V)" LIBFDT_srcdir=$(SRC_PATH)/dtc/libfdt +# LIBFDT_lib="": avoid breaking existing trees with objects requiring -fPIC +DTC_MAKE_ARGS=-I$(SRC_PATH)/dtc VPATH=$(SRC_PATH)/dtc -C dtc V="$(V)" LIBFDT_lib="" DTC_CFLAGS=$(CFLAGS) $(QEMU_CFLAGS) -DTC_CPPFLAGS=-I$(BUILD_DIR)/dtc -I$(SRC_PATH)/dtc -I$(SRC_PATH)/dtc/libfdt +DTC_CPPFLAGS=-I$(SRC_PATH)/dtc/libfdt .PHONY: dtc/all -dtc/all: .git-submodule-status dtc/libfdt dtc/tests - $(call quiet-command,$(MAKE) $(DTC_MAKE_ARGS) CPPFLAGS="$(DTC_CPPFLAGS)" CFLAGS="$(DTC_CFLAGS)" LDFLAGS="$(QEMU_LDFLAGS)" ARFLAGS="$(ARFLAGS)" CC="$(CC)" AR="$(AR)" LD="$(LD)" $(SUBDIR_MAKEFLAGS) libfdt/libfdt.a,) +dtc/all: .git-submodule-status dtc/libfdt + $(call quiet-command,$(MAKE) $(DTC_MAKE_ARGS) CPPFLAGS="$(DTC_CPPFLAGS)" CFLAGS="$(DTC_CFLAGS)" LDFLAGS="$(QEMU_LDFLAGS)" ARFLAGS="$(ARFLAGS)" CC="$(CC)" AR="$(AR)" LD="$(LD)" $(SUBDIR_MAKEFLAGS) libfdt,) dtc/%: .git-submodule-status @mkdir -p $@ @@ -820,7 +821,6 @@ distclean: clean rm -rf $$d || exit 1 ; \ done rm -Rf .sdk - if test -f dtc/version_gen.h; then $(MAKE) $(DTC_MAKE_ARGS) clean; fi KEYMAPS=da en-gb et fr fr-ch is lt no pt-br sv \ ar de en-us fi fr-be hr it lv nl pl ru th \ diff --git a/configure b/configure index 89867a1720..8a9f544b0b 100755 --- a/configure +++ b/configure @@ -4312,7 +4312,6 @@ EOF mkdir -p dtc if [ "$pwd_is_source_path" != "y" ] ; then symlink "$source_path/dtc/Makefile" "dtc/Makefile" - symlink "$source_path/dtc/scripts" "dtc/scripts" fi fdt_cflags="-I\$(SRC_PATH)/dtc/libfdt" fdt_ldflags="-L\$(BUILD_DIR)/dtc/libfdt" diff --git a/dtc b/dtc index 88f18909db..85e5d83984 160000 --- a/dtc +++ b/dtc @@ -1 +1 @@ -Subproject commit 88f18909db731a627456f26d779445f84e449536 +Subproject commit 85e5d839847af54efab170f2b1331b2a6421e647 From 897e34f20f2196089ad4910d95a7c74ee14292c8 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Fri, 12 Jun 2020 20:02:22 +0100 Subject: [PATCH 1309/2595] Makefile: remove old compatibility gunks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Claudio Fontana Reviewed-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200518160319.18861-3-cfontana@suse.de> Message-Id: <20200612190237.30436-4-alex.bennee@linaro.org> --- Makefile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Makefile b/Makefile index 895410fbf9..48f23aa978 100644 --- a/Makefile +++ b/Makefile @@ -562,12 +562,6 @@ slirp/all: .git-submodule-status CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" \ CFLAGS="$(QEMU_CFLAGS) $(CFLAGS)" LDFLAGS="$(QEMU_LDFLAGS)") -# Compatibility gunk to keep make working across the rename of targets -# for recursion, to be removed some time after 4.1. -subdir-dtc: dtc/all -subdir-capstone: capstone/all -subdir-slirp: slirp/all - $(filter %/all, $(TARGET_DIRS_RULES)): libqemuutil.a $(common-obj-y) \ $(qom-obj-y) From 0aebab04b9289bd37017593b413ce7a762b54c55 Mon Sep 17 00:00:00 2001 From: Lingfeng Yang Date: Fri, 12 Jun 2020 20:02:23 +0100 Subject: [PATCH 1310/2595] configure: add --enable-tsan flag + fiber annotations for coroutine-ucontext MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We tried running QEMU under tsan in 2016, but tsan's lack of support for longjmp-based fibers was a blocker: https://groups.google.com/forum/#!topic/thread-sanitizer/se0YuzfWazw Fortunately, thread sanitizer gained fiber support in early 2019: https://reviews.llvm.org/D54889 This patch brings tsan support upstream by importing the patch that annotated QEMU's coroutines as tsan fibers in Android's QEMU fork: https://android-review.googlesource.com/c/platform/external/qemu/+/844675 Tested with '--enable-tsan --cc=clang-9 --cxx=clang++-9 --disable-werror' configure flags. Signed-off-by: Lingfeng Yang Signed-off-by: Emilio G. Cota [cota: minor modifications + configure changes] Signed-off-by: Robert Foley [RF: configure changes, coroutine fix + minor modifications] Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-2-robert.foley@linaro.org> Message-Id: <20200612190237.30436-5-alex.bennee@linaro.org> --- configure | 47 +++++++++++++++++++++++++++- util/coroutine-ucontext.c | 66 +++++++++++++++++++++++++++++++++------ 2 files changed, 103 insertions(+), 10 deletions(-) diff --git a/configure b/configure index 8a9f544b0b..b01b5e3bed 100755 --- a/configure +++ b/configure @@ -395,6 +395,7 @@ gprof="no" debug_tcg="no" debug="no" sanitizers="no" +tsan="no" fortify_source="" strip_opt="yes" tcg_interpreter="no" @@ -1152,6 +1153,10 @@ for opt do ;; --disable-sanitizers) sanitizers="no" ;; + --enable-tsan) tsan="yes" + ;; + --disable-tsan) tsan="no" + ;; --enable-sparse) sparse="yes" ;; --disable-sparse) sparse="no" @@ -1764,6 +1769,7 @@ Advanced options (experts only): --with-pkgversion=VERS use specified string as sub-version of the package --enable-debug enable common debug build options --enable-sanitizers enable default sanitizers + --enable-tsan enable thread sanitizer --disable-strip disable stripping binaries --disable-werror disable compilation abort on warning --disable-stack-protector disable compiler-provided stack protection @@ -6220,6 +6226,30 @@ if test "$fuzzing" = "yes" ; then fi fi +# Thread sanitizer is, for now, much noisier than the other sanitizers; +# keep it separate until that is not the case. +if test "$tsan" = "yes" && test "$sanitizers" = "yes"; then + error_exit "TSAN is not supported with other sanitiziers." +fi +have_tsan=no +have_tsan_iface_fiber=no +if test "$tsan" = "yes" ; then + write_c_skeleton + if compile_prog "$CPU_CFLAGS -Werror -fsanitize=thread" "" ; then + have_tsan=yes + fi + cat > $TMPC << EOF +#include +int main(void) { + __tsan_create_fiber(0); + return 0; +} +EOF + if compile_prog "$CPU_CFLAGS -Werror -fsanitize=thread" "" ; then + have_tsan_iface_fiber=yes + fi +fi + ########################################## # check for libpmem @@ -6377,6 +6407,16 @@ if test "$have_asan" = "yes"; then "Without code annotation, the report may be inferior." fi fi +if test "$have_tsan" = "yes" ; then + if test "$have_tsan_iface_fiber" = "yes" ; then + QEMU_CFLAGS="-fsanitize=thread $QEMU_CFLAGS" + QEMU_LDFLAGS="-fsanitize=thread $QEMU_LDFLAGS" + else + error_exit "Cannot enable TSAN due to missing fiber annotation interface." + fi +elif test "$tsan" = "yes" ; then + error_exit "Cannot enable TSAN due to missing sanitize thread interface." +fi if test "$have_ubsan" = "yes"; then QEMU_CFLAGS="-fsanitize=undefined $QEMU_CFLAGS" QEMU_LDFLAGS="-fsanitize=undefined $QEMU_LDFLAGS" @@ -6412,7 +6452,8 @@ if test "$werror" = "yes"; then QEMU_CFLAGS="-Werror $QEMU_CFLAGS" fi -if test "$solaris" = "no" ; then +# Exclude --warn-common with TSan to suppress warnings from the TSan libraries. +if test "$solaris" = "no" && test "$tsan" = "no"; then if $ld --version 2>/dev/null | grep "GNU ld" >/dev/null 2>/dev/null ; then QEMU_LDFLAGS="-Wl,--warn-common $QEMU_LDFLAGS" fi @@ -7476,6 +7517,10 @@ if test "$have_asan_iface_fiber" = "yes" ; then echo "CONFIG_ASAN_IFACE_FIBER=y" >> $config_host_mak fi +if test "$have_tsan" = "yes" && test "$have_tsan_iface_fiber" = "yes" ; then + echo "CONFIG_TSAN=y" >> $config_host_mak +fi + if test "$has_environ" = "yes" ; then echo "CONFIG_HAS_ENVIRON=y" >> $config_host_mak fi diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index bd593e61bc..613f4c118e 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -37,12 +37,19 @@ #endif #endif +#ifdef CONFIG_TSAN +#include +#endif + typedef struct { Coroutine base; void *stack; size_t stack_size; sigjmp_buf env; + void *tsan_co_fiber; + void *tsan_caller_fiber; + #ifdef CONFIG_VALGRIND_H unsigned int valgrind_stack_id; #endif @@ -65,7 +72,18 @@ union cc_arg { int i[2]; }; -static void finish_switch_fiber(void *fake_stack_save) +/* QEMU_ALWAYS_INLINE only does so if __OPTIMIZE__, so we cannot use it. */ +static inline __attribute__((always_inline)) +void on_new_fiber(CoroutineUContext *co) +{ +#ifdef CONFIG_TSAN + co->tsan_co_fiber = __tsan_create_fiber(0); /* flags: sync on switch */ + co->tsan_caller_fiber = __tsan_get_current_fiber(); +#endif +} + +static inline __attribute__((always_inline)) +void finish_switch_fiber(void *fake_stack_save) { #ifdef CONFIG_ASAN const void *bottom_old; @@ -78,13 +96,30 @@ static void finish_switch_fiber(void *fake_stack_save) leader.stack_size = size_old; } #endif +#ifdef CONFIG_TSAN + if (fake_stack_save) { + __tsan_release(fake_stack_save); + __tsan_switch_to_fiber(fake_stack_save, 0); /* 0=synchronize */ + } +#endif } -static void start_switch_fiber(void **fake_stack_save, - const void *bottom, size_t size) +static inline __attribute__((always_inline)) void start_switch_fiber( + CoroutineAction action, void **fake_stack_save, + const void *bottom, size_t size, void *new_fiber) { #ifdef CONFIG_ASAN - __sanitizer_start_switch_fiber(fake_stack_save, bottom, size); + __sanitizer_start_switch_fiber( + action == COROUTINE_TERMINATE ? NULL : fake_stack_save, + bottom, size); +#endif +#ifdef CONFIG_TSAN + void *curr_fiber = + __tsan_get_current_fiber(); + __tsan_acquire(curr_fiber); + + *fake_stack_save = curr_fiber; + __tsan_switch_to_fiber(new_fiber, 0); /* 0=synchronize */ #endif } @@ -104,8 +139,12 @@ static void coroutine_trampoline(int i0, int i1) /* Initialize longjmp environment and switch back the caller */ if (!sigsetjmp(self->env, 0)) { - start_switch_fiber(&fake_stack_save, - leader.stack, leader.stack_size); + start_switch_fiber( + COROUTINE_YIELD, + &fake_stack_save, + leader.stack, + leader.stack_size, + self->tsan_caller_fiber); siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); } @@ -154,12 +193,16 @@ Coroutine *qemu_coroutine_new(void) arg.p = co; + on_new_fiber(co); makecontext(&uc, (void (*)(void))coroutine_trampoline, 2, arg.i[0], arg.i[1]); /* swapcontext() in, siglongjmp() back out */ if (!sigsetjmp(old_env, 0)) { - start_switch_fiber(&fake_stack_save, co->stack, co->stack_size); + start_switch_fiber( + COROUTINE_YIELD, + &fake_stack_save, + co->stack, co->stack_size, co->tsan_co_fiber); swapcontext(&old_uc, &uc); } @@ -216,8 +259,8 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, ret = sigsetjmp(from->env, 0); if (ret == 0) { - start_switch_fiber(action == COROUTINE_TERMINATE ? - NULL : &fake_stack_save, to->stack, to->stack_size); + start_switch_fiber(action, &fake_stack_save, + to->stack, to->stack_size, to->tsan_co_fiber); siglongjmp(to->env, action); } @@ -231,6 +274,11 @@ Coroutine *qemu_coroutine_self(void) if (!current) { current = &leader.base; } +#ifdef CONFIG_TSAN + if (!leader.tsan_co_fiber) { + leader.tsan_co_fiber = __tsan_get_current_fiber(); + } +#endif return current; } From 0c0fcc2052915c629daa2469bfae620da18b2394 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Jun 2020 20:02:24 +0100 Subject: [PATCH 1311/2595] cpu: convert queued work to a QSIMPLEQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We convert queued work to a QSIMPLEQ, instead of open-coding it. While at it, make sure that all accesses to the list are performed while holding the list's lock. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Emilio G. Cota Signed-off-by: Robert Foley Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-3-robert.foley@linaro.org> Message-Id: <20200612190237.30436-6-alex.bennee@linaro.org> --- cpus-common.c | 25 ++++++++----------------- cpus.c | 14 ++++++++++++-- hw/core/cpu.c | 1 + include/hw/core/cpu.h | 6 +++--- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/cpus-common.c b/cpus-common.c index 70a9d12981..8f5512b3d7 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -97,7 +97,7 @@ void cpu_list_remove(CPUState *cpu) } struct qemu_work_item { - struct qemu_work_item *next; + QSIMPLEQ_ENTRY(qemu_work_item) node; run_on_cpu_func func; run_on_cpu_data data; bool free, exclusive, done; @@ -106,13 +106,7 @@ struct qemu_work_item { static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi) { qemu_mutex_lock(&cpu->work_mutex); - if (cpu->queued_work_first == NULL) { - cpu->queued_work_first = wi; - } else { - cpu->queued_work_last->next = wi; - } - cpu->queued_work_last = wi; - wi->next = NULL; + QSIMPLEQ_INSERT_TAIL(&cpu->work_list, wi, node); wi->done = false; qemu_mutex_unlock(&cpu->work_mutex); @@ -306,17 +300,14 @@ void process_queued_cpu_work(CPUState *cpu) { struct qemu_work_item *wi; - if (cpu->queued_work_first == NULL) { + qemu_mutex_lock(&cpu->work_mutex); + if (QSIMPLEQ_EMPTY(&cpu->work_list)) { + qemu_mutex_unlock(&cpu->work_mutex); return; } - - qemu_mutex_lock(&cpu->work_mutex); - while (cpu->queued_work_first != NULL) { - wi = cpu->queued_work_first; - cpu->queued_work_first = wi->next; - if (!cpu->queued_work_first) { - cpu->queued_work_last = NULL; - } + while (!QSIMPLEQ_EMPTY(&cpu->work_list)) { + wi = QSIMPLEQ_FIRST(&cpu->work_list); + QSIMPLEQ_REMOVE_HEAD(&cpu->work_list, node); qemu_mutex_unlock(&cpu->work_mutex); if (wi->exclusive) { /* Running work items outside the BQL avoids the following deadlock: diff --git a/cpus.c b/cpus.c index 34fc203808..7317ae06b9 100644 --- a/cpus.c +++ b/cpus.c @@ -97,9 +97,19 @@ bool cpu_is_stopped(CPUState *cpu) return cpu->stopped || !runstate_is_running(); } +static inline bool cpu_work_list_empty(CPUState *cpu) +{ + bool ret; + + qemu_mutex_lock(&cpu->work_mutex); + ret = QSIMPLEQ_EMPTY(&cpu->work_list); + qemu_mutex_unlock(&cpu->work_mutex); + return ret; +} + static bool cpu_thread_is_idle(CPUState *cpu) { - if (cpu->stop || cpu->queued_work_first) { + if (cpu->stop || !cpu_work_list_empty(cpu)) { return false; } if (cpu_is_stopped(cpu)) { @@ -1518,7 +1528,7 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) cpu = first_cpu; } - while (cpu && !cpu->queued_work_first && !cpu->exit_request) { + while (cpu && cpu_work_list_empty(cpu) && !cpu->exit_request) { atomic_mb_set(&tcg_current_rr_cpu, cpu); current_cpu = cpu; diff --git a/hw/core/cpu.c b/hw/core/cpu.c index f31ec48ee6..80d51c24dd 100644 --- a/hw/core/cpu.c +++ b/hw/core/cpu.c @@ -370,6 +370,7 @@ static void cpu_common_initfn(Object *obj) cpu->nr_threads = 1; qemu_mutex_init(&cpu->work_mutex); + QSIMPLEQ_INIT(&cpu->work_list); QTAILQ_INIT(&cpu->breakpoints); QTAILQ_INIT(&cpu->watchpoints); diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 497600c49e..b3f4b79318 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -331,8 +331,8 @@ struct qemu_work_item; * @opaque: User data. * @mem_io_pc: Host Program Counter 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. + * @work_mutex: Lock to prevent multiple access to @work_list. + * @work_list: List of pending asynchronous work. * @trace_dstate_delayed: Delayed changes to trace_dstate (includes all changes * to @trace_dstate). * @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask). @@ -376,7 +376,7 @@ struct CPUState { sigjmp_buf jmp_env; QemuMutex work_mutex; - struct qemu_work_item *queued_work_first, *queued_work_last; + QSIMPLEQ_HEAD(, qemu_work_item) work_list; CPUAddressSpace *cpu_ases; int num_ases; From 4384a70d0188a356d85a80c62ae88ec5aef8b3ee Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Jun 2020 20:02:25 +0100 Subject: [PATCH 1312/2595] thread: add qemu_spin_destroy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will be used for TSAN annotations. Signed-off-by: Emilio G. Cota Signed-off-by: Robert Foley Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-4-robert.foley@linaro.org> Message-Id: <20200612190237.30436-7-alex.bennee@linaro.org> --- include/qemu/thread.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/qemu/thread.h b/include/qemu/thread.h index 06c058fb58..9479facdcc 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -215,6 +215,9 @@ static inline void qemu_spin_init(QemuSpin *spin) __sync_lock_release(&spin->value); } +static inline void qemu_spin_destroy(QemuSpin *spin) +{ } + static inline void qemu_spin_lock(QemuSpin *spin) { while (unlikely(__sync_lock_test_and_set(&spin->value, true))) { From 816d9be5ea31d848ee090eca4a2bf185bd609066 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Jun 2020 20:02:26 +0100 Subject: [PATCH 1313/2595] cputlb: destroy CPUTLB with tlb_destroy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I was after adding qemu_spin_destroy calls, but while at it I noticed that we are leaking some memory. Signed-off-by: Emilio G. Cota Signed-off-by: Robert Foley Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-5-robert.foley@linaro.org> Message-Id: <20200612190237.30436-8-alex.bennee@linaro.org> --- accel/tcg/cputlb.c | 15 +++++++++++++++ exec.c | 1 + include/exec/exec-all.h | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index eb2cf9de5e..1e815357c7 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -270,6 +270,21 @@ void tlb_init(CPUState *cpu) } } +void tlb_destroy(CPUState *cpu) +{ + CPUArchState *env = cpu->env_ptr; + int i; + + qemu_spin_destroy(&env_tlb(env)->c.lock); + for (i = 0; i < NB_MMU_MODES; i++) { + CPUTLBDesc *desc = &env_tlb(env)->d[i]; + CPUTLBDescFast *fast = &env_tlb(env)->f[i]; + + g_free(fast->table); + g_free(desc->iotlb); + } +} + /* flush_all_helper: run fn across all cpus * * If the wait flag is set then the src cpu's helper will be queued as diff --git a/exec.c b/exec.c index 9c8f558590..d6712fba7e 100644 --- a/exec.c +++ b/exec.c @@ -892,6 +892,7 @@ void cpu_exec_unrealizefn(CPUState *cpu) { CPUClass *cc = CPU_GET_CLASS(cpu); + tlb_destroy(cpu); cpu_list_remove(cpu); if (cc->vmsd != NULL) { diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 8792bea07a..3cf88272df 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -124,6 +124,11 @@ void cpu_address_space_init(CPUState *cpu, int asidx, * @cpu: CPU whose TLB should be initialized */ void tlb_init(CPUState *cpu); +/** + * tlb_destroy - destroy a CPU's TLB + * @cpu: CPU whose TLB should be destroyed + */ +void tlb_destroy(CPUState *cpu); /** * tlb_flush_page: * @cpu: CPU whose TLB should be flushed @@ -284,6 +289,9 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr, static inline void tlb_init(CPUState *cpu) { } +static inline void tlb_destroy(CPUState *cpu) +{ +} static inline void tlb_flush_page(CPUState *cpu, target_ulong addr) { } From 5107a47bb2bf3a7492db5f86cf02302f170a0bf0 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Jun 2020 20:02:27 +0100 Subject: [PATCH 1314/2595] qht: call qemu_spin_destroy for head buckets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Emilio G. Cota Signed-off-by: Robert Foley Reviewed-by: Alex Bennée [AJB: add implied cota s-o-b c.f. github.com/cota/qemu/tree/tsan @ 1bd1209] Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-6-robert.foley@linaro.org> Message-Id: <20200612190237.30436-9-alex.bennee@linaro.org> --- util/qht.c | 1 + 1 file changed, 1 insertion(+) diff --git a/util/qht.c b/util/qht.c index aa51be3c52..67e5d5b916 100644 --- a/util/qht.c +++ b/util/qht.c @@ -348,6 +348,7 @@ static inline void qht_chain_destroy(const struct qht_bucket *head) struct qht_bucket *curr = head->next; struct qht_bucket *prev; + qemu_spin_destroy(&head->lock); while (curr) { prev = curr; curr = curr->next; From 938e897a6615b63093881e8b58206f6f69212abe Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Jun 2020 20:02:28 +0100 Subject: [PATCH 1315/2595] tcg: call qemu_spin_destroy for tb->jmp_lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Emilio G. Cota Signed-off-by: Robert Foley Signed-off-by: Alex Bennée [RF: minor changes + remove tb_destroy_func] Message-Id: <20200609200738.445-7-robert.foley@linaro.org> Message-Id: <20200612190237.30436-10-alex.bennee@linaro.org> --- accel/tcg/translate-all.c | 8 ++++++++ include/tcg/tcg.h | 1 + tcg/tcg.c | 9 +++++++++ 3 files changed, 18 insertions(+) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 42ce1dfcff..c937210e21 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -384,6 +384,11 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, return 0; } +void tb_destroy(TranslationBlock *tb) +{ + qemu_spin_destroy(&tb->jmp_lock); +} + bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit) { TranslationBlock *tb; @@ -413,6 +418,7 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit) /* one-shot translation, invalidate it immediately */ tb_phys_invalidate(tb, -1); tcg_tb_remove(tb); + tb_destroy(tb); } r = true; } @@ -1886,6 +1892,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, orig_aligned -= ROUND_UP(sizeof(*tb), qemu_icache_linesize); atomic_set(&tcg_ctx->code_gen_ptr, (void *)orig_aligned); + tb_destroy(tb); return existing_tb; } tcg_tb_insert(tb); @@ -2235,6 +2242,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) tb_phys_invalidate(tb->orig_tb, -1); } tcg_tb_remove(tb); + tb_destroy(tb); } /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 380014ed80..e63450a893 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -819,6 +819,7 @@ void tcg_pool_reset(TCGContext *s); TranslationBlock *tcg_tb_alloc(TCGContext *s); void tcg_region_init(void); +void tb_destroy(TranslationBlock *tb); void tcg_region_reset_all(void); size_t tcg_code_size(void); diff --git a/tcg/tcg.c b/tcg/tcg.c index 1aa6cb47f2..1362bc6101 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -502,6 +502,14 @@ size_t tcg_nb_tbs(void) return nb_tbs; } +static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data) +{ + TranslationBlock *tb = v; + + tb_destroy(tb); + return FALSE; +} + static void tcg_region_tree_reset_all(void) { size_t i; @@ -510,6 +518,7 @@ static void tcg_region_tree_reset_all(void) for (i = 0; i < region.n; i++) { struct tcg_region_tree *rt = region_trees + i * tree_size; + g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL); /* Increment the refcount first so that destroy acts as a reset */ g_tree_ref(rt->tree); g_tree_destroy(rt->tree); From 3f640eb8812f92dfcc4947fc1e7cd9004456d58a Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Jun 2020 20:02:29 +0100 Subject: [PATCH 1316/2595] translate-all: call qemu_spin_destroy for PageDesc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The radix tree is append-only, but we can fail to insert a PageDesc if the insertion races with another thread. Signed-off-by: Emilio G. Cota Signed-off-by: Robert Foley Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-8-robert.foley@linaro.org> Message-Id: <20200612190237.30436-11-alex.bennee@linaro.org> --- accel/tcg/translate-all.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index c937210e21..c3d37058a1 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -547,6 +547,15 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc) #endif existing = atomic_cmpxchg(lp, NULL, pd); if (unlikely(existing)) { +#ifndef CONFIG_USER_ONLY + { + int i; + + for (i = 0; i < V_L2_SIZE; i++) { + qemu_spin_destroy(&pd[i].lock); + } + } +#endif g_free(pd); pd = existing; } From 45a9595a1b16666cdac1969469937b72cfb28129 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Jun 2020 20:02:30 +0100 Subject: [PATCH 1317/2595] thread: add tsan annotations to QemuSpin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Emilio G. Cota Signed-off-by: Robert Foley Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-9-robert.foley@linaro.org> Message-Id: <20200612190237.30436-12-alex.bennee@linaro.org> --- include/qemu/thread.h | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/include/qemu/thread.h b/include/qemu/thread.h index 9479facdcc..4baf4d1715 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -206,6 +206,10 @@ void qemu_thread_atexit_add(struct Notifier *notifier); */ void qemu_thread_atexit_remove(struct Notifier *notifier); +#ifdef CONFIG_TSAN +#include +#endif + struct QemuSpin { int value; }; @@ -213,23 +217,46 @@ struct QemuSpin { static inline void qemu_spin_init(QemuSpin *spin) { __sync_lock_release(&spin->value); +#ifdef CONFIG_TSAN + __tsan_mutex_create(spin, __tsan_mutex_not_static); +#endif } -static inline void qemu_spin_destroy(QemuSpin *spin) -{ } +/* const parameter because the only purpose here is the TSAN annotation */ +static inline void qemu_spin_destroy(const QemuSpin *spin) +{ +#ifdef CONFIG_TSAN + __tsan_mutex_destroy((void *)spin, __tsan_mutex_not_static); +#endif +} static inline void qemu_spin_lock(QemuSpin *spin) { +#ifdef CONFIG_TSAN + __tsan_mutex_pre_lock(spin, 0); +#endif while (unlikely(__sync_lock_test_and_set(&spin->value, true))) { while (atomic_read(&spin->value)) { cpu_relax(); } } +#ifdef CONFIG_TSAN + __tsan_mutex_post_lock(spin, 0, 0); +#endif } static inline bool qemu_spin_trylock(QemuSpin *spin) { - return __sync_lock_test_and_set(&spin->value, true); +#ifdef CONFIG_TSAN + __tsan_mutex_pre_lock(spin, __tsan_mutex_try_lock); +#endif + bool busy = __sync_lock_test_and_set(&spin->value, true); +#ifdef CONFIG_TSAN + unsigned flags = __tsan_mutex_try_lock; + flags |= busy ? __tsan_mutex_try_lock_failed : 0; + __tsan_mutex_post_lock(spin, flags, 0); +#endif + return busy; } static inline bool qemu_spin_locked(QemuSpin *spin) @@ -239,7 +266,13 @@ static inline bool qemu_spin_locked(QemuSpin *spin) static inline void qemu_spin_unlock(QemuSpin *spin) { +#ifdef CONFIG_TSAN + __tsan_mutex_pre_unlock(spin, 0); +#endif __sync_lock_release(&spin->value); +#ifdef CONFIG_TSAN + __tsan_mutex_post_unlock(spin, 0); +#endif } struct QemuLockCnt { From df79fd5667fb99c6fdfa0d295cb020e9e3eef1e7 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Fri, 12 Jun 2020 20:02:31 +0100 Subject: [PATCH 1318/2595] tests/docker: Added docker build support for TSan. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a new docker for ubuntu 20.04. This docker has support for Thread Sanitizer including one patch we need in one of the header files. https://github.com/llvm/llvm-project/commit/a72dc86cd This command will build with tsan enabled: make docker-test-tsan-ubuntu2004 V=1 Also added the TSAN suppresion file to disable certain cases of TSAN warnings. Cc: Fam Zheng Cc: Philippe Mathieu-Daudé Signed-off-by: Robert Foley Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-10-robert.foley@linaro.org> Message-Id: <20200612190237.30436-13-alex.bennee@linaro.org> --- tests/docker/dockerfiles/ubuntu2004.docker | 65 ++++++++++++++++++++++ tests/docker/test-tsan | 44 +++++++++++++++ tests/tsan/blacklist.tsan | 10 ++++ tests/tsan/suppressions.tsan | 14 +++++ 4 files changed, 133 insertions(+) create mode 100644 tests/docker/dockerfiles/ubuntu2004.docker create mode 100755 tests/docker/test-tsan create mode 100644 tests/tsan/blacklist.tsan create mode 100644 tests/tsan/suppressions.tsan diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker new file mode 100644 index 0000000000..6050ce7e8a --- /dev/null +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -0,0 +1,65 @@ +FROM ubuntu:20.04 +ENV PACKAGES flex bison \ + ccache \ + clang-10\ + gcc \ + gettext \ + git \ + glusterfs-common \ + libaio-dev \ + libattr1-dev \ + libbrlapi-dev \ + libbz2-dev \ + libcacard-dev \ + libcap-ng-dev \ + libcurl4-gnutls-dev \ + libdrm-dev \ + libepoxy-dev \ + libfdt-dev \ + libgbm-dev \ + libgtk-3-dev \ + libibverbs-dev \ + libiscsi-dev \ + libjemalloc-dev \ + libjpeg-turbo8-dev \ + liblzo2-dev \ + libncurses5-dev \ + libncursesw5-dev \ + libnfs-dev \ + libnss3-dev \ + libnuma-dev \ + libpixman-1-dev \ + librados-dev \ + librbd-dev \ + librdmacm-dev \ + libsasl2-dev \ + libsdl2-dev \ + libseccomp-dev \ + libsnappy-dev \ + libspice-protocol-dev \ + libspice-server-dev \ + libssh-dev \ + libusb-1.0-0-dev \ + libusbredirhost-dev \ + libvdeplug-dev \ + libvte-2.91-dev \ + libxen-dev \ + libzstd-dev \ + make \ + python3-yaml \ + python3-sphinx \ + sparse \ + texinfo \ + xfslibs-dev\ + vim +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES +RUN dpkg -l $PACKAGES | sort > /packages.txt +ENV FEATURES clang tsan pyyaml sdl2 + +# https://bugs.launchpad.net/qemu/+bug/1838763 +ENV QEMU_CONFIGURE_OPTS --disable-libssh + +# Apply patch https://reviews.llvm.org/D75820 +# This is required for TSan in clang-10 to compile with QEMU. +RUN sed -i 's/^const/static const/g' /usr/lib/llvm-10/lib/clang/10.0.0/include/sanitizer/tsan_interface.h diff --git a/tests/docker/test-tsan b/tests/docker/test-tsan new file mode 100755 index 0000000000..eb40ac45b7 --- /dev/null +++ b/tests/docker/test-tsan @@ -0,0 +1,44 @@ +#!/bin/bash -e +# +# This test will use TSan as part of a build and a make check. +# +# Copyright (c) 2020 Linaro +# Copyright (c) 2016 Red Hat Inc. +# +# Authors: +# Robert Foley +# Originally based on test-quick from Fam Zheng +# +# This work is licensed under the terms of the GNU GPL, version 2 +# or (at your option) any later version. See the COPYING file in +# the top-level directory. + +. common.rc + +setup_tsan() +{ + requires clang tsan + tsan_log_dir="/tmp/qemu-test/build/tsan" + mkdir -p $tsan_log_dir > /dev/null || true + EXTRA_CONFIGURE_OPTS="${EXTRA_CONFIGURE_OPTS} --enable-tsan \ + --cc=clang-10 --cxx=clang++-10 \ + --disable-werror --extra-cflags=-O0" + # detect deadlocks is false currently simply because + # TSan crashes immediately with deadlock detector enabled. + # We have maxed out the history size to get the best chance of finding + # warnings during testing. + # Note, to get TSan to fail on warning, use exitcode=66 below. + tsan_opts="suppressions=/tmp/qemu-test/src/tests/tsan/suppressions.tsan\ + detect_deadlocks=false history_size=7\ + halt_on_error=0 exitcode=0 verbose=5\ + log_path=$tsan_log_dir/tsan_warning" + export TSAN_OPTIONS="$tsan_opts" +} + +cd "$BUILD_DIR" + +TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \ +setup_tsan +build_qemu +check_qemu +install_qemu diff --git a/tests/tsan/blacklist.tsan b/tests/tsan/blacklist.tsan new file mode 100644 index 0000000000..75e444f5dc --- /dev/null +++ b/tests/tsan/blacklist.tsan @@ -0,0 +1,10 @@ +# This is an example blacklist. +# To enable use of the blacklist add this to configure: +# "--extra-cflags=-fsanitize-blacklist=/tests/tsan/blacklist.tsan" +# The eventual goal would be to fix these warnings. + +# TSan is not happy about setting/getting of dirty bits, +# for example, cpu_physical_memory_set_dirty_range, +# and cpu_physical_memory_get_dirty. +src:bitops.c +src:bitmap.c diff --git a/tests/tsan/suppressions.tsan b/tests/tsan/suppressions.tsan new file mode 100644 index 0000000000..73414b9ebd --- /dev/null +++ b/tests/tsan/suppressions.tsan @@ -0,0 +1,14 @@ +# This is the set of runtime suppressions of TSan warnings. +# The goal would be to have here only items we do not +# plan to fix, and to explain why for each item. + +# TSan reports a double lock on RECURSIVE mutexes. +# Since the recursive lock is intentional, we choose to ignore it. +mutex:aio_context_acquire +mutex:pthread_mutex_lock + +# TSan reports a race betwen pthread_mutex_init() and +# pthread_mutex_lock(). Since this is outside of QEMU, +# we choose to ignore it. +race:pthread_mutex_init +race:pthread_mutex_lock From e51345eea9057c2a2098322df9e9797cd4bc7f8d Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Fri, 12 Jun 2020 20:02:32 +0100 Subject: [PATCH 1319/2595] include/qemu: Added tsan.h for annotations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These annotations will allow us to give tsan additional hints. For example, we can inform tsan about reads/writes to ignore to silence certain classes of warnings. We can also annotate threads so that the proper thread naming shows up in tsan warning results. Signed-off-by: Robert Foley Reviewed-by: Emilio G. Cota Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-11-robert.foley@linaro.org> Message-Id: <20200612190237.30436-14-alex.bennee@linaro.org> --- include/qemu/tsan.h | 71 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 include/qemu/tsan.h diff --git a/include/qemu/tsan.h b/include/qemu/tsan.h new file mode 100644 index 0000000000..09cc665f91 --- /dev/null +++ b/include/qemu/tsan.h @@ -0,0 +1,71 @@ +#ifndef QEMU_TSAN_H +#define QEMU_TSAN_H +/* + * tsan.h + * + * This file defines macros used to give ThreadSanitizer + * additional information to help suppress warnings. + * This is necessary since TSan does not provide a header file + * for these annotations. The standard way to include these + * is via the below macros. + * + * Annotation examples can be found here: + * https://github.com/llvm/llvm-project/tree/master/compiler-rt/test/tsan + * annotate_happens_before.cpp or ignore_race.cpp are good places to start. + * + * The full set of annotations can be found here in tsan_interface_ann.cpp. + * https://github.com/llvm/llvm-project/blob/master/compiler-rt/lib/tsan/rtl/ + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifdef CONFIG_TSAN +/* + * Informs TSan of a happens before/after relationship. + */ +#define QEMU_TSAN_ANNOTATE_HAPPENS_BEFORE(addr) \ + AnnotateHappensBefore(__FILE__, __LINE__, (void *)(addr)) +#define QEMU_TSAN_ANNOTATE_HAPPENS_AFTER(addr) \ + AnnotateHappensAfter(__FILE__, __LINE__, (void *)(addr)) +/* + * Gives TSan more information about thread names it can report the + * name of the thread in the warning report. + */ +#define QEMU_TSAN_ANNOTATE_THREAD_NAME(name) \ + AnnotateThreadName(__FILE__, __LINE__, (void *)(name)) +/* + * Allows defining a region of code on which TSan will not record memory READS. + * This has the effect of disabling race detection for this section of code. + */ +#define QEMU_TSAN_ANNOTATE_IGNORE_READS_BEGIN() \ + AnnotateIgnoreReadsBegin(__FILE__, __LINE__) +#define QEMU_TSAN_ANNOTATE_IGNORE_READS_END() \ + AnnotateIgnoreReadsEnd(__FILE__, __LINE__) +/* + * Allows defining a region of code on which TSan will not record memory + * WRITES. This has the effect of disabling race detection for this + * section of code. + */ +#define QEMU_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN() \ + AnnotateIgnoreWritesBegin(__FILE__, __LINE__) +#define QEMU_TSAN_ANNOTATE_IGNORE_WRITES_END() \ + AnnotateIgnoreWritesEnd(__FILE__, __LINE__) +#else +#define QEMU_TSAN_ANNOTATE_HAPPENS_BEFORE(addr) +#define QEMU_TSAN_ANNOTATE_HAPPENS_AFTER(addr) +#define QEMU_TSAN_ANNOTATE_THREAD_NAME(name) +#define QEMU_TSAN_ANNOTATE_IGNORE_READS_BEGIN() +#define QEMU_TSAN_ANNOTATE_IGNORE_READS_END() +#define QEMU_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN() +#define QEMU_TSAN_ANNOTATE_IGNORE_WRITES_END() +#endif + +void AnnotateHappensBefore(const char *f, int l, void *addr); +void AnnotateHappensAfter(const char *f, int l, void *addr); +void AnnotateThreadName(const char *f, int l, char *name); +void AnnotateIgnoreReadsBegin(const char *f, int l); +void AnnotateIgnoreReadsEnd(const char *f, int l); +void AnnotateIgnoreWritesBegin(const char *f, int l); +void AnnotateIgnoreWritesEnd(const char *f, int l); +#endif From ce9f0e5b26eb0f37329d27f5f2e3e453ac0acabc Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Fri, 12 Jun 2020 20:02:33 +0100 Subject: [PATCH 1320/2595] util: Added tsan annotate for thread name. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to see the name of the thread in tsan warning reports such as this: Thread T7 'CPU 1/TCG' (tid=24317, running) created by main thread at: Signed-off-by: Robert Foley Reviewed-by: Emilio G. Cota Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-12-robert.foley@linaro.org> Message-Id: <20200612190237.30436-15-alex.bennee@linaro.org> --- util/qemu-thread-posix.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index 838980aaa5..b4c2359272 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -15,6 +15,7 @@ #include "qemu/atomic.h" #include "qemu/notify.h" #include "qemu-thread-common.h" +#include "qemu/tsan.h" static bool name_threads; @@ -513,6 +514,7 @@ static void *qemu_thread_start(void *args) # endif } #endif + QEMU_TSAN_ANNOTATE_THREAD_NAME(qemu_thread_args->name); g_free(qemu_thread_args->name); g_free(qemu_thread_args); pthread_cleanup_push(qemu_thread_atexit_notify, NULL); From 3b6882bd96c7913725831bef116fb5a91b327e90 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Fri, 12 Jun 2020 20:02:34 +0100 Subject: [PATCH 1321/2595] docs: Added details on TSan to testing.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds TSan details to testing.rst. This includes background and reference details on TSan, and details on how to build and test with TSan both with and without docker. Signed-off-by: Robert Foley Reviewed-by: Emilio G. Cota Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-13-robert.foley@linaro.org> Message-Id: <20200612190237.30436-16-alex.bennee@linaro.org> --- docs/devel/testing.rst | 107 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index 770a987ea4..c1ff24370b 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -397,6 +397,113 @@ list is in the ``make docker`` help text. The frequently used ones are: * ``DEBUG=1``: enables debug. See the previous "Debugging a Docker test failure" section. +Thread Sanitizer +================ + +Thread Sanitizer (TSan) is a tool which can detect data races. QEMU supports +building and testing with this tool. + +For more information on TSan: + +https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual + +Thread Sanitizer in Docker +--------------------------- +TSan is currently supported in the ubuntu2004 docker. + +The test-tsan test will build using TSan and then run make check. + +.. code:: + + make docker-test-tsan@ubuntu2004 + +TSan warnings under docker are placed in files located at build/tsan/. + +We recommend using DEBUG=1 to allow launching the test from inside the docker, +and to allow review of the warnings generated by TSan. + +Building and Testing with TSan +------------------------------ + +It is possible to build and test with TSan, with a few additional steps. +These steps are normally done automatically in the docker. + +There is a one time patch needed in clang-9 or clang-10 at this time: + +.. code:: + + sed -i 's/^const/static const/g' \ + /usr/lib/llvm-10/lib/clang/10.0.0/include/sanitizer/tsan_interface.h + +To configure the build for TSan: + +.. code:: + + ../configure --enable-tsan --cc=clang-10 --cxx=clang++-10 \ + --disable-werror --extra-cflags="-O0" + +The runtime behavior of TSAN is controlled by the TSAN_OPTIONS environment +variable. + +More information on the TSAN_OPTIONS can be found here: + +https://github.com/google/sanitizers/wiki/ThreadSanitizerFlags + +For example: + +.. code:: + + export TSAN_OPTIONS=suppressions=/tests/tsan/suppressions.tsan \ + detect_deadlocks=false history_size=7 exitcode=0 \ + log_path=/tsan/tsan_warning + +The above exitcode=0 has TSan continue without error if any warnings are found. +This allows for running the test and then checking the warnings afterwards. +If you want TSan to stop and exit with error on warnings, use exitcode=66. + +TSan Suppressions +----------------- +Keep in mind that for any data race warning, although there might be a data race +detected by TSan, there might be no actual bug here. TSan provides several +different mechanisms for suppressing warnings. In general it is recommended +to fix the code if possible to eliminate the data race rather than suppress +the warning. + +A few important files for suppressing warnings are: + +tests/tsan/suppressions.tsan - Has TSan warnings we wish to suppress at runtime. +The comment on each supression will typically indicate why we are +suppressing it. More information on the file format can be found here: + +https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions + +tests/tsan/blacklist.tsan - Has TSan warnings we wish to disable +at compile time for test or debug. +Add flags to configure to enable: + +"--extra-cflags=-fsanitize-blacklist=/tests/tsan/blacklist.tsan" + +More information on the file format can be found here under "Blacklist Format": + +https://github.com/google/sanitizers/wiki/ThreadSanitizerFlags + +TSan Annotations +---------------- +include/qemu/tsan.h defines annotations. See this file for more descriptions +of the annotations themselves. Annotations can be used to suppress +TSan warnings or give TSan more information so that it can detect proper +relationships between accesses of data. + +Annotation examples can be found here: + +https://github.com/llvm/llvm-project/tree/master/compiler-rt/test/tsan/ + +Good files to start with are: annotate_happens_before.cpp and ignore_race.cpp + +The full set of annotations can be found here: + +https://github.com/llvm/llvm-project/blob/master/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cpp + VM testing ========== From ff8f63da5c11d9c9884c1aafc6320e51d64666e4 Mon Sep 17 00:00:00 2001 From: Robert Foley Date: Fri, 12 Jun 2020 20:02:35 +0100 Subject: [PATCH 1322/2595] tests: Disable select tests under TSan, which hit TSan issue. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disable a few tests under CONFIG_TSAN, which run into a known TSan issue that results in a hang. https://github.com/google/sanitizers/issues/1116 The disabled tests under TSan include all the qtests as well as the test-char, test-qga, and test-qdev-global-props. Signed-off-by: Robert Foley Reviewed-by: Emilio G. Cota Signed-off-by: Alex Bennée Message-Id: <20200609200738.445-14-robert.foley@linaro.org> Message-Id: <20200612190237.30436-17-alex.bennee@linaro.org> --- tests/Makefile.include | 9 +++++++-- tests/qtest/Makefile.include | 7 +++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 5607c7290d..3f4448a20b 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -55,7 +55,6 @@ SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \ check-unit-y += tests/check-qdict$(EXESUF) check-unit-y += tests/check-block-qdict$(EXESUF) -check-unit-$(CONFIG_SOFTMMU) += tests/test-char$(EXESUF) check-unit-y += tests/check-qnum$(EXESUF) check-unit-y += tests/check-qstring$(EXESUF) check-unit-y += tests/check-qlist$(EXESUF) @@ -108,7 +107,6 @@ check-unit-y += tests/test-qht$(EXESUF) check-unit-y += tests/test-qht-par$(EXESUF) check-unit-y += tests/test-bitops$(EXESUF) check-unit-y += tests/test-bitcnt$(EXESUF) -check-unit-$(CONFIG_SOFTMMU) += tests/test-qdev-global-props$(EXESUF) check-unit-y += tests/check-qom-interface$(EXESUF) check-unit-y += tests/check-qom-proplist$(EXESUF) check-unit-y += tests/test-qemu-opts$(EXESUF) @@ -123,9 +121,16 @@ check-speed-$(CONFIG_BLOCK) += tests/benchmark-crypto-cipher$(EXESUF) check-unit-$(CONFIG_BLOCK) += tests/test-crypto-secret$(EXESUF) check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_GNUTLS)) += tests/test-crypto-tlscredsx509$(EXESUF) check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_GNUTLS)) += tests/test-crypto-tlssession$(EXESUF) +ifndef CONFIG_TSAN +# Some tests: test-char, test-qdev-global-props, and test-qga, +# are not runnable under TSan due to a known issue. +# https://github.com/google/sanitizers/issues/1116 +check-unit-$(CONFIG_SOFTMMU) += tests/test-char$(EXESUF) +check-unit-$(CONFIG_SOFTMMU) += tests/test-qdev-global-props$(EXESUF) ifneq (,$(findstring qemu-ga,$(TOOLS))) check-unit-$(call land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF) endif +endif check-unit-$(CONFIG_SOFTMMU) += tests/test-timed-average$(EXESUF) check-unit-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_INOTIFY1)) += tests/test-util-filemonitor$(EXESUF) check-unit-$(CONFIG_SOFTMMU) += tests/test-util-sockets$(EXESUF) diff --git a/tests/qtest/Makefile.include b/tests/qtest/Makefile.include index 5023fa413d..98af2c2d93 100644 --- a/tests/qtest/Makefile.include +++ b/tests/qtest/Makefile.include @@ -314,12 +314,15 @@ tests/qtest/tpm-tis-device-test$(EXESUF): tests/qtest/tpm-tis-device-test.o test # QTest rules TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS))) +QTEST_TARGETS = +# The qtests are not runnable (yet) under TSan due to a known issue. +# https://github.com/google/sanitizers/issues/1116 +ifndef CONFIG_TSAN ifeq ($(CONFIG_POSIX),y) QTEST_TARGETS = $(TARGETS) check-qtest-y=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y:%=tests/qtest/%$(EXESUF))) check-qtest-y += $(check-qtest-generic-y:%=tests/qtest/%$(EXESUF)) -else -QTEST_TARGETS = +endif endif qtest-obj-y = tests/qtest/libqtest.o $(test-util-obj-y) From 8cb14dbb8df0970143cf287661cb446abc697377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 12 Jun 2020 20:02:36 +0100 Subject: [PATCH 1323/2595] Revert ".shippable: temporaily disable some cross builds" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 12d43b5ae916809aad9ccf8aa2a0a06260527340. Signed-off-by: Alex Bennée Message-Id: <20200612190237.30436-18-alex.bennee@linaro.org> --- .shippable.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.shippable.yml b/.shippable.yml index 10cf219bff..2cce7b5689 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -5,8 +5,8 @@ env: global: - LC_ALL=C matrix: - # - IMAGE=debian-amd64 - # TARGET_LIST=x86_64-softmmu,x86_64-linux-user + - IMAGE=debian-amd64 + TARGET_LIST=x86_64-softmmu,x86_64-linux-user - IMAGE=debian-win32-cross TARGET_LIST=arm-softmmu,i386-softmmu,lm32-softmmu - IMAGE=debian-win64-cross @@ -19,10 +19,10 @@ env: TARGET_LIST=aarch64-softmmu,aarch64-linux-user - IMAGE=debian-s390x-cross TARGET_LIST=s390x-softmmu,s390x-linux-user - # - IMAGE=debian-mips-cross - # TARGET_LIST=mips-softmmu,mipsel-linux-user - # - IMAGE=debian-mips64el-cross - # TARGET_LIST=mips64el-softmmu,mips64el-linux-user + - IMAGE=debian-mips-cross + TARGET_LIST=mips-softmmu,mipsel-linux-user + - IMAGE=debian-mips64el-cross + TARGET_LIST=mips64el-softmmu,mips64el-linux-user - IMAGE=debian-ppc64el-cross TARGET_LIST=ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user build: From 7e1236148c343f9189aa937eef97d42e2c8a00d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 12 Jun 2020 20:02:37 +0100 Subject: [PATCH 1324/2595] cirrus.yml: serialise make check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do this on our other platforms to make it easier to see what has broken. Signed-off-by: Alex Bennée Reviewed-by: Li-Wen Hsu Message-Id: <20200612190237.30436-19-alex.bennee@linaro.org> --- .cirrus.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index ce7850a320..69342ae031 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -14,7 +14,7 @@ freebsd_12_task: - cd build - ../configure || { cat config.log; exit 1; } - gmake -j8 - - gmake -j8 V=1 check + - gmake V=1 check macos_task: osx_instance: @@ -26,7 +26,7 @@ macos_task: - cd build - ../configure --python=/usr/local/bin/python3 || { cat config.log; exit 1; } - gmake -j$(sysctl -n hw.ncpu) - - gmake check -j$(sysctl -n hw.ncpu) + - gmake check macos_xcode_task: osx_instance: @@ -39,4 +39,4 @@ macos_xcode_task: - cd build - ../configure --cc=clang || { cat config.log; exit 1; } - gmake -j$(sysctl -n hw.ncpu) - - gmake check -j$(sysctl -n hw.ncpu) + - gmake check From fefa0271544146e027cd682cf483223ee2f37e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 15 Jun 2020 15:19:21 +0100 Subject: [PATCH 1325/2595] tests/tcg: build plugin list from contents of src directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If you jump back and forth between branches while developing plugins you end up debugging failures caused by plugins left in the build directory. Fix this by basing plugins on the source tree instead. Signed-off-by: Alex Bennée Message-Id: <20200615141922.18829-2-alex.bennee@linaro.org> --- tests/tcg/Makefile.target | 11 ++++++----- tests/tcg/aarch64/Makefile.target | 2 +- tests/tcg/arm/Makefile.target | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target index b3cff3cad1..2ae86776cd 100644 --- a/tests/tcg/Makefile.target +++ b/tests/tcg/Makefile.target @@ -126,9 +126,10 @@ RUN_TESTS=$(patsubst %,run-%, $(TESTS)) # If plugins exist also include those in the tests ifeq ($(CONFIG_PLUGIN),y) -PLUGIN_DIR=../../plugin -VPATH+=$(PLUGIN_DIR) -PLUGINS=$(notdir $(wildcard $(PLUGIN_DIR)/*.so)) +PLUGIN_SRC=$(SRC_PATH)/tests/plugin +PLUGIN_LIB=../../plugin +VPATH+=$(PLUGIN_LIB) +PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c))) # We need to ensure expand the run-plugin-TEST-with-PLUGIN # pre-requistes manually here as we can't use stems to handle it. We @@ -152,7 +153,7 @@ run-%: % run-plugin-%: $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ - -plugin $(PLUGIN_DIR)/$(call extract-plugin,$@) \ + -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \ -d plugin -D $*.pout \ $(call strip-plugin,$<), \ "$* on $(TARGET_NAME)") @@ -168,7 +169,7 @@ run-plugin-%: $(call run-test, $@, \ $(QEMU) -monitor none -display none \ -chardev file$(COMMA)path=$@.out$(COMMA)id=output \ - -plugin $(PLUGIN_DIR)/$(call extract-plugin,$@) \ + -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \ -d plugin -D $*.pout \ $(QEMU_OPTS) $(call strip-plugin,$<), \ "$* on $(TARGET_NAME)") diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index 312f36cde5..6d60a2f2ee 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -31,7 +31,7 @@ run-semihosting: semihosting run-plugin-semihosting-with-%: $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ - -plugin $(PLUGIN_DIR)/$(call extract-plugin,$@) \ + -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \ $(call strip-plugin,$<) 2> $<.err, \ "$< on $(TARGET_NAME) with $*") diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target index 3da09a38be..ec95156562 100644 --- a/tests/tcg/arm/Makefile.target +++ b/tests/tcg/arm/Makefile.target @@ -45,7 +45,7 @@ run-semihosting-arm: semihosting-arm run-plugin-semihosting-with-%: $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ - -plugin $(PLUGIN_DIR)/$(call extract-plugin,$@) \ + -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \ $(call strip-plugin,$<) 2> $<.err, \ "$< on $(TARGET_NAME) with $*") From d16242e524a47d2c3e0281951c6d27979992ac3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 15 Jun 2020 15:19:22 +0100 Subject: [PATCH 1326/2595] tests/tcg: ensure -cpu max also used for plugin run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The check-tcg plugins build was failing because some special case tests that needed -cpu max failed because the plugin variant hadn't carried across the QEMU_OPTS tweak. Guests which globally set QEMU_OPTS=-cpu FOO where unaffected. Signed-off-by: Alex Bennée Message-Id: <20200615141922.18829-3-alex.bennee@linaro.org> --- tests/tcg/aarch64/Makefile.target | 3 ++- tests/tcg/i386/Makefile.target | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index 6d60a2f2ee..b617f2ac7e 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -20,8 +20,9 @@ run-fcvt: fcvt # Pauth Tests ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_3),) AARCH64_TESTS += pauth-1 pauth-2 pauth-4 -run-pauth-%: QEMU_OPTS += -cpu max pauth-%: CFLAGS += -march=armv8.3-a +run-pauth-%: QEMU_OPTS += -cpu max +run-plugin-pauth-%: QEMU_OPTS += -cpu max endif # Semihosting smoke test for linux-user diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index 53efec0668..1a6463a7dc 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -12,6 +12,7 @@ X86_64_TESTS:=$(filter test-i386-ssse3, $(ALL_X86_TESTS)) test-i386-pcmpistri: CFLAGS += -msse4.2 run-test-i386-pcmpistri: QEMU_OPTS += -cpu max +run-plugin-test-i386-pcmpistri-%: QEMU_OPTS += -cpu max # # hello-i386 is a barebones app From c81950a2f1923dec3f6b952ec6bb9b921be58a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 10 Jun 2020 16:55:05 +0100 Subject: [PATCH 1327/2595] plugins: new lockstep plugin for debugging TCG changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we make changes to the TCG we sometimes cause regressions that are deep into the execution cycle of the guest. Debugging this often requires comparing large volumes of trace information to figure out where behaviour has diverged. The lockstep plugin utilises a shared socket so two QEMU's running with the plugin will write their current execution position and wait to receive the position of their partner process. When execution diverges the plugins output where they were and the previous few blocks before unloading themselves and letting execution continue. Originally I planned for this to be most useful with -icount but it turns out you can get divergence pretty quickly due to asynchronous qemu_cpu_kick_rr_cpus() events causing one side to eventually run into a short block a few cycles before the other side. For this reason I've added a bit of tracking and I think the divergence reporting could be finessed to report only if we really start to diverge in execution. An example run would be: qemu-system-sparc -monitor none -parallel none -net none \ -M SS-20 -m 256 -kernel day11/zImage.elf \ -plugin ./tests/plugin/liblockstep.so,arg=lockstep-sparc.sock \ -d plugin,nochain with an identical command in another window in the same working directory. Signed-off-by: Alex Bennée Reviewed-by: Robert Foley Tested-by: Robert Foley Cc: Richard Henderson Cc: Mark Cave-Ayland Message-Id: <20200610155509.12850-3-alex.bennee@linaro.org> --- tests/plugin/Makefile | 1 + tests/plugin/lockstep.c | 340 ++++++++++++++++++++++++++++++++++++++ tests/tcg/Makefile.target | 3 +- 3 files changed, 343 insertions(+), 1 deletion(-) create mode 100644 tests/plugin/lockstep.c diff --git a/tests/plugin/Makefile b/tests/plugin/Makefile index 75467b6db8..b3250e2504 100644 --- a/tests/plugin/Makefile +++ b/tests/plugin/Makefile @@ -13,6 +13,7 @@ NAMES += mem NAMES += hotblocks NAMES += howvec NAMES += hotpages +NAMES += lockstep SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES))) diff --git a/tests/plugin/lockstep.c b/tests/plugin/lockstep.c new file mode 100644 index 0000000000..a696673dff --- /dev/null +++ b/tests/plugin/lockstep.c @@ -0,0 +1,340 @@ +/* + * Lockstep Execution Plugin + * + * Allows you to execute two QEMU instances in lockstep and report + * when their execution diverges. This is mainly useful for developers + * who want to see where a change to TCG code generation has + * introduced a subtle and hard to find bug. + * + * Caveats: + * - single-threaded linux-user apps only with non-deterministic syscalls + * - no MTTCG enabled system emulation (icount may help) + * + * While icount makes things more deterministic it doesn't mean a + * particular run may execute the exact same sequence of blocks. An + * asynchronous event (for example X11 graphics update) may cause a + * block to end early and a new partial block to start. This means + * serial only test cases are a better bet. -d nochain may also help. + * + * This code is not thread safe! + * + * Copyright (c) 2020 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + +/* saved so we can uninstall later */ +static qemu_plugin_id_t our_id; + +static unsigned long bb_count; +static unsigned long insn_count; + +/* Information about a translated block */ +typedef struct { + uint64_t pc; + uint64_t insns; +} BlockInfo; + +/* Information about an execution state in the log */ +typedef struct { + BlockInfo *block; + unsigned long insn_count; + unsigned long block_count; +} ExecInfo; + +/* The execution state we compare */ +typedef struct { + uint64_t pc; + unsigned long insn_count; +} ExecState; + +typedef struct { + GSList *log_pos; + int distance; +} DivergeState; + +/* list of translated block info */ +static GSList *blocks; + +/* execution log and points of divergence */ +static GSList *log, *divergence_log; + +static int socket_fd; +static char *path_to_unlink; + +static bool verbose; + +static void plugin_cleanup(qemu_plugin_id_t id) +{ + /* Free our block data */ + g_slist_free_full(blocks, &g_free); + g_slist_free_full(log, &g_free); + g_slist_free(divergence_log); + + close(socket_fd); + if (path_to_unlink) { + unlink(path_to_unlink); + } +} + +static void plugin_exit(qemu_plugin_id_t id, void *p) +{ + g_autoptr(GString) out = g_string_new("No divergence :-)\n"); + g_string_append_printf(out, "Executed %ld/%d blocks\n", + bb_count, g_slist_length(log)); + g_string_append_printf(out, "Executed ~%ld instructions\n", insn_count); + qemu_plugin_outs(out->str); + + plugin_cleanup(id); +} + +static void report_divergance(ExecState *us, ExecState *them) +{ + DivergeState divrec = { log, 0 }; + g_autoptr(GString) out = g_string_new(""); + bool diverged = false; + + /* + * If we have diverged before did we get back on track or are we + * totally loosing it? + */ + if (divergence_log) { + DivergeState *last = (DivergeState *) divergence_log->data; + GSList *entry; + + for (entry = log; g_slist_next(entry); entry = g_slist_next(entry)) { + if (entry == last->log_pos) { + break; + } + divrec.distance++; + } + + /* + * If the last two records are so close it is likely we will + * not recover synchronisation with the other end. + */ + if (divrec.distance == 1 && last->distance == 1) { + diverged = true; + } + } + divergence_log = g_slist_prepend(divergence_log, + g_memdup(&divrec, sizeof(divrec))); + + /* Output short log entry of going out of sync... */ + if (verbose || divrec.distance == 1 || diverged) { + g_string_printf(out, "@ %#016lx vs %#016lx (%d/%d since last)\n", + us->pc, them->pc, g_slist_length(divergence_log), + divrec.distance); + qemu_plugin_outs(out->str); + } + + if (diverged) { + int i; + GSList *entry; + + g_string_printf(out, "Δ insn_count @ %#016lx (%ld) vs %#016lx (%ld)\n", + us->pc, us->insn_count, them->pc, them->insn_count); + + for (entry = log, i = 0; + g_slist_next(entry) && i < 5; + entry = g_slist_next(entry), i++) { + ExecInfo *prev = (ExecInfo *) entry->data; + g_string_append_printf(out, + " previously @ %#016lx/%ld (%ld insns)\n", + prev->block->pc, prev->block->insns, + prev->insn_count); + } + qemu_plugin_outs(out->str); + qemu_plugin_outs("too much divergence... giving up."); + qemu_plugin_uninstall(our_id, plugin_cleanup); + } +} + +static void vcpu_tb_exec(unsigned int cpu_index, void *udata) +{ + BlockInfo *bi = (BlockInfo *) udata; + ExecState us, them; + ssize_t bytes; + ExecInfo *exec; + + us.pc = bi->pc; + us.insn_count = insn_count; + + /* + * Write our current position to the other end. If we fail the + * other end has probably died and we should shut down gracefully. + */ + bytes = write(socket_fd, &us, sizeof(ExecState)); + if (bytes < sizeof(ExecState)) { + qemu_plugin_outs(bytes < 0 ? + "problem writing to socket" : + "wrote less than expected to socket"); + qemu_plugin_uninstall(our_id, plugin_cleanup); + return; + } + + /* + * Now read where our peer has reached. Again a failure probably + * indicates the other end died and we should close down cleanly. + */ + bytes = read(socket_fd, &them, sizeof(ExecState)); + if (bytes < sizeof(ExecState)) { + qemu_plugin_outs(bytes < 0 ? + "problem reading from socket" : + "read less than expected"); + qemu_plugin_uninstall(our_id, plugin_cleanup); + return; + } + + /* + * Compare and report if we have diverged. + */ + if (us.pc != them.pc) { + report_divergance(&us, &them); + } + + /* + * Assume this block will execute fully and record it + * in the execution log. + */ + insn_count += bi->insns; + bb_count++; + exec = g_new0(ExecInfo, 1); + exec->block = bi; + exec->insn_count = insn_count; + exec->block_count = bb_count; + log = g_slist_prepend(log, exec); +} + +static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) +{ + BlockInfo *bi = g_new0(BlockInfo, 1); + bi->pc = qemu_plugin_tb_vaddr(tb); + bi->insns = qemu_plugin_tb_n_insns(tb); + + /* save a reference so we can free later */ + blocks = g_slist_prepend(blocks, bi); + qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec, + QEMU_PLUGIN_CB_NO_REGS, (void *)bi); +} + + +/* + * Instead of encoding master/slave status into what is essentially + * two peers we shall just take the simple approach of checking for + * the existence of the pipe and assuming if it's not there we are the + * first process. + */ +static bool setup_socket(const char *path) +{ + struct sockaddr_un sockaddr; + int fd; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + perror("create socket"); + return false; + } + + sockaddr.sun_family = AF_UNIX; + g_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1); + if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { + perror("bind socket"); + close(fd); + return false; + } + + /* remember to clean-up */ + path_to_unlink = g_strdup(path); + + if (listen(fd, 1) < 0) { + perror("listen socket"); + close(fd); + return false; + } + + socket_fd = accept(fd, NULL, NULL); + if (socket_fd < 0 && errno != EINTR) { + perror("accept socket"); + return false; + } + + qemu_plugin_outs("setup_socket::ready\n"); + + return true; +} + +static bool connect_socket(const char *path) +{ + int fd; + struct sockaddr_un sockaddr; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + perror("create socket"); + return false; + } + + sockaddr.sun_family = AF_UNIX; + g_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1); + + if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { + perror("failed to connect"); + return false; + } + + qemu_plugin_outs("connect_socket::ready\n"); + + socket_fd = fd; + return true; +} + +static bool setup_unix_socket(const char *path) +{ + if (g_file_test(path, G_FILE_TEST_EXISTS)) { + return connect_socket(path); + } else { + return setup_socket(path); + } +} + + +QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, + const qemu_info_t *info, + int argc, char **argv) +{ + int i; + + if (!argc || !argv[0]) { + qemu_plugin_outs("Need a socket path to talk to other instance."); + return -1; + } + + for (i = 0; i < argc; i++) { + char *p = argv[i]; + if (strcmp(p, "verbose") == 0) { + verbose = true; + } else if (!setup_unix_socket(argv[0])) { + qemu_plugin_outs("Failed to setup socket for communications."); + return -1; + } + } + + our_id = id; + + qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); + qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); + return 0; +} diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target index 2ae86776cd..4b2b696fce 100644 --- a/tests/tcg/Makefile.target +++ b/tests/tcg/Makefile.target @@ -129,7 +129,8 @@ ifeq ($(CONFIG_PLUGIN),y) PLUGIN_SRC=$(SRC_PATH)/tests/plugin PLUGIN_LIB=../../plugin VPATH+=$(PLUGIN_LIB) -PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c))) +PLUGINS=$(filter-out liblockstep.so,\ + $(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c)))) # We need to ensure expand the run-plugin-TEST-with-PLUGIN # pre-requistes manually here as we can't use stems to handle it. We From 9f815e83e983d247a3cd67579d2d9c1765adc644 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 5 Jun 2020 14:59:52 +0200 Subject: [PATCH 1328/2595] usb: add hostdevice property to usb-host The new property allows to specify usb host device name. Uses standard qemu_open(), so both file system path (/dev/bus/usb/$bus/$dev on linux) and file descriptor passing can be used. Requires libusb 1.0.23 or newer. The hostdevice property is only present in case qemu is compiled against a new enough library version, so the presence of the property can be used for feature detection. Signed-off-by: Gerd Hoffmann Message-Id: <20200605125952.13113-1-kraxel@redhat.com> --- hw/usb/host-libusb.c | 75 +++++++++++++++++++++++++++++++++++--------- hw/usb/trace-events | 1 + 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index e28441379d..e88db544bc 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -80,6 +80,7 @@ struct USBHostDevice { /* properties */ struct USBAutoFilter match; + char *hostdevice; int32_t bootindex; uint32_t iso_urb_count; uint32_t iso_urb_frames; @@ -97,6 +98,7 @@ struct USBHostDevice { int addr; char port[16]; + int hostfd; libusb_device *dev; libusb_device_handle *dh; struct libusb_device_descriptor ddesc; @@ -880,26 +882,45 @@ static void usb_host_ep_update(USBHostDevice *s) libusb_free_config_descriptor(conf); } -static int usb_host_open(USBHostDevice *s, libusb_device *dev) +static int usb_host_open(USBHostDevice *s, libusb_device *dev, int hostfd) { USBDevice *udev = USB_DEVICE(s); - int bus_num = libusb_get_bus_number(dev); - int addr = libusb_get_device_address(dev); + int bus_num = 0; + int addr = 0; int rc; Error *local_err = NULL; if (s->bh_postld_pending) { return -1; } - - trace_usb_host_open_started(bus_num, addr); - if (s->dh != NULL) { goto fail; } - rc = libusb_open(dev, &s->dh); - if (rc != 0) { - goto fail; + + if (dev) { + bus_num = libusb_get_bus_number(dev); + addr = libusb_get_device_address(dev); + trace_usb_host_open_started(bus_num, addr); + + rc = libusb_open(dev, &s->dh); + if (rc != 0) { + goto fail; + } + } else { +#if LIBUSB_API_VERSION >= 0x01000107 + trace_usb_host_open_hostfd(hostfd); + + rc = libusb_wrap_sys_device(ctx, hostfd, &s->dh); + if (rc != 0) { + goto fail; + } + s->hostfd = hostfd; + dev = libusb_get_device(s->dh); + bus_num = libusb_get_bus_number(dev); + addr = libusb_get_device_address(dev); +#else + g_assert_not_reached(); +#endif } s->dev = dev; @@ -988,6 +1009,11 @@ static int usb_host_close(USBHostDevice *s) s->dh = NULL; s->dev = NULL; + if (s->hostfd != -1) { + close(s->hostfd); + s->hostfd = -1; + } + usb_host_auto_check(NULL); return 0; } @@ -1025,9 +1051,6 @@ static libusb_device *usb_host_find_ref(int bus, int addr) libusb_device *ret = NULL; int i, n; - if (usb_host_init() != 0) { - return NULL; - } n = libusb_get_device_list(ctx, &devs); for (i = 0; i < n; i++) { if (libusb_get_bus_number(devs[i]) == bus && @@ -1046,6 +1069,10 @@ static void usb_host_realize(USBDevice *udev, Error **errp) libusb_device *ldev; int rc; + if (usb_host_init() != 0) { + error_setg(errp, "failed to init libusb"); + return; + } if (s->match.vendor_id > 0xffff) { error_setg(errp, "vendorid out of range"); return; @@ -1064,7 +1091,24 @@ static void usb_host_realize(USBDevice *udev, Error **errp) udev->auto_attach = 0; QTAILQ_INIT(&s->requests); QTAILQ_INIT(&s->isorings); + s->hostfd = -1; +#if LIBUSB_API_VERSION >= 0x01000107 + if (s->hostdevice) { + int fd; + s->needs_autoscan = false; + fd = qemu_open(s->hostdevice, O_RDWR); + if (fd < 0) { + error_setg_errno(errp, errno, "failed to open %s", s->hostdevice); + return; + } + rc = usb_host_open(s, NULL, fd); + if (rc < 0) { + error_setg(errp, "failed to open host usb device %s", s->hostdevice); + return; + } + } else +#endif if (s->match.addr && s->match.bus_num && !s->match.vendor_id && !s->match.product_id && @@ -1077,7 +1121,7 @@ static void usb_host_realize(USBDevice *udev, Error **errp) s->match.bus_num, s->match.addr); return; } - rc = usb_host_open(s, ldev); + rc = usb_host_open(s, ldev, 0); libusb_unref_device(ldev); if (rc < 0) { error_setg(errp, "failed to open host usb device %d:%d", @@ -1605,6 +1649,9 @@ static Property usb_host_dev_properties[] = { DEFINE_PROP_STRING("hostport", USBHostDevice, match.port), DEFINE_PROP_UINT32("vendorid", USBHostDevice, match.vendor_id, 0), DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0), +#if LIBUSB_API_VERSION >= 0x01000107 + DEFINE_PROP_STRING("hostdevice", USBHostDevice, hostdevice), +#endif DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4), DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32), DEFINE_PROP_BOOL("guest-reset", USBHostDevice, @@ -1723,7 +1770,7 @@ static void usb_host_auto_check(void *unused) if (s->dh != NULL) { continue; } - if (usb_host_open(s, devs[i]) < 0) { + if (usb_host_open(s, devs[i], 0) < 0) { s->errcount++; continue; } diff --git a/hw/usb/trace-events b/hw/usb/trace-events index 5817ce4421..e9cdeeed14 100644 --- a/hw/usb/trace-events +++ b/hw/usb/trace-events @@ -291,6 +291,7 @@ usb_mtp_file_monitor_event(int dev, const char *path, const char *s) "dev %d, pa # host-libusb.c usb_host_open_started(int bus, int addr) "dev %d:%d" +usb_host_open_hostfd(int hostfd) "hostfd %d" usb_host_open_success(int bus, int addr) "dev %d:%d" usb_host_open_failure(int bus, int addr) "dev %d:%d" usb_host_close(int bus, int addr) "dev %d:%d" From 54cdfe511219b8051046be55a6e156c4f08ff7ff Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 29 May 2020 09:22:24 +0200 Subject: [PATCH 1329/2595] usb-host: workaround libusb bug libusb seems to no allways call the completion callback for requests canceled (which it is supposed to do according to the docs). So add a limit to avoid qemu waiting forever. Tested-by: BALATON Zoltan Signed-off-by: Gerd Hoffmann Message-Id: <20200529072225.3195-1-kraxel@redhat.com> --- hw/usb/host-libusb.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index e88db544bc..ad7ed8fb0c 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -972,6 +972,7 @@ fail: static void usb_host_abort_xfers(USBHostDevice *s) { USBHostRequest *r, *rtmp; + int limit = 100; QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) { usb_host_req_abort(r); @@ -982,6 +983,19 @@ static void usb_host_abort_xfers(USBHostDevice *s) memset(&tv, 0, sizeof(tv)); tv.tv_usec = 2500; libusb_handle_events_timeout(ctx, &tv); + if (--limit == 0) { + /* + * Don't wait forever for libusb calling the complete + * callback (which will unlink and free the request). + * + * Leaking memory here, to make sure libusb will not + * access memory which we have released already. + */ + QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) { + QTAILQ_REMOVE(&s->requests, r, next); + } + return; + } } } From e289655cea93bd50856a0896e2d49e5c7ed10c3b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 29 May 2020 09:39:54 +0200 Subject: [PATCH 1330/2595] microvm: use 3G split unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like the logic was copied over from q35. q35 does this for backward compatibility, there is no reason to do this on microvm though. Also microvm doesn't need much mmio space, 1G is more than enough. Using an mmio window smaller than 1G is bad for gigabyte alignment and hugepages though. So split @ 3G unconditionally. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov Acked-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Message-id: 20200529073957.8018-2-kraxel@redhat.com --- hw/i386/microvm.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 937db10ae6..44f940813b 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -170,23 +170,9 @@ static void microvm_memory_init(MicrovmMachineState *mms) MemoryRegion *ram_below_4g, *ram_above_4g; MemoryRegion *system_memory = get_system_memory(); FWCfgState *fw_cfg; - ram_addr_t lowmem; + ram_addr_t lowmem = 0xc0000000; /* 3G */ int i; - /* - * Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory - * and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping - * also known as MMCFG). - * If it doesn't, we need to split it in chunks below and above 4G. - * In any case, try to make sure that guest addresses aligned at - * 1G boundaries get mapped to host addresses aligned at 1G boundaries. - */ - if (machine->ram_size >= 0xb0000000) { - lowmem = 0x80000000; - } else { - lowmem = 0xb0000000; - } - /* * Handle the machine opt max-ram-below-4g. It is basically doing * min(qemu limit, user limit). From 3235936e306b5eae6291907e4d675f226707fd14 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 29 May 2020 09:39:55 +0200 Subject: [PATCH 1331/2595] microvm: drop max-ram-below-4g support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not useful for microvm and allows users to shoot themself into the foot (make ram + mmio overlap). Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Acked-by: Paolo Bonzini Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-id: 20200529073957.8018-3-kraxel@redhat.com --- hw/i386/microvm.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 44f940813b..5e931975a0 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -173,25 +173,6 @@ static void microvm_memory_init(MicrovmMachineState *mms) ram_addr_t lowmem = 0xc0000000; /* 3G */ int i; - /* - * Handle the machine opt max-ram-below-4g. It is basically doing - * min(qemu limit, user limit). - */ - if (!x86ms->max_ram_below_4g) { - x86ms->max_ram_below_4g = 4 * GiB; - } - if (lowmem > x86ms->max_ram_below_4g) { - lowmem = x86ms->max_ram_below_4g; - if (machine->ram_size - lowmem > lowmem && - lowmem & (1 * GiB - 1)) { - warn_report("There is possibly poor performance as the ram size " - " (0x%" PRIx64 ") is more then twice the size of" - " max-ram-below-4g (%"PRIu64") and" - " max-ram-below-4g is not a multiple of 1G.", - (uint64_t)machine->ram_size, x86ms->max_ram_below_4g); - } - } - if (machine->ram_size > lowmem) { x86ms->above_4g_mem_size = machine->ram_size - lowmem; x86ms->below_4g_mem_size = lowmem; From 9a45729d3bfcc87a23efaab84092473e770d900b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 29 May 2020 09:39:56 +0200 Subject: [PATCH 1332/2595] x86: move max-ram-below-4g to pc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move from X86MachineClass to PCMachineClass so it disappears from microvm machine type property list. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Acked-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Reviewed-by: Igor Mammedov Reviewed-by: Paul Durrant Message-id: 20200529073957.8018-4-kraxel@redhat.com --- hw/i386/pc.c | 46 +++++++++++++++++++++++++++++++++++++++++++ hw/i386/pc_piix.c | 10 +++++----- hw/i386/pc_q35.c | 10 +++++----- hw/i386/x86.c | 46 ------------------------------------------- hw/i386/xen/xen-hvm.c | 2 +- include/hw/i386/pc.h | 2 ++ include/hw/i386/x86.h | 4 ---- 7 files changed, 59 insertions(+), 61 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index ec39741c87..d103b8c0ab 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1857,6 +1857,45 @@ static void pc_machine_set_pit(Object *obj, bool value, Error **errp) pcms->pit_enabled = value; } +static void pc_machine_get_max_ram_below_4g(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + uint64_t value = pcms->max_ram_below_4g; + + visit_type_size(v, name, &value, errp); +} + +static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + Error *error = NULL; + uint64_t value; + + visit_type_size(v, name, &value, &error); + if (error) { + error_propagate(errp, error); + return; + } + if (value > 4 * GiB) { + error_setg(&error, + "Machine option 'max-ram-below-4g=%"PRIu64 + "' expects size less than or equal to 4G", value); + error_propagate(errp, error); + return; + } + + if (value < 1 * MiB) { + warn_report("Only %" PRIu64 " bytes of RAM below the 4GiB boundary," + "BIOS may not work with less than 1MiB", value); + } + + pcms->max_ram_below_4g = value; +} + static void pc_machine_initfn(Object *obj) { PCMachineState *pcms = PC_MACHINE(obj); @@ -1866,6 +1905,7 @@ static void pc_machine_initfn(Object *obj) #else pcms->vmport = ON_OFF_AUTO_OFF; #endif /* CONFIG_VMPORT */ + pcms->max_ram_below_4g = 0; /* use default */ /* acpi build is enabled by default if machine supports it */ pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build; pcms->smbus_enabled = true; @@ -1964,6 +2004,12 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) mc->numa_mem_supported = true; mc->default_ram_id = "pc.ram"; + object_class_property_add(oc, PC_MACHINE_MAX_RAM_BELOW_4G, "size", + pc_machine_get_max_ram_below_4g, pc_machine_set_max_ram_below_4g, + NULL, NULL); + object_class_property_set_description(oc, PC_MACHINE_MAX_RAM_BELOW_4G, + "Maximum ram below the 4G boundary (32bit boundary)"); + object_class_property_add(oc, PC_MACHINE_DEVMEM_REGION_SIZE, "int", pc_machine_get_device_memory_region_size, NULL, NULL, NULL); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 054d3aa9f7..1497d0e4ae 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -129,11 +129,11 @@ static void pc_init1(MachineState *machine, if (xen_enabled()) { xen_hvm_init(pcms, &ram_memory); } else { - if (!x86ms->max_ram_below_4g) { - x86ms->max_ram_below_4g = 0xe0000000; /* default: 3.5G */ + if (!pcms->max_ram_below_4g) { + pcms->max_ram_below_4g = 0xe0000000; /* default: 3.5G */ } - lowmem = x86ms->max_ram_below_4g; - if (machine->ram_size >= x86ms->max_ram_below_4g) { + lowmem = pcms->max_ram_below_4g; + if (machine->ram_size >= pcms->max_ram_below_4g) { if (pcmc->gigabyte_align) { if (lowmem > 0xc0000000) { lowmem = 0xc0000000; @@ -142,7 +142,7 @@ static void pc_init1(MachineState *machine, warn_report("Large machine and max_ram_below_4g " "(%" PRIu64 ") not a multiple of 1G; " "possible bad performance.", - x86ms->max_ram_below_4g); + pcms->max_ram_below_4g); } } } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 18d2fad9c5..46cd06524c 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -156,18 +156,18 @@ static void pc_q35_init(MachineState *machine) /* Handle the machine opt max-ram-below-4g. It is basically doing * min(qemu limit, user limit). */ - if (!x86ms->max_ram_below_4g) { - x86ms->max_ram_below_4g = 4 * GiB; + if (!pcms->max_ram_below_4g) { + pcms->max_ram_below_4g = 4 * GiB; } - if (lowmem > x86ms->max_ram_below_4g) { - lowmem = x86ms->max_ram_below_4g; + if (lowmem > pcms->max_ram_below_4g) { + lowmem = pcms->max_ram_below_4g; if (machine->ram_size - lowmem > lowmem && lowmem & (1 * GiB - 1)) { warn_report("There is possibly poor performance as the ram size " " (0x%" PRIx64 ") is more then twice the size of" " max-ram-below-4g (%"PRIu64") and" " max-ram-below-4g is not a multiple of 1G.", - (uint64_t)machine->ram_size, x86ms->max_ram_below_4g); + (uint64_t)machine->ram_size, pcms->max_ram_below_4g); } } diff --git a/hw/i386/x86.c b/hw/i386/x86.c index bb31935f70..34229b45c7 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -846,45 +846,6 @@ void x86_bios_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw) bios); } -static void x86_machine_get_max_ram_below_4g(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - X86MachineState *x86ms = X86_MACHINE(obj); - uint64_t value = x86ms->max_ram_below_4g; - - visit_type_size(v, name, &value, errp); -} - -static void x86_machine_set_max_ram_below_4g(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - X86MachineState *x86ms = X86_MACHINE(obj); - Error *error = NULL; - uint64_t value; - - visit_type_size(v, name, &value, &error); - if (error) { - error_propagate(errp, error); - return; - } - if (value > 4 * GiB) { - error_setg(&error, - "Machine option 'max-ram-below-4g=%"PRIu64 - "' expects size less than or equal to 4G", value); - error_propagate(errp, error); - return; - } - - if (value < 1 * MiB) { - warn_report("Only %" PRIu64 " bytes of RAM below the 4GiB boundary," - "BIOS may not work with less than 1MiB", value); - } - - x86ms->max_ram_below_4g = value; -} - bool x86_machine_is_smm_enabled(X86MachineState *x86ms) { bool smm_available = false; @@ -958,7 +919,6 @@ static void x86_machine_initfn(Object *obj) x86ms->smm = ON_OFF_AUTO_AUTO; x86ms->acpi = ON_OFF_AUTO_AUTO; - x86ms->max_ram_below_4g = 0; /* use default */ x86ms->smp_dies = 1; x86ms->apicid_from_cpu_idx = x86_apicid_from_cpu_idx; @@ -980,12 +940,6 @@ static void x86_machine_class_init(ObjectClass *oc, void *data) x86mc->save_tsc_khz = true; nc->nmi_monitor_handler = x86_nmi; - object_class_property_add(oc, X86_MACHINE_MAX_RAM_BELOW_4G, "size", - x86_machine_get_max_ram_below_4g, x86_machine_set_max_ram_below_4g, - NULL, NULL); - object_class_property_set_description(oc, X86_MACHINE_MAX_RAM_BELOW_4G, - "Maximum ram below the 4G boundary (32bit boundary)"); - object_class_property_add(oc, X86_MACHINE_SMM, "OnOffAuto", x86_machine_get_smm, x86_machine_set_smm, NULL, NULL); diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index 628bde5fac..cde981bad6 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -205,7 +205,7 @@ static void xen_ram_init(PCMachineState *pcms, ram_addr_t block_len; uint64_t user_lowmem = object_property_get_uint(qdev_get_machine(), - X86_MACHINE_MAX_RAM_BELOW_4G, + PC_MACHINE_MAX_RAM_BELOW_4G, &error_abort); /* Handle the machine opt max-ram-below-4g. It is basically doing diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 8d764f965c..e6135c34d6 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -35,6 +35,7 @@ struct PCMachineState { PFlashCFI01 *flash[2]; /* Configuration options: */ + uint64_t max_ram_below_4g; OnOffAuto vmport; bool acpi_build_enabled; @@ -51,6 +52,7 @@ struct PCMachineState { }; #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" +#define PC_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g" #define PC_MACHINE_DEVMEM_REGION_SIZE "device-memory-region-size" #define PC_MACHINE_VMPORT "vmport" #define PC_MACHINE_SMBUS "smbus" diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index b522854816..b79f24e285 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -51,9 +51,6 @@ typedef struct { qemu_irq *gsi; GMappedFile *initrd_mapped_file; - /* Configuration options: */ - uint64_t max_ram_below_4g; - /* RAM information (sizes, addresses, configuration): */ ram_addr_t below_4g_mem_size, above_4g_mem_size; @@ -82,7 +79,6 @@ typedef struct { AddressSpace *ioapic_as; } X86MachineState; -#define X86_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g" #define X86_MACHINE_SMM "smm" #define X86_MACHINE_ACPI "acpi" From c8b473594b8fbba169a6ea950493a3015d15a18d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 29 May 2020 09:39:57 +0200 Subject: [PATCH 1333/2595] microvm: move virtio base to 0xfeb00000 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Place virtio-mmio devices near the other mmio regions, next ioapic is at @ 0xfec00000. Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov Reviewed-by: Paul Durrant Acked-by: Paolo Bonzini Message-id: 20200529073957.8018-5-kraxel@redhat.com --- include/hw/i386/microvm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h index ba68d1f22b..fd34b78e0d 100644 --- a/include/hw/i386/microvm.h +++ b/include/hw/i386/microvm.h @@ -26,7 +26,7 @@ #include "hw/i386/x86.h" /* Platform virtio definitions */ -#define VIRTIO_MMIO_BASE 0xc0000000 +#define VIRTIO_MMIO_BASE 0xfeb00000 #define VIRTIO_IRQ_BASE 5 #define VIRTIO_NUM_TRANSPORTS 8 #define VIRTIO_CMDLINE_MAXLEN 64 From 36963ed116b625c6dcdf71002c804f893dc6fdc1 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:13 +1000 Subject: [PATCH 1334/2595] audio/jack: fix invalid minimum buffer size check JACK does not provide us with the configured buffer size until after activiation which was overriding this minimum value. JACK itself doesn't have this minimum limitation, but the QEMU virtual hardware and as such it must be enforced, failure to do so results in audio discontinuities. Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-2-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index 722ddb1dfe..d0b6f748f2 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -434,17 +434,6 @@ static int qjack_client_init(QJackClient *c) jack_set_xrun_callback(c->client, qjack_xrun, c); jack_on_shutdown(c->client, qjack_shutdown, c); - /* - * ensure the buffersize is no smaller then 512 samples, some (all?) qemu - * virtual devices do not work correctly otherwise - */ - if (c->buffersize < 512) { - c->buffersize = 512; - } - - /* create a 2 period buffer */ - qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 2); - /* allocate and register the ports */ c->port = g_malloc(sizeof(jack_port_t *) * c->nchannels); for (int i = 0; i < c->nchannels; ++i) { @@ -468,6 +457,17 @@ static int qjack_client_init(QJackClient *c) jack_activate(c->client); c->buffersize = jack_get_buffer_size(c->client); + /* + * ensure the buffersize is no smaller then 512 samples, some (all?) qemu + * virtual devices do not work correctly otherwise + */ + if (c->buffersize < 512) { + c->buffersize = 512; + } + + /* create a 2 period buffer */ + qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 2); + qjack_client_connect_ports(c); c->state = QJACK_STATE_RUNNING; return 0; From 2f33ee08083ca540120ab572a7130f08c4d47be3 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:14 +1000 Subject: [PATCH 1335/2595] audio/jack: remove unused stopped state Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-3-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index d0b6f748f2..fb8efd7af7 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -38,7 +38,6 @@ struct QJack; typedef enum QJackState { QJACK_STATE_DISCONNECTED, - QJACK_STATE_STOPPED, QJACK_STATE_RUNNING, QJACK_STATE_SHUTDOWN } @@ -549,9 +548,6 @@ static void qjack_client_fini(QJackClient *c) { switch (c->state) { case QJACK_STATE_RUNNING: - /* fallthrough */ - - case QJACK_STATE_STOPPED: for (int i = 0; i < c->nchannels; ++i) { jack_port_unregister(c->client, c->port[i]); } From f8f0f218d4212598eab6c824754cfc40d4961ab7 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:15 +1000 Subject: [PATCH 1336/2595] audio/jack: remove invalid set of input support bool Initial code for JACK did not support audio input and as such this boolean was set to let QEMU know, however JACK ended up including input support making this invalid. Further investigation shows it was invalid to set it in the first instance anyway due to a failure on my part understand properly what this was for when the audodev was initially developed. Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-4-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index fb8efd7af7..58c7344497 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -607,9 +607,6 @@ static int qjack_thread_creator(jack_native_thread_t *thread, static void *qjack_init(Audiodev *dev) { assert(dev->driver == AUDIODEV_DRIVER_JACK); - - dev->u.jack.has_in = false; - return dev; } From de82640843769e84139b5b5a8ed60b076f0bcabe Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:16 +1000 Subject: [PATCH 1337/2595] audio/jack: do not remove ports when finishing This fixes a hang when there is a communications issue with the JACK server. Simply closing the connection is enough to completely clean up and as such we do not need to remove the ports first. As JACK uses a socket based protocol that relies on the `select` call, if there is a communication breakdown with the server the client library waits forever for a response to the unregister request. Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-5-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index 58c7344497..249cbd3265 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -548,9 +548,6 @@ static void qjack_client_fini(QJackClient *c) { switch (c->state) { case QJACK_STATE_RUNNING: - for (int i = 0; i < c->nchannels; ++i) { - jack_port_unregister(c->client, c->port[i]); - } jack_deactivate(c->client); /* fallthrough */ From 81e0efb2e57cfdb076887b0f99ce6f0353952617 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:17 +1000 Subject: [PATCH 1338/2595] audio/jack: honour the enable state of the audio device When the guest closes the audio device we must start dropping input samples from JACK and zeroing the output buffer samples. Failure to do so causes sound artifacts during operations such as guest OS reboot, and causes a hang of the input pipeline breaking it until QEMU is restated. Closing and reconnecting to JACK was tested during these enable/disable calls which works well for Linux guests, however Windows re-opens the audio hardware repeatedly even when doing simple tasks like playing a system sounds. As such it was decided it is better to feed silence to JACK while the device is disabled. Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-6-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index 249cbd3265..b2b53985ae 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -56,7 +56,7 @@ typedef struct QJackClient { AudiodevJackPerDirectionOptions *opt; bool out; - bool finished; + bool enabled; bool connect_ports; int packets; @@ -271,9 +271,17 @@ static int qjack_process(jack_nframes_t nframes, void *arg) } if (c->out) { - qjack_buffer_read_l(&c->fifo, buffers, nframes); + if (likely(c->enabled)) { + qjack_buffer_read_l(&c->fifo, buffers, nframes); + } else { + for(int i = 0; i < c->nchannels; ++i) { + memset(buffers[i], 0, nframes * sizeof(float)); + } + } } else { - qjack_buffer_write_l(&c->fifo, buffers, nframes); + if (likely(c->enabled)) { + qjack_buffer_write_l(&c->fifo, buffers, nframes); + } } return 0; @@ -314,8 +322,8 @@ static void qjack_client_recover(QJackClient *c) if (c->state == QJACK_STATE_DISCONNECTED && c->packets % 100 == 0) { - /* if not finished then attempt to recover */ - if (!c->finished) { + /* if enabled then attempt to recover */ + if (c->enabled) { dolog("attempting to reconnect to server\n"); qjack_client_init(c); } @@ -387,7 +395,6 @@ static int qjack_client_init(QJackClient *c) char client_name[jack_client_name_size()]; jack_options_t options = JackNullOption; - c->finished = false; c->connect_ports = true; snprintf(client_name, sizeof(client_name), "%s-%s", @@ -483,8 +490,10 @@ static int qjack_init_out(HWVoiceOut *hw, struct audsettings *as, } jo->c.out = true; + jo->c.enabled = false; jo->c.nchannels = as->nchannels; jo->c.opt = dev->u.jack.out; + int ret = qjack_client_init(&jo->c); if (ret != 0) { return ret; @@ -519,8 +528,10 @@ static int qjack_init_in(HWVoiceIn *hw, struct audsettings *as, } ji->c.out = false; + ji->c.enabled = false; ji->c.nchannels = as->nchannels; ji->c.opt = dev->u.jack.in; + int ret = qjack_client_init(&ji->c); if (ret != 0) { return ret; @@ -568,23 +579,25 @@ static void qjack_client_fini(QJackClient *c) static void qjack_fini_out(HWVoiceOut *hw) { QJackOut *jo = (QJackOut *)hw; - jo->c.finished = true; qjack_client_fini(&jo->c); } static void qjack_fini_in(HWVoiceIn *hw) { QJackIn *ji = (QJackIn *)hw; - ji->c.finished = true; qjack_client_fini(&ji->c); } static void qjack_enable_out(HWVoiceOut *hw, bool enable) { + QJackOut *jo = (QJackOut *)hw; + jo->c.enabled = enable; } static void qjack_enable_in(HWVoiceIn *hw, bool enable) { + QJackIn *ji = (QJackIn *)hw; + ji->c.enabled = enable; } static int qjack_thread_creator(jack_native_thread_t *thread, From bc81e6e56eeea88bb1e3b6105c80850ffb58841c Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:18 +1000 Subject: [PATCH 1339/2595] audio/jack: simplify the re-init code path Instead of checking for the audodev state in each code path, centralize the check into the initialize function itself to make it safe to call it at any time. Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-7-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index b2b53985ae..72ed7c4929 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -395,6 +395,10 @@ static int qjack_client_init(QJackClient *c) char client_name[jack_client_name_size()]; jack_options_t options = JackNullOption; + if (c->state == QJACK_STATE_RUNNING) { + return 0; + } + c->connect_ports = true; snprintf(client_name, sizeof(client_name), "%s-%s", @@ -485,9 +489,7 @@ static int qjack_init_out(HWVoiceOut *hw, struct audsettings *as, QJackOut *jo = (QJackOut *)hw; Audiodev *dev = (Audiodev *)drv_opaque; - if (jo->c.state != QJACK_STATE_DISCONNECTED) { - return 0; - } + qjack_client_fini(&jo->c); jo->c.out = true; jo->c.enabled = false; @@ -523,9 +525,7 @@ static int qjack_init_in(HWVoiceIn *hw, struct audsettings *as, QJackIn *ji = (QJackIn *)hw; Audiodev *dev = (Audiodev *)drv_opaque; - if (ji->c.state != QJACK_STATE_DISCONNECTED) { - return 0; - } + qjack_client_fini(&ji->c); ji->c.out = false; ji->c.enabled = false; From ae0cebd71215188951902c5ccdd8685e431c286c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 12 May 2020 21:49:17 +0200 Subject: [PATCH 1340/2595] hw/ide: Make IDEDMAOps handlers take a const IDEDMA pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handlers don't need to modify the IDEDMA structure. Make it const. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200512194917.15807-1-philmd@redhat.com> Acked-by: John Snow Signed-off-by: Kevin Wolf --- hw/ide/ahci.c | 18 +++++++++--------- hw/ide/core.c | 6 +++--- hw/ide/macio.c | 6 +++--- hw/ide/pci.c | 12 ++++++------ include/hw/ide/internal.h | 12 ++++++------ 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index fc82cbd5f1..009120f88b 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -44,7 +44,7 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot); static void ahci_reset_port(AHCIState *s, int port); static bool ahci_write_fis_d2h(AHCIDevice *ad); static void ahci_init_d2h(AHCIDevice *ad); -static int ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit); +static int ahci_dma_prepare_buf(const IDEDMA *dma, int32_t limit); static bool ahci_map_clb_address(AHCIDevice *ad); static bool ahci_map_fis_address(AHCIDevice *ad); static void ahci_unmap_clb_address(AHCIDevice *ad); @@ -1338,7 +1338,7 @@ out: } /* Transfer PIO data between RAM and device */ -static void ahci_pio_transfer(IDEDMA *dma) +static void ahci_pio_transfer(const IDEDMA *dma) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); IDEState *s = &ad->port.ifs[0]; @@ -1397,7 +1397,7 @@ out: } } -static void ahci_start_dma(IDEDMA *dma, IDEState *s, +static void ahci_start_dma(const IDEDMA *dma, IDEState *s, BlockCompletionFunc *dma_cb) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); @@ -1406,7 +1406,7 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s, dma_cb(s, 0); } -static void ahci_restart_dma(IDEDMA *dma) +static void ahci_restart_dma(const IDEDMA *dma) { /* Nothing to do, ahci_start_dma already resets s->io_buffer_offset. */ } @@ -1415,7 +1415,7 @@ static void ahci_restart_dma(IDEDMA *dma) * IDE/PIO restarts are handled by the core layer, but NCQ commands * need an extra kick from the AHCI HBA. */ -static void ahci_restart(IDEDMA *dma) +static void ahci_restart(const IDEDMA *dma) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); int i; @@ -1432,7 +1432,7 @@ static void ahci_restart(IDEDMA *dma) * Called in DMA and PIO R/W chains to read the PRDT. * Not shared with NCQ pathways. */ -static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit) +static int32_t ahci_dma_prepare_buf(const IDEDMA *dma, int32_t limit) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); IDEState *s = &ad->port.ifs[0]; @@ -1453,7 +1453,7 @@ static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit) * Called via dma_buf_commit, for both DMA and PIO paths. * sglist destruction is handled within dma_buf_commit. */ -static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes) +static void ahci_commit_buf(const IDEDMA *dma, uint32_t tx_bytes) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); @@ -1461,7 +1461,7 @@ static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes) ad->cur_cmd->status = cpu_to_le32(tx_bytes); } -static int ahci_dma_rw_buf(IDEDMA *dma, bool is_write) +static int ahci_dma_rw_buf(const IDEDMA *dma, bool is_write) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); IDEState *s = &ad->port.ifs[0]; @@ -1486,7 +1486,7 @@ static int ahci_dma_rw_buf(IDEDMA *dma, bool is_write) return 1; } -static void ahci_cmd_done(IDEDMA *dma) +static void ahci_cmd_done(const IDEDMA *dma) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); diff --git a/hw/ide/core.c b/hw/ide/core.c index 689bb36409..d997a78e47 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2570,16 +2570,16 @@ static void ide_init1(IDEBus *bus, int unit) ide_sector_write_timer_cb, s); } -static int ide_nop_int(IDEDMA *dma, bool is_write) +static int ide_nop_int(const IDEDMA *dma, bool is_write) { return 0; } -static void ide_nop(IDEDMA *dma) +static void ide_nop(const IDEDMA *dma) { } -static int32_t ide_nop_int32(IDEDMA *dma, int32_t l) +static int32_t ide_nop_int32(const IDEDMA *dma, int32_t l) { return 0; } diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 30af0e93e6..62a599a075 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -376,17 +376,17 @@ static void macio_ide_reset(DeviceState *dev) ide_bus_reset(&d->bus); } -static int ide_nop_int(IDEDMA *dma, bool is_write) +static int ide_nop_int(const IDEDMA *dma, bool is_write) { return 0; } -static int32_t ide_nop_int32(IDEDMA *dma, int32_t l) +static int32_t ide_nop_int32(const IDEDMA *dma, int32_t l) { return 0; } -static void ide_dbdma_start(IDEDMA *dma, IDEState *s, +static void ide_dbdma_start(const IDEDMA *dma, IDEState *s, BlockCompletionFunc *cb) { MACIOIDEState *m = container_of(dma, MACIOIDEState, dma); diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 97347f07f1..5e85c4ad17 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -103,7 +103,7 @@ const MemoryRegionOps pci_ide_data_le_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static void bmdma_start_dma(IDEDMA *dma, IDEState *s, +static void bmdma_start_dma(const IDEDMA *dma, IDEState *s, BlockCompletionFunc *dma_cb) { BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); @@ -126,7 +126,7 @@ static void bmdma_start_dma(IDEDMA *dma, IDEState *s, * IDEState.io_buffer_size will contain the number of bytes described * by the PRDs, whether or not we added them to the sglist. */ -static int32_t bmdma_prepare_buf(IDEDMA *dma, int32_t limit) +static int32_t bmdma_prepare_buf(const IDEDMA *dma, int32_t limit) { BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); IDEState *s = bmdma_active_if(bm); @@ -181,7 +181,7 @@ static int32_t bmdma_prepare_buf(IDEDMA *dma, int32_t limit) } /* return 0 if buffer completed */ -static int bmdma_rw_buf(IDEDMA *dma, bool is_write) +static int bmdma_rw_buf(const IDEDMA *dma, bool is_write) { BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); IDEState *s = bmdma_active_if(bm); @@ -230,7 +230,7 @@ static int bmdma_rw_buf(IDEDMA *dma, bool is_write) return 1; } -static void bmdma_set_inactive(IDEDMA *dma, bool more) +static void bmdma_set_inactive(const IDEDMA *dma, bool more) { BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); @@ -242,7 +242,7 @@ static void bmdma_set_inactive(IDEDMA *dma, bool more) } } -static void bmdma_restart_dma(IDEDMA *dma) +static void bmdma_restart_dma(const IDEDMA *dma) { BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); @@ -257,7 +257,7 @@ static void bmdma_cancel(BMDMAState *bm) } } -static void bmdma_reset(IDEDMA *dma) +static void bmdma_reset(const IDEDMA *dma) { BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h index 55da35d768..1a7869e85d 100644 --- a/include/hw/ide/internal.h +++ b/include/hw/ide/internal.h @@ -322,12 +322,12 @@ typedef enum { IDE_HD, IDE_CD, IDE_CFATA } IDEDriveKind; typedef void EndTransferFunc(IDEState *); -typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockCompletionFunc *); -typedef void DMAVoidFunc(IDEDMA *); -typedef int DMAIntFunc(IDEDMA *, bool); -typedef int32_t DMAInt32Func(IDEDMA *, int32_t len); -typedef void DMAu32Func(IDEDMA *, uint32_t); -typedef void DMAStopFunc(IDEDMA *, bool); +typedef void DMAStartFunc(const IDEDMA *, IDEState *, BlockCompletionFunc *); +typedef void DMAVoidFunc(const IDEDMA *); +typedef int DMAIntFunc(const IDEDMA *, bool); +typedef int32_t DMAInt32Func(const IDEDMA *, int32_t len); +typedef void DMAu32Func(const IDEDMA *, uint32_t); +typedef void DMAStopFunc(const IDEDMA *, bool); struct unreported_events { bool eject_request; From 5fb0a6b5e771b235275acc8af7da490de072917b Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Wed, 3 Jun 2020 13:22:02 +0300 Subject: [PATCH 1341/2595] icount: make dma reads deterministic Windows guest sometimes makes DMA requests with overlapping target addresses. This leads to the following structure of iov for the block driver: addr size1 addr size2 addr size3 It means that three adjacent disk blocks should be read into the same memory buffer. Windows does not expects anything from these bytes (should it be data from the first block, or the last one, or some mix), but uses them somehow. It leads to non-determinism of the guest execution, because block driver does not preserve any order of reading. This situation was discusses in the mailing list at least twice: https://lists.gnu.org/archive/html/qemu-devel/2010-09/msg01996.html https://lists.gnu.org/archive/html/qemu-devel/2020-02/msg05185.html This patch makes such disk reads deterministic in icount mode. It splits the whole request into several parts. Parts may overlap, but SGs inside one part do not overlap. Parts that are processed later overwrite the prior ones in case of overlapping. Examples for different SG part sequences: 1) A1 1000 A2 1000 A1 1000 A3 1000 -> One request is split into two. A1 1000 A2 1000 -- A1 1000 A3 1000 2) A1 800 A2 1000 A1 1000 -> A1 800 A2 1000 -- A1 1000 Signed-off-by: Pavel Dovgalyuk Message-Id: <159117972206.12193.12939621311413561779.stgit@pasha-ThinkPad-X280> Signed-off-by: Kevin Wolf --- dma-helpers.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/dma-helpers.c b/dma-helpers.c index e8a26e81e1..2a77b5a9cb 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -13,6 +13,8 @@ #include "trace-root.h" #include "qemu/thread.h" #include "qemu/main-loop.h" +#include "sysemu/cpus.h" +#include "qemu/range.h" /* #define DEBUG_IOMMU */ @@ -142,6 +144,26 @@ static void dma_blk_cb(void *opaque, int ret) cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte; cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte; mem = dma_memory_map(dbs->sg->as, cur_addr, &cur_len, dbs->dir); + /* + * Make reads deterministic in icount mode. Windows sometimes issues + * disk read requests with overlapping SGs. It leads + * to non-determinism, because resulting buffer contents may be mixed + * from several sectors. This code splits all SGs into several + * groups. SGs in every group do not overlap. + */ + if (mem && use_icount && dbs->dir == DMA_DIRECTION_FROM_DEVICE) { + int i; + for (i = 0 ; i < dbs->iov.niov ; ++i) { + if (ranges_overlap((intptr_t)dbs->iov.iov[i].iov_base, + dbs->iov.iov[i].iov_len, (intptr_t)mem, + cur_len)) { + dma_memory_unmap(dbs->sg->as, mem, cur_len, + dbs->dir, cur_len); + mem = NULL; + break; + } + } + } if (!mem) break; qemu_iovec_add(&dbs->iov, mem, cur_len); From 7aa1c247b466870b0704d3ccdc3755e5e7394dca Mon Sep 17 00:00:00 2001 From: Sergio Lopez Date: Wed, 3 Jun 2020 11:32:39 +0200 Subject: [PATCH 1342/2595] virtio-blk: Refactor the code that processes queued requests Move the code that processes queued requests from virtio_blk_dma_restart_bh() to its own, non-static, function. This will allow us to call it from the virtio_blk_data_plane_start() in a future patch. Signed-off-by: Sergio Lopez Message-Id: <20200603093240.40489-2-slp@redhat.com> Signed-off-by: Kevin Wolf --- hw/block/virtio-blk.c | 16 +++++++++++----- include/hw/virtio/virtio-blk.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index f5f6fc925e..978574e4da 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -819,15 +819,11 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) virtio_blk_handle_output_do(s, vq); } -static void virtio_blk_dma_restart_bh(void *opaque) +void virtio_blk_process_queued_requests(VirtIOBlock *s) { - VirtIOBlock *s = opaque; VirtIOBlockReq *req = s->rq; MultiReqBuffer mrb = {}; - qemu_bh_delete(s->bh); - s->bh = NULL; - s->rq = NULL; aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); @@ -855,6 +851,16 @@ static void virtio_blk_dma_restart_bh(void *opaque) aio_context_release(blk_get_aio_context(s->conf.conf.blk)); } +static void virtio_blk_dma_restart_bh(void *opaque) +{ + VirtIOBlock *s = opaque; + + qemu_bh_delete(s->bh); + s->bh = NULL; + + virtio_blk_process_queued_requests(s); +} + static void virtio_blk_dma_restart_cb(void *opaque, int running, RunState state) { diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 1e62f869b2..f584ad9b86 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -86,5 +86,6 @@ typedef struct MultiReqBuffer { } MultiReqBuffer; bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); +void virtio_blk_process_queued_requests(VirtIOBlock *s); #endif From 49b44549ace7890fffdf027fd3695218ee7f1121 Mon Sep 17 00:00:00 2001 From: Sergio Lopez Date: Wed, 3 Jun 2020 11:32:40 +0200 Subject: [PATCH 1343/2595] virtio-blk: On restart, process queued requests in the proper context On restart, we were scheduling a BH to process queued requests, which would run before starting up the data plane, leading to those requests being assigned and started on coroutines on the main context. This could cause requests to be wrongly processed in parallel from different threads (the main thread and the iothread managing the data plane), potentially leading to multiple issues. For example, stopping and resuming a VM multiple times while the guest is generating I/O on a virtio_blk device can trigger a crash with a stack tracing looking like this one: <------> Thread 2 (Thread 0x7ff736765700 (LWP 1062503)): #0 0x00005567a13b99d6 in iov_memset (iov=0x6563617073206f4e, iov_cnt=1717922848, offset=516096, fillc=0, bytes=7018105756081554803) at util/iov.c:69 #1 0x00005567a13bab73 in qemu_iovec_memset (qiov=0x7ff73ec99748, offset=516096, fillc=0, bytes=7018105756081554803) at util/iov.c:530 #2 0x00005567a12f411c in qemu_laio_process_completion (laiocb=0x7ff6512ee6c0) at block/linux-aio.c:86 #3 0x00005567a12f42ff in qemu_laio_process_completions (s=0x7ff7182e8420) at block/linux-aio.c:217 #4 0x00005567a12f480d in ioq_submit (s=0x7ff7182e8420) at block/linux-aio.c:323 #5 0x00005567a12f43d9 in qemu_laio_process_completions_and_submit (s=0x7ff7182e8420) at block/linux-aio.c:236 #6 0x00005567a12f44c2 in qemu_laio_poll_cb (opaque=0x7ff7182e8430) at block/linux-aio.c:267 #7 0x00005567a13aed83 in run_poll_handlers_once (ctx=0x5567a2b58c70, timeout=0x7ff7367645f8) at util/aio-posix.c:520 #8 0x00005567a13aee9f in run_poll_handlers (ctx=0x5567a2b58c70, max_ns=16000, timeout=0x7ff7367645f8) at util/aio-posix.c:562 #9 0x00005567a13aefde in try_poll_mode (ctx=0x5567a2b58c70, timeout=0x7ff7367645f8) at util/aio-posix.c:597 #10 0x00005567a13af115 in aio_poll (ctx=0x5567a2b58c70, blocking=true) at util/aio-posix.c:639 #11 0x00005567a109acca in iothread_run (opaque=0x5567a2b29760) at iothread.c:75 #12 0x00005567a13b2790 in qemu_thread_start (args=0x5567a2b694c0) at util/qemu-thread-posix.c:519 #13 0x00007ff73eedf2de in start_thread () at /lib64/libpthread.so.0 #14 0x00007ff73ec10e83 in clone () at /lib64/libc.so.6 Thread 1 (Thread 0x7ff743986f00 (LWP 1062500)): #0 0x00005567a13b99d6 in iov_memset (iov=0x6563617073206f4e, iov_cnt=1717922848, offset=516096, fillc=0, bytes=7018105756081554803) at util/iov.c:69 #1 0x00005567a13bab73 in qemu_iovec_memset (qiov=0x7ff73ec99748, offset=516096, fillc=0, bytes=7018105756081554803) at util/iov.c:530 #2 0x00005567a12f411c in qemu_laio_process_completion (laiocb=0x7ff6512ee6c0) at block/linux-aio.c:86 #3 0x00005567a12f42ff in qemu_laio_process_completions (s=0x7ff7182e8420) at block/linux-aio.c:217 #4 0x00005567a12f480d in ioq_submit (s=0x7ff7182e8420) at block/linux-aio.c:323 #5 0x00005567a12f4a2f in laio_do_submit (fd=19, laiocb=0x7ff5f4ff9ae0, offset=472363008, type=2) at block/linux-aio.c:375 #6 0x00005567a12f4af2 in laio_co_submit (bs=0x5567a2b8c460, s=0x7ff7182e8420, fd=19, offset=472363008, qiov=0x7ff5f4ff9ca0, type=2) at block/linux-aio.c:394 #7 0x00005567a12f1803 in raw_co_prw (bs=0x5567a2b8c460, offset=472363008, bytes=20480, qiov=0x7ff5f4ff9ca0, type=2) at block/file-posix.c:1892 #8 0x00005567a12f1941 in raw_co_pwritev (bs=0x5567a2b8c460, offset=472363008, bytes=20480, qiov=0x7ff5f4ff9ca0, flags=0) at block/file-posix.c:1925 #9 0x00005567a12fe3e1 in bdrv_driver_pwritev (bs=0x5567a2b8c460, offset=472363008, bytes=20480, qiov=0x7ff5f4ff9ca0, qiov_offset=0, flags=0) at block/io.c:1183 #10 0x00005567a1300340 in bdrv_aligned_pwritev (child=0x5567a2b5b070, req=0x7ff5f4ff9db0, offset=472363008, bytes=20480, align=512, qiov=0x7ff72c0425b8, qiov_offset=0, flags=0) at block/io.c:1980 #11 0x00005567a1300b29 in bdrv_co_pwritev_part (child=0x5567a2b5b070, offset=472363008, bytes=20480, qiov=0x7ff72c0425b8, qiov_offset=0, flags=0) at block/io.c:2137 #12 0x00005567a12baba1 in qcow2_co_pwritev_task (bs=0x5567a2b92740, file_cluster_offset=472317952, offset=487305216, bytes=20480, qiov=0x7ff72c0425b8, qiov_offset=0, l2meta=0x0) at block/qcow2.c:2444 #13 0x00005567a12bacdb in qcow2_co_pwritev_task_entry (task=0x5567a2b48540) at block/qcow2.c:2475 #14 0x00005567a13167d8 in aio_task_co (opaque=0x5567a2b48540) at block/aio_task.c:45 #15 0x00005567a13cf00c in coroutine_trampoline (i0=738245600, i1=32759) at util/coroutine-ucontext.c:115 #16 0x00007ff73eb622e0 in __start_context () at /lib64/libc.so.6 #17 0x00007ff6626f1350 in () #18 0x0000000000000000 in () <------> This is also known to cause crashes with this message (assertion failed): aio_co_schedule: Co-routine was already scheduled in 'aio_co_schedule' RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1812765 Signed-off-by: Sergio Lopez Message-Id: <20200603093240.40489-3-slp@redhat.com> Signed-off-by: Kevin Wolf --- hw/block/dataplane/virtio-blk.c | 8 ++++++++ hw/block/virtio-blk.c | 18 ++++++++++++------ include/hw/virtio/virtio-blk.h | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 1b52e8159c..37499c5564 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -220,6 +220,9 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) goto fail_guest_notifiers; } + /* Process queued requests before the ones in vring */ + virtio_blk_process_queued_requests(vblk, false); + /* Kick right away to begin processing requests already in vring */ for (i = 0; i < nvqs; i++) { VirtQueue *vq = virtio_get_queue(s->vdev, i); @@ -239,6 +242,11 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) return 0; fail_guest_notifiers: + /* + * If we failed to set up the guest notifiers queued requests will be + * processed on the main context. + */ + virtio_blk_process_queued_requests(vblk, false); vblk->dataplane_disabled = true; s->starting = false; vblk->dataplane_started = true; diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 978574e4da..8882a1d1d4 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -819,7 +819,7 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) virtio_blk_handle_output_do(s, vq); } -void virtio_blk_process_queued_requests(VirtIOBlock *s) +void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh) { VirtIOBlockReq *req = s->rq; MultiReqBuffer mrb = {}; @@ -847,7 +847,9 @@ void virtio_blk_process_queued_requests(VirtIOBlock *s) if (mrb.num_reqs) { virtio_blk_submit_multireq(s->blk, &mrb); } - blk_dec_in_flight(s->conf.conf.blk); + if (is_bh) { + blk_dec_in_flight(s->conf.conf.blk); + } aio_context_release(blk_get_aio_context(s->conf.conf.blk)); } @@ -858,21 +860,25 @@ static void virtio_blk_dma_restart_bh(void *opaque) qemu_bh_delete(s->bh); s->bh = NULL; - virtio_blk_process_queued_requests(s); + virtio_blk_process_queued_requests(s, true); } static void virtio_blk_dma_restart_cb(void *opaque, int running, RunState state) { VirtIOBlock *s = opaque; + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); + VirtioBusState *bus = VIRTIO_BUS(qbus); if (!running) { return; } - if (!s->bh) { - /* FIXME The data plane is not started yet, so these requests are - * processed in the main thread. */ + /* + * If ioeventfd is enabled, don't schedule the BH here as queued + * requests will be processed while starting the data plane. + */ + if (!s->bh && !virtio_bus_ioeventfd_enabled(bus)) { s->bh = aio_bh_new(blk_get_aio_context(s->conf.conf.blk), virtio_blk_dma_restart_bh, s); blk_inc_in_flight(s->conf.conf.blk); diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index f584ad9b86..b1334c3904 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -86,6 +86,6 @@ typedef struct MultiReqBuffer { } MultiReqBuffer; bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); -void virtio_blk_process_queued_requests(VirtIOBlock *s); +void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh); #endif From e37adbebd19634836369e9572d9aaa0f088332fd Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 8 Jun 2020 12:33:39 -0500 Subject: [PATCH 1344/2595] block: Refactor subdirectory recursion during make Rather than listing block/monitor from the top-level Makefile.objs, we should instead list monitor from block/Makefile.objs. Suggested-by: Kevin Wolf Fixes: bb4e58c613 Signed-off-by: Eric Blake Message-Id: <20200608173339.3244211-1-eblake@redhat.com> Signed-off-by: Kevin Wolf --- Makefile.objs | 2 +- block/Makefile.objs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.objs b/Makefile.objs index c09d95dfe3..7ce2588b89 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -13,7 +13,7 @@ chardev-obj-y = chardev/ authz-obj-y = authz/ -block-obj-y = block/ block/monitor/ nbd/ scsi/ +block-obj-y = block/ nbd/ scsi/ block-obj-y += block.o blockjob.o job.o block-obj-y += qemu-io-cmds.o block-obj-$(CONFIG_REPLICATION) += replication.o diff --git a/block/Makefile.objs b/block/Makefile.objs index 3635b6b4c1..96028eedce 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -46,6 +46,7 @@ block-obj-y += aio_task.o block-obj-y += backup-top.o block-obj-y += filter-compress.o common-obj-y += monitor/ +block-obj-y += monitor/ block-obj-y += stream.o From f17d68477030b24a13ecb55d371f57f19199210d Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 8 Jun 2020 14:08:21 -0500 Subject: [PATCH 1345/2595] qcow2: Tweak comments on qcow2_get_persistent_dirty_bitmap_size For now, we don't have persistent bitmaps in any other formats, but that might not be true in the future. Make it obvious that our incoming parameter is not necessarily a qcow2 image, and therefore is limited to just the bdrv_dirty_bitmap_* API calls (rather than probing into qcow2 internals). Suggested-by: Kevin Wolf Signed-off-by: Eric Blake Message-Id: <20200608190821.3293867-1-eblake@redhat.com> Signed-off-by: Kevin Wolf --- block/qcow2-bitmap.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 7bf12502da..1f38806ca6 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -1757,19 +1757,20 @@ bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs) } /* - * Compute the space required for bitmaps in @bs. + * Compute the space required to copy bitmaps from @in_bs. * * The computation is based as if copying to a new image with the - * given @cluster_size, which may differ from the cluster size in @bs. + * given @cluster_size, which may differ from the cluster size in + * @in_bs; in fact, @in_bs might be something other than qcow2. */ -uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs, +uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *in_bs, uint32_t cluster_size) { uint64_t bitmaps_size = 0; BdrvDirtyBitmap *bm; size_t bitmap_dir_size = 0; - FOR_EACH_DIRTY_BITMAP(bs, bm) { + FOR_EACH_DIRTY_BITMAP(in_bs, bm) { if (bdrv_dirty_bitmap_get_persistence(bm)) { const char *name = bdrv_dirty_bitmap_name(bm); uint32_t granularity = bdrv_dirty_bitmap_granularity(bm); From f7e8c23f398c82eeba8ac02650f50e9c1747e033 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:12 +0200 Subject: [PATCH 1346/2595] hw/block/nvme: fix pci doorbell size calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The size of the BAR is 0x1000 (main registers) + 8 bytes for each queue. Currently, the size of the BAR is calculated like so: n->reg_size = pow2ceil(0x1004 + 2 * (n->num_queues + 1) * 4); Since the 'num_queues' parameter already accounts for the admin queue, this should in any case not need to be incremented by one. Also, the size should be initialized to (0x1000). n->reg_size = pow2ceil(0x1000 + 2 * n->num_queues * 4); This, with the default value of num_queues (64), we will set aside room for 1 admin queue and 63 I/O queues (4 bytes per doorbell, 2 doorbells per queue). Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-2-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index a21eeca2fb..c1476e8b2a 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -53,6 +53,9 @@ #include "trace.h" #include "nvme.h" +#define NVME_REG_SIZE 0x1000 +#define NVME_DB_SIZE 4 + #define NVME_GUEST_ERR(trace, fmt, ...) \ do { \ (trace_##trace)(__VA_ARGS__); \ @@ -1401,7 +1404,9 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) pcie_endpoint_cap_init(pci_dev, 0x80); n->num_namespaces = 1; - n->reg_size = pow2ceil(0x1004 + 2 * (n->num_queues + 1) * 4); + + /* num_queues is really number of pairs, so each has two doorbells */ + n->reg_size = pow2ceil(NVME_REG_SIZE + 2 * n->num_queues * NVME_DB_SIZE); n->ns_size = bs_size / (uint64_t)n->num_namespaces; n->namespaces = g_new0(NvmeNamespace, n->num_namespaces); From 6f4ee2e9aacf01d8f4bfa5b54caff9aa46b2ff04 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:13 +0200 Subject: [PATCH 1347/2595] hw/block/nvme: rename trace events to pci_nvme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the prefix of all nvme device related trace events to 'pci_nvme' to not clash with trace events from the nvme block driver. Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-3-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 198 +++++++++++++++++++++--------------------- hw/block/trace-events | 180 +++++++++++++++++++------------------- 2 files changed, 188 insertions(+), 190 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index c1476e8b2a..e8f5c5ab82 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -125,16 +125,16 @@ static void nvme_irq_assert(NvmeCtrl *n, NvmeCQueue *cq) { if (cq->irq_enabled) { if (msix_enabled(&(n->parent_obj))) { - trace_nvme_irq_msix(cq->vector); + trace_pci_nvme_irq_msix(cq->vector); msix_notify(&(n->parent_obj), cq->vector); } else { - trace_nvme_irq_pin(); + trace_pci_nvme_irq_pin(); assert(cq->cqid < 64); n->irq_status |= 1 << cq->cqid; nvme_irq_check(n); } } else { - trace_nvme_irq_masked(); + trace_pci_nvme_irq_masked(); } } @@ -159,7 +159,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, int num_prps = (len >> n->page_bits) + 1; if (unlikely(!prp1)) { - trace_nvme_err_invalid_prp(); + trace_pci_nvme_err_invalid_prp(); return NVME_INVALID_FIELD | NVME_DNR; } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr && prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) { @@ -173,7 +173,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, len -= trans_len; if (len) { if (unlikely(!prp2)) { - trace_nvme_err_invalid_prp2_missing(); + trace_pci_nvme_err_invalid_prp2_missing(); goto unmap; } if (len > n->page_size) { @@ -189,7 +189,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, if (i == n->max_prp_ents - 1 && len > n->page_size) { if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) { - trace_nvme_err_invalid_prplist_ent(prp_ent); + trace_pci_nvme_err_invalid_prplist_ent(prp_ent); goto unmap; } @@ -202,7 +202,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, } if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) { - trace_nvme_err_invalid_prplist_ent(prp_ent); + trace_pci_nvme_err_invalid_prplist_ent(prp_ent); goto unmap; } @@ -217,7 +217,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, } } else { if (unlikely(prp2 & (n->page_size - 1))) { - trace_nvme_err_invalid_prp2_align(prp2); + trace_pci_nvme_err_invalid_prp2_align(prp2); goto unmap; } if (qsg->nsg) { @@ -265,20 +265,20 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len, QEMUIOVector iov; uint16_t status = NVME_SUCCESS; - trace_nvme_dma_read(prp1, prp2); + trace_pci_nvme_dma_read(prp1, prp2); if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) { return NVME_INVALID_FIELD | NVME_DNR; } if (qsg.nsg > 0) { if (unlikely(dma_buf_read(ptr, len, &qsg))) { - trace_nvme_err_invalid_dma(); + trace_pci_nvme_err_invalid_dma(); status = NVME_INVALID_FIELD | NVME_DNR; } qemu_sglist_destroy(&qsg); } else { if (unlikely(qemu_iovec_from_buf(&iov, 0, ptr, len) != len)) { - trace_nvme_err_invalid_dma(); + trace_pci_nvme_err_invalid_dma(); status = NVME_INVALID_FIELD | NVME_DNR; } qemu_iovec_destroy(&iov); @@ -367,7 +367,7 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd, uint32_t count = nlb << data_shift; if (unlikely(slba + nlb > ns->id_ns.nsze)) { - trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); + trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); return NVME_LBA_RANGE | NVME_DNR; } @@ -395,11 +395,11 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd, int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0; enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ; - trace_nvme_rw(is_write ? "write" : "read", nlb, data_size, slba); + trace_pci_nvme_rw(is_write ? "write" : "read", nlb, data_size, slba); if (unlikely((slba + nlb) > ns->id_ns.nsze)) { block_acct_invalid(blk_get_stats(n->conf.blk), acct); - trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); + trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); return NVME_LBA_RANGE | NVME_DNR; } @@ -434,7 +434,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) uint32_t nsid = le32_to_cpu(cmd->nsid); if (unlikely(nsid == 0 || nsid > n->num_namespaces)) { - trace_nvme_err_invalid_ns(nsid, n->num_namespaces); + trace_pci_nvme_err_invalid_ns(nsid, n->num_namespaces); return NVME_INVALID_NSID | NVME_DNR; } @@ -448,7 +448,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) case NVME_CMD_READ: return nvme_rw(n, ns, cmd, req); default: - trace_nvme_err_invalid_opc(cmd->opcode); + trace_pci_nvme_err_invalid_opc(cmd->opcode); return NVME_INVALID_OPCODE | NVME_DNR; } } @@ -473,11 +473,11 @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd) uint16_t qid = le16_to_cpu(c->qid); if (unlikely(!qid || nvme_check_sqid(n, qid))) { - trace_nvme_err_invalid_del_sq(qid); + trace_pci_nvme_err_invalid_del_sq(qid); return NVME_INVALID_QID | NVME_DNR; } - trace_nvme_del_sq(qid); + trace_pci_nvme_del_sq(qid); sq = n->sq[qid]; while (!QTAILQ_EMPTY(&sq->out_req_list)) { @@ -541,26 +541,26 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd) uint16_t qflags = le16_to_cpu(c->sq_flags); uint64_t prp1 = le64_to_cpu(c->prp1); - trace_nvme_create_sq(prp1, sqid, cqid, qsize, qflags); + trace_pci_nvme_create_sq(prp1, sqid, cqid, qsize, qflags); if (unlikely(!cqid || nvme_check_cqid(n, cqid))) { - trace_nvme_err_invalid_create_sq_cqid(cqid); + trace_pci_nvme_err_invalid_create_sq_cqid(cqid); return NVME_INVALID_CQID | NVME_DNR; } if (unlikely(!sqid || !nvme_check_sqid(n, sqid))) { - trace_nvme_err_invalid_create_sq_sqid(sqid); + trace_pci_nvme_err_invalid_create_sq_sqid(sqid); return NVME_INVALID_QID | NVME_DNR; } if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) { - trace_nvme_err_invalid_create_sq_size(qsize); + trace_pci_nvme_err_invalid_create_sq_size(qsize); return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR; } if (unlikely(!prp1 || prp1 & (n->page_size - 1))) { - trace_nvme_err_invalid_create_sq_addr(prp1); + trace_pci_nvme_err_invalid_create_sq_addr(prp1); return NVME_INVALID_FIELD | NVME_DNR; } if (unlikely(!(NVME_SQ_FLAGS_PC(qflags)))) { - trace_nvme_err_invalid_create_sq_qflags(NVME_SQ_FLAGS_PC(qflags)); + trace_pci_nvme_err_invalid_create_sq_qflags(NVME_SQ_FLAGS_PC(qflags)); return NVME_INVALID_FIELD | NVME_DNR; } sq = g_malloc0(sizeof(*sq)); @@ -586,17 +586,17 @@ static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd) uint16_t qid = le16_to_cpu(c->qid); if (unlikely(!qid || nvme_check_cqid(n, qid))) { - trace_nvme_err_invalid_del_cq_cqid(qid); + trace_pci_nvme_err_invalid_del_cq_cqid(qid); return NVME_INVALID_CQID | NVME_DNR; } cq = n->cq[qid]; if (unlikely(!QTAILQ_EMPTY(&cq->sq_list))) { - trace_nvme_err_invalid_del_cq_notempty(qid); + trace_pci_nvme_err_invalid_del_cq_notempty(qid); return NVME_INVALID_QUEUE_DEL; } nvme_irq_deassert(n, cq); - trace_nvme_del_cq(qid); + trace_pci_nvme_del_cq(qid); nvme_free_cq(cq, n); return NVME_SUCCESS; } @@ -629,27 +629,27 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd) uint16_t qflags = le16_to_cpu(c->cq_flags); uint64_t prp1 = le64_to_cpu(c->prp1); - trace_nvme_create_cq(prp1, cqid, vector, qsize, qflags, - NVME_CQ_FLAGS_IEN(qflags) != 0); + trace_pci_nvme_create_cq(prp1, cqid, vector, qsize, qflags, + NVME_CQ_FLAGS_IEN(qflags) != 0); if (unlikely(!cqid || !nvme_check_cqid(n, cqid))) { - trace_nvme_err_invalid_create_cq_cqid(cqid); + trace_pci_nvme_err_invalid_create_cq_cqid(cqid); return NVME_INVALID_CQID | NVME_DNR; } if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) { - trace_nvme_err_invalid_create_cq_size(qsize); + trace_pci_nvme_err_invalid_create_cq_size(qsize); return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR; } if (unlikely(!prp1)) { - trace_nvme_err_invalid_create_cq_addr(prp1); + trace_pci_nvme_err_invalid_create_cq_addr(prp1); return NVME_INVALID_FIELD | NVME_DNR; } if (unlikely(vector > n->num_queues)) { - trace_nvme_err_invalid_create_cq_vector(vector); + trace_pci_nvme_err_invalid_create_cq_vector(vector); return NVME_INVALID_IRQ_VECTOR | NVME_DNR; } if (unlikely(!(NVME_CQ_FLAGS_PC(qflags)))) { - trace_nvme_err_invalid_create_cq_qflags(NVME_CQ_FLAGS_PC(qflags)); + trace_pci_nvme_err_invalid_create_cq_qflags(NVME_CQ_FLAGS_PC(qflags)); return NVME_INVALID_FIELD | NVME_DNR; } @@ -664,7 +664,7 @@ static uint16_t nvme_identify_ctrl(NvmeCtrl *n, NvmeIdentify *c) uint64_t prp1 = le64_to_cpu(c->prp1); uint64_t prp2 = le64_to_cpu(c->prp2); - trace_nvme_identify_ctrl(); + trace_pci_nvme_identify_ctrl(); return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl), prp1, prp2); @@ -677,10 +677,10 @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c) uint64_t prp1 = le64_to_cpu(c->prp1); uint64_t prp2 = le64_to_cpu(c->prp2); - trace_nvme_identify_ns(nsid); + trace_pci_nvme_identify_ns(nsid); if (unlikely(nsid == 0 || nsid > n->num_namespaces)) { - trace_nvme_err_invalid_ns(nsid, n->num_namespaces); + trace_pci_nvme_err_invalid_ns(nsid, n->num_namespaces); return NVME_INVALID_NSID | NVME_DNR; } @@ -700,7 +700,7 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c) uint16_t ret; int i, j = 0; - trace_nvme_identify_nslist(min_nsid); + trace_pci_nvme_identify_nslist(min_nsid); list = g_malloc0(data_len); for (i = 0; i < n->num_namespaces; i++) { @@ -729,14 +729,14 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd) case 0x02: return nvme_identify_nslist(n, c); default: - trace_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns)); + trace_pci_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns)); return NVME_INVALID_FIELD | NVME_DNR; } } static inline void nvme_set_timestamp(NvmeCtrl *n, uint64_t ts) { - trace_nvme_setfeat_timestamp(ts); + trace_pci_nvme_setfeat_timestamp(ts); n->host_timestamp = le64_to_cpu(ts); n->timestamp_set_qemu_clock_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); @@ -769,7 +769,7 @@ static inline uint64_t nvme_get_timestamp(const NvmeCtrl *n) /* If the host timestamp is non-zero, set the timestamp origin */ ts.origin = n->host_timestamp ? 0x01 : 0x00; - trace_nvme_getfeat_timestamp(ts.all); + trace_pci_nvme_getfeat_timestamp(ts.all); return cpu_to_le64(ts.all); } @@ -793,17 +793,17 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) switch (dw10) { case NVME_VOLATILE_WRITE_CACHE: result = blk_enable_write_cache(n->conf.blk); - trace_nvme_getfeat_vwcache(result ? "enabled" : "disabled"); + trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled"); break; case NVME_NUMBER_OF_QUEUES: result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16)); - trace_nvme_getfeat_numq(result); + trace_pci_nvme_getfeat_numq(result); break; case NVME_TIMESTAMP: return nvme_get_feature_timestamp(n, cmd); break; default: - trace_nvme_err_invalid_getfeat(dw10); + trace_pci_nvme_err_invalid_getfeat(dw10); return NVME_INVALID_FIELD | NVME_DNR; } @@ -839,9 +839,9 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) blk_set_enable_write_cache(n->conf.blk, dw11 & 1); break; case NVME_NUMBER_OF_QUEUES: - trace_nvme_setfeat_numq((dw11 & 0xFFFF) + 1, - ((dw11 >> 16) & 0xFFFF) + 1, - n->num_queues - 1, n->num_queues - 1); + trace_pci_nvme_setfeat_numq((dw11 & 0xFFFF) + 1, + ((dw11 >> 16) & 0xFFFF) + 1, + n->num_queues - 1, n->num_queues - 1); req->cqe.result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16)); break; @@ -851,7 +851,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) break; default: - trace_nvme_err_invalid_setfeat(dw10); + trace_pci_nvme_err_invalid_setfeat(dw10); return NVME_INVALID_FIELD | NVME_DNR; } return NVME_SUCCESS; @@ -875,7 +875,7 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) case NVME_ADM_CMD_GET_FEATURES: return nvme_get_feature(n, cmd, req); default: - trace_nvme_err_invalid_admin_opc(cmd->opcode); + trace_pci_nvme_err_invalid_admin_opc(cmd->opcode); return NVME_INVALID_OPCODE | NVME_DNR; } } @@ -938,77 +938,77 @@ static int nvme_start_ctrl(NvmeCtrl *n) uint32_t page_size = 1 << page_bits; if (unlikely(n->cq[0])) { - trace_nvme_err_startfail_cq(); + trace_pci_nvme_err_startfail_cq(); return -1; } if (unlikely(n->sq[0])) { - trace_nvme_err_startfail_sq(); + trace_pci_nvme_err_startfail_sq(); return -1; } if (unlikely(!n->bar.asq)) { - trace_nvme_err_startfail_nbarasq(); + trace_pci_nvme_err_startfail_nbarasq(); return -1; } if (unlikely(!n->bar.acq)) { - trace_nvme_err_startfail_nbaracq(); + trace_pci_nvme_err_startfail_nbaracq(); return -1; } if (unlikely(n->bar.asq & (page_size - 1))) { - trace_nvme_err_startfail_asq_misaligned(n->bar.asq); + trace_pci_nvme_err_startfail_asq_misaligned(n->bar.asq); return -1; } if (unlikely(n->bar.acq & (page_size - 1))) { - trace_nvme_err_startfail_acq_misaligned(n->bar.acq); + trace_pci_nvme_err_startfail_acq_misaligned(n->bar.acq); return -1; } if (unlikely(NVME_CC_MPS(n->bar.cc) < NVME_CAP_MPSMIN(n->bar.cap))) { - trace_nvme_err_startfail_page_too_small( + trace_pci_nvme_err_startfail_page_too_small( NVME_CC_MPS(n->bar.cc), NVME_CAP_MPSMIN(n->bar.cap)); return -1; } if (unlikely(NVME_CC_MPS(n->bar.cc) > NVME_CAP_MPSMAX(n->bar.cap))) { - trace_nvme_err_startfail_page_too_large( + trace_pci_nvme_err_startfail_page_too_large( NVME_CC_MPS(n->bar.cc), NVME_CAP_MPSMAX(n->bar.cap)); return -1; } if (unlikely(NVME_CC_IOCQES(n->bar.cc) < NVME_CTRL_CQES_MIN(n->id_ctrl.cqes))) { - trace_nvme_err_startfail_cqent_too_small( + trace_pci_nvme_err_startfail_cqent_too_small( NVME_CC_IOCQES(n->bar.cc), NVME_CTRL_CQES_MIN(n->bar.cap)); return -1; } if (unlikely(NVME_CC_IOCQES(n->bar.cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes))) { - trace_nvme_err_startfail_cqent_too_large( + trace_pci_nvme_err_startfail_cqent_too_large( NVME_CC_IOCQES(n->bar.cc), NVME_CTRL_CQES_MAX(n->bar.cap)); return -1; } if (unlikely(NVME_CC_IOSQES(n->bar.cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes))) { - trace_nvme_err_startfail_sqent_too_small( + trace_pci_nvme_err_startfail_sqent_too_small( NVME_CC_IOSQES(n->bar.cc), NVME_CTRL_SQES_MIN(n->bar.cap)); return -1; } if (unlikely(NVME_CC_IOSQES(n->bar.cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes))) { - trace_nvme_err_startfail_sqent_too_large( + trace_pci_nvme_err_startfail_sqent_too_large( NVME_CC_IOSQES(n->bar.cc), NVME_CTRL_SQES_MAX(n->bar.cap)); return -1; } if (unlikely(!NVME_AQA_ASQS(n->bar.aqa))) { - trace_nvme_err_startfail_asqent_sz_zero(); + trace_pci_nvme_err_startfail_asqent_sz_zero(); return -1; } if (unlikely(!NVME_AQA_ACQS(n->bar.aqa))) { - trace_nvme_err_startfail_acqent_sz_zero(); + trace_pci_nvme_err_startfail_acqent_sz_zero(); return -1; } @@ -1031,14 +1031,14 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, unsigned size) { if (unlikely(offset & (sizeof(uint32_t) - 1))) { - NVME_GUEST_ERR(nvme_ub_mmiowr_misaligned32, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_misaligned32, "MMIO write not 32-bit aligned," " offset=0x%"PRIx64"", offset); /* should be ignored, fall through for now */ } if (unlikely(size < sizeof(uint32_t))) { - NVME_GUEST_ERR(nvme_ub_mmiowr_toosmall, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_toosmall, "MMIO write smaller than 32-bits," " offset=0x%"PRIx64", size=%u", offset, size); @@ -1048,32 +1048,30 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, switch (offset) { case 0xc: /* INTMS */ if (unlikely(msix_enabled(&(n->parent_obj)))) { - NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_intmask_with_msix, "undefined access to interrupt mask set" " when MSI-X is enabled"); /* should be ignored, fall through for now */ } n->bar.intms |= data & 0xffffffff; n->bar.intmc = n->bar.intms; - trace_nvme_mmio_intm_set(data & 0xffffffff, - n->bar.intmc); + trace_pci_nvme_mmio_intm_set(data & 0xffffffff, n->bar.intmc); nvme_irq_check(n); break; case 0x10: /* INTMC */ if (unlikely(msix_enabled(&(n->parent_obj)))) { - NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_intmask_with_msix, "undefined access to interrupt mask clr" " when MSI-X is enabled"); /* should be ignored, fall through for now */ } n->bar.intms &= ~(data & 0xffffffff); n->bar.intmc = n->bar.intms; - trace_nvme_mmio_intm_clr(data & 0xffffffff, - n->bar.intmc); + trace_pci_nvme_mmio_intm_clr(data & 0xffffffff, n->bar.intmc); nvme_irq_check(n); break; case 0x14: /* CC */ - trace_nvme_mmio_cfg(data & 0xffffffff); + trace_pci_nvme_mmio_cfg(data & 0xffffffff); /* Windows first sends data, then sends enable bit */ if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) && !NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc)) @@ -1084,42 +1082,42 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) { n->bar.cc = data; if (unlikely(nvme_start_ctrl(n))) { - trace_nvme_err_startfail(); + trace_pci_nvme_err_startfail(); n->bar.csts = NVME_CSTS_FAILED; } else { - trace_nvme_mmio_start_success(); + trace_pci_nvme_mmio_start_success(); n->bar.csts = NVME_CSTS_READY; } } else if (!NVME_CC_EN(data) && NVME_CC_EN(n->bar.cc)) { - trace_nvme_mmio_stopped(); + trace_pci_nvme_mmio_stopped(); nvme_clear_ctrl(n); n->bar.csts &= ~NVME_CSTS_READY; } if (NVME_CC_SHN(data) && !(NVME_CC_SHN(n->bar.cc))) { - trace_nvme_mmio_shutdown_set(); + trace_pci_nvme_mmio_shutdown_set(); nvme_clear_ctrl(n); n->bar.cc = data; n->bar.csts |= NVME_CSTS_SHST_COMPLETE; } else if (!NVME_CC_SHN(data) && NVME_CC_SHN(n->bar.cc)) { - trace_nvme_mmio_shutdown_cleared(); + trace_pci_nvme_mmio_shutdown_cleared(); n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE; n->bar.cc = data; } break; case 0x1C: /* CSTS */ if (data & (1 << 4)) { - NVME_GUEST_ERR(nvme_ub_mmiowr_ssreset_w1c_unsupported, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_ssreset_w1c_unsupported, "attempted to W1C CSTS.NSSRO" " but CAP.NSSRS is zero (not supported)"); } else if (data != 0) { - NVME_GUEST_ERR(nvme_ub_mmiowr_ro_csts, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_ro_csts, "attempted to set a read only bit" " of controller status"); } break; case 0x20: /* NSSR */ if (data == 0x4E564D65) { - trace_nvme_ub_mmiowr_ssreset_unsupported(); + trace_pci_nvme_ub_mmiowr_ssreset_unsupported(); } else { /* The spec says that writes of other values have no effect */ return; @@ -1127,55 +1125,55 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, break; case 0x24: /* AQA */ n->bar.aqa = data & 0xffffffff; - trace_nvme_mmio_aqattr(data & 0xffffffff); + trace_pci_nvme_mmio_aqattr(data & 0xffffffff); break; case 0x28: /* ASQ */ n->bar.asq = data; - trace_nvme_mmio_asqaddr(data); + trace_pci_nvme_mmio_asqaddr(data); break; case 0x2c: /* ASQ hi */ n->bar.asq |= data << 32; - trace_nvme_mmio_asqaddr_hi(data, n->bar.asq); + trace_pci_nvme_mmio_asqaddr_hi(data, n->bar.asq); break; case 0x30: /* ACQ */ - trace_nvme_mmio_acqaddr(data); + trace_pci_nvme_mmio_acqaddr(data); n->bar.acq = data; break; case 0x34: /* ACQ hi */ n->bar.acq |= data << 32; - trace_nvme_mmio_acqaddr_hi(data, n->bar.acq); + trace_pci_nvme_mmio_acqaddr_hi(data, n->bar.acq); break; case 0x38: /* CMBLOC */ - NVME_GUEST_ERR(nvme_ub_mmiowr_cmbloc_reserved, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_cmbloc_reserved, "invalid write to reserved CMBLOC" " when CMBSZ is zero, ignored"); return; case 0x3C: /* CMBSZ */ - NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_cmbsz_readonly, "invalid write to read only CMBSZ, ignored"); return; case 0xE00: /* PMRCAP */ - NVME_GUEST_ERR(nvme_ub_mmiowr_pmrcap_readonly, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrcap_readonly, "invalid write to PMRCAP register, ignored"); return; case 0xE04: /* TODO PMRCTL */ break; case 0xE08: /* PMRSTS */ - NVME_GUEST_ERR(nvme_ub_mmiowr_pmrsts_readonly, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrsts_readonly, "invalid write to PMRSTS register, ignored"); return; case 0xE0C: /* PMREBS */ - NVME_GUEST_ERR(nvme_ub_mmiowr_pmrebs_readonly, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrebs_readonly, "invalid write to PMREBS register, ignored"); return; case 0xE10: /* PMRSWTP */ - NVME_GUEST_ERR(nvme_ub_mmiowr_pmrswtp_readonly, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrswtp_readonly, "invalid write to PMRSWTP register, ignored"); return; case 0xE14: /* TODO PMRMSC */ break; default: - NVME_GUEST_ERR(nvme_ub_mmiowr_invalid, + NVME_GUEST_ERR(pci_nvme_ub_mmiowr_invalid, "invalid MMIO write," " offset=0x%"PRIx64", data=%"PRIx64"", offset, data); @@ -1190,12 +1188,12 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) uint64_t val = 0; if (unlikely(addr & (sizeof(uint32_t) - 1))) { - NVME_GUEST_ERR(nvme_ub_mmiord_misaligned32, + NVME_GUEST_ERR(pci_nvme_ub_mmiord_misaligned32, "MMIO read not 32-bit aligned," " offset=0x%"PRIx64"", addr); /* should RAZ, fall through for now */ } else if (unlikely(size < sizeof(uint32_t))) { - NVME_GUEST_ERR(nvme_ub_mmiord_toosmall, + NVME_GUEST_ERR(pci_nvme_ub_mmiord_toosmall, "MMIO read smaller than 32-bits," " offset=0x%"PRIx64"", addr); /* should RAZ, fall through for now */ @@ -1213,7 +1211,7 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) } memcpy(&val, ptr + addr, size); } else { - NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs, + NVME_GUEST_ERR(pci_nvme_ub_mmiord_invalid_ofs, "MMIO read beyond last register," " offset=0x%"PRIx64", returning 0", addr); } @@ -1226,7 +1224,7 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) uint32_t qid; if (unlikely(addr & ((1 << 2) - 1))) { - NVME_GUEST_ERR(nvme_ub_db_wr_misaligned, + NVME_GUEST_ERR(pci_nvme_ub_db_wr_misaligned, "doorbell write not 32-bit aligned," " offset=0x%"PRIx64", ignoring", addr); return; @@ -1241,7 +1239,7 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) qid = (addr - (0x1000 + (1 << 2))) >> 3; if (unlikely(nvme_check_cqid(n, qid))) { - NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cq, + NVME_GUEST_ERR(pci_nvme_ub_db_wr_invalid_cq, "completion queue doorbell write" " for nonexistent queue," " sqid=%"PRIu32", ignoring", qid); @@ -1250,7 +1248,7 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) cq = n->cq[qid]; if (unlikely(new_head >= cq->size)) { - NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cqhead, + NVME_GUEST_ERR(pci_nvme_ub_db_wr_invalid_cqhead, "completion queue doorbell write value" " beyond queue size, sqid=%"PRIu32"," " new_head=%"PRIu16", ignoring", @@ -1279,7 +1277,7 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) qid = (addr - 0x1000) >> 3; if (unlikely(nvme_check_sqid(n, qid))) { - NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sq, + NVME_GUEST_ERR(pci_nvme_ub_db_wr_invalid_sq, "submission queue doorbell write" " for nonexistent queue," " sqid=%"PRIu32", ignoring", qid); @@ -1288,7 +1286,7 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) sq = n->sq[qid]; if (unlikely(new_tail >= sq->size)) { - NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sqtail, + NVME_GUEST_ERR(pci_nvme_ub_db_wr_invalid_sqtail, "submission queue doorbell write value" " beyond queue size, sqid=%"PRIu32"," " new_tail=%"PRIu16", ignoring", diff --git a/hw/block/trace-events b/hw/block/trace-events index aca54bda14..958fcc5508 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -29,100 +29,100 @@ hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int t # nvme.c # nvme traces for successful events -nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u" -nvme_irq_pin(void) "pulsing IRQ pin" -nvme_irq_masked(void) "IRQ is masked" -nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64"" -nvme_rw(const char *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64"" -nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" -nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" -nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16"" -nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16"" -nvme_identify_ctrl(void) "identify controller" -nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16"" -nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16"" -nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s" -nvme_getfeat_numq(int result) "get feature number of queues, result=%d" -nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d" -nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64"" -nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64"" -nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64"" -nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64"" -nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64"" -nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64"" -nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64"" -nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64"" -nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" -nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" -nvme_mmio_start_success(void) "setting controller enable bit succeeded" -nvme_mmio_stopped(void) "cleared controller enable bit" -nvme_mmio_shutdown_set(void) "shutdown bit set" -nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" +pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u" +pci_nvme_irq_pin(void) "pulsing IRQ pin" +pci_nvme_irq_masked(void) "IRQ is masked" +pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64"" +pci_nvme_rw(const char *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64"" +pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" +pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" +pci_nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16"" +pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16"" +pci_nvme_identify_ctrl(void) "identify controller" +pci_nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16"" +pci_nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16"" +pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s" +pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d" +pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d" +pci_nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64"" +pci_nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64"" +pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64"" +pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64"" +pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64"" +pci_nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64"" +pci_nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64"" +pci_nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64"" +pci_nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" +pci_nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" +pci_nvme_mmio_start_success(void) "setting controller enable bit succeeded" +pci_nvme_mmio_stopped(void) "cleared controller enable bit" +pci_nvme_mmio_shutdown_set(void) "shutdown bit set" +pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" # nvme traces for error conditions -nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size" -nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64"" -nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64"" -nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred" -nvme_err_invalid_prp(void) "invalid PRP" -nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u" -nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8"" -nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8"" -nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64"" -nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16"" -nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16"" -nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16"" -nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16"" -nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64"" -nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16"" -nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16"" -nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16"" -nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16"" -nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16"" -nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64"" -nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16"" -nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16"" -nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16"" -nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32"" -nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32"" -nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues" -nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues" -nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null" -nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null" -nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64"" -nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64"" -nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u" -nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u" -nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u" -nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u" -nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u" -nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u" -nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero" -nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero" -nvme_err_startfail(void) "setting controller enable bit failed" +pci_nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size" +pci_nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64"" +pci_nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64"" +pci_nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred" +pci_nvme_err_invalid_prp(void) "invalid PRP" +pci_nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u" +pci_nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8"" +pci_nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8"" +pci_nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64"" +pci_nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16"" +pci_nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16"" +pci_nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16"" +pci_nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16"" +pci_nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64"" +pci_nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16"" +pci_nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16"" +pci_nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16"" +pci_nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16"" +pci_nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16"" +pci_nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64"" +pci_nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16"" +pci_nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16"" +pci_nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16"" +pci_nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32"" +pci_nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32"" +pci_nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues" +pci_nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues" +pci_nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null" +pci_nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null" +pci_nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64"" +pci_nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64"" +pci_nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u" +pci_nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u" +pci_nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u" +pci_nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u" +pci_nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u" +pci_nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u" +pci_nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero" +pci_nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero" +pci_nvme_err_startfail(void) "setting controller enable bit failed" # Traces for undefined behavior -nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64"" -nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u" -nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled" -nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status" -nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)" -nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)" -nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored" -nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored" -nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored" -nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored" -nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored" -nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored" -nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64"" -nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64"" -nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64"" -nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0" -nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring" -nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring" -nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring" -nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring" -nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring" +pci_nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64"" +pci_nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u" +pci_nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled" +pci_nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status" +pci_nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)" +pci_nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)" +pci_nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored" +pci_nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored" +pci_nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored" +pci_nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored" +pci_nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored" +pci_nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored" +pci_nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64"" +pci_nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64"" +pci_nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64"" +pci_nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0" +pci_nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring" +pci_nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring" +pci_nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring" +pci_nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring" +pci_nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring" # xen-block.c xen_block_realize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" From 4920786ee69595137cfae1834798e73f15b402d8 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:14 +0200 Subject: [PATCH 1348/2595] hw/block/nvme: remove superfluous breaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These break statements was left over when commit 3036a626e9ef ("nvme: add Get/Set Feature Timestamp support") was merged. Signed-off-by: Klaus Jensen Reviewed-by: Maxim Levitsky Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-4-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index e8f5c5ab82..0d3f8f345f 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -801,7 +801,6 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) break; case NVME_TIMESTAMP: return nvme_get_feature_timestamp(n, cmd); - break; default: trace_pci_nvme_err_invalid_getfeat(dw10); return NVME_INVALID_FIELD | NVME_DNR; @@ -845,11 +844,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) req->cqe.result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16)); break; - case NVME_TIMESTAMP: return nvme_set_feature_timestamp(n, cmd); - break; - default: trace_pci_nvme_err_invalid_setfeat(dw10); return NVME_INVALID_FIELD | NVME_DNR; From 1065abfbf1f82cb2f4c8666fde9fae1084222cf9 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:15 +0200 Subject: [PATCH 1349/2595] hw/block/nvme: move device parameters to separate struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move device configuration parameters to separate struct to make it explicit what is configurable and what is set internally. Signed-off-by: Klaus Jensen Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Message-Id: <20200609190333.59390-5-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 49 ++++++++++++++++++++++++++----------------------- hw/block/nvme.h | 11 ++++++++--- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 0d3f8f345f..bc2d9d2091 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -77,12 +77,12 @@ static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid) { - return sqid < n->num_queues && n->sq[sqid] != NULL ? 0 : -1; + return sqid < n->params.num_queues && n->sq[sqid] != NULL ? 0 : -1; } static int nvme_check_cqid(NvmeCtrl *n, uint16_t cqid) { - return cqid < n->num_queues && n->cq[cqid] != NULL ? 0 : -1; + return cqid < n->params.num_queues && n->cq[cqid] != NULL ? 0 : -1; } static void nvme_inc_cq_tail(NvmeCQueue *cq) @@ -644,7 +644,7 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd) trace_pci_nvme_err_invalid_create_cq_addr(prp1); return NVME_INVALID_FIELD | NVME_DNR; } - if (unlikely(vector > n->num_queues)) { + if (unlikely(vector > n->params.num_queues)) { trace_pci_nvme_err_invalid_create_cq_vector(vector); return NVME_INVALID_IRQ_VECTOR | NVME_DNR; } @@ -796,7 +796,8 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled"); break; case NVME_NUMBER_OF_QUEUES: - result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16)); + result = cpu_to_le32((n->params.num_queues - 2) | + ((n->params.num_queues - 2) << 16)); trace_pci_nvme_getfeat_numq(result); break; case NVME_TIMESTAMP: @@ -840,9 +841,10 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) case NVME_NUMBER_OF_QUEUES: trace_pci_nvme_setfeat_numq((dw11 & 0xFFFF) + 1, ((dw11 >> 16) & 0xFFFF) + 1, - n->num_queues - 1, n->num_queues - 1); - req->cqe.result = - cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16)); + n->params.num_queues - 1, + n->params.num_queues - 1); + req->cqe.result = cpu_to_le32((n->params.num_queues - 2) | + ((n->params.num_queues - 2) << 16)); break; case NVME_TIMESTAMP: return nvme_set_feature_timestamp(n, cmd); @@ -913,12 +915,12 @@ static void nvme_clear_ctrl(NvmeCtrl *n) blk_drain(n->conf.blk); - for (i = 0; i < n->num_queues; i++) { + for (i = 0; i < n->params.num_queues; i++) { if (n->sq[i] != NULL) { nvme_free_sq(n->sq[i], n); } } - for (i = 0; i < n->num_queues; i++) { + for (i = 0; i < n->params.num_queues; i++) { if (n->cq[i] != NULL) { nvme_free_cq(n->cq[i], n); } @@ -1348,7 +1350,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) int64_t bs_size; uint8_t *pci_conf; - if (!n->num_queues) { + if (!n->params.num_queues) { error_setg(errp, "num_queues can't be zero"); return; } @@ -1364,12 +1366,12 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) return; } - if (!n->serial) { + if (!n->params.serial) { error_setg(errp, "serial property not set"); return; } - if (!n->cmb_size_mb && n->pmrdev) { + if (!n->params.cmb_size_mb && n->pmrdev) { if (host_memory_backend_is_mapped(n->pmrdev)) { char *path = object_get_canonical_path_component(OBJECT(n->pmrdev)); error_setg(errp, "can't use already busy memdev: %s", path); @@ -1400,25 +1402,26 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) n->num_namespaces = 1; /* num_queues is really number of pairs, so each has two doorbells */ - n->reg_size = pow2ceil(NVME_REG_SIZE + 2 * n->num_queues * NVME_DB_SIZE); + n->reg_size = pow2ceil(NVME_REG_SIZE + + 2 * n->params.num_queues * NVME_DB_SIZE); n->ns_size = bs_size / (uint64_t)n->num_namespaces; n->namespaces = g_new0(NvmeNamespace, n->num_namespaces); - n->sq = g_new0(NvmeSQueue *, n->num_queues); - n->cq = g_new0(NvmeCQueue *, n->num_queues); + n->sq = g_new0(NvmeSQueue *, n->params.num_queues); + n->cq = g_new0(NvmeCQueue *, n->params.num_queues); memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n, "nvme", n->reg_size); pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, &n->iomem); - msix_init_exclusive_bar(pci_dev, n->num_queues, 4, NULL); + msix_init_exclusive_bar(pci_dev, n->params.num_queues, 4, NULL); id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); strpadcpy((char *)id->mn, sizeof(id->mn), "QEMU NVMe Ctrl", ' '); strpadcpy((char *)id->fr, sizeof(id->fr), "1.0", ' '); - strpadcpy((char *)id->sn, sizeof(id->sn), n->serial, ' '); + strpadcpy((char *)id->sn, sizeof(id->sn), n->params.serial, ' '); id->rab = 6; id->ieee[0] = 0x00; id->ieee[1] = 0x02; @@ -1447,7 +1450,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) n->bar.vs = 0x00010200; n->bar.intmc = n->bar.intms = 0; - if (n->cmb_size_mb) { + if (n->params.cmb_size_mb) { NVME_CMBLOC_SET_BIR(n->bar.cmbloc, 2); NVME_CMBLOC_SET_OFST(n->bar.cmbloc, 0); @@ -1458,7 +1461,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) NVME_CMBSZ_SET_RDS(n->bar.cmbsz, 1); NVME_CMBSZ_SET_WDS(n->bar.cmbsz, 1); NVME_CMBSZ_SET_SZU(n->bar.cmbsz, 2); /* MBs */ - NVME_CMBSZ_SET_SZ(n->bar.cmbsz, n->cmb_size_mb); + NVME_CMBSZ_SET_SZ(n->bar.cmbsz, n->params.cmb_size_mb); n->cmbloc = n->bar.cmbloc; n->cmbsz = n->bar.cmbsz; @@ -1542,7 +1545,7 @@ static void nvme_exit(PCIDevice *pci_dev) g_free(n->cq); g_free(n->sq); - if (n->cmb_size_mb) { + if (n->params.cmb_size_mb) { g_free(n->cmbuf); } @@ -1556,9 +1559,9 @@ static Property nvme_props[] = { DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf), DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND, HostMemoryBackend *), - DEFINE_PROP_STRING("serial", NvmeCtrl, serial), - DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0), - DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64), + DEFINE_PROP_STRING("serial", NvmeCtrl, params.serial), + DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, params.cmb_size_mb, 0), + DEFINE_PROP_UINT32("num_queues", NvmeCtrl, params.num_queues, 64), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 6520a9f0be..9df244c93c 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -1,7 +1,14 @@ #ifndef HW_NVME_H #define HW_NVME_H + #include "block/nvme.h" +typedef struct NvmeParams { + char *serial; + uint32_t num_queues; + uint32_t cmb_size_mb; +} NvmeParams; + typedef struct NvmeAsyncEvent { QSIMPLEQ_ENTRY(NvmeAsyncEvent) entry; NvmeAerResult result; @@ -63,6 +70,7 @@ typedef struct NvmeCtrl { MemoryRegion ctrl_mem; NvmeBar bar; BlockConf conf; + NvmeParams params; uint32_t page_size; uint16_t page_bits; @@ -71,10 +79,8 @@ typedef struct NvmeCtrl { uint16_t sqe_size; uint32_t reg_size; uint32_t num_namespaces; - uint32_t num_queues; uint32_t max_q_ents; uint64_t ns_size; - uint32_t cmb_size_mb; uint32_t cmbsz; uint32_t cmbloc; uint8_t *cmbuf; @@ -82,7 +88,6 @@ typedef struct NvmeCtrl { uint64_t host_timestamp; /* Timestamp sent by the host */ uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */ - char *serial; HostMemoryBackend *pmrdev; NvmeNamespace *namespaces; From 3e829fd438033cdf8646ec22bcc869555b100212 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:16 +0200 Subject: [PATCH 1350/2595] hw/block/nvme: use constants in identify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Klaus Jensen Reviewed-by: Maxim Levitsky Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-6-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 8 ++++---- include/block/nvme.h | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index bc2d9d2091..2a26b8859a 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -692,7 +692,7 @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c) static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c) { - static const int data_len = 4 * KiB; + static const int data_len = NVME_IDENTIFY_DATA_SIZE; uint32_t min_nsid = le32_to_cpu(c->nsid); uint64_t prp1 = le64_to_cpu(c->prp1); uint64_t prp2 = le64_to_cpu(c->prp2); @@ -722,11 +722,11 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd) NvmeIdentify *c = (NvmeIdentify *)cmd; switch (le32_to_cpu(c->cns)) { - case 0x00: + case NVME_ID_CNS_NS: return nvme_identify_ns(n, c); - case 0x01: + case NVME_ID_CNS_CTRL: return nvme_identify_ctrl(n, c); - case 0x02: + case NVME_ID_CNS_NS_ACTIVE_LIST: return nvme_identify_nslist(n, c); default: trace_pci_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns)); diff --git a/include/block/nvme.h b/include/block/nvme.h index 5525c8e343..1720ee1d51 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -705,6 +705,14 @@ typedef struct NvmePSD { uint8_t resv[16]; } NvmePSD; +#define NVME_IDENTIFY_DATA_SIZE 4096 + +enum { + NVME_ID_CNS_NS = 0x0, + NVME_ID_CNS_CTRL = 0x1, + NVME_ID_CNS_NS_ACTIVE_LIST = 0x2, +}; + typedef struct NvmeIdCtrl { uint16_t vid; uint16_t ssvid; From b4529c5c3af69189b65b22906a35b09a7fe17960 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:17 +0200 Subject: [PATCH 1351/2595] hw/block/nvme: refactor nvme_addr_read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull the controller memory buffer check to its own function. The check will be used on its own in later patches. Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-7-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 2a26b8859a..d6fcf078a4 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -65,14 +65,22 @@ static void nvme_process_sq(void *opaque); +static bool nvme_addr_is_cmb(NvmeCtrl *n, hwaddr addr) +{ + hwaddr low = n->ctrl_mem.addr; + hwaddr hi = n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size); + + return addr >= low && addr < hi; +} + static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) { - if (n->cmbsz && addr >= n->ctrl_mem.addr && - addr < (n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size))) { + if (n->cmbsz && nvme_addr_is_cmb(n, addr)) { memcpy(buf, (void *)&n->cmbuf[addr - n->ctrl_mem.addr], size); - } else { - pci_dma_read(&n->parent_obj, addr, buf, size); + return; } + + pci_dma_read(&n->parent_obj, addr, buf, size); } static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid) From ca247d35098d396db25233d5f554bd3098949d60 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:18 +0200 Subject: [PATCH 1352/2595] hw/block/nvme: fix pin-based interrupt behavior First, since the device only supports MSI-X or pin-based interrupt, if MSI-X is not enabled, it should not accept interrupt vectors different from 0 when creating completion queues. Secondly, the irq_status NvmeCtrl member is meant to be compared to the INTMS register, so it should only be 32 bits wide. And it is really only useful when used with multi-message MSI. Third, since we do not force a 1-to-1 correspondence between cqid and interrupt vector, the irq_status register should not have bits set according to cqid, but according to the associated interrupt vector. Fix these issues, but keep irq_status available so we can easily support multi-message MSI down the line. Fixes: 5e9aa92eb1a5 ("hw/block: Fix pin-based interrupt behaviour of NVMe") Cc: "Michael S. Tsirkin" Cc: Marcel Apfelbaum Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-8-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 12 ++++++++---- hw/block/nvme.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index d6fcf078a4..ee514625ee 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -137,8 +137,8 @@ static void nvme_irq_assert(NvmeCtrl *n, NvmeCQueue *cq) msix_notify(&(n->parent_obj), cq->vector); } else { trace_pci_nvme_irq_pin(); - assert(cq->cqid < 64); - n->irq_status |= 1 << cq->cqid; + assert(cq->vector < 32); + n->irq_status |= 1 << cq->vector; nvme_irq_check(n); } } else { @@ -152,8 +152,8 @@ static void nvme_irq_deassert(NvmeCtrl *n, NvmeCQueue *cq) if (msix_enabled(&(n->parent_obj))) { return; } else { - assert(cq->cqid < 64); - n->irq_status &= ~(1 << cq->cqid); + assert(cq->vector < 32); + n->irq_status &= ~(1 << cq->vector); nvme_irq_check(n); } } @@ -652,6 +652,10 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd) trace_pci_nvme_err_invalid_create_cq_addr(prp1); return NVME_INVALID_FIELD | NVME_DNR; } + if (unlikely(!msix_enabled(&n->parent_obj) && vector)) { + trace_pci_nvme_err_invalid_create_cq_vector(vector); + return NVME_INVALID_IRQ_VECTOR | NVME_DNR; + } if (unlikely(vector > n->params.num_queues)) { trace_pci_nvme_err_invalid_create_cq_vector(vector); return NVME_INVALID_IRQ_VECTOR | NVME_DNR; diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 9df244c93c..91f16c8125 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -84,7 +84,7 @@ typedef struct NvmeCtrl { uint32_t cmbsz; uint32_t cmbloc; uint8_t *cmbuf; - uint64_t irq_status; + uint32_t irq_status; uint64_t host_timestamp; /* Timestamp sent by the host */ uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */ From dce22c864612659793342bb99bd3d7a91f31afd6 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:19 +0200 Subject: [PATCH 1353/2595] hw/block/nvme: add max_ioqpairs device parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The num_queues device paramater has a slightly confusing meaning because it accounts for the admin queue pair which is not really optional. Secondly, it is really a maximum value of queues allowed. Add a new max_ioqpairs parameter that only accounts for I/O queue pairs, but keep num_queues for compatibility. Signed-off-by: Klaus Jensen Reviewed-by: Maxim Levitsky Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-9-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 51 ++++++++++++++++++++++++++++++------------------- hw/block/nvme.h | 3 ++- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index ee514625ee..1c1d2f8b77 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -20,7 +20,7 @@ * -device nvme,drive=,serial=,id=, \ * cmb_size_mb=, \ * [pmrdev=,] \ - * num_queues= + * max_ioqpairs= * * Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at * offset 0 in BAR2 and supports only WDS, RDS and SQS for now. @@ -36,6 +36,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" +#include "qemu/error-report.h" #include "hw/block/block.h" #include "hw/pci/msix.h" #include "hw/pci/pci.h" @@ -85,12 +86,12 @@ static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid) { - return sqid < n->params.num_queues && n->sq[sqid] != NULL ? 0 : -1; + return sqid < n->params.max_ioqpairs + 1 && n->sq[sqid] != NULL ? 0 : -1; } static int nvme_check_cqid(NvmeCtrl *n, uint16_t cqid) { - return cqid < n->params.num_queues && n->cq[cqid] != NULL ? 0 : -1; + return cqid < n->params.max_ioqpairs + 1 && n->cq[cqid] != NULL ? 0 : -1; } static void nvme_inc_cq_tail(NvmeCQueue *cq) @@ -656,7 +657,7 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd) trace_pci_nvme_err_invalid_create_cq_vector(vector); return NVME_INVALID_IRQ_VECTOR | NVME_DNR; } - if (unlikely(vector > n->params.num_queues)) { + if (unlikely(vector > n->params.max_ioqpairs)) { trace_pci_nvme_err_invalid_create_cq_vector(vector); return NVME_INVALID_IRQ_VECTOR | NVME_DNR; } @@ -808,8 +809,8 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled"); break; case NVME_NUMBER_OF_QUEUES: - result = cpu_to_le32((n->params.num_queues - 2) | - ((n->params.num_queues - 2) << 16)); + result = cpu_to_le32((n->params.max_ioqpairs - 1) | + ((n->params.max_ioqpairs - 1) << 16)); trace_pci_nvme_getfeat_numq(result); break; case NVME_TIMESTAMP: @@ -853,10 +854,10 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) case NVME_NUMBER_OF_QUEUES: trace_pci_nvme_setfeat_numq((dw11 & 0xFFFF) + 1, ((dw11 >> 16) & 0xFFFF) + 1, - n->params.num_queues - 1, - n->params.num_queues - 1); - req->cqe.result = cpu_to_le32((n->params.num_queues - 2) | - ((n->params.num_queues - 2) << 16)); + n->params.max_ioqpairs, + n->params.max_ioqpairs); + req->cqe.result = cpu_to_le32((n->params.max_ioqpairs - 1) | + ((n->params.max_ioqpairs - 1) << 16)); break; case NVME_TIMESTAMP: return nvme_set_feature_timestamp(n, cmd); @@ -927,12 +928,12 @@ static void nvme_clear_ctrl(NvmeCtrl *n) blk_drain(n->conf.blk); - for (i = 0; i < n->params.num_queues; i++) { + for (i = 0; i < n->params.max_ioqpairs + 1; i++) { if (n->sq[i] != NULL) { nvme_free_sq(n->sq[i], n); } } - for (i = 0; i < n->params.num_queues; i++) { + for (i = 0; i < n->params.max_ioqpairs + 1; i++) { if (n->cq[i] != NULL) { nvme_free_cq(n->cq[i], n); } @@ -1362,8 +1363,17 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) int64_t bs_size; uint8_t *pci_conf; - if (!n->params.num_queues) { - error_setg(errp, "num_queues can't be zero"); + if (n->params.num_queues) { + warn_report("num_queues is deprecated; please use max_ioqpairs " + "instead"); + + n->params.max_ioqpairs = n->params.num_queues - 1; + } + + if (n->params.max_ioqpairs < 1 || + n->params.max_ioqpairs > PCI_MSIX_FLAGS_QSIZE) { + error_setg(errp, "max_ioqpairs must be between 1 and %d", + PCI_MSIX_FLAGS_QSIZE); return; } @@ -1413,21 +1423,21 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) n->num_namespaces = 1; - /* num_queues is really number of pairs, so each has two doorbells */ + /* add one to max_ioqpairs to account for the admin queue pair */ n->reg_size = pow2ceil(NVME_REG_SIZE + - 2 * n->params.num_queues * NVME_DB_SIZE); + 2 * (n->params.max_ioqpairs + 1) * NVME_DB_SIZE); n->ns_size = bs_size / (uint64_t)n->num_namespaces; n->namespaces = g_new0(NvmeNamespace, n->num_namespaces); - n->sq = g_new0(NvmeSQueue *, n->params.num_queues); - n->cq = g_new0(NvmeCQueue *, n->params.num_queues); + n->sq = g_new0(NvmeSQueue *, n->params.max_ioqpairs + 1); + n->cq = g_new0(NvmeCQueue *, n->params.max_ioqpairs + 1); memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n, "nvme", n->reg_size); pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, &n->iomem); - msix_init_exclusive_bar(pci_dev, n->params.num_queues, 4, NULL); + msix_init_exclusive_bar(pci_dev, n->params.max_ioqpairs + 1, 4, NULL); id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); @@ -1573,7 +1583,8 @@ static Property nvme_props[] = { HostMemoryBackend *), DEFINE_PROP_STRING("serial", NvmeCtrl, params.serial), DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, params.cmb_size_mb, 0), - DEFINE_PROP_UINT32("num_queues", NvmeCtrl, params.num_queues, 64), + DEFINE_PROP_UINT32("num_queues", NvmeCtrl, params.num_queues, 0), + DEFINE_PROP_UINT32("max_ioqpairs", NvmeCtrl, params.max_ioqpairs, 64), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 91f16c8125..26c38bd913 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -5,7 +5,8 @@ typedef struct NvmeParams { char *serial; - uint32_t num_queues; + uint32_t num_queues; /* deprecated since 5.1 */ + uint32_t max_ioqpairs; uint32_t cmb_size_mb; } NvmeParams; From e1731e816ad201273ed284fbb9cd51db131fd196 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:20 +0200 Subject: [PATCH 1354/2595] hw/block/nvme: remove redundant cmbloc/cmbsz members MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-10-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 7 ++----- hw/block/nvme.h | 2 -- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 1c1d2f8b77..61447220a8 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -76,7 +76,7 @@ static bool nvme_addr_is_cmb(NvmeCtrl *n, hwaddr addr) static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) { - if (n->cmbsz && nvme_addr_is_cmb(n, addr)) { + if (n->bar.cmbsz && nvme_addr_is_cmb(n, addr)) { memcpy(buf, (void *)&n->cmbuf[addr - n->ctrl_mem.addr], size); return; } @@ -170,7 +170,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, if (unlikely(!prp1)) { trace_pci_nvme_err_invalid_prp(); return NVME_INVALID_FIELD | NVME_DNR; - } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr && + } else if (n->bar.cmbsz && prp1 >= n->ctrl_mem.addr && prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) { qsg->nsg = 0; qemu_iovec_init(iov, num_prps); @@ -1485,9 +1485,6 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) NVME_CMBSZ_SET_SZU(n->bar.cmbsz, 2); /* MBs */ NVME_CMBSZ_SET_SZ(n->bar.cmbsz, n->params.cmb_size_mb); - n->cmbloc = n->bar.cmbloc; - n->cmbsz = n->bar.cmbsz; - n->cmbuf = g_malloc0(NVME_CMBSZ_GETSIZE(n->bar.cmbsz)); memory_region_init_io(&n->ctrl_mem, OBJECT(n), &nvme_cmb_ops, n, "nvme-cmb", NVME_CMBSZ_GETSIZE(n->bar.cmbsz)); diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 26c38bd913..cedc8022db 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -82,8 +82,6 @@ typedef struct NvmeCtrl { uint32_t num_namespaces; uint32_t max_q_ents; uint64_t ns_size; - uint32_t cmbsz; - uint32_t cmbloc; uint8_t *cmbuf; uint32_t irq_status; uint64_t host_timestamp; /* Timestamp sent by the host */ From 54000c66f050ab2aec180e0822c09523057448e7 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:21 +0200 Subject: [PATCH 1355/2595] hw/block/nvme: factor out property/constraint checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-11-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 61447220a8..ee669ee8dc 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1354,24 +1354,19 @@ static const MemoryRegionOps nvme_cmb_ops = { }, }; -static void nvme_realize(PCIDevice *pci_dev, Error **errp) +static void nvme_check_constraints(NvmeCtrl *n, Error **errp) { - NvmeCtrl *n = NVME(pci_dev); - NvmeIdCtrl *id = &n->id_ctrl; + NvmeParams *params = &n->params; - int i; - int64_t bs_size; - uint8_t *pci_conf; - - if (n->params.num_queues) { + if (params->num_queues) { warn_report("num_queues is deprecated; please use max_ioqpairs " "instead"); - n->params.max_ioqpairs = n->params.num_queues - 1; + params->max_ioqpairs = params->num_queues - 1; } - if (n->params.max_ioqpairs < 1 || - n->params.max_ioqpairs > PCI_MSIX_FLAGS_QSIZE) { + if (params->max_ioqpairs < 1 || + params->max_ioqpairs > PCI_MSIX_FLAGS_QSIZE) { error_setg(errp, "max_ioqpairs must be between 1 and %d", PCI_MSIX_FLAGS_QSIZE); return; @@ -1382,13 +1377,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) return; } - bs_size = blk_getlength(n->conf.blk); - if (bs_size < 0) { - error_setg(errp, "could not get backing file size"); - return; - } - - if (!n->params.serial) { + if (!params->serial) { error_setg(errp, "serial property not set"); return; } @@ -1408,6 +1397,29 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) host_memory_backend_set_mapped(n->pmrdev, true); } +} + +static void nvme_realize(PCIDevice *pci_dev, Error **errp) +{ + NvmeCtrl *n = NVME(pci_dev); + NvmeIdCtrl *id = &n->id_ctrl; + Error *local_err = NULL; + + int i; + int64_t bs_size; + uint8_t *pci_conf; + + nvme_check_constraints(n, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + bs_size = blk_getlength(n->conf.blk); + if (bs_size < 0) { + error_setg(errp, "could not get backing file size"); + return; + } blkconf_blocksizes(&n->conf); if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk), From a17f50188bfe0a59e96745a823d309ae2de39f10 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:22 +0200 Subject: [PATCH 1356/2595] hw/block/nvme: factor out device state setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-12-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index ee669ee8dc..b721cab9b0 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1399,6 +1399,17 @@ static void nvme_check_constraints(NvmeCtrl *n, Error **errp) } } +static void nvme_init_state(NvmeCtrl *n) +{ + n->num_namespaces = 1; + /* add one to max_ioqpairs to account for the admin queue pair */ + n->reg_size = pow2ceil(NVME_REG_SIZE + + 2 * (n->params.max_ioqpairs + 1) * NVME_DB_SIZE); + n->namespaces = g_new0(NvmeNamespace, n->num_namespaces); + n->sq = g_new0(NvmeSQueue *, n->params.max_ioqpairs + 1); + n->cq = g_new0(NvmeCQueue *, n->params.max_ioqpairs + 1); +} + static void nvme_realize(PCIDevice *pci_dev, Error **errp) { NvmeCtrl *n = NVME(pci_dev); @@ -1415,6 +1426,8 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) return; } + nvme_init_state(n); + bs_size = blk_getlength(n->conf.blk); if (bs_size < 0) { error_setg(errp, "could not get backing file size"); @@ -1433,17 +1446,8 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) pci_config_set_class(pci_dev->config, PCI_CLASS_STORAGE_EXPRESS); pcie_endpoint_cap_init(pci_dev, 0x80); - n->num_namespaces = 1; - - /* add one to max_ioqpairs to account for the admin queue pair */ - n->reg_size = pow2ceil(NVME_REG_SIZE + - 2 * (n->params.max_ioqpairs + 1) * NVME_DB_SIZE); n->ns_size = bs_size / (uint64_t)n->num_namespaces; - n->namespaces = g_new0(NvmeNamespace, n->num_namespaces); - n->sq = g_new0(NvmeSQueue *, n->params.max_ioqpairs + 1); - n->cq = g_new0(NvmeCQueue *, n->params.max_ioqpairs + 1); - memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n, "nvme", n->reg_size); pci_register_bar(pci_dev, 0, From 90f4511543748de94bb34c250deab865f4018128 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:23 +0200 Subject: [PATCH 1357/2595] hw/block/nvme: factor out block backend setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-13-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index b721cab9b0..87f1f0d0d1 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1410,6 +1410,13 @@ static void nvme_init_state(NvmeCtrl *n) n->cq = g_new0(NvmeCQueue *, n->params.max_ioqpairs + 1); } +static void nvme_init_blk(NvmeCtrl *n, Error **errp) +{ + blkconf_blocksizes(&n->conf); + blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk), + false, errp); +} + static void nvme_realize(PCIDevice *pci_dev, Error **errp) { NvmeCtrl *n = NVME(pci_dev); @@ -1434,9 +1441,9 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) return; } - blkconf_blocksizes(&n->conf); - if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk), - false, errp)) { + nvme_init_blk(n, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } From 3adee1c2d3c443e49fffe995b424932dda577a3a Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:24 +0200 Subject: [PATCH 1358/2595] hw/block/nvme: add namespace helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce some small helpers to make the next patches easier on the eye. Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-14-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 3 +-- hw/block/nvme.h | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 87f1f0d0d1..3f3db17231 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1573,8 +1573,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) id_ns->dps = 0; id_ns->lbaf[0].ds = BDRV_SECTOR_BITS; id_ns->ncap = id_ns->nuse = id_ns->nsze = - cpu_to_le64(n->ns_size >> - id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas)].ds); + cpu_to_le64(nvme_ns_nlbas(n, ns)); } } diff --git a/hw/block/nvme.h b/hw/block/nvme.h index cedc8022db..61dd9b23b8 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -61,6 +61,17 @@ typedef struct NvmeNamespace { NvmeIdNs id_ns; } NvmeNamespace; +static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns) +{ + NvmeIdNs *id_ns = &ns->id_ns; + return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; +} + +static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns) +{ + return nvme_ns_lbaf(ns)->ds; +} + #define TYPE_NVME "nvme" #define NVME(obj) \ OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME) @@ -97,4 +108,10 @@ typedef struct NvmeCtrl { NvmeIdCtrl id_ctrl; } NvmeCtrl; +/* calculate the number of LBAs that the namespace can accomodate */ +static inline uint64_t nvme_ns_nlbas(NvmeCtrl *n, NvmeNamespace *ns) +{ + return n->ns_size >> nvme_ns_lbads(ns); +} + #endif /* HW_NVME_H */ From d634d74229c413dfdf7383bc943b8dcf0e22e9a1 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:25 +0200 Subject: [PATCH 1359/2595] hw/block/nvme: factor out namespace setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-15-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 3f3db17231..c98af03f44 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1417,6 +1417,27 @@ static void nvme_init_blk(NvmeCtrl *n, Error **errp) false, errp); } +static void nvme_init_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) +{ + int64_t bs_size; + NvmeIdNs *id_ns = &ns->id_ns; + + bs_size = blk_getlength(n->conf.blk); + if (bs_size < 0) { + error_setg_errno(errp, -bs_size, "could not get backing file size"); + return; + } + + n->ns_size = bs_size; + + id_ns->lbaf[0].ds = BDRV_SECTOR_BITS; + id_ns->nsze = cpu_to_le64(nvme_ns_nlbas(n, ns)); + + /* no thin provisioning */ + id_ns->ncap = id_ns->nsze; + id_ns->nuse = id_ns->ncap; +} + static void nvme_realize(PCIDevice *pci_dev, Error **errp) { NvmeCtrl *n = NVME(pci_dev); @@ -1424,7 +1445,6 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) Error *local_err = NULL; int i; - int64_t bs_size; uint8_t *pci_conf; nvme_check_constraints(n, &local_err); @@ -1435,12 +1455,6 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) nvme_init_state(n); - bs_size = blk_getlength(n->conf.blk); - if (bs_size < 0) { - error_setg(errp, "could not get backing file size"); - return; - } - nvme_init_blk(n, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -1453,8 +1467,6 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) pci_config_set_class(pci_dev->config, PCI_CLASS_STORAGE_EXPRESS); pcie_endpoint_cap_init(pci_dev, 0x80); - n->ns_size = bs_size / (uint64_t)n->num_namespaces; - memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n, "nvme", n->reg_size); pci_register_bar(pci_dev, 0, @@ -1563,17 +1575,11 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) } for (i = 0; i < n->num_namespaces; i++) { - NvmeNamespace *ns = &n->namespaces[i]; - NvmeIdNs *id_ns = &ns->id_ns; - id_ns->nsfeat = 0; - id_ns->nlbaf = 0; - id_ns->flbas = 0; - id_ns->mc = 0; - id_ns->dpc = 0; - id_ns->dps = 0; - id_ns->lbaf[0].ds = BDRV_SECTOR_BITS; - id_ns->ncap = id_ns->nuse = id_ns->nsze = - cpu_to_le64(nvme_ns_nlbas(n, ns)); + nvme_init_namespace(n, &n->namespaces[i], &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } } } From c3f5526d221c63a3278aefcba1415fa966fad615 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:26 +0200 Subject: [PATCH 1360/2595] hw/block/nvme: factor out pci setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-16-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index c98af03f44..a4022b0291 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1438,6 +1438,22 @@ static void nvme_init_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) id_ns->nuse = id_ns->ncap; } +static void nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev) +{ + uint8_t *pci_conf = pci_dev->config; + + pci_conf[PCI_INTERRUPT_PIN] = 1; + pci_config_set_prog_interface(pci_conf, 0x2); + pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_EXPRESS); + pcie_endpoint_cap_init(pci_dev, 0x80); + + memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n, "nvme", + n->reg_size); + pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64, &n->iomem); + msix_init_exclusive_bar(pci_dev, n->params.max_ioqpairs + 1, 4, NULL); +} + static void nvme_realize(PCIDevice *pci_dev, Error **errp) { NvmeCtrl *n = NVME(pci_dev); @@ -1461,19 +1477,9 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) return; } + nvme_init_pci(n, pci_dev); + pci_conf = pci_dev->config; - pci_conf[PCI_INTERRUPT_PIN] = 1; - pci_config_set_prog_interface(pci_dev->config, 0x2); - pci_config_set_class(pci_dev->config, PCI_CLASS_STORAGE_EXPRESS); - pcie_endpoint_cap_init(pci_dev, 0x80); - - memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n, - "nvme", n->reg_size); - pci_register_bar(pci_dev, 0, - PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, - &n->iomem); - msix_init_exclusive_bar(pci_dev, n->params.max_ioqpairs + 1, 4, NULL); - id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); strpadcpy((char *)id->mn, sizeof(id->mn), "QEMU NVMe Ctrl", ' '); From 51ec094d4017eb61d8d92b8eb64343b013d9f90f Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:27 +0200 Subject: [PATCH 1361/2595] hw/block/nvme: factor out cmb setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-17-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index a4022b0291..8aabb4c3c3 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -56,6 +56,7 @@ #define NVME_REG_SIZE 0x1000 #define NVME_DB_SIZE 4 +#define NVME_CMB_BIR 2 #define NVME_GUEST_ERR(trace, fmt, ...) \ do { \ @@ -1438,6 +1439,28 @@ static void nvme_init_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) id_ns->nuse = id_ns->ncap; } +static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev) +{ + NVME_CMBLOC_SET_BIR(n->bar.cmbloc, NVME_CMB_BIR); + NVME_CMBLOC_SET_OFST(n->bar.cmbloc, 0); + + NVME_CMBSZ_SET_SQS(n->bar.cmbsz, 1); + NVME_CMBSZ_SET_CQS(n->bar.cmbsz, 0); + NVME_CMBSZ_SET_LISTS(n->bar.cmbsz, 0); + NVME_CMBSZ_SET_RDS(n->bar.cmbsz, 1); + NVME_CMBSZ_SET_WDS(n->bar.cmbsz, 1); + NVME_CMBSZ_SET_SZU(n->bar.cmbsz, 2); /* MBs */ + NVME_CMBSZ_SET_SZ(n->bar.cmbsz, n->params.cmb_size_mb); + + n->cmbuf = g_malloc0(NVME_CMBSZ_GETSIZE(n->bar.cmbsz)); + memory_region_init_io(&n->ctrl_mem, OBJECT(n), &nvme_cmb_ops, n, + "nvme-cmb", NVME_CMBSZ_GETSIZE(n->bar.cmbsz)); + pci_register_bar(pci_dev, NVME_CMBLOC_BIR(n->bar.cmbloc), + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64 | + PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem); +} + static void nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev) { uint8_t *pci_conf = pci_dev->config; @@ -1514,25 +1537,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) n->bar.intmc = n->bar.intms = 0; if (n->params.cmb_size_mb) { - - NVME_CMBLOC_SET_BIR(n->bar.cmbloc, 2); - NVME_CMBLOC_SET_OFST(n->bar.cmbloc, 0); - - NVME_CMBSZ_SET_SQS(n->bar.cmbsz, 1); - NVME_CMBSZ_SET_CQS(n->bar.cmbsz, 0); - NVME_CMBSZ_SET_LISTS(n->bar.cmbsz, 0); - NVME_CMBSZ_SET_RDS(n->bar.cmbsz, 1); - NVME_CMBSZ_SET_WDS(n->bar.cmbsz, 1); - NVME_CMBSZ_SET_SZU(n->bar.cmbsz, 2); /* MBs */ - NVME_CMBSZ_SET_SZ(n->bar.cmbsz, n->params.cmb_size_mb); - - n->cmbuf = g_malloc0(NVME_CMBSZ_GETSIZE(n->bar.cmbsz)); - memory_region_init_io(&n->ctrl_mem, OBJECT(n), &nvme_cmb_ops, n, - "nvme-cmb", NVME_CMBSZ_GETSIZE(n->bar.cmbsz)); - pci_register_bar(pci_dev, NVME_CMBLOC_BIR(n->bar.cmbloc), - PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 | - PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem); - + nvme_init_cmb(n, pci_dev); } else if (n->pmrdev) { /* Controller Capabilities register */ NVME_CAP_SET_PMRS(n->bar.cap, 1); From 37712e00b1f0ef157a71c0ad211bb4bf47efc9b8 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:28 +0200 Subject: [PATCH 1362/2595] hw/block/nvme: factor out pmr setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Klaus Jensen Reviewed-by: Maxim Levitsky Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200609190333.59390-18-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 95 ++++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 8aabb4c3c3..b954e7b7b2 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -57,6 +57,7 @@ #define NVME_REG_SIZE 0x1000 #define NVME_DB_SIZE 4 #define NVME_CMB_BIR 2 +#define NVME_PMR_BIR 2 #define NVME_GUEST_ERR(trace, fmt, ...) \ do { \ @@ -1461,6 +1462,55 @@ static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev) PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem); } +static void nvme_init_pmr(NvmeCtrl *n, PCIDevice *pci_dev) +{ + /* Controller Capabilities register */ + NVME_CAP_SET_PMRS(n->bar.cap, 1); + + /* PMR Capabities register */ + n->bar.pmrcap = 0; + NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 0); + NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 0); + NVME_PMRCAP_SET_BIR(n->bar.pmrcap, NVME_PMR_BIR); + NVME_PMRCAP_SET_PMRTU(n->bar.pmrcap, 0); + /* Turn on bit 1 support */ + NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02); + NVME_PMRCAP_SET_PMRTO(n->bar.pmrcap, 0); + NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 0); + + /* PMR Control register */ + n->bar.pmrctl = 0; + NVME_PMRCTL_SET_EN(n->bar.pmrctl, 0); + + /* PMR Status register */ + n->bar.pmrsts = 0; + NVME_PMRSTS_SET_ERR(n->bar.pmrsts, 0); + NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 0); + NVME_PMRSTS_SET_HSTS(n->bar.pmrsts, 0); + NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 0); + + /* PMR Elasticity Buffer Size register */ + n->bar.pmrebs = 0; + NVME_PMREBS_SET_PMRSZU(n->bar.pmrebs, 0); + NVME_PMREBS_SET_RBB(n->bar.pmrebs, 0); + NVME_PMREBS_SET_PMRWBZ(n->bar.pmrebs, 0); + + /* PMR Sustained Write Throughput register */ + n->bar.pmrswtp = 0; + NVME_PMRSWTP_SET_PMRSWTU(n->bar.pmrswtp, 0); + NVME_PMRSWTP_SET_PMRSWTV(n->bar.pmrswtp, 0); + + /* PMR Memory Space Control register */ + n->bar.pmrmsc = 0; + NVME_PMRMSC_SET_CMSE(n->bar.pmrmsc, 0); + NVME_PMRMSC_SET_CBA(n->bar.pmrmsc, 0); + + pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap), + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64 | + PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr); +} + static void nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev) { uint8_t *pci_conf = pci_dev->config; @@ -1539,50 +1589,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) if (n->params.cmb_size_mb) { nvme_init_cmb(n, pci_dev); } else if (n->pmrdev) { - /* Controller Capabilities register */ - NVME_CAP_SET_PMRS(n->bar.cap, 1); - - /* PMR Capabities register */ - n->bar.pmrcap = 0; - NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 0); - NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 0); - NVME_PMRCAP_SET_BIR(n->bar.pmrcap, 2); - NVME_PMRCAP_SET_PMRTU(n->bar.pmrcap, 0); - /* Turn on bit 1 support */ - NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02); - NVME_PMRCAP_SET_PMRTO(n->bar.pmrcap, 0); - NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 0); - - /* PMR Control register */ - n->bar.pmrctl = 0; - NVME_PMRCTL_SET_EN(n->bar.pmrctl, 0); - - /* PMR Status register */ - n->bar.pmrsts = 0; - NVME_PMRSTS_SET_ERR(n->bar.pmrsts, 0); - NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 0); - NVME_PMRSTS_SET_HSTS(n->bar.pmrsts, 0); - NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 0); - - /* PMR Elasticity Buffer Size register */ - n->bar.pmrebs = 0; - NVME_PMREBS_SET_PMRSZU(n->bar.pmrebs, 0); - NVME_PMREBS_SET_RBB(n->bar.pmrebs, 0); - NVME_PMREBS_SET_PMRWBZ(n->bar.pmrebs, 0); - - /* PMR Sustained Write Throughput register */ - n->bar.pmrswtp = 0; - NVME_PMRSWTP_SET_PMRSWTU(n->bar.pmrswtp, 0); - NVME_PMRSWTP_SET_PMRSWTV(n->bar.pmrswtp, 0); - - /* PMR Memory Space Control register */ - n->bar.pmrmsc = 0; - NVME_PMRMSC_SET_CMSE(n->bar.pmrmsc, 0); - NVME_PMRMSC_SET_CBA(n->bar.pmrmsc, 0); - - pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap), - PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 | - PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr); + nvme_init_pmr(n, pci_dev); } for (i = 0; i < n->num_namespaces; i++) { From 0c35ad46b6ffec663f94e0ef47b8df856e180f98 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:29 +0200 Subject: [PATCH 1363/2595] hw/block/nvme: do cmb/pmr init as part of pci init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Klaus Jensen Reviewed-by: Maxim Levitsky Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200609190333.59390-19-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index b954e7b7b2..02a6a97df9 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1525,6 +1525,12 @@ static void nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev) pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, &n->iomem); msix_init_exclusive_bar(pci_dev, n->params.max_ioqpairs + 1, 4, NULL); + + if (n->params.cmb_size_mb) { + nvme_init_cmb(n, pci_dev); + } else if (n->pmrdev) { + nvme_init_pmr(n, pci_dev); + } } static void nvme_realize(PCIDevice *pci_dev, Error **errp) @@ -1586,12 +1592,6 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) n->bar.vs = 0x00010200; n->bar.intmc = n->bar.intms = 0; - if (n->params.cmb_size_mb) { - nvme_init_cmb(n, pci_dev); - } else if (n->pmrdev) { - nvme_init_pmr(n, pci_dev); - } - for (i = 0; i < n->num_namespaces; i++) { nvme_init_namespace(n, &n->namespaces[i], &local_err); if (local_err) { From 945cb8f4c20e01241ede4ab33593d18812a3c1e4 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:30 +0200 Subject: [PATCH 1364/2595] hw/block/nvme: factor out controller identify setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maxim Levitsky Reviewed-by: Keith Busch Message-Id: <20200609190333.59390-20-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 02a6a97df9..e10fc774fc 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1533,32 +1533,11 @@ static void nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev) } } -static void nvme_realize(PCIDevice *pci_dev, Error **errp) +static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) { - NvmeCtrl *n = NVME(pci_dev); NvmeIdCtrl *id = &n->id_ctrl; - Error *local_err = NULL; + uint8_t *pci_conf = pci_dev->config; - int i; - uint8_t *pci_conf; - - nvme_check_constraints(n, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - nvme_init_state(n); - - nvme_init_blk(n, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - nvme_init_pci(n, pci_dev); - - pci_conf = pci_dev->config; id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); strpadcpy((char *)id->mn, sizeof(id->mn), "QEMU NVMe Ctrl", ' '); @@ -1591,6 +1570,30 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) n->bar.vs = 0x00010200; n->bar.intmc = n->bar.intms = 0; +} + +static void nvme_realize(PCIDevice *pci_dev, Error **errp) +{ + NvmeCtrl *n = NVME(pci_dev); + Error *local_err = NULL; + + int i; + + nvme_check_constraints(n, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + nvme_init_state(n); + nvme_init_blk(n, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + nvme_init_pci(n, pci_dev); + nvme_init_ctrl(n, pci_dev); for (i = 0; i < n->num_namespaces; i++) { nvme_init_namespace(n, &n->namespaces[i], &local_err); From fbf2e5375e33d43c9e1386eed448e1a3c0996e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 9 Jun 2020 21:03:31 +0200 Subject: [PATCH 1365/2595] hw/block/nvme: Verify msix_vector_use() returned value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msix_vector_use() returns -EINVAL on error. Assert it won't. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200609190333.59390-21-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index e10fc774fc..fe17aa5d70 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -615,6 +615,10 @@ static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd) static void nvme_init_cq(NvmeCQueue *cq, NvmeCtrl *n, uint64_t dma_addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t irq_enabled) { + int ret; + + ret = msix_vector_use(&n->parent_obj, vector); + assert(ret == 0); cq->ctrl = n; cq->cqid = cqid; cq->size = size; @@ -625,7 +629,6 @@ static void nvme_init_cq(NvmeCQueue *cq, NvmeCtrl *n, uint64_t dma_addr, cq->head = cq->tail = 0; QTAILQ_INIT(&cq->req_list); QTAILQ_INIT(&cq->sq_list); - msix_vector_use(&n->parent_obj, cq->vector); n->cq[cqid] = cq; cq->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, nvme_post_cqes, cq); } From 6a25a4b42e24df515e0e9a6b65683e500c66de73 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:32 +0200 Subject: [PATCH 1366/2595] hw/block/nvme: add msix_qsize parameter Decouple the requested maximum number of ioqpairs (param max_ioqpairs) from the number of MSI-X interrupt vectors by introducing a new msix_qsize parameter and initialize MSI-X with that. This allows emulating a device that has fewer vectors than I/O queue pairs and also allows more than 2048 queue pairs. To keep the device behaving as previously, use a msix_qsize default of 65 (default max_ioqpairs + 1). This decoupling was actually suggested by Maxim some time ago in a slightly different context, so adding a Suggested-by. Suggested-by: Maxim Levitsky Signed-off-by: Klaus Jensen Message-Id: <20200609190333.59390-22-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 17 +++++++++++++---- hw/block/nvme.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index fe17aa5d70..acc6dbc900 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -54,6 +54,7 @@ #include "trace.h" #include "nvme.h" +#define NVME_MAX_IOQPAIRS 0xffff #define NVME_REG_SIZE 0x1000 #define NVME_DB_SIZE 4 #define NVME_CMB_BIR 2 @@ -662,7 +663,7 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd) trace_pci_nvme_err_invalid_create_cq_vector(vector); return NVME_INVALID_IRQ_VECTOR | NVME_DNR; } - if (unlikely(vector > n->params.max_ioqpairs)) { + if (unlikely(vector >= n->params.msix_qsize)) { trace_pci_nvme_err_invalid_create_cq_vector(vector); return NVME_INVALID_IRQ_VECTOR | NVME_DNR; } @@ -1371,9 +1372,16 @@ static void nvme_check_constraints(NvmeCtrl *n, Error **errp) } if (params->max_ioqpairs < 1 || - params->max_ioqpairs > PCI_MSIX_FLAGS_QSIZE) { + params->max_ioqpairs > NVME_MAX_IOQPAIRS) { error_setg(errp, "max_ioqpairs must be between 1 and %d", - PCI_MSIX_FLAGS_QSIZE); + NVME_MAX_IOQPAIRS); + return; + } + + if (params->msix_qsize < 1 || + params->msix_qsize > PCI_MSIX_FLAGS_QSIZE + 1) { + error_setg(errp, "msix_qsize must be between 1 and %d", + PCI_MSIX_FLAGS_QSIZE + 1); return; } @@ -1527,7 +1535,7 @@ static void nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev) n->reg_size); pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, &n->iomem); - msix_init_exclusive_bar(pci_dev, n->params.max_ioqpairs + 1, 4, NULL); + msix_init_exclusive_bar(pci_dev, n->params.msix_qsize, 4, NULL); if (n->params.cmb_size_mb) { nvme_init_cmb(n, pci_dev); @@ -1634,6 +1642,7 @@ static Property nvme_props[] = { DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, params.cmb_size_mb, 0), DEFINE_PROP_UINT32("num_queues", NvmeCtrl, params.num_queues, 0), DEFINE_PROP_UINT32("max_ioqpairs", NvmeCtrl, params.max_ioqpairs, 64), + DEFINE_PROP_UINT16("msix_qsize", NvmeCtrl, params.msix_qsize, 65), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 61dd9b23b8..1d30c0bca2 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -7,6 +7,7 @@ typedef struct NvmeParams { char *serial; uint32_t num_queues; /* deprecated since 5.1 */ uint32_t max_ioqpairs; + uint16_t msix_qsize; uint32_t cmb_size_mb; } NvmeParams; From 1c0c2163aa087c34efc7f84a8bc7e6640e3f6b75 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Jun 2020 21:03:33 +0200 Subject: [PATCH 1367/2595] hw/block/nvme: verify msix_init_exclusive_bar() return value Pass an Error to msix_init_exclusive_bar() and check it. Signed-off-by: Klaus Jensen Message-Id: <20200609190333.59390-23-its@irrelevant.dk> Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index acc6dbc900..2a2e43f681 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1522,7 +1522,7 @@ static void nvme_init_pmr(NvmeCtrl *n, PCIDevice *pci_dev) PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr); } -static void nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev) +static void nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp) { uint8_t *pci_conf = pci_dev->config; @@ -1535,7 +1535,9 @@ static void nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev) n->reg_size); pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, &n->iomem); - msix_init_exclusive_bar(pci_dev, n->params.msix_qsize, 4, NULL); + if (msix_init_exclusive_bar(pci_dev, n->params.msix_qsize, 4, errp)) { + return; + } if (n->params.cmb_size_mb) { nvme_init_cmb(n, pci_dev); @@ -1603,7 +1605,12 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) return; } - nvme_init_pci(n, pci_dev); + nvme_init_pci(n, pci_dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + nvme_init_ctrl(n, pci_dev); for (i = 0; i < n->num_namespaces; i++) { From d54f36ea8c26af32584511533f8884ac7a50bf4a Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Fri, 12 Jun 2020 13:58:31 +0300 Subject: [PATCH 1368/2595] .gitignore: Ignore storage-daemon files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The files are generated. Fixes: 2af282ec51a ("qemu-storage-daemon: Add --monitor option") Cc: Kevin Wolf Signed-off-by: Roman Bolshakov Message-Id: <20200612105830.17082-1-r.bolshakov@yadro.com> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- .gitignore | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 0c5af83aa7..90acb4347d 100644 --- a/.gitignore +++ b/.gitignore @@ -34,18 +34,18 @@ /qapi/qapi-builtin-types.[ch] /qapi/qapi-builtin-visit.[ch] /qapi/qapi-commands-*.[ch] -/qapi/qapi-commands.[ch] -/qapi/qapi-emit-events.[ch] +**/qapi/qapi-commands.[ch] +**/qapi/qapi-emit-events.[ch] /qapi/qapi-events-*.[ch] -/qapi/qapi-events.[ch] -/qapi/qapi-init-commands.[ch] -/qapi/qapi-introspect.[ch] +**/qapi/qapi-events.[ch] +**/qapi/qapi-init-commands.[ch] +**/qapi/qapi-introspect.[ch] /qapi/qapi-types-*.[ch] -/qapi/qapi-types.[ch] +**/qapi/qapi-types.[ch] /qapi/qapi-visit-*.[ch] !/qapi/qapi-visit-core.c -/qapi/qapi-visit.[ch] -/qapi/qapi-doc.texi +**/qapi/qapi-visit.[ch] +**/qapi/qapi-doc.texi /qemu-edid /qemu-img /qemu-nbd @@ -59,6 +59,7 @@ /qemu-keymap /qemu-monitor.texi /qemu-monitor-info.texi +/qemu-storage-daemon /qemu-version.h /qemu-version.h.tmp /module_block.h From 6abee2608563599f783bf1305a8322ee7b447815 Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 29 May 2020 01:55:09 +0300 Subject: [PATCH 1369/2595] virtio-blk: store opt_io_size with correct size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The width of opt_io_size in virtio_blk_config is 32bit. However, it's written with virtio_stw_p; this may result in value truncation, and on big-endian systems with legacy virtio in completely bogus readings in the guest. Use the appropriate accessor to store it. Signed-off-by: Roman Kagan Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Kevin Wolf Message-Id: <20200528225516.1676602-2-rvkagan@yandex-team.ru> Signed-off-by: Kevin Wolf --- hw/block/virtio-blk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 8882a1d1d4..6938a75aa5 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -930,7 +930,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) virtio_stw_p(vdev, &blkcfg.geometry.cylinders, conf->cyls); virtio_stl_p(vdev, &blkcfg.blk_size, blk_size); virtio_stw_p(vdev, &blkcfg.min_io_size, conf->min_io_size / blk_size); - virtio_stw_p(vdev, &blkcfg.opt_io_size, conf->opt_io_size / blk_size); + virtio_stl_p(vdev, &blkcfg.opt_io_size, conf->opt_io_size / blk_size); blkcfg.geometry.heads = conf->heads; /* * We must ensure that the block device capacity is a multiple of From c56ee92fcba8cc922b1b2188ac20614d20223db2 Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 29 May 2020 01:55:10 +0300 Subject: [PATCH 1370/2595] block: consolidate blocksize properties consistency checks Several block device properties related to blocksize configuration must be in certain relationship WRT each other: physical block must be no smaller than logical block; min_io_size, opt_io_size, and discard_granularity must be a multiple of a logical block. To ensure these requirements are met, add corresponding consistency checks to blkconf_blocksizes, adjusting its signature to communicate possible error to the caller. Also remove the now redundant consistency checks from the specific devices. Signed-off-by: Roman Kagan Reviewed-by: Eric Blake Reviewed-by: Paul Durrant Message-Id: <20200528225516.1676602-3-rvkagan@yandex-team.ru> Signed-off-by: Kevin Wolf --- hw/block/block.c | 30 +++++++++++++++++++++++++++++- hw/block/fdc.c | 5 ++++- hw/block/nvme.c | 4 +++- hw/block/swim.c | 5 ++++- hw/block/virtio-blk.c | 7 +------ hw/block/xen-block.c | 6 +----- hw/ide/qdev.c | 5 ++++- hw/scsi/scsi-disk.c | 12 +++++------- hw/usb/dev-storage.c | 5 ++++- include/hw/block/block.h | 2 +- tests/qemu-iotests/172.out | 2 +- 11 files changed, 57 insertions(+), 26 deletions(-) diff --git a/hw/block/block.c b/hw/block/block.c index bf56c7612b..b22207c921 100644 --- a/hw/block/block.c +++ b/hw/block/block.c @@ -61,7 +61,7 @@ bool blk_check_size_and_read_all(BlockBackend *blk, void *buf, hwaddr size, return true; } -void blkconf_blocksizes(BlockConf *conf) +bool blkconf_blocksizes(BlockConf *conf, Error **errp) { BlockBackend *blk = conf->blk; BlockSizes blocksizes; @@ -83,6 +83,34 @@ void blkconf_blocksizes(BlockConf *conf) conf->logical_block_size = BDRV_SECTOR_SIZE; } } + + if (conf->logical_block_size > conf->physical_block_size) { + error_setg(errp, + "logical_block_size > physical_block_size not supported"); + return false; + } + + if (!QEMU_IS_ALIGNED(conf->min_io_size, conf->logical_block_size)) { + error_setg(errp, + "min_io_size must be a multiple of logical_block_size"); + return false; + } + + if (!QEMU_IS_ALIGNED(conf->opt_io_size, conf->logical_block_size)) { + error_setg(errp, + "opt_io_size must be a multiple of logical_block_size"); + return false; + } + + if (conf->discard_granularity != -1 && + !QEMU_IS_ALIGNED(conf->discard_granularity, + conf->logical_block_size)) { + error_setg(errp, "discard_granularity must be " + "a multiple of logical_block_size"); + return false; + } + + return true; } bool blkconf_apply_backend_options(BlockConf *conf, bool readonly, diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 8528b9a3c7..be0674e4aa 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -554,7 +554,10 @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp) read_only = !blk_bs(dev->conf.blk) || blk_is_read_only(dev->conf.blk); } - blkconf_blocksizes(&dev->conf); + if (!blkconf_blocksizes(&dev->conf, errp)) { + return; + } + if (dev->conf.logical_block_size != 512 || dev->conf.physical_block_size != 512) { diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 2a2e43f681..1aee042d4c 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1425,7 +1425,9 @@ static void nvme_init_state(NvmeCtrl *n) static void nvme_init_blk(NvmeCtrl *n, Error **errp) { - blkconf_blocksizes(&n->conf); + if (!blkconf_blocksizes(&n->conf, errp)) { + return; + } blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk), false, errp); } diff --git a/hw/block/swim.c b/hw/block/swim.c index 8f124782f4..74f56e8f46 100644 --- a/hw/block/swim.c +++ b/hw/block/swim.c @@ -189,7 +189,10 @@ static void swim_drive_realize(DeviceState *qdev, Error **errp) assert(ret == 0); } - blkconf_blocksizes(&dev->conf); + if (!blkconf_blocksizes(&dev->conf, errp)) { + return; + } + if (dev->conf.logical_block_size != 512 || dev->conf.physical_block_size != 512) { diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 6938a75aa5..413783693c 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1174,12 +1174,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) return; } - blkconf_blocksizes(&conf->conf); - - if (conf->conf.logical_block_size > - conf->conf.physical_block_size) { - error_setg(errp, - "logical_block_size > physical_block_size not supported"); + if (!blkconf_blocksizes(&conf->conf, errp)) { return; } diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 2827c90ac7..1b7bc5de08 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -239,11 +239,7 @@ static void xen_block_realize(XenDevice *xendev, Error **errp) return; } - blkconf_blocksizes(conf); - - if (conf->logical_block_size > conf->physical_block_size) { - error_setg( - errp, "logical_block_size > physical_block_size not supported"); + if (!blkconf_blocksizes(conf, errp)) { return; } diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index caa88526f5..3ccb5e2529 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -187,7 +187,10 @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp) return; } - blkconf_blocksizes(&dev->conf); + if (!blkconf_blocksizes(&dev->conf, errp)) { + return; + } + if (dev->conf.logical_block_size != 512) { error_setg(errp, "logical_block_size must be 512 for IDE"); return; diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 387503e11b..8ce68a9dd6 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2346,12 +2346,7 @@ static void scsi_realize(SCSIDevice *dev, Error **errp) return; } - blkconf_blocksizes(&s->qdev.conf); - - if (s->qdev.conf.logical_block_size > - s->qdev.conf.physical_block_size) { - error_setg(errp, - "logical_block_size > physical_block_size not supported"); + if (!blkconf_blocksizes(&s->qdev.conf, errp)) { return; } @@ -2436,7 +2431,9 @@ static void scsi_hd_realize(SCSIDevice *dev, Error **errp) if (s->qdev.conf.blk) { ctx = blk_get_aio_context(s->qdev.conf.blk); aio_context_acquire(ctx); - blkconf_blocksizes(&s->qdev.conf); + if (!blkconf_blocksizes(&s->qdev.conf, errp)) { + goto out; + } } s->qdev.blocksize = s->qdev.conf.logical_block_size; s->qdev.type = TYPE_DISK; @@ -2444,6 +2441,7 @@ static void scsi_hd_realize(SCSIDevice *dev, Error **errp) s->product = g_strdup("QEMU HARDDISK"); } scsi_realize(&s->qdev, errp); +out: if (ctx) { aio_context_release(ctx); } diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index a5204b6f2a..f5977eb72e 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -612,7 +612,10 @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp) return; } - blkconf_blocksizes(&s->conf); + if (!blkconf_blocksizes(&s->conf, errp)) { + return; + } + if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true, errp)) { return; diff --git a/include/hw/block/block.h b/include/hw/block/block.h index d7246f3862..784953a237 100644 --- a/include/hw/block/block.h +++ b/include/hw/block/block.h @@ -87,7 +87,7 @@ bool blk_check_size_and_read_all(BlockBackend *blk, void *buf, hwaddr size, bool blkconf_geometry(BlockConf *conf, int *trans, unsigned cyls_max, unsigned heads_max, unsigned secs_max, Error **errp); -void blkconf_blocksizes(BlockConf *conf); +bool blkconf_blocksizes(BlockConf *conf, Error **errp); bool blkconf_apply_backend_options(BlockConf *conf, bool readonly, bool resizable, Error **errp); diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index 7abbe82427..59cc70aebb 100644 --- a/tests/qemu-iotests/172.out +++ b/tests/qemu-iotests/172.out @@ -1204,7 +1204,7 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physica drive-type = "144" Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,logical_block_size=4096 -QEMU_PROG: -device floppy,drive=none0,logical_block_size=4096: Physical and logical block size must be 512 for floppy +QEMU_PROG: -device floppy,drive=none0,logical_block_size=4096: logical_block_size > physical_block_size not supported Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physical_block_size=1024 QEMU_PROG: -device floppy,drive=none0,physical_block_size=1024: Physical and logical block size must be 512 for floppy From a345c5523607a0a4549990cce1be096b63df9668 Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 29 May 2020 01:55:11 +0300 Subject: [PATCH 1371/2595] qdev-properties: blocksize: use same limits in code and description Make it easier (more visible) to maintain the limits on the blocksize properties in sync with the respective description, by using macros both in the code and in the description. Signed-off-by: Roman Kagan Reviewed-by: Eric Blake Message-Id: <20200528225516.1676602-4-rvkagan@yandex-team.ru> Signed-off-by: Kevin Wolf --- hw/core/qdev-properties.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index cc924815da..249dc69bd8 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -729,6 +729,13 @@ const PropertyInfo qdev_prop_pci_devfn = { /* --- blocksize --- */ +/* lower limit is sector size */ +#define MIN_BLOCK_SIZE 512 +#define MIN_BLOCK_SIZE_STR stringify(MIN_BLOCK_SIZE) +/* upper limit is the max power of 2 that fits in uint16_t */ +#define MAX_BLOCK_SIZE 32768 +#define MAX_BLOCK_SIZE_STR stringify(MAX_BLOCK_SIZE) + static void set_blocksize(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -736,8 +743,6 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name, Property *prop = opaque; uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop); Error *local_err = NULL; - const int64_t min = 512; - const int64_t max = 32768; if (dev->realized) { qdev_prop_set_after_realize(dev, name, errp); @@ -750,9 +755,12 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name, return; } /* value of 0 means "unset" */ - if (value && (value < min || value > max)) { - error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, - dev->id ? : "", name, (int64_t)value, min, max); + if (value && (value < MIN_BLOCK_SIZE || value > MAX_BLOCK_SIZE)) { + error_setg(errp, + "Property %s.%s doesn't take value %" PRIu16 + " (minimum: " MIN_BLOCK_SIZE_STR + ", maximum: " MAX_BLOCK_SIZE_STR ")", + dev->id ? : "", name, value); return; } @@ -769,7 +777,8 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name, const PropertyInfo qdev_prop_blocksize = { .name = "uint16", - .description = "A power of two between 512 and 32768", + .description = "A power of two between " MIN_BLOCK_SIZE_STR + " and " MAX_BLOCK_SIZE_STR, .get = get_uint16, .set = set_blocksize, .set_default_value = set_default_value_uint, From 914e74cda9a54ac860000aa18882dc40d3c8180b Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 29 May 2020 01:55:12 +0300 Subject: [PATCH 1372/2595] qdev-properties: add size32 property type Introduce size32 property type which handles size suffixes (k, m, g) just like size property, but is uint32_t rather than uint64_t. It's going to be useful for properties that are byte sizes but are inherently 32bit, like BlkConf.opt_io_size or .discard_granularity (they are switched to this new property type in a followup commit). The getter for size32 is left out for a separate patch as its benefit is less obvious, and it affects test output; for now the regular uint32 getter is used. Signed-off-by: Roman Kagan Message-Id: <20200528225516.1676602-5-rvkagan@yandex-team.ru> Signed-off-by: Kevin Wolf --- hw/core/qdev-properties.c | 40 ++++++++++++++++++++++++++++++++++++ include/hw/qdev-properties.h | 3 +++ 2 files changed, 43 insertions(+) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 249dc69bd8..40c13f6ebe 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -727,6 +727,46 @@ const PropertyInfo qdev_prop_pci_devfn = { .set_default_value = set_default_value_int, }; +/* --- 32bit unsigned int 'size' type --- */ + +static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque, + Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + uint64_t value; + Error *local_err = NULL; + + if (dev->realized) { + qdev_prop_set_after_realize(dev, name, errp); + return; + } + + visit_type_size(v, name, &value, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + if (value > UINT32_MAX) { + error_setg(errp, + "Property %s.%s doesn't take value %" PRIu64 + " (maximum: %u)", + dev->id ? : "", name, value, UINT32_MAX); + return; + } + + *ptr = value; +} + +const PropertyInfo qdev_prop_size32 = { + .name = "size", + .get = get_uint32, + .set = set_size32, + .set_default_value = set_default_value_uint, +}; + /* --- blocksize --- */ /* lower limit is sector size */ diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index f161604fb6..c03eadfad6 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -29,6 +29,7 @@ extern const PropertyInfo qdev_prop_drive; extern const PropertyInfo qdev_prop_drive_iothread; extern const PropertyInfo qdev_prop_netdev; extern const PropertyInfo qdev_prop_pci_devfn; +extern const PropertyInfo qdev_prop_size32; extern const PropertyInfo qdev_prop_blocksize; extern const PropertyInfo qdev_prop_pci_host_devaddr; extern const PropertyInfo qdev_prop_uuid; @@ -196,6 +197,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width; BlockdevOnError) #define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int) +#define DEFINE_PROP_SIZE32(_n, _s, _f, _d) \ + DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_size32, uint32_t) #define DEFINE_PROP_BLOCKSIZE(_n, _s, _f) \ DEFINE_PROP_UNSIGNED(_n, _s, _f, 0, qdev_prop_blocksize, uint16_t) #define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \ From 645b55d1c2bf35ce6344f1f472fa30e327cafce0 Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 29 May 2020 01:55:13 +0300 Subject: [PATCH 1373/2595] qdev-properties: make blocksize accept size suffixes It appears convenient to be able to specify physical_block_size and logical_block_size using common size suffixes. Teach the blocksize property setter to interpret them. Also express the upper and lower limits in the respective units. Signed-off-by: Roman Kagan Reviewed-by: Eric Blake Message-Id: <20200528225516.1676602-6-rvkagan@yandex-team.ru> Signed-off-by: Kevin Wolf --- hw/core/qdev-properties.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 40c13f6ebe..c9af6a1341 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -14,6 +14,7 @@ #include "qapi/visitor.h" #include "chardev/char.h" #include "qemu/uuid.h" +#include "qemu/units.h" void qdev_prop_set_after_realize(DeviceState *dev, const char *name, Error **errp) @@ -771,17 +772,18 @@ const PropertyInfo qdev_prop_size32 = { /* lower limit is sector size */ #define MIN_BLOCK_SIZE 512 -#define MIN_BLOCK_SIZE_STR stringify(MIN_BLOCK_SIZE) +#define MIN_BLOCK_SIZE_STR "512 B" /* upper limit is the max power of 2 that fits in uint16_t */ -#define MAX_BLOCK_SIZE 32768 -#define MAX_BLOCK_SIZE_STR stringify(MAX_BLOCK_SIZE) +#define MAX_BLOCK_SIZE (32 * KiB) +#define MAX_BLOCK_SIZE_STR "32 KiB" static void set_blocksize(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop); + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); + uint64_t value; Error *local_err = NULL; if (dev->realized) { @@ -789,7 +791,7 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name, return; } - visit_type_uint16(v, name, &value, &local_err); + visit_type_size(v, name, &value, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -797,7 +799,7 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name, /* value of 0 means "unset" */ if (value && (value < MIN_BLOCK_SIZE || value > MAX_BLOCK_SIZE)) { error_setg(errp, - "Property %s.%s doesn't take value %" PRIu16 + "Property %s.%s doesn't take value %" PRIu64 " (minimum: " MIN_BLOCK_SIZE_STR ", maximum: " MAX_BLOCK_SIZE_STR ")", dev->id ? : "", name, value); @@ -816,7 +818,7 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name, } const PropertyInfo qdev_prop_blocksize = { - .name = "uint16", + .name = "size", .description = "A power of two between " MIN_BLOCK_SIZE_STR " and " MAX_BLOCK_SIZE_STR, .get = get_uint16, From 4f44bbc5bba0858d34b1aa356397847696276546 Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 29 May 2020 01:55:14 +0300 Subject: [PATCH 1374/2595] block: make BlockConf size props 32bit and accept size suffixes Convert all size-related properties in BlockConf to 32bit. This will accommodate bigger block sizes (in a followup patch). This also allows to make them all accept size suffixes, either via DEFINE_PROP_BLOCKSIZE or via DEFINE_PROP_SIZE32. Also, since min_io_size is exposed to the guest by scsi and virtio-blk devices as an uint16_t in units of logical blocks, introduce an additional check in blkconf_blocksizes to prevent its silent truncation. Signed-off-by: Roman Kagan Message-Id: <20200528225516.1676602-7-rvkagan@yandex-team.ru> Signed-off-by: Kevin Wolf --- hw/block/block.c | 10 ++++++++++ hw/core/qdev-properties.c | 4 ++-- include/hw/block/block.h | 12 ++++++------ include/hw/qdev-properties.h | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/hw/block/block.c b/hw/block/block.c index b22207c921..1e34573da7 100644 --- a/hw/block/block.c +++ b/hw/block/block.c @@ -96,6 +96,16 @@ bool blkconf_blocksizes(BlockConf *conf, Error **errp) return false; } + /* + * all devices which support min_io_size (scsi and virtio-blk) expose it to + * the guest as a uint16_t in units of logical blocks + */ + if (conf->min_io_size / conf->logical_block_size > UINT16_MAX) { + error_setg(errp, "min_io_size must not exceed %u logical blocks", + UINT16_MAX); + return false; + } + if (!QEMU_IS_ALIGNED(conf->opt_io_size, conf->logical_block_size)) { error_setg(errp, "opt_io_size must be a multiple of logical_block_size"); diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index c9af6a1341..bd4abdc1d1 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -782,7 +782,7 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name, { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - uint16_t *ptr = qdev_get_prop_ptr(dev, prop); + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); uint64_t value; Error *local_err = NULL; @@ -821,7 +821,7 @@ const PropertyInfo qdev_prop_blocksize = { .name = "size", .description = "A power of two between " MIN_BLOCK_SIZE_STR " and " MAX_BLOCK_SIZE_STR, - .get = get_uint16, + .get = get_uint32, .set = set_blocksize, .set_default_value = set_default_value_uint, }; diff --git a/include/hw/block/block.h b/include/hw/block/block.h index 784953a237..1e8b6253dd 100644 --- a/include/hw/block/block.h +++ b/include/hw/block/block.h @@ -18,9 +18,9 @@ typedef struct BlockConf { BlockBackend *blk; - uint16_t physical_block_size; - uint16_t logical_block_size; - uint16_t min_io_size; + uint32_t physical_block_size; + uint32_t logical_block_size; + uint32_t min_io_size; uint32_t opt_io_size; int32_t bootindex; uint32_t discard_granularity; @@ -51,9 +51,9 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf) _conf.logical_block_size), \ DEFINE_PROP_BLOCKSIZE("physical_block_size", _state, \ _conf.physical_block_size), \ - DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0), \ - DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0), \ - DEFINE_PROP_UINT32("discard_granularity", _state, \ + DEFINE_PROP_SIZE32("min_io_size", _state, _conf.min_io_size, 0), \ + DEFINE_PROP_SIZE32("opt_io_size", _state, _conf.opt_io_size, 0), \ + DEFINE_PROP_SIZE32("discard_granularity", _state, \ _conf.discard_granularity, -1), \ DEFINE_PROP_ON_OFF_AUTO("write-cache", _state, _conf.wce, \ ON_OFF_AUTO_AUTO), \ diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index c03eadfad6..5252bb6b1a 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -200,7 +200,7 @@ extern const PropertyInfo qdev_prop_pcie_link_width; #define DEFINE_PROP_SIZE32(_n, _s, _f, _d) \ DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_size32, uint32_t) #define DEFINE_PROP_BLOCKSIZE(_n, _s, _f) \ - DEFINE_PROP_UNSIGNED(_n, _s, _f, 0, qdev_prop_blocksize, uint16_t) + DEFINE_PROP_UNSIGNED(_n, _s, _f, 0, qdev_prop_blocksize, uint32_t) #define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress) #define DEFINE_PROP_OFF_AUTO_PCIBAR(_n, _s, _f, _d) \ From 031ffd9a612618e86eb1d783b285d658e95f117d Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 29 May 2020 01:55:15 +0300 Subject: [PATCH 1375/2595] qdev-properties: add getter for size32 and blocksize Add getter for size32, and use it for blocksize, too. In its human-readable branch, it reports approximate size in human-readable units next to the exact byte value, like the getter for 64bit size does. Adjust the expected test output accordingly. Signed-off-by: Roman Kagan Reviewed-by: Eric Blake Message-Id: <20200528225516.1676602-8-rvkagan@yandex-team.ru> Signed-off-by: Kevin Wolf --- hw/core/qdev-properties.c | 15 +- tests/qemu-iotests/172.out | 530 ++++++++++++++++++------------------- 2 files changed, 278 insertions(+), 267 deletions(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index bd4abdc1d1..63d48db70c 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -730,6 +730,17 @@ const PropertyInfo qdev_prop_pci_devfn = { /* --- 32bit unsigned int 'size' type --- */ +static void get_size32(Object *obj, Visitor *v, const char *name, void *opaque, + Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + uint64_t value = *ptr; + + visit_type_size(v, name, &value, errp); +} + static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -763,7 +774,7 @@ static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque, const PropertyInfo qdev_prop_size32 = { .name = "size", - .get = get_uint32, + .get = get_size32, .set = set_size32, .set_default_value = set_default_value_uint, }; @@ -821,7 +832,7 @@ const PropertyInfo qdev_prop_blocksize = { .name = "size", .description = "A power of two between " MIN_BLOCK_SIZE_STR " and " MAX_BLOCK_SIZE_STR, - .get = get_uint32, + .get = get_size32, .set = set_blocksize, .set_default_value = set_default_value_uint, }; diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index 59cc70aebb..e782c5957e 100644 --- a/tests/qemu-iotests/172.out +++ b/tests/qemu-iotests/172.out @@ -24,11 +24,11 @@ Testing: dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "288" @@ -54,11 +54,11 @@ Testing: -fda TEST_DIR/t.qcow2 dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -81,22 +81,22 @@ Testing: -fdb TEST_DIR/t.qcow2 dev: floppy, id "" unit = 1 (0x1) drive = "floppy1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "288" @@ -119,22 +119,22 @@ Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2.2 dev: floppy, id "" unit = 1 (0x1) drive = "floppy1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -160,11 +160,11 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -187,22 +187,22 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1 dev: floppy, id "" unit = 1 (0x1) drive = "floppy1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "288" @@ -225,22 +225,22 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t dev: floppy, id "" unit = 1 (0x1) drive = "floppy1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -266,11 +266,11 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveA=none0 dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -293,11 +293,11 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveB=none0 dev: floppy, id "" unit = 1 (0x1) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -320,22 +320,22 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco dev: floppy, id "" unit = 1 (0x1) drive = "none1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -361,11 +361,11 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0 dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -388,11 +388,11 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=1 dev: floppy, id "" unit = 1 (0x1) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -415,22 +415,22 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco dev: floppy, id "" unit = 1 (0x1) drive = "none1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -456,22 +456,22 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global is dev: floppy, id "" unit = 1 (0x1) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -494,22 +494,22 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global is dev: floppy, id "" unit = 1 (0x1) drive = "floppy1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -532,11 +532,11 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global is dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -559,11 +559,11 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global is dev: floppy, id "" unit = 1 (0x1) drive = "floppy1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -589,22 +589,22 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl dev: floppy, id "" unit = 1 (0x1) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -627,22 +627,22 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl dev: floppy, id "" unit = 1 (0x1) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -665,22 +665,22 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 1 (0x1) drive = "floppy1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -703,22 +703,22 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 1 (0x1) drive = "floppy1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -750,22 +750,22 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q dev: floppy, id "" unit = 1 (0x1) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -788,22 +788,22 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q dev: floppy, id "" unit = 1 (0x1) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -832,22 +832,22 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco dev: floppy, id "" unit = 1 (0x1) drive = "none1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -870,22 +870,22 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco dev: floppy, id "" unit = 1 (0x1) drive = "none1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -908,22 +908,22 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco dev: floppy, id "" unit = 0 (0x0) drive = "none1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 1 (0x1) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -946,22 +946,22 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco dev: floppy, id "" unit = 0 (0x0) drive = "none1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" dev: floppy, id "" unit = 1 (0x1) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -999,11 +999,11 @@ Testing: -device floppy dev: floppy, id "" unit = 0 (0x0) drive = "" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "288" @@ -1026,11 +1026,11 @@ Testing: -device floppy,drive-type=120 dev: floppy, id "" unit = 0 (0x0) drive = "" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "120" @@ -1053,11 +1053,11 @@ Testing: -device floppy,drive-type=144 dev: floppy, id "" unit = 0 (0x0) drive = "" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -1080,11 +1080,11 @@ Testing: -device floppy,drive-type=288 dev: floppy, id "" unit = 0 (0x0) drive = "" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "288" @@ -1110,11 +1110,11 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "120" @@ -1137,11 +1137,11 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "288" @@ -1167,11 +1167,11 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,logical dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -1194,11 +1194,11 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physica dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" From 6510ba1c0ebd1503097ac831956505adf5ec29d2 Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 29 May 2020 01:55:16 +0300 Subject: [PATCH 1376/2595] block: lift blocksize property limit to 2 MiB Logical and physical block sizes in QEMU are limited to 32 KiB. This appears unnecessarily tight, and we've seen bigger block sizes handy at times. Lift the limitation up to 2 MiB which appears to be good enough for everybody, and matches the qcow2 cluster size limit. Signed-off-by: Roman Kagan Reviewed-by: Eric Blake Message-Id: <20200528225516.1676602-9-rvkagan@yandex-team.ru> Signed-off-by: Kevin Wolf --- hw/core/qdev-properties.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 63d48db70c..ead35d7ffd 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -784,9 +784,12 @@ const PropertyInfo qdev_prop_size32 = { /* lower limit is sector size */ #define MIN_BLOCK_SIZE 512 #define MIN_BLOCK_SIZE_STR "512 B" -/* upper limit is the max power of 2 that fits in uint16_t */ -#define MAX_BLOCK_SIZE (32 * KiB) -#define MAX_BLOCK_SIZE_STR "32 KiB" +/* + * upper limit is arbitrary, 2 MiB looks sufficient for all sensible uses, and + * matches qcow2 cluster size limit + */ +#define MAX_BLOCK_SIZE (2 * MiB) +#define MAX_BLOCK_SIZE_STR "2 MiB" static void set_blocksize(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) From ff3caf5af0fd204133668f26fde39b27f86c5d76 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 17 Jun 2020 12:48:18 +0200 Subject: [PATCH 1377/2595] iotests.py: Add skip_for_formats() decorator Sometimes, we want to skip some test methods for certain formats. This decorator allows that. Signed-off-by: Max Reitz Message-Id: <20200617104822.27525-2-mreitz@redhat.com> Tested-by: Thomas Huth Signed-off-by: Kevin Wolf --- tests/qemu-iotests/118 | 7 +++---- tests/qemu-iotests/iotests.py | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/qemu-iotests/118 b/tests/qemu-iotests/118 index adc8a848b5..2350929fd8 100755 --- a/tests/qemu-iotests/118 +++ b/tests/qemu-iotests/118 @@ -683,11 +683,10 @@ class TestBlockJobsAfterCycle(ChangeBaseClass): except OSError: pass + # We need backing file support + @iotests.skip_for_formats(('vpc', 'parallels', 'qcow', 'vdi', 'vmdk', 'raw', + 'vhdx')) def test_snapshot_and_commit(self): - # We need backing file support - if iotests.imgfmt != 'qcow2' and iotests.imgfmt != 'qed': - return - result = self.vm.qmp('blockdev-snapshot-sync', device='drive0', snapshot_file=new_img, format=iotests.imgfmt) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index f20d90f969..5ea4c4df8b 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -1103,6 +1103,22 @@ def skip_if_unsupported(required_formats=(), read_only=False): return func_wrapper return skip_test_decorator +def skip_for_formats(formats: Sequence[str] = ()) \ + -> Callable[[Callable[[QMPTestCase, List[Any], Dict[str, Any]], None]], + Callable[[QMPTestCase, List[Any], Dict[str, Any]], None]]: + '''Skip Test Decorator + Skips the test for the given formats''' + def skip_test_decorator(func): + def func_wrapper(test_case: QMPTestCase, *args: List[Any], + **kwargs: Dict[str, Any]) -> None: + if imgfmt in formats: + msg = f'{test_case}: Skipped for format {imgfmt}' + test_case.case_skip(msg) + else: + func(test_case, *args, **kwargs) + return func_wrapper + return skip_test_decorator + def skip_if_user_is_root(func): '''Skip Test Decorator Runs the test only without root permissions''' From c7070942c78741a7040655f94ed011c09aa832cf Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 17 Jun 2020 12:48:19 +0200 Subject: [PATCH 1378/2595] iotests/041: Skip test_small_target for qed qed does not support shrinking images, so the test_small_target method should be skipped to keep 041 passing. Fixes: 16cea4ee1c8e5a69a058e76f426b2e17974d8d7d Signed-off-by: Max Reitz Message-Id: <20200617104822.27525-3-mreitz@redhat.com> Tested-by: Thomas Huth Signed-off-by: Kevin Wolf --- tests/qemu-iotests/041 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 601c756117..b843f88a66 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -277,6 +277,8 @@ class TestSingleBlockdev(TestSingleDrive): result = self.vm.run_job('job0') self.assertEqual(result, 'Source and target image have different sizes') + # qed does not support shrinking + @iotests.skip_for_formats(('qed')) def test_small_target(self): self.do_test_target_size(self.image_len // 2) From e6de31bcad4079d055036b75b0a4715de6140f15 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 17 Jun 2020 12:48:20 +0200 Subject: [PATCH 1379/2595] iotests/292: data_file is unsupported Fixes: e4d7019e1a81c61de6a925c3ac5bb6e62ea21b29 Signed-off-by: Max Reitz Message-Id: <20200617104822.27525-4-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/292 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/qemu-iotests/292 b/tests/qemu-iotests/292 index a2de27cca4..83ab19231d 100755 --- a/tests/qemu-iotests/292 +++ b/tests/qemu-iotests/292 @@ -40,6 +40,11 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file _supported_os Linux +# We need qemu-img map to show the file where the data is allocated, +# but with an external data file, it will show that instead of the +# file we want to check. So just skip this test for external data +# files. +_unsupported_imgopts data_file echo '### Create the backing image' BACKING_IMG="$TEST_IMG.base" From 73b2b7b5cab2d06cf810d7f8c7c4cc918db30e04 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 17 Jun 2020 12:48:21 +0200 Subject: [PATCH 1380/2595] iotests/229: data_file is unsupported Fixes: d89ac3cf305b28c024a76805a84d75c0ee1e786f Signed-off-by: Max Reitz Message-Id: <20200617104822.27525-5-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/229 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229 index 99acb55ebb..89a5359f32 100755 --- a/tests/qemu-iotests/229 +++ b/tests/qemu-iotests/229 @@ -46,6 +46,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 qed _supported_proto file _supported_os Linux +# blkdebug can only inject errors on bs->file, so external data files +# do not work with this test +_unsupported_imgopts data_file DEST_IMG="$TEST_DIR/d.$IMGFMT" From 2e3becf9d7ca8d07e3587aacd5431e0b5945896e Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 17 Jun 2020 12:48:22 +0200 Subject: [PATCH 1381/2595] iotests/{190,291}: compat=0.10 is unsupported Fixes: 5d72c68b49769c927e90b78af6d90f6a384b26ac Fixes: cf2d1203dcfc2bf964453d83a2302231ce77f2dc Signed-off-by: Max Reitz Message-Id: <20200617104822.27525-6-mreitz@redhat.com> Signed-off-by: Kevin Wolf --- tests/qemu-iotests/190 | 2 ++ tests/qemu-iotests/291 | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190 index fe630918e9..c22d8d64f9 100755 --- a/tests/qemu-iotests/190 +++ b/tests/qemu-iotests/190 @@ -41,6 +41,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 # See 178 for more extensive tests across more formats _supported_fmt qcow2 _supported_proto file +# compat=0.10 does not support bitmaps +_unsupported_imgopts 'compat=0.10' echo "== Huge file without bitmaps ==" echo diff --git a/tests/qemu-iotests/291 b/tests/qemu-iotests/291 index 404f8521f7..28e4fb9b4d 100755 --- a/tests/qemu-iotests/291 +++ b/tests/qemu-iotests/291 @@ -39,6 +39,8 @@ _supported_fmt qcow2 _supported_proto file _supported_os Linux _require_command QEMU_NBD +# compat=0.10 does not support bitmaps +_unsupported_imgopts 'compat=0.10' echo echo "=== Initial image setup ===" From 3419ec713f04c323b030e0763459435335b25476 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 9 Jun 2020 15:59:44 -0500 Subject: [PATCH 1382/2595] iotests: Add copyright line in qcow2.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The file qcow2.py was originally contributed in 2012 by Kevin Wolf, but was not given traditional boilerplate headers at the time. The missing license was just rectified (commit 16306a7b39) using the project-default GPLv2+, but as Vladimir is not at Red Hat, he did not add a Copyright line. All earlier contributions have come from CC'd authors, where all but Stefan used a Red Hat address at the time of the contribution, and that copyright carries over to the split to qcow2_format.py (d5262c7124). CC: Kevin Wolf CC: Stefan Hajnoczi CC: Eduardo Habkost CC: Max Reitz CC: Philippe Mathieu-Daudé CC: Paolo Bonzini Signed-off-by: Eric Blake Message-Id: <20200609205944.3549240-1-eblake@redhat.com> Acked-by: Stefan Hajnoczi Acked-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- tests/qemu-iotests/qcow2.py | 2 ++ tests/qemu-iotests/qcow2_format.py | 1 + 2 files changed, 3 insertions(+) diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py index 8c187e9a72..0910e6ac07 100755 --- a/tests/qemu-iotests/qcow2.py +++ b/tests/qemu-iotests/qcow2.py @@ -2,6 +2,8 @@ # # Manipulations with qcow2 image # +# Copyright (C) 2012 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 diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index 0f65fd161d..cc432e7ae0 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -1,6 +1,7 @@ # Library for manipulations with qcow2 image # # Copyright (c) 2020 Virtuozzo International GmbH. +# Copyright (C) 2012 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 From 63659fe74e76f5c5285466f0c5cfbdca65b3688e Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 8 Jun 2020 11:31:11 +0200 Subject: [PATCH 1383/2595] virtiofsd: Whitelist fchmod lo_setattr() invokes fchmod() in a rarely used code path, so it should be whitelisted or virtiofsd will crash with EBADSYS. Said code path can be triggered for example as follows: On the host, in the shared directory, create a file with the sticky bit set and a security.capability xattr: (1) # touch foo (2) # chmod u+s foo (3) # setcap '' foo Then in the guest let some process truncate that file after it has dropped all of its capabilities (at least CAP_FSETID): int main(int argc, char *argv[]) { capng_setpid(getpid()); capng_clear(CAPNG_SELECT_BOTH); capng_updatev(CAPNG_ADD, CAPNG_PERMITTED | CAPNG_EFFECTIVE, 0); capng_apply(CAPNG_SELECT_BOTH); ftruncate(open(argv[1], O_RDWR), 0); } This will cause the guest kernel to drop the sticky bit (i.e. perform a mode change) as part of the truncate (where FATTR_FH is set), and that will cause virtiofsd to invoke fchmod() instead of fchmodat(). (A similar configuration exists further below with futimens() vs. utimensat(), but the former is not a syscall but just a wrapper for the latter, so no further whitelisting is required.) Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1842667 Reported-by: Qian Cai Cc: qemu-stable@nongnu.org Signed-off-by: Max Reitz Message-Id: <20200608093111.14942-1-mreitz@redhat.com> Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Vivek Goyal Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/seccomp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/virtiofsd/seccomp.c b/tools/virtiofsd/seccomp.c index bd9e7b083c..3b1522acdd 100644 --- a/tools/virtiofsd/seccomp.c +++ b/tools/virtiofsd/seccomp.c @@ -42,6 +42,7 @@ static const int syscall_whitelist[] = { SCMP_SYS(exit_group), SCMP_SYS(fallocate), SCMP_SYS(fchdir), + SCMP_SYS(fchmod), SCMP_SYS(fchmodat), SCMP_SYS(fchownat), SCMP_SYS(fcntl), From 246da7db3cc103c537b0dd3c1adadbfd9a94ecd7 Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Wed, 3 Jun 2020 03:03:38 -0400 Subject: [PATCH 1384/2595] qom-hmp-cmds: fix a memleak in hmp_qom_get 'obj' forgot to free at the end of hmp_qom_get(). Fix that. The leak stack: Direct leak of 40 byte(s) in 1 object(s) allocated from: #0 0x7f4e3a779ae8 in __interceptor_malloc (/lib64/libasan.so.5+0xefae8) #1 0x7f4e398f91d5 in g_malloc (/lib64/libglib-2.0.so.0+0x531d5) #2 0x55c9fd9a3999 in qstring_from_substr /build/qemu/src/qobject/qstring.c:45 #3 0x55c9fd894bd3 in qobject_output_type_str /build/qemu/src/qapi/qobject-output-visitor.c:175 #4 0x55c9fd894bd3 in qobject_output_type_str /build/qemu/src/qapi/qobject-output-visitor.c:168 #5 0x55c9fd88b34d in visit_type_str /build/qemu/src/qapi/qapi-visit-core.c:308 #6 0x55c9fd59aa6b in property_get_str /build/qemu/src/qom/object.c:2064 #7 0x55c9fd5adb8a in object_property_get_qobject /build/qemu/src/qom/qom-qobject.c:38 #8 0x55c9fd4a029d in hmp_qom_get /build/qemu/src/qom/qom-hmp-cmds.c:66 Fixes: 89cf4fe34f4 Reported-by: Euler Robot Signed-off-by: Pan Nengyuan Message-Id: <20200603070338.7922-1-pannengyuan@huawei.com> Reviewed-by: Li Qiang Tested-by: Li Qiang Signed-off-by: Dr. David Alan Gilbert --- qom/qom-hmp-cmds.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index 99385b6ad2..158e2d7409 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -71,6 +71,7 @@ void hmp_qom_get(Monitor *mon, const QDict *qdict) qobject_unref(str); } + qobject_unref(obj); hmp_handle_error(mon, err); } From 2d9e3dd9be1de3bbdca113673084dd19a8d957c3 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 10 Jun 2020 09:51:53 +0200 Subject: [PATCH 1385/2595] hmp: Make json format optional for qom-set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 7d2ef6dcc1cf ("hmp: Simplify qom-set") switched to the json parser, making it possible to specify complex types. However, with this change it is no longer possible to specify proper sizes (e.g., 2G, 128M), turning the interface harder to use for properties that consume sizes. Let's switch back to the previous handling and allow to specify passing json via the "-j" parameter. Cc: Philippe Mathieu-Daudé Cc: Markus Armbruster Cc: Dr. David Alan Gilbert Cc: Paolo Bonzini Cc: "Daniel P. Berrangé" Cc: Eduardo Habkost Signed-off-by: David Hildenbrand Message-Id: <20200610075153.33892-1-david@redhat.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- hmp-commands.hx | 7 ++++--- qom/qom-hmp-cmds.c | 20 ++++++++++++++++---- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 28256209b5..60f395c276 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1806,9 +1806,10 @@ ERST { .name = "qom-set", - .args_type = "path:s,property:s,value:S", - .params = "path property value", - .help = "set QOM property", + .args_type = "json:-j,path:s,property:s,value:S", + .params = "[-j] path property value", + .help = "set QOM property.\n\t\t\t" + "-j: the value is specified in json format.", .cmd = hmp_qom_set, .flags = "p", }, diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index 158e2d7409..b0abe84cb1 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -44,15 +44,27 @@ void hmp_qom_list(Monitor *mon, const QDict *qdict) void hmp_qom_set(Monitor *mon, const QDict *qdict) { + const bool json = qdict_get_try_bool(qdict, "json", false); const char *path = qdict_get_str(qdict, "path"); const char *property = qdict_get_str(qdict, "property"); const char *value = qdict_get_str(qdict, "value"); Error *err = NULL; - QObject *obj; - obj = qobject_from_json(value, &err); - if (err == NULL) { - qmp_qom_set(path, property, obj, &err); + if (!json) { + Object *obj = object_resolve_path(path, NULL); + + if (!obj) { + error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", path); + } else { + object_property_parse(obj, value, property, &err); + } + } else { + QObject *obj = qobject_from_json(value, &err); + + if (!err) { + qmp_qom_set(path, property, obj, &err); + } } hmp_handle_error(mon, err); From f663492f40c1e2b500c9eda0625ff8bbb04a478c Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 3 Jun 2020 16:08:56 +0800 Subject: [PATCH 1386/2595] tests/migration: mem leak fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ‘data’ has the possibility of memory leaks, so use the glib macros g_autofree recommended by CODING_STYLE.rst to automatically release the memory that returned from g_malloc(). Signed-off-by: Mao Zhongyi Reviewed-by: Alex Bennée Reviewed-by: Laurent Vivier Message-Id: <20200603080904.997083-2-maozhongyi@cmss.chinamobile.com> Signed-off-by: Dr. David Alan Gilbert --- tests/migration/stress.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/tests/migration/stress.c b/tests/migration/stress.c index 0c23964693..f9626d50ee 100644 --- a/tests/migration/stress.c +++ b/tests/migration/stress.c @@ -170,26 +170,14 @@ static unsigned long long now(void) static int stressone(unsigned long long ramsizeMB) { size_t pagesPerMB = 1024 * 1024 / PAGE_SIZE; - char *ram = malloc(ramsizeMB * 1024 * 1024); + g_autofree char *ram = g_malloc(ramsizeMB * 1024 * 1024); char *ramptr; size_t i, j, k; - char *data = malloc(PAGE_SIZE); + g_autofree char *data = g_malloc(PAGE_SIZE); char *dataptr; size_t nMB = 0; unsigned long long before, after; - if (!ram) { - fprintf(stderr, "%s (%05d): ERROR: cannot allocate %llu MB of RAM: %s\n", - argv0, gettid(), ramsizeMB, strerror(errno)); - return -1; - } - if (!data) { - fprintf(stderr, "%s (%d): ERROR: cannot allocate %d bytes of RAM: %s\n", - argv0, gettid(), PAGE_SIZE, strerror(errno)); - free(ram); - return -1; - } - /* We don't care about initial state, but we do want * to fault it all into RAM, otherwise the first iter * of the loop below will be quite slow. We can't use @@ -198,8 +186,6 @@ static int stressone(unsigned long long ramsizeMB) memset(ram, 0xfe, ramsizeMB * 1024 * 1024); if (random_bytes(data, PAGE_SIZE) < 0) { - free(ram); - free(data); return -1; } @@ -227,9 +213,6 @@ static int stressone(unsigned long long ramsizeMB) } } } - - free(data); - free(ram); } From 71cfce73f454fcdd5b4e8e9629cd6f41900cef13 Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 3 Jun 2020 16:08:57 +0800 Subject: [PATCH 1387/2595] tests/migration: fix unreachable path in stress test If stressone() or stress() exits it's because of a failure because the test runs forever otherwise, so change stressone and stress type to void to make the exit_failure() as the exit function of main(). Signed-off-by: Mao Zhongyi Reviewed-by: Laurent Vivier Message-Id: <20200603080904.997083-3-maozhongyi@cmss.chinamobile.com> Signed-off-by: Dr. David Alan Gilbert --- tests/migration/stress.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/migration/stress.c b/tests/migration/stress.c index f9626d50ee..a062ef6b55 100644 --- a/tests/migration/stress.c +++ b/tests/migration/stress.c @@ -167,7 +167,7 @@ static unsigned long long now(void) return (tv.tv_sec * 1000ull) + (tv.tv_usec / 1000ull); } -static int stressone(unsigned long long ramsizeMB) +static void stressone(unsigned long long ramsizeMB) { size_t pagesPerMB = 1024 * 1024 / PAGE_SIZE; g_autofree char *ram = g_malloc(ramsizeMB * 1024 * 1024); @@ -186,7 +186,7 @@ static int stressone(unsigned long long ramsizeMB) memset(ram, 0xfe, ramsizeMB * 1024 * 1024); if (random_bytes(data, PAGE_SIZE) < 0) { - return -1; + return; } before = now(); @@ -225,7 +225,7 @@ static void *stressthread(void *arg) return NULL; } -static int stress(unsigned long long ramsizeGB, int ncpus) +static void stress(unsigned long long ramsizeGB, int ncpus) { size_t i; unsigned long long ramsizeMB = ramsizeGB * 1024 / ncpus; @@ -238,8 +238,6 @@ static int stress(unsigned long long ramsizeGB, int ncpus) } stressone(ramsizeMB); - - return 0; } @@ -335,8 +333,7 @@ int main(int argc, char **argv) fprintf(stdout, "%s (%05d): INFO: RAM %llu GiB across %d CPUs\n", argv0, gettid(), ramsizeGB, ncpus); - if (stress(ramsizeGB, ncpus) < 0) - exit_failure(); + stress(ramsizeGB, ncpus); - exit_success(); + exit_failure(); } From 39337f121192c9ca305cb5c1a695f25c35e967ff Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 3 Jun 2020 16:08:58 +0800 Subject: [PATCH 1388/2595] monitor/hmp-cmds: add units for migrate_parameters When running: (qemu) info migrate_parameters announce-initial: 50 ms announce-max: 550 ms announce-step: 100 ms compress-wait-thread: on ... max-bandwidth: 33554432 bytes/second downtime-limit: 300 milliseconds x-checkpoint-delay: 20000 ... xbzrle-cache-size: 67108864 add units for the parameters 'x-checkpoint-delay' and 'xbzrle-cache-size', it's easier to read, also move milliseconds to ms to keep the same style. Signed-off-by: Mao Zhongyi Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Stefano Garzarella Message-Id: <20200603080904.997083-4-maozhongyi@cmss.chinamobile.com> Signed-off-by: Dr. David Alan Gilbert --- monitor/hmp-cmds.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index e03adf0d4d..2c630ec88d 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -443,11 +443,11 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH), params->max_bandwidth); assert(params->has_downtime_limit); - monitor_printf(mon, "%s: %" PRIu64 " milliseconds\n", + monitor_printf(mon, "%s: %" PRIu64 " ms\n", MigrationParameter_str(MIGRATION_PARAMETER_DOWNTIME_LIMIT), params->downtime_limit); assert(params->has_x_checkpoint_delay); - monitor_printf(mon, "%s: %u\n", + monitor_printf(mon, "%s: %u ms\n", MigrationParameter_str(MIGRATION_PARAMETER_X_CHECKPOINT_DELAY), params->x_checkpoint_delay); assert(params->has_block_incremental); @@ -460,7 +460,7 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%s: %s\n", MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_COMPRESSION), MultiFDCompression_str(params->multifd_compression)); - monitor_printf(mon, "%s: %" PRIu64 "\n", + monitor_printf(mon, "%s: %" PRIu64 " bytes\n", MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE), params->xbzrle_cache_size); monitor_printf(mon, "%s: %" PRIu64 "\n", From fe025508c0c98ff1349c02e6f99b13844d7079b1 Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 3 Jun 2020 16:08:59 +0800 Subject: [PATCH 1389/2595] monitor/hmp-cmds: don't silently output when running 'migrate_set_downtime' fails Although 'migrate_set_downtime' has been deprecated and replaced with 'migrate_set_parameter downtime_limit', it has not been completely eliminated, possibly due to compatibility with older versions. I think as long as this old parameter is running, we should report appropriate message when something goes wrong, not be silent. before: (qemu) migrate_set_downtime -1 (qemu) after: (qemu) migrate_set_downtime -1 Error: Parameter 'downtime_limit' expects an integer in the range of 0 to 2000 seconds Signed-off-by: Mao Zhongyi Reviewed-by: Dr. David Alan Gilbert Message-Id: <20200603080904.997083-5-maozhongyi@cmss.chinamobile.com> Signed-off-by: Dr. David Alan Gilbert --- monitor/hmp-cmds.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 2c630ec88d..a704b3469a 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -1189,8 +1189,11 @@ void hmp_migrate_pause(Monitor *mon, const QDict *qdict) /* Kept for backwards compatibility */ void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict) { + Error *err = NULL; + double value = qdict_get_double(qdict, "value"); - qmp_migrate_set_downtime(value, NULL); + qmp_migrate_set_downtime(value, &err); + hmp_handle_error(mon, err); } void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict) From 0705ecc4ade74f03df00e8528987e7876a293f3b Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 3 Jun 2020 16:09:00 +0800 Subject: [PATCH 1390/2595] monitor/hmp-cmds: delete redundant Error check before invoke hmp_handle_error() hmp_handle_error() does Error check internally. Signed-off-by: Mao Zhongyi Message-Id: <20200603080904.997083-6-maozhongyi@cmss.chinamobile.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- monitor/hmp-cmds.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index a704b3469a..504796d6e9 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -1637,9 +1637,8 @@ void hmp_object_add(Monitor *mon, const QDict *qdict) obj = user_creatable_add_opts(opts, &err); qemu_opts_del(opts); - if (err) { - hmp_handle_error(mon, err); - } + hmp_handle_error(mon, err); + if (obj) { object_unref(obj); } From ac9c95b13fc1ccd097834b29d846f25795bd76de Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 3 Jun 2020 16:09:01 +0800 Subject: [PATCH 1391/2595] monitor/hmp-cmds: add 'goto end' to reduce duplicate code. Signed-off-by: Mao Zhongyi Message-Id: <20200603080904.997083-7-maozhongyi@cmss.chinamobile.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- monitor/hmp-cmds.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 504796d6e9..00e3362cb0 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -1502,8 +1502,7 @@ void hmp_change(Monitor *mon, const QDict *qdict) read_only, BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err); if (err) { - hmp_handle_error(mon, err); - return; + goto end; } } @@ -1512,6 +1511,7 @@ void hmp_change(Monitor *mon, const QDict *qdict) &err); } +end: hmp_handle_error(mon, err); } @@ -1630,13 +1630,13 @@ void hmp_object_add(Monitor *mon, const QDict *qdict) opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err); if (err) { - hmp_handle_error(mon, err); - return; + goto end; } obj = user_creatable_add_opts(opts, &err); qemu_opts_del(opts); +end: hmp_handle_error(mon, err); if (obj) { From afb5d01cb6eb05abfe46a6e6a821df4674f13f2f Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 3 Jun 2020 16:09:02 +0800 Subject: [PATCH 1392/2595] monitor/hmp-cmds: improvements for the 'info migrate' When running: (qemu) info migrate globals: store-global-state: on only-migratable: off ... xbzrle transferred: 640892 kbytes xbzrle pages: 16645936 pages xbzrle cache miss: 1525426 xbzrle cache miss rate: 0.09 xbzrle encoding rate: 91.42 xbzrle overflow: 40896 ... compression pages: 377710 pages compression busy: 0 compression busy rate: 0.00 compressed size: 463169457 compression rate: 3.33 Add units for 'xbzrle cache miss' and 'compressed size', make it easier to read. Suggested-by: Dr. David Alan Gilbert Signed-off-by: Mao Zhongyi Message-Id: <20200603080904.997083-8-maozhongyi@cmss.chinamobile.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- docs/xbzrle.txt | 2 +- monitor/hmp-cmds.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/xbzrle.txt b/docs/xbzrle.txt index b431bdaf0f..385b4993f8 100644 --- a/docs/xbzrle.txt +++ b/docs/xbzrle.txt @@ -112,7 +112,7 @@ is recommended. cache size: H bytes xbzrle transferred: I kbytes xbzrle pages: J pages - xbzrle cache miss: K + xbzrle cache miss: K pages xbzrle overflow: L xbzrle cache-miss: the number of cache misses to date - high cache-miss rate diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 00e3362cb0..2b0b58a336 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -299,7 +299,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) info->xbzrle_cache->bytes >> 10); monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n", info->xbzrle_cache->pages); - monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n", + monitor_printf(mon, "xbzrle cache miss: %" PRIu64 " pages\n", info->xbzrle_cache->cache_miss); monitor_printf(mon, "xbzrle cache miss rate: %0.2f\n", info->xbzrle_cache->cache_miss_rate); @@ -316,8 +316,8 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) info->compression->busy); monitor_printf(mon, "compression busy rate: %0.2f\n", info->compression->busy_rate); - monitor_printf(mon, "compressed size: %" PRIu64 "\n", - info->compression->compressed_size); + monitor_printf(mon, "compressed size: %" PRIu64 " kbytes\n", + info->compression->compressed_size >> 10); monitor_printf(mon, "compression rate: %0.2f\n", info->compression->compression_rate); } From 6bcd361a52e73889d2123033ce48450289a1933e Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 3 Jun 2020 16:09:03 +0800 Subject: [PATCH 1393/2595] docs/xbzrle: update 'cache miss rate' and 'encoding rate' to docs Signed-off-by: Mao Zhongyi Message-Id: <20200603080904.997083-9-maozhongyi@cmss.chinamobile.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- docs/xbzrle.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/xbzrle.txt b/docs/xbzrle.txt index 385b4993f8..6bd1828f34 100644 --- a/docs/xbzrle.txt +++ b/docs/xbzrle.txt @@ -113,9 +113,11 @@ is recommended. xbzrle transferred: I kbytes xbzrle pages: J pages xbzrle cache miss: K pages - xbzrle overflow: L + xbzrle cache miss rate: L + xbzrle encoding rate: M + xbzrle overflow: N -xbzrle cache-miss: the number of cache misses to date - high cache-miss rate +xbzrle cache miss: the number of cache misses to date - high cache-miss rate indicates that the cache size is set too low. xbzrle overflow: the number of overflows in the decoding which where the delta could not be compressed. This can happen if the changes in the pages are too From 7e89a1401a9674c9882948f05f4d17ea7be1c4eb Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 17 Jun 2020 13:31:54 +0200 Subject: [PATCH 1394/2595] migration: fix multifd_send_pages() next channel multifd_send_pages() loops around the available channels, the next channel to use between two calls to multifd_send_pages() is stored inside a local static variable, next_channel. It works well, except if the number of channels decreases between two calls to multifd_send_pages(). In this case, the loop can try to access the data of a channel that doesn't exist anymore. The problem can be triggered if we start a migration with a given number of channels and then we cancel the migration to restart it with a lower number. This ends generally with an error like: qemu-system-ppc64: .../util/qemu-thread-posix.c:77: qemu_mutex_lock_impl: Assertion `mutex->initialized' failed. This patch fixes the error by capping next_channel with the current number of channels before using it. Signed-off-by: Laurent Vivier Message-Id: <20200617113154.593233-1-lvivier@redhat.com> Reviewed-by: Juan Quintela Signed-off-by: Dr. David Alan Gilbert --- migration/multifd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/migration/multifd.c b/migration/multifd.c index 5a3e4d0d46..d0441202aa 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -415,6 +415,12 @@ static int multifd_send_pages(QEMUFile *f) } qemu_sem_wait(&multifd_send_state->channels_ready); + /* + * next_channel can remain from a previous migration that was + * using more channels, so ensure it doesn't overflow if the + * limit is lower now. + */ + next_channel %= migrate_multifd_channels(); for (i = next_channel;; i = (i + 1) % migrate_multifd_channels()) { p = &multifd_send_state->params[i]; From 4066288694c3bdd175df813cad675a3b5191956b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 13:13:04 -0700 Subject: [PATCH 1395/2595] fpu/softfloat: Silence 'bitwise negation of boolean expression' warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building with clang version 10.0.0-4ubuntu1, we get: CC lm32-softmmu/fpu/softfloat.o fpu/softfloat.c:3365:13: error: bitwise negation of a boolean expression; did you mean logical negation? [-Werror,-Wbool-operation] absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ fpu/softfloat.c:3423:18: error: bitwise negation of a boolean expression; did you mean logical negation? [-Werror,-Wbool-operation] absZ0 &= ~ ( ( (uint64_t) ( absZ1<<1 ) == 0 ) & roundNearestEven ); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ... fpu/softfloat.c:4273:18: error: bitwise negation of a boolean expression; did you mean logical negation? [-Werror,-Wbool-operation] zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven ); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fix by rewriting the fishy bitwise AND of two bools as an int. Suggested-by: Eric Blake Buglink: https://bugs.launchpad.net/bugs/1881004 Reviewed-by: Alex Bennée Reviewed-by: Thomas Huth Reviewed-by: Eric Blake Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20200617201309.1640952-2-richard.henderson@linaro.org Message-Id: <20200528155420.9802-1-philmd@redhat.com> Signed-off-by: Richard Henderson Signed-off-by: Peter Maydell --- fpu/softfloat.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 6c8f2d597a..5e9746c287 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -3362,7 +3362,9 @@ static int32_t roundAndPackInt32(bool zSign, uint64_t absZ, } roundBits = absZ & 0x7F; absZ = ( absZ + roundIncrement )>>7; - absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + if (!(roundBits ^ 0x40) && roundNearestEven) { + absZ &= ~1; + } z = absZ; if ( zSign ) z = - z; if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) { @@ -3420,7 +3422,9 @@ static int64_t roundAndPackInt64(bool zSign, uint64_t absZ0, uint64_t absZ1, if ( increment ) { ++absZ0; if ( absZ0 == 0 ) goto overflow; - absZ0 &= ~ ( ( (uint64_t) ( absZ1<<1 ) == 0 ) & roundNearestEven ); + if (!(absZ1 << 1) && roundNearestEven) { + absZ0 &= ~1; + } } z = absZ0; if ( zSign ) z = - z; @@ -3480,7 +3484,9 @@ static int64_t roundAndPackUint64(bool zSign, uint64_t absZ0, float_raise(float_flag_invalid, status); return UINT64_MAX; } - absZ0 &= ~(((uint64_t)(absZ1<<1) == 0) & roundNearestEven); + if (!(absZ1 << 1) && roundNearestEven) { + absZ0 &= ~1; + } } if (zSign && absZ0) { @@ -3603,7 +3609,9 @@ static float32 roundAndPackFloat32(bool zSign, int zExp, uint32_t zSig, status->float_exception_flags |= float_flag_inexact; } zSig = ( zSig + roundIncrement )>>7; - zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + if (!(roundBits ^ 0x40) && roundNearestEven) { + zSig &= ~1; + } if ( zSig == 0 ) zExp = 0; return packFloat32( zSign, zExp, zSig ); @@ -3757,7 +3765,9 @@ static float64 roundAndPackFloat64(bool zSign, int zExp, uint64_t zSig, status->float_exception_flags |= float_flag_inexact; } zSig = ( zSig + roundIncrement )>>10; - zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven ); + if (!(roundBits ^ 0x200) && roundNearestEven) { + zSig &= ~1; + } if ( zSig == 0 ) zExp = 0; return packFloat64( zSign, zExp, zSig ); @@ -3983,8 +3993,9 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign, } if ( increment ) { ++zSig0; - zSig0 &= - ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven ); + if (!(zSig1 << 1) && roundNearestEven) { + zSig0 &= ~1; + } if ( (int64_t) zSig0 < 0 ) zExp = 1; } return packFloatx80( zSign, zExp, zSig0 ); @@ -4000,7 +4011,9 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign, zSig0 = UINT64_C(0x8000000000000000); } else { - zSig0 &= ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven ); + if (!(zSig1 << 1) && roundNearestEven) { + zSig0 &= ~1; + } } } else { @@ -4270,7 +4283,9 @@ static float128 roundAndPackFloat128(bool zSign, int32_t zExp, } if ( increment ) { add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 ); - zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven ); + if ((zSig2 + zSig2 == 0) && roundNearestEven) { + zSig1 &= ~1; + } } else { if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0; From 92271402177bb02930113a853f64952d8689b0c0 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 17 Jun 2020 13:13:05 -0700 Subject: [PATCH 1396/2595] migration: fix xbzrle encoding rate calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's reported an error of implicit conversion from "unsigned long" to "double" when compiling with Clang 10. Simply make the encoding rate 0 when the encoded_size is 0. Fixes: e460a4b1a4 Reviewed-by: Alex Bennée Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Richard Henderson Reported-by: Richard Henderson Signed-off-by: Wei Wang Signed-off-by: Richard Henderson Message-id: 20200617201309.1640952-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- migration/ram.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 41cc530d9d..069b6e30bc 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -913,10 +913,8 @@ static void migration_update_rates(RAMState *rs, int64_t end_time) unencoded_size = (xbzrle_counters.pages - rs->xbzrle_pages_prev) * TARGET_PAGE_SIZE; encoded_size = xbzrle_counters.bytes - rs->xbzrle_bytes_prev; - if (xbzrle_counters.pages == rs->xbzrle_pages_prev) { + if (xbzrle_counters.pages == rs->xbzrle_pages_prev || !encoded_size) { xbzrle_counters.encoding_rate = 0; - } else if (!encoded_size) { - xbzrle_counters.encoding_rate = UINT64_MAX; } else { xbzrle_counters.encoding_rate = unencoded_size / encoded_size; } From 00849b92247403bf5b23fc997e1b383cad8a3759 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 17 Jun 2020 13:13:06 -0700 Subject: [PATCH 1397/2595] configure: Clean up warning flag lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a helper function to tidy the assembly of gcc_flags. Separate flags that disable warnings from those that enable, and sort the disable warnings to the end. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20200617201309.1640952-4-richard.henderson@linaro.org Suggested-by: Eric Blake Signed-off-by: Richard Henderson Signed-off-by: Peter Maydell --- configure | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/configure b/configure index b01b5e3bed..a8bef95282 100755 --- a/configure +++ b/configure @@ -97,6 +97,11 @@ do_cxx() { do_compiler "$cxx" "$@" } +# Append $2 to the variable named $1, with space separation +add_to() { + eval $1=\${$1:+\"\$$1 \"}\$2 +} + update_cxxflags() { # Set QEMU_CXXFLAGS from QEMU_CFLAGS by filtering out those # options which some versions of GCC's C++ compiler complain about @@ -2024,16 +2029,33 @@ if ! compile_prog "" "" ; then error_exit "You need at least GCC v4.8 or Clang v3.4 (or XCode Clang v5.1)" fi -gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits" -gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags" -gcc_flags="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" -gcc_flags="-Wendif-labels -Wno-shift-negative-value $gcc_flags" -gcc_flags="-Wno-initializer-overrides -Wexpansion-to-defined $gcc_flags" -gcc_flags="-Wno-string-plus-int -Wno-typedef-redefinition $gcc_flags" -# Note that we do not add -Werror to gcc_flags here, because that would -# enable it for all configure tests. If a configure test failed due -# to -Werror this would just silently disable some features, -# so it's too error prone. +# Accumulate -Wfoo and -Wno-bar separately. +# We will list all of the enable flags first, and the disable flags second. +# Note that we do not add -Werror, because that would enable it for all +# configure tests. If a configure test failed due to -Werror this would +# just silently disable some features, so it's too error prone. + +warn_flags= +add_to warn_flags -Wold-style-declaration +add_to warn_flags -Wold-style-definition +add_to warn_flags -Wtype-limits +add_to warn_flags -Wformat-security +add_to warn_flags -Wformat-y2k +add_to warn_flags -Winit-self +add_to warn_flags -Wignored-qualifiers +add_to warn_flags -Wempty-body +add_to warn_flags -Wnested-externs +add_to warn_flags -Wendif-labels +add_to warn_flags -Wexpansion-to-defined + +nowarn_flags= +add_to nowarn_flags -Wno-initializer-overrides +add_to nowarn_flags -Wno-missing-include-dirs +add_to nowarn_flags -Wno-shift-negative-value +add_to nowarn_flags -Wno-string-plus-int +add_to nowarn_flags -Wno-typedef-redefinition + +gcc_flags="$warn_flags $nowarn_flags" cc_has_warning_flag() { write_c_skeleton; From aabab96797a7d61989c25a7ca2b094591bbc74f9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 17 Jun 2020 13:13:07 -0700 Subject: [PATCH 1398/2595] configure: Disable -Wtautological-type-limit-compare MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang 10 enables this by default with -Wtype-limit. All of the instances flagged by this Werror so far have been cases in which we really do want the compiler to optimize away the test completely. Disabling the warning will avoid having to add ifdefs to work around this. Cc: Eric Blake Buglink: https://bugs.launchpad.net/qemu/+bug/1878628 Acked-by: Thomas Huth Reviewed-by: Eric Blake Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20200617201309.1640952-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index a8bef95282..5e27229f58 100755 --- a/configure +++ b/configure @@ -2054,6 +2054,7 @@ add_to nowarn_flags -Wno-missing-include-dirs add_to nowarn_flags -Wno-shift-negative-value add_to nowarn_flags -Wno-string-plus-int add_to nowarn_flags -Wno-typedef-redefinition +add_to nowarn_flags -Wno-tautological-type-limit-compare gcc_flags="$warn_flags $nowarn_flags" From bac8d222a19f4a30d0a17980bd932f23a6af77bb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 17 Jun 2020 13:13:08 -0700 Subject: [PATCH 1399/2595] configure: Add -Wno-psabi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On aarch64, gcc 9.3 is generating qemu/exec.c: In function ‘address_space_translate_iommu’: qemu/exec.c:431:28: note: parameter passing for argument of type \ ‘MemTxAttrs’ {aka ‘struct MemTxAttrs’} changed in GCC 9.1 and many other repetitions. This structure, and the functions amongst which it is passed, are not part of a QEMU public API. Therefore we do not care how the compiler passes the argument, so long as the compiler is self-consistent. The only portion of QEMU which does have a public api, and so must have a stable abi, is "qemu/plugin.h". We test this by forcing -Wpsabi in tests/plugin/Makefile. Buglink: https://bugs.launchpad.net/qemu/+bug/1881552 Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20200617201309.1640952-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- configure | 1 + tests/plugin/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 5e27229f58..ba88fd1824 100755 --- a/configure +++ b/configure @@ -2055,6 +2055,7 @@ add_to nowarn_flags -Wno-shift-negative-value add_to nowarn_flags -Wno-string-plus-int add_to nowarn_flags -Wno-typedef-redefinition add_to nowarn_flags -Wno-tautological-type-limit-compare +add_to nowarn_flags -Wno-psabi gcc_flags="$warn_flags $nowarn_flags" diff --git a/tests/plugin/Makefile b/tests/plugin/Makefile index b3250e2504..3a50451428 100644 --- a/tests/plugin/Makefile +++ b/tests/plugin/Makefile @@ -17,7 +17,7 @@ NAMES += lockstep SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES))) -QEMU_CFLAGS += -fPIC +QEMU_CFLAGS += -fPIC -Wpsabi QEMU_CFLAGS += -I$(SRC_PATH)/include/qemu all: $(SONAMES) From f76b348ec78fb7316bbcc981127ae8894cfcc609 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 9 Jun 2020 16:26:53 +0200 Subject: [PATCH 1400/2595] Linux headers: update Update against Linux 5.8-rc1. Signed-off-by: Cornelia Huck --- include/standard-headers/asm-x86/kvm_para.h | 17 +- include/standard-headers/drm/drm_fourcc.h | 140 +++++++- include/standard-headers/linux/ethtool.h | 16 +- include/standard-headers/linux/virtio_ids.h | 1 + include/standard-headers/linux/virtio_mem.h | 211 ++++++++++++ include/standard-headers/linux/virtio_ring.h | 48 ++- linux-headers/asm-arm64/mman.h | 8 + linux-headers/asm-generic/unistd.h | 4 +- linux-headers/asm-mips/unistd_n32.h | 1 + linux-headers/asm-mips/unistd_n64.h | 1 + linux-headers/asm-mips/unistd_o32.h | 1 + linux-headers/asm-powerpc/unistd_32.h | 1 + linux-headers/asm-powerpc/unistd_64.h | 1 + linux-headers/asm-s390/unistd_32.h | 1 + linux-headers/asm-s390/unistd_64.h | 1 + linux-headers/asm-x86/kvm.h | 20 +- linux-headers/asm-x86/unistd.h | 11 +- linux-headers/asm-x86/unistd_32.h | 1 + linux-headers/asm-x86/unistd_64.h | 1 + linux-headers/asm-x86/unistd_x32.h | 1 + linux-headers/linux/kvm.h | 18 +- linux-headers/linux/psp-sev.h | 2 + linux-headers/linux/vfio.h | 322 +++++++++++++++++++ linux-headers/linux/vfio_ccw.h | 19 ++ linux-headers/linux/vhost.h | 4 + 25 files changed, 818 insertions(+), 33 deletions(-) create mode 100644 include/standard-headers/linux/virtio_mem.h diff --git a/include/standard-headers/asm-x86/kvm_para.h b/include/standard-headers/asm-x86/kvm_para.h index 90604a8fb7..07877d3295 100644 --- a/include/standard-headers/asm-x86/kvm_para.h +++ b/include/standard-headers/asm-x86/kvm_para.h @@ -31,6 +31,7 @@ #define KVM_FEATURE_PV_SEND_IPI 11 #define KVM_FEATURE_POLL_CONTROL 12 #define KVM_FEATURE_PV_SCHED_YIELD 13 +#define KVM_FEATURE_ASYNC_PF_INT 14 #define KVM_HINTS_REALTIME 0 @@ -50,6 +51,8 @@ #define MSR_KVM_STEAL_TIME 0x4b564d03 #define MSR_KVM_PV_EOI_EN 0x4b564d04 #define MSR_KVM_POLL_CONTROL 0x4b564d05 +#define MSR_KVM_ASYNC_PF_INT 0x4b564d06 +#define MSR_KVM_ASYNC_PF_ACK 0x4b564d07 struct kvm_steal_time { uint64_t steal; @@ -81,6 +84,11 @@ struct kvm_clock_pairing { #define KVM_ASYNC_PF_ENABLED (1 << 0) #define KVM_ASYNC_PF_SEND_ALWAYS (1 << 1) #define KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT (1 << 2) +#define KVM_ASYNC_PF_DELIVERY_AS_INT (1 << 3) + +/* MSR_KVM_ASYNC_PF_INT */ +#define KVM_ASYNC_PF_VEC_MASK GENMASK(7, 0) + /* Operations for KVM_HC_MMU_OP */ #define KVM_MMU_OP_WRITE_PTE 1 @@ -112,8 +120,13 @@ struct kvm_mmu_op_release_pt { #define KVM_PV_REASON_PAGE_READY 2 struct kvm_vcpu_pv_apf_data { - uint32_t reason; - uint8_t pad[60]; + /* Used for 'page not present' events delivered via #PF */ + uint32_t flags; + + /* Used for 'page ready' events delivered via interrupt notification */ + uint32_t token; + + uint8_t pad[56]; uint32_t enabled; }; diff --git a/include/standard-headers/drm/drm_fourcc.h b/include/standard-headers/drm/drm_fourcc.h index 66e838074c..909a66753c 100644 --- a/include/standard-headers/drm/drm_fourcc.h +++ b/include/standard-headers/drm/drm_fourcc.h @@ -353,9 +353,12 @@ extern "C" { * a platform-dependent stride. On top of that the memory can apply * platform-depending swizzling of some higher address bits into bit6. * - * This format is highly platforms specific and not useful for cross-driver - * sharing. It exists since on a given platform it does uniquely identify the - * layout in a simple way for i915-specific userspace. + * Note that this layout is only accurate on intel gen 8+ or valleyview chipsets. + * On earlier platforms the is highly platforms specific and not useful for + * cross-driver sharing. It exists since on a given platform it does uniquely + * identify the layout in a simple way for i915-specific userspace, which + * facilitated conversion of userspace to modifiers. Additionally the exact + * format on some really old platforms is not known. */ #define I915_FORMAT_MOD_X_TILED fourcc_mod_code(INTEL, 1) @@ -368,9 +371,12 @@ extern "C" { * memory can apply platform-depending swizzling of some higher address bits * into bit6. * - * This format is highly platforms specific and not useful for cross-driver - * sharing. It exists since on a given platform it does uniquely identify the - * layout in a simple way for i915-specific userspace. + * Note that this layout is only accurate on intel gen 8+ or valleyview chipsets. + * On earlier platforms the is highly platforms specific and not useful for + * cross-driver sharing. It exists since on a given platform it does uniquely + * identify the layout in a simple way for i915-specific userspace, which + * facilitated conversion of userspace to modifiers. Additionally the exact + * format on some really old platforms is not known. */ #define I915_FORMAT_MOD_Y_TILED fourcc_mod_code(INTEL, 2) @@ -520,7 +526,113 @@ extern "C" { #define DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED fourcc_mod_code(NVIDIA, 1) /* - * 16Bx2 Block Linear layout, used by desktop GPUs, and Tegra K1 and later + * Generalized Block Linear layout, used by desktop GPUs starting with NV50/G80, + * and Tegra GPUs starting with Tegra K1. + * + * Pixels are arranged in Groups of Bytes (GOBs). GOB size and layout varies + * based on the architecture generation. GOBs themselves are then arranged in + * 3D blocks, with the block dimensions (in terms of GOBs) always being a power + * of two, and hence expressible as their log2 equivalent (E.g., "2" represents + * a block depth or height of "4"). + * + * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format + * in full detail. + * + * Macro + * Bits Param Description + * ---- ----- ----------------------------------------------------------------- + * + * 3:0 h log2(height) of each block, in GOBs. Placed here for + * compatibility with the existing + * DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK()-based modifiers. + * + * 4:4 - Must be 1, to indicate block-linear layout. Necessary for + * compatibility with the existing + * DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK()-based modifiers. + * + * 8:5 - Reserved (To support 3D-surfaces with variable log2(depth) block + * size). Must be zero. + * + * Note there is no log2(width) parameter. Some portions of the + * hardware support a block width of two gobs, but it is impractical + * to use due to lack of support elsewhere, and has no known + * benefits. + * + * 11:9 - Reserved (To support 2D-array textures with variable array stride + * in blocks, specified via log2(tile width in blocks)). Must be + * zero. + * + * 19:12 k Page Kind. This value directly maps to a field in the page + * tables of all GPUs >= NV50. It affects the exact layout of bits + * in memory and can be derived from the tuple + * + * (format, GPU model, compression type, samples per pixel) + * + * Where compression type is defined below. If GPU model were + * implied by the format modifier, format, or memory buffer, page + * kind would not need to be included in the modifier itself, but + * since the modifier should define the layout of the associated + * memory buffer independent from any device or other context, it + * must be included here. + * + * 21:20 g GOB Height and Page Kind Generation. The height of a GOB changed + * starting with Fermi GPUs. Additionally, the mapping between page + * kind and bit layout has changed at various points. + * + * 0 = Gob Height 8, Fermi - Volta, Tegra K1+ Page Kind mapping + * 1 = Gob Height 4, G80 - GT2XX Page Kind mapping + * 2 = Gob Height 8, Turing+ Page Kind mapping + * 3 = Reserved for future use. + * + * 22:22 s Sector layout. On Tegra GPUs prior to Xavier, there is a further + * bit remapping step that occurs at an even lower level than the + * page kind and block linear swizzles. This causes the layout of + * surfaces mapped in those SOC's GPUs to be incompatible with the + * equivalent mapping on other GPUs in the same system. + * + * 0 = Tegra K1 - Tegra Parker/TX2 Layout. + * 1 = Desktop GPU and Tegra Xavier+ Layout + * + * 25:23 c Lossless Framebuffer Compression type. + * + * 0 = none + * 1 = ROP/3D, layout 1, exact compression format implied by Page + * Kind field + * 2 = ROP/3D, layout 2, exact compression format implied by Page + * Kind field + * 3 = CDE horizontal + * 4 = CDE vertical + * 5 = Reserved for future use + * 6 = Reserved for future use + * 7 = Reserved for future use + * + * 55:25 - Reserved for future use. Must be zero. + */ +#define DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(c, s, g, k, h) \ + fourcc_mod_code(NVIDIA, (0x10 | \ + ((h) & 0xf) | \ + (((k) & 0xff) << 12) | \ + (((g) & 0x3) << 20) | \ + (((s) & 0x1) << 22) | \ + (((c) & 0x7) << 23))) + +/* To grandfather in prior block linear format modifiers to the above layout, + * the page kind "0", which corresponds to "pitch/linear" and hence is unusable + * with block-linear layouts, is remapped within drivers to the value 0xfe, + * which corresponds to the "generic" kind used for simple single-sample + * uncompressed color formats on Fermi - Volta GPUs. + */ +static inline uint64_t +drm_fourcc_canonicalize_nvidia_format_mod(uint64_t modifier) +{ + if (!(modifier & 0x10) || (modifier & (0xff << 12))) + return modifier; + else + return modifier | (0xfe << 12); +} + +/* + * 16Bx2 Block Linear layout, used by Tegra K1 and later * * Pixels are arranged in 64x8 Groups Of Bytes (GOBs). GOBs are then stacked * vertically by a power of 2 (1 to 32 GOBs) to form a block. @@ -541,20 +653,20 @@ extern "C" { * in full detail. */ #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(v) \ - fourcc_mod_code(NVIDIA, 0x10 | ((v) & 0xf)) + DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0, (v)) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB \ - fourcc_mod_code(NVIDIA, 0x10) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB \ - fourcc_mod_code(NVIDIA, 0x11) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB \ - fourcc_mod_code(NVIDIA, 0x12) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB \ - fourcc_mod_code(NVIDIA, 0x13) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB \ - fourcc_mod_code(NVIDIA, 0x14) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB \ - fourcc_mod_code(NVIDIA, 0x15) + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5) /* * Some Broadcom modifiers take parameters, for example the number of diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h index 1200890c86..fd8d2cccfe 100644 --- a/include/standard-headers/linux/ethtool.h +++ b/include/standard-headers/linux/ethtool.h @@ -1666,6 +1666,18 @@ static inline int ethtool_validate_duplex(uint8_t duplex) return 0; } +#define MASTER_SLAVE_CFG_UNSUPPORTED 0 +#define MASTER_SLAVE_CFG_UNKNOWN 1 +#define MASTER_SLAVE_CFG_MASTER_PREFERRED 2 +#define MASTER_SLAVE_CFG_SLAVE_PREFERRED 3 +#define MASTER_SLAVE_CFG_MASTER_FORCE 4 +#define MASTER_SLAVE_CFG_SLAVE_FORCE 5 +#define MASTER_SLAVE_STATE_UNSUPPORTED 0 +#define MASTER_SLAVE_STATE_UNKNOWN 1 +#define MASTER_SLAVE_STATE_MASTER 2 +#define MASTER_SLAVE_STATE_SLAVE 3 +#define MASTER_SLAVE_STATE_ERR 4 + /* Which connector port. */ #define PORT_TP 0x00 #define PORT_AUI 0x01 @@ -1904,7 +1916,9 @@ struct ethtool_link_settings { uint8_t eth_tp_mdix_ctrl; int8_t link_mode_masks_nwords; uint8_t transceiver; - uint8_t reserved1[3]; + uint8_t master_slave_cfg; + uint8_t master_slave_state; + uint8_t reserved1[1]; uint32_t reserved[7]; uint32_t link_mode_masks[0]; /* layout of link_mode_masks fields: diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h index ecc27a1740..b052355ac7 100644 --- a/include/standard-headers/linux/virtio_ids.h +++ b/include/standard-headers/linux/virtio_ids.h @@ -44,6 +44,7 @@ #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ #define VIRTIO_ID_CRYPTO 20 /* virtio crypto */ #define VIRTIO_ID_IOMMU 23 /* virtio IOMMU */ +#define VIRTIO_ID_MEM 24 /* virtio mem */ #define VIRTIO_ID_FS 26 /* virtio filesystem */ #define VIRTIO_ID_PMEM 27 /* virtio pmem */ #define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */ diff --git a/include/standard-headers/linux/virtio_mem.h b/include/standard-headers/linux/virtio_mem.h new file mode 100644 index 0000000000..05e5ade75d --- /dev/null +++ b/include/standard-headers/linux/virtio_mem.h @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Virtio Mem Device + * + * Copyright Red Hat, Inc. 2020 + * + * Authors: + * David Hildenbrand + * + * This header is BSD licensed so anyone can use the definitions + * to implement compatible drivers/servers: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of IBM nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LINUX_VIRTIO_MEM_H +#define _LINUX_VIRTIO_MEM_H + +#include "standard-headers/linux/types.h" +#include "standard-headers/linux/virtio_types.h" +#include "standard-headers/linux/virtio_ids.h" +#include "standard-headers/linux/virtio_config.h" + +/* + * Each virtio-mem device manages a dedicated region in physical address + * space. Each device can belong to a single NUMA node, multiple devices + * for a single NUMA node are possible. A virtio-mem device is like a + * "resizable DIMM" consisting of small memory blocks that can be plugged + * or unplugged. The device driver is responsible for (un)plugging memory + * blocks on demand. + * + * Virtio-mem devices can only operate on their assigned memory region in + * order to (un)plug memory. A device cannot (un)plug memory belonging to + * other devices. + * + * The "region_size" corresponds to the maximum amount of memory that can + * be provided by a device. The "size" corresponds to the amount of memory + * that is currently plugged. "requested_size" corresponds to a request + * from the device to the device driver to (un)plug blocks. The + * device driver should try to (un)plug blocks in order to reach the + * "requested_size". It is impossible to plug more memory than requested. + * + * The "usable_region_size" represents the memory region that can actually + * be used to (un)plug memory. It is always at least as big as the + * "requested_size" and will grow dynamically. It will only shrink when + * explicitly triggered (VIRTIO_MEM_REQ_UNPLUG). + * + * There are no guarantees what will happen if unplugged memory is + * read/written. Such memory should, in general, not be touched. E.g., + * even writing might succeed, but the values will simply be discarded at + * random points in time. + * + * It can happen that the device cannot process a request, because it is + * busy. The device driver has to retry later. + * + * Usually, during system resets all memory will get unplugged, so the + * device driver can start with a clean state. However, in specific + * scenarios (if the device is busy) it can happen that the device still + * has memory plugged. The device driver can request to unplug all memory + * (VIRTIO_MEM_REQ_UNPLUG) - which might take a while to succeed if the + * device is busy. + */ + +/* --- virtio-mem: feature bits --- */ + +/* node_id is an ACPI PXM and is valid */ +#define VIRTIO_MEM_F_ACPI_PXM 0 + + +/* --- virtio-mem: guest -> host requests --- */ + +/* request to plug memory blocks */ +#define VIRTIO_MEM_REQ_PLUG 0 +/* request to unplug memory blocks */ +#define VIRTIO_MEM_REQ_UNPLUG 1 +/* request to unplug all blocks and shrink the usable size */ +#define VIRTIO_MEM_REQ_UNPLUG_ALL 2 +/* request information about the plugged state of memory blocks */ +#define VIRTIO_MEM_REQ_STATE 3 + +struct virtio_mem_req_plug { + __virtio64 addr; + __virtio16 nb_blocks; + __virtio16 padding[3]; +}; + +struct virtio_mem_req_unplug { + __virtio64 addr; + __virtio16 nb_blocks; + __virtio16 padding[3]; +}; + +struct virtio_mem_req_state { + __virtio64 addr; + __virtio16 nb_blocks; + __virtio16 padding[3]; +}; + +struct virtio_mem_req { + __virtio16 type; + __virtio16 padding[3]; + + union { + struct virtio_mem_req_plug plug; + struct virtio_mem_req_unplug unplug; + struct virtio_mem_req_state state; + } u; +}; + + +/* --- virtio-mem: host -> guest response --- */ + +/* + * Request processed successfully, applicable for + * - VIRTIO_MEM_REQ_PLUG + * - VIRTIO_MEM_REQ_UNPLUG + * - VIRTIO_MEM_REQ_UNPLUG_ALL + * - VIRTIO_MEM_REQ_STATE + */ +#define VIRTIO_MEM_RESP_ACK 0 +/* + * Request denied - e.g. trying to plug more than requested, applicable for + * - VIRTIO_MEM_REQ_PLUG + */ +#define VIRTIO_MEM_RESP_NACK 1 +/* + * Request cannot be processed right now, try again later, applicable for + * - VIRTIO_MEM_REQ_PLUG + * - VIRTIO_MEM_REQ_UNPLUG + * - VIRTIO_MEM_REQ_UNPLUG_ALL + */ +#define VIRTIO_MEM_RESP_BUSY 2 +/* + * Error in request (e.g. addresses/alignment), applicable for + * - VIRTIO_MEM_REQ_PLUG + * - VIRTIO_MEM_REQ_UNPLUG + * - VIRTIO_MEM_REQ_STATE + */ +#define VIRTIO_MEM_RESP_ERROR 3 + + +/* State of memory blocks is "plugged" */ +#define VIRTIO_MEM_STATE_PLUGGED 0 +/* State of memory blocks is "unplugged" */ +#define VIRTIO_MEM_STATE_UNPLUGGED 1 +/* State of memory blocks is "mixed" */ +#define VIRTIO_MEM_STATE_MIXED 2 + +struct virtio_mem_resp_state { + __virtio16 state; +}; + +struct virtio_mem_resp { + __virtio16 type; + __virtio16 padding[3]; + + union { + struct virtio_mem_resp_state state; + } u; +}; + +/* --- virtio-mem: configuration --- */ + +struct virtio_mem_config { + /* Block size and alignment. Cannot change. */ + uint64_t block_size; + /* Valid with VIRTIO_MEM_F_ACPI_PXM. Cannot change. */ + uint16_t node_id; + uint8_t padding[6]; + /* Start address of the memory region. Cannot change. */ + uint64_t addr; + /* Region size (maximum). Cannot change. */ + uint64_t region_size; + /* + * Currently usable region size. Can grow up to region_size. Can + * shrink due to VIRTIO_MEM_REQ_UNPLUG_ALL (in which case no config + * update will be sent). + */ + uint64_t usable_region_size; + /* + * Currently used size. Changes due to plug/unplug requests, but no + * config updates will be sent. + */ + uint64_t plugged_size; + /* Requested size. New plug requests cannot exceed it. Can change. */ + uint64_t requested_size; +}; + +#endif /* _LINUX_VIRTIO_MEM_H */ diff --git a/include/standard-headers/linux/virtio_ring.h b/include/standard-headers/linux/virtio_ring.h index f230fed479..0fa0e1067f 100644 --- a/include/standard-headers/linux/virtio_ring.h +++ b/include/standard-headers/linux/virtio_ring.h @@ -84,6 +84,13 @@ * at the end of the used ring. Guest should ignore the used->flags field. */ #define VIRTIO_RING_F_EVENT_IDX 29 +/* Alignment requirements for vring elements. + * When using pre-virtio 1.0 layout, these fall out naturally. + */ +#define VRING_AVAIL_ALIGN_SIZE 2 +#define VRING_USED_ALIGN_SIZE 4 +#define VRING_DESC_ALIGN_SIZE 16 + /* Virtio ring descriptors: 16 bytes. These can chain together via "next". */ struct vring_desc { /* Address (guest-physical). */ @@ -110,28 +117,47 @@ struct vring_used_elem { __virtio32 len; }; +typedef struct vring_used_elem __attribute__((aligned(VRING_USED_ALIGN_SIZE))) + vring_used_elem_t; + struct vring_used { __virtio16 flags; __virtio16 idx; - struct vring_used_elem ring[]; + vring_used_elem_t ring[]; }; +/* + * The ring element addresses are passed between components with different + * alignments assumptions. Thus, we might need to decrease the compiler-selected + * alignment, and so must use a typedef to make sure the aligned attribute + * actually takes hold: + * + * https://gcc.gnu.org/onlinedocs//gcc/Common-Type-Attributes.html#Common-Type-Attributes + * + * When used on a struct, or struct member, the aligned attribute can only + * increase the alignment; in order to decrease it, the packed attribute must + * be specified as well. When used as part of a typedef, the aligned attribute + * can both increase and decrease alignment, and specifying the packed + * attribute generates a warning. + */ +typedef struct vring_desc __attribute__((aligned(VRING_DESC_ALIGN_SIZE))) + vring_desc_t; +typedef struct vring_avail __attribute__((aligned(VRING_AVAIL_ALIGN_SIZE))) + vring_avail_t; +typedef struct vring_used __attribute__((aligned(VRING_USED_ALIGN_SIZE))) + vring_used_t; + struct vring { unsigned int num; - struct vring_desc *desc; + vring_desc_t *desc; - struct vring_avail *avail; + vring_avail_t *avail; - struct vring_used *used; + vring_used_t *used; }; -/* Alignment requirements for vring elements. - * When using pre-virtio 1.0 layout, these fall out naturally. - */ -#define VRING_AVAIL_ALIGN_SIZE 2 -#define VRING_USED_ALIGN_SIZE 4 -#define VRING_DESC_ALIGN_SIZE 16 +#ifndef VIRTIO_RING_NO_LEGACY /* The standard layout for the ring is a continuous chunk of memory which looks * like this. We assume num is a power of 2. @@ -179,6 +205,8 @@ static inline unsigned vring_size(unsigned int num, unsigned long align) + sizeof(__virtio16) * 3 + sizeof(struct vring_used_elem) * num; } +#endif /* VIRTIO_RING_NO_LEGACY */ + /* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */ /* Assuming a given event_idx value from the other side, if * we have just incremented index from old to new_idx, diff --git a/linux-headers/asm-arm64/mman.h b/linux-headers/asm-arm64/mman.h index 8eebf89f5a..e94b9af859 100644 --- a/linux-headers/asm-arm64/mman.h +++ b/linux-headers/asm-arm64/mman.h @@ -1 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __ASM_MMAN_H +#define __ASM_MMAN_H + #include + +#define PROT_BTI 0x10 /* BTI guarded page */ + +#endif /* ! _UAPI__ASM_MMAN_H */ diff --git a/linux-headers/asm-generic/unistd.h b/linux-headers/asm-generic/unistd.h index 3a3201e461..f4a01305d9 100644 --- a/linux-headers/asm-generic/unistd.h +++ b/linux-headers/asm-generic/unistd.h @@ -855,9 +855,11 @@ __SYSCALL(__NR_clone3, sys_clone3) __SYSCALL(__NR_openat2, sys_openat2) #define __NR_pidfd_getfd 438 __SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd) +#define __NR_faccessat2 439 +__SYSCALL(__NR_faccessat2, sys_faccessat2) #undef __NR_syscalls -#define __NR_syscalls 439 +#define __NR_syscalls 440 /* * 32 bit systems traditionally used different diff --git a/linux-headers/asm-mips/unistd_n32.h b/linux-headers/asm-mips/unistd_n32.h index aec9f6081a..3b9eda7e7d 100644 --- a/linux-headers/asm-mips/unistd_n32.h +++ b/linux-headers/asm-mips/unistd_n32.h @@ -367,6 +367,7 @@ #define __NR_clone3 (__NR_Linux + 435) #define __NR_openat2 (__NR_Linux + 437) #define __NR_pidfd_getfd (__NR_Linux + 438) +#define __NR_faccessat2 (__NR_Linux + 439) #endif /* _ASM_MIPS_UNISTD_N32_H */ diff --git a/linux-headers/asm-mips/unistd_n64.h b/linux-headers/asm-mips/unistd_n64.h index 1c75d83df5..9cdf9b6c60 100644 --- a/linux-headers/asm-mips/unistd_n64.h +++ b/linux-headers/asm-mips/unistd_n64.h @@ -343,6 +343,7 @@ #define __NR_clone3 (__NR_Linux + 435) #define __NR_openat2 (__NR_Linux + 437) #define __NR_pidfd_getfd (__NR_Linux + 438) +#define __NR_faccessat2 (__NR_Linux + 439) #endif /* _ASM_MIPS_UNISTD_N64_H */ diff --git a/linux-headers/asm-mips/unistd_o32.h b/linux-headers/asm-mips/unistd_o32.h index 660716e240..e3e5e238f0 100644 --- a/linux-headers/asm-mips/unistd_o32.h +++ b/linux-headers/asm-mips/unistd_o32.h @@ -413,6 +413,7 @@ #define __NR_clone3 (__NR_Linux + 435) #define __NR_openat2 (__NR_Linux + 437) #define __NR_pidfd_getfd (__NR_Linux + 438) +#define __NR_faccessat2 (__NR_Linux + 439) #endif /* _ASM_MIPS_UNISTD_O32_H */ diff --git a/linux-headers/asm-powerpc/unistd_32.h b/linux-headers/asm-powerpc/unistd_32.h index 4ba8e32f73..862edb7448 100644 --- a/linux-headers/asm-powerpc/unistd_32.h +++ b/linux-headers/asm-powerpc/unistd_32.h @@ -420,6 +420,7 @@ #define __NR_clone3 435 #define __NR_openat2 437 #define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 #endif /* _ASM_POWERPC_UNISTD_32_H */ diff --git a/linux-headers/asm-powerpc/unistd_64.h b/linux-headers/asm-powerpc/unistd_64.h index ac20bb4f95..f553224ce4 100644 --- a/linux-headers/asm-powerpc/unistd_64.h +++ b/linux-headers/asm-powerpc/unistd_64.h @@ -392,6 +392,7 @@ #define __NR_clone3 435 #define __NR_openat2 437 #define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 #endif /* _ASM_POWERPC_UNISTD_64_H */ diff --git a/linux-headers/asm-s390/unistd_32.h b/linux-headers/asm-s390/unistd_32.h index e4a6b654f1..e08233c0c3 100644 --- a/linux-headers/asm-s390/unistd_32.h +++ b/linux-headers/asm-s390/unistd_32.h @@ -410,5 +410,6 @@ #define __NR_clone3 435 #define __NR_openat2 437 #define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 #endif /* _ASM_S390_UNISTD_32_H */ diff --git a/linux-headers/asm-s390/unistd_64.h b/linux-headers/asm-s390/unistd_64.h index 472f732956..560e19ae2b 100644 --- a/linux-headers/asm-s390/unistd_64.h +++ b/linux-headers/asm-s390/unistd_64.h @@ -358,5 +358,6 @@ #define __NR_clone3 435 #define __NR_openat2 437 #define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 #endif /* _ASM_S390_UNISTD_64_H */ diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index 3f3f780c8c..17c5a038f4 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -385,32 +385,48 @@ struct kvm_sync_regs { #define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4) #define KVM_STATE_NESTED_FORMAT_VMX 0 -#define KVM_STATE_NESTED_FORMAT_SVM 1 /* unused */ +#define KVM_STATE_NESTED_FORMAT_SVM 1 #define KVM_STATE_NESTED_GUEST_MODE 0x00000001 #define KVM_STATE_NESTED_RUN_PENDING 0x00000002 #define KVM_STATE_NESTED_EVMCS 0x00000004 #define KVM_STATE_NESTED_MTF_PENDING 0x00000008 +#define KVM_STATE_NESTED_GIF_SET 0x00000100 #define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001 #define KVM_STATE_NESTED_SMM_VMXON 0x00000002 #define KVM_STATE_NESTED_VMX_VMCS_SIZE 0x1000 +#define KVM_STATE_NESTED_SVM_VMCB_SIZE 0x1000 + +#define KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE 0x00000001 + struct kvm_vmx_nested_state_data { __u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE]; __u8 shadow_vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE]; }; struct kvm_vmx_nested_state_hdr { + __u32 flags; __u64 vmxon_pa; __u64 vmcs12_pa; + __u64 preemption_timer_deadline; struct { __u16 flags; } smm; }; +struct kvm_svm_nested_state_data { + /* Save area only used if KVM_STATE_NESTED_RUN_PENDING. */ + __u8 vmcb12[KVM_STATE_NESTED_SVM_VMCB_SIZE]; +}; + +struct kvm_svm_nested_state_hdr { + __u64 vmcb_pa; +}; + /* for KVM_CAP_NESTED_STATE */ struct kvm_nested_state { __u16 flags; @@ -419,6 +435,7 @@ struct kvm_nested_state { union { struct kvm_vmx_nested_state_hdr vmx; + struct kvm_svm_nested_state_hdr svm; /* Pad the header to 128 bytes. */ __u8 pad[120]; @@ -431,6 +448,7 @@ struct kvm_nested_state { */ union { struct kvm_vmx_nested_state_data vmx[0]; + struct kvm_svm_nested_state_data svm[0]; } data; }; diff --git a/linux-headers/asm-x86/unistd.h b/linux-headers/asm-x86/unistd.h index 498d1515c6..d2af42d61d 100644 --- a/linux-headers/asm-x86/unistd.h +++ b/linux-headers/asm-x86/unistd.h @@ -2,8 +2,15 @@ #ifndef _ASM_X86_UNISTD_H #define _ASM_X86_UNISTD_H -/* x32 syscall flag bit */ -#define __X32_SYSCALL_BIT 0x40000000UL +/* + * x32 syscall flag bit. Some user programs expect syscall NR macros + * and __X32_SYSCALL_BIT to have type int, even though syscall numbers + * are, for practical purposes, unsigned long. + * + * Fortunately, expressions like (nr & ~__X32_SYSCALL_BIT) do the right + * thing regardless. + */ +#define __X32_SYSCALL_BIT 0x40000000 # ifdef __i386__ # include diff --git a/linux-headers/asm-x86/unistd_32.h b/linux-headers/asm-x86/unistd_32.h index 1e6c1a5867..c727981d4a 100644 --- a/linux-headers/asm-x86/unistd_32.h +++ b/linux-headers/asm-x86/unistd_32.h @@ -428,6 +428,7 @@ #define __NR_clone3 435 #define __NR_openat2 437 #define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 #endif /* _ASM_X86_UNISTD_32_H */ diff --git a/linux-headers/asm-x86/unistd_64.h b/linux-headers/asm-x86/unistd_64.h index 6daf0aecb2..843fa62745 100644 --- a/linux-headers/asm-x86/unistd_64.h +++ b/linux-headers/asm-x86/unistd_64.h @@ -350,6 +350,7 @@ #define __NR_clone3 435 #define __NR_openat2 437 #define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 #endif /* _ASM_X86_UNISTD_64_H */ diff --git a/linux-headers/asm-x86/unistd_x32.h b/linux-headers/asm-x86/unistd_x32.h index e3f17ef370..7d63d703ca 100644 --- a/linux-headers/asm-x86/unistd_x32.h +++ b/linux-headers/asm-x86/unistd_x32.h @@ -303,6 +303,7 @@ #define __NR_clone3 (__X32_SYSCALL_BIT + 435) #define __NR_openat2 (__X32_SYSCALL_BIT + 437) #define __NR_pidfd_getfd (__X32_SYSCALL_BIT + 438) +#define __NR_faccessat2 (__X32_SYSCALL_BIT + 439) #define __NR_rt_sigaction (__X32_SYSCALL_BIT + 512) #define __NR_rt_sigreturn (__X32_SYSCALL_BIT + 513) #define __NR_ioctl (__X32_SYSCALL_BIT + 514) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 9804495a46..a28c366737 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -116,7 +116,7 @@ struct kvm_irq_level { * ACPI gsi notion of irq. * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47.. * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23.. - * For ARM: See Documentation/virt/kvm/api.txt + * For ARM: See Documentation/virt/kvm/api.rst */ union { __u32 irq; @@ -188,10 +188,13 @@ struct kvm_s390_cmma_log { struct kvm_hyperv_exit { #define KVM_EXIT_HYPERV_SYNIC 1 #define KVM_EXIT_HYPERV_HCALL 2 +#define KVM_EXIT_HYPERV_SYNDBG 3 __u32 type; + __u32 pad1; union { struct { __u32 msr; + __u32 pad2; __u64 control; __u64 evt_page; __u64 msg_page; @@ -201,6 +204,15 @@ struct kvm_hyperv_exit { __u64 result; __u64 params[2]; } hcall; + struct { + __u32 msr; + __u32 pad2; + __u64 control; + __u64 status; + __u64 send_page; + __u64 recv_page; + __u64 pending_page; + } syndbg; } u; }; @@ -1017,6 +1029,8 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_S390_VCPU_RESETS 179 #define KVM_CAP_S390_PROTECTED 180 #define KVM_CAP_PPC_SECURE_GUEST 181 +#define KVM_CAP_HALT_POLL 182 +#define KVM_CAP_ASYNC_PF_INT 183 #ifdef KVM_CAP_IRQ_ROUTING @@ -1107,7 +1121,7 @@ struct kvm_xen_hvm_config { * * KVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies * the irqfd to operate in resampling mode for level triggered interrupt - * emulation. See Documentation/virt/kvm/api.txt. + * emulation. See Documentation/virt/kvm/api.rst. */ #define KVM_IRQFD_FLAG_RESAMPLE (1 << 1) diff --git a/linux-headers/linux/psp-sev.h b/linux-headers/linux/psp-sev.h index 31f971e896..51d8b3940e 100644 --- a/linux-headers/linux/psp-sev.h +++ b/linux-headers/linux/psp-sev.h @@ -83,6 +83,8 @@ struct sev_user_data_status { __u32 guest_count; /* Out */ } __attribute__((packed)); +#define SEV_STATUS_FLAGS_CONFIG_ES 0x0100 + /** * struct sev_user_data_pek_csr - PEK_CSR command parameters * diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index a41c452865..f09df262c4 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -305,6 +305,7 @@ struct vfio_region_info_cap_type { #define VFIO_REGION_TYPE_PCI_VENDOR_MASK (0xffff) #define VFIO_REGION_TYPE_GFX (1) #define VFIO_REGION_TYPE_CCW (2) +#define VFIO_REGION_TYPE_MIGRATION (3) /* sub-types for VFIO_REGION_TYPE_PCI_* */ @@ -378,6 +379,235 @@ struct vfio_region_gfx_edid { /* sub-types for VFIO_REGION_TYPE_CCW */ #define VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD (1) +#define VFIO_REGION_SUBTYPE_CCW_SCHIB (2) +#define VFIO_REGION_SUBTYPE_CCW_CRW (3) + +/* sub-types for VFIO_REGION_TYPE_MIGRATION */ +#define VFIO_REGION_SUBTYPE_MIGRATION (1) + +/* + * The structure vfio_device_migration_info is placed at the 0th offset of + * the VFIO_REGION_SUBTYPE_MIGRATION region to get and set VFIO device related + * migration information. Field accesses from this structure are only supported + * at their native width and alignment. Otherwise, the result is undefined and + * vendor drivers should return an error. + * + * device_state: (read/write) + * - The user application writes to this field to inform the vendor driver + * about the device state to be transitioned to. + * - The vendor driver should take the necessary actions to change the + * device state. After successful transition to a given state, the + * vendor driver should return success on write(device_state, state) + * system call. If the device state transition fails, the vendor driver + * should return an appropriate -errno for the fault condition. + * - On the user application side, if the device state transition fails, + * that is, if write(device_state, state) returns an error, read + * device_state again to determine the current state of the device from + * the vendor driver. + * - The vendor driver should return previous state of the device unless + * the vendor driver has encountered an internal error, in which case + * the vendor driver may report the device_state VFIO_DEVICE_STATE_ERROR. + * - The user application must use the device reset ioctl to recover the + * device from VFIO_DEVICE_STATE_ERROR state. If the device is + * indicated to be in a valid device state by reading device_state, the + * user application may attempt to transition the device to any valid + * state reachable from the current state or terminate itself. + * + * device_state consists of 3 bits: + * - If bit 0 is set, it indicates the _RUNNING state. If bit 0 is clear, + * it indicates the _STOP state. When the device state is changed to + * _STOP, driver should stop the device before write() returns. + * - If bit 1 is set, it indicates the _SAVING state, which means that the + * driver should start gathering device state information that will be + * provided to the VFIO user application to save the device's state. + * - If bit 2 is set, it indicates the _RESUMING state, which means that + * the driver should prepare to resume the device. Data provided through + * the migration region should be used to resume the device. + * Bits 3 - 31 are reserved for future use. To preserve them, the user + * application should perform a read-modify-write operation on this + * field when modifying the specified bits. + * + * +------- _RESUMING + * |+------ _SAVING + * ||+----- _RUNNING + * ||| + * 000b => Device Stopped, not saving or resuming + * 001b => Device running, which is the default state + * 010b => Stop the device & save the device state, stop-and-copy state + * 011b => Device running and save the device state, pre-copy state + * 100b => Device stopped and the device state is resuming + * 101b => Invalid state + * 110b => Error state + * 111b => Invalid state + * + * State transitions: + * + * _RESUMING _RUNNING Pre-copy Stop-and-copy _STOP + * (100b) (001b) (011b) (010b) (000b) + * 0. Running or default state + * | + * + * 1. Normal Shutdown (optional) + * |------------------------------------->| + * + * 2. Save the state or suspend + * |------------------------->|---------->| + * + * 3. Save the state during live migration + * |----------->|------------>|---------->| + * + * 4. Resuming + * |<---------| + * + * 5. Resumed + * |--------->| + * + * 0. Default state of VFIO device is _RUNNNG when the user application starts. + * 1. During normal shutdown of the user application, the user application may + * optionally change the VFIO device state from _RUNNING to _STOP. This + * transition is optional. The vendor driver must support this transition but + * must not require it. + * 2. When the user application saves state or suspends the application, the + * device state transitions from _RUNNING to stop-and-copy and then to _STOP. + * On state transition from _RUNNING to stop-and-copy, driver must stop the + * device, save the device state and send it to the application through the + * migration region. The sequence to be followed for such transition is given + * below. + * 3. In live migration of user application, the state transitions from _RUNNING + * to pre-copy, to stop-and-copy, and to _STOP. + * On state transition from _RUNNING to pre-copy, the driver should start + * gathering the device state while the application is still running and send + * the device state data to application through the migration region. + * On state transition from pre-copy to stop-and-copy, the driver must stop + * the device, save the device state and send it to the user application + * through the migration region. + * Vendor drivers must support the pre-copy state even for implementations + * where no data is provided to the user before the stop-and-copy state. The + * user must not be required to consume all migration data before the device + * transitions to a new state, including the stop-and-copy state. + * The sequence to be followed for above two transitions is given below. + * 4. To start the resuming phase, the device state should be transitioned from + * the _RUNNING to the _RESUMING state. + * In the _RESUMING state, the driver should use the device state data + * received through the migration region to resume the device. + * 5. After providing saved device data to the driver, the application should + * change the state from _RESUMING to _RUNNING. + * + * reserved: + * Reads on this field return zero and writes are ignored. + * + * pending_bytes: (read only) + * The number of pending bytes still to be migrated from the vendor driver. + * + * data_offset: (read only) + * The user application should read data_offset field from the migration + * region. The user application should read the device data from this + * offset within the migration region during the _SAVING state or write + * the device data during the _RESUMING state. See below for details of + * sequence to be followed. + * + * data_size: (read/write) + * The user application should read data_size to get the size in bytes of + * the data copied in the migration region during the _SAVING state and + * write the size in bytes of the data copied in the migration region + * during the _RESUMING state. + * + * The format of the migration region is as follows: + * ------------------------------------------------------------------ + * |vfio_device_migration_info| data section | + * | | /////////////////////////////// | + * ------------------------------------------------------------------ + * ^ ^ + * offset 0-trapped part data_offset + * + * The structure vfio_device_migration_info is always followed by the data + * section in the region, so data_offset will always be nonzero. The offset + * from where the data is copied is decided by the kernel driver. The data + * section can be trapped, mmapped, or partitioned, depending on how the kernel + * driver defines the data section. The data section partition can be defined + * as mapped by the sparse mmap capability. If mmapped, data_offset must be + * page aligned, whereas initial section which contains the + * vfio_device_migration_info structure, might not end at the offset, which is + * page aligned. The user is not required to access through mmap regardless + * of the capabilities of the region mmap. + * The vendor driver should determine whether and how to partition the data + * section. The vendor driver should return data_offset accordingly. + * + * The sequence to be followed while in pre-copy state and stop-and-copy state + * is as follows: + * a. Read pending_bytes, indicating the start of a new iteration to get device + * data. Repeated read on pending_bytes at this stage should have no side + * effects. + * If pending_bytes == 0, the user application should not iterate to get data + * for that device. + * If pending_bytes > 0, perform the following steps. + * b. Read data_offset, indicating that the vendor driver should make data + * available through the data section. The vendor driver should return this + * read operation only after data is available from (region + data_offset) + * to (region + data_offset + data_size). + * c. Read data_size, which is the amount of data in bytes available through + * the migration region. + * Read on data_offset and data_size should return the offset and size of + * the current buffer if the user application reads data_offset and + * data_size more than once here. + * d. Read data_size bytes of data from (region + data_offset) from the + * migration region. + * e. Process the data. + * f. Read pending_bytes, which indicates that the data from the previous + * iteration has been read. If pending_bytes > 0, go to step b. + * + * The user application can transition from the _SAVING|_RUNNING + * (pre-copy state) to the _SAVING (stop-and-copy) state regardless of the + * number of pending bytes. The user application should iterate in _SAVING + * (stop-and-copy) until pending_bytes is 0. + * + * The sequence to be followed while _RESUMING device state is as follows: + * While data for this device is available, repeat the following steps: + * a. Read data_offset from where the user application should write data. + * b. Write migration data starting at the migration region + data_offset for + * the length determined by data_size from the migration source. + * c. Write data_size, which indicates to the vendor driver that data is + * written in the migration region. Vendor driver must return this write + * operations on consuming data. Vendor driver should apply the + * user-provided migration region data to the device resume state. + * + * If an error occurs during the above sequences, the vendor driver can return + * an error code for next read() or write() operation, which will terminate the + * loop. The user application should then take the next necessary action, for + * example, failing migration or terminating the user application. + * + * For the user application, data is opaque. The user application should write + * data in the same order as the data is received and the data should be of + * same transaction size at the source. + */ + +struct vfio_device_migration_info { + __u32 device_state; /* VFIO device state */ +#define VFIO_DEVICE_STATE_STOP (0) +#define VFIO_DEVICE_STATE_RUNNING (1 << 0) +#define VFIO_DEVICE_STATE_SAVING (1 << 1) +#define VFIO_DEVICE_STATE_RESUMING (1 << 2) +#define VFIO_DEVICE_STATE_MASK (VFIO_DEVICE_STATE_RUNNING | \ + VFIO_DEVICE_STATE_SAVING | \ + VFIO_DEVICE_STATE_RESUMING) + +#define VFIO_DEVICE_STATE_VALID(state) \ + (state & VFIO_DEVICE_STATE_RESUMING ? \ + (state & VFIO_DEVICE_STATE_MASK) == VFIO_DEVICE_STATE_RESUMING : 1) + +#define VFIO_DEVICE_STATE_IS_ERROR(state) \ + ((state & VFIO_DEVICE_STATE_MASK) == (VFIO_DEVICE_STATE_SAVING | \ + VFIO_DEVICE_STATE_RESUMING)) + +#define VFIO_DEVICE_STATE_SET_ERROR(state) \ + ((state & ~VFIO_DEVICE_STATE_MASK) | VFIO_DEVICE_SATE_SAVING | \ + VFIO_DEVICE_STATE_RESUMING) + + __u32 reserved; + __u64 pending_bytes; + __u64 data_offset; + __u64 data_size; +}; /* * The MSIX mappable capability informs that MSIX data of a BAR can be mmapped @@ -577,6 +807,7 @@ enum { enum { VFIO_CCW_IO_IRQ_INDEX, + VFIO_CCW_CRW_IRQ_INDEX, VFIO_CCW_NUM_IRQS }; @@ -785,6 +1016,29 @@ struct vfio_iommu_type1_info_cap_iova_range { struct vfio_iova_range iova_ranges[]; }; +/* + * The migration capability allows to report supported features for migration. + * + * The structures below define version 1 of this capability. + * + * The existence of this capability indicates that IOMMU kernel driver supports + * dirty page logging. + * + * pgsize_bitmap: Kernel driver returns bitmap of supported page sizes for dirty + * page logging. + * max_dirty_bitmap_size: Kernel driver returns maximum supported dirty bitmap + * size in bytes that can be used by user applications when getting the dirty + * bitmap. + */ +#define VFIO_IOMMU_TYPE1_INFO_CAP_MIGRATION 1 + +struct vfio_iommu_type1_info_cap_migration { + struct vfio_info_cap_header header; + __u32 flags; + __u64 pgsize_bitmap; + __u64 max_dirty_bitmap_size; /* in bytes */ +}; + #define VFIO_IOMMU_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12) /** @@ -805,6 +1059,12 @@ struct vfio_iommu_type1_dma_map { #define VFIO_IOMMU_MAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 13) +struct vfio_bitmap { + __u64 pgsize; /* page size for bitmap in bytes */ + __u64 size; /* in bytes */ + __u64 *data; /* one bit per page */ +}; + /** * VFIO_IOMMU_UNMAP_DMA - _IOWR(VFIO_TYPE, VFIO_BASE + 14, * struct vfio_dma_unmap) @@ -814,12 +1074,23 @@ struct vfio_iommu_type1_dma_map { * field. No guarantee is made to the user that arbitrary unmaps of iova * or size different from those used in the original mapping call will * succeed. + * VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP should be set to get the dirty bitmap + * before unmapping IO virtual addresses. When this flag is set, the user must + * provide a struct vfio_bitmap in data[]. User must provide zero-allocated + * memory via vfio_bitmap.data and its size in the vfio_bitmap.size field. + * A bit in the bitmap represents one page, of user provided page size in + * vfio_bitmap.pgsize field, consecutively starting from iova offset. Bit set + * indicates that the page at that offset from iova is dirty. A Bitmap of the + * pages in the range of unmapped size is returned in the user-provided + * vfio_bitmap.data. */ struct vfio_iommu_type1_dma_unmap { __u32 argsz; __u32 flags; +#define VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP (1 << 0) __u64 iova; /* IO virtual address */ __u64 size; /* Size of mapping (bytes) */ + __u8 data[]; }; #define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14) @@ -831,6 +1102,57 @@ struct vfio_iommu_type1_dma_unmap { #define VFIO_IOMMU_ENABLE _IO(VFIO_TYPE, VFIO_BASE + 15) #define VFIO_IOMMU_DISABLE _IO(VFIO_TYPE, VFIO_BASE + 16) +/** + * VFIO_IOMMU_DIRTY_PAGES - _IOWR(VFIO_TYPE, VFIO_BASE + 17, + * struct vfio_iommu_type1_dirty_bitmap) + * IOCTL is used for dirty pages logging. + * Caller should set flag depending on which operation to perform, details as + * below: + * + * Calling the IOCTL with VFIO_IOMMU_DIRTY_PAGES_FLAG_START flag set, instructs + * the IOMMU driver to log pages that are dirtied or potentially dirtied by + * the device; designed to be used when a migration is in progress. Dirty pages + * are logged until logging is disabled by user application by calling the IOCTL + * with VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP flag. + * + * Calling the IOCTL with VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP flag set, instructs + * the IOMMU driver to stop logging dirtied pages. + * + * Calling the IOCTL with VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP flag set + * returns the dirty pages bitmap for IOMMU container for a given IOVA range. + * The user must specify the IOVA range and the pgsize through the structure + * vfio_iommu_type1_dirty_bitmap_get in the data[] portion. This interface + * supports getting a bitmap of the smallest supported pgsize only and can be + * modified in future to get a bitmap of any specified supported pgsize. The + * user must provide a zeroed memory area for the bitmap memory and specify its + * size in bitmap.size. One bit is used to represent one page consecutively + * starting from iova offset. The user should provide page size in bitmap.pgsize + * field. A bit set in the bitmap indicates that the page at that offset from + * iova is dirty. The caller must set argsz to a value including the size of + * structure vfio_iommu_type1_dirty_bitmap_get, but excluding the size of the + * actual bitmap. If dirty pages logging is not enabled, an error will be + * returned. + * + * Only one of the flags _START, _STOP and _GET may be specified at a time. + * + */ +struct vfio_iommu_type1_dirty_bitmap { + __u32 argsz; + __u32 flags; +#define VFIO_IOMMU_DIRTY_PAGES_FLAG_START (1 << 0) +#define VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP (1 << 1) +#define VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP (1 << 2) + __u8 data[]; +}; + +struct vfio_iommu_type1_dirty_bitmap_get { + __u64 iova; /* IO virtual address */ + __u64 size; /* Size of iova range */ + struct vfio_bitmap bitmap; +}; + +#define VFIO_IOMMU_DIRTY_PAGES _IO(VFIO_TYPE, VFIO_BASE + 17) + /* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */ /* diff --git a/linux-headers/linux/vfio_ccw.h b/linux-headers/linux/vfio_ccw.h index fcc3e69ef5..516496f1d4 100644 --- a/linux-headers/linux/vfio_ccw.h +++ b/linux-headers/linux/vfio_ccw.h @@ -34,4 +34,23 @@ struct ccw_cmd_region { __u32 ret_code; } __attribute__((packed)); +/* + * Used for processing commands that read the subchannel-information block + * Reading this region triggers a stsch() to hardware + * Note: this is controlled by a capability + */ +struct ccw_schib_region { +#define SCHIB_AREA_SIZE 52 + __u8 schib_area[SCHIB_AREA_SIZE]; +} __attribute__((packed)); + +/* + * Used for returning a Channel Report Word to userspace. + * Note: this is controlled by a capability + */ +struct ccw_crw_region { + __u32 crw; + __u32 pad; +} __attribute__((packed)); + #endif diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h index 9fe72e4b13..0c2349612e 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -15,6 +15,8 @@ #include #include +#define VHOST_FILE_UNBIND -1 + /* ioctls */ #define VHOST_VIRTIO 0xAF @@ -140,4 +142,6 @@ /* Get the max ring size. */ #define VHOST_VDPA_GET_VRING_NUM _IOR(VHOST_VIRTIO, 0x76, __u16) +/* Set event fd for config interrupt*/ +#define VHOST_VDPA_SET_CONFIG_CALL _IOW(VHOST_VIRTIO, 0x77, int) #endif From 2a3b9cbaa7b25a4db4cdcfe1c65279c5464f2923 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Tue, 5 May 2020 14:57:53 +0200 Subject: [PATCH 1401/2595] vfio-ccw: Refactor cleanup of regions While we're at it, add a g_free() for the async_cmd_region that is the last thing currently created. g_free() knows how to handle NULL pointers, so this makes it easier to remember what cleanups need to be performed when new regions are added. Signed-off-by: Eric Farman Reviewed-by: Cornelia Huck Message-Id: <20200505125757.98209-3-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/vfio/ccw.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index 63406184d2..ca06213d03 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -363,8 +363,7 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) vcdev->io_region_size = info->size; if (sizeof(*vcdev->io_region) != vcdev->io_region_size) { error_setg(errp, "vfio: Unexpected size of the I/O region"); - g_free(info); - return; + goto out_err; } vcdev->io_region_offset = info->offset; @@ -377,15 +376,20 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) vcdev->async_cmd_region_size = info->size; if (sizeof(*vcdev->async_cmd_region) != vcdev->async_cmd_region_size) { error_setg(errp, "vfio: Unexpected size of the async cmd region"); - g_free(vcdev->io_region); - g_free(info); - return; + goto out_err; } vcdev->async_cmd_region_offset = info->offset; vcdev->async_cmd_region = g_malloc0(info->size); } g_free(info); + return; + +out_err: + g_free(vcdev->async_cmd_region); + g_free(vcdev->io_region); + g_free(info); + return; } static void vfio_ccw_put_region(VFIOCCWDevice *vcdev) From 46ea3841edaff2a7657b8f6c7f474e5e3850cd62 Mon Sep 17 00:00:00 2001 From: Farhan Ali Date: Tue, 5 May 2020 14:57:54 +0200 Subject: [PATCH 1402/2595] vfio-ccw: Add support for the schib region The schib region can be used to obtain the latest SCHIB from the host passthrough subchannel. Since the guest SCHIB is virtualized, we currently only update the path related information so that the guest is aware of any path related changes when it issues the 'stsch' instruction. Signed-off-by: Farhan Ali Signed-off-by: Eric Farman Reviewed-by: Cornelia Huck Message-Id: <20200505125757.98209-4-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 13 ++++++-- hw/s390x/s390-ccw.c | 21 +++++++++++++ hw/vfio/ccw.c | 63 +++++++++++++++++++++++++++++++++++++ include/hw/s390x/css.h | 3 +- include/hw/s390x/s390-ccw.h | 1 + target/s390x/ioinst.c | 3 +- 6 files changed, 99 insertions(+), 5 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 5d8e08667e..a44faa3549 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1335,11 +1335,20 @@ static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src) } } -int css_do_stsch(SubchDev *sch, SCHIB *schib) +IOInstEnding css_do_stsch(SubchDev *sch, SCHIB *schib) { + int ret; + + /* + * For some subchannels, we may want to update parts of + * the schib (e.g., update path masks from the host device + * for passthrough subchannels). + */ + ret = s390_ccw_store(sch); + /* Use current status. */ copy_schib_to_guest(schib, &sch->curr_status); - return 0; + return ret; } static void copy_pmcw_from_guest(PMCW *dest, const PMCW *src) diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index c48510f9e5..b497571863 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -51,6 +51,27 @@ int s390_ccw_clear(SubchDev *sch) return cdc->handle_clear(sch); } +IOInstEnding s390_ccw_store(SubchDev *sch) +{ + S390CCWDeviceClass *cdc = NULL; + int ret = IOINST_CC_EXPECTED; + + /* + * This code is called for both virtual and passthrough devices, + * but only applies to to the latter. This ugly check makes that + * distinction for us. + */ + if (object_dynamic_cast(OBJECT(sch->driver_data), TYPE_S390_CCW)) { + cdc = S390_CCW_DEVICE_GET_CLASS(sch->driver_data); + } + + if (cdc && cdc->handle_store) { + ret = cdc->handle_store(sch); + } + + return ret; +} + static void s390_ccw_get_dev_info(S390CCWDevice *cdev, char *sysfsdev, Error **errp) diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index ca06213d03..f5a5e038aa 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -41,6 +41,9 @@ struct VFIOCCWDevice { uint64_t async_cmd_region_size; uint64_t async_cmd_region_offset; struct ccw_cmd_region *async_cmd_region; + uint64_t schib_region_size; + uint64_t schib_region_offset; + struct ccw_schib_region *schib_region; EventNotifier io_notifier; bool force_orb_pfch; bool warned_orb_pfch; @@ -116,6 +119,51 @@ again: } } +static IOInstEnding vfio_ccw_handle_store(SubchDev *sch) +{ + S390CCWDevice *cdev = sch->driver_data; + VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); + SCHIB *schib = &sch->curr_status; + struct ccw_schib_region *region = vcdev->schib_region; + SCHIB *s; + int ret; + + /* schib region not available so nothing else to do */ + if (!region) { + return IOINST_CC_EXPECTED; + } + + memset(region, 0, sizeof(*region)); + ret = pread(vcdev->vdev.fd, region, vcdev->schib_region_size, + vcdev->schib_region_offset); + + if (ret == -1) { + /* + * Device is probably damaged, but store subchannel does not + * have a nonzero cc defined for this scenario. Log an error, + * and presume things are otherwise fine. + */ + error_report("vfio-ccw: store region read failed with errno=%d", errno); + return IOINST_CC_EXPECTED; + } + + /* + * Selectively copy path-related bits of the SCHIB, + * rather than copying the entire struct. + */ + s = (SCHIB *)region->schib_area; + schib->pmcw.pnom = s->pmcw.pnom; + schib->pmcw.lpum = s->pmcw.lpum; + schib->pmcw.pam = s->pmcw.pam; + schib->pmcw.pom = s->pmcw.pom; + + if (s->scsw.flags & SCSW_FLAGS_MASK_PNO) { + schib->scsw.flags |= SCSW_FLAGS_MASK_PNO; + } + + return IOINST_CC_EXPECTED; +} + static int vfio_ccw_handle_clear(SubchDev *sch) { S390CCWDevice *cdev = sch->driver_data; @@ -382,10 +430,23 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) vcdev->async_cmd_region = g_malloc0(info->size); } + ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW, + VFIO_REGION_SUBTYPE_CCW_SCHIB, &info); + if (!ret) { + vcdev->schib_region_size = info->size; + if (sizeof(*vcdev->schib_region) != vcdev->schib_region_size) { + error_setg(errp, "vfio: Unexpected size of the schib region"); + goto out_err; + } + vcdev->schib_region_offset = info->offset; + vcdev->schib_region = g_malloc(info->size); + } + g_free(info); return; out_err: + g_free(vcdev->schib_region); g_free(vcdev->async_cmd_region); g_free(vcdev->io_region); g_free(info); @@ -394,6 +455,7 @@ out_err: static void vfio_ccw_put_region(VFIOCCWDevice *vcdev) { + g_free(vcdev->schib_region); g_free(vcdev->async_cmd_region); g_free(vcdev->io_region); } @@ -569,6 +631,7 @@ static void vfio_ccw_class_init(ObjectClass *klass, void *data) cdc->handle_request = vfio_ccw_handle_request; cdc->handle_halt = vfio_ccw_handle_halt; cdc->handle_clear = vfio_ccw_handle_clear; + cdc->handle_store = vfio_ccw_handle_store; } static const TypeInfo vfio_ccw_info = { diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index f46bcafb16..7e3a5e7433 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -218,6 +218,7 @@ IOInstEnding do_subchannel_work_passthrough(SubchDev *sub); int s390_ccw_halt(SubchDev *sch); int s390_ccw_clear(SubchDev *sch); +IOInstEnding s390_ccw_store(SubchDev *sch); typedef enum { CSS_IO_ADAPTER_VIRTIO = 0, @@ -242,7 +243,7 @@ SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid); bool css_subch_visible(SubchDev *sch); void css_conditional_io_interrupt(SubchDev *sch); -int css_do_stsch(SubchDev *sch, SCHIB *schib); +IOInstEnding css_do_stsch(SubchDev *sch, SCHIB *schib); bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid); IOInstEnding css_do_msch(SubchDev *sch, const SCHIB *schib); IOInstEnding css_do_xsch(SubchDev *sch); diff --git a/include/hw/s390x/s390-ccw.h b/include/hw/s390x/s390-ccw.h index 7f27bc2f53..d8e08b5f4c 100644 --- a/include/hw/s390x/s390-ccw.h +++ b/include/hw/s390x/s390-ccw.h @@ -37,6 +37,7 @@ typedef struct S390CCWDeviceClass { IOInstEnding (*handle_request) (SubchDev *sch); int (*handle_halt) (SubchDev *sch); int (*handle_clear) (SubchDev *sch); + IOInstEnding (*handle_store) (SubchDev *sch); } S390CCWDeviceClass; #endif diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index 7a14c52c12..a412926d27 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -292,8 +292,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, sch = css_find_subch(m, cssid, ssid, schid); if (sch) { if (css_subch_visible(sch)) { - css_do_stsch(sch, &schib); - cc = 0; + cc = css_do_stsch(sch, &schib); } else { /* Indicate no more subchannels in this css/ss */ cc = 3; From 690e29b91102ac69810b35fe72cd90bc9fa1fff7 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Tue, 5 May 2020 14:57:55 +0200 Subject: [PATCH 1403/2595] vfio-ccw: Refactor ccw irq handler Make it easier to add new ones in the future. Signed-off-by: Eric Farman Reviewed-by: Cornelia Huck Message-Id: <20200505125757.98209-5-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/vfio/ccw.c | 58 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index f5a5e038aa..47e43ea606 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -324,22 +324,36 @@ read_err: css_inject_io_interrupt(sch); } -static void vfio_ccw_register_io_notifier(VFIOCCWDevice *vcdev, Error **errp) +static void vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev, + unsigned int irq, + Error **errp) { VFIODevice *vdev = &vcdev->vdev; struct vfio_irq_info *irq_info; size_t argsz; int fd; + EventNotifier *notifier; + IOHandler *fd_read; - if (vdev->num_irqs < VFIO_CCW_IO_IRQ_INDEX + 1) { - error_setg(errp, "vfio: unexpected number of io irqs %u", + switch (irq) { + case VFIO_CCW_IO_IRQ_INDEX: + notifier = &vcdev->io_notifier; + fd_read = vfio_ccw_io_notifier_handler; + break; + default: + error_setg(errp, "vfio: Unsupported device irq(%d)", irq); + return; + } + + if (vdev->num_irqs < irq + 1) { + error_setg(errp, "vfio: unexpected number of irqs %u", vdev->num_irqs); return; } argsz = sizeof(*irq_info); irq_info = g_malloc0(argsz); - irq_info->index = VFIO_CCW_IO_IRQ_INDEX; + irq_info->index = irq; irq_info->argsz = argsz; if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info) < 0 || irq_info->count < 1) { @@ -347,37 +361,49 @@ static void vfio_ccw_register_io_notifier(VFIOCCWDevice *vcdev, Error **errp) goto out_free_info; } - if (event_notifier_init(&vcdev->io_notifier, 0)) { + if (event_notifier_init(notifier, 0)) { error_setg_errno(errp, errno, - "vfio: Unable to init event notifier for IO"); + "vfio: Unable to init event notifier for irq (%d)", + irq); goto out_free_info; } - fd = event_notifier_get_fd(&vcdev->io_notifier); - qemu_set_fd_handler(fd, vfio_ccw_io_notifier_handler, NULL, vcdev); + fd = event_notifier_get_fd(notifier); + qemu_set_fd_handler(fd, fd_read, NULL, vcdev); - if (vfio_set_irq_signaling(vdev, VFIO_CCW_IO_IRQ_INDEX, 0, + if (vfio_set_irq_signaling(vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, fd, errp)) { qemu_set_fd_handler(fd, NULL, NULL, vcdev); - event_notifier_cleanup(&vcdev->io_notifier); + event_notifier_cleanup(notifier); } out_free_info: g_free(irq_info); } -static void vfio_ccw_unregister_io_notifier(VFIOCCWDevice *vcdev) +static void vfio_ccw_unregister_irq_notifier(VFIOCCWDevice *vcdev, + unsigned int irq) { Error *err = NULL; + EventNotifier *notifier; - if (vfio_set_irq_signaling(&vcdev->vdev, VFIO_CCW_IO_IRQ_INDEX, 0, + switch (irq) { + case VFIO_CCW_IO_IRQ_INDEX: + notifier = &vcdev->io_notifier; + break; + default: + error_report("vfio: Unsupported device irq(%d)", irq); + return; + } + + if (vfio_set_irq_signaling(&vcdev->vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { error_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name); } - qemu_set_fd_handler(event_notifier_get_fd(&vcdev->io_notifier), + qemu_set_fd_handler(event_notifier_get_fd(notifier), NULL, NULL, vcdev); - event_notifier_cleanup(&vcdev->io_notifier); + event_notifier_cleanup(notifier); } static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) @@ -565,7 +591,7 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp) goto out_region_err; } - vfio_ccw_register_io_notifier(vcdev, &err); + vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX, &err); if (err) { goto out_notifier_err; } @@ -594,7 +620,7 @@ static void vfio_ccw_unrealize(DeviceState *dev) S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev); VFIOGroup *group = vcdev->vdev.group; - vfio_ccw_unregister_io_notifier(vcdev); + vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX); vfio_ccw_put_region(vcdev); vfio_ccw_put_device(vcdev); vfio_put_group(group); From f6dde1b012e678aa64339520ef7519ec04026cf1 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Tue, 5 May 2020 14:57:56 +0200 Subject: [PATCH 1404/2595] s390x/css: Refactor the css_queue_crw() routine We have a use case (vfio-ccw) where a CRW is already built and ready to use. Rather than teasing out the components just to reassemble it later, let's rework this code so we can queue a fully-qualified CRW directly. Signed-off-by: Eric Farman Reviewed-by: Cornelia Huck Message-Id: <20200505125757.98209-6-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 44 ++++++++++++++++++++++++++++-------------- include/hw/s390x/css.h | 1 + 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index a44faa3549..d1e365e3e6 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -2170,30 +2170,23 @@ void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, } } -void css_queue_crw(uint8_t rsc, uint8_t erc, int solicited, - int chain, uint16_t rsid) +void css_crw_add_to_queue(CRW crw) { CrwContainer *crw_cont; - trace_css_crw(rsc, erc, rsid, chain ? "(chained)" : ""); + trace_css_crw((crw.flags & CRW_FLAGS_MASK_RSC) >> 8, + crw.flags & CRW_FLAGS_MASK_ERC, + crw.rsid, + (crw.flags & CRW_FLAGS_MASK_C) ? "(chained)" : ""); + /* TODO: Maybe use a static crw pool? */ crw_cont = g_try_new0(CrwContainer, 1); if (!crw_cont) { channel_subsys.crws_lost = true; return; } - crw_cont->crw.flags = (rsc << 8) | erc; - if (solicited) { - crw_cont->crw.flags |= CRW_FLAGS_MASK_S; - } - if (chain) { - crw_cont->crw.flags |= CRW_FLAGS_MASK_C; - } - crw_cont->crw.rsid = rsid; - if (channel_subsys.crws_lost) { - crw_cont->crw.flags |= CRW_FLAGS_MASK_R; - channel_subsys.crws_lost = false; - } + + crw_cont->crw = crw; QTAILQ_INSERT_TAIL(&channel_subsys.pending_crws, crw_cont, sibling); @@ -2204,6 +2197,27 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int solicited, } } +void css_queue_crw(uint8_t rsc, uint8_t erc, int solicited, + int chain, uint16_t rsid) +{ + CRW crw; + + crw.flags = (rsc << 8) | erc; + if (solicited) { + crw.flags |= CRW_FLAGS_MASK_S; + } + if (chain) { + crw.flags |= CRW_FLAGS_MASK_C; + } + crw.rsid = rsid; + if (channel_subsys.crws_lost) { + crw.flags |= CRW_FLAGS_MASK_R; + channel_subsys.crws_lost = false; + } + + css_crw_add_to_queue(crw); +} + void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, int hotplugged, int add) { diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index 7e3a5e7433..08c869ab0a 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -205,6 +205,7 @@ void copy_scsw_to_guest(SCSW *dest, const SCSW *src); void css_inject_io_interrupt(SubchDev *sch); void css_reset(void); void css_reset_sch(SubchDev *sch); +void css_crw_add_to_queue(CRW crw); void css_queue_crw(uint8_t rsc, uint8_t erc, int solicited, int chain, uint16_t rsid); void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, From f030532f2ad6eeb200034915e9c6357cce81b538 Mon Sep 17 00:00:00 2001 From: Farhan Ali Date: Tue, 5 May 2020 14:57:57 +0200 Subject: [PATCH 1405/2595] vfio-ccw: Add support for the CRW region and IRQ The crw region can be used to obtain information about Channel Report Words (CRW) from vfio-ccw driver. Currently only channel-path related CRWs are passed to QEMU from vfio-ccw driver. Signed-off-by: Farhan Ali Signed-off-by: Eric Farman Reviewed-by: Cornelia Huck Message-Id: <20200505125757.98209-7-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/vfio/ccw.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index 47e43ea606..06e69d7066 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -44,7 +44,11 @@ struct VFIOCCWDevice { uint64_t schib_region_size; uint64_t schib_region_offset; struct ccw_schib_region *schib_region; + uint64_t crw_region_size; + uint64_t crw_region_offset; + struct ccw_crw_region *crw_region; EventNotifier io_notifier; + EventNotifier crw_notifier; bool force_orb_pfch; bool warned_orb_pfch; }; @@ -254,6 +258,44 @@ static void vfio_ccw_reset(DeviceState *dev) ioctl(vcdev->vdev.fd, VFIO_DEVICE_RESET); } +static void vfio_ccw_crw_read(VFIOCCWDevice *vcdev) +{ + struct ccw_crw_region *region = vcdev->crw_region; + CRW crw; + int size; + + /* Keep reading CRWs as long as data is returned */ + do { + memset(region, 0, sizeof(*region)); + size = pread(vcdev->vdev.fd, region, vcdev->crw_region_size, + vcdev->crw_region_offset); + + if (size == -1) { + error_report("vfio-ccw: Read crw region failed with errno=%d", + errno); + break; + } + + if (region->crw == 0) { + /* No more CRWs to queue */ + break; + } + + memcpy(&crw, ®ion->crw, sizeof(CRW)); + + css_crw_add_to_queue(crw); + } while (1); +} + +static void vfio_ccw_crw_notifier_handler(void *opaque) +{ + VFIOCCWDevice *vcdev = opaque; + + while (event_notifier_test_and_clear(&vcdev->crw_notifier)) { + vfio_ccw_crw_read(vcdev); + } +} + static void vfio_ccw_io_notifier_handler(void *opaque) { VFIOCCWDevice *vcdev = opaque; @@ -340,6 +382,10 @@ static void vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev, notifier = &vcdev->io_notifier; fd_read = vfio_ccw_io_notifier_handler; break; + case VFIO_CCW_CRW_IRQ_INDEX: + notifier = &vcdev->crw_notifier; + fd_read = vfio_ccw_crw_notifier_handler; + break; default: error_setg(errp, "vfio: Unsupported device irq(%d)", irq); return; @@ -391,6 +437,9 @@ static void vfio_ccw_unregister_irq_notifier(VFIOCCWDevice *vcdev, case VFIO_CCW_IO_IRQ_INDEX: notifier = &vcdev->io_notifier; break; + case VFIO_CCW_CRW_IRQ_INDEX: + notifier = &vcdev->crw_notifier; + break; default: error_report("vfio: Unsupported device irq(%d)", irq); return; @@ -468,10 +517,24 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) vcdev->schib_region = g_malloc(info->size); } + ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW, + VFIO_REGION_SUBTYPE_CCW_CRW, &info); + + if (!ret) { + vcdev->crw_region_size = info->size; + if (sizeof(*vcdev->crw_region) != vcdev->crw_region_size) { + error_setg(errp, "vfio: Unexpected size of the CRW region"); + goto out_err; + } + vcdev->crw_region_offset = info->offset; + vcdev->crw_region = g_malloc(info->size); + } + g_free(info); return; out_err: + g_free(vcdev->crw_region); g_free(vcdev->schib_region); g_free(vcdev->async_cmd_region); g_free(vcdev->io_region); @@ -481,6 +544,7 @@ out_err: static void vfio_ccw_put_region(VFIOCCWDevice *vcdev) { + g_free(vcdev->crw_region); g_free(vcdev->schib_region); g_free(vcdev->async_cmd_region); g_free(vcdev->io_region); @@ -596,6 +660,14 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp) goto out_notifier_err; } + if (vcdev->crw_region) { + vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX, &err); + if (err) { + vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX); + goto out_notifier_err; + } + } + return; out_notifier_err: @@ -620,6 +692,7 @@ static void vfio_ccw_unrealize(DeviceState *dev) S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev); VFIOGroup *group = vcdev->vdev.group; + vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX); vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX); vfio_ccw_put_region(vcdev); vfio_ccw_put_device(vcdev); From 458e056257e67254546e58158f3f74ce040c7ca1 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 17 Jun 2020 18:06:04 +0200 Subject: [PATCH 1406/2595] docs/s390x: fix vfio-ap device_del description device_del requires an id and not a sysfsfile. Fixes: bac03ec72f1b ("s390x/vfio-ap: document hot plug/unplug of vfio-ap device") Signed-off-by: Christian Borntraeger Reviewed-by: Thomas Huth Message-Id: <20200617160604.5593-1-borntraeger@de.ibm.com> [CH: add missing '$'] Signed-off-by: Cornelia Huck --- docs/system/s390x/vfio-ap.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/system/s390x/vfio-ap.rst b/docs/system/s390x/vfio-ap.rst index 3cd84179a2..084ba9c4e3 100644 --- a/docs/system/s390x/vfio-ap.rst +++ b/docs/system/s390x/vfio-ap.rst @@ -606,10 +606,11 @@ action. To hot plug a vfio-ap device, use the QEMU ``device_add`` command:: - (qemu) device_add vfio-ap,sysfsdev="$path-to-mdev" + (qemu) device_add vfio-ap,sysfsdev="$path-to-mdev",id="$id" Where the ``$path-to-mdev`` value specifies the absolute path to a mediated device to which AP resources to be used by the guest have been assigned. +``$id`` is the name value for the optional id parameter. Note that on Linux guests, the AP devices will be created in the ``/sys/bus/ap/devices`` directory when the AP bus subsequently performs its periodic @@ -632,10 +633,9 @@ or a prior hot plug action. To hot unplug a vfio-ap device, use the QEMU ``device_del`` command:: - (qemu) device_del vfio-ap,sysfsdev="$path-to-mdev" + (qemu) device_del "$id" -Where ``$path-to-mdev`` is the same as the path specified when the vfio-ap -device was attached to the virtual machine's ap-bus. +Where ``$id`` is the same id that was specified at device creation. On a Linux guest, the AP devices will be removed from the ``/sys/bus/ap/devices`` directory on the guest when the AP bus subsequently performs its periodic scan, From 590790297c0dd2c8e817c7b33daf66862b0ee8ef Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Fri, 8 May 2020 15:59:28 +0300 Subject: [PATCH 1407/2595] virtio-net: implement RSS configuration command Optionally report RSS feature. Handle RSS configuration command and keep RSS parameters in virtio-net device context. Signed-off-by: Yuri Benditovich Signed-off-by: Jason Wang --- hw/net/trace-events | 3 + hw/net/virtio-net.c | 169 +++++++++++++++++++++++++++++++-- include/hw/virtio/virtio-net.h | 13 +++ 3 files changed, 175 insertions(+), 10 deletions(-) diff --git a/hw/net/trace-events b/hw/net/trace-events index 26700dad99..e6875c4c0f 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -381,6 +381,9 @@ virtio_net_announce_notify(void) "" virtio_net_announce_timer(int round) "%d" virtio_net_handle_announce(int round) "%d" virtio_net_post_load_device(void) +virtio_net_rss_disable(void) +virtio_net_rss_error(const char *msg, uint32_t value) "%s, value 0x%08x" +virtio_net_rss_enable(uint32_t p1, uint16_t p2, uint8_t p3) "hashes 0x%x, table of %d, key of %d" # tulip.c tulip_reg_write(uint64_t addr, const char *name, int size, uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64 diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index b7f3d1b2eb..e803b0a26f 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -77,6 +77,16 @@ tso/gso/gro 'off'. */ #define VIRTIO_NET_RSC_DEFAULT_INTERVAL 300000 +#define VIRTIO_NET_RSS_SUPPORTED_HASHES (VIRTIO_NET_RSS_HASH_TYPE_IPv4 | \ + VIRTIO_NET_RSS_HASH_TYPE_TCPv4 | \ + VIRTIO_NET_RSS_HASH_TYPE_UDPv4 | \ + VIRTIO_NET_RSS_HASH_TYPE_IPv6 | \ + VIRTIO_NET_RSS_HASH_TYPE_TCPv6 | \ + VIRTIO_NET_RSS_HASH_TYPE_UDPv6 | \ + VIRTIO_NET_RSS_HASH_TYPE_IP_EX | \ + VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \ + VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) + /* temporary until standard header include it */ #if !defined(VIRTIO_NET_HDR_F_RSC_INFO) @@ -108,6 +118,8 @@ static VirtIOFeature feature_sizes[] = { .end = endof(struct virtio_net_config, mtu)}, {.flags = 1ULL << VIRTIO_NET_F_SPEED_DUPLEX, .end = endof(struct virtio_net_config, duplex)}, + {.flags = 1ULL << VIRTIO_NET_F_RSS, + .end = endof(struct virtio_net_config, supported_hash_types)}, {} }; @@ -138,6 +150,11 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) memcpy(netcfg.mac, n->mac, ETH_ALEN); virtio_stl_p(vdev, &netcfg.speed, n->net_conf.speed); netcfg.duplex = n->net_conf.duplex; + netcfg.rss_max_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE; + virtio_stw_p(vdev, &netcfg.rss_max_indirection_table_length, + VIRTIO_NET_RSS_MAX_TABLE_LEN); + virtio_stl_p(vdev, &netcfg.supported_hash_types, + VIRTIO_NET_RSS_SUPPORTED_HASHES); memcpy(config, &netcfg, n->config_size); } @@ -701,6 +718,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, return features; } + virtio_clear_feature(&features, VIRTIO_NET_F_RSS); features = vhost_net_get_features(get_vhost_net(nc->peer), features); vdev->backend_features = features; @@ -860,6 +878,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) } virtio_net_set_multiqueue(n, + virtio_has_feature(features, VIRTIO_NET_F_RSS) || virtio_has_feature(features, VIRTIO_NET_F_MQ)); virtio_net_set_mrg_rx_bufs(n, @@ -1136,25 +1155,152 @@ static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd, } } +static void virtio_net_disable_rss(VirtIONet *n) +{ + if (n->rss_data.enabled) { + trace_virtio_net_rss_disable(); + } + n->rss_data.enabled = false; +} + +static uint16_t virtio_net_handle_rss(VirtIONet *n, + struct iovec *iov, unsigned int iov_cnt) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(n); + struct virtio_net_rss_config cfg; + size_t s, offset = 0, size_get; + uint16_t queues, i; + struct { + uint16_t us; + uint8_t b; + } QEMU_PACKED temp; + const char *err_msg = ""; + uint32_t err_value = 0; + + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) { + err_msg = "RSS is not negotiated"; + goto error; + } + size_get = offsetof(struct virtio_net_rss_config, indirection_table); + s = iov_to_buf(iov, iov_cnt, offset, &cfg, size_get); + if (s != size_get) { + err_msg = "Short command buffer"; + err_value = (uint32_t)s; + goto error; + } + n->rss_data.hash_types = virtio_ldl_p(vdev, &cfg.hash_types); + n->rss_data.indirections_len = + virtio_lduw_p(vdev, &cfg.indirection_table_mask); + n->rss_data.indirections_len++; + if (!is_power_of_2(n->rss_data.indirections_len)) { + err_msg = "Invalid size of indirection table"; + err_value = n->rss_data.indirections_len; + goto error; + } + if (n->rss_data.indirections_len > VIRTIO_NET_RSS_MAX_TABLE_LEN) { + err_msg = "Too large indirection table"; + err_value = n->rss_data.indirections_len; + goto error; + } + n->rss_data.default_queue = + virtio_lduw_p(vdev, &cfg.unclassified_queue); + if (n->rss_data.default_queue >= n->max_queues) { + err_msg = "Invalid default queue"; + err_value = n->rss_data.default_queue; + goto error; + } + offset += size_get; + size_get = sizeof(uint16_t) * n->rss_data.indirections_len; + g_free(n->rss_data.indirections_table); + n->rss_data.indirections_table = g_malloc(size_get); + if (!n->rss_data.indirections_table) { + err_msg = "Can't allocate indirections table"; + err_value = n->rss_data.indirections_len; + goto error; + } + s = iov_to_buf(iov, iov_cnt, offset, + n->rss_data.indirections_table, size_get); + if (s != size_get) { + err_msg = "Short indirection table buffer"; + err_value = (uint32_t)s; + goto error; + } + for (i = 0; i < n->rss_data.indirections_len; ++i) { + uint16_t val = n->rss_data.indirections_table[i]; + n->rss_data.indirections_table[i] = virtio_lduw_p(vdev, &val); + } + offset += size_get; + size_get = sizeof(temp); + s = iov_to_buf(iov, iov_cnt, offset, &temp, size_get); + if (s != size_get) { + err_msg = "Can't get queues"; + err_value = (uint32_t)s; + goto error; + } + queues = virtio_lduw_p(vdev, &temp.us); + if (queues == 0 || queues > n->max_queues) { + err_msg = "Invalid number of queues"; + err_value = queues; + goto error; + } + if (temp.b > VIRTIO_NET_RSS_MAX_KEY_SIZE) { + err_msg = "Invalid key size"; + err_value = temp.b; + goto error; + } + if (!temp.b && n->rss_data.hash_types) { + err_msg = "No key provided"; + err_value = 0; + goto error; + } + if (!temp.b && !n->rss_data.hash_types) { + virtio_net_disable_rss(n); + return queues; + } + offset += size_get; + size_get = temp.b; + s = iov_to_buf(iov, iov_cnt, offset, n->rss_data.key, size_get); + if (s != size_get) { + err_msg = "Can get key buffer"; + err_value = (uint32_t)s; + goto error; + } + n->rss_data.enabled = true; + trace_virtio_net_rss_enable(n->rss_data.hash_types, + n->rss_data.indirections_len, + temp.b); + return queues; +error: + trace_virtio_net_rss_error(err_msg, err_value); + virtio_net_disable_rss(n); + return 0; +} + static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, struct iovec *iov, unsigned int iov_cnt) { VirtIODevice *vdev = VIRTIO_DEVICE(n); - struct virtio_net_ctrl_mq mq; - size_t s; uint16_t queues; - s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq)); - if (s != sizeof(mq)) { + virtio_net_disable_rss(n); + if (cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) { + queues = virtio_net_handle_rss(n, iov, iov_cnt); + } else if (cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { + struct virtio_net_ctrl_mq mq; + size_t s; + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ)) { + return VIRTIO_NET_ERR; + } + s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq)); + if (s != sizeof(mq)) { + return VIRTIO_NET_ERR; + } + queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs); + + } else { return VIRTIO_NET_ERR; } - if (cmd != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { - return VIRTIO_NET_ERR; - } - - queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs); - if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX || queues > n->max_queues || @@ -3111,6 +3257,7 @@ static void virtio_net_device_unrealize(DeviceState *dev) g_free(n->vqs); qemu_del_nic(n->nic); virtio_net_rsc_cleanup(n); + g_free(n->rss_data.indirections_table); virtio_cleanup(vdev); } @@ -3212,6 +3359,8 @@ static Property virtio_net_properties[] = { DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true), DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false), + DEFINE_PROP_BIT64("rss", VirtIONet, host_features, + VIRTIO_NET_F_RSS, false), DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features, VIRTIO_NET_F_RSC_EXT, false), DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout, diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 96c68d4a92..d3fad7c8f3 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -126,6 +126,18 @@ typedef struct VirtioNetRscChain { /* Maximum packet size we can receive from tap device: header + 64k */ #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 * KiB)) +#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40 +#define VIRTIO_NET_RSS_MAX_TABLE_LEN 128 + +typedef struct VirtioNetRssData { + bool enabled; + uint32_t hash_types; + uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE]; + uint16_t indirections_len; + uint16_t *indirections_table; + uint16_t default_queue; +} VirtioNetRssData; + typedef struct VirtIONetQueue { VirtQueue *rx_vq; VirtQueue *tx_vq; @@ -199,6 +211,7 @@ struct VirtIONet { bool failover; DeviceListener primary_listener; Notifier migration_state; + VirtioNetRssData rss_data; }; void virtio_net_set_netclient_name(VirtIONet *n, const char *name, From 4474e37a5b3a616803f4570b542e8eede91e50d2 Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Fri, 8 May 2020 15:59:29 +0300 Subject: [PATCH 1408/2595] virtio-net: implement RX RSS processing If VIRTIO_NET_F_RSS negotiated and RSS is enabled, process incoming packets, calculate packet's hash and place the packet into respective RX virtqueue. Signed-off-by: Yuri Benditovich Signed-off-by: Jason Wang --- hw/net/Makefile.objs | 1 + hw/net/virtio-net.c | 88 +++++++++++++++++++++++++++++++++- include/hw/virtio/virtio-net.h | 1 + 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs index f2b73983ee..7ccbf72ea7 100644 --- a/hw/net/Makefile.objs +++ b/hw/net/Makefile.objs @@ -41,6 +41,7 @@ obj-$(CONFIG_MILKYMIST) += milkymist-minimac2.o obj-$(CONFIG_PSERIES) += spapr_llan.o obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o +common-obj-$(CONFIG_VIRTIO_NET) += net_rx_pkt.o obj-$(CONFIG_VIRTIO_NET) += virtio-net.o common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET)) += vhost_net.o common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET))) += vhost_net-stub.o diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index e803b0a26f..556f221669 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -42,6 +42,7 @@ #include "trace.h" #include "monitor/qdev.h" #include "hw/pci/pci.h" +#include "net_rx_pkt.h" #define VIRTIO_NET_VM_VERSION 11 @@ -1533,8 +1534,80 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) return 0; } +static uint8_t virtio_net_get_hash_type(bool isip4, + bool isip6, + bool isudp, + bool istcp, + uint32_t types) +{ + if (isip4) { + if (istcp && (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4)) { + return NetPktRssIpV4Tcp; + } + if (isudp && (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4)) { + return NetPktRssIpV4Udp; + } + if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) { + return NetPktRssIpV4; + } + } else if (isip6) { + uint32_t mask = VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | + VIRTIO_NET_RSS_HASH_TYPE_TCPv6; + + if (istcp && (types & mask)) { + return (types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) ? + NetPktRssIpV6TcpEx : NetPktRssIpV6Tcp; + } + mask = VIRTIO_NET_RSS_HASH_TYPE_UDP_EX | VIRTIO_NET_RSS_HASH_TYPE_UDPv6; + if (isudp && (types & mask)) { + return (types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) ? + NetPktRssIpV6UdpEx : NetPktRssIpV6Udp; + } + mask = VIRTIO_NET_RSS_HASH_TYPE_IP_EX | VIRTIO_NET_RSS_HASH_TYPE_IPv6; + if (types & mask) { + return (types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) ? + NetPktRssIpV6Ex : NetPktRssIpV6; + } + } + return 0xff; +} + +static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf, + size_t size) +{ + VirtIONet *n = qemu_get_nic_opaque(nc); + unsigned int index = nc->queue_index, new_index; + struct NetRxPkt *pkt = n->rx_pkt; + uint8_t net_hash_type; + uint32_t hash; + bool isip4, isip6, isudp, istcp; + + net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len, + size - n->host_hdr_len); + net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); + if (isip4 && (net_rx_pkt_get_ip4_info(pkt)->fragment)) { + istcp = isudp = false; + } + if (isip6 && (net_rx_pkt_get_ip6_info(pkt)->fragment)) { + istcp = isudp = false; + } + net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp, + n->rss_data.hash_types); + if (net_hash_type > NetPktRssIpV6UdpEx) { + return n->rss_data.default_queue; + } + + hash = net_rx_pkt_calc_rss_hash(pkt, net_hash_type, n->rss_data.key); + new_index = hash & (n->rss_data.indirections_len - 1); + new_index = n->rss_data.indirections_table[new_index]; + if (index == new_index) { + return -1; + } + return new_index; +} + static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, - size_t size) + size_t size, bool no_rss) { VirtIONet *n = qemu_get_nic_opaque(nc); VirtIONetQueue *q = virtio_net_get_subqueue(nc); @@ -1548,6 +1621,14 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, return -1; } + if (!no_rss && n->rss_data.enabled) { + int index = virtio_net_process_rss(nc, buf, size); + if (index >= 0) { + NetClientState *nc2 = qemu_get_subqueue(n->nic, index); + return virtio_net_receive_rcu(nc2, buf, size, true); + } + } + /* hdr_len refers to the header we supply to the guest */ if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) { return 0; @@ -1642,7 +1723,7 @@ static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, { RCU_READ_LOCK_GUARD(); - return virtio_net_receive_rcu(nc, buf, size); + return virtio_net_receive_rcu(nc, buf, size, false); } static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, @@ -3221,6 +3302,8 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) QTAILQ_INIT(&n->rsc_chains); n->qdev = dev; + + net_rx_pkt_init(&n->rx_pkt, false); } static void virtio_net_device_unrealize(DeviceState *dev) @@ -3258,6 +3341,7 @@ static void virtio_net_device_unrealize(DeviceState *dev) qemu_del_nic(n->nic); virtio_net_rsc_cleanup(n); g_free(n->rss_data.indirections_table); + net_rx_pkt_uninit(n->rx_pkt); virtio_cleanup(vdev); } diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index d3fad7c8f3..5081f3c52a 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -212,6 +212,7 @@ struct VirtIONet { DeviceListener primary_listener; Notifier migration_state; VirtioNetRssData rss_data; + struct NetRxPkt *rx_pkt; }; void virtio_net_set_netclient_name(VirtIONet *n, const char *name, From fbbdbddec018723d9f863f01cdec172dda9df12b Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Fri, 8 May 2020 15:59:30 +0300 Subject: [PATCH 1409/2595] tap: allow extended virtio header with hash info Signed-off-by: Yuri Benditovich Signed-off-by: Jason Wang --- net/tap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/tap.c b/net/tap.c index 6207f61f84..ca48f2a285 100644 --- a/net/tap.c +++ b/net/tap.c @@ -254,7 +254,8 @@ static void tap_set_vnet_hdr_len(NetClientState *nc, int len) assert(nc->info->type == NET_CLIENT_DRIVER_TAP); assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) || - len == sizeof(struct virtio_net_hdr)); + len == sizeof(struct virtio_net_hdr) || + len == sizeof(struct virtio_net_hdr_v1_hash)); tap_fd_set_vnet_hdr_len(s->fd, len); s->host_vnet_hdr_len = len; From e22f0603fb2fc274920a9e3a1d1306260b9a4cc4 Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Fri, 8 May 2020 15:59:31 +0300 Subject: [PATCH 1410/2595] virtio-net: reference implementation of hash report Suggest VIRTIO_NET_F_HASH_REPORT if specified in device parameters. If the VIRTIO_NET_F_HASH_REPORT is set, the device extends configuration space. If the feature is negotiated, the packet layout is extended to accomodate the hash information. In this case deliver packet's hash value and report type in virtio header extension. Use for configuration the same procedure as already used for RSS. We add two fields in rss_data that controls what the device does with the calculated hash if rss_data.enabled is set. If field 'populate' is set the hash is set in the packet, if field 'redirect' is set the hash is used to decide the queue to place the packet to. Signed-off-by: Yuri Benditovich Signed-off-by: Jason Wang --- hw/net/virtio-net.c | 99 +++++++++++++++++++++++++++------- include/hw/virtio/virtio-net.h | 2 + 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 556f221669..6ff3cc35c5 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -119,7 +119,7 @@ static VirtIOFeature feature_sizes[] = { .end = endof(struct virtio_net_config, mtu)}, {.flags = 1ULL << VIRTIO_NET_F_SPEED_DUPLEX, .end = endof(struct virtio_net_config, duplex)}, - {.flags = 1ULL << VIRTIO_NET_F_RSS, + {.flags = (1ULL << VIRTIO_NET_F_RSS) | (1ULL << VIRTIO_NET_F_HASH_REPORT), .end = endof(struct virtio_net_config, supported_hash_types)}, {} }; @@ -153,7 +153,8 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) netcfg.duplex = n->net_conf.duplex; netcfg.rss_max_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE; virtio_stw_p(vdev, &netcfg.rss_max_indirection_table_length, - VIRTIO_NET_RSS_MAX_TABLE_LEN); + virtio_host_has_feature(vdev, VIRTIO_NET_F_RSS) ? + VIRTIO_NET_RSS_MAX_TABLE_LEN : 1); virtio_stl_p(vdev, &netcfg.supported_hash_types, VIRTIO_NET_RSS_SUPPORTED_HASHES); memcpy(config, &netcfg, n->config_size); @@ -579,7 +580,7 @@ static int peer_has_ufo(VirtIONet *n) } static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs, - int version_1) + int version_1, int hash_report) { int i; NetClientState *nc; @@ -587,7 +588,10 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs, n->mergeable_rx_bufs = mergeable_rx_bufs; if (version_1) { - n->guest_hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); + n->guest_hdr_len = hash_report ? + sizeof(struct virtio_net_hdr_v1_hash) : + sizeof(struct virtio_net_hdr_mrg_rxbuf); + n->rss_data.populate_hash = !!hash_report; } else { n->guest_hdr_len = n->mergeable_rx_bufs ? sizeof(struct virtio_net_hdr_mrg_rxbuf) : @@ -708,6 +712,8 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO4); virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO6); virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ECN); + + virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT); } if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) { @@ -720,6 +726,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, } virtio_clear_feature(&features, VIRTIO_NET_F_RSS); + virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT); features = vhost_net_get_features(get_vhost_net(nc->peer), features); vdev->backend_features = features; @@ -886,12 +893,15 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) virtio_has_feature(features, VIRTIO_NET_F_MRG_RXBUF), virtio_has_feature(features, - VIRTIO_F_VERSION_1)); + VIRTIO_F_VERSION_1), + virtio_has_feature(features, + VIRTIO_NET_F_HASH_REPORT)); n->rsc4_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) && virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO4); n->rsc6_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) && virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO6); + n->rss_data.redirect = virtio_has_feature(features, VIRTIO_NET_F_RSS); if (n->has_vnet_hdr) { n->curr_guest_offloads = @@ -1165,7 +1175,9 @@ static void virtio_net_disable_rss(VirtIONet *n) } static uint16_t virtio_net_handle_rss(VirtIONet *n, - struct iovec *iov, unsigned int iov_cnt) + struct iovec *iov, + unsigned int iov_cnt, + bool do_rss) { VirtIODevice *vdev = VIRTIO_DEVICE(n); struct virtio_net_rss_config cfg; @@ -1178,10 +1190,14 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n, const char *err_msg = ""; uint32_t err_value = 0; - if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) { + if (do_rss && !virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) { err_msg = "RSS is not negotiated"; goto error; } + if (!do_rss && !virtio_vdev_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) { + err_msg = "Hash report is not negotiated"; + goto error; + } size_get = offsetof(struct virtio_net_rss_config, indirection_table); s = iov_to_buf(iov, iov_cnt, offset, &cfg, size_get); if (s != size_get) { @@ -1193,6 +1209,9 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n, n->rss_data.indirections_len = virtio_lduw_p(vdev, &cfg.indirection_table_mask); n->rss_data.indirections_len++; + if (!do_rss) { + n->rss_data.indirections_len = 1; + } if (!is_power_of_2(n->rss_data.indirections_len)) { err_msg = "Invalid size of indirection table"; err_value = n->rss_data.indirections_len; @@ -1203,8 +1222,8 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n, err_value = n->rss_data.indirections_len; goto error; } - n->rss_data.default_queue = - virtio_lduw_p(vdev, &cfg.unclassified_queue); + n->rss_data.default_queue = do_rss ? + virtio_lduw_p(vdev, &cfg.unclassified_queue) : 0; if (n->rss_data.default_queue >= n->max_queues) { err_msg = "Invalid default queue"; err_value = n->rss_data.default_queue; @@ -1238,7 +1257,7 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n, err_value = (uint32_t)s; goto error; } - queues = virtio_lduw_p(vdev, &temp.us); + queues = do_rss ? virtio_lduw_p(vdev, &temp.us) : n->curr_queues; if (queues == 0 || queues > n->max_queues) { err_msg = "Invalid number of queues"; err_value = queues; @@ -1284,8 +1303,12 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, uint16_t queues; virtio_net_disable_rss(n); + if (cmd == VIRTIO_NET_CTRL_MQ_HASH_CONFIG) { + queues = virtio_net_handle_rss(n, iov, iov_cnt, false); + return queues ? VIRTIO_NET_OK : VIRTIO_NET_ERR; + } if (cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) { - queues = virtio_net_handle_rss(n, iov, iov_cnt); + queues = virtio_net_handle_rss(n, iov, iov_cnt, true); } else if (cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { struct virtio_net_ctrl_mq mq; size_t s; @@ -1572,15 +1595,34 @@ static uint8_t virtio_net_get_hash_type(bool isip4, return 0xff; } +static void virtio_set_packet_hash(const uint8_t *buf, uint8_t report, + uint32_t hash) +{ + struct virtio_net_hdr_v1_hash *hdr = (void *)buf; + hdr->hash_value = hash; + hdr->hash_report = report; +} + static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf, size_t size) { VirtIONet *n = qemu_get_nic_opaque(nc); - unsigned int index = nc->queue_index, new_index; + unsigned int index = nc->queue_index, new_index = index; struct NetRxPkt *pkt = n->rx_pkt; uint8_t net_hash_type; uint32_t hash; bool isip4, isip6, isudp, istcp; + static const uint8_t reports[NetPktRssIpV6UdpEx + 1] = { + VIRTIO_NET_HASH_REPORT_IPv4, + VIRTIO_NET_HASH_REPORT_TCPv4, + VIRTIO_NET_HASH_REPORT_TCPv6, + VIRTIO_NET_HASH_REPORT_IPv6, + VIRTIO_NET_HASH_REPORT_IPv6_EX, + VIRTIO_NET_HASH_REPORT_TCPv6_EX, + VIRTIO_NET_HASH_REPORT_UDPv4, + VIRTIO_NET_HASH_REPORT_UDPv6, + VIRTIO_NET_HASH_REPORT_UDPv6_EX + }; net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len, size - n->host_hdr_len); @@ -1594,16 +1636,24 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf, net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp, n->rss_data.hash_types); if (net_hash_type > NetPktRssIpV6UdpEx) { - return n->rss_data.default_queue; + if (n->rss_data.populate_hash) { + virtio_set_packet_hash(buf, VIRTIO_NET_HASH_REPORT_NONE, 0); + } + return n->rss_data.redirect ? n->rss_data.default_queue : -1; } hash = net_rx_pkt_calc_rss_hash(pkt, net_hash_type, n->rss_data.key); - new_index = hash & (n->rss_data.indirections_len - 1); - new_index = n->rss_data.indirections_table[new_index]; - if (index == new_index) { - return -1; + + if (n->rss_data.populate_hash) { + virtio_set_packet_hash(buf, reports[net_hash_type], hash); } - return new_index; + + if (n->rss_data.redirect) { + new_index = hash & (n->rss_data.indirections_len - 1); + new_index = n->rss_data.indirections_table[new_index]; + } + + return (index == new_index) ? -1 : new_index; } static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, @@ -1679,6 +1729,11 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, } receive_header(n, sg, elem->in_num, buf, size); + if (n->rss_data.populate_hash) { + offset = sizeof(mhdr); + iov_from_buf(sg, elem->in_num, offset, + buf + offset, n->host_hdr_len - sizeof(mhdr)); + } offset = n->host_hdr_len; total += n->guest_hdr_len; guest_offset = n->guest_hdr_len; @@ -2671,7 +2726,9 @@ static int virtio_net_post_load_device(void *opaque, int version_id) trace_virtio_net_post_load_device(); virtio_net_set_mrg_rx_bufs(n, n->mergeable_rx_bufs, virtio_vdev_has_feature(vdev, - VIRTIO_F_VERSION_1)); + VIRTIO_F_VERSION_1), + virtio_vdev_has_feature(vdev, + VIRTIO_NET_F_HASH_REPORT)); /* MAC_TABLE_ENTRIES may be different from the saved image */ if (n->mac_table.in_use > MAC_TABLE_ENTRIES) { @@ -3290,7 +3347,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) n->vqs[0].tx_waiting = 0; n->tx_burst = n->net_conf.txburst; - virtio_net_set_mrg_rx_bufs(n, 0, 0); + virtio_net_set_mrg_rx_bufs(n, 0, 0, 0); n->promisc = 1; /* for compatibility */ n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN); @@ -3445,6 +3502,8 @@ static Property virtio_net_properties[] = { DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false), DEFINE_PROP_BIT64("rss", VirtIONet, host_features, VIRTIO_NET_F_RSS, false), + DEFINE_PROP_BIT64("hash", VirtIONet, host_features, + VIRTIO_NET_F_HASH_REPORT, false), DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features, VIRTIO_NET_F_RSC_EXT, false), DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout, diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 5081f3c52a..a45ef8278e 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -131,6 +131,8 @@ typedef struct VirtioNetRscChain { typedef struct VirtioNetRssData { bool enabled; + bool redirect; + bool populate_hash; uint32_t hash_types; uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE]; uint16_t indirections_len; From ff4e6d545d924ad9bfe135a90c05b4f9960773d6 Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Fri, 8 May 2020 15:59:32 +0300 Subject: [PATCH 1411/2595] vmstate.h: provide VMSTATE_VARRAY_UINT16_ALLOC macro Similar to VMSTATE_VARRAY_UINT32_ALLOC, but the size is 16-bit field. Signed-off-by: Michael S. Tsirkin Signed-off-by: Yuri Benditovich Signed-off-by: Jason Wang --- include/migration/vmstate.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index eafa39f560..f68ed7db13 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -432,6 +432,16 @@ extern const VMStateInfo vmstate_info_qlist; .offset = vmstate_offset_pointer(_state, _field, _type), \ } +#define VMSTATE_VARRAY_UINT16_ALLOC(_field, _state, _field_num, _version, _info, _type) {\ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\ + .info = &(_info), \ + .size = sizeof(_type), \ + .flags = VMS_VARRAY_UINT16 | VMS_POINTER | VMS_ALLOC, \ + .offset = vmstate_offset_pointer(_state, _field, _type), \ +} + #define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\ .name = (stringify(_field)), \ .version_id = (_version), \ From e41b711485e5b2dcf747ef27cf252a940e09247f Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Fri, 8 May 2020 15:59:33 +0300 Subject: [PATCH 1412/2595] virtio-net: add migration support for RSS and hash report Save and restore RSS/hash report configuration. Signed-off-by: Yuri Benditovich Signed-off-by: Jason Wang --- hw/net/virtio-net.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 6ff3cc35c5..2a5da2985a 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -2777,6 +2777,13 @@ static int virtio_net_post_load_device(void *opaque, int version_id) } } + if (n->rss_data.enabled) { + trace_virtio_net_rss_enable(n->rss_data.hash_types, + n->rss_data.indirections_len, + sizeof(n->rss_data.key)); + } else { + trace_virtio_net_rss_disable(); + } return 0; } @@ -2954,6 +2961,32 @@ static const VMStateDescription vmstate_virtio_net_has_vnet = { }, }; +static bool virtio_net_rss_needed(void *opaque) +{ + return VIRTIO_NET(opaque)->rss_data.enabled; +} + +static const VMStateDescription vmstate_virtio_net_rss = { + .name = "virtio-net-device/rss", + .version_id = 1, + .minimum_version_id = 1, + .needed = virtio_net_rss_needed, + .fields = (VMStateField[]) { + VMSTATE_BOOL(rss_data.enabled, VirtIONet), + VMSTATE_BOOL(rss_data.redirect, VirtIONet), + VMSTATE_BOOL(rss_data.populate_hash, VirtIONet), + VMSTATE_UINT32(rss_data.hash_types, VirtIONet), + VMSTATE_UINT16(rss_data.indirections_len, VirtIONet), + VMSTATE_UINT16(rss_data.default_queue, VirtIONet), + VMSTATE_UINT8_ARRAY(rss_data.key, VirtIONet, + VIRTIO_NET_RSS_MAX_KEY_SIZE), + VMSTATE_VARRAY_UINT16_ALLOC(rss_data.indirections_table, VirtIONet, + rss_data.indirections_len, 0, + vmstate_info_uint16, uint16_t), + VMSTATE_END_OF_LIST() + }, +}; + static const VMStateDescription vmstate_virtio_net_device = { .name = "virtio-net-device", .version_id = VIRTIO_NET_VM_VERSION, @@ -3004,6 +3037,10 @@ static const VMStateDescription vmstate_virtio_net_device = { has_ctrl_guest_offloads), VMSTATE_END_OF_LIST() }, + .subsections = (const VMStateDescription * []) { + &vmstate_virtio_net_rss, + NULL + } }; static NetClientInfo net_virtio_info = { From dd3d85e89123c907be7628957457af3d03e3b85b Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Fri, 8 May 2020 15:59:34 +0300 Subject: [PATCH 1413/2595] virtio-net: align RSC fields with updated virtio-net header Removal of duplicated RSC definitions. Changing names of the fields to ones defined in the Linux header. Signed-off-by: Yuri Benditovich Signed-off-by: Jason Wang --- hw/net/virtio-net.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 2a5da2985a..aff67a92df 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -88,26 +88,6 @@ VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \ VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) -/* temporary until standard header include it */ -#if !defined(VIRTIO_NET_HDR_F_RSC_INFO) - -#define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc_ext data in csum_ fields */ -#define VIRTIO_NET_F_RSC_EXT 61 - -#endif - -static inline __virtio16 *virtio_net_rsc_ext_num_packets( - struct virtio_net_hdr *hdr) -{ - return &hdr->csum_start; -} - -static inline __virtio16 *virtio_net_rsc_ext_num_dupacks( - struct virtio_net_hdr *hdr) -{ - return &hdr->csum_offset; -} - static VirtIOFeature feature_sizes[] = { {.flags = 1ULL << VIRTIO_NET_F_MAC, .end = endof(struct virtio_net_config, mac)}, @@ -1821,15 +1801,15 @@ static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain, VirtioNetRscSeg *seg) { int ret; - struct virtio_net_hdr *h; + struct virtio_net_hdr_v1 *h; - h = (struct virtio_net_hdr *)seg->buf; + h = (struct virtio_net_hdr_v1 *)seg->buf; h->flags = 0; h->gso_type = VIRTIO_NET_HDR_GSO_NONE; if (seg->is_coalesced) { - *virtio_net_rsc_ext_num_packets(h) = seg->packets; - *virtio_net_rsc_ext_num_dupacks(h) = seg->dup_ack; + h->rsc.segments = seg->packets; + h->rsc.dup_acks = seg->dup_ack; h->flags = VIRTIO_NET_HDR_F_RSC_INFO; if (chain->proto == ETH_P_IP) { h->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; From d9b69640391618045949f7c500b87fc129f862ed Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 26 Apr 2020 12:55:39 +0200 Subject: [PATCH 1414/2595] Fix tulip breakage The tulip network driver in a qemu-system-hppa emulation is broken in the sense that bigger network packages aren't received any longer and thus even running e.g. "apt update" inside the VM fails. The breakage was introduced by commit 8ffb7265af ("check frame size and r/w data length") which added checks to prevent accesses outside of the rx/tx buffers. But the new checks were implemented wrong. The variable rx_frame_len counts backwards, from rx_frame_size down to zero, and the variable len is never bigger than rx_frame_len, so accesses just can't happen and the checks are unnecessary. On the contrary the checks now prevented bigger packages to be moved into the rx buffers. This patch reverts the wrong checks and were sucessfully tested with a qemu-system-hppa emulation. Fixes: 8ffb7265af ("check frame size and r/w data length") Buglink: https://bugs.launchpad.net/bugs/1874539 Signed-off-by: Helge Deller Signed-off-by: Jason Wang --- hw/net/tulip.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/net/tulip.c b/hw/net/tulip.c index 6cefc0add2..57ecbe2161 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -171,9 +171,6 @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc) len = s->rx_frame_len; } - if (s->rx_frame_len + len > sizeof(s->rx_frame)) { - return; - } pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame + (s->rx_frame_size - s->rx_frame_len), len); s->rx_frame_len -= len; @@ -186,9 +183,6 @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc) len = s->rx_frame_len; } - if (s->rx_frame_len + len > sizeof(s->rx_frame)) { - return; - } pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame + (s->rx_frame_size - s->rx_frame_len), len); s->rx_frame_len -= len; From 171ce2e27906a59e243baf8c67ad1c1193cec4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 24 Apr 2020 01:16:42 +0200 Subject: [PATCH 1415/2595] hw/net/tulip: Fix 'Descriptor Error' definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bit #14 is "DE" for 'Descriptor Error': When set, indicates a frame truncation caused by a frame that does not fit within the current descriptor buffers, and that the 21143 does not own the next descriptor. [Table 4-1. RDES0 Bit Fields Description] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/tulip.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/tulip.h b/hw/net/tulip.h index 97521b21db..5271aad8d5 100644 --- a/hw/net/tulip.h +++ b/hw/net/tulip.h @@ -211,7 +211,7 @@ #define RDES0_RF BIT(11) #define RDES0_DT_SHIFT 12 #define RDES0_DT_MASK 3 -#define RDES0_LE BIT(14) +#define RDES0_DE BIT(14) #define RDES0_ES BIT(15) #define RDES0_FL_SHIFT 16 #define RDES0_FL_MASK 0x3fff From 97d7fb5a792b8b289ca6a981d9fe3369fa8b8c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 24 Apr 2020 01:16:43 +0200 Subject: [PATCH 1416/2595] hw/net/tulip: Log descriptor overflows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Log with GUEST_ERROR what the guest is doing wrong. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/tulip.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/net/tulip.c b/hw/net/tulip.c index 57ecbe2161..4487fd61cf 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -578,6 +578,9 @@ static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc) int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK; if (s->tx_frame_len + len1 > sizeof(s->tx_frame)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n", + __func__, s->tx_frame_len, len1, sizeof(s->tx_frame)); return -1; } if (len1) { @@ -587,6 +590,9 @@ static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc) } if (s->tx_frame_len + len2 > sizeof(s->tx_frame)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n", + __func__, s->tx_frame_len, len2, sizeof(s->tx_frame)); return -1; } if (len2) { From 6fe7661d3dc16d605e0ef283b5c77b5256125c2a Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Tue, 12 May 2020 20:24:43 +0530 Subject: [PATCH 1417/2595] net: cadence_gem: Fix debug statements Enabling debug breaks the build, Fix them and make debug statements always compilable. Fix few statements to use sized integer casting. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index e8f9cc7f1e..2e273dca18 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -35,14 +35,13 @@ #include "sysemu/dma.h" #include "net/checksum.h" -#ifdef CADENCE_GEM_ERR_DEBUG -#define DB_PRINT(...) do { \ - fprintf(stderr, ": %s: ", __func__); \ - fprintf(stderr, ## __VA_ARGS__); \ - } while (0) -#else - #define DB_PRINT(...) -#endif +#define CADENCE_GEM_ERR_DEBUG 0 +#define DB_PRINT(...) do {\ + if (CADENCE_GEM_ERR_DEBUG) { \ + qemu_log(": %s: ", __func__); \ + qemu_log(__VA_ARGS__); \ + } \ +} while (0) #define GEM_NWCTRL (0x00000000/4) /* Network Control reg */ #define GEM_NWCFG (0x00000004/4) /* Network Config reg */ @@ -979,7 +978,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) size += 4; } - DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size); + DB_PRINT("config bufsize: %u packet size: %zd\n", rxbufsize, size); /* Find which queue we are targeting */ q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize); @@ -992,9 +991,9 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) return -1; } - DB_PRINT("copy %u bytes to 0x%" PRIx64 "\n", - MIN(bytes_to_copy, rxbufsize), - rx_desc_get_buffer(s, s->rx_desc[q])); + DB_PRINT("copy %" PRIu32 " bytes to 0x%" PRIx64 "\n", + MIN(bytes_to_copy, rxbufsize), + rx_desc_get_buffer(s, s->rx_desc[q])); /* Copy packet data to emulated DMA buffer */ address_space_write(&s->dma_as, rx_desc_get_buffer(s, s->rx_desc[q]) + @@ -1160,8 +1159,8 @@ static void gem_transmit(CadenceGEMState *s) */ if ((tx_desc_get_buffer(s, desc) == 0) || (tx_desc_get_length(desc) == 0)) { - DB_PRINT("Invalid TX descriptor @ 0x%x\n", - (unsigned)packet_desc_addr); + DB_PRINT("Invalid TX descriptor @ 0x%" HWADDR_PRIx "\n", + packet_desc_addr); break; } From 96ea126a8deef30cc81519fb3cb50bf3d65eb6aa Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Tue, 12 May 2020 20:24:44 +0530 Subject: [PATCH 1418/2595] net: cadence_gem: Fix the queue address update during wrap around During wrap around and reset, queues are pointing to initial base address of queue 0, irrespective of what queue we are dealing with. Fix it by assigning proper base address every time. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 2e273dca18..fd3e4a8cd6 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -845,6 +845,35 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr, return 0; } +static uint32_t gem_get_queue_base_addr(CadenceGEMState *s, bool tx, int q) +{ + uint32_t base_addr = 0; + + switch (q) { + case 0: + base_addr = s->regs[tx ? GEM_TXQBASE : GEM_RXQBASE]; + break; + case 1 ... (MAX_PRIORITY_QUEUES - 1): + base_addr = s->regs[(tx ? GEM_TRANSMIT_Q1_PTR : + GEM_RECEIVE_Q1_PTR) + q - 1]; + break; + default: + g_assert_not_reached(); + }; + + return base_addr; +} + +static inline uint32_t gem_get_tx_queue_base_addr(CadenceGEMState *s, int q) +{ + return gem_get_queue_base_addr(s, true, q); +} + +static inline uint32_t gem_get_rx_queue_base_addr(CadenceGEMState *s, int q) +{ + return gem_get_queue_base_addr(s, false, q); +} + static hwaddr gem_get_desc_addr(CadenceGEMState *s, bool tx, int q) { hwaddr desc_addr = 0; @@ -1043,7 +1072,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) /* Next descriptor */ if (rx_desc_get_wrap(s->rx_desc[q])) { DB_PRINT("wrapping RX descriptor list\n"); - s->rx_desc_addr[q] = s->regs[GEM_RXQBASE]; + s->rx_desc_addr[q] = gem_get_rx_queue_base_addr(s, q); } else { DB_PRINT("incrementing RX descriptor list\n"); s->rx_desc_addr[q] += 4 * gem_get_desc_len(s, true); @@ -1199,7 +1228,7 @@ static void gem_transmit(CadenceGEMState *s) sizeof(desc_first)); /* Advance the hardware current descriptor past this packet */ if (tx_desc_get_wrap(desc)) { - s->tx_desc_addr[q] = s->regs[GEM_TXQBASE]; + s->tx_desc_addr[q] = gem_get_tx_queue_base_addr(s, q); } else { s->tx_desc_addr[q] = packet_desc_addr + 4 * gem_get_desc_len(s, false); @@ -1251,7 +1280,7 @@ static void gem_transmit(CadenceGEMState *s) } else { packet_desc_addr = 0; } - packet_desc_addr |= s->regs[GEM_TXQBASE]; + packet_desc_addr |= gem_get_tx_queue_base_addr(s, q); } else { packet_desc_addr += 4 * gem_get_desc_len(s, false); } @@ -1457,7 +1486,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, if (!(val & GEM_NWCTRL_TXENA)) { /* Reset to start of Q when transmit disabled. */ for (i = 0; i < s->num_priority_queues; i++) { - s->tx_desc_addr[i] = s->regs[GEM_TXQBASE]; + s->tx_desc_addr[i] = gem_get_tx_queue_base_addr(s, i); } } if (gem_can_receive(qemu_get_queue(s->nic))) { From 86a29d4c72e42130e08bae3335c25575d4af0b4d Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Tue, 12 May 2020 20:24:45 +0530 Subject: [PATCH 1419/2595] net: cadence_gem: Fix irq update w.r.t queue Set irq's specific to a queue, present implementation is setting q1 irq based on q0 status. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index fd3e4a8cd6..4ad6c8e3c9 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -554,29 +554,10 @@ static void gem_update_int_status(CadenceGEMState *s) { int i; - if (!s->regs[GEM_ISR]) { - /* ISR isn't set, clear all the interrupts */ - for (i = 0; i < s->num_priority_queues; ++i) { - qemu_set_irq(s->irq[i], 0); - } - return; - } + qemu_set_irq(s->irq[0], !!s->regs[GEM_ISR]); - /* If we get here we know s->regs[GEM_ISR] is set, so we don't need to - * check it again. - */ - if (s->num_priority_queues == 1) { - /* No priority queues, just trigger the interrupt */ - DB_PRINT("asserting int.\n"); - qemu_set_irq(s->irq[0], 1); - return; - } - - for (i = 0; i < s->num_priority_queues; ++i) { - if (s->regs[GEM_INT_Q1_STATUS + i]) { - DB_PRINT("asserting int. (q=%d)\n", i); - qemu_set_irq(s->irq[i], 1); - } + for (i = 1; i < s->num_priority_queues; ++i) { + qemu_set_irq(s->irq[i], !!s->regs[GEM_INT_Q1_STATUS + i - 1]); } } From 4c70e32f05fc7903185a4e9d01987ee3de2052f6 Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Tue, 12 May 2020 20:24:46 +0530 Subject: [PATCH 1420/2595] net: cadence_gem: Define access permission for interrupt registers Q1 to Q7 ISR's are clear-on-read, IER/IDR registers are write-only, mask reg are read-only. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 4ad6c8e3c9..72e7cf99d7 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -458,6 +458,7 @@ static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; */ static void gem_init_register_masks(CadenceGEMState *s) { + unsigned int i; /* Mask of register bits which are read only */ memset(&s->regs_ro[0], 0, sizeof(s->regs_ro)); s->regs_ro[GEM_NWCTRL] = 0xFFF80000; @@ -470,10 +471,19 @@ static void gem_init_register_masks(CadenceGEMState *s) s->regs_ro[GEM_ISR] = 0xFFFFFFFF; s->regs_ro[GEM_IMR] = 0xFFFFFFFF; s->regs_ro[GEM_MODID] = 0xFFFFFFFF; + for (i = 0; i < s->num_priority_queues; i++) { + s->regs_ro[GEM_INT_Q1_STATUS + i] = 0xFFFFFFFF; + s->regs_ro[GEM_INT_Q1_ENABLE + i] = 0xFFFFF319; + s->regs_ro[GEM_INT_Q1_DISABLE + i] = 0xFFFFF319; + s->regs_ro[GEM_INT_Q1_MASK + i] = 0xFFFFFFFF; + } /* Mask of register bits which are clear on read */ memset(&s->regs_rtc[0], 0, sizeof(s->regs_rtc)); s->regs_rtc[GEM_ISR] = 0xFFFFFFFF; + for (i = 0; i < s->num_priority_queues; i++) { + s->regs_rtc[GEM_INT_Q1_STATUS + i] = 0x00000CE6; + } /* Mask of register bits which are write 1 to clear */ memset(&s->regs_w1c[0], 0, sizeof(s->regs_w1c)); @@ -485,6 +495,10 @@ static void gem_init_register_masks(CadenceGEMState *s) s->regs_wo[GEM_NWCTRL] = 0x00073E60; s->regs_wo[GEM_IER] = 0x07FFFFFF; s->regs_wo[GEM_IDR] = 0x07FFFFFF; + for (i = 0; i < s->num_priority_queues; i++) { + s->regs_wo[GEM_INT_Q1_ENABLE + i] = 0x00000CE6; + s->regs_wo[GEM_INT_Q1_DISABLE + i] = 0x00000CE6; + } } /* From 68dbee3bf95173d73f103d1a82ad9b14e5cde354 Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Tue, 12 May 2020 20:24:47 +0530 Subject: [PATCH 1421/2595] net: cadence_gem: Set ISR according to queue in use Set ISR according to queue in use, added interrupt support for all queues. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 72e7cf99d7..2e183b5976 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -451,6 +451,16 @@ static inline void rx_desc_set_sar(uint32_t *desc, int sar_idx) /* The broadcast MAC address: 0xFFFFFFFFFFFF */ static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static void gem_set_isr(CadenceGEMState *s, int q, uint32_t flag) +{ + if (q == 0) { + s->regs[GEM_ISR] |= flag & ~(s->regs[GEM_IMR]); + } else { + s->regs[GEM_INT_Q1_STATUS + q - 1] |= flag & + ~(s->regs[GEM_INT_Q1_MASK + q - 1]); + } +} + /* * gem_init_register_masks: * One time initialization. @@ -906,7 +916,7 @@ static void gem_get_rx_desc(CadenceGEMState *s, int q) if (rx_desc_get_ownership(s->rx_desc[q]) == 1) { DB_PRINT("descriptor 0x%" HWADDR_PRIx " owned by sw.\n", desc_addr); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF; - s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]); + gem_set_isr(s, q, GEM_INT_RXUSED); /* Handle interrupt consequences */ gem_update_int_status(s); } @@ -1080,7 +1090,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) gem_receive_updatestats(s, buf, size); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD; - s->regs[GEM_ISR] |= GEM_INT_RXCMPL & ~(s->regs[GEM_IMR]); + gem_set_isr(s, q, GEM_INT_RXCMPL); /* Handle interrupt consequences */ gem_update_int_status(s); @@ -1231,13 +1241,7 @@ static void gem_transmit(CadenceGEMState *s) DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]); s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL; - s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]); - - /* Update queue interrupt status */ - if (s->num_priority_queues > 1) { - s->regs[GEM_INT_Q1_STATUS + q] |= - GEM_INT_TXCMPL & ~(s->regs[GEM_INT_Q1_MASK + q]); - } + gem_set_isr(s, q, GEM_INT_TXCMPL); /* Handle interrupt consequences */ gem_update_int_status(s); @@ -1287,7 +1291,10 @@ static void gem_transmit(CadenceGEMState *s) if (tx_desc_get_used(desc)) { s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED; - s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]); + /* IRQ TXUSED is defined only for queue 0 */ + if (q == 0) { + gem_set_isr(s, 0, GEM_INT_TXUSED); + } gem_update_int_status(s); } } From 24d62fd5028ea66448f441de8ae483beaf4afe93 Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Tue, 12 May 2020 20:24:48 +0530 Subject: [PATCH 1422/2595] net: cadence_gem: Move tx/rx packet buffert to CadenceGEMState Moving this buffers to CadenceGEMState, as their size will be increased more when JUMBO frames support is added. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 38 ++++++++++++++++-------------------- include/hw/net/cadence_gem.h | 4 ++++ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 2e183b5976..247a52f8ce 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -928,17 +928,14 @@ static void gem_get_rx_desc(CadenceGEMState *s, int q) */ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - CadenceGEMState *s; + CadenceGEMState *s = qemu_get_nic_opaque(nc); unsigned rxbufsize, bytes_to_copy; unsigned rxbuf_offset; - uint8_t rxbuf[2048]; uint8_t *rxbuf_ptr; bool first_desc = true; int maf; int q = 0; - s = qemu_get_nic_opaque(nc); - /* Is this destination MAC address "for us" ? */ maf = gem_mac_address_filter(s, buf); if (maf == GEM_RX_REJECT) { @@ -994,19 +991,19 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) } else { unsigned crc_val; - if (size > sizeof(rxbuf) - sizeof(crc_val)) { - size = sizeof(rxbuf) - sizeof(crc_val); + if (size > MAX_FRAME_SIZE - sizeof(crc_val)) { + size = MAX_FRAME_SIZE - sizeof(crc_val); } bytes_to_copy = size; /* The application wants the FCS field, which QEMU does not provide. * We must try and calculate one. */ - memcpy(rxbuf, buf, size); - memset(rxbuf + size, 0, sizeof(rxbuf) - size); - rxbuf_ptr = rxbuf; - crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60))); - memcpy(rxbuf + size, &crc_val, sizeof(crc_val)); + memcpy(s->rx_packet, buf, size); + memset(s->rx_packet + size, 0, MAX_FRAME_SIZE - size); + rxbuf_ptr = s->rx_packet; + crc_val = cpu_to_le32(crc32(0, s->rx_packet, MAX(size, 60))); + memcpy(s->rx_packet + size, &crc_val, sizeof(crc_val)); bytes_to_copy += 4; size += 4; @@ -1152,7 +1149,6 @@ static void gem_transmit(CadenceGEMState *s) { uint32_t desc[DESC_MAX_NUM_WORDS]; hwaddr packet_desc_addr; - uint8_t tx_packet[2048]; uint8_t *p; unsigned total_bytes; int q = 0; @@ -1168,7 +1164,7 @@ static void gem_transmit(CadenceGEMState *s) * Packets scattered across multiple descriptors are gathered to this * one contiguous buffer first. */ - p = tx_packet; + p = s->tx_packet; total_bytes = 0; for (q = s->num_priority_queues - 1; q >= 0; q--) { @@ -1198,12 +1194,12 @@ static void gem_transmit(CadenceGEMState *s) break; } - if (tx_desc_get_length(desc) > sizeof(tx_packet) - - (p - tx_packet)) { + if (tx_desc_get_length(desc) > MAX_FRAME_SIZE - + (p - s->tx_packet)) { DB_PRINT("TX descriptor @ 0x%" HWADDR_PRIx \ " too large: size 0x%x space 0x%zx\n", packet_desc_addr, tx_desc_get_length(desc), - sizeof(tx_packet) - (p - tx_packet)); + MAX_FRAME_SIZE - (p - s->tx_packet)); break; } @@ -1248,24 +1244,24 @@ static void gem_transmit(CadenceGEMState *s) /* Is checksum offload enabled? */ if (s->regs[GEM_DMACFG] & GEM_DMACFG_TXCSUM_OFFL) { - net_checksum_calculate(tx_packet, total_bytes); + net_checksum_calculate(s->tx_packet, total_bytes); } /* Update MAC statistics */ - gem_transmit_updatestats(s, tx_packet, total_bytes); + gem_transmit_updatestats(s, s->tx_packet, total_bytes); /* Send the packet somewhere */ if (s->phy_loop || (s->regs[GEM_NWCTRL] & GEM_NWCTRL_LOCALLOOP)) { - gem_receive(qemu_get_queue(s->nic), tx_packet, + gem_receive(qemu_get_queue(s->nic), s->tx_packet, total_bytes); } else { - qemu_send_packet(qemu_get_queue(s->nic), tx_packet, + qemu_send_packet(qemu_get_queue(s->nic), s->tx_packet, total_bytes); } /* Prepare for next packet */ - p = tx_packet; + p = s->tx_packet; total_bytes = 0; } diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h index 5c83036ade..eddac70f20 100644 --- a/include/hw/net/cadence_gem.h +++ b/include/hw/net/cadence_gem.h @@ -40,6 +40,8 @@ #define MAX_TYPE1_SCREENERS 16 #define MAX_TYPE2_SCREENERS 16 +#define MAX_FRAME_SIZE 2048 + typedef struct CadenceGEMState { /*< private >*/ SysBusDevice parent_obj; @@ -80,6 +82,8 @@ typedef struct CadenceGEMState { uint8_t can_rx_state; /* Debug only */ + uint8_t tx_packet[MAX_FRAME_SIZE]; + uint8_t rx_packet[MAX_FRAME_SIZE]; uint32_t rx_desc[MAX_PRIORITY_QUEUES][DESC_MAX_NUM_WORDS]; bool sar_active[4]; From 88dba7ed842d18da0a9354660adf1e6a5a87b37b Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Tue, 12 May 2020 20:24:49 +0530 Subject: [PATCH 1423/2595] net: cadence_gem: Fix up code style Fix the code style for register definitions. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 202 ++++++++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 100 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 247a52f8ce..22d0d167c1 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -43,110 +43,112 @@ } \ } while (0) -#define GEM_NWCTRL (0x00000000/4) /* Network Control reg */ -#define GEM_NWCFG (0x00000004/4) /* Network Config reg */ -#define GEM_NWSTATUS (0x00000008/4) /* Network Status reg */ -#define GEM_USERIO (0x0000000C/4) /* User IO reg */ -#define GEM_DMACFG (0x00000010/4) /* DMA Control reg */ -#define GEM_TXSTATUS (0x00000014/4) /* TX Status reg */ -#define GEM_RXQBASE (0x00000018/4) /* RX Q Base address reg */ -#define GEM_TXQBASE (0x0000001C/4) /* TX Q Base address reg */ -#define GEM_RXSTATUS (0x00000020/4) /* RX Status reg */ -#define GEM_ISR (0x00000024/4) /* Interrupt Status reg */ -#define GEM_IER (0x00000028/4) /* Interrupt Enable reg */ -#define GEM_IDR (0x0000002C/4) /* Interrupt Disable reg */ -#define GEM_IMR (0x00000030/4) /* Interrupt Mask reg */ -#define GEM_PHYMNTNC (0x00000034/4) /* Phy Maintenance reg */ -#define GEM_RXPAUSE (0x00000038/4) /* RX Pause Time reg */ -#define GEM_TXPAUSE (0x0000003C/4) /* TX Pause Time reg */ -#define GEM_TXPARTIALSF (0x00000040/4) /* TX Partial Store and Forward */ -#define GEM_RXPARTIALSF (0x00000044/4) /* RX Partial Store and Forward */ -#define GEM_HASHLO (0x00000080/4) /* Hash Low address reg */ -#define GEM_HASHHI (0x00000084/4) /* Hash High address reg */ -#define GEM_SPADDR1LO (0x00000088/4) /* Specific addr 1 low reg */ -#define GEM_SPADDR1HI (0x0000008C/4) /* Specific addr 1 high reg */ -#define GEM_SPADDR2LO (0x00000090/4) /* Specific addr 2 low reg */ -#define GEM_SPADDR2HI (0x00000094/4) /* Specific addr 2 high reg */ -#define GEM_SPADDR3LO (0x00000098/4) /* Specific addr 3 low reg */ -#define GEM_SPADDR3HI (0x0000009C/4) /* Specific addr 3 high reg */ -#define GEM_SPADDR4LO (0x000000A0/4) /* Specific addr 4 low reg */ -#define GEM_SPADDR4HI (0x000000A4/4) /* Specific addr 4 high reg */ -#define GEM_TIDMATCH1 (0x000000A8/4) /* Type ID1 Match reg */ -#define GEM_TIDMATCH2 (0x000000AC/4) /* Type ID2 Match reg */ -#define GEM_TIDMATCH3 (0x000000B0/4) /* Type ID3 Match reg */ -#define GEM_TIDMATCH4 (0x000000B4/4) /* Type ID4 Match reg */ -#define GEM_WOLAN (0x000000B8/4) /* Wake on LAN reg */ -#define GEM_IPGSTRETCH (0x000000BC/4) /* IPG Stretch reg */ -#define GEM_SVLAN (0x000000C0/4) /* Stacked VLAN reg */ -#define GEM_MODID (0x000000FC/4) /* Module ID reg */ -#define GEM_OCTTXLO (0x00000100/4) /* Octects transmitted Low reg */ -#define GEM_OCTTXHI (0x00000104/4) /* Octects transmitted High reg */ -#define GEM_TXCNT (0x00000108/4) /* Error-free Frames transmitted */ -#define GEM_TXBCNT (0x0000010C/4) /* Error-free Broadcast Frames */ -#define GEM_TXMCNT (0x00000110/4) /* Error-free Multicast Frame */ -#define GEM_TXPAUSECNT (0x00000114/4) /* Pause Frames Transmitted */ -#define GEM_TX64CNT (0x00000118/4) /* Error-free 64 TX */ -#define GEM_TX65CNT (0x0000011C/4) /* Error-free 65-127 TX */ -#define GEM_TX128CNT (0x00000120/4) /* Error-free 128-255 TX */ -#define GEM_TX256CNT (0x00000124/4) /* Error-free 256-511 */ -#define GEM_TX512CNT (0x00000128/4) /* Error-free 512-1023 TX */ -#define GEM_TX1024CNT (0x0000012C/4) /* Error-free 1024-1518 TX */ -#define GEM_TX1519CNT (0x00000130/4) /* Error-free larger than 1519 TX */ -#define GEM_TXURUNCNT (0x00000134/4) /* TX under run error counter */ -#define GEM_SINGLECOLLCNT (0x00000138/4) /* Single Collision Frames */ -#define GEM_MULTCOLLCNT (0x0000013C/4) /* Multiple Collision Frames */ -#define GEM_EXCESSCOLLCNT (0x00000140/4) /* Excessive Collision Frames */ -#define GEM_LATECOLLCNT (0x00000144/4) /* Late Collision Frames */ -#define GEM_DEFERTXCNT (0x00000148/4) /* Deferred Transmission Frames */ -#define GEM_CSENSECNT (0x0000014C/4) /* Carrier Sense Error Counter */ -#define GEM_OCTRXLO (0x00000150/4) /* Octects Received register Low */ -#define GEM_OCTRXHI (0x00000154/4) /* Octects Received register High */ -#define GEM_RXCNT (0x00000158/4) /* Error-free Frames Received */ -#define GEM_RXBROADCNT (0x0000015C/4) /* Error-free Broadcast Frames RX */ -#define GEM_RXMULTICNT (0x00000160/4) /* Error-free Multicast Frames RX */ -#define GEM_RXPAUSECNT (0x00000164/4) /* Pause Frames Received Counter */ -#define GEM_RX64CNT (0x00000168/4) /* Error-free 64 byte Frames RX */ -#define GEM_RX65CNT (0x0000016C/4) /* Error-free 65-127B Frames RX */ -#define GEM_RX128CNT (0x00000170/4) /* Error-free 128-255B Frames RX */ -#define GEM_RX256CNT (0x00000174/4) /* Error-free 256-512B Frames RX */ -#define GEM_RX512CNT (0x00000178/4) /* Error-free 512-1023B Frames RX */ -#define GEM_RX1024CNT (0x0000017C/4) /* Error-free 1024-1518B Frames RX */ -#define GEM_RX1519CNT (0x00000180/4) /* Error-free 1519-max Frames RX */ -#define GEM_RXUNDERCNT (0x00000184/4) /* Undersize Frames Received */ -#define GEM_RXOVERCNT (0x00000188/4) /* Oversize Frames Received */ -#define GEM_RXJABCNT (0x0000018C/4) /* Jabbers Received Counter */ -#define GEM_RXFCSCNT (0x00000190/4) /* Frame Check seq. Error Counter */ -#define GEM_RXLENERRCNT (0x00000194/4) /* Length Field Error Counter */ -#define GEM_RXSYMERRCNT (0x00000198/4) /* Symbol Error Counter */ -#define GEM_RXALIGNERRCNT (0x0000019C/4) /* Alignment Error Counter */ -#define GEM_RXRSCERRCNT (0x000001A0/4) /* Receive Resource Error Counter */ -#define GEM_RXORUNCNT (0x000001A4/4) /* Receive Overrun Counter */ -#define GEM_RXIPCSERRCNT (0x000001A8/4) /* IP header Checksum Error Counter */ -#define GEM_RXTCPCCNT (0x000001AC/4) /* TCP Checksum Error Counter */ -#define GEM_RXUDPCCNT (0x000001B0/4) /* UDP Checksum Error Counter */ +#define GEM_NWCTRL (0x00000000 / 4) /* Network Control reg */ +#define GEM_NWCFG (0x00000004 / 4) /* Network Config reg */ +#define GEM_NWSTATUS (0x00000008 / 4) /* Network Status reg */ +#define GEM_USERIO (0x0000000C / 4) /* User IO reg */ +#define GEM_DMACFG (0x00000010 / 4) /* DMA Control reg */ +#define GEM_TXSTATUS (0x00000014 / 4) /* TX Status reg */ +#define GEM_RXQBASE (0x00000018 / 4) /* RX Q Base address reg */ +#define GEM_TXQBASE (0x0000001C / 4) /* TX Q Base address reg */ +#define GEM_RXSTATUS (0x00000020 / 4) /* RX Status reg */ +#define GEM_ISR (0x00000024 / 4) /* Interrupt Status reg */ +#define GEM_IER (0x00000028 / 4) /* Interrupt Enable reg */ +#define GEM_IDR (0x0000002C / 4) /* Interrupt Disable reg */ +#define GEM_IMR (0x00000030 / 4) /* Interrupt Mask reg */ +#define GEM_PHYMNTNC (0x00000034 / 4) /* Phy Maintenance reg */ +#define GEM_RXPAUSE (0x00000038 / 4) /* RX Pause Time reg */ +#define GEM_TXPAUSE (0x0000003C / 4) /* TX Pause Time reg */ +#define GEM_TXPARTIALSF (0x00000040 / 4) /* TX Partial Store and Forward */ +#define GEM_RXPARTIALSF (0x00000044 / 4) /* RX Partial Store and Forward */ +#define GEM_HASHLO (0x00000080 / 4) /* Hash Low address reg */ +#define GEM_HASHHI (0x00000084 / 4) /* Hash High address reg */ +#define GEM_SPADDR1LO (0x00000088 / 4) /* Specific addr 1 low reg */ +#define GEM_SPADDR1HI (0x0000008C / 4) /* Specific addr 1 high reg */ +#define GEM_SPADDR2LO (0x00000090 / 4) /* Specific addr 2 low reg */ +#define GEM_SPADDR2HI (0x00000094 / 4) /* Specific addr 2 high reg */ +#define GEM_SPADDR3LO (0x00000098 / 4) /* Specific addr 3 low reg */ +#define GEM_SPADDR3HI (0x0000009C / 4) /* Specific addr 3 high reg */ +#define GEM_SPADDR4LO (0x000000A0 / 4) /* Specific addr 4 low reg */ +#define GEM_SPADDR4HI (0x000000A4 / 4) /* Specific addr 4 high reg */ +#define GEM_TIDMATCH1 (0x000000A8 / 4) /* Type ID1 Match reg */ +#define GEM_TIDMATCH2 (0x000000AC / 4) /* Type ID2 Match reg */ +#define GEM_TIDMATCH3 (0x000000B0 / 4) /* Type ID3 Match reg */ +#define GEM_TIDMATCH4 (0x000000B4 / 4) /* Type ID4 Match reg */ +#define GEM_WOLAN (0x000000B8 / 4) /* Wake on LAN reg */ +#define GEM_IPGSTRETCH (0x000000BC / 4) /* IPG Stretch reg */ +#define GEM_SVLAN (0x000000C0 / 4) /* Stacked VLAN reg */ +#define GEM_MODID (0x000000FC / 4) /* Module ID reg */ +#define GEM_OCTTXLO (0x00000100 / 4) /* Octects transmitted Low reg */ +#define GEM_OCTTXHI (0x00000104 / 4) /* Octects transmitted High reg */ +#define GEM_TXCNT (0x00000108 / 4) /* Error-free Frames transmitted */ +#define GEM_TXBCNT (0x0000010C / 4) /* Error-free Broadcast Frames */ +#define GEM_TXMCNT (0x00000110 / 4) /* Error-free Multicast Frame */ +#define GEM_TXPAUSECNT (0x00000114 / 4) /* Pause Frames Transmitted */ +#define GEM_TX64CNT (0x00000118 / 4) /* Error-free 64 TX */ +#define GEM_TX65CNT (0x0000011C / 4) /* Error-free 65-127 TX */ +#define GEM_TX128CNT (0x00000120 / 4) /* Error-free 128-255 TX */ +#define GEM_TX256CNT (0x00000124 / 4) /* Error-free 256-511 */ +#define GEM_TX512CNT (0x00000128 / 4) /* Error-free 512-1023 TX */ +#define GEM_TX1024CNT (0x0000012C / 4) /* Error-free 1024-1518 TX */ +#define GEM_TX1519CNT (0x00000130 / 4) /* Error-free larger than 1519 TX */ +#define GEM_TXURUNCNT (0x00000134 / 4) /* TX under run error counter */ +#define GEM_SINGLECOLLCNT (0x00000138 / 4) /* Single Collision Frames */ +#define GEM_MULTCOLLCNT (0x0000013C / 4) /* Multiple Collision Frames */ +#define GEM_EXCESSCOLLCNT (0x00000140 / 4) /* Excessive Collision Frames */ +#define GEM_LATECOLLCNT (0x00000144 / 4) /* Late Collision Frames */ +#define GEM_DEFERTXCNT (0x00000148 / 4) /* Deferred Transmission Frames */ +#define GEM_CSENSECNT (0x0000014C / 4) /* Carrier Sense Error Counter */ +#define GEM_OCTRXLO (0x00000150 / 4) /* Octects Received register Low */ +#define GEM_OCTRXHI (0x00000154 / 4) /* Octects Received register High */ +#define GEM_RXCNT (0x00000158 / 4) /* Error-free Frames Received */ +#define GEM_RXBROADCNT (0x0000015C / 4) /* Error-free Broadcast Frames RX */ +#define GEM_RXMULTICNT (0x00000160 / 4) /* Error-free Multicast Frames RX */ +#define GEM_RXPAUSECNT (0x00000164 / 4) /* Pause Frames Received Counter */ +#define GEM_RX64CNT (0x00000168 / 4) /* Error-free 64 byte Frames RX */ +#define GEM_RX65CNT (0x0000016C / 4) /* Error-free 65-127B Frames RX */ +#define GEM_RX128CNT (0x00000170 / 4) /* Error-free 128-255B Frames RX */ +#define GEM_RX256CNT (0x00000174 / 4) /* Error-free 256-512B Frames RX */ +#define GEM_RX512CNT (0x00000178 / 4) /* Error-free 512-1023B Frames RX */ +#define GEM_RX1024CNT (0x0000017C / 4) /* Error-free 1024-1518B Frames RX */ +#define GEM_RX1519CNT (0x00000180 / 4) /* Error-free 1519-max Frames RX */ +#define GEM_RXUNDERCNT (0x00000184 / 4) /* Undersize Frames Received */ +#define GEM_RXOVERCNT (0x00000188 / 4) /* Oversize Frames Received */ +#define GEM_RXJABCNT (0x0000018C / 4) /* Jabbers Received Counter */ +#define GEM_RXFCSCNT (0x00000190 / 4) /* Frame Check seq. Error Counter */ +#define GEM_RXLENERRCNT (0x00000194 / 4) /* Length Field Error Counter */ +#define GEM_RXSYMERRCNT (0x00000198 / 4) /* Symbol Error Counter */ +#define GEM_RXALIGNERRCNT (0x0000019C / 4) /* Alignment Error Counter */ +#define GEM_RXRSCERRCNT (0x000001A0 / 4) /* Receive Resource Error Counter */ +#define GEM_RXORUNCNT (0x000001A4 / 4) /* Receive Overrun Counter */ +#define GEM_RXIPCSERRCNT (0x000001A8 / 4) /* IP header Checksum Err Counter */ +#define GEM_RXTCPCCNT (0x000001AC / 4) /* TCP Checksum Error Counter */ +#define GEM_RXUDPCCNT (0x000001B0 / 4) /* UDP Checksum Error Counter */ -#define GEM_1588S (0x000001D0/4) /* 1588 Timer Seconds */ -#define GEM_1588NS (0x000001D4/4) /* 1588 Timer Nanoseconds */ -#define GEM_1588ADJ (0x000001D8/4) /* 1588 Timer Adjust */ -#define GEM_1588INC (0x000001DC/4) /* 1588 Timer Increment */ -#define GEM_PTPETXS (0x000001E0/4) /* PTP Event Frame Transmitted (s) */ -#define GEM_PTPETXNS (0x000001E4/4) /* PTP Event Frame Transmitted (ns) */ -#define GEM_PTPERXS (0x000001E8/4) /* PTP Event Frame Received (s) */ -#define GEM_PTPERXNS (0x000001EC/4) /* PTP Event Frame Received (ns) */ -#define GEM_PTPPTXS (0x000001E0/4) /* PTP Peer Frame Transmitted (s) */ -#define GEM_PTPPTXNS (0x000001E4/4) /* PTP Peer Frame Transmitted (ns) */ -#define GEM_PTPPRXS (0x000001E8/4) /* PTP Peer Frame Received (s) */ -#define GEM_PTPPRXNS (0x000001EC/4) /* PTP Peer Frame Received (ns) */ +#define GEM_1588S (0x000001D0 / 4) /* 1588 Timer Seconds */ +#define GEM_1588NS (0x000001D4 / 4) /* 1588 Timer Nanoseconds */ +#define GEM_1588ADJ (0x000001D8 / 4) /* 1588 Timer Adjust */ +#define GEM_1588INC (0x000001DC / 4) /* 1588 Timer Increment */ +#define GEM_PTPETXS (0x000001E0 / 4) /* PTP Event Frame Transmitted (s) */ +#define GEM_PTPETXNS (0x000001E4 / 4) /* + * PTP Event Frame Transmitted (ns) + */ +#define GEM_PTPERXS (0x000001E8 / 4) /* PTP Event Frame Received (s) */ +#define GEM_PTPERXNS (0x000001EC / 4) /* PTP Event Frame Received (ns) */ +#define GEM_PTPPTXS (0x000001E0 / 4) /* PTP Peer Frame Transmitted (s) */ +#define GEM_PTPPTXNS (0x000001E4 / 4) /* PTP Peer Frame Transmitted (ns) */ +#define GEM_PTPPRXS (0x000001E8 / 4) /* PTP Peer Frame Received (s) */ +#define GEM_PTPPRXNS (0x000001EC / 4) /* PTP Peer Frame Received (ns) */ /* Design Configuration Registers */ -#define GEM_DESCONF (0x00000280/4) -#define GEM_DESCONF2 (0x00000284/4) -#define GEM_DESCONF3 (0x00000288/4) -#define GEM_DESCONF4 (0x0000028C/4) -#define GEM_DESCONF5 (0x00000290/4) -#define GEM_DESCONF6 (0x00000294/4) +#define GEM_DESCONF (0x00000280 / 4) +#define GEM_DESCONF2 (0x00000284 / 4) +#define GEM_DESCONF3 (0x00000288 / 4) +#define GEM_DESCONF4 (0x0000028C / 4) +#define GEM_DESCONF5 (0x00000290 / 4) +#define GEM_DESCONF6 (0x00000294 / 4) #define GEM_DESCONF6_64B_MASK (1U << 23) -#define GEM_DESCONF7 (0x00000298/4) +#define GEM_DESCONF7 (0x00000298 / 4) #define GEM_INT_Q1_STATUS (0x00000400 / 4) #define GEM_INT_Q1_MASK (0x00000640 / 4) From 7ca151c381c1da146dd274c428ed7825906cc29a Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Tue, 12 May 2020 20:24:50 +0530 Subject: [PATCH 1424/2595] net: cadence_gem: Add support for jumbo frames Add a property "jumbo-max-len", which sets default value of jumbo frames up to 16,383 bytes. Add Frame length checks for standard and jumbo frames. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 51 ++++++++++++++++++++++++++++++++---- include/hw/net/cadence_gem.h | 4 ++- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 22d0d167c1..8e927ada73 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -61,6 +61,7 @@ #define GEM_TXPAUSE (0x0000003C / 4) /* TX Pause Time reg */ #define GEM_TXPARTIALSF (0x00000040 / 4) /* TX Partial Store and Forward */ #define GEM_RXPARTIALSF (0x00000044 / 4) /* RX Partial Store and Forward */ +#define GEM_JUMBO_MAX_LEN (0x00000048 / 4) /* Max Jumbo Frame Size */ #define GEM_HASHLO (0x00000080 / 4) /* Hash Low address reg */ #define GEM_HASHHI (0x00000084 / 4) /* Hash High address reg */ #define GEM_SPADDR1LO (0x00000088 / 4) /* Specific addr 1 low reg */ @@ -212,10 +213,12 @@ #define GEM_NWCFG_LERR_DISC 0x00010000 /* Discard RX frames with len err */ #define GEM_NWCFG_BUFF_OFST_M 0x0000C000 /* Receive buffer offset mask */ #define GEM_NWCFG_BUFF_OFST_S 14 /* Receive buffer offset shift */ +#define GEM_NWCFG_RCV_1538 0x00000100 /* Receive 1538 bytes frame */ #define GEM_NWCFG_UCAST_HASH 0x00000080 /* accept unicast if hash match */ #define GEM_NWCFG_MCAST_HASH 0x00000040 /* accept multicast if hash match */ #define GEM_NWCFG_BCAST_REJ 0x00000020 /* Reject broadcast packets */ #define GEM_NWCFG_PROMISC 0x00000010 /* Accept all packets */ +#define GEM_NWCFG_JUMBO_FRAME 0x00000008 /* Jumbo Frames enable */ #define GEM_DMACFG_ADDR_64B (1U << 30) #define GEM_DMACFG_TX_BD_EXT (1U << 29) @@ -233,6 +236,7 @@ /* GEM_ISR GEM_IER GEM_IDR GEM_IMR */ #define GEM_INT_TXCMPL 0x00000080 /* Transmit Complete */ +#define GEM_INT_AMBA_ERR 0x00000040 #define GEM_INT_TXUSED 0x00000008 #define GEM_INT_RXUSED 0x00000004 #define GEM_INT_RXCMPL 0x00000002 @@ -453,6 +457,24 @@ static inline void rx_desc_set_sar(uint32_t *desc, int sar_idx) /* The broadcast MAC address: 0xFFFFFFFFFFFF */ static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static uint32_t gem_get_max_buf_len(CadenceGEMState *s, bool tx) +{ + uint32_t size; + if (s->regs[GEM_NWCFG] & GEM_NWCFG_JUMBO_FRAME) { + size = s->regs[GEM_JUMBO_MAX_LEN]; + if (size > s->jumbo_max_len) { + size = s->jumbo_max_len; + qemu_log_mask(LOG_GUEST_ERROR, "GEM_JUMBO_MAX_LEN reg cannot be" + " greater than 0x%" PRIx32 "\n", s->jumbo_max_len); + } + } else if (tx) { + size = 1518; + } else { + size = s->regs[GEM_NWCFG] & GEM_NWCFG_RCV_1538 ? 1538 : 1518; + } + return size; +} + static void gem_set_isr(CadenceGEMState *s, int q, uint32_t flag) { if (q == 0) { @@ -1016,6 +1038,12 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) /* Find which queue we are targeting */ q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize); + if (size > gem_get_max_buf_len(s, false)) { + qemu_log_mask(LOG_GUEST_ERROR, "rx frame too long\n"); + gem_set_isr(s, q, GEM_INT_AMBA_ERR); + return -1; + } + while (bytes_to_copy) { hwaddr desc_addr; @@ -1196,12 +1224,13 @@ static void gem_transmit(CadenceGEMState *s) break; } - if (tx_desc_get_length(desc) > MAX_FRAME_SIZE - + if (tx_desc_get_length(desc) > gem_get_max_buf_len(s, true) - (p - s->tx_packet)) { - DB_PRINT("TX descriptor @ 0x%" HWADDR_PRIx \ - " too large: size 0x%x space 0x%zx\n", + qemu_log_mask(LOG_GUEST_ERROR, "TX descriptor @ 0x%" \ + HWADDR_PRIx " too large: size 0x%x space 0x%zx\n", packet_desc_addr, tx_desc_get_length(desc), - MAX_FRAME_SIZE - (p - s->tx_packet)); + gem_get_max_buf_len(s, true) - (p - s->tx_packet)); + gem_set_isr(s, q, GEM_INT_AMBA_ERR); break; } @@ -1343,9 +1372,10 @@ static void gem_reset(DeviceState *d) s->regs[GEM_RXPARTIALSF] = 0x000003ff; s->regs[GEM_MODID] = s->revision; s->regs[GEM_DESCONF] = 0x02500111; - s->regs[GEM_DESCONF2] = 0x2ab13fff; + s->regs[GEM_DESCONF2] = 0x2ab10000 | s->jumbo_max_len; s->regs[GEM_DESCONF5] = 0x002f2045; s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK; + s->regs[GEM_JUMBO_MAX_LEN] = s->jumbo_max_len; if (s->num_priority_queues > 1) { queues_mask = MAKE_64BIT_MASK(1, s->num_priority_queues - 1); @@ -1516,6 +1546,9 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, s->regs[GEM_IMR] &= ~val; gem_update_int_status(s); break; + case GEM_JUMBO_MAX_LEN: + s->regs[GEM_JUMBO_MAX_LEN] = val & MAX_JUMBO_FRAME_SIZE_MASK; + break; case GEM_INT_Q1_ENABLE ... GEM_INT_Q7_ENABLE: s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_ENABLE] &= ~val; gem_update_int_status(s); @@ -1610,6 +1643,12 @@ static void gem_realize(DeviceState *dev, Error **errp) s->nic = qemu_new_nic(&net_gem_info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s); + + if (s->jumbo_max_len > MAX_FRAME_SIZE) { + error_setg(errp, "jumbo-max-len is greater than %d", + MAX_FRAME_SIZE); + return; + } } static void gem_init(Object *obj) @@ -1658,6 +1697,8 @@ static Property gem_properties[] = { num_type1_screeners, 4), DEFINE_PROP_UINT8("num-type2-screeners", CadenceGEMState, num_type2_screeners, 4), + DEFINE_PROP_UINT16("jumbo-max-len", CadenceGEMState, + jumbo_max_len, 10240), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h index eddac70f20..54e646ff79 100644 --- a/include/hw/net/cadence_gem.h +++ b/include/hw/net/cadence_gem.h @@ -40,7 +40,8 @@ #define MAX_TYPE1_SCREENERS 16 #define MAX_TYPE2_SCREENERS 16 -#define MAX_FRAME_SIZE 2048 +#define MAX_JUMBO_FRAME_SIZE_MASK 0x3FFF +#define MAX_FRAME_SIZE MAX_JUMBO_FRAME_SIZE_MASK typedef struct CadenceGEMState { /*< private >*/ @@ -59,6 +60,7 @@ typedef struct CadenceGEMState { uint8_t num_type1_screeners; uint8_t num_type2_screeners; uint32_t revision; + uint16_t jumbo_max_len; /* GEM registers backing store */ uint32_t regs[CADENCE_GEM_MAXREG]; From d48cb519b35010a90f18df915d187e566bf10c3e Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Tue, 12 May 2020 20:24:51 +0530 Subject: [PATCH 1425/2595] net: cadnece_gem: Update irq_read_clear field of designcfg_debug1 reg Advertise support of clear-on-read for ISR registers. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 8e927ada73..2211550d2b 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1371,7 +1371,7 @@ static void gem_reset(DeviceState *d) s->regs[GEM_TXPARTIALSF] = 0x000003ff; s->regs[GEM_RXPARTIALSF] = 0x000003ff; s->regs[GEM_MODID] = s->revision; - s->regs[GEM_DESCONF] = 0x02500111; + s->regs[GEM_DESCONF] = 0x02D00111; s->regs[GEM_DESCONF2] = 0x2ab10000 | s->jumbo_max_len; s->regs[GEM_DESCONF5] = 0x002f2045; s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK; From 15baf5e23743871820504be6afb1bae24d1211c2 Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Tue, 12 May 2020 20:24:52 +0530 Subject: [PATCH 1426/2595] net: cadence_gem: Update the reset value for interrupt mask register Mask all interrupt on reset. Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 2211550d2b..df6d8186ca 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1375,6 +1375,7 @@ static void gem_reset(DeviceState *d) s->regs[GEM_DESCONF2] = 0x2ab10000 | s->jumbo_max_len; s->regs[GEM_DESCONF5] = 0x002f2045; s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK; + s->regs[GEM_INT_Q1_MASK] = 0x00000CE6; s->regs[GEM_JUMBO_MAX_LEN] = s->jumbo_max_len; if (s->num_priority_queues > 1) { From fdd35195c5ed57162b080a20df588773768b589c Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Tue, 12 May 2020 20:24:53 +0530 Subject: [PATCH 1427/2595] net: cadence_gem: TX_LAST bit should be set by guest TX_LAST bit should not be set by hardware, its set by guest to inform the last bd of the frame. Signed-off-by: Sai Pavan Boddu Signed-off-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index df6d8186ca..78fb9acf96 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -350,11 +350,6 @@ static inline unsigned tx_desc_get_last(uint32_t *desc) return (desc[1] & DESC_1_TX_LAST) ? 1 : 0; } -static inline void tx_desc_set_last(uint32_t *desc) -{ - desc[1] |= DESC_1_TX_LAST; -} - static inline unsigned tx_desc_get_length(uint32_t *desc) { return desc[1] & DESC_1_LENGTH; @@ -1298,7 +1293,6 @@ static void gem_transmit(CadenceGEMState *s) /* read next descriptor */ if (tx_desc_get_wrap(desc)) { - tx_desc_set_last(desc); if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) { packet_desc_addr = s->regs[GEM_TBQPH]; From fbc14a098d945dfa9c141423771db0122defa38c Mon Sep 17 00:00:00 2001 From: Tong Ho Date: Tue, 12 May 2020 20:24:54 +0530 Subject: [PATCH 1428/2595] net: cadence_gem: Fix RX address filtering Two defects are fixed: 1/ Detection of multicast frames 2/ Treating drop of mis-addressed frames as non-error Signed-off-by: Tong Ho Signed-off-by: Edgar E. Iglesias Signed-off-by: Sai Pavan Boddu Reviewed-by: Edgar E. Iglesias Signed-off-by: Jason Wang --- hw/net/cadence_gem.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 78fb9acf96..a93b5c07ce 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -34,6 +34,7 @@ #include "qemu/module.h" #include "sysemu/dma.h" #include "net/checksum.h" +#include "net/eth.h" #define CADENCE_GEM_ERR_DEBUG 0 #define DB_PRINT(...) do {\ @@ -702,7 +703,7 @@ static unsigned calc_mac_hash(const uint8_t *mac) static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet) { uint8_t *gem_spaddr; - int i; + int i, is_mc; /* Promiscuous mode? */ if (s->regs[GEM_NWCFG] & GEM_NWCFG_PROMISC) { @@ -718,22 +719,17 @@ static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet) } /* Accept packets -w- hash match? */ - if ((packet[0] == 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_MCAST_HASH)) || - (packet[0] != 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_UCAST_HASH))) { + is_mc = is_multicast_ether_addr(packet); + if ((is_mc && (s->regs[GEM_NWCFG] & GEM_NWCFG_MCAST_HASH)) || + (!is_mc && (s->regs[GEM_NWCFG] & GEM_NWCFG_UCAST_HASH))) { + uint64_t buckets; unsigned hash_index; hash_index = calc_mac_hash(packet); - if (hash_index < 32) { - if (s->regs[GEM_HASHLO] & (1<regs[GEM_HASHHI] & (1<regs[GEM_HASHHI] << 32) | s->regs[GEM_HASHLO]; + if ((buckets >> hash_index) & 1) { + return is_mc ? GEM_RX_MULTICAST_HASH_ACCEPT + : GEM_RX_UNICAST_HASH_ACCEPT; } } @@ -958,7 +954,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) /* Is this destination MAC address "for us" ? */ maf = gem_mac_address_filter(s, buf); if (maf == GEM_RX_REJECT) { - return -1; + return size; /* no, drop siliently b/c it's not an error */ } /* Discard packets with receive length error enabled ? */ From 5fe19fb81839ea42b592b409f725349cf3c73551 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 11 May 2020 12:04:53 +0800 Subject: [PATCH 1429/2595] net: use peer when purging queue in qemu_flush_or_purge_queue_packets() The sender of packet will be checked in the qemu_net_queue_purge() but we use NetClientState not its peer when trying to purge the incoming queue in qemu_flush_or_purge_packets(). This will trigger the assert in virtio_net_reset since we can't pass the sender check: hw/net/virtio-net.c:533: void virtio_net_reset(VirtIODevice *): Assertion `!virtio_net_get_subqueue(nc)->async_tx.elem' failed. #9 0x55a33fa31b78 in virtio_net_reset hw/net/virtio-net.c:533:13 #10 0x55a33fc88412 in virtio_reset hw/virtio/virtio.c:1919:9 #11 0x55a341d82764 in virtio_bus_reset hw/virtio/virtio-bus.c:95:9 #12 0x55a341dba2de in virtio_pci_reset hw/virtio/virtio-pci.c:1824:5 #13 0x55a341db3e02 in virtio_pci_common_write hw/virtio/virtio-pci.c:1252:13 #14 0x55a33f62117b in memory_region_write_accessor memory.c:496:5 #15 0x55a33f6205e4 in access_with_adjusted_size memory.c:557:18 #16 0x55a33f61e177 in memory_region_dispatch_write memory.c:1488:16 Reproducer: https://www.mail-archive.com/qemu-devel@nongnu.org/msg701914.html Fix by using the peer. Reported-by: "Alexander Bulekov" Acked-by: Alexander Bulekov Fixes: ca77d85e1dbf9 ("net: complete all queued packets on VM stop") Cc: qemu-stable@nongnu.org Signed-off-by: Jason Wang --- net/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/net.c b/net/net.c index cbeeeadff8..4c62b10acd 100644 --- a/net/net.c +++ b/net/net.c @@ -610,7 +610,7 @@ void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge) qemu_notify_event(); } else if (purge) { /* Unable to empty the queue, purge remaining packets */ - qemu_net_queue_purge(nc->incoming_queue, nc); + qemu_net_queue_purge(nc->incoming_queue, nc->peer); } } From 5893c7383e6e16e3e6b24b0551501721f3309d9e Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Fri, 22 May 2020 15:53:51 +0800 Subject: [PATCH 1430/2595] net/colo-compare.c: Create event_bh with the right AioContext qemu_bh_new will set the bh to be executed in the main loop. This causes crashes as colo_compare_handle_event assumes that it has exclusive access the queues, which are also concurrently accessed in the iothread. Create the bh with the AioContext of the iothread to fulfill these assumptions and fix the crashes. This is safe, because the bh already takes the appropriate locks. Signed-off-by: Lukas Straub Reviewed-by: Zhang Chen Reviewed-by: Derek Su Tested-by: Derek Su Signed-off-by: Zhang Chen Signed-off-by: Jason Wang --- net/colo-compare.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/colo-compare.c b/net/colo-compare.c index c07e7c1c09..e557da70e5 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -890,6 +890,7 @@ static void colo_compare_handle_event(void *opaque) static void colo_compare_iothread(CompareState *s) { + AioContext *ctx = iothread_get_aio_context(s->iothread); object_ref(OBJECT(s->iothread)); s->worker_context = iothread_get_g_main_context(s->iothread); @@ -906,7 +907,7 @@ static void colo_compare_iothread(CompareState *s) } colo_compare_timer_init(s); - s->event_bh = qemu_bh_new(colo_compare_handle_event, s); + s->event_bh = aio_bh_new(ctx, colo_compare_handle_event, s); } static char *compare_get_pri_indev(Object *obj, Error **errp) From 2158fa1be7c1e76e2c25c32d75bb38e90cce0267 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Fri, 22 May 2020 15:53:52 +0800 Subject: [PATCH 1431/2595] chardev/char.c: Use qemu_co_sleep_ns if in coroutine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To be able to convert compare_chr_send to a coroutine in the next commit, use qemu_co_sleep_ns if in coroutine. Signed-off-by: Lukas Straub Reviewed-by: Marc-André Lureau Reviewed-by: Zhang Chen Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Zhang Chen Signed-off-by: Jason Wang --- chardev/char.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/chardev/char.c b/chardev/char.c index ea06c5ff4d..e3051295ac 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -38,6 +38,7 @@ #include "qemu/module.h" #include "qemu/option.h" #include "qemu/id.h" +#include "qemu/coroutine.h" #include "chardev/char-mux.h" @@ -119,7 +120,11 @@ static int qemu_chr_write_buffer(Chardev *s, retry: res = cc->chr_write(s, buf + *offset, len - *offset); if (res < 0 && errno == EAGAIN && write_all) { - g_usleep(100); + if (qemu_in_coroutine()) { + qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); + } else { + g_usleep(100); + } goto retry; } From 9c55fe94081dd15148428d32e60fd75ec2eb37ec Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Fri, 22 May 2020 15:53:53 +0800 Subject: [PATCH 1432/2595] net/colo-compare.c: Fix deadlock in compare_chr_send The chr_out chardev is connected to a filter-redirector running in the main loop. qemu_chr_fe_write_all might block here in compare_chr_send if the (socket-)buffer is full. If another filter-redirector in the main loop want's to send data to chr_pri_in it might also block if the buffer is full. This leads to a deadlock because both event loops get blocked. Fix this by converting compare_chr_send to a coroutine and putting the packets in a send queue. Signed-off-by: Lukas Straub Reviewed-by: Zhang Chen Tested-by: Zhang Chen Signed-off-by: Zhang Chen Signed-off-by: Jason Wang --- net/colo-compare.c | 205 ++++++++++++++++++++++++++++++++++----------- net/colo.c | 7 ++ net/colo.h | 1 + 3 files changed, 162 insertions(+), 51 deletions(-) diff --git a/net/colo-compare.c b/net/colo-compare.c index e557da70e5..62ecd38bb7 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -32,6 +32,9 @@ #include "migration/migration.h" #include "util.h" +#include "block/aio-wait.h" +#include "qemu/coroutine.h" + #define TYPE_COLO_COMPARE "colo-compare" #define COLO_COMPARE(obj) \ OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE) @@ -77,6 +80,23 @@ static int event_unhandled_count; * |packet | |packet + |packet | |packet + * +--------+ +--------+ +--------+ +--------+ */ + +typedef struct SendCo { + Coroutine *co; + struct CompareState *s; + CharBackend *chr; + GQueue send_list; + bool notify_remote_frame; + bool done; + int ret; +} SendCo; + +typedef struct SendEntry { + uint32_t size; + uint32_t vnet_hdr_len; + uint8_t *buf; +} SendEntry; + typedef struct CompareState { Object parent; @@ -91,6 +111,8 @@ typedef struct CompareState { SocketReadState pri_rs; SocketReadState sec_rs; SocketReadState notify_rs; + SendCo out_sendco; + SendCo notify_sendco; bool vnet_hdr; uint32_t compare_timeout; uint32_t expired_scan_cycle; @@ -124,10 +146,11 @@ enum { static int compare_chr_send(CompareState *s, - const uint8_t *buf, + uint8_t *buf, uint32_t size, uint32_t vnet_hdr_len, - bool notify_remote_frame); + bool notify_remote_frame, + bool zero_copy); static bool packet_matches_str(const char *str, const uint8_t *buf, @@ -145,7 +168,7 @@ static void notify_remote_frame(CompareState *s) char msg[] = "DO_CHECKPOINT"; int ret = 0; - ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true); + ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true, false); if (ret < 0) { error_report("Notify Xen COLO-frame failed"); } @@ -272,12 +295,13 @@ static void colo_release_primary_pkt(CompareState *s, Packet *pkt) pkt->data, pkt->size, pkt->vnet_hdr_len, - false); + false, + true); if (ret < 0) { error_report("colo send primary packet failed"); } trace_colo_compare_main("packet same and release packet"); - packet_destroy(pkt, NULL); + packet_destroy_partial(pkt, NULL); } /* @@ -699,65 +723,115 @@ static void colo_compare_connection(void *opaque, void *user_data) } } +static void coroutine_fn _compare_chr_send(void *opaque) +{ + SendCo *sendco = opaque; + CompareState *s = sendco->s; + int ret = 0; + + while (!g_queue_is_empty(&sendco->send_list)) { + SendEntry *entry = g_queue_pop_tail(&sendco->send_list); + uint32_t len = htonl(entry->size); + + ret = qemu_chr_fe_write_all(sendco->chr, (uint8_t *)&len, sizeof(len)); + + if (ret != sizeof(len)) { + g_free(entry->buf); + g_slice_free(SendEntry, entry); + goto err; + } + + if (!sendco->notify_remote_frame && s->vnet_hdr) { + /* + * We send vnet header len make other module(like filter-redirector) + * know how to parse net packet correctly. + */ + len = htonl(entry->vnet_hdr_len); + + ret = qemu_chr_fe_write_all(sendco->chr, + (uint8_t *)&len, + sizeof(len)); + + if (ret != sizeof(len)) { + g_free(entry->buf); + g_slice_free(SendEntry, entry); + goto err; + } + } + + ret = qemu_chr_fe_write_all(sendco->chr, + (uint8_t *)entry->buf, + entry->size); + + if (ret != entry->size) { + g_free(entry->buf); + g_slice_free(SendEntry, entry); + goto err; + } + + g_free(entry->buf); + g_slice_free(SendEntry, entry); + } + + sendco->ret = 0; + goto out; + +err: + while (!g_queue_is_empty(&sendco->send_list)) { + SendEntry *entry = g_queue_pop_tail(&sendco->send_list); + g_free(entry->buf); + g_slice_free(SendEntry, entry); + } + sendco->ret = ret < 0 ? ret : -EIO; +out: + sendco->co = NULL; + sendco->done = true; + aio_wait_kick(); +} + static int compare_chr_send(CompareState *s, - const uint8_t *buf, + uint8_t *buf, uint32_t size, uint32_t vnet_hdr_len, - bool notify_remote_frame) + bool notify_remote_frame, + bool zero_copy) { - int ret = 0; - uint32_t len = htonl(size); + SendCo *sendco; + SendEntry *entry; + + if (notify_remote_frame) { + sendco = &s->notify_sendco; + } else { + sendco = &s->out_sendco; + } if (!size) { return 0; } - if (notify_remote_frame) { - ret = qemu_chr_fe_write_all(&s->chr_notify_dev, - (uint8_t *)&len, - sizeof(len)); + entry = g_slice_new(SendEntry); + entry->size = size; + entry->vnet_hdr_len = vnet_hdr_len; + if (zero_copy) { + entry->buf = buf; } else { - ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len)); + entry->buf = g_malloc(size); + memcpy(entry->buf, buf, size); } + g_queue_push_head(&sendco->send_list, entry); - if (ret != sizeof(len)) { - goto err; - } - - if (s->vnet_hdr) { - /* - * We send vnet header len make other module(like filter-redirector) - * know how to parse net packet correctly. - */ - len = htonl(vnet_hdr_len); - - if (!notify_remote_frame) { - ret = qemu_chr_fe_write_all(&s->chr_out, - (uint8_t *)&len, - sizeof(len)); - } - - if (ret != sizeof(len)) { - goto err; + if (sendco->done) { + sendco->co = qemu_coroutine_create(_compare_chr_send, sendco); + sendco->done = false; + qemu_coroutine_enter(sendco->co); + if (sendco->done) { + /* report early errors */ + return sendco->ret; } } - if (notify_remote_frame) { - ret = qemu_chr_fe_write_all(&s->chr_notify_dev, - (uint8_t *)buf, - size); - } else { - ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size); - } - - if (ret != size) { - goto err; - } - + /* assume success */ return 0; - -err: - return ret < 0 ? ret : -EIO; } static int compare_chr_can_read(void *opaque) @@ -1063,6 +1137,7 @@ static void compare_pri_rs_finalize(SocketReadState *pri_rs) pri_rs->buf, pri_rs->packet_len, pri_rs->vnet_hdr_len, + false, false); } else { /* compare packet in the specified connection */ @@ -1093,7 +1168,7 @@ static void compare_notify_rs_finalize(SocketReadState *notify_rs) if (packet_matches_str("COLO_USERSPACE_PROXY_INIT", notify_rs->buf, notify_rs->packet_len)) { - ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true); + ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true, false); if (ret < 0) { error_report("Notify Xen COLO-frame INIT failed"); } @@ -1199,6 +1274,20 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) QTAILQ_INSERT_TAIL(&net_compares, s, next); + s->out_sendco.s = s; + s->out_sendco.chr = &s->chr_out; + s->out_sendco.notify_remote_frame = false; + s->out_sendco.done = true; + g_queue_init(&s->out_sendco.send_list); + + if (s->notify_dev) { + s->notify_sendco.s = s; + s->notify_sendco.chr = &s->chr_notify_dev; + s->notify_sendco.notify_remote_frame = true; + s->notify_sendco.done = true; + g_queue_init(&s->notify_sendco.send_list); + } + g_queue_init(&s->conn_list); qemu_mutex_init(&event_mtx); @@ -1225,8 +1314,9 @@ static void colo_flush_packets(void *opaque, void *user_data) pkt->data, pkt->size, pkt->vnet_hdr_len, - false); - packet_destroy(pkt, NULL); + false, + true); + packet_destroy_partial(pkt, NULL); } while (!g_queue_is_empty(&conn->secondary_list)) { pkt = g_queue_pop_head(&conn->secondary_list); @@ -1297,10 +1387,23 @@ static void colo_compare_finalize(Object *obj) } } + AioContext *ctx = iothread_get_aio_context(s->iothread); + aio_context_acquire(ctx); + AIO_WAIT_WHILE(ctx, !s->out_sendco.done); + if (s->notify_dev) { + AIO_WAIT_WHILE(ctx, !s->notify_sendco.done); + } + aio_context_release(ctx); + /* Release all unhandled packets after compare thead exited */ g_queue_foreach(&s->conn_list, colo_flush_packets, s); + AIO_WAIT_WHILE(NULL, !s->out_sendco.done); g_queue_clear(&s->conn_list); + g_queue_clear(&s->out_sendco.send_list); + if (s->notify_dev) { + g_queue_clear(&s->notify_sendco.send_list); + } if (s->connection_track_table) { g_hash_table_destroy(s->connection_track_table); diff --git a/net/colo.c b/net/colo.c index 8196b35837..a6c66d829a 100644 --- a/net/colo.c +++ b/net/colo.c @@ -185,6 +185,13 @@ void packet_destroy(void *opaque, void *user_data) g_slice_free(Packet, pkt); } +void packet_destroy_partial(void *opaque, void *user_data) +{ + Packet *pkt = opaque; + + g_slice_free(Packet, pkt); +} + /* * Clear hashtable, stop this hash growing really huge */ diff --git a/net/colo.h b/net/colo.h index 679314b1ca..573ab91785 100644 --- a/net/colo.h +++ b/net/colo.h @@ -102,5 +102,6 @@ bool connection_has_tracked(GHashTable *connection_track_table, void connection_hashtable_reset(GHashTable *connection_track_table); Packet *packet_new(const void *data, int size, int vnet_hdr_len); void packet_destroy(void *opaque, void *user_data); +void packet_destroy_partial(void *opaque, void *user_data); #endif /* NET_COLO_H */ From 76658541f3950e580ae3be8019f1b4c019a8a638 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Fri, 22 May 2020 15:53:54 +0800 Subject: [PATCH 1433/2595] net/colo-compare.c: Only hexdump packets if tracing is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Else the log will be flooded if there is a lot of network traffic. Signed-off-by: Lukas Straub Reviewed-by: Zhang Chen Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Zhang Chen Signed-off-by: Jason Wang --- net/colo-compare.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/colo-compare.c b/net/colo-compare.c index 62ecd38bb7..a609f499b9 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -483,10 +483,12 @@ sec: g_queue_push_head(&conn->primary_list, ppkt); g_queue_push_head(&conn->secondary_list, spkt); - qemu_hexdump((char *)ppkt->data, stderr, - "colo-compare ppkt", ppkt->size); - qemu_hexdump((char *)spkt->data, stderr, - "colo-compare spkt", spkt->size); + if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) { + qemu_hexdump((char *)ppkt->data, stderr, + "colo-compare ppkt", ppkt->size); + qemu_hexdump((char *)spkt->data, stderr, + "colo-compare spkt", spkt->size); + } colo_compare_inconsistency_notify(s); } From 45942b79b9f89b42a5f5ccfa861c36a86a95d89a Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Fri, 22 May 2020 15:53:55 +0800 Subject: [PATCH 1434/2595] net/colo-compare.c: Check that colo-compare is active If the colo-compare object is removed before failover and a checkpoint happens, qemu crashes because it tries to lock the destroyed event_mtx in colo_notify_compares_event. Fix this by checking if everything is initialized by introducing a new variable colo_compare_active which is protected by a new mutex colo_compare_mutex. The new mutex also protects against concurrent access of the net_compares list and makes sure that colo_notify_compares_event isn't active while we destroy event_mtx and event_complete_cond. With this it also is again possible to use colo without colo-compare (periodic mode) and to use multiple colo-compare for multiple network interfaces. Signed-off-by: Lukas Straub Tested-by: Lukas Straub Reviewed-by: Zhang Chen Signed-off-by: Zhang Chen Signed-off-by: Jason Wang --- net/colo-compare.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/net/colo-compare.c b/net/colo-compare.c index a609f499b9..c30dbfb6e6 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -54,6 +54,8 @@ static NotifierList colo_compare_notifiers = #define REGULAR_PACKET_CHECK_MS 3000 #define DEFAULT_TIME_OUT_MS 3000 +static QemuMutex colo_compare_mutex; +static bool colo_compare_active; static QemuMutex event_mtx; static QemuCond event_complete_cond; static int event_unhandled_count; @@ -906,6 +908,12 @@ static void check_old_packet_regular(void *opaque) void colo_notify_compares_event(void *opaque, int event, Error **errp) { CompareState *s; + qemu_mutex_lock(&colo_compare_mutex); + + if (!colo_compare_active) { + qemu_mutex_unlock(&colo_compare_mutex); + return; + } qemu_mutex_lock(&event_mtx); QTAILQ_FOREACH(s, &net_compares, next) { @@ -919,6 +927,7 @@ void colo_notify_compares_event(void *opaque, int event, Error **errp) } qemu_mutex_unlock(&event_mtx); + qemu_mutex_unlock(&colo_compare_mutex); } static void colo_compare_timer_init(CompareState *s) @@ -1274,7 +1283,14 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) s->vnet_hdr); } + qemu_mutex_lock(&colo_compare_mutex); + if (!colo_compare_active) { + qemu_mutex_init(&event_mtx); + qemu_cond_init(&event_complete_cond); + colo_compare_active = true; + } QTAILQ_INSERT_TAIL(&net_compares, s, next); + qemu_mutex_unlock(&colo_compare_mutex); s->out_sendco.s = s; s->out_sendco.chr = &s->chr_out; @@ -1292,9 +1308,6 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) g_queue_init(&s->conn_list); - qemu_mutex_init(&event_mtx); - qemu_cond_init(&event_complete_cond); - s->connection_track_table = g_hash_table_new_full(connection_key_hash, connection_key_equal, g_free, @@ -1382,12 +1395,19 @@ static void colo_compare_finalize(Object *obj) qemu_bh_delete(s->event_bh); + qemu_mutex_lock(&colo_compare_mutex); QTAILQ_FOREACH(tmp, &net_compares, next) { if (tmp == s) { QTAILQ_REMOVE(&net_compares, s, next); break; } } + if (QTAILQ_EMPTY(&net_compares)) { + colo_compare_active = false; + qemu_mutex_destroy(&event_mtx); + qemu_cond_destroy(&event_complete_cond); + } + qemu_mutex_unlock(&colo_compare_mutex); AioContext *ctx = iothread_get_aio_context(s->iothread); aio_context_acquire(ctx); @@ -1415,15 +1435,18 @@ static void colo_compare_finalize(Object *obj) object_unref(OBJECT(s->iothread)); } - qemu_mutex_destroy(&event_mtx); - qemu_cond_destroy(&event_complete_cond); - g_free(s->pri_indev); g_free(s->sec_indev); g_free(s->outdev); g_free(s->notify_dev); } +static void __attribute__((__constructor__)) colo_compare_init_globals(void) +{ + colo_compare_active = false; + qemu_mutex_init(&colo_compare_mutex); +} + static const TypeInfo colo_compare_info = { .name = TYPE_COLO_COMPARE, .parent = TYPE_OBJECT, From 5bd57eba041fb62c373f89c311936000c115fdd6 Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Fri, 22 May 2020 15:53:56 +0800 Subject: [PATCH 1435/2595] net/colo-compare.c: Correct ordering in complete and finalize In colo_compare_complete, insert CompareState into net_compares only after everything has been initialized. In colo_compare_finalize, remove CompareState from net_compares before anything is deinitialized. Signed-off-by: Lukas Straub Reviewed-by: Zhang Chen Signed-off-by: Zhang Chen Signed-off-by: Jason Wang --- net/colo-compare.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/net/colo-compare.c b/net/colo-compare.c index c30dbfb6e6..ed1f3d0af0 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -1283,15 +1283,6 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) s->vnet_hdr); } - qemu_mutex_lock(&colo_compare_mutex); - if (!colo_compare_active) { - qemu_mutex_init(&event_mtx); - qemu_cond_init(&event_complete_cond); - colo_compare_active = true; - } - QTAILQ_INSERT_TAIL(&net_compares, s, next); - qemu_mutex_unlock(&colo_compare_mutex); - s->out_sendco.s = s; s->out_sendco.chr = &s->chr_out; s->out_sendco.notify_remote_frame = false; @@ -1314,6 +1305,16 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) connection_destroy); colo_compare_iothread(s); + + qemu_mutex_lock(&colo_compare_mutex); + if (!colo_compare_active) { + qemu_mutex_init(&event_mtx); + qemu_cond_init(&event_complete_cond); + colo_compare_active = true; + } + QTAILQ_INSERT_TAIL(&net_compares, s, next); + qemu_mutex_unlock(&colo_compare_mutex); + return; } @@ -1382,19 +1383,6 @@ static void colo_compare_finalize(Object *obj) CompareState *s = COLO_COMPARE(obj); CompareState *tmp = NULL; - qemu_chr_fe_deinit(&s->chr_pri_in, false); - qemu_chr_fe_deinit(&s->chr_sec_in, false); - qemu_chr_fe_deinit(&s->chr_out, false); - if (s->notify_dev) { - qemu_chr_fe_deinit(&s->chr_notify_dev, false); - } - - if (s->iothread) { - colo_compare_timer_del(s); - } - - qemu_bh_delete(s->event_bh); - qemu_mutex_lock(&colo_compare_mutex); QTAILQ_FOREACH(tmp, &net_compares, next) { if (tmp == s) { @@ -1409,6 +1397,19 @@ static void colo_compare_finalize(Object *obj) } qemu_mutex_unlock(&colo_compare_mutex); + qemu_chr_fe_deinit(&s->chr_pri_in, false); + qemu_chr_fe_deinit(&s->chr_sec_in, false); + qemu_chr_fe_deinit(&s->chr_out, false); + if (s->notify_dev) { + qemu_chr_fe_deinit(&s->chr_notify_dev, false); + } + + if (s->iothread) { + colo_compare_timer_del(s); + } + + qemu_bh_delete(s->event_bh); + AioContext *ctx = iothread_get_aio_context(s->iothread); aio_context_acquire(ctx); AIO_WAIT_WHILE(ctx, !s->out_sendco.done); From bdadbb0f74305d1509805936bf9b1ac14eab30e4 Mon Sep 17 00:00:00 2001 From: Derek Su Date: Fri, 22 May 2020 15:53:57 +0800 Subject: [PATCH 1436/2595] colo-compare: Fix memory leak in packet_enqueue() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patch is to fix the "pkt" memory leak in packet_enqueue(). The allocated "pkt" needs to be freed if the colo compare primary or secondary queue is too big. Replace the error_report of full queue with a trace event. Signed-off-by: Derek Su Reviewed-by: Zhang Chen Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Zhang Chen Signed-off-by: Jason Wang --- net/colo-compare.c | 23 +++++++++++++++-------- net/trace-events | 1 + 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/net/colo-compare.c b/net/colo-compare.c index ed1f3d0af0..f15779dedc 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -146,6 +146,10 @@ enum { SECONDARY_IN, }; +static const char *colo_mode[] = { + [PRIMARY_IN] = "primary", + [SECONDARY_IN] = "secondary", +}; static int compare_chr_send(CompareState *s, uint8_t *buf, @@ -242,6 +246,7 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con) ConnectionKey key; Packet *pkt = NULL; Connection *conn; + int ret; if (mode == PRIMARY_IN) { pkt = packet_new(s->pri_rs.buf, @@ -270,16 +275,18 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con) } if (mode == PRIMARY_IN) { - if (!colo_insert_packet(&conn->primary_list, pkt, &conn->pack)) { - error_report("colo compare primary queue size too big," - "drop packet"); - } + ret = colo_insert_packet(&conn->primary_list, pkt, &conn->pack); } else { - if (!colo_insert_packet(&conn->secondary_list, pkt, &conn->sack)) { - error_report("colo compare secondary queue size too big," - "drop packet"); - } + ret = colo_insert_packet(&conn->secondary_list, pkt, &conn->sack); } + + if (!ret) { + trace_colo_compare_drop_packet(colo_mode[mode], + "queue size too big, drop packet"); + packet_destroy(pkt, NULL); + pkt = NULL; + } + *con = conn; return 0; diff --git a/net/trace-events b/net/trace-events index 02c13fd0ba..fa49c71533 100644 --- a/net/trace-events +++ b/net/trace-events @@ -12,6 +12,7 @@ colo_proxy_main(const char *chr) ": %s" # colo-compare.c colo_compare_main(const char *chr) ": %s" +colo_compare_drop_packet(const char *queue, const char *chr) ": %s: %s" colo_compare_udp_miscompare(const char *sta, int size) ": %s = %d" colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d" colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s" From fda43b1204aecd1db158b3255c591d227fbdd629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 25 May 2020 14:23:30 +0200 Subject: [PATCH 1437/2595] hw/net/e1000e: Do not abort() on invalid PSRCTL register value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libFuzzer found using 'qemu-system-i386 -M q35': qemu: hardware error: e1000e: PSRCTL.BSIZE0 cannot be zero CPU #0: EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000663 ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000 EIP=0000fff0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0 ES =0000 00000000 0000ffff 00009300 CS =f000 ffff0000 0000ffff 00009b00 SS =0000 00000000 0000ffff 00009300 DS =0000 00000000 0000ffff 00009300 FS =0000 00000000 0000ffff 00009300 GS =0000 00000000 0000ffff 00009300 LDT=0000 00000000 0000ffff 00008200 TR =0000 00000000 0000ffff 00008b00 GDT= 00000000 0000ffff IDT= 00000000 0000ffff CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000 DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 DR6=ffff0ff0 DR7=00000400 EFER=0000000000000000 FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80 FPR0=0000000000000000 0000 FPR1=0000000000000000 0000 FPR2=0000000000000000 0000 FPR3=0000000000000000 0000 FPR4=0000000000000000 0000 FPR5=0000000000000000 0000 FPR6=0000000000000000 0000 FPR7=0000000000000000 0000 XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000 XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000 XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000 XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000 ==1988== ERROR: libFuzzer: deadly signal #6 0x7fae4d3ea894 in __GI_abort (/lib64/libc.so.6+0x22894) #7 0x563f4cc59a1d in hw_error (qemu-fuzz-i386+0xe8ca1d) #8 0x563f4d7c93f2 in e1000e_set_psrctl (qemu-fuzz-i386+0x19fc3f2) #9 0x563f4d7b798f in e1000e_core_write (qemu-fuzz-i386+0x19ea98f) #10 0x563f4d7afc46 in e1000e_mmio_write (qemu-fuzz-i386+0x19e2c46) #11 0x563f4cc9a0a7 in memory_region_write_accessor (qemu-fuzz-i386+0xecd0a7) #12 0x563f4cc99c13 in access_with_adjusted_size (qemu-fuzz-i386+0xeccc13) #13 0x563f4cc987b4 in memory_region_dispatch_write (qemu-fuzz-i386+0xecb7b4) It simply sent the following 2 I/O command to the e1000e PCI BAR #2 I/O region: writew 0x0100 0x0c00 # RCTL = E1000_RCTL_DTYP_MASK writeb 0x2170 0x00 # PSRCTL = 0 2813 static void 2814 e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val) 2815 { 2816 if (core->mac[RCTL] & E1000_RCTL_DTYP_MASK) { 2817 2818 if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) { 2819 hw_error("e1000e: PSRCTL.BSIZE0 cannot be zero"); 2820 } Instead of calling hw_error() which abort the process (it is meant for CPU fatal error condition, not for device logging), log the invalid request with qemu_log_mask(LOG_GUEST_ERROR) and return, ignoring the request. Cc: qemu-stable@nongnu.org Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/e1000e_core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index d5676871fa..bcd186cac5 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -34,9 +34,9 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "net/net.h" #include "net/tap.h" -#include "hw/hw.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" #include "sysemu/runstate.h" @@ -2816,11 +2816,15 @@ e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val) if (core->mac[RCTL] & E1000_RCTL_DTYP_MASK) { if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) { - hw_error("e1000e: PSRCTL.BSIZE0 cannot be zero"); + qemu_log_mask(LOG_GUEST_ERROR, + "e1000e: PSRCTL.BSIZE0 cannot be zero"); + return; } if ((val & E1000_PSRCTL_BSIZE1_MASK) == 0) { - hw_error("e1000e: PSRCTL.BSIZE1 cannot be zero"); + qemu_log_mask(LOG_GUEST_ERROR, + "e1000e: PSRCTL.BSIZE1 cannot be zero"); + return; } } From 9d903f30cb37eb2f7aec53ab58cd869f48ec16d5 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 18 May 2020 20:01:02 +0200 Subject: [PATCH 1438/2595] net: Drop the legacy "name" parameter from the -net option It's been deprecated since QEMU v3.1, so it's time to finally remove it. The "id" parameter can simply be used instead. Reviewed-by: Eric Blake Signed-off-by: Thomas Huth Signed-off-by: Jason Wang --- docs/system/deprecated.rst | 15 +++++++++------ net/net.c | 10 +--------- qapi/net.json | 3 --- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 544ece0a45..3a255591c3 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -47,12 +47,6 @@ The 'file' driver for drives is no longer appropriate for character or host devices and will only accept regular files (S_IFREG). The correct driver for these file types is 'host_cdrom' or 'host_device' as appropriate. -``-net ...,name=``\ *name* (since 3.1) -'''''''''''''''''''''''''''''''''''''' - -The ``name`` parameter of the ``-net`` option is a synonym -for the ``id`` parameter, which should now be used instead. - ``-smp`` (invalid topologies) (since 3.1) ''''''''''''''''''''''''''''''''''''''''' @@ -441,6 +435,15 @@ What follows is a record of recently removed, formerly deprecated features that serves as a record for users who have encountered trouble after a recent upgrade. +System emulator command line arguments +-------------------------------------- + +``-net ...,name=``\ *name* (removed in 5.1) +''''''''''''''''''''''''''''''''''''''''''' + +The ``name`` parameter of the ``-net`` option was a synonym +for the ``id`` parameter, which should now be used instead. + QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/net/net.c b/net/net.c index 4c62b10acd..e55d3572a4 100644 --- a/net/net.c +++ b/net/net.c @@ -969,12 +969,10 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp) { Netdev legacy = {0}; const Netdev *netdev; - const char *name; NetClientState *peer = NULL; if (is_netdev) { netdev = object; - name = netdev->id; if (netdev->type == NET_CLIENT_DRIVER_NIC || !net_client_init_fun[netdev->type]) { @@ -987,12 +985,6 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp) const NetLegacyOptions *opts = net->opts; legacy.id = net->id; netdev = &legacy; - /* missing optional values have been initialized to "all bits zero" */ - name = net->has_id ? net->id : net->name; - - if (net->has_name) { - warn_report("The 'name' parameter is deprecated, use 'id' instead"); - } /* Map the old options to the new flat type */ switch (opts->type) { @@ -1052,7 +1044,7 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp) } } - if (net_client_init_fun[netdev->type](netdev, name, peer, errp) < 0) { + if (net_client_init_fun[netdev->type](netdev, netdev->id, peer, errp) < 0) { /* FIXME drop when all init functions store an Error */ if (errp && !*errp) { error_setg(errp, QERR_DEVICE_INIT_FAILED, diff --git a/qapi/net.json b/qapi/net.json index cebb1b52e3..fc7c95f6d8 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -474,8 +474,6 @@ # # @id: identifier for monitor commands # -# @name: identifier for monitor commands, ignored if @id is present -# # @opts: device type specific properties (legacy) # # Since: 1.2 @@ -483,7 +481,6 @@ { 'struct': 'NetLegacy', 'data': { '*id': 'str', - '*name': 'str', 'opts': 'NetLegacyOptions' } } ## From 71830d8430e65dd20aec4765d87e60336148e1a6 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 18 May 2020 20:01:03 +0200 Subject: [PATCH 1439/2595] net: Drop the NetLegacy structure, always use Netdev instead Now that the "name" parameter is gone, there is hardly any difference between NetLegacy and Netdev anymore, so we can drop NetLegacy and always use Netdev to simplify the code quite a bit. The only two differences that were really left between Netdev and NetLegacy: 1) NetLegacy does not allow a "hubport" type. We can continue to block this with a simple check in net_client_init1() for this type. 2) The "id" parameter was optional in NetLegacy (and an internal id was chosen via assign_name() during initialization), but it is mandatory for Netdev. To avoid that the visitor code bails out here, we have to add an internal id to the QemuOpts already earlier now. Signed-off-by: Thomas Huth Reviewed-by: Eric Blake Signed-off-by: Jason Wang --- net/net.c | 77 +++++++++------------------------------------------ qapi/net.json | 46 ------------------------------ 2 files changed, 13 insertions(+), 110 deletions(-) diff --git a/net/net.c b/net/net.c index e55d3572a4..d1130296e1 100644 --- a/net/net.c +++ b/net/net.c @@ -965,15 +965,11 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( }; -static int net_client_init1(const void *object, bool is_netdev, Error **errp) +static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp) { - Netdev legacy = {0}; - const Netdev *netdev; NetClientState *peer = NULL; if (is_netdev) { - netdev = object; - if (netdev->type == NET_CLIENT_DRIVER_NIC || !net_client_init_fun[netdev->type]) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", @@ -981,56 +977,11 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp) return -1; } } else { - const NetLegacy *net = object; - const NetLegacyOptions *opts = net->opts; - legacy.id = net->id; - netdev = &legacy; - - /* Map the old options to the new flat type */ - switch (opts->type) { - case NET_LEGACY_OPTIONS_TYPE_NONE: + if (netdev->type == NET_CLIENT_DRIVER_NONE) { return 0; /* nothing to do */ - case NET_LEGACY_OPTIONS_TYPE_NIC: - legacy.type = NET_CLIENT_DRIVER_NIC; - legacy.u.nic = opts->u.nic; - break; - case NET_LEGACY_OPTIONS_TYPE_USER: - legacy.type = NET_CLIENT_DRIVER_USER; - legacy.u.user = opts->u.user; - break; - case NET_LEGACY_OPTIONS_TYPE_TAP: - legacy.type = NET_CLIENT_DRIVER_TAP; - legacy.u.tap = opts->u.tap; - break; - case NET_LEGACY_OPTIONS_TYPE_L2TPV3: - legacy.type = NET_CLIENT_DRIVER_L2TPV3; - legacy.u.l2tpv3 = opts->u.l2tpv3; - break; - case NET_LEGACY_OPTIONS_TYPE_SOCKET: - legacy.type = NET_CLIENT_DRIVER_SOCKET; - legacy.u.socket = opts->u.socket; - break; - case NET_LEGACY_OPTIONS_TYPE_VDE: - legacy.type = NET_CLIENT_DRIVER_VDE; - legacy.u.vde = opts->u.vde; - break; - case NET_LEGACY_OPTIONS_TYPE_BRIDGE: - legacy.type = NET_CLIENT_DRIVER_BRIDGE; - legacy.u.bridge = opts->u.bridge; - break; - case NET_LEGACY_OPTIONS_TYPE_NETMAP: - legacy.type = NET_CLIENT_DRIVER_NETMAP; - legacy.u.netmap = opts->u.netmap; - break; - case NET_LEGACY_OPTIONS_TYPE_VHOST_USER: - legacy.type = NET_CLIENT_DRIVER_VHOST_USER; - legacy.u.vhost_user = opts->u.vhost_user; - break; - default: - abort(); } - - if (!net_client_init_fun[netdev->type]) { + if (netdev->type == NET_CLIENT_DRIVER_HUBPORT || + !net_client_init_fun[netdev->type]) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", "a net backend type (maybe it is not compiled " "into this binary)"); @@ -1039,7 +990,7 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp) /* Do not add to a hub if it's a nic with a netdev= parameter. */ if (netdev->type != NET_CLIENT_DRIVER_NIC || - !opts->u.nic.has_netdev) { + !netdev->u.nic.has_netdev) { peer = net_hub_add_port(0, NULL, NULL); } } @@ -1100,7 +1051,7 @@ static void show_netdevs(void) static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) { gchar **substrings = NULL; - void *object = NULL; + Netdev *object = NULL; Error *err = NULL; int ret = -1; Visitor *v = opts_visitor_new(opts); @@ -1143,21 +1094,19 @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) } } - if (is_netdev) { - visit_type_Netdev(v, NULL, (Netdev **)&object, &err); - } else { - visit_type_NetLegacy(v, NULL, (NetLegacy **)&object, &err); + /* Create an ID for -net if the user did not specify one */ + if (!is_netdev && !qemu_opts_id(opts)) { + static int idx; + qemu_opts_set_id(opts, g_strdup_printf("__org.qemu.net%i", idx++)); } + visit_type_Netdev(v, NULL, &object, &err); + if (!err) { ret = net_client_init1(object, is_netdev, &err); } - if (is_netdev) { - qapi_free_Netdev(object); - } else { - qapi_free_NetLegacy(object); - } + qapi_free_Netdev(object); out: error_propagate(errp, err); diff --git a/qapi/net.json b/qapi/net.json index fc7c95f6d8..9244c9af56 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -467,52 +467,6 @@ 'netmap': 'NetdevNetmapOptions', 'vhost-user': 'NetdevVhostUserOptions' } } -## -# @NetLegacy: -# -# Captures the configuration of a network device; legacy. -# -# @id: identifier for monitor commands -# -# @opts: device type specific properties (legacy) -# -# Since: 1.2 -## -{ 'struct': 'NetLegacy', - 'data': { - '*id': 'str', - 'opts': 'NetLegacyOptions' } } - -## -# @NetLegacyOptionsType: -# -# Since: 1.2 -## -{ 'enum': 'NetLegacyOptionsType', - 'data': ['none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde', - 'bridge', 'netmap', 'vhost-user'] } - -## -# @NetLegacyOptions: -# -# Like Netdev, but for use only by the legacy command line options -# -# Since: 1.2 -## -{ 'union': 'NetLegacyOptions', - 'base': { 'type': 'NetLegacyOptionsType' }, - 'discriminator': 'type', - 'data': { - 'nic': 'NetLegacyNicOptions', - 'user': 'NetdevUserOptions', - 'tap': 'NetdevTapOptions', - 'l2tpv3': 'NetdevL2TPv3Options', - 'socket': 'NetdevSocketOptions', - 'vde': 'NetdevVdeOptions', - 'bridge': 'NetdevBridgeOptions', - 'netmap': 'NetdevNetmapOptions', - 'vhost-user': 'NetdevVhostUserOptions' } } - ## # @NetFilterDirection: # From 586803455b3fa44d949ecd42cd9c87e5a6287aef Mon Sep 17 00:00:00 2001 From: Allan Peramaki Date: Thu, 18 Jun 2020 12:36:23 +0200 Subject: [PATCH 1440/2595] hw/audio/gus: Fix registers 32-bit access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix audio on software that accesses DRAM above 64k via register peek/poke and some cases when more than 16 voices are used. Cc: qemu-stable@nongnu.org Fixes: 135f5ae1974c ("audio: GUSsample is int16_t") Signed-off-by: Allan Peramaki Tested-by: Volker Rümelin Reviewed-by: Volker Rümelin Reviewed-by: Thomas Huth Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200618103623.6031-1-philmd@redhat.com Message-Id: <20200615201757.16868-1-aperamak@pp1.inet.fi> [PMD: Removed unrelated style changes] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Gerd Hoffmann --- hw/audio/gusemu_hal.c | 2 +- hw/audio/gusemu_mixer.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/audio/gusemu_hal.c b/hw/audio/gusemu_hal.c index ae40ca341c..5b9a14ee21 100644 --- a/hw/audio/gusemu_hal.c +++ b/hw/audio/gusemu_hal.c @@ -32,7 +32,7 @@ #define GUSregb(position) (* (gusptr+(position))) #define GUSregw(position) (*(uint16_t *) (gusptr+(position))) -#define GUSregd(position) (*(uint16_t *)(gusptr+(position))) +#define GUSregd(position) (*(uint32_t *)(gusptr + (position))) /* size given in bytes */ unsigned int gus_read(GUSEmuState * state, int port, int size) diff --git a/hw/audio/gusemu_mixer.c b/hw/audio/gusemu_mixer.c index 00b9861b92..56300de77e 100644 --- a/hw/audio/gusemu_mixer.c +++ b/hw/audio/gusemu_mixer.c @@ -28,7 +28,7 @@ #define GUSregb(position) (* (gusptr+(position))) #define GUSregw(position) (*(uint16_t *) (gusptr+(position))) -#define GUSregd(position) (*(uint16_t *)(gusptr+(position))) +#define GUSregd(position) (*(uint32_t *)(gusptr + (position))) #define GUSvoice(position) (*(uint16_t *)(voiceptr+(position))) From 8a5fee0325f5627adf0f0e171083d512351d3acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:33 +0200 Subject: [PATCH 1441/2595] docs/specs/tpm: Correct header path name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 8dc6701722 introduce the documentation but an incorrect path name was used. Fix that. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Message-id: 20200612085444.8362-2-philmd@redhat.com Signed-off-by: Stefan Berger --- docs/specs/tpm.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst index 5e61238bc5..9e48e3b981 100644 --- a/docs/specs/tpm.rst +++ b/docs/specs/tpm.rst @@ -199,8 +199,8 @@ to be used with the passthrough backend or the swtpm backend. QEMU files related to TPM backends: - ``backends/tpm.c`` + - ``include/sysemu/tpm.h`` - ``include/sysemu/tpm_backend.h`` - - ``include/sysemu/tpm_backend_int.h`` The QEMU TPM passthrough device ------------------------------- From 8ae92e2418c85755992ac306f8d57769275fa0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:34 +0200 Subject: [PATCH 1442/2595] backends: Add TPM files into their own directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As we will have various TPM backend files, it is cleaner to use a single directory. Suggested-by: Stefan Berger Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Message-id: 20200612085444.8362-3-philmd@redhat.com Signed-off-by: Stefan Berger --- MAINTAINERS | 2 +- backends/Makefile.objs | 2 +- backends/tpm/Makefile.objs | 1 + backends/{tpm.c => tpm/tpm_backend.c} | 0 4 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 backends/tpm/Makefile.objs rename backends/{tpm.c => tpm/tpm_backend.c} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 955cc8dd5c..60a183c117 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2395,7 +2395,7 @@ F: hw/tpm/* F: include/hw/acpi/tpm.h F: include/sysemu/tpm* F: qapi/tpm.json -F: backends/tpm.c +F: backends/tpm/ F: tests/qtest/*tpm* T: git https://github.com/stefanberger/qemu-tpm.git tpm-next diff --git a/backends/Makefile.objs b/backends/Makefile.objs index 28a847cd57..22d204cb48 100644 --- a/backends/Makefile.objs +++ b/backends/Makefile.objs @@ -1,7 +1,7 @@ common-obj-y += rng.o rng-egd.o rng-builtin.o common-obj-$(CONFIG_POSIX) += rng-random.o -common-obj-$(CONFIG_TPM) += tpm.o +common-obj-$(CONFIG_TPM) += tpm/ common-obj-y += hostmem.o hostmem-ram.o common-obj-$(CONFIG_POSIX) += hostmem-file.o diff --git a/backends/tpm/Makefile.objs b/backends/tpm/Makefile.objs new file mode 100644 index 0000000000..8cf5772824 --- /dev/null +++ b/backends/tpm/Makefile.objs @@ -0,0 +1 @@ +common-obj-y += tpm_backend.o diff --git a/backends/tpm.c b/backends/tpm/tpm_backend.c similarity index 100% rename from backends/tpm.c rename to backends/tpm/tpm_backend.c From 81c7aa03e956dc5796aac9d93bff08df2eee1607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:35 +0200 Subject: [PATCH 1443/2595] hw/tpm: Rename TPMDEV as TPM_BACKEND in Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TPMDEV describe TPM backends. Use the TPM_BACKEND config name which is self-explicit. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Message-id: 20200612085444.8362-4-philmd@redhat.com Signed-off-by: Stefan Berger --- hw/tpm/Kconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig index 4794e7fe28..5028fd8880 100644 --- a/hw/tpm/Kconfig +++ b/hw/tpm/Kconfig @@ -1,4 +1,4 @@ -config TPMDEV +config TPM_BACKEND bool depends on TPM @@ -15,26 +15,26 @@ config TPM_TIS_SYSBUS config TPM_TIS bool depends on TPM - select TPMDEV + select TPM_BACKEND config TPM_CRB bool depends on TPM && PC - select TPMDEV + select TPM_BACKEND config TPM_PASSTHROUGH bool default y # FIXME: should check for x86 host as well - depends on TPMDEV && LINUX + depends on TPM_BACKEND && LINUX config TPM_EMULATOR bool default y - depends on TPMDEV + depends on TPM_BACKEND config TPM_SPAPR bool default y depends on TPM && PSERIES - select TPMDEV + select TPM_BACKEND From 29ce02bfb9fc79fec151dd450f54655e9aff2c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:36 +0200 Subject: [PATCH 1444/2595] hw/tpm: Do not include 'qemu/osdep.h' in header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From CODING_STYLE.rst: Do not include "qemu/osdep.h" from header files since the .c file will have already included it. Remove "qemu/osdep.h" from "tpm_tis.h". Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Message-id: 20200612085444.8362-5-philmd@redhat.com Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis.h | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h index 5554989395..f6b5872ba6 100644 --- a/hw/tpm/tpm_tis.h +++ b/hw/tpm/tpm_tis.h @@ -24,7 +24,6 @@ #ifndef TPM_TPM_TIS_H #define TPM_TPM_TIS_H -#include "qemu/osdep.h" #include "sysemu/tpm_backend.h" #include "tpm_ppi.h" From ae9604013094fffe4d65d03874881f0a58a72167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:37 +0200 Subject: [PATCH 1445/2595] hw/tpm: Include missing 'qemu/option.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Files using the TPM_STANDARD_CMDLINE_OPTS macro declared in "tpm_int.h" will use QEMU_OPT_STRING definition declared in "qemu/option.h". Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Message-id: 20200612085444.8362-6-philmd@redhat.com Signed-off-by: Stefan Berger --- hw/tpm/tpm_int.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h index 3fb28a9d6c..fd5ebc6489 100644 --- a/hw/tpm/tpm_int.h +++ b/hw/tpm/tpm_int.h @@ -12,6 +12,8 @@ #ifndef TPM_TPM_INT_H #define TPM_TPM_INT_H +#include "qemu/option.h" + #define TPM_STANDARD_CMDLINE_OPTS \ { \ .name = "type", \ From 4021476605228eb4c1c0ddb16780fdfab75306e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:38 +0200 Subject: [PATCH 1446/2595] hw/tpm: Move 'hw/acpi/tpm.h' inclusion from header to sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing in "tpm_ppi.h" require declarations from "hw/acpi/tpm.h". Reduce dependencies and include it only in the files requiring it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Message-id: 20200612085444.8362-7-philmd@redhat.com Signed-off-by: Stefan Berger --- hw/tpm/tpm_ppi.c | 1 + hw/tpm/tpm_ppi.h | 1 - hw/tpm/tpm_tis_isa.c | 1 + hw/tpm/tpm_tis_sysbus.c | 1 + 4 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c index 6d9c1a3e40..72d7a3d926 100644 --- a/hw/tpm/tpm_ppi.c +++ b/hw/tpm/tpm_ppi.c @@ -17,6 +17,7 @@ #include "cpu.h" #include "sysemu/memory_mapping.h" #include "migration/vmstate.h" +#include "hw/acpi/tpm.h" #include "tpm_ppi.h" #include "trace.h" diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h index d33ef27de6..6f773c25a0 100644 --- a/hw/tpm/tpm_ppi.h +++ b/hw/tpm/tpm_ppi.h @@ -12,7 +12,6 @@ #ifndef TPM_TPM_PPI_H #define TPM_TPM_PPI_H -#include "hw/acpi/tpm.h" #include "exec/address-spaces.h" typedef struct TPMPPI { diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c index 30ba37079d..42f909ff1e 100644 --- a/hw/tpm/tpm_tis_isa.c +++ b/hw/tpm/tpm_tis_isa.c @@ -26,6 +26,7 @@ #include "hw/isa/isa.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" +#include "hw/acpi/tpm.h" #include "tpm_util.h" #include "tpm_tis.h" diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c index eced1fc843..edca1dae0d 100644 --- a/hw/tpm/tpm_tis_sysbus.c +++ b/hw/tpm/tpm_tis_sysbus.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" +#include "hw/acpi/tpm.h" #include "tpm_util.h" #include "hw/sysbus.h" #include "tpm_tis.h" From 680725651799e4f1c74a29b6fc5813708c786747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:39 +0200 Subject: [PATCH 1447/2595] hw/tpm: Remove unnecessary 'tpm_int.h' header inclusion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnecessary 'tpm_int.h' header inclusion. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Message-id: 20200612085444.8362-8-philmd@redhat.com Signed-off-by: Stefan Berger --- hw/tpm/tpm_crb.c | 1 - hw/tpm/tpm_spapr.c | 1 - hw/tpm/tpm_tis_common.c | 1 - 3 files changed, 3 deletions(-) diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index cd004e7f8e..664ff70ef9 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -25,7 +25,6 @@ #include "migration/vmstate.h" #include "sysemu/tpm_backend.h" #include "sysemu/reset.h" -#include "tpm_int.h" #include "tpm_util.h" #include "tpm_ppi.h" #include "trace.h" diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c index ce65eb2e45..ab1a86ad6e 100644 --- a/hw/tpm/tpm_spapr.c +++ b/hw/tpm/tpm_spapr.c @@ -20,7 +20,6 @@ #include "migration/vmstate.h" #include "sysemu/tpm_backend.h" -#include "tpm_int.h" #include "tpm_util.h" #include "hw/ppc/spapr.h" diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c index 1af4bce139..94704870f6 100644 --- a/hw/tpm/tpm_tis_common.c +++ b/hw/tpm/tpm_tis_common.c @@ -33,7 +33,6 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "sysemu/tpm_backend.h" -#include "tpm_int.h" #include "tpm_util.h" #include "tpm_ppi.h" #include "trace.h" From f670a562af4bd6ef9adee7654cf5129f14a277a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:40 +0200 Subject: [PATCH 1448/2595] hw/tpm: Make TRACE_TPM_UTIL_SHOW_BUFFER check local to tpm_util.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The trace_event_get_state_backends() call is useful to avoid making extensive calls (usually preparing arguments passed to the tracing framework. In this case, the extensive work is done in tpm_util_show_buffer(), and the arguments used to call it don't involve extra processing. Simplify by moving the TRACE_TPM_UTIL_SHOW_BUFFER check to tpm_util_show_buffer. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Message-id: 20200612085444.8362-9-philmd@redhat.com Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis_common.c | 8 ++------ hw/tpm/tpm_util.c | 3 +++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c index 94704870f6..1779b4fc1e 100644 --- a/hw/tpm/tpm_tis_common.c +++ b/hw/tpm/tpm_tis_common.c @@ -78,9 +78,7 @@ static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) */ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) { - if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { - tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); - } + tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); /* * rw_offset serves as length indicator for length of data; @@ -246,9 +244,7 @@ void tpm_tis_request_completed(TPMState *s, int ret) s->loc[locty].state = TPM_TIS_STATE_COMPLETION; s->rw_offset = 0; - if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { - tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); - } + tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { tpm_tis_abort(s); diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c index c0a0f3d71f..12f19465c5 100644 --- a/hw/tpm/tpm_util.c +++ b/hw/tpm/tpm_util.c @@ -357,6 +357,9 @@ void tpm_util_show_buffer(const unsigned char *buffer, size_t len, i; char *line_buffer, *p; + if (!trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { + return; + } len = MIN(tpm_cmd_get_size(buffer), buffer_size); /* From eccc0b0f022e2b19efee5daa1ae448f762cf748f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:41 +0200 Subject: [PATCH 1449/2595] hw/tpm: Move few declarations from 'tpm_util.h' to 'tpm_int.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are going to make "tpm_util.h" publicly accessible by moving it to the include/ directory in a pair of commits. Keep declarations internals to hw/tpm/ in "tpm_int.h". Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Message-id: 20200612085444.8362-10-philmd@redhat.com Signed-off-by: Stefan Berger --- hw/tpm/tpm_int.h | 11 +++++++++++ hw/tpm/tpm_util.h | 10 ---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h index fd5ebc6489..9f72879d89 100644 --- a/hw/tpm/tpm_int.h +++ b/hw/tpm/tpm_int.h @@ -13,6 +13,7 @@ #define TPM_TPM_INT_H #include "qemu/option.h" +#include "sysemu/tpm.h" #define TPM_STANDARD_CMDLINE_OPTS \ { \ @@ -74,4 +75,14 @@ struct tpm_resp_hdr { #define TPM_RC_FAILURE 0x101 #define TPM_RC_LOCALITY 0x907 +int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, + size_t *buffersize); + +typedef struct TPMSizedBuffer { + uint32_t size; + uint8_t *buffer; +} TPMSizedBuffer; + +void tpm_sized_buffer_reset(TPMSizedBuffer *tsb); + #endif /* TPM_TPM_INT_H */ diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h index 7889081fba..d524935576 100644 --- a/hw/tpm/tpm_util.h +++ b/hw/tpm/tpm_util.h @@ -66,19 +66,9 @@ static inline void tpm_cmd_set_error(void *b, uint32_t error) stl_be_p(b + 6, error); } -int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, - size_t *buffersize); - #define DEFINE_PROP_TPMBE(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *) -typedef struct TPMSizedBuffer { - uint32_t size; - uint8_t *buffer; -} TPMSizedBuffer; - -void tpm_sized_buffer_reset(TPMSizedBuffer *tsb); - void tpm_util_show_buffer(const unsigned char *buffer, size_t buffer_size, const char *string); From a3500613bdf13c7583e292a6de835b8cbfc1e8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:42 +0200 Subject: [PATCH 1450/2595] hw/tpm: Move DEFINE_PROP_TPMBE() macro to 'tmp_prop.h' local header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are going to make "tpm_util.h" publicly accessible by moving it to the include/ directory in the next commit. The DEFINE_PROP_TPMBE() macro is only meaningful for the TPM hardware files (in hw/tpm/), so keep this macro in a local header. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Message-id: 20200612085444.8362-11-philmd@redhat.com Signed-off-by: Stefan Berger --- hw/tpm/tpm_crb.c | 1 + hw/tpm/tpm_prop.h | 31 +++++++++++++++++++++++++++++++ hw/tpm/tpm_spapr.c | 1 + hw/tpm/tpm_tis_isa.c | 2 +- hw/tpm/tpm_tis_sysbus.c | 2 +- hw/tpm/tpm_util.h | 3 --- 6 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 hw/tpm/tpm_prop.h diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index 664ff70ef9..1cac4d671d 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -25,6 +25,7 @@ #include "migration/vmstate.h" #include "sysemu/tpm_backend.h" #include "sysemu/reset.h" +#include "tpm_prop.h" #include "tpm_util.h" #include "tpm_ppi.h" #include "trace.h" diff --git a/hw/tpm/tpm_prop.h b/hw/tpm/tpm_prop.h new file mode 100644 index 0000000000..85e1ae5718 --- /dev/null +++ b/hw/tpm/tpm_prop.h @@ -0,0 +1,31 @@ +/* + * TPM utility functions + * + * Copyright (c) 2010 - 2015 IBM Corporation + * Authors: + * Stefan Berger + * + * 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 + */ + +#ifndef HW_TPM_PROP_H +#define HW_TPM_PROP_H + +#include "sysemu/tpm_backend.h" +#include "hw/qdev-properties.h" + +#define DEFINE_PROP_TPMBE(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *) + +#endif /* HW_TPM_PROP_H */ diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c index ab1a86ad6e..65672048c7 100644 --- a/hw/tpm/tpm_spapr.c +++ b/hw/tpm/tpm_spapr.c @@ -21,6 +21,7 @@ #include "sysemu/tpm_backend.h" #include "tpm_util.h" +#include "tpm_prop.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c index 42f909ff1e..5faf6231c0 100644 --- a/hw/tpm/tpm_tis_isa.c +++ b/hw/tpm/tpm_tis_isa.c @@ -27,7 +27,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "hw/acpi/tpm.h" -#include "tpm_util.h" +#include "tpm_prop.h" #include "tpm_tis.h" typedef struct TPMStateISA { diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c index edca1dae0d..4a3bc70625 100644 --- a/hw/tpm/tpm_tis_sysbus.c +++ b/hw/tpm/tpm_tis_sysbus.c @@ -26,7 +26,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "hw/acpi/tpm.h" -#include "tpm_util.h" +#include "tpm_prop.h" #include "hw/sysbus.h" #include "tpm_tis.h" diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h index d524935576..cf61d830d7 100644 --- a/hw/tpm/tpm_util.h +++ b/hw/tpm/tpm_util.h @@ -66,9 +66,6 @@ static inline void tpm_cmd_set_error(void *b, uint32_t error) stl_be_p(b + 6, error); } -#define DEFINE_PROP_TPMBE(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *) - void tpm_util_show_buffer(const unsigned char *buffer, size_t buffer_size, const char *string); From 0f7d2148201932c6a02b310543b1e50503a0ab2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:43 +0200 Subject: [PATCH 1451/2595] hw/tpm: Make 'tpm_util.h' publicly accessible as "sysemu/tpm_util.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are going to split the TPM backends from the TPM emulated hardware in the next commit. Make the TPM util helpers accessible by moving local "tpm_util.h" to global "sysemu/tpm_util.h". Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Message-id: 20200612085444.8362-12-philmd@redhat.com Signed-off-by: Stefan Berger --- docs/specs/tpm.rst | 4 ++-- hw/tpm/tpm_crb.c | 2 +- hw/tpm/tpm_emulator.c | 2 +- hw/tpm/tpm_passthrough.c | 2 +- hw/tpm/tpm_spapr.c | 2 +- hw/tpm/tpm_tis_common.c | 2 +- hw/tpm/tpm_util.c | 2 +- {hw/tpm => include/sysemu}/tpm_util.h | 6 +++--- 8 files changed, 11 insertions(+), 11 deletions(-) rename {hw/tpm => include/sysemu}/tpm_util.h (95%) diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst index 9e48e3b981..0200fdac68 100644 --- a/docs/specs/tpm.rst +++ b/docs/specs/tpm.rst @@ -234,7 +234,7 @@ PCRs. QEMU files related to the TPM passthrough device: - ``hw/tpm/tpm_passthrough.c`` - ``hw/tpm/tpm_util.c`` - - ``hw/tpm/tpm_util.h`` + - ``include/sysemu/tpm_util.h`` Command line to start QEMU with the TPM passthrough device using the host's @@ -294,7 +294,7 @@ command. QEMU files related to the TPM emulator device: - ``hw/tpm/tpm_emulator.c`` - ``hw/tpm/tpm_util.c`` - - ``hw/tpm/tpm_util.h`` + - ``include/sysemu/tpm_util.h`` The following commands start the swtpm with a UnixIO control channel over a socket interface. They do not need to be run as root. diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index 1cac4d671d..60247295d4 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -24,9 +24,9 @@ #include "hw/acpi/tpm.h" #include "migration/vmstate.h" #include "sysemu/tpm_backend.h" +#include "sysemu/tpm_util.h" #include "sysemu/reset.h" #include "tpm_prop.h" -#include "tpm_util.h" #include "tpm_ppi.h" #include "trace.h" diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index 3a0fc442f3..9605339f93 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -32,8 +32,8 @@ #include "qemu/sockets.h" #include "io/channel-socket.h" #include "sysemu/tpm_backend.h" +#include "sysemu/tpm_util.h" #include "tpm_int.h" -#include "tpm_util.h" #include "tpm_ioctl.h" #include "migration/blocker.h" #include "migration/vmstate.h" diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index f67244b5d4..7403807ec4 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -28,10 +28,10 @@ #include "qemu/module.h" #include "qemu/sockets.h" #include "sysemu/tpm_backend.h" +#include "sysemu/tpm_util.h" #include "tpm_int.h" #include "qapi/clone-visitor.h" #include "qapi/qapi-visit-tpm.h" -#include "tpm_util.h" #include "trace.h" #define TYPE_TPM_PASSTHROUGH "tpm-passthrough" diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c index 65672048c7..cb4dfd1e6a 100644 --- a/hw/tpm/tpm_spapr.c +++ b/hw/tpm/tpm_spapr.c @@ -20,7 +20,7 @@ #include "migration/vmstate.h" #include "sysemu/tpm_backend.h" -#include "tpm_util.h" +#include "sysemu/tpm_util.h" #include "tpm_prop.h" #include "hw/ppc/spapr.h" diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c index 1779b4fc1e..e700d82181 100644 --- a/hw/tpm/tpm_tis_common.c +++ b/hw/tpm/tpm_tis_common.c @@ -33,7 +33,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "sysemu/tpm_backend.h" -#include "tpm_util.h" +#include "sysemu/tpm_util.h" #include "tpm_ppi.h" #include "trace.h" diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c index 12f19465c5..cfc7572a61 100644 --- a/hw/tpm/tpm_util.c +++ b/hw/tpm/tpm_util.c @@ -23,11 +23,11 @@ #include "qemu/error-report.h" #include "qapi/error.h" #include "qapi/visitor.h" -#include "tpm_util.h" #include "tpm_int.h" #include "exec/memory.h" #include "hw/qdev-properties.h" #include "sysemu/tpm_backend.h" +#include "sysemu/tpm_util.h" #include "trace.h" /* tpm backend property */ diff --git a/hw/tpm/tpm_util.h b/include/sysemu/tpm_util.h similarity index 95% rename from hw/tpm/tpm_util.h rename to include/sysemu/tpm_util.h index cf61d830d7..63e872c3b2 100644 --- a/hw/tpm/tpm_util.h +++ b/include/sysemu/tpm_util.h @@ -19,8 +19,8 @@ * License along with this library; if not, see */ -#ifndef TPM_TPM_UTIL_H -#define TPM_TPM_UTIL_H +#ifndef SYSEMU_TPM_UTIL_H +#define SYSEMU_TPM_UTIL_H #include "sysemu/tpm.h" #include "qemu/bswap.h" @@ -69,4 +69,4 @@ static inline void tpm_cmd_set_error(void *b, uint32_t error) void tpm_util_show_buffer(const unsigned char *buffer, size_t buffer_size, const char *string); -#endif /* TPM_TPM_UTIL_H */ +#endif /* SYSEMU_TPM_UTIL_H */ From ca64b08638e259c313a3e7c3da106116b59be8e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 12 Jun 2020 10:54:44 +0200 Subject: [PATCH 1452/2595] tpm: Move backend code under the 'backends/' directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TPM subsytem is split into backends (see commit f4ede81eed2) and frontends (see i.e. 3676bc69b35). Keep the emulated hardware 'frontends' under hw/tpm/, but move the backends in the backends/tpm/ directory. Suggested-by: Marc-André Lureau Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200612085444.8362-13-philmd@redhat.com Signed-off-by: Stefan Berger --- Makefile | 2 +- Makefile.objs | 1 + backends/Kconfig | 1 + backends/tpm/Kconfig | 14 +++++++++++ backends/tpm/Makefile.objs | 3 +++ {hw => backends}/tpm/tpm_emulator.c | 0 {hw => backends}/tpm/tpm_int.h | 6 ++--- {hw => backends}/tpm/tpm_ioctl.h | 0 {hw => backends}/tpm/tpm_passthrough.c | 0 {hw => backends}/tpm/tpm_util.c | 0 backends/tpm/trace-events | 33 +++++++++++++++++++++++++ docs/specs/tpm.rst | 8 +++--- hw/tpm/Kconfig | 15 ------------ hw/tpm/Makefile.objs | 3 --- hw/tpm/trace-events | 34 +------------------------- tests/qtest/tpm-emu.c | 2 +- 16 files changed, 62 insertions(+), 60 deletions(-) create mode 100644 backends/Kconfig create mode 100644 backends/tpm/Kconfig rename {hw => backends}/tpm/tpm_emulator.c (100%) rename {hw => backends}/tpm/tpm_int.h (96%) rename {hw => backends}/tpm/tpm_ioctl.h (100%) rename {hw => backends}/tpm/tpm_passthrough.c (100%) rename {hw => backends}/tpm/tpm_util.c (100%) create mode 100644 backends/tpm/trace-events diff --git a/Makefile b/Makefile index 48f23aa978..a0092153af 100644 --- a/Makefile +++ b/Makefile @@ -418,7 +418,7 @@ MINIKCONF_ARGS = \ CONFIG_LINUX=$(CONFIG_LINUX) \ CONFIG_PVRDMA=$(CONFIG_PVRDMA) -MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig +MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/backends/Kconfig $(SRC_PATH)/hw/Kconfig MINIKCONF_DEPS = $(MINIKCONF_INPUTS) $(wildcard $(SRC_PATH)/hw/*/Kconfig) MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \ diff --git a/Makefile.objs b/Makefile.objs index 7ce2588b89..98383972ee 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -125,6 +125,7 @@ trace-events-subdirs = trace-events-subdirs += accel/kvm trace-events-subdirs += accel/tcg trace-events-subdirs += backends +trace-events-subdirs += backends/tpm trace-events-subdirs += crypto trace-events-subdirs += monitor ifeq ($(CONFIG_USER_ONLY),y) diff --git a/backends/Kconfig b/backends/Kconfig new file mode 100644 index 0000000000..f35abc1609 --- /dev/null +++ b/backends/Kconfig @@ -0,0 +1 @@ +source tpm/Kconfig diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig new file mode 100644 index 0000000000..5d91eb89c2 --- /dev/null +++ b/backends/tpm/Kconfig @@ -0,0 +1,14 @@ +config TPM_BACKEND + bool + depends on TPM + +config TPM_PASSTHROUGH + bool + default y + # FIXME: should check for x86 host as well + depends on TPM_BACKEND && LINUX + +config TPM_EMULATOR + bool + default y + depends on TPM_BACKEND diff --git a/backends/tpm/Makefile.objs b/backends/tpm/Makefile.objs index 8cf5772824..db2731f634 100644 --- a/backends/tpm/Makefile.objs +++ b/backends/tpm/Makefile.objs @@ -1 +1,4 @@ common-obj-y += tpm_backend.o +common-obj-y += tpm_util.o +common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o +common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o diff --git a/hw/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c similarity index 100% rename from hw/tpm/tpm_emulator.c rename to backends/tpm/tpm_emulator.c diff --git a/hw/tpm/tpm_int.h b/backends/tpm/tpm_int.h similarity index 96% rename from hw/tpm/tpm_int.h rename to backends/tpm/tpm_int.h index 9f72879d89..ba6109306e 100644 --- a/hw/tpm/tpm_int.h +++ b/backends/tpm/tpm_int.h @@ -9,8 +9,8 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ -#ifndef TPM_TPM_INT_H -#define TPM_TPM_INT_H +#ifndef BACKENDS_TPM_INT_H +#define BACKENDS_TPM_INT_H #include "qemu/option.h" #include "sysemu/tpm.h" @@ -85,4 +85,4 @@ typedef struct TPMSizedBuffer { void tpm_sized_buffer_reset(TPMSizedBuffer *tsb); -#endif /* TPM_TPM_INT_H */ +#endif /* BACKENDS_TPM_INT_H */ diff --git a/hw/tpm/tpm_ioctl.h b/backends/tpm/tpm_ioctl.h similarity index 100% rename from hw/tpm/tpm_ioctl.h rename to backends/tpm/tpm_ioctl.h diff --git a/hw/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c similarity index 100% rename from hw/tpm/tpm_passthrough.c rename to backends/tpm/tpm_passthrough.c diff --git a/hw/tpm/tpm_util.c b/backends/tpm/tpm_util.c similarity index 100% rename from hw/tpm/tpm_util.c rename to backends/tpm/tpm_util.c diff --git a/backends/tpm/trace-events b/backends/tpm/trace-events new file mode 100644 index 0000000000..0a2591fb2d --- /dev/null +++ b/backends/tpm/trace-events @@ -0,0 +1,33 @@ +# See docs/devel/tracing.txt for syntax documentation. + +# tpm_passthrough.c +tpm_passthrough_handle_request(void *cmd) "processing command %p" +tpm_passthrough_reset(void) "reset" + +# tpm_util.c +tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu" +tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu" +tpm_util_get_buffer_size_hdr_len2(uint32_t len, size_t expected) "tpm2_resp->hdr.len = %u, expected = %zu" +tpm_util_get_buffer_size_len2(uint32_t len, size_t expected) "tpm2_resp->len = %u, expected = %zu" +tpm_util_get_buffer_size(size_t len) "buffersize of device: %zu" +tpm_util_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" + +# tpm_emulator.c +tpm_emulator_set_locality(uint8_t locty) "setting locality to %d" +tpm_emulator_handle_request(void) "processing TPM command" +tpm_emulator_probe_caps(uint64_t caps) "capabilities: 0x%"PRIx64 +tpm_emulator_set_buffer_size(uint32_t buffersize, uint32_t minsize, uint32_t maxsize) "buffer size: %u, min: %u, max: %u" +tpm_emulator_startup_tpm_resume(bool is_resume, size_t buffersize) "is_resume: %d, buffer size: %zu" +tpm_emulator_get_tpm_established_flag(uint8_t flag) "got established flag: %d" +tpm_emulator_cancel_cmd_not_supt(void) "Backend does not support CANCEL_TPM_CMD" +tpm_emulator_handle_device_opts_tpm12(void) "TPM Version 1.2" +tpm_emulator_handle_device_opts_tpm2(void) "TPM Version 2" +tpm_emulator_handle_device_opts_unspec(void) "TPM Version Unspecified" +tpm_emulator_handle_device_opts_startup_error(void) "Startup error" +tpm_emulator_get_state_blob(uint8_t type, uint32_t size, uint32_t flags) "got state blob type %d, %u bytes, flags 0x%08x" +tpm_emulator_set_state_blob(uint8_t type, uint32_t size, uint32_t flags) "set state blob type %d, %u bytes, flags 0x%08x" +tpm_emulator_set_state_blobs(void) "setting state blobs" +tpm_emulator_set_state_blobs_error(const char *msg) "error while setting state blobs: %s" +tpm_emulator_set_state_blobs_done(void) "Done setting state blobs" +tpm_emulator_pre_save(void) "" +tpm_emulator_inst_init(void) "" diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst index 0200fdac68..ed6c0d785d 100644 --- a/docs/specs/tpm.rst +++ b/docs/specs/tpm.rst @@ -232,8 +232,8 @@ Integrity Measurement Architecture (IMA), are not expecting to share PCRs. QEMU files related to the TPM passthrough device: - - ``hw/tpm/tpm_passthrough.c`` - - ``hw/tpm/tpm_util.c`` + - ``backends/tpm/tpm_passthrough.c`` + - ``backends/tpm/tpm_util.c`` - ``include/sysemu/tpm_util.h`` @@ -292,8 +292,8 @@ instrumented to initialize a TPM 1.2 or TPM 2 device using this command. QEMU files related to the TPM emulator device: - - ``hw/tpm/tpm_emulator.c`` - - ``hw/tpm/tpm_util.c`` + - ``backends/tpm/tpm_emulator.c`` + - ``backends/tpm/tpm_util.c`` - ``include/sysemu/tpm_util.h`` The following commands start the swtpm with a UnixIO control channel over diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig index 5028fd8880..29e82f3c92 100644 --- a/hw/tpm/Kconfig +++ b/hw/tpm/Kconfig @@ -1,7 +1,3 @@ -config TPM_BACKEND - bool - depends on TPM - config TPM_TIS_ISA bool depends on TPM && ISA_BUS @@ -22,17 +18,6 @@ config TPM_CRB depends on TPM && PC select TPM_BACKEND -config TPM_PASSTHROUGH - bool - default y - # FIXME: should check for x86 host as well - depends on TPM_BACKEND && LINUX - -config TPM_EMULATOR - bool - default y - depends on TPM_BACKEND - config TPM_SPAPR bool default y diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index f1ec4beb95..6fc05be67c 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,9 +1,6 @@ -common-obj-$(CONFIG_TPM) += tpm_util.o obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o common-obj-$(CONFIG_TPM_TIS_SYSBUS) += tpm_tis_sysbus.o common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o -common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o -common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o obj-$(CONFIG_TPM_SPAPR) += tpm_spapr.o diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events index 439e514787..de9bf1e01b 100644 --- a/hw/tpm/trace-events +++ b/hw/tpm/trace-events @@ -4,38 +4,6 @@ tpm_crb_mmio_read(uint64_t addr, unsigned size, uint32_t val) "CRB read 0x%016" PRIx64 " len:%u val: 0x%" PRIx32 tpm_crb_mmio_write(uint64_t addr, unsigned size, uint32_t val) "CRB write 0x%016" PRIx64 " len:%u val: 0x%" PRIx32 -# tpm_passthrough.c -tpm_passthrough_handle_request(void *cmd) "processing command %p" -tpm_passthrough_reset(void) "reset" - -# tpm_util.c -tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu" -tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu" -tpm_util_get_buffer_size_hdr_len2(uint32_t len, size_t expected) "tpm2_resp->hdr.len = %u, expected = %zu" -tpm_util_get_buffer_size_len2(uint32_t len, size_t expected) "tpm2_resp->len = %u, expected = %zu" -tpm_util_get_buffer_size(size_t len) "buffersize of device: %zu" -tpm_util_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" - -# tpm_emulator.c -tpm_emulator_set_locality(uint8_t locty) "setting locality to %d" -tpm_emulator_handle_request(void) "processing TPM command" -tpm_emulator_probe_caps(uint64_t caps) "capabilities: 0x%"PRIx64 -tpm_emulator_set_buffer_size(uint32_t buffersize, uint32_t minsize, uint32_t maxsize) "buffer size: %u, min: %u, max: %u" -tpm_emulator_startup_tpm_resume(bool is_resume, size_t buffersize) "is_resume: %d, buffer size: %zu" -tpm_emulator_get_tpm_established_flag(uint8_t flag) "got established flag: %d" -tpm_emulator_cancel_cmd_not_supt(void) "Backend does not support CANCEL_TPM_CMD" -tpm_emulator_handle_device_opts_tpm12(void) "TPM Version 1.2" -tpm_emulator_handle_device_opts_tpm2(void) "TPM Version 2" -tpm_emulator_handle_device_opts_unspec(void) "TPM Version Unspecified" -tpm_emulator_handle_device_opts_startup_error(void) "Startup error" -tpm_emulator_get_state_blob(uint8_t type, uint32_t size, uint32_t flags) "got state blob type %d, %u bytes, flags 0x%08x" -tpm_emulator_set_state_blob(uint8_t type, uint32_t size, uint32_t flags) "set state blob type %d, %u bytes, flags 0x%08x" -tpm_emulator_set_state_blobs(void) "setting state blobs" -tpm_emulator_set_state_blobs_error(const char *msg) "error while setting state blobs: %s" -tpm_emulator_set_state_blobs_done(void) "Done setting state blobs" -tpm_emulator_pre_save(void) "" -tpm_emulator_inst_init(void) "" - # tpm_tis.c tpm_tis_raise_irq(uint32_t irqmask) "Raising IRQ for flag 0x%08x" tpm_tis_new_active_locality(uint8_t locty) "Active locality is now %d" @@ -56,7 +24,7 @@ tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u" # tpm_ppi.c tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu" -# hw/tpm/tpm_spapr.c +# tpm_spapr.c tpm_spapr_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" tpm_spapr_do_crq(uint8_t raw1, uint8_t raw2) "1st 2 bytes in CRQ: 0x%02x 0x%02x" tpm_spapr_do_crq_crq_result(void) "SPAPR_VTPM_INIT_CRQ_RESULT" diff --git a/tests/qtest/tpm-emu.c b/tests/qtest/tpm-emu.c index 298d0eec74..2e8eb7b94f 100644 --- a/tests/qtest/tpm-emu.c +++ b/tests/qtest/tpm-emu.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include -#include "hw/tpm/tpm_ioctl.h" +#include "backends/tpm/tpm_ioctl.h" #include "io/channel-socket.h" #include "qapi/error.h" #include "tpm-emu.h" From 354908cee1f7ff761b5fedbdb6376c378c10f941 Mon Sep 17 00:00:00 2001 From: Ian Jiang Date: Tue, 28 Jan 2020 08:37:07 +0800 Subject: [PATCH 1453/2595] riscv: Add helper to make NaN-boxing for FP register The function that makes NaN-boxing when a 32-bit value is assigned to a 64-bit FP register is split out to a helper gen_nanbox_fpr(). Then it is applied in translating of the FLW instruction. Signed-off-by: Ian Jiang Message-Id: <20200128003707.17028-1-ianjiang.ict@gmail.com> Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvf.inc.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvf.inc.c b/target/riscv/insn_trans/trans_rvf.inc.c index e23cd639a6..3bfd8881e7 100644 --- a/target/riscv/insn_trans/trans_rvf.inc.c +++ b/target/riscv/insn_trans/trans_rvf.inc.c @@ -23,6 +23,20 @@ return false; \ } while (0) +/* + * RISC-V requires NaN-boxing of narrower width floating + * point values. This applies when a 32-bit value is + * assigned to a 64-bit FP register. Thus this does not + * apply when the RVD extension is not present. + */ +static void gen_nanbox_fpr(DisasContext *ctx, int regno) +{ + if (has_ext(ctx, RVD)) { + tcg_gen_ori_i64(cpu_fpr[regno], cpu_fpr[regno], + MAKE_64BIT_MASK(32, 32)); + } +} + static bool trans_flw(DisasContext *ctx, arg_flw *a) { TCGv t0 = tcg_temp_new(); @@ -32,8 +46,7 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a) tcg_gen_addi_tl(t0, t0, a->imm); tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEUL); - /* RISC-V requires NaN-boxing of narrower width floating point values */ - tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 0xffffffff00000000ULL); + gen_nanbox_fpr(ctx, a->rd); tcg_temp_free(t0); mark_fs_dirty(ctx); From 5a842062b9d0ffc27ebfc6d4ce0a80a95c6055b1 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 13 May 2020 10:42:46 -0700 Subject: [PATCH 1454/2595] sifive_e: Support the revB machine Signed-off-by: Alistair Francis --- hw/riscv/sifive_e.c | 34 ++++++++++++++++++++++++++++++---- include/hw/riscv/sifive_e.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 1c17d02cf0..36486b72d2 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -95,10 +95,14 @@ static void riscv_sifive_e_init(MachineState *machine) memmap[SIFIVE_E_DTIM].base, main_mem); /* Mask ROM reset vector */ - uint32_t reset_vec[2] = { - 0x204002b7, /* 0x1000: lui t0,0x20400 */ - 0x00028067, /* 0x1004: jr t0 */ - }; + uint32_t reset_vec[2]; + + if (s->revb) { + reset_vec[0] = 0x200102b7; /* 0x1000: lui t0,0x20010 */ + } else { + reset_vec[0] = 0x204002b7; /* 0x1000: lui t0,0x20400 */ + } + reset_vec[1] = 0x00028067; /* 0x1004: jr t0 */ /* copy in the reset vector in little_endian byte order */ for (i = 0; i < sizeof(reset_vec) >> 2; i++) { @@ -112,8 +116,30 @@ static void riscv_sifive_e_init(MachineState *machine) } } +static bool sifive_e_machine_get_revb(Object *obj, Error **errp) +{ + SiFiveEState *s = RISCV_E_MACHINE(obj); + + return s->revb; +} + +static void sifive_e_machine_set_revb(Object *obj, bool value, Error **errp) +{ + SiFiveEState *s = RISCV_E_MACHINE(obj); + + s->revb = value; +} + static void sifive_e_machine_instance_init(Object *obj) { + SiFiveEState *s = RISCV_E_MACHINE(obj); + + s->revb = false; + object_property_add_bool(obj, "revb", sifive_e_machine_get_revb, + sifive_e_machine_set_revb); + object_property_set_description(obj, "revb", + "Set on to tell QEMU that it should model " + "the revB HiFive1 board"); } static void sifive_e_machine_class_init(ObjectClass *oc, void *data) diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h index d386ea9223..637414130b 100644 --- a/include/hw/riscv/sifive_e.h +++ b/include/hw/riscv/sifive_e.h @@ -45,6 +45,7 @@ typedef struct SiFiveEState { /*< public >*/ SiFiveESoCState soc; + bool revb; } SiFiveEState; #define TYPE_RISCV_E_MACHINE MACHINE_TYPE_NAME("sifive_e") From e7b5dfd34f296db56aa5de31d1cf64dbe82674a3 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 10 Jun 2020 18:08:46 -0700 Subject: [PATCH 1455/2595] riscv: Generalize CPU init routine for the base CPU There is no need to have two functions that have exactly the same codes for 32-bit and 64-bit base CPUs. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591837729-27486-1-git-send-email-bmeng.cn@gmail.com Message-Id: <1591837729-27486-1-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 3a6d202d03..81cdea8680 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -126,9 +126,7 @@ static void riscv_any_cpu_init(Object *obj) set_resetvec(env, DEFAULT_RSTVEC); } -#if defined(TARGET_RISCV32) - -static void riscv_base32_cpu_init(Object *obj) +static void riscv_base_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ @@ -136,6 +134,8 @@ static void riscv_base32_cpu_init(Object *obj) set_resetvec(env, DEFAULT_RSTVEC); } +#if defined(TARGET_RISCV32) + static void rv32gcsu_priv1_10_0_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -173,14 +173,6 @@ static void rv32imafcu_nommu_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) -static void riscv_base64_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - /* We set this in the realise function */ - set_misa(env, 0); - set_resetvec(env, DEFAULT_RSTVEC); -} - static void rv64gcsu_priv1_10_0_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -603,13 +595,13 @@ static const TypeInfo riscv_cpu_type_infos[] = { }, DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), #if defined(TARGET_RISCV32) - DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base32_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32imcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32imafcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init), #elif defined(TARGET_RISCV64) - DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base64_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init), #endif From 4c56793f59b9a1513868e11fd87c5d6e4a5e8edd Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 10 Jun 2020 18:08:47 -0700 Subject: [PATCH 1456/2595] riscv: Generalize CPU init routine for the gcsu CPU There is no need to have two functions that have almost the same codes for 32-bit and 64-bit gcsu CPUs. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1591837729-27486-2-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 81cdea8680..437e141ef2 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -134,16 +134,16 @@ static void riscv_base_cpu_init(Object *obj) set_resetvec(env, DEFAULT_RSTVEC); } -#if defined(TARGET_RISCV32) - -static void rv32gcsu_priv1_10_0_cpu_init(Object *obj) +static void rvxx_gcsu_priv1_10_0_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); } +#if defined(TARGET_RISCV32) + static void rv32imcu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -173,14 +173,6 @@ static void rv32imafcu_nommu_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) -static void rv64gcsu_priv1_10_0_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); - set_priv_version(env, PRIV_VERSION_1_10_0); - set_resetvec(env, DEFAULT_RSTVEC); -} - static void rv64imacu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -599,11 +591,11 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32imcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32imafcu_nommu_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rvxx_gcsu_priv1_10_0_cpu_init), #elif defined(TARGET_RISCV64) DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rvxx_gcsu_priv1_10_0_cpu_init), #endif }; From d8e72bd1613d4fcae10fd7409fc90cb3586714d1 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 10 Jun 2020 18:08:48 -0700 Subject: [PATCH 1457/2595] riscv: Generalize CPU init routine for the imacu CPU There is no need to have two functions that have almost the same codes for 32-bit and 64-bit imacu CPUs. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1591837729-27486-3-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 437e141ef2..35a8c7853b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -142,6 +142,15 @@ static void rvxx_gcsu_priv1_10_0_cpu_init(Object *obj) set_resetvec(env, DEFAULT_RSTVEC); } +static void rvxx_imacu_nommu_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + set_misa(env, RVXLEN | RVI | RVM | RVA | RVC | RVU); + set_priv_version(env, PRIV_VERSION_1_10_0); + set_resetvec(env, DEFAULT_RSTVEC); + qdev_prop_set_bit(DEVICE(obj), "mmu", false); +} + #if defined(TARGET_RISCV32) static void rv32imcu_nommu_cpu_init(Object *obj) @@ -153,15 +162,6 @@ static void rv32imcu_nommu_cpu_init(Object *obj) qdev_prop_set_bit(DEVICE(obj), "mmu", false); } -static void rv32imacu_nommu_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU); - set_priv_version(env, PRIV_VERSION_1_10_0); - set_resetvec(env, DEFAULT_RSTVEC); - qdev_prop_set_bit(DEVICE(obj), "mmu", false); -} - static void rv32imafcu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -171,17 +171,6 @@ static void rv32imafcu_nommu_cpu_init(Object *obj) qdev_prop_set_bit(DEVICE(obj), "mmu", false); } -#elif defined(TARGET_RISCV64) - -static void rv64imacu_nommu_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU); - set_priv_version(env, PRIV_VERSION_1_10_0); - set_resetvec(env, DEFAULT_RSTVEC); - qdev_prop_set_bit(DEVICE(obj), "mmu", false); -} - #endif static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) @@ -589,12 +578,12 @@ static const TypeInfo riscv_cpu_type_infos[] = { #if defined(TARGET_RISCV32) DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32imcu_nommu_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rvxx_imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32imafcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rvxx_gcsu_priv1_10_0_cpu_init), #elif defined(TARGET_RISCV64) DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rvxx_imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rvxx_gcsu_priv1_10_0_cpu_init), #endif }; From 2fdd2c094a3df68084df07de99ac5f7316c54145 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 10 Jun 2020 18:08:49 -0700 Subject: [PATCH 1458/2595] riscv: Keep the CPU init routine names consistent Adding a _ to keep some consistency among the CPU init routines. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1591837729-27486-4-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 35a8c7853b..e867766cf0 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -153,7 +153,7 @@ static void rvxx_imacu_nommu_cpu_init(Object *obj) #if defined(TARGET_RISCV32) -static void rv32imcu_nommu_cpu_init(Object *obj) +static void rv32_imcu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RV32 | RVI | RVM | RVC | RVU); @@ -162,7 +162,7 @@ static void rv32imcu_nommu_cpu_init(Object *obj) qdev_prop_set_bit(DEVICE(obj), "mmu", false); } -static void rv32imafcu_nommu_cpu_init(Object *obj) +static void rv32_imafcu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVC | RVU); @@ -577,9 +577,9 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), #if defined(TARGET_RISCV32) DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32imcu_nommu_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32_imcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rvxx_imacu_nommu_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32imafcu_nommu_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32_imafcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rvxx_gcsu_priv1_10_0_cpu_init), #elif defined(TARGET_RISCV64) DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base_cpu_init), From efe9f9c820d1322729957a60ff785c9527a79ddf Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 27 Mar 2020 12:53:40 -0700 Subject: [PATCH 1459/2595] target/riscv: Set access as data_load when validating stage-2 PTEs Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson --- target/riscv/cpu_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 62fe1ecc8f..eda7057663 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -435,7 +435,7 @@ restart: hwaddr vbase; /* Do the second stage translation on the base PTE address. */ - get_physical_address(env, &vbase, &vbase_prot, base, access_type, + get_physical_address(env, &vbase, &vbase_prot, base, MMU_DATA_LOAD, mmu_idx, false, true); pte_addr = vbase + idx * ptesize; From 88914473e748db20d8e18b9735f647a683319fa6 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 27 Mar 2020 12:54:45 -0700 Subject: [PATCH 1460/2595] target/riscv: Report errors validating 2nd-stage PTEs Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson --- target/riscv/cpu_helper.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index eda7057663..75d2ae3434 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -435,8 +435,13 @@ restart: hwaddr vbase; /* Do the second stage translation on the base PTE address. */ - get_physical_address(env, &vbase, &vbase_prot, base, MMU_DATA_LOAD, - mmu_idx, false, true); + int vbase_ret = get_physical_address(env, &vbase, &vbase_prot, + base, MMU_DATA_LOAD, + mmu_idx, false, true); + + if (vbase_ret != TRANSLATE_SUCCESS) { + return vbase_ret; + } pte_addr = vbase + idx * ptesize; } else { From b8429ded723ec52568e05f6a24ed78c93224687c Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 3 Apr 2020 14:05:01 -0700 Subject: [PATCH 1461/2595] target/riscv: Move the hfence instructions to the rvh decode Also correct the name of the VVMA instruction. Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson --- target/riscv/insn32.decode | 8 ++- .../riscv/insn_trans/trans_privileged.inc.c | 38 ------------- target/riscv/insn_trans/trans_rvh.inc.c | 57 +++++++++++++++++++ target/riscv/translate.c | 1 + 4 files changed, 63 insertions(+), 41 deletions(-) create mode 100644 target/riscv/insn_trans/trans_rvh.inc.c diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index b883672e63..4c8d1215ce 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -64,7 +64,7 @@ @r2 ....... ..... ..... ... ..... ....... %rs1 %rd @hfence_gvma ....... ..... ..... ... ..... ....... %rs2 %rs1 -@hfence_bvma ....... ..... ..... ... ..... ....... %rs2 %rs1 +@hfence_vvma ....... ..... ..... ... ..... ....... %rs2 %rs1 @sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1 @sfence_vm ....... ..... ..... ... ..... ....... %rs1 @@ -77,8 +77,6 @@ uret 0000000 00010 00000 000 00000 1110011 sret 0001000 00010 00000 000 00000 1110011 mret 0011000 00010 00000 000 00000 1110011 wfi 0001000 00101 00000 000 00000 1110011 -hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma -hfence_bvma 0010001 ..... ..... 000 00000 1110011 @hfence_bvma sfence_vma 0001001 ..... ..... 000 00000 1110011 @sfence_vma sfence_vm 0001000 00100 ..... 000 00000 1110011 @sfence_vm @@ -207,3 +205,7 @@ fcvt_w_d 1100001 00000 ..... ... ..... 1010011 @r2_rm fcvt_wu_d 1100001 00001 ..... ... ..... 1010011 @r2_rm fcvt_d_w 1101001 00000 ..... ... ..... 1010011 @r2_rm fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm + +# *** RV32H Base Instruction Set *** +hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma +hfence_vvma 0010001 ..... ..... 000 00000 1110011 @hfence_vvma diff --git a/target/riscv/insn_trans/trans_privileged.inc.c b/target/riscv/insn_trans/trans_privileged.inc.c index 5f26e0f5ea..2a61a853bf 100644 --- a/target/riscv/insn_trans/trans_privileged.inc.c +++ b/target/riscv/insn_trans/trans_privileged.inc.c @@ -95,41 +95,3 @@ static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a) { return false; } - -static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) -{ -#ifndef CONFIG_USER_ONLY - if (has_ext(ctx, RVH)) { - /* Hpervisor extensions exist */ - /* - * if (env->priv == PRV_M || - * (env->priv == PRV_S && - * !riscv_cpu_virt_enabled(env) && - * get_field(ctx->mstatus_fs, MSTATUS_TVM))) { - */ - gen_helper_tlb_flush(cpu_env); - return true; - /* } */ - } -#endif - return false; -} - -static bool trans_hfence_bvma(DisasContext *ctx, arg_sfence_vma *a) -{ -#ifndef CONFIG_USER_ONLY - if (has_ext(ctx, RVH)) { - /* Hpervisor extensions exist */ - /* - * if (env->priv == PRV_M || - * (env->priv == PRV_S && - * !riscv_cpu_virt_enabled(env) && - * get_field(ctx->mstatus_fs, MSTATUS_TVM))) { - */ - gen_helper_tlb_flush(cpu_env); - return true; - /* } */ - } -#endif - return false; -} diff --git a/target/riscv/insn_trans/trans_rvh.inc.c b/target/riscv/insn_trans/trans_rvh.inc.c new file mode 100644 index 0000000000..2c0359819d --- /dev/null +++ b/target/riscv/insn_trans/trans_rvh.inc.c @@ -0,0 +1,57 @@ +/* + * RISC-V translation routines for the RVXI Base Integer Instruction Set. + * + * Copyright (c) 2020 Western Digital + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) +{ +#ifndef CONFIG_USER_ONLY + if (ctx->priv_ver >= PRIV_VERSION_1_10_0 && + has_ext(ctx, RVH)) { + /* Hpervisor extensions exist */ + /* + * if (env->priv == PRV_M || + * (env->priv == PRV_S && + * !riscv_cpu_virt_enabled(env) && + * get_field(ctx->mstatus_fs, MSTATUS_TVM))) { + */ + gen_helper_tlb_flush(cpu_env); + return true; + /* } */ + } +#endif + return false; +} + +static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a) +{ +#ifndef CONFIG_USER_ONLY + if (ctx->priv_ver >= PRIV_VERSION_1_10_0 && + has_ext(ctx, RVH)) { + /* Hpervisor extensions exist */ + /* + * if (env->priv == PRV_M || + * (env->priv == PRV_S && + * !riscv_cpu_virt_enabled(env) && + * get_field(ctx->mstatus_fs, MSTATUS_TVM))) { + */ + gen_helper_tlb_flush(cpu_env); + return true; + /* } */ + } +#endif + return false; +} diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 43bf7e39a6..ce71ca7a92 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -711,6 +711,7 @@ static bool gen_shift(DisasContext *ctx, arg_r *a, #include "insn_trans/trans_rva.inc.c" #include "insn_trans/trans_rvf.inc.c" #include "insn_trans/trans_rvd.inc.c" +#include "insn_trans/trans_rvh.inc.c" #include "insn_trans/trans_privileged.inc.c" /* Include the auto-generated decoder for 16 bit insn */ From 2761db5fc20943bbd606b6fd49640ac000398de6 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 3 Apr 2020 15:54:59 -0700 Subject: [PATCH 1462/2595] target/riscv: Implement checks for hfence Call the helper_hyp_tlb_flush() function on hfence instructions which will generate an illegal insruction execption if we don't have permission to flush the Hypervisor level TLBs. Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson --- target/riscv/helper.h | 5 ++++ target/riscv/insn_trans/trans_rvh.inc.c | 32 +++++-------------------- target/riscv/op_helper.c | 13 ++++++++++ 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index debb22a480..b36be978d5 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -76,3 +76,8 @@ DEF_HELPER_2(mret, tl, env, tl) DEF_HELPER_1(wfi, void, env) DEF_HELPER_1(tlb_flush, void, env) #endif + +/* Hypervisor functions */ +#ifndef CONFIG_USER_ONLY +DEF_HELPER_1(hyp_tlb_flush, void, env) +#endif diff --git a/target/riscv/insn_trans/trans_rvh.inc.c b/target/riscv/insn_trans/trans_rvh.inc.c index 2c0359819d..263b652d90 100644 --- a/target/riscv/insn_trans/trans_rvh.inc.c +++ b/target/riscv/insn_trans/trans_rvh.inc.c @@ -18,40 +18,20 @@ static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) { + REQUIRE_EXT(ctx, RVH); #ifndef CONFIG_USER_ONLY - if (ctx->priv_ver >= PRIV_VERSION_1_10_0 && - has_ext(ctx, RVH)) { - /* Hpervisor extensions exist */ - /* - * if (env->priv == PRV_M || - * (env->priv == PRV_S && - * !riscv_cpu_virt_enabled(env) && - * get_field(ctx->mstatus_fs, MSTATUS_TVM))) { - */ - gen_helper_tlb_flush(cpu_env); - return true; - /* } */ - } + gen_helper_hyp_tlb_flush(cpu_env); + return true; #endif return false; } static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a) { + REQUIRE_EXT(ctx, RVH); #ifndef CONFIG_USER_ONLY - if (ctx->priv_ver >= PRIV_VERSION_1_10_0 && - has_ext(ctx, RVH)) { - /* Hpervisor extensions exist */ - /* - * if (env->priv == PRV_M || - * (env->priv == PRV_S && - * !riscv_cpu_virt_enabled(env) && - * get_field(ctx->mstatus_fs, MSTATUS_TVM))) { - */ - gen_helper_tlb_flush(cpu_env); - return true; - /* } */ - } + gen_helper_hyp_tlb_flush(cpu_env); + return true; #endif return false; } diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index b0c49efc4a..7cccd42a1e 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -194,4 +194,17 @@ void helper_tlb_flush(CPURISCVState *env) } } +void helper_hyp_tlb_flush(CPURISCVState *env) +{ + CPUState *cs = env_cpu(env); + + if (env->priv == PRV_M || + (env->priv == PRV_S && !riscv_cpu_virt_enabled(env))) { + tlb_flush(cs); + return; + } + + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); +} + #endif /* !CONFIG_USER_ONLY */ From 888c9af23ff0fced10a58041e6658e0eb60143cb Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 9 Jun 2020 16:08:29 -0700 Subject: [PATCH 1463/2595] riscv/opentitan: Fix the ROM size Signed-off-by: Alistair Francis Reported-by: Damien Hedde --- hw/riscv/opentitan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index f6776da8e9..011e4f7ee2 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -25,12 +25,13 @@ #include "hw/misc/unimp.h" #include "hw/riscv/boot.h" #include "exec/address-spaces.h" +#include "qemu/units.h" static const struct MemmapEntry { hwaddr base; hwaddr size; } ibex_memmap[] = { - [IBEX_ROM] = { 0x00008000, 0xc000 }, + [IBEX_ROM] = { 0x00008000, 16 * KiB }, [IBEX_RAM] = { 0x10000000, 0x10000 }, [IBEX_FLASH] = { 0x20000000, 0x80000 }, [IBEX_UART] = { 0x40000000, 0x10000 }, From a7d2d98c5944cec9ac8ed12215c2ea9d4545779b Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 23 Apr 2020 14:07:27 -0700 Subject: [PATCH 1464/2595] hw/char: Initial commit of Ibex UART This is the initial commit of the Ibex UART device. Serial TX is working, while RX has been implemeneted but untested. This is based on the documentation from: https://docs.opentitan.org/hw/ip/uart/doc/ Signed-off-by: Alistair Francis Reviewed-by: LIU Zhiwei --- MAINTAINERS | 2 + hw/char/Makefile.objs | 1 + hw/char/ibex_uart.c | 492 ++++++++++++++++++++++++++++++++++++ hw/riscv/Kconfig | 4 + include/hw/char/ibex_uart.h | 110 ++++++++ 5 files changed, 609 insertions(+) create mode 100644 hw/char/ibex_uart.c create mode 100644 include/hw/char/ibex_uart.h diff --git a/MAINTAINERS b/MAINTAINERS index 955cc8dd5c..4010ea5606 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1250,7 +1250,9 @@ M: Alistair Francis L: qemu-riscv@nongnu.org S: Supported F: hw/riscv/opentitan.c +F: hw/char/ibex_uart.c F: include/hw/riscv/opentitan.h +F: include/hw/char/ibex_uart.h SH4 Machines ------------ diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs index 9e9a6c1aff..633996be5b 100644 --- a/hw/char/Makefile.objs +++ b/hw/char/Makefile.objs @@ -12,6 +12,7 @@ common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o common-obj-$(CONFIG_XEN) += xen_console.o common-obj-$(CONFIG_CADENCE) += cadence_uart.o +common-obj-$(CONFIG_IBEX) += ibex_uart.o common-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o common-obj-$(CONFIG_COLDFIRE) += mcf_uart.o diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c new file mode 100644 index 0000000000..3e0dd9968e --- /dev/null +++ b/hw/char/ibex_uart.c @@ -0,0 +1,492 @@ +/* + * QEMU lowRISC Ibex UART device + * + * Copyright (c) 2020 Western Digital + * + * For details check the documentation here: + * https://docs.opentitan.org/hw/ip/uart/doc/ + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/char/ibex_uart.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" + +static void ibex_uart_update_irqs(IbexUartState *s) +{ + if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) { + qemu_set_irq(s->tx_watermark, 1); + } else { + qemu_set_irq(s->tx_watermark, 0); + } + + if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) { + qemu_set_irq(s->rx_watermark, 1); + } else { + qemu_set_irq(s->rx_watermark, 0); + } + + if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) { + qemu_set_irq(s->tx_empty, 1); + } else { + qemu_set_irq(s->tx_empty, 0); + } + + if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) { + qemu_set_irq(s->rx_overflow, 1); + } else { + qemu_set_irq(s->rx_overflow, 0); + } +} + +static int ibex_uart_can_receive(void *opaque) +{ + IbexUartState *s = opaque; + + if (s->uart_ctrl & UART_CTRL_RX_ENABLE) { + return 1; + } + + return 0; +} + +static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size) +{ + IbexUartState *s = opaque; + uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL) + >> FIFO_CTRL_RXILVL_SHIFT; + + s->uart_rdata = *buf; + + s->uart_status &= ~UART_STATUS_RXIDLE; + s->uart_status &= ~UART_STATUS_RXEMPTY; + + if (size > rx_fifo_level) { + s->uart_intr_state |= INTR_STATE_RX_WATERMARK; + } + + ibex_uart_update_irqs(s); +} + +static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond, + void *opaque) +{ + IbexUartState *s = opaque; + uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL) + >> FIFO_CTRL_TXILVL_SHIFT; + int ret; + + /* instant drain the fifo when there's no back-end */ + if (!qemu_chr_fe_backend_connected(&s->chr)) { + s->tx_level = 0; + return FALSE; + } + + if (!s->tx_level) { + s->uart_status &= ~UART_STATUS_TXFULL; + s->uart_status |= UART_STATUS_TXEMPTY; + s->uart_intr_state |= INTR_STATE_TX_EMPTY; + s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK; + ibex_uart_update_irqs(s); + return FALSE; + } + + ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level); + + if (ret >= 0) { + s->tx_level -= ret; + memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level); + } + + if (s->tx_level) { + guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, + ibex_uart_xmit, s); + if (!r) { + s->tx_level = 0; + return FALSE; + } + } + + /* Clear the TX Full bit */ + if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) { + s->uart_status &= ~UART_STATUS_TXFULL; + } + + /* Disable the TX_WATERMARK IRQ */ + if (s->tx_level < tx_fifo_level) { + s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK; + } + + /* Set TX empty */ + if (s->tx_level == 0) { + s->uart_status |= UART_STATUS_TXEMPTY; + s->uart_intr_state |= INTR_STATE_TX_EMPTY; + } + + ibex_uart_update_irqs(s); + return FALSE; +} + +static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf, + int size) +{ + uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL) + >> FIFO_CTRL_TXILVL_SHIFT; + + if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) { + size = IBEX_UART_TX_FIFO_SIZE - s->tx_level; + qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow"); + } + + memcpy(s->tx_fifo + s->tx_level, buf, size); + s->tx_level += size; + + if (s->tx_level > 0) { + s->uart_status &= ~UART_STATUS_TXEMPTY; + } + + if (s->tx_level >= tx_fifo_level) { + s->uart_intr_state |= INTR_STATE_TX_WATERMARK; + ibex_uart_update_irqs(s); + } + + if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) { + s->uart_status |= UART_STATUS_TXFULL; + } + + timer_mod(s->fifo_trigger_handle, current_time + + (s->char_tx_time * 4)); +} + +static void ibex_uart_reset(DeviceState *dev) +{ + IbexUartState *s = IBEX_UART(dev); + + s->uart_intr_state = 0x00000000; + s->uart_intr_state = 0x00000000; + s->uart_intr_enable = 0x00000000; + s->uart_ctrl = 0x00000000; + s->uart_status = 0x0000003c; + s->uart_rdata = 0x00000000; + s->uart_fifo_ctrl = 0x00000000; + s->uart_fifo_status = 0x00000000; + s->uart_ovrd = 0x00000000; + s->uart_val = 0x00000000; + s->uart_timeout_ctrl = 0x00000000; + + s->tx_level = 0; + + s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10; + + ibex_uart_update_irqs(s); +} + +static uint64_t ibex_uart_read(void *opaque, hwaddr addr, + unsigned int size) +{ + IbexUartState *s = opaque; + uint64_t retvalue = 0; + + switch (addr) { + case IBEX_UART_INTR_STATE: + retvalue = s->uart_intr_state; + break; + case IBEX_UART_INTR_ENABLE: + retvalue = s->uart_intr_enable; + break; + case IBEX_UART_INTR_TEST: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: wdata is write only\n", __func__); + break; + + case IBEX_UART_CTRL: + retvalue = s->uart_ctrl; + break; + case IBEX_UART_STATUS: + retvalue = s->uart_status; + break; + + case IBEX_UART_RDATA: + retvalue = s->uart_rdata; + if (s->uart_ctrl & UART_CTRL_RX_ENABLE) { + qemu_chr_fe_accept_input(&s->chr); + + s->uart_status |= UART_STATUS_RXIDLE; + s->uart_status |= UART_STATUS_RXEMPTY; + } + break; + case IBEX_UART_WDATA: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: wdata is write only\n", __func__); + break; + + case IBEX_UART_FIFO_CTRL: + retvalue = s->uart_fifo_ctrl; + break; + case IBEX_UART_FIFO_STATUS: + retvalue = s->uart_fifo_status; + + retvalue |= s->tx_level & 0x1F; + + qemu_log_mask(LOG_UNIMP, + "%s: RX fifos are not supported\n", __func__); + break; + + case IBEX_UART_OVRD: + retvalue = s->uart_ovrd; + qemu_log_mask(LOG_UNIMP, + "%s: ovrd is not supported\n", __func__); + break; + case IBEX_UART_VAL: + retvalue = s->uart_val; + qemu_log_mask(LOG_UNIMP, + "%s: val is not supported\n", __func__); + break; + case IBEX_UART_TIMEOUT_CTRL: + retvalue = s->uart_timeout_ctrl; + qemu_log_mask(LOG_UNIMP, + "%s: timeout_ctrl is not supported\n", __func__); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + return 0; + } + + return retvalue; +} + +static void ibex_uart_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + IbexUartState *s = opaque; + uint32_t value = val64; + + switch (addr) { + case IBEX_UART_INTR_STATE: + /* Write 1 clear */ + s->uart_intr_state &= ~value; + ibex_uart_update_irqs(s); + break; + case IBEX_UART_INTR_ENABLE: + s->uart_intr_enable = value; + ibex_uart_update_irqs(s); + break; + case IBEX_UART_INTR_TEST: + s->uart_intr_state |= value; + ibex_uart_update_irqs(s); + break; + + case IBEX_UART_CTRL: + s->uart_ctrl = value; + + if (value & UART_CTRL_NF) { + qemu_log_mask(LOG_UNIMP, + "%s: UART_CTRL_NF is not supported\n", __func__); + } + if (value & UART_CTRL_SLPBK) { + qemu_log_mask(LOG_UNIMP, + "%s: UART_CTRL_SLPBK is not supported\n", __func__); + } + if (value & UART_CTRL_LLPBK) { + qemu_log_mask(LOG_UNIMP, + "%s: UART_CTRL_LLPBK is not supported\n", __func__); + } + if (value & UART_CTRL_PARITY_EN) { + qemu_log_mask(LOG_UNIMP, + "%s: UART_CTRL_PARITY_EN is not supported\n", + __func__); + } + if (value & UART_CTRL_PARITY_ODD) { + qemu_log_mask(LOG_UNIMP, + "%s: UART_CTRL_PARITY_ODD is not supported\n", + __func__); + } + if (value & UART_CTRL_RXBLVL) { + qemu_log_mask(LOG_UNIMP, + "%s: UART_CTRL_RXBLVL is not supported\n", __func__); + } + if (value & UART_CTRL_NCO) { + uint64_t baud = ((value & UART_CTRL_NCO) >> 16); + baud *= 1000; + baud /= 2 ^ 20; + + s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; + } + break; + case IBEX_UART_STATUS: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: status is read only\n", __func__); + break; + + case IBEX_UART_RDATA: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: rdata is read only\n", __func__); + break; + case IBEX_UART_WDATA: + uart_write_tx_fifo(s, (uint8_t *) &value, 1); + break; + + case IBEX_UART_FIFO_CTRL: + s->uart_fifo_ctrl = value; + + if (value & FIFO_CTRL_RXRST) { + qemu_log_mask(LOG_UNIMP, + "%s: RX fifos are not supported\n", __func__); + } + if (value & FIFO_CTRL_TXRST) { + s->tx_level = 0; + } + break; + case IBEX_UART_FIFO_STATUS: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: fifo_status is read only\n", __func__); + break; + + case IBEX_UART_OVRD: + s->uart_ovrd = value; + qemu_log_mask(LOG_UNIMP, + "%s: ovrd is not supported\n", __func__); + break; + case IBEX_UART_VAL: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: val is read only\n", __func__); + break; + case IBEX_UART_TIMEOUT_CTRL: + s->uart_timeout_ctrl = value; + qemu_log_mask(LOG_UNIMP, + "%s: timeout_ctrl is not supported\n", __func__); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + } +} + +static void fifo_trigger_update(void *opaque) +{ + IbexUartState *s = opaque; + + if (s->uart_ctrl & UART_CTRL_TX_ENABLE) { + ibex_uart_xmit(NULL, G_IO_OUT, s); + } +} + +static const MemoryRegionOps ibex_uart_ops = { + .read = ibex_uart_read, + .write = ibex_uart_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl.min_access_size = 4, + .impl.max_access_size = 4, +}; + +static int ibex_uart_post_load(void *opaque, int version_id) +{ + IbexUartState *s = opaque; + + ibex_uart_update_irqs(s); + return 0; +} + +static const VMStateDescription vmstate_ibex_uart = { + .name = TYPE_IBEX_UART, + .version_id = 1, + .minimum_version_id = 1, + .post_load = ibex_uart_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState, + IBEX_UART_TX_FIFO_SIZE), + VMSTATE_UINT32(tx_level, IbexUartState), + VMSTATE_UINT64(char_tx_time, IbexUartState), + VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState), + VMSTATE_UINT32(uart_intr_state, IbexUartState), + VMSTATE_UINT32(uart_intr_enable, IbexUartState), + VMSTATE_UINT32(uart_ctrl, IbexUartState), + VMSTATE_UINT32(uart_status, IbexUartState), + VMSTATE_UINT32(uart_rdata, IbexUartState), + VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState), + VMSTATE_UINT32(uart_fifo_status, IbexUartState), + VMSTATE_UINT32(uart_ovrd, IbexUartState), + VMSTATE_UINT32(uart_val, IbexUartState), + VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState), + VMSTATE_END_OF_LIST() + } +}; + +static Property ibex_uart_properties[] = { + DEFINE_PROP_CHR("chardev", IbexUartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ibex_uart_init(Object *obj) +{ + IbexUartState *s = IBEX_UART(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow); + + memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s, + TYPE_IBEX_UART, 0x400); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static void ibex_uart_realize(DeviceState *dev, Error **errp) +{ + IbexUartState *s = IBEX_UART(dev); + + s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, + fifo_trigger_update, s); + + qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive, + ibex_uart_receive, NULL, NULL, + s, NULL, true); +} + +static void ibex_uart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = ibex_uart_reset; + dc->realize = ibex_uart_realize; + dc->vmsd = &vmstate_ibex_uart; + device_class_set_props(dc, ibex_uart_properties); +} + +static const TypeInfo ibex_uart_info = { + .name = TYPE_IBEX_UART, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IbexUartState), + .instance_init = ibex_uart_init, + .class_init = ibex_uart_class_init, +}; + +static void ibex_uart_register_types(void) +{ + type_register_static(&ibex_uart_info); +} + +type_init(ibex_uart_register_types) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 94d19571f7..28947ef3e0 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -4,6 +4,9 @@ config HTIF config HART bool +config IBEX + bool + config SIFIVE bool select MSI_NONBROKEN @@ -29,6 +32,7 @@ config SPIKE config OPENTITAN bool + select IBEX select HART select UNIMP diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h new file mode 100644 index 0000000000..2bec772615 --- /dev/null +++ b/include/hw/char/ibex_uart.h @@ -0,0 +1,110 @@ +/* + * QEMU lowRISC Ibex UART device + * + * Copyright (c) 2020 Western Digital + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_IBEX_UART_H +#define HW_IBEX_UART_H + +#include "hw/sysbus.h" +#include "chardev/char-fe.h" +#include "qemu/timer.h" + +#define IBEX_UART_INTR_STATE 0x00 + #define INTR_STATE_TX_WATERMARK (1 << 0) + #define INTR_STATE_RX_WATERMARK (1 << 1) + #define INTR_STATE_TX_EMPTY (1 << 2) + #define INTR_STATE_RX_OVERFLOW (1 << 3) +#define IBEX_UART_INTR_ENABLE 0x04 +#define IBEX_UART_INTR_TEST 0x08 + +#define IBEX_UART_CTRL 0x0c + #define UART_CTRL_TX_ENABLE (1 << 0) + #define UART_CTRL_RX_ENABLE (1 << 1) + #define UART_CTRL_NF (1 << 2) + #define UART_CTRL_SLPBK (1 << 4) + #define UART_CTRL_LLPBK (1 << 5) + #define UART_CTRL_PARITY_EN (1 << 6) + #define UART_CTRL_PARITY_ODD (1 << 7) + #define UART_CTRL_RXBLVL (3 << 8) + #define UART_CTRL_NCO (0xFFFF << 16) + +#define IBEX_UART_STATUS 0x10 + #define UART_STATUS_TXFULL (1 << 0) + #define UART_STATUS_RXFULL (1 << 1) + #define UART_STATUS_TXEMPTY (1 << 2) + #define UART_STATUS_RXIDLE (1 << 4) + #define UART_STATUS_RXEMPTY (1 << 5) + +#define IBEX_UART_RDATA 0x14 +#define IBEX_UART_WDATA 0x18 + +#define IBEX_UART_FIFO_CTRL 0x1c + #define FIFO_CTRL_RXRST (1 << 0) + #define FIFO_CTRL_TXRST (1 << 1) + #define FIFO_CTRL_RXILVL (7 << 2) + #define FIFO_CTRL_RXILVL_SHIFT (2) + #define FIFO_CTRL_TXILVL (3 << 5) + #define FIFO_CTRL_TXILVL_SHIFT (5) + +#define IBEX_UART_FIFO_STATUS 0x20 +#define IBEX_UART_OVRD 0x24 +#define IBEX_UART_VAL 0x28 +#define IBEX_UART_TIMEOUT_CTRL 0x2c + +#define IBEX_UART_TX_FIFO_SIZE 16 + +#define TYPE_IBEX_UART "ibex-uart" +#define IBEX_UART(obj) \ + OBJECT_CHECK(IbexUartState, (obj), TYPE_IBEX_UART) + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + + uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE]; + uint32_t tx_level; + + QEMUTimer *fifo_trigger_handle; + uint64_t char_tx_time; + + uint32_t uart_intr_state; + uint32_t uart_intr_enable; + uint32_t uart_ctrl; + uint32_t uart_status; + uint32_t uart_rdata; + uint32_t uart_fifo_ctrl; + uint32_t uart_fifo_status; + uint32_t uart_ovrd; + uint32_t uart_val; + uint32_t uart_timeout_ctrl; + + CharBackend chr; + qemu_irq tx_watermark; + qemu_irq rx_watermark; + qemu_irq tx_empty; + qemu_irq rx_overflow; +} IbexUartState; +#endif /* HW_IBEX_UART_H */ From 879f60f01c1c655676207ea73d9250a7bc4a915f Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 23 Apr 2020 18:34:15 -0700 Subject: [PATCH 1465/2595] hw/intc: Initial commit of lowRISC Ibex PLIC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Ibex core contains a PLIC that although similar to the RISC-V spec is not RISC-V spec compliant. This patch implements a Ibex PLIC in a somewhat generic way. As the current RISC-V PLIC needs tidying up, my hope is that as the Ibex PLIC move towards spec compliance this PLIC implementation can be updated until it can replace the current PLIC. Signed-off-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé --- MAINTAINERS | 2 + hw/intc/Makefile.objs | 1 + hw/intc/ibex_plic.c | 261 ++++++++++++++++++++++++++++++++++++ include/hw/intc/ibex_plic.h | 63 +++++++++ 4 files changed, 327 insertions(+) create mode 100644 hw/intc/ibex_plic.c create mode 100644 include/hw/intc/ibex_plic.h diff --git a/MAINTAINERS b/MAINTAINERS index 4010ea5606..63b3bb3266 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1251,8 +1251,10 @@ L: qemu-riscv@nongnu.org S: Supported F: hw/riscv/opentitan.c F: hw/char/ibex_uart.c +F: hw/intc/ibex_plic.c F: include/hw/riscv/opentitan.h F: include/hw/char/ibex_uart.h +F: include/hw/intc/ibex_plic.h SH4 Machines ------------ diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index f726d87532..a61e6728fe 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -49,3 +49,4 @@ obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o obj-$(CONFIG_MIPS_CPS) += mips_gic.o obj-$(CONFIG_NIOS2) += nios2_iic.o obj-$(CONFIG_OMPIC) += ompic.o +obj-$(CONFIG_IBEX) += ibex_plic.o diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c new file mode 100644 index 0000000000..41079518c6 --- /dev/null +++ b/hw/intc/ibex_plic.c @@ -0,0 +1,261 @@ +/* + * QEMU RISC-V lowRISC Ibex PLIC + * + * Copyright (c) 2020 Western Digital + * + * Documentation avaliable: https://docs.opentitan.org/hw/ip/rv_plic/doc/ + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/qdev-properties.h" +#include "hw/core/cpu.h" +#include "hw/boards.h" +#include "hw/pci/msi.h" +#include "target/riscv/cpu_bits.h" +#include "target/riscv/cpu.h" +#include "hw/intc/ibex_plic.h" + +static bool addr_between(uint32_t addr, uint32_t base, uint32_t num) +{ + uint32_t end = base + (num * 0x04); + + if (addr >= base && addr < end) { + return true; + } + + return false; +} + +static void ibex_plic_irqs_set_pending(IbexPlicState *s, int irq, bool level) +{ + int pending_num = irq / 32; + + s->pending[pending_num] |= level << (irq % 32); +} + +static bool ibex_plic_irqs_pending(IbexPlicState *s, uint32_t context) +{ + int i; + + for (i = 0; i < s->pending_num; i++) { + uint32_t irq_num = ctz64(s->pending[i]) + (i * 32); + + if (!(s->pending[i] & s->enable[i])) { + /* No pending and enabled IRQ */ + continue; + } + + if (s->priority[irq_num] > s->threshold) { + if (!s->claim) { + s->claim = irq_num; + } + return true; + } + } + + return false; +} + +static void ibex_plic_update(IbexPlicState *s) +{ + CPUState *cpu; + int level, i; + + for (i = 0; i < s->num_cpus; i++) { + cpu = qemu_get_cpu(i); + + if (!cpu) { + continue; + } + + level = ibex_plic_irqs_pending(s, 0); + + riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level)); + } +} + +static void ibex_plic_reset(DeviceState *dev) +{ + IbexPlicState *s = IBEX_PLIC(dev); + + s->threshold = 0x00000000; + s->claim = 0x00000000; +} + +static uint64_t ibex_plic_read(void *opaque, hwaddr addr, + unsigned int size) +{ + IbexPlicState *s = opaque; + int offset; + uint32_t ret = 0; + + if (addr_between(addr, s->pending_base, s->pending_num)) { + offset = (addr - s->pending_base) / 4; + ret = s->pending[offset]; + } else if (addr_between(addr, s->source_base, s->source_num)) { + qemu_log_mask(LOG_UNIMP, + "%s: Interrupt source mode not supported\n", __func__); + } else if (addr_between(addr, s->priority_base, s->priority_num)) { + offset = (addr - s->priority_base) / 4; + ret = s->priority[offset]; + } else if (addr_between(addr, s->enable_base, s->enable_num)) { + offset = (addr - s->enable_base) / 4; + ret = s->enable[offset]; + } else if (addr_between(addr, s->threshold_base, 1)) { + ret = s->threshold; + } else if (addr_between(addr, s->claim_base, 1)) { + int pending_num = s->claim / 32; + s->pending[pending_num] &= ~(1 << (s->claim % 32)); + + ret = s->claim; + } + + return ret; +} + +static void ibex_plic_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + IbexPlicState *s = opaque; + + if (addr_between(addr, s->pending_base, s->pending_num)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Pending registers are read only\n", __func__); + } else if (addr_between(addr, s->source_base, s->source_num)) { + qemu_log_mask(LOG_UNIMP, + "%s: Interrupt source mode not supported\n", __func__); + } else if (addr_between(addr, s->priority_base, s->priority_num)) { + uint32_t irq = ((addr - s->priority_base) >> 2) + 1; + s->priority[irq] = value & 7; + } else if (addr_between(addr, s->enable_base, s->enable_num)) { + uint32_t enable_reg = (addr - s->enable_base) / 4; + + s->enable[enable_reg] = value; + } else if (addr_between(addr, s->threshold_base, 1)) { + s->threshold = value & 3; + } else if (addr_between(addr, s->claim_base, 1)) { + if (s->claim == value) { + /* Interrupt was completed */ + s->claim = 0; + } + } + + ibex_plic_update(s); +} + +static const MemoryRegionOps ibex_plic_ops = { + .read = ibex_plic_read, + .write = ibex_plic_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static void ibex_plic_irq_request(void *opaque, int irq, int level) +{ + IbexPlicState *s = opaque; + + ibex_plic_irqs_set_pending(s, irq, level > 0); + ibex_plic_update(s); +} + +static Property ibex_plic_properties[] = { + DEFINE_PROP_UINT32("num-cpus", IbexPlicState, num_cpus, 1), + DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 80), + + DEFINE_PROP_UINT32("pending-base", IbexPlicState, pending_base, 0), + DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 3), + + DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x0c), + DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 3), + + DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x18), + DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 80), + + DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x200), + DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 3), + + DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x20c), + + DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x210), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ibex_plic_init(Object *obj) +{ + IbexPlicState *s = IBEX_PLIC(obj); + + memory_region_init_io(&s->mmio, obj, &ibex_plic_ops, s, + TYPE_IBEX_PLIC, 0x400); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static void ibex_plic_realize(DeviceState *dev, Error **errp) +{ + IbexPlicState *s = IBEX_PLIC(dev); + int i; + + s->pending = g_new0(uint32_t, s->pending_num); + s->source = g_new0(uint32_t, s->source_num); + s->priority = g_new0(uint32_t, s->priority_num); + s->enable = g_new0(uint32_t, s->enable_num); + + qdev_init_gpio_in(dev, ibex_plic_irq_request, s->num_sources); + + /* + * We can't allow the supervisor to control SEIP as this would allow the + * supervisor to clear a pending external interrupt which will result in + * a lost interrupt in the case a PLIC is attached. The SEIP bit must be + * hardware controlled when a PLIC is attached. + */ + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + for (i = 0; i < smp_cpus; i++) { + RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(i)); + if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) { + error_report("SEIP already claimed"); + exit(1); + } + } + + msi_nonbroken = true; +} + +static void ibex_plic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = ibex_plic_reset; + device_class_set_props(dc, ibex_plic_properties); + dc->realize = ibex_plic_realize; +} + +static const TypeInfo ibex_plic_info = { + .name = TYPE_IBEX_PLIC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IbexPlicState), + .instance_init = ibex_plic_init, + .class_init = ibex_plic_class_init, +}; + +static void ibex_plic_register_types(void) +{ + type_register_static(&ibex_plic_info); +} + +type_init(ibex_plic_register_types) diff --git a/include/hw/intc/ibex_plic.h b/include/hw/intc/ibex_plic.h new file mode 100644 index 0000000000..ddc7909903 --- /dev/null +++ b/include/hw/intc/ibex_plic.h @@ -0,0 +1,63 @@ +/* + * QEMU RISC-V lowRISC Ibex PLIC + * + * Copyright (c) 2020 Western Digital + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#ifndef HW_IBEX_PLIC_H +#define HW_IBEX_PLIC_H + +#include "hw/sysbus.h" + +#define TYPE_IBEX_PLIC "ibex-plic" +#define IBEX_PLIC(obj) \ + OBJECT_CHECK(IbexPlicState, (obj), TYPE_IBEX_PLIC) + +typedef struct IbexPlicState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion mmio; + + uint32_t *pending; + uint32_t *source; + uint32_t *priority; + uint32_t *enable; + uint32_t threshold; + uint32_t claim; + + /* config */ + uint32_t num_cpus; + uint32_t num_sources; + + uint32_t pending_base; + uint32_t pending_num; + + uint32_t source_base; + uint32_t source_num; + + uint32_t priority_base; + uint32_t priority_num; + + uint32_t enable_base; + uint32_t enable_num; + + uint32_t threshold_base; + + uint32_t claim_base; +} IbexPlicState; + +#endif /* HW_IBEX_PLIC_H */ From b9fc51354cdc8e2623925c8fd76d7634240a28af Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 23 Apr 2020 18:40:57 -0700 Subject: [PATCH 1466/2595] riscv/opentitan: Connect the PLIC device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé --- hw/riscv/opentitan.c | 14 ++++++++++++-- include/hw/riscv/opentitan.h | 3 +++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 011e4f7ee2..835b2c503f 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -26,6 +26,7 @@ #include "hw/riscv/boot.h" #include "exec/address-spaces.h" #include "qemu/units.h" +#include "sysemu/sysemu.h" static const struct MemmapEntry { hwaddr base; @@ -94,6 +95,8 @@ static void riscv_lowrisc_ibex_soc_init(Object *obj) LowRISCIbexSoCState *s = RISCV_IBEX_SOC(obj); object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); + + object_initialize_child(obj, "plic", &s->plic, TYPE_IBEX_PLIC); } static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) @@ -102,6 +105,7 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) MachineState *ms = MACHINE(qdev_get_machine()); LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc); MemoryRegion *sys_mem = get_system_memory(); + Error *err = NULL; object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type", &error_abort); @@ -121,6 +125,14 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) memory_region_add_subregion(sys_mem, memmap[IBEX_FLASH].base, &s->flash_mem); + /* PLIC */ + sysbus_realize(SYS_BUS_DEVICE(&s->plic), &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->plic), 0, memmap[IBEX_PLIC].base); + create_unimplemented_device("riscv.lowrisc.ibex.uart", memmap[IBEX_UART].base, memmap[IBEX_UART].size); create_unimplemented_device("riscv.lowrisc.ibex.gpio", @@ -141,8 +153,6 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) memmap[IBEX_AES].base, memmap[IBEX_AES].size); create_unimplemented_device("riscv.lowrisc.ibex.hmac", memmap[IBEX_HMAC].base, memmap[IBEX_HMAC].size); - create_unimplemented_device("riscv.lowrisc.ibex.plic", - memmap[IBEX_PLIC].base, memmap[IBEX_PLIC].size); create_unimplemented_device("riscv.lowrisc.ibex.pinmux", memmap[IBEX_PINMUX].base, memmap[IBEX_PINMUX].size); create_unimplemented_device("riscv.lowrisc.ibex.alert_handler", diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index a4b6499444..76f72905a8 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -20,6 +20,7 @@ #define HW_OPENTITAN_H #include "hw/riscv/riscv_hart.h" +#include "hw/intc/ibex_plic.h" #define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc" #define RISCV_IBEX_SOC(obj) \ @@ -31,6 +32,8 @@ typedef struct LowRISCIbexSoCState { /*< public >*/ RISCVHartArrayState cpus; + IbexPlicState plic; + MemoryRegion flash_mem; MemoryRegion rom; } LowRISCIbexSoCState; From cc4112605eaf5aebbe186469eba790ac1562b3ef Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 23 Apr 2020 14:08:45 -0700 Subject: [PATCH 1467/2595] riscv/opentitan: Connect the UART device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé --- hw/riscv/opentitan.c | 25 +++++++++++++++++++++++-- include/hw/riscv/opentitan.h | 13 +++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 835b2c503f..675ce900bd 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -97,6 +97,8 @@ static void riscv_lowrisc_ibex_soc_init(Object *obj) object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); object_initialize_child(obj, "plic", &s->plic, TYPE_IBEX_PLIC); + + object_initialize_child(obj, "uart", &s->uart, TYPE_IBEX_UART); } static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) @@ -133,8 +135,27 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) } sysbus_mmio_map(SYS_BUS_DEVICE(&s->plic), 0, memmap[IBEX_PLIC].base); - create_unimplemented_device("riscv.lowrisc.ibex.uart", - memmap[IBEX_UART].base, memmap[IBEX_UART].size); + /* UART */ + qdev_prop_set_chr(DEVICE(&(s->uart)), "chardev", serial_hd(0)); + sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart), 0, memmap[IBEX_UART].base); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), + 0, qdev_get_gpio_in(DEVICE(&s->plic), + IBEX_UART_TX_WATERMARK_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), + 1, qdev_get_gpio_in(DEVICE(&s->plic), + IBEX_UART_RX_WATERMARK_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), + 2, qdev_get_gpio_in(DEVICE(&s->plic), + IBEX_UART_TX_EMPTY_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), + 3, qdev_get_gpio_in(DEVICE(&s->plic), + IBEX_UART_RX_OVERFLOW_IRQ)); + create_unimplemented_device("riscv.lowrisc.ibex.gpio", memmap[IBEX_GPIO].base, memmap[IBEX_GPIO].size); create_unimplemented_device("riscv.lowrisc.ibex.spi", diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index 76f72905a8..8f29b9cbbf 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -21,6 +21,7 @@ #include "hw/riscv/riscv_hart.h" #include "hw/intc/ibex_plic.h" +#include "hw/char/ibex_uart.h" #define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc" #define RISCV_IBEX_SOC(obj) \ @@ -33,6 +34,7 @@ typedef struct LowRISCIbexSoCState { /*< public >*/ RISCVHartArrayState cpus; IbexPlicState plic; + IbexUartState uart; MemoryRegion flash_mem; MemoryRegion rom; @@ -68,4 +70,15 @@ enum { IBEX_PADCTRL, }; +enum { + IBEX_UART_RX_PARITY_ERR_IRQ = 0x28, + IBEX_UART_RX_TIMEOUT_IRQ = 0x27, + IBEX_UART_RX_BREAK_ERR_IRQ = 0x26, + IBEX_UART_RX_FRAME_ERR_IRQ = 0x25, + IBEX_UART_RX_OVERFLOW_IRQ = 0x24, + IBEX_UART_TX_EMPTY_IRQ = 0x23, + IBEX_UART_RX_WATERMARK_IRQ = 0x22, + IBEX_UART_TX_WATERMARK_IRQ = 0x21, +}; + #endif From 1145188e091aa4675b09882b6bd500c50b87547f Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 23 Apr 2020 18:47:38 -0700 Subject: [PATCH 1468/2595] target/riscv: Use a smaller guess size for no-MMU PMP Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- target/riscv/pmp.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 0e6b640fbd..9418660f1b 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -233,12 +233,16 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, return true; } - /* - * if size is unknown (0), assume that all bytes - * from addr to the end of the page will be accessed. - */ if (size == 0) { - pmp_size = -(addr | TARGET_PAGE_MASK); + if (riscv_feature(env, RISCV_FEATURE_MMU)) { + /* + * If size is unknown (0), assume that all bytes + * from addr to the end of the page will be accessed. + */ + pmp_size = -(addr | TARGET_PAGE_MASK); + } else { + pmp_size = sizeof(target_ulong); + } } else { pmp_size = size; } From 8f8c6c1a6420483af93fe1fbeb14c5aa8f104c8d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 8 Jun 2020 07:17:30 -0700 Subject: [PATCH 1469/2595] hw/riscv: sifive_e: Remove the riscv_ prefix of the machine* and soc* functions This was done in the virt & sifive_u codes, but sifive_e codes were missed. Remove the riscv_ prefix of the machine* and soc* functions. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591625864-31494-2-git-send-email-bmeng.cn@gmail.com Message-Id: <1591625864-31494-2-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_e.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 36486b72d2..01626820bb 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -75,7 +75,7 @@ static const struct MemmapEntry { [SIFIVE_E_DTIM] = { 0x80000000, 0x4000 } }; -static void riscv_sifive_e_init(MachineState *machine) +static void sifive_e_machine_init(MachineState *machine) { const struct MemmapEntry *memmap = sifive_e_memmap; @@ -147,7 +147,7 @@ static void sifive_e_machine_class_init(ObjectClass *oc, void *data) MachineClass *mc = MACHINE_CLASS(oc); mc->desc = "RISC-V Board compatible with SiFive E SDK"; - mc->init = riscv_sifive_e_init; + mc->init = sifive_e_machine_init; mc->max_cpus = 1; mc->default_cpu_type = SIFIVE_E_CPU; } @@ -167,7 +167,7 @@ static void sifive_e_machine_init_register_types(void) type_init(sifive_e_machine_init_register_types) -static void riscv_sifive_e_soc_init(Object *obj) +static void sifive_e_soc_init(Object *obj) { MachineState *ms = MACHINE(qdev_get_machine()); SiFiveESoCState *s = RISCV_E_SOC(obj); @@ -179,7 +179,7 @@ static void riscv_sifive_e_soc_init(Object *obj) TYPE_SIFIVE_GPIO); } -static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) +static void sifive_e_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); const struct MemmapEntry *memmap = sifive_e_memmap; @@ -262,26 +262,26 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) &s->xip_mem); } -static void riscv_sifive_e_soc_class_init(ObjectClass *oc, void *data) +static void sifive_e_soc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); - dc->realize = riscv_sifive_e_soc_realize; + dc->realize = sifive_e_soc_realize; /* Reason: Uses serial_hds in realize function, thus can't be used twice */ dc->user_creatable = false; } -static const TypeInfo riscv_sifive_e_soc_type_info = { +static const TypeInfo sifive_e_soc_type_info = { .name = TYPE_RISCV_E_SOC, .parent = TYPE_DEVICE, .instance_size = sizeof(SiFiveESoCState), - .instance_init = riscv_sifive_e_soc_init, - .class_init = riscv_sifive_e_soc_class_init, + .instance_init = sifive_e_soc_init, + .class_init = sifive_e_soc_class_init, }; -static void riscv_sifive_e_soc_register_types(void) +static void sifive_e_soc_register_types(void) { - type_register_static(&riscv_sifive_e_soc_type_info); + type_register_static(&sifive_e_soc_type_info); } -type_init(riscv_sifive_e_soc_register_types) +type_init(sifive_e_soc_register_types) From 894944624bd986383ff403368bdae902ec97cc57 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 8 Jun 2020 07:17:31 -0700 Subject: [PATCH 1470/2595] hw/riscv: opentitan: Remove the riscv_ prefix of the machine* and soc* functions This was done in the virt & sifive_u codes, but opentitan codes were missed. Remove the riscv_ prefix of the machine* and soc* functions. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591625864-31494-3-git-send-email-bmeng.cn@gmail.com Message-Id: <1591625864-31494-3-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/opentitan.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 675ce900bd..19223e4c29 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -53,7 +53,7 @@ static const struct MemmapEntry { [IBEX_PADCTRL] = { 0x40160000, 0x10000 } }; -static void riscv_opentitan_init(MachineState *machine) +static void opentitan_board_init(MachineState *machine) { const struct MemmapEntry *memmap = ibex_memmap; OpenTitanState *s = g_new0(OpenTitanState, 1); @@ -70,7 +70,6 @@ static void riscv_opentitan_init(MachineState *machine) memory_region_add_subregion(sys_mem, memmap[IBEX_RAM].base, main_mem); - if (machine->firmware) { riscv_load_firmware(machine->firmware, memmap[IBEX_RAM].base, NULL); } @@ -80,17 +79,17 @@ static void riscv_opentitan_init(MachineState *machine) } } -static void riscv_opentitan_machine_init(MachineClass *mc) +static void opentitan_machine_init(MachineClass *mc) { mc->desc = "RISC-V Board compatible with OpenTitan"; - mc->init = riscv_opentitan_init; + mc->init = opentitan_board_init; mc->max_cpus = 1; mc->default_cpu_type = TYPE_RISCV_CPU_IBEX; } -DEFINE_MACHINE("opentitan", riscv_opentitan_machine_init) +DEFINE_MACHINE("opentitan", opentitan_machine_init) -static void riscv_lowrisc_ibex_soc_init(Object *obj) +static void lowrisc_ibex_soc_init(Object *obj) { LowRISCIbexSoCState *s = RISCV_IBEX_SOC(obj); @@ -101,7 +100,7 @@ static void riscv_lowrisc_ibex_soc_init(Object *obj) object_initialize_child(obj, "uart", &s->uart, TYPE_IBEX_UART); } -static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) +static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) { const struct MemmapEntry *memmap = ibex_memmap; MachineState *ms = MACHINE(qdev_get_machine()); @@ -186,26 +185,26 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) memmap[IBEX_PADCTRL].base, memmap[IBEX_PADCTRL].size); } -static void riscv_lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data) +static void lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); - dc->realize = riscv_lowrisc_ibex_soc_realize; + dc->realize = lowrisc_ibex_soc_realize; /* Reason: Uses serial_hds in realize function, thus can't be used twice */ dc->user_creatable = false; } -static const TypeInfo riscv_lowrisc_ibex_soc_type_info = { +static const TypeInfo lowrisc_ibex_soc_type_info = { .name = TYPE_RISCV_IBEX_SOC, .parent = TYPE_DEVICE, .instance_size = sizeof(LowRISCIbexSoCState), - .instance_init = riscv_lowrisc_ibex_soc_init, - .class_init = riscv_lowrisc_ibex_soc_class_init, + .instance_init = lowrisc_ibex_soc_init, + .class_init = lowrisc_ibex_soc_class_init, }; -static void riscv_lowrisc_ibex_soc_register_types(void) +static void lowrisc_ibex_soc_register_types(void) { - type_register_static(&riscv_lowrisc_ibex_soc_type_info); + type_register_static(&lowrisc_ibex_soc_type_info); } -type_init(riscv_lowrisc_ibex_soc_register_types) +type_init(lowrisc_ibex_soc_register_types) From 5874f0a7155e262e96c91ed60b5f728f592cd516 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 8 Jun 2020 07:17:32 -0700 Subject: [PATCH 1471/2595] hw/riscv: sifive_u: Simplify the GEM IRQ connect code a little bit There is no need to retrieve all PLIC IRQ information in order to just connect the GEM IRQ. Use qdev_get_gpio_in() directly like what is done for other peripherals. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591625864-31494-4-git-send-email-bmeng.cn@gmail.com Message-Id: <1591625864-31494-4-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index ea197ab64f..20b0276ea3 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -514,7 +514,6 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1); - qemu_irq plic_gpios[SIFIVE_U_PLIC_NUM_SOURCES]; char *plic_hart_config; size_t plic_hart_config_len; int i; @@ -594,10 +593,6 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->otp), &err); sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base); - for (i = 0; i < SIFIVE_U_PLIC_NUM_SOURCES; i++) { - plic_gpios[i] = qdev_get_gpio_in(DEVICE(s->plic), i); - } - if (nd->used) { qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(DEVICE(&s->gem), nd); @@ -611,7 +606,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem), 0, memmap[SIFIVE_U_GEM].base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem), 0, - plic_gpios[SIFIVE_U_GEM_IRQ]); + qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_GEM_IRQ)); create_unimplemented_device("riscv.sifive.u.gem-mgmt", memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size); From ea85f27d4123b97e0f2a58d2ed3b5215bf93bab4 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 8 Jun 2020 07:17:33 -0700 Subject: [PATCH 1472/2595] hw/riscv: sifive_u: Generate device tree node for OTP Upstream U-Boot v2020.07 codes switch to access SiFive FU540 OTP based on device tree information. Let's generate the device tree node for OTP. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591625864-31494-5-git-send-email-bmeng.cn@gmail.com Message-Id: <1591625864-31494-5-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 20b0276ea3..a6dfce4273 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -207,6 +207,17 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(cells); g_free(nodename); + nodename = g_strdup_printf("/soc/otp@%lx", + (long)memmap[SIFIVE_U_OTP].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "fuse-count", SIFIVE_U_OTP_REG_SIZE); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_OTP].base, + 0x0, memmap[SIFIVE_U_OTP].size); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "sifive,fu540-c000-otp"); + g_free(nodename); + prci_phandle = phandle++; nodename = g_strdup_printf("/soc/clock-controller@%lx", (long)memmap[SIFIVE_U_PRCI].base); From 2e30ccb425fafa7b7b76d41a7f2e97dd6977fbce Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 8 Jun 2020 07:17:34 -0700 Subject: [PATCH 1473/2595] hw/riscv: sifive_gpio: Clean up the codes Do various minor clean-ups to the exisiting codes for: - coding convention conformance - remove unnecessary blank lines - spell SiFive correctly Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591625864-31494-6-git-send-email-bmeng.cn@gmail.com Message-Id: <1591625864-31494-6-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_gpio.c | 13 +++++-------- include/hw/riscv/sifive_gpio.h | 7 ++++--- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/hw/riscv/sifive_gpio.c b/hw/riscv/sifive_gpio.c index 5c7c596e6b..c9cffa2eba 100644 --- a/hw/riscv/sifive_gpio.c +++ b/hw/riscv/sifive_gpio.c @@ -1,5 +1,5 @@ /* - * sifive System-on-Chip general purpose input/output register definition + * SiFive System-on-Chip general purpose input/output register definition * * Copyright 2019 AdaCore * @@ -20,7 +20,6 @@ static void update_output_irq(SIFIVEGPIOState *s) { - uint32_t pending; uint32_t pin; @@ -186,7 +185,7 @@ static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size) } static void sifive_gpio_write(void *opaque, hwaddr offset, - uint64_t value, unsigned int size) + uint64_t value, unsigned int size) { SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); @@ -318,7 +317,6 @@ static void sifive_gpio_reset(DeviceState *dev) s->out_xor = 0; s->in = 0; s->in_mask = 0; - } static const VMStateDescription vmstate_sifive_gpio = { @@ -342,8 +340,8 @@ static const VMStateDescription vmstate_sifive_gpio = { VMSTATE_UINT32(iof_en, SIFIVEGPIOState), VMSTATE_UINT32(iof_sel, SIFIVEGPIOState), VMSTATE_UINT32(out_xor, SIFIVEGPIOState), - VMSTATE_UINT32(in, SIFIVEGPIOState), - VMSTATE_UINT32(in_mask, SIFIVEGPIOState), + VMSTATE_UINT32(in, SIFIVEGPIOState), + VMSTATE_UINT32(in_mask, SIFIVEGPIOState), VMSTATE_END_OF_LIST() } }; @@ -356,7 +354,6 @@ static void sifive_gpio_init(Object *obj) TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); - for (int i = 0; i < SIFIVE_GPIO_PINS; i++) { sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq[i]); } @@ -371,7 +368,7 @@ static void sifive_gpio_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_sifive_gpio; dc->reset = sifive_gpio_reset; - dc->desc = "sifive GPIO"; + dc->desc = "SiFive GPIO"; } static const TypeInfo sifive_gpio_info = { diff --git a/include/hw/riscv/sifive_gpio.h b/include/hw/riscv/sifive_gpio.h index fce03d6c41..ad915b26d6 100644 --- a/include/hw/riscv/sifive_gpio.h +++ b/include/hw/riscv/sifive_gpio.h @@ -1,5 +1,5 @@ /* - * sifive System-on-Chip general purpose input/output register definition + * SiFive System-on-Chip general purpose input/output register definition * * Copyright 2019 AdaCore * @@ -10,10 +10,12 @@ * This code is licensed under the GPL version 2 or later. See * the COPYING file in the top-level directory. */ + #ifndef SIFIVE_GPIO_H #define SIFIVE_GPIO_H #include "hw/sysbus.h" + #define TYPE_SIFIVE_GPIO "sifive_soc.gpio" #define SIFIVE_GPIO(obj) OBJECT_CHECK(SIFIVEGPIOState, (obj), TYPE_SIFIVE_GPIO) @@ -66,7 +68,6 @@ typedef struct SIFIVEGPIOState { uint32_t out_xor; uint32_t in; uint32_t in_mask; - } SIFIVEGPIOState; -#endif +#endif /* SIFIVE_GPIO_H */ From 4bb216f637d16b6deed499d0be1c34ff03bd625c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 8 Jun 2020 07:17:35 -0700 Subject: [PATCH 1474/2595] hw/riscv: sifive_gpio: Add a new 'ngpio' property Add a new property to represent the number of GPIO pins supported by the GPIO controller. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591625864-31494-7-git-send-email-bmeng.cn@gmail.com Message-Id: <1591625864-31494-7-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_gpio.c | 30 +++++++++++++++++++----------- include/hw/riscv/sifive_gpio.h | 3 +++ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/hw/riscv/sifive_gpio.c b/hw/riscv/sifive_gpio.c index c9cffa2eba..0d0fd2ba5e 100644 --- a/hw/riscv/sifive_gpio.c +++ b/hw/riscv/sifive_gpio.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "hw/irq.h" +#include "hw/qdev-properties.h" #include "hw/riscv/sifive_gpio.h" #include "migration/vmstate.h" #include "trace.h" @@ -28,7 +29,7 @@ static void update_output_irq(SIFIVEGPIOState *s) pending |= s->rise_ip & s->rise_ie; pending |= s->fall_ip & s->fall_ie; - for (int i = 0; i < SIFIVE_GPIO_PINS; i++) { + for (int i = 0; i < s->ngpio; i++) { pin = 1 << i; qemu_set_irq(s->irq[i], (pending & pin) != 0); trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0); @@ -41,7 +42,7 @@ static void update_state(SIFIVEGPIOState *s) bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en, rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival; - for (i = 0; i < SIFIVE_GPIO_PINS; i++) { + for (i = 0; i < s->ngpio; i++) { prev_ival = extract32(s->value, i, 1); in = extract32(s->in, i, 1); @@ -346,27 +347,35 @@ static const VMStateDescription vmstate_sifive_gpio = { } }; -static void sifive_gpio_init(Object *obj) +static Property sifive_gpio_properties[] = { + DEFINE_PROP_UINT32("ngpio", SIFIVEGPIOState, ngpio, SIFIVE_GPIO_PINS), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sifive_gpio_realize(DeviceState *dev, Error **errp) { - SIFIVEGPIOState *s = SIFIVE_GPIO(obj); + SIFIVEGPIOState *s = SIFIVE_GPIO(dev); - memory_region_init_io(&s->mmio, obj, &gpio_ops, s, + memory_region_init_io(&s->mmio, OBJECT(dev), &gpio_ops, s, TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); - for (int i = 0; i < SIFIVE_GPIO_PINS; i++) { - sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq[i]); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); + + for (int i = 0; i < s->ngpio; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); } - qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, SIFIVE_GPIO_PINS); - qdev_init_gpio_out(DEVICE(s), s->output, SIFIVE_GPIO_PINS); + qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, s->ngpio); + qdev_init_gpio_out(DEVICE(s), s->output, s->ngpio); } static void sifive_gpio_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + device_class_set_props(dc, sifive_gpio_properties); dc->vmsd = &vmstate_sifive_gpio; + dc->realize = sifive_gpio_realize; dc->reset = sifive_gpio_reset; dc->desc = "SiFive GPIO"; } @@ -375,7 +384,6 @@ static const TypeInfo sifive_gpio_info = { .name = TYPE_SIFIVE_GPIO, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SIFIVEGPIOState), - .instance_init = sifive_gpio_init, .class_init = sifive_gpio_class_init }; diff --git a/include/hw/riscv/sifive_gpio.h b/include/hw/riscv/sifive_gpio.h index ad915b26d6..cf12fcfd62 100644 --- a/include/hw/riscv/sifive_gpio.h +++ b/include/hw/riscv/sifive_gpio.h @@ -68,6 +68,9 @@ typedef struct SIFIVEGPIOState { uint32_t out_xor; uint32_t in; uint32_t in_mask; + + /* config */ + uint32_t ngpio; } SIFIVEGPIOState; #endif /* SIFIVE_GPIO_H */ From 8a88b9f54f5fb2acecf73760903b1f58fb40d0cd Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 8 Jun 2020 07:17:36 -0700 Subject: [PATCH 1475/2595] hw/riscv: sifive_u: Hook a GPIO controller SiFive FU540 SoC integrates a GPIO controller with 16 GPIO lines. This hooks the exsiting SiFive GPIO model to the SoC, and adds its device tree data as well. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591625864-31494-8-git-send-email-bmeng.cn@gmail.com Message-Id: <1591625864-31494-8-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 43 +++++++++++++++++++++++++++++++++++-- include/hw/riscv/sifive_u.h | 19 ++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index a6dfce4273..f6976a0d09 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -11,8 +11,9 @@ * 1) CLINT (Core Level Interruptor) * 2) PLIC (Platform Level Interrupt Controller) * 3) PRCI (Power, Reset, Clock, Interrupt) - * 4) OTP (One-Time Programmable) memory with stored serial number - * 5) GEM (Gigabit Ethernet Controller) and management block + * 4) GPIO (General Purpose Input/Output Controller) + * 5) OTP (One-Time Programmable) memory with stored serial number + * 6) GEM (Gigabit Ethernet Controller) and management block * * This board currently generates devicetree dynamically that indicates at least * two harts and up to five harts. @@ -75,6 +76,7 @@ static const struct MemmapEntry { [SIFIVE_U_PRCI] = { 0x10000000, 0x1000 }, [SIFIVE_U_UART0] = { 0x10010000, 0x1000 }, [SIFIVE_U_UART1] = { 0x10011000, 0x1000 }, + [SIFIVE_U_GPIO] = { 0x10060000, 0x1000 }, [SIFIVE_U_OTP] = { 0x10070000, 0x1000 }, [SIFIVE_U_FLASH0] = { 0x20000000, 0x10000000 }, [SIFIVE_U_DRAM] = { 0x80000000, 0x0 }, @@ -268,6 +270,28 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(cells); g_free(nodename); + nodename = g_strdup_printf("/soc/gpio@%lx", + (long)memmap[SIFIVE_U_GPIO].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + prci_phandle, PRCI_CLK_TLCLK); + qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 2); + qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(fdt, nodename, "#gpio-cells", 2); + qemu_fdt_setprop(fdt, nodename, "gpio-controller", NULL, 0); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_GPIO].base, + 0x0, memmap[SIFIVE_U_GPIO].size); + qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_GPIO_IRQ0, + SIFIVE_U_GPIO_IRQ1, SIFIVE_U_GPIO_IRQ2, SIFIVE_U_GPIO_IRQ3, + SIFIVE_U_GPIO_IRQ4, SIFIVE_U_GPIO_IRQ5, SIFIVE_U_GPIO_IRQ6, + SIFIVE_U_GPIO_IRQ7, SIFIVE_U_GPIO_IRQ8, SIFIVE_U_GPIO_IRQ9, + SIFIVE_U_GPIO_IRQ10, SIFIVE_U_GPIO_IRQ11, SIFIVE_U_GPIO_IRQ12, + SIFIVE_U_GPIO_IRQ13, SIFIVE_U_GPIO_IRQ14, SIFIVE_U_GPIO_IRQ15); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,gpio0"); + g_free(nodename); + phy_phandle = phandle++; nodename = g_strdup_printf("/soc/ethernet@%lx", (long)memmap[SIFIVE_U_GEM].base); @@ -515,6 +539,7 @@ static void sifive_u_soc_instance_init(Object *obj) object_initialize_child(obj, "prci", &s->prci, TYPE_SIFIVE_U_PRCI); object_initialize_child(obj, "otp", &s->otp, TYPE_SIFIVE_U_OTP); object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM); + object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO); } static void sifive_u_soc_realize(DeviceState *dev, Error **errp) @@ -600,6 +625,20 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->prci), &err); sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base); + qdev_prop_set_uint32(DEVICE(&s->gpio), "ngpio", 16); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_U_GPIO].base); + + /* Pass all GPIOs to the SOC layer so they are available to the board */ + qdev_pass_gpios(DEVICE(&s->gpio), dev, NULL); + + /* Connect GPIO interrupts to the PLIC */ + for (i = 0; i < 16; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), i, + qdev_get_gpio_in(DEVICE(s->plic), + SIFIVE_U_GPIO_IRQ0 + i)); + } + qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial); sysbus_realize(SYS_BUS_DEVICE(&s->otp), &err); sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base); diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index 5f62cf5f85..b1399a90a6 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -22,6 +22,7 @@ #include "hw/net/cadence_gem.h" #include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_cpu.h" +#include "hw/riscv/sifive_gpio.h" #include "hw/riscv/sifive_u_prci.h" #include "hw/riscv/sifive_u_otp.h" @@ -40,6 +41,7 @@ typedef struct SiFiveUSoCState { RISCVHartArrayState u_cpus; DeviceState *plic; SiFiveUPRCIState prci; + SIFIVEGPIOState gpio; SiFiveUOTPState otp; CadenceGEMState gem; @@ -73,6 +75,7 @@ enum { SIFIVE_U_PRCI, SIFIVE_U_UART0, SIFIVE_U_UART1, + SIFIVE_U_GPIO, SIFIVE_U_OTP, SIFIVE_U_FLASH0, SIFIVE_U_DRAM, @@ -83,6 +86,22 @@ enum { enum { SIFIVE_U_UART0_IRQ = 4, SIFIVE_U_UART1_IRQ = 5, + SIFIVE_U_GPIO_IRQ0 = 7, + SIFIVE_U_GPIO_IRQ1 = 8, + SIFIVE_U_GPIO_IRQ2 = 9, + SIFIVE_U_GPIO_IRQ3 = 10, + SIFIVE_U_GPIO_IRQ4 = 11, + SIFIVE_U_GPIO_IRQ5 = 12, + SIFIVE_U_GPIO_IRQ6 = 13, + SIFIVE_U_GPIO_IRQ7 = 14, + SIFIVE_U_GPIO_IRQ8 = 15, + SIFIVE_U_GPIO_IRQ9 = 16, + SIFIVE_U_GPIO_IRQ10 = 17, + SIFIVE_U_GPIO_IRQ11 = 18, + SIFIVE_U_GPIO_IRQ12 = 19, + SIFIVE_U_GPIO_IRQ13 = 20, + SIFIVE_U_GPIO_IRQ14 = 21, + SIFIVE_U_GPIO_IRQ15 = 22, SIFIVE_U_GEM_IRQ = 0x35 }; From 621c1006d2d82da9f266f21ad8e887c38769a11b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 8 Jun 2020 07:17:37 -0700 Subject: [PATCH 1476/2595] hw/riscv: sifive_gpio: Do not blindly trigger output IRQs At present the GPIO output IRQs are triggered each time any GPIO register is written. However this is not correct. We should only trigger the output IRQ when the pin is configured as output enable. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591625864-31494-9-git-send-email-bmeng.cn@gmail.com Message-Id: <1591625864-31494-9-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_gpio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/riscv/sifive_gpio.c b/hw/riscv/sifive_gpio.c index 0d0fd2ba5e..aac6b44cac 100644 --- a/hw/riscv/sifive_gpio.c +++ b/hw/riscv/sifive_gpio.c @@ -76,7 +76,9 @@ static void update_state(SIFIVEGPIOState *s) actual_value = pull; } - qemu_set_irq(s->output[i], actual_value); + if (output_en) { + qemu_set_irq(s->output[i], actual_value); + } /* Input value */ ival = input_en && actual_value; From 5133ed17906d1116c7ce47fd49ae77373cd41e29 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 8 Jun 2020 07:17:38 -0700 Subject: [PATCH 1477/2595] hw/riscv: sifive_u: Add reset functionality The HiFive Unleashed board wires GPIO pin#10 to the input of the system reset signal. Let's set up the GPIO pin#10 and insert a "gpio-restart" device tree node so that reboot is now functional with QEMU 'sifive_u' machine. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591625864-31494-10-git-send-email-bmeng.cn@gmail.com Message-Id: <1591625864-31494-10-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index f6976a0d09..b9d2185c04 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -37,6 +37,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "hw/boards.h" +#include "hw/irq.h" #include "hw/loader.h" #include "hw/sysbus.h" #include "hw/char/serial.h" @@ -53,6 +54,7 @@ #include "net/eth.h" #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" +#include "sysemu/runstate.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" @@ -96,7 +98,7 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, uint32_t *cells; char *nodename; char ethclk_names[] = "pclk\0hclk"; - uint32_t plic_phandle, prci_phandle, phandle = 1; + uint32_t plic_phandle, prci_phandle, gpio_phandle, phandle = 1; uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle; fdt = s->fdt = create_device_tree(&s->fdt_size); @@ -270,9 +272,11 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(cells); g_free(nodename); + gpio_phandle = phandle++; nodename = g_strdup_printf("/soc/gpio@%lx", (long)memmap[SIFIVE_U_GPIO].base); qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", gpio_phandle); qemu_fdt_setprop_cells(fdt, nodename, "clocks", prci_phandle, PRCI_CLK_TLCLK); qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 2); @@ -292,6 +296,12 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,gpio0"); g_free(nodename); + nodename = g_strdup_printf("/gpio-restart"); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cells(fdt, nodename, "gpios", gpio_phandle, 10, 1); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "gpio-restart"); + g_free(nodename); + phy_phandle = phandle++; nodename = g_strdup_printf("/soc/ethernet@%lx", (long)memmap[SIFIVE_U_GEM].base); @@ -352,6 +362,14 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(nodename); } +static void sifive_u_machine_reset(void *opaque, int n, int level) +{ + /* gpio pin active low triggers reset */ + if (!level) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } +} + static void sifive_u_machine_init(MachineState *machine) { const struct MemmapEntry *memmap = sifive_u_memmap; @@ -380,6 +398,10 @@ static void sifive_u_machine_init(MachineState *machine) memory_region_add_subregion(system_memory, memmap[SIFIVE_U_FLASH0].base, flash0); + /* register gpio-restart */ + qdev_connect_gpio_out(DEVICE(&(s->soc.gpio)), 10, + qemu_allocate_irq(sifive_u_machine_reset, NULL, 0)); + /* create device tree */ create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline); From 3e9667cdaa7d552bad232b7da0e116c50e15b3b5 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 8 Jun 2020 07:17:39 -0700 Subject: [PATCH 1478/2595] hw/riscv: sifive_u: Rename serial property get/set functions to a generic name In prepration to add more properties to this machine, rename the existing serial property get/set functions to a generic name. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591625864-31494-11-git-send-email-bmeng.cn@gmail.com Message-Id: <1591625864-31494-11-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index b9d2185c04..6dac662910 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -478,14 +478,16 @@ static void sifive_u_machine_set_start_in_flash(Object *obj, bool value, Error * s->start_in_flash = value; } -static void sifive_u_machine_get_serial(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) +static void sifive_u_machine_get_uint32_prop(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) { visit_type_uint32(v, name, (uint32_t *)opaque, errp); } -static void sifive_u_machine_set_serial(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) +static void sifive_u_machine_set_uint32_prop(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) { visit_type_uint32(v, name, (uint32_t *)opaque, errp); } @@ -504,8 +506,8 @@ static void sifive_u_machine_instance_init(Object *obj) s->serial = OTP_SERIAL; object_property_add(obj, "serial", "uint32", - sifive_u_machine_get_serial, - sifive_u_machine_set_serial, NULL, &s->serial); + sifive_u_machine_get_uint32_prop, + sifive_u_machine_set_uint32_prop, NULL, &s->serial); object_property_set_description(obj, "serial", "Board serial number"); } From cfa32630d914373413c0b42faf756ccaabc4bbb9 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 8 Jun 2020 07:17:40 -0700 Subject: [PATCH 1479/2595] hw/riscv: sifive_u: Add a new property msel for MSEL pin state On SiFive FU540 SoC, the value stored at physical address 0x1000 stores the MSEL pin state that is used to control the next boot location that ROM codes jump to. Add a new property msel to sifive_u machine for this. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1591625864-31494-12-git-send-email-bmeng.cn@gmail.com Message-Id: <1591625864-31494-12-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 7 +++++++ include/hw/riscv/sifive_u.h | 1 + 2 files changed, 8 insertions(+) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 6dac662910..b04be42167 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -504,6 +504,13 @@ static void sifive_u_machine_instance_init(Object *obj) "Set on to tell QEMU's ROM to jump to " "flash. Otherwise QEMU will jump to DRAM"); + s->msel = 0; + object_property_add(obj, "msel", "uint32", + sifive_u_machine_get_uint32_prop, + sifive_u_machine_set_uint32_prop, NULL, &s->msel); + object_property_set_description(obj, "msel", + "Mode Select (MSEL[3:0]) pin state"); + s->serial = OTP_SERIAL; object_property_add(obj, "serial", "uint32", sifive_u_machine_get_uint32_prop, diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index b1399a90a6..f6d10ebfb6 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -63,6 +63,7 @@ typedef struct SiFiveUState { int fdt_size; bool start_in_flash; + uint32_t msel; uint32_t serial; } SiFiveUState; From e8905c6ce86f5023f6814abd7c72a809e5d018ec Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 15 Jun 2020 17:50:37 -0700 Subject: [PATCH 1480/2595] target/riscv: Rename IBEX CPU init routine Current IBEX CPU init routine name seems to be too generic. Since it uses a different reset vector from the generic one, it merits a dedicated name. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1592268641-7478-2-git-send-email-bmeng.cn@gmail.com Message-Id: <1592268641-7478-2-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index e867766cf0..5f034588ec 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -153,7 +153,7 @@ static void rvxx_imacu_nommu_cpu_init(Object *obj) #if defined(TARGET_RISCV32) -static void rv32_imcu_nommu_cpu_init(Object *obj) +static void rv32_ibex_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RV32 | RVI | RVM | RVC | RVU); @@ -577,7 +577,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), #if defined(TARGET_RISCV32) DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32_imcu_nommu_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32_ibex_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rvxx_imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32_imafcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rvxx_gcsu_priv1_10_0_cpu_init), From 495134b75cca3e6a34d4233113c5143439061771 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 15 Jun 2020 17:50:38 -0700 Subject: [PATCH 1481/2595] hw/riscv: sifive: Change SiFive E/U CPU reset vector to 0x1004 Per the SiFive manual, all E/U series CPU cores' reset vector is at 0x1004. Update our codes to match the hardware. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1592268641-7478-3-git-send-email-bmeng.cn@gmail.com Message-Id: <1592268641-7478-3-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_e.c | 10 ++++++---- hw/riscv/sifive_u.c | 6 +++--- target/riscv/cpu.c | 16 ++++++++-------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 01626820bb..0cb66ac4e2 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -95,14 +95,16 @@ static void sifive_e_machine_init(MachineState *machine) memmap[SIFIVE_E_DTIM].base, main_mem); /* Mask ROM reset vector */ - uint32_t reset_vec[2]; + uint32_t reset_vec[4]; if (s->revb) { - reset_vec[0] = 0x200102b7; /* 0x1000: lui t0,0x20010 */ + reset_vec[1] = 0x200102b7; /* 0x1004: lui t0,0x20010 */ } else { - reset_vec[0] = 0x204002b7; /* 0x1000: lui t0,0x20400 */ + reset_vec[1] = 0x204002b7; /* 0x1004: lui t0,0x20400 */ } - reset_vec[1] = 0x00028067; /* 0x1004: jr t0 */ + reset_vec[2] = 0x00028067; /* 0x1008: jr t0 */ + + reset_vec[0] = reset_vec[3] = 0; /* copy in the reset vector in little_endian byte order */ for (i = 0; i < sizeof(reset_vec) >> 2; i++) { diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index b04be42167..ed13bc043c 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -430,18 +430,18 @@ static void sifive_u_machine_init(MachineState *machine) /* reset vector */ uint32_t reset_vec[8] = { + 0x00000000, 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ - 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */ + 0x01c28593, /* addi a1, t0, %pcrel_lo(1b) */ 0xf1402573, /* csrr a0, mhartid */ #if defined(TARGET_RISCV32) 0x0182a283, /* lw t0, 24(t0) */ #elif defined(TARGET_RISCV64) - 0x0182b283, /* ld t0, 24(t0) */ + 0x0182e283, /* lwu t0, 24(t0) */ #endif 0x00028067, /* jr t0 */ 0x00000000, start_addr, /* start: .dword */ - 0x00000000, /* dtb: */ }; diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 5f034588ec..391a0b9eec 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -134,20 +134,20 @@ static void riscv_base_cpu_init(Object *obj) set_resetvec(env, DEFAULT_RSTVEC); } -static void rvxx_gcsu_priv1_10_0_cpu_init(Object *obj) +static void rvxx_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); - set_resetvec(env, DEFAULT_RSTVEC); + set_resetvec(env, 0x1004); } -static void rvxx_imacu_nommu_cpu_init(Object *obj) +static void rvxx_sifive_e_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RVXLEN | RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); - set_resetvec(env, DEFAULT_RSTVEC); + set_resetvec(env, 0x1004); qdev_prop_set_bit(DEVICE(obj), "mmu", false); } @@ -578,13 +578,13 @@ static const TypeInfo riscv_cpu_type_infos[] = { #if defined(TARGET_RISCV32) DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32_ibex_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rvxx_imacu_nommu_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rvxx_sifive_e_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32_imafcu_nommu_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rvxx_gcsu_priv1_10_0_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rvxx_sifive_u_cpu_init), #elif defined(TARGET_RISCV64) DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rvxx_imacu_nommu_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rvxx_gcsu_priv1_10_0_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rvxx_sifive_e_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rvxx_sifive_u_cpu_init), #endif }; From 17aad9f276953c1eaf0750faf4758fd2f5ebeb84 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 15 Jun 2020 17:50:39 -0700 Subject: [PATCH 1482/2595] hw/riscv: sifive_u: Support different boot source per MSEL pin state SiFive FU540 SoC supports booting from several sources, which are controlled using the Mode Select (MSEL[3:0]) pins on the chip. Typically, the boot process runs through several stages before it begins execution of user-provided programs. The SoC supports booting from memory-mapped QSPI flash, which is how start_in_flash property is used for at present. This matches MSEL = 1 configuration (QSPI0). Typical booting flows involve the Zeroth Stage Boot Loader (ZSBL). It's not necessary for QEMU to implement the full ZSBL ROM codes, because we know ZSBL downloads the next stage program into the L2 LIM at address 0x8000000 and executes from there. We can bypass the whole ZSBL execution and use "-bios" to load the next stage program directly if MSEL indicates a ZSBL booting flow. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1592268641-7478-4-git-send-email-bmeng.cn@gmail.com Message-Id: <1592268641-7478-4-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 39 +++++++++++++++++++++++++++++-------- include/hw/riscv/sifive_u.h | 6 ++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index ed13bc043c..eb767aa863 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -405,8 +405,34 @@ static void sifive_u_machine_init(MachineState *machine) /* create device tree */ create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline); - riscv_find_and_load_firmware(machine, BIOS_FILENAME, - memmap[SIFIVE_U_DRAM].base, NULL); + if (s->start_in_flash) { + /* + * If start_in_flash property is given, assign s->msel to a value + * that representing booting from QSPI0 memory-mapped flash. + * + * This also means that when both start_in_flash and msel properties + * are given, start_in_flash takes the precedence over msel. + * + * Note this is to keep backward compatibility not to break existing + * users that use start_in_flash property. + */ + s->msel = MSEL_MEMMAP_QSPI0_FLASH; + } + + switch (s->msel) { + case MSEL_MEMMAP_QSPI0_FLASH: + start_addr = memmap[SIFIVE_U_FLASH0].base; + break; + case MSEL_L2LIM_QSPI0_FLASH: + case MSEL_L2LIM_QSPI2_SD: + start_addr = memmap[SIFIVE_U_L2LIM].base; + break; + default: + start_addr = memmap[SIFIVE_U_DRAM].base; + break; + } + + riscv_find_and_load_firmware(machine, BIOS_FILENAME, start_addr, NULL); if (machine->kernel_filename) { uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename, @@ -424,13 +450,9 @@ static void sifive_u_machine_init(MachineState *machine) } } - if (s->start_in_flash) { - start_addr = memmap[SIFIVE_U_FLASH0].base; - } - /* reset vector */ uint32_t reset_vec[8] = { - 0x00000000, + s->msel, /* MSEL pin state */ 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ 0x01c28593, /* addi a1, t0, %pcrel_lo(1b) */ 0xf1402573, /* csrr a0, mhartid */ @@ -502,7 +524,8 @@ static void sifive_u_machine_instance_init(Object *obj) sifive_u_machine_set_start_in_flash); object_property_set_description(obj, "start-in-flash", "Set on to tell QEMU's ROM to jump to " - "flash. Otherwise QEMU will jump to DRAM"); + "flash. Otherwise QEMU will jump to DRAM " + "or L2LIM depending on the msel value"); s->msel = 0; object_property_add(obj, "msel", "uint32", diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index f6d10ebfb6..27dc35e0a3 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -111,6 +111,12 @@ enum { SIFIVE_U_RTCCLK_FREQ = 1000000 }; +enum { + MSEL_MEMMAP_QSPI0_FLASH = 1, + MSEL_L2LIM_QSPI0_FLASH = 6, + MSEL_L2LIM_QSPI2_SD = 11 +}; + #define SIFIVE_U_MANAGEMENT_CPU_COUNT 1 #define SIFIVE_U_COMPUTE_CPU_COUNT 4 From 49093916d37f663e86316ec54cb77d5515bb973f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 15 Jun 2020 17:50:40 -0700 Subject: [PATCH 1483/2595] hw/riscv: sifive_u: Sort the SoC memmap table entries Move the flash and DRAM to the end of the SoC memmap table. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1592268641-7478-5-git-send-email-bmeng.cn@gmail.com Message-Id: <1592268641-7478-5-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index eb767aa863..b9d0a6901a 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -80,10 +80,10 @@ static const struct MemmapEntry { [SIFIVE_U_UART1] = { 0x10011000, 0x1000 }, [SIFIVE_U_GPIO] = { 0x10060000, 0x1000 }, [SIFIVE_U_OTP] = { 0x10070000, 0x1000 }, - [SIFIVE_U_FLASH0] = { 0x20000000, 0x10000000 }, - [SIFIVE_U_DRAM] = { 0x80000000, 0x0 }, [SIFIVE_U_GEM] = { 0x10090000, 0x2000 }, [SIFIVE_U_GEM_MGMT] = { 0x100a0000, 0x1000 }, + [SIFIVE_U_FLASH0] = { 0x20000000, 0x10000000 }, + [SIFIVE_U_DRAM] = { 0x80000000, 0x0 }, }; #define OTP_SERIAL 1 From 3eaea6eb4e534f7b87c6eca808149bb671976800 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 15 Jun 2020 17:50:41 -0700 Subject: [PATCH 1484/2595] hw/riscv: sifive_u: Add a dummy DDR memory controller device It is enough to simply map the SiFive FU540 DDR memory controller into the MMIO space using create_unimplemented_device(), to make the upstream U-Boot v2020.07 DDR memory initialization codes happy. Note we do not generate device tree fragment for the DDR memory controller. Since the controller data in device tree consumes a very large space (see fu540-hifive-unleashed-a00-ddr.dtsi in the U-Boot source), and it is only needed by U-Boot SPL but not any operating system, we choose not to generate the fragment here. This also means when testing with U-Boot SPL, the device tree has to come from U-Boot SPL itself, but not the one generated by QEMU on the fly. The memory has to be set to 8GiB to match the real HiFive Unleashed board when invoking QEMU (-m 8G). With this commit, QEMU can boot U-Boot SPL built for SiFive FU540 all the way up to loading U-Boot proper from MMC: $ qemu-system-riscv64 -nographic -M sifive_u,msel=6 -m 8G -bios u-boot-spl.bin U-Boot SPL 2020.07-rc3-00208-g88bd5b1 (Jun 08 2020 - 20:16:10 +0800) Trying to boot from MMC1 Unhandled exception: Load access fault EPC: 0000000008009be6 TVAL: 0000000010050014 The above exception is expected because QSPI is unsupported yet. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 1592268641-7478-6-git-send-email-bmeng.cn@gmail.com Message-Id: <1592268641-7478-6-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 4 ++++ include/hw/riscv/sifive_u.h | 1 + 2 files changed, 5 insertions(+) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index b9d0a6901a..7d051e7c92 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -82,6 +82,7 @@ static const struct MemmapEntry { [SIFIVE_U_OTP] = { 0x10070000, 0x1000 }, [SIFIVE_U_GEM] = { 0x10090000, 0x2000 }, [SIFIVE_U_GEM_MGMT] = { 0x100a0000, 0x1000 }, + [SIFIVE_U_DMC] = { 0x100b0000, 0x10000 }, [SIFIVE_U_FLASH0] = { 0x20000000, 0x10000000 }, [SIFIVE_U_DRAM] = { 0x80000000, 0x0 }, }; @@ -714,6 +715,9 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) create_unimplemented_device("riscv.sifive.u.gem-mgmt", memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size); + + create_unimplemented_device("riscv.sifive.u.dmc", + memmap[SIFIVE_U_DMC].base, memmap[SIFIVE_U_DMC].size); } static Property sifive_u_soc_props[] = { diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index 27dc35e0a3..aba4d0181f 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -78,6 +78,7 @@ enum { SIFIVE_U_UART1, SIFIVE_U_GPIO, SIFIVE_U_OTP, + SIFIVE_U_DMC, SIFIVE_U_FLASH0, SIFIVE_U_DRAM, SIFIVE_U_GEM, From 06c4cc3660b366278bdc7bc8b6677032d7b1118c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 17 Jun 2020 13:13:09 -0700 Subject: [PATCH 1485/2595] qht: Fix threshold rate calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tests/qht-bench.c:287:29: error: implicit conversion from 'unsigned long' to 'double' changes value from 18446744073709551615 to 18446744073709551616 [-Werror,-Wimplicit-int-float-conversion] *threshold = rate * UINT64_MAX; ~ ^~~~~~~~~~ Fix this by splitting the 64-bit constant into two halves, each of which is individually perfectly representable, the sum of which produces the correct arithmetic result. This is very likely just a sticking plaster over some underlying incorrect code, but it will suppress the warning for the moment. Cc: Emilio G. Cota Reported-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- tests/qht-bench.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/qht-bench.c b/tests/qht-bench.c index e3b512f26f..eb88a90137 100644 --- a/tests/qht-bench.c +++ b/tests/qht-bench.c @@ -284,7 +284,8 @@ static void do_threshold(double rate, uint64_t *threshold) if (rate == 1.0) { *threshold = UINT64_MAX; } else { - *threshold = rate * UINT64_MAX; + *threshold = (rate * 0xffff000000000000ull) + + (rate * 0x0000ffffffffffffull); } } From 6634f1c43d0e2f26ab2cc71d1f53a25c5b56bdd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 29 Jan 2020 17:45:05 +0100 Subject: [PATCH 1486/2595] MAINTAINERS: Add an entry to review Avocado based acceptance tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acceptance tests can test any piece of the QEMU codebase. As such, the directory holding them does not belong to a specific subsystem with designated maintainers. Each subsystem covered by a test is welcomed to add the test path to its section. See for example commits 71b290e70, b11785ca2 or 5d480ddde. Add an entry for to allow reviewers to be notified when acceptance / integration tests are added or modified. The designated reviewers are not maintainers, subsystem maintainers are expected to merge their tests. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Eduardo Habkost Acked-by: Cleber Rosa Message-Id: <20200129212345.20547-30-philmd@redhat.com> Message-Id: <20200605165656.17578-1-philmd@redhat.com> --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 955cc8dd5c..7b1262e925 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2941,6 +2941,14 @@ S: Maintained F: tests/tcg/Makefile F: tests/tcg/Makefile.include +Acceptance (Integration) Testing with the Avocado framework +W: https://trello.com/b/6Qi1pxVn/avocado-qemu +R: Cleber Rosa +R: Philippe Mathieu-Daudé +R: Wainer dos Santos Moschetta +S: Odd Fixes +F: tests/acceptance/ + Documentation ------------- Build system architecture From c7ebab0f16fd4e0dc3dd6d9c7ea73876a9db88f5 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 29 May 2020 10:04:51 +0300 Subject: [PATCH 1487/2595] tests/acceptance: add base class record/replay kernel tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a base for testing kernel boot recording and replaying. Each test has the phase of recording and phase of replaying. Virtual machines just boot the kernel and do not interact with the network. Structure and image links for the tests are borrowed from boot_linux_console.py Testing controls the message pattern at the end of the kernel boot for both record and replay modes. In replay mode QEMU is also intended to finish the execution automatically. Signed-off-by: Pavel Dovgalyuk Tested-by: Philippe Mathieu-Daude Message-Id: <159073589099.20809.14078431743098373301.stgit@pasha-ThinkPad-X280> Reviewed-by: Philippe Mathieu-Daudé [PMD: Keep imports sorted alphabetically] Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 1 + tests/acceptance/replay_kernel.py | 73 +++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 tests/acceptance/replay_kernel.py diff --git a/MAINTAINERS b/MAINTAINERS index 7b1262e925..dc61830c64 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2534,6 +2534,7 @@ F: net/filter-replay.c F: include/sysemu/replay.h F: docs/replay.txt F: stubs/replay.c +F: tests/acceptance/replay_kernel.py IOVA Tree M: Peter Xu diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py new file mode 100644 index 0000000000..90986ca503 --- /dev/null +++ b/tests/acceptance/replay_kernel.py @@ -0,0 +1,73 @@ +# Record/replay test that boots a Linux kernel +# +# Copyright (c) 2020 ISP RAS +# +# Author: +# Pavel Dovgalyuk +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +import os +import logging +import time + +from avocado_qemu import wait_for_console_pattern +from avocado.utils import archive +from avocado.utils import process +from boot_linux_console import LinuxKernelTest + +class ReplayKernel(LinuxKernelTest): + """ + Boots a Linux kernel in record mode and checks that the console + is operational and the kernel command line is properly passed + from QEMU to the kernel. + Then replays the same scenario and verifies, that QEMU correctly + terminates. + """ + + timeout = 90 + KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 ' + + def run_vm(self, kernel_path, kernel_command_line, console_pattern, + record, shift, args, replay_path): + logger = logging.getLogger('replay') + start_time = time.time() + vm = self.get_vm() + vm.set_console() + if record: + logger.info('recording the execution...') + mode = 'record' + else: + logger.info('replaying the execution...') + mode = 'replay' + vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' % + (shift, mode, replay_path), + '-kernel', kernel_path, + '-append', kernel_command_line, + '-net', 'none', + '-no-reboot') + if args: + vm.add_args(*args) + vm.launch() + self.wait_for_console_pattern(console_pattern, vm) + if record: + vm.shutdown() + logger.info('finished the recording with log size %s bytes' + % os.path.getsize(replay_path)) + else: + vm.wait() + logger.info('successfully finished the replay') + elapsed = time.time() - start_time + logger.info('elapsed time %.2f sec' % elapsed) + return elapsed + + def run_rr(self, kernel_path, kernel_command_line, console_pattern, + shift=7, args=None): + replay_path = os.path.join(self.workdir, 'replay.bin') + t1 = self.run_vm(kernel_path, kernel_command_line, console_pattern, + True, shift, args, replay_path) + t2 = self.run_vm(kernel_path, kernel_command_line, console_pattern, + False, shift, args, replay_path) + logger = logging.getLogger('replay') + logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1)) From 904be130b21f21b0aa0e8a9210dfda7b80278b28 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 29 May 2020 10:04:56 +0300 Subject: [PATCH 1488/2595] tests/acceptance: add kernel record/replay test for x86_64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a test for record/replay an execution of x86_64 machine. Execution scenario includes simple kernel boot, which allows testing basic hardware interaction in RR mode. Signed-off-by: Pavel Dovgalyuk Tested-by: Philippe Mathieu-Daude Message-Id: <159073589656.20809.14010247947948822435.stgit@pasha-ThinkPad-X280> Reviewed-by: Philippe Mathieu-Daudé [PMD: Skip test_x86_64_pc on Travis-CI] Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/replay_kernel.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py index 90986ca503..64956e85f1 100644 --- a/tests/acceptance/replay_kernel.py +++ b/tests/acceptance/replay_kernel.py @@ -12,6 +12,7 @@ import os import logging import time +from avocado import skipIf from avocado_qemu import wait_for_console_pattern from avocado.utils import archive from avocado.utils import process @@ -71,3 +72,20 @@ class ReplayKernel(LinuxKernelTest): False, shift, args, replay_path) logger = logging.getLogger('replay') logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1)) + + @skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI') + def test_x86_64_pc(self): + """ + :avocado: tags=arch:x86_64 + :avocado: tags=machine:pc + """ + kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' + '/linux/releases/29/Everything/x86_64/os/images/pxeboot' + '/vmlinuz') + kernel_hash = '23bebd2680757891cf7adedb033532163a792495' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0' + console_pattern = 'VFS: Cannot open root device' + + self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) From 152a41b774df3adc20fa968260306c13431d543f Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 29 May 2020 10:05:02 +0300 Subject: [PATCH 1489/2595] tests/acceptance: add record/replay test for aarch64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a test for record/replay of the kernel image boot for aarch64 platform. Signed-off-by: Pavel Dovgalyuk Tested-by: Philippe Mathieu-Daude Message-Id: <159073590231.20809.9842179251741585482.stgit@pasha-ThinkPad-X280> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/replay_kernel.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py index 64956e85f1..60559a13ad 100644 --- a/tests/acceptance/replay_kernel.py +++ b/tests/acceptance/replay_kernel.py @@ -89,3 +89,22 @@ class ReplayKernel(LinuxKernelTest): console_pattern = 'VFS: Cannot open root device' self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) + + def test_aarch64_virt(self): + """ + :avocado: tags=arch:aarch64 + :avocado: tags=machine:virt + :avocado: tags=cpu:cortex-a53 + """ + kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' + '/linux/releases/29/Everything/aarch64/os/images/pxeboot' + '/vmlinuz') + kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyAMA0') + console_pattern = 'VFS: Cannot open root device' + + self.run_rr(kernel_path, kernel_command_line, console_pattern, + args=('-cpu', 'cortex-a53')) From 2f2d83ad2e588e85ad0e7e9ab24ef62af694f34f Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 29 May 2020 10:05:07 +0300 Subject: [PATCH 1490/2595] tests/acceptance: add record/replay test for arm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a test for record/replay of the kernel image boot for two different arm platforms. Signed-off-by: Pavel Dovgalyuk Tested-by: Philippe Mathieu-Daude Message-Id: <159073590785.20809.17654573764167037499.stgit@pasha-ThinkPad-X280> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/replay_kernel.py | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py index 60559a13ad..748c780575 100644 --- a/tests/acceptance/replay_kernel.py +++ b/tests/acceptance/replay_kernel.py @@ -108,3 +108,51 @@ class ReplayKernel(LinuxKernelTest): self.run_rr(kernel_path, kernel_command_line, console_pattern, args=('-cpu', 'cortex-a53')) + + def test_arm_virt(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:virt + """ + kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' + '/linux/releases/29/Everything/armhfp/os/images/pxeboot' + '/vmlinuz') + kernel_hash = 'e9826d741b4fb04cadba8d4824d1ed3b7fb8b4d4' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyAMA0') + console_pattern = 'VFS: Cannot open root device' + + self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1) + + def test_arm_cubieboard_initrd(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:cubieboard + """ + deb_url = ('https://apt.armbian.com/pool/main/l/' + 'linux-4.20.7-sunxi/linux-image-dev-sunxi_5.75_armhf.deb') + deb_hash = '1334c29c44d984ffa05ed10de8c3361f33d78315' + deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash) + kernel_path = self.extract_from_deb(deb_path, + '/boot/vmlinuz-4.20.7-sunxi') + dtb_path = '/usr/lib/linux-image-dev-sunxi/sun4i-a10-cubieboard.dtb' + dtb_path = self.extract_from_deb(deb_path, dtb_path) + initrd_url = ('https://github.com/groeck/linux-build-test/raw/' + '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/' + 'arm/rootfs-armv5.cpio.gz') + initrd_hash = '2b50f1873e113523967806f4da2afe385462ff9b' + initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash) + initrd_path = os.path.join(self.workdir, 'rootfs.cpio') + archive.gzip_uncompress(initrd_path_gz, initrd_path) + + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyS0,115200 ' + 'usbcore.nousb ' + 'panic=-1 noreboot') + console_pattern = 'Boot successful.' + self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1, + args=('-dtb', dtb_path, + '-initrd', initrd_path, + '-no-reboot')) From 2e1206b9cb03894e824e1eaa2a81a0248b4abcba Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 29 May 2020 10:05:13 +0300 Subject: [PATCH 1491/2595] tests/acceptance: add record/replay test for ppc64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a test for record/replay of the kernel image boot for ppc64 platform. Signed-off-by: Pavel Dovgalyuk Tested-by: Philippe Mathieu-Daude Message-Id: <159073591363.20809.15658672985367330140.stgit@pasha-ThinkPad-X280> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/replay_kernel.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py index 748c780575..b7acc4bc71 100644 --- a/tests/acceptance/replay_kernel.py +++ b/tests/acceptance/replay_kernel.py @@ -156,3 +156,19 @@ class ReplayKernel(LinuxKernelTest): args=('-dtb', dtb_path, '-initrd', initrd_path, '-no-reboot')) + + def test_ppc64_pseries(self): + """ + :avocado: tags=arch:ppc64 + :avocado: tags=machine:pseries + """ + kernel_url = ('https://archives.fedoraproject.org/pub/archive' + '/fedora-secondary/releases/29/Everything/ppc64le/os' + '/ppc/ppc64/vmlinuz') + kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=hvc0' + # icount is not good enough for PPC64 for complete boot yet + console_pattern = 'Kernel command line: %s' % kernel_command_line + self.run_rr(kernel_path, kernel_command_line, console_pattern) From 20b1bf2ea907a69d64ba50d3c737bba95231fc8d Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 29 May 2020 10:05:20 +0300 Subject: [PATCH 1492/2595] tests/acceptance: add record/replay test for m68k MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a test for record/replay of the kernel image boot for m68k platform. Signed-off-by: Pavel Dovgalyuk Tested-by: Philippe Mathieu-Daude Reviewed-by: Laurent Vivier Message-Id: <159073592033.20809.1838967871297177313.stgit@pasha-ThinkPad-X280> Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/replay_kernel.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py index b7acc4bc71..8ef4e499b7 100644 --- a/tests/acceptance/replay_kernel.py +++ b/tests/acceptance/replay_kernel.py @@ -172,3 +172,21 @@ class ReplayKernel(LinuxKernelTest): # icount is not good enough for PPC64 for complete boot yet console_pattern = 'Kernel command line: %s' % kernel_command_line self.run_rr(kernel_path, kernel_command_line, console_pattern) + + def test_m68k_q800(self): + """ + :avocado: tags=arch:m68k + :avocado: tags=machine:q800 + """ + deb_url = ('https://snapshot.debian.org/archive/debian-ports' + '/20191021T083923Z/pool-m68k/main' + '/l/linux/kernel-image-5.3.0-1-m68k-di_5.3.7-1_m68k.udeb') + deb_hash = '044954bb9be4160a3ce81f8bc1b5e856b75cccd1' + deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash) + kernel_path = self.extract_from_deb(deb_path, + '/boot/vmlinux-5.3.0-1-m68k') + + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyS0 vga=off') + console_pattern = 'No filesystem could mount root' + self.run_rr(kernel_path, kernel_command_line, console_pattern) From b52d7e216c663ae89c65d656faf3a80b1c05737e Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 29 May 2020 10:05:25 +0300 Subject: [PATCH 1493/2595] tests/acceptance: record/replay tests with advcal images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds more record/replay tests with kernel images. Signed-off-by: Pavel Dovgalyuk Tested-by: Philippe Mathieu-Daude Message-Id: <159073592589.20809.5156301499042635614.stgit@pasha-ThinkPad-X280> Reviewed-by: Philippe Mathieu-Daudé [PMD: Use os.path.join(), add avocado 'cpu' tags] Signed-off-by: Philippe Mathieu-Daudé --- tests/acceptance/replay_kernel.py | 108 ++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py index 8ef4e499b7..60621417dd 100644 --- a/tests/acceptance/replay_kernel.py +++ b/tests/acceptance/replay_kernel.py @@ -190,3 +190,111 @@ class ReplayKernel(LinuxKernelTest): 'console=ttyS0 vga=off') console_pattern = 'No filesystem could mount root' self.run_rr(kernel_path, kernel_command_line, console_pattern) + + def do_test_advcal_2018(self, file_path, kernel_name, args=None): + archive.extract(file_path, self.workdir) + + for entry in os.scandir(self.workdir): + if entry.name.startswith('day') and entry.is_dir(): + kernel_path = os.path.join(entry.path, kernel_name) + break + + kernel_command_line = '' + console_pattern = 'QEMU advent calendar' + self.run_rr(kernel_path, kernel_command_line, console_pattern, + args=args) + + def test_arm_vexpressa9(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:vexpress-a9 + """ + tar_hash = '32b7677ce8b6f1471fb0059865f451169934245b' + tar_url = ('https://www.qemu-advent-calendar.org' + '/2018/download/day16.tar.xz') + file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + dtb_path = self.workdir + '/day16/vexpress-v2p-ca9.dtb' + self.do_test_advcal_2018(file_path, 'winter.zImage', + args=('-dtb', dtb_path)) + + def test_m68k_mcf5208evb(self): + """ + :avocado: tags=arch:m68k + :avocado: tags=machine:mcf5208evb + """ + tar_hash = 'ac688fd00561a2b6ce1359f9ff6aa2b98c9a570c' + tar_url = ('https://www.qemu-advent-calendar.org' + '/2018/download/day07.tar.xz') + file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + self.do_test_advcal_2018(file_path, 'sanity-clause.elf') + + def test_microblaze_s3adsp1800(self): + """ + :avocado: tags=arch:microblaze + :avocado: tags=machine:petalogix-s3adsp1800 + """ + tar_hash = '08bf3e3bfb6b6c7ce1e54ab65d54e189f2caf13f' + tar_url = ('https://www.qemu-advent-calendar.org' + '/2018/download/day17.tar.xz') + file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + self.do_test_advcal_2018(file_path, 'ballerina.bin') + + def test_ppc64_e500(self): + """ + :avocado: tags=arch:ppc64 + :avocado: tags=machine:ppce500 + :avocado: tags=cpu:e5500 + """ + tar_hash = '6951d86d644b302898da2fd701739c9406527fe1' + tar_url = ('https://www.qemu-advent-calendar.org' + '/2018/download/day19.tar.xz') + file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + self.do_test_advcal_2018(file_path, 'uImage', ('-cpu', 'e5500')) + + def test_ppc_g3beige(self): + """ + :avocado: tags=arch:ppc + :avocado: tags=machine:g3beige + """ + tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc' + tar_url = ('https://www.qemu-advent-calendar.org' + '/2018/download/day15.tar.xz') + file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + self.do_test_advcal_2018(file_path, 'invaders.elf', + args=('-M', 'graphics=off')) + + def test_ppc_mac99(self): + """ + :avocado: tags=arch:ppc + :avocado: tags=machine:mac99 + """ + tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc' + tar_url = ('https://www.qemu-advent-calendar.org' + '/2018/download/day15.tar.xz') + file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + self.do_test_advcal_2018(file_path, 'invaders.elf', + args=('-M', 'graphics=off')) + + def test_sparc_ss20(self): + """ + :avocado: tags=arch:sparc + :avocado: tags=machine:SS-20 + """ + tar_hash = 'b18550d5d61c7615d989a06edace051017726a9f' + tar_url = ('https://www.qemu-advent-calendar.org' + '/2018/download/day11.tar.xz') + file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + self.do_test_advcal_2018(file_path, 'zImage.elf') + + def test_xtensa_lx60(self): + """ + :avocado: tags=arch:xtensa + :avocado: tags=machine:lx60 + :avocado: tags=cpu:dc233c + """ + tar_hash = '49e88d9933742f0164b60839886c9739cb7a0d34' + tar_url = ('https://www.qemu-advent-calendar.org' + '/2018/download/day02.tar.xz') + file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + self.do_test_advcal_2018(file_path, 'santas-sleigh-ride.elf', + args=('-cpu', 'dc233c')) From 8a3a81478dcc592518069125a6ad271fe5511b95 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sun, 21 Jun 2020 22:26:50 -0700 Subject: [PATCH 1494/2595] target/xtensa: drop gen_io_end call Since commit ba3e7926691e ("icount: clean up cpu_can_io at the entry to the block") it has been unnecessary for target code to call gen_io_end() after an IO instruction in icount mode; it is sufficient to call gen_io_start() before it and to force the end of the TB. Remaining call in xtensa target translator is for the opcodes that may change IRQ state. All of them end current TB, so gen_io_end is not needed. Drop gen_io_end call from the xtensa target translator. Signed-off-by: Max Filippov Reviewed-by: Peter Maydell --- target/xtensa/translate.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 4bc15252c8..6346b2eef0 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -595,9 +595,6 @@ static int gen_postprocess(DisasContext *dc, int slot) gen_io_start(); } gen_helper_check_interrupts(cpu_env); - if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } } #endif if (op_flags & XTENSA_OP_SYNC_REGISTER_WINDOW) { From 65b8dc2914c073d877e7c8804d1064fdfb5b5a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 10 Jun 2020 23:41:52 +0200 Subject: [PATCH 1495/2595] MAINTAINERS: Cover sh_intc files in the R2D/Shix machine sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 81527b94ad added hw/intc/sh_intc.c, but only to the R2D machine (it is also used by the Shix machine). Complete the previous commit by adding the header to the R2D section, and both source + header to the Shix section. Suggested-by: Thomas Huth Reviewed-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 63b3bb3266..a9c916024e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1265,12 +1265,15 @@ S: Maintained F: hw/sh4/r2d.c F: hw/intc/sh_intc.c F: hw/timer/sh_timer.c +F: include/hw/sh4/sh_intc.h Shix M: Yoshinori Sato R: Magnus Damm S: Odd Fixes F: hw/sh4/shix.c +F: hw/intc/sh_intc.c +F: include/hw/sh4/sh_intc.h SPARC Machines -------------- From 7bd0d13fa5669611d8a29abfe71fc7683c400d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 10 Jun 2020 23:32:38 +0200 Subject: [PATCH 1496/2595] MAINTAINERS: Add an entry for common Renesas peripherals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renesas peripherals are common to SH4/RX based MCUs. Their datasheets share common sections. It makes sense to maintain them altogether. Add the uncovered UART SCI peripheral. The current names are misleading (see the 'sh_' prefix). In another series we will remove these peripherals with the 'renesas_' prefix. Out of the scope of this change in MAINTAINERS. Cc: Magnus Damm Cc: Yoshinori Sato Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson --- MAINTAINERS | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a9c916024e..09333366a2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1264,7 +1264,6 @@ R: Magnus Damm S: Maintained F: hw/sh4/r2d.c F: hw/intc/sh_intc.c -F: hw/timer/sh_timer.c F: include/hw/sh4/sh_intc.h Shix @@ -1968,6 +1967,14 @@ F: hw/*/*xive* F: include/hw/*/*xive* F: docs/*/*xive* +Renesas peripherals +M: Yoshinori Sato +R: Magnus Damm +S: Maintained +F: hw/char/sh_serial.c +F: hw/timer/sh_timer.c +F: include/hw/sh4/sh.h + Subsystems ---------- Audio From ba2afd0eb2c5ca0b23feb347369660d0577c225f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 10:16:51 +0200 Subject: [PATCH 1497/2595] hw/sh4: Use MemoryRegion typedef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the MemoryRegion type defined in "qemu/typedefs.h", to keep the repository style consistent. Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé --- include/hw/sh4/sh.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/hw/sh4/sh.h b/include/hw/sh4/sh.h index 767a2df7e2..fe773cb01d 100644 --- a/include/hw/sh4/sh.h +++ b/include/hw/sh4/sh.h @@ -10,9 +10,8 @@ /* sh7750.c */ struct SH7750State; -struct MemoryRegion; -struct SH7750State *sh7750_init(SuperHCPU *cpu, struct MemoryRegion *sysmem); +struct SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem); typedef struct { /* The callback will be triggered if any of the designated lines change */ @@ -32,7 +31,7 @@ int sh7750_register_io_device(struct SH7750State *s, #define TMU012_FEAT_TOCR (1 << 0) #define TMU012_FEAT_3CHAN (1 << 1) #define TMU012_FEAT_EXTCLK (1 << 2) -void tmu012_init(struct MemoryRegion *sysmem, hwaddr base, +void tmu012_init(MemoryRegion *sysmem, hwaddr base, int feat, uint32_t freq, qemu_irq ch0_irq, qemu_irq ch1_irq, qemu_irq ch2_irq0, qemu_irq ch2_irq1); From 95f4dc444a99ea91534b4ac9237bdec3b2581588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 10:16:52 +0200 Subject: [PATCH 1498/2595] hw/sh4: Extract timer definitions to 'hw/timer/tmu012.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract timer definitions to 'hw/timer/tmu012.h'. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé --- hw/sh4/sh7750.c | 1 + hw/timer/sh_timer.c | 2 ++ include/hw/sh4/sh.h | 9 --------- include/hw/timer/tmu012.h | 23 +++++++++++++++++++++++ 4 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 include/hw/timer/tmu012.h diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c index d660714443..f8ac3ec6e3 100644 --- a/hw/sh4/sh7750.c +++ b/hw/sh4/sh7750.c @@ -30,6 +30,7 @@ #include "sh7750_regs.h" #include "sh7750_regnames.h" #include "hw/sh4/sh_intc.h" +#include "hw/timer/tmu012.h" #include "cpu.h" #include "exec/exec-all.h" diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c index 13c4051808..b9cbacf5d0 100644 --- a/hw/timer/sh_timer.c +++ b/hw/timer/sh_timer.c @@ -9,10 +9,12 @@ */ #include "qemu/osdep.h" +#include "exec/memory.h" #include "hw/hw.h" #include "hw/irq.h" #include "hw/sh4/sh.h" #include "qemu/timer.h" +#include "hw/timer/tmu012.h" #include "hw/ptimer.h" //#define DEBUG_TIMER diff --git a/include/hw/sh4/sh.h b/include/hw/sh4/sh.h index fe773cb01d..93f464bf4c 100644 --- a/include/hw/sh4/sh.h +++ b/include/hw/sh4/sh.h @@ -27,15 +27,6 @@ typedef struct { int sh7750_register_io_device(struct SH7750State *s, sh7750_io_device * device); -/* sh_timer.c */ -#define TMU012_FEAT_TOCR (1 << 0) -#define TMU012_FEAT_3CHAN (1 << 1) -#define TMU012_FEAT_EXTCLK (1 << 2) -void tmu012_init(MemoryRegion *sysmem, hwaddr base, - int feat, uint32_t freq, - qemu_irq ch0_irq, qemu_irq ch1_irq, - qemu_irq ch2_irq0, qemu_irq ch2_irq1); - /* sh_serial.c */ #define SH_SERIAL_FEAT_SCIF (1 << 0) diff --git a/include/hw/timer/tmu012.h b/include/hw/timer/tmu012.h new file mode 100644 index 0000000000..808ed8de1d --- /dev/null +++ b/include/hw/timer/tmu012.h @@ -0,0 +1,23 @@ +/* + * SuperH Timer + * + * Copyright (c) 2007 Magnus Damm + * + * This code is licensed under the GPL. + */ + +#ifndef HW_TIMER_TMU012_H +#define HW_TIMER_TMU012_H + +#include "exec/hwaddr.h" + +#define TMU012_FEAT_TOCR (1 << 0) +#define TMU012_FEAT_3CHAN (1 << 1) +#define TMU012_FEAT_EXTCLK (1 << 2) + +void tmu012_init(MemoryRegion *sysmem, hwaddr base, + int feat, uint32_t freq, + qemu_irq ch0_irq, qemu_irq ch1_irq, + qemu_irq ch2_irq0, qemu_irq ch2_irq1); + +#endif From f4d2382a9b6c3dca678d9d43b7f1e55d59ddd55d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 May 2020 10:16:53 +0200 Subject: [PATCH 1499/2595] hw/timer/sh_timer: Remove unused 'qemu/timer.h' include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unused "qemu/timer.h" include. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé --- hw/timer/sh_timer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c index b9cbacf5d0..bb0e1c8ee5 100644 --- a/hw/timer/sh_timer.c +++ b/hw/timer/sh_timer.c @@ -13,7 +13,6 @@ #include "hw/hw.h" #include "hw/irq.h" #include "hw/sh4/sh.h" -#include "qemu/timer.h" #include "hw/timer/tmu012.h" #include "hw/ptimer.h" From e78597cc457ff76119bfc8f78aa21b2e5092da92 Mon Sep 17 00:00:00 2001 From: Yoshinori Sato Date: Mon, 21 Jan 2019 22:15:57 +0900 Subject: [PATCH 1500/2595] hw/intc: RX62N interrupt controller (ICUa) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implementation supported only ICUa. Hardware manual. https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf Signed-off-by: Yoshinori Sato Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-Id: <20200224141923.82118-15-ysato@users.sourceforge.jp> [PMD: Fill VMStateField for migration, cover files in MAINTAINERS] Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 6 + hw/intc/Kconfig | 3 + hw/intc/Makefile.objs | 1 + hw/intc/rx_icu.c | 397 +++++++++++++++++++++++++++++++++++++++ include/hw/intc/rx_icu.h | 76 ++++++++ 5 files changed, 483 insertions(+) create mode 100644 hw/intc/rx_icu.c create mode 100644 include/hw/intc/rx_icu.h diff --git a/MAINTAINERS b/MAINTAINERS index 09333366a2..7109aa581b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1975,6 +1975,12 @@ F: hw/char/sh_serial.c F: hw/timer/sh_timer.c F: include/hw/sh4/sh.h +Renesas RX peripherals +M: Yoshinori Sato +S: Maintained +F: hw/intc/rx_icu.c +F: include/hw/intc/rx_icu.h + Subsystems ---------- Audio diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index a189d6fedd..f562342bab 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -61,3 +61,6 @@ config S390_FLIC_KVM config OMPIC bool + +config RX_ICU + bool diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index a61e6728fe..a4202636d4 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -20,6 +20,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_its_common.o common-obj-$(CONFIG_OPENPIC) += openpic.o +common-obj-$(CONFIG_RX_ICU) += rx_icu.o common-obj-y += intc.o obj-$(CONFIG_APIC) += apic.o apic_common.o diff --git a/hw/intc/rx_icu.c b/hw/intc/rx_icu.c new file mode 100644 index 0000000000..df4b6a8d22 --- /dev/null +++ b/hw/intc/rx_icu.c @@ -0,0 +1,397 @@ +/* + * RX Interrupt Control Unit + * + * Warning: Only ICUa is supported. + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * + * Copyright (c) 2019 Yoshinori Sato + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "hw/irq.h" +#include "hw/registerfields.h" +#include "hw/qdev-properties.h" +#include "hw/intc/rx_icu.h" +#include "migration/vmstate.h" + +REG8(IR, 0) + FIELD(IR, IR, 0, 1) +REG8(DTCER, 0x100) + FIELD(DTCER, DTCE, 0, 1) +REG8(IER, 0x200) +REG8(SWINTR, 0x2e0) + FIELD(SWINTR, SWINT, 0, 1) +REG16(FIR, 0x2f0) + FIELD(FIR, FVCT, 0, 8) + FIELD(FIR, FIEN, 15, 1) +REG8(IPR, 0x300) + FIELD(IPR, IPR, 0, 4) +REG8(DMRSR, 0x400) +REG8(IRQCR, 0x500) + FIELD(IRQCR, IRQMD, 2, 2) +REG8(NMISR, 0x580) + FIELD(NMISR, NMIST, 0, 1) + FIELD(NMISR, LVDST, 1, 1) + FIELD(NMISR, OSTST, 2, 1) +REG8(NMIER, 0x581) + FIELD(NMIER, NMIEN, 0, 1) + FIELD(NMIER, LVDEN, 1, 1) + FIELD(NMIER, OSTEN, 2, 1) +REG8(NMICLR, 0x582) + FIELD(NMICLR, NMICLR, 0, 1) + FIELD(NMICLR, OSTCLR, 2, 1) +REG8(NMICR, 0x583) + FIELD(NMICR, NMIMD, 3, 1) + +static void set_irq(RXICUState *icu, int n_IRQ, int req) +{ + if ((icu->fir & R_FIR_FIEN_MASK) && + (icu->fir & R_FIR_FVCT_MASK) == n_IRQ) { + qemu_set_irq(icu->_fir, req); + } else { + qemu_set_irq(icu->_irq, req); + } +} + +static uint16_t rxicu_level(RXICUState *icu, unsigned n) +{ + return (icu->ipr[icu->map[n]] << 8) | n; +} + +static void rxicu_request(RXICUState *icu, int n_IRQ) +{ + int enable; + + enable = icu->ier[n_IRQ / 8] & (1 << (n_IRQ & 7)); + if (n_IRQ > 0 && enable != 0 && atomic_read(&icu->req_irq) < 0) { + atomic_set(&icu->req_irq, n_IRQ); + set_irq(icu, n_IRQ, rxicu_level(icu, n_IRQ)); + } +} + +static void rxicu_set_irq(void *opaque, int n_IRQ, int level) +{ + RXICUState *icu = opaque; + struct IRQSource *src; + int issue; + + if (n_IRQ >= NR_IRQS) { + error_report("%s: IRQ %d out of range", __func__, n_IRQ); + return; + } + + src = &icu->src[n_IRQ]; + + level = (level != 0); + switch (src->sense) { + case TRG_LEVEL: + /* level-sensitive irq */ + issue = level; + src->level = level; + break; + case TRG_NEDGE: + issue = (level == 0 && src->level == 1); + src->level = level; + break; + case TRG_PEDGE: + issue = (level == 1 && src->level == 0); + src->level = level; + break; + case TRG_BEDGE: + issue = ((level ^ src->level) & 1); + src->level = level; + break; + default: + g_assert_not_reached(); + } + if (issue == 0 && src->sense == TRG_LEVEL) { + icu->ir[n_IRQ] = 0; + if (atomic_read(&icu->req_irq) == n_IRQ) { + /* clear request */ + set_irq(icu, n_IRQ, 0); + atomic_set(&icu->req_irq, -1); + } + return; + } + if (issue) { + icu->ir[n_IRQ] = 1; + rxicu_request(icu, n_IRQ); + } +} + +static void rxicu_ack_irq(void *opaque, int no, int level) +{ + RXICUState *icu = opaque; + int i; + int n_IRQ; + int max_pri; + + n_IRQ = atomic_read(&icu->req_irq); + if (n_IRQ < 0) { + return; + } + atomic_set(&icu->req_irq, -1); + if (icu->src[n_IRQ].sense != TRG_LEVEL) { + icu->ir[n_IRQ] = 0; + } + + max_pri = 0; + n_IRQ = -1; + for (i = 0; i < NR_IRQS; i++) { + if (icu->ir[i]) { + if (max_pri < icu->ipr[icu->map[i]]) { + n_IRQ = i; + max_pri = icu->ipr[icu->map[i]]; + } + } + } + + if (n_IRQ >= 0) { + rxicu_request(icu, n_IRQ); + } +} + +static uint64_t icu_read(void *opaque, hwaddr addr, unsigned size) +{ + RXICUState *icu = opaque; + int reg = addr & 0xff; + + if ((addr != A_FIR && size != 1) || + (addr == A_FIR && size != 2)) { + qemu_log_mask(LOG_GUEST_ERROR, "rx_icu: Invalid read size 0x%" + HWADDR_PRIX "\n", + addr); + return UINT64_MAX; + } + switch (addr) { + case A_IR ... A_IR + 0xff: + return icu->ir[reg] & R_IR_IR_MASK; + case A_DTCER ... A_DTCER + 0xff: + return icu->dtcer[reg] & R_DTCER_DTCE_MASK; + case A_IER ... A_IER + 0x1f: + return icu->ier[reg]; + case A_SWINTR: + return 0; + case A_FIR: + return icu->fir & (R_FIR_FIEN_MASK | R_FIR_FVCT_MASK); + case A_IPR ... A_IPR + 0x8f: + return icu->ipr[reg] & R_IPR_IPR_MASK; + case A_DMRSR: + case A_DMRSR + 4: + case A_DMRSR + 8: + case A_DMRSR + 12: + return icu->dmasr[reg >> 2]; + case A_IRQCR ... A_IRQCR + 0x1f: + return icu->src[64 + reg].sense << R_IRQCR_IRQMD_SHIFT; + case A_NMISR: + case A_NMICLR: + return 0; + case A_NMIER: + return icu->nmier; + case A_NMICR: + return icu->nmicr; + default: + qemu_log_mask(LOG_UNIMP, "rx_icu: Register 0x%" HWADDR_PRIX " " + "not implemented.\n", + addr); + break; + } + return UINT64_MAX; +} + +static void icu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + RXICUState *icu = opaque; + int reg = addr & 0xff; + + if ((addr != A_FIR && size != 1) || + (addr == A_FIR && size != 2)) { + qemu_log_mask(LOG_GUEST_ERROR, "rx_icu: Invalid write size at " + "0x%" HWADDR_PRIX "\n", + addr); + return; + } + switch (addr) { + case A_IR ... A_IR + 0xff: + if (icu->src[reg].sense != TRG_LEVEL && val == 0) { + icu->ir[reg] = 0; + } + break; + case A_DTCER ... A_DTCER + 0xff: + icu->dtcer[reg] = val & R_DTCER_DTCE_MASK; + qemu_log_mask(LOG_UNIMP, "rx_icu: DTC not implemented\n"); + break; + case A_IER ... A_IER + 0x1f: + icu->ier[reg] = val; + break; + case A_SWINTR: + if (val & R_SWINTR_SWINT_MASK) { + qemu_irq_pulse(icu->_swi); + } + break; + case A_FIR: + icu->fir = val & (R_FIR_FIEN_MASK | R_FIR_FVCT_MASK); + break; + case A_IPR ... A_IPR + 0x8f: + icu->ipr[reg] = val & R_IPR_IPR_MASK; + break; + case A_DMRSR: + case A_DMRSR + 4: + case A_DMRSR + 8: + case A_DMRSR + 12: + icu->dmasr[reg >> 2] = val; + qemu_log_mask(LOG_UNIMP, "rx_icu: DMAC not implemented\n"); + break; + case A_IRQCR ... A_IRQCR + 0x1f: + icu->src[64 + reg].sense = val >> R_IRQCR_IRQMD_SHIFT; + break; + case A_NMICLR: + break; + case A_NMIER: + icu->nmier |= val & (R_NMIER_NMIEN_MASK | + R_NMIER_LVDEN_MASK | + R_NMIER_OSTEN_MASK); + break; + case A_NMICR: + if ((icu->nmier & R_NMIER_NMIEN_MASK) == 0) { + icu->nmicr = val & R_NMICR_NMIMD_MASK; + } + break; + default: + qemu_log_mask(LOG_UNIMP, "rx_icu: Register 0x%" HWADDR_PRIX " " + "not implemented\n", + addr); + break; + } +} + +static const MemoryRegionOps icu_ops = { + .write = icu_write, + .read = icu_read, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 2, + }, + .valid = { + .min_access_size = 1, + .max_access_size = 2, + }, +}; + +static void rxicu_realize(DeviceState *dev, Error **errp) +{ + RXICUState *icu = RX_ICU(dev); + int i, j; + + if (icu->init_sense == NULL) { + qemu_log_mask(LOG_GUEST_ERROR, + "rx_icu: trigger-level property must be set."); + return; + } + for (i = j = 0; i < NR_IRQS; i++) { + if (icu->init_sense[j] == i) { + icu->src[i].sense = TRG_LEVEL; + if (j < icu->nr_sense) { + j++; + } + } else { + icu->src[i].sense = TRG_PEDGE; + } + } + icu->req_irq = -1; +} + +static void rxicu_init(Object *obj) +{ + SysBusDevice *d = SYS_BUS_DEVICE(obj); + RXICUState *icu = RX_ICU(obj); + + memory_region_init_io(&icu->memory, OBJECT(icu), &icu_ops, + icu, "rx-icu", 0x600); + sysbus_init_mmio(d, &icu->memory); + + qdev_init_gpio_in(DEVICE(d), rxicu_set_irq, NR_IRQS); + qdev_init_gpio_in_named(DEVICE(d), rxicu_ack_irq, "ack", 1); + sysbus_init_irq(d, &icu->_irq); + sysbus_init_irq(d, &icu->_fir); + sysbus_init_irq(d, &icu->_swi); +} + +static void rxicu_fini(Object *obj) +{ + RXICUState *icu = RX_ICU(obj); + g_free(icu->map); + g_free(icu->init_sense); +} + +static const VMStateDescription vmstate_rxicu = { + .name = "rx-icu", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(ir, RXICUState, NR_IRQS), + VMSTATE_UINT8_ARRAY(dtcer, RXICUState, NR_IRQS), + VMSTATE_UINT8_ARRAY(ier, RXICUState, NR_IRQS / 8), + VMSTATE_UINT8_ARRAY(ipr, RXICUState, 142), + VMSTATE_UINT8_ARRAY(dmasr, RXICUState, 4), + VMSTATE_UINT16(fir, RXICUState), + VMSTATE_UINT8(nmisr, RXICUState), + VMSTATE_UINT8(nmier, RXICUState), + VMSTATE_UINT8(nmiclr, RXICUState), + VMSTATE_UINT8(nmicr, RXICUState), + VMSTATE_INT16(req_irq, RXICUState), + VMSTATE_END_OF_LIST() + } +}; + +static Property rxicu_properties[] = { + DEFINE_PROP_ARRAY("ipr-map", RXICUState, nr_irqs, map, + qdev_prop_uint8, uint8_t), + DEFINE_PROP_ARRAY("trigger-level", RXICUState, nr_sense, init_sense, + qdev_prop_uint8, uint8_t), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rxicu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rxicu_realize; + dc->vmsd = &vmstate_rxicu; + device_class_set_props(dc, rxicu_properties); +} + +static const TypeInfo rxicu_info = { + .name = TYPE_RX_ICU, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RXICUState), + .instance_init = rxicu_init, + .instance_finalize = rxicu_fini, + .class_init = rxicu_class_init, +}; + +static void rxicu_register_types(void) +{ + type_register_static(&rxicu_info); +} + +type_init(rxicu_register_types) diff --git a/include/hw/intc/rx_icu.h b/include/hw/intc/rx_icu.h new file mode 100644 index 0000000000..7176015cd9 --- /dev/null +++ b/include/hw/intc/rx_icu.h @@ -0,0 +1,76 @@ +/* + * RX Interrupt Control Unit + * + * Copyright (c) 2019 Yoshinori Sato + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#ifndef HW_INTC_RX_ICU_H +#define HW_INTC_RX_ICU_H + +#include "hw/sysbus.h" + +enum TRG_MODE { + TRG_LEVEL = 0, + TRG_NEDGE = 1, /* Falling */ + TRG_PEDGE = 2, /* Raising */ + TRG_BEDGE = 3, /* Both */ +}; + +struct IRQSource { + enum TRG_MODE sense; + int level; +}; + +enum { + /* Software interrupt request */ + SWI = 27, + NR_IRQS = 256 +}; + +struct RXICUState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + MemoryRegion memory; + struct IRQSource src[NR_IRQS]; + uint32_t nr_irqs; + uint8_t *map; + uint32_t nr_sense; + uint8_t *init_sense; + + uint8_t ir[NR_IRQS]; + uint8_t dtcer[NR_IRQS]; + uint8_t ier[NR_IRQS / 8]; + uint8_t ipr[142]; + uint8_t dmasr[4]; + uint16_t fir; + uint8_t nmisr; + uint8_t nmier; + uint8_t nmiclr; + uint8_t nmicr; + int16_t req_irq; + qemu_irq _irq; + qemu_irq _fir; + qemu_irq _swi; +}; +typedef struct RXICUState RXICUState; + +#define TYPE_RX_ICU "rx-icu" +#define RX_ICU(obj) OBJECT_CHECK(RXICUState, (obj), TYPE_RX_ICU) + +#endif /* RX_ICU_H */ From 7adca78edaa91069f66e373f5b7e4e7d5fe14879 Mon Sep 17 00:00:00 2001 From: Yoshinori Sato Date: Wed, 20 Mar 2019 23:16:05 +0900 Subject: [PATCH 1501/2595] hw/timer: RX62N 8-Bit timer (TMR) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit renesas_tmr: 8bit timer modules. This part use many renesas's CPU. Hardware manual. https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf Signed-off-by: Yoshinori Sato Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-Id: <20200224141923.82118-16-ysato@users.sourceforge.jp> [PMD: Split from CMT, filled VMStateField for migration] Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 2 + hw/timer/Kconfig | 3 + hw/timer/Makefile.objs | 1 + hw/timer/renesas_tmr.c | 477 +++++++++++++++++++++++++++++++++ include/hw/timer/renesas_tmr.h | 55 ++++ 5 files changed, 538 insertions(+) create mode 100644 hw/timer/renesas_tmr.c create mode 100644 include/hw/timer/renesas_tmr.h diff --git a/MAINTAINERS b/MAINTAINERS index 7109aa581b..d803ed974e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1972,8 +1972,10 @@ M: Yoshinori Sato R: Magnus Damm S: Maintained F: hw/char/sh_serial.c +F: hw/timer/renesas_tmr.c F: hw/timer/sh_timer.c F: include/hw/sh4/sh.h +F: include/hw/timer/renesas_tmr.h Renesas RX peripherals M: Yoshinori Sato diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index 59b3f44d69..7039c2a686 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -35,3 +35,6 @@ config CMSDK_APB_TIMER config CMSDK_APB_DUALTIMER bool select PTIMER + +config RENESAS_TMR + bool diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index dece235fd7..44fb47a433 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -23,6 +23,7 @@ common-obj-$(CONFIG_OMAP) += omap_gptimer.o common-obj-$(CONFIG_OMAP) += omap_synctimer.o common-obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o common-obj-$(CONFIG_SH4) += sh_timer.o +common-obj-$(CONFIG_RENESAS_TMR) += renesas_tmr.o common-obj-$(CONFIG_DIGIC) += digic-timer.o common-obj-$(CONFIG_MIPS_CPS) += mips_gictimer.o diff --git a/hw/timer/renesas_tmr.c b/hw/timer/renesas_tmr.c new file mode 100644 index 0000000000..446f2eacdd --- /dev/null +++ b/hw/timer/renesas_tmr.c @@ -0,0 +1,477 @@ +/* + * Renesas 8bit timer + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * + * Copyright (c) 2019 Yoshinori Sato + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "hw/registerfields.h" +#include "hw/qdev-properties.h" +#include "hw/timer/renesas_tmr.h" +#include "migration/vmstate.h" + +REG8(TCR, 0) + FIELD(TCR, CCLR, 3, 2) + FIELD(TCR, OVIE, 5, 1) + FIELD(TCR, CMIEA, 6, 1) + FIELD(TCR, CMIEB, 7, 1) +REG8(TCSR, 2) + FIELD(TCSR, OSA, 0, 2) + FIELD(TCSR, OSB, 2, 2) + FIELD(TCSR, ADTE, 4, 2) +REG8(TCORA, 4) +REG8(TCORB, 6) +REG8(TCNT, 8) +REG8(TCCR, 10) + FIELD(TCCR, CKS, 0, 3) + FIELD(TCCR, CSS, 3, 2) + FIELD(TCCR, TMRIS, 7, 1) + +#define INTERNAL 0x01 +#define CASCADING 0x03 +#define CCLR_A 0x01 +#define CCLR_B 0x02 + +static const int clkdiv[] = {0, 1, 2, 8, 32, 64, 1024, 8192}; + +static uint8_t concat_reg(uint8_t *reg) +{ + return (reg[0] << 8) | reg[1]; +} + +static void update_events(RTMRState *tmr, int ch) +{ + uint16_t diff[TMR_NR_EVENTS], min; + int64_t next_time; + int i, event; + + if (tmr->tccr[ch] == 0) { + return ; + } + if (FIELD_EX8(tmr->tccr[ch], TCCR, CSS) == 0) { + /* external clock mode */ + /* event not happened */ + return ; + } + if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) == CASCADING) { + /* cascading mode */ + if (ch == 1) { + tmr->next[ch] = none; + return ; + } + diff[cmia] = concat_reg(tmr->tcora) - concat_reg(tmr->tcnt); + diff[cmib] = concat_reg(tmr->tcorb) - concat_reg(tmr->tcnt); + diff[ovi] = 0x10000 - concat_reg(tmr->tcnt); + } else { + /* separate mode */ + diff[cmia] = tmr->tcora[ch] - tmr->tcnt[ch]; + diff[cmib] = tmr->tcorb[ch] - tmr->tcnt[ch]; + diff[ovi] = 0x100 - tmr->tcnt[ch]; + } + /* Search for the most recently occurring event. */ + for (event = 0, min = diff[0], i = 1; i < none; i++) { + if (min > diff[i]) { + event = i; + min = diff[i]; + } + } + tmr->next[ch] = event; + next_time = diff[event]; + next_time *= clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)]; + next_time *= NANOSECONDS_PER_SECOND; + next_time /= tmr->input_freq; + next_time += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + timer_mod(&tmr->timer[ch], next_time); +} + +static int elapsed_time(RTMRState *tmr, int ch, int64_t delta) +{ + int divrate = clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)]; + int et; + + tmr->div_round[ch] += delta; + if (divrate > 0) { + et = tmr->div_round[ch] / divrate; + tmr->div_round[ch] %= divrate; + } else { + /* disble clock. so no update */ + et = 0; + } + return et; +} + +static uint16_t read_tcnt(RTMRState *tmr, unsigned size, int ch) +{ + int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int elapsed, ovf = 0; + uint16_t tcnt[2]; + uint32_t ret; + + delta = (now - tmr->tick) * NANOSECONDS_PER_SECOND / tmr->input_freq; + if (delta > 0) { + tmr->tick = now; + + if (FIELD_EX8(tmr->tccr[1], TCCR, CSS) == INTERNAL) { + /* timer1 count update */ + elapsed = elapsed_time(tmr, 1, delta); + if (elapsed >= 0x100) { + ovf = elapsed >> 8; + } + tcnt[1] = tmr->tcnt[1] + (elapsed & 0xff); + } + switch (FIELD_EX8(tmr->tccr[0], TCCR, CSS)) { + case INTERNAL: + elapsed = elapsed_time(tmr, 0, delta); + tcnt[0] = tmr->tcnt[0] + elapsed; + break; + case CASCADING: + if (ovf > 0) { + tcnt[0] = tmr->tcnt[0] + ovf; + } + break; + } + } else { + tcnt[0] = tmr->tcnt[0]; + tcnt[1] = tmr->tcnt[1]; + } + if (size == 1) { + return tcnt[ch]; + } else { + ret = 0; + ret = deposit32(ret, 0, 8, tcnt[1]); + ret = deposit32(ret, 8, 8, tcnt[0]); + return ret; + } +} + +static uint8_t read_tccr(uint8_t r) +{ + uint8_t tccr = 0; + tccr = FIELD_DP8(tccr, TCCR, TMRIS, + FIELD_EX8(r, TCCR, TMRIS)); + tccr = FIELD_DP8(tccr, TCCR, CSS, + FIELD_EX8(r, TCCR, CSS)); + tccr = FIELD_DP8(tccr, TCCR, CKS, + FIELD_EX8(r, TCCR, CKS)); + return tccr; +} + +static uint64_t tmr_read(void *opaque, hwaddr addr, unsigned size) +{ + RTMRState *tmr = opaque; + int ch = addr & 1; + uint64_t ret; + + if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) { + qemu_log_mask(LOG_GUEST_ERROR, "renesas_tmr: Invalid read size 0x%" + HWADDR_PRIX "\n", + addr); + return UINT64_MAX; + } + switch (addr & 0x0e) { + case A_TCR: + ret = 0; + ret = FIELD_DP8(ret, TCR, CCLR, + FIELD_EX8(tmr->tcr[ch], TCR, CCLR)); + ret = FIELD_DP8(ret, TCR, OVIE, + FIELD_EX8(tmr->tcr[ch], TCR, OVIE)); + ret = FIELD_DP8(ret, TCR, CMIEA, + FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)); + ret = FIELD_DP8(ret, TCR, CMIEB, + FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)); + return ret; + case A_TCSR: + ret = 0; + ret = FIELD_DP8(ret, TCSR, OSA, + FIELD_EX8(tmr->tcsr[ch], TCSR, OSA)); + ret = FIELD_DP8(ret, TCSR, OSB, + FIELD_EX8(tmr->tcsr[ch], TCSR, OSB)); + switch (ch) { + case 0: + ret = FIELD_DP8(ret, TCSR, ADTE, + FIELD_EX8(tmr->tcsr[ch], TCSR, ADTE)); + break; + case 1: /* CH1 ADTE unimplement always 1 */ + ret = FIELD_DP8(ret, TCSR, ADTE, 1); + break; + } + return ret; + case A_TCORA: + if (size == 1) { + return tmr->tcora[ch]; + } else if (ch == 0) { + return concat_reg(tmr->tcora); + } + case A_TCORB: + if (size == 1) { + return tmr->tcorb[ch]; + } else { + return concat_reg(tmr->tcorb); + } + case A_TCNT: + return read_tcnt(tmr, size, ch); + case A_TCCR: + if (size == 1) { + return read_tccr(tmr->tccr[ch]); + } else { + return read_tccr(tmr->tccr[0]) << 8 | read_tccr(tmr->tccr[1]); + } + default: + qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX + " not implemented\n", + addr); + break; + } + return UINT64_MAX; +} + +static void tmr_write_count(RTMRState *tmr, int ch, unsigned size, + uint8_t *reg, uint64_t val) +{ + if (size == 1) { + reg[ch] = val; + update_events(tmr, ch); + } else { + reg[0] = extract32(val, 8, 8); + reg[1] = extract32(val, 0, 8); + update_events(tmr, 0); + update_events(tmr, 1); + } +} + +static void tmr_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + RTMRState *tmr = opaque; + int ch = addr & 1; + + if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_tmr: Invalid write size 0x%" HWADDR_PRIX "\n", + addr); + return; + } + switch (addr & 0x0e) { + case A_TCR: + tmr->tcr[ch] = val; + break; + case A_TCSR: + tmr->tcsr[ch] = val; + break; + case A_TCORA: + tmr_write_count(tmr, ch, size, tmr->tcora, val); + break; + case A_TCORB: + tmr_write_count(tmr, ch, size, tmr->tcorb, val); + break; + case A_TCNT: + tmr_write_count(tmr, ch, size, tmr->tcnt, val); + break; + case A_TCCR: + tmr_write_count(tmr, ch, size, tmr->tccr, val); + break; + default: + qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX + " not implemented\n", + addr); + break; + } +} + +static const MemoryRegionOps tmr_ops = { + .write = tmr_write, + .read = tmr_read, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 2, + }, + .valid = { + .min_access_size = 1, + .max_access_size = 2, + }, +}; + +static void timer_events(RTMRState *tmr, int ch); + +static uint16_t issue_event(RTMRState *tmr, int ch, int sz, + uint16_t tcnt, uint16_t tcora, uint16_t tcorb) +{ + uint16_t ret = tcnt; + + switch (tmr->next[ch]) { + case none: + break; + case cmia: + if (tcnt >= tcora) { + if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_A) { + ret = tcnt - tcora; + } + if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)) { + qemu_irq_pulse(tmr->cmia[ch]); + } + if (sz == 8 && ch == 0 && + FIELD_EX8(tmr->tccr[1], TCCR, CSS) == CASCADING) { + tmr->tcnt[1]++; + timer_events(tmr, 1); + } + } + break; + case cmib: + if (tcnt >= tcorb) { + if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_B) { + ret = tcnt - tcorb; + } + if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)) { + qemu_irq_pulse(tmr->cmib[ch]); + } + } + break; + case ovi: + if ((tcnt >= (1 << sz)) && FIELD_EX8(tmr->tcr[ch], TCR, OVIE)) { + qemu_irq_pulse(tmr->ovi[ch]); + } + break; + default: + g_assert_not_reached(); + } + return ret; +} + +static void timer_events(RTMRState *tmr, int ch) +{ + uint16_t tcnt; + + tmr->tcnt[ch] = read_tcnt(tmr, 1, ch); + if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) != CASCADING) { + tmr->tcnt[ch] = issue_event(tmr, ch, 8, + tmr->tcnt[ch], + tmr->tcora[ch], + tmr->tcorb[ch]) & 0xff; + } else { + if (ch == 1) { + return ; + } + tcnt = issue_event(tmr, ch, 16, + concat_reg(tmr->tcnt), + concat_reg(tmr->tcora), + concat_reg(tmr->tcorb)); + tmr->tcnt[0] = (tcnt >> 8) & 0xff; + tmr->tcnt[1] = tcnt & 0xff; + } + update_events(tmr, ch); +} + +static void timer_event0(void *opaque) +{ + RTMRState *tmr = opaque; + + timer_events(tmr, 0); +} + +static void timer_event1(void *opaque) +{ + RTMRState *tmr = opaque; + + timer_events(tmr, 1); +} + +static void rtmr_reset(DeviceState *dev) +{ + RTMRState *tmr = RTMR(dev); + tmr->tcr[0] = tmr->tcr[1] = 0x00; + tmr->tcsr[0] = 0x00; + tmr->tcsr[1] = 0x10; + tmr->tcnt[0] = tmr->tcnt[1] = 0x00; + tmr->tcora[0] = tmr->tcora[1] = 0xff; + tmr->tcorb[0] = tmr->tcorb[1] = 0xff; + tmr->tccr[0] = tmr->tccr[1] = 0x00; + tmr->next[0] = tmr->next[1] = none; + tmr->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + +static void rtmr_init(Object *obj) +{ + SysBusDevice *d = SYS_BUS_DEVICE(obj); + RTMRState *tmr = RTMR(obj); + int i; + + memory_region_init_io(&tmr->memory, OBJECT(tmr), &tmr_ops, + tmr, "renesas-tmr", 0x10); + sysbus_init_mmio(d, &tmr->memory); + + for (i = 0; i < ARRAY_SIZE(tmr->ovi); i++) { + sysbus_init_irq(d, &tmr->cmia[i]); + sysbus_init_irq(d, &tmr->cmib[i]); + sysbus_init_irq(d, &tmr->ovi[i]); + } + timer_init_ns(&tmr->timer[0], QEMU_CLOCK_VIRTUAL, timer_event0, tmr); + timer_init_ns(&tmr->timer[1], QEMU_CLOCK_VIRTUAL, timer_event1, tmr); +} + +static const VMStateDescription vmstate_rtmr = { + .name = "rx-tmr", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT64(tick, RTMRState), + VMSTATE_UINT8_ARRAY(tcnt, RTMRState, TMR_CH), + VMSTATE_UINT8_ARRAY(tcora, RTMRState, TMR_CH), + VMSTATE_UINT8_ARRAY(tcorb, RTMRState, TMR_CH), + VMSTATE_UINT8_ARRAY(tcr, RTMRState, TMR_CH), + VMSTATE_UINT8_ARRAY(tccr, RTMRState, TMR_CH), + VMSTATE_UINT8_ARRAY(tcor, RTMRState, TMR_CH), + VMSTATE_UINT8_ARRAY(tcsr, RTMRState, TMR_CH), + VMSTATE_INT64_ARRAY(div_round, RTMRState, TMR_CH), + VMSTATE_UINT8_ARRAY(next, RTMRState, TMR_CH), + VMSTATE_TIMER_ARRAY(timer, RTMRState, TMR_CH), + VMSTATE_END_OF_LIST() + } +}; + +static Property rtmr_properties[] = { + DEFINE_PROP_UINT64("input-freq", RTMRState, input_freq, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rtmr_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_rtmr; + dc->reset = rtmr_reset; + device_class_set_props(dc, rtmr_properties); +} + +static const TypeInfo rtmr_info = { + .name = TYPE_RENESAS_TMR, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RTMRState), + .instance_init = rtmr_init, + .class_init = rtmr_class_init, +}; + +static void rtmr_register_types(void) +{ + type_register_static(&rtmr_info); +} + +type_init(rtmr_register_types) diff --git a/include/hw/timer/renesas_tmr.h b/include/hw/timer/renesas_tmr.h new file mode 100644 index 0000000000..cf3baa7a28 --- /dev/null +++ b/include/hw/timer/renesas_tmr.h @@ -0,0 +1,55 @@ +/* + * Renesas 8bit timer Object + * + * Copyright (c) 2018 Yoshinori Sato + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_TIMER_RENESAS_TMR_H +#define HW_TIMER_RENESAS_TMR_H + +#include "qemu/timer.h" +#include "hw/sysbus.h" + +#define TYPE_RENESAS_TMR "renesas-tmr" +#define RTMR(obj) OBJECT_CHECK(RTMRState, (obj), TYPE_RENESAS_TMR) + +enum timer_event { + cmia = 0, + cmib = 1, + ovi = 2, + none = 3, + TMR_NR_EVENTS = 4 +}; + +enum { + TMR_CH = 2, + TMR_NR_IRQ = 3 * TMR_CH +}; + +typedef struct RTMRState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + uint64_t input_freq; + MemoryRegion memory; + + int64_t tick; + uint8_t tcnt[TMR_CH]; + uint8_t tcora[TMR_CH]; + uint8_t tcorb[TMR_CH]; + uint8_t tcr[TMR_CH]; + uint8_t tccr[TMR_CH]; + uint8_t tcor[TMR_CH]; + uint8_t tcsr[TMR_CH]; + int64_t div_round[TMR_CH]; + uint8_t next[TMR_CH]; + qemu_irq cmia[TMR_CH]; + qemu_irq cmib[TMR_CH]; + qemu_irq ovi[TMR_CH]; + QEMUTimer timer[TMR_CH]; +} RTMRState; + +#endif From c7f37bafde83a73eedc3bd6e029abba745871dea Mon Sep 17 00:00:00 2001 From: Yoshinori Sato Date: Wed, 20 Mar 2019 23:16:05 +0900 Subject: [PATCH 1502/2595] hw/timer: RX62N compare match timer (CMT) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit renesas_cmt: 16bit compare match timer modules. This part use many renesas's CPU. Hardware manual. https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf Signed-off-by: Yoshinori Sato Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-Id: <20200224141923.82118-16-ysato@users.sourceforge.jp> [PMD: Split from TMR, filled VMStateField for migration] Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 4 +- hw/timer/Kconfig | 3 + hw/timer/Makefile.objs | 1 + hw/timer/renesas_cmt.c | 283 +++++++++++++++++++++++++++++++++ include/hw/timer/renesas_cmt.h | 40 +++++ 5 files changed, 329 insertions(+), 2 deletions(-) create mode 100644 hw/timer/renesas_cmt.c create mode 100644 include/hw/timer/renesas_cmt.h diff --git a/MAINTAINERS b/MAINTAINERS index d803ed974e..e4ade67a79 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1972,10 +1972,10 @@ M: Yoshinori Sato R: Magnus Damm S: Maintained F: hw/char/sh_serial.c -F: hw/timer/renesas_tmr.c +F: hw/timer/renesas_*.c F: hw/timer/sh_timer.c F: include/hw/sh4/sh.h -F: include/hw/timer/renesas_tmr.h +F: include/hw/timer/renesas_*.h Renesas RX peripherals M: Yoshinori Sato diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index 7039c2a686..59a667c503 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -38,3 +38,6 @@ config CMSDK_APB_DUALTIMER config RENESAS_TMR bool + +config RENESAS_CMT + bool diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index 44fb47a433..a39f6ec0c2 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -24,6 +24,7 @@ common-obj-$(CONFIG_OMAP) += omap_synctimer.o common-obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o common-obj-$(CONFIG_SH4) += sh_timer.o common-obj-$(CONFIG_RENESAS_TMR) += renesas_tmr.o +common-obj-$(CONFIG_RENESAS_CMT) += renesas_cmt.o common-obj-$(CONFIG_DIGIC) += digic-timer.o common-obj-$(CONFIG_MIPS_CPS) += mips_gictimer.o diff --git a/hw/timer/renesas_cmt.c b/hw/timer/renesas_cmt.c new file mode 100644 index 0000000000..2e0fd21a36 --- /dev/null +++ b/hw/timer/renesas_cmt.c @@ -0,0 +1,283 @@ +/* + * Renesas 16bit Compare-match timer + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * + * Copyright (c) 2019 Yoshinori Sato + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "hw/registerfields.h" +#include "hw/qdev-properties.h" +#include "hw/timer/renesas_cmt.h" +#include "migration/vmstate.h" + +/* + * +0 CMSTR - common control + * +2 CMCR - ch0 + * +4 CMCNT - ch0 + * +6 CMCOR - ch0 + * +8 CMCR - ch1 + * +10 CMCNT - ch1 + * +12 CMCOR - ch1 + * If we think that the address of CH 0 has an offset of +2, + * we can treat it with the same address as CH 1, so define it like that. + */ +REG16(CMSTR, 0) + FIELD(CMSTR, STR0, 0, 1) + FIELD(CMSTR, STR1, 1, 1) + FIELD(CMSTR, STR, 0, 2) +/* This addeess is channel offset */ +REG16(CMCR, 0) + FIELD(CMCR, CKS, 0, 2) + FIELD(CMCR, CMIE, 6, 1) +REG16(CMCNT, 2) +REG16(CMCOR, 4) + +static void update_events(RCMTState *cmt, int ch) +{ + int64_t next_time; + + if ((cmt->cmstr & (1 << ch)) == 0) { + /* count disable, so not happened next event. */ + return ; + } + next_time = cmt->cmcor[ch] - cmt->cmcnt[ch]; + next_time *= NANOSECONDS_PER_SECOND; + next_time /= cmt->input_freq; + /* + * CKS -> div rate + * 0 -> 8 (1 << 3) + * 1 -> 32 (1 << 5) + * 2 -> 128 (1 << 7) + * 3 -> 512 (1 << 9) + */ + next_time *= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2); + next_time += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + timer_mod(&cmt->timer[ch], next_time); +} + +static int64_t read_cmcnt(RCMTState *cmt, int ch) +{ + int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + if (cmt->cmstr & (1 << ch)) { + delta = (now - cmt->tick[ch]); + delta /= NANOSECONDS_PER_SECOND; + delta /= cmt->input_freq; + delta /= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2); + cmt->tick[ch] = now; + return cmt->cmcnt[ch] + delta; + } else { + return cmt->cmcnt[ch]; + } +} + +static uint64_t cmt_read(void *opaque, hwaddr offset, unsigned size) +{ + RCMTState *cmt = opaque; + int ch = offset / 0x08; + uint64_t ret; + + if (offset == A_CMSTR) { + ret = 0; + ret = FIELD_DP16(ret, CMSTR, STR, + FIELD_EX16(cmt->cmstr, CMSTR, STR)); + return ret; + } else { + offset &= 0x07; + if (ch == 0) { + offset -= 0x02; + } + switch (offset) { + case A_CMCR: + ret = 0; + ret = FIELD_DP16(ret, CMCR, CKS, + FIELD_EX16(cmt->cmstr, CMCR, CKS)); + ret = FIELD_DP16(ret, CMCR, CMIE, + FIELD_EX16(cmt->cmstr, CMCR, CMIE)); + return ret; + case A_CMCNT: + return read_cmcnt(cmt, ch); + case A_CMCOR: + return cmt->cmcor[ch]; + } + } + qemu_log_mask(LOG_UNIMP, "renesas_cmt: Register 0x%" HWADDR_PRIX " " + "not implemented\n", + offset); + return UINT64_MAX; +} + +static void start_stop(RCMTState *cmt, int ch, int st) +{ + if (st) { + update_events(cmt, ch); + } else { + timer_del(&cmt->timer[ch]); + } +} + +static void cmt_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) +{ + RCMTState *cmt = opaque; + int ch = offset / 0x08; + + if (offset == A_CMSTR) { + cmt->cmstr = FIELD_EX16(val, CMSTR, STR); + start_stop(cmt, 0, FIELD_EX16(cmt->cmstr, CMSTR, STR0)); + start_stop(cmt, 1, FIELD_EX16(cmt->cmstr, CMSTR, STR1)); + } else { + offset &= 0x07; + if (ch == 0) { + offset -= 0x02; + } + switch (offset) { + case A_CMCR: + cmt->cmcr[ch] = FIELD_DP16(cmt->cmcr[ch], CMCR, CKS, + FIELD_EX16(val, CMCR, CKS)); + cmt->cmcr[ch] = FIELD_DP16(cmt->cmcr[ch], CMCR, CMIE, + FIELD_EX16(val, CMCR, CMIE)); + break; + case 2: + cmt->cmcnt[ch] = val; + break; + case 4: + cmt->cmcor[ch] = val; + break; + default: + qemu_log_mask(LOG_UNIMP, "renesas_cmt: Register 0x%" HWADDR_PRIX " " + "not implemented\n", + offset); + return; + } + if (FIELD_EX16(cmt->cmstr, CMSTR, STR) & (1 << ch)) { + update_events(cmt, ch); + } + } +} + +static const MemoryRegionOps cmt_ops = { + .write = cmt_write, + .read = cmt_read, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 2, + .max_access_size = 2, + }, + .valid = { + .min_access_size = 2, + .max_access_size = 2, + }, +}; + +static void timer_events(RCMTState *cmt, int ch) +{ + cmt->cmcnt[ch] = 0; + cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + update_events(cmt, ch); + if (FIELD_EX16(cmt->cmcr[ch], CMCR, CMIE)) { + qemu_irq_pulse(cmt->cmi[ch]); + } +} + +static void timer_event0(void *opaque) +{ + RCMTState *cmt = opaque; + + timer_events(cmt, 0); +} + +static void timer_event1(void *opaque) +{ + RCMTState *cmt = opaque; + + timer_events(cmt, 1); +} + +static void rcmt_reset(DeviceState *dev) +{ + RCMTState *cmt = RCMT(dev); + cmt->cmstr = 0; + cmt->cmcr[0] = cmt->cmcr[1] = 0; + cmt->cmcnt[0] = cmt->cmcnt[1] = 0; + cmt->cmcor[0] = cmt->cmcor[1] = 0xffff; +} + +static void rcmt_init(Object *obj) +{ + SysBusDevice *d = SYS_BUS_DEVICE(obj); + RCMTState *cmt = RCMT(obj); + int i; + + memory_region_init_io(&cmt->memory, OBJECT(cmt), &cmt_ops, + cmt, "renesas-cmt", 0x10); + sysbus_init_mmio(d, &cmt->memory); + + for (i = 0; i < ARRAY_SIZE(cmt->cmi); i++) { + sysbus_init_irq(d, &cmt->cmi[i]); + } + timer_init_ns(&cmt->timer[0], QEMU_CLOCK_VIRTUAL, timer_event0, cmt); + timer_init_ns(&cmt->timer[1], QEMU_CLOCK_VIRTUAL, timer_event1, cmt); +} + +static const VMStateDescription vmstate_rcmt = { + .name = "rx-cmt", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT16(cmstr, RCMTState), + VMSTATE_UINT16_ARRAY(cmcr, RCMTState, CMT_CH), + VMSTATE_UINT16_ARRAY(cmcnt, RCMTState, CMT_CH), + VMSTATE_UINT16_ARRAY(cmcor, RCMTState, CMT_CH), + VMSTATE_INT64_ARRAY(tick, RCMTState, CMT_CH), + VMSTATE_TIMER_ARRAY(timer, RCMTState, CMT_CH), + VMSTATE_END_OF_LIST() + } +}; + +static Property rcmt_properties[] = { + DEFINE_PROP_UINT64("input-freq", RCMTState, input_freq, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rcmt_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_rcmt; + dc->reset = rcmt_reset; + device_class_set_props(dc, rcmt_properties); +} + +static const TypeInfo rcmt_info = { + .name = TYPE_RENESAS_CMT, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RCMTState), + .instance_init = rcmt_init, + .class_init = rcmt_class_init, +}; + +static void rcmt_register_types(void) +{ + type_register_static(&rcmt_info); +} + +type_init(rcmt_register_types) diff --git a/include/hw/timer/renesas_cmt.h b/include/hw/timer/renesas_cmt.h new file mode 100644 index 0000000000..e28a15cb38 --- /dev/null +++ b/include/hw/timer/renesas_cmt.h @@ -0,0 +1,40 @@ +/* + * Renesas Compare-match timer Object + * + * Copyright (c) 2019 Yoshinori Sato + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_TIMER_RENESAS_CMT_H +#define HW_TIMER_RENESAS_CMT_H + +#include "qemu/timer.h" +#include "hw/sysbus.h" + +#define TYPE_RENESAS_CMT "renesas-cmt" +#define RCMT(obj) OBJECT_CHECK(RCMTState, (obj), TYPE_RENESAS_CMT) + +enum { + CMT_CH = 2, + CMT_NR_IRQ = 1 * CMT_CH +}; + +typedef struct RCMTState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + uint64_t input_freq; + MemoryRegion memory; + + uint16_t cmstr; + uint16_t cmcr[CMT_CH]; + uint16_t cmcnt[CMT_CH]; + uint16_t cmcor[CMT_CH]; + int64_t tick[CMT_CH]; + qemu_irq cmi[CMT_CH]; + QEMUTimer timer[CMT_CH]; +} RCMTState; + +#endif From 645194c7aa8ff501cfdab864c9f5cdf220c3af76 Mon Sep 17 00:00:00 2001 From: Yoshinori Sato Date: Mon, 21 Jan 2019 22:15:59 +0900 Subject: [PATCH 1503/2595] hw/char: RX62N serial communication interface (SCI) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This module supported only non FIFO type. Hardware manual. https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf Signed-off-by: Yoshinori Sato Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-Id: <20200224141923.82118-17-ysato@users.sourceforge.jp> [PMD: Filled VMStateField for migration] Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 2 + hw/char/Kconfig | 3 + hw/char/Makefile.objs | 1 + hw/char/renesas_sci.c | 350 ++++++++++++++++++++++++++++++++++ include/hw/char/renesas_sci.h | 51 +++++ 5 files changed, 407 insertions(+) create mode 100644 hw/char/renesas_sci.c create mode 100644 include/hw/char/renesas_sci.h diff --git a/MAINTAINERS b/MAINTAINERS index e4ade67a79..e92150187c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1971,9 +1971,11 @@ Renesas peripherals M: Yoshinori Sato R: Magnus Damm S: Maintained +F: hw/char/renesas_sci.c F: hw/char/sh_serial.c F: hw/timer/renesas_*.c F: hw/timer/sh_timer.c +F: include/hw/char/renesas_sci.h F: include/hw/sh4/sh.h F: include/hw/timer/renesas_*.h diff --git a/hw/char/Kconfig b/hw/char/Kconfig index 40e7a8b8bb..874627520c 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig @@ -46,3 +46,6 @@ config SCLPCONSOLE config TERMINAL3270 bool + +config RENESAS_SCI + bool diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs index 633996be5b..8306c4a789 100644 --- a/hw/char/Makefile.objs +++ b/hw/char/Makefile.objs @@ -21,6 +21,7 @@ common-obj-$(CONFIG_SH4) += sh_serial.o common-obj-$(CONFIG_DIGIC) += digic-uart.o common-obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o common-obj-$(CONFIG_RASPI) += bcm2835_aux.o +common-obj-$(CONFIG_RENESAS_SCI) += renesas_sci.o common-obj-$(CONFIG_CMSDK_APB_UART) += cmsdk-apb-uart.o common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o diff --git a/hw/char/renesas_sci.c b/hw/char/renesas_sci.c new file mode 100644 index 0000000000..5d7c6e6523 --- /dev/null +++ b/hw/char/renesas_sci.c @@ -0,0 +1,350 @@ +/* + * Renesas Serial Communication Interface + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * + * Copyright (c) 2019 Yoshinori Sato + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "hw/registerfields.h" +#include "hw/qdev-properties.h" +#include "hw/char/renesas_sci.h" +#include "migration/vmstate.h" + +/* SCI register map */ +REG8(SMR, 0) + FIELD(SMR, CKS, 0, 2) + FIELD(SMR, MP, 2, 1) + FIELD(SMR, STOP, 3, 1) + FIELD(SMR, PM, 4, 1) + FIELD(SMR, PE, 5, 1) + FIELD(SMR, CHR, 6, 1) + FIELD(SMR, CM, 7, 1) +REG8(BRR, 1) +REG8(SCR, 2) + FIELD(SCR, CKE, 0, 2) + FIELD(SCR, TEIE, 2, 1) + FIELD(SCR, MPIE, 3, 1) + FIELD(SCR, RE, 4, 1) + FIELD(SCR, TE, 5, 1) + FIELD(SCR, RIE, 6, 1) + FIELD(SCR, TIE, 7, 1) +REG8(TDR, 3) +REG8(SSR, 4) + FIELD(SSR, MPBT, 0, 1) + FIELD(SSR, MPB, 1, 1) + FIELD(SSR, TEND, 2, 1) + FIELD(SSR, ERR, 3, 3) + FIELD(SSR, PER, 3, 1) + FIELD(SSR, FER, 4, 1) + FIELD(SSR, ORER, 5, 1) + FIELD(SSR, RDRF, 6, 1) + FIELD(SSR, TDRE, 7, 1) +REG8(RDR, 5) +REG8(SCMR, 6) + FIELD(SCMR, SMIF, 0, 1) + FIELD(SCMR, SINV, 2, 1) + FIELD(SCMR, SDIR, 3, 1) + FIELD(SCMR, BCP2, 7, 1) +REG8(SEMR, 7) + FIELD(SEMR, ACS0, 0, 1) + FIELD(SEMR, ABCS, 4, 1) + +static int can_receive(void *opaque) +{ + RSCIState *sci = RSCI(opaque); + if (sci->rx_next > qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) { + return 0; + } else { + return FIELD_EX8(sci->scr, SCR, RE); + } +} + +static void receive(void *opaque, const uint8_t *buf, int size) +{ + RSCIState *sci = RSCI(opaque); + sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime; + if (FIELD_EX8(sci->ssr, SSR, RDRF) || size > 1) { + sci->ssr = FIELD_DP8(sci->ssr, SSR, ORER, 1); + if (FIELD_EX8(sci->scr, SCR, RIE)) { + qemu_set_irq(sci->irq[ERI], 1); + } + } else { + sci->rdr = buf[0]; + sci->ssr = FIELD_DP8(sci->ssr, SSR, RDRF, 1); + if (FIELD_EX8(sci->scr, SCR, RIE)) { + qemu_irq_pulse(sci->irq[RXI]); + } + } +} + +static void send_byte(RSCIState *sci) +{ + if (qemu_chr_fe_backend_connected(&sci->chr)) { + qemu_chr_fe_write_all(&sci->chr, &sci->tdr, 1); + } + timer_mod(&sci->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime); + sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 0); + sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 1); + qemu_set_irq(sci->irq[TEI], 0); + if (FIELD_EX8(sci->scr, SCR, TIE)) { + qemu_irq_pulse(sci->irq[TXI]); + } +} + +static void txend(void *opaque) +{ + RSCIState *sci = RSCI(opaque); + if (!FIELD_EX8(sci->ssr, SSR, TDRE)) { + send_byte(sci); + } else { + sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1); + if (FIELD_EX8(sci->scr, SCR, TEIE)) { + qemu_set_irq(sci->irq[TEI], 1); + } + } +} + +static void update_trtime(RSCIState *sci) +{ + /* char per bits */ + sci->trtime = 8 - FIELD_EX8(sci->smr, SMR, CHR); + sci->trtime += FIELD_EX8(sci->smr, SMR, PE); + sci->trtime += FIELD_EX8(sci->smr, SMR, STOP) + 1; + /* x bit transmit time (32 * divrate * brr) / base freq */ + sci->trtime *= 32 * sci->brr; + sci->trtime *= 1 << (2 * FIELD_EX8(sci->smr, SMR, CKS)); + sci->trtime *= NANOSECONDS_PER_SECOND; + sci->trtime /= sci->input_freq; +} + +static bool sci_is_tr_enabled(RSCIState *sci) +{ + return FIELD_EX8(sci->scr, SCR, TE) || FIELD_EX8(sci->scr, SCR, RE); +} + +static void sci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) +{ + RSCIState *sci = RSCI(opaque); + + switch (offset) { + case A_SMR: + if (!sci_is_tr_enabled(sci)) { + sci->smr = val; + update_trtime(sci); + } + break; + case A_BRR: + if (!sci_is_tr_enabled(sci)) { + sci->brr = val; + update_trtime(sci); + } + break; + case A_SCR: + sci->scr = val; + if (FIELD_EX8(sci->scr, SCR, TE)) { + sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 1); + sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1); + if (FIELD_EX8(sci->scr, SCR, TIE)) { + qemu_irq_pulse(sci->irq[TXI]); + } + } + if (!FIELD_EX8(sci->scr, SCR, TEIE)) { + qemu_set_irq(sci->irq[TEI], 0); + } + if (!FIELD_EX8(sci->scr, SCR, RIE)) { + qemu_set_irq(sci->irq[ERI], 0); + } + break; + case A_TDR: + sci->tdr = val; + if (FIELD_EX8(sci->ssr, SSR, TEND)) { + send_byte(sci); + } else { + sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 0); + } + break; + case A_SSR: + sci->ssr = FIELD_DP8(sci->ssr, SSR, MPBT, + FIELD_EX8(val, SSR, MPBT)); + sci->ssr = FIELD_DP8(sci->ssr, SSR, ERR, + FIELD_EX8(val, SSR, ERR) & 0x07); + if (FIELD_EX8(sci->read_ssr, SSR, ERR) && + FIELD_EX8(sci->ssr, SSR, ERR) == 0) { + qemu_set_irq(sci->irq[ERI], 0); + } + break; + case A_RDR: + qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: RDR is read only.\n"); + break; + case A_SCMR: + sci->scmr = val; break; + case A_SEMR: /* SEMR */ + sci->semr = val; break; + default: + qemu_log_mask(LOG_UNIMP, "renesas_sci: Register 0x%" HWADDR_PRIX " " + "not implemented\n", + offset); + } +} + +static uint64_t sci_read(void *opaque, hwaddr offset, unsigned size) +{ + RSCIState *sci = RSCI(opaque); + + switch (offset) { + case A_SMR: + return sci->smr; + case A_BRR: + return sci->brr; + case A_SCR: + return sci->scr; + case A_TDR: + return sci->tdr; + case A_SSR: + sci->read_ssr = sci->ssr; + return sci->ssr; + case A_RDR: + sci->ssr = FIELD_DP8(sci->ssr, SSR, RDRF, 0); + return sci->rdr; + case A_SCMR: + return sci->scmr; + case A_SEMR: + return sci->semr; + default: + qemu_log_mask(LOG_UNIMP, "renesas_sci: Register 0x%" HWADDR_PRIX + " not implemented.\n", offset); + } + return UINT64_MAX; +} + +static const MemoryRegionOps sci_ops = { + .write = sci_write, + .read = sci_read, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl.max_access_size = 1, + .valid.max_access_size = 1, +}; + +static void rsci_reset(DeviceState *dev) +{ + RSCIState *sci = RSCI(dev); + sci->smr = sci->scr = 0x00; + sci->brr = 0xff; + sci->tdr = 0xff; + sci->rdr = 0x00; + sci->ssr = 0x84; + sci->scmr = 0x00; + sci->semr = 0x00; + sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + +static void sci_event(void *opaque, QEMUChrEvent event) +{ + RSCIState *sci = RSCI(opaque); + if (event == CHR_EVENT_BREAK) { + sci->ssr = FIELD_DP8(sci->ssr, SSR, FER, 1); + if (FIELD_EX8(sci->scr, SCR, RIE)) { + qemu_set_irq(sci->irq[ERI], 1); + } + } +} + +static void rsci_realize(DeviceState *dev, Error **errp) +{ + RSCIState *sci = RSCI(dev); + + if (sci->input_freq == 0) { + qemu_log_mask(LOG_GUEST_ERROR, + "renesas_sci: input-freq property must be set."); + return; + } + qemu_chr_fe_set_handlers(&sci->chr, can_receive, receive, + sci_event, NULL, sci, NULL, true); +} + +static void rsci_init(Object *obj) +{ + SysBusDevice *d = SYS_BUS_DEVICE(obj); + RSCIState *sci = RSCI(obj); + int i; + + memory_region_init_io(&sci->memory, OBJECT(sci), &sci_ops, + sci, "renesas-sci", 0x8); + sysbus_init_mmio(d, &sci->memory); + + for (i = 0; i < SCI_NR_IRQ; i++) { + sysbus_init_irq(d, &sci->irq[i]); + } + timer_init_ns(&sci->timer, QEMU_CLOCK_VIRTUAL, txend, sci); +} + +static const VMStateDescription vmstate_rsci = { + .name = "renesas-sci", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT64(trtime, RSCIState), + VMSTATE_INT64(rx_next, RSCIState), + VMSTATE_UINT8(smr, RSCIState), + VMSTATE_UINT8(brr, RSCIState), + VMSTATE_UINT8(scr, RSCIState), + VMSTATE_UINT8(tdr, RSCIState), + VMSTATE_UINT8(ssr, RSCIState), + VMSTATE_UINT8(rdr, RSCIState), + VMSTATE_UINT8(scmr, RSCIState), + VMSTATE_UINT8(semr, RSCIState), + VMSTATE_UINT8(read_ssr, RSCIState), + VMSTATE_TIMER(timer, RSCIState), + VMSTATE_END_OF_LIST() + } +}; + +static Property rsci_properties[] = { + DEFINE_PROP_UINT64("input-freq", RSCIState, input_freq, 0), + DEFINE_PROP_CHR("chardev", RSCIState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rsci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rsci_realize; + dc->vmsd = &vmstate_rsci; + dc->reset = rsci_reset; + device_class_set_props(dc, rsci_properties); +} + +static const TypeInfo rsci_info = { + .name = TYPE_RENESAS_SCI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RSCIState), + .instance_init = rsci_init, + .class_init = rsci_class_init, +}; + +static void rsci_register_types(void) +{ + type_register_static(&rsci_info); +} + +type_init(rsci_register_types) diff --git a/include/hw/char/renesas_sci.h b/include/hw/char/renesas_sci.h new file mode 100644 index 0000000000..efdebc620a --- /dev/null +++ b/include/hw/char/renesas_sci.h @@ -0,0 +1,51 @@ +/* + * Renesas Serial Communication Interface + * + * Copyright (c) 2018 Yoshinori Sato + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_CHAR_RENESAS_SCI_H +#define HW_CHAR_RENESAS_SCI_H + +#include "chardev/char-fe.h" +#include "hw/sysbus.h" + +#define TYPE_RENESAS_SCI "renesas-sci" +#define RSCI(obj) OBJECT_CHECK(RSCIState, (obj), TYPE_RENESAS_SCI) + +enum { + ERI = 0, + RXI = 1, + TXI = 2, + TEI = 3, + SCI_NR_IRQ = 4 +}; + +typedef struct { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + MemoryRegion memory; + QEMUTimer timer; + CharBackend chr; + qemu_irq irq[SCI_NR_IRQ]; + + uint8_t smr; + uint8_t brr; + uint8_t scr; + uint8_t tdr; + uint8_t ssr; + uint8_t rdr; + uint8_t scmr; + uint8_t semr; + + uint8_t read_ssr; + int64_t trtime; + int64_t rx_next; + uint64_t input_freq; +} RSCIState; + +#endif From 0c80f50f1e047535f76cffcf9629ebf6d4542c4d Mon Sep 17 00:00:00 2001 From: Yoshinori Sato Date: Mon, 21 Jan 2019 22:16:00 +0900 Subject: [PATCH 1504/2595] hw/rx: RX62N microcontroller (MCU) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rx62n - RX62N cpu. Signed-off-by: Yoshinori Sato Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson [PMD: Use TYPE_RX62N_CPU, use #define for RX62N_NR_TMR/CMT/SCI, renamed CPU -> MCU, device -> microcontroller] Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200224141923.82118-18-ysato@users.sourceforge.jp> [PMD: Rebased on b77b5b3dc7, split of machine, use &error_abort] Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 2 + hw/Kconfig | 1 + hw/rx/Kconfig | 6 + hw/rx/Makefile.objs | 1 + hw/rx/rx62n.c | 254 ++++++++++++++++++++++++++++++++++++++++++ include/hw/rx/rx62n.h | 75 +++++++++++++ 6 files changed, 339 insertions(+) create mode 100644 hw/rx/Kconfig create mode 100644 hw/rx/Makefile.objs create mode 100644 hw/rx/rx62n.c create mode 100644 include/hw/rx/rx62n.h diff --git a/MAINTAINERS b/MAINTAINERS index e92150187c..570807936c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1983,7 +1983,9 @@ Renesas RX peripherals M: Yoshinori Sato S: Maintained F: hw/intc/rx_icu.c +F: hw/rx/ F: include/hw/intc/rx_icu.h +F: include/hw/rx/ Subsystems ---------- diff --git a/hw/Kconfig b/hw/Kconfig index ecf491bf04..62f9ebdc22 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -55,6 +55,7 @@ source nios2/Kconfig source openrisc/Kconfig source ppc/Kconfig source riscv/Kconfig +source rx/Kconfig source s390x/Kconfig source sh4/Kconfig source sparc/Kconfig diff --git a/hw/rx/Kconfig b/hw/rx/Kconfig new file mode 100644 index 0000000000..e7b1c59516 --- /dev/null +++ b/hw/rx/Kconfig @@ -0,0 +1,6 @@ +config RX62N_MCU + bool + select RX_ICU + select RENESAS_TMR + select RENESAS_CMT + select RENESAS_SCI diff --git a/hw/rx/Makefile.objs b/hw/rx/Makefile.objs new file mode 100644 index 0000000000..fe19ee7984 --- /dev/null +++ b/hw/rx/Makefile.objs @@ -0,0 +1 @@ +obj-$(CONFIG_RX62N_MCU) += rx62n.o diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c new file mode 100644 index 0000000000..85b7770023 --- /dev/null +++ b/hw/rx/rx62n.c @@ -0,0 +1,254 @@ +/* + * RX62N Microcontroller + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * + * Copyright (c) 2019 Yoshinori Sato + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/rx/rx62n.h" +#include "hw/loader.h" +#include "hw/sysbus.h" +#include "hw/qdev-properties.h" +#include "sysemu/sysemu.h" +#include "cpu.h" + +/* + * RX62N Internal Memory + */ +#define RX62N_IRAM_BASE 0x00000000 +#define RX62N_DFLASH_BASE 0x00100000 +#define RX62N_CFLASH_BASE 0xfff80000 + +/* + * RX62N Peripheral Address + * See users manual section 5 + */ +#define RX62N_ICU_BASE 0x00087000 +#define RX62N_TMR_BASE 0x00088200 +#define RX62N_CMT_BASE 0x00088000 +#define RX62N_SCI_BASE 0x00088240 + +/* + * RX62N Peripheral IRQ + * See users manual section 11 + */ +#define RX62N_TMR_IRQ 174 +#define RX62N_CMT_IRQ 28 +#define RX62N_SCI_IRQ 214 + +/* + * IRQ -> IPR mapping table + * 0x00 - 0x91: IPR no (IPR00 to IPR91) + * 0xff: IPR not assigned + * See "11.3.1 Interrupt Vector Table" in hardware manual. + */ +static const uint8_t ipr_table[NR_IRQS] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 15 */ + 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0x02, + 0xff, 0xff, 0xff, 0x03, 0x04, 0x05, 0x06, 0x07, /* 31 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x14, 0x14, 0x14, /* 47 */ + 0x15, 0x15, 0x15, 0x15, 0xff, 0xff, 0xff, 0xff, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1d, 0x1e, 0x1f, /* 63 */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 79 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x3a, 0x3b, 0x3c, 0xff, 0xff, 0xff, /* 95 */ + 0x40, 0xff, 0x44, 0x45, 0xff, 0xff, 0x48, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 111 */ + 0xff, 0xff, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, + 0x52, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x56, /* 127 */ + 0x56, 0x57, 0x57, 0x57, 0x57, 0x58, 0x59, 0x59, + 0x59, 0x59, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, /* 143 */ + 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, + 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 0x62, /* 159 */ + 0x62, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x66, + 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, /* 175 */ + 0x68, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6b, + 0x6b, 0x6b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 191 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x71, + 0x72, 0x73, 0x74, 0x75, 0xff, 0xff, 0xff, 0xff, /* 207 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x80, + 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, /* 223 */ + 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0xff, 0xff, + 0xff, 0xff, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, /* 239 */ + 0x86, 0x86, 0xff, 0xff, 0xff, 0xff, 0x88, 0x89, + 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, /* 255 */ +}; + +/* + * Level triggerd IRQ list + * Not listed IRQ is Edge trigger. + * See "11.3.1 Interrupt Vector Table" in hardware manual. + */ +static const uint8_t levelirq[] = { + 16, 21, 32, 44, 47, 48, 51, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 90, 91, 170, 171, 172, 173, 214, + 217, 218, 221, 222, 225, 226, 229, 234, 237, 238, + 241, 246, 249, 250, 253, +}; + +static void register_icu(RX62NState *s) +{ + int i; + SysBusDevice *icu; + + object_initialize_child(OBJECT(s), "icu", &s->icu, TYPE_RX_ICU); + icu = SYS_BUS_DEVICE(&s->icu); + qdev_prop_set_uint32(DEVICE(icu), "len-ipr-map", NR_IRQS); + for (i = 0; i < NR_IRQS; i++) { + char propname[32]; + snprintf(propname, sizeof(propname), "ipr-map[%d]", i); + qdev_prop_set_uint32(DEVICE(icu), propname, ipr_table[i]); + } + qdev_prop_set_uint32(DEVICE(icu), "len-trigger-level", + ARRAY_SIZE(levelirq)); + for (i = 0; i < ARRAY_SIZE(levelirq); i++) { + char propname[32]; + snprintf(propname, sizeof(propname), "trigger-level[%d]", i); + qdev_prop_set_uint32(DEVICE(icu), propname, levelirq[i]); + } + + for (i = 0; i < NR_IRQS; i++) { + s->irq[i] = qdev_get_gpio_in(DEVICE(icu), i); + } + sysbus_realize(icu, &error_abort); + sysbus_connect_irq(icu, 0, qdev_get_gpio_in(DEVICE(&s->cpu), RX_CPU_IRQ)); + sysbus_connect_irq(icu, 1, qdev_get_gpio_in(DEVICE(&s->cpu), RX_CPU_FIR)); + sysbus_connect_irq(icu, 2, s->irq[SWI]); + sysbus_mmio_map(SYS_BUS_DEVICE(icu), 0, RX62N_ICU_BASE); +} + +static void register_tmr(RX62NState *s, int unit) +{ + SysBusDevice *tmr; + int i, irqbase; + + object_initialize_child(OBJECT(s), "tmr[*]", + &s->tmr[unit], TYPE_RENESAS_TMR); + tmr = SYS_BUS_DEVICE(&s->tmr[unit]); + qdev_prop_set_uint64(DEVICE(tmr), "input-freq", RX62N_PCLK); + sysbus_realize(tmr, &error_abort); + + irqbase = RX62N_TMR_IRQ + TMR_NR_IRQ * unit; + for (i = 0; i < TMR_NR_IRQ; i++) { + sysbus_connect_irq(tmr, i, s->irq[irqbase + i]); + } + sysbus_mmio_map(tmr, 0, RX62N_TMR_BASE + unit * 0x10); +} + +static void register_cmt(RX62NState *s, int unit) +{ + SysBusDevice *cmt; + int i, irqbase; + + object_initialize_child(OBJECT(s), "cmt[*]", + &s->cmt[unit], TYPE_RENESAS_CMT); + cmt = SYS_BUS_DEVICE(&s->cmt[unit]); + qdev_prop_set_uint64(DEVICE(cmt), "input-freq", RX62N_PCLK); + sysbus_realize(cmt, &error_abort); + + irqbase = RX62N_CMT_IRQ + CMT_NR_IRQ * unit; + for (i = 0; i < CMT_NR_IRQ; i++) { + sysbus_connect_irq(cmt, i, s->irq[irqbase + i]); + } + sysbus_mmio_map(cmt, 0, RX62N_CMT_BASE + unit * 0x10); +} + +static void register_sci(RX62NState *s, int unit) +{ + SysBusDevice *sci; + int i, irqbase; + + object_initialize_child(OBJECT(s), "sci[*]", + &s->sci[unit], TYPE_RENESAS_SCI); + sci = SYS_BUS_DEVICE(&s->sci[unit]); + qdev_prop_set_chr(DEVICE(sci), "chardev", serial_hd(unit)); + qdev_prop_set_uint64(DEVICE(sci), "input-freq", RX62N_PCLK); + sysbus_realize(sci, &error_abort); + + irqbase = RX62N_SCI_IRQ + SCI_NR_IRQ * unit; + for (i = 0; i < SCI_NR_IRQ; i++) { + sysbus_connect_irq(sci, i, s->irq[irqbase + i]); + } + sysbus_mmio_map(sci, 0, RX62N_SCI_BASE + unit * 0x08); +} + +static void rx62n_realize(DeviceState *dev, Error **errp) +{ + RX62NState *s = RX62N_MCU(dev); + + memory_region_init_ram(&s->iram, OBJECT(dev), "iram", + RX62N_IRAM_SIZE, &error_abort); + memory_region_add_subregion(s->sysmem, RX62N_IRAM_BASE, &s->iram); + memory_region_init_rom(&s->d_flash, OBJECT(dev), "flash-data", + RX62N_DFLASH_SIZE, &error_abort); + memory_region_add_subregion(s->sysmem, RX62N_DFLASH_BASE, &s->d_flash); + memory_region_init_rom(&s->c_flash, OBJECT(dev), "flash-code", + RX62N_CFLASH_SIZE, &error_abort); + memory_region_add_subregion(s->sysmem, RX62N_CFLASH_BASE, &s->c_flash); + + if (!s->kernel) { + rom_add_file_fixed(bios_name, RX62N_CFLASH_BASE, 0); + } + + /* Initialize CPU */ + object_initialize_child(OBJECT(s), "cpu", &s->cpu, TYPE_RX62N_CPU); + qdev_realize(DEVICE(&s->cpu), NULL, &error_abort); + + register_icu(s); + s->cpu.env.ack = qdev_get_gpio_in_named(DEVICE(&s->icu), "ack", 0); + register_tmr(s, 0); + register_tmr(s, 1); + register_cmt(s, 0); + register_cmt(s, 1); + register_sci(s, 0); +} + +static Property rx62n_properties[] = { + DEFINE_PROP_LINK("main-bus", RX62NState, sysmem, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_BOOL("load-kernel", RX62NState, kernel, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rx62n_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rx62n_realize; + device_class_set_props(dc, rx62n_properties); +} + +static const TypeInfo rx62n_info = { + .name = TYPE_RX62N_MCU, + .parent = TYPE_DEVICE, + .instance_size = sizeof(RX62NState), + .class_init = rx62n_class_init, +}; + +static void rx62n_register_types(void) +{ + type_register_static(&rx62n_info); +} + +type_init(rx62n_register_types) diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h new file mode 100644 index 0000000000..7c6023bcd6 --- /dev/null +++ b/include/hw/rx/rx62n.h @@ -0,0 +1,75 @@ +/* + * RX62N MCU Object + * + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware + * (Rev.1.40 R01UH0033EJ0140) + * + * Copyright (c) 2019 Yoshinori Sato + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#ifndef HW_RX_RX62N_MCU_H +#define HW_RX_RX62N_MCU_H + +#include "target/rx/cpu.h" +#include "hw/intc/rx_icu.h" +#include "hw/timer/renesas_tmr.h" +#include "hw/timer/renesas_cmt.h" +#include "hw/char/renesas_sci.h" +#include "qemu/units.h" + +#define TYPE_RX62N_MCU "rx62n-mcu" +#define RX62N_MCU(obj) OBJECT_CHECK(RX62NState, (obj), TYPE_RX62N_MCU) + +#define RX62N_NR_TMR 2 +#define RX62N_NR_CMT 2 +#define RX62N_NR_SCI 6 + +typedef struct RX62NState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + + RXCPU cpu; + RXICUState icu; + RTMRState tmr[RX62N_NR_TMR]; + RCMTState cmt[RX62N_NR_CMT]; + RSCIState sci[RX62N_NR_SCI]; + + MemoryRegion *sysmem; + bool kernel; + + MemoryRegion iram; + MemoryRegion iomem1; + MemoryRegion d_flash; + MemoryRegion iomem2; + MemoryRegion iomem3; + MemoryRegion c_flash; + qemu_irq irq[NR_IRQS]; +} RX62NState; + +/* + * RX62N Internal Memory + * It is the value of R5F562N8. + * Please change the size for R5F562N7. + */ +#define RX62N_IRAM_SIZE (96 * KiB) +#define RX62N_DFLASH_SIZE (32 * KiB) +#define RX62N_CFLASH_SIZE (512 * KiB) + +#define RX62N_PCLK (48 * 1000 * 1000) + +#endif From 7d272cb43d64e44d476e83c89dc61f5b54a658e9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 May 2019 08:43:07 -0500 Subject: [PATCH 1505/2595] hw/rx: Honor -accel qtest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue an error if no kernel, no bios, and not qtest'ing. Fixes make check-qtest-rx: test/qom-test. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Yoshinori Sato Tested-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-Id: <20190531134315.4109-16-richard.henderson@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/rx/rx62n.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index 85b7770023..d8f0fa4625 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -21,12 +21,14 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/error-report.h" #include "hw/hw.h" #include "hw/rx/rx62n.h" #include "hw/loader.h" #include "hw/sysbus.h" #include "hw/qdev-properties.h" #include "sysemu/sysemu.h" +#include "sysemu/qtest.h" #include "cpu.h" /* @@ -208,7 +210,12 @@ static void rx62n_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(s->sysmem, RX62N_CFLASH_BASE, &s->c_flash); if (!s->kernel) { - rom_add_file_fixed(bios_name, RX62N_CFLASH_BASE, 0); + if (bios_name) { + rom_add_file_fixed(bios_name, RX62N_CFLASH_BASE, 0); + } else if (!qtest_enabled()) { + error_report("No bios or kernel specified"); + exit(1); + } } /* Initialize CPU */ From 1db2086e6a98c4e917d6618c97e730eaeb2a8ada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 30 May 2020 18:35:29 +0200 Subject: [PATCH 1506/2595] hw/rx: Register R5F562N7 and R5F562N8 MCUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the current TYPE_RX62N_MCU an abstract class, and generate TYPE_R5F562N7_MCU and TYPE_R5F562N8_MCU models. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé --- hw/rx/rx62n.c | 92 ++++++++++++++++++++++++++++++++++++------- include/hw/rx/rx62n.h | 19 ++++----- 2 files changed, 85 insertions(+), 26 deletions(-) diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index d8f0fa4625..b9c217ebfa 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -5,6 +5,7 @@ * (Rev.1.40 R01UH0033EJ0140) * * Copyright (c) 2019 Yoshinori Sato + * Copyright (c) 2020 Philippe Mathieu-Daudé * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -55,6 +56,25 @@ #define RX62N_CMT_IRQ 28 #define RX62N_SCI_IRQ 214 +#define RX62N_XTAL_MIN_HZ (8 * 1000 * 1000) +#define RX62N_XTAL_MAX_HZ (14 * 1000 * 1000) +#define RX62N_PCLK_MAX_HZ (50 * 1000 * 1000) + +typedef struct RX62NClass { + /*< private >*/ + DeviceClass parent_class; + /*< public >*/ + const char *name; + uint64_t ram_size; + uint64_t rom_flash_size; + uint64_t data_flash_size; +} RX62NClass; + +#define RX62N_MCU_CLASS(klass) \ + OBJECT_CLASS_CHECK(RX62NClass, (klass), TYPE_RX62N_MCU) +#define RX62N_MCU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(RX62NClass, (obj), TYPE_RX62N_MCU) + /* * IRQ -> IPR mapping table * 0x00 - 0x91: IPR no (IPR00 to IPR91) @@ -148,7 +168,7 @@ static void register_tmr(RX62NState *s, int unit) object_initialize_child(OBJECT(s), "tmr[*]", &s->tmr[unit], TYPE_RENESAS_TMR); tmr = SYS_BUS_DEVICE(&s->tmr[unit]); - qdev_prop_set_uint64(DEVICE(tmr), "input-freq", RX62N_PCLK); + qdev_prop_set_uint64(DEVICE(tmr), "input-freq", s->pclk_freq_hz); sysbus_realize(tmr, &error_abort); irqbase = RX62N_TMR_IRQ + TMR_NR_IRQ * unit; @@ -166,7 +186,7 @@ static void register_cmt(RX62NState *s, int unit) object_initialize_child(OBJECT(s), "cmt[*]", &s->cmt[unit], TYPE_RENESAS_CMT); cmt = SYS_BUS_DEVICE(&s->cmt[unit]); - qdev_prop_set_uint64(DEVICE(cmt), "input-freq", RX62N_PCLK); + qdev_prop_set_uint64(DEVICE(cmt), "input-freq", s->pclk_freq_hz); sysbus_realize(cmt, &error_abort); irqbase = RX62N_CMT_IRQ + CMT_NR_IRQ * unit; @@ -185,7 +205,7 @@ static void register_sci(RX62NState *s, int unit) &s->sci[unit], TYPE_RENESAS_SCI); sci = SYS_BUS_DEVICE(&s->sci[unit]); qdev_prop_set_chr(DEVICE(sci), "chardev", serial_hd(unit)); - qdev_prop_set_uint64(DEVICE(sci), "input-freq", RX62N_PCLK); + qdev_prop_set_uint64(DEVICE(sci), "input-freq", s->pclk_freq_hz); sysbus_realize(sci, &error_abort); irqbase = RX62N_SCI_IRQ + SCI_NR_IRQ * unit; @@ -198,15 +218,31 @@ static void register_sci(RX62NState *s, int unit) static void rx62n_realize(DeviceState *dev, Error **errp) { RX62NState *s = RX62N_MCU(dev); + RX62NClass *rxc = RX62N_MCU_GET_CLASS(dev); + + if (s->xtal_freq_hz == 0) { + error_setg(errp, "\"xtal-frequency-hz\" property must be provided."); + return; + } + /* XTAL range: 8-14 MHz */ + if (s->xtal_freq_hz < RX62N_XTAL_MIN_HZ + || s->xtal_freq_hz > RX62N_XTAL_MAX_HZ) { + error_setg(errp, "\"xtal-frequency-hz\" property in incorrect range."); + return; + } + /* Use a 4x fixed multiplier */ + s->pclk_freq_hz = 4 * s->xtal_freq_hz; + /* PCLK range: 8-50 MHz */ + assert(s->pclk_freq_hz <= RX62N_PCLK_MAX_HZ); memory_region_init_ram(&s->iram, OBJECT(dev), "iram", - RX62N_IRAM_SIZE, &error_abort); + rxc->ram_size, &error_abort); memory_region_add_subregion(s->sysmem, RX62N_IRAM_BASE, &s->iram); memory_region_init_rom(&s->d_flash, OBJECT(dev), "flash-data", - RX62N_DFLASH_SIZE, &error_abort); + rxc->data_flash_size, &error_abort); memory_region_add_subregion(s->sysmem, RX62N_DFLASH_BASE, &s->d_flash); memory_region_init_rom(&s->c_flash, OBJECT(dev), "flash-code", - RX62N_CFLASH_SIZE, &error_abort); + rxc->rom_flash_size, &error_abort); memory_region_add_subregion(s->sysmem, RX62N_CFLASH_BASE, &s->c_flash); if (!s->kernel) { @@ -235,6 +271,7 @@ static Property rx62n_properties[] = { DEFINE_PROP_LINK("main-bus", RX62NState, sysmem, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_BOOL("load-kernel", RX62NState, kernel, false), + DEFINE_PROP_UINT32("xtal-frequency-hz", RX62NState, xtal_freq_hz, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -246,16 +283,41 @@ static void rx62n_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, rx62n_properties); } -static const TypeInfo rx62n_info = { - .name = TYPE_RX62N_MCU, - .parent = TYPE_DEVICE, - .instance_size = sizeof(RX62NState), - .class_init = rx62n_class_init, +static void r5f562n7_class_init(ObjectClass *oc, void *data) +{ + RX62NClass *rxc = RX62N_MCU_CLASS(oc); + + rxc->ram_size = 64 * KiB; + rxc->rom_flash_size = 384 * KiB; + rxc->data_flash_size = 32 * KiB; }; -static void rx62n_register_types(void) +static void r5f562n8_class_init(ObjectClass *oc, void *data) { - type_register_static(&rx62n_info); -} + RX62NClass *rxc = RX62N_MCU_CLASS(oc); -type_init(rx62n_register_types) + rxc->ram_size = 96 * KiB; + rxc->rom_flash_size = 512 * KiB; + rxc->data_flash_size = 32 * KiB; +}; + +static const TypeInfo rx62n_types[] = { + { + .name = TYPE_R5F562N7_MCU, + .parent = TYPE_RX62N_MCU, + .class_init = r5f562n7_class_init, + }, { + .name = TYPE_R5F562N8_MCU, + .parent = TYPE_RX62N_MCU, + .class_init = r5f562n8_class_init, + }, { + .name = TYPE_RX62N_MCU, + .parent = TYPE_DEVICE, + .instance_size = sizeof(RX62NState), + .class_size = sizeof(RX62NClass), + .class_init = rx62n_class_init, + .abstract = true, + } +}; + +DEFINE_TYPES(rx62n_types) diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index 7c6023bcd6..1d3e6a5cad 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -34,6 +34,9 @@ #define TYPE_RX62N_MCU "rx62n-mcu" #define RX62N_MCU(obj) OBJECT_CHECK(RX62NState, (obj), TYPE_RX62N_MCU) +#define TYPE_R5F562N7_MCU "r5f562n7-mcu" +#define TYPE_R5F562N8_MCU "r5f562n8-mcu" + #define RX62N_NR_TMR 2 #define RX62N_NR_CMT 2 #define RX62N_NR_SCI 6 @@ -59,17 +62,11 @@ typedef struct RX62NState { MemoryRegion iomem3; MemoryRegion c_flash; qemu_irq irq[NR_IRQS]; + + /* Input Clock (XTAL) frequency */ + uint32_t xtal_freq_hz; + /* Peripheral Module Clock frequency */ + uint32_t pclk_freq_hz; } RX62NState; -/* - * RX62N Internal Memory - * It is the value of R5F562N8. - * Please change the size for R5F562N7. - */ -#define RX62N_IRAM_SIZE (96 * KiB) -#define RX62N_DFLASH_SIZE (32 * KiB) -#define RX62N_CFLASH_SIZE (512 * KiB) - -#define RX62N_PCLK (48 * 1000 * 1000) - #endif From bda19d7bb56fe8f76dc32a9145c35087f81d4db7 Mon Sep 17 00:00:00 2001 From: Yoshinori Sato Date: Mon, 21 Jan 2019 22:16:00 +0900 Subject: [PATCH 1507/2595] hw/rx: Add RX GDB simulator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the RX machine internally simulated in GDB. Signed-off-by: Yoshinori Sato Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson [PMD: Use TYPE_RX62N_CPU, use #define for RX62N_NR_TMR/CMT/SCI, renamed CPU -> MCU, device -> microcontroller] Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200224141923.82118-18-ysato@users.sourceforge.jp> [PMD: Split of MCU, rename gdbsim, Add gdbsim-r5f562n7/r5f562n8] Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 7 ++ default-configs/rx-softmmu.mak | 1 + hw/rx/Kconfig | 4 + hw/rx/Makefile.objs | 1 + hw/rx/rx-gdbsim.c | 198 +++++++++++++++++++++++++++++++++ include/hw/rx/rx62n.h | 4 + 6 files changed, 215 insertions(+) create mode 100644 hw/rx/rx-gdbsim.c diff --git a/MAINTAINERS b/MAINTAINERS index 570807936c..dc0203784a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1256,6 +1256,13 @@ F: include/hw/riscv/opentitan.h F: include/hw/char/ibex_uart.h F: include/hw/intc/ibex_plic.h +RX Machines +----------- +rx-gdbsim +M: Yoshinori Sato +S: Maintained +F: hw/rx/rx-gdbsim.c + SH4 Machines ------------ R2D diff --git a/default-configs/rx-softmmu.mak b/default-configs/rx-softmmu.mak index 7c4eb2c1a0..df2b4e4f42 100644 --- a/default-configs/rx-softmmu.mak +++ b/default-configs/rx-softmmu.mak @@ -1,2 +1,3 @@ # Default configuration for rx-softmmu +CONFIG_RX_GDBSIM=y diff --git a/hw/rx/Kconfig b/hw/rx/Kconfig index e7b1c59516..2b297c5a6a 100644 --- a/hw/rx/Kconfig +++ b/hw/rx/Kconfig @@ -4,3 +4,7 @@ config RX62N_MCU select RENESAS_TMR select RENESAS_CMT select RENESAS_SCI + +config RX_GDBSIM + bool + select RX62N_MCU diff --git a/hw/rx/Makefile.objs b/hw/rx/Makefile.objs index fe19ee7984..4ef6b9e5b1 100644 --- a/hw/rx/Makefile.objs +++ b/hw/rx/Makefile.objs @@ -1 +1,2 @@ obj-$(CONFIG_RX62N_MCU) += rx62n.o +obj-$(CONFIG_RX_GDBSIM) += rx-gdbsim.o diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c new file mode 100644 index 0000000000..b8a56fa7af --- /dev/null +++ b/hw/rx/rx-gdbsim.c @@ -0,0 +1,198 @@ +/* + * RX QEMU GDB simulator + * + * Copyright (c) 2019 Yoshinori Sato + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/loader.h" +#include "hw/rx/rx62n.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "sysemu/device_tree.h" +#include "hw/boards.h" + +/* Same address of GDB integrated simulator */ +#define SDRAM_BASE EXT_CS_BASE + +typedef struct RxGdbSimMachineClass { + /*< private >*/ + MachineClass parent_class; + /*< public >*/ + const char *mcu_name; + uint32_t xtal_freq_hz; +} RxGdbSimMachineClass; + +typedef struct RxGdbSimMachineState { + /*< private >*/ + MachineState parent_obj; + /*< public >*/ + RX62NState mcu; +} RxGdbSimMachineState; + +#define TYPE_RX_GDBSIM_MACHINE MACHINE_TYPE_NAME("rx62n-common") + +#define RX_GDBSIM_MACHINE(obj) \ + OBJECT_CHECK(RxGdbSimMachineState, (obj), TYPE_RX_GDBSIM_MACHINE) + +#define RX_GDBSIM_MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(RxGdbSimMachineClass, (klass), TYPE_RX_GDBSIM_MACHINE) +#define RX_GDBSIM_MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(RxGdbSimMachineClass, (obj), TYPE_RX_GDBSIM_MACHINE) + +static void rx_load_image(RXCPU *cpu, const char *filename, + uint32_t start, uint32_t size) +{ + static uint32_t extable[32]; + long kernel_size; + int i; + + kernel_size = load_image_targphys(filename, start, size); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", filename); + exit(1); + } + cpu->env.pc = start; + + /* setup exception trap trampoline */ + /* linux kernel only works little-endian mode */ + for (i = 0; i < ARRAY_SIZE(extable); i++) { + extable[i] = cpu_to_le32(0x10 + i * 4); + } + rom_add_blob_fixed("extable", extable, sizeof(extable), VECTOR_TABLE_BASE); +} + +static void rx_gdbsim_init(MachineState *machine) +{ + MachineClass *mc = MACHINE_GET_CLASS(machine); + RxGdbSimMachineState *s = RX_GDBSIM_MACHINE(machine); + RxGdbSimMachineClass *rxc = RX_GDBSIM_MACHINE_GET_CLASS(machine); + MemoryRegion *sysmem = get_system_memory(); + const char *kernel_filename = machine->kernel_filename; + const char *dtb_filename = machine->dtb; + + if (machine->ram_size < mc->default_ram_size) { + char *sz = size_to_str(mc->default_ram_size); + error_report("Invalid RAM size, should be more than %s", sz); + g_free(sz); + } + + /* Allocate memory space */ + memory_region_add_subregion(sysmem, SDRAM_BASE, machine->ram); + + /* Initialize MCU */ + object_initialize_child(OBJECT(machine), "mcu", &s->mcu, rxc->mcu_name); + object_property_set_link(OBJECT(&s->mcu), OBJECT(sysmem), + "main-bus", &error_abort); + object_property_set_uint(OBJECT(&s->mcu), rxc->xtal_freq_hz, + "xtal-frequency-hz", &error_abort); + object_property_set_bool(OBJECT(&s->mcu), kernel_filename != NULL, + "load-kernel", &error_abort); + qdev_realize(DEVICE(&s->mcu), NULL, &error_abort); + + /* Load kernel and dtb */ + if (kernel_filename) { + ram_addr_t kernel_offset; + + /* + * The kernel image is loaded into + * the latter half of the SDRAM space. + */ + kernel_offset = machine->ram_size / 2; + rx_load_image(RXCPU(first_cpu), kernel_filename, + SDRAM_BASE + kernel_offset, kernel_offset); + if (dtb_filename) { + ram_addr_t dtb_offset; + int dtb_size; + void *dtb; + + dtb = load_device_tree(dtb_filename, &dtb_size); + if (dtb == NULL) { + error_report("Couldn't open dtb file %s", dtb_filename); + exit(1); + } + if (machine->kernel_cmdline && + qemu_fdt_setprop_string(dtb, "/chosen", "bootargs", + machine->kernel_cmdline) < 0) { + error_report("Couldn't set /chosen/bootargs"); + exit(1); + } + /* DTB is located at the end of SDRAM space. */ + dtb_offset = machine->ram_size - dtb_size; + rom_add_blob_fixed("dtb", dtb, dtb_size, + SDRAM_BASE + dtb_offset); + /* Set dtb address to R1 */ + RXCPU(first_cpu)->env.regs[1] = SDRAM_BASE + dtb_offset; + } + } +} + +static void rx_gdbsim_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->init = rx_gdbsim_init; + mc->default_cpu_type = TYPE_RX62N_CPU; + mc->default_ram_size = 16 * MiB; + mc->default_ram_id = "ext-sdram"; +} + +static void rx62n7_class_init(ObjectClass *oc, void *data) +{ + RxGdbSimMachineClass *rxc = RX_GDBSIM_MACHINE_CLASS(oc); + MachineClass *mc = MACHINE_CLASS(oc); + + rxc->mcu_name = TYPE_R5F562N7_MCU; + rxc->xtal_freq_hz = 12 * 1000 * 1000; + mc->desc = "gdb simulator (R5F562N7 MCU and external RAM)"; +}; + +static void rx62n8_class_init(ObjectClass *oc, void *data) +{ + RxGdbSimMachineClass *rxc = RX_GDBSIM_MACHINE_CLASS(oc); + MachineClass *mc = MACHINE_CLASS(oc); + + rxc->mcu_name = TYPE_R5F562N8_MCU; + rxc->xtal_freq_hz = 12 * 1000 * 1000; + mc->desc = "gdb simulator (R5F562N8 MCU and external RAM)"; +}; + +static const TypeInfo rx_gdbsim_types[] = { + { + .name = MACHINE_TYPE_NAME("gdbsim-r5f562n7"), + .parent = TYPE_RX_GDBSIM_MACHINE, + .class_init = rx62n7_class_init, + }, { + .name = MACHINE_TYPE_NAME("gdbsim-r5f562n8"), + .parent = TYPE_RX_GDBSIM_MACHINE, + .class_init = rx62n8_class_init, + }, { + .name = TYPE_RX_GDBSIM_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(RxGdbSimMachineState), + .class_size = sizeof(RxGdbSimMachineClass), + .class_init = rx_gdbsim_class_init, + .abstract = true, + } +}; + +DEFINE_TYPES(rx_gdbsim_types) diff --git a/include/hw/rx/rx62n.h b/include/hw/rx/rx62n.h index 1d3e6a5cad..aa94758c27 100644 --- a/include/hw/rx/rx62n.h +++ b/include/hw/rx/rx62n.h @@ -37,6 +37,10 @@ #define TYPE_R5F562N7_MCU "r5f562n7-mcu" #define TYPE_R5F562N8_MCU "r5f562n8-mcu" +#define EXT_CS_BASE 0x01000000 +#define VECTOR_TABLE_BASE 0xffffff80 +#define RX62N_CFLASH_BASE 0xfff80000 + #define RX62N_NR_TMR 2 #define RX62N_NR_CMT 2 #define RX62N_NR_SCI 6 From cf665623cb00c18997ac4a38244b360d80787417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 24 May 2019 05:17:04 +0200 Subject: [PATCH 1508/2595] BootLinuxConsoleTest: Test the RX GDB simulator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add two tests for the rx-gdbsim machine, based on the recommended test setup from Yoshinori Sato: https://lists.gnu.org/archive/html/qemu-devel/2019-05/msg03586.html - U-Boot prompt - Linux kernel with Sash shell These are very quick tests: $ avocado run -t arch:rx tests/acceptance/machine_rx_gdbsim.py JOB ID : 84a6ef01c0b87975ecbfcb31a920afd735753ace JOB LOG : /home/phil/avocado/job-results/job-2019-05-24T05.02-84a6ef0/job.log (1/2) tests/acceptance/machine_rx_gdbsim.py:RxGdbSimMachine.test_uboot: PASS (0.11 s) (2/2) tests/acceptance/machine_rx_gdbsim.py:RxGdbSimMachine.test_linux_sash: PASS (0.45 s) RESULTS : PASS 2 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0 Tests can also be run with: $ avocado --show=console run -t arch:rx tests/acceptance/machine_rx_gdbsim.py console: U-Boot 2016.05-rc3-23705-ga1ef3c71cb-dirty (Feb 05 2019 - 21:56:06 +0900) console: Linux version 4.19.0+ (yo-satoh@yo-satoh-debian) (gcc version 9.0.0 20181105 (experimental) (GCC)) #137 Wed Feb 20 23:20:02 JST 2019 console: Built 1 zonelists, mobility grouping on. Total pages: 8128 ... console: SuperH (H)SCI(F) driver initialized console: 88240.serial: ttySC0 at MMIO 0x88240 (irq = 215, base_baud = 0) is a sci console: console [ttySC0] enabled console: 88248.serial: ttySC1 at MMIO 0x88248 (irq = 219, base_baud = 0) is a sci Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Yoshinori Sato Message-Id: <20200224141923.82118-22-ysato@users.sourceforge.jp> [PMD: Replace obsolete set_machine() by machine tag, and rename as gdbsim] Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson --- MAINTAINERS | 1 + tests/acceptance/machine_rx_gdbsim.py | 68 +++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 tests/acceptance/machine_rx_gdbsim.py diff --git a/MAINTAINERS b/MAINTAINERS index dc0203784a..37c5f10934 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1262,6 +1262,7 @@ rx-gdbsim M: Yoshinori Sato S: Maintained F: hw/rx/rx-gdbsim.c +F: tests/acceptance/machine_rx_gdbsim.py SH4 Machines ------------ diff --git a/tests/acceptance/machine_rx_gdbsim.py b/tests/acceptance/machine_rx_gdbsim.py new file mode 100644 index 0000000000..a44f2c87da --- /dev/null +++ b/tests/acceptance/machine_rx_gdbsim.py @@ -0,0 +1,68 @@ +# Functional test that boots a Linux kernel and checks the console +# +# Copyright (c) 2018 Red Hat, Inc. +# +# Author: +# Cleber Rosa +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +from avocado_qemu import Test +from avocado_qemu import exec_command_and_wait_for_pattern +from avocado_qemu import wait_for_console_pattern +from avocado.utils import archive + + +class RxGdbSimMachine(Test): + + timeout = 30 + KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' + + def test_uboot(self): + """ + U-Boot and checks that the console is operational. + + :avocado: tags=arch:rx + :avocado: tags=machine:gdbsim-r5f562n8 + :avocado: tags=endian:little + """ + uboot_url = ('https://acc.dl.osdn.jp/users/23/23888/u-boot.bin.gz') + uboot_hash = '9b78dbd43b40b2526848c0b1ce9de02c24f4dcdb' + uboot_path = self.fetch_asset(uboot_url, asset_hash=uboot_hash) + uboot_path = archive.uncompress(uboot_path, self.workdir) + + self.vm.set_console() + self.vm.add_args('-bios', uboot_path, + '-no-reboot') + self.vm.launch() + uboot_version = 'U-Boot 2016.05-rc3-23705-ga1ef3c71cb-dirty' + wait_for_console_pattern(self, uboot_version) + gcc_version = 'rx-unknown-linux-gcc (GCC) 9.0.0 20181105 (experimental)' + # FIXME limit baudrate on chardev, else we type too fast + #exec_command_and_wait_for_pattern(self, 'version', gcc_version) + + def test_linux_sash(self): + """ + Boots a Linux kernel and checks that the console is operational. + + :avocado: tags=arch:rx + :avocado: tags=machine:gdbsim-r5f562n7 + :avocado: tags=endian:little + """ + dtb_url = ('https://acc.dl.osdn.jp/users/23/23887/rx-qemu.dtb') + dtb_hash = '7b4e4e2c71905da44e86ce47adee2210b026ac18' + dtb_path = self.fetch_asset(dtb_url, asset_hash=dtb_hash) + kernel_url = ('http://acc.dl.osdn.jp/users/23/23845/zImage') + kernel_hash = '39a81067f8d72faad90866ddfefa19165d68fc99' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + self.vm.set_console() + kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'earlycon' + self.vm.add_args('-kernel', kernel_path, + '-dtb', dtb_path, + '-no-reboot') + self.vm.launch() + wait_for_console_pattern(self, 'Sash command shell (version 1.1.1)', + failure_message='Kernel panic - not syncing') + exec_command_and_wait_for_pattern(self, 'printenv', 'TERM=linux') From 4adbfa45cc3793fa85157a4813306618f6009f52 Mon Sep 17 00:00:00 2001 From: Yoshinori Sato Date: Thu, 23 Jan 2020 22:25:25 +0900 Subject: [PATCH 1509/2595] docs: Document the RX target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add rx-virt target specification document. Signed-off-by: Yoshinori Sato Message-Id: <20200308130637.37651-1-ysato@users.sourceforge.jp> [PMD: Cover in MAINTAINERS, rename as gdbsim, use machine argument] Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson --- MAINTAINERS | 1 + docs/system/target-rx.rst | 36 ++++++++++++++++++++++++++++++++++++ docs/system/targets.rst | 1 + 3 files changed, 38 insertions(+) create mode 100644 docs/system/target-rx.rst diff --git a/MAINTAINERS b/MAINTAINERS index 37c5f10934..a61dddf098 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1261,6 +1261,7 @@ RX Machines rx-gdbsim M: Yoshinori Sato S: Maintained +F: docs/system/target-rx.rst F: hw/rx/rx-gdbsim.c F: tests/acceptance/machine_rx_gdbsim.py diff --git a/docs/system/target-rx.rst b/docs/system/target-rx.rst new file mode 100644 index 0000000000..4a20a89a06 --- /dev/null +++ b/docs/system/target-rx.rst @@ -0,0 +1,36 @@ +.. _RX-System-emulator: + +RX System emulator +-------------------- + +Use the executable ``qemu-system-rx`` to simulate RX target (GDB simulator). +This target emulated following devices. + +- R5F562N8 MCU + + - On-chip memory (ROM 512KB, RAM 96KB) + - Interrupt Control Unit (ICUa) + - 8Bit Timer x 1CH (TMR0,1) + - Compare Match Timer x 2CH (CMT0,1) + - Serial Communication Interface x 1CH (SCI0) + +- External memory 16MByte + +Example of ``qemu-system-rx`` usage for RX is shown below: + +Download ```` from +https://osdn.net/users/ysato/pf/qemu/dl/u-boot.bin.gz + +Start emulation of rx-virt:: + qemu-system-rx -M gdbsim-r5f562n8 -bios + +Download ``kernel_image_file`` from +https://osdn.net/users/ysato/pf/qemu/dl/zImage + +Download ``device_tree_blob`` from +https://osdn.net/users/ysato/pf/qemu/dl/rx-virt.dtb + +Start emulation of rx-virt:: + qemu-system-rx -M gdbsim-r5f562n8 \ + -kernel -dtb \ + -append "earlycon" diff --git a/docs/system/targets.rst b/docs/system/targets.rst index 0d8f91580a..99435a3eba 100644 --- a/docs/system/targets.rst +++ b/docs/system/targets.rst @@ -18,3 +18,4 @@ Contents: target-m68k target-xtensa target-s390x + target-rx From c62288072c9c6c275a28c074612941a44572691d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 22 Jun 2020 17:22:00 +0100 Subject: [PATCH 1510/2595] hw/arm/virt: Add 5.0 HW compat props Cc: Cornelia Huck Signed-off-by: Andrew Jones Reviewed-by: Cornelia Huck Message-id: 20200616140803.25515-1-drjones@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index caceb1e4a0..8b6e6aa7b1 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2375,6 +2375,7 @@ DEFINE_VIRT_MACHINE_AS_LATEST(5, 1) static void virt_machine_5_0_options(MachineClass *mc) { virt_machine_5_1_options(mc); + compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len); } DEFINE_VIRT_MACHINE(5, 0) From 2032e243a52c9834e5536463bcaa179f18d3319f Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 22 Jun 2020 17:22:00 +0100 Subject: [PATCH 1511/2595] util/oslib-posix : qemu_init_exec_dir implementation for Mac From 3025a0ce3fdf7d3559fc35a52c659f635f5c750c Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 26 May 2020 21:35:27 +0100 Subject: [PATCH] util/oslib-posix : qemu_init_exec_dir implementation for Mac Using dyld API to get the full path of the current process. Signed-off-by: David Carlier Message-id: CA+XhMqxwC10XHVs4Z-JfE0-WLAU3ztDuU9QKVi31mjr59HWCxg@mail.gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- util/oslib-posix.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 916f1be224..39ddc77c85 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -57,6 +57,10 @@ #include #endif +#ifdef __APPLE__ +#include +#endif + #include "qemu/mmap-alloc.h" #ifdef CONFIG_DEBUG_STACK_USAGE @@ -375,6 +379,17 @@ void qemu_init_exec_dir(const char *argv0) p = buf; } } +#elif defined(__APPLE__) + { + char fpath[PATH_MAX]; + uint32_t len = sizeof(fpath); + if (_NSGetExecutablePath(fpath, &len) == 0) { + p = realpath(fpath, buf); + if (!p) { + return; + } + } + } #endif /* If we don't have any way of figuring out the actual executable location then try argv[0]. */ From 353d2b85058711a5e44c2dc63eb5b620db50a602 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:24 +0100 Subject: [PATCH 1512/2595] target/arm: Convert Neon 2-reg-misc VREV64 to decodetree Convert the Neon VREV64 insn from the 2-reg-misc grouping to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-2-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 12 ++++++++ target/arm/translate-neon.inc.c | 50 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 24 ++-------------- 3 files changed, 64 insertions(+), 22 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 6d890b2161..e12fdf3095 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -429,6 +429,18 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm vm=%vm_dp vd=%vd_dp size=1 VDUP_scalar 1111 001 1 1 . 11 index:1 100 .... 11 000 q:1 . 0 .... \ vm=%vm_dp vd=%vd_dp size=2 + + ################################################################## + # 2-reg-misc grouping: + # 1111 001 11 D 11 size:2 opc1:2 Vd:4 0 opc2:4 q:1 M 0 Vm:4 + ################################################################## + + &2misc vd vm q size + + @2misc .... ... .. . .. size:2 .. .... . .... q:1 . . .... \ + &2misc vm=%vm_dp vd=%vd_dp + + VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index a5aa56bbde..90431a5383 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2970,3 +2970,53 @@ static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) a->q ? 16 : 8, a->q ? 16 : 8); return true; } + +static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) +{ + int pass, half; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (a->size == 3) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + for (pass = 0; pass < (a->q ? 2 : 1); pass++) { + TCGv_i32 tmp[2]; + + for (half = 0; half < 2; half++) { + tmp[half] = neon_load_reg(a->vm, pass * 2 + half); + switch (a->size) { + case 0: + tcg_gen_bswap32_i32(tmp[half], tmp[half]); + break; + case 1: + gen_swap_half(tmp[half]); + break; + case 2: + break; + default: + g_assert_not_reached(); + } + } + neon_store_reg(a->vd, pass * 2, tmp[1]); + neon_store_reg(a->vd, pass * 2 + 1, tmp[0]); + } + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 6d18892ade..5fca38b5fa 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5092,28 +5092,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } switch (op) { case NEON_2RM_VREV64: - for (pass = 0; pass < (q ? 2 : 1); pass++) { - tmp = neon_load_reg(rm, pass * 2); - tmp2 = neon_load_reg(rm, pass * 2 + 1); - switch (size) { - case 0: tcg_gen_bswap32_i32(tmp, tmp); break; - case 1: gen_swap_half(tmp); break; - case 2: /* no-op */ break; - default: abort(); - } - neon_store_reg(rd, pass * 2 + 1, tmp); - if (size == 2) { - neon_store_reg(rd, pass * 2, tmp2); - } else { - switch (size) { - case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break; - case 1: gen_swap_half(tmp2); break; - default: abort(); - } - neon_store_reg(rd, pass * 2, tmp2); - } - } - break; + /* handled by decodetree */ + return 1; case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U: case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: for (pass = 0; pass < q + 1; pass++) { From 6106af3aa2304fccee91a3a90138352b0c2af998 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:25 +0100 Subject: [PATCH 1513/2595] target/arm: Convert Neon 2-reg-misc pairwise ops to decodetree Convert the pairwise ops VPADDL and VPADAL in the 2-reg-misc grouping to decodetree. At this point we can get rid of the weird CPU_V001 #define that was used to avoid having to explicitly list all the arguments being passed to some TCG gen/helper functions. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-3-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 6 ++ target/arm/translate-neon.inc.c | 149 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 35 +------- 3 files changed, 157 insertions(+), 33 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index e12fdf3095..dd521baa07 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -441,6 +441,12 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm &2misc vm=%vm_dp vd=%vd_dp VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc + + VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc + VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc + + VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc + VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 90431a5383..2f7bd0d556 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3020,3 +3020,152 @@ static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) } return true; } + +static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a, + NeonGenWidenFn *widenfn, + NeonGenTwo64OpFn *opfn, + NeonGenTwo64OpFn *accfn) +{ + /* + * Pairwise long operations: widen both halves of the pair, + * combine the pairs with the opfn, and then possibly accumulate + * into the destination with the accfn. + */ + int pass; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!widenfn) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + for (pass = 0; pass < a->q + 1; pass++) { + TCGv_i32 tmp; + TCGv_i64 rm0_64, rm1_64, rd_64; + + rm0_64 = tcg_temp_new_i64(); + rm1_64 = tcg_temp_new_i64(); + rd_64 = tcg_temp_new_i64(); + tmp = neon_load_reg(a->vm, pass * 2); + widenfn(rm0_64, tmp); + tcg_temp_free_i32(tmp); + tmp = neon_load_reg(a->vm, pass * 2 + 1); + widenfn(rm1_64, tmp); + tcg_temp_free_i32(tmp); + opfn(rd_64, rm0_64, rm1_64); + tcg_temp_free_i64(rm0_64); + tcg_temp_free_i64(rm1_64); + + if (accfn) { + TCGv_i64 tmp64 = tcg_temp_new_i64(); + neon_load_reg64(tmp64, a->vd + pass); + accfn(rd_64, tmp64, rd_64); + tcg_temp_free_i64(tmp64); + } + neon_store_reg64(rd_64, a->vd + pass); + tcg_temp_free_i64(rd_64); + } + return true; +} + +static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a) +{ + static NeonGenWidenFn * const widenfn[] = { + gen_helper_neon_widen_s8, + gen_helper_neon_widen_s16, + tcg_gen_ext_i32_i64, + NULL, + }; + static NeonGenTwo64OpFn * const opfn[] = { + gen_helper_neon_paddl_u16, + gen_helper_neon_paddl_u32, + tcg_gen_add_i64, + NULL, + }; + + return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); +} + +static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a) +{ + static NeonGenWidenFn * const widenfn[] = { + gen_helper_neon_widen_u8, + gen_helper_neon_widen_u16, + tcg_gen_extu_i32_i64, + NULL, + }; + static NeonGenTwo64OpFn * const opfn[] = { + gen_helper_neon_paddl_u16, + gen_helper_neon_paddl_u32, + tcg_gen_add_i64, + NULL, + }; + + return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); +} + +static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a) +{ + static NeonGenWidenFn * const widenfn[] = { + gen_helper_neon_widen_s8, + gen_helper_neon_widen_s16, + tcg_gen_ext_i32_i64, + NULL, + }; + static NeonGenTwo64OpFn * const opfn[] = { + gen_helper_neon_paddl_u16, + gen_helper_neon_paddl_u32, + tcg_gen_add_i64, + NULL, + }; + static NeonGenTwo64OpFn * const accfn[] = { + gen_helper_neon_addl_u16, + gen_helper_neon_addl_u32, + tcg_gen_add_i64, + NULL, + }; + + return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], + accfn[a->size]); +} + +static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a) +{ + static NeonGenWidenFn * const widenfn[] = { + gen_helper_neon_widen_u8, + gen_helper_neon_widen_u16, + tcg_gen_extu_i32_i64, + NULL, + }; + static NeonGenTwo64OpFn * const opfn[] = { + gen_helper_neon_paddl_u16, + gen_helper_neon_paddl_u32, + tcg_gen_add_i64, + NULL, + }; + static NeonGenTwo64OpFn * const accfn[] = { + gen_helper_neon_addl_u16, + gen_helper_neon_addl_u32, + tcg_gen_add_i64, + NULL, + }; + + return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], + accfn[a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 5fca38b5fa..4405b034f7 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2934,8 +2934,6 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc) gen_rfe(s, pc, load_cpu_field(spsr)); } -#define CPU_V001 cpu_V0, cpu_V0, cpu_V1 - static int gen_neon_unzip(int rd, int rm, int size, int q) { TCGv_ptr pd, pm; @@ -3117,16 +3115,6 @@ static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u) tcg_temp_free_i32(src); } -static inline void gen_neon_addl(int size) -{ - switch (size) { - case 0: gen_helper_neon_addl_u16(CPU_V001); break; - case 1: gen_helper_neon_addl_u32(CPU_V001); break; - case 2: tcg_gen_add_i64(CPU_V001); break; - default: abort(); - } -} - static void gen_neon_narrow_op(int op, int u, int size, TCGv_i32 dest, TCGv_i64 src) { @@ -5092,29 +5080,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } switch (op) { case NEON_2RM_VREV64: - /* handled by decodetree */ - return 1; case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U: case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: - for (pass = 0; pass < q + 1; pass++) { - tmp = neon_load_reg(rm, pass * 2); - gen_neon_widen(cpu_V0, tmp, size, op & 1); - tmp = neon_load_reg(rm, pass * 2 + 1); - gen_neon_widen(cpu_V1, tmp, size, op & 1); - switch (size) { - case 0: gen_helper_neon_paddl_u16(CPU_V001); break; - case 1: gen_helper_neon_paddl_u32(CPU_V001); break; - case 2: tcg_gen_add_i64(CPU_V001); break; - default: abort(); - } - if (op >= NEON_2RM_VPADAL) { - /* Accumulate. */ - neon_load_reg64(cpu_V1, rd + pass); - gen_neon_addl(size); - } - neon_store_reg64(cpu_V0, rd + pass); - } - break; + /* handled by decodetree */ + return 1; case NEON_2RM_VTRN: if (size == 2) { int n; From 567663a2af2457da8aa74f221b1f3f8a6d2eddf6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:26 +0100 Subject: [PATCH 1514/2595] target/arm: Convert VZIP, VUZP to decodetree Convert the Neon VZIP and VUZP insns in the 2-reg-misc group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-4-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 3 ++ target/arm/translate-neon.inc.c | 74 ++++++++++++++++++++++++++ target/arm/translate.c | 92 +-------------------------------- 3 files changed, 79 insertions(+), 90 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index dd521baa07..ad9e17fd73 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -447,6 +447,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc + + VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc + VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 2f7bd0d556..f4799dd977 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3169,3 +3169,77 @@ static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a) return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], accfn[a->size]); } + +typedef void ZipFn(TCGv_ptr, TCGv_ptr); + +static bool do_zip_uzp(DisasContext *s, arg_2misc *a, + ZipFn *fn) +{ + TCGv_ptr pd, pm; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!fn) { + /* Bad size or size/q combination */ + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + pd = vfp_reg_ptr(true, a->vd); + pm = vfp_reg_ptr(true, a->vm); + fn(pd, pm); + tcg_temp_free_ptr(pd); + tcg_temp_free_ptr(pm); + return true; +} + +static bool trans_VUZP(DisasContext *s, arg_2misc *a) +{ + static ZipFn * const fn[2][4] = { + { + gen_helper_neon_unzip8, + gen_helper_neon_unzip16, + NULL, + NULL, + }, { + gen_helper_neon_qunzip8, + gen_helper_neon_qunzip16, + gen_helper_neon_qunzip32, + NULL, + } + }; + return do_zip_uzp(s, a, fn[a->q][a->size]); +} + +static bool trans_VZIP(DisasContext *s, arg_2misc *a) +{ + static ZipFn * const fn[2][4] = { + { + gen_helper_neon_zip8, + gen_helper_neon_zip16, + NULL, + NULL, + }, { + gen_helper_neon_qzip8, + gen_helper_neon_qzip16, + gen_helper_neon_qzip32, + NULL, + } + }; + return do_zip_uzp(s, a, fn[a->q][a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 4405b034f7..442f287d86 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2934,86 +2934,6 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc) gen_rfe(s, pc, load_cpu_field(spsr)); } -static int gen_neon_unzip(int rd, int rm, int size, int q) -{ - TCGv_ptr pd, pm; - - if (!q && size == 2) { - return 1; - } - pd = vfp_reg_ptr(true, rd); - pm = vfp_reg_ptr(true, rm); - if (q) { - switch (size) { - case 0: - gen_helper_neon_qunzip8(pd, pm); - break; - case 1: - gen_helper_neon_qunzip16(pd, pm); - break; - case 2: - gen_helper_neon_qunzip32(pd, pm); - break; - default: - abort(); - } - } else { - switch (size) { - case 0: - gen_helper_neon_unzip8(pd, pm); - break; - case 1: - gen_helper_neon_unzip16(pd, pm); - break; - default: - abort(); - } - } - tcg_temp_free_ptr(pd); - tcg_temp_free_ptr(pm); - return 0; -} - -static int gen_neon_zip(int rd, int rm, int size, int q) -{ - TCGv_ptr pd, pm; - - if (!q && size == 2) { - return 1; - } - pd = vfp_reg_ptr(true, rd); - pm = vfp_reg_ptr(true, rm); - if (q) { - switch (size) { - case 0: - gen_helper_neon_qzip8(pd, pm); - break; - case 1: - gen_helper_neon_qzip16(pd, pm); - break; - case 2: - gen_helper_neon_qzip32(pd, pm); - break; - default: - abort(); - } - } else { - switch (size) { - case 0: - gen_helper_neon_zip8(pd, pm); - break; - case 1: - gen_helper_neon_zip16(pd, pm); - break; - default: - abort(); - } - } - tcg_temp_free_ptr(pd); - tcg_temp_free_ptr(pm); - return 0; -} - static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) { TCGv_i32 rd, tmp; @@ -5082,6 +5002,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VREV64: case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U: case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: + case NEON_2RM_VUZP: + case NEON_2RM_VZIP: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -5097,16 +5019,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) goto elementwise; } break; - case NEON_2RM_VUZP: - if (gen_neon_unzip(rd, rm, size, q)) { - return 1; - } - break; - case NEON_2RM_VZIP: - if (gen_neon_zip(rd, rm, size, q)) { - return 1; - } - break; case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: /* also VQMOVUN; op field and mnemonics don't line up */ if (rm & 1) { From 3882bdacb0ad548864b9f2582a32bb5c785e3165 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:27 +0100 Subject: [PATCH 1515/2595] target/arm: Convert Neon narrowing moves to decodetree Convert the Neon narrowing moves VMQNV, VQMOVN, VQMOVUN in the 2-reg-misc group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-5-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 9 ++++ target/arm/translate-neon.inc.c | 59 ++++++++++++++++++++++++ target/arm/translate.c | 81 +-------------------------------- 3 files changed, 70 insertions(+), 79 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index ad9e17fd73..2277b4c7b5 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -439,6 +439,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm @2misc .... ... .. . .. size:2 .. .... . .... q:1 . . .... \ &2misc vm=%vm_dp vd=%vd_dp + @2misc_q0 .... ... .. . .. size:2 .. .... . .... . . . .... \ + &2misc vm=%vm_dp vd=%vd_dp q=0 VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc @@ -450,6 +452,13 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc + + VMOVN 1111 001 11 . 11 .. 10 .... 0 0100 0 . 0 .... @2misc_q0 + # VQMOVUN: unsigned result (source is always signed) + VQMOVUN 1111 001 11 . 11 .. 10 .... 0 0100 1 . 0 .... @2misc_q0 + # VQMOVN: signed result, source may be signed (_S) or unsigned (_U) + VQMOVN_S 1111 001 11 . 11 .. 10 .... 0 0101 0 . 0 .... @2misc_q0 + VQMOVN_U 1111 001 11 . 11 .. 10 .... 0 0101 1 . 0 .... @2misc_q0 ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index f4799dd977..b062097285 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3243,3 +3243,62 @@ static bool trans_VZIP(DisasContext *s, arg_2misc *a) }; return do_zip_uzp(s, a, fn[a->q][a->size]); } + +static bool do_vmovn(DisasContext *s, arg_2misc *a, + NeonGenNarrowEnvFn *narrowfn) +{ + TCGv_i64 rm; + TCGv_i32 rd0, rd1; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (a->vm & 1) { + return false; + } + + if (!narrowfn) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + rm = tcg_temp_new_i64(); + rd0 = tcg_temp_new_i32(); + rd1 = tcg_temp_new_i32(); + + neon_load_reg64(rm, a->vm); + narrowfn(rd0, cpu_env, rm); + neon_load_reg64(rm, a->vm + 1); + narrowfn(rd1, cpu_env, rm); + neon_store_reg(a->vd, 0, rd0); + neon_store_reg(a->vd, 1, rd1); + tcg_temp_free_i64(rm); + return true; +} + +#define DO_VMOVN(INSN, FUNC) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + static NeonGenNarrowEnvFn * const narrowfn[] = { \ + FUNC##8, \ + FUNC##16, \ + FUNC##32, \ + NULL, \ + }; \ + return do_vmovn(s, a, narrowfn[a->size]); \ + } + +DO_VMOVN(VMOVN, gen_neon_narrow_u) +DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat) +DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s) +DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u) diff --git a/target/arm/translate.c b/target/arm/translate.c index 442f287d86..8ecae264e1 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2975,46 +2975,6 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) tcg_temp_free_i32(rd); } -static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_narrow_u8(dest, src); break; - case 1: gen_helper_neon_narrow_u16(dest, src); break; - case 2: tcg_gen_extrl_i64_i32(dest, src); break; - default: abort(); - } -} - -static inline void gen_neon_narrow_sats(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break; - case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break; - case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break; - default: abort(); - } -} - -static inline void gen_neon_narrow_satu(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break; - case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break; - case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break; - default: abort(); - } -} - -static inline void gen_neon_unarrow_sats(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break; - case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break; - case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break; - default: abort(); - } -} - static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u) { if (u) { @@ -3035,24 +2995,6 @@ static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u) tcg_temp_free_i32(src); } -static void gen_neon_narrow_op(int op, int u, int size, - TCGv_i32 dest, TCGv_i64 src) -{ - if (op) { - if (u) { - gen_neon_unarrow_sats(size, dest, src); - } else { - gen_neon_narrow(size, dest, src); - } - } else { - if (u) { - gen_neon_narrow_satu(size, dest, src); - } else { - gen_neon_narrow_sats(size, dest, src); - } - } -} - /* Symbolic constants for op fields for Neon 2-register miscellaneous. * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B * table A7-13. @@ -4994,8 +4936,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) !arm_dc_feature(s, ARM_FEATURE_V8)) { return 1; } - if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) && - q && ((rm | rd) & 1)) { + if (q && ((rm | rd) & 1)) { return 1; } switch (op) { @@ -5004,6 +4945,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: case NEON_2RM_VUZP: case NEON_2RM_VZIP: + case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -5019,25 +4961,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) goto elementwise; } break; - case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: - /* also VQMOVUN; op field and mnemonics don't line up */ - if (rm & 1) { - return 1; - } - tmp2 = NULL; - for (pass = 0; pass < 2; pass++) { - neon_load_reg64(cpu_V0, rm + pass); - tmp = tcg_temp_new_i32(); - gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size, - tmp, cpu_V0); - if (pass == 0) { - tmp2 = tmp; - } else { - neon_store_reg(rd, 0, tmp2); - neon_store_reg(rd, 1, tmp); - } - } - break; case NEON_2RM_VSHLL: if (q || (rd & 1)) { return 1; From 749e2be36d75f11d5fa8f8277e2a0569bd2a1c97 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:28 +0100 Subject: [PATCH 1516/2595] target/arm: Convert Neon 2-reg-misc VSHLL to decodetree Convert the VSHLL insn in the 2-reg-misc Neon group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-6-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 2 ++ target/arm/translate-neon.inc.c | 52 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 35 +--------------------- 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 2277b4c7b5..0102aa7254 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -459,6 +459,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm # VQMOVN: signed result, source may be signed (_S) or unsigned (_U) VQMOVN_S 1111 001 11 . 11 .. 10 .... 0 0101 0 . 0 .... @2misc_q0 VQMOVN_U 1111 001 11 . 11 .. 10 .... 0 0101 1 . 0 .... @2misc_q0 + + VSHLL 1111 001 11 . 11 .. 10 .... 0 0110 0 . 0 .... @2misc_q0 ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index b062097285..78239ec1c1 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3302,3 +3302,55 @@ DO_VMOVN(VMOVN, gen_neon_narrow_u) DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat) DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s) DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u) + +static bool trans_VSHLL(DisasContext *s, arg_2misc *a) +{ + TCGv_i32 rm0, rm1; + TCGv_i64 rd; + static NeonGenWidenFn * const widenfns[] = { + gen_helper_neon_widen_u8, + gen_helper_neon_widen_u16, + tcg_gen_extu_i32_i64, + NULL, + }; + NeonGenWidenFn *widenfn = widenfns[a->size]; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (a->vd & 1) { + return false; + } + + if (!widenfn) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + rd = tcg_temp_new_i64(); + + rm0 = neon_load_reg(a->vm, 0); + rm1 = neon_load_reg(a->vm, 1); + + widenfn(rd, rm0); + tcg_gen_shli_i64(rd, rd, 8 << a->size); + neon_store_reg64(rd, a->vd); + widenfn(rd, rm1); + tcg_gen_shli_i64(rd, rd, 8 << a->size); + neon_store_reg64(rd, a->vd + 1); + + tcg_temp_free_i64(rd); + tcg_temp_free_i32(rm0); + tcg_temp_free_i32(rm1); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 8ecae264e1..94d5e34fff 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2975,26 +2975,6 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) tcg_temp_free_i32(rd); } -static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u) -{ - if (u) { - switch (size) { - case 0: gen_helper_neon_widen_u8(dest, src); break; - case 1: gen_helper_neon_widen_u16(dest, src); break; - case 2: tcg_gen_extu_i32_i64(dest, src); break; - default: abort(); - } - } else { - switch (size) { - case 0: gen_helper_neon_widen_s8(dest, src); break; - case 1: gen_helper_neon_widen_s16(dest, src); break; - case 2: tcg_gen_ext_i32_i64(dest, src); break; - default: abort(); - } - } - tcg_temp_free_i32(src); -} - /* Symbolic constants for op fields for Neon 2-register miscellaneous. * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B * table A7-13. @@ -4946,6 +4926,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VUZP: case NEON_2RM_VZIP: case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: + case NEON_2RM_VSHLL: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4961,20 +4942,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) goto elementwise; } break; - case NEON_2RM_VSHLL: - if (q || (rd & 1)) { - return 1; - } - tmp = neon_load_reg(rm, 0); - tmp2 = neon_load_reg(rm, 1); - for (pass = 0; pass < 2; pass++) { - if (pass == 1) - tmp = tmp2; - gen_neon_widen(cpu_V0, tmp, size, 1); - tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size); - neon_store_reg64(cpu_V0, rd + pass); - } - break; case NEON_2RM_VCVT_F16_F32: { TCGv_ptr fpst; From 654a517355e249435505ae5ff14a7520410cf7a4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:29 +0100 Subject: [PATCH 1517/2595] target/arm: Convert Neon VCVT f16/f32 insns to decodetree Convert the Neon insns in the 2-reg-misc group which are VCVT between f32 and f16 to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-7-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 3 ++ target/arm/translate-neon.inc.c | 96 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 65 ++-------------------- 3 files changed, 102 insertions(+), 62 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 0102aa7254..8174f2f92f 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -461,6 +461,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VQMOVN_U 1111 001 11 . 11 .. 10 .... 0 0101 1 . 0 .... @2misc_q0 VSHLL 1111 001 11 . 11 .. 10 .... 0 0110 0 . 0 .... @2misc_q0 + + VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0 + VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0 ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 78239ec1c1..d37be597cf 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3354,3 +3354,99 @@ static bool trans_VSHLL(DisasContext *s, arg_2misc *a) tcg_temp_free_i32(rm1); return true; } + +static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a) +{ + TCGv_ptr fpst; + TCGv_i32 ahp, tmp, tmp2, tmp3; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !dc_isar_feature(aa32_fp16_spconv, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vm & 1) || (a->size != 1)) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fpst = get_fpstatus_ptr(true); + ahp = get_ahp_flag(); + tmp = neon_load_reg(a->vm, 0); + gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); + tmp2 = neon_load_reg(a->vm, 1); + gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp); + tcg_gen_shli_i32(tmp2, tmp2, 16); + tcg_gen_or_i32(tmp2, tmp2, tmp); + tcg_temp_free_i32(tmp); + tmp = neon_load_reg(a->vm, 2); + gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); + tmp3 = neon_load_reg(a->vm, 3); + neon_store_reg(a->vd, 0, tmp2); + gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp); + tcg_gen_shli_i32(tmp3, tmp3, 16); + tcg_gen_or_i32(tmp3, tmp3, tmp); + neon_store_reg(a->vd, 1, tmp3); + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(ahp); + tcg_temp_free_ptr(fpst); + + return true; +} + +static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) +{ + TCGv_ptr fpst; + TCGv_i32 ahp, tmp, tmp2, tmp3; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !dc_isar_feature(aa32_fp16_spconv, s)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vd & 1) || (a->size != 1)) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fpst = get_fpstatus_ptr(true); + ahp = get_ahp_flag(); + tmp3 = tcg_temp_new_i32(); + tmp = neon_load_reg(a->vm, 0); + tmp2 = neon_load_reg(a->vm, 1); + tcg_gen_ext16u_i32(tmp3, tmp); + gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); + neon_store_reg(a->vd, 0, tmp3); + tcg_gen_shri_i32(tmp, tmp, 16); + gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp); + neon_store_reg(a->vd, 1, tmp); + tmp3 = tcg_temp_new_i32(); + tcg_gen_ext16u_i32(tmp3, tmp2); + gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); + neon_store_reg(a->vd, 2, tmp3); + tcg_gen_shri_i32(tmp2, tmp2, 16); + gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp); + neon_store_reg(a->vd, 3, tmp2); + tcg_temp_free_i32(ahp); + tcg_temp_free_ptr(fpst); + + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 94d5e34fff..1ea0969554 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4860,7 +4860,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int pass; int u; int vec_size; - TCGv_i32 tmp, tmp2, tmp3; + TCGv_i32 tmp, tmp2; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { return 1; @@ -4927,6 +4927,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VZIP: case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: case NEON_2RM_VSHLL: + case NEON_2RM_VCVT_F16_F32: + case NEON_2RM_VCVT_F32_F16: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4942,67 +4944,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) goto elementwise; } break; - case NEON_2RM_VCVT_F16_F32: - { - TCGv_ptr fpst; - TCGv_i32 ahp; - - if (!dc_isar_feature(aa32_fp16_spconv, s) || - q || (rm & 1)) { - return 1; - } - fpst = get_fpstatus_ptr(true); - ahp = get_ahp_flag(); - tmp = neon_load_reg(rm, 0); - gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); - tmp2 = neon_load_reg(rm, 1); - gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp); - tcg_gen_shli_i32(tmp2, tmp2, 16); - tcg_gen_or_i32(tmp2, tmp2, tmp); - tcg_temp_free_i32(tmp); - tmp = neon_load_reg(rm, 2); - gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); - tmp3 = neon_load_reg(rm, 3); - neon_store_reg(rd, 0, tmp2); - gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp); - tcg_gen_shli_i32(tmp3, tmp3, 16); - tcg_gen_or_i32(tmp3, tmp3, tmp); - neon_store_reg(rd, 1, tmp3); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(ahp); - tcg_temp_free_ptr(fpst); - break; - } - case NEON_2RM_VCVT_F32_F16: - { - TCGv_ptr fpst; - TCGv_i32 ahp; - if (!dc_isar_feature(aa32_fp16_spconv, s) || - q || (rd & 1)) { - return 1; - } - fpst = get_fpstatus_ptr(true); - ahp = get_ahp_flag(); - tmp3 = tcg_temp_new_i32(); - tmp = neon_load_reg(rm, 0); - tmp2 = neon_load_reg(rm, 1); - tcg_gen_ext16u_i32(tmp3, tmp); - gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); - neon_store_reg(rd, 0, tmp3); - tcg_gen_shri_i32(tmp, tmp, 16); - gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp); - neon_store_reg(rd, 1, tmp); - tmp3 = tcg_temp_new_i32(); - tcg_gen_ext16u_i32(tmp3, tmp2); - gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); - neon_store_reg(rd, 2, tmp3); - tcg_gen_shri_i32(tmp2, tmp2, 16); - gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp); - neon_store_reg(rd, 3, tmp2); - tcg_temp_free_i32(ahp); - tcg_temp_free_ptr(fpst); - break; - } case NEON_2RM_AESE: case NEON_2RM_AESMC: if (!dc_isar_feature(aa32_aes, s) || ((rm | rd) & 1)) { return 1; From 75153179e9928775d5333243ea4b278f438d75ae Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:30 +0100 Subject: [PATCH 1518/2595] target/arm: Convert vectorised 2-reg-misc Neon ops to decodetree Convert to decodetree the insns in the Neon 2-reg-misc grouping which we implement using gvec. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-8-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 11 +++++++ target/arm/translate-neon.inc.c | 55 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 35 +++++---------------- 3 files changed, 74 insertions(+), 27 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 8174f2f92f..b5692070d6 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -447,9 +447,20 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc + VMVN 1111 001 11 . 11 .. 00 .... 0 1011 . . 0 .... @2misc + VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc + VCGT0 1111 001 11 . 11 .. 01 .... 0 0000 . . 0 .... @2misc + VCGE0 1111 001 11 . 11 .. 01 .... 0 0001 . . 0 .... @2misc + VCEQ0 1111 001 11 . 11 .. 01 .... 0 0010 . . 0 .... @2misc + VCLE0 1111 001 11 . 11 .. 01 .... 0 0011 . . 0 .... @2misc + VCLT0 1111 001 11 . 11 .. 01 .... 0 0100 . . 0 .... @2misc + + VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc + VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc + VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index d37be597cf..d80123514c 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3450,3 +3450,58 @@ static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) return true; } + +static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn) +{ + int vec_size = a->q ? 16 : 8; + int rd_ofs = neon_reg_offset(a->vd, 0); + int rm_ofs = neon_reg_offset(a->vm, 0); + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (a->size == 3) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size); + + return true; +} + +#define DO_2MISC_VEC(INSN, FN) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + return do_2misc_vec(s, a, FN); \ + } + +DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg) +DO_2MISC_VEC(VABS, tcg_gen_gvec_abs) +DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0) +DO_2MISC_VEC(VCGT0, gen_gvec_cgt0) +DO_2MISC_VEC(VCLE0, gen_gvec_cle0) +DO_2MISC_VEC(VCGE0, gen_gvec_cge0) +DO_2MISC_VEC(VCLT0, gen_gvec_clt0) + +static bool trans_VMVN(DisasContext *s, arg_2misc *a) +{ + if (a->size != 0) { + return false; + } + return do_2misc_vec(s, a, tcg_gen_gvec_not); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 1ea0969554..0f0741a37b 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4859,7 +4859,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int size; int pass; int u; - int vec_size; TCGv_i32 tmp, tmp2; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { @@ -4883,7 +4882,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) VFP_DREG_D(rd, insn); VFP_DREG_M(rm, insn); size = (insn >> 20) & 3; - vec_size = q ? 16 : 8; rd_ofs = neon_reg_offset(rd, 0); rm_ofs = neon_reg_offset(rm, 0); @@ -4929,6 +4927,14 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VSHLL: case NEON_2RM_VCVT_F16_F32: case NEON_2RM_VCVT_F32_F16: + case NEON_2RM_VMVN: + case NEON_2RM_VNEG: + case NEON_2RM_VABS: + case NEON_2RM_VCEQ0: + case NEON_2RM_VCGT0: + case NEON_2RM_VCLE0: + case NEON_2RM_VCGE0: + case NEON_2RM_VCLT0: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4989,31 +4995,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) q ? gen_helper_crypto_sha256su0 : gen_helper_crypto_sha1su1); break; - case NEON_2RM_VMVN: - tcg_gen_gvec_not(0, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VNEG: - tcg_gen_gvec_neg(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VABS: - tcg_gen_gvec_abs(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - - case NEON_2RM_VCEQ0: - gen_gvec_ceq0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCGT0: - gen_gvec_cgt0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCLE0: - gen_gvec_cle0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCGE0: - gen_gvec_cge0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCLT0: - gen_gvec_clt0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; default: elementwise: From 0b30dd5b85e20aba259768cb7aaa952b3e319468 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:31 +0100 Subject: [PATCH 1519/2595] target/arm: Convert Neon 2-reg-misc crypto operations to decodetree Convert the Neon-2-reg misc crypto ops (AESE, AESMC, SHA1H, SHA1SU1) to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-9-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 12 ++++++++ target/arm/translate-neon.inc.c | 42 ++++++++++++++++++++++++++ target/arm/translate.c | 52 +++------------------------------ 3 files changed, 58 insertions(+), 48 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index b5692070d6..86b1b9e34b 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -441,12 +441,19 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm &2misc vm=%vm_dp vd=%vd_dp @2misc_q0 .... ... .. . .. size:2 .. .... . .... . . . .... \ &2misc vm=%vm_dp vd=%vd_dp q=0 + @2misc_q1 .... ... .. . .. size:2 .. .... . .... . . . .... \ + &2misc vm=%vm_dp vd=%vd_dp q=1 VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc + AESE 1111 001 11 . 11 .. 00 .... 0 0110 0 . 0 .... @2misc_q1 + AESD 1111 001 11 . 11 .. 00 .... 0 0110 1 . 0 .... @2misc_q1 + AESMC 1111 001 11 . 11 .. 00 .... 0 0111 0 . 0 .... @2misc_q1 + AESIMC 1111 001 11 . 11 .. 00 .... 0 0111 1 . 0 .... @2misc_q1 + VMVN 1111 001 11 . 11 .. 00 .... 0 1011 . . 0 .... @2misc VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc @@ -458,6 +465,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VCLE0 1111 001 11 . 11 .. 01 .... 0 0011 . . 0 .... @2misc VCLT0 1111 001 11 . 11 .. 01 .... 0 0100 . . 0 .... @2misc + SHA1H 1111 001 11 . 11 .. 01 .... 0 0101 1 . 0 .... @2misc_q1 + VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc @@ -473,6 +482,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VSHLL 1111 001 11 . 11 .. 10 .... 0 0110 0 . 0 .... @2misc_q0 + SHA1SU1 1111 001 11 . 11 .. 10 .... 0 0111 0 . 0 .... @2misc_q1 + SHA256SU0 1111 001 11 . 11 .. 10 .... 0 0111 1 . 0 .... @2misc_q1 + VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0 VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0 ] diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index d80123514c..5e2cd18bf7 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3505,3 +3505,45 @@ static bool trans_VMVN(DisasContext *s, arg_2misc *a) } return do_2misc_vec(s, a, tcg_gen_gvec_not); } + +#define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA) \ + static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ + uint32_t rm_ofs, uint32_t oprsz, \ + uint32_t maxsz) \ + { \ + tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz, \ + DATA, FUNC); \ + } + +#define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA) \ + static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ + uint32_t rm_ofs, uint32_t oprsz, \ + uint32_t maxsz) \ + { \ + tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC); \ + } + +WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0) +WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1) +WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0) +WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1) +WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0) +WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0) +WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0) + +#define DO_2M_CRYPTO(INSN, FEATURE, SIZE) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) { \ + return false; \ + } \ + return do_2misc_vec(s, a, gen_##INSN); \ + } + +DO_2M_CRYPTO(AESE, aa32_aes, 0) +DO_2M_CRYPTO(AESD, aa32_aes, 0) +DO_2M_CRYPTO(AESMC, aa32_aes, 0) +DO_2M_CRYPTO(AESIMC, aa32_aes, 0) +DO_2M_CRYPTO(SHA1H, aa32_sha1, 2) +DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2) +DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2) diff --git a/target/arm/translate.c b/target/arm/translate.c index 0f0741a37b..38644995ab 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4855,7 +4855,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) { int op; int q; - int rd, rm, rd_ofs, rm_ofs; + int rd, rm; int size; int pass; int u; @@ -4882,8 +4882,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) VFP_DREG_D(rd, insn); VFP_DREG_M(rm, insn); size = (insn >> 20) & 3; - rd_ofs = neon_reg_offset(rd, 0); - rm_ofs = neon_reg_offset(rm, 0); if ((insn & (1 << 23)) == 0) { /* Three register same length: handled by decodetree */ @@ -4935,6 +4933,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VCLE0: case NEON_2RM_VCGE0: case NEON_2RM_VCLT0: + case NEON_2RM_AESE: case NEON_2RM_AESMC: + case NEON_2RM_SHA1H: + case NEON_2RM_SHA1SU1: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4950,51 +4951,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) goto elementwise; } break; - case NEON_2RM_AESE: case NEON_2RM_AESMC: - if (!dc_isar_feature(aa32_aes, s) || ((rm | rd) & 1)) { - return 1; - } - /* - * Bit 6 is the lowest opcode bit; it distinguishes - * between encryption (AESE/AESMC) and decryption - * (AESD/AESIMC). - */ - if (op == NEON_2RM_AESE) { - tcg_gen_gvec_3_ool(vfp_reg_offset(true, rd), - vfp_reg_offset(true, rd), - vfp_reg_offset(true, rm), - 16, 16, extract32(insn, 6, 1), - gen_helper_crypto_aese); - } else { - tcg_gen_gvec_2_ool(vfp_reg_offset(true, rd), - vfp_reg_offset(true, rm), - 16, 16, extract32(insn, 6, 1), - gen_helper_crypto_aesmc); - } - break; - case NEON_2RM_SHA1H: - if (!dc_isar_feature(aa32_sha1, s) || ((rm | rd) & 1)) { - return 1; - } - tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0, - gen_helper_crypto_sha1h); - break; - case NEON_2RM_SHA1SU1: - if ((rm | rd) & 1) { - return 1; - } - /* bit 6 (q): set -> SHA256SU0, cleared -> SHA1SU1 */ - if (q) { - if (!dc_isar_feature(aa32_sha2, s)) { - return 1; - } - } else if (!dc_isar_feature(aa32_sha1, s)) { - return 1; - } - tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0, - q ? gen_helper_crypto_sha256su0 - : gen_helper_crypto_sha1su1); - break; default: elementwise: From 039f4e809ad2772fb33de4511ff68a485d875618 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:32 +0100 Subject: [PATCH 1520/2595] target/arm: Rename NeonGenOneOpFn to NeonGenOne64OpFn The NeonGenOneOpFn typedef breaks with the pattern of the other NeonGen*Fn typedefs, because it is a TCGv_i64 -> TCGv_i64 operation but it does not have '64' in its name. Rename it to NeonGenOne64OpFn, so that the old name is available for a TCGv_i32 -> TCGv_i32 operation (which we will need in a subsequent commit). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-10-peter.maydell@linaro.org --- target/arm/translate-a64.c | 4 ++-- target/arm/translate.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index a0e72ad694..7cb5fbfba8 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -11917,8 +11917,8 @@ static void handle_2misc_pairwise(DisasContext *s, int opcode, bool u, } else { for (pass = 0; pass < maxpass; pass++) { TCGv_i64 tcg_op = tcg_temp_new_i64(); - NeonGenOneOpFn *genfn; - static NeonGenOneOpFn * const fns[2][2] = { + NeonGenOne64OpFn *genfn; + static NeonGenOne64OpFn * const fns[2][2] = { { gen_helper_neon_addlp_s8, gen_helper_neon_addlp_u8 }, { gen_helper_neon_addlp_s16, gen_helper_neon_addlp_u16 }, }; diff --git a/target/arm/translate.h b/target/arm/translate.h index 62ed5c4780..35218b3fdf 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -374,7 +374,7 @@ typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32); typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32); typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); -typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64); +typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64); typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr); typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32); typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr); From 5de3fd045be11b74cd0fbf36c6d4fb8387d5463b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:33 +0100 Subject: [PATCH 1521/2595] target/arm: Fix capitalization in NeonGenTwo{Single, Double}OPFn typedefs All the other typedefs like these spell "Op" with a lowercase 'p'; remane the NeonGenTwoSingleOPFn and NeonGenTwoDoubleOPFn typedefs to match. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-11-peter.maydell@linaro.org --- target/arm/translate-a64.c | 4 ++-- target/arm/translate-neon.inc.c | 2 +- target/arm/translate.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 7cb5fbfba8..1204098498 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -9534,7 +9534,7 @@ static void handle_2misc_fcmp_zero(DisasContext *s, int opcode, TCGv_i64 tcg_op = tcg_temp_new_i64(); TCGv_i64 tcg_zero = tcg_const_i64(0); TCGv_i64 tcg_res = tcg_temp_new_i64(); - NeonGenTwoDoubleOPFn *genfn; + NeonGenTwoDoubleOpFn *genfn; bool swap = false; int pass; @@ -9576,7 +9576,7 @@ static void handle_2misc_fcmp_zero(DisasContext *s, int opcode, TCGv_i32 tcg_op = tcg_temp_new_i32(); TCGv_i32 tcg_zero = tcg_const_i32(0); TCGv_i32 tcg_res = tcg_temp_new_i32(); - NeonGenTwoSingleOPFn *genfn; + NeonGenTwoSingleOpFn *genfn; bool swap = false; int pass, maxpasses; diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 5e2cd18bf7..c39443c8ca 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1664,7 +1664,7 @@ static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) } static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, - NeonGenTwoSingleOPFn *fn) + NeonGenTwoSingleOpFn *fn) { /* FP operations in 2-reg-and-shift group */ TCGv_i32 tmp, shiftv; diff --git a/target/arm/translate.h b/target/arm/translate.h index 35218b3fdf..467c529110 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -372,8 +372,8 @@ typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64); typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32); typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32); -typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); -typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); +typedef void NeonGenTwoSingleOpFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); +typedef void NeonGenTwoDoubleOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64); typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr); typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32); From 8ec3de7018a8198624aae49eef5568256114a829 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:34 +0100 Subject: [PATCH 1522/2595] target/arm: Make gen_swap_half() take separate src and dest Make gen_swap_half() take a source and destination TCGv_i32 rather than modifying the input TCGv_i32; we're going to want to be able to use it with the more flexible function signature, and this also brings it into line with other functions like gen_rev16() and gen_revsh(). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-12-peter.maydell@linaro.org --- target/arm/translate-neon.inc.c | 2 +- target/arm/translate.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index c39443c8ca..4967e97438 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3007,7 +3007,7 @@ static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) tcg_gen_bswap32_i32(tmp[half], tmp[half]); break; case 1: - gen_swap_half(tmp[half]); + gen_swap_half(tmp[half], tmp[half]); break; case 2: break; diff --git a/target/arm/translate.c b/target/arm/translate.c index 38644995ab..64b18a95b6 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -378,9 +378,9 @@ static void gen_revsh(TCGv_i32 dest, TCGv_i32 var) } /* Swap low and high halfwords. */ -static void gen_swap_half(TCGv_i32 var) +static void gen_swap_half(TCGv_i32 dest, TCGv_i32 var) { - tcg_gen_rotri_i32(var, var, 16); + tcg_gen_rotri_i32(dest, var, 16); } /* Dual 16-bit add. Result placed in t0 and t1 is marked as dead. @@ -4960,7 +4960,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VREV32: switch (size) { case 0: tcg_gen_bswap32_i32(tmp, tmp); break; - case 1: gen_swap_half(tmp); break; + case 1: gen_swap_half(tmp, tmp); break; default: abort(); } break; @@ -8046,7 +8046,7 @@ static bool op_smlad(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub) t1 = load_reg(s, a->rn); t2 = load_reg(s, a->rm); if (m_swap) { - gen_swap_half(t2); + gen_swap_half(t2, t2); } gen_smul_dual(t1, t2); @@ -8104,7 +8104,7 @@ static bool op_smlald(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub) t1 = load_reg(s, a->rn); t2 = load_reg(s, a->rm); if (m_swap) { - gen_swap_half(t2); + gen_swap_half(t2, t2); } gen_smul_dual(t1, t2); From 8966808205b59d6c196b380b638475bcd1657ef4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:35 +0100 Subject: [PATCH 1523/2595] target/arm: Convert Neon 2-reg-misc VREV32 and VREV16 to decodetree Convert the VREV32 and VREV16 insns in the Neon 2-reg-misc group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-13-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 2 ++ target/arm/translate-neon.inc.c | 55 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 12 ++----- target/arm/translate.h | 1 + 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 86b1b9e34b..0a791af46c 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -445,6 +445,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm &2misc vm=%vm_dp vd=%vd_dp q=1 VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc + VREV32 1111 001 11 . 11 .. 00 .... 0 0001 . . 0 .... @2misc + VREV16 1111 001 11 . 11 .. 00 .... 0 0010 . . 0 .... @2misc VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 4967e97438..0a779980d0 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3547,3 +3547,58 @@ DO_2M_CRYPTO(AESIMC, aa32_aes, 0) DO_2M_CRYPTO(SHA1H, aa32_sha1, 2) DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2) DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2) + +static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn) +{ + int pass; + + /* Handle a 2-reg-misc operation by iterating 32 bits at a time */ + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (!fn) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + TCGv_i32 tmp = neon_load_reg(a->vm, pass); + fn(tmp, tmp); + neon_store_reg(a->vd, pass, tmp); + } + + return true; +} + +static bool trans_VREV32(DisasContext *s, arg_2misc *a) +{ + static NeonGenOneOpFn * const fn[] = { + tcg_gen_bswap32_i32, + gen_swap_half, + NULL, + NULL, + }; + return do_2misc(s, a, fn[a->size]); +} + +static bool trans_VREV16(DisasContext *s, arg_2misc *a) +{ + if (a->size != 0) { + return false; + } + return do_2misc(s, a, gen_rev16); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 64b18a95b6..5b50eddd11 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4936,6 +4936,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_AESE: case NEON_2RM_AESMC: case NEON_2RM_SHA1H: case NEON_2RM_SHA1SU1: + case NEON_2RM_VREV32: + case NEON_2RM_VREV16: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4957,16 +4959,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) for (pass = 0; pass < (q ? 4 : 2); pass++) { tmp = neon_load_reg(rm, pass); switch (op) { - case NEON_2RM_VREV32: - switch (size) { - case 0: tcg_gen_bswap32_i32(tmp, tmp); break; - case 1: gen_swap_half(tmp, tmp); break; - default: abort(); - } - break; - case NEON_2RM_VREV16: - gen_rev16(tmp, tmp); - break; case NEON_2RM_VCLS: switch (size) { case 0: gen_helper_neon_cls_s8(tmp, tmp); break; diff --git a/target/arm/translate.h b/target/arm/translate.h index 467c529110..4dbeee4c89 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -363,6 +363,7 @@ typedef void GVecGen4Fn(unsigned, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); /* Function prototype for gen_ functions for calling Neon helpers */ +typedef void NeonGenOneOpFn(TCGv_i32, TCGv_i32); typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32); typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32); typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32); From 84eae770af69c37a92496a4c4248875c070d5ee3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:36 +0100 Subject: [PATCH 1524/2595] target/arm: Convert remaining simple 2-reg-misc Neon ops Convert the remaining ops in the Neon 2-reg-misc group which can be implemented simply with our do_2misc() helper. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-14-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 10 +++++ target/arm/translate-neon.inc.c | 69 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 38 ++++-------------- 3 files changed, 86 insertions(+), 31 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 0a791af46c..f947f7d09f 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -456,6 +456,10 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm AESMC 1111 001 11 . 11 .. 00 .... 0 0111 0 . 0 .... @2misc_q1 AESIMC 1111 001 11 . 11 .. 00 .... 0 0111 1 . 0 .... @2misc_q1 + VCLS 1111 001 11 . 11 .. 00 .... 0 1000 . . 0 .... @2misc + VCLZ 1111 001 11 . 11 .. 00 .... 0 1001 . . 0 .... @2misc + VCNT 1111 001 11 . 11 .. 00 .... 0 1010 . . 0 .... @2misc + VMVN 1111 001 11 . 11 .. 00 .... 0 1011 . . 0 .... @2misc VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc @@ -472,6 +476,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc + VABS_F 1111 001 11 . 11 .. 01 .... 0 1110 . . 0 .... @2misc + VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc + VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc @@ -489,6 +496,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0 VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0 + + VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc + VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 0a779980d0..336c2b312e 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3602,3 +3602,72 @@ static bool trans_VREV16(DisasContext *s, arg_2misc *a) } return do_2misc(s, a, gen_rev16); } + +static bool trans_VCLS(DisasContext *s, arg_2misc *a) +{ + static NeonGenOneOpFn * const fn[] = { + gen_helper_neon_cls_s8, + gen_helper_neon_cls_s16, + gen_helper_neon_cls_s32, + NULL, + }; + return do_2misc(s, a, fn[a->size]); +} + +static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm) +{ + tcg_gen_clzi_i32(rd, rm, 32); +} + +static bool trans_VCLZ(DisasContext *s, arg_2misc *a) +{ + static NeonGenOneOpFn * const fn[] = { + gen_helper_neon_clz_u8, + gen_helper_neon_clz_u16, + do_VCLZ_32, + NULL, + }; + return do_2misc(s, a, fn[a->size]); +} + +static bool trans_VCNT(DisasContext *s, arg_2misc *a) +{ + if (a->size != 0) { + return false; + } + return do_2misc(s, a, gen_helper_neon_cnt_u8); +} + +static bool trans_VABS_F(DisasContext *s, arg_2misc *a) +{ + if (a->size != 2) { + return false; + } + /* TODO: FP16 : size == 1 */ + return do_2misc(s, a, gen_helper_vfp_abss); +} + +static bool trans_VNEG_F(DisasContext *s, arg_2misc *a) +{ + if (a->size != 2) { + return false; + } + /* TODO: FP16 : size == 1 */ + return do_2misc(s, a, gen_helper_vfp_negs); +} + +static bool trans_VRECPE(DisasContext *s, arg_2misc *a) +{ + if (a->size != 2) { + return false; + } + return do_2misc(s, a, gen_helper_recpe_u32); +} + +static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) +{ + if (a->size != 2) { + return false; + } + return do_2misc(s, a, gen_helper_rsqrte_u32); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 5b50eddd11..1737374388 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4938,6 +4938,13 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_SHA1SU1: case NEON_2RM_VREV32: case NEON_2RM_VREV16: + case NEON_2RM_VCLS: + case NEON_2RM_VCLZ: + case NEON_2RM_VCNT: + case NEON_2RM_VABS_F: + case NEON_2RM_VNEG_F: + case NEON_2RM_VRECPE: + case NEON_2RM_VRSQRTE: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4959,25 +4966,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) for (pass = 0; pass < (q ? 4 : 2); pass++) { tmp = neon_load_reg(rm, pass); switch (op) { - case NEON_2RM_VCLS: - switch (size) { - case 0: gen_helper_neon_cls_s8(tmp, tmp); break; - case 1: gen_helper_neon_cls_s16(tmp, tmp); break; - case 2: gen_helper_neon_cls_s32(tmp, tmp); break; - default: abort(); - } - break; - case NEON_2RM_VCLZ: - switch (size) { - case 0: gen_helper_neon_clz_u8(tmp, tmp); break; - case 1: gen_helper_neon_clz_u16(tmp, tmp); break; - case 2: tcg_gen_clzi_i32(tmp, tmp, 32); break; - default: abort(); - } - break; - case NEON_2RM_VCNT: - gen_helper_neon_cnt_u8(tmp, tmp); - break; case NEON_2RM_VQABS: switch (size) { case 0: @@ -5051,12 +5039,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(fpstatus); break; } - case NEON_2RM_VABS_F: - gen_helper_vfp_abss(tmp, tmp); - break; - case NEON_2RM_VNEG_F: - gen_helper_vfp_negs(tmp, tmp); - break; case NEON_2RM_VSWP: tmp2 = neon_load_reg(rd, pass); neon_store_reg(rm, pass, tmp2); @@ -5137,12 +5119,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(fpst); break; } - case NEON_2RM_VRECPE: - gen_helper_recpe_u32(tmp, tmp); - break; - case NEON_2RM_VRSQRTE: - gen_helper_rsqrte_u32(tmp, tmp); - break; case NEON_2RM_VRECPE_F: { TCGv_ptr fpstatus = get_fpstatus_ptr(1); From 4936f38abe6db0a9d23fd04e4cb0cf4d51cff174 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:37 +0100 Subject: [PATCH 1525/2595] target/arm: Convert Neon VQABS, VQNEG to decodetree Convert the Neon VQABS and VQNEG insns to decodetree. Since these are the only ones which need cpu_env passing to the helper, we wrap the helper rather than creating a whole new do_2misc_env() function. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-15-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 3 +++ target/arm/translate-neon.inc.c | 35 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 30 ++-------------------------- 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index f947f7d09f..f0bb34a49e 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -465,6 +465,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc + VQABS 1111 001 11 . 11 .. 00 .... 0 1110 . . 0 .... @2misc + VQNEG 1111 001 11 . 11 .. 00 .... 0 1111 . . 0 .... @2misc + VCGT0 1111 001 11 . 11 .. 01 .... 0 0000 . . 0 .... @2misc VCGE0 1111 001 11 . 11 .. 01 .... 0 0001 . . 0 .... @2misc VCEQ0 1111 001 11 . 11 .. 01 .... 0 0010 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 336c2b312e..2b5dc86f62 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3671,3 +3671,38 @@ static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) } return do_2misc(s, a, gen_helper_rsqrte_u32); } + +#define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \ + static void WRAPNAME(TCGv_i32 d, TCGv_i32 m) \ + { \ + FUNC(d, cpu_env, m); \ + } + +WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8) +WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16) +WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32) +WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8) +WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16) +WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32) + +static bool trans_VQABS(DisasContext *s, arg_2misc *a) +{ + static NeonGenOneOpFn * const fn[] = { + gen_VQABS_s8, + gen_VQABS_s16, + gen_VQABS_s32, + NULL, + }; + return do_2misc(s, a, fn[a->size]); +} + +static bool trans_VQNEG(DisasContext *s, arg_2misc *a) +{ + static NeonGenOneOpFn * const fn[] = { + gen_VQNEG_s8, + gen_VQNEG_s16, + gen_VQNEG_s32, + NULL, + }; + return do_2misc(s, a, fn[a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 1737374388..3cbd2ab0c9 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4945,6 +4945,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VNEG_F: case NEON_2RM_VRECPE: case NEON_2RM_VRSQRTE: + case NEON_2RM_VQABS: + case NEON_2RM_VQNEG: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4966,34 +4968,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) for (pass = 0; pass < (q ? 4 : 2); pass++) { tmp = neon_load_reg(rm, pass); switch (op) { - case NEON_2RM_VQABS: - switch (size) { - case 0: - gen_helper_neon_qabs_s8(tmp, cpu_env, tmp); - break; - case 1: - gen_helper_neon_qabs_s16(tmp, cpu_env, tmp); - break; - case 2: - gen_helper_neon_qabs_s32(tmp, cpu_env, tmp); - break; - default: abort(); - } - break; - case NEON_2RM_VQNEG: - switch (size) { - case 0: - gen_helper_neon_qneg_s8(tmp, cpu_env, tmp); - break; - case 1: - gen_helper_neon_qneg_s16(tmp, cpu_env, tmp); - break; - case 2: - gen_helper_neon_qneg_s32(tmp, cpu_env, tmp); - break; - default: abort(); - } - break; case NEON_2RM_VCGT0_F: { TCGv_ptr fpstatus = get_fpstatus_ptr(1); From 3e96b205286dfb8bbf363229709e4f8648fce379 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:38 +0100 Subject: [PATCH 1526/2595] target/arm: Convert simple fp Neon 2-reg-misc insns Convert the Neon 2-reg-misc insns which are implemented with simple calls to functions that take the input, output and fpstatus pointer. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-16-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 8 +++++ target/arm/translate-neon.inc.c | 62 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 56 ++++------------------------- target/arm/translate.h | 1 + 4 files changed, 78 insertions(+), 49 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index f0bb34a49e..ea8d5fd99c 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -497,11 +497,19 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm SHA1SU1 1111 001 11 . 11 .. 10 .... 0 0111 0 . 0 .... @2misc_q1 SHA256SU0 1111 001 11 . 11 .. 10 .... 0 0111 1 . 0 .... @2misc_q1 + VRINTX 1111 001 11 . 11 .. 10 .... 0 1001 . . 0 .... @2misc + VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0 VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0 VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc + VRECPE_F 1111 001 11 . 11 .. 11 .... 0 1010 . . 0 .... @2misc + VRSQRTE_F 1111 001 11 . 11 .. 11 .... 0 1011 . . 0 .... @2misc + VCVT_FS 1111 001 11 . 11 .. 11 .... 0 1100 . . 0 .... @2misc + VCVT_FU 1111 001 11 . 11 .. 11 .... 0 1101 . . 0 .... @2misc + VCVT_SF 1111 001 11 . 11 .. 11 .... 0 1110 . . 0 .... @2misc + VCVT_UF 1111 001 11 . 11 .. 11 .... 0 1111 . . 0 .... @2misc ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 2b5dc86f62..ab183e47d7 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3706,3 +3706,65 @@ static bool trans_VQNEG(DisasContext *s, arg_2misc *a) }; return do_2misc(s, a, fn[a->size]); } + +static bool do_2misc_fp(DisasContext *s, arg_2misc *a, + NeonGenOneSingleOpFn *fn) +{ + int pass; + TCGv_ptr fpst; + + /* Handle a 2-reg-misc operation by iterating 32 bits at a time */ + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (a->size != 2) { + /* TODO: FP16 will be the size == 1 case */ + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fpst = get_fpstatus_ptr(1); + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + TCGv_i32 tmp = neon_load_reg(a->vm, pass); + fn(tmp, tmp, fpst); + neon_store_reg(a->vd, pass, tmp); + } + tcg_temp_free_ptr(fpst); + + return true; +} + +#define DO_2MISC_FP(INSN, FUNC) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + return do_2misc_fp(s, a, FUNC); \ + } + +DO_2MISC_FP(VRECPE_F, gen_helper_recpe_f32) +DO_2MISC_FP(VRSQRTE_F, gen_helper_rsqrte_f32) +DO_2MISC_FP(VCVT_FS, gen_helper_vfp_sitos) +DO_2MISC_FP(VCVT_FU, gen_helper_vfp_uitos) +DO_2MISC_FP(VCVT_SF, gen_helper_vfp_tosizs) +DO_2MISC_FP(VCVT_UF, gen_helper_vfp_touizs) + +static bool trans_VRINTX(DisasContext *s, arg_2misc *a) +{ + if (!arm_dc_feature(s, ARM_FEATURE_V8)) { + return false; + } + return do_2misc_fp(s, a, gen_helper_rints_exact); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 3cbd2ab0c9..48377860c7 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4947,6 +4947,13 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VRSQRTE: case NEON_2RM_VQABS: case NEON_2RM_VQNEG: + case NEON_2RM_VRECPE_F: + case NEON_2RM_VRSQRTE_F: + case NEON_2RM_VCVT_FS: + case NEON_2RM_VCVT_FU: + case NEON_2RM_VCVT_SF: + case NEON_2RM_VCVT_UF: + case NEON_2RM_VRINTX: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -5052,13 +5059,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_temp_free_i32(tcg_rmode); break; } - case NEON_2RM_VRINTX: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_rints_exact(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } case NEON_2RM_VCVTAU: case NEON_2RM_VCVTAS: case NEON_2RM_VCVTNU: @@ -5093,48 +5093,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(fpst); break; } - case NEON_2RM_VRECPE_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_recpe_f32(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VRSQRTE_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_rsqrte_f32(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */ - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_sitos(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */ - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_uitos(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */ - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_tosizs(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */ - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_touizs(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } default: /* Reserved op values were caught by the * neon_2rm_sizes[] check earlier. diff --git a/target/arm/translate.h b/target/arm/translate.h index 4dbeee4c89..19650a9e2d 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -373,6 +373,7 @@ typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64); typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32); typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32); +typedef void NeonGenOneSingleOpFn(TCGv_i32, TCGv_i32, TCGv_ptr); typedef void NeonGenTwoSingleOpFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); typedef void NeonGenTwoDoubleOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64); From baa59323e841f76523f6ad4d746cdeb47ea574cd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:39 +0100 Subject: [PATCH 1527/2595] target/arm: Convert Neon 2-reg-misc fp-compare-with-zero insns to decodetree Convert the fp-compare-with-zero insns in the Neon 2-reg-misc group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-17-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 6 ++++ target/arm/translate-neon.inc.c | 28 ++++++++++++++++++ target/arm/translate.c | 50 ++++----------------------------- 3 files changed, 39 insertions(+), 45 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index ea8d5fd99c..c9acd00f1e 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -479,6 +479,12 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc + VCGT0_F 1111 001 11 . 11 .. 01 .... 0 1000 . . 0 .... @2misc + VCGE0_F 1111 001 11 . 11 .. 01 .... 0 1001 . . 0 .... @2misc + VCEQ0_F 1111 001 11 . 11 .. 01 .... 0 1010 . . 0 .... @2misc + VCLE0_F 1111 001 11 . 11 .. 01 .... 0 1011 . . 0 .... @2misc + VCLT0_F 1111 001 11 . 11 .. 01 .... 0 1100 . . 0 .... @2misc + VABS_F 1111 001 11 . 11 .. 01 .... 0 1110 . . 0 .... @2misc VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index ab183e47d7..a62da21b15 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3768,3 +3768,31 @@ static bool trans_VRINTX(DisasContext *s, arg_2misc *a) } return do_2misc_fp(s, a, gen_helper_rints_exact); } + +#define WRAP_FP_CMP0_FWD(WRAPNAME, FUNC) \ + static void WRAPNAME(TCGv_i32 d, TCGv_i32 m, TCGv_ptr fpst) \ + { \ + TCGv_i32 zero = tcg_const_i32(0); \ + FUNC(d, m, zero, fpst); \ + tcg_temp_free_i32(zero); \ + } +#define WRAP_FP_CMP0_REV(WRAPNAME, FUNC) \ + static void WRAPNAME(TCGv_i32 d, TCGv_i32 m, TCGv_ptr fpst) \ + { \ + TCGv_i32 zero = tcg_const_i32(0); \ + FUNC(d, zero, m, fpst); \ + tcg_temp_free_i32(zero); \ + } + +#define DO_FP_CMP0(INSN, FUNC, REV) \ + WRAP_FP_CMP0_##REV(gen_##INSN, FUNC) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + return do_2misc_fp(s, a, gen_##INSN); \ + } + +DO_FP_CMP0(VCGT0_F, gen_helper_neon_cgt_f32, FWD) +DO_FP_CMP0(VCGE0_F, gen_helper_neon_cge_f32, FWD) +DO_FP_CMP0(VCEQ0_F, gen_helper_neon_ceq_f32, FWD) +DO_FP_CMP0(VCLE0_F, gen_helper_neon_cge_f32, REV) +DO_FP_CMP0(VCLT0_F, gen_helper_neon_cgt_f32, REV) diff --git a/target/arm/translate.c b/target/arm/translate.c index 48377860c7..dc98928856 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4954,6 +4954,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VCVT_SF: case NEON_2RM_VCVT_UF: case NEON_2RM_VRINTX: + case NEON_2RM_VCGT0_F: + case NEON_2RM_VCGE0_F: + case NEON_2RM_VCEQ0_F: + case NEON_2RM_VCLE0_F: + case NEON_2RM_VCLT0_F: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4975,51 +4980,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) for (pass = 0; pass < (q ? 4 : 2); pass++) { tmp = neon_load_reg(rm, pass); switch (op) { - case NEON_2RM_VCGT0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCGE0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCEQ0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCLE0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCLT0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } case NEON_2RM_VSWP: tmp2 = neon_load_reg(rd, pass); neon_store_reg(rm, pass, tmp2); From 128123ea34e9e6afe4842aefcb9cf84b9642ac22 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:40 +0100 Subject: [PATCH 1528/2595] target/arm: Convert Neon 2-reg-misc VRINT insns to decodetree Convert the Neon 2-reg-misc VRINT insns to decodetree. Giving these insns their own do_vrint() function allows us to change the rounding mode just once at the start and end rather than doing it for every element in the vector. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-18-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 8 +++++ target/arm/translate-neon.inc.c | 61 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 31 +++-------------- 3 files changed, 74 insertions(+), 26 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index c9acd00f1e..e0717c7e4a 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -503,11 +503,19 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm SHA1SU1 1111 001 11 . 11 .. 10 .... 0 0111 0 . 0 .... @2misc_q1 SHA256SU0 1111 001 11 . 11 .. 10 .... 0 0111 1 . 0 .... @2misc_q1 + VRINTN 1111 001 11 . 11 .. 10 .... 0 1000 . . 0 .... @2misc VRINTX 1111 001 11 . 11 .. 10 .... 0 1001 . . 0 .... @2misc + VRINTA 1111 001 11 . 11 .. 10 .... 0 1010 . . 0 .... @2misc + VRINTZ 1111 001 11 . 11 .. 10 .... 0 1011 . . 0 .... @2misc VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0 + + VRINTM 1111 001 11 . 11 .. 10 .... 0 1101 . . 0 .... @2misc + VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0 + VRINTP 1111 001 11 . 11 .. 10 .... 0 1111 . . 0 .... @2misc + VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc VRECPE_F 1111 001 11 . 11 .. 11 .... 0 1010 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index a62da21b15..0e7f86ad15 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3796,3 +3796,64 @@ DO_FP_CMP0(VCGE0_F, gen_helper_neon_cge_f32, FWD) DO_FP_CMP0(VCEQ0_F, gen_helper_neon_ceq_f32, FWD) DO_FP_CMP0(VCLE0_F, gen_helper_neon_cge_f32, REV) DO_FP_CMP0(VCLT0_F, gen_helper_neon_cgt_f32, REV) + +static bool do_vrint(DisasContext *s, arg_2misc *a, int rmode) +{ + /* + * Handle a VRINT* operation by iterating 32 bits at a time, + * with a specified rounding mode in operation. + */ + int pass; + TCGv_ptr fpst; + TCGv_i32 tcg_rmode; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !arm_dc_feature(s, ARM_FEATURE_V8)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (a->size != 2) { + /* TODO: FP16 will be the size == 1 case */ + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fpst = get_fpstatus_ptr(1); + tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); + gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + TCGv_i32 tmp = neon_load_reg(a->vm, pass); + gen_helper_rints(tmp, tmp, fpst); + neon_store_reg(a->vd, pass, tmp); + } + gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); + tcg_temp_free_i32(tcg_rmode); + tcg_temp_free_ptr(fpst); + + return true; +} + +#define DO_VRINT(INSN, RMODE) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + return do_vrint(s, a, RMODE); \ + } + +DO_VRINT(VRINTN, FPROUNDING_TIEEVEN) +DO_VRINT(VRINTA, FPROUNDING_TIEAWAY) +DO_VRINT(VRINTZ, FPROUNDING_ZERO) +DO_VRINT(VRINTM, FPROUNDING_NEGINF) +DO_VRINT(VRINTP, FPROUNDING_POSINF) diff --git a/target/arm/translate.c b/target/arm/translate.c index dc98928856..61dfc3ae7a 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4959,6 +4959,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VCEQ0_F: case NEON_2RM_VCLE0_F: case NEON_2RM_VCLT0_F: + case NEON_2RM_VRINTN: + case NEON_2RM_VRINTA: + case NEON_2RM_VRINTM: + case NEON_2RM_VRINTP: + case NEON_2RM_VRINTZ: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4993,32 +4998,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } neon_store_reg(rm, pass, tmp2); break; - case NEON_2RM_VRINTN: - case NEON_2RM_VRINTA: - case NEON_2RM_VRINTM: - case NEON_2RM_VRINTP: - case NEON_2RM_VRINTZ: - { - TCGv_i32 tcg_rmode; - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - int rmode; - - if (op == NEON_2RM_VRINTZ) { - rmode = FPROUNDING_ZERO; - } else { - rmode = fp_decode_rm[((op & 0x6) >> 1) ^ 1]; - } - - tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - gen_helper_rints(tmp, tmp, fpstatus); - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - tcg_temp_free_ptr(fpstatus); - tcg_temp_free_i32(tcg_rmode); - break; - } case NEON_2RM_VCVTAU: case NEON_2RM_VCVTAS: case NEON_2RM_VCVTNU: From a183d5fb38b07bab2a840196186c4806f3c67c0d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:41 +0100 Subject: [PATCH 1529/2595] target/arm: Convert Neon 2-reg-misc VCVT insns to decodetree Convert the VCVT instructions in the 2-reg-misc grouping to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-19-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 9 +++++ target/arm/translate-neon.inc.c | 70 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 70 ++++----------------------------- 3 files changed, 87 insertions(+), 62 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index e0717c7e4a..5507c3e462 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -516,6 +516,15 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VRINTP 1111 001 11 . 11 .. 10 .... 0 1111 . . 0 .... @2misc + VCVTAS 1111 001 11 . 11 .. 11 .... 0 0000 . . 0 .... @2misc + VCVTAU 1111 001 11 . 11 .. 11 .... 0 0001 . . 0 .... @2misc + VCVTNS 1111 001 11 . 11 .. 11 .... 0 0010 . . 0 .... @2misc + VCVTNU 1111 001 11 . 11 .. 11 .... 0 0011 . . 0 .... @2misc + VCVTPS 1111 001 11 . 11 .. 11 .... 0 0100 . . 0 .... @2misc + VCVTPU 1111 001 11 . 11 .. 11 .... 0 0101 . . 0 .... @2misc + VCVTMS 1111 001 11 . 11 .. 11 .... 0 0110 . . 0 .... @2misc + VCVTMU 1111 001 11 . 11 .. 11 .... 0 0111 . . 0 .... @2misc + VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc VRECPE_F 1111 001 11 . 11 .. 11 .... 0 1010 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 0e7f86ad15..29bc161f36 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3857,3 +3857,73 @@ DO_VRINT(VRINTA, FPROUNDING_TIEAWAY) DO_VRINT(VRINTZ, FPROUNDING_ZERO) DO_VRINT(VRINTM, FPROUNDING_NEGINF) DO_VRINT(VRINTP, FPROUNDING_POSINF) + +static bool do_vcvt(DisasContext *s, arg_2misc *a, int rmode, bool is_signed) +{ + /* + * Handle a VCVT* operation by iterating 32 bits at a time, + * with a specified rounding mode in operation. + */ + int pass; + TCGv_ptr fpst; + TCGv_i32 tcg_rmode, tcg_shift; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !arm_dc_feature(s, ARM_FEATURE_V8)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (a->size != 2) { + /* TODO: FP16 will be the size == 1 case */ + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fpst = get_fpstatus_ptr(1); + tcg_shift = tcg_const_i32(0); + tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); + gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + TCGv_i32 tmp = neon_load_reg(a->vm, pass); + if (is_signed) { + gen_helper_vfp_tosls(tmp, tmp, tcg_shift, fpst); + } else { + gen_helper_vfp_touls(tmp, tmp, tcg_shift, fpst); + } + neon_store_reg(a->vd, pass, tmp); + } + gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); + tcg_temp_free_i32(tcg_rmode); + tcg_temp_free_i32(tcg_shift); + tcg_temp_free_ptr(fpst); + + return true; +} + +#define DO_VCVT(INSN, RMODE, SIGNED) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + return do_vcvt(s, a, RMODE, SIGNED); \ + } + +DO_VCVT(VCVTAU, FPROUNDING_TIEAWAY, false) +DO_VCVT(VCVTAS, FPROUNDING_TIEAWAY, true) +DO_VCVT(VCVTNU, FPROUNDING_TIEEVEN, false) +DO_VCVT(VCVTNS, FPROUNDING_TIEEVEN, true) +DO_VCVT(VCVTPU, FPROUNDING_POSINF, false) +DO_VCVT(VCVTPS, FPROUNDING_POSINF, true) +DO_VCVT(VCVTMU, FPROUNDING_NEGINF, false) +DO_VCVT(VCVTMS, FPROUNDING_NEGINF, true) diff --git a/target/arm/translate.c b/target/arm/translate.c index 61dfc3ae7a..b018106202 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3042,30 +3042,6 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) #define NEON_2RM_VCVT_SF 62 #define NEON_2RM_VCVT_UF 63 -static bool neon_2rm_is_v8_op(int op) -{ - /* Return true if this neon 2reg-misc op is ARMv8 and up */ - switch (op) { - case NEON_2RM_VRINTN: - case NEON_2RM_VRINTA: - case NEON_2RM_VRINTM: - case NEON_2RM_VRINTP: - case NEON_2RM_VRINTZ: - case NEON_2RM_VRINTX: - case NEON_2RM_VCVTAU: - case NEON_2RM_VCVTAS: - case NEON_2RM_VCVTNU: - case NEON_2RM_VCVTNS: - case NEON_2RM_VCVTPU: - case NEON_2RM_VCVTPS: - case NEON_2RM_VCVTMU: - case NEON_2RM_VCVTMS: - return true; - default: - return false; - } -} - /* Each entry in this array has bit n set if the insn allows * size value n (otherwise it will UNDEF). Since unallocated * op values will have no bits set they always UNDEF. @@ -4908,10 +4884,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if ((neon_2rm_sizes[op] & (1 << size)) == 0) { return 1; } - if (neon_2rm_is_v8_op(op) && - !arm_dc_feature(s, ARM_FEATURE_V8)) { - return 1; - } if (q && ((rm | rd) & 1)) { return 1; } @@ -4964,6 +4936,14 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VRINTM: case NEON_2RM_VRINTP: case NEON_2RM_VRINTZ: + case NEON_2RM_VCVTAU: + case NEON_2RM_VCVTAS: + case NEON_2RM_VCVTNU: + case NEON_2RM_VCVTNS: + case NEON_2RM_VCVTPU: + case NEON_2RM_VCVTPS: + case NEON_2RM_VCVTMU: + case NEON_2RM_VCVTMS: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4998,40 +4978,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } neon_store_reg(rm, pass, tmp2); break; - case NEON_2RM_VCVTAU: - case NEON_2RM_VCVTAS: - case NEON_2RM_VCVTNU: - case NEON_2RM_VCVTNS: - case NEON_2RM_VCVTPU: - case NEON_2RM_VCVTPS: - case NEON_2RM_VCVTMU: - case NEON_2RM_VCVTMS: - { - bool is_signed = !extract32(insn, 7, 1); - TCGv_ptr fpst = get_fpstatus_ptr(1); - TCGv_i32 tcg_rmode, tcg_shift; - int rmode = fp_decode_rm[extract32(insn, 8, 2)]; - - tcg_shift = tcg_const_i32(0); - tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - - if (is_signed) { - gen_helper_vfp_tosls(tmp, tmp, - tcg_shift, fpst); - } else { - gen_helper_vfp_touls(tmp, tmp, - tcg_shift, fpst); - } - - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - tcg_temp_free_i32(tcg_rmode); - tcg_temp_free_i32(tcg_shift); - tcg_temp_free_ptr(fpst); - break; - } default: /* Reserved op values were caught by the * neon_2rm_sizes[] check earlier. From 8ab3a227a0f13f0ff85846f36f7c466769aef4fc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:42 +0100 Subject: [PATCH 1530/2595] target/arm: Convert Neon VSWP to decodetree Convert the Neon VSWP insn to decodetree. Since the new implementation doesn't have to share a pass-loop with the other 2-reg-misc operations we can implement the swap with 64-bit accesses rather than 32-bits (which brings us into line with the pseudocode and is more efficient). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-20-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 2 ++ target/arm/translate-neon.inc.c | 41 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 5 +--- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 5507c3e462..2f64841de5 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -488,6 +488,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VABS_F 1111 001 11 . 11 .. 01 .... 0 1110 . . 0 .... @2misc VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc + VSWP 1111 001 11 . 11 .. 10 .... 0 0000 . . 0 .... @2misc + VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 29bc161f36..01da7fad46 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3927,3 +3927,44 @@ DO_VCVT(VCVTPU, FPROUNDING_POSINF, false) DO_VCVT(VCVTPS, FPROUNDING_POSINF, true) DO_VCVT(VCVTMU, FPROUNDING_NEGINF, false) DO_VCVT(VCVTMS, FPROUNDING_NEGINF, true) + +static bool trans_VSWP(DisasContext *s, arg_2misc *a) +{ + TCGv_i64 rm, rd; + int pass; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (a->size != 0) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + rm = tcg_temp_new_i64(); + rd = tcg_temp_new_i64(); + for (pass = 0; pass < (a->q ? 2 : 1); pass++) { + neon_load_reg64(rm, a->vm + pass); + neon_load_reg64(rd, a->vd + pass); + neon_store_reg64(rm, a->vd + pass); + neon_store_reg64(rd, a->vm + pass); + } + tcg_temp_free_i64(rm); + tcg_temp_free_i64(rd); + + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index b018106202..e8cd4a9c61 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4944,6 +4944,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VCVTPS: case NEON_2RM_VCVTMU: case NEON_2RM_VCVTMS: + case NEON_2RM_VSWP: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4965,10 +4966,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) for (pass = 0; pass < (q ? 4 : 2); pass++) { tmp = neon_load_reg(rm, pass); switch (op) { - case NEON_2RM_VSWP: - tmp2 = neon_load_reg(rd, pass); - neon_store_reg(rm, pass, tmp2); - break; case NEON_2RM_VTRN: tmp2 = neon_load_reg(rd, pass); switch (size) { From d4366190f84fe89cc5d46da995dac1e7d541b98e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:43 +0100 Subject: [PATCH 1531/2595] target/arm: Convert Neon VTRN to decodetree Convert the Neon VTRN insn to decodetree. This is the last insn in the Neon data-processing group, so we can remove all the now-unused old decoder framework. It's possible that there's a more efficient implementation of VTRN, but for this conversion we just copy the existing approach. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-21-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 2 +- target/arm/translate-neon.inc.c | 90 ++++++++ target/arm/translate.c | 363 +------------------------------- 3 files changed, 93 insertions(+), 362 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 2f64841de5..686f9fbf46 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -489,7 +489,7 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc VSWP 1111 001 11 . 11 .. 10 .... 0 0000 . . 0 .... @2misc - + VTRN 1111 001 11 . 11 .. 10 .... 0 0001 . . 0 .... @2misc VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 01da7fad46..8cc7f5db54 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3968,3 +3968,93 @@ static bool trans_VSWP(DisasContext *s, arg_2misc *a) return true; } +static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) +{ + TCGv_i32 rd, tmp; + + rd = tcg_temp_new_i32(); + tmp = tcg_temp_new_i32(); + + tcg_gen_shli_i32(rd, t0, 8); + tcg_gen_andi_i32(rd, rd, 0xff00ff00); + tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); + tcg_gen_or_i32(rd, rd, tmp); + + tcg_gen_shri_i32(t1, t1, 8); + tcg_gen_andi_i32(t1, t1, 0x00ff00ff); + tcg_gen_andi_i32(tmp, t0, 0xff00ff00); + tcg_gen_or_i32(t1, t1, tmp); + tcg_gen_mov_i32(t0, rd); + + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(rd); +} + +static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) +{ + TCGv_i32 rd, tmp; + + rd = tcg_temp_new_i32(); + tmp = tcg_temp_new_i32(); + + tcg_gen_shli_i32(rd, t0, 16); + tcg_gen_andi_i32(tmp, t1, 0xffff); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shri_i32(t1, t1, 16); + tcg_gen_andi_i32(tmp, t0, 0xffff0000); + tcg_gen_or_i32(t1, t1, tmp); + tcg_gen_mov_i32(t0, rd); + + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(rd); +} + +static bool trans_VTRN(DisasContext *s, arg_2misc *a) +{ + TCGv_i32 tmp, tmp2; + int pass; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (a->size == 3) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + if (a->size == 2) { + for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) { + tmp = neon_load_reg(a->vm, pass); + tmp2 = neon_load_reg(a->vd, pass + 1); + neon_store_reg(a->vm, pass, tmp2); + neon_store_reg(a->vd, pass + 1, tmp); + } + } else { + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + tmp = neon_load_reg(a->vm, pass); + tmp2 = neon_load_reg(a->vd, pass); + if (a->size == 0) { + gen_neon_trn_u8(tmp, tmp2); + } else { + gen_neon_trn_u16(tmp, tmp2); + } + neon_store_reg(a->vm, pass, tmp2); + neon_store_reg(a->vd, pass, tmp); + } + } + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index e8cd4a9c61..581b0b5cde 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2934,183 +2934,6 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc) gen_rfe(s, pc, load_cpu_field(spsr)); } -static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) -{ - TCGv_i32 rd, tmp; - - rd = tcg_temp_new_i32(); - tmp = tcg_temp_new_i32(); - - tcg_gen_shli_i32(rd, t0, 8); - tcg_gen_andi_i32(rd, rd, 0xff00ff00); - tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); - tcg_gen_or_i32(rd, rd, tmp); - - tcg_gen_shri_i32(t1, t1, 8); - tcg_gen_andi_i32(t1, t1, 0x00ff00ff); - tcg_gen_andi_i32(tmp, t0, 0xff00ff00); - tcg_gen_or_i32(t1, t1, tmp); - tcg_gen_mov_i32(t0, rd); - - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(rd); -} - -static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) -{ - TCGv_i32 rd, tmp; - - rd = tcg_temp_new_i32(); - tmp = tcg_temp_new_i32(); - - tcg_gen_shli_i32(rd, t0, 16); - tcg_gen_andi_i32(tmp, t1, 0xffff); - tcg_gen_or_i32(rd, rd, tmp); - tcg_gen_shri_i32(t1, t1, 16); - tcg_gen_andi_i32(tmp, t0, 0xffff0000); - tcg_gen_or_i32(t1, t1, tmp); - tcg_gen_mov_i32(t0, rd); - - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(rd); -} - -/* Symbolic constants for op fields for Neon 2-register miscellaneous. - * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B - * table A7-13. - */ -#define NEON_2RM_VREV64 0 -#define NEON_2RM_VREV32 1 -#define NEON_2RM_VREV16 2 -#define NEON_2RM_VPADDL 4 -#define NEON_2RM_VPADDL_U 5 -#define NEON_2RM_AESE 6 /* Includes AESD */ -#define NEON_2RM_AESMC 7 /* Includes AESIMC */ -#define NEON_2RM_VCLS 8 -#define NEON_2RM_VCLZ 9 -#define NEON_2RM_VCNT 10 -#define NEON_2RM_VMVN 11 -#define NEON_2RM_VPADAL 12 -#define NEON_2RM_VPADAL_U 13 -#define NEON_2RM_VQABS 14 -#define NEON_2RM_VQNEG 15 -#define NEON_2RM_VCGT0 16 -#define NEON_2RM_VCGE0 17 -#define NEON_2RM_VCEQ0 18 -#define NEON_2RM_VCLE0 19 -#define NEON_2RM_VCLT0 20 -#define NEON_2RM_SHA1H 21 -#define NEON_2RM_VABS 22 -#define NEON_2RM_VNEG 23 -#define NEON_2RM_VCGT0_F 24 -#define NEON_2RM_VCGE0_F 25 -#define NEON_2RM_VCEQ0_F 26 -#define NEON_2RM_VCLE0_F 27 -#define NEON_2RM_VCLT0_F 28 -#define NEON_2RM_VABS_F 30 -#define NEON_2RM_VNEG_F 31 -#define NEON_2RM_VSWP 32 -#define NEON_2RM_VTRN 33 -#define NEON_2RM_VUZP 34 -#define NEON_2RM_VZIP 35 -#define NEON_2RM_VMOVN 36 /* Includes VQMOVN, VQMOVUN */ -#define NEON_2RM_VQMOVN 37 /* Includes VQMOVUN */ -#define NEON_2RM_VSHLL 38 -#define NEON_2RM_SHA1SU1 39 /* Includes SHA256SU0 */ -#define NEON_2RM_VRINTN 40 -#define NEON_2RM_VRINTX 41 -#define NEON_2RM_VRINTA 42 -#define NEON_2RM_VRINTZ 43 -#define NEON_2RM_VCVT_F16_F32 44 -#define NEON_2RM_VRINTM 45 -#define NEON_2RM_VCVT_F32_F16 46 -#define NEON_2RM_VRINTP 47 -#define NEON_2RM_VCVTAU 48 -#define NEON_2RM_VCVTAS 49 -#define NEON_2RM_VCVTNU 50 -#define NEON_2RM_VCVTNS 51 -#define NEON_2RM_VCVTPU 52 -#define NEON_2RM_VCVTPS 53 -#define NEON_2RM_VCVTMU 54 -#define NEON_2RM_VCVTMS 55 -#define NEON_2RM_VRECPE 56 -#define NEON_2RM_VRSQRTE 57 -#define NEON_2RM_VRECPE_F 58 -#define NEON_2RM_VRSQRTE_F 59 -#define NEON_2RM_VCVT_FS 60 -#define NEON_2RM_VCVT_FU 61 -#define NEON_2RM_VCVT_SF 62 -#define NEON_2RM_VCVT_UF 63 - -/* Each entry in this array has bit n set if the insn allows - * size value n (otherwise it will UNDEF). Since unallocated - * op values will have no bits set they always UNDEF. - */ -static const uint8_t neon_2rm_sizes[] = { - [NEON_2RM_VREV64] = 0x7, - [NEON_2RM_VREV32] = 0x3, - [NEON_2RM_VREV16] = 0x1, - [NEON_2RM_VPADDL] = 0x7, - [NEON_2RM_VPADDL_U] = 0x7, - [NEON_2RM_AESE] = 0x1, - [NEON_2RM_AESMC] = 0x1, - [NEON_2RM_VCLS] = 0x7, - [NEON_2RM_VCLZ] = 0x7, - [NEON_2RM_VCNT] = 0x1, - [NEON_2RM_VMVN] = 0x1, - [NEON_2RM_VPADAL] = 0x7, - [NEON_2RM_VPADAL_U] = 0x7, - [NEON_2RM_VQABS] = 0x7, - [NEON_2RM_VQNEG] = 0x7, - [NEON_2RM_VCGT0] = 0x7, - [NEON_2RM_VCGE0] = 0x7, - [NEON_2RM_VCEQ0] = 0x7, - [NEON_2RM_VCLE0] = 0x7, - [NEON_2RM_VCLT0] = 0x7, - [NEON_2RM_SHA1H] = 0x4, - [NEON_2RM_VABS] = 0x7, - [NEON_2RM_VNEG] = 0x7, - [NEON_2RM_VCGT0_F] = 0x4, - [NEON_2RM_VCGE0_F] = 0x4, - [NEON_2RM_VCEQ0_F] = 0x4, - [NEON_2RM_VCLE0_F] = 0x4, - [NEON_2RM_VCLT0_F] = 0x4, - [NEON_2RM_VABS_F] = 0x4, - [NEON_2RM_VNEG_F] = 0x4, - [NEON_2RM_VSWP] = 0x1, - [NEON_2RM_VTRN] = 0x7, - [NEON_2RM_VUZP] = 0x7, - [NEON_2RM_VZIP] = 0x7, - [NEON_2RM_VMOVN] = 0x7, - [NEON_2RM_VQMOVN] = 0x7, - [NEON_2RM_VSHLL] = 0x7, - [NEON_2RM_SHA1SU1] = 0x4, - [NEON_2RM_VRINTN] = 0x4, - [NEON_2RM_VRINTX] = 0x4, - [NEON_2RM_VRINTA] = 0x4, - [NEON_2RM_VRINTZ] = 0x4, - [NEON_2RM_VCVT_F16_F32] = 0x2, - [NEON_2RM_VRINTM] = 0x4, - [NEON_2RM_VCVT_F32_F16] = 0x2, - [NEON_2RM_VRINTP] = 0x4, - [NEON_2RM_VCVTAU] = 0x4, - [NEON_2RM_VCVTAS] = 0x4, - [NEON_2RM_VCVTNU] = 0x4, - [NEON_2RM_VCVTNS] = 0x4, - [NEON_2RM_VCVTPU] = 0x4, - [NEON_2RM_VCVTPS] = 0x4, - [NEON_2RM_VCVTMU] = 0x4, - [NEON_2RM_VCVTMS] = 0x4, - [NEON_2RM_VRECPE] = 0x4, - [NEON_2RM_VRSQRTE] = 0x4, - [NEON_2RM_VRECPE_F] = 0x4, - [NEON_2RM_VRSQRTE_F] = 0x4, - [NEON_2RM_VCVT_FS] = 0x4, - [NEON_2RM_VCVT_FU] = 0x4, - [NEON_2RM_VCVT_SF] = 0x4, - [NEON_2RM_VCVT_UF] = 0x4, -}; - static void gen_gvec_fn3_qc(uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz, gen_helper_gvec_3_ptr *fn) @@ -4822,178 +4645,6 @@ void gen_gvec_uaba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); } -/* Translate a NEON data processing instruction. Return nonzero if the - instruction is invalid. - We process data in a mixture of 32-bit and 64-bit chunks. - Mostly we use 32-bit chunks so we can use normal scalar instructions. */ - -static int disas_neon_data_insn(DisasContext *s, uint32_t insn) -{ - int op; - int q; - int rd, rm; - int size; - int pass; - int u; - TCGv_i32 tmp, tmp2; - - if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { - return 1; - } - - /* FIXME: this access check should not take precedence over UNDEF - * for invalid encodings; we will generate incorrect syndrome information - * for attempts to execute invalid vfp/neon encodings with FP disabled. - */ - if (s->fp_excp_el) { - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_simd_access_trap(1, 0xe, false), s->fp_excp_el); - return 0; - } - - if (!s->vfp_enabled) - return 1; - q = (insn & (1 << 6)) != 0; - u = (insn >> 24) & 1; - VFP_DREG_D(rd, insn); - VFP_DREG_M(rm, insn); - size = (insn >> 20) & 3; - - if ((insn & (1 << 23)) == 0) { - /* Three register same length: handled by decodetree */ - return 1; - } else if (insn & (1 << 4)) { - /* Two registers and shift or reg and imm: handled by decodetree */ - return 1; - } else { /* (insn & 0x00800010 == 0x00800000) */ - if (size != 3) { - /* - * Three registers of different lengths, or two registers and - * a scalar: handled by decodetree - */ - return 1; - } else { /* size == 3 */ - if (!u) { - /* Extract: handled by decodetree */ - return 1; - } else if ((insn & (1 << 11)) == 0) { - /* Two register misc. */ - op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf); - size = (insn >> 18) & 3; - /* UNDEF for unknown op values and bad op-size combinations */ - if ((neon_2rm_sizes[op] & (1 << size)) == 0) { - return 1; - } - if (q && ((rm | rd) & 1)) { - return 1; - } - switch (op) { - case NEON_2RM_VREV64: - case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U: - case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: - case NEON_2RM_VUZP: - case NEON_2RM_VZIP: - case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: - case NEON_2RM_VSHLL: - case NEON_2RM_VCVT_F16_F32: - case NEON_2RM_VCVT_F32_F16: - case NEON_2RM_VMVN: - case NEON_2RM_VNEG: - case NEON_2RM_VABS: - case NEON_2RM_VCEQ0: - case NEON_2RM_VCGT0: - case NEON_2RM_VCLE0: - case NEON_2RM_VCGE0: - case NEON_2RM_VCLT0: - case NEON_2RM_AESE: case NEON_2RM_AESMC: - case NEON_2RM_SHA1H: - case NEON_2RM_SHA1SU1: - case NEON_2RM_VREV32: - case NEON_2RM_VREV16: - case NEON_2RM_VCLS: - case NEON_2RM_VCLZ: - case NEON_2RM_VCNT: - case NEON_2RM_VABS_F: - case NEON_2RM_VNEG_F: - case NEON_2RM_VRECPE: - case NEON_2RM_VRSQRTE: - case NEON_2RM_VQABS: - case NEON_2RM_VQNEG: - case NEON_2RM_VRECPE_F: - case NEON_2RM_VRSQRTE_F: - case NEON_2RM_VCVT_FS: - case NEON_2RM_VCVT_FU: - case NEON_2RM_VCVT_SF: - case NEON_2RM_VCVT_UF: - case NEON_2RM_VRINTX: - case NEON_2RM_VCGT0_F: - case NEON_2RM_VCGE0_F: - case NEON_2RM_VCEQ0_F: - case NEON_2RM_VCLE0_F: - case NEON_2RM_VCLT0_F: - case NEON_2RM_VRINTN: - case NEON_2RM_VRINTA: - case NEON_2RM_VRINTM: - case NEON_2RM_VRINTP: - case NEON_2RM_VRINTZ: - case NEON_2RM_VCVTAU: - case NEON_2RM_VCVTAS: - case NEON_2RM_VCVTNU: - case NEON_2RM_VCVTNS: - case NEON_2RM_VCVTPU: - case NEON_2RM_VCVTPS: - case NEON_2RM_VCVTMU: - case NEON_2RM_VCVTMS: - case NEON_2RM_VSWP: - /* handled by decodetree */ - return 1; - case NEON_2RM_VTRN: - if (size == 2) { - int n; - for (n = 0; n < (q ? 4 : 2); n += 2) { - tmp = neon_load_reg(rm, n); - tmp2 = neon_load_reg(rd, n + 1); - neon_store_reg(rm, n, tmp2); - neon_store_reg(rd, n + 1, tmp); - } - } else { - goto elementwise; - } - break; - - default: - elementwise: - for (pass = 0; pass < (q ? 4 : 2); pass++) { - tmp = neon_load_reg(rm, pass); - switch (op) { - case NEON_2RM_VTRN: - tmp2 = neon_load_reg(rd, pass); - switch (size) { - case 0: gen_neon_trn_u8(tmp, tmp2); break; - case 1: gen_neon_trn_u16(tmp, tmp2); break; - default: abort(); - } - neon_store_reg(rm, pass, tmp2); - break; - default: - /* Reserved op values were caught by the - * neon_2rm_sizes[] check earlier. - */ - abort(); - } - neon_store_reg(rd, pass, tmp); - } - break; - } - } else { - /* VTBL, VTBX, VDUP: handled by decodetree */ - return 1; - } - } - } - return 0; -} - static int disas_coproc_insn(DisasContext *s, uint32_t insn) { int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2; @@ -8694,13 +8345,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } /* fall back to legacy decoder */ - if (((insn >> 25) & 7) == 1) { - /* NEON Data processing. */ - if (disas_neon_data_insn(s, insn)) { - goto illegal_op; - } - return; - } if ((insn & 0x0e000f00) == 0x0c000100) { if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) { /* iWMMXt register transfer. */ @@ -8888,11 +8532,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) break; } if (((insn >> 24) & 3) == 3) { - /* Translate into the equivalent ARM encoding. */ - insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28); - if (disas_neon_data_insn(s, insn)) { - goto illegal_op; - } + /* Neon DP, but failed disas_neon_dp() */ + goto illegal_op; } else if (((insn >> 8) & 0xe) == 10) { /* VFP, but failed disas_vfp. */ goto illegal_op; From 6fb5787898aab6aa04887fed9cf3220dd4c3f36a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:44 +0100 Subject: [PATCH 1532/2595] target/arm: Move some functions used only in translate-neon.inc.c to that file The functions neon_element_offset(), neon_load_element(), neon_load_element64(), neon_store_element() and neon_store_element64() are used only in the translate-neon.inc.c file, so move their definitions there. Since the .inc.c file is #included in translate.c this doesn't make much difference currently, but it's a more logical place to put the functions and it might be helpful if we ever decide to try to make the .inc.c files genuinely separate compilation units. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-22-peter.maydell@linaro.org --- target/arm/translate-neon.inc.c | 101 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 101 -------------------------------- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 8cc7f5db54..f6cb921573 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -54,6 +54,107 @@ static inline int rsub_8(DisasContext *s, int x) #include "decode-neon-ls.inc.c" #include "decode-neon-shared.inc.c" +/* Return the offset of a 2**SIZE piece of a NEON register, at index ELE, + * where 0 is the least significant end of the register. + */ +static inline long +neon_element_offset(int reg, int element, MemOp size) +{ + int element_size = 1 << size; + int ofs = element * element_size; +#ifdef HOST_WORDS_BIGENDIAN + /* Calculate the offset assuming fully little-endian, + * then XOR to account for the order of the 8-byte units. + */ + if (element_size < 8) { + ofs ^= 8 - element_size; + } +#endif + return neon_reg_offset(reg, 0) + ofs; +} + +static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) +{ + long offset = neon_element_offset(reg, ele, mop & MO_SIZE); + + switch (mop) { + case MO_UB: + tcg_gen_ld8u_i32(var, cpu_env, offset); + break; + case MO_UW: + tcg_gen_ld16u_i32(var, cpu_env, offset); + break; + case MO_UL: + tcg_gen_ld_i32(var, cpu_env, offset); + break; + default: + g_assert_not_reached(); + } +} + +static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) +{ + long offset = neon_element_offset(reg, ele, mop & MO_SIZE); + + switch (mop) { + case MO_UB: + tcg_gen_ld8u_i64(var, cpu_env, offset); + break; + case MO_UW: + tcg_gen_ld16u_i64(var, cpu_env, offset); + break; + case MO_UL: + tcg_gen_ld32u_i64(var, cpu_env, offset); + break; + case MO_Q: + tcg_gen_ld_i64(var, cpu_env, offset); + break; + default: + g_assert_not_reached(); + } +} + +static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) +{ + long offset = neon_element_offset(reg, ele, size); + + switch (size) { + case MO_8: + tcg_gen_st8_i32(var, cpu_env, offset); + break; + case MO_16: + tcg_gen_st16_i32(var, cpu_env, offset); + break; + case MO_32: + tcg_gen_st_i32(var, cpu_env, offset); + break; + default: + g_assert_not_reached(); + } +} + +static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) +{ + long offset = neon_element_offset(reg, ele, size); + + switch (size) { + case MO_8: + tcg_gen_st8_i64(var, cpu_env, offset); + break; + case MO_16: + tcg_gen_st16_i64(var, cpu_env, offset); + break; + case MO_32: + tcg_gen_st32_i64(var, cpu_env, offset); + break; + case MO_64: + tcg_gen_st_i64(var, cpu_env, offset); + break; + default: + g_assert_not_reached(); + } +} + static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) { int opr_sz; diff --git a/target/arm/translate.c b/target/arm/translate.c index 581b0b5cde..408fb7a492 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -1133,25 +1133,6 @@ neon_reg_offset (int reg, int n) return vfp_reg_offset(0, sreg); } -/* Return the offset of a 2**SIZE piece of a NEON register, at index ELE, - * where 0 is the least significant end of the register. - */ -static inline long -neon_element_offset(int reg, int element, MemOp size) -{ - int element_size = 1 << size; - int ofs = element * element_size; -#ifdef HOST_WORDS_BIGENDIAN - /* Calculate the offset assuming fully little-endian, - * then XOR to account for the order of the 8-byte units. - */ - if (element_size < 8) { - ofs ^= 8 - element_size; - } -#endif - return neon_reg_offset(reg, 0) + ofs; -} - static TCGv_i32 neon_load_reg(int reg, int pass) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -1159,94 +1140,12 @@ static TCGv_i32 neon_load_reg(int reg, int pass) return tmp; } -static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) -{ - long offset = neon_element_offset(reg, ele, mop & MO_SIZE); - - switch (mop) { - case MO_UB: - tcg_gen_ld8u_i32(var, cpu_env, offset); - break; - case MO_UW: - tcg_gen_ld16u_i32(var, cpu_env, offset); - break; - case MO_UL: - tcg_gen_ld_i32(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - -static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) -{ - long offset = neon_element_offset(reg, ele, mop & MO_SIZE); - - switch (mop) { - case MO_UB: - tcg_gen_ld8u_i64(var, cpu_env, offset); - break; - case MO_UW: - tcg_gen_ld16u_i64(var, cpu_env, offset); - break; - case MO_UL: - tcg_gen_ld32u_i64(var, cpu_env, offset); - break; - case MO_Q: - tcg_gen_ld_i64(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - static void neon_store_reg(int reg, int pass, TCGv_i32 var) { tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass)); tcg_temp_free_i32(var); } -static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) -{ - long offset = neon_element_offset(reg, ele, size); - - switch (size) { - case MO_8: - tcg_gen_st8_i32(var, cpu_env, offset); - break; - case MO_16: - tcg_gen_st16_i32(var, cpu_env, offset); - break; - case MO_32: - tcg_gen_st_i32(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - -static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) -{ - long offset = neon_element_offset(reg, ele, size); - - switch (size) { - case MO_8: - tcg_gen_st8_i64(var, cpu_env, offset); - break; - case MO_16: - tcg_gen_st16_i64(var, cpu_env, offset); - break; - case MO_32: - tcg_gen_st32_i64(var, cpu_env, offset); - break; - case MO_64: - tcg_gen_st_i64(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - static inline void neon_load_reg64(TCGv_i64 var, int reg) { tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg)); From 55c812b74289863c348449135812027d188f040a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 19 Jun 2020 18:03:24 +0100 Subject: [PATCH 1533/2595] target/arm: Remove unnecessary gen_io_end() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ba3e7926691ed3 it has been unnecessary for target code to call gen_io_end() after an IO instruction in icount mode; it is sufficient to call gen_io_start() before it and to force the end of the TB. Many now-unnecessary calls to gen_io_end() were removed in commit 9e9b10c6491153b, but some were missed or accidentally added later. Remove unneeded calls from the arm target: * the call in the handling of exception-return-via-LDM is unnecessary, and the code is already forcing end-of-TB * the call in the VFP access check code is more complicated: we weren't ending the TB, so we need to add the code to force that by setting DISAS_UPDATE * the doc comment for ARM_CP_IO doesn't need to mention gen_io_end() any more Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Pavel Dovgalyuk Message-id: 20200619170324.12093-1-peter.maydell@linaro.org --- target/arm/cpu.h | 2 +- target/arm/translate-vfp.inc.c | 7 +++---- target/arm/translate.c | 3 --- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 677584e5da..cf66b8c7fb 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2334,7 +2334,7 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) * migration or KVM state synchronization. (Typically this is for "registers" * which are actually used as instructions for cache maintenance and so on.) * IO indicates that this register does I/O and therefore its accesses - * need to be surrounded by gen_io_start()/gen_io_end(). In particular, + * need to be marked with gen_io_start() and also end the TB. In particular, * registers which implement clocks or timers require this. * RAISES_EXC is for when the read or write hook might raise an exception; * the generated code will synchronize the CPU state before calling the hook diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c index e1a9017598..bf31b18657 100644 --- a/target/arm/translate-vfp.inc.c +++ b/target/arm/translate-vfp.inc.c @@ -119,15 +119,14 @@ static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled) if (s->v7m_lspact) { /* * Lazy state saving affects external memory and also the NVIC, - * so we must mark it as an IO operation for icount. + * so we must mark it as an IO operation for icount (and cause + * this to be the last insn in the TB). */ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + s->base.is_jmp = DISAS_UPDATE; gen_io_start(); } gen_helper_v7m_preserve_fp_state(cpu_env); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } /* * If the preserve_fp_state helper doesn't throw an exception * then it will clear LSPACT; we don't need to repeat this for diff --git a/target/arm/translate.c b/target/arm/translate.c index 408fb7a492..795964da1f 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -7785,9 +7785,6 @@ static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n) gen_io_start(); } gen_helper_cpsr_write_eret(cpu_env, tmp); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } tcg_temp_free_i32(tmp); /* Must exit loop to check un-masked IRQs */ s->base.is_jmp = DISAS_EXIT; From ced7e8edb282765685d2ba0206a11f8692d8ec1c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 19 Jun 2020 18:15:47 +0100 Subject: [PATCH 1534/2595] target/arm: Remove dead code relating to SABA and UABA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit cfdb2c0c95ae9205b0 ("target/arm: Vectorize SABA/UABA") we replaced the old handling of SABA/UABA with a vectorized implementation which returns early rather than falling into the loop-ever-elements code. We forgot to delete the part of the old looping code that did the accumulate step, and Coverity correctly warns (CID 1428955) that this code is now dead. Delete it. Fixes: cfdb2c0c95ae9205b0 Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20200619171547.29780-1-peter.maydell@linaro.org --- target/arm/translate-a64.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 1204098498..4cef862c41 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -11370,18 +11370,6 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) genfn(tcg_res, tcg_op1, tcg_op2); } - if (opcode == 0xf) { - /* SABA, UABA: accumulating ops */ - static NeonGenTwoOpFn * const fns[3] = { - gen_helper_neon_add_u8, - gen_helper_neon_add_u16, - tcg_gen_add_i32, - }; - - read_vec_element_i32(s, tcg_op1, rd, pass, MO_32); - fns[size](tcg_res, tcg_op1, tcg_res); - } - write_vec_element_i32(s, tcg_res, rd, pass, MO_32); tcg_temp_free_i32(tcg_res); From 69ed08e4c5bb0b9d9ae55219ba5429064b0d272e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:26 +0200 Subject: [PATCH 1535/2595] hw/watchdog/cmsdk-apb-watchdog: Add trace event for lock status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a trace event to see when a guest disable/enable the watchdog. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-2-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/watchdog/cmsdk-apb-watchdog.c | 1 + hw/watchdog/trace-events | 1 + 2 files changed, 2 insertions(+) diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c index 1541365914..5bbadadfa6 100644 --- a/hw/watchdog/cmsdk-apb-watchdog.c +++ b/hw/watchdog/cmsdk-apb-watchdog.c @@ -225,6 +225,7 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset, break; case A_WDOGLOCK: s->lock = (value != WDOG_UNLOCK_VALUE); + trace_cmsdk_apb_watchdog_lock(s->lock); break; case A_WDOGITCR: if (s->is_luminary) { diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events index ab94d7df50..3124ca1f1b 100644 --- a/hw/watchdog/trace-events +++ b/hw/watchdog/trace-events @@ -4,3 +4,4 @@ cmsdk_apb_watchdog_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_watchdog_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_watchdog_reset(void) "CMSDK APB watchdog: reset" +cmsdk_apb_watchdog_lock(uint32_t lock) "CMSDK APB watchdog: lock %" PRIu32 From faa1bdfa32547ea616ec554aa807b4e24e30acef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:27 +0200 Subject: [PATCH 1536/2595] hw/i2c/versatile_i2c: Add definitions for register addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use self-explicit definitions instead of magic values. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-3-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/i2c/versatile_i2c.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index 1ac2a6f59a..040139d701 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "hw/i2c/bitbang_i2c.h" +#include "hw/registerfields.h" #include "qemu/log.h" #include "qemu/module.h" @@ -40,14 +41,19 @@ typedef struct VersatileI2CState { int in; } VersatileI2CState; +REG32(CONTROL_GET, 0) +REG32(CONTROL_SET, 0) +REG32(CONTROL_CLR, 4) + static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, unsigned size) { VersatileI2CState *s = (VersatileI2CState *)opaque; - if (offset == 0) { + switch (offset) { + case A_CONTROL_SET: return (s->out & 1) | (s->in << 1); - } else { + default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%x\n", __func__, (int)offset); return -1; @@ -60,10 +66,10 @@ static void versatile_i2c_write(void *opaque, hwaddr offset, VersatileI2CState *s = (VersatileI2CState *)opaque; switch (offset) { - case 0: + case A_CONTROL_SET: s->out |= value & 3; break; - case 4: + case A_CONTROL_CLR: s->out &= ~value; break; default: From cfcfbae0a1028383d7c084fc4cd3ee958ef78d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:28 +0200 Subject: [PATCH 1537/2595] hw/i2c/versatile_i2c: Add SCL/SDA definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use self-explicit definitions instead of magic values. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-4-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/i2c/versatile_i2c.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index 040139d701..0ce10a1bcc 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -45,6 +45,9 @@ REG32(CONTROL_GET, 0) REG32(CONTROL_SET, 0) REG32(CONTROL_CLR, 4) +#define SCL BIT(0) +#define SDA BIT(1) + static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, unsigned size) { @@ -76,8 +79,8 @@ static void versatile_i2c_write(void *opaque, hwaddr offset, qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%x\n", __func__, (int)offset); } - bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0); - s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0); + bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SCL, (s->out & SCL) != 0); + s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & SDA) != 0); } static const MemoryRegionOps versatile_i2c_ops = { From f61c3fb56bfad1d76422fa80d18ae5e39a47d61d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:29 +0200 Subject: [PATCH 1538/2595] hw/i2c: Add header for ARM SBCon two-wire serial bus interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'ARM SBCon two-wire serial bus interface' is the official name describing the pair of registers used to bitbanging I2C in the Versatile boards. Make the private VersatileI2CState structure as public ArmSbconI2CState. Add the TYPE_ARM_SBCON_I2C, alias to our current TYPE_VERSATILE_I2C model. Rename the memory region description as 'arm_sbcon_i2c'. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-5-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- MAINTAINERS | 1 + hw/i2c/versatile_i2c.c | 17 +++++------------ include/hw/i2c/arm_sbcon_i2c.h | 35 ++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 include/hw/i2c/arm_sbcon_i2c.h diff --git a/MAINTAINERS b/MAINTAINERS index f0cb1fd337..f1a74b1dfe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -842,6 +842,7 @@ M: Peter Maydell L: qemu-arm@nongnu.org S: Maintained F: hw/*/versatile* +F: include/hw/i2c/arm_sbcon_i2c.h F: hw/misc/arm_sysctl.c F: docs/system/arm/versatile.rst diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index 0ce10a1bcc..da8cda2ec1 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -1,5 +1,6 @@ /* - * ARM Versatile I2C controller + * ARM SBCon two-wire serial bus interface (I2C bitbang) + * a.k.a. ARM Versatile I2C controller * * Copyright (c) 2006-2007 CodeSourcery. * Copyright (c) 2012 Oskar Andero @@ -22,24 +23,16 @@ */ #include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "hw/i2c/bitbang_i2c.h" +#include "hw/i2c/arm_sbcon_i2c.h" #include "hw/registerfields.h" #include "qemu/log.h" #include "qemu/module.h" -#define TYPE_VERSATILE_I2C "versatile_i2c" #define VERSATILE_I2C(obj) \ OBJECT_CHECK(VersatileI2CState, (obj), TYPE_VERSATILE_I2C) -typedef struct VersatileI2CState { - SysBusDevice parent_obj; +typedef ArmSbconI2CState VersatileI2CState; - MemoryRegion iomem; - bitbang_i2c_interface bitbang; - int out; - int in; -} VersatileI2CState; REG32(CONTROL_GET, 0) REG32(CONTROL_SET, 0) @@ -99,7 +92,7 @@ static void versatile_i2c_init(Object *obj) bus = i2c_init_bus(dev, "i2c"); bitbang_i2c_init(&s->bitbang, bus); memory_region_init_io(&s->iomem, obj, &versatile_i2c_ops, s, - "versatile_i2c", 0x1000); + "arm_sbcon_i2c", 0x1000); sysbus_init_mmio(sbd, &s->iomem); } diff --git a/include/hw/i2c/arm_sbcon_i2c.h b/include/hw/i2c/arm_sbcon_i2c.h new file mode 100644 index 0000000000..5d96507ab6 --- /dev/null +++ b/include/hw/i2c/arm_sbcon_i2c.h @@ -0,0 +1,35 @@ +/* + * ARM SBCon two-wire serial bus interface (I2C bitbang) + * a.k.a. + * ARM Versatile I2C controller + * + * Copyright (c) 2006-2007 CodeSourcery. + * Copyright (c) 2012 Oskar Andero + * Copyright (C) 2020 Philippe Mathieu-Daudé + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef HW_I2C_ARM_SBCON_H +#define HW_I2C_ARM_SBCON_H + +#include "hw/sysbus.h" +#include "hw/i2c/bitbang_i2c.h" + +#define TYPE_VERSATILE_I2C "versatile_i2c" +#define TYPE_ARM_SBCON_I2C TYPE_VERSATILE_I2C + +#define ARM_SBCON_I2C(obj) \ + OBJECT_CHECK(ArmSbconI2CState, (obj), TYPE_ARM_SBCON_I2C) + +typedef struct ArmSbconI2CState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + MemoryRegion iomem; + bitbang_i2c_interface bitbang; + int out; + int in; +} ArmSbconI2CState; + +#endif /* HW_I2C_ARM_SBCON_H */ From 440c9f959d20b83c20c589f614cb14fd0dce4546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:30 +0200 Subject: [PATCH 1539/2595] hw/arm: Use TYPE_VERSATILE_I2C instead of hardcoded string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using the TYPE_* definitions for devices, we can: - quickly find where devices are used with 'git-grep' - easily rename a device (one-line change). Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-6-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/realview.c | 3 ++- hw/arm/versatilepb.c | 3 ++- hw/arm/vexpress.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/arm/realview.c b/hw/arm/realview.c index f3c00fe00c..b6c0a1adb9 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -26,6 +26,7 @@ #include "hw/cpu/a9mpcore.h" #include "hw/intc/realview_gic.h" #include "hw/irq.h" +#include "hw/i2c/arm_sbcon_i2c.h" #define SMP_BOOT_ADDR 0xe0000000 #define SMP_BOOTREG_ADDR 0x10000030 @@ -282,7 +283,7 @@ static void realview_init(MachineState *machine, } } - dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL); + dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); i2c_create_slave(i2c, "ds1338", 0x68); diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 2ebdcbd8ac..e596b8170f 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -18,6 +18,7 @@ #include "sysemu/sysemu.h" #include "hw/pci/pci.h" #include "hw/i2c/i2c.h" +#include "hw/i2c/arm_sbcon_i2c.h" #include "hw/irq.h" #include "hw/boards.h" #include "exec/address-spaces.h" @@ -314,7 +315,7 @@ static void versatile_init(MachineState *machine, int board_id) /* Add PL031 Real Time Clock. */ sysbus_create_simple("pl031", 0x101e8000, pic[10]); - dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL); + dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); i2c_create_slave(i2c, "ds1338", 0x68); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 7ca5d523a4..24d656e653 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -42,6 +42,7 @@ #include "hw/char/pl011.h" #include "hw/cpu/a9mpcore.h" #include "hw/cpu/a15mpcore.h" +#include "hw/i2c/arm_sbcon_i2c.h" #define VEXPRESS_BOARD_ID 0x8e0 #define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) @@ -640,7 +641,7 @@ static void vexpress_common_init(MachineState *machine) sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]); sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]); - dev = sysbus_create_simple("versatile_i2c", map[VE_SERIALDVI], NULL); + dev = sysbus_create_simple(TYPE_VERSATILE_I2C, map[VE_SERIALDVI], NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); i2c_create_slave(i2c, "sii9022", 0x39); From 75ca834136517a48f838537b10318e68abecaed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:31 +0200 Subject: [PATCH 1540/2595] hw/arm/mps2: Document CMSDK/FPGA APB subsystem sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-7-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mps2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index daa55f730b..ee555f919d 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -65,7 +65,9 @@ typedef struct { MemoryRegion blockram_m2; MemoryRegion blockram_m3; MemoryRegion sram; + /* FPGA APB subsystem */ MPS2SCC scc; + /* CMSDK APB subsystem */ CMSDKAPBDualTimer dualtimer; } MPS2MachineState; @@ -299,9 +301,9 @@ static void mps2_common_init(MachineState *machine) g_assert_not_reached(); } + /* CMSDK APB subsystem */ cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ); cmsdk_apb_timer_create(0x40001000, qdev_get_gpio_in(armv7m, 9), SYSCLK_FRQ); - object_initialize_child(OBJECT(mms), "dualtimer", &mms->dualtimer, TYPE_CMSDK_APB_DUALTIMER); qdev_prop_set_uint32(DEVICE(&mms->dualtimer), "pclk-frq", SYSCLK_FRQ); @@ -310,6 +312,7 @@ static void mps2_common_init(MachineState *machine) qdev_get_gpio_in(armv7m, 10)); sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000); + /* FPGA APB subsystem */ object_initialize_child(OBJECT(mms), "scc", &mms->scc, TYPE_MPS2_SCC); sccdev = DEVICE(&mms->scc); qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); From 90b1b6eff423e1f6dc06b663528ab8d4423fa71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:32 +0200 Subject: [PATCH 1541/2595] hw/arm/mps2: Rename CMSDK AHB peripheral region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To differenciate with the CMSDK APB peripheral region, rename this region 'CMSDK AHB peripheral region'. Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-8-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/mps2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index ee555f919d..4fe5cc8622 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -212,10 +212,11 @@ static void mps2_common_init(MachineState *machine) */ create_unimplemented_device("CMSDK APB peripheral region @0x40000000", 0x40000000, 0x00010000); - create_unimplemented_device("CMSDK peripheral region @0x40010000", + create_unimplemented_device("CMSDK AHB peripheral region @0x40010000", 0x40010000, 0x00010000); create_unimplemented_device("Extra peripheral region @0x40020000", 0x40020000, 0x00010000); + create_unimplemented_device("RESERVED 4", 0x40030000, 0x001D0000); create_unimplemented_device("VGA", 0x41000000, 0x0200000); From ecbe51aff923b42b453b85471b000d4daa094fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:33 +0200 Subject: [PATCH 1542/2595] hw/arm/mps2: Add CMSDK APB watchdog device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already model the CMSDK APB watchdog device, let's use it! Suggested-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-9-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 1 + hw/arm/mps2.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 9afa6eee79..5c8f689b3d 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -405,6 +405,7 @@ config MPS2 select PL080 # DMA controller select SPLIT_IRQ select UNIMP + select CMSDK_APB_WATCHDOG config FSL_IMX7 bool diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index 4fe5cc8622..f7bef20b40 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -312,6 +312,13 @@ static void mps2_common_init(MachineState *machine) sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0, qdev_get_gpio_in(armv7m, 10)); sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000); + object_initialize_child(OBJECT(mms), "watchdog", &mms->watchdog, + TYPE_CMSDK_APB_WATCHDOG); + qdev_prop_set_uint32(DEVICE(&mms->watchdog), "wdogclk-frq", SYSCLK_FRQ); + sysbus_realize(SYS_BUS_DEVICE(&mms->watchdog), &error_fatal); + sysbus_connect_irq(SYS_BUS_DEVICE(&mms->watchdog), 0, + qdev_get_gpio_in_named(armv7m, "NMI", 0)); + sysbus_mmio_map(SYS_BUS_DEVICE(&mms->watchdog), 0, 0x40008000); /* FPGA APB subsystem */ object_initialize_child(OBJECT(mms), "scc", &mms->scc, TYPE_MPS2_SCC); From bb8fba9c896dd889e36db8346cd90e17476fca02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:34 +0200 Subject: [PATCH 1543/2595] hw/arm/mps2: Add CMSDK AHB GPIO peripherals as unimplemented devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register the GPIO peripherals as unimplemented to better follow their accesses, for example booting Zephyr: ---------------- IN: arm_mps2_pinmux_init 0x00001160: f64f 0231 movw r2, #0xf831 0x00001164: 4b06 ldr r3, [pc, #0x18] 0x00001166: 2000 movs r0, #0 0x00001168: 619a str r2, [r3, #0x18] 0x0000116a: f24c 426f movw r2, #0xc46f 0x0000116e: f503 5380 add.w r3, r3, #0x1000 0x00001172: 619a str r2, [r3, #0x18] 0x00001174: f44f 529e mov.w r2, #0x13c0 0x00001178: f503 5380 add.w r3, r3, #0x1000 0x0000117c: 619a str r2, [r3, #0x18] 0x0000117e: 4770 bx lr cmsdk-ahb-gpio: unimplemented device write (size 4, value 0xf831, offset 0x18) cmsdk-ahb-gpio: unimplemented device write (size 4, value 0xc46f, offset 0x18) cmsdk-ahb-gpio: unimplemented device write (size 4, value 0x13c0, offset 0x18) Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-10-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/mps2.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index f7bef20b40..c66c595d4a 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -113,6 +113,7 @@ static void mps2_common_init(MachineState *machine) MemoryRegion *system_memory = get_system_memory(); MachineClass *mc = MACHINE_GET_CLASS(machine); DeviceState *armv7m, *sccdev; + int i; if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) { error_report("This board can only be used with CPU %s", @@ -228,7 +229,6 @@ static void mps2_common_init(MachineState *machine) */ Object *orgate; DeviceState *orgate_dev; - int i; orgate = object_new(TYPE_OR_IRQ); object_property_set_int(orgate, 6, "num-lines", &error_fatal); @@ -265,7 +265,6 @@ static void mps2_common_init(MachineState *machine) */ Object *orgate; DeviceState *orgate_dev; - int i; orgate = object_new(TYPE_OR_IRQ); object_property_set_int(orgate, 10, "num-lines", &error_fatal); @@ -301,6 +300,11 @@ static void mps2_common_init(MachineState *machine) default: g_assert_not_reached(); } + for (i = 0; i < 4; i++) { + static const hwaddr gpiobase[] = {0x40010000, 0x40011000, + 0x40012000, 0x40013000}; + create_unimplemented_device("cmsdk-ahb-gpio", gpiobase[i], 0x1000); + } /* CMSDK APB subsystem */ cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ); From adbb23b6a88341fa66a8cfaebedeeadd9a7ac891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:35 +0200 Subject: [PATCH 1544/2595] hw/arm/mps2: Map the FPGA I/O block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-11-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mps2.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index c66c595d4a..e106123225 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -38,8 +38,10 @@ #include "hw/timer/cmsdk-apb-timer.h" #include "hw/timer/cmsdk-apb-dualtimer.h" #include "hw/misc/mps2-scc.h" +#include "hw/misc/mps2-fpgaio.h" #include "hw/net/lan9118.h" #include "net/net.h" +#include "hw/watchdog/cmsdk-apb-watchdog.h" typedef enum MPS2FPGAType { FPGA_AN385, @@ -67,8 +69,10 @@ typedef struct { MemoryRegion sram; /* FPGA APB subsystem */ MPS2SCC scc; + MPS2FPGAIO fpgaio; /* CMSDK APB subsystem */ CMSDKAPBDualTimer dualtimer; + CMSDKAPBWatchdog watchdog; } MPS2MachineState; #define TYPE_MPS2_MACHINE "mps2" @@ -332,6 +336,11 @@ static void mps2_common_init(MachineState *machine) qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); sysbus_realize(SYS_BUS_DEVICE(&mms->scc), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(sccdev), 0, 0x4002f000); + object_initialize_child(OBJECT(mms), "fpgaio", + &mms->fpgaio, TYPE_MPS2_FPGAIO); + qdev_prop_set_uint32(DEVICE(&mms->fpgaio), "prescale-clk", 25000000); + sysbus_realize(SYS_BUS_DEVICE(&mms->fpgaio), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&mms->fpgaio), 0, 0x40028000); /* In hardware this is a LAN9220; the LAN9118 is software compatible * except that it doesn't support the checksum-offload feature. From 58f7f3c4526ce90accc87006531e12971a366f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:36 +0200 Subject: [PATCH 1545/2595] hw/arm/mps2: Add SPI devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 'Application Note AN385', chapter 3.9, SPI: The SMM implements five PL022 SPI modules. Two pairs of modules share the same OR-gated IRQ. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-12-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 6 +++--- hw/arm/mps2.c | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 5c8f689b3d..90ed584e7a 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -59,7 +59,7 @@ config HIGHBANK select ARM_TIMER # sp804 select ARM_V7M select PL011 # UART - select PL022 # Serial port + select PL022 # SPI select PL031 # RTC select PL061 # GPIO select PL310 # cache controller @@ -222,7 +222,7 @@ config STELLARIS select CMSDK_APB_WATCHDOG select I2C select PL011 # UART - select PL022 # Serial port + select PL022 # SPI select PL061 # GPIO select SSD0303 # OLED display select SSD0323 # OLED display @@ -401,7 +401,7 @@ config MPS2 select MPS2_FPGAIO select MPS2_SCC select OR_IRQ - select PL022 # Serial port + select PL022 # SPI select PL080 # DMA controller select SPLIT_IRQ select UNIMP diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index e106123225..daa26f68d7 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -39,6 +39,7 @@ #include "hw/timer/cmsdk-apb-dualtimer.h" #include "hw/misc/mps2-scc.h" #include "hw/misc/mps2-fpgaio.h" +#include "hw/ssi/pl022.h" #include "hw/net/lan9118.h" #include "net/net.h" #include "hw/watchdog/cmsdk-apb-watchdog.h" @@ -341,6 +342,29 @@ static void mps2_common_init(MachineState *machine) qdev_prop_set_uint32(DEVICE(&mms->fpgaio), "prescale-clk", 25000000); sysbus_realize(SYS_BUS_DEVICE(&mms->fpgaio), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&mms->fpgaio), 0, 0x40028000); + sysbus_create_simple(TYPE_PL022, 0x40025000, /* External ADC */ + qdev_get_gpio_in(armv7m, 22)); + for (i = 0; i < 2; i++) { + static const int spi_irqno[] = {11, 24}; + static const hwaddr spibase[] = {0x40020000, /* APB */ + 0x40021000, /* LCD */ + 0x40026000, /* Shield0 */ + 0x40027000}; /* Shield1 */ + DeviceState *orgate_dev; + Object *orgate; + int j; + + orgate = object_new(TYPE_OR_IRQ); + object_property_set_int(orgate, 2, "num-lines", &error_fatal); + orgate_dev = DEVICE(orgate); + qdev_realize(orgate_dev, NULL, &error_fatal); + qdev_connect_gpio_out(orgate_dev, 0, + qdev_get_gpio_in(armv7m, spi_irqno[i])); + for (j = 0; j < 2; j++) { + sysbus_create_simple(TYPE_PL022, spibase[2 * i + j], + qdev_get_gpio_in(orgate_dev, j)); + } + } /* In hardware this is a LAN9220; the LAN9118 is software compatible * except that it doesn't support the checksum-offload feature. From ada45de9ea67b814a879a6151361c50122326e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:37 +0200 Subject: [PATCH 1546/2595] hw/arm/mps2: Add I2C devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 'Application Note AN385', chapter 3.14: The SMM implements a simple SBCon interface based on I2C. There are 4 SBCon interfaces on the FPGA APB subsystem. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-13-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 1 + hw/arm/mps2.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 90ed584e7a..4a224a6351 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -406,6 +406,7 @@ config MPS2 select SPLIT_IRQ select UNIMP select CMSDK_APB_WATCHDOG + select VERSATILE_I2C config FSL_IMX7 bool diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index daa26f68d7..2f6acbf2c2 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -40,6 +40,7 @@ #include "hw/misc/mps2-scc.h" #include "hw/misc/mps2-fpgaio.h" #include "hw/ssi/pl022.h" +#include "hw/i2c/arm_sbcon_i2c.h" #include "hw/net/lan9118.h" #include "net/net.h" #include "hw/watchdog/cmsdk-apb-watchdog.h" @@ -365,6 +366,13 @@ static void mps2_common_init(MachineState *machine) qdev_get_gpio_in(orgate_dev, j)); } } + for (i = 0; i < 4; i++) { + static const hwaddr i2cbase[] = {0x40022000, /* Touch */ + 0x40023000, /* Audio */ + 0x40029000, /* Shield0 */ + 0x4002a000}; /* Shield1 */ + sysbus_create_simple(TYPE_ARM_SBCON_I2C, i2cbase[i], NULL); + } /* In hardware this is a LAN9220; the LAN9118 is software compatible * except that it doesn't support the checksum-offload feature. From 7b465641ed6fd037f577666c0edd5d389ae39696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:38 +0200 Subject: [PATCH 1547/2595] hw/arm/mps2: Add audio I2S interface as unimplemented device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-14-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mps2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index 2f6acbf2c2..d1653a7e6e 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -373,6 +373,7 @@ static void mps2_common_init(MachineState *machine) 0x4002a000}; /* Shield1 */ sysbus_create_simple(TYPE_ARM_SBCON_I2C, i2cbase[i], NULL); } + create_unimplemented_device("i2s", 0x40024000, 0x400); /* In hardware this is a LAN9220; the LAN9118 is software compatible * except that it doesn't support the checksum-offload feature. From 2e34818f08d28812e8efa319a4db36668348ac9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:39 +0200 Subject: [PATCH 1548/2595] hw/arm/mps2-tz: Use the ARM SBCon two-wire serial bus interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 'Application Note AN521', chapter 4.7: The SMM implements four SBCon serial modules: One SBCon module for use by the Color LCD touch interface. One SBCon module to configure the audio controller. Two general purpose SBCon modules, that connect to the Expansion headers J7 and J8, are intended for use with the V2C-Shield1 which provide an I2C interface on the headers. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-15-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mps2-tz.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 8155c35418..a4fd5ddede 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -58,6 +58,7 @@ #include "hw/arm/armsse.h" #include "hw/dma/pl080.h" #include "hw/ssi/pl022.h" +#include "hw/i2c/arm_sbcon_i2c.h" #include "hw/net/lan9118.h" #include "net/net.h" #include "hw/core/split-irq.h" @@ -87,7 +88,7 @@ typedef struct { TZPPC ppc[5]; TZMPC ssram_mpc[3]; PL022State spi[5]; - UnimplementedDeviceState i2c[4]; + ArmSbconI2CState i2c[4]; UnimplementedDeviceState i2s_audio; UnimplementedDeviceState gpio[4]; UnimplementedDeviceState gfx; @@ -365,6 +366,18 @@ static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque, return sysbus_mmio_get_region(s, 0); } +static MemoryRegion *make_i2c(MPS2TZMachineState *mms, void *opaque, + const char *name, hwaddr size) +{ + ArmSbconI2CState *i2c = opaque; + SysBusDevice *s; + + object_initialize_child(OBJECT(mms), name, i2c, TYPE_ARM_SBCON_I2C); + s = SYS_BUS_DEVICE(i2c); + sysbus_realize(s, &error_fatal); + return sysbus_mmio_get_region(s, 0); +} + static void mps2tz_common_init(MachineState *machine) { MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); @@ -499,10 +512,10 @@ static void mps2tz_common_init(MachineState *machine) { "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000 }, { "uart3", make_uart, &mms->uart[3], 0x40203000, 0x1000 }, { "uart4", make_uart, &mms->uart[4], 0x40204000, 0x1000 }, - { "i2c0", make_unimp_dev, &mms->i2c[0], 0x40207000, 0x1000 }, - { "i2c1", make_unimp_dev, &mms->i2c[1], 0x40208000, 0x1000 }, - { "i2c2", make_unimp_dev, &mms->i2c[2], 0x4020c000, 0x1000 }, - { "i2c3", make_unimp_dev, &mms->i2c[3], 0x4020d000, 0x1000 }, + { "i2c0", make_i2c, &mms->i2c[0], 0x40207000, 0x1000 }, + { "i2c1", make_i2c, &mms->i2c[1], 0x40208000, 0x1000 }, + { "i2c2", make_i2c, &mms->i2c[2], 0x4020c000, 0x1000 }, + { "i2c3", make_i2c, &mms->i2c[3], 0x4020d000, 0x1000 }, }, }, { .name = "apb_ppcexp2", From 7d20e6815bf5ab678a55673224340b39218be510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 11:06:22 +0200 Subject: [PATCH 1549/2595] target/arm: Check supported KVM features globally (not per vCPU) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit d70c996df23f, when enabling the PMU we get: $ qemu-system-aarch64 -cpu host,pmu=on -M virt,accel=kvm,gic-version=3 Segmentation fault (core dumped) Thread 1 "qemu-system-aar" received signal SIGSEGV, Segmentation fault. 0x0000aaaaaae356d0 in kvm_ioctl (s=0x0, type=44547) at accel/kvm/kvm-all.c:2588 2588 ret = ioctl(s->fd, type, arg); (gdb) bt #0 0x0000aaaaaae356d0 in kvm_ioctl (s=0x0, type=44547) at accel/kvm/kvm-all.c:2588 #1 0x0000aaaaaae31568 in kvm_check_extension (s=0x0, extension=126) at accel/kvm/kvm-all.c:916 #2 0x0000aaaaaafce254 in kvm_arm_pmu_supported (cpu=0xaaaaac214ab0) at target/arm/kvm.c:213 #3 0x0000aaaaaafc0f94 in arm_set_pmu (obj=0xaaaaac214ab0, value=true, errp=0xffffffffe438) at target/arm/cpu.c:1111 #4 0x0000aaaaab5533ac in property_set_bool (obj=0xaaaaac214ab0, v=0xaaaaac223a80, name=0xaaaaac11a970 "pmu", opaque=0xaaaaac222730, errp=0xffffffffe438) at qom/object.c:2170 #5 0x0000aaaaab5512f0 in object_property_set (obj=0xaaaaac214ab0, v=0xaaaaac223a80, name=0xaaaaac11a970 "pmu", errp=0xffffffffe438) at qom/object.c:1328 #6 0x0000aaaaab551e10 in object_property_parse (obj=0xaaaaac214ab0, string=0xaaaaac11b4c0 "on", name=0xaaaaac11a970 "pmu", errp=0xffffffffe438) at qom/object.c:1561 #7 0x0000aaaaab54ee8c in object_apply_global_props (obj=0xaaaaac214ab0, props=0xaaaaac018e20, errp=0xaaaaabd6fd88 ) at qom/object.c:407 #8 0x0000aaaaab1dd5a4 in qdev_prop_set_globals (dev=0xaaaaac214ab0) at hw/core/qdev-properties.c:1218 #9 0x0000aaaaab1d9fac in device_post_init (obj=0xaaaaac214ab0) at hw/core/qdev.c:1050 ... #15 0x0000aaaaab54f310 in object_initialize_with_type (obj=0xaaaaac214ab0, size=52208, type=0xaaaaabe237f0) at qom/object.c:512 #16 0x0000aaaaab54fa24 in object_new_with_type (type=0xaaaaabe237f0) at qom/object.c:687 #17 0x0000aaaaab54fa80 in object_new (typename=0xaaaaabe23970 "host-arm-cpu") at qom/object.c:702 #18 0x0000aaaaaaf04a74 in machvirt_init (machine=0xaaaaac0a8550) at hw/arm/virt.c:1770 #19 0x0000aaaaab1e8720 in machine_run_board_init (machine=0xaaaaac0a8550) at hw/core/machine.c:1138 #20 0x0000aaaaaaf95394 in qemu_init (argc=5, argv=0xffffffffea58, envp=0xffffffffea88) at softmmu/vl.c:4348 #21 0x0000aaaaaada3f74 in main (argc=, argv=, envp=) at softmmu/main.c:48 This is because in frame #2, cpu->kvm_state is still NULL (the vCPU is not yet realized). KVM has a hard requirement of all cores supporting the same feature set. We only need to check if the accelerator supports a feature, not each vCPU individually. Fix by removing the 'CPUState *cpu' argument from the kvm_arm__supported() functions. Fixes: d70c996df23f ('Use CPUState::kvm_state in kvm_arm_pmu_supported') Reported-by: Haibo Xu Reviewed-by: Andrew Jones Acked-by: Paolo Bonzini Signed-off-by: Philippe Mathieu-Daudé Suggested-by: Paolo Bonzini Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/cpu.c | 2 +- target/arm/cpu64.c | 10 +++++----- target/arm/kvm.c | 4 ++-- target/arm/kvm64.c | 14 +++++--------- target/arm/kvm_arm.h | 21 +++++++++------------ 5 files changed, 22 insertions(+), 29 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 5b7a36b5d7..e44e18062c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1108,7 +1108,7 @@ static void arm_set_pmu(Object *obj, bool value, Error **errp) ARMCPU *cpu = ARM_CPU(obj); if (value) { - if (kvm_enabled() && !kvm_arm_pmu_supported(CPU(cpu))) { + if (kvm_enabled() && !kvm_arm_pmu_supported()) { error_setg(errp, "'pmu' feature not supported by KVM on this host"); return; } diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 778cecc2e6..a0c1d8894b 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -266,7 +266,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) /* Collect the set of vector lengths supported by KVM. */ bitmap_zero(kvm_supported, ARM_MAX_VQ); - if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) { + if (kvm_enabled() && kvm_arm_sve_supported()) { kvm_arm_sve_get_vls(CPU(cpu), kvm_supported); } else if (kvm_enabled()) { assert(!cpu_isar_feature(aa64_sve, cpu)); @@ -473,7 +473,7 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, return; } - if (kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) { + if (kvm_enabled() && !kvm_arm_sve_supported()) { error_setg(errp, "cannot set sve-max-vq"); error_append_hint(errp, "SVE not supported by KVM on this host\n"); return; @@ -519,7 +519,7 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name, return; } - if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) { + if (value && kvm_enabled() && !kvm_arm_sve_supported()) { error_setg(errp, "cannot enable %s", name); error_append_hint(errp, "SVE not supported by KVM on this host\n"); return; @@ -556,7 +556,7 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name, return; } - if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) { + if (value && kvm_enabled() && !kvm_arm_sve_supported()) { error_setg(errp, "'sve' feature not supported by KVM on this host"); return; } @@ -751,7 +751,7 @@ static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp) * uniform execution state like do_interrupt. */ if (value == false) { - if (!kvm_enabled() || !kvm_arm_aarch32_supported(CPU(cpu))) { + if (!kvm_enabled() || !kvm_arm_aarch32_supported()) { error_setg(errp, "'aarch64' feature cannot be disabled " "unless KVM is enabled and 32-bit EL1 " "is supported"); diff --git a/target/arm/kvm.c b/target/arm/kvm.c index eef3bbd1cc..7c672c78b8 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -208,9 +208,9 @@ void kvm_arm_add_vcpu_properties(Object *obj) } } -bool kvm_arm_pmu_supported(CPUState *cpu) +bool kvm_arm_pmu_supported(void) { - return kvm_check_extension(cpu->kvm_state, KVM_CAP_ARM_PMU_V3); + return kvm_check_extension(kvm_state, KVM_CAP_ARM_PMU_V3); } int kvm_arm_get_max_vm_ipa_size(MachineState *ms) diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index f09ed9f4df..3dc494aaa7 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -652,18 +652,14 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) return true; } -bool kvm_arm_aarch32_supported(CPUState *cpu) +bool kvm_arm_aarch32_supported(void) { - KVMState *s = KVM_STATE(current_accel()); - - return kvm_check_extension(s, KVM_CAP_ARM_EL1_32BIT); + return kvm_check_extension(kvm_state, KVM_CAP_ARM_EL1_32BIT); } -bool kvm_arm_sve_supported(CPUState *cpu) +bool kvm_arm_sve_supported(void) { - KVMState *s = KVM_STATE(current_accel()); - - return kvm_check_extension(s, KVM_CAP_ARM_SVE); + return kvm_check_extension(kvm_state, KVM_CAP_ARM_SVE); } QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1); @@ -798,7 +794,7 @@ int kvm_arch_init_vcpu(CPUState *cs) env->features &= ~(1ULL << ARM_FEATURE_PMU); } if (cpu_isar_feature(aa64_sve, cpu)) { - assert(kvm_arm_sve_supported(cs)); + assert(kvm_arm_sve_supported()); cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_SVE; } diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index 48bf5e16d5..a4ce4fd93d 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -269,29 +269,26 @@ void kvm_arm_add_vcpu_properties(Object *obj); /** * kvm_arm_aarch32_supported: - * @cs: CPUState * - * Returns: true if the KVM VCPU can enable AArch32 mode + * Returns: true if KVM can enable AArch32 mode * and false otherwise. */ -bool kvm_arm_aarch32_supported(CPUState *cs); +bool kvm_arm_aarch32_supported(void); /** * kvm_arm_pmu_supported: - * @cs: CPUState * - * Returns: true if the KVM VCPU can enable its PMU + * Returns: true if KVM can enable the PMU * and false otherwise. */ -bool kvm_arm_pmu_supported(CPUState *cs); +bool kvm_arm_pmu_supported(void); /** * kvm_arm_sve_supported: - * @cs: CPUState * - * Returns true if the KVM VCPU can enable SVE and false otherwise. + * Returns true if KVM can enable SVE and false otherwise. */ -bool kvm_arm_sve_supported(CPUState *cs); +bool kvm_arm_sve_supported(void); /** * kvm_arm_get_max_vm_ipa_size: @@ -359,17 +356,17 @@ static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) static inline void kvm_arm_add_vcpu_properties(Object *obj) {} -static inline bool kvm_arm_aarch32_supported(CPUState *cs) +static inline bool kvm_arm_aarch32_supported(void) { return false; } -static inline bool kvm_arm_pmu_supported(CPUState *cs) +static inline bool kvm_arm_pmu_supported(void) { return false; } -static inline bool kvm_arm_sve_supported(CPUState *cs) +static inline bool kvm_arm_sve_supported(void) { return false; } From 92a70997ad6dcff865b0071475a878a4fa478da5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 23 Jun 2020 11:06:21 +0200 Subject: [PATCH 1550/2595] tests/qtest/arm-cpu-features: Add feature setting tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some cpu features may be enabled and disabled for all configurations that support the feature. Let's test that. A recent regression[*] inspired adding these tests. [*] '-cpu host,pmu=on' caused a segfault Signed-off-by: Andrew Jones Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200623090622.30365-2-philmd@redhat.com Message-Id: <20200623082310.17577-1-drjones@redhat.com> Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- tests/qtest/arm-cpu-features.c | 38 ++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c index 4692173676..f7e062c189 100644 --- a/tests/qtest/arm-cpu-features.c +++ b/tests/qtest/arm-cpu-features.c @@ -159,16 +159,35 @@ static bool resp_get_feature(QDict *resp, const char *feature) qobject_unref(_resp); \ }) -#define assert_feature(qts, cpu_type, feature, expected_value) \ +#define resp_assert_feature(resp, feature, expected_value) \ ({ \ - QDict *_resp, *_props; \ + QDict *_props; \ \ - _resp = do_query_no_props(qts, cpu_type); \ g_assert(_resp); \ g_assert(resp_has_props(_resp)); \ _props = resp_get_props(_resp); \ g_assert(qdict_get(_props, feature)); \ g_assert(qdict_get_bool(_props, feature) == (expected_value)); \ +}) + +#define assert_feature(qts, cpu_type, feature, expected_value) \ +({ \ + QDict *_resp; \ + \ + _resp = do_query_no_props(qts, cpu_type); \ + g_assert(_resp); \ + resp_assert_feature(_resp, feature, expected_value); \ + qobject_unref(_resp); \ +}) + +#define assert_set_feature(qts, cpu_type, feature, value) \ +({ \ + const char *_fmt = (value) ? "{ %s: true }" : "{ %s: false }"; \ + QDict *_resp; \ + \ + _resp = do_query(qts, cpu_type, _fmt, feature); \ + g_assert(_resp); \ + resp_assert_feature(_resp, feature, value); \ qobject_unref(_resp); \ }) @@ -424,10 +443,14 @@ static void test_query_cpu_model_expansion(const void *data) assert_error(qts, "host", "The CPU type 'host' requires KVM", NULL); /* Test expected feature presence/absence for some cpu types */ - assert_has_feature_enabled(qts, "max", "pmu"); assert_has_feature_enabled(qts, "cortex-a15", "pmu"); assert_has_not_feature(qts, "cortex-a15", "aarch64"); + /* Enabling and disabling pmu should always work. */ + assert_has_feature_enabled(qts, "max", "pmu"); + assert_set_feature(qts, "max", "pmu", false); + assert_set_feature(qts, "max", "pmu", true); + assert_has_not_feature(qts, "max", "kvm-no-adjvtime"); if (g_str_equal(qtest_get_arch(), "aarch64")) { @@ -464,7 +487,10 @@ static void test_query_cpu_model_expansion_kvm(const void *data) return; } + /* Enabling and disabling kvm-no-adjvtime should always work. */ assert_has_feature_disabled(qts, "host", "kvm-no-adjvtime"); + assert_set_feature(qts, "host", "kvm-no-adjvtime", true); + assert_set_feature(qts, "host", "kvm-no-adjvtime", false); if (g_str_equal(qtest_get_arch(), "aarch64")) { bool kvm_supports_sve; @@ -475,7 +501,11 @@ static void test_query_cpu_model_expansion_kvm(const void *data) char *error; assert_has_feature_enabled(qts, "host", "aarch64"); + + /* Enabling and disabling pmu should always work. */ assert_has_feature_enabled(qts, "host", "pmu"); + assert_set_feature(qts, "host", "pmu", false); + assert_set_feature(qts, "host", "pmu", true); assert_error(qts, "cortex-a15", "We cannot guarantee the CPU type 'cortex-a15' works " From 539533b85fbd269f777bed931de8ccae1dd837e9 Mon Sep 17 00:00:00 2001 From: Shameer Kolothum Date: Mon, 22 Jun 2020 13:41:57 +0100 Subject: [PATCH 1551/2595] arm/virt: Add memory hot remove support This adds support for memory(pc-dimm) hot remove on arm/virt that uses acpi ged device. NVDIMM hot removal is not yet supported. Signed-off-by: Shameer Kolothum Message-id: 20200622124157.20360-1-shameerali.kolothum.thodi@huawei.com Reviewed-by: Eric Auger Tested-by: Eric Auger Signed-off-by: Peter Maydell --- hw/acpi/generic_event_device.c | 29 ++++++++++++++++ hw/arm/virt.c | 62 ++++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index 1cb34111e5..b8abdefa1c 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -193,6 +193,33 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, } } +static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + AcpiGedState *s = ACPI_GED(hotplug_dev); + + if ((object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) && + !(object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)))) { + acpi_memory_unplug_request_cb(hotplug_dev, &s->memhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + AcpiGedState *s = ACPI_GED(hotplug_dev); + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + acpi_memory_unplug_cb(&s->memhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) { AcpiGedState *s = ACPI_GED(adev); @@ -318,6 +345,8 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) dc->vmsd = &vmstate_acpi_ged; hc->plug = acpi_ged_device_plug_cb; + hc->unplug_request = acpi_ged_unplug_request_cb; + hc->unplug = acpi_ged_unplug_cb; adevc->send_event = acpi_ged_send_event; } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 8b6e6aa7b1..402c362c14 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2177,11 +2177,68 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, } } +static void virt_dimm_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + Error *local_err = NULL; + + if (!vms->acpi_dev) { + error_setg(&local_err, + "memory hotplug is not enabled: missing acpi-ged device"); + goto out; + } + + if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { + error_setg(&local_err, + "nvdimm device hot unplug is not supported yet."); + goto out; + } + + hotplug_handler_unplug_request(HOTPLUG_HANDLER(vms->acpi_dev), dev, + &local_err); +out: + error_propagate(errp, local_err); +} + +static void virt_dimm_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + Error *local_err = NULL; + + hotplug_handler_unplug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &local_err); + if (local_err) { + goto out; + } + + pc_dimm_unplug(PC_DIMM(dev), MACHINE(vms)); + qdev_unrealize(dev); + +out: + error_propagate(errp, local_err); +} + static void virt_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - error_setg(errp, "device unplug request for unsupported device" - " type: %s", object_get_typename(OBJECT(dev))); + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + virt_dimm_unplug_request(hotplug_dev, dev, errp); + } else { + error_setg(errp, "device unplug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void virt_machine_device_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + virt_dimm_unplug(hotplug_dev, dev, errp); + } else { + error_setg(errp, "virt: device unplug for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } } static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, @@ -2262,6 +2319,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) hc->pre_plug = virt_machine_device_pre_plug_cb; hc->plug = virt_machine_device_plug_cb; hc->unplug_request = virt_machine_device_unplug_request_cb; + hc->unplug = virt_machine_device_unplug_cb; mc->numa_mem_supported = true; mc->nvdimm_supported = true; mc->auto_enable_numa_with_memhp = true; From 6a1a643301417381b1eefc324f6fe9e8cff48840 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:12 +0200 Subject: [PATCH 1552/2595] iotests/172: Include "info block" in test output The additional output demonstrates we screw up when -global isa-fdc clashes with -drive if=floppy or its sugared forms: according to "info qtree", only the latter backend is attached, but according to "info block", both are. For instance: Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 dev: isa-fdc, id "" [...] driveA = "" driveB = "" [...] bus: floppy-bus.0 type floppy-bus dev: floppy, id "" unit = 0 (0x0) ---> drive = "floppy0" [...] floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) ---> Attached to: /machine/unattached/device[15] Removable device: not locked, tray closed Cache mode: writeback none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) ---> Attached to: /machine/unattached/device[14] Cache mode: writeback /machine/unattached/device[15] is floppy, and /machine/unattached/device[14] is isa-fdc. Signed-off-by: Markus Armbruster Message-Id: <20200622094227.1271650-2-armbru@redhat.com> --- tests/qemu-iotests/172 | 5 +- tests/qemu-iotests/172.out | 486 +++++++++++++++++++++++++++++++++++++ 2 files changed, 489 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172 index 7195fb895a..19c2516cf8 100755 --- a/tests/qemu-iotests/172 +++ b/tests/qemu-iotests/172 @@ -69,9 +69,10 @@ check_floppy_qtree() # # Apply the sed filter to stdout only, but keep the stderr output and # filter the qemu program name in it. - echo "info qtree" | + printf "info qtree\ninfo block\n" | (QEMU_OPTIONS="" do_run_qemu "$@" | - sed -ne '/^ dev: isa-fdc/,/^ dev:/{x;p}' ) 2>&1 | + _filter_testdir |_filter_generated_node_ids | _filter_hmp | + sed -ne '/^ dev: isa-fdc/,/^ dev:/{x;p};/^[a-z][^ ]* (NODE_NAME):* /,/^(qemu)$/{p}') 2>&1 | _filter_win32 | _filter_qemu } diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index e782c5957e..a315866e17 100644 --- a/tests/qemu-iotests/172.out +++ b/tests/qemu-iotests/172.out @@ -62,6 +62,19 @@ Testing: -fda TEST_DIR/t.qcow2 write-cache = "auto" share-rw = false drive-type = "144" +floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -fdb TEST_DIR/t.qcow2 @@ -100,6 +113,23 @@ Testing: -fdb TEST_DIR/t.qcow2 write-cache = "auto" share-rw = false drive-type = "288" +floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[16] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[23] + Removable device: not locked, tray closed + +floppy0: [not inserted] + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2.2 @@ -138,6 +168,24 @@ Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2.2 write-cache = "auto" share-rw = false drive-type = "144" +floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +floppy1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/unattached/device[16] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[23] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + === Using -drive options === @@ -168,6 +216,19 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 write-cache = "auto" share-rw = false drive-type = "144" +floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1 @@ -206,6 +267,23 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1 write-cache = "auto" share-rw = false drive-type = "288" +floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[16] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[23] + Removable device: not locked, tray closed + +floppy0: [not inserted] + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t.qcow2.2,index=1 @@ -244,6 +322,24 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t write-cache = "auto" share-rw = false drive-type = "144" +floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +floppy1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/unattached/device[16] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[23] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + === Using -drive if=none and -global === @@ -274,6 +370,19 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveA=none0 write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveB=none0 @@ -301,6 +410,19 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveB=none0 write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 -global isa-fdc.driveB=none1 @@ -339,6 +461,24 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/unattached/device[16] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[23] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + === Using -drive if=none and -device === @@ -369,6 +509,19 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0 write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[21] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=1 @@ -396,6 +549,19 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=1 write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[21] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device floppy,drive=none0 -device floppy,drive=none1,unit=1 @@ -434,6 +600,24 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[1] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[21] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + === Mixing -fdX and -global === @@ -475,6 +659,24 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global is write-cache = "auto" share-rw = false drive-type = "144" +floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/unattached/device[16] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[23] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 @@ -513,6 +715,24 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global is write-cache = "auto" share-rw = false drive-type = "144" +floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[16] + Removable device: not locked, tray closed + Cache mode: writeback + +none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[23] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 @@ -540,6 +760,23 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global is write-cache = "auto" share-rw = false drive-type = "144" +floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/unattached/device[14] + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveB=none0 @@ -567,6 +804,23 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global is write-cache = "auto" share-rw = false drive-type = "144" +floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/unattached/device[14] + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + === Mixing -fdX and -device === @@ -608,6 +862,24 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl write-cache = "auto" share-rw = false drive-type = "144" +floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device floppy,drive=none0,unit=1 @@ -646,6 +918,24 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl write-cache = "auto" share-rw = false drive-type = "144" +floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device floppy,drive=none0 @@ -684,6 +974,24 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl write-cache = "auto" share-rw = false drive-type = "144" +floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device floppy,drive=none0,unit=0 @@ -722,6 +1030,24 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl write-cache = "auto" share-rw = false drive-type = "144" +floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device floppy,drive=none0,unit=0 QEMU_PROG: -device floppy,drive=none0,unit=0: Floppy unit 0 is in use @@ -769,6 +1095,24 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q write-cache = "auto" share-rw = false drive-type = "144" +floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device floppy,drive=none0,unit=1 @@ -807,6 +1151,24 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q write-cache = "auto" share-rw = false drive-type = "144" +floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device floppy,drive=none0,unit=0 QEMU_PROG: -device floppy,drive=none0,unit=0: Floppy unit 0 is in use @@ -851,6 +1213,24 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 -device floppy,drive=none1,unit=1 @@ -889,6 +1269,24 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveB=none0 -device floppy,drive=none1 @@ -927,6 +1325,24 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveB=none0 -device floppy,drive=none1,unit=0 @@ -965,6 +1381,24 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 -device floppy,drive=none1,unit=0 QEMU_PROG: -device floppy,drive=none1,unit=0: Floppy unit 0 is in use @@ -1118,6 +1552,19 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t write-cache = "auto" share-rw = false drive-type = "120" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[21] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-type=288 @@ -1145,6 +1592,19 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t write-cache = "auto" share-rw = false drive-type = "288" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[21] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + === Try passing different block sizes === @@ -1175,6 +1635,19 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,logical write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[21] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physical_block_size=512 @@ -1202,6 +1675,19 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physica write-cache = "auto" share-rw = false drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[21] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,logical_block_size=4096 QEMU_PROG: -device floppy,drive=none0,logical_block_size=4096: logical_block_size > physical_block_size not supported From 20171739685c77d84a5694890b4e365dc2159216 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:13 +0200 Subject: [PATCH 1553/2595] iotests/172: Cover empty filename and multiple use of drives Signed-off-by: Markus Armbruster Message-Id: <20200622094227.1271650-3-armbru@redhat.com> --- tests/qemu-iotests/172 | 12 +++++++++ tests/qemu-iotests/172.out | 50 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172 index 19c2516cf8..714c7527b4 100755 --- a/tests/qemu-iotests/172 +++ b/tests/qemu-iotests/172 @@ -111,6 +111,7 @@ echo === Using -fda/-fdb options === check_floppy_qtree -fda "$TEST_IMG" check_floppy_qtree -fdb "$TEST_IMG" check_floppy_qtree -fda "$TEST_IMG" -fdb "$TEST_IMG.2" +check_floppy_qtree -fdb "" echo @@ -198,6 +199,17 @@ check_floppy_qtree -drive if=none,file="$TEST_IMG" -drive if=none,file="$TEST_IM check_floppy_qtree -drive if=none,file="$TEST_IMG" -drive if=none,file="$TEST_IMG.2" \ -global isa-fdc.driveB=none0 -device floppy,drive=none1,unit=1 +echo +echo +echo === Attempt to use drive twice === + +# if=none +check_floppy_qtree -drive if=none -device floppy,drive=none0 -device floppy -device floppy,drive=none0 +# if=floppy +check_floppy_qtree -fda "" -device floppy,drive=floppy0 +# default if=floppy (not found, because it's created later) +check_floppy_qtree -device floppy,drive=floppy0 + echo echo echo === Too many floppy drives === diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index a315866e17..0665cdcb51 100644 --- a/tests/qemu-iotests/172.out +++ b/tests/qemu-iotests/172.out @@ -187,6 +187,44 @@ sd0: [not inserted] (qemu) quit +Testing: -fdb + + dev: isa-fdc, id "" + iobase = 1008 (0x3f0) + irq = 6 (0x6) + dma = 2 (0x2) + driveA = "" + driveB = "" + check_media_rate = true + fdtypeA = "auto" + fdtypeB = "auto" + fallback = "288" + isa irq 6 + bus: floppy-bus.0 + type floppy-bus + dev: floppy, id "" + unit = 1 (0x1) + drive = "floppy1" + logical_block_size = 512 (0x200) + physical_block_size = 512 (0x200) + min_io_size = 0 (0x0) + opt_io_size = 0 (0x0) + discard_granularity = 4294967295 (0xffffffff) + write-cache = "auto" + share-rw = false + drive-type = "288" + dev: floppy, id "" + unit = 0 (0x0) + drive = "floppy0" + logical_block_size = 512 (0x200) + physical_block_size = 512 (0x200) + min_io_size = 0 (0x0) + opt_io_size = 0 (0x0) + discard_granularity = 4294967295 (0xffffffff) + write-cache = "auto" + share-rw = false + drive-type = "288" + === Using -drive options === @@ -1407,6 +1445,18 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco QEMU_PROG: -device floppy,drive=none1,unit=1: Floppy unit 1 is in use +=== Attempt to use drive twice === + +Testing: -drive if=none -device floppy,drive=none0 -device floppy -device floppy,drive=none0 +QEMU_PROG: -device floppy,drive=none0: Drive 'none0' is already in use by another device + +Testing: -fda -device floppy,drive=floppy0 +QEMU_PROG: -device floppy,drive=floppy0: Drive 'floppy0' is already in use because it has been automatically connected to another device (did you need 'if=none' in the drive options?) + +Testing: -device floppy,drive=floppy0 +QEMU_PROG: -device floppy,drive=floppy0: Property 'floppy.drive' can't find value 'floppy0' + + === Too many floppy drives === Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -drive if=none,file=TEST_DIR/t.qcow2.3 -global isa-fdc.driveB=none0 -device floppy,drive=none1 From 02b83f7d7c0828bb03fe0324c0ec8388d7e711d4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:14 +0200 Subject: [PATCH 1554/2595] iotests/172: Cover -global floppy.drive=... Use of -global to set a default backend for non-singleton devices is a bad idea. But as long as we permit it, we better test it. Test output demonstrates we screw up when -global floppy clashes with -fda or with -device floppy: according to "info qtree", only the latter backend is attached, but according to "info block", both are. Here's the clash with -device: Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global floppy.drive=none0 -device floppy,drive=none1,unit=0 dev: isa-fdc, id "" [...] driveA = "" driveB = "" [...] bus: floppy-bus.0 type floppy-bus dev: floppy, id "" unit = 0 (0x0) ---> drive = "none1" [...] none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) ---> Attached to: /machine/peripheral-anon/device[0] Cache mode: writeback none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) ---> Attached to: /machine/peripheral-anon/device[0] Removable device: not locked, tray closed Cache mode: writeback /machine/peripheral-anon/device[0] is the floppy created with -device. Test output further demonstrates the "Drive 'FOO' is already in use because it has been automatically connected to another device" error message can be misleading. With '-fda "" -global floppy.drive=floppy0', it's in use because -global reuses -fda's backend. There is no other device involved. Signed-off-by: Markus Armbruster Message-Id: <20200622094227.1271650-4-armbru@redhat.com> --- tests/qemu-iotests/172 | 7 ++ tests/qemu-iotests/172.out | 134 +++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172 index 714c7527b4..18056bcef7 100755 --- a/tests/qemu-iotests/172 +++ b/tests/qemu-iotests/172 @@ -151,6 +151,7 @@ check_floppy_qtree -fdb "$TEST_IMG" -drive if=none,file="$TEST_IMG.2" -global is # Conflicting (-fdX wins) check_floppy_qtree -fda "$TEST_IMG" -drive if=none,file="$TEST_IMG.2" -global isa-fdc.driveA=none0 check_floppy_qtree -fdb "$TEST_IMG" -drive if=none,file="$TEST_IMG.2" -global isa-fdc.driveB=none0 +check_floppy_qtree -fda "$TEST_IMG" -drive if=none,file="$TEST_IMG.2" -global floppy.drive=none0 echo echo @@ -192,12 +193,16 @@ check_floppy_qtree -drive if=none,file="$TEST_IMG" -drive if=none,file="$TEST_IM -global isa-fdc.driveB=none0 -device floppy,drive=none1 check_floppy_qtree -drive if=none,file="$TEST_IMG" -drive if=none,file="$TEST_IMG.2" \ -global isa-fdc.driveB=none0 -device floppy,drive=none1,unit=0 +check_floppy_qtree -drive if=none,file="$TEST_IMG" \ + -global floppy.drive=none0 -device floppy,unit=0 # Conflicting check_floppy_qtree -drive if=none,file="$TEST_IMG" -drive if=none,file="$TEST_IMG.2" \ -global isa-fdc.driveA=none0 -device floppy,drive=none1,unit=0 check_floppy_qtree -drive if=none,file="$TEST_IMG" -drive if=none,file="$TEST_IMG.2" \ -global isa-fdc.driveB=none0 -device floppy,drive=none1,unit=1 +check_floppy_qtree -drive if=none,file="$TEST_IMG" -drive if=none,file="$TEST_IMG.2" \ + -global floppy.drive=none0 -device floppy,drive=none1,unit=0 echo echo @@ -205,8 +210,10 @@ echo === Attempt to use drive twice === # if=none check_floppy_qtree -drive if=none -device floppy,drive=none0 -device floppy -device floppy,drive=none0 +check_floppy_qtree -drive if=none -global floppy.drive=none0 -device floppy -device floppy # if=floppy check_floppy_qtree -fda "" -device floppy,drive=floppy0 +check_floppy_qtree -fda "" -global floppy.drive=floppy0 # default if=floppy (not found, because it's created later) check_floppy_qtree -device floppy,drive=floppy0 diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index 0665cdcb51..68e7a5ea5f 100644 --- a/tests/qemu-iotests/172.out +++ b/tests/qemu-iotests/172.out @@ -860,6 +860,50 @@ sd0: [not inserted] (qemu) quit +Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global floppy.drive=none0 + + dev: isa-fdc, id "" + iobase = 1008 (0x3f0) + irq = 6 (0x6) + dma = 2 (0x2) + driveA = "" + driveB = "" + check_media_rate = true + fdtypeA = "auto" + fdtypeB = "auto" + fallback = "288" + isa irq 6 + bus: floppy-bus.0 + type floppy-bus + dev: floppy, id "" + unit = 0 (0x0) + drive = "floppy0" + logical_block_size = 512 (0x200) + physical_block_size = 512 (0x200) + min_io_size = 0 (0x0) + opt_io_size = 0 (0x0) + discard_granularity = 4294967295 (0xffffffff) + write-cache = "auto" + share-rw = false + drive-type = "144" +floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/unattached/device[15] + Removable device: not locked, tray closed + Cache mode: writeback + +none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/unattached/device[15] + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[22] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + + === Mixing -fdX and -device === @@ -1438,21 +1482,111 @@ sd0: [not inserted] (qemu) quit +Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global floppy.drive=none0 -device floppy,unit=0 + + dev: isa-fdc, id "" + iobase = 1008 (0x3f0) + irq = 6 (0x6) + dma = 2 (0x2) + driveA = "" + driveB = "" + check_media_rate = true + fdtypeA = "auto" + fdtypeB = "auto" + fallback = "288" + isa irq 6 + bus: floppy-bus.0 + type floppy-bus + dev: floppy, id "" + unit = 0 (0x0) + drive = "none0" + logical_block_size = 512 (0x200) + physical_block_size = 512 (0x200) + min_io_size = 0 (0x0) + opt_io_size = 0 (0x0) + discard_granularity = 4294967295 (0xffffffff) + write-cache = "auto" + share-rw = false + drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[21] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + + Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 -device floppy,drive=none1,unit=0 QEMU_PROG: -device floppy,drive=none1,unit=0: Floppy unit 0 is in use Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveB=none0 -device floppy,drive=none1,unit=1 QEMU_PROG: -device floppy,drive=none1,unit=1: Floppy unit 1 is in use +Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global floppy.drive=none0 -device floppy,drive=none1,unit=0 + + dev: isa-fdc, id "" + iobase = 1008 (0x3f0) + irq = 6 (0x6) + dma = 2 (0x2) + driveA = "" + driveB = "" + check_media_rate = true + fdtypeA = "auto" + fdtypeB = "auto" + fallback = "288" + isa irq 6 + bus: floppy-bus.0 + type floppy-bus + dev: floppy, id "" + unit = 0 (0x0) + drive = "none1" + logical_block_size = 512 (0x200) + physical_block_size = 512 (0x200) + min_io_size = 0 (0x0) + opt_io_size = 0 (0x0) + discard_granularity = 4294967295 (0xffffffff) + write-cache = "auto" + share-rw = false + drive-type = "144" +none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Cache mode: writeback + +none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) + Attached to: /machine/peripheral-anon/device[0] + Removable device: not locked, tray closed + Cache mode: writeback + +ide1-cd0: [not inserted] + Attached to: /machine/unattached/device[21] + Removable device: not locked, tray closed + +sd0: [not inserted] + Removable device: not locked, tray closed +(qemu) quit + + === Attempt to use drive twice === Testing: -drive if=none -device floppy,drive=none0 -device floppy -device floppy,drive=none0 QEMU_PROG: -device floppy,drive=none0: Drive 'none0' is already in use by another device +Testing: -drive if=none -global floppy.drive=none0 -device floppy -device floppy +QEMU_PROG: -device floppy: can't apply global floppy.drive=none0: Drive 'none0' is already in use by another device + Testing: -fda -device floppy,drive=floppy0 QEMU_PROG: -device floppy,drive=floppy0: Drive 'floppy0' is already in use because it has been automatically connected to another device (did you need 'if=none' in the drive options?) +Testing: -fda -global floppy.drive=floppy0 +QEMU_PROG: can't apply global floppy.drive=floppy0: Drive 'floppy0' is already in use because it has been automatically connected to another device (did you need 'if=none' in the drive options?) + Testing: -device floppy,drive=floppy0 QEMU_PROG: -device floppy,drive=floppy0: Property 'floppy.drive' can't find value 'floppy0' From 6172e067a4f2a521ace14f7d0d88c6df76e26eab Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:15 +0200 Subject: [PATCH 1555/2595] fdc: Reject clash between -drive if=floppy and -global isa-fdc The floppy controller devices desugar their drive properties into floppy devices (since commit a92bd191a4 "fdc: Move qdev properties to FloppyDrive", v2.8.0). This involves some bad magic in fdctrl_connect_drives(), and exists for backward compatibility. The functions for boards to create floppy controller devices fdctrl_init_isa(), fdctrl_init_sysbus(), and sun4m_fdctrl_init() desugar -drive if=floppy to these floppy controller drive properties. If you use both -drive if=floppy (or its -fda / -fdb sugar) and -global isa-fdc for the same floppy device, -global silently loses the conflict, and both backends involved end up with the floppy device frontend attached, as demonstrated by iotest 172 (see commit before previous). This is wrong. Desugar -drive if=floppy straight to floppy devices instead, with helper fdctrl_init_drives(). The conflict now gets rejected cleanly: first, fdctrl_connect_drives() creates the floppy for the controller's property, then fdctrl_init_drives() attempts to create the floppy for -drive if=floppy, but fails because the unit is already in use. Output of iotest 172 changes in three ways: 1. The clash gets rejected. 2. In one test case, "info qtree" has the floppy devices swapped, and "info block" has their QOM paths swapped. This is because the floppy device for -fda now gets created after the one for -global isa-fdc.driveB. 3. The error message for -global floppy.drive=floppy0 changes. Before the patch, we set isa-fdc.driveA to -fda's block backend, then create the floppy device for it, then move the backend from isa-fdc.driveA to floppy.drive. Floppy creation fails when applying -global floppy.drive=floppy0, because floppy0 is still attached to isa-fdc. After the patch, we create the floppy for -fda, then set its drive property to floppy0. Now floppy creation succeeds, but setting the drive property fails, because -global already set it. Yes, this is exasperatingly complicated. Signed-off-by: Markus Armbruster Message-Id: <20200622094227.1271650-5-armbru@redhat.com> --- hw/block/fdc.c | 51 ++++++------ hw/isa/isa-superio.c | 18 ++-- hw/sparc64/sun4u.c | 9 +- include/hw/block/fdc.h | 1 + tests/qemu-iotests/172 | 3 +- tests/qemu-iotests/172.out | 164 ++++++++++--------------------------- 6 files changed, 79 insertions(+), 167 deletions(-) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index be0674e4aa..2650dcb0df 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2497,6 +2497,29 @@ static void fdctrl_result_timer(void *opaque) } /* Init functions */ + +static void fdctrl_init_drives(FloppyBus *bus, DriveInfo **fds) +{ + DeviceState *dev; + int i; + + for (i = 0; i < MAX_FD; i++) { + if (fds[i]) { + dev = qdev_new("floppy"); + qdev_prop_set_uint32(dev, "unit", i); + qdev_prop_set_enum(dev, "drive-type", FLOPPY_DRIVE_TYPE_AUTO); + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(fds[i]), + &error_fatal); + qdev_realize_and_unref(dev, &bus->bus, &error_fatal); + } + } +} + +void isa_fdc_init_drives(ISADevice *fdc, DriveInfo **fds) +{ + fdctrl_init_drives(&ISA_FDC(fdc)->state.bus, fds); +} + static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, Error **errp) { @@ -2544,25 +2567,15 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds) { - DeviceState *dev; ISADevice *isadev; isadev = isa_try_new(TYPE_ISA_FDC); if (!isadev) { return NULL; } - dev = DEVICE(isadev); - - if (fds[0]) { - qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fds[0]), - &error_fatal); - } - if (fds[1]) { - qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]), - &error_fatal); - } isa_realize_and_unref(isadev, bus, &error_fatal); + isa_fdc_init_drives(isadev, fds); return isadev; } @@ -2578,18 +2591,12 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, sys = SYSBUS_FDC(dev); fdctrl = &sys->state; fdctrl->dma_chann = dma_chann; /* FIXME */ - if (fds[0]) { - qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fds[0]), - &error_fatal); - } - if (fds[1]) { - qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]), - &error_fatal); - } sbd = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sbd, &error_fatal); sysbus_connect_irq(sbd, 0, irq); sysbus_mmio_map(sbd, 0, mmio_base); + + fdctrl_init_drives(&sys->state.bus, fds); } void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, @@ -2599,15 +2606,13 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, FDCtrlSysBus *sys; dev = qdev_new("SUNW,fdtwo"); - if (fds[0]) { - qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(fds[0]), - &error_fatal); - } sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sys = SYSBUS_FDC(dev); sysbus_connect_irq(SYS_BUS_DEVICE(sys), 0, irq); sysbus_mmio_map(SYS_BUS_DEVICE(sys), 0, io_base); *fdc_tc = qdev_get_gpio_in(dev, 0); + + fdctrl_init_drives(&sys->state.bus, fds); } static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl, diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index d3d58f9f16..e2e47d8fd9 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -17,6 +17,7 @@ #include "sysemu/sysemu.h" #include "sysemu/blockdev.h" #include "chardev/char.h" +#include "hw/block/fdc.h" #include "hw/isa/superio.h" #include "hw/qdev-properties.h" #include "hw/input/i8042.h" @@ -31,7 +32,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) ISADevice *isa; DeviceState *d; Chardev *chr; - DriveInfo *drive; + DriveInfo *fd[MAX_FD]; char *name; int i; @@ -115,7 +116,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) /* Floppy disc */ if (!k->floppy.is_enabled || k->floppy.is_enabled(sio, 0)) { - isa = isa_new("isa-fdc"); + isa = isa_new(TYPE_ISA_FDC); d = DEVICE(isa); if (k->floppy.get_iobase) { qdev_prop_set_uint32(d, "iobase", k->floppy.get_iobase(sio, 0)); @@ -124,19 +125,12 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(d, "irq", k->floppy.get_irq(sio, 0)); } /* FIXME use a qdev drive property instead of drive_get() */ - drive = drive_get(IF_FLOPPY, 0, 0); - if (drive != NULL) { - qdev_prop_set_drive(d, "driveA", blk_by_legacy_dinfo(drive), - &error_fatal); - } - /* FIXME use a qdev drive property instead of drive_get() */ - drive = drive_get(IF_FLOPPY, 0, 1); - if (drive != NULL) { - qdev_prop_set_drive(d, "driveB", blk_by_legacy_dinfo(drive), - &error_fatal); + for (i = 0; i < MAX_FD; i++) { + fd[i] = drive_get(IF_FLOPPY, 0, i); } object_property_add_child(OBJECT(sio), "isa-fdc", OBJECT(isa)); isa_realize_and_unref(isa, bus, &error_fatal); + isa_fdc_init_drives(isa, fd); sio->floppy = isa; trace_superio_create_floppy(0, k->floppy.get_iobase ? diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 97e6d3a025..9c8655cffc 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -341,16 +341,9 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) } isa_dev = isa_new(TYPE_ISA_FDC); dev = DEVICE(isa_dev); - if (fd[0]) { - qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fd[0]), - &error_abort); - } - if (fd[1]) { - qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fd[1]), - &error_abort); - } qdev_prop_set_uint32(dev, "dma", -1); isa_realize_and_unref(isa_dev, s->isa_bus, &error_fatal); + isa_fdc_init_drives(isa_dev, fd); /* Power */ dev = qdev_new(TYPE_SUN4U_POWER); diff --git a/include/hw/block/fdc.h b/include/hw/block/fdc.h index c15ff4c623..8855d3476c 100644 --- a/include/hw/block/fdc.h +++ b/include/hw/block/fdc.h @@ -9,6 +9,7 @@ #define TYPE_ISA_FDC "isa-fdc" +void isa_fdc_init_drives(ISADevice *fdc, DriveInfo **fds); ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds); void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, hwaddr mmio_base, DriveInfo **fds); diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172 index 18056bcef7..3abfa72948 100755 --- a/tests/qemu-iotests/172 +++ b/tests/qemu-iotests/172 @@ -148,9 +148,10 @@ echo === Mixing -fdX and -global === check_floppy_qtree -fda "$TEST_IMG" -drive if=none,file="$TEST_IMG.2" -global isa-fdc.driveB=none0 check_floppy_qtree -fdb "$TEST_IMG" -drive if=none,file="$TEST_IMG.2" -global isa-fdc.driveA=none0 -# Conflicting (-fdX wins) +# Conflicting check_floppy_qtree -fda "$TEST_IMG" -drive if=none,file="$TEST_IMG.2" -global isa-fdc.driveA=none0 check_floppy_qtree -fdb "$TEST_IMG" -drive if=none,file="$TEST_IMG.2" -global isa-fdc.driveB=none0 +# Conflicting, -fdX wins check_floppy_qtree -fda "$TEST_IMG" -drive if=none,file="$TEST_IMG.2" -global floppy.drive=none0 echo diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index 68e7a5ea5f..340dbd39cb 100644 --- a/tests/qemu-iotests/172.out +++ b/tests/qemu-iotests/172.out @@ -205,22 +205,22 @@ Testing: -fdb dev: floppy, id "" unit = 1 (0x1) drive = "floppy1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "288" dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "288" @@ -675,17 +675,6 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global is isa irq 6 bus: floppy-bus.0 type floppy-bus - dev: floppy, id "" - unit = 1 (0x1) - drive = "none0" - logical_block_size = 512 (512 B) - physical_block_size = 512 (512 B) - min_io_size = 0 (0 B) - opt_io_size = 0 (0 B) - discard_granularity = 4294967295 (4 GiB) - write-cache = "auto" - share-rw = false - drive-type = "144" dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" @@ -697,13 +686,24 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global is write-cache = "auto" share-rw = false drive-type = "144" + dev: floppy, id "" + unit = 1 (0x1) + drive = "none0" + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) + write-cache = "auto" + share-rw = false + drive-type = "144" floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) - Attached to: /machine/unattached/device[15] + Attached to: /machine/unattached/device[16] Removable device: not locked, tray closed Cache mode: writeback none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) - Attached to: /machine/unattached/device[16] + Attached to: /machine/unattached/device[15] Removable device: not locked, tray closed Cache mode: writeback @@ -773,92 +773,10 @@ sd0: [not inserted] Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 - - dev: isa-fdc, id "" - iobase = 1008 (0x3f0) - irq = 6 (0x6) - dma = 2 (0x2) - driveA = "" - driveB = "" - check_media_rate = true - fdtypeA = "auto" - fdtypeB = "auto" - fallback = "288" - isa irq 6 - bus: floppy-bus.0 - type floppy-bus - dev: floppy, id "" - unit = 0 (0x0) - drive = "floppy0" - logical_block_size = 512 (512 B) - physical_block_size = 512 (512 B) - min_io_size = 0 (0 B) - opt_io_size = 0 (0 B) - discard_granularity = 4294967295 (4 GiB) - write-cache = "auto" - share-rw = false - drive-type = "144" -floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) - Attached to: /machine/unattached/device[15] - Removable device: not locked, tray closed - Cache mode: writeback - -none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) - Attached to: /machine/unattached/device[14] - Cache mode: writeback - -ide1-cd0: [not inserted] - Attached to: /machine/unattached/device[22] - Removable device: not locked, tray closed - -sd0: [not inserted] - Removable device: not locked, tray closed -(qemu) quit - +QEMU_PROG: Floppy unit 0 is in use Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveB=none0 - - dev: isa-fdc, id "" - iobase = 1008 (0x3f0) - irq = 6 (0x6) - dma = 2 (0x2) - driveA = "" - driveB = "" - check_media_rate = true - fdtypeA = "auto" - fdtypeB = "auto" - fallback = "288" - isa irq 6 - bus: floppy-bus.0 - type floppy-bus - dev: floppy, id "" - unit = 1 (0x1) - drive = "floppy1" - logical_block_size = 512 (512 B) - physical_block_size = 512 (512 B) - min_io_size = 0 (0 B) - opt_io_size = 0 (0 B) - discard_granularity = 4294967295 (4 GiB) - write-cache = "auto" - share-rw = false - drive-type = "144" -floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) - Attached to: /machine/unattached/device[15] - Removable device: not locked, tray closed - Cache mode: writeback - -none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) - Attached to: /machine/unattached/device[14] - Cache mode: writeback - -ide1-cd0: [not inserted] - Attached to: /machine/unattached/device[22] - Removable device: not locked, tray closed - -sd0: [not inserted] - Removable device: not locked, tray closed -(qemu) quit - +QEMU_PROG: Floppy unit 1 is in use Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global floppy.drive=none0 @@ -878,11 +796,11 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global fl dev: floppy, id "" unit = 0 (0x0) drive = "floppy0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -1500,11 +1418,11 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global floppy.drive=none0 -device dev: floppy, id "" unit = 0 (0x0) drive = "none0" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -1546,11 +1464,11 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco dev: floppy, id "" unit = 0 (0x0) drive = "none1" - logical_block_size = 512 (0x200) - physical_block_size = 512 (0x200) - min_io_size = 0 (0x0) - opt_io_size = 0 (0x0) - discard_granularity = 4294967295 (0xffffffff) + logical_block_size = 512 (512 B) + physical_block_size = 512 (512 B) + min_io_size = 0 (0 B) + opt_io_size = 0 (0 B) + discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false drive-type = "144" @@ -1585,7 +1503,7 @@ Testing: -fda -device floppy,drive=floppy0 QEMU_PROG: -device floppy,drive=floppy0: Drive 'floppy0' is already in use because it has been automatically connected to another device (did you need 'if=none' in the drive options?) Testing: -fda -global floppy.drive=floppy0 -QEMU_PROG: can't apply global floppy.drive=floppy0: Drive 'floppy0' is already in use because it has been automatically connected to another device (did you need 'if=none' in the drive options?) +QEMU_PROG: Drive 'floppy0' is already in use because it has been automatically connected to another device (did you need 'if=none' in the drive options?) Testing: -device floppy,drive=floppy0 QEMU_PROG: -device floppy,drive=floppy0: Property 'floppy.drive' can't find value 'floppy0' From fed2c1731c3dfdcf2d69a3ba73da01a80950bcfd Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:16 +0200 Subject: [PATCH 1556/2595] fdc: Open-code fdctrl_init_isa() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Helper function fdctrl_init_isa() is less than helpful: one of three places creating "isa-fdc" devices use it. Open-code it there, and drop the function. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200622094227.1271650-6-armbru@redhat.com> --- hw/block/fdc.c | 14 -------------- hw/i386/pc.c | 8 ++++++-- include/hw/block/fdc.h | 1 - 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 2650dcb0df..d1f7722cff 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2565,20 +2565,6 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, } } -ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds) -{ - ISADevice *isadev; - - isadev = isa_try_new(TYPE_ISA_FDC); - if (!isadev) { - return NULL; - } - isa_realize_and_unref(isadev, bus, &error_fatal); - - isa_fdc_init_drives(isadev, fds); - return isadev; -} - void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, hwaddr mmio_base, DriveInfo **fds) { diff --git a/hw/i386/pc.c b/hw/i386/pc.c index d103b8c0ab..f670bcd6e6 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1142,7 +1142,7 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport) int i; DriveInfo *fd[MAX_FD]; qemu_irq *a20_line; - ISADevice *i8042, *port92, *vmmouse; + ISADevice *fdc, *i8042, *port92, *vmmouse; serial_hds_isa_init(isa_bus, 0, MAX_ISA_SERIAL_PORTS); parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS); @@ -1152,7 +1152,11 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport) create_fdctrl |= !!fd[i]; } if (create_fdctrl) { - fdctrl_init_isa(isa_bus, fd); + fdc = isa_new(TYPE_ISA_FDC); + if (fdc) { + isa_realize_and_unref(fdc, isa_bus, &error_fatal); + isa_fdc_init_drives(fdc, fd); + } } i8042 = isa_create_simple(isa_bus, "i8042"); diff --git a/include/hw/block/fdc.h b/include/hw/block/fdc.h index 8855d3476c..d232d3fa1e 100644 --- a/include/hw/block/fdc.h +++ b/include/hw/block/fdc.h @@ -10,7 +10,6 @@ #define TYPE_ISA_FDC "isa-fdc" void isa_fdc_init_drives(ISADevice *fdc, DriveInfo **fds); -ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds); void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, hwaddr mmio_base, DriveInfo **fds); void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, From 4a27a638e718b445648de6b27c709353551d9b44 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:17 +0200 Subject: [PATCH 1557/2595] fdc: Deprecate configuring floppies with -global isa-fdc Deprecate -global isa-fdc.driveA=... -global isa-fdc.driveB=... in favour of -device floppy,unit=0,drive=... -device floppy,unit=1,drive=... Same for the other floppy controller devices. Signed-off-by: Markus Armbruster Acked-by: John Snow Message-Id: <20200622094227.1271650-7-armbru@redhat.com> --- docs/qdev-device-use.txt | 13 ++++--------- docs/system/deprecated.rst | 26 ++++++++++++++++++++++++++ hw/block/fdc.c | 17 +++++++++++++++++ tests/qemu-iotests/172.out | 30 ++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 9 deletions(-) diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt index cc53e97dcd..3d781be547 100644 --- a/docs/qdev-device-use.txt +++ b/docs/qdev-device-use.txt @@ -104,15 +104,10 @@ The -device argument differs in detail for each type of drive: * if=floppy - -global isa-fdc.driveA=DRIVE-ID - -global isa-fdc.driveB=DRIVE-ID + -device floppy,unit=UNIT,drive=DRIVE-ID - This is -global instead of -device, because the floppy controller is - created automatically, and we want to configure that one, not create - a second one (which isn't possible anyway). - - Without any -global isa-fdc,... you get an empty driveA and no - driveB. You can use -nodefaults to suppress the default driveA, see + Without any -device floppy,... you get an empty unit 0 and no unit + 1. You can use -nodefaults to suppress the default unit 0, see "Default Devices". * if=virtio @@ -385,7 +380,7 @@ some DEVNAMEs: default device suppressing DEVNAMEs CD-ROM ide-cd, ide-drive, ide-hd, scsi-cd, scsi-hd - isa-fdc's driveA floppy, isa-fdc + floppy floppy, isa-fdc parallel isa-parallel serial isa-serial VGA VGA, cirrus-vga, isa-vga, isa-cirrus-vga, diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 3a255591c3..6f8bf19d37 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -164,6 +164,32 @@ previously available ``-tb-size`` option. Use ``-display sdl,show-cursor=on`` or ``-display gtk,show-cursor=on`` instead. +``Configuring floppies with ``-global`` +''''''''''''''''''''''''''''''''''''''' + +Use ``-device floppy,...`` instead: +:: + + -global isa-fdc.driveA=... + -global sysbus-fdc.driveA=... + -global SUNW,fdtwo.drive=... + +become +:: + + -device floppy,unit=0,drive=... + +and +:: + + -global isa-fdc.driveB=... + -global sysbus-fdc.driveB=... + +become +:: + + -device floppy,unit=1,drive=... + QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/hw/block/fdc.c b/hw/block/fdc.c index d1f7722cff..7e143cbab0 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2528,6 +2528,7 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, DeviceState *dev; BlockBackend *blk; Error *local_err = NULL; + const char *fdc_name, *drive_suffix; for (i = 0; i < MAX_FD; i++) { drive = &fdctrl->drives[i]; @@ -2542,10 +2543,26 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, continue; } + fdc_name = object_get_typename(OBJECT(fdc_dev)); + drive_suffix = !strcmp(fdc_name, "SUNW,fdtwo") ? "" : i ? "B" : "A"; + warn_report("warning: property %s.drive%s is deprecated", + fdc_name, drive_suffix); + error_printf("Use -device floppy,unit=%d,drive=... instead.\n", i); + dev = qdev_new("floppy"); qdev_prop_set_uint32(dev, "unit", i); qdev_prop_set_enum(dev, "drive-type", fdctrl->qdev_for_drives[i].type); + /* + * Hack alert: we move the backend from the floppy controller + * device to the floppy device. We first need to detach the + * controller, or else floppy_create()'s qdev_prop_set_drive() + * will die when it attaches floppy device. We also need to + * take another reference so that blk_detach_dev() doesn't + * free blk while we still need it. + * + * The hack is probably a bad idea. + */ blk_ref(blk); blk_detach_dev(blk, fdc_dev); fdctrl->qdev_for_drives[i].blk = NULL; diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index 340dbd39cb..778406e4bf 100644 --- a/tests/qemu-iotests/172.out +++ b/tests/qemu-iotests/172.out @@ -383,6 +383,8 @@ sd0: [not inserted] === Using -drive if=none and -global === Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveA=none0 +QEMU_PROG: warning: warning: property isa-fdc.driveA is deprecated +Use -device floppy,unit=0,drive=... instead. dev: isa-fdc, id "" iobase = 1008 (0x3f0) @@ -423,6 +425,8 @@ sd0: [not inserted] Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global isa-fdc.driveB=none0 +QEMU_PROG: warning: warning: property isa-fdc.driveB is deprecated +Use -device floppy,unit=1,drive=... instead. dev: isa-fdc, id "" iobase = 1008 (0x3f0) @@ -463,6 +467,10 @@ sd0: [not inserted] Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 -global isa-fdc.driveB=none1 +QEMU_PROG: warning: warning: property isa-fdc.driveA is deprecated +Use -device floppy,unit=0,drive=... instead. +QEMU_PROG: warning: warning: property isa-fdc.driveB is deprecated +Use -device floppy,unit=1,drive=... instead. dev: isa-fdc, id "" iobase = 1008 (0x3f0) @@ -661,6 +669,8 @@ sd0: [not inserted] === Mixing -fdX and -global === Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveB=none0 +QEMU_PROG: warning: warning: property isa-fdc.driveB is deprecated +Use -device floppy,unit=1,drive=... instead. dev: isa-fdc, id "" iobase = 1008 (0x3f0) @@ -717,6 +727,8 @@ sd0: [not inserted] Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 +QEMU_PROG: warning: warning: property isa-fdc.driveA is deprecated +Use -device floppy,unit=0,drive=... instead. dev: isa-fdc, id "" iobase = 1008 (0x3f0) @@ -773,9 +785,13 @@ sd0: [not inserted] Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 +QEMU_PROG: warning: warning: property isa-fdc.driveA is deprecated +Use -device floppy,unit=0,drive=... instead. QEMU_PROG: Floppy unit 0 is in use Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveB=none0 +QEMU_PROG: warning: warning: property isa-fdc.driveB is deprecated +Use -device floppy,unit=1,drive=... instead. QEMU_PROG: Floppy unit 1 is in use Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global floppy.drive=none0 @@ -1177,6 +1193,8 @@ QEMU_PROG: -device floppy,drive=none0,unit=0: Floppy unit 0 is in use === Mixing -global and -device === Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 -device floppy,drive=none1 +QEMU_PROG: warning: warning: property isa-fdc.driveA is deprecated +Use -device floppy,unit=0,drive=... instead. dev: isa-fdc, id "" iobase = 1008 (0x3f0) @@ -1233,6 +1251,8 @@ sd0: [not inserted] Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 -device floppy,drive=none1,unit=1 +QEMU_PROG: warning: warning: property isa-fdc.driveA is deprecated +Use -device floppy,unit=0,drive=... instead. dev: isa-fdc, id "" iobase = 1008 (0x3f0) @@ -1289,6 +1309,8 @@ sd0: [not inserted] Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveB=none0 -device floppy,drive=none1 +QEMU_PROG: warning: warning: property isa-fdc.driveB is deprecated +Use -device floppy,unit=1,drive=... instead. dev: isa-fdc, id "" iobase = 1008 (0x3f0) @@ -1345,6 +1367,8 @@ sd0: [not inserted] Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveB=none0 -device floppy,drive=none1,unit=0 +QEMU_PROG: warning: warning: property isa-fdc.driveB is deprecated +Use -device floppy,unit=1,drive=... instead. dev: isa-fdc, id "" iobase = 1008 (0x3f0) @@ -1441,9 +1465,13 @@ sd0: [not inserted] Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 -device floppy,drive=none1,unit=0 +QEMU_PROG: warning: warning: property isa-fdc.driveA is deprecated +Use -device floppy,unit=0,drive=... instead. QEMU_PROG: -device floppy,drive=none1,unit=0: Floppy unit 0 is in use Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveB=none0 -device floppy,drive=none1,unit=1 +QEMU_PROG: warning: warning: property isa-fdc.driveB is deprecated +Use -device floppy,unit=1,drive=... instead. QEMU_PROG: -device floppy,drive=none1,unit=1: Floppy unit 1 is in use Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global floppy.drive=none0 -device floppy,drive=none1,unit=0 @@ -1512,6 +1540,8 @@ QEMU_PROG: -device floppy,drive=floppy0: Property 'floppy.drive' can't find valu === Too many floppy drives === Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -drive if=none,file=TEST_DIR/t.qcow2.3 -global isa-fdc.driveB=none0 -device floppy,drive=none1 +QEMU_PROG: warning: warning: property isa-fdc.driveB is deprecated +Use -device floppy,unit=1,drive=... instead. QEMU_PROG: -device floppy,drive=none1: Can't create floppy unit 2, bus supports only 2 units From 63d5dfbe0de3b021f285a471db632381561e1efb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:18 +0200 Subject: [PATCH 1558/2595] docs/qdev-device-use.txt: Update section "Default Devices" Resynchronize the table of default device suppressions with vl.c's default_list[]. Signed-off-by: Markus Armbruster Message-Id: <20200622094227.1271650-8-armbru@redhat.com> --- docs/qdev-device-use.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt index 3d781be547..4bbbcf561f 100644 --- a/docs/qdev-device-use.txt +++ b/docs/qdev-device-use.txt @@ -384,8 +384,8 @@ some DEVNAMEs: parallel isa-parallel serial isa-serial VGA VGA, cirrus-vga, isa-vga, isa-cirrus-vga, - vmware-svga, qxl-vga, virtio-vga - virtioconsole virtio-serial-pci, virtio-serial + vmware-svga, qxl-vga, virtio-vga, ati-vga, + vhost-user-vga The default NIC is connected to a default part created along with it. It is *not* suppressed by configuring a NIC with -device (you may call From a1b40bda089e39b4dfad3cea72a696eb7bdef58e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:19 +0200 Subject: [PATCH 1559/2595] blockdev: Deprecate -drive with bogus interface type Drives with interface types other than if=none are for onboard devices. Unfortunately, any such drives the board doesn't pick up can still be used with -device, like this: $ qemu-system-x86_64 -nodefaults -display none -S -drive if=floppy,id=bogus,unit=7 -device ide-cd,drive=bogus -monitor stdio QEMU 5.0.50 monitor - type 'help' for more information (qemu) info block bogus: [not inserted] Attached to: /machine/peripheral-anon/device[0] Removable device: not locked, tray closed (qemu) info qtree bus: main-system-bus type System [...] bus: ide.1 type IDE dev: ide-cd, id "" ---> drive = "bogus" [...] unit = 0 (0x0) [...] This kind of abuse has always worked. Deprecate it: qemu-system-x86_64: -drive if=floppy,id=bogus,unit=7: warning: bogus if=floppy is deprecated, use if=none Signed-off-by: Markus Armbruster Message-Id: <20200622094227.1271650-9-armbru@redhat.com> --- blockdev.c | 27 +++++++++++++++++++++++++-- docs/system/deprecated.rst | 8 ++++++++ include/sysemu/blockdev.h | 2 ++ softmmu/vl.c | 8 ++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/blockdev.c b/blockdev.c index 72df193ca7..31d5eaf6bf 100644 --- a/blockdev.c +++ b/blockdev.c @@ -239,6 +239,19 @@ DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit) return NULL; } +void drive_mark_claimed_by_board(void) +{ + BlockBackend *blk; + DriveInfo *dinfo; + + for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { + dinfo = blk_legacy_dinfo(blk); + if (dinfo && blk_get_attached_dev(blk)) { + dinfo->claimed_by_board = true; + } + } +} + void drive_check_orphaned(void) { BlockBackend *blk; @@ -248,8 +261,10 @@ void drive_check_orphaned(void) for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { dinfo = blk_legacy_dinfo(blk); - if (!blk_get_attached_dev(blk) && !dinfo->is_default && - dinfo->type != IF_NONE) { + if (dinfo->is_default || dinfo->type == IF_NONE) { + continue; + } + if (!blk_get_attached_dev(blk)) { loc_push_none(&loc); qemu_opts_loc_restore(dinfo->opts); error_report("machine type does not support" @@ -257,6 +272,14 @@ void drive_check_orphaned(void) if_name[dinfo->type], dinfo->bus, dinfo->unit); loc_pop(&loc); orphans = true; + continue; + } + if (!dinfo->claimed_by_board && dinfo->type != IF_VIRTIO) { + loc_push_none(&loc); + qemu_opts_loc_restore(dinfo->opts); + warn_report("bogus if=%s is deprecated, use if=none", + if_name[dinfo->type]); + loc_pop(&loc); } } diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 6f8bf19d37..728233a8ff 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -190,6 +190,14 @@ become -device floppy,unit=1,drive=... +``-drive`` with bogus interface type +'''''''''''''''''''''''''''''''''''' + +Drives with interface types other than ``if=none`` are for onboard +devices. It is possible to use drives the board doesn't pick up with +-device. This usage is now deprecated. Use ``if=none`` instead. + + QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h index a86d99b3d8..3b5fcda08d 100644 --- a/include/sysemu/blockdev.h +++ b/include/sysemu/blockdev.h @@ -35,6 +35,7 @@ struct DriveInfo { bool is_default; /* Added by default_drive() ? */ int media_cd; QemuOpts *opts; + bool claimed_by_board; QTAILQ_ENTRY(DriveInfo) next; }; @@ -45,6 +46,7 @@ BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo); void override_max_devs(BlockInterfaceType type, int max_devs); DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit); +void drive_mark_claimed_by_board(void); void drive_check_orphaned(void); DriveInfo *drive_get_by_index(BlockInterfaceType type, int index); int drive_get_max_bus(BlockInterfaceType type); diff --git a/softmmu/vl.c b/softmmu/vl.c index f669c06ede..3e15ee2435 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -4347,6 +4347,14 @@ void qemu_init(int argc, char **argv, char **envp) /* from here on runstate is RUN_STATE_PRELAUNCH */ machine_run_board_init(current_machine); + /* + * TODO To drop support for deprecated bogus if=..., move + * drive_check_orphaned() here, replacing this call. Also drop + * its deprecation warning, along with DriveInfo member + * @claimed_by_board. + */ + drive_mark_claimed_by_board(); + realtime_init(); soundhw_init(); From 466c2983f88b75c37d8bab0d68ca1a1ae15949a1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:20 +0200 Subject: [PATCH 1560/2595] qdev: Eliminate get_pointer(), set_pointer() We stopped using get_pointer() and set_pointer() for netdev in commit 23120b13c6 "net: don't use set/get_pointer() in set/get_netdev()" (v2.3.0), and for chardev in commit becdfa00cf "char: replace PROP_CHR with CharBackend" (v2.8.0). With only the drive user left, they're not helpful anymore. Eliminate. Signed-off-by: Markus Armbruster Message-Id: <20200622094227.1271650-10-armbru@redhat.com> --- hw/core/qdev-properties-system.c | 95 ++++++++++++-------------------- 1 file changed, 35 insertions(+), 60 deletions(-) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 70bfd4809b..9aa80495ee 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -25,29 +25,45 @@ #include "sysemu/iothread.h" #include "sysemu/tpm_backend.h" -static void get_pointer(Object *obj, Visitor *v, Property *prop, - char *(*print)(void *ptr), - const char *name, Error **errp) +/* --- drive --- */ + +static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque, + Error **errp) { DeviceState *dev = DEVICE(obj); + Property *prop = opaque; void **ptr = qdev_get_prop_ptr(dev, prop); + const char *value; char *p; - p = *ptr ? print(*ptr) : g_strdup(""); + if (*ptr) { + value = blk_name(*ptr); + if (!*value) { + BlockDriverState *bs = blk_bs(*ptr); + if (bs) { + value = bdrv_get_node_name(bs); + } + } + } else { + value = ""; + } + + p = g_strdup(value); visit_type_str(v, name, &p, errp); g_free(p); } -static void set_pointer(Object *obj, Visitor *v, Property *prop, - void (*parse)(DeviceState *dev, const char *str, - void **ptr, const char *propname, - Error **errp), - const char *name, Error **errp) +static void set_drive_helper(Object *obj, Visitor *v, const char *name, + void *opaque, bool iothread, Error **errp) { DeviceState *dev = DEVICE(obj); + Property *prop = opaque; Error *local_err = NULL; void **ptr = qdev_get_prop_ptr(dev, prop); char *str; + BlockBackend *blk; + bool blk_created = false; + int ret; if (dev->realized) { qdev_prop_set_after_realize(dev, name, errp); @@ -59,23 +75,12 @@ static void set_pointer(Object *obj, Visitor *v, Property *prop, error_propagate(errp, local_err); return; } + if (!*str) { g_free(str); *ptr = NULL; return; } - parse(dev, str, ptr, prop->name, errp); - g_free(str); -} - -/* --- drive --- */ - -static void do_parse_drive(DeviceState *dev, const char *str, void **ptr, - const char *propname, bool iothread, Error **errp) -{ - BlockBackend *blk; - bool blk_created = false; - int ret; blk = blk_by_name(str); if (!blk) { @@ -101,7 +106,7 @@ static void do_parse_drive(DeviceState *dev, const char *str, void **ptr, } if (!blk) { error_setg(errp, "Property '%s.%s' can't find value '%s'", - object_get_typename(OBJECT(dev)), propname, str); + object_get_typename(OBJECT(dev)), prop->name, str); goto fail; } if (blk_attach_dev(blk, dev) < 0) { @@ -126,18 +131,20 @@ fail: /* If we need to keep a reference, blk_attach_dev() took it */ blk_unref(blk); } + + g_free(str); } -static void parse_drive(DeviceState *dev, const char *str, void **ptr, - const char *propname, Error **errp) +static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque, + Error **errp) { - do_parse_drive(dev, str, ptr, propname, false, errp); + set_drive_helper(obj, v, name, opaque, false, errp); } -static void parse_drive_iothread(DeviceState *dev, const char *str, void **ptr, - const char *propname, Error **errp) +static void set_drive_iothread(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) { - do_parse_drive(dev, str, ptr, propname, true, errp); + set_drive_helper(obj, v, name, opaque, true, errp); } static void release_drive(Object *obj, const char *name, void *opaque) @@ -156,38 +163,6 @@ static void release_drive(Object *obj, const char *name, void *opaque) } } -static char *print_drive(void *ptr) -{ - const char *name; - - name = blk_name(ptr); - if (!*name) { - BlockDriverState *bs = blk_bs(ptr); - if (bs) { - name = bdrv_get_node_name(bs); - } - } - return g_strdup(name); -} - -static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque, - Error **errp) -{ - get_pointer(obj, v, opaque, print_drive, name, errp); -} - -static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque, - Error **errp) -{ - set_pointer(obj, v, opaque, parse_drive, name, errp); -} - -static void set_drive_iothread(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - set_pointer(obj, v, opaque, parse_drive_iothread, name, errp); -} - const PropertyInfo qdev_prop_drive = { .name = "str", .description = "Node name or ID of a block device to use as a backend", From 1bc133365e39feb2a37747d47de281927ce1b853 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:21 +0200 Subject: [PATCH 1561/2595] qdev: Improve netdev property override error a bit qdev_prop_set_netdev() fails when the property already has a non-null value. Seems to go back to commit 30c367ed44 "qdev-properties-system.c: Allow vlan or netdev for -device, not both", v1.7.0. Board code doesn't expect failure, and crashes: $ qemu-system-x86_64 --nodefaults -nic user -netdev user,id=nic0 -global e1000.netdev=nic0 Unexpected error in error_set_from_qdev_prop_error() at /work/armbru/qemu/hw/core/qdev-properties.c:1101: qemu-system-x86_64: Property 'e1000.netdev' doesn't take value '__org.qemu.nic0 ' Aborted (core dumped) -device and device_add handle the failure: $ qemu-system-x86_64 -nodefaults -netdev user,id=net0 -netdev user,id=net1 -device e1000,netdev=net0,netdev=net1 qemu-system-x86_64: -device e1000,netdev=net0,netdev=net1: Property 'e1000.netdev' doesn't take value 'net1' $ qemu-system-x86_64 -nodefaults -S -display none -monitor stdio -netdev user,id=net0 -netdev user,id=net1 -global e1000.netdev=net0 QEMU 5.0.50 monitor - type 'help' for more information (qemu) qemu-system-x86_64: warning: netdev net0 has no peer qemu-system-x86_64: warning: netdev net1 has no peer device_add e1000,netdev=net1 Error: Property 'e1000.netdev' doesn't take value 'net1' Perhaps netdev property override could be made to work. Perhaps it should. I'm not the right guy to figure this out. What I can do is improve the error message a bit: (qemu) device_add e1000,netdev=net1 Error: -global e1000.netdev=... conflicts with netdev=net1 Cc: Jason Wang Signed-off-by: Markus Armbruster Message-Id: <20200622094227.1271650-11-armbru@redhat.com> --- hw/core/qdev-properties-system.c | 30 +++++++++++++++++++++++++++--- hw/core/qdev-properties.c | 17 +++++++++++++++++ include/hw/qdev-properties.h | 2 ++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 9aa80495ee..3f84309b7e 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -25,6 +25,28 @@ #include "sysemu/iothread.h" #include "sysemu/tpm_backend.h" +static bool check_prop_still_unset(DeviceState *dev, const char *name, + const void *old_val, const char *new_val, + Error **errp) +{ + const GlobalProperty *prop = qdev_find_global_prop(dev, name); + + if (!old_val) { + return true; + } + + if (prop) { + error_setg(errp, "-global %s.%s=... conflicts with %s=%s", + prop->driver, prop->property, name, new_val); + } else { + /* Error message is vague, but a better one would be hard */ + error_setg(errp, "%s=%s conflicts, and override is not implemented", + name, new_val); + } + return false; +} + + /* --- drive --- */ static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque, @@ -299,14 +321,16 @@ static void set_netdev(Object *obj, Visitor *v, const char *name, } for (i = 0; i < queues; i++) { - if (peers[i]->peer) { err = -EEXIST; goto out; } - if (ncs[i]) { - err = -EINVAL; + /* + * TODO Should this really be an error? If no, the old value + * needs to be released before we store the new one. + */ + if (!check_prop_still_unset(dev, name, ncs[i], str, errp)) { goto out; } diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index ead35d7ffd..71f8aca7c6 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -1246,6 +1246,23 @@ void qdev_prop_register_global(GlobalProperty *prop) g_ptr_array_add(global_props(), prop); } +const GlobalProperty *qdev_find_global_prop(DeviceState *dev, + const char *name) +{ + GPtrArray *props = global_props(); + const GlobalProperty *p; + int i; + + for (i = 0; i < props->len; i++) { + p = g_ptr_array_index(props, i); + if (object_dynamic_cast(OBJECT(dev), p->driver) + && !strcmp(p->property, name)) { + return p; + } + } + return NULL; +} + int qdev_prop_check_globals(void) { int i, ret = 0; diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 5252bb6b1a..fc0b2f6b45 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -251,6 +251,8 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name, void qdev_prop_set_enum(DeviceState *dev, const char *name, int value); void qdev_prop_register_global(GlobalProperty *prop); +const GlobalProperty *qdev_find_global_prop(DeviceState *dev, + const char *name); int qdev_prop_check_globals(void); void qdev_prop_set_globals(DeviceState *dev); void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, From 84b0475ced86d7e0f182f0753b23f5977fdb201e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:22 +0200 Subject: [PATCH 1562/2595] qdev: Reject drive property override qdev_prop_set_drive() screws up when the property already has a non-null value: it neglects to release the old value. Both the old and the new backend become attached to the same device. Example (taken from iotest 172): -fda ... -drive if=none,... -global floppy.drive=none0. Special case: attempting to use the same backend both times fails. Example (also from iotest 172): -fda ... -global floppy.drive=floppy0. Yet another example: -device with multiple drive=... (but not device_add, which silently drops all but the last duplicate property). Perhaps drive property override could be made to work. Perhaps it should. I can't afford the time to figure this out now. What I can do is reject usage that leaves backends in unhealthy states. For what it's worth, we've long done the same for netdev properties. Signed-off-by: Markus Armbruster Message-Id: <20200622094227.1271650-12-armbru@redhat.com> --- hw/core/qdev-properties-system.c | 8 +++ tests/qemu-iotests/172.out | 88 ++------------------------------ 2 files changed, 11 insertions(+), 85 deletions(-) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 3f84309b7e..6b5fc59901 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -98,6 +98,14 @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name, return; } + /* + * TODO Should this really be an error? If no, the old value + * needs to be released before we store the new one. + */ + if (!check_prop_still_unset(dev, name, *ptr, str, errp)) { + return; + } + if (!*str) { g_free(str); *ptr = NULL; diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index 778406e4bf..cca2894af0 100644 --- a/tests/qemu-iotests/172.out +++ b/tests/qemu-iotests/172.out @@ -795,48 +795,7 @@ Use -device floppy,unit=1,drive=... instead. QEMU_PROG: Floppy unit 1 is in use Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global floppy.drive=none0 - - dev: isa-fdc, id "" - iobase = 1008 (0x3f0) - irq = 6 (0x6) - dma = 2 (0x2) - driveA = "" - driveB = "" - check_media_rate = true - fdtypeA = "auto" - fdtypeB = "auto" - fallback = "288" - isa irq 6 - bus: floppy-bus.0 - type floppy-bus - dev: floppy, id "" - unit = 0 (0x0) - drive = "floppy0" - logical_block_size = 512 (512 B) - physical_block_size = 512 (512 B) - min_io_size = 0 (0 B) - opt_io_size = 0 (0 B) - discard_granularity = 4294967295 (4 GiB) - write-cache = "auto" - share-rw = false - drive-type = "144" -floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) - Attached to: /machine/unattached/device[15] - Removable device: not locked, tray closed - Cache mode: writeback - -none0 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) - Attached to: /machine/unattached/device[15] - Cache mode: writeback - -ide1-cd0: [not inserted] - Attached to: /machine/unattached/device[22] - Removable device: not locked, tray closed - -sd0: [not inserted] - Removable device: not locked, tray closed -(qemu) quit - +QEMU_PROG: -global floppy.drive=... conflicts with drive=floppy0 === Mixing -fdX and -device === @@ -1475,48 +1434,7 @@ Use -device floppy,unit=1,drive=... instead. QEMU_PROG: -device floppy,drive=none1,unit=1: Floppy unit 1 is in use Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global floppy.drive=none0 -device floppy,drive=none1,unit=0 - - dev: isa-fdc, id "" - iobase = 1008 (0x3f0) - irq = 6 (0x6) - dma = 2 (0x2) - driveA = "" - driveB = "" - check_media_rate = true - fdtypeA = "auto" - fdtypeB = "auto" - fallback = "288" - isa irq 6 - bus: floppy-bus.0 - type floppy-bus - dev: floppy, id "" - unit = 0 (0x0) - drive = "none1" - logical_block_size = 512 (512 B) - physical_block_size = 512 (512 B) - min_io_size = 0 (0 B) - opt_io_size = 0 (0 B) - discard_granularity = 4294967295 (4 GiB) - write-cache = "auto" - share-rw = false - drive-type = "144" -none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) - Attached to: /machine/peripheral-anon/device[0] - Cache mode: writeback - -none1 (NODE_NAME): TEST_DIR/t.qcow2.2 (qcow2) - Attached to: /machine/peripheral-anon/device[0] - Removable device: not locked, tray closed - Cache mode: writeback - -ide1-cd0: [not inserted] - Attached to: /machine/unattached/device[21] - Removable device: not locked, tray closed - -sd0: [not inserted] - Removable device: not locked, tray closed -(qemu) quit - +QEMU_PROG: -device floppy,drive=none1,unit=0: -global floppy.drive=... conflicts with drive=none1 === Attempt to use drive twice === @@ -1531,7 +1449,7 @@ Testing: -fda -device floppy,drive=floppy0 QEMU_PROG: -device floppy,drive=floppy0: Drive 'floppy0' is already in use because it has been automatically connected to another device (did you need 'if=none' in the drive options?) Testing: -fda -global floppy.drive=floppy0 -QEMU_PROG: Drive 'floppy0' is already in use because it has been automatically connected to another device (did you need 'if=none' in the drive options?) +QEMU_PROG: -global floppy.drive=... conflicts with drive=floppy0 Testing: -device floppy,drive=floppy0 QEMU_PROG: -device floppy,drive=floppy0: Property 'floppy.drive' can't find value 'floppy0' From 9572a787975fa27981cbcea5cecb8f250435dbe6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:23 +0200 Subject: [PATCH 1563/2595] qdev: Reject chardev property override MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qdev_prop_set_chr() screws up when the property already has a non-null value: it neglects to release the old value. Both the old and the new backend become attached to the same device. Unlike for block devices (see previous commit), this can't be observed from the monitor (I think). Example: -serial null -chardev null,id=chr0 -global isa-serial.chardev=chr0 Special case: attempting to use the same backend both times crashes: $ qemu-system-x86_64 --nodefaults -serial null -global isa-serial.chardev=serial0 Unexpected error in qemu_chr_fe_init() at /work/armbru/qemu/chardev/char-fe.c:220: qemu-system-x86_64: Device 'serial0' is in use Aborted (core dumped) Yet another example: -device with multiple chardev=... (but not device_add, which silently drops all but the last duplicate property). Perhaps chardev property override could be made to work. Perhaps it should. I can't afford the time to figure this out now. What I can do reject usage that leaves backends in unhealthy states. For what it's worth, we've long done the same for netdev properties. Cc: Marc-André Lureau Cc: Paolo Bonzini Signed-off-by: Markus Armbruster Message-Id: <20200622094227.1271650-13-armbru@redhat.com> --- hw/core/qdev-properties-system.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 6b5fc59901..2561fa09a8 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -244,6 +244,14 @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque, return; } + /* + * TODO Should this really be an error? If no, the old value + * needs to be released before we store the new one. + */ + if (!check_prop_still_unset(dev, name, be->chr, str, errp)) { + return; + } + if (!*str) { g_free(str); be->chr = NULL; From 934df912966683b942840f67b9d1a07c8cfea102 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:24 +0200 Subject: [PATCH 1564/2595] qdev: Make qdev_prop_set_drive() match the other helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qdev_prop_set_drive() can fail. None of the other qdev_prop_set_FOO() can; they abort on error. To clean up this inconsistency, rename qdev_prop_set_drive() to qdev_prop_set_drive_err(), and create a qdev_prop_set_drive() that aborts on error. Coccinelle script to update callers: @ depends on !(file in "hw/core/qdev-properties-system.c")@ expression dev, name, value; symbol error_abort; @@ - qdev_prop_set_drive(dev, name, value, &error_abort); + qdev_prop_set_drive(dev, name, value); @@ expression dev, name, value, errp; @@ - qdev_prop_set_drive(dev, name, value, errp); + qdev_prop_set_drive_err(dev, name, value, errp); Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200622094227.1271650-14-armbru@redhat.com> --- hw/arm/aspeed.c | 8 ++++---- hw/arm/cubieboard.c | 2 +- hw/arm/exynos4210.c | 2 +- hw/arm/imx25_pdk.c | 2 +- hw/arm/mcimx6ul-evk.c | 2 +- hw/arm/mcimx7d-sabre.c | 2 +- hw/arm/msf2-som.c | 4 ++-- hw/arm/nseries.c | 4 ++-- hw/arm/orangepi.c | 2 +- hw/arm/raspi.c | 2 +- hw/arm/sabrelite.c | 6 +++--- hw/arm/vexpress.c | 3 +-- hw/arm/xilinx_zynq.c | 7 ++++--- hw/arm/xlnx-versal-virt.c | 2 +- hw/arm/xlnx-zcu102.c | 10 +++++----- hw/block/fdc.c | 6 +++--- hw/block/nand.c | 2 +- hw/block/pflash_cfi01.c | 6 +++--- hw/block/pflash_cfi02.c | 2 +- hw/core/qdev-properties-system.c | 10 ++++++++-- hw/ide/qdev.c | 4 ++-- hw/m68k/q800.c | 3 +-- hw/microblaze/petalogix_ml605_mmu.c | 5 +++-- hw/ppc/pnv.c | 3 +-- hw/ppc/spapr.c | 4 ++-- hw/scsi/scsi-bus.c | 2 +- hw/sd/milkymist-memcard.c | 2 +- hw/sd/pxa2xx_mmci.c | 2 +- hw/sd/sd.c | 2 +- hw/sd/ssi-sd.c | 3 ++- hw/xtensa/xtfpga.c | 3 +-- include/hw/qdev-properties.h | 16 +++++++++++++--- 32 files changed, 74 insertions(+), 59 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 0ad08a2b4c..42d818b81c 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -227,8 +227,8 @@ static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, fl->flash = qdev_new(flashtype); if (dinfo) { - qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo), - errp); + qdev_prop_set_drive_err(fl->flash, "drive", + blk_by_legacy_dinfo(dinfo), errp); } qdev_realize_and_unref(fl->flash, BUS(s->spi), &error_fatal); @@ -243,8 +243,8 @@ static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo) card = qdev_new(TYPE_SD_CARD); if (dinfo) { - qdev_prop_set_drive(card, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); + qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo), + &error_fatal); } qdev_realize_and_unref(card, qdev_get_child_bus(DEVICE(sdhci), "sd-bus"), diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index a96c860575..5cbd115c53 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -93,7 +93,7 @@ static void cubieboard_init(MachineState *machine) /* Plug in SD card */ carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); qdev_realize_and_unref(carddev, bus, &error_fatal); memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE, diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index b888a5c9ab..fa639806ec 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -434,7 +434,7 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) di = drive_get(IF_SD, 0, n); blk = di ? blk_by_legacy_dinfo(di) : NULL; carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_abort); + qdev_prop_set_drive(carddev, "drive", blk); qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"), &error_fatal); } diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index af8f7f969c..1c201d0d8e 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -130,7 +130,7 @@ static void imx25_pdk_init(MachineState *machine) blk = di ? blk_by_legacy_dinfo(di) : NULL; bus = qdev_get_child_bus(DEVICE(&s->soc.esdhc[i]), "sd-bus"); carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); qdev_realize_and_unref(carddev, bus, &error_fatal); } diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c index 3d1d2e3c04..2f845cedfc 100644 --- a/hw/arm/mcimx6ul-evk.c +++ b/hw/arm/mcimx6ul-evk.c @@ -55,7 +55,7 @@ static void mcimx6ul_evk_init(MachineState *machine) blk = di ? blk_by_legacy_dinfo(di) : NULL; bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus"); carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); qdev_realize_and_unref(carddev, bus, &error_fatal); } diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c index 365f8183bc..e57d52b344 100644 --- a/hw/arm/mcimx7d-sabre.c +++ b/hw/arm/mcimx7d-sabre.c @@ -57,7 +57,7 @@ static void mcimx7d_sabre_init(MachineState *machine) blk = di ? blk_by_legacy_dinfo(di) : NULL; bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus"); carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); qdev_realize_and_unref(carddev, bus, &error_fatal); } diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c index 355966c073..f9b61c36dd 100644 --- a/hw/arm/msf2-som.c +++ b/hw/arm/msf2-som.c @@ -86,8 +86,8 @@ static void emcraft_sf2_s2s010_init(MachineState *machine) spi_flash = qdev_new("s25sl12801"); qdev_prop_set_uint8(spi_flash, "spansion-cr2nv", 1); if (dinfo) { - qdev_prop_set_drive(spi_flash, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); + qdev_prop_set_drive_err(spi_flash, "drive", + blk_by_legacy_dinfo(dinfo), &error_fatal); } qdev_realize_and_unref(spi_flash, spi_bus, &error_fatal); cs_line = qdev_get_gpio_in_named(spi_flash, SSI_GPIO_CS, 0); diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index 02678dda2d..428a2a2c5a 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -182,8 +182,8 @@ static void n8x0_nand_setup(struct n800_s *s) qdev_prop_set_int32(s->nand, "shift", 1); dinfo = drive_get(IF_MTD, 0, 0); if (dinfo) { - qdev_prop_set_drive(s->nand, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); + qdev_prop_set_drive_err(s->nand, "drive", blk_by_legacy_dinfo(dinfo), + &error_fatal); } sysbus_realize_and_unref(SYS_BUS_DEVICE(s->nand), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0, diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c index 678c93033e..843dcbbd62 100644 --- a/hw/arm/orangepi.c +++ b/hw/arm/orangepi.c @@ -95,7 +95,7 @@ static void orangepi_init(MachineState *machine) /* Plug in SD card */ carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); qdev_realize_and_unref(carddev, bus, &error_fatal); /* SDRAM */ diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 380978fc27..09bf02ec9c 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -298,7 +298,7 @@ static void raspi_machine_init(MachineState *machine) exit(1); } carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); qdev_realize_and_unref(carddev, bus, &error_fatal); vcram_size = object_property_get_uint(OBJECT(&s->soc), "vcram-size", diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index a27e5baf60..91d8c43a7e 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -77,9 +77,9 @@ static void sabrelite_init(MachineState *machine) flash_dev = qdev_new("sst25vf016b"); if (dinfo) { - qdev_prop_set_drive(flash_dev, "drive", - blk_by_legacy_dinfo(dinfo), - &error_fatal); + qdev_prop_set_drive_err(flash_dev, "drive", + blk_by_legacy_dinfo(dinfo), + &error_fatal); } qdev_realize_and_unref(flash_dev, BUS(spi_bus), &error_fatal); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 7ca5d523a4..725d024c91 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -517,8 +517,7 @@ static PFlashCFI01 *ve_pflash_cfi01_register(hwaddr base, const char *name, DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); if (di) { - qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di), - &error_abort); + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di)); } qdev_prop_set_uint32(dev, "num-blocks", diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 4247c4dbd8..ed970273f3 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -159,8 +159,9 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, DriveInfo *dinfo = drive_get_next(IF_MTD); flash_dev = qdev_new("n25q128"); if (dinfo) { - qdev_prop_set_drive(flash_dev, "drive", - blk_by_legacy_dinfo(dinfo), &error_fatal); + qdev_prop_set_drive_err(flash_dev, "drive", + blk_by_legacy_dinfo(dinfo), + &error_fatal); } qdev_realize_and_unref(flash_dev, BUS(spi), &error_fatal); @@ -290,7 +291,7 @@ static void zynq_init(MachineState *machine) di = drive_get_next(IF_SD); blk = di ? blk_by_legacy_dinfo(di) : NULL; carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"), &error_fatal); } diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 5bcca7f95b..a3b1ce9c7c 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -465,7 +465,7 @@ static void sd_plugin_card(SDHCIState *sd, DriveInfo *di) card = qdev_new(TYPE_SD_CARD); object_property_add_child(OBJECT(sd), "card[*]", OBJECT(card)); - qdev_prop_set_drive(card, "drive", blk, &error_fatal); + qdev_prop_set_drive_err(card, "drive", blk, &error_fatal); qdev_realize_and_unref(card, qdev_get_child_bus(DEVICE(sd), "sd-bus"), &error_fatal); } diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index b920bcee94..77449759c6 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -143,7 +143,7 @@ static void xlnx_zcu102_init(MachineState *machine) exit(1); } carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); qdev_realize_and_unref(carddev, bus, &error_fatal); } @@ -159,8 +159,8 @@ static void xlnx_zcu102_init(MachineState *machine) flash_dev = qdev_new("sst25wf080"); if (dinfo) { - qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); + qdev_prop_set_drive_err(flash_dev, "drive", + blk_by_legacy_dinfo(dinfo), &error_fatal); } qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal); @@ -182,8 +182,8 @@ static void xlnx_zcu102_init(MachineState *machine) flash_dev = qdev_new("n25q512a11"); if (dinfo) { - qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); + qdev_prop_set_drive_err(flash_dev, "drive", + blk_by_legacy_dinfo(dinfo), &error_fatal); } qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal); diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 7e143cbab0..f4493d6afa 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2508,8 +2508,8 @@ static void fdctrl_init_drives(FloppyBus *bus, DriveInfo **fds) dev = qdev_new("floppy"); qdev_prop_set_uint32(dev, "unit", i); qdev_prop_set_enum(dev, "drive-type", FLOPPY_DRIVE_TYPE_AUTO); - qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(fds[i]), - &error_fatal); + qdev_prop_set_drive_err(dev, "drive", blk_by_legacy_dinfo(fds[i]), + &error_fatal); qdev_realize_and_unref(dev, &bus->bus, &error_fatal); } } @@ -2566,7 +2566,7 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev, blk_ref(blk); blk_detach_dev(blk, fdc_dev); fdctrl->qdev_for_drives[i].blk = NULL; - qdev_prop_set_drive(dev, "drive", blk, &local_err); + qdev_prop_set_drive_err(dev, "drive", blk, &local_err); blk_unref(blk); if (local_err) { diff --git a/hw/block/nand.c b/hw/block/nand.c index 7e25681d59..654e0cb5d1 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -648,7 +648,7 @@ DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id) qdev_prop_set_uint8(dev, "manufacturer_id", manf_id); qdev_prop_set_uint8(dev, "chip_id", chip_id); if (blk) { - qdev_prop_set_drive(dev, "drive", blk, &error_fatal); + qdev_prop_set_drive_err(dev, "drive", blk, &error_fatal); } qdev_realize(dev, NULL, &error_fatal); diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 9f0c1d61ca..cddc3a5a0c 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -962,7 +962,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); if (blk) { - qdev_prop_set_drive(dev, "drive", blk, &error_abort); + qdev_prop_set_drive(dev, "drive", blk); } assert(QEMU_IS_ALIGNED(size, sector_len)); qdev_prop_set_uint32(dev, "num-blocks", size / sector_len); @@ -1010,8 +1010,8 @@ void pflash_cfi01_legacy_drive(PFlashCFI01 *fl, DriveInfo *dinfo) error_report("clashes with -machine"); exit(1); } - qdev_prop_set_drive(DEVICE(fl), "drive", - blk_by_legacy_dinfo(dinfo), &error_fatal); + qdev_prop_set_drive_err(DEVICE(fl), "drive", blk_by_legacy_dinfo(dinfo), + &error_fatal); loc_pop(&loc); } diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 6eb66e7bb0..b40ce2335a 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -1001,7 +1001,7 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base, DeviceState *dev = qdev_new(TYPE_PFLASH_CFI02); if (blk) { - qdev_prop_set_drive(dev, "drive", blk, &error_abort); + qdev_prop_set_drive(dev, "drive", blk); } assert(QEMU_IS_ALIGNED(size, sector_len)); qdev_prop_set_uint32(dev, "num-blocks", size / sector_len); diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 2561fa09a8..38b0c9f09b 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -425,8 +425,8 @@ const PropertyInfo qdev_prop_audiodev = { .set = set_audiodev, }; -void qdev_prop_set_drive(DeviceState *dev, const char *name, - BlockBackend *value, Error **errp) +void qdev_prop_set_drive_err(DeviceState *dev, const char *name, + BlockBackend *value, Error **errp) { const char *ref = ""; @@ -443,6 +443,12 @@ void qdev_prop_set_drive(DeviceState *dev, const char *name, object_property_set_str(OBJECT(dev), ref, name, errp); } +void qdev_prop_set_drive(DeviceState *dev, const char *name, + BlockBackend *value) +{ + qdev_prop_set_drive_err(dev, name, value, &error_abort); +} + void qdev_prop_set_chr(DeviceState *dev, const char *name, Chardev *value) { diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 3ccb5e2529..f68fbee93d 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -129,8 +129,8 @@ IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive) dev = qdev_new(drive->media_cd ? "ide-cd" : "ide-hd"); qdev_prop_set_uint32(dev, "unit", unit); - qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(drive), - &error_fatal); + qdev_prop_set_drive_err(dev, "drive", blk_by_legacy_dinfo(drive), + &error_fatal); qdev_realize_and_unref(dev, &bus->qbus, &error_fatal); return DO_UPCAST(IDEDevice, qdev, dev); } diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 503ec54f5d..459d326af0 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -221,8 +221,7 @@ static void q800_init(MachineState *machine) via_dev = qdev_new(TYPE_MAC_VIA); dinfo = drive_get(IF_MTD, 0, 0); if (dinfo) { - qdev_prop_set_drive(via_dev, "drive", blk_by_legacy_dinfo(dinfo), - &error_abort); + qdev_prop_set_drive(via_dev, "drive", blk_by_legacy_dinfo(dinfo)); } sysbus = SYS_BUS_DEVICE(via_dev); sysbus_realize_and_unref(sysbus, &error_fatal); diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index 23420028f5..fff2c578ef 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -188,8 +188,9 @@ petalogix_ml605_init(MachineState *machine) dev = qdev_new("n25q128"); if (dinfo) { - qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); + qdev_prop_set_drive_err(dev, "drive", + blk_by_legacy_dinfo(dinfo), + &error_fatal); } qdev_realize_and_unref(dev, BUS(spi), &error_fatal); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 80b4afd211..8bd03f3b10 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -730,8 +730,7 @@ static void pnv_init(MachineState *machine) */ dev = qdev_new(TYPE_PNV_PNOR); if (pnor) { - qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(pnor), - &error_abort); + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(pnor)); } sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); pnv->pnor = PNV_PNOR(dev); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8d630baa5d..bd9345cdac 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1716,8 +1716,8 @@ static void spapr_create_nvram(SpaprMachineState *spapr) DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0); if (dinfo) { - qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); + qdev_prop_set_drive_err(dev, "drive", blk_by_legacy_dinfo(dinfo), + &error_fatal); } qdev_realize_and_unref(dev, &spapr->vio_bus->bus, &error_fatal); diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 1a7320c0af..27843bb04b 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -277,7 +277,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, if (serial && object_property_find(OBJECT(dev), "serial", NULL)) { qdev_prop_set_string(dev, "serial", serial); } - qdev_prop_set_drive(dev, "drive", blk, &err); + qdev_prop_set_drive_err(dev, "drive", blk, &err); if (err) { error_propagate(errp, err); object_unparent(OBJECT(dev)); diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index 4cfdf7b64c..1c23310715 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -279,7 +279,7 @@ static void milkymist_memcard_realize(DeviceState *dev, Error **errp) dinfo = drive_get_next(IF_SD); blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &err); + qdev_prop_set_drive_err(carddev, "drive", blk, &err); qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err); if (err) { error_setg(errp, "failed to init SD card: %s", error_get_pretty(err)); diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index 623be70b26..3407617afc 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -496,7 +496,7 @@ PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, /* Create and plug in the sd card */ carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &err); + qdev_prop_set_drive_err(carddev, "drive", blk, &err); if (err) { error_reportf_err(err, "failed to init SD card: "); return NULL; diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 7070a116ea..97a9d32964 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -706,7 +706,7 @@ SDState *sd_init(BlockBackend *blk, bool is_spi) obj = object_new(TYPE_SD_CARD); dev = DEVICE(obj); - qdev_prop_set_drive(dev, "drive", blk, &err); + qdev_prop_set_drive_err(dev, "drive", blk, &err); if (err) { error_reportf_err(err, "sd_init failed: "); return NULL; diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index f98a6f3ae1..25cec2ddea 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -254,7 +254,8 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) dinfo = drive_get_next(IF_SD); carddev = qdev_new(TYPE_SD_CARD); if (dinfo) { - qdev_prop_set_drive(carddev, "drive", blk_by_legacy_dinfo(dinfo), &err); + qdev_prop_set_drive_err(carddev, "drive", blk_by_legacy_dinfo(dinfo), + &err); if (err) { goto fail; } diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index 5d0834c1d9..10de15855a 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -173,8 +173,7 @@ static PFlashCFI01 *xtfpga_flash_init(MemoryRegion *address_space, SysBusDevice *s; DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); - qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo), - &error_abort); + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo)); qdev_prop_set_uint32(dev, "num-blocks", board->flash->size / board->flash->sector_size); qdev_prop_set_uint64(dev, "sector-length", board->flash->sector_size); diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index fc0b2f6b45..49c6cd2460 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -233,8 +233,16 @@ extern const PropertyInfo qdev_prop_pcie_link_width; #define DEFINE_PROP_END_OF_LIST() \ {} -/* Set properties between creation and init. */ -void *qdev_get_prop_ptr(DeviceState *dev, Property *prop); +/* + * Set properties between creation and realization. + */ +void qdev_prop_set_drive_err(DeviceState *dev, const char *name, + BlockBackend *value, Error **errp); + +/* + * Set properties between creation and realization. + * @value must be valid. Each property may be set at most once. + */ void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value); void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value); void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value); @@ -245,11 +253,13 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) void qdev_prop_set_chr(DeviceState *dev, const char *name, Chardev *value); void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value); void qdev_prop_set_drive(DeviceState *dev, const char *name, - BlockBackend *value, Error **errp); + BlockBackend *value); void qdev_prop_set_macaddr(DeviceState *dev, const char *name, const uint8_t *value); void qdev_prop_set_enum(DeviceState *dev, const char *name, int value); +void *qdev_get_prop_ptr(DeviceState *dev, Property *prop); + void qdev_prop_register_global(GlobalProperty *prop); const GlobalProperty *qdev_find_global_prop(DeviceState *dev, const char *name); From c20b4ccce017bc6ac62617b458367f6a1de9afb5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:25 +0200 Subject: [PATCH 1565/2595] arm/aspeed: Drop aspeed_board_init_flashes() parameter @errp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We always pass &error_abort. Drop the parameter, use &error_abort directly. Cc: Cédric Le Goater Cc: Peter Maydell Cc: Andrew Jeffery Cc: Joel Stanley Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200622094227.1271650-15-armbru@redhat.com> --- hw/arm/aspeed.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 42d818b81c..863757e1f0 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -215,8 +215,8 @@ static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size, g_free(storage); } -static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, - Error **errp) +static void aspeed_board_init_flashes(AspeedSMCState *s, + const char *flashtype) { int i ; @@ -227,8 +227,8 @@ static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, fl->flash = qdev_new(flashtype); if (dinfo) { - qdev_prop_set_drive_err(fl->flash, "drive", - blk_by_legacy_dinfo(dinfo), errp); + qdev_prop_set_drive(fl->flash, "drive", + blk_by_legacy_dinfo(dinfo)); } qdev_realize_and_unref(fl->flash, BUS(s->spi), &error_fatal); @@ -314,8 +314,8 @@ static void aspeed_machine_init(MachineState *machine) "max_ram", max_ram_size - ram_size); memory_region_add_subregion(&bmc->ram_container, ram_size, &bmc->max_ram); - aspeed_board_init_flashes(&bmc->soc.fmc, amc->fmc_model, &error_abort); - aspeed_board_init_flashes(&bmc->soc.spi[0], amc->spi_model, &error_abort); + aspeed_board_init_flashes(&bmc->soc.fmc, amc->fmc_model); + aspeed_board_init_flashes(&bmc->soc.spi[0], amc->spi_model); /* Install first FMC flash content as a boot rom. */ if (drive0) { From 17d26ac61ee637a38d58b7053fdd1695ea2b7bc9 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:26 +0200 Subject: [PATCH 1566/2595] sd/pxa2xx_mmci: Don't crash on pxa2xx_mmci_init() error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On error, pxa2xx_mmci_init() reports to stderr and returns NULL. Callers don't check for errors. Machines akita, borzoi, mainstone, spitz, terrier, tosa, and z2 crash shortly after, like this: $ qemu-system-aarch64 -M akita -drive if=sd,readonly=on qemu-system-aarch64: failed to init SD card: Cannot use read-only drive as SD card Segmentation fault (core dumped) Machines connex and verdex reach the check for orphaned drives first: $ aarch64-softmmu/qemu-system-aarch64 -M connex -drive if=sd,readonly=on -accel qtest qemu-system-aarch64: failed to init SD card: Cannot use read-only drive as SD card qemu-system-aarch64: -drive if=sd,readonly=on: machine type does not support if=sd,bus=0,unit=0 Make pxa2xx_mmci_init() fail cleanly right away. Cc: Andrzej Zaborowski Cc: Peter Maydell Cc: qemu-arm@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200622094227.1271650-16-armbru@redhat.com> --- hw/sd/pxa2xx_mmci.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index 3407617afc..68bed24480 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -18,7 +18,6 @@ #include "hw/arm/pxa.h" #include "hw/sd/sd.h" #include "hw/qdev-properties.h" -#include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/module.h" #include "trace.h" @@ -483,7 +482,6 @@ PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, DeviceState *dev, *carddev; SysBusDevice *sbd; PXA2xxMMCIState *s; - Error *err = NULL; dev = qdev_new(TYPE_PXA2XX_MMCI); s = PXA2XX_MMCI(dev); @@ -496,16 +494,9 @@ PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, /* Create and plug in the sd card */ carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive_err(carddev, "drive", blk, &err); - if (err) { - error_reportf_err(err, "failed to init SD card: "); - return NULL; - } - qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"), &err); - if (err) { - error_reportf_err(err, "failed to init SD card: "); - return NULL; - } + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); + qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"), + &error_fatal); return s; } From 953cd66139b6e28fdc7cdbf28065a0a98ce7877c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 22 Jun 2020 11:42:27 +0200 Subject: [PATCH 1567/2595] sd/milkymist-memcard: Fix error API violation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Error ** argument must be NULL, &error_abort, &error_fatal, or a pointer to a variable containing NULL. Passing an argument of the latter kind twice without clearing it in between is wrong: if the first call sets an error, it no longer points to NULL for the second call. milkymist_memcard_realize() is wrong that way: it passes &err to qdev_prop_set_drive_err() and qdev_realize_and_unref(). Currently harmless, because the latter uses it only as first argument of error_propagate(). Making qdev_prop_set_drive_err() fail involves abuse of -global. Leave handling that to qdev_prop_set_drive(), like we do elsewhere. Cc: Michael Walle Signed-off-by: Markus Armbruster Message-Id: <20200622094227.1271650-17-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/sd/milkymist-memcard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index 1c23310715..482e97191e 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -279,7 +279,7 @@ static void milkymist_memcard_realize(DeviceState *dev, Error **errp) dinfo = drive_get_next(IF_SD); blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; carddev = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive_err(carddev, "drive", blk, &err); + qdev_prop_set_drive(carddev, "drive", blk); qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err); if (err) { error_setg(errp, "failed to init SD card: %s", error_get_pretty(err)); From ddd633e525fec68437d04b074130aedc9d461331 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 21 May 2020 16:36:16 +0100 Subject: [PATCH 1568/2595] minikconf: explicitly set encoding to UTF-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU currently only has ASCII Kconfig files but Linux actually uses UTF-8. Explicitly specify the encoding and that we're doing text file I/O. It's unclear whether or not QEMU will ever need Unicode in its Kconfig files. If we start using the help text then it will become an issue sooner or later. Make this change now for consistency with Linux Kconfig. Reported-by: Philippe Mathieu-Daudé Signed-off-by: Stefan Hajnoczi Reviewed-by: Richard Henderson Message-id: 20200521153616.307100-1-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/minikconf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/minikconf.py b/scripts/minikconf.py index 90b99517c1..bcd91015d3 100755 --- a/scripts/minikconf.py +++ b/scripts/minikconf.py @@ -402,7 +402,7 @@ class KconfigParser: if incl_abs_fname in self.data.previously_included: return try: - fp = open(incl_abs_fname, 'r') + fp = open(incl_abs_fname, 'rt', encoding='utf-8') except IOError as e: raise KconfigParserError(self, '%s: %s' % (e.strerror, include)) @@ -696,7 +696,7 @@ if __name__ == '__main__': parser.do_assignment(name, value == 'y') external_vars.add(name[7:]) else: - fp = open(arg, 'r') + fp = open(arg, 'rt', encoding='utf-8') parser.parse_file(fp) fp.close() @@ -705,7 +705,7 @@ if __name__ == '__main__': if key not in external_vars and config[key]: print ('CONFIG_%s=y' % key) - deps = open(argv[2], 'w') + deps = open(argv[2], 'wt', encoding='utf-8') for fname in data.previously_included: print ('%s: %s' % (argv[1], fname), file=deps) deps.close() From 58ebc2c31337734a8a79b0566b31b19040deb2ea Mon Sep 17 00:00:00 2001 From: Daniele Buono Date: Fri, 29 May 2020 16:51:19 -0400 Subject: [PATCH 1569/2595] coroutine: support SafeStack in ucontext backend LLVM's SafeStack instrumentation does not yet support programs that make use of the APIs in ucontext.h With the current implementation of coroutine-ucontext, the resulting binary is incorrect, with different coroutines sharing the same unsafe stack and producing undefined behavior at runtime. This fix allocates an additional unsafe stack area for each coroutine, and sets the new unsafe stack pointer before calling swapcontext() in qemu_coroutine_new. This is the only place where the pointer needs to be manually updated, since sigsetjmp/siglongjmp are already instrumented by LLVM to properly support SafeStack. The additional stack is then freed in qemu_coroutine_delete. Signed-off-by: Daniele Buono Message-id: 20200529205122.714-2-dbuono@linux.vnet.ibm.com Signed-off-by: Stefan Hajnoczi --- include/qemu/coroutine_int.h | 5 +++++ util/coroutine-ucontext.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/qemu/coroutine_int.h b/include/qemu/coroutine_int.h index bd6b0468e1..1da148552f 100644 --- a/include/qemu/coroutine_int.h +++ b/include/qemu/coroutine_int.h @@ -28,6 +28,11 @@ #include "qemu/queue.h" #include "qemu/coroutine.h" +#ifdef CONFIG_SAFESTACK +/* Pointer to the unsafe stack, defined by the compiler */ +extern __thread void *__safestack_unsafe_stack_ptr; +#endif + #define COROUTINE_STACK_SIZE (1 << 20) typedef enum { diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index 613f4c118e..f0b66320e1 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -45,6 +45,11 @@ typedef struct { Coroutine base; void *stack; size_t stack_size; +#ifdef CONFIG_SAFESTACK + /* Need an unsafe stack for each coroutine */ + void *unsafe_stack; + size_t unsafe_stack_size; +#endif sigjmp_buf env; void *tsan_co_fiber; @@ -179,6 +184,10 @@ Coroutine *qemu_coroutine_new(void) co = g_malloc0(sizeof(*co)); co->stack_size = COROUTINE_STACK_SIZE; co->stack = qemu_alloc_stack(&co->stack_size); +#ifdef CONFIG_SAFESTACK + co->unsafe_stack_size = COROUTINE_STACK_SIZE; + co->unsafe_stack = qemu_alloc_stack(&co->unsafe_stack_size); +#endif co->base.entry_arg = &old_env; /* stash away our jmp_buf */ uc.uc_link = &old_uc; @@ -203,6 +212,22 @@ Coroutine *qemu_coroutine_new(void) COROUTINE_YIELD, &fake_stack_save, co->stack, co->stack_size, co->tsan_co_fiber); + +#ifdef CONFIG_SAFESTACK + /* + * Before we swap the context, set the new unsafe stack + * The unsafe stack grows just like the normal stack, so start from + * the last usable location of the memory area. + * NOTE: we don't have to re-set the usp afterwards because we are + * coming back to this context through a siglongjmp. + * The compiler already wrapped the corresponding sigsetjmp call with + * code that saves the usp on the (safe) stack before the call, and + * restores it right after (which is where we return with siglongjmp). + */ + void *usp = co->unsafe_stack + co->unsafe_stack_size; + __safestack_unsafe_stack_ptr = usp; +#endif + swapcontext(&old_uc, &uc); } @@ -235,6 +260,9 @@ void qemu_coroutine_delete(Coroutine *co_) #endif qemu_free_stack(co->stack, co->stack_size); +#ifdef CONFIG_SAFESTACK + qemu_free_stack(co->unsafe_stack, co->unsafe_stack_size); +#endif g_free(co); } From ff76097ad8f7fdc9d1d707bed85c146fdbb5a16d Mon Sep 17 00:00:00 2001 From: Daniele Buono Date: Fri, 29 May 2020 16:51:20 -0400 Subject: [PATCH 1570/2595] coroutine: add check for SafeStack in sigaltstack Current implementation of LLVM's SafeStack is not compatible with code that uses an alternate stack created with sigaltstack(). Since coroutine-sigaltstack relies on sigaltstack(), it is not compatible with SafeStack. The resulting binary is incorrect, with different coroutines sharing the same unsafe stack and producing undefined behavior at runtime. In the future LLVM may provide a SafeStack implementation compatible with sigaltstack(). In the meantime, if SafeStack is desired, the coroutine implementation from coroutine-ucontext should be used. As a safety check, add a control in coroutine-sigaltstack to throw a preprocessor #error if SafeStack is enabled and we are trying to use coroutine-sigaltstack to implement coroutines. Signed-off-by: Daniele Buono Message-id: 20200529205122.714-3-dbuono@linux.vnet.ibm.com Signed-off-by: Stefan Hajnoczi --- util/coroutine-sigaltstack.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c index f6fc49a0e5..aade82afb8 100644 --- a/util/coroutine-sigaltstack.c +++ b/util/coroutine-sigaltstack.c @@ -30,6 +30,10 @@ #include "qemu-common.h" #include "qemu/coroutine_int.h" +#ifdef CONFIG_SAFESTACK +#error "SafeStack is not compatible with code run in alternate signal stacks" +#endif + typedef struct { Coroutine base; void *stack; From 1e4f6065da160977f212270893372436b8f13336 Mon Sep 17 00:00:00 2001 From: Daniele Buono Date: Fri, 29 May 2020 16:51:21 -0400 Subject: [PATCH 1571/2595] configure: add flags to support SafeStack This patch adds a flag to enable/disable the SafeStack instrumentation provided by LLVM. On enable, make sure that the compiler supports the flags, and that we are using the proper coroutine implementation (coroutine-ucontext). On disable, explicitly disable the option if it was enabled by default. While SafeStack is supported only on Linux, NetBSD, FreeBSD and macOS, we are not checking for the O.S. since this is already done by LLVM. Signed-off-by: Daniele Buono Message-id: 20200529205122.714-4-dbuono@linux.vnet.ibm.com Signed-off-by: Stefan Hajnoczi --- configure | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/configure b/configure index ba88fd1824..ae8737d5a2 100755 --- a/configure +++ b/configure @@ -307,6 +307,7 @@ audio_win_int="" libs_qga="" debug_info="yes" stack_protector="" +safe_stack="" use_containers="yes" gdb_bin=$(command -v "gdb-multiarch" || command -v "gdb") @@ -1287,6 +1288,10 @@ for opt do ;; --disable-stack-protector) stack_protector="no" ;; + --enable-safe-stack) safe_stack="yes" + ;; + --disable-safe-stack) safe_stack="no" + ;; --disable-curses) curses="no" ;; --enable-curses) curses="yes" @@ -1829,6 +1834,8 @@ disabled with --disable-FEATURE, default is enabled if available: debug-tcg TCG debugging (default is disabled) debug-info debugging information sparse sparse checker + safe-stack SafeStack Stack Smash Protection. Depends on + clang/llvm >= 3.7 and requires coroutine backend ucontext. gnutls GNUTLS cryptography support nettle nettle cryptography support @@ -5573,6 +5580,67 @@ if test "$debug_stack_usage" = "yes"; then fi fi +################################################## +# SafeStack + + +if test "$safe_stack" = "yes"; then +cat > $TMPC << EOF +int main(int argc, char *argv[]) +{ +#if ! __has_feature(safe_stack) +#error SafeStack Disabled +#endif + return 0; +} +EOF + flag="-fsanitize=safe-stack" + # Check that safe-stack is supported and enabled. + if compile_prog "-Werror $flag" "$flag"; then + # Flag needed both at compilation and at linking + QEMU_CFLAGS="$QEMU_CFLAGS $flag" + QEMU_LDFLAGS="$QEMU_LDFLAGS $flag" + else + error_exit "SafeStack not supported by your compiler" + fi + if test "$coroutine" != "ucontext"; then + error_exit "SafeStack is only supported by the coroutine backend ucontext" + fi +else +cat > $TMPC << EOF +int main(int argc, char *argv[]) +{ +#if defined(__has_feature) +#if __has_feature(safe_stack) +#error SafeStack Enabled +#endif +#endif + return 0; +} +EOF +if test "$safe_stack" = "no"; then + # Make sure that safe-stack is disabled + if ! compile_prog "-Werror" ""; then + # SafeStack was already enabled, try to explicitly remove the feature + flag="-fno-sanitize=safe-stack" + if ! compile_prog "-Werror $flag" "$flag"; then + error_exit "Configure cannot disable SafeStack" + fi + QEMU_CFLAGS="$QEMU_CFLAGS $flag" + QEMU_LDFLAGS="$QEMU_LDFLAGS $flag" + fi +else # "$safe_stack" = "" + # Set safe_stack to yes or no based on pre-existing flags + if compile_prog "-Werror" ""; then + safe_stack="no" + else + safe_stack="yes" + if test "$coroutine" != "ucontext"; then + error_exit "SafeStack is only supported by the coroutine backend ucontext" + fi + fi +fi +fi ########################################## # check if we have open_by_handle_at @@ -6765,6 +6833,7 @@ echo "sparse enabled $sparse" echo "strip binaries $strip_opt" echo "profiler $profiler" echo "static build $static" +echo "safe stack $safe_stack" if test "$darwin" = "yes" ; then echo "Cocoa support $cocoa" fi @@ -8370,6 +8439,10 @@ if test "$ccache_cpp2" = "yes"; then echo "export CCACHE_CPP2=y" >> $config_host_mak fi +if test "$safe_stack" = "yes"; then + echo "CONFIG_SAFESTACK=y" >> $config_host_mak +fi + # If we're using a separate build tree, set it up now. # DIRS are directories which we simply mkdir in the build tree; # LINKS are things to symlink back into the source tree From d6d1a65ccab670788b6c30d918ac7bd636513f8e Mon Sep 17 00:00:00 2001 From: Daniele Buono Date: Fri, 29 May 2020 16:51:22 -0400 Subject: [PATCH 1572/2595] check-block: enable iotests with SafeStack SafeStack is a stack protection technique implemented in llvm. It is enabled with a -fsanitize flag. iotests are currently disabled when any -fsanitize option is used, because such options tend to produce additional warnings and false positives. While common -fsanitize options are used to verify the code and not added in production, SafeStack's main use is in production environments to protect against stack smashing. Since SafeStack does not print any warning or false positive, enable iotests when SafeStack is the only -fsanitize option used. This is likely going to be a production binary and we want to make sure it works correctly. Signed-off-by: Daniele Buono Message-id: 20200529205122.714-5-dbuono@linux.vnet.ibm.com Signed-off-by: Stefan Hajnoczi --- tests/check-block.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/check-block.sh b/tests/check-block.sh index ad320c21ba..8e29c868e5 100755 --- a/tests/check-block.sh +++ b/tests/check-block.sh @@ -21,7 +21,17 @@ if grep -q "CONFIG_GPROF=y" config-host.mak 2>/dev/null ; then exit 0 fi -if grep -q "CFLAGS.*-fsanitize" config-host.mak 2>/dev/null ; then +# Disable tests with any sanitizer except for SafeStack +CFLAGS=$( grep "CFLAGS.*-fsanitize" config-host.mak 2>/dev/null ) +SANITIZE_FLAGS="" +#Remove all occurrencies of -fsanitize=safe-stack +for i in ${CFLAGS}; do + if [ "${i}" != "-fsanitize=safe-stack" ]; then + SANITIZE_FLAGS="${SANITIZE_FLAGS} ${i}" + fi +done +if echo ${SANITIZE_FLAGS} | grep -q "\-fsanitize" 2>/dev/null; then + # Have a sanitize flag that is not allowed, stop echo "Sanitizers are enabled ==> Not running the qemu-iotests." exit 0 fi From 2446e0e2e9c9aaa5f8e8c7ef9a41fe8516054831 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 17 Jun 2020 14:21:55 +0100 Subject: [PATCH 1573/2595] block/nvme: poll queues without q->lock A lot of CPU time is spent simply locking/unlocking q->lock during polling. Check for completion outside the lock to make q->lock disappear from the profile. Signed-off-by: Stefan Hajnoczi Reviewed-by: Sergio Lopez Message-id: 20200617132201.1832152-2-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- block/nvme.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/block/nvme.c b/block/nvme.c index eb2f54dd9d..e4375ec245 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -512,6 +512,18 @@ static bool nvme_poll_queues(BDRVNVMeState *s) for (i = 0; i < s->nr_queues; i++) { NVMeQueuePair *q = s->queues[i]; + const size_t cqe_offset = q->cq.head * NVME_CQ_ENTRY_BYTES; + NvmeCqe *cqe = (NvmeCqe *)&q->cq.queue[cqe_offset]; + + /* + * Do an early check for completions. q->lock isn't needed because + * nvme_process_completion() only runs in the event loop thread and + * cannot race with itself. + */ + if ((le16_to_cpu(cqe->status) & 0x1) == q->cq_phase) { + continue; + } + qemu_mutex_lock(&q->lock); while (nvme_process_completion(s, q)) { /* Keep polling */ From d38253cf8b44e3b94a5b327d014ab035ae1126ed Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 17 Jun 2020 14:21:56 +0100 Subject: [PATCH 1574/2595] block/nvme: drop tautologous assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nvme_process_completion() explicitly checks cid so the assertion that follows is always true: if (cid == 0 || cid > NVME_QUEUE_SIZE) { ... continue; } assert(cid <= NVME_QUEUE_SIZE); Signed-off-by: Stefan Hajnoczi Reviewed-by: Sergio Lopez Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200617132201.1832152-3-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- block/nvme.c | 1 - 1 file changed, 1 deletion(-) diff --git a/block/nvme.c b/block/nvme.c index e4375ec245..d567ece3f4 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -336,7 +336,6 @@ static bool nvme_process_completion(BDRVNVMeState *s, NVMeQueuePair *q) cid); continue; } - assert(cid <= NVME_QUEUE_SIZE); trace_nvme_complete_command(s, q->index, cid); preq = &q->reqs[cid - 1]; req = *preq; From 04b3fb39c815e6de67c5003e610d1cdecc911980 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 17 Jun 2020 14:21:57 +0100 Subject: [PATCH 1575/2595] block/nvme: don't access CQE after moving cq.head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not access a CQE after incrementing q->cq.head and releasing q->lock. It is unlikely that this causes problems in practice but it's a latent bug. The reason why it should be safe at the moment is that completion processing is not re-entrant and the CQ doorbell isn't written until the end of nvme_process_completion(). Make this change now because QEMU expects completion processing to be re-entrant and later patches will do that. Signed-off-by: Stefan Hajnoczi Reviewed-by: Sergio Lopez Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200617132201.1832152-4-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- block/nvme.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/block/nvme.c b/block/nvme.c index d567ece3f4..344893811a 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -321,11 +321,14 @@ static bool nvme_process_completion(BDRVNVMeState *s, NVMeQueuePair *q) q->busy = true; assert(q->inflight >= 0); while (q->inflight) { + int ret; int16_t cid; + c = (NvmeCqe *)&q->cq.queue[q->cq.head * NVME_CQ_ENTRY_BYTES]; if ((le16_to_cpu(c->status) & 0x1) == q->cq_phase) { break; } + ret = nvme_translate_error(c); q->cq.head = (q->cq.head + 1) % NVME_QUEUE_SIZE; if (!q->cq.head) { q->cq_phase = !q->cq_phase; @@ -344,7 +347,7 @@ static bool nvme_process_completion(BDRVNVMeState *s, NVMeQueuePair *q) preq->busy = false; preq->cb = preq->opaque = NULL; qemu_mutex_unlock(&q->lock); - req.cb(req.opaque, nvme_translate_error(c)); + req.cb(req.opaque, ret); qemu_mutex_lock(&q->lock); q->inflight--; progress = true; From 1086e95da1705087db542276dcbb8ba4d55cb97f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 17 Jun 2020 14:21:58 +0100 Subject: [PATCH 1576/2595] block/nvme: switch to a NVMeRequest freelist There are three issues with the current NVMeRequest->busy field: 1. The busy field is accidentally accessed outside q->lock when request submission fails. 2. Waiters on free_req_queue are not woken when a request is returned early due to submission failure. 2. Finding a free request involves scanning all requests. This makes request submission O(n^2). Switch to an O(1) freelist that is always accessed under the lock. Also differentiate between NVME_QUEUE_SIZE, the actual SQ/CQ size, and NVME_NUM_REQS, the number of usable requests. This makes the code simpler than using NVME_QUEUE_SIZE everywhere and having to keep in mind that one slot is reserved. Signed-off-by: Stefan Hajnoczi Reviewed-by: Sergio Lopez Message-id: 20200617132201.1832152-5-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- block/nvme.c | 81 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/block/nvme.c b/block/nvme.c index 344893811a..8e60882af3 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -33,6 +33,12 @@ #define NVME_QUEUE_SIZE 128 #define NVME_BAR_SIZE 8192 +/* + * We have to leave one slot empty as that is the full queue case where + * head == tail + 1. + */ +#define NVME_NUM_REQS (NVME_QUEUE_SIZE - 1) + typedef struct { int32_t head, tail; uint8_t *queue; @@ -47,7 +53,7 @@ typedef struct { int cid; void *prp_list_page; uint64_t prp_list_iova; - bool busy; + int free_req_next; /* q->reqs[] index of next free req */ } NVMeRequest; typedef struct { @@ -61,7 +67,8 @@ typedef struct { /* Fields protected by @lock */ NVMeQueue sq, cq; int cq_phase; - NVMeRequest reqs[NVME_QUEUE_SIZE]; + int free_req_head; + NVMeRequest reqs[NVME_NUM_REQS]; bool busy; int need_kick; int inflight; @@ -200,19 +207,23 @@ static NVMeQueuePair *nvme_create_queue_pair(BlockDriverState *bs, qemu_mutex_init(&q->lock); q->index = idx; qemu_co_queue_init(&q->free_req_queue); - q->prp_list_pages = qemu_blockalign0(bs, s->page_size * NVME_QUEUE_SIZE); + q->prp_list_pages = qemu_blockalign0(bs, s->page_size * NVME_NUM_REQS); r = qemu_vfio_dma_map(s->vfio, q->prp_list_pages, - s->page_size * NVME_QUEUE_SIZE, + s->page_size * NVME_NUM_REQS, false, &prp_list_iova); if (r) { goto fail; } - for (i = 0; i < NVME_QUEUE_SIZE; i++) { + q->free_req_head = -1; + for (i = 0; i < NVME_NUM_REQS; i++) { NVMeRequest *req = &q->reqs[i]; req->cid = i + 1; + req->free_req_next = q->free_req_head; + q->free_req_head = i; req->prp_list_page = q->prp_list_pages + i * s->page_size; req->prp_list_iova = prp_list_iova + i * s->page_size; } + nvme_init_queue(bs, &q->sq, size, NVME_SQ_ENTRY_BYTES, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -254,13 +265,11 @@ static void nvme_kick(BDRVNVMeState *s, NVMeQueuePair *q) */ static NVMeRequest *nvme_get_free_req(NVMeQueuePair *q) { - int i; - NVMeRequest *req = NULL; + NVMeRequest *req; qemu_mutex_lock(&q->lock); - while (q->inflight + q->need_kick > NVME_QUEUE_SIZE - 2) { - /* We have to leave one slot empty as that is the full queue case (head - * == tail + 1). */ + + while (q->free_req_head == -1) { if (qemu_in_coroutine()) { trace_nvme_free_req_queue_wait(q); qemu_co_queue_wait(&q->free_req_queue, &q->lock); @@ -269,20 +278,41 @@ static NVMeRequest *nvme_get_free_req(NVMeQueuePair *q) return NULL; } } - for (i = 0; i < NVME_QUEUE_SIZE; i++) { - if (!q->reqs[i].busy) { - q->reqs[i].busy = true; - req = &q->reqs[i]; - break; - } - } - /* We have checked inflight and need_kick while holding q->lock, so one - * free req must be available. */ - assert(req); + + req = &q->reqs[q->free_req_head]; + q->free_req_head = req->free_req_next; + req->free_req_next = -1; + qemu_mutex_unlock(&q->lock); return req; } +/* With q->lock */ +static void nvme_put_free_req_locked(NVMeQueuePair *q, NVMeRequest *req) +{ + req->free_req_next = q->free_req_head; + q->free_req_head = req - q->reqs; +} + +/* With q->lock */ +static void nvme_wake_free_req_locked(BDRVNVMeState *s, NVMeQueuePair *q) +{ + if (!qemu_co_queue_empty(&q->free_req_queue)) { + replay_bh_schedule_oneshot_event(s->aio_context, + nvme_free_req_queue_cb, q); + } +} + +/* Insert a request in the freelist and wake waiters */ +static void nvme_put_free_req_and_wake(BDRVNVMeState *s, NVMeQueuePair *q, + NVMeRequest *req) +{ + qemu_mutex_lock(&q->lock); + nvme_put_free_req_locked(q, req); + nvme_wake_free_req_locked(s, q); + qemu_mutex_unlock(&q->lock); +} + static inline int nvme_translate_error(const NvmeCqe *c) { uint16_t status = (le16_to_cpu(c->status) >> 1) & 0xFF; @@ -344,7 +374,7 @@ static bool nvme_process_completion(BDRVNVMeState *s, NVMeQueuePair *q) req = *preq; assert(req.cid == cid); assert(req.cb); - preq->busy = false; + nvme_put_free_req_locked(q, preq); preq->cb = preq->opaque = NULL; qemu_mutex_unlock(&q->lock); req.cb(req.opaque, ret); @@ -356,10 +386,7 @@ static bool nvme_process_completion(BDRVNVMeState *s, NVMeQueuePair *q) /* Notify the device so it can post more completions. */ smp_mb_release(); *q->cq.doorbell = cpu_to_le32(q->cq.head); - if (!qemu_co_queue_empty(&q->free_req_queue)) { - replay_bh_schedule_oneshot_event(s->aio_context, - nvme_free_req_queue_cb, q); - } + nvme_wake_free_req_locked(s, q); } q->busy = false; return progress; @@ -1001,7 +1028,7 @@ static coroutine_fn int nvme_co_prw_aligned(BlockDriverState *bs, r = nvme_cmd_map_qiov(bs, &cmd, req, qiov); qemu_co_mutex_unlock(&s->dma_map_lock); if (r) { - req->busy = false; + nvme_put_free_req_and_wake(s, ioq, req); return r; } nvme_submit_command(s, ioq, req, &cmd, nvme_rw_cb, &data); @@ -1218,7 +1245,7 @@ static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs, qemu_co_mutex_unlock(&s->dma_map_lock); if (ret) { - req->busy = false; + nvme_put_free_req_and_wake(s, ioq, req); goto out; } From a5db74f324ee55badfa61b03922ec24439bb94a6 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 17 Jun 2020 14:21:59 +0100 Subject: [PATCH 1577/2595] block/nvme: clarify that free_req_queue is protected by q->lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Existing users access free_req_queue under q->lock. Document this. Signed-off-by: Stefan Hajnoczi Reviewed-by: Sergio Lopez Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200617132201.1832152-6-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- block/nvme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/nvme.c b/block/nvme.c index 8e60882af3..426c77e5ab 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -57,7 +57,6 @@ typedef struct { } NVMeRequest; typedef struct { - CoQueue free_req_queue; QemuMutex lock; /* Fields protected by BQL */ @@ -65,6 +64,7 @@ typedef struct { uint8_t *prp_list_pages; /* Fields protected by @lock */ + CoQueue free_req_queue; NVMeQueue sq, cq; int cq_phase; int free_req_head; From b75fd5f55467307a6e367bc349a8ea6ce30d8a1c Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 17 Jun 2020 14:22:00 +0100 Subject: [PATCH 1578/2595] block/nvme: keep BDRVNVMeState pointer in NVMeQueuePair MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Passing around both BDRVNVMeState and NVMeQueuePair is unwieldy. Reduce the number of function arguments by keeping the BDRVNVMeState pointer in NVMeQueuePair. This will come in handly when a BH is introduced in a later patch and only one argument can be passed to it. Signed-off-by: Stefan Hajnoczi Reviewed-by: Sergio Lopez Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200617132201.1832152-7-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- block/nvme.c | 70 ++++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/block/nvme.c b/block/nvme.c index 426c77e5ab..8dc68d3daa 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -39,6 +39,8 @@ */ #define NVME_NUM_REQS (NVME_QUEUE_SIZE - 1) +typedef struct BDRVNVMeState BDRVNVMeState; + typedef struct { int32_t head, tail; uint8_t *queue; @@ -59,8 +61,11 @@ typedef struct { typedef struct { QemuMutex lock; + /* Read from I/O code path, initialized under BQL */ + BDRVNVMeState *s; + int index; + /* Fields protected by BQL */ - int index; uint8_t *prp_list_pages; /* Fields protected by @lock */ @@ -96,7 +101,7 @@ typedef volatile struct { QEMU_BUILD_BUG_ON(offsetof(NVMeRegs, doorbells) != 0x1000); -typedef struct { +struct BDRVNVMeState { AioContext *aio_context; QEMUVFIOState *vfio; NVMeRegs *regs; @@ -130,7 +135,7 @@ typedef struct { /* PCI address (required for nvme_refresh_filename()) */ char *device; -} BDRVNVMeState; +}; #define NVME_BLOCK_OPT_DEVICE "device" #define NVME_BLOCK_OPT_NAMESPACE "namespace" @@ -174,7 +179,7 @@ static void nvme_init_queue(BlockDriverState *bs, NVMeQueue *q, } } -static void nvme_free_queue_pair(BlockDriverState *bs, NVMeQueuePair *q) +static void nvme_free_queue_pair(NVMeQueuePair *q) { qemu_vfree(q->prp_list_pages); qemu_vfree(q->sq.queue); @@ -205,6 +210,7 @@ static NVMeQueuePair *nvme_create_queue_pair(BlockDriverState *bs, uint64_t prp_list_iova; qemu_mutex_init(&q->lock); + q->s = s; q->index = idx; qemu_co_queue_init(&q->free_req_queue); q->prp_list_pages = qemu_blockalign0(bs, s->page_size * NVME_NUM_REQS); @@ -240,13 +246,15 @@ static NVMeQueuePair *nvme_create_queue_pair(BlockDriverState *bs, return q; fail: - nvme_free_queue_pair(bs, q); + nvme_free_queue_pair(q); return NULL; } /* With q->lock */ -static void nvme_kick(BDRVNVMeState *s, NVMeQueuePair *q) +static void nvme_kick(NVMeQueuePair *q) { + BDRVNVMeState *s = q->s; + if (s->plugged || !q->need_kick) { return; } @@ -295,21 +303,20 @@ static void nvme_put_free_req_locked(NVMeQueuePair *q, NVMeRequest *req) } /* With q->lock */ -static void nvme_wake_free_req_locked(BDRVNVMeState *s, NVMeQueuePair *q) +static void nvme_wake_free_req_locked(NVMeQueuePair *q) { if (!qemu_co_queue_empty(&q->free_req_queue)) { - replay_bh_schedule_oneshot_event(s->aio_context, + replay_bh_schedule_oneshot_event(q->s->aio_context, nvme_free_req_queue_cb, q); } } /* Insert a request in the freelist and wake waiters */ -static void nvme_put_free_req_and_wake(BDRVNVMeState *s, NVMeQueuePair *q, - NVMeRequest *req) +static void nvme_put_free_req_and_wake(NVMeQueuePair *q, NVMeRequest *req) { qemu_mutex_lock(&q->lock); nvme_put_free_req_locked(q, req); - nvme_wake_free_req_locked(s, q); + nvme_wake_free_req_locked(q); qemu_mutex_unlock(&q->lock); } @@ -336,8 +343,9 @@ static inline int nvme_translate_error(const NvmeCqe *c) } /* With q->lock */ -static bool nvme_process_completion(BDRVNVMeState *s, NVMeQueuePair *q) +static bool nvme_process_completion(NVMeQueuePair *q) { + BDRVNVMeState *s = q->s; bool progress = false; NVMeRequest *preq; NVMeRequest req; @@ -386,7 +394,7 @@ static bool nvme_process_completion(BDRVNVMeState *s, NVMeQueuePair *q) /* Notify the device so it can post more completions. */ smp_mb_release(); *q->cq.doorbell = cpu_to_le32(q->cq.head); - nvme_wake_free_req_locked(s, q); + nvme_wake_free_req_locked(q); } q->busy = false; return progress; @@ -403,8 +411,7 @@ static void nvme_trace_command(const NvmeCmd *cmd) } } -static void nvme_submit_command(BDRVNVMeState *s, NVMeQueuePair *q, - NVMeRequest *req, +static void nvme_submit_command(NVMeQueuePair *q, NVMeRequest *req, NvmeCmd *cmd, BlockCompletionFunc cb, void *opaque) { @@ -413,15 +420,15 @@ static void nvme_submit_command(BDRVNVMeState *s, NVMeQueuePair *q, req->opaque = opaque; cmd->cid = cpu_to_le32(req->cid); - trace_nvme_submit_command(s, q->index, req->cid); + trace_nvme_submit_command(q->s, q->index, req->cid); nvme_trace_command(cmd); qemu_mutex_lock(&q->lock); memcpy((uint8_t *)q->sq.queue + q->sq.tail * NVME_SQ_ENTRY_BYTES, cmd, sizeof(*cmd)); q->sq.tail = (q->sq.tail + 1) % NVME_QUEUE_SIZE; q->need_kick++; - nvme_kick(s, q); - nvme_process_completion(s, q); + nvme_kick(q); + nvme_process_completion(q); qemu_mutex_unlock(&q->lock); } @@ -436,13 +443,12 @@ static int nvme_cmd_sync(BlockDriverState *bs, NVMeQueuePair *q, NvmeCmd *cmd) { NVMeRequest *req; - BDRVNVMeState *s = bs->opaque; int ret = -EINPROGRESS; req = nvme_get_free_req(q); if (!req) { return -EBUSY; } - nvme_submit_command(s, q, req, cmd, nvme_cmd_sync_cb, &ret); + nvme_submit_command(q, req, cmd, nvme_cmd_sync_cb, &ret); BDRV_POLL_WHILE(bs, ret == -EINPROGRESS); return ret; @@ -554,7 +560,7 @@ static bool nvme_poll_queues(BDRVNVMeState *s) } qemu_mutex_lock(&q->lock); - while (nvme_process_completion(s, q)) { + while (nvme_process_completion(q)) { /* Keep polling */ progress = true; } @@ -592,7 +598,7 @@ static bool nvme_add_io_queue(BlockDriverState *bs, Error **errp) }; if (nvme_cmd_sync(bs, s->queues[0], &cmd)) { error_setg(errp, "Failed to create io queue [%d]", n); - nvme_free_queue_pair(bs, q); + nvme_free_queue_pair(q); return false; } cmd = (NvmeCmd) { @@ -603,7 +609,7 @@ static bool nvme_add_io_queue(BlockDriverState *bs, Error **errp) }; if (nvme_cmd_sync(bs, s->queues[0], &cmd)) { error_setg(errp, "Failed to create io queue [%d]", n); - nvme_free_queue_pair(bs, q); + nvme_free_queue_pair(q); return false; } s->queues = g_renew(NVMeQueuePair *, s->queues, n + 1); @@ -798,7 +804,7 @@ static void nvme_close(BlockDriverState *bs) BDRVNVMeState *s = bs->opaque; for (i = 0; i < s->nr_queues; ++i) { - nvme_free_queue_pair(bs, s->queues[i]); + nvme_free_queue_pair(s->queues[i]); } g_free(s->queues); aio_set_event_notifier(bdrv_get_aio_context(bs), &s->irq_notifier, @@ -1028,10 +1034,10 @@ static coroutine_fn int nvme_co_prw_aligned(BlockDriverState *bs, r = nvme_cmd_map_qiov(bs, &cmd, req, qiov); qemu_co_mutex_unlock(&s->dma_map_lock); if (r) { - nvme_put_free_req_and_wake(s, ioq, req); + nvme_put_free_req_and_wake(ioq, req); return r; } - nvme_submit_command(s, ioq, req, &cmd, nvme_rw_cb, &data); + nvme_submit_command(ioq, req, &cmd, nvme_rw_cb, &data); data.co = qemu_coroutine_self(); while (data.ret == -EINPROGRESS) { @@ -1131,7 +1137,7 @@ static coroutine_fn int nvme_co_flush(BlockDriverState *bs) assert(s->nr_queues > 1); req = nvme_get_free_req(ioq); assert(req); - nvme_submit_command(s, ioq, req, &cmd, nvme_rw_cb, &data); + nvme_submit_command(ioq, req, &cmd, nvme_rw_cb, &data); data.co = qemu_coroutine_self(); if (data.ret == -EINPROGRESS) { @@ -1184,7 +1190,7 @@ static coroutine_fn int nvme_co_pwrite_zeroes(BlockDriverState *bs, req = nvme_get_free_req(ioq); assert(req); - nvme_submit_command(s, ioq, req, &cmd, nvme_rw_cb, &data); + nvme_submit_command(ioq, req, &cmd, nvme_rw_cb, &data); data.co = qemu_coroutine_self(); while (data.ret == -EINPROGRESS) { @@ -1245,13 +1251,13 @@ static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs, qemu_co_mutex_unlock(&s->dma_map_lock); if (ret) { - nvme_put_free_req_and_wake(s, ioq, req); + nvme_put_free_req_and_wake(ioq, req); goto out; } trace_nvme_dsm(s, offset, bytes); - nvme_submit_command(s, ioq, req, &cmd, nvme_rw_cb, &data); + nvme_submit_command(ioq, req, &cmd, nvme_rw_cb, &data); data.co = qemu_coroutine_self(); while (data.ret == -EINPROGRESS) { @@ -1333,8 +1339,8 @@ static void nvme_aio_unplug(BlockDriverState *bs) for (i = 1; i < s->nr_queues; i++) { NVMeQueuePair *q = s->queues[i]; qemu_mutex_lock(&q->lock); - nvme_kick(s, q); - nvme_process_completion(s, q); + nvme_kick(q); + nvme_process_completion(q); qemu_mutex_unlock(&q->lock); } } From 7838c67f22a81fcf669785cd6c0876438422071a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 17 Jun 2020 14:22:01 +0100 Subject: [PATCH 1579/2595] block/nvme: support nested aio_poll() QEMU block drivers are supposed to support aio_poll() from I/O completion callback functions. This means completion processing must be re-entrant. The standard approach is to schedule a BH during completion processing and cancel it at the end of processing. If aio_poll() is invoked by a callback function then the BH will run. The BH continues the suspended completion processing. All of this means that request A's cb() can synchronously wait for request B to complete. Previously the nvme block driver would hang because it didn't process completions from nested aio_poll(). Signed-off-by: Stefan Hajnoczi Reviewed-by: Sergio Lopez Message-id: 20200617132201.1832152-8-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- block/nvme.c | 63 +++++++++++++++++++++++++++++++++++++++++----- block/trace-events | 2 +- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/block/nvme.c b/block/nvme.c index 8dc68d3daa..374e268915 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -74,9 +74,11 @@ typedef struct { int cq_phase; int free_req_head; NVMeRequest reqs[NVME_NUM_REQS]; - bool busy; int need_kick; int inflight; + + /* Thread-safe, no lock necessary */ + QEMUBH *completion_bh; } NVMeQueuePair; /* Memory mapped registers */ @@ -140,6 +142,8 @@ struct BDRVNVMeState { #define NVME_BLOCK_OPT_DEVICE "device" #define NVME_BLOCK_OPT_NAMESPACE "namespace" +static void nvme_process_completion_bh(void *opaque); + static QemuOptsList runtime_opts = { .name = "nvme", .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), @@ -181,6 +185,9 @@ static void nvme_init_queue(BlockDriverState *bs, NVMeQueue *q, static void nvme_free_queue_pair(NVMeQueuePair *q) { + if (q->completion_bh) { + qemu_bh_delete(q->completion_bh); + } qemu_vfree(q->prp_list_pages); qemu_vfree(q->sq.queue); qemu_vfree(q->cq.queue); @@ -214,6 +221,8 @@ static NVMeQueuePair *nvme_create_queue_pair(BlockDriverState *bs, q->index = idx; qemu_co_queue_init(&q->free_req_queue); q->prp_list_pages = qemu_blockalign0(bs, s->page_size * NVME_NUM_REQS); + q->completion_bh = aio_bh_new(bdrv_get_aio_context(bs), + nvme_process_completion_bh, q); r = qemu_vfio_dma_map(s->vfio, q->prp_list_pages, s->page_size * NVME_NUM_REQS, false, &prp_list_iova); @@ -352,11 +361,21 @@ static bool nvme_process_completion(NVMeQueuePair *q) NvmeCqe *c; trace_nvme_process_completion(s, q->index, q->inflight); - if (q->busy || s->plugged) { - trace_nvme_process_completion_queue_busy(s, q->index); + if (s->plugged) { + trace_nvme_process_completion_queue_plugged(s, q->index); return false; } - q->busy = true; + + /* + * Support re-entrancy when a request cb() function invokes aio_poll(). + * Pending completions must be visible to aio_poll() so that a cb() + * function can wait for the completion of another request. + * + * The aio_poll() loop will execute our BH and we'll resume completion + * processing there. + */ + qemu_bh_schedule(q->completion_bh); + assert(q->inflight >= 0); while (q->inflight) { int ret; @@ -384,10 +403,10 @@ static bool nvme_process_completion(NVMeQueuePair *q) assert(req.cb); nvme_put_free_req_locked(q, preq); preq->cb = preq->opaque = NULL; + q->inflight--; qemu_mutex_unlock(&q->lock); req.cb(req.opaque, ret); qemu_mutex_lock(&q->lock); - q->inflight--; progress = true; } if (progress) { @@ -396,10 +415,28 @@ static bool nvme_process_completion(NVMeQueuePair *q) *q->cq.doorbell = cpu_to_le32(q->cq.head); nvme_wake_free_req_locked(q); } - q->busy = false; + + qemu_bh_cancel(q->completion_bh); + return progress; } +static void nvme_process_completion_bh(void *opaque) +{ + NVMeQueuePair *q = opaque; + + /* + * We're being invoked because a nvme_process_completion() cb() function + * called aio_poll(). The callback may be waiting for further completions + * so notify the device that it has space to fill in more completions now. + */ + smp_mb_release(); + *q->cq.doorbell = cpu_to_le32(q->cq.head); + nvme_wake_free_req_locked(q); + + nvme_process_completion(q); +} + static void nvme_trace_command(const NvmeCmd *cmd) { int i; @@ -1309,6 +1346,13 @@ static void nvme_detach_aio_context(BlockDriverState *bs) { BDRVNVMeState *s = bs->opaque; + for (int i = 0; i < s->nr_queues; i++) { + NVMeQueuePair *q = s->queues[i]; + + qemu_bh_delete(q->completion_bh); + q->completion_bh = NULL; + } + aio_set_event_notifier(bdrv_get_aio_context(bs), &s->irq_notifier, false, NULL, NULL); } @@ -1321,6 +1365,13 @@ static void nvme_attach_aio_context(BlockDriverState *bs, s->aio_context = new_context; aio_set_event_notifier(new_context, &s->irq_notifier, false, nvme_handle_event, nvme_poll_cb); + + for (int i = 0; i < s->nr_queues; i++) { + NVMeQueuePair *q = s->queues[i]; + + q->completion_bh = + aio_bh_new(new_context, nvme_process_completion_bh, q); + } } static void nvme_aio_plug(BlockDriverState *bs) diff --git a/block/trace-events b/block/trace-events index 29dff8881c..dbe76a7613 100644 --- a/block/trace-events +++ b/block/trace-events @@ -158,7 +158,7 @@ nvme_kick(void *s, int queue) "s %p queue %d" nvme_dma_flush_queue_wait(void *s) "s %p" nvme_error(int cmd_specific, int sq_head, int sqid, int cid, int status) "cmd_specific %d sq_head %d sqid %d cid %d status 0x%x" nvme_process_completion(void *s, int index, int inflight) "s %p queue %d inflight %d" -nvme_process_completion_queue_busy(void *s, int index) "s %p queue %d" +nvme_process_completion_queue_plugged(void *s, int index) "s %p queue %d" nvme_complete_command(void *s, int index, int cid) "s %p queue %d cid %d" nvme_submit_command(void *s, int index, int cid) "s %p queue %d cid %d" nvme_submit_command_raw(int c0, int c1, int c2, int c3, int c4, int c5, int c6, int c7) "%02x %02x %02x %02x %02x %02x %02x %02x" From e11543c53fed2634146b9223112bc5c941434607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 16 Jun 2020 17:49:49 +0200 Subject: [PATCH 1580/2595] iotests: Fix 051 output after qdev_init_nofail() removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 96927c744 replaced qdev_init_nofail() call by isa_realize_and_unref() which has a different error message. Update the test output accordingly. Gitlab CI error after merging b77b5b3dc7: https://gitlab.com/qemu-project/qemu/-/jobs/597414772#L4375 Reported-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200616154949.6586-1-philmd@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Max Reitz --- tests/qemu-iotests/051.pc.out | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out index 0ea80d35f0..da8ad87187 100644 --- a/tests/qemu-iotests/051.pc.out +++ b/tests/qemu-iotests/051.pc.out @@ -142,7 +142,7 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive if=ide QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Initialization of device ide-hd failed: Device needs media, but drive is empty +(qemu) QEMU_PROG: Device needs media, but drive is empty Testing: -drive if=virtio QEMU X.Y.Z monitor - type 'help' for more information @@ -214,7 +214,7 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Initialization of device ide-hd failed: Block node is read-only +(qemu) QEMU_PROG: Block node is read-only Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on QEMU X.Y.Z monitor - type 'help' for more information From 24b861c0386a17ea31eb824310c21118fb7be883 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 18 Jun 2020 18:40:52 +0300 Subject: [PATCH 1581/2595] iotests: don't test qcow2.py inside 291 820c6bee534ec3b added testing of qcow2.py into 291, and it breaks 291 with external data file. Actually, 291 is bad place for qcow2.py testing, better add a separate test. For now, drop qcow2.py testing from 291 to fix the regression. Fixes: 820c6bee534ec3b Reported-by: Max Reitz Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20200618154052.8629-1-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake Signed-off-by: Max Reitz --- tests/qemu-iotests/291 | 4 ---- tests/qemu-iotests/291.out | 33 --------------------------------- 2 files changed, 37 deletions(-) diff --git a/tests/qemu-iotests/291 b/tests/qemu-iotests/291 index 28e4fb9b4d..1e0bb76959 100755 --- a/tests/qemu-iotests/291 +++ b/tests/qemu-iotests/291 @@ -64,8 +64,6 @@ $QEMU_IO -c 'w 1M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io $QEMU_IMG bitmap --disable -f $IMGFMT "$TEST_IMG" b1 $QEMU_IMG bitmap --enable -f $IMGFMT "$TEST_IMG" b2 $QEMU_IO -c 'w 2M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io -echo "Check resulting qcow2 header extensions:" -$PYTHON qcow2.py "$TEST_IMG" dump-header-exts echo echo "=== Bitmap preservation not possible to non-qcow2 ===" @@ -92,8 +90,6 @@ $QEMU_IMG bitmap --merge tmp -f $IMGFMT "$TEST_IMG" b0 $QEMU_IMG bitmap --remove --image-opts \ driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG" tmp _img_info --format-specific -echo "Check resulting qcow2 header extensions:" -$PYTHON qcow2.py "$TEST_IMG" dump-header-exts echo echo "=== Check bitmap contents ===" diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out index 08bfaaaa6b..9f661515b4 100644 --- a/tests/qemu-iotests/291.out +++ b/tests/qemu-iotests/291.out @@ -14,25 +14,6 @@ wrote 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1048576/1048576 bytes at offset 2097152 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Check resulting qcow2 header extensions: -Header extension: -magic 0xe2792aca (Backing format) -length 5 -data 'qcow2' - -Header extension: -magic 0x6803f857 (Feature table) -length 336 -data - -Header extension: -magic 0x23852875 (Bitmaps) -length 24 -nb_bitmaps 2 -reserved32 0 -bitmap_directory_size 0x40 -bitmap_directory_offset 0x510000 - === Bitmap preservation not possible to non-qcow2 === @@ -84,20 +65,6 @@ Format specific information: granularity: 65536 refcount bits: 16 corrupt: false -Check resulting qcow2 header extensions: -Header extension: -magic 0x6803f857 (Feature table) -length 336 -data - -Header extension: -magic 0x23852875 (Bitmaps) -length 24 -nb_bitmaps 3 -reserved32 0 -bitmap_directory_size 0x60 -bitmap_directory_offset 0x520000 - === Check bitmap contents === From f892b494fafd39660679c1c4ef1dbe711a73df45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 11 May 2020 10:28:16 +0200 Subject: [PATCH 1582/2595] scripts/tracetool: Update maintainer email address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is an effort in progress to generate a QEMU Python package. As I'm not sure this old email is still valid, update it to not produce package with broken maintainer email. Patch created mechanically by running: $ sed -i 's,\(__email__ *= "\)stefanha@linux.vnet.ibm.com",\1stefanha@redhat.com",' \ $(git grep -l 'email.*stefanha@linux.vnet.ibm.com') Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: John Snow Message-id: 20200511082816.696-1-philmd@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/tracetool.py | 2 +- scripts/tracetool/__init__.py | 2 +- scripts/tracetool/backend/__init__.py | 2 +- scripts/tracetool/backend/dtrace.py | 2 +- scripts/tracetool/backend/log.py | 2 +- scripts/tracetool/backend/simple.py | 2 +- scripts/tracetool/backend/ust.py | 2 +- scripts/tracetool/format/__init__.py | 2 +- scripts/tracetool/format/c.py | 2 +- scripts/tracetool/format/d.py | 2 +- scripts/tracetool/format/h.py | 2 +- scripts/tracetool/format/stap.py | 2 +- scripts/tracetool/format/tcg_h.py | 2 +- scripts/tracetool/format/tcg_helper_c.py | 2 +- scripts/tracetool/format/tcg_helper_h.py | 2 +- scripts/tracetool/format/tcg_helper_wrapper_h.py | 2 +- scripts/tracetool/transform.py | 2 +- scripts/tracetool/vcpu.py | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/scripts/tracetool.py b/scripts/tracetool.py index 264cc9eecc..31146242b7 100755 --- a/scripts/tracetool.py +++ b/scripts/tracetool.py @@ -10,7 +10,7 @@ __copyright__ = "Copyright 2012-2014, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" import sys diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index 13d29f1e42..3ccfa1e116 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2017, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" import re diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py index 54cab2c4de..7bfcc86cc5 100644 --- a/scripts/tracetool/backend/__init__.py +++ b/scripts/tracetool/backend/__init__.py @@ -50,7 +50,7 @@ __copyright__ = "Copyright 2012-2014, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" import os diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py index 638990db79..5711892ba0 100644 --- a/scripts/tracetool/backend/dtrace.py +++ b/scripts/tracetool/backend/dtrace.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2017, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import out diff --git a/scripts/tracetool/backend/log.py b/scripts/tracetool/backend/log.py index 23b274c0fd..877222bbe9 100644 --- a/scripts/tracetool/backend/log.py +++ b/scripts/tracetool/backend/log.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2017, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import out diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py index b650c262b5..a74d61fcd6 100644 --- a/scripts/tracetool/backend/simple.py +++ b/scripts/tracetool/backend/simple.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2017, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import out diff --git a/scripts/tracetool/backend/ust.py b/scripts/tracetool/backend/ust.py index a772a3b53b..6c0a5f8d68 100644 --- a/scripts/tracetool/backend/ust.py +++ b/scripts/tracetool/backend/ust.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2017, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import out diff --git a/scripts/tracetool/format/__init__.py b/scripts/tracetool/format/__init__.py index aba2f7a441..2dc46f3dd9 100644 --- a/scripts/tracetool/format/__init__.py +++ b/scripts/tracetool/format/__init__.py @@ -32,7 +32,7 @@ __copyright__ = "Copyright 2012-2014, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" import os diff --git a/scripts/tracetool/format/c.py b/scripts/tracetool/format/c.py index 78af8aff72..23d82ea861 100644 --- a/scripts/tracetool/format/c.py +++ b/scripts/tracetool/format/c.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2014, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import out diff --git a/scripts/tracetool/format/d.py b/scripts/tracetool/format/d.py index d3980b914b..0afb5f3f47 100644 --- a/scripts/tracetool/format/d.py +++ b/scripts/tracetool/format/d.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2014, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import out diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index 83e1a2f355..e94f0be7da 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2017, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import out diff --git a/scripts/tracetool/format/stap.py b/scripts/tracetool/format/stap.py index 8fc808f2ef..a218b0445c 100644 --- a/scripts/tracetool/format/stap.py +++ b/scripts/tracetool/format/stap.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2014, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import out diff --git a/scripts/tracetool/format/tcg_h.py b/scripts/tracetool/format/tcg_h.py index 0180e3d76c..33cf6a31b3 100644 --- a/scripts/tracetool/format/tcg_h.py +++ b/scripts/tracetool/format/tcg_h.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2017, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import out, Arguments diff --git a/scripts/tracetool/format/tcg_helper_c.py b/scripts/tracetool/format/tcg_helper_c.py index 6527b69afd..2db6317f3c 100644 --- a/scripts/tracetool/format/tcg_helper_c.py +++ b/scripts/tracetool/format/tcg_helper_c.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2017, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import Arguments, out diff --git a/scripts/tracetool/format/tcg_helper_h.py b/scripts/tracetool/format/tcg_helper_h.py index 98ebe52f18..08554fbc85 100644 --- a/scripts/tracetool/format/tcg_helper_h.py +++ b/scripts/tracetool/format/tcg_helper_h.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2016, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import out diff --git a/scripts/tracetool/format/tcg_helper_wrapper_h.py b/scripts/tracetool/format/tcg_helper_wrapper_h.py index 6adeab74df..0c5a9797d1 100644 --- a/scripts/tracetool/format/tcg_helper_wrapper_h.py +++ b/scripts/tracetool/format/tcg_helper_wrapper_h.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2016, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import out diff --git a/scripts/tracetool/transform.py b/scripts/tracetool/transform.py index 8fd4dcf20d..ea8b27799d 100644 --- a/scripts/tracetool/transform.py +++ b/scripts/tracetool/transform.py @@ -9,7 +9,7 @@ __copyright__ = "Copyright 2012-2016, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" def _transform_type(type_, trans): diff --git a/scripts/tracetool/vcpu.py b/scripts/tracetool/vcpu.py index 0b104e4f15..b54e4f4e7a 100644 --- a/scripts/tracetool/vcpu.py +++ b/scripts/tracetool/vcpu.py @@ -10,7 +10,7 @@ __copyright__ = "Copyright 2016, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" +__email__ = "stefanha@redhat.com" from tracetool import Arguments, try_import From db25d56c014aa1a96319c663e0a60346a223b31e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 27 May 2020 08:56:13 +0200 Subject: [PATCH 1583/2595] trace/simple: Fix unauthorized enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit st_set_trace_file() accidentally enables tracing. It's called unconditionally during startup, which is why QEMU built with the simple trace backend always writes a trace file "trace-$PID". This has been broken for quite a while. I didn't track down the exact commit. Fix st_set_trace_file() to restore the state. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200527065613.25322-1-armbru@redhat.com Signed-off-by: Stefan Hajnoczi --- trace/simple.c | 20 ++++++++++++++------ trace/simple.h | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/trace/simple.c b/trace/simple.c index fc7106ec49..9cd2ed1fb3 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -302,10 +302,17 @@ static int st_write_event_mapping(void) return 0; } -void st_set_trace_file_enabled(bool enable) +/** + * Enable / disable tracing, return whether it was enabled. + * + * @enable: enable if %true, else disable. + */ +bool st_set_trace_file_enabled(bool enable) { + bool was_enabled = trace_fp; + if (enable == !!trace_fp) { - return; /* no change */ + return was_enabled; /* no change */ } /* Halt trace writeout */ @@ -323,14 +330,14 @@ void st_set_trace_file_enabled(bool enable) trace_fp = fopen(trace_file_name, "wb"); if (!trace_fp) { - return; + return was_enabled; } if (fwrite(&header, sizeof header, 1, trace_fp) != 1 || st_write_event_mapping() < 0) { fclose(trace_fp); trace_fp = NULL; - return; + return was_enabled; } /* Resume trace writeout */ @@ -340,6 +347,7 @@ void st_set_trace_file_enabled(bool enable) fclose(trace_fp); trace_fp = NULL; } + return was_enabled; } /** @@ -350,7 +358,7 @@ void st_set_trace_file_enabled(bool enable) */ void st_set_trace_file(const char *file) { - st_set_trace_file_enabled(false); + bool saved_enable = st_set_trace_file_enabled(false); g_free(trace_file_name); @@ -361,7 +369,7 @@ void st_set_trace_file(const char *file) trace_file_name = g_strdup_printf("%s", file); } - st_set_trace_file_enabled(true); + st_set_trace_file_enabled(saved_enable); } void st_print_trace_file_status(void) diff --git a/trace/simple.h b/trace/simple.h index 5771a0634f..26ccbc8b8a 100644 --- a/trace/simple.h +++ b/trace/simple.h @@ -12,7 +12,7 @@ #define TRACE_SIMPLE_H void st_print_trace_file_status(void); -void st_set_trace_file_enabled(bool enable); +bool st_set_trace_file_enabled(bool enable); void st_set_trace_file(const char *file); bool st_init(void); void st_flush_trace_buffer(void); From 48fedfd7dd658fcd2bec3b004bb1bce0d2cdd11d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:18:54 +0200 Subject: [PATCH 1584/2595] qtest: allow DSDT acpi table changes Signed-off-by: Gerd Hoffmann Message-Id: <20200619091905.21676-2-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..8992f1f12b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,19 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT", +"tests/data/acpi/pc/DSDT.acpihmat", +"tests/data/acpi/pc/DSDT.bridge", +"tests/data/acpi/pc/DSDT.cphp", +"tests/data/acpi/pc/DSDT.dimmpxm", +"tests/data/acpi/pc/DSDT.ipmikcs", +"tests/data/acpi/pc/DSDT.memhp", +"tests/data/acpi/pc/DSDT.numamem", +"tests/data/acpi/q35/DSDT", +"tests/data/acpi/q35/DSDT.acpihmat", +"tests/data/acpi/q35/DSDT.bridge", +"tests/data/acpi/q35/DSDT.cphp", +"tests/data/acpi/q35/DSDT.dimmpxm", +"tests/data/acpi/q35/DSDT.ipmibt", +"tests/data/acpi/q35/DSDT.memhp", +"tests/data/acpi/q35/DSDT.mmio64", +"tests/data/acpi/q35/DSDT.numamem", +"tests/data/acpi/q35/DSDT.tis", From b20fdf2cc381143271b335bd43f20eb90974e164 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:18:55 +0200 Subject: [PATCH 1585/2595] acpi: bios-tables-test: show more context on asl diffs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes it easier to create good commit messages from the logs. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200619091905.21676-3-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index b482f76c03..c315156858 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -469,7 +469,7 @@ static void test_acpi_asl(test_data *data) fflush(stderr); if (getenv("V")) { const char *diff_env = getenv("DIFF"); - const char *diff_cmd = diff_env ? diff_env : "diff -u"; + const char *diff_cmd = diff_env ? diff_env : "diff -U 16"; char *diff = g_strdup_printf("%s %s %s", diff_cmd, exp_sdt->asl_file, sdt->asl_file); int out = dup(STDOUT_FILENO); From 2055dbc1c9cd548628b06bc2547d3c617b5b03be Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:18:56 +0200 Subject: [PATCH 1586/2595] acpi: move aml builder code for floppy device DSDT change: isa device order changes in case MI1 (ipmi) is present. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Message-Id: <20200619091905.21676-4-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/fdc.c | 83 ++++++++++++++++++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 83 -------------------------------------------- stubs/Makefile.objs | 1 + stubs/cmos.c | 7 ++++ 4 files changed, 91 insertions(+), 83 deletions(-) create mode 100644 stubs/cmos.c diff --git a/hw/block/fdc.c b/hw/block/fdc.c index be0674e4aa..5244df6f91 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -32,6 +32,8 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/timer.h" +#include "hw/i386/pc.h" +#include "hw/acpi/aml-build.h" #include "hw/irq.h" #include "hw/isa/isa.h" #include "hw/qdev-properties.h" @@ -2768,6 +2770,85 @@ void isa_fdc_get_drive_max_chs(FloppyDriveType type, (*maxc)--; } +static Aml *build_fdinfo_aml(int idx, FloppyDriveType type) +{ + Aml *dev, *fdi; + uint8_t maxc, maxh, maxs; + + isa_fdc_get_drive_max_chs(type, &maxc, &maxh, &maxs); + + dev = aml_device("FLP%c", 'A' + idx); + + aml_append(dev, aml_name_decl("_ADR", aml_int(idx))); + + fdi = aml_package(16); + aml_append(fdi, aml_int(idx)); /* Drive Number */ + aml_append(fdi, + aml_int(cmos_get_fd_drive_type(type))); /* Device Type */ + /* + * the values below are the limits of the drive, and are thus independent + * of the inserted media + */ + aml_append(fdi, aml_int(maxc)); /* Maximum Cylinder Number */ + aml_append(fdi, aml_int(maxs)); /* Maximum Sector Number */ + aml_append(fdi, aml_int(maxh)); /* Maximum Head Number */ + /* + * SeaBIOS returns the below values for int 0x13 func 0x08 regardless of + * the drive type, so shall we + */ + aml_append(fdi, aml_int(0xAF)); /* disk_specify_1 */ + aml_append(fdi, aml_int(0x02)); /* disk_specify_2 */ + aml_append(fdi, aml_int(0x25)); /* disk_motor_wait */ + aml_append(fdi, aml_int(0x02)); /* disk_sector_siz */ + aml_append(fdi, aml_int(0x12)); /* disk_eot */ + aml_append(fdi, aml_int(0x1B)); /* disk_rw_gap */ + aml_append(fdi, aml_int(0xFF)); /* disk_dtl */ + aml_append(fdi, aml_int(0x6C)); /* disk_formt_gap */ + aml_append(fdi, aml_int(0xF6)); /* disk_fill */ + aml_append(fdi, aml_int(0x0F)); /* disk_head_sttl */ + aml_append(fdi, aml_int(0x08)); /* disk_motor_strt */ + + aml_append(dev, aml_name_decl("_FDI", fdi)); + return dev; +} + +static void fdc_isa_build_aml(ISADevice *isadev, Aml *scope) +{ + Aml *dev; + Aml *crs; + int i; + +#define ACPI_FDE_MAX_FD 4 + uint32_t fde_buf[5] = { + 0, 0, 0, 0, /* presence of floppy drives #0 - #3 */ + cpu_to_le32(2) /* tape presence (2 == never present) */ + }; + + crs = aml_resource_template(); + aml_append(crs, aml_io(AML_DECODE16, 0x03F2, 0x03F2, 0x00, 0x04)); + aml_append(crs, aml_io(AML_DECODE16, 0x03F7, 0x03F7, 0x00, 0x01)); + aml_append(crs, aml_irq_no_flags(6)); + aml_append(crs, + aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, 2)); + + dev = aml_device("FDC0"); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0700"))); + aml_append(dev, aml_name_decl("_CRS", crs)); + + for (i = 0; i < MIN(MAX_FD, ACPI_FDE_MAX_FD); i++) { + FloppyDriveType type = isa_fdc_get_drive_type(isadev, i); + + if (type < FLOPPY_DRIVE_TYPE_NONE) { + fde_buf[i] = cpu_to_le32(1); /* drive present */ + aml_append(dev, build_fdinfo_aml(i, type)); + } + } + aml_append(dev, aml_name_decl("_FDE", + aml_buffer(sizeof(fde_buf), (uint8_t *)fde_buf))); + + aml_append(scope, dev); +} + static const VMStateDescription vmstate_isa_fdc ={ .name = "fdc", .version_id = 2, @@ -2801,11 +2882,13 @@ static Property isa_fdc_properties[] = { static void isabus_fdc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); dc->realize = isabus_fdc_realize; dc->fw_name = "fdc"; dc->reset = fdctrl_external_reset_isa; dc->vmsd = &vmstate_isa_fdc; + isa->build_aml = fdc_isa_build_aml; device_class_set_props(dc, isa_fdc_properties); set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 900f786d08..45297d9a90 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -938,85 +938,6 @@ static void build_hpet_aml(Aml *table) aml_append(table, scope); } -static Aml *build_fdinfo_aml(int idx, FloppyDriveType type) -{ - Aml *dev, *fdi; - uint8_t maxc, maxh, maxs; - - isa_fdc_get_drive_max_chs(type, &maxc, &maxh, &maxs); - - dev = aml_device("FLP%c", 'A' + idx); - - aml_append(dev, aml_name_decl("_ADR", aml_int(idx))); - - fdi = aml_package(16); - aml_append(fdi, aml_int(idx)); /* Drive Number */ - aml_append(fdi, - aml_int(cmos_get_fd_drive_type(type))); /* Device Type */ - /* - * the values below are the limits of the drive, and are thus independent - * of the inserted media - */ - aml_append(fdi, aml_int(maxc)); /* Maximum Cylinder Number */ - aml_append(fdi, aml_int(maxs)); /* Maximum Sector Number */ - aml_append(fdi, aml_int(maxh)); /* Maximum Head Number */ - /* - * SeaBIOS returns the below values for int 0x13 func 0x08 regardless of - * the drive type, so shall we - */ - aml_append(fdi, aml_int(0xAF)); /* disk_specify_1 */ - aml_append(fdi, aml_int(0x02)); /* disk_specify_2 */ - aml_append(fdi, aml_int(0x25)); /* disk_motor_wait */ - aml_append(fdi, aml_int(0x02)); /* disk_sector_siz */ - aml_append(fdi, aml_int(0x12)); /* disk_eot */ - aml_append(fdi, aml_int(0x1B)); /* disk_rw_gap */ - aml_append(fdi, aml_int(0xFF)); /* disk_dtl */ - aml_append(fdi, aml_int(0x6C)); /* disk_formt_gap */ - aml_append(fdi, aml_int(0xF6)); /* disk_fill */ - aml_append(fdi, aml_int(0x0F)); /* disk_head_sttl */ - aml_append(fdi, aml_int(0x08)); /* disk_motor_strt */ - - aml_append(dev, aml_name_decl("_FDI", fdi)); - return dev; -} - -static Aml *build_fdc_device_aml(ISADevice *fdc) -{ - int i; - Aml *dev; - Aml *crs; - -#define ACPI_FDE_MAX_FD 4 - uint32_t fde_buf[5] = { - 0, 0, 0, 0, /* presence of floppy drives #0 - #3 */ - cpu_to_le32(2) /* tape presence (2 == never present) */ - }; - - dev = aml_device("FDC0"); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0700"))); - - crs = aml_resource_template(); - aml_append(crs, aml_io(AML_DECODE16, 0x03F2, 0x03F2, 0x00, 0x04)); - aml_append(crs, aml_io(AML_DECODE16, 0x03F7, 0x03F7, 0x00, 0x01)); - aml_append(crs, aml_irq_no_flags(6)); - aml_append(crs, - aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, 2)); - aml_append(dev, aml_name_decl("_CRS", crs)); - - for (i = 0; i < MIN(MAX_FD, ACPI_FDE_MAX_FD); i++) { - FloppyDriveType type = isa_fdc_get_drive_type(fdc, i); - - if (type < FLOPPY_DRIVE_TYPE_NONE) { - fde_buf[i] = cpu_to_le32(1); /* drive present */ - aml_append(dev, build_fdinfo_aml(i, type)); - } - } - aml_append(dev, aml_name_decl("_FDE", - aml_buffer(sizeof(fde_buf), (uint8_t *)fde_buf))); - - return dev; -} - static Aml *build_kbd_device_aml(void) { Aml *dev; @@ -1092,7 +1013,6 @@ static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge) static void build_isa_devices_aml(Aml *table) { - ISADevice *fdc = pc_find_fdc0(); VMBusBridge *vmbus_bridge = vmbus_bridge_find(); bool ambiguous; @@ -1101,9 +1021,6 @@ static void build_isa_devices_aml(Aml *table) aml_append(scope, build_kbd_device_aml()); aml_append(scope, build_mouse_device_aml()); - if (fdc) { - aml_append(scope, build_fdc_device_aml(fdc)); - } if (ambiguous) { error_report("Multiple ISA busses, unable to define IPMI ACPI data"); diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 28e48171d1..f32b9e47a3 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -1,4 +1,5 @@ stub-obj-y += blk-commit-all.o +stub-obj-y += cmos.o stub-obj-y += cpu-get-clock.o stub-obj-y += cpu-get-icount.o stub-obj-y += dump.o diff --git a/stubs/cmos.c b/stubs/cmos.c new file mode 100644 index 0000000000..416cbe4055 --- /dev/null +++ b/stubs/cmos.c @@ -0,0 +1,7 @@ +#include "qemu/osdep.h" +#include "hw/i386/pc.h" + +int cmos_get_fd_drive_type(FloppyDriveType fd0) +{ + return 0; +} From ffdf43edc351c1d125201a7bb8ee315d45a273c6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:18:57 +0200 Subject: [PATCH 1587/2595] floppy: make isa_fdc_get_drive_max_chs static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit acpi aml generator needs this, but it is in floppy code now so we can make the function static. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Reviewed-by: Philippe Mathieu-Daudé Acked-by: John Snow Message-Id: <20200619091905.21676-5-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/fdc.c | 4 ++-- include/hw/block/fdc.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 5244df6f91..f1da83f08e 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2747,8 +2747,8 @@ FloppyDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i) return isa->state.drives[i].drive; } -void isa_fdc_get_drive_max_chs(FloppyDriveType type, - uint8_t *maxc, uint8_t *maxh, uint8_t *maxs) +static void isa_fdc_get_drive_max_chs(FloppyDriveType type, uint8_t *maxc, + uint8_t *maxh, uint8_t *maxs) { const FDFormat *fdf; diff --git a/include/hw/block/fdc.h b/include/hw/block/fdc.h index c15ff4c623..5d71cf9722 100644 --- a/include/hw/block/fdc.h +++ b/include/hw/block/fdc.h @@ -16,7 +16,5 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, DriveInfo **fds, qemu_irq *fdc_tc); FloppyDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i); -void isa_fdc_get_drive_max_chs(FloppyDriveType type, - uint8_t *maxc, uint8_t *maxh, uint8_t *maxs); #endif From 89ed90e318847e27e64185fe6a370fc7c91e2165 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:18:58 +0200 Subject: [PATCH 1588/2595] floppy: move cmos_get_fd_drive_type() from pc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Acked-by: John Snow Message-Id: <20200619091905.21676-6-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/fdc.c | 26 +++++++++++++++++++++++++- hw/i386/pc.c | 25 ------------------------- include/hw/block/fdc.h | 1 + include/hw/i386/pc.h | 1 - 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index f1da83f08e..4f0921298b 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -32,7 +32,6 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/timer.h" -#include "hw/i386/pc.h" #include "hw/acpi/aml-build.h" #include "hw/irq.h" #include "hw/isa/isa.h" @@ -2812,6 +2811,31 @@ static Aml *build_fdinfo_aml(int idx, FloppyDriveType type) return dev; } +int cmos_get_fd_drive_type(FloppyDriveType fd0) +{ + int val; + + switch (fd0) { + case FLOPPY_DRIVE_TYPE_144: + /* 1.44 Mb 3"5 drive */ + val = 4; + break; + case FLOPPY_DRIVE_TYPE_288: + /* 2.88 Mb 3"5 drive */ + val = 5; + break; + case FLOPPY_DRIVE_TYPE_120: + /* 1.2 Mb 5"5 drive */ + val = 2; + break; + case FLOPPY_DRIVE_TYPE_NONE: + default: + val = 0; + break; + } + return val; +} + static void fdc_isa_build_aml(ISADevice *isadev, Aml *scope) { Aml *dev; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index d103b8c0ab..e78e32b41b 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -386,31 +386,6 @@ static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size) #define REG_EQUIPMENT_BYTE 0x14 -int cmos_get_fd_drive_type(FloppyDriveType fd0) -{ - int val; - - switch (fd0) { - case FLOPPY_DRIVE_TYPE_144: - /* 1.44 Mb 3"5 drive */ - val = 4; - break; - case FLOPPY_DRIVE_TYPE_288: - /* 2.88 Mb 3"5 drive */ - val = 5; - break; - case FLOPPY_DRIVE_TYPE_120: - /* 1.2 Mb 5"5 drive */ - val = 2; - break; - case FLOPPY_DRIVE_TYPE_NONE: - default: - val = 0; - break; - } - return val; -} - static void cmos_init_hd(ISADevice *s, int type_ofs, int info_ofs, int16_t cylinders, int8_t heads, int8_t sectors) { diff --git a/include/hw/block/fdc.h b/include/hw/block/fdc.h index 5d71cf9722..479cebc0a3 100644 --- a/include/hw/block/fdc.h +++ b/include/hw/block/fdc.h @@ -16,5 +16,6 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, DriveInfo **fds, qemu_irq *fdc_tc); FloppyDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i); +int cmos_get_fd_drive_type(FloppyDriveType fd0); #endif diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index e6135c34d6..dce1273c7d 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -178,7 +178,6 @@ typedef void (*cpu_set_smm_t)(int smm, void *arg); void pc_i8259_create(ISABus *isa_bus, qemu_irq *i8259_irqs); ISADevice *pc_find_fdc0(void); -int cmos_get_fd_drive_type(FloppyDriveType fd0); /* port92.c */ #define PORT92_A20_LINE "a20" From df0f3d134a92cbbe07ccbfc017f39ed2dbcc6a3f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:18:59 +0200 Subject: [PATCH 1589/2595] acpi: move aml builder code for i8042 (kbd+mouse) device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DSDT change: isa device order changes in case MI1 (ipmi) is present. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov Message-Id: <20200619091905.21676-7-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 39 --------------------------------------- hw/input/pckbd.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 45297d9a90..13113e83df 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -938,42 +938,6 @@ static void build_hpet_aml(Aml *table) aml_append(table, scope); } -static Aml *build_kbd_device_aml(void) -{ - Aml *dev; - Aml *crs; - - dev = aml_device("KBD"); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0303"))); - - aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); - - crs = aml_resource_template(); - aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01)); - aml_append(crs, aml_io(AML_DECODE16, 0x0064, 0x0064, 0x01, 0x01)); - aml_append(crs, aml_irq_no_flags(1)); - aml_append(dev, aml_name_decl("_CRS", crs)); - - return dev; -} - -static Aml *build_mouse_device_aml(void) -{ - Aml *dev; - Aml *crs; - - dev = aml_device("MOU"); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0F13"))); - - aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); - - crs = aml_resource_template(); - aml_append(crs, aml_irq_no_flags(12)); - aml_append(dev, aml_name_decl("_CRS", crs)); - - return dev; -} - static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge) { Aml *dev; @@ -1019,9 +983,6 @@ static void build_isa_devices_aml(Aml *table) Aml *scope = aml_scope("_SB.PCI0.ISA"); Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous); - aml_append(scope, build_kbd_device_aml()); - aml_append(scope, build_mouse_device_aml()); - if (ambiguous) { error_report("Multiple ISA busses, unable to define IPMI ACPI data"); } else if (!obj) { diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index 60a4130320..29d633ca94 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -26,6 +26,7 @@ #include "qemu/log.h" #include "hw/isa/isa.h" #include "migration/vmstate.h" +#include "hw/acpi/aml-build.h" #include "hw/input/ps2.h" #include "hw/irq.h" #include "hw/input/i8042.h" @@ -561,12 +562,42 @@ static void i8042_realizefn(DeviceState *dev, Error **errp) qemu_register_reset(kbd_reset, s); } +static void i8042_build_aml(ISADevice *isadev, Aml *scope) +{ + Aml *kbd; + Aml *mou; + Aml *crs; + + crs = aml_resource_template(); + aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01)); + aml_append(crs, aml_io(AML_DECODE16, 0x0064, 0x0064, 0x01, 0x01)); + aml_append(crs, aml_irq_no_flags(1)); + + kbd = aml_device("KBD"); + aml_append(kbd, aml_name_decl("_HID", aml_eisaid("PNP0303"))); + aml_append(kbd, aml_name_decl("_STA", aml_int(0xf))); + aml_append(kbd, aml_name_decl("_CRS", crs)); + + crs = aml_resource_template(); + aml_append(crs, aml_irq_no_flags(12)); + + mou = aml_device("MOU"); + aml_append(mou, aml_name_decl("_HID", aml_eisaid("PNP0F13"))); + aml_append(mou, aml_name_decl("_STA", aml_int(0xf))); + aml_append(mou, aml_name_decl("_CRS", crs)); + + aml_append(scope, kbd); + aml_append(scope, mou); +} + static void i8042_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); dc->realize = i8042_realizefn; dc->vmsd = &vmstate_kbd_isa; + isa->build_aml = i8042_build_aml; set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } From 0575c2fd6ddeba1fbe6e4dca959917895aa8ee31 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:19:00 +0200 Subject: [PATCH 1590/2595] acpi: factor out fw_cfg_add_acpi_dsdt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper function to add fw_cfg device, also move code to hw/i386/fw_cfg.c. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov Message-Id: <20200619091905.21676-8-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 24 +----------------------- hw/i386/fw_cfg.c | 28 ++++++++++++++++++++++++++++ hw/i386/fw_cfg.h | 1 + 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 13113e83df..19e9c298dc 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1802,30 +1802,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, /* create fw_cfg node, unconditionally */ { - /* when using port i/o, the 8-bit data register *always* overlaps - * with half of the 16-bit control register. Hence, the total size - * of the i/o region used is FW_CFG_CTL_SIZE; when using DMA, the - * DMA control register is located at FW_CFG_DMA_IO_BASE + 4 */ - uint8_t io_size = object_property_get_bool(OBJECT(x86ms->fw_cfg), - "dma_enabled", NULL) ? - ROUND_UP(FW_CFG_CTL_SIZE, 4) + sizeof(dma_addr_t) : - FW_CFG_CTL_SIZE; - scope = aml_scope("\\_SB.PCI0"); - dev = aml_device("FWCF"); - - aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); - - /* device present, functioning, decoding, not shown in UI */ - aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); - - crs = aml_resource_template(); - aml_append(crs, - aml_io(AML_DECODE16, FW_CFG_IO_BASE, FW_CFG_IO_BASE, 0x01, io_size) - ); - aml_append(dev, aml_name_decl("_CRS", crs)); - - aml_append(scope, dev); + fw_cfg_add_acpi_dsdt(scope, x86ms->fw_cfg); aml_append(dsdt, scope); } diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c index da60ada594..c55abfb01a 100644 --- a/hw/i386/fw_cfg.c +++ b/hw/i386/fw_cfg.c @@ -15,6 +15,7 @@ #include "qemu/osdep.h" #include "sysemu/numa.h" #include "hw/acpi/acpi.h" +#include "hw/acpi/aml-build.h" #include "hw/firmware/smbios.h" #include "hw/i386/fw_cfg.h" #include "hw/timer/hpet.h" @@ -179,3 +180,30 @@ void fw_cfg_build_feature_control(MachineState *ms, FWCfgState *fw_cfg) *val = cpu_to_le64(feature_control_bits | FEATURE_CONTROL_LOCKED); fw_cfg_add_file(fw_cfg, "etc/msr_feature_control", val, sizeof(*val)); } + +void fw_cfg_add_acpi_dsdt(Aml *scope, FWCfgState *fw_cfg) +{ + /* + * when using port i/o, the 8-bit data register *always* overlaps + * with half of the 16-bit control register. Hence, the total size + * of the i/o region used is FW_CFG_CTL_SIZE; when using DMA, the + * DMA control register is located at FW_CFG_DMA_IO_BASE + 4 + */ + Object *obj = OBJECT(fw_cfg); + uint8_t io_size = object_property_get_bool(obj, "dma_enabled", NULL) ? + ROUND_UP(FW_CFG_CTL_SIZE, 4) + sizeof(dma_addr_t) : + FW_CFG_CTL_SIZE; + Aml *dev = aml_device("FWCF"); + Aml *crs = aml_resource_template(); + + aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); + + /* device present, functioning, decoding, not shown in UI */ + aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); + + aml_append(crs, + aml_io(AML_DECODE16, FW_CFG_IO_BASE, FW_CFG_IO_BASE, 0x01, io_size)); + + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} diff --git a/hw/i386/fw_cfg.h b/hw/i386/fw_cfg.h index 9e74278779..275f15c1c5 100644 --- a/hw/i386/fw_cfg.h +++ b/hw/i386/fw_cfg.h @@ -25,5 +25,6 @@ FWCfgState *fw_cfg_arch_create(MachineState *ms, uint16_t apic_id_limit); void fw_cfg_build_smbios(MachineState *ms, FWCfgState *fw_cfg); void fw_cfg_build_feature_control(MachineState *ms, FWCfgState *fw_cfg); +void fw_cfg_add_acpi_dsdt(Aml *scope, FWCfgState *fw_cfg); #endif From 13371f9bf44c294b0cbc58f10c21fa0c82a2c7d8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:19:01 +0200 Subject: [PATCH 1591/2595] acpi: simplify build_isa_devices_aml() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit x86 machines can have a single ISA bus only. Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200619091905.21676-9-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 19e9c298dc..d27cecc877 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -979,18 +979,14 @@ static void build_isa_devices_aml(Aml *table) { VMBusBridge *vmbus_bridge = vmbus_bridge_find(); bool ambiguous; - - Aml *scope = aml_scope("_SB.PCI0.ISA"); Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous); + Aml *scope; - if (ambiguous) { - error_report("Multiple ISA busses, unable to define IPMI ACPI data"); - } else if (!obj) { - error_report("No ISA bus, unable to define IPMI ACPI data"); - } else { - build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA"); - isa_build_aml(ISA_BUS(obj), scope); - } + assert(obj && !ambiguous); + + scope = aml_scope("_SB.PCI0.ISA"); + build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA"); + isa_build_aml(ISA_BUS(obj), scope); if (vmbus_bridge) { aml_append(scope, build_vmbus_device_aml(vmbus_bridge)); From d23f78349fd8048e137cc96f99cb56110212bfe5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:19:02 +0200 Subject: [PATCH 1592/2595] acpi: drop serial/parallel enable bits from dsdt The _STA methods for COM+LPT used to reference them, but that isn't the case any more. piix4 DSDT changes: Scope (_SB.PCI0) { Device (ISA) { Name (_ADR, 0x00010000) // _ADR: Address OperationRegion (P40C, PCI_Config, 0x60, 0x04) - Field (^PX13.P13C, AnyAcc, NoLock, Preserve) - { - Offset (0x5F), - , 7, - LPEN, 1, - Offset (0x67), - , 3, - CAEN, 1, - , 3, - CBEN, 1 - } } } ich9 DSDT changes: Scope (_SB.PCI0) { Device (ISA) { Name (_ADR, 0x001F0000) // _ADR: Address OperationRegion (PIRQ, PCI_Config, 0x60, 0x0C) OperationRegion (LPCD, PCI_Config, 0x80, 0x02) Field (LPCD, AnyAcc, NoLock, Preserve) { COMA, 3, , 1, COMB, 3, Offset (0x01), LPTD, 2 } - - OperationRegion (LPCE, PCI_Config, 0x82, 0x02) - Field (LPCE, AnyAcc, NoLock, Preserve) - { - CAEN, 1, - CBEN, 1, - LPEN, 1 - } } } Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Message-Id: <20200619091905.21676-10-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index d27cecc877..ffbdbee51a 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1360,15 +1360,6 @@ static void build_q35_isa_bridge(Aml *table) aml_append(field, aml_named_field("LPTD", 2)); aml_append(dev, field); - aml_append(dev, aml_operation_region("LPCE", AML_PCI_CONFIG, - aml_int(0x82), 0x02)); - /* enable bits */ - field = aml_field("LPCE", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE); - aml_append(field, aml_named_field("CAEN", 1)); - aml_append(field, aml_named_field("CBEN", 1)); - aml_append(field, aml_named_field("LPEN", 1)); - aml_append(dev, field); - aml_append(scope, dev); aml_append(table, scope); } @@ -1392,7 +1383,6 @@ static void build_piix4_isa_bridge(Aml *table) { Aml *dev; Aml *scope; - Aml *field; scope = aml_scope("_SB.PCI0"); dev = aml_device("ISA"); @@ -1401,19 +1391,6 @@ static void build_piix4_isa_bridge(Aml *table) /* PIIX PCI to ISA irq remapping */ aml_append(dev, aml_operation_region("P40C", AML_PCI_CONFIG, aml_int(0x60), 0x04)); - /* enable bits */ - field = aml_field("^PX13.P13C", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE); - /* Offset(0x5f),, 7, */ - aml_append(field, aml_reserved_field(0x2f8)); - aml_append(field, aml_reserved_field(7)); - aml_append(field, aml_named_field("LPEN", 1)); - /* Offset(0x67),, 3, */ - aml_append(field, aml_reserved_field(0x38)); - aml_append(field, aml_reserved_field(3)); - aml_append(field, aml_named_field("CAEN", 1)); - aml_append(field, aml_reserved_field(3)); - aml_append(field, aml_named_field("CBEN", 1)); - aml_append(dev, field); aml_append(scope, dev); aml_append(table, scope); From 9b3bff1f75e32c8e7e43f54d42a2dbbf3a1631d5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:19:03 +0200 Subject: [PATCH 1593/2595] acpi: drop build_piix4_pm() The _SB.PCI0.PX13.P13C opregion (holds isa device enable bits) is not used any more, remove it from DSDT. piix4 DSDT changes: Scope (_SB.PCI0) { - Device (PX13) - { - Name (_ADR, 0x00010003) // _ADR: Address - OperationRegion (P13C, PCI_Config, Zero, 0xFF) - } - } - - Scope (_SB.PCI0) - { Device (ISA) { Name (_ADR, 0x00010000) // _ADR: Address OperationRegion (P40C, PCI_Config, 0x60, 0x04) } } Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedow Message-Id: <20200619091905.21676-11-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index ffbdbee51a..59f1b4d890 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1364,21 +1364,6 @@ static void build_q35_isa_bridge(Aml *table) aml_append(table, scope); } -static void build_piix4_pm(Aml *table) -{ - Aml *dev; - Aml *scope; - - scope = aml_scope("_SB.PCI0"); - dev = aml_device("PX13"); - aml_append(dev, aml_name_decl("_ADR", aml_int(0x00010003))); - - aml_append(dev, aml_operation_region("P13C", AML_PCI_CONFIG, - aml_int(0x00), 0xff)); - aml_append(scope, dev); - aml_append(table, scope); -} - static void build_piix4_isa_bridge(Aml *table) { Aml *dev; @@ -1530,7 +1515,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, sb_scope); build_hpet_aml(dsdt); - build_piix4_pm(dsdt); build_piix4_isa_bridge(dsdt); build_isa_devices_aml(dsdt); build_piix4_pci_hotplug(dsdt); From e0d1a82b126a9a60b56aaf3991901683203534d8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:19:04 +0200 Subject: [PATCH 1594/2595] acpi: q35: drop _SB.PCI0.ISA.LPCD opregion. Seems to be unused. ich9 DSDT changes: Scope (_SB.PCI0) { Device (ISA) { Name (_ADR, 0x001F0000) // _ADR: Address OperationRegion (PIRQ, PCI_Config, 0x60, 0x0C) - OperationRegion (LPCD, PCI_Config, 0x80, 0x02) - Field (LPCD, AnyAcc, NoLock, Preserve) - { - COMA, 3, - , 1, - COMB, 3, - Offset (0x01), - LPTD, 2 - } } } Signed-off-by: Gerd Hoffmann Reviewed-by: Igor Mammedov Message-Id: <20200619091905.21676-12-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 59f1b4d890..378515df66 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1340,7 +1340,6 @@ static void build_q35_isa_bridge(Aml *table) { Aml *dev; Aml *scope; - Aml *field; scope = aml_scope("_SB.PCI0"); dev = aml_device("ISA"); @@ -1350,16 +1349,6 @@ static void build_q35_isa_bridge(Aml *table) aml_append(dev, aml_operation_region("PIRQ", AML_PCI_CONFIG, aml_int(0x60), 0x0C)); - aml_append(dev, aml_operation_region("LPCD", AML_PCI_CONFIG, - aml_int(0x80), 0x02)); - field = aml_field("LPCD", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE); - aml_append(field, aml_named_field("COMA", 3)); - aml_append(field, aml_reserved_field(1)); - aml_append(field, aml_named_field("COMB", 3)); - aml_append(field, aml_reserved_field(1)); - aml_append(field, aml_named_field("LPTD", 2)); - aml_append(dev, field); - aml_append(scope, dev); aml_append(table, scope); } From 93dd625f8bf73788058d6fabf7b21b727293166c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 19 Jun 2020 11:19:05 +0200 Subject: [PATCH 1595/2595] tests/acpi: update expected data files Signed-off-by: Gerd Hoffmann Message-Id: <20200619091905.21676-13-kraxel@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/pc/DSDT | Bin 5014 -> 4934 bytes tests/data/acpi/pc/DSDT.acpihmat | Bin 6338 -> 6258 bytes tests/data/acpi/pc/DSDT.bridge | Bin 6873 -> 6793 bytes tests/data/acpi/pc/DSDT.cphp | Bin 5477 -> 5397 bytes tests/data/acpi/pc/DSDT.dimmpxm | Bin 6667 -> 6587 bytes tests/data/acpi/pc/DSDT.ipmikcs | Bin 5086 -> 5006 bytes tests/data/acpi/pc/DSDT.memhp | Bin 6373 -> 6293 bytes tests/data/acpi/pc/DSDT.numamem | Bin 5020 -> 4940 bytes tests/data/acpi/q35/DSDT | Bin 7752 -> 7678 bytes tests/data/acpi/q35/DSDT.acpihmat | Bin 9076 -> 9002 bytes tests/data/acpi/q35/DSDT.bridge | Bin 7769 -> 7695 bytes tests/data/acpi/q35/DSDT.cphp | Bin 8215 -> 8141 bytes tests/data/acpi/q35/DSDT.dimmpxm | Bin 9405 -> 9331 bytes tests/data/acpi/q35/DSDT.ipmibt | Bin 7827 -> 7753 bytes tests/data/acpi/q35/DSDT.memhp | Bin 9111 -> 9037 bytes tests/data/acpi/q35/DSDT.mmio64 | Bin 8882 -> 8808 bytes tests/data/acpi/q35/DSDT.numamem | Bin 7758 -> 7684 bytes tests/data/acpi/q35/DSDT.tis | Bin 8357 -> 8283 bytes 18 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT index 384a82dbb3cb0e9f47db6f4d08945631c2b72b56..6d0aaf729ac7d64cf966621adf276534de5cc555 100644 GIT binary patch delta 62 zcmbQHeoT$aCDoQ7eL^rC%>49{BR537k=rgeU1i1P!GFUJ$J3E3H%+5|g JYOx!m5C9(`8>;{S diff --git a/tests/data/acpi/pc/DSDT.acpihmat b/tests/data/acpi/pc/DSDT.acpihmat index 47ddfdb027b06dc2daa46be711c3f4640ce68320..2e5e02400b1bd2842989d395c573fc593f45503b 100644 GIT binary patch delta 63 zcmX?P_{o6FCDZZv3Dbv7^9k+UVN}qe1Nm3L3ERpXRu>DN4%p;5D!qEA-W;J R#K4(}D}jq;^E5^saR3*D4`~1Z delta 123 zcmexlaLAC$CDF-B8Wz4&0K_yA{5gXkv7fCxilj(A6xARcB0MuzBy z07GMECI+tm0uHQ5%A8py>oQ7eL^rC%>49{BR537k=rgeU1i1P!GFUJ$J3E3H%+5|g KYO@=ojyM2sP8?SN diff --git a/tests/data/acpi/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge index d1e2fa9fb8c75160fc1fa46deed6a6a9cb515559..623c4c03585c47d4d28adc611823b7cce8f4a5c7 100644 GIT binary patch delta 63 zcmca<+G)z=66_MvDaF9R$gz=2j8RQZFFx2QKET=2Ai7D)GuSbnBi_*^hzBUo5Zw@9 RV&KfgmB7Wac^ad$BmnX}4$S}n delta 123 zcmeA)y=ltj66_LkQ;LCs@%%oQ7eL^rC%>49{BR537k=rgeU1i1P!GFUJ$J3E3H%+5|g KYO@=ovm^kEs~o!k diff --git a/tests/data/acpi/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp index 54f481faf1e336c0bbf5e774cd67220fe06e951b..e0a43ccdadae150c0f39599c85e4e21ed8fff2a4 100644 GIT binary patch delta 63 zcmaE=HC2ntCDDN4%p;5D!qEA-W;J R#K4(}D}jq;^EAfu!T{rs4-5bR delta 123 zcmbQL^;CoQ7eL^rC%>49{BR537k=rgeU1i1P!GFUJ$J3E3H%+5|g KYO@>Td0_x-S{(WS diff --git a/tests/data/acpi/pc/DSDT.dimmpxm b/tests/data/acpi/pc/DSDT.dimmpxm index 5d98016ae571cde04ff96d58212e0faf9aaf50e6..21eb065a0ee3bd96f1a2e7601aa83fefa833349a 100644 GIT binary patch delta 63 zcmeA+*=@|_66_MPTatl+QDGyO7^9k+UVN}qe1Nm3L3ERpXRu>DN4%p;5D!qEA-W;J R#K4(}D}jq;^EAd%2>|(!4=4Zt delta 123 zcmdmO+-<_;66_MfEycjV_-rGW7^A7GUVN}qe1Nm3L3ER3K!l+&N4%p;5Dzm0BSUmU zfT6K769dogG08W@jfL Kwb_laR004i*&G%C diff --git a/tests/data/acpi/pc/DSDT.ipmikcs b/tests/data/acpi/pc/DSDT.ipmikcs index 57b78358744a5bb13639ccddb887be2721240807..b8f08f266b5735fe6967d4e105ee6b3662dad7e6 100644 GIT binary patch delta 88 zcmcbo-lxvx66_MvC(OXW7`%~7jL}?8FFx2QKET=2Ai7D)GuSbnBi_*^hzBUo5Zw@9 jV&KfgmB7U!;3lKb3{wbFHMxz+Yw}9Q`ogG08W@jfL eCEzBb&kVD~GuSbH@_fdJlOq{DHa9Tw2?794F(Zip diff --git a/tests/data/acpi/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp index 8cb90ef14e13be85995c6fe3d3f6d12f4d939504..9a9418f4bde5fb18883c244ea956122e371ff01a 100644 GIT binary patch delta 63 zcmaEAIMtBLCD R69Z=^t^_WY&C?kD#Q_+=51Ie~ delta 123 zcmbPg_|%ZgCDoQ7eL^rC%>49{BR537k=rgeU1i1P!GFUJ$J3E3H%+5|g KYO@=ozc>JL)EtNa diff --git a/tests/data/acpi/pc/DSDT.numamem b/tests/data/acpi/pc/DSDT.numamem index f194bc639482eb839a875d493857526f85f1a9e0..6eec385c2ec00544c6eaa7e19d32b2ccd5a51915 100644 GIT binary patch delta 63 zcmbQEenySUCD@oA7^9k+UVN}qe1Nm3L3ERpXRu>DN4%p;5D!qEA-W;J R#K4(}D}jq;^E5^_Apr0P4vzo; delta 123 zcmX@3HboQ7eL^rC%>49{BR537k=rgeU1i1P!GFUJ$J3E3H%+5|g KYO@<7n-BmV+#7uW diff --git a/tests/data/acpi/q35/DSDT b/tests/data/acpi/q35/DSDT index 6a5e4dd85a7d9a95f7ad0fb95e6a4fa7a8d91adb..e63676d7a63afec714debeb465ee478ea4714337 100644 GIT binary patch delta 63 zcmX?M^Us>gCDB|5BVXhFs delta 152 zcmexoeZq#zCDgNCodb_^bFp7k5NGe0GZ(>WdHyG diff --git a/tests/data/acpi/q35/DSDT.acpihmat b/tests/data/acpi/q35/DSDT.acpihmat index c1dd7773f3386a946fcb4a9a3bf9ad3a33ddbbe9..cd97b819824e4140d087e465d179b71775d6a494 100644 GIT binary patch delta 63 zcmez3w#tpmCD(TV^lo)6ss delta 152 zcmZ4G_Qj3MCDgNCodb_^bFp7kI_dF0FK)wf&c&j diff --git a/tests/data/acpi/q35/DSDT.bridge b/tests/data/acpi/q35/DSDT.bridge index 2ef1e894a35b9e85fe07e2678bd2456f5ec40dc6..8b0fb497dbbaeba18e9d0e1503de4396f1c230b0 100644 GIT binary patch delta 63 zcmca<({ID&66_MfFUP>Z=(Uk+KBJnNUVN}qe1Nm3L3ERpXRu>DN4%p;5Dx=`JVSIt SfM-x36ITKk&t^#`2N?hd0uLns delta 152 zcmeCTxoN}Y66_KZDaXLTShA68K4ZNDyIy>-Q+$B4r$Ka+Gn;3yV?0N^qe~DE1A{z6 zbVGn=P#_am0vAtogHM373lmoZ7gKbjB#6!6?CFZj061qP$^ZZW diff --git a/tests/data/acpi/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp index 74e86176e5fec46e660c567acf8fbcf08a14bdfb..d9bb414e9bf15d9b9149f38c9bb5d8b993f88650 100644 GIT binary patch delta 63 zcmbR4aMqs7CDcIWDYg)R delta 152 zcmX?WKiz@LCD(^b diff --git a/tests/data/acpi/q35/DSDT.dimmpxm b/tests/data/acpi/q35/DSDT.dimmpxm index 4bf8e9d64b04f9f805047d6850c2dd0086970445..29f19b22a38f9d8e7dc9870f0c1aa3d4470643ff 100644 GIT binary patch delta 63 zcmdn%`PqZZCDgNCodb_^bFp7k8!FJ0DIsiq5uE@ diff --git a/tests/data/acpi/q35/DSDT.ipmibt b/tests/data/acpi/q35/DSDT.ipmibt index 38723daef80421ea528b2ad2d411e7357df43956..e8dea1ea42af765babcb747af998b0d912abdcbd 100644 GIT binary patch delta 88 zcmbPid(wu>CDgNC>!z=rhA?^bBTljGwH{6gT-1qxa@crUTLdx=1KU diff --git a/tests/data/acpi/q35/DSDT.memhp b/tests/data/acpi/q35/DSDT.memhp index 98328d1c4197ab19a71de7f3f18e2985f4910f45..dca76db15b943122efd5c200cb54ce3dbc97a55f 100644 GIT binary patch delta 63 zcmbR4e%6i4CDJ$Me+z<`` delta 152 zcmX@>Hr<`eCDGZg?Wst_;$ delta 152 zcmaFivdNXpCDgNCodb_^bFp7kFiSu0Gx{@)c^nh diff --git a/tests/data/acpi/q35/DSDT.numamem b/tests/data/acpi/q35/DSDT.numamem index cf3fde3449bc8e9bbe683b936cf9866590b0ef82..737325dc3082fdf06283857811f6f5174e0ff2a9 100644 GIT binary patch delta 63 zcmX?S(_+Kr66_MfBFDhM7_yOTKBJnNUVN}qe1Nm3L3ERpXRu>DN4%p;5Dx=`JVSIt SfM-x36ITKk&t^#`QyBmOFb@L& delta 152 zcmZp%IcLM=66_M-Q+$B4r$Ka+Gn;3yV?0N^qe~DE1A{z6 zbVGn=P#_am0vAtogHM373lmoZ7gKbjB#6!6?CJ#qjlZ4es( delta 152 zcmccZu+)*uCD0GBu=zyJUM From e27e1e63ce075b87f03d3257d8f30cf7c4287340 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 22 Jun 2020 16:06:18 +0200 Subject: [PATCH 1596/2595] acpi: Some build_tpm2() code reshape Remove any reference to Acpi20TPM2 and adopt an implementation similar to build_ghes_v2(). Signed-off-by: Eric Auger Suggested-by: Igor Mammedov Reviewed-by: Stefan Berger Tested-by: Stefan Berger Reviewed-by: Igor Mammedov Message-Id: <20200622140620.17229-2-eric.auger@redhat.com> Tested-by: Ard Biesheuvel Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/aml-build.c | 51 +++++++++++++++++++++++-------------- include/hw/acpi/acpi-defs.h | 18 ------------- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 2cb7b991ef..f6fbc9b95d 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1878,48 +1878,61 @@ build_hdr: "FACP", tbl->len - fadt_start, f->rev, oem_id, oem_table_id); } +/* + * build_tpm2 - Build the TPM2 table as specified in + * table 7: TCG Hardware Interface Description Table Format for TPM 2.0 + * of TCG ACPI Specification, Family “1.2” and “2.0”, Version 1.2, Rev 8 + */ void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) { - Acpi20TPM2 *tpm2_ptr = acpi_data_push(table_data, sizeof(AcpiTableHeader)); - unsigned log_addr_size = sizeof(tpm2_ptr->log_area_start_address); - unsigned log_addr_offset = - (char *)&tpm2_ptr->log_area_start_address - table_data->data; uint8_t start_method_params[12] = {}; + unsigned log_addr_offset, tpm2_start; + uint64_t control_area_start_address; TPMIf *tpmif = tpm_find(); + uint32_t start_method; + void *tpm2_ptr; - /* platform class */ + tpm2_start = table_data->len; + tpm2_ptr = acpi_data_push(table_data, sizeof(AcpiTableHeader)); + + /* Platform Class */ build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2); - /* reserved */ + /* Reserved */ build_append_int_noprefix(table_data, 0, 2); if (TPM_IS_TIS_ISA(tpmif) || TPM_IS_TIS_SYSBUS(tpmif)) { - /* address of control area */ - build_append_int_noprefix(table_data, 0, 8); - /* start method */ - build_append_int_noprefix(table_data, TPM2_START_METHOD_MMIO, 4); + control_area_start_address = 0; + start_method = TPM2_START_METHOD_MMIO; } else if (TPM_IS_CRB(tpmif)) { - build_append_int_noprefix(table_data, TPM_CRB_ADDR_CTRL, 8); - build_append_int_noprefix(table_data, TPM2_START_METHOD_CRB, 4); + control_area_start_address = TPM_CRB_ADDR_CTRL; + start_method = TPM2_START_METHOD_CRB; } else { - g_warn_if_reached(); + g_assert_not_reached(); } + /* Address of Control Area */ + build_append_int_noprefix(table_data, control_area_start_address, 8); + /* Start Method */ + build_append_int_noprefix(table_data, start_method, 4); - /* platform specific parameters */ - g_array_append_vals(table_data, &start_method_params, 12); + /* Platform Specific Parameters */ + g_array_append_vals(table_data, &start_method_params, + ARRAY_SIZE(start_method_params)); - /* log area minimum length */ + /* Log Area Minimum Length */ build_append_int_noprefix(table_data, TPM_LOG_AREA_MINIMUM_SIZE, 4); acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE); bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1, false); - /* log area start address to be filled by Guest linker */ + log_addr_offset = table_data->len; + + /* Log Area Start Address to be filled by Guest linker */ build_append_int_noprefix(table_data, 0, 8); bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, - log_addr_offset, log_addr_size, + log_addr_offset, 8, ACPI_BUILD_TPMLOG_FILE, 0); build_header(linker, table_data, - (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL); + tpm2_ptr, "TPM2", table_data->len - tpm2_start, 4, NULL, NULL); } /* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors */ diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 3be9ab5049..38a42f409a 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -465,24 +465,6 @@ struct Acpi20Tcpa { } QEMU_PACKED; typedef struct Acpi20Tcpa Acpi20Tcpa; -/* - * TPM2 - * - * Following Version 1.2, Revision 8 of specs: - * https://trustedcomputinggroup.org/tcg-acpi-specification/ - */ -struct Acpi20TPM2 { - ACPI_TABLE_HEADER_DEF - uint16_t platform_class; - uint16_t reserved; - uint64_t control_area_address; - uint32_t start_method; - uint8_t start_method_params[12]; - uint32_t log_area_minimum_length; - uint64_t log_area_start_address; -} QEMU_PACKED; -typedef struct Acpi20TPM2 Acpi20TPM2; - /* DMAR - DMA Remapping table r2.2 */ struct AcpiTableDmar { ACPI_TABLE_HEADER_DEF From 5ab540e9b79eb902267b0ddf827c9f7c99332f59 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 22 Jun 2020 16:06:19 +0200 Subject: [PATCH 1597/2595] arm/acpi: Add the TPM2.0 device under the DSDT In case it is dynamically instantiated, add the TPM 2.0 device object under the DSDT table in the ACPI namespace. Its HID is MSFT0101 while its current resource settings (CRS) property is initialized with the guest physical address and MMIO size of the device. Signed-off-by: Eric Auger Reviewed-by: Stefan Berger Reviewed-by: Igor Mammedov Message-Id: <20200622140620.17229-3-eric.auger@redhat.com> Tested-by: Ard Biesheuvel Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/virt-acpi-build.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index ca31f70f7f..1384a2cf2a 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -46,6 +46,7 @@ #include "hw/pci/pci.h" #include "hw/arm/virt.h" #include "hw/mem/nvdimm.h" +#include "hw/platform-bus.h" #include "sysemu/numa.h" #include "sysemu/reset.h" #include "sysemu/tpm.h" @@ -364,6 +365,38 @@ static void acpi_dsdt_add_power_button(Aml *scope) aml_append(scope, dev); } +static void acpi_dsdt_add_tpm(Aml *scope, VirtMachineState *vms) +{ + PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev); + hwaddr pbus_base = vms->memmap[VIRT_PLATFORM_BUS].base; + SysBusDevice *sbdev = SYS_BUS_DEVICE(tpm_find()); + MemoryRegion *sbdev_mr; + hwaddr tpm_base; + + if (!sbdev) { + return; + } + + tpm_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); + assert(tpm_base != -1); + + tpm_base += pbus_base; + + sbdev_mr = sysbus_mmio_get_region(sbdev, 0); + + Aml *dev = aml_device("TPM0"); + aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + Aml *crs = aml_resource_template(); + aml_append(crs, + aml_memory32_fixed(tpm_base, + (uint32_t)memory_region_size(sbdev_mr), + AML_READ_WRITE)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + static void build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { @@ -762,6 +795,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) } acpi_dsdt_add_power_button(scope); + acpi_dsdt_add_tpm(scope, vms); aml_append(dsdt, scope); From 56172c4ccdbbfae3aded3baecd6148935fac39a9 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 22 Jun 2020 16:06:20 +0200 Subject: [PATCH 1598/2595] docs/specs/tpm: ACPI boot now supported for TPM/ARM ACPI boot now is supported. Let's remove the comment saying it is not. Signed-off-by: Eric Auger Reviewed-by: Stefan Berger Reviewed-by: Igor Mammedov Message-Id: <20200622140620.17229-4-eric.auger@redhat.com> Tested-by: Ard Biesheuvel Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/specs/tpm.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst index 5e61238bc5..eeeb93730a 100644 --- a/docs/specs/tpm.rst +++ b/docs/specs/tpm.rst @@ -346,8 +346,6 @@ In case an Arm virt machine is emulated, use the following command line: -drive if=pflash,format=raw,file=flash0.img,readonly \ -drive if=pflash,format=raw,file=flash1.img - On Arm, ACPI boot with TPM is not yet supported. - In case SeaBIOS is used as firmware, it should show the TPM menu item after entering the menu with 'ESC'. From 8d19371593dedda64622bbcec8f81d8d8cee5e76 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz Date: Mon, 22 Jun 2020 23:50:44 +0000 Subject: [PATCH 1599/2595] Stop vhost-user sending uninitialized mmap_offsets Prior to this change, the vhost_user_fill_msg_region function filled out all elements of the VhostUserMemoryRegion struct except the mmap_offset. This function is often called on uninitialized structs, which are then copied into VHOST_USER_SET_MEM_TABLE and VHOST_USER_ADD/REM_MEM_REG messages. In some cases, where the mmap_offset was not needed, it was left uninitialized, causing QEMU to send the backend uninitialized data, which Coverity flagged as a series of issues. This change augments the vhost_user_fill_msg_region API, adding a mmap_offset paramenter, forcing the caller to initialize mmap_offset. Fixes: ece99091c2d0aeb23734289a50ef2ff4e0a08929 Fixes: f1aeb14b0809e313c74244d838645ed25e85ea63 Reported-by: Coverity (CIDs 1429802, 1429803 and 1429804) Suggested-by: Peter Maydell Signed-off-by: Raphael Norwitz Message-Id: <1592650156-25845-1-git-send-email-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Peter Maydell Reviewed-by: Stefan Hajnoczi --- hw/virtio/vhost-user.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 4d6cd4e58a..31231218dc 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -460,12 +460,14 @@ static MemoryRegion *vhost_user_get_mr_data(uint64_t addr, ram_addr_t *offset, } static void vhost_user_fill_msg_region(VhostUserMemoryRegion *dst, - struct vhost_memory_region *src) + struct vhost_memory_region *src, + uint64_t mmap_offset) { assert(src != NULL && dst != NULL); dst->userspace_addr = src->userspace_addr; dst->memory_size = src->memory_size; dst->guest_phys_addr = src->guest_phys_addr; + dst->mmap_offset = mmap_offset; } static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, @@ -500,9 +502,8 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, error_report("Failed preparing vhost-user memory table msg"); return -1; } - vhost_user_fill_msg_region(®ion_buffer, reg); + vhost_user_fill_msg_region(®ion_buffer, reg, offset); msg->payload.memory.regions[*fd_num] = region_buffer; - msg->payload.memory.regions[*fd_num].mmap_offset = offset; fds[(*fd_num)++] = fd; } else if (track_ramblocks) { u->region_rb_offset[i] = 0; @@ -649,7 +650,7 @@ static int send_remove_regions(struct vhost_dev *dev, if (fd > 0) { msg->hdr.request = VHOST_USER_REM_MEM_REG; - vhost_user_fill_msg_region(®ion_buffer, shadow_reg); + vhost_user_fill_msg_region(®ion_buffer, shadow_reg, 0); msg->payload.mem_reg.region = region_buffer; if (vhost_user_write(dev, msg, &fd, 1) < 0) { @@ -709,9 +710,8 @@ static int send_add_regions(struct vhost_dev *dev, u->region_rb[reg_idx] = mr->ram_block; } msg->hdr.request = VHOST_USER_ADD_MEM_REG; - vhost_user_fill_msg_region(®ion_buffer, reg); + vhost_user_fill_msg_region(®ion_buffer, reg, offset); msg->payload.mem_reg.region = region_buffer; - msg->payload.mem_reg.region.mmap_offset = offset; if (vhost_user_write(dev, msg, &fd, 1) < 0) { return -1; From 0affda043675c7619248a924a89bfd3781759f63 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Tue, 16 Jun 2020 12:31:39 +0000 Subject: [PATCH 1600/2595] Rename use_acpi_pci_hotplug to more appropriate use_acpi_hotplug_bridge Currently, the option use_acpi_pci_hotplug is being used to control device hotplug capability using ACPI for slots of cold plugged bridges. Hence, we are renaming this option to better reflect what it actually does. Signed-off-by: Ani Sinha Message-Id: <1592310699-58916-1-git-send-email-ani.sinha@nutanix.com> Reviewed-by: Igor Mammedov Signed-off-by: Ani Sinha Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/piix4.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 1262abc77a..630ca6ec87 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -77,7 +77,7 @@ typedef struct PIIX4PMState { Notifier powerdown_notifier; AcpiPciHpState acpi_pci_hotplug; - bool use_acpi_pci_hotplug; + bool use_acpi_hotplug_bridge; uint8_t disable_s3; uint8_t disable_s4; @@ -204,16 +204,17 @@ static const VMStateDescription vmstate_pci_status = { } }; -static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id) +static bool vmstate_test_use_acpi_hotplug_bridge(void *opaque, int version_id) { PIIX4PMState *s = opaque; - return s->use_acpi_pci_hotplug; + return s->use_acpi_hotplug_bridge; } -static bool vmstate_test_no_use_acpi_pci_hotplug(void *opaque, int version_id) +static bool vmstate_test_no_use_acpi_hotplug_bridge(void *opaque, + int version_id) { PIIX4PMState *s = opaque; - return !s->use_acpi_pci_hotplug; + return !s->use_acpi_hotplug_bridge; } static bool vmstate_test_use_memhp(void *opaque) @@ -290,11 +291,11 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_STRUCT_TEST( acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], PIIX4PMState, - vmstate_test_no_use_acpi_pci_hotplug, + vmstate_test_no_use_acpi_hotplug_bridge, 2, vmstate_pci_status, struct AcpiPciHpPciStatus), VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState, - vmstate_test_use_acpi_pci_hotplug), + vmstate_test_use_acpi_hotplug_bridge), VMSTATE_END_OF_LIST() }, .subsections = (const VMStateDescription*[]) { @@ -530,7 +531,7 @@ I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, s->smi_irq = smi_irq; s->smm_enabled = smm_enabled; if (xen_enabled()) { - s->use_acpi_pci_hotplug = false; + s->use_acpi_hotplug_bridge = false; } pci_realize_and_unref(pci_dev, bus, &error_fatal); @@ -595,7 +596,7 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe); acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent, - s->use_acpi_pci_hotplug); + s->use_acpi_hotplug_bridge); s->cpu_hotplug_legacy = true; object_property_add_bool(OBJECT(s), "cpu-hotplug-legacy", @@ -633,7 +634,7 @@ static Property piix4_pm_properties[] = { DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0), DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2), DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState, - use_acpi_pci_hotplug, true), + use_acpi_hotplug_bridge, true), DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState, acpi_memory_hotplug.is_enabled, true), DEFINE_PROP_END_OF_LIST(), From a816f2d6b801061c3fee44f9162607abcb43123d Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 11 Jun 2020 15:40:11 +0200 Subject: [PATCH 1601/2595] spapr: Simplify some warning printing paths in spapr_caps.c We obviously only want to print a warning in these cases, but this is done in a rather convoluted manner. Just use warn_report() instead. Signed-off-by: Greg Kurz Message-Id: <159188281098.70166.18387926536399257573.stgit@bahia.lan> Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Laurent Vivier Signed-off-by: David Gibson --- hw/ppc/spapr_caps.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index efdc0dbbcf..0c2bc8e06e 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -248,23 +248,18 @@ SpaprCapPossible cap_cfpc_possible = { static void cap_safe_cache_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { - Error *local_err = NULL; uint8_t kvm_val = kvmppc_get_cap_safe_cache(); if (tcg_enabled() && val) { /* TCG only supports broken, allow other values and print a warning */ - error_setg(&local_err, - "TCG doesn't support requested feature, cap-cfpc=%s", - cap_cfpc_possible.vals[val]); + warn_report("TCG doesn't support requested feature, cap-cfpc=%s", + cap_cfpc_possible.vals[val]); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, "Requested safe cache capability level not supported by kvm," " try appending -machine cap-cfpc=%s", cap_cfpc_possible.vals[kvm_val]); } - - if (local_err != NULL) - warn_report_err(local_err); } SpaprCapPossible cap_sbbc_possible = { @@ -277,23 +272,18 @@ SpaprCapPossible cap_sbbc_possible = { static void cap_safe_bounds_check_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { - Error *local_err = NULL; uint8_t kvm_val = kvmppc_get_cap_safe_bounds_check(); if (tcg_enabled() && val) { /* TCG only supports broken, allow other values and print a warning */ - error_setg(&local_err, - "TCG doesn't support requested feature, cap-sbbc=%s", - cap_sbbc_possible.vals[val]); + warn_report("TCG doesn't support requested feature, cap-sbbc=%s", + cap_sbbc_possible.vals[val]); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, "Requested safe bounds check capability level not supported by kvm," " try appending -machine cap-sbbc=%s", cap_sbbc_possible.vals[kvm_val]); } - - if (local_err != NULL) - warn_report_err(local_err); } SpaprCapPossible cap_ibs_possible = { @@ -309,24 +299,18 @@ SpaprCapPossible cap_ibs_possible = { static void cap_safe_indirect_branch_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { - Error *local_err = NULL; uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch(); if (tcg_enabled() && val) { /* TCG only supports broken, allow other values and print a warning */ - error_setg(&local_err, - "TCG doesn't support requested feature, cap-ibs=%s", - cap_ibs_possible.vals[val]); + warn_report("TCG doesn't support requested feature, cap-ibs=%s", + cap_ibs_possible.vals[val]); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, "Requested safe indirect branch capability level not supported by kvm," " try appending -machine cap-ibs=%s", cap_ibs_possible.vals[kvm_val]); } - - if (local_err != NULL) { - warn_report_err(local_err); - } } #define VALUE_DESC_TRISTATE " (broken, workaround, fixed)" From 7861e083f89ef4c841a511bb12234982c918ef39 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Thu, 28 May 2020 20:04:41 -0400 Subject: [PATCH 1602/2595] spapr: Fix typos in comments and macro indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes typos in spapr_vio_reg_to_irq() comments and a macro indentation. Signed-off-by: Gustavo Romero Message-Id: <1590710681-12873-1-git-send-email-gromero@linux.ibm.com> Acked-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr_vio.c | 6 +++--- include/hw/ppc/xive_regs.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 4318ed9638..731080d989 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -420,7 +420,7 @@ static void spapr_vio_busdev_reset(DeviceState *qdev) } /* - * The register property of a VIO device is defined in livirt using + * The register property of a VIO device is defined in libvirt using * 0x1000 as a base register number plus a 0x1000 increment. For the * VIO tty device, the base number is changed to 0x30000000. QEMU uses * a base register number of 0x71000000 and then a simple increment. @@ -450,7 +450,7 @@ static inline uint32_t spapr_vio_reg_to_irq(uint32_t reg) } else if (reg >= 0x30000000) { /* - * VIO tty devices register values, when allocated by livirt, + * VIO tty devices register values, when allocated by libvirt, * are mapped in range [0xf0 - 0xff], gives us a maximum of 16 * vtys. */ @@ -459,7 +459,7 @@ static inline uint32_t spapr_vio_reg_to_irq(uint32_t reg) } else { /* * Other VIO devices register values, when allocated by - * livirt, should be mapped in range [0x00 - 0xef]. Conflicts + * libvirt, should be mapped in range [0x00 - 0xef]. Conflicts * will be detected when IRQ is claimed. */ irq = (reg >> 12) & 0xff; diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h index 09f243600c..7879692825 100644 --- a/include/hw/ppc/xive_regs.h +++ b/include/hw/ppc/xive_regs.h @@ -71,7 +71,7 @@ * QW word 2 contains the valid bit at the top and other fields * depending on the QW. */ -#define TM_WORD2 0x8 +#define TM_WORD2 0x8 #define TM_QW0W2_VU PPC_BIT32(0) #define TM_QW0W2_LOGIC_SERV PPC_BITMASK32(1, 31) /* XX 2,31 ? */ #define TM_QW1W2_VO PPC_BIT32(0) From 38d2448a376882a3efc32c21f7e8ce48ad96c644 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 22 Jun 2020 08:57:18 +0200 Subject: [PATCH 1603/2595] ppc/pnv: Silence missing BMC warning with qtest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The device introspect test in qtest emits some warnings with the the pnv machine types during the "nodefaults" phase: TEST check-qtest-ppc64: tests/qtest/device-introspect-test qemu-system-ppc64: warning: machine has no BMC device. Use '-device ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10' to define one qemu-system-ppc64: warning: machine has no BMC device. Use '-device ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10' to define one qemu-system-ppc64: warning: machine has no BMC device. Use '-device ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10' to define one This is expected since the pnv machine doesn't create the internal BMC simulator fallback when "-nodefaults" is passed on the command line, but these warnings appear in ci logs and confuse people. Not having a BMC isn't recommended but it is still a supported configuration, so a straightforward fix is to just silent this warning when qtest is enabled. Fixes: 25f3170b0654 ("ppc/pnv: Create BMC devices only when defaults are enabled") Reported-by: Philippe Mathieu-Daudé Signed-off-by: Greg Kurz Message-Id: <159280903824.485572.831378159272329707.stgit@bahia.lan> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/pnv.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 8bd03f3b10..643098ad5f 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -21,6 +21,7 @@ #include "qemu-common.h" #include "qemu/units.h" #include "qapi/error.h" +#include "sysemu/qtest.h" #include "sysemu/sysemu.h" #include "sysemu/numa.h" #include "sysemu/reset.h" @@ -587,9 +588,11 @@ static void pnv_reset(MachineState *machine) bmc = pnv_bmc_find(&error_fatal); if (!pnv->bmc) { if (!bmc) { - warn_report("machine has no BMC device. Use '-device " - "ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10' " - "to define one"); + if (!qtest_enabled()) { + warn_report("machine has no BMC device. Use '-device " + "ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10' " + "to define one"); + } } else { pnv_bmc_set_pnor(bmc, pnv->pnor); pnv->bmc = bmc; From 737ef968d442cb287b1fcc7da94b53284b0ad1e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 23 Jun 2020 17:45:34 +0200 Subject: [PATCH 1604/2595] target/ppc: Remove TIDR from POWER10 processor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is not part of Power ISA Version 3.1. Signed-off-by: Cédric Le Goater Message-Id: <20200623154534.266065-1-clg@kaod.org> Signed-off-by: David Gibson --- target/ppc/translate_init.inc.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index a40888411c..49212bfd90 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -9086,11 +9086,6 @@ static void init_proc_POWER10(CPUPPCState *env) gen_spr_power8_rpr(env); gen_spr_power9_mmu(env); - /* POWER9 Specific registers */ - spr_register_kvm(env, SPR_TIDR, "TIDR", NULL, NULL, - spr_read_generic, spr_write_generic, - KVM_REG_PPC_TIDR, 0); - /* FIXME: Filter fields properly based on privilege level */ spr_register_kvm_hv(env, SPR_PSSCR, "PSSCR", NULL, NULL, NULL, NULL, spr_read_generic, spr_write_generic, From bcaaefdbb2167858d3b92745b79473deb49c417a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:15 +0100 Subject: [PATCH 1605/2595] adb: coding style update to fix checkpatch errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will help ensure that style guidelines are being maintained during subsequent changes. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-2-mark.cave-ayland@ilande.co.uk> --- hw/input/adb.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/input/adb.c b/hw/input/adb.c index b1ac4a3852..bf1bc30d19 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -44,14 +44,14 @@ int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) cmd = buf[0] & 0xf; if (cmd == ADB_BUSRESET) { - for(i = 0; i < s->nb_devices; i++) { + for (i = 0; i < s->nb_devices; i++) { d = s->devices[i]; adb_device_reset(d); } return 0; } devaddr = buf[0] >> 4; - for(i = 0; i < s->nb_devices; i++) { + for (i = 0; i < s->nb_devices; i++) { d = s->devices[i]; if (d->devaddr == devaddr) { ADBDeviceClass *adc = ADB_DEVICE_GET_CLASS(d); @@ -69,9 +69,10 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask) uint8_t buf[1]; olen = 0; - for(i = 0; i < s->nb_devices; i++) { - if (s->poll_index >= s->nb_devices) + for (i = 0; i < s->nb_devices; i++) { + if (s->poll_index >= s->nb_devices) { s->poll_index = 0; + } d = s->devices[s->poll_index]; if ((1 << d->devaddr) & poll_mask) { buf[0] = ADB_READREG | (d->devaddr << 4); From 167f1667b120ddac301163da64b57b19ce7cf622 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:16 +0100 Subject: [PATCH 1606/2595] adb: fix adb-mouse read length and revert disable-reg3-direct-writes workaround Commit 84051eb400 "adb: add property to disable direct reg 3 writes" introduced a workaround for spurious writes to ADB register 3 when MacOS 9 enables autopoll on the mouse device. Further analysis shows that the problem is that only a partial request is sent, and since the len parameter is ignored then stale data from the previous request is used causing the incorrect address assignment. Remove the disable-reg3-direct-writes workaround and instead check the length parameter when the write is attempted, discarding the invalid request. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-3-mark.cave-ayland@ilande.co.uk> --- hw/input/adb-kbd.c | 26 +++++++++++------------ hw/input/adb-mouse.c | 48 ++++++++++++++++++++++++------------------ hw/input/adb.c | 7 ------ hw/ppc/mac_newworld.c | 2 -- include/hw/input/adb.h | 1 - 5 files changed, 40 insertions(+), 44 deletions(-) diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c index a6d5c9b7c9..027dd3e531 100644 --- a/hw/input/adb-kbd.c +++ b/hw/input/adb-kbd.c @@ -259,21 +259,19 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, trace_adb_kbd_request_change_addr(d->devaddr); break; default: - if (!d->disable_direct_reg3_writes) { - d->devaddr = buf[1] & 0xf; - - /* we support handlers: - * 1: Apple Standard Keyboard - * 2: Apple Extended Keyboard (LShift = RShift) - * 3: Apple Extended Keyboard (LShift != RShift) - */ - if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) { - d->handler = buf[2]; - } - - trace_adb_kbd_request_change_addr_and_handler(d->devaddr, - d->handler); + d->devaddr = buf[1] & 0xf; + /* + * we support handlers: + * 1: Apple Standard Keyboard + * 2: Apple Extended Keyboard (LShift = RShift) + * 3: Apple Extended Keyboard (LShift != RShift) + */ + if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) { + d->handler = buf[2]; } + + trace_adb_kbd_request_change_addr_and_handler(d->devaddr, + d->handler); break; } } diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c index aeba41bddd..78b6f5030c 100644 --- a/hw/input/adb-mouse.c +++ b/hw/input/adb-mouse.c @@ -135,6 +135,16 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, case 2: break; case 3: + /* + * MacOS 9 has a bug in its ADB driver whereby after configuring + * the ADB bus devices it sends another write of invalid length + * to reg 3. Make sure we ignore it to prevent an address clash + * with the previous device. + */ + if (len != 3) { + return 0; + } + switch (buf[2]) { case ADB_CMD_SELF_TEST: break; @@ -145,27 +155,25 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, trace_adb_mouse_request_change_addr(d->devaddr); break; default: - if (!d->disable_direct_reg3_writes) { - d->devaddr = buf[1] & 0xf; - - /* we support handlers: - * 0x01: Classic Apple Mouse Protocol / 100 cpi operations - * 0x02: Classic Apple Mouse Protocol / 200 cpi operations - * we don't support handlers (at least): - * 0x03: Mouse systems A3 trackball - * 0x04: Extended Apple Mouse Protocol - * 0x2f: Microspeed mouse - * 0x42: Macally - * 0x5f: Microspeed mouse - * 0x66: Microspeed mouse - */ - if (buf[2] == 1 || buf[2] == 2) { - d->handler = buf[2]; - } - - trace_adb_mouse_request_change_addr_and_handler( - d->devaddr, d->handler); + d->devaddr = buf[1] & 0xf; + /* + * we support handlers: + * 0x01: Classic Apple Mouse Protocol / 100 cpi operations + * 0x02: Classic Apple Mouse Protocol / 200 cpi operations + * we don't support handlers (at least): + * 0x03: Mouse systems A3 trackball + * 0x04: Extended Apple Mouse Protocol + * 0x2f: Microspeed mouse + * 0x42: Macally + * 0x5f: Microspeed mouse + * 0x66: Microspeed mouse + */ + if (buf[2] == 1 || buf[2] == 2) { + d->handler = buf[2]; } + + trace_adb_mouse_request_change_addr_and_handler(d->devaddr, + d->handler); break; } } diff --git a/hw/input/adb.c b/hw/input/adb.c index bf1bc30d19..d85278a7b7 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -118,18 +118,11 @@ static void adb_device_realizefn(DeviceState *dev, Error **errp) bus->devices[bus->nb_devices++] = d; } -static Property adb_device_properties[] = { - DEFINE_PROP_BOOL("disable-direct-reg3-writes", ADBDevice, - disable_direct_reg3_writes, false), - DEFINE_PROP_END_OF_LIST(), -}; - static void adb_device_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = adb_device_realizefn; - device_class_set_props(dc, adb_device_properties); dc->bus_type = TYPE_ADB_BUS; } diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 5f3a028e6a..828c5992ae 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -404,11 +404,9 @@ static void ppc_core99_init(MachineState *machine) adb_bus = qdev_get_child_bus(dev, "adb.0"); dev = qdev_new(TYPE_ADB_KEYBOARD); - qdev_prop_set_bit(dev, "disable-direct-reg3-writes", true); qdev_realize_and_unref(dev, adb_bus, &error_fatal); dev = qdev_new(TYPE_ADB_MOUSE); - qdev_prop_set_bit(dev, "disable-direct-reg3-writes", true); qdev_realize_and_unref(dev, adb_bus, &error_fatal); } diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h index b7b32e2b16..4d2c565f54 100644 --- a/include/hw/input/adb.h +++ b/include/hw/input/adb.h @@ -49,7 +49,6 @@ struct ADBDevice { int devaddr; int handler; - bool disable_direct_reg3_writes; }; #define ADB_DEVICE_CLASS(cls) \ From d9b898943dbcce7c513739febc05ccaa7142c49e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:17 +0100 Subject: [PATCH 1607/2595] cuda: convert ADB autopoll timer from ns to ms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is in preparation for consolidating all of the ADB autopoll management in one place. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-4-mark.cave-ayland@ilande.co.uk> --- hw/misc/macio/cuda.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 47aa3b0552..01bf47327c 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -210,8 +210,9 @@ static void cuda_adb_poll(void *opaque) obuf[1] = 0x40; /* polled data */ cuda_send_packet_to_host(s, obuf, olen + 2); } - timer_mod(s->adb_poll_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - (NANOSECONDS_PER_SECOND / (1000 / s->autopoll_rate_ms))); + + timer_mod(s->adb_poll_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + s->autopoll_rate_ms); } /* description of commands */ @@ -238,8 +239,8 @@ static bool cuda_cmd_autopoll(CUDAState *s, s->autopoll = autopoll; if (autopoll) { timer_mod(s->adb_poll_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - (NANOSECONDS_PER_SECOND / (1000 / s->autopoll_rate_ms))); + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + s->autopoll_rate_ms); } else { timer_del(s->adb_poll_timer); } @@ -264,8 +265,8 @@ static bool cuda_cmd_set_autorate(CUDAState *s, s->autopoll_rate_ms = in_data[0]; if (s->autopoll) { timer_mod(s->adb_poll_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - (NANOSECONDS_PER_SECOND / (1000 / s->autopoll_rate_ms))); + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + s->autopoll_rate_ms); } return true; } @@ -544,7 +545,7 @@ static void cuda_realize(DeviceState *dev, Error **errp) s->sr_delay_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_set_sr_int, s); s->sr_delay_ns = 20 * SCALE_US; - s->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_adb_poll, s); + s->adb_poll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, cuda_adb_poll, s); s->adb_poll_mask = 0xffff; s->autopoll_rate_ms = 20; } From dcb091c40ef8c77590b1c5b7160ec428f2a2a053 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:18 +0100 Subject: [PATCH 1608/2595] pmu: fix duplicate autopoll mask variable It seems that during the initial work to introduce the via-pmu ADB support a duplicate autopoll mask variable was accidentally left in place. Remove the duplicate autopoll_mask variable and switch everything over to use adb_poll_mask instead. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-5-mark.cave-ayland@ilande.co.uk> --- hw/misc/macio/pmu.c | 15 +++++++-------- include/hw/misc/macio/pmu.h | 1 - 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index 41b626c46c..cae2845936 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -175,11 +175,11 @@ static void pmu_cmd_set_adb_autopoll(PMUState *s, uint16_t mask) { trace_pmu_cmd_set_adb_autopoll(mask); - if (s->autopoll_mask == mask) { + if (s->adb_poll_mask == mask) { return; } - s->autopoll_mask = mask; + s->adb_poll_mask = mask; if (mask) { timer_mod(s->adb_poll_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 30); @@ -274,9 +274,9 @@ static void pmu_cmd_adb_poll_off(PMUState *s, return; } - if (s->has_adb && s->autopoll_mask) { + if (s->has_adb && s->adb_poll_mask) { timer_del(s->adb_poll_timer); - s->autopoll_mask = false; + s->adb_poll_mask = 0; } } @@ -698,8 +698,8 @@ static const VMStateDescription vmstate_pmu_adb = { static const VMStateDescription vmstate_pmu = { .name = "pmu", - .version_id = 0, - .minimum_version_id = 0, + .version_id = 1, + .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT(mos6522_pmu.parent_obj, PMUState, 0, vmstate_mos6522, MOS6522State), @@ -715,7 +715,6 @@ static const VMStateDescription vmstate_pmu = { VMSTATE_UINT8(intbits, PMUState), VMSTATE_UINT8(intmask, PMUState), VMSTATE_UINT8(autopoll_rate_ms, PMUState), - VMSTATE_UINT8(autopoll_mask, PMUState), VMSTATE_UINT32(tick_offset, PMUState), VMSTATE_TIMER_PTR(one_sec_timer, PMUState), VMSTATE_INT64(one_sec_target, PMUState), @@ -735,7 +734,7 @@ static void pmu_reset(DeviceState *dev) s->intbits = 0; s->cmd_state = pmu_state_idle; - s->autopoll_mask = 0; + s->adb_poll_mask = 0; } static void pmu_realize(DeviceState *dev, Error **errp) diff --git a/include/hw/misc/macio/pmu.h b/include/hw/misc/macio/pmu.h index 7ef83dee4c..4f34b6f9e7 100644 --- a/include/hw/misc/macio/pmu.h +++ b/include/hw/misc/macio/pmu.h @@ -220,7 +220,6 @@ typedef struct PMUState { ADBBusState adb_bus; uint16_t adb_poll_mask; uint8_t autopoll_rate_ms; - uint8_t autopoll_mask; QEMUTimer *adb_poll_timer; uint8_t adb_reply_size; uint8_t adb_reply[ADB_MAX_OUT_LEN]; From 414eb1d500b94b2774440656f5bde4bf2e0f4a29 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:19 +0100 Subject: [PATCH 1609/2595] pmu: honour autopoll_rate_ms when rearming the ADB autopoll timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't use a fixed value but instead use the default value from the ADB bus state. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-6-mark.cave-ayland@ilande.co.uk> --- hw/misc/macio/pmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index cae2845936..bae0b440d0 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -106,7 +106,7 @@ static void pmu_adb_poll(void *opaque) } timer_mod(s->adb_poll_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 30); + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->autopoll_rate_ms); } static void pmu_one_sec_timer(void *opaque) @@ -182,7 +182,7 @@ static void pmu_cmd_set_adb_autopoll(PMUState *s, uint16_t mask) s->adb_poll_mask = mask; if (mask) { timer_mod(s->adb_poll_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 30); + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->autopoll_rate_ms); } else { timer_del(s->adb_poll_timer); } From 0606b2883038b4b9a31a46fd1275a31323ec22d0 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:20 +0100 Subject: [PATCH 1610/2595] adb: introduce realize/unrealize and VMStateDescription for ADB bus Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-7-mark.cave-ayland@ilande.co.uk> --- hw/input/adb.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/hw/input/adb.c b/hw/input/adb.c index d85278a7b7..21a9b3aa96 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -89,10 +89,42 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask) return olen; } +static const VMStateDescription vmstate_adb_bus = { + .name = "adb_bus", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static void adb_bus_realize(BusState *qbus, Error **errp) +{ + ADBBusState *adb_bus = ADB_BUS(qbus); + + vmstate_register(NULL, -1, &vmstate_adb_bus, adb_bus); +} + +static void adb_bus_unrealize(BusState *qbus) +{ + ADBBusState *adb_bus = ADB_BUS(qbus); + + vmstate_unregister(NULL, &vmstate_adb_bus, adb_bus); +} + +static void adb_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->realize = adb_bus_realize; + k->unrealize = adb_bus_unrealize; +} + static const TypeInfo adb_bus_type_info = { .name = TYPE_ADB_BUS, .parent = TYPE_BUS, .instance_size = sizeof(ADBBusState), + .class_init = adb_bus_class_init, }; const VMStateDescription vmstate_adb_device = { From da52c083ac4af9bf934898470dfdeef0f6ead343 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:21 +0100 Subject: [PATCH 1611/2595] adb: create autopoll variables directly within ADBBusState Rather than each ADB implementation requiring its own functions to manage autopoll state, timers, and autopoll masks prepare to move this information directly into ADBBusState. Add external functions within adb.h to allow each ADB implementation to manage the new autopoll variables. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-8-mark.cave-ayland@ilande.co.uk> --- hw/input/adb.c | 77 ++++++++++++++++++++++++++++++++++++++++++ include/hw/input/adb.h | 13 +++++++ 2 files changed, 90 insertions(+) diff --git a/hw/input/adb.c b/hw/input/adb.c index 21a9b3aa96..bb36ce6fad 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -27,6 +27,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qemu/module.h" +#include "qemu/timer.h" #include "adb-internal.h" /* error codes */ @@ -89,19 +90,92 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask) return olen; } +void adb_set_autopoll_enabled(ADBBusState *s, bool enabled) +{ + if (s->autopoll_enabled != enabled) { + s->autopoll_enabled = enabled; + if (s->autopoll_enabled) { + timer_mod(s->autopoll_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + s->autopoll_rate_ms); + } else { + timer_del(s->autopoll_timer); + } + } +} + +void adb_set_autopoll_rate_ms(ADBBusState *s, int rate_ms) +{ + s->autopoll_rate_ms = rate_ms; + + if (s->autopoll_enabled) { + timer_mod(s->autopoll_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + s->autopoll_rate_ms); + } +} + +void adb_set_autopoll_mask(ADBBusState *s, uint16_t mask) +{ + if (s->autopoll_mask != mask) { + s->autopoll_mask = mask; + if (s->autopoll_enabled && s->autopoll_mask) { + timer_mod(s->autopoll_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + s->autopoll_rate_ms); + } else { + timer_del(s->autopoll_timer); + } + } +} + +static void adb_autopoll(void *opaque) +{ + ADBBusState *s = opaque; + + s->autopoll_cb(s->autopoll_cb_opaque); + + timer_mod(s->autopoll_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + s->autopoll_rate_ms); +} + +void adb_register_autopoll_callback(ADBBusState *s, void (*cb)(void *opaque), + void *opaque) +{ + s->autopoll_cb = cb; + s->autopoll_cb_opaque = opaque; +} + static const VMStateDescription vmstate_adb_bus = { .name = "adb_bus", .version_id = 0, .minimum_version_id = 0, .fields = (VMStateField[]) { + VMSTATE_TIMER_PTR(autopoll_timer, ADBBusState), + VMSTATE_BOOL(autopoll_enabled, ADBBusState), + VMSTATE_UINT8(autopoll_rate_ms, ADBBusState), + VMSTATE_UINT16(autopoll_mask, ADBBusState), VMSTATE_END_OF_LIST() } }; +static void adb_bus_reset(BusState *qbus) +{ + ADBBusState *adb_bus = ADB_BUS(qbus); + + adb_bus->autopoll_enabled = false; + adb_bus->autopoll_mask = 0xffff; + adb_bus->autopoll_rate_ms = 20; +} + static void adb_bus_realize(BusState *qbus, Error **errp) { ADBBusState *adb_bus = ADB_BUS(qbus); + adb_bus->autopoll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, adb_autopoll, + adb_bus); + vmstate_register(NULL, -1, &vmstate_adb_bus, adb_bus); } @@ -109,6 +183,8 @@ static void adb_bus_unrealize(BusState *qbus) { ADBBusState *adb_bus = ADB_BUS(qbus); + timer_del(adb_bus->autopoll_timer); + vmstate_unregister(NULL, &vmstate_adb_bus, adb_bus); } @@ -118,6 +194,7 @@ static void adb_bus_class_init(ObjectClass *klass, void *data) k->realize = adb_bus_realize; k->unrealize = adb_bus_unrealize; + k->reset = adb_bus_reset; } static const TypeInfo adb_bus_type_info = { diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h index 4d2c565f54..15b1874a3d 100644 --- a/include/hw/input/adb.h +++ b/include/hw/input/adb.h @@ -75,12 +75,25 @@ struct ADBBusState { ADBDevice *devices[MAX_ADB_DEVICES]; int nb_devices; int poll_index; + + QEMUTimer *autopoll_timer; + bool autopoll_enabled; + uint8_t autopoll_rate_ms; + uint16_t autopoll_mask; + void (*autopoll_cb)(void *opaque); + void *autopoll_cb_opaque; }; int adb_request(ADBBusState *s, uint8_t *buf_out, const uint8_t *buf, int len); int adb_poll(ADBBusState *s, uint8_t *buf_out, uint16_t poll_mask); +void adb_set_autopoll_enabled(ADBBusState *s, bool enabled); +void adb_set_autopoll_rate_ms(ADBBusState *s, int rate_ms); +void adb_set_autopoll_mask(ADBBusState *s, uint16_t mask); +void adb_register_autopoll_callback(ADBBusState *s, void (*cb)(void *opaque), + void *opaque); + #define TYPE_ADB_KEYBOARD "adb-keyboard" #define TYPE_ADB_MOUSE "adb-mouse" From b12a0b164c6de824b2aa3a22b4670e93e3b24e4a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:22 +0100 Subject: [PATCH 1612/2595] cuda: convert to use ADBBusState internal autopoll variables Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-9-mark.cave-ayland@ilande.co.uk> --- hw/misc/macio/cuda.c | 56 +++++++++++++++--------------------- include/hw/misc/macio/cuda.h | 4 --- 2 files changed, 23 insertions(+), 37 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 01bf47327c..b7071e89d5 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -201,18 +201,16 @@ static void cuda_send_packet_to_host(CUDAState *s, static void cuda_adb_poll(void *opaque) { CUDAState *s = opaque; + ADBBusState *adb_bus = &s->adb_bus; uint8_t obuf[ADB_MAX_OUT_LEN + 2]; int olen; - olen = adb_poll(&s->adb_bus, obuf + 2, s->adb_poll_mask); + olen = adb_poll(adb_bus, obuf + 2, adb_bus->autopoll_mask); if (olen > 0) { obuf[0] = ADB_PACKET; obuf[1] = 0x40; /* polled data */ cuda_send_packet_to_host(s, obuf, olen + 2); } - - timer_mod(s->adb_poll_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + - s->autopoll_rate_ms); } /* description of commands */ @@ -228,23 +226,16 @@ static bool cuda_cmd_autopoll(CUDAState *s, const uint8_t *in_data, int in_len, uint8_t *out_data, int *out_len) { - int autopoll; + ADBBusState *adb_bus = &s->adb_bus; + bool autopoll; if (in_len != 1) { return false; } - autopoll = (in_data[0] != 0); - if (autopoll != s->autopoll) { - s->autopoll = autopoll; - if (autopoll) { - timer_mod(s->adb_poll_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + - s->autopoll_rate_ms); - } else { - timer_del(s->adb_poll_timer); - } - } + autopoll = (in_data[0] != 0) ? true : false; + + adb_set_autopoll_enabled(adb_bus, autopoll); return true; } @@ -252,6 +243,8 @@ static bool cuda_cmd_set_autorate(CUDAState *s, const uint8_t *in_data, int in_len, uint8_t *out_data, int *out_len) { + ADBBusState *adb_bus = &s->adb_bus; + if (in_len != 1) { return false; } @@ -262,12 +255,7 @@ static bool cuda_cmd_set_autorate(CUDAState *s, return false; } - s->autopoll_rate_ms = in_data[0]; - if (s->autopoll) { - timer_mod(s->adb_poll_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + - s->autopoll_rate_ms); - } + adb_set_autopoll_rate_ms(adb_bus, in_data[0]); return true; } @@ -275,11 +263,16 @@ static bool cuda_cmd_set_device_list(CUDAState *s, const uint8_t *in_data, int in_len, uint8_t *out_data, int *out_len) { + ADBBusState *adb_bus = &s->adb_bus; + uint16_t mask; + if (in_len != 2) { return false; } - s->adb_poll_mask = (((uint16_t)in_data[0]) << 8) | in_data[1]; + mask = (((uint16_t)in_data[0]) << 8) | in_data[1]; + + adb_set_autopoll_mask(adb_bus, mask); return true; } @@ -490,8 +483,8 @@ static const MemoryRegionOps mos6522_cuda_ops = { static const VMStateDescription vmstate_cuda = { .name = "cuda", - .version_id = 5, - .minimum_version_id = 5, + .version_id = 6, + .minimum_version_id = 6, .fields = (VMStateField[]) { VMSTATE_STRUCT(mos6522_cuda.parent_obj, CUDAState, 0, vmstate_mos6522, MOS6522State), @@ -500,13 +493,9 @@ static const VMStateDescription vmstate_cuda = { VMSTATE_INT32(data_in_size, CUDAState), VMSTATE_INT32(data_in_index, CUDAState), VMSTATE_INT32(data_out_index, CUDAState), - VMSTATE_UINT8(autopoll, CUDAState), - VMSTATE_UINT8(autopoll_rate_ms, CUDAState), - VMSTATE_UINT16(adb_poll_mask, CUDAState), VMSTATE_BUFFER(data_in, CUDAState), VMSTATE_BUFFER(data_out, CUDAState), VMSTATE_UINT32(tick_offset, CUDAState), - VMSTATE_TIMER_PTR(adb_poll_timer, CUDAState), VMSTATE_TIMER_PTR(sr_delay_timer, CUDAState), VMSTATE_END_OF_LIST() } @@ -515,11 +504,13 @@ static const VMStateDescription vmstate_cuda = { static void cuda_reset(DeviceState *dev) { CUDAState *s = CUDA(dev); + ADBBusState *adb_bus = &s->adb_bus; s->data_in_size = 0; s->data_in_index = 0; s->data_out_index = 0; - s->autopoll = 0; + + adb_set_autopoll_enabled(adb_bus, false); } static void cuda_realize(DeviceState *dev, Error **errp) @@ -527,6 +518,7 @@ static void cuda_realize(DeviceState *dev, Error **errp) CUDAState *s = CUDA(dev); Error *err = NULL; SysBusDevice *sbd; + ADBBusState *adb_bus = &s->adb_bus; struct tm tm; sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_cuda), &err); @@ -545,9 +537,7 @@ static void cuda_realize(DeviceState *dev, Error **errp) s->sr_delay_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_set_sr_int, s); s->sr_delay_ns = 20 * SCALE_US; - s->adb_poll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, cuda_adb_poll, s); - s->adb_poll_mask = 0xffff; - s->autopoll_rate_ms = 20; + adb_register_autopoll_callback(adb_bus, cuda_adb_poll, s); } static void cuda_init(Object *obj) diff --git a/include/hw/misc/macio/cuda.h b/include/hw/misc/macio/cuda.h index 5768075ac5..a8cf0be1ec 100644 --- a/include/hw/misc/macio/cuda.h +++ b/include/hw/misc/macio/cuda.h @@ -95,12 +95,8 @@ typedef struct CUDAState { int data_out_index; qemu_irq irq; - uint16_t adb_poll_mask; - uint8_t autopoll_rate_ms; - uint8_t autopoll; uint8_t data_in[128]; uint8_t data_out[16]; - QEMUTimer *adb_poll_timer; } CUDAState; #endif /* CUDA_H */ From df381d584ca2b33106eb78aff4c1d6b61cd0558b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:23 +0100 Subject: [PATCH 1613/2595] pmu: convert to use ADBBusState internal autopoll variables Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-10-mark.cave-ayland@ilande.co.uk> --- hw/misc/macio/pmu.c | 39 ++++++++++++++----------------------- include/hw/misc/macio/pmu.h | 3 --- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index bae0b440d0..01d49e6695 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -92,10 +92,11 @@ static void pmu_update_extirq(PMUState *s) static void pmu_adb_poll(void *opaque) { PMUState *s = opaque; + ADBBusState *adb_bus = &s->adb_bus; int olen; if (!(s->intbits & PMU_INT_ADB)) { - olen = adb_poll(&s->adb_bus, s->adb_reply, s->adb_poll_mask); + olen = adb_poll(adb_bus, s->adb_reply, adb_bus->autopoll_mask); trace_pmu_adb_poll(olen); if (olen > 0) { @@ -104,9 +105,6 @@ static void pmu_adb_poll(void *opaque) pmu_update_extirq(s); } } - - timer_mod(s->adb_poll_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->autopoll_rate_ms); } static void pmu_one_sec_timer(void *opaque) @@ -173,18 +171,15 @@ static void pmu_cmd_set_int_mask(PMUState *s, static void pmu_cmd_set_adb_autopoll(PMUState *s, uint16_t mask) { + ADBBusState *adb_bus = &s->adb_bus; + trace_pmu_cmd_set_adb_autopoll(mask); - if (s->adb_poll_mask == mask) { - return; - } - - s->adb_poll_mask = mask; if (mask) { - timer_mod(s->adb_poll_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->autopoll_rate_ms); + adb_set_autopoll_mask(adb_bus, mask); + adb_set_autopoll_enabled(adb_bus, true); } else { - timer_del(s->adb_poll_timer); + adb_set_autopoll_enabled(adb_bus, false); } } @@ -267,6 +262,8 @@ static void pmu_cmd_adb_poll_off(PMUState *s, const uint8_t *in_data, uint8_t in_len, uint8_t *out_data, uint8_t *out_len) { + ADBBusState *adb_bus = &s->adb_bus; + if (in_len != 0) { qemu_log_mask(LOG_GUEST_ERROR, "PMU: ADB POLL OFF command, invalid len: %d want: 0\n", @@ -274,9 +271,8 @@ static void pmu_cmd_adb_poll_off(PMUState *s, return; } - if (s->has_adb && s->adb_poll_mask) { - timer_del(s->adb_poll_timer); - s->adb_poll_mask = 0; + if (s->has_adb) { + adb_set_autopoll_enabled(adb_bus, false); } } @@ -684,12 +680,10 @@ static bool pmu_adb_state_needed(void *opaque) static const VMStateDescription vmstate_pmu_adb = { .name = "pmu/adb", - .version_id = 0, - .minimum_version_id = 0, + .version_id = 1, + .minimum_version_id = 1, .needed = pmu_adb_state_needed, .fields = (VMStateField[]) { - VMSTATE_UINT16(adb_poll_mask, PMUState), - VMSTATE_TIMER_PTR(adb_poll_timer, PMUState), VMSTATE_UINT8(adb_reply_size, PMUState), VMSTATE_BUFFER(adb_reply, PMUState), VMSTATE_END_OF_LIST() @@ -714,7 +708,6 @@ static const VMStateDescription vmstate_pmu = { VMSTATE_BUFFER(cmd_rsp, PMUState), VMSTATE_UINT8(intbits, PMUState), VMSTATE_UINT8(intmask, PMUState), - VMSTATE_UINT8(autopoll_rate_ms, PMUState), VMSTATE_UINT32(tick_offset, PMUState), VMSTATE_TIMER_PTR(one_sec_timer, PMUState), VMSTATE_INT64(one_sec_target, PMUState), @@ -734,7 +727,6 @@ static void pmu_reset(DeviceState *dev) s->intbits = 0; s->cmd_state = pmu_state_idle; - s->adb_poll_mask = 0; } static void pmu_realize(DeviceState *dev, Error **errp) @@ -742,6 +734,7 @@ static void pmu_realize(DeviceState *dev, Error **errp) PMUState *s = VIA_PMU(dev); Error *err = NULL; SysBusDevice *sbd; + ADBBusState *adb_bus = &s->adb_bus; struct tm tm; sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_pmu), &err); @@ -763,9 +756,7 @@ static void pmu_realize(DeviceState *dev, Error **errp) if (s->has_adb) { qbus_create_inplace(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS, dev, "adb.0"); - s->adb_poll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, pmu_adb_poll, s); - s->adb_poll_mask = 0xffff; - s->autopoll_rate_ms = 20; + adb_register_autopoll_callback(adb_bus, pmu_adb_poll, s); } } diff --git a/include/hw/misc/macio/pmu.h b/include/hw/misc/macio/pmu.h index 4f34b6f9e7..72f75612b6 100644 --- a/include/hw/misc/macio/pmu.h +++ b/include/hw/misc/macio/pmu.h @@ -218,9 +218,6 @@ typedef struct PMUState { /* ADB */ bool has_adb; ADBBusState adb_bus; - uint16_t adb_poll_mask; - uint8_t autopoll_rate_ms; - QEMUTimer *adb_poll_timer; uint8_t adb_reply_size; uint8_t adb_reply[ADB_MAX_OUT_LEN]; From f3d61457e86cf43eb5322b57e3f9fcd1bb087591 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:24 +0100 Subject: [PATCH 1614/2595] mac_via: convert to use ADBBusState internal autopoll variables Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-11-mark.cave-ayland@ilande.co.uk> --- hw/misc/mac_via.c | 22 ++++++++++------------ include/hw/misc/mac_via.h | 1 - 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 9cd313c812..7a28bb37ac 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -601,6 +601,8 @@ static void via1_rtc_update(MacVIAState *m) static int adb_via_poll(MacVIAState *s, int state, uint8_t *data) { + ADBBusState *adb_bus = &s->adb_bus; + if (state != ADB_STATE_IDLE) { return 0; } @@ -615,7 +617,8 @@ static int adb_via_poll(MacVIAState *s, int state, uint8_t *data) s->adb_data_in_index = 0; s->adb_data_out_index = 0; - s->adb_data_in_size = adb_poll(&s->adb_bus, s->adb_data_in, 0xffff); + s->adb_data_in_size = adb_poll(adb_bus, s->adb_data_in, + adb_bus->autopoll_mask); if (s->adb_data_in_size) { *data = s->adb_data_in[s->adb_data_in_index++]; @@ -768,10 +771,6 @@ static void via_adb_poll(void *opaque) s->b &= ~VIA1B_vADBInt; } } - - timer_mod(m->adb_poll_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - (NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ)); } static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size) @@ -854,10 +853,9 @@ static void mac_via_reset(DeviceState *dev) { MacVIAState *m = MAC_VIA(dev); MOS6522Q800VIA1State *v1s = &m->mos6522_via1; + ADBBusState *adb_bus = &m->adb_bus; - timer_mod(m->adb_poll_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - (NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ)); + adb_set_autopoll_enabled(adb_bus, true); timer_del(v1s->VBL_timer); v1s->next_VBL = 0; @@ -872,6 +870,7 @@ static void mac_via_realize(DeviceState *dev, Error **errp) { MacVIAState *m = MAC_VIA(dev); MOS6522State *ms; + ADBBusState *adb_bus = &m->adb_bus; struct tm tm; int ret; @@ -907,7 +906,7 @@ static void mac_via_realize(DeviceState *dev, Error **errp) qemu_get_timedate(&tm, 0); m->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; - m->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, via_adb_poll, m); + adb_register_autopoll_callback(adb_bus, via_adb_poll, m); m->adb_data_ready = qdev_get_gpio_in_named(dev, "via1-irq", VIA1_IRQ_ADB_READY_BIT); @@ -980,8 +979,8 @@ static int mac_via_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_mac_via = { .name = "mac-via", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .post_load = mac_via_post_load, .fields = (VMStateField[]) { /* VIAs */ @@ -1005,7 +1004,6 @@ static const VMStateDescription vmstate_mac_via = { VMSTATE_INT32(wprotect, MacVIAState), VMSTATE_INT32(alt, MacVIAState), /* ADB */ - VMSTATE_TIMER_PTR(adb_poll_timer, MacVIAState), VMSTATE_INT32(adb_data_in_size, MacVIAState), VMSTATE_INT32(adb_data_in_index, MacVIAState), VMSTATE_INT32(adb_data_out_index, MacVIAState), diff --git a/include/hw/misc/mac_via.h b/include/hw/misc/mac_via.h index e74f85be0f..2aaf9e27bf 100644 --- a/include/hw/misc/mac_via.h +++ b/include/hw/misc/mac_via.h @@ -106,7 +106,6 @@ typedef struct MacVIAState { /* ADB */ ADBBusState adb_bus; - QEMUTimer *adb_poll_timer; qemu_irq adb_data_ready; int adb_data_in_size; int adb_data_in_index; From 969ca2f7a1a41123f08ce67d7a51075c3ee2fd6e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:25 +0100 Subject: [PATCH 1615/2595] adb: introduce new ADBDeviceHasData method to ADBDeviceClass This is required later to allow devices to assert a service request (SRQ) signal to indicate that it has data to send, without having to consume it. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-12-mark.cave-ayland@ilande.co.uk> --- hw/input/adb-kbd.c | 8 ++++++++ hw/input/adb-mouse.c | 9 +++++++++ include/hw/input/adb.h | 3 +++ 3 files changed, 20 insertions(+) diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c index 027dd3e531..23760ecf7b 100644 --- a/hw/input/adb-kbd.c +++ b/hw/input/adb-kbd.c @@ -300,6 +300,13 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, return olen; } +static bool adb_kbd_has_data(ADBDevice *d) +{ + KBDState *s = ADB_KEYBOARD(d); + + return s->count > 0; +} + /* This is where keyboard events enter this file */ static void adb_keyboard_event(DeviceState *dev, QemuConsole *src, InputEvent *evt) @@ -382,6 +389,7 @@ static void adb_kbd_class_init(ObjectClass *oc, void *data) set_bit(DEVICE_CATEGORY_INPUT, dc->categories); adc->devreq = adb_kbd_request; + adc->devhasdata = adb_kbd_has_data; dc->reset = adb_kbd_reset; dc->vmsd = &vmstate_adb_kbd; } diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c index 78b6f5030c..e2359fd74d 100644 --- a/hw/input/adb-mouse.c +++ b/hw/input/adb-mouse.c @@ -197,6 +197,14 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, return olen; } +static bool adb_mouse_has_data(ADBDevice *d) +{ + MouseState *s = ADB_MOUSE(d); + + return !(s->last_buttons_state == s->buttons_state && + s->dx == 0 && s->dy == 0); +} + static void adb_mouse_reset(DeviceState *dev) { ADBDevice *d = ADB_DEVICE(dev); @@ -252,6 +260,7 @@ static void adb_mouse_class_init(ObjectClass *oc, void *data) set_bit(DEVICE_CATEGORY_INPUT, dc->categories); adc->devreq = adb_mouse_request; + adc->devhasdata = adb_mouse_has_data; dc->reset = adb_mouse_reset; dc->vmsd = &vmstate_adb_mouse; } diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h index 15b1874a3d..9b80204e43 100644 --- a/include/hw/input/adb.h +++ b/include/hw/input/adb.h @@ -39,6 +39,8 @@ typedef struct ADBDevice ADBDevice; typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out, const uint8_t *buf, int len); +typedef bool ADBDeviceHasData(ADBDevice *d); + #define TYPE_ADB_DEVICE "adb-device" #define ADB_DEVICE(obj) OBJECT_CHECK(ADBDevice, (obj), TYPE_ADB_DEVICE) @@ -62,6 +64,7 @@ typedef struct ADBDeviceClass { /*< public >*/ ADBDeviceRequest *devreq; + ADBDeviceHasData *devhasdata; } ADBDeviceClass; #define TYPE_ADB_BUS "apple-desktop-bus" From 244a0ee96545e79af7ade39b510e459ef5a1c366 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:26 +0100 Subject: [PATCH 1616/2595] adb: keep track of devices with pending data Add a new pending variable to ADBBusState which is a bitmask indicating which ADB devices have data to send. Update the bitmask every time that an ADB request is executed. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-13-mark.cave-ayland@ilande.co.uk> --- hw/input/adb.c | 16 +++++++++++++++- include/hw/input/adb.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/hw/input/adb.c b/hw/input/adb.c index bb36ce6fad..c1adb21e6b 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -41,6 +41,7 @@ static void adb_device_reset(ADBDevice *d) int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) { ADBDevice *d; + ADBDeviceClass *adc; int devaddr, cmd, i; cmd = buf[0] & 0xf; @@ -51,14 +52,27 @@ int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) } return 0; } + + s->pending = 0; + for (i = 0; i < s->nb_devices; i++) { + d = s->devices[i]; + adc = ADB_DEVICE_GET_CLASS(d); + + if (adc->devhasdata(d)) { + s->pending |= (1 << d->devaddr); + } + } + devaddr = buf[0] >> 4; for (i = 0; i < s->nb_devices; i++) { d = s->devices[i]; + adc = ADB_DEVICE_GET_CLASS(d); + if (d->devaddr == devaddr) { - ADBDeviceClass *adc = ADB_DEVICE_GET_CLASS(d); return adc->devreq(d, obuf, buf, len); } } + return ADB_RET_NOTPRESENT; } diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h index 9b80204e43..f1bc358d8e 100644 --- a/include/hw/input/adb.h +++ b/include/hw/input/adb.h @@ -76,6 +76,7 @@ struct ADBBusState { /*< public >*/ ADBDevice *devices[MAX_ADB_DEVICES]; + uint16_t pending; int nb_devices; int poll_index; From 3fe02cc8b3a5b50fad6d5e7cc3a65fd52d1fad36 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:27 +0100 Subject: [PATCH 1617/2595] adb: add status field for holding information about the last ADB request Currently only 2 bits are defined: one to indicate if the request timed out (no reply) and another to indicate whether the request was the result of an autopoll operation. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-14-mark.cave-ayland@ilande.co.uk> --- hw/input/adb.c | 14 +++++++++++--- include/hw/input/adb.h | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/hw/input/adb.c b/hw/input/adb.c index c1adb21e6b..a7a482fdfa 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -42,7 +42,7 @@ int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) { ADBDevice *d; ADBDeviceClass *adc; - int devaddr, cmd, i; + int devaddr, cmd, olen, i; cmd = buf[0] & 0xf; if (cmd == ADB_BUSRESET) { @@ -50,6 +50,7 @@ int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) d = s->devices[i]; adb_device_reset(d); } + s->status = 0; return 0; } @@ -63,16 +64,22 @@ int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) } } + s->status = 0; devaddr = buf[0] >> 4; for (i = 0; i < s->nb_devices; i++) { d = s->devices[i]; adc = ADB_DEVICE_GET_CLASS(d); if (d->devaddr == devaddr) { - return adc->devreq(d, obuf, buf, len); + olen = adc->devreq(d, obuf, buf, len); + if (!olen) { + s->status |= ADB_STATUS_BUSTIMEOUT; + } + return olen; } } + s->status |= ADB_STATUS_BUSTIMEOUT; return ADB_RET_NOTPRESENT; } @@ -94,9 +101,10 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask) olen = adb_request(s, obuf + 1, buf, 1); /* if there is data, we poll again the same device */ if (olen > 0) { + s->status |= ADB_STATUS_POLLREPLY; obuf[0] = buf[0]; olen++; - break; + return olen; } } s->poll_index++; diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h index f1bc358d8e..cff264739c 100644 --- a/include/hw/input/adb.h +++ b/include/hw/input/adb.h @@ -70,6 +70,9 @@ typedef struct ADBDeviceClass { #define TYPE_ADB_BUS "apple-desktop-bus" #define ADB_BUS(obj) OBJECT_CHECK(ADBBusState, (obj), TYPE_ADB_BUS) +#define ADB_STATUS_BUSTIMEOUT 0x1 +#define ADB_STATUS_POLLREPLY 0x2 + struct ADBBusState { /*< private >*/ BusState parent_obj; @@ -79,6 +82,7 @@ struct ADBBusState { uint16_t pending; int nb_devices; int poll_index; + uint8_t status; QEMUTimer *autopoll_timer; bool autopoll_enabled; From d2288b75845d86d4a9486e72f966676ce5c3ed1e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:28 +0100 Subject: [PATCH 1618/2595] adb: use adb_request() only for explicit requests Currently adb_request() is called both for explicit ADB requests and internal autopoll requests via adb_poll(). Move the current functionality into do_adb_request() to be used internally and add a simple adb_request() wrapper for explicit requests. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-15-mark.cave-ayland@ilande.co.uk> --- hw/input/adb.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/input/adb.c b/hw/input/adb.c index a7a482fdfa..b3ad7c5fca 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -38,7 +38,8 @@ static void adb_device_reset(ADBDevice *d) qdev_reset_all(DEVICE(d)); } -int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) +static int do_adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, + int len) { ADBDevice *d; ADBDeviceClass *adc; @@ -83,6 +84,11 @@ int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) return ADB_RET_NOTPRESENT; } +int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) +{ + return do_adb_request(s, obuf, buf, len); +} + /* XXX: move that to cuda ? */ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask) { @@ -98,7 +104,7 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask) d = s->devices[s->poll_index]; if ((1 << d->devaddr) & poll_mask) { buf[0] = ADB_READREG | (d->devaddr << 4); - olen = adb_request(s, obuf + 1, buf, 1); + olen = do_adb_request(s, obuf + 1, buf, 1); /* if there is data, we poll again the same device */ if (olen > 0) { s->status |= ADB_STATUS_POLLREPLY; From 4e5df0369fb5a49ed26518dccffeb03a252352db Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:29 +0100 Subject: [PATCH 1619/2595] adb: add autopoll_blocked variable to block autopoll Whilst autopoll is enabled it is necessary to prevent the ADB buffer contents from being overwritten until the host has read back the response in its entirety. Add adb_autopoll_block() and adb_autopoll_unblock() functions in preparation for ensuring that the ADB buffer contents are protected for explicit ADB requests. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-16-mark.cave-ayland@ilande.co.uk> --- hw/input/adb.c | 21 +++++++++++++++++++++ include/hw/input/adb.h | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/hw/input/adb.c b/hw/input/adb.c index b3ad7c5fca..70aa1f4570 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -157,6 +157,26 @@ void adb_set_autopoll_mask(ADBBusState *s, uint16_t mask) } } +void adb_autopoll_block(ADBBusState *s) +{ + s->autopoll_blocked = true; + + if (s->autopoll_enabled) { + timer_del(s->autopoll_timer); + } +} + +void adb_autopoll_unblock(ADBBusState *s) +{ + s->autopoll_blocked = false; + + if (s->autopoll_enabled) { + timer_mod(s->autopoll_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + s->autopoll_rate_ms); + } +} + static void adb_autopoll(void *opaque) { ADBBusState *s = opaque; @@ -184,6 +204,7 @@ static const VMStateDescription vmstate_adb_bus = { VMSTATE_BOOL(autopoll_enabled, ADBBusState), VMSTATE_UINT8(autopoll_rate_ms, ADBBusState), VMSTATE_UINT16(autopoll_mask, ADBBusState), + VMSTATE_BOOL(autopoll_blocked, ADBBusState), VMSTATE_END_OF_LIST() } }; diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h index cff264739c..bb75a7b1e3 100644 --- a/include/hw/input/adb.h +++ b/include/hw/input/adb.h @@ -86,6 +86,7 @@ struct ADBBusState { QEMUTimer *autopoll_timer; bool autopoll_enabled; + bool autopoll_blocked; uint8_t autopoll_rate_ms; uint16_t autopoll_mask; void (*autopoll_cb)(void *opaque); @@ -96,6 +97,9 @@ int adb_request(ADBBusState *s, uint8_t *buf_out, const uint8_t *buf, int len); int adb_poll(ADBBusState *s, uint8_t *buf_out, uint16_t poll_mask); +void adb_autopoll_block(ADBBusState *s); +void adb_autopoll_unblock(ADBBusState *s); + void adb_set_autopoll_enabled(ADBBusState *s, bool enabled); void adb_set_autopoll_rate_ms(ADBBusState *s, int rate_ms); void adb_set_autopoll_mask(ADBBusState *s, uint16_t mask); From 45c9d721ef9ea4e50dbede53bc97922767db70b8 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:30 +0100 Subject: [PATCH 1620/2595] cuda: add adb_autopoll_block() and adb_autopoll_unblock() functions Ensure that the CUDA buffer is protected from autopoll requests overwriting its contents whilst existing CUDA requests are in progress. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-17-mark.cave-ayland@ilande.co.uk> --- hw/misc/macio/cuda.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index b7071e89d5..5bbc7770fa 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -116,6 +116,7 @@ static void cuda_update(CUDAState *s) { MOS6522CUDAState *mcs = &s->mos6522_cuda; MOS6522State *ms = MOS6522(mcs); + ADBBusState *adb_bus = &s->adb_bus; int packet_received, len; packet_received = 0; @@ -126,6 +127,9 @@ static void cuda_update(CUDAState *s) /* data output */ if ((ms->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { if (s->data_out_index < sizeof(s->data_out)) { + if (s->data_out_index == 0) { + adb_autopoll_block(adb_bus); + } trace_cuda_data_send(ms->sr); s->data_out[s->data_out_index++] = ms->sr; cuda_delay_set_sr_int(s); @@ -140,6 +144,7 @@ static void cuda_update(CUDAState *s) /* indicate end of transfer */ if (s->data_in_index >= s->data_in_size) { ms->b = (ms->b | TREQ); + adb_autopoll_unblock(adb_bus); } cuda_delay_set_sr_int(s); } From cf093b0772ad43538ba45c1dececec7113ab3d03 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:31 +0100 Subject: [PATCH 1621/2595] pmu: add adb_autopoll_block() and adb_autopoll_unblock() functions Ensure that the PMU buffer is protected from autopoll requests overwriting its contents whilst existing PMU requests are in progress. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-18-mark.cave-ayland@ilande.co.uk> --- hw/misc/macio/pmu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index 01d49e6695..598d8e7517 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -517,6 +517,7 @@ static void pmu_update(PMUState *s) { MOS6522PMUState *mps = &s->mos6522_pmu; MOS6522State *ms = MOS6522(mps); + ADBBusState *adb_bus = &s->adb_bus; /* Only react to changes in reg B */ if (ms->b == s->last_b) { @@ -578,6 +579,7 @@ static void pmu_update(PMUState *s) s->cmd_rsp_pos = 0; s->cmd_state = pmu_state_cmd; + adb_autopoll_block(adb_bus); trace_pmu_debug_protocol_cmd(s->cmd, s->cmdlen, s->rsplen); break; @@ -636,6 +638,7 @@ static void pmu_update(PMUState *s) if (s->cmd_state == pmu_state_rsp && s->rsplen == s->cmd_rsp_pos) { trace_pmu_debug_protocol_cmd_resp_complete(ms->ier); + adb_autopoll_unblock(adb_bus); s->cmd_state = pmu_state_idle; } } From 378a50347931e71b15aaec44c4dc0f9adfa346bf Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:32 +0100 Subject: [PATCH 1622/2595] mac_via: move VIA1 portB write logic into mos6522_q800_via1_write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the logic is split between the mos6522 portB_write() callback and the memory region used to capture the VIA1 MMIO accesses. Move everything into the latter mos6522_q800_via1_write() function to keep all the logic in one place to make it easier to follow. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-19-mark.cave-ayland@ilande.co.uk> --- hw/misc/mac_via.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 7a28bb37ac..a1dc00d9f6 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -801,11 +801,21 @@ static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(opaque); + MacVIAState *m = container_of(v1s, MacVIAState, mos6522_via1); MOS6522State *ms = MOS6522(v1s); addr = (addr >> 9) & 0xf; mos6522_write(ms, addr, val, size); + switch (addr) { + case VIA_REG_B: + via1_rtc_update(m); + via1_adb_update(m); + + v1s->last_b = ms->b; + break; + } + via1_one_second_update(v1s); via1_VBL_update(v1s); } @@ -1037,18 +1047,6 @@ static TypeInfo mac_via_info = { }; /* VIA 1 */ -static void mos6522_q800_via1_portB_write(MOS6522State *s) -{ - MOS6522Q800VIA1State *v1s = container_of(s, MOS6522Q800VIA1State, - parent_obj); - MacVIAState *m = container_of(v1s, MacVIAState, mos6522_via1); - - via1_rtc_update(m); - via1_adb_update(m); - - v1s->last_b = s->b; -} - static void mos6522_q800_via1_reset(DeviceState *dev) { MOS6522State *ms = MOS6522(dev); @@ -1071,10 +1069,8 @@ static void mos6522_q800_via1_init(Object *obj) static void mos6522_q800_via1_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); - MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc); dc->reset = mos6522_q800_via1_reset; - mdc->portB_write = mos6522_q800_via1_portB_write; } static const TypeInfo mos6522_q800_via1_type_info = { From 975fcedd3194b486916a4b13afbf8308edf5b1a1 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:33 +0100 Subject: [PATCH 1623/2595] mac_via: rework ADB state machine to be compatible with both MacOS and Linux The existing ADB state machine is designed to work with Linux which has a different interpretation of the state machine detailed in "Guide to the Macintosh Family Hardware". In particular the current Linux implementation includes an extra change to IDLE state when switching the VIA between send and receive modes which does not occur in MacOS, and omitting this transition causes the current mac_via ADB state machine to fail. Rework the ADB state machine accordingly so that it can enumerate and autopoll the ADB under both Linux and MacOS, including the addition of the new adb_autopoll_block() and adb_autopoll_unblock() functions. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-20-mark.cave-ayland@ilande.co.uk> --- hw/misc/mac_via.c | 407 +++++++++++++++++++++++++------------- hw/misc/trace-events | 3 + include/hw/misc/mac_via.h | 1 + 3 files changed, 276 insertions(+), 135 deletions(-) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index a1dc00d9f6..71b6f92645 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -599,176 +599,312 @@ static void via1_rtc_update(MacVIAState *m) m->cmd = REG_EMPTY; } -static int adb_via_poll(MacVIAState *s, int state, uint8_t *data) +static void adb_via_poll(void *opaque) { + MacVIAState *m = opaque; + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); + MOS6522State *s = MOS6522(v1s); + ADBBusState *adb_bus = &m->adb_bus; + uint8_t obuf[9]; + uint8_t *data = &s->sr; + int olen; + uint16_t pending; + + /* + * Setting vADBInt below indicates that an autopoll reply has been + * received, however we must block autopoll until the point where + * the entire reply has been read back to the host + */ + if (adb_bus->autopoll_blocked) { + return; + } else { + adb_autopoll_block(adb_bus); + } + + m->adb_data_in_index = 0; + m->adb_data_out_index = 0; + olen = adb_poll(adb_bus, obuf, adb_bus->autopoll_mask); + + if (olen > 0) { + /* Autopoll response */ + *data = obuf[0]; + olen--; + memcpy(m->adb_data_in, &obuf[1], olen); + m->adb_data_in_size = olen; + + s->b &= ~VIA1B_vADBInt; + qemu_irq_raise(m->adb_data_ready); + } else if (olen < 0) { + /* Bus timeout (device does not exist) */ + *data = 0xff; + s->b |= VIA1B_vADBInt; + adb_autopoll_unblock(adb_bus); + } else { + pending = adb_bus->pending & ~(1 << (m->adb_autopoll_cmd >> 4)); + + if (pending) { + /* + * Bus timeout (device exists but another device has data). Block + * autopoll so the OS can read out the first EVEN and first ODD + * byte to determine bus timeout and SRQ status + */ + *data = m->adb_autopoll_cmd; + s->b &= ~VIA1B_vADBInt; + + obuf[0] = 0xff; + obuf[1] = 0xff; + olen = 2; + + memcpy(m->adb_data_in, obuf, olen); + m->adb_data_in_size = olen; + + qemu_irq_raise(m->adb_data_ready); + } else { + /* Bus timeout (device exists but no other device has data) */ + *data = 0; + s->b |= VIA1B_vADBInt; + adb_autopoll_unblock(adb_bus); + } + } + + trace_via1_adb_poll(*data, (s->b & VIA1B_vADBInt) ? "+" : "-", + adb_bus->status, m->adb_data_in_index, olen); +} + +static int adb_via_send_len(uint8_t data) +{ + /* Determine the send length from the given ADB command */ + uint8_t cmd = data & 0xc; + uint8_t reg = data & 0x3; + + switch (cmd) { + case 0x8: + /* Listen command */ + switch (reg) { + case 2: + /* Register 2 is only used for the keyboard */ + return 3; + case 3: + /* + * Fortunately our devices only implement writes + * to register 3 which is fixed at 2 bytes + */ + return 3; + default: + qemu_log_mask(LOG_UNIMP, "ADB unknown length for register %d\n", + reg); + return 1; + } + default: + /* Talk, BusReset */ + return 1; + } +} + +static void adb_via_send(MacVIAState *s, int state, uint8_t data) +{ + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&s->mos6522_via1); + MOS6522State *ms = MOS6522(v1s); ADBBusState *adb_bus = &s->adb_bus; + uint16_t autopoll_mask; - if (state != ADB_STATE_IDLE) { - return 0; - } + switch (state) { + case ADB_STATE_NEW: + /* + * Command byte: vADBInt tells host autopoll data already present + * in VIA shift register and ADB transceiver + */ + adb_autopoll_block(adb_bus); - if (s->adb_data_in_size < s->adb_data_in_index) { - return 0; - } + if (adb_bus->status & ADB_STATUS_POLLREPLY) { + /* Tell the host the existing data is from autopoll */ + ms->b &= ~VIA1B_vADBInt; + } else { + ms->b |= VIA1B_vADBInt; + s->adb_data_out_index = 0; + s->adb_data_out[s->adb_data_out_index++] = data; + } - if (s->adb_data_out_index != 0) { - return 0; - } - - s->adb_data_in_index = 0; - s->adb_data_out_index = 0; - s->adb_data_in_size = adb_poll(adb_bus, s->adb_data_in, - adb_bus->autopoll_mask); - - if (s->adb_data_in_size) { - *data = s->adb_data_in[s->adb_data_in_index++]; + trace_via1_adb_send(" NEW", data, (ms->b & VIA1B_vADBInt) ? "+" : "-"); qemu_irq_raise(s->adb_data_ready); - } - - return s->adb_data_in_size; -} - -static int adb_via_send(MacVIAState *s, int state, uint8_t data) -{ - switch (state) { - case ADB_STATE_NEW: - s->adb_data_out_index = 0; break; - case ADB_STATE_EVEN: - if ((s->adb_data_out_index & 1) == 0) { - return 0; - } - break; - case ADB_STATE_ODD: - if (s->adb_data_out_index & 1) { - return 0; - } - break; - case ADB_STATE_IDLE: - return 0; - } - - assert(s->adb_data_out_index < sizeof(s->adb_data_out) - 1); - - s->adb_data_out[s->adb_data_out_index++] = data; - qemu_irq_raise(s->adb_data_ready); - return 1; -} - -static int adb_via_receive(MacVIAState *s, int state, uint8_t *data) -{ - switch (state) { - case ADB_STATE_NEW: - return 0; case ADB_STATE_EVEN: - if (s->adb_data_in_size <= 0) { - qemu_irq_raise(s->adb_data_ready); - return 0; - } - - if (s->adb_data_in_index >= s->adb_data_in_size) { - *data = 0; - qemu_irq_raise(s->adb_data_ready); - return 1; - } - - if ((s->adb_data_in_index & 1) == 0) { - return 0; - } - - break; - case ADB_STATE_ODD: - if (s->adb_data_in_size <= 0) { - qemu_irq_raise(s->adb_data_ready); - return 0; - } - - if (s->adb_data_in_index >= s->adb_data_in_size) { - *data = 0; - qemu_irq_raise(s->adb_data_ready); - return 1; - } - - if (s->adb_data_in_index & 1) { - return 0; - } + ms->b |= VIA1B_vADBInt; + s->adb_data_out[s->adb_data_out_index++] = data; + trace_via1_adb_send(state == ADB_STATE_EVEN ? "EVEN" : " ODD", + data, (ms->b & VIA1B_vADBInt) ? "+" : "-"); + qemu_irq_raise(s->adb_data_ready); break; case ADB_STATE_IDLE: - if (s->adb_data_out_index == 0) { - return 0; - } + return; + } - s->adb_data_in_size = adb_request(&s->adb_bus, s->adb_data_in, + /* If the command is complete, execute it */ + if (s->adb_data_out_index == adb_via_send_len(s->adb_data_out[0])) { + s->adb_data_in_size = adb_request(adb_bus, s->adb_data_in, s->adb_data_out, s->adb_data_out_index); - s->adb_data_out_index = 0; s->adb_data_in_index = 0; - if (s->adb_data_in_size < 0) { - *data = 0xff; - qemu_irq_raise(s->adb_data_ready); - return -1; + + if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) { + /* + * Bus timeout (but allow first EVEN and ODD byte to indicate + * timeout via vADBInt and SRQ status) + */ + s->adb_data_in[0] = 0xff; + s->adb_data_in[1] = 0xff; + s->adb_data_in_size = 2; } - if (s->adb_data_in_size == 0) { - return 0; + /* + * If last command is TALK, store it for use by autopoll and adjust + * the autopoll mask accordingly + */ + if ((s->adb_data_out[0] & 0xc) == 0xc) { + s->adb_autopoll_cmd = s->adb_data_out[0]; + + autopoll_mask = 1 << (s->adb_autopoll_cmd >> 4); + adb_set_autopoll_mask(adb_bus, autopoll_mask); } + } +} + +static void adb_via_receive(MacVIAState *s, int state, uint8_t *data) +{ + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&s->mos6522_via1); + MOS6522State *ms = MOS6522(v1s); + ADBBusState *adb_bus = &s->adb_bus; + uint16_t pending; + + switch (state) { + case ADB_STATE_NEW: + ms->b |= VIA1B_vADBInt; + return; + + case ADB_STATE_IDLE: + /* + * Since adb_request() will have already consumed the data from the + * device, we must detect this extra state change and re-inject the + * reponse as either a "fake" autopoll reply or bus timeout + * accordingly + */ + if (s->adb_data_in_index == 0) { + if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) { + *data = 0xff; + ms->b |= VIA1B_vADBInt; + qemu_irq_raise(s->adb_data_ready); + } else if (s->adb_data_in_size > 0) { + adb_bus->status = ADB_STATUS_POLLREPLY; + *data = s->adb_autopoll_cmd; + ms->b &= ~VIA1B_vADBInt; + qemu_irq_raise(s->adb_data_ready); + } + } else { + ms->b |= VIA1B_vADBInt; + adb_autopoll_unblock(adb_bus); + } + + trace_via1_adb_receive("IDLE", *data, + (ms->b & VIA1B_vADBInt) ? "+" : "-", adb_bus->status, + s->adb_data_in_index, s->adb_data_in_size); break; - } - assert(s->adb_data_in_index < sizeof(s->adb_data_in) - 1); + case ADB_STATE_EVEN: + case ADB_STATE_ODD: + switch (s->adb_data_in_index) { + case 0: + /* First EVEN byte: vADBInt indicates bus timeout */ + trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD", + *data, (ms->b & VIA1B_vADBInt) ? "+" : "-", + adb_bus->status, s->adb_data_in_index, + s->adb_data_in_size); - *data = s->adb_data_in[s->adb_data_in_index++]; - qemu_irq_raise(s->adb_data_ready); - if (*data == 0xff || *data == 0) { - return 0; + *data = s->adb_data_in[s->adb_data_in_index++]; + if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) { + ms->b &= ~VIA1B_vADBInt; + } else { + ms->b |= VIA1B_vADBInt; + } + break; + + case 1: + /* First ODD byte: vADBInt indicates SRQ */ + trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD", + *data, (ms->b & VIA1B_vADBInt) ? "+" : "-", + adb_bus->status, s->adb_data_in_index, + s->adb_data_in_size); + + *data = s->adb_data_in[s->adb_data_in_index++]; + pending = adb_bus->pending & ~(1 << (s->adb_autopoll_cmd >> 4)); + if (pending) { + ms->b &= ~VIA1B_vADBInt; + } else { + ms->b |= VIA1B_vADBInt; + } + break; + + default: + /* + * Otherwise vADBInt indicates end of data. Note that Linux + * specifically checks for the sequence 0x0 0xff to confirm the + * end of the poll reply, so provide these extra bytes below to + * keep it happy + */ + trace_via1_adb_receive(state == ADB_STATE_EVEN ? "EVEN" : " ODD", + *data, (ms->b & VIA1B_vADBInt) ? "+" : "-", + adb_bus->status, s->adb_data_in_index, + s->adb_data_in_size); + + if (s->adb_data_in_index < s->adb_data_in_size) { + /* Next data byte */ + *data = s->adb_data_in[s->adb_data_in_index++]; + ms->b |= VIA1B_vADBInt; + } else if (s->adb_data_in_index == s->adb_data_in_size) { + if (adb_bus->status & ADB_STATUS_BUSTIMEOUT) { + /* Bus timeout (no more data) */ + *data = 0xff; + } else { + /* Return 0x0 after reply */ + *data = 0; + } + s->adb_data_in_index++; + ms->b &= ~VIA1B_vADBInt; + } else { + /* Bus timeout (no more data) */ + *data = 0xff; + ms->b &= ~VIA1B_vADBInt; + adb_bus->status = 0; + adb_autopoll_unblock(adb_bus); + } + break; + } + + qemu_irq_raise(s->adb_data_ready); + break; } - return 1; } static void via1_adb_update(MacVIAState *m) { MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); MOS6522State *s = MOS6522(v1s); - int state; - int ret; + int oldstate, state; + oldstate = (v1s->last_b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift; state = (s->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift; - if (s->acr & VIA1ACR_vShiftOut) { - /* output mode */ - ret = adb_via_send(m, state, s->sr); - if (ret > 0) { - s->b &= ~VIA1B_vADBInt; + if (state != oldstate) { + if (s->acr & VIA1ACR_vShiftOut) { + /* output mode */ + adb_via_send(m, state, s->sr); } else { - s->b |= VIA1B_vADBInt; - } - } else { - /* input mode */ - ret = adb_via_receive(m, state, &s->sr); - if (ret > 0 && s->sr != 0xff) { - s->b &= ~VIA1B_vADBInt; - } else { - s->b |= VIA1B_vADBInt; - } - } -} - -static void via_adb_poll(void *opaque) -{ - MacVIAState *m = opaque; - MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); - MOS6522State *s = MOS6522(v1s); - int state; - - if (s->b & VIA1B_vADBInt) { - state = (s->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift; - if (adb_via_poll(m, state, &s->sr)) { - s->b &= ~VIA1B_vADBInt; + /* input mode */ + adb_via_receive(m, state, &s->sr); } } } @@ -916,7 +1052,7 @@ static void mac_via_realize(DeviceState *dev, Error **errp) qemu_get_timedate(&tm, 0); m->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; - adb_register_autopoll_callback(adb_bus, via_adb_poll, m); + adb_register_autopoll_callback(adb_bus, adb_via_poll, m); m->adb_data_ready = qdev_get_gpio_in_named(dev, "via1-irq", VIA1_IRQ_ADB_READY_BIT); @@ -1019,6 +1155,7 @@ static const VMStateDescription vmstate_mac_via = { VMSTATE_INT32(adb_data_out_index, MacVIAState), VMSTATE_BUFFER(adb_data_in, MacVIAState), VMSTATE_BUFFER(adb_data_out, MacVIAState), + VMSTATE_UINT8(adb_autopoll_cmd, MacVIAState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 5561746866..68a6d9f2ab 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -202,6 +202,9 @@ via1_rtc_cmd_pram_read(int addr, int value) "addr=%u value=0x%02x" via1_rtc_cmd_pram_write(int addr, int value) "addr=%u value=0x%02x" via1_rtc_cmd_pram_sect_read(int sector, int offset, int addr, int value) "sector=%u offset=%u addr=%d value=0x%02x" via1_rtc_cmd_pram_sect_write(int sector, int offset, int addr, int value) "sector=%u offset=%u addr=%d value=0x%02x" +via1_adb_send(const char *state, uint8_t data, const char *vadbint) "state %s data=0x%02x vADBInt=%s" +via1_adb_receive(const char *state, uint8_t data, const char *vadbint, int status, int index, int size) "state %s data=0x%02x vADBInt=%s status=0x%x index=%d size=%d" +via1_adb_poll(uint8_t data, const char *vadbint, int status, int index, int size) "data=0x%02x vADBInt=%s status=0x%x index=%d size=%d" # grlib_ahb_apb_pnp.c grlib_ahb_pnp_read(uint64_t addr, uint32_t value) "AHB PnP read addr:0x%03"PRIx64" data:0x%08x" diff --git a/include/hw/misc/mac_via.h b/include/hw/misc/mac_via.h index 2aaf9e27bf..0be05d649b 100644 --- a/include/hw/misc/mac_via.h +++ b/include/hw/misc/mac_via.h @@ -112,6 +112,7 @@ typedef struct MacVIAState { int adb_data_out_index; uint8_t adb_data_in[128]; uint8_t adb_data_out[16]; + uint8_t adb_autopoll_cmd; } MacVIAState; #endif From 913f47ef96990fc72135ec604b6bb1fe2d1e389a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:34 +0100 Subject: [PATCH 1624/2595] adb: only call autopoll callbacks when autopoll is not blocked Handle this at the ADB bus level so that individual implementations do not need to handle this themselves. Finally add an assert() into adb_request() to prevent developers from accidentally making an explicit ADB request without blocking autopoll. Signed-off-by: Mark Cave-Ayland Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-21-mark.cave-ayland@ilande.co.uk> --- hw/input/adb.c | 7 +++++-- hw/misc/mac_via.c | 6 +----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/input/adb.c b/hw/input/adb.c index 70aa1f4570..fe0f6c7ef3 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -86,10 +86,11 @@ static int do_adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) { + assert(s->autopoll_blocked); + return do_adb_request(s, obuf, buf, len); } -/* XXX: move that to cuda ? */ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask) { ADBDevice *d; @@ -181,7 +182,9 @@ static void adb_autopoll(void *opaque) { ADBBusState *s = opaque; - s->autopoll_cb(s->autopoll_cb_opaque); + if (!s->autopoll_blocked) { + s->autopoll_cb(s->autopoll_cb_opaque); + } timer_mod(s->autopoll_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 71b6f92645..d76d7b28d3 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -615,11 +615,7 @@ static void adb_via_poll(void *opaque) * received, however we must block autopoll until the point where * the entire reply has been read back to the host */ - if (adb_bus->autopoll_blocked) { - return; - } else { - adb_autopoll_block(adb_bus); - } + adb_autopoll_block(adb_bus); m->adb_data_in_index = 0; m->adb_data_out_index = 0; From fa6c9539645a2e2df9ef5c423ccfa7d849dee41a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:35 +0100 Subject: [PATCH 1625/2595] adb: use adb_device prefix for ADB device trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is to allow us to distinguish between ADB device events and ADB bus events separately. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-22-mark.cave-ayland@ilande.co.uk> --- hw/input/adb-kbd.c | 12 ++++++------ hw/input/adb-mouse.c | 12 ++++++------ hw/input/trace-events | 20 ++++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c index 23760ecf7b..3cfb6a7a20 100644 --- a/hw/input/adb-kbd.c +++ b/hw/input/adb-kbd.c @@ -243,7 +243,7 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, olen = 0; switch (cmd) { case ADB_WRITEREG: - trace_adb_kbd_writereg(reg, buf[1]); + trace_adb_device_kbd_writereg(reg, buf[1]); switch (reg) { case 2: /* LED status */ @@ -256,7 +256,7 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, case ADB_CMD_CHANGE_ID_AND_ACT: case ADB_CMD_CHANGE_ID_AND_ENABLE: d->devaddr = buf[1] & 0xf; - trace_adb_kbd_request_change_addr(d->devaddr); + trace_adb_device_kbd_request_change_addr(d->devaddr); break; default: d->devaddr = buf[1] & 0xf; @@ -270,8 +270,8 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, d->handler = buf[2]; } - trace_adb_kbd_request_change_addr_and_handler(d->devaddr, - d->handler); + trace_adb_device_kbd_request_change_addr_and_handler( + d->devaddr, d->handler); break; } } @@ -294,7 +294,7 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, olen = 2; break; } - trace_adb_kbd_readreg(reg, obuf[0], obuf[1]); + trace_adb_device_kbd_readreg(reg, obuf[0], obuf[1]); break; } return olen; @@ -321,7 +321,7 @@ static void adb_keyboard_event(DeviceState *dev, QemuConsole *src, /* FIXME: take handler into account when translating qcode */ keycode = qcode_to_adb_keycode[qcode]; if (keycode == NO_KEY) { /* We don't want to send this to the guest */ - trace_adb_kbd_no_key(); + trace_adb_device_kbd_no_key(); return; } if (evt->u.key.data->down == false) { /* if key release event */ diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c index e2359fd74d..577a38ff2e 100644 --- a/hw/input/adb-mouse.c +++ b/hw/input/adb-mouse.c @@ -121,7 +121,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, s->dx = 0; s->dy = 0; s->dz = 0; - trace_adb_mouse_flush(); + trace_adb_device_mouse_flush(); return 0; } @@ -130,7 +130,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, olen = 0; switch (cmd) { case ADB_WRITEREG: - trace_adb_mouse_writereg(reg, buf[1]); + trace_adb_device_mouse_writereg(reg, buf[1]); switch (reg) { case 2: break; @@ -152,7 +152,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, case ADB_CMD_CHANGE_ID_AND_ACT: case ADB_CMD_CHANGE_ID_AND_ENABLE: d->devaddr = buf[1] & 0xf; - trace_adb_mouse_request_change_addr(d->devaddr); + trace_adb_device_mouse_request_change_addr(d->devaddr); break; default: d->devaddr = buf[1] & 0xf; @@ -172,8 +172,8 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, d->handler = buf[2]; } - trace_adb_mouse_request_change_addr_and_handler(d->devaddr, - d->handler); + trace_adb_device_mouse_request_change_addr_and_handler( + d->devaddr, d->handler); break; } } @@ -191,7 +191,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, olen = 2; break; } - trace_adb_mouse_readreg(reg, obuf[0], obuf[1]); + trace_adb_device_mouse_readreg(reg, obuf[0], obuf[1]); break; } return olen; diff --git a/hw/input/trace-events b/hw/input/trace-events index a2888fd10c..6f0d78241c 100644 --- a/hw/input/trace-events +++ b/hw/input/trace-events @@ -1,18 +1,18 @@ # See docs/devel/tracing.txt for syntax documentation. # adb-kbd.c -adb_kbd_no_key(void) "Ignoring NO_KEY" -adb_kbd_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x" -adb_kbd_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x" -adb_kbd_request_change_addr(int devaddr) "change addr to 0x%x" -adb_kbd_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x" +adb_device_kbd_no_key(void) "Ignoring NO_KEY" +adb_device_kbd_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x" +adb_device_kbd_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x" +adb_device_kbd_request_change_addr(int devaddr) "change addr to 0x%x" +adb_device_kbd_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x" # adb-mouse.c -adb_mouse_flush(void) "flush" -adb_mouse_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x" -adb_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x" -adb_mouse_request_change_addr(int devaddr) "change addr to 0x%x" -adb_mouse_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x" +adb_device_mouse_flush(void) "flush" +adb_device_mouse_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x" +adb_device_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x" +adb_device_mouse_request_change_addr(int devaddr) "change addr to 0x%x" +adb_device_mouse_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x" # pckbd.c pckbd_kbd_read_data(uint32_t val) "0x%02x" From e590e7f01479a1d4544aac062fe9fdb986502294 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 23 Jun 2020 21:49:36 +0100 Subject: [PATCH 1626/2595] adb: add ADB bus trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Tested-by: Finn Thain Acked-by: Laurent Vivier Message-Id: <20200623204936.24064-23-mark.cave-ayland@ilande.co.uk> --- hw/input/adb.c | 21 ++++++++++++++++++++- hw/input/trace-events | 7 +++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/hw/input/adb.c b/hw/input/adb.c index fe0f6c7ef3..013fcc9c54 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -29,10 +29,18 @@ #include "qemu/module.h" #include "qemu/timer.h" #include "adb-internal.h" +#include "trace.h" /* error codes */ #define ADB_RET_NOTPRESENT (-2) +static const char *adb_commands[] = { + "RESET", "FLUSH", "(Reserved 0x2)", "(Reserved 0x3)", + "Reserved (0x4)", "(Reserved 0x5)", "(Reserved 0x6)", "(Reserved 0x7)", + "LISTEN r0", "LISTEN r1", "LISTEN r2", "LISTEN r3", + "TALK r0", "TALK r1", "TALK r2", "TALK r3", +}; + static void adb_device_reset(ADBDevice *d) { qdev_reset_all(DEVICE(d)); @@ -86,9 +94,16 @@ static int do_adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) { + int ret; + + trace_adb_bus_request(buf[0] >> 4, adb_commands[buf[0] & 0xf], len); + assert(s->autopoll_blocked); - return do_adb_request(s, obuf, buf, len); + ret = do_adb_request(s, obuf, buf, len); + + trace_adb_bus_request_done(buf[0] >> 4, adb_commands[buf[0] & 0xf], ret); + return ret; } int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask) @@ -161,6 +176,7 @@ void adb_set_autopoll_mask(ADBBusState *s, uint16_t mask) void adb_autopoll_block(ADBBusState *s) { s->autopoll_blocked = true; + trace_adb_bus_autopoll_block(s->autopoll_blocked); if (s->autopoll_enabled) { timer_del(s->autopoll_timer); @@ -170,6 +186,7 @@ void adb_autopoll_block(ADBBusState *s) void adb_autopoll_unblock(ADBBusState *s) { s->autopoll_blocked = false; + trace_adb_bus_autopoll_block(s->autopoll_blocked); if (s->autopoll_enabled) { timer_mod(s->autopoll_timer, @@ -183,7 +200,9 @@ static void adb_autopoll(void *opaque) ADBBusState *s = opaque; if (!s->autopoll_blocked) { + trace_adb_bus_autopoll_cb(s->autopoll_mask); s->autopoll_cb(s->autopoll_cb_opaque); + trace_adb_bus_autopoll_cb_done(s->autopoll_mask); } timer_mod(s->autopoll_timer, diff --git a/hw/input/trace-events b/hw/input/trace-events index 6f0d78241c..1dd8ad6018 100644 --- a/hw/input/trace-events +++ b/hw/input/trace-events @@ -14,6 +14,13 @@ adb_device_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x adb_device_mouse_request_change_addr(int devaddr) "change addr to 0x%x" adb_device_mouse_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x" +# adb.c +adb_bus_request(uint8_t addr, const char *cmd, int size) "device 0x%x %s cmdsize=%d" +adb_bus_request_done(uint8_t addr, const char *cmd, int size) "device 0x%x %s replysize=%d" +adb_bus_autopoll_block(bool blocked) "blocked: %d" +adb_bus_autopoll_cb(uint16_t mask) "executing autopoll_cb with autopoll mask 0x%x" +adb_bus_autopoll_cb_done(uint16_t mask) "done executing autopoll_cb with autopoll mask 0x%x" + # pckbd.c pckbd_kbd_read_data(uint32_t val) "0x%02x" pckbd_kbd_read_status(int status) "0x%02x" From 494cd11d769ad1681c5914f8be7aa93ef497591f Mon Sep 17 00:00:00 2001 From: Jay Zhou Date: Wed, 4 Mar 2020 10:55:54 +0800 Subject: [PATCH 1627/2595] kvm: support to get/set dirty log initial-all-set capability Since the new capability KVM_DIRTY_LOG_INITIALLY_SET of KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 has been introduced in the kernel, tweak the userspace side to detect and enable this capability. Signed-off-by: Jay Zhou Reviewed-by: Peter Xu Message-Id: <20200304025554.2159-1-jianjay.zhou@huawei.com> Signed-off-by: Paolo Bonzini --- accel/kvm/kvm-all.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index f24d7da783..d54a8701d8 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -101,7 +101,7 @@ struct KVMState bool kernel_irqchip_required; OnOffAuto kernel_irqchip_split; bool sync_mmu; - bool manual_dirty_log_protect; + uint64_t manual_dirty_log_protect; /* The man page (and posix) say ioctl numbers are signed int, but * they're not. Linux, glibc and *BSD all treat ioctl numbers as * unsigned, and treating them as signed here can break things */ @@ -1995,6 +1995,7 @@ static int kvm_init(MachineState *ms) int ret; int type = 0; const char *kvm_type; + uint64_t dirty_log_manual_caps; s = KVM_STATE(ms->accelerator); @@ -2120,14 +2121,20 @@ static int kvm_init(MachineState *ms) s->coalesced_pio = s->coalesced_mmio && kvm_check_extension(s, KVM_CAP_COALESCED_PIO); - s->manual_dirty_log_protect = + dirty_log_manual_caps = kvm_check_extension(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2); - if (s->manual_dirty_log_protect) { - ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0, 1); + dirty_log_manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | + KVM_DIRTY_LOG_INITIALLY_SET); + s->manual_dirty_log_protect = dirty_log_manual_caps; + if (dirty_log_manual_caps) { + ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0, + dirty_log_manual_caps); if (ret) { - warn_report("Trying to enable KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 " - "but failed. Falling back to the legacy mode. "); - s->manual_dirty_log_protect = false; + warn_report("Trying to enable capability %"PRIu64" of " + "KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 but failed. " + "Falling back to the legacy mode. ", + dirty_log_manual_caps); + s->manual_dirty_log_protect = 0; } } From ae2b72072bc401114ebb9f46abd67d07d4cabf10 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Fri, 12 Jun 2020 09:46:06 +0100 Subject: [PATCH 1628/2595] util/getauxval: Porting to FreeBSD getauxval feature From d7f9d40777d1ed7c9450b0be4f957da2993dfc72 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 12 Jun 2020 09:39:17 +0100 Subject: [PATCH] util/getauxval: Porting to FreeBSD getauxval feature FreeBSD has a similar API for auxiliary vector. Signed-off-by: David Carlier Message-Id: Signed-off-by: Paolo Bonzini --- util/getauxval.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/util/getauxval.c b/util/getauxval.c index 36afdfb9e6..b124107d61 100644 --- a/util/getauxval.c +++ b/util/getauxval.c @@ -98,6 +98,16 @@ unsigned long qemu_getauxval(unsigned long type) return 0; } +#elif defined(__FreeBSD__) +#include + +unsigned long qemu_getauxval(unsigned long type) +{ + unsigned long aux = 0; + elf_aux_info(type, &aux, sizeof(aux)); + return aux; +} + #else unsigned long qemu_getauxval(unsigned long type) From 89ed83d8b23c11d250c290593cad3ca839d5b053 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 23 Jun 2020 12:18:24 -0400 Subject: [PATCH 1629/2595] libqos: usb-hcd-ehci: use 32-bit write for config register The memory region ops have min_access_size == 4 so obey it. Tested-by: Thomas Huth Signed-off-by: Paolo Bonzini --- tests/qtest/usb-hcd-ehci-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/usb-hcd-ehci-test.c b/tests/qtest/usb-hcd-ehci-test.c index 5251d539e9..c51e8bb223 100644 --- a/tests/qtest/usb-hcd-ehci-test.c +++ b/tests/qtest/usb-hcd-ehci-test.c @@ -96,7 +96,7 @@ static void pci_ehci_port_1(void) static void pci_ehci_config(void) { /* hands over all ports from companion uhci to ehci */ - qpci_io_writew(ehci1.dev, ehci1.bar, 0x60, 1); + qpci_io_writel(ehci1.dev, ehci1.bar, 0x60, 1); } static void pci_uhci_port_2(void) From 4b7c06837ae0b1ff56473202a42e7e386f53d6db Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 23 Jun 2020 12:17:59 -0400 Subject: [PATCH 1630/2595] libqos: pci-pc: use 32-bit write for EJ register The memory region ops have min_access_size == 4 so obey it. Tested-by: Thomas Huth Signed-off-by: Paolo Bonzini --- tests/qtest/libqos/pci-pc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/libqos/pci-pc.c b/tests/qtest/libqos/pci-pc.c index 0bc591d1da..3bb2eb3ba8 100644 --- a/tests/qtest/libqos/pci-pc.c +++ b/tests/qtest/libqos/pci-pc.c @@ -186,7 +186,7 @@ void qpci_unplug_acpi_device_test(QTestState *qts, const char *id, uint8_t slot) g_assert(!qdict_haskey(response, "error")); qobject_unref(response); - qtest_outb(qts, ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot); + qtest_outl(qts, ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot); qtest_qmp_eventwait(qts, "DEVICE_DELETED"); } From 5d971f9e672507210e77d020d89e0e89165c8fc9 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 10 Jun 2020 09:47:49 -0400 Subject: [PATCH 1631/2595] memory: Revert "memory: accept mismatching sizes in memory_region_access_valid" Memory API documentation documents valid .min_access_size and .max_access_size fields and explains that any access outside these boundaries is blocked. This is what devices seem to assume. However this is not what the implementation does: it simply ignores the boundaries unless there's an "accepts" callback. Naturally, this breaks a bunch of devices. Revert to the documented behaviour. Devices that want to allow any access can just drop the valid field, or add the impl field to have accesses converted to appropriate length. Cc: qemu-stable@nongnu.org Reviewed-by: Richard Henderson Fixes: CVE-2020-13754 Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1842363 Fixes: a014ed07bd5a ("memory: accept mismatching sizes in memory_region_access_valid") Signed-off-by: Michael S. Tsirkin Message-Id: <20200610134731.1514409-1-mst@redhat.com> Signed-off-by: Paolo Bonzini --- memory.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/memory.c b/memory.c index 2f15a4b250..9200b20130 100644 --- a/memory.c +++ b/memory.c @@ -1352,35 +1352,24 @@ bool memory_region_access_valid(MemoryRegion *mr, bool is_write, MemTxAttrs attrs) { - int access_size_min, access_size_max; - int access_size, i; + if (mr->ops->valid.accepts + && !mr->ops->valid.accepts(mr->opaque, addr, size, is_write, attrs)) { + return false; + } if (!mr->ops->valid.unaligned && (addr & (size - 1))) { return false; } - if (!mr->ops->valid.accepts) { + /* Treat zero as compatibility all valid */ + if (!mr->ops->valid.max_access_size) { return true; } - access_size_min = mr->ops->valid.min_access_size; - if (!mr->ops->valid.min_access_size) { - access_size_min = 1; + if (size > mr->ops->valid.max_access_size + || size < mr->ops->valid.min_access_size) { + return false; } - - access_size_max = mr->ops->valid.max_access_size; - if (!mr->ops->valid.max_access_size) { - access_size_max = 4; - } - - access_size = MAX(MIN(size, access_size_max), access_size_min); - for (i = 0; i < size; i += access_size) { - if (!mr->ops->valid.accepts(mr->opaque, addr + i, access_size, - is_write, attrs)) { - return false; - } - } - return true; } From 255ae6e2158c743717bed76c9a2365ee4bcd326e Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 22 May 2020 09:47:58 +0300 Subject: [PATCH 1632/2595] replay: notify the main loop when there are no instructions When QEMU is executed in console mode without any external event sources, main loop may sleep for a very long time. But in case of replay there is another event source - event log. This patch adds main loop notification when the vCPU loop has nothing to do and main loop should process the inputs from the event log. Signed-off-by: Pavel Dovgalyuk Message-Id: <159013007895.28110.2020104406699709721.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- cpus.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/cpus.c b/cpus.c index 7317ae06b9..41d1c5099f 100644 --- a/cpus.c +++ b/cpus.c @@ -1374,6 +1374,13 @@ static int64_t tcg_get_icount_limit(void) } } +static void notify_aio_contexts(void) +{ + /* Wake up other AioContexts. */ + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); +} + static void handle_icount_deadline(void) { assert(qemu_in_vcpu_thread()); @@ -1382,9 +1389,7 @@ static void handle_icount_deadline(void) QEMU_TIMER_ATTR_ALL); if (deadline == 0) { - /* Wake up other AioContexts. */ - qemu_clock_notify(QEMU_CLOCK_VIRTUAL); - qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); + notify_aio_contexts(); } } } @@ -1407,6 +1412,10 @@ static void prepare_icount_for_run(CPUState *cpu) cpu->icount_extra = cpu->icount_budget - insns_left; replay_mutex_lock(); + + if (cpu->icount_budget == 0 && replay_has_checkpoint()) { + notify_aio_contexts(); + } } } From 677a3baba4356b91c7acfb5828dd9a598decda6a Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Fri, 22 May 2020 09:35:27 +0300 Subject: [PATCH 1633/2595] replay: synchronize on every virtual timer callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes virtual timer callbacks depend on order of virtual timer processing and warping of virtual clock. Therefore every callback should be logged to make replay deterministic. This patch creates a checkpoint before every virtual timer callback. With these checkpoints virtual timers processing and clock warping events order is completely deterministic. Signed-off-by: Pavel Dovgalyuk Acked-by: Alex Bennée -- v2: - remove mutex lock/unlock for virtual clock checkpoint since it is not process any asynchronous events (commit ca9759c2a92f528f256fef0e3922416f7bb47bf9) - bump record/replay log file version Message-Id: <159012932716.27256.8854065545365559921.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini --- replay/replay.c | 2 +- util/qemu-timer.c | 32 +++++++++----------------------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/replay/replay.c b/replay/replay.c index 7d93746c73..83ed9e0e24 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -22,7 +22,7 @@ /* Current version of the replay mechanism. Increase it when file format changes. */ -#define REPLAY_VERSION 0xe02009 +#define REPLAY_VERSION 0xe0200a /* Size of replay log header */ #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) diff --git a/util/qemu-timer.c b/util/qemu-timer.c index b6575a2cd5..f62b4feecd 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -501,7 +501,6 @@ bool timerlist_run_timers(QEMUTimerList *timer_list) bool progress = false; QEMUTimerCB *cb; void *opaque; - bool need_replay_checkpoint = false; if (!atomic_read(&timer_list->active_timers)) { return false; @@ -517,16 +516,6 @@ bool timerlist_run_timers(QEMUTimerList *timer_list) break; default: case QEMU_CLOCK_VIRTUAL: - if (replay_mode != REPLAY_MODE_NONE) { - /* Checkpoint for virtual clock is redundant in cases where - * it's being triggered with only non-EXTERNAL timers, because - * these timers don't change guest state directly. - * Since it has conditional dependence on specific timers, it is - * subject to race conditions and requires special handling. - * See below. - */ - need_replay_checkpoint = true; - } break; case QEMU_CLOCK_HOST: if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) { @@ -559,19 +548,16 @@ bool timerlist_run_timers(QEMUTimerList *timer_list) */ break; } - if (need_replay_checkpoint - && !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL)) { - /* once we got here, checkpoint clock only once */ - need_replay_checkpoint = false; + /* Checkpoint for virtual clock is redundant in cases where + * it's being triggered with only non-EXTERNAL timers, because + * these timers don't change guest state directly. + */ + if (replay_mode != REPLAY_MODE_NONE + && timer_list->clock->type == QEMU_CLOCK_VIRTUAL + && !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL) + && !replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) { qemu_mutex_unlock(&timer_list->active_timers_lock); - if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) { - goto out; - } - qemu_mutex_lock(&timer_list->active_timers_lock); - /* The lock was released; start over again in case the list was - * modified. - */ - continue; + goto out; } /* remove timer from the list before calling the callback */ From 21b2eca6fc48c6485f5c3b4ed813246839f0a4df Mon Sep 17 00:00:00 2001 From: Jingqi Liu Date: Wed, 29 Apr 2020 16:50:11 +0800 Subject: [PATCH 1634/2595] configure: add libdaxctl support Add a pair of configure options --{enable,disable}-libdaxctl to control whether QEMU is compiled with libdaxctl [1]. Libdaxctl is a utility library for managing the device dax subsystem. QEMU uses mmap(2) to maps vNVDIMM backends and aligns the mapping address to the page size (getpagesize(2)) by default. However, some types of backends may require an alignment different than the page size. The 'align' option is provided to memory-backend-file to allow users to specify the proper alignment. For device dax (e.g., /dev/dax0.0), the 'align' option needs to match the alignment requirement of the device dax, which can be fetched through the APIs of libdaxctl version 57 or up. [1] Libdaxctl is a part of ndctl project. The project's repository is: https://github.com/pmem/ndctl For more information about libdaxctl APIs, you can refer to the comments in source code of: pmem/ndctl/daxctl/lib/libdaxctl.c. Reviewed-by: Joao Martins Signed-off-by: Jingqi Liu Message-Id: <20200429085011.63752-4-jingqi.liu@intel.com> Signed-off-by: Paolo Bonzini --- configure | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/configure b/configure index ba88fd1824..8d9435a0e0 100755 --- a/configure +++ b/configure @@ -517,6 +517,7 @@ plugins="no" fuzzing="no" rng_none="no" secret_keyring="" +libdaxctl="" supported_cpu="no" supported_os="no" @@ -1621,6 +1622,10 @@ for opt do ;; --disable-keyring) secret_keyring="no" ;; + --enable-libdaxctl) libdaxctl=yes + ;; + --disable-libdaxctl) libdaxctl=no + ;; *) echo "ERROR: unknown option $opt" echo "Try '$0 --help' for more information" @@ -1920,6 +1925,7 @@ disabled with --disable-FEATURE, default is enabled if available: libpmem libpmem support xkbcommon xkbcommon support rng-none dummy RNG, avoid using /dev/(u)random and getrandom() + libdaxctl libdaxctl support NOTE: The object files are built at the place where configure is launched EOF @@ -6292,6 +6298,24 @@ if test "$libpmem" != "no"; then fi fi +########################################## +# check for libdaxctl + +if test "$libdaxctl" != "no"; then + if $pkg_config --atleast-version=57 "libdaxctl"; then + libdaxctl="yes" + libdaxctl_libs=$($pkg_config --libs libdaxctl) + libdaxctl_cflags=$($pkg_config --cflags libdaxctl) + libs_softmmu="$libs_softmmu $libdaxctl_libs" + QEMU_CFLAGS="$QEMU_CFLAGS $libdaxctl_cflags" + else + if test "$libdaxctl" = "yes" ; then + feature_not_found "libdaxctl" "Install libdaxctl" + fi + libdaxctl="no" + fi +fi + ########################################## # check for slirp @@ -6898,6 +6922,7 @@ echo "parallels support $parallels" echo "sheepdog support $sheepdog" echo "capstone $capstone" echo "libpmem support $libpmem" +echo "libdaxctl support $libdaxctl" echo "libudev $libudev" echo "default devices $default_devices" echo "plugin support $plugins" @@ -7731,6 +7756,10 @@ if test "$libpmem" = "yes" ; then echo "CONFIG_LIBPMEM=y" >> $config_host_mak fi +if test "$libdaxctl" = "yes" ; then + echo "CONFIG_LIBDAXCTL=y" >> $config_host_mak +fi + if test "$bochs" = "yes" ; then echo "CONFIG_BOCHS=y" >> $config_host_mak fi From ce317be98db0dfdfae1d77b77e6b2575d7c59eeb Mon Sep 17 00:00:00 2001 From: Jingqi Liu Date: Wed, 29 Apr 2020 16:50:09 +0800 Subject: [PATCH 1635/2595] exec: fetch the alignment of Linux devdax pmem character device nodes If the backend file is devdax pmem character device, the alignment specified by the option 'align=NUM' in the '-object memory-backend-file' needs to match the alignment requirement of the devdax pmem character device. This patch uses the interfaces of libdaxctl to fetch the devdax pmem file 'align', so that we can compare it with the NUM of 'align=NUM'. The NUM needs to be larger than or equal to the devdax pmem file 'align'. It also fixes the problem that mmap() returns failure in qemu_ram_mmap() when the NUM of 'align=NUM' is less than the devdax pmem file 'align'. Suggested-by: Dan Williams Reviewed-by: Joao Martins Signed-off-by: Jingqi Liu Message-Id: <20200429085011.63752-2-jingqi.liu@intel.com> Signed-off-by: Paolo Bonzini --- exec.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index d6712fba7e..c5ab59ec44 100644 --- a/exec.c +++ b/exec.c @@ -77,6 +77,10 @@ #include "monitor/monitor.h" +#ifdef CONFIG_LIBDAXCTL +#include +#endif + //#define DEBUG_SUBPAGE #if !defined(CONFIG_USER_ONLY) @@ -1745,6 +1749,46 @@ static int64_t get_file_size(int fd) return size; } +static int64_t get_file_align(int fd) +{ + int64_t align = -1; +#if defined(__linux__) && defined(CONFIG_LIBDAXCTL) + struct stat st; + + if (fstat(fd, &st) < 0) { + return -errno; + } + + /* Special handling for devdax character devices */ + if (S_ISCHR(st.st_mode)) { + g_autofree char *path = NULL; + g_autofree char *rpath = NULL; + struct daxctl_ctx *ctx; + struct daxctl_region *region; + int rc = 0; + + path = g_strdup_printf("/sys/dev/char/%d:%d", + major(st.st_rdev), minor(st.st_rdev)); + rpath = realpath(path, NULL); + + rc = daxctl_new(&ctx); + if (rc) { + return -1; + } + + daxctl_region_foreach(ctx, region) { + if (strstr(rpath, daxctl_region_get_path(region))) { + align = daxctl_region_get_align(region); + break; + } + } + daxctl_unref(ctx); + } +#endif /* defined(__linux__) && defined(CONFIG_LIBDAXCTL) */ + + return align; +} + static int file_ram_open(const char *path, const char *region_name, bool *created, @@ -2296,7 +2340,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, { RAMBlock *new_block; Error *local_err = NULL; - int64_t file_size; + int64_t file_size, file_align; /* Just support these ram flags by now. */ assert((ram_flags & ~(RAM_SHARED | RAM_PMEM)) == 0); @@ -2332,6 +2376,14 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, return NULL; } + file_align = get_file_align(fd); + if (file_align > 0 && mr && file_align > mr->align) { + error_setg(errp, "backing store align 0x%" PRIx64 + " is larger than 'align' option 0x" PRIx64, + file_align, mr->align); + return NULL; + } + new_block = g_malloc0(sizeof(*new_block)); new_block->mr = mr; new_block->used_length = size; From f489960d36c49e91cf57c185b70cd028aa4976e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:21:30 +0200 Subject: [PATCH 1636/2595] hw/arm/aspeed: Remove extraneous MemoryRegion object owner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm confused by this code, 'bmc' is created as: bmc = g_new0(AspeedBoardState, 1); Then we use it as QOM owner for different MemoryRegion objects. But looking at memory_region_init_ram (similarly for ROM): void memory_region_init_ram(MemoryRegion *mr, struct Object *owner, const char *name, uint64_t size, Error **errp) { DeviceState *owner_dev; Error *err = NULL; memory_region_init_ram_nomigrate(mr, owner, name, size, &err); if (err) { error_propagate(errp, err); return; } /* This will assert if owner is neither NULL nor a DeviceState. * We only want the owner here for the purposes of defining a * unique name for migration. TODO: Ideally we should implement * a naming scheme for Objects which are not DeviceStates, in * which case we can relax this restriction. */ owner_dev = DEVICE(owner); vmstate_register_ram(mr, owner_dev); } The expected assertion is not triggered ('bmc' is not NULL neither a DeviceState). 'bmc' structure is defined as: struct AspeedBoardState { AspeedSoCState soc; MemoryRegion ram_container; MemoryRegion max_ram; }; What happens is when using 'OBJECT(bmc)', the QOM macros cast the memory pointed by bmc, which first member is 'soc', which is initialized ...: object_initialize_child(OBJECT(machine), "soc", &bmc->soc, amc->soc_name); The 'soc' object is indeed a DeviceState, so the assertion passes. Since this is fragile and only happens to work by luck, remove the dangerous OBJECT(bmc) owner argument. Note, this probably breaks migration for this machine. Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200623072132.2868-2-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 863757e1f0..167fd5ed1c 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -329,12 +329,12 @@ static void aspeed_machine_init(MachineState *machine) * needed by the flash modules of the Aspeed machines. */ if (ASPEED_MACHINE(machine)->mmio_exec) { - memory_region_init_alias(boot_rom, OBJECT(bmc), "aspeed.boot_rom", + memory_region_init_alias(boot_rom, NULL, "aspeed.boot_rom", &fl->mmio, 0, fl->size); memory_region_add_subregion(get_system_memory(), FIRMWARE_ADDR, boot_rom); } else { - memory_region_init_rom(boot_rom, OBJECT(bmc), "aspeed.boot_rom", + memory_region_init_rom(boot_rom, NULL, "aspeed.boot_rom", fl->size, &error_abort); memory_region_add_subregion(get_system_memory(), FIRMWARE_ADDR, boot_rom); @@ -345,7 +345,7 @@ static void aspeed_machine_init(MachineState *machine) if (machine->kernel_filename && sc->num_cpus > 1) { /* With no u-boot we must set up a boot stub for the secondary CPU */ MemoryRegion *smpboot = g_new(MemoryRegion, 1); - memory_region_init_ram(smpboot, OBJECT(bmc), "aspeed.smpboot", + memory_region_init_ram(smpboot, NULL, "aspeed.smpboot", 0x80, &error_abort); memory_region_add_subregion(get_system_memory(), AST_SMP_MAILBOX_BASE, smpboot); From 612b219a2a6e3d8192ce1d2408780be655f60359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:21:31 +0200 Subject: [PATCH 1637/2595] hw/arm/aspeed: Rename AspeedBoardState as AspeedMachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To have a more consistent naming, rename AspeedBoardState as AspeedMachineState. Suggested-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Message-id: 20200623072132.2868-3-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 20 ++++++++++---------- include/hw/arm/aspeed.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 167fd5ed1c..a167b73697 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -32,7 +32,7 @@ static struct arm_boot_info aspeed_board_binfo = { .board_id = -1, /* device-tree-only board */ }; -struct AspeedBoardState { +struct AspeedMachineState { AspeedSoCState soc; MemoryRegion ram_container; MemoryRegion max_ram; @@ -253,7 +253,7 @@ static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo) static void aspeed_machine_init(MachineState *machine) { - AspeedBoardState *bmc; + AspeedMachineState *bmc; AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine); AspeedSoCClass *sc; DriveInfo *drive0 = drive_get(IF_MTD, 0, 0); @@ -261,7 +261,7 @@ static void aspeed_machine_init(MachineState *machine) int i; NICInfo *nd = &nd_table[0]; - bmc = g_new0(AspeedBoardState, 1); + bmc = g_new0(AspeedMachineState, 1); memory_region_init(&bmc->ram_container, NULL, "aspeed-ram-container", 4 * GiB); @@ -374,7 +374,7 @@ static void aspeed_machine_init(MachineState *machine) arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo); } -static void palmetto_bmc_i2c_init(AspeedBoardState *bmc) +static void palmetto_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; DeviceState *dev; @@ -396,7 +396,7 @@ static void palmetto_bmc_i2c_init(AspeedBoardState *bmc) object_property_set_int(OBJECT(dev), 110000, "temperature3", &error_abort); } -static void ast2500_evb_i2c_init(AspeedBoardState *bmc) +static void ast2500_evb_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; uint8_t *eeprom_buf = g_malloc0(8 * 1024); @@ -413,13 +413,13 @@ static void ast2500_evb_i2c_init(AspeedBoardState *bmc) i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32); } -static void ast2600_evb_i2c_init(AspeedBoardState *bmc) +static void ast2600_evb_i2c_init(AspeedMachineState *bmc) { /* Start with some devices on our I2C busses */ ast2500_evb_i2c_init(bmc); } -static void romulus_bmc_i2c_init(AspeedBoardState *bmc) +static void romulus_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; @@ -428,7 +428,7 @@ static void romulus_bmc_i2c_init(AspeedBoardState *bmc) i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32); } -static void swift_bmc_i2c_init(AspeedBoardState *bmc) +static void swift_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; @@ -457,7 +457,7 @@ static void swift_bmc_i2c_init(AspeedBoardState *bmc) i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 12), "tmp105", 0x4a); } -static void sonorapass_bmc_i2c_init(AspeedBoardState *bmc) +static void sonorapass_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; @@ -501,7 +501,7 @@ static void sonorapass_bmc_i2c_init(AspeedBoardState *bmc) } -static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc) +static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; uint8_t *eeprom_buf = g_malloc0(8 * 1024); diff --git a/include/hw/arm/aspeed.h b/include/hw/arm/aspeed.h index 95b4daece8..5114ba0bd4 100644 --- a/include/hw/arm/aspeed.h +++ b/include/hw/arm/aspeed.h @@ -11,7 +11,7 @@ #include "hw/boards.h" -typedef struct AspeedBoardState AspeedBoardState; +typedef struct AspeedMachineState AspeedMachineState; #define TYPE_ASPEED_MACHINE MACHINE_TYPE_NAME("aspeed") #define ASPEED_MACHINE(obj) \ @@ -45,7 +45,7 @@ typedef struct AspeedMachineClass { const char *spi_model; uint32_t num_cs; uint32_t macs_mask; - void (*i2c_init)(AspeedBoardState *bmc); + void (*i2c_init)(AspeedMachineState *bmc); } AspeedMachineClass; From 888b2b034a29fa8fe99417c9665e0d671a9f33fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:21:32 +0200 Subject: [PATCH 1638/2595] hw/arm/aspeed: QOM'ify AspeedMachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AspeedMachineState seems crippled. We use incorrectly 2 different structures to do the same thing. Merge them altogether: - Move AspeedMachine fields to AspeedMachineState - AspeedMachineState is now QOM - Remove unused AspeedMachine structure Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Message-id: 20200623072132.2868-4-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 11 +++++++---- include/hw/arm/aspeed.h | 8 +------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index a167b73697..665d04fbf6 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -33,9 +33,14 @@ static struct arm_boot_info aspeed_board_binfo = { }; struct AspeedMachineState { + /* Private */ + MachineState parent_obj; + /* Public */ + AspeedSoCState soc; MemoryRegion ram_container; MemoryRegion max_ram; + bool mmio_exec; }; /* Palmetto hardware value: 0x120CE416 */ @@ -253,7 +258,7 @@ static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo) static void aspeed_machine_init(MachineState *machine) { - AspeedMachineState *bmc; + AspeedMachineState *bmc = ASPEED_MACHINE(machine); AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine); AspeedSoCClass *sc; DriveInfo *drive0 = drive_get(IF_MTD, 0, 0); @@ -261,8 +266,6 @@ static void aspeed_machine_init(MachineState *machine) int i; NICInfo *nd = &nd_table[0]; - bmc = g_new0(AspeedMachineState, 1); - memory_region_init(&bmc->ram_container, NULL, "aspeed-ram-container", 4 * GiB); memory_region_add_subregion(&bmc->ram_container, 0, machine->ram); @@ -751,7 +754,7 @@ static const TypeInfo aspeed_machine_types[] = { }, { .name = TYPE_ASPEED_MACHINE, .parent = TYPE_MACHINE, - .instance_size = sizeof(AspeedMachine), + .instance_size = sizeof(AspeedMachineState), .instance_init = aspeed_machine_instance_init, .class_size = sizeof(AspeedMachineClass), .class_init = aspeed_machine_class_init, diff --git a/include/hw/arm/aspeed.h b/include/hw/arm/aspeed.h index 5114ba0bd4..09da9d9acc 100644 --- a/include/hw/arm/aspeed.h +++ b/include/hw/arm/aspeed.h @@ -15,13 +15,7 @@ typedef struct AspeedMachineState AspeedMachineState; #define TYPE_ASPEED_MACHINE MACHINE_TYPE_NAME("aspeed") #define ASPEED_MACHINE(obj) \ - OBJECT_CHECK(AspeedMachine, (obj), TYPE_ASPEED_MACHINE) - -typedef struct AspeedMachine { - MachineState parent_obj; - - bool mmio_exec; -} AspeedMachine; + OBJECT_CHECK(AspeedMachineState, (obj), TYPE_ASPEED_MACHINE) #define ASPEED_MAC0_ON (1 << 0) #define ASPEED_MAC1_ON (1 << 1) From d88c42ff2c5cdcaecd02e6b31ea4c134b02be084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:27:15 +0200 Subject: [PATCH 1639/2595] hw/i2c/core: Add i2c_try_create_slave() and i2c_realize_and_unref() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract i2c_try_create_slave() and i2c_realize_and_unref() from i2c_create_slave(). We can now set properties on a I2CSlave before it is realized. This is in line with the recent qdev/QOM changes merged in commit 6675a653d2e. Reviewed-by: Corey Minyard Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Markus Armbruster Tested-by: Cédric Le Goater Message-id: 20200623072723.6324-2-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/i2c/core.c | 18 ++++++++++++++++-- include/hw/i2c/i2c.h | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/hw/i2c/core.c b/hw/i2c/core.c index 1aac457a2a..acf34a12d6 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -267,13 +267,27 @@ const VMStateDescription vmstate_i2c_slave = { } }; -DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr) +DeviceState *i2c_try_create_slave(const char *name, uint8_t addr) { DeviceState *dev; dev = qdev_new(name); qdev_prop_set_uint8(dev, "address", addr); - qdev_realize_and_unref(dev, &bus->qbus, &error_fatal); + return dev; +} + +bool i2c_realize_and_unref(DeviceState *dev, I2CBus *bus, Error **errp) +{ + return qdev_realize_and_unref(dev, &bus->qbus, errp); +} + +DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr) +{ + DeviceState *dev; + + dev = i2c_try_create_slave(name, addr); + i2c_realize_and_unref(dev, bus, &error_fatal); + return dev; } diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index 4117211565..d6e3d85faf 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -80,6 +80,8 @@ int i2c_send(I2CBus *bus, uint8_t data); uint8_t i2c_recv(I2CBus *bus); DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr); +DeviceState *i2c_try_create_slave(const char *name, uint8_t addr); +bool i2c_realize_and_unref(DeviceState *dev, I2CBus *bus, Error **errp); /* lm832x.c */ void lm832x_key_event(DeviceState *dev, int key, int state); From 8208335b9539e7b5aa4702b36e2f9a8abd704079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:27:16 +0200 Subject: [PATCH 1640/2595] hw/misc/pca9552: Rename 'nr_leds' as 'pin_count' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCA9552 device does not expose LEDs, but simple pins to connnect LEDs to. To be clearer with the device model, rename 'nr_leds' as 'pin_count'. Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater Message-id: 20200623072723.6324-3-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/misc/pca9552.c | 10 +++++----- include/hw/misc/pca9552.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index cac729e35a..81da757a7e 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -37,7 +37,7 @@ static void pca9552_update_pin_input(PCA9552State *s) { int i; - for (i = 0; i < s->nr_leds; i++) { + for (i = 0; i < s->pin_count; i++) { uint8_t input_reg = PCA9552_INPUT0 + (i / 8); uint8_t input_shift = (i % 8); uint8_t config = pca9552_pin_get_config(s, i); @@ -185,7 +185,7 @@ static void pca9552_get_led(Object *obj, Visitor *v, const char *name, error_setg(errp, "%s: error reading %s", __func__, name); return; } - if (led < 0 || led > s->nr_leds) { + if (led < 0 || led > s->pin_count) { error_setg(errp, "%s invalid led %s", __func__, name); return; } @@ -228,7 +228,7 @@ static void pca9552_set_led(Object *obj, Visitor *v, const char *name, error_setg(errp, "%s: error reading %s", __func__, name); return; } - if (led < 0 || led > s->nr_leds) { + if (led < 0 || led > s->pin_count) { error_setg(errp, "%s invalid led %s", __func__, name); return; } @@ -291,9 +291,9 @@ static void pca9552_initfn(Object *obj) * PCA955X device */ s->max_reg = PCA9552_LS3; - s->nr_leds = 16; + s->pin_count = 16; - for (led = 0; led < s->nr_leds; led++) { + for (led = 0; led < s->pin_count; led++) { char *name; name = g_strdup_printf("led%d", led); diff --git a/include/hw/misc/pca9552.h b/include/hw/misc/pca9552.h index ebb43c63fe..bc5ed31087 100644 --- a/include/hw/misc/pca9552.h +++ b/include/hw/misc/pca9552.h @@ -26,7 +26,7 @@ typedef struct PCA9552State { uint8_t regs[PCA9552_NR_REGS]; uint8_t max_reg; - uint8_t nr_leds; + uint8_t pin_count; } PCA9552State; #endif From ec17228a25e7fd46287842322f8dc4923eccca92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:27:17 +0200 Subject: [PATCH 1641/2595] hw/misc/pca9552: Rename generic code as pca955x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various code from the PCA9552 device model is generic to the PCA955X family. We'll split the generic code in a base class in the next commit. To ease review, first do a dumb renaming. Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater Message-id: 20200623072723.6324-4-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/misc/pca9552.c | 80 +++++++++++++++++++-------------------- include/hw/misc/pca9552.h | 10 ++--- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index 81da757a7e..5681ff3b22 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -25,7 +25,7 @@ static const char *led_state[] = {"on", "off", "pwm0", "pwm1"}; -static uint8_t pca9552_pin_get_config(PCA9552State *s, int pin) +static uint8_t pca955x_pin_get_config(PCA955xState *s, int pin) { uint8_t reg = PCA9552_LS0 + (pin / 4); uint8_t shift = (pin % 4) << 1; @@ -33,14 +33,14 @@ static uint8_t pca9552_pin_get_config(PCA9552State *s, int pin) return extract32(s->regs[reg], shift, 2); } -static void pca9552_update_pin_input(PCA9552State *s) +static void pca955x_update_pin_input(PCA955xState *s) { int i; for (i = 0; i < s->pin_count; i++) { uint8_t input_reg = PCA9552_INPUT0 + (i / 8); uint8_t input_shift = (i % 8); - uint8_t config = pca9552_pin_get_config(s, i); + uint8_t config = pca955x_pin_get_config(s, i); switch (config) { case PCA9552_LED_ON: @@ -58,7 +58,7 @@ static void pca9552_update_pin_input(PCA9552State *s) } } -static uint8_t pca9552_read(PCA9552State *s, uint8_t reg) +static uint8_t pca955x_read(PCA955xState *s, uint8_t reg) { switch (reg) { case PCA9552_INPUT0: @@ -79,7 +79,7 @@ static uint8_t pca9552_read(PCA9552State *s, uint8_t reg) } } -static void pca9552_write(PCA9552State *s, uint8_t reg, uint8_t data) +static void pca955x_write(PCA955xState *s, uint8_t reg, uint8_t data) { switch (reg) { case PCA9552_PSC0: @@ -94,7 +94,7 @@ static void pca9552_write(PCA9552State *s, uint8_t reg, uint8_t data) case PCA9552_LS2: case PCA9552_LS3: s->regs[reg] = data; - pca9552_update_pin_input(s); + pca955x_update_pin_input(s); break; case PCA9552_INPUT0: @@ -110,7 +110,7 @@ static void pca9552_write(PCA9552State *s, uint8_t reg, uint8_t data) * after each byte is sent to or received by the device. The index * rollovers to 0 when the maximum register address is reached. */ -static void pca9552_autoinc(PCA9552State *s) +static void pca955x_autoinc(PCA955xState *s) { if (s->pointer != 0xFF && s->pointer & PCA9552_AUTOINC) { uint8_t reg = s->pointer & 0xf; @@ -120,12 +120,12 @@ static void pca9552_autoinc(PCA9552State *s) } } -static uint8_t pca9552_recv(I2CSlave *i2c) +static uint8_t pca955x_recv(I2CSlave *i2c) { - PCA9552State *s = PCA9552(i2c); + PCA955xState *s = PCA955X(i2c); uint8_t ret; - ret = pca9552_read(s, s->pointer & 0xf); + ret = pca955x_read(s, s->pointer & 0xf); /* * From the Specs: @@ -143,40 +143,40 @@ static uint8_t pca9552_recv(I2CSlave *i2c) __func__); } - pca9552_autoinc(s); + pca955x_autoinc(s); return ret; } -static int pca9552_send(I2CSlave *i2c, uint8_t data) +static int pca955x_send(I2CSlave *i2c, uint8_t data) { - PCA9552State *s = PCA9552(i2c); + PCA955xState *s = PCA955X(i2c); /* First byte sent by is the register address */ if (s->len == 0) { s->pointer = data; s->len++; } else { - pca9552_write(s, s->pointer & 0xf, data); + pca955x_write(s, s->pointer & 0xf, data); - pca9552_autoinc(s); + pca955x_autoinc(s); } return 0; } -static int pca9552_event(I2CSlave *i2c, enum i2c_event event) +static int pca955x_event(I2CSlave *i2c, enum i2c_event event) { - PCA9552State *s = PCA9552(i2c); + PCA955xState *s = PCA955X(i2c); s->len = 0; return 0; } -static void pca9552_get_led(Object *obj, Visitor *v, const char *name, +static void pca955x_get_led(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - PCA9552State *s = PCA9552(obj); + PCA955xState *s = PCA955X(obj); int led, rc, reg; uint8_t state; @@ -195,7 +195,7 @@ static void pca9552_get_led(Object *obj, Visitor *v, const char *name, * reading the INPUTx reg */ reg = PCA9552_LS0 + led / 4; - state = (pca9552_read(s, reg) >> (led % 8)) & 0x3; + state = (pca955x_read(s, reg) >> (led % 8)) & 0x3; visit_type_str(v, name, (char **)&led_state[state], errp); } @@ -209,10 +209,10 @@ static inline uint8_t pca955x_ledsel(uint8_t oldval, int led_num, int state) ((state & 0x3) << (led_num << 1)); } -static void pca9552_set_led(Object *obj, Visitor *v, const char *name, +static void pca955x_set_led(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - PCA9552State *s = PCA9552(obj); + PCA955xState *s = PCA955X(obj); Error *local_err = NULL; int led, rc, reg, val; uint8_t state; @@ -244,9 +244,9 @@ static void pca9552_set_led(Object *obj, Visitor *v, const char *name, } reg = PCA9552_LS0 + led / 4; - val = pca9552_read(s, reg); + val = pca955x_read(s, reg); val = pca955x_ledsel(val, led % 4, state); - pca9552_write(s, reg, val); + pca955x_write(s, reg, val); } static const VMStateDescription pca9552_vmstate = { @@ -254,17 +254,17 @@ static const VMStateDescription pca9552_vmstate = { .version_id = 0, .minimum_version_id = 0, .fields = (VMStateField[]) { - VMSTATE_UINT8(len, PCA9552State), - VMSTATE_UINT8(pointer, PCA9552State), - VMSTATE_UINT8_ARRAY(regs, PCA9552State, PCA9552_NR_REGS), - VMSTATE_I2C_SLAVE(i2c, PCA9552State), + VMSTATE_UINT8(len, PCA955xState), + VMSTATE_UINT8(pointer, PCA955xState), + VMSTATE_UINT8_ARRAY(regs, PCA955xState, PCA955X_NR_REGS), + VMSTATE_I2C_SLAVE(i2c, PCA955xState), VMSTATE_END_OF_LIST() } }; static void pca9552_reset(DeviceState *dev) { - PCA9552State *s = PCA9552(dev); + PCA955xState *s = PCA955X(dev); s->regs[PCA9552_PSC0] = 0xFF; s->regs[PCA9552_PWM0] = 0x80; @@ -275,15 +275,15 @@ static void pca9552_reset(DeviceState *dev) s->regs[PCA9552_LS2] = 0x55; s->regs[PCA9552_LS3] = 0x55; - pca9552_update_pin_input(s); + pca955x_update_pin_input(s); s->pointer = 0xFF; s->len = 0; } -static void pca9552_initfn(Object *obj) +static void pca955x_initfn(Object *obj) { - PCA9552State *s = PCA9552(obj); + PCA955xState *s = PCA955X(obj); int led; /* If support for the other PCA955X devices are implemented, these @@ -297,7 +297,7 @@ static void pca9552_initfn(Object *obj) char *name; name = g_strdup_printf("led%d", led); - object_property_add(obj, name, "bool", pca9552_get_led, pca9552_set_led, + object_property_add(obj, name, "bool", pca955x_get_led, pca955x_set_led, NULL, NULL); g_free(name); } @@ -308,9 +308,9 @@ static void pca9552_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - k->event = pca9552_event; - k->recv = pca9552_recv; - k->send = pca9552_send; + k->event = pca955x_event; + k->recv = pca955x_recv; + k->send = pca955x_send; dc->reset = pca9552_reset; dc->vmsd = &pca9552_vmstate; } @@ -318,14 +318,14 @@ static void pca9552_class_init(ObjectClass *klass, void *data) static const TypeInfo pca9552_info = { .name = TYPE_PCA9552, .parent = TYPE_I2C_SLAVE, - .instance_init = pca9552_initfn, - .instance_size = sizeof(PCA9552State), + .instance_init = pca955x_initfn, + .instance_size = sizeof(PCA955xState), .class_init = pca9552_class_init, }; -static void pca9552_register_types(void) +static void pca955x_register_types(void) { type_register_static(&pca9552_info); } -type_init(pca9552_register_types) +type_init(pca955x_register_types) diff --git a/include/hw/misc/pca9552.h b/include/hw/misc/pca9552.h index bc5ed31087..db527595a3 100644 --- a/include/hw/misc/pca9552.h +++ b/include/hw/misc/pca9552.h @@ -12,11 +12,11 @@ #include "hw/i2c/i2c.h" #define TYPE_PCA9552 "pca9552" -#define PCA9552(obj) OBJECT_CHECK(PCA9552State, (obj), TYPE_PCA9552) +#define PCA955X(obj) OBJECT_CHECK(PCA955xState, (obj), TYPE_PCA9552) -#define PCA9552_NR_REGS 10 +#define PCA955X_NR_REGS 10 -typedef struct PCA9552State { +typedef struct PCA955xState { /*< private >*/ I2CSlave i2c; /*< public >*/ @@ -24,9 +24,9 @@ typedef struct PCA9552State { uint8_t len; uint8_t pointer; - uint8_t regs[PCA9552_NR_REGS]; + uint8_t regs[PCA955X_NR_REGS]; uint8_t max_reg; uint8_t pin_count; -} PCA9552State; +} PCA955xState; #endif From 736132e455eea08e37fe21b4140b8088f2c0956b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:27:18 +0200 Subject: [PATCH 1642/2595] hw/misc/pca9552: Add generic PCA955xClass, parent of TYPE_PCA9552 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the code common to the PCA955x family in PCA955xClass, keeping the PCA9552 specific parts into pca9552_class_init(). Remove the 'TODO' comment added in commit 5141d4158cf. Suggested-by: Cédric Le Goater Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater Message-id: 20200623072723.6324-5-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/misc/pca9552.c | 66 ++++++++++++++++++++++++++++----------- include/hw/misc/pca9552.h | 6 ++-- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index 5681ff3b22..4de57dbe2e 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -4,6 +4,7 @@ * https://www.nxp.com/docs/en/application-note/AN264.pdf * * Copyright (c) 2017-2018, IBM Corporation. + * Copyright (c) 2020 Philippe Mathieu-Daudé * * This work is licensed under the terms of the GNU GPL, version 2 or * later. See the COPYING file in the top-level directory. @@ -18,6 +19,20 @@ #include "qapi/error.h" #include "qapi/visitor.h" +typedef struct PCA955xClass { + /*< private >*/ + I2CSlaveClass parent_class; + /*< public >*/ + + uint8_t pin_count; + uint8_t max_reg; +} PCA955xClass; + +#define PCA955X_CLASS(klass) \ + OBJECT_CLASS_CHECK(PCA955xClass, (klass), TYPE_PCA955X) +#define PCA955X_GET_CLASS(obj) \ + OBJECT_GET_CLASS(PCA955xClass, (obj), TYPE_PCA955X) + #define PCA9552_LED_ON 0x0 #define PCA9552_LED_OFF 0x1 #define PCA9552_LED_PWM0 0x2 @@ -35,9 +50,10 @@ static uint8_t pca955x_pin_get_config(PCA955xState *s, int pin) static void pca955x_update_pin_input(PCA955xState *s) { + PCA955xClass *k = PCA955X_GET_CLASS(s); int i; - for (i = 0; i < s->pin_count; i++) { + for (i = 0; i < k->pin_count; i++) { uint8_t input_reg = PCA9552_INPUT0 + (i / 8); uint8_t input_shift = (i % 8); uint8_t config = pca955x_pin_get_config(s, i); @@ -112,10 +128,12 @@ static void pca955x_write(PCA955xState *s, uint8_t reg, uint8_t data) */ static void pca955x_autoinc(PCA955xState *s) { + PCA955xClass *k = PCA955X_GET_CLASS(s); + if (s->pointer != 0xFF && s->pointer & PCA9552_AUTOINC) { uint8_t reg = s->pointer & 0xf; - reg = (reg + 1) % (s->max_reg + 1); + reg = (reg + 1) % (k->max_reg + 1); s->pointer = reg | PCA9552_AUTOINC; } } @@ -176,6 +194,7 @@ static int pca955x_event(I2CSlave *i2c, enum i2c_event event) static void pca955x_get_led(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { + PCA955xClass *k = PCA955X_GET_CLASS(obj); PCA955xState *s = PCA955X(obj); int led, rc, reg; uint8_t state; @@ -185,7 +204,7 @@ static void pca955x_get_led(Object *obj, Visitor *v, const char *name, error_setg(errp, "%s: error reading %s", __func__, name); return; } - if (led < 0 || led > s->pin_count) { + if (led < 0 || led > k->pin_count) { error_setg(errp, "%s invalid led %s", __func__, name); return; } @@ -212,6 +231,7 @@ static inline uint8_t pca955x_ledsel(uint8_t oldval, int led_num, int state) static void pca955x_set_led(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { + PCA955xClass *k = PCA955X_GET_CLASS(obj); PCA955xState *s = PCA955X(obj); Error *local_err = NULL; int led, rc, reg, val; @@ -228,7 +248,7 @@ static void pca955x_set_led(Object *obj, Visitor *v, const char *name, error_setg(errp, "%s: error reading %s", __func__, name); return; } - if (led < 0 || led > s->pin_count) { + if (led < 0 || led > k->pin_count) { error_setg(errp, "%s invalid led %s", __func__, name); return; } @@ -283,17 +303,11 @@ static void pca9552_reset(DeviceState *dev) static void pca955x_initfn(Object *obj) { - PCA955xState *s = PCA955X(obj); + PCA955xClass *k = PCA955X_GET_CLASS(obj); int led; - /* If support for the other PCA955X devices are implemented, these - * constant values might be part of class structure describing the - * PCA955X device - */ - s->max_reg = PCA9552_LS3; - s->pin_count = 16; - - for (led = 0; led < s->pin_count; led++) { + assert(k->pin_count <= PCA955X_PIN_COUNT_MAX); + for (led = 0; led < k->pin_count; led++) { char *name; name = g_strdup_printf("led%d", led); @@ -303,28 +317,44 @@ static void pca955x_initfn(Object *obj) } } -static void pca9552_class_init(ObjectClass *klass, void *data) +static void pca955x_class_init(ObjectClass *klass, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); k->event = pca955x_event; k->recv = pca955x_recv; k->send = pca955x_send; +} + +static const TypeInfo pca955x_info = { + .name = TYPE_PCA955X, + .parent = TYPE_I2C_SLAVE, + .instance_init = pca955x_initfn, + .instance_size = sizeof(PCA955xState), + .class_init = pca955x_class_init, + .abstract = true, +}; + +static void pca9552_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PCA955xClass *pc = PCA955X_CLASS(oc); + dc->reset = pca9552_reset; dc->vmsd = &pca9552_vmstate; + pc->max_reg = PCA9552_LS3; + pc->pin_count = 16; } static const TypeInfo pca9552_info = { .name = TYPE_PCA9552, - .parent = TYPE_I2C_SLAVE, - .instance_init = pca955x_initfn, - .instance_size = sizeof(PCA955xState), + .parent = TYPE_PCA955X, .class_init = pca9552_class_init, }; static void pca955x_register_types(void) { + type_register_static(&pca955x_info); type_register_static(&pca9552_info); } diff --git a/include/hw/misc/pca9552.h b/include/hw/misc/pca9552.h index db527595a3..90843b03b8 100644 --- a/include/hw/misc/pca9552.h +++ b/include/hw/misc/pca9552.h @@ -12,9 +12,11 @@ #include "hw/i2c/i2c.h" #define TYPE_PCA9552 "pca9552" -#define PCA955X(obj) OBJECT_CHECK(PCA955xState, (obj), TYPE_PCA9552) +#define TYPE_PCA955X "pca955x" +#define PCA955X(obj) OBJECT_CHECK(PCA955xState, (obj), TYPE_PCA955X) #define PCA955X_NR_REGS 10 +#define PCA955X_PIN_COUNT_MAX 16 typedef struct PCA955xState { /*< private >*/ @@ -25,8 +27,6 @@ typedef struct PCA955xState { uint8_t pointer; uint8_t regs[PCA955X_NR_REGS]; - uint8_t max_reg; - uint8_t pin_count; } PCA955xState; #endif From 2df252d8793097386d4972640653da93f7857da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:27:19 +0200 Subject: [PATCH 1643/2595] hw/misc/pca9552: Add a 'description' property for debugging purpose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a description field to distinguish between multiple devices. Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater Message-id: 20200623072723.6324-6-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/misc/pca9552.c | 18 ++++++++++++++++++ include/hw/misc/pca9552.h | 1 + 2 files changed, 19 insertions(+) diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index 4de57dbe2e..2cc52b0205 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qemu/module.h" +#include "hw/qdev-properties.h" #include "hw/misc/pca9552.h" #include "hw/misc/pca9552_regs.h" #include "migration/vmstate.h" @@ -317,13 +318,30 @@ static void pca955x_initfn(Object *obj) } } +static void pca955x_realize(DeviceState *dev, Error **errp) +{ + PCA955xState *s = PCA955X(dev); + + if (!s->description) { + s->description = g_strdup("pca-unspecified"); + } +} + +static Property pca955x_properties[] = { + DEFINE_PROP_STRING("description", PCA955xState, description), + DEFINE_PROP_END_OF_LIST(), +}; + static void pca955x_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); k->event = pca955x_event; k->recv = pca955x_recv; k->send = pca955x_send; + dc->realize = pca955x_realize; + device_class_set_props(dc, pca955x_properties); } static const TypeInfo pca955x_info = { diff --git a/include/hw/misc/pca9552.h b/include/hw/misc/pca9552.h index 90843b03b8..bf1a589137 100644 --- a/include/hw/misc/pca9552.h +++ b/include/hw/misc/pca9552.h @@ -27,6 +27,7 @@ typedef struct PCA955xState { uint8_t pointer; uint8_t regs[PCA955X_NR_REGS]; + char *description; /* For debugging purpose only */ } PCA955xState; #endif From b989b89f672597cc0e780b5ce95e604d4f49247a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:27:20 +0200 Subject: [PATCH 1644/2595] hw/misc/pca9552: Trace GPIO High/Low events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a trivial representation of the PCA9552 GPIOs. Example booting obmc-phosphor-image: $ qemu-system-arm -M witherspoon-bmc -trace pca955x_gpio_status 1592689902.327837:pca955x_gpio_status pca-unspecified GPIOs 0-15 [*...............] 1592689902.329934:pca955x_gpio_status pca-unspecified GPIOs 0-15 [**..............] 1592689902.330717:pca955x_gpio_status pca-unspecified GPIOs 0-15 [***.............] 1592689902.331431:pca955x_gpio_status pca-unspecified GPIOs 0-15 [****............] 1592689902.332163:pca955x_gpio_status pca-unspecified GPIOs 0-15 [****.........*..] 1592689902.332888:pca955x_gpio_status pca-unspecified GPIOs 0-15 [****.........**.] 1592689902.333629:pca955x_gpio_status pca-unspecified GPIOs 0-15 [****.........***] 1592690032.793289:pca955x_gpio_status pca-unspecified GPIOs 0-15 [****.........*.*] 1592690033.303163:pca955x_gpio_status pca-unspecified GPIOs 0-15 [****.........***] 1592690033.812962:pca955x_gpio_status pca-unspecified GPIOs 0-15 [****.........*.*] 1592690034.323234:pca955x_gpio_status pca-unspecified GPIOs 0-15 [****.........***] 1592690034.832922:pca955x_gpio_status pca-unspecified GPIOs 0-15 [****.........*.*] We notice the GPIO #14 (front-power LED) starts to blink. This LED is described in the witherspoon device-tree [*]: front-power { retain-state-shutdown; default-state = "keep"; gpios = <&pca0 14 GPIO_ACTIVE_LOW>; }; [*] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts?id=b1f9be9392f0#n140 Suggested-by: Cédric Le Goater Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater Message-id: 20200623072723.6324-7-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/misc/pca9552.c | 39 +++++++++++++++++++++++++++++++++++++++ hw/misc/trace-events | 3 +++ 2 files changed, 42 insertions(+) diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index 2cc52b0205..41f8ad213d 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -13,12 +13,14 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qemu/module.h" +#include "qemu/bitops.h" #include "hw/qdev-properties.h" #include "hw/misc/pca9552.h" #include "hw/misc/pca9552_regs.h" #include "migration/vmstate.h" #include "qapi/error.h" #include "qapi/visitor.h" +#include "trace.h" typedef struct PCA955xClass { /*< private >*/ @@ -49,6 +51,39 @@ static uint8_t pca955x_pin_get_config(PCA955xState *s, int pin) return extract32(s->regs[reg], shift, 2); } +/* Return INPUT status (bit #N belongs to GPIO #N) */ +static uint16_t pca955x_pins_get_status(PCA955xState *s) +{ + return (s->regs[PCA9552_INPUT1] << 8) | s->regs[PCA9552_INPUT0]; +} + +static void pca955x_display_pins_status(PCA955xState *s, + uint16_t previous_pins_status) +{ + PCA955xClass *k = PCA955X_GET_CLASS(s); + uint16_t pins_status, pins_changed; + int i; + + pins_status = pca955x_pins_get_status(s); + pins_changed = previous_pins_status ^ pins_status; + if (!pins_changed) { + return; + } + if (trace_event_get_state_backends(TRACE_PCA955X_GPIO_STATUS)) { + char *buf = g_newa(char, k->pin_count + 1); + + for (i = 0; i < k->pin_count; i++) { + if (extract32(pins_status, i, 1)) { + buf[i] = '*'; + } else { + buf[i] = '.'; + } + } + buf[i] = '\0'; + trace_pca955x_gpio_status(s->description, buf); + } +} + static void pca955x_update_pin_input(PCA955xState *s) { PCA955xClass *k = PCA955X_GET_CLASS(s); @@ -98,6 +133,8 @@ static uint8_t pca955x_read(PCA955xState *s, uint8_t reg) static void pca955x_write(PCA955xState *s, uint8_t reg, uint8_t data) { + uint16_t pins_status; + switch (reg) { case PCA9552_PSC0: case PCA9552_PWM0: @@ -110,8 +147,10 @@ static void pca955x_write(PCA955xState *s, uint8_t reg, uint8_t data) case PCA9552_LS1: case PCA9552_LS2: case PCA9552_LS3: + pins_status = pca955x_pins_get_status(s); s->regs[reg] = data; pca955x_update_pin_input(s); + pca955x_display_pins_status(s, pins_status); break; case PCA9552_INPUT0: diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 68a6d9f2ab..bd7bd37ea8 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -209,3 +209,6 @@ via1_adb_poll(uint8_t data, const char *vadbint, int status, int index, int size # grlib_ahb_apb_pnp.c grlib_ahb_pnp_read(uint64_t addr, uint32_t value) "AHB PnP read addr:0x%03"PRIx64" data:0x%08x" grlib_apb_pnp_read(uint64_t addr, uint32_t value) "APB PnP read addr:0x%03"PRIx64" data:0x%08x" + +# pca9552.c +pca955x_gpio_status(const char *description, const char *buf) "%s GPIOs 0-15 [%s]" From 15ce12cfdd3740d38a7ab19ad0f5c812ff649fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:27:21 +0200 Subject: [PATCH 1645/2595] hw/arm/aspeed: Describe each PCA9552 device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have 2 distinct PCA9552 devices. Set their description to distinguish them when looking at the trace events. Description name taken from: https://github.com/open-power/witherspoon-xml/blob/master/witherspoon.xml Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Corey Minyard Reviewed-by: Markus Armbruster Tested-by: Cédric Le Goater Message-id: 20200623072723.6324-8-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 665d04fbf6..379f9672a5 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -508,12 +508,15 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; uint8_t *eeprom_buf = g_malloc0(8 * 1024); + DeviceState *dev; /* Bus 3: TODO bmp280@77 */ /* Bus 3: TODO max31785@52 */ /* Bus 3: TODO dps310@76 */ - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), TYPE_PCA9552, - 0x60); + dev = i2c_try_create_slave(TYPE_PCA9552, 0x60); + qdev_prop_set_string(dev, "description", "pca1"); + i2c_realize_and_unref(dev, aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), + &error_fatal); i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), "tmp423", 0x4c); i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 5), "tmp423", 0x4c); @@ -528,8 +531,10 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc) smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), 0x51, eeprom_buf); - i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), TYPE_PCA9552, - 0x60); + dev = i2c_try_create_slave(TYPE_PCA9552, 0x60); + qdev_prop_set_string(dev, "description", "pca0"); + i2c_realize_and_unref(dev, aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), + &error_fatal); /* Bus 11: TODO ucd90160@64 */ } From d82ab2931d14c1d8aa27a330b03fe5bf944130cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:27:22 +0200 Subject: [PATCH 1646/2595] hw/misc/pca9552: Trace GPIO change events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Emit a trace event when a GPIO change its state. Example booting obmc-phosphor-image: $ qemu-system-arm -M witherspoon-bmc -trace pca955x_gpio_change 1592690552.687372:pca955x_gpio_change pca1 GPIO id:0 status: 0 -> 1 1592690552.690169:pca955x_gpio_change pca1 GPIO id:1 status: 0 -> 1 1592690552.691673:pca955x_gpio_change pca1 GPIO id:2 status: 0 -> 1 1592690552.696886:pca955x_gpio_change pca1 GPIO id:3 status: 0 -> 1 1592690552.698614:pca955x_gpio_change pca1 GPIO id:13 status: 0 -> 1 1592690552.699833:pca955x_gpio_change pca1 GPIO id:14 status: 0 -> 1 1592690552.700842:pca955x_gpio_change pca1 GPIO id:15 status: 0 -> 1 1592690683.841921:pca955x_gpio_change pca1 GPIO id:14 status: 1 -> 0 1592690683.861660:pca955x_gpio_change pca1 GPIO id:14 status: 0 -> 1 1592690684.371460:pca955x_gpio_change pca1 GPIO id:14 status: 1 -> 0 1592690684.882115:pca955x_gpio_change pca1 GPIO id:14 status: 0 -> 1 1592690685.391411:pca955x_gpio_change pca1 GPIO id:14 status: 1 -> 0 1592690685.901391:pca955x_gpio_change pca1 GPIO id:14 status: 0 -> 1 1592690686.411678:pca955x_gpio_change pca1 GPIO id:14 status: 1 -> 0 1592690686.921279:pca955x_gpio_change pca1 GPIO id:14 status: 0 -> 1 We notice the GPIO #14 (front-power LED) starts to blink. This LED is described in the witherspoon device-tree [*]: front-power { retain-state-shutdown; default-state = "keep"; gpios = <&pca0 14 GPIO_ACTIVE_LOW>; }; [*] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts?id=b1f9be9392f0#n140 Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater Message-id: 20200623072723.6324-9-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/misc/pca9552.c | 15 +++++++++++++++ hw/misc/trace-events | 1 + 2 files changed, 16 insertions(+) diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index 41f8ad213d..1c3ad57432 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -82,6 +82,21 @@ static void pca955x_display_pins_status(PCA955xState *s, buf[i] = '\0'; trace_pca955x_gpio_status(s->description, buf); } + if (trace_event_get_state_backends(TRACE_PCA955X_GPIO_CHANGE)) { + for (i = 0; i < k->pin_count; i++) { + if (extract32(pins_changed, i, 1)) { + unsigned new_state = extract32(pins_status, i, 1); + + /* + * We display the state using the PCA logic ("active-high"). + * This is not the state of the LED, which signal might be + * wired "active-low" on the board. + */ + trace_pca955x_gpio_change(s->description, i, + !new_state, new_state); + } + } + } } static void pca955x_update_pin_input(PCA955xState *s) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index bd7bd37ea8..ebea53735c 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -212,3 +212,4 @@ grlib_apb_pnp_read(uint64_t addr, uint32_t value) "APB PnP read addr:0x%03"PRIx6 # pca9552.c pca955x_gpio_status(const char *description, const char *buf) "%s GPIOs 0-15 [%s]" +pca955x_gpio_change(const char *description, unsigned id, unsigned prev_state, unsigned current_state) "%s GPIO id:%u status: %u -> %u" From 586f495b1e78c27e141ff432dd971eb41866fb80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 09:27:23 +0200 Subject: [PATCH 1647/2595] hw/misc/pca9552: Model qdev output GPIOs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCA9552 has 16 GPIOs which can be used as input, output or PWM mode. QEMU models the output GPIO with the qemu_irq type. Let the device expose the 16 GPIOs to allow us to later connect LEDs to these outputs. Reviewed-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Tested-by: Cédric Le Goater Message-id: 20200623072723.6324-10-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/misc/pca9552.c | 6 ++++++ include/hw/misc/pca9552.h | 1 + 2 files changed, 7 insertions(+) diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index 1c3ad57432..80caa9ec8f 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -17,6 +17,7 @@ #include "hw/qdev-properties.h" #include "hw/misc/pca9552.h" #include "hw/misc/pca9552_regs.h" +#include "hw/irq.h" #include "migration/vmstate.h" #include "qapi/error.h" #include "qapi/visitor.h" @@ -111,9 +112,11 @@ static void pca955x_update_pin_input(PCA955xState *s) switch (config) { case PCA9552_LED_ON: + qemu_set_irq(s->gpio[i], 1); s->regs[input_reg] |= 1 << input_shift; break; case PCA9552_LED_OFF: + qemu_set_irq(s->gpio[i], 0); s->regs[input_reg] &= ~(1 << input_shift); break; case PCA9552_LED_PWM0: @@ -374,11 +377,14 @@ static void pca955x_initfn(Object *obj) static void pca955x_realize(DeviceState *dev, Error **errp) { + PCA955xClass *k = PCA955X_GET_CLASS(dev); PCA955xState *s = PCA955X(dev); if (!s->description) { s->description = g_strdup("pca-unspecified"); } + + qdev_init_gpio_out(dev, s->gpio, k->pin_count); } static Property pca955x_properties[] = { diff --git a/include/hw/misc/pca9552.h b/include/hw/misc/pca9552.h index bf1a589137..600356fbf9 100644 --- a/include/hw/misc/pca9552.h +++ b/include/hw/misc/pca9552.h @@ -27,6 +27,7 @@ typedef struct PCA955xState { uint8_t pointer; uint8_t regs[PCA955X_NR_REGS]; + qemu_irq gpio[PCA955X_PIN_COUNT_MAX]; char *description; /* For debugging purpose only */ } PCA955xState; From c7fd0baac0c24defec66263799faa8618327b352 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:30:59 -0700 Subject: [PATCH 1648/2595] target/arm: Add isar tests for mte Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index cf66b8c7fb..ff70115801 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3814,6 +3814,16 @@ static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; } +static inline bool isar_feature_aa64_mte_insn_reg(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) != 0; +} + +static inline bool isar_feature_aa64_mte(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 2; +} + static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && From 252e8c69669599b4bcff802df300726300292f47 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:00 -0700 Subject: [PATCH 1649/2595] target/arm: Improve masking of SCR RES0 bits Protect reads of aa64 id registers with ARM_CP_STATE_AA64. Use this as a simpler test than arm_el_is_aa64, since EL3 cannot change mode. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 972a766730..a29f0a28d8 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2011,9 +2011,16 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) uint32_t valid_mask = 0x3fff; ARMCPU *cpu = env_archcpu(env); - if (arm_el_is_aa64(env, 3)) { + if (ri->state == ARM_CP_STATE_AA64) { value |= SCR_FW | SCR_AW; /* these two bits are RES1. */ valid_mask &= ~SCR_NET; + + if (cpu_isar_feature(aa64_lor, cpu)) { + valid_mask |= SCR_TLOR; + } + if (cpu_isar_feature(aa64_pauth, cpu)) { + valid_mask |= SCR_API | SCR_APK; + } } else { valid_mask &= ~(SCR_RW | SCR_ST); } @@ -2032,12 +2039,6 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) valid_mask &= ~SCR_SMD; } } - if (cpu_isar_feature(aa64_lor, cpu)) { - valid_mask |= SCR_TLOR; - } - if (cpu_isar_feature(aa64_pauth, cpu)) { - valid_mask |= SCR_API | SCR_APK; - } /* Clear all-context RES0 bits. */ value &= valid_mask; From f00faf130d5dcf64b04f71a95f14745845ca1014 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:01 -0700 Subject: [PATCH 1650/2595] target/arm: Add support for MTE to SCTLR_ELx This does not attempt to rectify all of the res0 bits, but does clear the mte bits when not enabled. Since there is no high-part mapping of SCTLR, aa32 mode cannot write to these bits. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index a29f0a28d8..8a0fb01581 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4698,6 +4698,22 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, { ARMCPU *cpu = env_archcpu(env); + if (arm_feature(env, ARM_FEATURE_PMSA) && !cpu->has_mpu) { + /* M bit is RAZ/WI for PMSA with no MPU implemented */ + value &= ~SCTLR_M; + } + + /* ??? Lots of these bits are not implemented. */ + + if (ri->state == ARM_CP_STATE_AA64 && !cpu_isar_feature(aa64_mte, cpu)) { + if (ri->opc1 == 6) { /* SCTLR_EL3 */ + value &= ~(SCTLR_ITFSB | SCTLR_TCF | SCTLR_ATA); + } else { + value &= ~(SCTLR_ITFSB | SCTLR_TCF0 | SCTLR_TCF | + SCTLR_ATA0 | SCTLR_ATA); + } + } + if (raw_read(env, ri) == value) { /* Skip the TLB flush if nothing actually changed; Linux likes * to do a lot of pointless SCTLR writes. @@ -4705,13 +4721,8 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, return; } - if (arm_feature(env, ARM_FEATURE_PMSA) && !cpu->has_mpu) { - /* M bit is RAZ/WI for PMSA with no MPU implemented */ - value &= ~SCTLR_M; - } - raw_write(env, ri, value); - /* ??? Lots of these bits are not implemented. */ + /* This may enable/disable the MMU, so do a TLB flush. */ tlb_flush(CPU(cpu)); From 8ddb300bf60a5f3d358dd6fbf81174f6c03c1d9f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:02 -0700 Subject: [PATCH 1651/2595] target/arm: Add support for MTE to HCR_EL2 and SCR_EL3 Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 8a0fb01581..d6c326b58e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2021,6 +2021,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) if (cpu_isar_feature(aa64_pauth, cpu)) { valid_mask |= SCR_API | SCR_APK; } + if (cpu_isar_feature(aa64_mte, cpu)) { + valid_mask |= SCR_ATA; + } } else { valid_mask &= ~(SCR_RW | SCR_ST); } @@ -5248,17 +5251,22 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) if (cpu_isar_feature(aa64_pauth, cpu)) { valid_mask |= HCR_API | HCR_APK; } + if (cpu_isar_feature(aa64_mte, cpu)) { + valid_mask |= HCR_ATA | HCR_DCT | HCR_TID5; + } } /* Clear RES0 bits. */ value &= valid_mask; - /* These bits change the MMU setup: + /* + * These bits change the MMU setup: * HCR_VM enables stage 2 translation * HCR_PTW forbids certain page-table setups - * HCR_DC Disables stage1 and enables stage2 translation + * HCR_DC disables stage1 and enables stage2 translation + * HCR_DCT enables tagging on (disabled) stage1 translation */ - if ((env->cp15.hcr_el2 ^ value) & (HCR_VM | HCR_PTW | HCR_DC)) { + if ((env->cp15.hcr_el2 ^ value) & (HCR_VM | HCR_PTW | HCR_DC | HCR_DCT)) { tlb_flush(CPU(cpu)); } env->cp15.hcr_el2 = value; From 14407ec2007e18536ed34772eef46f6e0a0e3d0e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:03 -0700 Subject: [PATCH 1652/2595] target/arm: Rename DISAS_UPDATE to DISAS_UPDATE_EXIT Emphasize that the is_jmp option exits to the main loop. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 8 ++++---- target/arm/translate-vfp.inc.c | 4 ++-- target/arm/translate.c | 12 ++++++------ target/arm/translate.h | 14 ++++++++------ 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 4cef862c41..e4795ae100 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1616,7 +1616,7 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, gen_helper_msr_i_daifclear(cpu_env, t1); tcg_temp_free_i32(t1); /* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs. */ - s->base.is_jmp = DISAS_UPDATE; + s->base.is_jmp = DISAS_UPDATE_EXIT; break; default: @@ -1795,7 +1795,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { /* I/O operations must end the TB here (whether read or write) */ - s->base.is_jmp = DISAS_UPDATE; + s->base.is_jmp = DISAS_UPDATE_EXIT; } if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) { /* @@ -1810,7 +1810,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, * but allow this to be suppressed by the register definition * (usually only necessary to work around guest bugs). */ - s->base.is_jmp = DISAS_UPDATE; + s->base.is_jmp = DISAS_UPDATE_EXIT; } } @@ -14292,7 +14292,7 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) gen_goto_tb(dc, 1, dc->base.pc_next); break; default: - case DISAS_UPDATE: + case DISAS_UPDATE_EXIT: gen_a64_set_pc_im(dc->base.pc_next); /* fall through */ case DISAS_EXIT: diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c index bf31b18657..afa8a5f888 100644 --- a/target/arm/translate-vfp.inc.c +++ b/target/arm/translate-vfp.inc.c @@ -123,7 +123,7 @@ static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled) * this to be the last insn in the TB). */ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - s->base.is_jmp = DISAS_UPDATE; + s->base.is_jmp = DISAS_UPDATE_EXIT; gen_io_start(); } gen_helper_v7m_preserve_fp_state(cpu_env); @@ -2860,6 +2860,6 @@ static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a) tcg_temp_free_i32(fptr); /* End the TB, because we have updated FP control bits */ - s->base.is_jmp = DISAS_UPDATE; + s->base.is_jmp = DISAS_UPDATE_EXIT; return true; } diff --git a/target/arm/translate.c b/target/arm/translate.c index 795964da1f..146ff5ddc2 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2775,7 +2775,7 @@ static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn) tcg_temp_free_i32(tcg_tgtmode); tcg_temp_free_i32(tcg_regno); tcg_temp_free_i32(tcg_reg); - s->base.is_jmp = DISAS_UPDATE; + s->base.is_jmp = DISAS_UPDATE_EXIT; } static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn) @@ -2797,7 +2797,7 @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn) tcg_temp_free_i32(tcg_tgtmode); tcg_temp_free_i32(tcg_regno); store_reg(s, rn, tcg_reg); - s->base.is_jmp = DISAS_UPDATE; + s->base.is_jmp = DISAS_UPDATE_EXIT; } /* Store value to PC as for an exception return (ie don't @@ -5114,7 +5114,7 @@ static void gen_srs(DisasContext *s, tcg_temp_free_i32(tmp); } tcg_temp_free_i32(addr); - s->base.is_jmp = DISAS_UPDATE; + s->base.is_jmp = DISAS_UPDATE_EXIT; } /* Generate a label used for skipping this instruction */ @@ -8160,7 +8160,7 @@ static bool trans_SETEND(DisasContext *s, arg_SETEND *a) } if (a->E != (s->be_data == MO_BE)) { gen_helper_setend(cpu_env); - s->base.is_jmp = DISAS_UPDATE; + s->base.is_jmp = DISAS_UPDATE_EXIT; } return true; } @@ -8873,7 +8873,7 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) break; case DISAS_NEXT: case DISAS_TOO_MANY: - case DISAS_UPDATE: + case DISAS_UPDATE_EXIT: gen_set_pc_im(dc, dc->base.pc_next); /* fall through */ default: @@ -8900,7 +8900,7 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_JUMP: gen_goto_ptr(); break; - case DISAS_UPDATE: + case DISAS_UPDATE_EXIT: gen_set_pc_im(dc, dc->base.pc_next); /* fall through */ default: diff --git a/target/arm/translate.h b/target/arm/translate.h index 19650a9e2d..d5edef2943 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -148,7 +148,8 @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) /* is_jmp field values */ #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ -#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ +/* CPU state was modified dynamically; exit to main loop for interrupts. */ +#define DISAS_UPDATE_EXIT DISAS_TARGET_1 /* These instructions trap after executing, so the A32/T32 decoder must * defer them until after the conditional execution state has been updated. * WFI also needs special handling when single-stepping. @@ -164,11 +165,12 @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) * custom end-of-TB code) */ #define DISAS_BX_EXCRET DISAS_TARGET_8 -/* For instructions which want an immediate exit to the main loop, - * as opposed to attempting to use lookup_and_goto_ptr. Unlike - * DISAS_UPDATE this doesn't write the PC on exiting the translation - * loop so you need to ensure something (gen_a64_set_pc_im or runtime - * helper) has done so before we reach return from cpu_tb_exec. +/* + * For instructions which want an immediate exit to the main loop, as opposed + * to attempting to use lookup_and_goto_ptr. Unlike DISAS_UPDATE_EXIT, this + * doesn't write the PC on exiting the translation loop so you need to ensure + * something (gen_a64_set_pc_im or runtime helper) has done so before we reach + * return from cpu_tb_exec. */ #define DISAS_EXIT DISAS_TARGET_9 From 329833286d7a1b0ef8c7daafe13c6ae32429694e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:04 -0700 Subject: [PATCH 1653/2595] target/arm: Add DISAS_UPDATE_NOCHAIN Add an option that writes back the PC, like DISAS_UPDATE_EXIT, but does not exit back to the main loop. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 3 +++ target/arm/translate.c | 4 ++++ target/arm/translate.h | 2 ++ 3 files changed, 9 insertions(+) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index e4795ae100..027be7d8c2 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14298,6 +14298,9 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_EXIT: tcg_gen_exit_tb(NULL, 0); break; + case DISAS_UPDATE_NOCHAIN: + gen_a64_set_pc_im(dc->base.pc_next); + /* fall through */ case DISAS_JUMP: tcg_gen_lookup_and_goto_ptr(); break; diff --git a/target/arm/translate.c b/target/arm/translate.c index 146ff5ddc2..c39a929b93 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -8874,6 +8874,7 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_NEXT: case DISAS_TOO_MANY: case DISAS_UPDATE_EXIT: + case DISAS_UPDATE_NOCHAIN: gen_set_pc_im(dc, dc->base.pc_next); /* fall through */ default: @@ -8897,6 +8898,9 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_TOO_MANY: gen_goto_tb(dc, 1, dc->base.pc_next); break; + case DISAS_UPDATE_NOCHAIN: + gen_set_pc_im(dc, dc->base.pc_next); + /* fall through */ case DISAS_JUMP: gen_goto_ptr(); break; diff --git a/target/arm/translate.h b/target/arm/translate.h index d5edef2943..6dfe24cedc 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -173,6 +173,8 @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) * return from cpu_tb_exec. */ #define DISAS_EXIT DISAS_TARGET_9 +/* CPU state was modified dynamically; no need to exit, but do not chain. */ +#define DISAS_UPDATE_NOCHAIN DISAS_TARGET_10 #ifdef TARGET_AARCH64 void a64_translate_init(void); From 4b779cebb3e5ab30b945181f1ba3932f5f8a1cb5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:05 -0700 Subject: [PATCH 1654/2595] target/arm: Add MTE system registers This is TFSRE0_EL1, TFSR_EL1, TFSR_EL2, TFSR_EL3, RGSR_EL1, GCR_EL1, GMID_EL1, and PSTATE.TCO. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 4 ++ target/arm/helper.c | 94 ++++++++++++++++++++++++++++++++++++++ target/arm/internals.h | 9 ++++ target/arm/translate-a64.c | 21 +++++++++ 4 files changed, 128 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index ff70115801..0a98b6a06d 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -502,6 +502,9 @@ typedef struct CPUARMState { uint64_t pmccfiltr_el0; /* Performance Monitor Filter Register */ uint64_t vpidr_el2; /* Virtualization Processor ID Register */ uint64_t vmpidr_el2; /* Virtualization Multiprocessor ID Register */ + uint64_t tfsr_el[4]; /* tfsre0_el1 is index 0. */ + uint64_t gcr_el1; + uint64_t rgsr_el1; } cp15; struct { @@ -1282,6 +1285,7 @@ void pmu_init(ARMCPU *cpu); #define PSTATE_SS (1U << 21) #define PSTATE_PAN (1U << 22) #define PSTATE_UAO (1U << 23) +#define PSTATE_TCO (1U << 25) #define PSTATE_V (1U << 28) #define PSTATE_C (1U << 29) #define PSTATE_Z (1U << 30) diff --git a/target/arm/helper.c b/target/arm/helper.c index d6c326b58e..b4842ea23e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5881,6 +5881,9 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) { K(3, 0, 1, 2, 0), K(3, 4, 1, 2, 0), K(3, 5, 1, 2, 0), "ZCR_EL1", "ZCR_EL2", "ZCR_EL12", isar_feature_aa64_sve }, + { K(3, 0, 5, 6, 0), K(3, 4, 5, 6, 0), K(3, 5, 5, 6, 0), + "TFSR_EL1", "TFSR_EL2", "TFSR_EL12", isar_feature_aa64_mte }, + /* TODO: ARMv8.2-SPE -- PMSCR_EL2 */ /* TODO: ARMv8.4-Trace -- TRFCR_EL2 */ }; @@ -6855,6 +6858,86 @@ static const ARMCPRegInfo dcpodp_reg[] = { }; #endif /*CONFIG_USER_ONLY*/ +static CPAccessResult access_aa64_tid5(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if ((arm_current_el(env) < 2) && (arm_hcr_el2_eff(env) & HCR_TID5)) { + return CP_ACCESS_TRAP_EL2; + } + + return CP_ACCESS_OK; +} + +static CPAccessResult access_mte(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + int el = arm_current_el(env); + + if (el < 2 && + arm_feature(env, ARM_FEATURE_EL2) && + !(arm_hcr_el2_eff(env) & HCR_ATA)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 && + arm_feature(env, ARM_FEATURE_EL3) && + !(env->cp15.scr_el3 & SCR_ATA)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +static uint64_t tco_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return env->pstate & PSTATE_TCO; +} + +static void tco_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val) +{ + env->pstate = (env->pstate & ~PSTATE_TCO) | (val & PSTATE_TCO); +} + +static const ARMCPRegInfo mte_reginfo[] = { + { .name = "TFSRE0_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 6, .opc2 = 1, + .access = PL1_RW, .accessfn = access_mte, + .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[0]) }, + { .name = "TFSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 6, .opc2 = 0, + .access = PL1_RW, .accessfn = access_mte, + .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) }, + { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 6, .opc2 = 0, + .access = PL2_RW, .accessfn = access_mte, + .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[2]) }, + { .name = "TFSR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 5, .crm = 6, .opc2 = 0, + .access = PL3_RW, + .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[3]) }, + { .name = "RGSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 5, + .access = PL1_RW, .accessfn = access_mte, + .fieldoffset = offsetof(CPUARMState, cp15.rgsr_el1) }, + { .name = "GCR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 6, + .access = PL1_RW, .accessfn = access_mte, + .fieldoffset = offsetof(CPUARMState, cp15.gcr_el1) }, + { .name = "GMID_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 4, + .access = PL1_R, .accessfn = access_aa64_tid5, + .type = ARM_CP_CONST, .resetvalue = GMID_EL1_BS }, + { .name = "TCO", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 7, + .type = ARM_CP_NO_RAW, + .access = PL0_RW, .readfn = tco_read, .writefn = tco_write }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo mte_tco_ro_reginfo[] = { + { .name = "TCO", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 7, + .type = ARM_CP_CONST, .access = PL0_RW, }, + REGINFO_SENTINEL +}; #endif static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri, @@ -7980,6 +8063,17 @@ void register_cp_regs_for_features(ARMCPU *cpu) } } #endif /*CONFIG_USER_ONLY*/ + + /* + * If full MTE is enabled, add all of the system registers. + * If only "instructions available at EL0" are enabled, + * then define only a RAZ/WI version of PSTATE.TCO. + */ + if (cpu_isar_feature(aa64_mte, cpu)) { + define_arm_cp_regs(cpu, mte_reginfo); + } else if (cpu_isar_feature(aa64_mte_insn_reg, cpu)) { + define_arm_cp_regs(cpu, mte_tco_ro_reginfo); + } #endif if (cpu_isar_feature(any_predinv, cpu)) { diff --git a/target/arm/internals.h b/target/arm/internals.h index 4bdbc3a8ac..56b4672685 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1159,6 +1159,9 @@ static inline uint32_t aarch64_pstate_valid_mask(const ARMISARegisters *id) if (isar_feature_aa64_uao(id)) { valid |= PSTATE_UAO; } + if (isar_feature_aa64_mte(id)) { + valid |= PSTATE_TCO; + } return valid; } @@ -1234,4 +1237,10 @@ void arm_log_exception(int idx); #endif /* !CONFIG_USER_ONLY */ +/* + * The log2 of the words in the tag block, for GMID_EL1.BS. + * The is the maximum, 256 bytes, which manipulates 64-bits of tags. + */ +#define GMID_EL1_BS 6 + #endif diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 027be7d8c2..d4793dd8fe 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1619,6 +1619,27 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, s->base.is_jmp = DISAS_UPDATE_EXIT; break; + case 0x1c: /* TCO */ + if (dc_isar_feature(aa64_mte, s)) { + /* Full MTE is enabled -- set the TCO bit as directed. */ + if (crm & 1) { + set_pstate_bits(PSTATE_TCO); + } else { + clear_pstate_bits(PSTATE_TCO); + } + t1 = tcg_const_i32(s->current_el); + gen_helper_rebuild_hflags_a64(cpu_env, t1); + tcg_temp_free_i32(t1); + /* Many factors, including TCO, go into MTE_ACTIVE. */ + s->base.is_jmp = DISAS_UPDATE_NOCHAIN; + } else if (dc_isar_feature(aa64_mte_insn_reg, s)) { + /* Only "instructions accessible at EL0" -- PSTATE.TCO is WI. */ + s->base.is_jmp = DISAS_NEXT; + } else { + goto do_unallocated; + } + break; + default: do_unallocated: unallocated_encoding(s); From 81ae05fa2d21ac1a0054935b74342aa38a5ecef7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:06 -0700 Subject: [PATCH 1655/2595] target/arm: Add MTE bits to tb_flags Cache the composite ATA setting. Cache when MTE is fully enabled, i.e. access to tags are enabled and tag checks affect the PE. Do this for both the normal context and the UNPRIV context. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 12 ++++++++---- target/arm/helper.c | 40 ++++++++++++++++++++++++++++++++++++++ target/arm/internals.h | 18 +++++++++++++++++ target/arm/translate-a64.c | 4 ++++ target/arm/translate.h | 5 +++++ 5 files changed, 75 insertions(+), 4 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 0a98b6a06d..cb4f6ba69f 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3187,10 +3187,10 @@ typedef ARMCPU ArchCPU; * | | | TBFLAG_A32 | | * | | +-----+----------+ TBFLAG_AM32 | * | TBFLAG_ANY | |TBFLAG_M32| | - * | | +-+----------+--------------| - * | | | TBFLAG_A64 | - * +--------------+---------+---------------------------+ - * 31 20 15 0 + * | +-----------+----------+--------------| + * | | TBFLAG_A64 | + * +--------------+-------------------------------------+ + * 31 20 0 * * Unless otherwise noted, these bits are cached in env->hflags. */ @@ -3257,6 +3257,10 @@ FIELD(TBFLAG_A64, BT, 9, 1) FIELD(TBFLAG_A64, BTYPE, 10, 2) /* Not cached. */ FIELD(TBFLAG_A64, TBID, 12, 2) FIELD(TBFLAG_A64, UNPRIV, 14, 1) +FIELD(TBFLAG_A64, ATA, 15, 1) +FIELD(TBFLAG_A64, TCMA, 16, 2) +FIELD(TBFLAG_A64, MTE_ACTIVE, 18, 1) +FIELD(TBFLAG_A64, MTE0_ACTIVE, 19, 1) /** * cpu_mmu_index: diff --git a/target/arm/helper.c b/target/arm/helper.c index b4842ea23e..2c6ec244af 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10655,6 +10655,16 @@ static int aa64_va_parameter_tbid(uint64_t tcr, ARMMMUIdx mmu_idx) } } +static int aa64_va_parameter_tcma(uint64_t tcr, ARMMMUIdx mmu_idx) +{ + if (regime_has_2_ranges(mmu_idx)) { + return extract64(tcr, 57, 2); + } else { + /* Replicate the single TCMA bit so we always have 2 bits. */ + return extract32(tcr, 30, 1) * 3; + } +} + ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, ARMMMUIdx mmu_idx, bool data) { @@ -12679,6 +12689,36 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, } } + if (cpu_isar_feature(aa64_mte, env_archcpu(env))) { + /* + * Set MTE_ACTIVE if any access may be Checked, and leave clear + * if all accesses must be Unchecked: + * 1) If no TBI, then there are no tags in the address to check, + * 2) If Tag Check Override, then all accesses are Unchecked, + * 3) If Tag Check Fail == 0, then Checked access have no effect, + * 4) If no Allocation Tag Access, then all accesses are Unchecked. + */ + if (allocation_tag_access_enabled(env, el, sctlr)) { + flags = FIELD_DP32(flags, TBFLAG_A64, ATA, 1); + if (tbid + && !(env->pstate & PSTATE_TCO) + && (sctlr & (el == 0 ? SCTLR_TCF0 : SCTLR_TCF))) { + flags = FIELD_DP32(flags, TBFLAG_A64, MTE_ACTIVE, 1); + } + } + /* And again for unprivileged accesses, if required. */ + if (FIELD_EX32(flags, TBFLAG_A64, UNPRIV) + && tbid + && !(env->pstate & PSTATE_TCO) + && (sctlr & SCTLR_TCF0) + && allocation_tag_access_enabled(env, 0, sctlr)) { + flags = FIELD_DP32(flags, TBFLAG_A64, MTE0_ACTIVE, 1); + } + /* Cache TCMA as well as TBI. */ + flags = FIELD_DP32(flags, TBFLAG_A64, TCMA, + aa64_va_parameter_tcma(tcr, mmu_idx)); + } + return rebuild_hflags_common(env, fp_el, mmu_idx, flags); } diff --git a/target/arm/internals.h b/target/arm/internals.h index 56b4672685..53e249687b 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1198,6 +1198,24 @@ static inline int exception_target_el(CPUARMState *env) return target_el; } +/* Determine if allocation tags are available. */ +static inline bool allocation_tag_access_enabled(CPUARMState *env, int el, + uint64_t sctlr) +{ + if (el < 3 + && arm_feature(env, ARM_FEATURE_EL3) + && !(env->cp15.scr_el3 & SCR_ATA)) { + return false; + } + if (el < 2 + && arm_feature(env, ARM_FEATURE_EL2) + && !(arm_hcr_el2_eff(env) & HCR_ATA)) { + return false; + } + sctlr &= (el == 0 ? SCTLR_ATA0 : SCTLR_ATA); + return sctlr != 0; +} + #ifndef CONFIG_USER_ONLY /* Security attributes for an address, as returned by v8m_security_lookup. */ diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index d4793dd8fe..55f49585be 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14171,6 +14171,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->mmu_idx = core_to_aa64_mmu_idx(core_mmu_idx); dc->tbii = FIELD_EX32(tb_flags, TBFLAG_A64, TBII); dc->tbid = FIELD_EX32(tb_flags, TBFLAG_A64, TBID); + dc->tcma = FIELD_EX32(tb_flags, TBFLAG_A64, TCMA); dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx); #if !defined(CONFIG_USER_ONLY) dc->user = (dc->current_el == 0); @@ -14182,6 +14183,9 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->bt = FIELD_EX32(tb_flags, TBFLAG_A64, BT); dc->btype = FIELD_EX32(tb_flags, TBFLAG_A64, BTYPE); dc->unpriv = FIELD_EX32(tb_flags, TBFLAG_A64, UNPRIV); + dc->ata = FIELD_EX32(tb_flags, TBFLAG_A64, ATA); + dc->mte_active[0] = FIELD_EX32(tb_flags, TBFLAG_A64, MTE_ACTIVE); + dc->mte_active[1] = FIELD_EX32(tb_flags, TBFLAG_A64, MTE0_ACTIVE); dc->vec_len = 0; dc->vec_stride = 0; dc->cp_regs = arm_cpu->cp_regs; diff --git a/target/arm/translate.h b/target/arm/translate.h index 6dfe24cedc..98bcc37c47 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -30,6 +30,7 @@ typedef struct DisasContext { ARMMMUIdx mmu_idx; /* MMU index to use for normal loads/stores */ uint8_t tbii; /* TBI1|TBI0 for insns */ uint8_t tbid; /* TBI1|TBI0 for data */ + uint8_t tcma; /* TCMA1|TCMA0 for MTE */ bool ns; /* Use non-secure CPREG bank on access */ int fp_excp_el; /* FP exception EL or 0 if enabled */ int sve_excp_el; /* SVE exception EL or 0 if enabled */ @@ -77,6 +78,10 @@ typedef struct DisasContext { bool unpriv; /* True if v8.3-PAuth is active. */ bool pauth_active; + /* True if v8.5-MTE access to tags is enabled. */ + bool ata; + /* True if v8.5-MTE tag checks affect the PE; index with is_unpriv. */ + bool mte_active[2]; /* True with v8.5-BTI and SCTLR_ELx.BT* set. */ bool bt; /* True if any CP15 access is trapped by HSTR_EL2 */ From da54941f45b820cbaca72aa6efd5669b3dc86e2f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:07 -0700 Subject: [PATCH 1656/2595] target/arm: Implement the IRG instruction Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/Makefile.objs | 1 + target/arm/helper-a64.h | 2 ++ target/arm/internals.h | 5 +++ target/arm/mte_helper.c | 72 ++++++++++++++++++++++++++++++++++++++ target/arm/translate-a64.c | 18 ++++++++++ 5 files changed, 98 insertions(+) create mode 100644 target/arm/mte_helper.c diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs index 83febd232c..fa39fd7c83 100644 --- a/target/arm/Makefile.objs +++ b/target/arm/Makefile.objs @@ -86,3 +86,4 @@ obj-$(CONFIG_SOFTMMU) += psci.o obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o obj-$(TARGET_AARCH64) += pauth_helper.o +obj-$(TARGET_AARCH64) += mte_helper.o diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index 3df7c185aa..587ccbe42f 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -103,3 +103,5 @@ DEF_HELPER_FLAGS_3(autda, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(autdb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_2(xpaci, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64) + +DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) diff --git a/target/arm/internals.h b/target/arm/internals.h index 53e249687b..ae611a6ff5 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1261,4 +1261,9 @@ void arm_log_exception(int idx); */ #define GMID_EL1_BS 6 +static inline uint64_t address_with_allocation_tag(uint64_t ptr, int rtag) +{ + return deposit64(ptr, 56, 4, rtag); +} + #endif diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c new file mode 100644 index 0000000000..539a04de84 --- /dev/null +++ b/target/arm/mte_helper.c @@ -0,0 +1,72 @@ +/* + * ARM v8.5-MemTag Operations + * + * Copyright (c) 2020 Linaro, Ltd. + * + * 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.1 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 . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internals.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "exec/helper-proto.h" + + +static int choose_nonexcluded_tag(int tag, int offset, uint16_t exclude) +{ + if (exclude == 0xffff) { + return 0; + } + if (offset == 0) { + while (exclude & (1 << tag)) { + tag = (tag + 1) & 15; + } + } else { + do { + do { + tag = (tag + 1) & 15; + } while (exclude & (1 << tag)); + } while (--offset > 0); + } + return tag; +} + +uint64_t HELPER(irg)(CPUARMState *env, uint64_t rn, uint64_t rm) +{ + int rtag; + + /* + * Our IMPDEF choice for GCR_EL1.RRND==1 is to behave as if + * GCR_EL1.RRND==0, always producing deterministic results. + */ + uint16_t exclude = extract32(rm | env->cp15.gcr_el1, 0, 16); + int start = extract32(env->cp15.rgsr_el1, 0, 4); + int seed = extract32(env->cp15.rgsr_el1, 8, 16); + int offset, i; + + /* RandomTag */ + for (i = offset = 0; i < 4; ++i) { + /* NextRandomTagBit */ + int top = (extract32(seed, 5, 1) ^ extract32(seed, 3, 1) ^ + extract32(seed, 2, 1) ^ extract32(seed, 0, 1)); + seed = (top << 15) | (seed >> 1); + offset |= top << i; + } + rtag = choose_nonexcluded_tag(start, offset, exclude); + env->cp15.rgsr_el1 = rtag | (seed << 8); + + return address_with_allocation_tag(rn, rtag); +} diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 55f49585be..30683061f9 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -226,6 +226,12 @@ static TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr) return clean; } +/* Insert a zero tag into src, with the result at dst. */ +static void gen_address_with_allocation_tag0(TCGv_i64 dst, TCGv_i64 src) +{ + tcg_gen_andi_i64(dst, src, ~MAKE_64BIT_MASK(56, 4)); +} + typedef struct DisasCompare64 { TCGCond cond; TCGv_i64 value; @@ -5284,6 +5290,18 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn) case 3: /* SDIV */ handle_div(s, true, sf, rm, rn, rd); break; + case 4: /* IRG */ + if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) { + goto do_unallocated; + } + if (s->ata) { + gen_helper_irg(cpu_reg_sp(s, rd), cpu_env, + cpu_reg_sp(s, rn), cpu_reg(s, rm)); + } else { + gen_address_with_allocation_tag0(cpu_reg_sp(s, rd), + cpu_reg_sp(s, rn)); + } + break; case 8: /* LSLV */ handle_shift_reg(s, A64_SHIFT_TYPE_LSL, sf, rm, rn, rd); break; From 21a8b343eaae63f6984f9a200092b0ea167647f1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:08 -0700 Subject: [PATCH 1657/2595] target/arm: Revise decoding for disas_add_sub_imm The current Arm ARM has adjusted the official decode of "Add/subtract (immediate)" so that the shift field is only bit 22, and bit 23 is part of the op1 field of the parent category "Data processing - immediate". Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-11-richard.henderson@linaro.org Suggested-by: Peter Maydell Signed-off-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 30683061f9..03aa092598 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -3754,22 +3754,22 @@ static void disas_pc_rel_adr(DisasContext *s, uint32_t insn) /* * Add/subtract (immediate) * - * 31 30 29 28 24 23 22 21 10 9 5 4 0 - * +--+--+--+-----------+-----+-------------+-----+-----+ - * |sf|op| S| 1 0 0 0 1 |shift| imm12 | Rn | Rd | - * +--+--+--+-----------+-----+-------------+-----+-----+ + * 31 30 29 28 23 22 21 10 9 5 4 0 + * +--+--+--+-------------+--+-------------+-----+-----+ + * |sf|op| S| 1 0 0 0 1 0 |sh| imm12 | Rn | Rd | + * +--+--+--+-------------+--+-------------+-----+-----+ * * sf: 0 -> 32bit, 1 -> 64bit * op: 0 -> add , 1 -> sub * S: 1 -> set flags - * shift: 00 -> LSL imm by 0, 01 -> LSL imm by 12 + * sh: 1 -> LSL imm by 12 */ static void disas_add_sub_imm(DisasContext *s, uint32_t insn) { int rd = extract32(insn, 0, 5); int rn = extract32(insn, 5, 5); uint64_t imm = extract32(insn, 10, 12); - int shift = extract32(insn, 22, 2); + bool shift = extract32(insn, 22, 1); bool setflags = extract32(insn, 29, 1); bool sub_op = extract32(insn, 30, 1); bool is_64bit = extract32(insn, 31, 1); @@ -3778,15 +3778,8 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t insn) TCGv_i64 tcg_rd = setflags ? cpu_reg(s, rd) : cpu_reg_sp(s, rd); TCGv_i64 tcg_result; - switch (shift) { - case 0x0: - break; - case 0x1: + if (shift) { imm <<= 12; - break; - default: - unallocated_encoding(s); - return; } tcg_result = tcg_temp_new_i64(); @@ -4174,7 +4167,7 @@ static void disas_data_proc_imm(DisasContext *s, uint32_t insn) case 0x20: case 0x21: /* PC-rel. addressing */ disas_pc_rel_adr(s, insn); break; - case 0x22: case 0x23: /* Add/subtract (immediate) */ + case 0x22: /* Add/subtract (immediate) */ disas_add_sub_imm(s, insn); break; case 0x24: /* Logical (immediate) */ From efbc78ad978763aedd11cb718eb1ff8db3fc9152 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:09 -0700 Subject: [PATCH 1658/2595] target/arm: Implement the ADDG, SUBG instructions Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-a64.h | 1 + target/arm/internals.h | 9 +++++++ target/arm/mte_helper.c | 10 ++++++++ target/arm/translate-a64.c | 51 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index 587ccbe42f..6c116481e8 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -105,3 +105,4 @@ DEF_HELPER_FLAGS_2(xpaci, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_4(addsubg, TCG_CALL_NO_RWG_SE, i64, env, i64, s32, i32) diff --git a/target/arm/internals.h b/target/arm/internals.h index ae611a6ff5..5c69d4e5a5 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1261,6 +1261,15 @@ void arm_log_exception(int idx); */ #define GMID_EL1_BS 6 +/* We associate one allocation tag per 16 bytes, the minimum. */ +#define LOG2_TAG_GRANULE 4 +#define TAG_GRANULE (1 << LOG2_TAG_GRANULE) + +static inline int allocation_tag_from_addr(uint64_t ptr) +{ + return extract64(ptr, 56, 4); +} + static inline uint64_t address_with_allocation_tag(uint64_t ptr, int rtag) { return deposit64(ptr, 56, 4, rtag); diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 539a04de84..9ab9ed749d 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -70,3 +70,13 @@ uint64_t HELPER(irg)(CPUARMState *env, uint64_t rn, uint64_t rm) return address_with_allocation_tag(rn, rtag); } + +uint64_t HELPER(addsubg)(CPUARMState *env, uint64_t ptr, + int32_t offset, uint32_t tag_offset) +{ + int start_tag = allocation_tag_from_addr(ptr); + uint16_t exclude = extract32(env->cp15.gcr_el1, 0, 16); + int rtag = choose_nonexcluded_tag(start_tag, tag_offset, exclude); + + return address_with_allocation_tag(ptr + offset, rtag); +} diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 03aa092598..2ec02c8a5f 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -3808,6 +3808,54 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_result); } +/* + * Add/subtract (immediate, with tags) + * + * 31 30 29 28 23 22 21 16 14 10 9 5 4 0 + * +--+--+--+-------------+--+---------+--+-------+-----+-----+ + * |sf|op| S| 1 0 0 0 1 1 |o2| uimm6 |o3| uimm4 | Rn | Rd | + * +--+--+--+-------------+--+---------+--+-------+-----+-----+ + * + * op: 0 -> add, 1 -> sub + */ +static void disas_add_sub_imm_with_tags(DisasContext *s, uint32_t insn) +{ + int rd = extract32(insn, 0, 5); + int rn = extract32(insn, 5, 5); + int uimm4 = extract32(insn, 10, 4); + int uimm6 = extract32(insn, 16, 6); + bool sub_op = extract32(insn, 30, 1); + TCGv_i64 tcg_rn, tcg_rd; + int imm; + + /* Test all of sf=1, S=0, o2=0, o3=0. */ + if ((insn & 0xa040c000u) != 0x80000000u || + !dc_isar_feature(aa64_mte_insn_reg, s)) { + unallocated_encoding(s); + return; + } + + imm = uimm6 << LOG2_TAG_GRANULE; + if (sub_op) { + imm = -imm; + } + + tcg_rn = cpu_reg_sp(s, rn); + tcg_rd = cpu_reg_sp(s, rd); + + if (s->ata) { + TCGv_i32 offset = tcg_const_i32(imm); + TCGv_i32 tag_offset = tcg_const_i32(uimm4); + + gen_helper_addsubg(tcg_rd, cpu_env, tcg_rn, offset, tag_offset); + tcg_temp_free_i32(tag_offset); + tcg_temp_free_i32(offset); + } else { + tcg_gen_addi_i64(tcg_rd, tcg_rn, imm); + gen_address_with_allocation_tag0(tcg_rd, tcg_rd); + } +} + /* The input should be a value in the bottom e bits (with higher * bits zero); returns that value replicated into every element * of size e in a 64 bit integer. @@ -4170,6 +4218,9 @@ static void disas_data_proc_imm(DisasContext *s, uint32_t insn) case 0x22: /* Add/subtract (immediate) */ disas_add_sub_imm(s, insn); break; + case 0x23: /* Add/subtract (immediate, with tags) */ + disas_add_sub_imm_with_tags(s, insn); + break; case 0x24: /* Logical (immediate) */ disas_logic_imm(s, insn); break; From 438efea0bb639c9c2dfb42c8d9459e21aa183c8a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:10 -0700 Subject: [PATCH 1659/2595] target/arm: Implement the GMI instruction Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 2ec02c8a5f..ee9dfa8e43 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -5346,6 +5346,21 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn) cpu_reg_sp(s, rn)); } break; + case 5: /* GMI */ + if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) { + goto do_unallocated; + } else { + TCGv_i64 t1 = tcg_const_i64(1); + TCGv_i64 t2 = tcg_temp_new_i64(); + + tcg_gen_extract_i64(t2, cpu_reg_sp(s, rn), 56, 4); + tcg_gen_shl_i64(t1, t1, t2); + tcg_gen_or_i64(cpu_reg(s, rd), cpu_reg(s, rm), t1); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + } + break; case 8: /* LSLV */ handle_shift_reg(s, A64_SHIFT_TYPE_LSL, sf, rm, rn, rd); break; From dad3015f55f8d48f84f0eae36021a9c6f9587e57 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:11 -0700 Subject: [PATCH 1660/2595] target/arm: Implement the SUBP instruction Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-14-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index ee9dfa8e43..abbcdbb53a 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -5315,19 +5315,39 @@ static void handle_crc32(DisasContext *s, */ static void disas_data_proc_2src(DisasContext *s, uint32_t insn) { - unsigned int sf, rm, opcode, rn, rd; + unsigned int sf, rm, opcode, rn, rd, setflag; sf = extract32(insn, 31, 1); + setflag = extract32(insn, 29, 1); rm = extract32(insn, 16, 5); opcode = extract32(insn, 10, 6); rn = extract32(insn, 5, 5); rd = extract32(insn, 0, 5); - if (extract32(insn, 29, 1)) { + if (setflag && opcode != 0) { unallocated_encoding(s); return; } switch (opcode) { + case 0: /* SUBP(S) */ + if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) { + goto do_unallocated; + } else { + TCGv_i64 tcg_n, tcg_m, tcg_d; + + tcg_n = read_cpu_reg_sp(s, rn, true); + tcg_m = read_cpu_reg_sp(s, rm, true); + tcg_gen_sextract_i64(tcg_n, tcg_n, 0, 56); + tcg_gen_sextract_i64(tcg_m, tcg_m, 0, 56); + tcg_d = cpu_reg(s, rd); + + if (setflag) { + gen_sub_CC(true, tcg_d, tcg_n, tcg_m); + } else { + tcg_gen_sub_i64(tcg_d, tcg_n, tcg_m); + } + } + break; case 2: /* UDIV */ handle_div(s, false, sf, rm, rn, rd); break; From 0d1762e931f8a694f261c604daba605bcda70928 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:12 -0700 Subject: [PATCH 1661/2595] target/arm: Define arm_cpu_do_unaligned_access for user-only Use the same code as system mode, so that we generate the same exception + syndrome for the unaligned access. For the moment, if MTE is enabled so that this path is reachable, this would generate a SIGSEGV in the user-only cpu_loop. Decoding the syndrome to produce the proper SIGBUS will be done later. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-15-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 2 +- target/arm/tlb_helper.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index e44e18062c..d9b8ec791e 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2169,8 +2169,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->tlb_fill = arm_cpu_tlb_fill; cc->debug_excp_handler = arm_debug_excp_handler; cc->debug_check_watchpoint = arm_debug_check_watchpoint; -#if !defined(CONFIG_USER_ONLY) cc->do_unaligned_access = arm_cpu_do_unaligned_access; +#if !defined(CONFIG_USER_ONLY) cc->do_transaction_failed = arm_cpu_do_transaction_failed; cc->adjust_watchpoint_address = arm_adjust_watchpoint_address; #endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c index 7388494a55..522a6442a4 100644 --- a/target/arm/tlb_helper.c +++ b/target/arm/tlb_helper.c @@ -10,8 +10,6 @@ #include "internals.h" #include "exec/exec-all.h" -#if !defined(CONFIG_USER_ONLY) - static inline uint32_t merge_syn_data_abort(uint32_t template_syn, unsigned int target_el, bool same_el, bool ea, @@ -122,6 +120,8 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi); } +#if !defined(CONFIG_USER_ONLY) + /* * arm_cpu_do_transaction_failed: handle a memory system error response * (eg "no device/memory present at address") by raising an external abort From c15294c1e36a7dd9b25bd54d98178e80f4b64bc1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:13 -0700 Subject: [PATCH 1662/2595] target/arm: Implement LDG, STG, ST2G instructions Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-a64.h | 7 ++ target/arm/helper.h | 2 + target/arm/mte_helper.c | 194 +++++++++++++++++++++++++++++++++++++ target/arm/op_helper.c | 16 +++ target/arm/translate-a64.c | 172 +++++++++++++++++++++++++++++++- 5 files changed, 386 insertions(+), 5 deletions(-) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index 6c116481e8..2fa61b86fa 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -106,3 +106,10 @@ DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_4(addsubg, TCG_CALL_NO_RWG_SE, i64, env, i64, s32, i32) +DEF_HELPER_FLAGS_3(ldg, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(stg, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_3(stg_parallel, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_2(stg_stub, TCG_CALL_NO_WG, void, env, i64) +DEF_HELPER_FLAGS_3(st2g, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_3(st2g_parallel, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_2(st2g_stub, TCG_CALL_NO_WG, void, env, i64) diff --git a/target/arm/helper.h b/target/arm/helper.h index 2a20c8174c..759639a63a 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -96,6 +96,8 @@ DEF_HELPER_FLAGS_1(rebuild_hflags_a32_newel, TCG_CALL_NO_RWG, void, env) DEF_HELPER_FLAGS_2(rebuild_hflags_a32, TCG_CALL_NO_RWG, void, env, int) DEF_HELPER_FLAGS_2(rebuild_hflags_a64, TCG_CALL_NO_RWG, void, env, int) +DEF_HELPER_FLAGS_5(probe_access, TCG_CALL_NO_WG, void, env, tl, i32, i32, i32) + DEF_HELPER_1(vfp_get_fpscr, i32, env) DEF_HELPER_2(vfp_set_fpscr, void, env, i32) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 9ab9ed749d..7ec7930dfc 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -44,6 +44,40 @@ static int choose_nonexcluded_tag(int tag, int offset, uint16_t exclude) return tag; } +/** + * allocation_tag_mem: + * @env: the cpu environment + * @ptr_mmu_idx: the addressing regime to use for the virtual address + * @ptr: the virtual address for which to look up tag memory + * @ptr_access: the access to use for the virtual address + * @ptr_size: the number of bytes in the normal memory access + * @tag_access: the access to use for the tag memory + * @tag_size: the number of bytes in the tag memory access + * @ra: the return address for exception handling + * + * Our tag memory is formatted as a sequence of little-endian nibbles. + * That is, the byte at (addr >> (LOG2_TAG_GRANULE + 1)) contains two + * tags, with the tag at [3:0] for the lower addr and the tag at [7:4] + * for the higher addr. + * + * Here, resolve the physical address from the virtual address, and return + * a pointer to the corresponding tag byte. Exit with exception if the + * virtual address is not accessible for @ptr_access. + * + * The @ptr_size and @tag_size values may not have an obvious relation + * due to the alignment of @ptr, and the number of tag checks required. + * + * If there is no tag storage corresponding to @ptr, return NULL. + */ +static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, + uint64_t ptr, MMUAccessType ptr_access, + int ptr_size, MMUAccessType tag_access, + int tag_size, uintptr_t ra) +{ + /* Tag storage not implemented. */ + return NULL; +} + uint64_t HELPER(irg)(CPUARMState *env, uint64_t rn, uint64_t rm) { int rtag; @@ -80,3 +114,163 @@ uint64_t HELPER(addsubg)(CPUARMState *env, uint64_t ptr, return address_with_allocation_tag(ptr + offset, rtag); } + +static int load_tag1(uint64_t ptr, uint8_t *mem) +{ + int ofs = extract32(ptr, LOG2_TAG_GRANULE, 1) * 4; + return extract32(*mem, ofs, 4); +} + +uint64_t HELPER(ldg)(CPUARMState *env, uint64_t ptr, uint64_t xt) +{ + int mmu_idx = cpu_mmu_index(env, false); + uint8_t *mem; + int rtag = 0; + + /* Trap if accessing an invalid page. */ + mem = allocation_tag_mem(env, mmu_idx, ptr, MMU_DATA_LOAD, 1, + MMU_DATA_LOAD, 1, GETPC()); + + /* Load if page supports tags. */ + if (mem) { + rtag = load_tag1(ptr, mem); + } + + return address_with_allocation_tag(xt, rtag); +} + +static void check_tag_aligned(CPUARMState *env, uint64_t ptr, uintptr_t ra) +{ + if (unlikely(!QEMU_IS_ALIGNED(ptr, TAG_GRANULE))) { + arm_cpu_do_unaligned_access(env_cpu(env), ptr, MMU_DATA_STORE, + cpu_mmu_index(env, false), ra); + g_assert_not_reached(); + } +} + +/* For use in a non-parallel context, store to the given nibble. */ +static void store_tag1(uint64_t ptr, uint8_t *mem, int tag) +{ + int ofs = extract32(ptr, LOG2_TAG_GRANULE, 1) * 4; + *mem = deposit32(*mem, ofs, 4, tag); +} + +/* For use in a parallel context, atomically store to the given nibble. */ +static void store_tag1_parallel(uint64_t ptr, uint8_t *mem, int tag) +{ + int ofs = extract32(ptr, LOG2_TAG_GRANULE, 1) * 4; + uint8_t old = atomic_read(mem); + + while (1) { + uint8_t new = deposit32(old, ofs, 4, tag); + uint8_t cmp = atomic_cmpxchg(mem, old, new); + if (likely(cmp == old)) { + return; + } + old = cmp; + } +} + +typedef void stg_store1(uint64_t, uint8_t *, int); + +static inline void do_stg(CPUARMState *env, uint64_t ptr, uint64_t xt, + uintptr_t ra, stg_store1 store1) +{ + int mmu_idx = cpu_mmu_index(env, false); + uint8_t *mem; + + check_tag_aligned(env, ptr, ra); + + /* Trap if accessing an invalid page. */ + mem = allocation_tag_mem(env, mmu_idx, ptr, MMU_DATA_STORE, TAG_GRANULE, + MMU_DATA_STORE, 1, ra); + + /* Store if page supports tags. */ + if (mem) { + store1(ptr, mem, allocation_tag_from_addr(xt)); + } +} + +void HELPER(stg)(CPUARMState *env, uint64_t ptr, uint64_t xt) +{ + do_stg(env, ptr, xt, GETPC(), store_tag1); +} + +void HELPER(stg_parallel)(CPUARMState *env, uint64_t ptr, uint64_t xt) +{ + do_stg(env, ptr, xt, GETPC(), store_tag1_parallel); +} + +void HELPER(stg_stub)(CPUARMState *env, uint64_t ptr) +{ + int mmu_idx = cpu_mmu_index(env, false); + uintptr_t ra = GETPC(); + + check_tag_aligned(env, ptr, ra); + probe_write(env, ptr, TAG_GRANULE, mmu_idx, ra); +} + +static inline void do_st2g(CPUARMState *env, uint64_t ptr, uint64_t xt, + uintptr_t ra, stg_store1 store1) +{ + int mmu_idx = cpu_mmu_index(env, false); + int tag = allocation_tag_from_addr(xt); + uint8_t *mem1, *mem2; + + check_tag_aligned(env, ptr, ra); + + /* + * Trap if accessing an invalid page(s). + * This takes priority over !allocation_tag_access_enabled. + */ + if (ptr & TAG_GRANULE) { + /* Two stores unaligned mod TAG_GRANULE*2 -- modify two bytes. */ + mem1 = allocation_tag_mem(env, mmu_idx, ptr, MMU_DATA_STORE, + TAG_GRANULE, MMU_DATA_STORE, 1, ra); + mem2 = allocation_tag_mem(env, mmu_idx, ptr + TAG_GRANULE, + MMU_DATA_STORE, TAG_GRANULE, + MMU_DATA_STORE, 1, ra); + + /* Store if page(s) support tags. */ + if (mem1) { + store1(TAG_GRANULE, mem1, tag); + } + if (mem2) { + store1(0, mem2, tag); + } + } else { + /* Two stores aligned mod TAG_GRANULE*2 -- modify one byte. */ + mem1 = allocation_tag_mem(env, mmu_idx, ptr, MMU_DATA_STORE, + 2 * TAG_GRANULE, MMU_DATA_STORE, 1, ra); + if (mem1) { + tag |= tag << 4; + atomic_set(mem1, tag); + } + } +} + +void HELPER(st2g)(CPUARMState *env, uint64_t ptr, uint64_t xt) +{ + do_st2g(env, ptr, xt, GETPC(), store_tag1); +} + +void HELPER(st2g_parallel)(CPUARMState *env, uint64_t ptr, uint64_t xt) +{ + do_st2g(env, ptr, xt, GETPC(), store_tag1_parallel); +} + +void HELPER(st2g_stub)(CPUARMState *env, uint64_t ptr) +{ + int mmu_idx = cpu_mmu_index(env, false); + uintptr_t ra = GETPC(); + int in_page = -(ptr | TARGET_PAGE_MASK); + + check_tag_aligned(env, ptr, ra); + + if (likely(in_page >= 2 * TAG_GRANULE)) { + probe_write(env, ptr, 2 * TAG_GRANULE, mmu_idx, ra); + } else { + probe_write(env, ptr, TAG_GRANULE, mmu_idx, ra); + probe_write(env, ptr + TAG_GRANULE, TAG_GRANULE, mmu_idx, ra); + } +} diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index eb0de080f1..b1065216b2 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -935,3 +935,19 @@ uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i) return ((uint32_t)x >> shift) | (x << (32 - shift)); } } + +void HELPER(probe_access)(CPUARMState *env, target_ulong ptr, + uint32_t access_type, uint32_t mmu_idx, + uint32_t size) +{ + uint32_t in_page = -((uint32_t)ptr | TARGET_PAGE_SIZE); + uintptr_t ra = GETPC(); + + if (likely(size <= in_page)) { + probe_access(env, ptr, size, access_type, mmu_idx, ra); + } else { + probe_access(env, ptr, in_page, access_type, mmu_idx, ra); + probe_access(env, ptr + in_page, size - in_page, + access_type, mmu_idx, ra); + } +} diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index abbcdbb53a..436191c15c 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -232,6 +232,19 @@ static void gen_address_with_allocation_tag0(TCGv_i64 dst, TCGv_i64 src) tcg_gen_andi_i64(dst, src, ~MAKE_64BIT_MASK(56, 4)); } +static void gen_probe_access(DisasContext *s, TCGv_i64 ptr, + MMUAccessType acc, int log2_size) +{ + TCGv_i32 t_acc = tcg_const_i32(acc); + TCGv_i32 t_idx = tcg_const_i32(get_mem_index(s)); + TCGv_i32 t_size = tcg_const_i32(1 << log2_size); + + gen_helper_probe_access(cpu_env, ptr, t_acc, t_idx, t_size); + tcg_temp_free_i32(t_acc); + tcg_temp_free_i32(t_idx); + tcg_temp_free_i32(t_size); +} + typedef struct DisasCompare64 { TCGCond cond; TCGv_i64 value; @@ -3685,6 +3698,154 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) } } +/* + * Load/Store memory tags + * + * 31 30 29 24 22 21 12 10 5 0 + * +-----+-------------+-----+---+------+-----+------+------+ + * | 1 1 | 0 1 1 0 0 1 | op1 | 1 | imm9 | op2 | Rn | Rt | + * +-----+-------------+-----+---+------+-----+------+------+ + */ +static void disas_ldst_tag(DisasContext *s, uint32_t insn) +{ + int rt = extract32(insn, 0, 5); + int rn = extract32(insn, 5, 5); + uint64_t offset = sextract64(insn, 12, 9) << LOG2_TAG_GRANULE; + int op2 = extract32(insn, 10, 2); + int op1 = extract32(insn, 22, 2); + bool is_load = false, is_pair = false, is_zero = false; + int index = 0; + TCGv_i64 addr, clean_addr, tcg_rt; + + /* We checked insn bits [29:24,21] in the caller. */ + if (extract32(insn, 30, 2) != 3) { + goto do_unallocated; + } + + /* + * @index is a tri-state variable which has 3 states: + * < 0 : post-index, writeback + * = 0 : signed offset + * > 0 : pre-index, writeback + */ + switch (op1) { + case 0: + if (op2 != 0) { + /* STG */ + index = op2 - 2; + break; + } + goto do_unallocated; + case 1: + if (op2 != 0) { + /* STZG */ + is_zero = true; + index = op2 - 2; + } else { + /* LDG */ + is_load = true; + } + break; + case 2: + if (op2 != 0) { + /* ST2G */ + is_pair = true; + index = op2 - 2; + break; + } + goto do_unallocated; + case 3: + if (op2 != 0) { + /* STZ2G */ + is_pair = is_zero = true; + index = op2 - 2; + break; + } + goto do_unallocated; + + default: + do_unallocated: + unallocated_encoding(s); + return; + } + + if (!dc_isar_feature(aa64_mte_insn_reg, s)) { + goto do_unallocated; + } + + if (rn == 31) { + gen_check_sp_alignment(s); + } + + addr = read_cpu_reg_sp(s, rn, true); + if (index >= 0) { + /* pre-index or signed offset */ + tcg_gen_addi_i64(addr, addr, offset); + } + + if (is_load) { + tcg_gen_andi_i64(addr, addr, -TAG_GRANULE); + tcg_rt = cpu_reg(s, rt); + if (s->ata) { + gen_helper_ldg(tcg_rt, cpu_env, addr, tcg_rt); + } else { + clean_addr = clean_data_tbi(s, addr); + gen_probe_access(s, clean_addr, MMU_DATA_LOAD, MO_8); + gen_address_with_allocation_tag0(tcg_rt, addr); + } + } else { + tcg_rt = cpu_reg_sp(s, rt); + if (!s->ata) { + /* + * For STG and ST2G, we need to check alignment and probe memory. + * TODO: For STZG and STZ2G, we could rely on the stores below, + * at least for system mode; user-only won't enforce alignment. + */ + if (is_pair) { + gen_helper_st2g_stub(cpu_env, addr); + } else { + gen_helper_stg_stub(cpu_env, addr); + } + } else if (tb_cflags(s->base.tb) & CF_PARALLEL) { + if (is_pair) { + gen_helper_st2g_parallel(cpu_env, addr, tcg_rt); + } else { + gen_helper_stg_parallel(cpu_env, addr, tcg_rt); + } + } else { + if (is_pair) { + gen_helper_st2g(cpu_env, addr, tcg_rt); + } else { + gen_helper_stg(cpu_env, addr, tcg_rt); + } + } + } + + if (is_zero) { + TCGv_i64 clean_addr = clean_data_tbi(s, addr); + TCGv_i64 tcg_zero = tcg_const_i64(0); + int mem_index = get_mem_index(s); + int i, n = (1 + is_pair) << LOG2_TAG_GRANULE; + + tcg_gen_qemu_st_i64(tcg_zero, clean_addr, mem_index, + MO_Q | MO_ALIGN_16); + for (i = 8; i < n; i += 8) { + tcg_gen_addi_i64(clean_addr, clean_addr, 8); + tcg_gen_qemu_st_i64(tcg_zero, clean_addr, mem_index, MO_Q); + } + tcg_temp_free_i64(tcg_zero); + } + + if (index != 0) { + /* pre-index or post-index */ + if (index < 0) { + /* post-index */ + tcg_gen_addi_i64(addr, addr, offset); + } + tcg_gen_mov_i64(cpu_reg_sp(s, rn), addr); + } +} + /* Loads and stores */ static void disas_ldst(DisasContext *s, uint32_t insn) { @@ -3709,13 +3870,14 @@ static void disas_ldst(DisasContext *s, uint32_t insn) case 0x0d: /* AdvSIMD load/store single structure */ disas_ldst_single_struct(s, insn); break; - case 0x19: /* LDAPR/STLR (unscaled immediate) */ - if (extract32(insn, 10, 2) != 0 || - extract32(insn, 21, 1) != 0) { + case 0x19: + if (extract32(insn, 21, 1) != 0) { + disas_ldst_tag(s, insn); + } else if (extract32(insn, 10, 2) == 0) { + disas_ldst_ldapr_stlr(s, insn); + } else { unallocated_encoding(s); - break; } - disas_ldst_ldapr_stlr(s, insn); break; default: unallocated_encoding(s); From 6439d67fc944cf29de94a160e9450a2063c7b515 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:14 -0700 Subject: [PATCH 1663/2595] target/arm: Implement the STGP instruction Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-17-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 436191c15c..e2295a371b 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -2690,7 +2690,7 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn) * +-----+-------+---+---+-------+---+-------+-------+------+------+ * * opc: LDP/STP/LDNP/STNP 00 -> 32 bit, 10 -> 64 bit - * LDPSW 01 + * LDPSW/STGP 01 * LDP/STP/LDNP/STNP (SIMD) 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit * V: 0 -> GPR, 1 -> Vector * idx: 00 -> signed offset with non-temporal hint, 01 -> post-index, @@ -2715,6 +2715,7 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) bool is_signed = false; bool postindex = false; bool wback = false; + bool set_tag = false; TCGv_i64 clean_addr, dirty_addr; @@ -2727,6 +2728,14 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) if (is_vector) { size = 2 + opc; + } else if (opc == 1 && !is_load) { + /* STGP */ + if (!dc_isar_feature(aa64_mte_insn_reg, s) || index == 0) { + unallocated_encoding(s); + return; + } + size = 3; + set_tag = true; } else { size = 2 + extract32(opc, 1, 1); is_signed = extract32(opc, 0, 1); @@ -2767,7 +2776,7 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) return; } - offset <<= size; + offset <<= (set_tag ? LOG2_TAG_GRANULE : size); if (rn == 31) { gen_check_sp_alignment(s); @@ -2777,8 +2786,22 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) if (!postindex) { tcg_gen_addi_i64(dirty_addr, dirty_addr, offset); } - clean_addr = clean_data_tbi(s, dirty_addr); + if (set_tag) { + if (!s->ata) { + /* + * TODO: We could rely on the stores below, at least for + * system mode, if we arrange to add MO_ALIGN_16. + */ + gen_helper_stg_stub(cpu_env, dirty_addr); + } else if (tb_cflags(s->base.tb) & CF_PARALLEL) { + gen_helper_stg_parallel(cpu_env, dirty_addr, dirty_addr); + } else { + gen_helper_stg(cpu_env, dirty_addr, dirty_addr); + } + } + + clean_addr = clean_data_tbi(s, dirty_addr); if (is_vector) { if (is_load) { do_fp_ld(s, rt, clean_addr, size); From a4157b80242bf1c8aa0ee77aae7458ba79012d5d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:15 -0700 Subject: [PATCH 1664/2595] target/arm: Restrict the values of DCZID.BS under TCG We can simplify our DC_ZVA if we recognize that the largest BS that we actually use in system mode is 64. Let us just assert that it fits within TARGET_PAGE_SIZE. For DC_GVA and STZGM, we want to be able to write whole bytes of tag memory, so assert that BS is >= 2 * TAG_GRANULE, or 32. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-18-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index d9b8ec791e..d9876337c0 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1758,6 +1758,30 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } #endif + if (tcg_enabled()) { + int dcz_blocklen = 4 << cpu->dcz_blocksize; + + /* + * We only support DCZ blocklen that fits on one page. + * + * Architectually this is always true. However TARGET_PAGE_SIZE + * is variable and, for compatibility with -machine virt-2.7, + * is only 1KiB, as an artifact of legacy ARMv5 subpage support. + * But even then, while the largest architectural DCZ blocklen + * is 2KiB, no cpu actually uses such a large blocklen. + */ + assert(dcz_blocklen <= TARGET_PAGE_SIZE); + + /* + * We only support DCZ blocksize >= 2*TAG_GRANULE, which is to say + * both nibbles of each byte storing tag data may be written at once. + * Since TAG_GRANULE is 16, this means that blocklen must be >= 32. + */ + if (cpu_isar_feature(aa64_mte, cpu)) { + assert(dcz_blocklen >= 2 * TAG_GRANULE); + } + } + qemu_init_vcpu(cs); cpu_reset(cs); From e26d0d226892f67435cadcce86df0ddfb9943174 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:16 -0700 Subject: [PATCH 1665/2595] target/arm: Simplify DC_ZVA Now that we know that the operation is on a single page, we need not loop over pages while probing. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-19-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-a64.c | 94 +++++++++++------------------------------ 1 file changed, 25 insertions(+), 69 deletions(-) diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index bc0649a44a..8682630ff6 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -1119,85 +1119,41 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in) * (which matches the usual QEMU behaviour of not implementing either * alignment faults or any memory attribute handling). */ - - ARMCPU *cpu = env_archcpu(env); - uint64_t blocklen = 4 << cpu->dcz_blocksize; + int blocklen = 4 << env_archcpu(env)->dcz_blocksize; uint64_t vaddr = vaddr_in & ~(blocklen - 1); + int mmu_idx = cpu_mmu_index(env, false); + void *mem; + + /* + * Trapless lookup. In addition to actual invalid page, may + * return NULL for I/O, watchpoints, clean pages, etc. + */ + mem = tlb_vaddr_to_host(env, vaddr, MMU_DATA_STORE, mmu_idx); #ifndef CONFIG_USER_ONLY - { + if (unlikely(!mem)) { + uintptr_t ra = GETPC(); + /* - * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than - * the block size so we might have to do more than one TLB lookup. - * We know that in fact for any v8 CPU the page size is at least 4K - * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only - * 1K as an artefact of legacy v5 subpage support being present in the - * same QEMU executable. So in practice the hostaddr[] array has - * two entries, given the current setting of TARGET_PAGE_BITS_MIN. + * Trap if accessing an invalid page. DC_ZVA requires that we supply + * the original pointer for an invalid page. But watchpoints require + * that we probe the actual space. So do both. */ - int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE); - void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)]; - int try, i; - unsigned mmu_idx = cpu_mmu_index(env, false); - TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx); + (void) probe_write(env, vaddr_in, 1, mmu_idx, ra); + mem = probe_write(env, vaddr, blocklen, mmu_idx, ra); - assert(maxidx <= ARRAY_SIZE(hostaddr)); - - for (try = 0; try < 2; try++) { - - for (i = 0; i < maxidx; i++) { - hostaddr[i] = tlb_vaddr_to_host(env, - vaddr + TARGET_PAGE_SIZE * i, - 1, mmu_idx); - if (!hostaddr[i]) { - break; - } - } - if (i == maxidx) { - /* - * If it's all in the TLB it's fair game for just writing to; - * we know we don't need to update dirty status, etc. - */ - for (i = 0; i < maxidx - 1; i++) { - memset(hostaddr[i], 0, TARGET_PAGE_SIZE); - } - memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE)); - return; - } + if (unlikely(!mem)) { /* - * OK, try a store and see if we can populate the tlb. This - * might cause an exception if the memory isn't writable, - * in which case we will longjmp out of here. We must for - * this purpose use the actual register value passed to us - * so that we get the fault address right. + * The only remaining reason for mem == NULL is I/O. + * Just do a series of byte writes as the architecture demands. */ - helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC()); - /* Now we can populate the other TLB entries, if any */ - for (i = 0; i < maxidx; i++) { - uint64_t va = vaddr + TARGET_PAGE_SIZE * i; - if (va != (vaddr_in & TARGET_PAGE_MASK)) { - helper_ret_stb_mmu(env, va, 0, oi, GETPC()); - } + for (int i = 0; i < blocklen; i++) { + cpu_stb_mmuidx_ra(env, vaddr + i, 0, mmu_idx, ra); } - } - - /* - * Slow path (probably attempt to do this to an I/O device or - * similar, or clearing of a block of code we have translations - * cached for). Just do a series of byte writes as the architecture - * demands. It's not worth trying to use a cpu_physical_memory_map(), - * memset(), unmap() sequence here because: - * + we'd need to account for the blocksize being larger than a page - * + the direct-RAM access case is almost always going to be dealt - * with in the fastpath code above, so there's no speed benefit - * + we would have to deal with the map returning NULL because the - * bounce buffer was in use - */ - for (i = 0; i < blocklen; i++) { - helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC()); + return; } } -#else - memset(g2h(vaddr), 0, blocklen); #endif + + memset(mem, 0, blocklen); } From 5f716a82388eb09754dd900e7dbb8ffa15897a28 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:17 -0700 Subject: [PATCH 1666/2595] target/arm: Implement the LDGM, STGM, STZGM instructions Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-20-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-a64.h | 3 ++ target/arm/mte_helper.c | 84 ++++++++++++++++++++++++++++++++++++++ target/arm/translate-a64.c | 72 ++++++++++++++++++++++++++++---- target/arm/translate.h | 2 + 4 files changed, 153 insertions(+), 8 deletions(-) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index 2fa61b86fa..7b628d100e 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -113,3 +113,6 @@ DEF_HELPER_FLAGS_2(stg_stub, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_3(st2g, TCG_CALL_NO_WG, void, env, i64, i64) DEF_HELPER_FLAGS_3(st2g_parallel, TCG_CALL_NO_WG, void, env, i64, i64) DEF_HELPER_FLAGS_2(st2g_stub, TCG_CALL_NO_WG, void, env, i64) +DEF_HELPER_FLAGS_2(ldgm, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(stgm, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_3(stzgm_tags, TCG_CALL_NO_WG, void, env, i64, i64) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 7ec7930dfc..27d4b4536c 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -274,3 +274,87 @@ void HELPER(st2g_stub)(CPUARMState *env, uint64_t ptr) probe_write(env, ptr + TAG_GRANULE, TAG_GRANULE, mmu_idx, ra); } } + +#define LDGM_STGM_SIZE (4 << GMID_EL1_BS) + +uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr) +{ + int mmu_idx = cpu_mmu_index(env, false); + uintptr_t ra = GETPC(); + void *tag_mem; + + ptr = QEMU_ALIGN_DOWN(ptr, LDGM_STGM_SIZE); + + /* Trap if accessing an invalid page. */ + tag_mem = allocation_tag_mem(env, mmu_idx, ptr, MMU_DATA_LOAD, + LDGM_STGM_SIZE, MMU_DATA_LOAD, + LDGM_STGM_SIZE / (2 * TAG_GRANULE), ra); + + /* The tag is squashed to zero if the page does not support tags. */ + if (!tag_mem) { + return 0; + } + + QEMU_BUILD_BUG_ON(GMID_EL1_BS != 6); + /* + * We are loading 64-bits worth of tags. The ordering of elements + * within the word corresponds to a 64-bit little-endian operation. + */ + return ldq_le_p(tag_mem); +} + +void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) +{ + int mmu_idx = cpu_mmu_index(env, false); + uintptr_t ra = GETPC(); + void *tag_mem; + + ptr = QEMU_ALIGN_DOWN(ptr, LDGM_STGM_SIZE); + + /* Trap if accessing an invalid page. */ + tag_mem = allocation_tag_mem(env, mmu_idx, ptr, MMU_DATA_STORE, + LDGM_STGM_SIZE, MMU_DATA_LOAD, + LDGM_STGM_SIZE / (2 * TAG_GRANULE), ra); + + /* + * Tag store only happens if the page support tags, + * and if the OS has enabled access to the tags. + */ + if (!tag_mem) { + return; + } + + QEMU_BUILD_BUG_ON(GMID_EL1_BS != 6); + /* + * We are storing 64-bits worth of tags. The ordering of elements + * within the word corresponds to a 64-bit little-endian operation. + */ + stq_le_p(tag_mem, val); +} + +void HELPER(stzgm_tags)(CPUARMState *env, uint64_t ptr, uint64_t val) +{ + uintptr_t ra = GETPC(); + int mmu_idx = cpu_mmu_index(env, false); + int log2_dcz_bytes, log2_tag_bytes; + intptr_t dcz_bytes, tag_bytes; + uint8_t *mem; + + /* + * In arm_cpu_realizefn, we assert that dcz > LOG2_TAG_GRANULE+1, + * i.e. 32 bytes, which is an unreasonably small dcz anyway, + * to make sure that we can access one complete tag byte here. + */ + log2_dcz_bytes = env_archcpu(env)->dcz_blocksize + 2; + log2_tag_bytes = log2_dcz_bytes - (LOG2_TAG_GRANULE + 1); + dcz_bytes = (intptr_t)1 << log2_dcz_bytes; + tag_bytes = (intptr_t)1 << log2_tag_bytes; + ptr &= -dcz_bytes; + + mem = allocation_tag_mem(env, mmu_idx, ptr, MMU_DATA_STORE, dcz_bytes, + MMU_DATA_STORE, tag_bytes, ra); + if (mem) { + int tag_pair = (val & 0xf) * 0x11; + memset(mem, tag_pair, tag_bytes); + } +} diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index e2295a371b..7dc493774e 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -3736,7 +3736,7 @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn) uint64_t offset = sextract64(insn, 12, 9) << LOG2_TAG_GRANULE; int op2 = extract32(insn, 10, 2); int op1 = extract32(insn, 22, 2); - bool is_load = false, is_pair = false, is_zero = false; + bool is_load = false, is_pair = false, is_zero = false, is_mult = false; int index = 0; TCGv_i64 addr, clean_addr, tcg_rt; @@ -3756,9 +3756,14 @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn) if (op2 != 0) { /* STG */ index = op2 - 2; - break; + } else { + /* STZGM */ + if (s->current_el == 0 || offset != 0) { + goto do_unallocated; + } + is_mult = is_zero = true; } - goto do_unallocated; + break; case 1: if (op2 != 0) { /* STZG */ @@ -3774,17 +3779,27 @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn) /* ST2G */ is_pair = true; index = op2 - 2; - break; + } else { + /* STGM */ + if (s->current_el == 0 || offset != 0) { + goto do_unallocated; + } + is_mult = true; } - goto do_unallocated; + break; case 3: if (op2 != 0) { /* STZ2G */ is_pair = is_zero = true; index = op2 - 2; - break; + } else { + /* LDGM */ + if (s->current_el == 0 || offset != 0) { + goto do_unallocated; + } + is_mult = is_load = true; } - goto do_unallocated; + break; default: do_unallocated: @@ -3792,7 +3807,9 @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn) return; } - if (!dc_isar_feature(aa64_mte_insn_reg, s)) { + if (is_mult + ? !dc_isar_feature(aa64_mte, s) + : !dc_isar_feature(aa64_mte_insn_reg, s)) { goto do_unallocated; } @@ -3806,6 +3823,44 @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn) tcg_gen_addi_i64(addr, addr, offset); } + if (is_mult) { + tcg_rt = cpu_reg(s, rt); + + if (is_zero) { + int size = 4 << s->dcz_blocksize; + + if (s->ata) { + gen_helper_stzgm_tags(cpu_env, addr, tcg_rt); + } + /* + * The non-tags portion of STZGM is mostly like DC_ZVA, + * except the alignment happens before the access. + */ + clean_addr = clean_data_tbi(s, addr); + tcg_gen_andi_i64(clean_addr, clean_addr, -size); + gen_helper_dc_zva(cpu_env, clean_addr); + } else if (s->ata) { + if (is_load) { + gen_helper_ldgm(tcg_rt, cpu_env, addr); + } else { + gen_helper_stgm(cpu_env, addr, tcg_rt); + } + } else { + MMUAccessType acc = is_load ? MMU_DATA_LOAD : MMU_DATA_STORE; + int size = 4 << GMID_EL1_BS; + + clean_addr = clean_data_tbi(s, addr); + tcg_gen_andi_i64(clean_addr, clean_addr, -size); + gen_probe_access(s, clean_addr, acc, size); + + if (is_load) { + /* The result tags are zeros. */ + tcg_gen_movi_i64(tcg_rt, 0); + } + } + return; + } + if (is_load) { tcg_gen_andi_i64(addr, addr, -TAG_GRANULE); tcg_rt = cpu_reg(s, rt); @@ -14472,6 +14527,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->vec_stride = 0; dc->cp_regs = arm_cpu->cp_regs; dc->features = env->features; + dc->dcz_blocksize = arm_cpu->dcz_blocksize; /* Single step state. The code-generation logic here is: * SS_ACTIVE == 0: diff --git a/target/arm/translate.h b/target/arm/translate.h index 98bcc37c47..16f2699ad7 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -91,6 +91,8 @@ typedef struct DisasContext { * < 0, set by the current instruction. */ int8_t btype; + /* A copy of cpu->dcz_blocksize. */ + uint8_t dcz_blocksize; /* True if this page is guarded. */ bool guarded_page; /* Bottom two bits of XScale c15_cpar coprocessor access control reg */ From 5463df160ecee510e78493993eb1bd38b4838a10 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:18 -0700 Subject: [PATCH 1667/2595] target/arm: Implement the access tag cache flushes Like the regular data cache flushes, these are nops within qemu. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-21-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index 2c6ec244af..d8c31d03da 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6929,6 +6929,32 @@ static const ARMCPRegInfo mte_reginfo[] = { .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 7, .type = ARM_CP_NO_RAW, .access = PL0_RW, .readfn = tco_read, .writefn = tco_write }, + { .name = "DC_IGVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 3, + .type = ARM_CP_NOP, .access = PL1_W, + .accessfn = aa64_cacheop_poc_access }, + { .name = "DC_IGSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 4, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, + { .name = "DC_IGDVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 5, + .type = ARM_CP_NOP, .access = PL1_W, + .accessfn = aa64_cacheop_poc_access }, + { .name = "DC_IGDSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 6, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, + { .name = "DC_CGSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 4, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, + { .name = "DC_CGDSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 6, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, + { .name = "DC_CIGSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 4, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, + { .name = "DC_CIGDSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 6, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, REGINFO_SENTINEL }; @@ -6938,6 +6964,43 @@ static const ARMCPRegInfo mte_tco_ro_reginfo[] = { .type = ARM_CP_CONST, .access = PL0_RW, }, REGINFO_SENTINEL }; + +static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { + { .name = "DC_CGVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 10, .opc2 = 3, + .type = ARM_CP_NOP, .access = PL0_W, + .accessfn = aa64_cacheop_poc_access }, + { .name = "DC_CGDVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 10, .opc2 = 5, + .type = ARM_CP_NOP, .access = PL0_W, + .accessfn = aa64_cacheop_poc_access }, + { .name = "DC_CGVAP", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 3, + .type = ARM_CP_NOP, .access = PL0_W, + .accessfn = aa64_cacheop_poc_access }, + { .name = "DC_CGDVAP", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 5, + .type = ARM_CP_NOP, .access = PL0_W, + .accessfn = aa64_cacheop_poc_access }, + { .name = "DC_CGVADP", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 3, + .type = ARM_CP_NOP, .access = PL0_W, + .accessfn = aa64_cacheop_poc_access }, + { .name = "DC_CGDVADP", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 5, + .type = ARM_CP_NOP, .access = PL0_W, + .accessfn = aa64_cacheop_poc_access }, + { .name = "DC_CIGVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 3, + .type = ARM_CP_NOP, .access = PL0_W, + .accessfn = aa64_cacheop_poc_access }, + { .name = "DC_CIGDVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 5, + .type = ARM_CP_NOP, .access = PL0_W, + .accessfn = aa64_cacheop_poc_access }, + REGINFO_SENTINEL +}; + #endif static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri, @@ -8071,8 +8134,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) */ if (cpu_isar_feature(aa64_mte, cpu)) { define_arm_cp_regs(cpu, mte_reginfo); + define_arm_cp_regs(cpu, mte_el0_cacheop_reginfo); } else if (cpu_isar_feature(aa64_mte_insn_reg, cpu)) { define_arm_cp_regs(cpu, mte_tco_ro_reginfo); + define_arm_cp_regs(cpu, mte_el0_cacheop_reginfo); } #endif From 9c7ab8fc8cb6d6e2fb7a82c1088691c7c23fa1b9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:19 -0700 Subject: [PATCH 1668/2595] target/arm: Move regime_el to internals.h We will shortly need this in mte_helper.c as well. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-22-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 36 ------------------------------------ target/arm/internals.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index d8c31d03da..d14313de66 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9793,42 +9793,6 @@ void arm_cpu_do_interrupt(CPUState *cs) } #endif /* !CONFIG_USER_ONLY */ -/* Return the exception level which controls this address translation regime */ -static uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) -{ - switch (mmu_idx) { - case ARMMMUIdx_E20_0: - case ARMMMUIdx_E20_2: - case ARMMMUIdx_E20_2_PAN: - case ARMMMUIdx_Stage2: - case ARMMMUIdx_E2: - return 2; - case ARMMMUIdx_SE3: - return 3; - case ARMMMUIdx_SE10_0: - return arm_el_is_aa64(env, 3) ? 1 : 3; - case ARMMMUIdx_SE10_1: - case ARMMMUIdx_SE10_1_PAN: - case ARMMMUIdx_Stage1_E0: - case ARMMMUIdx_Stage1_E1: - case ARMMMUIdx_Stage1_E1_PAN: - case ARMMMUIdx_E10_0: - case ARMMMUIdx_E10_1: - case ARMMMUIdx_E10_1_PAN: - case ARMMMUIdx_MPrivNegPri: - case ARMMMUIdx_MUserNegPri: - case ARMMMUIdx_MPriv: - case ARMMMUIdx_MUser: - case ARMMMUIdx_MSPrivNegPri: - case ARMMMUIdx_MSUserNegPri: - case ARMMMUIdx_MSPriv: - case ARMMMUIdx_MSUser: - return 1; - default: - g_assert_not_reached(); - } -} - uint64_t arm_sctlr(CPUARMState *env, int el) { /* Only EL0 needs to be adjusted for EL1&0 or EL2&0. */ diff --git a/target/arm/internals.h b/target/arm/internals.h index 5c69d4e5a5..c36fcb151b 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -913,6 +913,42 @@ static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx) } } +/* Return the exception level which controls this address translation regime */ +static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + switch (mmu_idx) { + case ARMMMUIdx_E20_0: + case ARMMMUIdx_E20_2: + case ARMMMUIdx_E20_2_PAN: + case ARMMMUIdx_Stage2: + case ARMMMUIdx_E2: + return 2; + case ARMMMUIdx_SE3: + return 3; + case ARMMMUIdx_SE10_0: + return arm_el_is_aa64(env, 3) ? 1 : 3; + case ARMMMUIdx_SE10_1: + case ARMMMUIdx_SE10_1_PAN: + case ARMMMUIdx_Stage1_E0: + case ARMMMUIdx_Stage1_E1: + case ARMMMUIdx_Stage1_E1_PAN: + case ARMMMUIdx_E10_0: + case ARMMMUIdx_E10_1: + case ARMMMUIdx_E10_1_PAN: + case ARMMMUIdx_MPrivNegPri: + case ARMMMUIdx_MUserNegPri: + case ARMMMUIdx_MPriv: + case ARMMMUIdx_MUser: + case ARMMMUIdx_MSPrivNegPri: + case ARMMMUIdx_MSUserNegPri: + case ARMMMUIdx_MSPriv: + case ARMMMUIdx_MSUser: + return 1; + default: + g_assert_not_reached(); + } +} + /* Return the FSR value for a debug exception (watchpoint, hardware * breakpoint or BKPT insn) targeting the specified exception level. */ From 38659d311d05e6c5feff6bddcc1c33b60d3b86a1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:20 -0700 Subject: [PATCH 1669/2595] target/arm: Move regime_tcr to internals.h We will shortly need this in mte_helper.c as well. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-23-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 9 --------- target/arm/internals.h | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index d14313de66..33f902387b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9875,15 +9875,6 @@ static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, #endif /* !CONFIG_USER_ONLY */ -/* Return the TCR controlling this translation regime */ -static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx) -{ - if (mmu_idx == ARMMMUIdx_Stage2) { - return &env->cp15.vtcr_el2; - } - return &env->cp15.tcr_el[regime_el(env, mmu_idx)]; -} - /* Convert a possible stage1+2 MMU index into the appropriate * stage 1 MMU index */ diff --git a/target/arm/internals.h b/target/arm/internals.h index c36fcb151b..7c9abbabc9 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -949,6 +949,15 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) } } +/* Return the TCR controlling this translation regime */ +static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + if (mmu_idx == ARMMMUIdx_Stage2) { + return &env->cp15.vtcr_el2; + } + return &env->cp15.tcr_el[regime_el(env, mmu_idx)]; +} + /* Return the FSR value for a debug exception (watchpoint, hardware * breakpoint or BKPT insn) targeting the specified exception level. */ From 0a405be2b8fd9506a009b10d7d2d98c394b36db6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:21 -0700 Subject: [PATCH 1670/2595] target/arm: Add gen_mte_check1 Replace existing uses of check_data_tbi in translate-a64.c that perform a single logical memory access. Leave the helper blank for now to reduce the patch size. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-24-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-a64.h | 1 + target/arm/internals.h | 8 +++ target/arm/mte_helper.c | 8 +++ target/arm/translate-a64.c | 100 ++++++++++++++++++++++++++++--------- target/arm/translate-a64.h | 2 + 5 files changed, 95 insertions(+), 24 deletions(-) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index 7b628d100e..2faa49d0a3 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -104,6 +104,7 @@ DEF_HELPER_FLAGS_3(autdb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_2(xpaci, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64) +DEF_HELPER_FLAGS_3(mte_check1, TCG_CALL_NO_WG, i64, env, i32, i64) DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_4(addsubg, TCG_CALL_NO_RWG_SE, i64, env, i64, s32, i32) DEF_HELPER_FLAGS_3(ldg, TCG_CALL_NO_WG, i64, env, i64, i64) diff --git a/target/arm/internals.h b/target/arm/internals.h index 7c9abbabc9..fb92ef6b84 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1310,6 +1310,14 @@ void arm_log_exception(int idx); #define LOG2_TAG_GRANULE 4 #define TAG_GRANULE (1 << LOG2_TAG_GRANULE) +/* Bits within a descriptor passed to the helper_mte_check* functions. */ +FIELD(MTEDESC, MIDX, 0, 4) +FIELD(MTEDESC, TBI, 4, 2) +FIELD(MTEDESC, TCMA, 6, 2) +FIELD(MTEDESC, WRITE, 8, 1) +FIELD(MTEDESC, ESIZE, 9, 5) +FIELD(MTEDESC, TSIZE, 14, 10) /* mte_checkN only */ + static inline int allocation_tag_from_addr(uint64_t ptr) { return extract64(ptr, 56, 4); diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 27d4b4536c..ec12768dfc 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -358,3 +358,11 @@ void HELPER(stzgm_tags)(CPUARMState *env, uint64_t ptr, uint64_t val) memset(mem, tag_pair, tag_bytes); } } + +/* + * Perform an MTE checked access for a single logical or atomic access. + */ +uint64_t HELPER(mte_check1)(CPUARMState *env, uint32_t desc, uint64_t ptr) +{ + return ptr; +} diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 7dc493774e..4d0453c895 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -204,20 +204,20 @@ static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src) } /* - * Return a "clean" address for ADDR according to TBID. - * This is always a fresh temporary, as we need to be able to - * increment this independently of a dirty write-back address. + * Handle MTE and/or TBI. + * + * For TBI, ideally, we would do nothing. Proper behaviour on fault is + * for the tag to be present in the FAR_ELx register. But for user-only + * mode we do not have a TLB with which to implement this, so we must + * remove the top byte now. + * + * Always return a fresh temporary that we can increment independently + * of the write-back address. */ + static TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr) { TCGv_i64 clean = new_tmp_a64(s); - /* - * In order to get the correct value in the FAR_ELx register, - * we must present the memory subsystem with the "dirty" address - * including the TBI. In system mode we can make this work via - * the TLB, dropping the TBI during translation. But for user-only - * mode we don't have that option, and must remove the top byte now. - */ #ifdef CONFIG_USER_ONLY gen_top_byte_ignore(s, clean, addr, s->tbid); #else @@ -245,6 +245,45 @@ static void gen_probe_access(DisasContext *s, TCGv_i64 ptr, tcg_temp_free_i32(t_size); } +/* + * For MTE, check a single logical or atomic access. This probes a single + * address, the exact one specified. The size and alignment of the access + * is not relevant to MTE, per se, but watchpoints do require the size, + * and we want to recognize those before making any other changes to state. + */ +static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr, + bool is_write, bool tag_checked, + int log2_size, bool is_unpriv, + int core_idx) +{ + if (tag_checked && s->mte_active[is_unpriv]) { + TCGv_i32 tcg_desc; + TCGv_i64 ret; + int desc = 0; + + desc = FIELD_DP32(desc, MTEDESC, MIDX, core_idx); + desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); + desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); + desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); + desc = FIELD_DP32(desc, MTEDESC, ESIZE, 1 << log2_size); + tcg_desc = tcg_const_i32(desc); + + ret = new_tmp_a64(s); + gen_helper_mte_check1(ret, cpu_env, tcg_desc, addr); + tcg_temp_free_i32(tcg_desc); + + return ret; + } + return clean_data_tbi(s, addr); +} + +TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write, + bool tag_checked, int log2_size) +{ + return gen_mte_check1_mmuidx(s, addr, is_write, tag_checked, log2_size, + false, get_mem_index(s)); +} + typedef struct DisasCompare64 { TCGCond cond; TCGv_i64 value; @@ -2367,7 +2406,7 @@ static void gen_compare_and_swap(DisasContext *s, int rs, int rt, if (rn == 31) { gen_check_sp_alignment(s); } - clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); + clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, size); tcg_gen_atomic_cmpxchg_i64(tcg_rs, clean_addr, tcg_rs, tcg_rt, memidx, size | MO_ALIGN | s->be_data); } @@ -2385,7 +2424,9 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt, if (rn == 31) { gen_check_sp_alignment(s); } - clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); + + /* This is a single atomic access, despite the "pair". */ + clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, size + 1); if (size == 2) { TCGv_i64 cmp = tcg_temp_new_i64(); @@ -2510,7 +2551,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) if (is_lasr) { tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); } - clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); + clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), + true, rn != 31, size); gen_store_exclusive(s, rs, rt, rt2, clean_addr, size, false); return; @@ -2519,7 +2561,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) if (rn == 31) { gen_check_sp_alignment(s); } - clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); + clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), + false, rn != 31, size); s->is_ldex = true; gen_load_exclusive(s, rt, rt2, clean_addr, size, false); if (is_lasr) { @@ -2539,7 +2582,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) gen_check_sp_alignment(s); } tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); - clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); + clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), + true, rn != 31, size); do_gpr_st(s, cpu_reg(s, rt), clean_addr, size, true, rt, disas_ldst_compute_iss_sf(size, false, 0), is_lasr); return; @@ -2555,7 +2599,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) if (rn == 31) { gen_check_sp_alignment(s); } - clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); + clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), + false, rn != 31, size); do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false, false, true, rt, disas_ldst_compute_iss_sf(size, false, 0), is_lasr); tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); @@ -2569,7 +2614,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) if (is_lasr) { tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); } - clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); + clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), + true, rn != 31, size); gen_store_exclusive(s, rs, rt, rt2, clean_addr, size, true); return; } @@ -2587,7 +2633,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) if (rn == 31) { gen_check_sp_alignment(s); } - clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); + clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), + false, rn != 31, size); s->is_ldex = true; gen_load_exclusive(s, rt, rt2, clean_addr, size, true); if (is_lasr) { @@ -2881,6 +2928,7 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, bool iss_valid = !is_vector; bool post_index; bool writeback; + int memidx; TCGv_i64 clean_addr, dirty_addr; @@ -2938,7 +2986,11 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, if (!post_index) { tcg_gen_addi_i64(dirty_addr, dirty_addr, imm9); } - clean_addr = clean_data_tbi(s, dirty_addr); + + memidx = is_unpriv ? get_a64_user_mem_index(s) : get_mem_index(s); + clean_addr = gen_mte_check1_mmuidx(s, dirty_addr, is_store, + writeback || rn != 31, + size, is_unpriv, memidx); if (is_vector) { if (is_store) { @@ -2948,7 +3000,6 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, } } else { TCGv_i64 tcg_rt = cpu_reg(s, rt); - int memidx = is_unpriv ? get_a64_user_mem_index(s) : get_mem_index(s); bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc); if (is_store) { @@ -3045,7 +3096,7 @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn, ext_and_shift_reg(tcg_rm, tcg_rm, opt, shift ? size : 0); tcg_gen_add_i64(dirty_addr, dirty_addr, tcg_rm); - clean_addr = clean_data_tbi(s, dirty_addr); + clean_addr = gen_mte_check1(s, dirty_addr, is_store, true, size); if (is_vector) { if (is_store) { @@ -3130,7 +3181,7 @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn, dirty_addr = read_cpu_reg_sp(s, rn, 1); offset = imm12 << size; tcg_gen_addi_i64(dirty_addr, dirty_addr, offset); - clean_addr = clean_data_tbi(s, dirty_addr); + clean_addr = gen_mte_check1(s, dirty_addr, is_store, rn != 31, size); if (is_vector) { if (is_store) { @@ -3223,7 +3274,7 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn, if (rn == 31) { gen_check_sp_alignment(s); } - clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); + clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), false, rn != 31, size); if (o3_opc == 014) { /* @@ -3300,7 +3351,8 @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn, tcg_gen_addi_i64(dirty_addr, dirty_addr, offset); /* Note that "clean" and "dirty" here refer to TBI not PAC. */ - clean_addr = clean_data_tbi(s, dirty_addr); + clean_addr = gen_mte_check1(s, dirty_addr, false, + is_wback || rn != 31, size); tcg_rt = cpu_reg(s, rt); do_gpr_ld(s, tcg_rt, clean_addr, size, /* is_signed */ false, diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index da0f59a2ce..daab6a9666 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -40,6 +40,8 @@ TCGv_ptr get_fpstatus_ptr(bool); bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn, unsigned int imms, unsigned int immr); bool sve_access_check(DisasContext *s); +TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write, + bool tag_checked, int log2_size); /* We should have at some point before trying to access an FP register * done the necessary access check, so assert that From 73ceeb0011b23bac8bd2c09ebe3c18d034aa69ce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:22 -0700 Subject: [PATCH 1671/2595] target/arm: Add gen_mte_checkN Replace existing uses of check_data_tbi in translate-a64.c that perform multiple logical memory access. Leave the helper blank for now to reduce the patch size. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-25-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-a64.h | 1 + target/arm/mte_helper.c | 8 +++++ target/arm/translate-a64.c | 71 +++++++++++++++++++++++++++++--------- target/arm/translate-a64.h | 2 ++ 4 files changed, 66 insertions(+), 16 deletions(-) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index 2faa49d0a3..005af678c7 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -105,6 +105,7 @@ DEF_HELPER_FLAGS_2(xpaci, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(mte_check1, TCG_CALL_NO_WG, i64, env, i32, i64) +DEF_HELPER_FLAGS_3(mte_checkN, TCG_CALL_NO_WG, i64, env, i32, i64) DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_4(addsubg, TCG_CALL_NO_RWG_SE, i64, env, i64, s32, i32) DEF_HELPER_FLAGS_3(ldg, TCG_CALL_NO_WG, i64, env, i64, i64) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index ec12768dfc..907a12b366 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -366,3 +366,11 @@ uint64_t HELPER(mte_check1)(CPUARMState *env, uint32_t desc, uint64_t ptr) { return ptr; } + +/* + * Perform an MTE checked access for multiple logical accesses. + */ +uint64_t HELPER(mte_checkN)(CPUARMState *env, uint32_t desc, uint64_t ptr) +{ + return ptr; +} diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 4d0453c895..52be0400d7 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -284,6 +284,34 @@ TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write, false, get_mem_index(s)); } +/* + * For MTE, check multiple logical sequential accesses. + */ +TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, + bool tag_checked, int log2_esize, int total_size) +{ + if (tag_checked && s->mte_active[0] && total_size != (1 << log2_esize)) { + TCGv_i32 tcg_desc; + TCGv_i64 ret; + int desc = 0; + + desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); + desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); + desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); + desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); + desc = FIELD_DP32(desc, MTEDESC, ESIZE, 1 << log2_esize); + desc = FIELD_DP32(desc, MTEDESC, TSIZE, total_size); + tcg_desc = tcg_const_i32(desc); + + ret = new_tmp_a64(s); + gen_helper_mte_checkN(ret, cpu_env, tcg_desc, addr); + tcg_temp_free_i32(tcg_desc); + + return ret; + } + return gen_mte_check1(s, addr, is_write, tag_checked, log2_esize); +} + typedef struct DisasCompare64 { TCGCond cond; TCGv_i64 value; @@ -2848,7 +2876,10 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) } } - clean_addr = clean_data_tbi(s, dirty_addr); + clean_addr = gen_mte_checkN(s, dirty_addr, !is_load, + (wback || rn != 31) && !set_tag, + size, 2 << size); + if (is_vector) { if (is_load) { do_fp_ld(s, rt, clean_addr, size); @@ -3514,7 +3545,7 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) TCGv_i64 clean_addr, tcg_rn, tcg_ebytes; MemOp endian = s->be_data; - int ebytes; /* bytes per element */ + int total; /* total bytes */ int elements; /* elements per vector */ int rpt; /* num iterations */ int selem; /* structure elements */ @@ -3584,19 +3615,26 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) endian = MO_LE; } - /* Consecutive little-endian elements from a single register + total = rpt * selem * (is_q ? 16 : 8); + tcg_rn = cpu_reg_sp(s, rn); + + /* + * Issue the MTE check vs the logical repeat count, before we + * promote consecutive little-endian elements below. + */ + clean_addr = gen_mte_checkN(s, tcg_rn, is_store, is_postidx || rn != 31, + size, total); + + /* + * Consecutive little-endian elements from a single register * can be promoted to a larger little-endian operation. */ if (selem == 1 && endian == MO_LE) { size = 3; } - ebytes = 1 << size; - elements = (is_q ? 16 : 8) / ebytes; - - tcg_rn = cpu_reg_sp(s, rn); - clean_addr = clean_data_tbi(s, tcg_rn); - tcg_ebytes = tcg_const_i64(ebytes); + elements = (is_q ? 16 : 8) >> size; + tcg_ebytes = tcg_const_i64(1 << size); for (r = 0; r < rpt; r++) { int e; for (e = 0; e < elements; e++) { @@ -3630,7 +3668,7 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) if (is_postidx) { if (rm == 31) { - tcg_gen_addi_i64(tcg_rn, tcg_rn, rpt * elements * selem * ebytes); + tcg_gen_addi_i64(tcg_rn, tcg_rn, total); } else { tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm)); } @@ -3676,7 +3714,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) int selem = (extract32(opc, 0, 1) << 1 | R) + 1; bool replicate = false; int index = is_q << 3 | S << 2 | size; - int ebytes, xs; + int xs, total; TCGv_i64 clean_addr, tcg_rn, tcg_ebytes; if (extract32(insn, 31, 1)) { @@ -3730,16 +3768,17 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) return; } - ebytes = 1 << scale; - if (rn == 31) { gen_check_sp_alignment(s); } + total = selem << scale; tcg_rn = cpu_reg_sp(s, rn); - clean_addr = clean_data_tbi(s, tcg_rn); - tcg_ebytes = tcg_const_i64(ebytes); + clean_addr = gen_mte_checkN(s, tcg_rn, !is_load, is_postidx || rn != 31, + scale, total); + + tcg_ebytes = tcg_const_i64(1 << scale); for (xs = 0; xs < selem; xs++) { if (replicate) { /* Load and replicate to all elements */ @@ -3766,7 +3805,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) if (is_postidx) { if (rm == 31) { - tcg_gen_addi_i64(tcg_rn, tcg_rn, selem * ebytes); + tcg_gen_addi_i64(tcg_rn, tcg_rn, total); } else { tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm)); } diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index daab6a9666..781c441399 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -42,6 +42,8 @@ bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn, bool sve_access_check(DisasContext *s); TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write, bool tag_checked, int log2_size); +TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, + bool tag_checked, int count, int log2_esize); /* We should have at some point before trying to access an FP register * done the necessary access check, so assert that From 2e34ff45f32cb032883616a1cc5ea8ac96f546d5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:23 -0700 Subject: [PATCH 1672/2595] target/arm: Implement helper_mte_check1 Fill out the stub that was added earlier. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-26-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/internals.h | 48 +++++++++++++++ target/arm/mte_helper.c | 132 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 179 insertions(+), 1 deletion(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index fb92ef6b84..807830cc40 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1318,6 +1318,10 @@ FIELD(MTEDESC, WRITE, 8, 1) FIELD(MTEDESC, ESIZE, 9, 5) FIELD(MTEDESC, TSIZE, 14, 10) /* mte_checkN only */ +bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr); +uint64_t mte_check1(CPUARMState *env, uint32_t desc, + uint64_t ptr, uintptr_t ra); + static inline int allocation_tag_from_addr(uint64_t ptr) { return extract64(ptr, 56, 4); @@ -1328,4 +1332,48 @@ static inline uint64_t address_with_allocation_tag(uint64_t ptr, int rtag) return deposit64(ptr, 56, 4, rtag); } +/* Return true if tbi bits mean that the access is checked. */ +static inline bool tbi_check(uint32_t desc, int bit55) +{ + return (desc >> (R_MTEDESC_TBI_SHIFT + bit55)) & 1; +} + +/* Return true if tcma bits mean that the access is unchecked. */ +static inline bool tcma_check(uint32_t desc, int bit55, int ptr_tag) +{ + /* + * We had extracted bit55 and ptr_tag for other reasons, so fold + * (ptr<59:55> == 00000 || ptr<59:55> == 11111) into a single test. + */ + bool match = ((ptr_tag + bit55) & 0xf) == 0; + bool tcma = (desc >> (R_MTEDESC_TCMA_SHIFT + bit55)) & 1; + return tcma && match; +} + +/* + * For TBI, ideally, we would do nothing. Proper behaviour on fault is + * for the tag to be present in the FAR_ELx register. But for user-only + * mode, we do not have a TLB with which to implement this, so we must + * remove the top byte. + */ +static inline uint64_t useronly_clean_ptr(uint64_t ptr) +{ + /* TBI is known to be enabled. */ +#ifdef CONFIG_USER_ONLY + ptr = sextract64(ptr, 0, 56); +#endif + return ptr; +} + +static inline uint64_t useronly_maybe_clean_ptr(uint32_t desc, uint64_t ptr) +{ +#ifdef CONFIG_USER_ONLY + int64_t clean_ptr = sextract64(ptr, 0, 56); + if (tbi_check(desc, clean_ptr < 0)) { + ptr = clean_ptr; + } +#endif + return ptr; +} + #endif diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 907a12b366..c8a5e7c0ed 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -359,12 +359,142 @@ void HELPER(stzgm_tags)(CPUARMState *env, uint64_t ptr, uint64_t val) } } +/* Record a tag check failure. */ +static void mte_check_fail(CPUARMState *env, int mmu_idx, + uint64_t dirty_ptr, uintptr_t ra) +{ + ARMMMUIdx arm_mmu_idx = core_to_aa64_mmu_idx(mmu_idx); + int el, reg_el, tcf, select; + uint64_t sctlr; + + reg_el = regime_el(env, arm_mmu_idx); + sctlr = env->cp15.sctlr_el[reg_el]; + + switch (arm_mmu_idx) { + case ARMMMUIdx_E10_0: + case ARMMMUIdx_E20_0: + el = 0; + tcf = extract64(sctlr, 38, 2); + break; + default: + el = reg_el; + tcf = extract64(sctlr, 40, 2); + } + + switch (tcf) { + case 1: + /* + * Tag check fail causes a synchronous exception. + * + * In restore_state_to_opc, we set the exception syndrome + * for the load or store operation. Unwind first so we + * may overwrite that with the syndrome for the tag check. + */ + cpu_restore_state(env_cpu(env), ra, true); + env->exception.vaddress = dirty_ptr; + raise_exception(env, EXCP_DATA_ABORT, + syn_data_abort_no_iss(el != 0, 0, 0, 0, 0, 0, 0x11), + exception_target_el(env)); + /* noreturn, but fall through to the assert anyway */ + + case 0: + /* + * Tag check fail does not affect the PE. + * We eliminate this case by not setting MTE_ACTIVE + * in tb_flags, so that we never make this runtime call. + */ + g_assert_not_reached(); + + case 2: + /* Tag check fail causes asynchronous flag set. */ + mmu_idx = arm_mmu_idx_el(env, el); + if (regime_has_2_ranges(mmu_idx)) { + select = extract64(dirty_ptr, 55, 1); + } else { + select = 0; + } + env->cp15.tfsr_el[el] |= 1 << select; + break; + + default: + /* Case 3: Reserved. */ + qemu_log_mask(LOG_GUEST_ERROR, + "Tag check failure with SCTLR_EL%d.TCF%s " + "set to reserved value %d\n", + reg_el, el ? "" : "0", tcf); + break; + } +} + /* * Perform an MTE checked access for a single logical or atomic access. */ +static bool mte_probe1_int(CPUARMState *env, uint32_t desc, uint64_t ptr, + uintptr_t ra, int bit55) +{ + int mem_tag, mmu_idx, ptr_tag, size; + MMUAccessType type; + uint8_t *mem; + + ptr_tag = allocation_tag_from_addr(ptr); + + if (tcma_check(desc, bit55, ptr_tag)) { + return true; + } + + mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX); + type = FIELD_EX32(desc, MTEDESC, WRITE) ? MMU_DATA_STORE : MMU_DATA_LOAD; + size = FIELD_EX32(desc, MTEDESC, ESIZE); + + mem = allocation_tag_mem(env, mmu_idx, ptr, type, size, + MMU_DATA_LOAD, 1, ra); + if (!mem) { + return true; + } + + mem_tag = load_tag1(ptr, mem); + return ptr_tag == mem_tag; +} + +/* + * No-fault version of mte_check1, to be used by SVE for MemSingleNF. + * Returns false if the access is Checked and the check failed. This + * is only intended to probe the tag -- the validity of the page must + * be checked beforehand. + */ +bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr) +{ + int bit55 = extract64(ptr, 55, 1); + + /* If TBI is disabled, the access is unchecked. */ + if (unlikely(!tbi_check(desc, bit55))) { + return true; + } + + return mte_probe1_int(env, desc, ptr, 0, bit55); +} + +uint64_t mte_check1(CPUARMState *env, uint32_t desc, + uint64_t ptr, uintptr_t ra) +{ + int bit55 = extract64(ptr, 55, 1); + + /* If TBI is disabled, the access is unchecked, and ptr is not dirty. */ + if (unlikely(!tbi_check(desc, bit55))) { + return ptr; + } + + if (unlikely(!mte_probe1_int(env, desc, ptr, ra, bit55))) { + int mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX); + mte_check_fail(env, mmu_idx, ptr, ra); + } + + return useronly_clean_ptr(ptr); +} + uint64_t HELPER(mte_check1)(CPUARMState *env, uint32_t desc, uint64_t ptr) { - return ptr; + return mte_check1(env, desc, ptr, GETPC()); } /* From 5add8248556a3c1006018d7d8e601c9572b280a9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:24 -0700 Subject: [PATCH 1673/2595] target/arm: Implement helper_mte_checkN Fill out the stub that was added earlier. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-27-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/internals.h | 2 + target/arm/mte_helper.c | 165 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 166 insertions(+), 1 deletion(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index 807830cc40..c763a23dfb 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1321,6 +1321,8 @@ FIELD(MTEDESC, TSIZE, 14, 10) /* mte_checkN only */ bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr); uint64_t mte_check1(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra); +uint64_t mte_checkN(CPUARMState *env, uint32_t desc, + uint64_t ptr, uintptr_t ra); static inline int allocation_tag_from_addr(uint64_t ptr) { diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index c8a5e7c0ed..abe6af6b79 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -500,7 +500,170 @@ uint64_t HELPER(mte_check1)(CPUARMState *env, uint32_t desc, uint64_t ptr) /* * Perform an MTE checked access for multiple logical accesses. */ + +/** + * checkN: + * @tag: tag memory to test + * @odd: true to begin testing at tags at odd nibble + * @cmp: the tag to compare against + * @count: number of tags to test + * + * Return the number of successful tests. + * Thus a return value < @count indicates a failure. + * + * A note about sizes: count is expected to be small. + * + * The most common use will be LDP/STP of two integer registers, + * which means 16 bytes of memory touching at most 2 tags, but + * often the access is aligned and thus just 1 tag. + * + * Using AdvSIMD LD/ST (multiple), one can access 64 bytes of memory, + * touching at most 5 tags. SVE LDR/STR (vector) with the default + * vector length is also 64 bytes; the maximum architectural length + * is 256 bytes touching at most 9 tags. + * + * The loop below uses 7 logical operations and 1 memory operation + * per tag pair. An implementation that loads an aligned word and + * uses masking to ignore adjacent tags requires 18 logical operations + * and thus does not begin to pay off until 6 tags. + * Which, according to the survey above, is unlikely to be common. + */ +static int checkN(uint8_t *mem, int odd, int cmp, int count) +{ + int n = 0, diff; + + /* Replicate the test tag and compare. */ + cmp *= 0x11; + diff = *mem++ ^ cmp; + + if (odd) { + goto start_odd; + } + + while (1) { + /* Test even tag. */ + if (unlikely((diff) & 0x0f)) { + break; + } + if (++n == count) { + break; + } + + start_odd: + /* Test odd tag. */ + if (unlikely((diff) & 0xf0)) { + break; + } + if (++n == count) { + break; + } + + diff = *mem++ ^ cmp; + } + return n; +} + +uint64_t mte_checkN(CPUARMState *env, uint32_t desc, + uint64_t ptr, uintptr_t ra) +{ + int mmu_idx, ptr_tag, bit55; + uint64_t ptr_last, ptr_end, prev_page, next_page; + uint64_t tag_first, tag_end; + uint64_t tag_byte_first, tag_byte_end; + uint32_t esize, total, tag_count, tag_size, n, c; + uint8_t *mem1, *mem2; + MMUAccessType type; + + bit55 = extract64(ptr, 55, 1); + + /* If TBI is disabled, the access is unchecked, and ptr is not dirty. */ + if (unlikely(!tbi_check(desc, bit55))) { + return ptr; + } + + ptr_tag = allocation_tag_from_addr(ptr); + + if (tcma_check(desc, bit55, ptr_tag)) { + goto done; + } + + mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX); + type = FIELD_EX32(desc, MTEDESC, WRITE) ? MMU_DATA_STORE : MMU_DATA_LOAD; + esize = FIELD_EX32(desc, MTEDESC, ESIZE); + total = FIELD_EX32(desc, MTEDESC, TSIZE); + + /* Find the addr of the end of the access, and of the last element. */ + ptr_end = ptr + total; + ptr_last = ptr_end - esize; + + /* Round the bounds to the tag granule, and compute the number of tags. */ + tag_first = QEMU_ALIGN_DOWN(ptr, TAG_GRANULE); + tag_end = QEMU_ALIGN_UP(ptr_last, TAG_GRANULE); + tag_count = (tag_end - tag_first) / TAG_GRANULE; + + /* Round the bounds to twice the tag granule, and compute the bytes. */ + tag_byte_first = QEMU_ALIGN_DOWN(ptr, 2 * TAG_GRANULE); + tag_byte_end = QEMU_ALIGN_UP(ptr_last, 2 * TAG_GRANULE); + + /* Locate the page boundaries. */ + prev_page = ptr & TARGET_PAGE_MASK; + next_page = prev_page + TARGET_PAGE_SIZE; + + if (likely(tag_end - prev_page <= TARGET_PAGE_SIZE)) { + /* Memory access stays on one page. */ + tag_size = (tag_byte_end - tag_byte_first) / (2 * TAG_GRANULE); + mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, total, + MMU_DATA_LOAD, tag_size, ra); + if (!mem1) { + goto done; + } + /* Perform all of the comparisons. */ + n = checkN(mem1, ptr & TAG_GRANULE, ptr_tag, tag_count); + } else { + /* Memory access crosses to next page. */ + tag_size = (next_page - tag_byte_first) / (2 * TAG_GRANULE); + mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, next_page - ptr, + MMU_DATA_LOAD, tag_size, ra); + + tag_size = (tag_byte_end - next_page) / (2 * TAG_GRANULE); + mem2 = allocation_tag_mem(env, mmu_idx, next_page, type, + ptr_end - next_page, + MMU_DATA_LOAD, tag_size, ra); + + /* + * Perform all of the comparisons. + * Note the possible but unlikely case of the operation spanning + * two pages that do not both have tagging enabled. + */ + n = c = (next_page - tag_first) / TAG_GRANULE; + if (mem1) { + n = checkN(mem1, ptr & TAG_GRANULE, ptr_tag, c); + } + if (n == c) { + if (!mem2) { + goto done; + } + n += checkN(mem2, 0, ptr_tag, tag_count - c); + } + } + + /* + * If we failed, we know which granule. Compute the element that + * is first in that granule, and signal failure on that element. + */ + if (unlikely(n < tag_count)) { + uint64_t fail_ofs; + + fail_ofs = tag_first + n * TAG_GRANULE - ptr; + fail_ofs = ROUND_UP(fail_ofs, esize); + mte_check_fail(env, mmu_idx, ptr + fail_ofs, ra); + } + + done: + return useronly_clean_ptr(ptr); +} + uint64_t HELPER(mte_checkN)(CPUARMState *env, uint32_t desc, uint64_t ptr) { - return ptr; + return mte_checkN(env, desc, ptr, GETPC()); } From 46dc1bc0601554823a42ad27f236da2ad8f3bdc6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:25 -0700 Subject: [PATCH 1674/2595] target/arm: Add helper_mte_check_zva Use a special helper for DC_ZVA, rather than the more general mte_checkN. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-28-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-a64.h | 1 + target/arm/mte_helper.c | 106 +++++++++++++++++++++++++++++++++++++ target/arm/translate-a64.c | 16 +++++- 3 files changed, 122 insertions(+), 1 deletion(-) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index 005af678c7..5b0b699a50 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -106,6 +106,7 @@ DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(mte_check1, TCG_CALL_NO_WG, i64, env, i32, i64) DEF_HELPER_FLAGS_3(mte_checkN, TCG_CALL_NO_WG, i64, env, i32, i64) +DEF_HELPER_FLAGS_3(mte_check_zva, TCG_CALL_NO_WG, i64, env, i32, i64) DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_4(addsubg, TCG_CALL_NO_RWG_SE, i64, env, i64, s32, i32) DEF_HELPER_FLAGS_3(ldg, TCG_CALL_NO_WG, i64, env, i64, i64) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index abe6af6b79..4f9bd3add3 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -667,3 +667,109 @@ uint64_t HELPER(mte_checkN)(CPUARMState *env, uint32_t desc, uint64_t ptr) { return mte_checkN(env, desc, ptr, GETPC()); } + +/* + * Perform an MTE checked access for DC_ZVA. + */ +uint64_t HELPER(mte_check_zva)(CPUARMState *env, uint32_t desc, uint64_t ptr) +{ + uintptr_t ra = GETPC(); + int log2_dcz_bytes, log2_tag_bytes; + int mmu_idx, bit55; + intptr_t dcz_bytes, tag_bytes, i; + void *mem; + uint64_t ptr_tag, mem_tag, align_ptr; + + bit55 = extract64(ptr, 55, 1); + + /* If TBI is disabled, the access is unchecked, and ptr is not dirty. */ + if (unlikely(!tbi_check(desc, bit55))) { + return ptr; + } + + ptr_tag = allocation_tag_from_addr(ptr); + + if (tcma_check(desc, bit55, ptr_tag)) { + goto done; + } + + /* + * In arm_cpu_realizefn, we asserted that dcz > LOG2_TAG_GRANULE+1, + * i.e. 32 bytes, which is an unreasonably small dcz anyway, to make + * sure that we can access one complete tag byte here. + */ + log2_dcz_bytes = env_archcpu(env)->dcz_blocksize + 2; + log2_tag_bytes = log2_dcz_bytes - (LOG2_TAG_GRANULE + 1); + dcz_bytes = (intptr_t)1 << log2_dcz_bytes; + tag_bytes = (intptr_t)1 << log2_tag_bytes; + align_ptr = ptr & -dcz_bytes; + + /* + * Trap if accessing an invalid page. DC_ZVA requires that we supply + * the original pointer for an invalid page. But watchpoints require + * that we probe the actual space. So do both. + */ + mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX); + (void) probe_write(env, ptr, 1, mmu_idx, ra); + mem = allocation_tag_mem(env, mmu_idx, align_ptr, MMU_DATA_STORE, + dcz_bytes, MMU_DATA_LOAD, tag_bytes, ra); + if (!mem) { + goto done; + } + + /* + * Unlike the reasoning for checkN, DC_ZVA is always aligned, and thus + * it is quite easy to perform all of the comparisons at once without + * any extra masking. + * + * The most common zva block size is 64; some of the thunderx cpus use + * a block size of 128. For user-only, aarch64_max_initfn will set the + * block size to 512. Fill out the other cases for future-proofing. + * + * In order to be able to find the first miscompare later, we want the + * tag bytes to be in little-endian order. + */ + switch (log2_tag_bytes) { + case 0: /* zva_blocksize 32 */ + mem_tag = *(uint8_t *)mem; + ptr_tag *= 0x11u; + break; + case 1: /* zva_blocksize 64 */ + mem_tag = cpu_to_le16(*(uint16_t *)mem); + ptr_tag *= 0x1111u; + break; + case 2: /* zva_blocksize 128 */ + mem_tag = cpu_to_le32(*(uint32_t *)mem); + ptr_tag *= 0x11111111u; + break; + case 3: /* zva_blocksize 256 */ + mem_tag = cpu_to_le64(*(uint64_t *)mem); + ptr_tag *= 0x1111111111111111ull; + break; + + default: /* zva_blocksize 512, 1024, 2048 */ + ptr_tag *= 0x1111111111111111ull; + i = 0; + do { + mem_tag = cpu_to_le64(*(uint64_t *)(mem + i)); + if (unlikely(mem_tag != ptr_tag)) { + goto fail; + } + i += 8; + align_ptr += 16 * TAG_GRANULE; + } while (i < tag_bytes); + goto done; + } + + if (likely(mem_tag == ptr_tag)) { + goto done; + } + + fail: + /* Locate the first nibble that differs. */ + i = ctz64(mem_tag ^ ptr_tag) >> 4; + mte_check_fail(env, mmu_idx, align_ptr + i * TAG_GRANULE, ra); + + done: + return useronly_clean_ptr(ptr); +} diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 52be0400d7..a2a8280010 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1857,7 +1857,21 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, return; case ARM_CP_DC_ZVA: /* Writes clear the aligned block of memory which rt points into. */ - tcg_rt = clean_data_tbi(s, cpu_reg(s, rt)); + if (s->mte_active[0]) { + TCGv_i32 t_desc; + int desc = 0; + + desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); + desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); + desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); + t_desc = tcg_const_i32(desc); + + tcg_rt = new_tmp_a64(s); + gen_helper_mte_check_zva(tcg_rt, cpu_env, t_desc, cpu_reg(s, rt)); + tcg_temp_free_i32(t_desc); + } else { + tcg_rt = clean_data_tbi(s, cpu_reg(s, rt)); + } gen_helper_dc_zva(cpu_env, tcg_rt); return; default: From b2aa8879b884cd66acde4123899dd92a38fe6527 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:26 -0700 Subject: [PATCH 1675/2595] target/arm: Use mte_checkN for sve unpredicated loads Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-29-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 61 +++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index ac7b3119e5..11e0dfc210 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4342,71 +4342,76 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm) int len_remain = len % 8; int nparts = len / 8 + ctpop8(len_remain); int midx = get_mem_index(s); - TCGv_i64 addr, t0, t1; + TCGv_i64 dirty_addr, clean_addr, t0, t1; - addr = tcg_temp_new_i64(); - t0 = tcg_temp_new_i64(); + dirty_addr = tcg_temp_new_i64(); + tcg_gen_addi_i64(dirty_addr, cpu_reg_sp(s, rn), imm); + clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len, MO_8); + tcg_temp_free_i64(dirty_addr); - /* Note that unpredicated load/store of vector/predicate registers + /* + * Note that unpredicated load/store of vector/predicate registers * are defined as a stream of bytes, which equates to little-endian - * operations on larger quantities. There is no nice way to force - * a little-endian load for aarch64_be-linux-user out of line. - * + * operations on larger quantities. * Attempt to keep code expansion to a minimum by limiting the * amount of unrolling done. */ if (nparts <= 4) { int i; + t0 = tcg_temp_new_i64(); for (i = 0; i < len_align; i += 8) { - tcg_gen_addi_i64(addr, cpu_reg_sp(s, rn), imm + i); - tcg_gen_qemu_ld_i64(t0, addr, midx, MO_LEQ); + tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEQ); tcg_gen_st_i64(t0, cpu_env, vofs + i); + tcg_gen_addi_i64(clean_addr, cpu_reg_sp(s, rn), 8); } + tcg_temp_free_i64(t0); } else { TCGLabel *loop = gen_new_label(); TCGv_ptr tp, i = tcg_const_local_ptr(0); + /* Copy the clean address into a local temp, live across the loop. */ + t0 = clean_addr; + clean_addr = tcg_temp_local_new_i64(); + tcg_gen_mov_i64(clean_addr, t0); + tcg_temp_free_i64(t0); + gen_set_label(loop); - /* Minimize the number of local temps that must be re-read from - * the stack each iteration. Instead, re-compute values other - * than the loop counter. - */ + t0 = tcg_temp_new_i64(); + tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEQ); + tcg_gen_addi_i64(clean_addr, clean_addr, 8); + tp = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(tp, i, imm); - tcg_gen_extu_ptr_i64(addr, tp); - tcg_gen_add_i64(addr, addr, cpu_reg_sp(s, rn)); - - tcg_gen_qemu_ld_i64(t0, addr, midx, MO_LEQ); - tcg_gen_add_ptr(tp, cpu_env, i); tcg_gen_addi_ptr(i, i, 8); tcg_gen_st_i64(t0, tp, vofs); tcg_temp_free_ptr(tp); + tcg_temp_free_i64(t0); tcg_gen_brcondi_ptr(TCG_COND_LTU, i, len_align, loop); tcg_temp_free_ptr(i); } - /* Predicate register loads can be any multiple of 2. + /* + * Predicate register loads can be any multiple of 2. * Note that we still store the entire 64-bit unit into cpu_env. */ if (len_remain) { - tcg_gen_addi_i64(addr, cpu_reg_sp(s, rn), imm + len_align); - + t0 = tcg_temp_new_i64(); switch (len_remain) { case 2: case 4: case 8: - tcg_gen_qemu_ld_i64(t0, addr, midx, MO_LE | ctz32(len_remain)); + tcg_gen_qemu_ld_i64(t0, clean_addr, midx, + MO_LE | ctz32(len_remain)); break; case 6: t1 = tcg_temp_new_i64(); - tcg_gen_qemu_ld_i64(t0, addr, midx, MO_LEUL); - tcg_gen_addi_i64(addr, addr, 4); - tcg_gen_qemu_ld_i64(t1, addr, midx, MO_LEUW); + tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUL); + tcg_gen_addi_i64(clean_addr, clean_addr, 4); + tcg_gen_qemu_ld_i64(t1, clean_addr, midx, MO_LEUW); tcg_gen_deposit_i64(t0, t0, t1, 32, 32); tcg_temp_free_i64(t1); break; @@ -4415,9 +4420,9 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm) g_assert_not_reached(); } tcg_gen_st_i64(t0, cpu_env, vofs + len_align); + tcg_temp_free_i64(t0); } - tcg_temp_free_i64(addr); - tcg_temp_free_i64(t0); + tcg_temp_free_i64(clean_addr); } /* Similarly for stores. */ From bba87d0a0f480805223a6428a7942a51733c488a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:27 -0700 Subject: [PATCH 1676/2595] target/arm: Use mte_checkN for sve unpredicated stores Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-30-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 61 +++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 11e0dfc210..4a613ca689 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4432,10 +4432,12 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) int len_remain = len % 8; int nparts = len / 8 + ctpop8(len_remain); int midx = get_mem_index(s); - TCGv_i64 addr, t0; + TCGv_i64 dirty_addr, clean_addr, t0; - addr = tcg_temp_new_i64(); - t0 = tcg_temp_new_i64(); + dirty_addr = tcg_temp_new_i64(); + tcg_gen_addi_i64(dirty_addr, cpu_reg_sp(s, rn), imm); + clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len, MO_8); + tcg_temp_free_i64(dirty_addr); /* Note that unpredicated load/store of vector/predicate registers * are defined as a stream of bytes, which equates to little-endian @@ -4448,33 +4450,35 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) if (nparts <= 4) { int i; + t0 = tcg_temp_new_i64(); for (i = 0; i < len_align; i += 8) { tcg_gen_ld_i64(t0, cpu_env, vofs + i); - tcg_gen_addi_i64(addr, cpu_reg_sp(s, rn), imm + i); - tcg_gen_qemu_st_i64(t0, addr, midx, MO_LEQ); + tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEQ); + tcg_gen_addi_i64(clean_addr, cpu_reg_sp(s, rn), 8); } + tcg_temp_free_i64(t0); } else { TCGLabel *loop = gen_new_label(); - TCGv_ptr t2, i = tcg_const_local_ptr(0); + TCGv_ptr tp, i = tcg_const_local_ptr(0); + + /* Copy the clean address into a local temp, live across the loop. */ + t0 = clean_addr; + clean_addr = tcg_temp_local_new_i64(); + tcg_gen_mov_i64(clean_addr, t0); + tcg_temp_free_i64(t0); gen_set_label(loop); - t2 = tcg_temp_new_ptr(); - tcg_gen_add_ptr(t2, cpu_env, i); - tcg_gen_ld_i64(t0, t2, vofs); - - /* Minimize the number of local temps that must be re-read from - * the stack each iteration. Instead, re-compute values other - * than the loop counter. - */ - tcg_gen_addi_ptr(t2, i, imm); - tcg_gen_extu_ptr_i64(addr, t2); - tcg_gen_add_i64(addr, addr, cpu_reg_sp(s, rn)); - tcg_temp_free_ptr(t2); - - tcg_gen_qemu_st_i64(t0, addr, midx, MO_LEQ); - + t0 = tcg_temp_new_i64(); + tp = tcg_temp_new_ptr(); + tcg_gen_add_ptr(tp, cpu_env, i); + tcg_gen_ld_i64(t0, tp, vofs); tcg_gen_addi_ptr(i, i, 8); + tcg_temp_free_ptr(tp); + + tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEQ); + tcg_gen_addi_i64(clean_addr, clean_addr, 8); + tcg_temp_free_i64(t0); tcg_gen_brcondi_ptr(TCG_COND_LTU, i, len_align, loop); tcg_temp_free_ptr(i); @@ -4482,29 +4486,30 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) /* Predicate register stores can be any multiple of 2. */ if (len_remain) { + t0 = tcg_temp_new_i64(); tcg_gen_ld_i64(t0, cpu_env, vofs + len_align); - tcg_gen_addi_i64(addr, cpu_reg_sp(s, rn), imm + len_align); switch (len_remain) { case 2: case 4: case 8: - tcg_gen_qemu_st_i64(t0, addr, midx, MO_LE | ctz32(len_remain)); + tcg_gen_qemu_st_i64(t0, clean_addr, midx, + MO_LE | ctz32(len_remain)); break; case 6: - tcg_gen_qemu_st_i64(t0, addr, midx, MO_LEUL); - tcg_gen_addi_i64(addr, addr, 4); + tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUL); + tcg_gen_addi_i64(clean_addr, clean_addr, 4); tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_qemu_st_i64(t0, addr, midx, MO_LEUW); + tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUW); break; default: g_assert_not_reached(); } + tcg_temp_free_i64(t0); } - tcg_temp_free_i64(addr); - tcg_temp_free_i64(t0); + tcg_temp_free_i64(clean_addr); } static bool trans_LDR_zri(DisasContext *s, arg_rri *a) From 4ac430e1f1eb1d27913a9f800a5965b281ac1b76 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:28 -0700 Subject: [PATCH 1677/2595] target/arm: Use mte_check1 for sve LD1R Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-31-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 4a613ca689..4fa521989d 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4892,7 +4892,7 @@ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a) unsigned esz = dtype_esz[a->dtype]; unsigned msz = dtype_msz(a->dtype); TCGLabel *over = gen_new_label(); - TCGv_i64 temp; + TCGv_i64 temp, clean_addr; /* If the guarding predicate has no bits set, no load occurs. */ if (psz <= 8) { @@ -4915,7 +4915,9 @@ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a) /* Load the data. */ temp = tcg_temp_new_i64(); tcg_gen_addi_i64(temp, cpu_reg_sp(s, a->rn), a->imm << msz); - tcg_gen_qemu_ld_i64(temp, temp, get_mem_index(s), + clean_addr = gen_mte_check1(s, temp, false, true, msz); + + tcg_gen_qemu_ld_i64(temp, clean_addr, get_mem_index(s), s->be_data | dtype_mop[a->dtype]); /* Broadcast to *all* elements. */ From c0ed9166b1aea86a2fbaada1195aacd1049f9e85 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:29 -0700 Subject: [PATCH 1678/2595] target/arm: Tidy trans_LD1R_zpri Move the variable declarations to the top of the function, but do not create a new label before sve_access_check. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-32-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 4fa521989d..a3a0b98fbc 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4883,17 +4883,19 @@ static bool trans_LD1RQ_zpri(DisasContext *s, arg_rpri_load *a) /* Load and broadcast element. */ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a) { - if (!sve_access_check(s)) { - return true; - } - unsigned vsz = vec_full_reg_size(s); unsigned psz = pred_full_reg_size(s); unsigned esz = dtype_esz[a->dtype]; unsigned msz = dtype_msz(a->dtype); - TCGLabel *over = gen_new_label(); + TCGLabel *over; TCGv_i64 temp, clean_addr; + if (!sve_access_check(s)) { + return true; + } + + over = gen_new_label(); + /* If the guarding predicate has no bits set, no load occurs. */ if (psz <= 8) { /* Reduce the pred_esz_masks value simply to reduce the From 149d3b31f3f0f7f9e1c3a77043450a95c7a7e93d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:30 -0700 Subject: [PATCH 1679/2595] target/arm: Add arm_tlb_bti_gp Introduce an lvalue macro to wrap target_tlb_bit0. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-33-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 13 +++++++++++++ target/arm/helper.c | 2 +- target/arm/translate-a64.c | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index cb4f6ba69f..c54f0ab18a 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3393,6 +3393,19 @@ static inline uint64_t *aa64_vfp_qreg(CPUARMState *env, unsigned regno) /* Shared between translate-sve.c and sve_helper.c. */ extern const uint64_t pred_esz_masks[4]; +/* Helper for the macros below, validating the argument type. */ +static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x) +{ + return x; +} + +/* + * Lvalue macros for ARM TLB bits that we must cache in the TCG TLB. + * Using these should be a bit more self-documenting than using the + * generic target bits directly. + */ +#define arm_tlb_bti_gp(x) (typecheck_memtxattrs(x)->target_tlb_bit0) + /* * Naming convention for isar_feature functions: * Functions which test 32-bit ID registers should have _aa32_ in diff --git a/target/arm/helper.c b/target/arm/helper.c index 33f902387b..44a3f9fb48 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11079,7 +11079,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, } /* When in aarch64 mode, and BTI is enabled, remember GP in the IOTLB. */ if (aarch64 && guarded && cpu_isar_feature(aa64_bti, cpu)) { - txattrs->target_tlb_bit0 = true; + arm_tlb_bti_gp(txattrs) = true; } if (cacheattrs != NULL) { diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index a2a8280010..7a3774bfda 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14434,7 +14434,7 @@ static bool is_guarded_page(CPUARMState *env, DisasContext *s) * table entry even for that case. */ return (tlb_hit(entry->addr_code, addr) && - env_tlb(env)->d[mmu_idx].iotlb[index].attrs.target_tlb_bit0); + arm_tlb_bti_gp(&env_tlb(env)->d[mmu_idx].iotlb[index].attrs)); #endif } From 206adacfb8d35e671e3619591608c475aa046b63 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:31 -0700 Subject: [PATCH 1680/2595] target/arm: Add mte helpers for sve scalar + int loads Because the elements are sequential, we can eliminate many tests all at once when the tag hits TCMA, or if the page(s) are not Tagged. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-34-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 1 + target/arm/helper-sve.h | 58 ++++++++++ target/arm/internals.h | 6 + target/arm/sve_helper.c | 218 ++++++++++++++++++++++++++++++------- target/arm/translate-sve.c | 186 ++++++++++++++++++++++--------- 5 files changed, 378 insertions(+), 91 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index c54f0ab18a..3bf0518ca4 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3405,6 +3405,7 @@ static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x) * generic target bits directly. */ #define arm_tlb_bti_gp(x) (typecheck_memtxattrs(x)->target_tlb_bit0) +#define arm_tlb_mte_tagged(x) (typecheck_memtxattrs(x)->target_tlb_bit1) /* * Naming convention for isar_feature functions: diff --git a/target/arm/helper-sve.h b/target/arm/helper-sve.h index 7a200755ac..1bc1974fc2 100644 --- a/target/arm/helper-sve.h +++ b/target/arm/helper-sve.h @@ -1196,6 +1196,64 @@ DEF_HELPER_FLAGS_4(sve_ld1sds_le_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_ld1sdu_be_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_ld1sds_be_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1bb_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld2bb_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld3bb_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld4bb_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ld1hh_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld2hh_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld3hh_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld4hh_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ld1hh_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld2hh_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld3hh_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld4hh_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ld1ss_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld2ss_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld3ss_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld4ss_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ld1ss_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld2ss_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld3ss_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld4ss_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ld1dd_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld2dd_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld3dd_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld4dd_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ld1dd_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld2dd_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld3dd_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld4dd_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ld1bhu_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1bsu_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1bdu_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1bhs_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1bss_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1bds_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ld1hsu_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1hdu_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1hss_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1hds_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ld1hsu_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1hdu_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1hss_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1hds_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ld1sdu_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1sds_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ld1sdu_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ld1sds_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + DEF_HELPER_FLAGS_4(sve_ldff1bb_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_ldff1bhu_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_ldff1bsu_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) diff --git a/target/arm/internals.h b/target/arm/internals.h index c763a23dfb..3306c4f829 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1310,6 +1310,12 @@ void arm_log_exception(int idx); #define LOG2_TAG_GRANULE 4 #define TAG_GRANULE (1 << LOG2_TAG_GRANULE) +/* + * The SVE simd_data field, for memory ops, contains either + * rd (5 bits) or a shift count (2 bits). + */ +#define SVE_MTEDESC_SHIFT 5 + /* Bits within a descriptor passed to the helper_mte_check* functions. */ FIELD(MTEDESC, MIDX, 0, 4) FIELD(MTEDESC, TBI, 4, 2) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index e590db6637..767ecb399f 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -4393,15 +4393,89 @@ static void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, #endif } +typedef uint64_t mte_check_fn(CPUARMState *, uint32_t, uint64_t, uintptr_t); + +static inline QEMU_ALWAYS_INLINE +void sve_cont_ldst_mte_check_int(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, int esize, + int msize, uint32_t mtedesc, uintptr_t ra, + mte_check_fn *check) +{ + intptr_t mem_off, reg_off, reg_last; + + /* Process the page only if MemAttr == Tagged. */ + if (arm_tlb_mte_tagged(&info->page[0].attrs)) { + mem_off = info->mem_off_first[0]; + reg_off = info->reg_off_first[0]; + reg_last = info->reg_off_split; + if (reg_last < 0) { + reg_last = info->reg_off_last[0]; + } + + do { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + check(env, mtedesc, addr, ra); + } + reg_off += esize; + mem_off += msize; + } while (reg_off <= reg_last && (reg_off & 63)); + } while (reg_off <= reg_last); + } + + mem_off = info->mem_off_first[1]; + if (mem_off >= 0 && arm_tlb_mte_tagged(&info->page[1].attrs)) { + reg_off = info->reg_off_first[1]; + reg_last = info->reg_off_last[1]; + + do { + uint64_t pg = vg[reg_off >> 6]; + do { + if ((pg >> (reg_off & 63)) & 1) { + check(env, mtedesc, addr, ra); + } + reg_off += esize; + mem_off += msize; + } while (reg_off & 63); + } while (reg_off <= reg_last); + } +} + +typedef void sve_cont_ldst_mte_check_fn(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, + int esize, int msize, uint32_t mtedesc, + uintptr_t ra); + +static void sve_cont_ldst_mte_check1(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, + int esize, int msize, uint32_t mtedesc, + uintptr_t ra) +{ + sve_cont_ldst_mte_check_int(info, env, vg, addr, esize, msize, + mtedesc, ra, mte_check1); +} + +static void sve_cont_ldst_mte_checkN(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, + int esize, int msize, uint32_t mtedesc, + uintptr_t ra) +{ + sve_cont_ldst_mte_check_int(info, env, vg, addr, esize, msize, + mtedesc, ra, mte_checkN); +} + + /* * Common helper for all contiguous 1,2,3,4-register predicated stores. */ static inline QEMU_ALWAYS_INLINE void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, uint32_t desc, const uintptr_t retaddr, - const int esz, const int msz, const int N, + const int esz, const int msz, const int N, uint32_t mtedesc, sve_ldst1_host_fn *host_fn, - sve_ldst1_tlb_fn *tlb_fn) + sve_ldst1_tlb_fn *tlb_fn, + sve_cont_ldst_mte_check_fn *mte_check_fn) { const unsigned rd = simd_data(desc); const intptr_t reg_max = simd_oprsz(desc); @@ -4426,7 +4500,14 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, sve_cont_ldst_watchpoints(&info, env, vg, addr, 1 << esz, N << msz, BP_MEM_READ, retaddr); - /* TODO: MTE check. */ + /* + * Handle mte checks for all active elements. + * Since TBI must be set for MTE, !mtedesc => !mte_active. + */ + if (mte_check_fn && mtedesc) { + mte_check_fn(&info, env, vg, addr, 1 << esz, N << msz, + mtedesc, retaddr); + } flags = info.page[0].flags | info.page[1].flags; if (unlikely(flags != 0)) { @@ -4532,26 +4613,67 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, } } -#define DO_LD1_1(NAME, ESZ) \ -void HELPER(sve_##NAME##_r)(CPUARMState *env, void *vg, \ - target_ulong addr, uint32_t desc) \ -{ \ - sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, 1, \ - sve_##NAME##_host, sve_##NAME##_tlb); \ +static inline QEMU_ALWAYS_INLINE +void sve_ldN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr, + uint32_t desc, const uintptr_t ra, + const int esz, const int msz, const int N, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) +{ + uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + int bit55 = extract64(addr, 55, 1); + + /* Remove mtedesc from the normal sve descriptor. */ + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* Perform gross MTE suppression early. */ + if (!tbi_check(desc, bit55) || + tcma_check(desc, bit55, allocation_tag_from_addr(addr))) { + mtedesc = 0; + } + + sve_ldN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn, + N == 1 ? sve_cont_ldst_mte_check1 : sve_cont_ldst_mte_checkN); } -#define DO_LD1_2(NAME, ESZ, MSZ) \ -void HELPER(sve_##NAME##_le_r)(CPUARMState *env, void *vg, \ - target_ulong addr, uint32_t desc) \ -{ \ - sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \ - sve_##NAME##_le_host, sve_##NAME##_le_tlb); \ -} \ -void HELPER(sve_##NAME##_be_r)(CPUARMState *env, void *vg, \ - target_ulong addr, uint32_t desc) \ -{ \ - sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \ - sve_##NAME##_be_host, sve_##NAME##_be_tlb); \ +#define DO_LD1_1(NAME, ESZ) \ +void HELPER(sve_##NAME##_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, 1, 0, \ + sve_##NAME##_host, sve_##NAME##_tlb, NULL); \ +} \ +void HELPER(sve_##NAME##_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MO_8, 1, \ + sve_##NAME##_host, sve_##NAME##_tlb); \ +} + +#define DO_LD1_2(NAME, ESZ, MSZ) \ +void HELPER(sve_##NAME##_le_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, 0, \ + sve_##NAME##_le_host, sve_##NAME##_le_tlb, NULL); \ +} \ +void HELPER(sve_##NAME##_be_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, 0, \ + sve_##NAME##_be_host, sve_##NAME##_be_tlb, NULL); \ +} \ +void HELPER(sve_##NAME##_le_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \ + sve_##NAME##_le_host, sve_##NAME##_le_tlb); \ +} \ +void HELPER(sve_##NAME##_be_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \ + sve_##NAME##_be_host, sve_##NAME##_be_tlb); \ } DO_LD1_1(ld1bb, MO_8) @@ -4577,26 +4699,44 @@ DO_LD1_2(ld1dd, MO_64, MO_64) #undef DO_LD1_1 #undef DO_LD1_2 -#define DO_LDN_1(N) \ -void HELPER(sve_ld##N##bb_r)(CPUARMState *env, void *vg, \ - target_ulong addr, uint32_t desc) \ -{ \ - sve_ldN_r(env, vg, addr, desc, GETPC(), MO_8, MO_8, N, \ - sve_ld1bb_host, sve_ld1bb_tlb); \ +#define DO_LDN_1(N) \ +void HELPER(sve_ld##N##bb_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r(env, vg, addr, desc, GETPC(), MO_8, MO_8, N, 0, \ + sve_ld1bb_host, sve_ld1bb_tlb, NULL); \ +} \ +void HELPER(sve_ld##N##bb_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r_mte(env, vg, addr, desc, GETPC(), MO_8, MO_8, N, \ + sve_ld1bb_host, sve_ld1bb_tlb); \ } -#define DO_LDN_2(N, SUFF, ESZ) \ -void HELPER(sve_ld##N##SUFF##_le_r)(CPUARMState *env, void *vg, \ - target_ulong addr, uint32_t desc) \ -{ \ - sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, \ - sve_ld1##SUFF##_le_host, sve_ld1##SUFF##_le_tlb); \ -} \ -void HELPER(sve_ld##N##SUFF##_be_r)(CPUARMState *env, void *vg, \ - target_ulong addr, uint32_t desc) \ -{ \ - sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, \ - sve_ld1##SUFF##_be_host, sve_ld1##SUFF##_be_tlb); \ +#define DO_LDN_2(N, SUFF, ESZ) \ +void HELPER(sve_ld##N##SUFF##_le_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, 0, \ + sve_ld1##SUFF##_le_host, sve_ld1##SUFF##_le_tlb, NULL); \ +} \ +void HELPER(sve_ld##N##SUFF##_be_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, 0, \ + sve_ld1##SUFF##_be_host, sve_ld1##SUFF##_be_tlb, NULL); \ +} \ +void HELPER(sve_ld##N##SUFF##_le_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, \ + sve_ld1##SUFF##_le_host, sve_ld1##SUFF##_le_tlb); \ +} \ +void HELPER(sve_ld##N##SUFF##_be_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, \ + sve_ld1##SUFF##_be_host, sve_ld1##SUFF##_be_tlb); \ } DO_LDN_1(2) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index a3a0b98fbc..2620c965f0 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4575,18 +4575,32 @@ static const uint8_t dtype_esz[16] = { }; static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, - int dtype, gen_helper_gvec_mem *fn) + int dtype, uint32_t mte_n, bool is_write, + gen_helper_gvec_mem *fn) { unsigned vsz = vec_full_reg_size(s); TCGv_ptr t_pg; TCGv_i32 t_desc; - int desc; + int desc = 0; - /* For e.g. LD4, there are not enough arguments to pass all 4 + /* + * For e.g. LD4, there are not enough arguments to pass all 4 * registers as pointers, so encode the regno into the data field. * For consistency, do this even for LD1. + * TODO: mte_n check here while callers are updated. */ - desc = simd_desc(vsz, vsz, zt); + if (mte_n && s->mte_active[0]) { + int msz = dtype_msz(dtype); + + desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); + desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); + desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); + desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); + desc = FIELD_DP32(desc, MTEDESC, ESIZE, 1 << msz); + desc = FIELD_DP32(desc, MTEDESC, TSIZE, mte_n << msz); + desc <<= SVE_MTEDESC_SHIFT; + } + desc = simd_desc(vsz, vsz, zt | desc); t_desc = tcg_const_i32(desc); t_pg = tcg_temp_new_ptr(); @@ -4600,64 +4614,132 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, static void do_ld_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype, int nreg) { - static gen_helper_gvec_mem * const fns[2][16][4] = { - /* Little-endian */ - { { gen_helper_sve_ld1bb_r, gen_helper_sve_ld2bb_r, + static gen_helper_gvec_mem * const fns[2][2][16][4] = { + { /* mte inactive, little-endian */ + { { gen_helper_sve_ld1bb_r, gen_helper_sve_ld2bb_r, gen_helper_sve_ld3bb_r, gen_helper_sve_ld4bb_r }, - { gen_helper_sve_ld1bhu_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1bsu_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1bdu_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1bhu_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1bsu_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1bdu_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1sds_le_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1hh_le_r, gen_helper_sve_ld2hh_le_r, - gen_helper_sve_ld3hh_le_r, gen_helper_sve_ld4hh_le_r }, - { gen_helper_sve_ld1hsu_le_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1hdu_le_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1sds_le_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1hh_le_r, gen_helper_sve_ld2hh_le_r, + gen_helper_sve_ld3hh_le_r, gen_helper_sve_ld4hh_le_r }, + { gen_helper_sve_ld1hsu_le_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1hdu_le_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1hds_le_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1hss_le_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1ss_le_r, gen_helper_sve_ld2ss_le_r, - gen_helper_sve_ld3ss_le_r, gen_helper_sve_ld4ss_le_r }, - { gen_helper_sve_ld1sdu_le_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1hds_le_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1hss_le_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1ss_le_r, gen_helper_sve_ld2ss_le_r, + gen_helper_sve_ld3ss_le_r, gen_helper_sve_ld4ss_le_r }, + { gen_helper_sve_ld1sdu_le_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1bds_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1bss_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1bhs_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1dd_le_r, gen_helper_sve_ld2dd_le_r, - gen_helper_sve_ld3dd_le_r, gen_helper_sve_ld4dd_le_r } }, + { gen_helper_sve_ld1bds_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1bss_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1bhs_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1dd_le_r, gen_helper_sve_ld2dd_le_r, + gen_helper_sve_ld3dd_le_r, gen_helper_sve_ld4dd_le_r } }, - /* Big-endian */ - { { gen_helper_sve_ld1bb_r, gen_helper_sve_ld2bb_r, - gen_helper_sve_ld3bb_r, gen_helper_sve_ld4bb_r }, - { gen_helper_sve_ld1bhu_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1bsu_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1bdu_r, NULL, NULL, NULL }, + /* mte inactive, big-endian */ + { { gen_helper_sve_ld1bb_r, gen_helper_sve_ld2bb_r, + gen_helper_sve_ld3bb_r, gen_helper_sve_ld4bb_r }, + { gen_helper_sve_ld1bhu_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1bsu_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1bdu_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1sds_be_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1hh_be_r, gen_helper_sve_ld2hh_be_r, - gen_helper_sve_ld3hh_be_r, gen_helper_sve_ld4hh_be_r }, - { gen_helper_sve_ld1hsu_be_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1hdu_be_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1sds_be_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1hh_be_r, gen_helper_sve_ld2hh_be_r, + gen_helper_sve_ld3hh_be_r, gen_helper_sve_ld4hh_be_r }, + { gen_helper_sve_ld1hsu_be_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1hdu_be_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1hds_be_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1hss_be_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1ss_be_r, gen_helper_sve_ld2ss_be_r, - gen_helper_sve_ld3ss_be_r, gen_helper_sve_ld4ss_be_r }, - { gen_helper_sve_ld1sdu_be_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1hds_be_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1hss_be_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1ss_be_r, gen_helper_sve_ld2ss_be_r, + gen_helper_sve_ld3ss_be_r, gen_helper_sve_ld4ss_be_r }, + { gen_helper_sve_ld1sdu_be_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1bds_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1bss_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1bhs_r, NULL, NULL, NULL }, - { gen_helper_sve_ld1dd_be_r, gen_helper_sve_ld2dd_be_r, - gen_helper_sve_ld3dd_be_r, gen_helper_sve_ld4dd_be_r } } + { gen_helper_sve_ld1bds_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1bss_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1bhs_r, NULL, NULL, NULL }, + { gen_helper_sve_ld1dd_be_r, gen_helper_sve_ld2dd_be_r, + gen_helper_sve_ld3dd_be_r, gen_helper_sve_ld4dd_be_r } } }, + + { /* mte active, little-endian */ + { { gen_helper_sve_ld1bb_r_mte, + gen_helper_sve_ld2bb_r_mte, + gen_helper_sve_ld3bb_r_mte, + gen_helper_sve_ld4bb_r_mte }, + { gen_helper_sve_ld1bhu_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1bsu_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1bdu_r_mte, NULL, NULL, NULL }, + + { gen_helper_sve_ld1sds_le_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1hh_le_r_mte, + gen_helper_sve_ld2hh_le_r_mte, + gen_helper_sve_ld3hh_le_r_mte, + gen_helper_sve_ld4hh_le_r_mte }, + { gen_helper_sve_ld1hsu_le_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1hdu_le_r_mte, NULL, NULL, NULL }, + + { gen_helper_sve_ld1hds_le_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1hss_le_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1ss_le_r_mte, + gen_helper_sve_ld2ss_le_r_mte, + gen_helper_sve_ld3ss_le_r_mte, + gen_helper_sve_ld4ss_le_r_mte }, + { gen_helper_sve_ld1sdu_le_r_mte, NULL, NULL, NULL }, + + { gen_helper_sve_ld1bds_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1bss_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1bhs_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1dd_le_r_mte, + gen_helper_sve_ld2dd_le_r_mte, + gen_helper_sve_ld3dd_le_r_mte, + gen_helper_sve_ld4dd_le_r_mte } }, + + /* mte active, big-endian */ + { { gen_helper_sve_ld1bb_r_mte, + gen_helper_sve_ld2bb_r_mte, + gen_helper_sve_ld3bb_r_mte, + gen_helper_sve_ld4bb_r_mte }, + { gen_helper_sve_ld1bhu_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1bsu_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1bdu_r_mte, NULL, NULL, NULL }, + + { gen_helper_sve_ld1sds_be_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1hh_be_r_mte, + gen_helper_sve_ld2hh_be_r_mte, + gen_helper_sve_ld3hh_be_r_mte, + gen_helper_sve_ld4hh_be_r_mte }, + { gen_helper_sve_ld1hsu_be_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1hdu_be_r_mte, NULL, NULL, NULL }, + + { gen_helper_sve_ld1hds_be_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1hss_be_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1ss_be_r_mte, + gen_helper_sve_ld2ss_be_r_mte, + gen_helper_sve_ld3ss_be_r_mte, + gen_helper_sve_ld4ss_be_r_mte }, + { gen_helper_sve_ld1sdu_be_r_mte, NULL, NULL, NULL }, + + { gen_helper_sve_ld1bds_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1bss_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1bhs_r_mte, NULL, NULL, NULL }, + { gen_helper_sve_ld1dd_be_r_mte, + gen_helper_sve_ld2dd_be_r_mte, + gen_helper_sve_ld3dd_be_r_mte, + gen_helper_sve_ld4dd_be_r_mte } } }, }; - gen_helper_gvec_mem *fn = fns[s->be_data == MO_BE][dtype][nreg]; + gen_helper_gvec_mem *fn + = fns[s->mte_active[0]][s->be_data == MO_BE][dtype][nreg]; - /* While there are holes in the table, they are not + /* + * While there are holes in the table, they are not * accessible via the instruction encoding. */ assert(fn != NULL); - do_mem_zpa(s, zt, pg, addr, dtype, fn); + do_mem_zpa(s, zt, pg, addr, dtype, nreg, false, fn); } static bool trans_LD_zprr(DisasContext *s, arg_rprr_load *a) @@ -4739,7 +4821,7 @@ static bool trans_LDFF1_zprr(DisasContext *s, arg_rprr_load *a) TCGv_i64 addr = new_tmp_a64(s); tcg_gen_shli_i64(addr, cpu_reg(s, a->rm), dtype_msz(a->dtype)); tcg_gen_add_i64(addr, addr, cpu_reg_sp(s, a->rn)); - do_mem_zpa(s, a->rd, a->pg, addr, a->dtype, + do_mem_zpa(s, a->rd, a->pg, addr, a->dtype, 0, false, fns[s->be_data == MO_BE][a->dtype]); } return true; @@ -4798,7 +4880,7 @@ static bool trans_LDNF1_zpri(DisasContext *s, arg_rpri_load *a) TCGv_i64 addr = new_tmp_a64(s); tcg_gen_addi_i64(addr, cpu_reg_sp(s, a->rn), off); - do_mem_zpa(s, a->rd, a->pg, addr, a->dtype, + do_mem_zpa(s, a->rd, a->pg, addr, a->dtype, 0, false, fns[s->be_data == MO_BE][a->dtype]); } return true; @@ -5002,7 +5084,7 @@ static void do_st_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, fn = fn_multiple[be][nreg - 1][msz]; } assert(fn != NULL); - do_mem_zpa(s, zt, pg, addr, msz_dtype(s, msz), fn); + do_mem_zpa(s, zt, pg, addr, msz_dtype(s, msz), 0, true, fn); } static bool trans_ST_zprr(DisasContext *s, arg_rprr_store *a) From 71b9f3948c75bb97641a3c8c7de96d1cb47cdc07 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:32 -0700 Subject: [PATCH 1681/2595] target/arm: Add mte helpers for sve scalar + int stores Because the elements are sequential, we can eliminate many tests all at once when the tag hits TCMA, or if the page(s) are not Tagged. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-35-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-sve.h | 47 +++++++++++ target/arm/sve_helper.c | 95 ++++++++++++++++------ target/arm/translate-sve.c | 162 ++++++++++++++++++++++++------------- 3 files changed, 226 insertions(+), 78 deletions(-) diff --git a/target/arm/helper-sve.h b/target/arm/helper-sve.h index 1bc1974fc2..1425f33c92 100644 --- a/target/arm/helper-sve.h +++ b/target/arm/helper-sve.h @@ -1363,6 +1363,53 @@ DEF_HELPER_FLAGS_4(sve_st1hd_be_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_st1sd_le_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_st1sd_be_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st1bb_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st2bb_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st3bb_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st4bb_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_st1hh_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st2hh_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st3hh_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st4hh_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_st1hh_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st2hh_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st3hh_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st4hh_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_st1ss_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st2ss_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st3ss_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st4ss_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_st1ss_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st2ss_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st3ss_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st4ss_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_st1dd_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st2dd_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st3dd_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st4dd_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_st1dd_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st2dd_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st3dd_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st4dd_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_st1bh_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st1bs_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st1bd_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_st1hs_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st1hd_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st1hs_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st1hd_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_st1sd_le_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_st1sd_be_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + DEF_HELPER_FLAGS_6(sve_ldbsu_zsu, TCG_CALL_NO_WG, void, env, ptr, ptr, ptr, tl, i32) DEF_HELPER_FLAGS_6(sve_ldhsu_le_zsu, TCG_CALL_NO_WG, diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 767ecb399f..ded9cedd18 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -5022,11 +5022,12 @@ DO_LDFF1_LDNF1_2(dd, MO_64, MO_64) */ static inline QEMU_ALWAYS_INLINE -void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, uint32_t desc, - const uintptr_t retaddr, const int esz, - const int msz, const int N, +void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, + uint32_t desc, const uintptr_t retaddr, + const int esz, const int msz, const int N, uint32_t mtedesc, sve_ldst1_host_fn *host_fn, - sve_ldst1_tlb_fn *tlb_fn) + sve_ldst1_tlb_fn *tlb_fn, + sve_cont_ldst_mte_check_fn *mte_check_fn) { const unsigned rd = simd_data(desc); const intptr_t reg_max = simd_oprsz(desc); @@ -5048,7 +5049,14 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, uint32_t desc, sve_cont_ldst_watchpoints(&info, env, vg, addr, 1 << esz, N << msz, BP_MEM_WRITE, retaddr); - /* TODO: MTE check. */ + /* + * Handle mte checks for all active elements. + * Since TBI must be set for MTE, !mtedesc => !mte_active. + */ + if (mte_check_fn && mtedesc) { + mte_check_fn(&info, env, vg, addr, 1 << esz, N << msz, + mtedesc, retaddr); + } flags = info.page[0].flags | info.page[1].flags; if (unlikely(flags != 0)) { @@ -5142,26 +5150,67 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, uint32_t desc, } } -#define DO_STN_1(N, NAME, ESZ) \ -void HELPER(sve_st##N##NAME##_r)(CPUARMState *env, void *vg, \ - target_ulong addr, uint32_t desc) \ -{ \ - sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, N, \ - sve_st1##NAME##_host, sve_st1##NAME##_tlb); \ +static inline QEMU_ALWAYS_INLINE +void sve_stN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr, + uint32_t desc, const uintptr_t ra, + const int esz, const int msz, const int N, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) +{ + uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + int bit55 = extract64(addr, 55, 1); + + /* Remove mtedesc from the normal sve descriptor. */ + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* Perform gross MTE suppression early. */ + if (!tbi_check(desc, bit55) || + tcma_check(desc, bit55, allocation_tag_from_addr(addr))) { + mtedesc = 0; + } + + sve_stN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn, + N == 1 ? sve_cont_ldst_mte_check1 : sve_cont_ldst_mte_checkN); } -#define DO_STN_2(N, NAME, ESZ, MSZ) \ -void HELPER(sve_st##N##NAME##_le_r)(CPUARMState *env, void *vg, \ - target_ulong addr, uint32_t desc) \ -{ \ - sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, \ - sve_st1##NAME##_le_host, sve_st1##NAME##_le_tlb); \ -} \ -void HELPER(sve_st##N##NAME##_be_r)(CPUARMState *env, void *vg, \ - target_ulong addr, uint32_t desc) \ -{ \ - sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, \ - sve_st1##NAME##_be_host, sve_st1##NAME##_be_tlb); \ +#define DO_STN_1(N, NAME, ESZ) \ +void HELPER(sve_st##N##NAME##_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, N, 0, \ + sve_st1##NAME##_host, sve_st1##NAME##_tlb, NULL); \ +} \ +void HELPER(sve_st##N##NAME##_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_stN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MO_8, N, \ + sve_st1##NAME##_host, sve_st1##NAME##_tlb); \ +} + +#define DO_STN_2(N, NAME, ESZ, MSZ) \ +void HELPER(sve_st##N##NAME##_le_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, 0, \ + sve_st1##NAME##_le_host, sve_st1##NAME##_le_tlb, NULL); \ +} \ +void HELPER(sve_st##N##NAME##_be_r)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, 0, \ + sve_st1##NAME##_be_host, sve_st1##NAME##_be_tlb, NULL); \ +} \ +void HELPER(sve_st##N##NAME##_le_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_stN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, \ + sve_st1##NAME##_le_host, sve_st1##NAME##_le_tlb); \ +} \ +void HELPER(sve_st##N##NAME##_be_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_stN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, \ + sve_st1##NAME##_be_host, sve_st1##NAME##_be_tlb); \ } DO_STN_1(1, bb, MO_8) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 2620c965f0..daac8589f3 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -5018,73 +5018,125 @@ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a) static void do_st_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, int msz, int esz, int nreg) { - static gen_helper_gvec_mem * const fn_single[2][4][4] = { - { { gen_helper_sve_st1bb_r, - gen_helper_sve_st1bh_r, - gen_helper_sve_st1bs_r, - gen_helper_sve_st1bd_r }, - { NULL, - gen_helper_sve_st1hh_le_r, - gen_helper_sve_st1hs_le_r, - gen_helper_sve_st1hd_le_r }, - { NULL, NULL, - gen_helper_sve_st1ss_le_r, - gen_helper_sve_st1sd_le_r }, - { NULL, NULL, NULL, - gen_helper_sve_st1dd_le_r } }, - { { gen_helper_sve_st1bb_r, - gen_helper_sve_st1bh_r, - gen_helper_sve_st1bs_r, - gen_helper_sve_st1bd_r }, - { NULL, - gen_helper_sve_st1hh_be_r, - gen_helper_sve_st1hs_be_r, - gen_helper_sve_st1hd_be_r }, - { NULL, NULL, - gen_helper_sve_st1ss_be_r, - gen_helper_sve_st1sd_be_r }, - { NULL, NULL, NULL, - gen_helper_sve_st1dd_be_r } }, + static gen_helper_gvec_mem * const fn_single[2][2][4][4] = { + { { { gen_helper_sve_st1bb_r, + gen_helper_sve_st1bh_r, + gen_helper_sve_st1bs_r, + gen_helper_sve_st1bd_r }, + { NULL, + gen_helper_sve_st1hh_le_r, + gen_helper_sve_st1hs_le_r, + gen_helper_sve_st1hd_le_r }, + { NULL, NULL, + gen_helper_sve_st1ss_le_r, + gen_helper_sve_st1sd_le_r }, + { NULL, NULL, NULL, + gen_helper_sve_st1dd_le_r } }, + { { gen_helper_sve_st1bb_r, + gen_helper_sve_st1bh_r, + gen_helper_sve_st1bs_r, + gen_helper_sve_st1bd_r }, + { NULL, + gen_helper_sve_st1hh_be_r, + gen_helper_sve_st1hs_be_r, + gen_helper_sve_st1hd_be_r }, + { NULL, NULL, + gen_helper_sve_st1ss_be_r, + gen_helper_sve_st1sd_be_r }, + { NULL, NULL, NULL, + gen_helper_sve_st1dd_be_r } } }, + + { { { gen_helper_sve_st1bb_r_mte, + gen_helper_sve_st1bh_r_mte, + gen_helper_sve_st1bs_r_mte, + gen_helper_sve_st1bd_r_mte }, + { NULL, + gen_helper_sve_st1hh_le_r_mte, + gen_helper_sve_st1hs_le_r_mte, + gen_helper_sve_st1hd_le_r_mte }, + { NULL, NULL, + gen_helper_sve_st1ss_le_r_mte, + gen_helper_sve_st1sd_le_r_mte }, + { NULL, NULL, NULL, + gen_helper_sve_st1dd_le_r_mte } }, + { { gen_helper_sve_st1bb_r_mte, + gen_helper_sve_st1bh_r_mte, + gen_helper_sve_st1bs_r_mte, + gen_helper_sve_st1bd_r_mte }, + { NULL, + gen_helper_sve_st1hh_be_r_mte, + gen_helper_sve_st1hs_be_r_mte, + gen_helper_sve_st1hd_be_r_mte }, + { NULL, NULL, + gen_helper_sve_st1ss_be_r_mte, + gen_helper_sve_st1sd_be_r_mte }, + { NULL, NULL, NULL, + gen_helper_sve_st1dd_be_r_mte } } }, }; - static gen_helper_gvec_mem * const fn_multiple[2][3][4] = { - { { gen_helper_sve_st2bb_r, - gen_helper_sve_st2hh_le_r, - gen_helper_sve_st2ss_le_r, - gen_helper_sve_st2dd_le_r }, - { gen_helper_sve_st3bb_r, - gen_helper_sve_st3hh_le_r, - gen_helper_sve_st3ss_le_r, - gen_helper_sve_st3dd_le_r }, - { gen_helper_sve_st4bb_r, - gen_helper_sve_st4hh_le_r, - gen_helper_sve_st4ss_le_r, - gen_helper_sve_st4dd_le_r } }, - { { gen_helper_sve_st2bb_r, - gen_helper_sve_st2hh_be_r, - gen_helper_sve_st2ss_be_r, - gen_helper_sve_st2dd_be_r }, - { gen_helper_sve_st3bb_r, - gen_helper_sve_st3hh_be_r, - gen_helper_sve_st3ss_be_r, - gen_helper_sve_st3dd_be_r }, - { gen_helper_sve_st4bb_r, - gen_helper_sve_st4hh_be_r, - gen_helper_sve_st4ss_be_r, - gen_helper_sve_st4dd_be_r } }, + static gen_helper_gvec_mem * const fn_multiple[2][2][3][4] = { + { { { gen_helper_sve_st2bb_r, + gen_helper_sve_st2hh_le_r, + gen_helper_sve_st2ss_le_r, + gen_helper_sve_st2dd_le_r }, + { gen_helper_sve_st3bb_r, + gen_helper_sve_st3hh_le_r, + gen_helper_sve_st3ss_le_r, + gen_helper_sve_st3dd_le_r }, + { gen_helper_sve_st4bb_r, + gen_helper_sve_st4hh_le_r, + gen_helper_sve_st4ss_le_r, + gen_helper_sve_st4dd_le_r } }, + { { gen_helper_sve_st2bb_r, + gen_helper_sve_st2hh_be_r, + gen_helper_sve_st2ss_be_r, + gen_helper_sve_st2dd_be_r }, + { gen_helper_sve_st3bb_r, + gen_helper_sve_st3hh_be_r, + gen_helper_sve_st3ss_be_r, + gen_helper_sve_st3dd_be_r }, + { gen_helper_sve_st4bb_r, + gen_helper_sve_st4hh_be_r, + gen_helper_sve_st4ss_be_r, + gen_helper_sve_st4dd_be_r } } }, + { { { gen_helper_sve_st2bb_r_mte, + gen_helper_sve_st2hh_le_r_mte, + gen_helper_sve_st2ss_le_r_mte, + gen_helper_sve_st2dd_le_r_mte }, + { gen_helper_sve_st3bb_r_mte, + gen_helper_sve_st3hh_le_r_mte, + gen_helper_sve_st3ss_le_r_mte, + gen_helper_sve_st3dd_le_r_mte }, + { gen_helper_sve_st4bb_r_mte, + gen_helper_sve_st4hh_le_r_mte, + gen_helper_sve_st4ss_le_r_mte, + gen_helper_sve_st4dd_le_r_mte } }, + { { gen_helper_sve_st2bb_r_mte, + gen_helper_sve_st2hh_be_r_mte, + gen_helper_sve_st2ss_be_r_mte, + gen_helper_sve_st2dd_be_r_mte }, + { gen_helper_sve_st3bb_r_mte, + gen_helper_sve_st3hh_be_r_mte, + gen_helper_sve_st3ss_be_r_mte, + gen_helper_sve_st3dd_be_r_mte }, + { gen_helper_sve_st4bb_r_mte, + gen_helper_sve_st4hh_be_r_mte, + gen_helper_sve_st4ss_be_r_mte, + gen_helper_sve_st4dd_be_r_mte } } }, }; gen_helper_gvec_mem *fn; int be = s->be_data == MO_BE; if (nreg == 0) { /* ST1 */ - fn = fn_single[be][msz][esz]; + fn = fn_single[s->mte_active[0]][be][msz][esz]; + nreg = 1; } else { /* ST2, ST3, ST4 -- msz == esz, enforced by encoding */ assert(msz == esz); - fn = fn_multiple[be][nreg - 1][msz]; + fn = fn_multiple[s->mte_active[0]][be][nreg - 1][msz]; } assert(fn != NULL); - do_mem_zpa(s, zt, pg, addr, msz_dtype(s, msz), 0, true, fn); + do_mem_zpa(s, zt, pg, addr, msz_dtype(s, msz), nreg, true, fn); } static bool trans_ST_zprr(DisasContext *s, arg_rprr_store *a) From aa13f7c3c378fa41366b9fcd6c29af1c3d81126a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:33 -0700 Subject: [PATCH 1682/2595] target/arm: Add mte helpers for sve scalar + int ff/nf loads Because the elements are sequential, we can eliminate many tests all at once when the tag hits TCMA, or if the page(s) are not Tagged. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-36-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-sve.h | 98 ++++++++++++++++ target/arm/sve_helper.c | 99 ++++++++++++++-- target/arm/translate-sve.c | 232 +++++++++++++++++++++++++------------ 3 files changed, 343 insertions(+), 86 deletions(-) diff --git a/target/arm/helper-sve.h b/target/arm/helper-sve.h index 1425f33c92..f48752eb42 100644 --- a/target/arm/helper-sve.h +++ b/target/arm/helper-sve.h @@ -1285,6 +1285,55 @@ DEF_HELPER_FLAGS_4(sve_ldff1sds_be_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_ldff1dd_le_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_ldff1dd_be_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1bb_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1bhu_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1bsu_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1bdu_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1bhs_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1bss_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1bds_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ldff1hh_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1hsu_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1hdu_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1hss_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1hds_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ldff1hh_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1hsu_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1hdu_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1hss_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1hds_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ldff1ss_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1sdu_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1sds_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ldff1ss_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1sdu_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1sds_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ldff1dd_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldff1dd_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) + DEF_HELPER_FLAGS_4(sve_ldnf1bb_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_ldnf1bhu_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_ldnf1bsu_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) @@ -1316,6 +1365,55 @@ DEF_HELPER_FLAGS_4(sve_ldnf1sds_be_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_ldnf1dd_le_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_ldnf1dd_be_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1bb_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1bhu_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1bsu_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1bdu_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1bhs_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1bss_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1bds_r_mte, TCG_CALL_NO_WG, void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ldnf1hh_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1hsu_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1hdu_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1hss_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1hds_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ldnf1hh_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1hsu_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1hdu_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1hss_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1hds_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ldnf1ss_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1sdu_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1sds_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ldnf1ss_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1sdu_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1sds_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) + +DEF_HELPER_FLAGS_4(sve_ldnf1dd_le_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) +DEF_HELPER_FLAGS_4(sve_ldnf1dd_be_r_mte, TCG_CALL_NO_WG, + void, env, ptr, tl, i32) + DEF_HELPER_FLAGS_4(sve_st1bb_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_st2bb_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) DEF_HELPER_FLAGS_4(sve_st3bb_r, TCG_CALL_NO_WG, void, env, ptr, tl, i32) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index ded9cedd18..7aca4ad384 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -4794,7 +4794,7 @@ static void record_fault(CPUARMState *env, uintptr_t i, uintptr_t oprsz) */ static inline QEMU_ALWAYS_INLINE void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr, - uint32_t desc, const uintptr_t retaddr, + uint32_t desc, const uintptr_t retaddr, uint32_t mtedesc, const int esz, const int msz, const SVEContFault fault, sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) @@ -4826,13 +4826,25 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr, mem_off = info.mem_off_first[0]; flags = info.page[0].flags; + /* + * Disable MTE checking if the Tagged bit is not set. Since TBI must + * be set within MTEDESC for MTE, !mtedesc => !mte_active. + */ + if (arm_tlb_mte_tagged(&info.page[0].attrs)) { + mtedesc = 0; + } + if (fault == FAULT_FIRST) { + /* Trapping mte check for the first-fault element. */ + if (mtedesc) { + mte_check1(env, mtedesc, addr + mem_off, retaddr); + } + /* * Special handling of the first active element, * if it crosses a page boundary or is MMIO. */ bool is_split = mem_off == info.mem_off_split; - /* TODO: MTE check. */ if (unlikely(flags != 0) || unlikely(is_split)) { /* * Use the slow path for cross-page handling. @@ -4868,7 +4880,9 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr, /* Watchpoint hit, see below. */ goto do_fault; } - /* TODO: MTE check. */ + if (mtedesc && !mte_probe1(env, mtedesc, addr + mem_off)) { + goto do_fault; + } /* * Use the slow path for cross-page handling. * This is RAM, without a watchpoint, and will not trap. @@ -4916,7 +4930,9 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr, & BP_MEM_READ)) { goto do_fault; } - /* TODO: MTE check. */ + if (mtedesc && !mte_probe1(env, mtedesc, addr + mem_off)) { + goto do_fault; + } host_fn(vd, reg_off, host + mem_off); } reg_off += 1 << esz; @@ -4954,44 +4970,103 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr, record_fault(env, reg_off, reg_max); } -#define DO_LDFF1_LDNF1_1(PART, ESZ) \ +static inline QEMU_ALWAYS_INLINE +void sve_ldnfff1_r_mte(CPUARMState *env, void *vg, target_ulong addr, + uint32_t desc, const uintptr_t retaddr, + const int esz, const int msz, const SVEContFault fault, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) +{ + uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + int bit55 = extract64(addr, 55, 1); + + /* Remove mtedesc from the normal sve descriptor. */ + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* Perform gross MTE suppression early. */ + if (!tbi_check(desc, bit55) || + tcma_check(desc, bit55, allocation_tag_from_addr(addr))) { + mtedesc = 0; + } + + sve_ldnfff1_r(env, vg, addr, desc, retaddr, mtedesc, + esz, msz, fault, host_fn, tlb_fn); +} + +#define DO_LDFF1_LDNF1_1(PART, ESZ) \ void HELPER(sve_ldff1##PART##_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, FAULT_FIRST, \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MO_8, FAULT_FIRST, \ sve_ld1##PART##_host, sve_ld1##PART##_tlb); \ } \ void HELPER(sve_ldnf1##PART##_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, FAULT_NO, \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MO_8, FAULT_NO, \ + sve_ld1##PART##_host, sve_ld1##PART##_tlb); \ +} \ +void HELPER(sve_ldff1##PART##_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MO_8, FAULT_FIRST, \ + sve_ld1##PART##_host, sve_ld1##PART##_tlb); \ +} \ +void HELPER(sve_ldnf1##PART##_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MO_8, FAULT_NO, \ sve_ld1##PART##_host, sve_ld1##PART##_tlb); \ } -#define DO_LDFF1_LDNF1_2(PART, ESZ, MSZ) \ +#define DO_LDFF1_LDNF1_2(PART, ESZ, MSZ) \ void HELPER(sve_ldff1##PART##_le_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_FIRST, \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MSZ, FAULT_FIRST, \ sve_ld1##PART##_le_host, sve_ld1##PART##_le_tlb); \ } \ void HELPER(sve_ldnf1##PART##_le_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_NO, \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MSZ, FAULT_NO, \ sve_ld1##PART##_le_host, sve_ld1##PART##_le_tlb); \ } \ void HELPER(sve_ldff1##PART##_be_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_FIRST, \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MSZ, FAULT_FIRST, \ sve_ld1##PART##_be_host, sve_ld1##PART##_be_tlb); \ } \ void HELPER(sve_ldnf1##PART##_be_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ - sve_ldnfff1_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_NO, \ + sve_ldnfff1_r(env, vg, addr, desc, GETPC(), 0, ESZ, MSZ, FAULT_NO, \ sve_ld1##PART##_be_host, sve_ld1##PART##_be_tlb); \ +} \ +void HELPER(sve_ldff1##PART##_le_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_FIRST, \ + sve_ld1##PART##_le_host, sve_ld1##PART##_le_tlb); \ +} \ +void HELPER(sve_ldnf1##PART##_le_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_NO, \ + sve_ld1##PART##_le_host, sve_ld1##PART##_le_tlb); \ +} \ +void HELPER(sve_ldff1##PART##_be_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_FIRST, \ + sve_ld1##PART##_be_host, sve_ld1##PART##_be_tlb); \ +} \ +void HELPER(sve_ldnf1##PART##_be_r_mte)(CPUARMState *env, void *vg, \ + target_ulong addr, uint32_t desc) \ +{ \ + sve_ldnfff1_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, FAULT_NO, \ + sve_ld1##PART##_be_host, sve_ld1##PART##_be_tlb); \ } DO_LDFF1_LDNF1_1(bb, MO_8) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index daac8589f3..e4fbe48493 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4773,104 +4773,188 @@ static bool trans_LD_zpri(DisasContext *s, arg_rpri_load *a) static bool trans_LDFF1_zprr(DisasContext *s, arg_rprr_load *a) { - static gen_helper_gvec_mem * const fns[2][16] = { - /* Little-endian */ - { gen_helper_sve_ldff1bb_r, - gen_helper_sve_ldff1bhu_r, - gen_helper_sve_ldff1bsu_r, - gen_helper_sve_ldff1bdu_r, + static gen_helper_gvec_mem * const fns[2][2][16] = { + { /* mte inactive, little-endian */ + { gen_helper_sve_ldff1bb_r, + gen_helper_sve_ldff1bhu_r, + gen_helper_sve_ldff1bsu_r, + gen_helper_sve_ldff1bdu_r, - gen_helper_sve_ldff1sds_le_r, - gen_helper_sve_ldff1hh_le_r, - gen_helper_sve_ldff1hsu_le_r, - gen_helper_sve_ldff1hdu_le_r, + gen_helper_sve_ldff1sds_le_r, + gen_helper_sve_ldff1hh_le_r, + gen_helper_sve_ldff1hsu_le_r, + gen_helper_sve_ldff1hdu_le_r, - gen_helper_sve_ldff1hds_le_r, - gen_helper_sve_ldff1hss_le_r, - gen_helper_sve_ldff1ss_le_r, - gen_helper_sve_ldff1sdu_le_r, + gen_helper_sve_ldff1hds_le_r, + gen_helper_sve_ldff1hss_le_r, + gen_helper_sve_ldff1ss_le_r, + gen_helper_sve_ldff1sdu_le_r, - gen_helper_sve_ldff1bds_r, - gen_helper_sve_ldff1bss_r, - gen_helper_sve_ldff1bhs_r, - gen_helper_sve_ldff1dd_le_r }, + gen_helper_sve_ldff1bds_r, + gen_helper_sve_ldff1bss_r, + gen_helper_sve_ldff1bhs_r, + gen_helper_sve_ldff1dd_le_r }, - /* Big-endian */ - { gen_helper_sve_ldff1bb_r, - gen_helper_sve_ldff1bhu_r, - gen_helper_sve_ldff1bsu_r, - gen_helper_sve_ldff1bdu_r, + /* mte inactive, big-endian */ + { gen_helper_sve_ldff1bb_r, + gen_helper_sve_ldff1bhu_r, + gen_helper_sve_ldff1bsu_r, + gen_helper_sve_ldff1bdu_r, - gen_helper_sve_ldff1sds_be_r, - gen_helper_sve_ldff1hh_be_r, - gen_helper_sve_ldff1hsu_be_r, - gen_helper_sve_ldff1hdu_be_r, + gen_helper_sve_ldff1sds_be_r, + gen_helper_sve_ldff1hh_be_r, + gen_helper_sve_ldff1hsu_be_r, + gen_helper_sve_ldff1hdu_be_r, - gen_helper_sve_ldff1hds_be_r, - gen_helper_sve_ldff1hss_be_r, - gen_helper_sve_ldff1ss_be_r, - gen_helper_sve_ldff1sdu_be_r, + gen_helper_sve_ldff1hds_be_r, + gen_helper_sve_ldff1hss_be_r, + gen_helper_sve_ldff1ss_be_r, + gen_helper_sve_ldff1sdu_be_r, - gen_helper_sve_ldff1bds_r, - gen_helper_sve_ldff1bss_r, - gen_helper_sve_ldff1bhs_r, - gen_helper_sve_ldff1dd_be_r }, + gen_helper_sve_ldff1bds_r, + gen_helper_sve_ldff1bss_r, + gen_helper_sve_ldff1bhs_r, + gen_helper_sve_ldff1dd_be_r } }, + + { /* mte active, little-endian */ + { gen_helper_sve_ldff1bb_r_mte, + gen_helper_sve_ldff1bhu_r_mte, + gen_helper_sve_ldff1bsu_r_mte, + gen_helper_sve_ldff1bdu_r_mte, + + gen_helper_sve_ldff1sds_le_r_mte, + gen_helper_sve_ldff1hh_le_r_mte, + gen_helper_sve_ldff1hsu_le_r_mte, + gen_helper_sve_ldff1hdu_le_r_mte, + + gen_helper_sve_ldff1hds_le_r_mte, + gen_helper_sve_ldff1hss_le_r_mte, + gen_helper_sve_ldff1ss_le_r_mte, + gen_helper_sve_ldff1sdu_le_r_mte, + + gen_helper_sve_ldff1bds_r_mte, + gen_helper_sve_ldff1bss_r_mte, + gen_helper_sve_ldff1bhs_r_mte, + gen_helper_sve_ldff1dd_le_r_mte }, + + /* mte active, big-endian */ + { gen_helper_sve_ldff1bb_r_mte, + gen_helper_sve_ldff1bhu_r_mte, + gen_helper_sve_ldff1bsu_r_mte, + gen_helper_sve_ldff1bdu_r_mte, + + gen_helper_sve_ldff1sds_be_r_mte, + gen_helper_sve_ldff1hh_be_r_mte, + gen_helper_sve_ldff1hsu_be_r_mte, + gen_helper_sve_ldff1hdu_be_r_mte, + + gen_helper_sve_ldff1hds_be_r_mte, + gen_helper_sve_ldff1hss_be_r_mte, + gen_helper_sve_ldff1ss_be_r_mte, + gen_helper_sve_ldff1sdu_be_r_mte, + + gen_helper_sve_ldff1bds_r_mte, + gen_helper_sve_ldff1bss_r_mte, + gen_helper_sve_ldff1bhs_r_mte, + gen_helper_sve_ldff1dd_be_r_mte } }, }; if (sve_access_check(s)) { TCGv_i64 addr = new_tmp_a64(s); tcg_gen_shli_i64(addr, cpu_reg(s, a->rm), dtype_msz(a->dtype)); tcg_gen_add_i64(addr, addr, cpu_reg_sp(s, a->rn)); - do_mem_zpa(s, a->rd, a->pg, addr, a->dtype, 0, false, - fns[s->be_data == MO_BE][a->dtype]); + do_mem_zpa(s, a->rd, a->pg, addr, a->dtype, 1, false, + fns[s->mte_active[0]][s->be_data == MO_BE][a->dtype]); } return true; } static bool trans_LDNF1_zpri(DisasContext *s, arg_rpri_load *a) { - static gen_helper_gvec_mem * const fns[2][16] = { - /* Little-endian */ - { gen_helper_sve_ldnf1bb_r, - gen_helper_sve_ldnf1bhu_r, - gen_helper_sve_ldnf1bsu_r, - gen_helper_sve_ldnf1bdu_r, + static gen_helper_gvec_mem * const fns[2][2][16] = { + { /* mte inactive, little-endian */ + { gen_helper_sve_ldnf1bb_r, + gen_helper_sve_ldnf1bhu_r, + gen_helper_sve_ldnf1bsu_r, + gen_helper_sve_ldnf1bdu_r, - gen_helper_sve_ldnf1sds_le_r, - gen_helper_sve_ldnf1hh_le_r, - gen_helper_sve_ldnf1hsu_le_r, - gen_helper_sve_ldnf1hdu_le_r, + gen_helper_sve_ldnf1sds_le_r, + gen_helper_sve_ldnf1hh_le_r, + gen_helper_sve_ldnf1hsu_le_r, + gen_helper_sve_ldnf1hdu_le_r, - gen_helper_sve_ldnf1hds_le_r, - gen_helper_sve_ldnf1hss_le_r, - gen_helper_sve_ldnf1ss_le_r, - gen_helper_sve_ldnf1sdu_le_r, + gen_helper_sve_ldnf1hds_le_r, + gen_helper_sve_ldnf1hss_le_r, + gen_helper_sve_ldnf1ss_le_r, + gen_helper_sve_ldnf1sdu_le_r, - gen_helper_sve_ldnf1bds_r, - gen_helper_sve_ldnf1bss_r, - gen_helper_sve_ldnf1bhs_r, - gen_helper_sve_ldnf1dd_le_r }, + gen_helper_sve_ldnf1bds_r, + gen_helper_sve_ldnf1bss_r, + gen_helper_sve_ldnf1bhs_r, + gen_helper_sve_ldnf1dd_le_r }, - /* Big-endian */ - { gen_helper_sve_ldnf1bb_r, - gen_helper_sve_ldnf1bhu_r, - gen_helper_sve_ldnf1bsu_r, - gen_helper_sve_ldnf1bdu_r, + /* mte inactive, big-endian */ + { gen_helper_sve_ldnf1bb_r, + gen_helper_sve_ldnf1bhu_r, + gen_helper_sve_ldnf1bsu_r, + gen_helper_sve_ldnf1bdu_r, - gen_helper_sve_ldnf1sds_be_r, - gen_helper_sve_ldnf1hh_be_r, - gen_helper_sve_ldnf1hsu_be_r, - gen_helper_sve_ldnf1hdu_be_r, + gen_helper_sve_ldnf1sds_be_r, + gen_helper_sve_ldnf1hh_be_r, + gen_helper_sve_ldnf1hsu_be_r, + gen_helper_sve_ldnf1hdu_be_r, - gen_helper_sve_ldnf1hds_be_r, - gen_helper_sve_ldnf1hss_be_r, - gen_helper_sve_ldnf1ss_be_r, - gen_helper_sve_ldnf1sdu_be_r, + gen_helper_sve_ldnf1hds_be_r, + gen_helper_sve_ldnf1hss_be_r, + gen_helper_sve_ldnf1ss_be_r, + gen_helper_sve_ldnf1sdu_be_r, - gen_helper_sve_ldnf1bds_r, - gen_helper_sve_ldnf1bss_r, - gen_helper_sve_ldnf1bhs_r, - gen_helper_sve_ldnf1dd_be_r }, + gen_helper_sve_ldnf1bds_r, + gen_helper_sve_ldnf1bss_r, + gen_helper_sve_ldnf1bhs_r, + gen_helper_sve_ldnf1dd_be_r } }, + + { /* mte inactive, little-endian */ + { gen_helper_sve_ldnf1bb_r_mte, + gen_helper_sve_ldnf1bhu_r_mte, + gen_helper_sve_ldnf1bsu_r_mte, + gen_helper_sve_ldnf1bdu_r_mte, + + gen_helper_sve_ldnf1sds_le_r_mte, + gen_helper_sve_ldnf1hh_le_r_mte, + gen_helper_sve_ldnf1hsu_le_r_mte, + gen_helper_sve_ldnf1hdu_le_r_mte, + + gen_helper_sve_ldnf1hds_le_r_mte, + gen_helper_sve_ldnf1hss_le_r_mte, + gen_helper_sve_ldnf1ss_le_r_mte, + gen_helper_sve_ldnf1sdu_le_r_mte, + + gen_helper_sve_ldnf1bds_r_mte, + gen_helper_sve_ldnf1bss_r_mte, + gen_helper_sve_ldnf1bhs_r_mte, + gen_helper_sve_ldnf1dd_le_r_mte }, + + /* mte inactive, big-endian */ + { gen_helper_sve_ldnf1bb_r_mte, + gen_helper_sve_ldnf1bhu_r_mte, + gen_helper_sve_ldnf1bsu_r_mte, + gen_helper_sve_ldnf1bdu_r_mte, + + gen_helper_sve_ldnf1sds_be_r_mte, + gen_helper_sve_ldnf1hh_be_r_mte, + gen_helper_sve_ldnf1hsu_be_r_mte, + gen_helper_sve_ldnf1hdu_be_r_mte, + + gen_helper_sve_ldnf1hds_be_r_mte, + gen_helper_sve_ldnf1hss_be_r_mte, + gen_helper_sve_ldnf1ss_be_r_mte, + gen_helper_sve_ldnf1sdu_be_r_mte, + + gen_helper_sve_ldnf1bds_r_mte, + gen_helper_sve_ldnf1bss_r_mte, + gen_helper_sve_ldnf1bhs_r_mte, + gen_helper_sve_ldnf1dd_be_r_mte } }, }; if (sve_access_check(s)) { @@ -4880,8 +4964,8 @@ static bool trans_LDNF1_zpri(DisasContext *s, arg_rpri_load *a) TCGv_i64 addr = new_tmp_a64(s); tcg_gen_addi_i64(addr, cpu_reg_sp(s, a->rn), off); - do_mem_zpa(s, a->rd, a->pg, addr, a->dtype, 0, false, - fns[s->be_data == MO_BE][a->dtype]); + do_mem_zpa(s, a->rd, a->pg, addr, a->dtype, 1, false, + fns[s->mte_active[0]][s->be_data == MO_BE][a->dtype]); } return true; } From 9473d0ecafcffc8b258892b1f9f18e037bdba958 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:34 -0700 Subject: [PATCH 1683/2595] target/arm: Handle TBI for sve scalar + int memory ops We still need to handle tbi for user-only when mte is inactive. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-37-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 2 +- target/arm/translate-a64.h | 1 + target/arm/translate-sve.c | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 7a3774bfda..e46c4a49e0 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -215,7 +215,7 @@ static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src) * of the write-back address. */ -static TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr) +TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr) { TCGv_i64 clean = new_tmp_a64(s); #ifdef CONFIG_USER_ONLY diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index 781c441399..49e4865918 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -40,6 +40,7 @@ TCGv_ptr get_fpstatus_ptr(bool); bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn, unsigned int imms, unsigned int immr); bool sve_access_check(DisasContext *s); +TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr); TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write, bool tag_checked, int log2_size); TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index e4fbe48493..04eda9a126 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4587,9 +4587,8 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, * For e.g. LD4, there are not enough arguments to pass all 4 * registers as pointers, so encode the regno into the data field. * For consistency, do this even for LD1. - * TODO: mte_n check here while callers are updated. */ - if (mte_n && s->mte_active[0]) { + if (s->mte_active[0]) { int msz = dtype_msz(dtype); desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); @@ -4599,7 +4598,10 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, desc = FIELD_DP32(desc, MTEDESC, ESIZE, 1 << msz); desc = FIELD_DP32(desc, MTEDESC, TSIZE, mte_n << msz); desc <<= SVE_MTEDESC_SHIFT; + } else { + addr = clean_data_tbi(s, addr); } + desc = simd_desc(vsz, vsz, zt | desc); t_desc = tcg_const_i32(desc); t_pg = tcg_temp_new_ptr(); From d28d12f008ee44dc2cc2ee5d8f673be9febc951e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:35 -0700 Subject: [PATCH 1684/2595] target/arm: Add mte helpers for sve scatter/gather memory ops Because the elements are non-sequential, we cannot eliminate many tests straight away like we can for sequential operations. But we often have the PTE details handy, so we can test for Tagged. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-38-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-sve.h | 285 ++++++++++++++++ target/arm/sve_helper.c | 185 +++++++++-- target/arm/translate-sve.c | 650 +++++++++++++++++++++++++------------ 3 files changed, 872 insertions(+), 248 deletions(-) diff --git a/target/arm/helper-sve.h b/target/arm/helper-sve.h index f48752eb42..63c4a087ca 100644 --- a/target/arm/helper-sve.h +++ b/target/arm/helper-sve.h @@ -1617,6 +1617,115 @@ DEF_HELPER_FLAGS_6(sve_ldsds_le_zd, TCG_CALL_NO_WG, DEF_HELPER_FLAGS_6(sve_ldsds_be_zd, TCG_CALL_NO_WG, void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldbsu_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhsu_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhsu_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldss_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldss_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldbss_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhss_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhss_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_ldbsu_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhsu_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhsu_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldss_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldss_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldbss_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhss_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhss_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_ldbdu_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhdu_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhdu_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsdu_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsdu_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_lddd_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_lddd_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldbds_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhds_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhds_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsds_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsds_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_ldbdu_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhdu_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhdu_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsdu_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsdu_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_lddd_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_lddd_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldbds_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhds_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhds_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsds_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsds_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_ldbdu_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhdu_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhdu_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsdu_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsdu_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_lddd_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_lddd_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldbds_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhds_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldhds_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsds_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldsds_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + DEF_HELPER_FLAGS_6(sve_ldffbsu_zsu, TCG_CALL_NO_WG, void, env, ptr, ptr, ptr, tl, i32) DEF_HELPER_FLAGS_6(sve_ldffhsu_le_zsu, TCG_CALL_NO_WG, @@ -1726,6 +1835,115 @@ DEF_HELPER_FLAGS_6(sve_ldffsds_le_zd, TCG_CALL_NO_WG, DEF_HELPER_FLAGS_6(sve_ldffsds_be_zd, TCG_CALL_NO_WG, void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffbsu_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhsu_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhsu_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffss_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffss_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffbss_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhss_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhss_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_ldffbsu_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhsu_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhsu_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffss_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffss_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffbss_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhss_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhss_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_ldffbdu_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhdu_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhdu_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsdu_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsdu_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffdd_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffdd_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffbds_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhds_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhds_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsds_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsds_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_ldffbdu_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhdu_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhdu_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsdu_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsdu_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffdd_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffdd_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffbds_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhds_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhds_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsds_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsds_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_ldffbdu_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhdu_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhdu_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsdu_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsdu_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffdd_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffdd_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffbds_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhds_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffhds_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsds_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_ldffsds_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + DEF_HELPER_FLAGS_6(sve_stbs_zsu, TCG_CALL_NO_WG, void, env, ptr, ptr, ptr, tl, i32) DEF_HELPER_FLAGS_6(sve_sths_le_zsu, TCG_CALL_NO_WG, @@ -1793,4 +2011,71 @@ DEF_HELPER_FLAGS_6(sve_stdd_le_zd, TCG_CALL_NO_WG, DEF_HELPER_FLAGS_6(sve_stdd_be_zd, TCG_CALL_NO_WG, void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stbs_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_sths_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_sths_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stss_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stss_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_stbs_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_sths_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_sths_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stss_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stss_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_stbd_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_sthd_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_sthd_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stsd_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stsd_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stdd_le_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stdd_be_zsu_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_stbd_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_sthd_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_sthd_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stsd_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stsd_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stdd_le_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stdd_be_zss_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + +DEF_HELPER_FLAGS_6(sve_stbd_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_sthd_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_sthd_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stsd_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stsd_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stdd_le_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) +DEF_HELPER_FLAGS_6(sve_stdd_be_zd_mte, TCG_CALL_NO_WG, + void, env, ptr, ptr, ptr, tl, i32) + DEF_HELPER_FLAGS_4(sve2_pmull_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 7aca4ad384..ad974c2cc5 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -5354,7 +5354,8 @@ static target_ulong off_zd_d(void *reg, intptr_t reg_ofs) static inline QEMU_ALWAYS_INLINE void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, target_ulong base, uint32_t desc, uintptr_t retaddr, - int esize, int msize, zreg_off_fn *off_fn, + uint32_t mtedesc, int esize, int msize, + zreg_off_fn *off_fn, sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) { @@ -5382,7 +5383,9 @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, cpu_check_watchpoint(env_cpu(env), addr, msize, info.attrs, BP_MEM_READ, retaddr); } - /* TODO: MTE check */ + if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) { + mte_check1(env, mtedesc, addr, retaddr); + } host_fn(&scratch, reg_off, info.host); } else { /* Element crosses the page boundary. */ @@ -5393,7 +5396,9 @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, msize, info.attrs, BP_MEM_READ, retaddr); } - /* TODO: MTE check */ + if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) { + mte_check1(env, mtedesc, addr, retaddr); + } tlb_fn(env, &scratch, reg_off, addr, retaddr); } } @@ -5406,20 +5411,53 @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, memcpy(vd, &scratch, reg_max); } +static inline QEMU_ALWAYS_INLINE +void sve_ld1_z_mte(CPUARMState *env, void *vd, uint64_t *vg, void *vm, + target_ulong base, uint32_t desc, uintptr_t retaddr, + int esize, int msize, zreg_off_fn *off_fn, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) +{ + uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + /* Remove mtedesc from the normal sve descriptor. */ + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* + * ??? TODO: For the 32-bit offset extractions, base + ofs cannot + * offset base entirely over the address space hole to change the + * pointer tag, or change the bit55 selector. So we could here + * examine TBI + TCMA like we do for sve_ldN_r_mte(). + */ + sve_ld1_z(env, vd, vg, vm, base, desc, retaddr, mtedesc, + esize, msize, off_fn, host_fn, tlb_fn); +} + #define DO_LD1_ZPZ_S(MEM, OFS, MSZ) \ void HELPER(sve_ld##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ void *vm, target_ulong base, uint32_t desc) \ { \ - sve_ld1_z(env, vd, vg, vm, base, desc, GETPC(), 4, 1 << MSZ, \ + sve_ld1_z(env, vd, vg, vm, base, desc, GETPC(), 0, 4, 1 << MSZ, \ off_##OFS##_s, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ +} \ +void HELPER(sve_ld##MEM##_##OFS##_mte)(CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_ld1_z_mte(env, vd, vg, vm, base, desc, GETPC(), 4, 1 << MSZ, \ + off_##OFS##_s, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ } #define DO_LD1_ZPZ_D(MEM, OFS, MSZ) \ void HELPER(sve_ld##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ void *vm, target_ulong base, uint32_t desc) \ { \ - sve_ld1_z(env, vd, vg, vm, base, desc, GETPC(), 8, 1 << MSZ, \ + sve_ld1_z(env, vd, vg, vm, base, desc, GETPC(), 0, 8, 1 << MSZ, \ off_##OFS##_d, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ +} \ +void HELPER(sve_ld##MEM##_##OFS##_mte)(CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_ld1_z_mte(env, vd, vg, vm, base, desc, GETPC(), 8, 1 << MSZ, \ + off_##OFS##_d, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ } DO_LD1_ZPZ_S(bsu, zsu, MO_8) @@ -5498,7 +5536,8 @@ DO_LD1_ZPZ_D(dd_be, zd, MO_64) static inline QEMU_ALWAYS_INLINE void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, target_ulong base, uint32_t desc, uintptr_t retaddr, - const int esz, const int msz, zreg_off_fn *off_fn, + uint32_t mtedesc, const int esz, const int msz, + zreg_off_fn *off_fn, sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) { @@ -5523,6 +5562,9 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, * Probe the first element, allowing faults. */ addr = base + (off_fn(vm, reg_off) << scale); + if (mtedesc) { + mte_check1(env, mtedesc, addr, retaddr); + } tlb_fn(env, vd, reg_off, addr, retaddr); /* After any fault, zero the other elements. */ @@ -5555,7 +5597,11 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, (env_cpu(env), addr, msize) & BP_MEM_READ)) { goto fault; } - /* TODO: MTE check. */ + if (mtedesc && + arm_tlb_mte_tagged(&info.attrs) && + !mte_probe1(env, mtedesc, addr)) { + goto fault; + } host_fn(vd, reg_off, info.host); } @@ -5568,20 +5614,58 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, record_fault(env, reg_off, reg_max); } -#define DO_LDFF1_ZPZ_S(MEM, OFS, MSZ) \ -void HELPER(sve_ldff##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ - void *vm, target_ulong base, uint32_t desc) \ -{ \ - sve_ldff1_z(env, vd, vg, vm, base, desc, GETPC(), MO_32, MSZ, \ - off_##OFS##_s, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ +static inline QEMU_ALWAYS_INLINE +void sve_ldff1_z_mte(CPUARMState *env, void *vd, uint64_t *vg, void *vm, + target_ulong base, uint32_t desc, uintptr_t retaddr, + const int esz, const int msz, + zreg_off_fn *off_fn, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) +{ + uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + /* Remove mtedesc from the normal sve descriptor. */ + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* + * ??? TODO: For the 32-bit offset extractions, base + ofs cannot + * offset base entirely over the address space hole to change the + * pointer tag, or change the bit55 selector. So we could here + * examine TBI + TCMA like we do for sve_ldN_r_mte(). + */ + sve_ldff1_z(env, vd, vg, vm, base, desc, retaddr, mtedesc, + esz, msz, off_fn, host_fn, tlb_fn); } -#define DO_LDFF1_ZPZ_D(MEM, OFS, MSZ) \ -void HELPER(sve_ldff##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ - void *vm, target_ulong base, uint32_t desc) \ -{ \ - sve_ldff1_z(env, vd, vg, vm, base, desc, GETPC(), MO_64, MSZ, \ - off_##OFS##_d, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ +#define DO_LDFF1_ZPZ_S(MEM, OFS, MSZ) \ +void HELPER(sve_ldff##MEM##_##OFS) \ + (CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_ldff1_z(env, vd, vg, vm, base, desc, GETPC(), 0, MO_32, MSZ, \ + off_##OFS##_s, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ +} \ +void HELPER(sve_ldff##MEM##_##OFS##_mte) \ + (CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_ldff1_z_mte(env, vd, vg, vm, base, desc, GETPC(), MO_32, MSZ, \ + off_##OFS##_s, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ +} + +#define DO_LDFF1_ZPZ_D(MEM, OFS, MSZ) \ +void HELPER(sve_ldff##MEM##_##OFS) \ + (CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_ldff1_z(env, vd, vg, vm, base, desc, GETPC(), 0, MO_64, MSZ, \ + off_##OFS##_d, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ +} \ +void HELPER(sve_ldff##MEM##_##OFS##_mte) \ + (CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_ldff1_z_mte(env, vd, vg, vm, base, desc, GETPC(), MO_64, MSZ, \ + off_##OFS##_d, sve_ld1##MEM##_host, sve_ld1##MEM##_tlb); \ } DO_LDFF1_ZPZ_S(bsu, zsu, MO_8) @@ -5653,7 +5737,8 @@ DO_LDFF1_ZPZ_D(dd_be, zd, MO_64) static inline QEMU_ALWAYS_INLINE void sve_st1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, target_ulong base, uint32_t desc, uintptr_t retaddr, - int esize, int msize, zreg_off_fn *off_fn, + uint32_t mtedesc, int esize, int msize, + zreg_off_fn *off_fn, sve_ldst1_host_fn *host_fn, sve_ldst1_tlb_fn *tlb_fn) { @@ -5697,7 +5782,10 @@ void sve_st1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, cpu_check_watchpoint(env_cpu(env), addr, msize, info.attrs, BP_MEM_WRITE, retaddr); } - /* TODO: MTE check. */ + + if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) { + mte_check1(env, mtedesc, addr, retaddr); + } } i += 1; reg_off += esize; @@ -5727,20 +5815,53 @@ void sve_st1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, } while (reg_off < reg_max); } -#define DO_ST1_ZPZ_S(MEM, OFS, MSZ) \ -void HELPER(sve_st##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ - void *vm, target_ulong base, uint32_t desc) \ -{ \ - sve_st1_z(env, vd, vg, vm, base, desc, GETPC(), 4, 1 << MSZ, \ - off_##OFS##_s, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \ +static inline QEMU_ALWAYS_INLINE +void sve_st1_z_mte(CPUARMState *env, void *vd, uint64_t *vg, void *vm, + target_ulong base, uint32_t desc, uintptr_t retaddr, + int esize, int msize, zreg_off_fn *off_fn, + sve_ldst1_host_fn *host_fn, + sve_ldst1_tlb_fn *tlb_fn) +{ + uint32_t mtedesc = desc >> (SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + /* Remove mtedesc from the normal sve descriptor. */ + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* + * ??? TODO: For the 32-bit offset extractions, base + ofs cannot + * offset base entirely over the address space hole to change the + * pointer tag, or change the bit55 selector. So we could here + * examine TBI + TCMA like we do for sve_ldN_r_mte(). + */ + sve_st1_z(env, vd, vg, vm, base, desc, retaddr, mtedesc, + esize, msize, off_fn, host_fn, tlb_fn); } -#define DO_ST1_ZPZ_D(MEM, OFS, MSZ) \ -void HELPER(sve_st##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ +#define DO_ST1_ZPZ_S(MEM, OFS, MSZ) \ +void HELPER(sve_st##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ void *vm, target_ulong base, uint32_t desc) \ -{ \ - sve_st1_z(env, vd, vg, vm, base, desc, GETPC(), 8, 1 << MSZ, \ - off_##OFS##_d, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \ +{ \ + sve_st1_z(env, vd, vg, vm, base, desc, GETPC(), 0, 4, 1 << MSZ, \ + off_##OFS##_s, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \ +} \ +void HELPER(sve_st##MEM##_##OFS##_mte)(CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_st1_z_mte(env, vd, vg, vm, base, desc, GETPC(), 4, 1 << MSZ, \ + off_##OFS##_s, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \ +} + +#define DO_ST1_ZPZ_D(MEM, OFS, MSZ) \ +void HELPER(sve_st##MEM##_##OFS)(CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_st1_z(env, vd, vg, vm, base, desc, GETPC(), 0, 8, 1 << MSZ, \ + off_##OFS##_d, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \ +} \ +void HELPER(sve_st##MEM##_##OFS##_mte)(CPUARMState *env, void *vd, void *vg, \ + void *vm, target_ulong base, uint32_t desc) \ +{ \ + sve_st1_z_mte(env, vd, vg, vm, base, desc, GETPC(), 8, 1 << MSZ, \ + off_##OFS##_d, sve_st1##MEM##_host, sve_st1##MEM##_tlb); \ } DO_ST1_ZPZ_S(bs, zsu, MO_8) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 04eda9a126..f318ca265f 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -5261,7 +5261,7 @@ static bool trans_ST_zpri(DisasContext *s, arg_rpri_store *a) */ static void do_mem_zpz(DisasContext *s, int zt, int pg, int zm, - int scale, TCGv_i64 scalar, int msz, + int scale, TCGv_i64 scalar, int msz, bool is_write, gen_helper_gvec_mem_scatter *fn) { unsigned vsz = vec_full_reg_size(s); @@ -5269,8 +5269,16 @@ static void do_mem_zpz(DisasContext *s, int zt, int pg, int zm, TCGv_ptr t_pg = tcg_temp_new_ptr(); TCGv_ptr t_zt = tcg_temp_new_ptr(); TCGv_i32 t_desc; - int desc; + int desc = 0; + if (s->mte_active[0]) { + desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); + desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); + desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); + desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); + desc = FIELD_DP32(desc, MTEDESC, ESIZE, 1 << msz); + desc <<= SVE_MTEDESC_SHIFT; + } desc = simd_desc(vsz, vsz, scale); t_desc = tcg_const_i32(desc); @@ -5285,176 +5293,339 @@ static void do_mem_zpz(DisasContext *s, int zt, int pg, int zm, tcg_temp_free_i32(t_desc); } -/* Indexed by [be][ff][xs][u][msz]. */ -static gen_helper_gvec_mem_scatter * const gather_load_fn32[2][2][2][2][3] = { - /* Little-endian */ - { { { { gen_helper_sve_ldbss_zsu, - gen_helper_sve_ldhss_le_zsu, - NULL, }, - { gen_helper_sve_ldbsu_zsu, - gen_helper_sve_ldhsu_le_zsu, - gen_helper_sve_ldss_le_zsu, } }, - { { gen_helper_sve_ldbss_zss, - gen_helper_sve_ldhss_le_zss, - NULL, }, - { gen_helper_sve_ldbsu_zss, - gen_helper_sve_ldhsu_le_zss, - gen_helper_sve_ldss_le_zss, } } }, +/* Indexed by [mte][be][ff][xs][u][msz]. */ +static gen_helper_gvec_mem_scatter * const +gather_load_fn32[2][2][2][2][2][3] = { + { /* MTE Inactive */ + { /* Little-endian */ + { { { gen_helper_sve_ldbss_zsu, + gen_helper_sve_ldhss_le_zsu, + NULL, }, + { gen_helper_sve_ldbsu_zsu, + gen_helper_sve_ldhsu_le_zsu, + gen_helper_sve_ldss_le_zsu, } }, + { { gen_helper_sve_ldbss_zss, + gen_helper_sve_ldhss_le_zss, + NULL, }, + { gen_helper_sve_ldbsu_zss, + gen_helper_sve_ldhsu_le_zss, + gen_helper_sve_ldss_le_zss, } } }, - /* First-fault */ - { { { gen_helper_sve_ldffbss_zsu, - gen_helper_sve_ldffhss_le_zsu, - NULL, }, - { gen_helper_sve_ldffbsu_zsu, - gen_helper_sve_ldffhsu_le_zsu, - gen_helper_sve_ldffss_le_zsu, } }, - { { gen_helper_sve_ldffbss_zss, - gen_helper_sve_ldffhss_le_zss, - NULL, }, - { gen_helper_sve_ldffbsu_zss, - gen_helper_sve_ldffhsu_le_zss, - gen_helper_sve_ldffss_le_zss, } } } }, + /* First-fault */ + { { { gen_helper_sve_ldffbss_zsu, + gen_helper_sve_ldffhss_le_zsu, + NULL, }, + { gen_helper_sve_ldffbsu_zsu, + gen_helper_sve_ldffhsu_le_zsu, + gen_helper_sve_ldffss_le_zsu, } }, + { { gen_helper_sve_ldffbss_zss, + gen_helper_sve_ldffhss_le_zss, + NULL, }, + { gen_helper_sve_ldffbsu_zss, + gen_helper_sve_ldffhsu_le_zss, + gen_helper_sve_ldffss_le_zss, } } } }, - /* Big-endian */ - { { { { gen_helper_sve_ldbss_zsu, - gen_helper_sve_ldhss_be_zsu, - NULL, }, - { gen_helper_sve_ldbsu_zsu, - gen_helper_sve_ldhsu_be_zsu, - gen_helper_sve_ldss_be_zsu, } }, - { { gen_helper_sve_ldbss_zss, - gen_helper_sve_ldhss_be_zss, - NULL, }, - { gen_helper_sve_ldbsu_zss, - gen_helper_sve_ldhsu_be_zss, - gen_helper_sve_ldss_be_zss, } } }, + { /* Big-endian */ + { { { gen_helper_sve_ldbss_zsu, + gen_helper_sve_ldhss_be_zsu, + NULL, }, + { gen_helper_sve_ldbsu_zsu, + gen_helper_sve_ldhsu_be_zsu, + gen_helper_sve_ldss_be_zsu, } }, + { { gen_helper_sve_ldbss_zss, + gen_helper_sve_ldhss_be_zss, + NULL, }, + { gen_helper_sve_ldbsu_zss, + gen_helper_sve_ldhsu_be_zss, + gen_helper_sve_ldss_be_zss, } } }, - /* First-fault */ - { { { gen_helper_sve_ldffbss_zsu, - gen_helper_sve_ldffhss_be_zsu, - NULL, }, - { gen_helper_sve_ldffbsu_zsu, - gen_helper_sve_ldffhsu_be_zsu, - gen_helper_sve_ldffss_be_zsu, } }, - { { gen_helper_sve_ldffbss_zss, - gen_helper_sve_ldffhss_be_zss, - NULL, }, - { gen_helper_sve_ldffbsu_zss, - gen_helper_sve_ldffhsu_be_zss, - gen_helper_sve_ldffss_be_zss, } } } }, + /* First-fault */ + { { { gen_helper_sve_ldffbss_zsu, + gen_helper_sve_ldffhss_be_zsu, + NULL, }, + { gen_helper_sve_ldffbsu_zsu, + gen_helper_sve_ldffhsu_be_zsu, + gen_helper_sve_ldffss_be_zsu, } }, + { { gen_helper_sve_ldffbss_zss, + gen_helper_sve_ldffhss_be_zss, + NULL, }, + { gen_helper_sve_ldffbsu_zss, + gen_helper_sve_ldffhsu_be_zss, + gen_helper_sve_ldffss_be_zss, } } } } }, + { /* MTE Active */ + { /* Little-endian */ + { { { gen_helper_sve_ldbss_zsu_mte, + gen_helper_sve_ldhss_le_zsu_mte, + NULL, }, + { gen_helper_sve_ldbsu_zsu_mte, + gen_helper_sve_ldhsu_le_zsu_mte, + gen_helper_sve_ldss_le_zsu_mte, } }, + { { gen_helper_sve_ldbss_zss_mte, + gen_helper_sve_ldhss_le_zss_mte, + NULL, }, + { gen_helper_sve_ldbsu_zss_mte, + gen_helper_sve_ldhsu_le_zss_mte, + gen_helper_sve_ldss_le_zss_mte, } } }, + + /* First-fault */ + { { { gen_helper_sve_ldffbss_zsu_mte, + gen_helper_sve_ldffhss_le_zsu_mte, + NULL, }, + { gen_helper_sve_ldffbsu_zsu_mte, + gen_helper_sve_ldffhsu_le_zsu_mte, + gen_helper_sve_ldffss_le_zsu_mte, } }, + { { gen_helper_sve_ldffbss_zss_mte, + gen_helper_sve_ldffhss_le_zss_mte, + NULL, }, + { gen_helper_sve_ldffbsu_zss_mte, + gen_helper_sve_ldffhsu_le_zss_mte, + gen_helper_sve_ldffss_le_zss_mte, } } } }, + + { /* Big-endian */ + { { { gen_helper_sve_ldbss_zsu_mte, + gen_helper_sve_ldhss_be_zsu_mte, + NULL, }, + { gen_helper_sve_ldbsu_zsu_mte, + gen_helper_sve_ldhsu_be_zsu_mte, + gen_helper_sve_ldss_be_zsu_mte, } }, + { { gen_helper_sve_ldbss_zss_mte, + gen_helper_sve_ldhss_be_zss_mte, + NULL, }, + { gen_helper_sve_ldbsu_zss_mte, + gen_helper_sve_ldhsu_be_zss_mte, + gen_helper_sve_ldss_be_zss_mte, } } }, + + /* First-fault */ + { { { gen_helper_sve_ldffbss_zsu_mte, + gen_helper_sve_ldffhss_be_zsu_mte, + NULL, }, + { gen_helper_sve_ldffbsu_zsu_mte, + gen_helper_sve_ldffhsu_be_zsu_mte, + gen_helper_sve_ldffss_be_zsu_mte, } }, + { { gen_helper_sve_ldffbss_zss_mte, + gen_helper_sve_ldffhss_be_zss_mte, + NULL, }, + { gen_helper_sve_ldffbsu_zss_mte, + gen_helper_sve_ldffhsu_be_zss_mte, + gen_helper_sve_ldffss_be_zss_mte, } } } } }, }; /* Note that we overload xs=2 to indicate 64-bit offset. */ -static gen_helper_gvec_mem_scatter * const gather_load_fn64[2][2][3][2][4] = { - /* Little-endian */ - { { { { gen_helper_sve_ldbds_zsu, - gen_helper_sve_ldhds_le_zsu, - gen_helper_sve_ldsds_le_zsu, - NULL, }, - { gen_helper_sve_ldbdu_zsu, - gen_helper_sve_ldhdu_le_zsu, - gen_helper_sve_ldsdu_le_zsu, - gen_helper_sve_lddd_le_zsu, } }, - { { gen_helper_sve_ldbds_zss, - gen_helper_sve_ldhds_le_zss, - gen_helper_sve_ldsds_le_zss, - NULL, }, - { gen_helper_sve_ldbdu_zss, - gen_helper_sve_ldhdu_le_zss, - gen_helper_sve_ldsdu_le_zss, - gen_helper_sve_lddd_le_zss, } }, - { { gen_helper_sve_ldbds_zd, - gen_helper_sve_ldhds_le_zd, - gen_helper_sve_ldsds_le_zd, - NULL, }, - { gen_helper_sve_ldbdu_zd, - gen_helper_sve_ldhdu_le_zd, - gen_helper_sve_ldsdu_le_zd, - gen_helper_sve_lddd_le_zd, } } }, +static gen_helper_gvec_mem_scatter * const +gather_load_fn64[2][2][2][3][2][4] = { + { /* MTE Inactive */ + { /* Little-endian */ + { { { gen_helper_sve_ldbds_zsu, + gen_helper_sve_ldhds_le_zsu, + gen_helper_sve_ldsds_le_zsu, + NULL, }, + { gen_helper_sve_ldbdu_zsu, + gen_helper_sve_ldhdu_le_zsu, + gen_helper_sve_ldsdu_le_zsu, + gen_helper_sve_lddd_le_zsu, } }, + { { gen_helper_sve_ldbds_zss, + gen_helper_sve_ldhds_le_zss, + gen_helper_sve_ldsds_le_zss, + NULL, }, + { gen_helper_sve_ldbdu_zss, + gen_helper_sve_ldhdu_le_zss, + gen_helper_sve_ldsdu_le_zss, + gen_helper_sve_lddd_le_zss, } }, + { { gen_helper_sve_ldbds_zd, + gen_helper_sve_ldhds_le_zd, + gen_helper_sve_ldsds_le_zd, + NULL, }, + { gen_helper_sve_ldbdu_zd, + gen_helper_sve_ldhdu_le_zd, + gen_helper_sve_ldsdu_le_zd, + gen_helper_sve_lddd_le_zd, } } }, - /* First-fault */ - { { { gen_helper_sve_ldffbds_zsu, - gen_helper_sve_ldffhds_le_zsu, - gen_helper_sve_ldffsds_le_zsu, - NULL, }, - { gen_helper_sve_ldffbdu_zsu, - gen_helper_sve_ldffhdu_le_zsu, - gen_helper_sve_ldffsdu_le_zsu, - gen_helper_sve_ldffdd_le_zsu, } }, - { { gen_helper_sve_ldffbds_zss, - gen_helper_sve_ldffhds_le_zss, - gen_helper_sve_ldffsds_le_zss, - NULL, }, - { gen_helper_sve_ldffbdu_zss, - gen_helper_sve_ldffhdu_le_zss, - gen_helper_sve_ldffsdu_le_zss, - gen_helper_sve_ldffdd_le_zss, } }, - { { gen_helper_sve_ldffbds_zd, - gen_helper_sve_ldffhds_le_zd, - gen_helper_sve_ldffsds_le_zd, - NULL, }, - { gen_helper_sve_ldffbdu_zd, - gen_helper_sve_ldffhdu_le_zd, - gen_helper_sve_ldffsdu_le_zd, - gen_helper_sve_ldffdd_le_zd, } } } }, + /* First-fault */ + { { { gen_helper_sve_ldffbds_zsu, + gen_helper_sve_ldffhds_le_zsu, + gen_helper_sve_ldffsds_le_zsu, + NULL, }, + { gen_helper_sve_ldffbdu_zsu, + gen_helper_sve_ldffhdu_le_zsu, + gen_helper_sve_ldffsdu_le_zsu, + gen_helper_sve_ldffdd_le_zsu, } }, + { { gen_helper_sve_ldffbds_zss, + gen_helper_sve_ldffhds_le_zss, + gen_helper_sve_ldffsds_le_zss, + NULL, }, + { gen_helper_sve_ldffbdu_zss, + gen_helper_sve_ldffhdu_le_zss, + gen_helper_sve_ldffsdu_le_zss, + gen_helper_sve_ldffdd_le_zss, } }, + { { gen_helper_sve_ldffbds_zd, + gen_helper_sve_ldffhds_le_zd, + gen_helper_sve_ldffsds_le_zd, + NULL, }, + { gen_helper_sve_ldffbdu_zd, + gen_helper_sve_ldffhdu_le_zd, + gen_helper_sve_ldffsdu_le_zd, + gen_helper_sve_ldffdd_le_zd, } } } }, + { /* Big-endian */ + { { { gen_helper_sve_ldbds_zsu, + gen_helper_sve_ldhds_be_zsu, + gen_helper_sve_ldsds_be_zsu, + NULL, }, + { gen_helper_sve_ldbdu_zsu, + gen_helper_sve_ldhdu_be_zsu, + gen_helper_sve_ldsdu_be_zsu, + gen_helper_sve_lddd_be_zsu, } }, + { { gen_helper_sve_ldbds_zss, + gen_helper_sve_ldhds_be_zss, + gen_helper_sve_ldsds_be_zss, + NULL, }, + { gen_helper_sve_ldbdu_zss, + gen_helper_sve_ldhdu_be_zss, + gen_helper_sve_ldsdu_be_zss, + gen_helper_sve_lddd_be_zss, } }, + { { gen_helper_sve_ldbds_zd, + gen_helper_sve_ldhds_be_zd, + gen_helper_sve_ldsds_be_zd, + NULL, }, + { gen_helper_sve_ldbdu_zd, + gen_helper_sve_ldhdu_be_zd, + gen_helper_sve_ldsdu_be_zd, + gen_helper_sve_lddd_be_zd, } } }, - /* Big-endian */ - { { { { gen_helper_sve_ldbds_zsu, - gen_helper_sve_ldhds_be_zsu, - gen_helper_sve_ldsds_be_zsu, - NULL, }, - { gen_helper_sve_ldbdu_zsu, - gen_helper_sve_ldhdu_be_zsu, - gen_helper_sve_ldsdu_be_zsu, - gen_helper_sve_lddd_be_zsu, } }, - { { gen_helper_sve_ldbds_zss, - gen_helper_sve_ldhds_be_zss, - gen_helper_sve_ldsds_be_zss, - NULL, }, - { gen_helper_sve_ldbdu_zss, - gen_helper_sve_ldhdu_be_zss, - gen_helper_sve_ldsdu_be_zss, - gen_helper_sve_lddd_be_zss, } }, - { { gen_helper_sve_ldbds_zd, - gen_helper_sve_ldhds_be_zd, - gen_helper_sve_ldsds_be_zd, - NULL, }, - { gen_helper_sve_ldbdu_zd, - gen_helper_sve_ldhdu_be_zd, - gen_helper_sve_ldsdu_be_zd, - gen_helper_sve_lddd_be_zd, } } }, + /* First-fault */ + { { { gen_helper_sve_ldffbds_zsu, + gen_helper_sve_ldffhds_be_zsu, + gen_helper_sve_ldffsds_be_zsu, + NULL, }, + { gen_helper_sve_ldffbdu_zsu, + gen_helper_sve_ldffhdu_be_zsu, + gen_helper_sve_ldffsdu_be_zsu, + gen_helper_sve_ldffdd_be_zsu, } }, + { { gen_helper_sve_ldffbds_zss, + gen_helper_sve_ldffhds_be_zss, + gen_helper_sve_ldffsds_be_zss, + NULL, }, + { gen_helper_sve_ldffbdu_zss, + gen_helper_sve_ldffhdu_be_zss, + gen_helper_sve_ldffsdu_be_zss, + gen_helper_sve_ldffdd_be_zss, } }, + { { gen_helper_sve_ldffbds_zd, + gen_helper_sve_ldffhds_be_zd, + gen_helper_sve_ldffsds_be_zd, + NULL, }, + { gen_helper_sve_ldffbdu_zd, + gen_helper_sve_ldffhdu_be_zd, + gen_helper_sve_ldffsdu_be_zd, + gen_helper_sve_ldffdd_be_zd, } } } } }, + { /* MTE Active */ + { /* Little-endian */ + { { { gen_helper_sve_ldbds_zsu_mte, + gen_helper_sve_ldhds_le_zsu_mte, + gen_helper_sve_ldsds_le_zsu_mte, + NULL, }, + { gen_helper_sve_ldbdu_zsu_mte, + gen_helper_sve_ldhdu_le_zsu_mte, + gen_helper_sve_ldsdu_le_zsu_mte, + gen_helper_sve_lddd_le_zsu_mte, } }, + { { gen_helper_sve_ldbds_zss_mte, + gen_helper_sve_ldhds_le_zss_mte, + gen_helper_sve_ldsds_le_zss_mte, + NULL, }, + { gen_helper_sve_ldbdu_zss_mte, + gen_helper_sve_ldhdu_le_zss_mte, + gen_helper_sve_ldsdu_le_zss_mte, + gen_helper_sve_lddd_le_zss_mte, } }, + { { gen_helper_sve_ldbds_zd_mte, + gen_helper_sve_ldhds_le_zd_mte, + gen_helper_sve_ldsds_le_zd_mte, + NULL, }, + { gen_helper_sve_ldbdu_zd_mte, + gen_helper_sve_ldhdu_le_zd_mte, + gen_helper_sve_ldsdu_le_zd_mte, + gen_helper_sve_lddd_le_zd_mte, } } }, - /* First-fault */ - { { { gen_helper_sve_ldffbds_zsu, - gen_helper_sve_ldffhds_be_zsu, - gen_helper_sve_ldffsds_be_zsu, - NULL, }, - { gen_helper_sve_ldffbdu_zsu, - gen_helper_sve_ldffhdu_be_zsu, - gen_helper_sve_ldffsdu_be_zsu, - gen_helper_sve_ldffdd_be_zsu, } }, - { { gen_helper_sve_ldffbds_zss, - gen_helper_sve_ldffhds_be_zss, - gen_helper_sve_ldffsds_be_zss, - NULL, }, - { gen_helper_sve_ldffbdu_zss, - gen_helper_sve_ldffhdu_be_zss, - gen_helper_sve_ldffsdu_be_zss, - gen_helper_sve_ldffdd_be_zss, } }, - { { gen_helper_sve_ldffbds_zd, - gen_helper_sve_ldffhds_be_zd, - gen_helper_sve_ldffsds_be_zd, - NULL, }, - { gen_helper_sve_ldffbdu_zd, - gen_helper_sve_ldffhdu_be_zd, - gen_helper_sve_ldffsdu_be_zd, - gen_helper_sve_ldffdd_be_zd, } } } }, + /* First-fault */ + { { { gen_helper_sve_ldffbds_zsu_mte, + gen_helper_sve_ldffhds_le_zsu_mte, + gen_helper_sve_ldffsds_le_zsu_mte, + NULL, }, + { gen_helper_sve_ldffbdu_zsu_mte, + gen_helper_sve_ldffhdu_le_zsu_mte, + gen_helper_sve_ldffsdu_le_zsu_mte, + gen_helper_sve_ldffdd_le_zsu_mte, } }, + { { gen_helper_sve_ldffbds_zss_mte, + gen_helper_sve_ldffhds_le_zss_mte, + gen_helper_sve_ldffsds_le_zss_mte, + NULL, }, + { gen_helper_sve_ldffbdu_zss_mte, + gen_helper_sve_ldffhdu_le_zss_mte, + gen_helper_sve_ldffsdu_le_zss_mte, + gen_helper_sve_ldffdd_le_zss_mte, } }, + { { gen_helper_sve_ldffbds_zd_mte, + gen_helper_sve_ldffhds_le_zd_mte, + gen_helper_sve_ldffsds_le_zd_mte, + NULL, }, + { gen_helper_sve_ldffbdu_zd_mte, + gen_helper_sve_ldffhdu_le_zd_mte, + gen_helper_sve_ldffsdu_le_zd_mte, + gen_helper_sve_ldffdd_le_zd_mte, } } } }, + { /* Big-endian */ + { { { gen_helper_sve_ldbds_zsu_mte, + gen_helper_sve_ldhds_be_zsu_mte, + gen_helper_sve_ldsds_be_zsu_mte, + NULL, }, + { gen_helper_sve_ldbdu_zsu_mte, + gen_helper_sve_ldhdu_be_zsu_mte, + gen_helper_sve_ldsdu_be_zsu_mte, + gen_helper_sve_lddd_be_zsu_mte, } }, + { { gen_helper_sve_ldbds_zss_mte, + gen_helper_sve_ldhds_be_zss_mte, + gen_helper_sve_ldsds_be_zss_mte, + NULL, }, + { gen_helper_sve_ldbdu_zss_mte, + gen_helper_sve_ldhdu_be_zss_mte, + gen_helper_sve_ldsdu_be_zss_mte, + gen_helper_sve_lddd_be_zss_mte, } }, + { { gen_helper_sve_ldbds_zd_mte, + gen_helper_sve_ldhds_be_zd_mte, + gen_helper_sve_ldsds_be_zd_mte, + NULL, }, + { gen_helper_sve_ldbdu_zd_mte, + gen_helper_sve_ldhdu_be_zd_mte, + gen_helper_sve_ldsdu_be_zd_mte, + gen_helper_sve_lddd_be_zd_mte, } } }, + + /* First-fault */ + { { { gen_helper_sve_ldffbds_zsu_mte, + gen_helper_sve_ldffhds_be_zsu_mte, + gen_helper_sve_ldffsds_be_zsu_mte, + NULL, }, + { gen_helper_sve_ldffbdu_zsu_mte, + gen_helper_sve_ldffhdu_be_zsu_mte, + gen_helper_sve_ldffsdu_be_zsu_mte, + gen_helper_sve_ldffdd_be_zsu_mte, } }, + { { gen_helper_sve_ldffbds_zss_mte, + gen_helper_sve_ldffhds_be_zss_mte, + gen_helper_sve_ldffsds_be_zss_mte, + NULL, }, + { gen_helper_sve_ldffbdu_zss_mte, + gen_helper_sve_ldffhdu_be_zss_mte, + gen_helper_sve_ldffsdu_be_zss_mte, + gen_helper_sve_ldffdd_be_zss_mte, } }, + { { gen_helper_sve_ldffbds_zd_mte, + gen_helper_sve_ldffhds_be_zd_mte, + gen_helper_sve_ldffsds_be_zd_mte, + NULL, }, + { gen_helper_sve_ldffbdu_zd_mte, + gen_helper_sve_ldffhdu_be_zd_mte, + gen_helper_sve_ldffsdu_be_zd_mte, + gen_helper_sve_ldffdd_be_zd_mte, } } } } }, }; static bool trans_LD1_zprz(DisasContext *s, arg_LD1_zprz *a) { gen_helper_gvec_mem_scatter *fn = NULL; - int be = s->be_data == MO_BE; + bool be = s->be_data == MO_BE; + bool mte = s->mte_active[0]; if (!sve_access_check(s)) { return true; @@ -5462,23 +5633,24 @@ static bool trans_LD1_zprz(DisasContext *s, arg_LD1_zprz *a) switch (a->esz) { case MO_32: - fn = gather_load_fn32[be][a->ff][a->xs][a->u][a->msz]; + fn = gather_load_fn32[mte][be][a->ff][a->xs][a->u][a->msz]; break; case MO_64: - fn = gather_load_fn64[be][a->ff][a->xs][a->u][a->msz]; + fn = gather_load_fn64[mte][be][a->ff][a->xs][a->u][a->msz]; break; } assert(fn != NULL); do_mem_zpz(s, a->rd, a->pg, a->rm, a->scale * a->msz, - cpu_reg_sp(s, a->rn), a->msz, fn); + cpu_reg_sp(s, a->rn), a->msz, false, fn); return true; } static bool trans_LD1_zpiz(DisasContext *s, arg_LD1_zpiz *a) { gen_helper_gvec_mem_scatter *fn = NULL; - int be = s->be_data == MO_BE; + bool be = s->be_data == MO_BE; + bool mte = s->mte_active[0]; TCGv_i64 imm; if (a->esz < a->msz || (a->esz == a->msz && !a->u)) { @@ -5490,10 +5662,10 @@ static bool trans_LD1_zpiz(DisasContext *s, arg_LD1_zpiz *a) switch (a->esz) { case MO_32: - fn = gather_load_fn32[be][a->ff][0][a->u][a->msz]; + fn = gather_load_fn32[mte][be][a->ff][0][a->u][a->msz]; break; case MO_64: - fn = gather_load_fn64[be][a->ff][2][a->u][a->msz]; + fn = gather_load_fn64[mte][be][a->ff][2][a->u][a->msz]; break; } assert(fn != NULL); @@ -5502,63 +5674,108 @@ static bool trans_LD1_zpiz(DisasContext *s, arg_LD1_zpiz *a) * by loading the immediate into the scalar parameter. */ imm = tcg_const_i64(a->imm << a->msz); - do_mem_zpz(s, a->rd, a->pg, a->rn, 0, imm, a->msz, fn); + do_mem_zpz(s, a->rd, a->pg, a->rn, 0, imm, a->msz, false, fn); tcg_temp_free_i64(imm); return true; } -/* Indexed by [be][xs][msz]. */ -static gen_helper_gvec_mem_scatter * const scatter_store_fn32[2][2][3] = { - /* Little-endian */ - { { gen_helper_sve_stbs_zsu, - gen_helper_sve_sths_le_zsu, - gen_helper_sve_stss_le_zsu, }, - { gen_helper_sve_stbs_zss, - gen_helper_sve_sths_le_zss, - gen_helper_sve_stss_le_zss, } }, - /* Big-endian */ - { { gen_helper_sve_stbs_zsu, - gen_helper_sve_sths_be_zsu, - gen_helper_sve_stss_be_zsu, }, - { gen_helper_sve_stbs_zss, - gen_helper_sve_sths_be_zss, - gen_helper_sve_stss_be_zss, } }, +/* Indexed by [mte][be][xs][msz]. */ +static gen_helper_gvec_mem_scatter * const scatter_store_fn32[2][2][2][3] = { + { /* MTE Inactive */ + { /* Little-endian */ + { gen_helper_sve_stbs_zsu, + gen_helper_sve_sths_le_zsu, + gen_helper_sve_stss_le_zsu, }, + { gen_helper_sve_stbs_zss, + gen_helper_sve_sths_le_zss, + gen_helper_sve_stss_le_zss, } }, + { /* Big-endian */ + { gen_helper_sve_stbs_zsu, + gen_helper_sve_sths_be_zsu, + gen_helper_sve_stss_be_zsu, }, + { gen_helper_sve_stbs_zss, + gen_helper_sve_sths_be_zss, + gen_helper_sve_stss_be_zss, } } }, + { /* MTE Active */ + { /* Little-endian */ + { gen_helper_sve_stbs_zsu_mte, + gen_helper_sve_sths_le_zsu_mte, + gen_helper_sve_stss_le_zsu_mte, }, + { gen_helper_sve_stbs_zss_mte, + gen_helper_sve_sths_le_zss_mte, + gen_helper_sve_stss_le_zss_mte, } }, + { /* Big-endian */ + { gen_helper_sve_stbs_zsu_mte, + gen_helper_sve_sths_be_zsu_mte, + gen_helper_sve_stss_be_zsu_mte, }, + { gen_helper_sve_stbs_zss_mte, + gen_helper_sve_sths_be_zss_mte, + gen_helper_sve_stss_be_zss_mte, } } }, }; /* Note that we overload xs=2 to indicate 64-bit offset. */ -static gen_helper_gvec_mem_scatter * const scatter_store_fn64[2][3][4] = { - /* Little-endian */ - { { gen_helper_sve_stbd_zsu, - gen_helper_sve_sthd_le_zsu, - gen_helper_sve_stsd_le_zsu, - gen_helper_sve_stdd_le_zsu, }, - { gen_helper_sve_stbd_zss, - gen_helper_sve_sthd_le_zss, - gen_helper_sve_stsd_le_zss, - gen_helper_sve_stdd_le_zss, }, - { gen_helper_sve_stbd_zd, - gen_helper_sve_sthd_le_zd, - gen_helper_sve_stsd_le_zd, - gen_helper_sve_stdd_le_zd, } }, - /* Big-endian */ - { { gen_helper_sve_stbd_zsu, - gen_helper_sve_sthd_be_zsu, - gen_helper_sve_stsd_be_zsu, - gen_helper_sve_stdd_be_zsu, }, - { gen_helper_sve_stbd_zss, - gen_helper_sve_sthd_be_zss, - gen_helper_sve_stsd_be_zss, - gen_helper_sve_stdd_be_zss, }, - { gen_helper_sve_stbd_zd, - gen_helper_sve_sthd_be_zd, - gen_helper_sve_stsd_be_zd, - gen_helper_sve_stdd_be_zd, } }, +static gen_helper_gvec_mem_scatter * const scatter_store_fn64[2][2][3][4] = { + { /* MTE Inactive */ + { /* Little-endian */ + { gen_helper_sve_stbd_zsu, + gen_helper_sve_sthd_le_zsu, + gen_helper_sve_stsd_le_zsu, + gen_helper_sve_stdd_le_zsu, }, + { gen_helper_sve_stbd_zss, + gen_helper_sve_sthd_le_zss, + gen_helper_sve_stsd_le_zss, + gen_helper_sve_stdd_le_zss, }, + { gen_helper_sve_stbd_zd, + gen_helper_sve_sthd_le_zd, + gen_helper_sve_stsd_le_zd, + gen_helper_sve_stdd_le_zd, } }, + { /* Big-endian */ + { gen_helper_sve_stbd_zsu, + gen_helper_sve_sthd_be_zsu, + gen_helper_sve_stsd_be_zsu, + gen_helper_sve_stdd_be_zsu, }, + { gen_helper_sve_stbd_zss, + gen_helper_sve_sthd_be_zss, + gen_helper_sve_stsd_be_zss, + gen_helper_sve_stdd_be_zss, }, + { gen_helper_sve_stbd_zd, + gen_helper_sve_sthd_be_zd, + gen_helper_sve_stsd_be_zd, + gen_helper_sve_stdd_be_zd, } } }, + { /* MTE Inactive */ + { /* Little-endian */ + { gen_helper_sve_stbd_zsu_mte, + gen_helper_sve_sthd_le_zsu_mte, + gen_helper_sve_stsd_le_zsu_mte, + gen_helper_sve_stdd_le_zsu_mte, }, + { gen_helper_sve_stbd_zss_mte, + gen_helper_sve_sthd_le_zss_mte, + gen_helper_sve_stsd_le_zss_mte, + gen_helper_sve_stdd_le_zss_mte, }, + { gen_helper_sve_stbd_zd_mte, + gen_helper_sve_sthd_le_zd_mte, + gen_helper_sve_stsd_le_zd_mte, + gen_helper_sve_stdd_le_zd_mte, } }, + { /* Big-endian */ + { gen_helper_sve_stbd_zsu_mte, + gen_helper_sve_sthd_be_zsu_mte, + gen_helper_sve_stsd_be_zsu_mte, + gen_helper_sve_stdd_be_zsu_mte, }, + { gen_helper_sve_stbd_zss_mte, + gen_helper_sve_sthd_be_zss_mte, + gen_helper_sve_stsd_be_zss_mte, + gen_helper_sve_stdd_be_zss_mte, }, + { gen_helper_sve_stbd_zd_mte, + gen_helper_sve_sthd_be_zd_mte, + gen_helper_sve_stsd_be_zd_mte, + gen_helper_sve_stdd_be_zd_mte, } } }, }; static bool trans_ST1_zprz(DisasContext *s, arg_ST1_zprz *a) { gen_helper_gvec_mem_scatter *fn; - int be = s->be_data == MO_BE; + bool be = s->be_data == MO_BE; + bool mte = s->mte_active[0]; if (a->esz < a->msz || (a->msz == 0 && a->scale)) { return false; @@ -5568,23 +5785,24 @@ static bool trans_ST1_zprz(DisasContext *s, arg_ST1_zprz *a) } switch (a->esz) { case MO_32: - fn = scatter_store_fn32[be][a->xs][a->msz]; + fn = scatter_store_fn32[mte][be][a->xs][a->msz]; break; case MO_64: - fn = scatter_store_fn64[be][a->xs][a->msz]; + fn = scatter_store_fn64[mte][be][a->xs][a->msz]; break; default: g_assert_not_reached(); } do_mem_zpz(s, a->rd, a->pg, a->rm, a->scale * a->msz, - cpu_reg_sp(s, a->rn), a->msz, fn); + cpu_reg_sp(s, a->rn), a->msz, true, fn); return true; } static bool trans_ST1_zpiz(DisasContext *s, arg_ST1_zpiz *a) { gen_helper_gvec_mem_scatter *fn = NULL; - int be = s->be_data == MO_BE; + bool be = s->be_data == MO_BE; + bool mte = s->mte_active[0]; TCGv_i64 imm; if (a->esz < a->msz) { @@ -5596,10 +5814,10 @@ static bool trans_ST1_zpiz(DisasContext *s, arg_ST1_zpiz *a) switch (a->esz) { case MO_32: - fn = scatter_store_fn32[be][0][a->msz]; + fn = scatter_store_fn32[mte][be][0][a->msz]; break; case MO_64: - fn = scatter_store_fn64[be][2][a->msz]; + fn = scatter_store_fn64[mte][be][2][a->msz]; break; } assert(fn != NULL); @@ -5608,7 +5826,7 @@ static bool trans_ST1_zpiz(DisasContext *s, arg_ST1_zpiz *a) * by loading the immediate into the scalar parameter. */ imm = tcg_const_i64(a->imm << a->msz); - do_mem_zpz(s, a->rd, a->pg, a->rn, 0, imm, a->msz, fn); + do_mem_zpz(s, a->rd, a->pg, a->rn, 0, imm, a->msz, true, fn); tcg_temp_free_i64(imm); return true; } From c4af8ba19b9d22aac79cab679a20b159af9d6809 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:36 -0700 Subject: [PATCH 1685/2595] target/arm: Complete TBI clearing for user-only for SVE There are a number of paths by which the TBI is still intact for user-only in the SVE helpers. Because we currently always set TBI for user-only, we do not need to pass down the actual TBI setting from above, and we can remove the top byte in the inner-most primitives, so that none are forgotten. Moreover, this keeps the "dirty" pointer around at the higher levels, where we need it for any MTE checking. Since the normal case, especially for user-only, goes through RAM, this clearing merely adds two insns per page lookup, which will be completely in the noise. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-39-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 3 +++ target/arm/sve_helper.c | 19 +++++++++++++++++-- target/arm/translate-a64.c | 5 +++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index d9876337c0..afe81e9b6c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -203,6 +203,9 @@ static void arm_cpu_reset(DeviceState *dev) * Enable TBI0 and TBI1. While the real kernel only enables TBI0, * turning on both here will produce smaller code and otherwise * make no difference to the user-level emulation. + * + * In sve_probe_page, we assume that this is set. + * Do not modify this without other changes. */ env->cp15.tcr_el[1].raw_tcr = (3ULL << 37); #else diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index ad974c2cc5..382fa82bc8 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -3966,14 +3966,16 @@ static void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \ static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \ target_ulong addr, uintptr_t ra) \ { \ - *(TYPEE *)(vd + H(reg_off)) = (TYPEM)TLB(env, addr, ra); \ + *(TYPEE *)(vd + H(reg_off)) = \ + (TYPEM)TLB(env, useronly_clean_ptr(addr), ra); \ } #define DO_ST_TLB(NAME, H, TYPEE, TYPEM, TLB) \ static void sve_##NAME##_tlb(CPUARMState *env, void *vd, intptr_t reg_off, \ target_ulong addr, uintptr_t ra) \ { \ - TLB(env, addr, (TYPEM)*(TYPEE *)(vd + H(reg_off)), ra); \ + TLB(env, useronly_clean_ptr(addr), \ + (TYPEM)*(TYPEE *)(vd + H(reg_off)), ra); \ } #define DO_LD_PRIM_1(NAME, H, TE, TM) \ @@ -4091,6 +4093,19 @@ static bool sve_probe_page(SVEHostPage *info, bool nofault, int flags; addr += mem_off; + + /* + * User-only currently always issues with TBI. See the comment + * above useronly_clean_ptr. Usually we clean this top byte away + * during translation, but we can't do that for e.g. vector + imm + * addressing modes. + * + * We currently always enable TBI for user-only, and do not provide + * a way to turn it off. So clean the pointer unconditionally here, + * rather than look it up here, or pass it down from above. + */ + addr = useronly_clean_ptr(addr); + flags = probe_access_flags(env, addr, access_type, mmu_idx, nofault, &info->host, retaddr); info->flags = flags; diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index e46c4a49e0..c20af6ee9d 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14634,6 +14634,11 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->features = env->features; dc->dcz_blocksize = arm_cpu->dcz_blocksize; +#ifdef CONFIG_USER_ONLY + /* In sve_probe_page, we assume TBI is enabled. */ + tcg_debug_assert(dc->tbid & 1); +#endif + /* Single step state. The code-generation logic here is: * SS_ACTIVE == 0: * generate code with no special handling for single-stepping (except From eb821168db798302bd124a3b000cebc23bd0a395 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:37 -0700 Subject: [PATCH 1686/2595] target/arm: Implement data cache set allocation tags This is DC GVA and DC GZVA, and the tag check for DC ZVA. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-40-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 4 +++- target/arm/helper.c | 16 ++++++++++++++++ target/arm/translate-a64.c | 39 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 3bf0518ca4..513c38970c 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2360,7 +2360,9 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) #define ARM_CP_NZCV (ARM_CP_SPECIAL | 0x0300) #define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | 0x0400) #define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | 0x0500) -#define ARM_LAST_SPECIAL ARM_CP_DC_ZVA +#define ARM_CP_DC_GVA (ARM_CP_SPECIAL | 0x0600) +#define ARM_CP_DC_GZVA (ARM_CP_SPECIAL | 0x0700) +#define ARM_LAST_SPECIAL ARM_CP_DC_GZVA #define ARM_CP_FPU 0x1000 #define ARM_CP_SVE 0x2000 #define ARM_CP_NO_GDB 0x4000 diff --git a/target/arm/helper.c b/target/arm/helper.c index 44a3f9fb48..23cf44fcf4 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6998,6 +6998,22 @@ static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 5, .type = ARM_CP_NOP, .access = PL0_W, .accessfn = aa64_cacheop_poc_access }, + { .name = "DC_GVA", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 4, .opc2 = 3, + .access = PL0_W, .type = ARM_CP_DC_GVA, +#ifndef CONFIG_USER_ONLY + /* Avoid overhead of an access check that always passes in user-mode */ + .accessfn = aa64_zva_access, +#endif + }, + { .name = "DC_GZVA", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 4, .opc2 = 4, + .access = PL0_W, .type = ARM_CP_DC_GZVA, +#ifndef CONFIG_USER_ONLY + /* Avoid overhead of an access check that always passes in user-mode */ + .accessfn = aa64_zva_access, +#endif + }, REGINFO_SENTINEL }; diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index c20af6ee9d..73d753f11f 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1874,6 +1874,45 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, } gen_helper_dc_zva(cpu_env, tcg_rt); return; + case ARM_CP_DC_GVA: + { + TCGv_i64 clean_addr, tag; + + /* + * DC_GVA, like DC_ZVA, requires that we supply the original + * pointer for an invalid page. Probe that address first. + */ + tcg_rt = cpu_reg(s, rt); + clean_addr = clean_data_tbi(s, tcg_rt); + gen_probe_access(s, clean_addr, MMU_DATA_STORE, MO_8); + + if (s->ata) { + /* Extract the tag from the register to match STZGM. */ + tag = tcg_temp_new_i64(); + tcg_gen_shri_i64(tag, tcg_rt, 56); + gen_helper_stzgm_tags(cpu_env, clean_addr, tag); + tcg_temp_free_i64(tag); + } + } + return; + case ARM_CP_DC_GZVA: + { + TCGv_i64 clean_addr, tag; + + /* For DC_GZVA, we can rely on DC_ZVA for the proper fault. */ + tcg_rt = cpu_reg(s, rt); + clean_addr = clean_data_tbi(s, tcg_rt); + gen_helper_dc_zva(cpu_env, clean_addr); + + if (s->ata) { + /* Extract the tag from the register to match STZGM. */ + tag = tcg_temp_new_i64(); + tcg_gen_shri_i64(tag, tcg_rt, 56); + gen_helper_stzgm_tags(cpu_env, clean_addr, tag); + tcg_temp_free_i64(tag); + } + } + return; default: break; } From 34669338bd9d66255fceaa84c314251ca49ca8d5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:38 -0700 Subject: [PATCH 1687/2595] target/arm: Set PSTATE.TCO on exception entry D1.10 specifies that exception handlers begin with tag checks overridden. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-41-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index 23cf44fcf4..d220612a20 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9704,6 +9704,9 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) break; } } + if (cpu_isar_feature(aa64_mte, cpu)) { + new_mode |= PSTATE_TCO; + } pstate_write(env, PSTATE_DAIF | new_mode); env->aarch64 = 1; From 7e98e21c09871cddc20946c8f3f3595e93154ecb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:39 -0700 Subject: [PATCH 1688/2595] target/arm: Always pass cacheattr to get_phys_addr We need to check the memattr of a page in order to determine whether it is Tagged for MTE. Between Stage1 and Stage2, this becomes simpler if we always collect this data, instead of occasionally being presented with NULL. Use the nonnull attribute to allow the compiler to check that all pointer arguments are non-null. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-42-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 60 ++++++++++++++++++++--------------------- target/arm/internals.h | 3 ++- target/arm/m_helper.c | 11 +++++--- target/arm/tlb_helper.c | 4 ++- 4 files changed, 42 insertions(+), 36 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index d220612a20..2072db2f92 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -44,7 +44,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, bool s1_is_el0, hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, target_ulong *page_size_ptr, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs); + ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) + __attribute__((nonnull)); #endif static void switch_mode(CPUARMState *env, int mode); @@ -11101,19 +11102,16 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, arm_tlb_bti_gp(txattrs) = true; } - if (cacheattrs != NULL) { - if (mmu_idx == ARMMMUIdx_Stage2) { - cacheattrs->attrs = convert_stage2_attrs(env, - extract32(attrs, 0, 4)); - } else { - /* Index into MAIR registers for cache attributes */ - uint8_t attrindx = extract32(attrs, 0, 3); - uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)]; - assert(attrindx <= 7); - cacheattrs->attrs = extract64(mair, attrindx * 8, 8); - } - cacheattrs->shareability = extract32(attrs, 6, 2); + if (mmu_idx == ARMMMUIdx_Stage2) { + cacheattrs->attrs = convert_stage2_attrs(env, extract32(attrs, 0, 4)); + } else { + /* Index into MAIR registers for cache attributes */ + uint8_t attrindx = extract32(attrs, 0, 3); + uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)]; + assert(attrindx <= 7); + cacheattrs->attrs = extract64(mair, attrindx * 8, 8); } + cacheattrs->shareability = extract32(attrs, 6, 2); *phys_ptr = descaddr; *page_size_ptr = page_size; @@ -11948,28 +11946,29 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, ret = get_phys_addr_lpae(env, ipa, access_type, ARMMMUIdx_Stage2, mmu_idx == ARMMMUIdx_E10_0, phys_ptr, attrs, &s2_prot, - page_size, fi, - cacheattrs != NULL ? &cacheattrs2 : NULL); + page_size, fi, &cacheattrs2); fi->s2addr = ipa; /* Combine the S1 and S2 perms. */ *prot &= s2_prot; - /* Combine the S1 and S2 cache attributes, if needed */ - if (!ret && cacheattrs != NULL) { - if (env->cp15.hcr_el2 & HCR_DC) { - /* - * HCR.DC forces the first stage attributes to - * Normal Non-Shareable, - * Inner Write-Back Read-Allocate Write-Allocate, - * Outer Write-Back Read-Allocate Write-Allocate. - */ - cacheattrs->attrs = 0xff; - cacheattrs->shareability = 0; - } - *cacheattrs = combine_cacheattrs(*cacheattrs, cacheattrs2); + /* If S2 fails, return early. */ + if (ret) { + return ret; } - return ret; + /* Combine the S1 and S2 cache attributes. */ + if (env->cp15.hcr_el2 & HCR_DC) { + /* + * HCR.DC forces the first stage attributes to + * Normal Non-Shareable, + * Inner Write-Back Read-Allocate Write-Allocate, + * Outer Write-Back Read-Allocate Write-Allocate. + */ + cacheattrs->attrs = 0xff; + cacheattrs->shareability = 0; + } + *cacheattrs = combine_cacheattrs(*cacheattrs, cacheattrs2); + return 0; } else { /* * For non-EL2 CPUs a stage1+stage2 translation is just stage 1. @@ -12094,11 +12093,12 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, bool ret; ARMMMUFaultInfo fi = {}; ARMMMUIdx mmu_idx = arm_mmu_idx(env); + ARMCacheAttrs cacheattrs = {}; *attrs = (MemTxAttrs) {}; ret = get_phys_addr(env, addr, 0, mmu_idx, &phys_addr, - attrs, &prot, &page_size, &fi, NULL); + attrs, &prot, &page_size, &fi, &cacheattrs); if (ret) { return -1; diff --git a/target/arm/internals.h b/target/arm/internals.h index 3306c4f829..ae99725d2b 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1294,7 +1294,8 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, target_ulong *page_size, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs); + ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) + __attribute__((nonnull)); void arm_log_exception(int idx); diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 5e8a795d20..036454234c 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -187,12 +187,13 @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value, hwaddr physaddr; int prot; ARMMMUFaultInfo fi = {}; + ARMCacheAttrs cacheattrs = {}; bool secure = mmu_idx & ARM_MMU_IDX_M_S; int exc; bool exc_secure; if (get_phys_addr(env, addr, MMU_DATA_STORE, mmu_idx, &physaddr, - &attrs, &prot, &page_size, &fi, NULL)) { + &attrs, &prot, &page_size, &fi, &cacheattrs)) { /* MPU/SAU lookup failed */ if (fi.type == ARMFault_QEMU_SFault) { if (mode == STACK_LAZYFP) { @@ -279,13 +280,14 @@ static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr, hwaddr physaddr; int prot; ARMMMUFaultInfo fi = {}; + ARMCacheAttrs cacheattrs = {}; bool secure = mmu_idx & ARM_MMU_IDX_M_S; int exc; bool exc_secure; uint32_t value; if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &physaddr, - &attrs, &prot, &page_size, &fi, NULL)) { + &attrs, &prot, &page_size, &fi, &cacheattrs)) { /* MPU/SAU lookup failed */ if (fi.type == ARMFault_QEMU_SFault) { qemu_log_mask(CPU_LOG_INT, @@ -1928,6 +1930,7 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, V8M_SAttributes sattrs = {}; MemTxAttrs attrs = {}; ARMMMUFaultInfo fi = {}; + ARMCacheAttrs cacheattrs = {}; MemTxResult txres; target_ulong page_size; hwaddr physaddr; @@ -1945,8 +1948,8 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, "...really SecureFault with SFSR.INVEP\n"); return false; } - if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx, - &physaddr, &attrs, &prot, &page_size, &fi, NULL)) { + if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx, &physaddr, + &attrs, &prot, &page_size, &fi, &cacheattrs)) { /* the MPU lookup failed */ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK; armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure); diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c index 522a6442a4..89d90465a3 100644 --- a/target/arm/tlb_helper.c +++ b/target/arm/tlb_helper.c @@ -166,6 +166,7 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, int prot, ret; MemTxAttrs attrs = {}; ARMMMUFaultInfo fi = {}; + ARMCacheAttrs cacheattrs = {}; /* * Walk the page table and (if the mapping exists) add the page @@ -175,7 +176,8 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, */ ret = get_phys_addr(&cpu->env, address, access_type, core_to_arm_mmu_idx(&cpu->env, mmu_idx), - &phys_addr, &attrs, &prot, &page_size, &fi, NULL); + &phys_addr, &attrs, &prot, &page_size, + &fi, &cacheattrs); if (likely(!ret)) { /* * Map a single [sub]page. Regions smaller than our declared From 337a03f07ff0f9e6295662f4094e03a045b60bdc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:40 -0700 Subject: [PATCH 1689/2595] target/arm: Cache the Tagged bit for a page in MemTxAttrs This "bit" is a particular value of the page's MemAttr. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-43-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 48 ++++++++++++++++++++++++++++++++++++++--- target/arm/tlb_helper.c | 5 +++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 2072db2f92..dc9c29f998 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11834,9 +11834,19 @@ static uint8_t combine_cacheattr_nibble(uint8_t s1, uint8_t s2) */ static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2) { - uint8_t s1lo = extract32(s1.attrs, 0, 4), s2lo = extract32(s2.attrs, 0, 4); - uint8_t s1hi = extract32(s1.attrs, 4, 4), s2hi = extract32(s2.attrs, 4, 4); + uint8_t s1lo, s2lo, s1hi, s2hi; ARMCacheAttrs ret; + bool tagged = false; + + if (s1.attrs == 0xf0) { + tagged = true; + s1.attrs = 0xff; + } + + s1lo = extract32(s1.attrs, 0, 4); + s2lo = extract32(s2.attrs, 0, 4); + s1hi = extract32(s1.attrs, 4, 4); + s2hi = extract32(s2.attrs, 4, 4); /* Combine shareability attributes (table D4-43) */ if (s1.shareability == 2 || s2.shareability == 2) { @@ -11884,6 +11894,11 @@ static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2) } } + /* TODO: CombineS1S2Desc does not consider transient, only WB, RWA. */ + if (tagged && ret.attrs == 0xff) { + ret.attrs = 0xf0; + } + return ret; } @@ -11963,8 +11978,11 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, * Normal Non-Shareable, * Inner Write-Back Read-Allocate Write-Allocate, * Outer Write-Back Read-Allocate Write-Allocate. + * Do not overwrite Tagged within attrs. */ - cacheattrs->attrs = 0xff; + if (cacheattrs->attrs != 0xf0) { + cacheattrs->attrs = 0xff; + } cacheattrs->shareability = 0; } *cacheattrs = combine_cacheattrs(*cacheattrs, cacheattrs2); @@ -12029,6 +12047,9 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, /* Definitely a real MMU, not an MPU */ if (regime_translation_disabled(env, mmu_idx)) { + uint64_t hcr; + uint8_t memattr; + /* * MMU disabled. S1 addresses within aa64 translation regimes are * still checked for bounds -- see AArch64.TranslateAddressS1Off. @@ -12066,6 +12087,27 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, *phys_ptr = address; *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; *page_size = TARGET_PAGE_SIZE; + + /* Fill in cacheattr a-la AArch64.TranslateAddressS1Off. */ + hcr = arm_hcr_el2_eff(env); + cacheattrs->shareability = 0; + if (hcr & HCR_DC) { + if (hcr & HCR_DCT) { + memattr = 0xf0; /* Tagged, Normal, WB, RWA */ + } else { + memattr = 0xff; /* Normal, WB, RWA */ + } + } else if (access_type == MMU_INST_FETCH) { + if (regime_sctlr(env, mmu_idx) & SCTLR_I) { + memattr = 0xee; /* Normal, WT, RA, NT */ + } else { + memattr = 0x44; /* Normal, NC, No */ + } + cacheattrs->shareability = 2; /* outer sharable */ + } else { + memattr = 0x00; /* Device, nGnRnE */ + } + cacheattrs->attrs = memattr; return 0; } diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c index 89d90465a3..b35dc8a011 100644 --- a/target/arm/tlb_helper.c +++ b/target/arm/tlb_helper.c @@ -188,6 +188,11 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, phys_addr &= TARGET_PAGE_MASK; address &= TARGET_PAGE_MASK; } + /* Notice and record tagged memory. */ + if (cpu_isar_feature(aa64_mte, cpu) && cacheattrs.attrs == 0xf0) { + arm_tlb_mte_tagged(&attrs) = true; + } + tlb_set_page_with_attrs(cs, address, phys_addr, attrs, prot, mmu_idx, page_size); return true; From 8bce44a2f6beb388a3f157652b46e99929839a96 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:41 -0700 Subject: [PATCH 1690/2595] target/arm: Create tagged ram when MTE is enabled Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20200626033144.790098-44-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- hw/arm/virt.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++-- target/arm/cpu.c | 52 +++++++++++++++++++++++++++++++++++++++++---- target/arm/cpu.h | 6 ++++++ 3 files changed, 107 insertions(+), 6 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 402c362c14..22ce6d6199 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1390,8 +1390,19 @@ static void create_platform_bus(VirtMachineState *vms) sysbus_mmio_get_region(s, 0)); } +static void create_tag_ram(MemoryRegion *tag_sysmem, + hwaddr base, hwaddr size, + const char *name) +{ + MemoryRegion *tagram = g_new(MemoryRegion, 1); + + memory_region_init_ram(tagram, NULL, name, size / 32, &error_fatal); + memory_region_add_subregion(tag_sysmem, base / 32, tagram); +} + static void create_secure_ram(VirtMachineState *vms, - MemoryRegion *secure_sysmem) + MemoryRegion *secure_sysmem, + MemoryRegion *secure_tag_sysmem) { MemoryRegion *secram = g_new(MemoryRegion, 1); char *nodename; @@ -1409,6 +1420,10 @@ static void create_secure_ram(VirtMachineState *vms, qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled"); qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay"); + if (secure_tag_sysmem) { + create_tag_ram(secure_tag_sysmem, base, size, "mach-virt.secure-tag"); + } + g_free(nodename); } @@ -1665,6 +1680,8 @@ static void machvirt_init(MachineState *machine) const CPUArchIdList *possible_cpus; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *secure_sysmem = NULL; + MemoryRegion *tag_sysmem = NULL; + MemoryRegion *secure_tag_sysmem = NULL; int n, virt_max_cpus; bool firmware_loaded; bool aarch64 = true; @@ -1819,6 +1836,35 @@ static void machvirt_init(MachineState *machine) "secure-memory", &error_abort); } + /* + * The cpu adds the property if and only if MemTag is supported. + * If it is, we must allocate the ram to back that up. + */ + if (object_property_find(cpuobj, "tag-memory", NULL)) { + if (!tag_sysmem) { + tag_sysmem = g_new(MemoryRegion, 1); + memory_region_init(tag_sysmem, OBJECT(machine), + "tag-memory", UINT64_MAX / 32); + + if (vms->secure) { + secure_tag_sysmem = g_new(MemoryRegion, 1); + memory_region_init(secure_tag_sysmem, OBJECT(machine), + "secure-tag-memory", UINT64_MAX / 32); + + /* As with ram, secure-tag takes precedence over tag. */ + memory_region_add_subregion_overlap(secure_tag_sysmem, 0, + tag_sysmem, -1); + } + } + + object_property_set_link(cpuobj, OBJECT(tag_sysmem), + "tag-memory", &error_abort); + if (vms->secure) { + object_property_set_link(cpuobj, OBJECT(secure_tag_sysmem), + "secure-tag-memory", &error_abort); + } + } + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); object_unref(cpuobj); } @@ -1857,10 +1903,15 @@ static void machvirt_init(MachineState *machine) create_uart(vms, VIRT_UART, sysmem, serial_hd(0)); if (vms->secure) { - create_secure_ram(vms, secure_sysmem); + create_secure_ram(vms, secure_sysmem, secure_tag_sysmem); create_uart(vms, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); } + if (tag_sysmem) { + create_tag_ram(tag_sysmem, vms->memmap[VIRT_MEM].base, + machine->ram_size, "mach-virt.tag"); + } + vms->highmem_ecam &= vms->highmem && (!firmware_loaded || aarch64); create_rtc(vms); diff --git a/target/arm/cpu.c b/target/arm/cpu.c index afe81e9b6c..5050e1843a 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1252,6 +1252,25 @@ void arm_cpu_post_init(Object *obj) if (kvm_enabled()) { kvm_arm_add_vcpu_properties(obj); } + +#ifndef CONFIG_USER_ONLY + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && + cpu_isar_feature(aa64_mte, cpu)) { + object_property_add_link(obj, "tag-memory", + TYPE_MEMORY_REGION, + (Object **)&cpu->tag_memory, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + + if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) { + object_property_add_link(obj, "secure-tag-memory", + TYPE_MEMORY_REGION, + (Object **)&cpu->secure_tag_memory, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + } + } +#endif } static void arm_cpu_finalizefn(Object *obj) @@ -1741,18 +1760,43 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) #ifndef CONFIG_USER_ONLY MachineState *ms = MACHINE(qdev_get_machine()); unsigned int smp_cpus = ms->smp.cpus; + bool has_secure = cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY); - if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) { - cs->num_ases = 2; + /* + * We must set cs->num_ases to the final value before + * the first call to cpu_address_space_init. + */ + if (cpu->tag_memory != NULL) { + cs->num_ases = 3 + has_secure; + } else { + cs->num_ases = 1 + has_secure; + } + if (has_secure) { if (!cpu->secure_memory) { cpu->secure_memory = cs->memory; } cpu_address_space_init(cs, ARMASIdx_S, "cpu-secure-memory", cpu->secure_memory); - } else { - cs->num_ases = 1; } + + if (cpu->tag_memory != NULL) { + cpu_address_space_init(cs, ARMASIdx_TagNS, "cpu-tag-memory", + cpu->tag_memory); + if (has_secure) { + cpu_address_space_init(cs, ARMASIdx_TagS, "cpu-tag-memory", + cpu->secure_tag_memory); + } + } else if (cpu_isar_feature(aa64_mte, cpu)) { + /* + * Since there is no tag memory, we can't meaningfully support MTE + * to its fullest. To avoid problems later, when we would come to + * use the tag memory, downgrade support to insns only. + */ + cpu->isar.id_aa64pfr1 = + FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 1); + } + cpu_address_space_init(cs, ARMASIdx_NS, "cpu-memory", cs->memory); /* No core_count specified, default to smp_cpus. */ diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 513c38970c..cf99dcca9f 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -792,6 +792,10 @@ struct ARMCPU { /* MemoryRegion to use for secure physical accesses */ MemoryRegion *secure_memory; + /* MemoryRegion to use for allocation tag accesses */ + MemoryRegion *tag_memory; + MemoryRegion *secure_tag_memory; + /* For v8M, pointer to the IDAU interface provided by board/SoC */ Object *idau; @@ -2985,6 +2989,8 @@ typedef enum ARMMMUIdxBit { typedef enum ARMASIdx { ARMASIdx_NS = 0, ARMASIdx_S = 1, + ARMASIdx_TagNS = 2, + ARMASIdx_TagS = 3, } ARMASIdx; /* Return the Exception Level targeted by debug exceptions. */ From e4d5bf4fbd5abfc3727e711eda64a583cab4d637 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:42 -0700 Subject: [PATCH 1691/2595] target/arm: Add allocation tag storage for system mode Look up the physical address for the given virtual address, convert that to a tag physical address, and finally return the host address that backs it. Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-45-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/mte_helper.c | 131 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 4f9bd3add3..5ea57d487a 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -21,6 +21,7 @@ #include "cpu.h" #include "internals.h" #include "exec/exec-all.h" +#include "exec/ram_addr.h" #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" @@ -74,8 +75,138 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, int ptr_size, MMUAccessType tag_access, int tag_size, uintptr_t ra) { +#ifdef CONFIG_USER_ONLY /* Tag storage not implemented. */ return NULL; +#else + uintptr_t index; + CPUIOTLBEntry *iotlbentry; + int in_page, flags; + ram_addr_t ptr_ra; + hwaddr ptr_paddr, tag_paddr, xlat; + MemoryRegion *mr; + ARMASIdx tag_asi; + AddressSpace *tag_as; + void *host; + + /* + * Probe the first byte of the virtual address. This raises an + * exception for inaccessible pages, and resolves the virtual address + * into the softmmu tlb. + * + * When RA == 0, this is for mte_probe1. The page is expected to be + * valid. Indicate to probe_access_flags no-fault, then assert that + * we received a valid page. + */ + flags = probe_access_flags(env, ptr, ptr_access, ptr_mmu_idx, + ra == 0, &host, ra); + assert(!(flags & TLB_INVALID_MASK)); + + /* + * Find the iotlbentry for ptr. This *must* be present in the TLB + * because we just found the mapping. + * TODO: Perhaps there should be a cputlb helper that returns a + * matching tlb entry + iotlb entry. + */ + index = tlb_index(env, ptr_mmu_idx, ptr); +# ifdef CONFIG_DEBUG_TCG + { + CPUTLBEntry *entry = tlb_entry(env, ptr_mmu_idx, ptr); + target_ulong comparator = (ptr_access == MMU_DATA_LOAD + ? entry->addr_read + : tlb_addr_write(entry)); + g_assert(tlb_hit(comparator, ptr)); + } +# endif + iotlbentry = &env_tlb(env)->d[ptr_mmu_idx].iotlb[index]; + + /* If the virtual page MemAttr != Tagged, access unchecked. */ + if (!arm_tlb_mte_tagged(&iotlbentry->attrs)) { + return NULL; + } + + /* + * If not backed by host ram, there is no tag storage: access unchecked. + * This is probably a guest os bug though, so log it. + */ + if (unlikely(flags & TLB_MMIO)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Page @ 0x%" PRIx64 " indicates Tagged Normal memory " + "but is not backed by host ram\n", ptr); + return NULL; + } + + /* + * The Normal memory access can extend to the next page. E.g. a single + * 8-byte access to the last byte of a page will check only the last + * tag on the first page. + * Any page access exception has priority over tag check exception. + */ + in_page = -(ptr | TARGET_PAGE_MASK); + if (unlikely(ptr_size > in_page)) { + void *ignore; + flags |= probe_access_flags(env, ptr + in_page, ptr_access, + ptr_mmu_idx, ra == 0, &ignore, ra); + assert(!(flags & TLB_INVALID_MASK)); + } + + /* Any debug exception has priority over a tag check exception. */ + if (unlikely(flags & TLB_WATCHPOINT)) { + int wp = ptr_access == MMU_DATA_LOAD ? BP_MEM_READ : BP_MEM_WRITE; + assert(ra != 0); + cpu_check_watchpoint(env_cpu(env), ptr, ptr_size, + iotlbentry->attrs, wp, ra); + } + + /* + * Find the physical address within the normal mem space. + * The memory region lookup must succeed because TLB_MMIO was + * not set in the cputlb lookup above. + */ + mr = memory_region_from_host(host, &ptr_ra); + tcg_debug_assert(mr != NULL); + tcg_debug_assert(memory_region_is_ram(mr)); + ptr_paddr = ptr_ra; + do { + ptr_paddr += mr->addr; + mr = mr->container; + } while (mr); + + /* Convert to the physical address in tag space. */ + tag_paddr = ptr_paddr >> (LOG2_TAG_GRANULE + 1); + + /* Look up the address in tag space. */ + tag_asi = iotlbentry->attrs.secure ? ARMASIdx_TagS : ARMASIdx_TagNS; + tag_as = cpu_get_address_space(env_cpu(env), tag_asi); + mr = address_space_translate(tag_as, tag_paddr, &xlat, NULL, + tag_access == MMU_DATA_STORE, + iotlbentry->attrs); + + /* + * Note that @mr will never be NULL. If there is nothing in the address + * space at @tag_paddr, the translation will return the unallocated memory + * region. For our purposes, the result must be ram. + */ + if (unlikely(!memory_region_is_ram(mr))) { + /* ??? Failure is a board configuration error. */ + qemu_log_mask(LOG_UNIMP, + "Tag Memory @ 0x%" HWADDR_PRIx " not found for " + "Normal Memory @ 0x%" HWADDR_PRIx "\n", + tag_paddr, ptr_paddr); + return NULL; + } + + /* + * Ensure the tag memory is dirty on write, for migration. + * Tag memory can never contain code or display memory (vga). + */ + if (tag_access == MMU_DATA_STORE) { + ram_addr_t tag_ra = memory_region_get_ram_addr(mr) + xlat; + cpu_physical_memory_set_dirty_flag(tag_ra, DIRTY_MEMORY_MIGRATION); + } + + return memory_region_get_ram_ptr(mr) + xlat; +#endif } uint64_t HELPER(irg)(CPUARMState *env, uint64_t rn, uint64_t rm) From c7459633baa71d1781fde4a245d6ec9ce2f008cf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 25 Jun 2020 20:31:43 -0700 Subject: [PATCH 1692/2595] target/arm: Enable MTE We now implement all of the components of MTE, without actually supporting any tagged memory. All MTE instructions will work, trivially, so we can enable support. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200626033144.790098-46-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu64.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index a0c1d8894b..a2f4733eed 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -654,6 +654,11 @@ static void aarch64_max_initfn(Object *obj) t = cpu->isar.id_aa64pfr1; t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); + /* + * Begin with full support for MTE; will be downgraded to MTE=1 + * during realize if the board provides no tag memory. + */ + t = FIELD_DP64(t, ID_AA64PFR1, MTE, 2); cpu->isar.id_aa64pfr1 = t; t = cpu->isar.id_aa64mmfr1; From 5f509751f711b54717c1be03d55d096015b1712b Mon Sep 17 00:00:00 2001 From: Jingqi Liu Date: Wed, 29 Apr 2020 16:50:10 +0800 Subject: [PATCH 1693/2595] docs/nvdimm: add description of alignment requirement of device dax For device dax (e.g., /dev/dax0.0), the NUM of 'align=NUM' option needs to match the alignment requirement of the device dax. It must be larger than or equal to the 'align' of device dax. Reviewed-by: Joao Martins Signed-off-by: Jingqi Liu Message-Id: <20200429085011.63752-3-jingqi.liu@intel.com> Signed-off-by: Paolo Bonzini --- docs/nvdimm.txt | 10 ++++++++++ exec.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/nvdimm.txt b/docs/nvdimm.txt index 362e99109e..c2c6e441b3 100644 --- a/docs/nvdimm.txt +++ b/docs/nvdimm.txt @@ -132,6 +132,16 @@ address to the page size (getpagesize(2)) by default. However, some types of backends may require an alignment different than the page size. In that case, QEMU v2.12.0 and later provide 'align' option to memory-backend-file to allow users to specify the proper alignment. +For device dax (e.g., /dev/dax0.0), this alignment needs to match the +alignment requirement of the device dax. The NUM of 'align=NUM' option +must be larger than or equal to the 'align' of device dax. +We can use one of the following commands to show the 'align' of device dax. + + ndctl list -X + daxctl list -R + +In order to get the proper 'align' of device dax, you need to install +the library 'libdaxctl'. For example, device dax require the 2 MB alignment, so we can use following QEMU command line options to use it (/dev/dax0.0) as the diff --git a/exec.c b/exec.c index c5ab59ec44..21926dc9c7 100644 --- a/exec.c +++ b/exec.c @@ -2379,7 +2379,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, file_align = get_file_align(fd); if (file_align > 0 && mr && file_align > mr->align) { error_setg(errp, "backing store align 0x%" PRIx64 - " is larger than 'align' option 0x" PRIx64, + " is larger than 'align' option 0x%" PRIx64, file_align, mr->align); return NULL; } From ee760ac80ac1f130138e8eb4eba263a4d48ace51 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 15 Jun 2020 09:26:29 +0200 Subject: [PATCH 1694/2595] hw/scsi/megasas: Fix possible out-of-bounds array access in tracepoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some tracepoints in megasas.c use a guest-controlled value as an index into the mfi_frame_desc[] array. Thus a malicious guest could cause an out-of-bounds error here. Fortunately, the impact is very low since this can only happen when the corresponding tracepoints have been enabled before, but the problem should be fixed anyway with a proper check. Buglink: https://bugs.launchpad.net/qemu/+bug/1882065 Signed-off-by: Thomas Huth Message-Id: <20200615072629.32321-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 634af0bbb8..5cfd1bf22e 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -54,10 +54,6 @@ #define MEGASAS_FLAG_USE_QUEUE64 1 #define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64) -static const char *mfi_frame_desc[] = { - "MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI", - "MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop"}; - typedef struct MegasasCmd { uint32_t index; uint16_t flags; @@ -183,6 +179,20 @@ static void megasas_frame_set_scsi_status(MegasasState *s, stb_pci_dma(pci, frame + offsetof(struct mfi_frame_header, scsi_status), v); } +static inline const char *mfi_frame_desc(unsigned int cmd) +{ + static const char *mfi_frame_descs[] = { + "MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI", + "MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop" + }; + + if (cmd < ARRAY_SIZE(mfi_frame_descs)) { + return mfi_frame_descs[cmd]; + } + + return "Unknown"; +} + /* * Context is considered opaque, but the HBA firmware is running * in little endian mode. So convert it to little endian, too. @@ -1670,25 +1680,25 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd, if (is_logical) { if (target_id >= MFI_MAX_LD || lun_id != 0) { trace_megasas_scsi_target_not_present( - mfi_frame_desc[frame_cmd], is_logical, target_id, lun_id); + mfi_frame_desc(frame_cmd), is_logical, target_id, lun_id); return MFI_STAT_DEVICE_NOT_FOUND; } } sdev = scsi_device_find(&s->bus, 0, target_id, lun_id); cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len); - trace_megasas_handle_scsi(mfi_frame_desc[frame_cmd], is_logical, + trace_megasas_handle_scsi(mfi_frame_desc(frame_cmd), is_logical, target_id, lun_id, sdev, cmd->iov_size); if (!sdev || (megasas_is_jbod(s) && is_logical)) { trace_megasas_scsi_target_not_present( - mfi_frame_desc[frame_cmd], is_logical, target_id, lun_id); + mfi_frame_desc(frame_cmd), is_logical, target_id, lun_id); return MFI_STAT_DEVICE_NOT_FOUND; } if (cdb_len > 16) { trace_megasas_scsi_invalid_cdb_len( - mfi_frame_desc[frame_cmd], is_logical, + mfi_frame_desc(frame_cmd), is_logical, target_id, lun_id, cdb_len); megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE)); cmd->frame->header.scsi_status = CHECK_CONDITION; @@ -1706,7 +1716,7 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd, cmd->req = scsi_req_new(sdev, cmd->index, lun_id, cdb, cmd); if (!cmd->req) { trace_megasas_scsi_req_alloc_failed( - mfi_frame_desc[frame_cmd], target_id, lun_id); + mfi_frame_desc(frame_cmd), target_id, lun_id); megasas_write_sense(cmd, SENSE_CODE(NO_SENSE)); cmd->frame->header.scsi_status = BUSY; s->event_count++; @@ -1751,17 +1761,17 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd) } trace_megasas_handle_io(cmd->index, - mfi_frame_desc[frame_cmd], target_id, lun_id, + mfi_frame_desc(frame_cmd), target_id, lun_id, (unsigned long)lba_start, (unsigned long)lba_count); if (!sdev) { trace_megasas_io_target_not_present(cmd->index, - mfi_frame_desc[frame_cmd], target_id, lun_id); + mfi_frame_desc(frame_cmd), target_id, lun_id); return MFI_STAT_DEVICE_NOT_FOUND; } if (cdb_len > 16) { trace_megasas_scsi_invalid_cdb_len( - mfi_frame_desc[frame_cmd], 1, target_id, lun_id, cdb_len); + mfi_frame_desc(frame_cmd), 1, target_id, lun_id, cdb_len); megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE)); cmd->frame->header.scsi_status = CHECK_CONDITION; s->event_count++; @@ -1781,7 +1791,7 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd) lun_id, cdb, cmd); if (!cmd->req) { trace_megasas_scsi_req_alloc_failed( - mfi_frame_desc[frame_cmd], target_id, lun_id); + mfi_frame_desc(frame_cmd), target_id, lun_id); megasas_write_sense(cmd, SENSE_CODE(NO_SENSE)); cmd->frame->header.scsi_status = BUSY; s->event_count++; From c13dba2c77b2f2066eeb04edd9ba72a09a668ea9 Mon Sep 17 00:00:00 2001 From: Liao Pingfang Date: Tue, 9 Jun 2020 08:47:50 +0800 Subject: [PATCH 1695/2595] Makefile: Install qemu-[qmp/ga]-ref.* into the directory "interop" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need install qemu-[qmp/ga]-ref.* files into the subdirectory of qemu docs: interop. If we visit the following address and click the link to qemu-qmp-ref.html: https://www.qemu.org/docs/master/interop/bitmaps.html#basic-qmp-usage It will report following error: " Not Found The requested URL /docs/master/interop/qemu-qmp-ref.html was not found on this server. " Signed-off-by: Liao Pingfang Reviewed-by: Philippe Mathieu-Daudé Message-Id: <1591663670-47712-1-git-send-email-wang.yi59@zte.com.cn> Signed-off-by: Paolo Bonzini --- Makefile | 10 ++++++---- docs/index.html.in | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index a0092153af..b1b8a5a6d0 100644 --- a/Makefile +++ b/Makefile @@ -873,8 +873,9 @@ install-sphinxdocs: sphinxdocs install-doc: $(DOCS) install-sphinxdocs $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)" $(INSTALL_DATA) $(MANUAL_BUILDDIR)/index.html "$(DESTDIR)$(qemu_docdir)" - $(INSTALL_DATA) docs/interop/qemu-qmp-ref.html "$(DESTDIR)$(qemu_docdir)" - $(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)" + $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)/interop" + $(INSTALL_DATA) docs/interop/qemu-qmp-ref.html "$(DESTDIR)$(qemu_docdir)/interop" + $(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)/interop" ifdef CONFIG_POSIX $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" $(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu.1 "$(DESTDIR)$(mandir)/man1" @@ -892,8 +893,9 @@ ifdef CONFIG_TRACE_SYSTEMTAP endif ifneq (,$(findstring qemu-ga,$(TOOLS))) $(INSTALL_DATA) $(MANUAL_BUILDDIR)/interop/qemu-ga.8 "$(DESTDIR)$(mandir)/man8" - $(INSTALL_DATA) docs/interop/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)" - $(INSTALL_DATA) docs/interop/qemu-ga-ref.txt "$(DESTDIR)$(qemu_docdir)" + $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)/interop" + $(INSTALL_DATA) docs/interop/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)/interop" + $(INSTALL_DATA) docs/interop/qemu-ga-ref.txt "$(DESTDIR)$(qemu_docdir)/interop" $(INSTALL_DATA) docs/interop/qemu-ga-ref.7 "$(DESTDIR)$(mandir)/man7" endif endif diff --git a/docs/index.html.in b/docs/index.html.in index e9a160384c..6736fa4360 100644 --- a/docs/index.html.in +++ b/docs/index.html.in @@ -12,8 +12,8 @@